pax_global_header00006660000000000000000000000064152073554130014517gustar00rootroot0000000000000052 comment=a3beaa632077a532330343d5db0d8e30e58b6705 scikit-bio-scikit-bio-a3beaa6/000077500000000000000000000000001520735541300163535ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/.codecov.yml000066400000000000000000000003101520735541300205700ustar00rootroot00000000000000coverage: status: patch: default: target: 80% project: default: target: 80% ignore: - "*/tests/*" - "test_*.py" - "util/_typing.py" - "util/_testing.py" scikit-bio-scikit-bio-a3beaa6/.coveragerc000066400000000000000000000006051520735541300204750ustar00rootroot00000000000000# this file is based on the examples provided on scikit-learn's .coveragerc [run] omit = */tests* */__init__.py source = skbio branch = True include = */skbio/* relative_files = True [report] exclude_lines = pass pragma: no cover raise NotImplementedError if __name__ == .__main__.: omit = */tests/* */__init__.py util/_typing.py util/_testing.py scikit-bio-scikit-bio-a3beaa6/.dockerignore000066400000000000000000000001371520735541300210300ustar00rootroot00000000000000.pytest_cache build/ dist/ *.swp env*/ __pycache__/ */__pycache__/ **/__pycache__/ *.egg-info/ scikit-bio-scikit-bio-a3beaa6/.editorconfig000066400000000000000000000003251520735541300210300ustar00rootroot00000000000000root = true [*] charset = utf-8 insert_final_newline = false [*.{py,c,h}] indent_style = space indent_size = 4 [*.{yml,yaml}] indent_style = space indent_size = 2 [Makefile] indent_style = tab indent_size = 4 scikit-bio-scikit-bio-a3beaa6/.github/000077500000000000000000000000001520735541300177135ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000024511520735541300235160ustar00rootroot00000000000000Please complete the following checklist: * [ ] I have read the [contribution guidelines](https://scikit.bio/contribute.html). * [ ] I have documented all public-facing changes in the [changelog](https://github.com/scikit-bio/scikit-bio/blob/main/CHANGELOG.md). * [ ] **This pull request includes code, documentation, or other content derived from external source(s).** If this is the case, ensure the external source's license is compatible with scikit-bio's [license](https://github.com/scikit-bio/scikit-bio/blob/main/LICENSE.txt). Include the license in the `licenses` directory and add a comment in the code giving proper attribution. Ensure any other requirements set forth by the license and/or author are satisfied. - **It is your responsibility to disclose** code, documentation, or other content derived from external source(s). If you have questions about whether something can be included in the project or how to give proper attribution, include those questions in your pull request and a reviewer will assist you. * [ ] This pull request does not include code, documentation, or other content derived from external source(s). Note: [This document](https://scikit.bio/devdoc/review.html) may also be helpful to see some of the things code reviewers will be verifying when reviewing your pull request. scikit-bio-scikit-bio-a3beaa6/.github/workflows/000077500000000000000000000000001520735541300217505ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/.github/workflows/array-api.yml000066400000000000000000000066211520735541300243650ustar00rootroot00000000000000name: Array API Compatibility on: pull_request: branches: [main] paths-ignore: ["web/**", "**.md", "README.rst"] types: [labeled, synchronize] workflow_dispatch: schedule: - cron: '0 6 * * 1' # Every Monday at 06:00 UTC env: latest_python: "3.13" # torch has no 3.14 wheels yet jobs: test-cpu: name: Array API (${{ matrix.backend }}, cpu) runs-on: ubuntu-latest strategy: fail-fast: false matrix: backend: [torch, jax] steps: - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: ${{ env.latest_python }} - name: Install scikit-bio + backend run: | pip install . case "${{ matrix.backend }}" in torch) pip install torch --index-url https://download.pytorch.org/whl/cpu ;; jax) pip install -U jax ;; esac pip install -r ci/requirements.txt -r ci/requirements.test.txt - name: Run tests env: SKBIO_ARRAY_BACKEND: ${{ matrix.backend }} SKBIO_DEVICE: cpu run: cd ci && pytest -m array_api --pyargs skbio test-gpu: if: | github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'gpu-ci') name: Array API (${{ matrix.backend }}, cuda) runs-on: gpu-t4-4-core strategy: fail-fast: false matrix: include: - backend: torch device: cuda - backend: jax device: cuda - backend: cupy device: cuda steps: - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: ${{ env.latest_python }} - name: Check CUDA driver run: nvidia-smi - name: Install scikit-bio + backend # CUDA 12 is pinned for the libraries. To update CUDA versions check the # installation guides for each package. run: | python -m ensurepip pip install -v . case "${{ matrix.backend }}" in torch) pip install torch --index-url https://download.pytorch.org/whl/cu128 ;; jax) pip install -U "jax[cuda12]" ;; cupy) pip install cupy-cuda12x[ctk] ;; esac pip install -r ci/requirements.txt -r ci/requirements.test.txt - name: Verify GPU is visible to backend env: BACKEND: ${{ matrix.backend }} run: | python - <<'PY' import os backend = os.environ["BACKEND"] if backend == "torch": import torch assert torch.cuda.is_available(), "torch installed without CUDA" print("torch:", torch.__version__, "CUDA:", torch.version.cuda, "device:", torch.cuda.get_device_name(0)) elif backend == "jax": import jax gpus = jax.devices("gpu") assert gpus, "jax sees no GPU" print("jax:", jax.__version__, "devices:", gpus) elif backend == "cupy": import cupy n = cupy.cuda.runtime.getDeviceCount() assert n > 0, "cupy sees no GPU" print("cupy:", cupy.__version__, "devices:", n) PY - name: Run tests env: SKBIO_ARRAY_BACKEND: ${{ matrix.backend }} SKBIO_DEVICE: ${{ matrix.device }} run: cd ci && pytest -m array_api --pyargs skbio scikit-bio-scikit-bio-a3beaa6/.github/workflows/ci.yml000066400000000000000000000171161520735541300230740ustar00rootroot00000000000000name: CI on: push: branches: [ main ] paths-ignore: ["web/**", "**.md", "README.rst"] pull_request: branches: [ main ] paths-ignore: ["web/**", "**.md", "README.rst"] env: latest_python: "3.14" supported_pythons: '["3.10", "3.11", "3.12", "3.13", "3.14"]' jobs: conf: # This job is needed to route the global environment variables into # a context that's available for matrix (and name, but that's unimportant) name: Prepare Test Plan runs-on: ubuntu-latest outputs: latest_python: ${{ steps.set-vars.outputs.latest_python }} supported_pythons: ${{ steps.set-vars.outputs.supported_pythons }} steps: - name: Report Plan id: set-vars run: | echo "latest_python=$latest_python" >> $GITHUB_OUTPUT echo "supported_pythons=$supported_pythons" >> $GITHUB_OUTPUT lint: name: Lint code (${{ needs.conf.outputs.latest_python }}, ubuntu-latest) needs: conf runs-on: ubuntu-latest defaults: run: shell: bash -l {0} steps: - uses: actions/checkout@v6 - uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true python-version: ${{ env.latest_python }} environment-file: ci/conda_host_env.yml - name: Install dependencies run: | python -m ensurepip pip install -r ci/requirements.lint.txt conda list - name: Run Ruff run: | ruff check --output-format=github . doc: name: Build Documentation (${{ needs.conf.outputs.latest_python }}, ubuntu-latest) needs: ["conf", "lint"] runs-on: ubuntu-latest defaults: run: shell: bash -l {0} steps: - uses: actions/checkout@v6 with: fetch-depth: 0 # to prevent a "Git clone too shallow" warning by Sphinx - uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true python-version: ${{ env.latest_python }} environment-file: ci/conda_host_env.yml - name: Install dependencies run: | python -m ensurepip pip install -r ci/requirements.doc.txt pip install . conda list - name: Make documentation run: make doc # save built documentation (HTML) for deployment - name: Modify documentation if: github.event_name == 'push' run: | python doc/suburl.py python doc/metatag.py python doc/editmap.py - name: Save documentation if: github.event_name == 'push' uses: actions/upload-artifact@v7 with: name: docpack path: doc/build/html/ # full-scale test with latest Python test-latest: name: Test (${{ needs.conf.outputs.latest_python }}, ${{ matrix.os }}) needs: conf runs-on: ${{ matrix.os }} defaults: run: shell: bash -l {0} strategy: fail-fast: true # https://docs.github.com/en/actions/using-github-hosted-runners/ # about-github-hosted-runners/about-github-hosted-runners#standard- # github-hosted-runners-for-public-repositories matrix: os: [ubuntu-latest, macos-latest, windows-latest, ubuntu-24.04-arm, macos-15-intel] steps: - uses: actions/checkout@v6 - uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true python-version: ${{ env.latest_python }} environment-file: ci/conda_host_env.yml - name: Install dependencies run: | conda install -q --yes -c conda-forge --file ci/requirements.txt --file ci/requirements.test.txt python -m ensurepip pip install --no-deps . conda list # install anndata and polars here to test as optional dependencies. # encountered errors when installing using conda - name: Install optional dependencies run: | pip install anndata polars conda list - name: Run unit tests env: WITH_COVERAGE: "TRUE" run: make test # upload coverage reports to Codecov (only under ubuntu-latest) - name: Generate coverage reports if: runner.os == 'Linux' && runner.arch == 'X64' run: | cd ci && coverage lcov --rcfile ../.coveragerc - name: Upload coverage reports to Codecov if: runner.os == 'Linux' && runner.arch == 'X64' uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} slug: scikit-bio/scikit-bio # test under all combinations of environments (Python versions, operating systems, PyPI vs Conda) test-all: name: Test (${{ matrix.python_version }}, ${{ matrix.os }}, ${{ fromJSON('["pypi", "conda"]')[matrix.use_conda] }}) runs-on: ${{ matrix.os }} needs: ["conf", "test-latest", "lint"] defaults: run: shell: bash -l {0} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] python_version: ${{ fromJSON(needs.conf.outputs.supported_pythons) }} use_conda: [true, false] steps: - uses: actions/checkout@v6 # set up conda environment - name: Setup conda environment if: ${{ matrix.use_conda }} uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true python-version: ${{ matrix.python_version }} environment-file: ci/conda_host_env.yml # set up CPython environment (pip) - name: Setup CPython environment if: ${{ !matrix.use_conda }} uses: actions/setup-python@v6 with: python-version: ${{ matrix.python_version }} # conda installation - name: Install dependencies (conda) if: ${{ matrix.use_conda }} run: | conda install -q --yes -c conda-forge --file ci/requirements.txt --file ci/requirements.test.txt python -m ensurepip pip install --no-deps . conda list # pip installation - name: Install dependencies if: ${{ !matrix.use_conda }} run: | python -m ensurepip pip install --prefer-binary -r ci/requirements.txt -r ci/requirements.test.txt pip install --no-deps . pip list - name: Run unit tests env: WITH_COVERAGE: "TRUE" run: make test # deploy the current development documentation to the website # only when event is push and all tests have passed deploy-doc: name: Deploy documentation if: github.event_name == 'push' needs: ["doc", "test-all"] runs-on: ubuntu-latest defaults: run: shell: bash -l {0} steps: # load documentation built by job "doc" - name: Load documentation uses: actions/download-artifact@v8 with: name: docpack path: docpack # checkout website repo - name: Check out website uses: actions/checkout@v6 with: repository: scikit-bio/scikit-bio.github.io path: website ssh-key: ${{ secrets.SSH_DEPLOY_KEY }} # synchronize documentation to website's docs/dev directory - name: Update documentation run: rsync -av --delete docpack/ website/docs/dev # push website back to repo - name: Push website run: | cd website git config user.name "${{ github.actor }}" git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com" git add -A git commit -m "Update from ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}" git push scikit-bio-scikit-bio-a3beaa6/.github/workflows/release.yml000066400000000000000000000037231520735541300241200ustar00rootroot00000000000000name: Release on: push: tags: - '*' env: earliest_python: "3.10" latest_python: "3.14" jobs: # Trigger wheel building workflow build_and_publish: name: Build and publish to PyPI uses: ./.github/workflows/wheels.yml secrets: inherit doc: name: Publish documentation runs-on: ubuntu-latest needs: build_and_publish # Wait for wheels to be built defaults: run: shell: bash -l {0} steps: - name: Check out repo uses: actions/checkout@v6 with: fetch-depth: 0 - name: Setup Python environment uses: actions/setup-python@v6 with: python-version: ${{ env.latest_python }} - name: Install dependencies run: | python -m ensurepip pip install --prefer-binary -r ci/requirements.doc.txt -r ci/requirements.txt pip install --no-deps . pip list - name: Build documentation run: make doc - name: Modify documentation run: | python doc/suburl.py python doc/metatag.py python doc/editmap.py - name: Check out website uses: actions/checkout@v6 with: repository: scikit-bio/scikit-bio.github.io path: website ssh-key: ${{ secrets.SSH_DEPLOY_KEY }} - name: Update documentation run: | rsync -av --delete doc/build/html/ website/docs/${{ github.ref_name }} sed -i 's/docs\/${{ github.ref_name }}\//docs\/latest\//g' doc/build/html/sitemap.xml rsync -av --delete doc/build/html/ website/docs/latest - name: Publish website run: | cd website git config user.name "${{ github.actor }}" git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com" git add -A git commit -m "Update from ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}" git push scikit-bio-scikit-bio-a3beaa6/.github/workflows/website.yml000066400000000000000000000042641520735541300241430ustar00rootroot00000000000000name: Website on: push: branches: [ main ] paths: [ "web/**", "!**.md" ] pull_request: branches: [ main ] paths: [ "web/**", "!**.md" ] env: latest_python: "3.14" jobs: build: name: Build website runs-on: ubuntu-latest defaults: run: shell: bash -l {0} steps: - name: Check out repo uses: actions/checkout@v6 - name: Set up conda uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true python-version: ${{ env.latest_python }} - name: Install dependencies run: | python -m ensurepip pip install -r ci/requirements.doc.txt - name: Make website run: make web - name: Substitute URLs if: github.event_name == 'push' run: python web/suburl.py - name: Add version list if: github.event_name == 'push' run: cp web/versions.json web/_build/html/ - name: Save website package if: github.event_name == 'push' uses: actions/upload-artifact@v7 with: name: webpack path: web/_build/html/ deploy: name: Deploy website if: github.event_name == 'push' needs: build runs-on: ubuntu-latest defaults: run: shell: bash -l {0} steps: - name: Check out repo uses: actions/checkout@v6 - name: Load website package uses: actions/download-artifact@v8 with: name: webpack path: webpack - name: Check out website repo uses: actions/checkout@v6 with: repository: scikit-bio/scikit-bio.github.io path: website ssh-key: ${{ secrets.SSH_DEPLOY_KEY }} - name: Update website run: rsync -av --delete --exclude-from web/.exclude webpack/ website - name: Push website run: | cd website git config user.name "${{ github.actor }}" git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com" git add -A git commit -m "Update from ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}" git push scikit-bio-scikit-bio-a3beaa6/.github/workflows/wheels.yml000066400000000000000000000062061520735541300237660ustar00rootroot00000000000000name: Build Wheels on: pull_request: branches: [ main ] workflow_dispatch: workflow_call: schedule: - cron: "0 7 1,15 * *" env: latest_python: "3.14" jobs: build_wheels: name: Build wheels on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-latest] # The 6 runners correspond to 6 architectures. Details: # https://cibuildwheel.pypa.io/en/stable/options/#archs # The runners and architectures should be automatically associated. However, in # case not in the future, they can be manually specified as follows: # include: # - os: ubuntu-latest # cibw_archs: 'x86_64' # - os: ubuntu-24.04-arm # cibw_archs: 'aarch64' # - os: windows-latest # cibw_archs: 'AMD64' # - os: windows-11-arm # cibw_archs: 'ARM64' # - os: macos-15-intel # cibw_archs: 'x86_64' # - os: macos-latest # cibw_archs: 'arm64' steps: - uses: actions/checkout@v6 with: submodules: true - name: Build wheels # This may need to be updated for new Python versions, double check before release. uses: pypa/cibuildwheel@v3.4.0 env: # Run full tests on release, manual trigger, and schedule (twice a month). Otherwise (i.e. on PRs) do simple import/print test. CIBW_TEST_COMMAND: > ${{ ((github.event_name == 'push' && startsWith(github.ref, 'refs/tags')) || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule') && 'python -m skbio.test' || 'python -c "import skbio; print(skbio.__version__)"' }} - uses: actions/upload-artifact@v7 with: name: wheels-${{ matrix.os }}-${{ strategy.job-index }} path: ./wheelhouse/*.whl build_sdist: name: Build source distribution runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: submodules: true - name: Set up Python uses: actions/setup-python@v6 with: python-version: ${{ env.latest_python }} - name: Install build dependencies run: | python -m ensurepip pip install numpy cython build - name: Build sdist run: python -m build --sdist - uses: actions/upload-artifact@v7 with: name: sdist path: dist/*.tar.gz upload_pypi: needs: [build_wheels, build_sdist] runs-on: ubuntu-latest # Only upload to PyPI on tagged commits if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') steps: - uses: actions/download-artifact@v8 with: pattern: wheels-* path: dist merge-multiple: true - uses: actions/download-artifact@v8 with: name: sdist path: dist - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.PYPI_API_TOKEN }} scikit-bio-scikit-bio-a3beaa6/.gitignore000066400000000000000000000010611520735541300203410ustar00rootroot00000000000000# Temporary files *~ \#*# .pytest_cache/* *.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 __pycache__ # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox nosetests.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject # vi .*.swp # Sphinx builds doc/source/generated doc/build web/_build # OSX files .DS_Store # VS Code .vscode # Cython files *.c # Environments .env .envrc .venv env/ venv/ ENV/ env.bak/ venv.bak/ scikit-bio-scikit-bio-a3beaa6/.pre-commit-config.yaml000066400000000000000000000003721520735541300226360ustar00rootroot00000000000000# This file gives the option to use Ruff as a pre-commit hook. repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. rev: v0.14.1 hooks: # Run the linter. - id: ruff # Run the formatter. - id: ruff-format scikit-bio-scikit-bio-a3beaa6/CHANGELOG.md000066400000000000000000004172431520735541300201770ustar00rootroot00000000000000# scikit-bio changelog ## Version 0.7.3 ### Features * Implemented a global mechanism to document, dispatch and test functions supporting the Python array API standard. The documentation pages of those functions now display a support grid of five array libraries (NumPy, CuPy, PyTorch, JAX and Dask) by two devices (CPU and GPU). An example is `clr`. A new developer documentation page (https://scikit.bio/devdoc/array_api.html) was added to introduce this mechanism ([#2412](https://github.com/scikit-bio/scikit-bio/pull/2412) and [#2459](https://github.com/scikit-bio/scikit-bio/pull/2459)). * Added `mmvec` (Microbe-Metabolite Vectors) to `skbio.stats.ordination` for learning joint embeddings of two feature sets from co-occurrence patterns. Supports L-BFGS and Adam optimizers, cross-validation via Q-squared scores, and prediction of one modality from another ([#2360](https://github.com/scikit-bio/scikit-bio/pull/2360)). Interface modernized and computational performance significantly enhanced ([#2448](https://github.com/scikit-bio/scikit-bio/pull/2448)). * Added gamma correction support for modeling among-site evolutionary rate heterogeneity in the JC69, F81, K2P, and TN93 models ([#2460](https://github.com/scikit-bio/scikit-bio/pull/2460)). Thank @keder for this contribution. * Added robust center log ratio (`rclr`) transformation for performing CLR-like transformation on only observed (non-zero) values, making it suitable for sparse compositional data ([#2386](https://github.com/scikit-bio/scikit-bio/pull/2386)). * Added support to `TreeNode.from_taxonomy` for parsing taxonomic lineage strings into trees with an optional `extract_rank` parameter ([#2406](https://github.com/scikit-bio/scikit-bio/pull/2406)). Thank @r0hansaxena for this and other contributions to this release. ### Performance enhancements * Reduced `import skbio` time by ~37% by making `requests` and `h5py` lazy imports ([#2427](https://github.com/scikit-bio/scikit-bio/pull/2427)). Thank @MAUK9086 for contributing this. * Significantly accelerated `gme`, `bme` and `nni` of the `skbio.tree` module. Of which, `bme` received the most rigorous optimization. Parallelization is now enabled by default for this function ([#2404](https://github.com/scikit-bio/scikit-bio/pull/2404)). ### Bug Fixes * Fixed `nni`'s parsing of tree with single-child root node by explicitly raising in this situation ([#2446](https://github.com/scikit-bio/scikit-bio/pull/2446)). * Fixed `permdisp` mutating the input `OrdinationResults` object by adding a `"grouping"` column to its `samples` DataFrame ([#2440](https://github.com/scikit-bio/scikit-bio/pull/2440)). * Fixed `permdisp` emitting pcoa's `RuntimeWarning` on every call with a distance matrix larger than 10 samples ([#2456](https://github.com/scikit-bio/scikit-bio/pull/2456)). Thank @jissen706 for this fix and the one below. * Fixed the GenBank/EMBL/GFF3 feature-location parser to accept single-base locations with a fuzzy boundary (e.g. `complement(<23231)` as found in the NCBI lambda virus record J02459.1). Previously such locations raised `FileFormatError: Could not parse location string`. The corresponding serializer was updated symmetrically to emit `N` instead of dropping the fuzzy marker ([#2473](https://github.com/scikit-bio/scikit-bio/pull/2473)). ### Miscellaneous * Replaced SciPy sparse matrix constructors with sparse array constructors to align with SciPy's sparse array APIs. This affects `subsample_counts` (`csr_array`) (no public-facing effect) and `tree_basis` (`coo_array`) ([#2444](https://github.com/scikit-bio/scikit-bio/pull/2444)). * Added a general `_reader_kwargs` mechanism for documenting class-specific parameters in auto-generated `read()` docstrings. Applied to `TabularMSA` to document the required `constructor` parameter ([#2421](https://github.com/scikit-bio/scikit-bio/pull/2421)). Thank @LiudengZhang for this addition. * `beta_diversity` now emits a `UserWarning` when `unweighted_unifrac` or `weighted_unifrac` are passed as a callable, advising users to pass the metric name as a string for the optimized implementation ([#2462](https://github.com/scikit-bio/scikit-bio/pull/2462)). Thank @SAY-5 for this patch. * Improved documentation for `pip`-based contribution instructions ([#2433](https://github.com/scikit-bio/scikit-bio/pull/2433)). Thank @AhmedKhairy22 for this and other contributions. ## Version 0.7.2 ### Features * Added multiple metrics for calculating the evolutionary distances between aligned sequences: generic: `pdist`, `logdet`, `paralin`, `jc69`, `f81`, `k2p`, `f84`, `tn93`. They are hosted by the submodule `skbio.sequence.distance`. Also added `align_dists`, which consumes a multiple sequence alignment and generates a distance matrix using choice of metrics ([#2336](https://github.com/scikit-bio/scikit-bio/pull/2336)). * `mantel` and `permanova` can now run directly on condensed form `DistanceMatrix` objects ([#2322](https://github.com/scikit-bio/scikit-bio/pull/2322), [#2335](https://github.com/scikit-bio/scikit-bio/pull/2335)). * Added new `phylip_dm` format for PHYLIP formatted distance matrices ([#2345](https://github.com/scikit-bio/scikit-bio/pull/2345) and [#2352](https://github.com/scikit-bio/scikit-bio/pull/2352)). * Added support for reading relaxed PHYLIP formatted multiple sequence alignments ([#2345](https://github.com/scikit-bio/scikit-bio/pull/2345), [#2352](https://github.com/scikit-bio/scikit-bio/pull/2352), and [#2361](https://github.com/scikit-bio/scikit-bio/pull/2361)). * Added new plotting functionality for `OrdinationResults` objects, including plotting centroids, confidence ellipses, and 2D plots ([#2362](https://github.com/scikit-bio/scikit-bio/pull/2362)) ### Performance enhancements * Improved `TreeNode.from_linkage_matrix`, including efficiency, compatibility (it now accepts array-like objects), and documentation ([#2356](https://github.com/scikit-bio/scikit-bio/pull/2356)). * Updated the documentation of `dirmult_ttest` to recommend input data supplied as raw counts rather than pre-normalized proportions, as the latter lose magnitude information and can lead to higher statistical uncertainty ([#2358](https://github.com/scikit-bio/scikit-bio/pull/2358)). ### Bug Fixes * Fixed an IO issue in `skbio.Table.write` where tables containing metadata could not be written ([#2338](https://github.com/scikit-bio/scikit-bio/pull/2338)). * Fixed an issue in the `from_iterable` methods of the `DistanceMatrix`, `SymmetricMatrix`, and `PairwiseMatrix` classes where diagonals were being filled with garbage values ([#2347](https://github.com/scikit-bio/scikit-bio/pull/2347)). * Fixed a bug in `TreeNode.root_at_midpoint` which could fail on a tree with no-length branches ([#2353](https://github.com/scikit-bio/scikit-bio/pull/2353)). * Fixed an unexpected behavior in several `TreeNode` methods, where tips with `.name is None` were considered as taxa and included in the calculation. Nameless tips are unusual but not forbidden by the current data model. After fixation, those tips are excluded from the calculation. Affected methods are `subset`, `subsets`, `bipart`, `bipart` and `cophenet` ([#2353](https://github.com/scikit-bio/scikit-bio/pull/2353)). * Fixed an integer overflow issue in `_nodes_by_counts` that can occur on 32-bit systems, such as WASM ([#2369]https://github.com/scikit-bio/scikit-bio/pull/2369). ### Miscellaneous * scikit-bio can now be cited by its [journal publication](https://doi.org/10.1038/s41592-025-02981-z) in _Nature Methods_. * `TreeNode.shear` now returns the sheared tree even if `inplace=True` ([#2353](https://github.com/scikit-bio/scikit-bio/pull/2353)). * Added compatibility for pandas 3.0. Most functionality works, but the `INSDC:missing` scheme for encoding missing values is not yet supported with pandas 3.0. See issue [#2375](https://github.com/scikit-bio/scikit-bio/issues/2375) for tracking ([#2371](https://github.com/scikit-bio/scikit-bio/pull/2371)). * Documentation was improved for the `default_write_format` attributes of supported file types ([#2340](https://github.com/scikit-bio/scikit-bio/pull/2340)) * Improved documentation for parallelization techniques across the package ([#2343](https://github.com/scikit-bio/scikit-bio/pull/2343)) ### Backward-incompatible changes * Removed `sokalmichener` from the list of supported beta diversity metrics (see `get_beta_diversity_metrics`), as this metric was removed in SciPy 1.17.0. SciPy's documentation recommended using `rogerstanimoto` instead ([#2367](https://github.com/scikit-bio/scikit-bio/pull/2367)). ## Version 0.7.1.post1 ### Features * Added support for building scikit-bio python wheels natively on Windows ARM64 ([#2309](https://github.com/scikit-bio/scikit-bio/pull/2309)). ### Bug Fixes * Fixed source distribution packaging for Python 3.14 support. ## Version 0.7.1 ### Features * Added function `ancombc`, a Python implementation of the ANCOM-BC (analysis of compositions of microbiomes with bias correction) method for differential abundance testing. We thank @FrederickHuangLin for advice ([#2293](https://github.com/scikit-bio/scikit-bio/pull/2293), [#2305](https://github.com/scikit-bio/scikit-bio/pull/2305), [#2306](https://github.com/scikit-bio/scikit-bio/pull/2306), [#2316](https://github.com/scikit-bio/scikit-bio/pull/2316)). * Added function `struc_zero`, a statistical test for structural zeros. This function complements `ancombc` or can be used alone ([#2305](https://github.com/scikit-bio/scikit-bio/pull/2305)). * Enabled inheritance of IO methods (read, write, sniff) on all scikit-bio objects. Subclasses now inherit IO operations, significantly improving custom class creation and extensibility ([#2301](https://github.com/scikit-bio/scikit-bio/pull/2301)). * Added new `PairwiseMatrix` and `SymmetricMatrix` classes and an updated `DistanceMatrix` class. Underlying data of `SymmetricMatrix` and `DistanceMatrix` classes can now be stored in condensed form, reducing memory footprint by 50% ([#2289](https://github.com/scikit-bio/scikit-bio/pull/2289)). ### Performance enhancements * Drastically speed up `pcoa` with the default eigh method ([#2285](https://github.com/scikit-bio/scikit-bio/pull/2285)). * Enriched documentation of `permanova`, explaining the underlying mathematics, the usage, and how to calculate R2, a statistic that measures the proportion of data variance explained by the specified variable ([#2294](https://github.com/scikit-bio/scikit-bio/pull/2297), [#2294](https://github.com/scikit-bio/scikit-bio/pull/2297)). * Added float32 support for minimum evolution phylogenetic tree building algorithms (`gme`, `bme` and `nni`) ([#2291](https://github.com/scikit-bio/scikit-bio/pull/2291)). * Added float32 support for reading labeled square matrix (lsmat) file format (`io.format.lsmat`) ([#2230](https://github.com/scikit-bio/scikit-bio/pull/2230)). ### Bug Fixes * Fixed an unexpected behavior in the file I/O of `TabularMSA` class that `fasta` and `fastq` formats populate `.metadata['id']` of each sequence whereas `clustal`, `phylip` and `stockholm` formats populate `.index` of the entire alignments. Now all file formats populate both pieces of information ([#2320](https://github.com/scikit-bio/scikit-bio/pull/2320)). * Fixed a bug that `pair_align` with `trim_ends=True` on completely misaligned sequences would raise an IndexError instead of returning an empty path ([#2284](https://github.com/scikit-bio/scikit-bio/pull/2284)). * Fixed IO format `binary_dm` implementation ([#2282](https://github.com/scikit-bio/scikit-bio/pull/2282), [#2283](https://github.com/scikit-bio/scikit-bio/pull/2283)). * Fixed a bug in reading binary dissimilarity matrix format (`io.format.binary_dm`), that a float32 data file would be unnecessarily casted into float64 ([#2230](https://github.com/scikit-bio/scikit-bio/pull/2230)). * Replace "Correspondance Analysis" with "Correspondence Analysis" in creating `OrdinationResults` objects for the accuracy of terminology. This term has been "Correspondence Analysis" otherwise in the project. * Fixed a runtime error when computing phylogenetic diversity metrics on 32-bit architectures ([#2321](https://github.com/scikit-bio/scikit-bio/pull/2321)). ### Miscellaneous * Renamed `DissimilarityMatrix` as `PairwiseMatrix` to better reflect its nature. The old name is kept as an alias ([#2289](https://github.com/scikit-bio/scikit-bio/pull/2289)). * Replace "Correspondance Analysis" with "Correspondence Analysis" in creating `OrdinationResults` objects for the accuracy of terminology. This term has been "Correspondence Analysis" otherwise in the project ([#2318](https://github.com/scikit-bio/scikit-bio/pull/2318)). * Added environment variable `DISABLE_OPENMP`, which lets a user optionally disable OpenMP when compiling the Cython code if needed ([#2319](https://github.com/scikit-bio/scikit-bio/pull/2319)). * Dropped support for Python 3.9 and added support for Python 3.14 ([#2311](https://github.com/scikit-bio/scikit-bio/pull/2311)). * Dropped support for NumPy versions older than 2.0 ([#2314](https://github.com/scikit-bio/scikit-bio/pull/2314)). ## Version 0.7.0 ### Features * Added a development roadmap for scikit-bio to the website ([#2251](https://github.com/scikit-bio/scikit-bio/pull/2251)). * Added function `dirmult_lme`, a differential abundance test for longitudinal data through fitting a Dirichlet-multinomial linear mixed effects model ([#2080](https://github.com/scikit-bio/scikit-bio/pull/2080) and [#2250](https://github.com/scikit-bio/scikit-bio/pull/2250)). * Added function `pair_align`, a re-designed pairwise sequence alignment engine that is versatile, efficient, and generalizable ([#2226](https://github.com/scikit-bio/scikit-bio/pull/2226) and [#2196](https://github.com/scikit-bio/scikit-bio/pull/2196)). It is meant to replace the old slow Python engine and the SSW wrapper. It supports: - Global, local and semi-global alignments (with all four ends customizable). - Nucleotide, protein, and un-grammared sequences, plain strings (ASCII and Unicode), words/tokens, and numbers. - Match/mismatch scores or substitution matrix. - Linear and affine gap penalties. - Integer, decimal and infinite scores. - Returning one, multiple or all optimal alignment paths. * Added wrapper functions `pair_align_prot` and `pair_align_nucl` which are preloaded with scoring schemes consistent with BLASTP and BLASTN, respectively ([#2234](https://github.com/scikit-bio/scikit-bio/pull/2234)). * Added function `align_score` to calculate the score of a pairwise or multiple sequence alignment ([#2201](https://github.com/scikit-bio/scikit-bio/pull/2201), [#2192](https://github.com/scikit-bio/scikit-bio/pull/2192)). * Implemented a dispatch system in scikit-bio to handle a variety of table formats. Currently, it handles arrays, Pandas and Polars dataframes, BIOM tables, and AnnData. Scikit-bio functions can now operate on any of these table formats and outputs an object of the same format, or a format designated by the user ([#2187](https://github.com/scikit-bio/scikit-bio/pull/2187), [#2203](https://github.com/scikit-bio/scikit-bio/pull/2203), [#2246](https://github.com/scikit-bio/scikit-bio/pull/2246), [#2258](https://github.com/scikit-bio/scikit-bio/pull/2258), [#2260](https://github.com/scikit-bio/scikit-bio/pull/2260)). * Added four augmentation methods: `phylomix`, `compos_cutmix`, `aitchison_mixup` and `mixup` to enable generation of synthetic samples ([#2214](https://github.com/scikit-bio/scikit-bio/pull/2214), [#2190](https://github.com/scikit-bio/scikit-bio/pull/2190), [#2253](https://github.com/scikit-bio/scikit-bio/pull/2253)). * Added support for scikit-bio-binaries, a separate package which currently increases performance of the `pcoa` and `permanova` functions within scikit-bio ([#2247](https://github.com/scikit-bio/scikit-bio/pull/2247)). * Added pre-built wheels of scikit-bio to PyPI for easier installation across platforms ([#2233](https://github.com/scikit-bio/scikit-bio/pull/2233), [#2232](https://github.com/scikit-bio/scikit-bio/pull/2232), [#2228](https://github.com/scikit-bio/scikit-bio/pull/2228), [#2252](https://github.com/scikit-bio/scikit-bio/pull/2252)). * Adopting the Python array API standard in scikit-bio to enable GPU support for select functions. Further expansion of GPU support within scikit-bio is expected ([#2239](https://github.com/scikit-bio/scikit-bio/pull/2239) and [#2250](https://github.com/scikit-bio/scikit-bio/pull/2250)). * Added `AlignPath.to_aligned` and `AlignPath.from_aligned` to extract aligned regions of the original sequences, and to reconstruct a path from aligned sequences ([#2226](https://github.com/scikit-bio/scikit-bio/pull/2226)). * Added parameter `starts` to `AlignPath.from_tabular` to specify starting positions in the original sequences ([#2226](https://github.com/scikit-bio/scikit-bio/pull/2226)). ### Performance enhancements * Enriched the tutorials of modules `sequence`, `alignment`, and `table` ([#2263](https://github.com/scikit-bio/scikit-bio/pull/2263)). * Improved the performance of `dirmult_ttest` ([#2250](https://github.com/scikit-bio/scikit-bio/pull/2250)). * Improved the performance of `ancom`. This is primarily due to exploiting vectorization of the statistical testing function (such as `f_oneway`). As a consequence, a custom testing function now must accept 2-D arrays as input and return 1-D arrays. Function names available under `scipy.stats` are not impacted ([#2250](https://github.com/scikit-bio/scikit-bio/pull/2250)). * Added attributes `ranges` and `stops` to `AlignPath`. They facilitate locating the aligned part of each sequence as `seq[start:stop]` ([#2226](https://github.com/scikit-bio/scikit-bio/pull/2226) and [#2201](https://github.com/scikit-bio/scikit-bio/pull/2201)). * Improved the performance of `SubstitutionMatrix.identity`. * Enhanced `TabularMSA.from_path_seqs`. It now can extract the aligned region from the middle of a sequence. Also added docstring and doctests ([#2201](https://github.com/scikit-bio/scikit-bio/pull/2201)). * Enhanced and changed the default behavior of `AlignPath.to_bits`, which now returns a bit array representing positions instead of segments. This is desired because with the old default behavior, `to_bits` and `from_bits` are not consistent with each other ([#2201](https://github.com/scikit-bio/scikit-bio/pull/2201)). ### Bug Fixes * Fixed a bug that `PairAlignPath.from_cigar` would ignore the first insertion (`I`) of a CIGAR string ([#2236](https://github.com/scikit-bio/scikit-bio/pull/2236)). * Fixed an inaccurate statement that one can specify `gap` as np.inf or np.nan in `AlignPath.to_indices`. These cases are impossible because the output is integer type. * Fixed an inaccurate statement in the documentation of `SubstitutionMatrix.is_ascii`. This attribute is True when all characters in the alphabet are ASCII codes (0 to 127), not extended ASCII codes (0 to 255) ([#2226](https://github.com/scikit-bio/scikit-bio/pull/2226)). * Fixed a bug that a `SubstitutionMatrix` cannot be copied ([#2226](https://github.com/scikit-bio/scikit-bio/pull/2226)). * Fixed a bug in `AlignPath.to_indices` which would throw an error if the alignment path has only one segment ([#2201](https://github.com/scikit-bio/scikit-bio/pull/2201)). * Fixed a bug in the documentation in which the `source` button would link to decorator code, instead of the relevant function ([#2184](https://github.com/scikit-bio/scikit-bio/pull/2184)). ### Miscellaneous * In `TreeNode.root_at` and `TreeNode.root_at_midpoint`, the default value of `branch_attrs` was changed to an empty list; that of `root_name` was changed to None; that of `reset` was changed to True ([#2259](https://github.com/scikit-bio/scikit-bio/pull/2259)). * In `TreeNode.unrooted_copy`, the default value of `branch_attrs` was changed to `{"length", "support"}`. Specifically, "name" was removed from this set, as a node label is often an attribute of the node instead of the branch. The default value of `root_name` was changed to None ([#2259](https://github.com/scikit-bio/scikit-bio/pull/2259)). * In `TreeNode.copy`, the default value of `deep` was set to False. Now `tree.copy()` returns a shallow copy instead of a deep copy ([#2259](https://github.com/scikit-bio/scikit-bio/pull/2259)). * In `TreeNode.compare_cophenet`, the default value of `ignore_self` was set to True. Therefore the estimated cophenetic distance between trees better correlates with their discrepancy ([#2259](https://github.com/scikit-bio/scikit-bio/pull/2259)). * Renamed column "Reject null hypothesis" as "Signif" in `ancom` and `dirmult_ttest`'s report tables for conciseness ([#2250](https://github.com/scikit-bio/scikit-bio/pull/2250)). * Renamed the parameter `significance_test` as `sig_test` in `ancom` for conciseness. The old name is preserved as an alias ([#2250](https://github.com/scikit-bio/scikit-bio/pull/2250)). * Set the default data type of `SubstitutionMatrix` as `np.float32` (previous it was `float`, which is equivalent to `np.float64`). Made `dtype` an optional parameter in `from_dict` and `identity` methods. * Adjusted the `__repr__` of `AlignPath` and `PairAlignPath` ([#2226](https://github.com/scikit-bio/scikit-bio/pull/2226) and [#2235](https://github.com/scikit-bio/scikit-bio/pull/2235)). * Changed `AlignPath.shape`'s type from a named tuple to a normal tuple ([#2235](https://github.com/scikit-bio/scikit-bio/pull/2235)). Let the values be native Python `int` rather than `np.int64` ([#2201](https://github.com/scikit-bio/scikit-bio/pull/2201)). * Changed `AlignPath.lengths` and `AlignPath.starts`'s dtype from `int64` to `intp`, as these attributes are to facilitate indexing ([#2226](https://github.com/scikit-bio/scikit-bio/pull/2226)). * Changed `Sequence.to_indices`'s output index array dtype from `uint8` to `intp`, which is the native NumPy indexing type ([#2226](https://github.com/scikit-bio/scikit-bio/pull/2226)). * Enriched the documentation of `SubstitutionMatrix` ([#2226](https://github.com/scikit-bio/scikit-bio/pull/2226)). * Let `AlignPath.states` be uniformly 2-D, even if there are 8 or less sequences in the alignment ([#2201](https://github.com/scikit-bio/scikit-bio/pull/2201)). * Updated documentation to include description of how to stream data through stdin with scikit-bio's `read` function ([#2185](https://github.com/scikit-bio/scikit-bio/pull/2185)). * Improved documentation for the `DistanceMatrix` object ([#2204](https://github.com/scikit-bio/scikit-bio/pull/2204)). * Remove autoplotting functionality to enable inplace operations on large in-memory objects, and improve documentation of existing plotting methods ([#2216](https://github.com/scikit-bio/scikit-bio/pull/2216), [#2223](https://github.com/scikit-bio/scikit-bio/pull/2223)). * Initiated efforts to add type annotations to scikit-bio's codebase, starting with the `stats.distance` module ([#2219](https://github.com/scikit-bio/scikit-bio/pull/2219)) * Restored functionality to scikit-bio's benchmarking system and introduced a new repository for storing, running, and hosting benchmarks to prevent performance regression ([#2245](https://github.com/scikit-bio/scikit-bio/pull/2245)). * Renamed the parameter `number_of_dimensions` to `dimensions` for the `pcoa` and `permdisp` functions. `number_of_dimensions` will remain a valid alias of the parameter, such that either option may be used. ([#2257](https://github.com/scikit-bio/scikit-bio/pull/2257)). * Enriched the tutorial for `skbio.Sequence` ([#2243](https://github.com/scikit-bio/scikit-bio/pull/2243)). * The `tree.nj` function can now operate on `DistanceMatrix` objects containing float32 or float64 values ([#2217](https://github.com/scikit-bio/scikit-bio/pull/2217)). * Improved documentation for conversion between scikit-bio sequence alignments and Biopython and Biotite alignments ([#2229](https://github.com/scikit-bio/scikit-bio/pull/2229), [#2230](https://github.com/scikit-bio/scikit-bio/pull/2230)). * Rewrote the `install` page for the website to reflect availability of wheels and to explicitly state scikit-bio's version support windows ([#2254](https://github.com/scikit-bio/scikit-bio/pull/2254)). * Renamed the parameter `distance_matrix` to `distmat` in `pcoa`, `bioenv`, `anosim`, `permanova`, and `permdisp`. `distance_matrix` will remain a valid alias of the parameter, such that either option may be used. ([#2261](https://github.com/scikit-bio/scikit-bio/pull/2261)) ### Backward-incompatible changes * Removed `TreeNode.unrooted_deepcopy`. Use `TreeNode.unrooted_copy(deep=True)` instead ([#2259](https://github.com/scikit-bio/scikit-bio/pull/2259)). * Removed `TreeNode.deepcopy`. Use `TreeNode.copy(deep=True)` instead ([#2259](https://github.com/scikit-bio/scikit-bio/pull/2259)). * Removed `TreeNode.subtree`. It was a placehold but never implemented ([#2259](https://github.com/scikit-bio/scikit-bio/pull/2259)). * Removed the wrapper for the Striped Smith Waterman (SSW) library ([#2240](https://github.com/scikit-bio/scikit-bio/pull/2240), [#2241](https://github.com/scikit-bio/scikit-bio/pull/2241)). Specifically, this removes `local_pairwise_align_ssw`, `StripedSmithWaterman`, and `AlignmentStructure` under `skbio.alignment`. We recommend using the new `skbio.alignment.pair_align` function for pairwise sequence alignment, or other packages that provide production-ready alignment algorithms. See [#1814](https://github.com/biocore/scikit-bio/issues/1814) for discussions. * Removed `skbio.alignment.make_identity_substitution_matrix`. This has been replaced with `skbio.sequence.SubstitutionMatrix.identity`. ## Version 0.6.3 ### Features * Python 3.13+ is now supported ([#2146](https://github.com/scikit-bio/scikit-bio/pull/2146)). * Added Balanced Minimum Evolution (BME) function for phylogenetic reconstruction and `balanced` option for NNI ([#2105](https://github.com/scikit-bio/scikit-bio/pull/2105) and [#2169](https://github.com/scikit-bio/scikit-bio/pull/2169)). * Added functions `rf_dists`, `wrf_dists` and `path_dists` under `skbio.tree` to calculate multiple pariwise distance metrics among an arbitrary number of trees. They correspond to `TreeNode` methods `compare_rfd`, `compare_wrfd` and `compare_cophenet` for two trees ([#2166](https://github.com/scikit-bio/scikit-bio/pull/2166)). * Added `height` and `depth` methods under `TreeNode` to calculate the height and depth of a given node. * Added `TreeNode.compare_wrfd` to calculate the weighted Robinson-Foulds distance or its variants between two trees ([#2144](https://github.com/scikit-bio/scikit-bio/pull/2144)). * Wrapped UPGMA and WPGMA from SciPy's linkage method ([#2094](https://github.com/scikit-bio/scikit-bio/pull/2094)). * Added `TreeNode` methods: `bipart`, `biparts` and `compare_biparts` to encode and compare bipartitions in a tree ([#2144](https://github.com/scikit-bio/scikit-bio/pull/2144)). * Added `TreeNode.has_caches` to check if a tree has caches ([#2103](https://github.com/scikit-bio/scikit-bio/pull/2103)). * Added `TreeNode.is_bifurcating` to check if a tree is bifurcating (i.e., binary) ([#2117](https://github.com/scikit-bio/scikit-bio/pull/2117)). * Added support for Python's `pathlib` module in the IO system ([#2119](https://github.com/scikit-bio/scikit-bio/pull/2119)). * Added `TreeNode.path` to return a list of nodes representing the path from one node to another ([#2131](https://github.com/scikit-bio/scikit-bio/pull/2131)). * Exposed `vectorize_counts_and_tree` function from the `diversity` module to allow use for improving ML accuracy in downstream pipelines ([#2173](https://github.com/scikit-bio/scikit-bio/pull/2173)) ### Performance enhancements * Significantly improved the performance of the neighbor joining (NJ) algorithm (`nj`) ([#2147](https://github.com/scikit-bio/scikit-bio/pull/2147)) and the greedy minimum evolution (GME) algorithm (`gme`) for phylogenetic reconstruction, and the NNI algorithm for tree rearrangement ([#2169](https://github.com/scikit-bio/scikit-bio/pull/2169)). * Significantly improved the performance of `TreeNode.cophenet` (renamed from `tip_tip_distances`) for computing a patristic distance matrix among all or selected tips of a tree ([#2152](https://github.com/scikit-bio/scikit-bio/pull/2152)). * Supported Robinson-Foulds distance calculation (`TreeNode.compare_rfd`) based on bipartitions (equivalent to `compare_biparts`). This is automatically enabled when the input tree is unrooted. Otherwise the calculation is still based on subsets (equivalent to `compare_subsets`). The user can override this behavior using the `rooted` parameter ([#2144](https://github.com/scikit-bio/scikit-bio/pull/2144)). * Re-wrote the underlying algorithm of `TreeNode.compare_subsets` because it is equivalent to the Robinson-Foulds distance on rooted trees. Added parameter `proportion`. Renamed parameter `exclude_absent_taxa` as `shared_only` ([#2144](https://github.com/scikit-bio/scikit-bio/pull/2144)). * Added parameter `include_self` to `TreeNode.subset`. Added parameters `within`, `include_full` and `include_tips` to `TreeNode.subsets` ([#2144](https://github.com/scikit-bio/scikit-bio/pull/2144)). * Improved the performance and customizability of `TreeNode.total_length` (renamed from `descending_branch_length`). Added parameters `include_stem` and `include_self`. * Improved the performance of `TreeNode.lca` ([#2132](https://github.com/scikit-bio/scikit-bio/pull/2132)). * Improved the performance of `TreeNode` methods: `ancestors`, `siblings`, and `neighbors` ([#2133](https://github.com/scikit-bio/scikit-bio/pull/2133), [#2135](https://github.com/scikit-bio/scikit-bio/pull/2135)). * Improved the performance of tree traversal algorithms ([#2093](https://github.com/scikit-bio/scikit-bio/pull/2093)). * Improved the performance of tree copying ([#2103](https://github.com/scikit-bio/scikit-bio/pull/2103)). * Further improved the caching mechanism of `TreeNode`. Specifically: 1. Node attribute caches are only registered at the root node, which improves memory efficiency. 2. Method `clear_caches` can be customized to clear node attribute and/or lookup caches, or specified attribute caches ([#2099](https://github.com/scikit-bio/scikit-bio/pull/2099)). 3. Added parameter `uncache` to multiple methods that involves tree manipulation. Default is True. When one knows that caches are not present or relevant, one may set this parameter as False to skip cache clearing to significantly improve performance ([#2103](https://github.com/scikit-bio/scikit-bio/pull/2103)). * Expanded the functionality of `TreeNode.cache_attr`. It can now take a custom function to combine children and self attributes. This makes it possible to cache multiple useful clade properties such as node count and total branch length. Also enriched the method's docstring to provide multiple examples of caching clade properties ([#2099](https://github.com/scikit-bio/scikit-bio/pull/2099)). * Added parameter `inplace` to methods `shear`, `root_at`, `root_at_midpoint` and `root_by_outgroup` of `TreeNode` to enable manipulating the tree in place (True), which is more efficient that making a manipulated copy of the tree (False, default) ([#2103](https://github.com/scikit-bio/scikit-bio/pull/2103)). * `TreeNode.extend` can accept any iterable type of nodes as input ([#2103](https://github.com/scikit-bio/scikit-bio/pull/2103)). * Added parameter `strict` to `TreeNode.shear` ([#2103](https://github.com/scikit-bio/scikit-bio/pull/2103)). * Added parameter `exclude_attrs` to `TreeNode.unrooted_copy` ([#2103](https://github.com/scikit-bio/scikit-bio/pull/2103)). * Added support for legacy random generator to `get_rng`, such that outputs of scikit-bio functions become reproducible with code that starts with `np.random.seed` or uses `RandomState` ([#2130](https://github.com/scikit-bio/scikit-bio/pull/2130)). * Allowed `shuffle` and `compare_cophenet` (renamed from `compare_tip_distances`) of `TreeNode` to accept a random seed or random generator to generate the shuffling function, which ensures output reproducibility ([#2118](https://github.com/scikit-bio/scikit-bio/pull/2118)). * Replaced `accumulate_to_ancestor` with `depth` under `TreeNode`. The latter has expanded functionality which covers the default behavior of the former. * Added beta diversity metric `jensenshannon`, which calculates Jensen-Shannon distance. Thank @quliping for suggesting this in [#2125](https://github.com/scikit-bio/scikit-bio/pull/2125). * Added parameter `include_self` to `TreeNode.ancestors` to optionally include the initial node in the path (default: False) ([#2135](https://github.com/scikit-bio/scikit-bio/pull/2135)). * Added parameter `seed` to functions `pcoa`, `anosim`, `permanova`, `permdisp`, `randdm`, `lladser_pe`, `lladser_ci`, `isubsample`, `subsample_power`, `subsample_paired_power`, `paired_subsamples` and `hommola_cospeciation` to accept a random seed or random generator to ensure output reproducibility ([#2120](https://github.com/scikit-bio/scikit-bio/pull/2120) and [#2129](https://github.com/scikit-bio/scikit-bio/pull/2129)). * Made the `IORegistry` sniffer only attempt file formats which are logical given a specific object, thus improving reading efficiency. * Allowed the `number_of_dimensions` parameter in the function `pcoa` to accept float values between 0 and 1 to capture fractional cumulative variance. ### Bug fixes * Fixed a bug in `TreeNode.find` which returns the input node object even if it's not in the current tree ([#2153](https://github.com/scikit-bio/scikit-bio/pull/2153)). * Fixed a bug in `TreeNode.get_max_distance` which returns tip names instead of tip instances when there are single-child nodes in the tree ([#2144](https://github.com/scikit-bio/scikit-bio/pull/2144)). * Fixed an issue in `subsets` and `cophenet` (renamed from `tip_tip_distances`) of `TreeNode` which leaves remnant attributes at each node after execution ([#2144](https://github.com/scikit-bio/scikit-bio/pull/2144)). * Fixed a bug in `TreeNode.compare_rfd` which raises an error if taxa of the two trees are not subsets of each other ([#2144](https://github.com/scikit-bio/scikit-bio/pull/2144)). * Fixed a bug in `TreeNode.compare_subsets` which includes the full set (not a subset) of shared taxa between two trees if a basal clade of either tree consists of entirely unshared taxa ([#2144](https://github.com/scikit-bio/scikit-bio/pull/2144)). * Fixed a bug in `TreeNode.lca` which returns the parent of input node X instead of X itself if X is ancestral to other input nodes ([#2132](https://github.com/scikit-bio/scikit-bio/pull/2132)). * Fixed a bug in `TreeNode.find_all` which does not look for other nodes with the same name if a `TreeNode` instance is provided, as in contrast to what the documentation claims ([#2099](https://github.com/scikit-bio/scikit-bio/pull/2099)). * Fixed a bug in `skbio.io.format.embed` which was not correctly updating the idptr sizing. ([#2100](https://github.com/scikit-bio/scikit-bio/pull/2100)). * Fixed a bug in `TreeNode.unrooted_move` which does not respect specified branch attributes ([#2103](https://github.com/scikit-bio/scikit-bio/pull/2103)). * Fixed a bug in `skbio.diversity.get_beta_diversity_metrics` which does not display metrics other than UniFrac ([#2126](https://github.com/scikit-bio/scikit-bio/pull/2126)). * Raises an error when beta diversity metric `mahalanobis` is called but sample number is smaller than or equal to feature number in the data. Thank @quliping for noting this in [#2125](https://github.com/scikit-bio/scikit-bio/pull/2125). * Fixed a bug in `io.format.fasta` that improperly handled sequences containing spaces. ([#2156](https://github.com/scikit-bio/scikit-bio/pull/2156)) ### Miscellaneous * Added a parameter `warn_neg_eigval` to `pcoa` and `permdisp` to control when to raise a warning when negative eigenvalues are encountered. The default setting is more relaxed than the previous behavior, therefore warnings will not be raised when the negative eigenvalues are small in magnitude, which is the case in many real-world scenarios [#2154](https://github.com/scikit-bio/scikit-bio/pull/2154). * Refactored `dirmult_ttest` to use a separate function for fitting data to Dirichlet-multinomial distribution ([#2113](https://github.com/scikit-bio/scikit-bio/pull/2113)) * Remodeled documentation. Special methods (previously referred to as built-in methods) and inherited methods of a class no longer have separate stub pages. This significantly reduced the total number of webpages in the documentation ([#2110](https://github.com/scikit-bio/scikit-bio/pull/2110)). * Renamed `invalidate_caches` as `clear_caches` under `TreeNode`, because the caches are indeed deleted rather than marked as obsolete. The old name is preserved as an alias ([#2099](https://github.com/scikit-bio/scikit-bio/pull/2099)). * Renamed `remove_deleted` as `remove_by_func` under `TreeNode`. The old name is preserved as an alias ([#2103](https://github.com/scikit-bio/scikit-bio/pull/2103)). * Renamed `descending_branch_length` as `total_length` under `TreeNode`. The old name is preserved as an alias. * Under `TreeNode`, renamed `get_max_distance` as `maxdist`. Renamed `tip_tip_distances` as `cophenet`. Renamed `compare_tip_distances` as `compare_cophenet`. The new names are consistent with SciPy's relevant functions and the main body of the literature. The old names are preserved as aliases. ### Deprecated functionality * Method `TreeNode.subtree` is deprecated. It will become a private member in version 0.7.0 ([#2103](https://github.com/scikit-bio/scikit-bio/pull/2103)). ### Backward-incompatible changes * Dropped support for Python 3.8 as it has reached end-of-life (EOL). scikit-bio may still be installed under Python 3.8 and will likely work, but the development team no longer guarantee that all functionality will work as intended. * Removed `skbio.util.SkbioWarning`. Now there are no specific warnings to scikit-bio. * Removed `skbio.util.EfficiencyWarning`. Previously it was only used in the Python implementations of pairwise sequence alignment algorithms. The new code replaced it with `PendingDeprecationWarning`. * Removed `skbio.util.RepresentationWarning`. Previously it was only used in `TreeNode.tip_tip_distances` when a node has no branch length. The new code removed this behavior ([#2152](https://github.com/scikit-bio/scikit-bio/pull/2152)). ## Version 0.6.2 ### Features * Added Greedy Minimum Evolution (GME) function for phylogenetic reconstruction ([#2087](https://github.com/scikit-bio/scikit-bio/pull/2087)). * Added support for Microsoft Windows operating system. ([#2071](https://github.com/scikit-bio/scikit-bio/pull/2071), [#2068](https://github.com/scikit-bio/scikit-bio/pull/2068), [#2067](https://github.com/scikit-bio/scikit-bio/pull/2067), [#2061](https://github.com/scikit-bio/scikit-bio/pull/2061), [#2046](https://github.com/scikit-bio/scikit-bio/pull/2046), [#2040](https://github.com/scikit-bio/scikit-bio/pull/2040), [#2036](https://github.com/scikit-bio/scikit-bio/pull/2036), [#2034](https://github.com/scikit-bio/scikit-bio/pull/2034), [#2032](https://github.com/scikit-bio/scikit-bio/pull/2032), [#2005](https://github.com/scikit-bio/scikit-bio/pull/2005)) * Added alpha diversity metrics: Hill number (`hill`), Renyi entropy (`renyi`) and Tsallis entropy (`tsallis`) ([#2074](https://github.com/scikit-bio/scikit-bio/pull/2074)). * Added `rename` method for `OrdinationResults` and `DissimilarityMatrix` classes ([#2027](https://github.com/scikit-bio/scikit-bio/pull/2027), [#2085](https://github.com/scikit-bio/scikit-bio/pull/2085)). * Added `nni` function for phylogenetic tree rearrangement using nearest neighbor interchange (NNI) ([#2050](https://github.com/scikit-bio/scikit-bio/pull/2050)). * Added method `TreeNode.unrooted_move`, which resembles `TreeNode.unrooted_copy` but rearranges the tree in place, thus avoid making copies of the nodes ([#2073](https://github.com/scikit-bio/scikit-bio/pull/2073)). * Added method `TreeNode.root_by_outgroup`, which reroots a tree according to a given outgroup ([#2073](https://github.com/scikit-bio/scikit-bio/pull/2073)). * Added method `TreeNode.unroot`, which converts a rooted tree into unrooted by trifucating its root ([#2073](https://github.com/scikit-bio/scikit-bio/pull/2073)). * Added method `TreeNode.insert`, which inserts a node into the branch connecting self and its parent ([#2073](https://github.com/scikit-bio/scikit-bio/pull/2073)). ### Performance enhancements * The time and memory efficiency of `TreeNode` has been significantly improved by making its caching mechanism lazy ([#2082](https://github.com/scikit-bio/scikit-bio/pull/2082)). * `Treenode.copy` and `TreeNode.unrooted_copy` can now perform shallow copy of a tree in addition to deep copy. * `TreeNode.unrooted_copy` can now copy all attributes of the nodes, in addition to name and length ([#2073](https://github.com/scikit-bio/scikit-bio/pull/2073)). * Paremter `above` was added to `TreeNode.root_at`, such that the user can root the tree within the branch connecting the given node and its parent, thereby creating a rooted tree ([#2073](https://github.com/scikit-bio/scikit-bio/pull/2073)). * Parameter `branch_attrs` was added to the `unrooted_copy`, `root_at`, and `root_at_midpoint` methods of `TreeNode`, such that the user can customize which node attributes should be considered as branch attributes and treated accordingly during the rerooting operation. The default behavior is preserved but is subject ot change in version 0.7.0 ([#2073](https://github.com/scikit-bio/scikit-bio/pull/2073)). * Parameter `root_name` was added to the `unrooted_copy`, `root_at`, and `root_at_midpoint` methods of `TreeNode`, such that the user can customize (or omit) the name to be given to the root node. The default behavior is preserved but is subject ot change in version 0.7.0 ([#2073](https://github.com/scikit-bio/scikit-bio/pull/2073)). ### Bug fixes * Cleared the internal node references after performing midpoint rooting (`TreeNode.root_at_midpoint`), such that a deep copy of the resulting tree will not result in infinite recursion ([#2073](https://github.com/scikit-bio/scikit-bio/pull/2073)). * Fixed the Zenodo link in the README to always point to the most recent version ([#2078](https://github.com/scikit-bio/scikit-bio/pull/2078)). ### Miscellaneous * Added statsmodels as a dependency of scikit-bio. It replaces some of the from-scratch statistical analyses in scikit-bio, including Welch's t-test (with confidence intervals), Benjamini-Hochberg FDR correction, and Holm-Bonferroni FDR correction ([#2049](https://github.com/scikit-bio/scikit-bio/pull/2049), ([#2063](https://github.com/scikit-bio/scikit-bio/pull/2063))). ### Deprecated functionality * Methods `deepcopy` and `unrooted_deepcopy` of `Treenode` are deprecated. Use `copy` and `unrooted_copy` instead. ## Version 0.6.1 ### Features * NumPy 2.0 is now supported ([#2051](https://github.com/scikit-bio/scikit-bio/pull/2051])). We thank @rgommers 's advice on this ([#1964](https://github.com/scikit-bio/scikit-bio/issues/1964)). * Added module `skbio.embedding` to provide support for storing and manipulating embeddings for biological objects, such as protein embeddings outputted from protein language models ([#2008](https://github.com/scikit-bio/scikit-bio/pull/2008])). * Added an efficient sequence alignment path data structure `AlignPath` and its derivative `PairAlignPath` to provide a uniform interface for various multiple and pariwise alignment formats ([#2011](https://github.com/scikit-bio/scikit-bio/pull/2011)). * Added `simpson_d` as an alias for `dominance` (Simpson's dominance index, a.k.a. Simpson's D) ([#2024](https://github.com/scikit-bio/scikit-bio/pull/2024)). * Added `inv_simpson` (inverse Simpson index), which is equivalent to `enspie` ([#2024](https://github.com/scikit-bio/scikit-bio/pull/2024)). * Added parameter `exp` to `shannon` to calculate the exponential of Shannon index (i.e., perplexity, or effective number of species) ([#2024](https://github.com/scikit-bio/scikit-bio/pull/2024)). * Added parameter `finite` to Simpson's _D_ (`dominance`) and derived metrics (`simpson`, `simpson_e` and `inv_simpson`) to correct for finite samples ([#2024](https://github.com/scikit-bio/scikit-bio/pull/2024)). * Added support for dictionary and pandas DataFrame as input for `TreeNode.from_taxonomy` ([#2042](https://github.com/scikit-bio/scikit-bio/pull/2042)). ### Performance enhancements * `subsample_counts` now uses an optimized method from `biom-format` ([#2016](https://github.com/scikit-bio/scikit-bio/pull/2016)). * Improved efficiency of counts matrix and vector validation prior to calculating community diversity metrics ([#2024](https://github.com/scikit-bio/scikit-bio/pull/2024)). ### Miscellaneous * Default logarithm base of Shannon index (`shannon`) was changed from 2 to e. This is to ensure consistency with other Shannon-based metrics (`pielou_e`), and with literature and implementations in the field. Meanwhile, parameter `base` was added to `pielou_e` such that the user can control this behavior ([#2024](https://github.com/scikit-bio/scikit-bio/pull/2024)). See discussions in [1884](https://github.com/scikit-bio/scikit-bio/issues/1884) and [2014](https://github.com/scikit-bio/scikit-bio/issues/2014). * Improved treatment of empty communities (i.e., all taxa have zero counts, or there is no taxon) when calculating alpha diversity metrics. Most metrics will return `np.nan` and do not raise a warning due to zero division. Exceptions are metrics that describe observed counts, includng `sobs`, `singles`, `doubles` and `osd`, which return zero ([#2024](https://github.com/scikit-bio/scikit-bio/pull/2024)). See discussions in [#2014](https://github.com/scikit-bio/scikit-bio/issues/2014). * Return values of `pielou_e` and `heip_e` were set to 1.0 for one-taxon communities, such that NaN is avoided, while honoring the definition (evenness of taxon abundance(s)) and the rationale (ratio between observed and maximum) ([#2024](https://github.com/scikit-bio/scikit-bio/pull/2024)). * Removed hdmedians as a dependency by porting its `geomedian` function (geometric median) into scikit-bio ([#2003](https://github.com/scikit-bio/scikit-bio/pull/2003)). * Removed 98% warnings issued during the test process ([#2045](https://github.com/scikit-bio/scikit-bio/pull/2045) and [#2037](https://github.com/scikit-bio/scikit-bio/pull/2037)). ## Version 0.6.0 ### Performance enhancements * Launched the new scikit-bio website: https://scikit.bio. The previous domain names _scikit-bio.org_ and _skbio.org_ continue to work and redirect to the new website. * Migrated the scikit-bio website repo from the `gh-pages` branch of the `scikit-bio` repo to a standalone repo: [`scikit-bio.github.io`](https://github.com/scikit-bio/scikit-bio.github.io). * Replaced the [Bootstrap theme](https://sphinx-bootstrap-theme.readthedocs.io/en/latest/) with the [PyData theme](https://pydata-sphinx-theme.readthedocs.io/en/stable/) for building documentation using Sphinx. Extended this theme to the website. Customized design elements ([#1934](https://github.com/scikit-bio/scikit-bio/pull/1934)). * Improved the calculation of Fisher's alpha diversity index (`fisher_alpha`). It is now compatible with optimizers in SciPy 1.11+. Edge cases such as all singletons can be handled correctly. Handling of errors and warnings was improved. Documentation was enriched ([#1890](https://github.com/scikit-bio/scikit-bio/pull/1890)). * Allowed `delimiter=None` which represents whitespace of arbitrary length in reading lsmat format matrices ([#1912](https://github.com/scikit-bio/scikit-bio/pull/1912)). ### Features * Added biom-format Table import and updated corresponding requirement files ([#1907](https://github.com/scikit-bio/scikit-bio/pull/1907)). * Added biom-format 2.1.0 IO support ([#1984](https://github.com/scikit-bio/scikit-bio/pull/1984)). * Added `Table` support to `alpha_diversity` and `beta_diversity` drivers ([#1984](https://github.com/scikit-bio/scikit-bio/pull/1984)). * Implemented a mechanism to automatically build documentation and/or homepage and deploy them to the website ([#1934](https://github.com/scikit-bio/scikit-bio/pull/1934)). * Added the Benjamini-Hochberg method as an option for FDR correction (in addition to the existing Holm-Bonferroni method) for `ancom` and `dirmult_ttest` ([#1988](https://github.com/scikit-bio/scikit-bio/pull/1988)). * Added function `dirmult_ttest`, which performs differential abundance test using a Dirichilet multinomial distribution. This function mirrors the method provided by ALDEx2 ([#1956](https://github.com/scikit-bio/scikit-bio/pull/1956)). * Added method `Sequence.to_indices` to convert a sequence into a vector of indices of characters in an alphabet (can be from a substitution matrix) or unique characters observed in the sequence. Supports gap masking and wildcard substitution ([#1917](https://github.com/scikit-bio/scikit-bio/pull/1917)). * Added class `SubstitutionMatrix` to support substitution matrices for nucleotides, amino acids are more general cases ([#1913](https://github.com/scikit-bio/scikit-bio/pull/1913)). * Added alpha diversity metric `sobs`, which is the observed species richness (S_{obs}) of a sample. `sobs` will replace `observed_otus`, which uses the historical term "OTU". Also added metric `observed_features` to be compatible with the QIIME 2 terminology. All three metrics are equivalent ([#1902](https://github.com/scikit-bio/scikit-bio/pull/1902)). * `beta_diversity` now supports use of Pandas a `DataFrame` index, issue [#1808](https://github.com/scikit-bio/scikit-bio/issues/1808). * Added alpha diversity metric `phydiv`, which is a generalized phylogenetic diversity (PD) framework permitting unrooted or rooted tree, unweighted or weighted by abundance, and an exponent parameter of the weight term ([#1893](https://github.com/scikit-bio/scikit-bio/pull/1893)). * Adopted NumPy's new random generator `np.random.Generator` (see [NEP 19](https://numpy.org/neps/nep-0019-rng-policy.html)) ([#1889](https://github.com/scikit-bio/scikit-bio/pull/1889)). * SciPy 1.11+ is now supported ([#1887](https://github.com/scikit-bio/scikit-bio/pull/1887)). * Removed IPython as a dependency. Scikit-bio continues to support displaying plots in IPython, but it no longer requires importing IPython functionality ([#1901](https://github.com/scikit-bio/scikit-bio/pull/1901)). * Made Matplotlib an optional dependency. Scikit-bio no longer requires Matplotlib except for plotting, during which it attempts to import Matplotlib if it is present in the system, and raises an error if not ([#1901](https://github.com/scikit-bio/scikit-bio/pull/1901)). * Ported the QIIME 2 metadata object into skbio. ([#1929](https://github.com/scikit-bio/scikit-bio/pull/1929)) * Python 3.12+ is now supported, thank you @actapia ([#1930](https://github.com/scikit-bio/scikit-bio/pull/1930)) * Introduced native character conversion ([#1971])(https://github.com/scikit-bio/scikit-bio/pull/1971) ### Backward-incompatible changes [experimental] * Beta diversity metric `kulsinski` was removed. This was motivated by that SciPy replaced this distance metric with `kulczynski1` in version 1.11 (see SciPy issue [#2009](https://github.com/scipy/scipy/issues/2009)), and that both metrics do not return 0 on two identical vectors ([#1887](https://github.com/scikit-bio/scikit-bio/pull/1887)). ### Bug fixes * Fixed documentation interface of `vlr` and relevant functions ([#1934](https://github.com/scikit-bio/scikit-bio/pull/1934)). * Fixed broken link in documentation of Simpson's evenness index. See issue [#1923](https://github.com/scikit-bio/scikit-bio/issues/1923). * Safely handle `Sequence.iter_kmers` where `k` is greater than the sequence length ([#1723](https://github.com/scikit-bio/scikit-bio/issues/1723)) * Re-enabled OpenMP support, which has been mistakenly disabled in 0.5.8 ([#1874](https://github.com/scikit-bio/scikit-bio/pull/1874)) * `permanova` and `permdist` operate on a `DistanceMatrix` and a grouping object. Element IDs must be synchronized to compare correct sets of pairwise distances. This failed in case the grouping was provided as a `pandas.Series`, because it was interpreted as an ordered `list` and indices were ignored (see issue [#1877](https://github.com/scikit-bio/scikit-bio/issues/1877) for an example). Note: `pandas.DataFrame` was handled correctly. This behavior has been fixed with PR [#1879](https://github.com/scikit-bio/scikit-bio/pull/1879) * Fixed slicing for `TabularMSALoc` on Python 3.12. See issue [#1926](https://github.com/scikit-bio/scikit-bio/issues/1926). ### Miscellaneous * Replaced the historical term "OTU" with the more generic term "taxon" (plural: "taxa"). As a consequence, the parameter "otu_ids" in phylogenetic alpha and beta diversity metrics was replaced by "taxa". Meanwhile, the old parameter "otu_ids" is still kept as an alias of "taxa" for backward compatibility. However it will be removed in a future release. * Revised contributor's guidelines. * Renamed function `multiplicative_replacement` as `multi_replace` for conciseness ([#1988](https://github.com/scikit-bio/scikit-bio/pull/1988)). * Renamed parameter `multiple_comparisons_correction` as `p_adjust` of function `ancom` for conciseness ([#1988](https://github.com/scikit-bio/scikit-bio/pull/1988)). * Enabled code coverage reporting via Codecov. See [#1954](https://github.com/scikit-bio/scikit-bio/pull/1954). * Renamed the default branch from "master" to "main". See [#1953](https://github.com/scikit-bio/scikit-bio/pull/1953). * Enabled subclassing of DNA, RNA and Protein classes to allow secondary development. * Dropped support for NumPy < 1.17.0 in order to utilize the new random generator. * Use CYTHON by default during build ([#1874](https://github.com/scikit-bio/scikit-bio/pull/1874)) * Implemented augmented assignments proposed in issue [#1789](https://github.com/scikit-bio/scikit-bio/issues/1789) * Incorporated Ruff's formatting and linting via pre-commit hooks and GitHub Actions. See PR [#1924](https://github.com/scikit-bio/scikit-bio/pull/1924). * Improved docstrings for functions accross the entire codebase. See [#1933](https://github.com/scikit-bio/scikit-bio/pull/1933) and [#1940](https://github.com/scikit-bio/scikit-bio/pull/1940) * Removed API lifecycle decorators in favor of deprecation warnings. See [#1916](https://github.com/scikit-bio/scikit-bio/issues/1916) ## Version 0.5.9 ### Features * Adding Variance log ratio estimators in `skbio.stats.composition.vlr` and `skbio.stats.composition.pairwise_vlr` ([#1803](https://github.com/scikit-bio/scikit-bio/pull/1803)) * Added `skbio.stats.composition.tree_basis` to construct ILR bases from `TreeNode` objects. ([#1862](https://github.com/scikit-bio/scikit-bio/pull/1862)) * `IntervalMetadata.query` now defaults to obtaining all results, see [#1817](https://github.com/scikit-bio/scikit-bio/issues/1817). ### Backward-incompatible changes [experimental] * With the introduction of the `tree_basis` object, the ILR bases are now represented in log-odds coordinates rather than in probabilities to minimize issues with numerical stability. Furthermore, the `ilr` and `ilr_inv` functions now takes the `basis` input parameter in terms of log-odds coordinates. This affects the `skbio.stats.composition.sbp_basis` as well. ([#1862](https://github.com/scikit-bio/scikit-bio/pull/1862)) ### Important * Complex multiple axis indexing operations with `TabularMSA` have been removed from testing due to incompatibilities with modern versions of Pandas. ([#1851](https://github.com/scikit-bio/scikit-bio/pull/1851)) * Pinning `scipy <= 1.10.1` ([#1851](https://github.com/scikit-bio/scikit-bio/pull/1867)) ### Bug fixes * Fixed a bug that caused build failure on the ARM64 microarchitecture due to floating-point number handling. ([#1859](https://github.com/scikit-bio/scikit-bio/pull/1859)) * Never let the Gini index go below 0.0, see [#1844](https://github.com/scikit-bio/scikit-bio/issue/1844). * Fixed bug [#1847](https://github.com/scikit-bio/scikit-bio/issues/1847) in which the edge from the root was inadvertantly included in the calculation for `descending_branch_length` ### Miscellaneous * Replaced dependencies `CacheControl` and `lockfile` with `requests` to avoid a dependency inconsistency issue of the former. (See [#1863](https://github.com/scikit-bio/scikit-bio/pull/1863), merged in [#1859](https://github.com/scikit-bio/scikit-bio/pull/1859)) * Updated installation instructions for developers in `CONTRIBUTING.md` ([#1860](https://github.com/scikit-bio/scikit-bio/pull/1860)) ## Version 0.5.8 ### Features * Added NCBI taxonomy database dump format (`taxdump`) ([#1810](https://github.com/scikit-bio/scikit-bio/pull/1810)). * Added `TreeNode.from_taxdump` for converting taxdump into a tree ([#1810](https://github.com/scikit-bio/scikit-bio/pull/1810)). * scikit-learn has been removed as a dependency. This was a fairly heavy-weight dependency that was providing minor functionality to scikit-bio. The critical components have been implemented in scikit-bio directly, and the non-criticial components are listed under "Backward-incompatible changes [experimental]". * Python 3.11 is now supported. ### Backward-incompatible changes [experimental] * With the removal of the scikit-learn dependency, three beta diversity metric names can no longer be specified. These are `wminkowski`, `nan_euclidean`, and `haversine`. On testing, `wminkowski` and `haversine` did not work through `skbio.diversity.beta_diversity` (or `sklearn.metrics.pairwise_distances`). The former was deprecated in favor of calling `minkowski` with a vector of weights provided as kwarg `w` (example below), and the latter does not work with data of this shape. `nan_euclidean` can still be accessed fron scikit-learn directly if needed, if a user installs scikit-learn in their environment (example below). ``` counts = [[23, 64, 14, 0, 0, 3, 1], [0, 3, 35, 42, 0, 12, 1], [0, 5, 5, 0, 40, 40, 0], [44, 35, 9, 0, 1, 0, 0], [0, 2, 8, 0, 35, 45, 1], [0, 0, 25, 35, 0, 19, 0], [88, 31, 0, 5, 5, 5, 5], [44, 39, 0, 0, 0, 0, 0]] # new mechanism of accessing wminkowski from skbio.diversity import beta_diversity beta_diversity("minkowski", counts, w=[1,1,1,1,1,1,2]) # accessing nan_euclidean through scikit-learn directly import skbio from sklearn.metrics import pairwise_distances sklearn_dm = pairwise_distances(counts, metric="nan_euclidean") skbio_dm = skbio.DistanceMatrix(sklearn_dm) ``` ### Deprecated functionality [experimental] * `skbio.alignment.local_pairwise_align_ssw` has been deprecated ([#1814](https://github.com/scikit-bio/scikit-bio/issues/1814)) and will be removed or replaced in scikit-bio 0.6.0. ### Bug fixes * Use `oldest-supported-numpy` as build dependency. This fixes problems with environments that use an older version of numpy than the one used to build scikit-bio ([#1813](https://github.com/scikit-bio/scikit-bio/pull/1813)). ## Version 0.5.7 ### Features * Introduce support for Python 3.10 ([#1801](https://github.com/scikit-bio/scikit-bio/pull/1801)). * Tentative support for Apple M1 ([#1709](https://github.com/scikit-bio/scikit-bio/pull/1709)). * Added support for reading and writing a binary distance matrix object format. ([#1716](https://github.com/scikit-bio/scikit-bio/pull/1716)) * Added support for `np.float32` with `DissimilarityMatrix` objects. * Added support for method and number_of_dimensions to permdisp reducing the runtime by 100x at 4000 samples, [issue #1769](https://github.com/scikit-bio/scikit-bio/pull/1769). * OrdinationResults object is now accepted as input for permdisp. ### Performance enhancements * Avoid an implicit data copy on construction of `DissimilarityMatrix` objects. * Avoid validation on copy of `DissimilarityMatrix` and `DistanceMatrix` objects, see [PR #1747](https://github.com/scikit-bio/scikit-bio/pull/1747) * Use an optimized version of symmetry check in DistanceMatrix, see [PR #1747](https://github.com/scikit-bio/scikit-bio/pull/1747) * Avoid performing filtering when ids are identical, see [PR #1752](https://github.com/scikit-bio/scikit-bio/pull/1752) * center_distance_matrix has been re-implemented in cython for both speed and memory use. Indirectly speeds up pcoa [PR #1749](https://github.com/scikit-bio/scikit-bio/pull/1749) * Use a memory-optimized version of permute in DistanceMatrix, see [PR #1756](https://github.com/scikit-bio/scikit-bio/pull/1756). * Refactor pearson and spearman skbio.stats.distance.mantel implementations to drastically improve memory locality. Also cache intermediate results that are invariant across permutations, see [PR #1756](https://github.com/scikit-bio/scikit-bio/pull/1756). * Refactor permanova to remove intermediate buffers and cythonize the internals, see [PR #1768](https://github.com/scikit-bio/scikit-bio/pull/1768). ### Bug fixes * Fix windows and 32bit incompatibility in `unweighted_unifrac`. ### Miscellaneous * Python 3.6 has been removed from our testing matrix. * Specify build dependencies in pyproject.toml. This allows the package to be installed without having to first manually install numpy. * Update hdmedians package to a version which doesn't require an initial manual numpy install. * Now buildable on non-x86 platforms due to use of the [SIMD Everywhere](https://github.com/simd-everywhere/simde) library. * Regenerate Cython wrapper by default to avoid incompatibilities with installed CPython. * Update documentation for the `skbio.stats.composition.ancom` function. ([#1741](https://github.com/scikit-bio/scikit-bio/pull/1741)) ## Version 0.5.6 ### Features * Added option to return a capture group compiled regex pattern to any class inheriting ``GrammaredSequence`` through the ``to_regex`` method. ([#1431](https://github.com/scikit-bio/scikit-bio/issues/1431)) * Added `Dissimilarity.within` and `.between` to obtain the respective distances and express them as a `DataFrame`. ([#1662](https://github.com/scikit-bio/scikit-bio/pull/1662)) * Added Kendall Tau as possible correlation method in the `skbio.stats.distance.mantel` function ([#1675](https://github.com/scikit-bio/scikit-bio/issues/1675)). * Added support for IUPAC amino acid codes U (selenocysteine), O (pyrrolysine), and J (leucine or isoleucine). ([#1576](https://github.com/scikit-bio/scikit-bio/issues/1576) ### Backward-incompatible changes [stable] ### Backward-incompatible changes [experimental] * Changed `skbio.tree.TreeNode.support` from a method to a property. * Added `assign_supports` method to `skbio.tree.TreeNode` to extract branch support values from node labels. * Modified the way a node's label is printed: `support:name` if both exist, or `support` or `name` if either exists. ### Performance enhancements ### Bug fixes * Require `Sphinx <= 3.0`. Newer Sphinx versions caused build errors. [#1719](https://github.com/scikit-bio/scikit-bio/pull/1719) * * `skbio.stats.ordination` tests have been relaxed. ([#1713](https://github.com/scikit-bio/scikit-bio/issues/1713)) * Fixes build errors for newer versions of NumPy, Pandas, and SciPy. * Corrected a criticial bug in `skbio.alignment.StripedSmithWaterman`/`skbio.alignment.local_pairwise_align_ssw` which would cause the formatting of the aligned sequences to misplace gap characters by the number of gap characters present in the opposing aligned sequence up to that point. This was caused by a faulty implementation of CIGAR string parsing, see [#1679](https://github.com/scikit-bio/scikit-bio/pull/1679) for full details. * Fixes build errors for newer versions of NumPy, Pandas, and SciPy. * Corrected a criticial bug in `skbio.alignment.StripedSmithWaterman`/`skbio.alignment.local_pairwise_align_ssw` which would cause the formatting of the aligned sequences to misplace gap characters by the number of gap characters present in the opposing aligned sequence up to that point. This was caused by a faulty implementation of CIGAR string parsing, see [#1679](https://github.com/scikit-bio/scikit-bio/pull/1679) for full details. ### Deprecated functionality [stable] ### Deprecated functionality [experimental] ### Miscellaneous * `skbio.diversity.beta_diversity` now accepts a pandas DataFrame as input. * Avoid pandas 1.0.0 import warning ([#1688](https://github.com/scikit-bio/scikit-bio/issues/1688)) * Added support for Python 3.8 and dropped support for Python 3.5. * This version now depends on `scipy >= 1.3` and `pandas >= 1.0`. ## Version 0.5.5 (2018-12-10) ### Features * `skbio.stats.composition` now has methods to compute additive log-ratio transformation and inverse additive log-ratio transformation (`alr`, `alr_inv`) as well as a method to build a basis from a sequential binary partition (`sbp_basis`). ### Backward-incompatible changes [stable] ### Backward-incompatible changes [experimental] ### Performance enhancements ### Bug fixes ### Deprecated functionality [stable] ### Deprecated functionality [experimental] ### Miscellaneous * Python 3.6 and 3.7 compatibility is now supported * A pytest runner is shipped with every installation ([#1633](https://github.com/scikit-bio/scikit-bio/pull/1633)) * The nosetest framework has been replaced in favor of pytest ([#1624](https://github.com/scikit-bio/scikit-bio/pull/1624)) * The numpy docs are deprecated in favor of [Napoleon](http://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html) ([#1629](https://github.com/scikit-bio/scikit-bio/pull/1629)) * This version is now compatible with numpy >= 1.17.0 and Pandas >= 0.23. ([#1627](https://github.com/scikit-bio/scikit-bio/pull/1627)) ## Version 0.5.4 (2018-08-23) ### Features * Added `FSVD`, an alternative fast heuristic method to perform Principal Coordinates Analysis, to `skbio.stats.ordination.pcoa`. ### Backward-incompatible changes [stable] ### Backward-incompatible changes [experimental] ### Performance enhancements * Added optimized utility methods `f_matrix_inplace` and `e_matrix_inplace` which perform `f_matrix` and `e_matrix` computations in-place and are used by the new `center_distance_matrix` method in `skbio.stats.ordination`. ### Bug fixes ### Deprecated functionality [stable] ### Deprecated functionality [experimental] ### Miscellaneous ## Version 0.5.3 (2018-08-07) ### Features * Added `unpack` and `unpack_by_func` methods to `skbio.tree.TreeNode` to unpack one or multiple internal nodes. The `unpack` operation removes an internal node and regrafts its children to its parent while retaining the overall length. ([#1572](https://github.com/scikit-bio/scikit-bio/pull/1572)) * Added `support` to `skbio.tree.TreeNode` to return the support value of a node. * Added `permdisp` to `skbio.stats.distance` to test for the homogeniety of groups. ([#1228](https://github.com/scikit-bio/scikit-bio/issues/1228)). * Added `pcoa_biplot` to `skbio.stats.ordination` to project descriptors into a PCoA plot. * Fixed pandas to 0.22.0 due to this: https://github.com/pandas-dev/pandas/issues/20527 ### Backward-incompatible changes [stable] ### Backward-incompatible changes [experimental] ### Performance enhancements ### Bug fixes * Relaxing type checking in diversity calculations. ([#1583](https://github.com/scikit-bio/scikit-bio/issues/1583)). ### Deprecated functionality [stable] ### Deprecated functionality [experimental] ### Miscellaneous ## Version 0.5.2 (2018-04-18) ### Features * Added ``skbio.io.format.embl`` for reading and writing EMBL files for ``DNA``, ``RNA`` and ``Sequence`` classes. * Removing ValueError check in `skbio.stats._subsample.subsample_counts` when `replace=True` and `n` is greater than the number of items in counts. [#1527](https://github.com/scikit-bio/scikit-bio/pull/1527) * Added ``skbio.io.format.gff3`` for reading and writing GFF3 files for ``DNA``, ``Sequence``, and ``IntervalMetadata`` classes. ([#1450](https://github.com/scikit-bio/scikit-bio/pull/1450)) * `skbio.metadata.IntervalMetadata` constructor has a new keyword argument, `copy_from`, for creating an `IntervalMetadata` object from an existing `IntervalMetadata` object with specified `upper_bound`. * `skbio.metadata.IntervalMetadata` constructor allows `None` as a valid value for `upper_bound`. An `upper_bound` of `None` means that the `IntervalMetadata` object has no upper bound. * `skbio.metadata.IntervalMetadata.drop` has a new boolean parameter `negate` to indicate whether to drop or keep the specified `Interval` objects. ### Backward-incompatible changes [stable] ### Backward-incompatible changes [experimental] ### Performance enhancements * `skbio.tree.nj` wall-clock runtime was decreased by 99% for a 500x500 distance matrix and 93% for a 100x100 distance matrix. ([#1512](https://github.com/scikit-bio/scikit-bio/pull/1512), [#1513](https://github.com/scikit-bio/scikit-bio/pull/1513)) ### Bug fixes * The `include_self` parameter was not being honored in `skbio.TreeNode.tips`. The scope of this bug was that if `TreeNode.tips` was called on a tip, it would always result in an empty `list` when unrolled. * In `skbio.stats.ordination.ca`, `proportion_explained` was missing in the returned `OrdinationResults` object. ([#1345](https://github.com/scikit-bio/scikit-bio/issues/1345)) * `skbio.diversity.beta_diversity` now handles qualitative metrics as expected such that `beta_diversity('jaccard', mat) == beta_diversity('jaccard', mat > 0)`. Please see [#1549](https://github.com/scikit-bio/scikit-bio/issues/1549) for further detail. * `skbio.stats.ordination.rda` The occasional column mismatch in output `biplot_scores` is fixed ([#1519](https://github.com/scikit-bio/scikit-bio/issues/1519)). ### Deprecated functionality [stable] ### Deprecated functionality [experimental] ### Miscellaneous * scikit-bio now depends on pandas >= 0.19.2, and is compatible with newer pandas versions (e.g. 0.20.3) that were previously incompatible. * scikit-bio now depends on `numpy >= 1.17.0, < 1.14.0` for compatibility with Python 3.4, 3.5, and 3.6 and the available numpy conda packages in `defaults` and `conda-forge` channels. * added support for running tests from `setup.py`. Both `python setup.py nosetests` and `python setup.py test` are now supported, however `python setup.py test` will only run a subset of the full test suite. ([#1341](https://github.com/scikit-bio/scikit-bio/issues/1341)) ## Version 0.5.1 (2016-11-12) ### Features * Added `IntervalMetadata` and `Interval` classes in `skbio.metadata` to store, query, and manipulate information of a sub-region of a sequence. ([#1414](https://github.com/scikit-bio/scikit-bio/issues/1414)) * `Sequence` and its child classes (including `GrammaredSequence`, `RNA`, `DNA`, `Protein`) now accept `IntervalMetadata` in their constructor API. Some of their relevant methods are also updated accordingly. ([#1430](https://github.com/scikit-bio/scikit-bio/pull/1430)) * GenBank parser now reads and writes `Sequence` or its subclass objects with `IntervalMetadata`. ([#1440](https://github.com/scikit-bio/scikit-bio/pull/1440)) * `DissimilarityMatrix` now has a new constructor method called `from_iterable`. ([#1343](https://github.com/scikit-bio/scikit-bio/issues/1343)). * `DissimilarityMatrix` now allows non-hollow matrices. ([#1343](https://github.com/scikit-bio/scikit-bio/issues/1343)). * `DistanceMatrix.from_iterable` now accepts a `validate=True` parameter. ([#1343](https://github.com/scikit-bio/scikit-bio/issues/1343)). * ``DistanceMatrix`` now has a new method called ``to_series`` to create a ``pandas.Series`` from a ``DistanceMatrix`` ([#1397](https://github.com/scikit-bio/scikit-bio/issues/1397)). * Added parallel beta diversity calculation support via `skbio.diversity.block_beta_diversity`. The issue and idea is discussed in ([#1181](https://github.com/scikit-bio/scikit-bio/issues/1181), while the actual code changes are in [#1352](https://github.com/scikit-bio/scikit-bio/pull/1352)). ### Backward-incompatible changes [stable] * The constructor API for `Sequence` and its child classes (including `GrammaredSequence`, `RNA`, `DNA`, `Protein`) are changed from `(sequence, metadata=None, positional_metadata=None, lowercase=False)` to `(sequence, metadata=None, positional_metadata=None, interval_metadata=None, lowercase=False)` The changes are made to allow these classes to adopt `IntervalMetadata` object for interval features on the sequence. The `interval_metadata` parameter is added imediately after `positional_metadata` instead of appended to the end, because it is more natural and logical and, more importantly, because it is unlikely in practice to break user code. A user's code would break only if they had supplied `metadata`, `postional_metadata`, and `lowercase` parameters positionally. In the unlikely event that this happens, users will get an error telling them a bool isn't a valid `IntervalMetadata` type, so it won't silently produce buggy behavior. ### Backward-incompatible changes [experimental] * Modifying basis handling in `skbio.stats.composition.ilr_inv` prior to checking for orthogonality. Now the basis is strictly assumed to be in the Aitchison simplex. * `DistanceMatrix.from_iterable` default behavior is now to validate matrix by computing all pairwise distances. Pass `validate=False` to get the previous behavior (no validation, but faster execution).([#1343](https://github.com/scikit-bio/scikit-bio/issues/1343)). * GenBank I/O now parses sequence features into the attribute of `interval_metadata` instead of `positiona_metadata`. And the key of `FEATURES` is removed from `metadata` attribute. ### Performance enhancements * `TreeNode.shear` was rewritten for approximately a 25% performance increase. ([#1399](https://github.com/scikit-bio/scikit-bio/pull/1399)) * The `IntervalMetadata` allows dramatic decrease in memory usage in reading GenBank files of feature rich sequences. ([#1159](https://github.com/scikit-bio/scikit-bio/issues/1159)) ### Bug fixes * `skbio.tree.TreeNode.prune` and implicitly `skbio.tree.TreeNode.shear` were not handling a situation in which a parent was validly removed during pruning operations as may happen if the resulting subtree does not include the root. Previously, an `AttributeError` would raise as `parent` would be `None` in this situation. * numpy linking was fixed for installation under El Capitan. * A bug was introduced in #1398 into `TreeNode.prune` and fixed in #1416 in which, under the special case of a single descendent existing from the root, the resulting children parent references were not updated. The cause of the bug was a call made to `self.children.extend` as opposed to `self.extend` where the former is a `list.extend` without knowledge of the tree, while the latter is `TreeNode.extend` which is able to adjust references to `self.parent`. ### Miscellaneous * Removed deprecated functions from `skbio.util`: `is_casava_v180_or_later`, `remove_files`, and `create_dir`. * Removed deprecated `skbio.Sequence.copy` method. ## Version 0.5.0 (2016-06-14) **IMPORTANT**: scikit-bio is no longer compatible with Python 2. scikit-bio is compatible with Python 3.4 and later. ### Features * Added more descriptive error message to `skbio.io.registry` when attempting to read without specifying `into` and when there is no generator reader. ([#1326](https://github.com/scikit-bio/scikit-bio/issues/1326)) * Added support for reference tags to `skbio.io.format.stockholm` reader and writer. ([#1348](https://github.com/scikit-bio/scikit-bio/issues/1348)) * Expanded error message in `skbio.io.format.stockholm` reader when `constructor` is not passed, in order to provide better explanation to user. ([#1327](https://github.com/scikit-bio/scikit-bio/issues/1327)) * Added `skbio.sequence.distance.kmer_distance` for computing the kmer distance between two sequences. ([#913](https://github.com/scikit-bio/scikit-bio/issues/913)) * Added `skbio.sequence.Sequence.replace` for assigning a character to positions in a `Sequence`. ([#1222](https://github.com/scikit-bio/scikit-bio/issues/1222)) * Added support for `pandas.RangeIndex`, lowering the memory footprint of default integer index objects. `Sequence.positional_metadata` and `TabularMSA.positional_metadata` now use `pd.RangeIndex` as the positional metadata index. `TabularMSA` now uses `pd.RangeIndex` as the default index. Usage of `pd.RangeIndex` over the previous `pd.Int64Index` [should be transparent](http://pandas.pydata.org/pandas-docs/version/0.18.0/whatsnew.html#range-index), so these changes should be non-breaking to users. scikit-bio now depends on pandas >= 0.18.0 ([#1308](https://github.com/scikit-bio/scikit-bio/issues/1308)) * Added `reset_index=False` parameter to `TabularMSA.append` and `TabularMSA.extend` for resetting the MSA's index to the default index after appending/extending. * Added support for partial pairwise calculations via `skbio.diversity.partial_beta_diversity`. ([#1221](https://github.com/scikit-bio/scikit-bio/issues/1221), [#1337](https://github.com/scikit-bio/scikit-bio/pull/1337)). This function is immediately deprecated as its return type will change in the future and should be used with caution in its present form (see the function's documentation for details). * `TemporaryFile` and `NamedTemporaryFile` are now supported IO sources for `skbio.io` and related functionality. ([#1291](https://github.com/scikit-bio/scikit-bio/issues/1291)) * Added `tree_node_class=TreeNode` parameter to `skbio.tree.majority_rule` to support returning consensus trees of type `TreeNode` (the default) or a type that has the same interface as `TreeNode` (e.g. `TreeNode` subclasses) ([#1193](https://github.com/scikit-bio/scikit-bio/pull/1193)) * `TreeNode.from_linkage_matrix` and `TreeNode.from_taxonomy` now support constructing `TreeNode` subclasses. `TreeNode.bifurcate` now supports `TreeNode` subclasses ([#1193](https://github.com/scikit-bio/scikit-bio/pull/1193)) * The `ignore_metadata` keyword has been added to `TabularMSA.iter_positions` to improve performance when metadata is not necessary. * Pairwise aligners in `skbio.alignment` now propagate per-sequence `metadata` objects (this does not include `positional_metadata`). ### Backward-incompatible changes [stable] ### Backward-incompatible changes [experimental] * `TabularMSA.append` and `TabularMSA.extend` now require one of `minter`, `index`, or `reset_index` to be provided when incorporating new sequences into an MSA. Previous behavior was to auto-increment the index labels if `minter` and `index` weren't provided and the MSA had a default integer index, otherwise error. Use `reset_index=True` to obtain the previous behavior in a more explicit way. * `skbio.stats.composition.ancom` now returns two `pd.DataFrame` objects, where it previously returned one. The first contains the ANCOM test results, as before, and the second contains percentile abundances of each feature in each group. The specific percentiles that are computed and returned is controlled by the new `percentiles` parameter to `skbio.stats.composition.ancom`. In the future, this second `pd.DataFrame` will not be returned by this function, but will be available through the [contingency table API](https://github.com/scikit-bio/scikit-bio/issues/848). ([#1293](https://github.com/scikit-bio/scikit-bio/issues/1293)) * `skbio.stats.composition.ancom` now performs multiple comparisons correction by default. The previous behavior of not performing multiple comparisons correction can be achieved by passing ``multiple_comparisons_correction=None``. * The ``reject`` column in the first ``pd.DataFrame`` returned from `skbio.stats.composition.ancom` has been renamed ``Reject null hypothesis`` for clarity. ([#1375](https://github.com/scikit-bio/scikit-bio/issues/1375)) ### Bug fixes * Fixed row and column names to `biplot_scores` in the `OrdinationResults` object from `skbio.stats.ordination`. This fix affect the `cca` and `rda` methods. ([#1322](https://github.com/scikit-bio/scikit-bio/issues/1322)) * Fixed bug when using `skbio.io.format.stockholm` reader on file with multi-line tree with no id. Previously this raised an `AttributeError`, now it correctly handles this type of tree. ([#1334](https://github.com/scikit-bio/scikit-bio/issues/1334)) * Fixed bug when reading Stockholm files with GF or GS features split over multiple lines. Previously, the feature text was simply concatenated because it was assumed to have trailing whitespace. There are examples of Stockholm files with and without trailing whitespace for multi-line features, so the `skbio.io.format.stockholm` reader now adds a single space when concatenating feature text without trailing whitespace to avoid joining words together. Multi-line trees stored as GF metadata are concatenated as they appear in the file; a space is not added when concatenating. ([#1328](https://github.com/scikit-bio/scikit-bio/issues/1328)) * Fixed bug when using `Sequence.iter_kmers` on empty `Sequence` object. Previously this raised a `ValueError`, now it returns an empty generator. * Fixed minor bug where adding sequences to an empty `TabularMSA` with MSA-wide `positional_metadata` would result in a `TabularMSA` object in an inconsistent state. This could happen using `TabularMSA.append` or `TabularMSA.extend`. This bug only affects a `TabularMSA` object *without* sequences that has MSA-wide `positional_metadata` (for example, `TabularMSA([], positional_metadata={'column': []})`). * `TreeNode.distance` now handles the situation in which `self` or `other` are ancestors. Previosly, a node further up the tree was used resulting in inflated distances. ([#807](https://github.com/scikit-bio/scikit-bio/issues/807)) * `TreeNode.prune` can now handle a root with a single descendent. Previously, the root was ignored from possibly having a single descendent. ([#1247](https://github.com/scikit-bio/scikit-bio/issues/1247)) * Providing the `format` keyword to `skbio.io.read` when creating a generator with an empty file will now return an empty generator instead of raising `StopIteration`. ([#1313](https://github.com/scikit-bio/scikit-bio/issues/1313)) * `OrdinationResults` is now importable from `skbio` and `skbio.stats.ordination` and correctly linked from the documentation ([#1205](https://github.com/scikit-bio/scikit-bio/issues/1205)) * Fixed performance bug in pairwise aligners resulting in 100x worse performance than in 0.2.4. ### Deprecated functionality [stable] * Deprecated use of the term "non-degenerate", in favor of "definite". `GrammaredSequence.nondegenerate_chars`, `GrammaredSequence.nondegenerates`, and `GrammaredSequence.has_nondegenerates` have been renamed to `GrammaredSequence.definite_chars`, `GrammaredSequence.definites`, and `GrammaredSequence.has_definites`, respectively. The old names will be removed in scikit-bio 0.5.2. Relevant affected public classes include `GrammaredSequence`, `DNA`, `RNA`, and `Protein`. ### Deprecated functionality [experimental] * Deprecated function `skbio.util.create_dir`. This function will be removed in scikit-bio 0.5.1. Please use the Python standard library functionality described [here](https://docs.python.org/2/library/os.html#os.makedirs). ([#833](https://github.com/scikit-bio/scikit-bio/issues/833)) * Deprecated function `skbio.util.remove_files`. This function will be removed in scikit-bio 0.5.1. Please use the Python standard library functionality described [here](https://docs.python.org/2/library/os.html#os.remove). ([#833](https://github.com/scikit-bio/scikit-bio/issues/833)) * Deprecated function `skbio.util.is_casava_v180_or_later`. This function will be removed in 0.5.1. Functionality moved to FASTQ sniffer. ([#833](https://github.com/scikit-bio/scikit-bio/issues/833)) ### Miscellaneous * When installing scikit-bio via `pip`, numpy must now be installed first ([#1296](https://github.com/scikit-bio/scikit-bio/issues/1296)) ## Version 0.4.2 (2016-02-17) Minor maintenance release. **This is the last Python 2.7 compatible release. Future scikit-bio releases will only support Python 3.** ### Features * Added `skbio.tree.TreeNode.bifurcate` for converting multifurcating trees into bifurcating trees. ([#896](https://github.com/scikit-bio/scikit-bio/issues/896)) * Added `skbio.io.format.stockholm` for reading Stockholm files into a `TabularMSA` and writing from a `TabularMSA`. ([#967](https://github.com/scikit-bio/scikit-bio/issues/967)) * scikit-bio `Sequence` objects have better compatibility with numpy. For example, calling `np.asarray(sequence)` now converts the sequence to a numpy array of characters (the same as calling `sequence.values`). * Added `skbio.sequence.distance` subpackage for computing distances between scikit-bio `Sequence` objects ([#913](https://github.com/scikit-bio/scikit-bio/issues/913)) * Added ``skbio.sequence.GrammaredSequence``, which can be inherited from to create grammared sequences with custom alphabets (e.g., for use with TabularMSA) ([#1175](https://github.com/scikit-bio/scikit-bio/issues/1175)) * Added ``skbio.util.classproperty`` decorator ### Backward-incompatible changes [stable] * When sniffing or reading a file (`skbio.io.sniff`, `skbio.io.read`, or the object-oriented `.read()` interface), passing `newline` as a keyword argument to `skbio.io.open` now raises a `TypeError`. This backward-incompatible change to a stable API is necessary because it fixes a bug (more details in bug fix section below). * When reading a FASTQ or QSEQ file and passing `variant='solexa'`, `ValueError` is now raised instead of `NotImplementedError`. This backward-incompatible change to a stable API is necessary to avoid creating a spin-locked process due to [a bug in Python](https://bugs.python.org/issue25786). See [#1256](https://github.com/scikit-bio/scikit-bio/issues/1256) for details. This change is temporary and will be reverted to `NotImplementedError` when the bug is fixed in Python. ### Backward-incompatible changes [experimental] * `skbio.io.format.genbank`: When reading GenBank files, the date field of the LOCUS line is no longer parsed into a `datetime.datetime` object and is left as a string. When writing GenBank files, the locus date metadata is expected to be a string instead of a `datetime.datetime` object ([#1153](https://github.com/scikit-bio/scikit-bio/issues/1153)) * `Sequence.distance` now converts the input sequence (`other`) to its type before passing both sequences to `metric`. Previous behavior was to always convert to `Sequence`. ### Bug fixes * Fixed bug when using `Sequence.distance` or `DistanceMatrix.from_iterable` to compute distances between `Sequence` objects with differing `metadata`/`positional_metadata` and passing `metric=scipy.spatial.distance.hamming` ([#1254](https://github.com/scikit-bio/scikit-bio/issues/1254)) * Fixed performance bug when computing Hamming distances between `Sequence` objects in `DistanceMatrix.from_iterable` ([#1250](https://github.com/scikit-bio/scikit-bio/issues/1250)) * Changed `skbio.stats.composition.multiplicative_replacement` to raise an error whenever a large value of `delta` is chosen ([#1241](https://github.com/scikit-bio/scikit-bio/issues/1241)) * When sniffing or reading a file (`skbio.io.sniff`, `skbio.io.read`, or the object-oriented `.read()` interface), passing `newline` as a keyword argument to `skbio.io.open` now raises a `TypeError`. The file format's `newline` character will be used when opening the file. Previous behavior allowed overriding the format's `newline` character but this could cause issues with readers that assume newline characters are those defined by the file format (which is an entirely reasonable assumption). This bug is very unlikely to have surfaced in practice as the default `newline` behavior is *universal newlines mode*. * DNA, RNA, and Protein are no longer inheritable because they assume an IUPAC alphabet. * `DistanceMatrix` constructor provides more informative error message when data contains NaNs ([#1276](https://github.com/scikit-bio/scikit-bio/issues/1276)) ### Miscellaneous * Warnings raised by scikit-bio now share a common subclass ``skbio.util.SkbioWarning``. ## Version 0.4.1 (2015-12-09) ### Features * The ``TabularMSA`` object was added to represent and operate on tabular multiple sequence alignments. This satisfies [RFC 1](https://github.com/scikit-bio/scikit-bio-rfcs/blob/master/active/001-tabular-msa.md). See the ``TabularMSA`` docs for full details. * Added phylogenetic diversity metrics, including weighted UniFrac, unweighted UniFrac, and Faith's Phylogenetic Diversity. These are accessible as ``skbio.diversity.beta.unweighted_unifrac``, ``skbio.diversity.beta.weighted_unifrac``, and ``skbio.diversity.alpha.faith_pd``, respectively. * Addition of the function ``skbio.diversity.alpha_diversity`` to support applying an alpha diversity metric to multiple samples in one call. * Addition of the functions ``skbio.diversity.get_alpha_diversity_metrics`` and ``skbio.diversity.get_beta_diversity_metrics`` to support discovery of the alpha and beta diversity metrics implemented in scikit-bio. * Added `skbio.stats.composition.ancom` function, a test for OTU differential abundance across sample categories. ([#1054](https://github.com/scikit-bio/scikit-bio/issues/1054)) * Added `skbio.io.format.blast7` for reading BLAST+ output format 7 or BLAST output format 9 files into a `pd.DataFrame`. ([#1110](https://github.com/scikit-bio/scikit-bio/issues/1110)) * Added `skbio.DissimilarityMatrix.to_data_frame` method for creating a ``pandas.DataFrame`` from a `DissimilarityMatrix` or `DistanceMatrix`. ([#757](https://github.com/scikit-bio/scikit-bio/issues/757)) * Added support for one-dimensional vector of dissimilarities in `skbio.stats.distance.DissimilarityMatrix` constructor. ([#6240](https://github.com/scikit-bio/scikit-bio/issues/624)) * Added `skbio.io.format.blast6` for reading BLAST+ output format 6 or BLAST output format 8 files into a `pd.DataFrame`. ([#1110](https://github.com/scikit-bio/scikit-bio/issues/1110)) * Added `inner`, `ilr`, `ilr_inv` and `clr_inv`, ``skbio.stats.composition``, which enables linear transformations on compositions ([#892](https://github.com/scikit-bio/scikit-bio/issues/892) * Added ``skbio.diversity.alpha.pielou_e`` function as an evenness metric of alpha diversity. ([#1068](https://github.com/scikit-bio/scikit-bio/issues/1068)) * Added `to_regex` method to `skbio.sequence._iupac_sequence` ABC - it returns a regex object that matches all non-degenerate versions of the sequence. * Added ``skbio.util.assert_ordination_results_equal`` function for comparing ``OrdinationResults`` objects in unit tests. * Added ``skbio.io.format.genbank`` for reading and writing GenBank/GenPept for ``DNA``, ``RNA``, ``Protein`` and ``Sequence`` classes. * Added ``skbio.util.RepresentationWarning`` for warning about substitutions, assumptions, or particular alterations that were made for the successful completion of a process. * ``TreeNode.tip_tip_distances`` now supports nodes without an associated length. In this case, a length of 0.0 is assumed and an ``skbio.util.RepresentationWarning`` is raised. Previous behavior was to raise a ``NoLengthError``. ([#791](https://github.com/scikit-bio/scikit-bio/issues/791)) * ``DistanceMatrix`` now has a new constructor method called `from_iterable`. * ``Sequence`` now accepts ``lowercase`` keyword like ``DNA`` and others. Updated ``fasta``, ``fastq``, and ``qseq`` readers/writers for ``Sequence`` to reflect this. * The ``lowercase`` method has been moved up to ``Sequence`` meaning all sequence objects now have a ``lowercase`` method. * Added ``reverse_transcribe`` class method to ``RNA``. * Added `Sequence.observed_chars` property for obtaining the set of observed characters in a sequence. ([#1075](https://github.com/scikit-bio/scikit-bio/issues/1075)) * Added `Sequence.frequencies` method for computing character frequencies in a sequence. ([#1074](https://github.com/scikit-bio/scikit-bio/issues/1074)) * Added experimental class-method ``Sequence.concat`` which will produce a new sequence from an iterable of existing sequences. Parameters control how positional metadata is propagated during a concatenation. * ``TreeNode.to_array`` now supports replacing ``nan`` branch lengths in the resulting branch length vector with the value provided as ``nan_length_value``. * ``skbio.io.format.phylip`` now supports sniffing and reading strict, sequential PHYLIP-formatted files into ``skbio.Alignment`` objects. ([#1006](https://github.com/scikit-bio/scikit-bio/issues/1006)) * Added `default_gap_char` class property to ``DNA``, ``RNA``, and ``Protein`` for representing gap characters in a new sequence. ### Backward-incompatible changes [stable] * `Sequence.kmer_frequencies` now returns a `dict`. Previous behavior was to return a `collections.Counter` if `relative=False` was passed, and a `collections.defaultdict` if `relative=True` was passed. In the case of a missing key, the `Counter` would return 0 and the `defaultdict` would return 0.0. Because the return type is now always a `dict`, attempting to access a missing key will raise a `KeyError`. This change *may* break backwards-compatibility depending on how the `Counter`/`defaultdict` is being used. We hope that in most cases this change will not break backwards-compatibility because both `Counter` and `defaultdict` are `dict` subclasses. If the previous behavior is desired, convert the `dict` into a `Counter`/`defaultdict`: ```python import collections from skbio import Sequence seq = Sequence('ACCGAGTTTAACCGAATA') # Counter freqs_dict = seq.kmer_frequencies(k=8) freqs_counter = collections.Counter(freqs_dict) # defaultdict freqs_dict = seq.kmer_frequencies(k=8, relative=True) freqs_default_dict = collections.defaultdict(float, freqs_dict) ``` **Rationale:** We believe it is safer to return `dict` instead of `Counter`/`defaultdict` as this may prevent error-prone usage of the return value. Previous behavior allowed accessing missing kmers, returning 0 or 0.0 depending on the `relative` parameter. This is convenient in many cases but also potentially misleading. For example, consider the following code: ```python from skbio import Sequence seq = Sequence('ACCGAGTTTAACCGAATA') freqs = seq.kmer_frequencies(k=8) freqs['ACCGA'] ``` Previous behavior would return 0 because the kmer `'ACCGA'` is not present in the `Counter`. In one respect this is the correct answer because we asked for kmers of length 8; `'ACCGA'` is a different length so it is not included in the results. However, we believe it is safer to avoid this implicit behavior in case the user assumes there are no `'ACCGA'` kmers in the sequence (which there are!). A `KeyError` in this case is more explicit and forces the user to consider their query. Returning a `dict` will also be consistent with `Sequence.frequencies`. ### Backward-incompatible changes [experimental] * Replaced ``PCoA``, ``CCA``, ``CA`` and ``RDA`` in ``skbio.stats.ordination`` with equivalent functions ``pcoa``, ``cca``, ``ca`` and ``rda``. These functions now take ``pd.DataFrame`` objects. * Change ``OrdinationResults`` to have its attributes based on ``pd.DataFrame`` and ``pd.Series`` objects, instead of pairs of identifiers and values. The changes are as follows: - ``species`` and ``species_ids`` have been replaced by a ``pd.DataFrame`` named ``features``. - ``site`` and ``site_ids`` have been replaced by a ``pd.DataFrame`` named ``samples``. - ``eigvals`` is now a ``pd.Series`` object. - ``proportion_explained`` is now a ``pd.Series`` object. - ``biplot`` is now a ``pd.DataFrame`` object named ``biplot_scores``. - ``site_constraints`` is now a ``pd.DataFrame`` object named ``sample_constraints``. * ``short_method_name`` and ``long_method_name`` are now required arguments of the ``OrdinationResults`` object. * Removed `skbio.diversity.alpha.equitability`. Please use `skbio.diversity.alpha.pielou_e`, which is more accurately named and better documented. Note that `equitability` by default used logarithm base 2 while `pielou_e` uses logarithm base `e` as described in Heip 1974. * ``skbio.diversity.beta.pw_distances`` is now called ``skbio.diversity.beta_diversity``. This function no longer defines a default metric, and ``metric`` is now the first argument to this function. This function can also now take a pairwise distances function as ``pairwise_func``. * Deprecated function ``skbio.diversity.beta.pw_distances_from_table`` has been removed from scikit-bio as scheduled. Code that used this should be adapted to use ``skbio.diversity.beta_diversity``. * ``TreeNode.index_tree`` now returns a 2-D numpy array as its second return value (the child node index) instead of a 1-D numpy array. * Deprecated functions `skbio.draw.boxplots` and `skbio.draw.grouped_distributions` have been removed from scikit-bio as scheduled. These functions generated plots that were not specific to bioinformatics. These types of plots can be generated with seaborn or another general-purpose plotting package. * Deprecated function `skbio.stats.power.bootstrap_power_curve` has been removed from scikit-bio as scheduled. Use `skbio.stats.power.subsample_power` or `skbio.stats.power.subsample_paired_power` followed by `skbio.stats.power.confidence_bound`. * Deprecated function `skbio.stats.spatial.procrustes` has been removed from scikit-bio as scheduled in favor of `scipy.spatial.procrustes`. * Deprecated class `skbio.tree.CompressedTrie` and function `skbio.tree.fasta_to_pairlist` have been removed from scikit-bio as scheduled in favor of existing general-purpose Python trie packages. * Deprecated function `skbio.util.flatten` has been removed from scikit-bio as scheduled in favor of solutions available in the Python standard library (see [here](http://stackoverflow.com/a/952952/3639023) and [here](http://stackoverflow.com/a/406199/3639023) for examples). * Pairwise alignment functions in `skbio.alignment` now return a tuple containing the `TabularMSA` alignment, alignment score, and start/end positions. The returned `TabularMSA`'s `index` is always the default integer index; sequence IDs are no longer propagated to the MSA. Additionally, the pairwise alignment functions now accept the following input types to align: - `local_pairwise_align_nucleotide`: `DNA` or `RNA` - `local_pairwise_align_protein`: `Protein` - `local_pairwise_align`: `IUPACSequence` - `global_pairwise_align_nucleotide`: `DNA`, `RNA`, or `TabularMSA[DNA|RNA]` - `global_pairwise_align_protein`: `Protein` or `TabularMSA[Protein]` - `global_pairwise_align`: `IUPACSequence` or `TabularMSA` - `local_pairwise_align_ssw`: `DNA`, `RNA`, or `Protein`. Additionally, this function now overrides the `protein` kwarg based on input type. `constructor` parameter was removed because the function now determines the return type based on input type. * Removed `skbio.alignment.SequenceCollection` in favor of using a list or other standard library containers to store scikit-bio sequence objects (most `SequenceCollection` operations were simple list comprehensions). Use `DistanceMatrix.from_iterable` instead of `SequenceCollection.distances` (pass `key="id"` to exactly match original behavior). * Removed `skbio.alignment.Alignment` in favor of `skbio.alignment.TabularMSA`. * Removed `skbio.alignment.SequenceCollectionError` and `skbio.alignment.AlignmentError` exceptions as their corresponding classes no longer exist. ### Bug Fixes * ``Sequence`` objects now handle slicing of empty positional metadata correctly. Any metadata that is empty will no longer be propagated by the internal ``_to`` constructor. ([#1133](https://github.com/scikit-bio/scikit-bio/issues/1133)) * ``DissimilarityMatrix.plot()`` no longer leaves a white border around the heatmap it plots (PR #1070). * TreeNode.root_at_midpoint`` no longer fails when a node with two equal length child branches exists in the tree. ([#1077](https://github.com/scikit-bio/scikit-bio/issues/1077)) * ``TreeNode._set_max_distance``, as called through ``TreeNode.get_max_distance`` or ``TreeNode.root_at_midpoint`` would store distance information as ``list``s in the attribute ``MaxDistTips`` on each node in the tree, however, these distances were only valid for the node in which the call to ``_set_max_distance`` was made. The values contained in ``MaxDistTips`` are now correct across the tree following a call to ``get_max_distance``. The scope of impact of this bug is limited to users that were interacting directly with ``MaxDistTips`` on descendant nodes; this bug does not impact any known method within scikit-bio. ([#1223](https://github.com/scikit-bio/scikit-bio/issues/1223)) * Added missing `nose` dependency to setup.py's `install_requires`. ([#1214](https://github.com/scikit-bio/scikit-bio/issues/1214)) * Fixed issue that resulted in legends of ``OrdinationResult`` plots sometimes being truncated. ([#1210](https://github.com/scikit-bio/scikit-bio/issues/1210)) ### Deprecated functionality [stable] * `skbio.Sequence.copy` has been deprecated in favor of `copy.copy(seq)` and `copy.deepcopy(seq)`. ### Miscellaneous * Doctests are now written in Python 3. * ``make test`` now validates MANIFEST.in using [check-manifest](https://github.com/mgedmin/check-manifest). ([#461](https://github.com/scikit-bio/scikit-bio/issues/461)) * Many new alpha diversity equations added to ``skbio.diversity.alpha`` documentation. ([#321](https://github.com/scikit-bio/scikit-bio/issues/321)) * Order of ``lowercase`` and ``validate`` keywords swapped in ``DNA``, ``RNA``, and ``Protein``. ## Version 0.4.0 (2015-07-08) Initial beta release. In addition to the changes detailed below, the following subpackages have been mostly or entirely rewritten and most of their APIs are substantially different (and improved!): * `skbio.sequence` * `skbio.io` The APIs of these subpackages are now stable, and all others are experimental. See the [API stability docs](https://github.com/scikit-bio/scikit-bio/tree/0.4.0/doc/source/user/api_stability.rst) for more details, including what we mean by *stable* and *experimental* in this context. We recognize that this is a lot of backward-incompatible changes. To avoid these types of changes being a surprise to our users, our public APIs are now decorated to make it clear to developers when an API can be relied upon (stable) and when it may be subject to change (experimental). ### Features * Added `skbio.stats.composition` for analyzing data made up of proportions * Added new ``skbio.stats.evolve`` subpackage for evolutionary statistics. Currently contains a single function, ``hommola_cospeciation``, which implements a permutation-based test of correlation between two distance matrices. * Added support for ``skbio.io.util.open_file`` and ``skbio.io.util.open_files`` to pull files from HTTP and HTTPS URLs. This behavior propagates to the I/O registry. * FASTA/QUAL (``skbio.io.format.fasta``) and FASTQ (``skbio.io.format.fastq``) readers now allow blank or whitespace-only lines at the beginning of the file, between records, or at the end of the file. A blank or whitespace-only line in any other location will continue to raise an error [#781](https://github.com/scikit-bio/scikit-bio/issues/781). * scikit-bio now ignores leading and trailing whitespace characters on each line while reading FASTA/QUAL and FASTQ files. * Added `ratio` parameter to `skbio.stats.power.subsample_power`. This allows the user to calculate power on groups for uneven size (For example, draw twice as many samples from Group B than Group A). If `ratio` is not set, group sizes will remain equal across all groups. * Power calculations (`skbio.stats.power.subsample_power` and `skbio.stats.power.subsample_paired_power`) can use test functions that return multiple p values, like some multivariate linear regression models. Previously, the power calculations required the test to return a single p value. * Added ``skbio.util.assert_data_frame_almost_equal`` function for comparing ``pd.DataFrame`` objects in unit tests. ### Performance enhancements * The speed of quality score decoding has been significantly improved (~2x) when reading `fastq` files. * The speed of `NucleotideSequence.reverse_complement` has been improved (~6x). ### Bug fixes * Changed `Sequence.distance` to raise an error any time two sequences are passed of different lengths regardless of the `distance_fn` being passed. [(#514)](https://github.com/scikit-bio/scikit-bio/issues/514) * Fixed issue with ``TreeNode.extend`` where if given the children of another ``TreeNode`` object (``tree.children``), both trees would be left in an incorrect and unpredictable state. ([#889](https://github.com/scikit-bio/scikit-bio/issues/889)) * Changed the way power was calculated in `subsample_paired_power` to move the subsample selection before the test is performed. This increases the number of Monte Carlo simulations performed during power estimation, and improves the accuracy of the returned estimate. Previous power estimates from `subsample_paired_power` should be disregarded and re-calculated. ([#910](https://github.com/scikit-bio/scikit-bio/issues/910)) * Fixed issue where `randdm` was attempting to create asymmetric distance matrices.This was causing an error to be raised by the `DistanceMatrix` constructor inside of the `randdm` function, so that `randdm` would fail when attempting to create large distance matrices. ([#943](https://github.com/scikit-bio/scikit-bio/issues/943)) ### Deprecated functionality * Deprecated `skbio.util.flatten`. This function will be removed in scikit-bio 0.3.1. Please use standard python library functionality described here [Making a flat list out of lists of lists](http://stackoverflow.com/a/952952/3639023), [Flattening a shallow list](http://stackoverflow.com/a/406199/3639023) ([#833](https://github.com/scikit-bio/scikit-bio/issues/833)) * Deprecated `skbio.stats.power.bootstrap_power_curve` will be removed in scikit-bio 0.4.1. It is deprecated in favor of using ``subsample_power`` or ``sample_paired_power`` to calculate a power matrix, and then the use of ``confidence_bounds`` to calculate the average and confidence intervals. ### Backward-incompatible changes * Removed the following deprecated functionality: - `skbio.parse` subpackage, including `SequenceIterator`, `FastaIterator`, `FastqIterator`, `load`, `parse_fasta`, `parse_fastq`, `parse_qual`, `write_clustal`, `parse_clustal`, and `FastqParseError`; please use `skbio.io` instead. - `skbio.format` subpackage, including `fasta_from_sequence`, `fasta_from_alignment`, and `format_fastq_record`; please use `skbio.io` instead. - `skbio.alignment.SequenceCollection.int_map`; please use `SequenceCollection.update_ids` instead. - `skbio.alignment.SequenceCollection` methods `to_fasta` and `toFasta`; please use `SequenceCollection.write` instead. - `constructor` parameter in `skbio.alignment.Alignment.majority_consensus`; please convert returned biological sequence object manually as desired (e.g., `str(seq)`). - `skbio.alignment.Alignment.to_phylip`; please use `Alignment.write` instead. - `skbio.sequence.BiologicalSequence.to_fasta`; please use `BiologicalSequence.write` instead. - `skbio.tree.TreeNode` methods `from_newick`, `from_file`, and `to_newick`; please use `TreeNode.read` and `TreeNode.write` instead. - `skbio.stats.distance.DissimilarityMatrix` methods `from_file` and `to_file`; please use `DissimilarityMatrix.read` and `DissimilarityMatrix.write` instead. - `skbio.stats.ordination.OrdinationResults` methods `from_file` and `to_file`; please use `OrdinationResults.read` and `OrdinationResults.write` instead. - `skbio.stats.p_value_to_str`; there is no replacement. - `skbio.stats.subsample`; please use `skbio.stats.subsample_counts` instead. - `skbio.stats.distance.ANOSIM`; please use `skbio.stats.distance.anosim` instead. - `skbio.stats.distance.PERMANOVA`; please use `skbio.stats.distance.permanova` instead. - `skbio.stats.distance.CategoricalStatsResults`; there is no replacement, please use `skbio.stats.distance.anosim` or `skbio.stats.distance.permanova`, which will return a `pandas.Series` object. * `skbio.alignment.Alignment.majority_consensus` now returns `BiologicalSequence('')` if the alignment is empty. Previously, `''` was returned. * `min_observations` was removed from `skbio.stats.power.subsample_power` and `skbio.stats.power.subsample_paired_power`. The minimum number of samples for subsampling depends on the data set and statistical tests. Having a default parameter to set unnecessary limitations on the technique. ### Miscellaneous * Changed testing procedures - Developers should now use `make test` - Users can use `python -m skbio.test` - Added `skbio.util._testing.TestRunner` (available through `skbio.util.TestRunner`). Used to provide a `test` method for each module init file. This class represents a unified testing path which wraps all `skbio` testing functionality. - Autodetect Python version and disable doctests for Python 3. * `numpy` is no longer required to be installed before installing scikit-bio! * Upgraded checklist.py to check source files non-conforming to [new header style](http://scikit-bio.org/docs/latest/development/new_module.html). ([#855](https://github.com/scikit-bio/scikit-bio/issues/855)) * Updated to use `natsort` >= 4.0.0. * The method of subsampling was changed for ``skbio.stats.power.subsample_paired_power``. Rather than drawing a paired sample for the run and then subsampling for each count, the subsample is now drawn for each sample and each run. In test data, this did not significantly alter the power results. * checklist.py now enforces `__future__` imports in .py files. ## Version 0.2.3 (2015-02-13) ### Features * Modified ``skbio.stats.distance.pwmantel`` to accept a list of filepaths. This is useful as it allows for a smaller amount of memory consumption as it only loads two matrices at a time as opposed to requiring that all distance matrices are loaded into memory. * Added ``skbio.util.find_duplicates`` for finding duplicate elements in an iterable. ### Bug fixes * Fixed floating point precision bugs in ``Alignment.position_frequencies``, ``Alignment.position_entropies``, ``Alignment.omit_gap_positions``, ``Alignment.omit_gap_sequences``, ``BiologicalSequence.k_word_frequencies``, and ``SequenceCollection.k_word_frequencies`` ([#801](https://github.com/scikit-bio/scikit-bio/issues/801)). ### Backward-incompatible changes * Removed ``feature_types`` attribute from ``BiologicalSequence`` and all subclasses ([#797](https://github.com/scikit-bio/scikit-bio/pull/797)). * Removed ``find_features`` method from ``BiologicalSequence`` and ``ProteinSequence`` ([#797](https://github.com/scikit-bio/scikit-bio/pull/797)). * ``BiologicalSequence.k_word_frequencies`` now returns a ``collections.defaultdict`` of type ``float`` instead of type ``int``. This only affects the "default" case, when a key isn't present in the dictionary. Previous behavior would return ``0`` as an ``int``, while the new behavior is to return ``0.0`` as a ``float``. This change also affects the ``defaultdict``s that are returned by ``SequenceCollection.k_word_frequencies``. ### Miscellaneous * ``DissimilarityMatrix`` and ``DistanceMatrix`` now report duplicate IDs in the ``DissimilarityMatrixError`` message that can be raised during validation. ## Version 0.2.2 (2014-12-04) ### Features * Added ``plot`` method to ``skbio.stats.distance.DissimilarityMatrix`` for creating basic heatmaps of a dissimilarity/distance matrix (see [#684](https://github.com/scikit-bio/scikit-bio/issues/684)). Also added ``_repr_png_`` and ``_repr_svg_`` methods for automatic display in the IPython Notebook, with ``png`` and ``svg`` properties for direct access. * Added `__str__` method to `skbio.stats.ordination.OrdinationResults`. * Added ``skbio.stats.distance.anosim`` and ``skbio.stats.distance.permanova`` functions, which replace the ``skbio.stats.distance.ANOSIM`` and ``skbio.stats.distance.PERMANOVA`` classes. These new functions provide simpler procedural interfaces to running these statistical methods. They also provide more convenient access to results by returning a ``pandas.Series`` instead of a ``CategoricalStatsResults`` object. These functions have more extensive documentation than their previous versions. If significance tests are suppressed, p-values are returned as ``np.nan`` instead of ``None`` for consistency with other statistical methods in scikit-bio. [#754](https://github.com/scikit-bio/scikit-bio/issues/754) * Added `skbio.stats.power` for performing empirical power analysis. The module uses existing datasets and iteratively draws samples to estimate the number of samples needed to see a significant difference for a given critical value. * Added `skbio.stats.isubsample` for subsampling from an unknown number of values. This method supports subsampling from multiple partitions and does not require that all items be stored in memory, requiring approximately `O(N*M)`` space where `N` is the number of partitions and `M` is the maximum subsample size. * Added ``skbio.stats.subsample_counts``, which replaces ``skbio.stats.subsample``. See deprecation section below for more details ([#770](https://github.com/scikit-bio/scikit-bio/issues/770)). ### Bug fixes * Fixed issue where SSW wouldn't compile on i686 architectures ([#409](https://github.com/scikit-bio/scikit-bio/issues/409)). ### Deprecated functionality * Deprecated ``skbio.stats.p_value_to_str``. This function will be removed in scikit-bio 0.3.0. Permutation-based p-values in scikit-bio are calculated as ``(num_extreme + 1) / (num_permutations + 1)``, so it is impossible to obtain a p-value of zero. This function historically existed for correcting the number of digits displayed when obtaining a p-value of zero. Since this is no longer possible, this functionality will be removed. * Deprecated ``skbio.stats.distance.ANOSIM`` and ``skbio.stats.distance.PERMANOVA`` in favor of ``skbio.stats.distance.anosim`` and ``skbio.stats.distance.permanova``, respectively. * Deprecated ``skbio.stats.distance.CategoricalStatsResults`` in favor of using ``pandas.Series`` to store statistical method results. ``anosim`` and ``permanova`` return ``pandas.Series`` instead of ``CategoricalStatsResults``. * Deprecated ``skbio.stats.subsample`` in favor of ``skbio.stats.subsample_counts``, which provides an identical interface; only the function name has changed. ``skbio.stats.subsample`` will be removed in scikit-bio 0.3.0. ### Backward-incompatible changes * Deprecation warnings are now raised using ``DeprecationWarning`` instead of ``UserWarning`` ([#774](https://github.com/scikit-bio/scikit-bio/issues/774)). ### Miscellaneous * The ``pandas.DataFrame`` returned by ``skbio.stats.distance.pwmantel`` now stores p-values as floats and does not convert them to strings with a specific number of digits. p-values that were previously stored as "N/A" are now stored as ``np.nan`` for consistency with other statistical methods in scikit-bio. See note in "Deprecated functionality" above regarding ``p_value_to_str`` for details. * scikit-bio now supports versions of IPython < 2.0.0 ([#767](https://github.com/scikit-bio/scikit-bio/issues/767)). ## Version 0.2.1 (2014-10-27) This is an alpha release of scikit-bio. At this stage, major backwards-incompatible API changes can and will happen. Unified I/O with the scikit-bio I/O registry was the focus of this release. ### Features * Added ``strict`` and ``lookup`` optional parameters to ``skbio.stats.distance.mantel`` for handling reordering and matching of IDs when provided ``DistanceMatrix`` instances as input (these parameters were previously only available in ``skbio.stats.distance.pwmantel``). * ``skbio.stats.distance.pwmantel`` now accepts an iterable of ``array_like`` objects. Previously, only ``DistanceMatrix`` instances were allowed. * Added ``plot`` method to ``skbio.stats.ordination.OrdinationResults`` for creating basic 3-D matplotlib scatterplots of ordination results, optionally colored by metadata in a ``pandas.DataFrame`` (see [#518](https://github.com/scikit-bio/scikit-bio/issues/518)). Also added ``_repr_png_`` and ``_repr_svg_`` methods for automatic display in the IPython Notebook, with ``png`` and ``svg`` properties for direct access. * Added ``skbio.stats.ordination.assert_ordination_results_equal`` for comparing ``OrdinationResults`` objects for equality in unit tests. * ``BiologicalSequence`` (and its subclasses) now optionally store Phred quality scores. A biological sequence's quality scores are stored as a 1-D ``numpy.ndarray`` of nonnegative integers that is the same length as the biological sequence. Quality scores can be provided upon object instantiation via the keyword argument ``quality``, and can be retrieved via the ``BiologicalSequence.quality`` property. ``BiologicalSequence.has_quality`` is also provided for determining whether a biological sequence has quality scores or not. See [#616](https://github.com/scikit-bio/scikit-bio/issues/616) for more details. * Added ``BiologicalSequence.sequence`` property for retrieving the underlying string representing the sequence characters. This was previously (and still is) accessible via ``BiologicalSequence.__str__``. It is provided via a property for convenience and explicitness. * Added ``BiologicalSequence.equals`` for full control over equality testing of biological sequences. By default, biological sequences must have the same type, underlying sequence of characters, identifier, description, and quality scores to compare equal. These properties can be ignored via the keyword argument ``ignore``. The behavior of ``BiologicalSequence.__eq__``/``__ne__`` remains unchanged (only type and underlying sequence of characters are compared). * Added ``BiologicalSequence.copy`` for creating a copy of a biological sequence, optionally with one or more attributes updated. * ``BiologicalSequence.__getitem__`` now supports specifying a sequence of indices to take from the biological sequence. * Methods to read and write taxonomies are now available under ``skbio.tree.TreeNode.from_taxonomy`` and ``skbio.tree.TreeNode.to_taxonomy`` respectively. * Added ``SequenceCollection.update_ids``, which provides a flexible way of updating sequence IDs on a ``SequenceCollection`` or ``Alignment`` (note that a new object is returned, since instances of these classes are immutable). Deprecated ``SequenceCollection.int_map`` in favor of this new method; it will be removed in scikit-bio 0.3.0. * Added ``skbio.util.cardinal_to_ordinal`` for converting a cardinal number to ordinal string (e.g., useful for error messages). * New I/O Registry: supports multiple file formats, automatic file format detection when reading, unified procedural ``skbio.io.read`` and ``skbio.io.write`` in addition to OOP interfaces (``read/write`` methods) on the below objects. See ``skbio.io`` for more details. - Added "clustal" format support: * Has sniffer * Readers: ``Alignment`` * Writers: ``Alignment`` - Added "lsmat" format support: * Has sniffer * Readers: ``DissimilarityMatrix``, ``DistanceMatrix`` * Writers: ``DissimilarityMatrix``, ``DistanceMatrix`` - Added "ordination" format support: * Has sniffer * Readers: ``OrdinationResults`` * Writers: ``OrdinationResults`` - Added "newick" format support: * Has sniffer * Readers: ``TreeNode`` * Writers: ``TreeNode`` - Added "phylip" format support: * No sniffer * Readers: None * Writers: ``Alignment`` - Added "qseq" format support: * Has sniffer * Readers: generator of ``BiologicalSequence`` or its subclasses, ``SequenceCollection``, ``BiologicalSequence``, ``NucleotideSequence``, ``DNASequence``, ``RNASequence``, ``ProteinSequence`` * Writers: None - Added "fasta"/QUAL format support: * Has sniffer * Readers: generator of ``BiologicalSequence`` or its subclasses, ``SequenceCollection``, ``Alignment``, ``BiologicalSequence``, ``NucleotideSequence``, ``DNASequence``, ``RNASequence``, ``ProteinSequence`` * Writers: same as readers - Added "fastq" format support: * Has sniffer * Readers: generator of ``BiologicalSequence`` or its subclasses, ``SequenceCollection``, ``Alignment``, ``BiologicalSequence``, ``NucleotideSequence``, ``DNASequence``, ``RNASequence``, ``ProteinSequence`` * Writers: same as readers ### Bug fixes * Removed ``constructor`` parameter from ``Alignment.k_word_frequencies``, ``BiologicalSequence.k_words``, ``BiologicalSequence.k_word_counts``, and ``BiologicalSequence.k_word_frequencies`` as it had no effect (it was never hooked up in the underlying code). ``BiologicalSequence.k_words`` now returns a generator of ``BiologicalSequence`` objects instead of strings. * Modified the ``Alignment`` constructor to verify that all sequences have the same length, if not, raise an ``AlignmentError`` exception. Updated the method ``Alignment.subalignment`` to calculate the indices only once now that identical sequence length is guaranteed. ### Deprecated functionality * Deprecated ``constructor`` parameter in ``Alignment.majority_consensus`` in favor of having users call ``str`` on the returned ``BiologicalSequence``. This parameter will be removed in scikit-bio 0.3.0. * Existing I/O functionality deprecated in favor of I/O registry, old functionality will be removed in scikit-bio 0.3.0. All functionality can be found at ``skbio.io.read``, ``skbio.io.write``, and the methods listed below: * Deprecated the following "clustal" readers/writers: - ``write_clustal`` -> ``Alignment.write`` - ``parse_clustal`` -> ``Alignment.read`` * Deprecated the following distance matrix format ("lsmat") readers/writers: - ``DissimilarityMatrix.from_file`` -> ``DissimilarityMatrix.read`` - ``DissimilarityMatrix.to_file`` -> ``DissimilarityMatrix.write`` - ``DistanceMatrix.from_file`` -> ``DistanceMatrix.read`` - ``DistanceMatrix.to_file`` -> ``DistanceMatrix.write`` * Deprecated the following ordination format ("ordination") readers/writers: - ``OrdinationResults.from_file`` -> ``OrdinationResults.read`` - ``OrdinationResults.to_file`` -> ``OrdinationResults.write`` * Deprecated the following "newick" readers/writers: - ``TreeNode.from_file`` -> ``TreeNode.read`` - ``TreeNode.from_newick`` -> ``TreeNode.read`` - ``TreeNode.to_newick`` -> ``TreeNode.write`` * Deprecated the following "phylip" writers: - ``Alignment.to_phylip`` -> ``Alignment.write`` * Deprecated the following "fasta"/QUAL readers/writers: - ``SequenceCollection.from_fasta_records`` -> ``SequenceCollection.read`` - ``SequenceCollection.to_fasta`` -> ``SequenceCollection.write`` - ``fasta_from_sequences`` -> ``skbio.io.write(obj, into=, format='fasta')`` - ``fasta_from_alignment`` -> ``Alignment.write`` - ``parse_fasta`` -> ``skbio.io.read(, format='fasta')`` - ``parse_qual`` -> ``skbio.io.read(, format='fasta', qual=)`` - ``BiologicalSequence.to_fasta`` -> ``BiologicalSequence.write`` * Deprecated the following "fastq" readers/writers: - ``parse_fastq`` -> ``skbio.io.read(, format='fastq')`` - ``format_fastq_record`` -> ``skbio.io.write(, format='fastq')`` ### Backward-incompatible changes * ``skbio.stats.distance.mantel`` now returns a 3-element tuple containing correlation coefficient, p-value, and the number of matching rows/cols in the distance matrices (``n``). The return value was previously a 2-element tuple containing only the correlation coefficient and p-value. * ``skbio.stats.distance.mantel`` reorders input ``DistanceMatrix`` instances based on matching IDs (see optional parameters ``strict`` and ``lookup`` for controlling this behavior). In the past, ``DistanceMatrix`` instances were treated the same as ``array_like`` input and no reordering took place, regardless of ID (mis)matches. ``array_like`` input behavior remains the same. * If mismatched types are provided to ``skbio.stats.distance.mantel`` (e.g., a ``DistanceMatrix`` and ``array_like``), a ``TypeError`` will be raised. ### Miscellaneous * Added git timestamp checking to checklist.py, ensuring that when changes are made to Cython (.pyx) files, their corresponding generated C files are also updated. * Fixed performance bug when instantiating ``BiologicalSequence`` objects. The previous runtime scaled linearly with sequence length; it is now constant time when the sequence is already a string. See [#623](https://github.com/scikit-bio/scikit-bio/issues/623) for details. * IPython and six are now required dependencies. ## Version 0.2.0 (2014-08-07) This is an initial alpha release of scikit-bio. At this stage, major backwards-incompatible API changes can and will happen. Many backwards-incompatible API changes were made since the previous release. ### Features * Added ability to compute distances between sequences in a ``SequenceCollection`` object ([#509](https://github.com/scikit-bio/scikit-bio/issues/509)), and expanded ``Alignment.distance`` to allow the user to pass a function for computing distances (the default distance metric is still ``scipy.spatial.distance.hamming``) ([#194](https://github.com/scikit-bio/scikit-bio/issues/194)). * Added functionality to not penalize terminal gaps in global alignment. This functionality results in more biologically relevant global alignments (see [#537](https://github.com/scikit-bio/scikit-bio/issues/537) for discussion of the issue) and is now the default behavior for global alignment. * The python global aligners (``global_pairwise_align``, ``global_pairwise_align_nucleotide``, and ``global_pairwise_align_protein``) now support aligning pairs of sequences, pairs of alignments, and a sequence and an alignment (see [#550](https://github.com/scikit-bio/scikit-bio/issues/550)). This functionality supports progressive multiple sequence alignment, among other things such as adding a sequence to an existing alignment. * Added ``StockholmAlignment.to_file`` for writing Stockholm-formatted files. * Added ``strict=True`` optional parameter to ``DissimilarityMatrix.filter``. * Added ``TreeNode.find_all`` for finding all tree nodes that match a given name. ### Bug fixes * Fixed bug that resulted in a ``ValueError`` from ``local_align_pairwise_nucleotide`` (see [#504](https://github.com/scikit-bio/scikit-bio/issues/504)) under many circumstances. This would not generate incorrect results, but would cause the code to fail. ### Backward-incompatible changes * Removed ``skbio.math``, leaving ``stats`` and ``diversity`` to become top level packages. For example, instead of ``from skbio.math.stats.ordination import PCoA`` you would now import ``from skbio.stats.ordination import PCoA``. * The module ``skbio.math.gradient`` as well as the contents of ``skbio.math.subsample`` and ``skbio.math.stats.misc`` are now found in ``skbio.stats``. As an example, to import subsample: ``from skbio.stats import subsample``; to import everything from gradient: ``from skbio.stats.gradient import *``. * The contents of ``skbio.math.stats.ordination.utils`` are now in ``skbio.stats.ordination``. * Removed ``skbio.app`` subpackage (i.e., the *application controller framework*) as this code has been ported to the standalone [burrito](https://github.com/biocore/burrito) Python package. This code was not specific to bioinformatics and is useful for wrapping command-line applications in general. * Removed ``skbio.core``, leaving ``alignment``, ``genetic_code``, ``sequence``, ``tree``, and ``workflow`` to become top level packages. For example, instead of ``from skbio.core.sequence import DNA`` you would now import ``from skbio.sequence import DNA``. * Removed ``skbio.util.exception`` and ``skbio.util.warning`` (see [#577](https://github.com/scikit-bio/scikit-bio/issues/577) for the reasoning behind this change). The exceptions/warnings were moved to the following locations: - ``FileFormatError``, ``RecordError``, ``FieldError``, and ``EfficiencyWarning`` have been moved to ``skbio.util`` - ``BiologicalSequenceError`` has been moved to ``skbio.sequence`` - ``SequenceCollectionError`` and ``StockholmParseError`` have been moved to ``skbio.alignment`` - ``DissimilarityMatrixError``, ``DistanceMatrixError``, ``DissimilarityMatrixFormatError``, and ``MissingIDError`` have been moved to ``skbio.stats.distance`` - ``TreeError``, ``NoLengthError``, ``DuplicateNodeError``, ``MissingNodeError``, and ``NoParentError`` have been moved to ``skbio.tree`` - ``FastqParseError`` has been moved to ``skbio.parse.sequences`` - ``GeneticCodeError``, ``GeneticCodeInitError``, and ``InvalidCodonError`` have been moved to ``skbio.genetic_code`` * The contents of ``skbio.genetic_code`` formerly ``skbio.core.genetic_code`` are now in ``skbio.sequence``. The ``GeneticCodes`` dictionary is now a function ``genetic_code``. The functionality is the same, except that because this is now a function rather than a dict, retrieving a genetic code is done using a function call rather than a lookup (so, for example, ``GeneticCodes[2]`` becomes ``genetic_code(2)``. * Many submodules have been made private with the intention of simplifying imports for users. See [#562](https://github.com/scikit-bio/scikit-bio/issues/562) for discussion of this change. The following list contains the previous module name and where imports from that module should now come from. - ``skbio.alignment.ssw`` to ``skbio.alignment`` - ``skbio.alignment.alignment`` to ``skbio.alignment`` - ``skbio.alignment.pairwise`` to ``skbio.alignment`` - ``skbio.diversity.alpha.base`` to ``skbio.diversity.alpha`` - ``skbio.diversity.alpha.gini`` to ``skbio.diversity.alpha`` - ``skbio.diversity.alpha.lladser`` to ``skbio.diversity.alpha`` - ``skbio.diversity.beta.base`` to ``skbio.diversity.beta`` - ``skbio.draw.distributions`` to ``skbio.draw`` - ``skbio.stats.distance.anosim`` to ``skbio.stats.distance`` - ``skbio.stats.distance.base`` to ``skbio.stats.distance`` - ``skbio.stats.distance.permanova`` to ``skbio.stats.distance`` - ``skbio.distance`` to ``skbio.stats.distance`` - ``skbio.stats.ordination.base`` to ``skbio.stats.ordination`` - ``skbio.stats.ordination.canonical_correspondence_analysis`` to ``skbio.stats.ordination`` - ``skbio.stats.ordination.correspondence_analysis`` to ``skbio.stats.ordination`` - ``skbio.stats.ordination.principal_coordinate_analysis`` to ``skbio.stats.ordination`` - ``skbio.stats.ordination.redundancy_analysis`` to ``skbio.stats.ordination`` - ``skbio.tree.tree`` to ``skbio.tree`` - ``skbio.tree.trie`` to ``skbio.tree`` - ``skbio.util.misc`` to ``skbio.util`` - ``skbio.util.testing`` to ``skbio.util`` - ``skbio.util.exception`` to ``skbio.util`` - ``skbio.util.warning`` to ``skbio.util`` * Moved ``skbio.distance`` contents into ``skbio.stats.distance``. ### Miscellaneous * Relaxed requirement in ``BiologicalSequence.distance`` that sequences being compared are of equal length. This is relevant for Hamming distance, so the check is still performed in that case, but other distance metrics may not have that requirement. See [#504](https://github.com/scikit-bio/scikit-bio/issues/507)). * Renamed ``powertrip.py`` repo-checking script to ``checklist.py`` for clarity. * ``checklist.py`` now ensures that all unit tests import from a minimally deep API. For example, it will produce an error if ``skbio.core.distance.DistanceMatrix`` is used over ``skbio.DistanceMatrix``. * Extra dimension is no longer calculated in ``skbio.stats.spatial.procrustes``. * Expanded documentation in various subpackages. * Added new scikit-bio logo. Thanks [Alina Prassas](http://cargocollective.com/alinaprassas)! ## Version 0.1.4 (2014-06-25) This is a pre-alpha release. At this stage, major backwards-incompatible API changes can and will happen. ### Features * Added Python implementations of Smith-Waterman and Needleman-Wunsch alignment as ``skbio.core.alignment.pairwise.local_pairwise_align`` and ``skbio.core.alignment.pairwise.global_pairwise_align``. These are much slower than native C implementations (e.g., ``skbio.core.alignment.local_pairwise_align_ssw``) and as a result raise an ``EfficencyWarning`` when called, but are included as they serve as useful educational examples as they’re simple to experiment with. * Added ``skbio.core.diversity.beta.pw_distances`` and ``skbio.core.diversity.beta.pw_distances_from_table``. These provide convenient access to the ``scipy.spatial.distance.pdist`` *beta diversity* metrics from within scikit-bio. The ``skbio.core.diversity.beta.pw_distances_from_table`` function will only be available temporarily, until the ``biom.table.Table`` object is merged into scikit-bio (see [#489](https://github.com/scikit-bio/scikit-bio/issues/489)), at which point ``skbio.core.diversity.beta.pw_distances`` will be updated to use that. * Added ``skbio.core.alignment.StockholmAlignment``, which provides support for parsing [Stockholm-formatted alignment files](http://sonnhammer.sbc.su.se/Stockholm.html) and working with those alignments in the context RNA secondary structural information. * Added ``skbio.core.tree.majority_rule`` function for computing consensus trees from a list of trees. ### Backward-incompatible changes * Function ``skbio.core.alignment.align_striped_smith_waterman`` renamed to ``local_pairwise_align_ssw`` and now returns an ``Alignment`` object instead of an ``AlignmentStructure`` * The following keyword-arguments for ``StripedSmithWaterman`` and ``local_pairwise_align_ssw`` have been renamed: * ``gap_open`` -> ``gap_open_penalty`` * ``gap_extend`` -> ``gap_extend_penalty`` * ``match`` -> ``match_score`` * ``mismatch`` -> ``mismatch_score`` * Removed ``skbio.util.sort`` module in favor of [natsort](https://pypi.python.org/pypi/natsort) package. ### Miscellaneous * Added powertrip.py script to perform basic sanity-checking of the repo based on recurring issues that weren't being caught until release time; added to Travis build. * Added RELEASE.md with release instructions. * Added intersphinx mappings to docs so that "See Also" references to numpy, scipy, matplotlib, and pandas are hyperlinks. * The following classes are no longer ``namedtuple`` subclasses (see [#359](https://github.com/scikit-bio/scikit-bio/issues/359) for the rationale): * ``skbio.math.stats.ordination.OrdinationResults`` * ``skbio.math.gradient.GroupResults`` * ``skbio.math.gradient.CategoryResults`` * ``skbio.math.gradient.GradientANOVAResults`` * Added coding guidelines draft. * Added new alpha diversity formulas to the ``skbio.math.diversity.alpha`` documentation. ## Version 0.1.3 (2014-06-12) This is a pre-alpha release. At this stage, major backwards-incompatible API changes can and will happen. ### Features * Added ``enforce_qual_range`` parameter to ``parse_fastq`` (on by default, maintaining backward compatibility). This allows disabling of the quality score range-checking. * Added ``skbio.core.tree.nj``, which applies neighbor-joining for phylogenetic reconstruction. * Added ``bioenv``, ``mantel``, and ``pwmantel`` distance-based statistics to ``skbio.math.stats.distance`` subpackage. * Added ``skbio.math.stats.misc`` module for miscellaneous stats utility functions. * IDs are now optional when constructing a ``DissimilarityMatrix`` or ``DistanceMatrix`` (monotonically-increasing integers cast as strings are automatically used). * Added ``DistanceMatrix.permute`` method for randomly permuting rows and columns of a distance matrix. * Added the following methods to ``DissimilarityMatrix``: ``filter``, ``index``, and ``__contains__`` for ID-based filtering, index lookup, and membership testing, respectively. * Added ``ignore_comment`` parameter to ``parse_fasta`` (off by default, maintaining backward compatibility). This handles stripping the comment field from the header line (i.e., all characters beginning with the first space) before returning the label. * Added imports of ``BiologicalSequence``, ``NucleotideSequence``, ``DNA``, ``DNASequence``, ``RNA``, ``RNASequence``, ``Protein``, ``ProteinSequence``, ``DistanceMatrix``, ``align_striped_smith_waterman``, `` SequenceCollection``, ``Alignment``, ``TreeNode``, ``nj``, ``parse_fasta``, ``parse_fastq``, ``parse_qual``, ``FastaIterator``, ``FastqIterator``, ``SequenceIterator`` in ``skbio/__init__.py`` for convenient importing. For example, it's now possible to ``from skbio import Alignment``, rather than ``from skbio.core.alignment import Alignment``. ### Bug fixes * Fixed a couple of unit tests that could fail stochastically. * Added missing ``__init__.py`` files to a couple of test directories so that these tests won't be skipped. * ``parse_fastq`` now raises an error on dangling records. * Fixed several warnings that were raised while running the test suite with Python 3.4. ### Backward-incompatible changes * Functionality imported from ``skbio.core.ssw`` must now be imported from ``skbio.core.alignment`` instead. ### Miscellaneous * Code is now flake8-compliant; added flake8 checking to Travis build. * Various additions and improvements to documentation (API, installation instructions, developer instructions, etc.). * ``__future__`` imports are now standardized across the codebase. * New website front page and styling changes throughout. Moved docs site to its own versioned subdirectories. * Reorganized alignment data structures and algorithms (e.g., SSW code, ``Alignment`` class, etc.) into an ``skbio.core.alignment`` subpackage. ## Version 0.1.1 (2014-05-16) Fixes to setup.py. This is a pre-alpha release. At this stage, major backwards-incompatible API changes can and will happen. ## Version 0.1.0 (2014-05-15) Initial pre-alpha release. At this stage, major backwards-incompatible API changes can and will happen. scikit-bio-scikit-bio-a3beaa6/LICENSE.txt000066400000000000000000000027531520735541300202050ustar00rootroot00000000000000Copyright (c) 2013--, scikit-bio development team. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names scikit-bio, skbio, or biocore nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. scikit-bio-scikit-bio-a3beaa6/MANIFEST.in000066400000000000000000000005121520735541300201070ustar00rootroot00000000000000include CHANGELOG.md include LICENSE.txt include Makefile include pyproject.toml include README.rst graft ci graft doc graft licenses graft logos graft skbio prune doc/build prune doc/source/generated prune web/_build global-exclude *.pyc global-exclude *.pyo global-exclude *.so global-exclude .*.swp global-exclude .coverage scikit-bio-scikit-bio-a3beaa6/Makefile000066400000000000000000000024531520735541300200170ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- ifeq ($(WITH_COVERAGE), TRUE) TEST_COMMAND = coverage run --rcfile ../.coveragerc -m skbio.test && coverage report --rcfile ../.coveragerc else TEST_COMMAND = python -m skbio.test endif .PHONY: doc web lint test dev install doc: $(MAKE) -C doc clean html web: $(MAKE) -C web clean html clean: $(MAKE) -C doc clean $(MAKE) -C web clean rm -rf build dist scikit_bio.egg-info lint: ruff check skbio setup.py checklist.py ./checklist.py check-manifest # cd into a directory that is different from scikit-bio root directory to # simulate a user's install and testing of scikit-bio. Running from the root # directory will find the `skbio` subpackage (not necessarily the installed # one!) because cwd is considered in Python's search path. It is important to # simulate a user's install/test process this way to find package data that did # not install correctly (for example). test: cd ci && $(TEST_COMMAND) install: pip install . dev: pip install -e . scikit-bio-scikit-bio-a3beaa6/README.rst000066400000000000000000000145141520735541300200470ustar00rootroot00000000000000|license| |build| |coverage| |bench| |release| |pypi| |conda| |gitter| .. image:: logos/logo.svg :width: 600 px :target: https://scikit.bio :alt: scikit-bio logo *scikit-bio is an open-source, BSD-licensed Python 3 package providing data structures, algorithms and educational resources for bioinformatics.* Visit the scikit-bio website: https://scikit.bio to learn more about this project. Releases -------- Latest release: `0.7.3 `_ (`documentation `_, `changelog `_). Compatible with Python 3.10 and above. Installation ------------ Install the latest release of scikit-bio using ``conda``:: conda install -c conda-forge scikit-bio Or using ``pip``:: pip install scikit-bio See further `instructions on installing `_ scikit-bio on various platforms. Adoption -------- Some of the projects that we know of that are using scikit-bio are: - `QIIME 2 `_, `Qiita `_, `Emperor `_, `tax2tree `_, `ghost-tree `_, `Platypus-Conquistador `_, `An Introduction to Applied Bioinformatics `_. License ------- scikit-bio is available under the new BSD license. See `LICENSE.txt `_ for scikit-bio's license, and the `licenses directory `_ for the licenses of third-party software that is (either partially or entirely) distributed with scikit-bio. Team ---- Our core development team consists of three lead developers: **Dr. Qiyun Zhu** at Arizona State University (ASU) (@qiyunzhu), **Dr. James Morton** at Gutz Analytics (@mortonjt), and **Dr. Daniel McDonald** at the University of California San Diego (UCSD) (@wasade), and one dedicated software engineer: **Matthew Aton** at ASU (@mataton). **Dr. Rob Knight** at UCSD (@rob-knight) provides guidance on the development and research. **Dr. Greg Caporaso** (@gregcaporaso) at Northern Arizona University (NAU), the former leader of the scikit-bio project, serves as an advisor on the current project. Credits ------- We thank the many contributors to scikit-bio. A complete `list of contributors `_ to the scikit-bio codebase is available at GitHub. This however may miss the larger community who contributed by testing the software and providing valuable comments, who we hold equal appreciation to. Wanna contribute? We enthusiastically welcome community contributors! Whether it's adding new features, improving code, or enhancing documentation, your contributions drive scikit-bio and open-source bioinformatics forward. Start your journey by reading the `Contributor's guidelines `_. Funding ------- The development of scikit-bio is currently supported by the U.S. Department of Energy, Office of Science under award number `DE-SC0024320 `_, awarded to Dr. Qiyun Zhu at ASU (lead PI), Dr. James Morton at Gutz Analytics, and Dr. Rob Knight at UCSD. Citation -------- If you use scikit-bio for any published research, please cite: Aton, M., McDonald, D., Cañardo Alastuey, J. et al. Scikit-bio: a fundamental Python library for biological omic data analysis. *Nat Methods* (2025). https://doi.org/10.1038/s41592-025-02981-z The full text of this article is available at: https://rdcu.be/eUcOO. Collaboration ------------- For collaboration inquiries and other formal communications, please reach out to **Dr. Qiyun Zhu** at `qiyun.zhu@asu.edu`. We welcome academic and industrial partnerships to advance our mission. Branding -------- The logo of scikit-bio was created by `Alina Prassas `_. Vector and bitmap image files are available at the `logos `_ directory. Pre-history ----------- scikit-bio began from code derived from `PyCogent `_ and `QIIME `_, and the contributors and/or copyright holders have agreed to make the code they wrote for PyCogent and/or QIIME available under the BSD license. The contributors to PyCogent and/or QIIME modules that have been ported to scikit-bio are listed below: - Rob Knight (@rob-knight), Gavin Huttley (@gavinhuttley), Daniel McDonald (@wasade), Micah Hamady, Antonio Gonzalez (@antgonza), Sandra Smit, Greg Caporaso (@gregcaporaso), Jai Ram Rideout (@jairideout), Cathy Lozupone (@clozupone), Mike Robeson (@mikerobeson), Marcin Cieslik, Peter Maxwell, Jeremy Widmann, Zongzhi Liu, Michael Dwan, Logan Knecht (@loganknecht), Andrew Cochran, Jose Carlos Clemente (@cleme), Damien Coy, Levi McCracken, Andrew Butterfield, Will Van Treuren (@wdwvt1), Justin Kuczynski (@justin212k), Jose Antonio Navas Molina (@josenavas), Matthew Wakefield (@genomematt) and Jens Reeder (@jensreeder). .. |license| image:: https://img.shields.io/badge/License-BSD%203--Clause-blue.svg :alt: License :target: https://opensource.org/licenses/BSD-3-Clause .. |build| image:: https://github.com/scikit-bio/scikit-bio/actions/workflows/ci.yml/badge.svg :alt: Build Status :target: https://github.com/scikit-bio/scikit-bio/actions/workflows/ci.yml .. |coverage| image:: https://codecov.io/gh/scikit-bio/scikit-bio/graph/badge.svg?token=1qbzC6d2F5 :alt: Coverage Status :target: https://codecov.io/gh/scikit-bio/scikit-bio .. |bench| image:: https://img.shields.io/badge/benchmarked%20by-asv-green.svg :alt: ASV Benchmarks :target: https://scikit.bio/scikit-bio-benchmarks .. |release| image:: https://img.shields.io/github/v/release/scikit-bio/scikit-bio.svg :alt: Release :target: https://github.com/scikit-bio/scikit-bio/releases .. |pypi| image:: https://img.shields.io/pypi/dm/scikit-bio.svg?label=PyPI%20downloads :alt: PyPI Downloads :target: https://pypi.org/project/scikit-bio/ .. |conda| image:: https://img.shields.io/conda/dn/conda-forge/scikit-bio.svg?label=Conda%20downloads :alt: Conda Downloads :target: https://anaconda.org/conda-forge/scikit-bio .. |gitter| image:: https://badges.gitter.im/Join%20Chat.svg :alt: Gitter :target: https://gitter.im/biocore/scikit-bio scikit-bio-scikit-bio-a3beaa6/checklist.py000077500000000000000000000420531520735541300207050ustar00rootroot00000000000000#!/usr/bin/env python """Validate the content and structure of a scikit-bio repository. ---------------------------------------------------------------------------- Copyright (c) 2013--, scikit-bio development team. Distributed under the terms of the Modified BSD License. The full license is in the file LICENSE.txt, distributed with this software. ---------------------------------------------------------------------------- """ import collections import os import os.path import subprocess import sys import ast import tokenize import warnings import dateutil.parser if sys.version_info.major != 3: sys.exit( "scikit-bio can only be used with Python 3. You are currently " "running Python %d." % sys.version_info.major ) class ChecklistWarning(Warning): """General warning class for warnings raised by checklist.py.""" pass def main(): """Go on a power trip by nitpicking the scikit-bio repo. Attempts to find things that are wrong with the repo -- these are usually annoying details introduced by human error. The code goes out of its way to nitpick as much as possible in order to maximize the effectiveness of the power trip. Returns ------- int Return code: 0 if there were no validation errors, 1 otherwise. Useful as an exit code (e.g. for use with ``sys.exit``). """ root = "skbio" validators = [ InitValidator(), CopyrightHeadersValidator(), ExecPermissionValidator(), GeneratedCythonValidator(), APIRegressionValidator(), ] return_code = 0 for validator in validators: success, msg = validator.validate(root) if not success: return_code = 1 sys.stderr.write("\n".join(msg)) sys.stderr.write("\n\n") return return_code class RepoValidator: """Abstract base class representing a repository validator. Subclasses must override and implement ``_validate`` (see its docstring for more details). Subclasses should also provide a ``reason``: this is a string describing the reason for a particular type of validation failure (see subclasses for examples). ``reason`` is included in the validation error message/report created by ``validate``. """ reason = "" def validate(self, root): """Validate a directory tree recursively. Parameters ---------- root : str Root directory to validate recursively. Returns ------- tuple of (bool, list of str) First element is a ``bool`` indicating success status: ``True`` if `root` passed validation, ``False`` if there were any errors. Second element is a list of strings containing the validation error message. """ invalids = [] for root, dirs, files in os.walk(root): result = self._validate(root, dirs, files) invalids.extend(result) success = True msg = [] if invalids: success = False msg.append(self.reason) for invalid in invalids: msg.append(" %s" % invalid) return success, msg def _validate(self, root, dirs, files): """Validate a single directory. Subclasses must override and implement this method. The method is supplied with the three values yielded by ``os.walk``. Parameters ---------- root : str Path to the current directory to be validated. dirs : list of str Directory names within `root`. files : list of str Filenames within `root`. Returns ------- list of str List of filepaths or dirpaths to be considered invalid (i.e., that did not pass the validation checks). See Also -------- os.walk """ raise NotImplementedError("Subclasses must implement _validate.") def _system_call(self, cmd): """Issue a system call, returning stdout, stderr, and return value. This code was taken from verman's ``verman.Version.verman_system_call``. See licenses/verman.txt and https://github.com/biocore/verman for more details. """ proc = subprocess.Popen( cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) # communicate pulls all stdout/stderr from the PIPEs to # avoid blocking -- don't remove this line! stdout, stderr = proc.communicate() return_value = proc.returncode return stdout, stderr, return_value class CopyrightHeadersValidator(RepoValidator): """Flag library files with non-standard copyright headers. See the current standard for scikit-bio's copyright headers at ``https://scikit.bio/devdoc/new_module.html`` Individual files are ignored if the first line in the file is exactly: # checklist.py:CopyrightHeadersValidator IGNORE If a file is ignored, a ``ChecklistWarning`` is raised. Parameters ---------- skip_dirs : iterable of str, optional Directory names to skip during validation. Defaults to skipping any directories named ``'data'`` or ``'__pycache__'`` (and anything contained within them). """ reason = ( "Files non-conforming to standard headers as described in\n" "https://scikit.bio/devdoc/new_module.html:" ) COPYRIGHT_HEADER = """\ # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """ def __init__(self, skip_dirs=None): """Initialize with directories to skip.""" if skip_dirs is None: skip_dirs = {"data", "__pycache__"} self.skip_dirs = set(skip_dirs) def _validate(self, root, dirs, files): for skip_dir in self.skip_dirs: if skip_dir in dirs: dirs.remove(skip_dir) invalid_files = [] for _file in files: if not _file.endswith(".py"): continue pos = 0 filepath = os.path.join(root, _file) f = open(filepath) first_line = f.readline().rstrip("\n") if first_line == "# checklist.py:CopyrightHeadersValidator IGNORE": warnings.warn( "File %s has IGNORE directive. Ignoring scikit-bio " "copyright header validation." % filepath, ChecklistWarning, ) continue f.seek(0) tokens = list(tokenize.generate_tokens(f.readline)) # A module docstring is fully described using just two tokens: the # main string and a terminating newline. By convention, however, it # is always followed by a newline, and thus we advance by three # positions to get to the next logical line. if tokens[pos][0] == tokenize.STRING: pos += 3 # copyright header consists of 7 lines, and by discussion in # preceding comment, spans through 14 tokens. cheader = "".join(map(lambda x: x[1], tokens[pos : pos + 14])) # Ensure that there is no blank line at the end of the file if cheader != self.COPYRIGHT_HEADER or ( tokens[pos + 14][0] != tokenize.NL and tokens[pos + 14][0] != tokenize.ENDMARKER ): invalid_files.append(f.name) f.close() return invalid_files class InitValidator(RepoValidator): """Flag library code directories that are missing init files. This type of validation is important mainly because it is very easy to forget to add an __init__.py file to a new test directory. If this happens, nose will skip those tests unless it is run from the root of the source repository. Thus, the tests will be skipped if the package is pip-installed, e.g., as an end-user might install a release. Parameters ---------- skip_dirs : iterable of str, optional Directory names to skip during validation. Defaults to skipping any directories named ``'data'`` or ``'__pycache__'`` (and anything contained within them). """ reason = "Directories missing init files:" def __init__(self, skip_dirs=None): """Initialize with directories to skip.""" if skip_dirs is None: skip_dirs = {"data", "__pycache__"} self.skip_dirs = set(skip_dirs) def _validate(self, root, dirs, files): # If any of the directories yet to be visited should be skipped, remove # them from ``dirs`` so that we don't visit them in a future iteration. # This guarantees that ``root`` is a valid directory that should not be # skipped (since we're doing a top-down walk). for skip_dir in self.skip_dirs: if skip_dir in dirs: dirs.remove(skip_dir) invalid_dirs = [] if "__init__.py" not in files: invalid_dirs.append(root) return invalid_dirs class ExecPermissionValidator(RepoValidator): """Flag code files that have execute permissions. Parameters ---------- extensions : iterable of str, optional File extensions of files to validate. Defaults to Python, Cython, and C files (header and source files). """ reason = "Library code with execute permissions:" def __init__(self, extensions=None): """Initialize with specific file extensions.""" if extensions is None: extensions = {".py", ".pyx", ".h", ".c"} self.extensions = set(extensions) def _validate(self, root, dirs, files): invalid_fps = [] for f in files: _, ext = os.path.splitext(f) if ext in self.extensions: fp = os.path.join(root, f) if os.access(fp, os.X_OK): invalid_fps.append(fp) return invalid_fps class GeneratedCythonValidator(RepoValidator): """Flag Cython files that have missing or outdated generated C files. Flags Cython files that aren't paired with an up-to-date generated C file. The generated C file must be in the same directory as the Cython file, and its name (besides the file extension) must match. The validator also ensures that the generated C file is not empty and that it was generated at the same time or later than the Cython file's timestamp. Parameters ---------- cython_ext : str, optional File extension for Cython files. c_ext : str, optional File extension for generated C files. """ reason = "Cython code with missing or outdated generated C code:" def __init__(self, cython_ext=".pyx", c_ext=".c"): """Initialize with specific file extensions.""" self.cython_ext = cython_ext self.c_ext = c_ext def _validate(self, root, dirs, files): invalid_fps = [] ext_to_base = collections.defaultdict(list) # Map from file extension to a list of basenames (without the # extension). for f in files: base, ext = os.path.splitext(f) ext_to_base[ext].append(base) # For each Cython file, try to find a matching C file. If we have a # match, make sure the C file isn't empty and that it was generated at # the same time or later than the Cython file. for cython_base in ext_to_base[self.cython_ext]: cython_fp = os.path.join(root, cython_base + self.cython_ext) c_fp = os.path.join(root, cython_base + self.c_ext) if cython_base not in ext_to_base[self.c_ext]: invalid_fps.append(cython_fp) elif os.path.getsize(c_fp) <= 0: invalid_fps.append(cython_fp) else: cython_ts = self._get_timestamp(cython_fp) c_ts = self._get_timestamp(c_fp) if c_ts < cython_ts: invalid_fps.append(cython_fp) return invalid_fps def _get_timestamp(self, fp): cmd = 'git log -1 --format="%%ad" -- %s' % fp stdout, stderr, retval = self._system_call(cmd) if retval != 0: raise RuntimeError( "Could not execute 'git log' command to determine file timestamp." ) return dateutil.parser.parse(stdout.strip()) class APIRegressionValidator(RepoValidator): """Flag tests that import from a non-minimized subpackage hierarchy. Flags tests that aren't imported from a minimally deep API target. (e.g. skbio.TabularMSA vs skbio.alignment.TabularMSA). This should prevent accidental regression in our API because tests will fail if any alias is removed, and this checklist will fail if any test doesn't import from the least deep API target. """ reason = "The following tests import `A` but should import `B` (file: A => B):" def __init__(self): """Initialize object for tests importing from non-minimized hierarchy.""" self._imports = {} def _validate(self, root, dirs, files): errors = [] test_imports = [] for file in files: current_fp = os.path.join(root, file) package, ext = os.path.splitext(current_fp) if ext == ".py": imports = self._parse_file(current_fp, root) if os.path.split(root)[1] == "tests": test_imports.append((current_fp, imports)) temp = package.split(os.sep) # Remove the __init__ if it is a directory import if temp[-1] == "__init__": temp = temp[:-1] package = ".".join(temp) self._add_imports(imports, package) for fp, imports in test_imports: for import_ in imports: substitute = self._minimal_import(import_) if substitute is not None: errors.append("%s: %s => %s" % (fp, import_, substitute)) return errors def _add_imports(self, imports, package): """Add the minimum depth import to our collection.""" for import_ in imports: value = import_ # The actual object imported will be the key. key = import_.split(".")[-1] # If package importing the behavior is shorter than its import: if len(package.split(".")) + 1 < len(import_.split(".")): value = ".".join([package, key]) if key in self._imports: sub = self._imports[key] if len(sub.split(".")) > len(value.split(".")): self._imports[key] = value else: self._imports[key] = value def _minimal_import(self, import_): """Given an normalized import, return a shorter substitute or None.""" key = import_.split(".")[-1] if key not in self._imports: return None substitute = self._imports[key] if len(substitute.split(".")) == len(import_.split(".")): return None else: return substitute def _parse_file(self, fp, root): """Parse a file and return all normalized skbio imports.""" imports = [] with open(fp) as f: # Read the file and run it through AST source = ast.parse(f.read()) # Get each top-level element, this is where API imports should be. for node in ast.iter_child_nodes(source): if isinstance(node, ast.Import): # Standard imports are easy, just get the names from the # ast.Alias list `node.names` imports += [x.name for x in node.names] elif isinstance(node, ast.ImportFrom): prefix = "" # Relative import handling. if node.level > 0: prefix = root extra = node.level - 1 while extra > 0: # Keep dropping... prefix = os.path.split(prefix)[0] extra -= 1 # We need this in '.' form not '/' prefix = prefix.replace(os.sep, ".") + "." # Prefix should be empty unless node.level > 0 if node.module is None: node.module = "" imports += [ ".".join([prefix + node.module, x.name]) for x in node.names ] skbio_imports = [] for import_ in imports: # Filter by skbio if import_.split(".")[0] == "skbio": skbio_imports.append(import_) return skbio_imports if __name__ == "__main__": sys.exit(main()) scikit-bio-scikit-bio-a3beaa6/ci/000077500000000000000000000000001520735541300167465ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/ci/conda_host_env.yml000066400000000000000000000002131520735541300224560ustar00rootroot00000000000000name: testing channels: - conda-forge - defaults dependencies: - hdf5 - pip - cython - pip: - "-r requirements.test.txt" scikit-bio-scikit-bio-a3beaa6/ci/requirements.doc.txt000066400000000000000000000002051520735541300227730ustar00rootroot00000000000000sphinx sphinx-design sphinx-copybutton pydata-sphinx-theme sphinxcontrib-youtube sphinx-sitemap numpydoc matplotlib statsmodels patsyscikit-bio-scikit-bio-a3beaa6/ci/requirements.lint.txt000066400000000000000000000000651520735541300232000ustar00rootroot00000000000000check-manifest python-dateutil numpy ruff pre-commit scikit-bio-scikit-bio-a3beaa6/ci/requirements.test.txt000066400000000000000000000000441520735541300232060ustar00rootroot00000000000000matplotlib pytest responses coveragescikit-bio-scikit-bio-a3beaa6/ci/requirements.txt000066400000000000000000000003031520735541300222260ustar00rootroot00000000000000requests >= 2.20.0 decorator >= 3.4.2 natsort >= 4.0.3 numpy >= 2.0 pandas >= 1.5.0 scipy >= 1.9.0 h5py >= 3.6.0 biom-format >= 2.1.16 statsmodels >= 0.14.0 patsy >= 0.5.0 array-api-compat >= 1.3scikit-bio-scikit-bio-a3beaa6/doc/000077500000000000000000000000001520735541300171205ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/doc/Makefile000066400000000000000000000157011520735541300205640ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. # Turn warnings into errors. SPHINXOPTS = -W SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" # In addition to removing everything from the build directory, we must also # remove the stubs for classes, functions, etc. that autosummary creates during # the build process. This differs from the original 'make clean' target that is # created by sphinx-quickstart. clean: rm -rf $(BUILDDIR)/* source/generated html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/scikit-bio.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/scikit-bio.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/scikit-bio" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/scikit-bio" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." scikit-bio-scikit-bio-a3beaa6/doc/README.md000066400000000000000000000004701520735541300204000ustar00rootroot00000000000000scikit-bio documentation ======================== Documentation of the latest release: https://scikit.bio/docs/latest/index.html Documentation of the current development version: https://scikit.bio/docs/dev/index.html Guidelines for contributing to the documentation: https://scikit.bio/devdoc/doc_guide.html scikit-bio-scikit-bio-a3beaa6/doc/editmap.py000066400000000000000000000020501520735541300211120ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # Script to manipulate sitemap.xml. import os import re # -- Configuration ----------------------------------------------------------- rootdir = "build/html" sitemap = 'sitemap.xml' # -- Workflow ---------------------------------------------------------------- pattern = re.compile(r'(.*?)', flags=re.DOTALL) def substitute(match): s = match.group() # omit pages like "__eq__.html" if '__.html' in s: return '' return s cwd = os.getcwd() os.chdir(os.path.join(os.path.dirname(__file__), rootdir)) with open(sitemap, 'r') as f: content = f.read() content = pattern.sub(substitute, content) with open(sitemap, 'w') as f: f.write(content) os.chdir(cwd) scikit-bio-scikit-bio-a3beaa6/doc/metatag.py000066400000000000000000000037471520735541300211270ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # Script to insert a meta description tag into each documentation page. The # content is the first line of the docstring of the corresponding object. import os import re import glob import html # -- Configuration ----------------------------------------------------------- rootdir = "build/html" max_length = 160 # -- Workflow ---------------------------------------------------------------- dd_pattern = re.compile(r'
(.*?)
', flags=re.DOTALL) p_pattern = re.compile(r'

(.*?)

', flags=re.DOTALL) meta_pattern = re.compile(r'(\s*)(]*\/?>)') cwd = os.getcwd() os.chdir(os.path.join(os.path.dirname(__file__), rootdir)) for file in glob.glob("**/*.html", recursive=True): with open(file, "r") as fh: content = fh.read() # find first line of docstring (summary) dd_match = dd_pattern.search(content) if not dd_match: continue p_match = p_pattern.search(dd_match.group(1)) if not p_match: continue summary = p_match.group(1) # truncate summary to given length if len(summary) > max_length: summary = summary[:max_length - 3] if ' ' in summary: summary = summary.rsplit(' ', 1)[0] summary += "..." # make summary safe for HTML summary = html.escape(summary) # insert summary into metadata line = f'' meta_match = meta_pattern.search(content) if not meta_match: continue indent = meta_match.group(1) pos = meta_match.end() content = content[:pos] + indent + line + content[pos:] with open(file, "w") as fh: fh.write(content) os.chdir(cwd) scikit-bio-scikit-bio-a3beaa6/doc/source/000077500000000000000000000000001520735541300204205ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/doc/source/_static/000077500000000000000000000000001520735541300220465ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/doc/source/_static/css/000077500000000000000000000000001520735541300226365ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/doc/source/_static/css/style.css000066400000000000000000000040301520735541300245050ustar00rootroot00000000000000/* ---------------------------------------------------------------------------- Copyright (c) 2013--, scikit-bio development team. Distributed under the terms of the Modified BSD License. The full license is in the file LICENSE.txt, distributed with this software. ---------------------------------------------------------------------------- */ /* Custom stylesheet for the Sphinx documentation with the PyData theme. Instructions: https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/styling.html */ html { /* hide external link icon */ --pst-icon-external-link: unset; /* custom font sizes for heading levels */ --pst-font-size-h1: 2rem; --pst-font-size-h2: 1.5rem; --pst-font-size-h3: 1.25rem; --pst-font-size-h4: 1.1rem; --pst-font-size-h5: 1.0rem; --pst-font-size-h6: 1.0rem; } /* remove inline code borders and background */ code { border: none !important; background-color: transparent !important; } /* brand color (monochromatic: shamrock green) */ /* primary color (for links, default: teal) secondary color (for links on hover, default: violet) target color (for highlights, default: sunset) inline code color (default: violet) */ html[data-theme="light"] { --pst-color-primary: #239552; --pst-color-target: #F5FDC6; --pst-color-secondary: var(--pst-color-primary); --pst-color-inline-code: var(--pst-color-accent); --pst-color-link-higher-contrast: var(--pst-color-primary); --pst-color-table-row-hover-bg: var(--pst-color-target); } html[data-theme="dark"] { --pst-color-primary: #72C093; --pst-color-target: #2C1E7F; --pst-color-secondary: var(--pst-color-primary); --pst-color-inline-code: var(--pst-color-accent); --pst-color-link-higher-contrast: var(--pst-color-primary); --pst-color-table-row-hover-bg: var(--pst-color-target); } /* banner background color (default: violet) */ html[data-theme="light"] div.bd-header-announcement { background-color: var(--pst-color-target); } html[data-theme="dark"] div.bd-header-announcement { background-color: var(--pst-color-target); } scikit-bio-scikit-bio-a3beaa6/doc/source/_static/favicon.ico000066400000000000000000000013761520735541300241760ustar00rootroot00000000000000 è( @�¶ ‡·(‹¼/”¿?ŸÆR«Íf´Ó}ÃÛ“ÅÛœÊà¥Õç·áìÆìôÞóøîûÿý!!PNì!îÄ !nì0ë"îqÎç !!º0\îQîVîÓ!Þ¾ë1îîaîéîî¡íné&íîRì1žá!!!ì! ì! ë!î`ê®Á!ê>ç è–ç!æ!!æ!!!æ!!!ææÕ! !!!scikit-bio-scikit-bio-a3beaa6/doc/source/_static/logo.svg000066400000000000000000000144751520735541300235420ustar00rootroot00000000000000 image/svg+xmlscikit-bio-scikit-bio-a3beaa6/doc/source/_static/logo_inv.svg000066400000000000000000000144751520735541300244160ustar00rootroot00000000000000 image/svg+xmlscikit-bio-scikit-bio-a3beaa6/doc/source/_templates/000077500000000000000000000000001520735541300225555ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/doc/source/_templates/TreeNode.rst000066400000000000000000000055751520735541300250300ustar00rootroot00000000000000{# This template is specifically for skbio.tree.TreeNode. #} {% extends "autosummary/class.rst" %} {% block methods %} .. rubric:: Tree IO .. autosummary:: :toctree: ~{{ name }}.read ~{{ name }}.write .. rubric:: Tree navigation .. autosummary:: :toctree: ~{{ name }}.ancestors ~{{ name }}.has_children ~{{ name }}.is_root ~{{ name }}.is_tip ~{{ name }}.lca ~{{ name }}.neighbors ~{{ name }}.path ~{{ name }}.root ~{{ name }}.siblings .. rubric:: Tree traversal .. autosummary:: :toctree: ~{{ name }}.levelorder ~{{ name }}.non_tips ~{{ name }}.postorder ~{{ name }}.pre_and_postorder ~{{ name }}.preorder ~{{ name }}.tips ~{{ name }}.traverse .. rubric:: Tree copying .. autosummary:: :toctree: ~{{ name }}.copy .. rubric:: Tree manipulation .. autosummary:: :toctree: ~{{ name }}.append ~{{ name }}.bifurcate ~{{ name }}.extend ~{{ name }}.insert ~{{ name }}.pop ~{{ name }}.prune ~{{ name }}.remove ~{{ name }}.remove_by_func ~{{ name }}.shear ~{{ name }}.shuffle ~{{ name }}.unpack ~{{ name }}.unpack_by_func .. rubric:: Tree rerooting .. autosummary:: :toctree: ~{{ name }}.root_at ~{{ name }}.root_at_midpoint ~{{ name }}.root_by_outgroup ~{{ name }}.unroot ~{{ name }}.unrooted_copy ~{{ name }}.unrooted_move .. rubric:: Tree searching .. autosummary:: :toctree: ~{{ name }}.assign_ids ~{{ name }}.cache_attr ~{{ name }}.clear_caches ~{{ name }}.create_caches ~{{ name }}.has_caches ~{{ name }}.find ~{{ name }}.find_all ~{{ name }}.find_by_func ~{{ name }}.find_by_id ~{{ name }}.index_tree .. rubric:: Tree analysis .. autosummary:: :toctree: ~{{ name }}.bipart ~{{ name }}.biparts ~{{ name }}.cophenet ~{{ name }}.count ~{{ name }}.depth ~{{ name }}.distance ~{{ name }}.height ~{{ name }}.is_bifurcating ~{{ name }}.maxdist ~{{ name }}.observed_node_counts ~{{ name }}.subset ~{{ name }}.subsets ~{{ name }}.total_length .. rubric:: Tree comparison .. autosummary:: :toctree: ~{{ name }}.compare_biparts ~{{ name }}.compare_cophenet ~{{ name }}.compare_rfd ~{{ name }}.compare_subsets ~{{ name }}.compare_wrfd .. rubric:: Tree visualization .. autosummary:: :toctree: ~{{ name }}.ascii_art .. rubric:: Format conversion .. autosummary:: :toctree: ~{{ name }}.assign_supports ~{{ name }}.from_linkage_matrix ~{{ name }}.from_taxdump ~{{ name }}.from_taxonomy ~{{ name }}.to_array ~{{ name }}.to_taxonomy {% endblock %} scikit-bio-scikit-bio-a3beaa6/doc/source/_templates/autosummary/000077500000000000000000000000001520735541300251435ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/doc/source/_templates/autosummary/attribute.rst000066400000000000000000000001551520735541300277010ustar00rootroot00000000000000:orphan: {{ fullname }} {{ underline }} .. currentmodule:: {{ module }} .. autoattribute:: {{ objname }} scikit-bio-scikit-bio-a3beaa6/doc/source/_templates/autosummary/class.rst000066400000000000000000000066171520735541300270140ustar00rootroot00000000000000{# This template was modified from autosummary's default template. #} {{ fullname | escape | underline}} {# Identify special methods (i.e., dunder or magic methods) that are relevant. #} {% set methods_to_ignore = [ '__class__', '__delattr__', '__getattribute__', '__init__', '__dir__', '__format__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__subclasshook__', '__init_subclass__', '__class_getitem__', ] %} {% set special_methods = [] %} {% for item in all_methods %} {% if item.startswith('__') and item not in methods_to_ignore %} {{ special_methods.append(item) or '' }} {% endif %} {% endfor %} {# Distinguish inherited and own members. #} {% set inherited_attributes = [] %} {% set own_attributes = [] %} {% for item in attributes %} {% if item in inherited_members %} {{ inherited_attributes.append(item) or '' }} {% else %} {{ own_attributes.append(item) or '' }} {% endif %} {% endfor %} {% set inherited_methods = [] %} {% set own_methods = [] %} {% for item in methods %} {% if item != '__init__' %} {% if item in inherited_members %} {{ inherited_methods.append(item) or '' }} {% else %} {{ own_methods.append(item) or '' }} {% endif %} {% endif %} {% endfor %} {% set inherited_special_methods = [] %} {% set own_special_methods = [] %} {% for item in special_methods %} {% if item in inherited_members %} {{ inherited_special_methods.append(item) or '' }} {% else %} {{ own_special_methods.append(item) or '' }} {% endif %} {% endfor %} {# Class name, signatures, superclass (if any) and docstring. #} .. currentmodule:: {{ module }} .. autoclass:: {{ objname }} {# Table of contents #} {% block attributes %} {% if own_attributes %} .. rubric:: Attributes .. autosummary:: {% for item in own_attributes %} ~{{ name }}.{{ item }} {%- endfor %} {% endif %} {% if inherited_attributes %} .. rubric:: Attributes (inherited) .. autoinherit:: {% for item in inherited_attributes %} ~{{ name }}.{{ item }} {%- endfor %} {% endif %} {% endblock %} {% block methods %} {% if own_methods %} .. rubric:: Methods .. autosummary:: :toctree: {% for item in own_methods %} ~{{ name }}.{{ item }} {% endfor %} {% endif %} {% if inherited_methods %} .. rubric:: Methods (inherited) .. autoinherit:: {%- for item in inherited_methods %} ~{{ name }}.{{ item }} {%- endfor %} {% endif %} {% endblock %} {% block special_methods %} {% if own_special_methods %} .. rubric:: Special methods .. autosummary:: {% for item in own_special_methods %} ~{{ name }}.{{ item }} {%- endfor %} {% endif %} {% if inherited_special_methods %} .. rubric:: Special methods (inherited) .. autoinherit:: {% for item in inherited_special_methods %} ~{{ name }}.{{ item }} {%- endfor %} {% endif %} {% endblock %} {# Detailed documentation #} {% block details %} .. rubric:: Details {% for item in own_attributes %} {% if item not in inherited_members %} .. autoattribute:: {{ name }}.{{ item }} {% endif %} {% endfor %} {% for item in own_special_methods %} {% if item not in inherited_members %} .. automethod:: {{ name }}.{{ item }} {% endif %} {% endfor %} {% endblock %} scikit-bio-scikit-bio-a3beaa6/doc/source/_templates/autosummary/method.rst000066400000000000000000000001521520735541300271530ustar00rootroot00000000000000:orphan: {{ fullname }} {{ underline }} .. currentmodule:: {{ module }} .. automethod:: {{ objname }} scikit-bio-scikit-bio-a3beaa6/doc/source/_templates/autosummary/module.rst000066400000000000000000000006741520735541300271710ustar00rootroot00000000000000.. The extra blocks seem to be required for autosummary to populate our docstrings correctly. In the original template, these would recusively call autosummary again, but we already do that in the narratively convenient places. .. automodule:: {{ fullname }} {% block attributes %} {% endblock %} {% block functions %} {% endblock %} {% block classes %} {% endblock %} {% block exceptions %} {% endblock %} scikit-bio-scikit-bio-a3beaa6/doc/source/_templates/namedtuple.rst000066400000000000000000000001361520735541300254450ustar00rootroot00000000000000{{ fullname }} {{ underline }} .. currentmodule:: {{ module }} .. autoclass:: {{ objname }} scikit-bio-scikit-bio-a3beaa6/doc/source/alignment.rst000066400000000000000000000001671520735541300231340ustar00rootroot00000000000000.. meta:: :description: Computing and manipulating biological sequence alignments. .. automodule:: skbio.alignment scikit-bio-scikit-bio-a3beaa6/doc/source/autoinherit.py000066400000000000000000000052671520735541300233370ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from sphinx.util.inspect import safe_getattr def trace_inherit(name, real_name): """Trace the base class from which a member is inherited. Parameters ---------- name : str Public name of the member. real_name : str True import path of the member. Returns ------- str Import path of the member from the base class. """ # `real_name` is the full path to the member, such as: # skbio.sequence.DNA.frequencies # It can be split into: # module: skbio.sequence # class: DNA # member: frequencies # `member` should be identical to `name`, therefore the `name` parameter # is actually redundant in this function. try: mod_name, cls_name, _ = real_name.rsplit(".", 2) except ValueError: return # Import the class which has the member. try: module = __import__(mod_name, fromlist=[cls_name]) except ImportError: return try: cls = safe_getattr(module, cls_name, None) except AttributeError: return # Make sure class has the member. # If the member is inherited, `hasattr` returns True but `cls.__dict__` # does not have it. if not hasattr(cls, name): return # Trace back the method resolution order (MRO) of the class to identify # the base class that has the same member. # If the member is owned by the current class (i.e., not inherited), it # will return the current class. origin = None for base in cls.__mro__: if name in base.__dict__: if base.__module__.startswith("skbio."): origin = base break if not origin: return # Get fully qualified name of the base class, such as: # skbio.sequence.Sequence # In scikit-bio, classes are implemented in files starting with `_` (e.g., # `_base.py`) but are imported in `__init__.py` of the module. Therefore, # the following code converts the name below into the above: # skbio.sequence._sequence.Sequence # However, if in the future this structure changes, the code needs to be # modified. path = origin.__module__.split(".") while path and path[-1].startswith("_"): del path[-1] # Eventually, it returns: # skbio.sequence.Sequence.frequencies return ".".join(path + [origin.__name__, name]) scikit-bio-scikit-bio-a3beaa6/doc/source/conf.py000066400000000000000000000220451520735541300217220ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # Configuration file for the Sphinx documentation builder. # Instructions: # https://www.sphinx-doc.org/en/master/usage/configuration.html import sys import inspect from datetime import datetime from os.path import abspath, relpath, dirname import skbio sys.path.insert(0, abspath('.')) # -- Project information ----------------------------------------------------- project = 'scikit-bio' author = f'{project} development team' copyright = f'2014-{datetime.now().year}, {author}' version = skbio.__version__ release = skbio.__version__ # -- General configuration --------------------------------------------------- extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.mathjax', 'sphinx.ext.linkcode', 'sphinx.ext.coverage', 'sphinx.ext.doctest', 'sphinx.ext.autosummary', 'sphinx.ext.intersphinx', 'sphinx.ext.extlinks', 'numpydoc', 'sphinx_design', 'sphinx_copybutton', 'matplotlib.sphinxext.plot_directive', 'sphinx_sitemap', ] root_doc = 'index' templates_path = ['_templates'] exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # set to none to avoid overly complicated function signatures autodoc_typehints = 'none' # -- Options for manual page output ------------------------------------------ # Elements: startdocname, name, description, authors, section man_pages = [ (root_doc, project, f'{project} Documentation', author, 1), ] # -- Options for Texinfo output ---------------------------------------------- # Elements: startdocname, targetname, title, author, dir_entry, description, # category, [toctree_only] texinfo_documents = [ (root_doc, project, f'{project} Documentation', author, project, 'Data structures, algorithms, and educational resources for working with ' 'biological data in Python.', 'Science'), ] # -- Options for HTML output ------------------------------------------------- html_title = f'{project} {version} documentation' html_short_title = project html_baseurl = 'https://scikit.bio' html_logo = '_static/logo.svg' html_favicon = '_static/favicon.ico' htmlhelp_basename = 'skbio-doc' # static files html_static_path = ['_static'] html_css_files = ['css/style.css'] # do not show source links html_show_sourcelink = False # do not show () after function link add_function_parentheses = False # -- External links ---------------------------------------------------------- github_url = f'https://github.com/{project}/{project}' twitter_url = 'https://twitter.com/scikitbio' wiki_url = 'https://en.wikipedia.org/wiki' extlinks = { 'home': (f'{html_baseurl}/%s', None), 'repo': (f'{github_url}/%s', None), 'wiki': (f'{wiki_url}/%s', None), 'install': (f'{html_baseurl}/install.html%s', None) } # -- Sitemap configuration --------------------------------------------------- doc_dir = 'dev' if version.endswith('-dev') else version sitemap_url_scheme = f'/docs/{doc_dir}/{{link}}' # -- numpydoc configuration -------------------------------------------------- # References: # https://numpydoc.readthedocs.io/en/latest/install.html#configuration numpydoc_class_members_toctree = False numpydoc_show_class_members = False numpydoc_show_inherited_class_members = False # -- PyData Theme configuration ---------------------------------------------- # References: # https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/layout.html# # references html_theme = 'pydata_sphinx_theme' html_theme_options = { # logo image for light/dark modes # image files must be placed under _static/ 'logo': { 'link': html_baseurl, 'alt_text': html_title, 'image_light': '_static/logo.svg', 'image_dark': '_static/logo_inv.svg', }, # social media links displayed as icons 'github_url': github_url, 'twitter_url': twitter_url, # show warning if not latest stable version # 'show_version_warning_banner': True, # version switcher 'switcher': { 'json_url': f'{html_baseurl}/versions.json', 'version_match': doc_dir, }, # simplify section navigation 'navigation_depth': 2, 'collapse_navigation': True, # display all header links 'header_links_before_dropdown': 7, # header layout 'navbar_start': ['navbar-logo', 'version-switcher'], # footer layout 'footer_start': ['copyright'], 'footer_center': ['sphinx-version'], 'footer_end': ['theme-version'], # google analytics 'analytics': { 'google_analytics_id': 'UA-6636235-9', } } # -- Intersphinx configuration ----------------------------------------------- # References: # https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html intersphinx_mapping = { 'python': ('https://docs.python.org/3/', None), 'numpy': ('https://numpy.org/doc/stable/', None), 'scipy': ('https://docs.scipy.org/doc/scipy/', None), 'matplotlib': ('https://matplotlib.org/stable/', None), 'pandas': ('https://pandas.pydata.org/docs/', None), 'sklearn': ('https://scikit-learn.org/stable/', None), 'statsmodels': ('https://www.statsmodels.org/stable/', None), # 'biom-format': ('https://biom-format.org/', None), 'polars': ('https://docs.pola.rs/api/python/stable/', None), 'anndata': ('https://anndata.readthedocs.io/en/stable/', None), 'array_api': ('https://data-apis.org/array-api/latest/', None), } # -- matplotlib.sphinxext.plot_directive ------------------------------------- # References: # https://matplotlib.org/stable/api/sphinxext_plot_directive_api.html plot_include_source = True plot_html_show_source_link = False plot_formats = ['png'] plot_html_show_formats = False # -- Source code links -------------------------------------------------------- def linkcode_resolve(domain, info): """Determine the URL corresponding to a Python object. """ if domain != 'py': return None modname = info['module'] fullname = info['fullname'] submod = sys.modules.get(modname) if submod is None: return None obj = submod for part in fullname.split('.'): try: obj = getattr(obj, part) except: return None # Link to functions, not decorators while hasattr(obj, "__wrapped__"): obj = obj.__wrapped__ try: fn = inspect.getsourcefile(obj) except: fn = None if not fn: try: fn = inspect.getsourcefile(sys.modules[obj.__module__]) except: fn = None if not fn: return None try: _, lineno = inspect.findsource(obj) except: lineno = None branch = 'main' if 'dev' in version else version fn = relpath(fn, start=dirname(skbio.__file__)) linespec = f'#L{lineno + 1}' if lineno else '' return f'{github_url}/blob/{branch}/skbio/{fn}{linespec}' # You might see the following exception when building the documentation: # TypeError: 'abstractproperty' object is not iterable from skbio.util._decorator import classproperty def _closure(): def __get__(self, cls, owner): return self classproperty.__get__ = __get__ _closure() # Custom classes to patch Sphinx extension "autosummary". from sphinx.ext.autosummary import Autosummary # -- Hide signatures ---------------------------------------------------------- class NoSignatureAutosummary(Autosummary): """Hide member signatures from autosummary toctrees. This is equivalent to adding a `:signatures: none` option to every `.. autosummary::` directive. """ def run(self): self.options['signatures'] = 'none' return super().run() # -- Automatic inheritance ---------------------------------------------------- from autoinherit import trace_inherit class InheritedAutosummary(NoSignatureAutosummary): """Auto-summarize inherited members of a class. This class automatically traces up to the base class from which each member is inherited, and create a link to the stub page of the base class' member. """ def get_items(self, names): items = super().get_items(names) new_items = [] for name, sig, summary, real_name in items: origin = trace_inherit(name, real_name) new_items.append((name, sig, summary, origin or real_name)) return new_items # Let autosummary skip members that have a "skipdoc" attribute that is True. # Skip __annotate_func__ because sphinx has an issue with Python 3.14 that they haven't # released a fix for yet. def skip_member(app, what, name, obj, skip, options): if name == '__annotate_func__': return True return getattr(obj, "_skipdoc", None) def setup(app): app.add_directive('autosummary', NoSignatureAutosummary, override=True) app.add_directive('autoinherit', InheritedAutosummary) app.connect("autodoc-skip-member", skip_member) scikit-bio-scikit-bio-a3beaa6/doc/source/config.rst000066400000000000000000000001301520735541300224110ustar00rootroot00000000000000.. meta:: :description: User configuration utilities. .. automodule:: skbio._config scikit-bio-scikit-bio-a3beaa6/doc/source/diversity.rst000066400000000000000000000002221520735541300231700ustar00rootroot00000000000000.. meta:: :description: Analyzing biodiversity of communities -- groups of organisms living in the same area. .. automodule:: skbio.diversity scikit-bio-scikit-bio-a3beaa6/doc/source/embedding.rst000066400000000000000000000002141520735541300230650ustar00rootroot00000000000000.. meta:: :description: Storing and working with embeddings of biological objects for machine learning. .. automodule:: skbio.embedding scikit-bio-scikit-bio-a3beaa6/doc/source/index.rst000066400000000000000000000025261520735541300222660ustar00rootroot00000000000000:html_theme.sidebar_secondary.remove: .. page style and classes .. raw:: html .. meta:: :description: A community-driven Python library for bioinformatics, providing versatile data structures, algorithms and educational resources. .. hidden page title .. title:: Home .. toctree hidden from document but provides header links .. toctree:: :hidden: :maxdepth: 1 Install Learn Documentation Contribute Community Releases About scikit-bio |version| documentation ================================== scikit-bio (canonically pronounced *sigh-kit-buy-oh*) is a library for working with biological data in Python 3. scikit-bio is open source, BSD-licensed software that is currently under active development. Please browse individual modules to see the API reference and tutorials for their usage. .. toctree:: :maxdepth: 1 io sequence alignment tree diversity stats embedding table metadata workflow util config scikit-bio-scikit-bio-a3beaa6/doc/source/io.rst000066400000000000000000000001461520735541300215620ustar00rootroot00000000000000.. meta:: :description: Input/output (I/O) functionality for scikit-bio. .. automodule:: skbio.io scikit-bio-scikit-bio-a3beaa6/doc/source/metadata.rst000066400000000000000000000001761520735541300227360ustar00rootroot00000000000000.. meta:: :description: Storing and working with metadata -- information about other data. .. automodule:: skbio.metadata scikit-bio-scikit-bio-a3beaa6/doc/source/sequence.rst000066400000000000000000000002411520735541300227570ustar00rootroot00000000000000.. meta:: :description: Storing and working with sequences: nucleotides, amino acids, custom alphabets and unrestricted ones. .. automodule:: skbio.sequence scikit-bio-scikit-bio-a3beaa6/doc/source/stats.rst000066400000000000000000000001741520735541300223120ustar00rootroot00000000000000.. meta:: :description: Statistical methods for analyzing high-dimensional biological data. .. automodule:: skbio.stats scikit-bio-scikit-bio-a3beaa6/doc/source/table.rst000066400000000000000000000001541520735541300222410ustar00rootroot00000000000000.. meta:: :description: Working with biological data tables in BIOM format. .. automodule:: skbio.table scikit-bio-scikit-bio-a3beaa6/doc/source/tree.rst000066400000000000000000000002171520735541300221110ustar00rootroot00000000000000.. meta:: :description: Storing and working with tree structures, including phylogenetic trees and hierarchies. .. automodule:: skbio.tree scikit-bio-scikit-bio-a3beaa6/doc/source/util.rst000066400000000000000000000002111520735541300221210ustar00rootroot00000000000000.. meta:: :description: General exception/warning definitions, utilities, and unit-testing functionality. .. automodule:: skbio.util scikit-bio-scikit-bio-a3beaa6/doc/source/workflow.rst000066400000000000000000000001471520735541300230260ustar00rootroot00000000000000.. meta:: :description: Constructing arbitrarily complex workflows. .. automodule:: skbio.workflow scikit-bio-scikit-bio-a3beaa6/doc/suburl.py000066400000000000000000000031121520735541300210030ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # Script to substitute domain names with relative paths in hyperlinks in the # built html files, such as to avoid unnecessary domain resolutions when the # visitor navigates the website. It may be executed only when "doc" and "web" # are hosted at the same web server. import os import re import glob from functools import partial # -- Configuration ----------------------------------------------------------- rootdir = "build/html" source = "https://scikit.bio" target = "../.." # -- Workflow ---------------------------------------------------------------- pattern = re.compile(f'href="{re.escape(source)}/([^"]+)"') def substitute(match, prefix): return f'href="{prefix}{target}/{match.group(1)}"' cwd = os.getcwd() os.chdir(os.path.join(os.path.dirname(__file__), rootdir)) for file in glob.glob("**/*.html", recursive=True): depth = len(os.path.normpath(file).split(os.sep)) prefix = "../" * (depth - 1) with open(file, "r") as fh: content = fh.read() content = content.replace( f'href="{source}"', f'href="{prefix}{target}/index.html"' ) repl = partial(substitute, prefix=prefix) content = pattern.sub(repl, content) with open(file, "w") as fh: fh.write(content) os.chdir(cwd) scikit-bio-scikit-bio-a3beaa6/licenses/000077500000000000000000000000001520735541300201605ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/licenses/bx_python.txt000066400000000000000000000021571520735541300227400ustar00rootroot00000000000000Copyright (c) 2005-2015 The Pennsylvania State University Copyright (c) 2013-2015 The Johns Hopkins University Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. scikit-bio-scikit-bio-a3beaa6/licenses/fastq-example-files-readme.txt000066400000000000000000000115271520735541300260310ustar00rootroot00000000000000This README file describes the FASTQ example files provided as supplementary information to the open-access publication: P.J.A. Cock, C.J. Fields, N. Goto, M.L. Heuer and P.M. Rice (2009). The Sanger FASTQ file format for sequences with quality scores, and the Solexa/Illumina FASTQ variants. These files are provided freely and we encourage anyone writing a FASTQ parser to use them as part of your test suite. Permission is granted to freely distribute and modify the files. We request (but do not insist) that this README file is included, or at least a reference to the above paper. Please cite the above paper if appropriate. We also request (but do not insist) that the example files are not modified, in order that they may serve as a common reference. Invalid FASTQ files =================== The archive contains the following sample FASTQ files with names of the form error_NAME.fastq, which all contain errors and should be rejected (if parsed as any of the three FASTQ variants): error_diff_ids.fastq error_double_qual.fastq error_double_seq.fastq error_long_qual.fastq error_no_qual.fastq error_qual_del.fastq error_qual_escape.fastq error_qual_null.fastq error_qual_space.fastq error_qual_tab.fastq error_qual_unit_sep.fastq error_qual_vtab.fastq error_short_qual.fastq error_spaces.fastq error_tabs.fastq error_trunc_at_seq.fastq error_trunc_at_plus.fastq error_trunc_at_qual.fastq error_trunc_in_title.fastq error_trunc_in_seq.fastq error_trunc_in_plus.fastq error_trunc_in_qual.fastq Of these, those with names error_qual_XXX.fastq would be valid except for the inclusion of spaces or non-printing ASCII characters outside the range allowed in the quality string. The files named error_trunc_XXX.fastq would be valid but for being truncated (e.g. simulating a partial copy over the network). The special cases of FASTQ files which would be valid as one variant, but not another, are covered below. Valid FASTQ =========== The archive contains the following valid sample FASTQ input files for testing: longreads_original_sanger.fastq wrapping_original_sanger.fastq illumina_full_range_original_illumina.fastq sanger_full_range_original_sanger.fastq solexa_full_range_original_solexa.fastq misc_dna_original_sanger.fastq misc_rna_original_sanger.fastq These all have the form NAME_original_FORMAT.fastq, where NAME is a prefix for that example, and FORMAT is one of sanger, solexa or illumina indicating which FASTQ variant that example is using. There are three matching files called NAME_as_FORMAT.fastq showing how the original file should be converted into each of the three FASTQ variants. These converted files are standardised not to use line wrapping (so each record has exactly four lines), and omit the optional repetition of the read titles on the plus line. The file longreads_original_sanger.fastq is based on real Roche 454 reads from the Sanger Institute for the the potato cyst nematodes Globodera pallida. Ten of the reads have been presented as FASTQ records, wrapping the sequence and the quality lines at 80 characters. This means some of the quality lines start with "@" or "+" characters, which may cause problems with naive parsers. Also note that the sequence is mixed case (with upper case denoting the trimmed region), and furthermore the free format title lines are over 100 characters and encode assorted read information (and are repeated on the "+" lines). The wrapping_original_sanger.fastq is based on three real reads from the NCBI Short Read Archive, but has been carefully edited to use line wrapping for the quality lines (but not the sequence lines) such that the due to the occurrence of "@" and "+" on alternating lines, the file may be misinterpreted by a simplistic parser. While this is therefore a very artificial example, it remains a valid FASTQ file, and is useful for testing purposes. The sanger_full_range_original_sanger.fastq file uses PHRED scores from 0 to 93 inclusive, covering ASCII characters from 33 (!) to 126 (~). This means it cannot be treated as a Solexa or Illumina 1.3+ FASTQ file, and attempting to parse it as such should raise an error. The solexa_full_range_original_solexa.fastq file uses Solexa scores from -5 to 62 inclusive, covering ASCII characters from 59 (;) to 126 (~). This means it cannot be treated as a Illumina 1.3+ FASTQ file, and attempting to parse it as such should raise an error. On the basis of the quality characters, the file would also qualify as a valid Sanger FASTQ file. The illumina_full_range_original_illumina.fastq file uses PHRED scores from 0 to 62 inclusive, covering ASCII characters from 64 (@) to 126 (~). On the basis of the quality characters, the file would also qualify as a valid Sanger or Solexa FASTQ file. The misc_dna_original_sanger.fastq and misc_rna_original_sanger.fastq files are artificial reads using the full range of IUPAC DNA or RNA letters, including ambiguous character codes, and both cases. scikit-bio-scikit-bio-a3beaa6/licenses/flask.txt000066400000000000000000000030561520735541300220250ustar00rootroot00000000000000Copyright (c) 2015 by Armin Ronacher and contributors. See AUTHORS for more details. Some rights reserved. Redistribution and use in source and binary forms of the software as well as documentation, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. scikit-bio-scikit-bio-a3beaa6/licenses/hdmedians.txt000066400000000000000000000261401520735541300226600ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. scikit-bio-scikit-bio-a3beaa6/licenses/ipython.txt000066400000000000000000000065271520735541300224250ustar00rootroot00000000000000============================= The IPython licensing terms ============================= IPython is licensed under the terms of the Modified BSD License (also known as New or Revised or 3-Clause BSD), as follows: - Copyright (c) 2008-2014, IPython Development Team - Copyright (c) 2001-2007, Fernando Perez - Copyright (c) 2001, Janko Hauser - Copyright (c) 2001, Nathaniel Gray All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the IPython Development Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. About the IPython Development Team ---------------------------------- Fernando Perez began IPython in 2001 based on code from Janko Hauser and Nathaniel Gray . Fernando is still the project lead. The IPython Development Team is the set of all contributors to the IPython project. This includes all of the IPython subprojects. A full list with details is kept in the documentation directory, in the file ``about/credits.txt``. The core team that coordinates development on GitHub can be found here: https://github.com/ipython/. Our Copyright Policy -------------------- IPython uses a shared copyright model. Each contributor maintains copyright over their contributions to IPython. But, it is important to note that these contributions are typically only changes to the repositories. Thus, the IPython source code, in its entirety is not the copyright of any single person or institution. Instead, it is the collective copyright of the entire IPython Development Team. If individual contributors want to maintain a record of what changes/contributions they have specific copyright on, they should indicate their copyright in the commit message of the change, when they commit the change to one of the IPython repositories. With this in mind, the following banner should be used in any source code file to indicate the copyright and license terms: :: # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. scikit-bio-scikit-bio-a3beaa6/licenses/nb-slideshow-template.txt000066400000000000000000000030461520735541300251330ustar00rootroot00000000000000Licensed under the terms of the Simplified BSD license: http://opensource.org/licenses/BSD-3-Clause Copyright (c) 2013, Fernando Perez. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. scikit-bio-scikit-bio-a3beaa6/licenses/pydata_sphinx_theme.txt000066400000000000000000000027421520735541300247630ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2018, pandas All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. scikit-bio-scikit-bio-a3beaa6/licenses/qiita.txt000066400000000000000000000027321520735541300220340ustar00rootroot00000000000000Copyright (c) 2013, Qiita development team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the {organization} nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. scikit-bio-scikit-bio-a3beaa6/licenses/scikit-learn.txt000066400000000000000000000032601520735541300233070ustar00rootroot00000000000000------------------------------------------------------------------------------ The file doc/source/_static/copybutton.js has the following license: New BSD License Copyright (c) 2007–2014 The scikit-learn developers. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: a. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. b. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. c. Neither the name of the Scikit-learn Developers nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. scikit-bio-scikit-bio-a3beaa6/licenses/scipy.txt000066400000000000000000000030541520735541300220520ustar00rootroot00000000000000Copyright (c) 2001, 2002 Enthought, Inc. All rights reserved. Copyright (c) 2003-2012 SciPy Developers. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: a. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. b. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. c. Neither the name of Enthought nor the names of the SciPy Developers may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. scikit-bio-scikit-bio-a3beaa6/licenses/verman.txt000066400000000000000000000027231520735541300222150ustar00rootroot00000000000000Copyright (c) 2014, Daniel McDonald All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the {organization} nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. scikit-bio-scikit-bio-a3beaa6/logos/000077500000000000000000000000001520735541300174765ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/logos/favicon.ico000066400000000000000000000013761520735541300216260ustar00rootroot00000000000000 è( @�¶ ‡·(‹¼/”¿?ŸÆR«Íf´Ó}ÃÛ“ÅÛœÊà¥Õç·áìÆìôÞóøîûÿý!!PNì!îÄ !nì0ë"îqÎç !!º0\îQîVîÓ!Þ¾ë1îîaîéîî¡íné&íîRì1žá!!!ì! ì! ë!î`ê®Á!ê>ç è–ç!æ!!æ!!!æ!!!ææÕ! !!!scikit-bio-scikit-bio-a3beaa6/logos/horizontal_powered_by.png000066400000000000000000000352331520735541300246220ustar00rootroot00000000000000‰PNG  IHDR-Чá¥ÍsBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î< IDATxœíÝy|Tåõ?ðÏyîLK6�E°Ö*.uïbõ«(¸ÐòµŠ�ÉÌDµ?lkU°*;ãn€ÚZ¥Ö/™d2 j­uC¨u©ØZ¿Õ¯Kmë ²ˆ!Iæ>ç÷G¶™É$s'¹“¹IÎûõâ¹yîsÏ$arÏ=ÏBÌ !„B!„p*•ë„B!„¢#’´!„B!M’!„B!„£IÒ"„B!„p4IZ„B!„Ž&I‹B!„ÂÑ$iB!„B8š+×!„¢ÕÌ•¡â~Úu´VTkpÃ^ÊË«ºõê9»r—BäÉæ’B!Dn]µj•»dßÎïz*@“ô‹û´IŒ[—^?a®âBˆ\“¤E!„È¡y÷Üz¬iòï>¬ƒf&Õ¹†.�=»ª»âB'‘9-B!DŽ„B!—©õ³i0¸_Ã!Ý“B8‘$-B!DŽÔ©ï€1ÒJ[&Še;!„p*IZ„Bˆ1M`µ­b³!›±!„“IÒ"„Bä.Ë«x6h—$-Bˆ>K’!„"GXk·Õ¶ù 2K’!„"W2¨´íÙ#•!DŸ%I‹‘®ºê*ËO …è©8ƒ9-7ƒf6cB'“¤EáHÛ·ï‘ë„Ⱥ *-7‡Bý²ŠB8™$-BG"2Îu Bd3³Õ¶»‹�ŸÍX„ÂÉ$iB8‘’¤EôzÄTgµí¸ûg3!„p2IZ„ŽÄ #sƒÙÆŠXm[ÓRiBôY’´!œ‰Y*-¢×#Ö–+-Ê%ÃÄ}—$-BG"�$-¢×c¶^ia(&„è³$iB8”TZDïGF•ÍRiBôY’´!‰@É^-¢·Ó:“J‹)•!DŸ%I‹‘TUUU�ë8„È&be¹ÒBÊ%•!DŸ%I‹‘(0(×q‘M™¬F2K’!„ãä5MÀ×$sZD_À»,5SRiBô]’´!‡Ù,hú‡TZD¯Ç kI‹TZ„}˜$-BÇ!j™Ë"•Ñë)‚µ¤’´!ú.W®Bˆd̪ q¨?I¥EôzÌÖ“¨iLÖ…B!U[@g‘Rã Æ*ÔÀfC«oýÅœw»#!„¤Ò"„p nFRi}[œÓ3V†Š²K“9+OÜ_hüƒH½Æ/Á4 ÿfàLnÔÊüûìK~ر! I‹‘+, H¥Eô~¤¬&-Èï†e�gß}ËyÌø€c:h–àšlÇ"„Í$iB8N󜂬&úë•�RY�×2÷Þ¥C¡U�IIš`ø_ÙŒE!âIÒ"„pnY5Læ´ˆÞ�ˆ¾´ÚV³‘ÕJ‹Ó‹X‚¦™Ë³‹BÄ“¤Eá<ªe©c©´ˆ^�•剸€6³Vi™³|щþ±µÖüÄí3ü)[±!D2IZ„ÎÃ-©´ˆÞOkëI Tö*-DwÃÚ}A‘¾>kq!D ’´!¨¹Ò"sZDï§c$-¤³Ri™³|I)ÿe­5ßµtFð?ÙˆC!Ú#I‹‰š’™Ó"z¿ê¢ƒ-'-œ…JËõ+VôgâÛ-6ßbšýoµ;!„HG’!„µ$+‰ˆrŠYöÀôé j¬´%Ø_iéÇûf8ÔÒõ‰n¼ã†öÙƒB¤ãÊuB‘BsÒB�g €½¹ &�oåW�RJ�$ÍÙí}o%xLÚÂyy[víÚµÇÎþ­ÇAê †7¸Ý#•Ò#aòÀl\‡Õ)M_°al­ªªú‚™²q<¸ðtfnçûåz«ªªjw¶®�ˆvµ‹ì°�­IËì{B‡‚Œ›,5&¼¼tƼ¬¬VXXx�að±©>ghUûeuõæLú+((æV8۞貯jÏÞDzùsžMç¼°`|®cÓ ýî½µ>ÏýÅÆñÁX6¯å�†òªJbßK×.ærýeãøà�lÆgm åáŠ5Œ(?Û×KÆDu†ÉÛj öm{õÔåû³uIZ„ŽC@?núw,ë&-EEE£ Å Á˜Œ¢‚ h€A€Íµ!FS¿³ƒ‹ ÷xƒ –îÚ½ûy{¯–hĈëÔ^ à§%E_3£ùµ"KE0b€‰CIQ—î#Ó¼¬¦¦f‡­ÓxŠ@)—øeŠ�`“­×kñ.0K׌mÞ\’µq;ý-4Õ¤ùZ;¯Ï0p:1­O}aþÀ¸Lús¹p4˜zÌ’ÌÅÅÅ%º)A¶mÌu  4` †iê‰nðbZñüÄгv_kçP 6LK¯û>¶ûúgm �6LóF&œAŒP L¹@e„µƒ0qÃÂjÛ¼¢ßþâY‹>°ë’´!GyÍ·ÃDÓor×�ˆˆJŠ ~m®„Í• pCŸUR\¸dx«ªª>±û"CŠ < ú€¡v÷�"`83ÝM\\¸ä«Ý{–æ0žìÐô%ˆÓ6#‚m•–›V,ú/*µÔ˜ð›¥3üÝ®k ‘E ÀÁfâó&nXðÀåaBðÝ\ÖU7Ì¿2@?`XxËÈ…¢¦?c•¦i7,\g˜ÆÕÏžìò'™Ó"„p»›ÿmuîŽÚv·ÁEƒ~à*8ä¡ßVl.·»ß’’’bÝ�Ü&,ÉXRR2ðÄ\b;b«“ñ²£–wÕªUnÕ˜�¦G¨Š™æü®^SˆÜ ã€ØZo4ä¨`�Áä^„Æ F®c±Hø‘i˜KìêL!Fµür©󋆈 Ý’ë8’10¥¸xÐ;û$6glgŸ6!bÕû*-lyƒI÷Ì¡’®^®¸vÇ\ß´Ø¥‰ð~·Äј·[ôS±áèäk÷F£ÆáDÿ†•‡&)¾²Òã1;s­\ŠÅð®[±¿«ý00šˆµóÙZ0lyX°»zwo_Fº�kŠØ©_†íÇx£^£ÒSÙã~žÑhû¿„݉FwµIZ„NÔrC¥9¦Ò¢¯µó™]_U×TtG%%E#ˆ¹MÒBÀáv]C)st»wÐÝöZ‡|—‰R&- ÝÞ÷¢G"¢lñ†Ä`ÕéJËáŸÿóF'[jÌ|×Òë¼ÑÙkåRÓ*s]þ9RTô]·“´PÃWÕ{ºåÿBOg˜ÆñÏž´õ!ÃY›BÅJ7¨ãˆé2€OIsJÞîⱇøÐÎ8º[yÏ{ƒ µY% 1øVÇ­,Åß!IZ„Ž …âJàZ›JZpˆƒt4tèЂ�;wZÚ¤°#¤�‘ mGLYC¤Éu vb†åJ‹&=¼3ט{×ÒqP´Øüƒþ5Új[!ºÝÆñÁÝ^ðÒyÏÍÂ4Ô§éÏ¢‘è�I �hŒJ×Î0�KíN­8ï¹Ð8Ó0ßKÓl�ˆÁ�þ-*I‹èSÖF"ß«•ñÇò œáñxêíè¿¢"úh:CÌu¿÷L;úî+^ýuw~ÿÂøCކ£o”c±Ø`XÜY½#šôH‡.¥ÙJ³£¿™"Ší`‹ÃÕ È8i …BJ¿`eã9 ¦+‚ÁìoŠ'„ž=wñg7,Ü Ã*$ggs©,›°aî08éwaçäMØ0w&`{g;�¤Eô)J«b&þNü±}ûjm[�BC qýêì껯4h�;7âØQÃìmÂ×]öxÀf&¼îr™¯ïܹg«s¾í;dÚŒ‰œô½è2ÝÐ;¹­=;ad><¬¶Àu-�Óîà ¾gÙÌù¯fz !r,k;±çšiäõ7Ì:'Žiäué}[’!„Ó$?MêéO—l¥5ž2 ~¡ªjï»Ììì1\²Ûnº©föŠÅûa!1&d6<ì¦;¡\°¶Oáßýh«+‹‰nTRRx1޶£/b»vï¹Ó޾„è.’´!¥®Îå6\­÷âZ;ªÒ’sÕÕÕÿÊu ";ØÁÀ×Óµc�åJ 4Ë… °Ðœ5ó•ÁéÁnŸÈ+Ò#¦À¥vôÅ@€>—´h%zz2IZ„ŽBÄN®´Èp¿ÜÑ>ã]ÞÕÐÏå: »1°’Y®´Ì^¹xã­´%ЯoŸ9ÿOVûÂa¥k •û?݈ÈIZ„Žâr)·æÖ±»DNª´ð§ÏõèUÈø˜ß`{wРÚ÷?ûŒ{í˜u ¥Òb[ª´ÌY¹ÄÏ–7‘¤�óûÅfYk+„³œ½qÁX’¦Ù®�ミwK@"+$iB8JƒjpfëÚLÚAI }–ëú’]»w?ŸëºSS¥ÅŠA¡U¡ ãšµbÉ· ü�Õkñÿ þ,¸×j{!ríügç\Ÿ§N$ƉŠijºöÄøŸîˆKdOV“–‡£ÑQ®Œb6¶æå™_x²°«îªU«ÜEEE‡Æ€ÁyJýÛãñ|e÷5œ*�54`´aèÝJ©�³ñõ—Ê=úèc\.]WXXøÉ¤I“2"³víÚBv¹F+ÓUãvëÿd#ÖM›6¹¶nýj`'ŠýÇï÷i÷5ì …Ô¸qãFÇ”r�:ôŸãÇ��å:&§0bJ%3¬­Û˜>Cêµ€�\\¸)˯#¦­L´¬·Â Ïªªjžcf²ÖKa‡Õ Ôb€�S}nþŠ%£ü8¬-o ¯\:cÁ Ö®,DæLÃ|oↅövê2 ¬ÏPùpßÀ½6 º[ÆIK8¼îë¬ÌHóÇýÏ€¯ôRˆD"GhÐtfœà0 ÄÐ` WDßx�‚^ãóù:µ4çCO>YÐÝO˜qÀ‡*,>Ôd Ád„+*wø'À€ðû@iéºöúZ½zu~^¿Ï2Q¿–×Cú¾@iéÖ¾‘êØ–s™kÝ.:ÇÊ ùÚÊÊÓ é®Öëò®@©w2ÐþÖuk#‘sS)G¢ñÏ0(Àd‚ir]¸"ú/üšÛ _y<KC)‘ûꤖX´QLù¤¼¼ü8�qó˜±G�¸ÄdBUu ‡+*_"ƃ55»#Ó§OoHÙgeå`L…Æ‘L8’ ÷bÊDƒ‰úµ•ÿ&Â`¼q`@þ½W\pA§ö–X�j˜|€KŒ†‚†�pEå§ ¼I ×] ¿ôx<9}ЉDŽŒ�®Ó cÆõM“1€LÆÖm;êÃÑ÷Áü6½²·ºêÁö¾®®¨œÉ –ɘÖfƒû©S/Ú‘iLáŠÈ½ Õ²‹­"<î/õ,ËüÕÙG)¥tÜ\Ib²mIê.3ø“vö\,�åýx�; 0@h ¤¨`ËࢢeU{öüF’—ž�ÙúþDj8R$-ׯXÑ?�ø 0¶tMà™�F�»Áz”Bô8/˜†qù«§.ïÕÃKû‚Œ“"î�¸}(”áHd ˜PÔΩÀÇX¦¡–¬-�,uðð¹VŸ0G£ÑÁõ1}]>Ñ5 ”tÐt€S:ŒiáŠÊW˜ø†²ÒÒ¿$7œ6mÚ�òŠÊ]_Ô|ŒY™Ò&-kÖ¬f¸ér·ÞP‹áti'2’‰+¿_ó/ÑN‰DŽÐLË tAáú5}}�0¥Áäk‘Ȭ@iiEºX::~o"î‰DŽd2žGÛ�šÀ™L ’ô9„Ãë¾eÞÀÓÜ:Å €<Žã(ö«=pMy$2×_Zº$mñV¯^�Ÿ—?`…LÐÞMí¡`Êà Lüxm$r‰j·iVQ8½LK èŸâ%æ|Ç�¹¬ °øgååÑé~¿çµT�±AÏ’Éw!îKk¸~ ”IPáðcc ègñ?Ã&øg™ô‘ ZkŠÿ¡Ñ䜤¥ªªæÙ’¢‚O`a²t7â{KŠ Êœšë`D×ѶXjѺí^-Ð,ì[ ÆÉ/ùÕ»}•YªÒ {îØõ\gÜlG_��=zµ:ªØ0á–‡»² »pŽ.c�+\Q¹ ™q‡5ï3áM dà›Ž@ëM–AD7nݶãÔh4êñx<Û:ºÆ#ãÔãD”*!Š�ñO¶8 hóté4bz-\�º \‘ü´Ý­VqI �O]»vÝ!eeS:œ¬¥Ü S�êfYñ…H“´D£Ñþ \œpZбÇÑhÔˆ™¼ˆA¿@Û”Àgþ À8$.iy(˜ÊÕ?×M»ÄãÉ`™Tý5“éAt¼³ì=ñÕ€P(¤F9.HŠnBÛ! ` ‚0ÀÑ6’€ÌôP8Ryµ ž6µ´ô�Ž¢ ‡×Þ/À:ŽOñé:ÞgÀDc×\E;‚˜þÌŠŸ³–ÙÆ—Wnጤã_ô. h4âŽñ+k#•«ò]ëñxvœ+óxÞ G*Ÿã¿ãÿ4�.MnÛ6ÌÄ ?Ã/^RZúf&/.ÚTZ´vLÒÂÌõ%%…!bXž+ÐM¾;¤¸àâ]»kËu ¢+8ƒJKÛ½ZnZ¹x!¯Å.v™“—Κ_mõš"·vîÜ·€-ÈörõLt1—o˜pË_%aé=l¸àc´$,LxÀmÐà€ß{L™Ï;ÕïóN ø¼cLƒccÒɧ7Ä8 …Ú�cm$2YA=ƒ6Ú  ¿[RT0(à÷ðy'|Þ‘ÄæPfL�4T†= 1¾?¹ÿÚ=U°3¾c¨†¥{ÕJÙ†¦;·ÞÄ [ûÂÿú|¾¿'·kÐ|?s—°0° DW¹ ðy¿ÞôºOþðƒ÷ ´Ac^“ÔÍiÊÔ/<òÈ:KC€‰ËÚôá~ž"`=€]öÖÈ{ þœ#Çu-Db² D3̆º‚€Ïûµ€ß{vÀçývÀç-PÐßp?âËŒ“ÓóáðºÃÛ‹mõêÕù0b�§HX^�¦SFŽ6ÈïóžðyO9bØ 6é8~ßÔÆÆ÷­~lâŠKXbÌ|‹ÙàðyG|ž‰_é‘ä�ø24~m›1®ŠiܘªSÒt{Ò¡áõ1ö[ *�¦Æÿ'­}2Ýaõül2ÍXÂû9¨Ò»w×< àñ\Ç‘ŒAKˆÈ9óDÆ”R–‡x2'VZf­\ü#b-žÞES–ÎÊò¯¢7Ê#æ™6Oذàó7.üNÚ3D�`ßÍ£F�&—•zâñxÚ<¹™êñ|ð{' y áŒÑG•r™Åòòòƒˆi5ZŸ–À•|ž‰>ŸïõäIá~¿ÿË2¿÷wбqmnà ek+*¯ˆ?4}úô0‡Û)OG/µ¼¼ü €Ç·óéÃÂáè �pÂ*Œ¶OmËË#×€ñã¤v•º¡nt Ô³*y¾J0Ô—x<ÿ øJ/%¦IHX…†¾®\±ÊŽcJдl ‡ëÔ.óy'|Þ››С zì´iînnŽD.eÆŒ„O» :"Pê¹{êÔ©û’¿>Ÿïã€ÏûSb: �£¦Ó0Ê\ß^"›—?à60¾™ÐcÖ‡¼wF àù[üpÃñãÇÇÊʵÌ_Lž{rÅÔJK&6�#a2,3ÏO•Äùýž—$ #•ô=è@ƒÉ?A\eŽ€wü~Ï3VÏÏ&Ã0’G:êFœ™Í¯vï¹HC} „§8e…±EEEN¶&:�‰¬WZÐZi™s÷¢oãw°¸7?]vݼ—:¢=ÍJãÏ7,¸:×�ˆ®³oõ0E |¥ž?¤iÅŸ7®¨œàôæƒDX�Fïk“ì�q+Zn ›:n(óy“Œ�@U4½¼ÁäqZ&poyyùë~¿ÿÿZCçßiÐu­mÒ S"þFŠñRüð&}€·R��F‡p^Ü¡úX½{mR›"&JxbÆ ×ì»lÚ´iio¼ý~Ï3k#‘ˉéé¸Ã§?R½àŸçÉtç7ùKý�ýW¦¸Ç/¢°fÍš�†»_ÂÄmÞÙß?ß°0¹Þï÷ü)\Yy 46¡å.7fܸK�4·¨q¾ ®IºÖ“¿7¹êÐFÀçY®¨<Àütm³€‰éRŸß÷׎ùýþíkÖ¬/3ò>£¸ép>«Ø¯LJnOŒÛ™°¾õ*8¡¼h5(�Çc®]½’ þ€æ½he\à'Íí|>ßßÑʷãžà7[™ò�òÄ�jÚ§HÿBC½Ñ|€H]¤.ÓÇbÚ¢–¯;O^zéE»’Ú”�7Ir‘.+³�°4++-ýc¸"úÀ“›�à+XKZfYI�”»_)’æ™Ä—e²XÀë})\}àÖ —¦+‘”´0ÅJ“æõ×±vÅÏ¥êÐÞA–Ú[; À!Vϱá·~Ÿçe+M§N½hG8]ð½­§ãüòòòãü~ÿ?âÛúýÞ'‘÷×|ŒÏ@š9U &ˆûž°eoÍî´º‹RJÅ@&í¬áaɘYØÖôçoÝqÍ’â›)UÒ¢Õ׺ãú";‚Á ž½bñ—,ìxOÃgß}ËyPj¬&,à?ô¯Ö)‡œ ‘M†éÚðì¹Á÷³Õÿ„Cw›Aë½^2E¬Vy£Þ“+=•²ðDeËÍ€…2Ùw£i¢õ+ñǘ•/þã~ýœ`PÂuHß‹«K5++ó¼ FâäT¦6÷´:ñ@ê!bÑht0ÀgÇ5|Úçóý•ž ðqíÍË`¢K>Ö)6;¢¤ø”––þ;UaÖ»ÁqVÏuu8¾1'ôÉÀ¶ÎLæ&ÖÏ%HD(Ml‚§�)–Ÿ*OŸ<¹ÀòLcë2Óµ8“æ#‡½@„zV*Õ�CÔ�IG.X�~£Ã _Ÿø1ÝÝÑËÝMk�0Ä…È9ñ�¸W%-CJŠ .)|ypIÁ½CJ ¯()x"%/JÒÛXš×ÂààՓ°˜°0ãnè烽}Õ(Ñm8;ø&çßväø¯3¶;âÙaK¥EiÃÒ n‡àÖ} I7¿„o'ŸÂ ýÞíT€„·øZ?äo†B!•ðæ­ckAÆmhúš´7D,¦õ�¸J óú¦øŸèÊ–ã†y!’n�#‘ȑſ®­n7=›®Gñ¹ч�TTŒÏìEŠÚl»ôõ‡ž|²ÀBä Ë›t’:6>�T ÷;«ÁIùhIü×? ©1c�JœËdœÈÓ{œzsÀlÙLù$“Æ� —W~B뛫N¹RÜÖ4˜X„Öʉri¾q‹cÄ+/�ž“”îѱúRµÍ•äJ ;l"¾“1w¸â_Ï£uˆNè4@0PRTÐ0¸¸ð]fz¨ªºúž\‡˜Û�¶m’ÐñÉD;•2ÿ{éM7uj?,!zb|À”°ªf ±£tî^Räœ7õn·™ÑM€‘°/ÃÿøÇ?ö‹ÿ‰ vwfó< nó:`ܸq Ù¶ßïßÎ@|‘r1N\5¬^ë†?SâjBÌ­Ë(73™¦&µy8E…Š|lâ!ž¬ 6fúÀÝÉ}÷ßW—ÔwJ$¡‰±2x|çbå¶Ãþ\ -¿¸ÇŽ;Ie_bþÈzœ�”ÒÝ;ÞŸðAgNcJüÿR)“–¦%޾Ï̸â¡'Ÿ,HÙ¯â_$ZUVV¶§31f sb¥æ$*~ߨÞË àx"|/×�dÉ—6÷·ÝTjâÒÁ�mîW‡¡äERµ92ûqˆléò/8þ�ÉаfÄø4ùPuuuË8ûæI†q2~ªÞÊü0ùH«1mb"þ]â�Ä!b«W?^ ÆÄÖÏã…æ¾Á……σÿë{kÖ¬�  ,¾?—j;4,‰ޏ=Lì§�I߯Z2Ð¸Šš•±×�CL™þ¯k IDAT-±jm´™‡ÂLgÚ§Rêctã¦ZÌ�û¹¥6ß>¬½¶nƒîŸxæï¯»"¹]yyù1à„E Øt%'¶9—¼Ä1‘³V"¢ƒ Ç•”]ZTT4:×ñˆÞƒ™ö¦oeÙ§ÚÀÝqÝܤo*DïGÜ뇗öj]Fm7´„ KÞïÇ0Œ¸'LzkœëÖÕ”2¿–a K¾M5m†?•>YU]S h;D,¯Ýˆÿ�gZ×üÏI“&Õ­­¨|Š€æÅ”ËU€ ¼ÖÈýœ–Áƒ‘n˜È oøvIQÁÉ($f¸@“d°y«í#b O‹­àºXM\|í¼ÏÒ·¢çc‡®4)ìcÇœ–C£Ñh^&;qƒ�HZP~WünõÄx'éõ°Î\§ñb4.yþ>³ÑfWÙI“&Õ…+"ý´9ŒÄUƆ™Ä±'âÏWŒÇ˜Z’°¢‹Ð”´hŗħ©öf÷³ WTV#n3M"Zï/õ,KÕ>—o–#ŸÔº7ãé€Ï³ÐîkUøÉ ½µ Ç!ã'ÜŸïÜy˜²s©ïôFtê,¢±I?³Ù‹´Òeòµh݈ôˆÑãÆ}ÀS@cUŒÉH¨ôkÇ,sÏК8.csÂæ’̱ñ=šë8,°kÂVOØAº'Ę1"ìµaÿîÿ5M}î²tjHµ=÷Ú}ª”nànzÖšU�¯£ çÛƒQ—Ù„@G$Jx’ÌF›Õ«ŒXLµ»Sz‡˜Ç%ª¯ßÓ&i…Ä!bDT 4îGÆ9-ÇAöûý c�k ü@ë�5cÂCO>Y�Fóˆá�kº/Ï Ž6{|;þÍ|z{ sO%Ä¿¸‚�šVþJø̬3NZTwëxVœ¾UÊ3“â¤ÿKݮѥÏ0öû!V-›“2įaOx6y e§`N|\‘üqnpU®#°BöÄÉh³A°õˆïI¦´F+-´¡ŽÌñwÜ”„Eôç=wã@ ;÷NЯÎÝ+Þïºú:ìY=ÌÄ©€õ ÇÑh´Üfu°„e‰ÝDï4´y�;@Fë|oÚ´ÉÅÀ9Iw=o¶·‰Ïç{=\^ùAÜÊMß ‡×}]¹óO¸u(ëuÉçNŸ<¹6\}à)M‡úõ«­û~=POMC΀€Gã«Jɘðâ„Í7O[µj•;Óei×F£G«˜žÐV­x‹Á¼Å0Œ­�™ƒÔ>þ€–½`@øÎš5kN�:5£_¼‘Häj23¶0·j�·eäÈÁ[âw¸ø÷ñ+´8-Óêt ÛðÓòõ€ápôä@ÀcyÿŽŠŠŠï*a&ÝaÒì¢;ÉäihݤóåååÃý~ÿv—%´e}‡Õxº›6 ?&~t—ÖîõíœûSâŽLQ€;a W•zhX3¥ñ~×iñ ‚¢e’W~êÁÄCLô &h¦£±Âµ3ƒ~:ÄįQâƒð~.w¿{\ÙÎ))™L¿ø ¡«ûlçÎ#�¸´ZÅqýÒá1�,±r�‡£ÑQ.Í7¤ÿe3¥àr+M£Ñ¨¡¡îK:¼#O©ÿMwn™Çón8Rù¸eÉG”ëÒ5‘È ÐI­-éïe>߆”�8€2MF܈0&Îùísuuõç%E�«î:+[näµV[”Ó³¦Þ™´t~NË.ŠÇ|ñáQÈhH!²Ï4ÌÍ7,´õMe àÎ,ɧ7Ò·q¬Ï¤YL‰níÞ]Z®k¥Q—ß³íÛH}L/pSº†ápôÛP-sFšp¹ÇãÝ–Ü–‰æ8w¨Fìþh4úC+Õ‚G¢ÑÑ Hž_±Ç­ÐñîßÚµFl1š†Ï18 ~Ó¶¿¶›8™õOÁp×£inßçÖyðï€×ûRG—?øàa[·mŸ¿Ó9ˆf†Ã•ïÓÆÞ$\QyßI8H¸ËãñØ–°@Yié•oøVó1®(/¯|Áï÷–[飼9—¥Yr¥@Ο3s}IqáŽ6K±`âß ..´iò´5”ò¸Ö¶ÜÈ—TWo­.j÷¿Êñƒ‹ ³¶³uj³Šd Vö¼V§!ð¾NæÆCÀ¸Ê4õU³W,ÙÈÄ÷|4jìï¥ê""¿{Ûˆfíæ\Ñ’Gëò{¶m³zˆèÆòŠÊÕ�;Ƨn®¨¼Š7 K˜þ›ÍØÏS�Pæó< ÐS �?h0ys8=¹½XB¡�Z[Qyµ2ùoHÜ-ØÔ ©é*BM Ië“hÆ †´Ä@ÔfhXë¹e{x>îÐ Ä%-DÔf™ãdãÇ��AÑÏÄ#(U m¦®žhW�°ò[>”ùz¸":­½ë<òȺƒË+*Ÿ` Í¾;ÝÄM„ÕáŠÊEhçnä¡'Ÿ,WD`æÄï㥚šêû­^Èï÷¼ àµÖ#4ÀÕqM>5bhGó©rN™‰KÒ1ç¾ÒDhï Ý!ÆvóŸTË@ï*¨©ù¸k¯²ÑGÌÐþPÜü,½¦TÚyÿàZÓl3ï±Wж,yÌgcýáŸðöœ•‹'¦o/D_@›Ÿ=÷Žn}Àd'&þK®cè ;â·u%.k0ùüòHe¹Öx ŠßUšF1áxMjó䨣 =¾6·Û;¨é ½µÏ!îé:€“ øõpEäQfzÓ ú?ÀÜ®‰ÆÓ1cÆu’žV1_{‰ßû¤¥Cü;pâÓÿf mç³$|žø1fúAŠOi3Ò>m€€×»±¼¼ò2&<‚Öä2Ÿ�9ùµ®(�T–3è=Íæ{Dt€€¯�éä�…ÅWpÛ«>cƒÎ·:|/Se¥¥oTTD=¼­@º™1Êui¸"©w5›ï¹€½Ìê&àJ¢„ 쀦ïûþ”¬S> ‡+§Ba=Z“Á€ÿ'\^y9)zŽoi��dècXãxå¦Ë¸uÉì@·îþUc| óÃÑ þ31þB¤ß×DcÁtB>àèЄ3 oCÇ.Ìt.1ngBüðÅþÍÿ`æ‰ó„œG+C«¸yGĹŸÓ s!Áø:DŒK›’ {úßÌ  »ú³‘Z¾gOõ®\Ç‘ ½ÏÆç‰G1ãùÙ+=C_¿ìÚ`òþhBô[LC•¥oæ\Z¹î2Ló'è쪤¹µM+W—œÛõθ­»øgÆ "¬&¦ÍM7O78!aaЫ¦A'ø|¾¿wÔñôÉ“kÝ�ÍÌ3‘ø„ݨ”·iðSê 0=ÂÀ´MXþMLçúý¥ÉsÚµwàÀõI›E6¡ÿKµ¿J<—ROh{cHx>“ù8~¿·\Ÿ³IŸÎŒ`~@A½DL›Áô€¹”ôÃLÀ;1ƒN-óxÞµzÝÎðù< 6Žáñ¤O èç`¾OAmÔPo4ÿLm–ÄßK7i=ð>­‰O�ø} œÁÌ‹5ø)(~�™Ñuq{ü¼3¨M2›]ü<_€–•Žø8W3aMóÏ,÷W‰OXê,®ß_ûí@ �ñJ~¿÷ €Û>%'ìÎs©;ñ"º•‘\YQΨ´TUíû;À–†<æÀç…»k~eg‡_Uï­¨Ã÷çùÊ娅$ºŒŒ,< ¦‹aïÏZ¾d†ý} áx»ãÜ�ãƒç:�®Ø8>¸— rGg0aÁÆñÁ.?8·'iÑ´ÎlpJ\,%ÂÛÄ|mž�3¦z<–v^÷x<õeþÒ•õòŽ@ãxü:+ç1ð€yõj�õû=ϧ=!ÎôÉ“k‰mûî°ÊÒïW`ljs&§–ì’ÒÒÿ ”zÏgè‰ÞÌàÔW@|IqQÁ)—z<[2½ngøý¿(õ^Ä §3èUëgÒ_¸rï Ç—––ZÚAþ’ÒÒ7Ý�ÌÌ·H›2á>·Aã»ëk¯¬´ô)h׉Ò�¥e¼dŸðy´·Â� ¨6óVXóýÙª¶Ù‰’67%vÎŒpÃ�ÿf^´Ýœ6GL0ÖPãí¬²33 ôkX|ÏÍ2 Â#&Ó©»víêÒ 4NÖXiÉŠþD¼böŠÅ�…î u¸‘½ÄL<Û4Œc_˜ÌêƒÛîòâÙ‹~ËDSÎä~0‡è¯_ôâÙ‹~kGo¶ ›:õ¢~´&=Ôã“4øDRt"˜\Lü)4>1H?ã+í¸²Ò‘iÓ.Ü àÆh4º¸^룈Õ€�dàÈÆ ²´ƒ‰·Aã—â§KKKßëÊk"è›Áê÷‰GÍ×R·Nd(¾Vk¬¤xÐ;KÓjO§D"‘ÃM“Fà1`Âh0Ü`|¶À¤WÊÊ›^/.Šïç“O>É|ÃÒv˜^tÅZû'âÏ�Æam¾ûH4z„ÑüÿƒÔñ€ÞC¤Þ6o³�·­&òé(˜tâ3‰:6Ý÷ØÑw¶¥˜Ã☉Ä;wxÈ�!÷èXì2Rz 1�b`$À#*D–†�PÇ ­oe`+˜?w1•ïܳ§ÃÊoWìÚUû9€Ÿ 2àV6]S:Ì#‰0Š #Á smÓøZñ€­ lQD[(¦#_ÖÔté==5®nï[FDÝ>”’HïcN5e)ek°Ü¸Ù”ý1×q7­¼ÕsûŒ¹oe_¶�¦§Üˆ�œ%©&QL!u\h÷xŸ“³¯š�¯Úðvblh»VæsÎ^œÁÃÓÌäÕC›Fú×íŠÙûÐ�ÁŒ³±Àú‰œÏDgc€ƒÑ8Òfçv·:€·ô€/šþÞøÂ„PSÁ`‘-¡L÷¬(/l“™ø‹CÓ‰�€Ç1o~BôuáŠÊ;Ð8ì¬Ù=Ÿ÷º\Å“‰‹.òž@Jµ>Ü`úùºuå¶}©n¸+t�KÖVy$ü ßáŒN\ê_³tÆÇBÀÆÙ~BgˆF£CÄ/+¾ßmÐÒ\Å“)"•¸z˜Cæ´Ñ´Ê`ùlÍûo»~þx~ŽÄÕ&­Èg¦ßÌY±xuhU(+3!„°“$-Bô2õ1}#€�Íá>�ÇÓf$§ÒZ'$)ÊAsZ„ȶå3gî¬ýÌ3©A ð²ó¥ÁЉ�ƒ¸¬v¯ñú¬»�MßZ!rG’!z‰M›6¹Ö–G–Qü°°}.E·å,¨Np¹\ 7lNÙ§EˆnTk¥‘·<œ¸}æ‚?Ã0O�ñ¼Q"K›gÝuKÊeþ… lݧEÑ}ÖVDÿBÌuLØF Ã>†ˆúÇ·aFÐãñdüô5—b*ÆÊl}žÂäŒ}Z„èFûи1q‡œÐfÙµÁOC«B§×Ö£4Ãk’ROÏY¹èê¥3¬Êð\!„È:IZ„è¡|„3×=j» 3æ–ù½]ÞÌ©»¹´KëÄÑ1ŽY=LˆnAØ ÆðôíT›Ä&8=X À7{Å’·^‚ÌFT¸˜é�ÙË�é_£gƒAy` „p &DEÉ›kÆaÆ e~o�™|¯AÅ—™%ÝíËÎ ‘Kİ6_§ØD¶É²™ó–�ÔèÌr´D7ì/T�Ê}!„“dœ´¸\ú €.�ÿãvãÓl'„hŸ&~ˆ+x†A¯üKb ]‡õÄ K3—éNXI±ÊtU$!z4 KIK5ˆè¨Á²sÿ ´ñ]f]´¯±é¦;B#2?W!ì—ñ>-B‘M?ü¡¤áâ--¯[W±.‡! Ñ­f/_ò ˆÏk·áoDüÓ¥×-xÃJs–-+á~±J;Χ†¡~°äÚ¹ïtâ\!„°� B8 3Õ'JþXˆ^�¯p ép3Êñ÷–͘ŠÕ„–Ξ]õŸCÆžƽ�çPÓÔ/ÏY¹øìNœ+„¶‘J‹ÂQ¼^oQÌT»›?VÄç?úhäÙ\Æ$Dw›{ïÒ¡fƒ>‚H׸Xí©Óý¾ºã†¬o<ÙŽ9+Mg¦_pgxj˜¯Xvý‚GºƒBt†$-BGñz½ýc¦jÙ§‚Àg?öXdc.c¢7¹iÅ¢3èQe~6Í[6sÞ­¶%„iÈð0!„£ìܹ3aâ=3ËD|!ltûÌ2M|›�˜§ÂKf­Xò€75ì�L!Ú'I‹ÂQ6nÜCÜÆ3Ì2§E»ÝqÃü�ËûÀ¿Ïô\O?üó÷Ÿ¸ñÎ;f#6!„HE’!„µTW Ã�J‹YpÛM7Õôߣ/xYægÓ ãÀ¦ywßš~L!„°�$-BÇ¡¸¤Ek&D¶ƒA½læ‚9Lt Ú®X–Î)¦Ö¯Íº{ñØlÄ&„ñ$iB8SÂ�0&D–Ý6cÞZ� à‹ Oýi¼:û®%§g#.!„h&I‹Âyâ&ßÇ\Z*-BtƒÛfÎÛì} „¿exê`(~~Îò%ž¬&„�¤EáL-Õ•|©´ÑmÏœ·¥žþÑ OÍgâÈìåK®ÏJ`Bˆ>OöiB8ÎÅûþÃÀ7œ7|ݺ‡wä8$!úhÖÊEËÁ4£§ßÝ�y}0Ô¶&„賤Ò"„pœøeŽ™k¤Ò"D7c€—ÍX0“€·¹E×í/4¢¡P(?± !ú&IZ„ÎCØ×üÏaÆí먩"{–ΜÀd>LsÊþBcÃÜ_-’�¸„}�$-B¢š¦Ô=ðÀ2_ˆZ6sA³>@u†§~O×Ç^�³2tx6âBô-’´!œ‡¸)i¡½¹ D·]¿p£©Ô lÍìL:’ÙxmÎÝ‹¾•�È„}…$-BçÑÍ•–æäE‘kw\7÷Pæ©¿›á©ÃXÓÆÙ+oýAVBô ’´!œG¡¹Â"•!dÙµÁO©Î}:ÎðÔ�`ýÄœ•‹~œ•À„½ž$-BçÑ-ÃäÒ"„Ã,�=»*�y.À�exªÁL¿™³|ñÍYKÑËIÒ"„p¢ædEK¥E ƒúïÑ^0îÍô\&g¯Xü`(re#6!Dï$I‹Â�tcÒBRi©‚Á ^výükA4 ™ïårem¡ñÄ�wÞ90± !zIZ„Ô´jËœ!œnÙŒy·3ÑT-ONÀ÷ ãÀ¦ï ËRhBˆ^D’!„5UXHV¢'¸mƼµDø>€LÿÏžb¸ŒWç¬�ÎF\BˆÞC’!„㘤›o|¤Ò"D±tÆü4©3|‘щŒ#Æksï^ô�ìD&„è $iB8‘’ÕÄè�nŸ1÷­˜¦S~?ÃSÒš^¼iùâÉY LÑãIÒ"„pž˜Y,•!zœ;1ï“zèÓ¼šá©áñ9+MÏF\BˆžM’!„ãhwc²B�9-BôDËg¿ªÇÀ‰`<žá©3=0gùâ[²˜¢Ç’¤Eá'›š_…BùÙ‰LÑHÒ"„p$jš'ä !z‡¥3ç?§I� `{fgòèú·l@)D&I‹©jPç’J‹½Ìí3æ¾iš8àZ<¥žó—\;÷�¬&„p4IZ„NUs È%•!z¡;n˜ÿQLëÓü¥£v ¼Â„n»~þ’n MáPÄ̹ŽA!Ú˜r±ïÅõë"XÞ¤„èµ®_±¢¿ûBDø1%ª~™@"Å/-½nÁfä=@!I‹™¦Lñ‡×­+ä:!D÷…Bêæ`�%IB¤"ÃÄÅ_ä:!D÷ ƒZ!D{$iB8IÒ"„B’´!Š[sƒB!œA’!„Ci©´!„€$-B‡"2$iB!àÿoª(çGÐ¥¡IEND®B`‚scikit-bio-scikit-bio-a3beaa6/logos/horizontal_powered_by.svg000066400000000000000000000340641520735541300246360ustar00rootroot00000000000000 image/svg+xmlscikit-bio-scikit-bio-a3beaa6/logos/logo.png000066400000000000000000000301551520735541300211500ustar00rootroot00000000000000‰PNG  IHDR„úùމsBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î< IDATxœíÝy|�e™ÿñïõœÓ”¶Iš´P击€¸âè¸@Ü•ŸcÑqe\ÐQ�¶Ð&iÓž94iÚI)Ž .£ã2 ø¥\EDÇmѶÐ4M÷æ<Ïõûƒ”)X '¹ÏyžsÎçýzÕí•s]—iÎ÷Ü÷sßæî4ž(íé @ƒ"@ƒ"@ƒ"@ƒ"@ƒ"@ƒÊ§=LD±XlÚÕ½0Rôr—Ž2ù I3dæRò+w»3²øÆ¾…?¤=+@ÖÓ¨5Åb1¿{zþÍæþNI/‘4õ1^²Wf…?õÔ‹/Ÿ??®Âˆ5�B5ãœK/�<¥4ôkÍ/6÷cËxéar_sÜŸïn—ÔU¡ñjϨ K.,9udûM&û7©¬0x°7†œ  Ö±e@æu¬<ÞeךtÌDkű޻ðüî?†˜  Ö±B ØGB„AIÊåü±ž7hB™¶lýª$�ª^äù‘Pµj�@¦•J>7d½‘$&Œ"È4‹Ô²^4™@p�@¦yâ“‚ÖÛ«RÈzµŒ@ Ó")h ÌOmb…`�@¶Eʇ,79ÙO E �i¡·Œn/µFd›YÐ@8}x˜@0Š@ ÓLaa¡PàP€QB™ætË(«ƒ!È6z¨ «ƒ!È6 zí+„!È4O„•B �iÆ !@Åd[Àg�@ðBÙð”Q“B �q!ï!t!ÀA„2.\ tgË(ÀÁ„²-ä–Q“‡ªP„²-èÅô>9\-€ÚG �m¯�0�à BÙæ²p¥tX¨Zõ€@ ëö¬E 8�@Ö*„@ Ó#d½4u÷÷Ó¹®÷;2û¼I¯”Ôô(_>MÒ[cO~¾d`åË«4"È0!€Ì‹B?Cèõ±BØ9°ò-%ó;å>¯Ì—É6tô¾®"ƒ€šA �}±]!”Õþ¡2]ëzN‘ìó’ZÇY"/yŸ)èf\Pc„2/N,ì ¡¼¦açúâÜu¹&þøñKÖõücˆ™@m"ȼüÔ\Ø@h6+h½**‹yʝJ:"D½ÈíÔu@m"ȼßÍzrÐ@讚 „{Zs’ôüPõ\Ép¨Z ödÞåóçÇ’v„ªgªÍ@¸ôÒ¾#$ýkÈš–èÊ�õ@m!¨¶5`±É�kÖLX¯*’RÜ+©-XA×÷ûÎ[þ³`õ@Í!¨¾%dµhRò¸�õ*mɺUÏ•ôž€%“$Ьj�@M0)h L<©©m£‘'—*äÏl·Ï®]°ôçÁꀚD PÜ-h 4Sͬv¬ë}›¤,¹#‰KËÖ5Š@ 6X4º¼&V‹-6›|mÈšîê[»¸°)dMP›„j‚)ð ¡jc…pϾh™\�Xò�{&MïXÔ0!€š�XØ@èQö¯žXraÏ“$ zð‹›–¬?ûì}!k€ÚE Pâ8h ”gËh”÷I“ƒt}Í‚nî"¨ x…Pf™Þ2Ú5ÐóJÉ^°$×L€¿A PrQ®aVßÙe“\Z´(×L€C ¨ MÛGî“äá*fw…pÆ®-çHzZÀ’\3Éܾ¿*·¹YSKKKkE­QTjvÏn@5Sœ$ù�qïlkÛ¹óž{|OÚ3¥ÁÌšZ[[›s¹\³�Œ4'yoJ{¦±ˆJ¶_Mñ°4exppp§»'iÏ„òuôÜ/if¨z»óÓËÚ+Ë.Yõ¸8I~+©5TMw-]³¨»/T½Fcfù¶¶i'¤=G­ÚõkwÏÔß7€”¯F“ßzT<2i¶™Ÿ éIÇKú»öé-£a"‘’HV�aÆË¥H‰¢œi׎Íhk�%Ý#Ó�rýJn¿,¹_7<<¼5íQC0³Éí--óÜü9fÑñr?A¦'·Oo™,¹””ä9“y¦×ä9Iq^ÒˆÚ§·øŒ¶Ö�’ý^–üJnwÊíŽmÃÃ7dýÍÊŒé­WÉô†2_ö½Á¡áS*1O ¶(` lž%éžPõBˆ“¤Oàj욉m-×IöŠ2_VÑ?ãGL›vxÉ£Û*U¿QÌliy†¤»Óž£^͹aÅwÍõò´çHQIÒ_%»Wò{Ýì/Rr¯¹Ý+Ù½q.úå�§îO{ȱš»qù—%{óĪøW6ÌYù–0UžÉlÎÆ}†Tz¦¹==‰ô s;NòIÍ’¦�þš’GÒ®ÿýe;¥ä�æÑÝnúµýú¥7ëÎB¡lq£b�ÐÌ&··¶ÎwKÞiÊÏ1óÌ®þ�SNÒ±r+éµ2WÞ42czëufþ…Áí;¯¬ÅU¨Ã§O?91oûô–ù’ÚL&É•í´^6“Ô"ù³åöìþWûô–¡m­—[¢Ïn¾%Ýq(&mqé¡êÅžd*v ôžlÒ™!krÍ€‘—tŒäÇH’¹ëß¼¸rqÏÛ°bcÙ—§í޾ò�×v§6)bîÆ/0×slùRüÉä&™KAŸ©SFþÀuIv²Û�ïE¬›^¢Mó6¬¸ÒM—oœ³òf×Ķ|V$¤Í˜ÑrBûô–Ëüó&›W©>4I¦×¹ì+íÓ[n>¼µõéi4Vf6¹}zkb~«¤÷IjK{¦´I:Ë#ý°½­õ“Gyä´´ÂC¹)ìåô:iÔ$3ùz…üø…k&à€œ›N3÷ÏìžÿjÞ†ÂkÒ¨Ñ�úÝâÑs7®¸VÒ�Ýt¾¤'¤=S 9ÒM–ôý9WÜcFkÈcã+bÖ¬YÍíÓ[o1ÓBÕÛZà8™ôÞ‘½»o›ÕÜ|dÚ³à IØ@èÊÎI£Kzß)é…KrÍÚ±nþ­¹ I{�F5ûÆå¯ÏÅñ�’^™ö,µÏ_,ŷϹaÅ™ã­4¶··?ÑÜ>£�)×¶ÉJô…¬¯–Fö~Tòç¤=GÖ¸ô”8}ÑÌe…;ûBßE˜‘“F‹—[M¾:hQ®™€Çàš»qEoÚS4š¹‹ÏŒû’¤éiÏRG¦˜ë“§]¿âÆóâ otÍãÏŠß܇kM"]nf™\y›ÙÖò&¹Þ‘öYåÒìöé-ç§=`J®š2÷ŒäVI ¹Í506KçÜPxUÚC4ŠW_{Îd)¾Rƒ°òI¤¯¼ôæ®ör_,¶µµ=WÒ)¡êÕ™Û[[3¹$înç¦=C 8ÇÌri) ¾B˜~ ìè=Y¦ YÓ]}k6…¬ õÊ<é1eóƒûz³¿©m¾‡¿qÔa{óg–û¢`�0’¿7T­ºdÉ‚´Gx¸#Z[Ÿ&ÓKÒž£5£µu^ÚC@²¸¾¶Œ‹Å¼É/SØÝ5uͤϞ;gc7‡ÌT…½?í ê�›½¯Ü×ybfyÉߢVý²yííí™:¹3ÉÙÛÓž¡V¸%l«Í€È¢°[FÝS „{¦çH:)dM®™€ñ0¶�VØì—?Mr"*ï³o\QÖ!uAa{{óÓųƒ�Å"÷¤=ÄÁÜýyiÏP;,äé�§d$Ú²ž¥ø áù÷>QîÅ E¹fÆëåiPï¢$" VI.ö—óõa.¦�£“de݇x•¤é�"—žgÒ›ÆþõñÉ’®¯àHå:±ü—X¯ä;Ã�RuË$5—ñõÇqÄ-÷ÝwߎJ „Ƕº£c{ç@Ï>…;ÉxæW\‘»|þü8P½1ËEþQIS–,ÉüÃëaTÔܼC{ww¥=‡¤ãôÀ=±e1óõîö× ÌS–‘ðÏ!=ó%?èh¹ùÖðÏùÊáDû*q+o÷Q˜@hþìò^àßÚññ ½SÔÞÞz¦¼œ@h™ù‹ÐÞÞÞfÒÑå¾._Š?²eçΚ?¬¢½­u�•-Þ·ïY’~P©™06.m1é˜@å¢cÿt×’ªúgº«¿w¾™^²¦K—¬Y¸ü—!kâ›6mÚ%)ìµ ãÐÞÞrŠyùφ$òß6´ãöJÌ„zc·JÉoÒžâÐ,'©]Ò I3õÀ{˜�ªÙä}M³$+ÆŸ›ö�ÃÊÊfa¡ë©\gþØì�b™àîOâ·¬<žÓSE L�I›.*ÊE�Saçš5ÓÕä—.ûç©“ã \@ƒqóÏmœ½²&>°?õ»ÅÃrq鵿ö>7�¦ªÏ”ôû0µpÏL{€RÖè�VÕ¤N�3eçûd·Ê‰„åˆd™:¨qùfüʬÊ'�Né“ëïB–4·…êa+7ŒÉ�§öJºòŒ+ÎøÚÖ™OßhâÀÜ̉×À¡‹ÅH/™øûà$ò׸åb¦¬š4’ŸD¾a‚e&ŸúÝâa£OS�@hRsYO6®ÌBÉ24KmH’„ïY&„})©b ìè¿àT³èa«úµ}‹º¿¶&Ô†Ëç_ŸúÝâ{sqü_­%j 1þÖ�NV³|š›‹}ðú¹õ}Ïîi×�”&~´AÓ~µJS rʨ—÷,VÃrËÐ÷)!–�ïY6xØ“F«t9}ñÒb«YôY…\Þ”öš%$ ¡ÝxJáw’†'ZÇ-aëT…Ĺn#¨2·Ò˜¿ç¡.CÎNÐÉ0÷ —OOˆ‰Õ®²±5:ÜÃ^=áîG†¬÷Hö”rë$=!dM7­ê[PøCÈšP›ìî´'À#™ñªÊJù±/dÙ2êÒ$>RyD;Lú‰K·šÛÍis€GÑ$s6ú–#rMJ{HfÉ– ÏVa…°£¿çõfúç°Uý·{rmkÃÖ€Úäæ{Ê» Õ”/å&%QÕoxjh¹8óûÖ0‡Êà€XÒ]’n5éGÊù­ƒƒ;íîIÚƒõÂÝ7›üªÂÏžqñð|”»,t]3ûÐú³ÏÞº.h,‰’t•¤¹ù­“&Mùé–-[8騠|>¿9ŽÃ}Æbî „ù(ú¸Â¯B~¹oA÷DO  NĶmÃWé�@ JöïÙ’Ëå‚Õó níX×û6“ýcТ¦m9E‹‚ÖjÄ̶–7¹¬;í9æ¦Û¶ #í9`¼„jJó.Ý¿§U±¤P©ððb± … [»»z�2ùGBÖ”$¹¸wáÒ¿¯ Ô——tRÚs<ÌŒ´€‰ÈÌ©—0£Áíþ€%s;§éð€õd’•䟑Ô²®LW¬^¸üKAkÓ�m@½ ÍÄ¡)¨gÛ%Ýêæ·¤=ôrú\. ºm´c ·KÒi!kJÚMÊýKàšPÌmòDk¸ù¯CÌÔš0[F]»ƒÔÒ5(×]2ÝåfwEnwY~ÿ]÷ß¿ûÞ´Ãߨ,éÄPÅì�“F¢V׺ž¹’V†¨õ½wÕ‡º¶¯ uÁŸ>ÁÃg÷üw�Q€êBNÖD­¹If›•$wy¤_7�ø]›wî zá9*Ç\›=à͉Â\=ÑqiñhóÜ—x;¾»}jÍÂ¥W‡¬ õâßé>F¹hB[ôÝÂ|(Ô¢0�дS\вmhx~Ú3`üÜÂnµdâ'�‹Å&kÍ]!éˆ#ì�S+- \ê‚ÉlNnù¿¨ô‹‰×jS¨-£;‚Ô€1½B(%„{Zrý’þ>À0Kù» ,° fކcËÏ•ôº –Ú“DQˆ™€Z$šôWT�o–Â%ÂÑgÇ­c]ïÛÌô¡Pó<Ƚí¢å7¯ ‡`®WÌÛ°"ìéÈ�$‘çÌ£vÉgJši®g¸EOSÝ—ßxJáwajµ'H LÌî0/'Ú¥3ÚZ×…è]]K¶KÒI;Ø*k÷¸'¿Rdw&‰ýrûöíü@*Ì£Üfy¸Ã�“ \N¿lýªÌý²`Ãü¯_ížÔ–© ¸Ô½ÓÝtzÚCйI=Ÿn—ˆýxÆàÝ5øž'С2Ée~ZŸ×»šL’¦êÀ3BþÀ¿˜™äRÎ\3ÚZãî_P”ÿ¶mÛþ”Ú¨@³8ÞâQÀÂqÂâ¥ÅÖ8޾*ÙÔ`Ã<`¿¹¿cýÙgï \0Ê\¿‹’è]—ϿܷhùmÁë$ÉÍõ‘){s'}û´ÂÝi¤-È*ÝÐÐжm­ß—ô²õêDdÒyíÓ[^1sæÔWoݺûž´êÅÔAmÙÓ´ä&™kìç%wÏo/“Ùk‚N!Ée_³hÙ'C×ê�%ö ™_’ö‹<º+íP–?IöîëçoL{ +‚mÛt·O™9�ðo�àqþ+fö2w/¥= P …ÂþÎ�ž!I¡?ÈŸwqq¦Î+Ü?–/îX¹RfïÔûA.ý`hÚç„® Ô‹­ÃÃ?”ôôç@Íù‹dßtÓ×'ïÛvÃ5¯ZÏv|à Áasëð•»v´¬W¸7hõäEíÓ[VJêJ{ ŽlVÀŸ7ù(zœ¤Ç „+?h²Jöro>Šþñg�5R�ÚЀìfóxñ†¹½?r•uú!ÐP‚G8–«':Öõ¼Ñd—†ì;jŸËÞØ{îÒÐÏF@ó—È¢kæl\þs7.Ó©ß-ò> 8„`�P’·oÿ‚¹>²fiÙ;?í!€ºaÚ¸à£Â%+_j®/*ðÏMI2÷¬Y¸ìÇ¡ë@£s©]ÒÛ%»"Ç÷ÏÛ°üK¯üvqFÚsYü�ÍàðŽ÷IÖ+‰#|Æ\ïJ{ n^!L’G¾zbÙúU'D²oH:,dOI’ëÒ¾EË?¼.àá&»Ù?•òñs7®xiÚÃY<ºûÈàÐön%z¹Ë6H w{tí;ÙÌ‚Ï�FäQè-£É!awï1qœ\§ <mÒ÷¦ìˆ…® xTGKºqîÆ+ŠÅ"ïËÐð*ö—`pxøÛ†¶ÏË�ÄG›é Õ—“T¼é%¥Ï¤=�¶`§Œ>’ûvíú«¤þÑ_š9sf«J¥g&‘?Îk–%ÍfÖœ$>-Š¢šû”ƶLoë×'‘Ÿ$é7 hi³<3ÎõÐ-£KÖ÷<%2m�ì áºîæßN{ŽG�7×Rô8Éç¦'Jš§ ¿—µw�v}áóß™WÜbH U<>ÜÖ­[‡%ÝZí¾•ÒÞÞz¦y�ÐõŒJÎ4Šœ|s" VÏìáâKV=+—è;Ò#?W8C‰E¯X{îR>�)I¤;6Î^yUÚsŒÕœº�’¢˜k�¤qŸ šDþ±W_{ΉÜOˆFUs+rµ.âžF ˆÒˆ…Ý2ê„¿¥ëV¾(—$ßSeÂà®ÈüÕk,½½µ ¡lœÝsïÆÙ,7×¹,õ”‘IíÜ�†E ¬²Ä¬5í ͘Þò–¶¶¶ç™Ùä´gÁøL›‡¾³oVÇÅÌKÜ®We>¸Ùçž¼aÕ‚å·T 64¬ëç^ðI×M¤†›wžqE±)ÐH@M!V�0Ül]¤ä§íÓ[vÎhkýÅŒöÖÿ˜Ù>}a{{Ë©mmmíiχÇVø`a§¤ÝK6Y}KÒ´€5(¹ëŒ5‹VðŒ T€›®ž`‰Éƒ3ôô Ã5¦êÏ6:“³%/éD¹Ntù;L&S¢m­ÿ-é6w¿]‘Ýn–¿mpp°ÑOÉÍ Û"ù± VâÓáDòw­Y´ü¨ �$ùo5ÁçÊÝ’ã%ý"Ì<@í V[kÄ%=ÑÌN—Kò’f´µ~rphø¬´ÃÁ|³¤cÓžâQ¹>¸zÑò/¥=Ô³Èó¿sÅ«‘èø@ã5…-£À™Wdõ`örúà̯^Ôý‰´Ç€zWÊMü7'¢!Ô,— ¦=Ã#³®Õ –]”ö€1{bÚi`Ë(€– Mô™‘ (¹ì½k.û\ÚƒÊÂB RE¡™åÚÛ§oIô—N–ì²äæÁm;ΩD?�ÉÛîÙʃ;%oZsîŠo§=ÀXL8𙵶¶>9'½À”¼À#{Aûô–ç*Ñð«\rûñD{ÀÁÙ�Éû «c³%þš¾…+~–ö c5î@Ø>}úÙ2½¾}zËó%o“$—);ïÍÔ»HÉ�gcËè™Å¯ì;¯ð‡´€Õœö@­w 4ó·IzaÀY <mÏÀ§P?Žò¹×®:»û¾´€F•‹KOÎà3å@M˜ÈóI°)K6¾oIFæ¨%Æ÷,k�‡Ò�À¯ž2->uÕÙ]„AH‘¹ž’ö xdIÄ{¨j+ç{>î@è²]ã}mC3eâûE¾3íjŽùŽ´GÀCy”ßžbûOONN/œU˜ðÝW€‰I"{ÃÄ«xê[NêU..ñªÊ¢ÄÆü=ÿ–Q(ÆÅ-ß7÷a¶V”+N{ö¿X¨Ž}®¡¦*öséÉÞ´fÑ2NM€”;qÅñQ¢Jöž0m$L<ÜPÛÖá¶¡ÇM¸NE?wãò¶#eWdÇ…(³oòH¡ÛŽ æP{\ÙX2wf�°\¬ùóÑÏÜ~ÜŸSµ~&{¼ä}ý=—¬YÔý�ª5€*ˆ\³çܰⰴç8sϹÙáæ~„¹á¦c"é9a»ø_ÃÖÃ?}Þ'Fæn\±WÒ„þ|™k€nc’üàÖî”ÖŒé‹'°v›ÜËoHù¢H÷¦=ƒ$%QôWó8í1j‹Gÿ“öx¨ËçÏ�;zvªjÇ�{NÒl3Íîè¹.ç¹sW-êúmuz@e¹4ß\óÓžãÐLæü»Wèí§y6Þ£Õ±ÿ–ô´´‡h÷xÏÄŽ?&vG™GÒ<­½½õÌq÷Ë*×KÊùróäŽJ�RŽmÛ¶ý÷Œ¶ÖaI­å¼ndRîÍíí­iä„ISÊ}M®©”‰ß;ü�íJáþ)“^™XüËŽu=S›âžÂ Ù7çƒßʺMÂj¹­œ/ÿ¡2“Jwx\ÖËO1×)ãíW/öÅ–¥Pñ+I/*çæ¾®B³dÝý÷Ý·ë/i�C’tTJ½›ÌÕ±gî�+¯^¸üK)͘ \œÿfÚ3Ô3sÿ¹›½%í9ƒÿ¼œ¯÷µ[·î¾GÒàx_ß�\Ù±cG–î+ûeÚÔ ——õI ªÇ„iñxɾØÙßó½%ö<)íqåòÛ¿}Zá䧨gI¤Ÿ¥=C£(÷{=‘‹é%é«|}c‰ìki�p07]�ö µÂø³žeÙÙÂlzY”×í]ëV¾;íQcg®ËÒž¡Þ%Qþû’8¸§ò¶¶wûÆr^0¡@¹}r"¯o4‰ÛgÒžá`CC;®qisÚsÔ€=Š&}9í!ph–…‡jv·Owô|ué¿õÍL{À£sÓÆ s{>žöõîÆS %ËØ{áúdŸ½æUë÷•óŠ Âû·oÿ‰dl¥ÿùÐÐPYûy+ÍÝK&}>í92ÏuÅàà`vV¡ðP–¡Ü94ÞIDAT‡zc²?þe×@ÏiixD[¥ä]åœÈˆñ+å£OIâ¾Çʉ¥¨ìÕî‰n•[é=’ÊJ¡ h¢ÜYiq(‰¢U§j=Š{K®óÒ�,ƒ+„û;—®ëèYW,3y·4*sýNʽlãì®›¨’O)üIÒùiÏQÇ–n˜S(û:¬ ÂmÛvÝ&7~c…™º†††2ù íÐÐÐ6KìŸ$•Òž%ƒFé-ÃÃÃ÷§=™Ë²¥.l=wOkîÇ�+�O{€$éºR>÷‚ s w¥=H£Ù0ç‚õ’x'¼«6ÎYyáx^8á@(IƒÛ·Ääó%ñÆù¡†äöö­Û†ûÓäÑlþ¡"Í–ô‡´gÉ�ß$Š^<88|sÚƒàѹ'»ÓžaŒN”ì'�ý=ÿ’ö иìÇIä¯Ù0ç‚WÝxJ!ë(Ö­ƒw¿ÝÜ—HÚ›ö,u`Ÿ¹ºf Þý¦ñn}ÿÅô³uhÇ•�kn¾©4É–Êí-.Í U»m“t¹åJ=[·îþsÚÃŒÅààðMGyä³öïݽTÒ;%�öL)ùƒ™}þ°©Íkï½÷ÞZ  ÍÜöÉÒžb̦ÈôÑÎþžÓ¢É¹÷®úP×Ö´€zç¦û¢Ä¯“¢/^?·øí´ç�tùüËcI¾â;Åoƹx±Iÿ×¥ö´çª%&msék¹8wá·O+Ü=‘ZÁ¡$mÞ¹s³¤sÍì¼öÖÖy2½VîÏ’éIm!{eÌNIwJú¥›®Úqµ»ïO{¨rmÚ´i—¤efÖÝÖÖüÒ(ÑÝì$IÇK:"åñ*å^Éï”ìæöÿ¶nß~kÚ¡\¾O5”%I¦Ó“ýñ :ú/xÇšE+nL{¨#’¶˜´É¥M’orÓÍí;7Ì^ùS�É¦Ñ óžçÿìýhž5Ï,ù÷Üö(Š~_s§‡æôiwûn9/‰<©‰Uêñ2Eû\Aÿú ©:`emèZ׳æ°íñŠB¡Às¼’Üìã’]WÎkêýÏøQÿ.I&-,÷u¥’q`F0÷�¸ÙUiÏQ æJ$Û%ÚTÊû¦()mÚ8§oð‘CßÕ0“>•˜¾;‘‘ëw�Æ©¸Ñ`sÍè/IÒ«¯-¶–ò:.Î�´FI®ÅÍ[ÜÔlîÓܬÆ> swóh·›ï0·IïÈÅ“†ó%ýášW†+Ù·Rµ â:Öõœn®¯…ªg¦n—N’k~¨šcð#³ø­} <Ç ª*È¡2�–\¢ Û³Ý-^½ û —�)iGÈÚ�â…î¹Û;Öõ¾­Jý$Ô¸XIÐ{PÝ|²$­Y¸ìsq¬“\úAÈú�¢ÅÜ¿Ð5Ðók×¶T©'hpB5Í<4FÒäÿùÂó»ÿøÇ£Ÿörwu«JwuºôkÚ[Ç@ïÉÕè�@M³|àBùäƒÿûåóçÇku÷ºìE’ÿ6d¯GâI&¿¹s ·³X,òsT o4Ô´’®*±É‡úŸ×,\öÓ)Ó’çÈô‰ ýÙ$Éûö´æ®ïX[||•z€C PÓ&•,ì¡2:t ”¤ÂY…Ý«t q½NÒ–�}Ål›”ûEçºU¯ªR?Ð@„jÚˆÇAW-òǼ[sí¢îoÅq|¢Iß ÙûQÌ”'ßêèí¬R?Ð „jZ”„ „~С2�æÂó [úv¿N®JÚr†GIÞ×9Ðó•âeÅ©Uè�@MËMk »B˜Œ-°zQ÷ÇÌýÅ’UëRù3öìÊý°k]ñØ*õuŒ@ ¦M¶ýa•1Ï•û’¾EËoÛg¥ç™éAgyd'¹ç~ÒÑÁ©Uêê�@m»OA•1ÙMãyÝÀ‚ÂÐêݧ›«SRr¦Gp¸Yô�ŽþÞsªÐ Ô)s÷´g€ éèI$YˆZIIO^»¸û÷©±d`åË#Ù—%b¦ÇdöÙݹÖ¬?ûì°«¥ î±B „Z%üòDà$­]¸ü{I)~ŽIß 1Ôcr?sjiû÷»z�ªJ?P7„êAˆ•±+§ ÇïPG’´vqaÓï�~Ú¹¯•T�­'—ä?íìï}qz€:A P&™>6e8þ§B¡P 6‘¤ËçÏ�W/ZÞá®Ó% …¬ýŽ”ù�]ëV¾· ½@àB5¯«¿ç nz[ù¯ô«s¹\gï9Kï ?ÕCu­+çž»RÒs*ÝK’dúض©³ÎýÄYg�T¥¨IB5¯s`剒Ý,©õ±¿Úþ$ù×ÝíËk-»µÒ³¬X,¶»%©™WeϤ›Jqü¦ Ï/l©F?P{„êBÇÚµ-Ê�ü³™^/ó6¹M—<'é÷&û­Ë›Xô½µ –Þžú¬½ï2ùÇ$M©t/—îq‹N_»`éÏ+Ý Ô!¤`ñ%«ž•Küë’[…v»%{Ëê…˾Y…^ †p¨ ¤àÂs—þ"ÊG'»ôƒ*´›*ù׺V~  ½@ !@JV�ÝußÔáx¶IŸ«B»œË>Öµ®gUz€Á–QÈ€®þž7õI²*´û¶i³ÞÍ ¤€@Ñ9ÐûÉ¿(iZå»ÙÆ)ùÒ g†+ß d�2¤³åInöM“Ž©t/“~‘“½ºgá²{+Ý dÏ@†¬^´ü/Å'KúQ¥{¹ô¬ù-ËÖ¯:¡Ò½@6 cÖ..lš2Ÿâ®ÿ¬t/“މãäæ®u=§TºÈ¶Œ@†u¬ëYn®¢*ØÌ~3;³oÁ²Š‡P�Bȸ®þÞùnþ9IS*ÜÊMêè[Ø}a…û€Œ @ èºxåó[Òýn•s·Ot¬\Yá> JØ2 ubÉúž§D±]'yÅ�1ésƒÓf½ïg�5Ré^ r„PG_Tœ•Ëå®–ôüŠ73»Þ÷OúÇ5K–ì¨x/PB¨3Õ¼«PÒí>¿fÍ’Â_ªÐ Æ3„PgªyW¡¤gÛ¤Ü-K/î{fz€ÀX!€:ÖÕßs�›–W¡Õ�"{Ãês—}¿ ½@ B¨s]ëVžånUåï*Ügnïê[´ì+îaË(Ô¹¾Ë/«Ò]…“Ýü?»zΫp+„Ð –^²ò…Ibß’tx¥{™|ýaÃÉÂB¡�Tº?!4�jÞU(éÿMŽßV(öV¡!4˜jÞUèÒF¿¾aa°Ò½@ù„Ѐª|WáoÌâWö-(ü© ½@8TЃwJÿ^…vOsÏݲdݪçV¡(+„ÐàªxWáN“æ÷-ì¾® ½À°B ®oQ÷ 3¿¤¸Â­š]úf׺•ï®p0FB€ú,¿L²ÿ«ÊßU˜w·Ow¬ë)T¸¶ŒTÍ» %}zÊpü�B¡PªB/pBÀCT÷®B¿6Ž§Ì¿ðüówU¾x8!ào,¾¨8+—Ï]#×ó*ÞÌô³œE¯é=wéæŠ÷A R•ï*ü£GzÕšs»S…^`‡Êé » ?]…vÿÇý ³¿÷ÅUèF±BxL�½+$/V¡Õ^“½µoᲯU¡ �@“Ž�ž6é2Iù ·JdZ°zA÷¥î@Ã#Ƭó’ ^¡$ºRRs¥{¹táÚ…Ý.ñ**„@(KWÿÊç¸Ù5’ެt/wýçÔñ™…Ba¥{Ј„€²u­+ë]+ÙÓ«Ðî»Ú?éôÕÛ«Ð €†B ŒË¢�âŒ&Ë}]®—Tº—»îœ${uÏ¢e÷Tº�„k'ãÒ¿°08e{ image/svg+xmlscikit-bio-scikit-bio-a3beaa6/logos/logo_and_powered.pdf000066400000000000000000001743041520735541300235110ustar00rootroot00000000000000%PDF-1.4 %âãÏÓ 8 0 obj <> endobj xref 8 6 0000000016 00000 n 0000000570 00000 n 0000000630 00000 n 0000000896 00000 n 0000001009 00000 n 0000000416 00000 n trailer <<2C780593B9ACC84D8EBE5A09F6477FED>]/Prev 63395>> startxref 0 %%EOF 13 0 obj <>stream hÞb```b``¼ÃÀÈÀÀ±‰�›¸�bŒ ,  r×÷1> endobj 10 0 obj <>>>/Rotate 0/TrimBox[0.0 0.0 720.0 200.0]/Type/Page>> endobj 11 0 obj <> endobj 12 0 obj <>stream H‰l—]Ž7 „ßç}�Q$êÿy6ò� âð:@’ûùŠR÷ô&†oSÓ’Èb±Èþë‹ñè�§þþíñëñç#†^ÚCëþü?æ8¾=~úù—xüþÏã¯#‘éh9ô˜ìHf!ÚÇëûC¿|òÑC­ú­‡Víx=f¨©`ó׸:†29Êrˆ³¿Í2¼çB®ÁòÔU{§j§äŠUØnÜÕL¿Õ0›îƒˆã¥‡�¿ 2c�Ð[?Î ¶ù"ª¬—kE‘�Í÷* tø,3äYn>k ¹ÚåгZÈùòö4w4z/dЩ~¥-·r -ÎûŠÒ@tJñü�m\iÉÓÓÌÛJI¡ ‰½"‡Óذ�ꥤ)Xî -ÖìyÊêYãÚ©¬öt³•�ì¡ì•Ê‘~é^ÀÍZŽóÀÑua ­8nÛ¡M–íî4�³ÂY–Þ fe›â^ÚÏÏœoc Lt|/‰-#pv¦ „Q樌<öóS˜Tg¦›5”$ÿ©+Î2ÝñÇãëãË­pi‹=ÿ°rò °ß g=ÞõùÙZ(ͧ‡-Ö+ì÷Â�õ¾ÀöÒ=ˆ’É2޶HhÓY?m³ø ´ìÎzËåëÛç'ÖÃÉRn¬oŠqè™ìa»ÖYF]ehÑœ#-Ú·ØÞö�÷{åN-Ä`eÖ(U)ËëâI-¬j^d™ @vº~ÅÝUÌE•íI•ŲH‹o À“‹ ÜÅÓ�û¢ð™„åóëJÊ.Ïi2×�“2iNˆX�Ž#m½Ú+¼„ý¥K²¿>2Ñuôé•öé•7ñJ,`ßòˆï)܇üeñ²/¬oÏDݵþ?f¼*Jz´^™²¹Äiz“qo¹(«ëÄXTgE¾»ÅP‹Ê Àæ Ęîµ#ù)Û±õ¬¦Rljîùlœ{™åêFæ,ÉbEÊ^\¯G YªOb:Ç-]x¦ä½-šH\¯ºYù�Ó$/pû<Ú”ëh!áØÄ�ÑRw-ú¿—z´Ñê-¸½ðŽPv�ï|BðÓÜVq¸aå Ü;'sK^çcQtöަ´À \ÙFçáq¹9èÒÓã’i°–ÖÉ!ø”}›ãᵈƒU2wWC.Áºíû•j±ø©ê,L¾_+Y•à·•ëØÓlÛ$_�p@�Òkb‚M­©pñu åÐo"Íô )›QxèéiqÖðw—ÍqÙÅt›‰ö­QTc$A¶iß("‡&‰�ZYQ«0Ò XÙÄž¤]<ä�^UHè7 Y}‚]£ƒÇˆõØC�&¬´<)×Ä‹&€3úœ‘. ewڜݚr~Úfz²FMšì uÑ¥3B?OŽMTà4ðY.ùÛI0„ñm½véÖIg£u§Læõ‡Äö›Ð4�/Há(>x­Ó8%¼Io4ÔBU•È×,Êöµ‚g‰¬ÓV¹dH´ijXC2‰µ×r]IB’rP)�KJ�§WMÑå#¯Ïæ=x/|Ø@=o)PŸõš&ß¡fˆáÍ\¨—LC–VÉEõaQ>–Evû +™²zâ~3'g«Ã$ö7§uôþ¯bâ|&| êÝÞÏ$¹Ÿ'5kÑ{DG*Ÿ:W8¤Q*ùÍ%eWY—wÍ}0I£F¤ŒP|̨AY}”ÆZp†V–¬ªö'˜õA€žòaU¸Œ9¥Jš•U¶˜ç«iDñc×7Nëþk.®?�-¨¾OZrIvµ(‰¹8{7(è'¨ˆÔÙµER$AVã‹Òõ¶¾È2Ñ#±R˜løC£Ň|ÒåWÁ4§fDO’‚Fσ‰<4ç\¨õ�&jÔŧbš¬ü›(¹f2Ûh,£+É9•’Pu¸þOÈþk @ÂòúžhîY0äöIa&&(¾�*L’’«4äî#sñW«£)ÆLФ‘WÒ#hQs¥À7�?˜=дg‡x˜(Ô&½mR¾¡Ñ„@15•*±ƶ5Š&¼%iYÞ�§J!�‹i W‹5ï�`Ù«Oqzr‡Ä]�;¿"!FÕ¾3¿‚7÷¯vU|¼ˆÝY_ôI¤Ï&Ç®ú �U}Us­‚Q3Õ'�EÏ¿Fn ¶}jðæ“HcNVÚU²‰Á6V[Éokhч_ò1K³Î;÷_ÿ 0;”!R endstream endobj 1 0 obj <>>>/Rotate 0/TrimBox[0.0 0.0 390.0 175.0]/Type/Page>> endobj 2 0 obj <>stream H‰t—[®ä¸DÿkÚ@É|?VàoÃ^@ÁcÓm`ìýs"H©êv·ÑÀm¥Š"óüãŽØë‘g8žzøï?ÿ8þóg/ígëþÛÇÇï�¿üõïáø×ÿñü‹|{†™ÆÑú9õÕëûC?|ËŒ:¡qv*gá§×#ŸA®¦Š�<ëÃÖ¼Ý~oóE`áÌ3Þoj>ÓìïOø?õ÷†ÏÔÎËÇ�ÏÔÏ\ûí�ìÑßÞÞöf}±Þ�±¼NMg#CÏØÎQ¾¼a—L¿QÔ’ÒÏ6éë”VE™gÊŸ/Ø"Æ÷¹úJ¸ã‰Aß³_X^µ3æìêd'¸�­ŒUÉü6UЏ×û»‡uÞz(O:®í"il÷qT‡Zëcû²á±-gÍÊ�ãX†Vž,Y–‚®ì¶¬tÖ¢u�¿ùl)jw`òz”³ÍÉï�tS¾,ŸòõȆ±,0ns AŒb/0ûíñïÇo�¿}ôÈ ”žæ¯{$S¥«Iò׊}}Žl?§ÁÜ[[XãÃ~ƒÝ¶ðÓ²¼.e¡«%ÂMaÃ}¡=ÖèÎ#–O´÷”?ÑNf[M_ÐNÝYÚImÚhŸÕÿ×r½O»êÕ —ùÒà¦ðµår›_ îßoŒØgLÓ©U… eŸ•TJ5ð‚H™Š8änŒ¨èoŒ(’$+Ô %+ËZZ@[É»0¸»ð¹R¾�{¥ß.¿®j,Ø»�x]n”D¨B…�fÖºN 4'8�Ž{Ä)ãÿÿþ†YJ¢éØ~ÆYø¬™wøÑ^ †öçó�ÑUùÑ w©ÐGËd=@fs§'v¶“LwQ€*˜(ž ¿º>!®Ê§UY…/ß-¥5Šm§ö3“¢÷•ËýÄ|¡&Ë‚žš§IÕóhUÏôŸážÛTz¿z@ígÍ—ìu6)aIì¾M@F÷шØûRŽöÑœ�ûüï¥I ‘¼wHûÅ;.ŽO+®ë)ži\ïá²JÓO É–5ÈêŠ*r\…ù‡¼+GÓ´õSÇ“Õç³éé2ÆÐzx€ÁÆØdbôM˜Q<ÈŒ­|¹|óòÀ›jñÈàãëï÷¦Sœ+}Ÿ¸#eÛd�)S„ðÓLØž'ò–æiCÔ¤ã¾SÉËRzÚZ+»;‹ß.³¥¦µ*¾æÇ< C3?EñüððfK†z÷|Iê¸+*%io~p¡Õ Œ²êÂÎrH“Ì¥×åA&zJ_Y§äJ(,½pYò}¯Ýò'-ðn纋TÖí­èDu«k§íœaíÚn2[™×¨x×áµ3C|w;ñäI˜Y*ä“@r%8^ŠAúDÕ,„! gE.…ÃëÑhÍÖ)ðýb@­ôQ©–mžT4,ØÃ)YôØ—£:ü•?O8{\îèìFR¶ÉêNÕðb¿<}×½~�|¤ÏµÛÐo‡ z5¦Ë—Q(Ûíç¶VZk‡ Òm©wÀ„ö�뉴ƼÎáuahYˆÚÒëzÄNj€,’¾‚Øæëq…¹_pÚNÃõÁÊѵÛNáû´�áË›�ÿË×ËT «ìÁ%´hQ¡õ(P}2nÌš\QDÀ@ó¨zS.¥Ÿ™CyãP�-hò"­NNcŠ‹*5|»n Ñd!"&ÿ⊠‹žVu0YxXDðo+Røf¸�8º­Ö¬A/vzL‰K¿ª«ÈvŽkíc�ó`ÌA·Ã+ÃÝ5ÏÔ%Ê3øˆ¾qÀt‹92³€©Æ¢me¦�™ +»V÷âbRhбbT²™Í4¸QÕ¿jCKBgS¥0”~Dø:ªŠÞžÞA`+™«¢%Y”f*Ve5ç¦ê‰¦X×åˆ:Ä‹¤‚àäìâcxh€ËŠ õg¶³¤)²¢D;™ ‚VµIž,SÖ"g1Ť̡dö̸¤Å*¯5_Cıfˆr8¹€²$¹áû]ïN§Xßä(þs[tç"9šÔs¦5 ù.øÍæ¨àš»Ù 1˜âƒªýUcàV*pC¤Q¦Æõ•a°V–ÀÐe¦ëQsfh¯¢QIÛièp±3}KÑiTD(˜¨Û% ¶Q6mPAä!hÌ誫¥>„ëIG¢˜Ò€åd¥mL'Ón¬þ ‚�*®:c¢{LÐBëYZc=Iœ=•¿îÛƒ„Ã÷ëE”tÑô�Áñm ·„¹m5ðjëN^ð-f[-ÌåxWÏ&£“u Ó'kÀ ŽÊh)«ÎYJ#Xi«Å¦ñB*5êoZQÜ5ÊY-A«AÃþ·�ò¤ØæÒhì1Ý&�9*êÉ‚�w|á¿æ šñ6u¨dì6”¸ýx]¸¢5û�÷¹ Ñ[]_…6(kæ1 #œŠ@Õ$§aÝ-§¯¢cÝ]H‹î.4}Þ¦3,èÝ¿“T2¦o»yJxfãæ–N7™ãT¥ê€®çÅ",\&àšú‰0$%ØŠ’­+Ép΢éÿ©OÉÞ”Z–E hºd±šb¬(Åd¸jê×Çú¯^†h=Ýl=¬C nˆž’0`aMÀpŽ›±8—«ÏŸËQiüÀ,“¿´¡†,‘&ÿÔeléFKÙQ~i1Äv XæÉÑ岜qQÀõ+äŸÝ”#šSEžÂ¿G¹s7£²)VÓÜ€ÚsëQÖ5«8¥©ÌšuãРØF0}xÉRñAŸ‰!PÚŸ=5œ¸¯¨¬Í¾ÇÑHÀ�™Uƒà–ÊÈ#ÉÆ7q½ò4°Ç »›UI"!ߦÊ$à_v5qKtªÞüõ ‰n¼—´FX'«ϸtðð‰C3Q÷-7"‚·@ÝŽ];›Ž/uýi8Šø¬«HÐÇGÃyŽtå1TÉEöÑ�é¶a#¼¯SùèVø_ÂÒ–º'¡cÝâ&Unkzi” s˜”�ijÈC Ìö>‡Ð�ïmó{6ârÓ�Å$xLXUÚa¨Ï4dSrä÷᜞˅•l~ênæi¬ã&y&uþ80['ܦ†ïðL£‹5<Þ´Ý‘*hìäë„nŰF>Y)L�žR£¬>Ü’É·Ly[<Ì1qu~´›{_À’m¿`ÎX©p(ó• ÎÓIb£ílÆÿöXì3ŠO´XRûG+ù²v/ýj^”¿röÕúeC!E@4£|Jç})\RB¿„c·�n¡ê; ÛÕ2&N]‚XÜâÓÂ# }‚e6Á·h H¬›|%W$ÚeÐbƒPc 9èrßœ�I#—ÐfBè¼Ö¤O!FtBã¶Nƒã ­j=Ù²ý>䢶ŠÂÓÖ„iÈ·°ïl׉"»�nÕ`/G´϶^äR²8¶�‰ëâ:FíËi1óXü�ü—x(ÅSñÎä/5¬Ç¦ÉwµÆ™R*œâÄqŸäú¸pznüT$yIì‹(XŠŠE5“—3j�¼Øï¿¢É{a—ö>%o”w0y ³® *þüú'À +.† endstream endobj 3 0 obj <>>>/Rotate 0/TrimBox[0.0 0.0 650.0 110.0]/Type/Page>> endobj 4 0 obj <>stream H‰tW[Ž$¹ ü¯SäJõ ¤øÛðÇ ±k;m`íûŽJYÕ=» '™¥”(2 þñÈ—Y¾¼çëɇÿþúøåúÏ#§ÑüÊɇþúÄß¹æõûãoÿg¾þõ¿Ç—]ÿì*«¤âîØ$åeóúø|ð—ÏdzXj\öã<>GZFÓÒ,ó6-åz~,iÍr=gjy^-åÒ¯ç‚Ñ®�€+OË©]=õ…Ç’jîÇèÉlh�̙ƨØ>LxЧc)ö}–šÚâöŽsKK ¿|Ž/4çxùyÛûñA¼A ªŽ,Éqû§yšíýö¨£ã "UÊÏ6Â6à+±R©ï/°…Ùë ýÍCfYKױ̰c¯þ¼0ÛSõkξ>öÂz¨2¡|¾Û/˜Ë&~¼ÒíÖ\ÀxK%o¤ûÒ­HÛˆ¶Íö†ôAHÜHGd½—w¤#†}½�ŽÀ–�ôÛôf÷ûÈyW¡UüPR,9‘³Í/@×ï7Ddçde !½3�¹õ8¬0“¬Ü@H[…ù­CaÎ_áEnŒÄEH"aExgºÁkÀ3À=Á—Ë'½²§ëºAR½á®ØuÂÆu¸xEqâJ àß­› ‹¿\ð‚Y¤±Þ~†Y~Ë™6øfü²€ýþ|G„TÕ¾›ù¾E[ØÅâ9-T€é*ô‚½å$Úˆª(ƒ½ÑFÔ ~s½wüV5gj^Jsd[nígô‡1"šû =I ‹;¨‡t>Oï|¶Qö Ð#„WÔ< äi?³­T­“‰¶‚Ý· ”€ö&Hìýq%#�öÑ@éWø”õïƒíL„ï_WÚ/^÷Âñ%îuž,•yÞƒwUÔ¼z£ÕD|”°:ßyV•³ÃêiÀ“Vã¥ë„1'/NT�Ã�3î ôÀ®ËhßHƒŽËT0ìöø¾Ë‡šÝb�š^×íöô&SO¯éÝP±m¢�1PÈn?ÙË�©nBgQÜ€Ú$/1Âø®£XŽÅèôXK{(ˆ?Žé(PçZæžíc]è Sh¤¾©¾�-Ñ·ÚKa1€¼Poý‘QÀÊ3Ë�¬+¯ ·P"¨Ã±=¨¸=2߱ޱ-·R8V“kí–<%°»m8§‹²±‡”Ndµž”xZy7íî7™EäM¡9ÖÇ®Ì>vž®dˆ*šÕó�? à;vkHPÖÄO`Hœ„}QcÌË�mûóõ!ê]„5ij}ñ(À)R†ÇÉ $±_¯ †ØŽ;<{¢lË ãZÏ‹¯lÓíþ ¢7÷zoWA_åí´ (��·7¨Á6\½­¸ WÇ‹FA6uØ~�î$i7°Zcw2æø°áF¥ê{ÄjuR³k`³™ú\e›�sÙýÇí`œv¨öv'”÷q'ÔÛ�“‡íìmÆe"ÿY¹”xaÆùHt½3/B�à ˆ†ã)'Þ˜7Ä8Z笤ËnÀ^ZP5ˆ‘7uvØ„íà¤`" *¦ üeì’@8òÀ°'a שˆý“Òy¢(»·G‰öÌ6ÔÀìú5J4(õ›ÈB¬ 4æ¨Ðû"8Îù¥�4ðŸ ß¾P›ónpPóôòžµÄÀ0*xŒùYÙ¥v £VxMòÉB/Å)Ô“è!.-šGH 4\ë= |v_Éü‹[ 6Ìw#?ËûÍH¹¾�ê^08¸›úÝb7›ë1‘}–8–¼€.}¶/Í ]5&è’+%Úv‘Vvy‹¦Nù$òÅÊ@×¢PÃ:eG12¯µ)´½H�=Y™ `~5È`¨Ë(•y8:B¡òÐ|ZϦðûd7S{rqq%Ÿb{†™'E?Àå…!˜œQp‹µÞJ:f°H÷™¼úUn0`6šßtº,ÓÅÂ�/äY‹Q ±XU}чÔÍ,T‹ò˜ÚòýÌÆ!"—Pƒƒù ºñ’òævZ‡›röCá\€ÈByP)m hQ5´À^ˆ)¿šœ‡Öd/ê™Ççnª™†¸bzRK48Á¹Š�ÓUÍPÏû3r©8†¢ [Sº_ÔÚs(T_ð¢”ía<3ðÒ²âVñÅ!§V�º!}¨nú«lÄüŸû)ô7<ïe Op•%ˆÖ侘l*ÂlÁùrl§âY°QIÐ"M°lr¹‘îIÄÀܪ–g4瘑mä-ê· l/=Ò•X§@m!IqSuhÖcïB¬Qh8 ®dMbCsÊRA¦•Õ?IðyÖ‚04ÐŒû7ôÁ.àszÂmÙ­À{ÎmvE@Ÿldå:qþÞ_;‹j‘õ>gºšg‘Å!B[·—M¾ÝSÇ2¾ ‚¢5;©Ø«¯‚�Ò€é’`ïõÚú#¿™¤ÐÁÐÐóƒQ%!âo〈 “«FÌo6Å÷÷·PNs½¹n]&óÑDí|ÄG*£ìÔžCÍŒø(n�/¾×ýà;Ѩ9æú¢ªš�s ù /¬hÜì)„ §¯ÎB°ÈàŦÁg¨«F¤ºrvj¿ß$_¨À""‚2:ˆZ!;u!u]hD¥œ®QZ4ñÉ€ä`£å+ÂÙ\,ãSÙavI›ŠL—ÔI‚xZÞT若ª‹…¿À0Ç"ɽÛè?ȾcdQJÖ„};ÀeÝу:cŠÜÚœ·�õ”Aµ4Äqž Ò¤OOÔ²j-–Â%˜Øâ):l?KP·µ-ΘK\–¥"{�Å�Ê$Qô×&z0¶µDÍ´ œ-ëe³Êiq(ݦK³Ãª�Ä‚òµuÛ?hgÞ¤içÝ@ºØn Ô©Ñ?†˜„]�½Ö”/`Ôaóìé6wº¨:›ÉÔѾ9ì´€€ »æÑg_Ñó�@,#&Tô?1H~U`U¾›i�b[U‘j�€"¢f±«²ö˜Z˜¤k—dÂb¤F>ž™Ñ� mú„Id# zÅÞým�[Èר–$ÂÆ RÙHè=5³¶A?¨·Ù¥£øâ ‡÷ލ[! *=Mc覵&Ö�aš²‚*é_&749¾üÿì—ËyÝ: „÷©" 8Ið¥2RC–7ý¯ïüž‡ì”à��`Q fy¹m’lÿö?©V„A2ûMIß”ôMIJB/t’�ûe”¥æcÔ—+ŸX¤G}šýàGXõèò<€³¿Fn%M/¾g=BáòS—Z‹a6ÝàµÏ0Û<m†T„ÙV¹mó½ÆYBUeº)Gµ/'+=úÓIëk†5æ§Ú’&=GÜœô±=NÔp9ZÞèý1Œž½Ò‘W3‰#om=ZSž2}il·æ‰§! QÎË–ö f2Ï'Û™f͘ÖÚó\gÛJ²Šç ¦°l5FI—]ö€Y媫>r¾s§5•œŸþp¸Â!cÑÓáæU5 çÂð(ÃT1à³óªêFRr‚"8e×2Æݸ ­ê|m'X,Tsõƒ›ÕÒ�@báEàEO•}f˜5÷W³ïTösð¤Ç`úž™ý婜›[ûŸâüC gÕ‘5—V8óÞ¥’üçS,Ð7Ó$PN—A,ÃU)v2༌Q'”VÂ…)Ï:ä厺 Ep\\…=ëþÛxƒµ¼¿ð¿Í{£Á¢«Äé)©iOzì…†\K«‡Ï¨€o–u®¨²û‰ÔÖ qæ¯Pazbn‚�`Áð4¤‘M Ö Ãu´‘éY1ã¿�XÕ˜szj{}õõ+r:ò¬%„‘¾üò<™rmNY�VdI¿<ÜlÛ't6Ž'RÊÆª%ì&ò£-Õ!Ì".[„ çCávÖ¿úQ@а�™P §'(žÓ¼�Pų¿ —ƒB/�¹%µrŒ£Èx¬£¥ûWÒ?rª* Õ@脘“Ô õqæÿA¸_`~i1ê*®â5·–#¯s5W"ìt†õªwº‰¿Œ¼ôh�ƒ`©*†œŽ¹K¦B)¶�Qff•TŸd9AkiÁ,ÕÕO¾‡1‘çþóC¿aú¦Å¦ªEr'¸gà%P‹…؆Dû § �’öêÐB¦3Èåè  ˜àq[o·5D>ಱüDÓk/oµV¢Ýy}{,ÏXËe¦½âßÔ"%$æùœ0‡kl¤Û,WŒQr@•“û“?‹wMîHêGBM˜f©£~´K”"Ø8)ƒH”­Ó"Ÿ:Gv- )ÇqBõ©¾Å>é¿7ø´€±»_%bŠ|¦Ù{ N_L÷„#kacê2±ù¶tRß %#jZ ,uÕ)¯³¶+=�#qÄâ0šý„¡=Ïf>%næ´=ç³zÿÖ‘Zy©Ç–X·X·¦�¸“|ËÏKDkwÿÿû#ŸÞwûØmï{dÝí·¾�þ–˜OY»¥ô-ׯúýþñ¿µ?zý endstream endobj 5 0 obj <> endobj 6 0 obj <>stream application/pdf scikit-bio final 2014-07-16T14:51:10-06:00 2014-07-16T14:51:10-06:00 2014-07-16T14:51:10-06:00 Adobe Illustrator CS5.1 256 68 JPEG /9j/4AAQSkZJRgABAgEBLAEsAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABABLAAAAAEA AQEsAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgARAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9I3WoR2UsFrplqshllll kiiVUSQmRjOqSkpF65dnlKkktxetDviqPhvYpDJGssTzxMvqRh1BVJGPplgC9OSbrX7Xt2VV45Vk BKhhSn2lZeoDftAeP8OuKrsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVWx yxyoJI3DxturqQQfkRiq7FXYq7FXYq7FXYq7FWM6hp99aauupGyTVI5GSICLjFJApmMgpHwPqjkE blJJ8L1YcFJ4qo/VdP1DmkulygXHGUPBcs7W0iuG+2aOy8XkDUSnIDidgvFVV0jy/p2lc/qYkT1X klmUyyurSzENLIRI71Zio3JNN6Uq1VUyxV2KuxV2KuZgoLE0AFScVQ2n30d9AZ41ZYuRVC1KnjsT t4NUfRiqJxV2KuxV2KuxV2KuxV2KuxV2KuxV2KqdzN6NvLNQH00Z6E8R8Ir1PTFXi2g/85A6pqWi apfy6dYwS2NvZXCAXXOIfXLqO3YyyReqqKgk5bsG2+zTcKWW+WvzLutU1bTtOdbC6F7eX1o17ps7 zwAWVtFcBkZkXkWMtDTYePbFCzQ/M1/YeTL+/giWWy8uadcu6SH4prmBWlCAgkqiooFad/bAxiVe z85ec7jzJLpqaZZTW6aZHq8aRTyC4kjnMqRQr6iJEJC8VCWYLv1wskRq3n++01o47rTFtLp7VLl7 Oe4iMis0kiemDGzK5/d1+Dl1wEut1faHgzMaH03z589vs6WmF/5se2lkj4QQql+1j9YuZfShULai 45u/E0JJ4gYssmt4SRsPXw2TQ+ni/YmWgas2qWLXLCP4ZpIg8L+pE4jbjzR6CqnEOTps3iR4tuZ5 bhMsLe7FXYqgr6e7ju7NbeOSQSMyyD4VhC7Fmlfg7gha8AKBm2JFa4qrpLcEJziVCZHVgX34Ly4s tBuWAU8dqVO+26rrRL1YlF3LHNMB8bxRtEpap3Cs8pApTbl/YqrYq7FXYq7FXYqh7OwtrNXS3X04 5G58B9kEgA8R2xVEYq7FUBdajLDqdtaqkPoyAtdSzSPEyAkJF6K+k0crNKQrKZFK1B3qBiqPxV2K uxV2KuxV2KuxV2KuxVwINfbbcUxV2KuxVJL3y3Gk6X2jFNO1CPYlEpDMhNSk0a05ddm6g4opOxWm /Xvil2KuxV2KuxV2KuxVA3umXFzcCRdSuraICL/RofQCcopll58miaSrhfTcc+JQnYH4sVU4LC+t bVY4pIpWgZ/QUoIecXpkRws0YonFuPxKnRfs1xVMsVdirsVdirsVdirsVdiqDv8ATmvHhP1qaCOI uXhi9PhLzjKASh0ckLy5AAgV+1UbYqhIbf1NZSWa6llKpMI7erRIDHMd3iL/AB8FlUIwjp+0xNY6 KpvirsVdirsVdirsVdirsVdiqE1D6yyCOBZQSQTJF6dQAdx+8ZevyxVKGOsJcQwSXVx6koLInp24 5cKFtxLtsRiqtBDrkbIXluJArKWBS3HJQd1/vu/jiqJ0xNShPG6NxcFti8ggVVNSa0R2bpQd/wAc VTPFUHc6xp9tMYZnYSAAlVjkfZthuqnFVIeYNMYVV5GAUMf3Ug+EkCu6jxxVJ/M/5haX5etVvJ7a 6vLeSWCCNbRFaUvcRySqeMjxfDxj7b1PTFUDb/mjYX0bta2F3EIGVpmmFuy+nzhUryimkCufrC/C 9GXfkBTFB2TG188rc6pLYJoupUhZ0lvOEBgDRy+i1P33qkct6iOnHfFJV185WTWa3Qs7sK37DJGr Cis3eQL+x0r1oOuDicMawcPFwy+z9af4XMdirsVdirsVdiqldwfWLWa39R4fWRo/WiPGROQI5I1D RhWoOKoDyvokuh6DaaVNqN1q0lqrK2o38hluZeTs9ZHPWnLiPYYqmmKuxVbJHHLG0cih43BV0YAq ykUIIPUHFVOW0iluILhmkElvy9NUlkRDzHE841YJJ7cwadRTFVbFXYq7FXYq7FXYq7FXYq7FWLed Py60XzdcWU+pXF3C9hHcxW4tZEj2u0CSklkdq8VFN8VULD8t9M0qEnTJSZlmFzHHOkQg5qKKnpW8 cCInsiihAOKCu0L8s/LWlW0n1eGSG4uraC3uXWQciIbdYPiZFjEpIXkS6n4qsADgpE4iUSD1TOLy lp0T2zpLNW1dXjDMjbr6YA3U0/uV+zQ9R0OPC440kRW52/Z+pO8LlOxV2KrFgjWZ5gKPIqq58Qla f8SxVcyq6lWAZWFGU7gg9jiqnaWlvaW629uvCFK8EqSFBNaCpNAK7DoOgxVVxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVj/m3WZNJtGulXnxaFApdo1Hqs4JJVl/lHU4 C05svAL5b9Uj8p+bb3XNRW3mgNvErVDpNMeY4OafEfEA420YM2SUzGQAHRkJvYpotWSITRy6fzX1 PVkKlvT5gip6juPlhcxjnmPzle6Xe6rFDbrJDpj2ylpJ5gz/AFmMvtRuoIpTw37YC6fVdpyxymBE VDh6/wA4Jo2tSRWkF24cx3DRBlDyMU9WGEqFHNeVZJafTjbsDqKgJEc6+39qtdLq07TWtvdGzuFk ZIp/jlXir255FDJuSsjD7XfFvJW+Xbi/uLC0vZrtpxcANQqyUJlRSN3YMo5Mtab9cWIJvyZNhbHY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FUo13QY9WHo3KrLZMF9 SEs0bc42JRgyg9ORxas2GOQVL8UgdO8n2+lSxS6VCkDo4Ll5pJQUowZQGXavLrgpjh08cf0/ffPd M7vTnn9aRbeJLmWF4DMJGBKuP2gEHKh6V6YW5LLjybZXd9NqF3AHvbleFy6TyojqECUMfErTiBgp xJ6DFKZmR6pc9zvtXLkjI9FlVZISkZtGVY44C3IBBGkZDc435V9MYXJ8McPDWy210KWzkX6sFWOr NJzlZ3LERBSGKdvQXrXBSiAAoIiDSjFM0iIqGVlaSj/DVWViQgRFqeHXCkRTPFk7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq0zKv2iB88VaEsRbiHUtStARWmKpYn mry1K9xFBqlpcT2qs9zBBNHLKio/puWRGLAK/wAJqNjiqYPd2qRJM80axSUEcjMArcvs0JNDXtig yA5twXNvcKzQSpKqsUYowYBh1U074ojIHkVTFk7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYqgdW/Q3pR/pX0fS5fu/X48eVD05bdMVQlr/hP65H9W+qfW/h9P 0+HPoONKe1KYqxnSf+VJfpu9/Rn6H/TFbn656Xp+rXlJ9Z/2VfVrTenLtXFSv03/AJUz+mJvq/6F /wAR82+ucvqv6T5eqtfrFP8ASK8+FfU3rTlvgacvh0OOqvr39GYaZ+ivSl/Rvp+n6p9b0qU9SgrW nfjT6MQnFwUeGuf2ozC2uxV2KuxV2Kv/2Q== uuid:c5eea29e-5a2f-4c92-a441-b709a51f3731 xmp.did:C73F93762A0DE411B42FD2453D6540A0 uuid:5D20892493BFDB11914A8590D31508C8 proof:pdf uuid:d9618e09-364d-4545-a3c8-10152cc09e2c xmp.did:2A3809C99907E41184C4D7B68ACFE949 uuid:5D20892493BFDB11914A8590D31508C8 proof:pdf saved xmp.iid:7C371A9505FEE311916CC1FAFB62AB15 2014-06-27T08:16:08-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:7D371A9505FEE311916CC1FAFB62AB15 2014-06-27T08:50:57-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:7E371A9505FEE311916CC1FAFB62AB15 2014-06-27T09:13:05-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:D713ACBD9904E4119064929701B7940E 2014-07-07T10:20:46-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:DB13ACBD9904E4119064929701B7940E 2014-07-07T14:47:34-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:DC13ACBD9904E4119064929701B7940E 2014-07-07T14:52:36-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:F24894488907E41184C4D7B68ACFE949 2014-07-09T10:51:33-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:F34894488907E41184C4D7B68ACFE949 2014-07-09T12:13:24-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:FA4894488907E41184C4D7B68ACFE949 2014-07-09T12:48:26-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:263809C99907E41184C4D7B68ACFE949 2014-07-09T12:49:41-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:2A3809C99907E41184C4D7B68ACFE949 2014-07-09T13:15:02-06:00 Adobe Illustrator CS5.1 / saved xmp.iid:C73F93762A0DE411B42FD2453D6540A0 2014-07-16T14:50:48-06:00 Adobe Illustrator CS5.1 / Print False False 1 10.000000 2.777778 Inches ArialMT Arial Regular Open Type Version 5.10 False arial.ttf BankGothicBT-Light BankGothic Lt BT Light TrueType mfgpctt-v1.67 Monday, August 30, 1993 3:58:29 pm (EST) False bgothl.ttf BankGothicBT-Medium BankGothic Md BT Medium TrueType mfgpctt-v1.52 Monday, January 25, 1993 2:11:37 pm (EST) False bgothm.ttf CenturyGothic-Bold Century Gothic Bold Open Type Version 2.35 False GOTHICB.TTF Cyan Magenta Yellow Black Default Swatch Group 0 White CMYK PROCESS 0.000000 0.000000 0.000000 0.000000 Black CMYK PROCESS 69.531298 67.187500 63.671899 73.828101 CMYK Red CMYK PROCESS 0.390601 98.828101 96.875000 0.000000 CMYK Yellow CMYK PROCESS 3.906298 0.000000 92.968798 0.000000 CMYK Green CMYK PROCESS 82.421899 6.640601 95.312500 0.390601 CMYK Cyan CMYK PROCESS 69.140601 14.062500 0.000000 0.000000 CMYK Blue CMYK PROCESS 98.828101 96.093798 3.515601 0.390601 CMYK Magenta CMYK PROCESS 0.781298 98.437500 0.390601 0.000000 C=15 M=100 Y=90 K=10 CMYK PROCESS 17.578101 100.000000 90.625000 7.812500 C=0 M=90 Y=85 K=0 CMYK PROCESS 0.000000 89.453101 84.375000 0.000000 C=0 M=80 Y=95 K=0 CMYK PROCESS 0.000000 79.687500 93.750000 0.000000 C=0 M=50 Y=100 K=0 CMYK PROCESS 0.000000 49.218798 98.046899 0.000000 C=0 M=35 Y=85 K=0 CMYK PROCESS 0.000000 34.765601 84.375000 0.000000 C=5 M=0 Y=90 K=0 CMYK PROCESS 5.468798 0.000000 89.453101 0.000000 C=20 M=0 Y=100 K=0 CMYK PROCESS 19.531298 0.000000 98.046899 0.000000 C=50 M=0 Y=100 K=0 CMYK PROCESS 49.609399 0.390601 98.437500 0.000000 C=75 M=0 Y=100 K=0 CMYK PROCESS 74.218798 0.000000 99.218798 0.000000 C=85 M=10 Y=100 K=10 CMYK PROCESS 85.937500 16.406298 100.000000 3.125000 C=90 M=30 Y=95 K=30 CMYK PROCESS 89.843798 33.203101 97.265601 25.781298 C=75 M=0 Y=75 K=0 CMYK PROCESS 74.609399 0.000000 74.609399 0.000000 C=80 M=10 Y=45 K=0 CMYK PROCESS 78.515601 10.546899 44.921899 0.000000 C=70 M=15 Y=0 K=0 CMYK PROCESS 69.921899 15.234399 0.000000 0.000000 C=85 M=50 Y=0 K=0 CMYK PROCESS 84.375000 50.000000 0.000000 0.000000 C=100 M=95 Y=5 K=0 CMYK PROCESS 98.828101 92.578101 5.859399 0.390601 C=100 M=100 Y=25 K=25 CMYK PROCESS 100.000000 100.000000 30.078101 21.484399 C=75 M=100 Y=0 K=0 CMYK PROCESS 74.218798 98.046899 0.781298 0.390601 C=50 M=100 Y=0 K=0 CMYK PROCESS 50.000000 98.828101 1.562500 0.000000 C=35 M=100 Y=35 K=10 CMYK PROCESS 35.937500 100.000000 35.156298 8.984399 C=10 M=100 Y=50 K=0 CMYK PROCESS 9.375000 99.218798 48.437500 0.390601 C=0 M=95 Y=20 K=0 CMYK PROCESS 0.000000 94.140601 20.312500 0.000000 C=25 M=25 Y=40 K=0 CMYK PROCESS 25.000000 24.609399 39.843798 0.000000 C=40 M=45 Y=50 K=5 CMYK PROCESS 39.062500 44.140601 48.828101 6.250000 C=50 M=50 Y=60 K=25 CMYK PROCESS 51.171899 50.781298 61.328101 22.656298 C=55 M=60 Y=65 K=40 CMYK PROCESS 54.687500 59.765601 64.453101 39.843798 C=25 M=40 Y=65 K=0 CMYK PROCESS 23.437500 39.062500 63.671899 1.562500 C=30 M=50 Y=75 K=10 CMYK PROCESS 30.468798 49.609399 74.609399 9.375000 C=35 M=60 Y=80 K=25 CMYK PROCESS 35.937500 59.765601 80.078101 23.437500 C=40 M=65 Y=90 K=35 CMYK PROCESS 39.062500 64.062500 88.281298 35.156298 C=40 M=70 Y=100 K=50 CMYK PROCESS 41.796899 69.140601 97.265601 48.828101 C=50 M=70 Y=80 K=70 CMYK PROCESS 51.562500 69.921899 78.906298 68.750000 R=43 G=182 B=133 CMYK PROCESS 73.828101 0.390601 64.062500 0.000000 R=48 G=161 B=112 CMYK PROCESS 77.734399 12.500000 72.656298 0.781298 R=38 G=148 B=115 CMYK PROCESS 80.468798 19.531298 67.187500 3.515601 R=125 G=143 B=135 CMYK PROCESS 53.906298 33.984399 44.921899 4.296899 Grays 1 C=0 M=0 Y=0 K=100 CMYK PROCESS 69.531298 67.187500 63.671899 73.828101 C=0 M=0 Y=0 K=90 CMYK PROCESS 67.578101 61.718798 57.812500 45.312500 C=0 M=0 Y=0 K=80 CMYK PROCESS 63.671899 55.468798 52.343798 27.343798 C=0 M=0 Y=0 K=70 CMYK PROCESS 58.203101 49.218798 46.093798 14.843798 C=0 M=0 Y=0 K=60 CMYK PROCESS 51.953101 42.578101 40.625000 6.250000 C=0 M=0 Y=0 K=50 CMYK PROCESS 44.921899 35.937500 34.765601 1.171899 C=0 M=0 Y=0 K=40 CMYK PROCESS 35.937500 28.125000 26.953101 0.000000 C=0 M=0 Y=0 K=30 CMYK PROCESS 26.171899 19.921899 19.531298 0.000000 C=0 M=0 Y=0 K=20 CMYK PROCESS 16.796899 12.109399 12.500000 0.000000 C=0 M=0 Y=0 K=10 CMYK PROCESS 8.203101 5.859399 5.859399 0.000000 C=0 M=0 Y=0 K=5 CMYK PROCESS 3.906298 2.343798 2.734399 0.000000 Brights 1 C=0 M=100 Y=100 K=0 CMYK PROCESS 0.390601 98.828101 96.875000 0.000000 C=0 M=75 Y=100 K=0 CMYK PROCESS 0.000000 74.218798 98.437500 0.000000 C=0 M=10 Y=95 K=0 CMYK PROCESS 1.562500 8.593798 96.484399 0.000000 C=85 M=10 Y=100 K=0 CMYK PROCESS 83.593798 9.375000 99.218798 0.781298 C=100 M=90 Y=0 K=0 CMYK PROCESS 99.218798 87.109399 3.125000 0.000000 C=60 M=90 Y=0 K=0 CMYK PROCESS 59.375000 89.453101 0.000000 0.000000 Adobe PDF library 9.90 endstream endobj 7 0 obj <> endobj xref 0 8 0000000000 65535 f 0000002856 00000 n 0000003119 00000 n 0000007055 00000 n 0000007315 00000 n 0000011197 00000 n 0000011261 00000 n 0000063214 00000 n trailer <<2C780593B9ACC84D8EBE5A09F6477FED>]>> startxref 116 %%EOF scikit-bio-scikit-bio-a3beaa6/logos/logo_inverted.png000066400000000000000000000261661520735541300230570ustar00rootroot00000000000000‰PNG  IHDRkç€/ή pHYsÃÃÇo¨dtEXtSoftwarewww.inkscape.org›î< IDATxœíÝy|�e™ÿñïõœ$] -«(nˆ2 ::#îÀXhÁ]iÑQgQ\~Ц@“´M§M›¤`@g´â2.ƒ¶n¸€–A�QVAÇ•RèÞ¦yžë÷Ç RJ·4÷³œs>ï×+/l͹®ë•Ó$ç{îû¹sw@ž*ÿ^Ùw󖦓ܓ×Ë¢¿—üpIÏ”4AÒzI�ÙO<Žÿ«÷œ…Wç;-@6Œ° &YÛE‹Þ¨ÄΔìTIãöì‘þí!íû¾¾ÖÖM©�³¦¼Ðxæ ,>¶Í­OŠ^=úGÛ;[´~ž¤ÎàƒH”÷‡IÖÑ×µ(qû±¤½j­tz°¡ Š•5™™ÛßÕë¦ó”:$@ €Bce @&æ]´ø5&�¨ÜÖ@u ‹° qbï–d�Êq¸¨{„5Ù0=/`5¨{„5™0÷ñËmX  �k2bce Ô=€l¸Â­¬9+k þÖd%àÊš±²êa @&`-€B"¬È„ËÂmƒ”ö X  �k2â!ÃÚÄ€µ ‰° +›Öbe Ô=€L¸´1`9¨{„5™0iCÀrÍg._Îñý ®Ödî¬iâÆY]u�° �WÖ´�7Ö@]#¬È„[Ø•µ¡’s"$¨k„5Ù0º²Vö}CÖ(€l¾fÍKѤ�õІ° î6¬Å¾_ÈzECX� º R‘M Z `k2EÉú =!¬€ºFX��$Z´ž³²êa @6ÌÆ5a Ô5€LX8¬‰•5Pßk²1ÜxeÍ k ®ÖdÂJ�WÖœm� ¾Öd¢eâÖÀÛ k ¾Öd¢|Fy£¤áPõL~`¨ZEDX�¥µáJÙája @–Bn…Ü¿R©ð3 Ô-^èÈŽiuÀj¥ÍãÆqݨ[My ‘ØjÉÕ·å@I�…+X s/¨<³Ô�êIt¬™¿Ð¥ƒ$m’üs»Mî—wŸÓy{Þs€tÖdÇýÑ�å,Š”tÈšyš÷‰î£“hxQÔTz›»še¾]´5¹é™u¶÷w]/ùÿëií¼'Ÿi@ÚØ 3& ¹ RŠ­.N„œ¹re©½qwÅwHönIÍ{ð°©’ýoGß’ÓSä„° ;�WÖâ¨öÃZeyeâáºïJÉÚ5úÝ-nþÕ¶O,:)�Ù@¾k2“„^YKTÓaíÌåË›7­oú–ÜǶJQ}væÊ•¥`ƒ€B ¬ÈŒ) ÖÌ’škûoxh¡ÌOk—žÿÂ?ýêø3€â ¬ÈNT º Ò=#d½,ÍXúw#[ƒHdÏU a @f"ÅaWÖÜk6¬•<PÈy“xU°Z k²“4]Y“©&ÃZ{ÿâ™.½!`ÉU×ù�Ö@X�™Í6ô— M‡­—�J¥2^ŠzCÖt·Þr¹<²&Èa @fú[Ë�IÚ¬ ×ÞÊÚÆ)¥ó$?,XAÓ›š'ÿG°z 0k2ã’ËôHÀ’“*Ë+ÖKÕ‚þ%Ï6W[Тn­ŸuÖ– 5@!ÖdËõpÈr›7ÖÎêÚ°¼GÒ>á*Úu=­ó¿®(€¬ k‰7ÕDXkë[òZIï X2Ž#›°(€¬ k^Ç÷›df~Qõ†á²Ï]0kÞ�¡ê€â!¬È–yаf5p"äÜþ%ÿ$éÕK®óáárÀz €k²åQÈF "dÛ²e“Ì|iТf]ËÎ+slêa @¦Ì’°+kQÁ·A6uÊuhÀŠ¿�°føâ€õ@AÖd*N,hX“[aÃÚÜ‹»Ž0éì�5Ý4·\.oYa @¦Ì‡5Ya¯Y‹†íIãBÕ3é†ÞÙ ¾ª(¶¦1>þ™’ö—4qä¿ûHjëPx\ÒFI›$­–ô'I[s�(;$*i?UŸ¯ ’&ç:Ñè KZ'i­ªÏáãª>žçP{áÅý÷ßÃ’Ja–LE6ü°{)`Åbnƒlèz‡™NX2Qä笗¶"þ?TÒ?¤X¿l•ôͼ‡¨gÓ®­¼Â-vrl­)žQjÚ°yüæuÏzð�µ+f¬ˆóži,N¼®óÈRlczm<ÜTzðº©å¿„š)/3WÎ,=ø¬Nn*M”l¼›í—÷Li)Å’•64mY'�ÛrÅ)åµ{[k4¿H�tª¤×Hz©¤¿•tàÞ6.˜­’~%éIwHú‘¤Ÿ©öÀöJ’Ž“4MO>g/ùûz²NÒ½’îRõyû¾¤ßç:Ñîý·¤ƒFù˜^Ií)Ì’©->ù¡mY²p+k•Je¼M.õ-êöÅîY n Z3]7ªú{c4–JšŸÂ,Ox…¤ËR¬ß6ˆ°–*óøÌkâ�ïT¸™¤Xã¶4kõGiúàÂuæº×MwI~·Ôtõ5ÓÊ÷æ=瞊û‘›ž?–¥8>GRØß))š>Xù·øõæz±¤›ëÅnz¾8ªyÜ–'?ÏjýUö.¸IR¬¡–&I±¦.”¤õ&ýÊå¿”ì^Éïmnúïž\^½«Z{Öþ^Õˆï”Ô<ÆÙ‹ªYÕ0óRI§«ú‚á×’>%éÓ’¶ìü¡…4YR«¤�¨ºúYï&©ú&ÂkFþü)I×Kú„ªÁ Ò×Úº©½¿k½¤}•¸ðÉ.}|¿U+n;æ3OÛé·«kÖšTMñ·Jš©ú j;s„¤UWl^›ó,£q’ª«„ç«1‚ÚÎL•ô=IWhô+XH]ÐëÖJÏÿݽ…Yå_Ð·ä¹’Ï YÓ\K–Ìž÷`ÈšPÃ^nn=ã¶4ß?íÚò¿æ=L#3™M\8W*Ý/Ù"I/Ì{¦S’4Uò¯LYsÈ�Ó®]ð´­ú; k‘¤ª®ÎÔÛ–¹Ñ:\Ò�%½)ïAöÀ;T '�Ò¶wФ›%œ÷ ØVØc·¨¹0×­ ›¨z=h ö›ñëâ‹ÂÕ€ºq€¹~úàÂOU*ÍËØ ×Wš¦ v®Põ2�P»e–¹Ž2�Oºfá?mû÷;û‡½@Õm�¨j‘´RÅ~·à’¾¢±S�Ž�ô5U÷O Ì4¬%MI!Þ hûÄ¢“$½+dM7?�£ú`—>vÃqq9ï!M)N.”tZÞsÔ™&7]zâÕ �}â/vÖž/©#»™jƾª^ UT*è»ùuçDIïÍ{T%�ïµæ‰çÖξä’qE—„­j×õÎ^ð­°5 .-8ñº…¯Ùý§!„éƒ _'ùYyÏQ§š­¤KO¸¾Ò$í8¬Í–4>Û™jÆÉzò‹"y‘ª[ ±k5’b½0KÂÞk-Šrk‡_(éÈ€%K’óÖ€zE‰ºò¢�,÷kN�¹ŽjŽgJOÿ"—ÄêÃî|0ïvà½âfOü­ª§›"w�oŒ�$¹ßßvQב’½šË.í>§óö�5 ÎM?ñºÎ�ošaN¾jÁs¥ ÷ŸéCÒÓ_à¿R¼gQÁ¼UÅ»ö‰o˜=÷Ö¼€d8¬™å¶²f’™ëRIã–]çÃÃ\£%öö¼g¨wqÉޥ⽮Go8þÆŽý·k¬:ìÞ³T=°¢(LÕ#ìþ�@’Ä«—Ì-¬µ,þ7¹Ž YӤʲóÊ¡¿FЂþ<ÆŽØÔ¼'h¥ ›Z^±ýÉ�/e‘s%ý>Ð@yú°¤7Žâó_&é¾”f­¨zìÑxTÒGS˜%kkô‡¾Œöß8RPòæ‡ wk÷|ÂÚü‹–ⲞÀeïY½Ï3.\U·J*»î§IúÀ(³UÅ8um8ï€ÝxIÞ4€Wç=@£H¢äï¶k/e�«$Ýhža-N’Iû,éîÉYŸ9㌭kâIIúnÞCHzé^<&Q1fG 0×@y‘WçÇKÑ”Èý9‰éoÍuTÀÚÜW5EÇÝÔ6i¼Æ=+ï9‡=-¬žËµ'䋳±z^ÞÔS5°ý<ç9Zkù±¶þ®- w�×�•J¥¥\.ª·[í-:YŠÞ´¨Ùö¶.¼.hM Ç­ô…ÁËwæ=Çž:áúÊ‹¢$î5rŸÊI3WVZVÌÈî÷A#i÷<¸^ͤÇŒSh^}�3qlUìEÛ‡µÑn§kTSò`“ò ñ5Ë™KÞ&=lÒs•´­“›–ô§@õv©²¼2QIÓ¿K²ìê¨Í YjÁuSË÷W*•7_é6ª�N;´ú€¡ýU]IG`Q&+<¶ßC‡ÜvÌgêzÉôÁÎ3%ûôتøäm)Iš0¶‚ £Hamß¼¨A„µ°À¿Hã$Él+äæ MHt'‚™w,=«ã‘�5 V”ËåÄÜ–…¨—ZšCÔÁÓ¹9¯¡²5iÛ°¶�8†sO) i–ZÁ r˜ôz /•2 k]Ó]ö€×­ã×$—­ 5fãÄÍ?Í{ìš9¯¡2ö”°Æ‹þ=W¤PËó6z¼+TxeÍ=ý•µöÞÞ)îúœÂþ ˆM~f¹\NÖ€šsã±½ë$mÉ{윛ñº3[“¶½f-ÜÑlõgƒ¤ÿ•ô“‘�›óç)¶¿Wv�ë`¦Uò’¯,ŽïoÙúI…>ÔÇü’îÖΟ­ µ‹7® ÌÜJ�¯×Æ®•¶?`U¿‘t“¤ÛG>~*‰S…€€B¯¬™tHÈzÛkï_òvIï\v•¶´œ¸&¨„µªÛ$ÍWuÕìVIkó¨–Ø*·€ïÎE魬ͻ¤û`É?¾²Ïêik[¾.¨„µª/ä=Ðh¼¤‡Bnv±·A&Ãß•,èÊ�K?ìmí\²&PC–Kz_ÞClçI¿Ì{Øa @.¢8Z•X¬ž+�°ÖÑ·ø_dööÀe×6»�¸&PKÜ,68®P8ü`�‹dkú†¥ÁÃZÇ@å07]W®s»æÌÿC𺵠qÎêǶa�ÓwPÏVI”ôII·ä< $�\«µ)`ÉIç]xá>¡Š�¹|y³{é«’¦„ª9âÚÞ9 ¸§lÇd&i¬7´N¦¬¹çÑóE°í6È ¹M„ó˜¤{%ݳÍïRà“Š=$ùaáêm~†¤ß†¨´ÿ†‡{%½>D­ml0‹ÿÍ9÷žæ�W�p\ŠÇz‰ÎC+f¬·ÇÈÙ¶ßës›Ø;%õIú…ž gœ¬WS|•¤ÃBUknö amä˜þÙcŸè©Ì|N÷ìòoB×€z—’“Æ^Åÿ{ì5€âØ6¬ «º%iBN³£õˆ¤sòcáI¬Z’DÏk�Ž�Êa²Òä“$ù÷zfw~¶;lQ¨ oúQå5yy¬uÌíŠóE±ýRózÖdÄ=dwº|La­R©Œ÷É¥•’ö4Ò.E%¶?ÀvNº¦}ŠÛ¸·¨ÉJ:bŒå~ß¼õñ¯‡˜ (ŠíÃÚï$<ŠÇ?Gµy­Û�ªs¯«¹‰Üò�ëW®1…µMSšþCî¯ 5ΗE\2k×MÈHÜ9}pá꼧؉ñ&M�kŠ›“µ.y�[I¹Ù‚+N¹xKˆZ@QlÿÍq‡¤Ñ¼P©‡¥æÍª®(> êA÷¨úu¸Yßð@Š<Ò#!ךÌFõfÓStôwµJú—pÓŒp}²§uÞ‚×€�;-ïvÅ¥�;àŸðÅÁ+_^ÈÙöaíÎ\¦È×ø‘�ƒ$½f›¿_/éÛ’.–t[suÏ{Ø-\Z³½\Ykë[t‚Y´,Ø #Üu÷VÛ§-t]À“Ü´âÀGKgæ=�†íÃÚÏs™¢˜ö•ôIï—ô_’þŸ¤Çs�¨7‘]YóÈFÖæ^ÜuDdÑJ=ýçáX­SI§õÍj y/9À“†$?ÿÚ»z\Î5Á¨KÛ¿8¹EÕ@²_³•IzŸªÛC§ªzseDÃÑÃq)àe£>ºFæ}ªûÀ(öïKv`¸!ª“˜Û‡zfÍÿUàº@½ø’¤[ób;æ=ö˜KúN\*ͽnjù~iqÞó©Ù>¬ Iú†¤ç0KÑ©ê¶Èã$q³E €!m}¸¤RÈ’{Ö*•JK2¹i¥drI’ywë‚•Áëõcpä�_Kö5·ä?O\ü@ÞÃYˆvðw}"ŒìÌk%}4ï!€zñ»çý¨Âþ¼9¸R©ìèçÚS˜d›&—>'ù {?á– k’Žê@#rI?ŒM½fÚ¢¿¹fZe!A �dG/j~!é’¬©!s%5ç=PV̘K y¼tÓ–ƒZv{�´¹ý]¨z=jhò­ñ»ËåòP µ ™¤7%‘®Ÿ>¸ðÁ“®YØâu _’÷P@Vvöt»¤ë²¤†#éFI�¥8WѽT {„а…]Y‹ž¾²ÖÑ·d†d_ÔžýÌs}µ·uþ’Ðu{ì_öì�‹óHÃhnû°¤/Œ|<áY’�4QÒUo$]«ïlœ!iú~îIGHúezã�Á#=b7[[¢ƒ·ýs{ÿâ™2ûªÂßôZ’®ÝÐ<åCÎvqÅòÞ$Ò¯óbgÌ“qRiJ”$‡Iö27�*éyc©é¦�L\xÓ5Ó}%Ì”@1ŒõÅ˃ªŸ›HNÓž‡5‰°a‰–…«çÑ“÷Zkï_üɾ¬t‚Úm¾µå·žµ%…Ú0¥{¯=¡|gÞSì)“Ù‰×.üsÿ¤ª {ë¢ãnj»üÆc{×…š È[ð-A drÞõÀ£°×¬i䀑¶þ®•ÒZQóû¢¦Ò©½sçò‚ÆÈå>xbå ’}pŒ¥·¥åcA† ‚°¶÷&å=t ¤ù’Þ,éÙ9Ï‚½dö4H¹ÜÞß5ˤK•ÆÏ8ÓŸÍ’“—žÕ6d@ƒœ¶h…¤;ÆRÃÜÎ4P„µ½GXËß¾’º$}_ÒU=ôæFIIú'I/Á^4…=`D~´¤¥óóí¹¿±{vùÿR¨ Íån²ޱÌá'_Õù‚ �Æu�‚°V<ûI:väã %Ý%ég’~>òß»$mÊ|:ìØx=¢¡påÌì pÕžâɧõ´vÞ“R}hx‰éWc=t*‰ìxI¿ 2�3VÖöA·6L”ôI‘ôiI?‘ôϹN„§èþxÇjI[óžc7þGÑôžÖλòêÜãj P„5¹9öþÑ¼çØ…Ç]vʳæÕÌÉjP«Ü’xì5žz  –ÖAQÃÚC‰E'ô¶Î¿-ïA{lß¼BmXkß3iuÞ3lϤßE^ú‡e³çý<ïY@cÚ]X;TÒ UO×»QÒIïN{(�Åå kþË’ÛñKçtÜ—÷$ qm{HÆ¡’ŽÙæãuªÞÇ ÒeÑcò1ÿŠéö¨ÔtJ÷Q9k’ôI¯”ôŒœgа’Õ’å=„\ºbbK|zùc Öç= 4"óh\õÜ)R5¬�š÷œG�åþËÙõ©ß>÷ÈY+fÌóId€½%ÉAnù¿yE“¤XR)ïAjP’÷#Š2G-áÅxÁ¸’Õ–ßÊZìnçöΙ?�×€*7“÷ Ø97�ÇzÓrŒJÜ$i£¤IyORƒÖå=Àˆ yPƒŠòÜaDާAn�ì}½sæ_žSÀˆ®¯ì™½�0P\æ¾¾—-4�u‘xặŠòu+ʵ„¯YÑDþXöMí~É_×ÓJP€¼™ÌJqÜoÎ ­‹Ì<â5T¶Ö6‰®{«(_7VÖF¯(ÏF˜lu¦o¤ºnÞ ¿¹vùñ,ÛžêÔ+Ï·µyÿ©Ó¬³]ÒÔ5ÝŒËRâækCÔÙÿ±g|ø¤Á…õþ< Æº&IA¾è ¨(§Å%¥¸´..�ý÷µ›ý{€q .ÈvѵM’þOÒ«BTk0¿Í{€¿Ï{€ã*Îs‡ÃñÐÚ¨)ësŽìhsÿÊæÉ¥¹íKçõÌž÷ƒŒ€´œ–÷»’öi�núCª XmúƒÔ’÷ ÃMh’t§¤£xÜ I/Ng¤\½fŸ;,é—i 2JwíÅc¦Hê =H&ïÅc~'‰­o³Ï­Ý”Ó†^—^&O¾ßÞßuMëŒ Î]@˜€%~wÞ3Ô««§÷¬™>¸ð!I‡ä=K#0·_5Iºc”�{óÈG#»OÒæ¼‡ñ€ª'zŽf Á$IméŒSx?Ï{<]ùŒòÆöþ®­’šscz©¤;ÛºæMXŠ­‘P“Ö7o]ó?yQçnY nº5’ô³¼©A£ ¸iŠ%Ý“÷5„°V\E¸Æ`_¹.Þ<¹t}Ç@å°¼‡ŒÚ×®8åâ-yQçþ;ïD’DÑÿD’þ¨êVHì¹+ò`;Wå=@ ùnÞ`§Šrh�\:Þ½ôóö¾ÅïÏ{ÀÛjî}yQïÜü›yÏÐ ®¿njù/ÑȾœë(µe�Š÷‚ÿkªœ�]»K¬$VõF›…2Ef_nïﺬu ²_ÞÃvÇ.¼zúâ_ä=E½:ïaÚ"iþñ7–ÞöÝ·”7æ=L£Ù8qýb;dh‰›>rÍ´EýºFÛ}ÂÙ’æ¨z<žô IÇJº%ïAvã‹’Þ)é/9ÏQ$—Kz�¤Gò»•Ó�ÖFíï“(¾½½¿k–IéÞÙ°#[%}ÅT:úši‹–r«•|Üüº¾M-C�Ÿ$ébUïAŒ±ù�›Ÿ2xâ¢K·ýËíÚ$õK:JÒEâæÁ÷Hú¨¤—«XÇõïÊå’Ž�TQuÛf#ŠU=±sº¤wˆë1k‚É6å=Ã(Œ—4ÐÖßuUÛ%•çä= 47év7o�’Òa×L[ô�«§•“÷P�îŠS.ÞrÍ´E³¤ÒË%ûŒŠ¿K¦€üç’>—JG�l/}Ц�<ê’fKš+é$'é%’^*éE»x\-[§ê Ú]zòÀŽ{s�hï=.é|U¯¯{�¤T}þ^<ò1.·ÉÒ±JÕçìnUO{¼R¬¤ÕœD¾©—©¦[\º³½ñÇzZ;¿–÷0P'Ö˜t¿K¿–ì׿ÉÏ›·Æ7\qÊR~·Ô5ÓÊ÷JúÈÌ••³=pø8I¯“ìhs?J²£$MÌyÄ¢ø³›~%ú…LwE±_ý£7.þí®°»Ð5$éš‘�'´H:HÕ/úIûJjÃÐyÙ êvÏuª¾ ð¨êXÒÍ#O(I:XÕço¿‘ÿŽÏ~´1Y£ês·AÕç­7S­÷jô¡ùþ4)ŠÈµÑæµÕ’Z�0„ã ÷IDATqG\ûKvYû@×»†<þH_k™•ܪ÷¨úûb4~�Æ ôu�~·FœÆ (7?%òî|ªK®(N"_Û¼µ´AÞ’D[W_=½§¨çìûWó±•(Ijfñ`ÅŒò�ª‡º]ûÄßU*•èú7耦X“]Ú×mëøÈmr~SfÄ5—l�äëKqÓ¦(Yÿè�ÞxÁ¨/ù0÷zË'jQG_W›[¸Û+˜ù‡Üõ6ÉÞªæî¸ô—`Ykç�³ê êWüs Ø’À׬¹ksOkç;äþÏ’2¹á¶IÏ�dƒ}]çÏ\¹²”EOP¿k Áäañê6ïž9�_Šc½Ì¥›‚Öß¹’›Ê‡ÿñ¾«ç,}VF=@"¬(�,è-C,zòšÜ Î]ðÛ‰kã©æjWõÈç ø ±'w´_´èälú€zCXPaWÖ<±§lC,—ËÃÝsôF‘/YV‡µ¬$º²£ñEg._^‹1€Ö‚) ÖÌwŽ–Îêü‰om~…Ë–‡ì· æ²³ØððÕ ú—<;£ž Ö‚) º=ÑÌvzÀGïܹëz[çŸin3•ÑMÓ]zðügm}‹¦eÑÔ>€¢YÌ|·÷‘T÷œù+“áø%’_²÷.lý¨£¯ë|“jðà K„5…à± kÒîÚ$-;¯¼ª·µóÍ&�«l)¹©ÜÖßµ¢mÙ²Iô5а Ü®¬%{°²ö×Þ’w·.ø„Ë^/Ó!çØ…Ó¬yèÖyŸè>:£~ ÆÖBäIFGêï\oëüÛ&”âWHZ‘QË#“(¾¥£oÉ»3êja @!Ä¥R²ž™ïÕ Yù¬òÚžÖ§›ù™’¶„œi'&¹ùʶ�®ž™+WîôPÐxk ¡y8è6È5[,¹j,ºgw.·Ä�Íh[¤™«íüÕ÷[*ûeÐÔ€Bp wÀˆ™ŸÛ?»üøXëtŸÓy»¶4#ÓÊsíŽIoç¥[æõuÿMý@±Ö‚GC!šKVîžÝyi€Z’¤ž¶¶5=³ÌÙ™ÅuuG&ßÚ>°ôÍôFXP[“¦±¡‡ÍíôžÖù‹‚ ´�îÙ�Ëù4I«Ò¨¿�Éòäò޾®¶ z€‚"¬(„Ië‡ÿ$iý^dÒ§%5¥ÜjØÌ?Ú=»óÒ”û€1b$@oë‚Ï)JÞ"i]Ê­šÜmyG_×ù)÷cÄÊHÇE‹_å‰}Oío²OŽ_;<‹{±PL„5(˜‘£ý¯�ì¨ô»ù·'¬Mþ±\.oN¿ ÂМþÊãTúŽKÇgÐîz 5¿£§­mM½À"¬@A�}É%ã&¯ù¢¤÷¤ÝË]w«9>¥÷¬òÓîö a Ì$›;ÐÕm®¶ zýÎ’Ò›–žÓñË´{€Ý#¬@ hïïš%©OiŸâkzL±½­çœù7¦Úìa jDÛ@×iæú²¤ñ)·Ú˜¸N_6gÁ÷Sîv�û¬@�è�½àîv‚¤GSn512}§½¯ëÌ”û€] ¬@ é�3ÿÉßàÒRnU’éÓm]=)÷;Á6H¨AmË*‡Zs釒þ6õfnŸŸ°nøÌr¹<œz/ðW„5¨Q==ûûøáïÊu\úÝüò!íûÞ¾ÖÖMé÷a jZeyeâæ ¥¯»ô– Úݵ”Þ²ôãi_3DX€š7såÊÒ þxß¿›üŒô»ù½M½©kÎü´¯™ áÖ ˜dí}]e7•3höçØ¢S.˜5ïÎÔ{ÐÀkPGÚº>.×ÅÊàæÙ‰ûÛ—µvÞ�ja êLÛ@×;Ìu™Ò¿yösû@÷œù+Sî@Câ>kPgzg/øŽ™N‘´&åVãÜü²ŽþÅI¹ ‰°u¨{ö‚ë%?VÒSnUrÙpólÂc$Ô±Ž�Êaî¥J:2ƒvŸýÍsŽüèŠ3â zP÷kPçæôWhVé»&›~7ÿÞ„}’÷”Ï(oL¿õ�° ã›gÿd8‰ßrá9å¿dÐ €ºEX€‘íͳõ •â7õœ]þ}½¨K„5h &Yû@×bwÍÏ ÝŸäþæž9�wdÐ €ºCX€Ô1°øƒîöIM)·Z/‹ÞÓ3{ÞRî@Ýáè~h@ݳ;?漣6¥Üj_yr9÷b`ôXY€ÖÖ·äµfþ}I¦ÝËä�_›´–Ëå$í^ÔÂ4¸öþÅ/qÙ•&=7õf¦•ÖÄÿT.—7§Þ €GX¨mYåШ¹t¥K/Ë ÝÍÃIüvŽö`×kIRGOÏþ7|¹KǧßÍî7 ŸÒÝZ¾?ý^Ô&Âà¯Î¾ä’q‡×|EÒi´[å²·ö¶Î¿-ƒ^ÔÂà)2¾yöÉÞÛÓ:ÿ{ô ¦Ö;ÔÞß5KRŸÒ¿ÍKìòÙ½­�ŸL¹5…°Ø©Ž¾%3ÜüK’Ƨ݋£ýx*Â`—Úû–¼^æ—K:(ƒvßÒ>ïïkmMûfÝa °[ý•¹JWH:"ƒv·DM¥·-=«ã‘ zPX„5À™{Aå™Q©ô]™^•A»{&4ů/ŸU^›A/ )í‹ÆubÙyåUq2þ3}7ƒv/Ù—>�A ‹°Øcœ{}ä»L–úÉ�–Ø_Òî@‘Ö£²bÆŒ¸»uþYr;GRZ'7Þ2~Ýð7Sª @Màš5À^ëè[òn7ÿ²¤ ¡jºtS´¥é­Ýíí�…ª @-be °×ºçÌÿfd>MRˆ-‹ÜtþĵñT‚¬¬è¨î^ºBÒ‘{ñð!—}±Éìü%³ç=z6ja ĹŸ¨Ô•¾áÒöàÓ“nJܾáñðŠeç•W¥> 5†°Æ$kë_ü^3;]®—»t¨¤Í’Ö»ô&ÝíÒOš,º‚U4víÿ›Ž ð Ë;–IEND®B`‚scikit-bio-scikit-bio-a3beaa6/logos/logo_inverted.svg000066400000000000000000000144751520735541300230720ustar00rootroot00000000000000 image/svg+xmlscikit-bio-scikit-bio-a3beaa6/logos/vertical_powered_by.png000066400000000000000000000367711520735541300242520ustar00rootroot00000000000000‰PNG  IHDRèۦɻsBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î< IDATxœíÝy|\e½?ðÏç9g’toZ -ˆâÈuWT  à­Â4EÔ{¹*?�¢Ð–-„® ´UÜÀ» mÖ‘EP‘ËV¹Èu¿²Š(Ph Mº'™sžïï�™´ÉÌIrfæLf’|߯W_$ç<ç9ß É|çYÎóPD ”RJ©òbJ€RJ)¥²i‚VJ)¥Ê�&h¥”Rª i‚VJ)¥Ê�&h¥”Rª i‚VJ)¥Ê�&h¥”Rª i‚VJ)¥Ê�&h¥”Rª i‚VJ)¥Ê�&h¥”Rª i‚VJ)¥Ê�&h¥”Rª ¹¥@eK$ŽçyÕ¾ëÎt}¦µfº8²Õ³qOgç«çŸ~²Ô1*¥”*.Žöí&[['‹‘¯å{½<ÛAl‡•í$·ØNÁVÀÿÝsÏ=÷Lcc£�.âl---Õ¤û g…Çò>±ÁB°à+€ý_¶=ÿÌ3�cKkG+ ª3îòD}íükò­³Ok{Çu¼;èœß;wÁ‚37TkǧÅà‚…¶{beÍ>ó™Ë&>,F ¹_>Äâþ†ºù7U¦µµc¾|¡à{ „D7Dv¹ƒ‚¶ƒò¬ùmmmí‹…ÔßÒÒñ)8¸°Ð8sE‹õuuó×U¦µ=qµ@>’såB ‘m tìÁV�F°`§ëâÿâñøÖ¼ƒ�Xk{ûç¬) Š=°è¤d)/[c~Õ�?ƒÔûKøXZ;΃Í<.q)—ÔÔÔ¶¡¡a{A±hiI¼ŸFn… *ãÔn±üøXH΀ŽA‡1™À?SxÏ¡‡ñÌúöö÷Za[[ÛÁ-íw ý§)ø7 ¬r€ …òxK{ÇOoK$Êéjâö€£3<((*û,IΩۢ¶�ê‰D Ÿ 8ÕQH½c\5 q#üMK{ÇO‰Ä¬R4 8>,"MÆ—§ZÛ:þ£¹ùŽ7•:¨È ¦ ð¡<ÚÜÖqo{{ûÛ‡»äøã�÷bæøkÀéÃèÆÖ£_;( ‰DbŒÜ d%gðœúúøo¢¼_)i‚ÎÍaFøxkkÇ9ùVÐÒÞ^kiþÁ§1ô/®ð7€÷ q�x�çtz•àS®•?5·v|.lL½{öÜ`gVU”ÓÂÖ‹ —€?ÚÖÖvp¾Õ÷Z{<€É™w5°?Ê·ÎqEð©¤�‡[[[(u(£ˆ#ÀèxÏ·´%”:˜b!pª'|l]{û»†+�Ç·RüÓ‘NHðé–¶Ž«£ŠkÆ nÒ—€ ÷�% µñ;£ºW9õ]܃¡ `g˜²–˜lÄN·à4ÓTCpˆÃŠW ñŸÍk˜?ÿ—aãI$NÒ“€Ì3é#àãFäÛ€ÿTOOÏsç�w^`"N$IkçA̹€| ™ãÕ‚é$nmiï˜3¬�ÇãÛ†Ší¼óÎënnëø�ù§N�×Wkkë sÂÀ£òw€oéw€¾˜ù†Ÿç|¢¶¶ö¥œj¹0/äÃð¬Å+ù^ÛÛ½;çÞ•ŠŠŠ ‹Í1f[b6!p²?Ì�£ÎC÷Þ{ïûN;í´ž|ã¤àl€»ò½~8¾‹¿äw¥‘}Fn­¯­¹®ÐúË͘MЮˇãñøðcChmM'”Û¼5ãTŒëÖ­;lÁ‚¡Þ”’¾½y°äLàO\^_¿'L]ñx¼Àî¸í¶;gº½×üYŸêõ¥-‘HÌn,Ùnf%èc‰Ä¬x<¾%L\ýY:g3Õ5¸/âÿQp7úý“¬Ež š©^ˆD$çîmóx}}ü÷ùÄPlƒ}HF7€NO§¿oinn^D'öE×!óqäÖ®í_°6ß8{z*<ï¼3ºò½¾Xf[}]üçù^ŸH$&ôzò‹ì—qš"r}Kkûìúºš¼'ªFÄ«+àu¶¶¶%pn‘ñ¡3]_®®Žsjãw·¶'®‘e§Háú––Û�­¯?ëù|cliKœGà«Y'¿ˆ¹æßò­·œi÷êêâ�Å~Äÿœ>Ðu+Buu7·¶_ð‹§^xîs~æÝuuóC%çLçž{æõµ5_…Å©^Í�ç3�Wð¸‹%~’Ž%‘YÞøÃŽUg3nvëüŸ††Ï¾œs]ãHCm¼ÀͧöëõýŽt<£E<ßÙP3ÿB7�'ä[‰DbÚ‡©óÏ??i /àežóÅœ¶ž]“'~àï²NG&­Üšk\­­­Px€ÊŒúº¬Ãyçž{æ¹Ö9Zh‚¡¾>þ$À2� pô-·Ü2Øóʸå–[b�Om‚uçæ:V:œsÏ=ó ßÈÙvgž#ð�á&dÑÍææ'›ššrú=±05ȇ’€xÎíÈjÁ1ç-"YãϤÎÞÀ�c�FxäHÇ2ÚÔ×ο"ß 85'é˪(bçÄã‘ýì2qtØ:Ο7o·ïà ÙkÎjmO,[×-·Ü:?�9kÞ±g—ú‘·bÓ–Ø?5««ßp0iÊ´ šUpU}ýg‹2)iAMÍŸDð•€S1_t|/×å=2»Šö;ôÐ#CuoíŬǧ¶îÚ¶íH·p3»¹� 3[´Okkë~>œqX<íÞ!™tÿ7ð„á ¿ËjŸêéS Ÿmÿ×1ñØš0{¨L�ÓsÅ âñPx²ßO "Ë[Z:B �Mš6}-€ã²N�4ÔÖ>˜KL£‘&è�$à1¤ôñÁ&_䢀ãÏ4{ÿÿŠ.²l uó ëM˜ä¿Üzë­A3R©ÙÞÌþ¥7ỹ×'ï€àý�Ê�ý H{Ö-løg¢…îiÈþÝýå¹ñxÞ³¥Ç“X¬çÍAÇ­ì�T¦†pÚi§õ@ð­€SŽçÙÓG< ÈÙìß�ày8Cª«‹?&@öäUÀÀ ¥­­í�¡®oiKœÇàÆÆšúšø-¹Æ3i‚‹ Z´ãõÁ?hno?†Àì€zn:þøã³Æx¢F‘ÿ8¼_å„ uÇû Z´äÔ°÷ O¦˜ Ù÷c?BƘ~z6wXYãϲƶU0¡ þY;vµ.•’ì©ø>´[ò¬„™õííïèõëõÞ•O} µóÈ·NͰ0­6l|’(Õ£&ßÍ>ß<ÿçg¾žO,£‘&艄ÀçA<9Ø5þsàqk²Æ²‹ÁuM€=Y'Ä ú6P¼#»Wà·ÝvçÌpwÎJ´[\õ?pÎ9Ÿ}À£åÞf¦hjÌ?kf¹.NR[[Û{EU!ºÒk1«R�”ÉÝ™Ç ÌmnnžZŠ˜ ÕÚÚz€ó_Èx<À÷‡{z(Î>`!œúЫ›6/Ï<˜H$&;–?BÆ ‹þsPWì½ʉ&è’¾|ÀŒÌã5ÄeAÝÂëêÎz6²À†�Ç·¸?ó¸@‚_Ù«®®îu�d6±X2hIÍÒŸz�ʸã�‚žÁfÀóʃ¶ìú™4uêÇ x$øXmmíÆá®ïZZ:N±0#pùU¹9n”0Þ‰ (iÅÄus~l°”š››§6·uü«Ðù ïíŽà†˜Ã+ ©ÿøã�÷¼d,HÖ¼\ÚÚšÐC—ZÐià"Q¼FØOÇãñÀ¡Æ±jÌ.T6·v\Bfì–”²•â5–œ¹¸ æ¼9AAˆÞr÷O$âñxvëºï2‘Û…ðXEúq«Ö¡n糺Ï3»·ûx^Å�œXò[è÷i]5.ʼnÂÐÌËÚ€MlaÝÛFNiiogAu bç¶m·—báþD"1Ãó¼7Yc2oòs0Ák« qsCMÍm…Ü/VÕûÙ–öö¬§"Ð[_SsGê-˜^ úE5>³‡¶Š¯ª¥­ãšá ‰ÈDCÎb…3˜A'ö6îÀŸ¸æõ^Ö¹çžùƺööÓÁÿ`àŠvÊmë×ßñîsÎùì«-í‰/L2ÝCËÓkë£}êe4Ð`ݺ;÷w+¼/ˆÈùdP¢…ÀbÁ`¿0‰DÂ�Õ%LÈ?¯Ç—‚r�ç™·´%ïºæŽ¤/7a@ OAêÑ©¡ZY™[à½úÜsOgve,8ssK[Ç#úxÓú¶¶ãΩ­ ¼${õ0›Ó.ĪôÖE‘«¨Ø¿@Þ+l5·%r&d?¨P0ôK#~6cꔋò�o_5ø�"ý ·!µj^ÙáKA«é‹ ˜{R|•†ÝJ•Lï—'€ ú§Ì?àòÚÚøO£ pAMÍŸZ[;q>†9˸ÞúæööŮɸL@ù\}ýüA‡Dz1› “ž\×ÜÞê“-¦8À pb˜!2øF"r]C}MÖŠ;}º»Ý™N,™5| Àˆî)+°/ïÇaÁ :�¿ÖÒÖñ8>Þ°KKâ}ƒíÓÜÞ~,ÁÌÝoCŽ‘í9qà!S‹ìñi©í9A ¼‡à±ô˜ö˜DHQ༴¶&Ú7áñD„/mkÈ9%'Jñi¹aÃ7ê ­uuóïjiëhpmÆ©)|™‹‘W××ÔŒÛ  cw š8—‚ óD-ˆ@‰TËwˆ¦€ÜZáš+‡ºuEEï`ªBmÞIµ>²�;eØkE²gsñ¸“2°�ÝÛû®ñî@ƪEœ=èÂ(Æf¯¦‹“äb7ÁGA~å ÙûÿSÔ-¤ñÆuí`É+s’Õ(#Ÿ¥ðž�¯m~¥¹µãkˆx»ÈúÚùË€ì‘ÑÍ.ÀúTÙñk̶ £Ç§`å²ú!ZÎ}Œ1›|?û“5´›P‰Ù/¨GÚˆüc¸K­kîp|ÐÝ$ài‚þ`2s£�—jkkÿg¨{ÔÕÕ½ÞÒ–x(cOçýß~øáE@+Z¬ÌËx«°ƒ Ë q¥8½½û¹¥]#˜¸àƒFü'fÏžýÅzÄO€V°(EáõJ1Ƶ#á‘3ÐKle¤‡²=¬df„Ø¿oÇ.Jª÷0(ìO↖¶ÄÇz»cçE¸Šìœ<á¼É»v Á{)óËÓ¦üKD÷µ4Agól`#À�"ö¶£®®î©°Äãñ­-í]Lï\Dö�>ÜÁ‘˜4Ì”LVûÈÄ‚xü-mÿ àØ½õA>ØÒÒR]__? '`}[ÛqfÀR|ée7ÃÌ î0`†¸ž�Œ�H$f€øhƵ�ºcÀçÕueº›•� šk+Œu’Sk¦Xâ ÔV¡òÏÈì"|�'Çy¶˜Ïß'»+¾RŽ»Y“ñ1#xØ�¯�t,ºëkç_“çµlkk{“Ði±_ÊØ€œ^YÕûè½÷Þ{L![’öwþ¼y»[Zî8Æû€êŒÓ/ÅžÕ½F³±› É‹!Á]¼ËYkļáѾZiÌÆ§Ÿ~zsDÏÙýÈXQk„Ǧ9$ Cî^°àÌì5rƒÝŽ~ €Cº'#c·ÒÔf¦b‹ìÕ‚ÄÜ™ôñ=ôß‘8À€íûz}œš¹}eУZcMmmí‹!‹¶·´´TÃÄn¤ÿÖ€³|£×—¯µ¶v|¹®n~^ N¨l©½¶³ÑHØ¿¯r!é}V577—n¬‚O (¼«kÛŽF—GuÓúúÏþ½¹-ñ\ö< þ6Ÿ-nÇ¢1› cí‘´®ò$‚¿23A >šH$*Flk4ÁIÇ^ {¹ux»ÉØ ý¸ÕÞĘH$Jæ^±òBCMMðzÏâñøÖ–¶Ä@ÿñm¾­¹9qtCC|ïò‚ùtf÷6` ïÞCÒ=ó[Ú:.°ý昘-D¢µµ£¡®nþ˜ÿ`3B2÷N_’ÉÀ‰”£ACCÃö 6œþÊk›ÿHàˆþ縴½½ýÖšššçJßx3v'‰•Á{ONŠ||$î["q�YPˆ ž!äœxü/þ0ð(¬âÕkí\¤Ziûî!¹MÜ’€µ¹éÈ}_' Ä€ûüE]]ݦ\î3^Ô×Î_AÁYÈÞ6Т¥¹-‘ù8œÊQSS“aÆÐLÚo¶�x@:þøã=R‚&º¾˜��x@ã˜&è"©ž6¹@v7�•!—ÚŒŠëKÐþÏâ"p«¼AIöÚÜsZ[oß»¨G: 0Øâ$ƒIöTü™Œˆ½›x>€Œq*�½=´ººùw�¼0à”CHskkÇpk²«!vØ‘CÀZ@à’–£N̘A>ÈË?�l$ã›&è"IOp¸9û ë¬9]ˆD"1 ‚KîýóšššœÖ[–€YÒbìÞ®="cÍqÁŸësœpuÞygt�¸/£ž÷$‰É ÌZ{Û÷{]íÞF}Mü{@ð®KB¬knKÔ�tLc…Pš[‡òŸ#LLžÔµmÇúAä(@j•.8õ˺ºxÖæaˆdvsËñH}ÐÈÞ±ËÍ­{»�µÉ»t8hðáD"1ƒ�þ3ɵ{;ñxÜïžPU;È~¾.a:Ö¯¿c´¯|5bZZn?” 5ø}Âý­�NFæ·2"›ý¨MÐEV_;¿)µXÄ@œýŽÃ�øáºuë&Et+¶´u\ àšìSòw?ûl¾;ÌZUlÖºöö£ðGLàO©wøyÿc"øP¯�“1ð÷Ô·ÉXY®Í\®¾ð™Ïìð OGÀJvf×K¤¶ñTCioo;Œw?R { "«jkkW‚°"×Ò’øÀ†€S{\׌Ûe7KAtñ‰ßÛó9Yã²Îqb•¿-tL:‘HÌni븩Gk2m§Ø.¤K8õÆ3p«8G8?«e äÕzî“ÝÍ-"ì©¥6h÷vîÄãƒÅ9^<棓¦M¿q¤c-Z[ogk[Ç­¾ð™ìE<µkǶ 1éQ§¥¥ãS0ò²�·ÅãñÝO`¼³ÏA—“ ìZ—Hœîøò(€7gœ>ÌÂ<ÙÒ–¸ÛÀ¿¾¶¶öñ°õ¶··¿Ý/¡à<ŠxB‰×׆_mp¼À×û¸™ð¬SP‚v]Þ“ôeö­É»0p Qºµä8V_?ÿg-mËd=BCÁW›ÛO4ÔÆ[JZY¸÷Þ{+;;÷Ì'9bæ±s„f.(g`°Æ qOτʆókG~KѨ´¶ÞþN¡?À<‡àµÄÿ–ÜS±x„C÷4A��ñø?š››�6Nl�_È8M@N·0§·´u¼ÁÓ ž𠞆ç¾×{}9B€#@s GÙÒÖñ2€A³Èoövp=Ìz¶:u i ÀC¢Ý¯'›°${gill´­­­õBç·Î8=‘ŽÜ‘H$މÇãÃ/“;-öÏÐ�ƒí7”*‡Gˆ`‡�ÿÚP�èw>&ò× Äÿ9�3ëkjþyÝjX:]õõó뽋ÀJQ=¶Ð ðÇÖá»ëkç7a9Q0hëu¸­%ÃÚ9iÒOì @goG¢®®îuXž�àݧޑ´²o18t¼”ù1—”YrŽÚnÖÃàäçŸ}æ=5šœKF[Ð%’^7ùrW´tt| VÆ09c»AÜ+Â;à÷þ¤èK Ü‹ Õ©žÌaS‡!�?oÞî–¶öŸÌ\ŽÒ3âßÅ=P_²µµ}¡�ßÉ:)øtK[Çãt/Þ]€l¸ àf¡¼f,Û3©êÇ_øÌgv”:¸ˆuØb3„›!²EˆGz&V%Æàk•F}‚Ž9¸Óóœ'²ÏØÑ²ŠÔÏŸÿ ¿H$_M&q4)r ¤á�ì/‚.¼f­¼Jƒ×@nŒ‘ÿ�Ç÷ŒT Ï?óÌc‡ö®#²Ïôf=¾Sˆ˜c¾âyæšþÇDØ[W?¿ mü\—xž ˆ¿ø(CÿŒ\ƒ[<ÏÑ�¦êêj¾ÛÞÞþ€µnVOšü k’Ým••þ†¢Àuì�³÷=Ä<'¯‰Lžk{ÐݽyÁ‚�½7å$æðFÏ3·æ{½çÚždeåëå�„i�R&ô?–tmÉã* ³e¯RJ)¥F’ŽA+¥”ReH´RJ)U†4A+¥”ReH´RJ)U†4A+¥”ReH´RJ)U†4A+¥”ReH´RJ)U†4A+¥”ReH´RJ)U†4A+¥”ReH´RJ)U†4A+¥”ReH´RJ)U†4A+¥”ReH´RJ)U†4A+¥”ReÈ-u*MMMfÆ fÖ¬YfÒ¤Iæ�7Þ0$�ÊÊJ³{wÌTTì1®ëšž׸®c<Ïce¥O߯ ãôß�ÑZK?æÓIcc–1£µ>�1ÆZKëZºÖ¥çyÆu]Zk)bé8}ß7ŽãPDh­¥1ƈXZÇ¡c-}cŒc-E„â8¤O#ŽÐKkãk�t}BCŸÖ8bR×!-�¡I#iúÎ1´´¦ïLªŠú¾I×™þ^R߀ÒR_ )FÒe@¦Ëû#{ï#bÓ÷µ�é{¦îŸ® †Â}e‚¾ïûºï¸�Ù{=(d¿2@R@`’úš¤XXI_"}e,ìÞ¯)©2™ßï­Ó¦ëå¾2°Ò¦�§Ê�’ª›Ú¾û‹X"õuVÙcß½mê}×Û~÷OßÓ¦^‡ˆØÔµV8È11bûÎù´âˆ±¤ß§�F$õ‹)ÆøâÓ}Š8béû©kŒÇZë#Æ÷…4b­µÆ˜ÔyßÇq¬Ÿ>gŒÏóÄu]ëOŒ—:–ºÆ‘¤IŠIñcÖ:IGŒ1â8Iñý ë8½ÒÓãˆëºây¾­¬ô¬çy¶·w‚�81i{zz¬ˆø3gδ»ví²[¶l±Ç¼mll´y¼]¨Q‚’ú;q'œp‚;kÖ¬XOO�ëû“݉“®ïWº¾ï¹¶Âw+l̵Öw�11ëZk]q×±Öq\q¬ëˆ¸Ö2&F\#ÆF\ãˆ+BWŒ¸´Œ¥Ž‹kп] \!b�)FRïãFRï°„C�ˆi(0pI—ƒ!ÄÆ�ˆaBÒå�:&0Hõ\8�ô1ÀýêÓeÒõQö^GÀà¤ëèÿO)5>ÙþÿøÒ÷=a!´€õ¦ËˆКþå$]ð÷]+@º- ér©ú´X°_}„…ˆ%h…°"©:)´ XV„>D¬>I!U>ÝBwúZó©ºh�ê%IBú¾‘êÞ%R÷L}Ïô±~_H]“jÑû¾' L}™ùuºN0u¼ÿýúßgo¹Pÿ”ê#!ÿY�€écL ËAÒÇ÷}-©_ìå˜:)Yu÷ÿº¯NBDÒu¤ºçÓõQ€tK³¯Õ øH·T‘nͲ¯µÛ×Zú©–ìÀ+Ÿ€•¾V¯¤[½€#–B Ð+éòfï×"b)&õµkÒ׊ˆc,>E,Lª5lÄXéWÞì+/ðG¬µNꘓ¾Æ÷=Òx$=/Ýꪵ[YYéUWW{·Ür‹'c%� bÌ$h5>‘ä5×\çžzŠ[¶láa‡ÆÎÎNîܹ“pwíÚÅîînöLŸN˜ÖÝÍžž&§LáäÞ^&“I@29‘'&éy=¯ŠPU•úÚ÷=VVzôýJ@ÿñ{ß÷YQáú�ãWØXú˜Ïþãù¾k 1›Ãï×·6uÜZËþãûÐl¿ïë¾²â8©1hßcÌÞq]?ý}ßשãûÆIûÊc¤ÿxiÒxŽg¤ÿ¸©ã8½&)ýÇO ·×Çq¤ÿ8j*îééqÅq\qÝnéîNwÝnq]WvïŽI,¶[ ‹ÉΊ ‰íØ!•••²­ªJ ²«KªªªdÒ¤I²iÓ&™ÿüp[d*¥THš UÙ+o€ Wvgr/¾îºi¨è½àG¾ím�7{„[½ksÏâµË± W-¼ê©‘ŠG)5¶i·*;³¡»¸Á‘iA/Z}í\T$_x5€“yö}À­„ÈÉÑÔÔT1ñ(¥Æ>MЪì$½©¡´½½dõÒ÷’æ.3†):c÷4çíÅŽG)5>h‚VegõÂ…{„ZMÌŠµÝÔÔd„¼ÀäáÊ ðÒu_ùL1ãQJ�š UY T+š¦¸-èÝS�Ï8&T,ä·‹‹Rj|Ñ­ÊC&h±ÝtSÓT+B~Â6om±bQJ�?:‹[•)¾�pÏZ­½Ç7�öU˜fac㕽ŊE)5þh Z•©Ðëq¥}ù�+ß áWÕ–{W]|ùO‹‡RjüÒ­ÊCvq“šššª¢¾½oü5b!Š&�¸G}¥”Ò­Ê-B¯Ç�œêFÚŠ^¼fù§ œª°È7W\²ä¹(ﯔR@ÄcÐ$Íôé“?ð­°ò&’8À¤(ï“¶ À+"òŠ!7ú�¿nÛ¶óa ¹Hdaf̘ò.ñÍ{I9�”­ð ¦º[Ã-�• p³@^ù²û²¥ûëÎÎΣ¾ÑŒiÓê@œ>H�líÚñ½¨ïD· á‰ÝÀ+QÜ·©©©SÝÕ!‹¿&^åµQÜ7ÈŒê)7A̬ sBegçÎ?äR_õô©ÿNàÑDW\ZÞèÚ~K©ãÈÇI^u6€³KÖó:`_¡ðмÜY½ù—¿~ÿÍEY–ö¤¿Ø“‡‰êñæ^û­bÜ?CÓ‘Öx‡kæPdŽ�³™ H1Þ—‡@²“b_¥˜×¬ÁkBùÇC'\›Óßl$ š$§OŸ|fõ´)M¼+}0ŠªÃÜÀ€¨ž>åéÓ¦­ìܾ½UDübܯºzÒ{i�F�§“©Ï",JVHR÷�€ øÞÌéS×ù0K»ººþÙm(ïP|ŠÝF$ACÂ/÷åzÜÝSœ…€„JbY²ê²ËvDuï,ÂOò– SÆ:·Èé��©ÇÅÞAdE'À¥Ž!_ó.¡þ �$!@ôµ„Äô®^>éÁ«n˜¸ÇýÁÝóC­5�ƒcóº"OÐsºê“/'ð c @Ò)¹¯½6Âùû~öB '=Øøk!Vzœ_?\¹‚´�¿¥è?†P¾e}ÕS§ÖCpd”uFE€÷Ϙ6y~©ãˆ’¡z’� ½ßâ5KkÁpèn[qÑU¿*ôžJ•Ø¿œøðÕï/uùJµ@y}©ã(À²OÝ{aåP ƒ&éVO›rÒ §w°…Ô6 SŽ>uêÔ™Û·o¿3Ò�7‘“†h.�Ôku0X Ox€¢tí—BU6ïé WV` jA_~ÓÊYo Y|«1fQ!÷+ÁÛ"¨i2R¿‹Aö(xÁÙShjxŽ�wøM©ãÈÇ#÷5–G—:޼¥»jú{ úa¿ ]]]} ¬ø‡*tþ©³Œ3í?yòlÏ5¯�3Æ‚°KFÃ’q�Mcñ�×·o6Šû ¥ºzò{(æwAç,yP±ï?’¿Ò¸sñše{L®,a jA[ßÿB®H&ä…Ë/º|S!÷+•­Û¶,ŠzfLŸú€Ÿ•K¶víø~÷ãžøßQVH‘JkpGcø�×Òñ°(cIÆš7�öQ& ߌb%hxÞÁåü$µÿDôé��²N€å_~¸ �C†+%`Þ-èEk—�MA ÁÓbü§§wízv«HÈ'‡G‹ð-hß7Qlñšå—s�µÆ³îülÕ%WÝ*¥ÊŒ±xSˆ-"ž�PTž JÐ"òÒHl¡Rººv=`¢ˆ¼Äh "›Â®`jÌðÅ–¬Y~& ËBÞ~[ n VO›²¦kûÎkEÆöccÝ”�غg*| ¾îó^–Á-è oº©r¢µwrÅž~6tMžõ•\âT¥!ân'üû"¬òÅë*[Y×]å]ôèq+µ!Sæ ~ÌŠ”&;¢&"ÓH^S=uê_¬/u0*���vñše[€ág\S‚w´šèmûw wGþ¥ÞY7Ÿþ¸J­ººº^pj©ãä�Bþ°÷<0wÙ˜^Àd,)¸zë¶�?X~ (KÇÞÊZã��ãÐÙ]Ü‹V/[àœ�·ê#óV/lÜ>:¥F MáçŒ5 Nùï¦Q¿×xQp‚¡“ü Àï(§Ç|™>}J¨•¢Tù2ärŸ»¸Ó+…-y�Düº‹®üsŽá)5Z�c„Xê;þïç>tÕ‰¥H /’•ÄÞxc÷Ë.˜5kÒr?éœ ð-9�ÄABANË0æ¡ 3)8¼È÷UEF+›C<Ë 3šššÜÆÆFoÑêkO Íz„�5#¸påÂ+( L¥rµ Àë×阉á·h�Cáýsj¬}ðĦDÄ1¨EºÔç–-»6Xe�aÌœ6e­�e�`è‰AªL‰‘M—¡Ù;-6ë²ÕËÞohH}h qÜ´ê’+Ã.û©TDäGÌ]z^1jþØcKª+zc5¬0m�b†"ßþØcKÐÉbåkÔ/6>$[ zÚ´i3fN›vÊ“'çµ½âèdBvqžµçâN„Nμ_˜odJ•£G�[Ùùà‰×~�EÃÝ¿¢7vÙˆ¥ò2ê7ËƘJÐÆøo1?Oº3¦O} �?ü=D~o,þðúŽÏ”:ƨÑÚÍr51+þCç3Hº5ñ¸ŸwpJ•1!n%1 êg±U”Æt‚–� SŒR³Îp HXx+9áo"Ý¥,JbœM�Ðk)„KÎÄFŸ·rÑ•ÛòL©2·g®�wO² GŽP8*c»‹[�z~ÔK¹þ�ð?¶òâÆ"®W©²RÙ3-ÌBMsŠˆÊ[Á-èéÓ§¿Ýˆ|@ Ç8ä·vm» Šà”JÒÙå„oACž–¤=Y·�TJ�y'èÕSÁ‡ 0Ü÷< EþQlJ�½vWD1¿6î©+.y#’Ú”*sŽß3iŒ�bŽyùwq >`Ft¡D�@$K6¾xQÔSl/Ž’8s«0; ®Dð IVœ¸âMÎjü°Æ}G©c(&މÝý8äkÈ;A PöÝ„^‹¢ñý¢Q{=ç˜RKî*äzo™°Ã?ùºË.ÛULJ•»ù‰¦ Çǵ¥Ž£˜„Rö9(„!_CÞý|I ‡å{ýHàå«{À~Ö1FùZËÇìÆÔ¼®ôH¬\uñWG‘R0‡Ï}èê/EY#E€3„8@˜5·GñÆ|)D¡¹'=xõ³E%‡�€'Ä�¯!ÿ ‘—‚RâÍÕÕSÏÈ»Þ<Ðð횯H¾ám^ðî –2·ºzê;#¼W ç­øBP¢|­e#½£Õ ¿|a&WW-^³ì R¾Õ#“›W/\¸§1*•;ù%ì.kaå´tê ‘Ç£�aä‹—ìð}À“�ò]òÙØ¡?d䟠 ÿŽàí–O à„¼ë�’HÔ-è`ä·C,P°A“sêäØlA`sOÐ}Žá*°kÕ’µËné†ýš‹£~tK©QIˆ_–:†|%cÎßt¯3D1Cö`ä=í ×!¢IXEÒ+tZ£ªL(ÍQÕU FøŸ¥Ž¡X˜OÓ ÛL,©ç¹%k—þKSS“® Æ»WŒuï,uùzøøÆŒÚMn(øÕý'_ó‡¡Êäý&ÕÕÕõW€?È÷ú¢£ÜÜÙÙÙøJgçŽG¹/ªú¢ÅÄëÛ¶=Yê(Іˆ²Å;K„?Ø3ÕùÕ¢ÕË#îbTjÔx�"'ÿ÷É£{Mc�KDµPˆb¡ Ò Ý§ V„ëùK!xª�:ŠBðT,)a÷_-eˆW£®·@¶à’RQT‚b<u )�-^³üʈZèJ�ò[kpêý'-õk÷ÿ÷É�¿§p)€ÞRÇ’ƒ$Áë˜{íÿ W° ½yçÎ×:·ï8š�³þ¾�º¢ÁßrvçöGoÚ¹3ô.Hauvîüô®oá…jLz$OCXß¹mÇ‘©ÞŒ1­ðg¡ƒ9€,]´zù½_¿±©Œgè+U°W~üë�¹KßÿÐ ×þ¦ÔEåþ“š®1Öy+7Ø^êx†°“‚µ¾ã¼íþ¹M‹Ã\Pð23""npûA4qçÎ�c¤Å�3 N¡÷da »Y 6Zk6Nž]”{Kv…ü±nEêCçôœª§œâÒùÝâÕËkV]rEÙÌj%q­2š’µ~Yci!!í¨�tÿçBS²‰ˆÙ`ÀM„³Éø;7Ý÷Éoçý¢¡í8Ì#MæÏŸwº«þR—žz_ÓŒÞ ŽceŽ€³™) ¹%^D("v ùªã›W}§çÕç®Ü:\—vP=ÅŠQ©H,^³¬@mˆ¢[cŽô­ý€ùyÜÊ#°xåÂ+oÌãZ¥”Š”ÎdU£AØOÿ“—_tù¦U ¯¬ÈÈý)W€¯Yz×µM¹µÂ•R*bš Õhv º¢©©É€ë^õ] ™ `sî·ãé•âüöÒo®ø§Ü¯UJ©hh‚V£€„?뚆½;Ô_¿ðªG]á1 ò™óVÇÚǯ]qZ×*¥TÁ4A«QÀ„NÐξ Ë.¹â¥ Ûüã¬ËãÆS öžÅk—éþæJ©§ Z•=‘ð�YÅ<7kÖcccc÷Ê…WžK๮ è@ðíÅk–­ÕÕÇ”R#IßpTùcè.î§–-¼bÐçÓW.¼r�ˆ=Èká“‹öL5w]zà “ò¸V)¥r¦ Z•=†ƒÞHÍp…®»äêIÿ@>+àñÓŽÓýè¢ë›ÌýZ¥”Ê�&hUö|ã µ@Ê?.1ÎQ«^*鮼¸ñIV|�{ò罌9¿ÒÞJ©bÓ…JÔ¨°xÍÒzç踃àvKyðoþãŽx<¯=çšššÌž©f9ÀPËîeØN⬕_9jwÓQJ•7MÐjÜ[´vyEþ@UŽ—&ü×ë^ñÃbÄ¥”ß´‹[�{×]|E³€Ÿ‘ëÖ{1Bn]´vÙUE L)5®i Z©´E×7H×¹ ıy\þ¶û_jllô"L)5.i Z©´ë.kÜ8a‡ÿq-y\þÅ=SÜŸ4}·iòðE•RjxÚ‚V*À¢ÕË–�X†Ü?ÄþÞ¡ùÔò‹/µq)¥ÆMÐJ bÑêeŸ!±À”/ý Ÿ ûØ—RJÑ­Ô®øÖŠwù¾½À[s¼´‹Ä™+/¾rCÂRJ�:­Ô–_xùŸL…s,€ 9^:]÷¥ŸßVJ©œi‚Vj+.XòFç¤ý?™ÇŽX×/Z½lIQSJ�iÚÅ­T–¬]¶B¹'\âæ:ü‚|W=SJ�?š •ÊÑ¢5K¿Bð&äÜ%?õý 5ßøú×Cïo­”¿4A+•‡Ek—�AA € 9^úkǘyË/º|S1âRJ�š •ÊÓåk—~Ø ï03·+ù¢±æ´_[òlQSJ� š •*À¢o.;œ–?ä�/Ý ËÓW}íŠÇŠ—RjôÓYÜJ຋®ü³õ¼ømŽ—Î€‘û—¬^~V1âRJ�~š •*Ðõ—6¾6¡Òÿ„÷åxi•P:­^~aQSJ�jš •Š@ãWwNØáÍ#�ëÞІ”o.Z³ì,JpJ©QIÇ •ŠØ’µË–‰àŠ\¯¢}�3ísßúêW{Š—RjtÑ­T,Y³ôK~€“Ëué¦Æš‹»ŠšRj”ЭT‘¤wÃjCîÏJ?å O[vÉ/#.¥Ôè  Z©"Z´zù‡H¹À~9]HlôiNûÆE—ÿ±8‘)¥Ê�NSªˆ®»äŠ'Œ8øBN t¬}tÑêkç)4¥T™Ó­T‘­¸dÉsŽáG@ü&ÇK§’æÞÅ«—žS”À”ReM´R#`ùE—ošPá/ÀÏs¼4ò6ݲR©ñGÇ •AMMMîž©Î->ŸóÅÄ÷^8èð¯ê–•J�š •*�%«—]+ÄU¹^Gâ~]ãù�»‹—Rª|h‚VªD–¬]z¾¿‹Ÿ•ð+ÏúónøZãëňK)U4A+UB—­^6Ïí&æv%ÿâYœtÃ×®ø{QSJ•œNSª„®¿äÊŸ#'Ø’Û•ò×HÎ]äJ©ÑC´R%¶â¢«~Eøñ×.ó…9ÏWJ�"š •*+6þÅ÷ü�øuˆâ¿£•^wñ•?*v\J©ÒÑ1h¥ÊÈ¥7Ü0É1ÝëAœ‘qjÈÇEìÝ·Ûï766z% P)5b4A+U†–ܸôýB¾€kùme—ý�&e¥ÆMÐJ)¥TÒ1h¥”Rª i‚VJ)¥Ê�&h¥”Rª i‚VJ)¥Ê�&h¥”Rª i‚VJ)¥Ê�&h¥”Rª i‚VJ)¥ÊÐÿAm›W„ðÞÐIEND®B`‚scikit-bio-scikit-bio-a3beaa6/logos/vertical_powered_by.svg000066400000000000000000000331541520735541300242550ustar00rootroot00000000000000 image/svg+xmlscikit-bio-scikit-bio-a3beaa6/pyproject.toml000066400000000000000000000111501520735541300212650ustar00rootroot00000000000000[build-system] requires = ["setuptools", "wheel", "numpy", "cython"] build-backend = "setuptools.build_meta" [project] name = "scikit-bio" dynamic = ["version"] description = "Data structures, algorithms and educational resources for bioinformatics." readme = "README.rst" requires-python = ">=3.10" license = "BSD-3-Clause" license-files = ["LICENSE.txt"] authors = [ {name = "scikit-bio development team", email = "qiyunzhu@gmail.com"} ] maintainers = [ {name = "scikit-bio development team", email = "qiyunzhu@gmail.com"} ] classifiers = [ "Development Status :: 4 - Beta", "Topic :: Software Development :: Libraries", "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Bio-Informatics", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Operating System :: Unix", "Operating System :: POSIX", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows" ] dependencies = [ "requests >= 2.20.0", "decorator >= 3.4.2", "natsort >= 4.0.3", "numpy >= 2.0", "pandas >= 1.5.0", "scipy >= 1.9.0", "h5py>=3.6.0", "biom-format >= 2.1.16", "statsmodels >= 0.14.0", "patsy >= 0.5.0", "array-api-compat >= 1.3" ] [project.urls] Homepage = "https://scikit.bio" Documentation = "https://scikit.bio/docs/latest/" Repository = "https://github.com/scikit-bio/scikit-bio" Issues = "https://github.com/scikit-bio/scikit-bio/issues" [project.optional-dependencies] test = [ "pytest", "coverage", "responses", "matplotlib" ] docs = [ "sphinx", "sphinx-design", "sphinx-copybutton", "pydata-sphinx-theme", "sphinxcontrib-youtube", "sphinx-sitemap", "numpydoc", "matplotlib", "statsmodels", "patsy" ] lint = [ "check-manifest", "python-dateutil", "numpy", "ruff", "pre-commit" ] dev = [ "pytest", "coverage", "responses", "matplotlib", "sphinx", "sphinx-design", "sphinx-copybutton", "pydata-sphinx-theme", "sphinxcontrib-youtube", "sphinx-sitemap", "numpydoc", "statsmodels", "patsy", "check-manifest", "python-dateutil", "numpy", "ruff", "pre-commit" ] [tool.setuptools.dynamic] version = {attr = "skbio.__version__"} [tool.setuptools] packages = ["skbio"] [tool.setuptools.package-data] "skbio.alignment.tests" = ["data/*"] "skbio.tree.tests" = ["data/*"] "skbio.diversity.alpha.tests" = ["data/qiime-191-tt/*"] "skbio.diversity.beta.tests" = ["data/qiime-191-tt/*"] "skbio.io.tests" = ["data/*"] "skbio.io.format.tests" = ["data/*"] "skbio.stats.tests" = ["data/*"] "skbio.stats.distance.tests" = ["data/*"] "skbio.stats.ordination.tests" = ["data/*"] "skbio.metadata.tests" = ["data/invalid/*", "data/valid/*"] "skbio.embedding.tests" = ["data/*"] [tool.cibuildwheel] # Skip 32-bit builds, PyPy, musllinux and unavailble Win-ARM64 Python builds skip = ["*-win32", "*-manylinux_i686", "pp*", "*-musllinux*", "cp39-win_arm64", "cp310-win_arm64"] # Python versions to build # UPDATE BEFORE RELEASE build = "cp310-* cp311-* cp312-* cp313-* cp314-*" # Test dependencies test-requires = ["pytest", "coverage", "responses"] # Install dependencies before building before-build = "pip install numpy cython" [tool.cibuildwheel.linux] # Updated to be compatible with Python 3.14 manylinux-x86_64-image = "manylinux_2_28" manylinux-aarch64-image = "manylinux_2_28" [tool.pytest.ini_options] addopts = [ "--doctest-modules", "--doctest-glob", "*.pyx", ] doctest_optionflags = [ "NORMALIZE_WHITESPACE", "IGNORE_EXCEPTION_DETAIL", ] markers = [ "array_api: tests that exercise the Array API across backends", ] [tool.check-manifest] ignore = [ ".coveragerc", ".dockerignore", ".editorconfig", "checklist.py", # created by conda-incubator/setup-miniconda@v3 action "ci/setup-miniconda-patched-conda_host_env.yml", ] # Basic configurations for Ruff. # See https://docs.astral.sh/ruff/configuration/ [tool.ruff] target-version = "py310" exclude = [ "skbio/**/tests/*", # ignoring to be able to implement pydocstyle "doc/**", # documentation "web/**", # website ] [tool.ruff.lint] select = ["E", "W"] # pycodestyle (E, W) ignore = [ "D203", # puts a space before class docstrings "D213", # puts summary on second line "D400", # redundant with D415 in place "D301", # forces raw string literals ] scikit-bio-scikit-bio-a3beaa6/setup.py000066400000000000000000000122051520735541300200650ustar00rootroot00000000000000#!/usr/bin/env python """Setup script for scikit-bio installation. ---------------------------------------------------------------------------- Copyright (c) 2013--, scikit-bio development team. Distributed under the terms of the Modified BSD License. The full license is in the file LICENSE.txt, distributed with this software. ---------------------------------------------------------------------------- """ import os import platform import sys import sysconfig import subprocess from setuptools import find_packages, setup from setuptools.extension import Extension import numpy as np from Cython.Build import cythonize if sys.version_info.major != 3: sys.exit( "scikit-bio can only be used with Python 3. You are currently " "running Python %d." % sys.version_info.major ) def check_bin(ccbin, source, allow_dash): """Check if a given compiler matches the specified name.""" # remove any parameters (e.g. gcc -I /a/b/c -> gcc) source0 = source.split()[0] # remove any path bsource = os.path.basename(source0) # now let's go search for ccbin if allow_dash: found = False # allow for the ccbin to be between - (e.g. gcc-1.2) for el in bsource.split("-"): if el == ccbin: found = True break else: found = bsource == ccbin return found # Enable OpenMP during build # Note: We are looking for Apple/MacOS clang, which does not support omp # Will treat "real clang" (e.g. llvm based) same as gcc clang = False # icc uses slightly different omp cmdline arguments icc = False # Are we using the default gcc as the compiler? gcc = True try: if os.environ["CC"] == "gcc": gcc = True elif os.environ["CC"] != "": gcc = False except KeyError: pass if not gcc: try: if check_bin("clang", os.environ["CC"], False): # note, the conda provideed clang is not detected here # and this is on purpose, as MacOS clang is very different # than conda-provised one (which is llvm based) # so do not look for substrings # (e.g. do not match x86_64-apple-darwin13.4.0-clang) clang = True elif check_bin("icc", os.environ["CC"], True): icc = True except KeyError: pass else: try: if check_bin("clang", sysconfig.get_config_vars()["CC"], False): # as above clang = True gcc = False elif check_bin("icc", sysconfig.get_config_vars()["CC"], True): icc = True gcc = False except KeyError: pass if gcc: # check if the default gcc is just a wrapper around clang try: if ( subprocess.check_output(["gcc", "--version"], universal_newlines=True).find( "clang" ) != -1 ): clang = True except (subprocess.CalledProcessError, FileNotFoundError): pass # Determine if we want to use OpenMP # Enabled by default use_openpm = True if clang: # Apple clang does not support OpenMP at all use_openpm = False if os.getenv("DISABLE_OPENMP") in ("Y", "Yes", "YES", "1"): # Developer explicity requested not to use OpenMP use_openpm = False # Compiler flags extra_compile_args = ["-I."] # search current directory extra_link_args = [] if use_openpm: # Enable OpenMP for parallelism. if platform.system() == "Windows": extra_compile_args.append("/openmp") elif icc: extra_compile_args.append("-qopenmp") extra_link_args.append("-qopenmp") else: extra_compile_args.append("-fopenmp") extra_link_args.append("-fopenmp") # Cython modules (*.pyx). They will be compiled into C code (*.c) during build. ext = ".pyx" extensions = [ Extension( "skbio.metadata._intersection", ["skbio/metadata/_intersection" + ext], ), Extension( "skbio.tree._c_nj", ["skbio/tree/_c_nj" + ext], extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, ), Extension( "skbio.tree._c_me", ["skbio/tree/_c_me" + ext], extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, ), Extension( "skbio.diversity._phylogenetic", ["skbio/diversity/_phylogenetic" + ext], include_dirs=[np.get_include()], ), Extension( "skbio.stats.ordination._cutils", ["skbio/stats/ordination/_cutils" + ext], extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, ), Extension( "skbio.stats.distance._cutils", ["skbio/stats/distance/_cutils" + ext], extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, ), Extension( "skbio.alignment._cutils", ["skbio/alignment/_cutils" + ext], extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, include_dirs=[np.get_include()], ), ] extensions = cythonize(extensions, force=True) setup( packages=find_packages(), ext_modules=extensions, include_dirs=[np.get_include()], ) scikit-bio-scikit-bio-a3beaa6/skbio/000077500000000000000000000000001520735541300174625ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/__init__.py000066400000000000000000000050341520735541300215750ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # ruff: noqa: D104 # Add skbio.io to sys.modules to prevent cycles in our imports import skbio.io # noqa # imports included for convenience from skbio.sequence import Sequence, DNA, RNA, Protein, GeneticCode, SubstitutionMatrix from skbio.stats.distance import DistanceMatrix from skbio.alignment import TabularMSA from skbio.tree import TreeNode, nj from skbio.embedding import ProteinEmbedding from skbio.io import read, write from skbio.stats.ordination import OrdinationResults from skbio.table import Table from skbio.metadata import SampleMetadata import skbio.diversity # noqa import skbio.binaries # noqa import skbio.stats.evolve # noqa from ._config import get_config, set_config __all__ = [ "Sequence", "DNA", "RNA", "Protein", "GeneticCode", "SubstitutionMatrix", "DistanceMatrix", "TabularMSA", "TreeNode", "nj", "read", "write", "OrdinationResults", "Table", "SampleMetadata", "get_config", "set_config", ] __credits__ = "https://github.com/scikit-bio/scikit-bio/graphs/contributors" __version__ = "0.7.3" mottos = [ # 03/15/2014 "It's gonna get weird, bro.", # 05/14/2014 "no cog yay", # 03/18/2015 "bincount!", ] motto = mottos[-1] # Created at patorjk.com title = r""" * * _ _ _ _ _ _ (_) | (_) | | | (_) ___ ___ _| | ___| |_ ______| |__ _ ___ / __|/ __| | |/ / | __|______| '_ \| |/ _ \ \__ \ (__| | <| | |_ | |_) | | (_) | |___/\___|_|_|\_\_|\__| |_.__/|_|\___/ * * """ # Created by @gregcaporaso art = r""" Opisthokonta \ Amoebozoa \ / * Euryarchaeota \ |_ Crenarchaeota \ * \ / * / / / * / \ / \ Proteobacteria \ Cyanobacteria """ __doc__ = title + art + (__doc__ or "") scikit-bio-scikit-bio-a3beaa6/skbio/_base.py000066400000000000000000000032551520735541300211120ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from abc import ABCMeta, abstractmethod class SkbioObject(metaclass=ABCMeta): """Abstract base class defining core API common to all scikit-bio objects. Public scikit-bio classes should subclass this class to ensure a common, core API is present. All abstract methods and properties defined here must be implemented in subclasses, otherwise they will not be instantiable. """ @abstractmethod def __str__(self): raise NotImplementedError class ElasticLines: """Store blocks of content separated by dashed lines. Each dashed line (separator) is as long as the longest content (non-separator) line. """ def __init__(self): self._lines = [] self._separator_idxs = [] self._max_line_len = -1 def add_line(self, line): line_len = len(line) if line_len > self._max_line_len: self._max_line_len = line_len self._lines.append(line) def add_lines(self, lines): for line in lines: self.add_line(line) def add_separator(self): self._lines.append(None) self._separator_idxs.append(len(self._lines) - 1) def to_str(self): separator = "-" * self._max_line_len for idx in self._separator_idxs: self._lines[idx] = separator return "\n".join(self._lines) scikit-bio-scikit-bio-a3beaa6/skbio/_config.py000066400000000000000000000046031520735541300214430ustar00rootroot00000000000000r"""Configuration Options ===================== .. currentmodule:: skbio This module provides a configuration system that controls the global behavior of all scikit-bio functionalities. Functions --------- .. autosummary:: :toctree: generated/ get_config set_config Configuration options --------------------- At present, only one configuration option is available: **table_output** : *{"pandas", "numpy", "polars"}, default="pandas"* The preferred output format of tables. See :ref:`details `. """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from typing import Any _SKBIO_OPTIONS = { "table_output": "pandas", } def set_config(option: str, value: Any): """Set a scikit-bio configuration option. This function enables users to set the configuration of scikit-bio functions globally. Parameters ---------- option : str The configuration option to be modified. value : str The value to update the configuration dictionary with. Raises ------ ValueError If an unknown option is used or if an unsupported value for an option is used. Examples -------- >>> from skbio import set_config >>> set_config("table_output", "numpy") # doctest: +SKIP """ if option not in _SKBIO_OPTIONS: raise KeyError(f"Unknown option: '{option}'.") # Validate option-specific values. match option: case "table_output": pos_opts = ["pandas", "polars", "numpy"] # , "biom"] if value not in pos_opts: raise ValueError(f"Unsupported value '{value}' for '{option}'.") _SKBIO_OPTIONS[option] = value def get_config(option: str) -> Any: """Get the current value of a scikit-bio configuration option. Parameters ---------- option : str The configuration option to be found. Returns ------- str The current value of the configuration option supplied. """ try: return _SKBIO_OPTIONS[option] except KeyError: raise KeyError(f"Unknown option: '{option}'.") scikit-bio-scikit-bio-a3beaa6/skbio/alignment/000077500000000000000000000000001520735541300214405ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/alignment/__init__.py000066400000000000000000000352741520735541300235640ustar00rootroot00000000000000r"""Sequence Alignments (:mod:`skbio.alignment`) ============================================ .. currentmodule:: skbio.alignment This module provides functionality for computing and manipulating sequence alignments. DNA, RNA, and protein sequences can be aligned, as well as sequences with or without custom alphabets. See the |alignment_tutorial|_ section for performing and working with sequence alignments using scikit-bio. Alignment structures -------------------- Tabular format of aligned sequences. .. autosummary:: :toctree: generated/ TabularMSA Compact format of alignment paths. .. autosummary:: :toctree: generated/ AlignPath PairAlignPath Pairwise alignment ------------------ A versatile, efficient and generalizable pairwise alignment algorithm. .. autosummary:: :toctree: generated/ pair_align Convenience wrappers with preset scoring schemes. .. autosummary:: :toctree: generated/ pair_align_nucl pair_align_prot Alignment statistics -------------------- .. autosummary:: :toctree: generated/ align_score align_dists Deprecated functionality ------------------------ Pure Python algorithms (slow; educational-purposes only) .. autosummary:: :toctree: generated/ global_pairwise_align_nucleotide global_pairwise_align_protein global_pairwise_align local_pairwise_align_nucleotide local_pairwise_align_protein local_pairwise_align .. |alignment_tutorial| replace:: **Tutorial** .. _alignment_tutorial: Tutorial -------- Sequence alignment is the process of arranging biological sequences such that they resemble each other when positioned together. The alignment reveals the degree of similarity between sequences, which may indicate evolutionary relationships (i.e., "homology") and/or structural and functional relevance. The alignment process permits only one operation: shifting characters by inserting gaps (`-`) between them. Shuffling characters is not permitted. Quick start ^^^^^^^^^^^ To demonstrate this process, let's create two DNA sequences. >>> from skbio.sequence import DNA >>> seq1 = DNA('ACTACCAGATTACTTACGGATCAGGTACTTGCCAACAA') >>> seq2 = DNA('CGAAACTACTAGATTACGGATCTTACTTTCCAGCAAGG') Just by eyeballing, we can observe some local similarities between the sequences, particularly in the middle sections. However, the beginning and ending portions aren't so similar between the two. Apply :func:`pair_align_nucl` to perform pairwise alignment of the two nucleotide sequences. >>> from skbio.alignment import pair_align_nucl >>> aln = pair_align_nucl(seq1, seq2) >>> aln # doctest: +ELLIPSIS PairAlignResult(score=22.0, paths=[>> aln.paths[0] To obtain aligned sequences, we can call the :meth:`~AlignPath.to_aligned` method of the path. >>> aln.paths[0].to_aligned((seq1, seq2)) ['----ACTACCAGATTACTTACGGATCAGGTACTTGCCAACAA--', 'CGAAACTACTAGATTAC----GGATCT--TACTTTCCAGCAAGG'] As we can see, by inserting four consecutive gaps in the appropriate positions, the two sequences appear more similar, or "aligned", with one another. The score measures the goodness of the alignment. The value is dependent on the sequences and the alignment parameters (discussed below). >>> aln.score 22.0 Likewise, we can align protein sequences with :func:`pair_align_prot`: >>> from skbio import Protein >>> from skbio.alignment import pair_align_prot >>> pair_align_prot(Protein("HEAGAWGHEE"), Protein("PAWHEAE")) # doctest: +ELLIPSIS PairAlignResult(score=15.0, paths=[` (DP) has been the gold standard for pairwise sequence alignment, and is widely covered in many bioinformatics textbooks. scikit-bio also implements this algorithm. ``pair_align_nucl`` and ``pair_align_prot`` are but convenience wrappers for the function :func:`pair_align`, which offers multiple customizable parameters and comprehensive documentation explaining the algorithm and everything you need to know for using it. >>> from skbio.alignment import pair_align By referring to the documentation of ``pair_align``, we can customize the algorithm's behavior to best suit our research objectives. The default mode is *global* alignment, as in the Needleman-Wunsch algorithm (which you may recall from textbooks), with both ends free of gap penalty (a.k.a., "semi-global alignment", or "overlap alignment", in some literature). Next, we will switch to *local* alignment, as in the Smith-Waterman algorithm. >>> aln = pair_align(seq1, seq2, mode="local") >>> aln # doctest: +ELLIPSIS PairAlignResult(score=13.0, paths=[>> aln.paths[0].to_aligned((seq1, seq2)) ['TTACGGATCAGGTACTTGCCAACAA', 'TTACGGATCT--TACTTTCCAGCAA'] As shown, the alignment is shorter than that of the global alignment, and truncated: only the highly similar regions in the middle of the two sequences are preserved, while the less similar regions at both ends are discarded. We can further tweak the alignment parameters. The wrapper function ``pair_align_nucl`` uses parameters that are consistent with NCBI BLASTN's defaults. To replicate this behavior using ``pair_align``, we can proceed as follows: >>> aln = pair_align(seq1, seq2, mode="global", sub_score=(2, -3), gap_cost=(5, 2)) >>> aln # doctest: +ELLIPSIS PairAlignResult(score=22.0, paths=[>> aln = pair_align(seq1, seq2, mode="global", sub_score="NUC.4.4", gap_cost=3) >>> aln # doctest: +ELLIPSIS PairAlignResult(score=106.0, paths=[>> from skbio.alignment import align_score >>> align_score((aln.paths[0], (seq1, seq2)), sub_score="NUC.4.4", gap_cost=3) 106.0 Pairwise alignment is often taught in bioinformatics courses. By adding ``keep_matrices=True`` to the function, the alignment matrix calculated during the DP process will be retained. This can be particularly useful for educational purposes. >>> score, (path,), (matrix,) = pair_align( ... "GATCT", "GTAC", mode="global", free_ends=False, keep_matrices=True) >>> matrix # doctest: +ELLIPSIS array([[ 0., -2., -4., -6., -8.], [ -2., 1., -1., -3., -5.], [ -4., -1., 0., 0., -2.], [ -6., -3., 0., -1., -1.], [ -8., -5., -2., -1., 0.], [-10., -7., -4., -3., -2.]]... Alignment path ^^^^^^^^^^^^^^ A pairwise alignment path is an instance of the :class:`PairAlignPath` class, which in turn is a subclass of the :class:`AlignPath` class. This class implements an efficient data structure to store the "path", i.e., the events of placing gaps inside sequences. It uses run-length encoding (RLE) under the hood, and does not store the sequence data, such that its memory cost is minimum. Refer to the class documentation for details of this data structure. >>> path = aln.paths[0] >>> path.lengths array([ 4, 13, 4, 6, 2, 13, 2]) >>> path.states array([[1, 0, 2, 0, 2, 0, 1]], dtype=uint8) The path can be represented by a CIGAR string, which is a common format used by many high-throughput pairwise alignment tools. >>> path.to_cigar() '4I13M4D6M2D13M2I' The letters in the CIGAR string represent the gap-placing events: ``I`` (insertion): gap in sequence 1, ``D`` (deletion): gap in sequence 2, ``M`` (mis/match): gap in neither sequence. The numbers represent the length of each segment. As you may have noticed, the ``PairAlignPath`` data structure resembles the CIGAR encoding. In this example, the alignment path contains four consecutive gaps flanking four chunks of (mis)matched characters. If we pass the sequences to the :meth:`~PairAlignPath.to_cigar` method, we will get ``=`` (match, i.e., same character) and ``X`` (mismatch, i.e., different characters) instead of ``M``. >>> path.to_cigar((seq1, seq2)) '4I5=1X7=4D5=1X2D5=1X3=1X3=2I' One can construct a ``PairAlignPath`` from a CIGAR string using the :meth:`~PairAlignPath.from_cigar` method. Likewise, this process doesn't rely on the sequence data. Therefore, it is suitable for handling many CIGAR strings from large data files, such as those in SAM/BAM formatted files. >>> from skbio.alignment import PairAlignPath >>> path = PairAlignPath.from_cigar('1I8M2D5M2I') >>> path This method can also be used to parse CIGAR-formatted alignment results of external sequence alignment tools, such as **Parasail**. .. code-block:: python import parasail res = parasail.nw_trace(...) path = PairAlignPath.from_cigar(res.cigar.decode) ``AlignPath`` is a more generalized data structure that supports an arbitrary number of sequences. For example, we can directly construct a path of three aligned sequences using the :meth:`~AlignPath.from_aligned` method: >>> from skbio.alignment import AlignPath >>> path = AlignPath.from_aligned([ ... 'CGTCGTGC', ... 'CA--GT-C', ... 'CGTCGT-T', ... ]) >>> path >>> path.lengths array([2, 2, 2, 1, 1]) >>> path.states[0] array([0, 2, 0, 6, 0], dtype=uint8) The ``AlignPath`` (as well as ``PairAlignPath``) class serves as a central hub for interacting with different alignment formats and tools. For example, the :meth:`~AlignPath.from_coordinates` method can parse **BioPython**'s alignment results (and vice versa with :meth:`~AlignPath.to_coordinates`). .. code-block:: python from Bio import Align res = Align.PairwiseAligner().align(...) path = AlignPath.from_coordinates(res[0].coordinates) The :meth:`~AlignPath.from_indices` method can parse **Biotite**'s alignment results (and vice versa with :meth:`~AlignPath.to_indices`). .. code-block:: python from biotite.sequence.align import align_optimal res = align_optimal(...) path = AlignPath.from_indices(res[0].trace.T) Tabular alignment ^^^^^^^^^^^^^^^^^ In addition to alignment paths, scikit-bio provides :class:`TabularMSA`, a tabular data structure that hosts aligned sequences ("MSA" stands for multiple sequence alignment). One can convert an alignment path and the original (unaligned) sequences into a ``TabularMSA`` object using the :meth:`~TabularMSA.from_path_seqs` method (and vice versa with :meth:`AlignPath.from_tabular`). >>> from skbio.alignment import TabularMSA >>> score, (path,), _ = pair_align_nucl(seq1, seq2) >>> msa = TabularMSA.from_path_seqs(path, (seq1, seq2)) >>> msa TabularMSA[DNA] -------------------------------------------- Stats: sequence count: 2 position count: 44 -------------------------------------------- ----ACTACCAGATTACTTACGGATCAGGTACTTGCCAACAA-- CGAAACTACTAGATTAC----GGATCT--TACTTTCCAGCAAGG Alternatively, one can read from a multi-FASTA file of aligned sequences: .. code-block:: python msa = TabularMSA.read('input.fasta', constructor=DNA) Or directly from aligned sequence objects: >>> msa = TabularMSA([ ... DNA('CGTCGTGC'), ... DNA('CA--GT-C'), ... DNA('CGTCGT-T'), ... ]) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 3 position count: 8 --------------------- CGTCGTGC CA--GT-C CGTCGT-T A ``TabularMSA`` object is iterally like a table. If you are also familiar with pandas DataFrame, you can apply similar indexing methods to it. >>> msa.index RangeIndex(start=0, stop=3, step=1) >>> msa.iloc[0] DNA -------------------------- Stats: length: 8 has gaps: False has degenerates: False has definites: True GC-content: 75.00% -------------------------- 0 CGTCGTGC >>> msa.iloc[:, 1] Sequence ------------- Stats: length: 3 ------------- 0 GAG Like :class:`~skbio.sequence.Sequence`, ``TabularMSA`` can be annotated with metadata. >>> msa.metadata = {'name': 'test alignment'} >>> msa.positional_metadata = { ... 'identity': [80, 85, 88, 90, 90, 95, 92, 86]} The class provides some utilities for downstream analysis. For example, to obtain a consensus sequence of the alignment: >>> msa.consensus() DNA ------------------------------ Positional metadata: 'identity': Stats: length: 8 has gaps: True has degenerates: False has definites: True GC-content: 71.43% ------------------------------ 0 CGTCGT-C """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._tabular_msa import TabularMSA from ._pairwise import ( local_pairwise_align_nucleotide, local_pairwise_align_protein, local_pairwise_align, global_pairwise_align_nucleotide, global_pairwise_align_protein, global_pairwise_align, ) from skbio.alignment._path import AlignPath, PairAlignPath from skbio.alignment._score import align_score from skbio.alignment._distance import align_dists from skbio.alignment._pair import pair_align, pair_align_nucl, pair_align_prot __all__ = [ "TabularMSA", "AlignPath", "PairAlignPath", "global_pairwise_align", "global_pairwise_align_nucleotide", "global_pairwise_align_protein", "local_pairwise_align", "local_pairwise_align_nucleotide", "local_pairwise_align_protein", "align_score", "align_dists", "pair_align", "pair_align_nucl", "pair_align_prot", ] scikit-bio-scikit-bio-a3beaa6/skbio/alignment/_cutils.pyx000066400000000000000000000417631520735541300236570ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # cython: language_level=3, boundscheck=False, wraparound=False, cdivision=True from cython cimport floating from libc.math cimport INFINITY, fabs, fabsf from libc.float cimport FLT_MAX, DBL_MAX cdef inline floating xabs(floating x) noexcept nogil: """Calculate absolute value of a floating-point number. It takes a fused floating type variable (float or double) and dispatches the corresponding C function (fabsf or fabs). Since it is inlined, there is little overhead compared with directly calling the C function. """ if floating is float: return fabsf(x) else: return fabs(x) cdef inline floating lbound(bint local, floating gap_extend) noexcept nogil: """Get lower bound of alignment score. `gap_extend` is supplied to let the compiler know the floating type (float or double). Otherwise it will complain: "Return type is not specified as argument type". Currently it is not used, because `-INFINITY` is good enough. """ if local: return 0 elif floating is float: return -FLT_MAX else: return -DBL_MAX def _fill_linear_matrix( floating[:, ::1] scomat, const floating[:, ::1] query, const Py_ssize_t[::1] target, floating gap_extend, bint local, ): """Calculate optimal scores over the alignment matrix with linear gap penalty. Parameters: ---------- scomat : memoryview of ndarray of shape (m, n) Main matrix. query : memoryview of ndarray of float of shape (m, n_symbols) Query profile. target : memoryview of ndarray of int of shape (n,) Target sequence. gap_extend : floating Gap extension penalty. local : bint Local (True) or global (False) alignment. Notes ----- Matrix filling is the most computationally intensive step in pairwise sequence alignment using dynamic programming. It is O(mn). The current algorithm adopts the classic and simple double loops method. Efficiency is achieved through memory layout and compiler's auto-optimization. All arrays are C-contiguous, facilitating row-wise iteration, which is what the inner loop (j-indexed) does. The loop content is simple as possible, involving a single `max` and no branches. The linear and affine versions are separated, whereas the global and local versions are unified with a lower bound constant defined prior to the loops. Directions are not saved during matrix filling, but instead re-calculated during traceback, which is O(m + n) anyway. `query` is a pre-computed profile of the query sequence. Each row represents a character in the query sequence and each column represents a symbol in the substitution matrix. `target` is a vector of indices in the substitution matrix, and each elements represents a character in the target sequence. Therefore, `query[i - 1, target[j - 1]]` directly looks up the substitution score between i-th character in query and j-th character in target. Although this algorithm does not utilize various manual optimization techniques that have been developed and shown effective in pairwise sequence alignment, such as wavefront sweep, loop tiling, SIMD striping and prefix scan, they are noted here for reference. """ cdef floating bound = 0 if local else -INFINITY cdef Py_ssize_t m1 = scomat.shape[0], n1 = scomat.shape[1] cdef Py_ssize_t i, j cdef floating* row for i in range(1, m1): row = &query[i - 1, 0] for j in range(1, n1): scomat[i, j] = max( scomat[i - 1, j - 1] + row[target[j - 1]], scomat[i, j - 1] - gap_extend, scomat[i - 1, j] - gap_extend, bound, ) def _fill_affine_matrices( floating[:, ::1] scomat, floating[:, ::1] insmat, floating[:, ::1] delmat, const floating[:, ::1] query, const Py_ssize_t[::1] target, floating gap_open, floating gap_extend, bint local, ): """Calculate optimal scores over the alignment matrix with affine gap penalty. Parameters: ---------- scomat : memoryview of ndarray of shape (m, n) Main matrix. insmat : memoryview of ndarray of shape (m, n) Insertion matrix. delmat : memoryview of ndarray of shape (m, n) Deletion matrix. query : memoryview of ndarray of float of shape (m, n_symbols) Query profile. target : memoryview of ndarray of int of shape (n,) Target sequence. gap_open : floating Gap opening penalty. gap_extend : floating Gap extension penalty. local : bint Local (True) or global (False) alignment. See Also -------- _fill_linear_matrix """ cdef floating bound = 0 if local else -INFINITY cdef floating gap_open_extend = gap_open + gap_extend cdef Py_ssize_t m1 = scomat.shape[0], n1 = scomat.shape[1] cdef Py_ssize_t i, j cdef floating sub_, ins_, del_ cdef floating* row for i in range(1, m1): row = &query[i - 1, 0] for j in range(1, n1): # substitution (diagonal) sub_ = scomat[i - 1, j - 1] + row[target[j - 1]] # open a new insertion or extend a previous insertion (horizontal) ins_ = insmat[i, j] = max( scomat[i, j - 1] - gap_open_extend, insmat[i, j - 1] - gap_extend, ) # open a new deletion or extend a previous deletion (vertical) del_ = delmat[i, j] = max( scomat[i - 1, j] - gap_open_extend, delmat[i - 1, j] - gap_extend, ) scomat[i, j] = max(sub_, ins_, del_, bound) def _trace_one_linear( unsigned char[::1] path, Py_ssize_t pos, Py_ssize_t i, Py_ssize_t j, floating[:, ::1] scomat, floating gap_extend, bint local, floating eps, ): """Traceback across matrix body with linear gap penalty. Parameters: ---------- path : memoryview of ndarray of shape (n_positions,) Dense alignment path. pos : int Current start position of the path. i : int Current row index in the matrix. j : int Current column index in the matrix. scomat : memoryview of ndarray of shape (m, n) Main matrix. gap_extend : floating Gap extension penalty. local : bint Local (True) or global (False) alignment. eps : floating Absolute tolerance. Returns ------- int Updated start position of the path. int Updated row index in the matrix. int Updated column index in the matrix. Notes ----- Only one optimal alignment path is traced. The priority is: deletion > insertion > substitution This function does not involve the original sequences or the substitution matrix, thereby improving memory efficiency. Altschul & Erickson (1986) [1]_ pointed out that the original Gotoh algorithm could fail in some situations. Specifically, if the traceback process does not jump between matrices, it won't be able to distinguish ties between creating a new gap vs. extending an existing gap. The current function follows the modified Gotoh algorithm. References ---------- .. [1] Altschul, S. F., & Erickson, B. W. (1986). Optimal sequence alignment using affine gap costs. Bull Math Biol, 48, 603-616. """ cdef floating score, gap_score # will stop when reaching either edge of the matrix while i and j: score = scomat[i, j] if local and xabs(score) <= eps: break gap_score = gap_extend + score pos -= 1 # deletion (vertical; gap in seq2) if xabs(scomat[i - 1, j] - gap_score) <= eps: path[pos] = 2 i -= 1 # insertion (horizontal; gap in seq1) elif xabs(scomat[i, j - 1] - gap_score) <= eps: path[pos] = 1 j -= 1 # substitution (diagonal; no gap) else: path[pos] = 0 i -= 1 j -= 1 return pos, i, j def _trace_one_affine( unsigned char[::1] path, Py_ssize_t pos, Py_ssize_t i, Py_ssize_t j, floating[:, ::1] scomat, floating[:, ::1] insmat, floating[:, ::1] delmat, floating gap_extend, bint local, floating eps, ): """Traceback across matrix body with affine gap penalty. Parameters: ---------- path : memoryview of ndarray of shape (n_positions,) Dense alignment path. pos : int Current start position of the path. i : int Current row index in the matrix. j : int Current column index in the matrix. scomat : memoryview of ndarray of shape (m, n) Main matrix. insmat : memoryview of ndarray of shape (m, n) Insertion matrix. delmat : memoryview of ndarray of shape (m, n) Deletion matrix. gap_extend : floating Gap extension penalty. local : bint Local (True) or global (False) alignment. eps : floating Absolute tolerance. Returns ------- int Updated start position of the path. int Updated row index in the matrix. int Updated column index in the matrix. Notes ----- Only one optimal alignment path is traced. The priority is: Main matrix: jumping to deletion matrix > jumping to insertion matrix > substitution. Deletion matrix: staying in deletion matrix > jumping to main matrix. Insertion matrix: staying in insertion matrix > jumping to main matrix. """ cdef floating score cdef int mat = 0 while i and j: score = scomat[i, j] if local and xabs(score) <= eps: break # deletion matrix (vertical; gap in seq2) if mat == 2: # extend an existing gap (stay in the current matrix), # or open a new gap (jump back to main matrix) if xabs(delmat[i - 1, j] - gap_extend - delmat[i, j]) > eps: mat = 0 i -= 1 pos -= 1 path[pos] = 2 # insertion matrix (horizontal; gap in seq1) elif mat == 1: # same as above if xabs(insmat[i, j - 1] - gap_extend - insmat[i, j]) > eps: mat = 0 j -= 1 pos -= 1 path[pos] = 1 # main matrix else: if xabs(delmat[i, j] - score) <= eps: # jump to deletion matrix mat = 2 elif xabs(insmat[i, j] - score) <= eps: # jump to insertion matrix mat = 1 else: # substitution (diagonal; no gap) i -= 1 j -= 1 pos -= 1 path[pos] = 0 return pos, i, j def _trim_end_gaps( const unsigned char[:, :] bits, Py_ssize_t[::1] starts, Py_ssize_t[::1] stops, ): r"""Identify the terminal gap-free region of a multiple alignment. Parameters ---------- bits : ndarray of uint8 of shape (n_sequences, n_positions) Bit array representing gaps in the alignment. starts : ndarray of int of shape (n_sequences,) Start position of terminal gap-free region of each sequence. (i.e., index of the first position within non-gap) stops : ndarray of int of shape (n_sequences,) Stop position of terminal gap-free region of each sequence. (i.e., index of the first position after non-gap) Notes ----- If a sequence only contains gaps, double zeros will be assigned. This function works for both the original alignment (columns are positions) and the alignment path (columns are segments). Parallelization is possible, although perhaps unnecessary. """ cdef Py_ssize_t i, j, k cdef Py_ssize_t n = bits.shape[1] for i in range(bits.shape[0]): k = n for j in range(n): if bits[i, j] == 0: starts[i] = k = j break if k == n: # gap-only sequence starts[i] = stops[i] = 0 continue for j in range(n - 1, k - 1, -1): if bits[i, j] == 0: stops[i] = j + 1 break def _multi_align_score( const Py_ssize_t[:, ::1] seqs, const unsigned char[:, :] bits, const Py_ssize_t[:] lens, const Py_ssize_t[::1] starts, const Py_ssize_t[::1] stops, const floating[:, ::1] submat, floating gap_open, floating gap_extend, bint free_ends, ): """Calculate sum-of-pairs (SP) alignment score of aligned sequences. Parameters ---------- seqs : ndarray of uint8 of shape (n_sequences, n_positions) Character array represented by ASCII code or alphabet index. bits : ndarray of uint8 of shape (n_sequences, n_segments) Bit array representing gap status in the alignment path. lens : ndarray of int of shape (n_segments,) Lengths of segments in the alignment path. starts : ndarray of int of shape (n_sequences,) Start position of terminal gap-free region of each sequence. stops : ndarray of int of shape (n_sequences,) Stop position of terminal gap-free region of each sequence. submat : ndarray of float of shape (n_alphabet, n_alphabet) Substitution matrix. gap_open : float Gap opening penalty. gap_extend : float Gap extension penalty. free_ends : bool Whether terminal gaps are free from penalization. Returns ------- float Alignment score. """ # TODO: Some array parameters can be [::1]. # This function employs an algorithm that is more complex than intuition. Instead # of iterating over all positions and accumulatively adding score or cost of each # position, it operates on the alignment path, which divides the alignment into # segments representing altering status. This design permits the calculation of # gap costs on the entire contiguous gap rather than by each gap position. It not # only saves compute, but also enables complex gap penalty schemes, such as convex # and dual affine penalties, although they are not currently implemented. # This algorithm calculates the alignment score between each pair of sequences and # sums the results. Therefore, it has a time complexity of O(n^2), which isn't # ideal especially when there are many sequences. Alternatively, one can iterate # over positions, calculate character frequencies, then calculate the overall # score accordingly. However, this design only works for linear gap penalty. # TODO: Implement a separate algorithm for linear gap penalty on many sequences. cdef Py_ssize_t i1, i2, j, k cdef Py_ssize_t start, end, pos cdef int L, cumL, prev, curr cdef floating score = 0 # cumulative alignment score cdef Py_ssize_t n = seqs.shape[0] # number of sequences # calculate alignment score of each pair of sequences and sum up # TODO: The current algorithm can be parallelized. for i1 in range(n): for i2 in range(i1 + 1, n): # determine start and end segment indices to iterate over if free_ends: start = max(starts[i1], starts[i2]) end = min(stops[i1], stops[i2]) else: start = min(starts[i1], starts[i2]) end = max(stops[i1], stops[i2]) # determine start position in the alignment pos = 0 for j in range(start): pos += lens[j] prev = 0 # previous state cumL = 0 # cumulative gap length # iterate over segments for j in range(start, end): L = lens[j] curr = bits[i1, j] + bits[i2, j] * 2 # gap in both sequences: ignore if curr == 3: pos += L continue # end of previous gap if prev and curr != prev: score -= gap_open + cumL * gap_extend # non-gap in both sequences: iterate by position within segment if curr == 0: for k in range(pos, pos + L): score += submat[seqs[i1, k], seqs[i2, k]] # gap in either sequence else: # gap in the same sequence continues if curr == prev: cumL += L # gap switches to a different sequence else: cumL = L if curr != prev: prev = curr pos += L # handle last gap if prev: score -= gap_open + cumL * gap_extend return score scikit-bio-scikit-bio-a3beaa6/skbio/alignment/_distance.py000066400000000000000000000231271520735541300237500ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from inspect import isfunction, getmodule from typing import Any, TYPE_CHECKING import numpy as np from skbio.stats.distance import DistanceMatrix from skbio.sequence.distance import ( _check_seqtype, _char_hash, _char_freqs, _check_gamma, ) import skbio.sequence.distance as sk_seqdist if TYPE_CHECKING: # pragma: no cover from collections.abc import Callable from skbio.alignment import TabularMSA def align_dists( alignment: TabularMSA, metric: str | Callable, shared_by_all: bool | None = True, **kwargs: Any, ) -> DistanceMatrix: r"""Create a distance matrix from a multiple sequence alignment. .. versionadded:: 0.7.2 This function calculates the distance between each pair of sequences based on the aligned sites, using a pre-defined distance metric or a custom function. The resulting distance matrix can be used for phylogenetic inference (see :mod:`skbio.tree`) or other types of distance-based analyses. Parameters ---------- alignment : TabularMSA of shape (n_sequences, n_positions) Multiple sequence alignment. metric : str or callable The distance metric to apply to each pair of aligned sequences. See :mod:`skbio.sequence.distance` for available metrics. Or supply a custom function that takes two sequence objects and returns a number. shared_by_all : bool, optional Calculate the distance between each pair of sequences based on sites shared across all sequences (True, default), or shared between the current pair of sequences (False). kwargs : dict, optional Metric-specific parameters. Refer to the documentation of the chosen metric. Returns ------- DistanceMatrix of shape (n_sequences, n_sequences) Distance matrix of aligned sequences. See Also -------- skbio.sequence.distance skbio.stats.distance.DistanceMatrix Notes ----- This function utilizes the preset metrics under :mod:`skbio.sequence.distance` to calculate pairwise sequence distances. These metrics have been optimized such that calling them through this function is significantly more efficient than directly calling them on every pair of sequences in an alignment. Custom functions may be provided but they may not have such acceleration. A "site" refers to a position in a sequence that has a valid character from an alphabet pre-defined by each metric. Typically, gaps are not considered as sites, and will be excluded from calculation. Some metrics are further restricted to certain characters, such as the four nucleobases or the 20 basic amino acids, while excluding degenerate and/or non-canonical characters. Sequences are filtered to aligned sites prior to calculation. This has two working modes: By default, alignment positions with at least one invalid character in any of the sequences are excluded from all sequences, leaving fully-aligned positions across the entire alignment. When ``shared_by_all`` is set to False, this filtering is applied to each pair of sequences, and positions with both characters valid are retained for calculation, even if there are invalid characters at the same position in other sequences. Some distance metrics require observed character frequencies (see the ``freqs`` parameter of individual metric functions). They will be sampled from the entire alignment using all sites prior to filtering. Therefore, distances calculated using this function may be unequal to distances calculated by calling the metric function on each pair of sequences, which would sample character frequencies from that pair of sequences specifically. If you wish to apply a custom function on each pair of sequences, without filtering sites or considering global character frequencies, use ``DistanceMatrix.from_iterable(alignment, function)`` instead. Examples -------- >>> from skbio.sequence import DNA >>> from skbio.alignment import TabularMSA, align_dists >>> msa = TabularMSA([ ... DNA('ATC-GTATCGG'), ... DNA('ATGCG--CCGC'), ... DNA('GTGCGTACGC-'), ... ], index=list("abc")) >>> dm = align_dists(msa, 'jc69') >>> print(dm) 3x3 distance matrix IDs: 'a', 'b', 'c' Data: [[ 0. 0.35967981 2.28339183] [ 0.35967981 0. 0.6354734 ] [ 2.28339183 0.6354734 0. ]] """ ids = alignment.index.astype(str) nseq, npos = alignment.shape # This is unusual. However, TabularMSA currently allows no sequence. if nseq == 0: raise ValueError("Alignment contains no sequence.") size = nseq * (nseq - 1) // 2 # Also, TabularMSA allows zero-length sequences. Just return a matrix of NaN. if npos == 0: return DistanceMatrix(np.full(size, np.nan), ids=ids) # determine preset or custom function func, preset = _get_preset(metric) name = func.__name__ # validate sequence type dtype = alignment.dtype seqtype = getattr(func, "_seqtype", None) _check_seqtype(name, dtype, seqtype) # get valid characters alphabet = getattr(func, "_alphabet", None) if alphabet is None and preset is False: alphabet = "nongap" valid = _char_hash(alphabet, dtype) # Create a 2D matrix of ASCII codes of all sequences. # TODO: This can be omitted after optimizing TabularMSA. seqs = np.vstack([seq._bytes for seq in alignment]) # Create a 2D Boolean mask of valid sites. site_mat = None if alphabet is None else valid[seqs] # Get character frequencies from the entire alignment. if getattr(func, "_has_freqs", None) is True and "freqs" not in kwargs: kwargs["freqs"] = _char_freqs(seqs, valid) # validate gamma if present if getattr(func, "_has_gamma", None) is True and "gamma" in kwargs: _check_gamma(kwargs["gamma"]) # Use a preset distance metric (efficient). if preset: func = getattr(sk_seqdist, "_" + name) # Delete positions that are not shared by all sequences (complete deletion). If # all positions are gone, return a NaN matrix. if shared_by_all and site_mat is not None: site_vec = np.all(site_mat, axis=0) seqs = seqs[:, site_vec] if seqs.shape[1] == 0: return DistanceMatrix(np.full(size, np.nan), ids=ids) site_mat = None # Otherwise, pass mask to the metric to trigger pairwise deletion. dm = func(seqs, site_mat, dtype, **kwargs) # Call a custom function on each pair of sequences (slow). else: dm = np.empty(size) # no deletion # TODO: This code block cannot be reached with the current implementation. # Needs refactoring. if site_mat is None: # pragma: no cover pos = -1 for i in range(nseq - 1): seq_i = alignment[i] for j in range(i + 1, nseq): dm[pos + j] = func(seq_i, alignment[j], **kwargs) pos += nseq - i - 2 # complete deletion elif shared_by_all: site_vec = np.all(site_mat, axis=0) seqs = [seq[site_vec] for seq in alignment] pos = -1 for i in range(nseq - 1): seq_i = seqs[i] for j in range(i + 1, nseq): dm[pos + j] = func(seq_i, seqs[j], **kwargs) pos += nseq - i - 2 # pairwise deletion else: pos = -1 for i in range(nseq - 1): seq_i = alignment[i] sites_i = site_mat[i] for j in range(i + 1, nseq): site_vec = sites_i & site_mat[j] seq1 = seq_i[site_vec] seq2 = alignment[j][site_vec] dm[pos + j] = func(seq1, seq2, **kwargs) pos += nseq - i - 2 return DistanceMatrix(dm, ids=ids) def _get_preset(metric): """Validate a present distance metric and return the underlying function. Parameters ---------- metric : str or callable The distance metric specified. Returns ------- func : callable Function that calculates this metric. preset : bool Whether the metric is a preset one under `skbio.sequence.distance`. """ if isinstance(metric, str): func = getattr(sk_seqdist, metric, None) if func is None or not isfunction(func) or not hasattr(func, "_is_metric"): raise ValueError( f"{metric!r} is not an available sequence distance metric name. Refer " "to `skbio.sequence.distance` for a list of available metrics." ) preset = True elif callable(metric): func = metric if getmodule(func) is sk_seqdist: if not isfunction(func) or not hasattr(func, "_is_metric"): raise ValueError( f"`{func.__name__}` is not a sequence distance metric. Refer to " "`skbio.sequence.distance` for a list of available metrics." ) preset = True else: preset = False else: raise TypeError("`metric` must be a function or a string.") return func, preset scikit-bio-scikit-bio-a3beaa6/skbio/alignment/_indexing.py000066400000000000000000000210561520735541300237620ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from abc import ABCMeta, abstractmethod import collections.abc import numpy as np import pandas as pd class _Indexing(metaclass=ABCMeta): def __init__(self, instance, axis=None): self._obj = instance self._axis = axis def __call__(self, axis=None): """Set the axis to index on.""" # verify axis param, discard value self._obj._is_sequence_axis(axis) return self.__class__(self._obj, axis=axis) def __getitem__(self, indexable): if self._axis is not None: if self._obj._is_sequence_axis(self._axis): return self._slice_on_first_axis(self._obj, indexable) else: return self._slice_on_second_axis(self._obj, indexable) if type(indexable) is tuple: if len(indexable) > 2: raise ValueError( "Can only slice on two axes. Tuple is length:" " %r" % len(indexable) ) elif len(indexable) > 1: return self._handle_both_axes(*indexable) else: (indexable,) = indexable return self._slice_on_first_axis(self._obj, indexable) def _handle_both_axes(self, seq_index, pos_index): seq_index = self._convert_ellipsis(seq_index) pos_index = self._convert_ellipsis(pos_index) if not hasattr(seq_index, "__iter__") and seq_index == slice(None): # Only slice second axis return self._slice_on_second_axis(self._obj, pos_index) else: r = self._slice_on_first_axis(self._obj, seq_index) if type(r) is self._obj.dtype: # [1, 1] [1, *] return r[pos_index] else: # [*, 1] [*, *] return self._slice_on_second_axis(r, pos_index) def _slice_on_second_axis(self, obj, indexable): indexable = self._convert_ellipsis(indexable) if self.is_scalar(indexable, axis=1): # [..., 1] return self._get_position(obj, indexable) else: # [..., *] return self._slice_positions(obj, indexable) def _slice_on_first_axis(self, obj, indexable): indexable = self._convert_ellipsis(indexable) if self.is_scalar(indexable, axis=0): # [1] return self._get_sequence(obj, indexable) else: # [*] return self._slice_sequences(obj, indexable) def _convert_ellipsis(self, indexable): if indexable is Ellipsis: return slice(None) return indexable @abstractmethod def is_scalar(self, indexable, axis): raise NotImplementedError @abstractmethod def _get_sequence(self, obj, indexable): raise NotImplementedError @abstractmethod def _slice_sequences(self, obj, indexable): raise NotImplementedError def _get_position(self, obj, indexable): return obj._get_position_(indexable) def _slice_positions(self, obj, indexable): indexable = self._assert_bool_vector_right_size(indexable, axis=1) indexable = self._convert_iterable_of_slices(indexable) return obj._slice_positions_(indexable) def _convert_iterable_of_slices(self, indexable): # _assert_bool_vector_right_size will have converted the iterable to # an ndarray if it wasn't yet. if isinstance(indexable, np.ndarray) and indexable.dtype == object: indexable = np.r_[tuple(indexable)] return indexable def _assert_bool_vector_right_size(self, indexable, axis): if isinstance(indexable, np.ndarray): pass elif hasattr(indexable, "__iter__"): indexable = np.asarray(list(indexable)) else: return indexable if indexable.dtype == bool and len(indexable) != self._obj.shape[axis]: raise IndexError( "Boolean index's length (%r) does not match the" " axis length (%r)" % (len(indexable), self._obj.shape[axis]) ) return indexable class TabularMSAILoc(_Indexing): def is_scalar(self, indexable, axis): return np.isscalar(indexable) def _get_sequence(self, obj, indexable): return obj._get_sequence_iloc_(indexable) def _slice_sequences(self, obj, indexable): indexable = self._assert_bool_vector_right_size(indexable, axis=0) indexable = self._convert_iterable_of_slices(indexable) return obj._slice_sequences_iloc_(indexable) class TabularMSALoc(_Indexing): def is_scalar(self, indexable, axis): """Check if an indexable object is scalar or not. Sometimes (MultiIndex!) something that looks like a scalar, isn't and vice-versa. Consider: A 0 1 2 B 0 1 2 'A' looks like a scalar, but isn't. ('A', 0) doesn't look like a scalar, but it is. """ index = self._obj.index complete_key = False partial_key = False duplicated_key = False if not isinstance(indexable, collections.abc.Hashable): return False if axis == 0 and self._has_fancy_index(): try: if type(indexable) is tuple: complete_key = ( len(indexable) == len(index.levshape) and indexable in index ) partial_key = not complete_key and indexable in index except ( TypeError, pd.errors.InvalidIndexError, ): # Unhashable type, no biggie pass if index.has_duplicates: # for a given Index object index, # index[index.duplicated()].unique() is pandas' recommended # replacement for index.get_duplicates(), per the pandas 0.23 docs duplicated_key = indexable in index[index.duplicated()].unique() return not duplicated_key and ( (np.isscalar(indexable) and not partial_key) or complete_key ) def _get_sequence(self, obj, indexable): self._assert_tuple_rules(indexable) return obj._get_sequence_loc_(indexable) def _slice_sequences(self, obj, indexable): self._assert_tuple_rules(indexable) if ( self._has_fancy_index() and type(indexable) is not tuple and pd.api.types.is_list_like(indexable) and len(indexable) > 0 ): if not self.is_scalar(indexable[0], axis=0): raise TypeError( "A list is used with complete labels, try" " using a tuple to indicate independent" " selections of a `pd.MultiIndex`." ) # prevents # pd.Series.loc[['x', 'b', 'b', 'a']] from being interepereted as # pd.Series.loc[[('a', 0), ('b', 1)]] who knows why it does this. elif indexable[0] not in self._obj.index: raise KeyError(repr(indexable[0])) # pandas acts normal if the first element is actually a scalar self._assert_bool_vector_right_size(indexable, axis=0) return obj._slice_sequences_loc_(indexable) def _assert_tuple_rules(self, indexable): # pandas is scary in what it will accept sometimes... if type(indexable) is tuple: if not self._has_fancy_index(): # prevents unfriendly errors raise TypeError( "Cannot provide a tuple to the first axis of" " `loc` unless the MSA's `index` is a" " `pd.MultiIndex`." ) elif self.is_scalar(indexable[0], axis=0): # prevents unreasonable results # pd.Series.loc[('a', 0), ('b', 1)] would be interpreted as # pd.Series.loc[('a', 1)] which is horrifying. raise TypeError( "A tuple provided to the first axis of `loc`" " represents a selection for each index of a" " `pd.MultiIndex`; it should not contain a" " complete label." ) def _has_fancy_index(self): return hasattr(self._obj.index, "levshape") scikit-bio-scikit-bio-a3beaa6/skbio/alignment/_pair.py000066400000000000000000001335071520735541300231150ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from typing import Any, NamedTuple, TYPE_CHECKING import numpy as np from skbio.alignment import PairAlignPath from ._utils import encode_sequences, prep_gapcost from ._cutils import ( _fill_linear_matrix, _fill_affine_matrices, _trace_one_linear, _trace_one_affine, ) if TYPE_CHECKING: # pragma: no cover from skbio.sequence import SubstitutionMatrix from ._utils import SequenceLike class PairAlignResult(NamedTuple): score: float paths: list[PairAlignPath] | None = None matrices: tuple[np.ndarray, ...] | None = None def pair_align( seq1: SequenceLike, seq2: SequenceLike, /, mode: str = "global", sub_score: tuple[float, float] | SubstitutionMatrix | str = (1.0, -1.0), gap_cost: float | tuple[float, float] = 2.0, free_ends: bool | tuple[bool, bool] | tuple[bool, bool, bool, bool] = True, trim_ends: bool = False, max_paths: int | None = 1, atol: float = 1e-5, keep_matrices: bool = False, ) -> PairAlignResult: r"""Perform pairwise alignment of two sequences. A versatile, efficient and generalizable function for pairwise alignment using dynamic programming. It supports: * Global, local and semi-global alignments (with all four ends customizable). * Nucleotide, protein, and un-grammared sequences, plain strings (ASCII and Unicode), words/tokens, and numbers. * Match/mismatch scores or substitution matrix. * Linear and affine gap penalties. * Integer, decimal and infinite scores. * Returning one, multiple or all optimal alignment paths. .. versionadded:: 0.7.0 Parameters ---------- seq1 : :class:`~skbio.sequence.Sequence`, str, or sequence of scalar The first sequence to be aligned. seq2 : :class:`~skbio.sequence.Sequence`, str, or sequence of scalar The second sequence to be aligned. mode : {'global', 'local'}, optional Mode of alignment. Options are: - "global" (default): Global alignment, as in the Needleman-Wunsch algorithm. The two sequences are aligned end-to-end. See also ``free_ends`` below. - "local": Local alignment, as in the Smith-Waterman algorithm. It identifies similar regions between two sequences. sub_score : tuple of (float, float), SubstitutionMatrix, or str, optional Score of a substitution. May be one of the following: - Tuple of two numbers: Match score (same symbol) and mismatch score (different symbols). - :class:`~skbio.sequence.SubstitutionMatrix`: A matrix of substitution scores between all symbols in the alphabet. - String: Name of the substitution matrix that can be recognized by ``SubstitutionMatrix.by_name``, such as "NUC.4.4" or "BLOSUM62". Default is (1.0, -1.0) (match, mismatch). gap_cost : float or tuple of (float, float), optional Penalty of a gap. Values are usually positive, representing subtractions from the alignment score. May be one of the following: - One number: Linear gap penalty. Each gap position is penalized by this value (*g*). A contiguous gap of length *k* has a total penalty of *g* * *k*. - Tuple of two numbers: Affine gap penalty. The two numbers (*o*, *e*) represent gap opening penalty and gap extension penalty, respectively. A contiguous gap of length *k* has a total penalty of *o* + *e* * *k*. See also notes below. Default is 2.0 (linear gap penalty). .. note:: Infinites are valid values for ``sub_score`` and ``gap_cost``. For example, ``gap_cost=np.inf`` disables gaps. ``sub_score=(..., -np.inf)`` disables mismatches. free_ends : bool, 2-tuple of bool, or 4-tuple of bool, optional Whether gaps at the sequence terminals are free from penalization. Relevant when ``mode`` is "global". Alignment with free ends is known as semi-global (or "glocal") alignment. Values can be: - False: Penalize terminal gaps using the same method defined by ``gap_cost``. This behavior is the true global alignment. - True: Do not penalize any terminal gap. This behavior is known as "overlap", as it identifies the maximum overlap between two sequences. - Tuple of two Booleans: Whether terminal gaps of seq1 and seq2 are free, respectively. For example, (True, False) is the typical semi-global alignment, useful for aligning a short seq1 within a long seq2. - Tuple of four Booleans: Whether leading gap of seq1, trailing gap of seq1, leading gap of seq2, and trailing gap of seq2 are free, respectively. For example, (False, True, True, False) joins the tail of seq1 with the head of seq2. Default is True (overlap). trim_ends : bool, optional If True, penalty-free terminal gaps defined by ``free_ends`` will be excluded from returned paths. Useful for locating a short query in a long reference. Default is False. max_paths : int, optional Maximum number of alignment paths to return. Default is 1, which is generated through a performance-oriented traceback algorithm. A value larger than 1 will trigger a less efficient traceback algorithm to enumerate up to this number of paths. Setting it as None will return all paths. However, be cautious that the total number of paths may be extremely large. Setting it as 0 will disable traceback and return no path (None). .. note:: When ``mode="local"``, it is possible that there is no path with a score > 0. In this case, an empty list will be returned. ``mode="global"`` guarantees to return at least one path, even if it's completely misaligned. atol : float, optional Absolute tolerance in comparing scores of alternative alignment paths. This is to ensure floating-point arithmetic safety when ``sub_score`` or ``gap_cost`` involve decimal numbers. Default is 1e-5. Setting it to 0 or None will slightly increase performance, and is usually safe when there are only integers (e.g., 2.0) or half integers (e.g., 2.5) involved. .. note:: Relative tolerance is not involved in the calculation. keep_matrices : bool, optional Whether to include the alignment matrix(ces) in the returned value. They are typically for diagnostic or educational purposes. Default is False, which lets the memory space free up after the function finishes. Returns ------- score : float Optimal alignment score. paths : list of :class:`~skbio.alignment.PairAlignPath`, optional Alignment paths. Up to ``max_paths`` paths will be returned. Note that all paths are optimal and share the same alignment score. matrices : tuple of ndarray of shape (m + 1, n + 1), optional Alignment matrices generated during the computation (if ``keep_matrices`` is True). *m* and *n* are the lengths of seq1 and seq2, respectively. - For linear gap penalty, one main matrix will be returned. - For affine gap penalty, the main matrix, plus an insertion matrix (gap in seq1) and a deletion matrix (gap in seq2) will be returned. See Also -------- align_score skbio.alignment.PairAlignPath Notes ----- This function implements the classic dynamic programming (DP) method for pairwise sequence alignment. It is commonly known as the Needleman-Wunsch algorithm [1]_ for global alignment, or the Smith-Waterman algorithm [2]_ for local alignment. These two algorithms use linear gap penalty. When affine gap penalty is specified, the underlying method is the Gotoh algorithm [3]_, with later modifications [4]_. The algorithms are exact and the output alignments are guaranteed to be optimal. The algorithms are quadratic (*O*\(*mn*\)) in both time and space, where *m* and *n* are the lengths of the two sequences, respectively. Affine gap penalty costs 3x as much memory and 2-3x as much runtime than linear gap penalty. **Parameters** The default parameters ``sub_score=(1, -1), gap_cost=2`` is a simple scoring scheme that quickly captures sequence similarity. However, in bioinformatics applications, one usually wants to replace them with more realistic parameters according to the specific task. For reference, below are the default parameters of some common bioinformatics programs: - NCBI MegaBLAST (nucleotide): ``sub_score=(1, -2), gap_cost=2.5`` - NCBI BLASTN (nucleotide): ``sub_score=(2, -3), gap_cost=(5, 2)`` (see also :func:`pair_align_nucl`) - NCBI BLASTP (protein): ``sub_score="BLOSUM62", gap_cost=(11, 1)`` (see also :func:`pair_align_prot`) - EMBOSS Needle/Water (protein): ``sub_score="BLOSUM62", gap_cost=(9.5, 0.5)`` (for nucleotide, replace ``sub_score`` with ``"NUC.4.4"``) - EBI FASTA (protein): ``sub_score="BLOSUM50", gap_cost=(8, 2)`` .. note:: These are scoring schemes only. ``pair_align`` does not reproduce the output of the programs mentioned. The flexibility of these parameters, especially the support for infinity, enables some common tasks in text analysis: - Edit (Levenshtein) distance: ``sub_score=(0, -1), gap_cost=1`` (negate the score to get the distance) - Longest common subsequence (LCS): ``mode="local", sub_score=(1, -np.inf), gap_cost=0`` - Longest common substring: ``mode="local", sub_score=(1, -np.inf), gap_cost=np.inf`` **Input sequences** The format of input sequences is flexible. The function is most efficient when they are subclasses of :class:`~skbio.sequence.GrammaredSequence`, such as ``DNA`` and ``Protein``, or any user-customized class. They have a finite alphabet, and permit auto-replacing degenerate codes with wildcard (such as nucleotides to "N" and amino acids to "X"), as long as the substitution matrix has the wildcard character. For non-grammared sequences, such as plain strings, bytes, and integer arrays, the the function will attempt to encode them into ASCII codes (*n* = 128), which permit efficient indexing. If ASCII encoding is not possible (for example lists of words, large or negative integers, or floats), unique symbols will be extracted from the sequences and indexed. **Performance** The underlying dynamic programming kernel is a plain dual loop structure, without further vectorization or parallelization techniques. This function does not discriminate between seq1 and seq2. Nevertheless, aligning a shorter seq1 (often referred to as "query") against a longer seq2 (often referred to as "target" or "reference") is usually more efficient than the other way around. The algorithm defaults to float32, which is sufficient for most use cases. It also supports float64, with a higher memory cost (2x) and moderately increased runtime. If float64 is what you need, you may supply a substitution matrix of float64 type, using e.g., ``SubstitutionMatrix.identity("ACGT", 1, -2, dtype="float64")``, which will be respected by the function without casting throughout calculation. **Affine gap penalty** Under the affine gap penalty mode, the penalty of a contiguous gap of length :math:`k` is calculated as: .. math:: G(k) = o + e \times k \tag{1} where :math:`o` is the gap opening penalty and :math:`e` is the gap extension penalty. It should be noted that, discrepancy exists among literature and implementations regarding whether gap extension penalty should apply to the first position of a gap. scikit-bio's equation is consistent with multiple common alignment tools, such as BLAST [5]_, Minimap2, SeqAn3, and WFA2-lib. Meanwhile, multiple other tools, such as EMBOSS, parasail, Biopython and Biotite, use the following equation instead: .. math:: G(k) = o + e \times (k - 1) \tag{2} Therefore, if you intend to reproduce the behavior of a software tool of the latter category using scikit-bio, you will need to subtract :math:`e` from :math:`o` when adopting its parameters. For example, EMBOSS' default parameters ``o=10, e=0.5`` will become ``o=9.5, e=0.5`` in scikit-bio. Vice versa. .. versionchanged:: 0.7.0 Previous alignment algorithms in scikit-bio used Eq. 2. These functions were deprecated in 0.5.x and will be removed in 0.6.x. Future functions will uniformly use Eq. 1. Related: A simple but less common scenario is constant gap penalty, where a contiguous gap has a constant penalty :math:`g` regardless of its length. This can be specified as ``gap_cost=(g, 0)``. References ---------- .. [1] Needleman, S. B., & Wunsch, C. D. (1970). A general method applicable to the search for similarities in the amino acid sequence of two proteins. J Mol Biol, 48(3), 443-453. .. [2] Smith, T. F., & Waterman, M. S. (1981). Identification of common molecular subsequences. J Mol Biol, 147(1), 195-197. .. [3] Gotoh, O. (1982). An improved algorithm for matching biological sequences. J Mol Biol, 162(3), 705-708. .. [4] Altschul, S. F., & Erickson, B. W. (1986). Optimal sequence alignment using affine gap costs. Bull Math Biol, 48, 603-616. .. [5] https://www.ncbi.nlm.nih.gov/books/NBK62051/ Examples -------- >>> from skbio.sequence import DNA, Protein >>> from skbio.alignment import pair_align Align two DNA sequences using default parameters (global alignment with free end gaps, match/mismatch scores, linear gap penalty, returning just one path): >>> seq1 = DNA('ACTACCAGATTACTTACGGATCAGGTACTTGCCAACAA') >>> seq2 = DNA('CGAAACTACTAGATTACGGATCTTACTTTCCAGCAAGG') >>> res = pair_align(seq1, seq2) The result is a named tuple consisting of score, path(s), and matrices (off by default). The score represents the "goodness" of the alignment. >>> res.score 12.0 The alignment path can be represented by a :wiki:`CIGAR string ` . See :class:`PairAlignPath` for details. >>> path = res.paths[0] >>> path Extract aligned sequences: >>> aln = path.to_aligned((seq1, seq2)) >>> aln ['----ACTACCAGATTACTTACGGATCAGGTACTTGCCAACAA--', 'CGAAACTACTAGATTAC----GGATCT--TACTTTCCAGCAAGG'] Alternatively, you can do ``TabularMSA.from_path_seqs(path, (seq1, seq2))`` to create a dedicated sequence alignment structure. See :class:`TabularMSA` for details. Align two protein sequences using local alignment, substitution matrix, and affine gap penalty (the default parameters of BLASTP): >>> seq1 = Protein('MKRTLKGHFVQWC') >>> seq2 = Protein('MQMLKTHYAQTRN') >>> score, paths, _ = pair_align(seq1, seq2, mode='local', ... sub_score='BLOSUM62', gap_cost=(11, 1)) >>> score 23.0 >>> paths[0].to_aligned((seq1, seq2)) ['LKGHFVQ', 'LKTHYAQ'] Search a sequencing read against a reference genome using the default parameters of MegaBLAST and return locations of all hits. >>> query = "ACCGT" >>> target = "AAACGCTACCGTCCGTAGACCGTGACCGTGCGAAGC" >>> score, paths, _ = pair_align(query, target, mode='global', ... sub_score=(1, -2), gap_cost=2.5, ... free_ends=(True, False), trim_ends=True, ... max_paths=None) >>> len(paths) 3 >>> for x in paths: ... print(x.ranges[1]) [ 7 12] [18 23] [24 29] Note: ``ranges[1]`` stores the start and stop positions of the aligned region in the target (``ranges[0]`` stores those of the query). The numbers are BED-like (i.e., 0-based, half-open). Calculate the edit distance between two sentences (lists of words). >>> text1 = 'The quick brown fox jumps over the lazy dog'.split() >>> text2 = 'The slow brown wolf jumps over a lazy dog'.split() >>> res = pair_align(text1, text2, mode='global', ... sub_score=(0, -1), gap_cost=1, ... free_ends=False, max_paths=0) >>> -int(res.score) 3 """ # This function implements the classic dynamic programming method for pairwise # sequence alignment. While the most time-consuming step (matrix filling) is done # in Cython, this function retains as many steps as possible in Python, thereby # "outsourcing" computation and optimization to the upstream library (NumPy). # Determine alignment mode (False - global, True - local) local = _prep_mode(mode) # Determine end gap policy. These are ternary flags (0 - penalize, 1 - free and # keep, 2 - free and trim). lead1, trail1, lead2, trail2 = _prep_free_ends(local, free_ends, trim_ends) # Prepare sequences and substitution matrix. # If `sub_score` consists of match/mismatch scores, an identity matrix will be # created or retrieved from cache. The two sequences are converted into indices in # the substitution matrix, which facilitate lookup and memory locality. (seq1, seq2), submat, _ = encode_sequences((seq1, seq2), sub_score) # Profile seq1 (query), which will be aligned against seq2 (target). # The profile is essentially a position-specific scoring matrix (PSSM). This design # is useful for future implementation of profile search (like PSI-BLAST) and one- # vs-many search. # Query and target must be C-contiguous for efficient loops. submat, seq1 and seq2 # are guaranteed to be C-contiguous by upstream code. submat[seq1] should be C- # contiguous too due to NumPy's advanced indexing. But `ascontiguousarray` is still # called here to be safe. query, target = np.ascontiguousarray(submat[seq1]), seq2 dtype = query.dtype.type # Prepare affine or linear gap penalties. gap_open, gap_extend = prep_gapcost(gap_cost, dtype=dtype) affine = gap_open != 0 # Allocate alignment matrices. # There is one matrix for linear gap penalty or three matrices for affine gap # penalty. Each matrix is (m + 1) by (n + 1). They can become quite large and # challenge the memory capacity. To overcome this, future implementation of # Hirschberg's algorithm with linear space is desired. matrices = _alloc_matrices(query.shape[0], target.size, affine, dtype=dtype) # Initialize alignment matrices. _init_matrices(matrices, gap_open, gap_extend, local, lead1, lead2) # Fill alignment matrices (quadratic; compute-intensive). if affine: _fill_affine_matrices(*matrices, query, target, gap_open, gap_extend, local) else: _fill_linear_matrix(matrices[0], query, target, gap_extend, local) # Get optimal alignment score and corresponding stop(s). if max_paths == 1 or max_paths == 0: score, stops = _one_stop(matrices[0], local, trail1, trail2) else: score, stops = _all_stops(matrices[0], local, trail1, trail2) # Traceback from each stop to reconstruct optimal alignment path(s). args = (gap_open, gap_extend, local, lead1, lead2, trail1, trail2, atol) if max_paths == 0: # traceback is disabled paths = None elif local and abs(score) <= atol: # no path is found paths = [] elif max_paths == 1: i, j = stops[0] paths = [_traceback_one(i, j, matrices, *args)] else: paths = _traceback_all(stops, max_paths, matrices, query, target, *args) # Discard or keep matrices. if not keep_matrices: matrices = None elif affine: _fill_nan(matrices) return PairAlignResult(float(score), paths, matrices) def pair_align_nucl( seq1: SequenceLike, seq2: SequenceLike, /, **kwargs: Any, ) -> PairAlignResult: r"""Align two nucleotide sequences. This is a convenience wrapper of ``pair_align`` for nucleotide sequence alignment. It is preloaded with a scoring scheme consistent with BLASTN's defaults [1]_: match score = 2, mismatch score = -3, gap opening penalty = 5, gap extension penalty = 2. All parameters remain customizable. Refer to :func:`pair_align` for full documentation. See Also -------- pair_align pair_align_prot References ---------- .. [1] https://www.ncbi.nlm.nih.gov/books/NBK279684/ Examples -------- >>> from skbio.sequence import DNA >>> from skbio.alignment import pair_align_nucl >>> seq1 = DNA('GATCGTC') >>> seq2 = DNA('ATCGCTC') >>> res = pair_align_nucl(seq1, seq2) >>> res.score 5.0 >>> res.paths[0] >>> res.paths[0].to_aligned((seq1, seq2)) ['GATCG-TC', '-ATCGCTC'] """ params: dict[str, Any] = dict(sub_score=(2.0, -3.0), gap_cost=(5.0, 2.0)) params.update(kwargs) return pair_align(seq1, seq2, **params) def pair_align_prot( seq1: SequenceLike, seq2: SequenceLike, /, **kwargs: Any, ) -> PairAlignResult: r"""Align two protein sequences. This is a convenience wrapper of ``pair_align`` for protein sequence alignment. It is preloaded with a scoring scheme consistent with BLASTP's defaults [1]_: substitution matrix = BLOSUM62, gap opening penalty = 11, gap extension penalty = 1. All parameters remain customizable. Refer to :func:`pair_align` for full documentation. See Also -------- pair_align pair_align_nucl References ---------- .. [1] https://www.ncbi.nlm.nih.gov/books/NBK279684/ Examples -------- >>> from skbio.sequence import Protein >>> from skbio.alignment import pair_align_prot >>> seq1 = Protein('PKKKRKV') >>> seq2 = Protein('PAAKRVKLD') >>> res = pair_align_prot(seq1, seq2) >>> res.score 11.0 >>> res.paths[0] >>> res.paths[0].to_aligned((seq1, seq2)) ['PKKKRKV--', 'PAAKRVKLD'] """ params: dict[str, Any] = dict(sub_score="BLOSUM62", gap_cost=(11.0, 1.0)) params.update(kwargs) return pair_align(seq1, seq2, **params) def _prep_mode(mode): """Prepare pairwise alignment mode. Parameters ---------- mode : str Alignment mode. Returns ------- bool Whether alignment mode is local. """ if mode == "global": return False elif mode == "local": return True else: raise ValueError(f"Invalid mode: {mode}.") def _prep_free_ends(local, free_ends, trim_ends): """Prepare end gap policy for pairwise alignment. Parameters ---------- local : bool Local or global alignment. free_ends : bool, (bool, bool), or (bool, bool, bool, bool) Free ends policy. trim_ends : bool End trimming policy. Returns ------- 4-tuple of {0, 1, 2} Ternary flags. Positions: 0. Leading gaps of sequence 1. 1. Trailing gaps of sequence 1. 2. Leading gaps of sequence 2. 3. Trailing gaps of sequence 2. Codes: 0. Penalize. 1. Free and keep. 2. Free and trim. """ # not relevant if local: return 2, 2, 2, 2 trim = bool(trim_ends) # all four ends if np.isscalar(free_ends): free = bool(free_ends) free += free and trim return free, free, free, free # both ends for seq1 and seq2 elif (n := len(free_ends)) == 2: free1, free2 = (x + (x and trim) for x in map(bool, free_ends)) return free1, free1, free2, free2 # leading and trailing ends for seq1 and seq2 elif n == 4: return tuple(x + (x and trim) for x in map(bool, free_ends)) else: raise ValueError("`free_ends` must be one, two or four Booleans.") def _alloc_matrices(m, n, affine, dtype=np.float32): """Allocate alignment matrix(ces). Parameters ---------- m, n: int Lengths of sequences 1 and 2, respectively. affine : bool Affine (True) or linear (False) gap penalty. dtype : type, optional Data type (np.float32 or np.float64). Returns ------- tuple of ndarray of shape (m + 1, n + 1) Alignment matrix(ces). Notes ----- The arrays should be C-contiguous to facilitate row-major operations. NumPy's default array is already C-contiguous. This is also enforced by the unit test. """ shape = (m + 1, n + 1) scomat = np.empty(shape, dtype=dtype) if not affine: return (scomat,) insmat = np.empty(shape, dtype=dtype) delmat = np.empty(shape, dtype=dtype) return scomat, insmat, delmat def _init_matrices(matrices, gap_open, gap_extend, local, lead1, lead2): """Initialize alignment matrix(ces) by populating first column and row. Parameters ---------- matrices : tuple of ndarray of shape (m + 1, n + 1) Alignment matrices. gap_open : float Gap opening penalty. gap_extend : float Gap extension penalty. local : bool Local or global alignment. lead1, lead2 : bool Whether leading gaps of sequence 1 and 2 are free. Notes ----- The initial values in the insertion and deletion matrices are -inf, which follows conventions and should be correct. However, one should note from Flouri et al. (2015) [1]_ that the original Gotoh algorithm (1982) made a mistake in it by using gap_open + k * gap_extend. Flouri et al. suggested that the minimum values must be 2 * gap_open + k * gap_extend. References ---------- .. [1] Flouri, T., Kobert, K., Rognes, T., & Stamatakis, A. (2015). Are all global alignment algorithms and implementations correct?. bioRxiv, 031500. """ scomat = matrices[0] m1, n1 = scomat.shape # initialize main scoring matrix scomat[0, 0] = 0 if local: scomat[1:m1, 0] = 0 scomat[0, 1:n1] = 0 else: series = np.arange(1, max(m1, n1), dtype=scomat.dtype) series *= -gap_extend if gap_open: series -= gap_open scomat[1:m1, 0] = 0 if lead2 else series[: m1 - 1] scomat[0, 1:n1] = 0 if lead1 else series[: n1 - 1] # initialize insertion and deletion matrices if gap_open: insmat = matrices[1] delmat = matrices[2] insmat[1:m1, 0] = -np.inf delmat[0, 1:n1] = -np.inf # Flouri's minimum value (see Notes): # series -= gap_open # insmat[1:m1, 0] = series[:m1 - 1] # delmat[0, 1:n1] = series[:n1 - 1] def _fill_nan(matrices): """Fill empty cells of affine matrices with NaN before returning. These are not useful during alignment, but can make things less confusing for diagnostic or educational purposes. This function supports arbitrary number of affine pieces. """ n = len(matrices) # odd numbers are insertion matrices for i in range(1, n, 2): matrices[i][0, :] = np.nan # even numbers are deletion matrices for i in range(2, n, 2): matrices[i][:, 0] = np.nan def _one_stop(scomat, local, trail1, trail2): """Locate one stop with optimal alignment score. Parameters ---------- scomat : ndarray of shape (m + 1, n + 1) Main matrix. local : bool Local or global alignment. trail1, trail2 : bool Whether trailing gaps of sequence 1 and 2 are free. Returns ------- float Optimal alignment score. ndarray of int of shape (1, 2) Coordinates of one alignment stop. Notes ----- When there is a tie, the smallest index (row, column) is chosen. """ m = scomat.shape[0] - 1 n = scomat.shape[1] - 1 # local alignment: maximum cell in the matrix if local: i, j = np.unravel_index(scomat.argmax(), scomat.shape) # semi-global alignment # free trailing gaps for both: maximum cell in the last column and row elif trail1 and trail2: i = scomat[:m, n].argmax() # last column (ends with deletion) j = scomat[m, :].argmax() # last row (ends with insertion) if scomat[i, n] >= scomat[m, j]: j = n else: i = m # free trailing gaps in seq1: maximum in last row elif trail1: i, j = m, scomat[m, :].argmax() # free trailing gaps in seq2: maximum in last column elif trail2: i, j = scomat[:, n].argmax(), n # global alignment: bottom right cell else: i, j = m, n return scomat[i, j], np.array([[i, j]]) def _all_stops(scomat, local, trail1, trail2, eps=1e-5): """Locate all stops with optimal alignment score. Parameters ---------- scomat : ndarray of shape (m + 1, n + 1) Main matrix. local : bool Local or global alignment. trail1, trail2 : bool Whether trailing gaps of sequence 1 and 2 are free. eps : float, optional Absolute tolerance. Default is 1e-5. Returns ------- float Optimal alignment score. ndarray of int of shape (k, 2) Coordinates of all (k) alignment stops. Notes ----- Coordinates (row, column) are sorted in ascending order. """ m = scomat.shape[0] - 1 n = scomat.shape[1] - 1 # local alignment if local: best = scomat.max() if eps: test = np.isclose(scomat, best, rtol=0, atol=eps) else: test = scomat == best return best, np.argwhere(test) # semi-global alignment, free trailing gaps for both elif trail1 and trail2: col_n, row_m = scomat[:m, n], scomat[m, :] best = np.max([col_n.max(), row_m.max()]) if eps: test1 = np.isclose(col_n, best, rtol=0, atol=eps) test2 = np.isclose(row_m, best, rtol=0, atol=eps) else: test1 = col_n == best test2 = row_m == best ii = np.argwhere(test1) jj = np.argwhere(test2) return best, np.vstack( ( np.column_stack((ii, np.full(ii.shape[0], n))), np.column_stack((np.full(jj.shape[0], m), jj)), ) ) # free trailing gaps in seq1 elif trail1: row_m = scomat[m, :] best = row_m.max() jj = np.argwhere( np.isclose(row_m, best, rtol=0, atol=eps) if eps else row_m == best ) return best, np.column_stack((np.full(jj.shape[0], m), jj)) # free trailing gaps in seq2 elif trail2: col_n = scomat[:, n] best = col_n.max() ii = np.argwhere( np.isclose(col_n, best, rtol=0, atol=eps) if eps else col_n == best ) return best, np.column_stack((ii, np.full(ii.shape[0], n))) # global alignment else: return scomat[m, n], np.array([[m, n]]) def _encode_path(path, i0, i1, j0, j1): """Perform run-length encoding (RLE) on a dense alignment path. Parameters ---------- path : ndarray of uint8 of shape (n_positions,) Dense alignment path. i0, i1 : int Start and stop positions in sequences 1, respectively. j0, j1 : int Start and stop positions in sequences 2, respectively. Returns ------- PairAlignPath Encoded alignment path. See Also -------- skbio.alignment.AlignPath.from_bits """ if L := path.size: segs = np.append(0, np.flatnonzero(path[:-1] != path[1:]) + 1) lens = np.append(segs[1:] - segs[:-1], L - segs[-1]) ints = path[segs] else: lens = np.array([], dtype=np.intp) ints = path ranges = np.array([[i0, i1], [j0, j1]], dtype=np.intp) return PairAlignPath(lens, ints, ranges=ranges) def _trailing_gaps(path, pos, i, j, m, n, fill1, fill2): """Fill trailing gaps before traceback starts. Parameters ---------- path : ndarray of uint8 of shape (n_positions,) Dense alignment path. pos : int Current start position of the path. i, j: int Current row and column indices in the matrix. m, n : int Last row and column indices in the matrix (lengths of seq1 and seq2). fill1, fill2 : bool Fill trailing gaps in sequences 1 and 2, respectively. Returns ------- int Updated start position of the path. int, int Stop positions of the path in sequences 1 and 2, respectively. """ # bottom row: ends with insertions (gaps in seq1) if fill1 and i == m and j < n: pos -= n - j path[pos:] = 1 return pos, m, n # right-most column: ends with deletions (gaps in seq2) elif fill2 and j == n and i < m: pos -= m - i path[pos:] = 2 return pos, m, n else: return pos, i, j def _leading_gaps(path, pos, i, j, fill1, fill2): """Fill leading gaps after traceback ends. Parameters ---------- path : ndarray of uint8 of shape (n_positions,) Dense alignment path. pos : int Current start position of the path. i, j: int Current row and column indices in the matrix. fill1, fill2 : bool Fill leading gaps in sequences 1 and 2, respectively. Returns ------- int Updated start position of the path. int, int Start positions of the path in sequences 1 and 2, respectively. """ stop = pos # top row: starts with insertions (gaps in seq1) if fill1 and i == 0 and j > 0: pos -= j path[pos:stop] = 1 return pos, 0, 0 # left-most column: starts with deletions (gaps in seq2) elif fill2 and j == 0 and i > 0: pos -= i path[pos:stop] = 2 return pos, 0, 0 else: return pos, i, j def _traceback_one( i, j, matrices, gap_open, gap_extend, local=False, lead1=0, lead2=0, trail1=0, trail2=0, eps=1e-5, ): """Traceback and return one optimal alignment path. Parameters ---------- i, j : int Stop positions in sequences 1 and 2, respectively. matrices : tuple of ndarray of float of shape (m + 1, n + 1) Alignment matrices. gap_open : float Gap opening penalty. gap_extend : float Gap extension penalty. local : bool, optional Global (False) or local (True) alignment. lead1, lead2, trail1, trail2 : int, optional If =2, trim leading / trailing gaps of sequences 1 / 2, respectively. eps : float, optional Absolute tolerance. Returns ------- PairAlignPath Optimal alignment path. See Also -------- _traceback_all Notes ----- This function pre-allocates memory space for the path, which has a maximum length of m + n (assuming none of the characters are aligned). Each element represents the gap status of one position in the alignment: 0: no gap 1: gap in seq1 2: gap in seq2 The path will be filled in reverse order (from stop to start, i.e., trace*back*). After the path is completed, run-length encoding (RLE) will be performed to compress it into a compact form. Alternatively, one can encode the path while constructing it, which reduces memory consumption. However, that will complicate Cythonization (it will need C++ vector). There is no obvious runtime difference between the two methods. """ scomat = matrices[0] m = scomat.shape[0] - 1 n = scomat.shape[1] - 1 # current start position of the path, i.e., the index right *after* the next # position to be filled. pos = m + n # allocate space for path path = np.empty(pos, dtype=np.uint8) # fill trailing gaps (from edge to bottom-right cell). pos, i1, j1 = _trailing_gaps(path, pos, i, j, m, n, trail1 < 2, trail2 < 2) # Traceback matrix body. This is a time-consuming step. However, it is O(m + n), # thus is faster than the matrix filling step. if gap_open: pos, i, j = _trace_one_affine( path, pos, i, j, *matrices, gap_extend, local, eps ) else: pos, i, j = _trace_one_linear(path, pos, i, j, scomat, gap_extend, local, eps) # fill leading gaps (from top-left cell to edge). pos, i0, j0 = _leading_gaps(path, pos, i, j, lead1 < 2, lead2 < 2) # encode path return _encode_path(path[pos:], i0, i1, j0, j1) """Encodings of moving directions during traceback. Columns are: 0. Row offset (i) - Can be calculated with (state & 1) ^ 1 1. Column offset (j) - Can be calculated with (state >> 1) ^ 1 2. Gap state 0. Substitution (no gap) 1. Insertion (gap in seq1) 2. Deletion (gap in seq2) 3. Invalid state 3. Matrix index 0. Main matrix 1. Insertion matrix (affine) 2. Deletion matrix (affine) 3. Insertion matrix 2 (2-piece affine) 4. Deletion matrix 2 (2-piece affine) """ MOVES = np.array( [ [1, 1, 0, 0], # substitution [0, 1, 1, 0], # insertion [1, 0, 2, 0], # deletion [0, 1, 1, 1], # extend insertion [1, 0, 2, 2], # extend deletion [0, 0, 3, 1], # jump to insertion matrix [0, 0, 3, 2], # jump to deletion matrix [0, 1, 1, 3], # extend insertion 2 [1, 0, 2, 4], # extend deletion 2 [0, 0, 3, 3], # jump to insertion matrix 2 [0, 0, 3, 4], # jump to deletion matrix 2 ] ) def _linear_moves(i, j, scomat, query, target, gap, eps): """Identify move direction(s) at a cell with linear gap penalty. Parameters ---------- i, j : int Current row and column indices in the matrix, respectively. scomat : ndarray of shape (m + 1, n + 1) Main matrix. query : ndarray of float of shape (m, n_symbols) Query profile. target : ndarray of int of shape (n,) Target sequence. gap : float Gap penalty. eps : float Absolute tolerance. Returns ------- list of int Move directions. """ score = scomat[i, j] moves = [] if ( abs(scomat[i - 1, j - 1] + query[i - 1, target[j - 1]] - score) <= eps ): # substitution moves.append(0) if abs(scomat[i, j - 1] - gap - score) <= eps: # insertion moves.append(1) if abs(scomat[i - 1, j] - gap - score) <= eps: # deletion moves.append(2) return moves def _affine_moves(i, j, mat, scomat, insmat, delmat, query, target, gap_oe, gap_e, eps): """Identify move direction(s) at a cell with affine gap penalty. Parameters ---------- i, j : int Current row and column indices in the matrix, respectively. mat : int Current matrix index. scomat : ndarray of shape (m + 1, n + 1) Main matrix. insmat : ndarray of shape (m + 1, n + 1) Insertion matrix. delmat : ndarray of shape (m + 1, n + 1) Deletion matrix. query : ndarray of float of shape (m, n_symbols) Query profile. target : ndarray of int of shape (n,) Target sequence. gap_oe : float Gap opening + extension penalty. gap_e : float Gap extension penalty. eps : float Absolute tolerance. Returns ------- list of int Move directions. """ moves = [] # main matrix if mat == 0: score = scomat[i, j] if ( abs(scomat[i - 1, j - 1] + query[i - 1, target[j - 1]] - score) <= eps ): # substitution moves.append(0) if abs(insmat[i, j] - score) <= eps: # jump to insertion matrix moves.append(5) if abs(delmat[i, j] - score) <= eps: # jump to deletion matrix moves.append(6) # insertion matrix elif mat == 1: score = insmat[i, j] if abs(scomat[i, j - 1] - gap_oe - score) <= eps: # open insertion moves.append(1) if abs(insmat[i, j - 1] - gap_e - score) <= eps: # extend insertion moves.append(3) # deletion matrix else: score = delmat[i, j] if abs(scomat[i - 1, j] - gap_oe - score) <= eps: # open deletion moves.append(2) if abs(delmat[i - 1, j] - gap_e - score) <= eps: # extend deletion moves.append(4) return moves def _traceback_all( stops, max_paths, matrices, query, target, gap_open, gap_extend, local=False, lead1=0, lead2=0, trail1=0, trail2=0, eps=1e-5, ): """Traceback and return all optimal alignment paths. Parameters ---------- stops : sequence of (int, int) Stop positions in both sequences. max_paths : int or None Maximum number of paths to return, or None to return all paths. Cannot be 0. matrices : tuple of ndarray of float of shape (m + 1, n + 1) Alignment matrices. query : ndarray of float of shape (m, n_symbols) Query profile. target : ndarray of int of shape (n,) Target sequence. gap_open : float Gap opening penalty. gap_extend : float Gap extension penalty. local : bool, optional Global (False) or local (True) alignment. lead1, lead2, trail1, trail2 : int, optional If =2, trim leading / trailing gaps of sequences 1 / 2, respectively. eps : float, optional Absolute tolerance. Returns ------- list of PairAlignPath Optimal alignment paths. See Also -------- _traceback_one Notes ----- This function enumerates all optimal alignment paths or until a given number of paths has been reached. A stack is used to store branching paths and to enable depth-first search (DFS). For linear gap penalty, the stack's maximum size is m + n, which is equivalent to the maximum size of a full path, times (b - 1), where b is the number of possible branches (3). For affine gap penalty, the space is appr. (m + n) * 3. Regardless of the total number of full paths, which could easily explode, the stack size is linear and manageable. This function is purely Python and is not as efficient as it could be. Cythonizing it is possible but complicated (requiring C++ vector and class). This can be done in the future. """ lead1, lead2, trail1, trail2 = lead1 < 2, lead2 < 2, trail1 < 2, trail2 < 2 scomat = matrices[0] m = scomat.shape[0] - 1 n = scomat.shape[1] - 1 max_len = m + n if gap_open: gap_oe = gap_open + gap_extend insmat = matrices[1] delmat = matrices[2] # results (optimal alignment paths) paths = [] # allocate the first path path = np.empty(max_len, dtype=np.uint8) # iterate over all starting points for i, j in stops: pos = max_len # fill trailing gaps pos, i1, j1 = _trailing_gaps(path, pos, i, j, m, n, trail1, trail2) # matrix index (start from main matrix (0)) mat = 0 # perform DFS to enumerate all paths stack = [(path, pos, i, j, mat)] while stack: path, pos, i, j, mat = stack.pop() # Check whether a full path has been completed. There are two scenarios: finished = False # 1) Local alignment: Path terminates where cell = 0. # Note: The matrix filling functions guarantee that in local alignment, # cell values cannot be negative. Otherwise this can terminate the loop # prematurely. if local and abs(scomat[i, j]) <= eps: i0, j0 = i, j finished = True # 2) Global alignment: Reached the top or left-most edge of the matrix. # Path will extend straight left or up to the top-left cell. elif i == 0 or j == 0: pos, i0, j0 = _leading_gaps(path, pos, i, j, lead1, lead2) finished = True # Create a path object, and halt if the path number limit has been reached. if finished: paths.append(_encode_path(path[pos:], i0, i1, j0, j1)) if max_paths and len(paths) == max_paths: break else: continue # Otherwise, the current cell must be within the main body of the matrix. # Check all possible moving directions and get ones that match the current # optimal alignment score. if gap_open: moves = _affine_moves( i, j, mat, scomat, insmat, delmat, query, target, gap_oe, gap_extend, eps, ) else: moves = _linear_moves(i, j, scomat, query, target, gap_extend, eps) # This is impossible. Raise error for debugging purpose. # if not moves: # raise ValueError("Traceback cannot proceed.") last = len(moves) - 1 for k, move in enumerate(moves): di, dj, state, mat_ = MOVES[move] # If path branches at this cell (i.e., 1 path becomes 2 or 3), we need # to create a copy of the path. Otherwise, we can use the same path to # save memory and runtime. if k < last: path_ = path.copy() else: path_ = path # Deal with gap state (3 means jumping from main matrix into another # matrix without advancing the path). if state < 3: pos_ = pos - 1 path_[pos_] = state else: pos_ = pos stack.append((path_, pos_, i - di, j - dj, mat_)) return paths scikit-bio-scikit-bio-a3beaa6/skbio/alignment/_pairwise.py000066400000000000000000001000531520735541300237730ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from warnings import warn from itertools import product import numpy as np from skbio.alignment import TabularMSA from skbio.sequence import DNA, RNA, Protein from skbio.sequence import GrammaredSequence from skbio.sequence import SubstitutionMatrix from skbio.util._decorator import deprecated def local_pairwise_align_nucleotide( seq1, seq2, gap_open_penalty=5, gap_extend_penalty=2, match_score=2, mismatch_score=-3, substitution_matrix=None, ): """Locally align exactly two nucleotide seqs with Smith-Waterman. Parameters ---------- seq1 : DNA or RNA The first unaligned sequence. seq2 : DNA or RNA The second unaligned sequence. gap_open_penalty : int or float, optional Penalty for opening a gap (this is subtracted from previous best alignment score, so is typically positive). gap_extend_penalty : int or float, optional Penalty for extending a gap (this is subtracted from previous best alignment score, so is typically positive). match_score : int or float, optional The score to add for a match between a pair of bases (this is added to the previous best alignment score, so is typically positive). mismatch_score : int or float, optional The score to add for a mismatch between a pair of bases (this is added to the previous best alignment score, so is typically negative). substitution_matrix: 2D dict (or similar) Lookup for substitution scores (these values are added to the previous best alignment score). If provided, this overrides ``match_score`` and ``mismatch_score``. Returns ------- tuple ``TabularMSA`` object containing the aligned sequences, alignment score (float), and start/end positions of each input sequence (iterable of two-item tuples). Note that start/end positions are indexes into the unaligned sequences. See Also -------- local_pairwise_align local_pairwise_align_protein global_pairwise_align global_pairwise_align_protein global_pairwise_align_nucleotide Notes ----- Default ``match_score``, ``mismatch_score``, ``gap_open_penalty`` and ``gap_extend_penalty`` parameters are derived from the NCBI BLAST Server [1]_. References ---------- .. [1] http://blast.ncbi.nlm.nih.gov/Blast.cgi """ for seq in seq1, seq2: if not isinstance(seq, (DNA, RNA)): raise TypeError( "`seq1` and `seq2` must be DNA or RNA, not type %r" % type(seq).__name__ ) # use the substitution matrix provided by the user, or compute from # match_score and mismatch_score if a substitution matrix was not provided if substitution_matrix is None: substitution_matrix = SubstitutionMatrix.identity( "ACGTU", match_score, mismatch_score ).to_dict() return local_pairwise_align( seq1, seq2, gap_open_penalty, gap_extend_penalty, substitution_matrix ) def local_pairwise_align_protein( seq1, seq2, gap_open_penalty=11, gap_extend_penalty=1, substitution_matrix=None ): """Locally align exactly two protein seqs with Smith-Waterman. Parameters ---------- seq1 : Protein The first unaligned sequence. seq2 : Protein The second unaligned sequence. gap_open_penalty : int or float, optional Penalty for opening a gap (this is subtracted from previous best alignment score, so is typically positive). gap_extend_penalty : int or float, optional Penalty for extending a gap (this is subtracted from previous best alignment score, so is typically positive). substitution_matrix: 2D dict (or similar), optional Lookup for substitution scores (these values are added to the previous best alignment score); default is BLOSUM 50. Returns ------- tuple ``TabularMSA`` object containing the aligned sequences, alignment score (float), and start/end positions of each input sequence (iterable of two-item tuples). Note that start/end positions are indexes into the unaligned sequences. See Also -------- local_pairwise_align local_pairwise_align_nucleotide global_pairwise_align global_pairwise_align_protein global_pairwise_align_nucleotide Notes ----- Default ``gap_open_penalty`` and ``gap_extend_penalty`` parameters are derived from the NCBI BLAST Server [1]_. The BLOSUM (blocks substitution matrices) amino acid substitution matrices were originally defined in [2]_. References ---------- .. [1] http://blast.ncbi.nlm.nih.gov/Blast.cgi .. [2] Amino acid substitution matrices from protein blocks. S Henikoff and J G Henikoff. Proc Natl Acad Sci U S A. Nov 15, 1992; 89(22): 10915-10919. """ for seq in seq1, seq2: if not isinstance(seq, Protein): raise TypeError( "`seq1` and `seq2` must be Protein, not type %r" % type(seq).__name__ ) if substitution_matrix is None: substitution_matrix = SubstitutionMatrix.by_name("BLOSUM50").to_dict() return local_pairwise_align( seq1, seq2, gap_open_penalty, gap_extend_penalty, substitution_matrix ) def local_pairwise_align( seq1, seq2, gap_open_penalty, gap_extend_penalty, substitution_matrix ): """Locally align exactly two seqs with Smith-Waterman. Parameters ---------- seq1 : GrammaredSequence The first unaligned sequence. seq2 : GrammaredSequence The second unaligned sequence. gap_open_penalty : int or float Penalty for opening a gap (this is subtracted from previous best alignment score, so is typically positive). gap_extend_penalty : int or float Penalty for extending a gap (this is subtracted from previous best alignment score, so is typically positive). substitution_matrix: 2D dict (or similar) Lookup for substitution scores (these values are added to the previous best alignment score). Returns ------- tuple ``TabularMSA`` object containing the aligned sequences, alignment score (float), and start/end positions of each input sequence (iterable of two-item tuples). Note that start/end positions are indexes into the unaligned sequences. See Also -------- local_pairwise_align_protein local_pairwise_align_nucleotide global_pairwise_align global_pairwise_align_protein global_pairwise_align_nucleotide Notes ----- This algorithm was originally described in [1]_. The scikit-bio implementation was validated against the EMBOSS water web server [2]_. References ---------- .. [1] Identification of common molecular subsequences. Smith TF, Waterman MS. J Mol Biol. 1981 Mar 25;147(1):195-7. .. [2] http://www.ebi.ac.uk/Tools/psa/emboss_water/ """ warn( "You're using skbio's pure Python implementation of local pairwise " "alignment. This is known to be very slow. We recommend using the " "efficient `skbio.alignment.pair_align` function instead.", PendingDeprecationWarning, ) for seq in seq1, seq2: if not isinstance(seq, GrammaredSequence): raise TypeError( "`seq1` and `seq2` must be %r subclasses, not type %r" % (GrammaredSequence.__name__, type(seq).__name__) ) if type(seq1) is not type(seq2): raise TypeError( "`seq1` and `seq2` must be the same type: %r != %r" % (type(seq1).__name__, type(seq2).__name__) ) seq1 = _coerce_alignment_input_type(seq1) seq2 = _coerce_alignment_input_type(seq2) score_matrix, traceback_matrix = _compute_score_and_traceback_matrices( seq1, seq2, gap_open_penalty, gap_extend_penalty, substitution_matrix, new_alignment_score=0.0, init_matrices_f=_init_matrices_sw, ) end_row_position, end_col_position = np.unravel_index( np.argmax(score_matrix), score_matrix.shape ) aligned1, aligned2, score, seq1_start_position, seq2_start_position = _traceback( traceback_matrix, score_matrix, seq1, seq2, end_row_position, end_col_position ) start_end_positions = [ (seq1_start_position, end_col_position - 1), (seq2_start_position, end_row_position - 1), ] msa = TabularMSA(aligned1 + aligned2) return msa, score, start_end_positions def global_pairwise_align_nucleotide( seq1, seq2, gap_open_penalty=5, gap_extend_penalty=2, match_score=1, mismatch_score=-2, substitution_matrix=None, penalize_terminal_gaps=False, ): """Globally align nucleotide seqs or alignments with Needleman-Wunsch. Parameters ---------- seq1 : DNA, RNA, or TabularMSA[DNA|RNA] The first unaligned sequence(s). seq2 : DNA, RNA, or TabularMSA[DNA|RNA] The second unaligned sequence(s). gap_open_penalty : int or float, optional Penalty for opening a gap (this is subtracted from previous best alignment score, so is typically positive). gap_extend_penalty : int or float, optional Penalty for extending a gap (this is subtracted from previous best alignment score, so is typically positive). match_score : int or float, optional The score to add for a match between a pair of bases (this is added to the previous best alignment score, so is typically positive). mismatch_score : int or float, optional The score to add for a mismatch between a pair of bases (this is added to the previous best alignment score, so is typically negative). substitution_matrix: 2D dict (or similar) Lookup for substitution scores (these values are added to the previous best alignment score). If provided, this overrides ``match_score`` and ``mismatch_score``. penalize_terminal_gaps: bool, optional If True, will continue to penalize gaps even after one sequence has been aligned through its end. This behavior is true Needleman-Wunsch alignment, but results in (biologically irrelevant) artifacts when the sequences being aligned are of different length. This is ``False`` by default, which is very likely to be the behavior you want in all or nearly all cases. Returns ------- tuple ``TabularMSA`` object containing the aligned sequences, alignment score (float), and start/end positions of each input sequence (iterable of two-item tuples). Note that start/end positions are indexes into the unaligned sequences. See Also -------- local_pairwise_align local_pairwise_align_protein local_pairwise_align_nucleotide global_pairwise_align global_pairwise_align_protein Notes ----- Default ``match_score``, ``mismatch_score``, ``gap_open_penalty`` and ``gap_extend_penalty`` parameters are derived from the NCBI BLAST Server [1]_. This function can be use to align either a pair of sequences, a pair of alignments, or a sequence and an alignment. References ---------- .. [1] http://blast.ncbi.nlm.nih.gov/Blast.cgi """ for seq in seq1, seq2: if not isinstance(seq, (DNA, RNA, TabularMSA)): raise TypeError( "`seq1` and `seq2` must be DNA, RNA, or TabularMSA, not type " "%r" % type(seq).__name__ ) if isinstance(seq, TabularMSA) and not issubclass(seq.dtype, (DNA, RNA)): raise TypeError( "`seq1` and `seq2` must be TabularMSA with DNA or RNA dtype, " "not dtype %r" % seq.dtype.__name__ ) # use the substitution matrix provided by the user, or compute from # match_score and mismatch_score if a substitution matrix was not provided if substitution_matrix is None: substitution_matrix = SubstitutionMatrix.identity( "ACGTU", match_score, mismatch_score ).to_dict() return global_pairwise_align( seq1, seq2, gap_open_penalty, gap_extend_penalty, substitution_matrix, penalize_terminal_gaps=penalize_terminal_gaps, ) def global_pairwise_align_protein( seq1, seq2, gap_open_penalty=11, gap_extend_penalty=1, substitution_matrix=None, penalize_terminal_gaps=False, ): """Globally align pair of protein seqs or alignments with Needleman-Wunsch. Parameters ---------- seq1 : Protein or TabularMSA[Protein] The first unaligned sequence(s). seq2 : Protein or TabularMSA[Protein] The second unaligned sequence(s). gap_open_penalty : int or float, optional Penalty for opening a gap (this is subtracted from previous best alignment score, so is typically positive). gap_extend_penalty : int or float, optional Penalty for extending a gap (this is subtracted from previous best alignment score, so is typically positive). substitution_matrix: 2D dict (or similar), optional Lookup for substitution scores (these values are added to the previous best alignment score); default is BLOSUM 50. penalize_terminal_gaps: bool, optional If True, will continue to penalize gaps even after one sequence has been aligned through its end. This behavior is true Needleman-Wunsch alignment, but results in (biologically irrelevant) artifacts when the sequences being aligned are of different length. This is ``False`` by default, which is very likely to be the behavior you want in all or nearly all cases. Returns ------- tuple ``TabularMSA`` object containing the aligned sequences, alignment score (float), and start/end positions of each input sequence (iterable of two-item tuples). Note that start/end positions are indexes into the unaligned sequences. See Also -------- local_pairwise_align local_pairwise_align_protein local_pairwise_align_nucleotide global_pairwise_align global_pairwise_align_nucleotide Notes ----- Default ``gap_open_penalty`` and ``gap_extend_penalty`` parameters are derived from the NCBI BLAST Server [1]_. The BLOSUM (blocks substitution matrices) amino acid substitution matrices were originally defined in [2]_. This function can be use to align either a pair of sequences, a pair of alignments, or a sequence and an alignment. References ---------- .. [1] http://blast.ncbi.nlm.nih.gov/Blast.cgi .. [2] Amino acid substitution matrices from protein blocks. S Henikoff and J G Henikoff. Proc Natl Acad Sci U S A. Nov 15, 1992; 89(22): 10915-10919. """ for seq in seq1, seq2: if not isinstance(seq, (Protein, TabularMSA)): raise TypeError( "`seq1` and `seq2` must be Protein or TabularMSA, not type %r" % type(seq).__name__ ) if isinstance(seq, TabularMSA) and not issubclass(seq.dtype, Protein): raise TypeError( "`seq1` and `seq2` must be TabularMSA with Protein dtype, " "not dtype %r" % seq.dtype.__name__ ) if substitution_matrix is None: substitution_matrix = SubstitutionMatrix.by_name("BLOSUM50").to_dict() return global_pairwise_align( seq1, seq2, gap_open_penalty, gap_extend_penalty, substitution_matrix, penalize_terminal_gaps=penalize_terminal_gaps, ) def global_pairwise_align( seq1, seq2, gap_open_penalty, gap_extend_penalty, substitution_matrix, penalize_terminal_gaps=False, ): """Globally align a pair of seqs or alignments with Needleman-Wunsch. Parameters ---------- seq1 : GrammaredSequence or TabularMSA The first unaligned sequence(s). seq2 : GrammaredSequence or TabularMSA The second unaligned sequence(s). gap_open_penalty : int or float Penalty for opening a gap (this is subtracted from previous best alignment score, so is typically positive). gap_extend_penalty : int or float Penalty for extending a gap (this is subtracted from previous best alignment score, so is typically positive). substitution_matrix: 2D dict (or similar) Lookup for substitution scores (these values are added to the previous best alignment score). penalize_terminal_gaps: bool, optional If True, will continue to penalize gaps even after one sequence has been aligned through its end. This behavior is true Needleman-Wunsch alignment, but results in (biologically irrelevant) artifacts when the sequences being aligned are of different length. This is ``False`` by default, which is very likely to be the behavior you want in all or nearly all cases. Returns ------- tuple ``TabularMSA`` object containing the aligned sequences, alignment score (float), and start/end positions of each input sequence (iterable of two-item tuples). Note that start/end positions are indexes into the unaligned sequences. See Also -------- local_pairwise_align local_pairwise_align_protein local_pairwise_align_nucleotide global_pairwise_align_protein global_pairwise_align_nucleotide Notes ----- This algorithm (in a slightly more basic form) was originally described in [1]_. The scikit-bio implementation was validated against the EMBOSS needle web server [2]_. This function can be use to align either a pair of sequences, a pair of alignments, or a sequence and an alignment. References ---------- .. [1] A general method applicable to the search for similarities in the amino acid sequence of two proteins. Needleman SB, Wunsch CD. J Mol Biol. 1970 Mar;48(3):443-53. .. [2] http://www.ebi.ac.uk/Tools/psa/emboss_needle/ """ warn( "You're using skbio's pure Python implementation of global pairwise " "alignment. This is known to be very slow. We recommend using the " "efficient `skbio.alignment.pair_align` function instead.", PendingDeprecationWarning, ) for seq in seq1, seq2: # We don't need to check the case where `seq` is a `TabularMSA` with a # dtype that isn't a subclass of `GrammaredSequence`, this is # guaranteed by `TabularMSA`. if not isinstance(seq, (GrammaredSequence, TabularMSA)): raise TypeError( "`seq1` and `seq2` must be GrammaredSequence subclasses or " "TabularMSA, not type %r" % type(seq).__name__ ) seq1 = _coerce_alignment_input_type(seq1) seq2 = _coerce_alignment_input_type(seq2) if seq1.dtype is not seq2.dtype: raise TypeError( "`seq1` and `seq2` must have the same dtype: %r != %r" % (seq1.dtype.__name__, seq2.dtype.__name__) ) if penalize_terminal_gaps: init_matrices_f = _init_matrices_nw else: init_matrices_f = _init_matrices_nw_no_terminal_gap_penalty score_matrix, traceback_matrix = _compute_score_and_traceback_matrices( seq1, seq2, gap_open_penalty, gap_extend_penalty, substitution_matrix, new_alignment_score=-np.inf, init_matrices_f=init_matrices_f, penalize_terminal_gaps=penalize_terminal_gaps, ) end_row_position = traceback_matrix.shape[0] - 1 end_col_position = traceback_matrix.shape[1] - 1 aligned1, aligned2, score, seq1_start_position, seq2_start_position = _traceback( traceback_matrix, score_matrix, seq1, seq2, end_row_position, end_col_position ) start_end_positions = [ (seq1_start_position, end_col_position - 1), (seq2_start_position, end_row_position - 1), ] msa = TabularMSA(aligned1 + aligned2) return msa, score, start_end_positions # Functions from here allow for generalized (global or local) alignment. I # will likely want to put these in a single object to make the naming a little # less clunky. def _coerce_alignment_input_type(seq): if isinstance(seq, GrammaredSequence): return TabularMSA([seq]) else: return seq _traceback_encoding = { "match": 1, "vertical-gap": 2, "horizontal-gap": 3, "uninitialized": -1, "alignment-end": 0, } def _init_matrices_sw(aln1, aln2, gap_open_penalty, gap_extend_penalty): shape = (aln2.shape.position + 1, aln1.shape.position + 1) score_matrix = np.zeros(shape) traceback_matrix = np.zeros(shape, dtype=int) traceback_matrix += _traceback_encoding["uninitialized"] traceback_matrix[0, :] = _traceback_encoding["alignment-end"] traceback_matrix[:, 0] = _traceback_encoding["alignment-end"] return score_matrix, traceback_matrix def _init_matrices_nw(aln1, aln2, gap_open_penalty, gap_extend_penalty): shape = (aln2.shape.position + 1, aln1.shape.position + 1) score_matrix = np.zeros(shape) traceback_matrix = np.zeros(shape, dtype=int) traceback_matrix += _traceback_encoding["uninitialized"] traceback_matrix[0, 0] = _traceback_encoding["alignment-end"] # cache some values for quicker access vgap = _traceback_encoding["vertical-gap"] hgap = _traceback_encoding["horizontal-gap"] for i in range(1, shape[0]): score_matrix[i, 0] = -gap_open_penalty - ((i - 1) * gap_extend_penalty) traceback_matrix[i, 0] = vgap for i in range(1, shape[1]): score_matrix[0, i] = -gap_open_penalty - ((i - 1) * gap_extend_penalty) traceback_matrix[0, i] = hgap return score_matrix, traceback_matrix def _init_matrices_nw_no_terminal_gap_penalty( aln1, aln2, gap_open_penalty, gap_extend_penalty ): shape = (aln2.shape.position + 1, aln1.shape.position + 1) score_matrix = np.zeros(shape) traceback_matrix = np.zeros(shape, dtype=int) traceback_matrix += _traceback_encoding["uninitialized"] traceback_matrix[0, 0] = _traceback_encoding["alignment-end"] # cache some values for quicker access vgap = _traceback_encoding["vertical-gap"] hgap = _traceback_encoding["horizontal-gap"] for i in range(1, shape[0]): traceback_matrix[i, 0] = vgap for i in range(1, shape[1]): traceback_matrix[0, i] = hgap return score_matrix, traceback_matrix def _compute_substitution_score( aln1_chars, aln2_chars, substitution_matrix, gap_substitution_score, gap_chars ): substitution_score = 0 for aln1_char, aln2_char in product(aln1_chars, aln2_chars): if aln1_char in gap_chars or aln2_char in gap_chars: substitution_score += gap_substitution_score else: try: substitution_score += substitution_matrix[aln1_char][aln2_char] except KeyError: offending_chars = [ c for c in (aln1_char, aln2_char) if c not in substitution_matrix ] raise ValueError( "One of the sequences contains a character that is " "not contained in the substitution matrix. Are you " "using an appropriate substitution matrix for your " "sequence type (e.g., a nucleotide substitution " "matrix does not make sense for aligning protein " "sequences)? Does your sequence contain invalid " "characters? The offending character(s) is: " " %s." % ", ".join(offending_chars) ) substitution_score /= len(aln1_chars) * len(aln2_chars) return substitution_score def _compute_score_and_traceback_matrices( aln1, aln2, gap_open_penalty, gap_extend_penalty, substitution_matrix, new_alignment_score=-np.inf, init_matrices_f=_init_matrices_nw, penalize_terminal_gaps=True, gap_substitution_score=0, ): """Return dynamic programming (score) and traceback matrices. A note on the ``penalize_terminal_gaps`` parameter. When this value is ``False``, this function is no longer true Smith-Waterman/Needleman-Wunsch scoring, but when ``True`` it can result in biologically irrelevant artifacts in Needleman-Wunsch (global) alignments. Specifically, if one sequence is longer than the other (e.g., if aligning a primer sequence to an amplification product, or searching for a gene in a genome) the shorter sequence will have a long gap inserted. The parameter is ``True`` by default (so that this function computes the score and traceback matrices as described by the original authors) but the global alignment wrappers pass ``False`` by default, so that the global alignment API returns the result that users are most likely to be looking for. """ aln1_length = aln1.shape.position aln2_length = aln2.shape.position # cache some values for quicker/simpler access aend = _traceback_encoding["alignment-end"] match = _traceback_encoding["match"] vgap = _traceback_encoding["vertical-gap"] hgap = _traceback_encoding["horizontal-gap"] new_alignment_score = (new_alignment_score, aend) # Initialize a matrix to use for scoring the alignment and for tracing # back the best alignment score_matrix, traceback_matrix = init_matrices_f( aln1, aln2, gap_open_penalty, gap_extend_penalty ) # Iterate over the characters in aln2 (which corresponds to the vertical # sequence in the matrix) for aln2_pos, aln2_chars in enumerate(aln2.iter_positions(ignore_metadata=True), 1): aln2_chars = str(aln2_chars) # Iterate over the characters in aln1 (which corresponds to the # horizontal sequence in the matrix) for aln1_pos, aln1_chars in enumerate( aln1.iter_positions(ignore_metadata=True), 1 ): aln1_chars = str(aln1_chars) # compute the score for a match/mismatch substitution_score = _compute_substitution_score( aln1_chars, aln2_chars, substitution_matrix, gap_substitution_score, aln1.dtype.gap_chars, ) diag_score = ( score_matrix[aln2_pos - 1, aln1_pos - 1] + substitution_score, match, ) # compute the score for adding a gap in aln2 (vertical) if not penalize_terminal_gaps and (aln1_pos == aln1_length): # we've reached the end of aln1, so adding vertical gaps # (which become gaps in aln1) should no longer # be penalized (if penalize_terminal_gaps == False) up_score = (score_matrix[aln2_pos - 1, aln1_pos], vgap) elif traceback_matrix[aln2_pos - 1, aln1_pos] == vgap: # gap extend, because the cell above was also a gap up_score = ( score_matrix[aln2_pos - 1, aln1_pos] - gap_extend_penalty, vgap, ) else: # gap open, because the cell above was not a gap up_score = ( score_matrix[aln2_pos - 1, aln1_pos] - gap_open_penalty, vgap, ) # compute the score for adding a gap in aln1 (horizontal) if not penalize_terminal_gaps and (aln2_pos == aln2_length): # we've reached the end of aln2, so adding horizontal gaps # (which become gaps in aln2) should no longer # be penalized (if penalize_terminal_gaps == False) left_score = (score_matrix[aln2_pos, aln1_pos - 1], hgap) elif traceback_matrix[aln2_pos, aln1_pos - 1] == hgap: # gap extend, because the cell to the left was also a gap left_score = ( score_matrix[aln2_pos, aln1_pos - 1] - gap_extend_penalty, hgap, ) else: # gap open, because the cell to the left was not a gap left_score = ( score_matrix[aln2_pos, aln1_pos - 1] - gap_open_penalty, hgap, ) # identify the largest score, and use that information to populate # the score and traceback matrices best_score = _first_largest( [new_alignment_score, left_score, diag_score, up_score] ) score_matrix[aln2_pos, aln1_pos] = best_score[0] traceback_matrix[aln2_pos, aln1_pos] = best_score[1] return score_matrix, traceback_matrix def _traceback(traceback_matrix, score_matrix, aln1, aln2, start_row, start_col): # cache some values for simpler reference aend = _traceback_encoding["alignment-end"] match = _traceback_encoding["match"] vgap = _traceback_encoding["vertical-gap"] hgap = _traceback_encoding["horizontal-gap"] gap_character = aln1.dtype.default_gap_char # initialize the result alignments aln1_sequence_count = aln1.shape.sequence aligned_seqs1 = [[] for e in range(aln1_sequence_count)] aln2_sequence_count = aln2.shape.sequence aligned_seqs2 = [[] for e in range(aln2_sequence_count)] current_row = start_row current_col = start_col best_score = score_matrix[current_row, current_col] current_value = None while current_value != aend: current_value = traceback_matrix[current_row, current_col] if current_value == match: for aligned_seq, input_seq in zip(aligned_seqs1, aln1): aligned_seq.append(str(input_seq[current_col - 1])) for aligned_seq, input_seq in zip(aligned_seqs2, aln2): aligned_seq.append(str(input_seq[current_row - 1])) current_row -= 1 current_col -= 1 elif current_value == vgap: for aligned_seq in aligned_seqs1: aligned_seq.append(gap_character) for aligned_seq, input_seq in zip(aligned_seqs2, aln2): aligned_seq.append(str(input_seq[current_row - 1])) current_row -= 1 elif current_value == hgap: for aligned_seq, input_seq in zip(aligned_seqs1, aln1): aligned_seq.append(str(input_seq[current_col - 1])) for aligned_seq in aligned_seqs2: aligned_seq.append(gap_character) current_col -= 1 elif current_value == aend: continue else: raise ValueError("Invalid value in traceback matrix: %s" % current_value) for i, (aligned_seq, original) in enumerate(zip(aligned_seqs1, aln1)): aligned_seq = "".join(aligned_seq)[::-1] constructor = aln1.dtype metadata = None if original.has_metadata(): metadata = original.metadata aligned_seqs1[i] = constructor(aligned_seq, metadata=metadata, validate=False) for i, (aligned_seq, original) in enumerate(zip(aligned_seqs2, aln2)): aligned_seq = "".join(aligned_seq)[::-1] constructor = aln2.dtype metadata = None if original.has_metadata(): metadata = original.metadata aligned_seqs2[i] = constructor(aligned_seq, metadata=metadata, validate=False) return aligned_seqs1, aligned_seqs2, best_score, current_col, current_row def _first_largest(scores): """Similar to max, but returns the first element achieving the high score. If max receives a tuple, it will break a tie for the highest value of entry[i] with entry[i+1]. We don't want that here - to better match with the results of other tools, we want to be able to define which entry is returned in the case of a tie. """ result = scores[0] for score, direction in scores[1:]: if score > result[0]: result = (score, direction) return result scikit-bio-scikit-bio-a3beaa6/skbio/alignment/_path.py000066400000000000000000001350011520735541300231050ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from typing import TYPE_CHECKING import numpy as np from skbio._base import SkbioObject from skbio.util._decorator import classonlymethod if TYPE_CHECKING: # pragma: no cover from numpy.typing import ArrayLike, NDArray from skbio.sequence import Sequence from typing import Self # CIGAR codes indexed by states in PairAlignPath _cigar_codes = np.array(["M", "I", "D", "P"]) # Mapping of CIGAR codes to states in PairAlignPath _cigar_mapping = { 77: 0, # M 73: 1, # I 68: 2, # D 80: 3, # P 61: 0, # = 88: 0, # X 78: 2, # N 83: 1, # S 72: 3, # H } class AlignPath(SkbioObject): r"""Store an alignment path between sequences. It is a compact data structure that stores the operations of sequence alignment: inserting gaps into designated positions between subsequences. It does not store the sequence data. Parameters ---------- lengths : array_like of int of shape (n_segments,) Length of each segment in the alignment. states : array_like of uint8 of shape (n_segments,) or (n_packs, n_segments) Packed bits representing character (0) or gap (1) status per sequence per segment in the alignment. ranges : array_like of int of shape (n_sequences, 2), optional Start and stop positions of each sequence in the alignment. starts : array_like of int of shape (n_sequences,), optional Start position of each sequence in the alignment. stops : array_like of int of shape (n_sequences,), optional Stop position of each sequence in the alignment. .. note:: The ranges can be defined by supplying ``starts``, ``stops`` or ``ranges``. With either of the first two, the program will locate the other side based on ``lengths`` and ``states``. For the last (``ranges``), the program will NOT validate the correctness of the values but simply take them. See Also -------- PairAlignPath skbio.alignment.TabularMSA skbio.sequence.Sequence Notes ----- The underlying data structure of the ``AlignPath`` class efficiently represents a sequence alignment as two equal-length vectors: ``lengths`` and ``states``. The lengths vector contains the lengths of individual segments of the alignment with consistent gap status. The states vector contains the packed bits of gap (1) and and character (0) status for each position in the alignment. This data structure is calculated by performing :wiki:`run-length encoding ` (RLE) on the alignment, considering each segment with consistent gap status to be a unit in the encoding. This resembles the CIGAR string (see :meth:`PairAlignPath.to_cigar`), and is generalized to an arbitrary number of sequences. An ``AlignPath`` object is detached from the original or aligned sequences and is highly memory efficient. The more similar the sequences are (i.e., the fewer gaps), the more compact this data structure is. In the worst case, this object consumes 1/8 memory space of the aligned sequences. This class permits fully vectorized operations and enables efficient conversion between various formats such as aligned sequences, indices (Biotite), and coordinates (Biopython). In addition to alignment operations, an ``AlignPath`` object also stores the ranges (start and stop positions) of the aligned region in the original sequences. This facilitates extraction of aligned sequences. The positions are 0-based and half-open, consistent with Python indexing, and compatible with the :wiki:`BED format `. Examples -------- Create an ``AlignPath`` object from a ``TabularMSA`` object with three DNA sequences and 20 positions. >>> from skbio import DNA, TabularMSA >>> from skbio.alignment import AlignPath >>> msa = TabularMSA([ ... DNA('CGGTCGTAACGCGTA---CA'), ... DNA('CAG--GTAAG-CATACCTCA'), ... DNA('CGGTCGTCAC-TGTACACTA'), ... ]) >>> path = AlignPath.from_tabular(msa) >>> path >>> path.lengths array([3, 2, 5, 1, 4, 3, 2]) >>> path.states array([[0, 2, 0, 6, 0, 1, 0]], dtype=uint8) In the above example, the first three positions of the alignment contain no gaps, so the first value in the lengths array is 3, and that in the states array is 0. The fourth segment, which has length 1, would have gap status (0, 1, 1), which then becomes 6 after bit packing. An ``AlignPath`` object is rarely created from scratch. But one still could, like: >>> path = AlignPath(lengths=[3, 2, 5, 1, 4, 3, 2], ... states=[0, 2, 0, 6, 0, 1, 0], ... starts=[5, 1, 0]) The parameter ``starts`` defines the start positions of the aligned region of each sequence. The program will automatically calculate the stop positions. >>> path.starts array([5, 1, 0]) >>> path.stops array([22, 18, 19]) >>> path.ranges array([[ 5, 22], [ 1, 18], [ 0, 19]]) With the ranges, one can extract aligned subsequences from the original sequences. >>> seqs = [ ... DNA("NNNNNCGGTCGTAACGCGTACANNNNNNN"), ... DNA("NCAGGTAAGCATACCTCA"), ... DNA("CGGTCGTCACTGTACACTANN"), ... ] >>> for seq, (start, stop) in zip(seqs, path.ranges): ... print(seq[start:stop]) CGGTCGTAACGCGTACA CAGGTAAGCATACCTCA CGGTCGTCACTGTACACTA Alternatively, one can extract the aligned sequences with gap characters: >>> print(*path.to_aligned(seqs), sep='\n') CGGTCGTAACGCGTA---CA CAG--GTAAG-CATACCTCA CGGTCGTCAC-TGTACACTA """ def __init__( self, lengths: ArrayLike, states: ArrayLike, *, ranges: ArrayLike | None = None, starts: ArrayLike | None = None, stops: ArrayLike | None = None, ) -> None: self._lengths = np.asarray(lengths, dtype=np.intp) if self._lengths.ndim > 1: raise TypeError("`lengths` must be a 1-D array.") self._states = np.atleast_2d(np.asarray(states, dtype=np.uint8)) if self._states.ndim > 2: raise TypeError("`states` must be a 1-D or 2-D array.") if self._lengths.shape[0] != self._states.shape[1]: raise ValueError( f"Numbers of segments in `lengths` ({self._lengths.shape[0]}) " f"and `states` ({self._states.shape[1]}) do not match." ) if ranges is not None: self._ranges = np.asarray(ranges, dtype=np.intp) if self._ranges.ndim != 2 or self._ranges.shape[1] != 2: raise TypeError("`ranges` must be a 2-column array.") else: if starts is not None: starts_ = np.asarray(starts, dtype=np.intp) if starts_.ndim != 1: raise TypeError("`starts` must be a 1-D array.") self._ranges = np.column_stack( (starts_, starts_ + self._to_sizes(starts_.shape[0])) ) elif stops is not None: stops_ = np.asarray(stops, dtype=np.intp) if stops_.ndim != 1: raise TypeError("`stops` must be a 1-D array.") self._ranges = np.column_stack( (stops_ - self._to_sizes(stops_.shape[0]), stops_) ) else: raise ValueError("`ranges`, `starts` or `stops` must be provided.") # Number of sequences needs to be explicitly provided, because the packed bits # does not contain this information. (It is merely in multiples of 8.) nseq = self._ranges.shape[0] if np.ceil(nseq / 8) != self._states.shape[0]: max_seqs = self._states.shape[0] * 8 raise ValueError( f"Number of sequences in ranges ({nseq}) and capacity of " f"states ({max_seqs - 7} to {max_seqs}) do not match." ) # Shape is n_sequences (rows) x n_positions (columns), which is consistent with # TabularMSA npos = int(self._lengths.sum()) self._shape = (nseq, npos) def __str__(self) -> str: r"""Return string representation of this alignment path.""" return self.__repr__() def __repr__(self) -> str: r"""Return summary of the alignment path.""" return ( f"<{self.__class__.__name__}, " f"sequences: {self._shape[0]}, " f"positions: {self._shape[1]}, " f"segments: {self._lengths.size}>" ) @property def lengths(self) -> NDArray[np.intp]: """Array of lengths of segments in alignment path.""" return self._lengths @property def states(self) -> NDArray[np.uint8]: """Array of gap status of segments in alignment path.""" return self._states @property def ranges(self) -> NDArray[np.intp]: """Array of (start, stop) positions of sequences in the alignment.""" return self._ranges @property def starts(self) -> NDArray[np.intp]: """Array of start positions of sequences in the alignment.""" return self._ranges[:, 0] @property def stops(self) -> NDArray[np.intp]: """Array of stop positions of sequences in the alignment.""" return self._ranges[:, 1] @property def shape(self) -> tuple[int, int]: """Number of sequences (rows) and positions (columns).""" return self._shape def _to_bits(self, count=None): r"""Unpack the alignment path into an array of bits by segment.""" if count is None: count = self._shape[0] return np.unpackbits(self._states, axis=0, count=count, bitorder="little") def _to_sizes(self, count=None): r"""Calculate the size of aligned region within each sequence.""" return (self._lengths * (1 - self._to_bits(count=count))).sum(axis=1) def to_bits(self, expand: bool = True) -> NDArray[np.uint8]: r"""Unpack the alignment path into an array of bits. .. versionchanged:: 0.7.0 The default behavior now returns positions. Parameters ---------- expand : bool, optional If True (default), each column in the returned array represents a position in the original alignment. If False, each column represents a segment in the alignment path. .. versionadded:: 0.7.0 Returns ------- ndarray of (0, 1) of shape (n_sequences, n_positions or n_segments) Array of zeros (character) and ones (gap) which represent the alignment. Examples -------- >>> from skbio import DNA, TabularMSA >>> from skbio.alignment import AlignPath >>> seqs = [ ... DNA('CGTCGTGC'), ... DNA('CA--GT-C'), ... DNA('CGTCGT-T') ... ] >>> msa = TabularMSA(seqs) >>> path = AlignPath.from_tabular(msa) Return a bit array representing positions: >>> path.to_bits() array([[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1, 0]], dtype=uint8) Return a bit array representing segments: >>> path.to_bits(expand=False) array([[0, 0, 0, 0, 0], [0, 1, 0, 1, 0], [0, 0, 0, 1, 0]], dtype=uint8) """ bits = self._to_bits() return np.repeat(bits, self._lengths, axis=1) if expand else bits @classonlymethod def from_bits(cls, bits: ArrayLike, starts: ArrayLike | None = None) -> Self: r"""Create an alignment path from a bit array (0 - character, 1 - gap). Parameters ---------- bits : array_like of (0, 1) of shape (n_sequences, n_positions) Array of zeros (character) and ones (gap) which represent the alignment. starts : array_like of int of shape (n_sequences,), optional Start position of each sequence in the alignment. If omitted, will set as zeros. Returns ------- AlignPath The alignment path created from the given bit array. Examples -------- >>> import numpy as np >>> from skbio.alignment import AlignPath >>> bit_arr = np.array([[0, 0, 0, 0, 0, 0, 0, 0], ... [0, 0, 1, 1, 0, 0, 1, 0], ... [0, 0, 0, 0, 0, 0, 1, 0]]) >>> path = AlignPath.from_bits(bit_arr) >>> path """ # pack bits into integers ints = np.packbits(bits, axis=0, bitorder="little") # get indices where segments start idx = np.append(0, np.where((ints[:, :-1] != ints[:, 1:]).any(axis=0))[0] + 1) # get lengths of segments lens = np.append(idx[1:] - idx[:-1], ints.shape[1] - idx[-1]) # keep indices of segment starts ints = ints[:, idx] # set start positions as zeros if not specified if starts is None: starts = np.zeros(bits.shape[0], dtype=int) # return per-segment lengths and states return cls(lens, ints, starts=starts) def to_aligned(self, seqs, gap_char="-", flanking=None): r"""Extract aligned regions from original sequences. .. versionadded:: 0.7.0 Parameters ---------- seqs : iterable of Sequence or str Original sequences. gap_char : str, optional Character to be placed in each gap position. Default is "-". Set as "" to suppress gaps in the output. flanking : int or (int, int), optional Length of flanking regions in the original sequences to be included in the output. Can be two numbers (leading and trailing, respectively) or one number (same for leading and trailing). If the specified flanking region is longer than a sequence actually has, the remaining space will be filled with white spaces (" "). Returns ------- list of str Aligned regions of the sequences. Raises ------ ValueError If there are more sequences than in the path. ValueError If any sequence is shorter than in the path. See Also -------- from_aligned skbio.alignment.TabularMSA.from_path_seqs Notes ----- This method provides a convenient way to process and display alignments, without invoking the explicit ``TabularMSA`` class. Both ``Sequence`` objects and plain strings are valid input sequences. However, it only outputs strings without retaining the ``Sequence`` objects and their metadata. For the later purpose, please use ``TabularMSA``'s :meth:`~skbio.alignment.TabularMSA.from_path_seqs` method instead. Examples -------- >>> from skbio.sequence import DNA >>> from skbio.alignment import AlignPath >>> path = AlignPath( ... lengths=[2, 2, 2, 1, 1], ... states=[0, 2, 0, 6, 0], ... starts=[0, 3, 0], ... ) >>> seqs = [ ... DNA('CGTCGTGC'), ... DNA('ATTCAGTCGG'), ... DNA('CGTCGTTAA') ... ] >>> path.to_aligned(seqs) ['CGTCGTGC', 'CA--GT-C', 'CGTCGT-T'] """ starts = self._ranges[:, 0] lens = self._lengths bits = self._to_bits() if isinstance(flanking, tuple): leading, trailing = flanking else: leading, trailing = flanking, flanking res = [] for i, seq in enumerate(map(str, seqs)): try: pos = starts[i] except IndexError: raise ValueError("There are more sequences than in the path.") aln = "" # leading flanking region if leading: offset = pos - leading if offset >= 0: aln += seq[offset:pos] else: aln += " " * -offset + seq[:pos] # alignment region for L, gap in zip(lens, bits[i]): if gap: aln += gap_char * L else: new_pos = pos + L aln += seq[pos:new_pos] pos = new_pos remaining = len(seq) - pos if remaining < 0: raise ValueError(f"Sequence {i} is shorter than in the path.") # trailing flanking region if trailing: offset = remaining - trailing if offset >= 0: aln += seq[pos : pos + trailing] else: aln += seq[pos:] + " " * -offset res.append(aln) return res @classonlymethod def from_aligned(cls, aln, gap_chars="-", starts=None) -> Self: r"""Create an alignment path from aligned sequences. Parameters ---------- aln : iterable of :class:`~skbio.sequence.Sequence`, str or sequence Aligned sequences. Can be skbio sequences, strings or sequences of any scalars. gap_chars : str or container, optional Characters that should be treated as gaps in aligned sequences. Default is "-". starts : array_like of int of shape (2,), optional Start positions of sequences. If omitted, will be all zeros. Returns ------- AlignPath The alignment path created from the aligned sequences. See Also -------- to_aligned from_tabular Notes ----- This method is more general but less efficient than ``from_tabular``. It works with various sequence formats. Examples -------- >>> from skbio.alignment import AlignPath >>> aln = [ ... 'CGTCGTGC', ... 'CA--GT-C', ... 'CGTCGT-T' ... ] >>> path = AlignPath.from_aligned(aln) >>> path """ from skbio.sequence import Sequence gaps = [] for seq in aln: if isinstance(seq, Sequence): seq = str(seq) row = [x in gap_chars for x in seq] gaps.append(np.array(row, dtype=int)) try: gaps = np.vstack(gaps) except ValueError: raise ValueError("Sequence lengths do not match.") return cls.from_bits(gaps, starts=starts) def _to_matrices(self, seqs, gap_code=45): r"""Generate matrices representing the alignment. Parameters ---------- seqs : list of ndarray Original sequences as bytes. gap_code : uint8, optional Code to fill in gap positions in the character matrix. Default is 45 (-). Returns ------- ndarray of shape (n_sequences, n_positions) Matrix of character codes. ndarray of bool of shape (n_sequences, n_positions) Matrix of gap status. ndarray of shape (n_sequences, n_segments) Matrix of segment status. ndarray of int of shape (n_segments,) Vector of segment lengths. Notes ----- This method is currently private. Its only use case is to prepare data for `align_score`. The code is efficient for this purpose because it avoids all unnecessary calculations. If one intends to index the output with an ``SubstitutionMatrix`` object, having a ``gap_code`` < 128 is necessary. Otherwise, setting ``gap_code`` as None can save some compute. """ # See also `to_bits` and `stops`. The following code mixes both to enhance # performance. bits = self._to_bits() lens = self._lengths # locate aligned region starts = self._ranges[:, 0] stops = self._ranges[:, 1] # create gap array gaps = np.repeat(bits, lens, axis=1).astype(bool) # allocate byte array chars = np.empty(self._shape, dtype=seqs[0].dtype) # fill in gaps (optional) if gap_code is not None: chars[gaps] = gap_code # fill in characters try: chars[~gaps] = np.concatenate( [seqs[i][starts[i] : stops[i]] for i in range(self._shape[0])] ) except IndexError: raise ValueError("Fewer sequences were provided than in alignment path.") except ValueError: raise ValueError("Some sequences are shorter than in alignment path.") return chars, gaps, bits, lens @classonlymethod def from_tabular(cls, msa, starts=None) -> Self: r"""Create an alignment path from a `TabularMSA` object. Parameters ---------- msa : TabularMSA TabularMSA to be converted into AlignPath object. starts : array_like of int of shape (2,), optional Start positions of sequences. If omitted, will be all zeros. Returns ------- AlignPath The alignment path created from the TabularMSA object. See Also -------- from_aligned skbio.TabularMSA.from_path_seqs Notes ----- This method is more efficient and more specific than ``from_aligned``. """ # Convert TabularMSA into a 2D array of bytes. # TODO: TabularMSA itself should be refactored to have this as the default data # structure. byte_arr = np.stack([x._bytes for x in msa._seqs]) # Get gap character code. gap_chars = [ord(x) for x in msa.dtype.gap_chars] # Identify gap positions, and convert them into a bit array, then create an # alignment path based on it. return cls.from_bits(np.isin(byte_arr, gap_chars), starts=starts) def to_indices(self, gap=-1): r"""Generate an array of indices of characters in the original sequences. Parameters ---------- gap : int, np.nan, np.inf, "del", or "mask", optional Method to encode gaps in the alignment. If numeric, replace gaps with this value. If "del", delete columns that have any gap. If "mask", return an ``np.ma.MaskedArray``, with gaps masked. Default is -1. Returns ------- ndarray of int of shape (n_sequences, n_positions) Array of indices of characters in the original sequences. See Also -------- from_indices Notes ----- The transpose of the output matches the underlying data structure of Biotite's ``Alignment`` class [1]_. Therefore, one can convert scikit-bio alignments into Biotite alignments, and vice versa. References ---------- .. [1] `biotite.sequence.align.Alignment `_ Examples -------- >>> from skbio.alignment import AlignPath >>> path = AlignPath(lengths=[2, 1, 2, 1], ... states=[0, 6, 0, 1], ... starts=[0, 1, 2]) >>> idx = path.to_indices() >>> idx array([[ 0, 1, 2, 3, 4, -1], [ 1, 2, -1, 3, 4, 5], [ 2, 3, -1, 4, 5, 6]]) One can create a Biotite ``Alignment`` object from the transposed indices and the original sequences. >>> from biotite.sequence import NucleotideSequence # doctest: +SKIP >>> from biotite.sequence.align import Alignment # doctest: +SKIP >>> seqs = [NucleotideSequence("ACGTGA"), # doctest: +SKIP ... NucleotideSequence("TACTCA"), # doctest: +SKIP ... NucleotideSequence("GGACTGA")] # doctest: +SKIP >>> aln = Alignment(seqs, idx.T) # doctest: +SKIP >>> print(aln) # doctest: +SKIP ACGTG- AC-TCA AC-TGA """ errmsg = "Gap must be an integer, 'del', or 'mask'." valid_gaps = {"del", "mask"} if isinstance(gap, str): if gap not in valid_gaps: raise TypeError(errmsg) elif not np.issubdtype(type(gap), np.integer): raise TypeError(errmsg) bits = np.squeeze(self._to_bits()) # TODO: Consider optimization using np.arange. # thought: initiate [-1, -1, -1 ... -1], then add slices of arange into it pos = np.repeat(1 - bits, self._lengths, axis=1) idx = np.cumsum(pos, axis=1, dtype=int) - 1 if (starts := self._ranges[:, 0]).any(): idx += starts.reshape(-1, 1) if gap == "del": keep = np.repeat(self._states == 0, self._lengths) return idx[:, keep] elif gap == "mask": return np.ma.array(idx, mask=(1 - pos)) else: return np.where(pos, idx, gap) @classonlymethod def from_indices(cls, indices, gap=-1) -> Self: r"""Create an alignment path from character indices in the original sequences. Parameters ---------- indices : array_like of int of shape (n_sequences, n_positions) Each element in the array is the index in the corresponding sequence. gap : int or "mask", optional The value which represents a gap in the alignment. Defaults to -1, but can be other values. If "mask", ``indices`` must be an ``np.ma.MaskedArray``. Cannot use "del". Returns ------- AlignPath The alignment path created from the given indices. See Also -------- to_indices Notes ----- If a sequence in the alignment consists of entirely gap characters, its start position will be equal to the gap character. The input is equivalent to the transpose of the underlying data structure of Biotite's ``Alignment`` class [1]_. References ---------- .. [1] `biotite.sequence.align.Alignment `_ Examples -------- >>> import numpy as np >>> from skbio.alignment import AlignPath >>> idx = np.array([[0, -1, -1, 1, 2, 3], ... [0, 1, 2, -1, -1, -1], ... [0, -1, -1, 1, 2, -1]]) >>> path = AlignPath.from_indices(idx) >>> path One can convert a Biotite's ``Alignment`` object into a scikit-bio alignment path using this method. For example: >>> from biotite.sequence import NucleotideSequence # doctest: +SKIP >>> from biotite.sequence.align import SubstitutionMatrix # doctest: +SKIP >>> from biotite.sequence.align import align_optimal # doctest: +SKIP >>> submat = SubstitutionMatrix.std_nucleotide_matrix() # doctest: +SKIP >>> seq1 = NucleotideSequence("GATCGTC") # doctest: +SKIP >>> seq2 = NucleotideSequence("ATCGCTC") # doctest: +SKIP >>> res = align_optimal(seq1, seq2, submat) # doctest: +SKIP >>> print(res[0]) # doctest: +SKIP GATCG-TC -ATCGCTC >>> trace = res[0].trace # doctest: +SKIP >>> trace # doctest: +SKIP array([[ 0, -1], [ 1, 0], [ 2, 1], [ 3, 2], [ 4, 3], [-1, 4], [ 5, 5], [ 6, 6]]) >>> from skbio.alignment import PairAlignPath # doctest: +SKIP >>> path = PairAlignPath.from_indices(trace.T) # doctest: +SKIP >>> path # doctest: +SKIP """ if gap == "mask": return cls.from_bits( np.ma.getmask(indices), indices[ np.arange(indices.shape[0]), np.argmax(indices != indices.fill_value, axis=1), ], ) else: if isinstance(indices, np.ma.MaskedArray): raise TypeError("For masked arrays, gap must be 'mask'.") indices = np.asarray(indices) return cls.from_bits( indices == gap, indices[np.arange(indices.shape[0]), np.argmax(indices != gap, axis=1)], ) # TODO # n. optimization def to_coordinates(self): r"""Generate an array of segment coordinates in the original sequences. Returns ------- ndarray of int of shape (n_sequences, n_segments) Array where each value defines the start positions (index) of each segment for each sequence. See Also -------- from_coordinates Notes ----- The output is consistent with the underlying data structure of BioPython's ``Alignment`` class [1]_. Therefore, one can convert scikit-bio alignments into Biopython alignments, and vice versa. References ---------- .. [1] `Bio.Align.Alignment `_ Examples -------- >>> from skbio.alignment import AlignPath >>> path = AlignPath(lengths=[2, 1, 2, 1], ... states=[0, 6, 0, 1], ... starts=[0, 1, 2]) >>> coords = path.to_coordinates() >>> coords # doctest: +ELLIPSIS array([[0, 2, 3, 5, 5], [1, 3, 3, 5, 6], [2, 4, 4, 6, 7]]... One can create a Biopython ``Alignment`` object from the coordinates and the original sequences. >>> from Bio.Align import Alignment # doctest: +SKIP >>> seqs = ["ACGTGA", "TACTCA", "GGACTGA"] # doctest: +SKIP >>> aln = Alignment(seqs, coords) # doctest: +SKIP >>> aln.coordinates is coords # doctest: +SKIP True >>> aln.counts() # doctest: +SKIP AlignmentCounts(gaps=5, identities=11, mismatches=2) >>> print(aln) # doctest: +SKIP 0 ACGTG- 5 1 AC-TCA 6 2 AC-TGA 7 """ lens = self._lengths * (1 - self._to_bits()) col0 = np.zeros((self._shape[0], 1), dtype=int) lens = np.append(col0, lens, axis=1) if self.starts.any(): return lens.cumsum(axis=1) + self.starts.reshape(-1, 1) else: return lens.cumsum(axis=1) @classonlymethod def from_coordinates(cls, coords) -> Self: r"""Create an alignment path from an array of segment coordinates. Parameters ---------- coords : array_like of int of shape (n_sequences, n_segments) Array where each value defines the start positions (index) of each segment for each sequence. Returns ------- AlignPath The alignment path created from the given coordinates. See Also -------- to_coordinates Notes ----- The input is compatible with the underlying data structure of BioPython's ``Alignment`` class [1]_. References ---------- .. [1] `Bio.Align.Alignment `_ Examples -------- >>> import numpy as np >>> from skbio.alignment import AlignPath >>> coordinates = np.array([[0, 1, 1, 3, 4], ... [0, 1, 3, 3, 3], ... [0, 1, 1, 3, 3]]) >>> path = AlignPath.from_coordinates(coordinates) >>> path One can convert a Biopython's ``Alignment`` object into a scikit-bio alignment path using this method. >>> from Bio import Align # doctest: +SKIP >>> a = Align.PairwiseAligner() # doctest: +SKIP >>> res = a.align("GATCGTC", "ATCGCTC") # doctest: +SKIP >>> print(res[0]) # doctest: +SKIP target 0 GATCG-TC 7 0 -||||-|| 8 query 0 -ATCGCTC 7 >>> coords = res[0].coordinates # doctest: +SKIP >>> coords # doctest: +SKIP array([[0, 1, 5, 5, 7], [0, 0, 4, 5, 7]]) >>> from skbio.alignment import PairAlignPath # doctest: +SKIP >>> path = PairAlignPath.from_coordinates(coords) # doctest: +SKIP >>> path # doctest: +SKIP """ starts = coords[:, 0] diff = np.diff(coords) bits = diff == 0 lens = diff[bits.argmin(axis=0), np.arange(diff.shape[1])] ints = np.packbits(bits, axis=0, bitorder="little") if ints.shape[0] == 1: ints = np.squeeze(ints, axis=0) return cls(lens, ints, starts=starts) class PairAlignPath(AlignPath): r"""Store a pairwise alignment path between two sequences. ``PairAlignPath`` is a subclass of ``AlignPath``, with additional methods specific to pairwise alignments, such as the processing of CIGAR strings. Parameters ---------- lengths : array_like of int of shape (n_segments,) Length of each segment in the alignment. states : array_like of uint8 of shape (n_segments,) Bits representing character (0) or gap (1) status per sequence per segment in the alignment. ranges : array_like of int of shape (n_sequences, 2), optional Start and stop positions of each sequence in the alignment. starts : array_like of int of shape (n_sequences,), optional Start position of each sequence in the alignment. stops : array_like of int of shape (n_sequences,), optional Stop position of each sequence in the alignment. .. note:: If none of ``ranges``, ``starts`` or ``stops`` are provided, ``starts=[0, 0]`` will be used. See Also -------- AlignPath skbio.sequence.Sequence skbio.alignment.TabularMSA Notes ----- ``PairAlignPath`` uses a compact data structure to store alignment operations. Specifically, it encodes gap status in the two sequences in ``states``, a 2-D array with just one row of packed bits. The elements may be: * 0: Gap in neither sequence. * 1: Gap in sequence 1. * 2: Gap in sequence 2. * 3: Gap in both sequences. Meanwhile, it stores the length of segment per gap status in a 1-D array ``lengths``. For example, the following alignment: .. code-block:: none GAGCCAT-AC GC--CATAAC Can be represented by: .. code-block:: none lengths: 2 2 3 1 2 states: 0 2 0 1 0 This data structure resembles the :wiki:`CIGAR string `, as defined in the SAM format specification [1]_. One can convert a pairwise alignment path to/from a CIGAR string using the :meth:`to_cigar` / :meth:`from_cigar` methods. The translation from CIGAR codes to ``states`` elements is as follows: +-----+----+------+----------------------------------+ |Code |BAM |State |Description | +=====+====+======+==================================+ |``M``|0 |0 |Alignment match | +-----+----+------+----------------------------------+ |``I``|1 |1 |Insertion to the reference | +-----+----+------+----------------------------------+ |``D``|2 |2 |Deletion from the reference | +-----+----+------+----------------------------------+ |``N``|3 |2 |Skipped region from the reference | +-----+----+------+----------------------------------+ |``S``|4 |1 |Soft clipping | +-----+----+------+----------------------------------+ |``H``|5 |3 |Hard clipping | +-----+----+------+----------------------------------+ |``P``|6 |3 |Padding | +-----+----+------+----------------------------------+ |``=``|7 |0 |Sequence match | +-----+----+------+----------------------------------+ |``X``|8 |0 |Sequence mismatch | +-----+----+------+----------------------------------+ .. note:: Sequences 1 and 2 are referred to as "query" and "reference" in the SAM format. See also the superclass :class:`AlignPath`, a generalization of this data structure to an arbitrary number of sequences. References ---------- .. [1] https://samtools.github.io/hts-specs/SAMv1.pdf Examples -------- >>> from skbio.alignment import pair_align >>> seqs = 'GATCGTC', 'ATCGCTC' >>> path = pair_align(*seqs).paths[0] >>> path >>> path.to_cigar() '1D4M1I2M' >>> path.lengths array([1, 4, 1, 2]) >>> path.states array([[2, 0, 1, 0]], dtype=uint8) >>> path.to_aligned(seqs) ['GATCG-TC', '-ATCGCTC'] """ def __init__( self, lengths: ArrayLike, states: ArrayLike, *, ranges: ArrayLike | None = None, starts: ArrayLike | None = None, stops: ArrayLike | None = None, ): if ranges is None and starts is None and stops is None: starts = [0, 0] super().__init__(lengths, states, ranges=ranges, starts=starts, stops=stops) if (self._states[0] > 3).any(): raise ValueError( "For pairwise alignment, `states` must only contain zeros, ones, " "twos, or threes." ) if self._shape[0] != 2: raise ValueError( "A pairwise alignment must represent exactly two sequences, but " f"{self._shape[0]} were given." ) def __str__(self) -> str: r"""Return string representation of this alignment path.""" return self.__repr__() def __repr__(self) -> str: r"""Return summary of the alignment path.""" repr_ = ( f"{self.__class__.__name__}, " f"positions: {self._shape[1]}, " f"segments: {self._lengths.size}" ) width = 66 - len(repr_) # maximum line width: 79 cigar = self.to_cigar() if len(cigar) > width: cigar = cigar[: max(width - 3, 0)] + "..." return f"<{repr_}, CIGAR: '{cigar}'>" @classonlymethod def from_bits(cls, bits, starts=None) -> Self: r"""Create a pairwise alignment path from a bit array. Refer to :meth:`AlignPath.from_bits` for usage. Parameters ---------- bits : array_like of (0, 1) of shape (2, n_positions) Bit array representing the alignment. starts : array_like of int of shape (2,), optional Start positions of sequences. Returns ------- PairAlignPath The pairwise alignment path created from the given bit array. See Also -------- AlignPath.from_bits """ bits = np.asarray(bits) if bits.shape[0] != 2: raise ValueError( "A pairwise alignment must represent exactly two sequences, but " f"{bits.shape[0]} were given." ) return super().from_bits(bits, starts) def to_cigar(self, seqs: list["Sequence" | str] | None = None): r"""Generate a CIGAR string representing the pairwise alignment path. Parameters ---------- seqs : list of skbio.Sequence or string A pair of sequences to generate CIGAR string. If provided, will distinguish match (``=``) and mismatch (``X``). Otherwise, will uniformly note them as (mis)match (``M``). The first sequence in the list is the query sequence, the second is the reference sequence. Returns ------- str CIGAR string representing the pairwise alignment path. Examples -------- >>> from skbio.alignment import PairAlignPath >>> path = PairAlignPath(lengths=[2, 5, 3, 1], ... states=[0, 3, 2, 1], ... starts=[0, 0]) >>> path.to_cigar() '2M5P3D1I' """ from skbio.sequence import Sequence cigar = [] states = np.squeeze(self._states) # TODO: Make this compatible with `SequenceLike`. if seqs is not None: # test if seqs is strings or Sequence object or something else if isinstance(seqs[0], str) and isinstance(seqs[1], str): seq1 = np.frombuffer(seqs[0].encode("ascii"), dtype=np.uint8) seq2 = np.frombuffer(seqs[1].encode("ascii"), dtype=np.uint8) elif isinstance(seqs[0], Sequence) and isinstance(seqs[1], Sequence): seq1 = seqs[0]._bytes seq2 = seqs[1]._bytes else: raise TypeError("`seqs` must be strings or Sequence objects.") idx1, idx2 = self._ranges[:, 0] for length, state in zip(self._lengths, states): if state == 0: match_arr = seq1[idx1 : idx1 + length] == seq2[idx2 : idx2 + length] char_arr = np.where(match_arr, "=", "X") n = len(char_arr) count = 1 curr_char = char_arr[0] for i in range(1, n): if char_arr[i] == curr_char: count += 1 else: cigar.append(str(count) + curr_char) curr_char = char_arr[i] count = 1 cigar.append(str(count) + curr_char) idx1 += length idx2 += length elif state == 1: cigar.append(str(length) + "I") idx2 += length elif state == 2: cigar.append(str(length) + "D") idx1 += length else: # state == 3: cigar.append(str(length) + "P") return "".join(cigar) else: return "".join( f"{L}{C}" for L, C in zip(self._lengths, _cigar_codes[states]) ) @classonlymethod def from_cigar(cls, cigar: str | bytes, starts: ArrayLike | None = None) -> Self: r"""Create a pairwise alignment path from a CIGAR string. Parameters ---------- cigar : str or bytes CIGAR format string used to build the PairAlignPath. starts : array_like of (int, int), optional Start position of each sequence in the alignment. If omitted, will set as zeros. Returns ------- PairAlignPath The pairwise alignment path created from the given CIGAR string. Raises ------ ValueError CIGAR string is empty. ValueError CIGAR string contains invalid characters. Examples -------- >>> from skbio.alignment import PairAlignPath >>> cigar = "2M5P3D1I" >>> path = PairAlignPath.from_cigar(cigar) >>> path """ if not cigar: raise ValueError("CIGAR string must not be empty.") if isinstance(cigar, str): try: cigar = cigar.encode("ascii") except UnicodeEncodeError: raise ValueError("CIGAR string contains invalid character(s).") lens, gaps = _parse_cigar(cigar) return cls(lens, gaps, starts=(starts or [0, 0])) def _parse_cigar(cigar: bytes) -> tuple[NDArray, NDArray]: r"""Convert a CIGAR string into run-length vectors. Parameters ---------- cigar : bytes CIGAR string. Returns ------- ndarray of intp Lengths. ndarray of uint8 Gap states. """ lens: list[int] = [] gaps: list[int] = [] L, no_ones, last = 0, 1, None for char in cigar: if char in _cigar_mapping: # letter (operation) curr = _cigar_mapping[char] if curr == last: lens[-1] += L + no_ones else: lens.append(L + no_ones) gaps.append(curr) last = curr L, no_ones = 0, 1 elif 48 <= char <= 57: # number (length) no_ones = 0 L = L * 10 + char - 48 else: raise ValueError("CIGAR string contains invalid character(s).") return ( np.array(lens, dtype=np.intp), np.array(gaps, dtype=np.uint8), ) def _merge_same_1d(lens, gaps): r"""Merge consecutive same gap states and sum corresponding lengths. Parameters ---------- lens : ndarray of int of shape (n_segments,) Segment lengths. gaps : ndarray of uint8 of shape (n_segments,) Segment states. Returns ------- ndarray of int of shape (n_merged_segments,) Merged segment lengths. ndarray of uint8 of shape (n_merged_segments,) Merged segment states. """ idx = np.flatnonzero(np.r_[True, gaps[1:] != gaps[:-1]]) return np.add.reduceat(lens, idx, dtype=lens.dtype), gaps[idx] def _merge_same_2d(lens, gaps): r"""Merge consecutive same gap states and sum corresponding lengths. Similar to ``_merge_same_1d`` but applies to a 2-D gaps array. """ idx = np.flatnonzero(np.r_[True, (gaps[:, 1:] != gaps[:, :-1]).any(axis=0)]) return np.add.reduceat(lens, idx, dtype=lens.dtype), gaps[:, idx] def _run_length_encode(s): r"""Perform run length encoding on a string. Parameters ---------- s : str String on which to perform run length encoding. """ input_arr = np.array(list(s)) idx = np.append(0, np.where(input_arr[:-1] != input_arr[1:])[0] + 1) count = np.diff(np.concatenate((idx, [len(s)]))) unique = input_arr[idx] return "".join(str(c) + u for c, u in zip(count, unique)) scikit-bio-scikit-bio-a3beaa6/skbio/alignment/_repr.py000066400000000000000000000050321520735541300231210ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from skbio.metadata._repr import _MetadataReprBuilder class _TabularMSAReprBuilder(_MetadataReprBuilder): def __init__(self, msa, width, indent): super(_TabularMSAReprBuilder, self).__init__(msa, width, indent) self._ellipse_insert = " ... " def _process_header(self): cls_name = self._obj.__class__.__name__ if self._obj.dtype is not None: dtype_class = "[" + self._obj.dtype.__name__ + "]" else: dtype_class = "" self._lines.add_line(cls_name + dtype_class) self._lines.add_separator() def _process_data(self): num_sequences = self._obj.shape.sequence num_positions = self._obj.shape.position # catch case of all empty sequences if num_positions > 0: # display all sequences if we can, else display the first two and # last two sequences separated by ellipsis if num_sequences <= 5: self._lines.add_lines(self._format_sequences(range(num_sequences))) else: self._lines.add_lines(self._format_sequences(range(2))) self._lines.add_line("...") self._lines.add_lines( self._format_sequences(range(num_sequences - 2, num_sequences)) ) def _format_sequences(self, sequence_indices): lines = [] for line_index in sequence_indices: seq_str = str(self._obj._get_sequence_iloc_(line_index)) if len(seq_str) <= self._width: formatted_seq = seq_str else: formatted_seq = ( seq_str[0 : self._num_characters_before_ellipse()] + self._ellipse_insert + seq_str[-self._num_characters_after_ellipse() :] ) lines.append(formatted_seq) return lines def _num_characters_before_ellipse(self): return int(self._num_characters_to_display() / 2) def _num_characters_after_ellipse(self): return self._num_characters_to_display() - self._num_characters_before_ellipse() def _num_characters_to_display(self): return self._width - len(self._ellipse_insert) scikit-bio-scikit-bio-a3beaa6/skbio/alignment/_score.py000066400000000000000000000106041520735541300232650ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from typing import TYPE_CHECKING import numpy as np from ._utils import encode_alignment, prep_gapcost from ._cutils import _trim_end_gaps, _multi_align_score if TYPE_CHECKING: # pragma: no cover from ._utils import AlignmentLike from skbio.sequence import SubstitutionMatrix def align_score( alignment: AlignmentLike, sub_score: tuple[float, float] | SubstitutionMatrix | str = (1.0, -1.0), gap_cost: float | tuple[float, float] = 2.0, free_ends: bool = True, gap_chars: str = "-.", ) -> float: r"""Calculate the alignment score of two or more aligned sequences. For two sequences, their pairwise alignment score will be calculated. For three or more sequences, the sum-of-pairs (SP) alignment score will be returned. .. versionadded:: 0.7.0 Parameters ---------- alignment : TabularMSA, iterable, or (AlignPath, iterable) Aligned sequences. Can be any of the following: - :class:`~skbio.alignment.TabularMSA`. - List of *aligned* sequences as raw strings or ``Sequence`` objects. - Tuple of :class:`~skbio.alignment.AlignPath` and the corresponding list of *original* (unaligned) sequences. sub_score : tuple of (float, float), SubstitutionMatrix, or str Score of a substitution. May be two numbers (match, mismatch), a substitution matrix, or its name. See :func:`pair_align` for details. Default is (1.0, -1.0). gap_cost : float or tuple of (float, float) Penalty of a gap. May be one (linear) or two numbers (affine). See :func:`pair_align` for details. Default is 2.0. free_ends : bool, optional If True (default), gaps at the sequence terminals are free from penalization. gap_chars : iterable of 1-length str, optional Character(s) that represent gaps. Only relevant when ``alignment`` is a list of aligned sequences. Returns ------- float Alignment score. Raises ------ ValueError If there are less than two sequences in the alignment. ValueError If the alignment has zero length. ValueError If any sequence in the alignment contains only gaps. ValueError If any sequence contains characters not present in the designated substitution matrix. See Also -------- pair_align skbio.sequence.SubstitutionMatrix Examples -------- >>> from skbio.sequence import DNA, Protein >>> from skbio.alignment import TabularMSA, align_score Calculate the score of a pair of aligned DNA sequences, with match score = 2, mismatch score = -3, gap opening penalty = 5, and gap extension penalty = 2 (the default BLASTN parameters). >>> seq1 = DNA("CGGTCGTAACGCGTA---CA") >>> seq2 = DNA("CAG--GTAAG-CATACCTCA") >>> align_score([seq1, seq2], (2, -3), (5, 2)) -14.0 Calculate the score of a multiple alignment of protein sequences, using the BLOSUM62 substitution matrix, with gap opening and extension penalties being 11 and 1 (the default BLASTP parameters). Note that terminal gaps are not penalized by default unless ``free_ends`` is set to False. >>> msa = TabularMSA([Protein("MKQ-PSV"), ... Protein("MKIDTS-"), ... Protein("MVIDPSS")]) >>> align_score(msa, "BLOSUM62", (11, 1)) 11.0 """ # process input alignment seqs, submat, bits, lens = encode_alignment(alignment, sub_score, gap_chars) if (n := seqs.shape[0]) < 2: raise ValueError("Alignment must contain at least two sequences.") # determine gap penalty method gap_open, gap_extend = prep_gapcost(gap_cost, dtype=submat.dtype.type) # identify terminal gaps starts, stops = np.empty(n, dtype=int), np.empty(n, dtype=int) _trim_end_gaps(bits, starts, stops) if not (starts + stops).all(): raise ValueError("The alignment contains gap-only sequence(s).") return _multi_align_score( seqs, bits, lens, starts, stops, submat, gap_open, gap_extend, free_ends ) scikit-bio-scikit-bio-a3beaa6/skbio/alignment/_tabular_msa.py000066400000000000000000002452401520735541300244520ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from collections import Counter, namedtuple import copy from typing import TYPE_CHECKING import numpy as np import pandas as pd import scipy.stats from skbio._base import SkbioObject from skbio.metadata._mixin import MetadataMixin, PositionalMetadataMixin from skbio.sequence import Sequence from skbio.sequence._grammared_sequence import GrammaredSequence from skbio.util._decorator import classonlymethod, overrides from skbio.util._misc import resolve_key from skbio.alignment._indexing import TabularMSAILoc, TabularMSALoc from skbio.io.descriptors import Read, Write from skbio.alignment._repr import _TabularMSAReprBuilder if TYPE_CHECKING: from typing import Self _Shape = namedtuple("Shape", ["sequence", "position"]) # type: ignore[name-match] class TabularMSA(MetadataMixin, PositionalMetadataMixin, SkbioObject): """Store a multiple sequence alignment in tabular (row/column) form. Parameters ---------- sequences : iterable of GrammaredSequence, TabularMSA Aligned sequences in the MSA. Sequences must all be the same type and length. For example, `sequences` could be an iterable of ``DNA``, ``RNA``, or ``Protein`` sequences. If `sequences` is a ``TabularMSA``, its `metadata`, `positional_metadata`, and `index` will be used unless overridden by parameters `metadata`, `positional_metadata`, and `minter`/`index`, respectively. metadata : dict, optional Arbitrary metadata which applies to the entire MSA. A shallow copy of the ``dict`` will be made. positional_metadata : pd.DataFrame consumable, optional Arbitrary metadata which applies to each position in the MSA. Must be able to be passed directly to ``pd.DataFrame`` constructor. Each column of metadata must be the same length as the number of positions in the MSA. A shallow copy of the positional metadata will be made. minter : callable or metadata key, optional If provided, defines an index label for each sequence in `sequences`. Can either be a callable accepting a single argument (each sequence) or a key into each sequence's ``metadata`` attribute. Note that `minter` cannot be combined with `index`. index : pd.Index consumable, optional Index containing labels for `sequences`. Must be the same length as `sequences`. Must be able to be passed directly to ``pd.Index`` constructor. Note that `index` cannot be combined with `minter` and the contents of `index` must be hashable. Raises ------ ValueError If `minter` and `index` are both provided. ValueError If `index` is not the same length as `sequences`. TypeError If `sequences` contains an object that isn't a ``GrammaredSequence``. TypeError If `sequences` does not contain exactly the same type of ``GrammaredSequence`` objects. ValueError If `sequences` does not contain ``GrammaredSequence`` objects of the same length. See Also -------- skbio.sequence.DNA skbio.sequence.RNA skbio.sequence.Protein pandas.DataFrame pandas.Index reassign_index Notes ----- If neither `minter` nor `index` are provided, default index labels will be used: ``pd.RangeIndex(start=0, stop=len(sequences), step=1)``. Examples -------- Create a ``TabularMSA`` object with three DNA sequences and four positions: >>> from skbio import DNA, TabularMSA >>> seqs = [ ... DNA('ACGT'), ... DNA('AG-T'), ... DNA('-C-T') ... ] >>> msa = TabularMSA(seqs) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 3 position count: 4 --------------------- ACGT AG-T -C-T Since `minter` or `index` wasn't provided, the MSA has default index labels: >>> msa.index RangeIndex(start=0, stop=3, step=1) Create an MSA with metadata, positional metadata, and non-default index labels: >>> msa = TabularMSA(seqs, index=['seq1', 'seq2', 'seq3'], ... metadata={'id': 'msa-id'}, ... positional_metadata={'prob': [3, 4, 2, 2]}) >>> msa TabularMSA[DNA] -------------------------- Metadata: 'id': 'msa-id' Positional metadata: 'prob': Stats: sequence count: 3 position count: 4 -------------------------- ACGT AG-T -C-T >>> msa.index # doctest: +ELLIPSIS Index(['seq1', 'seq2', 'seq3'], dtype='...') """ default_write_format = "fasta" """Default write format for this object: ``fasta``.""" __hash__ = None # type: ignore[assignment] _reader_kwargs = { "constructor": ( "type, required\n" " The type of sequence to read each alignment entry into. Must be a\n" " subclass of :class:`~skbio.sequence.GrammaredSequence` (e.g., \n" " :class:`~skbio.sequence.DNA`, :class:`~skbio.sequence.RNA`,\n" " :class:`~skbio.sequence.Protein`). Required by most formats that \n" " read into a ``TabularMSA``." ) } read = Read() write = Write() @property def dtype(self): """Data type of the stored sequences. Notes ----- This property is not writeable. Examples -------- >>> from skbio import DNA, TabularMSA >>> msa = TabularMSA([DNA('ACG'), DNA('AC-')]) >>> msa.dtype >>> msa.dtype is DNA True """ return type(self._get_sequence_iloc_(0)) if len(self) > 0 else None @property def shape(self): """Number of sequences (rows) and positions (columns). Notes ----- This property is not writeable. Examples -------- >>> from skbio import DNA, TabularMSA Create a ``TabularMSA`` object with 2 sequences and 3 positions: >>> msa = TabularMSA([DNA('ACG'), DNA('AC-')]) >>> msa.shape Shape(sequence=2, position=3) >>> msa.shape == (2, 3) True Dimensions can be accessed by index or by name: >>> msa.shape[0] 2 >>> msa.shape.sequence 2 >>> msa.shape[1] 3 >>> msa.shape.position 3 """ sequence_count = len(self) if sequence_count > 0: position_count = len(self._get_sequence_iloc_(0)) else: position_count = 0 return _Shape(sequence=sequence_count, position=position_count) @property def index(self): """Index containing labels along the sequence axis. Returns ------- pd.Index Index containing sequence labels. See Also -------- reassign_index Notes ----- This property can be set and deleted. Deleting the index will reset the index to the ``TabularMSA`` constructor's default. Examples -------- Create a ``TabularMSA`` object with sequences labeled by sequence identifier: >>> from skbio import DNA, TabularMSA >>> seqs = [DNA('ACG', metadata={'id': 'a'}), ... DNA('AC-', metadata={'id': 'b'}), ... DNA('AC-', metadata={'id': 'c'})] >>> msa = TabularMSA(seqs, minter='id') Retrieve index: >>> msa.index # doctest: +ELLIPSIS Index(['a', 'b', 'c'], dtype='...') Set index: >>> msa.index = ['seq1', 'seq2', 'seq3'] >>> msa.index # doctest: +ELLIPSIS Index(['seq1', 'seq2', 'seq3'], dtype='...') Deleting the index resets it to the ``TabularMSA`` constructor's default: >>> del msa.index >>> msa.index RangeIndex(start=0, stop=3, step=1) """ return self._seqs.index @index.setter def index(self, index): # Cast to Index to identify tuples as a MultiIndex to match # pandas constructor. Just setting would make an index of tuples. if not isinstance(index, pd.Index): index = pd.Index(index) self._seqs.index = index @index.deleter def index(self): # Create a memory-efficient integer index as the default MSA index. self._seqs.index = pd.RangeIndex(start=0, stop=len(self), step=1) @property def loc(self): """Slice the MSA on first axis by index label, second axis by position. This will return an object with the following interface: .. code-block:: python msa.loc[seq_idx] msa.loc[seq_idx, pos_idx] msa.loc(axis='sequence')[seq_idx] msa.loc(axis='position')[pos_idx] Parameters ---------- seq_idx : label, slice, 1D array_like (bool or label) Slice the first axis of the MSA. When this value is a scalar, a sequence of ``msa.dtype`` will be returned. This may be further sliced by `pos_idx`. pos_idx : (same as seq_idx), optional Slice the second axis of the MSA. When this value is a scalar, a sequence of type :class:`skbio.sequence.Sequence` will be returned. This represents a column of the MSA and may have been additionally sliced by `seq_idx`. axis : {'sequence', 'position', 0, 1, None}, optional Limit the axis to slice on. When set, a tuple as the argument will no longer be split into `seq_idx` and `pos_idx`. Returns ------- TabularMSA, GrammaredSequence, Sequence A ``TabularMSA`` is returned when `seq_idx` and `pos_idx` are non-scalars. A ``GrammaredSequence`` of type ``msa.dtype`` is returned when `seq_idx` is a scalar (this object will match the dtype of the MSA). A ``Sequence`` is returned when `seq_idx` is non-scalar and `pos_idx` is scalar. See Also -------- iloc __getitem__ Notes ----- If the slice operation results in a ``TabularMSA`` without any sequences, the MSA's ``positional_metadata`` will be unset. When the MSA's index is a ``pd.MultiIndex`` a tuple may be given to `seq_idx` to indicate the slicing operations to perform on each component index. Examples -------- First we need to set up an MSA to slice: >>> from skbio import TabularMSA, DNA >>> msa = TabularMSA([DNA("ACGT"), DNA("A-GT"), DNA("AC-T"), ... DNA("ACGA")], index=['a', 'b', 'c', 'd']) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 4 position count: 4 --------------------- ACGT A-GT AC-T ACGA >>> msa.index # doctest: +ELLIPSIS Index(['a', 'b', 'c', 'd'], dtype='...') When we slice by a scalar we get the original sequence back out of the MSA: >>> msa.loc['b'] DNA -------------------------- Stats: length: 4 has gaps: True has degenerates: False has definites: True GC-content: 33.33% -------------------------- 0 A-GT Similarly when we slice the second axis by a scalar we get a column of the MSA: >>> msa.loc[..., 1] Sequence ------------- Stats: length: 4 ------------- 0 C-CC Note: we return an ``skbio.Sequence`` object because the column of an alignment has no biological meaning and many operations defined for the MSA's sequence `dtype` would be meaningless. When we slice both axes by a scalar, operations are applied left to right: >>> msa.loc['a', 0] DNA -------------------------- Stats: length: 1 has gaps: False has degenerates: False has definites: True GC-content: 0.00% -------------------------- 0 A In other words, it exactly matches slicing the resulting sequence object directly: >>> msa.loc['a'][0] DNA -------------------------- Stats: length: 1 has gaps: False has degenerates: False has definites: True GC-content: 0.00% -------------------------- 0 A When our slice is non-scalar we get back an MSA of the same `dtype`: >>> msa.loc[['a', 'c']] TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 4 --------------------- ACGT AC-T We can similarly slice out a column of that: >>> msa.loc[['a', 'c'], 2] Sequence ------------- Stats: length: 2 ------------- 0 G- Slice syntax works as well: >>> msa.loc[:'c'] TabularMSA[DNA] --------------------- Stats: sequence count: 3 position count: 4 --------------------- ACGT A-GT AC-T Notice how the end label is included in the results. This is different from how positional slices behave: >>> msa.loc[[True, False, False, True], 2:3] TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 1 --------------------- G G Here we sliced the first axis by a boolean vector, but then restricted the columns to a single column. Because the second axis was given a nonscalar we still receive an MSA even though only one column is present. Duplicate labels can be an unfortunate reality in the real world, however `loc` is capable of handling this: >>> msa.index = ['a', 'a', 'b', 'c'] Notice how the label 'a' happens twice. If we were to access 'a' we get back an MSA with both sequences: >>> msa.loc['a'] TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 4 --------------------- ACGT A-GT Remember that `iloc` can always be used to differentiate sequences with duplicate labels. More advanced slicing patterns are possible with different index types. Let's use a `pd.MultiIndex`: >>> msa.index = [('a', 0), ('a', 1), ('b', 0), ('b', 1)] Here we will explicitly set the axis that we are slicing by to make things easier to read: >>> msa.loc(axis='sequence')['a', 0] DNA -------------------------- Stats: length: 4 has gaps: False has degenerates: False has definites: True GC-content: 50.00% -------------------------- 0 ACGT This selected the first sequence because the complete label was provided. In other words `('a', 0)` was treated as a scalar for this index. We can also slice along the component indices of the multi-index: >>> msa.loc(axis='sequence')[:, 1] TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 4 --------------------- A-GT ACGA If we were to do that again without the `axis` argument, it would look like this: >>> msa.loc[(slice(None), 1), ...] TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 4 --------------------- A-GT ACGA Notice how we needed to specify the second axis. If we had left that out we would have simply gotten the 2nd column back instead. We also lost the syntactic sugar for slice objects. These are a few of the reasons specifying the `axis` preemptively can be useful. """ return self._loc @property def iloc(self): """Slice the MSA on either axis by index position. This will return an object with the following interface: .. code-block:: python msa.iloc[seq_idx] msa.iloc[seq_idx, pos_idx] msa.iloc(axis='sequence')[seq_idx] msa.iloc(axis='position')[pos_idx] Parameters ---------- seq_idx : int, slice, iterable (int and slice), 1D array_like (bool) Slice the first axis of the MSA. When this value is a scalar, a sequence of ``msa.dtype`` will be returned. This may be further sliced by `pos_idx`. pos_idx : (same as seq_idx), optional Slice the second axis of the MSA. When this value is a scalar, a sequence of type :class:`skbio.sequence.Sequence` will be returned. This represents a column of the MSA and may have been additionally sliced by `seq_idx`. axis : {'sequence', 'position', 0, 1, None}, optional Limit the axis to slice on. When set, a tuple as the argument will no longer be split into `seq_idx` and `pos_idx`. Returns ------- TabularMSA, GrammaredSequence, Sequence A ``TabularMSA`` is returned when `seq_idx` and `pos_idx` are non-scalars. A ``GrammaredSequence`` of type ``msa.dtype`` is returned when `seq_idx` is a scalar (this object will match the dtype of the MSA). A ``Sequence`` is returned when `seq_idx` is non-scalar and `pos_idx` is scalar. See Also -------- __getitem__ loc Notes ----- If the slice operation results in a ``TabularMSA`` without any sequences, the MSA's ``positional_metadata`` will be unset. Examples -------- First we need to set up an MSA to slice: >>> from skbio import TabularMSA, DNA >>> msa = TabularMSA([DNA("ACGT"), DNA("A-GT"), DNA("AC-T"), ... DNA("ACGA")]) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 4 position count: 4 --------------------- ACGT A-GT AC-T ACGA When we slice by a scalar we get the original sequence back out of the MSA: >>> msa.iloc[1] DNA -------------------------- Stats: length: 4 has gaps: True has degenerates: False has definites: True GC-content: 33.33% -------------------------- 0 A-GT Similarly when we slice the second axis by a scalar we get a column of the MSA: >>> msa.iloc[..., 1] Sequence ------------- Stats: length: 4 ------------- 0 C-CC Note: we return an ``skbio.Sequence`` object because the column of an alignment has no biological meaning and many operations defined for the MSA's sequence `dtype` would be meaningless. When we slice both axes by a scalar, operations are applied left to right: >>> msa.iloc[0, 0] DNA -------------------------- Stats: length: 1 has gaps: False has degenerates: False has definites: True GC-content: 0.00% -------------------------- 0 A In other words, it exactly matches slicing the resulting sequence object directly: >>> msa.iloc[0][0] DNA -------------------------- Stats: length: 1 has gaps: False has degenerates: False has definites: True GC-content: 0.00% -------------------------- 0 A When our slice is non-scalar we get back an MSA of the same `dtype`: >>> msa.iloc[[0, 2]] TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 4 --------------------- ACGT AC-T We can similarly slice out a column of that: >>> msa.iloc[[0, 2], 2] Sequence ------------- Stats: length: 2 ------------- 0 G- Slice syntax works as well: >>> msa.iloc[:3] TabularMSA[DNA] --------------------- Stats: sequence count: 3 position count: 4 --------------------- ACGT A-GT AC-T We can also use boolean vectors: >>> msa.iloc[[True, False, False, True], 2:3] TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 1 --------------------- G G Here we sliced the first axis by a boolean vector, but then restricted the columns to a single column. Because the second axis was given a nonscalar we still receive an MSA even though only one column is present. """ return self._iloc @classonlymethod def from_dict(cls, dictionary: dict) -> Self: """Create a ``TabularMSA`` from a ``dict``. Parameters ---------- dictionary : dict Dictionary mapping keys to ``GrammaredSequence`` sequence objects. The ``TabularMSA`` object will have its index labels set to the keys in the dictionary. Returns ------- TabularMSA ``TabularMSA`` object constructed from the keys and sequences in `dictionary`. See Also -------- to_dict sort Notes ----- The order of sequences and index labels in the resulting ``TabularMSA`` object is arbitrary. Use ``TabularMSA.sort`` to set a different order. Examples -------- >>> from skbio import DNA, TabularMSA >>> seqs = {'a': DNA('ACGT'), 'b': DNA('A--T')} >>> msa = TabularMSA.from_dict(seqs) >>> msa.shape Shape(sequence=2, position=4) >>> 'a' in msa True >>> 'b' in msa True """ # Python 3 guarantees same order of iteration as long as no # modifications are made to the dictionary between calls: # https://docs.python.org/3/library/stdtypes.html# # dictionary-view-objects return cls(dictionary.values(), index=dictionary.keys()) def __init__( self, sequences, metadata=None, positional_metadata=None, minter=None, index=None, ): if isinstance(sequences, TabularMSA): if metadata is None and sequences.has_metadata(): metadata = sequences.metadata if positional_metadata is None and sequences.has_positional_metadata(): positional_metadata = sequences.positional_metadata if minter is None and index is None: index = sequences.index # Give a better error message than the one raised by `extend` (it # references `reset_index`, which isn't a constructor parameter). if minter is not None and index is not None: raise ValueError("Cannot use both `minter` and `index` at the same time.") self._seqs = pd.Series([], dtype=object) self.extend( sequences, minter=minter, index=index, reset_index=minter is None and index is None, ) MetadataMixin._init_(self, metadata=metadata) PositionalMetadataMixin._init_(self, positional_metadata=positional_metadata) # Set up our indexers self._loc = TabularMSALoc(self) self._iloc = TabularMSAILoc(self) def _constructor_( self, sequences=NotImplemented, metadata=NotImplemented, positional_metadata=NotImplemented, index=NotImplemented, ): """Return new copy of the MSA with overridden properties. NotImplemented is used as a sentinel so that None may be used to override values. """ if metadata is NotImplemented: if self.has_metadata(): metadata = self.metadata else: metadata = None if positional_metadata is NotImplemented: if self.has_positional_metadata(): positional_metadata = self.positional_metadata else: positional_metadata = None if index is NotImplemented: if isinstance(sequences, pd.Series): index = sequences.index else: index = self.index if sequences is NotImplemented: sequences = self._seqs sequences = [copy.copy(s) for s in sequences] return self.__class__( sequences, metadata=metadata, positional_metadata=positional_metadata, index=index, ) def __repr__(self): """Return string summary of this MSA.""" pep8_line_length_limit = 79 length_taken_by_docstring_indent = 8 width = pep8_line_length_limit - length_taken_by_docstring_indent return _TabularMSAReprBuilder(msa=self, width=width, indent=4).build() def _repr_stats(self): return [ ("sequence count", str(self.shape.sequence)), ("position count", str(self.shape.position)), ] def __bool__(self): """Boolean indicating whether the MSA is empty or not. Returns ------- bool ``False`` if there are no sequences, OR if there are no positions (i.e., all sequences are empty). ``True`` otherwise. Examples -------- >>> from skbio import DNA, TabularMSA MSA with sequences and positions: >>> msa = TabularMSA([DNA('ACG'), DNA('AC-')]) >>> bool(msa) True No sequences: >>> msa = TabularMSA([]) >>> bool(msa) False No positions: >>> msa = TabularMSA([DNA(''), DNA('')]) >>> bool(msa) False """ # It is impossible to have 0 sequences and >0 positions. # TODO: change for #1198 return self.shape.position > 0 def __contains__(self, label): """Determine if an index label is in this MSA. Parameters ---------- label : hashable Label to search for in this MSA. Returns ------- bool Indicates whether `label` is in this MSA. Examples -------- >>> from skbio import DNA, TabularMSA >>> msa = TabularMSA([DNA('ACG'), DNA('AC-')], index=['l1', 'l2']) >>> 'l1' in msa True >>> 'l2' in msa True >>> 'l3' in msa False """ return label in self.index def __len__(self): """Return number of sequences in the MSA. Returns ------- int Number of sequences in the MSA (i.e., size of the 1st dimension). Notes ----- This is equivalent to ``msa.shape[0]``. Examples -------- >>> from skbio import DNA, TabularMSA >>> msa = TabularMSA([DNA('ACG'), DNA('AC-')]) >>> len(msa) 2 >>> msa = TabularMSA([]) >>> len(msa) 0 """ return len(self._seqs) def __iter__(self): """Iterate over sequences in the MSA. Yields ------ GrammaredSequence Each sequence in the order they are stored in the MSA. Examples -------- >>> from skbio import DNA, TabularMSA >>> msa = TabularMSA([DNA('ACG'), DNA('AC-')]) >>> for seq in msa: ... str(seq) 'ACG' 'AC-' """ return iter(self._seqs) def __reversed__(self): """Iterate in reverse order over sequences in the MSA. Yields ------ GrammaredSequence Each sequence in reverse order from how they are stored in the MSA. Examples -------- >>> from skbio import DNA, TabularMSA >>> msa = TabularMSA([DNA('ACG'), DNA('AC-')]) >>> for seq in reversed(msa): ... str(seq) 'AC-' 'ACG' """ return reversed(self._seqs) def __str__(self): """Return string summary of this MSA.""" return self.__repr__() def __eq__(self, other): """Determine if this MSA is equal to another. ``TabularMSA`` objects are equal if their sequences, index, metadata, and positional metadata are equal. Parameters ---------- other : TabularMSA MSA to test for equality against. Returns ------- bool Indicates whether this MSA is equal to `other`. Examples -------- >>> from skbio import DNA, RNA, TabularMSA >>> msa = TabularMSA([DNA('ACG'), DNA('AC-')]) >>> msa == msa True MSAs with different sequence characters are not equal: >>> msa == TabularMSA([DNA('ACG'), DNA('--G')]) False MSAs with different types of sequences (different ``dtype``) are not equal: >>> msa == TabularMSA([RNA('ACG'), RNA('AC-')]) False MSAs with different sequence metadata are not equal: >>> msa == TabularMSA([DNA('ACG', metadata={'id': 'a'}), DNA('AC-')]) False MSAs with different index labels are not equal: >>> msa == TabularMSA([DNA('ACG'), DNA('AC-')], minter=str) False MSAs with different metadata are not equal: >>> msa == TabularMSA([DNA('ACG'), DNA('AC-')], ... metadata={'id': 'msa-id'}) False MSAs with different positional metadata are not equal: >>> msa == TabularMSA([DNA('ACG'), DNA('AC-')], ... positional_metadata={'prob': [3, 2, 1]}) False """ if not isinstance(other, TabularMSA): return False if not MetadataMixin._eq_(self, other): return False if not PositionalMetadataMixin._eq_(self, other): return False return self._seqs.equals(other._seqs) def __ne__(self, other): """Determine if this MSA is not equal to another. ``TabularMSA`` objects are not equal if their sequences, index, metadata, or positional metadata are not equal. Parameters ---------- other : TabularMSA MSA to test for inequality against. Returns ------- bool Indicates whether this MSA is not equal to `other`. See Also -------- __eq__ """ return not (self == other) def __copy__(self): """Return a shallow copy of this MSA. Returns ------- TabularMSA Shallow copy of this MSA. Sequence objects will be shallow-copied. See Also -------- __deepcopy__ Examples -------- >>> import copy >>> from skbio import DNA, TabularMSA >>> msa = TabularMSA([DNA('ACG'), DNA('AC-')]) >>> msa_copy = copy.copy(msa) >>> msa_copy == msa True >>> msa_copy is msa False """ msa_copy = self._constructor_() msa_copy._metadata = MetadataMixin._copy_(self) msa_copy._positional_metadata = PositionalMetadataMixin._copy_(self) return msa_copy def __deepcopy__(self, memo): """Return a deep copy of this MSA. Returns ------- TabularMSA Deep copy of this MSA. Sequence objects will be deep-copied. See Also -------- __copy__ Examples -------- >>> import copy >>> from skbio import DNA, TabularMSA >>> msa = TabularMSA([DNA('ACG'), DNA('AC-')]) >>> msa_copy = copy.deepcopy(msa) >>> msa_copy == msa True >>> msa_copy is msa False """ seqs = (copy.deepcopy(seq, memo) for seq in self._seqs) msa_copy = self._constructor_(sequences=seqs) msa_copy._metadata = MetadataMixin._deepcopy_(self, memo) msa_copy._positional_metadata = PositionalMetadataMixin._deepcopy_(self, memo) return msa_copy def __getitem__(self, indexable): """Slice the MSA on either axis. This is a pass-through for :func:`skbio.alignment.TabularMSA.iloc`. Please refer to the associated documentation. See Also -------- iloc loc Notes ----- Axis restriction is not possible for this method. To slice by labels, use ``loc``. """ return self.iloc[indexable] # Helpers for TabularMSAILoc and TabularMSALoc def _get_sequence_iloc_(self, i): return self._seqs.iloc[i] def _slice_sequences_iloc_(self, i): new_seqs = self._seqs.iloc[i] # TODO: change for #1198 if len(new_seqs) == 0: return self._constructor_(new_seqs, positional_metadata=None) return self._constructor_(new_seqs) def _get_sequence_loc_(self, ids): new_seqs = self._seqs.loc[ids] if type(new_seqs) is self.dtype: return new_seqs else: # Thanks CategoricalIndex, you understand no such thing as a scalar if len(new_seqs) == 1: return new_seqs.iloc[0] else: # This was a common failure mode; shouldn't happen anymore, but # it could strike again. raise AssertionError( "Something went wrong with the index %r provided to" " `_get_sequence_loc_`, please report this stack trace to" "\nhttps://github.com/scikit-bio/scikit-bio/issues" % ids ) def _slice_sequences_loc_(self, ids): new_seqs = self._seqs.loc[ids] try: # TODO: change for #1198 if len(new_seqs) == 0: return self._constructor_(new_seqs, positional_metadata=None) return self._constructor_(new_seqs) except TypeError: # NaN hit the constructor, key was bad... probably raise KeyError("Part of `%r` was not in the index." % ids) def _get_position_(self, i, ignore_metadata=False): if ignore_metadata: return Sequence("".join([str(s[i]) for s in self._seqs])) seq = Sequence.concat([s[i] for s in self._seqs], how="outer") # TODO: change for #1198 if len(self) and self.has_positional_metadata(): seq.metadata = dict(self.positional_metadata.iloc[i]) return seq def _slice_positions_(self, i): seqs = self._seqs.apply(lambda seq: seq[i]) # TODO: change for #1198 pm = None if len(self) and self.has_positional_metadata(): pm = self.positional_metadata.iloc[i] return self._constructor_(seqs, positional_metadata=pm) # end of helpers def iter_positions(self, reverse=False, ignore_metadata=False): """Iterate over positions (columns) in the MSA. Parameters ---------- reverse : bool, optional If ``True``, iterate over positions in reverse order. ignore_metadata : bool, optional If ``True``, ``Sequence.metadata`` and ``Sequence.positional_metadata`` will not be included. This can significantly improve performance if metadata is not needed. Yields ------ Sequence Each position in the order they are stored in the MSA. See Also -------- __iter__ __reversed__ skbio.sequence.Sequence.concat Notes ----- Each position will be yielded as *exactly* a ``Sequence`` object, regardless of this MSA's ``dtype``. ``Sequence`` is used because a position is an artifact of multiple sequence alignment and is not a real biological sequence. Each ``Sequence`` object will have its corresponding MSA positional metadata stored as ``metadata`` unless ``ignore_metadata`` is set to ``True``. Sequences will have their positional metadata concatenated using an outer join unless ``ignore_metadata`` is set to ``True``. See ``Sequence.concat(how='outer')`` for details. Examples -------- Create an MSA with positional metadata: >>> from skbio import DNA, TabularMSA >>> sequences = [DNA('ACG'), ... DNA('A-T')] >>> msa = TabularMSA(sequences, ... positional_metadata={'prob': [3, 1, 2]}) Iterate over positions: >>> for position in msa.iter_positions(): ... position ... print() Sequence ------------- Metadata: 'prob': 3 Stats: length: 2 ------------- 0 AA Sequence ------------- Metadata: 'prob': 1 Stats: length: 2 ------------- 0 C- Sequence ------------- Metadata: 'prob': 2 Stats: length: 2 ------------- 0 GT Note that MSA positional metadata is stored as ``metadata`` on each ``Sequence`` object. Iterate over positions in reverse order: >>> for position in msa.iter_positions(reverse=True): ... position ... print('') Sequence ------------- Metadata: 'prob': 2 Stats: length: 2 ------------- 0 GT Sequence ------------- Metadata: 'prob': 1 Stats: length: 2 ------------- 0 C- Sequence ------------- Metadata: 'prob': 3 Stats: length: 2 ------------- 0 AA """ indices = range(self.shape.position) if reverse: indices = reversed(indices) return ( self._get_position_(index, ignore_metadata=ignore_metadata) for index in indices ) def consensus(self): """Compute the majority consensus sequence for this MSA. The majority consensus sequence contains the most common character at each position in this MSA. Ties will be broken in an arbitrary manner. Returns ------- Sequence The majority consensus sequence for this MSA. The type of sequence returned will be the same as this MSA's ``dtype`` or ``Sequence`` if this MSA does not contain any sequences. The majority consensus sequence will have its positional metadata set to this MSA's positional metadata if present. Notes ----- The majority consensus sequence will use this MSA's default gap character (``dtype.default_gap_char``) to represent gap majority at a position, regardless of the gap characters present at that position. Different gap characters at a position are **not** treated as distinct characters. All gap characters at a position contribute to that position's gap consensus. Examples -------- >>> from skbio import DNA, TabularMSA >>> sequences = [DNA('AC---'), ... DNA('AT-C.'), ... DNA('TT-CG')] >>> msa = TabularMSA(sequences, ... positional_metadata={'prob': [2, 1, 2, 3, 5]}) >>> msa.consensus() DNA -------------------------- Positional metadata: 'prob': Stats: length: 5 has gaps: True has degenerates: False has definites: True GC-content: 33.33% -------------------------- 0 AT-C- Note that the last position in the MSA has more than one type of gap character. These are not treated as distinct characters; both types of gap characters contribute to the position's consensus. Also note that ``DNA.default_gap_char`` is used to represent gap majority at a position (``'-'``). """ dtype = self.dtype if dtype is None: dtype = Sequence positional_metadata = None if self.has_positional_metadata(): positional_metadata = self.positional_metadata consensus = [] for position in self.iter_positions(ignore_metadata=True): freqs = position.frequencies() gap_freq = 0 for gap_char in dtype.gap_chars: if gap_char in freqs: gap_freq += freqs.pop(gap_char) assert dtype.default_gap_char not in freqs freqs[dtype.default_gap_char] = gap_freq consensus.append(Counter(freqs).most_common(1)[0][0]) return dtype("".join(consensus), positional_metadata=positional_metadata) def _build_inverse_shannon_uncertainty_f(self, include_gaps): base = len(self.dtype.definite_chars) if include_gaps: # Increment the base by one to reflect the possible inclusion of # the default gap character. base += 1 def f(p): freqs = list(p.frequencies().values()) return 1.0 - scipy.stats.entropy(freqs, base=base) return f def conservation( self, metric="inverse_shannon_uncertainty", degenerate_mode="error", gap_mode="nan", ): """Apply metric to compute conservation for all alignment positions. Parameters ---------- metric : {'inverse_shannon_uncertainty'}, optional Metric that should be applied for computing conservation. Resulting values should be larger when a position is more conserved. degenerate_mode : {'nan', 'error'}, optional Mode for handling positions with degenerate characters. If ``"nan"``, positions with degenerate characters will be assigned a conservation score of ``np.nan``. If ``"error"``, an error will be raised if one or more degenerate characters are present. gap_mode : {'nan', 'ignore', 'error', 'include'}, optional Mode for handling positions with gap characters. If ``"nan"``, positions with gaps will be assigned a conservation score of ``np.nan``. If ``"ignore"``, positions with gaps will be filtered to remove gaps before ``metric`` is applied. If ``"error"``, an error will be raised if one or more gap characters are present. If ``"include"``, conservation will be computed on alignment positions with gaps included. In this case, it is up to the metric to ensure that gaps are handled as they should be or to raise an error if gaps are not supported by that metric. Returns ------- np.array of floats Values resulting from the application of ``metric`` to each position in the alignment. Raises ------ ValueError If an unknown ``metric``, ``degenerate_mode`` or ``gap_mode`` is provided. ValueError If any degenerate characters are present in the alignment when ``degenerate_mode`` is ``"error"``. ValueError If any gaps are present in the alignment when ``gap_mode`` is ``"error"``. Notes ----- Users should be careful interpreting results when ``gap_mode = "include"`` as the results may be misleading. For example, as pointed out in [1]_, a protein alignment position composed of 90% gaps and 10% tryptophans would score as more highly conserved than a position composed of alanine and glycine in equal frequencies with the ``"inverse_shannon_uncertainty"`` metric. ``gap_mode = "include"`` will result in all gap characters being recoded to ``TabularMSA.dtype.default_gap_char``. Because no conservation metrics that we are aware of consider different gap characters differently (e.g., none of the metrics described in [1]_), they are all treated the same within this method. The ``inverse_shannon_uncertainty`` metric is simply one minus Shannon's uncertainty metric. This method uses the inverse of Shannon's uncertainty so that larger values imply higher conservation. Shannon's uncertainty is also referred to as Shannon's entropy, but when making computations from symbols, as is done here, "uncertainty" is the preferred term ([2]_). References ---------- .. [1] Valdar WS. Scoring residue conservation. Proteins. (2002) .. [2] Schneider T. Pitfalls in information theory (website, ca. 2015). https://schneider.ncifcrf.gov/glossary.html#Shannon_entropy """ if gap_mode not in {"nan", "error", "include", "ignore"}: raise ValueError("Unknown gap_mode provided: %s" % gap_mode) if degenerate_mode not in {"nan", "error"}: raise ValueError("Unknown degenerate_mode provided: %s" % degenerate_mode) if metric not in {"inverse_shannon_uncertainty"}: raise ValueError("Unknown metric provided: %s" % metric) if self.shape[0] == 0: # handle empty alignment to avoid error on lookup of character sets return np.array([]) # Since the only currently allowed metric is # inverse_shannon_uncertainty, and we already know that a valid metric # was provided, we just define metric_f here. When additional metrics # are supported, this will be handled differently (e.g., via a lookup # or if/elif/else). metric_f = self._build_inverse_shannon_uncertainty_f(gap_mode == "include") result = [] for p in self.iter_positions(ignore_metadata=True): cons = None # cast p to self.dtype for access to gap/degenerate related # functionality pos_seq = self.dtype(p) # handle degenerate characters if present if pos_seq.has_degenerates(): if degenerate_mode == "nan": cons = np.nan else: # degenerate_mode == 'error' is the only choice left degenerate_chars = pos_seq[pos_seq.degenerates()] raise ValueError( "Conservation is undefined for positions " "with degenerate characters. The " "following degenerate characters were " "observed: %s." % degenerate_chars ) # handle gap characters if present if pos_seq.has_gaps(): if gap_mode == "nan": cons = np.nan elif gap_mode == "error": raise ValueError("Gap characters present in alignment.") elif gap_mode == "ignore": pos_seq = pos_seq.degap() else: # gap_mode == 'include' is the only choice left # Recode all gap characters with pos_seq.default_gap_char. pos_seq = pos_seq.replace(pos_seq.gaps(), pos_seq.default_gap_char) if cons is None: cons = metric_f(pos_seq) result.append(cons) return np.array(result) def gap_frequencies(self, axis="sequence", relative=False): """Compute frequency of gap characters across an axis. Parameters ---------- axis : {'sequence', 'position'}, optional Axis to compute gap character frequencies across. If 'sequence' or 0, frequencies are computed for each position in the MSA. If 'position' or 1, frequencies are computed for each sequence. relative : bool, optional If ``True``, return the relative frequency of gap characters instead of the count. Returns ------- 1D np.ndarray (int or float) Vector of gap character frequencies across the specified axis. Will have ``int`` dtype if ``relative=False`` and ``float`` dtype if ``relative=True``. Raises ------ ValueError If `axis` is invalid. Notes ----- If there are no positions in the MSA, ``axis='position'``, **and** ``relative=True``, the relative frequency of gap characters in each sequence will be ``np.nan``. Examples -------- Compute frequency of gap characters for each position in the MSA (i.e., *across* the sequence axis): >>> from skbio import DNA, TabularMSA >>> msa = TabularMSA([DNA('ACG'), ... DNA('A--'), ... DNA('AC.'), ... DNA('AG.')]) >>> msa.gap_frequencies() array([0, 1, 3]) Compute relative frequencies across the same axis: >>> msa.gap_frequencies(relative=True) array([ 0. , 0.25, 0.75]) Compute frequency of gap characters for each sequence (i.e., *across* the position axis): >>> msa.gap_frequencies(axis='position') array([0, 2, 1, 1]) """ if self._is_sequence_axis(axis): seq_iterator = self.iter_positions(ignore_metadata=True) length = self.shape.sequence else: seq_iterator = self length = self.shape.position gap_freqs = [] for seq in seq_iterator: # Not using Sequence.frequencies(relative=relative) because each # gap character's relative frequency is computed separately and # must be summed. This is less precise than summing the absolute # frequencies of gap characters and dividing by the length. Likely # not a big deal for typical gap characters ('-', '.') but can be # problematic as the number of gap characters grows (we aren't # guaranteed to always have two gap characters). See unit tests for # an example. freqs = seq.frequencies(chars=self.dtype.gap_chars) gap_freqs.append(sum(freqs.values())) gap_freqs = np.asarray(gap_freqs, dtype=float if relative else int) if relative: gap_freqs /= length return gap_freqs def reassign_index(self, mapping=None, minter=None): """Reassign index labels to sequences in this MSA. Parameters ---------- mapping : dict or callable, optional Dictionary or callable that maps existing labels to new labels. Any label without a mapping will remain the same. minter : callable or metadata key, optional If provided, defines an index label for each sequence. Can either be a callable accepting a single argument (each sequence) or a key into each sequence's ``metadata`` attribute. Raises ------ ValueError If `mapping` and `minter` are both provided. See Also -------- index Notes ----- If neither `mapping` nor `minter` are provided, index labels will be reset to the ``TabularMSA`` constructor's default. Examples -------- Create a ``TabularMSA`` object with default index labels: >>> from skbio import DNA, TabularMSA >>> seqs = [DNA('ACG', metadata={'id': 'a'}), ... DNA('AC-', metadata={'id': 'b'}), ... DNA('CCG', metadata={'id': 'c'})] >>> msa = TabularMSA(seqs) >>> msa.index RangeIndex(start=0, stop=3, step=1) Assign new index to the MSA using each sequence's ID as a label: >>> msa.reassign_index(minter='id') >>> msa.index # doctest: +ELLIPSIS Index(['a', 'b', 'c'], dtype='...') Assign default index: >>> msa.reassign_index() >>> msa.index RangeIndex(start=0, stop=3, step=1) Alternatively, a mapping of existing labels to new labels may be passed via `mapping`: >>> msa.reassign_index(mapping={0: 'seq1', 1: 'seq2'}) >>> msa.index # doctest: +ELLIPSIS Index(['seq1', 'seq2', 2], dtype='...') """ if mapping is not None and minter is not None: raise ValueError("Cannot use both `mapping` and `minter` at the same time.") if mapping is not None: if isinstance(mapping, dict): self.index = [ mapping[label] if label in mapping else label for label in self.index ] elif callable(mapping): self.index = [mapping(label) for label in self.index] else: raise TypeError( "`mapping` must be a dict or callable, not type %r" % type(mapping).__name__ ) elif minter is not None: self.index = [resolve_key(seq, minter) for seq in self._seqs] else: del self.index def append(self, sequence, minter=None, index=None, reset_index=False): """Append a sequence to the MSA without recomputing alignment. Parameters ---------- sequence : GrammaredSequence Sequence to be appended. Must match the dtype of the MSA and the number of positions in the MSA. minter : callable or metadata key, optional Used to create an index label for the sequence being appended. If callable, it generates a label directly. Otherwise it's treated as a key into the sequence metadata. Note that `minter` cannot be combined with `index` nor `reset_index`. index : object, optional Index label to use for the appended sequence. Note that `index` cannot be combined with `minter` nor `reset_index`. reset_index : bool, optional If ``True``, this MSA's index is reset to the ``TabularMSA`` constructor's default after appending. Note that `reset_index` cannot be combined with `minter` nor `index`. Raises ------ ValueError If exactly one choice of `minter`, `index`, or `reset_index` is not provided. TypeError If the sequence object isn't a ``GrammaredSequence``. TypeError If the type of the sequence does not match the dtype of the MSA. ValueError If the length of the sequence does not match the number of positions in the MSA. See Also -------- extend reassign_index Notes ----- The MSA is not automatically re-aligned when a sequence is appended. Therefore, this operation is not necessarily meaningful on its own. Examples -------- Create an MSA with a single sequence labeled ``'seq1'``: >>> from skbio import DNA, TabularMSA >>> msa = TabularMSA([DNA('ACGT')], index=['seq1']) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 1 position count: 4 --------------------- ACGT >>> msa.index # doctest: +ELLIPSIS Index(['seq1'], dtype='...') Append a new sequence to the MSA, providing its index label via `index`: >>> msa.append(DNA('AG-T'), index='seq2') >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 4 --------------------- ACGT AG-T >>> msa.index # doctest: +ELLIPSIS Index(['seq1', 'seq2'], dtype='...') Append another sequence, this time resetting the MSA's index labels to the default with `reset_index`. Note that since the MSA's index is reset, we do not need to provide an index label for the new sequence via `index` or `minter`: >>> msa.append(DNA('ACGA'), reset_index=True) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 3 position count: 4 --------------------- ACGT AG-T ACGA >>> msa.index RangeIndex(start=0, stop=3, step=1) """ if index is not None: index = [index] self.extend([sequence], minter=minter, index=index, reset_index=reset_index) def extend(self, sequences, minter=None, index=None, reset_index=False): """Extend this MSA with sequences without recomputing alignment. Parameters ---------- sequences : iterable of GrammaredSequence Sequences to be appended. Must match the dtype of the MSA and the number of positions in the MSA. minter : callable or metadata key, optional Used to create index labels for the sequences being appended. If callable, it generates a label directly. Otherwise it's treated as a key into the sequence metadata. Note that `minter` cannot be combined with `index` nor `reset_index`. index : pd.Index consumable, optional Index labels to use for the appended sequences. Must be the same length as `sequences`. Must be able to be passed directly to ``pd.Index`` constructor. Note that `index` cannot be combined with `minter` nor `reset_index`. reset_index : bool, optional If ``True``, this MSA's index is reset to the ``TabularMSA`` constructor's default after extending. Note that `reset_index` cannot be combined with `minter` nor `index`. Raises ------ ValueError If exactly one choice of `minter`, `index`, or `reset_index` is not provided. ValueError If `index` is not the same length as `sequences`. TypeError If `sequences` contains an object that isn't a ``GrammaredSequence``. TypeError If `sequences` contains a type that does not match the dtype of the MSA. ValueError If the length of a sequence does not match the number of positions in the MSA. See Also -------- append reassign_index Notes ----- The MSA is not automatically re-aligned when appending sequences. Therefore, this operation is not necessarily meaningful on its own. Examples -------- Create an MSA with a single sequence labeled ``'seq1'``: >>> from skbio import DNA, TabularMSA >>> msa = TabularMSA([DNA('ACGT')], index=['seq1']) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 1 position count: 4 --------------------- ACGT >>> msa.index # doctest: +ELLIPSIS Index(['seq1'], dtype='...') Extend the MSA with sequences, providing their index labels via `index`: >>> msa.extend([DNA('AG-T'), DNA('-G-T')], index=['seq2', 'seq3']) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 3 position count: 4 --------------------- ACGT AG-T -G-T >>> msa.index # doctest: +ELLIPSIS Index(['seq1', 'seq2', 'seq3'], dtype='...') Extend with more sequences, this time resetting the MSA's index labels to the default with `reset_index`. Note that since the MSA's index is reset, we do not need to provide index labels for the new sequences via `index` or `minter`: >>> msa.extend([DNA('ACGA'), DNA('AC-T'), DNA('----')], ... reset_index=True) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 6 position count: 4 --------------------- ACGT AG-T ... AC-T ---- >>> msa.index RangeIndex(start=0, stop=6, step=1) """ if sum([minter is not None, index is not None, bool(reset_index)]) != 1: raise ValueError( "Must provide exactly one of the following parameters: " "`minter`, `index`, `reset_index`" ) # Verify `sequences` first because `minter` could interact with each # sequence's `metadata`. sequences = list(sequences) self._assert_valid_sequences(sequences) if minter is not None: # Convert to Index to identify tuples as a MultiIndex instead of an # index of tuples. index = pd.Index([resolve_key(seq, minter) for seq in sequences]) elif index is not None: # Convert to Index to identify tuples as a MultiIndex instead of an # index of tuples. if not isinstance(index, pd.Index): index = pd.Index(index) # pandas doesn't give a user-friendly error message if we pass # through. if len(sequences) != len(index): raise ValueError( "Number of sequences (%d) must match index length (%d)" % (len(sequences), len(index)) ) else: # Case for `reset_index=True`. We could simply set `index=None` # since it will be reset after appending below, but we can avoid a # memory spike if Series.append creates a new RangeIndex from # adjacent RangeIndexes in the future (pandas 0.18.0 creates an # Int64Index). index = pd.RangeIndex( start=len(self), stop=len(self) + len(sequences), step=1 ) if len(self): self._seqs = pd.concat( [self._seqs, pd.Series(sequences, index=index, dtype=object)] ) else: # Not using Series.append to avoid turning a RangeIndex supplied # via `index` parameter into an Int64Index (this happens in pandas # 0.18.0). self._seqs = pd.Series(sequences, index=index, dtype=object) # When extending a TabularMSA without sequences, the number of # positions in the TabularMSA may change from zero to non-zero. If # this happens, the TabularMSA's positional_metadata must be reset # to its default "empty" representation for the new number of # positions, otherwise the number of positions in the TabularMSA # and positional_metadata will differ. # # TODO: change for #1198 if self.shape.position > 0: del self.positional_metadata if reset_index: self.reassign_index() def _assert_valid_sequences(self, sequences): if not sequences: return if len(self): expected_dtype = self.dtype expected_length = self.shape.position else: sequence = sequences[0] expected_dtype = type(sequence) if not issubclass(expected_dtype, GrammaredSequence): raise TypeError( "Each sequence must be of type %r, not type %r" % (GrammaredSequence.__name__, expected_dtype.__name__) ) expected_length = len(sequence) for sequence in sequences: dtype = type(sequence) if dtype is not expected_dtype: raise TypeError( "Sequences in MSA must have matching type. Type %r does " "not match type %r" % (dtype.__name__, expected_dtype.__name__) ) length = len(sequence) if length != expected_length: raise ValueError( "Each sequence's length must match the number of " "positions in the MSA: %d != %d" % (length, expected_length) ) def join(self, other, how="strict"): """Join this MSA with another by sequence (horizontally). Sequences will be joined by index labels. MSA ``positional_metadata`` will be joined by columns. Use `how` to control join behavior. Alignment is **not** recomputed during join operation (see *Notes* section for details). Parameters ---------- other : TabularMSA MSA to join with. Must have same ``dtype`` as this MSA. how : {'strict', 'inner', 'outer', 'left', 'right'}, optional How to join the sequences and MSA `positional_metadata`: * ``'strict'``: MSA indexes and `positional_metadata` columns must match * ``'inner'``: an inner-join of the MSA indexes and ``positional_metadata`` columns (only the shared set of index labels and columns are used) * ``'outer'``: an outer-join of the MSA indexes and ``positional_metadata`` columns (all index labels and columns are used). Unshared sequences will be padded with the MSA's default gap character (``TabularMSA.dtype.default_gap_char``). Unshared columns will be padded with NaN. * ``'left'``: a left-outer-join of the MSA indexes and ``positional_metadata`` columns (this MSA's index labels and columns are used). Padding of unshared data is handled the same as ``'outer'``. * ``'right'``: a right-outer-join of the MSA indexes and ``positional_metadata`` columns (`other` index labels and columns are used). Padding of unshared data is handled the same as ``'outer'``. Returns ------- TabularMSA Joined MSA. There is no guaranteed ordering to its index (call ``sort`` to define one). Raises ------ ValueError If `how` is invalid. ValueError If either the index of this MSA or the index of `other` contains duplicates. ValueError If ``how='strict'`` and this MSA's index doesn't match with `other`. ValueError If ``how='strict'`` and this MSA's ``positional_metadata`` columns don't match with `other`. TypeError If `other` is not a subclass of ``TabularMSA``. TypeError If the ``dtype`` of `other` does not match this MSA's ``dtype``. See Also -------- extend sort skbio.sequence.Sequence.concat Notes ----- The join operation does not automatically perform re-alignment; sequences are simply joined together. Therefore, this operation is not necessarily meaningful on its own. The index labels of this MSA must be unique. Likewise, the index labels of `other` must be unique. The MSA-wide and per-sequence metadata (``TabularMSA.metadata`` and ``Sequence.metadata``) are not retained on the joined ``TabularMSA``. The positional metadata of the sequences will be outer-joined, regardless of `how` (using ``Sequence.concat(how='outer')``). If the join operation results in a ``TabularMSA`` without any sequences, the MSA's ``positional_metadata`` will not be set. Examples -------- .. note:: The following examples call `.sort()` on the joined MSA because there isn't a guaranteed ordering to the index. The joined MSA is sorted in these examples to make the output reproducible. When using this method with your own data, sorting the joined MSA is not necessary. Join MSAs by sequence: >>> from skbio import DNA, TabularMSA >>> msa1 = TabularMSA([DNA('AC'), ... DNA('A-')]) >>> msa2 = TabularMSA([DNA('G-T'), ... DNA('T--')]) >>> joined = msa1.join(msa2) >>> joined.sort() # unnecessary in practice, see note above >>> joined TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 5 --------------------- ACG-T A-T-- Sequences are joined based on MSA index labels: >>> msa1 = TabularMSA([DNA('AC'), ... DNA('A-')], index=['a', 'b']) >>> msa2 = TabularMSA([DNA('G-T'), ... DNA('T--')], index=['b', 'a']) >>> joined = msa1.join(msa2) >>> joined.sort() # unnecessary in practice, see note above >>> joined TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 5 --------------------- ACT-- A-G-T >>> joined.index # doctest: +ELLIPSIS Index(['a', 'b'], dtype='...') By default both MSA indexes must match. Use ``how`` to specify an inner join: >>> msa1 = TabularMSA([DNA('AC'), ... DNA('A-'), ... DNA('-C')], index=['a', 'b', 'c'], ... positional_metadata={'col1': [42, 43], ... 'col2': [1, 2]}) >>> msa2 = TabularMSA([DNA('G-T'), ... DNA('T--'), ... DNA('ACG')], index=['b', 'a', 'z'], ... positional_metadata={'col2': [3, 4, 5], ... 'col3': ['f', 'o', 'o']}) >>> joined = msa1.join(msa2, how='inner') >>> joined.sort() # unnecessary in practice, see note above >>> joined TabularMSA[DNA] -------------------------- Positional metadata: 'col2': Stats: sequence count: 2 position count: 5 -------------------------- ACT-- A-G-T >>> joined.index # doctest: +ELLIPSIS Index(['a', 'b'], dtype='...') >>> joined.positional_metadata col2 0 1 1 2 2 3 3 4 4 5 When performing an outer join (``'outer'``, ``'left'``, or ``'right'``), unshared sequences are padded with gaps and unshared ``positional_metadata`` columns are padded with NaN: >>> joined = msa1.join(msa2, how='outer') >>> joined.sort() # unnecessary in practice, see note above >>> joined # doctest: +ELLIPSIS TabularMSA[DNA] ---------------------------- Positional metadata: 'col1': 'col2': 'col3': Stats: sequence count: 4 position count: 5 ---------------------------- ACT-- A-G-T -C--- --ACG >>> joined.index # doctest: +ELLIPSIS Index(['a', 'b', 'c', 'z'], dtype='...') >>> joined.positional_metadata col1 col2 col3 0 42.0 1 NaN 1 43.0 2 NaN 2 NaN 3 f 3 NaN 4 o 4 NaN 5 o """ if how not in {"strict", "inner", "outer", "left", "right"}: raise ValueError( "`how` must be 'strict', 'inner', 'outer', 'left', or 'right'." ) self._assert_joinable(other) join_index, concat_kwargs = self._get_join_index(other, how) joined_seqs = [] for label in join_index: left_seq = self._get_sequence_for_join(label) right_seq = other._get_sequence_for_join(label) joined_seqs.append(self.dtype.concat([left_seq, right_seq], how="outer")) # TODO: update when #1198 is implemented. joined_positional_metadata = None if joined_seqs: if how == "left": joined_positional_metadata = pd.concat( [ self.positional_metadata, other.positional_metadata.reindex( columns=self.positional_metadata.columns ), ], ignore_index=True, sort=True, ) # Because left join, attempt to preserve dtypes of left MSA self._preserve_dtypes( joined_positional_metadata, self.positional_metadata ) elif how == "right": joined_positional_metadata = pd.concat( [ self.positional_metadata.reindex( columns=other.positional_metadata.columns ), other.positional_metadata, ], ignore_index=True, sort=True, ) # Because right join, attempt to preserve dtypes of right MSA self._preserve_dtypes( joined_positional_metadata, other.positional_metadata ) else: joined_positional_metadata = pd.concat( [self.positional_metadata, other.positional_metadata], ignore_index=True, sort=True, **concat_kwargs, ) # This handles strict, inner, and outer joins. If the columns are the # same then either one is sufficient. If it's an outer join then each # column will attempt to preserve its dtype from its original MSA. self._preserve_dtypes( joined_positional_metadata, self.positional_metadata ) self._preserve_dtypes( joined_positional_metadata, other.positional_metadata ) if not self.has_positional_metadata(): del self.positional_metadata if not other.has_positional_metadata(): del other.positional_metadata joined = self.__class__( joined_seqs, index=join_index, positional_metadata=joined_positional_metadata, ) if not joined.has_positional_metadata(): del joined.positional_metadata return joined def _preserve_dtypes(self, joined_pm, reference_pm): """Coerce positional_metadata column dtypes to match a reference DataFrame.""" for col in reference_pm.columns: if col in joined_pm.columns: try: joined_pm[col] = joined_pm[col].astype(reference_pm[col].dtype) except (ValueError, TypeError): pass def _assert_joinable(self, other): if not isinstance(other, TabularMSA): raise TypeError( "`other` must be a `TabularMSA` object, not type %r" % type(other).__name__ ) if self.dtype is not other.dtype: raise TypeError( "`other` dtype %r does not match this MSA's dtype %r" % ( other.dtype if other.dtype is None else other.dtype.__name__, self.dtype if self.dtype is None else self.dtype.__name__, ) ) if not self.index.is_unique: raise ValueError("This MSA's index labels must be unique.") if not other.index.is_unique: raise ValueError("`other`'s index labels must be unique.") def _get_join_index(self, other, how): if how == "strict": diff = self.index.symmetric_difference(other.index) if len(diff) > 0: raise ValueError("Index labels must all match with `how='strict'`") diff = self.positional_metadata.columns.symmetric_difference( other.positional_metadata.columns ) if not self.has_positional_metadata(): del self.positional_metadata if not other.has_positional_metadata(): del other.positional_metadata if len(diff) > 0: raise ValueError( "Positional metadata columns must all match with `how='strict'`" ) join_index = self.index concat_kwargs = {"join": "inner"} elif how == "inner": join_index = self.index.intersection(other.index) concat_kwargs = {"join": "inner"} elif how == "outer": join_index = self.index.union(other.index) concat_kwargs = {"join": "outer"} elif how == "left": join_index = self.index concat_kwargs = {"join_axes": [self.positional_metadata.columns]} else: # how='right' join_index = other.index concat_kwargs = {"join_axes": [other.positional_metadata.columns]} return join_index, concat_kwargs def _get_sequence_for_join(self, label): if label in self.index: return self.loc[label] else: return self.dtype(self.dtype.default_gap_char * self.shape.position) def sort(self, level=None, ascending=True): """Sort sequences by index label in-place. Parameters ---------- level : int or object, optional Index level to sort on when index is a ``pd.MultiIndex``. Does nothing otherwise. ascending: bool, optional If ``False``, sort in descending (i.e., reverse) order. See Also -------- index reassign_index pandas.Series.sort_index Notes ----- This is a passthrough to ``pd.Series.sort_index`` internally. Examples -------- Create a ``TabularMSA`` object with sequence identifiers as index labels: >>> from skbio import DNA, TabularMSA >>> seqs = [DNA('ACG', metadata={'id': 'c'}), ... DNA('AC-', metadata={'id': 'b'}), ... DNA('AC-', metadata={'id': 'a'})] >>> msa = TabularMSA(seqs, minter='id') >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 3 position count: 3 --------------------- ACG AC- AC- >>> msa.index # doctest: +ELLIPSIS Index(['c', 'b', 'a'], dtype='...') Sort the sequences in alphabetical order by index label: >>> msa.sort() >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 3 position count: 3 --------------------- AC- AC- ACG >>> msa.index # # doctest: +ELLIPSIS Index(['a', 'b', 'c'], dtype='...') Note that since the sort is in-place, the ``TabularMSA`` object is modified (a new object is *not* returned). """ self._seqs.sort_index(ascending=ascending, level=level, inplace=True) self.positional_metadata.sort_index(axis=1, inplace=True) def to_dict(self): """Create a ``dict`` from this ``TabularMSA``. Returns ------- dict Dictionary constructed from the index labels and sequences in this ``TabularMSA``. Raises ------ ValueError If index labels are not unique. See Also -------- from_dict index reassign_index Examples -------- >>> from skbio import DNA, TabularMSA >>> seqs = [DNA('ACGT'), DNA('A--T')] >>> msa = TabularMSA(seqs, index=['a', 'b']) >>> dictionary = msa.to_dict() >>> dictionary == {'a': DNA('ACGT'), 'b': DNA('A--T')} True """ if self.index.is_unique: return self._seqs.to_dict() else: raise ValueError("Cannot convert to dict. Index labels are not unique.") def _is_sequence_axis(self, axis): if axis == "sequence" or axis == 0: return True elif axis == "position" or axis == 1: return False else: raise ValueError( "`axis` must be 'sequence' (0) or 'position' (1), not %r" % axis ) @overrides(PositionalMetadataMixin) def _positional_metadata_axis_len_(self): return self.shape.position @classonlymethod def from_path_seqs(cls, path, seqs) -> Self: """Create a tabular MSA from an alignment path and the original sequences. Parameters ---------- path : AlignPath Alignment path. seqs : iterable of GrammaredSequence Original sequences. Returns ------- TabularMSA The created tabular MSA object. See Also -------- skbio.alignment.AlignPath.from_tabular Examples -------- >>> from skbio import DNA, TabularMSA >>> from skbio.alignment import AlignPath >>> seqs = [ ... DNA('CGTCGTGC'), ... DNA('CAGTC'), ... DNA('CGTCGTT'), ... ] >>> path = AlignPath( ... lengths=[2, 2, 2, 1, 1], ... states=[0, 2, 0, 6, 0], ... starts=[0, 0, 0], ... ) >>> msa = TabularMSA.from_path_seqs(path, seqs) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 3 position count: 8 --------------------- CGTCGTGC CA--GT-C CGTCGT-T """ # TODO: add `minter` and `index` support if not all(isinstance(x, GrammaredSequence) for x in seqs): raise ValueError("`seqs` must be of skbio.Sequence type.") if len(seqs) != path._shape[0]: raise ValueError("Sequence counts in `path` and `seqs` do not match.") seqtype = seqs[0].__class__ gap_code = ord(seqtype.default_gap_char) byte_lst = [x._bytes for x in seqs] byte_arr = path._to_matrices(byte_lst, gap_code)[0] return cls([seqtype(x) for x in byte_arr]) scikit-bio-scikit-bio-a3beaa6/skbio/alignment/_utils.py000066400000000000000000000372121520735541300233160ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from collections.abc import Iterable from typing import TypeAlias import numpy as np from numpy.typing import NDArray from skbio.alignment import TabularMSA, AlignPath from skbio.sequence import Sequence, GrammaredSequence, SubstitutionMatrix from skbio.sequence._alphabet import ( _encode_alphabet, _alphabet_to_hashes, _indices_in_observed, ) # This could be exposed as a public API. SequenceLike: TypeAlias = ( Sequence | str | bytes | Iterable[str | bytes | int | float | bool] | NDArray ) # This could be exposed as a public API. AlignmentLike: TypeAlias = ( TabularMSA | Iterable[SequenceLike] | tuple[AlignPath, Iterable[SequenceLike]] ) # cached identity matrices for alignment with match/mismatch scores _idmats: dict[str | type, NDArray] = {} # indices of cached identity matrices _ididxs: dict[type, NDArray] = {} def encode_sequences( seqs: Iterable[SequenceLike], sub_score: tuple[float, float] | SubstitutionMatrix | str, aligned: bool = False, dtype: type = np.float32, gap_chars: str = "-", not_empty: bool = True, ) -> tuple[list[NDArray], NDArray, NDArray]: """Encode sequences for alignment operations. This function transforms sequences into indices in a substitution matrix to facilitate subsequent alignment operations. Parameters ---------- seqs : iterable of Sequence, str, or sequence of scalar Input sequences. sub_score : tuple of (float, float), SubstitutionMatrix, or str Substitution scoring method. Can be two numbers (match, mismatch), a substitution matrix, or its name. aligned : bool, optional Whether sequences are aligned. If True, sequences will be checked for equal length and gaps will be encoded into a Boolean mask. dtype : type, optional Default floating-point data type (np.float32 or np.float64) to use if it cannot be automatically inferred. gap_chars : str, optional Characters that should be treated as gaps in aligned sequences. Default is "-". not_empty : bool, optional If True (default), each sequence must not be empty. Returns ------- seqs : list of ndarray of intp Indices of sequence characters in the substitution matrix. submat : ndarray of float of shape (n_alphabet, n_alphabet) Substitution matrix. gaps : ndarray of bool of shape (n_sequences, n_positions), optional Boolean mask of gap positions. Raises ------ TypeError If sequences are of heterogeneous types. ValueError If there is no sequence. ValueError If any sequence has a length of zero. See Also -------- encode_alignment Notes ----- This function is currently private but it could be exposed as a public API. """ # Determine type of sequences. They can be skbio sequences (grammared or not), # raw strings or any iterables of scalars. Heterogeneous sequences are not allowed. seqtype = _check_seqtype(seqs) if issubclass(seqtype, GrammaredSequence): is_sequence = has_grammar = True else: has_grammar = False is_sequence = issubclass(seqtype, Sequence) # Determine substitution scoring method. It can be a specified substitution matrix # or match & mismatch scores. For the later scenario, an identity matrix will be # later constructed or retrieved from the cache. if isinstance(sub_score, str): submat = SubstitutionMatrix.by_name(sub_score) is_submat = True elif isinstance(sub_score, SubstitutionMatrix): submat = sub_score is_submat = True else: is_submat = False match, mismatch = sub_score match, mismatch = dtype(match), dtype(mismatch) # Determine whether sequences should be encoded as ASCII codes, which skbio has # optimizations for. # This requires that 1) sequences are ASCII, and 2) substitution matrix (if # provided) supports ASCII. # If yes, convert sequences into ASCII codes. Otherwise, keep sequences as strings # or whatever iterables in the original form. if not is_submat or submat.is_ascii: if is_sequence: is_ascii = True seqs = [x._bytes for x in seqs] else: try: seqs = [_encode_alphabet(x) for x in seqs] except (TypeError, ValueError, UnicodeEncodeError): if is_submat: raise ValueError( "Substitution matrix has an ASCII alphabet, but sequences " "cannot be fully encoded into ASCII codes." ) is_ascii = False else: is_ascii = True else: is_ascii = False if is_sequence: seqs = [str(x) for x in seqs] # Identify gaps in aligned sequences. The output is a 2D Boolean mask representing # gap positions (0: character, 1: gap). This process also validates that all # sequences in the alignment are of equal length. gaps = None if aligned: if is_ascii: if has_grammar: gap_codes = seqtype._gap_codes else: gap_codes = [ord(x) for x in gap_chars] else: if has_grammar: gap_codes = list(seqtype.gap_chars) else: gap_codes = list(gap_chars) gaps = _mask_gaps(seqs, gap_codes) # Index sequences according to a given substitution matrix. if is_submat: # Determine wildcard if available. wild = None if has_grammar: wild = getattr(seqtype, "wildcard_char", None) if is_ascii and wild is not None: wild = ord(wild) if is_ascii: seqs = _map_chars_ascii(seqs, submat._char_hash, wild=wild) else: seqs = _map_chars(seqs, submat._char_map, wild=wild) # Validate that all non-gap positions have valid indices. _check_indices(seqs, gaps) submat = submat._data # Construct a substitution matrix based on match/mismatch scores, or retrieve one # from cache. else: if is_ascii: key = seqtype if has_grammar else "ascii" else: seqs, uniq = _indices_in_observed(seqs) key = uniq.size seqs, submat = prep_identity_matrix(seqs, key, match, mismatch) if not_empty: for i, seq in enumerate(seqs): if seq.size == 0: raise ValueError(f"Sequence {i + 1} has a length of zero.") return seqs, submat, gaps def encode_alignment( aln: AlignmentLike, sub_score: tuple[float, float] | SubstitutionMatrix | str, gap_chars: str = "-", ) -> tuple[NDArray, NDArray, NDArray, NDArray]: """Encode sequences for alignment operations. This function transforms an alignment into a 2D array of indices in a substitution matrix, and run-length encoded gaps, which will facilitate subsequent alignment operations. Parameters ---------- aln : TabularMSA, iterable, or (AlignPath, iterable) Input alignment. sub_score : tuple of (float, float), SubstitutionMatrix, or str Substitution scoring method. Can be two numbers (match, mismatch), a substitution matrix, or its name. gap_chars : str, optional Characters that should be treated as gaps in aligned sequences. Returns ------- seqs : ndarray of intp Indices of sequence characters in the substitution matrix. submat : ndarray of float of shape (n_alphabet, n_alphabet) Substitution matrix. bits : ndarray of bool of shape (n_sequences, n_segments) Gap status of segments in the alignment path. lens : ndarray of int of shape (n_segments,) Lengths of segments in the alignment path. Raises ------ TypeError If sequences are of heterogeneous types. ValueError If the alignment has no sequence. ValueError If the alignment has no column (position). See Also -------- encode_sequences Notes ----- This function is currently private but it could be exposed as a public API. """ # There are two scenarios: is_path = False if isinstance(aln, (list, tuple)) and len(aln) == 2: path, seqs = aln if isinstance(path, AlignPath) and isinstance(seqs, Iterable): is_path = True # 1. Input is an alignment path and original (unaligned) sequences. if is_path: seqs, submat, _ = encode_sequences( seqs, sub_score, aligned=False, gap_chars=gap_chars ) seqs, _, bits, lens = path._to_matrices(seqs) # 2. Input is aligned sequences (with gaps inside them). else: seqs, submat, gaps = encode_sequences( aln, sub_score, aligned=True, gap_chars=gap_chars, not_empty=False ) seqs = np.vstack(seqs) if seqs.shape[1] == 0: raise ValueError("The alignment has a length of zero.") bits, lens = _get_align_path(gaps) return seqs, submat, bits, lens def prep_gapcost(gap_cost, dtype=np.float32): """Prepare gap penalty method for alignment. Parameters ---------- gap_cost : float or tuple of (float, float), optional Penalty of a gap. May be one (linear) or two numbers (affine). See :func:`align_score` for instructions and rationales. Default is -2. dtype : type, optional Floating-point data type (np.float32 or np.float64) to use. Returns ------- float Gap opening penalty. float Gap extension penalty. Notes ----- Gap penalties are usually positive, representing subtractions from the alignment score. Although scikit-bio does not prohibit negative gap penalties, it should be noted that negative penalties (positive scores) might lead to all-gap alignments, especially when gaps are scored higher than substitutions. """ if np.isscalar(gap_cost): gap_open, gap_extend = 0, gap_cost else: gap_open, gap_extend = gap_cost return dtype(gap_open), dtype(gap_extend) def prep_identity_matrix(seqs, key, match, mismatch): """Prepare an identity matrix based on match/mismatch scores. Parameters ---------- seqs : list of ndarray of uint8 or int Encoded sequences. key: type, int, or "ascii" Sequence type | alphabet is ASCII | alphabet size match : float Match score. mismatch : float Mismatch score. Returns ------- list of ndarray of intp Indices of sequence characters in the substitution matrix. ndarray of float of shape (n_alphabet, n_alphabet) Substitution matrix. Notes ----- An identity matrix is created on the first use and saved in the cache for reuse. There are three scenarios: 1. Each GrammaredSequence type (such as DNA and Protein) will have its own identity matrix that covers its specific alphabet. 2. For non-grammared Sequence, string and other types that can be ASCII-encoded, a single identity matrix with all 128 ASCII codes will be created and cached. 3. For other types, an identity matrix will be created each time and not cached. It will cover all unique elements in the sequences. """ # create a temporary matrix of arbitrary size if isinstance(key, int): submat = np.full((key, key), mismatch) np.fill_diagonal(submat, match) # check existing matrix in cache and update it if needed elif key in _idmats: submat = _idmats[key] if submat[0, 1] != mismatch: submat[:] = mismatch if submat[0, 0] != match: np.fill_diagonal(submat, match) if key == "ascii": # cast ASCII codes (uint8) into indices (intp) seqs = [x.astype(np.intp) for x in seqs] else: # translate ASCII codes to indices in matrix idx = _ididxs[key] seqs = [idx[x] for x in seqs] # create a new matrix and save it to cache else: if key == "ascii": # TODO: This can be further optimized in `SubstitutionMatrix`. alphabet = [chr(i) for i in range(128)] seqs = [x.astype(np.intp) for x in seqs] else: alphabet = sorted(key.alphabet) # create index and translate idx = _ididxs[key] = _alphabet_to_hashes(alphabet) seqs = [idx[x] for x in seqs] n = len(alphabet) submat = np.full((n, n), mismatch) np.fill_diagonal(submat, match) _idmats[key] = submat return seqs, submat def _check_seqtype(seqs: Iterable[SequenceLike]) -> type[SequenceLike]: """Check if sequences are homogeneous, and return the common type.""" if isinstance(seqs, TabularMSA): dtype = seqs.dtype if seqs.shape[0] == 0: raise ValueError("No sequence is provided.") return dtype try: dtype = type(seqs[0]) except IndexError: raise ValueError("No sequence is provided.") for seq in seqs[1:]: if type(seq) is not dtype: raise TypeError("Sequences are of different types.") return dtype def _mask_gaps(seqs, gap_codes): """Mask gap positions in aligned sequences.""" if isinstance(seqs[0], str): gaps = [np.isin(list(x), gap_codes) for x in seqs] else: gaps = [np.isin(x, gap_codes) for x in seqs] try: return np.vstack(gaps) except ValueError: raise ValueError("Sequence lengths do not match.") def _map_chars_ascii(seqs, mapping, wild=None): """Map characters in sequences to indices. `mapping` is an array of ASCII codes (n=128). This function can be considered as a refined and batched version of `skbio.sequence._alphabet._indices_in_alphabet_ascii`. """ seqs = [mapping[x] for x in seqs] if wild is not None and (wild := mapping[wild]) != -1: for seq in seqs: seq[seq == -1] = wild return seqs def _map_chars(seqs, mapping, wild=None): """Map characters in sequences to indices. `mapping` is a dictionary of original characters. This function can be considered as a refined and batched version of `skbio.sequence._alphabet._indices_in_alphabet`. """ wild = -1 if wild is None else mapping.get(wild, -1) return [np.array([mapping.get(x, wild) for x in y], dtype=np.intp) for y in seqs] def _check_indices(seqs, gaps=None): """Validate that all non-gap positions have valid indices. `gaps` is a 2D Boolean mask whereas `seqs` are a list of equal-size arrays (they will be vstack'ed later). """ msg = "Sequence {} contain character(s) absent from the substitution matrix." if gaps is None: for i, seq in enumerate(seqs): if (seq == -1).any(): raise ValueError(msg.format(i + 1)) else: for i, (seq, gap) in enumerate(zip(seqs, gaps)): if (seq[~gap] == -1).any(): raise ValueError(msg.format(i + 1)) def _get_align_path(bits): """Calculate the path of an alignment. This function is similar to `AlignPath.from_tabular`, except that bits don't need to be packed into uint8's. """ idx = np.append(0, np.where((bits[:, :-1] != bits[:, 1:]).any(axis=0))[0] + 1) lens = np.append(idx[1:] - idx[:-1], bits.shape[1] - idx[-1]) bits = bits[:, idx] return bits, lens scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/000077500000000000000000000000001520735541300226025ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/__init__.py000066400000000000000000000005411520735541300247130ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/data/000077500000000000000000000000001520735541300235135ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/data/16s.frn000066400000000000000000000061541520735541300246410ustar00rootroot00000000000000>NR_024570.1 Escherichia coli strain U 5/41 16S ribosomal RNA, partial sequence AGTTTGATCATGGCTCAGATTGAACGCTGGCGGCAGGCCTAACACATGCAAGTCGAACGGTAACAGGAAG CAGCTTGCTGCTTTGCTGACGAGTGGCGGACGGGTGAGTAATGTCTGGGAAACTGCCTGATGGAGGGGGA TAACTACTGGAAACGGTAGCTAATACCGCATAACGTCGCAAGCACAAAGAGGGGGACCTTAGGGCCTCTT GCCATCGGATGTGCCCAGATGGGATTAGCTAGTAGGTGGGGTAACGGCTCACCTAGGCGACGATCCCTAG CTGGTCTGAGAGGATGACCAGCAACACTGGAACTGAGACACGGTCCAGACTCCTACGGGAGGCAGCAGTG GGGAATATTGCACAATGGGCGCAAGCCTGATGCAGCCATGCNGCGTGTATGAAGAAGGCCTTCGGGTTGT AAAGTACTTTCAGCGGGGAGGAAGGGAGTAAAGTTAATACCTTTGCTCATTGACGTTACCCGCAGAAGAA GCACCGGCTAACTCCGTGCCAGCAGCCGCGGTAATACGGAGGGTGCAAGCGTTAATCGGAATTACTGGGC GTAAAGCGCACGCAGGCGGTTTGTTAAGTCAGATGTGAAATCCCCGGGCTCAACCTGGGAACTGCATCTG ATACTGGCAAGCTTGAGTCTCGTAGAGGGGGGTAGAATTCCAGGTGTAGCGGTGAAATGCGTAGAGATCT GGAGGAATACCGGTGGCGAAGGCGGCCCCCTGGACGAAGACTGACGCTCAGGTGCGAAAGCGTGGGGAGC AAACAGGATTAGATACCCTGGTAGTCCACGCCGTAAACGATGTCGACTTGGAGGTTGTGCCCTTGAGGCG TGGCTTCCGGANNTAACGCGTTAAGTCGACCGCCTGGGGAGTACGGCCGCAAGGTTAAAACTCAAATGAA TTGACGGGGGCCGCACAAGCGGTGGAGCATGTGGTTTAATTCGATGCAACGCGAAGAACCTTACCTGGTC TTGACATCCACGGAAGTTTTCAGAGATGAGAATGTGCCTTCGGGAACCGTGAGACAGGTGCTGCATGGCT GTCGTCAGCTCGTGTTGTGAAATGTTGGGTTAAGTCCCGCAACGAGCGCAACCCTTATCCTTTGTTGCCA GCGGTCCGGCCGGGAACTCAAAGGAGACTGCCAGTGATAAACTGGAGGAAGGTGGGGATGACGTCAAGTC ATCATGGCCCTTACGACCAGGGCTACACACGTGCTACAATGGCGCATACAAAGAGAAGCGACCTCGCGAG AGCAAGCGGACCTCATAAAGTGCGTCGTAGTCCGGATTGGAGTCTGCAACTCGACTCCATGAAGTCGGAA TCGCTAGTAATCGTGGATCAGAATGCCACGGTGAATACGTTCCCGGGCCTTGTACACACCGCCCGTCACA CCATGGGAGTGGGTTGCAAAAGAAGTAGGTAGCTTAACTTCGGGAGGGCG >NR_028665.1 Streptococcus pneumoniae strain ATCC 33400 16S ribosomal RNA, partial sequence ATTTGATCCTGGCTCAGGACGAACGCTGGCGGCGTGCCTAATACATGCAAGTAGAACGCTGAAGGAGGAG CTTGCTTCTCTGGATGAGTTGCGAACGGGTGAGTAACGCGTAGGTAACCTGCCTGGTAGCGGGGGATAAC TATTGGAAACGATAGCTAATACCGCATAAGAGTGGATGTTGCATGACATTTGCTTAAAAGGTGCACTTGC ATCACTACCAGATGGACCTGCGTTGTATTAGCTAGTTGGTGGGGTAACGGCTCACCAAGGCGACGATACA TAGCCGACCTGAGAGGGTGATCGGCCACACTGGGACTGAGACACGKCCCAGACTCCTACGGGAGGCAGCA GTAGGGAATCTTCGGCAATGGACGGAAGTCTGACCGAGCAACGCCGCGTGAGTGAAGAAGGTTTTCGGAT CGTAAAGCTCTGTTGTAAGAGAAGAACGAGTGTGAGAGTGGAAAGTTCACACTGTGACGGTATCTTACCA GAAAGGGACGGCTAACTACGTGCCAGCAGCCGCGGTAATACGTAGGTCCCGAGCGTTGTCCGGATTTATT GGGCGTAAAGCGAGCGCAGGCGGTTAGATAAGTCTGAAGTTAAAGGCTGTGGCTTAACCATAGTAGGCTT TGGAAACTGTTTAACTTGAGTGCAAGAGGGGAGAGTGGAATTCCATGTGTAGCGGTGAAATGCGTAGATA TATGGAGGAACACCGGTGGCGAAAGCGGCTCTCTGGCTTGTAACTGACGCTGAGGCTCGAAAGCGTGGGG AGCAAACAGGATTAGATACCCTGGTAGTCCACGCTGTAAACGATGAGTGCTAGGTGTTAGACCCTTTCCG GGGTTTAGTGCCGTAGCTAACGCATTAAGCACTCCGCCTGGGGAGTACGACCGCAAGGTTGAAACTCAAA GGAATTGACGGGGGCCCGCACAAGCGGTGGAGCATGTGGTTTAATTCGAAGCAACGCGAAGAACCTTACC AGGTCTTGACATCCCTCTGACCGCTCTAGAGATAGAGTTTTCCTTCGGGACAGAGGTGACAGGTGGTGCA TGGTTGTCGTCAGCTCGTGTCGTGAGATGTTGGGTTAAGTCCCGCAACGAGCGCAACCCCTATTGTTAGT TGCCATCATTCAGTTGGGCACTCTAGCGAGACTGCCGGTAATAAACCGGAGGAAGGTGGGGATGACGTCA AATCATCATGCCCCTTATGACCTGGGCTACACACGTGCTACAATGGCTGGTACAACGAGTCGCAAGCCGG TGACGGCAAGCTAATCTCTTAAAGCCAGTCTCAGTTCGGATTGTAGGCTGCAACTCGCCTACATGAAGTC GGAATCGCTAGTAATCGCGGATCAGCACGCCGCGGTGAATACGTTCCCGGGCCTTGTACACACCGCCCGT CACACCACGAGAGTTTGTAACACCCGAAGTCGGTGAGGTAACCGTAAGGAGCCAGCCGCCTAAGGTGGGA TAGATGATTGGGGTGAAGTCGTAACAAGGTCAGCCGTTTGGGAGA scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/data/il6.nucl.aln000066400000000000000000000122171520735541300256440ustar00rootroot00000000000000>human ------------------------------------------------ATGAACTCCTTC TCCACAAGCGCCTTCGGTCCAGTTGCCTT---------------CTCCCTGGGGCTGCTC CTGGTGTTGCCTGCTGCCTTCCCTGCCCCAGTACCCCCAGGAGAAGATTCCAAAGATGTA GCCGCCCCA--CACAGACAGCCACTCACCT-CTTCAGAACGAATTGACAAACAAATTCGG TACATCCTCGACGGCATCTCAGCCCTGAGAAAGGAGACATGTAACAAGAGTAACATGTGT GAAAGCAGCAAAGAGGCACTGGCAGAAAACAACCTGAACCTTCCAAAGATGGCTGAAAAA GATGGATGCTTCCAATCTGGATTCAATGAGGAGACTTGCCTGGTGAAAATCATCACTGGT CTTTTGGAGTTTGAGGTATACCTAGAGTACCTCCAGAACAGATTTGAGAGTAGTGAGGAA ---CAAGCCAGAGCTGTGCAGATGAGTACAAAAGTCCTGATCCAGTTCCTGCAGAAAAAG GCAAAGAATCTAGATGCAATAACCACCCCTGACCCAACCACAAATGCCAGCCTGCTGACG AAGCTGCAGGCACAGAACCAGTGGCTGCAGGACATGACAACTCATCTCATTCTGCGCAGC TTTAAGGAGTTCCTGCAGTCCAGCCTGAGGGCTCTTCGGCAAATGTAG------------ ------------ >chimp ------------------------------------------------ATGAACTCCGTC TCCACAAGCGCCTTCGGTCCAGTTGCCTT---------------CTCCCTGGGGCTGCTC CTGGTGTTGCCTGCTGCCTTCCCTGCCCCAGTACCCCCAGGAGAAGATTCCAAAGATGTA GCCGCCCCA--CACAGACAGCCACTCACCT-CTTCAGAACGAATTGACAAACAAATTCGG TACATCCTCGACGGCATCTCAGCCCTGAGAAAGGAGACATGTAACAAGAGTAACATGTGT GAAAGCAGCAAAGAGGCACTGGCAGAAAACAACCTGAACCTTCCAAAGATGGCTGAAAAA GATGGATGCTTCCAATCTGGATTCAATGAGGAGACTTGCCTGGTGAAAATCATCACTGGT CTTTTGGAGTTTGAGGTATACCTAGAGTACCTCCAGAACAGATTTGAGAGTAGTGAGGAA ---CAAGCCAGAGCTGTGCAGATGAGTACAAAAGTCCTGATCCAGTTCCTGCAGAAAAAG GCAAAGAATCTAGATGCAATAACCACCCCTGACCCAACCACAAATGCCAGCCTGCTGACG AAGCTGCAGGCACAGAACCAGTGGCTGCAGGACATGACAACTCATCTCATCCTGCGCAGC TTTAAGGAGTTCCTGCAGTCCAGCCTGAGGGCTCTTCGGCAAATGTAG------------ ------------ >monkey ------------------------------------------------ATGAACTCCGTC TCCACAAGCGCCTTCGGTCCAGTTGCCTT---------------CTCCCTGGGGCTGCTC CTGGTGTTGCCTGCTGCCTTCCCCGCCCCAGTACTCCCAGGAGAAGATTCCAAAGATGTA GCCGCCCCA--CACAGCCAGCCACTGACCT-CTTCAGAACGAATTGACAAACACATTCGG TACATCCTCGACGGCATCTCAGCCCTGAGAAAGGAGACATGTAACAGGAGTAACATGTGT GAAAGCAGCAAAGAGGCACTGGCAGAAAACAACCTGAACCTTCCAAAGATGGCTGAAAAA GATGGATGCTTCCAATCTGGATTCAATGAGGACACTTGCCTGGTGAAAATCATCACTGGT CTTTTGGAGTTTGAGGTATACCTAGAGTACCTCCAGAACAGGTTTGAGAGTAGTGAGGAG ---CAAGCCAGAGCTGTGCAAATGAGTACAAAAGTCCTGATCCAGTTCCTGCAGAAAAAG GCAAAGAATCTAGATGCAATAACCACCCCTGAACCAACCACAAATGCCAGCCTGCTGACG AAGCTGCAGGCACAGAACCAGTGGCTGCAGGACATGACGACGCATCTCATCCTGCGCAGC TTTAAGGAGTTCCTGCAGTCCAGCCTGAGGGCTCTTCGGCAAATGTAA------------ ------------ >pig ------------------------------------------------ATGAACTCCCTC TCCACAAGCGCCTTCAGTCCAGTCGCCTT---------------CTCCCTGGGGCTGCTT CTGGTGATGGCTACTGCCTTCCCTACCCCGGGACGCCTGGAAGAAGATGCCAAAGGTGAT GCCACCTCA--GACAAAATGCTCTTCACCT-CTCCGGACAAAACTGAAGAACTCATTAAG TACATCCTCGGCAAAATCTCTGCAATGAGAAAGGAGATGTGTGAGAAGTATGAGAAGTGT GAAAACAGCAAGGAGGTACTGGCAGAAAACAACCTGAACCTTCCAAAAATGGCAGAAAAA GACGGATGCTTCCAATCTGGGTTCAATCAGGAGACCTGCTTGATGAGAATCACCACCGGT CTTGTGGAGTTTCAGATATACCTGGACTACCTCCAGAAAGAGTATGAGAGCAATAAGGGA ---AATGTCGAGGCTGTGCAGATTAGTACCAAAGCACTGATCCAGACCCTGAGGCAAAAG GGAAAGAATCCAGACAAAGCCACCACCCCTAACCCCACCACAAATGCCGGCCTGCTGGAT AAGCTGCAGTCACAGAACGAGTGGATGAAGAACACAAAGATCATTCTCATCCTGCGCAGC CTTGAGGATTTCCTGCAGTTCAGCCTGAGGGCCATTCGGATAATGTAG------------ ------------ >mouse ------------------------------------------------ATGAAGTTCCTC TCTGCAAGAGACTTCCATCCAGTTGCCTT---------------CTTGGG---ACTGATG CTGGTGACAACCACGGCCTTCCCTACTTCACAAGTCCGGAGAGGAGACTTCACAGAGGAT ACCACTCCC--AACAGACCTGTCTATACCA-CTTC---ACAAGTCGGAGGCTTAATTACA CATGTTCTCTGGGAAATCGTGGAAATGAGAAAAGAGTTGTGCAATGGCAATTCTGATTGT ATGAACAACGATGATGCACTTGCAGAAAACAATCTGAAACTTCCAGAGATACAAAGAAAT GATGGATGCTACCAAACTGGATATAATCAGGAAATTTGCCTATTGAAAATTTCCTCTGGT CTTCTGGAGTACCATAGCTACCTGGAGTACATGAAGAACAACTTAAAAGATAACAAGAAA GACAAAGCCAGAGTCCTTCAGAGAGATACAGAAACTCTAATTCATATCTTCAACCAAGAG GTAAAAGATTTACATAAAATAGTCCTTCCTACCCCAATTTCCAATGCTCTCCTAACAGAT AAGCTGGAGTCACAGAAGGAGTGGCTAAGGACCAAGACCATCCAATTCATCTTGAAATCA CTTGAAGAATTTCTAAAAGTCACTTTGAGATCTACTCGGCAAACCTAG------------ ------------ >rat ------------------------------------------------ATGAAGTTTCTC TCCGCAAGAGACTTCCAGCCAGTTGCCTT---------------CTTGGG---ACTGATG TTGTTGACAGCCACTGCCTTCCCTACTTCACAAGTCCGGAGAGGAGACTTCACAGAGGAT ACCACCCAC--AACAGACCAGTATATACCA-CTTC---ACAAGTCGGAGGCTTAATTACA TATGTTCTCAGGGAGATCTTGGAAATGAGAAAAGAGTTGTGCAATGGCAATTCTGATTGT ATGAACAGCGATGATGCACTGTCAGAAAACAATCTGAAACTTCCAGAAATACAAAGAAAT GATGGATGCTTCCAAACTGGATATAACCAGGAAATTTGCCTATTGAAAATCTGCTCTGGT CTTCTGGAGTTCCGTTTCTACCTGGAGTTTGTGAAGAACAACTTACAAGATAACAAGAAA GACAAAGCCAGAGTCATTCAGAGCAATACTGAAACCCTAGTTCATATCTTCAAACAAGAG ATAAAAGACTCATATAAAATAGTCCTTCCTACCCCAACTTCCAATGCTCTCCTAATGGAG AAGTTAGAGTCACAGAAGGAGTGGCTAAGGACCAAGACCATCCAACTCATCTTGAAAGCA CTTGAAGAATTTCTAAAGGTCACTATGAGGTCTACTCGGCAAACCTAG------------ ------------ >chicken ATGAACTTCACCGAGGGCTGCGAGGCGACGGGACGGCGGCCGGGGAGCGCCGGGAGCCGC CGCCGGAGAGCGCCCCGTCCCGGCCCCGTCGCGCTGCTGCCGCTGCTGCTGCCGCTGCTG CTGCCGCCCGCCGCCGCCGTCCCGCTGCCCGCCGCC---GCGGACTCGTCCGGAGAGGTT GGGCTGGAGGAGGAGGCGGGGGCGCGGCGGGCGCTGCTCGACTGCGAGCCGCTGGCCCGG GTGCTGCGCGACCGCGCCGTCCAGCTGCAGGACGAGATGTGCAAGAAGTTCACCGTGTGC GAGAACAGCATGGAGATGCTCGTCCGGAACAACCTCAACCTGCCCAAGGTGACGGAGGAG GACGGCTGCCTGCTCGCCGGCTTCGACGAGGAGAAATGCCTGACGAAGCTCTCCAGCGGC CTGTTCGCCTTTCAGACCTACCTGGAATTCATTCAAGAGACTTTCGATAGCGAAAAGCAG ---AACGTCGAGTCTCTGTGCTACAGCACAAAGCACCTGGCGGCCACGATCCGGCAGATG GTGATAAATCCCGATGAAGTGGTCATCCCAGACTCGGCCGCCCAGAAATCCCTCCTCGCC AATCTGAAGTCAGATAAGGACTGGATAGAGAAAATCACCATGCACCTCATCCTCCGAGAC TTTACTTCGTTTATGGAGAAGACCGTGAGGGCCGTTCGCTATTTGAAAAAGACCAGGAGT TTCAGTGCCTGA scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/data/il6.prot.aln000066400000000000000000000034151520735541300256670ustar00rootroot00000000000000>human MNS------------------FSTSAFGPVAF---SLGLLLVLPAAFPAPVPPGED---- SKDVAAPHRQPLTSSERIDKQIRYILDGISALRKETCNKSNMCESSKEALAENNLNLPKM AEKDGCFQSGFNEETCLVKIITGLLEFEVYLEYLQNRFESSE-EQARAVQMSTKVLIQFL QKKAKNLDAITTPDPTTNASLLTKLQAQNQWLQDMTTHLILRSFKEFLQSSLRALRQM-- ------ >chimp MNS------------------VSTSAFGPVAF---SLGLLLVLPAAFPAPVPPGED---- SKDVAAPHRQPLTSSERIDKQIRYILDGISALRKETCNKSNMCESSKEALAENNLNLPKM AEKDGCFQSGFNEETCLVKIITGLLEFEVYLEYLQNRFESSE-EQARAVQMSTKVLIQFL QKKAKNLDAITTPDPTTNASLLTKLQAQNQWLQDMTTHLILRSFKEFLQSSLRALRQM-- ------ >monkey MNS------------------VSTSAFGPVAF---SLGLLLVLPAAFPAPVLPGED---- SKDVAAPHSQPLTSSERIDKHIRYILDGISALRKETCNRSNMCESSKEALAENNLNLPKM AEKDGCFQSGFNEDTCLVKIITGLLEFEVYLEYLQNRFESSE-EQARAVQMSTKVLIQFL QKKAKNLDAITTPEPTTNASLLTKLQAQNQWLQDMTTHLILRSFKEFLQSSLRALRQM-- ------ >pig MNS------------------LSTSAFSPVAF---SLGLLLVMATAFPTPGRLEED---- AKGDATSDKMLFTSPDKTEELIKYILGKISAMRKEMCEKYEKCENSKEVLAENNLNLPKM AEKDGCFQSGFNQETCLMRITTGLVEFQIYLDYLQKEYESNK-GNVEAVQISTKALIQTL RQKGKNPDKATTPNPTTNAGLLDKLQSQNEWMKNTKIILILRSLEDFLQFSLRAIRIM-- ------ >mouse MKF------------------LSARDFHPVAF----LGLMLVTTTAFPTSQVRRGD---- FTEDTTPNRPVYT-TSQVGGLITHVLWEIVEMRKELCNGNSDCMNNDDALAENNLKLPEI QRNDGCYQTGYNQEICLLKISSGLLEYHSYLEYMKNNLKDNKKDKARVLQRDTETLIHIF NQEVKDLHKIVLPTPISNALLTDKLESQKEWLRTKTIQFILKSLEEFLKVTLRSTRQT-- ------ >rat MKF------------------LSARDFQPVAF----LGLMLLTATAFPTSQVRRGD---- FTEDTTHNRPVYT-TSQVGGLITYVLREILEMRKELCNGNSDCMNSDDALSENNLKLPEI QRNDGCFQTGYNQEICLLKICSGLLEFRFYLEFVKNNLQDNKKDKARVIQSNTETLVHIF KQEIKDSYKIVLPTPTSNALLMEKLESQKEWLRTKTIQLILKALEEFLKVTMRSTRQT-- ------ >chicken MNFTEGCEATGRRPGSAGSRRRRAPRPGPVALLPLLLPLLLPPAAAVPLPAAADSSGEVG LEEEAGARRALL----DCEPLARVLRDRAVQLQDEMCKKFTVCENSMEMLVRNNLNLPKV TEEDGCLLAGFDEEKCLTKLSSGLFAFQTYLEFIQETFDSEK-QNVESLCYSTKHLAATI RQMVINPDEVVIPDSAAQKSLLANLKSDKDWIEKITMHLILRDFTSFMEKTVRAVRYLKK TRSFSA scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/data/insulin.faa000066400000000000000000000005571520735541300256540ustar00rootroot00000000000000>sp|P01308|INS_HUMAN Insulin OS=Homo sapiens OX=9606 GN=INS PE=1 SV=1 MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAED LQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN >sp|P01325|INS1_MOUSE Insulin-1 OS=Mus musculus OX=10090 GN=Ins1 PE=1 SV=1 MALLVHFLPLLALLALWEPKPTQAFVKQHLCGPHLVEALYLVCGERGFFYTPKSRREVED PQVEQLELGGSPGDLQTLALEVARQKRGIVDQCCTSICSLYQLENYCN scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/data/tp53.nucl.aln000066400000000000000000000137531520735541300257530ustar00rootroot00000000000000>human ---------ATGGAGGAGCCGCAGTCAGATCCTAGCGTCGAGCCCCCTCTGAGTCAGGAA ACATTTTCAGACCTATGGAAACTACTTCCTGAAAACAACGTTCTGTCCCCCTTGCCGTCC CAAGCAATGGATGATTTGATGCTGTCCCCGGACGATATTGAACAATGGTTCACTGAAGAC CCAGGTCCAGATGAAGCTCCCAGAATGCCAGAGGCTGCTCCCCCCGTGGCCCCTGCACCA GCAGCTCCTACACCGGCGGCCCCTGCACCAGCCCCCTCCTGGCCCCTGTCATCTTCTGTC CCTTCCCAGAAAACCTACCAGGGCAGCTACGGTTTCCGTCTGGGCTTCTTGCATTCTGGG ACAGCCAAGTCTGTGACTTGCACGTACTCCCCTGCCCTCAACAAGATGTTTTGCCAACTG GCCAAGACCTGCCCTGTGCAGCTGTGGGTTGATTCCACACCCCCGCCCGGCACCCGCGTC CGCGCCATGGCCATCTACAAGCAGTCACAGCACATGACGGAGGTTGTGAGGCGCTGCCCC CACCATGAGCGCTGCTCA---GATAGCGATGGTCTGGCCCCTCCTCAGCATCTTATCCGA GTGGAAGGAAATTTGCGTGTGGAGTATTTGGATGACAGAAACACTTTTCGACATAGTGTG GTGGTGCCCTATGAGCCGCCTGAGGTTGGCTCTGACTGTACCACCATCCACTACAACTAC ATGTGTAACAGTTCCTGCATGGGCGGCATGAACCGGAGGCCCATCCTCACCATCATCACA CTGGAAGACTCCAGTGGTAATCTACTGGGACGGAACAGCTTTGAGGTGCGTGTTTGTGCC TGTCCTGGGAGAGACCGGCGCACAGAGGAAGAGAATCTCCGCAAGAAAGGGGAGCCTCAC CACGAGCTGCCCCCAGGGAGCACTAAGCGAGCACTGCCCAACAAC---ACCAGCTCCTCT CCCCAGCCAAAGAAGAAACCACTGGATGGAGAATATTTCACCCTTCAGATCCGTGGGCGT GAGCGCTTCGAGATGTTCCGAGAGCTGAATGAGGCCTTGGAACTCAAGGATGCCCAGGCT GGGAAGGAGCCAGGGGGGAGCAGGGCTCACTCCAGCCACCTGAAGTCCAAAAAGGGTCAG TCTACCTCCCGCCATAAAAAACTCATGTTCAAGACAGAAGGGCCTGACTCAGACTGA >monkey ---------ATGGAGGAGCCGCAGTCAGATCCTAGCATCGAGCCCCCTCTGAGTCAGGAA ACATTTTCAGACCTATGGAAACTACTTCCTGAAAACAACGTTCTGTCCCCCTTGCCGTCC CAAGCAGTGGATGATTTGATGCTGTCTCCAGACGATCTTGCACAATGGTTAACTGAAGAC CCAGGTCCAGATGAAGCTCCGAGAATGTCAGAGGCTGCTCCCCCCATGGCCCCCACACCA GCAGCTCCTACACCGGCGGCCCCTGCACCAGCCCCCTCCTGGCCCCTGTCATCCTCTGTC CCTTCCCAGAAAACCTACCATGGCAGCTACGGTTTCCGTCTGGGCTTCCTGCATTCTGGA ACAGCCAAGTCTGTGACTTGCACGTACTCCCCTGACCTCAACAAGATGTTTTGCCAGCTG GCCAAGACCTGCCCCGTGCAGCTATGGGTTGATTCCACACCCCCACCCGGCAGCCGCGTC CGCGCCATGGCCATCTACAAGCAGTCACAGCACATGACGGAGGTCGTGAGGCGCTGCCCC CACCATGAGCGCTGCTCA---GACAGCGATGGACTGGCCCCTCCTCAGCACCTTATCCGA GTGGAAGGAAATTTGCGTGTGGAGTATTCGGATGACAGAAACACTTTTCGACATAGTGTG GTGGTGCCCTATGAGCCGCCTGAGGTTGGCTCTGACTGTACCACCATCCACTACAACTAC ATGTGTAACAGTTCCTGCATGGGCGGCATGAACCGGAGGCCCATCCTTACCATTATCACA CTGGAAGACTCCAGTGGTAATCTACTGGGACGGAACAGCTTTGAGGTGCGAGTTTGTGCC TGTCCTGGGAGAGACCGGCGCACAGAGGAAGAGAATTTCCGCAAGAAAGGGGAGCCTTGC CACCAGCTGCCCCCTGGGAGCACTAAGCGAGCACTGCCCAACAAC---ACCAGCTCCTCT CCCCAGCCAAAGAAGAAACCACTGGATGGAGAATATTTCACCCTTCAGATCCGTGGGCGT GAGCGCTTCGAGATGTTCCGAGAGCTGAATGAGGCCTTGGAACTCAAGGATGCCCAGGCT GGGAAAGAGCCAGCGGGGAGCAGGGCTCACTCCAGCCACCTGAAGTCCAAGAAGGGGCAA TCTACCTCCCGCCATAAAAAATTCATGTTCAAGACAGAGGGGCCTGACTCAGACTGA >mouse ATGACTGCCATGGAGGAGTCACAGTCGGATATCAGCCTCGAGCTCCCTCTGAGCCAGGAG ACATTTTCAGGCTTATGGAAACTACTTCCTCCAGAAGATATCCTGCCATCACCTCACTGC ATGGAC------GATCTGTTGCTGCCCCAGGATGT---TGAGGA---G------TTTTTT GAAGGCCCAAGTGAAGCCCTCCGAGTGTCAGGAGCTCCTGCAGCACAGGACCCTGTCACC GAGACCCCTGGGCCAGTGGCCCCTGCCCCAGCCACTCCATGGCCCCTGTCATCTTTTGTC CCTTCTCAAAAAACTTACCAGGGCAACTATGGCTTCCACCTGGGCTTCCTGCAGTCTGGG ACAGCCAAGTCTGTTATGTGCACGTACTCTCCTCCCCTCAATAAGCTATTCTGCCAGCTG GCGAAGACGTGCCCTGTGCAGTTGTGGGTCAGCGCCACACCTCCAGCTGGGAGCCGTGTC CGCGCCATGGCCATCTACAAGAAGTCACAGCACATGACGGAGGTCGTGAGACGCTGCCCC CACCATGAGCGCTGCTCC---GATGGTGATGGCCTGGCTCCTCCCCAGCATCTTATCCGG GTGGAAGGAAATTTGTATCCCGAGTATCTGGAAGACAGGCAGACTTTTCGCCACAGCGTG GTGGTACCTTATGAGCCACCCGAGGCCGGCTCTGAGTATACCACCATCCACTACAAGTAC ATGTGTAATAGCTCCTGCATGGGGGGCATGAACCGCCGACCTATCCTTACCATCATCACA CTGGAAGACTCCAGTGGGAACCTTCTGGGACGGGACAGCTTTGAGGTTCGTGTTTGTGCC TGCCCTGGGAGAGACCGCCGTACAGAAGAAGAAAATTTCCGCAAAAAGGAAGTCCTTTGC CCTGAACTGCCCCCAGGGAGCGCAAAGAGAGCGCTGCCCACCTGC---ACAAGCGCCTCT CCCCCGCAAAAGAAAAAACCACTTGATGGAGAGTATTTCACCCTCAAGATCCGCGGGCGT AAACGCTTCGAGATGTTCCGGGAGCTGAATGAGGCCTTAGAGTTAAAGGATGCCCATGCT ACAGAGGAGTCTGGAGACAGCAGGGCTCACTCCAGCTACCTGAAGACCAAGAAGGGCCAG TCTACTTCCCGCCATAAAAAAACAATGGTCAAGAAAGTGGGGCCTGACTCAGACTGA >cattle ---------ATGGAAGAATCACAGGCAGAACTCAATGTGGAGCCCCCTCTGAGTCAGGAG ACATTTTCCGACTTGTGGAACCTACTTCCTGAAAATAACCTTCTGTCCTCCGAGCTCTCC GCACCCGTGGATGACCTGCTCCCGTACACAGATGT---TGCCACCTGGCTGGATGAAT-- ----GTCCGAATGAAGCGCCCCAAATGC---------------CAGAGCCTTCTGCCCCA GCTGCCCCGCCACCAGCCACCCCAGCACCAGCCACCTCCTGGCCCCTGTCGTCCTTTGTC CCCTCCCAGAAGACCTACCCTGGCAATTACGGTTTCCGTCTAGGGTTCCTGCAATCCGGA ACAGCCAAGTCCGTGACCTGCACGTATTCCCCTTCCCTTAACAAGCTGTTCTGCCAGCTG GCCAAGACCTGCCCAGTGCAGCTGTGGGTCGACTCGCCACCCCCGCCCGGCACCCGCGTC CGCGCCATGGCCATCTACAAGAAGTTGGAGCACATGACGGAGGTTGTGAGGCGTTGTCCC CACCATGAGCGCTCCTCTGACTATAGCGATGGTCTGGCCCCTCCTCAGCACCTTATCCGG GTGGAAGGGAATTTACGCGCGGAGTATTTGGACGACCGGAACACCTTTAGACACAGTGTG GTGGTGCCCTATGAGTCCCCCGAGATCGACTCTGAGTGCACCACCATCCACTACAATTTC ATGTGTAACAGCTCCTGCATGGGGGGCATGAACCGGCGGCCCATCCTCACCATCATCACA CTGGAAGACTCTTGTGGTAACCTGCTGGGACGGAACAGCTTTGAGGTGCGTGTTTGTGCC TGTCCTGGGAGAGACCGCCGCACTGAGGAAGAAAATCTTCGCAAGAAGGGGCAGTCTTGC CCCGAGCCACCCCCTAGGAGCACTAAGCGAGCACTGCCTACCAAC---ACCAGCTCCTCT CCACAGCCAAAGAAGAAACCACTGGATGGAGAGTACTTCACTCTTCAGATCCGTGGGTTT AAACGCTATGAGATGTTCCGAGAGCTGAATGATGCCTTGGAGCTGAAGGATGCTCTGGAT GGAAGGGAACCAGGGGAAAGCAGGGCTCACTCTAGCCACCTGAAGTCTAAGAAGAGGCCT TCTCCCTCCTGCCATAAAAAACCAATGCTCAAGAGAGAGGGACCTGACTCAGACTGA >rabbit ---------ATGGAGGAGTCGCAGTCGGATCTCAGCCTCGAGCCTCCCCTGAGTCAGGAG ACGTTTTCAGACCTGTGGAAACTGCTTCCTGAGAACAACCTGCTGACCACCTCGCTGAAC CCTCCCGTGGATGATCTGCTGTCTGC---AGAAGACGTTGCAAACTGGCTCAACGAAG-- ----ACCCAGAAGAAGGGCTCCGAGTACCAGCAGCTCCTGCACCAGAGGCCCCCGCCCCA GCTGCCCCTGCGCTGGCGGCCCCTGCACCAGCCACCTCCTGGCCCCTGTCATCCTCTGTC CCTTCCCAAAAGACCTACCATGGCAACTACGGTTTCCGGCTGGGCTTCCTGCACTCTGGG ACGGCCAAGTCTGTCACCTGCACATACTCCCCCTGCCTCAACAAGCTGTTCTGCCAGCTA GCAAAGACCTGCCCTGTGCAGCTGTGGGTCGACTCGACGCCCCCGCCTGGCACCCGCGTC CGGGCCATGGCCATCTACAAGAAGTCTCAGCACATGACGGAAGTTGTCAGACGCTGCCCC CACCACGAGCGCTGCTCC---GACAGCGATGGTCTGGCCCCCCCTCAGCATCTCATCCGG GTGGAGGGAAATCTCCGTGCGGAGTATTTGGATGACAGAAACACCTTCCGACACAGCGTG GTGGTGCCCTACGAGCCGCCCGAGGTTGGCTCTGACTGTACCACCATCCACTATAATTAC ATGTGTAACAGCTCCTGCATGGGGGGCATGAACCGGCGGCCCATCCTCACCATCATCACA CTGGAAGACTCCAGTGGGAACCTGCTGGGACGGAACAGCTTTGAGGTGCGAGTGTGTGCC TGTCCTGGGAGGGACCGCCGCACGGAGGAAGAAAATTTCCGCAAGAAAGGGGAGCCCTGC CCTGAACTGCCCCCTGGGAGCTCTAAGCGAGCACTGCCGACCACCACCACCGACTCCTCT CCCCAGACAAAGAAGAAGCCGCTGGATGGAGAATATTTCATCCTTAAGATCCGCGGGCGT GAACGGTTCGAGATGTTCCGAGAGCTGAACGAGGCCCTGGAGCTAAAGGATGCCCAGGCC GAGAAGGAGCCCGGGGGGAGCAGGGCTCACTCCAGCTACCTGAAGGCCAAGAAGGGGCAG TCTACCTCCCGCCATAAAAAACCAATGTTCAAGAGAGAGGGGCCTGACTCAGACTGA scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/data/tp53.prot.aln000066400000000000000000000040171520735541300257670ustar00rootroot00000000000000>human ---MEEPQSDPSVEPPLSQETFSDLWKLLPENNVLSPLPSQAMDDLMLSPDDIEQWFTED PGPDEAPRMPEAAPPVAPAPAAPTPAAPAPAPSWPLSSSVPSQKTYQGSYGFRLGFLHSG TAKSVTCTYSPALNKMFCQLAKTCPVQLWVDSTPPPGTRVRAMAIYKQSQHMTEVVRRCP HHERCSD-SDGLAPPQHLIRVEGNLRVEYLDDRNTFRHSVVVPYEPPEVGSDCTTIHYNY MCNSSCMGGMNRRPILTIITLEDSSGNLLGRNSFEVRVCACPGRDRRTEEENLRKKGEPH HELPPGSTKRALPNNT-SSSPQPKKKPLDGEYFTLQIRGRERFEMFRELNEALELKDAQA GKEPGGSRAHSSHLKSKKGQSTSRHKKLMFKTEGPDSD >monkey ---MEEPQSDPSIEPPLSQETFSDLWKLLPENNVLSPLPSQAVDDLMLSPDDLAQWLTED PGPDEAPRMSEAAPPMAPTPAAPTPAAPAPAPSWPLSSSVPSQKTYHGSYGFRLGFLHSG TAKSVTCTYSPDLNKMFCQLAKTCPVQLWVDSTPPPGSRVRAMAIYKQSQHMTEVVRRCP HHERCSD-SDGLAPPQHLIRVEGNLRVEYSDDRNTFRHSVVVPYEPPEVGSDCTTIHYNY MCNSSCMGGMNRRPILTIITLEDSSGNLLGRNSFEVRVCACPGRDRRTEEENFRKKGEPC HQLPPGSTKRALPNNT-SSSPQPKKKPLDGEYFTLQIRGRERFEMFRELNEALELKDAQA GKEPAGSRAHSSHLKSKKGQSTSRHKKFMFKTEGPDSD >mouse MTAMEESQSDISLELPLSQETFSGLWKLLPPEDILPSP--HCMDDL-LLPQDVEEFFE-- -GPSEALRVSGAPAAQDPVTETPGPVAPAPATPWPLSSFVPSQKTYQGNYGFHLGFLQSG TAKSVMCTYSPPLNKLFCQLAKTCPVQLWVSATPPAGSRVRAMAIYKKSQHMTEVVRRCP HHERCSD-GDGLAPPQHLIRVEGNLYPEYLEDRQTFRHSVVVPYEPPEAGSEYTTIHYKY MCNSSCMGGMNRRPILTIITLEDSSGNLLGRDSFEVRVCACPGRDRRTEEENFRKKEVLC PELPPGSAKRALPTCT-SASPPQKKKPLDGEYFTLKIRGRKRFEMFRELNEALELKDAHA TEESGDSRAHSSYLKTKKGQSTSRHKKTMVKKVGPDSD >cattle ---MEESQAELNVEPPLSQETFSDLWNLLPENNLLSSELSAPVDDL-LPYTDVATWLDEC P--NEAPQMPEP-----SAPAAPPPATPAPATSWPLSSFVPSQKTYPGNYGFRLGFLQSG TAKSVTCTYSPSLNKLFCQLAKTCPVQLWVDSPPPPGTRVRAMAIYKKLEHMTEVVRRCP HHERSSDYSDGLAPPQHLIRVEGNLRAEYLDDRNTFRHSVVVPYESPEIDSECTTIHYNF MCNSSCMGGMNRRPILTIITLEDSCGNLLGRNSFEVRVCACPGRDRRTEEENLRKKGQSC PEPPPRSTKRALPTNT-SSSPQPKKKPLDGEYFTLQIRGFKRYEMFRELNDALELKDALD GREPGESRAHSSHLKSKKRPSPSCHKKPMLKREGPDSD >rabbit ---MEESQSDLSLEPPLSQETFSDLWKLLPENNLLTTSLNPPVDDL-LSAEDVANWLNED P--EEGLRVPAAPAPEAPAPAAPALAAPAPATSWPLSSSVPSQKTYHGNYGFRLGFLHSG TAKSVTCTYSPCLNKLFCQLAKTCPVQLWVDSTPPPGTRVRAMAIYKKSQHMTEVVRRCP HHERCSD-SDGLAPPQHLIRVEGNLRAEYLDDRNTFRHSVVVPYEPPEVGSDCTTIHYNY MCNSSCMGGMNRRPILTIITLEDSSGNLLGRNSFEVRVCACPGRDRRTEEENFRKKGEPC PELPPGSSKRALPTTTTDSSPQTKKKPLDGEYFILKIRGRERFEMFRELNEALELKDAQA EKEPGGSRAHSSYLKAKKGQSTSRHKKPMFKREGPDSD scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/test_distance.py000066400000000000000000000704701520735541300260150ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt from skbio.alignment import TabularMSA from skbio.sequence import DNA, RNA, Protein from skbio.sequence.distance import ( hamming, pdist, jc69, f81, k2p, f84, tn93, logdet, paralin, _p_correct ) from skbio.stats.distance import DistanceMatrix from skbio.util import get_data_path from skbio.alignment._distance import align_dists, _char_hash nan = np.nan class AlignDistsTests(TestCase): def setUp(self): # a DNA sequence alignment self.msa_nucl = TabularMSA([ DNA("CTGGTG---CCTGCTGCCTTCCCTGCCCCAGTACCCGGAGAAG--TCCAAAGATGTA"), DNA("CTGGTG---ACCACGGCC------ACTTCACAAGT----GGAGACTTCACAGAGGAT"), DNA("CTG-CGCCCGCCG-CGCCGTCC--CTGCCCGCCGCCGCGGACTCGTCCG----GGTT"), ]) # a protein sequence alignment self.msa_prot = TabularMSA([ Protein("MLGLLLVLPAAF-APVPPGEDMF"), Protein("MLPLLLVMATAFDTPGRL-EDML"), Protein("--GLMLQCTTAFPTSQVRRGDIL"), ]) # a DNA sequence alignment with ambiguous codes self.msa1 = TabularMSA([ DNA("ATC-GTATCGY"), # degenerate char: "Y" DNA("ATGCG--CCGC"), DNA("GT-CGTACG-T"), DNA("GT-NTTACAGT"), # degenerate char: "N" ], index=list("abcd")) # a protein sequence alignment with ambiguous codes self.msa2 = TabularMSA([ Protein("MQVEGATSI"), Protein("MKNJ-PTSL"), # degenerate char: "J" Protein("MKDE-PYRX"), # degenerate char: "X" Protein("MQUENPT--"), # non-canonical char: "U" ], index=list("abcd")) # an RNA sequence alignment where no site is shared across all sequences. self.msa3 = TabularMSA([ RNA("AG-UGCU-CA"), RNA("--AUC--GC-"), RNA("ACU--AUG-A"), ], index=list("abc")) # a DNA sequence alignment where one pair of sequences shares no site. self.msa4 = TabularMSA([ DNA("ACGT-CT"), DNA("AG--A-T"), DNA("--CT-C-"), ], index=list("abc")) # Identical sequences: # 0 and 1 are identical # 1 and 2 are identical after complete/pairwise deletion # 2 and 3 are identical after complete deletion self.msa_ident = TabularMSA([ DNA("ACG-TCTGCC"), DNA("ACG-TCTGCC"), DNA("ACGGTCT-CC"), DNA("ACGATCT-CC"), ], index=list("abcd")) def test_align_dists_error(self): # wrong sequence type with self.assertRaises(TypeError) as cm: align_dists(self.msa_prot, "jc69") msg = "'jc69' is compatible with ('DNA', 'RNA') sequences, not 'Protein'." self.assertEqual(str(cm.exception), msg) # wrong metric type with self.assertRaises(TypeError) as cm: align_dists(self.msa_prot, 123) msg = "`metric` must be a function or a string." self.assertEqual(str(cm.exception), msg) # wrong metric name with self.assertRaises(ValueError) as cm: align_dists(self.msa_prot, "hello") msg = ("'hello' is not an available sequence distance metric name. " "Refer to `skbio.sequence.distance` for a list of available metrics.") self.assertEqual(str(cm.exception), msg) # is a preset function but not a distance metric with self.assertRaises(ValueError) as cm: align_dists(self.msa_prot, _p_correct) msg = ("`_p_correct` is not a sequence distance metric. Refer to " "`skbio.sequence.distance` for a list of available metrics.") self.assertEqual(str(cm.exception), msg) # no sequence with self.assertRaises(ValueError) as cm: align_dists(TabularMSA(()), "pdist") msg = "Alignment contains no sequence." self.assertEqual(str(cm.exception), msg) def test_align_dists_edge(self): # one sequence msa = TabularMSA((DNA("ACGT"),), index=["a"]) obs = align_dists(msa, "pdist") exp = np.array([]) npt.assert_array_equal(obs.condensed_form(), exp) self.assertTupleEqual(obs.ids, ("a",)) # zero-length sequences msa = TabularMSA((DNA(""), DNA(""), DNA("")), index=list("abc")) obs = align_dists(msa, "pdist") exp = np.array([nan, nan, nan]) npt.assert_array_equal(obs.condensed_form(), exp) self.assertTupleEqual(obs.ids, ("a", "b", "c")) def test_align_dists_custom(self): # custom function def metric1(seq1, seq2): return seq1.count("A") + seq2.count("A") obs = align_dists(self.msa1, metric1) exp = np.array([2, 1, 2, 1, 2, 1], dtype=float) npt.assert_array_equal(obs.condensed_form(), exp) obs = align_dists(self.msa1, metric1, shared_by_all=False) exp = np.array([2, 3, 4, 1, 2, 3], dtype=float) npt.assert_array_equal(obs.condensed_form(), exp) def test_align_dists_hamming(self): """Hamming distance.""" obs = align_dists(self.msa_nucl, "hamming") exp = np.array([0.5087719, 0.5614035, 0.6666667]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "hamming", shared_by_all=False) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, hamming) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, hamming, shared_by_all=False) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "hamming", proportion=False) exp = np.array([29, 32, 38], dtype=float) npt.assert_array_equal(obs.condensed_form(), exp) def test_align_dists_pdist(self): """p-distance.""" obs = align_dists(self.msa_nucl, "pdist") exp = np.array([0.4444444, 0.4444444, 0.5277778]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "pdist", shared_by_all=False) exp = np.array([0.4047619, 0.4318182, 0.5526316]) npt.assert_array_equal(obs.condensed_form().round(7), exp) # complete deletion (5 sites) obs = align_dists(self.msa1, "pdist") self.assertIsInstance(obs, DistanceMatrix) self.assertTupleEqual(obs.ids, tuple("abcd")) exp = np.array([0.2, 0.6, 0.8, 0.4, 0.6, 0.4]) npt.assert_array_equal(obs.condensed_form(), exp) # supply function obs = align_dists(self.msa1, pdist) npt.assert_array_equal(obs.condensed_form(), exp) # pairwise deletion obs = align_dists(self.msa1, "pdist", shared_by_all=False) exp = np.array([2/7, 3/7, 4/8, 3/7, 4/7, 2/8]) npt.assert_allclose(obs.condensed_form(), exp) # supply function obs = align_dists(self.msa1, pdist, shared_by_all=False) npt.assert_array_equal(obs.condensed_form(), exp) # edge case: no site left after complete deletion obs = align_dists(self.msa3, "pdist") self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa3, "pdist", shared_by_all=False) exp = np.array([0.333, 0.4, 0.5]) npt.assert_array_equal(obs.condensed_form().round(3), exp) # edge case: no site left after pairwise deletion obs = align_dists(self.msa4, "pdist") self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa4, "pdist", shared_by_all=False) exp = np.array([0.333, 0.333, nan]) npt.assert_array_equal(obs.condensed_form().round(3), exp) def test_align_dists_jc69(self): """JC69 distance.""" obs = align_dists(self.msa_nucl, "jc69") exp = np.array([0.6734562, 0.6734562, 0.9122965]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "jc69", gamma=2.0) exp = np.array([0.8500484, 0.8500484, 1.255676]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "jc69", shared_by_all=False) exp = np.array([0.5818792, 0.6430877, 1.0012508]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "jc69", shared_by_all=False, gamma=2.0) exp = np.array([0.7108666, 0.8029484, 1.4240383]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa1, "jc69") exp = np.array([0.233, 1.207, nan, 0.572, 1.207, 0.572]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, jc69) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "jc69", gamma=2.0) exp = np.array([0.252, 1.854, nan, 0.696, 1.854, 0.696]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, jc69, gamma=2.0) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "jc69", shared_by_all=False) exp = np.array([0.360, 0.635, 0.824, 0.635, 1.076, 0.304]) npt.assert_allclose(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, jc69, shared_by_all=False) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "jc69", shared_by_all=False, gamma=2.0) exp = np.array([0.406, 0.791, 1.098, 0.791, 1.574, 0.337]) npt.assert_allclose(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "jc69", shared_by_all=False, gamma=2) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, jc69, shared_by_all=False, gamma=2.0) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa3, "jc69") self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa3, "jc69", gamma=2.0) self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa3, "jc69", shared_by_all=False) exp = np.array([0.441, 0.572, 0.824]) npt.assert_array_equal(obs.condensed_form().round(3), exp) msg = "'jc69' is compatible with ('DNA', 'RNA') sequences, not 'Protein'." with self.assertRaises(TypeError) as cm: align_dists(self.msa2, "jc69") self.assertEqual(str(cm.exception), msg) with self.assertRaises(TypeError) as cm: align_dists(self.msa2, jc69) self.assertEqual(str(cm.exception), msg) msg = "Parameter 'gamma' must be a positive number." with self.assertRaises(ValueError) as cm: align_dists(self.msa1, "jc69", gamma=-2.0) self.assertEqual(str(cm.exception), msg) with self.assertRaises(ValueError) as cm: align_dists(self.msa1, "jc69", gamma=0.0) self.assertEqual(str(cm.exception), msg) def test_align_dists_f81(self): """F81 distance.""" # normal DNA sequences obs = align_dists(self.msa_nucl, "f81") exp = np.array([0.6922797, 0.6922797, 0.9524649]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, f81) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "f81", gamma=2.0) exp = np.array([0.8892592, 0.8892592, 1.3508859]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, f81, gamma=2.0) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "f81", shared_by_all=False) exp = np.array([0.5951889, 0.6599422, 1.0526322]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "f81", shared_by_all=False, gamma=2.0) exp = np.array([0.7373042, 0.8375044, 1.5520988]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "f81", freqs=np.full(4, 0.25)) exp = np.array([0.6734562, 0.6734562, 0.9122965]) npt.assert_array_equal(obs.condensed_form().round(7), exp) # F81 is equivalent to JC69 when base frequencies are equal. exp = align_dists(self.msa_nucl, "jc69") npt.assert_allclose(obs.condensed_form(), exp.condensed_form()) obs = align_dists(self.msa_nucl, "f81", freqs=np.full(4, 0.25), gamma=2.0) exp = np.array([0.8500484, 0.8500484, 1.255676]) npt.assert_array_equal(obs.condensed_form().round(7), exp) # F81 is equivalent to JC69 when base frequencies are equal. exp = align_dists(self.msa_nucl, "jc69", gamma=2.0) npt.assert_allclose(obs.condensed_form(), exp.condensed_form()) # short DNA sequences with ambiguity obs = align_dists(self.msa1, "f81") exp = np.array([0.233, 1.234, nan, 0.576, 1.234, 0.576]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "f81", gamma=2.0) exp = np.array([0.253, 1.928, nan, 0.704, 1.928, 0.704]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "f81", shared_by_all=False) exp = np.array([0.361, 0.641, 0.834, 0.641, 1.096, 0.305]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "f81", shared_by_all=False, gamma=2.0) exp = np.array([0.409, 0.802, 1.121, 0.802, 1.625, 0.339]) npt.assert_array_equal(obs.condensed_form().round(3), exp) # short, hollow RNA sequences obs = align_dists(self.msa3, "f81") self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa3, "f81", gamma=2.0) self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa3, "f81", shared_by_all=False) exp = np.array([0.442, 0.574, 0.829]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa3, "f81", shared_by_all=False, gamma=2.0) exp = np.array([0.514, 0.7, 1.108]) npt.assert_array_equal(obs.condensed_form().round(3), exp) with self.assertRaises(TypeError): align_dists(self.msa2, "f81") with self.assertRaises(ValueError): align_dists(self.msa1, "f81", gamma=-2.0) with self.assertRaises(ValueError): align_dists(self.msa1, "f81", gamma=0.0) def test_align_dists_k2p(self): """K2P distance.""" # normal DNA sequences obs = align_dists(self.msa_nucl, "k2p") exp = np.array([0.6962528, 0.6749634, 0.9547713]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, k2p) exp = np.array([0.6962528, 0.6749634, 0.9547713]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "k2p", gamma=2.0) exp = np.array([0.9028712, 0.8535675, 1.3713203]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, k2p, gamma=2.0) exp = np.array([0.9028712, 0.8535675, 1.3713203]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "k2p", shared_by_all=False) exp = np.array([0.5921321, 0.6440233, 1.0287045]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "k2p", shared_by_all=False, gamma=2.0) exp = np.array([0.7332483, 0.8050918, 1.5032039]) npt.assert_array_equal(obs.condensed_form().round(7), exp) # short DNA sequences with ambiguity obs = align_dists(self.msa1, "k2p") exp = np.array([0.255, nan, nan, 0.586, 1.207, 0.586]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "k2p", gamma=2.0) exp = np.array([0.291, nan, nan, 0.727, 1.854, 0.727]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "k2p", shared_by_all=False) exp = np.array([0.364, 0.710, 0.866, 0.710, 1.185, 0.307]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "k2p", shared_by_all=False, gamma=2.0) exp = np.array([0.414, 0.962, 1.207, 0.962, 1.91, 0.342]) npt.assert_array_equal(obs.condensed_form().round(3), exp) # short, hollow RNA sequences obs = align_dists(self.msa3, "k2p") self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa3, "k2p", gamma=2.0) self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa3, "k2p", shared_by_all=False) exp = np.array([0.477, 0.658, nan]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa3, "k2p", shared_by_all=False, gamma=2.0) exp = np.array([0.591, 0.909, nan]) npt.assert_array_equal(obs.condensed_form().round(3), exp) with self.assertRaises(ValueError): align_dists(self.msa1, "k2p", gamma=-2.0) with self.assertRaises(ValueError): align_dists(self.msa1, "k2p", gamma=0.0) def test_align_dists_f84(self): """F84 distance.""" # normal DNA sequences obs = align_dists(self.msa_nucl, "f84") exp = np.array([0.7322711, 0.6966819, 1.0393658]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, f84) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "f84", shared_by_all=False) exp = np.array([0.6132254, 0.6629780, 1.1168612]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "f84", freqs=np.full(4, .25)) exp = np.array([0.6962528, 0.6749634, 0.9547713]) npt.assert_array_equal(obs.condensed_form().round(7), exp) # F84 is equivalent to K2P when base frequencies are equal. exp = align_dists(self.msa_nucl, "k2p") npt.assert_allclose(obs.condensed_form(), exp.condensed_form()) # short DNA sequences with ambiguity obs = align_dists(self.msa1, "f84") exp = np.array([0.258, nan, nan, 0.592, 1.234, 0.592]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "f84", shared_by_all=False) exp = np.array([0.366, 0.727, 0.884, 0.727, 1.230, 0.308]) npt.assert_array_equal(obs.condensed_form().round(3), exp) # short, hollow RNA sequences obs = align_dists(self.msa3, "f84") self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa3, "f84", shared_by_all=False) exp = np.array([0.479, 0.661, nan]) npt.assert_array_equal(obs.condensed_form().round(3), exp) with self.assertRaises(TypeError): align_dists(self.msa2, "f84") def test_align_dists_tn93(self): """TN93 distance.""" obs = align_dists(self.msa_nucl, "tn93") exp = np.array([0.7404173, 0.7636621, 1.0432672]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, tn93) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "tn93", gamma=2.0) exp = np.array([1.0093559, 1.0793108, 1.6223118]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, tn93, gamma=2.0) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "tn93", shared_by_all=False) exp = np.array([0.6164222, 0.6757994, 1.1236656]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "tn93", shared_by_all=False, gamma=2.0) exp = np.array([0.78596, 0.8764643, 1.7801847]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "tn93", freqs=np.full(4, 0.25)) exp = np.array([0.7256986, 0.7737915, 0.9709059]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "tn93", freqs=np.full(4, 0.25), gamma=2.0) exp = np.array([0.9814806, 1.114347, 1.4234282]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa1, "tn93") exp = np.array([0.357, nan, nan, nan, nan, nan]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa1, "tn93", gamma=2.0) exp = np.array([0.503, nan, nan, nan, nan, nan]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa3, "tn93") self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa3, "tn93", gamma=2.0) self.assertTrue(np.isnan(obs.condensed_form()).all()) obs = align_dists(self.msa3, "tn93", shared_by_all=False) exp = np.array([0.479, 0.661, nan]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa3, "tn93", shared_by_all=False, gamma=2.0) exp = np.array([0.594, 0.916, nan]) npt.assert_array_equal(obs.condensed_form().round(3), exp) with self.assertRaises(ValueError): align_dists(self.msa1, "tn93", gamma=-2.0) with self.assertRaises(ValueError): align_dists(self.msa1, "tn93", gamma=0.0) def test_align_dists_logdet(self): """LogDet distance.""" obs = align_dists(self.msa_nucl, "logdet") exp = np.array([0.7422038, 0.9347606, nan]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, logdet) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "logdet", shared_by_all=False) exp = np.array([0.6549783, 0.9558150, nan]) npt.assert_array_equal(obs.condensed_form().round(7), exp) aln = TabularMSA.read(get_data_path("tp53.nucl.aln"), constructor=DNA) obs = align_dists(aln, "logdet") exp = np.array([ 0.049, 0.242, 0.195, 0.171, 0.253, 0.204, 0.175, 0.289, 0.248, 0.219]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(aln, "logdet", shared_by_all=False) exp = np.array([ 0.051, 0.250, 0.199, 0.177, 0.262, 0.208, 0.181, 0.291, 0.247, 0.219]) npt.assert_array_equal(obs.condensed_form().round(3), exp) aln = TabularMSA.read(get_data_path("tp53.prot.aln"), constructor=Protein) obs = align_dists(aln, "logdet") exp = np.array([ 0.189, 0.393, 0.342, 0.277, 0.406, 0.348, 0.267, 0.450, 0.374, 0.347]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(aln, "logdet", pseudocount=0.5) exp = np.array([ 0.585, 0.787, 0.737, 0.672, 0.800, 0.743, 0.663, 0.844, 0.768, 0.741]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa4, "logdet", shared_by_all=False) self.assertTrue(np.isnan(obs.condensed_form()).all()) def test_align_dists_paralin(self): """Paralinear distance.""" obs = align_dists(self.msa_nucl, "paralin") exp = np.array([0.7212106, 0.7054428, nan]) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, paralin) npt.assert_array_equal(obs.condensed_form().round(7), exp) obs = align_dists(self.msa_nucl, "paralin", shared_by_all=False) exp = np.array([0.6378228, 0.6976025, nan]) npt.assert_array_equal(obs.condensed_form().round(7), exp) aln = TabularMSA.read(get_data_path("tp53.nucl.aln"), constructor=DNA) obs = align_dists(aln, "paralin") exp = np.array([ 0.035, 0.231, 0.181, 0.151, 0.242, 0.190, 0.154, 0.278, 0.230, 0.199]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(aln, "paralin", shared_by_all=False) exp = np.array([ 0.037, 0.238, 0.186, 0.158, 0.25 , 0.195, 0.161, 0.279, 0.229, 0.199]) npt.assert_array_equal(obs.condensed_form().round(3), exp) aln = TabularMSA.read(get_data_path("tp53.prot.aln"), constructor=Protein) obs = align_dists(aln, "paralin") exp = np.array([ 0.048, 0.244, 0.19 , 0.127, 0.258, 0.197, 0.119, 0.291, 0.218, 0.188]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(aln, "paralin", pseudocount=0.5) exp = np.array([ 0.531, 0.732, 0.678, 0.615, 0.745, 0.685, 0.606, 0.784, 0.710, 0.681]) npt.assert_array_equal(obs.condensed_form().round(3), exp) obs = align_dists(self.msa4, "paralin", shared_by_all=False) self.assertTrue(np.isnan(obs.condensed_form()).all()) def test_site_mask(self): # NOTE: This test complements the original test of `_char_hash` in skbio. # sequence.distance, as it demonstrates the outcome of site masking. # DNA sequences seqs = np.vstack([seq._bytes for seq in self.msa1]) obs = _char_hash("ACGT", DNA)[seqs] exp = np.array([[1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1], [1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1], [1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1]], dtype=bool) npt.assert_array_equal(obs, exp) obs = _char_hash("ACGTN", DNA)[seqs] exp = np.array([[1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1], [1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1], [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1]], dtype=bool) npt.assert_array_equal(obs, exp) obs = _char_hash("ABCD", DNA)[seqs] exp = np.array([[1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1], [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0]], dtype=bool) npt.assert_array_equal(obs, exp) obs = _char_hash("nongap", DNA)[seqs] exp = np.array([[1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1], [1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1], [1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1]], dtype=bool) npt.assert_array_equal(obs, exp) obs = _char_hash("definite", DNA)[seqs] exp = np.array([[1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0], [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1], [1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1], [1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1]], dtype=bool) npt.assert_array_equal(obs, exp) # protein sequences seqs = np.vstack([seq._bytes for seq in self.msa2]) obs = _char_hash("nongap", Protein)[seqs] exp = np.array([[1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 0, 1, 1, 1, 1], [1, 1, 1, 1, 0, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 0, 0]], dtype=bool) npt.assert_array_equal(obs, exp) obs = _char_hash("definite", Protein)[seqs] exp = np.array([[1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 1, 1, 1, 1], [1, 1, 1, 1, 0, 1, 1, 1, 0], [1, 1, 1, 1, 1, 1, 1, 0, 0]], dtype=bool) npt.assert_array_equal(obs, exp) obs = _char_hash("canonical", Protein)[seqs] exp = np.array([[1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 1, 1, 1, 1], [1, 1, 1, 1, 0, 1, 1, 1, 0], [1, 1, 0, 1, 1, 1, 1, 0, 0]], dtype=bool) npt.assert_array_equal(obs, exp) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/test_pair.py000066400000000000000000001715311520735541300251560ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy as np import numpy.testing as npt import skbio.io from skbio.util import get_data_path from skbio.alignment import TabularMSA from skbio.sequence import Sequence, GrammaredSequence, DNA, Protein from skbio.sequence import SubstitutionMatrix from skbio.util import classproperty from skbio.util._decorator import overrides from skbio.alignment._utils import encode_sequences from skbio.alignment._pair import ( pair_align, pair_align_nucl, pair_align_prot, _prep_free_ends, _alloc_matrices, _init_matrices, _one_stop, _all_stops, _traceback_one, _traceback_all, ) from skbio.alignment._cutils import ( _fill_linear_matrix, _fill_affine_matrices, ) class PairAlignTests(unittest.TestCase): def test_pair_align_nucl(self): """Walk-through of a nucleotide alignment case.""" # Recognition sites of restriction enzymes EcoRI (GAATTC) and BglII (AGATCT). seq1 = DNA("GAATTC") seq2 = DNA("AGATCT") # Default behavior is semi-global alignment (free ends) with match score = 1, # mismatch score = -1 and linear gap penalty = 2. res = pair_align(seq1, seq2) # Up to one alignment path is returned. self.assertEqual(len(res.paths), 1) # Print the aligned sequences. path = res.paths[0] obs = path.to_aligned((seq1, seq2)) exp = ["-GAATTC", "AGATCT-"] self.assertListEqual(obs, exp) # A path can be represented by a CIGAR string. self.assertEqual(path.to_cigar(), "1I5M1D") # There are 3 matches and 2 mismatches, so score = 3 - 2 = 1. self.assertEqual(res.score, 1) # By default, the alignment matrix is discarded. self.assertIsNone(res.matrices) # Return all optimal alignments. There are two. res = pair_align(seq1, seq2, max_paths=None) self.assertEqual(len(res.paths), 2) # The 1st path is identical to the previous one. But the 2nd is different. obs = res.paths[0].to_aligned((seq1, seq2)) self.assertListEqual(obs, exp) obs = res.paths[1].to_aligned((seq1, seq2)) exp = ["GAATTC-", "-AGATCT"] self.assertListEqual(obs, exp) self.assertEqual(res.score, 1) # Disable traceback. res = pair_align(seq1, seq2, max_paths=0) self.assertIsNone(res.paths) # Keep the alignment matrix. res = pair_align(seq1, seq2, keep_matrices=True) self.assertEqual(len(res.matrices), 1) obs = res.matrices[0] exp = np.array([[ 0, 0, 0, 0, 0, 0, 0], [ 0, -1, 1, -1, -1, -1, -1], [ 0, 1, -1, 2, 0, -2, -2], [ 0, 1, 0, 0, 1, -1, -3], [ 0, -1, 0, -1, 1, 0, 0], [ 0, -1, -2, -1, 0, 0, 1], [ 0, -1, -2, -3, -2, 1, -1]]) npt.assert_array_equal(obs, exp) # Disable free ends. This is the true global alignment (i.e, the Needleman- # Wunsch algorithm in textbooks). res = pair_align(seq1, seq2, mode="global", free_ends=False) obs = res.paths[0].to_aligned((seq1, seq2)) exp = ["GAATTC", "AGATCT"] self.assertListEqual(obs, exp) self.assertEqual(res.score, -2) # Local alignment (i.e., the Smith-Waterman algorithm in textbooks). It gets # subsequences that are best aligned. res = pair_align(seq1, seq2, mode="local") obs = res.paths[0].to_aligned((seq1, seq2)) exp = ["GA", "GA"] self.assertListEqual(obs, exp) self.assertEqual(res.score, 2) # Return all alignments. res = pair_align(seq1, seq2, mode="local", max_paths=None) self.assertEqual(len(res.paths), 3) obs = res.paths[1].to_aligned((seq1, seq2)) self.assertListEqual(obs, ["AT", "AT"]) obs = res.paths[2].to_aligned((seq1, seq2)) self.assertListEqual(obs, ["TC", "TC"]) # Tweak the parameters: match score = 1, mismatch score = -2, linear gap # penalty = 2.5. These are the default MegaBLAST parameters. res = pair_align(seq1, seq2, sub_score=(1, -2), gap_cost=2.5) # With greater mismatch and gap penalties, the two sequences are not aligned # at all. (Semi-)global alignment returns the unaligned "alignment" anyway. obs = res.paths[0].to_aligned((seq1, seq2)) exp = ["------GAATTC", "AGATCT------"] self.assertListEqual(obs, exp) self.assertEqual(res.score, 0) # Try a different scoring scheme with affine gap penalty: match score = 5, # mismatch score = -4, gap opening penalty = 5, gap extension penalty = 2. # This triggers the Gotoh algorithm. res = pair_align(seq1, seq2, sub_score=(5, -4), gap_cost=(5, 2)) obs = res.paths[0].to_aligned((seq1, seq2)) exp = ["-GAATTC-", "AGA--TCT"] self.assertListEqual(obs, exp) self.assertEqual(res.score, 11) # The scores match = 5 and mismatch = -4 correspond to the standard # nucleotide substitution matrix "NUC.4.4" (a.k.a., DNAfull). We can # specify it and get the same result. res = pair_align(seq1, seq2, sub_score="NUC.4.4", gap_cost=(5, 2)) obs = res.paths[0].to_aligned((seq1, seq2)) self.assertListEqual(obs, exp) # Or load an instance of SubstitutionMatrix. submat = SubstitutionMatrix.by_name("NUC.4.4") res = pair_align(seq1, seq2, sub_score=submat, gap_cost=(5, 2)) obs = res.paths[0].to_aligned((seq1, seq2)) self.assertListEqual(obs, exp) def test_pair_align_demo(self): """Demonstration of very simple cases.""" # perfect match obs = pair_align("ACG", "ACG") self.assertEqual(obs.score, 3) self.assertEqual(obs.paths[0].to_cigar(), "3M") # one mismatch obs = pair_align("ACG", "ATG") self.assertEqual(obs.score, 1) self.assertEqual(obs.paths[0].to_cigar(), "3M") # leading insertion obs = pair_align("CGT", "ACGT") self.assertEqual(obs.score, 3) self.assertEqual(obs.paths[0].to_cigar(), "1I3M") # trailing deletion obs = pair_align("ACGT", "ACG") self.assertEqual(obs.score, 3) self.assertEqual(obs.paths[0].to_cigar(), "3M1D") # overlap obs = pair_align("CGT", "ACGTA") self.assertEqual(obs.score, 3) self.assertEqual(obs.paths[0].to_cigar(), "1I3M1I") # one gap obs = pair_align("CGT", "ACGTA") self.assertEqual(obs.score, 3) self.assertEqual(obs.paths[0].to_cigar(), "1I3M1I") def test_pair_align_prot(self): """Align protein sequences.""" # Nuclear localization signals (NLS') of SV40 (PKKKRKV) (Kalderon et al., # Cell, 1984) and c-Myc (PAAKRVKLD) (Dang & Lee, Mol Cell Biol, 1988). seq1 = Protein("PKKKRKV") seq2 = Protein("PAAKRVKLD") # default BLASTP parameters obs = pair_align(seq1, seq2, sub_score="BLOSUM62", gap_cost=(11, 1)) self.assertEqual(obs.score, 11) self.assertEqual(obs.paths[0].to_cigar(), "7M2I") exp = ["PKKKRKV--", "PAAKRVKLD"] self.assertListEqual(obs.paths[0].to_aligned((seq1, seq2)), exp) # Defensins (a category of antimicrobial peptides) of human (2PM4) and rat # (NP_775421.1). seq1 = Protein("DCYCRIPACIAGEKKYGTCIYQGKLWAFCC") seq2 = Protein("CYCRIGACVSGERLTGACGLNGRIYRLCC") obs = pair_align(seq1, seq2, sub_score="BLOSUM62", gap_cost=(11, 1)) self.assertEqual(obs.score, 97) self.assertEqual(obs.paths[0].to_cigar(), "1D29M") # alternative substitution matrix obs = pair_align(seq1, seq2, sub_score="PAM70", gap_cost=(11, 1)) self.assertEqual(obs.score, 86) self.assertEqual(obs.paths[0].to_cigar(), "1D29M") def test_pair_align_custom(self): """Align custom sequence types.""" # This example is taken from the previous scikit-bio code. class CustomSequence(GrammaredSequence): @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set('^$') @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return '^' @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set('WXYZ') @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return {} seq1 = CustomSequence("WXYZ") seq2 = CustomSequence("WXYYZZ") obs = pair_align(seq1, seq2) self.assertEqual(obs.score, 2) self.assertListEqual(obs.paths[0].to_aligned((seq1, seq2), gap_char="^"), [ "WXYZ^^", "WXYYZZ", ]) obs = pair_align(seq1, seq2, free_ends=False) self.assertEqual(obs.score, 0) self.assertListEqual(obs.paths[0].to_aligned((seq1, seq2), gap_char="^"), [ "WXY^Z^", "WXYYZZ", ]) obs = pair_align(seq1, seq2, mode="local") self.assertEqual(obs.score, 3) self.assertListEqual(obs.paths[0].to_aligned((seq1, seq2), gap_char="^"), [ "WXY", "WXY", ]) # also from the previous scikit-bio code seq1 = CustomSequence("YWXXZZYWXXWYYZWXX") seq2 = CustomSequence("YWWXZZZYWXYZWWX") obs = pair_align(seq1, seq2, mode="local", sub_score=(5, -4), gap_cost=(4.5, 0.5), max_paths=None) self.assertEqual(obs.score, 41) self.assertEqual(len(obs.paths), 5) self.assertEqual( TabularMSA.from_path_seqs(obs.paths[4], [seq1, seq2]), TabularMSA([CustomSequence("WXXZZYWXXWYYZWXX"), CustomSequence("WXZZZYWX^^^YZWWX")])) def test_pair_align_no_grammar(self): """Align Sequence objects that are not GrammaredSequence.""" seq1 = Sequence("GAATTC") seq2 = Sequence("AGATCT") obs = pair_align(seq1, seq2) self.assertEqual(obs.score, 1) self.assertListEqual(obs.paths[0].to_aligned((seq1, seq2)), [ "-GAATTC", "AGATCT-", ]) def test_pair_align_strings(self): """Align raw strings.""" seq1 = "accttgcaaaa" seq2 = "cctgca" obs = pair_align(seq1, seq2, mode="local") self.assertEqual(obs.score, 4) self.assertEqual(obs.paths[0].to_cigar(), "3M1D3M") self.assertListEqual(obs.paths[0].to_aligned((seq1, seq2)), [ "ccttgca", "cct-gca", ]) def test_pair_align_unicode(self): """Align Unicode characters.""" seq1 = "äëïïöëüëö" seq2 = "äïïööüëëö" obs = pair_align(seq1, seq2) self.assertEqual(obs.score, 2) self.assertListEqual(obs.paths[0].to_aligned((seq1, seq2)), [ "äëïïöëüëö-", "ä-ïïööüëëö", ]) def test_pair_align_words(self): """Align sentences of words.""" seq1 = "lorem ipsum sit amet tempor".split() seq2 = "ipsum sit dolor sed eiusmod".split() obs = pair_align(seq1, seq2, mode="local") self.assertEqual(obs.score, 2) self.assertEqual(obs.paths[0].to_cigar(), "2M") npt.assert_array_equal(obs.paths[0].starts, [1, 0]) def test_pair_align_numbers(self): """Align arrays of numbers.""" seq1 = np.array([2, 13, 52, 11, 27, 8, 33, 77, 25]) seq2 = np.array([95, 11, 27, 8, 62, 33, 77, 25, 5]) obs = pair_align(seq1, seq2, mode="local") self.assertEqual(obs.score, 4) self.assertEqual(obs.paths[0].to_cigar(), "3M1I3M") npt.assert_array_equal(obs.paths[0].starts, [3, 1]) def test_pair_align_degen(self): """Align sequences with degenerate codes.""" # This works because "N" has been defined as a wildcard by the DNA class, and # it is also included in the substitution matrix. submat = SubstitutionMatrix.identity("ACGTN", 1, -1) seq1 = DNA("CGGRATCCA") seq2 = DNA("GGAATYCT") obs = pair_align(seq1, seq2, sub_score=submat) self.assertEqual(obs.score, 2) self.assertListEqual(obs.paths[0].to_aligned((seq1, seq2)), [ "CGGRATCCA", "-GGAATYCT", ]) # Won't work if the substitution matrix doesn't contain "N". submat = SubstitutionMatrix.identity("ACGT", 1, -1) msg = "Sequence 1 contain character(s) absent from the substitution matrix." with self.assertRaises(ValueError) as cm: _ = pair_align(seq1, seq2, sub_score=submat) self.assertEqual(str(cm.exception), msg) def test_pair_align_trick_1(self): """Tricky case 1.""" # This example is from Altschul & Erickson, Bull Math Biol, 1986 (Fig. 2), # which showed that the original Gotoh algorithm (1982) could fail in some # situations. Specifically, if the traceback process does not jump between # matrices, it won't be able to distinguish ties between creating a new gap # vs. extending an existing gap. In this example, such a tie happens in cell # (2, 5). This test could be useful during future attempts to improve the # algorithm (e.g., by introducing a traceback matrix). seq1 = DNA("AGT") seq2 = DNA("TGAGTT") obs = pair_align(seq1, seq2, sub_score=(0, -1), gap_cost=(1, 1), free_ends=False, max_paths=None, keep_matrices=True) self.assertEqual(obs.score, -5) self.assertEqual(len(obs.paths), 3) self.assertEqual(obs.paths[0].to_cigar(), "2I3M1I") self.assertEqual(obs.paths[1].to_cigar(), "2M3I1M") self.assertEqual(obs.paths[2].to_cigar(), "2I2M1I1M") npt.assert_array_equal(obs.matrices[0], np.array([ [ 0, -2, -3, -4, -5, -6, -7], [-2, -1, -3, -3, -5, -6, -7], [-3, -3, -1, -3, -3, -5, -6], [-4, -3, -3, -2, -4, -3, -5]])) npt.assert_array_equal(obs.matrices[1][1:, 1:], np.array([ [-4, -3, -4, -5, -6, -7], [-5, -5, -3, -4, -5, -6], [-6, -5, -5, -4, -5, -5]])) npt.assert_array_equal(obs.matrices[2][1:, 1:], np.array([ [-4, -5, -6, -7, -8, -9], [-3, -5, -5, -7, -8, -9], [-4, -3, -5, -5, -7, -8]])) def test_pair_align_trick_2(self): """Tricky case 2.""" # This example is from Flouri et al., BioRxiv, 2015, which stated that the # original Gotoh algorithm (1982) had a mistake in the initialization of the # matrices. Specifically, the insertion and deletion matrices should be # initialized with at least 2 gap_open + k gap_extend. If one does this with # gap_open + k * gap_extend, as the Gotoh paper suggested, this example will # break. obs = pair_align("A", "G", sub_score=(0, -5), gap_cost=(2, 1), free_ends=False) self.assertEqual(obs.score, -5) self.assertEqual(obs.paths[0].to_cigar(), "1M") def test_pair_align_semi(self): """Customization of end gap policy.""" # case 1: search longer seq1 for shorter seq1 seq1 = "TCGA" seq2 = "ATCGAG" # true global: end gaps penalized obs = pair_align(seq1, seq2, free_ends=False) self.assertEqual(obs.score, 0) self.assertEqual(obs.paths[0].to_cigar(), "1I4M1I") # ends completely free obs = pair_align(seq1, seq2, free_ends=True) self.assertEqual(obs.score, 4) self.assertEqual(obs.paths[0].to_cigar(), "1I4M1I") # seq1 free (typical semi-global) obs = pair_align(seq1, seq2, free_ends=(True, False)) self.assertEqual(obs.score, 4) # seq2 free (not helpful here) obs = pair_align(seq1, seq2, free_ends=(False, True)) self.assertEqual(obs.score, 0) # case 2: seq1 can align to either side of seq2 seq1 = "ACGT" seq2 = "ACGTACGT" obs = pair_align(seq1, seq2, free_ends=True, max_paths=None) self.assertEqual(obs.score, 4) self.assertEqual(len(obs.paths), 2) self.assertEqual(obs.paths[0].to_cigar(), "4M4I") self.assertEqual(obs.paths[1].to_cigar(), "4I4M") # force align to left obs = pair_align(seq1, seq2, free_ends=(False, True, False, False), max_paths=None) self.assertEqual(obs.score, 4) path, = obs.paths self.assertEqual(path.to_cigar(), "4M4I") # force align to right obs = pair_align(seq1, seq2, free_ends=(True, False, False, False), max_paths=None) self.assertEqual(obs.score, 4) path, = obs.paths self.assertEqual(path.to_cigar(), "4I4M") # case 3: seqs overlap on either side seq1 = "GAATTC" seq2 = "TTCGAA" obs = pair_align(seq1, seq2, free_ends=True, max_paths=None) path1, path2 = obs.paths self.assertEqual(path1.to_cigar(), "3I3M3D") self.assertEqual(path2.to_cigar(), "3D3M3I") # seq1 left connects seq2 right obs = pair_align(seq1, seq2, free_ends=(True, False, False, True), max_paths=None) path, = obs.paths self.assertEqual(path.to_cigar(), "3I3M3D") # seq1 right connects seq2 left obs = pair_align(seq1, seq2, free_ends=(False, True, True, False), max_paths=None) path, = obs.paths self.assertEqual(path.to_cigar(), "3D3M3I") def test_pair_align_text(self): """Text analysis.""" # edit (Levenshtein) distance txts = ["here", "hear"] obs = pair_align(*txts, sub_score=(0, -1), gap_cost=1, free_ends=False) self.assertEqual(obs.score, -2) self.assertListEqual(obs.paths[0].to_aligned(txts), ["he-re", "hear-"]) # longest common subsequence (LCS) txts = ["strawberry", "stranger"] obs = pair_align(*txts, mode="local", sub_score=(1, -np.inf), gap_cost=0) exp = ["stra--wber", "strang--er"] # LCS is "straer"; gap allowed self.assertListEqual(obs.paths[0].to_aligned(txts), exp) # longest common substring obs = pair_align(*txts, mode="local", sub_score=(1, -np.inf), gap_cost=np.inf) exp = ["stra", "stra"] # "stra"; gap not allowed self.assertListEqual(obs.paths[0].to_aligned(txts), exp) def test_pair_align_trim(self): """Trim free gaps.""" # make match score large such that "AAA" in both sequences alway align scoring = dict(sub_score=(9, -1)) # baseline (-AAA- vs TAAAT) obs = pair_align("AAA", "TAAAT", **scoring) self.assertEqual(obs.paths[0].to_cigar(), "1I3M1I") # trim both ends obs = pair_align("AAA", "TAAAT", **scoring, trim_ends=True) self.assertEqual(obs.paths[0].to_cigar(), "3M") # no free, no trim obs = pair_align("AAA", "TAAAT", **scoring, free_ends=False, trim_ends=True) self.assertEqual(obs.paths[0].to_cigar(), "1I3M1I") # trim seq1 (can trim) obs = pair_align("AAA", "TAAAT", **scoring, free_ends=(True, False), trim_ends=True) self.assertEqual(obs.paths[0].to_cigar(), "3M") # trim seq2 (nothing to trim) obs = pair_align("AAA", "TAAAT", **scoring, free_ends=(False, True), trim_ends=True) self.assertEqual(obs.paths[0].to_cigar(), "1I3M1I") # trim leading gap obs = pair_align("AAA", "TAAAT", **scoring, free_ends=(True, False, False, False), trim_ends=True) self.assertEqual(obs.paths[0].to_cigar(), "3M1I") # no impact obs = pair_align("AAA", "TAAAT", **scoring, free_ends=(True, False, True, False), trim_ends=True) self.assertEqual(obs.paths[0].to_cigar(), "3M1I") # trim trailing gap obs = pair_align("AAA", "TAAAT", **scoring, free_ends=(False, True, False, False), trim_ends=True) self.assertEqual(obs.paths[0].to_cigar(), "1I3M") # no impact obs = pair_align("AAA", "TAAAT", **scoring, free_ends=(False, True, False, True), trim_ends=True) self.assertEqual(obs.paths[0].to_cigar(), "1I3M") def test_pair_align_search(self): """Search for short query in long target.""" obs = pair_align("r", "strawberry", trim_ends=True, max_paths=None).paths self.assertEqual(len(obs), 3) self.assertEqual(obs[0].starts[1], 2) self.assertEqual(obs[1].starts[1], 7) self.assertEqual(obs[2].starts[1], 8) def test_pair_align_64bit(self): """Float64 scoring scheme.""" obs = pair_align("GAATTC", "AGATCT", keep_matrices=True) self.assertEqual(obs.paths[0].to_cigar(), "1I5M1D") self.assertEqual(obs.matrices[0].dtype, np.float32) submat = SubstitutionMatrix.identity("ACGTN", 1, -1, dtype="float64") obs = pair_align("GAATTC", "AGATCT", sub_score=submat, keep_matrices=True) self.assertEqual(obs.paths[0].to_cigar(), "1I5M1D") self.assertEqual(obs.matrices[0].dtype, np.float64) def test_pair_align_edge(self): """Edge cases.""" # distinct sequences: global alignment completely misaligned obs = pair_align("AAA", "TTT", sub_score=(1, -1), gap_cost=2) self.assertEqual(obs.paths[0].to_cigar(), "3I3D") # local alignment returns no path obs = pair_align("AAA", "TTT", mode="local", sub_score=(1, -1), gap_cost=2) self.assertEqual(len(obs.paths), 0) # single character, identical obs = pair_align("A", "A") self.assertEqual(obs.paths[0].to_cigar(), "1M") obs = pair_align("A", "A", free_ends=False) self.assertEqual(obs.paths[0].to_cigar(), "1M") obs = pair_align("A", "A", mode="local") self.assertEqual(obs.paths[0].to_cigar(), "1M") # single character, different obs = pair_align("A", "T") self.assertEqual(obs.paths[0].to_cigar(), "1I1D") obs = pair_align("A", "T", free_ends=False) self.assertEqual(obs.paths[0].to_cigar(), "1M") obs = pair_align("A", "T", mode="local") self.assertEqual(len(obs.paths), 0) # no path returned # gap cost is negative (more favorable than match) obs = pair_align("A", "A", sub_score=(1, -1), gap_cost=-2).paths[0] self.assertEqual(obs.to_cigar(), "1I1D") self.assertListEqual(obs.to_aligned(("A", "A")), ["-A", "A-"]) # mismatch score greater than match score obs = pair_align("ATG", "ATG", sub_score=(1, 2)).paths[0] self.assertEqual(obs.to_cigar(), "1I2M1D") self.assertListEqual(obs.to_aligned(("ATG", "ATG")), ["-ATG", "ATG-"]) # Make sure path length is always <= sum of sequence lengths. The maximum # happens when all characters are misaligned. This check is to make sure # the pre-allocation of path in the trackback functions does not lead to # overflow. seq1, seq2 = "AAAAA", "TTTTT" obs = pair_align(seq1, seq2).paths[0] self.assertEqual(obs.to_cigar(), "5I5D") self.assertLessEqual(obs.lengths.sum(), len(seq1) + len(seq2)) # complete misalignment becomes empty after trimming ends obs = pair_align(seq1, seq2, trim_ends=True).paths[0] self.assertEqual(obs.to_cigar(), "") self.assertListEqual(obs.ranges.tolist(), [[0, 0], [5, 5]]) def test_pair_align_inf(self): """Infinite scores.""" # infinite match score (returned score is also infinite) obs = pair_align("ATG", "ATG", sub_score=(np.inf, 0)) self.assertTrue(np.isposinf(obs.score)) # infinite match score not working (there is no match) obs = pair_align("AT", "GC", sub_score=(np.inf, 0)) self.assertEqual(obs.score, 0) # infinite gap cost (which disables gaps) obs = pair_align("ATT", "GGC", sub_score=(1, -100), gap_cost=np.inf, free_ends=False) self.assertEqual(obs.score, -300) self.assertEqual(obs.paths[0].to_cigar(), "3M") # make sure things don't break obs = pair_align("AT", "A", sub_score=(np.inf, np.inf), gap_cost=(np.inf, np.inf)) self.assertTrue(np.isposinf(obs.score)) def test_pair_align_nan(self): """NaN scores.""" # this is nonsense; just want to make sure things don't break obs = pair_align("AT", "A", sub_score=(np.nan, np.nan), gap_cost=(np.nan, np.nan)) self.assertTrue(np.isnan(obs.score)) def test_pair_align_error(self): """Errors.""" with self.assertRaises(ValueError) as cm: _ = pair_align("", "ATG") self.assertEqual(str(cm.exception), "Sequence 1 has a length of zero.") with self.assertRaises(ValueError) as cm: _ = pair_align("ATG", "") self.assertEqual(str(cm.exception), "Sequence 2 has a length of zero.") with self.assertRaises(ValueError) as cm: _ = pair_align("ACGT", "TCGA", mode="xyz") self.assertEqual(str(cm.exception), "Invalid mode: xyz.") def test_pair_align_real_1(self): # 16S rRNA gene sequences of Escherichia coli and Streptococcus pneumoniae with open(get_data_path("16s.frn"), "r") as fh: seq1, seq2 = skbio.io.read(fh, format="fasta", constructor=DNA) # Perform semi-global alignment using BLASTN's default parameters. obs = pair_align(seq1, seq2, sub_score=(2, -3), gap_cost=(5, 2)) self.assertEqual(obs.score, 1199) # Perform global alignment using EMBOSS needle's default parameters. # Note: the score should be exact because it only involves half-integers. # `assertAlmostEqual` is used here just in case. obs = pair_align(seq1, seq2, sub_score="NUC.4.4", gap_cost=(9.5, 0.5), free_ends=False) self.assertAlmostEqual(obs.score, 4355.5) # Map the 16S rRNA V4 primers (515F and 806R) to the E. coli sequence. Note # that there are degenerate characters in the primer sequences. # Source: https://earthmicrobiome.org/protocols-and-standards/16s/ seq515F = DNA("GTGYCAGCMGCCGCGGTAA") seq806R = DNA("GGACTACNVGGGTWTCTAAT").reverse_complement() # Perform semi-global alignment using BLASTN's default parameters. # There is a unique alignment. obs = pair_align(seq515F, seq1, sub_score=(2, -3), gap_cost=(5, 2), max_paths=10) self.assertEqual(obs.score, 28) self.assertEqual(len(obs.paths), 1) self.assertEqual(obs.paths[0].to_cigar(), "505I19M926I") msa = TabularMSA.from_path_seqs(obs.paths[0], [seq515F, seq1])[:, 500:530] self.assertEqual(str(msa[0]), "-----GTGYCAGCMGCCGCGGTAA------") self.assertEqual(str(msa[1]), "ACTCCGTGCCAGCAGCCGCGGTAATACGGA") obs = pair_align(seq806R, seq1, sub_score=(2, -3), gap_cost=(5, 2), max_paths=10) self.assertEqual(obs.score, 25) self.assertEqual(len(obs.paths), 1) self.assertEqual(obs.paths[0].to_cigar(), "777I20M653I") msa = TabularMSA.from_path_seqs(obs.paths[0], [seq806R, seq1])[:, 770:805] self.assertEqual(str(msa[0]), "-------ATTAGAWACCCBNGTAGTCC--------") self.assertEqual(str(msa[1]), "AAACAGGATTAGATACCCTGGTAGTCCACGCCGTA") # Perform local alignment instead. obs = pair_align(seq515F, seq1, mode="local", sub_score=(2, -3), gap_cost=(5, 2), max_paths=10) self.assertEqual(obs.score, 28) self.assertEqual(len(obs.paths), 1) self.assertEqual(obs.paths[0].to_cigar(), "19M") def test_pair_align_real_2(self): # Insulin sequences of human and mouse with open(get_data_path("insulin.faa"), "r") as fh: seq1, seq2 = skbio.io.read(fh, format="fasta", constructor=Protein) # Perform semi-global alignment using BLASTP's default parameters. obs = pair_align(seq1, seq2, sub_score="BLOSUM62", gap_cost=(11, 1)) self.assertEqual(obs.score, 440) def test_pair_align_nucl_wrap(self): """Nucleotide sequence alignment.""" seq1 = DNA("GATCGTC") seq2 = DNA("ATCGCTC") obs = pair_align_nucl(seq1, seq2) self.assertEqual(obs.score, 5) self.assertEqual(obs.paths[0].to_cigar(), "1D4M1I2M") self.assertListEqual(obs.paths[0].to_aligned((seq1, seq2)), [ "GATCG-TC", "-ATCGCTC"]) kwargs = dict(sub_score="NUC.4.4", gap_cost=7) obs = pair_align_nucl(seq1, seq2, **kwargs) self.assertEqual(obs.score, 23) def test_pair_align_prot_wrap(self): """Protein sequence alignment.""" seq1 = Protein("PKKKRKV") seq2 = Protein("PAAKRVKLD") obs = pair_align_prot(seq1, seq2) self.assertEqual(obs.score, 11) self.assertEqual(obs.paths[0].to_cigar(), "7M2I") self.assertListEqual(obs.paths[0].to_aligned((seq1, seq2)), [ "PKKKRKV--", "PAAKRVKLD"]) kwargs = dict(sub_score="PAM70", gap_cost=6) obs = pair_align_prot(seq1, seq2, **kwargs) self.assertEqual(obs.score, 13) def test_prep_free_ends(self): obs = _prep_free_ends(local=True, free_ends=True, trim_ends=False) self.assertTupleEqual(obs, (2, 2, 2, 2)) obs = _prep_free_ends(local=False, free_ends=False, trim_ends=False) self.assertTupleEqual(obs, (0, 0, 0, 0)) obs = _prep_free_ends(local=False, free_ends=True, trim_ends=False) self.assertTupleEqual(obs, (1, 1, 1, 1)) obs = _prep_free_ends(local=False, free_ends=True, trim_ends=True) self.assertTupleEqual(obs, (2, 2, 2, 2)) obs = _prep_free_ends(local=False, free_ends=(True, False), trim_ends=False) self.assertTupleEqual(obs, (1, 1, 0, 0)) obs = _prep_free_ends(local=False, free_ends=(True, False), trim_ends=True) self.assertTupleEqual(obs, (2, 2, 0, 0)) obs = _prep_free_ends( local=False, free_ends=(True, False, False, True), trim_ends=True) self.assertTupleEqual(obs, (2, 0, 0, 2)) obs = _prep_free_ends( local=False, free_ends=(True, False, True, False), trim_ends=False) self.assertTupleEqual(obs, (1, 0, 1, 0)) # non-Boolean inputs obs = _prep_free_ends(local=False, free_ends=(0, 1, 2, 3), trim_ends="yes") self.assertTupleEqual(obs, (0, 2, 2, 2)) msg = "`free_ends` must be one, two or four Booleans." with self.assertRaises(ValueError) as cm: _ = _prep_free_ends(local=False, free_ends=(1, 2, 3), trim_ends=False) self.assertEqual(str(cm.exception), msg) def test_alloc_matrices(self): # linear obs = _alloc_matrices(3, 4, affine=False) self.assertEqual(len(obs), 1) self.assertTrue(isinstance(obs[0], np.ndarray)) self.assertTupleEqual(obs[0].shape, (4, 5)) self.assertEqual(obs[0].dtype, np.float32) # ensure matrix is C-contiguous self.assertTrue(obs[0].flags.c_contiguous) # affine obs = _alloc_matrices(3, 4, affine=True, dtype=np.float32) self.assertEqual(len(obs), 3) for mat in obs: self.assertTupleEqual(mat.shape, (4, 5)) self.assertEqual(mat.dtype, np.float32) # float64 obs = _alloc_matrices(3, 4, affine=False, dtype=np.float64) self.assertEqual(obs[0].dtype, np.float64) def test_init_matrices(self): # classic global alignment obs = _alloc_matrices(3, 4, affine=False) _init_matrices(obs, 0, 2, local=False, lead1=False, lead2=False) npt.assert_array_equal(obs[0][:, 0], [0, -2, -4, -6]) npt.assert_array_equal(obs[0][0, :], [0, -2, -4, -6, -8]) # local alignment obs = _alloc_matrices(3, 4, affine=False) _init_matrices(obs, 0, 2, local=True, lead1=False, lead2=False) self.assertTrue((obs[0][:, 0] == 0).all()) self.assertTrue((obs[0][0, :] == 0).all()) # semi-global alignment (free ends) obs = _alloc_matrices(3, 4, affine=False) _init_matrices(obs, 0, 2, local=False, lead1=True, lead2=True) self.assertTrue((obs[0][:, 0] == 0).all()) self.assertTrue((obs[0][0, :] == 0).all()) # free end for seq1 obs = _alloc_matrices(3, 4, affine=False) _init_matrices(obs, 0, 2, local=False, lead1=True, lead2=False) npt.assert_array_equal(obs[0][:, 0], [0, -2, -4, -6]) self.assertTrue((obs[0][0, :] == 0).all()) # free end for seq2 obs = _alloc_matrices(3, 4, affine=False) _init_matrices(obs, 0, 2, local=False, lead1=False, lead2=True) self.assertTrue((obs[0][:, 0] == 0).all()) npt.assert_array_equal(obs[0][0, :], [0, -2, -4, -6, -8]) # affine and global obs = _alloc_matrices(3, 4, affine=True) _init_matrices(obs, 5, 2, local=False, lead1=False, lead2=False) npt.assert_array_equal(obs[0][:, 0], [0, -7, -9, -11]) npt.assert_array_equal(obs[0][0, :], [0, -7, -9, -11, -13]) self.assertTrue(np.isneginf(obs[1][1:, 0]).all()) self.assertTrue(np.isneginf(obs[2][0, 1:]).all()) # affine and local obs = _alloc_matrices(3, 4, affine=True) _init_matrices(obs, 5, 2, local=True, lead1=False, lead2=False) self.assertTrue((obs[0][:, 0] == 0).all()) self.assertTrue((obs[0][0, :] == 0).all()) self.assertTrue(np.isneginf(obs[1][1:, 0]).all()) self.assertTrue(np.isneginf(obs[2][0, 1:]).all()) def test_fill_linear_matrix(self): seq1 = DNA("ACGT") seq2 = DNA("AACTG") (seq1, seq2), submat, _ = encode_sequences((seq1, seq2), (1, -1)) query, target = np.ascontiguousarray(submat[seq1]), seq2 dtype=query.dtype.type m, n = seq1.size, seq2.size # global obs = _alloc_matrices(m, n, False, dtype=dtype) _init_matrices(obs, 0, 2, local=False, lead1=False, lead2=False) _fill_linear_matrix(obs[0], query, target, 2, local=False) exp = np.array([[ 0, -2, -4, -6, -8, -10], [ -2, 1, -1, -3, -5, -7], [ -4, -1, 0, 0, -2, -4], [ -6, -3, -2, -1, -1, -1], [ -8, -5, -4, -3, 0, -2]]) npt.assert_array_equal(obs[0], exp) # local obs = _alloc_matrices(m, n, False, dtype=dtype) _init_matrices(obs, 0, 2, local=True, lead1=False, lead2=False) _fill_linear_matrix(obs[0], query, target, 2, local=True) exp = np.array([[0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0], [0, 0, 0, 2, 0, 0], [0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 1, 0]]) npt.assert_array_equal(obs[0], exp) # semi-global obs = _alloc_matrices(m, n, False, dtype=dtype) _init_matrices(obs, 0, 2, local=False, lead1=True, lead2=True) _fill_linear_matrix(obs[0], query, target, 2, local=False) exp = np.array([[ 0, 0, 0, 0, 0, 0], [ 0, 1, 1, -1, -1, -1], [ 0, -1, 0, 2, 0, -2], [ 0, -1, -2, 0, 1, 1], [ 0, -1, -2, -2, 1, 0]]) npt.assert_array_equal(obs[0], exp) def test_fill_affine_matrices(self): seq1 = DNA("ACGT") seq2 = DNA("AACTG") (seq1, seq2), submat, _ = encode_sequences((seq1, seq2), (1, -1)) query, target = np.ascontiguousarray(submat[seq1]), seq2 dtype=query.dtype.type m, n = seq1.size, seq2.size # global obs = _alloc_matrices(m, n, True, dtype=dtype) _init_matrices(obs, 3, 1, local=False, lead1=False, lead2=False) _fill_affine_matrices(*obs, query, target, 3, 1, local=False) exp0 = np.array([[ 0, -4, -5, -6, -7, -8], [-4, 1, -3, -4, -5, -6], [-5, -3, 0, -2, -5, -6], [-6, -4, -4, -1, -3, -4], [-7, -5, -5, -5, 0, -4]]) npt.assert_array_equal(obs[0], exp0) exp1 = np.array([[ -8, -3, -4, -5, -6], [ -9, -7, -4, -5, -6], [-10, -8, -8, -5, -6], [-11, -9, -9, -9, -4]]) npt.assert_array_equal(obs[1][1:, 1:], exp1) exp2 = np.array([[ -8, -9, -10, -11, -12], [ -3, -7, -8, -9, -10], [ -4, -4, -6, -9, -10], [ -5, -5, -5, -7, -8]]) npt.assert_array_equal(obs[2][1:, 1:], exp2) # local obs = _alloc_matrices(m, n, True, dtype=dtype) _init_matrices(obs, 3, 1, local=True, lead1=False, lead2=False) _fill_affine_matrices(*obs, query, target, 3, 1, local=True) exp0 = np.array([[0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0], [0, 0, 0, 2, 0, 0], [0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 1, 0]]) npt.assert_array_equal(obs[0], exp0) exp1 = np.array([[-4, -3, -3, -4, -4], [-4, -4, -4, -2, -3], [-4, -4, -4, -4, -3], [-4, -4, -4, -4, -3]]) npt.assert_array_equal(obs[1][1:, 1:], exp1) exp2 = np.array([[-4, -4, -4, -4, -4], [-3, -3, -4, -4, -4], [-4, -4, -2, -4, -4], [-4, -4, -3, -3, -3]]) npt.assert_array_equal(obs[2][1:, 1:], exp2) # semi-global obs = _alloc_matrices(m, n, True, dtype=dtype) _init_matrices(obs, 3, 1, local=False, lead1=True, lead2=True) _fill_affine_matrices(*obs, query, target, 3, 1, local=False) exp0 = np.array([[ 0, 0, 0, 0, 0, 0], [ 0, 1, 1, -1, -1, -1], [ 0, -1, 0, 2, -2, -2], [ 0, -1, -2, -1, 1, -1], [ 0, -1, -2, -3, 0, 0]]) npt.assert_array_equal(obs[0], exp0) exp1 = np.array([[-4, -3, -3, -4, -5], [-4, -5, -4, -2, -3], [-4, -5, -6, -5, -3], [-4, -5, -6, -7, -4]]) npt.assert_array_equal(obs[1][1:, 1:], exp1) exp2 = np.array([[-4, -4, -4, -4, -4], [-3, -3, -5, -5, -5], [-4, -4, -2, -6, -6], [-5, -5, -3, -3, -5]]) npt.assert_array_equal(obs[2][1:, 1:], exp2) def test_one_stop(self): # ACGT vs AACTG, sub=(1, -1), gap=2, same below, unless otherwise stated # global (bottom-right corner) scomat = np.array([[ 0, -2, -4, -6, -8, -10], [ -2, 1, -1, -3, -5, -7], [ -4, -1, 0, 0, -2, -4], [ -6, -3, -2, -1, -1, -1], [ -8, -5, -4, -3, 0, -2]]) obs = _one_stop(scomat, local=False, trail1=False, trail2=False) self.assertEqual(obs[0], -2) npt.assert_array_equal(obs[1], [[4, 5]]) # local (maximum in the matrix) scomat = np.array([[0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0], [0, 0, 0, 2, 0, 0], [0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 1, 0]]) obs = _one_stop(scomat, local=True, trail1=False, trail2=False) self.assertEqual(obs[0], 2) npt.assert_array_equal(obs[1], [[2, 3]]) # local, tie (will pick the smaller index) scomat = np.array([[0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 2, 0, 1], [0, 1, 0, 0, 1, 0], [0, 0, 2, 0, 0, 0]]) obs = _one_stop(scomat, local=True, trail1=False, trail2=False) self.assertEqual(obs[0], 2) npt.assert_array_equal(obs[1], [[2, 3]]) # semi-global (maximum in bottom row) scomat = np.array([[ 0, 0, 0, 0, 0, 0, 0], [ 0, -1, 1, -1, -1, -1, -1], [ 0, -1, -2, 2, -2, -2, -2], [ 0, -1, -2, -2, 3, -1, -1], [ 0, 1, -2, -3, -1, 4, 0]]) obs = _one_stop(scomat, local=False, trail1=True, trail2=True) self.assertEqual(obs[0], 4) npt.assert_array_equal(obs[1], [[4, 5]]) # bottom row only obs = _one_stop(scomat, local=False, trail1=True, trail2=False) self.assertEqual(obs[0], 4) npt.assert_array_equal(obs[1], [[4, 5]]) # right-most column only obs = _one_stop(scomat, local=False, trail1=False, trail2=True) self.assertEqual(obs[0], 0) npt.assert_array_equal(obs[1], [[0, 6]]) # transpose and maximum in right-most column scomat = np.ascontiguousarray(scomat.T) obs = _one_stop(scomat, local=False, trail1=True, trail2=True) self.assertEqual(obs[0], 4) npt.assert_array_equal(obs[1], [[5, 4]]) # semi-global, tie scomat = np.array([[ 0, 0, 0, 0, 0, 0], [ 0, 1, 1, -1, -1, -1], [ 0, -1, 0, 2, 0, -2], [ 0, -1, -2, 0, 1, 1], [ 0, -1, -2, -2, 1, 0]]) obs = _one_stop(scomat, local=False, trail1=True, trail2=True) self.assertEqual(obs[0], 1) npt.assert_array_equal(obs[1], [[3, 5]]) def test_all_stops(self): # ACGT vs AACTG, sub=(1, -1), gap=2, same below, unless otherwise stated # global (always unique) scomat = np.array([[ 0, -2, -4, -6, -8, -10], [ -2, 1, -1, -3, -5, -7], [ -4, -1, 0, 0, -2, -4], [ -6, -3, -2, -1, -1, -1], [ -8, -5, -4, -3, 0, -2]]) obs = _all_stops(scomat, local=False, trail1=False, trail2=False) self.assertEqual(obs[0], -2) npt.assert_array_equal(obs[1], [[4, 5]]) # local, unique scomat = np.array([[0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0], [0, 0, 0, 2, 0, 0], [0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 1, 0]]) obs = _all_stops(scomat, local=True, trail1=False, trail2=False) self.assertEqual(obs[0], 2) npt.assert_array_equal(obs[1], [[2, 3]]) # local, tie (CGTC vs. TCGAG) scomat = np.array([[0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 2, 0, 1], [0, 1, 0, 0, 1, 0], [0, 0, 2, 0, 0, 0]]) obs = _all_stops(scomat, local=True, trail1=False, trail2=False) self.assertEqual(obs[0], 2) npt.assert_array_equal(obs[1], [[2, 3], [4, 2]]) # exact comparison obs = _all_stops(scomat, local=True, trail1=False, trail2=False, eps=None) self.assertEqual(obs[0], 2) npt.assert_array_equal(obs[1], [[2, 3], [4, 2]]) # semi-global, unique (TCGA vs. ATCGAG) scomat = np.array([[ 0, 0, 0, 0, 0, 0, 0], [ 0, -1, 1, -1, -1, -1, -1], [ 0, -1, -2, 2, -2, -2, -2], [ 0, -1, -2, -2, 3, -1, -1], [ 0, 1, -2, -3, -1, 4, 0]]) obs = _all_stops(scomat, local=False, trail1=True, trail2=True) self.assertEqual(obs[0], 4) npt.assert_array_equal(obs[1], [[4, 5]]) # semi-global, tie scomat = np.array([[ 0, 0, 0, 0, 0, 0], [ 0, 1, 1, -1, -1, -1], [ 0, -1, 0, 2, 0, -2], [ 0, -1, -2, 0, 1, 1], [ 0, -1, -2, -2, 1, 0]]) obs = _all_stops(scomat, local=False, trail1=True, trail2=True) self.assertEqual(obs[0], 1) npt.assert_array_equal(obs[1], [[3, 5], [4, 4]]) # bottom row only obs = _all_stops(scomat, local=False, trail1=True, trail2=False) self.assertEqual(obs[0], 1) npt.assert_array_equal(obs[1], [[4, 4]]) # right-most column only obs = _all_stops(scomat, local=False, trail1=False, trail2=True) self.assertEqual(obs[0], 1) npt.assert_array_equal(obs[1], [[3, 5]]) # exact comparison obs = _all_stops(scomat, local=False, trail1=True, trail2=True, eps=None) self.assertEqual(obs[0], 1) npt.assert_array_equal(obs[1], [[3, 5], [4, 4]]) # ensure ascending order scomat = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 1], [0, 0, 0, 0, 1], [0, 0, 1, 1, 1]]) obs = _all_stops(scomat, local=False, trail1=True, trail2=True) self.assertEqual(obs[0], 1) npt.assert_array_equal(obs[1], [[1, 4], [2, 4], [3, 2], [3, 3], [3, 4]]) def test_traceback_one(self): # ACTCA vs CAGAG, sub=(1, -1), gap=2 (linear) # global: unique path, bottom-right corner to left-most column scomat = np.array([[ 0, -2, -4, -6, -8, -10], [ -2, -1, -1, -3, -5, -7], [ -4, -1, -2, -2, -4, -6], [ -6, -3, -2, -3, -3, -5], [ -8, -5, -4, -3, -4, -4], [-10, -7, -4, -5, -2, -4]], dtype=float) obs = _traceback_one(5, 5, (scomat,), 0., 2.) self.assertEqual(obs.to_cigar(), "1D4M1I") # transpose: bottom-right corner to top row scomat = np.ascontiguousarray(scomat.T) obs = _traceback_one(5, 5, (scomat,), 0., 2.) self.assertEqual(obs.to_cigar(), "1I4M1D") # semi-global: unique path, bottom row to left-most column scomat = np.array([[ 0, 0, 0, 0, 0, 0], [ 0, -1, 1, -1, 1, -1], [ 0, 1, -1, 0, -1, 0], [ 0, -1, 0, -2, -1, -2], [ 0, 1, -1, -1, -3, -2], [ 0, -1, 2, 0, 0, -2]], dtype=float) obs = _traceback_one(5, 2, (scomat,), 0., 2.) self.assertEqual(obs.to_cigar(), "3D2M3I") # transpose: right-most column to top row scomat = np.ascontiguousarray(scomat.T) obs = _traceback_one(2, 5, (scomat,), 0., 2.) self.assertEqual(obs.to_cigar(), "3I2M3D") # local: unique path, bottom row to left-most column scomat = np.array([[0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 2, 0, 1, 0]], dtype=float) obs = _traceback_one(5, 2, (scomat,), 0., 2., True, 2, 2, 2, 2) self.assertEqual(obs.to_cigar(), "2M") npt.assert_array_equal(obs.starts, [3, 0]) # transpose: right-most column to top row scomat = np.ascontiguousarray(scomat.T) obs = _traceback_one(2, 5, (scomat,), 0., 2., True, 2, 2, 2, 2) self.assertEqual(obs.to_cigar(), "2M") npt.assert_array_equal(obs.starts, [0, 3]) # GATCA vs CTTC, sub=(1, -1), gap=2 (linear) # local: unique path, right-most column to middle of the matrix scomat = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 1, 0, 0, 2], [0, 0, 0, 0, 0]], dtype=float) obs = _traceback_one(4, 4, (scomat,), 0., 2., True, 2, 2, 2, 2) self.assertEqual(obs.to_cigar(), "2M") npt.assert_array_equal(obs.starts, [2, 2]) # ACGT vs AACTG, sub=(1, -1), gap=2, global # multiple paths: algorithm favors D > I > M in reverse order scomat = np.array([[ 0, -2, -4, -6, -8, -10], [ -2, 1, -1, -3, -5, -7], [ -4, -1, 0, 0, -2, -4], [ -6, -3, -2, -1, -1, -1], [ -8, -5, -4, -3, 0, -2]], dtype=float) obs = _traceback_one(4, 5, (scomat,), 0., 2., local=False) self.assertEqual(obs.to_cigar(), "4M1I") # TAGCATC vs TCAGTC, sub=(2, -1), gap=(3, 1) (affine), global # involves tie, gap opening, gap extension NAN, INF = np.nan, -np.inf scomat = np.array([[ 0, -4, -5, -6, -7, -8, -9], [ -4, 2, -2, -3, -4, -5, -6], [ -5, -2, 1, 0, -4, -5, -6], [ -6, -3, -3, 0, 2, -2, -3], [ -7, -4, -1, -4, -1, 1, 0], [ -8, -5, -5, 1, -3, -2, 0], [ -9, -6, -6, -3, 0, -1, -3], [-10, -7, -4, -4, -4, -1, 1]], dtype=float) insmat = np.array([[NAN, NAN, NAN, NAN, NAN, NAN, NAN], [INF, -8, -2, -3, -4, -5, -6], [INF, -9, -6, -3, -4, -5, -6], [INF, -10, -7, -7, -4, -2, -3], [INF, -11, -8, -5, -6, -5, -3], [INF, -12, -9, -9, -3, -4, -5], [INF, -13, -10, -10, -7, -4, -5], [INF, -14, -11, -8, -8, -8, -5]], dtype=float) delmat = np.array([[NAN, INF, INF, INF, INF, INF, INF], [NAN, -8, -9, -10, -11, -12, -13], [NAN, -2, -6, -7, -8, -9, -10], [NAN, -3, -3, -4, -8, -9, -10], [NAN, -4, -4, -4, -2, -6, -7], [NAN, -5, -5, -5, -3, -3, -4], [NAN, -6, -6, -3, -4, -4, -4], [NAN, -7, -7, -4, -4, -5, -5]], dtype=float) matrices = (scomat, insmat, delmat) obs = _traceback_one(7, 6, matrices, 3., 1.) self.assertEqual(obs.to_cigar(), "1M1I2M2D2M") # transpose (needs to transpose all 3 matrices and shuffle the latter 2) scomat = np.ascontiguousarray(scomat.T) insmat = np.ascontiguousarray(insmat.T) delmat = np.ascontiguousarray(delmat.T) matrices = (scomat, delmat, insmat) obs = _traceback_one(6, 7, matrices, 3., 1.) self.assertEqual(obs.to_cigar(), "1M2I2M1D2M") # GTCGG vs ATCGA, sub=(2, -1), gap=(3, 1), local # starts from middle, ends in middle of the matrix scomat = np.array([[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 2, 0], [0, 0, 2, 0, 0, 1], [0, 0, 0, 4, 0, 0], [0, 0, 0, 0, 6, 2], [0, 0, 0, 0, 2, 5]], dtype=float) insmat = np.array([[NAN, NAN, NAN, NAN, NAN, NAN], [INF, -4, -4, -4, -4, -2], [INF, -4, -4, -2, -3, -4], [INF, -4, -4, -4, 0, -1], [INF, -4, -4, -4, -4, 2], [INF, -4, -4, -4, -4, -2]], dtype=float) delmat = np.array([[NAN, INF, INF, INF, INF, INF], [NAN, -4, -4, -4, -4, -4], [NAN, -4, -4, -4, -2, -4], [NAN, -4, -2, -4, -3, -3], [NAN, -4, -3, 0, -4, -4], [NAN, -4, -4, -1, 2, -2]], dtype=float) matrices = (scomat, insmat, delmat) obs = _traceback_one(4, 4, matrices, 3., 1., True, 2, 2, 2, 2) self.assertEqual(obs.to_cigar(), "3M") # floating-point tolerance scomat = np.array([[0, -2], [-2, -4]], dtype=float) args = (1, 1, (scomat,), 0., 2.,) self.assertEqual(_traceback_one(*args).to_cigar(), "1I1D") scomat[0, 1] = -2.0000000001 self.assertEqual(_traceback_one(*args).to_cigar(), "1I1D") scomat[0, 1] = -2.0001 self.assertEqual(_traceback_one(*args).to_cigar(), "1D1I") self.assertEqual(_traceback_one(*args, eps=1.0e-2).to_cigar(), "1I1D") def test_traceback_all(self): # linear, global, one stop, unique path seq1 = DNA("ACTCA") seq2 = DNA("CAGAG") (seq1, seq2), submat, _ = encode_sequences((seq1, seq2), (1, -1)) query, target = np.ascontiguousarray(submat[seq1]), seq2 scomat = np.array([[ 0, -2, -4, -6, -8, -10], [ -2, -1, -1, -3, -5, -7], [ -4, -1, -2, -2, -4, -6], [ -6, -3, -2, -3, -3, -5], [ -8, -5, -4, -3, -4, -4], [-10, -7, -4, -5, -2, -4]]) obs = _traceback_all([[5, 5]], None, (scomat,), query, target, 0, 2) self.assertEqual(len(obs), 1) self.assertEqual(obs[0].to_cigar(), "1D4M1I") # one stop, three paths (ordering: D > I > M in reverse order) seq1 = DNA("ACGT") seq2 = DNA("AACTG") (seq1, seq2), submat, _ = encode_sequences((seq1, seq2), (1, -1)) scomat = np.array([[ 0, -2, -4, -6, -8, -10], [ -2, 1, -1, -3, -5, -7], [ -4, -1, 0, 0, -2, -4], [ -6, -3, -2, -1, -1, -1], [ -8, -5, -4, -3, 0, -2]]) obs = _traceback_all([[4, 5]], None, (scomat,), submat[seq1], seq2, 0, 2) self.assertEqual(len(obs), 3) self.assertEqual(obs[0].to_cigar(), "4M1I") self.assertEqual(obs[1].to_cigar(), "1M1I3M") self.assertEqual(obs[2].to_cigar(), "1I4M") # limit number of paths to return obs = _traceback_all([[4, 5]], 2, (scomat,), submat[seq1], seq2, 0, 2) self.assertEqual(len(obs), 2) self.assertEqual(obs[0].to_cigar(), "4M1I") self.assertEqual(obs[1].to_cigar(), "1M1I3M") obs = _traceback_all([[4, 5]], 1, (scomat,), submat[seq1], seq2, 0, 2) self.assertEqual(len(obs), 1) self.assertEqual(obs[0].to_cigar(), "4M1I") # semi-global, two stops, one path each scomat = np.array([[ 0, 0, 0, 0, 0, 0], [ 0, 1, 1, -1, -1, -1], [ 0, -1, 0, 2, 0, -2], [ 0, -1, -2, 0, 1, 1], [ 0, -1, -2, -2, 1, 0]]) obs = _traceback_all( [[3, 5], [4, 4]], None, (scomat,), submat[seq1], seq2, 0, 2) self.assertEqual(len(obs), 2) self.assertEqual(obs[0].to_cigar(), "1I2M1I1M1D") self.assertEqual(obs[1].to_cigar(), "1I2M1D1M1I") # local, two stops, one path each seq1 = DNA("CGTC") seq2 = DNA("TCGAG") (seq1, seq2), submat, _ = encode_sequences((seq1, seq2), (1, -1)) scomat = np.array([[0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 2, 0, 1], [0, 1, 0, 0, 1, 0], [0, 0, 2, 0, 0, 0]]) obs = _traceback_all([[2, 3], [4, 2]], None, (scomat,), submat[seq1], seq2, 0, 2, True, 2, 2, 2, 2) self.assertEqual(len(obs), 2) self.assertEqual(obs[0].to_cigar(), "2M") self.assertEqual(obs[1].to_cigar(), "2M") # affine, one stop, two paths (involving both opening and extension) seq1 = DNA("TAGCATC") seq2 = DNA("TCAGTC") (seq1, seq2), submat, _ = encode_sequences((seq1, seq2), (2, -1)) NAN, INF = np.nan, -np.inf scomat = np.array([[ 0, -4, -5, -6, -7, -8, -9], [ -4, 2, -2, -3, -4, -5, -6], [ -5, -2, 1, 0, -4, -5, -6], [ -6, -3, -3, 0, 2, -2, -3], [ -7, -4, -1, -4, -1, 1, 0], [ -8, -5, -5, 1, -3, -2, 0], [ -9, -6, -6, -3, 0, -1, -3], [-10, -7, -4, -4, -4, -1, 1]]) insmat = np.array([[NAN, NAN, NAN, NAN, NAN, NAN, NAN], [INF, -8, -2, -3, -4, -5, -6], [INF, -9, -6, -3, -4, -5, -6], [INF, -10, -7, -7, -4, -2, -3], [INF, -11, -8, -5, -6, -5, -3], [INF, -12, -9, -9, -3, -4, -5], [INF, -13, -10, -10, -7, -4, -5], [INF, -14, -11, -8, -8, -8, -5]]) delmat = np.array([[NAN, INF, INF, INF, INF, INF, INF], [NAN, -8, -9, -10, -11, -12, -13], [NAN, -2, -6, -7, -8, -9, -10], [NAN, -3, -3, -4, -8, -9, -10], [NAN, -4, -4, -4, -2, -6, -7], [NAN, -5, -5, -5, -3, -3, -4], [NAN, -6, -6, -3, -4, -4, -4], [NAN, -7, -7, -4, -4, -5, -5]]) matrices = [scomat, insmat, delmat] obs = _traceback_all([[7, 6]], None, matrices, submat[seq1], seq2, 3, 1) self.assertEqual(len(obs), 2) self.assertEqual(obs[0].to_cigar(), "1M1I2M2D2M") self.assertEqual(obs[1].to_cigar(), "1M2D2M1I2M") # transpose submat = np.ascontiguousarray(submat.T) scomat = np.ascontiguousarray(scomat.T) insmat = np.ascontiguousarray(insmat.T) delmat = np.ascontiguousarray(delmat.T) matrices = [scomat, delmat, insmat] obs = _traceback_all([[6, 7]], None, matrices, submat[seq2], seq1, 3, 1) self.assertEqual(len(obs), 2) self.assertEqual(obs[0].to_cigar(), "1M2I2M1D2M") self.assertEqual(obs[1].to_cigar(), "1M1D2M2I2M") # local, unique path, middle to middle seq1 = DNA("GTCGG") seq2 = DNA("ATCGA") (seq1, seq2), submat, _ = encode_sequences((seq1, seq2), (2, -1)) scomat = np.array([[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 2, 0], [0, 0, 2, 0, 0, 1], [0, 0, 0, 4, 0, 0], [0, 0, 0, 0, 6, 2], [0, 0, 0, 0, 2, 5]]) insmat = np.array([[NAN, NAN, NAN, NAN, NAN, NAN], [INF, -4, -4, -4, -4, -2], [INF, -4, -4, -2, -3, -4], [INF, -4, -4, -4, 0, -1], [INF, -4, -4, -4, -4, 2], [INF, -4, -4, -4, -4, -2]]) delmat = np.array([[NAN, INF, INF, INF, INF, INF], [NAN, -4, -4, -4, -4, -4], [NAN, -4, -4, -4, -2, -4], [NAN, -4, -2, -4, -3, -3], [NAN, -4, -3, 0, -4, -4], [NAN, -4, -4, -1, 2, -2]]) matrices = [scomat, insmat, delmat] obs = _traceback_all( [[4, 4]], None, matrices, submat[seq1], seq2, 3, 1, True, 2, 2, 2, 2) self.assertEqual(len(obs), 1) self.assertEqual(obs[0].to_cigar(), "3M") # floating-point tolerance seq1 = DNA("A") seq2 = DNA("A") (seq1, seq2), submat, _ = encode_sequences((seq1, seq2), (2, -1)) scomat = np.array([[1, 5], [5, 3]], dtype=float) args = ([[1, 1]], None, (scomat,), submat[seq1], seq2, 0., 2.) obs = _traceback_all(*args) self.assertEqual(len(obs), 3) for i, exp in enumerate(["1I1D", "1D1I", "1M"]): self.assertEqual(obs[i].to_cigar(), exp) scomat[0, 1] -= 0.00000001 scomat[1, 0] += 0.00000001 obs = _traceback_all(*args) self.assertEqual(len(obs), 3) for i, exp in enumerate(["1I1D", "1D1I", "1M"]): self.assertEqual(obs[i].to_cigar(), exp) scomat[0, 1] -= 0.0001 scomat[1, 0] += 0.0001 obs = _traceback_all(*args) self.assertEqual(len(obs), 1) self.assertEqual(obs[0].to_cigar(), "1M") obs = _traceback_all(*args, eps=1.0e-2) self.assertEqual(len(obs), 3) for i, exp in enumerate(["1I1D", "1D1I", "1M"]): self.assertEqual(obs[i].to_cigar(), exp) if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/test_pairwise.py000066400000000000000000001051121520735541300260360ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import warnings import numpy as np from skbio import Sequence, Protein, DNA, RNA, TabularMSA, SubstitutionMatrix from skbio.alignment import ( global_pairwise_align_protein, local_pairwise_align_protein, global_pairwise_align_nucleotide, local_pairwise_align_nucleotide, local_pairwise_align, global_pairwise_align) from skbio.alignment._pairwise import ( _init_matrices_sw, _init_matrices_nw, _compute_score_and_traceback_matrices, _traceback, _first_largest, _compute_substitution_score) from skbio.sequence import GrammaredSequence from skbio.util import classproperty from skbio.util._decorator import overrides class CustomSequence(GrammaredSequence): @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set('^$') @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return '^' @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set('WXYZ') @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return {} class PairwiseAlignmentTests(TestCase): """ Note: In the high-level tests, the expected results were derived with assistance from the EMBOSS web server: http://www.ebi.ac.uk/Tools/psa/emboss_needle/ http://www.ebi.ac.uk/Tools/psa/emboss_water/ In some cases, placement of non-gap characters surrounded by gap characters are slighly different between scikit-bio and the EMBOSS server. These differences arise from arbitrary implementation differences, and always result in the same score (which tells us that the alignments are equivalent). In cases where the expected results included here differ from those generated by the EMBOSS server, I note the EMBOSS result as a comment below the expected value. """ def setUp(self): """Ignore warnings during tests.""" warnings.simplefilter("ignore") def tearDown(self): """Clear the list of warning filters, so that no filters are active.""" warnings.resetwarnings() # TODO: duplicate of test_global_pairwise_align_custom_alphabet, remove # when nondegenerate_chars is removed def test_global_pairwise_align_custom_alphabet_nondegenerate_chars(self): custom_substitution_matrix = SubstitutionMatrix.identity( sorted(CustomSequence.nondegenerate_chars), 1, -1 ).to_dict() custom_msa, custom_score, custom_start_end = global_pairwise_align( CustomSequence("WXYZ"), CustomSequence("WXYYZZ"), 10.0, 5.0, custom_substitution_matrix) # Expected values computed by running an equivalent alignment using the # DNA alphabet with the following mapping: # # W X Y Z # | | | | # A C G T # self.assertEqual(custom_msa, TabularMSA([CustomSequence('WXYZ^^'), CustomSequence('WXYYZZ')])) self.assertEqual(custom_score, 2.0) self.assertEqual(custom_start_end, [(0, 3), (0, 5)]) def test_global_pairwise_align_custom_alphabet(self): custom_substitution_matrix = SubstitutionMatrix.identity( sorted(CustomSequence.definite_chars), 1, -1 ).to_dict() custom_msa, custom_score, custom_start_end = global_pairwise_align( CustomSequence("WXYZ"), CustomSequence("WXYYZZ"), 10.0, 5.0, custom_substitution_matrix) # Expected values computed by running an equivalent alignment using the # DNA alphabet with the following mapping: # # W X Y Z # | | | | # A C G T # self.assertEqual(custom_msa, TabularMSA([CustomSequence('WXYZ^^'), CustomSequence('WXYYZZ')])) self.assertEqual(custom_score, 2.0) self.assertEqual(custom_start_end, [(0, 3), (0, 5)]) # TODO: duplicate of test_local_pairwise_align_custom_alphabet, remove # when nondegenerate_chars is removed. def test_local_pairwise_align_custom_alphabet_nondegenerate_chars(self): custom_substitution_matrix = SubstitutionMatrix.identity( sorted(CustomSequence.nondegenerate_chars), 5, -4 ).to_dict() custom_msa, custom_score, custom_start_end = local_pairwise_align( CustomSequence("YWXXZZYWXXWYYZWXX"), CustomSequence("YWWXZZZYWXYZWWX"), 5.0, 0.5, custom_substitution_matrix) # Expected values computed by running an equivalent alignment using the # DNA alphabet with the following mapping: # # W X Y Z # | | | | # A C G T # self.assertEqual( custom_msa, TabularMSA([CustomSequence('WXXZZYWXXWYYZWXX'), CustomSequence('WXZZZYWX^^^YZWWX')])) self.assertEqual(custom_score, 41.0) self.assertEqual(custom_start_end, [(1, 16), (2, 14)]) def test_local_pairwise_align_custom_alphabet(self): custom_substitution_matrix = SubstitutionMatrix.identity( sorted(CustomSequence.definite_chars), 5, -4 ).to_dict() custom_msa, custom_score, custom_start_end = local_pairwise_align( CustomSequence("YWXXZZYWXXWYYZWXX"), CustomSequence("YWWXZZZYWXYZWWX"), 5.0, 0.5, custom_substitution_matrix) # Expected values computed by running an equivalent alignment using the # DNA alphabet with the following mapping: # # W X Y Z # | | | | # A C G T # self.assertEqual( custom_msa, TabularMSA([CustomSequence('WXXZZYWXXWYYZWXX'), CustomSequence('WXZZZYWX^^^YZWWX')])) self.assertEqual(custom_score, 41.0) self.assertEqual(custom_start_end, [(1, 16), (2, 14)]) def test_global_pairwise_align_invalid_type(self): with self.assertRaisesRegex(TypeError, r"GrammaredSequence.*" "TabularMSA.*'Sequence'"): global_pairwise_align(DNA('ACGT'), Sequence('ACGT'), 1.0, 1.0, {}) def test_global_pairwise_align_dtype_mismatch(self): with self.assertRaisesRegex(TypeError, r"same dtype: 'DNA' != 'RNA'"): global_pairwise_align(DNA('ACGT'), TabularMSA([RNA('ACGU')]), 1.0, 1.0, {}) with self.assertRaisesRegex(TypeError, r"same dtype: 'DNA' != 'RNA'"): global_pairwise_align(TabularMSA([DNA('ACGT')]), TabularMSA([RNA('ACGU')]), 1.0, 1.0, {}) def test_global_pairwise_align_protein(self): obs_msa, obs_score, obs_start_end = global_pairwise_align_protein( Protein("HEAGAWGHEE"), Protein("PAWHEAE"), gap_open_penalty=10., gap_extend_penalty=5.) self.assertEqual(obs_msa, TabularMSA([Protein("HEAGAWGHEE-"), Protein("---PAW-HEAE")])) self.assertEqual(obs_score, 23.0) self.assertEqual(obs_start_end, [(0, 9), (0, 6)]) # EMBOSS result: P---AW-HEAE obs_msa, obs_score, obs_start_end = global_pairwise_align_protein( Protein("HEAGAWGHEE"), Protein("PAWHEAE"), gap_open_penalty=5., gap_extend_penalty=0.5) self.assertEqual(obs_msa, TabularMSA([Protein("HEAGAWGHE-E"), Protein("---PAW-HEAE")])) self.assertEqual(obs_score, 30.0) self.assertEqual(obs_start_end, [(0, 9), (0, 6)]) # Alternative substitution matrix obs_msa, obs_score, obs_start_end = global_pairwise_align_protein( Protein("HEAGAWGHEE"), Protein("PAWHEAE"), gap_open_penalty=11., gap_extend_penalty=1., substitution_matrix=SubstitutionMatrix.by_name( 'BLOSUM62').to_dict()) self.assertEqual(obs_msa, TabularMSA([Protein("---HEAGAWGHEE"), Protein("PAWHEAE------")])) self.assertEqual(obs_score, 15.0) self.assertEqual(obs_start_end, [(0, 9), (0, 6)]) # Protein sequences with metadata obs_msa, obs_score, obs_start_end = global_pairwise_align_protein( Protein("HEAGAWGHEE", metadata={'id': "s1"}), Protein("PAWHEAE", metadata={'id': "s2"}), gap_open_penalty=10., gap_extend_penalty=5.) self.assertEqual( obs_msa, TabularMSA([Protein("HEAGAWGHEE-", metadata={'id': "s1"}), Protein("---PAW-HEAE", metadata={'id': "s2"})])) self.assertEqual(obs_score, 23.0) self.assertEqual(obs_start_end, [(0, 9), (0, 6)]) # One TabularMSA and one Protein as input obs_msa, obs_score, obs_start_end = global_pairwise_align_protein( TabularMSA([Protein("HEAGAWGHEE", metadata={'id': "s1"})]), Protein("PAWHEAE", metadata={'id': "s2"}), gap_open_penalty=10., gap_extend_penalty=5.) self.assertEqual( obs_msa, TabularMSA([Protein("HEAGAWGHEE-", metadata={'id': "s1"}), Protein("---PAW-HEAE", metadata={'id': "s2"})])) self.assertEqual(obs_score, 23.0) self.assertEqual(obs_start_end, [(0, 9), (0, 6)]) # One single-sequence alignment as input and one double-sequence # alignment as input. Score confirmed manually. obs_msa, obs_score, obs_start_end = global_pairwise_align_protein( TabularMSA([Protein("HEAGAWGHEE", metadata={'id': "s1"}), Protein("HDAGAWGHDE", metadata={'id': "s2"})]), TabularMSA([Protein("PAWHEAE", metadata={'id': "s3"})]), gap_open_penalty=10., gap_extend_penalty=5.) self.assertEqual( obs_msa, TabularMSA([Protein("HEAGAWGHEE-", metadata={'id': "s1"}), Protein("HDAGAWGHDE-", metadata={'id': "s2"}), Protein("---PAW-HEAE", metadata={'id': "s3"})])) self.assertEqual(obs_score, 21.0) self.assertEqual(obs_start_end, [(0, 9), (0, 6)]) # TypeError on invalid input self.assertRaises(TypeError, global_pairwise_align_protein, 42, Protein("HEAGAWGHEE")) self.assertRaises(TypeError, global_pairwise_align_protein, Protein("HEAGAWGHEE"), 42) def test_global_pairwise_align_protein_invalid_dtype(self): with self.assertRaisesRegex(TypeError, r"TabularMSA with Protein dtype.*dtype " "'DNA'"): global_pairwise_align_protein(TabularMSA([Protein('PAW')]), TabularMSA([DNA('ACGT')])) def test_global_pairwise_align_protein_penalize_terminal_gaps(self): obs_msa, obs_score, obs_start_end = global_pairwise_align_protein( Protein("HEAGAWGHEE"), Protein("PAWHEAE"), gap_open_penalty=10., gap_extend_penalty=5., penalize_terminal_gaps=True) self.assertEqual(obs_msa, TabularMSA([Protein("HEAGAWGHEE"), Protein("---PAWHEAE")])) self.assertEqual(obs_score, 1.0) self.assertEqual(obs_start_end, [(0, 9), (0, 6)]) def test_global_pairwise_align_nucleotide_penalize_terminal_gaps(self): # in these tests one sequence is about 3x the length of the other. # we toggle penalize_terminal_gaps to confirm that it results in # different alignments and alignment scores. seq1 = DNA("ACCGTGGACCGTTAGGATTGGACCCAAGGTTG") seq2 = DNA("T"*25 + "ACCGTGGACCGTAGGATTGGACCAAGGTTA" + "A"*25) obs_msa, obs_score, obs_start_end = global_pairwise_align_nucleotide( seq1, seq2, gap_open_penalty=5., gap_extend_penalty=0.5, match_score=5, mismatch_score=-4, penalize_terminal_gaps=False) self.assertEqual( obs_msa, TabularMSA([DNA("-------------------------ACCGTGGACCGTTAGGA" "TTGGACCCAAGGTTG-------------------------"), DNA("TTTTTTTTTTTTTTTTTTTTTTTTTACCGTGGACCGT-AGGA" "TTGGACC-AAGGTTAAAAAAAAAAAAAAAAAAAAAAAAAA")])) self.assertEqual(obs_score, 131.0) obs_msa, obs_score, obs_start_end = global_pairwise_align_nucleotide( seq1, seq2, gap_open_penalty=5., gap_extend_penalty=0.5, match_score=5, mismatch_score=-4, penalize_terminal_gaps=True) self.assertEqual( obs_msa, TabularMSA([DNA("-------------------------ACCGTGGACCGTTAGGA" "TTGGACCCAAGGTT-------------------------G"), DNA("TTTTTTTTTTTTTTTTTTTTTTTTTACCGTGGACCGT-AGGA" "TTGGACC-AAGGTTAAAAAAAAAAAAAAAAAAAAAAAAAA")])) self.assertEqual(obs_score, 97.0) def test_local_pairwise_align_protein(self): obs_msa, obs_score, obs_start_end = local_pairwise_align_protein( Protein("HEAGAWGHEE"), Protein("PAWHEAE"), gap_open_penalty=10., gap_extend_penalty=5.) self.assertEqual(obs_msa, TabularMSA([Protein("AWGHE"), Protein("AW-HE")])) self.assertEqual(obs_score, 26.0) self.assertEqual(obs_start_end, [(4, 8), (1, 4)]) obs_msa, obs_score, obs_start_end = local_pairwise_align_protein( Protein("HEAGAWGHEE"), Protein("PAWHEAE"), gap_open_penalty=5., gap_extend_penalty=0.5) self.assertEqual(obs_msa, TabularMSA([Protein("AWGHE-E"), Protein("AW-HEAE")])) self.assertEqual(obs_score, 32.0) self.assertEqual(obs_start_end, [(4, 9), (1, 6)]) # Protein sequences with metadata obs_msa, obs_score, obs_start_end = local_pairwise_align_protein( Protein("HEAGAWGHEE", metadata={'id': "s1"}), Protein("PAWHEAE", metadata={'id': "s2"}), gap_open_penalty=10., gap_extend_penalty=5.) self.assertEqual( obs_msa, TabularMSA([Protein("AWGHE", metadata={'id': "s1"}), Protein("AW-HE", metadata={'id': "s2"})])) self.assertEqual(obs_score, 26.0) self.assertEqual(obs_start_end, [(4, 8), (1, 4)]) # Fails when either input is passed as a TabularMSA self.assertRaises(TypeError, local_pairwise_align_protein, TabularMSA([Protein("HEAGAWGHEE", metadata={'id': "s1"})]), Protein("PAWHEAE", metadata={'id': "s2"}), gap_open_penalty=10., gap_extend_penalty=5.) self.assertRaises(TypeError, local_pairwise_align_protein, Protein("HEAGAWGHEE", metadata={'id': "s1"}), TabularMSA([Protein("PAWHEAE", metadata={'id': "s2"})]), gap_open_penalty=10., gap_extend_penalty=5.) # TypeError on invalid input self.assertRaises(TypeError, local_pairwise_align_protein, 42, Protein("HEAGAWGHEE")) self.assertRaises(TypeError, local_pairwise_align_protein, Protein("HEAGAWGHEE"), 42) def test_global_pairwise_align_nucleotide(self): obs_msa, obs_score, obs_start_end = global_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC"), DNA("GAACTTTGACGTAAC"), gap_open_penalty=5., gap_extend_penalty=0.5, match_score=5, mismatch_score=-4) self.assertEqual(obs_msa, TabularMSA([DNA("G-ACCTTGACCAGGTACC"), DNA("GAACTTTGAC---GTAAC")])) self.assertEqual(obs_score, 41.0) self.assertEqual(obs_start_end, [(0, 16), (0, 14)]) obs_msa, obs_score, obs_start_end = global_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC"), DNA("GAACTTTGACGTAAC"), gap_open_penalty=10., gap_extend_penalty=0.5, match_score=5, mismatch_score=-4) self.assertEqual(obs_msa, TabularMSA([DNA("-GACCTTGACCAGGTACC"), DNA("GAACTTTGAC---GTAAC")])) self.assertEqual(obs_score, 32.0) self.assertEqual(obs_start_end, [(0, 16), (0, 14)]) # Use a substitution matrix obs_msa, obs_score, obs_start_end = global_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC"), DNA("GAACTTTGACGTAAC"), gap_open_penalty=5., gap_extend_penalty=2., substitution_matrix=SubstitutionMatrix.by_name( 'NUC.4.4').to_dict()) self.assertEqual(obs_msa, TabularMSA([DNA("G-ACCTTGACCAGGTACC"), DNA("GAACTTTGAC---GTAAC")])) self.assertEqual(obs_score, 38.0) self.assertEqual(obs_start_end, [(0, 16), (0, 14)]) # DNA sequences with metadata obs_msa, obs_score, obs_start_end = global_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC", metadata={'id': "s1"}), DNA("GAACTTTGACGTAAC", metadata={'id': "s2"}), gap_open_penalty=10., gap_extend_penalty=0.5, match_score=5, mismatch_score=-4) self.assertEqual( obs_msa, TabularMSA([DNA("-GACCTTGACCAGGTACC", metadata={'id': "s1"}), DNA("GAACTTTGAC---GTAAC", metadata={'id': "s2"})])) self.assertEqual(obs_score, 32.0) self.assertEqual(obs_start_end, [(0, 16), (0, 14)]) # Align one DNA sequence and one TabularMSA, score computed manually obs_msa, obs_score, obs_start_end = global_pairwise_align_nucleotide( TabularMSA([DNA("GACCTTGACCAGGTACC", metadata={'id': "s1"}), DNA("GACCATGACCAGGTACC", metadata={'id': "s2"})]), DNA("GAACTTTGACGTAAC", metadata={'id': "s3"}), gap_open_penalty=10., gap_extend_penalty=0.5, match_score=5, mismatch_score=-4) self.assertEqual( obs_msa, TabularMSA([DNA("-GACCTTGACCAGGTACC", metadata={'id': "s1"}), DNA("-GACCATGACCAGGTACC", metadata={'id': "s2"}), DNA("GAACTTTGAC---GTAAC", metadata={'id': "s3"})])) self.assertEqual(obs_score, 27.5) self.assertEqual(obs_start_end, [(0, 16), (0, 14)]) # TypeError on invalid input self.assertRaises(TypeError, global_pairwise_align_nucleotide, 42, DNA("ACGT")) self.assertRaises(TypeError, global_pairwise_align_nucleotide, DNA("ACGT"), 42) def test_global_pairwise_align_nucleotide_invalid_dtype(self): with self.assertRaisesRegex(TypeError, r"TabularMSA with DNA or RNA dtype.*dtype " "'Protein'"): global_pairwise_align_nucleotide(TabularMSA([DNA('ACGT')]), TabularMSA([Protein('PAW')])) def test_local_pairwise_align_nucleotide(self): obs_msa, obs_score, obs_start_end = local_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC"), DNA("GAACTTTGACGTAAC"), gap_open_penalty=5., gap_extend_penalty=0.5, match_score=5, mismatch_score=-4) self.assertEqual(obs_msa, TabularMSA([DNA("ACCTTGACCAGGTACC"), DNA("ACTTTGAC---GTAAC")])) self.assertEqual(obs_score, 41.0) self.assertEqual(obs_start_end, [(1, 16), (2, 14)]) obs_msa, obs_score, obs_start_end = local_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC"), DNA("GAACTTTGACGTAAC"), gap_open_penalty=10., gap_extend_penalty=5., match_score=5, mismatch_score=-4) self.assertEqual(obs_msa, TabularMSA([DNA("ACCTTGAC"), DNA("ACTTTGAC")])) self.assertEqual(obs_score, 31.0) self.assertEqual(obs_start_end, [(1, 8), (2, 9)]) # DNA sequences with metadata obs_msa, obs_score, obs_start_end = local_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC", metadata={'id': "s1"}), DNA("GAACTTTGACGTAAC", metadata={'id': "s2"}), gap_open_penalty=10., gap_extend_penalty=5., match_score=5, mismatch_score=-4) self.assertEqual( obs_msa, TabularMSA([DNA("ACCTTGAC", metadata={'id': "s1"}), DNA("ACTTTGAC", metadata={'id': "s2"})])) self.assertEqual(obs_score, 31.0) self.assertEqual(obs_start_end, [(1, 8), (2, 9)]) # Fails when either input is passed as a TabularMSA self.assertRaises(TypeError, local_pairwise_align_nucleotide, TabularMSA([DNA("GACCTTGACCAGGTACC", metadata={'id': "s1"})]), DNA("GAACTTTGACGTAAC", metadata={'id': "s2"}), gap_open_penalty=10., gap_extend_penalty=5., match_score=5, mismatch_score=-4) self.assertRaises(TypeError, local_pairwise_align_nucleotide, DNA("GACCTTGACCAGGTACC", metadata={'id': "s1"}), TabularMSA([DNA("GAACTTTGACGTAAC", metadata={'id': "s2"})]), gap_open_penalty=10., gap_extend_penalty=5., match_score=5, mismatch_score=-4) # TypeError on invalid input self.assertRaises(TypeError, local_pairwise_align_nucleotide, 42, DNA("ACGT")) self.assertRaises(TypeError, local_pairwise_align_nucleotide, DNA("ACGT"), 42) def test_nucleotide_aligners_use_substitution_matrices(self): alt_sub = SubstitutionMatrix.identity("ACGTU", 10, -10).to_dict() # alternate substitution matrix yields different alignment (the # aligned sequences and the scores are different) with local alignment msa_no_sub, score_no_sub, start_end_no_sub = \ local_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC"), DNA("GAACTTTGACGTAAC"), gap_open_penalty=10., gap_extend_penalty=5., match_score=5, mismatch_score=-4) msa_alt_sub, score_alt_sub, start_end_alt_sub = \ local_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC"), DNA("GAACTTTGACGTAAC"), gap_open_penalty=10., gap_extend_penalty=5., match_score=5, mismatch_score=-4, substitution_matrix=alt_sub) self.assertNotEqual(msa_no_sub, msa_alt_sub) self.assertNotEqual(score_no_sub, score_alt_sub) self.assertNotEqual(start_end_no_sub, start_end_alt_sub) # alternate substitution matrix yields different alignment (the # aligned sequences and the scores are different) with global alignment msa_no_sub, score_no_sub, start_end_no_sub = \ global_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC"), DNA("GAACTTTGACGTAAC"), gap_open_penalty=10., gap_extend_penalty=5., match_score=5, mismatch_score=-4) msa_alt_sub, score_alt_sub, start_end_alt_sub = \ global_pairwise_align_nucleotide( DNA("GACCTTGACCAGGTACC"), DNA("GAACTTTGACGTAAC"), gap_open_penalty=10., gap_extend_penalty=5., match_score=5, mismatch_score=-4, substitution_matrix=alt_sub) self.assertNotEqual(msa_no_sub, msa_alt_sub) self.assertNotEqual(score_no_sub, score_alt_sub) self.assertEqual(start_end_no_sub, start_end_alt_sub) def test_local_pairwise_align_invalid_type(self): with self.assertRaisesRegex(TypeError, r'GrammaredSequence.*Sequence'): local_pairwise_align(DNA('ACGT'), Sequence('ACGT'), 1.0, 1.0, {}) def test_local_pairwise_align_type_mismatch(self): with self.assertRaisesRegex(TypeError, r"same type: 'DNA' != 'RNA'"): local_pairwise_align(DNA('ACGT'), RNA('ACGU'), 1.0, 1.0, {}) def test_init_matrices_sw(self): expected_score_m = np.zeros((5, 4)) expected_tback_m = [[0, 0, 0, 0], [0, -1, -1, -1], [0, -1, -1, -1], [0, -1, -1, -1], [0, -1, -1, -1]] actual_score_m, actual_tback_m = _init_matrices_sw( TabularMSA([DNA('AAA', metadata={'id': 'id'})]), TabularMSA([DNA('AAAA', metadata={'id': 'id'})]), 5, 2) np.testing.assert_array_equal(actual_score_m, expected_score_m) np.testing.assert_array_equal(actual_tback_m, expected_tback_m) def test_init_matrices_nw(self): expected_score_m = [[0, -5, -7, -9], [-5, 0, 0, 0], [-7, 0, 0, 0], [-9, 0, 0, 0], [-11, 0, 0, 0]] expected_tback_m = [[0, 3, 3, 3], [2, -1, -1, -1], [2, -1, -1, -1], [2, -1, -1, -1], [2, -1, -1, -1]] actual_score_m, actual_tback_m = _init_matrices_nw( TabularMSA([DNA('AAA', metadata={'id': 'id'})]), TabularMSA([DNA('AAAA', metadata={'id': 'id'})]), 5, 2) np.testing.assert_array_equal(actual_score_m, expected_score_m) np.testing.assert_array_equal(actual_tback_m, expected_tback_m) def test_compute_substitution_score(self): # these results were computed manually subs_m = SubstitutionMatrix.identity("ACGTU", 5, -4).to_dict() gap_chars = set('-.') self.assertEqual( _compute_substitution_score(['A'], ['A'], subs_m, 0, gap_chars), 5.0) self.assertEqual( _compute_substitution_score(['A', 'A'], ['A'], subs_m, 0, gap_chars), 5.0) self.assertEqual( _compute_substitution_score(['A', 'C'], ['A'], subs_m, 0, gap_chars), 0.5) self.assertEqual( _compute_substitution_score(['A', 'C'], ['A', 'C'], subs_m, 0, gap_chars), 0.5) self.assertEqual( _compute_substitution_score(['A', 'A'], ['A', '-'], subs_m, 0, gap_chars), 2.5) self.assertEqual( _compute_substitution_score(['A', 'A'], ['A', '-'], subs_m, 1, gap_chars), 3) # alt subs_m subs_m = SubstitutionMatrix.identity("ACGTU", 1, -2).to_dict() self.assertEqual( _compute_substitution_score(['A', 'A'], ['A', '-'], subs_m, 0, gap_chars), 0.5) def test_compute_score_and_traceback_matrices(self): # these results were computed manually expected_score_m = [[0, -5, -7, -9], [-5, 2, -3, -5], [-7, -3, 4, -1], [-9, -5, -1, 6], [-11, -7, -3, 1]] expected_tback_m = [[0, 3, 3, 3], [2, 1, 3, 3], [2, 2, 1, 3], [2, 2, 2, 1], [2, 2, 2, 2]] m = SubstitutionMatrix.identity("ACGTU", 2, -1).to_dict() actual_score_m, actual_tback_m = _compute_score_and_traceback_matrices( TabularMSA([DNA('ACG', metadata={'id': 'id'})]), TabularMSA([DNA('ACGT', metadata={'id': 'id'})]), 5, 2, m) np.testing.assert_array_equal(actual_score_m, expected_score_m) np.testing.assert_array_equal(actual_tback_m, expected_tback_m) # different sequences # these results were computed manually expected_score_m = [[0, -5, -7, -9], [-5, 2, -3, -5], [-7, -3, 4, -1], [-9, -5, -1, 3], [-11, -7, -3, -2]] expected_tback_m = [[0, 3, 3, 3], [2, 1, 3, 3], [2, 2, 1, 3], [2, 2, 2, 1], [2, 2, 2, 1]] m = SubstitutionMatrix.identity("ACGTU", 2, -1).to_dict() actual_score_m, actual_tback_m = _compute_score_and_traceback_matrices( TabularMSA([DNA('ACC', metadata={'id': 'id'})]), TabularMSA([DNA('ACGT', metadata={'id': 'id'})]), 5, 2, m) np.testing.assert_array_equal(actual_score_m, expected_score_m) np.testing.assert_array_equal(actual_tback_m, expected_tback_m) # four sequences provided in two alignments # these results were computed manually expected_score_m = [[0, -5, -7, -9], [-5, 2, -3, -5], [-7, -3, 4, -1], [-9, -5, -1, 3], [-11, -7, -3, -2]] expected_tback_m = [[0, 3, 3, 3], [2, 1, 3, 3], [2, 2, 1, 3], [2, 2, 2, 1], [2, 2, 2, 1]] m = SubstitutionMatrix.identity("ACGTU", 2, -1).to_dict() actual_score_m, actual_tback_m = _compute_score_and_traceback_matrices( TabularMSA([DNA('ACC', metadata={'id': 's1'}), DNA('ACC', metadata={'id': 's2'})]), TabularMSA([DNA('ACGT', metadata={'id': 's3'}), DNA('ACGT', metadata={'id': 's4'})]), 5, 2, m) np.testing.assert_array_equal(actual_score_m, expected_score_m) np.testing.assert_array_equal(actual_tback_m, expected_tback_m) def test_compute_score_and_traceback_matrices_invalid(self): # if the sequence contains a character that is not in the # substitution matrix, an informative error should be raised m = SubstitutionMatrix.identity("ACGTU", 2, -1).to_dict() self.assertRaises(ValueError, _compute_score_and_traceback_matrices, TabularMSA([DNA('AWG', metadata={'id': 'id'})]), TabularMSA([DNA('ACGT', metadata={'id': 'id'})]), 5, 2, m) def test_traceback(self): score_m = [[0, -5, -7, -9], [-5, 2, -3, -5], [-7, -3, 4, -1], [-9, -5, -1, 6], [-11, -7, -3, 1]] score_m = np.array(score_m) tback_m = [[0, 3, 3, 3], [2, 1, 3, 3], [2, 2, 1, 3], [2, 2, 2, 1], [2, 2, 2, 2]] tback_m = np.array(tback_m) # start at bottom-right expected = ([DNA("ACG-", metadata={'id': 'foo'})], [DNA("ACGT", metadata={'id': 'bar'})], 1, 0, 0) actual = _traceback(tback_m, score_m, TabularMSA([DNA('ACG', metadata={'id': 'foo'})]), TabularMSA([DNA('ACGT', metadata={'id': 'bar'})]), 4, 3) self.assertEqual(actual, expected) # four sequences in two alignments score_m = [[0, -5, -7, -9], [-5, 2, -3, -5], [-7, -3, 4, -1], [-9, -5, -1, 6], [-11, -7, -3, 1]] score_m = np.array(score_m) tback_m = [[0, 3, 3, 3], [2, 1, 3, 3], [2, 2, 1, 3], [2, 2, 2, 1], [2, 2, 2, 2]] tback_m = np.array(tback_m) # start at bottom-right expected = ([DNA("ACG-", metadata={'id': 's1'}), DNA("ACG-", metadata={'id': 's2'})], [DNA("ACGT", metadata={'id': 's3'}), DNA("ACGT", metadata={'id': 's4'})], 1, 0, 0) actual = _traceback(tback_m, score_m, TabularMSA([DNA('ACG', metadata={'id': 's1'}), DNA('ACG', metadata={'id': 's2'})]), TabularMSA([DNA('ACGT', metadata={'id': 's3'}), DNA('ACGT', metadata={'id': 's4'})]), 4, 3) self.assertEqual(actual, expected) # start at highest-score expected = ([DNA("ACG", metadata={'id': 'foo'})], [DNA("ACG", metadata={'id': 'bar'})], 6, 0, 0) actual = _traceback(tback_m, score_m, TabularMSA([DNA('ACG', metadata={'id': 'foo'})]), TabularMSA([DNA('ACGT', metadata={'id': 'bar'})]), 3, 3) self.assertEqual(actual, expected) # terminate traceback before top-right tback_m = [[0, 3, 3, 3], [2, 1, 3, 3], [2, 2, 0, 3], [2, 2, 2, 1], [2, 2, 2, 2]] tback_m = np.array(tback_m) expected = ([DNA("G", metadata={'id': 'a'})], [DNA("G", metadata={'id': 'a'})], 6, 2, 2) actual = _traceback(tback_m, score_m, TabularMSA([DNA('ACG', metadata={'id': 'a'})]), TabularMSA([DNA('ACGT', metadata={'id': 'a'})]), 3, 3) self.assertEqual(actual, expected) def test_first_largest(self): input = [(5, 'a'), (5, 'b'), (5, 'c')] self.assertEqual(_first_largest(input), (5, 'a')) input = [(5, 'c'), (5, 'b'), (5, 'a')] self.assertEqual(_first_largest(input), (5, 'c')) input = [(5, 'c'), (6, 'b'), (5, 'a')] self.assertEqual(_first_largest(input), (6, 'b')) # works for more than three entries input = [(5, 'c'), (6, 'b'), (5, 'a'), (7, 'd')] self.assertEqual(_first_largest(input), (7, 'd')) # Note that max([(5, 'a'), (5, 'c')]) == max([(5, 'c'), (5, 'a')]) # but for the purposes needed here, we want the max to be the same # regardless of what the second item in the tuple is. if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/test_path.py000066400000000000000000001024071520735541300251530ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy as np import numpy.testing as npt from skbio.alignment._path import PairAlignPath, AlignPath, _run_length_encode from skbio.alignment import TabularMSA from skbio.sequence import DNA, Protein class TestAlignPath(unittest.TestCase): def setUp(self): self.path1 = AlignPath( lengths=[3, 2, 5, 1, 4, 3, 2], states=[0, 2, 0, 6, 0, 1, 0], starts=[0, 0, 0], ) def test_init(self): # alignment path with 3 sequences, 20 positions and 7 segments data = dict( lengths = np.array([3, 2, 5, 1, 4, 3, 2], dtype=np.intp), states = np.array([[0, 2, 0, 6, 0, 1, 0]], dtype=np.uint8), ranges = np.array([[0, 17], [0, 17], [0, 19]], dtype=np.intp), starts = np.array([0, 0, 0], dtype=np.intp), stops = np.array([17, 17, 19], dtype=np.intp), ) # supply all components as-is (including ranges) obs = AlignPath(data["lengths"], data["states"], ranges=data["ranges"]) for key, value in data.items(): npt.assert_array_equal(getattr(obs, key), value) self.assertTupleEqual(obs.shape, (3, 20)) # confirm that data are not copied self.assertIs(obs.lengths, data["lengths"]) self.assertIs(obs.states, data["states"]) self.assertIs(obs.ranges, data["ranges"]) # confirm that starts and stops are views of ranges self.assertIs(obs.starts.base, data["ranges"]) self.assertIs(obs.stops.base, data["ranges"]) # supply starts instead of ranges, and stops will be calculated obs = AlignPath(data["lengths"], data["states"], starts=data["starts"]) for key, value in data.items(): npt.assert_array_equal(getattr(obs, key), value) self.assertTupleEqual(obs.shape, (3, 20)) self.assertIsNot(obs.ranges, data["ranges"]) # supply stops instead of ranges, and starts will be calculated obs = AlignPath(data["lengths"], data["states"], stops=data["stops"]) for key, value in data.items(): npt.assert_array_equal(getattr(obs, key), value) self.assertTupleEqual(obs.shape, (3, 20)) self.assertIsNot(obs.ranges, data["ranges"]) # supply states as 1-D array, which will be reshaped to 2-D states_1d = np.squeeze(data["states"]).copy() obs = AlignPath(data["lengths"], states_1d, ranges=data["ranges"]) for key, value in data.items(): npt.assert_array_equal(getattr(obs, key), value) self.assertTupleEqual(obs.shape, (3, 20)) # although states was reshaped, it wasn't copied self.assertIs(obs.states.base, states_1d) # supply parameters as plain lists obs = AlignPath(data["lengths"].tolist(), data["states"].tolist(), ranges=data["ranges"].tolist()) for key, value in data.items(): npt.assert_array_equal(getattr(obs, key), value) self.assertTupleEqual(obs.shape, (3, 20)) def test_init_error(self): msg = "`lengths` must be a 1-D array." with self.assertRaises(TypeError) as cm: AlignPath(lengths=[[1, 2, 3]], states=[0, 1, 2], starts=[0, 0]) self.assertEqual(str(cm.exception), msg) msg = "`states` must be a 1-D or 2-D array." with self.assertRaises(TypeError) as cm: AlignPath(lengths=[1, 2, 3], states=[[[]]], starts=[0, 0]) self.assertEqual(str(cm.exception), msg) msg = "Numbers of segments in `lengths` (3) and `states` (4) do not match." with self.assertRaises(ValueError) as cm: AlignPath(lengths=[1, 2, 3], states=[1, 0, 1, 0], starts=[0, 0]) self.assertEqual(str(cm.exception), msg) msg = "`ranges` must be a 2-column array." with self.assertRaises(TypeError) as cm: AlignPath(lengths=[1, 2, 3], states=[0, 1, 2], ranges=[1, 2]) self.assertEqual(str(cm.exception), msg) with self.assertRaises(TypeError) as cm: AlignPath(lengths=[1, 2, 3], states=[0, 1, 2], ranges=[[1, 2, 3]]) self.assertEqual(str(cm.exception), msg) msg = "`starts` must be a 1-D array." with self.assertRaises(TypeError) as cm: AlignPath(lengths=[1, 2, 3], states=[0, 1, 2], starts=[[0], [0]]) self.assertEqual(str(cm.exception), msg) msg = "`stops` must be a 1-D array." with self.assertRaises(TypeError) as cm: AlignPath(lengths=[1, 2, 3], states=[0, 1, 2], stops=[[0], [0]]) self.assertEqual(str(cm.exception), msg) msg = ("Number of sequences in ranges (10) and capacity of states " "(1 to 8) do not match.") with self.assertRaises(ValueError) as cm: AlignPath(lengths=[1, 2, 3], states=[0, 1, 2], starts=[0] * 10) self.assertEqual(str(cm.exception), msg) msg = "`ranges`, `starts` or `stops` must be provided." with self.assertRaises(ValueError) as cm: AlignPath(lengths=[1, 2, 3], states=[0, 1, 2]) self.assertEqual(str(cm.exception), msg) def test_lengths(self): obs = self.path1.lengths npt.assert_array_equal(obs, np.array([3, 2, 5, 1, 4, 3, 2])) def test_states(self): obs = self.path1.states npt.assert_array_equal(obs, np.array([[0, 2, 0, 6, 0, 1, 0]])) def test_ranges(self): obs = self.path1.ranges npt.assert_array_equal(obs, np.array([[0, 17], [0, 17], [0, 19]])) def test_starts(self): obs = self.path1.starts npt.assert_array_equal(obs, np.array([0, 0, 0])) def test_stops(self): obs = self.path1.stops npt.assert_array_equal(obs, np.array([17, 17, 19])) def test_shape(self): obs = self.path1.shape self.assertTupleEqual(obs, (3, 20)) def test_repr(self): obs = repr(self.path1) exp = "" self.assertEqual(obs, exp) def test_to_sizes(self): path = AlignPath(lengths=[3, 2, 5, 1, 4, 3, 2], states=[0, 2, 0, 6, 0, 1, 0], starts=[1, 2, 3]) obs = path._to_sizes() npt.assert_array_equal(obs, [17, 17, 19]) obs = path._to_sizes(2) npt.assert_array_equal(obs, [17, 17]) def test_to_bits(self): path = AlignPath(lengths=[2, 2, 2, 1, 1], states=[0, 2, 0, 6, 0], starts=[0, 0, 0]) # return array of segments obs = path.to_bits(expand=False) exp = np.array([[0, 0, 0, 0, 0], [0, 1, 0, 1, 0], [0, 0, 0, 1, 0]]) npt.assert_array_equal(obs, exp) # return array of positions (default) obs = path.to_bits() exp = np.array([[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1, 0]]) npt.assert_array_equal(obs, exp) # more complex example exp = np.array(([0, 0, 0, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0])) obs = self.path1.to_bits(expand=False) npt.assert_array_equal(obs, exp) # edge case: 0-length alignment path = AlignPath(lengths=[], states=[], starts=[0, 0, 0]) for expand in True, False: exp = path.to_bits(expand=expand) self.assertEqual(exp.size, 0) self.assertTupleEqual(exp.shape, (3, 0)) def test_from_bits(self): # test 1D base case, less than 8 sequences bits = np.array(([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])) exp = self.path1 obs = AlignPath.from_bits(bits) npt.assert_array_equal(obs.lengths, exp.lengths) npt.assert_array_equal(obs.states, exp.states) # test starts parameter starts = [1, 2, 3] obs = AlignPath.from_bits(bits, starts) npt.assert_array_equal(obs.lengths, exp.lengths) npt.assert_array_equal(obs.states, exp.states) npt.assert_array_equal(obs.starts, starts) # test 2D base case, more than 8 sequences rng = np.random.default_rng(seed=42) bits = rng.choice([0, 1], size=(10, 10), p=[0.85, 0.15]) exp = AlignPath(lengths=[1, 1, 1, 1, 1, 1, 3, 1], states=[[0, 10, 133, 4, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 2]], starts=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) obs = AlignPath.from_bits(bits) npt.assert_array_equal(obs.lengths, exp.lengths) npt.assert_array_equal(obs.states, exp.states) def test_to_matrices(self): seqs = ["CGGTCGTAACGCGTACA", "CAGGTAAGCATACCTCA", "CGGTCGTCACTGTACACTA"] seqs = [np.frombuffer(x.encode("ascii"), dtype=np.uint8) for x in seqs] obs = self.path1._to_matrices(seqs, gap_code=45) msa = ('CGGTCGTAACGCGTA---CA', 'CAG--GTAAG-CATACCTCA', 'CGGTCGTCAC-TGTACACTA') exp0 = np.vstack([ np.frombuffer(x.encode("ascii"), dtype=np.uint8) for x in msa]) npt.assert_array_equal(obs[0], exp0) exp1 = exp0 == 45 npt.assert_array_equal(obs[1], exp1) npt.assert_array_equal(obs[2], self.path1._to_bits()) npt.assert_array_equal(obs[3], self.path1._lengths) # no gap code (leave empty) obs = self.path1._to_matrices(seqs, gap_code=None) npt.assert_array_equal( obs[0][0, :6], np.frombuffer("CGGTCG".encode("ascii"), dtype=np.uint8)) msg = "Fewer sequences were provided than in alignment path." seqs = ["CGGTCGTAACGCGTACA", "CAGGTAAGCATACCTCA"] seqs = [np.frombuffer(x.encode("ascii"), dtype=np.uint8) for x in seqs] with self.assertRaises(ValueError) as cm: self.path1._to_matrices(seqs, gap_code=45) self.assertEqual(str(cm.exception), msg) msg = "Some sequences are shorter than in alignment path." seqs = ["AAAAA", "CCCCC", "GGGGG"] seqs = [np.frombuffer(x.encode("ascii"), dtype=np.uint8) for x in seqs] with self.assertRaises(ValueError) as cm: self.path1._to_matrices(seqs, gap_code=45) self.assertEqual(str(cm.exception), msg) def test_from_aligned(self): aln = ["CGGTCGTAACGCGTA---CA", "CAG--GTAAG-CATACCTCA", "CGGTCGTCAC-TGTACACTA"] obs = AlignPath.from_aligned(aln) exp = AlignPath( lengths=[3, 2, 5, 1, 4, 3, 2], states=[0, 2, 0, 6, 0, 1, 0], starts=[0, 0, 0], ) for x in ("lengths", "states", "starts"): npt.assert_array_equal(getattr(obs, x), getattr(exp, x)) aln = list(map(DNA, aln)) obs = AlignPath.from_aligned(aln) for x in ("lengths", "states", "starts"): npt.assert_array_equal(getattr(obs, x), getattr(exp, x)) msa = TabularMSA(aln) obs = AlignPath.from_aligned(msa) for x in ("lengths", "states", "starts"): npt.assert_array_equal(getattr(obs, x), getattr(exp, x)) obs = AlignPath.from_aligned(aln, starts=[1, 2, 3]) exp._ranges[:, 0] = [1, 2, 3] for x in ("lengths", "states", "starts"): npt.assert_array_equal(getattr(obs, x), getattr(exp, x)) # custom gap character aln = ["AAX", "AXA", "XAA"] obs = AlignPath.from_aligned(aln, gap_chars="X") npt.assert_array_equal(obs.lengths, [1, 1, 1]) npt.assert_array_equal(obs.states[0], [4, 2, 1]) # multiple gap characters aln = ["AAX", "AYA", "ZAA"] obs = AlignPath.from_aligned(aln, gap_chars="XYZ") npt.assert_array_equal(obs.lengths, [1, 1, 1]) npt.assert_array_equal(obs.states[0], [4, 2, 1]) # non-string sequences aln = [[1, 2, 3, 0], [1, 0, 4, 5], [2, 0, 2, 3]] obs = AlignPath.from_aligned(aln, gap_chars={0}) npt.assert_array_equal(obs.lengths, [1, 1, 1, 1]) npt.assert_array_equal(obs.states[0], [0, 6, 0, 1]) msg = "Sequence lengths do not match." with self.assertRaises(ValueError) as cm: _ = AlignPath.from_aligned(["A", "AA", "AAA"]) self.assertEqual(str(cm.exception), msg) def test_to_aligned(self): # globally aligned DNA sequences path = AlignPath( lengths=[3, 2, 5, 1, 4, 3, 2], states=[0, 2, 0, 6, 0, 1, 0], starts=[0, 0, 0], ) seqs = [DNA("CGGTCGTAACGCGTACA"), DNA("CAGGTAAGCATACCTCA"), DNA("CGGTCGTCACTGTACACTA")] obs = path.to_aligned(seqs) exp = ["CGGTCGTAACGCGTA---CA", "CAG--GTAAG-CATACCTCA", "CGGTCGTCAC-TGTACACTA"] self.assertListEqual(obs, exp) # custom gap character obs = path.to_aligned(seqs, gap_char=".") exp = ["CGGTCGTAACGCGTA...CA", "CAG..GTAAG.CATACCTCA", "CGGTCGTCAC.TGTACACTA"] self.assertListEqual(obs, exp) # raw strings with flanking regions path.starts[0] = 5 path.starts[1] = 1 seqs = ["XXXXXCGGTCGTAACGCGTACAXXXXXXX", "XCAGGTAAGCATACCTCA", "CGGTCGTCACTGTACACTAXX"] obs = path.to_aligned(seqs, flanking=3) exp = ["XXXCGGTCGTAACGCGTA---CAXXX", " XCAG--GTAAG-CATACCTCA ", " CGGTCGTCAC-TGTACACTAXX "] self.assertListEqual(obs, exp) # locally aligned protein sequences path = AlignPath( lengths=[5, 1, 6], states=[0, 2, 0], starts=[0, 8], ) seqs = [Protein("RQPLTSSERIDK"), Protein("FTEDTTPNRPVYTTSQVGGLITHVLWEIVEMRKELCNGNSD")] obs = path.to_aligned(seqs, flanking=(5, 10)) exp = [" RQPLTSSERIDK ", "DTTPNRPVYT-TSQVGGLITHVLWEIV"] self.assertListEqual(obs, exp) msg = "There are more sequences than in the path." seqs.append(Protein("AKGDATSDKMLFTSPDKTEELIK")) with self.assertRaises(ValueError) as cm: _ = path.to_aligned(seqs, flanking=(5, 10)) self.assertEqual(str(cm.exception), msg) msg = "Sequence 1 is shorter than in the path." seqs = [Protein("RQPLTSSERIDK"), Protein("FTEDTTPNRPVY")] with self.assertRaises(ValueError) as cm: _ = path.to_aligned(seqs, flanking=(5, 10)) self.assertEqual(str(cm.exception), msg) def test_from_tabular(self): msa = ('CGGTCGTAACGCGTA---CA', 'CAG--GTAAG-CATACCTCA', 'CGGTCGTCAC-TGTACACTA') tabular = TabularMSA([DNA(x) for x in msa]) obs = AlignPath.from_tabular(tabular) lengths = [3, 2, 5, 1, 4, 3, 2] states = [0, 2, 0, 6, 0, 1, 0] npt.assert_array_equal(obs.lengths, lengths) npt.assert_array_equal(np.squeeze(obs.states), states) npt.assert_array_equal(obs.starts, [0, 0, 0]) obs = AlignPath.from_tabular(tabular, starts=[1, 2, 3]) npt.assert_array_equal(obs.starts, [1, 2, 3]) def test_to_indices(self): # test gap = -1 path = self.path1 exp = np.array([ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, 15, 16], [0, 1, 2, -1, -1, 3, 4, 5, 6, 7, -1, 8, 9, 10, 11, 12, 13, 14, 15, 16], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18], ]) obs = path.to_indices() npt.assert_array_equal(obs, exp) # test gap = 'del' exp = np.array([[0, 1, 2, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16], [0, 1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 17, 18]]) obs = path.to_indices(gap='del') npt.assert_array_equal(obs, exp) # test gap = 'mask' exp = np.ma.array(data=[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, 14, 14, 15, 16], [0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]], mask=[[False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, True, True, False, False], [False, False, False, True, True, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False], [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False]], fill_value=999999) obs = path.to_indices(gap='mask') npt.assert_array_equal(obs, exp) # test with starts as non-zero path = AlignPath(lengths=[3, 2, 5, 1, 4, 3, 2], states=[0, 2, 0, 6, 0, 1, 0], starts=[1, 35, 28]) exp = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1, -1, -1, 16, 17], [35, 36, 37, -1, -1, 38, 39, 40, 41, 42, -1, 43, 44, 45, 46, 47, 48, 49, 50, 51], [28, 29, 30, 31, 32, 33, 34, 35, 36, 37, -1, 38, 39, 40, 41, 42, 43, 44, 45, 46]]) obs = path.to_indices() npt.assert_array_equal(obs, exp) # test 'del' with non-zero starts exp = np.array([[1, 2, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17], [35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 50, 51], [28, 29, 30, 33, 34, 35, 36, 37, 38, 39, 40, 41, 45, 46]]) obs = path.to_indices(gap='del') npt.assert_array_equal(obs, exp) # test 'mask' with non-zero starts exp = np.ma.array(data=[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 16, 17], [35, 36, 37, 37, 37, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51], [28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46]], mask=[[False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, True, True, False, False], [False, False, False, True, True, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False], [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False]], fill_value=999999) obs = path.to_indices(gap='mask') npt.assert_array_equal(obs, exp) # test invalid gap msg = "Gap must be an integer, 'del', or 'mask'." with self.assertRaises(TypeError) as cm: _ = path.to_indices(gap="no") self.assertEqual(str(cm.exception), msg) with self.assertRaises(TypeError) as cm: _ = path.to_indices(gap=2.5) self.assertEqual(str(cm.exception), msg) def test_from_indices(self): # test no mask indices = np.array([ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, 15, 16], [0, 1, 2, -1, -1, 3, 4, 5, 6, 7, -1, 8, 9, 10, 11, 12, 13, 14, 15, 16], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18], ]) path = AlignPath.from_indices(indices) lengths = [3, 2, 5, 1, 4, 3, 2] states = [0, 2, 0, 6, 0, 1, 0] npt.assert_array_equal(lengths, path.lengths) npt.assert_array_equal(states, np.squeeze(path.states)) # test masked array masked = np.ma.array(indices, mask=(indices == -1)) path = AlignPath.from_indices(masked, gap="mask") npt.assert_array_equal(lengths, path.lengths) npt.assert_array_equal(states, np.squeeze(path.states)) msg = "For masked arrays, gap must be 'mask'." with self.assertRaises(TypeError) as cm: _ = AlignPath.from_indices(masked, gap=-1) self.assertEqual(str(cm.exception), msg) # test non-zero indices indices = np.array([[25, 26, -1, -1, 27, 28, 29, 30], [-1, 79, 80, 81, 82, 83, 84, -1]]) path = AlignPath.from_indices(indices) lengths = [1, 1, 2, 3, 1] states = [2, 0, 1, 0, 2] npt.assert_array_equal(lengths, path.lengths) npt.assert_array_equal(states, np.squeeze(path.states)) npt.assert_array_equal(path.starts, [25, 79]) # test masked array and non-zero indices # TODO # test indices all gaps indices = np.array([[25, 26, -1, -1, 27, 28, 29, 30], [-1, -1, -1, -1, -1, -1, -1, -1]]) path = AlignPath.from_indices(indices) lengths = [2, 2, 4] states = [2, 3, 2] starts = [25, -1] npt.assert_array_equal(path.lengths, lengths) npt.assert_array_equal(np.squeeze(path.states), states) npt.assert_array_equal(path.starts, starts) def test_to_coordinates(self): # test base case exp = np.array([[0, 3, 5, 10, 11, 15, 15, 17], [0, 3, 3, 8, 8, 12, 15, 17], [0, 3, 5, 10, 10, 14, 17, 19]]) path = AlignPath(lengths=[3, 2, 5, 1, 4, 3, 2], states=[0, 2, 0, 6, 0, 1, 0], starts=[0, 0, 0]) obs = path.to_coordinates() npt.assert_array_equal(obs, exp) # test non-zero starts exp = np.array([[2, 5, 7, 12, 13, 17, 17, 19], [512, 515, 515, 520, 520, 524, 527, 529], [28, 31, 33, 38, 38, 42, 45, 47]]) path = AlignPath(lengths=[3, 2, 5, 1, 4, 3, 2], states=[0, 2, 0, 6, 0, 1, 0], starts=[2, 512, 28]) obs = path.to_coordinates() npt.assert_array_equal(obs, exp) def test_from_coordinates(self): # test base case coords = np.array([[0, 3, 5, 10, 11, 15, 15, 17], [0, 3, 3, 8, 8, 12, 15, 17], [0, 3, 5, 10, 10, 14, 17, 19]]) path = AlignPath.from_coordinates(coords) lengths = [3, 2, 5, 1, 4, 3, 2] states = [0, 2, 0, 6, 0, 1, 0] starts = [0, 0, 0] npt.assert_array_equal(lengths, path.lengths) npt.assert_array_equal(states, np.squeeze(path.states)) npt.assert_array_equal(starts, path.starts) # test non-zero starts coords = np.array([[2, 5, 7, 12, 13, 17, 17, 19], [512, 515, 515, 520, 520, 524, 527, 529], [28, 31, 33, 38, 38, 42, 45, 47]]) path = AlignPath.from_coordinates(coords) lengths = [3, 2, 5, 1, 4, 3, 2] states = [0, 2, 0, 6, 0, 1, 0] starts = [2, 512, 28] npt.assert_array_equal(lengths, path.lengths) npt.assert_array_equal(states, np.squeeze(path.states)) npt.assert_array_equal(starts, path.starts) class TestPairAlignPath(unittest.TestCase): def setUp(self): # alignment path with 2 sequences, 20 positions and 7 segments self.path1 = PairAlignPath( lengths=[3, 2, 5, 1, 4, 3, 2], states=[0, 2, 0, 2, 0, 1, 0], starts=[0, 0], ) def test_init(self): # normal case data = dict( lengths = np.array([3, 2, 5, 1, 4, 3, 2], dtype=np.intp), states = np.array([[0, 2, 0, 2, 0, 1, 0]], dtype=np.uint8), ranges = np.array([[0, 17], [0, 17]], dtype=np.intp), starts = np.array([0, 0], dtype=np.intp), stops = np.array([17, 17], dtype=np.intp), ) obs = PairAlignPath(data["lengths"], data["states"], starts=data["starts"]) for key, value in data.items(): npt.assert_array_equal(getattr(obs, key), value) self.assertTupleEqual(obs.shape, (2, 20)) for key in ("lengths", "states"): self.assertIs(getattr(obs, key), data[key]) # supply ranges obs = PairAlignPath(data["lengths"], data["states"], ranges=data["ranges"]) for key, value in data.items(): npt.assert_array_equal(getattr(obs, key), value) self.assertTupleEqual(obs.shape, (2, 20)) for key in ("lengths", "states", "ranges"): self.assertIs(getattr(obs, key), data[key]) # omit starts obs = PairAlignPath(data["lengths"], data["states"]) npt.assert_array_equal(obs.starts, data["starts"]) self.assertTupleEqual(obs.shape, (2, 20)) # more than two sequences msg = ("A pairwise alignment must represent exactly two sequences, " "but %d were given.") with self.assertRaises(ValueError) as cm: PairAlignPath(lengths=[1, 2, 3], states=[0, 1, 2], starts=[0, 0, 0]) self.assertEqual(str(cm.exception), msg % 3) # only one sequence with self.assertRaises(ValueError) as cm: PairAlignPath(lengths=[1], states=[0], starts=[0]) self.assertEqual(str(cm.exception), msg % 1) # invalid bits msg = ("For pairwise alignment, `states` must only contain zeros, ones, " "twos, or threes.") with self.assertRaises(ValueError) as cm: PairAlignPath(lengths=[1, 2, 3], states=[1, 2, 4], starts=[0, 0]) self.assertEqual(str(cm.exception), msg) def test_repr(self): obs = repr(self.path1) exp = "" self.assertEqual(obs, exp) # make a long CIGAR string path = PairAlignPath.from_bits(np.array(( [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0]))) obs = repr(path) exp = ("") self.assertEqual(obs, exp) self.assertEqual(len(obs), 79) # also check `__str__` obs = str(path) self.assertEqual(obs, exp) # make a long number (rare) path._shape = (2, "I_am_a_long_number") exp = ("") obs = repr(path) self.assertEqual(obs, exp) self.assertEqual(len(obs), 79) # an even longer number (rarer) path._shape = (2, "I_am_a_long_number_look_at_me") exp = ("") obs = repr(path) self.assertEqual(obs, exp) self.assertGreater(len(obs), 79) def test_from_bits(self): # test base case bits = np.array(([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])) exp = self.path1 obs = PairAlignPath.from_bits(bits) npt.assert_array_equal(obs.lengths, exp.lengths) npt.assert_array_equal(obs.states, exp.states) # more than two sequences msg = ("A pairwise alignment must represent exactly two sequences, " "but %d were given.") bits = np.array([[0, 0, 1, 1, 0], [1, 0, 1, 0, 0], [0, 1, 1, 0, 1]]) with self.assertRaises(ValueError) as cm: PairAlignPath.from_bits(bits) self.assertEqual(str(cm.exception), msg % 3) # only one sequence bits = np.array([[0, 0, 1, 1, 0]]) with self.assertRaises(ValueError) as cm: PairAlignPath.from_bits(bits) self.assertEqual(str(cm.exception), msg % 1) def test_from_cigar(self): # very simple case cigar = "1I3M2D" path = PairAlignPath.from_cigar(cigar) lengths = [1, 3, 2] states = [1, 0, 2] npt.assert_array_equal(lengths, path.lengths) npt.assert_array_equal(states, np.squeeze(path.states)) # test valid cigar with no = or X cigar = "3M42I270M32D" path = PairAlignPath.from_cigar(cigar) lengths = [3, 42, 270, 32] states = [0, 1, 0, 2] npt.assert_array_equal(lengths, path.lengths) npt.assert_array_equal(states, np.squeeze(path.states)) # test valid cigar with = or X cigar = "3M42I270M23X663=32D24X43=" path = PairAlignPath.from_cigar(cigar) lengths = [3, 42, 956, 32, 67] states = [0, 1, 0, 2, 0] npt.assert_array_equal(lengths, path.lengths) npt.assert_array_equal(states, np.squeeze(path.states)) # test empty cigar string msg = "CIGAR string must not be empty." with self.assertRaises(ValueError) as cm: PairAlignPath.from_cigar("") self.assertEqual(str(cm.exception), msg) # test invalid cigar string msg = "CIGAR string contains invalid character(s)." with self.assertRaises(ValueError) as cm: PairAlignPath.from_cigar("23M45B13X") self.assertEqual(str(cm.exception), msg) # test invalid cigar string msg = "CIGAR string contains invalid character(s)." with self.assertRaises(ValueError) as cm: PairAlignPath.from_cigar("23M45B13X") self.assertEqual(str(cm.exception), msg) with self.assertRaises(ValueError) as cm: PairAlignPath.from_cigar("αβγ") self.assertEqual(str(cm.exception), msg) # test valid cigar with no 1's cigar = "MID12MI" path = PairAlignPath.from_cigar(cigar) lengths = [1, 1, 1, 12, 1] states = [0, 1, 2, 0, 1] npt.assert_array_equal(lengths, path.lengths) npt.assert_array_equal(states, np.squeeze(path.states)) # test cigar with all possible valid codes cigar = "1M2I3D4P5=6X7N8S9H" path = PairAlignPath.from_cigar(cigar) lengths = [1, 2, 3, 4, 11, 7, 8, 9] states = [0, 1, 2, 3, 0, 2, 1, 3] npt.assert_array_equal(lengths, path.lengths) npt.assert_array_equal(states, np.squeeze(path.states)) def test_to_cigar(self): # test base case lengths = [1, 2, 3, 4, 50, 234] gaps = [1, 0, 2, 1, 0, 1] ExamplePairAlignPath = PairAlignPath(lengths=lengths, states=gaps, starts=[0, 0]) obs = ExamplePairAlignPath.to_cigar() exp = "1I2M3D4I50M234I" self.assertEqual(obs, exp) # test if seqs are provided seq1 = "-AATCT----" + "C"*50 + "-"*234 seq2 = "TAC---GGCC" + "C"*20 + "A"*264 seqs = [DNA(seq1), DNA(seq2)] obs = ExamplePairAlignPath.to_cigar(seqs=seqs) exp = "1I2X3D4I5X18=27X234I" self.assertEqual(obs, exp) # test if alignment has two gaps in same position lengths = [1, 2, 3, 4, 1] gaps = [1, 0, 2, 1, 3] path = PairAlignPath(lengths=lengths, states=gaps, starts=[0, 0]) obs = path.to_cigar() exp = "1I2M3D4I1P" self.assertEqual(obs, exp) # two gaps with seqs provided seq1 = '-ATCGC-----' seq2 = 'GTA---ATTA-' seqs = [DNA(seq1), DNA(seq2)] obs = path.to_cigar(seqs=seqs) exp = "1I1X1=3D4I1P" self.assertEqual(obs, exp) # test sequences as strings seq1 = '-ATCGC-----' seq2 = 'GTA---ATTA-' seqs = [seq1, seq2] obs = path.to_cigar(seqs=seqs) exp = "1I1X1=3D4I1P" self.assertEqual(obs, exp) # test invalid sequence input seq1 = 1 seq2 = 'GTA---ATTA-' seqs = [seq1, seq2] msg = "`seqs` must be strings or Sequence objects." with self.assertRaises(TypeError) as cm: path.to_cigar(seqs=seqs) self.assertEqual(str(cm.exception), msg) class TestMisc(unittest.TestCase): def test_run_length_encode(self): obs = _run_length_encode("ABBCCCDDDD") exp = "1A2B3C4D" self.assertEqual(obs, exp) if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/test_score.py000066400000000000000000000246431520735541300253370ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy as np from skbio.sequence import DNA, Protein, SubstitutionMatrix from skbio.alignment import TabularMSA, AlignPath from skbio.util import get_data_path from skbio.alignment._score import align_score class ScoreTests(unittest.TestCase): def test_align_score_basic(self): """Test on a basic case.""" # This is a complex example, with terminal gap, continuous internal gap, dual # gaps, and terminal gap swapping sequences. aln = ["CGGTCGTAACGCGTA---CA", "CAG--GTAAG-CATACCTCA", "CGGTCGTCAC-TGTACAC--"] # Typical setting: match/mismatch with affine gap penalty. # Parameters were adopted from NCBI BLASTN: # match = 2, mismatch = -3, gap_open = 5, gap_extend = 2 obs = align_score(aln, (2, -3), (5, 2)) self.assertEqual(obs, -28.0) # Manual calculation: # 0: CGGTCGTAACGCGTA---CA # 1: CAG--GTAAG-CATACCTCA # => 2 * 11 - 3 * 3 - 5 * 3 - 2 * 6 = -14 # 0: CGGTCGTAACGCGTA---|CA # 2: CGGTCGTCAC-TGTACAC|xx # => 2 * 12 - 3 * 2 - 5 * 2 - 2 * 4 = 0 # 1: CAG--GTAAG|x|CATACCT|CA # 2: CGGTCGTCAC|x|TGTACAC|xx # => 2 * 8 - 3 * 7 - 5 * 1 - 2 * 2 = -14 # total => -14 + 0 -14 = -28 # penalize terminal gaps obs = align_score(aln, (2, -3), (5, 2), free_ends=False) self.assertEqual(obs, -46.0) # Alternative parameters: adopted from EMBOSS Needle: # match = 5, mismatch = -4, gap_open = 10, gap_extend = 0.5 # Because EMBOSS doesn't apply gap_extend to the first gap position, we # subtract gap_extend from gap_open here to mimic its behavior. # 5 * 11 - 4 * 3 - 9.5 * 3 - 0.5 * 6 = 11.5 # 5 * 12 - 4 * 2 - 9.5 * 2 - 0.5 * 4 = 31 # 5 * 8 - 4 * 7 - 9.5 * 1 - 0.5 * 2 = 1.5 # total: 11.5 + 31 + 1.5 = 44 obs = align_score(aln, (5, -4), (9.5, 0.5)) self.assertEqual(obs, 44.0) # The match/mismatch scores are from substitution matrix "NUC.4.4". submat = SubstitutionMatrix.by_name("NUC.4.4") obs = align_score(aln, submat, (9.5, 0.5)) self.assertEqual(obs, 44.0) # substitution matrix by name obs = align_score(aln, "NUC.4.4", (9.5, 0.5)) self.assertEqual(obs, 44.0) # linear gap penalty # 1 * (11 + 12 + 8) - 2 * (6 + 4 + 2) = 7 obs = align_score(aln, (1, 0), 2) self.assertEqual(obs, 7.0) def test_align_score_input(self): """Test on various input formats.""" aln = ["CGGTCGTAACGCGTA---CA", "CAG--GTAAG-CATACCTCA", "CGGTCGTCAC-TGTACAC--"] # list of raw strings obs = align_score(aln, (5, -4), (5, 2)) self.assertEqual(obs, 53) # list of Sequence objects seqs = list(map(DNA, aln)) obs = align_score(seqs, (5, -4), (5, 2)) self.assertEqual(obs, 53) # custom gap_chars seqs = aln obs = align_score(seqs, (5, -4), (5, 2), gap_chars="A") self.assertEqual(obs, -8) # which is equivalent to (- becomes X and A becomes -): aln2 = [ "CGGTCGT--CGCGT-XXXC-", "C-GXXGT--GXC-T-CCTC-", "CGGTCGTC-CXTGT-C-CXX", ] obs = align_score(aln2, (5, -4), (5, 2)) self.assertEqual(obs, -8) # gap_chars doesn't impact GrammaredSequence seqs = list(map(DNA, aln)) obs = align_score(seqs, (5, -4), (5, 2), gap_chars="A") self.assertEqual(obs, 53) # TabularMSA object msa = TabularMSA(map(DNA, aln)) obs = align_score(msa, (5, -4), (5, 2)) self.assertEqual(obs, 53) # gap_chars doesn't impact TabularMSA obs = align_score(msa, (5, -4), (5, 2), gap_chars="A") self.assertEqual(obs, 53) # alignment path path = AlignPath(lengths=[3, 2, 5, 1, 4, 3, 2], states=[0, 2, 0, 6, 0, 1, 4], starts=[0, 3, 0]) seqs = ["CGGTCGTAACGCGTACA", "GGGCAGGTAAGCATACCTCA", "CGGTCGTCACTGTACACAAA"] obs = align_score((path, seqs), (5, -4), (5, 2)) self.assertEqual(obs, 53) # gap_chars doesn't impact AlignPath obs = align_score((path, seqs), (5, -4), (5, 2), gap_chars="A") self.assertEqual(obs, 53) def test_align_score_pair(self): """Test on pairwise alignments.""" # single internal gap, no terminal gap aln = ["CCTCAT-C", "CGTCGTGC"] obs = align_score(aln, (5, -4), (5, 2)) self.assertEqual(obs, 10) obs = align_score(aln, "NUC.4.4", (5, 2)) self.assertEqual(obs, 10) obs = align_score(aln, (5, -4), (5, 2), free_ends=False) self.assertEqual(obs, 10) obs = align_score(aln, (5, -4), 3) self.assertEqual(obs, 14) # continuous internal gap, no terminal gap aln = ["ACGT---ACGT", "ACGTCCCACGT"] obs = align_score(aln, (5, -4), (5, 2)) self.assertEqual(obs, 29) # with terminal gaps aln = ["CGTCAT--", "--TCATGC"] obs = align_score(aln, (5, -4), (5, 2)) self.assertEqual(obs, 20) obs = align_score(aln, (5, -4), (5, 2), free_ends=False) self.assertEqual(obs, 2) # very complex gaps aln = ["--AA-AAA-----CC--TCAT--G------", "----C-GG--G--C-TC--GT---CCA---"] obs = align_score(aln, (5, -4), (5, 2)) self.assertEqual(obs, -55) obs = align_score(aln, (5, -4), (5, 2), free_ends=False) self.assertEqual(obs, -75) def test_align_score_real(self): """Test on real-world datasets.""" # protein aln = TabularMSA.read(get_data_path("il6.prot.aln"), constructor=Protein) exp = 11044 obs = align_score(aln, "BLOSUM62", (5, 2)) self.assertEqual(obs, exp) exp = 10918 obs = align_score(aln, "BLOSUM62", (5, 2), free_ends=False) self.assertEqual(obs, exp) # DNA aln = TabularMSA.read(get_data_path("il6.nucl.aln"), constructor=DNA) exp = 26550 obs = align_score(aln, (5, -4), (5, 2)) self.assertEqual(obs, exp) obs = align_score(aln, "NUC.4.4", (5, 2)) self.assertEqual(obs, exp) def test_align_score_edge(self): """Test on edge cases.""" # single character, same across sequences obs = align_score(["A"] * 3, (5, -4), (5, 2)) self.assertEqual(obs, 15) # single character, different between sequences obs = align_score(["A", "B", "C"], (5, -4), (5, 2)) self.assertEqual(obs, -12) # all gaps are terminal obs = align_score(["A--", "-A-", "--A"], (5, -4), (5, 2)) self.assertEqual(obs, 0) # one pair doesn't align aln = ["AAAAA", "AA---", "---AA"] obs = align_score(aln, (5, -4), (5, 2), free_ends=False) self.assertEqual(obs, -20) obs = align_score(aln, (5, -4), (5, 2), free_ends=True) self.assertEqual(obs, 20) def test_align_score_floating(self): """Test on mixed floating-point types.""" aln = ["CGGTCGTAACGCGTA---CA", "CAG--GTAAG-CATACCTCA", "CGGTCGTCAC-TGTACAC--"] # original (float32) submat = SubstitutionMatrix.by_name("NUC.4.4") self.assertEqual(submat.dtype, np.float32) obs = align_score(aln, submat, (9.5, 0.5)) self.assertEqual(obs, 44.0) self.assertIsInstance(obs, float) # substitution matrix is float64 submat2 = submat.copy() submat2._data = submat2._data.astype(np.float64) self.assertEqual(submat2.dtype, np.float64) obs = align_score(aln, submat2, (9.5, 0.5)) self.assertEqual(obs, 44.0) self.assertIsInstance(obs, float) # gap costs are float64 self.assertEqual(submat.dtype, np.float32) obs = align_score(aln, submat2, (np.float64(9.5), np.float64(0.5))) self.assertEqual(obs, 44.0) # mixed types obs = align_score(aln, (np.float64(5), -4), (np.float64(9.5), 0.5)) self.assertEqual(obs, 44.0) def test_align_score_error(self): """Test on inputs that cause errors.""" msg = "Sequences are of different types." with self.assertRaises(TypeError) as cm: align_score([1, None, 0.5], (5, -4), (5, 2)) self.assertEqual(str(cm.exception), msg) msg = "No sequence is provided." with self.assertRaises(ValueError) as cm: align_score([], (5, -4), (5, 2)) self.assertEqual(str(cm.exception), msg) msg = "Alignment must contain at least two sequences." with self.assertRaises(ValueError) as cm: align_score(["ABC"], (5, -4), (5, 2)) self.assertEqual(str(cm.exception), msg) msg = "The alignment contains gap-only sequence(s)." with self.assertRaises(ValueError) as cm: align_score(["ABC", "---"], (5, -4), (5, 2)) self.assertEqual(str(cm.exception), msg) msg = "Sequence lengths do not match." with self.assertRaises(ValueError) as cm: align_score(["A", "AA", "AAA"], (5, -4), (5, 2)) self.assertEqual(str(cm.exception), msg) msg = "The alignment has a length of zero." with self.assertRaises(ValueError) as cm: align_score([""] * 3, (5, -4), (5, 2)) self.assertEqual(str(cm.exception), msg) aln = ["MKQ-PSV", "MKIDTS-"] obs = align_score(aln, "BLOSUM62", (5, 2)) self.assertEqual(obs, 3) msg = "Sequence 1 contain character(s) absent from the substitution matrix." with self.assertRaises(ValueError) as cm: align_score(aln, "NUC.4.4", (5, 2)) self.assertEqual(str(cm.exception), msg) aln = [chr(0) + chr(12) + chr(34) + chr(56) + chr(78) + chr(90), chr(123) + chr(98) + chr(76) + "-" + chr(54) + chr(32)] with self.assertRaises(ValueError) as cm: align_score(aln, "BLOSUM62", (5, 2)) self.assertEqual(str(cm.exception), msg) if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/test_tabular_msa.py000066400000000000000000004413061520735541300265150ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import collections.abc import copy import unittest import functools import itertools import types import numpy as np import numpy.testing as npt import pandas as pd import scipy.stats from skbio import Sequence, DNA, RNA, Protein, TabularMSA from skbio.alignment import AlignPath from skbio.sequence import GrammaredSequence from skbio.util import classproperty from skbio.util._decorator import overrides from skbio.util._testing import ReallyEqualMixin from skbio.metadata._testing import (MetadataMixinTests, PositionalMetadataMixinTests) from skbio.util import assert_data_frame_almost_equal from skbio.util._testing import assert_index_equal class TabularMSASubclass(TabularMSA): """Used for testing purposes.""" pass class TestTabularMSAMetadata(unittest.TestCase, ReallyEqualMixin, MetadataMixinTests): def setUp(self): self._metadata_constructor_ = functools.partial(TabularMSA, []) class TestTabularMSAPositionalMetadata(unittest.TestCase, ReallyEqualMixin, PositionalMetadataMixinTests): def setUp(self): def factory(axis_len, positional_metadata=None): return TabularMSA([DNA('A' * axis_len)], positional_metadata=positional_metadata) self._positional_metadata_constructor_ = factory class TestTabularMSA(unittest.TestCase, ReallyEqualMixin): def test_from_dict_empty(self): self.assertEqual(TabularMSA.from_dict({}), TabularMSA([], index=[])) def test_from_dict_single_sequence(self): self.assertEqual(TabularMSA.from_dict({'foo': DNA('ACGT')}), TabularMSA([DNA('ACGT')], index=['foo'])) def test_from_dict_multiple_sequences(self): msa = TabularMSA.from_dict( {1: DNA('ACG'), 2: DNA('GGG'), 3: DNA('TAG')}) # Sort because order is arbitrary. msa.sort() self.assertEqual( msa, TabularMSA([DNA('ACG'), DNA('GGG'), DNA('TAG')], index=[1, 2, 3])) def test_from_dict_invalid_input(self): # Basic test to make sure error-checking in the TabularMSA constructor # is being invoked. with self.assertRaisesRegex( ValueError, r'must match the number of positions'): TabularMSA.from_dict({'a': DNA('ACG'), 'b': DNA('ACGT')}) def test_constructor_invalid_dtype(self): with self.assertRaisesRegex(TypeError, r'GrammaredSequence.*Sequence'): TabularMSA([Sequence('')]) with self.assertRaisesRegex(TypeError, r'GrammaredSequence.*int'): TabularMSA([42, DNA('')]) def test_constructor_not_monomorphic(self): with self.assertRaisesRegex(TypeError, r'matching type.*RNA.*DNA'): TabularMSA([DNA(''), RNA('')]) with self.assertRaisesRegex(TypeError, r'matching type.*float.*Protein'): TabularMSA([Protein(''), Protein(''), 42.0, Protein('')]) def test_constructor_unequal_length(self): with self.assertRaisesRegex( ValueError, r'must match the number of positions.*1 != 0'): TabularMSA([Protein(''), Protein('P')]) with self.assertRaisesRegex( ValueError, r'must match the number of positions.*1 != 3'): TabularMSA([Protein('PAW'), Protein('ABC'), Protein('A')]) def test_constructor_non_iterable(self): with self.assertRaises(TypeError): TabularMSA(42) def test_constructor_minter_and_index_both_provided(self): with self.assertRaisesRegex(ValueError, r'both.*minter.*index'): TabularMSA([DNA('ACGT'), DNA('TGCA')], minter=str, index=['a', 'b']) def test_constructor_invalid_minter_callable(self): with self.assertRaises(TypeError): TabularMSA([DNA('ACGT'), DNA('TGCA')], minter=float) def test_constructor_missing_minter_metadata_key(self): with self.assertRaises(KeyError): TabularMSA([DNA('ACGT', metadata={'foo': 'bar'}), DNA('TGCA')], minter='foo') def test_constructor_unhashable_minter_metadata_key(self): with self.assertRaises(TypeError): TabularMSA([DNA('ACGT'), DNA('TGCA')], minter=[]) def test_constructor_index_length_mismatch_iterable(self): with self.assertRaisesRegex(ValueError, r'sequences.*2.*index length.*0'): TabularMSA([DNA('ACGT'), DNA('TGCA')], index=iter([])) def test_constructor_index_length_mismatch_index_object(self): with self.assertRaisesRegex(ValueError, r'sequences.*2.*index length.*0'): TabularMSA([DNA('ACGT'), DNA('TGCA')], index=pd.Index([])) def test_constructor_invalid_index_scalar(self): with self.assertRaises(TypeError): TabularMSA([DNA('ACGT'), DNA('TGCA')], index=42) def test_constructor_non_unique_labels(self): msa = TabularMSA([DNA('ACGT'), DNA('ACGT')], index=[1, 1]) assert_index_equal(msa.index, pd.Index([1, 1], dtype=np.int64)) def test_constructor_empty_no_index(self): # sequence empty msa = TabularMSA([]) self.assertIsNone(msa.dtype) self.assertEqual(msa.shape, (0, 0)) assert_index_equal(msa.index, pd.RangeIndex(0)) with self.assertRaises(StopIteration): next(iter(msa)) # position empty seqs = [DNA(''), DNA('')] msa = TabularMSA(seqs) self.assertIs(msa.dtype, DNA) self.assertEqual(msa.shape, (2, 0)) assert_index_equal(msa.index, pd.RangeIndex(2)) self.assertEqual(list(msa), seqs) def test_constructor_empty_with_labels(self): # sequence empty msa = TabularMSA([], minter=lambda x: x) assert_index_equal(msa.index, pd.Index([])) msa = TabularMSA([], index=iter([])) assert_index_equal(msa.index, pd.Index([])) # position empty msa = TabularMSA([DNA('', metadata={'id': 42}), DNA('', metadata={'id': 43})], minter='id') assert_index_equal(msa.index, pd.Index([42, 43])) msa = TabularMSA([DNA(''), DNA('')], index=iter([42, 43])) assert_index_equal(msa.index, pd.Index([42, 43])) def test_constructor_non_empty_no_labels_provided(self): # 1x3 seqs = [DNA('ACG')] msa = TabularMSA(seqs) self.assertIs(msa.dtype, DNA) self.assertEqual(msa.shape, (1, 3)) assert_index_equal(msa.index, pd.RangeIndex(1)) self.assertEqual(list(msa), seqs) # 3x1 seqs = [DNA('A'), DNA('C'), DNA('G')] msa = TabularMSA(seqs) self.assertIs(msa.dtype, DNA) self.assertEqual(msa.shape, (3, 1)) assert_index_equal(msa.index, pd.RangeIndex(3)) self.assertEqual(list(msa), seqs) def test_constructor_non_empty_with_labels_provided(self): seqs = [DNA('ACG'), DNA('CGA'), DNA('GTT')] msa = TabularMSA(seqs, minter=str) self.assertIs(msa.dtype, DNA) self.assertEqual(msa.shape, (3, 3)) assert_index_equal(msa.index, pd.Index(['ACG', 'CGA', 'GTT'])) self.assertEqual(list(msa), seqs) msa = TabularMSA(seqs, index=iter([42, 43, 44])) assert_index_equal(msa.index, pd.Index([42, 43, 44])) def test_constructor_works_with_iterator(self): seqs = [DNA('ACG'), DNA('CGA'), DNA('GTT')] msa = TabularMSA(iter(seqs), minter=str) self.assertIs(msa.dtype, DNA) self.assertEqual(msa.shape, (3, 3)) assert_index_equal(msa.index, pd.Index(['ACG', 'CGA', 'GTT'])) self.assertEqual(list(msa), seqs) def test_constructor_with_multiindex_index(self): msa = TabularMSA([DNA('AA'), DNA('GG')], index=[('foo', 42), ('bar', 43)]) self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal(msa.index, pd.Index([('foo', 42), ('bar', 43)])) def test_constructor_with_multiindex_minter(self): def multiindex_minter(seq): if str(seq) == 'AC': return ('foo', 42) else: return ('bar', 43) msa = TabularMSA([DNA('AC'), DNA('GG')], minter=multiindex_minter) self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal(msa.index, pd.Index([('foo', 42), ('bar', 43)])) def test_copy_constructor_respects_default_index(self): msa = TabularMSA([DNA('ACGT'), DNA('----'), DNA('AAAA')]) copy = TabularMSA(msa) self.assertEqual(msa, copy) self.assertIsNot(msa, copy) assert_index_equal(msa.index, pd.RangeIndex(3)) assert_index_equal(copy.index, pd.RangeIndex(3)) def test_copy_constructor_without_metadata(self): msa = TabularMSA([DNA('ACGT'), DNA('----')]) copy = TabularMSA(msa) self.assertEqual(msa, copy) self.assertIsNot(msa, copy) assert_index_equal(copy.index, pd.RangeIndex(2)) def test_copy_constructor_with_metadata(self): msa = TabularMSA([DNA('ACGT'), DNA('----')], metadata={'foo': 42}, positional_metadata={'bar': range(4)}, index=['idx1', 'idx2']) copy = TabularMSA(msa) self.assertEqual(msa, copy) self.assertIsNot(msa, copy) self.assertIsNot(msa.metadata, copy.metadata) self.assertIsNot(msa.positional_metadata, copy.positional_metadata) # pd.Index is immutable, no copy necessary. self.assertIs(msa.index, copy.index) def test_copy_constructor_state_override_with_minter(self): msa = TabularMSA([DNA('ACGT'), DNA('----')], metadata={'foo': 42}, positional_metadata={'bar': range(4)}, index=['idx1', 'idx2']) copy = TabularMSA(msa, metadata={'foo': 43}, positional_metadata={'bar': range(4, 8)}, minter=str) self.assertNotEqual(msa, copy) self.assertEqual( copy, TabularMSA([DNA('ACGT'), DNA('----')], metadata={'foo': 43}, positional_metadata={'bar': range(4, 8)}, minter=str)) def test_copy_constructor_state_override_with_index(self): msa = TabularMSA([DNA('ACGT'), DNA('----')], metadata={'foo': 42}, positional_metadata={'bar': range(4)}, index=['idx1', 'idx2']) copy = TabularMSA(msa, metadata={'foo': 43}, positional_metadata={'bar': range(4, 8)}, index=['a', 'b']) self.assertNotEqual(msa, copy) self.assertEqual( copy, TabularMSA([DNA('ACGT'), DNA('----')], metadata={'foo': 43}, positional_metadata={'bar': range(4, 8)}, index=['a', 'b'])) def test_copy_constructor_with_minter_and_index(self): msa = TabularMSA([DNA('ACGT'), DNA('----')], index=['idx1', 'idx2']) with self.assertRaisesRegex(ValueError, r'both.*minter.*index'): TabularMSA(msa, index=['a', 'b'], minter=str) def test_dtype(self): self.assertIsNone(TabularMSA([]).dtype) self.assertIs(TabularMSA([Protein('')]).dtype, Protein) with self.assertRaises(AttributeError): TabularMSA([]).dtype = DNA with self.assertRaises(AttributeError): del TabularMSA([]).dtype def test_shape(self): shape = TabularMSA([DNA('ACG'), DNA('GCA')]).shape self.assertEqual(shape, (2, 3)) self.assertEqual(shape.sequence, shape[0]) self.assertEqual(shape.position, shape[1]) with self.assertRaises(TypeError): shape[0] = 3 with self.assertRaises(AttributeError): TabularMSA([]).shape = (3, 3) with self.assertRaises(AttributeError): del TabularMSA([]).shape def test_index_getter_default_index(self): msa = TabularMSA([DNA('AC'), DNA('AG'), DNA('AT')]) assert_index_equal(msa.index, pd.RangeIndex(3)) # immutable with self.assertRaises(TypeError): msa.index[1] = 2 # original state is maintained assert_index_equal(msa.index, pd.RangeIndex(3)) def test_index_getter(self): index = TabularMSA([DNA('AC'), DNA('AG'), DNA('AT')], minter=str).index self.assertIsInstance(index, pd.Index) assert_index_equal(index, pd.Index(['AC', 'AG', 'AT'])) # immutable with self.assertRaises(TypeError): index[1] = 'AA' # original state is maintained assert_index_equal(index, pd.Index(['AC', 'AG', 'AT'])) def test_index_mixed_type(self): msa = TabularMSA([DNA('AC'), DNA('CA'), DNA('AA')], index=['abc', 'd', 42]) assert_index_equal(msa.index, pd.Index(['abc', 'd', 42])) def test_index_setter_empty(self): msa = TabularMSA([]) msa.index = iter([]) assert_index_equal(msa.index, pd.Index([])) def test_index_setter_non_empty(self): msa = TabularMSA([DNA('AC'), DNA('AG'), DNA('AT')]) msa.index = range(3) assert_index_equal(msa.index, pd.RangeIndex(3)) msa.index = range(3, 6) assert_index_equal(msa.index, pd.RangeIndex(3, 6)) def test_index_setter_length_mismatch(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')], minter=str) index = pd.Index(['ACGT', 'TGCA']) assert_index_equal(msa.index, index) with self.assertRaisesRegex(ValueError, r'Length mismatch.*2.*3'): msa.index = iter(['ab', 'cd', 'ef']) # original state is maintained assert_index_equal(msa.index, index) def test_index_setter_non_unique_index(self): msa = TabularMSA([RNA('UUU'), RNA('AAA')], minter=str) msa.index = ['1', '1'] self.assertEqual(msa, TabularMSA([RNA('UUU'), RNA('AAA')], index=['1', '1'])) def test_index_setter_tuples(self): msa = TabularMSA([RNA('UUU'), RNA('AAA')]) msa.index = [('foo', 42), ('bar', 43)] self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal( msa.index, pd.Index([('foo', 42), ('bar', 43)], tupleize_cols=True)) def test_index_setter_preserves_range_index(self): msa = TabularMSA([RNA('UUU'), RNA('AAA')], minter=str) msa.index = pd.RangeIndex(2) self.assertEqual(msa, TabularMSA([RNA('UUU'), RNA('AAA')])) assert_index_equal(msa.index, pd.RangeIndex(2)) def test_index_deleter(self): msa = TabularMSA([RNA('UUU'), RNA('AAA')], minter=str) assert_index_equal(msa.index, pd.Index(['UUU', 'AAA'])) del msa.index assert_index_equal(msa.index, pd.RangeIndex(2)) # Delete again. del msa.index assert_index_equal(msa.index, pd.RangeIndex(2)) def test_bool(self): self.assertFalse(TabularMSA([])) self.assertFalse(TabularMSA([RNA('')])) self.assertFalse( TabularMSA([RNA('', metadata={'id': 1}), RNA('', metadata={'id': 2})], minter='id')) self.assertTrue(TabularMSA([RNA('U')])) self.assertTrue(TabularMSA([RNA('--'), RNA('..')])) self.assertTrue(TabularMSA([RNA('AUC'), RNA('GCA')])) def test_len(self): self.assertEqual(len(TabularMSA([])), 0) self.assertEqual(len(TabularMSA([DNA('')])), 1) self.assertEqual(len(TabularMSA([DNA('AT'), DNA('AG'), DNA('AT')])), 3) def test_iter(self): with self.assertRaises(StopIteration): next(iter(TabularMSA([]))) seqs = [DNA(''), DNA('')] self.assertEqual(list(iter(TabularMSA(seqs))), seqs) seqs = [DNA('AAA'), DNA('GCT')] self.assertEqual(list(iter(TabularMSA(seqs))), seqs) def test_reversed(self): with self.assertRaises(StopIteration): next(reversed(TabularMSA([]))) seqs = [DNA(''), DNA('', metadata={'id': 42})] self.assertEqual(list(reversed(TabularMSA(seqs))), seqs[::-1]) seqs = [DNA('AAA'), DNA('GCT')] self.assertEqual(list(reversed(TabularMSA(seqs))), seqs[::-1]) def test_eq_and_ne(self): # Each element contains the components necessary to construct a # TabularMSA object: seqs and kwargs. None of these objects (once # constructed) should compare equal to one another. components = [ # empties ([], {}), ([RNA('')], {}), ([RNA('')], {'minter': str}), # 1x1 ([RNA('U')], {'minter': str}), # 2x3 ([RNA('AUG'), RNA('GUA')], {'minter': str}), ([RNA('AG'), RNA('GG')], {}), # has labels ([RNA('AG'), RNA('GG')], {'minter': str}), # different dtype ([DNA('AG'), DNA('GG')], {'minter': str}), # different labels ([RNA('AG'), RNA('GG')], {'minter': lambda x: str(x) + '42'}), # different sequence metadata ([RNA('AG', metadata={'id': 42}), RNA('GG')], {'minter': str}), # different sequence data, same labels ([RNA('AG'), RNA('GA')], {'minter': lambda x: 'AG' if 'AG' in x else 'GG'}), # different MSA metadata ([RNA('AG'), RNA('GG')], {'metadata': {'foo': 42}}), ([RNA('AG'), RNA('GG')], {'metadata': {'foo': 43}}), ([RNA('AG'), RNA('GG')], {'metadata': {'foo': 42, 'bar': 43}}), # different MSA positional metadata ([RNA('AG'), RNA('GG')], {'positional_metadata': {'foo': [42, 43]}}), ([RNA('AG'), RNA('GG')], {'positional_metadata': {'foo': [43, 44]}}), ([RNA('AG'), RNA('GG')], {'positional_metadata': {'foo': [42, 43], 'bar': [43, 44]}}), ] for seqs, kwargs in components: obj = TabularMSA(seqs, **kwargs) self.assertReallyEqual(obj, obj) self.assertReallyEqual(obj, TabularMSA(seqs, **kwargs)) self.assertReallyEqual(obj, TabularMSASubclass(seqs, **kwargs)) for (seqs1, kwargs1), (seqs2, kwargs2) in \ itertools.combinations(components, 2): obj1 = TabularMSA(seqs1, **kwargs1) obj2 = TabularMSA(seqs2, **kwargs2) self.assertReallyNotEqual(obj1, obj2) self.assertReallyNotEqual(obj1, TabularMSASubclass(seqs2, **kwargs2)) # completely different types msa = TabularMSA([]) self.assertReallyNotEqual(msa, 42) self.assertReallyNotEqual(msa, []) self.assertReallyNotEqual(msa, {}) self.assertReallyNotEqual(msa, '') def test_eq_constructed_from_different_iterables_compare_equal(self): msa1 = TabularMSA([DNA('ACGT')]) msa2 = TabularMSA((DNA('ACGT'),)) self.assertReallyEqual(msa1, msa2) def test_eq_ignores_minter_str_and_lambda(self): # as long as the labels generated by the minters are the same, it # doesn't matter whether the minters are equal. msa1 = TabularMSA([DNA('ACGT', metadata={'id': 'a'})], minter='id') msa2 = TabularMSA([DNA('ACGT', metadata={'id': 'a'})], minter=lambda x: x.metadata['id']) self.assertReallyEqual(msa1, msa2) def test_eq_minter_and_index(self): # as long as the labels generated by the minters are the same, it # doesn't matter whether the minters are equal. msa1 = TabularMSA([DNA('ACGT', metadata={'id': 'a'})], index=['a']) msa2 = TabularMSA([DNA('ACGT', metadata={'id': 'a'})], minter='id') self.assertReallyEqual(msa1, msa2) def test_eq_default_index_and_equivalent_provided_index(self): msa1 = TabularMSA([DNA('ACGT'), DNA('----'), DNA('....')]) msa2 = TabularMSA([DNA('ACGT'), DNA('----'), DNA('....')], index=[0, 1, 2]) self.assertReallyEqual(msa1, msa2) assert_index_equal(msa1.index, pd.RangeIndex(3)) assert_index_equal(msa2.index, pd.Index([0, 1, 2], dtype=np.int64)) def test_reassign_index_empty(self): # sequence empty msa = TabularMSA([]) msa.reassign_index() self.assertEqual(msa, TabularMSA([])) assert_index_equal(msa.index, pd.RangeIndex(0)) msa.reassign_index(minter=str) self.assertEqual(msa, TabularMSA([], minter=str)) assert_index_equal(msa.index, pd.Index([])) # position empty msa = TabularMSA([DNA('')]) msa.reassign_index() self.assertEqual(msa, TabularMSA([DNA('')])) assert_index_equal(msa.index, pd.RangeIndex(1)) msa.reassign_index(minter=str) self.assertEqual(msa, TabularMSA([DNA('')], minter=str)) assert_index_equal(msa.index, pd.Index([''])) def test_reassign_index_non_empty(self): msa = TabularMSA([DNA('ACG', metadata={'id': 1}), DNA('AAA', metadata={'id': 2})], minter=str) assert_index_equal(msa.index, pd.Index(['ACG', 'AAA'])) msa.reassign_index(minter='id') self.assertEqual( msa, TabularMSA([DNA('ACG', metadata={'id': 1}), DNA('AAA', metadata={'id': 2})], minter='id')) assert_index_equal(msa.index, pd.Index([1, 2])) msa.reassign_index(mapping={1: 5}) self.assertEqual( msa, TabularMSA([DNA('ACG', metadata={'id': 1}), DNA('AAA', metadata={'id': 2})], index=[5, 2])) assert_index_equal(msa.index, pd.Index([5, 2])) msa.reassign_index() assert_index_equal(msa.index, pd.RangeIndex(2)) def test_reassign_index_minter_and_mapping_both_provided(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')], minter=str) with self.assertRaisesRegex(ValueError, r'both.*mapping.*minter.*'): msa.reassign_index(minter=str, mapping={"ACGT": "fleventy"}) # original state is maintained assert_index_equal(msa.index, pd.Index(['ACGT', 'TGCA'])) def test_reassign_index_mapping_invalid_type(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')], minter=str) with self.assertRaisesRegex(TypeError, r'mapping.*dict.*callable.*list'): msa.reassign_index(mapping=['abc', 'def']) # original state is maintained assert_index_equal(msa.index, pd.Index(['ACGT', 'TGCA'])) def test_reassign_index_with_mapping_dict_empty(self): seqs = [DNA("A"), DNA("C"), DNA("G")] msa = TabularMSA(seqs, index=[0.5, 1.5, 2.5]) msa.reassign_index(mapping={}) self.assertEqual(msa, TabularMSA(seqs, index=[0.5, 1.5, 2.5])) def test_reassign_index_with_mapping_dict_subset(self): seqs = [DNA("A"), DNA("C"), DNA("G")] mapping = {0.5: "a", 2.5: "c"} msa = TabularMSA(seqs, index=[0.5, 1.5, 2.5]) msa.reassign_index(mapping=mapping) self.assertEqual(msa, TabularMSA(seqs, index=['a', 1.5, 'c'])) def test_reassign_index_with_mapping_dict_superset(self): seqs = [DNA("A"), DNA("C"), DNA("G")] mapping = {0.5: "a", 1.5: "b", 2.5: "c", 3.5: "d"} msa = TabularMSA(seqs, index=[0.5, 1.5, 2.5]) msa.reassign_index(mapping=mapping) self.assertEqual(msa, TabularMSA(seqs, index=['a', 'b', 'c'])) def test_reassign_index_with_mapping_callable(self): seqs = [DNA("A"), DNA("C"), DNA("G")] msa = TabularMSA(seqs, index=[0, 1, 2]) msa.reassign_index(mapping=str) self.assertEqual(msa, TabularMSA(seqs, index=['0', '1', '2'])) msa.reassign_index(mapping=lambda e: int(e) + 42) self.assertEqual(msa, TabularMSA(seqs, index=[42, 43, 44])) def test_reassign_index_non_unique_existing_index(self): seqs = [DNA("A"), DNA("C"), DNA("G")] mapping = {0.5: "a", 1.5: "b", 2.5: "c", 3.5: "d"} msa = TabularMSA(seqs, index=[0.5, 0.5, 0.5]) msa.reassign_index(mapping=mapping) self.assertEqual(msa, TabularMSA(seqs, index=['a', 'a', 'a'])) def test_reassign_index_non_unique_new_index(self): seqs = [DNA("A"), DNA("C"), DNA("G")] mapping = {0.5: "a", 1.5: "a", 2.5: "a"} msa = TabularMSA(seqs, index=[0.5, 1.5, 2.5]) msa.reassign_index(mapping=mapping) self.assertEqual(msa, TabularMSA(seqs, index=['a', 'a', 'a'])) def test_reassign_index_to_multiindex_with_minter(self): msa = TabularMSA([DNA('AC'), DNA('.G')]) def multiindex_minter(seq): if str(seq) == 'AC': return ('foo', 42) else: return ('bar', 43) msa.reassign_index(minter=multiindex_minter) self.assertIsInstance(msa.index, pd.MultiIndex) self.assertEqual( msa, TabularMSA([DNA('AC'), DNA('.G')], index=[('foo', 42), ('bar', 43)])) def test_reassign_index_to_multiindex_with_mapping(self): msa = TabularMSA([DNA('AC'), DNA('.G')]) mapping = {0: ('foo', 42), 1: ('bar', 43)} msa.reassign_index(mapping=mapping) self.assertIsInstance(msa.index, pd.MultiIndex) self.assertEqual( msa, TabularMSA([DNA('AC'), DNA('.G')], index=[('foo', 42), ('bar', 43)])) def test_sort_on_unorderable_msa_index(self): msa = TabularMSA([DNA('AAA'), DNA('ACG'), DNA('---')], index=[42, 41, 'foo']) with self.assertRaises(TypeError): msa.sort() self.assertEqual( msa, TabularMSA([DNA('AAA'), DNA('ACG'), DNA('---')], index=[42, 41, 'foo'])) def test_sort_empty_on_msa_index(self): msa = TabularMSA([], index=[]) msa.sort() self.assertEqual(msa, TabularMSA([], index=[])) msa = TabularMSA([], index=[]) msa.sort(ascending=False) self.assertEqual(msa, TabularMSA([], index=[])) def test_sort_single_sequence_on_msa_index(self): msa = TabularMSA([DNA('ACGT')], index=[42]) msa.sort() self.assertEqual(msa, TabularMSA([DNA('ACGT')], index=[42])) msa = TabularMSA([DNA('ACGT')], index=[42]) msa.sort(ascending=False) self.assertEqual(msa, TabularMSA([DNA('ACGT')], index=[42])) def test_sort_multiple_sequences_on_msa_index(self): msa = TabularMSA([ DNA('TC'), DNA('GG'), DNA('CC')], index=['z', 'a', 'b']) msa.sort(ascending=True) self.assertEqual( msa, TabularMSA([ DNA('GG'), DNA('CC'), DNA('TC')], index=['a', 'b', 'z'])) msa = TabularMSA([ DNA('TC'), DNA('GG'), DNA('CC')], index=['z', 'a', 'b']) msa.sort(ascending=False) self.assertEqual( msa, TabularMSA([ DNA('TC'), DNA('CC'), DNA('GG')], index=['z', 'b', 'a'])) def test_sort_on_labels_with_some_repeats(self): msa = TabularMSA([ DNA('TCCG', metadata={'id': 10}), DNA('TAGG', metadata={'id': 10}), DNA('GGGG', metadata={'id': 8}), DNA('TGGG', metadata={'id': 10}), DNA('ACGT', metadata={'id': 0}), DNA('TAGA', metadata={'id': 10})], minter='id') msa.sort() self.assertEqual(msa._seqs.index.to_list(), [0, 8, 10, 10, 10, 10]) vals = list(msa._seqs.values) self.assertEqual(vals[0], DNA('ACGT', metadata={'id': 0})) self.assertEqual(vals[1], DNA('GGGG', metadata={'id': 8})) self.assertIn(DNA('TCCG', metadata={'id': 10}), vals) self.assertIn(DNA('TAGG', metadata={'id': 10}), vals[2:]) self.assertIn(DNA('TGGG', metadata={'id': 10}), vals[2:]) self.assertIn(DNA('TAGA', metadata={'id': 10}), vals[2:]) def test_sort_on_key_with_all_repeats(self): msa = TabularMSA([ DNA('TTT', metadata={'id': 'a'}), DNA('TTT', metadata={'id': 'b'}), DNA('TTT', metadata={'id': 'c'})], minter=str) msa.sort() self.assertEqual( msa, TabularMSA([ DNA('TTT', metadata={'id': 'a'}), DNA('TTT', metadata={'id': 'b'}), DNA('TTT', metadata={'id': 'c'})], minter=str)) def test_sort_default_index(self): msa = TabularMSA([DNA('TC'), DNA('GG'), DNA('CC')]) msa.sort() self.assertEqual( msa, TabularMSA([DNA('TC'), DNA('GG'), DNA('CC')])) def test_sort_default_index_descending(self): msa = TabularMSA([DNA('TC'), DNA('GG'), DNA('CC')]) msa.sort(ascending=False) self.assertEqual( msa, TabularMSA([DNA('CC'), DNA('GG'), DNA('TC')], index=[2, 1, 0])) def test_sort_already_sorted(self): msa = TabularMSA([DNA('TC'), DNA('GG'), DNA('CC')], index=[1, 2, 3]) msa.sort() self.assertEqual( msa, TabularMSA([DNA('TC'), DNA('GG'), DNA('CC')], index=[1, 2, 3])) msa = TabularMSA([DNA('TC'), DNA('GG'), DNA('CC')], index=[3, 2, 1]) msa.sort(ascending=False) self.assertEqual( msa, TabularMSA([DNA('TC'), DNA('GG'), DNA('CC')], index=[3, 2, 1])) def test_sort_reverse_sorted(self): msa = TabularMSA([DNA('T'), DNA('G'), DNA('A')], index=[3, 2, 1]) msa.sort() self.assertEqual( msa, TabularMSA([DNA('A'), DNA('G'), DNA('T')], index=[1, 2, 3])) msa = TabularMSA([DNA('T'), DNA('G'), DNA('A')], index=[1, 2, 3]) msa.sort(ascending=False) self.assertEqual( msa, TabularMSA([DNA('A'), DNA('G'), DNA('T')], index=[3, 2, 1])) def test_sort_multiindex(self): multiindex = [(2, 'a'), (1, 'c'), (3, 'b')] sortedindex = [(1, 'c'), (2, 'a'), (3, 'b')] msa = TabularMSA([DNA('A'), DNA('C'), DNA('G')], index=multiindex) msa.sort() self.assertEqual(msa, TabularMSA([DNA('C'), DNA('A'), DNA('G')], index=sortedindex)) def test_sort_multiindex_with_level(self): multiindex = [(2, 'a'), (1, 'c'), (3, 'b')] first_sorted = [(1, 'c'), (2, 'a'), (3, 'b')] second_sorted = [(2, 'a'), (3, 'b'), (1, 'c')] msa = TabularMSA([DNA('A'), DNA('C'), DNA('G')], index=multiindex) self.assertIsInstance(msa.index, pd.MultiIndex) msa.sort(level=0) self.assertEqual(msa, TabularMSA([DNA('C'), DNA('A'), DNA('G')], index=first_sorted)) msa.sort(level=1) self.assertEqual(msa, TabularMSA([DNA('A'), DNA('G'), DNA('C')], index=second_sorted)) def test_to_dict_falsey_msa(self): self.assertEqual(TabularMSA([]).to_dict(), {}) self.assertEqual(TabularMSA([RNA('')], index=['foo']).to_dict(), {'foo': RNA('')}) def test_to_dict_non_empty(self): seqs = [Protein('PAW', metadata={'id': 42}), Protein('WAP', metadata={'id': -999})] msa = TabularMSA(seqs, minter='id') self.assertEqual(msa.to_dict(), {42: seqs[0], -999: seqs[1]}) def test_to_dict_default_index(self): msa = TabularMSA([RNA('UUA'), RNA('-C-'), RNA('AAA')]) d = msa.to_dict() self.assertEqual(d, {0: RNA('UUA'), 1: RNA('-C-'), 2: RNA('AAA')}) def test_to_dict_duplicate_labels(self): msa = TabularMSA([DNA("A"), DNA("G")], index=[0, 0]) with self.assertRaises(ValueError) as cm: msa.to_dict() self.assertIn("unique", str(cm.exception)) def test_from_dict_to_dict_roundtrip(self): d = {} self.assertEqual(TabularMSA.from_dict(d).to_dict(), d) # can roundtrip even with mixed key types d1 = {'a': DNA('CAT'), 42: DNA('TAG')} d2 = TabularMSA.from_dict(d1).to_dict() self.assertEqual(d2, d1) self.assertIs(d1['a'], d2['a']) self.assertIs(d1[42], d2[42]) def test_from_path_seqs(self): # whole sequences path = AlignPath(lengths=[3, 2, 5, 1, 4, 3, 2], states=[0, 2, 0, 6, 0, 1, 0], starts=[0, 0, 0]) seqs = list(map(DNA, [ "CGGTCGTAACGCGTACA", "CAGGTAAGCATACCTCA", "CGGTCGTCACTGTACACTA", ])) obs = TabularMSA.from_path_seqs(path=path, seqs=seqs) exp = [ "CGGTCGTAACGCGTA---CA", "CAG--GTAAG-CATACCTCA", "CGGTCGTCAC-TGTACACTA", ] for o, e in zip(obs, exp): self.assertEqual(str(o), e) # middle of the sequences path._ranges[0] += 1 path._ranges[1] += 3 path._ranges[2] += 5 seqs = list(map(DNA, [ "ACGGTCGTAACGCGTACATTT", "AAACAGGTAAGCATACCTCATTTTT", "AAAAACGGTCGTCACTGTACACTAT", ])) obs = TabularMSA.from_path_seqs(path=path, seqs=seqs) for o, e in zip(obs, exp): self.assertEqual(str(o), e) msg = "`seqs` must be of skbio.Sequence type." with self.assertRaises(ValueError) as cm: TabularMSA.from_path_seqs(path=path, seqs=[1, 2, 3]) self.assertEqual(str(cm.exception), msg) msg = "Sequence counts in `path` and `seqs` do not match." with self.assertRaises(ValueError) as cm: TabularMSA.from_path_seqs(path=path, seqs=seqs[:-1]) self.assertEqual(str(cm.exception), msg) class TestContains(unittest.TestCase): def test_no_sequences(self): msa = TabularMSA([], index=[]) self.assertFalse('' in msa) self.assertFalse('foo' in msa) def test_with_str_labels(self): msa = TabularMSA([RNA('AU'), RNA('A.')], index=['foo', 'bar']) self.assertTrue('foo' in msa) self.assertTrue('bar' in msa) self.assertFalse('baz' in msa) self.assertFalse(0 in msa) def test_with_int_labels(self): msa = TabularMSA([RNA('AU'), RNA('A.')], index=[42, -1]) self.assertTrue(42 in msa) self.assertTrue(-1 in msa) self.assertFalse(0 in msa) self.assertFalse('foo' in msa) class TestCopy(unittest.TestCase): # Note: tests for metadata/positional_metadata are in mixin tests above. def test_no_sequences(self): msa = TabularMSA([]) msa_copy = copy.copy(msa) self.assertEqual(msa, msa_copy) self.assertIsNot(msa, msa_copy) self.assertIsNot(msa._seqs, msa_copy._seqs) def test_with_sequences(self): msa = TabularMSA([DNA('ACGT', metadata={'foo': [1]}), DNA('TGCA')]) msa_copy = copy.copy(msa) self.assertEqual(msa, msa_copy) self.assertIsNot(msa, msa_copy) self.assertIsNot(msa._seqs, msa_copy._seqs) self.assertIsNot(msa[0], msa_copy[0]) self.assertIsNot(msa[1], msa_copy[1]) msa_copy.append(DNA('AAAA'), reset_index=True) self.assertEqual( msa, TabularMSA([DNA('ACGT', metadata={'foo': [1]}), DNA('TGCA')])) msa_copy._seqs[0].metadata['bar'] = 42 self.assertEqual( msa, TabularMSA([DNA('ACGT', metadata={'foo': [1]}), DNA('TGCA')])) msa_copy._seqs[0].metadata['foo'].append(2) self.assertEqual( msa, TabularMSA([DNA('ACGT', metadata={'foo': [1, 2]}), DNA('TGCA')])) def test_with_index(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')], index=['foo', 'bar']) msa_copy = copy.copy(msa) self.assertEqual(msa, msa_copy) self.assertIsNot(msa, msa_copy) # pd.Index is immutable, no copy necessary. self.assertIs(msa.index, msa_copy.index) msa_copy.index = [1, 2] assert_index_equal(msa_copy.index, pd.Index([1, 2])) assert_index_equal(msa.index, pd.Index(['foo', 'bar'])) class TestDeepCopy(unittest.TestCase): # Note: tests for metadata/positional_metadata are in mixin tests above. def test_no_sequences(self): msa = TabularMSA([]) msa_copy = copy.deepcopy(msa) self.assertEqual(msa, msa_copy) self.assertIsNot(msa, msa_copy) self.assertIsNot(msa._seqs, msa_copy._seqs) def test_with_sequences(self): msa = TabularMSA([DNA('ACGT', metadata={'foo': [1]}), DNA('TGCA')]) msa_copy = copy.deepcopy(msa) self.assertEqual(msa, msa_copy) self.assertIsNot(msa, msa_copy) self.assertIsNot(msa._seqs, msa_copy._seqs) self.assertIsNot(msa[0], msa_copy[0]) self.assertIsNot(msa[1], msa_copy[1]) msa_copy.append(DNA('AAAA'), reset_index=True) self.assertEqual( msa, TabularMSA([DNA('ACGT', metadata={'foo': [1]}), DNA('TGCA')])) msa_copy._seqs[0].metadata['bar'] = 42 self.assertEqual( msa, TabularMSA([DNA('ACGT', metadata={'foo': [1]}), DNA('TGCA')])) msa_copy._seqs[0].metadata['foo'].append(2) self.assertEqual( msa, TabularMSA([DNA('ACGT', metadata={'foo': [1]}), DNA('TGCA')])) def test_with_index(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')], index=['foo', 'bar']) msa_copy = copy.deepcopy(msa) self.assertEqual(msa, msa_copy) self.assertIsNot(msa, msa_copy) # pd.Index is immutable, no copy necessary. self.assertIs(msa.index, msa_copy.index) msa_copy.index = [1, 2] assert_index_equal(msa_copy.index, pd.Index([1, 2])) assert_index_equal(msa.index, pd.Index(['foo', 'bar'])) class SharedIndexTests: def get(self, obj, indexable): raise NotImplementedError() def test_tuple_too_big(self): with self.assertRaises(ValueError): self.get(TabularMSA([]), (None, None, None)) def test_empty_msa_slice(self): msa = TabularMSA([]) new = self.get(msa, slice(None, None)) self.assertIsNot(msa, new) self.assertEqual(msa, new) def test_msa_slice_all_first_axis(self): msa = TabularMSA([RNA("AAA", metadata={1: 1}), RNA("AAU", positional_metadata={0: [1, 2, 3]})], metadata={0: 0}, positional_metadata={1: [3, 2, 1]}) new_slice = self.get(msa, slice(None)) new_ellipsis = self.get(msa, Ellipsis) self.assertIsNot(msa, new_slice) for s1, s2 in zip(msa, new_slice): self.assertIsNot(s1, s2) self.assertEqual(msa, new_slice) self.assertIsNot(msa, new_ellipsis) for s1, s2 in zip(msa, new_ellipsis): self.assertIsNot(s1, s2) self.assertEqual(msa, new_ellipsis) def test_msa_slice_all_both_axes(self): msa = TabularMSA([RNA("AAA", metadata={1: 1}), RNA("AAU", positional_metadata={0: [1, 2, 3]})], metadata={0: 0}, positional_metadata={1: [3, 2, 1]}) new_slice = self.get(msa, (slice(None), slice(None))) new_ellipsis = self.get(msa, (Ellipsis, Ellipsis)) self.assertIsNot(msa, new_slice) for s1, s2 in zip(msa, new_slice): self.assertIsNot(s1, s2) self.assertEqual(msa, new_slice) self.assertIsNot(msa, new_ellipsis) for s1, s2 in zip(msa, new_ellipsis): self.assertIsNot(s1, s2) self.assertEqual(msa, new_ellipsis) def test_bool_index_first_axis(self): a = DNA("AAA", metadata={1: 1}) b = DNA("NNN", positional_metadata={1: ['x', 'y', 'z']}) c = DNA("AAC") msa = TabularMSA([a, b, c], metadata={0: 'x'}, positional_metadata={0: [1, 2, 3]}, index=[True, False, True]) new = self.get(msa, [True, True, False]) self.assertEqual(new, TabularMSA([a, b], metadata={0: 'x'}, positional_metadata={0: [1, 2, 3]}, index=[True, False])) def test_bool_index_second_axis(self): a = DNA("AAA", metadata={1: 1}) b = DNA("NNN", positional_metadata={1: ['x', 'y', 'z']}) c = DNA("AAC") msa = TabularMSA([a, b, c], metadata={0: 'x'}, positional_metadata={0: [1, 2, 3]}, index=[True, False, True]) new = self.get(msa, (Ellipsis, [True, True, False])) self.assertEqual(new, TabularMSA([a[0, 1], b[0, 1], c[0, 1]], metadata={0: 'x'}, positional_metadata={0: [1, 2]}, index=[True, False, True])) def test_bool_index_both_axes(self): a = DNA("AAA", metadata={1: 1}) b = DNA("NNN", positional_metadata={1: ['x', 'y', 'z']}) c = DNA("AAC") msa = TabularMSA([a, b, c], metadata={0: 'x'}, positional_metadata={0: [1, 2, 3]}, index=[True, False, True]) new = self.get(msa, ([False, True, True], [True, True, False])) self.assertEqual(new, TabularMSA([b[0, 1], c[0, 1]], metadata={0: 'x'}, positional_metadata={0: [1, 2]}, index=[False, True])) def test_bool_index_too_big(self): msa = TabularMSA([DNA("ABCD"), DNA("GHKM"), DNA("NRST")], index=[False, True, False]) with self.assertRaises(IndexError): self.get(msa, [False, False, False, False]) with self.assertRaises(IndexError): self.get(msa, [True, True, True, True]) with self.assertRaises(IndexError): self.get(msa, (Ellipsis, [True, False, True, False, True])) with self.assertRaises(IndexError): self.get(msa, ([True, False, True, False], [True, False, True, False, False])) def test_bool_index_too_small(self): msa = TabularMSA([DNA("ABCD"), DNA("GHKM"), DNA("NRST")], index=[False, True, False]) with self.assertRaises(IndexError): self.get(msa, [False]) with self.assertRaises(IndexError): self.get(msa, [True]) with self.assertRaises(IndexError): self.get(msa, (Ellipsis, [True])) with self.assertRaises(IndexError): self.get(msa, ([True, False], [True, False, True, False])) def test_bad_scalar(self): msa = TabularMSA([DNA("ABCD"), DNA("GHKM"), DNA("NRST")]) with self.assertRaises((KeyError, TypeError)): self.get(msa, "foo") with self.assertRaises(IndexError): self.get(msa, (Ellipsis, "foo")) def test_bad_fancy_index(self): msa = TabularMSA([DNA("ABCD"), DNA("GHKM"), DNA("NRST")]) with self.assertRaises((KeyError, TypeError, ValueError)): self.get(msa, [0, "foo"]) with self.assertRaises(IndexError): self.get(msa, (Ellipsis, [0, "foo"])) def test_asburd_slice(self): msa = TabularMSA([DNA("ABCD"), DNA("GHKM"), DNA("NRST")]) with self.assertRaises(TypeError): self.get(msa, {set(1): 0}) class SharedPropertyIndexTests(SharedIndexTests): def setUp(self): self.combo_msa = TabularMSA([ DNA('ACGTA', metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4, 5]}), DNA('CGTAC', metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4, 5]}), DNA('GTACG', metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4, 5]}), DNA('TACGT', metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4, 5]}), DNA('ACGTT', metadata={4: 4}, positional_metadata={4: [1, 2, 3, 4, 5]}) ], index=list('ABCDE'), metadata={'x': 'x'}, positional_metadata={'y': [5, 4, 3, 2, 1]}) """First off, sorry to the next person who has to deal with this. The next few tests will try and slice by a bunch of stuff, with all combinations. Each element in the two lists is a tuple where the first element is the thing to slice with, and the second is the equivalent fancy index which describes the same range. This lets us describe the results a little more declaratively without setting up a thousand tests for each possible combination. This does mean the iloc via a fancy index and simple scalar must work correctly. """ # This will be overridden for TestLoc because the first axis are labels self.combo_first_axis = [ ([], []), (slice(0, 0), []), (Ellipsis, [0, 1, 2, 3, 4]), (slice(None), [0, 1, 2, 3, 4]), (slice(0, 10000), [0, 1, 2, 3, 4]), (3, 3), (-4, 1), ([0], [0]), ([2], [2]), (slice(1, 3), [1, 2]), (slice(3, 0, -1), [3, 2, 1]), ([-3, 2, 1], [2, 2, 1]), ([-4, -3, -2, -1], [1, 2, 3, 4]), (np.array([-3, 2, 1]), [2, 2, 1]), ([True, True, False, False, True], [0, 1, 4]), (np.array([True, True, False, True, False]), [0, 1, 3]), (range(3), [0, 1, 2]), ([slice(0, 2), slice(3, 4), 4], [0, 1, 3, 4]) ] # Same in both TestLoc and TestILoc self.combo_second_axis = self.combo_first_axis def test_combo_single_axis_natural(self): for idx, exp in self.combo_first_axis: self.assertEqual(self.get(self.combo_msa, idx), self.combo_msa.iloc[exp], msg="%r did not match iloc[%r]" % (idx, exp)) def test_combo_first_axis_only(self): for idx, exp in self.combo_first_axis: self.assertEqual(self.get(self.combo_msa, idx, axis=0), self.combo_msa.iloc[exp, ...], msg="%r did not match iloc[%r, ...]" % (idx, exp)) def test_combo_second_axis_only(self): for idx, exp in self.combo_second_axis: self.assertEqual(self.get(self.combo_msa, idx, axis=1), self.combo_msa.iloc[..., exp], msg="%r did not match iloc[..., %r]" % (idx, exp)) def test_combo_both_axes(self): for idx1, exp1 in self.combo_first_axis: for idx2, exp2 in self.combo_second_axis: self.assertEqual(self.get(self.combo_msa, (idx1, idx2)), self.combo_msa.iloc[exp1, exp2], msg=("%r did not match iloc[%r, %r]" % ((idx1, idx2), exp1, exp2))) class TestLoc(SharedPropertyIndexTests, unittest.TestCase): def setUp(self): SharedPropertyIndexTests.setUp(self) self.combo_first_axis = [ ([], []), (slice('X', "Z"), []), ('A', 0), ('E', 4), (['B'], [1]), (np.asarray(['B']), [1]), (slice('A', 'C', 2), [0, 2]), (slice('C', 'A', -2), [2, 0]), (slice('A', 'B'), [0, 1]), (slice(None), [0, 1, 2, 3, 4]), (slice('A', None), [0, 1, 2, 3, 4]), (slice(None, 'C'), [0, 1, 2]), (Ellipsis, [0, 1, 2, 3, 4]), (self.combo_msa.index, [0, 1, 2, 3, 4]), (['B', 'A', 'A', 'C'], [1, 0, 0, 2]), (np.asarray(['B', 'A', 'A', 'C']), [1, 0, 0, 2]), ([True, False, True, True, False], [0, 2, 3]), (np.asarray([True, False, True, True, False]), [0, 2, 3]), ] def test_forced_axis_returns_copy(self): msa = TabularMSA([Protein("EVANTHQMVS"), Protein("EVANTH*MVS")]) self.assertIsNot(msa.loc(axis=1), msa.loc) def test_forced_axis_no_mutate(self): msa = TabularMSA([Protein("EVANTHQMVS"), Protein("EVANTH*MVS")]) self.assertEqual(msa.loc(axis=1)[0], Sequence("EE")) self.assertEqual(msa.loc[0], Protein("EVANTHQMVS")) self.assertIsNone(msa.loc._axis) def get(self, obj, indexable, axis=None): if axis is None: return obj.loc[indexable] else: return obj.loc(axis=axis)[indexable] def test_complex_single_label(self): a = DNA("ACG") b = DNA("ACT") c = DNA("ACA") msa = TabularMSA([a, b, c], index=[('a', 0), ('a', 1), ('b', 0)]) self.assertIs(a, self.get(msa, (('a', 0),))) self.assertIs(b, self.get(msa, (('a', 1),))) self.assertIs(c, self.get(msa, (('b', 0),))) def test_partial_label(self): a = DNA("ACG") b = DNA("ACT") c = DNA("ACA") msa = TabularMSA([a, b, c], index=[('a', 0), ('a', 1), ('b', 0)]) exp_a = TabularMSA([a, b], index=[0, 1]) exp_b = TabularMSA([c], index=[0]) self.assertEqual(self.get(msa, 'a'), exp_a) self.assertEqual(self.get(msa, 'b'), exp_b) def test_label_not_exists(self): msa = TabularMSA([DNA("ACG")], index=['foo']) with self.assertRaises(KeyError): self.get(msa, 'bar') def test_duplicate_index_nonscalar_label(self): a = DNA("ACGA", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("A-GA", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("AAGA", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) d = DNA("ACCA", metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c, d], metadata={'x': 'y'}, positional_metadata={'z': [1, 2, 3, 4]}, index=[0, 0, 1, 2]) self.assertEqual(self.get(msa, 0), TabularMSA([a, b], metadata={'x': 'y'}, positional_metadata={'z': [1, 2, 3, 4]}, index=[0, 0])) def test_duplicate_index_scalar_label(self): a = DNA("ACGA", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("A-GA", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("AAGA", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) d = DNA("ACCA", metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c, d], metadata={'x': 'y'}, positional_metadata={'z': [1, 2, 3, 4]}, index=[0, 0, 1, 2]) self.assertEqual(self.get(msa, 1), c) def test_multiindex_complex(self): a = DNA("ACG") b = DNA("ACT") c = DNA("ACA") msa = TabularMSA([a, b, c], index=[('a', 0), ('a', 1), ('b', 0)]) exp = TabularMSA([a, c], index=[('a', 0), ('b', 0)]) self.assertEqual(self.get(msa, [('a', 0), ('b', 0)]), exp) def test_fancy_index_missing_label(self): msa = TabularMSA([DNA("ACG")], index=['foo']) with self.assertRaises(KeyError): self.get(msa, ['foo', 'bar']) with self.assertRaises(KeyError): self.get(msa, ['bar']) def test_multiindex_fancy_indexing_incomplete_label(self): a = RNA("UUAG", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = RNA("UAAG", metadata={1: 0}, positional_metadata={1: [1, 2, 3, 4]}) c = RNA("UAA-", metadata={2: 0}, positional_metadata={2: [1, 2, 3, 4]}) d = RNA("UA-G", metadata={3: 0}, positional_metadata={3: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c, d], metadata={'x': 'y'}, positional_metadata={'c': ['a', 'b', 'c', 'd']}, index=[('a', 'x', 0), ('a', 'x', 1), ('a', 'y', 2), ('b', 'x', 0)]) self.assertEqual(self.get(msa, (('a', 'x'), Ellipsis)), TabularMSA([a, b], metadata={'x': 'y'}, positional_metadata={'c': ['a', 'b', 'c', 'd']}, index=[0, 1])) def test_bool_index_scalar_bool_label(self): a = DNA("ACGA", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("A-GA", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("AAGA", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) d = DNA("ACCA", metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c, d], metadata={'x': 'y'}, positional_metadata={'z': [1, 2, 3, 4]}, index=[False, True, False, False]) self.assertEqual(self.get(msa, True), b) def test_bool_index_nonscalar_bool_label(self): a = DNA("ACGA", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("A-GA", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("AAGA", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) d = DNA("ACCA", metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c, d], metadata={'x': 'y'}, positional_metadata={'z': [1, 2, 3, 4]}, index=[False, True, False, True]) self.assertEqual(self.get(msa, True), TabularMSA([b, d], metadata={'x': 'y'}, positional_metadata={'z': [1, 2, 3, 4]}, index=[True, True])) def test_categorical_index_scalar_label(self): msa = TabularMSA([RNA("ACUG"), RNA("ACUA"), RNA("AAUG"), RNA("AC-G")], index=pd.CategoricalIndex(['a', 'b', 'b', 'c'])) self.assertEqual(self.get(msa, 'a'), RNA("ACUG")) def test_categorical_index_nonscalar_label(self): msa = TabularMSA([RNA("ACUG"), RNA("ACUA"), RNA("AAUG"), RNA("AC-G")], index=pd.CategoricalIndex(['a', 'b', 'b', 'c'])) self.assertEqual(self.get(msa, 'b'), TabularMSA([RNA("ACUA"), RNA("AAUG")], index=pd.CategoricalIndex( ['b', 'b'], categories=['a', 'b', 'c']) )) def test_float_index_out_of_order_slice(self): msa = TabularMSA([DNA("ACGG"), DNA("AAGC"), DNA("AAAA"), DNA("ACTC")], index=[0.1, 2.4, 5.1, 2.6]) with self.assertRaises(KeyError): self.get(msa, slice(0.1, 2.7)) msa.sort() result = self.get(msa, slice(0.1, 2.7)) self.assertEqual(result, TabularMSA([DNA("ACGG"), DNA("AAGC"), DNA("ACTC")], index=[0.1, 2.4, 2.6])) def test_nonscalar_fancy_index(self): msa = TabularMSA([DNA('ACGT'), DNA('ACGT'), DNA('ACGT')], index=[('a', 0, 1), ('a', 1, 1), ('b', 0, 1)]) with self.assertRaisesRegex(TypeError, r'tuple.*independent.*MultiIndex'): self.get(msa, ['a', 'b']) def test_missing_first_nonscalar_fancy_index(self): msa = TabularMSA([DNA('ACGT'), DNA('ACGT'), DNA('ACGT')], index=[('a', 0, 1), ('a', 1, 1), ('b', 0, 1)]) with self.assertRaises(KeyError): self.get(msa, ['x', 'a', 'b']) def test_tuple_fancy_index(self): msa = TabularMSA([DNA('ACGT'), DNA('ACGT'), DNA('ACGT')], index=[('a', 0, 1), ('a', 1, 1), ('b', 0, 1)]) with self.assertRaisesRegex(TypeError, r'tuple.*pd.MultiIndex.*label'): self.get(msa, ((('a', 0, 1), ('b', 0, 1)), Ellipsis)) def test_non_multiindex_tuple(self): msa = TabularMSA([DNA('ACGT'), DNA('ACGT'), DNA('ACGT')]) with self.assertRaisesRegex(TypeError, r'tuple.*first axis'): self.get(msa, ((0, 1), Ellipsis)) def test_assertion_exists_for_future_failure_of_get_sequence_loc(self): # Ideally we wouldn't need this test or the branch, but the most common # failure for pandas would be returning a series instead of the value. # We should make sure that the user get's an error should this ever # happen again. Getting a series of DNA looks pretty weird... msa = TabularMSA([DNA('ACGT'), DNA('ACGT'), DNA('ACGT')]) with self.assertRaises(AssertionError): msa._get_sequence_loc_([1, 2]) class TestILoc(SharedPropertyIndexTests, unittest.TestCase): def setUp(self): SharedPropertyIndexTests.setUp(self) self.combo_first_axis = self.combo_second_axis def test_forced_axis_returns_copy(self): msa = TabularMSA([Protein("EVANTHQMVS"), Protein("EVANTH*MVS")]) self.assertIsNot(msa.iloc(axis=1), msa.iloc) def test_forced_axis_no_mutate(self): msa = TabularMSA([Protein("EVANTHQMVS"), Protein("EVANTH*MVS")]) self.assertEqual(msa.iloc(axis=1)[0], Sequence("EE")) self.assertEqual(msa.iloc[0], Protein("EVANTHQMVS")) self.assertIsNone(msa.iloc._axis) def get(self, obj, indexable, axis=None): if axis is None: return obj.iloc[indexable] else: return obj.iloc(axis=axis)[indexable] def test_entire_fancy_first_axis(self): msa = TabularMSA([ DNA("ACCA", metadata={'a': 'foo'}, positional_metadata={'a': [7, 6, 5, 4]}), DNA("GGAA", metadata={'b': 'bar'}, positional_metadata={'b': [3, 4, 5, 6]}) ], metadata={'c': 'baz'}, positional_metadata={'foo': [1, 2, 3, 4]}) new_np_simple = self.get(msa, np.arange(2)) new_list_simple = self.get(msa, [0, 1]) new_list_backwards = self.get(msa, [-2, -1]) self.assertIsNot(msa, new_np_simple) self.assertEqual(msa, new_np_simple) self.assertIsNot(msa, new_list_simple) self.assertEqual(msa, new_list_simple) self.assertIsNot(msa, new_list_backwards) self.assertEqual(msa, new_list_backwards) def test_fancy_entire_second_axis(self): msa = TabularMSA([ DNA("ACCA", metadata={'a': 'foo'}, positional_metadata={'a': [7, 6, 5, 4]}), DNA("GGAA", metadata={'b': 'bar'}, positional_metadata={'b': [3, 4, 5, 6]}) ], metadata={'c': 'baz'}, positional_metadata={'foo': [1, 2, 3, 4]}) new_np_simple = self.get(msa, (Ellipsis, np.arange(4))) new_list_simple = self.get(msa, (Ellipsis, [0, 1, 2, 3])) new_list_backwards = self.get(msa, (Ellipsis, [-4, -3, -2, -1])) self.assertIsNot(msa, new_np_simple) self.assertEqual(msa, new_np_simple) self.assertIsNot(msa, new_list_simple) self.assertEqual(msa, new_list_simple) self.assertIsNot(msa, new_list_backwards) self.assertEqual(msa, new_list_backwards) def test_fancy_entire_both_axes(self): msa = TabularMSA([ DNA("ACCA", metadata={'a': 'foo'}, positional_metadata={'a': [7, 6, 5, 4]}), DNA("GGAA", metadata={'b': 'bar'}, positional_metadata={'b': [3, 4, 5, 6]}) ], metadata={'c': 'baz'}, positional_metadata={'foo': [1, 2, 3, 4]}) new_np_simple = self.get(msa, (np.arange(2), np.arange(4))) new_list_simple = self.get(msa, ([0, 1], [0, 1, 2, 3])) new_list_backwards = self.get(msa, ([-2, -1], [-4, -3, -2, -1])) self.assertIsNot(msa, new_np_simple) self.assertEqual(msa, new_np_simple) self.assertIsNot(msa, new_list_simple) self.assertEqual(msa, new_list_simple) self.assertIsNot(msa, new_list_backwards) self.assertEqual(msa, new_list_backwards) def test_fancy_out_of_bound(self): with self.assertRaises(IndexError): self.get(TabularMSA([DNA('AC')]), [0, 1, 2]) with self.assertRaises(IndexError): self.get(TabularMSA([DNA('AC')]), (Ellipsis, [0, 1, 2])) def test_fancy_empty_both_axis(self): msa = TabularMSA([DNA("ACGT", metadata={'x': 1}), DNA("TGCA", metadata={'y': 2})], index=list("AB")) new_np_simple = self.get(msa, (np.arange(0), np.arange(0))) new_list_simple = self.get(msa, ([], [])) self.assertEqual(TabularMSA([]), new_np_simple) self.assertEqual(TabularMSA([]), new_list_simple) def test_fancy_standard_first_axis(self): a = DNA("ACGT", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("ACGT", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("ACGT", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c], metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) self.assertEqual(self.get(msa, [0, 2]), TabularMSA([a, c], metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}, index=[0, 2])) def test_fancy_standard_second_axis(self): a = DNA("ACGT", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("ACGT", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("ACGT", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c], metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) self.assertEqual(self.get(msa, (Ellipsis, [0, 2])), TabularMSA([a[0, 2], b[0, 2], c[0, 2]], metadata={3: 3}, positional_metadata={3: [1, 3]}, index=[0, 1, 2])) def test_fancy_standard_both_axes(self): a = DNA("ACGT", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("ACGT", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("ACGT", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c], metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) self.assertEqual(self.get(msa, ([0, 2], [0, 2])), TabularMSA([a[0, 2], c[0, 2]], metadata={3: 3}, positional_metadata={3: [1, 3]}, index=[0, 2])) def test_fancy_empty_first_axis(self): a = DNA("ACGT", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("ACGT", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("ACGT", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c], metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) # TODO: Change for #1198 self.assertEqual(self.get(msa, []), TabularMSA([], metadata={3: 3})) def test_fancy_empty_second_axis(self): a = DNA("ACGT", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("ACGT", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("ACGT", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c], metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) self.assertEqual(self.get(msa, (Ellipsis, [])), TabularMSA([a[0:0], b[0:0], c[0:0]], metadata={3: 3}, positional_metadata={3: np.array( [], dtype=np.int64)})) def test_fancy_empty_both_axes(self): a = DNA("ACGT", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("ACGT", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("ACGT", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c], metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) # TODO: Change for #1198 self.assertEqual(self.get(msa, ([], [])), TabularMSA([], metadata={3: 3})) def test_fancy_out_of_bounds_first_axis(self): msa = TabularMSA([DNA("ACGT"), DNA("GCAT")]) with self.assertRaises(IndexError): self.get(msa, [10]) with self.assertRaises(IndexError): self.get(msa, [0, 1, 10]) def test_fancy_out_of_bounds_second_axis(self): msa = TabularMSA([DNA("ACGT"), DNA("GCAT")]) with self.assertRaises(IndexError): self.get(msa, (Ellipsis, [10])) with self.assertRaises(IndexError): self.get(msa, (Ellipsis, [1, 2, 4])) def test_get_scalar_first_axis(self): a = DNA("AA", metadata={'a': 'foo'}, positional_metadata={'x': [1, 2]}) b = DNA("GG", metadata={'b': 'bar'}, positional_metadata={'y': [3, 4]}) msa = TabularMSA([a, b]) new0 = self.get(msa, 0) new1 = self.get(msa, 1) self.assertEqual(new0, a) self.assertEqual(new1, b) def test_get_scalar_second_axis(self): a = DNA("AA", metadata={'a': 'foo'}, positional_metadata={'x': [1, 2]}) b = DNA("GC", metadata={'b': 'bar'}, positional_metadata={'y': [3, 4]}) msa = TabularMSA([a, b], positional_metadata={'z': [5, 6]}) new0 = self.get(msa, (Ellipsis, 0)) new1 = self.get(msa, (Ellipsis, 1)) self.assertEqual(new0, Sequence("AG", metadata={'z': 5}, positional_metadata={'x': [1, np.nan], 'y': [np.nan, 3]})) self.assertEqual(new1, Sequence("AC", metadata={'z': 6}, positional_metadata={'x': [2, np.nan], 'y': [np.nan, 4]})) def test_scalar_sliced_first_axis(self): a = DNA("ACGT", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("ACGT", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("ACGT", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c], metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) self.assertEqual(self.get(msa, (1, [1, 3])), DNA("CT", metadata={1: 1}, positional_metadata={1: [2, 4]})) def test_scalar_sliced_second_axis(self): a = DNA("ACGT", metadata={0: 0}, positional_metadata={0: [1, 2, 3, 4]}) b = DNA("ACGA", metadata={1: 1}, positional_metadata={1: [1, 2, 3, 4]}) c = DNA("ACGT", metadata={2: 2}, positional_metadata={2: [1, 2, 3, 4]}) msa = TabularMSA([a, b, c], metadata={3: 3}, positional_metadata={3: [1, 2, 3, 4]}) self.assertEqual(self.get(msa, ([1, 2], 3)), Sequence("AT", metadata={3: 4}, positional_metadata={1: [4, np.nan], 2: [np.nan, 4]})) def test_get_scalar_out_of_bound_first_axis(self): a = DNA("AA", metadata={'a': 'foo'}, positional_metadata={'x': [1, 2]}) b = DNA("GC", metadata={'b': 'bar'}, positional_metadata={'y': [3, 4]}) msa = TabularMSA([a, b], positional_metadata={'z': [5, 6]}) with self.assertRaises(IndexError): self.get(msa, 3) def test_get_scalar_out_of_bound_second_axis(self): a = DNA("AA", metadata={'a': 'foo'}, positional_metadata={'x': [1, 2]}) b = DNA("GC", metadata={'b': 'bar'}, positional_metadata={'y': [3, 4]}) msa = TabularMSA([a, b], positional_metadata={'z': [5, 6]}) with self.assertRaises(IndexError): self.get(msa, (Ellipsis, 3)) class TestGetItem(SharedIndexTests, unittest.TestCase): def get(self, obj, indexable): return obj[indexable] def test_uses_iloc_not_loc(self): a = DNA("ACGA") b = DNA("ACGT") msa = TabularMSA([a, b], index=[1, 0]) self.assertIs(msa[0], a) self.assertIs(msa[1], b) class TestConstructor(unittest.TestCase): def setUp(self): self.seqs = [DNA("ACGT"), DNA("GCTA")] self.m = {'x': 'y', 0: 1} self.pm = pd.DataFrame({'foo': [1, 2, 3, 4]}) self.index = pd.Index(['a', 'b']) self.msa = TabularMSA(self.seqs, metadata=self.m, positional_metadata=self.pm, index=self.index) def test_no_override(self): result = self.msa._constructor_() self.assertEqual(self.msa, result) for seq1, seq2 in zip(result, self.msa): self.assertIsNot(seq1, seq2) self.assertIsNot(result.metadata, self.msa.metadata) self.assertIsNot(result.positional_metadata, self.msa.positional_metadata) def test_sequence_override_same_seqs(self): result = self.msa._constructor_(sequences=self.seqs) self.assertEqual(self.msa, result) for seq1, seq2 in zip(result, self.msa): self.assertIsNot(seq1, seq2) self.assertIsNot(result.metadata, self.msa.metadata) self.assertIsNot(result.positional_metadata, self.msa.positional_metadata) def test_sequence_override(self): seqs = [RNA("ACGU"), RNA("GCUA")] result = self.msa._constructor_(sequences=seqs) self.assertNotEqual(result, self.msa) self.assertEqual(list(result), seqs) assert_index_equal(result.index, self.index) self.assertEqual(result.metadata, self.m) assert_data_frame_almost_equal(result.positional_metadata, self.pm) def test_no_override_no_md(self): msa = TabularMSA(self.seqs, index=self.index) self.assertEqual(msa, msa._constructor_()) def test_metadata_override(self): new_md = {'foo': {'x': 0}} result = self.msa._constructor_(metadata=new_md) self.assertNotEqual(result, self.msa) self.assertEqual(list(result), self.seqs) assert_index_equal(result.index, self.index) self.assertEqual(result.metadata, new_md) assert_data_frame_almost_equal(result.positional_metadata, self.pm) def test_positional_metadata_override(self): new_pm = pd.DataFrame({'x': [1, 2, 3, 4]}) result = self.msa._constructor_(positional_metadata=new_pm) self.assertNotEqual(result, self.msa) self.assertEqual(list(result), self.seqs) assert_index_equal(result.index, self.index) self.assertEqual(result.metadata, self.m) assert_data_frame_almost_equal(result.positional_metadata, new_pm) def test_index_override(self): new_index = pd.Index([('a', 0), ('b', 1)]) result = self.msa._constructor_(index=new_index) self.assertNotEqual(result, self.msa) self.assertEqual(list(result), self.seqs) assert_index_equal(result.index, new_index) self.assertEqual(result.metadata, self.m) assert_data_frame_almost_equal(result.positional_metadata, self.pm) class TestAppend(unittest.TestCase): # Error cases def test_invalid_minter_index_reset_index_parameter_combos(self): msa = TabularMSA([]) param_combos = ( {}, {'minter': str, 'index': 'foo', 'reset_index': True}, {'minter': str, 'index': 'foo'}, {'minter': str, 'reset_index': True}, {'index': 'foo', 'reset_index': True} ) for params in param_combos: with self.assertRaisesRegex(ValueError, r"one of.*minter.*index.*reset_index"): msa.append(DNA('ACGT'), **params) self.assertEqual(msa, TabularMSA([])) def test_invalid_dtype(self): msa = TabularMSA([]) with self.assertRaisesRegex(TypeError, r'GrammaredSequence.*Sequence'): msa.append(Sequence(''), reset_index=True) self.assertEqual(msa, TabularMSA([])) def test_dtype_mismatch_rna(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')]) with self.assertRaisesRegex(TypeError, r'matching type.*RNA.*DNA'): msa.append(RNA('UUUU'), reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT'), DNA('TGCA')])) def test_dtype_mismatch_float(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')]) with self.assertRaisesRegex(TypeError, r'matching type.*float.*DNA'): msa.append(42.0, reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT'), DNA('TGCA')])) def test_length_mismatch(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')]) with self.assertRaisesRegex( ValueError, r'must match the number of positions.*5 != 4'): msa.append(DNA('ACGTA'), reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT'), DNA('TGCA')])) def test_invalid_minter(self): msa = TabularMSA([DNA('ACGT')], index=['foo']) with self.assertRaises(KeyError): msa.append(DNA('AAAA'), minter='id') self.assertEqual(msa, TabularMSA([DNA('ACGT')], index=['foo'])) # Valid cases: `minter` def test_minter_empty_msa(self): msa = TabularMSA([]) msa.append(DNA('ACGT'), minter=str) self.assertEqual(msa, TabularMSA([DNA('ACGT')], minter=str)) def test_minter_metadata_key(self): msa = TabularMSA([DNA('', metadata={'id': 'a'}), DNA('', metadata={'id': 'b'})], minter='id') msa.append(DNA('', metadata={'id': 'c'}), minter='id') self.assertEqual( msa, TabularMSA([ DNA('', metadata={'id': 'a'}), DNA('', metadata={'id': 'b'}), DNA('', metadata={'id': 'c'})], minter='id')) def test_minter_callable(self): msa = TabularMSA([DNA('', metadata={'id': 'a'}), DNA('', metadata={'id': 'b'})], minter='id') msa.append(DNA(''), minter=str) self.assertEqual( msa, TabularMSA([ DNA('', metadata={'id': 'a'}), DNA('', metadata={'id': 'b'}), DNA('')], index=['a', 'b', ''])) def test_multiindex_minter_empty_msa(self): def multiindex_minter(seq): return ('foo', 42) msa = TabularMSA([]) msa.append(DNA('AC'), minter=multiindex_minter) self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal(msa.index, pd.Index([('foo', 42)])) def test_multiindex_minter_non_empty_msa(self): def multiindex_minter(seq): return ('baz', 44) msa = TabularMSA([RNA('UU'), RNA('CA')], index=[('foo', 42), ('bar', 43)]) msa.append(RNA('AC'), minter=multiindex_minter) self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal(msa.index, pd.Index([('foo', 42), ('bar', 43), ('baz', 44)])) # Valid cases: `index` def test_index_empty_msa(self): msa = TabularMSA([]) msa.append(DNA('ACGT'), index='a') self.assertEqual( msa, TabularMSA([DNA('ACGT')], index=['a'])) def test_index_non_empty_msa(self): msa = TabularMSA([DNA('AC'), DNA('GT')], index=['a', 'b']) msa.append(DNA('--'), index='foo') self.assertEqual( msa, TabularMSA([DNA('AC'), DNA('GT'), DNA('--')], index=['a', 'b', 'foo'])) def test_multiindex_index_empty_msa(self): msa = TabularMSA([]) msa.append(DNA('AA'), index=('foo', 42)) self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal(msa.index, pd.Index([('foo', 42)])) def test_multiindex_index_non_empty_msa(self): msa = TabularMSA([RNA('A'), RNA('C')], index=[('foo', 42), ('bar', 43)]) msa.append(RNA('U'), index=('baz', 44)) self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal(msa.index, pd.Index([('foo', 42), ('bar', 43), ('baz', 44)])) # Valid cases: `reset_index` def test_reset_index_empty_msa(self): msa = TabularMSA([]) msa.append(DNA('ACGT'), reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT')])) assert_index_equal(msa.index, pd.RangeIndex(1)) def test_reset_index_default_index(self): msa = TabularMSA([DNA('ACGT'), DNA('CCCC')]) msa.append(DNA('ACGT'), reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT'), DNA('CCCC'), DNA('ACGT')])) assert_index_equal(msa.index, pd.RangeIndex(3)) def test_reset_index_non_default_index(self): msa = TabularMSA([DNA('ACGT'), DNA('CCCC')], index=['foo', 'bar']) msa.append(DNA('ACGT'), reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT'), DNA('CCCC'), DNA('ACGT')])) assert_index_equal(msa.index, pd.RangeIndex(3)) def test_reset_index_bool_cast(self): msa = TabularMSA([RNA('AC'), RNA('UU')], index=[42, 43]) msa.append(RNA('..'), reset_index='abc') self.assertEqual(msa, TabularMSA([RNA('AC'), RNA('UU'), RNA('..')])) assert_index_equal(msa.index, pd.RangeIndex(3)) # Valid cases (misc) def test_index_type_change(self): msa = TabularMSA([DNA('A'), DNA('.')]) msa.append(DNA('C'), index='foo') self.assertEqual( msa, TabularMSA([DNA('A'), DNA('.'), DNA('C')], index=[0, 1, 'foo'])) def test_duplicate_index(self): msa = TabularMSA([DNA('A'), DNA('.')], index=['foo', 'bar']) msa.append(DNA('C'), index='foo') self.assertEqual( msa, TabularMSA([DNA('A'), DNA('.'), DNA('C')], index=['foo', 'bar', 'foo'])) def test_empty_msa_with_positional_metadata_no_new_positions(self): msa = TabularMSA([], positional_metadata={'foo': []}) msa.append(DNA(''), reset_index=True) self.assertEqual( msa, TabularMSA([DNA('')], positional_metadata={'foo': []})) def test_empty_msa_with_positional_metadata_add_new_positions(self): # bug in 0.4.2 msa = TabularMSA([], positional_metadata={'foo': []}) msa.append(DNA('AA'), reset_index=True) self.assertEqual( msa, TabularMSA([DNA('AA')])) class TestExtend(unittest.TestCase): # Error cases # # Note: these tests check that the MSA isn't mutated when an error is # raised. Where applicable, the "invalid" sequence is preceded by valid # sequence(s) to test one possible (buggy) implementation of `extend`: # looping over `sequences` and calling `append`. These tests ensure that # valid sequences aren't appended to the MSA before the error is raised. def test_invalid_minter_index_reset_index_parameter_combos(self): msa = TabularMSA([]) param_combos = ( {}, {'minter': str, 'index': 'foo', 'reset_index': True}, {'minter': str, 'index': 'foo'}, {'minter': str, 'reset_index': True}, {'index': 'foo', 'reset_index': True} ) for params in param_combos: with self.assertRaisesRegex(ValueError, r"one of.*minter.*index.*reset_index"): msa.extend([DNA('ACGT')], **params) self.assertEqual(msa, TabularMSA([])) def test_from_tabular_msa_index_param_still_required(self): msa = TabularMSA([DNA('AC'), DNA('TG')]) with self.assertRaisesRegex(ValueError, r"one of.*minter.*index.*reset_index"): msa.extend(TabularMSA([DNA('GG'), DNA('CC')])) self.assertEqual(msa, TabularMSA([DNA('AC'), DNA('TG')])) def test_invalid_dtype(self): msa = TabularMSA([]) with self.assertRaisesRegex(TypeError, r'GrammaredSequence.*Sequence'): msa.extend([Sequence('')], reset_index=True) self.assertEqual(msa, TabularMSA([])) def test_dtype_mismatch_rna(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')]) with self.assertRaisesRegex(TypeError, r'matching type.*RNA.*DNA'): msa.extend([DNA('----'), RNA('UUUU')], reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT'), DNA('TGCA')])) def test_dtype_mismatch_float(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')]) with self.assertRaisesRegex(TypeError, r'matching type.*float.*DNA'): msa.extend([DNA('GGGG'), 42.0], reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT'), DNA('TGCA')])) def test_length_mismatch(self): msa = TabularMSA([DNA('ACGT'), DNA('TGCA')]) with self.assertRaisesRegex( ValueError, r'must match the number of positions.*5 != 4'): msa.extend([DNA('TTTT'), DNA('ACGTA')], reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT'), DNA('TGCA')])) def test_invalid_minter(self): msa = TabularMSA([DNA('ACGT')], index=['foo']) with self.assertRaises(KeyError): msa.extend([DNA('AAAA', metadata={'id': 'foo'}), DNA('----')], minter='id') self.assertEqual(msa, TabularMSA([DNA('ACGT')], index=['foo'])) def test_invalid_index(self): msa = TabularMSA([DNA('ACGT')], index=['foo']) with self.assertRaises(TypeError): msa.extend([DNA('----')], index=42) self.assertEqual(msa, TabularMSA([DNA('ACGT')], index=['foo'])) def test_sequences_index_length_mismatch(self): msa = TabularMSA([]) with self.assertRaisesRegex(ValueError, r'sequences.*2.*index length.*3'): msa.extend([DNA('TTTT'), DNA('ACGT')], index=['a', 'b', 'c']) self.assertEqual(msa, TabularMSA([])) # Valid cases: `minter` def test_minter_empty_msa(self): msa = TabularMSA([]) msa.extend([RNA('UU'), RNA('--')], minter=str) self.assertEqual(msa, TabularMSA([RNA('UU'), RNA('--')], minter=str)) def test_minter_metadata_key(self): msa = TabularMSA([DNA('', metadata={'id': 'a'}), DNA('', metadata={'id': 'b'})], minter='id') msa.extend([DNA('', metadata={'id': 'c'}), DNA('', metadata={'id': 'd'})], minter='id') self.assertEqual( msa, TabularMSA([ DNA('', metadata={'id': 'a'}), DNA('', metadata={'id': 'b'}), DNA('', metadata={'id': 'c'}), DNA('', metadata={'id': 'd'})], minter='id')) def test_minter_callable(self): msa = TabularMSA([DNA('A', metadata={'id': 'a'}), DNA('C', metadata={'id': 'b'})], minter='id') msa.extend([DNA('G'), DNA('T')], minter=str) self.assertEqual( msa, TabularMSA([ DNA('A', metadata={'id': 'a'}), DNA('C', metadata={'id': 'b'}), DNA('G'), DNA('T')], index=['a', 'b', 'G', 'T'])) def test_multiindex_minter_empty_msa(self): def multiindex_minter(seq): if str(seq) == 'AC': return ('foo', 42) else: return ('bar', 43) msa = TabularMSA([]) msa.extend([DNA('AC'), DNA('GG')], minter=multiindex_minter) self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal(msa.index, pd.Index([('foo', 42), ('bar', 43)])) def test_multiindex_minter_non_empty_msa(self): def multiindex_minter(seq): if str(seq) == 'C': return ('baz', 44) else: return ('baz', 45) msa = TabularMSA([DNA('A'), DNA('G')], index=[('foo', 42), ('bar', 43)]) msa.extend([DNA('C'), DNA('T')], minter=multiindex_minter) self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal( msa.index, pd.Index([('foo', 42), ('bar', 43), ('baz', 44), ('baz', 45)])) # Valid cases: `index` def test_index_empty_msa(self): msa = TabularMSA([]) msa.extend([RNA('UAC'), RNA('AAU')], index=['foo', 'bar']) self.assertEqual(msa, TabularMSA([RNA('UAC'), RNA('AAU')], index=['foo', 'bar'])) def test_index_non_empty_msa(self): msa = TabularMSA([DNA('AC'), DNA('GT')], index=['a', 'b']) msa.extend([DNA('--'), DNA('..')], index=['foo', 'bar']) self.assertEqual( msa, TabularMSA([DNA('AC'), DNA('GT'), DNA('--'), DNA('..')], index=['a', 'b', 'foo', 'bar'])) def test_multiindex_index_empty_msa(self): msa = TabularMSA([]) msa.extend([DNA('AA'), DNA('GG')], index=[('foo', 42), ('bar', 43)]) self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal(msa.index, pd.Index([('foo', 42), ('bar', 43)])) def test_multiindex_index_non_empty_msa(self): msa = TabularMSA([DNA('.'), DNA('-')], index=[('foo', 42), ('bar', 43)]) msa.extend([DNA('A'), DNA('G')], index=[('baz', 44), ('baz', 45)]) self.assertIsInstance(msa.index, pd.MultiIndex) assert_index_equal( msa.index, pd.Index([('foo', 42), ('bar', 43), ('baz', 44), ('baz', 45)])) def test_index_object_empty_msa(self): msa = TabularMSA([]) msa.extend([DNA('AA'), DNA('GG')], index=pd.RangeIndex(2)) self.assertEqual(msa, TabularMSA([DNA('AA'), DNA('GG')])) assert_index_equal(msa.index, pd.RangeIndex(2)) def test_index_object_non_empty_msa(self): msa = TabularMSA([DNA('CT'), DNA('GG')]) msa.extend([DNA('AA'), DNA('GG')], index=pd.RangeIndex(2)) self.assertEqual( msa, TabularMSA([DNA('CT'), DNA('GG'), DNA('AA'), DNA('GG')], index=[0, 1, 0, 1])) # Valid cases: `reset_index` def test_reset_index_empty_msa(self): msa = TabularMSA([]) msa.extend([DNA('ACGT'), DNA('----')], reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT'), DNA('----')])) assert_index_equal(msa.index, pd.RangeIndex(2)) def test_reset_index_empty_msa_empty_iterable(self): msa = TabularMSA([]) msa.extend([], reset_index=True) self.assertEqual(msa, TabularMSA([])) assert_index_equal(msa.index, pd.RangeIndex(0)) def test_reset_index_non_empty_msa_empty_iterable(self): msa = TabularMSA([RNA('UU'), RNA('CC')], index=['a', 'b']) msa.extend([], reset_index=True) self.assertEqual(msa, TabularMSA([RNA('UU'), RNA('CC')])) assert_index_equal(msa.index, pd.RangeIndex(2)) def test_reset_index_default_index(self): msa = TabularMSA([DNA('A'), DNA('G')]) msa.extend([DNA('.'), DNA('-')], reset_index=True) self.assertEqual(msa, TabularMSA([DNA('A'), DNA('G'), DNA('.'), DNA('-')])) assert_index_equal(msa.index, pd.RangeIndex(4)) def test_reset_index_non_default_index(self): msa = TabularMSA([DNA('A'), DNA('G')], index=['a', 'b']) msa.extend([DNA('.'), DNA('-')], reset_index=True) self.assertEqual(msa, TabularMSA([DNA('A'), DNA('G'), DNA('.'), DNA('-')])) assert_index_equal(msa.index, pd.RangeIndex(4)) def test_reset_index_from_tabular_msa(self): msa = TabularMSA([DNA('AC'), DNA('TG')], index=[42, 43]) msa.extend(TabularMSA([DNA('GG'), DNA('CC'), DNA('AA')], index=['a', 'b', 'c']), reset_index=True) self.assertEqual( msa, TabularMSA([DNA('AC'), DNA('TG'), DNA('GG'), DNA('CC'), DNA('AA')])) assert_index_equal(msa.index, pd.RangeIndex(5)) def test_reset_index_bool_cast(self): msa = TabularMSA([RNA('AC'), RNA('UU')], index=[42, 43]) msa.extend([RNA('..')], reset_index='abc') self.assertEqual(msa, TabularMSA([RNA('AC'), RNA('UU'), RNA('..')])) assert_index_equal(msa.index, pd.RangeIndex(3)) # Valid cases (misc) def test_index_type_change(self): msa = TabularMSA([DNA('A'), DNA('.')]) msa.extend([DNA('C')], index=['foo']) self.assertEqual( msa, TabularMSA([DNA('A'), DNA('.'), DNA('C')], index=[0, 1, 'foo'])) def test_duplicate_index(self): msa = TabularMSA([DNA('A'), DNA('.')], index=['foo', 'bar']) msa.extend([DNA('C'), DNA('.')], index=['foo', 'baz']) self.assertEqual( msa, TabularMSA([DNA('A'), DNA('.'), DNA('C'), DNA('.')], index=['foo', 'bar', 'foo', 'baz'])) def test_empty_msa_with_positional_metadata_no_new_positions(self): msa = TabularMSA([], positional_metadata={'foo': []}) msa.extend([DNA(''), DNA('')], reset_index=True) self.assertEqual( msa, TabularMSA([DNA(''), DNA('')], positional_metadata={'foo': []})) def test_empty_msa_with_positional_metadata_add_new_positions(self): # bug in 0.4.2 msa = TabularMSA([], positional_metadata={'foo': []}) msa.extend([DNA('AA'), DNA('GG')], reset_index=True) self.assertEqual( msa, TabularMSA([DNA('AA'), DNA('GG')])) def test_empty_msa_empty_iterable(self): msa = TabularMSA([]) msa.extend([], minter=str) self.assertEqual(msa, TabularMSA([])) def test_non_empty_msa_empty_iterable(self): msa = TabularMSA([DNA('AC')], index=['foo']) msa.extend([], index=[]) self.assertEqual(msa, TabularMSA([DNA('AC')], index=['foo'])) def test_single_sequence(self): msa = TabularMSA([DNA('AC')]) msa.extend([DNA('-C')], minter=str) self.assertEqual(msa, TabularMSA([DNA('AC'), DNA('-C')], index=[0, '-C'])) def test_multiple_sequences(self): msa = TabularMSA([DNA('AC')]) msa.extend([DNA('-C'), DNA('AG')], minter=str) self.assertEqual(msa, TabularMSA([DNA('AC'), DNA('-C'), DNA('AG')], index=[0, '-C', 'AG'])) def test_from_iterable(self): msa = TabularMSA([]) msa.extend(iter([DNA('ACGT'), DNA('TGCA')]), reset_index=True) self.assertEqual(msa, TabularMSA([DNA('ACGT'), DNA('TGCA')])) def test_from_tabular_msa_with_index(self): msa1 = TabularMSA([DNA('AC'), DNA('TG')]) msa2 = TabularMSA([DNA('GG'), DNA('CC'), DNA('AA')]) msa1.extend(msa2, index=msa2.index) self.assertEqual( msa1, TabularMSA([DNA('AC'), DNA('TG'), DNA('GG'), DNA('CC'), DNA('AA')], index=[0, 1, 0, 1, 2])) class TestJoin(unittest.TestCase): def assertEqualJoinedMSA(self, msa1, msa2): # `TabularMSA.join` doesn't guarantee index order in the joined MSA. # The order differs across pandas versions, so sort each MSA before # comparing for equality. # copy because `TabularMSA.sort` is in-place. msa1 = copy.copy(msa1) msa2 = copy.copy(msa2) msa1.sort() msa2.sort() self.assertEqual(msa1, msa2) def test_invalid_how(self): with self.assertRaisesRegex(ValueError, r'`how`'): TabularMSA([]).join(TabularMSA([]), how='really') def test_invalid_other_type(self): with self.assertRaisesRegex(TypeError, r'TabularMSA.*DNA'): TabularMSA([]).join(DNA('ACGT')) def test_dtype_mismatch(self): with self.assertRaisesRegex(TypeError, r'dtype.*RNA.*DNA'): TabularMSA([DNA('AC')]).join(TabularMSA([RNA('UG')])) with self.assertRaisesRegex(TypeError, r'dtype.*None.*DNA'): TabularMSA([DNA('AC')]).join(TabularMSA([])) with self.assertRaisesRegex(TypeError, r'dtype.*DNA.*None'): TabularMSA([]).join(TabularMSA([DNA('AC')])) def test_duplicate_index_labels(self): with self.assertRaisesRegex(ValueError, r"This MSA's index labels.*unique"): TabularMSA([DNA('AC'), DNA('--')], index=[0, 0]).join( TabularMSA([DNA('GT'), DNA('..')])) with self.assertRaisesRegex(ValueError, r"`other`'s index labels.*unique"): TabularMSA([DNA('AC'), DNA('--')]).join( TabularMSA([DNA('GT'), DNA('..')], index=[0, 0])) def test_no_metadata(self): msa1 = TabularMSA([DNA('AC'), DNA('G.')]) msa2 = TabularMSA([DNA('-C'), DNA('.G')]) joined = msa1.join(msa2) self.assertEqualJoinedMSA( joined, TabularMSA([DNA('AC-C'), DNA('G..G')])) def test_ignores_metadata(self): msa1 = TabularMSA([DNA('AC', metadata={'id': 'a'}), DNA('G.', metadata={'id': 'b'}), DNA('C-', metadata={'id': 'c'})], metadata={'id': 'msa1'}) msa2 = TabularMSA([DNA('-C', metadata={'id': 'd'}), DNA('.G', metadata={'id': 'e'}), DNA('CA', metadata={'id': 'f'})], index=[2, 1, 0], metadata={'id': 'msa2'}) joined = msa1.join(msa2) self.assertEqualJoinedMSA( joined, TabularMSA([DNA('ACCA'), DNA('G..G'), DNA('C--C')])) def test_outer_join_on_per_sequence_positional_metadata(self): msa1 = TabularMSA([ DNA('AC', positional_metadata={'1': [1, 2], 'foo': ['a', 'b']}), DNA('GT', positional_metadata={'2': [3, 4], 'foo': ['c', 'd']})]) msa2 = TabularMSA([ DNA('CA', positional_metadata={'3': [5, 6], 'foo': ['e', 'f']}), DNA('TG', positional_metadata={'4': [7, 8], 'foo': ['g', 'h']})]) joined = msa1.join(msa2) self.assertEqualJoinedMSA( joined, TabularMSA([ DNA('ACCA', positional_metadata={'1': [1, 2, np.nan, np.nan], '3': [np.nan, np.nan, 5, 6], 'foo': ['a', 'b', 'e', 'f']}), DNA('GTTG', positional_metadata={'2': [3, 4, np.nan, np.nan], '4': [np.nan, np.nan, 7, 8], 'foo': ['c', 'd', 'g', 'h']})])) def test_no_sequences(self): msa1 = TabularMSA([], positional_metadata={'foo': []}) msa2 = TabularMSA([], positional_metadata={'foo': []}) joined = msa1.join(msa2) self.assertEqualJoinedMSA(joined, TabularMSA([])) def test_no_positions(self): msa1 = TabularMSA([DNA('', positional_metadata={'1': []}), DNA('', positional_metadata={'2': []})], positional_metadata={'foo': []}) msa2 = TabularMSA([DNA('', positional_metadata={'3': []}), DNA('', positional_metadata={'4': []})], positional_metadata={'foo': []}) joined = msa1.join(msa2) self.assertEqualJoinedMSA( joined, TabularMSA([DNA('', positional_metadata={'1': [], '3': []}), DNA('', positional_metadata={'2': [], '4': []})], positional_metadata={'foo': []})) def test_one_with_positions_one_without_positions(self): msa1 = TabularMSA([DNA('A', positional_metadata={'1': ['a']}), DNA('C', positional_metadata={'2': ['b']})], positional_metadata={'foo': ['bar']}) msa2 = TabularMSA([DNA('', positional_metadata={'3': []}), DNA('', positional_metadata={'4': []})], positional_metadata={'foo': []}) joined = msa1.join(msa2) self.assertEqualJoinedMSA( joined, TabularMSA([DNA('A', positional_metadata={'1': ['a'], '3': [np.nan]}), DNA('C', positional_metadata={'2': ['b'], '4': [np.nan]})], positional_metadata={'foo': ['bar']})) def test_how_strict(self): msa1 = TabularMSA([DNA('AC'), DNA('G.'), DNA('C-')], positional_metadata={'foo': [1, 2], 'bar': ['a', 'b']}) msa2 = TabularMSA([DNA('-C'), DNA('.G'), DNA('CA')], index=[2, 1, 0], positional_metadata={'foo': [3, 4], 'bar': ['c', 'd']}) joined = msa1.join(msa2) self.assertEqualJoinedMSA( joined, TabularMSA([DNA('ACCA'), DNA('G..G'), DNA('C--C')], positional_metadata={'bar': ['a', 'b', 'c', 'd'], 'foo': [1, 2, 3, 4]})) def test_how_strict_failure_index_mismatch(self): msa1 = TabularMSA([DNA('AC'), DNA('G.'), DNA('C-')]) msa2 = TabularMSA([DNA('-C'), DNA('.G'), DNA('CA'), DNA('--')]) with self.assertRaisesRegex(ValueError, r'Index labels must all ' 'match'): msa1.join(msa2) def test_how_strict_failure_positional_metadata_mismatch(self): msa1 = TabularMSA([DNA('AC'), DNA('G.')], positional_metadata={'foo': [1, 2], 'bar': ['a', 'b']}) msa2 = TabularMSA([DNA('-C'), DNA('.G')], positional_metadata={'foo': [3, 4]}) with self.assertRaisesRegex(ValueError, r'Positional metadata columns.*match'): msa1.join(msa2) def test_how_inner(self): msa1 = TabularMSA([DNA('AC'), DNA('G.'), DNA('C-'), DNA('--')], index=[0, 1, 2, 3], positional_metadata={'foo': [1, 2], 'bar': ['a', 'b']}) msa2 = TabularMSA([DNA('-C'), DNA('.G'), DNA('CA'), DNA('..')], index=[2, 1, 0, -1], positional_metadata={'foo': [3, 4], 'baz': ['c', 'd']}) joined = msa1.join(msa2, how='inner') self.assertEqualJoinedMSA( joined, TabularMSA([DNA('C--C'), DNA('G..G'), DNA('ACCA')], index=[2, 1, 0], positional_metadata={'foo': [1, 2, 3, 4]})) def test_how_inner_no_positional_metadata_overlap(self): msa1 = TabularMSA([DNA('AC'), DNA('G.')], index=['b', 'a'], positional_metadata={'foo': [1, 2]}) msa2 = TabularMSA([DNA('-C'), DNA('.G')], index=['a', 'b'], positional_metadata={'bar': ['c', 'd']}) joined = msa1.join(msa2, how='inner') self.assertEqualJoinedMSA( joined, TabularMSA([DNA('G.-C'), DNA('AC.G')], index=['a', 'b'])) def test_how_inner_no_index_overlap_with_positional_metadata_overlap(self): msa1 = TabularMSA([DNA('AC'), DNA('G.')], positional_metadata={'foo': [1, 2]}) msa2 = TabularMSA([DNA('-C'), DNA('.G')], index=['a', 'b'], positional_metadata={'foo': [3, 4]}) joined = msa1.join(msa2, how='inner') self.assertEqualJoinedMSA(joined, TabularMSA([])) def test_how_outer(self): msa1 = TabularMSA([DNA('AC'), DNA('G.'), DNA('C-'), DNA('--')], index=[0, 1, 2, 3], positional_metadata={'foo': [1, 2], 'bar': ['a', 'b']}) msa2 = TabularMSA([DNA('-CC'), DNA('.GG'), DNA('CAA'), DNA('...')], index=[2, 1, 0, -1], positional_metadata={'foo': [3, 4, 5], 'baz': ['c', 'd', 'e']}) joined = msa1.join(msa2, how='outer') self.assertEqualJoinedMSA( joined, TabularMSA([DNA('--...'), DNA('ACCAA'), DNA('G..GG'), DNA('C--CC'), DNA('-----')], index=range(-1, 4), positional_metadata={ 'bar': ['a', 'b', np.nan, np.nan, np.nan], 'baz': [np.nan, np.nan, 'c', 'd', 'e'], 'foo': [1, 2, 3, 4, 5]})) def test_how_left(self): msa1 = TabularMSA([DNA('AC'), DNA('G.'), DNA('C-'), DNA('--')], index=[0, 1, 2, 3], positional_metadata={'foo': [1, 2], 'bar': ['a', 'b']}) msa2 = TabularMSA([DNA('-CC'), DNA('.GG'), DNA('CAA'), DNA('...')], index=[2, 1, 0, -1], positional_metadata={'foo': [3, 4, 5], 'baz': ['c', 'd', 'e']}) joined = msa1.join(msa2, how='left') self.assertEqualJoinedMSA( joined, TabularMSA([DNA('ACCAA'), DNA('G..GG'), DNA('C--CC'), DNA('-----')], positional_metadata={ 'foo': [1, 2, 3, 4, 5], 'bar': ['a', 'b', np.nan, np.nan, np.nan]})) def test_how_right(self): msa1 = TabularMSA([DNA('AC'), DNA('G.'), DNA('C-'), DNA('--')], index=[0, 1, 2, 3], positional_metadata={'foo': [1, 2], 'bar': ['a', 'b']}) msa2 = TabularMSA([DNA('-CC'), DNA('.GG'), DNA('CAA'), DNA('...')], index=[2, 1, 0, -1], positional_metadata={'foo': [3, 4, 5], 'baz': ['c', 'd', 'e']}) joined = msa1.join(msa2, how='right') self.assertEqualJoinedMSA( joined, TabularMSA([DNA('C--CC'), DNA('G..GG'), DNA('ACCAA'), DNA('--...')], index=[2, 1, 0, -1], positional_metadata={ 'foo': [1, 2, 3, 4, 5], 'baz': [np.nan, np.nan, 'c', 'd', 'e']})) class TestIterPositions(unittest.TestCase): def test_method_return_type(self): msa = TabularMSA([DNA('AC'), DNA('GT')]) obs = msa.iter_positions() self.assertIsInstance(obs, types.GeneratorType) def test_position_type(self): msa = TabularMSA([DNA('AC'), DNA('GT')]) first_position = next(msa.iter_positions()) # Type should be *exactly* Sequence. self.assertIs(type(first_position), Sequence) def test_no_sequences(self): msa = TabularMSA([]) obs = list(msa.iter_positions()) self.assertEqual(obs, []) def test_no_sequences_ignore_metadata(self): msa = TabularMSA([]) obs = list(msa.iter_positions(ignore_metadata=True)) self.assertEqual(obs, []) def test_no_sequences_reverse(self): msa = TabularMSA([]) obs = list(msa.iter_positions(reverse=True)) self.assertEqual(obs, []) def test_no_sequences_reverse_ignore_metadata(self): msa = TabularMSA([]) obs = list(msa.iter_positions(reverse=True, ignore_metadata=True)) self.assertEqual(obs, []) def test_no_positions(self): msa = TabularMSA([DNA(''), DNA('')]) obs = list(msa.iter_positions()) self.assertEqual(obs, []) def test_no_positions_ignore_metadata(self): msa = TabularMSA([DNA(''), DNA('')]) obs = list(msa.iter_positions(ignore_metadata=True)) self.assertEqual(obs, []) def test_no_positions_reverse(self): msa = TabularMSA([DNA(''), DNA('')]) obs = list(msa.iter_positions(reverse=True)) self.assertEqual(obs, []) def test_no_positions_reverse_ignore_metadata(self): msa = TabularMSA([DNA(''), DNA('')]) obs = list(msa.iter_positions(reverse=True, ignore_metadata=True)) self.assertEqual(obs, []) def test_single_position(self): msa = TabularMSA([DNA('A')]) obs = list(msa.iter_positions()) self.assertEqual(obs, [Sequence('A')]) def test_single_position_reverse(self): msa = TabularMSA([DNA('A'), DNA('T')]) obs = list(msa.iter_positions(reverse=True)) self.assertEqual(obs, [Sequence('AT')]) def test_multiple_positions(self): msa = TabularMSA([DNA('ACGT'), DNA('A-G.'), DNA('----')]) obs = list(msa.iter_positions()) self.assertEqual(obs, [Sequence('AA-'), Sequence('C--'), Sequence('GG-'), Sequence('T.-')]) def test_multiple_positions_reverse(self): msa = TabularMSA([DNA('AC'), DNA('A-'), DNA('--')]) obs = list(msa.iter_positions(reverse=True)) self.assertEqual(obs, [Sequence('C--'), Sequence('AA-')]) def test_with_positional_metadata(self): # MSA *and* sequence positional metadata. msa_positional_metadata = {'pm1': [0.5, 1.5], 'foo': [9, 99]} seqs = [ DNA('AC', positional_metadata={'foo': [42, 43]}), DNA('A-'), DNA('--', positional_metadata={'foo': [-1, -2], 'bar': ['baz', 'bazz']})] msa = TabularMSA(seqs, positional_metadata=msa_positional_metadata) obs = list(msa.iter_positions()) self.assertEqual( obs, [Sequence('AA-', metadata={'pm1': 0.5, 'foo': 9}, positional_metadata={'bar': [np.nan, np.nan, 'baz'], 'foo': [42, np.nan, -1]}), Sequence('C--', metadata={'pm1': 1.5, 'foo': 99}, positional_metadata={'bar': [np.nan, np.nan, 'bazz'], 'foo': [43, np.nan, -2]})]) def test_with_positional_metadata_reverse(self): # MSA *and* sequence positional metadata. msa_positional_metadata = {'pm1': [0.5, 1.5], 'foo': [9, 99]} seqs = [ DNA('AC', positional_metadata={'foo': [42, 43]}), DNA('A-'), DNA('--', positional_metadata={'foo': [-1, -2], 'bar': ['baz', 'bazz']})] msa = TabularMSA(seqs, positional_metadata=msa_positional_metadata) obs = list(msa.iter_positions(reverse=True)) self.assertEqual( obs, [Sequence('C--', metadata={'pm1': 1.5, 'foo': 99}, positional_metadata={'bar': [np.nan, np.nan, 'bazz'], 'foo': [43, np.nan, -2]}), Sequence('AA-', metadata={'pm1': 0.5, 'foo': 9}, positional_metadata={'bar': [np.nan, np.nan, 'baz'], 'foo': [42, np.nan, -1]})]) def test_with_positional_metadata_ignore_metadata(self): # MSA *and* sequence positional metadata. msa_positional_metadata = {'pm1': [0.5, 1.5], 'foo': [9, 99]} seqs = [ DNA('AC', positional_metadata={'foo': [42, 43]}), DNA('A-'), DNA('--', positional_metadata={'foo': [-1, -2], 'bar': ['baz', 'bazz']})] msa = TabularMSA(seqs, positional_metadata=msa_positional_metadata) obs = list(msa.iter_positions(ignore_metadata=True)) self.assertEqual(obs, [Sequence('AA-'), Sequence('C--')]) class TestConsensus(unittest.TestCase): def test_no_sequences(self): msa = TabularMSA([]) cons = msa.consensus() self.assertEqual(cons, Sequence('')) def test_no_positions(self): msa = TabularMSA([DNA(''), DNA('')]) cons = msa.consensus() self.assertEqual(cons, DNA('')) def test_single_sequence(self): msa = TabularMSA([DNA('ACGT-.')]) cons = msa.consensus() self.assertEqual(cons, DNA('ACGT--')) def test_multiple_sequences(self): msa = TabularMSA([DNA('ACGT'), DNA('AG-.'), DNA('AC-.')]) cons = msa.consensus() self.assertEqual(cons, DNA('AC--')) def test_ties(self): msa = TabularMSA([DNA('A-'), DNA('C-'), DNA('G-')]) cons = msa.consensus() self.assertTrue(cons in [DNA('A-'), DNA('C-'), DNA('G-')]) def test_ties_with_gaps(self): msa = TabularMSA([DNA('-'), DNA('.'), DNA('T'), DNA('T')]) cons = msa.consensus() self.assertTrue(cons in [DNA('T'), DNA('-')]) def test_default_gap_char(self): msa = TabularMSA([DNA('.'), DNA('.'), DNA('.')]) cons = msa.consensus() self.assertEqual(cons, DNA('-')) def test_different_dtype(self): msa = TabularMSA([RNA('---'), RNA('AG-'), RNA('AGG')]) cons = msa.consensus() self.assertEqual(cons, RNA('AG-')) def test_with_positional_metadata(self): # Defining *all* types of metadata to ensure correct metadata is # propagated to majority consensus sequence. seqs = [ DNA('-.-', metadata={'id': 'seq1'}, positional_metadata={'qual': range(0, 3)}), DNA('A.T', metadata={'id': 'seq2'}, positional_metadata={'qual': range(3, 6)}), DNA('ACT', metadata={'id': 'seq3'}, positional_metadata={'qual': range(6, 9)}) ] msa = TabularMSA(seqs, metadata={'pubmed': 123456}, positional_metadata={'foo': [42, 43, 42], 'bar': ['a', 'b', 'c']}) cons = msa.consensus() self.assertEqual( cons, DNA('A-T', positional_metadata={'foo': [42, 43, 42], 'bar': ['a', 'b', 'c']})) def test_mixed_gap_chars_as_majority(self): seqs = [ DNA('A'), DNA('A'), DNA('A'), DNA('A'), DNA('.'), DNA('.'), DNA('.'), DNA('-'), DNA('-') ] msa = TabularMSA(seqs) cons = msa.consensus() self.assertEqual(cons, DNA('-')) class TestConservation(unittest.TestCase): def test_no_sequences(self): msa = TabularMSA([]) cons = msa.conservation() npt.assert_array_equal(cons, np.array([])) def test_shannon_entropy_dna(self): msa = TabularMSA([DNA('A'), DNA('G')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=4)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([DNA('A'), DNA('G'), DNA('C'), DNA('G')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.25, 0.25], base=4)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([DNA('AAC'), DNA('GAC')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=4), 1. - scipy.stats.entropy([1.0], base=4), 1. - scipy.stats.entropy([1.0], base=4)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([DNA('AACT'), DNA('GACA')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=4), 1. - scipy.stats.entropy([1.0], base=4), 1. - scipy.stats.entropy([1.0], base=4), 1. - scipy.stats.entropy([0.5, 0.5], base=4)]) npt.assert_array_equal(actual, expected) def test_shannon_entropy_rna(self): msa = TabularMSA([RNA('A'), RNA('G')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=4)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([RNA('A'), RNA('G'), RNA('C'), RNA('G')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.25, 0.25], base=4)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([RNA('AAC'), RNA('GAC')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=4), 1. - scipy.stats.entropy([1.0], base=4), 1. - scipy.stats.entropy([1.0], base=4)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([RNA('AACU'), RNA('GACA')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=4), 1. - scipy.stats.entropy([1.0], base=4), 1. - scipy.stats.entropy([1.0], base=4), 1. - scipy.stats.entropy([0.5, 0.5], base=4)]) npt.assert_array_equal(actual, expected) def test_shannon_entropy_protein(self): msa = TabularMSA([Protein('A'), Protein('G')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=22)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([Protein('A'), Protein('G'), Protein('C'), Protein('G')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.25, 0.25], base=22)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([Protein('AAC'), Protein('GAC')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=22), 1. - scipy.stats.entropy([1.0], base=22), 1. - scipy.stats.entropy([1.0], base=22)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([Protein('AACT'), Protein('GACA')]) actual = msa.conservation(metric='inverse_shannon_uncertainty') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=22), 1. - scipy.stats.entropy([1.0], base=22), 1. - scipy.stats.entropy([1.0], base=22), 1. - scipy.stats.entropy([0.5, 0.5], base=22)]) npt.assert_array_equal(actual, expected) def test_degenerate_mode_nan(self): msa = TabularMSA([DNA('NAC'), DNA('NNC')]) actual = msa.conservation(metric='inverse_shannon_uncertainty', degenerate_mode='nan') expected = np.array([np.nan, np.nan, 1. - scipy.stats.entropy([1.0], base=4)]) npt.assert_array_equal(actual, expected) def test_degenerate_mode_error(self): msa = TabularMSA([DNA('NACN'), DNA('NNCA')]) self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', degenerate_mode='error') msa = TabularMSA([DNA('AACA'), DNA('ANCA')]) self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', degenerate_mode='error') def test_error_on_degenerate_w_nan_on_gap(self): msa = TabularMSA([DNA('-ACA'), DNA('-NCA')]) self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', degenerate_mode='error', gap_mode='nan') def test_column_with_degen_and_gap(self): msa = TabularMSA([DNA('N'), DNA('-')]) # test all eight combinations of gap_mode and degenerate_mode actual = msa.conservation(metric='inverse_shannon_uncertainty', degenerate_mode='nan', gap_mode='nan') npt.assert_array_equal(actual, np.array([np.nan])) actual = msa.conservation(metric='inverse_shannon_uncertainty', degenerate_mode='nan', gap_mode='ignore') npt.assert_array_equal(actual, np.array([np.nan])) actual = msa.conservation(metric='inverse_shannon_uncertainty', degenerate_mode='nan', gap_mode='include') npt.assert_array_equal(actual, np.array([np.nan])) self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', degenerate_mode='nan', gap_mode='error') self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', degenerate_mode='error', gap_mode='nan') self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', degenerate_mode='error', gap_mode='error') self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', degenerate_mode='error', gap_mode='include') self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', degenerate_mode='error', gap_mode='ignore') def test_gap_mode_nan(self): msa = TabularMSA([DNA('-AC.'), DNA('--CA')]) actual = msa.conservation(metric='inverse_shannon_uncertainty', gap_mode='nan') expected = np.array([np.nan, np.nan, 1. - scipy.stats.entropy([1.0], base=4), np.nan]) npt.assert_array_equal(actual, expected) def test_gap_mode_include(self): msa = TabularMSA([DNA('AC'), DNA('-G')]) actual = msa.conservation(metric='inverse_shannon_uncertainty', gap_mode='include') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=5), 1. - scipy.stats.entropy([0.5, 0.5], base=5)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([DNA('AC'), DNA('.G')]) actual = msa.conservation(metric='inverse_shannon_uncertainty', gap_mode='include') expected = np.array([1. - scipy.stats.entropy([0.5, 0.5], base=5), 1. - scipy.stats.entropy([0.5, 0.5], base=5)]) npt.assert_array_equal(actual, expected) def test_gap_mode_include_gaps_treated_as_single_char(self): msa = TabularMSA([DNA('.'), DNA('-')]) actual = msa.conservation(metric='inverse_shannon_uncertainty', gap_mode='include') expected = np.array([1. - scipy.stats.entropy([1.0], base=5)]) npt.assert_array_equal(actual, expected) def test_gap_mode_ignore(self): msa = TabularMSA([DNA('AC'), DNA('-G')]) actual = msa.conservation(metric='inverse_shannon_uncertainty', gap_mode='ignore') expected = np.array([1. - scipy.stats.entropy([1.0], base=4), 1. - scipy.stats.entropy([0.5, 0.5], base=4)]) npt.assert_array_equal(actual, expected) msa = TabularMSA([DNA('AC'), DNA('.G')]) actual = msa.conservation(metric='inverse_shannon_uncertainty', gap_mode='ignore') expected = np.array([1. - scipy.stats.entropy([1.0], base=4), 1. - scipy.stats.entropy([0.5, 0.5], base=4)]) npt.assert_array_equal(actual, expected) def test_gap_mode_error(self): msa = TabularMSA([DNA('-AC-'), DNA('--CA')]) self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', gap_mode="error") msa = TabularMSA([DNA('AACA'), DNA('A-CA')]) self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', gap_mode="error") msa = TabularMSA([DNA('AACA'), DNA('A.CA')]) self.assertRaises(ValueError, msa.conservation, metric='inverse_shannon_uncertainty', gap_mode="error") def test_bad_metric(self): msa = TabularMSA([DNA('AA'), DNA('A-')]) with self.assertRaisesRegex(ValueError, r'xyz'): msa.conservation(metric='xyz') msa = TabularMSA([]) with self.assertRaisesRegex(ValueError, r'xyz'): msa.conservation(metric='xyz') def test_bad_gap_mode(self): msa = TabularMSA([DNA('AA'), DNA('A-')]) with self.assertRaisesRegex(ValueError, r'xyz'): msa.conservation(gap_mode='xyz') msa = TabularMSA([]) with self.assertRaisesRegex(ValueError, r'xyz'): msa.conservation(gap_mode='xyz') def test_bad_degenerate_mode(self): msa = TabularMSA([DNA('AA'), DNA('A-')]) with self.assertRaisesRegex(ValueError, r'xyz'): msa.conservation(degenerate_mode='xyz') msa = TabularMSA([]) with self.assertRaisesRegex(ValueError, r'xyz'): msa.conservation(degenerate_mode='xyz') class TestGapFrequencies(unittest.TestCase): def test_default_behavior(self): msa = TabularMSA([DNA('AA.'), DNA('-A-')]) freqs = msa.gap_frequencies() npt.assert_array_equal(np.array([1, 0, 2]), freqs) def test_invalid_axis_str(self): with self.assertRaisesRegex(ValueError, r"axis.*'foo'"): TabularMSA([]).gap_frequencies(axis='foo') def test_invalid_axis_int(self): with self.assertRaisesRegex(ValueError, r"axis.*2"): TabularMSA([]).gap_frequencies(axis=2) def test_position_axis_str_and_int_equivalent(self): msa = TabularMSA([DNA('ACGT'), DNA('A.G-'), DNA('----')]) str_freqs = msa.gap_frequencies(axis='position') int_freqs = msa.gap_frequencies(axis=1) npt.assert_array_equal(str_freqs, int_freqs) npt.assert_array_equal(np.array([0, 2, 4]), str_freqs) def test_sequence_axis_str_and_int_equivalent(self): msa = TabularMSA([DNA('ACGT'), DNA('A.G-'), DNA('----')]) str_freqs = msa.gap_frequencies(axis='sequence') int_freqs = msa.gap_frequencies(axis=0) npt.assert_array_equal(str_freqs, int_freqs) npt.assert_array_equal(np.array([1, 2, 1, 2]), str_freqs) def test_correct_dtype_absolute_empty(self): msa = TabularMSA([]) freqs = msa.gap_frequencies(axis='position') npt.assert_array_equal(np.array([]), freqs) self.assertEqual(int, freqs.dtype) def test_correct_dtype_relative_empty(self): msa = TabularMSA([]) freqs = msa.gap_frequencies(axis='position', relative=True) npt.assert_array_equal(np.array([]), freqs) self.assertEqual(float, freqs.dtype) def test_correct_dtype_absolute_non_empty(self): msa = TabularMSA([DNA('AC'), DNA('-.')]) freqs = msa.gap_frequencies(axis='position') npt.assert_array_equal(np.array([0, 2]), freqs) self.assertEqual(int, freqs.dtype) def test_correct_dtype_relative_non_empty(self): msa = TabularMSA([DNA('AC'), DNA('-.')]) freqs = msa.gap_frequencies(axis='position', relative=True) npt.assert_array_equal(np.array([0.0, 1.0]), freqs) self.assertEqual(float, freqs.dtype) def test_no_sequences_absolute(self): msa = TabularMSA([]) seq_freqs = msa.gap_frequencies(axis='sequence') pos_freqs = msa.gap_frequencies(axis='position') npt.assert_array_equal(np.array([]), seq_freqs) npt.assert_array_equal(np.array([]), pos_freqs) def test_no_sequences_relative(self): msa = TabularMSA([]) seq_freqs = msa.gap_frequencies(axis='sequence', relative=True) pos_freqs = msa.gap_frequencies(axis='position', relative=True) npt.assert_array_equal(np.array([]), seq_freqs) npt.assert_array_equal(np.array([]), pos_freqs) def test_no_positions_absolute(self): msa = TabularMSA([DNA('')]) seq_freqs = msa.gap_frequencies(axis='sequence') pos_freqs = msa.gap_frequencies(axis='position') npt.assert_array_equal(np.array([]), seq_freqs) npt.assert_array_equal(np.array([0]), pos_freqs) def test_no_positions_relative(self): msa = TabularMSA([DNA('')]) seq_freqs = msa.gap_frequencies(axis='sequence', relative=True) pos_freqs = msa.gap_frequencies(axis='position', relative=True) npt.assert_array_equal(np.array([]), seq_freqs) npt.assert_array_equal(np.array([np.nan]), pos_freqs) def test_single_sequence_absolute(self): msa = TabularMSA([DNA('.T')]) seq_freqs = msa.gap_frequencies(axis='sequence') pos_freqs = msa.gap_frequencies(axis='position') npt.assert_array_equal(np.array([1, 0]), seq_freqs) npt.assert_array_equal(np.array([1]), pos_freqs) def test_single_sequence_relative(self): msa = TabularMSA([DNA('.T')]) seq_freqs = msa.gap_frequencies(axis='sequence', relative=True) pos_freqs = msa.gap_frequencies(axis='position', relative=True) npt.assert_array_equal(np.array([1.0, 0.0]), seq_freqs) npt.assert_array_equal(np.array([0.5]), pos_freqs) def test_single_position_absolute(self): msa = TabularMSA([DNA('.'), DNA('T')]) seq_freqs = msa.gap_frequencies(axis='sequence') pos_freqs = msa.gap_frequencies(axis='position') npt.assert_array_equal(np.array([1]), seq_freqs) npt.assert_array_equal(np.array([1, 0]), pos_freqs) def test_single_position_relative(self): msa = TabularMSA([DNA('.'), DNA('T')]) seq_freqs = msa.gap_frequencies(axis='sequence', relative=True) pos_freqs = msa.gap_frequencies(axis='position', relative=True) npt.assert_array_equal(np.array([0.5]), seq_freqs) npt.assert_array_equal(np.array([1.0, 0.0]), pos_freqs) def test_position_axis_absolute(self): msa = TabularMSA([ DNA('ACGT'), # no gaps DNA('A.G-'), # some gaps (mixed gap chars) DNA('----'), # all gaps DNA('....')]) # all gaps freqs = msa.gap_frequencies(axis='position') npt.assert_array_equal(np.array([0, 2, 4, 4]), freqs) def test_position_axis_relative(self): msa = TabularMSA([DNA('ACGT'), DNA('A.G-'), DNA('CCC.'), DNA('----'), DNA('....')]) freqs = msa.gap_frequencies(axis='position', relative=True) npt.assert_array_equal(np.array([0.0, 0.5, 0.25, 1.0, 1.0]), freqs) def test_sequence_axis_absolute(self): msa = TabularMSA([DNA('AC-.'), DNA('A.-.'), DNA('G--.')]) freqs = msa.gap_frequencies(axis='sequence') npt.assert_array_equal(np.array([0, 2, 3, 3]), freqs) def test_sequence_axis_relative(self): msa = TabularMSA([DNA('AC--.'), DNA('A.A-.'), DNA('G-A-.')]) freqs = msa.gap_frequencies(axis='sequence', relative=True) npt.assert_array_equal(np.array([0.0, 2/3, 1/3, 1.0, 1.0]), freqs) def test_relative_frequencies_precise(self): class CustomSequence(GrammaredSequence): @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set('0123456789') @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return '0' @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set('') @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return {} msa = TabularMSA([CustomSequence('0123456789')]) freqs = msa.gap_frequencies(axis='position', relative=True) npt.assert_array_equal(np.array([1.0]), freqs) def test_custom_gap_chars(self): class CustomSequence(GrammaredSequence): @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set('#$*') @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return '#' @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set('ABC-.') @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return {'D': 'ABC-.'} msa = TabularMSA([CustomSequence('ABCD'), CustomSequence('-.-.'), CustomSequence('A#C*'), CustomSequence('####'), CustomSequence('$$$$')]) freqs = msa.gap_frequencies(axis='position') npt.assert_array_equal(np.array([0, 0, 2, 4, 4]), freqs) class TestGetPosition(unittest.TestCase): def test_without_positional_metadata(self): msa = TabularMSA([DNA('ACG'), DNA('A-G')]) position = msa._get_position_(1) self.assertEqual(position, Sequence('C-')) def test_with_positional_metadata(self): msa = TabularMSA([DNA('ACG'), DNA('A-G')], positional_metadata={'foo': [42, 43, 44], 'bar': ['abc', 'def', 'ghi']}) position = msa._get_position_(1) self.assertEqual(position, Sequence('C-', metadata={'foo': 43, 'bar': 'def'})) class TestIsSequenceAxis(unittest.TestCase): def setUp(self): self.msa = TabularMSA([]) def test_invalid_str(self): with self.assertRaisesRegex(ValueError, r"axis.*'foo'"): self.msa._is_sequence_axis('foo') def test_invalid_int(self): with self.assertRaisesRegex(ValueError, r"axis.*2"): self.msa._is_sequence_axis(2) def test_positive_str(self): self.assertTrue(self.msa._is_sequence_axis('sequence')) def test_positive_int(self): self.assertTrue(self.msa._is_sequence_axis(0)) def test_negative_str(self): self.assertFalse(self.msa._is_sequence_axis('position')) def test_negative_int(self): self.assertFalse(self.msa._is_sequence_axis(1)) class TestHashable(unittest.TestCase): def test_unhashable_type(self): self.assertNotIsInstance(TabularMSA([]), collections.abc.Hashable) def test_unhashable_object(self): with self.assertRaisesRegex(TypeError, r'unhashable'): hash(TabularMSA([])) class TestRepr(unittest.TestCase): def test_repr(self): # basic sanity checks -- more extensive testing of formatting and # special cases is performed in TabularMSAReprDoctests below. here we # only test that pieces of the repr are present. these tests also # exercise coverage in case doctests stop counting towards coverage in # the future # str calls repr self.assertEqual(repr(TabularMSA([])), str(TabularMSA([]))) self.assertEqual(repr(TabularMSA([DNA('')])), str(TabularMSA([DNA('')]))) self.assertEqual(repr(TabularMSA([DNA('ACGT')])), str(TabularMSA([DNA('ACGT')]))) self.assertEqual(repr(TabularMSA([DNA('ACGT'*25) for x in range(10)])), str(TabularMSA([DNA('ACGT'*25) for x in range(10)]))) # empty obs = repr(TabularMSA([])) self.assertEqual(obs.count('\n'), 5) self.assertTrue(obs.startswith('TabularMSA')) self.assertIn('sequence count: 0', obs) self.assertIn('position count: 0', obs) # minimal obs = repr(TabularMSA([DNA('')])) self.assertEqual(obs.count('\n'), 5) self.assertTrue(obs.startswith('TabularMSA')) self.assertIn('sequence count: 1', obs) self.assertIn('position count: 0', obs) self.assertIn('[DNA]', obs) # no metadata obs = repr(TabularMSA([DNA('ACGT')])) self.assertEqual(obs.count('\n'), 6) self.assertTrue(obs.startswith('TabularMSA')) self.assertIn('sequence count: 1', obs) self.assertIn('position count: 4', obs) self.assertIn('[DNA]', obs) self.assertTrue(obs.endswith('ACGT')) # sequence spanning > 5 lines obs = repr(TabularMSA([DNA('A' * 71) for x in range(6)])) self.assertEqual(obs.count('\n'), 10) self.assertTrue(obs.startswith('TabularMSA')) self.assertIn('sequence count: 6', obs) self.assertIn('position count: 71', obs) self.assertIn('\n...\n', obs) self.assertIn('[DNA]', obs) self.assertTrue(obs.endswith('AAAA')) # sequences overflowing obs = repr(TabularMSA([DNA('A' * 72)])) self.assertEqual(obs.count('\n'), 6) self.assertTrue(obs.startswith('TabularMSA')) self.assertIn('sequence count: 1', obs) self.assertIn('position count: 72', obs) self.assertIn('[DNA]', obs) self.assertTrue(obs.endswith(' ... ' + 'A'*33)) # NOTE: this must be a *separate* class for doctests only (no unit tests). nose # will not run the unit tests otherwise # TODO: check if this is still the case since nose is no longer used # # these doctests exercise the correct formatting of TabularMSA's repr in a # variety of situations. they are more extensive than the unit tests above # (TestRepr.test_repr) but cannot be relied upon for coverage (the unit tests # take care of this) class TabularMSAReprDoctests: r""" >>> from skbio import DNA, TabularMSA Empty (minimal) MSA: >>> TabularMSA([]) TabularMSA --------------------- Stats: sequence count: 0 position count: 0 --------------------- MSA with single empty sequence: >>> TabularMSA([DNA('')]) TabularMSA[DNA] --------------------- Stats: sequence count: 1 position count: 0 --------------------- MSA with single sequence with single character: >>> TabularMSA([DNA('G')]) TabularMSA[DNA] --------------------- Stats: sequence count: 1 position count: 1 --------------------- G MSA with multicharacter sequence: >>> TabularMSA([DNA('ACGT')]) TabularMSA[DNA] --------------------- Stats: sequence count: 1 position count: 4 --------------------- ACGT Full single line: >>> TabularMSA([DNA('A' * 71)]) TabularMSA[DNA] ----------------------------------------------------------------------- Stats: sequence count: 1 position count: 71 ----------------------------------------------------------------------- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Full single line with 1 character overflow: >>> TabularMSA([DNA('A' * 72)]) TabularMSA[DNA] ----------------------------------------------------------------------- Stats: sequence count: 1 position count: 72 ----------------------------------------------------------------------- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ... AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Two sequences with full lines: >>> TabularMSA([DNA('T' * 71), DNA('T' * 71)]) TabularMSA[DNA] ----------------------------------------------------------------------- Stats: sequence count: 2 position count: 71 ----------------------------------------------------------------------- TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT Two sequences with full lines with 1 character overflow: >>> TabularMSA([DNA('T' * 72), DNA('T' * 72)]) TabularMSA[DNA] ----------------------------------------------------------------------- Stats: sequence count: 2 position count: 72 ----------------------------------------------------------------------- TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT ... TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT ... TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT Five full lines (maximum amount of information): >>> TabularMSA([DNA('A' * 71) for x in range(5)]) TabularMSA[DNA] ----------------------------------------------------------------------- Stats: sequence count: 5 position count: 71 ----------------------------------------------------------------------- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Six lines starts "summarized" output: >>> TabularMSA([DNA('A' * 71) for x in range(6)]) TabularMSA[DNA] ----------------------------------------------------------------------- Stats: sequence count: 6 position count: 71 ----------------------------------------------------------------------- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ... AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Supply horrendous metadata and positional metadata to exercise a variety of metadata formatting cases and rules. Sorting should be by type, then by value within each type (Python 3 doesn't allow sorting of mixed types): >>> metadata = { ... # str key, str value ... 'abc': 'some description', ... # int value ... 'foo': 42, ... # unsupported type (dict) value ... 'bar': {}, ... # int key, wrapped str (single line) ... 42: 'some words to test text wrapping and such... yada yada yada ' ... 'yada yada yada yada yada.', ... # bool key, wrapped str (multi-line) ... True: 'abc ' * 34, ... # float key, truncated str (too long) ... 42.5: 'abc ' * 200, ... # unsupported type (tuple) key, unsupported type (list) value ... ('foo', 'bar'): [1, 2, 3], ... # bytes key, single long word that wraps ... b'long word': 'abc' * 30, ... # truncated key (too long), None value ... 'too long of a key name to display in repr': None, ... # wrapped bytes value (has b'' prefix) ... 'bytes wrapped value': b'abcd' * 25, ... # float value ... 0.1: 99.9999, ... # bool value ... 43: False, ... # None key, complex value ... None: complex(-1.0, 0.0), ... # nested quotes ... 10: '"\'' ... } >>> positional_metadata = pd.DataFrame({ ... # str key, int list value ... 'foo': [1, 2, 3, 4], ... # float key, float list value ... 42.5: [2.5, 3.0, 4.2, -0.00001], ... # int key, object list value ... 42: [[], 4, 5, {}], ... # truncated key (too long), bool list value ... 'abc' * 90: [True, False, False, True], ... # None key ... None: range(4)}) >>> positional_metadata = positional_metadata.reindex( ... columns=['foo', 42.5, 42, 'abc' * 90, None]) >>> TabularMSA([DNA('ACGT')], metadata=metadata, ... positional_metadata=positional_metadata) TabularMSA[DNA] ----------------------------------------------------------------------- Metadata: None: (-1+0j) True: 'abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc ' b'long word': 'abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabca bcabcabcabcabcabcabcabcabcabcabcabcabc' 0.1: 99.9999 42.5: 10: '"\'' 42: 'some words to test text wrapping and such... yada yada yada yada yada yada yada yada.' 43: False 'abc': 'some description' 'bar': 'bytes wrapped value': b'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdab cdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd abcdabcdabcdabcd' 'foo': 42 : None : Positional metadata: 'foo': 42.5: 42: : None: Stats: sequence count: 1 position count: 4 ----------------------------------------------------------------------- ACGT """ pass if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/alignment/tests/test_utils.py000066400000000000000000000370471520735541300253660ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy as np import numpy.testing as npt from skbio.sequence import Sequence, DNA, Protein, SubstitutionMatrix from skbio.alignment import TabularMSA from skbio.alignment._utils import ( encode_sequences, encode_alignment, prep_gapcost, prep_identity_matrix, _check_seqtype, ) class UtilsTests(unittest.TestCase): def test_encode_sequences_submat(self): """Encode sequences with a substitution matrix.""" # nucleotide substitution matrix sm = SubstitutionMatrix.by_name("NUC.4.4") # DNA sequences seqs = (DNA("GAATCC"), DNA("AGATCT"), DNA("CCGG")) obs = encode_sequences(seqs, sm) exp = [[2, 0, 0, 1, 3, 3], [0, 2, 0, 1, 3, 1], [3, 3, 2, 2]] for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertIs(obs[1], sm._data) # non-grammared sequences seqs = (Sequence("GAATCC"), Sequence("AGATCT"), Sequence("CCGG")) obs = encode_sequences(seqs, sm) for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) # raw strings seqs = ("GAATCC", "AGATCT", "CCGG") obs = encode_sequences(seqs, sm) for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) # degenerate code becomes wildcard ("N") sm = SubstitutionMatrix.identity("ACGTN", 1, -1) seqs = (DNA("CGGRATCCA"), DNA("GGAATYCT")) obs = encode_sequences(seqs, sm) exp = [[1, 2, 2, 4, 0, 3, 1, 1, 0], [2, 2, 0, 0, 3, 4, 1, 3]] for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertIs(obs[1], sm._data) # won't work if wildcard is not defined msg = "Sequence 1 contain character(s) absent from the substitution matrix." seqs = (Sequence("CGGRATCCA"), Sequence("GGAATYCT")) with self.assertRaises(ValueError) as cm: _ = encode_sequences(seqs, sm) self.assertEqual(str(cm.exception), msg) # won't work if the substitution matrix doesn't contain "N". sm = SubstitutionMatrix.identity("ACGT", 1, -1) seqs = (DNA("CGGRATCCA"), DNA("GGAATYCT")) with self.assertRaises(ValueError) as cm: _ = encode_sequences(seqs, sm) self.assertEqual(str(cm.exception), msg) # Unicode sequences against ASCII matrix self.assertTrue(sm.is_ascii) seqs = ("â‘ â‘¡â‘¢", "①③④⑤") msg = ("Substitution matrix has an ASCII alphabet, but sequences cannot be " "fully encoded into ASCII codes.") with self.assertRaises(ValueError) as cm: _ = encode_sequences(seqs, sm) self.assertEqual(str(cm.exception), msg) # Unicode sequences against Unicode matrix sm = SubstitutionMatrix.identity("①②③④⑤", 1, -1) self.assertFalse(sm.is_ascii) obs = encode_sequences(seqs, sm) exp = [[0, 1, 2], [0, 2, 3, 4]] for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertIs(obs[1], sm._data) # with missing characters msg = "Sequence 2 contain character(s) absent from the substitution matrix." seqs = ("①③⑤", "â‘£â“�â‘¡") with self.assertRaises(ValueError) as cm: _ = encode_sequences(seqs, sm) self.assertEqual(str(cm.exception), msg) # ASCII sequences against Unicode matrix alphabet = "ACGT" + chr(100) + chr(200) + chr(300) sm = SubstitutionMatrix.identity(alphabet, 1, -1) seqs = (DNA("GAATCC"), DNA("AGATCT")) obs = encode_sequences(seqs, sm) exp = [[2, 0, 0, 3, 1, 1], [0, 2, 0, 3, 1, 3]] for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertIs(obs[1], sm._data) def test_encode_sequences_edit(self): """Encode sequences with match/mismatch scores.""" match, mismatch = 1, -1 # grammared sequences: submat will cover their alphabet seqs = (DNA("GAATCC"), DNA("AGATCT"), DNA("CCGG")) obs = encode_sequences(seqs, (match, mismatch)) exp = [[6, 2, 2, 13, 4, 4], [2, 6, 2, 13, 4, 13], [4, 4, 6, 6]] for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertEqual(obs[1].shape[0], 17) self.assertEqual(obs[1][0, 0], match) self.assertEqual(obs[1][0, 1], mismatch) # non-grammared sequences: submat will cover all ASCII codes seqs = (Sequence("GAATCC"), Sequence("AGATCT"), Sequence("CCGG")) obs = encode_sequences(seqs, (match, mismatch)) exp = [[71, 65, 65, 84, 67, 67], [65, 71, 65, 84, 67, 84], [67, 67, 71, 71]] for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertEqual(obs[1].shape[0], 128) submat = obs[1] # raw strings: same as above, plus the same submat will be reloaded from cache seqs = ("GAATCC", "AGATCT", "CCGG") obs = encode_sequences(seqs, (match, mismatch)) for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertIs(submat, obs[1]) # Unicode strings: submat will cover unique elements seqs = ("â‘ â‘¡â‘¢", "①③④⑤") exp = [[0, 1, 2], [0, 2, 3, 4]] obs = encode_sequences(seqs, (match, mismatch)) for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertEqual(obs[1].shape[0], 5) self.assertEqual(obs[1][0, 0], match) self.assertEqual(obs[1][0, 1], mismatch) self.assertIsNot(submat, obs[1]) # lists of words seq1 = "lorem ipsum sit amet tempor".split() seq2 = "ipsum sit dolor sed eiusmod".split() obs = encode_sequences([seq1, seq2], (match, mismatch)) exp = [[4, 3, 6, 0, 7], [3, 6, 1, 5, 2]] for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertEqual(obs[1].shape[0], 8) # arrays of numbers that are within ASCII range seq1 = np.array([9, 4, 4, 2, 3]) seq2 = np.array([5, 2, 4, 3, 3, 3, 7]) obs = encode_sequences([seq1, seq2], (match, mismatch)) npt.assert_array_equal(obs[0][0], seq1) npt.assert_array_equal(obs[0][1], seq2) self.assertEqual(obs[1].shape[0], 128) # arrays of numbers that are outside ASCII range seq1 = np.array([100, 150, 200, 200, 300]) seq2 = np.array([150, 300, 300, 200, 100, 350]) obs = encode_sequences([seq1, seq2], (match, mismatch)) exp = [[0, 1, 2, 2, 3], [1, 3, 3, 2, 0, 4]] for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertEqual(obs[1].shape[0], 5) def test_encode_sequences_error(self): msg = "Sequences are of different types." with self.assertRaises(TypeError) as cm: _ = encode_sequences([DNA("CGT"), Protein("MKY")], (1, -1)) self.assertEqual(str(cm.exception), msg) msg = "No sequence is provided." with self.assertRaises(ValueError) as cm: _ = encode_sequences([], (1, -1)) self.assertEqual(str(cm.exception), msg) msg = "Sequence {} has a length of zero." with self.assertRaises(ValueError) as cm: _ = encode_sequences(["", "ATG"], (1, -1)) self.assertEqual(str(cm.exception), msg.format(1)) with self.assertRaises(ValueError) as cm: _ = encode_sequences(["MKY", ""], (1, -1)) self.assertEqual(str(cm.exception), msg.format(2)) def test_encode_alignment_aligned(self): # Note: the unit-tests of this function aren't adequate. It still has 100% # coverage because all conditions have been tested in upstream and downstream # functions. But it would be good to enrich tests in the future. match, mismatch = 1, -1 # raw sequences seqs = ["GCG-TCAGT", "AGG-TCATT", "ACGTTC--T"] obs = encode_alignment(seqs, (match, mismatch)) exp0 = np.array([[71, 67, 71, 45, 84, 67, 65, 71, 84], [65, 71, 71, 45, 84, 67, 65, 84, 84], [65, 67, 71, 84, 84, 67, 45, 45, 84]]) npt.assert_array_equal(obs[0], exp0) self.assertEqual(obs[1].shape[0], 128) exp2 = np.array([[0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 1, 0]]).astype(bool) npt.assert_array_equal(obs[2], exp2) exp3 = np.array([3, 1, 2, 2, 1]) npt.assert_array_equal(obs[3], exp3) # grammared sequences seqs = list(map(DNA, seqs)) obs = encode_alignment(seqs, (match, mismatch)) exp0 = np.array([[6, 4, 6, 0, 13, 4, 2, 6, 13], [2, 6, 6, 0, 13, 4, 2, 13, 13], [2, 4, 6, 13, 13, 4, 0, 0, 13]]) npt.assert_array_equal(obs[0], exp0) self.assertEqual(obs[1].shape[0], 17) # tabular alignment msa = TabularMSA(map(DNA, seqs)) obs = encode_alignment(msa, (match, mismatch)) npt.assert_array_equal(obs[0], exp0) self.assertEqual(obs[1].shape[0], 17) # Unicode characters seqs = ["ïëï-öëäïö", "äïï-öëäöö", "äëïööë--ö"] obs = encode_alignment(seqs, (match, mismatch)) exp0 = np.array([[3, 2, 3, 0, 4, 2, 1, 3, 4], [1, 3, 3, 0, 4, 2, 1, 4, 4], [1, 2, 3, 4, 4, 2, 0, 0, 4]]) npt.assert_array_equal(obs[0], exp0) # substitution matrix alphabet = "ACGT" sm = SubstitutionMatrix.identity(alphabet, 1, -1) seqs = (DNA("GAA-CC"), DNA("AGATCT")) obs = encode_alignment(seqs, sm) exp = [[2, 0, 0, -1, 1, 1], [0, 2, 0, 3, 1, 3]] for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertIs(obs[1], sm._data) # ASCII sequences against Unicode matrix alphabet += chr(100) + chr(200) + chr(300) sm = SubstitutionMatrix.identity(alphabet, 1, -1) obs = encode_alignment(seqs, sm) for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) def test_prep_gapcost(self): obs = prep_gapcost(3) self.assertTupleEqual(obs, (0.0, 3.0)) self.assertIsInstance(obs[0], np.float32) self.assertIsInstance(obs[1], np.float32) obs = prep_gapcost((2, 5)) self.assertTupleEqual(obs, (2.0, 5.0)) self.assertIsInstance(obs[0], np.float32) self.assertIsInstance(obs[1], np.float32) obs = prep_gapcost((0.5, 2.5)) self.assertTupleEqual(obs, (0.5, 2.5)) self.assertIsInstance(obs[0], np.float32) self.assertIsInstance(obs[1], np.float32) obs = prep_gapcost((0.5, 2.5), dtype=np.float64) self.assertTupleEqual(obs, (0.5, 2.5)) self.assertIsInstance(obs[0], np.float64) self.assertIsInstance(obs[1], np.float64) obs = prep_gapcost((np.float64(0.5), np.float64(2.5))) self.assertTupleEqual(obs, (0.5, 2.5)) self.assertIsInstance(obs[0], np.float32) self.assertIsInstance(obs[1], np.float32) obs = prep_gapcost((np.float32(0.5), np.float32(2.5)), dtype=np.float64) self.assertTupleEqual(obs, (0.5, 2.5)) self.assertIsInstance(obs[0], np.float64) self.assertIsInstance(obs[1], np.float64) def testprep_identity_matrix(self): # Grammared (DNA) matrix seqs = [np.array([71, 65, 65, 84, 67, 67]), np.array([65, 71, 65, 84, 67, 84]), np.array([67, 67, 71, 71])] obs = prep_identity_matrix(seqs, DNA, 1.0, -1.0) exp = [np.array([6, 2, 2, 13, 4, 4]), np.array([2, 6, 2, 13, 4, 13]), np.array([4, 4, 6, 6])] for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertEqual(obs[1].shape[0], 17) self.assertEqual(obs[1][2, 2], 1.0) self.assertEqual(obs[1][3, 1], -1.0) submat = obs[1] # update cached matrix without recreating it obs = prep_identity_matrix(seqs, DNA, 2.0, -3.0) for o, e in zip(obs[0], exp): npt.assert_array_equal(o, e) self.assertEqual(obs[1].shape[0], 17) self.assertEqual(obs[1][2, 2], 2.0) self.assertEqual(obs[1][3, 1], -3.0) self.assertIs(obs[1], submat) # ASCII matrix seqs = [np.array([9, 4, 4, 2, 3], dtype=np.uint8), np.array([5, 2, 4, 3, 3, 3, 7], dtype=np.uint8)] obs = prep_identity_matrix(seqs, "ascii", 2.0, -3.0) for o, e in zip(obs[0], seqs): npt.assert_array_equal(o, e) self.assertIs(o.dtype.type, np.intp) self.assertEqual(obs[1].shape[0], 128) self.assertEqual(obs[1][5, 5], 2.0) self.assertEqual(obs[1][7, 8], -3.0) submat = obs[1] # update cached matrix obs = prep_identity_matrix(seqs, "ascii", 1.0, -2.5) for o, e in zip(obs[0], seqs): npt.assert_array_equal(o, e) self.assertEqual(obs[1][5, 5], 1.0) self.assertEqual(obs[1][7, 8], -2.5) self.assertIs(obs[1], submat) # arbitrary matrix seqs = [np.array([0, 1, 2, 2, 3]), np.array([1, 3, 3, 2, 0, 4])] obs = prep_identity_matrix(seqs, 5, 1.0, -2.5) for o, e in zip(obs[0], seqs): npt.assert_array_equal(o, e) self.assertIs(o.dtype.type, np.intp) self.assertEqual(obs[1].shape[0], 5) self.assertEqual(obs[1][2, 2], 1.0) self.assertEqual(obs[1][3, 1], -2.5) submat = obs[1] # create every time (no update) obs = prep_identity_matrix(seqs, 5, 3.5, -4.0) self.assertEqual(obs[1][2, 2], 3.5) self.assertEqual(obs[1][3, 1], -4.0) self.assertIsNot(obs[1], submat) def test_check_seqtype(self): obs = _check_seqtype([1, 2, 3, 4]) self.assertIs(obs, int) obs = _check_seqtype(["abc", "def"]) self.assertIs(obs, str) obs = _check_seqtype([DNA("CGT"), DNA("AAT"), DNA("GC")]) self.assertIs(obs, DNA) obs = _check_seqtype(TabularMSA(list(map(DNA, ["CGT", "AAT", "GCA"])))) self.assertIs(obs, DNA) msg = "Sequences are of different types." with self.assertRaises(TypeError) as cm: _ = _check_seqtype(["a", 1]) self.assertEqual(str(cm.exception), msg) with self.assertRaises(TypeError) as cm: _ = _check_seqtype([DNA("CGT"), Protein("MKY")]) self.assertEqual(str(cm.exception), msg) msg = "No sequence is provided." with self.assertRaises(ValueError) as cm: _ = _check_seqtype([]) self.assertEqual(str(cm.exception), msg) with self.assertRaises(ValueError) as cm: _ = _check_seqtype(TabularMSA([])) self.assertEqual(str(cm.exception), msg) if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/binaries/000077500000000000000000000000001520735541300212565ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/binaries/__init__.py000066400000000000000000000023271520735541300233730ustar00rootroot00000000000000r"""Optimized libraries from scikit-bio-binaries ============================================ .. currentmodule:: skbio.binaries This module provides an interface to the optimized functions that are available in the scikit-bio-binaries package, via the libskbb shared library. Since scikit-bio-binaries is not guaranteed to be installed the module provides ways to check for the presence of the needed shared library. """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2025--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._util import ( available, get_api_version, set_random_seed, py_to_bin_random_seed, ) from ._ordination import ( pcoa_fsvd_available, pcoa_fsvd, ) from ._distance import ( permanova_available, permanova, ) __all__ = [ "available", "get_api_version", "set_random_seed", "py_to_bin_random_seed", "pcoa_fsvd_available", "pcoa_fsvd", "permanova_available", "permanova", ] scikit-bio-scikit-bio-a3beaa6/skbio/binaries/_distance.py000066400000000000000000000162601520735541300235660ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2025--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import ctypes import numpy as np from numbers import Integral from ..binaries._util import ( get_api_version as _skbb_get_api_version, get_dll as _get_skbb_dll, py_to_bin_random_seed, ) def permanova_available( distance_matrix, grouping, permutations, seed=None, ): """Is binaries permanova available? Check if the scikit-bio-binaries shared library provides the permanova functionality. Parameters ---------- distance_matrix : np.ndarray or DistanceMatrix Distance matrix containing distances between objects (e.g., distances between samples of microbial communities). grouping : 1-D np.ndarray Vector indicating the assignment of objects to groups. These integers denote which group an object belongs to. It must be the same length and in the same order as the objects in `distance_matrix`. permutations : int Number of permutations to use when assessing statistical significance. Must be greater than zero. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. Returns ------- boolean If False, the permanova function will raise an exception. Note ---- Internally it uses caching, to minimize overhead. """ # v1 is the minimum version that support permanova # includes check for library existence if _skbb_get_api_version() >= 1: # pragma: no cover # Do some basic sanity checks # check it is a positive number if not isinstance(permutations, Integral): return False elif permutations < 1: return False if not isinstance(grouping, np.ndarray): return False return True else: # pragma: no cover return False def permanova( distance_matrix, grouping, permutations, seed=None, ): r"""Test for significant differences between groups using PERMANOVA. Permutational Multivariate Analysis of Variance (PERMANOVA) is a non-parametric method that tests whether two or more groups of objects (e.g., samples) are significantly different based on a categorical factor. It is conceptually similar to ANOVA except that it operates on a distance matrix, which allows for multivariate analysis. PERMANOVA computes a pseudo-F statistic. Statistical significance is assessed via a permutation test. The assignment of objects to groups (`grouping`) is randomly permuted a number of times (controlled via `permutations`). A pseudo-F statistic is computed for each permutation and the p-value is the proportion of permuted pseudo-F statistics that are equal to or greater than the original (unpermuted) pseudo-F statistic. Parameters ---------- distance_matrix : np.ndarray or DistanceMatrix Distance matrix containing distances between objects (e.g., distances between samples of microbial communities). grouping : 1-D np.ndarray Vector indicating the assignment of objects to groups. These integers denote which group an object belongs to. It must be the same length and in the same order as the objects in `distance_matrix`. permutations : int Number of permutations to use when assessing statistical significance. Must be greater than zero. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. Returns ------- float pair ``test statistic`` and ``p-value``. Notes ----- See [1]_ for the original method reference, as well as ``vegan::adonis``, available in R's vegan package [2]_. Finally, the result is undefined if distance_matrix is a np.ndarray that does not represent a valid distance matrix. References ---------- .. [1] Anderson, Marti J. "A new method for non-parametric multivariate analysis of variance." Austral Ecology 26.1 (2001): 32-46. .. [2] http://cran.r-project.org/web/packages/vegan/index.html """ # minimum version that support pcoa if _skbb_get_api_version() >= 1: # pragma: no cover if permutations < 1: raise ValueError("permutations must be a positive number") int_seed = py_to_bin_random_seed(seed) if isinstance(distance_matrix, np.ndarray): # already a raw matrix, just use distance_matrix_data = distance_matrix else: # we are assuming it is a DistanceMatrix object # get internal representations distance_matrix_data = distance_matrix.data distance_matrix_shape0 = distance_matrix_data.shape[0] if ( len(distance_matrix_data.shape) != 2 or distance_matrix_data.shape[1] != distance_matrix_shape0 ): raise TypeError("distance_matrix not square") if not isinstance(grouping, np.ndarray): raise TypeError("grouping not ndarray") if len(grouping.shape) != 1: raise TypeError("grouping not 1D ndarray") distance_matrix_shape0 = distance_matrix_data.shape[0] if grouping.shape[0] != distance_matrix_shape0: raise TypeError("grouping not the same size as distance_matrix") # skbb expects uint32 array, so convert if needed (cheap) if grouping.dtype == np.dtype("uint32"): grouping_data = grouping else: grouping_data = grouping.astype(np.uint32) # ready to call the C functions dll = _get_skbb_dll() i_mdim = ctypes.c_uint(distance_matrix_shape0) i_mat = distance_matrix_data.ctypes.data_as(ctypes.c_void_p) i_grp = grouping_data.ctypes.data_as(ctypes.c_void_p) i_n_perm = ctypes.c_uint(permutations) i_seed = ctypes.c_int(int_seed) if distance_matrix_data.dtype == np.dtype("float64"): o_fstat = ctypes.c_double() o_pvalue = ctypes.c_double() dll.skbb_permanova_fp64( i_mdim, i_mat, i_grp, i_n_perm, i_seed, ctypes.byref(o_fstat), ctypes.byref(o_pvalue), ) elif distance_matrix_data.dtype == np.dtype("float32"): o_fstat = ctypes.c_float() o_pvalue = ctypes.c_float() dll.skbb_permanova_fp32( i_mdim, i_mat, i_grp, i_n_perm, i_seed, ctypes.byref(o_fstat), ctypes.byref(o_pvalue), ) else: raise TypeError("distance_matrix type must be either float32 or float64") # if we got here, everything went well return o_fstat.value, o_pvalue.value else: # pragma: no cover raise ImportError("skbb_permanova not available") scikit-bio-scikit-bio-a3beaa6/skbio/binaries/_ordination.py000066400000000000000000000201751520735541300241420ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2025--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import ctypes import numpy as np from numbers import Integral from ..binaries._util import ( get_api_version as _skbb_get_api_version, get_dll as _get_skbb_dll, py_to_bin_random_seed, ) def pcoa_fsvd_available( distance_matrix, dimensions, inplace=False, seed=None, ): """Check if the scikit-bio-binaries shared library provides the pcoa functionality. Parameters ---------- distance_matrix : np.ndarray or DistanceMatrix Distance matrix containing distances between objects (e.g., distances between samples of microbial communities). dimensions : int Dimensions to reduce the distance matrix to. This number determines how many eigenvectors and eigenvalues will be returned. inplace : bool If True, the input distance matrix will be centered in-place to reduce memory consumption, at the cost of losing the original distances. Default is False. seed : int or np.random.Generator, optional A user-provided random seed or random generator instance. Returns ------- boolean If False, the pcoa_fsvd function will raise an exception. Note ---- Internally it uses caching, to minimize overhead. """ # v1 is the minimum version that supports pcoa_fsvd # includes check for library existence if _skbb_get_api_version() >= 1: # pragma: no cover # Do some basic sanity checks # check it is a positive number if not isinstance(dimensions, Integral): return False elif dimensions < 1: return False return True else: # pragma: no cover return False def pcoa_fsvd( distance_matrix, dimensions, inplace=False, seed=None, ): r"""Perform Principal Coordinate Analysis (PCoA). PCoA is an ordination method similar to Principal Components Analysis (PCA), with the difference that it operates on distance matrices, calculated using meaningful and typically non-Euclidian methods. Parameters ---------- distance_matrix : np.ndarray or DistanceMatrix Distance matrix containing distances between objects (e.g., distances between samples of microbial communities). dimensions : int Dimensions to reduce the distance matrix to. This number determines how many eigenvectors and eigenvalues will be returned. inplace : bool If True, the input distance matrix will be centered in-place to reduce memory consumption, at the cost of losing the original distances. Default is False. seed : int or np.random.Generator, optional A user-provided random seed or random generator instance. Returns ------- tuple of 3 np.ndarray eigenvalues, transformed samples and the proportion explained by each of them. Notes ----- Principal Coordinate Analysis (PCoA) was first described in [1]_. It used the ``fsvd`` method, which performs fast singular value decomposition (FSVD) [2]_, an efficient heuristic method that allows a custom number of dimensions to be specified to reduce calculation at the cost of losing accuracy. The degree of accuracy lost is dependent on dataset. Eigenvalues represent the magnitude of individual principal coordinates, and they are usually positive. However, negative eigenvalues can occur when the distances were calculated using a non-Euclidean metric that does not satisfy triangle inequality. If the negative eigenvalues are small in magnitude compared to the largest positive eigenvalue, it is usually safe to ignore them. However, large negative eigenvalues may indicate result inaccuracy, in which case a warning message will be displayed. PCoA on Euclidean distances is equivalent to Principal Component Analysis (PCA). However, in ecology, the Euclidean distance preserved by PCA is often not a good choice because it deals poorly with double zeros. For example, species have unimodal distributions along environmental gradients. If a species is absent from two sites simultaneously, it can't be known if an environmental variable is too high in one of them and too low in the other, or too low in both, etc. On the other hand, if a species is present in two sites, that means that the sites are similar. Note that the returned eigenvectors are not normalized to unit length. Finally, the result is undefined if distance_matrix is a np.ndarray that does not represent a valid distance matrix. References ---------- .. [1] Gower, J. C. (1966). Some distance properties of latent root and vector methods used in multivariate analysis. Biometrika, 53(3-4), 325-338. .. [2] Halko, N., Martinsson, P. G., Shkolnisky, Y., & Tygert, M. (2011). An algorithm for the principal component analysis of large data sets. SIAM Journal on Scientific computing, 33(5), 2580-2594. """ # minimum version that support pcoa if _skbb_get_api_version() >= 1: # pragma: no cover if not isinstance(dimensions, Integral): raise ValueError("dimensions must be an integer value") if dimensions < 1: raise ValueError("dimensions must be a positive number") int_seed = py_to_bin_random_seed(seed) if isinstance(distance_matrix, np.ndarray): # already a raw matrix, just use distance_matrix_data = distance_matrix else: # we are assuming it is a DistanceMatrix object # get internal representations distance_matrix_data = distance_matrix.data distance_matrix_shape0 = distance_matrix_data.shape[0] if ( len(distance_matrix_data.shape) != 2 or distance_matrix_data.shape[1] != distance_matrix_shape0 ): raise TypeError("distance_matrix not square") if dimensions > distance_matrix_shape0: raise ValueError("dimensions cannot be larger than matrix size") # create output buffers eigenvalues = np.ndarray(shape=(dimensions,), dtype=distance_matrix_data.dtype) proportion_explained = np.ndarray( shape=(dimensions,), dtype=distance_matrix_data.dtype ) samples = np.ndarray( shape=(distance_matrix_shape0, dimensions), dtype=distance_matrix_data.dtype, order="C", ) # ready to call the C functions dll = _get_skbb_dll() i_mdim = ctypes.c_uint(distance_matrix_shape0) i_mat = distance_matrix_data.ctypes.data_as(ctypes.c_void_p) i_n_eigh = ctypes.c_uint(dimensions) i_seed = ctypes.c_int(int_seed) o_ev = eigenvalues.ctypes.data_as(ctypes.c_void_p) o_sp = samples.ctypes.data_as(ctypes.c_void_p) o_pe = proportion_explained.ctypes.data_as(ctypes.c_void_p) if distance_matrix_data.dtype == np.dtype("float64"): if inplace: dll.skbb_pcoa_fsvd_inplace_fp64( i_mdim, i_mat, i_n_eigh, i_seed, o_ev, o_sp, o_pe ) else: dll.skbb_pcoa_fsvd_fp64( i_mdim, i_mat, i_n_eigh, i_seed, o_ev, o_sp, o_pe ) elif distance_matrix_data.dtype == np.dtype("float32"): if inplace: dll.skbb_pcoa_fsvd_inplace_fp32( i_mdim, i_mat, i_n_eigh, i_seed, o_ev, o_sp, o_pe ) else: dll.skbb_pcoa_fsvd_fp32( i_mdim, i_mat, i_n_eigh, i_seed, o_ev, o_sp, o_pe ) else: raise TypeError("distance_matrix type must be either float32 or float64") # if we got here, everything went well return eigenvalues, samples, proportion_explained else: # pragma: no cover raise ImportError("skbb_pcoa_fsvd not available") scikit-bio-scikit-bio-a3beaa6/skbio/binaries/_util.py000066400000000000000000000107441520735541300227520ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2025--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import ctypes import numpy as np from numbers import Integral # ==================================================== # Internal, do not use directly # # Global values used for caching purposes # _skbb_first_try = True # Set to invalid values _skbb_dll = None _skbb_version = 0 # ==================================================== def _get_new_skbb_dll(): """Load scikit-bio-binaries shared library object, if exists. Returns ------- ctypes.CDLL object or None Object to invoked external functions, or None, if no shared library found Note ---- Should not be used directly, use get_dll instead. """ import os try: dll = ctypes.CDLL("libskbb.so") if os.environ.get("SKBB_CPU_INFO", "N") in ("Y", "YES"): print("INFO (scikit-bio): Using shared library libskbb.so") except OSError: dll = None return dll def get_dll(): """Load scikit-bio-binaries shared library object, if exists. Returns ------- ctypes.CDLL object or None Object to invoked external functions, or None, if no shared library found Note ---- Internally it uses caching, to minimize overhead """ global _skbb_first_try global _skbb_dll if _skbb_first_try: _skbb_dll = _get_new_skbb_dll() _skbb_first_try = False return _skbb_dll # ==================================================== def available(): """Check if the scikit-bio-binaries shared library available. Returns ------- boolean If False, no other function in skbio.binaries will work Note ---- Internally it uses caching, to minimize overhead """ return get_dll() is not None def get_api_version(): """What API version does the scikit-bio-binaries shared library implement. Returns ------- integer API version, or 0, if the shared library is not available Note ---- Internally it uses caching, to minimize overhead """ global _skbb_version if _skbb_version == 0: dll = get_dll() if dll is not None: _skbb_version = dll.skbb_get_api_version() return _skbb_version # ==================================================== def set_random_seed(new_seed): """Set sbkio.binaries internal random seed Parameters ---------- new_seed : integer Random seed to use """ dll = get_dll() if dll is not None: dll.skbb_set_random_seed(ctypes.c_uint(new_seed)) # since there is no collateral impact # just do nothing if the shared library does not exist # ==================================================== def py_to_bin_random_seed(seed_or_generator=None): r"""Get a seed from a python random generator, if needed. Parameters ---------- seed_or_generator : int, Generator or RandomState, optional A user-provided random seed or random generator instance. Returns ------- int Seed to use in scikit-bio-binaries internal random objects. Can be the special -1 value, if the default seed should be used. See Also -------- numpy.random.Generator numpy.random.RandomState Notes ----- A random generator ensures reproducibility of outputs. This code provides the equivalent of scikit-bio ``get_rn`` but returns just a seed, instead. """ if seed_or_generator is None: return -1 # special value for scikit-bio-binaries elif isinstance(seed_or_generator, Integral): if seed_or_generator < 0: raise ValueError("seed must be a non-negative number") else: return seed_or_generator # was already a valid seed else: # assume it is a generator, get a new int seed maxint = np.iinfo(np.int32).max + 1 if isinstance(seed_or_generator, np.random.Generator): return seed_or_generator.integers(0, maxint) elif isinstance(seed_or_generator, np.random.RandomState): return seed_or_generator.randint(maxint) else: raise ValueError( "Invalid seed. It must be an integer or a random generator instance." ) scikit-bio-scikit-bio-a3beaa6/skbio/binaries/tests/000077500000000000000000000000001520735541300224205ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/binaries/tests/test_util.py000066400000000000000000000045761520735541300250220ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np from skbio.binaries._util import py_to_bin_random_seed class UtilTests(TestCase): def test_py_to_bin_random_seed_default(self): # returns default value (-1) if seed or generator is None obs = py_to_bin_random_seed() self.assertIsInstance(obs, int) self.assertEqual(obs, -1) def test_py_to_bin_random_seed_int(self): # returns given value if seed is integer obs = py_to_bin_random_seed(seed_or_generator=42) self.assertIsInstance(obs, int) self.assertEqual(obs, 42) def test_py_to_bin_random_seed_negative(self): # raise error if seed is negative with self.assertRaisesRegex(ValueError, "seed must be a non-negative number"): py_to_bin_random_seed(-1) def test_py_to_bin_random_seed_generator(self): # return an int between 0 and maxint if Generator is provided maxint = np.iinfo(np.int32).max + 1 rng = np.random.default_rng(42) obs = py_to_bin_random_seed(rng) self.assertIsInstance(obs, (int, np.integer)) self.assertTrue(obs >= 0 and obs <= maxint) def test_py_to_bin_random_seed_state(self): # return an int between 0 and maxint if RandomState is provided maxint = np.iinfo(np.int32).max + 1 state = np.random.RandomState(42) obs = py_to_bin_random_seed(state) self.assertIsInstance(obs, (int, np.integer)) self.assertTrue(obs >= 0 and obs <= maxint) def test_py_to_bin_random_seed_invalid(self): # raise error if invalid seed with self.assertRaisesRegex( ValueError, "Invalid seed. It must be an integer or a random generator instance.", ): py_to_bin_random_seed(0.5) def test_py_to_bin_random_seed_deterministic(self): # check that expected value is returned rng = np.random.default_rng(42) obs = py_to_bin_random_seed(rng) self.assertEqual(obs, 191664964) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/000077500000000000000000000000001520735541300215045ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/__init__.py000066400000000000000000000440261520735541300236230ustar00rootroot00000000000000r"""Community Diversity (:mod:`skbio.diversity`) ============================================ .. currentmodule:: skbio.diversity This module provides functionality for analyzing biodiversity of communities -- groups of organisms living in the same area. It implements various metrics of **alpha** (*within*-community) and **beta** (*between*-community) diversity, and provides "driver functions" for computing alpha and beta diversity for an entire data table. Additional utilities are provided to support discovery of available diversity metrics. While diversity metrics were originally designed to study biological communities, they can be generalized to the analysis of various biological data types. See an |diversity_intro|_ to community data and diversity metrics and a |diversity_tutorial|_ for performing community diversity analyses using scikit-bio. Alpha diversity --------------- .. rubric:: Alpha diversity metrics .. autosummary:: :toctree: generated/ alpha get_alpha_diversity_metrics .. rubric:: Driver function .. autosummary:: :toctree: generated/ alpha_diversity Beta diversity -------------- .. rubric:: Beta diversity metrics .. autosummary:: :toctree: generated/ beta get_beta_diversity_metrics .. rubric:: Driver functions .. autosummary:: :toctree: generated/ beta_diversity partial_beta_diversity block_beta_diversity Utility functions ----------------- .. autosummary:: :toctree: generated/ vectorize_counts_and_tree .. |diversity_intro| replace:: **Introduction** .. _diversity_intro: Introduction ------------ A community (i.e., sample) is represented by a vector of frequencies of taxa within the sample. The term "taxon" (plural: "taxa") describes a group of biologically related organisms that constitute a unit in the community. Taxa are usually defined at a uniform taxonomic rank, such as species, genus or family. In community ecology, taxon is usually referred to as "species" (singular = plural), but its definition is not limited to species as a taxonomic rank. The term "taxonomic group" is a synonym of taxon in many situations. In scikit-bio, the term "taxon/taxa" is used very loosely, as these can in practice represent diverse feature types including organisms, genes, and metabolites. The term "sample" is also loosely defined for these purposes. These are intended to represent a single unit of sampling, and as such what a single sample represents can vary widely. For example, in a microbiome survey, these could represent all 16S rRNA gene sequences from a single oral swab. In a comparative genomics study on the other hand, a sample could represent an individual organism's genome. .. note:: Previous versions of scikit-bio referred to taxon as operational taxonomic unit (OTU), a historically important term in microbiome research. However, as the field advances and the research targets diverge (e.g., amplicon sequence variant, or ASV), a more generic term such as "taxon" becomes more appropriate. Therefore, the term OTU was replaced by taxon in scikit-bio 0.6.0. Each frequency in a given vector represents the number of individuals observed for a particular taxon. We will refer to the frequencies associated with a single sample as a *counts vector* or ``counts`` throughout the documentation. Counts vectors are `array_like`: anything that can be converted into a 1-D array is acceptable input. For example, you can provide a NumPy array or a native Python list and the results will be identical. The driver functions :func:`alpha_diversity` and :func:`beta_diversity` are designed to compute alpha diversity for one or more samples, or beta diversity for one or more pairs of samples. The driver functions accept a matrix containing vectors of frequencies of taxa within each sample. Each row in the matrix represents a single sample's count vector, so that rows represent samples and columns represent taxa. Some diversity metrics incorporate relationships between the taxa in their computation through reference to a phylogenetic tree. These metrics additionally take a :class:`~skbio.TreeNode` object and a list of taxa mapping the values in the counts vector to tips in the tree. The driver functions are optimized so that computing a diversity metric more than one time (i.e., for more than one sample for alpha diversity metrics, or more than one pair of samples for beta diversity metrics) is often much faster than repeated calls to the metric. For this reason, the driver functions take matrices of counts vectors rather than a single counts vector for alpha diversity metrics or two counts vectors for beta diversity metrics. The ``alpha_diversity`` driver function will thus compute alpha diversity for all counts vectors in the matrix, and the ``beta_diversity`` driver function will compute beta diversity for all pairs of counts vectors in the matrix. Input validation ^^^^^^^^^^^^^^^^ The driver functions perform validation of input by default. Validation can be slow so it is possible to disable this step by passing ``validate=False``. This can be dangerous however. If invalid input is encountered when validation is disabled it can result in difficult-to-interpret error messages or incorrect results. We therefore recommend that users are careful to ensure that their input data is valid before disabling validation. The conditions that the driver functions validate follow. If disabling validation, users should be confident that these conditions are met. * the data in the counts vectors can be safely cast to integers * there are no negative values in the counts vectors * each counts vector is one dimensional * the counts matrix is two dimensional * all counts vectors are of equal length Additionally, if a phylogenetic diversity metric is being computed, the following conditions are also confirmed: * the provided taxa are all unique * the length of each counts vector is equal to the number of taxa * the provided tree is rooted * the tree has more than one node * all nodes in the provided tree except for the root node have branch lengths * all tip names in the provided tree are unique * all provided taxa correspond to tip names in the provided tree Count vectors ^^^^^^^^^^^^^ There are different ways that count vectors are represented in the ecological literature and in related software. The diversity measures provided here *always* assume that the input contains abundance data: each count represents the number of individuals observed for a particular taxon in the sample. For example, if you have two taxa, where three individuals were observed from the first taxon and only a single individual was observed from the second taxon, you could represent this data in the following forms (among others). As a vector of counts. This is the expected type of input for the diversity measures in this module. There are 3 individuals from the taxon at index 0, and 1 individual from the taxon at index 1: >>> counts = [3, 1] As a vector of indices. The taxon at index 0 is observed 3 times, while the taxon at index 1 is observed 1 time: >>> indices = [0, 0, 0, 1] As a vector of frequencies. We have 1 taxon that is a singleton and 1 taxon that is a tripleton. We do not have any 0-tons or doubletons: >>> frequencies = [0, 1, 0, 1] Always use the first representation (a counts vector) with this module. Specifying a diversity metric ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The driver functions take a parameter, ``metric``, that specifies which diversity metric should be applied. The value that you provide for ``metric`` can be either a string (e.g., ``"faith_pd"``) or a function (e.g., :func:`~alpha.faith_pd`). The metric should generally be passed as a string, as this often uses an optimized version of the metric. For example, passing ``metric="faith_pd"`` (a string) to ``alpha_diversity`` will be tens of times faster than passing ``metric=faith_pd`` (a function) when computing Faith's PD on about 100 samples. Similarly, passing ``metric="unweighted_unifrac"`` (a string) will be hundreds of times faster than passing ``metric=unweighted_unifrac`` (a function) when computing unweighted UniFrac on about 100 samples. The latter may be faster if computing only one alpha or beta diversity value, but in these cases the run times will likely be so small that the difference will be negligible. **We therefore recommend that you always pass the metric as a string when possible.** Passing a metric as a string will not be possible if the metric you'd like to run is not one that scikit-bio knows about. This might be the case, for example, if you're applying a custom metric that you've developed. To discover the metric names that scikit-bio knows about as strings that can be passed as ``metric`` to ``alpha_diversity`` or ``beta_diversity``, you can call :func:`get_alpha_diversity_metrics` or :func:`get_beta_diversity_metrics`, respectively. These functions return lists of alpha and beta diversity metrics that are implemented in scikit-bio. There may be additional metrics that can be passed as strings which won't be listed here, such as those implemented in SciPy's :func:`~scipy.spatial.distance.pdist`. .. |diversity_tutorial| replace:: **Tutorial** .. _diversity_tutorial: Tutorial -------- Create a matrix containing 6 samples (rows) and 7 taxa (columns): .. plot:: :context: >>> data = [[23, 64, 14, 0, 0, 3, 1], ... [0, 3, 35, 42, 0, 12, 1], ... [0, 5, 5, 0, 40, 40, 0], ... [44, 35, 9, 0, 1, 0, 0], ... [0, 2, 8, 0, 35, 45, 1], ... [0, 0, 25, 35, 0, 19, 0]] >>> ids = list('ABCDEF') First, we'll compute :math:`S_{obs}`, an alpha diversity metric, for each sample using the ``alpha_diversity`` driver function: >>> from skbio.diversity import alpha_diversity >>> adiv_sobs = alpha_diversity('sobs', data, ids) >>> adiv_sobs # doctest: +ELLIPSIS A 5 B 5 C 4 D 4 E 5 F 3 dtype: ... Next we'll compute Faith's PD on the same samples. Since this is a phylogenetic diversity metric, we'll first create a tree and an ordered list of taxa. >>> from skbio import TreeNode >>> from io import StringIO >>> tree = TreeNode.read(StringIO( ... '(((((U1:0.5,U2:0.5):0.5,U3:1.0):1.0):0.0,' ... '(U4:0.75,(U5:0.5,(U6:0.5,U7:0.5):0.5):' ... '0.5):1.25):0.0)root;')) >>> taxa = ['U1', 'U2', 'U3', 'U4', 'U5', 'U6', 'U7'] >>> adiv_faith_pd = alpha_diversity('faith_pd', data, ids=ids, ... taxa=taxa, tree=tree) >>> adiv_faith_pd A 6.75 B 7.00 C 6.25 D 5.75 E 6.75 F 5.50 dtype: float64 Now we'll compute Bray-Curtis distances, a beta diversity metric, between all pairs of samples. Notice that the ``data`` and ``ids`` parameters provided to ``beta_diversity`` are the same as those provided to ``alpha_diversity``. >>> from skbio.diversity import beta_diversity >>> bc_dm = beta_diversity("braycurtis", data, ids) >>> print(bc_dm) 6x6 distance matrix IDs: 'A', 'B', 'C', 'D', 'E', 'F' Data: [[ 0. 0.78787879 0.86666667 0.30927835 0.85714286 0.81521739] [ 0.78787879 0. 0.78142077 0.86813187 0.75 0.1627907 ] [ 0.86666667 0.78142077 0. 0.87709497 0.09392265 0.71597633] [ 0.30927835 0.86813187 0.87709497 0. 0.87777778 0.89285714] [ 0.85714286 0.75 0.09392265 0.87777778 0. 0.68235294] [ 0.81521739 0.1627907 0.71597633 0.89285714 0.68235294 0. ]] Next, we'll compute weighted UniFrac distances between all pairs of samples. Because weighted UniFrac is a phylogenetic beta diversity metric, we'll need to pass the ``skbio.TreeNode`` and list of taxa that we created above. Again, these are the same values that were provided to ``alpha_diversity``. >>> wu_dm = beta_diversity("weighted_unifrac", data, ids, tree=tree, ... taxa=taxa) >>> print(wu_dm) 6x6 distance matrix IDs: 'A', 'B', 'C', 'D', 'E', 'F' Data: [[ 0. 2.77549923 3.82857143 0.42512039 3.8547619 3.10937312] [ 2.77549923 0. 2.26433692 2.98435423 2.24270353 0.46774194] [ 3.82857143 2.26433692 0. 3.95224719 0.16025641 1.86111111] [ 0.42512039 2.98435423 3.95224719 0. 3.98796148 3.30870431] [ 3.8547619 2.24270353 0.16025641 3.98796148 0. 1.82967033] [ 3.10937312 0.46774194 1.86111111 3.30870431 1.82967033 0. ]] Next we'll do some work with these beta diversity distance matrices. First, we'll determine if the UniFrac and Bray-Curtis distance matrices are significantly correlated by computing the Mantel correlation between them. Then we'll determine if the p-value is significant based on an alpha of 0.05. >>> from skbio.stats.distance import mantel >>> r, p_value, n = mantel(wu_dm, bc_dm) >>> print(r) 0.922404392093 >>> alpha = 0.05 >>> print(p_value < alpha) True Next, we'll perform principal coordinates analysis (PCoA) on our weighted UniFrac distance matrix. >>> from skbio.stats.ordination import pcoa >>> wu_pc = pcoa(wu_dm) PCoA plots are only really interesting in the context of sample metadata, so let's define some before we visualize these results. >>> import pandas as pd >>> sample_md = pd.DataFrame([ ... ['gut', 's1'], ... ['skin', 's1'], ... ['tongue', 's1'], ... ['gut', 's2'], ... ['tongue', 's2'], ... ['skin', 's2']], ... index=['A', 'B', 'C', 'D', 'E', 'F'], ... columns=['body_site', 'subject']) >>> sample_md body_site subject A gut s1 B skin s1 C tongue s1 D gut s2 E tongue s2 F skin s2 Now let's plot our PCoA results, coloring each sample by the subject it was taken from: >>> fig = wu_pc.plot( ... sample_md, 'subject', ... axis_labels=('PC 1', 'PC 2', 'PC 3'), ... title='Samples colored by subject', ... cmap='jet', s=50 ... ) # doctest: +SKIP .. plot:: :context: We don't see any clustering/grouping of samples. If we were to instead color the samples by the body site they were taken from, we see that the samples from the same body site (those that are colored the same) appear to be closer to one another in the 3-D space then they are to samples from other body sites. >>> fig = wu_pc.plot( ... sample_md, 'body_site', ... axis_labels=('PC 1', 'PC 2', 'PC 3'), ... title='Samples colored by body site', ... cmap='jet', s=50 ... ) # doctest: +SKIP .. plot:: :context: Ordination techniques, such as PCoA, are useful for exploratory analysis. The next step is to quantify the strength of the grouping/clustering that we see in ordination plots. There are many statistical methods available to accomplish this; many operate on distance matrices. Let's use ANOSIM to quantify the strength of the clustering we see in the ordination plots above, using our weighted UniFrac distance matrix and sample metadata. First test the grouping of samples by subject: >>> from skbio.stats.distance import anosim >>> results = anosim(wu_dm, sample_md, column='subject', permutations=999) >>> results['test statistic'] -0.33333333333333331 >>> results['p-value'] < 0.1 False The negative value of ANOSIM's R statistic indicates anti-clustering and the p-value is insignificant at an alpha of 0.1. Now let's test the grouping of samples by body site: >>> results = anosim(wu_dm, sample_md, column='body_site', permutations=999) >>> results['test statistic'] 1.0 >>> results['p-value'] < 0.1 True The R statistic indicates strong separation of samples based on body site. The p-value is significant at an alpha of 0.1. We can also explore the alpha diversity in the context of sample metadata. To do this, let's add the observed richness and Faith's PD metrics to our sample metadata. This is straight-forward because ``alpha_diversity`` returns a Pandas ``Series`` object, and we're representing our sample metadata in a Pandas ``DataFrame`` object. >>> sample_md['Obs. richness'] = adiv_sobs >>> sample_md['Faith PD'] = adiv_faith_pd >>> sample_md body_site subject Obs. richness Faith PD A gut s1 5 6.75 B skin s1 5 7.00 C tongue s1 4 6.25 D gut s2 4 5.75 E tongue s2 5 6.75 F skin s2 3 5.50 We can investigate these alpha diversity data in the context of our metadata categories. For example, we can generate boxplots showing Faith PD by body site. >>> fig = sample_md.boxplot(column='Faith PD', by='body_site') # doctest: +SKIP We can also compute Spearman correlations between all pairs of columns in this ``DataFrame``. Since our alpha diversity metrics are the only two numeric columns (and thus the only columns for which Spearman correlation is relevant), this will give us a symmetric 2x2 correlation matrix. >>> sample_md.corr(method="spearman", numeric_only=True) Obs. richness Faith PD Obs. richness 1.000000 0.939336 Faith PD 0.939336 1.000000 """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._driver import ( alpha_diversity, beta_diversity, partial_beta_diversity, get_alpha_diversity_metrics, get_beta_diversity_metrics, ) from ._block import block_beta_diversity from ._util import vectorize_counts_and_tree __all__ = [ "alpha_diversity", "beta_diversity", "get_alpha_diversity_metrics", "get_beta_diversity_metrics", "partial_beta_diversity", "block_beta_diversity", "vectorize_counts_and_tree", ] scikit-bio-scikit-bio-a3beaa6/skbio/diversity/_block.py000066400000000000000000000260171520735541300233150ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from typing import Any, TYPE_CHECKING import numpy as np from skbio.diversity._driver import partial_beta_diversity from skbio.stats.distance import DistanceMatrix from skbio.diversity._util import _validate_counts_matrix from skbio.table._tabular import _ingest_table if TYPE_CHECKING: # pragma: no cover from collections.abc import Callable from numpy.typing import ArrayLike from skbio.util._typing import TableLike def _generate_id_blocks(ids, k=64): """Generate blocks of IDs that map into a DistanceMatrix. Parameters ---------- ids : Iterable object An iterable of IDs of whatever type. k : int, optional The size of a block to generate IDs for, defaults to 64. Notes ----- This method is intended to facilitate partial beta diversity calculations. Blocks of IDs are generated from the upper triangle of the subsequent distance matrix. For instance, given the following distance matrix with IDs {A, B, C, D, E}: A B C D E A 0 # # # # B # 0 # # # C # # 0 # # D # # # 0 # E # # # # 0 The goal of this method is to generate tuples of IDs of at most size k over the upper triangle which correspond to blocks of the matrix to compute. IDs are remapped as well into integers to facilitate downstream indexing. Given k=3, the following ID tuples would be generated: ((0, 1, 2), (0, 1, 2)) ((0, 1, 2), (3, 4)) ((3, 4), (3, 4)) This method is not responsible for describing which specific pairs of IDs are to be computed, only the subset of the matrix of interest. Returns ------- tuple of 1D np.array Index 0 contains the row IDs, and index 1 contains the column IDs """ n = len(ids) ids_idx = np.arange(n) for row_start in range(0, n, k): for col_start in range(row_start, n, k): row_ids = ids_idx[row_start : row_start + k] col_ids = ids_idx[col_start : col_start + k] yield (row_ids, col_ids) def _block_party(counts=None, row_ids=None, col_ids=None, **kwargs): """Subset counts to relevant rows and columns. Parameters ---------- counts : 2D array_like of ints or floats Matrix containing count/abundance data where each row contains counts of taxa in a given sample. row_ids : 1D np.ndarray of int Block row IDs to keep in the counts matrix. col_ids : 1D np.ndarray of int Block column IDs to keep in the counts matrix. Note, these correspond to rows in the counts matrix, but columns in a subsequent distance matrix. kwargs : dict Keyword arguments containing information about the block to compute. Returns ------- dict kwargs that describe the block to compute. A filtered ``counts`` matrix is stored in kwargs. If applicable, a filtered ``tree`` and ``taxa`` are also stored. """ ids_to_keep = np.unique(np.hstack([row_ids, col_ids])) # create a view of the relevant samples counts_block = counts[ids_to_keep] # remove from the block any empty observations # NOTE: this will perform an implicit copy nonzero_cols = (counts_block != 0).any(axis=0) counts_block = counts_block[:, nonzero_cols] kwargs["counts"] = counts_block kwargs["ids"] = ids_to_keep if "tree" in kwargs and "taxa" in kwargs: kwargs["taxa"] = np.asarray(kwargs["taxa"])[nonzero_cols] kwargs["tree"] = kwargs["tree"].shear(kwargs["taxa"]) return kwargs def _pairs_to_compute(rids, cids): """Determine the pairs of samples to compute distances between. Parameters ---------- rids : Iterable The row IDs in the partial pairwise computation. cids : Iterable The column IDs in the partial pairwise computation. Raises ------ ValueError When determining ID pairs for blocks that fall outside of the diagonal of the resulting distance matrix, if a pair corresponds to the lower triangle, complain loudly. Returns ------- list of tuple The ID pairs to compute distances between. """ # if identical, gather the upper triangle if len(rids) == len(cids) and (rids == cids).all(): return [(i, j) for idx, i in enumerate(rids) for j in rids[idx + 1 :]] # otherwise, grab pairwise combinations disregarding the diagonal else: if set(rids).intersection(set(cids)): raise ValueError("Attempting to compute a lower triangle") return [(i, j) for i in rids for j in cids if i != j] def _block_kwargs(**kwargs): """Construct arguments describing a block to compute. Returns ------- dict The parameters for the block of the distance matrix to compute. """ valid_block_keys = { "counts", "ids", "tree", "taxa", "metric", "id_pairs", "validate", "otu_ids", } for row_ids, col_ids in _generate_id_blocks(kwargs["ids"], kwargs["k"]): id_pairs = _pairs_to_compute(row_ids, col_ids) if id_pairs: kw = {k: v for k, v in kwargs.items() if k in valid_block_keys} kw["id_pairs"] = id_pairs kw["row_ids"] = row_ids kw["col_ids"] = col_ids yield kw def _block_compute(**kwargs): """Compute a block within the resulting distance matrix. Notes ----- This method encapsulates the two expensive operations to perform for each block, namely, the "shearing" of the phylogenetic tree to correspond to only the taxa of interest, and the actual beta diversity calculations. Returns ------- DistanceMatrix """ block_kw = _block_party(**kwargs) return partial_beta_diversity(**block_kw) def _map(func, kw_gen): """Map a function over arguments. Notes ----- builtin map does not allow for mapping with kwargs. Parallel uses of block decomposition will likely replace this method with one which can distribute compute. """ for kwargs in kw_gen: yield func(**kwargs) def _reduce(blocks): """Reduce an iterable of partial distance matrices into a full matrix. Note, the reduce doesn't actually care about what pairs are computed so if a distance between pairs exists multiple times, it'll get added. as such, this reduction is only safe to perform if by the block_beta_diversity method which assures that distances are not computed multiple times. """ all_blocks = list(blocks) # Determine the maximum integer ID observed in the blocks. There exists a # 1-1 mapping between the integer ID and a sample ID. We increment by 1 # as the integer ID space begins with zero, and we'll be using this value # to determine the size of the resulting full distance matrix. n_ids = max(map(lambda x: max(x.ids), all_blocks)) + 1 mat = np.zeros((n_ids, n_ids), dtype=float) # TODO: something smarter. for block in all_blocks: n_blk_ids = len(block.ids) # get the corresponding coordinates in the master matrix master_idx = [ (i, j) for row, i in enumerate(block.ids) for j in block.ids[row + 1 :] ] # get the corresponding coordinates within the current block block_idx = [ (i, j) for row, i in enumerate(range(n_blk_ids)) for j in range(row + 1, n_blk_ids) ] for (m_i, m_j), (b_i, b_j) in zip(master_idx, block_idx): mat[m_i, m_j] += block.data[b_i, b_j] return DistanceMatrix(mat + mat.T, list(range(n_ids))) def block_beta_diversity( metric: str | Callable, counts: TableLike, ids: ArrayLike | None = None, validate: bool = True, k: int = 64, reduce_f: Callable | None = None, map_f: Callable | None = None, **kwargs: Any, ) -> DistanceMatrix: """Perform a block-decomposition beta diversity calculation. Parameters ---------- metric : str or callable The beta diversity metric to apply to the samples. See :func:`~skbio.diversity.beta_diversity` for details. counts : table_like of shape (n_samples, n_taxa) Matrix containing count/abundance data of the samples. See :ref:`supported formats `. ids : array_like of shape (n_samples,), optional Identifiers for each sample in ``counts``. validate : bool, optional If True (default), validate the input data. See ``beta_diversity`` for details. reduce_f : callable, optional A method to reduce `PartialDistanceMatrix` objects into a single `DistanceMatrix`. The expected signature is: `f(Iterable of DistanceMatrix) -> DistanceMatrix` Note, this is the reduce within a map/reduce. map_f: callable, optional A method that accepts a `_block_compute`. The expected signature is: `f(**kwargs) -> DistanceMatrix` NOTE: ipyparallel's `map_async` will not work here as we need to be able to pass around `**kwargs``. k : int, optional The blocksize used when computing distances. Default is 64. kwargs : kwargs, optional Metric-specific parameters. See ``beta_diversity`` for details. Returns ------- DistanceMatrix Distances between all pairs of samples (i.e., rows). The number of rows and columns will be equal to the number of rows in ``counts``. Notes ----- This method is designed to facilitate computing beta diversity in parallel. In general, if you are processing a few hundred samples or less, then it is likely the case that `skbio.diversity.beta_diversity` will be faster. The original need which motivated the development of this method was processing the Earth Microbiome Project [1]_ dataset which at the time spanned over 25,000 samples and 7.5 million open reference taxa. See Also -------- beta_diversity partial_beta_diversity References ---------- .. [1] https://earthmicrobiome.ucsd.edu/ """ if "taxa" in kwargs: counts, ids, kwargs["taxa"] = _ingest_table(counts, ids, kwargs["taxa"]) else: counts, ids, _ = _ingest_table(counts, ids) if validate: counts = _validate_counts_matrix(counts) if reduce_f is None: reduce_f = _reduce if map_f is None: map_f = _map # The block method uses numeric IDs to take advantage of NumPy's advanced indexing. kwargs["ids"] = np.arange(counts.shape[0]) kwargs["metric"] = metric kwargs["counts"] = counts kwargs["k"] = k kwargs["validate"] = False # we've already validated if necessary dm = reduce_f(map_f(_block_compute, _block_kwargs(**kwargs))) dm.ids = ids return dm scikit-bio-scikit-bio-a3beaa6/skbio/diversity/_driver.py000066400000000000000000000403161520735541300235140ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations import warnings from functools import partial from itertools import chain from inspect import signature, getmembers, isfunction from typing import Any, TYPE_CHECKING import numpy as np import pandas as pd from skbio.diversity import alpha from skbio.diversity.alpha._pd import _setup_pd, _faith_pd, _phydiv from skbio.diversity.beta._unifrac import ( _setup_multiple_unweighted_unifrac, _setup_multiple_weighted_unifrac, _normalize_weighted_unifrac_by_default, ) from skbio.stats.distance import DistanceMatrix from skbio.diversity._util import ( _validate_counts_matrix, _get_phylogenetic_kwargs, _qualify_counts, ) from skbio.util._decorator import deprecated from skbio.table._tabular import _ingest_table if TYPE_CHECKING: # pragma: no cover from collections.abc import Iterable, Callable from numpy.typing import ArrayLike from skbio.util._typing import TableLike # Qualitative (absence/presence-based) metrics, which require Boolean input. _qualitative_metrics = { "dice", "jaccard", "matching", "rogerstanimoto", "russellrao", "sokalsneath", "yule", "unweighted_unifrac", } # Names of beta diversity callables that have a faster string-keyed equivalent. _slow_beta_callables = {"unweighted_unifrac", "weighted_unifrac"} # Beta diversity metrics implemented in SciPy's pdist. _pdist_metrics = { "euclidean", "cityblock", "braycurtis", "canberra", "chebyshev", "correlation", "cosine", "dice", "hamming", "jaccard", "jensenshannon", "mahalanobis", "manhattan", # aliases to "cityblock" in beta_diversity "matching", "minkowski", "rogerstanimoto", "russellrao", "seuclidean", "sokalsneath", "sqeuclidean", "yule", } def get_alpha_diversity_metrics() -> list[str]: r"""List scikit-bio's alpha diversity metrics. The alpha diversity metrics listed here can be passed as metrics to :func:`alpha_diversity`. Returns ------- list of str Alphabetically sorted list of alpha diversity metrics implemented in scikit-bio. See Also -------- alpha alpha_diversity get_beta_diversity_metrics """ return [x[0] for x in getmembers(alpha, isfunction)] def get_beta_diversity_metrics() -> list[str]: """List scikit-bio's beta diversity metrics. The beta diversity metrics listed here can be passed as metrics to :func:`beta_diversity`. Returns ------- list of str Alphabetically sorted list of beta diversity metrics implemented in scikit-bio. See Also -------- beta_diversity get_alpha_diversity_metrics scipy.spatial.distance.pdist Notes ----- SciPy implements many additional beta diversity metrics that are not included in this list. See documentation for SciPy's :func:`~scipy.spatial.distance.pdist` for more details. """ return sorted(_pdist_metrics.union(["unweighted_unifrac", "weighted_unifrac"])) def alpha_diversity( metric: str | Callable, counts: TableLike, ids: ArrayLike | None = None, validate: bool = True, **kwargs: Any, ) -> pd.Series: r"""Compute alpha diversity for one or more samples. Parameters ---------- metric : str or callable The alpha diversity metric to apply to the sample(s). See :mod:`~skbio.diversity.alpha` for available metrics. Passing metric as a string is preferable as this often results in an optimized version of the metric being used. counts : table_like of shape (n_samples, n_taxa) or (n_taxa,) Vector or matrix containing count/abundance data of one or multiple samples. See :ref:`supported formats `. ids : array_like of shape (n_samples,), optional Identifiers for each sample in ``counts``. If not provided, will extract sample IDs from ``counts``, if available, or assign integer identifiers in the order that samples were provided. validate: bool, optional If True (default), validate the input data before applying the alpha diversity metric. See :mod:`skbio.diversity` for the details of validation. kwargs : dict, optional Metric-specific parameters. Refer to the documentation of the chosen metric. A special parameter is ``taxa``, needed by some phylogenetic metrics. If not provided, will extract taxa (feature IDs) from ``counts``, if available, and pass to the metric. Returns ------- pd.Series Values of ``metric`` for all samples provided in ``counts``. The index will be ``ids``, if provided. Raises ------ ValueError, MissingNodeError, DuplicateNodeError If validation fails. Exact error will depend on what was invalid. TypeError If invalid method-specific parameters are provided. See Also -------- alpha get_alpha_diversity_metrics beta_diversity """ taxa = kwargs.pop("taxa", None) counts, ids, taxa = _ingest_table(counts, ids, taxa) if validate: counts = _validate_counts_matrix(counts) # phylogenetic diversity (call on entire matrix) if metric in ("faith_pd", "phydiv"): taxa, tree, kwargs = _get_phylogenetic_kwargs(kwargs, taxa) is_faith_pd = metric == "faith_pd" counts, lengths = _setup_pd( counts, taxa, tree, validate, rooted=is_faith_pd, single_sample=False ) if is_faith_pd: func = _faith_pd else: func = _phydiv kwargs.setdefault("rooted", tree._is_rooted()) kwargs.setdefault("weight", False) func = partial(func, branch_lengths=lengths, **kwargs) # other metrics (call on each sample) else: if callable(metric): func = metric elif isinstance(metric, str): func = getattr(alpha, metric, None) if func is None or not isfunction(func): raise ValueError( f'"{metric}" is not an available alpha diversity metric name. ' "Refer to `get_alpha_diversity_metrics` for a list of available " "metrics." ) else: raise ValueError(f"Invalid metric provided: {metric!r}.") # add "taxa" back to parameters if taxa is not None and "taxa" in signature(func).parameters: kwargs["taxa"] = taxa func = partial(func, **kwargs) # kwargs is provided here so an error is raised on extra kwargs results = [func(c, **kwargs) for c in counts] return pd.Series(results, index=ids) def beta_diversity( metric: str | Callable, counts: TableLike, ids: ArrayLike | None = None, validate: bool = True, pairwise_func: Callable | None = None, **kwargs: Any, ) -> DistanceMatrix: r"""Compute distances between all pairs of samples. Parameters ---------- metric : str or callable The beta diversity metric, i.e., a pairwise distance function to apply to the sample(s). See :mod:`~skbio.diversity.beta` and SciPy's :func:`~scipy.spatial.distance.pdist` for available metrics. Passing metric as a string is preferable as this often results in an optimized version of the metric being used. counts : table_like of shape (n_samples, n_taxa) or (n_taxa,) Vector or matrix containing count/abundance data of one or multiple samples. See :ref:`supported formats `. ids : array_like of shape (n_samples,), optional Identifiers for each sample in ``counts``. If not provided, will extract sample IDs from ``counts``, if available, or assign integer identifiers in the order that samples were provided. validate: bool, optional If True (default), validate the input data before applying the alpha diversity metric. See :mod:`skbio.diversity` for the details of validation. pairwise_func : callable, optional The function to use for computing pairwise distances. Must take ``counts`` and ``metric`` and return a square, hollow, 2-D float array of dissimilarities. Examples of functions that can be provided are SciPy's :func:`~scipy.spatial.distance.pdist` (default) and scikit-learn's :func:`~sklearn.metrics.pairwise_distances`. kwargs : dict, optional Metric-specific parameters. Refer to the documentation of the chosen metric. A special parameter is ``taxa``, needed by some phylogenetic metrics. If not provided, will extract taxa (feature IDs) from ``counts``, if available, and pass to the metric. Returns ------- :class:`~skbio.stats.distance.DistanceMatrix` Distances between all pairs of samples (i.e., rows). The number of rows and columns will be equal to the number of rows in ``counts``. Raises ------ ValueError, MissingNodeError, DuplicateNodeError If validation fails. Exact error will depend on what was invalid. Any Exception If invalid method-specific parameters are provided. See Also -------- beta get_beta_diversity_metrics alpha_diversity scipy.spatial.distance.pdist sklearn.metrics.pairwise_distances """ taxa = kwargs.pop("taxa", None) counts, ids, taxa = _ingest_table(counts, ids, taxa) if 0 in counts.shape: # if the input counts are empty, return an empty DistanceMatrix. # this check is not necessary for scipy.spatial.distance.pdist but # it is necessary for sklearn.metrics.pairwise_distances where the # latter raises an exception over empty data. return DistanceMatrix(np.zeros((len(ids), len(ids))), ids) if validate: counts = _validate_counts_matrix(counts) if metric in _qualitative_metrics: counts = _qualify_counts(counts) if metric in ("unweighted_unifrac", "weighted_unifrac"): taxa, tree, kwargs = _get_phylogenetic_kwargs(kwargs, taxa) if metric == "unweighted_unifrac": metric, counts = _setup_multiple_unweighted_unifrac( counts, taxa=taxa, tree=tree, validate=validate ) elif metric == "weighted_unifrac": # get the value for normalized. if it was not provided, it will fall # back to the default value inside of _weighted_unifrac_pdist_f normalized = kwargs.pop("normalized", _normalize_weighted_unifrac_by_default) metric, counts = _setup_multiple_weighted_unifrac( counts, taxa=taxa, tree=tree, normalized=normalized, validate=validate ) elif metric == "manhattan": metric = "cityblock" elif metric == "mahalanobis": nrow, ncol = counts.shape if nrow < ncol: raise ValueError( "Metric 'mahalanobis' requires more samples than features. " f"The input has {nrow} samples and {ncol} features." ) elif callable(metric): if getattr(metric, "__name__", None) in _slow_beta_callables: warnings.warn( f"Passing `{metric.__name__}` as a callable invokes a much slower " "implementation. Pass the metric name as a string " f"(e.g., metric='{metric.__name__}') to use the optimized version.", stacklevel=2, ) # add "taxa" back to parameters if taxa is not None and "taxa" in signature(metric).parameters: kwargs["taxa"] = taxa metric = partial(metric, **kwargs) # remove all values from kwargs, since they have already been provided # through the partial kwargs = {} elif metric not in _pdist_metrics: raise ValueError( f'"{metric}" is not an available beta diversity metric name. ' "Refer to `get_beta_diversity_metrics` for a list of available metrics." ) if pairwise_func is None: from scipy.spatial.distance import pdist pairwise_func = pdist distances = pairwise_func(counts, metric=metric, **kwargs) return DistanceMatrix(distances, ids) @deprecated( "0.5.0", msg="The return type is unstable. Developer caution is advised. The resulting " "DistanceMatrix object will include zeros when distance has not been calculated, " "and therefore can be misleading.", ) def partial_beta_diversity( metric: str | Callable, counts: TableLike, ids: ArrayLike | None, id_pairs: Iterable[tuple[str, str]], validate: bool = True, **kwargs: Any, ) -> DistanceMatrix: r"""Compute distances only between specified ID pairs. Parameters ---------- metric : str or callable The beta diversity metric to apply to the samples. See :func:`beta_diversity` for details. counts : table_like of shape (n_samples, n_taxa) Matrix containing count/abundance data of the samples. See :ref:`supported formats `. ids : iterable of strs Identifiers for each sample in ``counts``. id_pairs : iterable of tuple of (str, str) Pairs of sample IDs to compare (e.g., ``[('a', 'b'), ('a', 'c'), ...])``. If specified, the they must be a subset of ``ids``. validate : bool, optional Validate the input data. See ``beta_diversity`` for details. kwargs : dict, optional Metric-specific parameters. See ``beta_diversity`` for details. Returns ------- :class:`~skbio.stats.distance.DistanceMatrix` Distances between pairs of samples indicated by ``id_pairs``. Pairwise distances not defined by id_pairs will be 0.0. Use this resulting DistanceMatrix with caution as 0.0 is a valid distance. Raises ------ ValueError If ``ids`` are not specified. If ``id_pairs`` are not a subset of ``ids``. If ``metric`` is not a callable or is unresolvable string by scikit-bio. If duplicates are observed in ``id_pairs``. See Also -------- beta_diversity get_beta_diversity_metrics """ taxa = kwargs.pop("taxa", None) counts, ids, taxa = _ingest_table(counts, ids, taxa) if validate: counts = _validate_counts_matrix(counts) if metric in _qualitative_metrics: counts = _qualify_counts(counts) id_pairs = list(id_pairs) all_ids_in_pairs = set(chain.from_iterable(id_pairs)) if not all_ids_in_pairs.issubset(ids): raise ValueError("`id_pairs` are not a subset of `ids`") hashes = {i for i in id_pairs}.union({i[::-1] for i in id_pairs}) if len(hashes) != len(id_pairs) * 2: raise ValueError("A duplicate or a self-self pair was observed.") if metric == "unweighted_unifrac": taxa, tree, kwargs = _get_phylogenetic_kwargs(kwargs, taxa) func, counts = _setup_multiple_unweighted_unifrac( counts, taxa=taxa, tree=tree, validate=validate ) elif metric == "weighted_unifrac": # get the value for normalized. if it was not provided, it will fall # back to the default value inside of _weighted_unifrac_pdist_f normalized = kwargs.pop("normalized", _normalize_weighted_unifrac_by_default) taxa, tree, kwargs = _get_phylogenetic_kwargs(kwargs, taxa) func, counts = _setup_multiple_weighted_unifrac( counts, taxa=taxa, tree=tree, normalized=normalized, validate=validate ) elif callable(metric): func = partial(metric, **kwargs) # remove all values from kwargs, since they have already been provided # through the partial kwargs = {} else: raise ValueError( "partial_beta_diversity is only compatible with " "optimized unifrac methods and callable functions." ) dm = np.zeros((len(ids), len(ids))) id_index = {id_: idx for idx, id_ in enumerate(ids)} id_pairs_indexed = ((id_index[u], id_index[v]) for u, v in id_pairs) for u, v in id_pairs_indexed: dm[u, v] = func(counts[u], counts[v], **kwargs) return DistanceMatrix(dm + dm.T, ids) scikit-bio-scikit-bio-a3beaa6/skbio/diversity/_phylogenetic.pyx000066400000000000000000000160321520735541300251010ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np cimport numpy as np cimport cython # platform-specific INDEX_DTYPE = np.intp # use 64-bit ints for counts (otherwise, overflows on 32-bit systems ie WASM) COUNT_DTYPE = np.int64 ctypedef np.npy_intp intp_t ctypedef np.int64_t count_t @cython.boundscheck(False) @cython.wraparound(False) def _tip_distances(np.ndarray[np.double_t, ndim=1] a, object t, np.ndarray[intp_t, ndim=1] tip_indices): """Sets each tip to its distance from the root Parameters ---------- a : np.ndarray of double A matrix in which each row corresponds to a node in ``t``. t : skbio.tree.TreeNode The tree that corresponds to the rows in ``a``. tip_indices : np.ndarray of int The index positions in ``a`` of the tips in ``t``. Returns ------- np.ndarray of double A matrix in which each row corresponds to a node in ``t``, Only the rows that correspond to tips are nonzero, and the values in these rows are the distance from that tip to the root of the tree. """ cdef: object n Py_ssize_t i, p_i, n_rows np.ndarray[np.double_t, ndim=1] mask np.ndarray[np.double_t, ndim=1] tip_ds = a.copy() # preorder reduction over the tree to gather distances at the tips n_rows = tip_ds.shape[0] for n in t.preorder(include_self=False): i = n.id p_i = n.parent.id tip_ds[i] += tip_ds[p_i] # construct a mask that represents the locations of the tips mask = np.zeros(n_rows, dtype=np.double) for i in range(tip_indices.shape[0]): mask[tip_indices[i]] = 1.0 # apply the mask such that tip_ds only includes values which correspond to # the tips of the tree. for i in range(n_rows): tip_ds[i] *= mask[i] return tip_ds @cython.boundscheck(False) @cython.wraparound(False) cdef _traverse_reduce(np.ndarray[intp_t, ndim=2] child_index, np.ndarray[count_t, ndim=2] a): """Apply a[k] = sum[i:j] Parameters ---------- child_index: np.array of int A matrix in which the first column corresponds to an index position in ``a``, which represents a node in a tree. The second column is the starting index in ``a`` for the node's children, and the third column is the ending index in ``a`` for the node's children. a : np.ndarray of int A matrix of the environment data. Each row corresponds to a node in a tree, and each column corresponds to an environment. On input, it is assumed that only tips have counts. Notes ----- This is effectively a postorder reduction over the tree. For example, given the following tree: /-A /E-------| | \-B -root----| | /-C \F-------| \-D And assuming counts for [A, B, C, D] in environment FOO of [1, 1, 1, 0] and counts for environment BAR of [0, 1, 1, 1], the input counts matrix ``a`` would be: [1 0 -> A 1 1 -> B 1 1 -> C 0 1 -> D 0 0 -> E 0 0 -> F 0 0] -> root The method will perform the following reduction: [1 0 [1 0 [1 0 [1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 -> 0 1 -> 0 1 -> 0 1 0 0 2 1 2 1 2 1 0 0 0 0 1 2 1 2 0 0] 0 0] 0 0] 3 3] The index positions of the above are encoded in ``child_index`` which describes the node to aggregate into, and the start and stop index positions of the nodes immediate descendents. This method operates inplace on ``a`` """ cdef: Py_ssize_t i, j, k intp_t node, start, end count_t n_envs = a.shape[1] # possible GPGPU target for i in range(child_index.shape[0]): node = child_index[i, 0] start = child_index[i, 1] end = child_index[i, 2] for j in range(start, end + 1): for k in range(n_envs): a[node, k] += a[j, k] @cython.boundscheck(False) @cython.wraparound(False) def _nodes_by_counts(np.ndarray counts, np.ndarray tip_ids, dict indexed): """Construct the count array, and the counts up the tree Parameters ---------- counts : np.array of int A 1D or 2D vector in which each row corresponds to the observed counts in an environment. The rows are expected to be in order with respect to `tip_ids`. tip_ids : np.array of str A vector of tip names that correspond to the columns in the `counts` matrix. indexed : dict The result of `index_tree`. Returns ------- np.array of int The observed counts of every node and the counts if its descendents. """ cdef: np.ndarray nodes, observed_ids np.ndarray[count_t, ndim=2] count_array, counts_t np.ndarray[intp_t, ndim=1] observed_indices, taxa_in_nodes Py_ssize_t i, j set observed_ids_set object n dict node_lookup count_t n_count_vectors, n_count_taxa nodes = indexed['name'] # allow counts to be a vector counts = np.atleast_2d(counts) counts = counts.astype(COUNT_DTYPE, copy=False) # determine observed IDs. It may be possible to unroll these calls to # squeeze a little more performance observed_indices = counts.sum(0).nonzero()[0] observed_ids = tip_ids[observed_indices] observed_ids_set = set(observed_ids) # construct mappings of the observed to their positions in the node array node_lookup = {} for i in range(nodes.shape[0]): n = nodes[i] if n in observed_ids_set: node_lookup[n] = i # determine the positions of the observed IDs in nodes taxa_in_nodes = np.zeros(observed_ids.shape[0], dtype=INDEX_DTYPE) for i in range(observed_ids.shape[0]): n = observed_ids[i] taxa_in_nodes[i] = node_lookup[n] # count_array has a row per node (not tip) and a column per env. n_count_vectors = counts.shape[0] count_array = np.zeros((nodes.shape[0], n_count_vectors), dtype=COUNT_DTYPE) # populate the counts array with the counts of each observation in each # env counts_t = counts.transpose() n_count_taxa = taxa_in_nodes.shape[0] for i in range(n_count_taxa): for j in range(n_count_vectors): count_array[taxa_in_nodes[i], j] = counts_t[observed_indices[i], j] child_index = indexed['child_index'].astype(INDEX_DTYPE, copy=False) _traverse_reduce(child_index, count_array) return count_arrayscikit-bio-scikit-bio-a3beaa6/skbio/diversity/_util.py000066400000000000000000000134371520735541300232020ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from skbio.tree import DuplicateNodeError, MissingNodeError from skbio.diversity._phylogenetic import _nodes_by_counts def _validate_counts(counts, cast_int=False): """Validate and convert input to an acceptable counts vector/matrix type. Parameters ---------- counts : array_like of shape (n_taxa,) or (n_samples, n_taxa) Vector or matrix of counts. cast_int : bool, optional Whether cast values into integers, if not already. Default is False. Returns ------- ndarray of shape (n_taxa,) or (n_samples, n_taxa) Valid counts vector or matrix. Raises ------ ValueError If input array has an invalid data type. ValueError If input array contains negative values. Notes ----- This function will return the original ``counts`` if it is already a valid counts vector. Otherwise it will return an edited copy that is valid. The data type of counts must be any subtype of ``np.integer`` (integers) or ``np.floating`` (floating-point numbers; excluding complex numbers) [1]_. References ---------- .. [1] https://numpy.org/doc/stable/reference/arrays.scalars.html """ counts = np.asarray(counts) dtype = counts.dtype if np.issubdtype(dtype, np.floating): if cast_int: counts = counts.astype(int) elif not np.issubdtype(dtype, np.integer) and dtype is not np.dtype("bool"): raise ValueError("Counts must be integers or floating-point numbers.") # This is more efficient that `(counts < 0).any()`, but a more efficient way is to # iterate by element and exit early on the first negative value. if counts.size > 0 and counts.min() < 0: raise ValueError("Counts cannot contain negative values.") return counts def _validate_counts_vector(counts, cast_int=False): """Validate and convert input to an acceptable counts vector type. Parameters ---------- counts : array_like of int or float of shape (n_taxa,) Vector of counts. cast_int : bool, optional Whether cast values into integers, if not already. Default is False. Returns ------- ndarray of int or float of shape (n_taxa,) Valid counts vector. Raises ------ ValueError If counts has more than 1 dimension. """ counts = _validate_counts(counts, cast_int=cast_int) if counts.ndim != 1: raise ValueError("`counts` must be a 1-D array (vector).") return counts def _validate_counts_matrix(counts, cast_int=False): """Validate and convert input to an acceptable counts matrix type. Parameters ---------- counts : array_like of shape (n_samples, n_taxa) Matrix of counts. cast_int : bool, optional Whether cast values into integers, if not already. Default is False. Returns ------- ndarray of shape (n_samples, n_taxa) Valid counts matrix. Raises ------ ValueError If counts has more than 2 dimensions. """ msg = "`counts` has {} dimensions whereas up to 2 dimensions are allowed." counts = _validate_counts(counts, cast_int=cast_int) counts = np.atleast_2d(counts) if counts.ndim > 2: raise ValueError(msg.format(counts.ndim)) return counts def vectorize_counts_and_tree(counts, taxa, tree): """Index tree and convert counts to np.array in corresponding order. Parameters ---------- counts : array_like of shape (n_samples, n_taxa) or (n_taxa,) Counts/abundances of taxa in one or multiple samples. taxa : array_like of shape (n_taxa,) Taxon IDs corresponding to tip names in `tree`. tree : skbio.TreeNode Tree relating taxa. The set of tip names in the tree can be a superset of `taxa`, but not a subset. Returns ------- ndarray of shape (n_samples, n_nodes) Total counts/abundances of taxa descending from individual nodes of the tree. dict of array Indexed tree. See `to_array`. ndarray of shape (n_nodes,) Branch lengths of corresponding nodes of the tree. See Also -------- skbio.tree.TreeNode.to_array Notes ----- Leveraging internal node counts in the tree (in addition to tip abundances) can double the accuracy in downstream machine learning pipelines [1]_. References ---------- .. [1] Martino C., McDonald D., Cantrell K., Dilmore AH., Vázquez-Baeza Y., Shenhav L., Shaffer J.P., Rahman G., Armstrong G., Allaband C., Song S.J., Knight R. Compositionally aware phylogenetic beta-diversity measures better resolve microbiomes associated with phenotype. mSystems. 7(3) (2022). """ tree_index = tree.to_array(nan_length_value=0.0) taxa = np.asarray(taxa) counts = np.atleast_2d(counts) counts_by_node = _nodes_by_counts(counts, taxa, tree_index) branch_lengths = tree_index["length"] # branch_lengths is just a reference to the array inside of tree_index, # but it's used so much that it's convenient to just pull it out here. return counts_by_node.T, tree_index, branch_lengths def _get_phylogenetic_kwargs(kwargs, taxa): if taxa is None: raise ValueError("`taxa` is required for phylogenetic diversity metrics.") try: tree = kwargs.pop("tree") except KeyError: raise ValueError("`tree` is required for phylogenetic diversity metrics.") return taxa, tree, kwargs def _qualify_counts(counts): return counts > 0.0 scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/000077500000000000000000000000001520735541300225715ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/__init__.py000066400000000000000000000113041520735541300247010ustar00rootroot00000000000000r"""Alpha diversity measures (:mod:`skbio.diversity.alpha`) ======================================================= .. currentmodule:: skbio.diversity.alpha This package provides implementations of various alpha diversity [1]_ metrics, including measures of richness, diversity, evenness, dominance, and coverage. Some functions generate confidence intervals (CIs). These functions have the suffix ``_ci``. Richness metrics ---------------- **Richness** [2]_ measures the number of species (taxa) in a community. Due to incomplete sampling, the number of observed species (``sobs``) in a sample is usually lower than the true number of species in the community. Metrics have been proposed to estimate the latter based on the distribution of observed species in the sample. .. autosummary:: :toctree: ace chao1 chao1_ci doubles faith_pd margalef menhinick michaelis_menten_fit observed_features osd singles sobs Diversity metrics ----------------- **Diversity** [3]_ measures the number and relative abundances of species (taxa) in a community. It combines richness and evenness. Some diversity metrics describe the effective number of species (a.k.a., true diversity) -- the number of equally-abundant species that produce the same diversity measurement. .. autosummary:: :toctree: brillouin_d enspie fisher_alpha hill inv_simpson kempton_taylor_q phydiv renyi shannon simpson tsallis Evenness metrics ---------------- **Evenness** [4]_ (or equitability) measures the closeness of species (taxa) in a community in terms of abundance (number of individuals within the species). The calculation of evenness involves the relative abundances of species. .. autosummary:: :toctree: heip_e mcintosh_e pielou_e simpson_e Dominance metrics ----------------- **Dominance** [5]_ (or concentration) measures the degree that one or a few most abundant species (taxa) represent the great majority of a community. It can be considered as a measure of community unevenness. It should be noted that higher dominance corresponds to lower biodiversity. .. autosummary:: :toctree: berger_parker_d dominance gini_index mcintosh_d simpson_d strong Coverage metrics ---------------- **Coverage** [6]_ measures the proportion of individuals of a community that have been observed (or unobserved) in a sample. It describes the completeness of sampling. .. autosummary:: :toctree: esty_ci goods_coverage lladser_ci lladser_pe robbins References ---------- .. [1] https://en.wikipedia.org/wiki/Alpha_diversity .. [2] https://en.wikipedia.org/wiki/Species_richness .. [3] https://en.wikipedia.org/wiki/Species_diversity .. [4] https://en.wikipedia.org/wiki/Species_evenness .. [5] https://en.wikipedia.org/wiki/Dominance_%28ecology%29 .. [6] Good, I. J. (1953). The population frequencies of species and the estimation of population parameters. Biometrika, 40(3-4), 237-264. """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._base import ( berger_parker_d, brillouin_d, dominance, doubles, enspie, esty_ci, fisher_alpha, goods_coverage, heip_e, hill, inv_simpson, kempton_taylor_q, margalef, mcintosh_d, mcintosh_e, menhinick, michaelis_menten_fit, observed_features, osd, pielou_e, renyi, robbins, shannon, simpson, simpson_d, simpson_e, singles, sobs, strong, tsallis, ) from ._ace import ace from ._chao1 import chao1, chao1_ci from ._gini import gini_index from ._lladser import lladser_pe, lladser_ci from ._pd import faith_pd, phydiv __all__ = [ "ace", "chao1", "chao1_ci", "berger_parker_d", "brillouin_d", "dominance", "doubles", "enspie", "esty_ci", "faith_pd", "fisher_alpha", "gini_index", "goods_coverage", "heip_e", "hill", "inv_simpson", "kempton_taylor_q", "lladser_pe", "lladser_ci", "margalef", "mcintosh_d", "mcintosh_e", "menhinick", "michaelis_menten_fit", "observed_features", "osd", "phydiv", "pielou_e", "renyi", "robbins", "shannon", "simpson", "simpson_d", "simpson_e", "singles", "sobs", "strong", "tsallis", ] from sys import modules from skbio.util._decorator import register_aliases register_aliases(modules[__name__]) scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/_ace.py000066400000000000000000000107271520735541300240410ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from skbio.diversity._util import _validate_counts_vector def ace(counts, rare_threshold=10): r"""Calculate the ACE metric (Abundance-based Coverage Estimator). The ACE metric is defined as: .. math:: S_{ace}=S_{abund}+\frac{S_{rare}}{C_{ace}}+ \frac{F_1}{C_{ace}}\gamma^2_{ace} where :math:`S_{abund}` is the number of abundant taxa (with more than ``rare_threshold`` individuals) when all samples are pooled, :math:`S_{rare}` is the number of rare taxa (with less than or equal to ``rare_threshold`` individuals) when all samples are pooled, :math:`C_{ace}` is the sample abundance coverage estimator, :math:`F_1` is the frequency of singletons, and :math:`\gamma^2_{ace}` is the estimated coefficient of variation for rare taxa. The estimated coefficient of variation is defined as (assuming ``rare_threshold`` is 10, the default): .. math:: \gamma^2_{ace}=max\left[\frac{S_{rare}}{C_{ace}} \frac{\sum^{10}_{i=1}{{i\left(i-1\right)}}F_i} {\left(N_{rare}\right)\left(N_{rare}-1\right)} -1,0\right] Parameters ---------- counts : 1-D array_like, int Vector of counts. rare_threshold : int, optional Threshold at which a taxon containing as many or fewer individuals will be considered rare. Returns ------- double Computed ACE metric. Raises ------ ValueError If every rare taxon is a singleton. Notes ----- ACE was first introduced in [1]_ and [2]_. The implementation here is based on the description given in the EstimateS manual [3]_. If no rare taxa exist, returns the number of abundant taxa. The default value of 10 for `rare_threshold` is based on [4]_. If ``counts`` contains zeros, indicating taxa which are known to exist in the environment but did not appear in the sample, they will be ignored for the purpose of calculating the number of rare taxa. References ---------- .. [1] Chao, A. & S.-M Lee. 1992 Estimating the number of classes via sample coverage. Journal of the American Statistical Association 87, 210-217. .. [2] Chao, A., M.-C. Ma, & M. C. K. Yang. 1993. Stopping rules and estimation for recapture debugging with unequal failure rates. Biometrika 80, 193-201. .. [3] http://viceroy.eeb.uconn.edu/estimates/ .. [4] Chao, A., W.-H. Hwang, Y.-C. Chen, and C.-Y. Kuo. 2000. Estimating the number of shared species in two communities. Statistica Sinica 10:227-246. """ counts = _validate_counts_vector(counts) freq_counts = np.bincount(counts) s_rare = _taxa_rare(freq_counts, rare_threshold) singles = freq_counts[1] if singles > 0 and singles == s_rare: raise ValueError( "The only rare taxa are singletons, so the ACE " "metric is undefined. EstimateS suggests using " "bias-corrected Chao1 instead." ) s_abun = _taxa_abundant(freq_counts, rare_threshold) if s_rare == 0: return s_abun n_rare = _number_rare(freq_counts, rare_threshold) c_ace = 1 - singles / n_rare top = s_rare * _number_rare(freq_counts, rare_threshold, gamma=True) bottom = c_ace * n_rare * (n_rare - 1) gamma_ace = (top / bottom) - 1 if gamma_ace < 0: gamma_ace = 0 return s_abun + (s_rare / c_ace) + ((singles / c_ace) * gamma_ace) def _taxa_rare(freq_counts, rare_threshold): """Count number of rare taxa.""" return freq_counts[1 : rare_threshold + 1].sum() def _taxa_abundant(freq_counts, rare_threshold): """Count number of abundant taxa.""" return freq_counts[rare_threshold + 1 :].sum() def _number_rare(freq_counts, rare_threshold, gamma=False): """Return number of individuals in rare taxa. ``gamma=True`` generates the ``n_rare`` used for the variation coefficient. """ n_rare = 0 if gamma: for i, j in enumerate(freq_counts[: rare_threshold + 1]): n_rare += (i * j) * (i - 1) else: for i, j in enumerate(freq_counts[: rare_threshold + 1]): n_rare += i * j return n_rare scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/_base.py000066400000000000000000001201711520735541300242160ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import functools import numpy as np from scipy.special import gammaln from scipy.optimize import fmin_powell, minimize_scalar from skbio.stats import subsample_counts from skbio.diversity._util import _validate_counts_vector from skbio.util._decorator import aliased def _validate_alpha(empty=None, cast_int=False): """Validate counts vector for an alpha diversity metric. Parameters ---------- func : callable Function that calculates an alpha diversity metric. empty : any, optional Return this value if set instead of calling the function when an input community is empty (i.e., no taxon, or all taxa have zero counts). cast_int : bool, optional Whether cast values into integers, if not already. Default is False. Returns ------- callable Decorated function. Notes ----- This function serves as a decorator for individual functions that calculate alpha diversity metrics. The first positional argument of a decorated function must be a 1-D vector of counts/abundances of taxa in a community. Additional arguments may follow. """ def decorator(func): @functools.wraps(func) def wrapper(counts, *args, **kwargs): counts = _validate_counts_vector(counts, cast_int) # drop zero values, as these represent taxa that are absent from # the community if not (nonzero := counts != 0).all(): counts = counts[nonzero] # return a value if community is empty (after dropping zeros) if empty is not None and counts.size == 0: return empty # call function to calculate alpha diversity metric return func(counts, *args, **kwargs) return wrapper return decorator @_validate_alpha(empty=np.nan) def berger_parker_d(counts): r"""Calculate Berger-Parker dominance index. Berger-Parker dominance index :math:`d` is defined as the fraction of the sample that belongs to the most abundant taxon: .. math:: d = \frac{n_{max}}{N} where :math:`n_{max}` is the number of individuals in the most abundant taxon (or any of the most abundant taxa in the case of ties), and :math:`N` is the total number of individuals in the sample. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float Berger-Parker dominance index. Notes ----- Berger-Parker dominance index was originally described in [1]_. References ---------- .. [1] Berger, W. H., & Parker, F. L. (1970). Diversity of planktonic foraminifera in deep-sea sediments. Science, 168(3937), 1345-1347. """ return counts.max() / counts.sum() @_validate_alpha(empty=np.nan) def brillouin_d(counts): r"""Calculate Brillouin's diversity index. Brillouin's diversity index (:math:`H_B`) is defined as: .. math:: H_B = \frac{\ln N!-\sum_{i=1}^S{\ln n_i!}}{N} where :math:`N` is the total number of individuals in the sample, :math:`S` is the number of taxa, and :math:`n_i` is the number of individuals in the :math:`i^{\text{th}}` taxon. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float Brillouin's diversity index. Notes ----- Brillouin's diversity index was originally described in [1]_. References ---------- .. [1] Brillouin, L. (1956). Science and Information Theory. Academic Press. New York. """ return (gammaln((N := counts.sum()) + 1) - gammaln(counts + 1).sum()) / N @_validate_alpha(empty=np.nan) def dominance(counts, finite=False): r"""Calculate Simpson's dominance index. Simpson's dominance index, a.k.a. Simpson's :math:`D`, measures the degree of concentration of taxon composition of a sample. It is defined as: .. math:: D = \sum_{i=1}^S{p_i^2} where :math:`S` is the number of taxa and :math:`p_i` is the proportion of the sample represented by taxon :math:`i`. Simpson's :math:`D` ranges from 0 (infinite diversity; no dominance) to 1 (complete dominance, no diversity). Simpson's :math:`D` can be interpreted as the probability that two randomly selected individuals belong to the same taxon. Simpson's :math:`D` may be corrected for finite samples to account for the effect of sampling without replacement. This more accurately represents the above probability when the sample is small. It is calculated as: .. math:: D = \frac{\sum_{i=1}^s{n_i(n_i - 1))}}{N(N - 1)} where :math:`n_i` is the number of individuals in the :math:`i^{\text{th}}` taxon and :math:`N` is the total number of individuals in the sample. Simpson's :math:`D` is sometimes referred to as "Simpson's index". It should be noted that :math:`D` is not a measure of community diversity. It is also important to distinguish :math:`D` from Simpson's diversity index (:math:`1 - D`) and inverse Simpson index (:math:`1 / D`), both of which are measures of community diversity. Discrepancy exists among literature in using the term "Simpson index" and the denotion :math:`D`. It is therefore important to distinguish these metrics according to their mathematic definition. Parameters ---------- counts : 1-D array_like, int Vector of counts. finite : bool, optional If True, correct for finite sampling. Returns ------- float Simpson's dominance index. See Also -------- simpson Notes ----- Simpson's dominance index was originally described in [1]_. References ---------- .. [1] Simpson, E. H. (1949). Measurement of diversity. Nature, 163(4148), 688-688. """ if finite: D = (counts * (counts - 1)).sum() / ((N := counts.sum()) * (N - 1)) else: D = ((counts / counts.sum()) ** 2).sum() return D @_validate_alpha() def doubles(counts): """Calculate number of double-occurrence taxa (doubletons). Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- int Doubleton count. """ return (counts == 2).sum() def enspie(counts, finite=False): r"""Calculate ENS_pie alpha diversity measure. The effective number of species (ENS) derived from Hurlbert's probability of interspecific encounter (PIE) ([1]_, [2]_) is defined as: .. math:: ENS_{pie} = \frac{1}{\sum_{i=1}^S{p_i^2}} where :math:`S` is the number of taxa and :math:`p_i` is the proportion of the sample represented by taxon :math:`i`. Therefore, :math:`ENS_{pie}` is equivalent to the inverse Simpson index (``1 / D``). Parameters ---------- counts : 1-D array_like, int Vector of counts. finite : bool, optional If True, correct for finite sampling. Returns ------- float ENS_pie alpha diversity measure. See Also -------- inv_simpson dominance Notes ----- ``enspie`` is an alias for ``inv_simpson``. References ---------- .. [1] Chase, J. M., & Knight, T. M. (2013). Scale-dependent effect sizes of ecological drivers on biodiversity: why standardised sampling is not enough. Ecology letters, 16, 17-26. .. [2] Hurlbert, S. H. (1971). The nonconcept of species diversity: a critique and alternative parameters. Ecology, 52(4), 577-586. """ return inv_simpson(counts, finite=finite) @_validate_alpha(empty=np.nan) def esty_ci(counts): r"""Calculate Esty's confidence interval of Good's coverage estimator. Esty's confidence interval is defined as: .. math:: F_1/N \pm z\sqrt{W} where :math:`F_1` is the number of singleton taxa, :math:`N` is the total number of individuals, and :math:`z` is a constant that depends on the targeted confidence and based on the normal distribution. :math:`W` is defined as: .. math:: \frac{F_1(N-F_1)+2NF_2}{N^3} where :math:`F_2` is the number of doubleton taxa. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- tuple Esty's confidence interval as ``(lower_bound, upper_bound)``. See Also -------- goods_coverage Notes ----- Esty's confidence interval was originally described in [1]_. :math:`z` is hardcoded for a 95% confidence interval. References ---------- .. [1] Esty, W. W. (1983). "A normal limit law for a nonparametric estimator of the coverage of a random sample". Ann Statist 11: 905-912. """ N = counts.sum() f1 = (counts == 1).sum() f2 = (counts == 2).sum() z = 1.959963985 W = (f1 * (N - f1) + 2 * N * f2) / (N**3) return f1 / N - z * np.sqrt(W), f1 / N + z * np.sqrt(W) @_validate_alpha(empty=np.nan) def fisher_alpha(counts): r"""Calculate Fisher's alpha, a metric of diversity. Fisher's alpha is estimated by solving the following equation for :math:`\alpha`: .. math:: S=\alpha\ln(1+\frac{N}{\alpha}) where :math:`S` is the number of taxa and :math:`N` is the total number of individuals in the sample. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float Fisher's alpha. Raises ------ RuntimeError If the optimizer fails to solve for Fisher's alpha. Notes ----- Fisher's alpha is defined in [1]_. There is no analytical solution to Fisher's alpha. However, one can use optimization techniques to obtain a numeric solution. This function calls SciPy's ``minimize_scalar`` to find alpha. It is deterministic. The result should be reasonably close to the true alpha. Alpha can become large when most taxa are singletons. Alpha = +inf when all taxa are singletons. When the sample is empty (i.e., all counts are zero), alpha = 0. References ---------- .. [1] Fisher, R.A., Corbet, A.S. and Williams, C.B., 1943. The relation between the number of taxa and the number of individuals in a random sample of an animal population. The Journal of Animal Ecology, pp.42-58. """ # alpha = +inf when all taxa are singletons if (N := counts.sum()) == (S := counts.size): return np.inf # objective function to minimize: # S = alpha * ln (1 + N / alpha), where alpha > 0 def f(x): return (x * np.log(1 + (N / x)) - S) ** 2 if x > 0 else np.inf # minimize the function using the default method (Brent's algorithm) with np.errstate(invalid="ignore"): res = minimize_scalar(f) # there is a chance optimization could fail if res.success is False: raise RuntimeError("Optimizer failed to solve for Fisher's alpha.") return res.x @_validate_alpha(empty=np.nan) def goods_coverage(counts): r"""Calculate Good's coverage estimator. Good's coverage estimator :math:`C`, a.k.a. Turing estimator or Good- Turing (GT) estimator, is an estimation of the proportion of the population represented in the sample. It is defined as: .. math:: C = 1 - \frac{F_1}{N} where :math:`F_1` is the number of taxa observed only once (i.e., singletons) and :math:`N` is the total number of individuals. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float Good's coverage estimator. See Also -------- esty_ci robbins Notes ----- Good's coverage estimator was originally described in [1]_. References ---------- .. [1] Good, I. J. (1953). The population frequencies of species and the estimation of population parameters. Biometrika, 40(3-4), 237-264. """ return 1 - ((counts == 1).sum() / counts.sum()) @_validate_alpha() def heip_e(counts): r"""Calculate Heip's evenness measure. Heip's evenness is defined as: .. math:: \frac{(e^H-1)}{(S-1)} where :math:`H` is Shannon's diversity index and :math:`S` is the number of taxa in the sample. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float Heip's evenness measure. See Also -------- shannon pielou_e Notes ----- Heip's evenness measure was originally described in [1]_. When there is only one taxon, the return value is 1.0. References ---------- .. [1] Heip, C. 1974. A new index measuring evenness. J. Mar. Biol. Ass. UK., 54, 555-557. """ if (S := counts.size) == 0: return np.nan elif S == 1: return 1.0 return (shannon(counts, exp=True) - 1) / (S - 1) @_validate_alpha(empty=np.nan) def hill(counts, order=2): r"""Calculate Hill number. Hill number (:math:`^qD`) is a generalized measure of the effective number of species. It is defined as: .. math:: ^qD = (\sum_{i=1}^S p_i^q)^{\frac{1}{1-q}} where :math:`S` is the number of taxa and :math:`p_i` is the proportion of the sample represented by taxon :math:`i`. Parameters ---------- counts : 1-D array_like, int Vector of counts. order : int or float, optional Order (:math:`q`). Ranges between 0 and infinity. Default is 2. Returns ------- float Hill number. See Also -------- inv_simpson renyi shannon sobs Notes ----- Hill number was originally defined in [1]_. It is a measurement of "true diversity", or the effective number of species (ENS) ([2]_), which is defined as the number of equally abundant taxa that would make the same diversity measurement given the observed total abundance of the community. Hill number is a generalization of multiple diversity metrics. Depending on the order :math:`q`, it is equivalent to: - :math:`q=0`: Observed species richness (:math:`S_{obs}`). - :math:`q \to 1`: The exponential of Shannon index (:math:`\exp{H'}`), i.e., perplexity. - :math:`q=2`: Inverse Simpson index (:math:`1 / D`). - :math:`q \to \infty`: :math:`1/\max{p}`, i.e., the inverse of Berger-Parker dominance index. The order :math:`q` determines the influence of taxon abundance on the metric. A larger (or smaller) :math:`q` puts more weight on the abundant (or rare) taxa. Hill number is equivalent to the exponential of Renyi entropy. References ---------- .. [1] Hill, M. O. (1973). Diversity and evenness: a unifying notation and its consequences. Ecology, 54(2), 427-432. .. [2] Jost, L. (2006). Entropy and diversity. Oikos, 113(2), 363-375. """ probs = counts / counts.sum() if order == 1: return _perplexity(probs) elif np.isposinf(order): return 1 / probs.max() else: return (probs**order).sum() ** (1 / (1 - order)) @_validate_alpha(empty=np.nan) def kempton_taylor_q(counts, lower_quantile=0.25, upper_quantile=0.75): r"""Calculate Kempton-Taylor Q index of alpha diversity. Kempton-Taylor Q index measures diversity based on the middle-ranking taxa in the abundance distribution. Specifically, it estimates the slope of the cumulative abundance curve in the interquantile range. It is defined as: .. math:: Q = \frac{S_{lower..upper}}{\ln n_{lower} - \ln n_{upper}} where "lower" and "upper" are the taxa at the lower and upper quantiles of the abundance distribution, :math:`S` is the number of taxa, and :math:`n` is the number of individuals. By default, the lower and upper quartiles are used. Therefore: .. math:: Q = \frac{S}{2(\ln n_{0.25} - \ln n_{0.75})} The quantiles are rounded inwards in this implementation. Parameters ---------- counts : 1-D array_like, int Vector of counts. lower_quantile : float, optional Lower bound of the interquantile range. Defaults to lower quartile. upper_quantile : float, optional Upper bound of the interquantile range. Defaults to upper quartile. Returns ------- float Kempton-Taylor Q index of alpha diversity. Notes ----- The index is defined in [1]_. The implementation here is based on the description given in the SDR-IV online manual [2]_. The implementation provided here differs slightly from the results given in Magurran 1998. Specifically, we have 14 in the numerator rather than 15. Magurran recommends counting half of the taxa with the same # counts as the point where the UQ falls and the point where the LQ falls, but the justification for this is unclear (e.g. if there were a very large # taxa that just overlapped one of the quantiles, the results would be considerably off). Leaving the calculation as-is for now, but consider changing. References ---------- .. [1] Kempton, R. A. and Taylor, L. R. (1976) Models and statistics for species diversity. Nature, 262, 818-820. .. [2] http://www.pisces-conservation.com/sdrhelp/index.html """ S = counts.size lower = int(np.ceil(S * lower_quantile)) upper = int(S * upper_quantile) sorted_counts = np.sort(counts) return (upper - lower) / np.log(sorted_counts[upper] / sorted_counts[lower]) def inv_simpson(counts, finite=False): r"""Calculate inverse Simpson index. The inverse Simpson index (:math:`1 / D`), a.k.a., Simpson's reciprocal index, is defined as: .. math:: 1 / D = \frac{1}{\sum_{i=1}^S{p_i^2}} where :math:`S` is the number of taxa and :math:`p_i` is the proportion of the sample represented by taxon :math:`i`. Parameters ---------- counts : 1-D array_like, int Vector of counts. finite : bool, optional If True, correct for finite sampling when calculating :math:`D`. Returns ------- float Inverse Simpson index. See Also -------- dominance Notes ----- :math:`1 / D` is a measurement of the effective number of species (ENS). It is equivalent to Hill number with order 2 (:math:`^2D`). Inverse Simpson index was originally described in [1]_. References ---------- .. [1] Simpson, E. H. (1949). Measurement of diversity. Nature, 163(4148), 688-688. """ return 1 / dominance(counts, finite=finite) @_validate_alpha(empty=np.nan) def margalef(counts): r"""Calculate Margalef's richness index. Margalef's richness index :math:`D` is defined as: .. math:: D = \frac{(S - 1)}{\ln N} where :math:`S` is the number of taxa and :math:`N` is the total number of individuals in the sample. Margalef's richness index assumes log accumulation. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float Margalef's richness index. See Also -------- menhinick Notes ----- Margalef's richness index was originally described in [1]_. References ---------- .. [1] Margalef, R. (1958) Information Theory in Ecology. General Systems, 3, 36-71. """ if (N := counts.sum()) == 1: return np.nan return (counts.size - 1) / np.log(N) @_validate_alpha(empty=np.nan) def mcintosh_d(counts): r"""Calculate McIntosh dominance index. McIntosh dominance index :math:`D` is defined as: .. math:: D = \frac{N - U}{N - \sqrt{N}} where :math:`N` is the total number of individuals in the sample and :math:`U` is defined as: .. math:: U = \sqrt{\sum{{n_i}^2}} where :math:`n_i` is the number of individuals in the :math:`i^{\text{th}}` taxon. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float McIntosh dominance index. See Also -------- mcintosh_e Notes ----- McIntosh dominance index was originally described in [1]_. References ---------- .. [1] McIntosh, R. P. 1967 An index of diversity and the relation of certain concepts to diversity. Ecology 48, 1115-1126. """ if (N := counts.sum()) == 1: return np.nan u = np.sqrt((counts**2).sum()) return (N - u) / (N - np.sqrt(N)) @_validate_alpha(empty=np.nan) def mcintosh_e(counts): r"""Calculate McIntosh's evenness measure. McIntosh's evenness measure :math:`E` is defined as: .. math:: E = \frac{\sqrt{\sum{n_i^2}}}{\sqrt{((N-S+1)^2 + S -1}} where :math:`n_i` is the number of individuals in the :math:`i^{\text{th}}` taxon, :math:`N` is the total number of individuals, and :math:`S` is the number of taxa in the sample. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float McIntosh evenness measure. See Also -------- mcintosh_d Notes ----- McIntosh's evenness measure was originally described in [1]_. References ---------- .. [1] Heip & Engels (1974) Comparing Species Diversity and Evenness Indices. p 560. """ S = counts.size N = counts.sum() numerator = np.sqrt((counts * counts).sum()) denominator = np.sqrt((N - S + 1) ** 2 + S - 1) return numerator / denominator @_validate_alpha(empty=np.nan) def menhinick(counts): r"""Calculate Menhinick's richness index. Menhinick's richness index is defined as: .. math:: D_{Mn} = \frac{S}{\sqrt{N}} where :math:`S` is the number of taxa and :math:`N` is the total number of individuals in the sample. Menhinick's richness index assumes square-root accumulation. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float Menhinick's richness index. See Also -------- margalef Notes ----- Based on the description in [1]_. References ---------- .. [1] Magurran, A E 2004. Measuring biological diversity. Blackwell. pp. 76-77. """ return counts.size / np.sqrt(counts.sum()) @_validate_alpha(empty=np.nan) def michaelis_menten_fit(counts, num_repeats=1, params_guess=None): r"""Calculate Michaelis-Menten fit to rarefaction curve of observed taxa. The Michaelis-Menten equation estimates the asymptote of the rarefaction curve. It is an estimator of the true richness of a community given the observation. It is defined as: .. math:: S = \frac{nS_{max}}{n+B} where :math:`n` is the number of individuals and :math:`S` is the number of taxa. This function estimates the :math:`S_{max}` parameter. The fit is made to datapoints for :math:`n=1,2,...,N`, where :math:`N` is the total number of individuals (sum of abundances for all taxa). :math:`S` is the number of taxa represented in a random sample of :math:`n` individuals. Parameters ---------- counts : 1-D array_like, int Vector of counts. num_repeats : int, optional The number of times to perform rarefaction (subsampling without replacement) at each value of :math:`n`. params_guess : tuple, optional Initial guess of :math:`S_{max}` and :math:`B`. If ``None``, default guess for :math:`S_{max}` is :math:`S` (as :math:`S_{max}` should be >= :math:`S`) and default guess for :math:`B` is ``round(N / 2)``. Returns ------- float Estimate of the :math:`S_{max}` parameter in the Michaelis-Menten equation. See Also -------- skbio.stats.subsample_counts Notes ----- There is some controversy about how to do the fitting. The ML model given in [1]_ is based on the assumption that error is roughly proportional to magnitude of observation, reasonable for enzyme kinetics but not reasonable for rarefaction data. Here we just do a nonlinear curve fit for the parameters using least-squares. References ---------- .. [1] Raaijmakers, J. G. W. 1987 Statistical analysis of the Michaelis-Menten equation. Biometrics 43, 793-803. """ n_indiv = counts.sum() if params_guess is None: S_max_guess = sobs(counts) B_guess = int(round(n_indiv / 2)) params_guess = (S_max_guess, B_guess) # observed # of taxa vs # of individuals sampled, S vs n xvals = np.arange(1, n_indiv + 1) ymtx = np.empty((num_repeats, len(xvals)), dtype=int) for i in range(num_repeats): ymtx[i] = np.asarray( [sobs(subsample_counts(counts, n)) for n in xvals], dtype=int ) yvals = ymtx.mean(0) # Vectors of actual vals y and number of individuals n. def errfn(p, n, y): return (((p[0] * n / (p[1] + n)) - y) ** 2).sum() # Return S_max. return fmin_powell(errfn, params_guess, ftol=1e-5, args=(xvals, yvals), disp=False)[ 0 ] def observed_features(counts): """Calculate the number of distinct features. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- int Distinct feature count. See Also -------- sobs Notes ----- ``observed_features`` is an alias for ``sobs``. """ return sobs(counts) @_validate_alpha() def osd(counts): """Calculate observed taxa, singletons, and doubletons. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- osd : tuple Numbers of observed taxa, singletons, and doubletons. See Also -------- sobs singles doubles Notes ----- This is a convenience function used by many of the other measures that rely on these three measures. """ return counts.size, (counts == 1).sum(), (counts == 2).sum() @_validate_alpha() def pielou_e(counts, base=None): r"""Calculate Pielou's evenness index. Pielou's evenness index (:math:`J'`), a.k.a., Shannon's equitability index (:math:`E_H`), is defined as: .. math:: J' = \frac{(H)}{\log(S)} where :math:`H` is the Shannon index of the sample and :math:`S` is the number of taxa in the sample. That is, :math:`J'` is the ratio of the actual Shannon index of the sample versus the maximum-possible Shannon index when all taxa have the same number of individuals. :math:`J'` ranges between 0 and 1. Parameters ---------- counts : 1-D array_like, int Vector of counts. base : int or float, optional Logarithm base to use in the calculation. Default is ``e``. Returns ------- float Pielou's evenness index. See Also -------- shannon heip_e Notes ----- Pielou's evenness index was originally described in [1]_. When there is only one taxon, the return value is 1.0. References ---------- .. [1] Pielou, E. C., 1966. The measurement of diversity in different types of biological collections. Journal of Theoretical Biology, 13, 131-44. """ if (S := counts.size) == 0: return np.nan elif S == 1: return 1.0 H = shannon(counts, base=base) H_max = np.log(S) if base is not None: H_max /= np.log(base) return H / H_max @_validate_alpha() def renyi(counts, order=2, base=None): r"""Calculate Renyi entropy. Renyi entropy (:math:`^qH`) is a generalization of Shannon index, with an exponent (order) :math:`q` instead of 1. It is defined as: .. math:: ^qH = \frac{1}{1-q}\log_b{(\sum_{i=1}^S p_i^q)} where :math:`S` is the number of taxa and :math:`p_i` is the proportion of the sample represented by taxon :math:`i`. Parameters ---------- counts : 1-D array_like, int Vector of counts. order : int or float, optional Order (:math:`q`). Ranges between 0 and infinity. Default is 2. base : int or float, optional Logarithm base to use in the calculation. Default is ``e``. Returns ------- float Renyi entropy. See Also -------- hill inv_simpson shannon tsallis Notes ----- Renyi entropy was originally defined in [1]_. It is a generalization of multiple entropy notions, as determined by the order (:math:`q`). Special cases of Renyi entropy include: - :math:`q=0`: Max-entropy (:math:`\log{S}`). - :math:`q \to 1`: Shannon entropy (index). - :math:`q=2`: Collision entropy, a.k.a, Renyi's quadratic entropy, or "Renyi entropy". Equivalent to the logarithm of inverse Simpson index. - :math:`q \to \infty`: Min-entropy (:math:`-\log{\max{p}}`). Renyi entropy is equivalent to the logarithm of Hill number. References ---------- .. [1] Rényi, A. (1961, January). On measures of entropy and information. In Proceedings of the fourth Berkeley symposium on mathematical statistics and probability, volume 1: contributions to the theory of statistics (Vol. 4, pp. 547-562). University of California Press. """ if (S := counts.size) == 0: return np.nan elif S == 1: return 0.0 probs = counts / counts.sum() # max-entropy if order == 0: qH = np.log(S) # Shannon entropy elif order == 1: qH = _entropy(probs) # min-entropy elif np.isposinf(order): qH = -np.log(probs.max()) else: qH = np.log((probs**order).sum()) / (1 - order) if base is not None: qH /= np.log(base) return qH @_validate_alpha(empty=np.nan) def robbins(counts): r"""Calculate Robbins' estimator for probability of unobserved outcomes. Robbins' estimator is defined as: .. math:: \frac{F_1}{N} where :math:`F_1` is the number of singleton taxa and and :math:`N` is the total number of individuals in the sample. The result can be interpreted as the probability of discovering a new taxon at the :math:`N`-th individual given the current :math:`N - 1` individuals. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float Robbins' estimator. See Also -------- goods_coverage Notes ----- Robbins' estimator is defined in [1]_. References ---------- .. [1] Robbins, H. E. (1968). Estimating the total probability of the unobserved outcomes of an experiment. Ann. Math. Statist., 39(6), 256-257. """ return (counts == 1).sum() / counts.sum() def _entropy(probs): """Calculate entropy.""" return (-probs * np.log(probs)).sum() def _perplexity(probs): """Calculate perplexity.""" return (probs**-probs).prod() @_validate_alpha(empty=np.nan) def shannon(counts, base=None, exp=False): r"""Calculate Shannon's diversity index. Shannon's diversity index, :math:`H'`, a.k.a., Shannon index, or Shannon- Wiener index, is equivalent to entropy in information theory. It is defined as: .. math:: H' = -\sum_{i=1}^S\left(p_i\log_b(p_i)\right) where :math:`S` is the number of taxa and :math:`p_i` is the proportion of the sample represented by taxon :math:`i`. The logarithm base :math:`b` defaults to ``e``, but may be 2, 10 or other custom values. The exponential of Shannon index, :math:`exp(H')`, measures the effective number of species (a.k.a., true diversity). It is equivalent to perplexity in information theory, or Hill number with order 1 (:math:`^1D`). The value is independent from the base: .. math:: exp(H') = b ^ {-\sum_{i=1}^S\left(p_i\log_b(p_i)\right)} = \prod_{i=1} ^{S}p_i^{-p_i} Parameters ---------- counts : 1-D array_like, int Vector of counts. base : int or float, optional Logarithm base to use in the calculation. Default is ``e``. .. versionchanged:: 0.6.1 The default logarithm base was changed from 2 to :math:`e` for consistency with the majority of literature. exp : bool, optional If True, return the exponential of Shannon index. Returns ------- float Shannon's diversity index. Notes ----- Shannon index (i.e., entropy) was originally proposed in [1]_. The exponential of Shannon index (i.e., perplexity) was discussed in [2]_ in the context of community diversity. References ---------- .. [1] Shannon, C. E. (1948). A mathematical theory of communication. The Bell system technical journal, 27(3), 379-423. .. [2] Jost, L. (2006). Entropy and diversity. Oikos, 113(2), 363-375. """ probs = counts / counts.sum() # perplexity if exp is True: return _perplexity(probs) # entropy else: H = _entropy(probs) if base is not None: H /= np.log(base) return H def simpson(counts, finite=False): r"""Calculate Simpson's diversity index. Simpson's diversity index, a.k.a., Gini-Simpson index, or Gini impurity, is defined as: .. math:: 1 - \sum_{i=1}^S{p_i^2} where :math:`S` is the number of taxa and :math:`p_i` is the proportion of the sample represented by taxon :math:`i`. Therefore, Simpson's diversity index is also denoted as :math:`1 - D`, in which :math:`D` is the Simpson's dominance index. Simpson's diversity index can be interpreted as the probability that two randomly selected individuals belong to different taxa. It is also known as Hurlbert's probability of interspecific encounter (PIE). Parameters ---------- counts : 1-D array_like, int Vector of counts. finite : bool, optional If True, correct for finite sampling when calculating :math:`D`. Returns ------- float Simpson's diversity index. See Also -------- dominance Notes ----- Simpson's diversity index was originally described in [1]_. Hurlbert's probability of interspecific encounter was described in [2]_. References ---------- .. [1] Simpson, E. H. (1949). Measurement of diversity. Nature, 163(4148), 688-688. .. [2] Hurlbert, S. H. (1971). The nonconcept of species diversity: a critique and alternative parameters. Ecology, 52(4), 577-586. """ return 1 - dominance(counts, finite=finite) def simpson_d(counts, finite=False): """Calculate Simpson's dominance index, a.k.a. Simpson's D. Parameters ---------- counts : 1-D array_like, int Vector of counts. finite : bool, optional If True, correct for finite sampling. Returns ------- int Simpson's dominance index. See Also -------- dominance simpson simpson_e Notes ----- ``simpson_d`` is an alias for ``dominance``. """ return dominance(counts, finite=finite) @_validate_alpha(empty=np.nan) def simpson_e(counts): r"""Calculate Simpson's evenness index. Simpson's evenness (a.k.a., equitability) index :math:`E_D` is defined as: .. math:: E_D = \frac{1}{D \times S} where :math:`D` is the Simpson's dominance index and :math:`S` is the number of taxa in the sample. That is, :math:`E_D` is the ratio of the minimum-possible Simpson's dominance index when all taxa have the same number of individuals: :math:`D_{min} = 1 / S`, versus the actual Simpson's dominance index of the sample. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float Simpson's evenness index. See Also -------- dominance simpson Notes ----- The implementation here is based on the description given in [1]_ and [2]_. References ---------- .. [1] Simpson, E. H. (1949). Measurement of diversity. nature, 163(4148), 688-688. .. [2] Pielou, E. C. (1966). The measurement of diversity in different types of biological collections. Journal of theoretical biology, 13, 131-144. """ # Note: the finite version of simpson_e might be: 1 / (D(S + 1)), because # S + 1 is the maximum possible finite D given S. Otherwise, the result can # be greater than 1 for small samples. However, I didn't find literature # stating this. Therefore, the `finite` parameter is not used here. return 1 / (counts.size * dominance(counts)) @_validate_alpha() def singles(counts): """Calculate number of single-occurrence taxa (singletons). Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- int Singleton count. """ return (counts == 1).sum() @aliased("observed_otus", "0.6.0", True) @_validate_alpha() def sobs(counts): """Calculate the observed species richness of a sample. Observed species richness, usually denoted as :math:`S_{obs}` or simply :math:`S`, is the number of distinct species (i.e., taxa), or any discrete groups of biological entities found in a sample. It should be noted that observed species richness is smaller than or equal to the true species richness of a population from which the sample is collected. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- int Observed species richness. See Also -------- observed_features """ return counts.size @_validate_alpha(empty=np.nan) def strong(counts): r"""Calculate Strong's dominance index. Strong's dominance index (:math:`D_w`) is defined as .. math:: D_w = max_i[(\frac{b_i}{N})-\frac{i}{S}] where :math:`b_i` is the sequential cumulative totaling of the :math:`i^{\text{th}}` taxon abundance values ranked from largest to smallest, :math:`N` is the total number of individuals in the sample, and :math:`S` is the number of taxa in the sample. The expression in brackets is computed for all taxa, and :math:`max_i` denotes the maximum value in brackets for any taxa. Parameters ---------- counts : 1-D array_like, int Vector of counts. Returns ------- float Strong's dominance index. Notes ----- Strong's dominance index is defined in [1]_. References ---------- .. [1] Strong, W. L., 2002 Assessing species abundance unevenness within and between plant communities. Community Ecology, 3, 237-246. """ S = counts.size sorted_sum = np.sort(counts)[::-1].cumsum() i = np.arange(1, S + 1) return (sorted_sum / counts.sum() - (i / S)).max() @_validate_alpha() def tsallis(counts, order=2): r"""Calculate Tsallis entropy. Tsallis entropy (:math:`^qH`), a.k.a. HCDT entropy, is a generalization of Boltzmann-Gibbs entropy with an exponent (order) :math:`q`. It is defined as: .. math:: ^qH = \frac{1}{q - 1}(1 - \sum_{i=1}^S p_i^q) where :math:`S` is the number of taxa and :math:`p_i` is the proportion of the sample represented by taxon :math:`i`. Parameters ---------- counts : 1-D array_like, int Vector of counts. order : int or float, optional Order (:math:`q`). Ranges between 0 and infinity. Default is 2. Returns ------- float Tsallis entropy. See Also -------- renyi shannon simpson sobs Notes ----- Tsallis entropy was originally defined in [1]_. Special cases of Tsallis entropy given order :math:`q` include: - :math:`q=0`: Observed species richness (:math:`S_{obs}`) minus 1. - :math:`q \to 1`: Shannon index :math:`H'`. - :math:`q=2`: Simpson diversity index (:math:`1 - D`). - :math:`q \to \infty`: 0. References ---------- .. [1] Tsallis, C. (1988). Possible generalization of Boltzmann-Gibbs statistics. Journal of statistical physics, 52, 479-487. """ if (S := counts.size) == 0: return np.nan elif S == 1: return 0.0 probs = counts / counts.sum() if order == 1: return _entropy(probs) elif np.isposinf(order): return 0.0 else: return (1 - (probs**order).sum()) / (order - 1) scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/_chao1.py000066400000000000000000000143421520735541300243010ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from ._base import osd from skbio.diversity._util import _validate_counts_vector def chao1(counts, bias_corrected=True): r"""Calculate Chao1 richness estimator. Uses the bias-corrected version unless ``bias_corrected`` is ``False`` *and* there are both singletons and doubletons. Parameters ---------- counts : 1-D array_like, int Vector of counts. bias_corrected : bool, optional Indicates whether or not to use the bias-corrected version of the equation. If ``False`` *and* there are both singletons and doubletons, the uncorrected version will be used. The biased-corrected version will be used otherwise. Returns ------- double Computed Chao1 richness estimator. See Also -------- chao1_ci Notes ----- The uncorrected version is based on Equation 6 in [1]_: .. math:: chao1=S_{obs}+\frac{F_1^2}{2F_2} where :math:`F_1` and :math:`F_2` are the count of singletons and doubletons, respectively. The bias-corrected version is defined as: .. math:: chao1=S_{obs}+\frac{F_1(F_1-1)}{2(F_2+1)} References ---------- .. [1] Chao, A. 1984. Non-parametric estimation of the number of classes in a population. Scandinavian Journal of Statistics 11, 265-270. """ counts = _validate_counts_vector(counts) o, s, d = osd(counts) if not bias_corrected and s and d: return o + s**2 / (d * 2) else: return o + s * (s - 1) / (2 * (d + 1)) def chao1_ci(counts, bias_corrected=True, zscore=1.96): """Calculate Chao1 confidence interval. Parameters ---------- counts : 1-D array_like, int Vector of counts. bias_corrected : bool, optional Indicates whether or not to use the bias-corrected version of the equation. If ``False`` *and* there are both singletons and doubletons, the uncorrected version will be used. The biased-corrected version will be used otherwise. zscore : scalar, optional Score to use for confidence. Default of 1.96 is for a 95% confidence interval. Returns ------- tuple Chao1 confidence interval as ``(lower_bound, upper_bound)``. See Also -------- chao1 Notes ----- The implementation here is based on the equations in the EstimateS manual [1]_. Different equations are employed to calculate the Chao1 variance and confidence interval depending on `bias_corrected` and the presence/absence of singletons and/or doubletons. Specifically, the following EstimateS equations are used: 1. No singletons, Equation 14. 2. Singletons but no doubletons, Equations 7, 13. 3. Singletons and doubletons, ``bias_corrected=True``, Equations 6, 13. 4. Singletons and doubletons, ``bias_corrected=False``, Equations 5, 13. References ---------- .. [1] http://viceroy.eeb.uconn.edu/estimates/ """ counts = _validate_counts_vector(counts) o, s, d = osd(counts) if s: chao = chao1(counts, bias_corrected) chaovar = _chao1_var(counts, bias_corrected) return _chao_confidence_with_singletons(chao, o, chaovar, zscore) else: n = counts.sum() return _chao_confidence_no_singletons(n, o, zscore) def _chao1_var(counts, bias_corrected=True): """Calculate Chao1 variance using decision rules in EstimateS.""" o, s, d = osd(counts) if not d: c = chao1(counts, bias_corrected) return _chao1_var_no_doubletons(s, c) if not s: n = counts.sum() return _chao1_var_no_singletons(n, o) if bias_corrected: return _chao1_var_bias_corrected(s, d) else: return _chao1_var_uncorrected(s, d) def _chao1_var_uncorrected(singles, doubles): """Calculate Chao1 variance without correction. From EstimateS manual, equation 5. """ r = singles / doubles return doubles * (0.5 * r**2 + r**3 + 0.24 * r**4) def _chao1_var_bias_corrected(s, d): """Calculate Chao1 variance with bias correction. `s` is the number of singletons and `d` is the number of doubletons. From EstimateS manual, equation 6. """ return ( s * (s - 1) / (2 * (d + 1)) + (s * (2 * s - 1) ** 2) / (4 * (d + 1) ** 2) + (s**2 * d * (s - 1) ** 2) / (4 * (d + 1) ** 4) ) def _chao1_var_no_doubletons(s, chao1): """Calculate Chao1 variance in absence of doubletons. From EstimateS manual, equation 7. `s` is the number of singletons, and `chao1` is the estimate of the mean of Chao1 from the same dataset. """ return s * (s - 1) / 2 + s * (2 * s - 1) ** 2 / 4 - s**4 / (4 * chao1) def _chao1_var_no_singletons(n, o): """Calculate Chao1 variance in absence of singletons. `n` is the number of individuals and `o` is the number of observed species. From EstimateS manual, equation 8. """ return o * np.exp(-n / o) * (1 - np.exp(-n / o)) def _chao_confidence_with_singletons(chao, observed, var_chao, zscore=1.96): """Calculate confidence bounds for Chao1 or Chao2. Uses Eq. 13 of EstimateS manual. `zscore` is the score to use for confidence. The default of 1.96 is for 95% confidence. """ T = chao - observed # if no diff between chao and observed, CI is just point estimate of # observed if T == 0: return observed, observed K = np.exp(abs(zscore) * np.sqrt(np.log(1 + (var_chao / T**2)))) return observed + T / K, observed + T * K def _chao_confidence_no_singletons(n, s, zscore=1.96): """Calculate confidence bounds for Chao1/Chao2 in absence of singletons. Uses Eq. 14 of EstimateS manual. `n` is the number of individuals and `s` is the number of observed taxa. """ P = np.exp(-n / s) return ( max(s, s / (1 - P) - zscore * np.sqrt((s * P / (1 - P)))), s / (1 - P) + zscore * np.sqrt(s * P / (1 - P)), ) scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/_gini.py000066400000000000000000000070361520735541300242360ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from skbio.diversity._util import _validate_counts_vector def gini_index(data, method="rectangles"): r"""Calculate the Gini index. The Gini index is defined as: .. math:: G=\frac{A}{A+B} where :math:`A` is the area between :math:`y=x` and the Lorenz curve and :math:`B` is the area under the Lorenz curve. Simplifies to :math:`1-2B` since :math:`A+B=0.5`. Parameters ---------- data : 1-D array_like Vector of counts, abundances, proportions, etc. All entries must be non-negative. method : {'rectangles', 'trapezoids'} Method for calculating the area under the Lorenz curve. If ``'rectangles'``, connects the Lorenz curve points by lines parallel to the x axis. This is the correct method (in our opinion) though ``'trapezoids'`` might be desirable in some circumstances. If ``'trapezoids'``, connects the Lorenz curve points by linear segments between them. Basically assumes that the given sampling is accurate and that more features of given data would fall on linear gradients between the values of this data. Returns ------- float Gini index. Raises ------ ValueError If ``method`` isn't one of the supported methods for calculating the area under the curve. Notes ----- The Gini index was introduced in [1]_. The formula for ``method='rectangles'`` is: .. math:: dx\sum_{i=1}^n h_i The formula for ``method='trapezoids'`` is: .. math:: dx(\frac{h_0+h_n}{2}+\sum_{i=1}^{n-1} h_i) References ---------- .. [1] Gini, C. (1912). "Variability and Mutability", C. Cuppini, Bologna, 156 pages. Reprinted in Memorie di metodologica statistica (Ed. Pizetti E, Salvemini, T). Rome: Libreria Eredi Virgilio Veschi (1955). """ # Suppress casting to int because this metric supports ints and floats. data = _validate_counts_vector(data, cast_int=False) lorenz_points = _lorenz_curve(data) B = _lorenz_curve_integrator(lorenz_points, method) return max(0.0, 1 - 2 * B) def _lorenz_curve(data): """Calculate the Lorenz curve for input data. Notes ----- Formula available on wikipedia. """ sorted_data = np.sort(data) Sn = sorted_data.sum() n = sorted_data.shape[0] return np.arange(1, n + 1) / n, sorted_data.cumsum() / Sn def _lorenz_curve_integrator(lc_pts, method): """Calculate the area under a Lorenz curve. Notes ----- Could be utilized for integrating other simple, non-pathological "functions" where width of the trapezoids is constant. """ x, y = lc_pts # each point differs by 1/n dx = 1 / x.shape[0] if method == "trapezoids": # 0 percent of the population has zero percent of the goods h_0 = 0.0 h_n = y[-1] # the 0th entry is at x=1/n sum_hs = y[:-1].sum() return dx * ((h_0 + h_n) / 2 + sum_hs) elif method == "rectangles": return dx * y.sum() else: raise ValueError( "Method '%s' not implemented. Available methods: " "'rectangles', 'trapezoids'." % method ) scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/_lladser.py000066400000000000000000000435651520735541300247450ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from skbio.util import get_rng from skbio.diversity._util import _validate_counts_vector def lladser_pe(counts, r=10, seed=None): """Calculate single point estimate of conditional uncovered probability. Parameters ---------- counts : 1-D array_like, int Vector of counts. r : int, optional Number of new colors that are required for the next prediction. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- double Single point estimate of the conditional uncovered probability. May be ``np.nan`` if a point estimate could not be computed. See Also -------- lladser_ci Notes ----- This function is just a wrapper around the full point estimator described in Theorem 2 (i) in [1]_, intended to be called for a single best estimate on a complete sample. This function is not guaranteed to return estimated uncovered probabilities less than 1 if the coverage is too low. References ---------- .. [1] Lladser, Gouet, and Reeder, "Extrapolation of Urn Models via Poissonization: Accurate Measurements of the Microbial Unknown" PLoS 2011. """ counts = _validate_counts_vector(counts) sample = _expand_counts(counts) rng = get_rng(seed) rng.shuffle(sample) try: pe = list(_lladser_point_estimates(sample, r))[-1][0] except IndexError: pe = np.nan return pe def lladser_ci(counts, r, alpha=0.95, f=10, ci_type="ULCL", seed=None): """Calculate single CI of the conditional uncovered probability. Parameters ---------- counts : 1-D array_like, int Vector of counts. r : int Number of new colors that are required for the next prediction. alpha : float, optional Desired confidence level. f : float, optional Ratio between upper and lower bound. ci_type : {'ULCL', 'ULCU', 'U', 'L'} Type of confidence interval. If ``'ULCL'``, upper and lower bounds with conservative lower bound. If ``'ULCU'``, upper and lower bounds with conservative upper bound. If ``'U'``, upper bound only, lower bound fixed to 0.0. If ``'L'``, lower bound only, upper bound fixed to 1.0. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- tuple Confidence interval as ``(lower_bound, upper_bound)``. See Also -------- lladser_pe Notes ----- This function is just a wrapper around the full CI estimator described in Theorem 2 (iii) in [1]_, intended to be called for a single best CI estimate on a complete sample. References ---------- .. [1] Lladser, Gouet, and Reeder, "Extrapolation of Urn Models via Poissonization: Accurate Measurements of the Microbial Unknown" PLoS 2011. """ counts = _validate_counts_vector(counts) sample = _expand_counts(counts) rng = get_rng(seed) rng.shuffle(sample) try: ci = list(_lladser_ci_series(sample, r, alpha, f, ci_type, rng))[-1] except IndexError: ci = (np.nan, np.nan) return ci def _expand_counts(counts): """Convert vector of counts at each index to vector of indices.""" # From http://stackoverflow.com/a/22671394 return np.repeat(np.arange(counts.size), counts) def _lladser_point_estimates(sample, r=10, seed=None): """Series of point estimates of the conditional uncovered probability. Parameters ---------- sample : 1-D array_like, int Series of random observations. r : int, optional Number of new colors that are required for the next prediction. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. Returns ------- generator Each new color yields a tuple of three elements: the point estimate, position in sample of prediction, and random variable from Poisson process (mostly to make testing easier). Raises ------ ValueError If `r` is less than or equal to 2. Notes ----- This is the point estimator described in Theorem 2 (i) in [1]_. References ---------- .. [1] Lladser, Gouet, and Reeder, "Extrapolation of Urn Models via Poissonization: Accurate Measurements of the Microbial Unknown" PLoS 2011. """ if r <= 2: raise ValueError("r must be greater than or equal to 3.") rng = get_rng(seed) for count, seen, cost, i in _get_interval_for_r_new_taxa(sample, r): t = rng.gamma(count, 1) point_est = (r - 1) / t yield point_est, i, t def _get_interval_for_r_new_taxa(seq, r): """Compute interval between r new taxa for seq of samples. Imagine an urn with colored balls. Given a drawing of balls from the urn, compute how many balls need to be looked at to discover r new colors. Colors can be repeated. Parameters ---------- seq : sequence Series of observations (the actual sample, not the frequencies). r : int Number of new colors that need to be observed for a new interval. Returns ------- generator For each new color seen for the first time, yields a tuple of four elements: the length of interval (i.e. number of observations looked at), the set of seen colors, position in seq after seeing last new color (end of interval), and position in seq where interval is started. """ seen = set() seen_add = seen.add seq_len = len(seq) # note: first iteration is after looking at first char for i, curr in enumerate(seq): # bail out if there's nothing new if curr in seen: continue else: seen_add(curr) # otherwise, need to see distance to get k colors unseen = 0 j = i + 1 while unseen < r and j < seq_len: if seq[j] not in seen: unseen += 1 # note: increments after termination condition j += 1 # the interval to see r new colors count = j - i - 1 # the position in seq after seeing r new ones cost = j # bail out if not enough unseen # note: unit test coverage can be increased by not breaking if it is # the last iteration, but code will be awkward if not count or (unseen < r): break # make a copy of seen before yielding, as we'll continue to add to the # set in subsequent iterations yield count, set(seen), cost, i def _lladser_ci_series(seq, r, alpha=0.95, f=10, ci_type="ULCL", seed=None): """Construct r-color confidence intervals for uncovered conditional prob. Parameters ---------- seq : sequence Sequence of colors (the actual sample, not the counts). r : int Number of new colors that are required for the next prediction. alpha : float, optional Desired confidence level. f : float, optional Ratio between upper and lower bound. ci_type : {'ULCL', 'ULCU', 'U', 'L'} Type of confidence interval. If ``'ULCL'``, upper and lower bounds with conservative lower bound. If ``'ULCU'``, upper and lower bounds with conservative upper bound. If ``'U'``, upper bound only, lower bound fixed to 0.0. If ``'L'``, lower bound only, upper bound fixed to 1.0. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. Returns ------- generator Yields one CI prediction for each new color that is detected and where. """ rng = get_rng(seed) for count, seen, cost, i in _get_interval_for_r_new_taxa(seq, r): t = rng.gamma(count, 1) yield _lladser_ci_from_r(r, t, alpha, f, ci_type) def _lladser_ci_from_r(r, t, alpha=0.95, f=10, ci_type="ULCL"): """Construct r-color confidence interval for uncovered conditional prob. Returns ------- tuple Confidence interval that contains the true conditional uncovered probability with a probability of 100% * `alpha`. Raises ------ ValueError For combinations of `r`, `f`, and `alpha` that do not have precomputed results. """ alpha = round(alpha, 2) if ci_type == "U": if alpha != 0.95: raise ValueError("alpha must be 0.95 if ci_type is 'U'.") if r not in _UPPER_CONFIDENCE_BOUND: raise ValueError("r must be between 1-25 or 50 if ci_type is 'U'.") return 0.0, _UPPER_CONFIDENCE_BOUND[r] / t elif ci_type == "L": if alpha != 0.95: raise ValueError("alpha must be 0.95 if ci_type is 'L'.") if r not in _LOWER_CONFIDENCE_BOUND: raise ValueError("r must be between 1-25 if ci_type is 'L'.") return _LOWER_CONFIDENCE_BOUND[r] / t, 1.0 bound_params = _ul_confidence_bounds(f, r, alpha) if ci_type == "ULCL": bound_param = bound_params[0] elif ci_type == "ULCU": bound_param = bound_params[1] else: raise ValueError("Unknown ci_type '%s'." % ci_type) upper_bound = bound_param * f / t lower_bound = bound_param / t # make sure upper bound is at most 1 if upper_bound > 1: upper_bound = 1.0 return lower_bound, upper_bound def _ul_confidence_bounds(f, r, alpha): """Return confidence bounds based on ratio and alpha. This function is just a lookup of some precomputed values. Parameters ---------- f : float Desired ratio of upper to lower bound. r : int Number of new colors. alpha : float Confidence interval (for 95% confidence use 0.95). Returns ------- tuple Constants ``(c_1, c_2)`` such that the confidence interval is ``[c_1/T_r, c_1*f/T_r]`` for conservative lower bound intervals and ``[c_2/T_r, c_2*f/T_r]`` for conservative upper bound intervals. """ a = None b = None if (f, r, alpha) in _PRECOMPUTED_TABLE: return _PRECOMPUTED_TABLE[(f, r, alpha)] # all others combination are only computed for f=10 # and alpha = 0.90, 0.95 and 0.99 if f == 10 and r <= 50: if alpha in _CBS and r < len(_CBS[alpha]): a, b = _CBS[alpha][r] if a is None or b is None: raise ValueError( "No constants are precomputed for the combination of " "f=%f, r=%d, and alpha=%.2f" % (f, r, alpha) ) return a, b # Maps r to a constant c such that the 95% confidence interval with lower bound # fixed at 0 is [0, c/T_r]. This constant is constant b according to # Theorem 2 (iii) in the paper with a=0, aka c_0 from Table 3. _UPPER_CONFIDENCE_BOUND = { 1: 2.995732274, 2: 4.743864518, 3: 6.295793622, 4: 7.753656528, 5: 9.153519027, 6: 10.51303491, 7: 11.84239565, 8: 13.14811380, 9: 14.43464972, 10: 15.70521642, 11: 16.96221924, 12: 18.20751425, 13: 19.44256933, 14: 20.66856908, 15: 21.88648591, 16: 23.09712976, 17: 24.30118368, 18: 25.49923008, 19: 26.69177031, 20: 27.87923964, 21: 29.06201884, 22: 30.24044329, 23: 31.41481021, 24: 32.58538445, 25: 33.75240327, 50: 62.17105670, } # Maps r to a constant c such that the 95% confidence interval with upper bound # fixed at 1 is [c/T_r, 1]. This constant is constant b according to # Theorem 2 (iii) in the paper with b=1, aka c_3 from Table 3. _LOWER_CONFIDENCE_BOUND = { 1: 0.051293294, 2: 0.355361510, 3: 0.817691447, 4: 1.366318397, 5: 1.970149568, 6: 2.613014744, 7: 3.285315692, 8: 3.980822786, 9: 4.695227540, 10: 5.425405697, 11: 6.169007289, 12: 6.924212514, 13: 7.689578292, 14: 8.463937522, 15: 9.246330491, 16: 10.03595673, 17: 10.83214036, 18: 11.63430451, 19: 12.44195219, 20: 13.25465160, 21: 14.07202475, 22: 14.89373854, 23: 15.71949763, 24: 16.54903871, 25: 17.38212584, } # Hack in some special values we used for the paper. # Since Manuel needs to compute those semi-automatically # using Maple, we pre-calculate only a few common ones # precomputed table is {(f, r, alpha):(c_1, c_2)} _PRECOMPUTED_TABLE = { (2, 50, 0.95): (31.13026306, 38.94718565), (2, 33, 0.95): (22.3203508, 23.4487304), (1.5, 100, 0.95): (79.0424349, 83.22790086), (1.5, 94, 0.95): (75.9077267, 76.5492088), (2.5, 19, 0.95): (11.26109001, 11.96814857), # In the next block for each f, we report the smallest possible value # of r from table 4 in the paper (80, 2, 0.95): (0.0598276655, 0.355361510), (48, 2, 0.95): (0.1013728884, 0.355358676), (40, 2, 0.95): (0.1231379857, 0.355320458), (24, 2, 0.95): (0.226833483, 0.346045204), (20, 3, 0.95): (0.320984257, 0.817610455), (12, 3, 0.95): (0.590243030, 0.787721610), (10, 4, 0.95): (0.806026244, 1.360288674), (6, 6, 0.95): (1.8207383, 2.58658608), (5, 7, 0.95): (2.48303930, 3.22806682), (3, 14, 0.95): (7.17185045, 8.27008349), (1.25, 309, 0.95): (275.661191, 275.949782), } # Below are the values used for Theorem 3 iii # Values hand computed by Manuel Lladser using Maple. For each alpha (0.90, # 0.95, and 0.99), there is a list mapping r to (c_1, c_2), where r is used as # an index into the list. _CB_90 = [ (None, None), # 0, makes indexing easier (None, None), # no feasible solution (None, None), # no feasible solution (0.5635941995, 1.095834700), (0.6764656264, 1.744588615), (0.8018565594, 2.432587343), (0.9282215025, 3.151897973), (1.053433716, 3.894766804), (1.177158858, 4.656118177), (1.299491033, 5.432468058), (1.420604842, 6.221304605), # 10 (1.540665805, 7.020746595), (1.659812701, 7.829342026), (1.778158703, 8.645942495), (1.895796167, 9.469621185), (2.012801198, 10.29961731), (2.129237257, 11.13529724), (2.245157877, 11.97612664), (2.360608695, 12.82164994), (2.475628991, 13.67147502), (2.590252861, 14.52526147), # 20 (2.704510123, 15.38271151), (2.818427036, 16.24356290), (2.932026869, 17.10758326), (3.045330351, 17.97456551), (3.158356050, 18.84432420), (None, None), # not computed (None, None), (None, None), (None, None), (3.719850286, 23.22944415), # 30 (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (4.828910181, 32.13892224), # 40 (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (5.924900191, 41.17906791), # 50 ] _CB_95 = [ (None, None), # 0 (None, None), (None, None), (None, None), (0.8060262438, 1.360288674), # 4 (0.9240311584, 1.969902537), (1.053998892, 2.613007253), (1.185086998, 3.285315518), (1.315076337, 3.980822783), (4.695227540, 4.695227541), (1.570546801, 5.425405698), # 10 (1.696229569, 6.169007289), (1.820753729, 6.924212513), (1.944257622, 7.689578291), (2.066857113, 8.463937522), (2.188648652, 9.246330491), (2.309712994, 10.03595673), (2.430118373, 10.83214036), (2.549923010, 11.63430451), (2.669177032, 12.44195219), (2.787923964, 13.25465160), # 20 (2.906201884, 14.07202475), (3.024044329, 14.89373854), (3.141481020, 15.71949763), (3.258538445, 16.54903871), (3.375240327, 17.38212584), (None, None), (None, None), (None, None), (None, None), (3.954097220, 21.59397923), # 30 (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (5.093973695, 30.19573919), # 40 (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (6.217105673, 38.96473258), # 50 ] _CB_99 = [ (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (1.360316290, 1.768978323), (1.470856924, 2.329171347), (1.604478487, 2.906049304), (1.741759456, 3.507452949), (1.878809285, 4.130199076), # 10 (2.014632329, 4.771246173), (2.149044735, 5.428180734), (2.282101533, 6.099073460), (2.413917374, 6.782354878), (2.544610844, 7.476728267), (2.674289153, 8.181107778), (2.803045614, 8.894573463), (2.930960779, 9.616337916), (3.058104355, 10.34572103), (3.184536992, 11.08213063), # 20 (3.310311816, 11.82504734), (3.435475649, 12.57401269), (3.560070013, 13.32861956), (3.684131925, 14.08850448), (3.807694563, 14.85334135), (None, None), (None, None), (None, None), (None, None), (4.41897094, 18.7424258), # 30 (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (5.61643962, 26.7700386), # 40 (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (None, None), (6.79033616, 35.0324474), # 50 ] _CBS = {0.90: _CB_90, 0.95: _CB_95, 0.99: _CB_99} scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/_pd.py000066400000000000000000000415131520735541300237110ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from skbio.diversity._util import ( _validate_counts_vector, vectorize_counts_and_tree, ) from skbio.tree._utils import _validate_taxa_and_tree from skbio.util._decorator import params_aliased def _setup_pd(counts, taxa, tree, validate, rooted, single_sample): if validate: # Only validate count if operating in single sample mode, as they will have # already been validated otherwise. if single_sample: counts = _validate_counts_vector(counts) if counts.size != len(taxa): raise ValueError("`taxa` must be the same length as `counts`.") _validate_taxa_and_tree(taxa, tree, rooted=rooted, lengths=True) counts_by_node, _, branch_lengths = vectorize_counts_and_tree(counts, taxa, tree) return counts_by_node, branch_lengths def _faith_pd(counts_by_node, branch_lengths): """Calculate Faith's phylogenetic diversity (Faith's PD) metric. Parameters ---------- counts_by_node : ndarray of shape (n_samples, n_nodes) Total counts/abundances of taxa descending from individual nodes of the tree. branch_lengths : ndarray of shape (n_nodes,) Branch lengths of corresponding nodes of the tree. Returns ------- float Faith's phylogenetic diversity (PD). """ return (branch_lengths * (counts_by_node > 0)).sum() @params_aliased([("taxa", "otu_ids", "0.6.0", True)]) def faith_pd(counts, taxa, tree, validate=True): r"""Calculate Faith's phylogenetic diversity (Faith's PD) metric. The Faith's PD metric is defined as: .. math:: PD = \sum_{b \in T \sqcup R} l(b) where :math:`T` is a minimum set of branches (:math:`b`) in a rooted tree that connect all taxa in a community. :math:`R` is a set of branches from the lowest common ancestor (LCA) of the taxa to the root of the tree. :math:`PD` is the sum of lengths (:math:`l`) of branches in both sets. Parameters ---------- counts : 1-D array_like, int Vectors of counts/abundances of taxa for one sample. taxa : list, np.array Vector of taxon IDs corresponding to tip names in ``tree``. Must be the same length as ``counts``. Required. tree : skbio.TreeNode Tree relating taxa. The set of tip names in the tree can be a superset of ``taxa``, but not a subset. Required. validate : bool, optional Whether validate the input data (default: True). This step can be slow, so if validation is run elsewhere it can be disabled here. However, invalid input data can lead to invalid results or error messages that are hard to interpret, so this step should not be bypassed if you're not certain that your input data are valid. See :mod:`skbio.diversity` for the description of what validation entails so you can determine if you can safely disable validation. Returns ------- float Faith's phylogenetic diversity (PD). Raises ------ ValueError, MissingNodeError, DuplicateNodeError If validation fails. Exact error will depend on what was invalid. See Also -------- phydiv skbio.diversity skbio.diversity.alpha_diversity Notes ----- Faith's phylogenetic diversity, often referred to as PD, was originally described in [1]_. It is the total phylogenetic branch length spanning all taxa of a community. It was clarified that the calculation should extend to the root of the tree [2]_, such that a single-taxon community will not have PD = 0. The root should be ancestral to all taxa being considered in the study, but does not need to be the origin of life. One should choose the root according to the scope of the study. Unrooted and abundance-weighted variants of PD are implemented in :func:`phydiv`. Several other metrics, such as evolutionary history (EH) [3]_ and functional diversity (FD) [4]_, are equivalent to PD in calculation. When computing Faith's PD for multiple samples, using :func:`~skbio.diversity.alpha_diversity` will be much faster than calling this function individually on each sample. This implementation of Faith's PD is based on the array-based implementation of UniFrac described in [5]_. .. note:: This implementation differs from that in PyCogent (and therefore QIIME versions less than 2.0.0) by imposing a few additional restrictions on the inputs. First, the input tree must be rooted. In PyCogent, if an unrooted tree was provided that had a single trifurcating node (a newick convention for unrooted trees) that node was considered the root of the tree. Next, all taxa must be tips in the tree. PyCogent would silently ignore taxa that were not present the tree. To reproduce Faith PD results from PyCogent with scikit-bio, ensure that your PyCogent Faith PD calculations are performed on a rooted tree and that all taxa are present in the tree. References ---------- .. [1] Faith, D. P. Conservation evaluation and phylogenetic diversity. Biol. Conserv. (1992). .. [2] Faith, D. P., & Baker, A. M. (2006). Phylogenetic diversity (PD) and biodiversity conservation: some bioinformatics challenges. Evolutionary bioinformatics, 2, 117693430600200007. .. [3] Nee, S., & May, R. M. (1997). Extinction and the loss of evolutionary history. Science, 278(5338), 692-694. .. [4] Petchey OL, Gaston KJ. Functional diversity (FD), species richness and community composition. Ecology letters. 2002 May;5(3):402-11. .. [5] Hamady M, Lozupone C, Knight R. Fast UniFrac: facilitating high-throughput phylogenetic analyses of microbial communities including analysis of pyrosequencing and PhyloChip data. ISME J. 4(1):17-27 (2010). Examples -------- Assume we have the following abundance data for a sample ``u``, represented as a counts vector. These counts represent the number of times specific taxa were observed in the sample. >>> u_counts = [1, 0, 0, 4, 1, 2, 3, 0] Because Faith PD is a phylogenetic diversity metric, we need to know which taxon each count corresponds to, which we'll provide as ``taxa``. >>> taxa = ['U1', 'U2', 'U3', 'U4', 'U5', 'U6', 'U7', 'U8'] We also need a phylogenetic tree that relates the taxa to one another. >>> from skbio import TreeNode >>> tree = TreeNode.read(['(((((U1:0.5,U2:0.5):0.5,U3:1.0):1.0):0.0,' ... '(U4:0.75,(U5:0.5,((U6:0.33,U7:0.62):0.5' ... ',U8:0.5):0.5):0.5):1.25):0.0)root;']) We can then compute the Faith PD of the sample. >>> from skbio.diversity.alpha import faith_pd >>> pd = faith_pd(u_counts, taxa, tree) >>> print(round(pd, 2)) 6.95 """ counts_by_node, branch_lengths = _setup_pd( counts, taxa, tree, validate, rooted=True, single_sample=True ) return _faith_pd(counts_by_node, branch_lengths) def _phydiv(counts_by_node, branch_lengths, rooted, weight): """Calculate generalized phylogenetic diversity (PD) metrics. Parameters ---------- counts_by_node : ndarray of shape (n_samples, n_nodes) Total counts/abundances of taxa descending from individual nodes of the tree. branch_lengths : ndarray of shape (n_nodes,) Branch lengths of corresponding nodes of the tree. rooted : bool Whether the metric is calculated considering the root of the tree. weight : bool or float Whether and to what degree branch lengths should be weighted by the relative abundance of taxa descending from the branch. Returns ------- float Phylogenetic diversity (PD). """ # select branches connecting taxa included = counts_by_node > 0 # get total counts counts_sum = counts_by_node.max() if counts_sum == 0.0: return 0.0 # in unrooted mode, remove branches to root if rooted is False: included &= counts_by_node < counts_sum # in unweighted mode, simply sum branch lengths if not weight: return (branch_lengths * included).sum() # get relative abundances fracs_by_node = counts_by_node / counts_sum # calculate balances in unrooted mode if rooted is False: fracs_by_node = 2 * np.minimum(fracs_by_node, 1 - fracs_by_node) # raise relative abundances to the power of theta if isinstance(weight, float) and weight < 1.0: fracs_by_node **= weight return (branch_lengths * fracs_by_node).sum() @params_aliased([("taxa", "otu_ids", "0.6.0", True)]) def phydiv(counts, taxa, tree, rooted=None, weight=False, validate=True): r"""Calculate generalized phylogenetic diversity (PD) metrics. Parameters ---------- counts : 1-D array_like, int Vectors of counts/abundances of taxa for one sample. taxa : list, np.array Vector of taxon IDs corresponding to tip names in ``tree``. Must be the same length as ``counts``. Required. tree : skbio.TreeNode Tree relating taxa. The set of tip names in the tree can be a superset of ``taxa``, but not a subset. Required. rooted : bool, optional Whether the metric is calculated considering the root of the tree. By default, this will be determined based on whether the input tree is rooted. However, one can override it by explicitly specifying True (rooted) or False (unrooted). weight : bool or float, optional Whether branch lengths should be weighted by the relative abundance of taxa descending from the branch (default: False). A float within [0, 1] indicates the degree of partial-weighting (0: unweighted, 1: fully-weighted). validate : bool, optional Whether validate the input data. See :func:`faith_pd` for details. Returns ------- float Phylogenetic diversity (PD). Raises ------ ValueError, MissingNodeError, DuplicateNodeError If validation fails. Exact error will depend on what was invalid. See Also -------- faith_pd skbio.diversity skbio.diversity.alpha_diversity Notes ----- Phylogenetic diversity (PD) metrics measure the diversity of a community with consideration of the phylogenetic relationships among taxa. In general, PD is the sum of branch lengths spanning across taxa, optionally weighted by their relative abundances in the community. The most widely-adopted PD metric, Faith's PD [1]_, is defined as: .. math:: PD = \sum_{b \in T \sqcup R} l(b) where :math:`T` is a minimum set of branches (:math:`b`) in a rooted tree that connect all taxa in a community. :math:`R` is a set of branches from the lowest common ancestor (LCA) of the taxa to the root of the tree. :math:`PD` is the sum of lengths (:math:`l`) of branches in both sets. It is equivalent to ``phydiv(..., rooted=True, weight=False)``. --- A variant of PD, which does not include the root in the calculation, was referred to by some authors as unrooted phylogenetic diversity (uPD) [2]_, as in contrast to rooted phylogenetic diversity (rPD, i.e., Faith's PD). uPD is defined as: .. math:: PD = \sum_{b \in T} l(b) It is equivalent to ``phydiv(..., rooted=False, weight=False)``. See :func:`faith_pd` for a discussion of the root. --- PD (rooted or unrooted) considers only the presence of taxa. Therefore, it can be considered as the phylogenetic generalization of species richness. However, there are advantages of incorporating abundance information in the measurement [3]_. A generalized framework of abundance-weighted PD is provided in [4]_. Abundance-weighted rooted PD (equivalent to :math:`RBWPD_{1}` described in [4]_) is analogous to the :math:`PD_{aw}` metric originally described in [5]_ with a multiplier. It is defined as: .. math:: PD = \sum_{b \in T \sqcup R} l(b) p(b) where :math:`p` is the sum of relative (proportional) abundances of taxa descending from branch (:math:`b`). It is equivalent to ``phydiv(..., rooted=True, weight=True)``. --- Abundance-weighted unrooted PD (equivalent to :math:`BWPD_{1}` described in [4]_) is analogous to the :math:`\delta nPD` metric originally described in [6]_ with a multiplier. It is defined as: .. math:: PD = 2 \sum_{b \in T} l(b) \min(p(b),1-p(b)) In which the term :math:`2\min(p(b),1-p(b))` is the lesser of the relative abundance of descending taxa on either side of a branch, multiplied by two. It is referred to as the "balance" of taxon abundance in [4]_. It is equivalent to ``phydiv(..., rooted=False, weight=True)``. --- The contribution of taxon abundance to the metric can be adjusted using the ``weight`` parameter when it is a float within [0, 1]. This factor was referred to as :math:`\theta` in [4]_. The metric, :math:`BWPD_{\theta}`, referred to as the balance-weighted phylogenetic diversity in [4]_, is defined as: .. math:: PD = \sum_{b \in T} l(b) (2\min(p(b),1-p(b)))^\theta It is equivalent to ``phydiv(..., rooted=False, weight=theta)``. This metric falls back to unweighted PD when :math:`\theta=0` or fully-weighted PD when :math:`\theta=1`. The original publication tested :math:`\theta=0.25` or :math:`0.5` [4]_. The parameter :math:`\theta` is analogous to the parameter :math:`\alpha` in the generalized UniFrac metric [7]_. --- Likewise, the rooted version of balance-weighted phylogenetic diversity, :math:`RBWPD_{\theta}` [4]_ (although "balance" is not involved), is defined as: .. math:: PD = \sum_{b \in T \sqcup R} l(b) p(b)^\theta It is equivalent to ``phydiv(..., rooted=True, weight=theta)``. --- It is important to report which metric is used. For practical perspective, we recommend the following denotions: - :math:`rPD`: rooted, unweighted PD (Faith's PD [1]_). - :math:`uPD`: unrooted, unweighted PD (uPD [2]_). - :math:`rPD_{w}`: rooted, weighted PD (analogous to :math:`PD_{aw}` [3]_). - :math:`uPD_{w}`: unrooted, weighted PD (analogous to :math:`\delta nPD` [4]_). - :math:`rPD_{w\theta}`: rooted, weighted PD with parameter :math:`\theta` (:math:`RBWPD_{\theta}` [5]_). - :math:`uPD_{w\theta}`: unrooted, weighted PD with parameter :math:`\theta` (:math:`BWPD_{\theta}` [5]_). References ---------- .. [1] Faith, D. P. Conservation evaluation and phylogenetic diversity. Biol. Conserv. (1992). .. [2] Pardi, F., & Goldman, N. (2007). Resource-aware taxon selection for maximizing phylogenetic diversity. Systematic biology, 56(3), 431-444. .. [3] Chao, A., Chiu, C. H., & Jost, L. (2016). Phylogenetic diversity measures and their decomposition: a framework based on Hill numbers. Biodiversity Conservation and Phylogenetic Systematics, 14, 141-72. .. [4] McCoy, C. O., & Matsen IV, F. A. (2013). Abundance-weighted phylogenetic diversity measures distinguish microbial community states and are robust to sampling depth. PeerJ, 1, e157. .. [5] Vellend, M., Cornwell, W. K., Magnuson-Ford, K., & Mooers, A. Ø. (2011). Measuring phylogenetic biodiversity. Biological diversity: frontiers in measurement and assessment, 194-207. .. [6] Barker, G. M. (2002). Phylogenetic diversity: a quantitative framework for measurement of priority and achievement in biodiversity conservation. Biological Journal of the Linnean Society, 76(2), 165-194. .. [7] Chen, J., Bittinger, K., Charlson, E. S., Hoffmann, C., Lewis, J., Wu, G. D., ... & Li, H. (2012). Associating microbiome composition with environmental covariates using generalized UniFrac distances. Bioinformatics, 28(16), 2106-2113. """ # whether tree is rooted should not affect whether metric can be calculated # ; it is common unrooted PD is calculated on a rooted tree counts_by_node, branch_lengths = _setup_pd( counts, taxa, tree, validate, rooted=False, single_sample=True ) # if not specified, determine whether metric should be calculated in rooted # mode according to the tree if rooted is None: rooted = len(tree.root().children) == 2 # validate weight parameter if ( not isinstance(weight, (bool, int, float)) or (w_ := float(weight)) < 0.0 or w_ > 1.0 ): raise ValueError("Weight parameter must be Boolean or within [0, 1].") return _phydiv(counts_by_node, branch_lengths, rooted, weight) scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/000077500000000000000000000000001520735541300237335ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/__init__.py000066400000000000000000000005411520735541300260440ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/data/000077500000000000000000000000001520735541300246445ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/data/qiime-191-tt/000077500000000000000000000000001520735541300267055ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/data/qiime-191-tt/README.md000066400000000000000000000002411520735541300301610ustar00rootroot00000000000000Files in this directory are the QIIME 1.9.1 "tiny test" files. For detail on how these were created, see skbio/diversity/beta/tests/data/qiime-191-tt/README.md. scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/data/qiime-191-tt/faith-pd.txt000066400000000000000000000001461520735541300311430ustar00rootroot00000000000000 PD_whole_tree f2 0.64607 f1 0.47803 f3 0.47803 f4 0.306525 p2 1.4239 p1 0.604145 t1 0.6574 t2 0.6574 scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/data/qiime-191-tt/otu-table.tsv000066400000000000000000000004431520735541300313400ustar00rootroot00000000000000# Constructed from biom file #OTU ID f2 f1 f3 f4 p2 p1 t1 t2 295053 20 18 18 22 4 0 0 0 42684 0 0 0 0 1 0 0 0 None11 1 0 0 0 1 1 0 0 None7 0 0 0 0 1 0 0 0 None5 0 0 0 0 1 0 0 0 None4 0 0 0 0 1 1 0 0 None3 0 0 0 0 1 0 2 3 879972 0 0 0 0 9 20 1 4 None9 0 0 0 0 3 0 19 15 None8 1 4 4 0 0 0 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/data/qiime-191-tt/tree.nwk000066400000000000000000000004121520735541300303620ustar00rootroot00000000000000(((879972:0.05039,None3:0.00778)0.980:0.15948,((None11:0.07161,None4:0.06965)0.917:0.09643,(295053:0.06096,42684:0.15599)0.910:0.08898)0.899:0.09227)0.958:0.064315,(None8:0.09606,(None7:0.10435,(None5:0.02626,None9:0.00014)1.000:0.25335)0.753:0.0465):0.075445)root; scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/test_ace.py000066400000000000000000000027301520735541300260760ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy as np import numpy.testing as npt from skbio.diversity.alpha import ace class AceTests(unittest.TestCase): def test_ace(self): npt.assert_almost_equal(ace(np.array([2, 0])), 1.0) npt.assert_almost_equal(ace(np.array([12, 0, 9])), 2.0) npt.assert_almost_equal(ace(np.array([12, 2, 8])), 3.0) npt.assert_almost_equal(ace(np.array([12, 2, 1])), 4.0) npt.assert_almost_equal(ace(np.array([12, 1, 2, 1])), 7.0) npt.assert_almost_equal(ace(np.array([12, 3, 2, 1])), 4.6) npt.assert_almost_equal(ace(np.array([12, 3, 6, 1, 10])), 5.62749672) # Just return the number of taxa when all are abundant. npt.assert_almost_equal(ace(np.array([12, 12, 13, 14])), 4.0) # Border case: only singletons and 10-tons, no abundant taxa. npt.assert_almost_equal(ace([0, 1, 1, 0, 0, 10, 10, 1, 0, 0]), 9.35681818182) def test_ace_only_rare_singletons(self): with self.assertRaises(ValueError): ace([0, 0, 43, 0, 1, 0, 1, 42, 1, 43]) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/test_base.py000066400000000000000000000422341520735541300262630ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main from io import StringIO import warnings import numpy as np import numpy.testing as npt from skbio import TreeNode from skbio.diversity.alpha import ( berger_parker_d, brillouin_d, dominance, doubles, enspie, esty_ci, fisher_alpha, goods_coverage, heip_e, hill, inv_simpson, kempton_taylor_q, margalef, mcintosh_d, mcintosh_e, menhinick, michaelis_menten_fit, observed_features, osd, pielou_e, renyi, robbins, shannon, simpson, simpson_d, simpson_e, singles, sobs, strong, tsallis) class BaseTests(TestCase): def setUp(self): self.counts = np.array([0, 1, 1, 4, 2, 5, 2, 4, 1, 2]) self.sids1 = list('ABCD') self.oids1 = ['OTU%d' % i for i in range(1, 6)] self.t1 = TreeNode.read(StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):' '0.0,(OTU4:0.75,OTU5:0.75):1.25):0.0)root;')) self.t1_w_extra_tips = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,(OTU5:0.25,(OTU6:0.5,OTU7:0.5):0.5):0.5):1.25):0.0' ')root;')) def test_berger_parker_d(self): self.assertEqual(berger_parker_d(np.array([5, 5])), 0.5) self.assertEqual(berger_parker_d(np.array([1, 1, 1, 1, 0])), 0.25) self.assertEqual(berger_parker_d(self.counts), 5 / 22) self.assertEqual(berger_parker_d(np.array([5])), 1) self.assertTrue(np.isnan(berger_parker_d([0, 0]))) def test_brillouin_d(self): self.assertAlmostEqual(brillouin_d(np.array([1, 2, 0, 0, 3, 1])), 0.86289353018248782) self.assertTrue(np.isnan(brillouin_d([0, 0]))) def test_dominance(self): self.assertEqual(dominance(np.array([5])), 1) self.assertAlmostEqual(dominance(np.array([1, 0, 2, 5, 2])), 0.34) self.assertTrue(np.isnan(dominance([0, 0]))) # finite sample correction self.assertEqual(dominance(np.array([5]), finite=True), 1) self.assertAlmostEqual(dominance( np.array([1, 0, 2, 5, 2]), finite=True), 0.8 / 3) self.assertTrue(np.isnan(dominance([0, 0], finite=True))) def test_doubles(self): self.assertEqual(doubles(self.counts), 3) self.assertEqual(doubles(np.array([0, 3, 4])), 0) self.assertEqual(doubles(np.array([2])), 1) self.assertEqual(doubles([0, 0]), 0) def test_enspie(self): for vec in ( np.array([1, 1, 1, 1, 1, 1]), np.array([1, 41, 0, 0, 12, 13]), np.array([1, 0, 2, 5, 2]) ): self.assertEqual(enspie(vec), inv_simpson(vec)) vec = np.array([1, 2, 3, 4]) self.assertEqual(enspie(vec, finite=True), inv_simpson(vec, finite=True)) def test_esty_ci(self): def _diversity(indices, f): """Calculate diversity index for each window of size 1. indices: vector of indices of taxa f: f(counts) -> diversity measure """ result = [] max_size = max(indices) + 1 freqs = np.zeros(max_size, dtype=int) for i in range(len(indices)): freqs += np.bincount(indices[i:i + 1], minlength=max_size) try: curr = f(freqs) except (ZeroDivisionError, FloatingPointError): curr = 0 result.append(curr) return np.array(result) data = [1, 1, 2, 1, 1, 3, 2, 1, 3, 4] observed_lower, observed_upper = zip(*_diversity(data, esty_ci)) expected_lower = np.array([1, -1.38590382, -0.73353593, -0.17434465, -0.15060902, -0.04386191, -0.33042054, -0.29041008, -0.43554755, -0.33385652]) expected_upper = np.array([1, 1.38590382, 1.40020259, 0.67434465, 0.55060902, 0.71052858, 0.61613483, 0.54041008, 0.43554755, 0.53385652]) npt.assert_allclose(observed_lower, expected_lower) npt.assert_allclose(observed_upper, expected_upper) self.assertTrue(np.isnan(esty_ci([0, 0]))) def test_fisher_alpha(self): exp = 2.7823796 arr = np.array([4, 3, 4, 0, 1, 0, 2]) obs = fisher_alpha(arr) self.assertAlmostEqual(obs, exp, places=6) # Should depend only on S and N (number of taxa, number of # individuals / seqs), so we should obtain the same output as above. obs = fisher_alpha([1, 6, 1, 0, 1, 0, 5]) self.assertAlmostEqual(obs, exp, places=6) # Should match another by hand: # 2 taxa, 62 seqs, alpha is 0.39509 obs = fisher_alpha([61, 0, 0, 1]) self.assertAlmostEqual(obs, 0.3950909, places=6) # Test case where we have >1000 individuals (SDR-IV makes note of this # case). Verified against R's vegan::fisher.alpha. obs = fisher_alpha([999, 0, 10]) self.assertAlmostEqual(obs, 0.2396492, places=6) # Should be infinite when all species are singletons obs = fisher_alpha([1, 1, 1, 1, 1]) self.assertEqual(obs, np.inf) # Should be large when most species are singletons obs = fisher_alpha([1] * 99 + [2]) self.assertAlmostEqual(obs, 5033.278, places=3) # Similar but even larger obs = fisher_alpha([1] * 999 + [2]) TestCase().assertAlmostEqual(obs, 500333.3, places=1) self.assertTrue(np.isnan(fisher_alpha([0, 0]))) def test_goods_coverage(self): counts = [1] * 75 + [2, 2, 2, 2, 2, 2, 3, 4, 4] obs = goods_coverage(counts) self.assertAlmostEqual(obs, 0.23469387755) self.assertTrue(np.isnan(goods_coverage([0, 0]))) def test_heip_e(self): # Calculate "by hand". arr = np.array([1, 2, 3, 1]) H = shannon(arr) expected = (np.exp(H) - 1) / (arr.size - 1) self.assertEqual(heip_e(arr), expected) # From Statistical Ecology: A Primer in Methods and Computing, page 94, # table 8.1. self.assertAlmostEqual(heip_e([500, 300, 200]), 0.90, places=2) self.assertAlmostEqual(heip_e([500, 299, 200, 1]), 0.61, places=2) # Edge cases self.assertEqual(heip_e([5]), 1) self.assertTrue(np.isnan(heip_e([0, 0]))) def test_hill(self): orders = [0, 0.5, 1, 2, 10, np.inf] # a regular case arr = np.array([1, 2, 3, 4, 5]) obs = [hill(arr, order=x) for x in orders] exp = [5, 4.68423304, 4.43598780, 4.09090909, 3.34923645, 3] npt.assert_almost_equal(obs, exp) # equivalent to observed species richness when q = 0 self.assertAlmostEqual(hill(arr, order=0), sobs(arr)) # equivalent to the exponential of Shannon index when q = 1 self.assertAlmostEqual(hill(arr, order=1), shannon(arr, exp=True)) # equivalent to inverse Simpson index when q = 2 (default) self.assertAlmostEqual(hill(arr), inv_simpson(arr)) # equivalent to the inverse of Berger-Parker dominance index when q = inf self.assertAlmostEqual(hill(arr, order=np.inf), 1 / berger_parker_d(arr)) # equally abundant taxa: qD = S arr = np.array([5, 5, 5]) obs = [hill(arr, order=x) for x in orders] exp = [arr.size] * 6 npt.assert_almost_equal(obs, exp) # single taxon: qD = 1 self.assertEqual(hill([1]), 1) # empty community self.assertTrue(np.isnan(hill([0, 0]))) def test_inv_simpson(self): # Totally even community should have 1 / D = number of taxa. self.assertAlmostEqual(inv_simpson(np.array([1, 1, 1, 1, 1, 1])), 6) self.assertAlmostEqual(inv_simpson(np.array([13, 13, 13, 13])), 4) # Hand calculated. arr = np.array([1, 41, 0, 0, 12, 13]) exp = 1 / ((arr / arr.sum()) ** 2).sum() self.assertAlmostEqual(inv_simpson(arr), exp) # Using dominance. exp = 1 / dominance(arr) self.assertAlmostEqual(inv_simpson(arr), exp) arr = np.array([1, 0, 2, 5, 2]) exp = 1 / dominance(arr) self.assertAlmostEqual(inv_simpson(arr), exp) # Finite sample correction. self.assertEqual(inv_simpson( np.array([1, 0, 2, 5, 2]), finite=True), 3.75) self.assertEqual(inv_simpson(np.array([3, 3, 3]), finite=True), 4) self.assertTrue(np.isnan(inv_simpson([0, 0]))) def test_kempton_taylor_q(self): # Approximate Magurran 1998 calculation p143. arr = np.array([2, 3, 3, 3, 3, 3, 4, 4, 4, 6, 6, 7, 7, 9, 9, 11, 14, 15, 15, 20, 29, 33, 34, 36, 37, 53, 57, 138, 146, 170]) exp = 14 / np.log(34 / 4) self.assertAlmostEqual(kempton_taylor_q(arr), exp) # Should get same answer regardless of input order. np.random.shuffle(arr) self.assertAlmostEqual(kempton_taylor_q(arr), exp) self.assertTrue(np.isnan(kempton_taylor_q([0, 0]))) def test_margalef(self): self.assertEqual(margalef(self.counts), 8 / np.log(22)) self.assertTrue(np.isnan(margalef([1]))) self.assertTrue(np.isnan(margalef([0, 0]))) def test_mcintosh_d(self): self.assertAlmostEqual(mcintosh_d(np.array([1, 2, 3])), 0.636061424871458) self.assertTrue(np.isnan(mcintosh_d([1]))) self.assertTrue(np.isnan(mcintosh_d([0, 0]))) def test_mcintosh_e(self): num = np.sqrt(15) den = np.sqrt(19) exp = num / den self.assertEqual(mcintosh_e(np.array([1, 2, 3, 1])), exp) self.assertTrue(np.isnan(mcintosh_e([0, 0]))) def test_menhinick(self): # observed species richness = 9, total # of individuals = 22 self.assertEqual(menhinick(self.counts), 9 / np.sqrt(22)) self.assertTrue(np.isnan(menhinick([0, 0]))) def test_michaelis_menten_fit(self): obs = michaelis_menten_fit([22]) self.assertAlmostEqual(obs, 1.0) obs = michaelis_menten_fit([42]) self.assertAlmostEqual(obs, 1.0) obs = michaelis_menten_fit([34], num_repeats=3, params_guess=(13, 13)) self.assertAlmostEqual(obs, 1.0) obs = michaelis_menten_fit([70, 70], num_repeats=5) self.assertAlmostEqual(obs, 2.0, places=1) obs_few = michaelis_menten_fit(np.arange(4) * 2, num_repeats=10) obs_many = michaelis_menten_fit(np.arange(4) * 100, num_repeats=10) # [0,100,200,300] looks like only 3 taxa. self.assertAlmostEqual(obs_many, 3.0, places=1) # [0,2,4,6] looks like 3 taxa with maybe more to be found. self.assertTrue(obs_few > obs_many) self.assertTrue(np.isnan(michaelis_menten_fit([0, 0]))) def test_observed_features(self): for vec in (np.array([4, 3, 4, 0, 1, 0, 2]), self.counts): self.assertEqual(observed_features(vec), sobs(vec)) def test_osd(self): self.assertEqual(osd(self.counts), (9, 3, 3)) def test_pielou_e(self): # Calculate "by hand". arr = np.array([1, 2, 3, 1]) H = shannon(arr) S = arr.size expected = H / np.log(S) self.assertAlmostEqual(pielou_e(arr), expected) # alternative logarithm base expected = shannon(arr, base=2) / np.log2(S) self.assertAlmostEqual(pielou_e(arr, base=2), expected) self.assertAlmostEqual(pielou_e(self.counts), 0.92485490560) self.assertAlmostEqual(pielou_e([1, 1]), 1.0) self.assertAlmostEqual(pielou_e([1, 1, 1, 1]), 1.0) self.assertAlmostEqual(pielou_e([1, 1, 1, 1, 0, 0]), 1.0) # Examples from # http://ww2.mdsg.umd.edu/interactive_lessons/biofilm/diverse.htm#3 self.assertAlmostEqual(pielou_e([1, 1, 196, 1, 1]), 0.078, 3) # Edge cases self.assertEqual(pielou_e([5]), 1) self.assertTrue(np.isnan(pielou_e([0, 0]))) def test_renyi(self): orders = [0, 0.5, 1, 2, 10, np.inf] # a regular case arr = np.array([1, 2, 3, 4, 5]) obs = [renyi(arr, order=x) for x in orders] exp = [1.60943791, 1.54420220, 1.48975032, 1.40876722, 1.20873239, 1.09861229] npt.assert_almost_equal(obs, exp) # equivalent to Shannon index when q = 1 self.assertAlmostEqual(renyi(arr, order=1), shannon(arr)) # equivalent to log(inverse Simpson index) when q = 2 (default) self.assertAlmostEqual(renyi(arr), np.log(inv_simpson(arr))) # default q, custom logarithm base self.assertAlmostEqual(renyi(arr, base=2), 2.03242148) # equally abundant taxa: qH = log(S) arr = np.array([5, 5, 5]) obs = [renyi(arr, order=x) for x in orders] exp = [np.log(arr.size)] * 6 npt.assert_almost_equal(obs, exp) # single taxon: qH = 0 self.assertEqual(renyi([1]), 0) # empty community self.assertTrue(np.isnan(renyi([0, 0]))) def test_robbins(self): self.assertEqual(robbins(np.array([1, 2, 3, 0, 1])), 2 / 7) self.assertTrue(np.isnan(robbins([0, 0]))) def test_shannon(self): self.assertAlmostEqual(shannon([5, 5]), 0.693147181) self.assertEqual(shannon([5, 5], base=2), 1) self.assertAlmostEqual(shannon([5, 5], base=10), 0.301029996) # taxa with 0 counts are excluded from calculation self.assertAlmostEqual(shannon([1, 2, 3, 4]), 1.279854226) self.assertAlmostEqual(shannon([0, 1, 2, 3, 4]), 1.279854226) # Shannon index of a single-taxon community is always 0 self.assertEqual(shannon(np.array([5])), 0) # Shannon index cannot be calculated for an empty community self.assertTrue(np.isnan(shannon([0, 0]))) # NaN still holds if input is empty (instead of 0's), this behavior is # different from scipy.stats.entropy, which would return 0.0. self.assertTrue(np.isnan(shannon([]))) # Exponential of Shannon index self.assertAlmostEqual(shannon([1, 2, 3, 4], exp=True), 3.596115467) # Equally abundant taxa, exp(H) = # taxa self.assertAlmostEqual(shannon([5, 5, 5], exp=True), 3.0) def test_simpson(self): self.assertAlmostEqual(simpson(np.array([1, 0, 2, 5, 2])), 0.66) self.assertEqual(simpson(np.array([5])), 0) self.assertEqual(simpson(np.array([5]), finite=True), 0) self.assertTrue(np.isnan(simpson([0, 0]))) def test_simpson_d(self): for vec in (np.array([5]), np.array([1, 0, 2, 5, 2])): self.assertEqual(dominance(vec), simpson_d(vec)) self.assertEqual(dominance(vec, finite=True), simpson_d(vec, finite=True)) def test_simpson_e(self): # A totally even community should have simpson_e = 1. self.assertEqual(simpson_e(np.array([1, 1, 1, 1, 1, 1, 1])), 1) arr = np.array([0, 30, 25, 40, 0, 0, 5]) freq_arr = arr / arr.sum() D = (freq_arr ** 2).sum() exp = 1 / (D * 4) obs = simpson_e(arr) self.assertEqual(obs, exp) # From: # https://groups.nceas.ucsb.edu/sun/meetings/calculating-evenness- # of-habitat-distributions arr = np.array([500, 400, 600, 500]) D = 0.0625 + 0.04 + 0.09 + 0.0625 exp = 1 / (D * 4) self.assertEqual(simpson_e(arr), exp) self.assertTrue(np.isnan(simpson_e([0, 0]))) def test_singles(self): self.assertEqual(singles(self.counts), 3) self.assertEqual(singles(np.array([0, 3, 4])), 0) self.assertEqual(singles(np.array([1])), 1) self.assertEqual(singles([0, 0]), 0) def test_sobs(self): obs = sobs(np.array([4, 3, 4, 0, 1, 0, 2])) self.assertEqual(obs, 5) obs = sobs(np.array([0, 0, 0])) self.assertEqual(obs, 0) obs = sobs(self.counts) self.assertEqual(obs, 9) def test_strong(self): self.assertAlmostEqual(strong(np.array([1, 2, 3, 1])), 0.214285714) self.assertTrue(np.isnan(strong([0, 0]))) def test_tsallis(self): orders = [0, 0.5, 1, 2, 10, np.inf] # a regular case arr = np.array([1, 2, 3, 4, 5]) obs = [tsallis(arr, order=x) for x in orders] exp = [4, 2.32861781, 1.48975032, 0.75555556, 0.11110902, 0] npt.assert_almost_equal(obs, exp) # equivalent to richess - 1 when q = 0 self.assertAlmostEqual(tsallis(arr, order=0), sobs(arr) - 1) # equivalent to Shannon index when q = 1 self.assertAlmostEqual(tsallis(arr, order=1), shannon(arr)) # equivalent to Simpson's diversity index) when q = 2 (default) self.assertAlmostEqual(tsallis(arr), simpson(arr)) # 0 when order is infinity self.assertAlmostEqual(tsallis(arr, order=np.inf), 0) # 0 when there is a single taxon self.assertEqual(tsallis([1]), 0) # empty community self.assertTrue(np.isnan(tsallis([0, 0]))) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/test_chao1.py000066400000000000000000000055711520735541300263470ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt from skbio.diversity.alpha import chao1, chao1_ci from skbio.diversity.alpha._chao1 import _chao1_var class Chao1Tests(TestCase): def setUp(self): self.counts = np.array([0, 1, 1, 4, 2, 5, 2, 4, 1, 2]) self.no_singles = np.array([0, 2, 2, 4, 5, 0, 0, 0, 0, 0]) self.no_doubles = np.array([0, 1, 1, 4, 5, 0, 0, 0, 0, 0]) def test_chao1(self): self.assertEqual(chao1(self.counts), 9.75) self.assertEqual(chao1(self.counts, bias_corrected=False), 10.5) self.assertEqual(chao1(self.no_singles), 4) self.assertEqual(chao1(self.no_singles, bias_corrected=False), 4) self.assertEqual(chao1(self.no_doubles), 5) self.assertEqual(chao1(self.no_doubles, bias_corrected=False), 5) def test_chao1_ci(self): # Should match observed results from EstimateS. NOTE: EstimateS rounds # to 2 dp. obs = chao1_ci(self.counts) npt.assert_allclose(obs, (9.07, 17.45), rtol=0.01) obs = chao1_ci(self.counts, bias_corrected=False) npt.assert_allclose(obs, (9.17, 21.89), rtol=0.01) obs = chao1_ci(self.no_singles) npt.assert_allclose(obs, (4, 4.95), rtol=0.01) obs = chao1_ci(self.no_singles, bias_corrected=False) npt.assert_allclose(obs, (4, 4.95), rtol=0.01) obs = chao1_ci(self.no_doubles) npt.assert_allclose(obs, (4.08, 17.27), rtol=0.01) obs = chao1_ci(self.no_doubles, bias_corrected=False) npt.assert_allclose(obs, (4.08, 17.27), rtol=0.01) # edge case (sobs == chao1) obs = chao1_ci([1, 2, 3]) npt.assert_allclose(obs, (3, 3)) def test_chao1_var(self): # Should match observed results from EstimateS.NOTE: EstimateS reports # sd, not var, and rounds to 2 dp. obs = _chao1_var(self.counts) npt.assert_allclose(obs, 1.42 ** 2, rtol=0.01) obs = _chao1_var(self.counts, bias_corrected=False) npt.assert_allclose(obs, 2.29 ** 2, rtol=0.01) obs = _chao1_var(self.no_singles) self.assertAlmostEqual(obs, 0.39 ** 2, delta=0.01) obs = _chao1_var(self.no_singles, bias_corrected=False) self.assertAlmostEqual(obs, 0.39 ** 2, delta=0.01) obs = _chao1_var(self.no_doubles) self.assertAlmostEqual(obs, 2.17 ** 2, delta=0.01) obs = _chao1_var(self.no_doubles, bias_corrected=False) self.assertAlmostEqual(obs, 2.17 ** 2, delta=0.01) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/test_gini.py000066400000000000000000000044001520735541300262700ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt from skbio.diversity.alpha import gini_index from skbio.diversity.alpha._gini import ( _lorenz_curve, _lorenz_curve_integrator) class GiniTests(TestCase): def setUp(self): self.data = np.array([4.5, 6.7, 3.4, 15., 18., 3.5, 6.7, 14.1]) self.lorenz_curve_points = ( np.array([0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0]), np.array([0.047287899860917935, 0.095966620305980521, 0.15855354659248957, 0.2517385257301808, 0.34492350486787204, 0.541029207232267, 0.74965229485396379, 1.0])) def test_gini_index_bug_1844(self): exp = 0.0 obs = gini_index([2, 2, 2, 2, 2]) self.assertAlmostEqual(obs, exp) def test_gini_index(self): exp = 0.32771210013908214 obs = gini_index(self.data, 'trapezoids') self.assertAlmostEqual(obs, exp) exp = 0.20271210013908214 obs = gini_index(self.data, 'rectangles') self.assertAlmostEqual(obs, exp) # Raises error on negative data. with self.assertRaises(ValueError): gini_index([1.0, -3.1, 4.5]) def test_lorenz_curve(self): npt.assert_allclose(_lorenz_curve(self.data), self.lorenz_curve_points) def test_lorenz_curve_integrator(self): exp = 0.33614394993045893 obs = _lorenz_curve_integrator(self.lorenz_curve_points, 'trapezoids') self.assertAlmostEqual(obs, exp) exp = 0.39864394993045893 obs = _lorenz_curve_integrator(self.lorenz_curve_points, 'rectangles') self.assertAlmostEqual(obs, exp) # Raises error on invalid method. with self.assertRaises(ValueError): _lorenz_curve_integrator(self.lorenz_curve_points, 'brofist') if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/test_lladser.py000066400000000000000000000206401520735541300267740ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy as np import numpy.testing as npt from skbio.stats import subsample_counts from skbio.diversity.alpha import lladser_pe, lladser_ci from skbio.diversity.alpha._lladser import ( _expand_counts, _lladser_point_estimates, _get_interval_for_r_new_taxa, _lladser_ci_series, _lladser_ci_from_r) def create_fake_observation(): """Create a subsample with defined property""" # Create a subsample of a larger sample such that we can compute # the expected probability of the unseen portion. # This is used in the tests of lladser_pe and lladser_ci counts = np.ones(1001, dtype='int64') counts[0] = 9000 total = counts.sum() fake_obs = subsample_counts(counts, 1000, replace=False, seed=123456789) exp_p = 1 - sum([x/total for (x, y) in zip(counts, fake_obs) if y > 0]) return fake_obs, exp_p class LladserTests(unittest.TestCase): def test_lladser_pe(self): """lladser_pe returns point estimates within the expected variance""" fake_obs, exp_p = create_fake_observation() reps = 100 sum = 0 for i in range(reps): sum += lladser_pe(fake_obs, r=30) obs = sum / reps # Estimator has variance of (1-p)^2/(r-2), # which for r=30 and p~=0.9 is 0.0289 self.assertTrue(abs(obs - exp_p) < 0.0289) # edge cases obs = lladser_pe([3], r=4) self.assertTrue(np.isnan(obs)) obs = lladser_pe([1], r=3) self.assertTrue(np.isnan(obs)) def test_lladser_ci_nan(self): """lladser_ci returns nan if sample is too short to make an estimate""" obs = lladser_ci([3], r=4) self.assertTrue(len(obs) == 2 and np.isnan(obs[0]) and np.isnan(obs[1])) def test_lladser_ci(self): """lladser_ci estimate using defaults contains p with 95% prob""" reps = 100 sum = 0 for i in range(reps): fake_obs, exp_p = create_fake_observation() (low, high) = lladser_ci(fake_obs, r=10, seed=123) if (low <= exp_p <= high): sum += 1 self.assertTrue(sum/reps >= 0.95) def test_lladser_ci_f3(self): """lladser_ci estimate using f=3 contains p with 95% prob""" # Test different values of f=3 and r=14, which lie exactly on the # 95% interval line. For 100 reps using simple cumulative binomial # probs we expect to have more than 5 misses of the interval in 38% # of all test runs. To make this test pass reliable we thus have to # set a defined seed reps = 1000 sum = 0 for i in range(reps): # re-create the obs for every estimate, such that they are truly # independent events fake_obs, exp_p = create_fake_observation() (low, high) = lladser_ci(fake_obs, r=14, f=3, seed=123) if (low <= exp_p <= high): sum += 1 self.assertTrue(sum/reps >= 0.95, msg=f"{sum}, {reps}, {sum/reps}") def test_expand_counts(self): arr = np.array([2, 0, 1, 2]) npt.assert_array_equal(_expand_counts(arr), np.array([0, 0, 2, 3, 3])) def test_lladser_point_estimates(self): s = [5, 1, 5, 1, 2, 3, 1, 5, 3, 2, 5, 3] r = 3 observed = list(_lladser_point_estimates(s, r)) self.assertEqual(len(observed), 3) for k in range(3): x = observed[k] t = x[2] self.assertEqual(x[0], (r - 1) / t) # Estimator has variance of (1-p)^2/(r-2), # which for r=7 and p=0.5 is 0.05 seq = "WBWBWBWBWBWBWBWBWBWBWBWBWBWBWBWBWBW" reps = 1000 sum = 0 for i in range(reps): p, _, _ = list(_lladser_point_estimates(seq, r=7))[0] sum += p self.assertTrue(0.45 < sum / reps and sum / reps < 0.55) def test_lladser_point_estimates_invalid_r(self): with self.assertRaises(ValueError): list(_lladser_point_estimates([5, 1, 5, 1, 2, 3, 1, 5, 3, 2, 5, 3], 2)) def test_get_interval_for_r_new_taxa(self): s = [5, 1, 5, 1, 2, 3, 1, 5, 3, 2, 5] expected = [(3, set([5]), 4, 0), (4, set([5, 1]), 6, 1), (4, set([5, 1, 2]), 9, 4)] for x, y in zip(_get_interval_for_r_new_taxa(s, 2), expected): self.assertEqual(x, y) s = [5, 5, 5, 5, 5] # never saw new one self.assertEqual(list(_get_interval_for_r_new_taxa(s, 2)), []) def test_lladser_ci_series_exact(self): # have seen RWB urn_1 = 'RWBWWBWRRWRYWRPPZ' results = list(_lladser_ci_series(urn_1, r=4)) self.assertEqual(len(results), 3) def test_lladser_ci_series_random(self): seq = "WBWBWBWBWBWB" observations = [] alpha = 0.95 reps = 1000 for i in range(reps): obs = list(_lladser_ci_series(seq, r=4, alpha=alpha))[0] observations.append(obs) tps = list(filter(lambda a_b: a_b[0] < 0.5 and 0.5 < a_b[1], observations)) self.assertTrue(len(tps) >= alpha * reps) # 100%-95% def test_lladser_ci_from_r(self): f = 10 t = 10 r = 4 obs_low, obs_high = _lladser_ci_from_r(r=r, t=t, f=f) npt.assert_almost_equal(obs_low, 0.0806026244) npt.assert_almost_equal(obs_high, 0.806026244) r = 20 t = 100 obs_low, obs_high = _lladser_ci_from_r(r=r, t=t, f=f) npt.assert_almost_equal(obs_low, 0.02787923964) npt.assert_almost_equal(obs_high, 0.2787923964) # make sure we test with each possible alpha alpha = 0.99 obs_low, obs_high = _lladser_ci_from_r(r=r, t=t, f=f, alpha=alpha) npt.assert_almost_equal(obs_low, 0.03184536992) npt.assert_almost_equal(obs_high, 0.3184536992) alpha = 0.9 r = 3 obs_low, obs_high = _lladser_ci_from_r(r=r, t=t, f=f, alpha=alpha) npt.assert_almost_equal(obs_low, 0.005635941995) npt.assert_almost_equal(obs_high, 0.05635941995) # test other ci_types ci_type = 'ULCU' obs_low, obs_high = _lladser_ci_from_r(r=r, t=t, f=f, alpha=alpha, ci_type=ci_type) npt.assert_almost_equal(obs_low, 0.01095834700) npt.assert_almost_equal(obs_high, 0.1095834700) alpha = 0.95 t = 10 ci_type = 'U' obs_low, obs_high = _lladser_ci_from_r(r=r, t=t, f=f, alpha=alpha, ci_type=ci_type) npt.assert_almost_equal(obs_low, 0) npt.assert_almost_equal(obs_high, 0.6295793622) ci_type = 'L' obs_low, obs_high = _lladser_ci_from_r(r=r, t=t, f=f, alpha=alpha, ci_type=ci_type) npt.assert_almost_equal(obs_low, 0.0817691447) npt.assert_almost_equal(obs_high, 1) # constant not precomputed with self.assertRaises(ValueError): _lladser_ci_from_r(r=r, t=t, f=f, alpha=0.88) def test_lladser_ci_from_r_invalid_input(self): # unsupported alpha for ci_type='U' with self.assertRaises(ValueError): _lladser_ci_from_r(r=3, t=10, f=10, alpha=0.90, ci_type='U') # unsupported r for ci_type='U' with self.assertRaises(ValueError): _lladser_ci_from_r(r=42, t=10, f=10, alpha=0.95, ci_type='U') # unsupported alpha for ci_type='L' with self.assertRaises(ValueError): _lladser_ci_from_r(r=3, t=10, f=10, alpha=0.90, ci_type='L') # unsupported r for ci_type='L' with self.assertRaises(ValueError): _lladser_ci_from_r(r=50, t=10, f=10, alpha=0.95, ci_type='L') # unknown ci_type with self.assertRaises(ValueError): _lladser_ci_from_r(r=4, t=10, f=10, alpha=0.95, ci_type='brofist') # requesting CI for not precomputed values with self.assertRaises(ValueError): _lladser_ci_from_r(r=500, t=10, f=10) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/alpha/tests/test_pd.py000066400000000000000000000377431520735541300257650ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main from io import StringIO import os import numpy as np import pandas as pd from skbio import TreeNode from skbio.util import get_data_path from skbio.tree import DuplicateNodeError, MissingNodeError from skbio.diversity.alpha import faith_pd, phydiv class FaithPDTests(TestCase): def setUp(self): self.counts = np.array([0, 1, 1, 4, 2, 5, 2, 4, 1, 2]) self.b1 = np.array([[1, 3, 0, 1, 0], [0, 2, 0, 4, 4], [0, 0, 6, 2, 1], [0, 0, 1, 1, 1], [2, 0, 3, 0, 0]]) self.sids1 = list('ABCDE') self.oids1 = ['OTU%d' % i for i in range(1, 6)] self.t1 = TreeNode.read(StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):' '0.0,(OTU4:0.75,OTU5:0.75):1.25):0.0)root;')) self.t1_w_extra_tips = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,(OTU5:0.25,(OTU6:0.5,OTU7:0.5):0.5):0.5):1.25):0.0' ')root;')) def test_faith_pd(self): # expected results derived from QIIME 1.9.1, which # is a completely different implementation skbio's initial # phylogenetic diversity implementation actual = faith_pd(self.b1[0], self.oids1, self.t1) expected = 4.5 self.assertAlmostEqual(actual, expected) actual = faith_pd(self.b1[0], self.oids1, self.t1, validate=False) self.assertAlmostEqual(actual, expected) actual = faith_pd(self.b1[1], self.oids1, self.t1) expected = 4.75 self.assertAlmostEqual(actual, expected) actual = faith_pd(self.b1[2], self.oids1, self.t1) expected = 4.75 self.assertAlmostEqual(actual, expected) actual = faith_pd(self.b1[3], self.oids1, self.t1) expected = 4.75 self.assertAlmostEqual(actual, expected) actual = faith_pd(self.b1[4], self.oids1, self.t1) expected = 3.0 self.assertAlmostEqual(actual, expected) def test_faith_pd_extra_tips(self): # results are the same despite presences of unobserved tips in tree actual = faith_pd(self.b1[0], self.oids1, self.t1_w_extra_tips) expected = faith_pd(self.b1[0], self.oids1, self.t1) self.assertAlmostEqual(actual, expected) actual = faith_pd(self.b1[1], self.oids1, self.t1_w_extra_tips) expected = faith_pd(self.b1[1], self.oids1, self.t1) self.assertAlmostEqual(actual, expected) actual = faith_pd(self.b1[2], self.oids1, self.t1_w_extra_tips) expected = faith_pd(self.b1[2], self.oids1, self.t1) self.assertAlmostEqual(actual, expected) actual = faith_pd(self.b1[3], self.oids1, self.t1_w_extra_tips) expected = faith_pd(self.b1[3], self.oids1, self.t1) self.assertAlmostEqual(actual, expected) actual = faith_pd(self.b1[4], self.oids1, self.t1_w_extra_tips) expected = 3.0 self.assertAlmostEqual(actual, expected) def test_faith_pd_none_observed(self): actual = faith_pd(np.array([], dtype=int), np.array([], dtype=int), self.t1) expected = 0.0 self.assertAlmostEqual(actual, expected) actual = faith_pd([0, 0, 0, 0, 0], self.oids1, self.t1) expected = 0.0 self.assertAlmostEqual(actual, expected) def test_faith_pd_all_observed(self): actual = faith_pd([1, 1, 1, 1, 1], self.oids1, self.t1) expected = sum(n.length for n in self.t1.traverse() if n.length is not None) self.assertAlmostEqual(actual, expected) actual = faith_pd([1, 2, 3, 4, 5], self.oids1, self.t1) expected = sum(n.length for n in self.t1.traverse() if n.length is not None) self.assertAlmostEqual(actual, expected) def test_faith_pd_one_observed(self): actual = faith_pd([1, 0, 0, 0, 0], self.oids1, self.t1) expected = 2.0 self.assertAlmostEqual(actual, expected) def test_faith_pd_minimal(self): # two tips tree = TreeNode.read(StringIO('(OTU1:0.25, OTU2:0.25)root;')) actual = faith_pd([1, 0], ['OTU1', 'OTU2'], tree) expected = 0.25 self.assertEqual(actual, expected) def test_faith_pd_qiime_tiny_test(self): # the following table and tree are derived from the QIIME 1.9.1 # "tiny-test" data tt_table_fp = get_data_path( os.path.join('qiime-191-tt', 'otu-table.tsv'), 'data') tt_tree_fp = get_data_path( os.path.join('qiime-191-tt', 'tree.nwk'), 'data') self.q_table = pd.read_csv(tt_table_fp, sep='\t', skiprows=1, index_col=0) self.q_tree = TreeNode.read(tt_tree_fp) expected_fp = get_data_path( os.path.join('qiime-191-tt', 'faith-pd.txt'), 'data') expected = pd.read_csv(expected_fp, sep='\t', index_col=0) for sid in self.q_table.columns: actual = faith_pd(self.q_table[sid], taxa=self.q_table.index, tree=self.q_tree) self.assertAlmostEqual(actual, expected['PD_whole_tree'][sid]) def test_faith_pd_root_not_observed(self): # expected values computed by hand tree = TreeNode.read( StringIO('((OTU1:0.1, OTU2:0.2):0.3, (OTU3:0.5, OTU4:0.7):1.1)' 'root;')) taxa = ['OTU%d' % i for i in range(1, 5)] # root node not observed, but branch between (OTU1, OTU2) and root # is considered observed actual = faith_pd([1, 1, 0, 0], taxa, tree) expected = 0.6 self.assertAlmostEqual(actual, expected) # root node not observed, but branch between (OTU3, OTU4) and root # is considered observed actual = faith_pd([0, 0, 1, 1], taxa, tree) expected = 2.3 self.assertAlmostEqual(actual, expected) def test_faith_pd_invalid_input(self): # tree has duplicated tip ids t = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU2:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(DuplicateNodeError, faith_pd, counts, taxa, t) # unrooted tree as input t = TreeNode.read(StringIO('((OTU1:0.1, OTU2:0.2):0.3, OTU3:0.5,' 'OTU4:0.7);')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, faith_pd, counts, taxa, t) # taxa has duplicated ids t = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU2'] self.assertRaises(ValueError, faith_pd, counts, taxa, t) # len of vectors not equal t = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, faith_pd, counts, taxa, t) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2'] self.assertRaises(ValueError, faith_pd, counts, taxa, t) # negative counts t = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2, -3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, faith_pd, counts, taxa, t) # tree with no branch lengths t = TreeNode.read( StringIO('((((OTU1,OTU2),OTU3)),(OTU4,OTU5));')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, faith_pd, counts, taxa, t) # tree missing some branch lengths t = TreeNode.read( StringIO('(((((OTU1,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, faith_pd, counts, taxa, t) # taxa not present in tree t = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU42'] self.assertRaises(MissingNodeError, faith_pd, counts, taxa, t) class PhyDivTests(TestCase): def setUp(self): self.tree = TreeNode.read(StringIO( '(((a:0.4,b:0.5):0.7,((c:0.1,d:0.2):0.6,(e:0.2,f:0.3):0.4):0.2)' ':0.1,g:1.2):0.2;')) # each dash (-) represents branch length = 0.05 # # /--------a # /--------------| # | \----------b # | # /--| /--c # | | /------------| # | | | \----d # | \----| # ----| | /----e # | \--------| # | \------f # | # \------------------------g self.taxa = list('abcdef') self.data = np.array([ [1, 2, 0, 0, 0, 0], # clade (a, b) [0, 0, 3, 4, 0, 0], # clade (c, d) [0, 0, 0, 0, 5, 6], # clade (e, f) [0, 0, 3, 4, 5, 6], # non-basal, monophyletic group (c, d, e, f) [1, 2, 3, 4, 0, 0]]) # basal, non-monophyletic group (a, b, c, d) def test_phydiv_rooted_unweighted(self): # equivalent to faith_pd for datum in self.data: obs = phydiv(datum, self.taxa, self.tree) exp = faith_pd(datum, self.taxa, self.tree) self.assertAlmostEqual(obs, exp) def test_phydiv_unrooted_unweighted(self): # equivalent to faith_pd without path to root exps = [0.9, 0.3, 0.5, 1.8, 2.7] for datum, exp in zip(self.data, exps): obs = phydiv(datum, self.taxa, self.tree, rooted=False) self.assertAlmostEqual(obs, exp) # edge case: one taxon obs = phydiv([1], ['a'], self.tree, rooted=False) self.assertEqual(obs, 0) # edge case: zero taxon obs = phydiv([0], ['a'], self.tree, rooted=False) self.assertEqual(obs, 0) # edge case: no taxon obs = phydiv([], [], self.tree, rooted=False) self.assertEqual(obs, 0) def test_phydiv_rooted_weighted(self): # group (a, b) # = (0.4 * 1 + 0.5 * 2 + (0.7 + 0.1 + 0.2) * (1 + 2)) / (1 + 2) obs = phydiv(self.data[0], self.taxa, self.tree, weight=True) exp = 1.46666667 self.assertAlmostEqual(obs, exp) # group (c, d) # = (0.1 * 3 + 0.2 * 4 + (0.6 + 0.2 + 0.1 + 0.2) * (3 + 4)) / (3 + 4) obs = phydiv(self.data[1], self.taxa, self.tree, weight=True) exp = 1.25714286 self.assertAlmostEqual(obs, exp) # group (c, d, e, f) # = (0.1 * 3 + 0.2 * 4 + 0.2 * 5 + 0.3 * 6 + 0.6 * (3 + 4) + 0.4 * # (5 + 6) + (0.2 + 0.1 + 0.2) * (3 + 4 + 5 + 6)) / (3 + 4 + 5 + 6) obs = phydiv(self.data[3], self.taxa, self.tree, weight=True) exp = 1.19444444 self.assertAlmostEqual(obs, exp) # group (a, b, c, d) # = (0.4 * 1 + 0.5 * 2 + 0.1 * 3 + 0.2 * 4 + 0.7 * (1 + 2) + (0.6 + # 0.2) * (3 + 4) + (0.1 + 0.2) * (1 + 2 + 3 + 4)) / (1 + 2 + 3 + 4) obs = phydiv(self.data[4], self.taxa, self.tree, weight=True) exp = 1.32 self.assertAlmostEqual(obs, exp) def test_phydiv_unrooted_weighted(self): # a.k.a., balance-weighted PD # group (a, b) # = (0.4 + 0.5) * 2 * min(1, 2) / (1 + 2) obs = phydiv(self.data[0], self.taxa, self.tree, rooted=False, weight=True) exp = 0.6 self.assertAlmostEqual(obs, exp) # group (c, d) # = (0.1 + 0.2) * 2 * min(3, 4) / (3 + 4) obs = phydiv(self.data[1], self.taxa, self.tree, rooted=False, weight=True) exp = 0.25714286 self.assertAlmostEqual(obs, exp) # group (c, d, e, f) # = 2 * (0.1 * min(3, 4 + 5 + 6) + 0.2 * min(4, 3 + 5 + 6) + 0.2 * # min(5, 3 + 4 + 6) + 0.3 * min(6, 3 + 4 + 5) + (0.6 + 0.4) * # min(3 + 4, 5 + 6)) / (3 + 4 + 5 + 6) obs = phydiv(self.data[3], self.taxa, self.tree, rooted=False, weight=True) exp = 1.21111111 self.assertAlmostEqual(obs, exp) # group (a, b, c, d) # = 2 * (0.4 * min(1, 2 + 3 + 4) + 0.5 * min(2, 1 + 3 + 4) + (0.7 + # 0.6 + 0.2) * min(1 + 2, 3 + 4) + 0.1 * min(3, 1 + 2 + 4) + 0.2 * # min(4, 1 + 2 + 3)) / (1 + 2 + 3 + 4) obs = phydiv(self.data[4], self.taxa, self.tree, rooted=False, weight=True) exp = 1.4 self.assertAlmostEqual(obs, exp) # edge cases self.assertEqual(phydiv([1], ['a'], self.tree, False, True), 0) self.assertEqual(phydiv([0], ['a'], self.tree, False, True), 0) self.assertEqual(phydiv([], [], self.tree, False, True), 0) def test_phydiv_weight_param(self): # group (a, b), unrooted # = (0.4 + 0.5) * (2 * min(1, 2) / (1 + 2)) ** theta obs = phydiv(self.data[0], self.taxa, self.tree, False, 0.5) exp = 0.73484692 self.assertAlmostEqual(obs, exp) obs = phydiv(self.data[0], self.taxa, self.tree, False, 0.25) exp = 0.81324180 self.assertAlmostEqual(obs, exp) # fall back to unweighted obs = phydiv(self.data[0], self.taxa, self.tree, False, 0) exp = 0.9 # fall back to fully-weighted self.assertAlmostEqual(obs, exp) obs = phydiv(self.data[0], self.taxa, self.tree, False, 1) exp = 0.6 self.assertAlmostEqual(obs, exp) # rooted # = (0.4 * 1 ** theta + 0.5 * 2 ** theta + (0.7 + 0.1 + 0.2) * # (1 + 2) ** theta) / (1 + 2) ** theta obs = phydiv(self.data[0], self.taxa, self.tree, True, 0.5) exp = 1.63918840 self.assertAlmostEqual(obs, exp) obs = phydiv(self.data[0], self.taxa, self.tree, True, 0.25) exp = 1.75573528 self.assertAlmostEqual(obs, exp) # edge cases self.assertEqual(phydiv([1], ['a'], self.tree, False, 0.5), 0) self.assertEqual(phydiv([0], ['a'], self.tree, False, 0.5), 0) self.assertEqual(phydiv([], [], self.tree, False, 0.5), 0) def test_phydiv_tree_unrooted(self): # convert tree to unrooted outgroup = self.tree.find('g') ingroup = outgroup.siblings()[0] unrooted = ingroup.copy() unrooted.extend([outgroup.copy()]) unrooted.length += self.tree.length or 0.0 # auto-enter unrooted mode obs = phydiv(self.data[0], self.taxa, unrooted) exp = phydiv(self.data[0], self.taxa, self.tree, rooted=False) self.assertEqual(obs, exp) # force rooted mode obs = phydiv(self.data[0], self.taxa, unrooted, rooted=True) exp = phydiv(self.data[0], self.taxa, self.tree) self.assertEqual(obs, exp) def test_phydiv_invalid_weight(self): params = (self.data[0], self.taxa, self.tree) self.assertRaises(ValueError, phydiv, *params, weight='hello') self.assertRaises(ValueError, phydiv, *params, weight=-0.5) self.assertRaises(ValueError, phydiv, *params, weight=2.0) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/000077500000000000000000000000001520735541300224175ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/__init__.py000066400000000000000000000021421520735541300245270ustar00rootroot00000000000000"""Beta diversity measures (:mod:`skbio.diversity.beta`) ===================================================== .. currentmodule:: skbio.diversity.beta This package provides implementations of beta diversity measures for computing sample dissimilarity. Users should also explore SciPy's :func:`~scipy.spatial.distance.pdist`, which provides implementations of additional beta diversity metrics with interfaces similar to those provided here, and can be directly used in the driver function :func:`~skbio.diversity.beta_diversity`. Functions --------- .. autosummary:: :toctree: unweighted_unifrac weighted_unifrac """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._unifrac import unweighted_unifrac, weighted_unifrac __all__ = ["unweighted_unifrac", "weighted_unifrac"] scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/_unifrac.py000066400000000000000000000551551520735541300245720ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from functools import partial import numpy as np from skbio.diversity._util import ( _validate_counts_matrix, vectorize_counts_and_tree, ) from skbio.diversity._phylogenetic import _tip_distances from skbio.util._decorator import params_aliased from skbio.tree._utils import _validate_taxa_and_tree # The default value indicating whether normalization should be applied # for weighted UniFrac. This is used in two locations, so set in a single # variable to avoid the code base becoming out of sync in the event of a # change in this default value. _normalize_weighted_unifrac_by_default = False @params_aliased([("taxa", "otu_ids", "0.6.0", True)]) def unweighted_unifrac(u_counts, v_counts, taxa, tree, validate=True): """Compute unweighted UniFrac. Parameters ---------- u_counts, v_counts: list, np.array Vectors of counts/abundances of taxa for two samples. Must be equal length. taxa : list, np.array Vector of taxon IDs corresponding to tip names in ``tree``. Must be the same length as ``u_counts`` and ``v_counts``. Required. tree : skbio.TreeNode Tree relating taxa. The set of tip names in the tree can be a superset of ``taxa``, but not a subset. Required. validate: bool, optional If ``False``, validation of the input won't be performed. This step can be slow, so if validation is run elsewhere it can be disabled here. However, invalid input data can lead to invalid results or error messages that are hard to interpret, so this step should not be bypassed if you're not certain that your input data are valid. See :mod:`skbio.diversity` for the description of what validation entails so you can determine if you can safely disable validation. Returns ------- float The unweighted UniFrac distance between the two samples. Raises ------ ValueError, MissingNodeError, DuplicateNodeError If validation fails. Exact error will depend on what was invalid. See Also -------- weighted_unifrac skbio.diversity skbio.diversity.beta_diversity Notes ----- Unweighted UniFrac was originally described in [1]_. A discussion of unweighted (qualitative) versus weighted (quantitative) diversity metrics is presented in [2]_. Deeper mathematical discussions of this metric is presented in [3]_. If computing unweighted UniFrac for multiple pairs of samples, using ``skbio.diversity.beta_diversity`` will be much faster than calling this function individually on each sample. This implementation differs from that in PyCogent (and therefore QIIME versions less than 2.0.0) by imposing a few additional restrictions on the inputs. First, the input tree must be rooted. In PyCogent, if an unrooted tree was provided that had a single trifurcating node (a newick convention for unrooted trees) that node was considered the root of the tree. Next, all taxa must be tips in the tree. PyCogent would silently ignore taxa that were not present the tree. To reproduce UniFrac results from PyCogent with scikit-bio, ensure that your PyCogent UniFrac calculations are performed on a rooted tree and that all taxa are present in the tree. This implementation of unweighted UniFrac is the array-based implementation described in [4]_. If using large number of samples or a large tree, we advise using the optimized UniFrac library [5]_. References ---------- .. [1] Lozupone, C. & Knight, R. UniFrac: a new phylogenetic method for comparing microbial communities. Appl. Environ. Microbiol. 71, 8228-8235 (2005). .. [2] Lozupone, C. A., Hamady, M., Kelley, S. T. & Knight, R. Quantitative and qualitative beta diversity measures lead to different insights into factors that structure microbial communities. Appl. Environ. Microbiol. 73, 1576-1585 (2007). .. [3] Lozupone, C., Lladser, M. E., Knights, D., Stombaugh, J. & Knight, R. UniFrac: an effective distance metric for microbial community comparison. ISME J. 5, 169-172 (2011). .. [4] Hamady M, Lozupone C, Knight R. Fast UniFrac: facilitating high- throughput phylogenetic analyses of microbial communities including analysis of pyrosequencing and PhyloChip data. ISME J. 4(1):17-27 (2010). .. [5] https://github.com/biocore/unifrac Examples -------- Assume we have the following abundance data for two samples, ``u`` and ``v``, represented as a pair of counts vectors. These counts represent the number of times specific Operational Taxonomic Units, or taxa, were observed in each of the samples. >>> u_counts = [1, 0, 0, 4, 1, 2, 3, 0] >>> v_counts = [0, 1, 1, 6, 0, 1, 0, 0] Because UniFrac is a phylogenetic diversity metric, we need to know which taxon each count corresponds to, which we'll provide as ``taxa``. >>> taxa = ['U1', 'U2', 'U3', 'U4', 'U5', 'U6', 'U7', 'U8'] We also need a phylogenetic tree that relates the taxa to one another. >>> from io import StringIO >>> from skbio import TreeNode >>> tree = TreeNode.read(StringIO( ... '(((((U1:0.5,U2:0.5):0.5,U3:1.0):1.0):0.0,' ... '(U4:0.75,(U5:0.5,((U6:0.33,U7:0.62):0.5' ... ',U8:0.5):0.5):0.5):1.25):0.0)root;')) We can then compute the unweighted UniFrac distance between the samples. >>> from skbio.diversity.beta import unweighted_unifrac >>> uu = unweighted_unifrac(u_counts, v_counts, taxa, tree) >>> print(round(uu, 2)) 0.37 """ u_node_counts, v_node_counts, _, _, tree_index = _setup_pairwise_unifrac( u_counts, v_counts, taxa, tree, validate, normalized=False, unweighted=True ) return _unweighted_unifrac(u_node_counts, v_node_counts, tree_index["length"]) @params_aliased([("taxa", "otu_ids", "0.6.0", True)]) def weighted_unifrac( u_counts, v_counts, taxa, tree, normalized=_normalize_weighted_unifrac_by_default, validate=True, ): """Compute weighted UniFrac with or without branch length normalization. Parameters ---------- u_counts, v_counts: list, np.array Vectors of counts/abundances of taxa for two samples. Must be equal length. taxa : list, np.array Vector of taxon IDs corresponding to tip names in ``tree``. Must be the same length as ``u_counts`` and ``v_counts``. Required. tree : skbio.TreeNode Tree relating taxa. The set of tip names in the tree can be a superset of ``taxa``, but not a subset. Required. normalized: boolean, optional If ``True``, apply branch length normalization, which is described in [1]_. Resulting distances will then be in the range ``[0, 1]``. validate: bool, optional If ``False``, validation of the input won't be performed. This step can be slow, so if validation is run elsewhere it can be disabled here. However, invalid input data can lead to invalid results or error messages that are hard to interpret, so this step should not be bypassed if you're not certain that your input data are valid. See :mod:`skbio.diversity` for the description of what validation entails so you can determine if you can safely disable validation. Returns ------- float The weighted UniFrac distance between the two samples. Raises ------ ValueError, MissingNodeError, DuplicateNodeError If validation fails. Exact error will depend on what was invalid. See Also -------- unweighted_unifrac skbio.diversity skbio.diversity.beta_diversity Notes ----- Weighted UniFrac was originally described in [1]_, which includes a discussion of unweighted (qualitative) versus weighted (quantitiative) diversity metrics. Deeper mathemtical discussions of this metric is presented in [2]_. If computing weighted UniFrac for multiple pairs of samples, using ``skbio.diversity.beta_diversity`` will be much faster than calling this function individually on each sample. This implementation differs from that in PyCogent (and therefore QIIME versions less than 2.0.0) by imposing a few additional restrictions on the inputs. First, the input tree must be rooted. In PyCogent, if an unrooted tree was provided that had a single trifurcating node (a newick convention for unrooted trees) that node was considered the root of the tree. Next, all taxa must be tips in the tree. PyCogent would silently ignore taxa that were not present the tree. To reproduce UniFrac results from PyCogent with scikit-bio, ensure that your PyCogent UniFrac calculations are performed on a rooted tree and that all taxa are present in the tree. This implementation of weighted UniFrac is the array-based implementation described in [3]_. If using large number of samples or a large tree, we advise using the optimized UniFrac library [4]_. References ---------- .. [1] Lozupone, C. A., Hamady, M., Kelley, S. T. & Knight, R. Quantitative and qualitative beta diversity measures lead to different insights into factors that structure microbial communities. Appl. Environ. Microbiol. 73, 1576-1585 (2007). .. [2] Lozupone, C., Lladser, M. E., Knights, D., Stombaugh, J. & Knight, R. UniFrac: an effective distance metric for microbial community comparison. ISME J. 5, 169-172 (2011). .. [3] Hamady M, Lozupone C, Knight R. Fast UniFrac: facilitating high- throughput phylogenetic analyses of microbial communities including analysis of pyrosequencing and PhyloChip data. ISME J. 4(1):17-27 (2010). .. [4] https://github.com/biocore/unifrac Examples -------- Assume we have the following abundance data for two samples, ``u`` and ``v``, represented as a pair of counts vectors. These counts represent the number of times specific taxa were observed in each of the samples. >>> u_counts = [1, 0, 0, 4, 1, 2, 3, 0] >>> v_counts = [0, 1, 1, 6, 0, 1, 0, 0] Because UniFrac is a phylogenetic diversity metric, we need to know which taxon each count corresponds to, which we'll provide as ``taxa``. >>> taxa = ['U1', 'U2', 'U3', 'U4', 'U5', 'U6', 'U7', 'U8'] We also need a phylogenetic tree that relates the taxa to one another. >>> from io import StringIO >>> from skbio import TreeNode >>> tree = TreeNode.read(StringIO( ... '(((((U1:0.5,U2:0.5):0.5,U3:1.0):1.0):0.0,' ... '(U4:0.75,(U5:0.5,((U6:0.33,U7:0.62):0.5' ... ',U8:0.5):0.5):0.5):1.25):0.0)root;')) Compute the weighted UniFrac distance between the samples. >>> from skbio.diversity.beta import weighted_unifrac >>> wu = weighted_unifrac(u_counts, v_counts, taxa, tree) >>> print(round(wu, 2)) 1.54 Compute the weighted UniFrac distance between the samples including branch length normalization so the value falls in the range ``[0.0, 1.0]``. >>> wu = weighted_unifrac(u_counts, v_counts, taxa, tree, normalized=True) >>> print(round(wu, 2)) 0.33 """ ( u_node_counts, v_node_counts, u_total_count, v_total_count, tree_index, ) = _setup_pairwise_unifrac( u_counts, v_counts, taxa, tree, validate, normalized=normalized, unweighted=False, ) branch_lengths = tree_index["length"] if normalized: tip_indices = _get_tip_indices(tree_index) node_to_root_distances = _tip_distances(branch_lengths, tree, tip_indices) return _weighted_unifrac_normalized( u_node_counts, v_node_counts, u_total_count, v_total_count, branch_lengths, node_to_root_distances, ) else: return _weighted_unifrac( u_node_counts, v_node_counts, u_total_count, v_total_count, branch_lengths )[0] def _setup_pairwise_unifrac( u_counts, v_counts, taxa, tree, validate, normalized, unweighted ): if validate: counts = _validate_counts_matrix([u_counts, v_counts], cast_int=False) if counts.shape[1] != len(taxa): raise ValueError("`taxa` must be the same length as `counts`.") _validate_taxa_and_tree(taxa, tree, rooted=True, lengths=True) else: counts = np.vstack([u_counts, v_counts]) counts_by_node, tree_index, branch_lengths = vectorize_counts_and_tree( counts, taxa, tree ) total_counts = counts.sum(axis=1) return (*counts_by_node, *total_counts, tree_index) def _unweighted_unifrac(u_node_counts, v_node_counts, branch_lengths): """Calculate unweighted UniFrac distance between samples. Parameters ---------- u_node_counts, v_node_counts : np.array Vectors indicating presence (value greater than zero) and absence (value equal to zero) of nodes in two samples, `u` and `v`. Order is assumed to be the same as in `branch_lengths`. branch_lengths : np.array Vector of branch lengths of all nodes (tips and internal nodes) in postorder representation of their tree. Returns ------- float Unweighted UniFrac distance between samples. Notes ----- The count vectors passed here correspond to all nodes in the tree, not just the tips. """ unique_nodes = np.logical_xor(u_node_counts, v_node_counts) observed_nodes = np.logical_or(u_node_counts, v_node_counts) unique_branch_length = (branch_lengths * unique_nodes).sum() observed_branch_length = (branch_lengths * observed_nodes).sum() if observed_branch_length == 0.0: # handle special case to avoid division by zero return 0.0 return unique_branch_length / observed_branch_length def _weighted_unifrac( u_node_counts, v_node_counts, u_total_count, v_total_count, branch_lengths ): """Calculate weighted Unifrac distance between samples. Parameters ---------- u_node_counts, v_node_counts : np.array Vectors indicating presence (value greater than zero) and absence (value equal to zero) of nodes in two samples, `u` and `v`. Order is assumed to be the same as in `branch_lengths`. u_total_count, v_total_count : int The sum of ``u_node_counts`` and ``v_node_counts`` vectors, respectively. This could be computed internally, but since this is a private method and the calling function has already generated these values, this saves an iteration over each of these vectors. branch_lengths : np.array Vector of branch lengths of all nodes (tips and internal nodes) in postorder representation of their tree. Returns ------- float Weighted UniFrac distance between samples. np.array of float Proportional abundance of each node in tree in sample `u` np.array of float Proportional abundance of each node in tree in sample `v` """ if u_total_count > 0: # convert to relative abundances if there are any counts u_node_proportions = u_node_counts / u_total_count else: # otherwise, we'll just do the computation with u_node_counts, which # is necessarily all zeros u_node_proportions = u_node_counts if v_total_count > 0: v_node_proportions = v_node_counts / v_total_count else: v_node_proportions = v_node_counts wu = (branch_lengths * np.absolute(u_node_proportions - v_node_proportions)).sum() return wu, u_node_proportions, v_node_proportions def _weighted_unifrac_normalized( u_node_counts, v_node_counts, u_total_count, v_total_count, branch_lengths, node_to_root_distances, ): """Calculate weighted normalized UniFrac distance between samples. Parameters ---------- u_node_counts, v_node_counts : np.array Vectors indicating presence (value greater than zero) and absence (value equal to zero) of nodes in two samples, `u` and `v`. Order is assumed to be the same as in `branch_lengths`. u_total_count, v_total_count : int The sum of ``u_node_counts`` and ``v_node_counts`` vectors, respectively. This could be computed internally, but since this is a private method and the calling function has already generated these values, this saves an iteration over each of these vectors. branch_lengths : np.array Vector of branch lengths of all nodes (tips and internal nodes) in postorder representation of their tree. node_to_root_distances : np.ndarray 1D column vector of branch lengths in post order form. There should be positions in this vector for all nodes in the tree, but only tips should be non-zero. Returns ------- float Normalized weighted UniFrac distance between samples. Notes ----- The count vectors passed here correspond to all nodes in the tree, not just the tips. """ if u_total_count == 0.0 and v_total_count == 0.0: # handle special case to avoid division by zero return 0.0 u, u_node_proportions, v_node_proportions = _weighted_unifrac( u_node_counts, v_node_counts, u_total_count, v_total_count, branch_lengths ) c = _weighted_unifrac_branch_correction( node_to_root_distances, u_node_proportions, v_node_proportions ) return u / c def _setup_multiple_unifrac(counts, taxa, tree, validate): if validate: _validate_taxa_and_tree(taxa, tree, rooted=True, lengths=True) counts_by_node, tree_index, branch_lengths = vectorize_counts_and_tree( counts, taxa, tree ) return counts_by_node, tree_index, branch_lengths def _setup_multiple_unweighted_unifrac(counts, taxa, tree, validate): r"""Create optimized pdist-compatible unweighted UniFrac function. Parameters ---------- counts : 2D array_like of ints or floats Matrix containing count/abundance data where each row contains counts of observations in a given sample. taxa: list, np.array Vector of taxon IDs corresponding to tip names in ``tree``. Must be the same length as ``u_counts`` and ``v_counts``. These IDs do not need to be in tip order with respect to the tree. tree: skbio.TreeNode Tree relating taxa. The set of tip names in the tree can be a superset of ``taxa``, but not a subset. validate: bool, optional If ``False``, validation of the input won't be performed. Returns ------- function Optimized pairwise unweighted UniFrac calculator that can be passed to ``scipy.spatial.distance.pdist``. 2D np.array of ints, floats Counts of all nodes in ``tree``. """ counts_by_node, _, branch_lengths = _setup_multiple_unifrac( counts, taxa, tree, validate ) f = partial(_unweighted_unifrac, branch_lengths=branch_lengths) return f, counts_by_node def _setup_multiple_weighted_unifrac(counts, taxa, tree, normalized, validate): r"""Create optimized pdist-compatible weighted UniFrac function. Parameters ---------- counts : 2D array_like of ints or floats Matrix containing count/abundance data where each row contains counts of observations in a given sample. taxa : list, np.array Vector of taxon IDs corresponding to tip names in ``tree``. Must be the same length as ``u_counts`` and ``v_counts``. These IDs do not need to be in tip order with respect to the tree. tree : skbio.TreeNode Tree relating taxa. The set of tip names in the tree can be a superset of ``taxa``, but not a subset. normalized : bool If ``True``, output will be normalized. validate: bool, optional If ``False``, validation of the input won't be performed. Returns ------- function Optimized pairwise unweighted UniFrac calculator that can be passed to ``scipy.spatial.distance.pdist``. 2D np.array of ints, floats Counts of all nodes in ``tree``. """ counts_by_node, tree_index, branch_lengths = _setup_multiple_unifrac( counts, taxa, tree, validate ) tip_indices = _get_tip_indices(tree_index) if normalized: node_to_root_distances = _tip_distances(branch_lengths, tree, tip_indices) def f(u_node_counts, v_node_counts): u_total_count = np.take(u_node_counts, tip_indices).sum() v_total_count = np.take(v_node_counts, tip_indices).sum() u = _weighted_unifrac_normalized( u_node_counts, v_node_counts, u_total_count, v_total_count, branch_lengths, node_to_root_distances, ) return u else: def f(u_node_counts, v_node_counts): u_total_count = np.take(u_node_counts, tip_indices).sum() v_total_count = np.take(v_node_counts, tip_indices).sum() u, _, _ = _weighted_unifrac( u_node_counts, v_node_counts, u_total_count, v_total_count, branch_lengths, ) return u return f, counts_by_node def _get_tip_indices(tree_index): tip_indices = np.array( [n.id for n in tree_index["id_index"].values() if n.is_tip()], dtype=np.intp ) return tip_indices def _weighted_unifrac_branch_correction( node_to_root_distances, u_node_proportions, v_node_proportions ): """Calculate weighted unifrac branch length correction. Parameters ---------- node_to_root_distances : np.ndarray 1D column vector of branch lengths in post order form. There should be positions in this vector for all nodes in the tree, but only tips should be non-zero. u_node_proportions, v_node_proportions : np.ndarray Proportional abundance of observations of all nodes in the tree in samples ``u`` and ``v``, respectively. u_total_count, v_total_count : float The sum of the observations in samples ``u`` and ``v``, respectively. Returns ------- np.ndarray The corrected branch lengths """ return ( node_to_root_distances.ravel() * (u_node_proportions + v_node_proportions) ).sum() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/000077500000000000000000000000001520735541300235615ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/__init__.py000066400000000000000000000005411520735541300256720ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/data/000077500000000000000000000000001520735541300244725ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/data/qiime-191-tt/000077500000000000000000000000001520735541300265335ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/data/qiime-191-tt/README.md000066400000000000000000000025701520735541300300160ustar00rootroot00000000000000Files in this directory are the QIIME 1.9.1 "tiny test" files. These data were developed by @gregcaporaso, who gave permission to reproduce them in scikit-bio. If you have a [QIIME 1.9.1 base installation](http://install.qiime.org), the raw input files in this directory can be obtained by running: ```bash python -c "from qiime.test import write_test_data; write_test_data('.')" biom convert -i biom --to-tsv -o otu-table.tsv ``` After converting to tsv, the following OTUs are removed because they are not present in the tree (they're not 16S sequences, so can't be aligned with PyNAST): ``None1``, ``None10``, ``None6``, and ``None2``. The ``not16S.1`` sample is also removed because, after removing those OTUs, it has a total count of 0. This boundary case is tested directly in the ``unifrac_*`` and ``faith_pd`` tests. Then, in the python interpreter, we midpoint root the tree (since this is a QIIME 1.9.1 installation, this step is performed with scikit-bio 0.2.3): ```python from skbio import TreeNode t = TreeNode.read('./tree') t = t.root_at_midpoint() t.write('tree', format='newick') ``` The output files (alpha diversity values and beta diversity distance matrices) can then be obtained by running: ```bash alpha_diversity.py -i biom -t tree -m PD_whole_tree -o pd.txt beta_diversity.py -m weighted_unifrac,unweighted_unifrac,weighted_normalized_unifrac -i biom -t tree -o o ``` scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/data/qiime-191-tt/otu-table.tsv000066400000000000000000000004431520735541300311660ustar00rootroot00000000000000# Constructed from biom file #OTU ID f2 f1 f3 f4 p2 p1 t1 t2 295053 20 18 18 22 4 0 0 0 42684 0 0 0 0 1 0 0 0 None11 1 0 0 0 1 1 0 0 None7 0 0 0 0 1 0 0 0 None5 0 0 0 0 1 0 0 0 None4 0 0 0 0 1 1 0 0 None3 0 0 0 0 1 0 2 3 879972 0 0 0 0 9 20 1 4 None9 0 0 0 0 3 0 19 15 None8 1 4 4 0 0 0 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/data/qiime-191-tt/tree.nwk000066400000000000000000000004121520735541300302100ustar00rootroot00000000000000(((879972:0.05039,None3:0.00778)0.980:0.15948,((None11:0.07161,None4:0.06965)0.917:0.09643,(295053:0.06096,42684:0.15599)0.910:0.08898)0.899:0.09227)0.958:0.064315,(None8:0.09606,(None7:0.10435,(None5:0.02626,None9:0.00014)1.000:0.25335)0.753:0.0465):0.075445)root; scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/data/qiime-191-tt/unweighted_unifrac_dm.txt000066400000000000000000000016661520735541300336370ustar00rootroot00000000000000 f2 f1 f3 f4 p2 p1 t1 not16S.1 t2 f2 0.0 0.26009565527 0.26009565527 0.525554506478 0.638141793205 0.649277757971 0.879901349993 1.0 0.879901349993 f1 0.26009565527 0.0 0.0 0.358774553898 0.74869733414 0.830826823972 0.859632207458 1.0 0.859632207458 f3 0.26009565527 0.0 0.0 0.358774553898 0.74869733414 0.830826823972 0.859632207458 1.0 0.859632207458 f4 0.525554506478 0.358774553898 0.358774553898 0.0 0.784728562399 0.792350994914 0.928507908983 1.0 0.928507908983 p2 0.638141793205 0.74869733414 0.74869733414 0.784728562399 0.0 0.575711075216 0.538310274598 1.0 0.538310274598 p1 0.649277757971 0.830826823972 0.830826823972 0.792350994914 0.575711075216 0.0 0.72230493437 1.0 0.72230493437 t1 0.879901349993 0.859632207458 0.859632207458 0.928507908983 0.538310274598 0.72230493437 0.0 1.0 0.0 not16S.1 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0 1.0 t2 0.879901349993 0.859632207458 0.859632207458 0.928507908983 0.538310274598 0.72230493437 0.0 1.0 0.0weighted_normalized_unifrac_dm.txt000066400000000000000000000017261520735541300354360ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/data/qiime-191-tt f2 f1 f3 f4 p2 p1 t1 not16S.1 t2 f2 0.0 0.113186179375 0.113186179375 0.0595362216515 0.599928715677 0.732991733568 0.962973616339 1.0 0.925172353416 f1 0.113186179375 0.0 0.0 0.14768803941 0.577821666109 0.782364205648 0.929696953333 1.0 0.889628707676 f3 0.113186179375 0.0 0.0 0.14768803941 0.577821666109 0.782364205648 0.929696953333 1.0 0.889628707676 f4 0.0595362216515 0.14768803941 0.14768803941 0.0 0.639547977307 0.751529763393 0.973594769453 1.0 0.936441078767 p2 0.599928715677 0.577821666109 0.577821666109 0.639547977307 0.0 0.430712953163 0.677634129601 1.0 0.519557525688 p1 0.732991733568 0.782364205648 0.782364205648 0.751529763393 0.430712953163 0.0 0.896900994816 1.0 0.739098773939 t1 0.962973616339 0.929696953333 0.929696953333 0.973594769453 0.677634129601 0.896900994816 0.0 1.0 0.167120342575 not16S.1 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0 1.0 t2 0.925172353416 0.889628707676 0.889628707676 0.936441078767 0.519557525688 0.739098773939 0.167120342575 1.0 0.0scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/data/qiime-191-tt/weighted_unifrac_dm.txt000066400000000000000000000016661520735541300332740ustar00rootroot00000000000000 f2 f1 f3 f4 p2 p1 t1 not16S.1 t2 f2 0.0 0.0660086363636 0.0660086363636 0.0361822727273 0.364183181818 0.425055909091 0.634565909091 1.0 0.590832727273 f1 0.0660086363636 0.0 0.0 0.0869145454545 0.339649090909 0.438638181818 0.594755454545 1.0 0.551022272727 f3 0.0660086363636 0.0 0.0 0.0869145454545 0.339649090909 0.438638181818 0.594755454545 1.0 0.551022272727 f4 0.0361822727273 0.0869145454545 0.0869145454545 0.0 0.391632727273 0.4398 0.646739090909 1.0 0.603005909091 p2 0.364183181818 0.339649090909 0.339649090909 0.391632727273 0.0 0.251758181818 0.44967 1.0 0.334201363636 p1 0.425055909091 0.438638181818 0.438638181818 0.4398 0.251758181818 0.0 0.57082 1.0 0.455351363636 t1 0.634565909091 0.594755454545 0.594755454545 0.646739090909 0.44967 0.57082 0.0 1.0 0.116175909091 not16S.1 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0 1.0 t2 0.590832727273 0.551022272727 0.551022272727 0.603005909091 0.334201363636 0.455351363636 0.116175909091 1.0 0.0scikit-bio-scikit-bio-a3beaa6/skbio/diversity/beta/tests/test_unifrac.py000066400000000000000000000723561520735541300266360ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from io import StringIO from unittest import main, TestCase import numpy as np from skbio import TreeNode from skbio.tree import DuplicateNodeError, MissingNodeError from skbio.diversity.beta import unweighted_unifrac, weighted_unifrac from skbio.diversity.beta._unifrac import (_unweighted_unifrac, _weighted_unifrac, _weighted_unifrac_branch_correction) class UnifracTests(TestCase): def setUp(self): self.b1 = np.array( [[1, 3, 0, 1, 0], [0, 2, 0, 4, 4], [0, 0, 6, 2, 1], [0, 0, 1, 1, 1], [5, 3, 5, 0, 0], [0, 0, 0, 3, 5]]) self.sids1 = list('ABCDEF') self.oids1 = ['OTU%d' % i for i in range(1, 6)] self.t1 = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) self.t1_w_extra_tips = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,(OTU5:0.25,(OTU6:0.5,OTU7:0.5):0.5):0.5):1.25):0.0' ')root;')) self.t2 = TreeNode.read( StringIO('((OTU1:0.1, OTU2:0.2):0.3, (OTU3:0.5, OTU4:0.7):1.1)' 'root;')) self.oids2 = ['OTU%d' % i for i in range(1, 5)] def test_unweighted_taxa_out_of_order(self): # UniFrac API does not assert the observations are in tip order of the # input tree shuffled_ids = self.oids1[:] shuffled_b1 = self.b1.copy() shuffled_ids[0], shuffled_ids[-1] = shuffled_ids[-1], shuffled_ids[0] shuffled_b1[:, [0, -1]] = shuffled_b1[:, [-1, 0]] for i in range(len(self.b1)): for j in range(len(self.b1)): actual = unweighted_unifrac( self.b1[i], self.b1[j], self.oids1, self.t1) expected = unweighted_unifrac( shuffled_b1[i], shuffled_b1[j], shuffled_ids, self.t1) self.assertAlmostEqual(actual, expected) def test_weighted_taxa_out_of_order(self): # UniFrac API does not assert the observations are in tip order of the # input tree shuffled_ids = self.oids1[:] shuffled_b1 = self.b1.copy() shuffled_ids[0], shuffled_ids[-1] = shuffled_ids[-1], shuffled_ids[0] shuffled_b1[:, [0, -1]] = shuffled_b1[:, [-1, 0]] for i in range(len(self.b1)): for j in range(len(self.b1)): actual = weighted_unifrac( self.b1[i], self.b1[j], self.oids1, self.t1) expected = weighted_unifrac( shuffled_b1[i], shuffled_b1[j], shuffled_ids, self.t1) self.assertAlmostEqual(actual, expected) def test_unweighted_extra_tips(self): # UniFrac values are the same despite unobserved tips in the tree for i in range(len(self.b1)): for j in range(len(self.b1)): actual = unweighted_unifrac( self.b1[i], self.b1[j], self.oids1, self.t1_w_extra_tips) expected = unweighted_unifrac( self.b1[i], self.b1[j], self.oids1, self.t1) self.assertAlmostEqual(actual, expected) def test_weighted_extra_tips(self): # UniFrac values are the same despite unobserved tips in the tree for i in range(len(self.b1)): for j in range(len(self.b1)): actual = weighted_unifrac( self.b1[i], self.b1[j], self.oids1, self.t1_w_extra_tips) expected = weighted_unifrac( self.b1[i], self.b1[j], self.oids1, self.t1) self.assertAlmostEqual(actual, expected) def test_unweighted_minimal_trees(self): # two tips tree = TreeNode.read(StringIO('(OTU1:0.25, OTU2:0.25)root;')) actual = unweighted_unifrac([1, 0], [0, 0], ['OTU1', 'OTU2'], tree) expected = 1.0 self.assertEqual(actual, expected) def test_weighted_minimal_trees(self): # two tips tree = TreeNode.read(StringIO('(OTU1:0.25, OTU2:0.25)root;')) actual = weighted_unifrac([1, 0], [0, 0], ['OTU1', 'OTU2'], tree) expected = 0.25 self.assertEqual(actual, expected) def test_unweighted_root_not_observed(self): # expected values computed with QIIME 1.9.1 and by hand # root node not observed, but branch between (OTU1, OTU2) and root # is considered shared actual = unweighted_unifrac([1, 1, 0, 0], [1, 0, 0, 0], self.oids2, self.t2) # for clarity of what I'm testing, compute expected as it would # based on the branch lengths. the values that compose shared was # a point of confusion for me here, so leaving these in for # future reference expected = 0.2 / (0.1 + 0.2 + 0.3) # 0.3333333333 self.assertAlmostEqual(actual, expected) # root node not observed, but branch between (OTU3, OTU4) and root # is considered shared actual = unweighted_unifrac([0, 0, 1, 1], [0, 0, 1, 0], self.oids2, self.t2) # for clarity of what I'm testing, compute expected as it would # based on the branch lengths. the values that compose shared was # a point of confusion for me here, so leaving these in for # future reference expected = 0.7 / (1.1 + 0.5 + 0.7) # 0.3043478261 self.assertAlmostEqual(actual, expected) def test_weighted_root_not_observed(self): # expected values computed by hand, these disagree with QIIME 1.9.1 # root node not observed, but branch between (OTU1, OTU2) and root # is considered shared actual = weighted_unifrac([1, 0, 0, 0], [1, 1, 0, 0], self.oids2, self.t2) expected = 0.15 self.assertAlmostEqual(actual, expected) # root node not observed, but branch between (OTU3, OTU4) and root # is considered shared actual = weighted_unifrac([0, 0, 1, 1], [0, 0, 1, 0], self.oids2, self.t2) expected = 0.6 self.assertAlmostEqual(actual, expected) def test_weighted_normalized_root_not_observed(self): # expected values computed by hand, these disagree with QIIME 1.9.1 # root node not observed, but branch between (OTU1, OTU2) and root # is considered shared actual = weighted_unifrac([1, 0, 0, 0], [1, 1, 0, 0], self.oids2, self.t2, normalized=True) expected = 0.1764705882 self.assertAlmostEqual(actual, expected) # root node not observed, but branch between (OTU3, OTU4) and root # is considered shared actual = weighted_unifrac([0, 0, 1, 1], [0, 0, 1, 0], self.oids2, self.t2, normalized=True) expected = 0.1818181818 self.assertAlmostEqual(actual, expected) def test_unweighted_unifrac_identity(self): for i in range(len(self.b1)): actual = unweighted_unifrac( self.b1[i], self.b1[i], self.oids1, self.t1) expected = 0.0 self.assertAlmostEqual(actual, expected) def test_unweighted_unifrac_symmetry(self): for i in range(len(self.b1)): for j in range(len(self.b1)): actual = unweighted_unifrac( self.b1[i], self.b1[j], self.oids1, self.t1) expected = unweighted_unifrac( self.b1[j], self.b1[i], self.oids1, self.t1) self.assertAlmostEqual(actual, expected) def test_invalid_input(self): # Many of these tests are duplicated from # skbio.diversity.tests.test_base, but I think it's important to # confirm that they are being run when *unifrac is called. # tree has duplicated tip ids t = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU2:0.75):1.25):0.0)root;')) u_counts = [1, 2, 3] v_counts = [1, 1, 1] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(DuplicateNodeError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(DuplicateNodeError, weighted_unifrac, u_counts, v_counts, taxa, t) # unrooted tree as input t = TreeNode.read(StringIO('((OTU1:0.1, OTU2:0.2):0.3, OTU3:0.5,' 'OTU4:0.7);')) u_counts = [1, 2, 3] v_counts = [1, 1, 1] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(ValueError, weighted_unifrac, u_counts, v_counts, taxa, t) # taxa has duplicated ids t = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) u_counts = [1, 2, 3] v_counts = [1, 1, 1] taxa = ['OTU1', 'OTU2', 'OTU2'] self.assertRaises(ValueError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(ValueError, weighted_unifrac, u_counts, v_counts, taxa, t) # len of vectors not equal t = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) u_counts = [1, 2] v_counts = [1, 1, 1] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(ValueError, weighted_unifrac, u_counts, v_counts, taxa, t) u_counts = [1, 2, 3] v_counts = [1, 1] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(ValueError, weighted_unifrac, u_counts, v_counts, taxa, t) u_counts = [1, 2, 3] v_counts = [1, 1, 1] taxa = ['OTU1', 'OTU2'] self.assertRaises(ValueError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(ValueError, weighted_unifrac, u_counts, v_counts, taxa, t) # negative counts t = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) u_counts = [1, 2, -3] v_counts = [1, 1, 1] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(ValueError, weighted_unifrac, u_counts, v_counts, taxa, t) u_counts = [1, 2, 3] v_counts = [1, 1, -1] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(ValueError, weighted_unifrac, u_counts, v_counts, taxa, t) # tree with no branch lengths t = TreeNode.read( StringIO('((((OTU1,OTU2),OTU3)),(OTU4,OTU5));')) u_counts = [1, 2, 3] v_counts = [1, 1, 1] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(ValueError, weighted_unifrac, u_counts, v_counts, taxa, t) # tree missing some branch lengths t = TreeNode.read( StringIO('(((((OTU1,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) u_counts = [1, 2, 3] v_counts = [1, 1, 1] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(ValueError, weighted_unifrac, u_counts, v_counts, taxa, t) # taxa not present in tree t = TreeNode.read( StringIO('(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) u_counts = [1, 2, 3] v_counts = [1, 1, 1] taxa = ['OTU1', 'OTU2', 'OTU42'] self.assertRaises(MissingNodeError, unweighted_unifrac, u_counts, v_counts, taxa, t) self.assertRaises(MissingNodeError, weighted_unifrac, u_counts, v_counts, taxa, t) def test_unweighted_unifrac_non_overlapping(self): # these communities only share the root node actual = unweighted_unifrac( self.b1[4], self.b1[5], self.oids1, self.t1) expected = 1.0 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( [1, 1, 1, 0, 0], [0, 0, 0, 1, 1], self.oids1, self.t1) expected = 1.0 self.assertAlmostEqual(actual, expected) def test_unweighted_unifrac_zero_counts(self): actual = unweighted_unifrac( [1, 1, 1, 0, 0], [0, 0, 0, 0, 0], self.oids1, self.t1) expected = 1.0 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], self.oids1, self.t1) expected = 0.0 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( [], [], [], self.t1) expected = 0.0 self.assertAlmostEqual(actual, expected) def test_unweighted_unifrac(self): # expected results derived from QIIME 1.9.1, which # is a completely different implementation skbio's initial # unweighted unifrac implementation # sample A versus all actual = unweighted_unifrac( self.b1[0], self.b1[1], self.oids1, self.t1) expected = 0.238095238095 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[0], self.b1[1], self.oids1, self.t1, validate=False) self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[0], self.b1[2], self.oids1, self.t1) expected = 0.52 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[0], self.b1[3], self.oids1, self.t1) expected = 0.52 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[0], self.b1[4], self.oids1, self.t1) expected = 0.545454545455 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[0], self.b1[5], self.oids1, self.t1) expected = 0.619047619048 self.assertAlmostEqual(actual, expected) # sample B versus remaining actual = unweighted_unifrac( self.b1[1], self.b1[2], self.oids1, self.t1) expected = 0.347826086957 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[1], self.b1[3], self.oids1, self.t1) expected = 0.347826086957 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[1], self.b1[4], self.oids1, self.t1) expected = 0.68 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[1], self.b1[5], self.oids1, self.t1) expected = 0.421052631579 self.assertAlmostEqual(actual, expected) # sample C versus remaining actual = unweighted_unifrac( self.b1[2], self.b1[3], self.oids1, self.t1) expected = 0.0 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[2], self.b1[4], self.oids1, self.t1) expected = 0.68 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[2], self.b1[5], self.oids1, self.t1) expected = 0.421052631579 self.assertAlmostEqual(actual, expected) # sample D versus remaining actual = unweighted_unifrac( self.b1[3], self.b1[4], self.oids1, self.t1) expected = 0.68 self.assertAlmostEqual(actual, expected) actual = unweighted_unifrac( self.b1[3], self.b1[5], self.oids1, self.t1) expected = 0.421052631579 self.assertAlmostEqual(actual, expected) # sample E versus remaining actual = unweighted_unifrac( self.b1[4], self.b1[5], self.oids1, self.t1) expected = 1.0 self.assertAlmostEqual(actual, expected) def test_weighted_unifrac_identity(self): for i in range(len(self.b1)): actual = weighted_unifrac( self.b1[i], self.b1[i], self.oids1, self.t1) expected = 0.0 self.assertAlmostEqual(actual, expected) def test_weighted_unifrac_symmetry(self): for i in range(len(self.b1)): for j in range(len(self.b1)): actual = weighted_unifrac( self.b1[i], self.b1[j], self.oids1, self.t1) expected = weighted_unifrac( self.b1[j], self.b1[i], self.oids1, self.t1) self.assertAlmostEqual(actual, expected) def test_weighted_unifrac_non_overlapping(self): # expected results derived from QIIME 1.9.1, which # is a completely different implementation skbio's initial # weighted unifrac implementation # these communities only share the root node actual = weighted_unifrac( self.b1[4], self.b1[5], self.oids1, self.t1) expected = 4.0 self.assertAlmostEqual(actual, expected) def test_weighted_unifrac_zero_counts(self): actual = weighted_unifrac( [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], self.oids1, self.t1) expected = 0.0 self.assertAlmostEqual(actual, expected) # calculated the following by hand, as QIIME 1.9.1 tells the user # that values involving empty vectors will be uninformative, and # returns 1.0 actual = weighted_unifrac( [1, 1, 1, 0, 0], [0, 0, 0, 0, 0], self.oids1, self.t1) expected = 2.0 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( [], [], [], self.t1) expected = 0.0 self.assertAlmostEqual(actual, expected) def test_weighted_unifrac(self): # expected results derived from QIIME 1.9.1, which # is a completely different implementation skbio's initial # weighted unifrac implementation actual = weighted_unifrac( self.b1[0], self.b1[1], self.oids1, self.t1) expected = 2.4 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[0], self.b1[2], self.oids1, self.t1) expected = 1.86666666667 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[0], self.b1[3], self.oids1, self.t1) expected = 2.53333333333 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[0], self.b1[4], self.oids1, self.t1) expected = 1.35384615385 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[0], self.b1[5], self.oids1, self.t1) expected = 3.2 self.assertAlmostEqual(actual, expected) # sample B versus remaining actual = weighted_unifrac( self.b1[1], self.b1[2], self.oids1, self.t1) expected = 2.26666666667 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[1], self.b1[3], self.oids1, self.t1) expected = 0.933333333333 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[1], self.b1[4], self.oids1, self.t1) expected = 3.2 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[1], self.b1[5], self.oids1, self.t1) expected = 0.8375 self.assertAlmostEqual(actual, expected) # sample C versus remaining actual = weighted_unifrac( self.b1[2], self.b1[3], self.oids1, self.t1) expected = 1.33333333333 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[2], self.b1[4], self.oids1, self.t1) expected = 1.89743589744 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[2], self.b1[5], self.oids1, self.t1) expected = 2.66666666667 self.assertAlmostEqual(actual, expected) # sample D versus remaining actual = weighted_unifrac( self.b1[3], self.b1[4], self.oids1, self.t1) expected = 2.66666666667 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[3], self.b1[5], self.oids1, self.t1) expected = 1.33333333333 self.assertAlmostEqual(actual, expected) # sample E versus remaining actual = weighted_unifrac( self.b1[4], self.b1[5], self.oids1, self.t1) expected = 4.0 self.assertAlmostEqual(actual, expected) def test_weighted_unifrac_identity_normalized(self): for i in range(len(self.b1)): actual = weighted_unifrac( self.b1[i], self.b1[i], self.oids1, self.t1, normalized=True) expected = 0.0 self.assertAlmostEqual(actual, expected) def test_weighted_unifrac_symmetry_normalized(self): for i in range(len(self.b1)): for j in range(len(self.b1)): actual = weighted_unifrac( self.b1[i], self.b1[j], self.oids1, self.t1, normalized=True) expected = weighted_unifrac( self.b1[j], self.b1[i], self.oids1, self.t1, normalized=True) self.assertAlmostEqual(actual, expected) def test_weighted_unifrac_non_overlapping_normalized(self): # these communities only share the root node actual = weighted_unifrac( self.b1[4], self.b1[5], self.oids1, self.t1, normalized=True) expected = 1.0 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( [1, 1, 1, 0, 0], [0, 0, 0, 1, 1], self.oids1, self.t1, normalized=True) expected = 1.0 self.assertAlmostEqual(actual, expected) def test_weighted_unifrac_zero_counts_normalized(self): # expected results derived from QIIME 1.9.1, which # is a completely different implementation skbio's initial # weighted unifrac implementation actual = weighted_unifrac( [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], self.oids1, self.t1, normalized=True) expected = 0.0 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( [1, 1, 1, 0, 0], [0, 0, 0, 0, 0], self.oids1, self.t1, normalized=True) expected = 1.0 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( [], [], [], self.t1, normalized=True) expected = 0.0 self.assertAlmostEqual(actual, expected) def test_weighted_unifrac_normalized(self): # expected results derived from QIIME 1.9.1, which # is a completely different implementation skbio's initial # weighted unifrac implementation actual = weighted_unifrac( self.b1[0], self.b1[1], self.oids1, self.t1, normalized=True) expected = 0.6 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[0], self.b1[2], self.oids1, self.t1, normalized=True) expected = 0.466666666667 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[0], self.b1[3], self.oids1, self.t1, normalized=True) expected = 0.633333333333 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[0], self.b1[4], self.oids1, self.t1, normalized=True) expected = 0.338461538462 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[0], self.b1[5], self.oids1, self.t1, normalized=True) expected = 0.8 self.assertAlmostEqual(actual, expected) # sample B versus remaining actual = weighted_unifrac( self.b1[1], self.b1[2], self.oids1, self.t1, normalized=True) expected = 0.566666666667 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[1], self.b1[3], self.oids1, self.t1, normalized=True) expected = 0.233333333333 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[1], self.b1[4], self.oids1, self.t1, normalized=True) expected = 0.8 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[1], self.b1[5], self.oids1, self.t1, normalized=True) expected = 0.209375 self.assertAlmostEqual(actual, expected) # sample C versus remaining actual = weighted_unifrac( self.b1[2], self.b1[3], self.oids1, self.t1, normalized=True) expected = 0.333333333333 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[2], self.b1[4], self.oids1, self.t1, normalized=True) expected = 0.474358974359 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[2], self.b1[5], self.oids1, self.t1, normalized=True) expected = 0.666666666667 self.assertAlmostEqual(actual, expected) # sample D versus remaining actual = weighted_unifrac( self.b1[3], self.b1[4], self.oids1, self.t1, normalized=True) expected = 0.666666666667 self.assertAlmostEqual(actual, expected) actual = weighted_unifrac( self.b1[3], self.b1[5], self.oids1, self.t1, normalized=True) expected = 0.333333333333 self.assertAlmostEqual(actual, expected) # sample E versus remaining actual = weighted_unifrac( self.b1[4], self.b1[5], self.oids1, self.t1, normalized=True) expected = 1.0 self.assertAlmostEqual(actual, expected) def test_weighted_unifrac_branch_correction(self): # for ((a:1, b:2)c:3,(d:4,e:5)f:6)root;" tip_ds = np.array([4, 5, 10, 11, 0, 0, 0])[:, np.newaxis] u_counts = np.array([1, 1, 0, 0, 2, 0, 2]) v_counts = np.array([0, 2, 1, 0, 2, 1, 3]) u_sum = 2 # counts at the tips v_sum = 3 exp = np.array([2.0, 5.0 * (.5 + (2.0/3.0)), 10.0 * (1.0 / 3.0), 0.0]).sum() obs = _weighted_unifrac_branch_correction( tip_ds, u_counts/u_sum, v_counts/v_sum) self.assertEqual(obs, exp) def test_unweighted_unifrac_pycogent_adapted(self): # adapted from PyCogent unit tests m = np.array([[1, 0, 1], [1, 1, 0], [0, 1, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 1, 1], [0, 1, 1], [1, 1, 1]]) # lengths from ((a:1,b:2):4,(c:3,(d:1,e:1):2):3) bl = np.array([1, 2, 1, 1, 3, 2, 4, 3, 0], dtype=float) self.assertEqual(_unweighted_unifrac(m[:, 0], m[:, 1], bl), 10/16.0) self.assertEqual(_unweighted_unifrac(m[:, 0], m[:, 2], bl), 8/13.0) self.assertEqual(_unweighted_unifrac(m[:, 1], m[:, 2], bl), 8/17.0) def test_weighted_unifrac_pycogent_adapted(self): # lengths from ((a:1,b:2):4,(c:3,(d:1,e:1):2):3) bl = np.array([1, 2, 1, 1, 3, 2, 4, 3, 0], dtype=float) # adapted from PyCogent unit tests m = np.array([[1, 0, 1], # a [1, 1, 0], # b [0, 1, 0], # d [0, 0, 1], # e [0, 1, 0], # c [0, 1, 1], # parent of (d, e) [2, 1, 1], # parent of a, b [0, 2, 1], # parent of c (d, e) [2, 3, 2]]) # root # sum just the counts at the tips m0s = m[:5, 0].sum() m1s = m[:5, 1].sum() m2s = m[:5, 2].sum() # scores computed by educational implementation self.assertAlmostEqual( _weighted_unifrac(m[:, 0], m[:, 1], m0s, m1s, bl)[0], 7.5) self.assertAlmostEqual( _weighted_unifrac(m[:, 0], m[:, 2], m0s, m2s, bl)[0], 6.0) self.assertAlmostEqual( _weighted_unifrac(m[:, 1], m[:, 2], m1s, m2s, bl)[0], 4.5) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/tests/000077500000000000000000000000001520735541300226465ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/diversity/tests/__init__.py000066400000000000000000000005411520735541300247570ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/diversity/tests/test_block.py000066400000000000000000000202151520735541300253510ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt from skbio import TreeNode, DistanceMatrix from skbio.diversity import beta_diversity, block_beta_diversity from skbio.diversity._block import (_block_party, _generate_id_blocks, _pairs_to_compute, _block_compute, _block_kwargs, _map, _reduce) class BlockBetaDiversityTests(TestCase): def setUp(self): self.table1 = [[1, 5], [2, 3], [0, 1]] self.sids1 = list('ABC') self.tree1 = TreeNode.read([ '((O1:0.25, O2:0.50):0.25, O3:0.75)root;']) self.oids1 = ['O1', 'O2'] def test_block_beta_diversity(self): exp = beta_diversity('unweighted_unifrac', self.table1, self.sids1, tree=self.tree1, taxa=self.oids1) obs = block_beta_diversity('unweighted_unifrac', self.table1, self.sids1, taxa=self.oids1, tree=self.tree1, k=2) npt.assert_equal(obs.data, exp.data) self.assertEqual(obs.ids, exp.ids) def test_block_kwargs(self): kws = {'ids': [1, 2, 3, 4, 5], 'foo': 'bar', 'k': 2} exp = [{'row_ids': np.array((0, 1)), 'col_ids': np.array((0, 1)), 'id_pairs': [(0, 1)], 'ids': [1, 2, 3, 4, 5]}, {'row_ids': np.array((0, 1)), 'col_ids': np.array((2, 3)), 'id_pairs': [(0, 2), (0, 3), (1, 2), (1, 3)], 'ids': [1, 2, 3, 4, 5]}, {'row_ids': np.array((0, 1)), 'col_ids': np.array((4,)), 'id_pairs': [(0, 4), (1, 4)], 'ids': [1, 2, 3, 4, 5]}, {'row_ids': np.array((2, 3)), 'col_ids': np.array((2, 3)), 'id_pairs': [(2, 3), ], 'ids': [1, 2, 3, 4, 5]}, {'row_ids': np.array((2, 3)), 'col_ids': np.array((4,)), 'id_pairs': [(2, 4), (3, 4)], 'ids': [1, 2, 3, 4, 5]}] obs = list(_block_kwargs(**kws)) npt.assert_equal(obs, exp) def test_block_compute(self): def mock_metric(u, v): return (u + v).sum() counts = np.array([[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 0], [2, 3, 4, 5, 0, 1], [10, 2, 3, 6, 8, 2], [9, 9, 2, 2, 3, 4]]) kwargs = {'metric': mock_metric, 'counts': counts, 'row_ids': np.array((2, 3)), 'col_ids': np.array((4, )), 'id_pairs': [(2, 4), (3, 4)], 'ids': [1, 2, 3, 4, 5]} exp = DistanceMatrix(np.array([[0, 0, 44], [0, 0, 60], [44, 60, 0]]), (2, 3, 4)) obs = _block_compute(**kwargs) npt.assert_equal(obs.data, exp.data) self.assertEqual(obs.ids, exp.ids) def test_map(self): def func(a, b, c=5): return a + b + c kwargs = [{'a': 0, 'b': 1, 'c': 0}, {'a': 2, 'b': 3}] exp = [1, 10] obs = list(_map(func, kwargs)) self.assertEqual(obs, exp) def test_reduce(self): dm1 = DistanceMatrix(np.array([[0, 0, 44], [0, 0, 60], [44, 60, 0]]), (2, 3, 4)) dm2 = DistanceMatrix(np.array([[0, 123], [123, 0]]), (1, 5)) dm3 = DistanceMatrix(np.array([[0, 1, 2, 3], [1, 0, 4, 5], [2, 4, 0, 6], [3, 5, 6, 0]]), (0, 3, 4, 5)) exp = DistanceMatrix(np.array([[0, 0, 0, 1, 2, 3], [0, 0, 0, 0, 0, 123], [0, 0, 0, 0, 44, 0], [1, 0, 0, 0, 64, 5], [2, 0, 44, 64, 0, 6], [3, 123, 0, 5, 6, 0]]), list(range(6))) obs = _reduce([dm1, dm2, dm3]) npt.assert_equal(obs.data, exp.data) self.assertEqual(obs.ids, exp.ids) def test_generate_id_blocks(self): ids = [1, 2, 3, 4, 5] exp = [(np.array((0, 1)), np.array((0, 1))), (np.array((0, 1)), np.array((2, 3))), (np.array((0, 1)), np.array((4,))), (np.array((2, 3)), np.array((2, 3))), (np.array((2, 3)), np.array((4,))), (np.array((4,)), np.array((4,)))] obs = list(_generate_id_blocks(ids, 2)) npt.assert_equal(obs, exp) def test_block_party_notree(self): counts = np.arange(15).reshape(5, 3) exp = [{'counts': np.array([[0, 1, 2], [3, 4, 5]]), 'ids': np.array([0, 1])}, {'counts': np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]), 'ids': np.array([0, 1, 2, 3])}, {'counts': np.array([[0, 1, 2], [3, 4, 5], [12, 13, 14]]), 'ids': np.array([0, 1, 4])}, {'counts': np.array([[6, 7, 8], [9, 10, 11]]), 'ids': np.array([2, 3])}, {'counts': np.array([[6, 7, 8], [9, 10, 11], [12, 13, 14]]), 'ids': np.array([2, 3, 4])}, {'counts': np.array([[12, 13, 14]]), 'ids': np.array([4])}] obs = [_block_party(counts, rids, cids) for rids, cids in _generate_id_blocks(list(range(5)), 2)] npt.assert_equal(obs, exp) def test_block_party_tree(self): counts = np.array([[1, 1, 1], [1, 0, 1], [1, 0, 1], [0, 0, 1], [0, 1, 1]]) tree = TreeNode.read(['(a:1,b:2,c:3);']) taxa = ['a', 'b', 'c'] kw = {'tree': tree, 'taxa': taxa} kw_no_a = {'tree': tree.shear(['b', 'c']), 'taxa': ['b', 'c']} kw_no_b = {'tree': tree.shear(['a', 'c']), 'taxa': ['a', 'c']} # python >= 3.5 supports {foo: bar, **baz} exp = [dict(counts=np.array([[1, 1, 1], [1, 0, 1]]), **kw), dict(counts=np.array([[1, 1, 1], [1, 0, 1], [1, 0, 1], [0, 0, 1]]), **kw), dict(counts=np.array([[1, 1, 1], [1, 0, 1], [0, 1, 1]]), **kw), dict(counts=np.array([[1, 1], [0, 1]]), **kw_no_b), dict(counts=np.array([[1, 0, 1], [0, 0, 1], [0, 1, 1]]), **kw), dict(counts=np.array([[1, 1]]), **kw_no_a)] obs = [_block_party(counts, rids, cids, **kw) for rids, cids in _generate_id_blocks(list(range(5)), 2)] for okw, ekw in zip(obs, exp): npt.assert_equal(okw['counts'], ekw['counts']) npt.assert_equal(okw['taxa'], ekw['taxa']) self.assertEqual(str(okw['tree']), str(ekw['tree'])) def test_pairs_to_compute_rids_are_cids(self): rids = np.array([0, 1, 2, 10]) cids = rids exp = [(0, 1), (0, 2), (0, 10), (1, 2), (1, 10), (2, 10)] self.assertEqual(_pairs_to_compute(rids, cids), exp) def test_pairs_to_compute_rids_are_not_cids(self): rids = np.array([0, 1, 2]) cids = np.array([3, 4, 5]) exp = [(0, 3), (0, 4), (0, 5), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)] self.assertEqual(_pairs_to_compute(rids, cids), exp) def test_pairs_to_compute_rids_overlap_cids(self): rids = np.array([0, 1, 2]) cids = np.array([0, 10, 20]) with self.assertRaises(ValueError): _pairs_to_compute(rids, cids) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/tests/test_driver.py000066400000000000000000001242431520735541300255600ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io import warnings from unittest import TestCase, main import pandas as pd import numpy as np import numpy.testing as npt from skbio import DistanceMatrix, TreeNode from skbio.table import Table, example_table from skbio.util._testing import assert_series_almost_equal from skbio.diversity import ( alpha_diversity, beta_diversity, partial_beta_diversity, get_alpha_diversity_metrics, get_beta_diversity_metrics, ) from skbio.diversity.alpha import faith_pd, phydiv, sobs from skbio.diversity.beta import unweighted_unifrac, weighted_unifrac from skbio.tree import DuplicateNodeError, MissingNodeError from skbio.diversity._driver import ( _qualitative_metrics, _pdist_metrics, ) class AlphaDiversityTests(TestCase): def setUp(self): self.table1 = np.array([[1, 3, 0, 1, 0], [0, 2, 0, 4, 4], [0, 0, 6, 2, 1], [0, 0, 1, 1, 1]]) self.sids1 = list('ABCD') self.oids1 = ['OTU%d' % i for i in range(1, 6)] self.tree1 = TreeNode.read(io.StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):' '0.0,(OTU4:0.75,OTU5:0.75):1.25):0.0)root;')) self.table2 = np.array([[1, 3], [0, 2], [0, 0]]) self.sids2 = list('xyz') self.oids2 = ['OTU1', 'OTU5'] self.tree2 = TreeNode.read(io.StringIO( '(((((OTU1:42.5,OTU2:0.5):0.5,OTU3:1.0):1.0):' '0.0,(OTU4:0.75,OTU5:0.0001):1.25):0.0)root;')) def test_invalid_input(self): # number of ids doesn't match the number of samples self.assertRaises(ValueError, alpha_diversity, 'sobs', self.table1, list('ABC')) # unknown metric provided self.assertRaises(ValueError, alpha_diversity, 'not-a-metric', self.table1) # 3-D list provided as input self.assertRaises(ValueError, alpha_diversity, 'sobs', [[[43]]]) # negative counts self.assertRaises(ValueError, alpha_diversity, 'sobs', [0, 3, -12, 42]) # additional kwargs self.assertRaises(TypeError, alpha_diversity, 'sobs', [0, 1], not_a_real_kwarg=42.0) self.assertRaises(TypeError, alpha_diversity, 'faith_pd', [0, 1], tree=self.tree1, taxa=['OTU1', 'OTU2'], not_a_real_kwarg=42.0) self.assertRaises(TypeError, alpha_diversity, faith_pd, [0, 1], tree=self.tree1, taxa=['OTU1', 'OTU2'], not_a_real_kwarg=42.0) def test_invalid_input_phylogenetic(self): # taxa not provided self.assertRaises(ValueError, alpha_diversity, 'faith_pd', self.table1, list('ABC'), tree=self.tree1) # tree not provided self.assertRaises(ValueError, alpha_diversity, 'faith_pd', self.table1, list('ABC'), taxa=self.oids1) # tree has duplicated tip ids t = TreeNode.read( io.StringIO( '(((((OTU2:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(DuplicateNodeError, alpha_diversity, 'faith_pd', counts, taxa=taxa, tree=t) # unrooted tree as input t = TreeNode.read(io.StringIO( '((OTU1:0.1, OTU2:0.2):0.3, OTU3:0.5,OTU4:0.7);')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, alpha_diversity, 'faith_pd', counts, taxa=taxa, tree=t) # taxa has duplicated ids t = TreeNode.read( io.StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU2:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU2'] self.assertRaises(ValueError, alpha_diversity, 'faith_pd', counts, taxa=taxa, tree=t) # count and OTU vectors are not equal length t = TreeNode.read( io.StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU2:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2'] self.assertRaises(ValueError, alpha_diversity, 'faith_pd', counts, taxa=taxa, tree=t) t = TreeNode.read( io.StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU2:0.75):1.25):0.0)root;')) counts = [1, 2] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, alpha_diversity, 'faith_pd', counts, taxa=taxa, tree=t) # tree with no branch lengths t = TreeNode.read( io.StringIO('((((OTU1,OTU2),OTU3)),(OTU4,OTU5));')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, alpha_diversity, 'faith_pd', counts, taxa=taxa, tree=t) # tree missing some branch lengths t = TreeNode.read( io.StringIO('(((((OTU1,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, alpha_diversity, 'faith_pd', counts, taxa=taxa, tree=t) # some taxa not present in tree t = TreeNode.read( io.StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU42'] self.assertRaises(MissingNodeError, alpha_diversity, 'faith_pd', counts, taxa=taxa, tree=t) # table has correct taxa but are overridden by wrong ones table = Table(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), ['OTU1', 'OTU2', 'OTU3'], ['S1', 'S2', 'S3']) self.assertRaises(MissingNodeError, alpha_diversity, 'faith_pd', table, taxa=taxa, tree=t) def test_empty(self): # empty vector actual = alpha_diversity('sobs', np.array([], dtype=np.int64)) expected = pd.Series([0], dtype=np.int64) assert_series_almost_equal(actual, expected) # array of empty vector actual = alpha_diversity('sobs', np.array([[]], dtype=np.int64)) expected = pd.Series([0], dtype=np.int64) assert_series_almost_equal(actual, expected) # array of empty vectors actual = alpha_diversity('sobs', np.array([[], []], dtype=np.int64)) expected = pd.Series([0, 0], dtype=np.int64) assert_series_almost_equal(actual, expected) # empty vector actual = alpha_diversity('faith_pd', np.array([], dtype=np.int64), tree=self.tree1, taxa=[]) expected = pd.Series([0.]) assert_series_almost_equal(actual, expected) # array of empty vector actual = alpha_diversity('faith_pd', np.array([[]], dtype=np.int64), tree=self.tree1, taxa=[]) expected = pd.Series([0.]) assert_series_almost_equal(actual, expected) # array of empty vectors actual = alpha_diversity('faith_pd', np.array([[], []], dtype=np.int64), tree=self.tree1, taxa=[]) expected = pd.Series([0., 0.]) assert_series_almost_equal(actual, expected) # empty Table actual = alpha_diversity('sobs', Table(np.array([[]]), [], ['S1', ])) actual.index = pd.RangeIndex(len(actual)) expected = pd.Series([0], dtype=np.int64) assert_series_almost_equal(actual, expected) def test_single_count_vector(self): actual = alpha_diversity('sobs', np.array([1, 0, 2])) expected = pd.Series([2], dtype=np.int64) assert_series_almost_equal(actual, expected) actual = alpha_diversity('faith_pd', np.array([1, 3, 0, 1, 0]), tree=self.tree1, taxa=self.oids1) self.assertAlmostEqual(actual[0], 4.5) def test_input_types(self): list_result = alpha_diversity('sobs', [1, 3, 0, 1, 0]) array_result = alpha_diversity('sobs', np.array([1, 3, 0, 1, 0])) table_result = alpha_diversity( 'sobs', Table(np.array([[1, 3, 0, 1, 0], ]).T, list('ABCDE'), ['S1', ])) # using a table we get sample IDs for free, drop them for the test table_result.index = pd.RangeIndex(len(table_result)) self.assertAlmostEqual(list_result[0], 3) assert_series_almost_equal(list_result, array_result) assert_series_almost_equal(table_result, array_result) list_result = alpha_diversity('faith_pd', [1, 3, 0, 1, 0], tree=self.tree1, taxa=self.oids1) array_result = alpha_diversity('faith_pd', np.array([1, 3, 0, 1, 0]), tree=self.tree1, taxa=self.oids1) table_result = alpha_diversity('faith_pd', Table(np.array([[1, 3, 0, 1, 0], ]).T, self.oids1, ['S1', ]), tree=self.tree1) # using a table we get sample IDs for free, drop them for the test table_result.index = pd.RangeIndex(len(table_result)) self.assertAlmostEqual(list_result[0], 4.5) assert_series_almost_equal(list_result, array_result) assert_series_almost_equal(table_result, array_result) def test_sobs(self): # expected values hand-calculated expected = pd.Series([3, 3, 3, 3], index=self.sids1, dtype=np.int64) actual = alpha_diversity('sobs', self.table1, self.sids1) assert_series_almost_equal(actual, expected) # function passed instead of string actual = alpha_diversity(sobs, self.table1, self.sids1) assert_series_almost_equal(actual, expected) # alt input table expected = pd.Series([2, 1, 0], index=self.sids2, dtype=np.int64) actual = alpha_diversity('sobs', self.table2, self.sids2) assert_series_almost_equal(actual, expected) def test_faith_pd(self): # calling faith_pd through alpha_diversity gives same results as # calling it directly expected = [] for e in self.table1: expected.append(faith_pd(e, tree=self.tree1, taxa=self.oids1)) expected = pd.Series(expected) actual = alpha_diversity('faith_pd', self.table1, tree=self.tree1, taxa=self.oids1) assert_series_almost_equal(actual, expected) # alt input table and tree expected = [] for e in self.table2: expected.append(faith_pd(e, tree=self.tree2, taxa=self.oids2)) expected = pd.Series(expected) actual = alpha_diversity('faith_pd', self.table2, tree=self.tree2, taxa=self.oids2) assert_series_almost_equal(actual, expected) def test_phydiv(self): expected = [] for e in self.table1: expected.append(phydiv(e, tree=self.tree1, taxa=self.oids1)) expected = pd.Series(expected) actual = alpha_diversity('phydiv', self.table1, tree=self.tree1, taxa=self.oids1) assert_series_almost_equal(actual, expected) expected = [] for e in self.table1: expected.append(phydiv(e, tree=self.tree1, taxa=self.oids1, rooted=False)) expected = pd.Series(expected) actual = alpha_diversity('phydiv', self.table1, tree=self.tree1, taxa=self.oids1, rooted=False) assert_series_almost_equal(actual, expected) expected = [] for e in self.table1: expected.append(phydiv(e, tree=self.tree1, taxa=self.oids1, weight=True)) expected = pd.Series(expected) actual = alpha_diversity('phydiv', self.table1, tree=self.tree1, taxa=self.oids1, weight=True) assert_series_almost_equal(actual, expected) def test_no_ids(self): # expected values hand-calculated expected = pd.Series([3, 3, 3, 3], dtype=np.int64) actual = alpha_diversity('sobs', self.table1) assert_series_almost_equal(actual, expected) def test_optimized(self): # calling optimized faith_pd gives same results as calling unoptimized # version optimized = alpha_diversity('faith_pd', self.table1, tree=self.tree1, taxa=self.oids1) unoptimized = alpha_diversity(faith_pd, self.table1, tree=self.tree1, taxa=self.oids1) assert_series_almost_equal(optimized, unoptimized) class BetaDiversityTests(TestCase): def setUp(self): self.table1 = [[1, 5], [2, 3], [0, 1]] self.sids1 = list('ABC') self.tree1 = TreeNode.read(io.StringIO( '((O1:0.25, O2:0.50):0.25, O3:0.75)root;')) self.oids1 = ['O1', 'O2'] self.table2 = [[23, 64, 14, 0, 0, 3, 1], [0, 3, 35, 42, 0, 12, 1], [0, 5, 5, 0, 40, 40, 0], [44, 35, 9, 0, 1, 0, 0], [0, 2, 8, 0, 35, 45, 1], [0, 0, 25, 35, 0, 19, 0]] self.sids2 = list('ABCDEF') self.table3 = [[23, 64, 14, 0, 0, 3, 1], [0, 3, 35, 42, 0, 12, 1], [0, 5, 5, 0, 40, 40, 0], [44, 35, 9, 0, 1, 0, 0], [0, 2, 8, 0, 35, 45, 1], [0, 0, 25, 35, 0, 19, 0], [88, 31, 0, 5, 5, 5, 5], [44, 39, 0, 0, 0, 0, 0]] def test_available_metrics(self): for metric in _pdist_metrics: try: beta_diversity(metric, self.table3) except Exception as exc: raise ValueError( f'Metric {metric} failed with exception:\n {exc}') def test_use_of_dataframe_index(self): '''reference to issue 1808''' df1 = pd.DataFrame(self.table1, index=self.sids1) df2 = pd.DataFrame(self.table2, index=self.sids2) matrix1 = beta_diversity('jaccard', df1) matrix2 = beta_diversity('jaccard', df2) self.assertEqual(self.sids1, list(matrix1.to_data_frame().index)) self.assertEqual(self.sids2, list(matrix2.to_data_frame().index)) def test_qualitative_bug_issue_1549(self): as_presence_absence = np.asarray(self.table3) > 0 for metric in _pdist_metrics: obs_mat = beta_diversity(metric, self.table3) obs_presence_absence = beta_diversity(metric, as_presence_absence) if metric in _qualitative_metrics: self.assertEqual(obs_mat, obs_presence_absence) else: self.assertNotEqual(obs_mat, obs_presence_absence) def test_invalid_input(self): # number of ids doesn't match the number of samples msg = "Input table has 3 samples whereas 2 sample IDs were provided." with self.assertRaises(ValueError) as cm: beta_diversity('euclidean', self.table1, list('AB')) self.assertEqual(str(cm.exception), msg) # unknown metric provided error_msg = r"not-a-metric" with self.assertRaisesRegex(ValueError, error_msg): beta_diversity('not-a-metric', self.table1) # 3-D list provided as input msg = "`counts` has 3 dimensions whereas up to 2 dimensions are allowed." with self.assertRaises(ValueError) as cm: beta_diversity('euclidean', [[[43]]]) self.assertEqual(str(cm.exception), msg) # negative counts error_msg = r"negative values." with self.assertRaisesRegex(ValueError, error_msg): beta_diversity('euclidean', [[0, 1, 3, 4], [0, 3, -12, 42]]) with self.assertRaisesRegex(ValueError, error_msg): beta_diversity('euclidean', [[0, 1, 3, -4], [0, 3, 12, 42]]) # additional kwargs error_msg = r"argument" with self.assertRaisesRegex(TypeError, error_msg): beta_diversity('euclidean', [[0, 1, 3], [0, 3, 12]], not_a_real_kwarg=42.0) with self.assertRaisesRegex(TypeError, error_msg): beta_diversity('unweighted_unifrac', [[0, 1, 3], [0, 3, 12]], not_a_real_kwarg=42.0, tree=self.tree1, taxa=['O1', 'O2', 'O3']) with self.assertRaisesRegex(TypeError, error_msg): beta_diversity('weighted_unifrac', [[0, 1, 3], [0, 3, 12]], not_a_real_kwarg=42.0, tree=self.tree1, taxa=['O1', 'O2', 'O3']) with self.assertRaisesRegex(TypeError, error_msg): beta_diversity(weighted_unifrac, [[0, 1, 3], [0, 3, 12]], not_a_real_kwarg=42.0, tree=self.tree1, taxa=['O1', 'O2', 'O3']) # non-matching id or taxon counts msg = "Input table has 3 samples whereas 2 sample IDs were provided." with self.assertRaises(ValueError) as cm: beta_diversity('euclidean', example_table, ids=['foo', 'bar']) self.assertEqual(str(cm.exception), msg) msg = "Input table has 2 features whereas 3 feature IDs were provided." with self.assertRaises(ValueError) as cm: beta_diversity(weighted_unifrac, example_table, taxa=['foo', 'bar', 'qux'], tree=self.tree1) self.assertEqual(str(cm.exception), msg) # non-matching taxa and tree msg = "2 taxa are not present as tip names in the tree." with self.assertRaises(MissingNodeError) as cm: beta_diversity(weighted_unifrac, example_table, taxa=['foo', 'bar'], tree=self.tree1) self.assertEqual(str(cm.exception), msg) def test_invalid_input_mahalanobis(self): error_msg = (r"requires more samples than features") with self.assertRaisesRegex(ValueError, error_msg): beta_diversity('mahalanobis', self.table2) def test_invalid_input_phylogenetic(self): # taxa not provided self.assertRaises(ValueError, beta_diversity, 'weighted_unifrac', self.table1, list('ABC'), tree=self.tree1) self.assertRaises(ValueError, beta_diversity, 'unweighted_unifrac', self.table1, list('ABC'), tree=self.tree1) # tree not provided self.assertRaises(ValueError, beta_diversity, 'weighted_unifrac', self.table1, list('ABC'), taxa=self.oids1) self.assertRaises(ValueError, beta_diversity, 'unweighted_unifrac', self.table1, list('ABC'), taxa=self.oids1) # tree has duplicated tip ids t = TreeNode.read( io.StringIO( '(((((OTU2:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(DuplicateNodeError, beta_diversity, 'weighted_unifrac', counts, taxa=taxa, tree=t) self.assertRaises(DuplicateNodeError, beta_diversity, 'unweighted_unifrac', counts, taxa=taxa, tree=t) # unrooted tree as input t = TreeNode.read(io.StringIO('((OTU1:0.1, OTU2:0.2):0.3, OTU3:0.5,' 'OTU4:0.7);')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, beta_diversity, 'weighted_unifrac', counts, taxa=taxa, tree=t) self.assertRaises(ValueError, beta_diversity, 'unweighted_unifrac', counts, taxa=taxa, tree=t) # taxa has duplicated ids t = TreeNode.read( io.StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU2:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU2'] self.assertRaises(ValueError, beta_diversity, 'weighted_unifrac', counts, taxa=taxa, tree=t) self.assertRaises(ValueError, beta_diversity, 'unweighted_unifrac', counts, taxa=taxa, tree=t) # count and OTU vectors are not equal length t = TreeNode.read( io.StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU2:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2'] self.assertRaises(ValueError, beta_diversity, 'weighted_unifrac', counts, taxa=taxa, tree=t) self.assertRaises(ValueError, beta_diversity, 'unweighted_unifrac', counts, taxa=taxa, tree=t) t = TreeNode.read( io.StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU2:0.75):1.25):0.0)root;')) counts = [1, 2] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, beta_diversity, 'weighted_unifrac', counts, taxa=taxa, tree=t) self.assertRaises(ValueError, beta_diversity, 'unweighted_unifrac', counts, taxa=taxa, tree=t) # tree with no branch lengths t = TreeNode.read( io.StringIO('((((OTU1,OTU2),OTU3)),(OTU4,OTU5));')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, beta_diversity, 'weighted_unifrac', counts, taxa=taxa, tree=t) self.assertRaises(ValueError, beta_diversity, 'unweighted_unifrac', counts, taxa=taxa, tree=t) # tree missing some branch lengths t = TreeNode.read( io.StringIO('(((((OTU1,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU3'] self.assertRaises(ValueError, beta_diversity, 'weighted_unifrac', counts, taxa=taxa, tree=t) self.assertRaises(ValueError, beta_diversity, 'unweighted_unifrac', counts, taxa=taxa, tree=t) # some taxa not present in tree t = TreeNode.read( io.StringIO( '(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:' '0.75,OTU5:0.75):1.25):0.0)root;')) counts = [1, 2, 3] taxa = ['OTU1', 'OTU2', 'OTU42'] self.assertRaises(MissingNodeError, beta_diversity, 'weighted_unifrac', counts, taxa=taxa, tree=t) self.assertRaises(MissingNodeError, beta_diversity, 'unweighted_unifrac', counts, taxa=taxa, tree=t) def test_empty(self): # array of empty vectors actual = beta_diversity('euclidean', np.array([[], []], dtype=np.int64), ids=['a', 'b']) expected_dm = DistanceMatrix([[0.0, 0.0], [0.0, 0.0]], ['a', 'b']) npt.assert_array_equal(actual, expected_dm) actual = beta_diversity('unweighted_unifrac', np.array([[], []], dtype=np.int64), ids=['a', 'b'], tree=self.tree1, taxa=[]) expected_dm = DistanceMatrix([[0.0, 0.0], [0.0, 0.0]], ['a', 'b']) self.assertEqual(actual, expected_dm) actual = beta_diversity('unweighted_unifrac', Table(np.array([[], []]).T, [], ['a', 'b']), tree=self.tree1) expected_dm = DistanceMatrix([[0.0, 0.0], [0.0, 0.0]], ['a', 'b']) self.assertEqual(actual, expected_dm) def test_input_types(self): actual_array = beta_diversity('euclidean', np.array([[1, 5], [2, 3]]), ids=['a', 'b']) actual_list = beta_diversity('euclidean', [[1, 5], [2, 3]], ids=['a', 'b']) actual_table = beta_diversity('euclidean', Table(np.array([[1, 5], [2, 3]]).T, ['O1', 'O2'], ['a', 'b'])) self.assertEqual(actual_array, actual_list) self.assertEqual(actual_array, actual_table) def test_euclidean(self): # TODO: update npt.assert_almost_equal calls to use DistanceMatrix # near-equality testing when that support is available actual_dm = beta_diversity('euclidean', self.table1, self.sids1) self.assertEqual(actual_dm.shape, (3, 3)) npt.assert_almost_equal(actual_dm['A', 'A'], 0.0) npt.assert_almost_equal(actual_dm['B', 'B'], 0.0) npt.assert_almost_equal(actual_dm['C', 'C'], 0.0) npt.assert_almost_equal(actual_dm['A', 'B'], 2.23606798) npt.assert_almost_equal(actual_dm['B', 'A'], 2.23606798) npt.assert_almost_equal(actual_dm['A', 'C'], 4.12310563) npt.assert_almost_equal(actual_dm['C', 'A'], 4.12310563) npt.assert_almost_equal(actual_dm['B', 'C'], 2.82842712) npt.assert_almost_equal(actual_dm['C', 'B'], 2.82842712) actual_dm = beta_diversity('euclidean', self.table2, self.sids2) expected_data = [ [0., 80.8455317, 84.0297566, 36.3042697, 86.0116271, 78.9176786], [80.8455317, 0., 71.0844568, 74.4714710, 69.3397433, 14.422205], [84.0297566, 71.0844568, 0., 77.2851861, 8.3066238, 60.7536007], [36.3042697, 74.4714710, 77.2851861, 0., 78.7908624, 70.7389567], [86.0116271, 69.3397433, 8.3066238, 78.7908624, 0., 58.4807660], [78.9176786, 14.422205, 60.7536007, 70.7389567, 58.4807660, 0.]] expected_dm = DistanceMatrix(expected_data, self.sids2) for id1 in self.sids2: for id2 in self.sids2: npt.assert_almost_equal(actual_dm[id1, id2], expected_dm[id1, id2], 6) def test_braycurtis(self): # TODO: update npt.assert_almost_equal calls to use DistanceMatrix # near-equality testing when that support is available actual_dm = beta_diversity('braycurtis', self.table1, self.sids1) self.assertEqual(actual_dm.shape, (3, 3)) npt.assert_almost_equal(actual_dm['A', 'A'], 0.0) npt.assert_almost_equal(actual_dm['B', 'B'], 0.0) npt.assert_almost_equal(actual_dm['C', 'C'], 0.0) npt.assert_almost_equal(actual_dm['A', 'B'], 0.27272727) npt.assert_almost_equal(actual_dm['B', 'A'], 0.27272727) npt.assert_almost_equal(actual_dm['A', 'C'], 0.71428571) npt.assert_almost_equal(actual_dm['C', 'A'], 0.71428571) npt.assert_almost_equal(actual_dm['B', 'C'], 0.66666667) npt.assert_almost_equal(actual_dm['C', 'B'], 0.66666667) actual_dm = beta_diversity('braycurtis', self.table2, self.sids2) expected_data = [ [0., 0.78787879, 0.86666667, 0.30927835, 0.85714286, 0.81521739], [0.78787879, 0., 0.78142077, 0.86813187, 0.75, 0.1627907], [0.86666667, 0.78142077, 0., 0.87709497, 0.09392265, 0.71597633], [0.30927835, 0.86813187, 0.87709497, 0., 0.87777778, 0.89285714], [0.85714286, 0.75, 0.09392265, 0.87777778, 0., 0.68235294], [0.81521739, 0.1627907, 0.71597633, 0.89285714, 0.68235294, 0.]] expected_dm = DistanceMatrix(expected_data, self.sids2) for id1 in self.sids2: for id2 in self.sids2: npt.assert_almost_equal(actual_dm[id1, id2], expected_dm[id1, id2], 6) def test_unweighted_unifrac(self): # TODO: update npt.assert_almost_equal calls to use DistanceMatrix # near-equality testing when that support is available # expected values calculated by hand dm1 = beta_diversity('unweighted_unifrac', self.table1, self.sids1, taxa=self.oids1, tree=self.tree1) dm2 = beta_diversity(unweighted_unifrac, self.table1, self.sids1, taxa=self.oids1, tree=self.tree1) self.assertEqual(dm1.shape, (3, 3)) self.assertEqual(dm1, dm2) expected_data = [[0.0, 0.0, 0.25], [0.0, 0.0, 0.25], [0.25, 0.25, 0.0]] expected_dm = DistanceMatrix(expected_data, ids=self.sids1) for id1 in self.sids1: for id2 in self.sids1: npt.assert_almost_equal(dm1[id1, id2], expected_dm[id1, id2], 6) def test_weighted_unifrac(self): # TODO: update npt.assert_almost_equal calls to use DistanceMatrix # near-equality testing when that support is available # expected values calculated by hand dm1 = beta_diversity('weighted_unifrac', self.table1, self.sids1, taxa=self.oids1, tree=self.tree1) dm2 = beta_diversity(weighted_unifrac, self.table1, self.sids1, taxa=self.oids1, tree=self.tree1) self.assertEqual(dm1.shape, (3, 3)) self.assertEqual(dm1, dm2) expected_data = [ [0.0, 0.1750000, 0.12499999], [0.1750000, 0.0, 0.3000000], [0.12499999, 0.3000000, 0.0]] expected_dm = DistanceMatrix(expected_data, ids=self.sids1) for id1 in self.sids1: for id2 in self.sids1: npt.assert_almost_equal(dm1[id1, id2], expected_dm[id1, id2], 6) def test_weighted_unifrac_normalized(self): # TODO: update npt.assert_almost_equal calls to use DistanceMatrix # near-equality testing when that support is available # expected values calculated by hand dm1 = beta_diversity('weighted_unifrac', self.table1, self.sids1, taxa=self.oids1, tree=self.tree1, normalized=True) dm2 = beta_diversity(weighted_unifrac, self.table1, self.sids1, taxa=self.oids1, tree=self.tree1, normalized=True) self.assertEqual(dm1.shape, (3, 3)) self.assertEqual(dm1, dm2) expected_data = [ [0.0, 0.128834, 0.085714], [0.128834, 0.0, 0.2142857], [0.085714, 0.2142857, 0.0]] expected_dm = DistanceMatrix(expected_data, ids=self.sids1) for id1 in self.sids1: for id2 in self.sids1: npt.assert_almost_equal(dm1[id1, id2], expected_dm[id1, id2], 6) def test_scipy_kwargs(self): # confirm that p can be passed to SciPy's minkowski, and that it # gives a different result than not passing it (the off-diagonal # entries are not equal). dm1 = beta_diversity('minkowski', self.table1, self.sids1) dm2 = beta_diversity('minkowski', self.table1, self.sids1, p=42.0) for id1 in self.sids1: for id2 in self.sids1: if id1 != id2: self.assertNotEqual(dm1[id1, id2], dm2[id1, id2]) def test_alt_pairwise_func(self): # confirm that pairwise_func is actually being used def not_a_real_pdist(counts, metric): return [[0.0, 42.0], [42.0, 0.0]] dm1 = beta_diversity('unweighted_unifrac', self.table1, taxa=self.oids1, tree=self.tree1, pairwise_func=not_a_real_pdist) expected = DistanceMatrix([[0.0, 42.0], [42.0, 0.0]]) self.assertEqual(dm1, expected) dm1 = beta_diversity('weighted_unifrac', self.table1, taxa=self.oids1, tree=self.tree1, pairwise_func=not_a_real_pdist) expected = DistanceMatrix([[0.0, 42.0], [42.0, 0.0]]) self.assertEqual(dm1, expected) dm1 = beta_diversity(unweighted_unifrac, self.table1, taxa=self.oids1, tree=self.tree1, pairwise_func=not_a_real_pdist) expected = DistanceMatrix([[0.0, 42.0], [42.0, 0.0]]) self.assertEqual(dm1, expected) dm1 = beta_diversity("euclidean", self.table1, pairwise_func=not_a_real_pdist) expected = DistanceMatrix([[0.0, 42.0], [42.0, 0.0]]) self.assertEqual(dm1, expected) def test_callable_unifrac_warns(self): # Passing the unifrac callables should warn that a faster string-keyed # implementation is available (see issue #1342). for func in (unweighted_unifrac, weighted_unifrac): with self.assertWarnsRegex(UserWarning, func.__name__): beta_diversity(func, self.table1, taxa=self.oids1, tree=self.tree1) def test_string_unifrac_does_not_warn(self): # The recommended string form should not emit the slow-callable warning. for name in ("unweighted_unifrac", "weighted_unifrac"): with warnings.catch_warnings(): warnings.simplefilter("error", UserWarning) beta_diversity(name, self.table1, taxa=self.oids1, tree=self.tree1) def test_custom_callable_does_not_warn(self): # Callables whose __name__ is not in the slow-callables set should # not trigger the slow-callable warning. def custom_metric(u, v): return 0.0 with warnings.catch_warnings(): warnings.simplefilter("error", UserWarning) beta_diversity(custom_metric, self.table1, self.sids1) def test_callable_without_taxa_param(self): # Callables that do not declare a 'taxa' parameter must not have # taxa injected into their kwargs, even when taxa is provided. def no_taxa_metric(u, v): return 0.0 dm = beta_diversity(no_taxa_metric, self.table1, self.sids1, taxa=self.oids1) self.assertEqual(dm.shape, (3, 3)) class MetricGetters(TestCase): def test_get_alpha_diversity_metrics(self): m = get_alpha_diversity_metrics() # basic sanity checks self.assertTrue('faith_pd' in m) self.assertTrue('chao1' in m) def test_get_alpha_diversity_metrics_sorted(self): m = get_alpha_diversity_metrics() n = sorted(list(m)) self.assertEqual(m, n) def test_get_beta_diversity_metrics(self): m = get_beta_diversity_metrics() # basic sanity checks self.assertTrue('unweighted_unifrac' in m) self.assertTrue('weighted_unifrac' in m) def test_get_beta_diversity_metrics_sorted(self): m = get_beta_diversity_metrics() n = sorted(list(m)) self.assertEqual(m, n) class TestPartialBetaDiversity(TestCase): def setUp(self): self.table1 = [[1, 5], [2, 3], [0, 1]] self.sids1 = list('ABC') self.tree1 = TreeNode.read(io.StringIO( '((O1:0.25, O2:0.50):0.25, O3:0.75)root;')) self.oids1 = ['O1', 'O2'] self.table2 = [[23, 64, 14, 0, 0, 3, 1], [0, 3, 35, 42, 0, 12, 1], [0, 5, 5, 0, 40, 40, 0], [44, 35, 9, 0, 1, 0, 0], [0, 2, 8, 0, 35, 45, 1], [0, 0, 25, 35, 0, 19, 0]] self.sids2 = list('ABCDEF') def test_id_pairs_as_iterable(self): id_pairs = iter([('B', 'C'), ]) dm = partial_beta_diversity('unweighted_unifrac', self.table1, self.sids1, taxa=self.oids1, tree=self.tree1, id_pairs=id_pairs) self.assertEqual(dm.shape, (3, 3)) expected_data = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.25], [0.0, 0.25, 0.0]] expected_dm = DistanceMatrix(expected_data, ids=self.sids1) for id1 in self.sids1: for id2 in self.sids1: npt.assert_almost_equal(dm[id1, id2], expected_dm[id1, id2], 6) # pass in iter(foo) def test_unweighted_unifrac_partial(self): # TODO: update npt.assert_almost_equal calls to use DistanceMatrix # near-equality testing when that support is available # expected values calculated by hand dm = partial_beta_diversity('unweighted_unifrac', self.table1, self.sids1, taxa=self.oids1, tree=self.tree1, id_pairs=[('B', 'C'), ]) self.assertEqual(dm.shape, (3, 3)) expected_data = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.25], [0.0, 0.25, 0.0]] expected_dm = DistanceMatrix(expected_data, ids=self.sids1) for id1 in self.sids1: for id2 in self.sids1: npt.assert_almost_equal(dm[id1, id2], expected_dm[id1, id2], 6) def test_weighted_unifrac_partial_full(self): # TODO: update npt.assert_almost_equal calls to use DistanceMatrix # near-equality testing when that support is available # expected values calculated by hand dm1 = partial_beta_diversity('weighted_unifrac', self.table1, self.sids1, taxa=self.oids1, tree=self.tree1, id_pairs=[('A', 'B'), ('A', 'C'), ('B', 'C')]) dm2 = beta_diversity('weighted_unifrac', self.table1, self.sids1, taxa=self.oids1, tree=self.tree1) self.assertEqual(dm1.shape, (3, 3)) self.assertEqual(dm1, dm2) expected_data = [ [0.0, 0.1750000, 0.12499999], [0.1750000, 0.0, 0.3000000], [0.12499999, 0.3000000, 0.0]] expected_dm = DistanceMatrix(expected_data, ids=self.sids1) for id1 in self.sids1: for id2 in self.sids1: npt.assert_almost_equal(dm1[id1, id2], expected_dm[id1, id2], 6) def test_self_self_pair(self): error_msg = (r"A duplicate or a self-self pair was observed.") with self.assertRaisesRegex(ValueError, error_msg): partial_beta_diversity((lambda x, y: x + y), self.table1, self.sids1, id_pairs=[('A', 'B'), ('A', 'A')]) def test_duplicate_pairs(self): # confirm that partial pairwise execution fails if duplicate pairs are # observed error_msg = (r"A duplicate or a self-self pair was observed.") with self.assertRaisesRegex(ValueError, error_msg): partial_beta_diversity((lambda x, y: x + y), self.table1, self.sids1, id_pairs=[('A', 'B'), ('A', 'B')]) def test_duplicate_transpose_pairs(self): # confirm that partial pairwise execution fails if a transpose # duplicate is observed error_msg = (r"A duplicate or a self-self pair was observed.") with self.assertRaisesRegex(ValueError, error_msg): partial_beta_diversity((lambda x, y: x + y), self.table1, self.sids1, id_pairs=[('A', 'B'), ('A', 'B')]) def test_pairs_not_subset(self): # confirm raise when pairs are not a subset of IDs error_msg = (r"`id_pairs` are not a subset of `ids`") with self.assertRaisesRegex(ValueError, error_msg): partial_beta_diversity((lambda x, y: x + y), self.table1, self.sids1, id_pairs=[('x', 'b'), ]) def test_euclidean(self): # confirm that pw execution through partial is identical def euclidean(u, v, **kwargs): return np.sqrt(((u - v)**2).sum()) id_pairs = [('A', 'B'), ('B', 'F'), ('D', 'E')] actual_dm = partial_beta_diversity(euclidean, self.table2, self.sids2, id_pairs=id_pairs) actual_dm = DistanceMatrix(actual_dm, self.sids2) expected_data = [ [0., 80.8455317, 0., 0., 0., 0.], [80.8455317, 0., 0., 0., 0., 14.422205], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 78.7908624, 0.], [0., 0., 0., 78.7908624, 0., 0.], [0., 14.422205, 0., 0., 0., 0.]] expected_dm = DistanceMatrix(expected_data, self.sids2) for id1 in self.sids2: for id2 in self.sids2: npt.assert_almost_equal(actual_dm[id1, id2], expected_dm[id1, id2], 6) def test_unusable_metric(self): id_pairs = [('A', 'B'), ('B', 'F'), ('D', 'E')] error_msg = r"partial_beta_diversity is only compatible" with self.assertRaisesRegex(ValueError, error_msg): partial_beta_diversity('hamming', self.table2, self.sids2, id_pairs=id_pairs) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/diversity/tests/test_util.py000066400000000000000000000146661520735541300252510ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import pandas as pd import numpy.testing as npt from skbio import TreeNode from skbio.diversity._util import ( vectorize_counts_and_tree, _validate_counts_vector, _validate_counts_matrix, _qualify_counts, ) from skbio.tree import DuplicateNodeError, MissingNodeError class VectorizeTests(TestCase): def test_vectorize_counts_and_tree(self): tree = TreeNode.read(["((a:1, b:2)c:3)root;"]) counts = np.array([[0, 1], [1, 5], [10, 1]]) count_array, indexed, branch_lengths = \ vectorize_counts_and_tree(counts, np.array(['a', 'b']), tree) exp_counts = np.array([[0, 1, 10], [1, 5, 1], [1, 6, 11], [1, 6, 11]]) npt.assert_equal(count_array, exp_counts.T) class ValidationTests(TestCase): def test_validate_counts_vector(self): # python list obs = _validate_counts_vector([0, 2, 1, 3]) npt.assert_array_equal(obs, np.array([0, 2, 1, 3])) self.assertEqual(obs.dtype, int) # numpy array (no copy made) data = np.array([0, 2, 1, 3]) obs = _validate_counts_vector(data) npt.assert_array_equal(obs, data) self.assertEqual(obs.dtype, int) self.assertTrue(obs is data) # single element obs = _validate_counts_vector([42]) npt.assert_array_equal(obs, np.array([42])) self.assertEqual(obs.dtype, int) self.assertEqual(obs.shape, (1,)) # keep float obs = _validate_counts_vector([42.2, 42.7, 0]) npt.assert_array_equal(obs, np.array([42.2, 42.7, 0])) self.assertEqual(obs.dtype, float) # cast into int obs = _validate_counts_vector([42.2, 42.7, 0], cast_int=True) npt.assert_array_equal(obs, np.array([42, 42, 0])) self.assertEqual(obs.dtype, int) # all zeros obs = _validate_counts_vector([0, 0, 0]) npt.assert_array_equal(obs, np.array([0, 0, 0])) self.assertEqual(obs.dtype, int) # all zeros (single value) obs = _validate_counts_vector([0]) npt.assert_array_equal(obs, np.array([0])) self.assertEqual(obs.dtype, int) def test_validate_counts_vector_invalid_input(self): # wrong data type (strings) with self.assertRaises(ValueError): _validate_counts_vector(['a', 'b', 'c']) # wrong data type (complex numbers) with self.assertRaises(ValueError): _validate_counts_vector([1 + 2j, 3 + 4j]) # wrong number of dimensions (2-D) with self.assertRaises(ValueError): _validate_counts_vector([[0, 2, 1, 3], [4, 5, 6, 7]]) # wrong number of dimensions (scalar) with self.assertRaises(ValueError): _validate_counts_vector(1) # negative values with self.assertRaises(ValueError): _validate_counts_vector([0, 0, 2, -1, 3]) # strings with self.assertRaises(ValueError): _validate_counts_vector([0, 0, 'a', -1, 3]) def test_validate_counts_matrix(self): # basic valid input (n=2) obs = _validate_counts_matrix([[0, 1, 1, 0, 2], [0, 0, 2, 1, 3]]) npt.assert_array_equal(obs[0], np.array([0, 1, 1, 0, 2])) npt.assert_array_equal(obs[1], np.array([0, 0, 2, 1, 3])) # basic valid input (n=3) obs = _validate_counts_matrix([[0, 1, 1, 0, 2], [0, 0, 2, 1, 3], [1, 1, 1, 1, 1]]) npt.assert_array_equal(obs[0], np.array([0, 1, 1, 0, 2])) npt.assert_array_equal(obs[1], np.array([0, 0, 2, 1, 3])) npt.assert_array_equal(obs[2], np.array([1, 1, 1, 1, 1])) # empty counts vectors obs = _validate_counts_matrix(np.array([[], []], dtype=int)) npt.assert_array_equal(obs[0], np.array([])) npt.assert_array_equal(obs[1], np.array([])) def test_validate_counts_matrix_pandas(self): obs = _validate_counts_matrix(pd.DataFrame([[0, 1, 1, 0, 2], [0, 0, 2, 1, 3], [1, 1, 1, 1, 1]])) npt.assert_array_equal(obs[0], np.array([0, 1, 1, 0, 2])) npt.assert_array_equal(obs[1], np.array([0, 0, 2, 1, 3])) npt.assert_array_equal(obs[2], np.array([1, 1, 1, 1, 1])) def test_validate_counts_matrix_cast_int(self): obs = _validate_counts_matrix( [[42.2, 42.1, 0], [42.2, 42.1, 1.0]], cast_int=True) npt.assert_array_equal(obs[0], np.array([42, 42, 0])) npt.assert_array_equal(obs[1], np.array([42, 42, 1])) self.assertEqual(obs[0].dtype, int) self.assertEqual(obs[1].dtype, int) def test_validate_counts_matrix_negative_counts(self): with self.assertRaises(ValueError): _validate_counts_matrix([[0, 1, 1, 0, 2], [0, 0, 2, -1, 3]]) with self.assertRaises(ValueError): _validate_counts_matrix([[0, 0, 2, -1, 3], [0, 1, 1, 0, 2]]) def test_validate_counts_matrix_unequal_lengths(self): with self.assertRaises(ValueError): _validate_counts_matrix([[0], [0, 0], [9, 8]]) with self.assertRaises(ValueError): _validate_counts_matrix([[0, 0], [0, 0, 8], [9, 8]]) with self.assertRaises(ValueError): _validate_counts_matrix([[0, 0, 75], [0, 0, 3], [9, 8, 22, 44]]) def test_validate_counts_matrix_invalid_input(self): with self.assertRaises(ValueError): _validate_counts_matrix([['a', 'b', 'c']]) with self.assertRaises(ValueError): _validate_counts_matrix([[1 + 2j, 3 + 4j]]) def test_qualify_counts(self): counts = np.array([[0, 1], [1, 5], [10, 1]]) exp = np.array([[False, True], [True, True], [True, True]]) obs = _qualify_counts(counts) npt.assert_equal(obs, exp) counts = np.array([[0, 0, 0], [1, 0, 42]]) exp = np.array([[False, False, False], [True, False, True]]) obs = _qualify_counts(counts) npt.assert_equal(obs, exp) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/embedding/000077500000000000000000000000001520735541300214005ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/embedding/__init__.py000066400000000000000000000033051520735541300235120ustar00rootroot00000000000000r"""Biological Embeddings (:mod:`skbio.embedding`) ================================================= .. currentmodule:: skbio.embedding This module provides support for storing embeddings for biological objects, such as protein embeddings outputted from protein language models (pLMs). Embedding types --------------- .. autosummary:: :toctree: generated/ Embedding SequenceEmbedding ProteinEmbedding Embedding vector types ---------------------- .. autosummary:: :toctree: generated/ EmbeddingVector SequenceVector ProteinVector Embedding vector utilities -------------------------- .. autosummary:: :toctree: generated/ embed_vec_to_numpy embed_vec_to_distances embed_vec_to_ordination embed_vec_to_dataframe """ # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._embedding import ( Embedding, SequenceEmbedding, EmbeddingVector, SequenceVector, embed_vec_to_numpy, embed_vec_to_distances, embed_vec_to_ordination, embed_vec_to_dataframe, ) from ._protein import ProteinEmbedding, ProteinVector, example_protein_embedding __all__ = [ "Embedding", "SequenceEmbedding", "EmbeddingVector", "SequenceVector", "embed_vec_to_numpy", "embed_vec_to_distances", "embed_vec_to_ordination", "embed_vec_to_dataframe", "ProteinEmbedding", "ProteinVector", "example_protein_embedding", ] scikit-bio-scikit-bio-a3beaa6/skbio/embedding/_embedding.py000066400000000000000000000253401520735541300240330ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np import pandas as pd from scipy.linalg import svd from skbio.sequence import Sequence from skbio._base import SkbioObject from skbio.stats.ordination import OrdinationResults from skbio.diversity import beta_diversity from skbio.io.descriptors import Read, Write def _repr_helper(rstr, org_name, new_name, dim_name, regex_match, shape): rstr = rstr.replace(org_name, new_name) n_indent = 4 # see Sequence.__repr__ indent = " " * n_indent rstr = rstr.replace( regex_match, f"{dim_name} dimension: {shape}\n{indent}has gaps", ) return rstr class Embedding(SkbioObject): r"""Embedding for a biological object. Parameters ---------- embedding : array_like Embedding matrix where the first axis is indexed by `ids`. ids : array_like IDs of biological objects. """ read = Read() write = Write() @property def embedding(self): r"""The embedding tensor.""" return self._embedding @property def ids(self): r"""IDs corresponding to each row of the embedding.""" # each embedding row corresponds to an id return self._ids def __init__(self, embedding, ids, **kwargs): # make sure that the embedding has the same length as the sequence ids_len = len(ids) if embedding.shape[0] != ids_len: raise ValueError( f"The embedding ({embedding.shape[0]}) must have the " f"same length as the ids ({ids_len})." ) self._embedding = np.asarray(embedding) self._ids = np.asarray(ids) def __str__(self): raise NotImplementedError("This method should be implemented by subclasses.") def bytes(self): r"""Bytes representation of string encoding.""" seq = np.frombuffer(str(self).encode("ascii"), dtype=np.uint8) return seq class SequenceEmbedding(Embedding): r"""Embedding for a biological sequence. Parameters ---------- embedding : array_like The embedding of the sequence. Row vectors correspond to the latent character coordinates. sequence : str, Sequence, or 1D ndarray Characters representing the sequence itself. See Also -------- Embedding skbio.sequence.Sequence """ def __init__(self, embedding, sequence, **kwargs): if isinstance(sequence, Sequence): sequence = str(sequence) if isinstance(sequence, str): sequence = sequence.encode("ascii") seq = np.frombuffer(sequence, dtype=np.uint8) super(SequenceEmbedding, self).__init__(embedding, seq, **kwargs) def __str__(self): r"""String representation of the underlying sequence.""" return str(self._ids.tobytes().decode("ascii")) @property def sequence(self): r"""String representation of the underlying sequence.""" return str(self) def __repr__(self): r"""Return a string representation of the SequenceEmbedding object. Returns ------- str String representation of the SequenceEmbedding object. See Also -------- skbio.sequence.Protein """ seq = Sequence(self.sequence) rstr = _repr_helper( repr(seq), "Sequence", "SequenceEmbedding", "embedding", regex_match="length", shape=self.embedding.shape[1], ) return rstr class EmbeddingVector(Embedding): r"""Vector representation for a biological entity. Parameters ---------- vector : 1D or 2D array_like The vector representation of the sequence. Typically a 1D array. Can also be a 2D array with only one row. sequence : str, Sequence, or 1D ndarray Characters representing the sequence itself. See Also -------- Embedding """ def __init__(self, vector, obj, **kwargs): super(EmbeddingVector, self).__init__(vector, obj, **kwargs) def __str__(self): return self._ids[0].decode("ascii") @property def vector(self): r"""Vector representation for the biological entity.""" return self._embedding.squeeze() @property def embedding(self): r"""The embedding tensor.""" return self._embedding.reshape(1, -1) class SequenceVector(EmbeddingVector): r"""Vector representation for a biological sequence. Parameters ---------- vector : 1D or 2D array_like The vector representation of the sequence. Typically a 1D array. Can also be a 2D array with only one row. sequence : str, Sequence, or 1D ndarray Characters representing the sequence itself. See Also -------- EmbeddingVector skbio.sequence.Sequence """ def __init__(self, vector, sequence, **kwargs): vector = np.atleast_2d(vector) if vector.shape[0] != 1: raise ValueError("Only one vector per sequence is allowed.") if isinstance(sequence, Sequence): sequence = str(sequence) if isinstance(sequence, str): sequence = sequence.encode("ascii") sequence = np.array([sequence], dtype="O") super(SequenceVector, self).__init__(vector, sequence, **kwargs) @property def sequence(self): r"""String representation of the underlying sequence.""" return str(self) def __repr__(self): r"""Return a string representation of the SequenceVector object. Returns ------- str A string representation of the SequenceVector object. See Also -------- skbio.sequence.Sequence """ seq = Sequence(str(self)) rstr = _repr_helper( repr(seq), "Sequence", "SequenceVector", "vector", regex_match="length", shape=self.embedding.shape[1], ) return rstr def embed_vec_to_numpy(vectors, validate=True): r"""Convert an iterable of EmbeddingVector objects to a NumPy array. Parameters ---------- vectors : iterable of EmbeddingVector objects An iterable of EmbeddingVector objects, or objects that subclass EmbeddingVector. validate : bool, optional If ``True``, validate that all vectors have the same length and are valid types. Returns ------- ndarray of shape (n_objects, n_features) A NumPy array where n_features corresponds to the dimensionality of the latent space. Raises ------ ValueError If the vectors do not have the same length. """ if validate: subcls = [issubclass(type(ev), EmbeddingVector) for ev in vectors] if not all(subcls): raise ValueError( "Input iterable contains objects that " "do not subclass EmbeddingVector." ) types = [type(ev) for ev in vectors] if not all(t == types[0] for t in types): raise ValueError("All objects must be of the same type.") lens = [len(ev.vector) for ev in vectors] if not all(ln == lens[0] for ln in lens): raise ValueError("All vectors must have the same length.") data = np.vstack([ev.vector for ev in vectors]) return data def embed_vec_to_distances(vectors, metric="euclidean", validate=True): r"""Convert EmbeddingVector objects to a DistanceMatrix object. Parameters ---------- vectors : iterable of EmbeddingVector objects An iterable of EmbeddingVector objects, or objects that subclass EmbeddingVector. metric : str or callable, optional The distance metric to use. Must be a valid metric for ``scipy.spatial.distance.pdist``. validate : bool, optional If ``True``, validate that all vectors have the same length and are valid types. Returns ------- DistanceMatrix A distance matrix representing pairwise distances among objects calculated by the given metric. See Also -------- skbio.stats.distance.DistanceMatrix """ data = embed_vec_to_numpy(vectors, validate=validate) ids = [str(ev) for ev in vectors] return beta_diversity(metric, data, ids) def embed_vec_to_ordination(vectors, validate=True): r"""Convert EmbeddingVector objects to an Ordination object. A singular value decomposition (SVD) is performed on the data. Parameters ---------- vectors : iterable of EmbeddingVector objects An iterable of EmbeddingVector objects, or objects that subclass EmbeddingVector. validate : bool, optional If ``True``, validate that all vectors have the same length and are valid types. Returns ------- OrdinationResults Ordination results with objects as samples and latent variables as features. See Also -------- skbio.stats.ordination.OrdinationResults """ data = embed_vec_to_numpy(vectors, validate=validate) u, s, vh = svd(data, full_matrices=False) eigvals = s**2 short_name = "SVD" long_name = "Singular Value Decomposition" # note that we are moving half of the singular values # in the eigvals to the samples and the other half to the features # this is to help with the interpretation of the ordination # if visualizing with biplots ordr = OrdinationResults( short_method_name=short_name, long_method_name=long_name, eigvals=eigvals, proportion_explained=eigvals / eigvals.sum(), samples=pd.DataFrame(u @ np.diag(s), index=[str(ev) for ev in vectors]), features=pd.DataFrame(vh.T, index=range(data.shape[1])), ) return ordr def embed_vec_to_dataframe(vectors, validate=True): r"""Convert a list of SequenceVector objects to a pandas DataFrame. Parameters ---------- vectors : iterable of EmbeddingVector objects An iterable of EmbeddingVector objects, or objects that subclass EmbeddingVector. validate : bool, optional If ``True``, validate that all vectors have the same length and are valid types. Returns ------- pd.DataFrame Data frame containing the embedding vectors as rows (index) and object IDs as columns. See Also -------- pd.DataFrame """ data = embed_vec_to_numpy(vectors, validate=validate) return pd.DataFrame(data, index=[str(ev) for ev in vectors]) scikit-bio-scikit-bio-a3beaa6/skbio/embedding/_protein.py000066400000000000000000000125101520735541300235700ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np import pandas as pd from skbio.sequence import Protein from skbio.stats.ordination import OrdinationResults from skbio.embedding._embedding import SequenceEmbedding, SequenceVector, _repr_helper def _validate_protein(sequence): if isinstance(sequence, Protein): sequence = str(sequence) elif isinstance(sequence, str): if " " in sequence: sequence = sequence.replace(" ", "") # perform a check to make sure the sequence is a valid protein sequence _ = Protein(sequence) return sequence class ProteinEmbedding(SequenceEmbedding): r"""Embedding of a protein sequence. Parameters ---------- embedding : array_like The embedding of the protein sequence. Row vectors correspond to the latent residues coordinates. sequence : str, Protein, or 1D ndarray Characters representing the protein sequence itself. clip_head : bool, optional If ``True``, then the first row of the embedding will be removed. Some language models specify start tokens, and this parameter can be used to account for this. clip_tail : bool, optional If ``True``, then the last row of the embedding will be removed. Some language models specify end tokens, and this parameter can be used to account for this. See Also -------- skbio.sequence.Protein Examples -------- >>> from skbio.embedding import ProteinEmbedding >>> import numpy as np >>> embedding = np.random.rand(10, 3) >>> sequence = "ACDEFGHIKL" >>> ProteinEmbedding(embedding, sequence) ProteinEmbedding -------------------------- Stats: length: 10 embedding dimension: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 ACDEFGHIKL """ default_write_format = "embed" """Default write format for this object: ``embed``.""" def __init__(self, embedding, sequence, clip_head=False, clip_tail=False, **kwargs): embedding = np.asarray(embedding) if clip_head: embedding = embedding[1:] if clip_tail: embedding = embedding[:-1] sequence = _validate_protein(sequence) super(ProteinEmbedding, self).__init__( embedding=embedding, sequence=sequence, **kwargs ) @property def residues(self): r"""Array containing underlying residue characters.""" return self._ids.view("|S1") def __repr__(self): r"""Return a string representation of the ProteinEmbedding object. Returns ------- str String representation of the ProteinEmbedding object. See Also -------- skbio.sequence.Protein """ seq = Protein(str(self)) rstr = _repr_helper( repr(seq), "Protein", "ProteinEmbedding", "embedding", regex_match="has gaps", shape=self.embedding.shape[1], ) return rstr example_protein_embedding = ProteinEmbedding( np.random.default_rng(0).normal(size=(62, 1024)), "IGKEEIQQRLAQFVDHWKELKQLAAARGQRLEESLEYQQFVANVEEEEAWINEKMTLVASED", ) class ProteinVector(SequenceVector): r"""Vector representation for a protein sequence. Parameters ---------- vector : 1D or 2D array_like The vector representation of the protein sequence. Typically a 1D array. Can also be a 2D array with only one row. sequence : str, Sequence, or 1D ndarray Characters representing the protein sequence itself. See Also -------- SequenceVector skbio.sequence.Protein Examples -------- >>> from skbio.embedding import ProteinVector >>> import numpy as np >>> vector = np.random.rand(10) >>> sequence = "ACDEFGHIKL" >>> ProteinVector(vector, sequence) ProteinVector -------------------------- Stats: length: 10 vector dimension: 10 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 ACDEFGHIKL """ default_write_format = "embed" """Default write format for this object: ``embed``.""" def __init__(self, vector, sequence: str, **kwargs): sequence = _validate_protein(sequence) super(ProteinVector, self).__init__(vector, sequence=sequence, **kwargs) def __repr__(self): r"""Return a string representation of the ProteinVector object. Returns ------- str String representation of the ProteinEmbedding object. See Also -------- skbio.sequence.Protein """ seq = Protein(str(self)) rstr = _repr_helper( repr(seq), "Protein", "ProteinVector", "vector", regex_match="has gaps", shape=self.embedding.shape[1], ) return rstr scikit-bio-scikit-bio-a3beaa6/skbio/embedding/tests/000077500000000000000000000000001520735541300225425ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/embedding/tests/__init__.py000066400000000000000000000005411520735541300246530ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/embedding/tests/data/000077500000000000000000000000001520735541300234535ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/embedding/tests/data/embed1.txt.npy000066400000000000000000007602001520735541300261630ustar00rootroot00000000000000“NUMPYv{'descr': 'Ö:J¼û/W½Ð0½ž½*¾t@¾8Ýí¼¬w>É#§>B…b>ñÄM= �Ѿ‡~ž>È™^>˜ë¥½\UN½ZL½%ب¾R³§>¿MÚ½&ß½ƒ`½ôß½ ºº#–2¾g®§>­P�=‹Ý£>8G[=™í¾Ø»f>Eù¾Ñß±½iœÄ¾Ƀ½ @==•°³¾ì~¦=å‰à>ЍÕ<—î>Ÿja½ä}M>ì >ýŽ7`ý½qß2=ïv¢¾kñ¾ÅVÚ>+a¥=úî€=éW>‰T¾2Ë=Å Œ¾aݦ½ù-´¾ª/(>òXô½o$K=@ÈN¾Ï÷@>]Y¨½8uu=§Þ8½Ñèx<éGª¾Ë´Y¾—'¾Ä��>F %=)ê=ï‹=A¶>®R¨>"¾ñJº½ûàP>Lzç=Žª‚>»õ¡¾Mü“¾öaP>[HE>c[=öJ2:R´¾ÛØt;Û¤]¾šó=òõo>™~ξU 0¾œ^¾¶Š >þ/Ù;„¥û=¡‰“¾r1S>ÀM>t±�=«Ò°=»Î\>9æž¾£‹=·ƒ> t¾Ùʰ½¤“¼Í�›¾�ˉ=ºo =¡-½â²¤¾¥¿>¶ÓÞª´E>ó:<UÓ=4¤&>|{ñð>H~›½rói>ÎÒ<•>Ct¾Ô‡=ú¦‚»6Ý»ïP„=öX”½Fø§¾=Â�½9é…>AŽS¾ª±u>“P¾;`æ>w½­>*æÚ¾ï² ¾9ÉØ¼ªÚ½þ-;¾ÂŸ˜¾:¾°¾ )E>óÃy=Ò»=÷#Ÿ>Ja ½w ‹½Ÿ—>Sh€¾?&¾Y¸¦½!é7¾ºIf½™Ê½(šv>ôŸs=óÎ>{/9¾ ¹�>/Ü >^>®'=îµ¾!�±¾Ï&?gbͽŸÉ<–¢½”™=Cc¾€È‹¾Â ¾ k¹¾ye>¬jN:p¬|>ƒ¡à< í¬º ê(=hø˜½¡€Œ¾=h ¾Â_ë½x¯>MHµ<õ„¾w½Å³ =,ˆª¼rì½=@ž>ª„>%Al½w·½½OêÅ=i¡¾V’f½¦Åâ¾µ�¾ Ôþ=†1ˆ¾©ǽ”c¾>çL\¾�>óLW¾‰”>픦¾Õ=Ƽ>_mM½ð¡¬¾ƾ:ÄÜ»>în¾Gÿª½RmÁ½¬äN½b G>ømº>4ó½‡Ã">®‘H½èÍO¾rÍ¢=u¬Ç½>—ß< m½ç_¢=¹±>й>š6>æfj¾é‡*¾nk¾“p>¡¡½‘ô�> ¾Ç>¼èÙ½�Aß>í}¥¾¢œ>>8«{¾õn > Øœ¾š¾Evn>bÂÓ=(>¾¹€º¡éû½x`¹½z¹m¾2{Ÿ¾´]µ¾Ó1¾iW¾×L*½aǾ…B ¾ –ê½ `–=¤È½ÿ´+<ó…{=ô×ö=¯,̾Bèp½�®>Û›M>‘tD¾CmÊ=öîh>S >;�o½cÙM½~î »¥­ ¾kr¾)=8>ƒÍšºö)l>u?Fƒµ>^$�>ÎCؾ«u1>H»€<´¾¹=K¹=ióI>‘G{=Pð’¼³%¾Óê+¾Ì,†=d”ƒ=‰óç¼äŒ= ¢\¾ ÅŠ>ߨ ¾Zè¹=-o[½6>kÉœ½2¤�¾Ò�Ë>ö»c=¿é;½‡S>­�;²·½Êº†<’Þª¼WÌG<øZm=æ „½Å, =Ùc•>î�½ÂŒ>ÞÀò½øù=½[-=É|ƒ½¾d ¼*‚¼ì@O< Ü–= )>ŠåÕ½¬1y¾þù*=•<§¾"û³>LM7¾Rý(>Ð65>Û•+>6Ü´½îž¾ë¨ä½"¸>åN‚¾0×$¾ ™=B­¤=é‘ý=a1]¾¨X>>M$`=ÑW†¾I«¾ðä§;Ú¶¼&[©>*²á»y–É= ½½8¾©§Ò=TëÉ>ôq’=a\c¾ 5r9z)>øg>�˜�>`Œ�<$>'>ãͽ€{=."­¾ 6>û<¾‰õâ>¯o¾ýVsË¿(=úF½LÕ‚¾×¾ =Ñ­ˆ=aË@>þ{½Žt”¼²å½=3Cp<“¾Í·¾Jè>]T¼àýÂ<¿”˜>ÍS¿¶wC¾%->? ¼µÞ=Iå>ß7¾�º>Œ!޽·Eç½Ú/p>8�>WL>ÊÕ˜½Ež> á ½^�A½{€T>Cþà=d8½fŸ=IǽqÔ-=‘¶Èç½Q½.w>¢ž ½Š]™¼¥ )¾Wj>x¢?PfÔ½ÂO~½Æbƒ>ò’y:ºu›½›u0>Ce>Mž> ŠÆ¾Ž�¾¸oš¾Zg�>Ї>ù½)¨>'û€½8>#=é˼>üD}>öÚ…>Âæ7¾,>!=…p¾ùNþE¦q½oð·½<† ¾a�„½\ÿè=¦ì¾Œv½�4>¼Ä*¾ËAo½!&=’¸J¾I�¾Yv¸<Ãp¡¾óΆ¾þر=(ø•=6¿Ü¼ÉÕð½NE�¾à¸¹;÷<õ½�Ý–½èH¾×æ¼<¿´>q�r¼e#8>…¾å*Ë<Ë%§¾þúß½œÜ¾¬ç-¾Åq�=w䓾‡¼€ôk¾z]ñ=æ=.á;Bq)>ãU½¼"¦�>W¿vŒP¼ª*�= ‡)>Î*ê¼ ýмܧà¼8½¿Áº½sèô½gï³¾VB˜<ÈSü2,ë½®ÝÑ=Ã#·>†@“>;’#>ý¿§Ãʽ ¾óEv= ¾âH¯½ 禼 Îš=¨‚½¸Y>�40=Èxu=àØ©=8?L= W>™‘…>j¾ò|å½øm">l�=7'É>†Å= –¾6®>xðÖ<)Û‰¾ì™‹>ª¹ð=ÊT>6Þ>¿Fͽ:yø¼]ÿJ¾ 2Ý=«»Š;W›=!$?9»‘¾FÀ¾¹HÐ>çøÂ>zÍÞ=»3 ¾¸ù¹>ì꽌ì3=X©½�¤V½N,F>k ‡¾÷²m¾2°¶¾¹s¥¾™Ä ½_:Ó=*ðW>òš2>Ó¾Ób¼¾Ö—>¾\¦�¾ö²É>‡d¾¸`U½:þ´¾–—'=r->Õ¶›½C²½ü,Z½+"->ॾ¾fî¼ÿ ³;Ô0‰<Ä÷*>×Û=Xø?<¾X¾Ì¾D='ËŸ=Î¥ ?Én'¿”.�¾I·š¾!7_=ò2¾Kß’=T�™½Z�»è_ò»¥“=*¥=Ï™A½ús¾ã¦>Ä…½Ò$î½u£¼¾®äc=0ѽ$ªI¾ñ”ì>tt">j¯$=�_F>3l6=°¹�<Ý–»9Òz½’κ=¯�;�v¸áµ¢½ãÈ–¾CÌ>vx1¾®¸>X;a>íý§½±{ü½Æ™¾üsò=hñ=ÁŠ´<€í™>`ç½GWé=7À]½ç!A>³a—¾¥ö ¾S? ½*tQ=¼ýÓ¾ 6 >aJq¾¿,<û!L=VEš>o =WGö½( ¾_^�¾§ÞP=iIQ¾ i:¼Óï¸=(N>)þ½Ùe€>]Ô„¼pH¾"÷½öGß½�J½Y[È=J9Û¼EË€¾Bɽf9²½ qÿ= Ü5¾•%>i%Ê=‚œ‚>P‘,<°ñоÑn¾¶® =K?Z¾®ì�¾˜>Fµ¾==CX¾¡àT¾PðC¾fýϼúhí½Ak³=Œ¾‚¾à]~<|�U>¯–‚>ƒô=,Ó…=ðëY¼��à½ò 1¾CŒƒ=�ôx¾Êö�=�½ê'Ñ=Ïêļ—'‹½OÃ=¾åŠé=I%¾R·@�÷1>cDc½wä >´Gì¼ÌŠ>�„¾~ôË=nDø>®ù’¾ €>73Ê=Œ@>O 7½e—½¢…¾ë˜ý¼käè¾½´V=óò™=�ì8>Ð;:¸>yõ=’ÿ…½fÉýÔð¼c…]¾òQÝ=Ø g>/ª¾=‚>Õm¾ƒüw>ßÕ=�2˜>yû=h‡=äà?ídó½?oF={e¾šüä¼z>R>iG$½ëz>½bã¾¢Œ<=ü¾>0@«=…»¾`=¤õ >TÍÚ½ý'Á½ˆ–C¾÷IÓ½wE�¾sžš¾°Îʽ9ƒ°=ôÑS;®Ø>:‚=ÚBK>@È>´HÝ>ɲP½\ÜØ=�ï8¡½ È>~ÿt½!áh½¯·Ü=¢>™AN>ÿé—½³�¤=zê=i Ò»qà«=s`=½ø…­>T=h>F==ʶÓ<:½q¾¯)•;Ðãb=p™>aÂ¥;Ñ=©¼à�Å=ÄØêM'•@¤½uÜ>ùXt=<“ï;™.—½ &'¾yŸ4¾ÚŒ;½S!Ô½ †>Ö(7>ƒÊ>ÊŠx¾§A޼>Ò½÷5¾ Ew>˜c/=2?>“wƒ>Öæ&¼A…õ=@ö½Ïœ½¼[ >B·>3¿¾�›©½½5<¾>Zý=¬ê»¾›`³½Æ3„<;Ç¿t§>/íÚ¼®Õb>sÉὋ…¾ˆZ½êš€¼Ì¬ã½Y¨>*˾ׯw¾ÿºCûó=�Ç'>úþ¿2@æ½—YÓ½¹Qñ¼ ó¾×õƒ>Ô ’>Ÿ‘y¾��¯eµ�>52ƒ¼‚Ÿ>¨™2>� ¾QG>Fª�¾xñ/«Ï>ÇiS¼í½€h>ö,¾Ø½{ÀH=Ê>Ÿ¾Sm¾4#e½ ôÞ>õx`>“ ¼ÚÙœ½vÿ/>¥Òɾ@DV¼ô?I>'SÑ<'÷ð½Sdž¾Öq£=°a>¼Ún>õÙ‹>z™½ëŒÓ=CÚ&>V¥>]|,<$^ò»ý£·:7h«>ö�n¾ÇÑ…¾ ü;>k¶3½N‚)±íc>D) >Wb>2A–>O4ž<`ï°>ÅP‹½éŸö½þ]q¾ý,H=[ñ½HC¾Ö‚½ŽZÙ=ÃKŽ>,éa½¼,"½op—½y¡(>lR ¾jgô=à÷ѾÁ2W¾Qï§øÆ„¾'L¾Uc ¾>+¹½e›=êTÅ»jX>÷–‚>1×¾FNC½€°¾ª>jŽ–<†}P¼ô/>.h¯;êཕ˽êú=ÂÛ7¼ óì½Yþ=6ç?<'*9=Ìý/>ÂOŒ>¾L>h4u=!þºŸ?qê ¾R›½=‹×C½4A^>f`1>"¿a –=¸I¯=ß]¾.Õ‹>“«î½8o ¾‡p>Æ{L=å²½HD+¾Õ³¾ÍéW;›/9<[Ú½Ö©½áco>XD“½I²¾¢ï’>©F2>ñÒ»¾¢b·¼Io¾æ…¼=Û½o¾\ª�½k Ï=V÷Ÿ>�ø‹>ÌØx¾ØVÒ¾zO‹½Y>¾Cu%>¨ì+>™w=*öÿ<ótM½`H5=dÿ½„l®¾œ›¥>{ø}>×Ü1=$›½¿:ç¾L>GÙ?¾–kI=j[¾‚£™½HãÒ;Ü é¾O>¼ 8=«û¦¾bAƒ¾}޾ ~ùàwá<“û\=9> /¤=æ„*=T‚>òêt¾?~¯>ïFø=Ò¨=“̼94Ù>{"¡½¶¥U¾ps²>WdÏ;Ö¬>ØT'¾@íÂ=5ºá=úòè½Ëæ½>ŸÄè»BW²>_0ê=CžÒ¼Ÿö=•߯½ª§O>Jç®>䤽ãPK>z¾ªß�=$“>’T¼>&ü7¼~Y™¾-_«¾Óbá;´£Ú½SØ=F”À¾ Á‚»¤0Þ½ºl>ˆV>d‡#>"³¼B:ÛƒÞò=‰îÆ>ß*ø<‡)¼;—=fÈc½,5²=Äõ>>s«è¼çZˆ>-G›=/fŒÍJ(½o5–=vÍã½^> w)½ŒÆø;úíí<�nŸ½|¤> I¾Fµ$=»üœ¾Cb¾¬·“=ª¸=°^ù¾HÌоa%¸¾qj½v„…¾³a¯¾åâ�½?A>Ž}¼Ä�^½ßh/>e%>øÁÌ= `~=Û£i¾ck?ñ?Y½¹±"¾^/¾�Ã>u/º¾èä¾™¾²§½ËM¾ß0 ¿Iâó=X;:¼ýr©¼¡b?¾{�Á¾ª”y=Îçñ½a¾ið�=îY¹=Ãü ¾¹÷ƾKúؽ§žk¼^ù=Fe¼“Ú¡½]/>ÕêH>“dš>„U?>Äþ½iƒ7¾Ï9ʽ¢ë#¾N¹½.D·½bì*>)�P>#éÏ>=§E¾79¾NT£¼Azn=À|Û»Üq½¾�@=óõ>¢ê¾›4=Ôæœ:�7P¾#ï-½˜†ð©ít½µd´¾”ǽ’ãï½<Œ$¾Yùº=™I‡¾_ŽA<”>5÷Ç=*ÖR½š×!¾ Àž¾ày´¾gC:={À½äÈT<ýâ =㣾Vw(¿Vk.>С¶=óņ½Z<¤ƒx=�O@>i€¾É…´»7 ²>õg¾¦Û¨¾$Çì½­ù6=±ŒV=Ç©m[v>÷}>Wè<Ûº =|¸®=¼ ”>¡.¾>Ý=‰(á=[™Y¼ZƒV>=^¾ÝwW<«� ½�p¿×I0>¶Û½ÕÒ´>RÆ ¾*C?<">2¹½ù.b¾Sï>Ju�=êj˽ŸR/> žÕ>¬¾Ä_=Óÿо¨(ò¾Es=ü¸…=Ôƒð;`NØ=lâ@>.ߨ¾3=…>+Œ¾ŽaÁ½Íá=ù‘>&Ÿd>hù=&¼ƒ=K/m¼–K�>ßT5>À!p¾³‰¾IÒ=§B¾[ÿ�>/Ù•¾,aÒ½ƒŒ¢>¹E; R<¾€ü7¾šÏ=Ro+>à@g¾v9j>Çýl>Ø´-¾ÿo�¾6¤“¾Ê²!¾$×Ú¾¹àA¾žf ½µÀ ½µŸâ¼ÿ—†=²T-¾tù•½ œ>J¾‡=€<½ß¸ì>ët‰=z@f>·ñx¾C“á=F£>¸¤Ú>?ÑE<Ê‹¾8E±>¿8}½¤Ý²¾Þ ƽüÛ=¾¿A8¾€3¾wµ;¼Ña>º®.¾sS¨½Àžm½²˜Å>†§ë=ØjW½Œfu½ˆ¹Ô½óÜ5¾Œ¾H)�>†¾±ñs¾ObÞ½¯cå¼!kª<ÄC×½åÕ’=öS3¾·(Qº‚¦> þªÆÈ½‹eÞ½Ëëʾi×ï=Šì>ðú½À@F>ggÕ¾n&½jÚ¾$Ý >�ñ<>'i¾û83>Ó΋=Ñú¾Î�¨>ØÛÜ=Êm-¾Rt«¾u¼Ô<”j ¾°HF¾ëy,=âÁ>EäÇ<ã‡r½“�‡>‘f¿½bÈt>¡£7>-j¾rœë=Òê?ùŽ >þ |¾b>>i•u> +R¼ýÈ‘=«ú(¾­Û:¾1¬ >ái½Ý³¢½üÑ>3º>¾‘L>ën ?ýz[>ò ?wxù=lUJ>»U¿%…–¾üSf¾¾‚m=žò>$´�¾|&W¾Úä=>‚"l=þÊG¾¬¶ô¾i ù¼.•<:#¯¾ï‘N¾'Ö=°,³¾ mÌ<Þ½e2>[ †¾Ôà¾5Äš¾à >šª½¤G‡½•�½dC”¾ƒ >ô�>­Ø<°'(¾ö¾jP¼yó¾¡}Y½®µ¾öÛq> ~ç<¡ƒ=­Ä[>ÿ1Ô=g*O=G –<ê�,¾µY»<¡Mþ=z,ѽkÚ!¾p÷�<[A.=×lä=‘z8»�<~¼å x½"m-=ÄUнP»‹¾ø`W½#e€¾·r>R¤Å=þk€=‰-2>'-®>•æÿ¼6¿‰‹Ù»ÚB ¿8¯>~JÖ¾SÝ"¾é¤k¾N­>c}¾ug¾=Ksè½Ä|޾xÜ8=Ç;µ>Ì/¾»®<¼mL¸½oc}> ô6¾|÷-¼§§P>¼óv>¾t-¾Ž‡½õ!î=“Z9¾?*¡½â,ƒ½Êp¾NJ€¾¾9>ùµŒ¾A!X¾ö'Ÿ½ì–H>ض<¾��+?(K¾"Ö€¾y�’>æ>äÚG=†bº>=kÞ>E‡�=­¾©=ö×_=:'ú½Øð˜½ˆæ9¾Ön¾MÀ—½‘XE¾ýH\>¥®‘½<>8 >„S�¾W± ¾m3Œ=©¼*¾$M=¥åÙ¼P3Y¾¿Q3<Ç$�> ô`=s%Ÿ½ÎÒä¾·ˆ¾¾E’%>DQ5¾%Œ|»âñ™=ߨ=:ˆ½ ?Çíš¼dÄi¾ù<Î뺼ċ‰¼Ýÿ‚½êp4=¿c†=Å&¾ ²ª¾ën[½)›X½r�e¼ÔîK½È=£#R=@w™½™Ÿ¾k°•>Lz…½£ÔѼ¤kÍ;ç4Ë;¤à|½ÙÁ¾qÕ>HÚ=Bà½Ö—нñ½=@žµ>,ÌQ>\gI¾æÓµ¼ê5†½Á¶â<¿.Œ=NC«½H2='菉ÂG->™$½=ñ}®¾G9 Åݽª«½>è>å(Â>:3¿†ð–¼E…U¼h�Ù½3¤=0à=ŠN±>𑼂C8=±åž=úí>ŠpľÂZm>g=Ò$µ<>Ko¾¼™>$Õ½:}î¾ØÉ½ô‡C¾¹&H¾x!¹>Æ ¿¾�Þÿ='i¤>âZ/>"‹F½du ¾A°Ò<ƒ³‰>¾ˆ¾EL�>Q_U>±’¾«>/=ÁE>î÷ >µªB>·í=©è$>ªT>™ú>¾œ£â¾ïD侩 ˆ<¹z¾ÃÚ!>§þ>“Ñ7>#âë½">³S¿=ű½u‰ü< P/>"ëd½Í†8¾¸E¾àlW½™^¦»¥N>~À·½ç ¾u[t=é¼>0‘1½äè=- ]<1:¼öQt½›˜¾œÐ‡>Ízx½åµ=p ?â~´½îŠM½_"Z>c6ò½ØP >~;¼�î^>hT¾o©’>g>¹JŸ=ªÊa>ð™ý¼É㣼”²½ªq¼=×)�>@Ý>vð¾>~z¾F…w¾"/C¾Mòž¾¬Œw¾Ì~ ¾ Ôf¾Î¹âÖ!>ZªÐ=¢IŒÙöí½O`¾ó-޾&Ð>¥JP>�be¾5MŒ=~æ@¾:º¨½+�ÿ>Ck=oƽ×z¾÷yݽÁé¾05»½pÚn¾ ø.¾Õ�ö<|­><¥�½Ö*нКZ=K>AK>Òæ½ŽúÕ¾™¡þ=&ŒÁ¾ / =E¼=0–T>6þn¾·Å­=r¿Ž=dþ¼¼Y_¢>Ë89>ÌTê»)§>¡_–½ž&Ø>*+�»¦ex>‘gß<¢ A¾B=œe¾�Ú¾œ®>Ò’å=>Á)>´‘l½ã^b>/:¾“3Í>°ÄÔ½ ‚š¾ÜÔ£> <+¾5š>%þÓ<7ëļ¾® =žÈ">UƒH>ÖYì¾}ÙܾW>¶÷†>¶�¾‚(Q¾U"?¾~½½q�->ÈÝ>× >ÕBÿ>ê¯>N¾§>Ãd†>ez9¾BåÁ¾Aÿê¼C{�¾w,Ä>…þ—<³*>êEå=‰Hú½j8«¼#%3¾s‚Ò¾;mC>ÒJ>Š«T¾x&8¾ïŠb>$ƒ€¼´¾½Á#Xåg¾@ò=иê>µÌŠ>A· >û ¾Ô >ý½XŸ\:Wˆñ=‹ï¡;ÒÍͽÇY¨¾Ùyh¾Eœ ½’·œ½$S¾·\ ¾!1(¾ é¼X%`¾-›i¾N<�¾Á¤m='…;” ª;ññƒ>,=wl÷½÷-m=ëœ=ð<Š]�½‡Û€½èWí½‚¶¡½: Խݔ½�JP¾N•?>½¢¾ZÓ<ÔkÉ=Ð&D>?*h>Ï�M>Ç$�>:Ù >QÅ<>/½�¾GWs>)„�=Un•¾—Û}½Òió¾Ô6>Kê=Ómš¾rå½Zþß½øúA>”î$¾²ƒ?ÁÚ¾vYF½;ê=»¬½Mò‡½£‘½�N>µ•Ï=q´ > ñn>3럽 ½�½—ÇŽ½ÏîÊ>x£=Ä™Z¾åÁî¾ÄÔ�>M0¾ÊZ%¾†_=œ#¯½ë)§=´�å=hJˆ½�Ÿ¾+ˆB½<“>vmý=‹9°>7¦4>Öøš¾2nù¼Ï5›¾ã¢¦¾ qνâŽì=£�v¾÷†Ä½¤$Â>ðŽæ¼‡ >Ææp¾O?¾ŽTI¾›ÃÚ=½šˆ>³<‚¾&¢íñ z=„ýÁ>%¥â½•*y=˜‰¾aÄá¾{,¾n‘¾N—>iÔ±¾3ˆ¾Ka>ª†>¼}¾ß½õ?É/L>c"Œ¾ o};&r„¾ÈF¼]¨¯½Ö,">æeɾ¯|>‹>3¾ªW¾z�=>€>‰ôô>aç=VÔ¾V(¦=ƒKÆ<ŸU^>z¢j=ê&J¾þd¼ðìÜ=ƒ4š¾Ý±W¾¥°¢¼ÈOˆ>Øc=y3¾'ªz>‡Ÿ@¾0‚*>Š[‡>ⳑ¾0“[=›¾/—¾>)î÷½æ„˜<=Ÿ¾A׺>�>V~¾âû‡½¾Ôj>!3Z¾[UM¼^f’¾*‡�>hâ?%s½PÂÓ½@š½?›æ>J�~½¸}>{>‚E£>@¾‚>è^>ç{>ó†>¦ëÿ=_–ˆ½"1¾¡Ã½õœ…=X%¾%,"¾Qu¾ ý¼4#ò=M=¾Xn¾µ >‘*¾Ÿ³6¾nÈ„>íEѽV›ð<¯0:> ½Fè½¼Hã¾Ý †>|ïX<Äý*„1= ð(¾•²>\£<>–ºÊ=,Eõ=q#¿Ë@>‰óܾâ“x½_[›º¤9¾Vk«vµ =.립�C¾šá<ÙÕØ>%ýÐ=¹»©»^˜>s>€¾Ü=â~®=bZ=g‘>Âbæ½8bµ¾‹f�>l…ï½1û>ö‚3½¶¶Þ>ºÑ“>ƒ›>–´Ž:9¬ >¡Mè½ßÙY=e&ܾÚ©>%©½òlÂ>bX =Ò0’>BÆB¾ ‰S>;𙾆k)¾É4¾»ÀW¾uç¬=##]<½O¾¿A?¾>^â=’D>ÇÀ>­za½fXÛ¾Ú¾ê]Î=ÏPÒ>HO>èP¼Ž¿R¾° €½‚é€>0 È=5p.¾8ü›>Þ•³>‹>§~>8P,=˜•f>Ã�tÿ£>nl>n½áX.=íÈ>È6`¾œÏ>³Íª>�ÎÀ½ÙZ¾F}^¾y7�=ׄ ¾w>¼½?3"½¬ ç=FÀ¾tl¨>ʦ>’ò ¾\1¼¨…é¼É’о³q½ª6y>±ï)=ëßâ> ûb>\Ÿ ¾0‡k¾è;=Ù²>ýÇS>Ι¾е>ú‡E>Çn›½Û×">pc®=óÿs¾~ ʾ«§˜½c$©=Œ]«=нí<ݽ”ž>—ý ¾ô§�½#®‹¾°¤k>pó½ÏÄP>Z]=ÿøŸ>“>b»¤¾*?ѽæMR¾ã£¾ÀçÕ½G‚¼�Ö«>%«Y>IC"¾œ˜©½æļÁ˜i¼¾Ýj¾DXê<�G]Ó=¬"W>´&þ>;6Ý<Ÿ×»¾�Ú€>$íÊ=9u>û7N¾áF–>S/>+¼2=â¥=(£u¾|¼ö;¢9Ÿ¾/Û¯¾!ž~¾}õ¾‰B0>Eê{=~õ€¾•“`>á-è½ïd>±¢>R&¾l6q:ð€=¾Sñ½\z}¾aª±¾ ‡¾ÊÈ”>ÅoB¾÷×D¼ÀÔþ=?JÈ=“ü¾¬Å¢¾Ê4¿a˜¾ ˆ:¾Ÿ^¾Í k[J>Âì…=4b6>L»=9B>¦m*=.•>ߖѽsë"?5)=Fƒ'½v<•>Ñf„;ù”&>m»Ê>¤Éœ¾[Cº<†�$>.>l"¾l¶:>sHt½Úàœ>×x½†ßܼSËm=wõ¡=¢;>–«“¾Tr=�í%>ø©”¼T˾)¤=$8a=Á�ñ=Ò¦¼§—0½„ÙT¾ó.>y†&=³'½Þ/>Ô@#¾–r>ýÖ ¾²&Ÿ½ «­<·¡>J4¼:áY½ž –=Ï…‡½;ò(¾ÍîT>êk�¾�µœ>1>±¤ ¾,sM½Ùgz¾îw$>"Dã½2ð½Ç.‹=»5ù½ÄXW=‹@¾¶˜a>mIe>ó$¾tM‡>ÏÞ>Èe=oêC>î¢e;½ž¨ÑK¾<±Ÿ|…½*L¾IäÀ>㌼!Áo=°)¾Ýþø½v.¾�È�>Keš¾bн‹'”½/7†½QÅ®=�<ý¾³mʽkUƒ½ÍYa¾J€½PÑo½Ãć¼Ef¾!O@>RÎ1¾�Õ>Ø¢v¾Í±<ó„í¾/CB¾èZ¾ÀY޾eïÿ½u^¬½ÚA+¾‡†¾´‡ ¿�ÄÕ½NŒ>ÞP¡¾µAd½¯ºÚ=…Í ¾�¢5¾¶1Õ¾à¥>Ä[ª=Pä8=¹>öóç¼ð‚оAæ=•-ú½%l�>©íâ=R[¾¨Õ/¾Öô÷=“�¾JÕŸ¾íÈ¢¾% ¬=å§¥=c³¥¾Îþƒ¼g>äãÇ=g½ï”µ¾bˈ=t­b>—T(>"€K=_ɬ=Ä´–>yã ½fúS¾ˆ±¾¾�çy½ZÇ”>ËŸ�¾2¨½Þ=ÿ­½Q¢>‚c>΄Ã>Á>¡ðœ½8¼³>�ò=Jg¾V)½½‰\L¾ñ.®=šÌŽ1*ô¾½;‰>¦åç>rýŸ=ìí…;TC¾afš¾«e>G�2=-ñ€>Úÿå<â §½òl½ì°½—Ê>Õ@/¾'·>~Ò$¾Êîò>¡¢>þؤ½…]7¼"K=Mç¥=Á£¾ßûC½ÓôS=*có¼¨ >DÀ5>“1ƒ½œi�¾ λFøw½�5°=�bs=nC>ñù‚>ƒpg½ôÞB>¶û½dp ¾“¤•>@@Ó¼˜Æ=³Ü=Á¾þ•¿…³½2Þ¼ä©ë½éæc<‡ô£¾ ¿Œ½ŸÕ>ôŠ)¾#i ¿æ$‹½F©Ø¾¿µ½kF�½çU ¾[ d;@àö<‰�Œ¾�¬·¾¤Þ¬½ýˆ¦½|�D>6r½ÿþ‘>0#p=Œë�¾%�™=Pê-=>Q€¾œ=Ñ>Æ’X>¸èÜ Ô±¾þŠ™½3k6>"³O>®l½8Æ<„̾LLž>×S]½š£O=Žw=;æo'?’Tоvã?=œ Ì½âëÁ>ÄF½î,>GK¦½ÐC=R¦ž½R!°=Øv>yΛ¾«?b<à¥P¾fÒ8¾Xν¼ÿ>vͽô?Ù>»°G>kúݼJ—{»¨Ÿ÷=ü¨¾i¼¡½ê±Ž¾Ntö¾dõ$>+[½4•>¾Â«¾Àh; ß¾Ði'>/L±½*]D¼Ü.}¾Ge{½É¯>\Ã>rä,>¿!Ѿ•‚*¾ Ù>È{:>bä¾úv½,Íy=<y¾oqc¾Y¾[‹¹>K®ƒ=:Ù=xA¾žyY>™å·=” ¿E|Œ>iá>–Ió½gÑ™=�Ô>ô¾Ä=¿£G¾#Å<~‘¾œ)h¾ìút½­ž>¼9¨>·A¾~z¢¾?™»½„™£=šù7=Sí§¾Z~[…=6<6>"d”>áôU¾œ ó>Y1Y>Ã̾» Í=åõ1>Òõ=ÄÕì<Í)ö=\õ•>µ·€=Õô}¾V¼¾a¾vék=.ÁF½:‹>€»ê½9 Ë½×Â(�¢>ã4î½Zz¿S.¾\ÄJ¾ç­¾²Ó=êoè=äØc¾â‹ ¾}ø”>æ³›¾i½—¾Ï!3¾ô³½¡'¡¾k¢Í¾&�½"'i>¨Ž€¾)¾=½µ˜¾P¸k>O{ ½Û=—r>ï”<=îQ½tk–¾ŽÊ\=‹ðì=º´>9J›>½ÁŒ>¸¬›>RQ¾zàÙ½Eã=ëX¾„7º=“u¼@Ž>†‚.>ª8“º=¾Ìm?½�lYfL�=àáν¬«É=·V=þ²Œ>œ¬£<“K¾Ý°£¾ˆ¬9>Ç)½ I6>¹þY½1� >‹S8>é¦*>,³k¿X£½%”½Ž÷µ>*M‚>¤w9>QÌ«>±‘ ½µª ¾ø,A¾²îN?ù¦¾Ø’k=Ðh£>­*°¼¥nn>0 :>5…¬»Þ}’ʼn;pÝ–½;ß>Ç:E½æÔ=!y�>ÇÅ=Ù¯å¼�]½9¾¬GŒ½?ê¤=X•;>–j<ë ž>E”›>—­¤>7F>±.’½Ìk°¼‚¼Þ ¾ç:‘ú=9H¾úz�=›X¢=y¤÷½>‹ƒ>Õ £=íió=‚"h¾; 1>I«w>nP•< Ñ€=ÁT>%‰â¾,rM¼hc?½‰õ½ýQ¾20á=ÄóÝ=®ñ¸=-ˆ¾%6¾¸1¾¾ëž=ã.>‚#=œPo¾çË‚>ÏN8>[–[>p¥½8N»:G] ¾Kõm¾»¿Ï=ÂEO¾q>뼬Q¾¿§”¾qX¼½ÆÞ=yM�¼Õy);�c¥=vŽ>£>KU>ùd¾˜¡2¾êU%¾@Wx<Æ €>±¾1=ºÎ;½½‹>% ,>nËf>•ï'¾¹@¹½pÎ>ÞRè½pÆ2¾Á�S>ê�½Ÿh=\‹ <ú²¾L¼%¾”ˆ¾øœI½XN>@i½$?yù$¿­Íx¼p =€ýã=-{==íÃ=U¥‚>½ËŸ½U`m>^ä>¿Ë´>f¤> Ë]¾œ+ú½oQ¦½ª½è=¬¡= ,6=i >N¦±¾N…>kr‰½xJ ¾y6Z=S¶>~™„¾laZ¾*œ¾é‹‰½”W¾¹¹¼ê¤§=W¨G>~,{»÷b¾eÜ‘½íú†¾\ÜX¾3ž½ÇM£>;³ç<šy¾ŸÙc½×r¾;H‹<Œš?MP‚½Úç3>C‘t¾Ç;>ܸ’= Íм] ¾@öß>u´o½x£D¾á)¡>Íþ‚>(m̾>ÏŒ¶:ßV¾M©®<ê¦2¾$ñ½ À=ª¥ê=˜³¶½)_³»T"Z¾‡É�¾‰àÀ¼cX¹½¨¹Û="¼ÿŒ:Ÿ�>½²$¾u =¥Òå2ú¼Z× <@/K¾ û½=vPü= I½¥�¨¾ekD>ªci¾‰/F>|ø=Xl>×]Ø=_ â=ªþØ;E!Q½�˜½„G¾çÒI>´]$½ZL•½ã>M¾:ãî¾An½…†«=Ý?IòŒ=ô¾¤¾ªJ޾ïÆ¾"®Ç¾çÄî=“ñ)¾¬ À¼Tݸ½9Í®¾> A=ˆ–>o>©”C½&Q?p�†=° ·>½ ½·‰ò<6¾~@5¾]/x½É+!¿Ëº­ >_xÿ¼­AÃ=Vo,¾ðÀ¾KäU¼y6!>LJ¼¼2¾µ+¾ž¹×¼‘¤»òPÚ=urš¼ñ­ˆ¾ ”¾Ý¯>öS�ßoX½6¢?¾ àõ=#~ƒ¾Ñ¡«¾KŠ>•3V¾Wq>¹´¾!ì¾}öä<.!C¾8H(>x®È¾ùGC¾+O=ê‹‚¾á�"¾Jú]>”éa>e¹<"‘ ¾MÒ =0×¾�)‹MÐÝ=lšv=Ò ¾æú>�˜>,[,¾²u)¾yÛJ¾*:>>">�d‡=~§âºÈø´<¬(=§ßf¾ñÕp>û�<¯ð>×Pº¾ãbN¾ ½7½ Á¾�ø¼œ_C¾‹eÌ½à·Ø½¸ŠÔ¼¿”™¾úÂ>Î>>&_Û>”„;Î$Ç=É6=8.÷=rjQ¾½ºm¼ž©>ô­J¾ïAµ=¨ñ=›§=Ã6Ý<ø–+¾jVA>tµã=¾ªÒ½&ë¾oé�¾n„¡=M1h½þDV=èC¾v_…=оŠß¾êRö»*'Æ=$®Å¾±óû½V½¡„$»œ1>È‹½éŸˆ>¹ >Í'©<ŽöÝ> Cå= l–=úê}¾·á=Ç^>‚ 3½{›¶½”¸¾ñÄ´>ô”½—__>jíu>j�¾©uu>_™©¾"Fç½»Ñã½Ëæv>Üø_=~­u¾•4¦¾|âù½X¾šŽ€>;`ý=Œk>>Y¢õ=+B[¼–­O¾CAÒ=ÅàĽÅ³>G&%=•ñ›½!9p¾ d>ã’¾õ:–¾×Iõ=Çîß¼'‘#>â¯>•œ8¾´t3¾5²<ã;Ѿ;á7¾b e¾:ëu>ag>³+J¾¡})>Tá1¾è*>Y2ª½–滺‹¾8¾;1—½õšb>hg¾ç¦Ž>&O)>s¼‚>MÉA½ X?0½Œ™=p@à=ÐÍ{=ݨ½¸)l>š‚½}�A<Ÿ+¾±êï;Yô*>/H7¾•–l>k.�¾Èh(>íç¾AÅ*>õ]½·‘¾»—Æz¾×[�¾œuš>´ùÄ<�>h±m¾Ä÷è<¿ºƒ=PÌô=‚¤"¼�–K¾49>Ï�’»Êø¼P‡¨¾Þý=eÿÍ=�DV>x{á½1˜=¥£h>侘>Æõ¬>ì¥Ë>ÞM¯¾ ᓽ@H=©Õ;½&s>´*y¾6±ª½,I >3`¾ö†”¾ mm¾rX ¼M%½qµ-=àlö=™¬yóól>ñ†Ò=uŽV K>Úl(¾£ÅǾÉõl¾Ö ¿³¾‡¾©¨™>qùŸ>e3�>&�O¾•®Š¾Ú¬¡¼n ¾J�Ü>ðð3ÖÁ>u¾”²Ä>”²¥¾¿nP¾üѾ9k•½R`s¾õÙu¾?�>/^?,Hc¾/Äx¾Âò½7¿J>f5 >[<¾<0d¾[»$¾,Jy¾¶²>xi¼C!¾Ü´Œ¾çtÉ> <> ª:t&â=ÎX-¾u-|¾Ä¹$>*¾ßÓí> Gµ½ W|=¿kz;~3>LŒµ¾|¾Î……=Ľ ¬Ó»‘ÿ½X%-¾|uŽ>vn�>+½@½q”?>Ní�>Ž¥>ÜÕŠ>Q2Ô=~s§=u<Ö=ÍÏ>/¯¼xÄœ½�…¯=zñ<½aA¾Å¿�§=ŸÔc¾æÔÂ>¢‰.½1´¢=‰¼;¾[ÈL¼º›¾F¼QÀu=‘�Õ½Æ2¾f5 ¾¾d¾L”0>9êù=½gã`½Ç6À=à†>TÆi½“^>ÆX<íH>ÈÉÑ=8l?ƒ�P=*ïÀ¾m†7>U>œ¾œx`¾¯M >Ê´¼>ð¾¬çƒ¾$ ³½bñ>y|m¾9�†>oX7¾�Æ›>Ës‰>Nž‚=µØ=r �>¾ £½®“v:œ5c¾Ã× ¾\we>nˆ¾ŒÁ"¾äYç¾aÿʾ_3¾H(>¸“òù=ÈÆ8¾¨g»àÈ1½xÃò=Ròœ=Ŀ޾ÅH>˜,–½Þ½Q˜^>ïqÓ>1*¾õX‰>w­>=Í:ë½Ë�€¾Û��¾¨Š¾¤©�½þ¼¾Ûr¾Ï¾aMÖ¾r‘ý½Ô²½oŒU½n~P> g½u¤�¾÷yq¾[×T=•>A¾Ôý±½ùñ*¾mÞT>¿q±½–Z侟“š¾ÿ„=™ýò½2„½àä¾ ñ—= –è¾Epœ¾„î>L'`6Ü‚y=bRÀ=ò>=µPD¾ÛOp¾Ëc¾ؓ§½TO>‹B>J¬‹=w½Ø½ÕOÝ=™>«d¿<›�Ç=ž=ÐWѽÖɪ>û¦¾r^i¾i?/=RWþ½†Tö=žº½Ñx2>„÷̼«V•=~�â=šê?¾¯†Ý<ìa=a°e<åξeˆ‡=Ã7œ>ut³¾ÖùÇ=yf2¾Ü}8<ȇ,;gC>Vʸ½:^°= G½ 0>® ‹>†ºó>o:Æ= _¾>ã̽¤¿å=2µ¡½ë|¾žâ3>;ˆÄ<Y;ȵ.>^¦Ñ½ß�>z4>rZ—¾Nm„>ÁÉ=Ã"¿q, ¾¿-­¾rk¾¦½ˆ>�óÅ<ƒð>N’¼¢V¶¾úsE¾ò<6¾ðþ�¾°é½ƒ�ö=R‰>x’¼Ç[¾>'P¼ˆ+w»HQ(>=j‹¼kšs¾ó¤¿½.{‹>÷L�>ïd1>�P->Ÿi�>_½ë=@$ž<�ãð½¯Çõ¼vQ¼…Ñ>ˆyx>·ÀÜ=€Y½(ò~=LQ`¾0¸>=i4>ކ½¨(¾äÇÊ;f ¿¯«5¾™Ý¾š¨(¾V^4>ÑwÙ¼a>>­’¡>š;ÈòL¼4Ÿ�>‘ÎG¿4b›=º| ¾èôh¾•!¿ð[Üœ¾Y[™>ö@¼=Ëp1¾Ãµ¼QëÍ=Eþõ"¦>&°Ä=oŸ½.—ô½õ–÷=o-1¾>·Œ¼Æx™>º�¾ì=�ï>áQ ½_­Ä¼tN¾±êQ½6t•>.7z>ú½Èõ›=Ä1¢>dbþ>Ð3>.MP=ÝÛ ?C»=�Š.>&™=*ݾ{ÃV¾Û›¶½öa+¾C½ü=k—H¾Ã4->}q€½È‘>X}¸½DÚ¾9¾�f‚<ðòä¾óÙ>øë6¾4L̾@U„>Ä})¾!‘Ù½>éY½GÆ==Á;#> ù/=º ¾.Ú+>¶ ¾› é½íì•;þ#G=Cd/=ž“¬¾"9È="z(>/�’¾¢¹²¾á9Ú¼ó£×¾Ní®¾Š% >=à >[¯=½3{=š ]¾…úÕ>vqc¾«ãʾ÷S=�âÆ¼A¤½•æP>+ú?0¨ß»œpº½ržd¾v[¹¾Åµ¤¾§ ¡¾?È¢¼¥=v=SÔ½=.�M¾·¾5áþ=†ž>¸ ¿”Jž½÷¼Ô=*’νp•ê¾X2Ÿ>Ïuƒ¾›ü½Ï`¾ÅK�>8†½z�1¾®òÃ= &ü½ƒÙä½²É= =êÇ'¿2L½Èçy>‰8K<Áõ¾rü<½—‚†¾^x<Î%<îÅ>ŸÏ̼wŽQ<»X^½Z3™=Ñ�¾w£Ÿ½Y�>GT=ký‘>ÿí%¼äpÓ½u­¬>n`½_S˽j>[¾t>/½ý:U¾ä÷Ï=ë¦@=PV>æ*ì<ÜÕ¢>÷‰›9€d=<ôD¾Úü†=«œ;=¢›ë¼ ˆ¾'<½«×»;zŠ>ìmA;[ ø¼Þ͹½wán=݉’=Ì�½ÓÔY>ÆrŸÓí= 3;½Ð»t>f±½¹†”¾'ø¼m7)¾'d>¼t¦w¾$ʱ¾LÚ>Û ƒ¾eŸ_¼Ä;“¾˜ÅS¾…=j_�>8Ú±=oe‡>)9Õ<Ú¾[ûž½cÝ>".+¾»„½Y‚f>>Ìð»ÇÞy=TN¾0Û¾‡ÜŸ¾RQñ=wU9>“­=¾ >$YW>z¾œš!½·®ž»ì’¾OáU=£?€„>b(ù½%D/¾ði ¾ãt>zÐÒ½}¶»sÒÛ<$³ ½ï5X=ÆÅ ¼§?>Ì==f©,>ûž§=Å�=šŸˆ>®{´½¬JE>ü²>KYo¾,,…<)W[=¿Õ >HÎL½S^Y=6>Ž‚ƒ>'»¨¾Ü™1¾û¿Ù½ŠÑ ¾ÄÁ½°«; ƒ¾ÿÿ =õz?âÄY½£Ä\¾}4«=Ÿ?ô=ÂíD¾Uçú¼èˆØ¼vm½¸Ã‘¼Ds~½†&�¾@¸:>½Ô›>Ô´=Iõ¾­N>Õ/E=Xu—>V ÷=O;>ÒŽ‡¾ ,S>R¤¾÷Ë ¾ržB¾# ?âÒ}>òÎè½”3="`ó½ùÇ~=ˆˆ>R¢½ž¾4~>£y÷<ÒÀæ½ ÃÔ½=&Ú=Û+¾�T­>óè >Lm�½@…¾ƒÈ"¼‰оŒîK¾Þކ¾»~¾SÍb½PÞj;à=#꽆ÎD>°·0?j>\½*¾ „B¾|ùݼ0Š#½¿G½ûÈ>_%?½™è¾Úý?>¸’¦½{ß}>ψ¾û»Õ½‹Æ>Mé½=ëû=’ ¿y˜9>A§[=„ò?½ù\Ä=*õG>`[¾�±¾÷“ž>Ы=Ñò˜>É4x=`1¾ÜA¾Ôb¾3^ü=¼|¾n³¼Âù’>S×¾ZôL>8–l½e‰ ½œï5>Ptò½s8R¾5=ønj¾xW<¾W•¼}î¨=ñŪ>Ë ‚<ƒ8¾>N½$]=:'¾m-´øò½“8ª>ÐTÛ¼Ë ¾?ï¾VÈ'†?¡ ó»ùaÒ= €€>Íß6=ïÓ¾m|¬=Aiß<Ýò=ƒ‡q¾¿<;Ï^轈÷è=o%= �=7a>ìÚH¾'!¾ ®¾½Õ>ž¾CF½.?;O:V= {÷=†–½M¯=MÙÎ<ìï˜=!#³¼åf ?ÄÇž½TçM>¾” ¾T¿­½-1¾(rR½.—±¾mI¯=Ä”½z6>”Ùm<¥�ƒ¾½#{¾,£»¼}´<Ég\¾ü‚2½,°<>H§½lÚ>;nß=¦ç§½JÁ¾´•�¾‘ýÔ>5xê><è=Z¼j½×îÖ¾¹ô¿+M†¾õ2 =“/‚<©e½=8Zk½”F¤¾¢Ý?>¼ÌØ= �>"~“>Ǩé=¾L÷g»JR¾9ð*¾ó˜¾¯²¼,ˆJ>¸½BUò=!/6=ÆEç½�4¼tŸˆ¾°ñ›>*!¶>´<Ý8<¬‰Ã¾Än==ß0§¾ƒð÷=Øi¾3d¼Z«=+$¾Ÿú<>m§ä¢¡¾íÙX½8¿1'8¾ç’>>ó²î¾BõÛ½û ¾@ =&¼hM˜½³˜t»"9O¾£ñ)¾34½ë䨽–U<^"€=ÔTÀ<þ‡Ô=b÷ ¾uÞ>оƒÜp>A¬Ø>R°¢<˜£i>Ñfp=cí->Lì½½ýÌŒ¾�˾<êSÒ¾` >î/q=”>ª>k§=f/b>-aú½5>¾‰ü“»Ö“~¾2 ï=º ¿%ྠ|¿½ÜY+=šW)>²Ö¾X}ý¾ÊżAæà=I=ë½µ¶-¾5‘’>’"h=å@ï½¶�_>uŸ¦½ ¥½ª¬Œ¾‡mó¼FMf>ƒ v¾¡©½Ñ"ê>èE>å悔p½~‰> Š>#ò¾�ª¾Y’ÿ¾x¤x½uûa¾^ós¾tÉ©¾âÍ1»ÏŽ =ܦ¾‰Í¾š#ž=”mY¾©`p½’Ç"=·à¸¾¥9�=z¶g¾Ç´½Q[�½ìµ>Âi?0ÅB=Ëp =Kì´¼kQv¼HY½gûá=^V¯½7Ÿ=”ñ=«°ˆ¾ÔC¾�˜>Éù4¿lœŠÈнó­>Ñ>§¾w>{ú–¼qÝû<�Âí=wÆ$>íQ3¾‘»=ßu±¾bñ^¾”Ð,¾ãÑl=�Mí<Ž�¾øb:¾NÔ•<žÒ‚> ¶> ¾þ<œÆV½µ‡=V™%>õ&f>ÒØ+¾îr>kòI>ºB¾÷#¬¾ª ‚½–’½c¿TK¾r”k¾,Ž–½`pŒ>ë =æ>jŒ°=´kŽ>?—¾„.y>Z¬=Rk ¾ð 5ºS>'ji¾z€>¬Pê½EÑ)¾6E >qe¾–O>>Åt ¾¤ÔÞ¾éýª¾ÜJø½Ìèq>ž©Ø>u®»½ßÍ–=�+½¦ù‡>i†"½+ÔÁ='ÂN½‚»D¾Ä =š¾=¥ÐŠ=ݸ¾bK>û!¶=­±¾ÄH­=O:¿¾8˜?Ü}8޾‹Æ¼û¥­>mÏa>e”>½Õ>~2Œ= $h<_±Ú¼¥U>ÃÑt¾1ì½J&Q½þ ²¾è€y¼*/0<æ4Ø»û{>Õ=Y¼dŸ¿yrú½#W+>zE>Ÿèk¾�#>ø9)‘𾹨 ¿2Ê=7e‘½OJÎ<ú0Z½ˆá½–&=­ÝC½û[‰¾þØþ¼ná¿f5�¼?L¾pÀ¾ØkN¾<ÿu=ëîD>øêŽ=½S2¾&„¥>žmJ¾ÖŸ¾ Æ½på>JX½=Œ£d>©Œ»—’¹¾žŸ–¼Å2=a®×¾ä¢"¾±Ú¼ì—�¾�%¾é—À»8œ=>çje¾ >¾$Ëë½ }ˆ>¼\S>µ*l<¢²É½c$¾† ‘¾ ¾ì @¾-òE½N¾×¼è<>Åb‡=!Ò€¾ tv>ŽÔ¾²¿ˆ=ÐɽÍ8¾:ºe¾ËlM;œT¼=!Û½Ç+¤½�úl¾æ]Ž>£2¦<ˆ‘¾Öh˜½ˆ =î6e¾ÇI>[bÔ½£ {=Êœ;>^ûl1|>[µ1>C¬Ã= ø#>"Ù9¾Âǵ<çæŒ¾‚=¾Ú>`ìó¼ pï½d64¾%ŒD>D2ؽà#ÿ=ù¥2¾ž^ƒ>Ìár¼nP(¾x… ½ZÀ£=æQ¾ÏÆð½Üa2½Ö˜…> oY=Â’+> ¥½î¡=&Ýò=&nß=ù—›>i‚i½)÷8>§f>r&)>aa›;ŸÀ>Tb>Äë‰=ÙsT=!ÆS½áÝ*> ">P×:>òr>t~¡¾O=μ‘j>óÃ!>¬´ >0<‰à³€½cÏN>}¾þ[<—ÖX>λ#=n¢½½4Rr¾Ÿ!¾êc�¾ÒôP>ð ; i¥>à‚»¼ Á½ Ðð=S‰a¾u¬ï> v ¾(~>p×Y>¨¢à¾�1Z¾Þ•<Êü•½S/)¼\/Q>>]¼á뉾N§½0¿Á½h½ûfQ½À¢U>ªX�½”’½–¿”¾MÐ>0’¼âOB¾ðD×¼çø±>;4F¾^a:½Ù°¼Éz>ý,’¾üÔ"¾Y4?¾mp’<v[¾°r¿Ýœ>T¾-u0>ÉI¡=ÎÇû¼Y€¾!-ǾM¢±¾þðN£>ÒÜŽ»#&�¾>ã¼`Yê>ä¸>âpË=Ó6½Ü›š½¼‹»½yQ½½­îD¾³È=qá>óP"<–Wx>Pú8½ûr¾íeå=ÌEN½Ù�d¾1n>S{Õ¼iнm\<AÊÛ=Ö¤‹¾_ß�½R,µ¾\¾4»¹b=jew=ÎÉP¾òšÏ>1Õg½1•œ¾¸ùG?‰¯2?ì ´='V=m¾q…€=ž^Æ=ÑŸ ¿'ú>hµã½ ÚÃ<4§¨¾žc–¾©Ït>à7e¾ã™¾º. =†X<éÏÓ¾t± ¾}!E>Ѳ¾õÃÌIP;=´ç›½5±¾1—¶½°½‚½¿V·¾òy‘½°ÜG>1 Ã=d-U<Kt™^­=ŽnV>ãöè½=Y�¾�S”½9.½=ªÛ¥>ge¬>øŠ>¬þ†>?Ma>ôL= Ü3=;¯ö¼É2¾Fáf>À£½=�¸Š¼ê@½Xƒ½€¤ù=2¡O½ê ð½ixÞ;’Ë/?2>‰½Î¦(¾Í¥=› ¿ÇŽ\½@¨Å½N¿cÔŽ¾My.¾uéj¾òp–>'ÂÝ=Xù¾(„=ÕÒ>¼¡=>½¬' ¾j=ü²p>RAš¾?Ð?r€#=-“B¾ ^«½Ò3¤½†”¾Ä2†=Úõr¾›"«½}Q¾JŒ½…`®¾¹ƒýºáÆ\¾"Á4¾3ç$<¯íH>X8¿H–>7ë>¾•�>òT=æÅ�>åÌ?Ò%=©.æ;#‰=<ëì¾�m¾’€à=¾u\¾\Èj½stÅ<]Ï >�.†¾³÷Œ= w’½“޾nľ.á¤=ïæk¾Æ¦ù½ó ¾ –s=Za;�ò½®’½ñ >Æ,º¾È_¾íF=²Ì™½Vþ(>ëP�=/�o=½t'¾V?3¾Â­D>�ˆ¾¼¥²¾ÊÒ·=(¨Î¾0D‰¾3ݰ¾M¦>j¢R>Â"^».`Â=s…˜¾Žó>ýú=–ÃŒ¾éî°>–¹"=>Ih;1H%¾Ý€€>ò¡>'?…=ry”½ p¿@lö¾\¢À¾Nãj=ÇÔ,<“ni=ð·M¾9x˜½©¨é= —½2—½rʾL „>M¦¾ `¾,>>Ihª½Rw*>®Rʾ¿;#?e»�=W¹=¸à¼–¼’ßm¾lÍOºÀŠ3½ u®¾ÿ- ¾Oƒ>r£ >n‘6¾¨�ú½^ ~½àü8>¿�~¼8™ ?àÙ¢¼Ñ o¾íC ½¸j4>_ã½ëö„½Ü{ ¾WW³>|jè=,Ì¥¾‹X<à¢ã½”És>´2²:Ev>à …¾X]½‹8®½-‘3½ò–b>t/¾X¼w>bˆÎ¾…ý†Hß=Þq$>9=ø=Þ–±<"‹g¾˜³:¼ðä/>X?Û½?¦{¼Æ=ê‹ä=ù•>'¨¾ ˜±¾üßd¾VÜ*¾¾Ï½Ã™…¼pFŽ=-:>3Û®>|þ“>B}>ËB>ªóѾ[%>ú’å¾ëqÝ½Ö ˆ=ë{«¾�(=´rz¾kËǾì~>_èð¾6 `½÷u*>´å̾Ûó>é†>ÈR?¼Þ6S>NKµ<z¿ÑvÝ=qM^>ôŽ0¾Õá½ø“¹>t·½[£¼ÌÕ½ ¯ó½Eå´=x‘²=Èü=hZ^>ë­M=BÁ½È0�½òÄÞ½ ,=û½^Þa>uÁ>¹™ >�÷�¾H«=¾ÂW¾_à×=aF�¾ŒM¼ pW>nü=¤Rv¾v|¾®(>fЦ=â�w¼fva<­4 ½ÏÎ0>I‰¾oE8½>D5¶¾g.P>ã1 =àÕ>Gñ=¨Í>>%/Ü:�–{>Õ@@;ñà½"€Z½&~F=×­o¾v ¾½’�ï=Êý¼—„>Q?Ÿ= 1¾…¥.=‘Vô== [¾{•µ>Æó›½Šä=ˆGË>’›®¾¥UȾ‹’>ðßñ>åd>ç)¾«Âg¾¢Õ*>&J>a$>£ô ?j‘F¾àáª>ïì ¾ôÂõ½n˾}‡[>ùŸ–>šsp¼Ç¿>ò]‰¾©¾’)=ãO>ûd‘¾‚<±>ºCÚ›d>1Ÿ�=ˉ‚¾I¾{hÿ<»>Ö½®ÿj¾jå¾³ Ö¾¯´á½ ä<ïm>%V ¾ü I>éð>ã¥�½I„>>=»°=¾%¡y>MIz¾nðõ=ŸØ½=‰ùx¾cä•>>ð²¾îˆ6>NÁÁ¾ÜF¾"О=�Áñ>þØw=?ô;¾6!¾4º<Ö„·¼ávc>°¸”>iÌ÷½éD¾êë>ÝŠò=ÝŠ> oÀ½1§¾·g޽çâ¾ödá=OD¾ËD =ƒI?ö¸¾äHª=¹Íé½"ëT¾²,œ½P„=F �½»©·¾g• ¾×±t=§l½æ}z=õ3>Nh«=˜@,¾à©/>i>Ÿ½ ®í=qq`:�Ð�¾‹¢…;\¾!á ¾ÛýK¾·Iú½EÑ%=H 4>§Ó ¾‰¤<>T¬+¾DÕç¾åÑ=èÄ]>åO¡½= È>t9ͼ¾Êp¾]õã=>î{¾€Cð¾Ð=Õ=Ô‡£=Ap?σ⽿@>ªüñ½Cˆ©=qi>¥ñC¾NœÜ>Xr¾ß¯º½äx¾/ Ò¾Æ,½¼wlò½£¤æ=ÖÒ›½¹c>¾#7=½«Ï>�§$¾�ò2¾¤)?‚w§=ŠÅ`½4âç¾j„.>Mj¾s�ç>„Íì¾2í½/£½‚ƒ?>‰*­¸êž<¾³º¾#¹ý»-›D>ú‹Û=êZ¸½ÎÄj<‡½h=ÈE >TBö¾˜û3¾õÃÝ>¥¿‘>S"-=¿xнH|î¾½×ܾïvõ¾#l=C{>lõ`=’qè;…­C¾2½‚= ŠN¾×û=BLL½$´`>¡4>0">¢ÐT¾{þ¥¾†u¥¾äáæ¾2 ->€ÿѾpf=r!™=ï-f=?Ì�½½’¾¥óË>ùÏ>C ¼ R‡>¸¾–ƒ> ó¹¾[Õ½InÓ<ú{•>æ’†½ðÔ>SìUªG�¼¾1+¾#µ=[¸'=½Ïb=Tàå¾�H¾êоúw`>‰È=‚#1>æ5>J)ß» Ü!¾Ÿ¼'½Î(¬>Ë{>Y‘�>ß4>4½Œ}—=è[¾&y–>ë–ó½Ü¢Ø»¥±%¾99g=—ï:>.ྠ[>G Û=9è >ôˆ/>õ.¾ôç¥>äë¾A:5>ú–¾9<Ø=˜š >ÖT‡>œaC½oh¾îá=óa ¾/½A=TÁ*>É.,=“›½û©¾ÉG½¾YϾ•�=¯±¦·=�=IH·¾¬YA¼ i¾÷êU¾ÕC0>¸êr>Bm|>�,=Ã>N|¾qn^½ØK0>kd9¾Á/¿°–Þ¾k�>D4»'ui>•oD½Ñ‰©½¬nH>’懾³~>$$J¾ õÿ:kvоù€¾Y X½Р½Dêz¾nSƒ½+è=ƒÿ>"Bî¼Ó ã>@ô0=XeŒ¾ÿ{Þ¾‰¿¾î ¾OnK½lt”½…3€>È>>�—=€…„=X*~>³Š<‚ ”=ýÒ?>ºø>|O.>gª< pn>F œ¾H}[½Ãª¶½£!=ÐlÆ<�Ï‚>gÁâ;ß4�¼e<ç=1ì]¼’P½|GT¾´ÐR>CJ¾ûl¨=ž¬¾Vð›>ˆ>¯¾Õ½‚Q=¾Ú•¾©ëV>ÛÎÒ>K>9…p½N8ƒ=Éùœ>8Ùñ;¬5¾4)¾I�¼T½ ¾•<�¾Ç޾Ñ-0>ªH¾ì“>iõ¾½ç„q>ƒ¡c¾ï-¾-®½¬¿>D§=³>Qµ+>u,5>Q�ƒ>F«,¼þè=yµi½b >'<@¾@˜?=—':¾>÷µ½*ÃG½¹0–>&Ý=ôJ>ª¡Ê=á•>¹F€½×_¾Ð›·=“{ =Ö}>�É+¾U½½³¾+½ÎÆ©>þP®>‹×>ÆZ¬¾ð>>ª?I=šæø¾Óé½à>¾åS=ŠÞ:>óª¬>€ý<¾Zjɽ?Ô=[Ej=¸W>Ò¶á¾p›5>…%ž>¿ðµ¼ãÌ™=}«=…bi>Îyõ½%t>Xä¡>Ѽo>LŠ?Wø<+×˽‡ ˜=€N¿ªÈt½Ù¹>¡V]¾M”®>fb¾híy>ô–õ¼™ê»+C×=D|š½Lk¾ô~ä½VÌ€>ýÀŠ»Þà ½è9þ½ZaÆ<¥P4>ú:º>ÿ€Í=û¢µ½,{>,n–¾Î“ž½² ‘¾jIÌ½Ž‡¾,»«=§ž>;Š>‹Âd½àJ>öì?>ñq%>ZÂÕ½ œF>³ð´=WšÀ½õ;(ek> G ¿UNà>Ì(?gy”¼µ>ë/ä½XÚæ½É«¿>=€à=@ |>ù>ù=@ ¾ ݈=9¾Ý= mT¾Ìú/=5G?¤LɼY¦Ä¾¦ìB>uN̽0�=§›N>àh/¼P×¾²0…>"¯$>ý®%>v¾Ómµ¾ºÿ&¾t¾ñÄ[¾+«¾îaø< r*>º’œ¼ÖÇ1¾”KÄ>yN¬¾†&ç=îg‘=´d1>-â½Ô<)ؾ1Ñp<¸16>!×>„>.1A=[2ä½™cf¾V˜Í>É¿¤¼ÉÆ6>o‡=Ê¡ä¼ýÀ2>PÞ…>f©‘¾5�ýe½U>´¸4Ë{¾F5k=Þ{S>K>UéÔ¾*Œ_>6ü~>yÂ>z”è¾ä(> ®U¾·7¸=ò¼¶¾ä›É¾�GŽ>´°=#¾|%ì>lW>çÉx=Fo‡¾ÜN¾Xç"=&SÝ>_Ÿ¹¾À?¾^tg½Rt ¾ì?ÏXO=«B¾ö©Ç<0a¾ÛÈn=!äµ½^õ>¸£�¾Þ‹¾ÉÚ<Û?ݽ%¹î=îÒ~½2Òô¼æ^4>?’¾a—ý=üy¾�F¾Íѽtz$¾au=ÁM¼˜õb¾$6ó½ Á©=�õ¼ð[ë=•É´½ ìO>7DÀ½]æ=×*h>}‹L¾ÀÃɽÇZ�ºœÞi¾Lh„¾âj¾î묻O =>n@¼ š—½_X½¾Âo=Ej„¾Ÿ»2¾Iq¥½PѤ= 2—½búþ=Ð¥–¾ŽÞ±½ê>¬>ýëê>èɺ=ÿ3À¼U%�¾7oð½ Р¾C¯¾üËT¼æYá½È£q¾ŽþI¿M.±>®оF‰%>ò·…»VŸ>>ý»o½qÀľ/-νïG0½nÔ>Ìþ�>É-a=;Ú-¿£i¾½ñˆ>ãè=zfÙ=Ì I>U0ƒ¾„Oy¾¿A�¾UWþ¾FC½Cd=BWû½Ã!3=L ï½?b >ôç£>Æ`=2Q¾ÌÌÃ>nï<¾dë‚=R­>ÓÖ§¾E-×>¥+¾®Ï=‡þG½— ‰>q‡1»˾«ÈÚ½Ô”M¾Ô–T¾‘•¤¾&ùë=Õ±> hš½M§ >„{1¾t­¼=ëÎþ>)Ž=ùwœ> Î>ø¥>«mÖ¾„PW>&—:=}ê¾$æ9¾í?ô¼S=Ó‰>G7–»°0>G¼j¾¹-޾èw•=¾�=Ú¾uo•½e³½\À§¼”>o¾rŽ™>¢ŸÂ=îÐÀ>ðÓ=sQ>ÓKÚ½—³½<¿˜>δ<÷z¾Ú¶î½L2=Y¦¾"Ï"6ÔÎ=<ß=gø^½–W¾J˜ã=·:=É�U½Ùn·½Î¾;¾ÊÙ–½Óit>—ý=»ÃH¾Ý?>Î><0о¶ù>$É꽯対Ÿn÷>ø>û¶º½WGI¾“^ü=35¦<£<7<ͬ¼·R�¾V½NMy>‘á¼²˜‰>ÈÃ=¾ªž½‡Ã`¾¬öƒ½&×9>™ÆÎ<±£="}ܽ}m¾&ï­¾ÿSS¼’6ø=Rù½ÔºU>åh>gô>ªh§½�#«½8\¿X�d=ñ‹>þNG>œsì½Ó뤽jâ—¼[šè=%£h½ëˆÁ½W*«¾nf>U>†¸/¾Dúo>6¥þ;¿>1ª'

–aâ½^tÆw¼=H๽ R¾ê>õH“½R¤�¾ö Þ=6¬>œI@> ƒæ»*¶¾+Å´½Â¶¼+¤º´ày>Uð½>˪½Eï´>Ïw>sľд%>Œ5>^ra¾Å§ì½s½L< º»Dóq>–Ÿ¼¾öw7¾oi¶¾­p�>?„z>ôFɽ“zc=Ü�†>4õ�>¬R–¾Í¾Ž¥z½?Œ�>¡$§¾ó¡j½—™C¾”î7¼B„´;ð?j ò>[Òx¾“º ¾a{š>u¾ß½�çƒ>x=ä½ì>A¨š¼øZß=��=a�=:=>=jÎ;Aƒ‘<ak=wD>Ò¼=>3¾³ X¾ µ½íb¾!¿�½Ž-ò½}ê¾Ò™U>óA=?i9>úà…¾oO4>ùHð>¿Åо¢ê¸¾"¥\="ð<7ÕØ= 1†3©í¾ºÓ¤>¬G)¾åŠ¿>õ>¬=‘ŽÃ½�K•>솽éc½¾°5>Æ�>†½#>«»„<Ì„ž>¡âü½¼^J¼R}%<‹e?-¾:¤¾E´Ë¾3¹>}µf¾_¼ ¾ w?ÜTO½Ìk‹=¿¶´¾Ù‡Î= KN¾�b=RÛÕ½rLµ>6é#¾…¼>Ò\Î>†X=•—È»gOÃ>†9h>Ùaº=äA>Gi>‡ ¿½*ä†=Q®|¾Ÿµ>eß­¾v¾›=´�ù> ?`Ø¿æ°=wµü=¼ÖI¾lã¾£ù¼¾Ð}=£Ç¬rÑü>n<×;{?È>ÆÈ¾$"¨>¾zœ¾À¾o¾ ˆ >¦ÊOg>ÂÁ:=¬‰%>¦j<¯ßt>š2|¾ÈÚU½Ë-a>Äs>¿Ãü²ã'¾�å~>’@<]§*¾PNÒ>þÉP¾M¨¼÷ �>ä¥P>¢Õƒ=l­¥¼Bž¾`gœ¾nnZ>õŠó; z½ë–¢½„5a ¾Ð/r¾y#°=N«Ì¾f;¥†=B¦=½‹f{=»´v¾‰èÝ>(©l<"þø=°‡^=/]¨½é=Ü=`“=Òƒ?Ì�8¾ƒ¿S¾<º=Ôkþ=Y¾œ¾ßš ¾Åµ½�¼Ï½rÑ9¾ãƒ>»ê ?U$=Óþ>)ð’¾{Vª¾ >º'=ò;Œ>i_ß=—;=4“ñ>n¤™½; ¾½Þö¾S ½à'>Æ8H=âA‘¾¢O�=éX�¾©]¾>;Y¾…ø"=»õL¾Kµ@>>ûU¾ Ö=Úü€¾®d-¿U!ø¾ûæ0>€½=õŽ;>A^D>Q^“=+þ=Ö˜ë¾QtD¾©rÅ>¶ q>v\’>ÉZ;›©D=,]×>Mªé=!UE=ø+¾¦ýi½¶¹Ý¾+ê=¼îÈ=BíR¾‚²?=°¾«�¾!�¾9ï=+ý4¾:4½åK«=Øn�¾Aj©>!¾„Žé=çžõ>ßf?/h¢¼e”Ö¾TÈ=f`þ#ô€¾N‘>1Pà=, �>Û˜½Ëˆ½’À|=V‘ˆ>褾k”½í…½Fñ¾‚†¯=l½p½ÇѼ` >¦5“¾³f¾9|;{ê´¾ïï×½ZIl>¹É>C5G¾=P¾Aú*>Þ•¾Oîï=–ì ¾æ¥Ý<¨W,?.¾@³=>È¥K>†,[¾Q#¾î2.>ØC‡>0ŒÈ¾ÃÞ[>Øk½w�½½+�J=€ØŸ=–‡�>ßÛ˜>»X=õ°¾³ƒÁ=K×±¾6– ½�Úù>­Ž¾°ß¶¾z7‚=SNº=¯Œ¡>+þ5¼Ä©?Í\¾úo¿ºXÞ½äïv¾â±±½Í,´¼3º©>Jþ·<Ê›€>; ¾Šqî½=;m¾Ä† =Ó>pŸ—>%c¾ñg>€ú9>'¡½›�½¶ˆ ¾—$×>°yŒ½‘“Ú='¶¾Ÿ®'¾Væè¼ÚjÊ=ðý½=h g¼œÚW½ªi†< ÷¾¡ ÷;x˾?ù½¹8¾\޽ê½¾˜ò)¾[yÈ>°8á»ÑË¿á;Ǽ��\¾ßÒÝ=Ir²½ø¼%=�F�=wlR=ï?½�'Œ½¸òq¾×Ž+¾—Ä=#몾Ǹ\¾=)>oÓ+¾¤ˆ=uê>®‚ͽ/™9>Fð­>‰äŒ<„Y¾ó+p½GÆó»·�>®Ž¾se€º¾‘V»Ü*Ý<»�¿>ÔÈß½ÜZ=�¬`¾ß„C=<ó‘= �=¾Öa›½Ä €<½Cñ½\È·=û-¾‡iò½?AD>Éy¿½«¨>>¨<­¾^ë|»üC8> §¼Ë¨A=ÍâA>Al‘¾07‘=Ww ¾þ³¾k ¾„Ö¾>e�‹>hÆÊ½‘ø~<“"s=˜ä!?Ó¯w¾±l&¾šào>gP¾vé>w.½ºˆ>­=²¾q[¼ß�à>÷÷̽®ŽÓ¾¥¹=踆>†?ø<5õ·»«‡Œ»ß¸w>¶CÙ¾¢;%¾™uD¾ÒÄM¾ ?¸½1@ؽcRØ>à=k¡Û>7üæ>f,½Æ¢›¼ „ë=sQ1¾Hÿ¾c*¾ðâ°=t %>É6M½dñ!>[í»å´ð¾}@K>†Ñì¼yÚ>æJ¾ZÇ!¼"•é½í´½«í[=�ä@¾ø`(=?�±½k?h¾,( >nÔ<Ú#¤=íò?Èr3>JÖª>Ð#!>IèK¾çt†½i“½‘jã<§.€¾$¥¦>—Ȫ¼Pƒ>Û™­½Cä­=©r1>Q¬«¾×Ö<µ‹½Ü½F¾”?=[>¤ªŒ>t®—¾s's¾z,>ä =+›>.¢œ>+_>W>.C½ Õ½=â�¾™±²=<Ók>š¥=¸J>Åa¿�œ¤>¦È=„Ž=kþ’¾�h§½JëS;ó³$>éÆÌ=|Íæ< />ø > &о}E7¾Usì>åg>5”÷¼èÈ>›9ƒ¾ôË->q‰¾„7ÿ¾¼À>µª>–Íž>7ø5¾Âßg¾q»‡>�”œ>þT5>{m¹=<Ì©=}k >­ ޽�ÿ@¼©f>$±>ÂÌ‚¾6O½²Žü¼q�9¾y#S>Aý¡¾$ƒÈ½ªˆ@¾´µ"¾öo¾i/~¼4u޽¦w9>³Ã_º%D">·)Q=\_(=¶Ð>ä~½;å>C\V½¸Z&>eÞ¤>ÏH3|=õ¿ƒ½aˆ)<$¯=ÆK§>@â”=yb#>Ãtí½ŽN>rµÃ= Ã=S#н :>ßHä½ûà™>`.s¾µ¼�>ÜLˆ=P‡f¾�”½·e1½lÿ=7û¾½°<3»ª?ó¢"=ÅÀ¾Ÿ½A­>>1Û;¦E+>Ûù–=‡<H«=n$>Uß½—X¾$¾Ä?¾UŒ¾DÆ>,EÆ==¼#VGźz%&>œF¡¾N0>táí=²;>Ù)>&v£>ÝNŠ>Ë1´;¼tž>¿ï²½m{M¾DL!>h7½Þ¿‚½pF–½AwÂ>û(¼½xþ9=aa>>*–ê½åˆŸ½t™>†‹€¾FÊ6>:°F¾Ý_R¾ú1Ç=Ø‘A¾õL¾¨Ñ-½á2༟ñú½ÝeÞ=Ñõ>çð >|‹¾©�;¾­œò=BD½pd»7µ=Σ†=Gnƽ™U'¾ç”¬<‰tͽ½ÅG¾(´¾©K½Í¶þ½ÈöL;'ɽÄ,¦½Q˜@¾Ð�>82�=‰ß¾„J¼Éç%¾ÔŽ}>˜Ûâ¼ßsT¾BA¤=;Vg>‡B<Ùë<}Üï¾Â0«=U‹Þ>*@�>X�½Ü3-¾Ó)9=˜÷Â=§ý½�Q}¹MV…½ÿ21>@#оM4ª¾€¾M)i>µ­Ú¾a‰Ÿ¶m9W=2ÙÏ=œH>e=Žüö¼'K¾Ìòž¾�V�½²Í½>³t>^fE>ÌIµ>§q>çð’¾Üíµ=/¯J¾®� ¾j5¾›±#>ž=u­1=ŠüD?µá½�! ?P$é=¾ËZ>8•<žÃ3> Ñ»=“–ê=¥ÔÌ»’Ð ¾ìæ¹¾•¼ÁVK¾å ½¨³»y ß½&™r½�.®=7/3ßÜ< oƒ>2Fý»±':= =ˆ>$^ä¾›�9¾ŠÒî=o™š>½DŸ½rsR>õ?a¾‰‰ß<Ë�>Ò j½x™¾´œ–>ŽŠ¬¾og×=kO¾â’Ö½²<]>û’¾–lß½üƒ&¼¢ÝF¾Jôz¼vq:½ç�¡>o:?¾^jS>[A¾ºôŸ>Ú y>"r¨>Õ¾x?¾ñ ä=ñ2L¾TŸ¾]¾„²¿^1>Žªþ½µ^¼ºÝ¨>½/—¾ÚÃJ<ч›¼?¦½*m°=Â#~¾S$ö;b—Î=jþ™>2h>˜­>®Cˆ<-pW>“0$>Ùuø½�TÙ=tî'>aDß¾:ƒå>˜ê¾9òB¾ÁV�¾ôr8>¯m>¦îÆ=$��=ñ�%>S×¾h­Ž>M�¾g�2>Ä«¬¼qFW>¯1&½¡GS<=ã=b¿¾ 䜺ÆŠ<ì‘>Z ‰=ñd=6Xæ½sjm>Np¿½Õ á=Ö£ »–¶’>Èn†¾¸…q=¦>˜…]>ÝX-¾êk޾šiP=L”{>fMn½}üœ< s >öRÎ<Õô£<ºÐâ¾}K’=ù ×>L¨¾ ]V¾ 'ç=‰Îd¾¸1'>ˆ�=T’>Åñ=xð¾àªa¾ØœÉ½ë™>'=‚¾ ¼’>d„¾´ª>»,ò=áØe¾JŠ7¾^éô=rÛ÷½^ý¢¾C° >Ô0>žë¶¾»1>´Ëо˜<‹=GyH»5‡¼æl¾U>¿¯æ=‰V}>ò¿ä=þ’“¾ƒˆ•¼F®a¾5pD¾¼”ý=„² >œ�³>ý<�>‰’ß=™¼³œD¾,;¿ÍS\¾x˜ª>AZœ¾É§¾éä�=H'>¿ø[>¾µš<o”¾øÜ¼½0üO¾40½â C¾.±¹>ëƒ*>Ò®P½�L >A83¼M">�Af>U•O¾•ýÍ<̇¾|Œhºø¹ã>q<á¼x>�nª½n½œ*6¾¾/q>E—X½ÄÞ?QÙQ=I�>ð£¾â÷p½MŽ—¾X,¾YľâKê=Ⱦ…ëܾý±ˆ½CY=ã b=Åa.>û–Z¼ìü¸=y^Ã>hjû=0W÷½<š>qÔ­¾¥‰f¾¸µ¨>w×¾’àæ½‰m=÷¹=¦Å¾/[?€ìv¾žy™=︩<¤‘‡¾ïk¿¼a¾ÇL½!‚¾F•뽉>ª¾:Wþ¼�‰ ¾ânϾÉÞ½ïT >nN0½îFɽ+òe½éR‹¾øg6=‰ZF½Ü”•=¥B>ÅJà=øS>VUg¾cð¾šd+=Ô$>¾¶“%=‘¾g¼sß >‘®¦==Pö=¡ˆC¾ ¶®>2ö¾§ì$¼]å¦>V³e¾p0`¼åÇ>W1?Âä®>¾V±¦>À“²¾±é¼Ð3ø½95¾)í3<¸ï >[m]¾ÍdÞ¾FªØ=5ó>DŽY½ ¶»ËŽ>o‘…;ÇŠœ=6?ì=”hº['ý=Ú¯s¼°XÀ>,¯Œ=ýŽ>­0¾ÊB =4�K>— ó>ã}w<&ƒ¾ 17¾W·5¾ ø¢=³œE½\“ñ½J¿Ê½ÍxH>ñb#=p¨îu·%>™Æè½8Û½³&ƾ:dí>´>ÖÉf¾H•>’f¼½Uš´=«ÉÙ>Ô8!¾Ó¾>ù�=ŸÝ'>ká¾mæh¾Ë]G>'«=E•€¾8Ž}½‰=¾ô²ö½Ë›Š¾pøé½5ƒ>xf<¾‘‰¾ ÷>�m³=>¹™¾�Ì>yc²>x4>X$¾øñ:½ÔÀß½×¢ <éh{½ñŸ ŒAõ=wI>R>«¯7> –¾.Ê ¾¿¥<Æi¾ á ='Ð>JŽ‹>˜~½&‚#½çü+¾wÛ¾XÖ—<]Ù¤¼›áQ<¯«'>¬p<2wt>UAA¾¶é¨=s 2>uf¾®{#>—`”¾&{¾€Ö>Ëc}>u~õ=l”½6g,¾æs—>·>=œæÈ¾J×Í=ÂJ?¼í;<Ô^¶¼(ì½=·”=Î)­½Z3g>Ýß›=òÝ+><Ë_=!R>óÞ>!=àÂÒ=ZÁ0=.¥U=;x»<± Õ=¸}‘½~¾5>dþ�b¦¾ªA< ¤ì<�•'¾%²Ž¾Ê�š>\q=èÞ¿>£!«=’ZB¾^t2>k*>ӂɽAÄ1½`»Í=ð±9>†‡¬=Ù ç½4*¥>-=Õ>ðk¾y5Ç>9畾¤8>c˜D>]#>õc…=}›á¼üä¦>Ö¯¾>É]w¾A?’>\Ä$>úm=‹,/>³<]ó<ÈuÔ=Лô=:á>êë’¾‡�>ï\>3žò¼nÌI¾ö_>§T>ˆy¿‚‰ ¾%‚¾CC¾ÛB¹=-D>-kA½féV=ÇÑO¾H…L¾H ¾?tO=Å2I½­˜}=ê�¥>!MŒ>^3�¾sï‘>�„¾ iº½ Ì;q;>ª[�¼m¸ ¾¶¿�=N¼¾芾îû=Õ›¸½±œ­¾þj=Ø™;) p½¹XѾÔN•= )9àzt¼¨Ì™=ÿ“¾Ò¾‘RÛ=Í®U½ÒÒ¾¼'|¨½qY ¿ãr>…N>ŒPŒ=º—¼·œ=™±Ó½’!K¾U <üÞ¾@u>‡Øó½ÊÍ�=%Õ¹¾ì?…¾Å’ø=¾Wð">=)7½ðσ¾ôÕ=3îÞ½z|¬=W~�>\ #¾¾½H=�½è½¤œš¾ÄG@¼ž°é=i<=Íi<‰Ow¼U“%=³=ÜS>°X¿rïP>öŒð=–ðÍ>æ'*¾Ý¾>òD0½ø¨Ù=0p¼=wÔp=4c>ýB\¾n%€¾-+õ:Î:½· ™¾SŸ=x(>Ôë4>6à/>„U>÷ä¸;û½�>l¦"> :н;&d=Œq½}ê½ÒÔžv‰¬=—Cž½©·®>d‡½w¼v¾ô÷-ƒ#«<åº>íöã>\å¾ÚsO¾„3>�¯<›v½].¾E}Ã=l Ó¾¸5¾”gè½·¼¸=/®°½‘ŠG>·)«>µáB¾~^o¾~pt¾øä¸¼Eì>9KP>³û¾O댽*o€=mØé=2g½×aÈ=6ľEÞ6>–¶¸>V#½u-¾°`¾0 ¾—»V¾ÊÀ¾ÝkF¾”f†<éö ½—=Èq>Ó²†¾‹>$ŸŸ<%�>¦ƒ‘¾(ä;¾QA>t”½ì ­½Ù08½´ƒ¾Ö&€½ŒäM¾bÖŠ:°ŽÄ¾Ÿ±Î½91‹¾3ÝÖ½™�1½ƒv1>°t7¾3[½¾!|`½«Ñ5¾ÈÇ>“üõ¼_3Ù=áZ•>ªaj¾@Á>¡�¼ôò=N£r=Îó`»ÊŸ6>šR=+⥾ŠÁ=Ó{>‚Å#>Í·¾œ4©½Œ"U>,Å.¾Îq½B]A½^i`>tù³¾‚« ¾Lë%¾uTʽC¼Y=|+=g ¾£ÿܽaq ¾ô�?1¢>™”ô½‡o)¾³÷w>%{=E]>$ù4¾¾z\¼± �¾-ù=¾÷\=“¢Ñ>ªtg¾Éÿ+>=l�>Þ›n¾y`¬>ƒ—y>>À¸>ü÷'>÷ß ¼')e¾^«T>ke9>Á–Ľ+<9¾nø ¾�±» »*ív>­VA>è!‘=Ð|ˆ> T€¼?,>J9í=FÒ2¾|� ¾‹×r>«ÞÀ½Ê˜=ë“�=߈—>Œ\;>4¡´¾cT¾“Ž>޽‰Ä¾Gá½Ø-+½S“I¾ú'=²t »Ú$9½B放ÆÈ\¾Çó(¾pÛ¼>‹þ�¾g¬¼—Ï»½T|Ù¾„}ˆ>Ø%K¾1t>t> çè=Þy>l V>jÕD½��>�ÕÞ½w¶9=Ö€Ó¾}U®=̾s]>˜4ß¾ôÿ>ɆÎ>|Y˾LÇ>š í½¼šó½ü ñ=Å”—½²ž¼¡¸ñ¼"ʾ¨TŒ>ƒ‚ê<6e½Ò÷Ö=àq“=*ñ€¾Ë«»uû¡¾™†Ž¾U¥¾‚‡½/=;S¢�>‡di¾üT¾çìf>â­�¾B½{•<8¡|>«¨=¡Ä!>Ò–5¾½d3=V]^>>ˆº¾x¶Œ»€ZË>=>T„\><Ÿª>–¶A=u‘<™Ü ¾$vé¾²†ƒ>l­þ½½vµ=‹«L¾Æ¾œ�Æ>�ˆ >ü  ¾ZG>ç¾.”>h$Ñ=( N=þf¿½Ü=_Ɖ= 9r¾c )>Æß`¾ãUJ>$*u=K°Ý¾å¯¹¾ÉªÖ=¥A0¾±Æ>Gö6=› G=|è¾l¶Š>aî>¦g=¸èç=°€�¼ó—Û>j˜°½ðù=à†>=¬’=&9‡¼Ó—ÿ½“¹š>#�¾.“>Q€!¾Øì>>Ôó<†7̽Ü×=êêd>uy’>Ú¬æ=¦óc¼k9.>ýŠ>}=À¹ ½Žâ¨½Áä=o¥Â½Á'=G©Y<ÁU½£´ˆ>Á_=䳿îw½¾� –> —¸=S[µ¾®B@>ÿŒF=ïÞ�>X�T½Óø»=/œ¼Ð>ÃzݽXä¼Û\=TòÒ=w|¾â¤>34µ¾×NÓ<›<2¾II0¿)…»Axe>‡‚8>Ç�H>ºŸ>|2>®=+UŠ=R¦«½ç!�>‰’9½<Žb=Q›0=?!•¾¯Yu>“´¾à5Œ½•Ý�>4kÔ=ä7ú:"j~½jâç½ðZª¼Waå=Ôí’½uò½Z�*=ð<û=äfN¾/€ ¾jPA¾1˜¾‚Ú?>xŸ¾†Ÿ¾TC=©½N�¾Ê<°¾:�ï>Ú`=>‡=V›À½8ÕY=Ò„‚=RÈ|=’mÅ=¸®ç½º|‹¼UK>ØN¾w¡i= À>—†¾ê…|½uR€¾î3e>ÂÙ>’Ò>Úˆ ¼"â�<F;>ÉŸ¥¾4"»6Ô;>¬×b>ö•�>JV)=ai1¾ÔÝr>�õK=eÀ£;ßa3¾M�‚>9 “={:=¼™S>‘¸>©œª¼è€”=¢U§¾DÖ<=Ú!»½®˜K<àö�¾H)§<Ü”<|Ât>&£s¾ågh¾†s½‘"=ˆ>Z’=ôô>‘?€õ?Ñû›>Â…‘½Ö–#>f¡ž¼:¥¾þ;=Í©>½k&i¾èl'½Í³Ã=Æ@>ù,´> ÿ¸½�EÙ>uff¾½W®½gK=Þ¦>‡Õ¼H’W<r7¾§B>“ =ô¾{ÿâ¾4†¾^I9º´’¾–_Ž>+­¾`Á:>ün>ò6,¾|ŠÕ=½Ý@>i!B>|½¦Ò¼h� >õ (>™P>S‚&=æ[•>UîQ>Ù= �¹=+Þ½3Kd>�µp½áú¿®A¾€é9>•fT>íê¾=¢™­½_è}dY½&ÝŠ>¹ø ½B´Q¾p�q>(ƒü=ˆA½á¼±½ ®>Ûk¼öؽ¢u‹>‚‘k¾9á²>* ->¼ν½ÍÝ>ªˆ"¾'FŒ½sv >“•¾s» =å;&¾¦0á¾D×C>Ùù=á>UYɼ³® ¾z6½¾0ÿü>ï뽓¸=]å_>‡Ø�½5öÆ>'« ¾¯x¥½v*ž¸š>øƒ�=Í ¦=íp3>;7—>¯T>ÈíÊ>ð<Ö½Œ>*$¾½}¶ô=I®x¾ZÀË=aýý°�½¾‹ü�>s œ<ÔkÑ>*¾™‹Õ=©ï:¾ /Ö>3Æ~¾ÿ¿I¾hçÙNa>�Ïç½9¶=üq/>±î„½z…¢>ß=³<85=û½¦Ló»¿•=¾†ù\¾V'�½U�¾ÅôW½Õj>ñ˜={o}>"Ê�>‚Œ¾Ã ѽƒõ¿¾–Z¾JÑL¾$×’;ÞŽ[>åç¤;LÓg¾µ7ä¾$Ñ>æ+>²2º¼-;¾-œ©=}óϾÂF)¾†—ƒ=û+¿¾!½¾üv=÷ù=n“;=2$¸=‹=¥·©>†6>6}º¾1�¾C�¾ÙϾŽA7¾*~>‚%6>=3½5ÿÓ=HÈ„½À¹½½Å¾Ú õ½Q… >„Ð’½5cÕ¾ÍF>ËK~¾½Ô½%3:>d_¥»I">+оOB¾43¾Yù†<ù؈¾]3>ˆ h>\@Ƚo*>ä-J=(’N>i›=XsܽË=‡êy½_>¼}*¾=£¶=j˜/½®È2>\ä=ïd¾§àI¾$áÕ=Êyè<ƒv{¾†¶<¾$܃<šî�>6½B¾ø:¾tÞ4>:–ù=�̉>@Z>ÅÍŽ½Ïéè>D*]=¯²í=µn=k/ˆ¾¿5E¾ñ°¢½YZ×=9¥¼k¶”=Ò�>™´A¾2\?ýë½vI#>.A¾¡:¾¾òå�¾˜j–=á >Œ=¶¾›Ž=Oq=‘+›¾Qah¾FŽB>Åé½èP>Ÿf¾ó§a¾»ó$½¯¹>Ú¤>©~ë½¹öÕ½¹˜h>>3“=Lž½£+(>HÝÅ¾é ‰=ÿ¿Ð½P‚¾©ž¾:÷<êrr>éâ=IÏD>MŽ7½SœÞ> V€¾,×½!¢0>ë{€=³±Û¼8ð>±Œ¼Hžì=¼5i¾‡»×½?_¾‚Ó2¾²x„=:>_Äa½›eÃ>ÖÚ—½¢0¾? X>V„>Râœ;"¬è=Hü;<“‡½ù7¾S–­=^+¡¨@¾�í?…Þ@½�[½ÚðV¼1µ8= â¨=ÅŽ>¡+f>}Žˆ¾v!¾ú�8>]s�¾I»¾¦¤½`}½Ò’¾id¢<:¿F>_Âù½!}&=çG ¾ÐJ|¾Ú@¼¾æ9>Æ;f>ÿÚø¹[¯½ðѽ…;>M€H¾x³>®“½Úû >WkŸ½=�À>¢S?×*[>åé.¾ 0¾š.=ìÕÿ<#È}½ÛïF¾«¼ƒ¾¾¼N=L%¾æ—¾>àw<¾'œ;‡’Š™�…¾'jv¾•Ÿ¯<[áݽïÿë=&i=7ñ¾°K>½0…>Ž©õ;ªÍ‰>í«²½¤ç> ÷H>l%t>ÓŸ�¾œ¾är>=ßÿ[¼ñÌû½ï¾˜<�~ú>­(¿½4½·~7¾Rô¾„«Å=yó»–Ž'=Ï�è¼j��½Lh°¾îç»; P¼Õwi½¡Fß<)Ñ”¾üB >¡Ò‘½ÍWƒ¾OS̽=Ÿ=L¿š ¾ß:ó;8˜>­9½yj°½œ½�éX½K}y½ùF’=ù'Î>ï" :!%­=‹´!½›4̼ÁpÇ=U¾};“>Õ˜'½ÀB½€_¾0ëH=âH>­õ½]yÇ=¸U»=†8¬¼É }=þt¤¾Ç³>(E‚>»`f¾¯è¤¾Ýé.=•Ù%>�&¾d0¦=¡øF¾ï4Z>ÔI¾¾èŸ¾M\¾ò�b¾žØ�=íDâ½ê[š=Ø6¾4¹†>i2½àT°=㛼òÙý=é?ˆ¾hU‚>¨–¾Õƾ0½ˆ>N·ž=-n¿¥•>M ú= ¾Fá^=£ë¤¾.W>ó7•¾›îy½ßÿ•>÷"È=j_½až¾¶Õ*½•šü½T½‚ ƒ>@𢾠ØT¾’ý·»³ó½§ì >’�$>?Ða>xlš>›l >Us¢=ÓˆE¾d\‘¾T†2¾Jÿ¾>eS=ÂEj>·¥Ò½þ"®=»m�¾ô|ä½Ú`á=戰½]S=2¿C¾e+>õ9¾Ñˆ¿ÿ q>S,<݉¾m—¼ï’Œ½'ñQ¾¸d«¾¿P{>[ëI=$Îw>ÒËþ=“Ƚºkž>æ+°¾píÑ=èAe<7X÷;rñ >ºp꾊¾G¼Øìé½Í¯‘½‰îˆ>Ÿ Ã;D¢>Ò8>)>½k ø¾Ö ¹§‘­½î€¾=Ú’¾Ïéó=¯ˆÑ¾- >-+�> û…¾¾�ã½9ah½k ¾ŽeW>ò½Ø—Õ=s"´=D§¾mŒÀ½×³þ<¸Ñ=ž3<fÒ½º’½’}Å=—î/¾a<¾Ñx?–ª9>‹=‡>?�¿CU½ =ìk½þ¦2¾¶¯p>wf9½�;¸=O}¾ Ø<¼Ø—½B6:½Óµ ¼Åô¯>Ùî>¾™‘>7%>�s ¾ÝÒ¾0;b>5”>Ù ´>£-I¾c!A¾wùë½vÈQ¾��>ր輂肽�m°=_oƽŽÂ>¾ÒL¸¾ë5½t}¾ÒÙ>¡>KBf>Hùó½Û�½Š @½Zä¾¾…åæ>Öóâ»Ú>7¾ó#‚=X47¾c2½íoǼ»о}F³=•Ö=ÚÛ>Õƒ>”‚¾&Y‚¾‘¥6¾qx=kÜ='5>®É>Óh¾¹Q¯½¥O>�LÚ;ßà<ë½ñBU>‰è•>ÃbW¼�ZÕ½B½¾ðyʽ»S­¾cÃ=×ô ?·z¾˜ßµ>£>ÌŠ$½„¸©<Ô>ï,>pi>˜Hß;èë =÷Ð¾Ž‡¾µr¢¾Áóc¾•½øi‹½¬¥æ¼ÛÞ >l†¾½KÓÍ=PëU=3V»¼©>¢#A>¥…Q¾Wò¿½tDN=>6:Z R=¡’¾ƒ½>�!&=jŽè½ju>ÖN®¾æ~Ñ=æ´½~:æ¾úº½û¼ ¿<_¼ÐƒÊ½ˆ©Å½ 8±=¸|°¾»Û½– ¾q„<áµP>a·=TÍ<>ÀѼ¢è>KŒ¾{€;>½ø�½G=;¿õ½EQ½× ¾!„˜>ó&á>6_C=`o;¾U°½?8ø<>é=¾=#C�8ª>Ýš¾¾=¤g¾\Ds¾v”>WQ^<ŠÈ=u'=Ð[ ¾Ò?f=œŠ>¾P>Â6>=½YŒ_¾ÇÅ.»ö—)<0©Ú=DÒ½^a?—–Á>«Š¾Ìú¨=×j ¾K’˜¾ùÇ=(´ø>N¯>-Ž>@Ÿ‹>laF¾ïJ“=Vªä½àœÅ>åçì==# ½q¾Xÿu¾ÎÜ3¾Ìô5>4_7># Ï=;hŸ¾Í�&>%’½Ç;¼î#>áa;¾­o<½X¬’>!Mm½0ðò½Á”¼½‹�>øOÍeꋽ?Ñ>’ô7¾x½�æ5½³>M½‹ÿ5½·~„¾úW–¾¡OÕ¾¶ q¾•U6½�Oö=ÐOÈ=æt~¾&U>ñ?ð=‚x‹>‡ôþƒíª¾ŽD<>ø8ß½®Ÿ=ŇŒ½ã›�½ [Ÿ¾¼)Ú¼KŸ"=“ÿ=Øzx¼Å޽å!ͽÌ>‚>W¤<¾e¨=ýÂ¥½Þ«À<ím‘=k4�=VŠN¾Hy¶½à#¼h)Û»øNS>ó}¿øÛH¾GÙÛ>P—>öä>”ሾ^úÛ½š¢½ð>“åÛ=å·¼O¼±=˜,è>Ä9²¾ÁD:½{¶Ñ½2ï=QØ\¾;ñ.=`…>“i¾Ðð¡½@ÃV¼à2þK™Î=J!£½>æR><1¢>(ˆ>âã¿r®f>’Ù.¾1†r¾ˆÓ¾óŽ >ùŒ½=™Tæ<8Ê›¼Ñ¾�‡>Døy>½Š¾’ü=À|a¾jù>›WA¾@vQ¾Ö(r¾:ãg¾…݇¾È~š¼ï|Ì=2G_¾7">Í*¼¹š>âkª¾± ½¦èš=Ó >ÖA˽г•=+õ]¾�\™¾€9•½hg¼=¢\r=ožY½o³ƒ>ˆ ¾š6¶<øiA>"Ò<ët„>!»¾¡îù¾º®½qKÈ<Ù ü=/è¯>›’»Û!½DØ ½¿ˆ¾Ð#M=« ?{ͽaS¾õ€,»èÜñ½>ÙM¾ÆI(¾�(º¼Änm=¿'¼¾*ë;.Ÿ ¾Ûe ½ôúÜ=ËXX¾!ؾ%×0=Ü!=[0=ÒAµ=eg>³J²½Iͦ½º ={ô‰¾Ãm¾ÝE ¾¤&”¾]š¾£ã½Åþª=þ©=XоÊ>>N¶>ȯ¾ÿVú=?±ù½Ö˜�=ÕHT½ÓÆ…=¥E-<‘¡>!�M¾ñ1?—r ¾T‹½èÄ‘¾*n¾pÒ>œ”¾ûg >ErŒ¾‹<3=ÒÛL¾ûšy½ÜSí½ >Ðò=}6z>Ž”M¾ã2z=_q‡>­ã¼=øk>¾ãQ¾‚~>èÛ=Gòy=,_=ÜjÚ>2+N¾¦¢´=k8T>Ää½Ö)>½’¾º¼ç½Fo>­¥Š¾¬+>Iþ?¸í=Öÿ4½¿#Z¾v>ˆ>ïe‹>÷ê(¼&Õ0=š4¡>ðç^¼ûQs½x(½Í± >œ}p¾î¿}=éRY>UÀ²=7ÂŽ=2‹b>Dzˆ¾ôI>~?‘>Ûˆs>åïÜ=¸¼»#ªU¾!”h½Ù˜nd>޼ö¼@Ë>Ò*“>W{¾éW=¸@€½Ñ@><ì�¼'ÃF>˜O>½—n€½‹N>&öz>iéX=$%¾˜G=÷ØW>…•½yX >ÌI<çÛÙ½«n�>M>f=J6¾÷ˆ¾ô¿ z޽¾©�d>ñ>­:�>úHÒ¾†Nÿ=CC¾g•‘¾†õ›>pÿ(>î¾F{U¼)úÞ=îw2>{.¾=ˤ>5W‚½™¸†½vˆ>ØDÿ<±p¥¾HŶ¾ï:ý=tQ°½x¤Ø½‘€¾†"ì½&h¾²{È=èžS>ïñ¢¾oÎ=±t½ÛõR¾ €g;“3>–º ¾÷ÕÞ=p¼±½t±½©îo¾œ‘¸ººù>s!b¾åû=EÈ<`X>Ü ˆ¾€v•¾È£Ê½ö’—¾ÀrÉ=+¿‚>Êéß¾:§ç>çо?¤>Á%Ç=Ùp‹¾ÓŒy=½}ؾ¾Ò¾—À¾ 3¿;¨(>NïݼE£Ž=èíÔ>2”ê=j5½¥Ò=0ÇŽ<,eϽܙY>ËW=¶,¾kM>ÔÄy¾Oá½­`@¼([ð½ÔìŒ=tà>z-¾ˆb?¾#Qß>ò%‰¾Âñ:¾Oæý=™Y>;\>^ª¾·ò>í�”¾$UQ>óíw»Åg€¾`aœ½ 4y>Óÿ¼æå‚¾�©�=Õü =š«Ç½ÖÈÌ=7�‚½œSܾ¿^¥½Ü ±¼ÐÈ>r‚ä>¶ ¼îAu¾Ð˜�>=¥�>*Úô¾~Œ¼HD�>yª^¾™¾t» >ud™=!H½‰ÖϾÈbº¼R=Hú“½1˜¾jÍ‘>˜â¿6ŸÊ½[N¡¼ÖLï½~ܽ>5ï±=â5 >÷'£½Þ-s=ÝT>û›¦ºú{Æ=5¿?>Û´0¾uZ>+ææ½rÁ‡¾Õ>åª=3="½‹¬½½¸–>ðZØÕ°Ë Òǽp:¾)Ì˜ ¾ÒÇ0=SL$>φ¥;äÞu¼w·¾>V¯–¾Ö±ã¾IŒ¾Ïý]>ƒ > >Û™7>ÿ¼P¾’y…½C@%¾ÞM‹¾Ûî½/ú<¤Â´½DÄ>)cS=*¼xN:¾É)¬¾Ž$<< I\<”7<{—v=Šžµ½/åd¾@�Š>I[ÐD>Ù"¼y4ݼ½9Ð<.—ó½©1¦¾ÌŸÐ=Ú*<'ßf=&¼¼æô¼Õ«½úZ¾VÔX>/Þe¾ÖØ«¾– ¾ª!õ=÷Jƒ>>Ãõ<úÛÊ>œÆ°=¸5¡>ŽÛ<í–ý¼0=ŒÚº½Ê�̾×Ù´¾í’(¾–©7¾Îa‘¾½œº¼ª°Ð¾aÞ>l”\>‡Â¾ÅFƒ=ÁǾƒ›_¾Yš/¾esè>¿’>Ú¤½z‡>bàÙ¾Ø��=I{¤=1æ¼_>¯kÌ<]¬©½ÑÈÁ=/ƒ <Ý;×=ÐjͽƒáI¾:~‰½ Æn>Ôû½ex§=øko=æþ‚=Ó|Ð¾Ø°í½´�•¾G\r¾,¶P>*38­¼ÑâÑ=c&>iG¾»i‚>,ŠÇ¼º‹=�˜£½ˆ€>œ©A¾j{s¾¥Ÿ=ÖMF>¢,=µØ`>šÒ¾pèG>®E>OBI¾OPy½Xí×=M¬E>ÿ¾â†„>®¾íK™>0� ½ƒ�Y;™§‡½ŒOg>ŸâË>Fƒ¾a˜Š=ˆƒ|=2ãu¾Q³i>מÕ=:ã;>D‹†>{„>}"¾V¸ ½ OV>.å¬>Þ*¢¾ñ�;>T«< lû>Õßp=Þå½½„è�>iíY>Ž”å=7¼>£E™=Êb>òÛW¾SeŸ¼€.Æ=ï¡K¾Ó>Óä/>;·ô<ˆ†=ì•>;�yº>d3�=û”ë=Ö>[¡ñ»vÊB>çÞ™<±V»øƒ¼î̹½^Ù;á�ø¼èR½¨H>øub>wýz=çþ)>˜Ÿ>ù±>Ý�M.°µì&à½ØãD>!zU>Ð.¾Wwß=ýkÿ<¸‰>×; ¾b3<\ÅØ»:ºØ>EOK¾­£ »ùŠé<ý•Í=2+=Îñ¿+a�¾çB=Íúê¼ól<>:¥Y½¿´¾Ëòv>ôØg>ÈÕ>=ÎÞݽ1¢à½õ9l¾x«×=òì�¾m˜¡>P—Á=›�=ú`[¾²·½°UI¾í�©¾ÿ“R=«ÉR¼Ï²ß¾- Ò½¦šI¾âb=A᫽½Ú=6�¼ÊlŽ> 6‘>9¹?½>cŠ<&¡¾½²¶>ò1Y½y¨Ô¾³X>OÁ½{õ•¾)ù¾�Až½Ÿ'…¾Ö¯U¾Sld¾Ç—,>.¢˜½ ͉½æ›f¾èmÓ>©}-¾�¾«Ð1¾,C¤½R"ñ=˜t¾±Pͼòi�>Æ|§=änĽùèB¼ž�>üÌ ?…²¼ÇÙ®¾Ø`Œ½‚¯>FV.½±"´½|…Û½]¶G=²ì:>Y�¿]qT¾ î«=þô*½>Ó;)š¾2ß ¾.%…¾6Y�>Á옺+f<3q~>˜<.¾„Q4½�À½c%=<Þß=¤=¾N9)¾V¡½/�>螆>nåJ¾7Š·=V‡2> ÷¦<ÄiP½�’½Ž±{¾iUØ>yК=´o>ÔC…>ì¼wb½G£=YH”¾ìMc½0&3>t‡>�c ¾€Ã >ú^‹¼'̽·²Û=¬ ö¾–>¦Ð‚½2XÀ¹ÿüž=Â(‚¾b%>*æµ½‘k‘½Ì/>¨ÄC>Î>JP»½+sô½:¸¼�)¿=éñؽ;;5Ïj><>ãð½^ ø=±8—½[>EÖ¾ô®½¸8†>¨ƒ=Â]Æ>ž½¾×­/=ŒÙã=Úº-;1"Ø>¿¾‘»gù¾jÞl¾­›”½&7;¾„ºŽ>§BÖ=N!޽›W½­ÿ)>u*>y±H½F|=±÷Ô>Ë\>:}ؽzÐ6>R]W>$–¼–Œ=lƒð½õÜ=¼Z°¾‡Œ=Ê×½,Â’½8êu�>Šžz=-줾ï( ¾æFó¾àï=®�[½”f‘¾ÃÕP=0ù?á)>nÃ->‡2Óyþ�Wš¾� >LO‘½G2D¾›ü½S“Þ¾ãoý½ãa?>ö_œ>·ˆN>ÆÂ޾u˜R¾ 5™¾óâÁ>$CÝ=½`‡>/ëy=Ûaa>jS ¾Ìöû=€v…=肾à >?•�=kÍÃ=¨Ü½¼k$ >Yœ¸½¨JW=ä‡Ã¾!ƒQ>œ ÿ¼áyƒ>(Ë#½â¡®½yý½¾½Ý¾ ¥�¾iÄ„>Ùã>Ô2 >kz¾ÿQÝ=bfÕ=ê]ÿ=rÞ“>ÈY‡>‘ê¶=ï G>€Ž\=G=þ½+Ñܽ —/¾9.>;ͼ×'Ú>ý„½�ºö¼º)Œ¾}Òµ¾Z±¾]¨>»ó“<«QÓ¼YõÜ>ÞL¿¾»Ù:¾}q�½¥NؾÚV¬¾.—¡=Û,¾�¬q>k`= q4=zêÇ=1ƒ>§É ?Øïñ=4ø×=-¿u<+Y½>p¸C>)ýòf ¾sšX¾S¡<[YC>Ôý0½@ò¾±£µ=PïI>»å">š =¯ª�=Åói¾¤½ä=ÿ† ¾¯AÖ¼˜’ý½žñ]¾ÿ=½¾ÆBž=Ûá>4ò[¾?¨~>Jk¾uö¢=Ø|D>þÖ<¡w>þ±¥>�B:= «ç¾nh˽G8.>¡£½�Ÿ½òy�>7«ª=ý>£¥;>ø|½7–¿¾¢ q½P„«ºb.$>=é!¾¿;.>…2µ: à1»½®¼Ñ˜T>ÊO½Å@ï½ý‚˜¼°ýs­¢²ã%¾Ø=ÿº_>Y)¾£†½ž‘_>pñU>¦Z ½²œ%>)�\=‰#¾µñ™½þΚ½Œ+¾HP�>éÛ�¾¿ÉJV¾œå¨¾šÝ ¾ï¯>énÞ=4Ú{½á­°¾rd¶¾˜ì¾­°=®øÈ¾*ß?zu>|‚ä=l†›=ª¶�¾á ;>�¾„u˜>W™¾ü==Æ=–Ø>š»=; =WU¢½më½6µ>¤ÌÕ<ƒ™½¿0G¾v�Ú=ÄyL¾ñP‡¾ýµ£½Ë¬½_Ѫ¾&‰+¾…)¾óåÐ>Jݽ›S¹>'¾à +½3ã½õ€å½Ø?÷Z¼f>LYȾw”ð½þ М–\½]UJ<ä=ÊO™>+2{=ö�*=,t³½I=’=N¼Ê=µK>µLÅ>ˆ7¾Yrt=­ï�;Í[¾öK=b�½ÌHÖ¼•¨Ä= Ã=çôe¾Â6ë½cÍý½J佨y=”ç=Sv’=ŠT™=Ær=Ãâ>þŠÆ>7V»^Q̼¤Ñ=(‰½H/¾îË>ÄÆ>¶\¿8~Û½àÂ>¬hL>™´=p3:>c²(:4–¾?«>RŒI½ˆkE>C²£¼$†¾¥ \¾§zA¾»r‚<ÔÙ†=Þ7 >b´í`!g>àâþ=XøË= :–>R‹½–t.>µðª=Ö½–©½ÿø ?[Ò„¾Ôm,>¦Ï½G�>HÓ­=Vu|¾P£]=ñýô¾‡S�;=?f>¾ÝÍ<Ä¡#½2^˜=Uv*¼«'>ZŠì½QrU>J_L¼„„7>;T¾…¿<§¶¾ d¾•Ì ¿?­¼½—?@>l_¢=¸®§¾YAs=+^.>&âs¾Ì¶¥½Š7D¾\n…¾¯sŽ=ë§j>´¨b>±Rq¾=08?8È®=Þ�½ÐbŸ>ךð½ºkƒ¾`ýÑ>ê‡Ê=¼ƒ§=Jɪ>~¨6¾å(V>´Ï¦=+â¾f§ö½ú%g>ab_¾jº6½Ÿ“M>Å>¸>s°à>�¥=NxÚ¼á1¾\“ž>1ç>·†‚>Kyš½¶i…¾ó¬>ãîì½°9¿¼‚É=>Ì�=®�*¾c�‘>æ;¦¾%çp<±B=‰º›=¹—Œ=¤›Ì=v½t½õ¸5>ƒk> ƒ}=@FS>BX>æìœ<`ÚÅ„>Æ#›½d4À>íRã<Ü3->‰î.>ñ¹s>»%*¾J­#>�ÆU= ’ú½q‘‡<&uQ>…X[>{’>H�>Šj½dÄ¥>X÷J¼ ソ&{·<¿Q¿îp¾›¯¼j´>ûE…¾Z›P½ª‰:>`ù½½”û ¿²¾}w½/eÑ>T$>}ã>S ¾Cñ ¾Þsò½¾›¼ø­¨>ì9H¾Û?>½C=�U>Õ‚#>®÷$¾B!¹¾:Ü-¾ˆÓ>¡~Û>SaÎI¶é½H4¢¼1¾Ôj?¾âü~=V%4¾Å:s¾ŽÞ9>b[›½½e>ÉäK¾u‡œ¼Û)ð½¶?Eù]¼¨¾°g�>H^×=öë¤<—eg½ >>¸dË=˜/>6õ8¾é‹>/%”½ç}ã=d¹ =ÖÈÙ=h´½OªÝ>¡„\½~t�>G£†¾1€œ<© ½û*$=^ >|ê;¾”ôT=_‰õ¾æP¾ÿè¨>jl¾\ŒS¾ãž>´.-¾oYc=;Ô±<žr›½[m>.>[p½Ïê>X'¥½Ì½“>ºz«½+\>%>>¾`?ØïS¾?tì=BTå=Ha>ö¢;¾Y�”¾¦¡Zž.>´Òõ½‡F�¾ òȾªA>ó=>âý½IÂG>ísú=,¡ˆ>W¤½ I¹;ÓÎp>w¿W>dÜ=¾b¿p>?ó5>oW ¿ªÊï=r;´/�=¬[�¾¡:„½É-Í=rÞ=Ìp½�¢—½Aå>¯¥¾X‹ÖF¾zÛ�½=³ç<ú¶>c7 >öÚ¿É™Þ=IÄ ¾0·à>ˆØ>_X‚½¶";�F?ßë#½ëU4l½Dá­¾]`>DÔ½"ª=Ùé>!r·><+Æ>ëî¾ o�»ýÞÜ=ºèã=ë&’>¼v;üŠç½¹±O¾4 a½Ö0½kÅè>ÌÉŸ=Kb`=«&¼’/i>ùkɼc¿h¬n½N,>#îI>œ¾ºfé½-oP>ÓXï=ËpÁ½ÓÖ�>Ì.`¾ý˜}>‚‘^>]-R»æ+b¾–=§ï-¾FMœ=NË->ý ¢=Ó´>Ä{i>nð=�ƾÚ:æ»,\†¾x?`ª¹¾Ú/›¾Æ ï;=Ó½XJ¾„G„¾ßzÁ¼³l›¾ |ü=¾$â½Ù›ä=ÉZ…½ø2>¾‹À2¼+ÝĽ›®õ;$íæ>¯Æ¤>X/“½ñÙf>ïNx½+‹8½á­¾;)[=:=é÷½2‘T= R¶¾Ÿ`¾ U=7Π½?µY>xÀð=Ð�X>Ihg½Ü^d=²Ø>0_„¾š®”=è£Í>¡1¥¾ ì+>|P.¾cR¾,žœ>öÂô=†è³¾�:0=«x˜½³C >vãï½÷ر¼±y‚¾©û¨>>2Ó¾¦1½Ûȼ=øM‚¾ çϽ{Ë>ïž6¾¬ƒf=𕬻n,ñ½¶'>L¿^<¶O¾Ã�‰<ʆ>uJ"¾� >ß,9=p­£½ˆ�=„%¨¼Žpë¾b+Ù½7=+M´½÷±¼ùc'½¢)¾nƾÀµ6½À©û=ì ¾t­;KA€>�Î5>Î[«=+úS¾2==“>�½]®O>Ü¥5½s˜Ó=܈˜½Ç÷´=èß¾3=É(>–o•=ÑŒ>¦;m¾Ó}A>±¼×\/>FŒ>Šlù<š*L=ÊÉŒ¼@wõ½<<Ÿ>£W“>�†>¼‡h¸;Õ,b>zIÌ=ï >'¾Ø¶[=Œ¿½µJZ=ájN¾l»<¾ -ã;‡*G>–y€=H;=ÿÊq> øÁ»kJ\¾s†Ä¾lòâ¾A¶¾8ço¾îè{>hzû½Ù?¾)½Ž¾öv=½àj�>ªP¾ËÐj¾÷™•¾ß)<>¡˜Õ»55>-È>z‰®=d ¾’Ù¾¼TEx¾üŒ¿½†W¾­ƒÎ<-y¼*¹¾íßT>í„=`[>QÅ=”ͯ=4ö¾>XXŠ»{Ï,¾í?j>ǹ>Òo=§_¾ñÉ‹>y´&½âÙ®½„ƒe¾äU½DûÅ=|ë>£­Z½öõˆ;£‹? ½B ô>¦É“½Ã°9(Öd>vºô`¾~{¨<è"ª¾Y�@¾ÏW¾ûwŠ>ùÎÄ>˜à¼�’ð½Ôÿw=ªsÓ=ùv¾]ƒ =œe‡=»¦‹<]J�<OW>~5‚»ñ¹¾V¾�>Á:»=¹_(¾œ�â9ä ð½ß£>½ÁP½&Çý¾U¬ ¾X•‘>àý?†û=v†~>©å×>´wa½GU.?tÒ;½­HP>bäÆ>†2¾°xÙ=·¾Ê•q¾°¾sB>”:e¾ÃA¯=†£§¾Ò$ù<®ã•=FIÁ<í[�>ßõï½§ï<à²Ò¾ã^=ú¦{½e¢=ʘ¾"(H>f¹,>«Í+=¸(K¾Kšg>Bú;>'[¾à÷žyÒ<_•‹¼Xš>=Jæ;ñ6�½§s>û �½PÖ²>xT�>üùæ=ñÝ4>ì×ñºt8?>Rs»¼‹d¾Ã‰¼¤ÛðºëU–½D«=•†–=í0>›4콥Ѿ·*¤=*>ú=<î>tY°>ÃLM>_mÆ=i„1¾KVƒ½[ˆO½¹¢¼=”?¾Îû+¾î¡Š¾Ô` ¾�)¿ ¶`¾Êd¾Êàž>¢Û­=¤ç¤¾‹ß¾¡F$>„çô=ÝF>ì”î<#p3>Å+޾=Y_>Óì=�k>YÚb>’Ì!¿w|>ך>«Ã>U˜½Hú½Ájš½Õ¹½Ê�¡>R_7>PæE¼�̽¢’”¾(§j=M¥>ͦ=,^&>ñ@¾Ñq´½n” >Mã2=4ȇ¾-(.> &ñ>4sµ½<”‘>ÅÞ¬»^Š >YÌ>sŸ=Fƒ…9Å >µ¸ã=:�‘¾Ö¾z>©¿½¦y=&V>3½€<“`>ˆ*>òlâ½¢㽎Ë>R�ú¾Õ5ͽ"%<¾1 º¼ñÒq>™ÅJ>|"ϽIÃ>0M¾¶L¿G =&Ý >-Ͻ9‡’½õ‘€=sfÈ>�ÍK½ É“>ž°¼Š �½uX>*Õ�=°NU¾Õ±o>U¾Ö‚·¾¢Q¾€L ¾É+�>(æ>ÝÒi>�”M¾3¨¾>r€¾ö*‰¾z¿©>*Ü ¾Gÿ½t´c½æÛÿ=ô¿Ú<�?ö-+>¶ñâ¾åØr½å,:>mïø=~>l9$>Wrü™AD>&r&>)<Þ½­m³=÷¿K¾œs;ºÙ>ö&¶>Iþ½¹À>¿is¾´—v¾#`¾_Â>pýÂL®>{Ân>ãè=¡Á<ú!ä»Vß>Žm�>ˆ¾è¾Ý¾çÇþ¼T>àø¨½mðÎ;� “¾\:)=ïÑ£>?1f=À8Î=Ä}'¾Þ]c½ †‡=-„­½÷˜=0Ü>ñ�¥¼Æ=½Çj¶¾¨:4½^îþ=-µø=®3V¾1Ú€¾f(–½Ã©ä=Óyƒ>çTнhí®½?†¼Ur¾�®k>2ÛP>ˆM½Çt¾³x×=ªk¾ôA꾿‰>Ûvþ<ív1¾Y,O¾9ÿ½=Ì †¾o"*¾Û‚=à.ü=­¼Å¾lÙˆ>¢ß¹=<ý½ðÝ?=c¸�>v<½M#e>ÓB¾Íiô½~O>¸,+¾ù–< TC¾åâ¾½Xý<=�"˜¾5ýˆ¾E u>ž2e<;‰Ë=“¾ó>LF¾1L^>;¬<> Hݽ”—Ð<ܸ=“±¼>X™=r‰>³:¾å =Qf¾€¾R@=�Ô~¾»Á¾º2¿:–Ùè¾C¿á½TÛ'<#Âð="ag=È4ϽÉð�»jˆÐ¼{|¾$…½üºÇ½¨ÇÞ<ÎùW½Ä‹“=‘r>n*%>^Þœ<ÙýºX«G¾•-`<­jQ¼œáʽ‰nÿ<õ3>Ig�=G5è=0A1>ÅÿV;’b¿=´1³½†^¹<H@¾a¾Â¢¶¾Øª‹»8ò ¼È{U¾×{R>©Dj=ÈçD¾\>”Dé=ð%½W`Ð=ª~D>ëW>áHÒ=¨gÙ=�ï»–¢=>[=0d@>˜¯%¾¯—=ᇑ¼¸Bÿ=9ò<Àé¦<­‡=Š]ä<µ_…>ú¹@¾‚Ñ&¾€!=u™¼Ô9¿¾ôl‘=¥q>¨Jœ=ÇY,¾Vûë>ÍÞŽ>øùºš�˾h¦½:ýªš> ­Í>ê_¼> =£xœ¾�×ë=©Oٽ˱£¾<È�>0,q¼6«[¼¶>Ì�½å|ß½6 ¾÷^z=¿µà½ö¹…=×_¾ÍÄf½å›–=ŠáÒ½_b½8·o>ÌP½D™)¾þU;Î7¼މ>÷Of>½S“¾Ž >Éþ½ Ǿ�Wõ=³ò%=­}>[Y ¾r8¾[Ƚ[Íø½È€+>"G”>&2Á¼Õ«@>éËs=:<¿âü=ŠÃ<ã&¾�¥�>L ‹<î–”<ø�>7\¦=$±.>1î¾Å]­=’Tоø´ˆ>®q­½9| >h“%>ø.>ï #>a¨?êÍ>)¸”=6%T>:^÷½Œ—=hνwX>- >äèµ½Tê„>àß=|áG½¿‡æ½bl>¬ã»s>ô££½/lP>j“=¾œÃa=‡{,=O$>‡*¾�)R>»†¾uϼ=i?s¾¬¾ä”¡=bñl<-8¾½Cà½Ô|d¾çÎ×¾®Ù|½I¿=^¡R<0v¥=h!Á¹vÚ>.h‹=8]W½®¢½ÆÌ >Jÿ™½ƒò•¾¦ßx>Û­O;x‡ ¾‹4¾Qõ“=Ð@#=ð‚¾ ‘³>S¿@ô=p}—=üÀ\¾¸Z0>)v=]b>j1½—c�½§äã)¾ñ¶<½ÜÉ=åÚf¾°8=n §<–Ýr¾Ëˆ–¾ Æ=-j>°�=hüt>88ã>>îú½Ù4&¾­;„>òx ¾±vǽVÂ>Iáâ½ €]¾˜û½ûÉ<½åx¾@uø=m>§#O½†)¸½.ý)¾ä±ù=Ï!þ½HúǼ,“V>�V¹½Åg˜=éÉ>޾öÏϾ»òÉ=–Ló=€j ¾]sÁ=Å¥¾=¬l~=~©Ó=%Š[>Þnø=H ,=膬=Qn'>E н’ì[>È"£=óc*½íÍ*\¾io¼ÿ´^½ÞO6=9ˆÂ¾óP½öS½¾0Ë+½9ñl¼nŸL>dŸ½’Ó²<›-=KO%¾S¬â<ÎI]¾®w/=µ¢¾Š8¸<µG·>¹¹“>Þ« =ÓJc½ ¾qÀ­¼\U’¾l"„=°ȼ`3¾,½}qå½D%m>æ„¡;>N§þ¼8ă>+Å<ó”�4Ÿ¾$¼]>£'>Ï—º¾hi�½eˆ>"É•¼óY„>Lf‹¾8•?¾0+Ë<º`¡>ðZP¾ž‡=‰!¾tkc> àŽ¾rľå¬>Ü8¶=SÞ2>:š=$·=ÝO¢=‚Öx¾dõA¾Y¦[¾;‚¨>Jš¼ã�{¾ä½Tó?¾¬+’>!&õ½˜½ý[Û;uã°½a ¾¥V¼}øÈ=e&`½�Þ5=îÀ=P¾/¾+êœ=Œâ=½^ð¾ì—¾qf'=Å‹>ü3¾ W?½I´¾˜/•¼dh�¾œç½,Ë>U�g>'Ë=-S>Ešò½¡ g>ÂÈ >UîÎ=¯¼½ =èW¾GÁ#¾ÈF>²¿ >§$—>%î½»‡>ÈÀE¹ìw²½wÚ=lù$>/Ž'¾�|>ðÞ�½䨽D>úý½Ðm9>?�½Ì·î<64*½¡l#>/n®>sWŒ8¶)¾x(ë=åËÜ=5�Q>Œ”¼åv¼¼kšM½0�>CÈ@¾z�¾ƒJK½t!M½v¾|$¾ç=ž=Á:½!X.¾køV¾m™>B>åÒ=Ôo>R�§½#Ì ¾rB¾Ó*î<¹].>ÿÙ>×'ƒ¾ÉçÖ½$/c>)/>½èV>–[�½ën‘>è7ƒ<áÚ†¾OEB>’¼#¼û†.¾ÕT9¾%R ¾ë!¸½L‚¾ê‡?< "Þ=#uâ>[K¤=Z)¾Ö'½’2=Š�¾!u¥=˜¯">Áù¾x2P>I =Ú@ô<Û9E¾ÚD ½Ô1"¼Ô#>x�+¾®*(¾5Ú¢¾·!> ÿ=ËNê½bà,Ãc½n±ç9zÞ]>Ù¬«¾¶Ç=æG>ê-ÿ½b<£=á7E¾“…¢½Ê O¾Cà@¾–"¾Gqœ½‡Ó¯½Šç™<ÎÚŒ> 3^>Ém‡<Ðô>"ÒO¾–¾²½®ºØ=îYç½Û¸V½3o ½¿r=C𥽱„½šl»>I°¾ú(Þ=Ÿq­>¢›–= ]½R’!¼\"¾¸³Ï¾Žê->'Ø$>23۽Ɨ¯>\*à=9;½½]«�<Õa>L£î½ô[Ê>T'üº1k=qN¾<1&¾­ŠJ¾õÒ!=7‹º3ä:>ª7”½È@“½f©©¾/>b“º'L¿>ïò8½±Y¿_�:¾ Çš¾Z>)I…»Åi=ï ¾ÅÕ+¾"oA<#³E¾¢ ¾fÖ!> (¾KÐ<»´ò\8½]¹~>e3;>lá.¾ØK¾v7­½Xš(¾}À�>²›¾L�Ó½Kˆ=¦ê"¾oE¼½þÙ>piÈ>©3T¼•w÷@\\>35>„>D½ ¾@õo¾¾üä½_ÐÔ¾u¼<>… �¾B¾&>­ª£½«޾ …¢<´×d>4¾´Êæ½ïØÝ½5 > œ¾ñR×¾­¡�½zÑð=êi,=—Ø=³�K=ã¤=•�=j·b;V]Ç=Y&X¾Lr¬>A‘¾{#…¾ãY>x—3½Èò¯çuß½F¶®;ŸD꽄ƒ½+¾²>è„=D¦/=‚>/€>ø=>ÆØ>õ1ø=„;;=Õʾ(»èxñIç1¾q K¾ñjß½­g>²`¨=ð�>o'g=SȤ¾Œd¼ÆÇµ½~h¼½-×d¾Ò:Þ½ þÈ›>_í=6C>i7> } ?½|ù=�æ‘=‰óæ½ç:ç¼}¸š>”c›¾[»l>fh¾S­‘=+:­¾6ؾī1¾ØW<>9k˜>;ܾ³±=bxJ½®6¾þ¼)b <-Ò:>‰U$¾>v=TÁ�;�ÎH½”)=>.¾@4¾ƒ“=©“Ú¾½LŽ>çÎ…½' ¯½º1Ù½A {¼áJ¢:J-÷½’;¾ìgp<¼•Y¾SBÅ=ë¶½uÂ^¾òK÷<#÷);¿z†>F¿»Í/>=2>½ú‡>û•=j¤ ½vÕk=G¯�½e'=¾Ç¿O>ÛlÄ»•+ƒ>޽‚ о§A¾Uc;>#ذ< ]>£ÓI¾2Á¾N á½ûZ¾Dqñ½» Ÿ=l̽:ÉTi>­þ½ÿ_0>xÿX=ƪ">…Õ½h€º¾nª >_l½N^>{ŵ<=Ò½®u3¾%¢3½—ÕÁ¾—= =¬Ê.½Yí3>±²>\8¨¼¼Æ�¾8 Ô¾* ?+Bâ=Åe¾tÎÙ=üsj¾23š¾�,;×i?½=Ë=œ(l>�ª^¾G��½O¾òè>©á-ë�8>8É�<þŒ¾i4>{™p>²X�=þ@�=&H²=Í‚’=>Z–½ñRô=íý0Ì}¾ì¦Ž>5pâ¾#{̽Ð-¾t‹k¾¼÷¾Š š¾àmy>¿£¾/>IŒµ¯\®¾�°£áˆ½Ú‘6>`IS>²$c< HB½7‡P=Á¢H=L�¦=o¤‹½2ì=<[ >jrn>g>q>-�Q>¬_�¾õk¤½5� ½(2g½D‘½&ž‘¾žÍ‰= ÿé½å~н}ì¾�!Ľ 5>~Z«>Ešã=“æi¾h >ã%M=Æ|t¾¦/q½ÞvÁ>´¿=Û`�¾§ÿν`öB½XÊ=CMÒ½�–>­p;4yA½‘¾FŸ‡>)I‹¼¹æ?=3½²d>Hºê<h¿<휽,'=9+º¾Ë!ˆ=—<‚ö=Ôg°½Ù >¹ìæ½dJ=+�¼Ö�º\0 ¾í„r=¤†è½Ó=)/=õoA½Ý,y>%V1>SVü¼Wm½Œ»i>ùF>0iÃ=Ôa+=jŒ¥½ò@ =´ÞU=F³ä½cð²½B›½›“F¾œÊ¯¾<îc>³ß¾¶—3>ò.‰>_齓yP¾Áª4¾‚�'¾CÁ >Ž6³½Ùr­½/O¿CiY<ô"G»ò¸Ö=øÌ™¾We&½Òl=õ4M¾¶JÀ¼Q0Q½%´½Š×¦¾³Ö”=ff¬¾úRû®TÔ=Ïe­½RÝ�=‡ôN>¸Ó‹=R >�ùN>å×�½XÖD<`¯�>f¬¼Äw¾úwc¾{Ѹ½ñy½òܽ†ž»\?à=aÚ½Õ¨J½ç†>Ç*g>Òš$=�–Á=Ë­)¾�§ª¾øNÃ= Ul»Kø€=�‹½,®i>èVX>þ„;¾o\>ëS¾Qº7=lðª<\J<¨z>o'<¨—¾©m³=yJÝ<ªw><¡¸¾shb¾üUŒ»ÔDv¾­q÷=§Q†=ºàk=b™Â½îwS¾ûñÀ¾»'*¼‹€€½zä=“¾ïñ„½ŒÈ ¾Å=š>ão‘>þ3½ 0¾­Ta>ŠÑÖ<¯VÑ;s%s½*�ニtc¾IÃÚ¼6J¾àX>èpá¼ÅÌ„>uå=”i=Ýó>áW5>¯º->^•u>~’¾üÚ¿týˆ=q4Ï=¸²¼>Œ�¾}f'>½¶·¼mÖ=’a>/ >±J}>®¨Ý=R¯¾-»>>ô!µ¼#ÄU¾œ_²¾wfo½`’´¾N³©=ojØ=YG»=BI>н…ñû½wùn=°õ–=J ¾0Ý=ÿš#¾m޾7Äð¼i1¾Ðÿ8¾7Çä=¢UÔ½‰Ï>LM =b=‚Ñ><ij½¹<¯¼�ï©>}À¼¾'.¾‚¾òqF>T£œ>¥’¾,)j½ÖŠ÷½™Ùò½¦òA=YJp½…@¢>E=)¾«:}¾Çê¾ á…¾® Ø<ô¡l¾:#’>X½´44=®W>åB6>ÂE¾·Z=Ćé½öp>©›A>ѱç<ĬÄ>n§0>±{ë½#˜j½W¼ öˆ¾1™T<…Úí¼ª®x¼¿)>îšy¾~ä½=© >ݳX¾éDÊ=Ös'tÔö=��|½åz>ñ)×>á즾<´6¼ )0>Ô÷°=¶ÕÅ>ý@½­™Ü=w"‘=-ƒ¾žà»¾P6æ=µ�‘½4ÊE¼ú\°¾ÿX>ØÏ*>Æô½|Ê >NB³<.€¾ê]>^ù…½‰â¯½”MľE'gJÉܾ q>˜é¼Áný=��P>¶e¾Š}8¾’JμÝÔ˜½Å4ú>98Õ>jF�½ßms½–\Ô=UD5>,!==ú›i=@ñB¾m�‰>®Ö�¾D>à$½½Œ;7¾O/?¾Yhû=t´ù>—R¾•ó…>Â�”½Q·>UÕ¾“'>|H¼;rô=ƒûÿ¼'|ù½L:¾ÐÚ&¼ED0>¼GÁ>$—ͼXe¬¾6œW¾)惾¬ß?¾‚ü>™é=-I®=ôŽ…>Ÿ ÿ¾#W‘¾FT>Ý#¥<T¾†Òÿé—>æK=�н Iî½²œ5¾“!¾BŒ…¾hó/¾’82>æ/y¾8º=ãz~½‘¨¾"6=:é[@½Í¼=ÈÒK¾ktF½ *\=•ø>.Y=.dë½RP=aI¾¤} <¿¯¾¾cÙ¾ ½)>I¿“>MÚ¾‘O=vf¾cDà½þƒ>·Ì=(ºü½‡S”=ýÛc=J™«½”€¾]Я¾½å€¾E÷’=ñ;„Ó&=ÒK>¶«= ;Ƚ̵½œ`…>œ/²=?¸>ÈDë¾é/ɽ÷¤>¨ã >w]>¿yj>&­„½¨ü³½vÈ<=ºÜc½‘2*=•±nñ¾Cë">"ð¾lz0>o£Ï=i‰>ƒÑK;$7>•òǸtŠ> KŸ>0>=¼˜F¾¶D&>ç8½„ZY½Ã¬‹>%mS>Zm/¾Ñ…½ÄI5¾�# >m‰U¾»C¾Ÿ8’¾?`í;k>`½Ú<�>H¥p¾$�¿}>î-û<Áå°><®Ã½fõã=ÕÓw=³‚¨>“ùð>=oŽ=Äa¼>H·É»PBÔ=‚£q>’ÿx=˜° ¾Ù³4>(=;нj@¾pS0=vˆr>/Mý;ðb½�² ?�“ˆ=Яľ6¡¾?¶=S©Œ½™ºL=ãf=bôû=åp>�ꓽ~¥š¾‡î�¾•µ>Hù˜=‹ðO=¡ú¾Ò é>Óe>UR¾p™>¨×>V.¸½y ¾b¾Rº>Árž=’Ι>Aݽ�?3Ø!>üí{=Sn½ëè.¾ò�b.›>:­Ü=��¼ÜO<;Xž<æùô½�û¾ãñL¾â8>°÷½K¹>tDнÄÏ…>Å è½R½¥½ ~˽t¦>• y¾W¡™=Œëž>Oh¾;pO¾4W5¾rØð¾üð4>âÃß>È|.>*�>0ÕŽé¬î=”ÈÅ=T°T½M¿¼Ó<ó½c}Õ½‹‚ ¾=7ç=#¶¶=6Ï<Ù®>¤Ä¾¹æÔ>�—þ½„Ù¾=Qü½³>Žâ>®qã=´5“='—¾öˆ>wl>” %½B3­=«š£>sP_=ÄÞ%>ºì>±ùT>§Í*¾w޼ꎇ¾m`4>YQå=À-X¾x…=ç½=ÚœÃ>m¾­eν6¾ ,>Ì>e–I¾@$½œ¼¼=.À½*ú ¾I6=°?à<ù->ûr·½Vów>›}¾[ë;Ïýá>eä†>Èîp=Ï7™=ö=½­·=ãAʼ�±·¾B¯5½4ð=¾ßjÝ=Ü4¢=$«#>‘=Ì=žèö=68¾+—>ÂZß¾µßÖ½i)¯½à×I¾E\¸=îÊý3’¾N I¾ýÚþ>ÆT»³Õ=÷½°?¤gȾó´?>EQ=R¸Á¾ø²Ñ¾ˆÉ�¾ æ=ë(=×ôÊ<� >=’pS>Ùn˜=j6‹=I̲¾éæô¾m±´¾iµe¾7H%> i>�‡½FËL>·cÕ¼Éÿ ¾ úÿ¼,jϽ Wu½*'½ ûü½Q’è>§á¿= OÕ=íª>ò4¬½Ðôç=än>CÁ?¾Œ,�¾´‡}½*{�¾>>o¾€#>Q—­¾I>ì>=D¶â<»÷J=ªÎ¾x?œ½ÞÜ ?ou?¾o� >ÂÚ.>¨Ó4¾HÑÝ=ÎWX= øÈ¼|Û¬=ð…ä½î͉½šŒ6=ðý¢¾ Wཿ R¾‹›·¾ Gu¾‹õýê'ü¾ç“^¾-»>\'¾Vú¥>°,a>Ì3b=Xýß>ó@�=fäv<&=ø8¾öM¾þ­[=¼>¸H)=‹ ‘>?î”>—[o¾·-O?|µÌ¼‘O<לּsÿÙ½C_½Çþ�6>Vޤ¾9Z¤= h%>û‰^G;j±!=ú�>§°£¾>ç½à¶2½«åÈ>˜Q.=å¾¾Põ}½ì‹1=•­�>0¤z½Pp¾Çä¾1Ò<=¼yL>’€‘¾G²¾|8=6Üj>„ë\½¢dò=ÜÔ=ó›?¬½–¾º$é½Ð C=«‡l>Z©%=å"½#zH>i¬=¾øA¾Û ¾ÅI+¾¼¡Œ½mÔ=[ô~½ÐA>ÔŸ†¾EäË=1m�>Ƀ±½FÕû=#�ϽºM&½Ù=ÂÒ:ß3o½+ó >2´¿=±q¾bÁ >I¬ù�Œ@>ßÌ">ý™d¾¢Ç¡¾ÚQ°>DKq¾®_�¾°®>¾?0 > Ø»¼õ¼‘^G½;†l=à:Ö§W>Æñb=RE¼©8<†=Pv,>5nã½*M—¾ÒY•>_Bͺ¹X>Ö ƒ=`©>�“B>Ê׋>= ±>L¾0�¥½ãé�=ےྠ²¦»¨�¾ÅäÉ<ê;ƾ•ùM¾DÌï¼€›Ó>à 彯žl>‘Þ ¾´‡Ç¾ ¶@¾¿À1¾'{>Òˆ¿Nj¾š;½‰³N¾\› ½K&—½kB>µ9F»)¡t>¶ £»rð%>½�Ú½�< >ÿP>¾f>“N » E,¾»E™½Ú»-¼œÇ¡½Wå|½ð=?q׿0«½â·¾´ ³¾V·_¾Îü˜>�Ôß=3&}¾§�=½hZM¾$g_>?ša=yš¼�̾p¦¾ˆS =©Úk=gî½b2=u  =[ŒE<¯<¹¾þŒ/>fy¾ªÑ¾›O-½y½"Ú)¾µ2¾ä${>k•½ó�è½âÅ ¾õ'½†>Q°>*4/¾N+½Ù4qt½>B>¯D@¾Ýž ¼És½{Ú£¾å+±½*û†>ló&½^PZ¼Á½Ì½ÀÒð=Þ7ľ ¶�¼[XO¾jfì=i/k=Œ;\=kãê½°wk¾²¾->ž‘T¼þö:<‘_À<Ù Ñ=ŒmÙ=$v>®NÛ»äÔ>윅½ªÏg>Ž|X¾UúÆ<‰Ä°>~»?> 9þïçß>=öU™¾L½¼ä¾É¾tÔÀ=ñís¾÷œH>!„´=;•C½ÿ >ø~¼¾+н ¾Œ¿½À>ã=pØ�¾#+¼Iü$¾\ ¾ gQ>¦mÿ=¢^O¾™´>õP>–>ÃR ¾Ï5±½HÖ—½éÎÅ>’Ñ»‡p�>ó ½C”D=‹²=åYþ½(Ÿ>Q ½bg.>þO¾¿+³=ÒHͽ  ¿ü!Â>,ؾ.i!½(ºo½QE…¼rе½î&å¾rw’>8q8½b==þ¿n>0ûνò©è>šY5¾â°¾ÝÀ½ r">‰&A>J “¾5À›½I¢!¾C/£º²¾ì=•Ž>hm>RE¼ü“´=ªöƒ¾æ=Ó=‡v>nF¶¾åÕ²½ `]¾O‘ï="¥6¾ï‚s=*ƒ>�Ç™¾cdt½Ä}—½¯`$¾s¤L>üY�¾•/>=�'ֽʿ· ½áY¾gµL>Á5‰¾¨q»=©÷J=xÓ„>l3n½f‚W¾–-¥>Üðh>øx€¾%øþ¾¸.">ù‡*=òì½¶–¦¾ ŽÚ=ž¸;ÉL¾rg›¾¾n½Ö=Û½rz¨=3(—¾üèó=þ‹.>-;¾DÙ=%B=r–½¤8ç¾f•Õ½£Ö=$‡“¾P6�=wð½àÂ=¾½´„>@­1½qÙd=vC=Tp2½òfD¾µ¢Ú¾ÅúŒ>ãùt>`TC>RŒÔ=†f_>Ë g¾W >„çL> wN¾9 ?2™z=aЙ¾ÎÏý¼¸î�½%|Û=çò½‡\ã¾¾ßk=ÖÛ<Ó>v¾ª=*mÕ¾Õçe¾PdL=ˆ›¢½\uö>*f2>ÍzU¾l¡»tÞâ¾»6®>Ø•= ,Î;Tg¾¥�ƾ?h!¾|…þuùã=¸çÖ>öL=u±Ë>e9l>>ë=¡Ú•½6oý=M�q>vc >Š�q=‚¼•=–ç'¾¾˜¾‡­•¾Ò„Y¾o\¾Àž ¾híz>rt>Y6]=ØgT½ë½$õŸ½(}¾›?¤=P�;½?Z§½¨i>µˆ›¾ßËô¼h±=�E>¿l;¤?I¾—¡½¼”q˼úr2>Tâ–=ñÙD>u3 >"rýN6†=å<¾‘0X¾'¦¸¾J%¾hƉ¾îÛ¥¾m+>�—>•i²¾e�>§æ”>²É�=Zÿ¾(—‚¾Öêå=Ÿ�½=ÌKý½[ò<-0¾®9#¾ß‰½¨�ì½ÑN ½1Ä…½‚Ü>&ÑÚ½v+>®Uº¾âGA;¸¶š>Y/|½Ìê=¾-¾ö/<>ÂWí½a’A>רè;<=¹ïÿ=¥ >†ñ¾˜xF¾Ç¿ùP<=gFx>×o]¾–²=� ç=Åw=«0»Gw>> åW>ñJ>x¾ :‰¾A„@¾rŒk¾ö=;� O¾Ú—Ë=þ&= ò ½•õ[=ô.˜=¦º¹½àV$¾âœö=0{)>šg’°J)½ì¹Ú½¯á»Ó­¯»G+¢=÷€Í½ºéѾ— �¾¿ô¾”ºô½ç6Ì>ìN>�(ú=tåó¾½l>뇪»a>½mÔV>^8v>úÜ=ÎÔ½öB$¾(’>ᆬ>0q«½n”ë½j,•½°, >”Êý=Iw¢=;§ƒ¾}1,>XÚ½�í*½…‹ž¾úº³>qP·<^‘'¾° ƒ½Y—i¾ 4 ¿†2sÏU½>ŒSd>uê;©’=Ô¹H= }6¼B´½«½ó ¾ Äe=Pv¹>Ï< ¾z-ͽ±@=Áqä½"›½Åïÿ<ûVf>Bö*>�E?z6?µ^{>S¹[¾žnb=}]¾álk>ñ�;iœ½F‚>uŒô½!B•¾ÓÆ'¾!•¾*2=4%>~¤¾‹Ÿ½£ZK¼…Ï׺Jý>Ñ©¾æc¡=¼´>>�³¾ÇA ¾ÈÛP>w <×—n>Y¿¼ ÍL>²¡½Œ$½²†®<3™½0²>•½Ô>k2¾#6>¢Ú‡>û†={ç§¼qY?žTó¼ŸÇ5¾ô˜>W*„¼tæ‡=CdȾ–|¸¼Ì'Þ¾yýa¾pñ$¼c%þ<+Ê×½TB¾HX¾»®Ù>‰Œ½-3>…ô¢¾Uù½íñ“>ÈãÎ<úù¥=&ô¥>ˆÜ`¾W,>ò»à½ 3<>¼©°½ç¢>rg¯½Tú ½…ýR¾ƒÎÍ=•½�>o¯™¼{þ¯=ÜJž?�¼ÐœÙeý$š;ÌZ‰¾’ã¾?ª>±úó½­B´>`{'¾ç+µ>K{p>Þ¾X½Ÿ¸ý=!ò>P¯³¾#¦¸¾Ÿ?‰:Ó¾˜*-=^�³¾*Ã">[<þÔò=e–>b›�>^?p.ö½M`½ÜÑ>‰ëƒ>ç>SR§>(�Ñ<{zW>wn>ÛÝW ,­>¥:Ý=(„=¡°½âªš=ªì=A͇½’ ¿¾/£®>o9»>×€.>\Ö&>Uzƒ¾M³¾.ïϽv¾ >ìl¾€!“½!3={Òž>J,>½n ½7¥<]L—=âB޾Êp¢=lJ~>ØÓ½�zr¾U>>[&½<žÜ=%³N=ŽÏr¼Lå�>�M…¾þ×)¾{Ä<>4ÐÑ>ƒó0¾õ)>Jc¬¾˜&Ù¼+¥?”>5C =n/=¨†o=î.�>vgÒ¾XØz= L>_¾l=â¾Â­‹>1%Ù=¸2–=½ì¾Ï ½‰Þz¾Ó _>5Áõ¾~;!¾© e>E>;ܦ¾Å]/¾^3ë½²¢C>õ—Š>Èÿ=>}t >›§^=šóô½�B;>`•œ>OWœ¼X5M½dªœ¾–¡O½2 N¾®O3¾Å80¾dX¾?>S–>{Ÿ�>eøÀ½†‘½*’°>?Ó½œ®�>�¦¯=¸3È>™à½à|Hž†<È&Ÿ=Qÿ_f‰¾á>¼Ï{“¾Fkl½õz >±—a¾ººÅ=Ì”I>績×ð6¾¿i©¼4w%=`Ç`>] 9=J•>X•½6ß3>ˆ�€½­Q¾Ü»’½’V�>Ñ:®Œ>Ík+;¿:«¾ðî8½¯f‰>åüæ=ÞKw¼ee…<¯K¾† ¨¾ˆSs¼C<&½|^¹½Að•>r­´=âü>œ5¾¨wê½E‹=áÒ”=åŽ;Ái7¾©jˆ>Þö†½içĽɋ4>Z€T>¾ÈS•¾MaÄ=ÔÕ¿=©l½¿¾íWx¾²Ò÷¼¨n>’•½‹¾>ÄΊ¾øÌоd'Y>Ýf±>¹�>(É> =ò2?h„¾‡`P=à¡G=ð•þ<Ö÷Ò= [—>i:;ûŠv>£…˜=×B½«`¾ 3J½Q᥼¼X®½I¼=ƒ*ˆ>z£¡=§�>n^P>úõ­½6-ô=‰ÿt¾Í¶i>ÃÚþ>2»‚¼µ£>¯¯ž¾Æí=Ê3ƒ¾Èޱ¾€âÌ>2&¾´î@½«D!=Óƒ½ª’?y�>ôáÇ=°½=/>¦Ö>¾’™ ½F°Œ¾@Ó±¾<N>ƒ…½5ëî=ñÁý>{Ã>¯ §=C¨–¼²“ö½:¹È=ç1ϽY·„>m›> ¿)™¾7zÎ=¢%Ù¼iv>Þj;= Z=Á #¾Ö¤>°ƒ½ÅÖ|¼ŽÐ™>W›†>³º¾©Z­>’‰Ø>¸L@?á2Ñ%>raœ»<ñ,?™2Ó¾þùœ=oWå>Šÿ_¾ÆM½Ï ½[t½æ²½¥|²>ÌG>g×'½Kr½(n¦¾‰HI¾ÒÖ½®­S½�å¾=ÒfV¾q- >ß­¾:F`¾Pö¼½‹ðX¼æ=Þ(=áÆç½a¸¾WÐÏ:8=ÞØù¾œ~#½œ¹®>{‡ý>|"B¾Ò⢾$‘->· <•’�½\Ë=I–E=¥±¾¿™i>2é½*¹‚¾[›8=¿ËM¼ë=;>fÞÄ= !‘>V'–¾ð" ½ ø°û꾿}'½îp¼'­l=”Ò¿½g€\=ÔF!»þ ø¼¨]¨ƒ >g·U¾¦¾õ5}¾âèÞ½ÏëÌ=6ß¾ås¾”"=Q„?A$>ç… ¾Á#Î=X6¿=ÖJ°>}Ÿw¾ 9¾¯œ:>‘¬‰¾79‚¾öª�½Ä&=}ä½%¾Òz>@�µ½ú„н»ß6>÷,À½ü‘­>Ø™d¼ÁRŽ>“^Ý=�dU¾GÅÀ¾ok�>C¼\&æ=“Ì>¿ ¾7h>ð;’>о9ø¿:Ï£¾îa>14º=u“Ì=6¶½¾í¥Ò>‡Ã¼!<Û=\>Æ,½)ãê>ßúѽ.Ĭ¾7¼#>^¸e¼Òž(¾˜Ž>ôÁP>¢Ê漡ä¿}e;�°>Ì,ñ=÷x€=o‡ø¾ñ+Ü<Ùðª>¸-¦½(·½<íÕ¾¾„¾c›z¾�R�>ξ�¾à ¾þ–¿¼1j>%[?�u.¼½$ÿ½ƒ�n=òêl½'µ,¾KU9>>Z˜>ìàH>ˆ±¯=Éa¿ä!¾Šx¾½ˆ„>Ì0>ö»Z½8Cö=O³E>)Uº=}ÿˆ½�U>uJ�=Fn/¾´»"<“â°½ða,>�¥<=+cÎ>ì1š¾Ï°“½Õ4Ê>lY$>ˆšI=þ>¸ªý½Ü,?;®Ÿ½ÈA¼Ä¼O¥¾4D@>‡LI¾›ú<Äd¾7úí½N�`>?‹B¾H¢–>ÐQ–¾¸ê¾V™>IbÞ¾ù6 ?­x7>LP¢=õ¾tD>¬å¾*~S½s8뾂f¶>ô 7¾wr}>B<>ɰŠ;—´¾Ìi>Ÿæ ¾@>¯ ¾£PO¾úͼÚo!>°©‡½ól¾r¥•¾,ú|>.cL>^“�¾�%Z¾–‘>à×¢=ˆ|œ=È2¾û½Î½~¶>³}Á>Bç!¼ŠXß=·ß%>¦0œ¾“ç ¾vZT½ E> û<^'‘½œ=��„¾:S¼Û¥¾¾ž‚�<4¬™>ƒ‹°¼]/#>c¡½<—Þ>Æ®¾�@¾ ¯O¾Óß¼ûñ޽øU¼/ƶ½Ä~7=ëO>Ƚ½»ö>K>,Úl½';‘¾…饽âjˆ=€¬½kf->Cƒ¥½Ž>'>?:¤½±ÖU>«ûš=Íš¾T¾=%"D¾$åè=úû’=5ì¾.H°> á�¾ä^ê=QñÐ<$ ·;e=6>ÕÄ^>äÌì>0C$>•‰=qs=&HJ>Ô.¾Px˾Kk¾qŽ ¾Á›5<‚ÿþ<ú�¾@On¾a ©>m.p½�ìI=!“©>âô|>H“¾t1”=)‡#>^™ù=&u>Z¨o>�-ú=m,¾Ÿ,ª¾H>a½Èžƒ>~¨x½ /!>³§®>’ß‹¾Ã§N¾ÌΤ=$ð¼ TÃ=Í{’>‘¦ô½1óܾèÓ•>áó¹>¥×B½½9B> ª½s¾Ê <‘-·=‡‘#¾ùÊ>!"ˆ=Õˆ>¾JA3= èѽÓt=ߨ½K˜Ç½#š·½CÿÜ=âZ½Æ#—>âó=&à˜=T5J¼¼ »Ùz!½PÚ‡¾~1D¾Ã†ß;Ô¸µ½nçÐ>b¨Î½Çx»¾<•?ºÃjP¾rX>iw3>H«8½�9¼©�­½ŽØ=jH ?ƒ2>­w¥½ØÝ=S¹>6½‡k=e³�¾{[޽|Âd¾uÖŠ¾É!?¥¥3>3Ö½1%¿´r<4x)¾´K=>‰ß@> ¬�>ã=¾˜O¦¾°L¾oD…¾š¹A½iÇߺÙoý½œ>ðñ½Ó<ée+>À!½­Ê‡¾ ɾÂë,>¶[Ľ×c…> ºã½ç'½mÔ>Žõà»'ê >w`L>ìp>(c1¾ä±>"J€>*eÙ¼¬…¾™ Õ½ÂÀ=)!Þ=°¤¾\Oh>FYß<»k˜¾M¹ç=tpR>¬Üš;|¥ª>ü\>XBh¾F¹=¹%B½@Ê >µJŽªþ<> ݾ ß=Äiq={™ >4\D¾Y¯½×‹=dÆ>kL¾á×>x>>æJƒ=ˆ,â½äwÕ¾^´e¾©zÿ="»=9­¾c—6<þ=zpJ>XB#½Nbt¾ÀÞ5¾SX1¾@—¿&l™>'-ž>‰Ð¾>O=�pò=«62> ¤K¾Q†û=X¾ºY>,ãî=}|] Ÿv¾nsƒ¾d ¾›±=A“£¾e ¾D\C>N{½½¤‡º= ¾Ž>Y÷<½�œÀ¾ f…>³±Î½2 ͽ;×�¾(Õ½ŠCá½+7¾íúþ¾šÑ<ó`k>…èð¼Óe˜¾VA¾ Ôü=ôò>Wi¾Á³š¾d ¾ðT=ÿK½s“¾)<;>(¬P>’g¬>F(˜½bè:ÄP«½#¾'={‚ =x§9ËvV;ÇÐͼÈ넾�ä<Êtø½bÐ[>GŸ¾†ö >æk>8z«¼$í=�Hç¾·†¾ z»¾$]=ŠÙ0¾wC½Šœï=€…ð>ߎÃ=E?&à?>Í2d>u¢¾ËúD>Ô©ô½pò=—œ¾óf*=ÿ(ó<²=”¾hÓ“> ºt=¼Œƒ¾05õ½–»­¾†"®>42ã<-Q`¾ß¡’=á =“J6¼Ø4=½ì�>†?žF_=G)_>š“=¾a­>Æo”=�2¾ÍbL>bm¾@Ÿ½yÊ\¼f³¾:ÞV¾QW8<O¾]˜>z£T¾ŒË2=·Í1>­(¸>-àë¼|8¾Ì"¾ÉÝò½`ü®½å^÷½­5t½T䡾I_¸=æf½\[²=�˜²=2ù½>— ©¾-w>ÄVž¾±Ìº¼Íš–=tÜÎ>¾ŒÒ>¯ô£>aŽÊ>iW½ÃF+¿ŸÃ±¾èÌf=œ§q¾ÔÛ½²ð‡½X<>Δ­½-I>ìše¾Ôï½»3ü5¾Ý�>èÐÀ¾/óZ=ËýL¾Ã">åá´¾ýÓ¾`.²>ÿl¼´w¡½¹K¾Å²&¾“é>H\½�<½J ú½]3ü¼Õj3=Òˆ ¾G´¤½Ö-­=þÑÅ=øØõ½Ÿ ¾‰°³>°¾ö³Þ=’&¼ÑÃE½ðêb<šu>½R¸V> X>¤»„R‚=ïªÀ<¸½—�<ꎘ¼Í>Q™|==8ì=qþŠ>,.£=ô¿˜½ý´=tž >xn¾à)>”ŽQ=¿lœ½F<>Þ+£>†ˆ>d[ž=j¹(?¤c¥>¶ås>š+>ˆÇñ=PG�>ÀÔ¡¼ìê½+²=V�>ûï´¼ƒwÎ=àq«=�U ¾ -˜=uî=Ûj>Û½°ü%>~R¾Ìs¼íÎ>ÞÊ�>Æ‘>Qy‡½ÚË�=’~d½ß™©½Rœ>½ò<Í£X¾KAr¾‹í ¾./¾­¥¾`¬[> f–=«I4>[݉=—X¾zO<캾ãÁÑ½ê¡ =7cç¾cV'>² =ú¹½‚«ø=7œ·<×:>wÖ‡>†ªÈ¾ƒ,�¼)Ì>©×ɽ€»½(�a>z6æ>„¶ƒ½S¤¾²¨>ζ¾VZ«>–¨ ½À¢¾9¿´>.;Ô>ç÷¸=ãwp=£¿r>ù}¾LÇ2¾µ”>ú[v¾à•Ô½qW>½·Yq¼H~Š>¶:…=Þ| ½i‘�½=Xƽp„¾E¯ž=Ê`>J`«;{m>”�»<æH8=åè8¾Y¤æ=û=ú0ù>^}|> !¾C¼=ÎGÞ½Wnz¾šb»¼©ån>AW¶=ƒ¬=*¸·=‡Ž¡½ê?–½T- >{Ìù= &h=>0F>mþ=·<¾Çq§¾u}j¾kWB=v§¦<¡w*¾IRÑ<¥½f½\¤6¼$ ¥=…ãH=MØ–>Ș¾U$ï½µ‹ >‘ *¾P}‚½ßpϾ «>üQͼ² �>.£…½:…>Ñ:5>ˆæ!=¯³=™¦¾8‘}<)‡>B‚7¾&¡S>Ë?L¾ò³> ïZ¼ÒåM¾×Óè>Ëž̋{>LJ>å½QC¿"™Þ¾ÍÜ»IÕü=wh)= EÕ=�®�>›è±¼*ÙT>s” >J=¾÷cǽk=]%Š»b­?` @<½$:¾ä%½ýÅš>XÏ¡>ŸÅ1>—š½¥ ='8D=—mD¾s/®=à.>È‚ >( ¸<Ç/Æ=¶O>¶w ¾´¨½÷{>¥0›¾‘ǽéÆ7¾÷T‹½ÎøŒ¼ Ñß½÷Èü½`ø>¾&Š>osô<¬][=õ4=>É<6 ‘>Ò®d=†ÈÛ¼·j¶>èáo¼6³½XƽyÍ�>«eÔ¾—�;:äD?´˜'¾æ©>ò ¨=Ùɉ½ðäxp¼q¼µ+¾Î@�>8·X¾e ¥¾­¾Ó#K>Õrx>-b>(ª>–ff>uß»\v¿<Ç™‘=„ä´=+,:¾7)Õ=Ôw¨=ãGW¾´‚»©ä,>ュ=‡kn>G ?È�¾€5¾oÏ=¼À[”Ò½¾À>>¯´·>s ø½æ#[½çK�¾½\P>ï‡6>»3i=¨¢½Öv®>÷=±>é Å=îq=žçs;^}“»4›€½èõ ¾Ò&,¾ÄZ‡='nÓ=´0>Λí=jÿó=x«ˆ½Ã+¾ÍCG¾=¼õ<ÇdÜ>‰ö¾ ü¾á5e¼>ü¶>î#‚½»ûŸ=ÀÅê>û4Q½ïËA>�…£=ÕZ"½•’ ½Õg=s·ºáÄ­½¼H‹>ò¦I¾ËˆP> y”½ÆY`½ô †<…v>à ‡=^pO¾Xe=$‰>7—>Qvͽ� ¿½*"¾}9«>+È=Ì\I¾±Þ>55e>ÍÞÉ=áÁ#>±Ù>L(Ô>}|S>«©÷=,Ë=%V‡¾‚{<©r <Ò¬=åUù¾50›=BYP»Á‘ÒÛ‡½éS>˜¥®>XƒÞ»ýËz>ÏíÀ>ªó³½Ãïå<,Ü=>s1º¾UoT>g¯ç=3¯=4±·=]:=ƒÕ©>O4¾.•ð½ä·½lY‚¾&u<>¬{ä<\²Ë<2G¾¦}D>Ò§k>¢:Ñ=$K‰½~ÌŸ¾Áõ0½¦ˆ¾§]œ>Bñ•=L©b¾rþ½2™r½8J‚½�"> òN¾‡¯�½BeË»u}ν-Ó?€ãž=È×—>ê�¬½¿?>1-¾_†M=Íñ ½šïH¾2‰©>ëK½ÓJ¾žŠŒ>à#5>‚ú‰<¦n©>—K@>¸½˜é„>†ÜY> +=¾çx;< @–½UÖ >�ŸW¾O&D>�·®½ý-§>pgê¾A•¾ÈK> Øq¼’%|¾K|¾Û8é½ A²=s«½\ˆ= é~>Îjï¾1A¸¾»“¾œå˜>¾cM>¿R¾æ,> *™¾mz©½Ý~5;²á¾k«ë<¡}W>.𻽠L¢½u†H<ý8¶<Û¤ ¾ù^¾ÄR->.‹>}’`¾>¹õ¾®d¡=Ì`o½Ph¦¾“´>>�Ã3¾AQؾ”o-½kº<›be¾a’±¾?ö>AHH=^±w>ìZ3=Wfö;ÉŽô=1ý>Ç‹ä½�N‹=ÒòľW|(¾ÃÇ >9y¾@ll½>£>4Ê?¯ ¾ùÈH¾�ËŽ>’{%>�þf>�na>AC^º/}Á¾TN ¾£Ü½òØÂ>òŸ½Üv»“q)>Ë©�=œÏ½ß6<„¦ª¾ã•c>N7¿þè>JM¾ C‚<úœ>-p<‡W‘ÃÏX½•L‡=§è >Ö‹‘=vÏÂ<+ãÀ½��÷<© U>ĉI¾åT½½d ú=|Ș>%˜=«"z½ˆ{>È[>ÐM…¾‘2½ÃÂ= `¼Ê $½•é–¾Ñ÷¿ _ô<�ð„>¦€=4»ü½~­ë½‚Ü#½„òð=§*A½Î#ž½ã±Û= 4ؽ˜�%½’ ¾)N½[*¨>sB^>5�¾)½¢<ÉéV>£Åµ¾�þ«½@`3>ÉÄ^¾YO>J ™=İ2={Ç?/mÔ=«HV½àƒ>ce¼Tš>Rk¤¾ø;³Hܼ‚^>øå¡½¥í½ˆý¼=J®¾c>m�¯½P¯,>zȾ]“¼= U(¾<¶½Ò‚�=}¯)¾ÆYá< F<¾¼}…½BÞ>)xû=Mé=¹‚U½L°Ó½}× >>³>�ɹ=—Q²½ðYú»î[>‘;e¾-ì ¾lßø>€«½�¯Ö¼.4„=Ûʼ½„˾R‘н»…®=$#S¼4b-=ý)Š=3‚y<Ê¡`>±úľ™… =¸t£>‚ú³=gqÜ»/¾ª€>æ�²¾¶˜m¾Ð/¾½Üˆ>{B ¾Óœj½I( >c§ý½€™†>'Ѥ¼Ž“´½®YŸ>Þìà¾Ñ”Š=SÚ‡¾è=žxs>�[€=Äó>_Ñk=åY >²`>bõ>_eš;³Áû=Ãü•¾h½QÒQ>3àz>ëùV>õŸ>ƒ—Í>¹Bß>Ll޾y“Î>¥u>ƒ¨Õ/<]¾�Û=IFV>±’>oè•>ìD¾gÓî½õ™4;ÄŽä>·Pù½Àä>™%>J>Ë´Œ»ÖO¤¾‹Ô>`z9>ݯS>%>»=ö`>:Êb=._Ÿ>üß1>%å+¾ï¾žï¾€•×½ø6Ã>˜f >£EK»-ØŽ>JFæ½îQ7½UŽ£¾E#»RkJ; §>× ¾§”¾²å>[Ò½ÊÓ…>bB¾—¢é½ŽúȾ4/ž><åu9³Ž=R[½¾èôE>à˾•êl=Kèü¼Ef½þçŒêèJ<)ZE¾veÆ<@¹*¾çÖ‰=ÿí¼¨5¨t>Yñ>'£®>Ú0[¾¬¬N½T®ºŽ}´>ÐE¢¾Ú1Í>)¹ß¼¨þñ<™Ûº>"Ï!»ÉŽÕ=ÎÜk¾óHË>Sè/>í¯�½âpa¾&9Ú=¡¾½Ð>uT­>Çh¾o!¾é1�½”Dí=�½þ;dž>ÿÂØ½¸As=²Õ†¾ð >6ÉH¾VK6>¡ÌÚ½Nw�½ä.>kȾk�U¾$ØÆ=|“¾mQ¸=kEü=Îpë¾]Ý'>…Dv¾Äh¼½iý!¾fÎ=>\X—>í$>;E4¾ŒWö=ýØÚ=ó%“¾˜½=�÷†¾ è ¾tQɽ œn>Å$¸;Ë—�>\Ò>ø€:½’çvH/½ÔЬ>ÖÛ9¼¹é£¾Ÿ7L¾0ß)¾ÇØ>lp˽~Ћ¾®›ù¾i/d> L¼>¡´;¼Ï ¾ïôŸ=(à¾ëº‰=?GI¾~ú=Íÿ=Ý€ ¾š«ž½“©Ç>|PS=>móÛ=.;о±ãN>Þ)>Úr¼¼�)N¾(õ¼j»=mH>5´¿9‚<úF¾(Pœ½áÊí¾Zg<Ÿƒé½0­¾ÁÔ·>íŒà<3W¦¾½v¾Çp¢½¥½¾à>Iìü> _¾É–m¾ÞˆU>+¿Œ<¿é•½eŒ>ˆ%¾Š»<½-0-<Ô&Ã>ž®%>îÓF>ѱƒ>†ðоåÙ�½T½HǾ9~Á½ÉƒK>©½¾¸$¾ÞÔ¾KüY¾ŽÂÓ<žé¤>òÉæ=¦ì¾… >}å ¾îZ>_Bc=¨€Ÿ¼ÑÐS¾¼Au>Ẕ=õ”\½ù¾âë¾f ¶½™þ§¾+žÂ½‹™¨>X>¢2@¾Þð=j|å¾.ŠŠ¼Ã® ¾Zc>¦²&> 1˜¾ͼ=©_¾”ù¶¼ŸcZ¾×›Y=¦á^¾Ì[¾¾B>ÀMr>VbV>|Ÿ>>e>¬0v¾–‹v>*ùr¾öeN¾£Õß½èôƒ=‚ †<ßo¾ ˜*>ˆˆ>á3>,°½³Ó>Ä¡=-¾ÿ=WÝ–¾�ε½²ÃÚ½U a½tÕ<¾ ]¾ïZ{¾MÏñ¼Ëšn>Ìc>Ð|>AŸµ>‡:†½Èg•¾Jvå;.DD¾–Œ>“ܽ«öæ<v|<þ„I=ø.‹¾Ižq½”TƼK‡»@k*>YAà½Á›T= Qú½ b¾éŽ<§Ø>RH ½±L‰¾Æžã¼´f—>æ ¾Ù $¼Öù=–‹=¬aV¾Ù#M½V$¼¾·a‰>¨:¦>/³³>x>Ÿl‹¾pà=· ¼;yµ¿ñR½‚Ñs>üD>¿úO¾Š—ȾÍI˽ÊîV¼…>‡°½t¾ì<º…H=䮼¡W¨½˜q¾�B�=<¬Ž>Gâ1=½ûX½�/"½’­>ÿš¡¼ˆ—=‚7½!\?ØHG=E9„:Mp.=\Ã<&–H¾‘µÒ¾0­“¾ÈiR½{ ¾]z+>N×>O‹ø=�u>/öû=/7'= c!=ĸ=·T¼½p¾ÍäŒ=ˆr·>@žÜ½JOú= L�=Ææ�:o-Z>å�U¾~ªÐ½g‘š¾U%½¢Ï‡¼¨]…¼ˆÅN=ÕÀ´><Œ>¯Ó ¼Ü§?ï'•<Íãg> å½ô>^{=<@ É=CÓ??ý½‹`<½Ùd)¾ûö\>èwš>À‡c>ݵ ½Á·•=¡nW¾ä' ¾;>Q>›,>÷>Þ4—½ßߢ=�z½eÎ>ˆeÇ=¦�¾›f”>U»”>~à>�—;¿“ Ò=gšÄ>ƒÇã½@B ¾_-Ã="°U¾Q„=Ì´q¾ãWþ»”Jß¾Å2Z>#ÑÂ=¿">è26=A–á½»Ž ¾�7>4ÿ÷¼òÐ=˜J’>h]å¾§è¼ðx­�ŠG>wGµ=„抽CÒU> ™“½uý†¾=Âê=d>X²½9*z>WAä¼îhq¾c #¾©* >”&¾H;é=ÐÛž=—¾½÷d>®Ÿ±>’8¾Á¶>*óp½§<­7Ó½z‘ ½=M…¾b>Šøþ½ß€¾}+û»jXC>ÝFM½>B‹½ýë¡=%±÷=0þš½ôÊa=©ßý¼1g1>¢6 ¾ÞvÕ=“«°=‹ ¾Wy¬½C¾8½ýQ ¾Ífe>1Œ>–gV>lD‘=f >’¡ý½ä£!¾>¨–=¬‰”=Rƾ>|;§>!ªë=î8_>˜›ºÁÀ=¹_<‘úã>Þ[<|ž³½¸í¾ŒV½èj >Ç=µ8q½CÈ>À”ѽ^Þï»ý5¾sn½¡Êû½iÂþ=›¡î½ýÀ(½ÙÌ=�\ >me=üé:¾Ál„=§E#¾3û­¾ä‘¾‚™P¾V¶L>ó–>S&Ü>säÖ>�€=0±ó<Åá½êcø¾sÉ=QB>ÓÀ3>Ö:‹¾ï�¾.úݽ³ük>ˆ=~>häl>ª=@Æ^½qj‘¾Ñͽ¤˜¾´°ë=zÉ<Ë“>CQS¾ÇXb¼ög„>š%¼’€Q=:O¾ˆî;=–+¾Ñ³~> ­¾Ê”a>O÷Ľ|a/>4è8><Àã=”œï=AÎÛ;ô9€¾\_?=‰´4¾» =zÃk¾! ÷>Ö9¯=É»'<½õC=)•F< Ö¼>æ8š¾¾O¾,D¾ þ<>ðj�>;–=šT²½Ü3>n¨ñ½¯®¾¥7€¾¨Yf½*A>à�1½§,¾¡uv½Kc>l8\>ÅÞ2¾?ÕÙ¾Ëd>Æ©==€L ¾ò €=É̇¼a~$¾ õi½ÞP½]ëÄ>5t\>W8X½3O>fcν¡…7=° ³=ß@Þ½p’¼ v¾s¾ÇŸ¾9ñ,=ñÈ=aŸh>!Nä½ÄV0½¯Md;¦½¶²•>m=*娾~ÜÈ»Ì7“>)ô>­co>—£½Sm=qUé=ºcÐ>‡Ï�>£:&>ÓÄ›¾ÞS�>ÿÐë½U¶»:ðØ>jv¹¾§-G½š/õ=eZ>êT?½ ›§>™Ü!¾(<„>z>¬P­¾ˆŒ½õBœ=ŸîY=9µ=”îÐ=•E¾þfM¾< ¾’Ò6=l,¾Lî¼ ž=ÿŒ»Æs£½¶q =;E>«ÔY¾7_…=‹±Œ¼VžM=ðæ>£Úº˜B©¾k™Ý¡¾‹b[¾p>™>ã93>yy>¶ªF¾ySÙ½Ó w¾ Zl¾�F>Ÿ© ¾"Ÿã¾úê_¾Ý™=¾ìÏp=04”¾×‹�¾Ž�äº6Š]>ð0£=ØßþM¬(¾š…c¾ml–½†8;>rjå»y'¼\ï€>}ÓÁ:‡x¾Kà$¾8ØY»iH8¾¼Ý>&Ù6¾›w—¾0­f<®Í¨½nF¹½o1’>¢Ÿ¾ ¸U<¦Ùž=ÃPn¾f:Þ¾GŠš=-7:>Ÿêc> ÷> O“¾ëô=ÞDs>™fÆ>Q‹ì=E_Á½ßvL=�¡ >9“»¾zðD¾¾ ½¶J>šá ½Œo=>h�¼[ì,¾*¹>Ã\’¾.‚Å=Xª¾Ø±ð=I†Ð½T¤ =?½Ê¢>b¦¾Gm$>;>(§�=İ–>cÕ£>óïi=‚œ«>y¶Ó=즋>åß=_¼ç¾§F¾îk>„b½=tåE>îz¼xر¾-Òœ¾&Ð=vÎ=Æ0>ïh¾ˆÄ޾1Ü�¾òë ½Íë>äjê=,;¡½©!Ê=…‘¾ ƈ=u÷/¾Šõ¤½$v>Ìà%¾Yʼ8¾û.>´V‘=8Ç•=ž^M¾ä×Ò½Ùg¦=iAмŸgB>;i‹¾lW¾–#¶=¸Ü&¿GDŸ½œñ<™m?¾žBß¾ÚÐý=¾_8>ÍÐU>G¥è=°'ü¼02<Ó²&Ç=f”™¼eT¬=-£§>L7¾Gƒ>~·z=‰¾ ¿¡½æM+>½�±=•Žò;ºæŠ½˜A¦½Éº6½¦é÷½=Ã>¾œœš>šèæ>óåB=jH¤>[‚4>Ã¥�=/ T»sB|½D%X¾µ>à—&½%É‹¾ÊÞμ�^ú>uD)½Ñ ¥¾5¦Í¼\ïA¼µ{>»sž½^w<>çaD>OÔ’>i8'½ «9¾bP�½œKù½N“½ Ãê=D�i>�È>r\ß>ßv>Šû>–ML=G³¾‡8¾6x-½.ã5>pu¾ýpí½†ôʼܖ¥>H,)¾æ‰¾gn„>`ÌŽ>Þœ¾o±3<ïí{>“dM=ÃÚƒ¾Ù\>¾�FF½Ž»¾†×9>“‹"= �ù=[Ñ8>BÖÉ=«>öÃK>>a~=‡v=çoU¾1ÅZ>qç>˜Ç§>cÝ‚¾ð:¥=é%>‰0³»|†€½�ýÿ¾³¦>6�©½Œ ½¼ä0¾-ÅØ¾îB!¾ï_>Zwß>“E–>¿¤½êtލßO=AÈ/>wsB¾½½H�W¼sˆ·>¬ºZ¾Åˆ>ˆ_¾uü´<÷øA½O¨>`$ü½RÀI=–åx½cR">nŽJ>»ì¾¾Åα>{6†=T ¾MPÔ¼]¦=ÔȽýn�>Å®™»Û[½Âؼû0 ¾·ž’¾±ïоO ­:Œß:>AW¾ B¾)€=p,>aQ꽑»qɾ(s>`ǾA�=.ù—¾¤> #F½šX§<·xY¾€Ll=îaJ>2¾½T¾ò#‹<7âí¼áÏ*½ºôe=±Ž¾ú6^=ZÕž>›Ü>ªÒÅ<ª– >�…–>pA/¾—ž; 9�=ÀËö¾^×È>Fäâ=0 >È>olÃ<$g¼>Å|Ö½Úu¾Ã³:½ÄEã>HA>ŒG¶=9·>e±§=vD»Ös{½ŽË·Y+>¶¨½Ô¸ª½m#J>�Ô,óÝ=¯R¾|´)¾š‡>»z@¾·Ù¶>YLû¼þBȾ]ë„>ØNµ>~Ô> �=Ôˆ¾ÙMF¾À›S¾Ï >³º¸=CÖE½–^‡½‰ÚA¾Gcƒ=“¾{Ò·<Æcd¾�ê=HÙL¾Õö’>-–¹< žÅ=ûûQ>çÜ4>¶˜ì>Z4ä½KA<>ö�¾ÛÕƒ>N@¾ˆ=´¾ZÖÞ½ÿ~¿½¡²½îôŠ>ÿG >ÁR[¾Ð/ ¾/½ÜC+¾” :‹6>›º¶>aÑ> œ½î…þ=°Õ½ö×7>yÖâ>퇾, ¾�¿%ºŠ e¾U¾ôë¾7ï2>žr ¾å¿©¾\K^¾‰ïí=& >ÿ=̦=¾X/×¾@“é<ü ½ £=4þ½Ô?úÏ">æ j¾Òn>ÒˆF¾ƒ×=­‡>xÿ¬<ö½gè´½**þ½€<ºÚRË=¤}ˆ>ðŒ ¾¾‘.>ê_’>ÄÝ=ç&Ï=ýù"¾ÿì¿¥°!>OÊ=Iþi>ã…¾¹FI>»ø½<±½'BÞ=Y�j»Áÿ½>Ë+‚½<)´ú|½Où>ž7¼¬<½"¾�¢¸½¨ç[½Ôl >?¹Ë½oÀ>¤çG=Õr}½.;k:ð9+¾…­Ž½B·å½ËC¾ÿ =üœ ¼Éñ0>{ت>«…’¾(·¾—€–½µé`¾¤‡,>‹Pa<¬ý¶¾ñ ¾)˜Ð½†Ð}=o)Ö<@“ø½¹£<¥M2½TÎx½;=£9O½®Óͽ ©S¾|¢@¾?­ >å΃>çš…¾¿%¢>Kߎ=u_–>ÜËܽ·M>9Pq>2ó\¾a“+¾pÇ+>Ò#'¾Ô� ¿hÑH¾L0T¾æ“,¾f«™¾‡}ù½ñéõ=L�½ÿ…@>Ër“¾¨"¾lἺò=wž^½/¯á½jv=»#>ãð>‚ʾh^´=’úJ¾àWh>æ-×½ÃôŸ=޼ >¨÷î½ ¨}½7f'¾ú?¾9`齨0®½ ˆì>íV0¿Rn3¾ÙR>Ù•½XUG¾EÌi¾%,>M­Ï½2â½ðð³¾ HM>ßN>7±=wàý½røÕ¼$þ¾Ñ‚€>É>|˜Ý¾³j£¾Iu¾Ü–�½ÈM¿<±ý¿ân§¾§W)¼¾”ž=ÂR½1`>eªª=ôtÉ=—$ >]d=c6W>�W|¾xà‘>#õ?GQ¾V=Y ©½h|·½ÙÚÿ>ˆ�=): ;Ú�=w©3¾%È/>H9C=Öë:ÂiQȽ{ã<½;“¾e޾L‡‡=�üŠ<ÿFp=äa¾�ñõ½¡ûé=,K,=¨Šú¼uln¼3~>/Á½óB¾™§¾GøÉ=–îX¾{¬P½ÉžÙ¾²Ò?tÎv=ÞCÈ>ÛǼWN½>17¾Y²·¾"ƒ>Þz÷=yQ#½ž®¾x+ >  ð< Êü>¡9¾—ˆ½‚±ã=¸\C¾éŽÿ=•9˜>¸˜×<ÿÕ½ŸÔ<¾¼ß1¿5 ¿J•›>蜾¾B¾w¾ÿ»¹7éú‰¾Îá3¼Ôsš¾±?•¾”„?¾D¼ª>*øÞ=Pü²=m�>Ýêù½äÂÝ>Êà·>TJ>…V­=±®°¾`vоðÍŠ<äV*>Nê½¼¾�@>ðè¶>ºN>�ð>Âñ5=’?J¾C±c=×/¾7–šµ£m>ø¦ø=™ɾiP ¾T¥ô=ÖÓ>Lm< ¨¾$>-€<ŽÄt>r³æ>[˜o¾u\G<å ò>¸_¿ß 6½ ¤5¾ú¯=C$>;õ¾éx¥=͸§>?‡>O†Éº¡1 ¾>kN¾¦$¾yÌ®¾Óÿ>5ßѽ",�¾Ë =O� ¾ìj}=W¡½ÕäÀ:�½.ξD—h¾Õ¹1<µçº=,\«=l¾½òû?. ’>B¦>q>Ñ‚½ªv½fJ¿i_õ¾ C>Û¿0?â=¬<‹¼=Ò· ?·Á­>¢@>�/€>(å5>õ±U½Ý"¿WZÄ=ÚqÕ¾âF3¾[œ.¾ºÀü<n½x¼œ¾¼á.¾ xÞ¼•~„= M½/i˜>íIw¼ˆs¸>Ie¾[ß»½ y¾O^¬=€µF>@ü“¼Õe'¾yÔ{=†Ä5¾¡y ½›Óм™<`ðË=·]â½K®]¾±°¾W6>oÓê¾aÕ¼z¼k¾­ >Ö[¾¦¥¤½à�M¾ËEy>;på½Ì¼ ?!þ�¾iN¾Ìù¸½>(ž>{,j¾¾«£Ð>–D=mW<Õ2¸=Öt‹>Á•>•´Ë½üÖM=uXÙ½¤>[*> ¼À=s©>É §=.eð½±Þ‹>]á¾å2>y›S¾ºü½╀¾F|¡>r¨N½h²¯½+=Õ>tš1¾à¾ní�¾yÚ#>å²ð½ã å¾�i~>ù™¾V¤¾)2Ü>yw>_�>>ZD>çß�<;€²=~Ú'>)š¾|> >¦r€½¬“C>ÜQ¾º¼´à>\I>ýÜï½þ5>µM>Òö5>X…ç¾gJF>ëD�=ñÔ=»½7=Ò‰g½,s¡=ÉÖÃ>˜¿w=êf½ü3 >N„‰¾q™¾]v_=T#Ľ�Õ¾«@!>©N»>>¾£=X÷<:ïk¾Ø¥Ê>Ù-¾çÒv>I̽dÅ?>¡@>œæÑ½‰/¾Õ >*+n>Dí¶>4ÀK½8›[>ò`F¾% ·>Üö >;“Ç=Ù/·¾õC¾ýÞ4¾Ô>†½V¾€¾&°=ó µ=H÷>‡Ç6?¬‡£>Ñ0þ½…Mî¾>±©¼ÀÒ(; >€½ -=Z¯´F¹€¾~xè>µ@Æ;øhà>JÿÑ=ÐʼBe?½Uj>>d¾VyX¼Â$ؽNÆ>Æxð½·�‰¾80 >£6¾$7ï½· =õ >R_n;ËM%¾ÄªÎ½ê¸½­Ö+>½2ZB=4§>|ýï:ßl·½ŒiE¾Èð-¾â�¾òÔP½ŠM=Ȉ}=©o=\¾t¾[o=�ˆ¾=“D&<ü~¾È�¯½!>“Í(¼ˆN¶¾Œ ¾3ØË¾-ó=ÎÅë>}'> (C=½ç~¾w@D`=Rx!½g´½Sö¹¾sÁ„½üë >ÈB=´A+=W,>[©¾Ófˆ=ôöÌ=_—>�¾’(U>B“£>Sy¾â¶>%¿¾Žµ½¾W½ÖOn>¬]ç½´Ô<%Pê>w¶¯>$æÓ>œyS>Jj¾„6]>Þ]¸½xùG>~; Ç¢¾v#ó=.¯±>Ã$<îP>‰µ<2“—¼¤�A>㶯½{|h½Y`)¾dÒ%>F½|=¸²­>¨f½×Àç<«�† ¡=¾¿Cæ>]®Ý=ÕJt>Ûž¡½M >c¥O½ÚÈ9=ÓS¾G罂øw: £<Žš­=­[¶½ ( =‰[>Xå½Î¥š<¶ ù=-@–½%U£½ÆÁ¾Â®¼¾Cê =§¤0¼èS¾Í>|=²ŽË½?¦_>*‡¾©ÚȽÑwØ>Õ"c=fVh>K2œ¾sˆ¾Há>ã76<ôÁ½Óèþ¾Ú1%½»±—<‡0­=²º”¾.—_=™Ø'¾ <"¿E‡`¾âÒ5¾‰‹=¥Â¾2}­=AžÆ=‰v¤=éõ¾nû>‘æ¤:ªmӼˌg;ÂQ=>ìÖŠ¾3ìØ¾ãˆÓ¾ë¾U·¿¯‰>ÖS˜½ /ʼXŸu¾jN¾hži¾z˜0¾Ò°˜¾ˆ2¼=KaY¾8cÁ>x½¼Ÿ¾\ÝÁ>t ¾¢¹½ì˜d¾c >G ‰¾Ê½%bø=x £=6ã÷½:—¼½Í9 >Ý`‡>Ÿ¨2¿ì0¿»:W¾”f?¾/ß&>Ô8ª>`ÂÙ½@nã¼5¥’¼{:v¾Hòù=~ó=TÕi=[´¦>Ѧ·=q¨ ¾ÒkŒ=~Š‘¾¼“ˆ:Ö¬\¾äp̾ÕkÖ=ñ·.¾˜6½ŽŽß½yS>4¾=óÙ7¾·.±;6¸B¾ÄÖi='^=ý̼>±uË>R˜¡¾_�h½N„ƒ¾WÞx¾°Ïç¼°]=ÿq>o—·¼­_Ö½¾0=>±AT>ɘǻybÂ=I¾ T9=½;£>=-¾nÀêºän[>g;|>4q=,ù0¾9¥–¾¨7ï=AR½dŽo<˜2Ö=!°Å<�ëÂ>ª•‚½ø «> ž¾n�«E>î¾rh¦¾ Ø*=*°h>¦›>uÐ=ŒÀ=u²u¾(®Â=ý˜‹=È/¾øºs>®ãùs>GëG=¥Ã?>܉¾Mš>“tõ=?�;Ô=¸ø-¾µÖp>tš]<_ñx>ë¨â>«@H¾ìr‡=T<½=:ª)¾.~q>¬’'‡É½�?ÛB>¿ž´5½ïŒ…»%Ê–>’X5=“ʽý0?bÐ>E£>›¬1?7]%=ùª?ôsY>=�>Y6•>ÅæŒ¾‘;/>S@ˆ>Û(ã=°éF=ee�>…tº½¥�>Nî–½a4Þ=… ¾w?!r½ƒ¾½¾áE¾Ûà<ëÒº¾•ž½äq<ØØà>n²Ø=~Ž5=¯>ö=z ¾?§È>ßʼ¦a‚>\†�¾á‰ì=0>?3¾D8.¼ÊÍнÆý¤>ðÏð½` ë>õ0h¾ ‘¾ë3>p{ô=n–=§]J¾ Âw>T¬a>ì1> Ö@½¯S«=³=>GI=>g‡ >Ÿ£Q¾…'4<ôìÓ¾rY¾,>é¼hòÓ>€s[½µS¾Zç;Èp>Á‹K¾ž j>]æ¿?ë½y5¨=S\–:�ˆ—>²_>ør=I ¼~~=�6>ÈܾYë½Éœ;½)ˆ¿>ÿ’K¾¦Öc>Öl’>ª¼Œ>� ß½ÌòÃ\د>2ÈX¾•WL½Kz½\¹=t{½´f¾‡ €¾}<Ã=[îd9€ó7¾%/”>ÔÚŸ=fƒ¥½y�‡¾¡?¾ÝÐ4>!€²;5÷¾ôƹ¾–¾º>hüO<ÛÞM½‡á¾'Û½A�=ÖÛ=ä‚¡¾œff>{•ó=²ý¸=f&>s Ì>`™¤>[„>·é8> g=ÆË>r~ÿ=¾Æ”¾òx½Ñ�îL¾n� >Ë4Ä>i¸ß½"¨}=†Ä»¾W€û½gÐó<® ¥>óɼ¾»ºÓ½U_*>˜Ó¼'â=1Û½óEB>.è>l^¿…胾¤z³<’ÛÔ=�©=÷ÿ ¾?…>[ÿh>­x2¾vˆ­<5ƒ7<`  ¾×d­;Ú½¦¦-¾³»¦>ýÓÀ>"톻–¼~>Æg@¾Ÿ�¾U«Ö>5®>/“¾½\®Ê=WÇ�¾b¦%½`i­>g¦•¾¯{¾tSÝ>’_Ù½vYR>²q&>ìȧ=ì¾>oÓè=ºI ¾'Qʼ/¬ª¾XŒ=}§>Gk >óý�»Ÿ¯>>ñʽy¼Š¼lR<÷ô¾&“½xL¾_>¥»Õ½à%¤½É&ú> ¼½4=J,>ˆ í=të=1bŸ>à)3>ÖžÕ=Uof>û�d½vÏ9¾´Q ¿*Ò=‰ŠŽª¬¼= –¾Fús>ûؾQ”•>Õ¯½¹ï>XÛ‰>„ÿ+¾ bª>Çj¾W9ݽ~ow¾�=Ž—ò=:¯…>Šø·=²k?•g˜>j·y¾?7«½;³>ìð¾ïw.¾‡É´½"iJ<ÒQ°>»ØÕ>UŒ5>5ë>*(V¾Í¨Ï¼d¾gr ¼%Þx¾‡ƒœ¾vZå½}¤#¾½Ì‹‚¾+„Ù=;DRºÎv¾ =–¼ØZ¯¾°¬ð¼ ïf>|‹ß¾Û&Ö=0&§¾þ j¾hŸƒ=�Ç >°²u>hT¬;¤Ž=ù›Â¾wü‰¾ô½œõ>¢nV><²¾“Y¾c‚>ò—Ç=Æ�Õ½üྌU=,>¹>¯9¾• ?_åA>œ2ß½Ù›u>Ⴞ^…ÿ=bö=§;¿Å±ä¼|p>�Èž>)´®=„~½!!ÄïF[=sMÅ>ö¯Õ»8\o>Í`>!‹á½�¼&¾÷šó=<Êú½CT�> Ý[>åk¾"ÝŒ¾=Ò¾WŽôö½ðÓaÿÔ©<ˆÄ‘¾ñÞá½�¬‚> Ô>²Ñ?=‰A­½F�¾PŒå½§¥ë>»xï½ë–'>¾Ä3¾Ø�¾L}¤<å&&¾Å®ô<ak=ª»e>ó)>›F¿É÷“¾ÒM>›¯‘;vf’½ORã¾/\ì¾GÃ>°›�½×—?`”©=-N ?/`E¹#´½›‡I¾I½½Íy�=8'‚½,R~½öDÞ½Žð¾“à ;h;>¬«>·A™½0j¾ ;-¾Ùbu¾ÀWó=)~>��N>Ô;¾q¦½=ht½_Ò=K>f´j¼p­¾‘�<½�³‰=Ã÷¡> ãô>eÝ=ƒáö¾?9>覽¦NÜ>-ñ¾‡Ú=�°=v:ú¾JɼÑÐs>޶ñ=‘G>c”¾4>Ç<¡|…¾Ë8¸»î6¬¾’Ú <ìÀ >âêl¾\If¾_Gq;¡G¾XD×<àÆ> ¨¾¨mp>Žg¾éíݽqÓœ¾û==þ[½>9¾j¹”=ñ6&>{ñh¾'Ò+¾rUi>!>¾pÆ‹¾ŒB>À*‚¾f¨7¾Ž>°â ?V¨‚>�/>QGèJŽ>pÀ>~La½¯Š»z*N½Âèò½½¢Ÿ>?U½H?|Fû:£¥ß:ÿ˜2=%ü’=lcz<Ödï½qÕ¾>«r¾ðâ>U*½9á>OW>L%˜¾2äˆ=èòÖ½¸v>¬þD?æ<1¾_¹˜=�Ì”°|‹¾å./¼ ‘)¾Q0 ¾‰˜”¾V==ìc¿«×˜½a›=ÒÝó½™o>!´=ØŠ^>tq=£H½Ó›>Zľ7|ý»Ì)&¾‡�¼‡õ6¾Cà½(¿¦¾+n=zö¶>Îùw>È’Ë=õQX>Ãs»7 ½ç=½­�¾”|.>¥Ÿ ½æ·Z¾Ÿ�Ð=ôÇD>j­Ž¾_c¡=á­:½•T.?³›×;òø=óU¾öÏÆ=5¯ù=è*±:BÃY=&^ö>¸3>ƒ?“> _<_î…¾¹‚|=—õñ>›d²=Hù¸=“I>‡¨=ì,>¶ôž>|£þ={¶^¾{qÑ=Àû>IG >¡[>RêÇ>n)Œ<ÜóW¾+y†¼\V¾ÝZ{¾z˼¹Æ ¾Eù”>ùu ¾\wc>/Ú=”,“>¢â >©Äø>|-¼ƒ ¾dξ^Ý!¾Ç1¾i’ó=éɇ=¹ÊÁ= ^¿Õa¬¾U>>G¬0¿‚à¸= †ÿ=XAY=äC{½/ 1¾Ú¹>Bk> ÿóe> 6K¾*fƒ¼x¥½Ì|I½OP´½¹7ó½Ü/5=Tñ2¾ñœ´>ÀœÀ=r ¾î~>FY,>ò™™=ÖȾ‹8>+ôé¼cy”¾C¥X>)R ?…¥Ä½! n=Þ¾=hâ=À"<>ٹ꽧G”>ÄOè>�‰À>Pt•¼ :‚>è˜Ý¾ðk½wFž=2Ú@=Ùž >�$>Gÿæ¼î—¼<Öœu½$”½4Œ�>–>ˆƒÝ>v-¾E b>q^>�¸K¾Ï\1>F1¿u¸U>Å. ¾� ÷½þ¡Á<¡H¾¨rª=¡Ö±> FĽ¢¸Ë¾Iö>W(m=Þª”¾NÀB¾ŒÔ¾\XÑ<­—?§pÿ=ÂNÓ>qôY=µØ¾îL¾ ¢§=Ü ¯>Û8ƾUö¾Ó=/>€ø?=ê¨O=‹¾6b¾o N>¯`ò¾QÝH>ÖÎe=±Ü=.‚k¾Ø«¾˜,e>¸xš¾CႽRÙO>�ˆ2¾›�í=‹Š½2܃>ç†{¾7È¿SuŽ%þ¿êj”½Ží¾Ã^?8嬻i ¾¾Tcã¾´ù¼ÚE€>YÅX>ØðY=ˆÊW=Æž�>:~¾<â >3X¾Ðy¼>™æ—¼‘Mu¾e5¾ÝÞ>îš;9#¾€·¬½O@õ¾N7>_º>`ËÞ=;¨ü½î(ë¾áHC>É ˆ¾?ëB?e?¡¼a¯Ñ=VV¾;¼¯½Ro˾L.<žï½2­¾×žE>}žÏch¾(Ï>OÎͽûÅ>8e!? »à>6r¾Á)©>c�>ÿ=õC¾Õz<ì0#¾ R->Õ+„>F΄=[ãS½©ån>M-˜>pÕ->¡ù¾¡vu>4m=3P–=ˆ°Á=�i½§XT>j3�>JÄa>¤¬ž>IÊ�¾‰/‘¾Q×n¾þ¡4>íòW½û½¾õ¯^=O¼¾s¸¸¾áå>F7Ÿ¾½©=¢º¬à™=éª>žz>>¼–¾Úÿ=>+ðÐ>ú¾=?ç>&�­¾«ÝY>QÁ³=W'0¾-xõ¾�Iɽ¯­>âf¿ J0>GÓY½}‡>;²>%ä=– P>–>>%Ž)¾xÉ]¾Ôr|¾±7ĽMC>y¨¾£˜}=¾§uâ= 'j>[¿="ݾîêk=§ >ÈSF¾çËà¾Þâß>X‹¾5ÕÔ>‡Ž€Lƒ¾ÎÚ¸>y鼎„>>kï ?Ž-J>]ª0>I.’=Mg>ZÓ» B>fÖ>š&?T}Ž>(£=Ë“¾»‘Ž>5Á¿½~È3>Å�ö½ãt¾7M�=Š»_=†>ždž¾Û·Õ½¹²¡»WlD?Ùb>@¥þ¼5u7>Œ¢¢¾ÂQ;ÿ[P¾THl½�ÁU>Îí±>zê¿ÁÊ=³Îè>õü…>¸Û >£*Ï=W¥n¾Ñ!½Í8½ŒRË=]y)¾ö‚?ºÔ½’ §½b)w>®Š>£N¾Ùs3¾Á¦½¬D[=uv0>6 [>Ý>VE’½ª ¾°9,¾(‡¾þ„Ǿ’¾d¾žÍ=<šqŒ½Yì=Ñ¥>á†>úfιŠ]>Œ%>>ÇÈ#¾ÛEѾøCœ¾Õ€¾m™¾-¾“Øw¾\ˆÍ½à«û½qmÀ>a(¾a#…¾?–ª¾6ºü=Áih½:T¾Yîo¾¶�‡>F‡¬¾B ³>ެ¾#+ƒ¾þ�¾ šó>Óòɾ »’>pwb;9Xˆ>ÑD?|Õ‡>§~½cCξH¾�ݾ©Ð¾gÁQ>�ó¯>«…¾à!�¼ c>�  ½$Rë¾9ÊM¾ƒÐ£=†^*½c3c¾—”•¾Kb>h­ô>tÒ"¿@€w¾?å<ƒkï=¢†›>Ìä‰=NáÛ½4} ¾,Ès=°‘8½Æ8=Z" ¾lJå=›Î=7«¾ ¢�=Ö¾Îm€¾6H ¾³$Ò¾HŒ¾f+ž½m}='–`=ŽQ¾’Ÿý> .œ> `e=›«Z½3�ª¾¢o¢>“—º¾ÃR5>F…½žù‰¾ªÖ>íÔê½§a>i·]½¾š“½Ýù=©?òªŸ½HǽyæX½Mÿú=¬ôC½½u ¾wìŸ>!�?#>ølº=+¦é½€I!¾mc>ÝŠ->F�­;s+™¾.€>̰%>E¦È=™Îê½ú꿹Ë,>"=¾Ô…>­DK¾J�ô ½Ýj¾L¡¤¾ÓÉ•¼oѪ>”á:?ÝJS¾;]>ØÔ½”.ä½X?e] >mÒS<ƒ[> 1±=�ƒÁ>:Ÿ¿dA >$M>•²&¾un~½žÌ>€9£½ÙúR½À]¾hð ¾+Ÿg¾ÒÕt<�’·¾e¯#¾˜ø==wœ-¾È”m>R“=1v£=ŸÔ‰¾ø#<²!½<ÂO¾ ó9¾¯ð#>€Ž>Ýn>Ṡ>{… ¾_+ ¿�R„>1>ñ¾�蟽�& ?W°½(�T<`Ï”>À£¾ Ë<«þô½Î¨>Zfœ¾Mö]¾ºwU¾#§‹;¶q�>fØ(>ÒÉÜ=âòë»ß.×>â&>T™=Yõ’<±·›=âeR;• ¿SWt>sU'>�™£=Ùã¿i½è¿ñ5)>ÂB ¾¤ì€>Ø$>s“€¾·3¡¾±3œ½†ŸY¾©Ü½jSÕ¾µ”@?û\Ð>=º£¾~ùu>ˆ{‡¾Ü•½/”>üÎð> Ã=i¢²½zà½[ä>',–¾{f¾]]ò=þä>zû >V„!>m-¾I¨*½›µ˜¾@º>ì„ =G¶>Ú“q>f¥€>p$.>ÿÔ͹ž£ ?ÔO>n-=]â³¾êh£>Rpµ¾Ù×H=ùî³=À†ƒ>%R-¾æ/=>™*¾¨^Ÿ¾û˽ù›F>쎾›ð¹¾ÃW¾fŽ>@Œì¾[Æ=÷¨ª>-ô&>�ã¾Rú ¿šÂн#+Þ> }>±´>bBw¾ú½g>Ì %½ëBŸ>ÚFj¾DV½£¶#¾yœk¾’U¾Ñ»<áˆX>¦ŠÁ½DÚ\¾OC«½½Ç ½i)‡½¥i2>~Š =ßqνÙDh•¾áu½‘àø¼ú…½ÚÔ+¾�8ã=¢.¾¯j´>ž`–=ZF™=‡Ìã>%Fu¾á$>9v>9>›í½ƒ j¾hŽ™½¢=(qó¼Áà>ú—’>Ço+½$r9>VõÝ=x?">ix=Ø·“=ª/×;,Ƚ±ÊO>» ¾s­�½‘™<úºm>˜·R=@p*>ˆçg>Â(¾w½Ç0®¾Ã™o>Èd°¾Á…™=dq='¿za=AÒ½o1]¾Jã,¾§2¾æ¶æ>'nk¾øU3¾ü"œ>ôN^> è>ŽC->««P=�Ò=Ü5>ÉKP>úG|>£-a> À§½y5F=ן½H­¾si.¾Ö?ï€c¾ðã&¾ D¿t÷=Ôæ)¾¿¾ŸD…¾Í¤®>Ç‘=  >by-=¦J}>Ô´/¾ßH>B�’<˜À\>˜vn¾KÏ=?:©œ¾Xfœ>üq¾€U»>‘½>œ$£¼c–i>Í8ž½jA½è6¹¾ó¤ >!Võ½îR(¾v#�¾ô}½W¥>�öü½šL ?Dü>«Ã¾‹¦˜¾ßwP½s�ö=¶I¦½H†6>@í’¾Èã >Š8,>Ä;¾kžÝ=;†>âv:¾Õ™>œ�ú½¼Â >œ¾»¾m O¾OêÙ=¼ƒ•>Þ¥$;¼e(¾l5`½ç‡6>Æ¯Š¾Âg¾ è½"Ï�>…·¿_ Ç<�E?ì�> fâ>¨ø§>ÕX¾Q!k>÷xƾÃU­½•S¾Û¿Â>µš¾Ö—š>\2<>Ñì >Š˜ ?ÉBB<Û×2?Ýe„>±Ýý>º¡>Ût¾Åï8>þ–›>¶RÁ¾1åø½�^å=²X«¾¶ö—¾*¥!¾Ùi=¿—3¾êS½÷$=…å`¾à 8>xNÅ<�©K¾xÚ�>Œ�|¾gÔU¾ðL‰>‘A¹¾�T$¿âE¾iD}¾§z‹¾Þ2^=lÙ.=–…“>­Ðͽ"‰Ï>÷Ìú½îðľ �š>°]ֽͪ=ð<7<ý¨V½×µ¬¼¾?µ>Á²Ù>Án>ú†¾N=]>ki=Aø7½ÙýÞ<á4¾ûû.¾ˆì½>Ø>q=Yà•¼õ¾K)�¾E�—>`Ão½<œÂ=w¾áæ�¾‰Ø¾EÀ ¾$˜£=¦[8¾óòð=l>å ¾÷SºY&ľøƒ‘¾KN½,Ú!>Ó>šü—½¹øH¾bJ†¾Hÿù=�°½Ä3=„ÊS¾òP>�…5îš=TV9>Ó€~=�œg=Ýt=¾ESS¾Òý<Æ,6½�·'¼X‡>µS >[Æ=ܯÝ=–Iz½6I>3l½Ø{¾¦‡A¾ì)Ì=ÈI‚½qn>8A4¾�z¹>µƒ>Fûó¼¾}ê…Ý=URð¾yã>=e‘�=43´½ôl=S%E<­;D¾Öàâ<’ >W2¨¾¾Í-½Þ�I>ÄÞ¹½V(¾2U‚<kj¾2‹€½›A>à ½Æ°m=×þ‰=?^t¾.Æ ¾p=þ>X+=`¼—>¥ú>í h¾¿ê~=D§M½sè">�ê½ü¡´=ïÁä;®¶¾Ô}=>¸Y<²�>dE?=íúú½|7\>IìÆ¾KÃÏ>›Ö÷=‚쌾«áX¾Äå½òÒ½�J†>Ñ¢¼<­¥=Þ8í= Z6½%¾¾ÃÇu=ÂÃâ½ýOý=Ú¼DïT¾ó� ¾û¥¾BÈн½ªb¾ ûr>Éð¾?"N½J÷½ÙؽÐ�`>^· ¾ ;Á½Ç̽K…>Í Š¾ ]¼" ¾Dù:>Ÿ¯>1ö\½Kn>iô>‘ž€>>!°¼q=¶¨>>-P ¾îŒ>¾=¯��=.™8=Ýd·¾|Æ =êùÓ>ˆ:—=l}¾g¾¨½4k¼û¦/=wbA¾B «>¬¸¾>~æ¾S�Õ>l€`>œ'N¾àÐL¾Q-Þ=ÐV½>·~(>G-?r“X=Qù=jÝm¾“ó~>¿ó3>}+>àËP>¹ˆ¼=Y{(¾½¤‡>¥V‰>G§¾xd†>ˆÚ@½B×½‘Ç¢< =…Í>ÍŒe¾r‡g<~ >s «>°•¼¯>%¿ Iš¾2ãY=å 1?5Ú¾¬²`>q)Ó¼:?»E¨=AĽ½A ñéÍ=�v>u=èEŒ¾›Þ^¾òÏj=z-¾áÓ�¼æ0ö¾#¥¾Œ+ >{¬¾tª?³ÎÙ½ßÇ®>úSf¾…zA¾¤ƒZ¾áT>¤=°»XJ¾ƒªB½�†Ý=¢¼<� ô=Øy¾è@†¾e]½�`p¾½(¾o.N¾-ŠË>” ½Éœ,>2Û†=²]ö½¿ˆ¥>µ ¾„’]¾­,>^ {½/äÁ¼7äf> {¾þ?¾nÖ¤½hLÃ>É’“½|™<ãx=uܹ³ä ¾«[=Ê!U=€d]>�Ž+>±Æ= …À<'Ò=tó)¿rŽÓs>;Ñ`¾gk¾qU¾Œù4>Dù’> ~,¾})¡>ªÕ\=PÂÜ=‘>¤Í�>žãì=bÍ�>lmI>^r`¾&ëÌ<*Æ­½ÇÐ$>A?>0Ýf>¹=ò"Ï=Z+ï=tC=s­X>-½¾5V¾±'R> ¾³C¾/ƒQ½T8¾‰Ç«>5份JG =NŒ> ƒ¾\£²¾ Ç=›¼¾t"¾ÚïÖ<²Î€>ÈF>¶ßô=þ(=¸H>S+û<Ð&£¼¸aļMë¾L>W®õ½($¾x]b¾§.޽*v½�>c>©i= ö=¥ÔI< Á*>t±½uBÜ=šÊÊ<Â(e<щ·½`të>íp½*Ž>"�¾Ï~…¼ Ÿ»ã€Î=CfÅ>;ÿ> ¸¾÷Üu¾">˜}Ƚ `:>ªæ>t4>÷Qx>ŸÜI¾XH¾¹´=W|¾Y¶ ¾±ñT>¯}}>ÊzÜ»Çe©¾NW¾¡ÅI½¯Þ¢=Èê“=X:¾ÚÈ1>åßî½ÉB=Tû<úCܽq6>YW�»Ó ¾ýÖ½°�i¾ª+²»mj¸»Â á»=Gð;Úü ½»ß5>R¹!¾Îÿ–¾Is»©>>%~À¾ÏZ>ÃÍ@¾]L¾\Z=u¯½®Yû=â0Ì=/b潨Ók>¡×E½¶¾®<—m =  “=¼Ñ*¼Š*¾ß{¢¾±Ì½2¢´=û—�>åî;½E=w7S=¸¾0Ì£=DUð=®¨ì»åC¹>/²¯=¯¶Æ½LÉ­½Ÿuk8Âv*¾ ³J>KÆC¾eJ•>j`õ<5ô;KÓ·¾©q>®þœ>]ëM=il½ŽL?¼å§‚¾Ë8�¾«E-¾•�ަ|ˆ>åõâ»Ìv>âÓ<›U°=FåνšL:¾óg>‰’Ô==lY>……I¼š°={e>Ö÷<1é�>:v™¾\éü=ø}_>ñ �¼‡Ö¨<ü="l¾É騽¦È¾T!3¾vÜ>¡‡»×¾'=Oj½ae%¾h->Ê)y=]¹µ¾0ñ6¾Ý™=Òö½©Ó“½DTv¾�x侇°Ú>:%>žs½úù'>]É=½f?h·=rSV=Õ5ܽ_!¯½ëW¾º>Ÿ§¾ŠËã½µúV½Xy‘>bà Àl>>B:>tȾ{0€¼¾ÌA¾ìP0½qm�½ûŒ ¾Ó«V¾”†Á=H¶õ¼hß“>À|_>³8U¾Å\»¾ü>&>N�b¾;çà=•>|[q¾þ=› »¿ç¾—ì º³ðÜ<–á=>c8œ=:¹ë½a¾ð=ú�¾›+¿x­=IÌá¾¹¾nž5¾k$½K[ >&{É=IÌ=0Ö>À ¾{ON½Ž>þ=�A�½ƒÚk>RH§½¶á>’a¦¾Ü¾@ñQ¼Ý<½™w>Aß$=p"ʼâŠh<Ç{Ž>1~нË`N=-’Ç=üVê=Ý/>öt9¾º}¢½‹�(=…(ÿ½Wj¾=¬’>þ†“>ëÖ'>¦ìI¼Í$’¾%–¼=,°o¾I²=¾ïmˆ¾… 0¾=lß¾ð�c½Þ3 >êý*¼íf½ >@ßA¾ªX´½¾Ã$>ü¸ú½þ>ÕýùK¨¼R*î=T¾ñè•=ìýš¾1‰<®”=‚©¨¾¶)½^øÀ¾Zª«½!O“½¯þ±¾éã‰>y,(>,ç©;[±k>©»È½\¾¨½î >˜=�}­>‚©=6Á0= ‘¾°Œ¬½¾¥¾Æã¾0±¾Ýa/¾ôi[>fÛ¾Å)û»iEò=g\×>=›¾„ú„¼ò÷D½ôŠ©=9a¾»ø>§2ü½—_=½�3¾“S½NŽ—=ûH™>óŒ>ü#&=}½¾ˆ{ƒ½±H¾ ˆö®B5=õ�Y>ˆE¾Ìí­¼Á?©ó#>I¥ƒ>ª%Ú½õŸ>:B�¾ìšN¾¹[è>EYº=dyY>Pm¼~2¾lÖ>=95;åé<ج.>4+¤½r»&¾ C;@V™½Ð™š¾8Ÿ= +µ>ìªÂ¾­4«¾u�‘½€µš>Ä=ƒÑ>o‡>µ¹—½©ö¼R [>¹yx> B�>‚“>X n¾¥;æ½®¡�½¶Ä>ïÀ=-Ü‚=`á)¾ÆUa>eYj>)ê^¼2aO>ÒÇ<¦¬Š½î%Ž>s¤l>AòÑ>îûÌ=�*¾L> Ä¿¼²ºl=ˆþ©Ó_>Jd =o?ò¼|Èh¾.�о@‘=½5é=€Õq>èh̽vÎ5¾9«3¾Sæ¢=¹(‰¾f>C¬>^ Ã=Ã�×=¶‹†>ÀŒ[>,BR=�±�¾ÛÌ©¾ð\¾> ‰_¾E§’>ô]¾Ý8ˆ¾Ðæ‘=C…í=þ²=ÕØB=xÜÈ>LŽ >{À�¾³Ø½k W>·qŽ>œ¦ƒ½‹ï¢½"á¦=Üy£=R5B¾Ôݼ(N4>{Q¬½'€�>EØP>\ʰ=Gª¹<· ¾‰å!¾-&{>\ŽdT¾ò/¿¶#>uT¾™Þž=Ä:?>ø*V=š¸¾ÿØj>»Ý¶¼»›Ø>,l™¾ü¡ß=ÈÇÔ½º—ü>åE>ðW´=jr¼8‹�>ƒ>Øÿ>¶3™=!e‰» dâ=”ÒU¾®j¼>Q±8¾âtw=×?¾½ !c¾Eˆ™>õ޾‘¾¹…ê=c4<>ƒ˜ >ÃȽ[>9� =Õ�æ½÷Ø©½˜4>„Ü>Û)´=ÐÔ#¾C<¼¿Ã�>˜€Â>„E¼ã=¾Šã=òn=šŽœ½•> ™´½_§Ž=¬?qsH>�m›>ì¹½q`)>ng5¾Þ†½½Äçå½ËiR¾VªÌ½²xÆ>¹žê= r¾rÒÀ½JÙ½‚ƒÎ½rq£¾ÞM�¾§±­= –‡=Gá>¡™Å>‚é€>ƒ¢À¾:i²= a!>ÉW>†»<Ý#> Y‚¾¡”¾>tš½Bïü¾OD"=©½8+¯<•Å=ûô=oR½6Mœ½-äµ¾\ ¾-´h½?´È=ÿ�¿½£Ä>À÷¦¾&€>ð=ð½µ·?=ãwQ¾åÙ|¾·ñ¹¼' =ÚÕ'¾ Ú‹¾ª¿ý½Ê=^‰½>Ov=:+“½¦!ê=D`f>Yî½Ú¾hdn½‡”k¾ÔûÚ= œÊ½K-Ž>žՊš>¾Ï.¾r%,½ïua<²¾¾Nc•=ï¹>šŒ¾‘�¾)�½T£v>nÄG¾ÜKØ=a|µ=²<˜>cå/>·Îg>Oªž=´ç5¾@ª;Ð@€>²*ª=;¾?‚ˆØ¾ >½#×½Yð=Fc„½½?I=/~v¾0aÇ=+3轋pÊj+½Œ¤6>Á«>E‰»>òG‡½¹ >У$Ѿ=„Z"> ‡}=½¨½æ÷ò=ð_ž=uþE¼° G½ 41¾1½ÐuH>V—>j¢³¾,f >Á¶ê½I»t>…=K¦¢½ F€¾õB›¾›u/=ñk=£¢i>1›¦=gh<1±m¾ŒY¹>ìíæ>Œc>YÍ= #¾bß=0ó?’g¬@¾Ú‡Æ½l€°ÝºL>ÀS}½Û‹º½È¾…=©Q>¾P4>j7Ï>ŽÞ�>[Nu¾NbK¾·u>�Þ½–Q!¾6F�½„_Ös¥­¾îÇç½þ•�>=ç½fzB=zßG¾]p”=[m¼� Ÿ¾á}•¾ƒÕΤeÇ=›ã¾nê½±%¾I)y>?C#=~:оI›·¾ ˆ>Τ<ƒ½óf¼ê>“¼Ã³£¾¼-ö=Wè…¾®=JÏ‚<–—½¾Lƾ83;=3CÉ=K‹ >‡Õ>…Ù>Ô÷=)»�¾¤ ²=%es>»•k½´üz=Y‘Š>_îϽÃÄm¾LRé>Pš=%ÈN>NBf<Â'½müË>϶¾ÄX¾­äš¾1„¤»p,u½/Ãú¼?rp¸5L=½7@U>ŒƒÔ½fò¾8¸¶½§Ýô½<߈¾Ë4»¼ÍÃѽœ¾ 8þ½�Fœ¾e§¿=÷d:>êñ†½ ;¡Az=ë>[¤°½‘Ãǽ<�c½]¶•½ Èà<¡†¾“PÁ=×û<Rí>E´Â½Eçå½(*u>P¾?>„! =­%´½¼e+¾|Ü.¾û?>ûý‹¾Ya¹=Ž^=„x•¾Ü[õ½Ò‘‰½®F›¾ «=h|t>p]ó½pbž½,2d>�åç¾6Q}>÷à>(6×¾[ì±<ù'v=kΟ=Pp±>l]Z¾ø_Ñ=ŠÈü<½n¨>7÷¾ÑǾ¨o\=¤Ùg½tỼŽW=¡w¨=ñaü=W¢f>˜s\¾“ʽ Ìú½:y ¾+wŸ½$Ò7¾4c_¾rg½Ûµ¾I»>œ#¾v«>´ä+½bt‡½r±¥=®”Û<'{§=f¸{¾Ü11¾ùKd>s_¡>¦š>½˜Í=Ö¨g¾t¨½ý"À¾®½ä¾P‰>7mV>×LI>CI}½�:ö¾ü²N½Ê¾¾@ì½½¸åó<_'>jP¾gÇm½DUç<¸°¼±ö> ü>摾 ¥>_ìG<=´ÿ“¾ô««¾"ì>9ú¸=Ž1?P˜D=mìù=ůŸ½ K¾>(y>v(>S Ñ=h\­½'b*;}c¥>R ½†€ƒ<â->ã ã=-A6=¹˜+¾MŽ\>õ<�¾ý€æ½“�·=±j>–o€>é¿­>‰½ Ìμ—&>86�½Z¡Q>Ô†â¾èh9¾²˜=Gù4>=k¯1¡÷º”H>×ß]¾ŽÌ¤½³Äƽ¸¦l¾x/ƾˆ5>ßA‚<)-¾;!½@,˽"ö¦¼Ïï¾¶4@¾Éܳ½‡…¼‹õñ¾¶µ+>kðB>™c¼|�>_2¼ÿ>Œ¾`y•¼7ǾÁüŒ¾Ë,>�Î6=é–;p‰w= ç»:£€»¦m8;oßû½7B:>¤á•½®b›>RÙ>\ò¦=vB§¾Ùy?¾ìлK)=×A½)[%¾‡W½#1O=Z&>d—I>lz¾6-¾vpž¾f…w=àöd={O >Œ¢ ¼vý½þÓ ¾µxÕ>—Š>¡¯±= -<‹Â ¾Ä-Ÿ½¹ï=>%ÒÚ½!²9¾€»>4>=·þ>Zãš>�o™>O1=7>l;!¾¢Ñ›¾w¿™¾ 8Ê=�‹â½} >dòs½í]•½À +=ç,¼”¾¼œœ<�~¾øU™¾ñ�Z¾ 7½ê·=æ«’¾¼/н»¹ >HDe=è¾’>¶ê˜¼œÕǽ�”i=�¹)½€÷v>À$¾…[›>}&‹¼l[?NÅ<á)Ø>ÉÀZ>/A*= ¨q½íS±¾öèÚ>ª ž…¶$>:º/=ƒ¾Ö�º½KqÚ=‚Õu¾þÁV=Ù ‰½.ÁE> I>;‰å>¤é~>惿³FÔ=œõ²¾¥Œ½áx9¾Þl•¼3-h¾ ž¡>¡^8>ñÀ=\¦>ɯ¾ÕÉ”=Žw¾4Ï< @_>i¾ÈÚ“¼gP£¾”›^>„ >q~ä=»!¾V Q>Ц:>éÉQ>™êf¾'½©=“j<±æY¾ú=Ò]½Iê¼®h<¤.Þ½œØd¾ Šb½Îÿμ¿xH½Ðg>{b¼©C>D£¾í#-½Ó@€¾ì໎mQ>œU¾S ”>¨¹ <'í£¾àº>¼òš¾¥™L>Yïú<î}¾ a‹¾ $ ¾/~+¾ªž6=6¾[ݳ½é£> á¾›ey¾¹}‚¾Øê=¾æ§>åuh½˜ä‹>dÎÁ=àäñ=#¾=FÞ>sem¾#_½4™ú=÷! ¼Jå™>( K½Ö¯¿»·?;âc½¥¥R¾Ãøj Ǿ„ˆ>ÂW:¾½ÄR=Íì >ÊO}>楖=¹û½ŠE°=é臽}‡¾>1!L¾;v�>™F9¼Ÿs½!Cá¼òq‘=_M¼½O9d= ½™½ ˜·=Ó+Þ½DË=5š„¾D->m l=éþª<¤�õ½éš>pQ ¼ðs>÷)M¾ÅˆÃ=òé5¾�tá½(l¾åýuðž=’ùa¾kX޾œDÈ=³Ëš>.¾4x½"н`Ëɽ1ôÓ¾¶ÒF¾†•ƾ®„>‚1¾ãK¿sÜ›½­ä>ðus>.Ë‹¾Ðö½l‘Ü=ί½Ž->ÿ>»Aöh¼Ðg >k}å¼2hÔ¼™xã¾'!+¾ïM=|>\úH=F>òÏœ¾VîU¾©¯¾šâ=}\Ž<ŠV!¾ßQ�=é4ˆ>ý(5¾ ƒ¹¾Æ-<¾©5¾ G°>޳½ ‚”¾ˆº/½�Õ> ÷¤¾æ¸ó=L³¾�­À¾þÚ=žŒœ¾ƒ/š¾û>Qªq¾¢ip;­§¾®�ž¾¿ˆ>^l‹>Mˆ>ço£I >í›’¾“B¢;L®=»L¾;q£½«ïö=^ÏX¾Œík¾ÀÑÇ=¹Ç¾Ž >Fš®¾PÏ >(CÛ=Õ¡%¾í‹¾y[Ê>ŒξáÖ/=Qæ8;€ÆŸ>º(2>uƒ>S’“<©¥œ=jˆ>¿C½Õ£×=Ÿ¢l¾rÌ⾤6v>ex ¾àO˜>##£=¡;¾é�¾ªÈ=üë¾$ö;Ûx3½T¦%¾6ù`¾œdœ¾»ß¦=Zku¾EŒ¾m=¸c‘¾©[‰½M¸=½lþ*½2_>[æ•<ÐË¡½vµÑ>Z+'>˜àä¼l ¦½hš¾/X>콚½<_j¾­®o¾¢fi¾m´c¾Äy¾ª0¾f]“¾im­>Þñr½—ÿ ¼nB±=læ=På°>eê‡>Q�¾ö�W¾™›ã<ý&>Ï3ð½Ü8>±GS>ÓÐ=íBï>H¨Â¾ùó8¾pãµ¾Î1= .ѾÆ”=_\˜½îϽ,ï,>‰âù=]Ø>žu¼%P‘½G?R>ý®h‚Õª>¢ù‚¾"–›>e ÿ»z%�½¦(¾w»Ý=ýÐÌ=H„½Á‡¾ü�½½–³e=";Ž>±Ó/¾Ònƒ¾þí�>H>(P>îéļøv†>o’½•´½ìʽ¼³·>D‚ü=\ö›¼ži²>X¡=ÿBD¾Æ¦P¾Þ6>Ö<¼‡Á»ÙÎw=Že}>ˆ9l=^Ÿ.>86•;böµ¾J̵½›Úh>^vZ>§P¾÷uǾþLP¾O© >Û ¾ñ=nI»=Yvß>#ò¾ D¾4>å¾/~d½ÄÃ>öjK¾ :¾¼àã<äò=½@§= ¥<õ¸ò¾E›½ß/å¼öì¢>U»Ò½6Ê=:3T=SUC=5 >»-V>‚Å;º¨=ÑC=…™z¼±EN¾_.…¾ÕÞú>›|>´‚Â;¶A­=Ækû½ª„ã¾Còw>xŒ>ÃŽi¾|½À+ò½Ç¤+>e@{>¬;þ`‚>¾$áö=ŽwÄ>½QÙ½‚E>+±½+ª¾šÌh> Ãú»lš¾oŽ=À�¾ë1ò¼È†à==³¾9@U>>7Œ=Cåõ>zÊ�=2s¶=š$8½UŠ >È÷µ;]²¸¼MÏI¾M•=˜¾½~ãö¾ªA¾—{><(´¾„é]¾†ƒð>¿ëi=ùr.>÷§L¾8pé¼WiV>g¦_=âe>¼ñþ¾·ßº>•û=}ç<ÓF,¾ …=ò Ò=¶ë)>;+[½×{½�ýÌ=Ó—;=f>$ßǾ Õ‘=ŸŒJ¾¸^Qó- >¸gß=òŠ�¾Zén=ö\–=Õ¬=€>f|]>v°´>ÀÎÏ»žîÄ>騽™ɽOç(>Kîµ>øª=«Þû=É ?1ñ=Ž{1>6�ø½-g±½�Ä¢=ÙS¶½ £c¾¥6b¾Oß«=¦i€>^fY½©Û4¾^Åw>M&0>&ÐÝ½Þ Z>¹Îµ½Bá>þfË»ÀB­½ºE*¾ºøã¾ÆÐJ>ÎÜ’½§ú÷º(ô@>;¥¾cÇ8=õü->ÉÔ=íæµ½Ç@\=ˆ�@>iŽ_¾ú0¼¶¦¾äMv¾ð©Ò¼·g&¾‡H…>xì®>�&¿¾…”�>÷Õ=j³>W{ñ=ܲӼG5½£u¼%Ÿ¾¼Zý¿¾n¢`>ݧ¤> ¡„¼ÄÄ´=|Á >€'¦¾^0¾°ì>;áÎ;³ÒŠ>ú£™>kag½y[>7`‹½èþ= .¾ê5>3úÆ>‡�¾õàX¾ËLo¼h;æw¾j1™<Žº?½ÖZ¾iN¾cÐ:n� ¾ã¯ˆ>žz¾Îe¨= ôO¾8Ü0>—¾<þ>Ú(Ê>Ш¹½SÕV>#ã;×_à=yYz>2gV>šH½Ñ·I>wÛ;¾$ó=Œo;'ãÙ¾qÉ-¾ƒ†=¢7o<Ü7Š:ÝJ># ô½°ŽM>þ·œ>̬¾d䢾p?>ä7¢>&¬¯¾ E$½aŒè½(>udÏ=‰›j»Ù–E<¦F¼:Œ&½'¾]+@¾ó>T É=u‰Ÿ½x[´< Ÿ7¾äÝœ¾p%<ˆÎX=Ñ?h=`Ð?:­=å¨E¾sâš½_}|>÷ñH¾J-¼aú<:Uí¼ Èf>F>ªj·½¹¿…½ãc5¼Ñ„c¾™­Ã><>¾Ù§3½2g¾°÷�<ÐéÃ=¤ô4¾´~¾¬àའA>‹D>ê:=è¾èÔ…¾VÑë¾ý ?¾ÍÕJ¼òé¬=Éì¾�Y=t®<¦¶Æ½ÎÑÔ<ðªù=˜ëϼIú̽BMN>Ù³i>Güx<ÓÒ¾(jº<꨾㲓>§?ø¾Oa?d>Bæ»í9 >-¸–¾ì7˜>AS•»§(½-û™½ª5+>èø¬=§ž¾|¡Í>•¯½:ù»à!ä½ü“½Ã¾WQt=®^G¾\Ø9½pê*½*Ò—½ B¾¢�8=�*=>$õ¾ŒW5¾»F=R1>Û«Ç»>€ƒ>¾Ú#¾QV'¾gDM>¾:¾Ü#™½>ù¥¾%%5¾á-¹=.¢!=ºt¾Î´L½T¾çrŒ=Ö¬þ½Tëá½K6¼é{ã½ h»½ˆ(޾]4=¹/˜>lù¾cŸ¢>"k¾¬—¾��ýΉ=èǾø�ͽaоƒ†×½ûx¾|W„>M ?> l¾;øM>ÂP7<˜45¾„cC½ãyÒ¼Âë>Y­s<“¡½ci‘=øÓÓ=hl¾mß<>A]¾Åx>¾ö=ݽ 烾¤È'=Ú“‹» K%½(ú¾G¸@¾™ÅÔÓ•,>øy¾Œ £=³‘½—”>êì3¾�âr¾G’Ƚ ûŸ½º ¾i(p¾G�>a�q>ì.<•à뾫$=”úƒ=*5å½8ν“…4>±qî>­¾/¹_½ <>U¶ê=vŒ�¾Ýé>$ –¼Ö€>“î+¿4² ¼×…‚¼Y!½ë»S½ —ƒ=vø>˜3%¾�%ë¾äwȾ ¥.>v}·¾Øß7½tW_>ñpƒ½oe½�“½;LT¿>WåZ>Öð½]?n½*Ê>™3y=Þ_a¼ƒÂ‚¾!è{>OÌß¼sª¾M™½¼}÷½×Vƒ¾íÇŸ¾õ)>ÎF½.û¾GSQ=ÃH¾´i¾bv8>¹ý#>O0нäóx¾6ßL¼Gi¬½)ó¯=�›Ñ=d/t¾²8Ö½ï ›>�¼»øÞ÷½ò³Û½¼Uû½´D˽½’¼¢ª�½ùk.<ÑÂ,>h}Õ>®Jƒ¾ôÚ¯¾–«>X&¾M>»Ñ= À–¼4»¾ý±=Þ==xl>¼gÒ�L>ß{§=²¾é<>œEß¾¤Z‹>Ez ¾ 鄾8> ŠÓ>0\@>õ¦a=" Ö>A_=5n×=†ËŠ=NÕx¼ì)¨<¬!œ>|qD>ª ¾»¿=Ó°R<:òѾ»‘?½“ÃÕ>óc¾ ¡ë>ºC�½ý< >Ë]Ö½Ô(>l'¾ø â>qïê½Ð#D¾ÿ`Ù>uO¿<.™;EZ¾w ½²l>±0K¾®å‡¾ù3S>�=«×ª=þw/=Ä2¾<®É=õÞ±¼ä*ν¥ìǼ;3büá’1¾f¼=Òö¾y';¾Ïw>ÄÌ“¾rãÌ;†•о–µ?;·=µT½.K<6P@>ܱš=‰f¾­ÜA>>¿¡T½©ÜÓ<Šfi<ľߥg>æüu¼i©Š½^C!>ë÷ù½ö‚¾o„<ø/@>¤º°= c²>ïym¾N9,½ñ’>Qen<cI½±Î6=6!C>щn½ç¾¥àÇ= €H¾âx˜>ÍWp¾‘c™>ÞÈy>>8>#wª={Iý½3·½ÒÆ&¾ î1=—a;Óõ7¾ÈX>Hé.>hÓ¼¤¤;¾—Åk>1Cº=�¾óó�½7â >ûÿW>\{½ B>™g/=b¹ƒ>šÃT½/F›½7•>7˜á=?û=8uw¾ ôß<½�ú®=_Ä}¾—À=¦S¨=‚“õ½}<=NËx½ÊQ ¾6sJ>ÔŽ…>Âé3¾ña>å›h=I©>µF�=H|Žž“ܽ øE¾4O�; Û%¼ïÝn¾¶U¾­`5¾Å$%=$j™>ùØ,¾«ï>u>¦c¾ïàù¾ŒcŒ<—=hV>„*b=²Ô>~�×»ØX½ÆT>{µ½=Lz;>y5>û™€½,{ë½>i–½ôªÛ½ÚŒÔ=!FƽÝ*�¾©HE>ý¾’Q™>Üú =ž³¾g�,¾pF!>›W@>T+ºñ ¾‡¾*0˜>ì~,>e΂¾þ?�o >hÛy;ºy¾¸j>—EH½y“°½ù"õ=*\¡=ñE>±ëc¾x¸‰½Ic‹<ª&�>ëu“»¹‰™=–w½Vf>\Bð¼ôé=ˆª:½÷=$dã=<ýP=ä¾¹‘o¾›æ&¾ÿ|”¼öÍÀ>J7ã¼¥p ¾–$¯=aÂ!¾�*“>>ÿ5¾ðÔ_¾©b>:Ö“½ª;¾»“§½�ÔÓ¾N Ü;8°> Ûª>Éú!¾ÓD>(Èþ=T(|>a•> v>�'©½„íß=©‚M¾N!¾6v¿ªØ(>—ñ~½q"¼:¥±=t:‚¾,û+>s×½1àí½È=>: W>ß’"¾“c> Aq=²ry>Z¼ý<÷äF=’†9>Ûàà=èû(>—\b=â½ù¼áý¢=¼Õ½áq(½'…í½—pK= ¥>À+À½¥úŒ¾ÍT½Ü½¤>Ÿ®>`>4)>àzÒ=Z®c>Bo{>tºÆ=¹Va½'Oc>dºú=Gñß½/pí¾žAì=ƒ<¨Ì7>ñËÆ¼î+v>AÇ(=ñ{¾R©a=å3q<õnD¾9*Œ½°Ù >=ž>¼ž¾ÛM½¦÷ =ÿ÷>ž´=>ƒ—¾(Rw½GóǽÀ"…½æ€>a>AtÀ¾çü¼¶¼†½Ç‰l¾î…4=&V½sÄ ¿\Š)>Pc)¼¶:�¼À[œ½²_˜½9^=Ê•€>X`G¾ȼĶœ>ÃN€<¸+¦¾kp>�E�=;z¢=(k¥½¤�|>°pA»±N™>Pî°¾TZ©¾Ú�¢>1v™¾QÊa¾RjJ½òL¾»l–Œ¼H¾µS‹>K">iJý V§<‡>ß½åêd¾Y�¼¾—±½®­a¾iXŸ½:7˾—¸Ï¾>¿¾ŒóÁ=cš ¾Ô-»>/`-¾\›•>µv‘¾`¾³™½M2¾Ä²´=Ú:>wó¦>~eö½ ˜±¾ã7½=Œ\Þ½™è¤½øJ¶½’ë‹>¬’>o0“>ïð“½a0½¾ß§Ë=Þø=ai¾+®ë»¤3À=å÷`¾º{"=vbM:¥2ݽšF=÷b.½Åµy¾B#>èêl»vjì¼PP]¾½Ç=yÇ⾡M=€„<} z¼r×G¾ÈæH=5¸Ï½ ,»¾’Å>Óv=>ð¢=²´ c.>Ö¨í½²žq½�hZ¾ÓœÌ<Œ‚Y>àœD¾Aù¾³À™½DV¯= –>®U°¾KžŠÉ±r=7æ�¾% <ÂT<ùòj¾ Ëþ»šåO>õþþ¼Žw½Ä•`=Ói¸=Ê5-¾¤‡ï=€›¾Uýb¾Ðìà=pÍ‘; W=˜Ì¥¼ÙÂY=Ï8·"|j>ÄH=‡Á½¾d°=¾fäî<Û�®½óîê=4]Û½ŸA¾‹èg>©�¼½ÅÕŠ=ór3>ÚŠ=B¯Ò=G��¾_?>0Í=R©˜>`r½7bžß+%½…í¾¬Ê ?”dÈ<æ§»,u×½¿Ân¾ý¼Œ¾ Äž>rw>¸9”=ÄàÔ½ÞÐy=ÅÁ'½°«¾¾B³Ô½Ì?>^Ö¿ÇìæÃ½�ʰ>ñm³½e�¤¾¹.C>ÈÙ=x8f¾7?:»0>êI>·:æ=6ÇU½B­»½yçí½WÜ.¾4Â\>i‡£>(þž=½÷Ÿ>D¦®¼„˜´½~ù—¾‡î£¾ï¬�=ÉS¾Lec= Ž> 1ª>çF›=hž½çØT]u¼R“½�­R¾a¶¾>ý5Q¼Œ�¼È'Ö¾±ç0>Å¿u>Hñ@¾aÉý<;Ûû=¶?$>¨ö ¾v™>ó«>¦¡»¾¼p‰½,‹¡½.þ„¾< d¾=ç4>Ö/Å=>7d=#9½ÀPä½:­¾ )¾G…>ܹšèOm>Û.²¼¢½•<(´ðÚïš=ö{¾ª”W½ã„)>/6>_œ=¾À'¾á”¢>¨ðp>„X¾¥m€=ß Í½¾²ò½øÙï=x”˜¾&”;>6³?kù¢>ëP?*÷+>Ð(¾ó÷‚=™‘ô½N²½5ž)¼ª¶ª½“H¡½Ò<Í=¢àé=@)5¼—;ܼ¢kí=ùD‡>¸é:¼Zì> b¾=')=Ýɽ æü½½ðh>ai=´ãS=‰>]ß̽ä>¯B¾eX‘½;`A=[êº<^ˆ>0£Ø½ 4˻퓅>›½o">€ ½’ë$=�!¾¬)›½{ø:öç!>XöX¾j½Q>#w˜½Œ&>ø˜÷=$e¾B‡»>²~¤=˜ÇÔ;?YG¾‚Y->( мM3V¾AK¾%M™¾÷ô¦=\ÇN¾–¸¬<¿­Ê¼—‘Ô¾`;¾»G–=ÕŸß½!ˆ¾¹CŒ½Ût‡=·ƒ>õ�º>‡u>Ã=H¥<†|;>-· >(pÖ=úľOÇ‚¾Í¬À=–žÈ>Rxç= U…=bäF¾¬I½¥Aj>ˆ‚¥>âY9>ó >ý® >3�‚=_Œ¾åä›<é£4>Ê”I¾Ë4>ììe¾"u=J—m½0T¾nc>͹½yŒ€>&÷‡=Q\½s ô¾u$=RÑé=·–b>½Wo>I‡ñ=? Õ½5$>Êñ-=å �=8­>àvï»!p<â�v¾é½‚½Ì<è½Q()½cŒè>v€1¾ä=Œ¾&DÅ=¦ë‘¾rÒ=‚¶¾Ý,Â;¤¦+½ç9/½’Y=�ßÇ=mœ¼×¬=­úü½Lb>Öû÷= ~u¾ mª½á¼Œ>î>Z>ÔÔ®>ôôV¾É2F½c"̽rññ½cçÖ¼Õ<Ã; %¾^ Q=`tê½v½Æ= Â#>áEú½Ù“’¾®Ÿ²½Wü¾ë;¿¼êaI½ØV›¾�zi¾ û{>b?a=*ο=Š÷�¼°x”½…2üvc¾/Ç=õ"¾�>ëA{¾ýÃ>,±½ˆ«<$ƒŠ=´v¢¼(սξ¼<¶I@¾8$¾—l‚>zä¾`Ús½þ)L='™è>;m:=¿Ë–>¿ ¾< Ò½¸Øå¾Ó¤½{çÔ»dÞg>jÿ >ϱŸ¾zki¾ÙÖ,¾Wì0>soÇ=š}=qkø=üx>Fؤ½ z¾JЬ¾”·¨>« ö=ŠL2<愾¶‚ù=%®Ð½rί=\¤=hâ…='˜¼Ø&û¼õP=go…¾Œw>†³¾ùy9>‰†>Ú'£½-Ù£¾ :›=²�½t/1>ïÃ�¾¤½do>¥©=Ûéi>]�½bô[¾×6I½ZËr¾&Dʾ#ÅÙ>T“==Í ¼Ò¾œ˜>FBo½aK>÷ì?�½Ï>Ž¡ˆ¾·ýe=OE»½Sm½¹ŒE½:q‡=8­Ð¾¿Uê½3Ñ(=Rð >ì|¾äý;¾œ8s=n4¾™Âå=×ü¾7G¿~Ô¾•ºg>3X½=æMA¾ÞE@½ZM½Oâ->âK¡¾¿}\¾p9¶¾\¯á½�Æ#>·4¾¢Ú.¾¬-¾WT�¼P13>Xf¾ëœ˜=æÑ>¾œt€½œXT½Ï>q{ ¾íB=֣½äÝ—¾6.'=ÌΖ=+Yl<–'¨>±>ï]%½Iù=R„>–޽ä~½Æá+¾±¨¾Rõ%½�¤i=˜FË<¯û¼½Ú3°¾ƒÚ*¼M0i>=ž>®lw¼­øº½#—½½‘ = ;´¾iª >�q=‘‘Ø<žòE>²lª¾÷â›=D”¾�¼ßr@¾Œ@�>TR¤¾Æ«7½îO=†„0>Ù}¾z¢E>¸pϾ°2Â<æ¦<Û‘/>:Z¾Àÿˆ>x1>ÿêÿ=›n›<˜¸Ì¾ÝÀu¾s[û>Y{g¾�¬í½Š‰=#AX=·©¾>[4>âD–>ëh—<Ž,ž½e¯5¾Ò„•¾ÿ¤>öǽßÑ¥>4+Ÿ>ùm0>ûã,=‘=8Ð><†Q>Z\à½`Ð\¾›áºñ$S=+“«>%W½ÛPÏ>åhÑ=;ç.½¾çP¾�Q=O…V¾ Ûï½y¾Æ¢Š½Ëž*>™Cѽ×mH¾Á…·½mÖ2>¥??¾E‹¸<;=¾¤·½ž N='ÓŸ¾ž=¿¾Q†>–+¼¾Rš<¾Šk;<·È¾>Iî,>d…]½²-´¾Â+N>È.‰¾KÓv=wm€¾ù•·½YÙ¾•Ê5¾>Ɖ=Œ¸È=¦ò¼ç¢™>7ôÿ½QቾÎD¼ÁˆÌ=�<ò} ¾«r˾{ú¾

C˜?‹ÚU¾)r@>—- >ïgð¾{a|»i=Óâ¾Ëÿ¡=N× >¤>z«½=â&ƒ¾1®>¡&�>ðçï=ʵT½nY—<a¾¦­©>¶J°>øë=>Á‘?oLJ> ,Ÿ½†"7½"§\=qJö=ix¾&®×¼ë|C½# >…#r¾œfÀ=Kú;¾eI…¾õ³>Žx£½Q¬h>¯áw¾jev=CäL>}î >®Âš>QZZ¾¢¯=ƒ5>û©“¾æ¾G¾¼=€¾~³`>.ŸÊ½"$ >ú6 ¿S”À¾¸e=e¨·=‚{œ>ìAq½ñfÌ>C¤Ö½K'¾ÒB¢½±‹¢> ݽU?c=œ&»¾§#=¾C•>Ní­; ‚‘¾ÞÎE¾Š8»¾�¾)�>#³L¾�ü†>ÐÚD>©·=»@¤ú½.y™>Cƒ½ `=>œFg=.•=&^]¾²Ûž= ޤ¾>Ù¿<»ª“> qü¼YF>uî§>Iþ;>u¾ï½.Y™¾pZ=Y0õ;w×i=ûÇv½¢¬¤=·b<{òi>sâ=­Å=®cнDsþ½ö4$¾bâM½P7¼n[½ƒæ¾L~ ;!ؾˆ:Ṻ>˵¾³Êk>fê¼½›÷½Á[½"Z’½_¶W>zÛs>$·=Œž¸>Vek¼µ‚>ͯ< v¯¾éM=G7�¾m@¾®Ü2¾å³¨¾?>‚¾8¼¾ƒb½´>¶z¢=pýÞ=4õf>:´T¾ÖSm¾·�=m\Z¾£áH=òÒ=<´½Ÿ½y½oôe¼Í�ž¾]êc>™¼>ÀE²;R7V>¥†¾¨Î–>Š!ç½*쓾7˜�¾.Û§=GTŽ=Ãäi>#�Í=ZtÁ>fão;d(>Krɽþ¡D¾‚ ½=”6&¾†^”½QEÓ½â­=6�>_Tó½7‹¾ßñ”>o,G>ræÈ>)]ͽ#Ðv½vg!¾�Èé>ð]–>A]NºÛ¸U="x[¼ô|>ñÀA¾Ë¡=mk’>Ä’0¾‡×4¿œN>$Šn>⌽ÕmG>ñ$‚Y>\%+>8¼ñ0�¾Çû´½u� ¾Éj€=ìÜç=¢Úä½ýŒ…½·u¶¼>àC¾˜@ ;n³½xôϺs¹=Å:½Î Ö=)Þ >æZ�¾vÖI=3Ÿ²½ü±œ½Á§O>Oz¾?iÖ¾ãq«¾Díš¾œÚ$¾ØtÀ>Ôäß½ˆR>ã°=ëp¾ä‘^<à >Íb= G>e©é½'ÞE=âZ=^>‡šŠ=û9>åÒÒ½ŽÿN¾÷1>“ÛÊ=µ‡±¾…œ½‹K®>Ä—è¼Ýh‚½~™ž=)£›=/Ï =µš‰¾7À¾É­À½”~¾1¡ã=T>F¾Šp™½‰®{>×t—=�8‰¼erƒL ‰9<@³>Çļaú¾÷tï½{°=sh}¾ÿ>óoú=”Èý½ŸÖŸ¾ê’ ¾h¾â½5$ä¼<*ª>ê¾ Uv>¾÷=mŠ£¼Jg>íÖÂ>®½Ï¾¦\ƒ>’H->ƺ¼½#bÊ>Iñ¢½[™¿e2.½~ò=d$t>Yé¾DÒ×=oÜ»Bá@¼tÈ�½óä½tÃc¼¨ í;,+—<ñãѾY+ ¾Õ‰T>寀>ÜB¼1h‹=iN>šÐã<žÈL½, ÂÅG0…=2 }>/¸ù½c¼�HÏ„>¢m¾ÞG|½3ƒ¦½ ï�¾Šf ¾Xñ¾ú¼e~ؾ½É>1ɾÚçÏ>Ã>å�=¾&Ù•¾.†Ä=®Pø=5Ÿ†>.q>ã j½7±T¾_þ=¾•º¾Yf>0ž�]'¼¶Ã<(ôf¾]1í>78>¾‘‚=úÊ>¸ |½”Ña½)jg¾“œQ¾ÛŽA¾ ¡X>æp‡> Ÿº/=;éè½P.µ½Iã½s >¾tè½¶Ö>8³²¾È὆†>9ï‰=aÚ—>ô®·=À ¾ˆ5©¾nVO=b1ò½F—õ= R>qŒG¾ó$-¾“­ˆ¾šW�=?V>WŒ;/ܼšgÿ>í|…>rã2½¯‡R¾_k¢½òÀ轸Vé=冞>òZ¾åÑe½Äk›½SâÕ½¿xä½Þú‡>KY‚=æm>¾À> ';½f’`¼0+½5=±¾ë¬$¾ûÓÀ½v‹¼ôW¾ÐzÏ<:¯‰¾Áî¾fÓ(>eüô½`G<ØGm½~½ÊÖ¿½ÀÀB¾*(‡=¥Ñ>žö>Œj`¾•G;Äf(½¸gÓ½ÚË >¶wë½óÀØ>¨¦½‡;¾AÛ=$çÕ½×`ÿ½0ÊÒ½ºÄ>³E”=Ç3¡=° ¸¾=_í¾E=t¾Ù=>««>Æh=²-O¾��^¾V«Y=† Å¼ðÒ>��¬>�=Î4>ͱN<§:‹>æûG¾†C/>@@¹½\X³½½Ç%?7E>©Àa=ñc=(àG=á×¾?ê=ÖcÝ= Ý<=B¤>©jD½Ý™¤>¬¦ã½ÈBr>ƒm*>1¾µ‘>åò¾ÞT=£g)>ЇA¾lm©¾ãš½�;2¦Ž>7Ë=¢>à¬4¾Í-„¾V A¾�ìW>o "½2‘="¼¼j û=—»P>å/‚>*m�=û‡¦;¬½0½s<£ô½i¶Ú¾îgÒ<`'l=ÓE½Èû=>{˜ >¢ÚÓ½"}<$Œ�¾6x_½,L=Ì-È>¯)b=+ð;¾;>Ÿè½�¸>¶Ë¼W�=\pÆ=<Àؽ®¶“=¬^=7*>¾ã¼j»FjϽën>U5§¾Š¿¾zÊ»&¹=¼€R>är2¾N¤">w,5=ÛÅî=kj™<†½„ �>�N.=ìhª=�†%>xª´;I>Œ�>]˜­¾·оI(>É&L¼÷Û=‡«W=ÇÒ�¾ßºh=³Ú�¾åÎ >º` ?Ÿ¦=Ü·‚¼½ —¾l‡=È·ï=éâ¼*°�>v>§¦ ¾Þ§Â<Š™�>ùѽ=Ÿ÷>¢·¾×h°¾ ÚJ>") =¸?¾ï‚±¾ˆ>e„>Y <ûq-¾Ã¼¸=Åã=ˆ‹?¤*¾(±=~н &Þ;¯·o¾ó×><·Ö=[ >WÕ«>Л?¥.>Õós½“Á<¹ªs<õã½ñ$>� g=®q†;!1>•_ë¾KŒ)¾Õ C> 0>½†�!¾+H¾‰1>bƒ=Dgñ<£ú¡>ͦÑ= kœ= ×¾�…P¾ê5H=°x ¾Ã¡ê¼Î!’¾ü†Ÿ>ó=¼�¾@‡¼¸F ¾•= ¾ÜF¾$¢6½/®Ž½á “½øj›>(ý>f]¶>K2¾ S]>ë#L>ÿ ½§¤¥>‡Ú�¾sX,¾I“ ?Y…“=ó3νnÕ«=¼€!¾•2Q¾fg‘½Ð¾¾îP>ÐK^>C‡¾þë[<ô,©=]Èã½µy>÷i,>²2=‰˜„=wºk¾—â½BÿŸ>—!D½&©¾ßlƒ>• ȼù ‚½©ÍQ>E>'>ˆ=è‡=]¯<‚ëI½Mü½®Ÿ¾£LJ¾Û >†ú0¾–Íü=Ž¾Ý¼C´Ó=]’>.Jƒ¾Ð¼×>ìŒb<Qš=ô/=¾ÁF�¾Gš¯>2Z¶½ÜÆR>ôGø½‚©7¾x_i>Vuù=ËðB¾I+¯½ˆgæ½’Â>>e.2>#{©>ë•<8Î=» U¾ C>9Ö–¾1ŒA¾Æž>4Y÷¼E‘|¾�^Ⱦ?Ë<>¢@¦½€5ÿ½Û­L¼“™c>µ)½ì¼Éº�7�=r)Ὤ7P>ò…½â{½º=Ò=DÒ¸¾P>,”Ù½ÞËC=ãÈÔ=1Ο½pОSgˆ>‚¾ƒv ¾™Y„¾ëAÕ=}tg=ÂF.¾ºyP½“l%¼È~¼Ô,ñ=­Äë>WšH>>È!½ËÞ«=æ½ûøú=vª»>3-¾´ý7¾®‚>ê% ¿)=gUo>_ŒÈ¼>߯<Ї½…˲½!€i¾Ls?"�>žÀ¾š”Ù½ ÆÚ½Ã±k>ê ì=÷»f¾Š—n<ÌÛ%=Ì(K¼>¾R>Ã!ýb¨é½‚Á½¾ˆr’> ƒ'µ>,û>¶¥í¾;02=Ëk >eãÆ>-‰Ë½µ&>Á»=õ¯¾áö$¾qÆ�¾hè¹>ƒàs¾Am•¾!ê¨=™½c‘„¾ μ~ 5>ìç½Cc¾roŠ= •¾ú ð>K{a<ßê†>q@½™Û¾IYÌ>˜4æ½ h¶=N d¾Ø¢=¢“="2>ZÆ ¾®¶j>’Žˆ>Ÿ«Œ>/^=Áv@>6lC>cC¾RÉD=ŠI=u× >y�¨¾R㥾Á*á=Ò÷ª¼(ÏU=UÃþ=Iæ¾2̾˜¾éú>ÝÉ=}­¾:”M¾¦¦=Ö‹�½âµD½¹Ý澆°­¾ †¾hü¢<¼µƒ>2æ%>©ó„¾plä½Q€>âW½ò<Š>™•â¼  “<Žèü=Ú�¬¹$�¾Ð9)>:†¬½}zz¾Îɧ½GÒí=aJмcÙÞ¼Ÿ)t>¸ €>àŸ€¾À¤²>¤ÇN¼›*2?f ½òý½Ê9¿Hヽz(½.³X½Õ;¾ �¢=Yæ–>꓾Ý`í¼oO>oùa6}¾n¬Ü½§¬ì½‡D>¬˜<yͼU. ¾ºÞþ½¬*¾ôö>a¹I½knz¾ËU¾Ó(]¾}„->°OI¾Ü’>,wZ»Ss˜¼Ä�6>§<žT©½oÛŽ=ëÍ›=3bd>Ä–¾)ä½Àp¿}–ª=Ö‰j¾ä¼=Ä>ä)E½ E¾` ,>yyP>€ñì=¢Q㾂�”½{l¾uè{>Ç?0=ÕžD>eò1<‰¾XLg>S‚6¼®vî=#Ô±½€'Õ¾*Öc=FJ¼TÙá>¬iQ>¼V±¾�73>.¯=kS„¾�Hƒ>³H¼=\>>Œs¤>/*¨½ôÓx¾ÆÂ½Óåÿ=Á?¹¾ÏD =›XÆ;ÝLY>:<ˆq>Žý=«€.¾åœ¾7Pú¾ûâš>3Õ¶=ÁÛ7½ÝiȽgëh=ºÞW>NÒ9>Ö˜½=¸•¾2S"½—°ç<ÖÀó=TKó=Ú”%¾2ù¾Lä=V2¡¾z>·O¾´Éõ>˜/4=ôž¾×rƽ\½½õ+þ“Æ•>Ð}E¾[Þ¾ÆuÉ<ˆAÓ½pz¿e>>Q´F>JZ ¾;Îi>ˆ¾>n;è½Vrâ½3©=¨E´=–u:=b?= 5¾°ÛÔ=—oļ—ã¿>�7 ¾niÊ=i¢§¾ÿ„w<••¼ÄA>S)>&>êEš>:i=Ž÷�½Ä+Ó¼L|F=h>O>›l#¾ç)C¼“)�¾xLŒ>Ø—�=W¾Jx¾Àã­½_û>fJǾ}N>̾è^>¸–Ä=¥•„=€¬>_Úœ>ɳë>×nV¼ZVQ¾° ¾%ûë½ÐS>šÇœ¾Á2¾åúç½â‰h¾9 ­=Ñd£;‰z>ª€*=5ÝE½aÇ¢¾—Ãß=|3¾Ó*>½�æ>UÐǽ¬z¾þUB<0åT¾ù„3=]Ò¿ãZ¥¾ß ¸¼ÔF>>Ô€×=g“ƒ¾ïøK¾#_ɾÉöý=ÙÉæ»Á*þ½êÖ|=v}=0à=¢@=\^¾¾a¬¾ËY-¾TLß½CØ= ó>nØb=kj¾Y/t>m�Ç>d½<_B�¾Eæ-½'ÈÆ¼â®>µ1•¼Û©==p¾j½{k¾—2>³G‡=r>>Z½¾< =Ðâx¾~”½|‘a¾µ%۽áW<´ÿ…<[]º=Mq¾Vz–>¼¹9¼Ì“¾>¹Üû¼HNF¼�zZ=;T¾ ½ùÈ:¾ˆ¾Ý¼u=V’>rܽ 6Ðh&°<¬‹~>"Ã`¾Ìõ’¾™½9í¼ÜÍ==kÅc=q8 ʃ¢>«‚=ÓA:>rÃQ=g³í=`œ–=BÕ­=©¯o¾•7©½¤V’½Æ‡(>>½�> â,>… >ýäy>Ùœ¾ÿ;¢½Á¸ú=Ü †>ƒ¾ày=á{Á½boƒ>ºðî;6Ùº¾i„¾Í�y¾%xŽ>¿£¾{ü¦½m_[¾YÅ™=•Ræ=µã½Û´³¼ˆãY=d#½õ‡�<Ï‘>'Ƨ¼q†{½¦|ä½V0¹_v•=q]¾Í˜8>¦Ú�¾¢‹?Àl�½{ˆ¯¾Ø#¾ˆ_¾å=p½Ùá=åǽ}· ½ õ�¼ìè½jhe½VÆŽ¾K½XÕ°½$Âå=Ýk~=`×Ä>½¤kú<|bX> ùÍ=߀ç=�8¾áù�>ú‚à»NsD¾@ß<-öd¾­JP>yÐ3>EŸ|=¥ ð=±©¾Ëâ�¾¸—=�‹á¼Ÿ™—<Švm=Ý÷3¾6ÈÕ>T„ >�6Ó=€~½CŽ5>Ã׎¾šØª>�~—¾J^©=Ê…½—Èp=vÕæ=Û.¾…X9a–ǽˆ™¬½ �=:>@‡§=0à> —…½²7>zõG<§ >í¦¼ÝÁ¼ Õã=sïL¼Ú=±½/FoÊ*¾ìð³>æ‚Z=oò¾Æ¹1>þÏ>ñN,=ÑäF¾¶u6½¿_ô=Æný=5€¸=§ñ¿¼ðÚŠ>Oî=¬b¢=�•E¾¢"²>µa†>P=Ë%>ºbK>UÊZ>‚r–=¦D=­ªÂ¼ƒÜô==¾ )O>'v�=SÚh<å#<» ™=–굄íí=gž¾k6½ÜË>}86½F¾ØÞ¬<1’¾ÿÿ¾¸´@¾ºr(>/Ä=;B¾eLR;ó)’>[¤¬=!ú¼K�¼vw¾àH�¾±×¼@ö—>f˜>ùŒe¾ï@d=ræT>úªž¾kŸS¾³ki=Y> ‡=ê‘y¾¢K�=½“¯0>¥;É>}ý#¾œ¾¾ ,?>H8P=�Ÿß½ÂŠ>‰µ…;Pº…¼Fd‚;ìμÁ\¦>Œƒ5>©B©½ÿ°=,vô¼¬£Ý>ä!ѼŸý¾È•ž=‘À=Mâ½.ˆb¾Þå…<µ¼å<`r>6é7½3Z¾±œ>έw¾¨Ò">Ëx²¾x ½ÿÙY¾ªŒg>É36¾<ß¾94x>äà>H>"Ë:=öÁ&¾á=46f>,ê=idg=Ì˰½L7¾“§WH�>£•äNƒ/¿0Bè¼ùQ½<Ɉ½¼>×S2=�r’=4q>D<8˜‡½¼>0¾'ƒ{=H#4=°sí½y½â�.>ˆªW¼TÊ¾ÄøT¾9„“¾†¾œÃˆ¾/è ¾Œù½þ>>Ž1ÿ½A޽Ú=6=/÷Œ=NBÕ>·e¾}H©¾IÐ*>ÏbJ¾Žƒ=‘v ½]³@>!>îºG¾ôj™¾GEͽ V¾hä¤=j>Ú/¹¾^Â>§œ>Žûý½÷Ú¹=f¸¢½YWþ¼ƒÈE>›Á‘¾-ß+>;%Ó¼‘yà<²øô;é˜ç=p#¾Ë°½áTw=¸C@= O§¾€Ñ}=b#ð»ëY†>ÞpC<_¾z¡ø½B‹½’+¬¾ÉH=G²c½Þj%>\ �<Ôÿ!½à[à½OÌ…¾eî½S}ª»�‡š½ÒûÃ=ùÄ;‹Î>�¾õ}µ½å¢ =Wõ=¢~½3H¾½E°<)Oo>ÛÕY=ý=.=˜>†'>K­o½˜ D¾éû¼mA«>\rQÐÊ>Òнa¢¾.Øh>aʳ¾ó5b½:ª½¯R½o:Ò¾ D„¾€­Æ» 6>HϼL­¾¶‚�=ðŽ> +7¾„¾Ý£3¾Nïj¾TRÐ>Ùî>V‚=Z¤»¾·Ò½�v>ö_+<>>©½y¼= Þ > 3�=~*>nK#¿´$I>ñŒ½ÿR>ÃÎs» °�¾^–)¾ã¦1¾qê÷=“;¾×$L½ŽÔì=¨Ùl¾†\=_™“¼Hè½ýðƒ¾I¾ƒzð½ìb¢=‡ —<Ø­>·'Q¾ÉB¶¾ÉVݽÛ>˜'Ò=5¹y>±7 >E¾Ø-½Êêb¾�©>E#>äež=Ó¬Ö½ïð�=SD¾7\N¾b =§5>’ ˆ¾dc­=ìc6½ ƽ�Á>åþª¾t©w=vƒ>¶=¾�ÿ½§Ÿÿ½µã¾@Jû=KÖ=Ç™Á½Ûbê>©Ëe¾Ñ9µ> Z¾')½UR¢>s Ò½I¾s^O½¦"=!Æí½Y‡>'«©½6(>6¬T¾ÀóÜ=âñ6¾¿Êµ=µ3V;\>’„ ¾BgŸ>‰ŒË½ŒÀ”½­ƒ±=šŠ¦¾±Ö¼ªJ>V·Ÿ< `=WŒò=��q>›3f¾ñ@?>_¾5<°>‡©-¾þŒž¼¿s^¾Bç<=²›H>ÊT'¾î¤y>šÒ¯>Ý>½†½çV¾Zgľ�¾I¾’û¡>ô>1ºs´>L²/¼äd>|¡õ½_PúElm>øry¾—–‹½9q,½ÀÀ¼=ì Ľ,è�¾çm=40=Íû#¾>6=Ö!s½Ã2¾O*™¾Eom=¤ßŒ>òW =TÇ>:Û€½\üÀ>f¡Î=i!ß½š¾üÕ£=6%ؼ¼© ¾4M5<‘D¾úL‘½2â=mHL=™ð+;9¹(> í²¾rkǾß2k¾?‚u=·4¾œ†Y½½Ä3¾åú>ÔÖ¾%)b½[L#½'½…¾$«w=ÓÀ×¼ý!Ú¾ü#r>J<·½fɾP¾Ã曾~ii4‰½xE>4™Ñ½a¿2¾ò½.‰‡½ ±¾ g້*?3ª½{8k¾Õ‡¿Tk[¾„ü2½¦¸O½�m’½×ÅW>èõ®½Ï}Ó=�ï½JþK¾GþBH(>œ"a=ÏŠ/>UJ3½iÉR¾*ä>¯Ð¥¾uÙ¡¾R¼,Û.¸ •¾"!Ó½šÕ½×ñ±¾øNI>¡ÿ(>u�ô¼u€0>1½½ÅA¾õ¬š¾ûÊ =‚?³=ǽ½èj&>(¶f>:`=È:нsF4=#ñ»(N“>®>dø½NÀ#>Ü.\=Pn¾V>G¾±¿¾ÀŒ#¾£CÉǃ =øVò¾^(¾ÄiW>÷n½˜`š>\Z‘>R!m¾¾é=Ïv=>GØ�»b )=–O½/çнÐÑ9>JiK>ßFÎ=� þ½�ê6¾ŒEW¾o@¸¾g²=/!‚½–±§¾ ªÆ=­wˆ>[£§½�PŽ>6>Ó¢1½‹9<‚9«=)“ù¼0{˜½1!�½øÃ&¾ãå;¾ùÈ=Šä=é3>3>烉½ª>ÐPy>ƒ !¾CŽ>öz•>º$ï=�Ö@½�ó=˜Ä :XÜt>â0½²”9¾"ÈI¾FdB>º/<,¹½ ¯;>W­¨<ë`¾è½„¾ØŒñ=3)î½z¾•Ð=:`X>hY�>�û”>:�h½É!ã¾ËQÙ=Ã�>ºýU¼Öóe¾Z]¾£¬j¾qˆ€>ŸBv=,ľP ¾\;XU•>6–µ¾>^’¾\l�¾Ô‘Ñ óJ>¼s=Ž ¢¼‹ãоäV%¾ýÃ;¾‰%U>lè>´Õž½z7¾Ü@ɽãJ= b›=‘8¾Œß?;Úî<Α>ö«==í½+Ë–>Š2P>Æ #¾u(¸=š™â;+û™>Èa>�þñ½Ç|Þ¾4‹>¹cn>”çI¾({¶¼ä»È<ÇÜ=†-¾êÙˆ>éÖÑ>}¯:>Hø¨>Ýõξ¦2å=ÀC¤=£…¢¾�€ =‘z†>ò\>Ž¿H>“нj#¾8êJ¾ÌƇ=ø^þ=«Äù»òi½ˆ©L½˜±=Ö{(¾é½#½ ÆU>FÎ�¾Ÿ‘½½ðà;‡+ž½”Eó=q¤E=BgB¾èq¾QL>#ˆ¾3䕽˜˜›¾žAž½BL�¾]i¾øŸ„¾¼c�¼’)I<Ójï=¤ø¾°<°½w­>—S>ìi¦>¼›Ã½�·½ ýÎ<Ê^Y>� > ]�»"R½+•¼R*>r4a>=*�¾z-Ò=ô>Ý,о¿Ì>/3>«Q‘>ì0�=ž8f>¿�½(©‚½€•À=>½¡úi>/Ïq= ÃN>Ýy‰=ˆv¾ñ6¾ž·Â¾[v¾})½v0¬>"�ž½ï Ž>^Ÿh>î\s>›tE¾2´†>¿4N¾}+¾&,=6õ޾¸xÊ=Òè¹½<Ý,>´@ ¾Ô~4¾±”w¾¿fu>ÍPB½†þî>„Qr¾·KľIÀ >¡l©½@3 >Ÿ0?¾”hš½òv¾ºŒ»žK½7ôÞ½KYÖ<ž¼™>a†÷½åÌ«>å:¡>Lµã¼Úž»b•‚½7 ¾ü=¾“é=F³Ž=ü->;Uê=RHƒ>]çX>(7d»ÖwÄ=Óûú=:¶a>�'>Òò½0ÀÑ=S¡½«- <½">{õp½Ñ^¹=|/¾Çec¾ñ9u½z>ÀX>Mfk»ÉØ =hõ!=¿¿Å½{ι>n«ì½TUU>‘qS¾áÏݾ�ý©¼i¢=wYξ,µ<‡™d>j½�j½ŒŸ¾©#A¾ö—Z>”Š¿¾-°s>åÄ=W„d¾^,¨¼5òœ½ñqK¾^Ãn¾Ó¡¾|‚®=vmö¼ƒÍ> ì?êf>з<&ºÄ»Ãü3¾òZE>„^¾Ît¦½({6¾F E¾ºàW>h‚¸½`]�=Ñ£›¾Ùý‹>ì- ¾ÉpŒ>„|¾¯›·¾ëc|¾²R‚¸'¼è„,½ž²Í>�©¾¨ò½9¿d¾©äÏ=}Ä»= dï=»Z¨¾EQ½á¼>fÞ‘=ó[×>’ ‹¼G�;Tˆ0¾m+A¾Jò¶;$%>l»6=µ. <�ʾ*Œ6>(ÉF=ì|ò>+ÔÇ=1q½Ú‘>�êZ¾tIå½Ì²=—‘–<Š£>Ï=¶B[¾4­Ù=j ý½;Œè½“qμ[ËY=BO>줕¹©0c¾Ò«¢½�ŠE¾ d6>ó,6>>켺x�>a´K>‡±�>74K=W*=hì·¾ðùؽªø9>Bž> 7>Užq»ûîA>ÁM>á½6?�Eý½ü½6>¤áJ>Š?‚¾áu�½å…‹¾ð>4øš<^Æé=âü(¾F5&¾â >«)½6¹–½ßÉb¾'{ >ºW6<ú¤¾.A^>Œº�½}½D¾Y ¾�cG¾ÒÌþ½½T“¾ý¯Å=;Ló¾  ¾Ø¹8>ÞØÚ½R>[‚»н¼^F_½VÍ=,âì=*:‹¾¢p½µž½\ã¼D¯„=~2伃aš<ʾXT©>Ôúr¾ù¿Ô>î^V¾Qb£¾ bI¼¯a¥¾ÍÚ¾/Ñ„¼È½©=Ü4œ<&É^¾2£§½ˆe%¾(ܼe ½ÿ=ѱ~>‰@¾O'™>:h¾Ë¿ø¼Ï*¾¯!}¾�RG¾ñ½ò>»T¾­G¾ªŒ«½—w¾Õ¾­¡>h#>d¼˜¾ë/(=È©¿½h±œ=1ûß=w”½ãE¦>Š�=88R>JîØ;¨„>Ï6û¼G×£=l#=@J¡=^ºž>ß(Ò=�Á>«Œ=Øs)¾×qî½,�½.¶¾$¡ÿ=a�(>Qä¬=‰;¾ZS;¾‚P6>¤’¼,ü|¾]ö?Ó<,>.§½ÁÁ¤=™µ?=,¢¾öd/¾ìzû=¶¹="5·=¼Èv=œ¹r=½ÖJ=cèÄ=2"«>ÇŸ�>]<©½)@W¾²„Ý=‘³ >éÊ�¼¦>Ø3‰¾Rx‰>‰7‡>^½@É>;V&¾\6^½¶U3¾Ù/t½¯#*¾b0> Mƒ¾|pX>ŒÑ(¾—sf>õ2=�åô½�]=> \½+2e¾Ôôð:îßõ<„VT=u¸­½7�‹½¶"¾]2¦=i}½wG¾ ? >ÏÛ‰> ï!= ¢>¸¥=öËU>H_׃> ¢¾�èÁ¼fdª¼¢ó¢½Š6¾3ßá½Ê(�½2M޾7Ó‹½{G¤=áT¾“}Í><êt= ‰¹Œ}¾†àa¾w°Ÿ¼Ví·¾þ:œ¾•^9=e^¾×Þ5¾ € ¾ö>8­�¾Ýâ¾6e¾¬Ù˜½,²Š¾)®>É?½½7�½*ÿŸ>û�¾Lå½ k�ºu‚¾©�ƒ¾}?Ž Î~½µÁ½@üR½B_v½™Ûp>f¸½=Éé;¾A^h½§¾gW=»AU½Ø9¼>¾R°:õ-§¾žÜ²½Ã ¯½Øx<>é¶ó;¼s¶¼4ž'= t=þQ¾È·;Š])¾* ¾8­»9Úϼ~ÐÔ½ˆ7‡>¯á¢½a\= u¾zfp>UŸp¾±Å½ÆÈm>&^Ú¼�à’=?Ñ>ˆ¨+>¸à–½dj >ß>U—>ƒ^x>äµ]½f>ª†Š¾)„k¾~#Œ>WV>p-/>a;'¾4½À½¤¨—½í{¾œU̽ºƒ.¼êÝ®¾tøš]sU¾¸> ÷V¼å?¼\¯ì= ÉŽ>õ>b^x; ;ý¾‰Ÿ©=–L„¾Ú›2½�j˜½ËÆ0¾Ä£¼Ãñ’¼×ÚÑ=óà»�ÜF>£¯=°áO½KÄ>¦ñ=MÕq=â�ƒ½¸ô¾1‹>jåU½Î‡¾º‡>˜Úü½7̃¾1wg=Бt>g ¾"gG=%u‹¾€šâ½ºK‰>§y=AÝ>F0½1é„=£j=”´¾NÎì½íì§¾Ñ5=k¤¢½ÏÍ�¾ðؾ�Mw=žãÙ¼â c¼8Lü½”9b¾3«™»ZOô=ƒX½J›>F/>H¾´]Ú¼¶°†¾Ôƒ>Dš>>7ö=í¾!A•¾úߥ=Äâz=š_>_ëû=‚aÔ;ŸDè½—s«½+Ù½I~¾ =żö½tX½6·>ð¯> q-¾ñHE>ê,º=Àö>*%>ó >Šêz=W¯<(ÛB=�/= 껾ÊÙâ½:õ”>gà< -§½�“(=#¼)©;½g™¾�…;�Dé½H�>³t‰>tи¾r'Í= ™2>$5¾oÿB¾å\>8¾å¦y¾ÔÎS>c%®>.0V>¸Š‚= Û¿¾&=Ì5í>ÏeŸ½-—>>þ“«½�În=Šñ„¾M¨†¾²Q ¾Äh*½¬´«>c5°>„>=B½òâ~¾\ãŽ=ÎO>(€ >mþ¸=·Âþ½.Ô<„äm= Ä$¾¤M>ãž>ôH¾S¬¾˜-[¾le ¾ÁÍ„>ú¹•»$“ƒ¼þu >Y�¾´k³>Wù‚¾”˜Â>âô…>üµ½Ý<¤>óŒ|>',À¾çH>ßÈŒºdl>a$ó= ÓO=st>½bHf=F+±>ãtH¾Á¡X½¸®«=ø‹>i ξª̽p¾šž€>ÁxÖ= è˜<“ëY¾«b >W¢Q½rkÍ=,Å = ­¤=ý¾H/Â=F¯™>³…>ž*·=>áC=lù¾ÿ±¼=Þõ ½ký‰0p>—9¾Üœ,¾'ˆ¢¾AôÙ½ˆïǽ<‚üª0É=‡Óð=À£>FïÆ=wo>�x̾ñZ„=»âØ= Ë¢>Û`ä¼ý¬×¾U¸­=·”w=´¿î<r%>nº¯¼–M)½Ús‡½½K3>—‘¾ ,%½!·¾–Ã4¾-ó¨<´ µ¼Ot`½ÈC£½þVY¾ >.º«>µq¾¬xð=&4²>‹�m;PÅu=Ýëb¾A®B=z¡ó=šY[=z/´=o‰Ò:î==:!§<Ä Z¾xŸ¼=Yåm¼š¬v>÷Že> ™–:³¿Ø �==þõ½®%Í> ¿0>N�ÿ=t_?>°Œ:™>甜;& W=„g½‹’¾‚N?¾ËŒ>ý�¾PT›¾z:>V(«>«ñ»¾®ÀL>„¾u=Ø7B<»‚нƒØ ½-ÿ½’tü<¢ºÁ>2¯¿óN.¼îˆz¾&S¾lÒ¨¾J9Ý=º°·<µ#?�¾Oà½ç†¾™ =ûhнv•X>ËŸ=Jþˆ>“ÒÀ½ ë†=üYã<ÜàY>èeq=éÛô½Ÿ‹¾w‡>ä Ñ=ßš8¾�Ëä½R ý½Ë;>Ô$†¾ ±ö;�ür¾rý¾°_=«ñ€½«í=>Ä">JKd¾Wˆ-=½…š=tmd<\»0>Y˾Ů>–½ž¾Æ;Á=:¾¾”«¸½KkÏ>iQ¾`e>¨æA½*e½mX¾“VT>6#ì½ ô ¾¬SÊ=ªc̽\¼ý½‘ÜÄ>̶ê>¥�¼R4¾!úÒ<ø›¼æ>K¾#�9½&¬í½ËæL¾v³S½‘í/>ò-y=¸G<=RñƾiÙŒ¾ç9ܽ|ý¿¯Þb¾4Y=pôÓ=@ƒ=Úy\¾º‰>‚6¿=ÎçW=t�¢>Úô®=ž¢„¾R®³¼s ’¯´ð£0ƽŠÝ€=c,w½?Þ�¼‡tY¾öJ¦¾ô¦š¾ä.š>‡£^>„°Ç½ý ¾(�/¾yWнÅ"0<Ð:ê=�El=¥LнŸŒ ¾'3¾ê q¾œc5¾ë7<™×>5h±½Ô$¨;ÄÞ–¾•’b>'Mž=0ǃ½Ç"I¾› Œ¾ñÖ>"ü½ìd†='à¾UC¾‘ñ¾¹U½ê>¢=ÌX®¾GBù>ïÿt¾0ï;¾*M޽zÖ_¼z¾á™¢¾G’¾5ô>pìµ½³ø>ÏÍ >˜„–= Ms>;+Á½©®½Pðì=‰g>üþ’½Ÿ½SX¾M?f=çI¾ËÙ;=ÆÃ?ëª5>ìr¥=ç=²½×Ér¾iÉ¿_µ€¾F'±½T¨.¾äЏ<µ»¤=™I”=w´¾bË–¾òÝ:½¿*M=mÑÓ>°˜>ô6|½†pݽ&ľcI€>¨íD>6‚=ÌÛ‘;-B!¾œÆý¼­æj¾+�¾>FN~¼¾­j¾xÓ÷½@3¿wÆ`¾Šý†>×㢾¤øª¾Ö%�¾>ÀE¾rçþT﬽pc¾Ã÷!½ÔÞu½þ7°=v/ý¾­½\¾L²r=VêM>Ò`>”g¾7 ½zÝ¥>&1½ùÝ=Co>®?>e®¾äÇ>4ž}ì–>ê>Q¾(1?Z÷7¾ûœ=¬Xʾ„Fh>Q&G>7ì=îg¿¿G¾4^ɾW8T>â_=ÚP"½O�E>޹½õã½^>¬­Ó=1мÕz^¾ðS¾ÂÄ ¾ û<]oJ¼Õ•ù1|æ½æCüë*¯=ºÖu¾Òý¾ük€>p@_½:²½¾ÉÅ÷=à'ö=V�!¾¨·½€!ð»df ÛŸ9>ˬe=¾õW=H¹°;ð\;v+½9ü¼=»¾ å½¾�7�¼ª¡“=È·Û=BBѽ•r–>°Á4=Õ$*=Ðä·> /‡¾>[v�¾b®½%Lc¾{f=A†›½ý,£½š_8>G”O>j�¼6Z¾G�޾â\•¾Çaƒ>Ð6ƽmžŽ½`A½vÂN=¼‰m>–¥3¾‘>2ÑÚ=fÕ>õu¨¾j† ¿tùºÿ ¡>*€I=Z’=½]>°x‚>®ðy¾; ʽ•>ßô ¾3)=|^#½<ª~¾U�>Y’'¾k�¾8âÂ=º¢½»´»dû7¾Z„½á%‰½x­�=g¦�¼§É¨=Ÿ†½äÏp>4þŸ½(57;„^>­%< ëÿ¼ø»’==ä±=º9)¾’¨!>Ä…e¾„7M>½š�<5ì>OÐÞ=nõ¼—ˆà½•¦¾\õ>ºã^>7Þž>ðC:hy½™w¯¾J«¾>èq„>º!¾r™¾Ÿ‰$>âT3¾"ëɾ8•Â>´$1¾þùn½èæ=Áœõ¼j}+<�ºû½Úˆh½“߃¾À„E>0`8=ÿk¯>¢:P¾ã’¾^z<ÿhŸ=‹À>¡˜g>•ª>gU�>œL¾ ˜¾NŠ<ÿ;Ò=?¹<ˆQ†<7>æx >F•�½äЕ>y•>ô^<Q‰>‘Ô¾®Å—½7—‚¾+VU>/‚‹¾‹´x=9s™¾´š¼µÂi½Ö.eÓ>`=ÄÑŽ¾íw?½·1?>—D9½â=t<ò–½h²Ÿ>æÑ#> >ä½¾,f¾qV†¾B»>NÀ¾üÅý<[!5¾Ñоmè–¾£oF=ÅÔ^>ª3a¾Õ?Š>uŸ6¾¦>¼—¦¾ì¨»2Ø=º>>c»<Ì�á½ðÕ=ãX>+E‡¾íS{¾mµ¾$>>ç†�>9’/¾¡ñ²½u´>Nlr=|a¹½2lr¾çØ5>20>–¥¹=R餾֙>ö©>®¬Ó¼‘Ãâ¼ÓJ¹=$¨¾•}F¾•›é=R$¾Y«=Óà >è‡/>�QÊ»ï¸Ú;5Ì>Òº1>¼¿¼½1çÆ<³H=¼mø¶>PO>—U½Ç%¯¾¿—½'Ô­=�³Ñ>|S‘=éP¬=é˺=»J1¾åcª½ŽL�¾÷0i>®Ê:=ñæ>Ç®¹¾Ñíf¾ÔŸã=¹ŒÌ>*„i¾¿íð¾¸*™¾áÀ»ë‘;>sý<œJý;N+j½ÞÃ>.�>ä¡�½’÷†¼·'^>šªÓ=%´±>—`W>8äG=]`¾ÙEâ>ÙnŠ>PhŠ>ñDo¾èk>S$ ¾‚N©½  ±=\St¾>ǽ¶º½ ;ܽL‹þ½Øw½-·)¼GÂU>V§½êr>o¸ª>Ý+�;é/³=©ç‚>è¸g¾°Ê€¾]d:>¸ì>Z>‚Gå=µ½ŽÇÁ=]*‰¾aóX=ˆb[½j*q¾W[v½Ô^/=€C>.É8¾Ü¸S=L›Þ=éž­½?åÝ=£&‹>IÖ¿>—qÔ=žÛ=‹ð‡=ñL >Çf>Ä:ÿ½†.n>W&™¾Õg>,)>OƒŠ¼ù“Ú¾A˜I<·[­=Htè=òs’=7E@>VD‹=yÄõ¾ŒÖ¥>F�>ZËî½…K>ÖÒ/>J*>›+뾤Òù2‹G>êî¿>Ã�g<·r½þ·…¾lâ@=_,x½¶x”¾´¥>ÅJ–¾Bq�>­@¾›œ½î>¡=¦�3¾DÔ~=Þ:/>-Äž¼•W·¾ä‡Ü=u0ö="©>À+%?Îÿ¦½Üb¼¤h7¾Úaž;ZÔ®¾Õ�„¾¯›>›Ô3=¯<½=�q»¹\ù¼û¿^¼{!›½v9Í=bá�>3ÁX=#·¾¶æG>â¦P=¦q”=zò½ÝI‘¾íÿ<¾FJ�='R>Kö½Q_C>± >R$¾ôáš½*ÝÖ>-¼¼;\`€=¦�>½uåZ>g$¡¼“ï=|ä·>‚†9>Øñê¾_.¾MD+½Þ<½t�¾Üî>ž ¾¹ H¾È >ÆŠ'¾‘¡>·Ck½Ô*=—)Ç=Bø¾qÉy¾‹'¼Æòñ½º$>ÙÚ>‚YJ>‰¤=ýÊç=ªƒà¾’ô”>›1´¾4=½FÒ$½¼ÿ>•A—>Ž^B½†v7¾•Kí¾ ¦“½Y*o>ëH,½§?¾—=‹õ¾jí=c:ä<^Ìh¾“½lù>D�ƾlÐ�=ËA|=¾Ò¾uÉ>;÷¸z=(“Š=îl"=¡¾Šx(¾>‹§¾8K6½oqÀ¼Ù5Î>ÇË=ˆá>ÙÎ >M�?e `>xÕ:=”´`>ïì¾LG<Ç䋽‰›½«ê³>&­¤;С–=PvÓ½5K.>®©q>¯‡ä>‰8‹=v,†>j~¿b­=ðÕ�½LCÅ=¢¨N¾o¯¼ãÝ÷=E¯Ä>GõY¾DE>î%°½m®z>²E7¾Ÿñ<Ã�¾¯ý¬¾Á3>}·=ð ]>Ì©Ã=Ì%U>ZàÎ=e"¾,è¾ÞR¾êξ©üŽ<âŹ=µw‚>|­‘¼=d/>³Óœ>B€°¾Øvy¾>£½=u¾½õ‚´>í~(¾q?þ½â„¶¾f)¾æ<ˆ>Á‚<•_¾à$>Ø(½=-I½éY>²ßË=�ÁK>pø$=²Û¾:ãâ½Ä·—¾–_`=ˆ»4¾mƒö½Ð‘̾“¦>ßÕ/>mNÁ=O†¼ân’¾®›¾ÈK/= í2<£¾½Ô#(>“\½L>Tq¾7n?i£á~Û‚½4‡«½ *>÷ºž>;”»éGŽ=âpä¼F¸äUC¾®–.¾9à.>>>�ì=¿æ¿½%.d>¿Öw>Ç‹™¾í×D=2d¡>ðÒ¹½" 7=„åe>TŒò½¬OK½IÊ¿ôò!=ÅC?>â±Ç½b™|<þq>’L‚½Î*>ÀË#¾c;©>󳬾lCÈ>´ŸÖ½Ö…=Ì›{>§¾‡×=ð»@>Æ3¸¾cÑ�¾ #E>?0®¸»J3¾é¢Ž¾wc¾ü­Ï8ç.™>W,œ=õÐ�> pH>홽®� ¾Ð u½µˆˆ¾×ĉ>|dL¾�ì>w@‘=ñ�=ˆ4¾†¤=·Â)>çSW¾­ìµ»®Þ�¾Îš=Öå+¾ê=ªˆ>¾Ð=/�j½j©°=¸Ç¾ò�ャkɾ‹£w>‘dœ¾Z°÷=¨Ü„>¤¯»"¦ä=ê@l¾§øÇ>·N²=¬÷½La¿½5”â¾^€&>*Ͼ¾µ€¹=8¼‘¾Bš¾K!o>¡¸¾ qÒ<7轎•>À·>?û >�¥¿mö ¾\æ<íÜ>2£=¢£¾bz ¾¾’5>8E¾¶GÐ=rWa¾">}‚=/O7¾ª$%>¤ÊS>н¨=µ"—>–Të½×‹Ï=9|®¼á}K=”ðg>¡Ýƒ½>?,=€W;>]`=ÈÇ•¼£Š¾AuÚ½a+ξÊZš=¢-½n…>N½>Æ®½áÃÀ¼¬Ìù>L4‹¾’T·¼ÓÊ¿ðH´½}-¼�åI=ù}$¿ {ý< ^¾Ë1>¼ˆ_=c¤”>Bí¿ùzo½Ò°¾mH>Lâ¼Ï4‹>æu¾9±½Òœ>±¼>ZáÝ=2…3>ç8™=%±L½³a“¾/¿K>fÒÞ=�eÜ>žë[< ¦t¾XÑ=Pav»ç<1=fÏY½‡ô¦=S³$>,mÈ;8 ù0¾ðsó=ˆ]Z¾µL¨¾³�®=¬{!¾ËV´>Ô�)¼m‹h>Íu¾Ê‚½&Fƒ>_Hù½+n>]羚}¿¡À>nZ¾ç°L>hïx¾†bq¾ ä®½Ê¡>ÉŸ¼=lC>-¾)s¦¼rˆ>ºüs>I#¾²Ý¦=+·¾îrÒ½%Í®>Äê?ˆÙˆ>%óq¾µIR½¨’¾òúI>dwA½ ؾ�¶~½~ç¾rLƒ¾ÙͽCS>m­L> L€>ú2è¼ÿmà½s08>ü™ß=\Ó2¾À¢Æ¾í“N¾ØÞ•¾í ¾¦G;=.ã³>™I¥½‹šL¾T&%¾.OM¾3 6¾¶½‚¾Á×4¾tÒØ>:?æ½�Ø¢=Å‘¾¦Î>L;(½èf,>½÷¾s&™>Ûw¾�fq=½ýC>çl¨¾¸Ñ>µ®m»æÔ€=…n÷½ì¶Ô> R>²¨—½yݧ¾)–=H'ð½*l�>&ã!½ïÍ&>нiÏÔ¾Pbj>ï‰o½§+>YS¾¢Ÿ¼Éþ¾4 ¤¾:Â<½#3Ã=Ò>>',¾Ô a>5ø=ØÍ< Õ…>D¬Œ>ú‚<œ¼;<ý |>kK1½½×¾‡«=|�¾A¯Õ=£û˜>íX¹½¢­¾{>µ¹j=Š#¥=>Z½S²Ê¾@ý½SÊ»}ö=¾ÛA¾žã9=ÑÖ¾':¾æg>>™Š¾©¾–Å=äx>à>Ö½&x½c„/>§Ã”>qöÞ=7j´½õë“=ÑË1>ÍÉ:>©ð¾†°¾¶Oò½J"„¾Kµ=ú‹½£ ¾ü~v¾øpF¼#·;>P`¾™¶“=_Ⱦêê‹>�zÿ=Xð£¾9÷¾û±°=~Ô>£Ï¾¿,ļsƒ+½ÿÙ�¼‚Èl¾i$¦=i“U½‹µ]¾™¾^°l=†^®½›Ì?¾TÚ¾’ýö½Ì¡o>E:¦¾òHº¾&åX¾ðÌ£¾3)�½UÁ ¾êû@>8ý{o¡>ÒH¢>ZòD=2Ê)¾÷Äâ½ÁÛß¾Ò�‰<Êdî=¯Î˽·YH¾ÿh¾QÆ=�‹–=”Âò¼y =>øÈò=²R >DÚb>�Γ½zK�½RT>A ¾L�.>“;z¾Ep3>ÐË}½Â½'>è‰r><*¾¨L@¾£c“;UA½©Ÿµ½+~l¾.–×=ôÇE¾4p<~{ê½2G>w®/¾'…£¾¤m¾ÞÝ:%sQ=ÁDê=Ÿ#¾Q|¾(u >« ½þí½ZÂ6¾[ŽD=„>,>þÀ|¾Ÿ¿¾í¦½B·Û¾Ó×µ>¢Oõ½6#8½�âr>Ï/ĺÂ=ÜFõ½Sd ¼¤G=<³Ã=5=©=Zé‚>�%£¾»“ÑD8T>O¿ùüP=g³I½õ8¾™§ ¾ûÉü=åž=Cpi>’S^ºOÙ�¾~í>D¬Î>±àŒ=µU¾½B>¿¼Ò=?[~½ýpd>áž;¾�cØ=•c½CgA¾ ‚Æ>0¦¾ß;þ=»Z"=´AÐ=]M­=±V =õ–™>9ž›=‘Q˜=¨‡Ô½ù$Ä=VÂ1=hJ¡½g d=Wó¾rã;å2ª=^í¾ÚЏ>όȽ°NŽ>Âc½½LM…½  )½ÛX~¹[RU½¸,Ƚâ)>v½½©³(¾ìÈ >5:l>‡O'¾½<˜�¯¾+jî¼Ì4>Z\“¾ö’>�Ë>¾k=Ì`W’>¦£¼Ø´¥½Ú•G=|h½[ ?½9˜=%÷‹=ŽA¾òÃÛ»÷Ù¦½ÄÎñ½îgþ½çUò½^¾¾›¼»go<š„½-Ã>Ð蛾hÉã½Ðë̽œ^6>3ø]¾O”q>¨½Û#�¾,U =m‘?>ün†¼#M•=b½>ºøì>˜½™»²¾3,¾û±E¾¾Œÿ½81¾-ßõ½ï)¾Ÿ®E=8Y>¢+N½¾`>KÁ>m§Ì¾ä½yl¤>ÎW%>]Æ >B¨£>¤R=CÜ�¾­›~>—V>|Š¾Î†q¼M+!½V¾©ÿ ½ø¥½@åE¼Ýg=)=na>¾Œåø½‹&½Œ‡Š¾‘´¾� ¾tã=Db;¾'¾’Î/¾jhÕ=‹ê?<‡f·;f‘>)Õ=-§å;‰É[¾ g|¾B^>Õxi½þy½›'μ6c¼=dÑÂ=h©D>2�ò=²5¼C>tµP¾nï ;ÂÄI¾ÊEØ=[Þï<ÐÅ>ªº�½¾û\¾rjx>¹Þ@¾ÂÎe>&Xç=å·œ<ƒó<…-¾Hž==û�>�*�½'S¾¿/G¾š�½tɽ/˜¦¾L¾1±¿ZmĽ\—¾9�å½W¤/¾½a>¾\‘Ã>þ¾‹™ê=Ža‹¾€¬É=Í'¾t`�½pÍ ½3gµ;{¤7¼å¦’¹[/½ ¹%>H�‚½?JÇ=Ñm?i�<¬Ë=á]=äµ¾/k”<'™Z=yû>‘Ž*¾¯€¨¼�ó弑=Š(9¾”G[>†Œ€>Mš9½ß4ʽØg=@¯œ¾¾í¾®~ì¼në=0Q†»¢v¼!¾ð=Ö î½Ê9Ó=Q-ü=jß’¼Ø£°=ÇW'¾‡j>Æ’ð<¾7.>_ÂI: , =š(`½-—å=<>¾Y`=ì x>ðݼA+ > 䌾ƒö%=u´=ò ¾Û™¾cžw¾/†ß>‘Ø¢¾?tP½ò¡¾[ÒŽ¾ÿè’=êe÷¼OÞø¼Êj]>Øœæ=­Ðè½ J¾=¹€Ž>_<¾–òy·ˆ¾T;T>† ¾Öu>�ˆ“=…²èËö½�*˽Ðú޽}ŠÐ¾²{ =A½½*j½$(£=5B½ˆB¾¯T>f9k>}Ѿòé°>É„¾Ün¨¾+XR>t >â=d=>a¸=€¥¶½ýö—> —×=žU4½ÊÓþ½­ÏT>K°D¼þ)ô ’>HÞ¡½àg¾e+R¼¬DQ>¬¾&?>|€>—Me¾ [Ò¼˜p¾´ m=!ç‡>M=c¾ó1†=^^\½ôz»÷æÄ=ÿ6<%ܸ½Nw>µ|ƒ>Œ¼´ s<0y>PÐ{½)|P¾7庽+—V<-ql¾!T®=,ƒ¾U}/¾m3Ǽse7¾^£¾Õ¦!>d÷å½#�»½fÛ½¡[¾CeP¾/¿L>öÄ[¾š[£=VØw:‰ªP>æa¾Î=J>Š=#I(>š.½ÿ$¾¿Øt¼òh¾aÁ¾½ƒ!½†1¥=°+f<ŒdÙ= ŽŽ=ÁÁÝ<49?à§3½Bî£=øÊ‘=¼G…¾è)¾û’=§º.>>È`=3k&½Ço)½ù>˜Ãß½s"¦:†=3R>Ðý”=,�øâS>”·>�ƒ¾ÙE®½æªã¼ïœÁ¾)¼>K”=¦Úö=³x=>y>4=ŠÒ€>ɼ½¾Ùr¾î7>Za£¾=N¼¾�ï>‚¾†¾dó‘>]¼‘>Sò•;Näî=Šfã=›ÒJ>¿ä¨=¥‘D=Vsl>ï² ¾;™Ö¼À'ƒ=È!3<^°a>^á>�»·½î<°½ €ž½^\¼Ñ0î½T׎¾¢âž½X,0>T›�¾ÎŸ’>X±¾`Ân¾B›>Ô< o#¾0y>¥×!>Û´I>:s>ÜT9¾µ©W¾0ã=d”„=Æ8G¾[l¼~§O½®A>¥i=lrÁ¼JÔó½m¶¶èCž¾vj^¾·!‘¾ý¼¯¼¿µ>f*¼‹ý„¼z ¾&*´¼'1> ¯Æ>av�> ×(>‡•=»cÙ=/A‰¾k–½“­>±PX>ºXް«î¼SÝŒ½³¡‡¾™²í=ß¿¾œhÅ= *D¾5rh¾Kf¾ä©]¾$��½h»½a¯Œ>¬f»Q~0=C?@½×½0#¾çÛr=î)½[ô½‹~M¾&Ž8¾D†¾„&„¾`g>NE <ûà¾ÁD>ƒS½.þ=ÝX»æ…¬=À–Ž=ã߀½lÒ>Õ¿[¾�@~¾™Z[¼‡r¾¤”>÷o={2̼ú3H½àƒ¼<Ä‹=Ô°:“±�¾@ª= Ý4>f)¾þ(I>+^©>GðJ¾T™>¹»>Ý•¾Ü|¡¼GoD¾É8ë=ôd;>:—<¾¬Öª¾·?‰½ÍoC½UÉÒ=üÐÙ<&ƒ><�ñŽã’2>ÄS¾e¾‡Ÿ¾œ<Î=¹á½UÖ¾ ¸¾îpp¾XŒU½ñW_½l¦†>æ:¾¬×˾Åôý€§?>Ü¼é½ ëܽŸ~¦¾Pª8>h]>ß±=xc™=â¸=YYǽgÜ<>*Yˆ=aÁϽo½‹w:<¢Æk¾ÿ?X¼}ú¸>øs‹½F6 >Ŭ辉Ve> ãS¾ùÐ>ªÙ@>tY´=+>¨ßü½EH»GÝY;[‡ú½ž5ö¾>2¨=�'L>¶h¸½%O>O͵;¥Ã˾ʣ^½R{Œ>E#Í=2§O<…@ê¼vœ>ž» >Ä•‘»ë§â»5ëR»!!U>Ï«¯>†·s½ÐÿP¾µ‰A¾ìî½Ry–<ç <¾ $µ=tòœ¾`Ÿ‹>òa¾aë=Ǿڸ>>jд<ðJž½R€�½LL_¾lÌ2¾"~Y>€�m½((>6Á\¾§§V½°ñ˜¾‹>.¶š=߃½â„=kH ½œz¤¾K‰/>ý£À½o—�»ø&Ó=ó,Ÿ½Ê°Q¾¯øþ<Û#>ɦ1>¶0V>™Ñ¹½`>¨…½Ákñ=~R½o:ò=R>l¾›[•¾jç¾$Ú4½ÏÐc¾­>®¡I>¢Å¾É½O¾Cgš=Bü >Æ.¾µ3ã=ãy<¾Ø>¹]…>.1¨½Ôé=s½»=Ç/G>ÃSˆ½93ˆ¾ôØÓ½¢÷¾áKv>EH¾z7�¼¶&z>pK>»Iɽ&Е=÷¯†½ÛÐ>óQ!½@¡>Q_‚½„”½«?»О=¸X>­žÛ½¬¡¢= \}¾Ý€ð=ŸÆ½S¿â½JÖ¾?�ܾËÝ„½Ù_7<ÓÀ>¾ã�Œ½ÿê½ Ê=�Ÿ ºlf³½8ïp=2>¨">Ÿ„ ¾ÖÐ=cg>]�Ô= „,½ Š:=NÏ=7‚‘¾ù¨Û½e¤>¢‡v>eˆ•½§kUC8 >:Ñ5½O³x>(o¾ÁY¾ ¬–>ö‘Î;¹d¾æ â½PÏ>mk–>V£>Úî�½a‹¼Ë°½ÀW>CE9½Ö̽A�…¾°ïo½h¹Y>ªiL>Žá:>çx¾V¬â½g€y¾+ë½aO¾:¶á½s;> ?�>ºEý¼ú->ã·6¾F.}¾²¶�=ª^¼ ‰<¢8z>!¬y¾Y[&½Ìо׀¾ª,¾â$š={ô>§¸>-¤>޳»=úͽöØf>F/>Ñß"¾Ì³5¾Ë=*뾕’v¼2ÝK½Çà´>á¦{<,,¾¾×>v)¾p4R>‹i@>Xë>±�?Õ¶Ô½0ªü;W§¾‘ËA>Äu¾õ°0>({Ͻ£Ÿd>ßëo¾Ÿú†<#°$>gû=èĽÿ„8¾^²½©K˾xc=GŠ9>k&®¾¨&�=2+_½> ë<ߎ>Z˜¾¼½Ž<ûU¾®,ˆ¾¿v§=¨ôI=C>?> ­¾ Q»GÄ¢¾ ª•¾PYt½ÇÛA¾L­>}hð>NåÖ>%> Ü‘>O R>ø›»ÌàÓ>6w=iBh½p½–½/žI>V+¾Þ°”=5ÿ>Òæ;-ú¤¾ie>´f>W.>Ú«Š<4”°¼“à–¾K½=èX½—f>楽Tß&¾"*­½ XR¾ >œŽ:Ù‹R¾+ôh½Q䈾#åç=~uÐ=¢óÊ=>0¾¾š¾LÑ ¾®�>žR¾®¼t­ë½(-4¾Ô,¼L#->îƒ ¾Ñ‰>kè¾qJ%>&TÌ=¶ö½›ŒÉ½µØ=³$>t ½síɽùzU> /¾ÂX¾Õás>v(Ï>Öy¾?b ¾SËK½›(@¾-Þ>阊½Tô=ÊÊ9¾k›�=Õ$ë¾ÿa=ZÚY½³àþ¼ñø¾¬P>P‚¾^ Œ>É‘˜>X7=ñOœ<ÂcÛ½W”¾v�š½Ü >Z$¾©3¼ú|a½Ì†¾g¾X@¼6P>^Qô=‰*ˆ>þX™>Yð­>˜)�¼yk~¼H³�¾ÖS>†X·¾:x¾�ª ¾0Ï“½ªŒ>+ª5=󣽎�>õ �>®"…>³4½ß�m¾`kº= â=ýà¹T˜©=Uº•= Y=¾Owþ¾¯Íz¾[i<Ë 5¾ùŠ·¼¸ŒX¾Š.‹=¶á'¾ìÍn¾V.½Ú”ƒ¾Zë¾=uÔÿ¼ª¨”¾ðSí¾¡bD=(ÂÕ¾sõœ>ö\|¾g„P¾C>ã¼à�>qŽ >Ï >·@�¼þ)Á½Œe<Î=Î<¬Éw>êÜ,¾jŽ“>7—¾’€¾ÿ§j=[Ï�¾¯·Ô<ñU¼’«Ò(ô=qûš>”M»= ”>NÝ=¾Ì‹¬==óÝ>”<>㺥>¿¥E=¤>2Aé<&]T¼I�‡¾¢A="ÿì¼µ¢=|`·>!k ¾–ƒ4¾{{½š‰=š\æ=È!š¼ˆù>á�Í=`ŽH½^U&¾÷¥=b[¾=à꺴wè½¼º*¾ ™Í¾Ô�‡½Á“Q¾+ð�>Α=þ >ŽB[<i ½&šL>/"¾©>½Zì)½Œ=¿?>¶â(¾ð:>þQ>K‰¾“þ>XQ¨¾dû2>xi^=0ë�¾Ìâk>-éÙ½ÜvÄ»¡³=R²Ä=�—Ü=3Ѩ=­tÞ>þ¡7¾ÒU×½Si!>±m =´ÿÿ¾UªÃ<Å´…=>•‘¼¾*¾ /¾V<þ=j²>ˆè¶¾±³Â=6gÕ¾Þj†<\+§=`cf½°O™¾E©‡>a˜n½íø�¾ø>d_÷ H‡>’Ð=­!>¦»b=Æé;>L>ë=h¼½W%9½Âöi¼û¾¬‰rºkp>}‡¿½JH:�”Î=q0>!«®ºï‚¬>qÝh>γî<‘L=ò�¾þEÔ¾¥Þž=�8©=£ßt¾�oñ¼QÔD½Tô�½bsྎÒ½ÿ¼¾L­T>.nŠ>é!p¾xõ¾•£ó½Ø›i¾¸0¾Ã2½Z#!¾Þó©½�8¾ýQ¨½•Ä<Ú˜X¾ä‹½Ý;¾¯þ¸<� ¾W…¾&Ö´½Õ2^=ê›1¼&Dð¼&>×-ª=lÖX¾äfQ¾;Fÿ¼!½ >ŠÙ’¾åH‡<Õ3‚»> •¾·Q½oºB½�¬º<µmH;’0>›þ=º¤¾E�Œ=«e3=!vèòƒÛ=bñ»<¤Ëh>F-½_Û‹¾Çx…¾mþ�¾üâ¾j‹¢½Ñ̾zW™¾ô¶"¾Ùß´½Æk ¾°é‡¾÷0½‘.Ï{¾¨Ñ§=�{½Õt1½c>£½>6"¾)}$>ÍäÆ<½¼¦>‰½àÄ”>…A‹=Ó¶h>§9j= †\¾¤Ù›¼d¤;ìÈÀ>åPµ½¡§9=+ÿ¾)g¼…Á¼àÏP>@ï{>= =ÏÅL¾�y9=]ã²¾²AÛ½€î¾wCn>Œ2¾|>>döÂ=ÐZ£¾•{oº‘½ >ä¸<5›”¾Áå=ÿY…=×V>ùj>HÇý=0F¾o·ø»R‡>2œ¸½ß �¾Žµ÷=L!i>T…>mÞ½ô�>sµû=M�¾erÒŠõ¾V†í¾Ä™Œ½¬§¾½SG}½4ÜH½ƒæU½lÑR>MÍe=Ù)õ½W W¼jW>‚¬8¾mõÅ=Y&>|“ν?f(>ÎSl¾~\K¾]$ؽÊ/Í=¼lÝ=µì=gx±½QÕ ¾`ê½$2>8:l='ö>¥ß½jq>aŸ=]Žº¦WÓ½â`8>Dšñ=LÜ4¾›ˆ>ˆmÁ=¹Òt<‰y=€ÂÉ=eòA>Ü!¦½n<+=õ=ÅçŠ>÷UÈ=>o>—û¤¹üj>œ©†»–WÜ£B·½P/f>\—�½·×>,…¾á?Î>É ñ=mδ¾!á«=}%²™!>̲`=ä¡Û=:àN¾K¹1=åœg½…½ìÈ>n³> ˜>‰> 4�¾ù>¤VÃ=zg¾R½Ù瘽…Q!¾Ëóż¢ñE¾¸{†½ ɽÁ ¾=^¾Ð€=>9о½np=õ6»ä<¾^ Û¾d)£>eŸÐ½9 ¾Ì좼×Á¡=B_¾^®½¥üx½ŠK>Üb§¾G5¾›‘¾Jx3¾Ô¾úlo¾#À£=½!¨>Öz3½ÌÓË>õ0w»œª< (¾{Ç£=Ì90¾^Þõ½ 4¾EϽ»J =v¯é<3Öó;7J¼Æ¨>µ^ ¾¬À¾j½Õ{ž=7É”=n´‹»¶Ïæ¼#¸!½Êú”½>t‹”¾‰`ʾ�Se=«()>* ×½µ]?u¹&¾‘H>xÚ_¾Œi¾ v¤>Dïæ¾ÙR¥½Ú€b½q�ÿ=Ìõ=‡Ú¯=ç0Ó=)®X=r�>WN½G&N<.þƽ¨òã=‘ <>ö]½4P">͘©=5þ*>¥=ƒ=�—>RŠŒ½{:µ½¯…�¼•ܧ=êi–¾”´Å¾-µo<ëNK>б#½0eA½µÞR¾ †–¾a2=ÆäB½Óý2"Ò=RÕ7>™¯½Íxù=µá)½ùƒ¾5“š>qWü=RrÞ½‹Õ6½¦·¾vVM>~�Œ= ¬<³_½èSO>ªy3½¯—̽•G·½-¦Ã<ô2=gS=y0¾¸¾Ë—=ø¹Ä>BÆŽ=üH>6«Á¼'bÈ<`Æl>r`Œ>t]>.$'>* •¾67Q9ðûa>çuù=Ó�ó=敽@@Žڢþ=�.ï=QgN¾jZ”=ÔʾÇ-=‹Ö€>9ç1»Eßi½!>öav½´â¾û»ˆ=xé�>o>gk>_i<•o÷½ûz½w,>·‘¾Ñ߀9 ʆ¾vº)½?/©>WØS¼p’½( ž¾Ü½N>'S)¾æt×½ÚZâ>iU{½‚·�½çý³=*©ï=tu)>‹J<¾SX�¾­ ½Iÿ�¾¥•»›ͽ¦9¤W½Þ=:Fª¾s• N^» T¾¾æU,¼5)½(2=þ*‰>‘Ó¾kýs¾þÇ�<‡’Î=¥SH=àv¾L¨ >è±P½€�A=l4 <Žr½Àöé<–ˆõ>³¸q¼÷�;¼ŒÏ¾Ã2½_;§=6e„>Óx=S§‡¾‚1>6Y¼ûN½†üÇ=Et±=òuy½Ä�= �ö½ç8¾‚©½»Râ<>ø3!¾í•ˆ=Ô[›½Œ¶„¾sÐN=IòU¾ÕZx½ƒ½nMؼ[LP¾ñÔn>™W¡<TC½Þi6½zÍÛ=È€…>œâR=—(=¤Š >„—¾xÇ>Î:=N·¾MX©¾¢¾÷¼N¾aV×¼—V°>Œo½./%>IÛ¾_U—;»¯…½ =¹QŽ>û–^½â!¥=+ ™¾³J>•f¾BÀ[¾_L¾5*Êw ð½I¢>ìíy½*ÿ0>Ÿé½]R¾º^>œÏ¡<–8�>Ìcì>@þ¼ÔòؽtNµ¾M[½¦¥¾–«O¾GѸ=ì]s¾íÙ'>†>òÍQ¾�¢‘¾²i>ô޽â~¬½7>!�…¾ Œ£;E.x>«€¼ÑÔ'>CJ½ýº<=�à½|a®=Ù1ˆ¾^–¼prŒ>{˜çg¾ýfÇ=™½¾Õÿ½ÊE²=*Âî=ùw>Ñ'L¾Ó,=H²@= =¾ug¾ä¿>–s“¾`>zµ\¾é}>v¨=BX¾(Ö½¤¿Ö½T�F¾ )‹=Šо¿e½X½¾æ–Õ½zF½’Eµ=áÄ>É¢>ɳ½×j^½çd¿½? >Ð[>‡A¾Y6Í=!iƒ¾N´[¾Åƒ>›äŠ>'ÃÁ¼¼A»=JÉ�>X8ª=*ìɼd$�¼sž=›2/>—lÚ¾%S³=>w =É®¢¾CZA¾!þ=–Ó>zÍ^>aö‘½&ܽ=ÝN>©ƒŒ½^–s¾4¾Ôn4>¢uQ<#>MUK¾Ä >¾F×®¾‰Ó*>t)>ñž‚¾#r]=gú¤>5c<½[r\=bÏ=8“=¤¡Ò=Ô•ºj´¾6!¾ "¾zb¤½X&.½nF°;²‡½1:R<±rf:@ÍC¾ýŸ~¾”?G¼&ÌU¾B^>™¡m<“Ì >kú¿ºñ¹Ý>Óu̽m3T¾9W¹½s§Ø<:ƒ¾ð`×=æ§<=®A ¾Ü¢^½*©=_¡Ô½néü½4é8>²yd¾L n¾Q•;¾…þ½þ̾ÈjÄ=ø¦Ý=cøZ¾?—§º¾ò–v>™ú<¾ö ½N±Û½ôý>ÝX,¾,½ÚwY½˜Ÿ¾á] >ÇÒª>‹’‹½£= >ãHí<}©*¾ý½l½­Ü;½®ž ¾ ƒ½wÄ= s�>Dc¨>B§.<”~ǽp=1>¯6>rÚ™¾8ªª¾R³6=.�н õž=™·Ž=ðL«¼âþk=Ò!…¾$ô¾ÔÞ¾S¯ >í7É»€ýÍ<¼ Œ>ƒe<´Œ=î#ȾhnC½^üñY>B>õð½Ï†¾²>ãìß¾¾–u½À•ܽƢÿ½§†'¾†ƒÆ½Åõ> /E¾¡¬ˆ¾é¼¸½oÙ‡;%Ri½$íH¾£R¿=˜ ¯¾rY=£¢>³T>ú (>{ã긂洽šV¾Z±=ßsï¾Ö×"¾ »§>˜5‡=»;;>½ >d&#<Àæ=õÅî>––ä>,‡¾½¬8b¼K$^¾(¾(bË=ü(„¾¹nÑ=k¾|>„†¥=»‚‡¾–£p>|St>.dh>¸d<l”=õÙŠ=›²×=‘—>·Ÿ>“�½Œ·¾r¬¾¶Öy>Êu1>4D¾D]*¾À:I¾¥É²½ ½-(•¾‡°c>Ÿ�€¾0‚"¾W’é½…‰S¾·|¾Ç¸Œ½&g>ˆÃн4üö=*t¥¾‰+>%Ä=¶Í=,dh>ÒV˜¾–Ÿ½=%ô˽ˆÛ=û€ô½†ãU¾Žš¿ê½½­C‹½›;¾³’¾¯¬�:v¿¥=ø?q>aé#½ &Ì=å'À¾ÃºY¼ÐI’¼!‰¾'Ü¿=Ž:—¾–èÜ>”pU=.Ž4½}c=>&."¾8Ã>yx>…/!>ª½æ‘ž=¶b¾/y¡=Iú>#_>( j>£?0ƒàºîv|½ÚM¾¢©–½Y„¾á ?û²>æ#>Pô¹=,‡=CÈÿ<˜ …¼±$�<®+’>@w¾Õ />²À�¾ìà÷½ÌÄ>îS‰>`] ?«»¸=½-ìA=˜¿�=W÷¾í䂽µF¾®Ì+¾ðQ>Üf&¿3æœ=|ff¾î;¾;ÞH>*‡¡¾’á³¾¬}¾œÎ¾‹«×»°Ä=�d>ܦ´¾ˆ¾¿Hîœ=ä‰p>Ì,À¾ûž›>d©=Ãld½$Ó×=®¡G>/–¾·ÙÖ=t=ZýF¾‚ϼf\¾ _ª=Ð�޾€Ñˆ½¾¼;¾X²>d‹>Bd#>xǽé«>�’>�«>5L‹>Ⱦ¢L©>I›¾¾-Pо œ�>6Û¸=ù=÷…޽Tò\=‘}w¾ñmE½I ;�»>Wñç>R=¾>—·=ëp¾+z®½ŠTB¾´:º»Ï=Ýq‰>XÒî½ö·ž¾Îi;½ØÿÁ¾ó®ð=ï 0>Í"w>vTi>%Í€½ Eˆ=_·µ¾›�«¾Œ¯u¾èlu;ÈÔÛ<©…ƒ½ÌTŽL"¾õ©F=¦m¾Fîz½[¢0>G&û=·;+¾ˆíù=\§1½ùÿ½*Ö¹½Í§š½­ýŠ>&É>_ŽD¾¬I¥>õÌ€=@Ý’>MB¿f“:¾…Ö°>ÛªR;˜‰h¾Zb)¾‘¨½8|¡½³…¾‚´À=A\>òC¿½á C;!s¾VOo<�>j>&×™¼T}¸¼¨#=ÔLt> @ȾLOx=àêz½Ê ß=‡›'¾È™¼‚1½è×">Ú²k¾J¢®~Â(½3v”½+Û°>IÍ=Ñr¾ Œ>œ‰(½ìǽ ÿ ¾k�{¾Ð�L<È8=µó½&1¾¥g§=%• ¾ü;h ?<Ú˜>#H#>�«ä½%Ú>_t(½ò¾%9¸¼]1=ßû…¾(¯a>pé]¾4 Ÿ=trÃ>”ºû¾-쓾uYë=©bó:=% >ˆñ½@‘Œ>d>h¾ä?1Ò²¼³,ƒ>,¢î½}PT>ÕÑ=ò^týØÌ>’Lµ=‹¡È½-7¾o࿽ ¯a>µÚ…>ÿÂ�=MÜð=ìè=›úê;~º?¿Ê'°<“7¿ÿì�>g€Ü¾�!ˆ¾P™t>HÌ’¾ ‡<6ãƒ=@¾·áŒ>5Ø ¾wâí½×5<éï?>ÜÝ<œ›ƒ>Y\ƒ½ë9û=Úiý½~�½Û =‘ëÝ=û׼½ê³¼¹à½�Ã>2 n¾HiÇ=ÿ ã>Ò‡ ?Z‰W¾\Ïe>ü}Ï(t»=6„=Ñ’®=â^=ÛN}=`àX¾m(6=(€ü¾¿t¤»y_>Í À<[C,¾íŽª=Ûg-=@Ÿ¾Š¿¹=«½‡>…4™=Úœï¼FrM¼C“z=ž£>()>ØL8¾@vw>Eò>ˆdŸ>5´›½©Vï= €¥> nž=¤�>Qˆ�¾I¤#¾¯£ï¾óþÈ>*œ¶>;Œ½/f–>Ä\Õ½k =F›L¾_—ò<vž½‰¿?¿ƒ«¾*‰È>ÖRÊ8û>†5R¾¢{=¢S¨<'(0¾ëèX>>$÷¼ZcP½{ø�¾hažî—<Ï^e¾¾@ܾ bn¾�hÚ½8‹§<ôÍ’>›É >בd<ýo‹½¥Ø0¾ªÏŽ>™Ø>€É<,Mƒ¾TD4½‡¦Œ>Ýæ=œ³Ž=�hE>¯8¬=i{2¾tà;> mQ=[ ·¾(—¾¿ž¾Û{_> Š`¾Ëò1½ík¿?"/¾¹ ¾Äë¾ì>Û=íz=Þþ޽3Q£>‹Uµ>µ>ÖøÃ=ëñH> ÑR¾¹p�¾¡­s>ï±¾O¼ÇøÇ=N[x>GÈ='z¾ò™¾ç¾ ;+=ì� ¾ÃÄ;¾I;§=® €9òÌp>ŠçÚ¼o£�>X⯾Üaº>¼Hœ=Hr½Ä´ž= xaºúaR=À]½žf@¾~6»½C¯Õ¾‚”�>Úº=çÐ�½jé¾ CŒ»=R =Eò¾-lö½Žlñ>Õ·Á>cî=« ¼¾C*>†öÎ=¯;½‚lž>…ÖÖ¾”ʾŠÀ>Öµ>®T¾ð#½è3é½â.Û¾z„>ïÎÇ>Q¢‹>ºü…>ÆYŒ¾ù3¼¸N ½ÛÂ>¾ ëPº[ ¿>?áܽÜ'¾Îнv€>¨¦> fv=ì³b>Õ�=•—>¾&f==<ö?Šš¬µôj½$;L=§gj¾l&g>†==äà½;Ï«=P>MI¾¿'6<-µ>ò:I¾B•>ì}o=nAp¾ôƒ¾W ¾¤,å<í£½…\�½G#¼¾ ä½”»¾ž v¾:| ¾½Þ²=¥Ü?•‡Ò< y‹¾xÀ¾kå+¾3my¾�y¾ ‹¿( ¼l\_¾k“C>??/ô>ôiA¼ì.ž¾2�Õ¾³Þ ¾óî̾&É»>S¾Œ´¾á° >Ãa¾ÆH¾9QϾW-ü½%²Ž¾¢l¾ÚÇ ½b6€¾é”E¾�÷a=^2«½­Û>(oæ=„Ÿ=T™¾–eÖ=ˆ‚Ó<„b¾xµ¾º¾³ëÝ=%‰ú>(‘‹¾sW½7B.¾sŒ> K�=÷„å½íçX=ø[j¾õîÁ=©9ð=6û¾cDž=µG¾9™½=¦�#¾4N¢>нF>ý O½Ir¶½´È}¾H‚G>²ªÝ>èÕA½yað=¡<�=íyE¾g3>Ý æ>(çè>–>««f¾°=b†v=«ðû=Æœš¼g"½wâ½ü´x½ÿ«†=­‚3¾-~½ò ‡>^b~>ñ~°=@³>¡´ƒ>%øË8›ÕÁ¾ö—ƒ<üi½žŠŸ¼ Îä½x¹‡>ËwÛ>á ¾ê�º‘>^¨T¾8á¬>{òì¾}cɼýñÉ>à5‹>��;n…œ>„™ >¨Ü…>zw½ȳ°¾Kâ�;mn¾sîx½ÿ|<<#u¾S �=øpÏ=‚°½f±ø½Ã¹s>°Ë ½b7=ÞG½?Q,=¡=>¯ø”>ÇZç=¤o‡>,µ =ô¢¾Pà[>FA·½¨—†;™î ={¾Ï=žJœ¾ÇN¾V)×<¸�ܾÀP>Ç�³=%¤½Cp>ƒp¹¾Ü0ð¼®��¾`ÌX½ò>]¥Ô=­ §½€@ ½‚ <É»<]£�>÷8r>5{.¾";S=úZU½¶À“½m>ÙÙ<Ê’²¾/g>Ê|˜=×u‚½-¨I>Äpü½GH¥>ÿãc½Ïì}¾0Mô½N=$?N!?]!>´½Ÿ¾ ”d>§ ³¾ãâÅ=i ¾SŒ¾v7Ù>^Û½ò‚>  ?j�‰¾*~º½ë=†Ëj='S½t ®¾¸Š?#»¾^�Z>'½N¼?ªÊ¾ ñ�¾ö½…ä�=½>"ž�=‰G=ó%á½Â0æ;?N>�…<Ûè–½ܧ¾Ì{¾Åè½½ª!=gÿ–½¼lž¾´§=FQ¾#º>‰eI>—¦½Šµ?a?½@Õ;¯FÌ=ªuh>×Á4¾�¶¾FÍt¾æP-¾¤Š—>@”J>3$¾fD> p�>¸]>‹@ò=GW€½1—½— ?…G*¾îMƒ¾-ýF>|«Ö½WŒ³¼Ë•4¾�°�=äLš¾¾²–½«l¹½×àô¼žÛ?°ö=òÙǽu D<‘Æ/>õÁ\¾{‘>^_L=€a!¿Þj¾>ðæ > j;>êÀˆ¾¸I½ÁµF>TÔ?½…¡<<óxœ½GB>wÒ8½;ï>œ°Ñ¾�lg¾5z¯½yp">ס†>=)“<¤$k<„HX¾õq">vq÷=8¿dY>n‰D½ ¡½˜=®>•9½vÙn=³£>Ü`i¾"!|¾¢MͽÎf–¾T“‡>\=ànl> ©½V‰®>¬&y¾mÈh¾vŸ´½/== ãA¾C®½~ï'>&v½�§©>ú‡û¾ÕÞ">^/¸>Þi¤=¯FŸ¾‚�†¾Šô_½K&нüÛ= w=G5>ñU>Ý­=—h?ûi¿½\Ö¾>¾½Å<|«¡>2ðS¼'h¾¤·”¼î›»wS[>§:F>³P>T«»=Hð•¾e“B>/Dp½M²´¾JW•¾\¡­<43¬½ ú ¾v™à<«N¯½+´ñ½ò“¼2Y"½ã]+>#—¾(I>äÞ½÷LÍ=eUœ¾È“Î=‡Õ>P"ñ=8[•¾{0�¼_:ˆ½¢"¾¶¨;¬´ºZ¹:>n±e¾¡åÆhÉ>SÖ=Ë8>=ž{½/.¢=ù ¥=�nºù°�¼#xS>Ü6½SUù½Úv;¾ûŒ¾à<ß½-7¾Ú<¼D´Ê=2^1½zC¤¾Œ 転 @>ØU‰¾æf›½)¹”½Dýï½p*>ti½ÐG=QÌ3»æ&>G¸4>öaÇ=µâÔ<è’¶>ÌxÏ>dú•¾�þ⽘ÞC¾’|0<·gm¾e‡•¾1 O> ©á¾Ô¿¼ly½ä±°=õ‚¨½Ü³9¾Ô(ì=$B7½š„¦¾ç…>½<áØÛ>Ö–>ÎÇ<*'¾œɽ(?b¾Í-¼>oþf¾|[ê=j(ƒ¾(X¾¹Ä.>Ê.Œ¾;(=ŸHd¾i±¿�"Ó¾’óU;|Ð+?.i->–ͽë‚Z¾½†=ˆ�>*¬¿>ÿ›É>ô¯¾±·Í¾ij>Huî=õ{Â>’¾y�½B¹e>ÑEí¼‡»Á¾¤>·ri¾b;¾wù_¼¸+ñ=ýt>LùI?®öï>éŸÜ¼üK¾©S‘>0{r½Áÿµ½Cœ½x«x½¹ÔK>jCȾA=¢½šân¾a—¾×²º>c®> ½C¾s¼8½ÞrK>à6½¶><—>OAc>ë†E>öÇF¾†þØ=‹O£>2 ˆ=�6¾Nßà=á=Ä È½2ï=Ko´>öÙ\=Ÿ~¾ãÿ>ðþ¼õ�Ï»pÜ >úÆv¼ÅŸ>T󄾌 A¾¥Ÿž>8ñ=!-">·¾bœÅ½5"8>$Œÿ½¬ð�>‰ ¾*ä>m%=‰mß=z@P=˜þJ¾—û.> �5¾iå?dûø>�T«½TÁ]¾®ò>M†¾´©¼‡¦…¾åÍ,¼yj½Ç9¾¾Q,„¾q^Ê;mSà<Ö´î½Çîð=\÷Ï=š:1>jîR=G…>}Ó>ÌZ½R2`¾…?p½/¦m>é�¾¿†Â¾¢C3½È9 ;Oì)¾«E›½~Ð%»58o>eF¾¿–r½ºv«=d¤>˜ëA>Ï•Â>ÇŠq¾'ô>x§¾í�U¾Y–> îh¾fE¾ñq�>©�=¿Ñn>}.^¾.ªó;p½ªÓ�=ð©-¾1¡¾Ù¹R¾ižÇ=¬þÖ=¶[.¾[((½²ðy=ö†> �¿=¹“¦½6¾e”¾Í=¸=¦ë¾y_¼‚3?>»ô¤¾®>¦¼ŠÖ½!­>=fÿï¼&W¾ ‹…¾ÿßn<Å)\¾I>†œ0½ $õ;Øø½P—=t~ï=5¿ ;è¾å‚>†Ž=X§¾.ûâ=�¾Æ=@ßç½µ5)>ðÛ>¶y<¾R†Œ>µ%R¾Ðz½�/¾Æ)¾=jР¾JÎõ¾„=çL¾¨ÁÞ=¬Z>8ó¿=Dƒd>^ x=ßy<È/ñ=™"½‹p3¾št¾_è¾»ù>¾WÛy¼¼Õª½£Ó3>=}¾^'¼»�t=®áÐ=ùk¾"¿¥=ïàú½¸Ñ>Áì*>áU¾ëÐͽøø=ºö¼�„?¶/>Pvu¾¼£ì½ ²½ :º=d_>JG>Ì•¾¼=•9¢=é¢O¼W=ß§½ÄŽ>Þ{?äD¤>¿ýâ½kо«Ú¾n5[¾JÍ’>¢äý;½ “>Ä‘v=ô%Œ=uñŸ=›’t¾±¾L5>¡y¯>�Qd¾=‚´¾¼ÍͽÕ±=€½ÞÞE¾¢.P<Öw&>2Úú½ê߼{ö>Cš>Ãþ>Ud¾Kÿ»=")¦½e’¾FëS>~ó>Ùš ½Ø¯œ¾ˆ˜ï; Ž„½zïS=a¼•>¬µ0=—û >¶lD>¥�«=Sb¨=û×]¼Ÿ¾»>j¢’=o•“¾9»D62<�A >TZ/>y ,>ÇÍ)=¶^ˆ=×ï<ØãC½ÊˆR¼âÏ-=Ñq½•¯Éñ1R>ýÑͼV‡=ÔàE¾'B>½zy˽u^m½l…3¿¼š,¾´_+>’Ÿ›>‰z&=´„ >ˆÍ›¾N›¾ñfö=ìëž¾è:ü½a„ ¾öºÜ¾:›>>¯4Ÿ¾ˆ}>éï…<ë~D¾ƒqŸ½Þmk½Üc¾>Ò=¯W=d¬u>ÊE>â+™¾æßª¾¥ A>a@•>ߟ¾u‘¦½WA®=?Ëe>ÍFm>lí^>!¯W<ÁLU<à=/R�>`뾊y>Ô3?¾…•>,Õz=!¾—6{¾ª«®=�íZ¾eTÿ<­`Ÿ½H˜¾ì�ÑÈ\¾„á¾?L¾»˜ø=Îǘ¾v}¾¯PÞ¾ÏP<&•¶½=(I¾Þ�U=\gʾ¤Ií=¶ßy>­­<ò>~%­¾°8ü=ŸÜ¾¶õÈ»ZžÊ½Å:<½'�O>çc>¾á†Æ>\Z¾N‡Ê½Ã¾œR<ée³¼£¥d¾ÒSc>nn¿œQ�›¾¨�µ½Ë¨>Š\¿†%¾½Ý�b>ÊS<>æ¾ñ™=K¨x>hÑ ¾Rq¾±b�¾þÚ¾v >�+œ>� >I… ¾Ì4§>á¦.¾7vN½’ >tÌ.>ïÖÛ<)¯>ê >iÑͽíÀñ=ñºD½Gݤ=‹½½-á/¾Äú½Vf‘½�œ=ù©û½g%m>…m¨½€ª´½ôÎæ>µYÙ½ûÿ=ú½|_î¼óC—>Kxú=ónÈ=OñȽÕës½W9d¾¨ÿ†=æI=ÉqÙ=c ¾åœÁ¾ëÏÂ<©,>»�5=0Hܽca½5Œ¾òE„¾W€*>H"Z½ã·=Z½x!R>Äí½¯>a>·ì=�$T½cW¼¾Ü¾öÀ­>¢Ý=uÒä<³X›<Íâj>hm >ðÆ&>Ë=g¾öv7¾¥*Ë>>ƒÖ>c>y|¼½1ÙV½<äø½Îè¼¾å~b>…œ>‹ÃǾó}å=®F<{Fâ=�+¹=W¨N¾Ô¼÷>ÌOœ=ñ²h>ê_.½q•’½LE.¾«q>Ì Ó½huw¾ÿ¼¸›þɾµ>ö²(½þü!¾W8ýæ—P>qb˜½m=>Iħ½Žu×¼t…€<�é°=Ÿ!¾¡]>­L¾›Á½}B¼¼ç‰U=_¯¹½YÎæ=×x> ØD¾�S̼g=¾£J5¾ž¼`j“¾zþ¾ª¯‚¾=13=ˆWN¾}GN>Á_¾9òé½Ç†™<”d콞\=F^¾&Ÿû=Ì^>¯ýؽ„‘•>&¯u¾><3>áHÉ<ÿZÆ=á²ã;¤(¸»[ñ½ËL>>²+Þ<Ù]½ã¥�=šN¾³…œ=Êf¬¼óP®½7�•=‰žÎ=ŠB”¾¹�½À:e<^ ®=IÆæ½ ­=°ó@¾hÅÍ=mF¾‰‘¾~8 ½b\¾/çc¾ ³‰¾…¤E¾�Pm;“àì>:ü½þPð=KG¾FL½4’¾åZQ>ûè~¾Z µ½Ò`Ô>ÿ² »Ê…T=nèI=ë>™Íß½^í'¾'¾Ž<> ̆¾Tp°=ì8{¼)Þ‘>"”>­Y§½3š¾G€É¼L>”[=fw´¾'ZÑ=«@�=mù½¢ÊC½>ƒB¾ŒIœ=ú•ž>í|6=^ø‡¼¸g+¼ÌiÀ>fŒ¾·¾I²?¾H”$¼èȳ¾7nl½[1='©!½Ã˜>剨<O辡®Œ¾-Ú¾²(㽜(>lR‹=°£ƒ>Štv¾6^³¾G;>'â¾=³·Ã>ªG>£>¨¬=ÚÅÀ½Fñà½�N ¾¼Ù=F%³¼nš=x÷„>ñf‹¾š1 ¾ÉÞŽ=ðžÛ¾Þ�>¢XÅ>ê—’>¤Òù½ƒl¾[º)>˜¥ð=�¥->ŽS%½X2*>«§¼h¸}¾¥Û\¾•ì<ú¯¾²K¬=Š{¡½ÑÏ|½t>›x>ÍÚN>H×S¾ÿ޽´Ó‰>ûü=ĉ>"¡×½«¡h¾�Pa¾J¾·k¾s£¤½ÁkR>òP>½‘#=bbû=™L>™v„¾M^í=«çã<@ø1>‹['>ãïh½½ê >Éά½sO£>ÊN4¾ž-B¾Z¬=ðÁÏ>àŠ=µ}G>9A½Üø½ØÎž<±�ƒ½ÐöO=ÙŒ>…lb¾ 0Ë>½éã=6¥­¾«¬*>Ž…|½ãMU<·ÓÃ<Ë‘‚º�õc¾PÁc¾„ïŠ=¼–w>hÅÞ¾;P$¾ÎŽ)¾¦Yª¾>È=+`b¾àˆ¿½üĨ¼ï“·>\²z=?ÛV¾‰-¾1Ôd¼ôØ´¾9~>\P=_;¾M­>%n¾=€0ê>ç#¬¾æ'‹<  ‘¼Ï Ý>'î/>>´=”ذ>†U¾›=H½NqÞ>Åߨ½–�‡½3 Ͼ]ož>ï4½†î¼âÜ©>¤d¾÷�>Ɔ Àê£=–‹j>õ{¾çi>/c¿>ì(H>;½½>ªÆ9¾&ý»½m›¾+~¾7r½=3õþ½¬L>§st¾qv�¾�¥m¾0 Ø>°¡Á> ‹Ò>_ò½sÚt>¥P>¿Ô½¾?¤)<‘[j¾Ø¢>°>¢½LÕF¾Äbоd.û½sÓ<*©={0#¼Åêö»õGŒ=Ý|u>—:ü½°Å>Ñ ô½Kÿ;>­\'½ð¾V [ºDwĽSü^¾|¡8>�‰“¾ :‹=¸ê¼¦ƒ ¿çÓß;Ÿó™=“$¾>¬£k½ýFk¾[[¹¾Zµ¾äü\>]µž½ >”°=:�Ò=Ù2¼Ã3¾žï§=¯c>õäY>U¨–¾Jü>Á¦Ÿ¼2Þ=å³Ç=áø<€„®½¿9¼¿¡Å½|¾DGœ>xæ5>)g£½ê¦=å=­‡Š>‰;¾òN¾6�ç>3Ÿá<à!>ø)?ƒ¾¤r¾L‘Ê=“‹„>æ2Y¾IÆ=ÿ@¾í+>­î€¾)Z=S(ì½YÔ�>Ñ¢>�r?:�¾�ØÖ=á#-¾€wÚ='³B¾ q3;_Ú\=Æ£»� ·<ƒß ; Î=¤ôí½Ë}¾ç°=ú6½#–%>²wF¾]o`¾ÕV¾UƒÛ¾2>€Ö–¾ÌwO=¼Aµ½Ha<¤[¾°›J>n]½ ³3¾½ì(¾ß =ýVþ=ZÕ<=¯Õ«>kbž½ü|é<ÓJ >¸�‰½„]˼‹PÁ¾¤>Ž·?«¾íų=SÔ >*±>EŸª¾Ú…¾�¤>ÐG¾²} >¢Ù¿Æ–H=ż=bŽZ½F7½¸ê¸<œ}c¾´o¯¾¹”½ŠÎz>øq„<Ý»¾UÆ“>þÐ&¾I[>�O¾ƒŠ`=į >ôœ=ýã!>÷7Î=g£>�´B¾l¶§>*‹=µ½+¥`=2-d>^`:uâ¾D� ¾â§š>†Âg>zBa<ÐK;¼Üü¾…úû»§[k¾¼¤>L7—>uS—¾)˜�<‡Ç½Ô ˆ=Æx¾ÈÏÊ=d±!>d³à½ábŽt)Ľ�ê±=6—‹<Çé½U‹¾¡¥›¾Îª�>±å§>^°>ko=×ÉV=hL=¶!">;ÔÚ<º^̼Žlž÷ux»è•°½h6>hŽ=æ°>¬�¾‹D9>ßZ¾£d‹>Œ¦à¾Ø+¾íBn>«·e=@žÚ¾;×1¾¶)¡¾À>{¢�>D}ò<5Å`¾Õ¸1¾Dé<ǧT=ìbœ=£üÿ½ož=¥ª¾€)>„+>r¿º^ÖÎ>®o”=^Dh¾ƒáá=•Iñ¾t‡²=Ê§Ž»wü»½Né¢>o•?qW>bŠÎ=±#Ö>Я¾ ¾'¾Å/¾{À=¢{œ=™ïA¾÷¶ž>S;ͽ”>Ñ,ãG8=Ì >$`†>81¾Ø³½ï—e>ksª>Å·b;¬“>Q�=¶ÆW¾W÷­>ôÕQ¾î&½É:¾óÙ>¤$¢=§ê„=ºK¾Ý€>çÏ=£ãD>ƒÙ“<‡Z>eä¼×’e¾î*=~y¸½Õ£4= #¾ùZ�¾u*‚½’%ˆ½ß1¾™;6>.; ¾c ¾Ó° ¾Ò½ú>>bž>‡ó/¾Æ«ö½‡én>y%¾3K¬=íš¾5> ËB¾Bl‹¾Dªè=AÏ�=Ì>»=Úc>^—ð;[Œ?¾È-Ý>B¡>q7>>±=Š=£¼[§ôÁ½ú�½ëûä>¨ön<” f½j,>DU†>÷0€>Þ;½}À¾Í¸¾Ø™½›l(¾Ê¨¾/¬¯=Ñ'f<ŒWí½ñ´ ½‹‡À=Šü{>Ö½W¾?¿*ž>¾“=–+c¾}šÔ¾y ô<Ê€¾Ë–>š¸9>•L7½X%«½ƒ7¾xf=¦²�>ˆ ¸¾4Ž›/è½e ¿Å§R<& h¼*=r,>ÁÙ‚=*N™>xe<ºZ›=r3b>r{|¾Uâ;Œæ';÷øI>gAÒ¾ƒ®î=3™-¾½0"½ùú>¢5 ½tDKù=×\¾o©h½´;Œý¼�˜ ¾e�¾¿Ö¶»Iúí½áÇ:>Óþ?¾¾‹ù=³™?ù‹j¾J Š>ß<¾K¡¾g&Ü`:©¾f˜>‡·s;�µØ½¸Õz=kƒ<Ðúo>6€>‡Ó”>” ;Êâ]9熾ŒK¤¾Õœ>I ¾€¢½tʘ¾ûÔ<Ñ‚H> Þ=¯>c–=Ý6¿œ0À>}‰>âú¾=•†&¾Ë×Í=J>â=:®=&ŒÆ¼µjí<½nã½t,¾}0=I‹t½ªMà=ºƒ¾g̼Ü¡=R¾Ú6’½ç 2>»&B>®j>J Ä=Ëà)¾Èn¶º×˜¿¾N&> Å>.ìY>ÐC¶=.I!=àúg=Ô´S¾-õŸ½¥¾bÚÆ=­Ï>¢á¥é¾Ô“;¾† “¾{â'=Y%¾–y½½&$Ú<äj> 1,½JC¾­ù¢>,g#=qò¾ ³¦>tzÿ¾ò£½]l> >¸AÏ=¶œ{>A¿z>a0 >�œ=±åѼV]¾íÖ>µ {>a @=ÎÛ<áh�¾:¥à>Q¾P‹¾3´½BLV¾ô>Ú‹>BK1>ºq¼èPÃ=U\¾=ÊM>ÿ(‘º¼A¾±z2>�¬P½0 @¾Ÿ6W¾p̃=‚Üœ>ÿ¿·R>t Ã=½QT=o(¾˜Øƒ¾MºÑ½ÂFž¾�ý‹>[n¾[ªó½¶¸Ÿ>É­²¸wVu>ô‡[¾ *¾0èi¾t~ ½¥ ¾ðGù½ £-=™V>ÛÃ>€A�¾ D�>|c‡½(Ú½Žô´=lîÂ=3"´½Z+>D°=!:Ù=ÞÔ >†ms½ ¦½ Ї=2’=à ¤=z´¼V­å<°×¾ûø>ÏÜ©=¤Ç·<€}²¼ñÚ=tI¾+ß󽨏»ó¦Z=SÞ=� A>Dƒà=9„Q=~Y =^µT¾Zà�¾à+,¾è°C=SØÝ¼Aö¾H„¾¢�>½>ŽK¾=¨›¼±¿d¾¤ú¼<çX?>ÞL¾Ìë#¾€¬™½›Z>„¾K¾Š½Uä¾¼¾…½+ôÝ=Ÿ^½*Œ>q'p>ȹz>PX½X�˜>ç">á0t<îW\>Žàº½˜ãj¾‚šU>Ù_+=ÓQ›¾›^½D�û…=•},¾Î—+¾ó6:=»šû½RË>ž™¢½D>9÷ž¾¡C>Ò| ¾µº¾¼Jò;¿T+¾L<Ÿ>Îñã½|•>lð÷½)~½ˆ¨>ó2)¾&¢>Y�>œr‚>Š­£½2.º<¦7\¾Ô�">¬ìò=ûÑ©½Ž#Œ>uYâ=tÅT½Ô-—½ˆ1;€ì¿>’"k¾mð¾W�#> ú ¾$Fi½Š¬�¾Žšš½ ž˜=ð:¾¢�+¾æ²·½y|Ì=Q?>u¸P½Itî=Õ½½oæ¯>èM\½ Þ´=Gñ½=éÒ7½i¶Î¾‘Ÿ>WZ™¾aáá;M33¾Öø¡> ¿Æ>t8>±¿=Îx5=˜>­{Ͼ¡ˆü¼$µ’>O>º=OK>6ï.>Þ>ÊgH¾T�¾ð&Ô½L‚>='7ˆ½b *=‘e'½ËKš>[>å²>ó‹¾àŠ0=¿ÜÓ<R¾¼9²½¡Z3¾¼Ú…>÷¨i¾'Ò‰½ôû}½Â»­>zH™=P‘e>o¡½XRµ=„d¹=9¸Å>ˆô¾ë l¾²ˆ>e"6=Z‘¾jŸ†½;°0<Û¨ý=7†~¾¦Lºõd½¾h·>Á¾º“=xf[½®QB>)ÃÕ=o}½³ç">M—À½�½�ty>öG›>-Âó½0I>ؤ=œs½A_"=Ïš¾!�¾×di¾Êá½YaÙ¾³^y:æ¿…¡¾Ò•É>TÆ.¾º~ü<ýÂ7¾‡>fÂ>ó ->Bß½I;u=/™¾�P¾X>¬—F=°�y=qý¼Möl>3Û=´¹¾o;N>4\Z¾RÞ"¾d‘W¾b“Æ=ý�=È ò½âÀá=âüǽß"å¾õø½¡‡¥¼ªúî ^0¾ G½¢~“>íz´<¨t>Q >UuB½äø¼-Øï=,6¶½<¨½åŠN< °>ï*;5šà½KªØ¼Dêp>z6¾ƒ—M¾}å—½$&L¾c>Í›™¼Ù2E¾€è5>GìÁ¼m;“=bÛ%¾Åž½P¡¬½ ³<å½£;’½Ã´Š½>ך>$†>.[=½Ò–¾d‰^>Á¶=™ÓP=»·ÿ¸`¿$½°Þ‰>[Ù>uê =%+¡>bò½DMš>ykÔ=ðTŠ»ß�>�Â>›&¾Ç ¾÷Wœ¾6]¾Cƒ>„„¢=ñ#>¹-N½^V¾H�»½Oº‡>`¯Í>Þ3#>Xè–¾ÅÌ…½MJX½Jµ=>á_>åWµ<>±B;Œœ>w³£½•¿k¾ÅýI¾w¿T½n㊼‰ Ç=Ÿ>¤f^>:x ¾ƒ¼+>”0™=ýY=˜'©½”‹>Ú-Q>`C¾´�½èJ=ÞÚ0¼ó=l{%½®o•>%õþD¥I>Õǽtà¡¼ÍÆ�¾·Ä¼:!Ó½ªE}>‰²=.0¤½X ¼;K°=ÏiÕ¼�ôK=rŸ¾ÚR ¾nòõ<�,K¼¹üË»ˆa�>�È"½�½=Z‚¾,E¾Ù}�<Їw»(ðO>Ïw=‰›B=Á½Ù:Ý…¹¾¹žo>ëÉ5¾›¶ >�\=F�Á¼ùÐ3¾–®B<õŸV¾·L½l9\>/Ëâ½§í{>]sÊ=󇼰"¾-Xß½¹4F¾¯JÀ=x9Ÿ>Ô* ¾c›¼¾ÒÄs—€½Fã<ã“>-d&¾DŸÎ½3–æ½?#=Ó4\=d@%½mÏ`¾"Ûß¾  ‹>¹*—>“Kí=ÿD7¾•>0¾ w ½þåk½SV”¾à÷> W½a‘M¾õ;Yð–>vr]½'K]>œ ³=-m=/Ot> 7é¼Y¿=¼{Ã�¾è C>í¦=¯ç­=�QR<@޾MU>2X°¼õ^‰¾[ä’½Ó­›>y¾o¾uG‚=iÛ�¾�Õ„>(Õž½2Çì<¢–�¾Í×í½žï¾ q¾¹�=~ÙT¾ üs¾°-=�jY¾©…á½Þ4×:Oÿ—¾Çê’¾°�U>àV‚=Ú®”½=£=¾7 [>üξ=³M°¾®Ü�>ätÿ=ðx>N˱>}™„=jÝ}¼Íã\½ûG¾2’ª>ï6*>¦š<ì1¥¾’>�¾MO¾È„‰>g ž<«E½ìŠi¼ôP½a›½½B#v¾Ôˆñ[½9½À�¦¾p§ô½´v€½Í|n¾ý[ ;8g=-̆>¯õ཯¾ >LЧ>mæ¾ÔÜ>ô=Oq9=›’!¾��R=Àâ�>F�¥>a‚¾yƒ >ªI"¾ôÜW>¶÷½i�<Âq¨½õ=Etü½ñô½C€í=kéq< ¿ªžµ¾Ý~¬>£k\>Ðvy>ÞA<»^?Ë.>§²= ð»>›»a¾TÞѽø�K>W%¾ŽÂɽ³2”¾Ç/>�Û=ë¦7¾Í.>‰³–>æOß>@¼a@¾\Ô¾£³>'`;¹Ø0¾Ê�=“q¾º1=OÎm¾ É~<Ö“ž>/‹i½³ æ½Z:½¸”=ü'¾“ä–¾«²�=ó˜³=+ŽG¾õ><=%=½4Zä¾6c�¾•oT>ó 8>‚Q½t>¥Sõ=§QI>rÅ“¾AN[¼. ¾ñ ¨=¿V¬>ÒƒÕ½\œ½•ñ¿‘�½Ï <ç >¤¾XãB¾ÚÞ½Uõ¾}�>šOt½â¶]½5à9¾ÏJĽ&: >’©ñ¾kƒ>Ÿ5”½:ä|¾ÕRD¾„l]= Ϲ¾ÿŸ="’/¾Jã<áÃg>tº½-¾=ÚEg>L.>¸‰¼¾u+㽈í=x .=AÄq¼@ôu=ŠÅ“> ¾jkž¾—γ¾N¾x=6B®=P è½Ð�o½]œ½¸½¾ð"›½c«½#±•¼0Ì=½¦r¾0Ö¾wö¼\�F>åbâ=ìk‡¾[S=YX#<.¢§=ÔL­>ìDí»Üá½ XϽMª}¾vÓk>Dz½»<©º<3@-¾iÃ.=OU¾”Kf¾K½ž=}w ¾ô>©¥Ï=Õ¤�¼8ÃÖ½s9n;Zm¼;´Í“>Z“j Œõ½"ª`½]ÕA¾æ½ôã=¯Œ¾: «¾võ½Ó•¾í6 ½4nÕ½sN>>’Ó½‘îR½¡ú¥½&$Ì=ˆa< GE¾$œd¾$Æ�>îÔ{¾Ê +>Ñ…p¾ª‚A¾ñ…Ù½Dý7¾²†>ñó >s˜¾cö >^œ>Îz?=0ä]>‹>º5K=,ÙÉ>,Oå½Gj³;>ob>ª¹Í½à T¾„¾ÓÎ9‚Ç£<Ü>…�=ƒ–:>T‰š=W€“½½8D>»î%>`vÏ=fð‹>,o�ºí>Á/½å:¾C˾>›‰>…Xz=±™>U ¾6,"¾)†ê½lп<ù+>r‘¥¾–¸±>ÜŒ¼hB¡=}†':&+%¾Hôð½¹XW¾‰`­¼&Ÿ$>`n$¾!>?Ig¼=ñJ>Ý=;åŽ>«¿ †*>7¾ 2ó=¯Î ¾ðö)½m„m>&=�¾<+¾Þ.=Ÿò >4W¿<Ô ü=8b>U>¾ _̼ŽÏ>·*¼¬¡o>¿j�=g[¾ck3¾ð¡º>›h„=Þy¦½¹sH=õÜ=ƒD¿ž¶>Ñ“>­Ád½Ù^ > ¹}=N6é<õVŽ>Cðp½‚G>í8Á>„Ò5¾"tY¾Ñ€¾Ìu¾|P�¾HÛ4½/‘¼…sz>âb¾>›–½[ >e<¨¼Àc>‡ƒ˜=-$>c¯½†³Œ;’P#>™ž >¦±ö½a ¾>nö¾Ú>6«r½vÃh¾5)¡=]'>™„Ç;¾i!>è]B¼íåD=šúä=D>=NdÄ=}ç–=®@u¾ ãx¾ª£Æ½jrq>³�ˆ¾ÏY<©Æ>Òô1¾©¾ë�Î>‡ÂI½Â\9¾¶�>Å¡.¾L>°¾h±”¾£¹Õ¾�±>C~Ib> >î8©Etº«+¼®V>;ZK’>À†¼�r ¾"±ƒ>œTI¾™ >!d¿(°¾c"É>�½=A΂½Z$S>çv>}bf¾‰ø=´Oi>M >‰ }>TᆽÄç¾¼<ç]¾èÞ½µ�=º1_=V£>Õ­>FÅm=;½r#>¾<œ¾Á,>±¬Ü=X±“=Ù >H7C>¡¾N¬Ü½‚Šü=k==Ê·=Wcv>¬¨º=ci >o~¾½½/½z�¾òn彺@¼øö#>”’ð¼*æ¾Ò ½ÿ…>+[¾³û¾R5>{¶Í>Ê z½æ(¾CïA>0CÛ=TøÀ½�¾˜¸:=¹ö<èx¾íÈ ¾¤ö–½q&L¾çÔ ¾'¶6½ Ýó=RøA¾ÜGu:6üÁ½÷kâ»?!>,ˆ/¾.�Ù¾n�¾ž˜ð½ðJ‡>B$Wº~q{¾wãÒ<7Xú½C1¾`²4;ÔL½Ÿ+]¾hм=§�”=ûG¾µ@=há!>š* ?Ö°»’û=yMŸ½ôÊ+>Q?£=è¸>¹8¾>01<ûì=ö»]=¯êê<[B#>Åõ½ÿl¾Ôо^µC=‰ŸŒ=±ž=ê*ƒ¾',£=²�§¾ Pˆ-‚N>E8>鯑½[É ¼/Þ·¾ë�P½ò?Í´ä½>é¾hbÕ¾=¦_ƒ>»lâ;fßý½�VG>¹O½J$Î=©ôä<‹r½°ƒ¾ ¾%¡X¾¸2D¼œ!j¾q—v>~;á=kÏ>dz|>Ïó•¾þ²¾‹0î=µ­%¼WA<½WûʽiÜã=™Ú¹¼ÆH‹=Ä�»Ôþ�¾¸Â`>‘ª¾=Ò’>ÉÒ½Ägº<™�-¾Ê޾�ûÃ>Ñ–2½Ïµ>2ƒ > Í =5Ûo>˜+£¾ãØ?>–\&>° ‰¼‰‚½=Nð�>î=<" ¾>ê�»[n>!Ì�=ùü™¾œ¸;àà½Ä ¾^ >>´j¾óŽE¾3Õ�¾ƒÆ^>Åb½¢µÄ½äC>¿˜¾H8Ï>C.×½&\†=a•š=Yyð½I< —>y6ƒ=Yà½|”>ÅÒ“= í§¾ž?9=HO¾:Ü»?Ù8½›6½�É®½Ô�c=¶Å½¦$½ �>ÙÊ>>/§A>ˆé_¾|ù§½>M‡>Ÿç.>^}c¾?´#½Y¾�>V¯g½Z>U³X¾ì0…¾ä;Ô½íŒ>Tš”°=¥½ 3(¾aû)>Hb¾ŒŽª½FTÄ=.�>Štè=`>+D²=Ì­^¼ÕN=n¾Ì÷=½ùÂåÖj>½ø¾Ò%¾!Ôª½S*ß=з=¦ê>ä°³½sG,¾ˆ�>\úã=Â(•<Ãr><“7½ð[˾E™�¾c}L=9e=™…=W¾�î)¾^];k³ö=¼FJ¾·I> üî½~ÛQ=5›–=ìz¢¾ÚD¾"Ã'¾ÌJǾâ >fþL¾®T¾+¹=(™Ö>n_ >'ík¾0qñ=†—z½™Äm>¬ˆ=¤+¾~Þ=ò0á=jÀ>Ié="˜=þâ‹=ײҽlu‡½Z�¾�1¾¯šÍ=í*?¾”öÁ=ÐQN;¿;�<~ò¾߉>õBÁ»¯Å¤B°„¼òu�\Í=Q^|¾ú^i¾Lœ>P\>�Sc>æÇ=>ð‰Û½6Y«=ê>ѽ 郾@¾>üD¼$‰„>øŒ�¾Bor¾>äQ>sê½6(>.ÉX>˜HÆ>Ášh»¼y]>¼´=ì=ô=û*$¼”âºól€=c€#¾9xå:Zõ"¾üꣾŠê‚¾#½W½ô÷ö½F½Æ¼š¦£º¨¡Ï½ X>æ‚Y=÷û+¾µ”>Âm‰>ãªx¾)”©=HÑn¾ E¾Ð�2=å´X>`«_½˜Í¿½Ð3>"?ä½ ‚;¼•f®¼V^¾¤Hà¾Ë­ö½Yµ5=dgǽ ºo½É´!½Mt=ò~¯¾¹”g¾Óf¾zô€¾P>¶o§<7?>dÒ§½j:0=ˆâï»fm >;QŸ¾n­½&ó¾üK%>^Ýp>V:é½§¨1¾°˜)¾ô6¾d�½†Èù½KgU>çD,¾›ö½«œ†>FvÛy¡~fn¾Bž;ô�¨>:ú>R…a>Ÿ§¾‡qS½‚I¾A6®<ñõ�>Š‹3¾Þ·Œ½‘À#>ìù÷>~¡-¾~3¾ìln¾:³»É'!=ˆnó<¯2ó<¼t>,B̾姽Uׯ½;�>,L›¾œŠ�>q­Î=òfà>å�Ž>š >^·=TÔ¿I»v¾†Jä>U„â<îÛ>¯å=¯N½\°Æ=8è¼?c>5Ç#>Ô¸ ¾M—½‹âž=� @½…ls==`’½Ä&;=p‘=Ñ7©<,‘¾Ý�¾ì¾îmѽ Ok¾e]>ä\2>ùœ¶¾L“§=e€7¾+–~½�<ÿ=Å]‰Ä\ð=`=�>͇±¼<ßæ½_?>س(¾½bÀ½Àa»>)ök>Ê.U>Á€.=Œ‡"=]½>£Äþ;f˜S¼Íæ²=ò“Œ½¢s”=ê¡g>¾˜Ë=Ã~‡=t„½‰ ¨>~®ó½h¾µ>V%R½`z4½øë<¾áw¾Ä̽­Áa¼²8æ<ÙÚP>ȼ =°ÄL>%Ln»¶Ù¾N¯³=CA–=v –=Æò;WæC»Ü¬ö=äS]=ê<£¾:îмoà;>Vžè=;Ž>*œ>Š­ =&$�¾Dl=9·¾ •¬=u€¾Sšx¼¶Ï$¾ BÂ=©‰ >Ð)°¼w®0¾çô=àF¾~=6½¦ã°>ðªõ½"�&¾�[œ¾Ñ®ê¾­ö+¼ÿ:T>žìP=e“6=œͽԘ“=ÿáU>L…>~쑼6•|>m÷>rÕ¾•r<É&=~uŽ?[Æ»¯Yu>}Ñ;=ŸíG<òýL>DM&¾ùåê½vs½{O=Ö˜½C¿�¾úàÕ= E©½Q)8>ŒP ½Ÿ^ª>òáù=ýl'½ÏÏ=¼0¾2ľb=uö¾•Be½�ÈɽLl<¾-œ½Ðõ¾C% =)Õï=D=³^¾;ÿ½…�-¾ 𿽊PX=XÔ¼éË„¾œ+P¹úÙ�>x³–¼ðÊI=¹æ£¼Qgb¾;Ô®=£[R>,9f>UCí½�ðr>¯–¶½B½ZT&>,¾Ñ>TÎ >�¥>eÿÄ=!�¼¿Hî=§†—½ÃA¦½cId>o�¾ä2L¾”¾ãù¯»òYþ¼öt©¾W…S¾@sN=tú?ƒ»==D¾õ‡¾ñ㉾i²ç½i»y>N�U½)½ë > &ˆ½ؾÒGª>œ% >`‡…=€>ð ¦=|¡„>ËáÝ=&• ½ä->»|…¾|“ð½F• ½;Ò>f½)±g¾D½”»i‹Ö;“C©Š‹¾‡ •¼'$œSß•>JnŽ=¶ÿ>v?!¾Þ9‘½nê>}绾kF=žt¾¢¡A>±>ìØÎ½ñ^¾”ºÔ=ý6‰=¢o>â¼==¯°ô¾ÏÁª>(¥¨¾vὑ’r>þ×8¾ÝNͽלX¾Ü¤±=õs�>5×]>§xt¾5²·>ºó·=›§÷½>w>–‡¤½’÷ ¾ÒX¾}Ù¾Áó>… ¾NE¾7ݬ½B¹°>Ÿú½µº>—éF>ãø<¾`i¾%Ï<3÷¾Y3<Óô>Ûc¾”ó¼=þ…6¾@Rn½¤§<˜ma½9;�>³ª)¾)’<ˆH¦½³ �½Ü|â½~Š=)î=T2>y�>ÀGû½±ûv>`o‡=�)¾…ðê½\+Ä;FU¥=fu>k¯ü<ý‡,¿Kä] &Z>"Ù=‰h >k»8¾UÎ>¦‘Õ"Y޾‚É‹<[`b¾¡mé½e/¾©…¾ô[’¾˜i½dLû=ã×¾ ž³¾×Ä=>rz>ïÑ�>€Þ<¾ MX½•‘—>:ɽrHÝ=^3<Äɽdx¾ös½Ò¨>¾‘†—=t‘Ö=ز‡¾!Áñ<'Õ¾¸Uù½ïÅ輓8ô»ã¬ý¼\óN=GÐ˽SÿÒ<Ÿ´#>Zá¦>¬¹Â=y»<=#˜¼x%>êç>æâÀ>*A#½Å�¼ˆ�m¾))’;€S6=«.¾àÛ >ž³§½¼R©¾¨oû½ßÞ½®-ô=õ!¾ïˆ¾°F<=p">ês½iÅ>…¿ô=�eþ¼vþ”½Ùp{>ÎRs>8C潺e{½Ë¶ ¾Í>ö½§½Ô3/¿t�v¾ÊI¾äRÔ»TÂX>œ¼ >*Ͻ^E¯>TÀò>-/𽇆½4²U>>>ð¼äx£¾TžZ¾KG޽7�·=T$‰¾²á«½)²·½¹Sý½'í¢>{ç½Hˆ˜=Ó»½¢x@?k@*>i�(>š„>ít(<¯de¾ª{¨>¤ï˜>Tc6¼WÑÖ¾;åÏ=lb=>õ<Í>M?%=% Q=»¨u>öL=ýöZ<¯y•¾Ò×g:ÿ/Í=�=§¾ÒÂé=°Š>Ǿ‹¾A¾Ãka> Ž>T 8>È/&¾p©f»ÔO=x Þ½�Ð$¾ã÷½àt>hæÚ¾Ë1M½ŽÂÄ="Œ<ôæš>'*;>(±ò>ùÆâ=ÓLž=~)½‰k`¾n“½úƒ¾$é�¾�‹§½»V>Ñ߆½I}µ> ³¾ Çá<¦‹Ë=ê5¬>úïÇ>Ø=É<[Žü=Fì<Ô²�>à”Z>ç={/λqó¸=õmº>[”¾t]ø`èh={J+¾E¬>™¸>o³È½¥¾�>‰¡>Û§º¾`,™=Hô9¾‚µ<~Ù>WL_¼`¼=^Um>áŒ>¦¾ÔÀ‘¾¡ >ì1¾$\?xN¡¾¾q»>ekx¾ A¾PKï½ù¾ˆ)“½Tc�¾½>¼ôÙ¼�-;VÓë¾0Q=rNa>p¿Ì=ßô¾@r¾…¿½[¾§LŽ>8«>•?½|0=æwн<|=däú½{ ™¾¸W¾}ÌX¾Sf=Øó©¾#• ¾ ¾×$ð¼轪8¿½¡QU¾‘z¾ƒ(9>»u=> Æë¶µ„>¥¤¾�Ô„¾ž„>½Xw=øˆ­¾©Ô�¾&æí=@@q¾µU>tÓA>eA;£Ã2>¬V¾m]>Ʒݽ·¹>Æ& <‹û†>ÊQ;ÒÃ>w»;½q¾&¤¶=®ß±=7~;<‘=VÍ%>ห½L#|¾J�‘»î€½ß/4>÷/ؽ©÷=Fè2>¤\Ú½C=f=ÍÍ–¾/z¾8°>Hò¨¼Æ>�½"ÿ4>mLx¼[[„¾­bv¼xX§>ç¬=°Õ<ÑWý(%ç>ÅUß¾ôôÚ¾öTP>‘,û¼R¨ª¾ò¾ì ?2rE>ƒ÷7¼-°;¡H•=kÆ�;bZ€¾ 0¤<Ãß¾–È=…Ä;>‚µ¾ˆò’=Õ`>ciν>C@¾{C>”‰Ì=˜½õºI= ÷w¾ˆÂ½r]Þ>°½½' =ȹü½8¾5Bé¾×bÒ>ïȇ¼g f¾_aö=?u”=¸¿¼Vu >/�)>%¬.>žBI>¨v•>Ù÷“¾Òss¾×­Š>6…Õ>‚ŽKÏ8½n£¸;%wu¾öv>«Ú»î)½óñ¼†±t>óÓ»=4™f½XðÒ<|1g¾[/¾Oݽê}½|»=ýÓa>u™ˆ¼á¡=È>X¼nÚ“<¾K)¼8WT¾Ða=b”N>Þƒ>T,>z �½=�̾wv·¼br1¾°ö½¾ïj¾ ?˜=U>>û2?½J®!¾ß™J¾¬•$¾Hxx>œÜä=Ý H>C>ÔÕ3>-·Á½rP«>õ ¿óŽ1=PµÓ=À,¾1L5¼r„¾�§>™¦Û>—~‚;¼W‡>Öú½"ü½—C>½ Õͽï)s»@ >4�ê½.±>A×—=àe¾Óã]=ÞsJ¼ÄK<Ìû�¾‡žA»ß^=ó¼ü‘x¾§ÞÃ<ÝIR>—bq=» ¾ÿ T¾|ºÆ<•†¾º¤ð=ùžM¾=剾 Y£¼ê­;òY6=DÝ =…¿º©Þ<À½>­Ù_½ÛÖ�>EßZ=wä½W_Ã>²Ç`½‚2w¾\t„>%¨Ø¾+9>5Y»í[£½îÇ’¾#eP=Ü0¾m-á½|jØ�}¿¡¨¾N¼Œ½“((=Åw½~„=en‘¾"„‚½1³¯¾‡$N>I¯k>$û{½)Ý<ã~>\cƒ¼©ÔʽNg&½Šù1¾Kœ¼þ’—¾‚¿ >úæ\¾}dl>i€Þ>Ut >g>‡²>ÔPü¾¢¼¾žÆ_¾j&K¾‰]=å²ý=Oh·<|=œFª½†ü¯¾\Q ¾ gÎ>Hr>ÙÁì=î7£=+»>¾së=wï˾�Ô4>__¾]¾ÇíP½ ÚJ¾âz> µ”>h¨ð½í´Ï><=W½f\¡½ ÒܺbɾÌÚ:ð>á˸=%¾´½¹)Ͻ—Ž¾ÉŒ=Ù” >±Øn<¿]$>ï¼d¾ÑŸ½«=¸°e¾Åô=Ck½æ,’¼ÅÙœ¾!o¦¼¾ð½ñJ¸½¤k(>74>Ì1w<|>|ÒÜ>“M>úi7¼ŸC[>¸„€>ScÝ>}ý�>E«E>–=®§È=’øH> zŸ½î;)¼-œ¤>ÞÃ0>«Œý¾J�¾ñ¼œ¾_nI¾[÷e` >z>@U=s³‰½&ã!>KÌ>FÐ=Ϫn¾ '½6-P>wŒ¼XBE¾ Uˆ¾U^X½ÎŽp¾Ÿ'J½â©-=ÿøŽ>^è¶¾êò:ÒîȽþä/>Av¾)r*½S(õ½ 7¾³‰>Ò!½’ÖÆ=¤ >¯R€>$蛾Niƒ>Þ$·=ŽSH>¡ÑÊ>>{°>rKF½³tî>fD¾Æsý=ýûT¾0f¾É]= ¼¾q¢‚> W0>�(7>©¯J½(F.>‡‘3¾ˆÍ!½Õà<ͼ>$×= e ¾ŠEð½ÆL¾Mƒ…>Y³˜>3‹®¾15\> ˽ílx> ©¾ã9¢=®Qž¼¯¨­>Ê×G>˜íÂ=ò”�>¯¢0½NJ�½±S>O‡'¾Ž>¼¾†•¸>¶èƽ«ì´½Y\>ê䦾5¸¦¾dÖ»>�tŸ¾ Í�¾¹þ‚>fݽýíd¾¼oû¾}R€¾lRl¾ÿŒ&¾_6Z=Úp’>Ÿ•Ý<¡ëξdhˆ=,ÐØ»ß<¾­ý_n†>Y#>¯Ðx>#@†>+  ½£p’¾0 H¾ ¸>îÖ¼½—R^½úüG>Qì>ú¸¤¼û?½ü·¾k `½ªòݽð䥾ý ¾íü½ù +¾,¢<×ʼ‘ú‡½2ëg¾\RK>û;y=3tf=„/¡>Ðy¼¾ˆb<0Û8½1¦Ì>«¥f¾ÉÀ¤>!¢¢=Oö¾ :>x¾Ó±™<�›ÆÜ7¾F>��…>xÕ>�j%¾'DŒ>`˽>Žz > ÔS¾0‰¼ÍGý½ñ½;¾j>¾9M=-ÔX=¼3o½ç¿Í>•é=¾Ï‡S>«­=iea>Õ*ß=8{Œ¾§±H¾TÊ=ö '¾Ú>ÐÞ0=ÓŸ)¾ðQž=Í_|½k Ù¾D`o:w>8®í=ñ…À=™‰’¾¬¾K¾¢i=¼è¥=ãá¿Îat=.âq>�I>_9â¾¼' ¾vH¾§·æ=Ö3,¾i›¾Ûµ¾ˆƒÃ½¼"f¾ï*¾Ìkõ½z¨>Æ’$¾”ûõ¾‡|¸>Àê¬<œtE=œ ¾¹î¸= ¾¥��½]‰&=ºÊ=Í[¾p¸¾M·§½”�"¾12%4™<Žg³¾)èï¾DÖ«>1»Š½g#ƒ>wx·=OQá¼—Gß½Dä/»#ÎÛ½úÕ;>}7[<”ä–¾mÙ>&Õj<‚A:×”:’¾#w>‘UT>ð8>]ø‚¾ÖŒ¦¾ Pá>ãwª¾Dg‡¾ëDx¾²&¾3‚2¾>{…=¹Ø¤>Ï*º½å¬>ðÅÍ>�Á�¾Û¶â=îÑZ=�“÷½Š ´=×Ü«½þ_>&É]¾Ô¥e>t¦³<´Á ¿l½m|o¾£�[¾¯é¼à‡ >ž3ä½u‚9>èÌ®>jùó<`Å»<Ólž=›ó>j©,>‡?Ær¾w‡¬=‘ý½L£½ù‡Õ½R:¾]4Œ=¢ã˜=¸¡Î¾å.>rS†½mp”=o®>̳λ;�<>&¿¼á‚i¾!nm¾aç:=«ò=KN?goŒ<Œ=°ÝM½K©<ض'=¼Š¾ëS¤¾ZRˆ>ÎÒ•=³[9¾Ê«¦=¡M¾úa>›8h½\ >�)Ÿ¼�y½s>ꉵ=/›A>Fûi¾‡�=Ÿ -¿¿Ò>R{*> y§=T“»3çw=—�>¹> JT>ˆß<>6/Ž<ï2å½Ì�7>R{­¾1ÿ¿9I‰=Iê¦>’×K¾ཷ�½^”=IK�¾ï9§»BÉS=ëå²>)­=8 >Å¿Y—¾ ®µ½W³*>†0„=-¿ á…¾¡‹ >ìæÛ=ÅdI>V4·¾íè>½¨µ¾ c¾Ç‰_¾^’¾+tî½1L6>&O‡¾¬·¡>Ïì¨=ÑŽ<½æ¿®>‰>Ôl”>½Ê—¾$Û>…g¿É ¾B’¾Àž¾”1‡>¨Êð¼Èwξ“¾ Ò»ºÇ¿·#¢»Ì†,> Ü_‚,¾3À=ØM>Ðþ͓d¾.ؽdDÛ=tˆ—=²-’>)�v=êK�½=Ç3¾þ =XPK¾˜^Ö¾-§i¾¾wDõ== W¾2Mj>Œæ}¾­‡ð¾8Ì9¾4™>ÑÓy>ûÐù<øÇJ¾•bÅ=�Ð=­—3½€–ƒ½ƒ\¿ê�¥¾7Åo¾e&‚>*ë½!ù¨>tœ=�Ÿ6¾5â>Ʋ={íÛ>ö+ô=†”=e{0¾Z~%>® ¸=5øš>t¬Ñ<>ˆ¼½ãÜž½Áp¾gwˆ<¢“>ª�ý;Ò‹Æ=~üмmo=¿WW>WvL½”@;Ïe~>‰>Ü´ž>46g=ƒŸ$>Ñq¾J ¾‘þ>-3罓üc–½¼ùƒ>R²È=x%¾K)Ø>ÌÚ<0€­¾×e¾¼û”>ªkŒ=lm >Ðñ¿>ÿ÷̽`:ö½­äÀ½ºÝm>Ó; ¾¢çà>Þû=S¸ì¾6©<þÕì½/iƒ<î#´½ïeô½8vL>F,¶>u¯W;Z×[¼Í˜b>U�½ó6̽½ô¡=ð»Á=�Ö=‘Pá¾ÿ Ø>¼Zé¾@ND>"»½h’¾l7e>šø�¾`€B¾Ù?o¾C¿n¾½Éjë½ø#¾Æïæ»ãyf¾©““»Šúø=Ú Å:I@‡¾+Ö½™å½–ñb=8 >&|£½×–ƒ=¥b^½j\ =z'=𦡾¦™>‰Sg¼êYŠ=(‰M>ƒ³´=b†ì=`ù³¼+Ÿd¾�Á­¾·W�=ã„é=Œsm>óA ¾_’›¼Äb»½mâŒ>—¥N>÷ÇÛ½¤Ó|¾Bø¶¾ã"Ë=$Ψ½¤‰§=PÈó¼6HM¾Éö½JÍ ½8ÓÍ=Q.>j8(>Yy>¡P>u¡ñ½©ÐÍ>Ö”½íØ(½yC>}q›>H½y'¾,°:½VÔ¢= §3»1�>£År>²Œ½(P¾fò÷½Á„¿>Öû¾w*%¾òï¹òÌê½ï—¯;ñŸí½_Þ=›5>¾�¸G¾·–¾uR=«L=Üù»ºæ“¾ßÁ>–ú>´j%<Š6½k*Y¾"M‹¾ÄªJ=oîÇ=Qàz¾3{¾ùÛ=W#¨=7“[½qÝ“=³LØ= ˆ7:øv^¾•U=U{½ô¥º>7) >KƾÄ/½eQÐ>®/¤<ã)¿½…¾…�">É1½,ÙÎ=!§½pká¼› �¾Œ¼1¾iø³¾–®¨½=—›=ØÜª½*ÿ»N%ª½šÛ9>ð’=ð?Í#‡¾æØ ¾„M±¾eŸœ¾Ds±= ¾È¾ï-q>Î8¾+—>ØS©==ï >Ô>j¬Õ½é?46A½›=¾> ¾?χ½!m‹<êL‹¾¿m¾×3>4zñ>±ÂW>[ ½'8�¾Ü¼=¾ÅÍe=W¨g>@¦þ=Ç6…¾žJ¾ÏÃT½ ¨ˆ=<õ5¾C‚.¾ª”.=[­¾¸09¾"A:½c¾•>aîX>U­|¾56¾>¿ù¼ín“¾l4Á¾Üù°>×R×=瓜¼.Ãå¼D–h=rˆR½­—…½à­ý¼^¾U~1½â­™½ýÌW>Ếçl¾~'¾�Ì«=dœ…½PM€>~’ê»vê'¾õ{ݼg¼>,•½¡�Q=žN޾Ò^¾XO>0Ì»:-E¾«]F=úO[¾µ$=Jåt½‘ >º]>”�½£Ü¦>¿äJ>¡U‹‡>'Þc;[És>­¨Ò>Óv�½QϽj>Ez²>ÞX =ú¹‡>C ½ÓŒ¾üQ¿ÖØH¾°�%> o޾‡v2¾#³‡¼9M<7bï;¯/¬½µ`:»ÎN‚ºf °>u->Ù뮸,Ãa½Oj‘½hÀ0>¾Ïç½®˜x>¬Ç{>"í½“R®½÷‰¾�–½‚Ë”¾A¯>˜âp=Lñ€½'dÙ¾!/(½ðÎP½>àL¼"¶=Füé=!k;>hÛÒ=EK�»u*À=óŠj>ª¢þ<Üÿ¾©�j½90>=f!½üñ2>øÕ¾)c9½¡5©½^‹B=<د;,zF>C:±=h徉7<¾ !C=ïwi= oR<¿�’=8Õs¾ŽD¼Ð‚¾6ƒ>ÓÇ:>4ãc½[Zï½®v£¾Â¿a½ë.—;•V>änÓ=I·.<ë6žEZW>ÍB>÷‚C¾ú';Ágô>Yhª=�7¿i¨Ë¾by½ü¥½¨½ò5ø¼ïYÒ>Þ¤a½ûã;†¨â<Ý‹¾>0û½™l‹=˜î¾yƒÏ½ÿ¦—½ …ù½Û�+¾¨9¢>§i:¾@µ]½Í’—=”»>&jH>éI½¥ÕE=ÂŒG¾6¼ ¾”©¾ù^¼˳¼¶̾aÜá=n�=/ü>=åÕú½à›=¦Ú={Ï>”>oç#>ù>ñ‚¾×Q>}}>Æò˽,’ >"‘›=Šî->õ™¾%û=p‰¦¾uGˆ¾Ã ¾A‚Š¼ÏŸÀ>p…�½TP>þ-´½£ÝC½Ö‘&¾N‡=Óçy¾ÒÐI¾  ¾ÉľYøU¾‘_ó½á*¾Ô˜�½Eþ’¾á=¦=¿‚¾˜>Ÿ[³=ã(–=Ïê½Gh¹=²O:=ãe½5¿A>BÁ>T!�>‹v=AòQ>Gºj>Y.�>¬Ãs¼BˆD¾ á=Êó¢>„Er=O<¿yó¥½J™¼ÄÅû½œ6½Ù=�c>bó¾¤èƒ¾î¢q>lh ¾[YÊ;üÒ&=Šö= ƒV<~îÛ>݃‚>GƾK÷¿¾“ˆ³½¢‰ =gg³»[ª¾5l²= %™½Ë=½Üú¾cËÉ>,'=Þ:8»çŒ½iú>|/>°Æ=¾7Ǩ¼8)1>D$¾í½dûˆ>8®¾{GQ>¬¿¾>as£¾Ó?<¬ˆh=}>=󸫽ÊÕ÷¼ôœà<åÂ"=áD½UÂʽX!¾R;…=´ü˜> å+=3V%¾¹Ã,½žÍä=ô”=r`œ>¶Ê‘½Öd$¾åi€¾óe‡¾ä/>€; ¾ÑS¾8_Ú½KÉR¾ñ ì¼A ñ¼êé>Üá=ÚÛ4¾ºq¾8­`>¥Xö½Ô8½qW¾ž3¾Žû›=*Ï(½z¼=gâ±=¬y£>¯c»-å?P8µ½BÉÖ=$®>tçR<« ~>¸ŠI=°`4>‘?ܼ™@¾Åˆ«=¾/$=c^p½ên¾9\ü¼ò·´½—æò¾¡ìM½P Q>0éF¾M'p½Æö½;Ðù=Ž4ú»¾¥6=åܾùxq=åL”¼—44>Û,Q¾¾¦>¸kˆ>¦²¼_=;&7½ý:¼^7£½è3ѽÂ;@¾øG½µö>Õ5º=sqË=÷…Ë=¤hY=ô¸H¾rÖ>ß�¾T´Ø=�û�>J»^=1ã§=ƒ/œ<Œ€=—ʽpK}»¨›½›`A>Ð Ù¼ 'Q¾ý ‚¾;©ö=²þ ¾Œt¾J0�¾É�x¾ñMÅ=,ž…>þº>‰@¼½Ô:½¡1‘¾à�ª½ân=ÿ‡>P‘>UϽ9Ї¼ݦ=ê°¾Í\Ì=àáÆ½G:¹=ø8«¼£:½{M>±¯¤= ú¤»0 =O‹¾ýp >'õY>+ ¾Hy°<€A»=w¹�>—ŒÖ¾½$Ö=L)G¾äB‚=Å5¾á(ƒ>´[¤¾)º½sâ“>ö‹ñ=xܾ>“¾H{D¾uÙ¿¾Eb¾†n8>ô>=™Ž=k{è¼÷K�=_tè<êm>O†�>«ý—½«¬!½W’=:t­>(=°¾ Ëy>šìÔ=©¯|½Ùd—¾.WC=ؽäÇW¾ô˜å='÷ ¾»ï½Þѽɾ¢eŒ=5Ò¾¬±{<ÝyÉ>gQ¿lž>Hx̽8â>Ñ*–=o)[>QÜ#>R<Óc>Þ¢²=øL ¼ç9>å?›<Θò»Àî>pÍ{>É¥J½çŠ>þ²Œ½�ÌŸ<šUg½^ñ>³ùo¾þ"O¾é ¹½ÔK¾Wè¼>I6\>íJ»> o¾bùâ=CT‡>ãg?ï™k>Ñ[%>*áš¾`Œ¯=i´“=œ€„=e:Œ¼=~:>²=½=×Ý<ždª>(̽ª³É¾lDª½•i¾8~ô¼~­>‰ÿ»=–3‹>PbM;÷ô½Ý>L3£>näò=ˆJô>¯cg¾(­X¾9´—=ð +=r®¾w÷“>¼Ìt½¾`ƒ¾b²‚¼[89¾ýšo=üZ¿Çå²¼^¥¾¤Â ¾Vcƒ=ä ¿åd=÷£E¾æþ0¾ª&¥¼üAx»†­>¼I)æ½zõ½×·9¼KØ>9åݽ<„>$U3¼ñvœ½êöç;öÍÿ=Q%Â>…;1W$½Äå'9©|¾tÎâ=ß<_@,¾L³Ÿ¾Ó.²>ËÁ>Â’ƒ=”»JÌ4»î}°½g'{¾¨Ç½àOÖ:�â=’5g>^Ó¤¾¨)D>i>Fy>Nn4¾Ž0©=P5оÐð7¾ ë�;;nƒ>Úaû½¦Kñ=Ëà†¾È׿=p$½ë:ü½ah¾õý·;WÆÜ=<ë">ÐÅÖ¾egü<=2=Z¸Â=eC›:)¦A¾­EH>;>r:7=¸“´>°ä˜½ÌS”¾¶˜‡=?ì>Ô&¾ZÂÅ¾Ö Ê=oOø;ï�m>¼µ=ÄÖ̽ 2s>u°¨<# ¯½ä{оӨ˜>yž¾¿êŒ>¹/ ¾`Œ€=K† ¿m¶Ë>y $¾bŒ¯>+ë¼»¿ S­=™q>fO�¾Äu8½å¼h»+>²‹¼Èä—½¶Åª¾j…u¼ŽÖ=¾P«=²Ç>©o�½ŠH¾®vo¾Z ˺F ½&|>Y°2>”¾ì'�»‚£Å½µþá¼GÍ,>˜ ©>žVo¼NFµ=JâÁ=�]°¾üwн'òŸ½³`ˆ>c|†½èÂH¾²Ô½O«‡<¹ÿ�<{‚[¾ýMa¾¾¸=øQ¯½Š%x¾|Ž>½ºK]>h =?€¾=07¾m’µ=†¢(¾6¥>ΣB>ONH¾¬{¾ÓÏs>/hŸ¾{îH¾N¤c>Ê9R¥ïJ¾æ� >­9B¾TÄ>mq4¾2Ä >xSÉ<¾¢:¾†¯}¾Û¥Ã½û0—>%:‡½ù¾¾S�›½­œ,>ßÍÎ=uï?=>Ľ¼´_�>ÂD>Ü$(>Ew€>¿Ÿƒ½Á ¾6!Q>Úäy>-‹ ¶uÁ=³û/¼-ÈS=ÞƒG> þ°½Sá=t>œ¾vYJ>Wá§>�¤–¾\:Á½ŽÜ>Ÿ²¾=û¿½6Ê9½h4³=Ñ;=¾]ÓÉ;+Aн\�­½Ú =¥;¾§¾•u`¾C³ý¼]5>î2=JRz¾ÈRª>ÊõÏ;š¾5|¾ºÊ>Öà¼RvŸ;#½[6M¾ÌÆC>â¼è_¾½õ c>j±h¾�ä]¾ÀЛ¾‚¢½NZ¦½::>šÆÁ¾A.½½êº�½<ƒ…=O>Ø>t·Ð=}K>µ½A¾y©ˆ¾t1+í`ǽØQc>Žù<µæD>܇½Ô1=c=[¾Al½�ª*>ú¨î¼ ßž=¤œ;<œ¾ìýE¾IÁƾ'zu=:ø¡=…mÍ>KÕ<˜"¿zpB>s¾çù™¾ö<~·õ=ªgÝ=Õ¼]$¾4'¾ñ4ç<$Ž�¾^Ì>€ð(¾Wo­½Ã"ܽ'B%;ý)>Ø2'¾uP¡>³6¥¾tÿœ¾J�9>µX‹½ö�=:†½X§C½ò¡û<±/•½Ï€=…8I½W~Y¼uÊ™=¶˜¥<Ûä=Yb‰¾7|¼>Ø=#>†-š¾N“ ½u¢½-¦>½½qm>úÖ~=àªÿ¾Aš¾Ô¢Ü¾öﯾOëõ;:8“º^ À=9*š½ÕH•=pÛ9>ÂØÂ½@I"=;Ѭ¾S ޽Cg¾í¾…ž=®åâ½Fç½!u²»gˆ½#ÿ=¥|?‡£>Ï%#¼38 >'©«=ï= >—Q½,“-½Îc<½ÓV5¾M¾9îV>³ø³>ôK—¾ÏM>´\¿»E9¾{Å>ô¹d¾¹ >/Ý«>Ú󇾫ïû=ObݼY÷Z¾ôëM>†+>„Á–>×J4=z\�:U˜¾»©;ó²½ýšŸ=wë<Ö�ø¾œÀ`¾`úZ½j‚½2Òz>„Ö»ÂnN>f{Ⱦ¾&1<ïn�>a^‘¾¨XÛ; Í–=€?;=KÕ¾gR=m²Ö½2>/¡ ¾éc*¾� ¾®Ó‡>Ÿ}>màI>Cß¾>V>¨�®>ÏÎã<}ïã=8ßo¾ˆ¿½ÃƼ½d„È=j:X½=¿ð=‡«>´L_»éý¼�ºr>ÑWâ<‡ÔŸ½7׸¾ume½Í\P¾B''>«Â>…¦$¾GŽP¾^�œ>™Ú½ ½Æ¾GŒA¾'@>´$n¼ÝǽCÉ·½ºˆ�>7;R3¾Ñó¾ŽèнZÞ„=Ô$,½úZƒ>G��½º• >­c…=z®Ç>Öš>sôŒ=ú¾åð¦½~Ã>.RQ¾ %ß=^M¾–W>9™¾8Éð=Šr³>Ô{ß=§Ê­>PÉy=/×¢=¥.ž¼1zí½Å¡W¾ñ&‰¾ø‡#¾°Wå=‘ÉÑ>ôÊ=äÅ‚=øJ>ŸÊʾ÷¶Ò$ô@<õÞ¾‚ñ~>ß57¾ö#¾¾_V(>¸'½N€½…Á£¼Ùêž½‹®¾¤v>ÏEñ<œA¾^$ú>|%=ß“¾y¥¾jâ>4£Ó<<€g>KC`½¡�l>*€/¾­¥>¬‘8¾²�¼¼ðr¾qÔ~½Ðö>°y‘¾­Ä£;J¨x>&f›¼ö´›>›üƒ>_Ä‚=Â0x¾ø™>þ‡Ó>ïnŠ>„b>cWò½?—®¾�l“¾#^¾åg/=†R<”�‘¾°­¼Ž°¦½Ú—_>›[>˜�ë¾ £Ñ>À÷=£l4:\6­¾~Þ‚>$cl¾¨ÞŽ>‹©?ˆR>¼Hñ=£ƒ>#U>–âÆ½‰‡‰>@u¦=©!ª½=G-¾õØ ¾]‰>Ú�„½xµ—¾ ¥u¾bò“=R~K¾,œ ¾S‡>'²>ƒ>.=ˆ½…ûe= â=Ð�N=Eà >ï›=[ó>ÚJ¾sª�¾® +>ä…7¾¯•µ=Ë€’¾tÎË=£|˽޲=檾ˆš“»½”`=�1�¾!–Ý<9f¾�=ö¼~Ð>B"½i¾!ßb=0e©¾Y”<}ª=áïˆ>šž¾ÜI>Mƒ^½$b€¾½±Ï¼=>ðbâ=暴¾i— ¾€Ù²>=ľÀ 8¾‘\¼!Kξ{Œã½Ð 8¾(5‡>þÖß½ðS¾…t!¾þ›î=_†Ã<P<¼Êy½d’>Î&æ=dR ¾øšÞ=}{>•a¾cÌd>[.>VQ¬½ö–ºÄ ¾;!†¾…É)>E;¾$f=ó[½¬cµ=:©‘…ùv>Ãؾáó½]ƒ>#õz½7›RÁËæ½;ð?‚œ™=Ï<“>²¨¼õ_X¾1£Œ¾Fç<9àr¾6ìá¼ÿcó=:Ø{¾8 k=ß(™=-Šº,k5>ÚZâ=`'?€=> (“>k" ¾-É-¾¨¥Q>È>¡ô >¾#2>Ön?Ƥ–>=稾rÂɽVy>�K>GV=§Å/>,ð/½¶…¼9êW ½4x…¾Þ£½UÝ4>lo¾Zz¾sŠ”½bR¼U¤Í»Q/>’ó—>ÖÕݾ¯Ü]¾µâž½&Û> À÷=âÄH> >Ø® ¾uÌ>SëÄ=jÔ->ÿÀ¨<�¸ ¾±d–>bÌ“< y¼>ðÐ-=¤Ž½�Eº¼ßg¾½ÐÏ>6ž8>7ð¼Í6k¾´ê=7±B½M—p>0ü´>6p‡½®¹³=\Ò¡¾ œô<x‹>ca¨½ˆ¼¾HБ½ýÅ!>÷<ž¼¼¤¾Ê«^>÷Žä=b�½V{†½§^>u|D¾¯V>EÂF>ˆ´l¾üh]èPy>Ër=�mܼJ‹b>ÚlÔTnê>S‘¿›÷ <ŸáÅ»‚¥k½ D<>ëK¼£:‚=òÀ¾ƒP<½¢ýÈp�¾ Ï0=Æ&É>}m—=Ìã =)޼ñ,½ð*¾Åp×=f8�¾â¹i>Œ²Þ=PÒ¼A“ø<@˜ó¼È·<ÆíľêCn=Ä7sÎR¾~=Õ.æ=s£m½â¾=ÙS¤½�â±=†�ª½ç£>l%>ãž>Ö¢‘½†BÕ=š6[>ýÈÅ=1yF>ú<ÐÅü=F~¼i0`=ê¾5ð´=…¾ÐžqξºrM¾ò/u¾±‹¦>ÆÄ¸=Î ‰¾ûf ½ùý¾¼_>ÄjŒ<Ðû¼>Îû½­º®>LRa=€åà§á+>Ñ»Z¼ ¯:¾âú½€E�½Ž³ß=úÅܽõ° =óJ6=a/¾¿’Ó¾Ó[‡>ÝÇ8¾$ÖŸ=Ø7>Aœ&¾ P:>«N¾ñô²=,DÅ>»r;¸I—=HÏC>µ>=¾O–>�®½È߇=Î,¾°¾Š¾t`¼ô%¾i(ˆ¾­ÔP¾­€â½÷ÞÇ=ÅŒÊ=#ܤ½58¼) !>ÉRÙ¼ Ãþù!>¬ùG>耾`á°="õ’¾Ò)›½‡ ú=AèÞ=QÄ{½‹¥¼¢c(>gpF>èÕ˜=i”=€g8¾–_×¾ ¦£=M½UwÓ¾äaš¼9á¢=ãgî=® ß¾¬õ¾qJ¾Ñ2¾3 í>HØg>Yh�=!y<X=­±Ù;ß¡U>lhÕ=ïÌù=QYø¼Š¾¸¢=¢e¤¾éªá=apb>\j¾]‰1>Iú>¬—b½šŽ.¾8–w½[å ½f÷C½Ë>¾áW=@оVÚ(=„A“¾›„>ø„Ó¾Ö”> –Y>»¾£½iW¹=÷Ô¼ñŒ =á‡*½òd“>’åØ>Jóa¾K®0»ùé«=ªòŒ>­37¾!æ7=¿{õê:½øÔ>ÜL >ÂvD>Ù™'>º5)=M”ß=3 ž>“=\ú¾:œÏ½„ã¢>Ù­¾6¼iþé“(>>ÔT>×€O>€&&>DO >ó[^=»ôŠ> .=Í謁G¾$>µùA¾Nï¸=H—€>É=Y ¼+5X½.¾ù‡À½CÎÆ>œ>½Šg¡½ºk„¾§B<˜û.½2à< †> L=>W_ª>—+½u�˜½.‹>„D>Áø}>¤Í¾Üs½ÊÎb=JQ=>[4¼}´?½ªå<‘B¾rÍ=7—¾Øw�<{;\=‰€¾½°Hm¾.̽U0½¨E­½³9Ö=fÔãqª>í0ç<ªe³½IÌ1¾ûY{½�vÂ=¨µ>>içK<ŒF>÷Ý\>àáÉ=A¾Æ<¥è̾  ½Ö&’>…\>-T>r)U¾Z 1=ô ‰=ÿE.>â¨R½š¼=��¾Ìºð=— =�àÅ=ì)š>‰¼u> g¾%XV>椬½Ñ· ¾}ë1¾pû=•ëʽµï‡¼£•¾ê">gû»>Y{’½+^·¼uD6¾"ê¾Ñ:û¼cÛ�¾h-í=–Št½žwº=ø3¼³þK=A²-¾þ …½g“o½²k>ð‡¾£Ò8>mK ¾‹¶c=võ#=HK%¾�Ø{= ½½kVÃ>B+̽!2¯½Ïb‰=;+v½:.¾äìŽ=�K;¿O®½ø•‰¾pKø¾q ~>ðc“¾aE�>�G@½¾ä�½Ÿìú¼Co;Á–bº�ÿ>€óš¾qæf½;>kZA½ý)_½èE¾´f¾¥¢¾®¨d¾^3½Ûð½gÈ´¾²�g¾üѾC£�>D>Û’½¯Ýâ¼ùD…¼Ó‰Ö½ÌÂk>Òq½ÆGy=¬ía>ËVºöÀ$>ã┾§ä >d7M<Ї>—³8>fˆ=eš½>8@<:ÇÙ=R„•>P�º¾ƒK~¾øC½„å*¾í¦‹=¨&Þ½Ù{1:îú¾øˆ;+ø*>Ý�÷=K³½ßé>äi»½­³¾HÒ‹=H5º>F ¼gmÉ=øß™¾�Û‘>÷]r>O±²½ªè >ÖÿÒ¾Né¼÷0ú½°Î:="ep½•M‚½!ü=Ä¿×>ÿË7>Ó7Ú¾ËU¾ÇU3¾‘õ;Q“¾Ô€>F©>#ZM>:½¬=¢V®>£w½$²X¾)}™=¼›>ÞÀˆ¾YFß=†ôå¾qy(=n§ö½¥È¼³jÀ½¾™Ù=ýø¬=“¢�>‘ßë<Õ÷’¾ýs>Œ`Y¾æ›¾Àh£¾ À;<à×A>=×£¾¿¦T¾8nÛ=çe> ”…½ ?É=º>ÞÓ½ »½°ÆA¾K²Ë½úlû<”çJ¾ãŸ©½€©€=—Uc¾b�Â=|o>N`¾v?�¾±>&Ý0¾+ûx½ï½Ù½‚½®½\¾K½Z’€½Ö >�.¾ü%1½È�º>ÈÙZ¾×Ö$>÷×ê¾lL’=3ýS<Ÿó>^î¥=I¹õ½6“<óY&>â.> Â)>ËW§½Lôc>‡A¾r1�<º!;¹¨‘½Í¶w>&-}>Xœ¾ ¨>IÚ�¾IòÞ=¾sý=¶í$> O÷=fŒ>ïÓŒ½Ïx„¾NðÜ>¯Â¡¼Äùy=®;¾~(¾¡yh¾`Öª¾øC¡½ºV/>˜e¯ºag¡½­ßž‘É>s"_¾Œ„Ÿ=D…t;R;?@ù½kÜg>h¸ï½°û¼;g×s>kœ½Û¾æK¾É„@>-ÞÂ= ^.¾¼­c¾% ʽø ­=:iu>¨ƒ¦¾–>=Có¾×Ò²¾E<¶‹½ÿêK=½Y½•ž¾Ì]¼«Oµ=WC>£*¾Öº˜ ™=Nb¸=h‡Ö¾ Ä>ÐV>}ù”< R¾ÿó>’-̼ïp)>Í…>�ô«=Ÿ˾aœø½mØN¾ o»¼l?¾a(Ï=u*ѽžÕ7=².>C³> \¾ÞÝù:Ò ”>îj>Ï ½–¢5>˜9¥½Uõ ½ yȾ¡ h=“P²=f;>?¤<¾r5;¾/ö�¾†¦ø½¶•_¾·Â>ÊÆO>±°=ò0V>:ó<úS<‘ä ½‚F‚½ùÂA¾ ß’¾]…‡=!?}>‡ƒ¾s7=<¾ü«=j÷‡<·CW>ËJ…=> w>ö¬=`ŸØ=S,> Î#¾òI¾1«�¾¬”&=À»¼ï³@½(Ç®¾Öt†¼ÀÉ>kàļ;úļŸt“¾¢ò7¾í7m½÷ì=ƺ¾ŸIh¼-Â6>+ï¾7"?>H¿8?}#¾$�¾Ûm«½gýe>�ì½Ra[>X[ ¿ùa>㎾‹ k>Z{¾O¡=¾û½ÃS¾*@轤>``×=qø6½V„ß='`c>2ù¾Ó?i¾º4 ½”-¾û@V<†wZ>Ó…d¾@W˜=]ï’=f*¶=`m¾¸;H=¾Z·Q=JŽª=l�>”à^=ù)F>¶޾¸lp»Ñ5>$N¾¼ú¼`8=$-j¼{ƒ>{>"ó½Qï9¾î_Œ¾&Mœ½Ì™Ü½“>Ù½)›> F™¾ÉU©&»�Š ¼=®k¾²‹>.ôž¾"ξ$›¾©á�=«Úv>p.¢>·‹Ñ½O'¿=A8û=…Kü<'ÃN>ö¼%›¡½îL@¾H≾; 6½/нÆj§½±õ¶¼gq½2?4¾‚�;¾9>¼µ5>'×T>ãÁ|>Yß”¾jù‘¼Mf¾= ѽþ¤¿¾¼mú<+ê¾ ä¾C~ >³µ=Pôn=<Þ@=±m=†Þ´½‡�¯½¡ñ¾5W >,éÌ=ãg½ó6“>›ZƼ¢^¾Gq%¾·€¾Ðf�=ö‹·¾çÖq=ý¹±<ÇG%¾æ†½„†5=o8r<Õ)Ó½'Þ§=ü÷Ÿ>2õ2¾²!AºZ,?s,Æ»qÒ´=–„•ºK!ç¼T—¿ 02¾DZ=2‡E=7=#>â3¿9Râ>è¸Ù½3Qo>«À¶>+j¾Pgƽœ÷B>´�=¥?D½›kb>}S¾(W¢<œW^=Yžu>^…‹>Æáp¼†/3>}E�<¢š°½ïV¼"�ò¼Ô—=/Ã>·�¹¾"BĽBs>"�='“•¼1<(¾ýd’=âbE>ùD ¾Ù¾ŸvL?72^¾¶È¾~Æš¾Ñïã>lÚ>=Öݽv &¾ˆ½îû×»sõ>†%ê¾à¾Ë=O¼(¾í>>)Nh¾/u<½¿C\>]už¾A½¿¾d >±Y¾àf!¾õ¾æq¾»–-¾¸„>�s齩…>ƒ@Ü>(½¥ïé½%f­>š}E>ØL¥;´;”%½Ñ¶—½»³E>–" ¿µjùºL„¾cÅ�¼á¡¡½?ç ¾"ÄV¾þØÒ>av¤=þXn<ìm½;ú=ri>“>p=Š/>u5…½vƒÔ=OÙ=“ >#¼T¾ÊƽK>F�1¼˜Y,>x²B>üÑ=Ú\>E�ὓ n>‘¯¾Ìò¾Æ¾§!ֽÜ>ˆÔC¾{qÄ>G‘a¾ú4�¾ T²=ê¬>-½õ½>¾ç=vµ�¾/;ݽ•O >þ¶>¿~޼·bÓ½²ä=~¿Ë=7MY>¾=¼ 9>÷$•>w«X¾ƒ©¾aÆy¾Ú?å½M4ª½‚‚e¾òû$¾Q]ö=^1C¾ FÆ=ì×É>æì¬=æço>B£¾óm»LF¾Û6‘>œ4$¼NÚN¾òC>¾s®½(£Í=ɹ½©ó\>+¶;²q ¾¾X«¾Íо)ʱ½Ó)¾ƒ‘\½™T¾¹¥¼¾ÈÌ>Ù¾Ù"¾*óŒ=¶J>a?Œ¾Q¾ÓGW>ƒƒ½#K;xô>{)+¾U¯J¾ˆÉ‰¼Ú§î½úX=©òù½”N‰½vØ‘½t�>à%¿Qw¾Í>™½‹?>Â7û={ë^¾å§±½ògC¼æÒ‡½Ûb=ÌþØ=W.нµ÷”>Û¼a(>dî(<ߌ‰áÿ ;`@:>¯¬¾AÓì½1&ž½R·ê¼žC›½£À8>VûI>1?>;}T¾H!ÿ½®ÿǽ9h>¾ÃËŒ>×>ŠÌ໢d;¾ž¥d>jÅ¢¾Ã;Ž>=c¾µ!†½¬°™>M[ÉÆ«>øm@¾]l½s=5vè>ë¨;¾^¼=7@W= Óû>zµ‹>¼Á>»O”«;< >¥lW¾,�N¾v1˽õ±î=l;>_û>æ €>5Ã�½¤C×½ÚIJ½úëì½^\ú<èÍ–>Ë{;½¦Á7½Jë̾Šý/¾ì»½=í]µ¼ñÃ=q— >á ¾<¨#Ë=)xŸ¾«‡ ¿â¯œ={ˆ¾¢-Ï=rUÖ½ôk›½œPȽøÍÛ¾ï,A>�Ää½f•¾™–d=üf¤>“°½—D�¼X`>9O>'Ïž>¨·Ÿ=E|½Î8´=Äûð=¶"ú=³.½5°è=[sÞ<ÝÖ…¾1{u¾ÀÑí½dÓﺸuº¾•ö.>–�=þÒ‹¼é%&¾| ï<‘ïW>V ì=U�À>p‚ ¾ÆŸÄ=Û£ž>×¼>;;<ÿ�Ó=E²¾aã=Û�=g%Á¼n&ñ¼c~ƒ<23Q>ËŸŸ=Rz�>fÿ¹=«8—='T¼?ðƒ>±Ï&¾‚�«;�R¾¿•¼¨¾-¾ñ"K¾·Çè=U > se¾"¸£=€½›‘½)âx>l K>(H�¾Nm>´(»>>M>èÂD>ç™»Õ>ß”¾£ë¦=D±�>€G¾yЍ½UB¾/èK½Œ> F¯½è…n¾}í«½SÇb>²ÕÇ=”Ðù>³)’½ð]ç¾µ¼<‹®>?<>ÔŒ¾Þs">²Kö8u ¾›Zš;Ï�]»øm$>jÑõ<ü¾=��^¾¤'ö½ÒGÍ<¯Ͻmz1¾ c”½ ¸>ȳå=õOr¼ï£>ºÂ‹>Cƒ6>4C¾2«—¾y‘§¾÷X==þu½F@½68=àK¢;YÁâ;å[¾ߪ=‰ö}¾!×@¾äIǽÎÜüui¸=œ�¾Õüº¾çÑ&¾I°1>}{¾{ˆ¾§“‘½P?Ž}�> è4>+9f¾ëPj>¢n¨êW‘=GËð=½Cw½Ù�c;/%e¾ñƒ¿Œþr>ƒ�P½?¢<¡%G>�pܼ%(Ê>#�ˆ½1¼›;I¾;Ã_>¼À%=?Ϙ>ìœà<©¥¿¾á>ü >˜3¾jRÄ>Ó±@¾!ü=.šT=̲¾-¢D>Ù>Éâ=TKÙ½��]¾(È>¿>þ<½¾ßã=%®=P’+½q$í;¼Kß¾=©=œÎ#¾®óÅ>“j½„Á=¨¾]4>Æ�¦>êÏÚ>$ó¢>4KÒ=°VÜ=m¶E=ó »=’•ƒ=ÖP{¾~è«>iì,>$ò<}W¾½[:Ý=À¿ž=Â�>›P—½ª@T¾?=§=•´£=ÕÁÚ½HÚt¾Þå\=û(¾‹Ê±=Hr¾ÇB(½ÌŠ”½:F“¼5³¾(ǰ½¥%½ì® ¾Í™>°ˆ¾ f~=C¾b§=[ÓÚ½Léì½% ö½)¼*¾)�޾³W—=Õèå>[ e¾oÀž ¾ÔA÷=Ÿj¶<ú€¾ºW>>“==Æ!c=êÌ྅g¸Vb)¾#:½:ш½'% >àÖ}>ïd», ¾r–`>Iv„¼‚>×Ãt½R€×»rÇ7>c ?=0û'=¡ª£½Ms½™££>¿þ°½qXV¾ž®O=ÍYF> ¹V¾¯É‚ Ú_>®àü>ëý¾D°<ùÈ„='O >à)>5¤æ¼ùù¾=Ø”=ÁÔk¾Ý#^=4S>.iM>Ü0>ñ'”=Ûœ½Á*¾‡/ô=X¾!®¾ ¦ ><9=áª>>åtZ>n(=¼K>>cNQ<°ùÀ¾iò»X–=ŠZR>Ò%X>lÓ…>ã1>ˆ§>uàÒ¼ñÖ=7,F=¼¿Ù¾Ö>uµ’½á!c¾Ÿ‚˜Pïß> Sc>Ö»Î>(9/¾ÿÑœ¾:n–¼àå%¾–�Œ¾Ë5®¼´ :>»>ºÿ@¾Uã=?Ò²½–þö;H�N¾]Ò�>ô¼¯=Í<ë= éø>µ64>Ÿ÷5=¢ëŽJ­G¾™J}>ìU[½gE¾6u´¾[-¾ç˜¢½yëS½ºß:¾ûXT>l›¾šu >gœ¼ g†>'ø¾B :; X,¾‚�Buœ<»->k×°¾ûbŒ<óTX>\ê~>6‹B¾­¹t¾ŒO=�fϽ ×­½0¼€¾ê„¼T[ƒ=Ëô€¾"Ñ0¾%2B>–°Ç<{;`c†¾"¸¸:V>ç=5LǽA¾±Õ…>¹xˆ¾&™¾Â¶r>éò]¾ÑГ¾Ñ½*½ú\”¾p�ƒ¾K=‹ÄÅ>è;>5Uy¾´�=ÐÆ>¾}%>‡0½‡Ãˆ¾µ5‹<,y-¾â¥@½^HI>4ˆ½MøÔ½âCy=g">º÷¼½q¶¾qÎÔ<íêm=Oá—=ªj>DsŒ>ˆk>!¥½&穽^îT> ä´=öæ�>Ì�è½êL¸¾'꫽]ÐC>b(ï½êˆ~=Ç*>VÌ=ÔË»ø�=zˆ½u(>‚·¾ÜÐ=ù½y�»¾¡è>“(>ÁAö¼ªëT½¨w>Ùlμßpÿ=¬¦¶½ÓÂÎ=ÝU÷=;Z¾O§�=£€‚<ÕGÊ<þ=�aø½�%â¾Q•½�o•>�òé;v¤œ>ß=Í?¾¸¾øw�¾¯¦¾_€>A>d⎽q¥];‡~U>´ å=×~¦½œAC>´,½Vª(=Å¿N>jÛ¾Tæg>¬G>ÅÁ—<¤…¾°m¤½#9™¾†ü5¾Ô>ß¼¼Æ½k!G>…õq>Gì+>Üþ">uÔ=¹™Ÿ¼øh>=ÁÊǽs®c>­>\·=^ƽ?ß½G?¿xJf<7ƒP½ð˜K= 1c=@s.¿bÎt=4 €>},8>OÙ<ë!5¾qßî¼t—¾ªóW»¾®´=àg˜¾—*ô=ŸîŽ=`µ¾@—?¾¨m/=3[È=ÌZ½?¤‰>§¦8½Y­‰>Aý2¾º9¡¾ óÓ>Þ×\»Õ;0>©d±=VÎ=8d)=ízH>ûÝ=|q½&Ya>eª>OÄj;8¾y>ÂdÁ‘¹?½ßú>Ø,C>½ïݽ¤:»=\= ¼ÂÛ½)oB¾«Õ½‚Æ» ßW=Ø_Ÿ¾²>~‚¨<`°c¾ÝçU>lõ7¾RÕ(¾lé½8ç=0¢â=bœÀ=»¿�¾ïf=³îоíáž>ËÕå=4þë:×M—¾Z4Ø=CåU>EŠ>U÷‡=hg0¾¶I/=¾m(>I€V¾t‘,=Ȉ=ú2>x#ê¼öGå=Á—q%½2wÖ¾4Ø=‰Â`=sŠƒ¾ø™Ÿ>Â÷o=Z¾E;9¾u[ ¾¦>¬Â<=}§ï½ö¬ ½)>m%=Ï�‚> Š%¼ÿS€¾Rr«½]c¢=>Ò±«¾ôw�===B=\½{¿\¾}›>å8>ÃÙ½@·$>žL¥<„™Q>ùŠW>IñJ=+‘¼ Ø:æØè=·¤k= o>Rçf=HòR> k‰>x‘µ¾˜%뾸˜“½Á¾ r+¾¾ˆ§½dC‹=aN†>yo‡¾r?I>ªº!½?¹Ò=³«B<�o‘>3u=¾SC›>�•ž¾j¤G>QC>7o›=Œm½ zß>>%zq¾¥‘½8}ѽ.º¾¾D÷þ>¯Êa¾©¬>Wó*>Ï~q¾�A,¾¹Í×¾Ÿ¢˜¾œ?= H�>üŽ+¾1Â>±Ë‘¾ÿU'¾yÉg½Bva¼ÈÚ=ùZx=\ù¼ŒmP¾âž*>é¿B½¿h¾ðn=M}Š=˜¤|¾’ :¾–û!½ÿ`E='[L�±>ÑÔ¥¾ò´½»Wn>—y{>%�'>,aâ=î¿SÐd½Ü«¾Ù§K¾yù>ìÂÍ=» =áÆ;=¡K[¼E =’Io¾ï§=YSʾœ,¾hÂϽ k¾M(>@–p>kK;¾£º9=hdî>ù6§>#·Z>JV³½* ¡¾§…>ÿ¸¾ÿÍ%=Ìÿ5>Vº¾ W#¾ðÐ=cà‘>d†<>?­0=yÒÛ½Q•×½ >\j�<’ØÒ>é¡ ½±¤¼�G>Û‚Ê>Vgç=�¿>á€=P1A> š¾÷òA=Ä»g>0¹+¾˜ƒÝ¼ÖhŽ>£n�>½S¼;¼ ì =ø×·½á^÷=_å>½ >þ½é>A�ú½®K§>�¯=ta>ðt ¾JEݾîÎ>°T¨»½â@>Û¾Ó#>ͦ¾¼1˜X¾+ë½´ùÏ=¢¶>~­]¼d©ï¾xž¹>¢ ¾Ð,·½›Ê½=4Úœ=ue§=Pqæ<W¾¾x?$Tœ>ÿ¸à<9B¾T>=š2>lN°¾å:}¾L½¼u!Ú=þ¾öŶ¾Ýl>åC½Ê„>‚޽”>ý >ÆT@½Ç�бg>ÿcé>ô’f½E>ؼ˵+>ÈÔ9=B#½¼zN¾R_…>¬i¢¼É™[>ÊmÜ=܃¾jf>j„Í< Xô>­°§¾Åv>?f¾Ìâœ=$Ž–¾hTվʊ¾¥@û½&Ÿ/>?¯‹¾º›/½=_¾÷]¾^í;>¦’ͽ¿Âi½®,`>cØ)>7=ÄĽ Äö½ö 4>PQ>Z'p¾š+ =VÛu½2öu»~ç½=§¤W=Ss»=áÎo¾™u¾<ܾs,¦>àá]¼ë"¾¹ý‰>Ú{>p*>‡€¼ Œ=ÿ>Öa´xˆû½�&i=�J…¾l9= êâ=ø”¹½Ï(2=Éå¾HÆJ¾4æ¾ô >Îþ'¿�6=eÇ.¾§š¾=ù =›ø8>¢cn=E–y¾?¼6ø�½ù\¾!ä’=+é=liF=*€¹>¬ç¨>84ñ½Ñâ=ß÷\=e-ê;@£®=¦ÚO>†>¬u>ëAÓ>¶ú ¾�ðz½#}¾L¥Ê¼aü˜¾Ñçœ=z ;>¯T~¾ÓŽÅù²=‰Jr=\,»õÔ³= Á#>ñW�=ñ”¾Î-¾¾Â)½%x¢<@t,¼W;s<'f¾¦iL½ÞnÙ½�5ž¾%_¾¾�§=)Òt>*íú=ØÆ9¾`A„;š<¾Hõù½ñN¡¾Ü b½´˜£=8ÿ¯½ ¸Î=ÆÙÊ=iÕB>µx(¾”6¾ªF(> ¾åÙŠ<Ñ)¾É蕽Så­½ÿ«m>±¾5¾ š&>ICŽ>Ï>¾(u#>)ö=>9ÖÖ=ì¶}½ɲ=€¹½/Y8½Œ“U½óè» †<äÔ>ûâ:=bJ¨=ðw>=DÂ=hé=þàš>Dm¾§ee¾^Èú=Ï¥=Îv½±˜U¾iâK¾¢ï�¾zÝå=z+V¾®^€<´·°½n)¾‚nn>ÿͽ&ì-½_»$>ôtɽèŒÓ¼r Æ=”:>§9 <ñ‘>Ìz ½Þ²Ò>à¿Â<uÐ=l£W>¥®#>ŒÙ‰>ŽQ@¾èqz>Ä–~>ß0B¾³¬‹¾: 5>o‹¼c9½NÀ>}Ìɽ¯O\=&S<¾«Uy¾²~Q½’ÿ£¾î‰—<5IV¼J”½hGç¾�÷ ½oÙ‚>{$¾�p >�L?©—¾42×¼..“½ï`>ˆÀL½�á¿è >>ëÝÕ=y5ß=2YJ¾0V·½ŒŽÜ< ½¾Öãt¼:ùŒ¾ôL¾3ˆ!=YË‚¾?T[½Ñ>Š<¾Xn¾ì™M¾‚üw=“4Ì<i¸¼O½ Âª<ª®'¼LÀ½3g ?´g8=勾øÀ¾IÕP=ƒ¼³±=Eòðóiü=¾Ü?¾½A¾º6>¡‚_;Ÿó™½Ð¤A>œ[¾Ê* >•¡ ¾Å3>Ók’=št>š+™¼â7D½÷y>C4¾Ž|¨>‚nï=¡iÅ<Û3¿'>FC—½oÂ>ÃFü<Ÿ=ïžd¾þ‚>gL¾{éսݯ->2ðq=$¨¾¦�`>>ä½ /ª¾|"ž=û'н(k¼8±Ñ»ñZ%¾†™¸=0Ëê¼ÔB§>´wC>²¢½øÀa½øè>>ð)=íÕ=#¿=K$g¾Õæ·¾°ª-½lÚ»»D”Ï=ê1‡½o/U>4~†=PRƒ=LqU=w.i½Æ¤„>As> ‘ì½xÙ >Y{ ¾ù¸=wtѽ$(>±Ì>)¹Q>ÆŒ>Èw”=ŸÍ<4ã+=|2½9YI=,”½/F’¾ò 0¾ûµ¾zªê»Þ,ƒ>cä¹=˜!w¾=wV>­rY<½ò_;™AË>žJ°½Bœ>a©> �—>w >ËÂ3¾s,¼j᯽'êP<|–>þ>m‰¾«9’=‚<1>yè¾³ü2¾:Ä);ÆØŒ½r…=ƒ¶>ðçˆ;øœ›>ZÍýO_½>_>܉<^óg=iHÂ<Ñ‚f¼yP½;V>Pe >¦ ‡>Üï?¶½=°˜ª½€±½+M=O0¾­”½YF¾Ø „¾9êÿ¾Ài7>S•Ó=¤)º¾Œ=2a ¾À=Xa¾ŒñL¾V}Y%ù;v˜—=ñ½Œ=É}¾åId¾ F>2+¾^Dˆ»xZ»½ ªÛ½‹²F>ðEh=Ëp˜=‚]e<.> >��½©P?êa’¾…•½¹VI¾pXýLp!<…=¾R]û½9F‡=´.«¼åJ¸¾Ö¿Œ-(= î;>ÌP{>©M¡=Z¦�><É ¾™—á_ñ=µ¦>¶F£¼™ÿr½ÌŸù= ù£¾]§¾íª½P×½l‰¾ ¾.ø6=‹¢u¾“;(=>Š6Ÿ½MA¾·€Í¾�´æ»7û™¾)–ü¼-Yù½Ø`Ä>íiŽxd‹>Ø/j½'’"> y½=Ê—-½¨Æ>@.„=#„w¾€.z>ÿ¦¾‘ =XRI¾»zü¾8 @=q%³¾Ã+¾ –¾/õ€>*èý;V]¿=Ñ^ý=xD¼~â*½-„¯=ˆY¬=·‡¼¾ìô=£]�7‹‘¼FQ~½ >-¾Ôœ½µÎĽöºŸ=:½¦ T¼êÝ"=¼>¼œƒ;¾ Þ<(?j>ï¨::´Œ½›º»Ë”q½ôói=a^™>C(¡¾ð‚'>áå½gX¾� ¾Óâξ´�>? …¾uʉ>`,‡=�²à=”±å½ñ´½80>cÇW=‰>ÃV =÷àg><Õ>ØÝ™>ðê¾ÇW3>䶤>)&>åɤ¾hˆ1=*–¾Ù#ǽÝÓ©½u©‡=-¿¾½“Rð< ¢Q¾^†¾:#¢¾…«½Î6 >jmû<ܶ�>º3A½ö@©=PD¦½´¿Á=ÕO=Õ¬ê=§¶Š½f >‚=¾'SK>/Í}» W½·8оö±½Ü›™<7§’>Ïç¼ç—¾¿5ê=CÞ�>ß½ôþº=Gíȼ—}�½='¯>ÿ"„¾> -:“Í·>d;f=UŸí=Ø«M>¡Bà=jÍ>Û€ø½i¶ê¾í+d¾HäM>;ð½k£o>—^ã>Õß> �¾=¨N=$ >‚¾�þ³¼ç$Ÿ>Hú!½N~Î=@™¡=ö�=±Ji½ÚËñ<5 °¼f¾{ßh>�Ô^¾ÝÀ·¾jž€:”A־Œ–=·¬½¨¹¼£Ô„½ŽQ¾Î>>Syü=lJ>¨ee>½¬>YÛ÷½ rœ¾Ë>Ç—¿<áÂ=½4==¡ñ>Ù—¡¾›=Ó# ¼'N¼Ëa¿¾5¨G>§ÆD¾#·=b†½ÉÓK>VÚC¾}%1>Ä»8>' o> œ>ÕÿY=üEK½JÙ:¾¨–·½—�ͽj@ª=Æ–;×>³½Ñ‹;õ¸ã½�ñ×¼üŸ6½Kܽs?9ùõ=T×p><’C>ªÊ‚¼Jn^¾H$7>9®Ý½rØÉ=Ø›g½n6¬>CÅ'>I싾BëK>jƒ¾vc¿=ú3ã=-þ¾1>…½*@ª¼¼©=•¾sš>�<~Ñ…>fÔ[>›áÈ<“`¾lˆŒ>-VÓ=ÀQ¾ç7>/©Œ>7J=%”ཽ'¾þ^>w!C½g~<=6—µ½\tÔ¾4ö%>úüö¼'Ж<°·2½É÷;¾8 ½x›‰>ȸ¢>Ò0r=ÕÝ2¾%` =ã(=S>Û¢=ys¸>”¡¾¾`“ =¶‚Þ=oèP¾ïèO=±A"½‹W’>31;€J¾¹ e½h>Ͼ°Ó‚¾t–½qK§: 6>tI†¼¿£=„_u;Úrq¾<ÃT¾¯é?>–®Æ=åŒa¾påŸ=þ(j>ùz>)JO¾§²¾t¾f‡=ÿïÖ½hZ>†Œ½µ¹=Ð;¾‡Ã>ðV½âTz½4瑽L 8>¢ç¡½‚ÂØ;¹?¡;â½]¾�Ëù¾z<‚½k8=Ï:=%+¼O³¾È3¿e’L¾íà�¾ô³3>(,n>05o¾Â->À›n;k==n¢*>øªä=Çäc>ò®j>«Æ<§Î«¾¿3Œ¾Ò¼»Zª> –ð½唾ñ†õ½F¹›=|/´¾šŸ^n¶½oÝú=àë½vzû=T2=»‘U=ÞÍ<"Ví=ËL ¾´(æ½_¾Ö7œ>øÍÉ>”µ˜¼ab¾’Í=_ëc½­ §=E«c¾ñ;¢¾/E_¾Ú™=;<½‰l<¾Ž\À½–C>×úW>ð$ê½v…]¾ª€c;xGá¼¹X&¾´ÓÕÇ2‹¼²)¾˜}œ*Nø»»B¾oÕ½ªI½‹qÚ½*AH¾ŸK¦>Ê>b #>»Õ>2Xì>«ÖŒ=Û=Ø®½¦/v¾½„ ¾ §¾ž( >Ônô½`It>©ž±¾zä¾G2ê=üܘ=T#µ>ð É=H)z>Ÿ‰ ¾FF¼xGZ½Ä(—¾ ¼Óq».dÆ>?º‚¾Ÿ’ὦòÊ>—¦½ K6¾©Óô¼$g'<ô‰u¾±“À>ÈeV>iÐ:¾‚'¡½æz¾ðí<�„¥½ØW¹º´�ß½³ý�>¬³>Ýe¾ÎïN>Ú…=C"޾V—,½v4=Åá0>ä~Ì=Ù�>»¥¾,:¾Ö³=¾/Z¾Ò�A¼**u¾øW™>ÖŒ½= æ²;9°=ñOS½AD=§&¾Ù/¿>¯½–þŸ¾w…’='eþ='Z¶;wü³=¤)¤=�û¾±Äµ=´ø¦¾Ïó¾w~\>ù|¾”z½Ñ95¾¸%>ÿÀ•>?\£¾w Ì>PŽ>÷Þ½“_¢¾¨�½lbÔ=X Œ>Uÿ«>H�‘>¢4½$À7>| N¼¼”¾¢ëa>�›K>þàù¾æˆ�¾N$=¾™•�=쇽˜é;PØå½Äü–½C8Ò½V¶K¾8ås>Ù=¥¼„ÌÀ=¸Õè= ,ѽ @>¶ú™¼.¶>g o¾N¹ > µ¶<¿Û̽€úˆ>~§¾õ%¦=‚ö >Ø1>�¥=A“©=fÓª=s!@>ÿ=r¾Ãì,>Á›.¼®Œ>¸šC¾G‹>û`Ê=LÛ‰¼=ù’=l»¾|¶¾9z¾¼ÞV>åU3½‰º&½¾*Ó¾ Qy>Ô¯^>R/=“”оFª=i*½záö¼9mv¾)> q¾­9Í=€ô™>Íîÿ½ãož½—=P//>¯=}޾%ª½È]W>‚:š=“M±¼T1¾ªO>ÞåM>=ç?= ¥u=QÛœ>¯[]=Ÿd>h>XÓ<=Öá#>†Y™¾·ü ={’>ÚâZ¾•ÌA>/‹=Q_í="]Ó½�©ˆ>*Ù¯8œÞ>…½½Ó$¦½‘æý½J Æ>c>ß=µ»¨¾T²½�b“=d ¾©á–>“)½ôA™½�šã=snÑ:ÎØx>­ê–½,& ¾Š=ê=-ϽüÑ ¿²ÁÛ½.<=T¾á¨>sP¾Œ4‚;¹,#¾¡¸>>Œ‰>µcÅ<¶l{>ƒ~>ÂÇJ>Ð|t=03‰<–Kœ>îéf¼ýt>¯Áv½€J¢>A¶=Ï¥t¾ $Œ¾…¾F•>Ÿœ;½s½]>ö>¾Ø"¾6%œ½ÑpM½�½1e¾àÃ>ò'½Á¦‘½]>+vï=ªŒX>Ú‰>ÀF¾ªY”¾1wf¾H±>X¹ÅÛ�>À¯½gÈ >ýl¯=Ó;ƒ¾JÉX¾ ¬>s¢‹=;€>71<–xW>ôd¾ic;ð ü¼ã‡¼~#{>�=CŽó½gë¼Y¤ >#=>`Äâ>0“F>0¾„˜õ½Îl…=7MB¾€›d½‘ò­½CÇ‘>+Ò+½»ÜS½)èÁ=Ó~:¾DÌ=%‘?¾çžhÉÿ>ð’(¾‘=謢½&€i¾YU=5ƒ=ÝS'½8üi>á‹›>Á™¡¾�Ó�=ذô½–sH<èP¾DÑ<³"¶;å†;½Üñe½â·õ½SRp¾y;¡We>}xÍ<#ÑZ=F¤Á=�¾=k=Ú=ž&>®ÐC¾Cï\< Z�¾Ü³R¾jn`<•­>L\÷½¼²9¾4Ž«½³e*>%Œ~=´€½ôª=ßo‚¾| >¼r>á6�¾úù‡½­¾#iľ»Ì佺<÷¼ (9=|Fó¼(Qy>êo=>e.¹=.¿c>›¤Û=,>º>(èB¾q˜­>ýý½.£t=hž=ÁŠm>Udp¾Š¸ > >¼¼`æÀ½{)ä½bµ½¸þ¾5z+>õâ ½3Ù'½*cí½%Þ@<ÀM`½ÕÎ*¾ÔX=¹_¾s%>L!u½S*+>ž›f¾Á>t¡=±­¹= p‚>%nˆ=†þ¾ó¬{½ Èe>s^®=�Gz>Šlà=M¯€=Ó·¹¾ÓÀ2>…ÊT¾I®½×k…=ÒØÔ¾¥9º>æÚ¡¾SÕ!½¸‡0=ソ(\t=t¤=Ѝš=2Ux=�4>€­p=C×y=ݺ®½á.a>a±Ž½°ð ¾¿» ¼>5Z¾,½Dï>‡=…Úv¾�MO=n0›¾9?¾õÍ,¾÷5™>Yµj>À»Ì =×1 ¼½Ã=îIª=cÙ¾. ‡½øÊ¸»*Xê=*+)>[Òh>@I>‰šÅ=‰Åj¾e×ݽ˜¼Ž½’¤Ç¾›Îh>œw ½/n“>ý4¾–_¾“u¾M©¾½R€>¡É<¿Õ×¼Z„=öÁ_=Ý«š>š0¾m¦½…»Ó; ѼÍ{£<’«þºí6‚¾õÛÓ>uâ½øþƒ¾³°÷=C5ö=ð޾;.@=;i̼á‘=Íþ>¾¿É¾Âåo>J½ ·B½ÆUʽˆÐ="d”=ˆ’¾�j=ô¦†=Ãh0¾e9¾Î6¾ÕõŸ>|„¥¼ªš=Á4O>êÀ¾¢=Y¾¡i޽‡wó>Â<˽wÑ>п½•� ¾‰0—=™&I>´Þ•Ã�Þ½æ£=== >c�@=⺠¾ö‘u¾ƒ;†=xæ±=é|z½"Ï£¾SÖ½NR_>‹’ˆ>@G>DÓ=P½€¾} R>ƒdp¼+g>Ñ@#>cýÙ;‚„º=WS>>PÇð½GtF=›“²½ø#§½€�>‰°>ígF¾lž}¾õ®½Ù”„=D‹¾¥">–Vn:Âé°>S²Å>‚Õ„½ðÅ$ÎÎÛ>A›L>Ê_þ«Ó¶¼±°•=¢ºH=üV9½2ܹ¼iN¾£Õ„¾°?Å=‰?¤¾ÔΩ=Jk…¾œšÆ½ ³¾Ð¿Q€¢½þ啾wö¿¼¥Ý�=] Û½ÔØ@>Çsý½S†¾”*v¾›ä¾kJ‘½ªÂ{>›j½:b–?yK =¡ ½i¢£¼vW5½˜¯x>':P½Ož€>±å©¾ÙƒÈ>WW½PU>¶â(¾a<>:mç½E;G¾®‚r¶†=œér>÷á-=d¡>š§-¾Z®¸=q=7y>8¾ࣽ‰Ç/¾„…0> �>‹Ó%¾²g¾wˆ+>v¼¾S¢¾Ò«j>Ÿ�>ô)¢½ž³>Â5Ö¾�3></=|ýä=''#<Ý~—½;¾z´î½�^x¾1š#>6Ÿñ=?ê=ŠJ6¾� >„å7½ˆö½]`Û½É|½õâ/½¶‚>ü ¾§Ï¾¥²¾ã V¾Ræø½ÙÜs½‚%?Õm¾Á‚½Ü+ƒ¾•Â<¢⽉Ë+=L‰œ=(”¢½…ë±½Œ6¾ÃXU>$¦¾åù?-C7¾T4¾1ºñ¼Q2ð¼Ò’²=ä‚»>“ý®¾F˜Š¾>=v4¾{dr¾Vþ½¯Ö¾ÄEs¾!e¾‡W�>=Ö½‹ W=ËÑ>>ñh¾XéÌ=ŠÁ½#Ž>xC,==1‡=,�½è×=a•¾º²üB=¹õÆ=¶ß½¸â=D_]=u„>M@ø½²Q{¾Ž„>EÀ>p$>ÊFÇ=WzÞ=¿…k=bª£¾¡F¥½P�4½SY‰¾J}^¾ Á¾0 >YϽö©š¼Æøz¾ï;=ý‡_=OOš=¿‹æ=±H@¼£ðg¼—3r>X3¾¼ §= G•>ßÒ˜>3Ù”>j¯Ñ½ú# >ö¨�½l�Õ<Æz0¾_£€=Gð¾èœ >Ö©8>uS\=>‚>(�‚¾÷Њ¼³Ù¶=§e;¾ò¹¯½ŠÜJ>‰?¯½NCi½$b>Ü÷>­¬�½Ö¼½iã~>Gx±=zlì=zE:¼K_¾â)\¼Ôï=‹®Ê>J F=}Èó>AÀh>—š›<T�½ÕT½ ›0>Q³†½ð–˼iU•¾ÅK=X >6–¾Ù ½›ðp¼(£¾<^˜™½x½°mð=RY¾ aˆ½ô¿7 P¾¹ Þ>¼¾!…b¾Wä\=‘¼=ÎËQ>)¹_>庼Žpy>`—½B>Ïçǃ›ü¼)´>L`q¾:(Ê=$w>9—&¾ÿ>ç½»ûž>¢á5¾ì·R¾NÉP¿rÅ’¾U.¾2~>¨ù½™s¡¼¢Ã½Ñžü=¥ÿ=Q _>Ú¿=8\W¼Òæ°¾VŸ­¾ø'= ñÎ=~fP>Â}>@q¾ ,¨=n(l¾ä…y=ñ¹ä¼O¯6>~�_=øCt>s�о>™Å¾øŠ6½Cª¼ /¾zà¿?á>̾Œ;ë6¸¾¢´+½ŸÃ†=צ=÷Ÿ‘½†T¾Î%•>"ø¾nòº¼œ‚=åá>€øì¼'b?²Øb¼ã_>‹S5>KÅP=+žì=©¯=²—6¾w~×<ÌlŒ¾·-›¾?´Ü½?Ç>Ž'Ý>8þ½Å§>æÐæ¾Á²¤¾|£ô:VÝC=k“8>W½=¸«¾Ð->ú´U=û™½Eɲ½n·(½ʧ=MÖ=ÜÓ>Óÿè¾ÎŒ>LTp>CÕí=8ù>võô¼.¼\O¤>wX;>³½±1�¾VZ>Rzx>Ò×½:¼¾rz´>ËAî=>rU¼éC¤=À¨¾ÅÁ7¾æ8¿¾R²È¼ÒfÇ<éh=}éC> zß=PG`¾k,š½°&§=°9>�!u>÷$>5g�=‹£q>mè=Ã:¾5Î&¾7ov¾)gî½#ݰ=•Ó¸=¹&¾8«,>¡në=Ý�c¾�ÓË9p´;)¹ž½ ç>qÆ>©ìÓ=ÐÞˆ¾S0¾†­¨>ïS¾½:õ=d›½ï.ʼ¿xª¾ÁÊA¾ÉÔ6¾„0þ¾ÃÏ«=³ ½œ¢]¾‘À¾Ã<¾5=µ¼ŠYÍ>Z>WX�=9K(>’ˆb>ôøŒ½È;(°I½CK>pÓ©>Õ×!>Ý(�¾õAö=Áì½_þ^=Ÿì¾÷ˆ¾Rê¾±5νìÑ“=nª‰=VT½K\=½Äû>?/“>Jbš>ÐÚ½ù1â>çÈ“>™ò=põ^=š[>ÑX†=sÚì=¬yY¾lPD‚Q½^_®½.†ˆ¾Â*S>Â˼Øý*»ß€ž=~7 >ÁS¾ +齈æ�½üÊ:¾˜>ZMŽ<�ëľI)¾kl¦½µç½2×ë½æhñ½î²•>÷a¼¸Û=_&I¾{Þ�>ó‘‘=�L—½Œu¾tÛT>ÞŸ=wJ>`º½QŒ½’3 ¾PöF>˜¯½²cî=*¾ˆ_˜>è�à= ÊÎ=v5¿¾r胾”ö½‰Lˆ½e$3>N[ž¼X—¾‘à…¾âù×½žr»>Ò¢<Ë2›½ÍïÜ=5f>Ò >x$@> ½XàD¾ŸIN¾ÙÉоöe=RŠ#=²¾ï½})¾›¾Ã>nþ¨;É<=ŒŽg¾?”!<F¾­{D½Øk‰½É]Ä<Þн>‰>\‹½’ö½@¥÷¼Õ.>$L>Òˆ{½Ì«>ý> ï">�K¾µZ’=ÝÂä:;€†<Un¾| î½EÂO¾Äh\¾d�?f·Ù¾©5>à}ì½4�O> 󦽑²Å½&½í½}ñÇ=W±>>ŠÚ”>*k³½Ý(M½•?¾H$>³½¾=À=mw=¡ý¾⟾ªN¾²)C¾ÊÈ�½�Ëø=f-4¼‹[}>Nñ¾.¡=¥^½õºN>F^U<À¨ =âyÞ·l[>ÊUÜ<‡Y÷¹IƒT=»|½PÈ)¼�l=�ŠŠ>Ñ& ¾W»½�ª�¼µí?Q¯=ˆKs>dß�=´gš;}’†>~´�½ýÀN¾X„=˜1[=Ý)½]Lo¾k=Ôfž¾.zF>Zìâ½Çñ >FB•>ôãÀ» Í>§|(>$ª„¾Ñ᪼ Ñ)¾W{¾Aì@>8Œ¾=‡ñý®t3½2Ða=½<·½AÂ>DÅ)>€Ô¾>ÏæN>?†¾/ñ =ï-D¼¢½ìír½Ù°ò>•û½Ṅ¾v¹’>4s¾oM&>N|==7µ>xl!>,Å[½Èc>>Á ¾7 >úÜç½ÉÆÉ;Žzx¾3%$>u^>n%…½ ¾9=v�™>ãF¦f‡¾]þ?>i­=‘°B½4ø¼Î½¸u¾=�Üâ½Ý}Î>{·»¾¯M¾†ß˾ï;M¢´½÷ÌA½0¬ú½×óU½ê,¨>±Œs‡§^>¶—-½å:w¾/©½ag=9¸©>ß ¡=0d‹¼Ï,ô=$%=4y>vL¾’ à=Ûd�½ô‡¾p�o¾´Ä>À±¹¾Ã?.>ònÊ=Ñé[¾7Ú¾|µ|> ßœ=~ã¤<Úúf>w±Ð½â-Ñ>… >²"Í=3¯,>:é¾*�´>£ÿ±<Òù¤¾ø_=$…�=Œ‰Í¸E=ïˆ={¾Á+©=Ól=} =G*[¾~a->xÂç=“¨�¾¿1¾#á>ËD¾Ã�>®·�>󼿾%Mâ=æL=Þ(>Ý r=&`½y >µ� ¾Üd4>Uµš¾¡¿«¾ V>u4@¾4˜>˜‘½ª¿d¾>Êœ¼�-¾u/?§;;=i+> ¾ƒ%´=à >4È >°óU>§ÃÚ=’ªJ=ÕÏàØü(=K6¾â ’¾,$^¾l›�>µì�½ò p¾Fk¾ˆ ;À“ŽT³°<ÎÄf¾Û>£÷i>Ž‹ü='±Æ¾Ô¨Ë½Ü\ ?€KA>gZ»=¼ôºÉ�j>"£Õ>úÛ8½c¤½ºóÊ=~t=n‚f>íܾèÑ�>{¡û=æû;Ô§=…1¾'Ê=½&%>´€+½¡G/¼HÊ£½ƒvÓ¼eßX¼rÅÚ=”ša(>¾^R=Tõɾ–¾bá;ò·´=9EŒ½-¥ª¾Ï“�½gê·>Ïbö¾µg‡¾Z?>ì� ½b>>uʾ0Љ¾0À[¾v:(¾âµa>Ìç\¾  ¾=½ ɼÐ.¯¼¡�ží}>’‚={¾ÆG�¾ õ.¾Dº½g9Í=9LK>Õ΄¾ÛÛ½ü“ô>侕U>x’>Ô_ ¾™Û=@½„>ð,b¾T¬�=éð >~ê«=ïFI>-K¾ì4¾~ s½0sl6B¬=Êw-¾×„W½¨yÅ=ÒK=Æïá<�Ó½†—{¾ñ¿½°®…>0î;B®¼H´e¾!=¹»G>¤^y¾i µ½„�м89]¾eI꽶Ʀ>z©ÑÖU>ó3½ø˜¾I–½¾¶g½~X>]´ø=rÑF=¸±>pËë½7(™<¸$¯>G¾.»aIh»Ýĸ¾E!0<Hª>О¾ä¤�¾Ce¼êN>‰-½©Åÿ¼™"G=VKP¾õ^Ê< À>>½ >Ìh…¾ Y'¾¹3£=*�¯>’Io½|¦”¾!ÕZ>^æ> ¡Ñ¼Ò½P&P¼ Væ=Ÿ¿“Âu•¾Ö’3>úe½:¼½Mh)>\Hö=<*=I¼=4J?Þ4¾xŠ.= Ï×¼‡5¾~þ+=–®×¾Í{y½ÕÁá>žiS½<«Ÿ>ã;«¾Ø‘á>³.½ƒÑP>–Å“¾¥k¡½žH-¾,ˆN>_= Zš¾°È³½«[£½ã#¾ �¾À­+>ͺ>—̼Hïç>Í›J¾·«=p‡l¾ª´Ü½Œ`#¿à8£>ßȾ4 ú½k{­=8ŽÎ>Eg©½±9´>�ç=¤Ê‚½‰Þw>ǫ̂¾u�X½Øñ„½§–©¾£©¼=÷š¾¢ž>Öà†>ɪ†¼‹?Y%#>ƒ°—0þQ¾6m™¼žD�>uÿN¾c3½Êñž>ÁŠt=7Å?ݾ ²+½D˜W>n="¾ÀÂö¼~¼B¶Þ¼ÕQ•>‹yw¾3fÊ>Œû>ÐŽG¾¯Ñè<Éa¾W[½qM=s==ëã¾î±=?µ¡>µ½š:,>÷Ç8½"f<Ÿ Ð>b¸C>òªÛ>Êé‰;ç >Ðïþ=硨½‚³Ó<ªË½~ºù½]Vk=P€¼ù­¶¾Õ"S¼Žâ&¾‹Ä ¾,§¼¾“¾jÖ<>' ¯¾Fz½°L¾dãÜ=[Ó¾’&Ñ;[ÚK¾ú\¾ñŠl½‡%=ì„°¾kä€=¡.>¶U»½7U'=œ½³_ ½�Þ8>(ªÏ=ܘw>íë=¾W\>‡¶ú=ðV¿¾V¤ã=“Ê’>LbÆ<_m¾µC¹¾kYJ=„;?=ö«k>>Ù¿Ï«=I¾ê*}=d=¾;/F=1Ö=åνŮ>¾gY>Ìu¸>hór=AD¨>]ýŸ»G_½¦=JÆ ¿6)£¾Îžœ½½?¬G¿=ãc½PF<*ú(>{W,¼ssÙ=9]ˆ¾yô]>§o‹> Š¿œ«½2Š-¼Ç«B½@Ð><á‚»Tê¾>WŠ>>½rj¼¹,7<¬Þ?ç+Ÿ=®H–½I ":½Ö²¾‚�½[¤;>�3>O./»roò=xûZ#¾º'>·;S¾Ÿã1¾Q³Ö=èS:=Î++¾¿o¢>h¦>äs ¾{L ¾Î¥µ¼Áã ¾/@‡<(9f¾òš/ºÀÛQ¾J †>@š>Üȼ�,^>.ɬ;¼•¡¾î™>¼f¯¾qõѾ®C‡>G(¾úz޾I õ=í§8=^Ó�>ªR�>‹ ?N-¦=˜¡Z¾$?>òX>4¥<,—}=Áxî= VÚ½•Ň=®|1½çÀ>±¦½“Ýn>u3°¼‹j&?HH ½2�Í>Â:>/¿§½Hc>޾KÂN>Z¶“= ½Š ¾ÿkã½ùaa=,á§¾†5É=h×7>^.‚¾Nç ¾{ç¢=§²|¾Š³g¾Â¬®¾Ý²C½v M=UR>]øí=«KξË->bl+»Ýh—¾Oý>b…ø¼à>”ß½Ê`�=S§„>�ö½t;X>Û6>¤gÌ>|à=äD„>ëID=ô¾|®>åÙŸ¼km†¾!�‘¼@˜< h�>9Äi¾÷åe¾­—‰½ý¥ý<ûž:¼·>øí ½z ½UG>�²³½:ò&=“ š>2Dò= P‹=êt>óä¾>MÝ£>/Èu¾'—ļ6!=»È&>ºÔì=¦¤/>¢Üì½�µ=¦‚�>ºê¨½lt]>ìR^=žÝ—¾Ú•U¾Í�ì8é>И¬½öh½¼§¾úÿÏ>^¯ ?,Ê >û¥R>Vè¿ÓÔË»Oô ?tÂK¾6ÿ?¾¦œk>Rõ×=æ¾H6C=s|‘½Õ©T¾?¨š½‚.«>_õ�=U$W>B–v>b¬=w™"=~d®>74<áÄØ>òüò=ÓöÓ¾ì À>Óf"¾l\=˜½¸ó¾=¬ðž>`Av=÷s½=ÀLC½¨>~ç7»3€ö½ØMb=ú�=Ö÷®¾1 ò¼U€g>IÕ¬¾+€^½§e�¼Ñ .>ñ…¼öyé=°Q>vÂÒ½öÂŒ>å´Š½ª¿<[ª˜=„È>Mh°>9|½b¸š=Æ´é=»¯‰;ùeG>cb=!¯ì<Áj¯>þËi>@a?©äP>†w?7§®=ÎÛ¿G&d¾;-½{eì½:×½�¬{=�~D¾C`0¾µø×=6¿Gë­½jÔ¤> „m¾¦v£½ùùC¿jƒ=%û‘»?æh<Ã� ¾¡À—¾´ze¾#ùˆ¾ÄIs=lMš<>‘¢»G—[>Æ ¾ãK¾l¡+>…ré=!ª>Ù`>ùÈ#='³{>ƒ|¾òw¾ö4©>¬Ñ¾”ÄŽ¾­ÆQ>éê=ŸÙ“½í ½*~޽&ã½ið¼Eûi¼m±=À€ý=CÅÅ»>B¾aï�=ØR >u+¾ó0Ò=“°J¾r¸á½ëÉ=v%˜¾è‚”¾$>Ýï¾ö—¶<˜�:<ñÞ›>-ÇK¾}Ì%>sÛz½'÷ܽ<俽¶­¯¾“à¾X°À<ƒBk=Ýjq>[¾àjï½&“=¾25µ¼¨î|=Z§>½�^>Þ …¾r¬O>C÷ï½ßìϼñS=Òt,>;¥>´›¾V\¾Ñh´=íc> ¥};Ào?½eŒ‘¾âA>;žm=¯Ú‰=šÊÛ½°á�>o27=Ás?=Ëà>@hM;¢�c¾×ŽJ¾ì5½�Â=_“ؽÆ^½½BÔ>Vィ”¾³¦ ¾·Kо'Áí>4tȽ�Á=þ>{W>†ç>==c>$É­=×Õ¾$º†¾øœÙ¾F¡=¦ŒÛ½¦çÏ>ÐùY½Xƽ»î—=®ì7¾~¹c>K»!=(œ…;&²·>xp?DßÙ=å§½]”]=<[<}õv<Ìi=M‡‹=°W?�ê~¾o>ÝVŒ=È 4¿ î'¾ƒÄ0>n*¾*D ¾O~3<×i9>Fo#>…>H>«¶á½BÓ>7¸Ž¾"?JU™¾XÛ=,¾d\b¾ƒ—r>�C�>‡3@=Œà­¾]O�¾¯Ê!=nìN¾�š½5Èø=¾Ì™>\ƒu¾�bZ½z„9>ôK=*¯ =T°½x/>ò|¾Ï e>®¦¸=Rû�>GD½P̾Ðåƒ=–|˜»&(Á=a½­‘’<ž¾bjƾè~C>€©=ޝºÈM¿wžê½ë¸È¼î¾ä»‰£F× >@“¾NŠÂ½f绾-×¾D<4î0> f¾ Íå<*ß½„ÄÆ>JU�> i½=z?>€]±¾Ð ¬=¬·¾¤ÓR¾˜§>�aH¾Ý¿Ò=,3n¾-`Ó¾Y‰ ¾a8¾Åõr>ÿO?>5M’½«ò½¼ö+¾àœ½ˆÚ¿ºŽ‘> +=‰”ê½ >°¾aká½ú0@< >t—Ǿ�нrÄ5=@¤d>‰ö6¾ÄU>kP>< €>Äß&½MÕr>~†Ž½h&?<–¾Z½•¿º=K¯>äkL>,Ÿ¹½Ó&S=”¦ö;c\|½CÚ¾�ï=Ψl<œBe½ÂO»U¥>Ú}¦=°Ì¾$5>ÀݽB–m=$½ší¾Áµ->X�¾…�7¾ˆa/¾ü¢F>ÍĽÚæ=c3¼>öþÿ=nï‰>ÏOJ=þÓ”¾àŽ‘>$üg>sx>lóv¾²r˜=P»›=k5S½(ÂB<¨7$<B¾Ü“f>>ξݔ½æÃ‰>oÓX>¼ þ¼!x¤¾ª!Ú=…Š®»šî½ÅÃ&½ör½>«½F.,¾¼–>/µ›½†¾Å3>ÿF¾ºjd>ÑŠ7:ð‘¾&—Ѿۀ{=©U¾£Rº>È>AU>Û÷ž<çar>ÁQK¾—U=¬–¾—Ï>£Ù>ëÐ×=¥]S>eÂJ½Ô1Þ¾R=�@u= þ¼I]ü¼{t>Q¥>ä'¸¾=¾Ý}T¾Z¿û½‚EÜ>[ç–=™®s¾R†>óO‹>Nò¾`è>uÝ&¾o9è=,+=—�¾´Þ;¾Vž¾ F‹>Ù0?>j:˜½roǾñk?¾GÞU>FÏ>Rn>&¾NóÑ=¨9D½Ž3¿Ék¾ç'’>н ƒ>”ÙC=Ãó5>ñ0a>G|!>20�½çz=Xª¹½üƒ‹¾´› ½ùÜ*¾\Z×½O¯¾÷¯í=ÞP¶¼Ç*A>p.ͽSì¾™¬½ëÊ =÷ôc>7)¾žCˆ=›öJ¾­:>A@ë=Ѿ†$¯¾ngÓ¾5j=Ú�¥=hkƒ½š%ϾÙáŠ>Òó–½AÓš>´‹¾fµ}=>[y>ô6½@Öd½¥þ§¼Nž¨=0Wá=’_>N;>x wlÎ=Û¸7¾f€¼=�j¿»²aܽ? >j‡y>‚¡´¾B7¾²9”¾¼Ò ¿3€b¾fc¾Õß8>¨ª¾•a¥¾„w·=ŠË˜¾`y•>Ûÿ™¾¿®t¾áu0>·¢…»§úL>ÛŸ>&ÓÍ=XÙ·¾³"¤¼fbR½xQ\>Pg›½Ä–>¥�›>+�V>…S"¾©{=.¦¾(/d>Š€g¾ur>å¾h|>t@¼á‡¾¥Ù ½µB¥½þ— ½v<|>1z!=R¥=þ=¾Ž¼½6½¿½cX½;Æ?y ¼£"´>`l,¾8e >»re>‰½“ >=äqb¾Vͼ³•=jì1½¨Þ+¼.B ¾rÃ1¾†KB>/‰Ì½w#ƒ¾¼}v¼�S¿„„U=P•!¾¢>X¾=±‰î>Y×-¾˜Pï=|¿¾‰#Ö=˜hŠ> k¾X®›=n4‡½¼¯²½ÈTå¾^eŠ>cx†½®71¾vÕ¡<Ä�½¢Š¾¶gŽ>2�=¤=|ÛL>Ûz >©RÚ==G£½ûó˽ÏJ =j$¾:¾ù¦¾$g‚¾Wª»ß€o¾w¼�>†¨Ö<‘}Ÿ>�ªü½døk¾Wn:¾xÑb½-.¾¤p¾=v´½L²+¾^l)¾‰Ã>¾P½Ô¤>2Y›>F|“>£a‰¾@¤ä=»²1½‡×Ÿ½ÁÁ½úž|¾§3ý�¤»½æýz>9•«;Úë·>06=CƽByß¾*l¥>_ >­Û½æãt¾(¢e¾{5E=U é½ïTc¾æþê½�½0¶=pk¾ÉÀ9>P8B¾|lL¾dP3><0 >˜ôE¾h4¾‰Z> ‹>F5>¼@ؽ4m<ÊÖZ>®û>Ç’¡=IÜä½ è¥>¦Ó‹¾Âóò=ÜWr>úp¾ï�>øk¾m—½Áá²<�,½!>{£@¾ "å½$ÝĽÑÒ̽v“>åŽ=s¼=+‡•>'ü>ÕÊ\¾âr�>'ÆK¾º|>´¯=å­+=ì%ƒ¾[aþ<ÿí�½7˜è½·“Í=~/k½8¡Õ=1d¾­ì>~„Æ=2 ͼH ¾Ðñ:¾1y³<7¥¦¼iœ>ÔŠ>PN轨ml¾È8O>ÝB¾s©Q>k•ž½�ﯽö1¾Qùý½?ê>Oh'¾_•C>þG>™Ç½…±Ý½+ø¤=0±~>aÉh>EÈL½@žÖ½Np¾©Pƒ¾;�̽"H=,�>@5m½°Ö¡;y,¾À¼<>³°Û½ƒ¼¬¾àÊ}¾ÙÃi>¡›×¾sš >y±0=J“À¾­¤Á¾¯Ö=vy?Å8>ßp>¾%±½í.¾Hov½0Û+¾å!¾Ð¹ª¼nôT>·,‹=t>oÙ(>$Ľ¢í>éÆ<Ï4$>É}…>¢‚>>kì=ᚯ>4h>>þuK>LÌ>Îma>2{=9âž=øXº¾@G>ùI ½_*R¾Â``¼fÆ!¾eð$>j‹Û6>¢‰¾ƒæG>P=_¾k€=>ŠtO>’1»üÕk½A½¤G>Š >'âA>9­ <«Ap¾ƒÃš>¸EZ¾Óx¾‰`W>Ma•<,xP¾Jð">«�f=:¦K>1Ei>{ֻ릚½4>¾"¼¸¼Äs=ßMA=PÔÆ¼§zâ¼q@ݼjÎË=2¹>V‹½j{=¾«·ª¹£F> À>EБ>mmä½¾çp=ñóp={lÔ½´k>Iä}¾.”»VRè¾#i½ãÞ꼡ã#=[Q> O]O ¾�­ê»Ò”³=¹Ž�½Ø™¼›ªë= 戼9ýd¾Db½ÛFˆ=fU½]ؤ>~ø×¾öoˆ=l>kDx=ôä½Eýµf*¾š³ˆ=³ÿ”< >³¢C=­±�¾*]>wœû¼ßM�¾}_>yÛ«½ÒÿȽ¼¯—=¦o>â婼¦¢=ÛÝ>‘¬=CÞ-½V“>LMŒ>„«O=Sç¾*œŒ;jÀ=)Z:!x½§5š:Qô>;Äc½îC¾ë‚7>¥"ç>gY/¾-j½È^¾ê<¾ì¢˜¾Y¹½9–Ž<ì©Ê¾õN½U¤¸>¶ª>it&¾Ze¾½SJÕ>J'¾^]N¼q“Œ=Q�>{™¾Ê/=eˆ¾À¿^>8W$¾�•›¾ 2¾¨JA½iA�½:Ÿ ¾U")<™· ½ßœ¼Q|,½ßW×¾¶Ï޾¾)¾Ûœ=�—P>‰*„>òý¾•ù+>jŽT¾ë¸¾Dt">yA�>„ÓÝ>j\$=� >®‘©¾îÞd=›d>e•½ÃÎ> ¸)¾“œ-=þ·^¾awï=YÝ\¾(O>¸‰>ÖZ¶=\AŽ®£–½ ½>F=e �¼X³$>{Xm>°ƒ½1"¾‰°“<2¸ù=j›"¾�›½œTØ= ±¼¯¼Ú+¼½€®©½ÉQ>ÆÑ,>Ê[þ½ÈH@>†¼>y:G>0L¦>_ã>À_¯½ç,©>rp4½–Ò1¾øÎk½5’½oÉ<>¸Ê¾ë¸!>ø›E¾@9è½ÍPP<Òi¾»ÙK>ê©?ÍeÍ=Hñb½&.ؼV]½añ=øTa¾yxš>_²L>tË·½æ½½7:þ>’`§¼¢�ƾEsc>—­>¹ë©=›'=ö[‘½æ�†=8®ö¾™€¾T`>��´¾CŠï=a‡w=ò"¾é£½EAÑ<T¾ �>ì�y>Cý¸¾Ðð ½ K¥¾7,¾j_t=š_>äA^=ž†­½ø9U=Òê^>’“#>ÝŒÁ¾áŸÖ>Ä|²=�ÝÛ½�6[¾’z>�&4¾'n>­¥¾üg“» ¤”½ÍíN>/8>dõP½ñ£¢=Ec‘>¤'ã=GÓ¿v©®<ÇA> &>‚š'>-¬¨½@×e<*õ•½sè4=«Å—>Ðj ?L8&=¼2†>>†ñ>õé> ]¾4¡;½ˆæ=ؼ>=;øØ½8Ô4¾ªGï½m’€¾”��=æ‹J½ùû¾¾Äž¡½å4¾œÚ#¾3‚˽ªnf>DWn>Ÿ\">ŽL >'KÓ<›nÒ½ø"$=ÃðU½âJ½=½¿nþô½»Ü¼¾*0"¾syÉ@¶=}îÀ<d�¾{ZÓ¾èí†=¾ ¾ÐL‹>H�=*œN>Ò}=¿Ž>­—>*¯±>}ð¼ƒ( >¿Äµ>¬U">1ï·>.�¾QL¯¾õÛ¥=á¼–½�““>øš�¾]hQ½dü ¾Ú}•¾êuw¾Çy>· Ô½*Ï> y޾ /D=¶.å½@Ñ=ÀuO½Æ’/¾éÔ^¾À1£>*‹¿ ¤½�ì½l;>Ût>¾F'¾Ç¦g>xÀ¿¾9½>o‹¾Gj¹=;M[¾SEg>ÁM@¾‘WQ¾Ú§Ó>U$&=´IL>8ÿ½Ht¾�÷á>Ú‡�>Ä>8½ !>O �¾Þ’&>ƒí!¾!�‡>¡u·¾zÊ >ÿ&'>˯½P˜>Yt >¾Ù’=T<�¾É²#½oHê¾ÖÇ ¾ÿw¾7Z>ˆH¾# t¾90¾Š@=;S>Z°ÿ¼ÌˆJ½õ>L>$+�¼¼º;½¢>`ÌZ<5äo¾�B{¾ç¾d¾œ¼\¾÷O"½’áͽp‹•>¢âѾAÓ½=íM<½û[4¼…—½[.>Ü­�¾§ÍŒ>޳æ>iBg=ÿpò½û¥†>Y1ì»M´~=:¨”>™X+½„x�>Û.è½4,¾ž³Ü>€¬¾(a(¾sLC¾º">/¾€UD¾eN>¹~<}ä•>é->äí°>—:'=Ó÷>UP‹¾ËAg¾XS¾�QA¾Œº¼úJI>ª“ü¼Ïlí¾`å�¼8íȽì×Þ½¨/’;7ûR>vh¬<ˆ¦Ò½UŠ?½Mq <Âá½K>²GÔ=¼�‚=éË>K8¾”ɶ¾ Lª>¹¿në�½Ñ^ ¾‡¼ u ¾‹~f¾êu‚>qð?½\†L¼MÌž¾|íœ>ºÇ¿•…¾_Ñ‚¾Ø ×=Ý3¾"‰à=T׋¾s‰l=ø1�=HR©»Vû•¾aÏA½ ¨¸=”¾Y¾Ô“µ½úªD>kÀ=c@4>U „>ª¼;>ÅÌ.¾àÌ�=4¼�Þ˜>Æ ¼`—7¾çjö=®…=€TϾ5³=ârW»z[²>MƒÙ>gE>‹åÚ<Ëûi¼A—·ç] ¿Å W>?ƒ=rèÍ=Zñ½“Iš=­ç7½7Õ/#'>’ >ÚY»Î‹>ÎÎ >?྆PX>šç>˜Rµ½ƒkÞ;Úѽ݋$=/F>¯l=Å·>Zûn>S“c½Šq¾"‡°=;¬Ø<|}È=÷u\>Œƒp=´I¬=lBr¾É¹ã=lA¾Ú �=‰o½'Ϩ¾zv>£šõ½8š<Þ(½V/¿>—¾1f=>Œ¬?>à:=õV±>{|¾Žë=p#¡>,l{>í§ò»–Qw½Õ”q>¯5B¾¥åh½$¡%>‰YǾ«R$½’'¾%�ô¾ˆØ�>ð¢>›=üp†½«…@>`Óv¼‡�f=°Ž.¾{*÷>UÉ =a L¾w_Û=s]è=÷ví¾ÀòÍ=é; ¾w–>ò8Â=çf­=ÚP¾%QὊ®V=ÊÍü½€µÅ>T1á=¬á½PŒ>¥Üæ>y \>’�À=]ñ>Û>|°> –‡¾V÷ >M;¹<~kí¾cÒ]¾ŽåÇ>œr.>Dˆ®=‹I�>‚od>ÄÕ²¾§±Û½ Ýì¾Ûâ¾¥ð>Mª¾ÁX¶¾Gòè¼Î¦ ¾vJ ¾Z8â>ñ2j¾€Gã=-1Y>N$Í=ûJ>¿n ½U'>¿rz=W¼á½^�¾”¥–¾oÛ=Æ97»¿r>FÐŒ¾™ðe>¬~¸¼-°§=MÚm¼t¹_>L_Ⱦäz¾H#´<Ü Y=›ßš>Öp£>BÓ=ŽÒã½wv¼%õ�¾1lÂ=GÏ,¾=Ð>�€$>qô>1Ǭ¾é§>bx›½½™*=`K¾V¨�=jž¾ºÜ½Óg—>8¡5½(~�=Âl½v`É<µ>™<í=t¿À¾@ j¾gf¾IT=övf=0žé¾ ý›½T0½j3 >´Ì=}ïZ>ßðŒ½ûvT¾$‰>¯‡>‚±j>ŸÜð=‹ѽ;uc><Å"==¨¼=…q=¬÷1>×."¾9Ä<Ô�U¾a?>;ޏ=Å‘>"&£>ì¤*=±v ¾nÊ ½¥“R>^±u<‡1î» qŒ>“S®½æ^µ¾ªL¾"b"VšÁ½7ÇŸ¾Ë~¾ÐF=j·Ð>èõ¥¾Á7>ǃ'>vO¾8$o¾ïzý=zŠ>'4¾_‡¿½msí½÷ç¥=”§“=Çä"¾a£¿@ÏA>Xê§> oH¾Gs‘¹™Œž<Ëó>rò>X¦#=ʦ‚=ZPÖ½ÕGQ¾÷¸Ü½zU¾øÅI½&U3>æú©»”+¾Vs<�”˜»õH}¾“q#>P3…>bðU½rl[¼î—.¾°S>‹ż&mx¾êsÇ,EÔ;ÈÙ½› =å}½KÝü=ã”;>K̽nk5»œ¦½»ßL¿,|ö½Ç%½bw=êɆ¾BßÖ>,Ž ¾³Â?ž½ašÎ=ž„>J”’½¦&>k*…½“I¿;Üðô¾µ0¨>Ssо¦&'¾ âPºI)=>hN=¾žh“½°O=ʺ=H%=‰â >ëš= Q{>Dl‹¾‘?̾Œ=¾JHÜ=i—¾±àݽ�º¤¾Ì·¬;Í<™>æîN=k>‚¹D¾WFNÉ;¬<·gÔ»„cͽí;>î„'>dƇ¼8¾Cç¼ÒÎ)½›ê=Nª‚¾vêK>£$N½_£¾%Þǽ¬Ç>{Ué=1Â>2KAý¾ —½©C >c´ >yæ=×®Û»Êêí<8À�>œ…н‹I¾²~ϼ©½ œ¾àZ>£&×=K†ž½Áß^>úp¾mÀ7¾K&=ºjR¾³ßð;~~½>·¦¾wˆÊ=[Ù�;Ñ ¶½‹m°=oQŽ=#…&>VY½FYl¾·•$>öéJ¾ü™¾ i>Œ_ ¾¥™A¾›ý >z³ã»ûòF¾�K‰>][¼(® >ÞÜÍ=oP›=Ðö�½ZŸì½Û(-¾â²L¾¥Ê;GÓ¼æê–»w�¾·æ#¾Lvº¾T¹>Ê¥`½�ðC>Å'¾6xq¾^e7¾Dþå¾ÿ«•¾p‘t= ÅÚ>xB>†ñ”¾ÛÐ6¾Zp»¦…õ=‚©=bÄêk5à½ðs¼Œ'6>¢ô=A+ >@ĽE1%>¼y›=ŽP¼\ f»3醾%ÜÃ>ŽÐ¼\>Äô€>ç®’½p¤¾pz†=kG‘>Gï>$=ëO=HÇõ½&û=$c>Æóù¼)~Í<ÉÂ>o=½ ¾�wY=ç=m¾Öñ>ÇA¿bR§»Áo<Û^Ñ<îºÂ½pÒZ>Ï÷->.ÝW;8ºÎ>ʽ¨‡½Ö),>6þ># >84¸½v©9¾=nâ=_?ô½Z®ü<[j¾ZÙ×=•Ëé=7C²=8îð¾k?Ö»&�>˜yJ½³z¹=äïá=Q�=³Ñ >Ñ^s½Òøµ½kÕ+¾-=¾˜L>¡Og>é¯=˜i+¾Ë‚¾mŸâ¼Œ¾þöï<†j�>=gŒ=\5>cÈP½Šb>WMâ¼+1¾–@ܽ¿ =ßÏ= ÏÓ¾žd=û\Î:*޾ƒø>ñÃ;•»Þ<À&™>ì6;¾þDL¾Òä�½ÿµ€»#¯ñ=Üï=» ¾=ÃY&¾Oé>Š+>Û&d¾‰ÑÑ<ïÓB=Êȉ½|´–¾-Ä ½ÀW²»Ï¿^½=œ"¾»™U<ö¾5ü�)=¸qµ=ßx¾†¿=½Jä>¾ŒÇ¾ŸôÚ½¸ƒ¾Iäv=Üq‘¾°OÁ½,ÿã=/–œ¾±±:¾w*=#‹¾C F¾á¤¿½|[¾�ó->‚šþ¼òª¾[I½ð&;<´³I¾£޾^6V>Ëà-¾¬Ï&>朽3�½Q<Œ½"d>Å蜾BÅ;äµ>±LC>O™=µŠŸ>ùÌ>x¸˜½f¿ö¾ŽiM½ƒa?>’Hò½QQ.<² ¾æÎ9½‹‰¾Á_½½›’å½ 3¾à„v<¤3¨½Ž…d>sÁ™>ÐR¹=FRì½Eèq>ÙG ¾­ß\>i.f>Ù¾Ó’`>öÓ>Vb`¾8ò&¾Æ”¾ên’>"¡þ;vpξæP>¦³@>oè ½Œú¦¾Ý1O¾0S/=s2»1�\¾×b¾©)‚¼"à‡¾À•A=Þ&ò¾r™A¾ë|>4;ƒ>äìQ>Þ¶*> Æ*>Ù=,½¸Ëã½·$Ä<:ô›½ PM>l9´=ÛúÒ=Pe>n¯E½Á¾>Eth½£"4½–¥¬>¾ñc=*mN¾"I=•çŸ=•�[½;§Ý<'¾©­³=•t¾E ½�©Ú=ƒžÐ>§>⪽¸†;«™õ½_æe<ÛB=½¯�Ç=fL6¾ÝÇ=đؽö`þ=f5=^Ý>÷Qp>xï§>±8ƒ¾ø“€¾LŸ>¼ú”>f Y½s�j>^˜ž¾�î½9Û¼�푽üD(=Ú«<`ìl¾‡€k¾HÈ=ÿ1N¾Jýq¾qÝ’¾a²�½JM#½E} >†ûν+ ©½Ñø ¾Ç..>·F/>&M6¾À{Á>»HÃ=å?X>þI¾CŠo>Š—/>V.û=·ìÁ=2¬>>6úk½[ù.¾\ѽ�.»<ÁݾÌPÞ½ô;­¾™çÀ½ó€å¾ò˜ô= Jã½�[¾¢P¼·j‘¾5jô=,ÿå½XнH³'=v»«¾ÇFH¾L¬äËÑð»&ZL¾þK‰> ¿ÛŸ”½Åd€½¢£(>[•€½TÈ(½ÐóÑ=롾�[‡¾´—Œ¾vSV¼4`ξÒyC>®] ¾³;E=HCc=b¬ì½î›§;|c¾t9�=n¯™¾µà½¿н¾ª=›qÃ=|¾~ù<<ã ­>ESÃ=M26< $H>°®©>£ =–}2¾½ái>X Þ¾bí%¾†ÀÙ½4w¾3‚>«*ì=!¸>¿�½낾¾Õ¾ßu¾-Ã×=%õ̽.%>ñ{:>?×[>g2ˆ=×å=-@/>lh >Ô@=Tš§=uê¿;>\>[Ó4¾èÎ<2UÒ>¶“f=³*–½¡fö=‰Ô�>Xàͽªq�¾† ‘¾ŽN„¾²Jò½0³4=_½î5=Sà>`½“>©ûs>1d¾©à=,ãʽB+>ŽÜÃ>_Za>jp‘=¨d¾p‰.¾ÍÓ�¾,Ó½ãú™<*Š’½ ÿƒ=éx>tf½×…>{>6$€¾‚}ѽ’í9¾îɹ½¼›=%•Á=Lç0¾ÞÌ ¾}@\¾L÷g>Ò+¦¾_½u>‹Å=aÈ.>#YI¾d&¾7p¤>èxݽk±Š¾¨dl½RDí½ÈÚ—¾IF>î•h>ßÍš¾ê]°>Ù�>5ÂU¼uUͽ©,¾®õ°½oë¾/=7Í:>´ž=žp¾Р¾+Ö½‰€P>™�yµZ—>¶·[>ëÛ@»8L•=9¥I»2¾H  =Ç:ýPUu>;ìõ½z¾Æ€¾x(î¼GÂ�>¾[€¾5„>rŠ˜º[‚½U¾U‘>´ÏN¾dfØ=x…¾ñË(<!¾Âÿ⼉eŸ¾²Õœ=y>=™¾uÚ=¦-r>3 $¾×ÝP¾ ¤°=Üá¼¶¾·¾ã#¾êù¼–ZU=̲™>·Æ=½e =ì¾Z� >xè=§Ÿã½G"í»c¡Ð=�D¾#v>™“m>¶®I½Ö`:>Ø¢½7ó=0ÿ‡>õ^¾ª0->Ýkj>®ÞÇ=J-«=b Î=˜ >æ£>Ú¹¾l>bºÂ>I²æ>^¹ß½íí�¾~K˜=á­=@�‚½c7a¾²Û:>áXî>Ü›†½ä®œ=KZ>�W3Ô…=�Œ«>"Üe>=ˆ =⣲=^¶-¾Éª¼Xù=ŒøÎ=«rb>wQÐ=ú‘>¢·¾½J`¾l¥¾k›x¾.a-=Q=>2`W½úQÚ½‘ñÓ¾þoŽ:©–—¾ ž>ç/Ë>ý®¾ ¥.=QÊ¿½¾>£® >!y›¾çÀU¼ØO<©óÌ=Çü0¾“1=óYt>…§K¾¯\½½1„Ý>2x>5u—<©2«¾š¿D½©Tâº2úJ½pª•=Ñ©„½_îå> ¨=U`n¾éá齃v’;"5O>‘ å> ½ý·¼ðd�¾]]¹¾ýÕ½tÈŠ>Lë˜=+º»½0Eš¾Ï5>ùP#=6üµ½BÛÖ=– *½oÊ)<2eç=æǽÔóŽ>�0J=9ÿë¾PC/½ï/§¼èt¾x`>Ã|';Lj°¾F¥ˆ¾b€f½&•´>1{¥=¾èG>Ñð,½o&*>âŠ>âNu¾ ù¾ )¢¼ù}¹:÷“�½^ÀÚ>T>Z'¾U>Œ>r­=Œ9C>·�u< Ǿ¤SÒ½ã7¼¸ÿý;`[¾Ø¡~½ycž]X0¾èK>½3�=03Ì>žã¾Yñ¤¾¶½’�Ÿ¾¾fÙ>½³¬>Ã¿Ž½-þB<&•½U,z¾  ¾?(Ë>žu=óUf>jù]¾¢‘=ÊUS¾äµe¾æê ½ô $>Ð*>Èa >v„h=ÿ*J¾�Of=“¦»<±Š.¾l7?¾-<¨=Ï.�¾i½\W§>Ȭ>§êàkŸ‘¾ÏÆÑ®V=�!¾'^A>ÉÛʽ4C >¯ly¾àƾç³¾>µ>|̾…;¾¿U•<´¦ù½N`N¾f¬=–$=¿·î=. š>è8£½e¾ÂRˆ=.‚�= 6ˆ>/,�¾’¼x>«ÕŒ¾duî>VÉμç—%>!ˆ‘¾E†>Gç<òÍ3>Ú¿‹œ9¾Œƒ¾VÚš¾=’¾Ñò²>›‹½Æ?f>Eœ?RyÈ<¶„>;û>�Q>EH±>l˽nK½ív¾,ü½¾óýq>@ÊA¾éë=¬å–=L¾¢Á=ú‡È=Þ)&>îf„=Ƀ?¾öûU=–ÈÔ>²ß”¾ˆv> ð‚>mSX½Èò¾ñãf½©§ã¾ ¾FžX< �=¢e;:h(®¾34>Â_‡½Ÿ>[žpF>ùø½\B¾ƒ t¾@1>ý²½‰ˆ3½¦Çš=î,>y Û>’/?äcƒ>a <Ö>¾††>æÍ©=‚6K>³Àý½\½Å‰>§Á=N×¾·|–¾â:»½VÏ)¾¨óÌ»�ŽØ½0=‹=Pù‘<¬9¾:c>ßéa¾jJf=ܿƾûÇh½þȾ½SŠ>¾¥¥†¾ÜV2>Ði>õÔý½�&_¾é:¾L’4¾™1Ú>½rŒ>LÔÿ¼¢c¡>À�¢<´->¿Êa>¼’M¾5í¡=îh=©‘J>oz>$äT>e5ö¼èvú½]ÿò½ŽO˼շ‡>Vª¿UPѽ崇½I�Ú½~£C>ËF`¾^¸5½PÅ=v?`>ðª>Ê�¾Žï¾\ ¾ÄɾH–B½¸‚¼¾þ8�¾'U½ƒV¿)\ƒ>tL¼¼^¾—½·Ü1¾h×ɽ"¹i½_¼D¾ ‘l>›¾z½º½¦ŠB½T‡C¾‡nm>`ìξrÐ>»@¾ž6ç=žuν-à~¾»$G¾RÄ=¾ž÷=ŠÊ€¾R?Y¾Œ+>ø\�¾ìr>cŸþ>ä(¿Ò¼š>�+²¼Ï“£½·8>ÔÙÒ=>U=fê;J](¿�Ô¾¦d>=¤-½µâ>¨U>o+½ñ8q>™ˆ>óH?>"g=ç†.¾ã÷�=i¶=‰qÒ½Õy+¾RÀ=;-0¾<¢=x´†>™ª^¾±÷¸>¹]ˆ¾ø—š¾<šS»¾bW潬=¯Òp¾Ú•]>Š>òÙ!>ôº½ û=Wœ$¾ q¤½xÓS>¼è$¾³P>>·‚=hª‰×Æ» ’½}e¿<<&d¾"°�¾™?�!ݼÈS¼¾%G>üíÄ=¥Ìa=ÈÈ>çî½]!:>ÎÍ>®‹>n^�½Y÷½q=½®Š‘¾ÙâÛ½W>¶>fs?¾„>«Žç=u,;>�ìc¾Œˆ<½ ÑC<Üe ¾ß*¬=ößy>ç$m¾SºÜ=œµr‘Ž>Ù¡¥>¡ŒÐ>+‡=›‚=¯Õó>Âdè¾HRO>}S»tÒľb&½gU‹=*.`¼bÀ³¾6,¾4Ë$½ú,\½ôÈq¾ƒ(‚>¿âd>n¬¾‘ ¾5‚õ¼„3r>|#Á¾pzN>r± ¾ñ?§å¾: ½hÅ­>2zº>¨+¾½¹=ú½±¾�¤’=æì·<¶Fþ>?>y’¾ 5¿¸ìؾ]ð¤¾-à?ƒé=µÚ¼*Hï>Æ·>OgX¾š¦ƒ=«¢@¾Z¼>ß9`¾¶;Ô=ª_‘½Ø ú½kÄ=aw·=Co�>#&F<+¾’Ÿ=Uw5½ÈŠ>¥‹>£µÆ>ë—c>à3€½§ ?‘ž >$¥¦¾ÿWÞ=Úd¼š¾E;ï•­=×½6¾iÄ/¾’5þ==Lo¾~èÙ½b €½Vü>á0¾\Â`>uH%=‚»Ž>-ök½ÁAø>�Œ‘>ŇU¾Æ|õ<–;¹¾*Œ¶=L³½\Õî=é ¾K4š=3 •>� ?>DH¿Ú�,½Èä’>±Ÿ=g!å=c¶¾âúf»’Ké½#�‰= ̤¾³K¥>—°Þ=is > ›¾H >ÄxU¾¸mÏ»‡c3>äe<;Ç>�¦€>îÀ>ÏZ¾Iñ:=ÛÓÔ½Î|ú=y²<Þ.À½Žì¤½/Öľs¾4¯Í<^j<]¾é°= Ù;çÐ<)e‹¾¤3Ð=³œ>ÚQ‹=y‹Ä<ž:¾/+g½©ŒB¾\”‰¾Cײ¾.€=âÊk¾L«=Rls¼&t>«�©>FÆg=Í�)²>Eœ>(êH¾O/=dÕ½bè�=Ï.w>¤å–¼îíŠ>3a>Àù«¾o[C='•">Ëÿ,½ÊÊ.>~?T½Hq޽&-Z>!ºŠ¾iÀ¾M?WŸ>/$l¾RоÂü ¾óÑG>s ®> cè½w�C¼­�">Âßî=«¹Â¾F/ß½±rf½Óg½�½°ZÙ¾s¬±=sо+9¥¾²s=B¢ö>‡ìŽ>�Å»¾îH›; 6I>°ÄE¾K̾d>º‚>vó=¾ŽÙž½¼‹«½¦b>h¾�w!>Ø£¯¾‰·=÷ó€>ÄÆP¾áõ¾©D ;ßR=ø ¹=½\¾=LNø¼2÷_>¾u®¼œÛ†>“·d½­†¾[~оšs-=ºŽò=* r¾ºŸ¾ƒhT>öhZ½C<Â�:¾Ž I>ìøu=Õ]‚½‡ ^>£N´½çM�½½@Ù=PD>¥X¨=ŸÖ ¾P=‡¤½áâc>þÍ,¿f,F>ú¡ý<@Ž<Åöo¾]Œ>S÷>¾h—¼Uã½¢Ó€¼K÷é=¾åo=>O®½<î¾ !œ>ß:µ=—Ü0¿Y¹>[ >æâ¾ÜݽébI>“±&½žKÁ>jËB½ø ­>­„=úʾŸ• >Me>$T­½±}=¾¹¡5¾'ï«»~gÖ½êSÞ½r1¾PŽì¾Ûžý¼Â/@>Lä=çØ}=áR?ˆ! ¾Ù'Ý>C—>¬)C=úT€½C$X½edD>çÛ½>LŒ8>ö¯¼§7½{r=¸£m¾˜¼5¾ÂBs>„ å½ÓÙ¬¾ØÅ©=„]ÿ=^Ñ= ì¾&©\>G_F¾Wâ=oŸD=£¢`¾ýòn=RAŸ¾ús=ÿp˜>Pß=S(é¾Ð`‡=D­½·6†>”í�>æ >¹…j>‹§=*Å4>\bȽ&=>uŒØ=æ+‰=l>p¾Ì=9¾>Aå½ìf¾ù÷ü>4�Ž=ÿ.>³U㽦ù´=Ýö¾—²M>Z—÷>÷û?¾ðÁÃ>«Û=vX!=²Q >ôoϾ,äá<úソ Ã=…í—=t$>Ó>B¸Ž¾–”+>£ª¾:ÎýÿÍî½3Ñ•½ë##¾‰â™¾ŽŽ*= Ú¾zú½«â¾(g:½wÍѾbB¾ßto¾'½B_=>×­R½ |Ö½[%|>éI‚=©h =Yù0>k=²¼„Ò‹=^$³=Œ0?UÏ7½öŸ2¾h÷‹¾åØ¥=õ¾=ž$�»o ä=3ž<CϾ,>h>_S>8 ¾%cV>ëM> aj=7âëºu‚>ò>Ò¾õ<›º[ ¯>˜qª= è=t¥¾Çø¨½"ì¦>»™ë= 2¾Ù­»½”£‚=«w½©ßÑ=˜æ>Z¡±>t>¨u>ä[t>õžG=Ý0á¼J� >ý‘>�<,¾„�<0@½ ¿n>glú;� J¾QÏ£¾)@›>òž8>Z¤…½£�—=Ö =Д‰>ùÛ¾W!$¼ ­>—Q>B¾ÓóÄ>|`Œ½� ›>¶¾ÐE}>sè„»ìYǽ§£ ¾/•¿>˜I¾dñõ=Ö«S>{ÔľrN=ð*R>ÎM’½�ô\>zæ>¾/£b½ÞPŒ¾HŸ‰¾‘æ¾ �>xû5>pø‡;]ºq>c¶p>½ ã=ŸˆG¾§¾"b> �½S6P=�F½RìǼ�á¾L>8‡¨=k =FP¤½`‡.¾¤~ù½ p¬½Ì­Ž>ª´†¾oC¼8ð ½ØÂv½�K€=ͽ¼õLÙ¼„¾”½k?½— ½½ïp»å.>1¾í|�>Ô4¾N׆=’úH¾›éÛ½"þ×=Kf.>8°?&Àã=žK>éd˜¾�K ¾!�O½ßÒP=ꃾoŽŽkî½ÈM>ŒÂã½B2î=úVU>¸ã9½н^̾÷->¥£¾{¶=œt>³ k> ZÖ=LVL½iÏ;tÀ>>–%v¾ <@>È£”¾À9�½jc?¾²"à½ó­½½¥"¹=2œ4<Þ¾{Êo¾µÌ©¼ð¹4=8Š/>OÅë< ¨Ä>k>q0¸>5–нV®Ø=u:>L éªd:>—³^7?½Ï<í¢¾9 ¾v‡ž>KØ)>ô4>6²Š>×~6>+•k¾ÝV˾ ŽŒ½©Vٽزî;Y¦Ô¼{tî½”–N>ç>=`‚&> ™½P´¶=ÿý´>~$4=΢½U&оY-“¾Ë ¾¼Ÿ¾M«½ûœæ¾fz½tRǽ}Œ =±§|=‡Ê�½„’`½Ÿ>±²V=h‘8¾žFú=E±ô½‡�¾¬.¾MY=QÀŠ=[º^>P@ɼÌsC>}Ø—>kay¾Òõß½Wp¾IŽ„=Pù"=•g>¼‚³‰=÷Òq¾|©ê=Mðz>{l+½ŽŽŒ>¤Ž÷{¾3 š>x ¾U¥+¾‹¾Ç›F>ß-ȽÕ£½µe®=ÎíÊ=ŒO¾Œ�>ûÊ}¾ïòÔ½Ðö�½Š ½) ¦¾šÞ¾>³d;¬+m=g[Ù=�}½š†¾yã[>¨3<@��»ïý2¾­ý<š\м'M>‚ð¾XM¾øuȼ‘“¾È|¼TÕh=±Éü<ô¦À½k”½½»&½À±,½Æm>ÿ›O¾÷]¼yP%½mVk>†3&¾"8â¾Q[š½Øë>侇¾Wí¤=¦×ð=Î�±>Ûø=¾M>=ƒ&Çúˆ½œ�>&z>è\Y¾ª�¼¦&=qad½ðÁ½³Cs>¦¯¾5ß6=¤$Ô¼³Ú.½_t¶=ÚE>W½ ž;ÿ¾=`°=fáݽͣ7>CŸ=lEù½Â0¾-½sq¶¾x©¹¾É2©>¯œ ¾ýpr½xwƽ¶Ò-=å{º;F5¾^?–<Ð?½ÖŠß»Õ¼á=¡Óˆ¾®´\>6ݾúg°>g®º;}„>¿±Ã½¶¶×=ŽÃ—>s�•=ÕÓ‰¼'»+¾†Ÿ½sF>H—õ<âÖ(¾+9>;Ïž>PDt½1 ¼+€ê=&¾ÌQ¾Ë,×¼8¾$1¥¾KÏ:„/—<|@½w�Ì=Ðtà=Œk“=¥Ä¿M�½=ð¡>ÈCà½9ÕŒ>µ�0>³~ ¾EÒ½Òèb=ƒBŸ¾7Pò=ûd=/Ò½X¯…=,Â5½$ɦ½²Ìž=Ų­¼…`8>UÅð»@¼@><\t>ny5¾ÿ~ =_ ¾-Ù=[–G½~ñ9¾˜Dн¼0 ¾;Lç½àꄾÕæ½ì–8>©á9¹Vð¸>~î½5% >ÒP§¾F½A;h¾rÓå¾°Pž½V×>Ëæ©>žâ€=,8ó½˜di¾çß�¾2ûD<ˆœC¼êˆßU<Üå,¾1=ÿÙ»Ö”Ï=p4> ô >ç&”½­‡ö¼|4ð$Üø=ó¦u<`«‡<Özª½)‡ ¼…h¾ðþ‘=Ža=.8^½@¨=ŸZX>êáÉ=ËN½í.J=ßd:=Ò(¾µ ‚½W•=`Ø›=b©¨;}cm½àÕß½mì¾R5>p¬>=�þô¼[¾æÐ¹¾—PD>0CN=ƒË ?l° =™ÿ5>,öä=,Œ…½B¿½’’¯½|¸>äͱ½‚¾@�Q¾Îµ—>:4>u‘нÜWŸ¾@t¾q¿Ð=üÎb=X]¾xÍ>Ôvýj×½à²=š)¬½|ľ¡Ü¯½Ò6=¾'œØ>ˆ¾¥~¼Wm!=(ǽcV½ƒ.¾‰þ=Yp;FÍE¾�—Ú½ÒÚÆ¾,P½È†½H¾¾ø~¾`&Z¾EUʼ S5ºÝn#=Ç]§¼�ŒV> ìô;¸Š>À}�=4=3 &>Ìç¾¢Wd=±5¾�Ù >ˆ=q¾Ó->½u2½<=�uH½"BÙ=ƒ3®>m””¾¥6¾<¡‡=“"7>šZM>Œ”ѼåÈ>…¼—¾}s >IF<©n]>*Õ4>¦õÂ=°ľ"\&½¾cÍ>O¾vÂR>™`½cL>ÍÓ˜½Ýà½3Õq¼:!½ˆ >yŒ ¾0œ÷<]U>k~î½=¡À=gpû=×úœ»#˾^ i¾(I¾Ù"&¾¬<<¨�›¾Ü@½Zc€½ÜÙM>V®¡>èM,¾­ƒÀ½+˜=¢®¾ J}»X¤=­!c=ÏB=[;=ŸÕé<†gà=Ê C>Ö)–½¬Èô½=Ôa>0Ç8>:y3>^¿¾¼ï™œ½gƃ¼Þ‡E>Ùe¾í�>Tñí< •†¾õ5¿<*ç„>€óŠ>ÿN¾Ég+¾Ü©š=N)>³–Æ=œBнד„>ö ñ=G@U>“·‚½$*¾8䓽)^ï½qq½(>µ=ˆý†>X²=wV(>t)¸>©µÛ<(B—=|3 >ÅHq¾a{B=�P3>¼Ý™=QŸu¾ù;L½KæÞ=Tk¡>U{ä=¦´½ÞÃ=%G>.’C= Òw¾óÿ‡½¾A�¾í Å=žÓ/;ÈŽ°½b á½:e°8»›Î¾Í⃾4Õˆev›>?„Ⱦ‡¦Ñ½lôç=Ì›–¹; ¦=ç†>tFÜ>&Ï!>èf">»|Š>Áòÿ¼´=‰ŽË½ÖZx>×Ða½­#…<Åj9>Ùþ"Ô=ñh�¾ŽA@½úŒD<ÌŤ>ój&> ÍS=ÒĽÔÁÄ="³¬=¸Çº=ÁYð½~�¾òM%¾ˆú½š5 =qmR½C„@=RÒ軫¸á¼XTG>ËÝÄ>'Aò<Šàa½  ¾)5>bÅ>2Yj<#ËϽÕ½=ÂèÛ>ð">ýV6¾zß ½Ïï¼§€Œ k=i;¡FÑ<“ »%n¾|—¶<|�¢>suK=•·à½?À�=£÷Š>ÇÂ9=šdü=f0ô½etò;"n5¾˜PȽüö¾YD$>νUO'¾(ü†¾êiô¼•:>÷H�=G¯Â½gu½\5€½ÜëÅ=U‹j=öØ6=ñKi=<·Ü½�6Ý=êL*<éwß<5ÉŒ>ui=/l8>JŽ]=qûN>4ip>GÔ¨¼› �½ãšÝ¼4(®¾#ÈŸ½W2>E[Ä>au¨½¶7>ë\R¼ðŠK¾�Œ9=QV¾\(>QÓ[¾4qà<¢¬½‚%Ê<È•½ô±I>h`½7à'¾#7…¾[�½©Ž¿º5*¾ñÔM½Å/|>1sF=ç¿L>ªÓ=¼´0о?¬<ì$=öŒ½Öðo=;B >€$¾ÿ»Ù½_ܽ£þ=[­Â½*õ½¾c2‚>~}>̧콱§ª=õüǽÛ{Š=·í>=(F“½È,ª¾X?ô½®bµ¾Ð±¬¾Ó𧾿`x>Uý{‹Z= f�=Óe3>,ßð½†TÖ»{ÛY¾�4>‘§”¼Õ¬¾ÚP¤<üƒa¾>µ½í˜�>Â1,=‚Ÿ]>ú¢<{=:¦P=k5¾SIž=Xò¢=®Ù·¾2�u>¸À˜=e¹{¾"ð=¾óø%¾r¤F>A-D= �>¦z:>ª´½<€7>Ÿº;{q¼3¬ç½ ü ½i)>îÅ>!p¹=Š{‚>þê½·¨‡=¯Å=qÔÉ>\³6>¬òæ=S`>©'ñ½x¿ÛšÕ=“¯¼¥ûU½#A =å R¾ƒ\综�e<–!:• -¾Kb„=j¡»äô”>¹Ì½q“ ¾ÕWȾP-Ž>¦Q¾}«x½Š¨r¾õó=Ó[=¸¾0ŸL>…é >e­ >ú¼ãÑš½u£¾¹[¶<{nH>Š¢½Ô‡>‡ùd¾yêH>‚ã<¾Ö¢ì=Úå¨=qÒ= ~è=ª¥¾¥â>¨©¾ I ½µ>Æ|„½r¬¾<;>¾zÐ<Ìå>.:Š=_r…>Ö¤>aÄ>¿ÝU½ÀðǼãŸN>&}R<²Š¾ŽJ¾:�½O�Ì=èCi=0c>Ën½v%>vKÖ¼Qz$¾À£}½S‡†¾Ý�‰=·H˜=é²E>H µ=Ö]ñ½s÷żõR—=úND¾=Ù§>…¾n>ŒÆ ¾íV½x-½-ý~>‹šL>©\0½`u‡½™é>ŠÔ¼=ž>Dœú¼P‰>ˆ‰½Ìåx=æ )>n&ü=ôjm½8éM¾�M ½æ s½»=&½h3¾ÃPм¼ëŠ>€o¾\°‚¾GìL>LÜÔ½Œ7¼ØH­=;.?âæ;´Ù³>SA;¾áç¾D; >"qÒºÜpR¾Ä’=Èä`¼z¡¾úâ5>Å?î<ÿžÐ½‚õ½u>½ÁU>x»=²a!¾ñ%½4¦¾Q„=èÀµ>ò¼¶<9ò=Q‹Û<åø¢:š:š=+=m´¾éä>w„Q¾�°½ -¾±Q¾¯¾¤í¾†C=#W¾þÊ×<ÌA^>³-�½8˜�=�Çô=zã�=è ¾�b> ‹½¶£u=Žgx»‡=>ôº–>­Ø>äËg½� è½Î|>·ÇÌ=]«»>õŽ>€&V>í'¿öá`¾ Yž>\帽¸YܽÔ_v¾8yò½Áq ¾�ºìŽ=ú�¾ o>„ˆP=F¨™>Ö[£=ã›l¾©ë“>O,$¾UÊ\>Í;FÅS>š[œ>!œ¼iÞî=ß „½%Y†¾ A`>‘y³½ÚYy=JÄ=Å9>ã3^="~Q>€©¶>n†k=dkν/~¹½¡¡Æ=Ž'>_(»1~ù=¤ˆí<Ôѵ=â=У=Z¸¾¾„›¾fÿd>ÌŽ>[”,>€²T¾†Ü=à‹ñ½õ„¸½ˆÆ¬¾+X/½6Š/¾T�¾Tî4¾›>¾Të<¾Î� >ˆì >/æ=UQˆ=­ U>}þؽu¸‰>>ž8¼Å1¼÷Ê™¾¿B=p2‹¼m?8¾¾Â ½ø”¾XÆ£½eŒ=,º,>&tm½úü_¼Ä)¾s ½º§í½pϾ‰ß={<ؽ ÿ<!–¾#‘ÿ=º�λ ,*¾<²Ù»lï,ƒåx½;‚¼ÐÕ‘½Ld8=È+W>¾Š½™Â=‰)7½áu‚=Ũ•<ÑV�>–à>˾„üC>:† ¾Ã7>ŠÌ=±æ>ð¬_=ôiƒ¼ò®‹>Dª@½ì4S> cÏ=Ãx3¾Ø%¾¹¾g¥`¾i>œ\¾7Mó= œ¾»p>¦Aš¼/ıɾ—ÿ=ŹJ;ÆO¾¹m ¾oe&=!ö½¨´Ñ¼%:ϾÊ;¾„>ÂB¾úÃK¾ñ‡S¾iOÅ>C[½÷}a¾#9> p7¾¶áƒ>¹>«í•>æøY½#ôE¼ÉR ½�:�=’�K½TxÖ¾ëMŽ=¬Hˆ¾l^<>'T…½ -A=”à=%V¾ <Ö=ÿ¤½0¹ ¾qú^>¨‰š>.ìv>DÊï½]h�<³—ñ=eɽ˪‡=¾g:¾âˆ�¼é¼¾ë%«»au¶»Ù² =­<¾Ïr¾uL¿ç^¾’ƒ½7݈¾þ½[¥Î½»´½pû9¾êRà=Ÿþ ½o–—=þþ½ì¨¹<Í�N¾¯J`>•pß<šŸ¸<»‘>…:š¾�¹“¾2h¼½˜@~=û˾«§P>{{„¼s=>Tk…>lèоt>>ŸÅ½­!•=j9¾pƒ)>ðΩ½ü�™¾ëx0=xl>nO’=Ì>t¾Ì=4>">2¿�>LKà=öz¾BZ>s?¾ Ê_¾ß؃=±¾6¦¿=ƒ�¯¾ö‚>èÐ�½–ì½g꘾ž¡±=ËU/>[ºV>ÛP<•br¼N÷»Õ�½ ãÑ=±á=­¢=2ω>ïfk>ٕнÀ£>J‡ü;½_=Š`½„ã¢>ãÔϽWjº´pî½Ýw=ÌjÏ=*=޼Ü/½Ï®×¾³}>–²-=ýD=å^ͽְò=<^'¾,w¾)錽ښ¦»q½0¾²›�¾Šì„=Uá·>»œ=ßPó½Ç>+ýP;`7:>=;¬¼_ìê½ýpº¼@\¼y`½½Ç½µ>&PP>|›¾â,¤=ÖË™=g'Ó=à˜«¾goŽ>õGc¾‹»q'»åƒ+>$hh½˜ >‡ž�>¡u]½…‹/¿Êö=@zË<âk«<@_¤¾¤Ö•½×!쾄ª¤>ïÿC½ŸW¾®‘½ >™ó ½€?¾¾ µ;°Ô§½¹aô=ªÉ¸=‰ <¼0W>؃†½2óö=ÀÚü¼®N‡>×ÐÜ=ÃÓÜ=Šc½A˜’¾^ s=dø¸¼oËz¾Áœå=fñä=ù£N>'T#>¤JÐ=GË=�¥!>fDؽLu.¾%}q½u€\¾Œ¦<¾Ì�¾*gõ<N>£3c½�v4< ¸ï=Nm¾O´}=»°M=øÏ<‘ξó)�½hv.=ÖC¯=¹hý>³…½Àgè=k¤k>g>>ip/>à…=ãe¾1”\>ª¢Ç½¶=Õµ<]éQ>«þ½sI‰¾Dw;>®~¾¡>rœ„¾‰½³H:öo¾u)‡¾|Qû=0˜�=Éè‡>ûOc½Ò˜Ï½ÜúÞ½ªaL=$¹M=‡¾L²½½9‡½Òš¼j >wŠ/¾‹GK¾œ9‚¾SÒƒ=«·>‚á½~˜¾´¾¼wÔ½’Bâ¼õ¨¶>.ó>Ÿ,=ä>¸½™à˼�»¼>�_>dk ¾¯+>zÔ5¾Gp¾`€¨½¯Ï­>],>ímÎ=@l¾B@"¾Âpe>z6¾8B>¿a‘>«‡œ½> Þ;@kó=͜ϾÂ\¾w½tx‰>Û[¾Å$þ½–pZ>å;c¾6ǽ;™Œ>u\]¼:Ç8>ëÃ\¾ØqŸ=Þ3>¯wz>ŒÃ½¸|„>+OS>¿Ý‰=Ô”á=»«�¾ÕÓ><ô8¾-pA>©è½¾á®?N7µ>Ëž¥ú¿³ n¾Ûg2?·ÿ¿2©j¾¸@/=‰<¾™`Ÿ>ß0=7_´=5•^>Šéü½ÄÒ½ŒŒ¾àßK>ªÉå<�̼2ÿ=Cç½Ôw¬½q—M¾?â>°&<Í _½í ¾ óø¼b‡½ã[Á½¡6—¼ÃÍZ=�ü=Bk<>04ó<¯–"¾}0B=øµÐ<æ6½_�>uE*>Ñ‚>f§t½âÄ,¿­ؾbj>o>cà¾mÈ >ô¾ÊZ?Ç<4ZÁ=]€y½‰.x=§L$>WÈk=asŽ>b~^¾Ù<@y=–Jؽ£‚¾ì ½m#>‰ Ü<�[>C‡=G Ò<±æ<Ú¶¾ª•‚;¿5œ>ö'¾‰u¾gؘ½J3è½r½¾‚#>„f;¾-v“>å œ>08>8y¾Ø9;=‚Ã⦅ ¾¡’ç½l퟽‘Ì=P˜°¾J3\>r˽…øÐ=\è~>"ù¼xú>Yèf>Ö¾Td!=©�¾{ǯ¼y°í<�Š,¾–�æ=‰³J¼œß«=@µ¾2M8¾É,>5•�>ù~=ˆMÃ<¹2+½Hõ€¾>„¾ÜX‹½Âq'>ÉX=ƒ漘‰Ð¾‘Bõ½ÎK›>Ç·¤¾¡6?cat<›#>2vN¾jl=Êb>ä>†M•>ÿ×y¼C¥ ½L ½&!‰¾Ú[¾$ùa>ÖÏ=4� ¾¾Ü�=ù#@¾,œ>S,ὓà�½ŠŒ²¾o ]=ÖÜ;Sù;fû¼#¤¯½B�>f~=·7þ;¢C¼zz¸½Ó‡¨>Ñg…=1€¾-ZÒ: ,ê¾[±3¾¡ÎŽ>4OؽJkß<б+½ÔÎLÏ<S@¼ÎÛ>½·;¾ AÁ=u„>¯h¾÷�V>ü,C¾è¡ê=à Ã<�·è<$=>O�½VU½ÚÆ&½@²b¾Nøn>å&¾ñiÜ<­„½H$=¦§“=óÛ×>�ü¾¼N>@!�¼¢ ª=n‘•>!J:¾w¦= ¾L¾à„¾´��¼«0f½3ùÖDi¾eyN>u{=d ¾²¯>ö½Z̳>ÞI¯>–1M>§M…¾�Tº=~¬¨>ž›>�©Ç½W˜=!>pÉA>ÑQ$¾Jü=gª”½r>)Ô·=÷ >¡Sƒ=MÁ#¾”ƒÐ½›Õ¤½[6¿=¤N¥>È2�½¿%½·¡=MFR>b†J>7T"¼#äø>Ýþ½1¸¾�·Y¼o[�>–v='ß½úi¬=}�¹;ŠD»>ïl[¾ÉÉ%=™Q(>¡@·=êÌ=¾/ˆ¼Ôž‘>Ì~û=Ýš~¾.›=�Gm½µ1³½ÞêŒ9[(¾ƒîi;´^½hH_>u¿ù½ŽN> Žƒ=êT½„ûü½bª>7Øå;ÀÊÅ> CÎ<=Ùp>›F6>PĽTž;>³ìH¾“‰g¾÷»‚¾Ÿ23½ƒ÷À=À5=uwX=葾ÔÙ¦=­‹™½„šÇ<Ê…i½Ïù½d¾Wª½zæÄ<·>d“=t÷{¾%í©¼ÈÅR>+äK¼Ñ…WºÌ…ç½WÛ½¦,¾Hõ¾AÞǾ}Æ7>é¶“½ðË㾇>,�ª¾¹F½ÖšÑ¼{tÄ=­œ¡¾¦A2=ɾR>¬Õ8¾©õ »(Ù¥¾=¢`¾ùA¾]L¿#]’½l–µ½¦vÚ½ÿË;>àŠ÷½C­’¾À »F¾ðs[=Î[‚¾�!½vËÙD¾«Œ�>o�j>n5L>þµN¼Wx,=÷ž¾ªV=f¾ý×­=O ‰¾ü|ó»¿ß=dP‹=%Âa¾ùS­¾Tü=å�œ¼w(¾—ˆ>@¤÷=þ5~>ôM¾=¼�ˆ±½iì=yy꽪x3>Ó!µ;q¾­¨G¾öX#¼$‘¾2½hpx>J žŀ0>2[¾¡/L¾ñÙ’¾ã¿½¾$™«;R�ľ×|Z¾Œ&æ½:DW¾FŠ>a(¾¤.ϽíG޾Z! >n„½©„�¼ü¼Ô½²>„XÓ¾AŠ>Ž�¾ï;²=¦¿¾ê´%¾`Ñ›½ ¾=ì[<ùË2½ÿ³¾ÕÂľ´ ‚=pͤ><_¾�5%=3¦:=q"=ˆ?Â=Á+ÿ=G,>;d¼>%z¿=Pù]½q† >l2;ðÄ<ùw>¯ÊÕ=?Ì¥=Äi>Â’=¢«â½ts¾{»‚=ma?>�¼¡=È{(=~‘(½Õ­'=\1~=‡¢½¾*.G>.$À>,¢Ó½òQ¿;u*x½Ÿ$Š>E]¾ô<¾½w)“¼G>ÿ >êÊp¼ ‹—>´¥”>Pz=˜ ¾?D¾ õ¾*±t>M,6Óþ½L– ¾: M¾•׿½S«Ø½þ‘>lß�½<ô½]•h>"cù9·¬€>Ýñ4¼ÈâQ>`”Œ>×?Î>�šœ=Ú4=>}Y@>He½&Oh¾2Er>۾ػ4¼fò¾òÿ�¾‚Y`>>³–‹½Y(>ÒÎ^>)©>Nä>pYO>Nf±=·ìÒ<:ƒ¾†é1>¾TE=U]ë»´›½KWj>¿´½2rð=ÚÖ¡¾×›=NÇϽ_—P>ê›>œ=�>Í«¾Ž–ª¾ #'¾<ú½f. ¾~ʽdè¡=ºTs½rm´½Rhâ½³bP<îÑã½d½.´(½WJ¾¾ŒÈy=U±’½“ˆ¢>(�‹½Û×ÿ=Æcu>‚v>ÜúÖ¼³†<.d>¾¾³å½žã¾Z¿Š>ö*¾G�<ÊØ½>Î'>)D!>qN©¾Ö&=&¼1 #¾A}=:¤×½æœ>«‡»=ê;">)/ò¼³½=îÛ>"”= ±û½! ?…*=�ƒ¯=ïÜ­¾\²½k©k¾>¶x>4a>¥ó޽^hú< I>†Wý>ƒø·<§»l¾À|">�¿=èD:>Õ{ã=©T½¡q-¾¦ ô=³Vo>øÚR½gw�¾�¶>Á®‡>f=$÷Ú=k~“¾ð`ü=Ï)“½=㮾,}ô¾üŽ-¼›°„¾jユB+>;œA<§Ô >*ú>PýÆ=T<«< vR¾–•>໓¾ñ]\¾Cù»Ìwý=ôº_4µ=•«<¾ÛZg½ÔD-<{vä½7¾ÒŒU>¾dP>®²“½Ú>ó½{ç/¾"b¶¾ð³„½´=¾ó·^>på½wÀ½ä~o¾SMé=óc€¾+È�¾:)b<¯v¾Ä£¦½G|W> ?Š@">q¬¦=È'<¾eG ½1†P=À=j¾â£á;´2?:@›½ëy‡=·dk>f°Â=Zc÷í„«½é,>ú3¾håº>‘0¾Û�>,á;xe'>Ï‚¾â��>Æ÷W=$Þd¾4 ú½ä¼]C^¾°Jžúp$>ª,˾¢Ãy»|3 ¾ïÅ’¾k‡¾÷'>J\<5w/½™�¶¼°Y8¿Å¯¬¾4ª®;¹ÁË=)3‰>áJA½J¹=$q»·a€¾@˜T>Vû¦¾€Ô€=ÓϼÉ,>´X9>ê…½(•~¾G„‘¾…Dé=ˆa¾ûÑ€½jó\=°õ˜¾�C�>†É>‘Ä>å¢>‚cð>è¥ñ>‰%·¼¾Œ§"è™›¾Åp >S&æ½JíV>d„é½ðx=RS®==L>Á<à>E!¿½n»À=²»8>ÝB¾Z\;øˆÃ=¦6Š=Sð$>lÄÒ¾@wÅ>°<¾9gl=¶)É>zŽŽ¾Éj#>÷ƒz¾÷�¾é¸‘½XëO¾ãåô<r¾ˆ V¾õ+‹=< ¾FuÐ<0>†ci>È>)=¬¾úBÄ=fIú=Eß²½ß1ð¼ =3Ù=¶ >êT¾Ý•½Ü%&½? C=Ñ‹§=¨a–=Í載ÄÛ:ÙÔľz™=¾ào >›>±±6¾œë)>˜.>j~™>‹>_ÙŽ¾åå¾ÔL¾Â޾ý+à=—�X½†ÛŽ>|õÇBM½ð’C>GÀ7<®Q�>nSv=–å.½±Á&>#$ð¼�Q€½vnç¼ñͦ> >¿=‡0@½ù->64Ö>jq<‚3¹=. -½‹6?>y$¾ûÆ ¾ d&>ž]Ó<8í̽͹­=¶~`¾"Dù½`H¾Báà=@öN=béº�ËI½6ŸM»™yp>ïU”>¥d´¾]m½>J½§çH¾ç¾1¾üf¾ˆ‹¾ÂX¼ª6q>Åk~=eð¾D<¾Ë$™½vR>q“{=‡•�>ÏÀ¾Þ€’>âæ<ˆô½ÇÒ’¾�,¸½µlL>¿±H>k-h=vIð>2ò>D¸¾ Ǹ>Ž»G¾ž>”Ú\>ÔÀ=V’\=dê­¾×9°¾¸¾Á{6½vi>Œ’Y>!]ê¾üÊоx>ͽQ)>É㋽Ž„>&Q‰=.ýÑ;8[‘½kàͼ6Ý�>Ì‚+>«i]½(à¹,ì—½µÝâ¾ïã@¾ˆA>5S>ÉL½Ø3ü=¡¾¼­#|=î%;>Bãð»ôœ=Ê8A=¢(²½3]T¾’µü½zPa>öȽò©É=A¡¯<<ûÿ½>ÖJ¾èʘ¾`͘¾†Ç¼-ñ+<Ãû�>ÝY’>!”>š·½Mx->¼™Ÿ½¢w0>>tÕ•¾y ‘=”ï¾ýœ…½8®½'¾˜>ñ5=×sü=P¬U>½r>íå–½(U>é@,>v=àö>O×ù=ÀÚ=¥´¾æ&"¾#(†>}@�=Ë[b;õ>U—8½¾Kq>M�¨¾úxÂ<„ùÒ½IÑû>Ç…º=w·=�V>ó­¬=Ñóa>\¿!¾q6½Ö»÷ÞK<ìؾœ(¿¾®›=ýHG>k™>Ö®l= ,¿Ÿ~»:wÂ$¾Ï})ž=máƒ=^w©½úO ¾8¦>º˜¢½Ú�œ>3Z¨¾MA>4kKºÔ—¾8Yn½‰=Ž>;Óg=×|´¼Ä)“>-ðQ>é ?ýq¾cë¸<µË=CÓ=xô%>›=uå”>�°>«t±¾…>ˆµ?=ý(,¾c¥q9úM½O_7>/÷Ô="¼†¾} 3¾ßÌ>Ž+­<Ã9}¾ˆã¾§Ús<,pC¾O?z>Γ§>«^›=S¬>}ì,<µÆƒ>Õ“ù=Ï–€¾*B5 ?…“M=#¤È¾¿#¿.ƒ9½sßÐ>jóO¾Ü]¾®o‚½œsоcœL¾Ø”R=ãå=ß·O>&¡¾½d¶½E¾ `I¾5ꈽ4¼iò=±ùå=—]1¾ãÒê¼×CŽ= ? >T¡¼Ÿëܽ@|â=qæM>LY=F7Œ¾øà1¾At¾I>']¾¯/>8Ç*>­_¾½³ >šã‚>6Tˆ¾T×>dT‡>¢!¨¾ÆÈ²¾»2½e¯Ø=Oo>ä�=44ɽùO£>�§> ªÃ=(Û¼ËÜa=$¾å;‹¶5¾ïÞw½eÌ >²ƒ¾'›>Õá�;êgZ>ˆä™=KÆÓ=ò›=µÛÅ>G>¾ü¯>‚;>¼i ¼¿�„=ÍäŒ>ÍøÄ>9ò�>RÄ=æ�Ç>îÒ¥½.]=é† ¾ ß³<6=dS¯¼£³Ô>hŽ¡>Igg>Š$=K.ª½Ìÿ¾üÍz<±p$¾ÅmË=›½£� >šá¡<>}‹<¦]p;nù–= ­m½š›�½Z3C>ySν¤†,½£ó¾”¶�¾‰Çƒ½ƒ%Ô=XåY>ê‰Ñ»Ü±¹=H|=õ7D¾Ã‘;o¾š;³Q"½~ =!„óº“n±<`U¨>¢Ò�½ÛËþ½&]¾äÓ‘¾ÉÓ¾7â³½-I™>ݺZ=ËÈ`½Ñîë=ÃÜž>B~>±¤Ë>®ï¼1ჼ«¬Ë½,vÓ¼¡Çk¾ŠR™½ÜGø½È<¼k™=ãEÕ= '®½*Þð¼ù %½ùñH>°í�¾´j_¾½¯'=˜=>˯5½ØgÞ=K£˜>ÑË>4�b¾ƒ0„¾ R=ð«v>[(<t¾„ÒM=| õ¾¿ r¾U)>£;>Âþľ“Þ¾¬ä¾åSº½gjo<û¯,»ÉÐ>A¼ö=0ÍÀ=¹¨ ¾½ƒ½Æ 3¾sYJ½0ý!>,µ>}ûK½Yƒ >ZÙô=N¥½ æ<¾(½2¾à§>˜YG¾—׃=8*“>�çb¾ú”²½ÆI<S¼o¡3¾)Ü>#‰„½ñ >,©Í¼¸î¼�Խ㵗=Õì„>RIH=Jõ =9y•¾wâ¾Èÿ@¾]D¼¡‰õ½ÄÕ>Ï»ð½[G=j¢=ù“M>kŠ>½ÆÁ=8#=z±¿=5 5>V>ÓR[¾–(^b>\>Y¾�l>)™>ÐÁô=2Y¢¾¾÷V<Ÿwã½vÅ©¾Œ£)>}Ž%=< Ã>Ò(¾Ä3C=!2²» EŸ>þ  >bˆe¾±A>¿* ¿©üª=Öä1¾�GW½†øg=[ ü<Ÿ ‹<'̰½”Þ=à¶½ÉQ>SZs=hD¾y ¯=WU�¾MPÆ=ÿ!œ¾Uø½ìÞ゚a/¾@t>z�À½?)%¼³¾Râ®>”M=R¾:¾2nRMAƒ=B’ˆ>Xp>´ÿ3>Ë>l$>¦í@=,>üá8>¹í>3ÞŒ>ß„(¾šõª=ãü¾”Ø>ø.=ÆÞ=CÝ;>K–½=Ä+¾(Ñ=jG½n2L:»ù¼ðëÑ=-�<ªé\¼ð从½¾Ü(Ü>Ã�‰¾¸ ϽlP6¾ x½³º½úî6>:­—>¡el¾�ˆ·<âé°=‹Ú�¾X'®<©Ú̽6´¤>ü½�Ò=H……>Qa�>ÿÓP>²¾4½44¥¼Ñ|˜¼@ª=ÄÏ?ÇÜn>áde=D´8½½ƒõ½´;ä¾Ê¸Ç¼“‹½Š_[>°�¾}ÉP>Ÿg9> +}¾ù×À=ç>þê*�½x|=.B¾ ÖÛ¾gãË>s»‹¾ ]h>¤öp=ÑK™¾®é=½¬ñ‚>²¼o=Y]½# ¾Œ^Š>žö�½/½wW">ËíI½ÈÖë=¾=Î>Ù^b½âŽ->*#Ä>¦âà=“­¼½ƒh ¾{7t½MgM¼¢U&¾Íqt>¤vK¾i™í½¿B¡>”d+¾ãt½†8t=Ѱ=ýmN¾´)>í¦L½ð÷£¾ æ¾`‘¾ÎÑm½]óq¾éjA¾í ½�©´½Ë|�<(…¬=?«—¾•ǾGó‡>_? ¾î½öm¾¥ü=&ÿ¤¼}`”¾?±¾LÀ.¼âW”¾ ˆ�¾ÖPâ¾^ŸN>«¶1<à\à½öaŠ>éç¯>;Ò‹=ï'¸= =)p�¾5ãµ>�â7½Ã¬ =A?í>õ²³>óä³úâ3¾y� >€Bˆ¾f¬…>½=mR¹=àq½¥eô>®¤*?…½¾e¢ž=]V>mÒ’>EPÖ¾>äèÞ=@T¯½õŒ+>¥>b¾â9=¨ Ý>=ˆ ¾ža¾%ù‹½7Nv½Óç„=ëDú=ä4Ÿ=Q©Ü=gÕ'>/Øš>0ÜÝ>åÐ]¾õû|>ùÔ>€¾�ñ´>È�€¼®%»½|ð�>pSz<+¥>÷ Š½1%>½Ž<·<½Ð >8*�¾Y‘<>Îïá<$â¾/ œ¾FÐ<W×>¦Ð¯>8྽’¾Äû=‰âƼ¥6>v17=›m®¾Ù‘I>î­Ñ½'A�>Œä>€ži¾³y¾Òp>9,u½…L„= ®¾Ølð½,z,¾²¸j=ÑÓ‘=P€à>áë1¾½Ü6¼p½¾»‰‘'ÇÁ€¾óŒ’¾ ¾½×?=�oK=·¾~=ü¾øU2¾»EG>Jgi¾}7w<þ© ¾ð°[>¢�´>“sí<„û²¾•˜¾o‡=T\–½Û�ݽìéð¾—51¾yû>½ þ€¾ü�+½«Ž=fE™=Ç|­>õ%==Çãн#¶¥<¸¤Ž½t×A¾92^>T·=Ui㾦›»è§½ Z>¼¶¢¼Þt½¼¼m#>+"¿Ð¾(XG½ðq½wÿÙ½©¾ºw½X ½Cäô=^0£¾?Ÿ¥¾7š½ŽˆÀ½ö•μ W>¥kF>~æ”=„;œ¼Zæ�½íê­½kå>äÄ?𙾉ˆ >+ɾ̽ šc>vaA>¾\D>ñUü½äjL=pÅ=~9K>È×ç>Ä‹ò<ñãϽ•w@¾n‡#=`-ï=¤ý¹½œí½^X ¾WÈ>Í�;>Л>»¢Y;´ís¾šÐ<‚µ=Eñt>ðO‡¾GÎá¼D€*=žwü½r…=ž?ÍI>ûs´¾[w]<›@%>¯=í=k>}¾½à%Y¾¯ô™=†+¾½v®¾ÁCa¾ml›=æ‡x>9G?>|”¥=Å B¾3¦¡>ŠyC½Q@·>-Òò½×Œ/>y›¾¾¬�>6e/¾ 5¿¼Ѝ=›i¾õY¾+Pg¾cK3¿¿è¾jü4>ïç\½áOE¾pž¾{ƒ=]²´¾ttp=ág!¾Š‘T½˜ÚÞ=.7->¨ƒ½Ø�>”÷�>ÄN >À¯>ß$=o$ˆ¾ ½>N‡í½™�‹>0Mþ½X4¡>«ñ¾vz >ÞŽ>ù§Q¾¨@¥>ïI>úŽ=AȾKŽ+ö¾ZG>º”‹=‡(‘¼…òI<øJQ=ü?à%:½s)`¾¢]4¾iÐ%=ß^W< ï<Ö¸>·D«<„Oï½Ö¡Ñ¼ý( <¶»µ”E¾ó¯¹½†·µ¾Øš¾¶™Œ¾“Í=ÿùK¾^ñ>''Ù;èõ)>�7â¾È슽a Ö<©’4>PÊh>–ß�½<â�>hÄb½×ã´>›L?Œí<âÌ¡>©"s½ I>2á¼ø¾Ø€÷½2 >�͸¾šúô<"6v?�‘/½¾·½bõ;¾žük½eމ¾:¶=ˆ×#¾u„S<\B¾�D�½‘mt½õ—E½sj¦½³²j½ŽžŠ>¾„È<œÏ>Ÿʼçßp¾’’¾ÈZ>öŽƒ¾V£á=› ‘¾Öc›»T-¬>©&‡>m“¾¿O=6 >³ f¾ +”½kƒ‰¾O`�¾˜Š½h®+½õ×Ǽ6j°=Eìg>f»>våf>#I>£ˆ(¾M÷ݽßX=ï²¼_Áª½ÌŒ¾õ!+>n·8¾›™>CŠª>”¿=<æ&{¾f »=uó:¾5ž=¾!AȽÿ�ž;z®!=´Nç=×Ué:`f…¾×ié½e¿?­·½Ô•=ö52>£Æa¼Ù¬=ùêÊ=WðEºµÁ—>ùz>ie¾vœ½KT§½® ú=1A:>ÌŸ‰¾/SR=ϧg¾ž¼R=2zr>k¼¾&^ñ½b2ì=ßDö<•1;¾Éuó=ë¢kºÇ¾Ès¾xÚ£½Œc=1�;ô¯n=´O±¾PQÇ>õ?Š>³\E¾rV<¾ f´¾ö#¢=]Ñ:¾0UÓ>¹µa½y >惋½ìßó½Û¿¤=36¬>)¨›=„D>°“ª¾µy¹>_ÓÅ=\¯p½ ‡Ö½Ï„à½�4¤>O$.>}‰u>�gØ>‚Ât¾`k¨>Ýü >Ýô?5ˆà½r[Q¾²�S>Ò½½a«¤=Œu0½¾Ü˜>‡;ç¾[‹ˆ¾öS—½¤g¾í;‘¾©£!¾7üf>zXq>œ`ˆ¾èä >KÆû½‡%é½—€ª>k霽íôc>– h>VÎ?=f6:¾óö콿Ä=õèÚ=áx%>ù>Ô!½Ô|½LQ>?9> ég¾A¾Ó=6j‰>@†Ì<ž¤>‹ÏS¾ãؽ¦Ú>—õ:¾ ì÷¼x‡>(  ¾¡ð¦¾D>:®[¾ƒ€¯¾@ø>>–g½Ç¹¿«¿ >ÑP¡¼bùÅ=ƒ~½jsu¾ówú=>íͽeN½”n=ì-=£¸$=çU5>Ʊè½FE>ó÷Z>Ë#޽éÏi¼_˜Û=Kb`=,˜?÷¼ß[>à’½)l«=`G�>,œ¾o†Á>Á>I½)%'>hÆ£=ÉBоp¡l¾`ûŽ>JÎ{>ÚU¤>…½Îö¸½CÙŠ>š8J=þ‡Ã¼y컽#˜¾å¼;ÑËo=v@¿¤F¾&u5>zò>™`O½Ó3k½†6¾¥ǽÑ�<ì¹>ô¿w=ÇWˆ>Êr9¾g¿G¾ÂMŽÀ�½ºŒ†>Æø£¼±u/=Ik�¾&±ä½°Ý¾©½¡+‡¾I”‡¾öÔ¼–-–¾›sG½jm­¾ÑP¾˜;>YK$>–2}=;�ù¼À¯>{,½Ð¸™¾:†�>Ú6û¼ô¾ôx°½êKÔ=tòn¾ÀÎï½~rF¾A˾÷�>S†.½¥I=Qä3¾¿ã¾4š(¾ •<>'å™=n=‰>Š<>°�¾IÉÌ>÷£1>QÖ¢<ŸæW>‘ÛJ¾n!~=M¼ð=h>q½¢b˜>-º*>ú� ½%š½Dü$¾vн ¾td.> Ý�>î`¾?ÐŽ¾ù=im:>fh¾ñ,>àáS½ì=F=i²> ŸÝ½< º½ã— >�Å>øG™=ûke½öà’¾6÷=)ºÃ½Ï¥1>ŒZ ¾n¾-­Ý>-~�¾¹W ¾A××½“ú=˜ ª¾:>Ó¾o¶F=Xެ½e@s=£f=ÒHT¾ñ›ºÐ‰0>Gvz¾#!„>Ê`/¾ÏýT�b�×=ØX½Õ„ݽ:éݾ�(¾š¾Åµ“½ªÈ¾¤si>ZÖ«=éj>>ÓÊž>tu>žk1¾$ô.>O†³¾ªǾі+>§f ¾n#„¼ú[>Åe>Ù‡¾:¾”k¾(Ãg>?Û?ÄN>¾PbÁ¾¢Æ�>xQJ<[9²>m>gÄžE>÷¾¢ñŒ¾¿ ¾8gͽM¾¬Dt¾0Ú?>½7ï<ú+þ=|ê<寧«Ô=¯">iä_¼<&§½ãõ¾û:>Òã½Øîл»N>1^l>|æ½{n6¾¹¦C=†·£>Î_ƒ¾÷jN>’S¾ÍwN>ù̾Ì*`¾Ó)*½�ŠB>Så">ˆ7Žî«ä¾§E�½S>©ˆŽ>ë[Ê=Û³Œ>Ú˜Þ¼)Á>rEÞ½î1 ½†â-¾Cµ¾”‹u½{Ó=ëå=�¥>d ¾kÎ¥>V>Ä� ¾(zÓ¼Ç0Œ½Zu²><>“~T>ˆˆÖ¾o=†RĽaé>|é:;”A¾o±º>ñ¾_>^³>¶�~½×°I½¬êµ¾’ƶ»kC½Y‘½ŒÞ¼Uμ!ji¾Ns ¿­µS¾¨ž®½·ˆ¼$GR= k–>õk&>|Ý|¾»†=*±‰:ýi“=ÚG‹=µ>éÙ>„N> Ço>¾¸>jîT> ×4>–º“½Ï—7>sD>͘Ç=¤ Í>¿®B<”˜Õ½cÖϽފ|>�ïN¾{Ðw>?Y½»$Ó¼_Å‹½ù*—=^m>›€u¾¯a¾*õÏ=Îä-<}Ò×=%/¦<Š‹Ò=h¹-=›ÞA½p¾âNÀ>Ô}Á>oáÎ= ˆ€¾-Zœ¾°v>M�¾ZˆJ>µRT½Báé¾AŸ”>.>>=£’» J¨»$¡.=®g>qÑ¿�9¸¼í¾š­�½Dd|=ˆðܼ1þµ>θe>º|½t.–>��²> *½>2嫾û}³>XÖi=€iL»ë»B¾En©½å@=b�нØ�¾ Àý  >™Ô\>S/'>zÁ¿=¥â;¾‘᩾ˆÔo½—{5¾ðÜ�¼N3¾>ñK>¾nx>¤ò¿=hã=£É¾7!:>¸œF>7Y¼3áo½“³ >#œj>89]>(nË=@VÌ>¸¸³¼v‘𾉵�>ÌCľd ¾Ñö#¾(>¬Á¾lò‹¾ÄB¾Mt¾[J§½¹Ñð;T ¾Mh”¾zûù½ü¶ª¾ b¹=â¿®¾‰ê³>X8>'Ñé½µ`=>a±=Ÿ>=b_†½ÞWw>¤@Â=ñd=¾Ý;¾X¾ØG>2ú<³¨c>¯±ë½°xº>ÔÁ]>ÔŸA¾ðÒ>ã�%>ÆG> ñu>‚Ò„¼1s>W˜’>tUd½ìûR¾ói¼rKè½A;a>_&ĽòFJ>ö .>AξrŸ¾”û6¾Çof>Ä>ؽ«K¾œPZ>¬Õ½‹Ec©Ð¾(bU¾ V·½œr�>4>½¯v> Â =ÑJ6=–•A>X;è=`Xæ=ø>Âm¾!“x>YÏ=<û€¾–!2=½Õ¾ZÖ´>,!¾òÞL½ç»[½ßÉ;Np&>W@¾t7-¾€¾ðè‰>o-3¾1|õ=ÞÍZ¾{Ò^½h\Ò>Óc=¾âò>¦Y™>ÇI¦>ö¥W>“€¾c…¾½™)¾YîÀ½TåK¾&œ½Z�U½-,N½Ø½ös.=Ͼñý@¼Ü)ù=NU—< S4>´]±=‰ÎZ>¿!ß½5–>NоhÌ’¶íŽ=Ñü=•:Ÿ¾D5*¾£Ç ¾iÔ&¼f¯¦¾¶lŸ=BNt¼îv'½/ H¾%n{¾„ÿÕ½É >#™R=P=)I²"GÚ=�ô>Ÿ›,½¿²ô=�òS>½Å@¾?ùÝ=L§½kéо7XV>†¯>Aûq>`¸?uG ¼ˆÏ¾b§#½@s®½¯=×½+\.¾Ÿ ±½j+Œ>ìΕ<›Ûþ=òa)=NÁÞ¼?%Ô=;(…½L4£½xºº<D\>Àb>^Ë·=à®ã½õ°ö½#p>.…>=€"¾€e}>Y•y=å†"¾]6ƒ¾FØÅ¾âš!½É›»ƒG=¡�A¾;™½¿EC¾Åw=¾6š=—Z¼>êø:½„=};=_©…½ôcÖ='¡@¼lô ½²ý*=v즽ëöù=Ħy=ö“>Nà ¾ §D½.D¾`ѨK½<÷·bd½”y2>Ö•¾úi¾n ‡¾Í>LôC=Iä{¾cOí=1Ì•=)ýe¾à:W>ÿ”¨¼É×Ê=÷ŽÏ=ÓVŒ>”q³½‡ =ª‚Ÿ=ÃéV½ã�„>Ú$B¾5Ô>ŽÈ,=ÎA„:9q£=Ú(R½y¼¿¯�¾t)†¾FÍ=”=ýã=¦©„> ,i¾¯ ñ>8?K<0(¾Ë2¾PÇ>µÉ¾6¼X=›°N>ji]¼§§Ä½iÁÂ=;̾ƒ¨´¾òñ·=n¥a=Ò¶œ>—å‰>ï ¥>o92< ¼½%BÔ>3>½Ý÷½œÖ½0©Ž½ç‡¾Û‚¼Uø>óïØ¾$C½%CŒ½þÜM>¸À=‘§L½� ¾l`-¾!‡-=:¢ ¿¹ã-<㌓>¼š¾·¹=°V¯½Fά½ƒ<,Íœ=æ¦ãº©›´<º*gº°Äz½cí�>LÈì<ú/j>üZ>«M×>¶KÖ>Q�=ÑZY=«¥¤>²=²üսݑ>¾† =²OŸ¾£©4¾0^>�Z‰=Í€9>àV„¾õ>ˆ>jàª>ˆ’õ=J{D¾Hhc=¯> ˆ–>k{¾í×=eø,¾øßÿ=‚²P¾fO[¾5kö¼Ö¾aÜÓ½@7—>¢ÐJ½ã-P¼Zo"¾²¢¹¾dU‹½i¶Û¼É.§½µ{¾JK·=Ég]¾o#½êͤ>ul¾uéF½Î™;¾D¢§>åx¾y ¶>H&¾»ÖŒ>á¶=[§D>=G¾”ñ£¾ £›¾sT>¾a4¼LB>“û»÷Ì�½ ��¾‡Û=0æ7>Å�r¾èâ…¾Nó±¼èÌ3>æT¾ö²i>«O½PP =xÑH=c)9§§¢>[U‡=}¨¾2­¾Jô ¾Û¡>L t½IªÔ½ ޽Ã~>8>d_Ö:ºŸ>.Ÿ¿% æ¾ Z±¼¡…Çv†É½Âû=®`w<�¹Š>Q­>ð ¾-Ù罈öоb¤½9~v½F޶>j0¾ä»½ðo¸»ˆÂ½Nw‡½:¼¤Šì¼Ô/½saJ¾ì‘@½>w>-\Ý»W´c¾�@b½e{ľwC¿=�R̽†FL< µK¾6]‰>¾±Ó>¡›¨=.”%½y¶h¾¤Jî<S>s!ô½Ç/½ù6B½GTF¾\†C>…ÓE¾Éc-¾–’ÿ½|ÿÚ¾bs_>7¶Y½½>t«¸>Ú#Ò<ͺ= [{=S=¯¼¦úã>)3¾=¼6ŠX¾#Ф>=Ï$=‚°ß<{m>�˜¾gª˜>P‰¾a§>bÒ½¹Èž&3¿=‚]¼uz)¾S Ë»—Â=9 "=â®&¾þbÌ=)¸¿²�4;ͻ½�1Ÿ<Ãôy½ä¢¾ ž½½?¾�ˆ=—¸Õ=¬*2>ýX¤¾µv ¾S=< ²>ˆGX¾"â@¾I«K¼MÀV=¦¯:Rн÷£�¾ûŸ>�]>8ÛB¾ìüW¾åÜ¥= ÓO¾<0Æ=”‹½•’¾<>È9ú½Xþm:·46¾�BÖ¼›Î•¼¾X¿-œ>·¶p>=B½7¸L>rY>ÖV€>^Ð>ö›ƒ>vÚ÷¼lt`½u¼Œ>"u>Àêû½àc»=ªq7¼5ʾï„-¾¥·ˆ¾¶k®½7»²¼ˆÐo½ƒ�—=Æ2G¼‰ôò½5€A¾EY\=êr´=ß– >‡²½d¦q¾Šù­>8Æ^¾ T>µì&¾õ®�¼£M@¾˜Æ®¾¾f’¾mn'¾³Ý�=þÄB¾5$>H ©¼‹‡P½°‚ ¾ Ów=C>âñ¤½&ø<êÖK½äëv=5Ƙ>ûÙŽÜÚÈ<"�ñ<þÓZ<ÎØã¼³i<•t>B‚F¾lÏŠ>±�·¾æ¯™=²Á¿½>ML>¸¤Ü½Åõƒ>K8Q¾<ÒØ½­?¾Å4=Êz¾‡é]=Þ f>3{½Dì2¾š��½ŽÄu¼pQ=§HJ=²þ�=$ô¾Í‚¾\²z½*[!½» ³>VtB>F¶Ò½) ˆ=º&;>Aî�½úÅ=ÏÚ>l€:QÌ>:Ûg¾m)ľèD¼o-Q½ÎXF= ;ɽ8ƒÏ=ÊÙ¾œ�®>R>=lŽ>â¼�Ⱦ唾YLí=bd;=bá¾¾>zEdQ”½cÔ‹½c…›<]#Ö=¶~\¾' ´½»Î'¾]Š<ÑbA>oEˆ½�àÓ=Ž%>—õœ¾ÙˆV<<¨>ø@S>ŸrG>hÿ=Sr>®È¾8­�;÷àx>Shy=bÅO½¨íª½@9�>Š\V=Må?<;7w¾Õ¾6¾ žl=¼ž=à°6½³q�>åïŽ>+¾z>N†¾%�>¾*>¼j2»0Mp¼ð냾|̾5–¡¾ ú$¾Cn‚=âìs¾•ê=E(ؽúUá½äÒÕ>¬6‚<9Ü.=$Jg>3;o¾Û Ð<‡ä)>R¸=ܱ¾É%>è«T>û•M¾6ðä>à޹Ãñö=†#¾{ ¾ F´¼’mJ½SÑ}=‚¾d–'¾¶½'`u>nS¾ÿª?ùìà=øN%¾XR0½ˆË•>r_¼¥Œ¤½¬[½¤>©Ÿ€½›¿Ú=7ýW>ü1¾Y@�¾þD¡¾ÆTo¾ôv@=À¨¾ó@>x)8>ê²=ëØJ=Zòœ>½„>›>ò2­½›l@½QÄC>!Æ¿t >ŸÒ¿½¯Dö>õ¿�=Z’*=F0¿pß">Ï+ª>�$¿êw¾  ~=ð¢-¾­ˆà½¦Zˆ=Òf\=¥Aˆ>¾àÎ=s"ʽ^{¼¼Ä8]=ѧ+>¬<лy®¾æÙ·=•µ˜<ž¡s½è„e>ñ£/¾b˜—½Nãµ½W¼ð¾® o>ì>še¾«�¥<ü(̽Ë[`>$Û9¾[ºQ=‘–à»`N=�FÞ t#>ªw2>F"¾¸]¹¾8£¿¾mY¾ñˆ>“‚¾R ê=œ¼>öàY>2è2>ýª°=®C¾ÙØÊ½Rz°>ÑŽ>,–>=…Ò¾½åß¼ïÀ½7w>EQ¾¤C^¾„°†½Ð^â½M¬’>Ï‘ÿ¼Ø€½÷°…¾³èϾ%>Ù=“4ˆ>ƒþè½Û,+½*˜È¾¾¾ÇnÌ=`>ƒD¡¾G�;=Lîí=P Ï¼Ø�F=ÅÏ>±|¾¨ì�½Ã‰¡½�ßC=“½yÒ:¾õÞÛ>¦.¾¾[Öw¾�•¥n¼HhÖ=éŽT>�_½tÌœ¾_l:=SÉûôã=Ö …¼Qé\=éø=Ï+¶½i‰ >à�¿ÆR½«½Â=ž?–¾�hìÝA�:â7ù¼É£ž¾Ç B½>–¼U„’=¿ >=Íÿª½¼—ò¼Q¥½qñ³=i3:>„@½ÜÄ“=jȶ½ëª==ê_>Þ>Ð�t½f =b¾ÔlE¾<…(>¨Ë ¾nRe¾/‰>¬—Ë=?ÿ²¾õ ¼=Ôâq¾ÝB„>Ù@ä¾TG>²ÓŸ>ÜT>%Ň>ˉ–<÷?ó¾«n½ƒÛ8>Ë1«¾òÉ‚¾â³Á½züp¾—ÆŽ>zG«½ÏÂ)¾Öª½’È)>ç¨Ü=)lS>1È¿'K™;æf´=7 …=©|¼1«¾àcN>ZÕ>¼µ>-Ï]¼ø m¾ïõ>ÌŽ¥¾-’W>tÇ¡=TÁp=VOQ¼SXñºe0‚¾‘á½äï"=mô¦> U>½t'R>¯Ê¾>CÙ¡½{.½yÔå¼Â£z¼ ú½´¾J½…M¾Æ[«½p»¼2·§=TN2½ ê£>@æ9¾AW¾Ð˜Z¾éJ¾<°¼Bʾ§›W¾ 7™½]¨¯> Àš¾oß>䆛¾0ˆ½�~=Ƥ>@SL=Ìi¢=ÚüK>vPN>&2¢¾„¿>@*5¾¥½Ý >™Ù�=]7>:÷½;ØZ½21>­"‹=gü¤=¤Ü>{>n°>>Ñÿ½ÿÃk>˜-x>nœ£½ó߆<êA½úô=úo;¼£!z> X�>Š3_¼Hxξ¯Â±¾6 ¾¯6(¾UJ!¾U?޽˜¬)=´î;– º½P—’½l¢,>�òY>Iã>Þr¡>Ú=r½éÏ…½C¹‰½ì¦c¾~zô>ùs=þñ>â>À<àžž¾7Ýž½ºü>~lß>½TÔ½*¾�m²¾E¤;>å¾bô3½Ý4u½Z ¾À*¢¾Ë)Ó¼i™ó<W�=sDK>û ½lL >IXã>&�¤¾WÕ?°ù<<ͼ!¾&>Û‹¾•f½14¾ hF>ø‚c>:u"<Çð7UÕ;=8`;¥�>ÈtŽ>;)ý£ï"¾.Ⱦ¶¼�> ê=uш¾,@º¾D®«½¹±^¼\¾ôÍ:Z^D>Ov…½Øí“<º#¾¼Õ$—¾Òßš¾¯H>*Žø½¾=ÎYš>¸ç›=�-f>¤é-<™vm½y·|½‡^C>ö<&¾¹Q³=aò?½À­›½í'©½€|>#•Û>a§›=á½Øn–¾º×#>À•>¸Q¾;8=>k?>`¾âŽC½fƒ>ãf“¾jtû½HNß;³r=‡°i> ø¾¾]‡¾”ðö¼Ý >^¾¯¾oÚA½!w=è£ ½Ì„¾ú&B¾Ž>é¾éŒO �A=îM$½Èpô=†Š=�ú1¾3´¾Ê-£>ª«E>wH“>kÚÔ;M=ª=0å<䨑¾âv¥¾¦=®¼ÝÒt½ª82½÷Bq¾Š¤“=wH¾óz”½Õù8¾ËI¾ó³½9‰%¼`C¾ƒºÛ¼POo½Bl¾br >SƱ3±>0ýò=¶_ì¼ÇÔ>‘˜>‡ü¢=�ž¼:�¼Vo~½`D>ê¤?»Œ¿¹þ®>ù˜»ÊJ�øÞù½"gĽ>ÝN½>ÒŒ¼å`<Ý,˜½†É%>=¦½™(‘<¢un¾®M‰¾x:k=“Â>ð^Ç>þ‚ó½ ‚¾>�Ó£=¸�ô=(¿>þäG>v o=—Fò>Y¦<½×½¾°Ë¾ Ô={Ô½�$=Ì㑽2{é< &=Øât=–8‘<çåZ¾­0½>ZA)=Á—Þ=!”6½½Xa¾Û¨¾ƒi¼(¦>?><>ºçÑ=0¿á± >®ù¼«“> hƒ=0>�l&>Òþã½ôK³¾¥P> Λ> :8>A¿M¾5>Œo>NA><ºÑ¼éªJ>¢P¾m >íy¿QW’½p|½jêÉ=±$ù=šÉŽ>5Y,½ïÈ>pr°¾šø¬=Îth=ñ@>nD�½À¾—–0¾îî=¯ƒ>è9‰¾•˜¤>bÈn>�y¤>Æ}Ö>ÀÀ¾)íx¾õëË=^´u¾O€(>² >¨W=u1 ¾Fõ¸¾ ÎT¾�Î > @‘½¡c[>û½V¾1‘=>š¾âf½6/ö½BN>ë@�½È71=s¯½a‰×=ÑÕº¼HÊ¢¼ªëÛ¼‡ß9>b_œ½6�?;M�¾€ßœ=<ÔѽÁg€>ªÁˆ»ìʹ¼�¡ß=g/ž½�•¾©P›¼–—å¾Ü*&¾n» ¾�/l>éòÈN¥l¼$G=¼¾f³Ü=�¤ÿ½)—‹=…/—;ÓX¶=?Q½Z>�'Z>ij‘>G4½¾Dã#¾¥9¥>Ì÷>éw6" *>^•^>¤pj½üD¾ßvŒ¾Êég=0">‚½4½éb >À—¨¾×�˜<7SоŸŽüŒÇ¼‚2»�5ò½±½ö+a¾Œ®>ª?>2ÿÿ=‘<>⻸½Pmû8¢k‚=¡•R¾Åžʪ†½ˆ‚y¾|ÇZ¾DT˜¿Ÿ>”ÛD>ïîå;{88>qùýY·O=;j7¾Á“=öÌ:>Åkñ½þʹ=Ó"Ø=p( ¾>y³¾º¾ò=ß7>k—>×ã:>ˆÄz=‰2L<‚;¾-´>b0)½xh‚=Û�.>Ul*¾¥j>Ib=›]ä½3“G>.Gú½Šw>Í`(¾8„G=cÀ¾…W=½Ú¼ÈNö=3Á?-°¿w®¿¼=©I>µã’½|A’=-¹¾2e >þTL»Ð]ô=¥é0>e@¾X2¾ú+o¾sƒ >Þ‘>WtÞ>+yA¾{½>¾Ü:{=Cl=/;;e˜Ý=çO ¾ºÔ�¾%€‚=15�>K ¼>Cšv¾ÛÁ…¾ ¾°Lf>q�¿=½"`¾OÃ">UA#¾›É�>¹pR?^]…½S{Œ½hi“¾1€»$翼îô®¾å!޾5³<¹e]½\Î=ƒ]9¾Àð;“M*¾ÜòE¾»ü=)¾‚½Êm>®2>îÓ¾]ÄË<ê~‘<ظ¾�$ñ½Uÿ?®¢=¤ß3=ç<½¯¿Â>i¾øU¡¾è•Î;OtÀ¾”ZF½„Qx¾b<È=Ït <0¼ê¾·²Ì=dñ;Þ4i=³Üñ=.´…="�ê=ôR³¾4Ü={v�¾ù—Ô½HpV>ÖÆ¾XT>0GZ¾ðR½é¢€¾ùû�;:›ð>;ʆ>5æ¾yÔ½„&ë>‡@Å=Aäÿ<ƒº¾ 3~>MU¨=ZÌË>8¬¤>0s=Mze¾ƒŽ>qµ> ¥t>W¾m–[¾»«½9—°¼½škF½˜P=4ú>;Ö#½þªœ>ð‘Ⱦ=ˆZ>w,è=>òt½ú*=øñ¼X'ï>‘»_O«>œL�=Ö¦½´Âq>ÖÙ6=Z�¿ýÆL=³˜Ù=Œ4¾p"c¾��¾Ép=XòÖ½»¾Ÿ* ¾5Ò¾tªd>Zè>¸~?_Œ¾ã¾äI>üðS½Öð·=˜(£¾*OU>"Á¾½àR«¾þ2Ý=KŸ½$ °>•7ɽa¾1>ÿ5˜=|{¾mIݾ]ïä=ÛÜ<=”¾6=wâ=ÜŒM¾úÿ"m>tse½Žb¾‚=²ÃX=¯îr=“X�½Ãþ<Æ›¨¾ˆÅF>2J̾e>R> 6:¾X©Ä=„è¢=.f±>¼#¾˜µÍ¾Áq`¾Æ¨Q=8¿©¾GŒ =?a >­<,¾½Ë½ TùºG}'>¬G¬½¡Ú>¢ø>J9…¾£³ï»žÕˆ½Èäš½ŒÈ>’Ec>• =™0?wº·>âŠó½J_‰>—)¿x—ò¾¤Jo½Ñn>‹>ƒÝ_>[!¾9u;¾2P‡=mw½T/�>Ѹ=*3¿¸=ô½©$t> Z5¼i €¾+E[=Jíq=&é9¾Çƒ¯» @¯¸"ã½ è¡=¶ìú>˜«>šAt=àó‘½VŸˆ¾‰R#½ëþÞ>Σ¾»îGú=tϽb0’¼ÿ6€½J¶5>»p5>ùÈd>TÕj>Âsƒ>àÿϾ~�=õv=¶‘T>Ÿ‘½/¼´¾8>BÚ�>õG¾²H‹¾Ü¾j§½•�>‘šè½sI>þÌ©=JÆZ½C¢¼<^/„¾&]C>Rû¾Xëó½-¸®½mD¶¾â}W<:h@=’-罸×½�mr=ÑXÀ=ëö×¾òL?¸’=s°z½<ÝS>Iû½LŒµ>TЪº+žq>Í^ˆ¾ê±j¼/•>Æå½TëÊ>3c>çrν¢ž˜¾Ùuœ½™\¢½0=†=¿…>Å-ž½¨7˜¾< Ú½ 4È>;95>(o©>àïz={öé¼a‘�¾Py¦>cáj¾½�=š¼ù½ªyöºw9­ÜV½g°\>­‚¿• ‰¾3T= DƼ¥Æ†=ÃÇ”ÿ>iJò> rí<Ù)>¼ûØo¾OS=Î埾 ^>ä�’><?=eW‰¾Y¿œj�>+žU>ok%¿›Èн!Š> ¾Ó¼½p"¾²‰¹=tq1>ímÆ=0d!>„=™½–© ½˜€°=ô§3>oiˆ½O;¾jà^=ÿË>} ½®·4=Ž„=„P½»()ç<œä-=Oôº=N¶­¾SÐø½ñÝ=.¿>öÜ®>q–=Y2.=ÖÚÕ=é[¼"Ÿ&¼¡3„>+Zž=ÖçŠ>¤1 ;^Ñ¿Û�ø¾Zé ¾6Ö >Ô”-¾j‚¼4òq>~“Œ>“ª‘>…æš=B©¶=]&g¾li…> ì ½û£>Êív¾V˜P¾{©¤½ƒdå=‰H >íÍ£½óOÚ=é¡r¾i¢¨>­#Û<¯)ͼ]Ï�¾ã$Ù¼ßþä;•2g»°ï‡>Üæ»=&iž,>ßÀ>˜õ”<á.y¾u±£=VO½ôÒ‡>Ÿ°Ï>õk>7Ç­<�›Œ¼û9]¾-c‰>”ÍN½š[ü½ñ�*>7ɾaÉÙ=VÂÔ½¢‘½µ·š>¹6>ÃØ}>B3=J×ø½€Ê=’H¾[Ò�=FDô¾!©î¹äZÔ¼þµª=ý?Ì<*"í<õ'±¾@^½ÿ„¿VÐ@¼,¾¾¿�?=vÔ˼¢5E>·5D>©�§>Íá=®LÒ½/믾‰[¥¾Ûî}w0¾9¿„¾Ó|®¾ïŒM>k3>‹w¶»1A>¼Ó¼ÜË>òs¢>kà >ÿ–=¨Ù­=!M¾ÔPã>Ú½«[0½ðÛ=8p…>.ÛÄ;Suy¾‰¾’€†¾|¾�>>Lܽ¿ö$=$f�>ÿ;\>Cm¾:¦‘½¡À¾YN­;–=cJi¾b«&¾Ü}¾Y˜¾Ù—•>Ë«¾ƒ[‚»8ˆÖ½SºŠ=‡é¸>_Ï>E,<ÅÞ¾§©Ã>:M8¾* >¾¾Î¤=�é@>£+*¾ �A> s;>³}4¼Ùž$¾™Ý ¾ÉG\¾$о¶µ™½b'.>›H½¯.W¾ˆ1;Ks˽çö>¾Òx!> û‰>´øÒ=#Âæ>®+оä�Ò½õbô½m£¾MZ½«Ð9½üµ#>£ò½MzÍ=ð྽KÑ(½XùH>TN½U)>…¤½j˜Û<�+z¾4×ý¾Êû»öÅ‚¾äÍ‚=ÅH—=G±¢=ÖË=3½ê<†Y‰¾@‰=æG¡») >27W=<¾1>Q·Ç>2`Y>ß]A:2eb>ú5¾«Ò)¼9,#>>¾;ñý½hò&¾‘6î=ËP~¾çÇ\<ñÉŠ¼ÊÞ¡½[Þ&>�c�=œx>¿ożWŒ?_æ;>£Í¾úˆâ+>¾–ò½XÉù½«3>­Ï1¼­QÔ½ Ì­¾7Ÿ2¾ÜŠ‘¾ñ·×º¦ó¾Kps¾Ù(<_ºÜ¯=³U>ƒRµ>Ê—<ñkš½;辟¥=r’?Ì(ú<ôª=Œ±Ê¾œ7¾=6â‡>æ(0>@Ó®¾ÿÉ.¿Š ¾&Û=.-©½ÆÒ¾Œ-=±ÄM>jû•¾qD¿yd=|ý¸}å½³ ê=Pï#?LJ>ÝB¾1î>tL¾’*»>Í:½=éè=¤Ãß¾©à½ñ5 >^¡L>G0Š=vfå¾!˜¡¼-o >­Y¼1̾°™�>R ?]+j¾�À >显VŸ”=Ÿ9…>µç/¿Ôdͽ»ôÔRH-¾ÚvY>a©�>jv>_?•¾ÉVľF¨¤¾ˆ’9=,”‚½àüß½0ï½j�K=BÔ¾xe™¾µ$$¾Êž¾ b> ž;¾9ú*½Ålð=ýã=©�q¼'©ˆ=ù³»Ö‘¥>V4}>\wY½µÐ]½ÊS>à´³¾Mï5>ð„¶>ûi>8•=„i™½\ꣾÀža=QL‹>!ÁS¾Nò«>�Ä>è>A¾Ã÷ ¼Óf>].þ½¯K\½ï•Q¾!”G¾ðª_=uD¾�ÞÕ¾ùN¥½ð¿>>´‰¿íy¼êo§>çw­>l7˜¾MˆÅ¾pð¾uÉ—¾>ƒ`b=maR½» >"Y/>¿>µ¾µö¢½·/Y>Œ‚^>,pª>Ьâ½wÏÓ=Â>d»¶¾p§¾éÐd½™ÏK¾%®M>·–¾'N¿=oàW½’2=^$>Ü9_>_RÇ=É‘†>ýw-<šG‡½� \¾Õª½½ã¸¾ŒŸ=S>ºý‚>�W̽æW>= Ðû=6p->ëð#=8ôý½×W=�·û½æ& =D36? >o¾oÇ>Å ¾m¹<^ÓÁ=;¼m’½^µÞ=Ph޾'­M>t»’>™>½ZÙ=}™¨¼V <>É…K½.¸¾ªxB>¼N¿…€­½¢'`>oó/??”Ô½Ezð>O«=À%>³ƒ«> S)=ñ.+?|¦>ãðß¾¯u¾rI5¾îÔ?>˜¿W¾Æ€¾ÆŽÙ¼s«>:y²½l´s>%Ç™=¹M¾L¨M>̾ (x>|å²>EÓÊ=b•¾ä„å>3Žß£>«wƾ6Ör>«ëú95(>ò›p>µì2>¡6)¾�æ>8½>¿ñ•>–ã>¤ö¶>;¿!¾Ñ•¸>2?¾xº£>äl>.žŠ>èÍ_>n”=rÍÕ½CE›=ߊ¾z(½™Þ=‰6¾(Æš¾è•Ž>‘Ѩ¾Ž >ä�¸=°Œ½–>(&œ½½Ýa¾¦Jì=†·¾»%'¾“Ѿ4 „>”w?ž�">Å 6¾:#¾n1¾Ê”A½zha>–)¾Ô�>›5޾sŒ¾€ m¾¦9¤=V}?;ƒƒZ>&(½'4½  ¿âž`¼`Mb>ùg!>·ý¾ª¾=d\�¼�åŠ<§€Ë¼)ª¥=¤‹>¥“î;Ü ¾”ÀX?£4=dȽDཀ">ð²¬=ÕÐ=²>¢Yq¾î‹={¥µ>U*>iO±=˜¼”>*Óª<Ž8ó¾?7 ¾°Ç½ÿ‹t>›Í¾Ðx0¾ÏHa>VK1>½o¼>{4´>Pß;9‚нpÈt½=úí=x7ö=} 辕0\> ¬=Ó>ô°½–eA¾÷�¾å­±>�Y>Î=Vîl>†Ä«¾�Ï ½a�¿ÊD¾qÁð½C¿œ>£·6½3xè½ÍíÕ=ùîÇ=Ÿü=5Öì=$†=8ܯ½" ¸¼Zœr=&_E¾9i€¾ôTx½ ív¾D6†¾¡Ô½HÑV>ðñ?¾2µS=Ìõì½ïÛY¾u“®>Ó¬>ðê�=!= L"<´ëb<Áá•ÁJ€¾Ü¿P˰¾�ÆÆ>ÂJS>8þ²½ïò>"³W> ý¿>1מּ¥¸=jƒg<·WJ>·@x¾À ½3ªŠ¾•:™=ÔnÁ½ùHÝ>¢ë½±¾“çÞ¾:ïí½bâ>~þ3¾=Ñß¾2Ü·¾k޼e‚½zÓ½Ú½îN>xó/¼“K…>Ýýà=k¿>>𳂼âÄc>ù›½]X¾t# ¾D}à¾HìÖ>ÒjǾZO°½h(u¾ñ™‘¾C2>d½²“=z<@¾À4�½é¿Û½»{ >¥qØ>òM>ii¾Ð‰H¾Å!<¾$¾èÈÜ=Nô¾^Â¥>÷(Q¾âT…>á<¦>Ùi›½öu8¾®_ú¾è¹>‡=ƾ¤:¼¾+Û½Q;Ï>7‘n¾gˆ3=¼\W>¦�¾”r%>:§t<ÞôX¾¥¶Î>}8 ?uì¼ÖÈn¾Œdš=/�=Y³½õi⾱ɔ>Cü$>fw½èM¥> Î_>\++¾t•¾1I:¸äÌK¾ A>çD¦>¾�{¾$6¾ð˜¾XnßÉ/½µj¾¾¹Ï-=¢D>-X쾯¾ê=ª_‡¼ü �¼W¬=P>%¾Â¦ñ½�‰â½Xþ>ð¼ƒ>0Š\>úÄ›>ª°=9U ?·R'>”ö;ý¾£Ò=>¡D >�|ùÚоJÏ=%>ÏuW=Þ°½î›Ù½®–÷¾ÜI©¾,ˆV>�s>Kýr½”úD¾t“Ô=|¶’¾˜ë™½Ä®ð¾(ø®: í>¯_>Èß’=+„¾ˆRš¾9þØ>Ù©¶>ð‡’¾… ½™“}¾™™+¼Ù‚ ½çyŸ½ò�¾WÛ:¾‘F¾EX†¼ý®Ê¾^ŒÈ>�ÚÖ>û G>¿¶‚=z@U¾Ê¾¾?ÆŸ;ïâP=¤¶ ¾…‹x¾ ”6¾m=½½ú¹‘¾ô¦¾%¢F½îß¾D„½=¶ï ½�½¼“>}V®=HPº>!fN>ÆÕ×è×­¾)³Ý<–ò>Eñ¾Û¾b;À>U }¼ˆ'¡¾ËÕ=äNÆ=7p¾=ÉÂõ½›7ó>¼¸y½àKì1ó�¾Žõ)=G=?x[Õ> i¾^‚]¾/�‰>.É">E#�½Èá¼E1¸>kÅF¾vG^¾èËa>l2D>#ö¿ûu×ÿÒÓ=À-™¾,0¢>°6> ¿•?Ž>휽°lA½�éF=¢€E¾Ké½{• ¾1 ?S®”½BãÍ>dt™=¸$Ô=¡ôÝ=Ͼ›�³¾ ¿•¾->ZÎ>œo¾ÿ—о’Ö¾ÉoØ>1ó¾6Ãû¼ã Õ=3Í{¾?Êë½] …>›>‚m>9*¾ô=? =¾‘Ë‹<× ]>Ký½);¨¾S‹>hB=‚">E½í> ìñ<�(3¾òÇö<*;!>”¼†>•1>?æ#>m>í=99V¼ ½˜ê྅«?=~¾Ù?dÞB?/�¿„’¾µù=å¼Ù½èZü¼¬jR>mÿ¡=’‡Ì½hi¤¾Îí½æWë¾w;¢>sIÁ>©t˽£Â ½]V’>°å>jÒ‰>]R²¾«@:=Ö~T=tÉ�¼Õ=¿ —¾¦cƒ<ƒ&>ö¯3>n�v¼»½`“½#4=Ú1™>ãùÄ¢ï¾C=€¾iá¾FÏ>çô/¾ü ’>a{f½”LG=̤¾»q³>e)>EÚ¾´Õ3¾>•¾D£¬¾±H<¾2äÍ=Õ1>‹ÓP>èç8{¯;á%º½þ9¹¾­—¾{+ ?­×2¾¿êd¾Àû>åQ}>qO¾jK¾äÙ�>PÕ®½¡4´>3rž=£ÿ¼JÒÈ=é¶¿D%¾={ å=Ƥõºa±>]ÏY¾LÀv½B ½b?ªè½£¨Y¾1/$¾êŠÇ<¢¥¼ ž¥>Ä{ß=ÄÝ!>~žZ¾“9¼>ž—Å<¢½t½Ž±> ÆB>ñkx¾û�¾‰¤=�ça>%c©<ãº>“]½‡E=Eœµ=—Òµ>‚i¼�qœ>y¥…>ˆUÖ:®â„½ÛÓD¾ÞÔf½«õ=ßî ½Ô >DÑU>¡4¾2ß·¾Ä�É=K>:>Nöš¾Éƒ>†Nù>ºÔ?>§þª½û# ¾÷¥Q>¨^O¾ð8¾_/ؾ³Ã„½ÆÔW½ë0ɽø•9>)ßc=Q]–=‹¢ì>ýçn¾âR½œÀ®=ú¾’>Atå¾6оTÎ(¿þÇê¼,0>ò$¾…õ1¾Ý¾í�œ<ßî¾1wS¾§å/>*@Ú>ù”…>Ÿù‰¾ÞÎj¾¦Ê½WF=>ÔîO½»$…½®�ò;´V‘¾ÒH¤¾’>Í™š>%ËC¾t2¼­€<èÑ>½—r>#>xǾîZ]¾ŸƒX>òøå<íó�=¹_Å=[}¡=5÷¾ËìZ>ñ ’¾„!ç=¸7±>.k2¾?ªÙ»^}Ë=<Ê(=š >ÛSÌ=°±¤<�K¹=a<Õ¾Çú&><¨F½M•³½…Q|>Ü o¾ '¼u²½¾.4„½EÙL¾EX>¼>,†½ÿ%*½&‚þèñ>ಾDµã=Ëù<º½¢¾¸x�¾ 6‹>S\7¾GÚÜ=3Óf=Êê÷=ÁÆÌ>Ûn>ñ­·½Oõ½Bˆ>¹îú=²qw¾»f/½ùMŽ>÷W½ �¹½ ³h>\¾·3�½1\P½–_»½¦�È<ø ’=1›Ù>MR¾¾QÞ>£–t¾Pß÷=-{H>�>½3ZB½ ‡¨=¬†>³=e[>¢i ¾è(>ßK‚>î6†>â—¾w­°½PÚv¾ˆìe¾œb+¾?ûü<ž+²½äÓp¾¾Ÿ,=šàA»WÞ]=☰=¾œ{½lNÆ=XKç½o ?ȧ…½¤3É=Ô¿¾›H>z÷Œ>§¹½šÜ=¶WÚ>QŒ ?/G’>‡!Å>Œ =’O‰= ·N¾…³`¾8=¾o)¾�;g<"¢ ½ñ+†<+ši>¨\â>;›7¾V€>ÿ[ò>J?å(¾“Ψ=°µO;é[�¾_s1¾jú½V¿±H¾å;į¾\:¾!ÚѾþªŽ½7‘i>4!>ã Ž>¼Üν¯îô=séi¾ˆw‚>)~õ=`«>XΓ¾¡ø=öÞ½ `¾±>‹½Ù ‘>QU¹=Z¢Š½TŬ=û�B>ãxµ>¬q8>Cƃ=�]Ì<{„>ð‡Æ; 軽âœ"¾!æY<š÷[¾²Â< âp¾ tÍ<5Ú¿¯›ï¾µ2>Íb½ —c=µÂ¾X†¿½ïp™¾y$#>¶‘¾`a>þü«¾Ê0E¾Æ9Á½'«G>¸jŠ> 1²= È€>Lš¶= xÜ>éϾD¨_>Q;>¨«=MŒ¾µ*P¾gÈ ½r°>·ñ¾ö°=÷Ev¾œ羡{¨¾„2š>•ö»¾l¸~Ó>´¶=´ž½0—= ê¾Ç½¦½¦>²_‹=î&%>½s´¾¥ð°> Ñ=¿¨G=Õà>=¸±¾½pŸ>vMc¾É8? *?>¬ j>,a?·Tø=à·ˆ½0ÅÏ> (D>(@©>Ö§#¿èO<>羋 |;n@‘>ZÓ0¾d ?87¾’m0>@¿}¾ÊƾzM8>ÉÔ>M•³½Žf>|÷”½}GZ¾„�>èÉI=W18¾øõ=fu]=©^¾ÒU½©÷•>�``>²Ó?>¢Âu=Úž@[?ç¯ù½°ãA>QXÿ½öY>–0>ÿ’=¾‘€�>¾ãË>ŒO?$¬�>Rš$¿K]£¾ºxG¾$ãܽiB§¾†?>¼Ø¡¾‘A=p�>ë„=ha¾“K >b¡™>· ‘>»*=Íë×<™%)½� æ9“[j>0Ýv½]ï‰=ï  >Dש;÷÷о¢p:>uyS>…?ï>ª¾ŽR>‹L޾P¾%ÎŒ½ æ?³‹t> ë>áì‘>�"‰>ŒLÐ=B/:>3j“¾Z� ¾g†‰½Ýö&>éIg½ ÍH>Eˆ¾Ý#¾Ý­>Œ Ù>Ÿ5¾ºa²>¼Žm=…µž>›ÂT=‡l¿«`=xdß¾Ê�E¾G~ŽÃ%4¿UU>ni¾Ú£ù=9,1>,ûü��>Dt¿KÛ*?-Wм B¿ƒg½¾·³¾!]—>sÏI>Âô¾@·¾ñ%;>ƒˆ¾1Ô§=½Ó-=zÞ<ðwµ=b7u¾h"á=úh­¼�PÉ>C,÷<”Cá>1f.¾çW3=ÄZÁ¾Qr°½mèV?l>êo<#%C¾` ÷=Íù/¾T£>#’&¾¬¼¾Ÿ£½60><éR=çÄP=º°M<¨m}¼:eK£)¿±Ù>®X ?t´?Û”*>eÜ‚>)ÿ>$ÛÒ=ýŽì¼§"=ñÄù=££½Ê*o>„ã?=u�i:8¦:¾çÚO¾l厾óÖ%>0BH¾W=úž%¾Þ­h>¥¸ >eü>f<¾’k$>c7>1§¾Î值0>Ǽ!¾bðs<0)Ø=²Ï·=W¿äͽ„À§¾Å‘¾>µ—>»”;3¿(½¨Hž¾^$Ⱦ\d¤½ò?þ;ŽO“>Ë'>Ft³>o©¾�Z�¾'*=¸Ý)>�}¾¿œG¾O#®=„°¢=—)>LAƼ¹äP=sb±>P¥½“¿É½v<í½”J>{~>8Î;™Æ4¾ÈRe>`UÁ¾hÚÉ=#C¿[‘þ4Ò%=ÿ\?P×X>ßÙ==j¿vÈ>Æy‚>aü½8ðï½å«¼ÏŠ�½´ÊX=Ÿy|½²y¤='U ¿c�¾Í t=Vß°¾uš'>½ë<$~‰>ˆ�t¾ý�¾š–>/= >É ©>Ï|ƾ»ñ5>TÏÇ<þgÛ½@EÉ=ës�¾<ø¾A„’¾SÚf>�²P>Y‰›>O6’=j#¿Frž=Uaù=qý²=Ì„¨½~{e¾…-Ê>Űã»ãt¾‰r�½Yw>}„L=žÈó=Ž}î½?Sæ>:`c>¤<ô¼¬š¾¾Î°½Ì">(f²=ç(”>ÞPÛ>—>c]¾×ˆ*¾ôƼÙÜ= ” ưܽ?£¾{Y>Z…´<¶ Ç=/Ï~<꥽€Ž©>…í}¾œHm½jUÒ½•¡>:`é=†é¿>“Fâ=’Ú=Ä'†¾dâɽ×`>æG¾kÕ‘>&]¾UǾŒÙ‹>à(¬=™É>Lã¹=Ÿ¥v>|ç`¾Ð1á¼Om=@ï-<¢ 2¾M±Æ½ÁÁÎ>ÅZÖ¾™zó½Ö‹> 3ù= ý<Ø{â¾_è >*L@½TËW½è;¾â¥ð<²¢ß=ö³®=³^¾¨k=…d¾„ >îá…¾Ðjm¾“—·>âoà>ÛÙ)=Bh½ˆŒ> "¦¾úàã¾ór3<ȇÕ=CÔ=�‡?F¥Q¾Ó@n>ÖK�='g?»Ô§½3[¼œ¾V¾‹.,¾aÅ$?bÈ‘¾ü^,¾´¥¡=ÅW¾®´`»>럽)9Ü>4¤;N‹¶=àý9&>ΰà;™•¼>ým¨=z„¾îü¾<[ ¦¾‡®@½Šw@¾…ÿ–=tC¾J-¯>Å!¼�D>ü+>j`˜¾V¾¥Û5¾^p"¾±NF=k@>qR7¼õg1>yM­=7)¥¾j¨=ðx×=‡L¼ŸÇ==Ád=D»…>ì`>Ý�¾ä<¼Ø*o>b·š=2K,>=3C>†>š=´?�¾�´ž¾½L¾ñ/�½ÕÐR=–[>s@=Mjf>Œ.¾¯ŠM¾¿þŒ¼kx5¾|Ò¢=[¥€>—̇¾5j¤>rrܽL±¿VT,>�öJ¼/>’]�="[>-þ‡ F=º½À½Z F>K]>Ø„*=»±V¾÷ à=+IÜ>§ϽÀò¢>ãŸM=yíO=[ƒ‹>oif¼j«>$ËX¾…z™=Û�€=>dB¾Vê@=„:’<×fϾÑÅB>ë¶½�Ý>£Ã=à韾Aa´½|ßB½M>ƒ>Èv¸¼Xv¾XÛ>Å[8=øÉK½U”§¾ý×½&Ÿ½ _>¾ÍŠ>îKǽ¦ÿ&¾NÒ¾=©ï¾«�=¸}ƒ=AÕ¾â:O¾P?ɽ_¿O ã=fYF¾Œ…¾4ñ½É3½Sk3¾à==t<<5u#¾#iˆ>~—ô½K”,>x˜�½Ú¤¿¾oU°=¯8à¾!Ï¡>þ}罸Ô=q\=ÆÍT½¹>‡~=½…M>áÀ�½H† ¾l ê½¯>z®ˆ<5 ×¾J¬¾Õ�¼èŒ>K½ÆdÉ=¸¥½!¦"¾ -—½B6>I°K¾­qp>ÁtÙ¼ü >©‰*¾ô™½Y6>*<^½•�¼CÓ<ç,½Î–­¼¹Þ½Ò±Â>ÎÑL¾O_†¾�Úë<®Ûã½’ØÛ>>î½!R:¼ÃÖ>z >l…Ó½>2Á¤½€i<µ²¾;®Y–=-F‰¾ÐsK¾ÍަM#¾&ð ¾tq}¾³?×½’é•> ÷ >´€<ãú˜¼¬³¾A`¾¨ý>”a�¾~ý×;/ÜH;+Ûì=\3k¾_9\½˜‹¾½¾T">wH<ÕcƼkH5=Ó7³>¥Q=´1ø=©Y¯JL¾6ÑϾò>Ô®¿ó;¤:Cl>�Þ>ïn=”>ôÏ1½#K?`S¾0ʼ&8>üؾ ×W>‚‡V=ëš�>€X¸=zß=ز2¾åá¾.ö ?%¸ž=¢¥Ó½°™™>™Ž=Ð[Á>–£Ú½PZò¼?‹¼õÅ›½ bB¾å÷‹½AŸm¾¤{¾ ò3=…(¾l‡ê½üÚ)>p®S½EÉ/¾kÚ>—= >¨ ¼À>t/¾€&Ô½G¾º?h>“X°¾(zç={Œ‘;«P±>­�¬>: š=YÔн„8\¾hm¾|±À½‡´º½"s­·1ž>^xì=s«= Ï©½€´À¾ ó²¾ä³Ž>±{=/†O=0Úk>= ÿ=�qÂ= &½6”T>袒=j D¾ ¹f¾kv¾ÙÚ9‡�“¾ð®m>°u>×:û>xƒI¾³e¡î½ i0½[MÁ=&MJ¾€>‰Hñ¾þdœ¾ „W¾ \Ž>–˜¡½ø¢¡½šR…¾¯Æ’>��>M3–¾,�>ŒÒ½DV>È+|<ݦ=ܧ=ÜGï;ë­=zD›½½k¾™¥¨=í—†=Î$½2áQ¾Xæ+>v>WÛ>k#>kC­½ih«=Y¥†¾#÷¸¾Î÷V>Ö½œ7�¾ûç'½“`Œ½Œ«�¼BgC>:ì=“ö=>®O=|¬º=*>쎽oB¾Q¿R¾3¥h¾]­Å=kT¹½$ž>Ý:>í+@=HåÈ>³"¦¼[E×½2éÕ=^̳¼l‹¾ñØ€=úØD¾o»M>Ï¡:Zu>Aå ¾Î�¾´ùu¾÷á�¾mWk½/O7¾¼È�>ÐÏë½ éÞ=B©¾Ï¾a-�½¬ê½ú¶J>ˆÁX¾Ý ¾ƒ‘³½Â¹ò=ßaY>a¾‹’‚¾ ÄS=E«U> d´¼$Šƒ>,µž½¶«�¾m�¾¾‚ï'>ƒ›6¾û—¾‚¸}>4¡#¾14›½“4ó=Å4J<¢�ã=hi=œJ=›�¾‘d¶»Õ�=N ñ=v8P¾Íݾ´/Ü=%ê>ŠÖí=»œ²=­5=È  ¾ý«ò½>Þ+¾-�¦½‚Ý%¾–«½ÞéB>fU>XÇ«=ÖBï¼�y‡=�•…¾v6q<‹žEd¾et¾k°>Õ¥™½ì7<‚¾‰R>¢.\¼ýn¨½4ig<îæ¾ÍÊy>óÝ+>аּª°&<ÚÔÎ;VçϾbû<>öÛ`=÷€J¾˜82>á�¦=܆¾¾X¶>7c€¾ÆÎÜ>¥ª¾öVë=eã¼²Q‘= Üå=¥£=üy¾ ¾�ãÞ»¹Ér¾�d“½î¸’¼4k­=aËN>1>öÜi¾®³Á=Úld>Œøi>&öa½÷Nï<Î9;:¹õ‰½™‡>’s>ïµÇ=2] ½þªÊ½Ø×Ê< SM½X¤>‰Üν:~å½ O�¾ óª<„¾Ž> ‡J=3h½,“µ½ËÛ§½@Ä=c5»KËl> ­ï=ÌÛ�½g®¯>lo„»ñþ½Ú᜽ðkì¼yfá¼ý™¾&c¸;¨!Ð>¤v>5¾Ô½×y>Ø™E>-½­ˆ> 'i¾pá+¾7ìQ¾Ô¼œ¾ûp†>êKÎ=ÙîY={0È>†t�¾’½þz=Äñ<<˸/>A‹æ½‹ >�àa>L®Á=ú¶½é_>Œ ¾½X>(ö9¾¬o¯¾Úïš<ŒÅh>@·¾äÓ=Ÿû©=f”ñ½MUö=8+3>²»>ƒˆµ¾ô{>?kk>°ç ½'aÝ>«ø­½ƒß‡¾A†Ï½‰ˆÇ½ìUÿ=8Ày¾`«>ªÕ¸†wÁ½=@ã¾—ô·¾½n«½ƒP)¾K =Œ±¼Wòñ=zõi<žÁ9¾V±Œ%l>nš-=û×»>&T¡>gÏD¾¥·=„?^=®øE?Á÷”½Þ�ÿ<…̾CÁ˾‰á=å¤A>iŒö>㉌»\¬=g¤h¾–y> áZ=ó�ì=!d3> ^>rE>„ j¾á3±8Õ…„=`û^=>W½¸“\>)äb;“›X¾EO(¼-¬ =Ýúž»ƒ@€¾ k†=ÒÙŒ¾[Èà>:W•½Å'©=¢gš>•r̼æྺÖ<Š3W=J¬¹=5¬‚¾Ø]æ=Î>7·{>ÊŒ>|¾ø=„˜^>£L–¾mJâ¼´³=ªôÿ=�}¾˜@%½òK>tÌ-¾_‘4=«áŒ="]ƾâT¼�‘Æ=™>Ô®>ªÖ\>³Z]½{H†>„Rž®ìŒ¾#¾âÐ�>›ñû½.¾˜t>ÆC‚>¤™½\ï—<Ži2¾h™¬>uÓ"¾}ã =z6¾m¯_>±çð½ËaR¾>^°>¼Žµ>*8ì> Yç<—^¿r€i¼ì}¡<»˜ ¾» >n¾°>Q‰=ð™õ¹&KV>sÿ´¾²«¶˜Š‹wR%¾`ÐÕ½]¾=.æ½N¥+>r“=,…«¾¹Ý�=zþ>͇¾3ž>Mðm>�Èž½ÂŇ>«XÞ½E,§½Z:=¦Ý½>ß„>äv*>�Öø½øZÔ>Я‚>?VM>‡Z¾€»�¾˜K= ¢]½lHæ»S:>qGq½o˜D=º3/>çíF¾ï w¾×£>HCs>_§Â¼cfνhø’¾[01¾¼ ˜¾­D=\¥½w>CAª>L¿¦½"Z >ª»>~M3;U]<7yf½Uµ=b8¾«s>1Ð<ø·l>¨j¾\>ƒ=x«B½IÆW=_D>B¢= è;½ÜÏ=¸%=Šc=õÑ=Ìù½þ+£=ëg*¾ÃCP> ½ ½uR¾ÂwË=¡àŠ>êËÕ½xI¾¨Ãn>¥²7¾Ò:M½ _ê½{è¾'Lß=±|å>œÈ¾û÷¾žr•=H3å>�–_<*.=ŒúŸ¾žï_= 1„½zÞ½1KE>K*A<Ê�.=ó@Á=E9È<0Ãv>^°l>qoë>J=3µ=Þ¶�½Åp:>wM�>k5·<¥z6=? t=£š¢¾ž=Z¾¹¢6¾;ÜW>ª·Ñ½²>Ö9­½�€=Кw>õÒ½-±¶¾�ú>>=5~¾f… ¿¦•Y¾O´�¾s–¾¬h=8¡ý=;'­¼*„°¾8‚†>ò~"¾ùwÁ½.Ï€=V­!¾çPì¼ ¶-=?Ñ>Y‹=‘†=½‚½_^É>5do>{¤>u1X>Ѹ%¾þàͼpà§>…+¾ùdŠ=(Õ¤¾OsÇ>1½7>caD½ïoÙ½^öé=¢Ù<õÍÓ;»f;¾ü‚=½­í\¾YÚ ½þÍ”>|^ç=&�§½ù’>Z<¾†X&¾h~Ñ=:wµ<�ŒÐ=�õC> X ¿›ÈT½œãf>�Ÿ÷½Qáï½Îâó=È‚Ý=âÝN¾Û”˜>Øo>™ÄؾùÛ½+œ=üÄR>å†�<á᜽ɯ>m¤a¾O+ú=Уj=‰ ¾=³›ð=c•™ðSI¾é¹G¾hT޽Öý7¾r†<>U8a>º$>ì s¾�˜&½Þ²Ý¼Çð»4È«>]qß¾ÓÛ =“’>–?˜= vo½©ÕO=k‰¾vÙs>óJ¾ ¤<>L>À“Š<îrJ¾HŒÌ½œ£<ºNÔ=—B= Kl¾4DŸ>õg[¾ŠÀŸ>‹ 8¾°Âö=�ý²>Õ½=á݆½–åT>ï\l¾B×·>!#£¥>9ï=Ó~4=î ?<Ö>{�¾/BN½.†"½ŒÐœ=J¶™¾fV½×÷§¼þg=T”:;Ò{,>µÝȽm\Û> u#>—ž¼1ã½SU>j­F>´Z—>1ž®>{´¦¾Eç¬=iM˜>Tü¡½6R½ÉVÑ=­/©»&HǾDAݽÈ/f½kMÁ:Òw=ô;Ý=Q ¾¯>¹ƒ¾¡%µ>¡mV>‰Iñ¾Dr'½? Ò= P=ÆÒ¼•nTBù½ä„m>WRE= �¼½/k¾ IZ=Ðäà•‘½è»ˆ¾8Šœ=@÷n¾Kª¸½c*¾Þ (¾A÷g>ÐÄ·½þ:ß¾@ O¾`¨|=¶ß¥¼´>ø\*¾ì”™»gÓ >DP\>SÈP¾Îy½m0ç½A-¦>-->Øý6=ƒá>>Œo¾ºrF<{z¹¾Ü÷²½¥C¦¾/�¾<$=¾ºÁ¿=æ‰(>È“Y>RM0¾x«2¾†¾ðêõ=T¶=� ³½„Ü=cA¼êSº=`äÜ==Ú>Yu¬½·xl¾˜#3=÷-¾ ˆ½ 1;¾Ÿ}ȽMÁÚ½{Ò¾µØ­¾ßr]¾¾ ª=xÆb>ùC‡¾Ž:=™‹¯½¤ß²=B'™¾nn> ß›¾ÝBŒ=zy Ù#U>·'½qª=À6¡½ÿñ/¾ä“=4ý Ÿ½ç«½=èÅ>è‹£<µ¥C¾¿R½Y�w¼pÒÔ=¬\Í>º×=šÃ;=c’>O¾ŒŒ¾̘>ágн’�s^YÅ=€k=aÐ^>¥úCº_&=¼�ê=s*Ë=(±½�È=JE;ô ¸>Z+/¾Ê²>猾µ©¾¾…˜þ¼¼³= ½I‡•>¹;=¯T¬='Yý½Hw£>H6v¾¶z>ät¾˜œ‡½ä>å=QC>ôˆ=ÿAŒ¾áŸV¾N‹ˆ¼är¾íg¾œ�‰=‰¥é=•F¾¶eX>ïP¸¾”ÓV½�±�<~Ôª½ô²¼ù5ª¾{íÉ>ÈÌ-¾$ ‚½"„½ëš²<†¯^=jÀ¾òŽ>fܼ“Ð4<çÇy¾/Ê=;ø›¾ÔfȽÇ�V=%wI½m�¾2ð>¾x7¾Tâ >Q°=á=ÏÒ8<ØÌÕ=ÑùË<,Ñù¾,e—=N™¾©IоÝCc:µ�+=–H¼Ä|�>�B„<÷Ù=¹wѽ–¼ýT¾�áÙ½aA­¼øa˜¼Ö¼½€�×=Ôß±½�7£½Ü¾¸J1½È%Ý>z.ˆ¾•=Ͻs¯ >wÔ;§Ý˜>ºcû»qÑ�½.a=JÄ®=°:>j‰­=[½6kV¾31¸<Œ¨w¼–ÿ†¾(ý`>d”¼?=³¾—£¿¾Û–=™:+¾ç�p<Õu>À#†¾GQ¾ý£®¼Ç\¾ˆOϽ¾Æ�¾Åav¾�2Q½R'‹¼Ø³ý<Ï“d> Ä;¾ M>¾GÚ;¾ñp=¿qM¾¸G~¾”GD=õ#¾-–q¾&¯½>P>?A¾ø?=Õ¼ vÚ½là>”Ú½�cƒ½ƒ~¼Kn¾!RѽǬ®={àQ<ÿÔ ¾ø°¾>‰>9ä¾ÏËá=E½¾ô¢²¾³�O>¸IÄ=+Pœ¾Î‘²<ý‹½P£¾ ‚X¾õ ‡¾á‘< Ä­½y!¼<ðUÙ½`ûš¾—º<ßÞ½í =*m½ù‡Œ=|—§½m�ƒ½[Âb>Ù@_=Üž¾×K‡¼ìý*¾ý’̼xAu¾ßq”½7@ ­Š¢>úfñ<ñÓ"¾Ëú9¾†ó¾æÆ¿½„>< •<+XR¾)‰l¾Ð]¾hc> ï¼ ‰>œø,>¶”‚¾¹‚½)޽'±¾žiº;ÐÇ=Ð >Žø‚¾UÖ¾’|'>�c ½%±]¾F+>¦@Œ½T>p¼cÌk¾1T«½¡8ö<‡7Æ>� ì½Þ”¼,¡9P¤‰>f¸š¾éÓ½¾Þ(L¼æÜ+¾ã•¯>?,Ì<ù4i>�é8>Ò�¾Ù@9¼Go[¾6!?“ö™½_Ñ�=ж½½Æî½[ÉT>è)™=1=y=ÐÆ>–¡>k„ƽFäI¾ò,>]Öª½²—o½=Ñ.=°T½k�°=:™¯½f1¾=Ù'¾¢­µ<Âé=ýR¿]1Ú½~¢¾ª¢i½Èj¾Œ‰ð»äTx> “<ц¾’k^>ï÷É=ÑØ=õS>ïÓżøÌ½án°½õwª¾{ >sG>™Ü >�¼ÙÍ€¾â´(>wæÙ½¡ñ½¿Ò=§Ñ>åÊѽï¡Õ>©@Û=Di½®8»½|}½[¦Ä½wÛ!¾Ÿút¾O¾Ü¼¢4Ž>Jåɺ¤…\>“Sνóë˜=L�_¾i—ñ¼Bõ½ë…•>Ãç½hA×¾(fнɇª<T¥½%•�>�J½•™ê>ŸÞ¶>½Ñ;V>b¾äå½½”p¾±»Ò¼Î{$>S\¢½ÏP4=ÀÓ">ï€*½ K>™�->/r>* ¾x™½L[/>åÛL½½¹<Ý&Œ»š7œ=4ƒ ¼X]>_á>Lœö¼á®Ñ;…€¼ø1½ u�=Þ–A=õÄ=¾M—�½€º¾îÍ�½h”¾•�Ô½{-q=ÇÿóÒ¼ÿ=u>zí=­±ã½]ð¾ï™[>óA ¾‹| >B-•=ܯ=‘…<�¿û¼èN;¾·ï>¾<�½I. ¾ýj²<%>÷½Ž›=ƒE =iÙ&;ëx]>Ù—¾Q¾Î½ >Âß>?M}»®�Á=|à±½¬-O>r�r=ƒi¼–®ž>Ü]¾ÏJe½s‡%½©5½8¡A¾?MÓ¾’ #¾Ò¥>;¨9=bšº½¾‡4>‡i>µ·>Nç½$Àp= Xr=?w> •̼VɾÜþê½U#J½£ú½3q‰=K>3·%¾Ïß > ·>’R=›Š>· z>~«s¾·>K(”¾eÚ½‘êî=½1š¾š^g»�·=š³¶=å¶A=Ã6¾4Ž>$~0¾N,N=øí˜»™ª5¾ê’>ç(<(¤V<¦9�½ÿ<†½»û½cø÷½lïu>+Îù="ƒ>H ¾½c–¿ÝJÌ>¡$ýjU>á+”>¢y³=h…]½ç Ò½5ç=AjÓ=…©À½°Ÿ>€ô¢>¨½(ÏA>-îi>¨t‰>W°>L¢¾qzu=Od¾,×¾y¦/¾o$#>†Í/½\ýæ½M”‘½KYé=퀫»vQ¾ ,>¥a>G˜„>VÆ>z¡¡>œ]O¾˜k¾MP8ºUœˆ>>º;=™·9½PÒ¼§T>¥�k½øk–¾Aq*¾*ð ¾7…‹>¾˽~Sk;VÄ›>^j¥¾Æ…ƽ¥m>ù*˼V‰=¸;¾c&=Ç!·¾¢Cb¾€<þ¼’ôü=8е½PÙ>7šš¾Áv€¾ód.>h¾4/>P¾2Te=ÿ(¹=@L¾ðA>Ø>¾�N—½ 5å»´Ñó½U88¾ˆÄÿ<ÑÊ=“Û{¾9 ¾Ê.¥>ëC>`û{¾¼�Î>xÇ>Kº =SÝw½g=¦=þñ’¾ c>O‹«>¬`#>©Äî=‹:¤¾í�=¾øªˆ¾Y¾?>ÞÇ=§œ>ñäŸ>k1<賨½)?útp¾Cð.>Æè¦=Íüg>‚Å~»®à¹=Ð|>I�>môs>{ÑŒ¾õâȽ]&�¾Ÿ™¾ 0ö<è]�½£ø2>M½ö̵½=ŠÛ<0sŸ>Éã½RŸF=ØS0¾E‡Š½¦íþ½—·:¾Ð•�½¸6f>a¶=GK}=LáB>D1>;f>%™½X\ì½zn>Ö8/¾FíÅ=Ä� >Aü‹>À™u<6O£½­d ¾2 s¾Œ~нïn‚=й›½»‰ ½žî…>Fܽw¹>Êó ½[© ¾ÆöR¾0�>6)½=.¹š>Ó»m=-å¹½¼Òá<‚¡¦¾9Ñ>_Ác>ržÑ½ô½ƒ½ *;>q𢾢Su¾OK�¾uÁ`½t–Û½ž�¢>®›ž¾‚­Þ½–¼*>Í >ŽÛ¦<ï%¾kí³<ÌC >RS<c[>�,3¾øŽ§=+v ¾Ö¸;¾îÑn¾�ô>½œ#¾‹ÙV>Ȥõ½^9¾ÙV­>B¿û=Þmî¾xT¥>N¾‚Eh¾Hd…¾µ 6=ソö}‚>TP¾Ïh=€5 >fNܼ̿†=¹ß»=j¸½>v¼ìÇC¾V5v> �½¤¢½™|ì>”(Ò=(™#½’×¼ÚE°½¯è•<<îL¾o ú=¦‹À=[C„>:vb=f$•½¼+Ó>à[½áZG¾þÅÁ¾%[½ÞÄ&½ ØG>HCÁ¸<ç�>…Nx>>S!¾/Œ~¾®æ„Þê>ƒÛ´½ Oʽó8•¾è™Å½×ÜV>0}=ì#©>è-¾»5¾9>=Gaa¼}RP¾|(¾¸.Œ¾H8輸,½®¡U½+#q½9 (>­M>¦ Ž>˜9�=¼¤�>*™S>§À½ø….>o÷œ½¡œî=e§£=Î2”>²³è;ºë1>·Ÿ >º w½è!¾ Û¼ÀY¼ôq”¾I²©=€V�¾'­ ¾ÒU½=µÖ ½tUh½ÿ ½òü=�{ë4�=`ä[¾ä<½¦=®üö¼—É<›p̾Ҩí=sŸ"½kS…>µ1>ÿ·¸=ó—€¾ö�—¾�Ý>¯.¾…¦M>Q‘;™Á>BÄù½qáÔ=ÞÔ¾g+³<²q½U”Ç>�3ê=03ý×¾rµ‰>™ˆ¾�H=¤8‹ºð‰ >ñ%k¼HÀñ¼”=;¢Û­=ïÑž¾j0£»¬ëd¾òNJ>Ï=f=m½GJÛ½~^¢>b\Ì=> ½½&56Š=¯h½#_ü=-Ü�½,¸= -®½ßŽŒ>H>^£Ì½ü©·=qó =_§Ä=’K½Ðv>׃ˆ>¨ÓU<ª•^=¿c<=�>³\¿>ÑÇ=Î9»=ýaÑ=4©‡½ÀU=1¨j¾öî =Œ-¾} À¸Ð=òÞ=9Ù©¾"Ÿ>Øá½|i�½’¢Ý=î�¾àã>³Íû;F ¾ä(¾KȾba½K”î=œÍ>Jé_=3P‰>\‹>´t ¾tw=c¸Ìa=ž­i¾%c�½ ú¼Š œ¼‡+|>W¤Ó¾”>#Ä<†{q½¤ÌS=DAÀ<5¯H>j©»>uX<òö¾Álá:`%ʾ¶2ª¾Æ—Ý>òRñ¾óm§>˜€¾6`¾�øƒ>´ ˽Žáï=n³¾ Þá=ÁÔ¹½l¡¾¾«ÂB> />™ r¾æyˆ¾C"�>U¾j>s&?F¸­½´+6¾—>^/ý=ô§¼@ÿÕ¾z�^=¤½*M½*GƽGzÀ¾qLü>[|ù¼¨ú ½,¦>dg*¾Ÿ|4<ï¢5¿‘Òƒ>¾Ü½GÄ—=ã¬=‡Î?džc?\ñS>'~¾¾2®>ÚE¡Ž5ž¾ct.¾yÒ­¾m‚.?ÆÏ)=? ‡¾¸È…½™ŽÃ¾S¾¢ҽDzþ¾Mš=Î>>É…:µŠ?¦¾Ÿ¾³3d¾z3�>?~ð¼óó½;¢>ï+¦¾ãÿB>C�´¾NèýÁPú=N…O»Vñ>ã‚>Öõ¾ØÜ>æO÷¼D¾¡¾I¦ ¾qà!¾‰Ê£=ùžI¼þµÉ¾ä�(=éžž>)ªA>Ýœ>Õ8x½%B&¼ÿn?¤5Ì>o(j¼«Ÿ¾qý‰¾}�q=TÄO?@°™>�"¾ð>î�¾-¹À>àÝÛ¾¡ð>’×Ú;ñ2ã½3 —¾ÄªÈ=¾pYµ=šO?âø|¾~Ïó½Lþ?l¥½6CÔ=•".>\� >Mp¿ÀK » F¦=ù\e>Í~ö=Ѓ²>&Ö½C�¿øì½ˆÁ>O —=þÜ>@(>­ÉG¾¯ w>bC‘=.€œ>w@U>„?ä’q¾`Tq> C->Š}¦>dm¾ˆð;Jµº=\°^>DÙc>4É™> …>a‡¾æŸ�½@X>Ü‚‹¾á™Ÿ¾ÿ>:? D=ßj½†v�<ÉÅ ¿D¾_ÝU¾0݉¾Læ<ýµZ>@c?6>æ×`¼7H€¾Ñ9»= ¤¿vI¸>[ݯ>’Øÿ½Ne=bc=K1Ú>ÄMo½eª—½u‡¾Oß>>‰åD>èÊ=¶)¿1ÿ¾kU5¾ŒŠ#=›s‡¾z¼=LÔ¡ƒ¾ª�I¾ù>Îo>a—‰¾WjǽUÞš½M;ĽúT¿«I뾿¾<4Ìྕ�µ»•_< dF¾­o€>³£h¾R…œ=6¨‹>‘Ó~=¯‰ >´R=ù£¾ò=fZ‘<Áö½:.?Y:Ÿ½Ìá/¿iÛì¾ ƒ¾¿Uo½–Üÿ½Í ²<_Í\>º‡9¾÷=±¾\E¾¾Ha>uÈ’½ãçs¾‹TC¾J¾/ؾ­˜>tÙª=8Ű=8–A>¡ÞÚ<Á|Z>8©2=\ŠV>Añ>·¸¹¾ î ?ƪå=޾>øž=Á‘¾ÜÌK>ï�¿“€#> «>�+>¿fÓ½®áœ½ZÃV½SÈZ>ÎÓ�=U`�¾H2 ¿p%c¾ÃÄ™>‡9Ú=”Ã> N3½@Ä>n6ý¼Ì„¾¤ÄU¾y5¯>ÑR…=B‰ñ=�H´¾á-;cˆ>ÓW¾ >Rì¿Yƒ½aI•>ݽ,> L!=¹Æ¾½l¾r K>-Bs»ã:?¶•X>ð#ù½d†¾+¶¿‰€D=VÀ¾/»<¦L*¼MG˜>å¿×½áX¾M…C>z3š=‰›p¾¾¿çö®½ ÃP>þ�q¾¶o<>Rfо/x¾¼„>�û‰¾‡Æž>Ú»R¾«Só¼w¢=¾)×:=jF$>8ë¾"l=üäþ½Àø>ÝúÔ=Îö!>Ú:ž¾å1뾑ž™¾N¡>b&¿¿ï:¾Ìdm½E ×>%}J½˜©½9mÙ>ÓGã¼Å�ç>ˆ«Ô=<t½ 9Ô=i]U½í¬¿ …é>TÁþAÀ¾ã]�<Ÿ²o½´ëT=?³=!u�¾þ]>Z«Ã¾v9 ¿W-l¾ç–�¾Ë˜•½Ä‰Ä¾Â¶¾qˆ >õ\=ÊÁÀ>&ÁÕ½S/b¾„€�½œdó=˜í¾ñ‚/>™˜¾“À¾€&—½ò=FL;ÌM@>% ;» ¾Kº?f׉>åi%¾8×<'О>Íß•=³¾SÛ½¹€>áns>‘  > ©X>¯ù+½¨‰½ø¯Ù>|Ð= è½OÖ‚>ÆÚ˜=~è¢=„ÖÊ>Wh½²Gp>#Ã=ámƒGÈO>¸ú½”;>I²¡;pD.¿ð5”½†ò¾„‡¼g]Ý<±\½Ù¿>>QT½)9š=´Ÿ#¾éa¿>F›·>Ý1¾n­7>4e¡>“<,;“¾0Ľæn>=3Œ=Ô9¿\›Ë¾3, >®µ¾MLJ¿sÂ=ºP…=gy«½ükr>]Æ=YÎ*?ysL>¦å¿hÕç¹sÒ½˜ì¾æg�>f—–¾Ë5®½o™Q>w\�½“~,?[>N¬•=aå¾RGν¡ü§¾?¤¾¸²Ë>K­O>”¥î¾/üÓºgE»d&”>Íš¶>4Ëh<И¼×NÌ=Aî>§È ¾rNi=«ÒѾ�CW>Ùž½ÝB›>’,<�Zå>Ĩ�¾Õà;�°>� ³¹¾ž­õ½VsнšC€¼õ¬¾*¸(=Tÿþ=ÁÄî=òlµ>*–ˆ>à�> ÏÝ=4ÿc¾TìÁ=ûn·½ûɽ±!½Ï†>jnˆ¾»<æ¼súõ>£M~>Wâ£>¬O>”‘š¾Yñ_¾²¼ö½æP?>íS®¾~jö½ø³©¾½i>ªô“>œ€‚>g!¾ŠyG=µ^´¾ˆ¾Ä¥>·üG>Æ;¢=ô™¾ª¿úï…>‹r_¾‘•x¾eæ½YAž¾‡2ý=% =÷¹Ž> ?9Öb>šϽÅl´½”>®<9ò¯¾#g>�¾à¿¿ ·>a·¼ºÿ-H=YaÐ=·×\><>¤/ ¾±tN>H–µ>–ؾB È¾É>š>°á¼6‰¾ƒeI>d�å=<à’=É„>êG‡>°Û¾¢7¨¼Ü}¼‘B¹> ó>!–<½ÔE�½:&™¾YYÖ¾ìe•¾­ƒ¾ <ý½s´>�j¯½ÉS¼µì¤¼$fÐ>€ë4> (=,>üÉQbN�=¢f½ÔϽ>«à¾i<¹ +?ÓžÒ¾Žs$>kîŽ>=�>Cü >A·Û>å>�½&é >&¬¾/�Œ½FÆ=0>É‚×=]B)½?}ø=Mª ¾ 6ƾeœY¾Ó2”>Y5¿ Þ’=ñ<™=�v»>K„=¦ó ¾;?çû7=8œy>6Î�¾)Òh>C§½�~ ½í6=#å>*¨8½^º”½ò Á¼i¾³û½=Å…>|½>½l`š. =5‘¾” «¾˜Ÿ=`? D>¹÷->Dü!=Æœ¾BªŽ=ˆF§>¸6¾6Õ¬=òC(½Ûyµ>ýˆs½ÝB¾± :¿¤ˆ>U+ë¾@W¨¾æ�¬¾ =3®Ž¾žº:>=g¿£2¼OU.?|E=—:ª=ý�¾!“>[ד¾ÔýÑ_>x>®>ë.u>¾9ý>?Á>:xº¾ñ╾õ0Ô¼ çc¾¤Q ?ùSL</5>t—¾�KÀ¾…ŽA>¥W%>ˆˆÀ;,ù!¾wKº½ž|C¸T.?»2J=¿m”<¶æ;¾ÿlà>5Ñ‹=ʾ̟·¾)`> Í=�·þ>Qx»=i/Ò=ሾ¬­>¸´µ¾X¤¾ ìò>\ð½µ—0?jðœ½n<�-�=† >† �>dåýä¾W¨">/3>¢y>û3»½S½—}¾c‚í¼2>ª‘¾iSt=Ø�Œ¾å ö½:‘¾P>ï:õ¾Ï‚=ÚÓ£¾^¿;¾Eý>F½'>­ü*¿)þÐ>»�>Š?’>ÀDJ=�XξvQ�¾ãÚÉ>•,C>ƒL ¿‹¯Ü>ü<¢=x½£>"å)> ¿!>Á¾AàϾj_>S݈>±ó¶¾3‹�=Ž.X¾fÿ3>³xµ¼ˆ={>ñM¾ ¾áP‰>FÓ>•]>¸À>2= €@¼-ކ> K ¾Cs½Ù‚¾{3B?éMý¯Ì§=á°Û¾Y>Ñj½>–&€=�|‘>S¾iWľê�·=ðI7>êb¾ÚT>I@>¾¿’E=™š¿V9 ½h‹{=5Më= m…>‰â•<ý£½¼w·=»¨¾U½½.7¾4º%=š„¾pË•½ÔH‚>»E[>‚žÓ½2=±=djs¾qW¾íÒ{¾Èa ¾ù¼>þhʾö=·åîϾ³ú½±›0½‚‡+¿“�¾¾³b=%i+>ÿ…‡>£÷>(kë>˜l_>RUâ=ÐZQ½W:¿ŒßW½µ‚ê½ÿ¼í¾3M½Æñ¥>äö‰>`P;‰³>Ÿ=±DÆ+FÕ=žT?Å+>,[Q>öy€½jj�<Ë`œ>;Òÿ<úü=Á©Î>)̲>¦ t=þÅC>¤ ->L‚$½h¦œ=ØÒ“¾Bœ½H„}¾"Z„>Áw\¾fÏξFù9¾ {¿SB’¾¯0½çG>ba{¾JÎd>Ríí=CÑÅ>»¾Œk*>ä¿X¾ö”­=U •>9¾ÀÖ¿¾â¶¶='å¾Åà>ï°¾Ð,¦¾q"f½ "å>Ý®Ÿ¾²P]½\b°½STø>�¢"¾û…º>B0”½ãùí>¨x¹¾Çä=ð­=&uƽto«¾:ì¾==Ü=‡*n¾-ùý½Ø¾€µ†>I>ó>ÿðè=Ü_7=#jŒ¾®Ö*=é¾(ýLûÈ=ÅŠ=‡”¿#(Ô¾ñ¨¼ž }¾ˆ“½}Ô=Bh·>ο�º˜>q»¯>L²¾ìœ¾ð2Z<ø¢>HpÍ=Ç{ ¾~À¸¾ÿé=4zÃ=Ç»¾ÁòX=«�>.ýŸ½ðÞ>£}Ô½lïë>�¾§¾�1?õ²¾kí¦= µ"?òY½µz˾Üìë=Ä4>?¡Ú=Ýä¾ýB2¾ú„x>Û ‚¿n9³>æ:¾ØÃ™>R1(>]K>>.‹äºµ�½rþ=‘ȼèÈd=âI�¼˜N> œÐ¼…ê¾Ky—¾Ô†>@ªÕ>K܉¾öí?=|ž½Â©œ>ƒŠ ¾ñ­M;Þ( ¿Ê™Þ=&g‚½ì™š¾¢éÁ=Ý­¾�Æò¾ìÞç<á×=‹Ò=)<¾Þ6¾=s|d>KÀÝ=P�q¾üÙ ¿¥¿‡>´ÿ ½æqš½FF?z†¾ ›¾³ž<ÃùÆ> 1;>ìþm>µðȽ�] ¾1E>W¾Dê®=Ðï²>…új¾ø?½”s¥½Ðxg>�$Š>¤Sž=H±Õ=‚6¤>ú¬¾¦1Æ=ËG¾Ä¿=óݾlÅr>ÀT->šÎ½ånA>fWb¾C%'>€¸P=dïÖ½ ‹>~iÁ¼¾ß9=¸Ë¾Õ³u>ð㾟R¾[»ƒ¾Xü=ÇL?Ñj=§Sm>}ÈL=ãú]¾V`³¾åؾ¼�##>Fƒ½/1½Œ<¬¼v9>$ ¾ àá>çi§½¨Â½m*Ã<êX‰¾¶e>Ö 0¼�b(<±œ©½²RI>1%¾JȆ¾Æ�½ >Ï ?»Œ?|¾¯¾ç=)7e½ÊÞ#¼¼#”=žªÓ½±Í\>R}:>>M'>øÚ>¾|#¾5>šô/>(G>’¾Ö>P¾ÇE9>ã�r>Ê×¢=fº>ØhE½[g£½û3>&µ¢¾‹(�=ÙPÎ=ûÎÙ¾¾>-ì¾M­T>˜"ò=ÐØ:¾AB>þÓ˽H¦­>͘¾ç¨ˆ¼ í—½‹è¾ÌE½k”=uRCºr‰6½SXY¾Ä|E¾êãÎ=ÄRr=Òˆ<”N"¾Á)>Ü ö=�_F>k„½¸!²¾*ä½>4½èÄ5¾‘>‰“d½ò”Ç=³kÀ½h(㽣ì¾ìü5¾R5j>泟=†µô¾!¸}> Iö¼PÝ>~Q>´·¨¾ñ·É=7{6>`ÞÕ=È!o½ä =ïᕽUIu¾uW<=VE{<çæÇ¾MW“>n²)½ƒš¾ëªD> e>¾M^‚=‡l€>ŸÚܾú>ÁAB½Ó¥=Îæ¿×}Õ>ySc>b9ã>dg/¾sI޾˜ù€¾ P…¾l'®½.¡S¾¸Ÿ#½n£—½ 3 ¾$#>ž¢à¼ôë¾-U&¾«gæ¾qtѽÅÜÍ=Ãb>3:$e=±i ¾Ü!˜½£…¾D->91ç¼{mȾìò¾{ǾEØ>“¿=e­¾N¶™¾‹ªP¸Í=æe>ÉêÆ>âYK>4¶¢¼á’?8ƒ=´æ›=Ͼn«½ŸÞ�=»e"¾mUx>v5B>¼¬)=ŠGŒ½~—½ sÒ=nôƒ¾¤Jý³[?_�½]櫽úê>Š=©>ûŒ>à „>D'T>�å¤=•ú�=+È ¼"áL¼Š‰g>Dœ™>p狾\€•¾3Ù�½2¾s¸»!Ó$)ûB¾@~A>3W†=*>Šd¾VXî¼�þ=׬š¾ ö½]‡D¾ß›Y¼Ò¾Ø¼:u¦¾%àºñ:½ífK>MB¾‚�Y>õ±¨>Ô;¼HIA>ó£”½L7ì½ãšh=­?Ľ÷bh¾!Ûî½#’°=‡èß¼-ú®=ᄍ㓽üô½öë’=(œÿ½ÇR˜¼P¡0¾Ý\Ú<!¡>fT¥;e¼ß>�.á=ú+½Žw½Ë]Ø=ï—†=~ôD>@Ù)½"ƒ¾½Â>û=)D>˾2½œCÁ=uJ¬>ÌÉ%¾3‡Y½}\9¾T|ž¾W¹�½÷šî¼R³<æà>œx®½Ìa¾Wµ=gD%=†£â½,%…¾týô½ u">6\=íqž>°”i½'d#¾Øb3>üU¾xä=Ÿœú¼qø¾¡Ñc¼ëý<Ò•ñ;/HN½êá½Eý½qv=‘­>óÞ½Cª™Ã�>ŠË1¾�Œ¾Ô„½G º¾±<‹7®½€èX¼�õ*¾(JO=ƒƒ<–Н½ Ód¾ø‡s¾ÕŸO>y¼‚âœ>hÞÚ¼@g‹¾X=ô¾§ ¨½ŠÎ>÷ço>`\þ¼8̽ÜËŸ< øX=¾¥ö¼Ü̓¼ë�¾‚ñ:¾¿M�=¿\½¾$K¾2v¼Æ˜†½nà_>…ÔʾîÓh¾ÃŒ=ÏK>êI.>ÐZ¾î}-¾Vj¾”ü)¾1Âå¼™Ö¶=T+¸=u/Ê(>Ô†> T½‰ä<Èù5>_8>‘ˆ-½eü>…ƒ”½ʲ9þ9½a¥€=eê̽i á¼ãc>üD>¤Í½·†¨¾ìôa>ú+.>Ú¸g=~‹ñ½G²>f@‡>Á�s¾`ñá=Ìe ˆÒ½!<)½ŽÄæ½Þ¬�>-—>I©Ž¾0ù>—æ>ORþSÄ{¾Oø‰¾�Q>>uFÎ=äoä=$Ð_¾e;E¾ó)>äʽ ü½ \=Œ@Œ¼T•#=Mýk½Ù­d>†I¼u¿=ò{G¾k@¬¾b½g‘\>Ìk¾ï1¾ñÂ<Öqo= 0޾ÞË‘½  ¾¦R°½”ˆ«>‚;}½Þq½Ãñp>ÚF¾PT9¾©C(;$N÷½®ñ½~¾aw>×þ©=è� =ŠŽq=¨¹¨<ÄO„>�¼Â�¡<ýn¾Àá=SŒ¾NO³;Qý½Ô;B>‘¼_^ϽÉŵ=h0•Í=O‡,¾]0®»óçÕ>E¦=ÙÍ|>¸Ó½Ï <½(õÔ¾Û±<»p…½bök¾§üÚ¾˜Í\¾&þ#¾– Ò<-< >JÖf½‚]d¾¾Öl>!/°½Jí¯¾?€¾/œ¼kÒ×<£Ôz>–’νe½Ë½.b¾½�+’¾½Î>8<ç=:Y ¾¡Lʽ¸K‡>?À>æ¼�<^/R>ゲ¾Òí彇i+=„þ'” ×½.ªŽ½Ç¯ÿºðp>ž¥¾Úü!>ü먼å”1¾‚A”¾µò’½ ¦é=ø‚p½D#=� s>ñ µ>QÛ‹>¨ò!?‰*ýÿ°¾I†>Ï-§½‚,L¼b†½^u¢= ‘ ¾ç“=8Ý¢¾·°?>—xO¾Õö·¾¶Ò½ý¹½tK‰<úƒ½;-É>µo/>ÔÓ›<…Ÿ|¾õžŸ=îæ{=eÝ—= M½LÖ½ðÓR<_u�¼-‡æ¼‚ç>!;ö½ðÀÚ½(c¾€‹³¾ìèÓ½>^>Ú‰¾�ß*>Ó´ >b¾M?¾q/>–ð¢=,¬<‘Y{¾Úð¾­#µ@ú–>S±�=?$?fðÐEнßN¾&R4;ó’Ÿ=y£ú¼rø‹=ýx2¼’û=Zý®>ûÆ•;ªl!>;1>=‘žm=“”޾Œ^À>So'¾óôk>®âT=˜_ ¾ìÈ.>­¯½çïw>25>W¬k=*} ¾*ÿ¾�u>%p¯=©¾ ûÍ=&·=Û!Ð:3\½‹"v¾EÍ”>í¾m6�½—ì�=ë±�<4M|;×´¾Üh8>ˆ„ƽJs"¼3L€>ìq€>üX>FUÿ¼ �=Ó[Õ½Sÿ=®í½/¼8=%8>%r>,ð�½¶Ú£¾d�M¾A½V:/¾ä~¼Ûk–>¬ =S?S>ñq‘½$4(¼oVÝ>ÏH&¾qÆ›½ÅÌñ¼z°“=æ]Ò=vê?Ê”Æ=.3=ï… ¾Þ�>¨Â'>þé…>§½y½p œ>ˆƒÂ½Ù=6úQ>Œ‚ð½ûRì=�ªÔ>¾å½&a¾]ܽêsË>ÿ/¬½ËùN½¿¤½Ý.M>² «¾ÉX®=0eŠ=‰/E¾,›/:#ô>å­=½Â.¾±‚Ã<¯†ø½9˜½óݼE¸9=ç«ú¼Çî">}â >Hdž>3ö>cm�>˜›ª=e†q=A1½+q=u°¾bãz>?8‚=& 6¾ÏƒÆ<Âó>)Û>J´š¾CZ¾¢Xj½<ð»u&¾q´½°>¾T‹ÜÌQ>–ˆ>cξkÝe>ˆØØ»¦nb¾®œà½C®F>ù\­<6ª½0`ò½×Á¾­yu½‹Ì?ª¦�½6UçÞ".>ljo>f«ö=Ì‚§=ò�f½ÑP >um`>è¦;>#Ø@½»`X>h>'ñ½ïž=Ñ6‚='ɾÒ3p=æHB=$>Þ¾]‹á½éü¨<%ˆh¿{>më´¼†Ó‡:°½Ï:¦=Hœ�¾sFº¾ÊXk¾þÂ=^ؾóJýjʳ=,Ÿ“>†¬2½•¡‡=R’Çg¾})L¾¼B½=Üí!>Ô“=x€�>J –¼Œ€>>K=—n¨=ñOâ½hø>t”½%¡>}˜¿1µ–>lò¼=pçå¼Ë~=œP4>Ø&վDZà»VêB¾K^t>£¿O>ãV¹=8£½êdQ¼¡· ¼O.Œ½èG>q ²>Jܾîß2¾,­½2_=š\™¼Ô¿–=J¼&>�‘ß=› [>+•ÿ½2‡½ä{;>x’{¾êý;v:8=v(9½U Ù¾˜¦‘¾ËQn>ØJT¾º<Ú¾}z¾éÓª½=Ù\=фԽs9¾ìp‘¾™�ó½[�>-" ½úT}=¿I¼!,G¾ü4™¼²Ð(¾á´r½½ >^›°¾××H=›#¾­1¦¾ Bo¾no³=î7">é“ͼԣ>Q]I¾'% ;F‡N>§fœ½X ¾Ú «¾K=µ;7>°=B>�H�>­Ýx¾\ÆS½Uú=^æ¹½!= ½dŒB=õ¬ˆ¾A±œ>ÓR|>?å¾)’_¾d¬ñ=´Yà=6ø½‹ë$>�o=¥†½Ë»M>ˆÔɽ�ª¾'„¾Ñ ¾vøä>7Ù[<¹Ð >rå³½lN¨¾šè-½fô¾›cٽ߼>â3;šl+>dT>bW¼=rðÒ¾ß;¾³³É½y =•¤u>ñב½{>‰û ½Û'a>˜Ìh=•{½hr>iݲ=ã% ¾EìJ<€Q¼¼VÎØ=€Z5¾¶6=_¥9½vì1>[-¾I/¾W†=©V =ßÎ/½Ü1®>À‹'>ïÿ̽°¥…¾{SŒ>¢4;>hbP¾�™�¾˜Bm>¸½>á=ÒÒ™¾·«™½Ïó>g<°½Ý…i½ÑAï=nGI>ú]>§•ˆ¾jZ¾s“Æ>‡ÿ ¾m7‡>#˜>‹üM¾ÖÎ=¢¶“=ÆïA¾_E½0A>3—3¼pôÈ>»i†=£4�=Õõû<>æf¾åeJ>[|o½Û1•=\±�=ãò=ór>É1¢>е>­K¿>CE ½Þ»ä½à7d½—˜D>>ð�>c‰R½d7Þ<€Îr>}—¾Îú¼z� ¾J*о…+_>òù>$Úw=ሠ¾$.3¼{Œ ¾¾žV>!’=¾u¾¨m"¾�Ñh>†}¬=>ƒŸ¹z!½Ö댾Æï¾˜}’¾“½…=$w佃û=­àÓ½ë÷†¾t?œ½„Z½Ûä¾A>Á%Ù½ôFu>¨Ðž¾Ü´<½fz^¾ê‹J<Žª½Üs|=�4à½X, >l`>ùwW½…8Ô=ˆW >·Y¾4Àn>#ì=R!�½ôY£=­>c>àዼÑȇ¾96å=ÑŽ†>e{]=Gßl=º… ¾ÿ—€>üÿ»+†$¾ð“!¾ ¬½•…[>²©=A¸½·)>Û—=¸¶V=ªl-½Ó‰;*r=†¯Ÿ½F�A½ç3ÿ=ˆ±¢=?r>uù>å]r;©Í½…Žƒ><|J>®^ƒ¾¸7½:gm=¿À·=ÕÝ«¾}ü½A´?=bQ'¾Ôê-¾h½^I >XÐÖ¾2e¼y„>Ù…¾Ç0M½�n†={×<¶f|><Á¾"¦(¾(r¼=6.½Å®>"úµ½­é7>ï¬ïº|J[½×dÓ=A™>e¢¹<(h¨¾â >DL;=2O><ªpÖ½î©R¾U_�¼YÌ*> ùö¾ ‹=P�˜>‰t0¾†™û>ù ϼ°V=õ=§Ã¼¼† ¼KÆ->zr8>%¾`p5>W¾‰Û¦½FA¾’°‘¾i”™>–ç=Ú´9>ö¤=¶‚Ü=|DÚ=Ö0½o»m=:xK>®ik¾ò•§¾x… ½ˆ·¾hϼ±m:n>£«P¾9y ½/ɽEC>a�ƒ½�¾(>Ö!<`S„½RHD;Ý™�>מ¾ŒG+¾–fÕ½E9œ»#nо^3\�@�=í å=/ó¾»Ù;¹Me>”Ñð=_ ½zɸ½ÇLœ= ZR=2ƒ>ÎvŒ¾ÔáR> â"½ŽÇ>Þ|€=RÅÂ>|b*=‘P4=WÞº=@Œ�¾¼‰³¾òÈg>’Ü>>¼;æ9T¢G>Ðl‰w<Üx^>6]>@`Ǿ�²I=Ž„¾C2ù=6î1>¾ž´=Øa«½÷®)<àòF>›‰¾¨çn¾î•î½+~->>˜üøcK¾jH ¾§Õ=’¯š¾a¾÷¾gÖ¾^5Ø<Šù\=2± ¿ôo=ɘ>>dF<:¸½�²¶>jQg=Q.a>ö {¼põÇ=Ž”6=9_+½Ý]ËN1ã½Ç~>gšZ¾ólݽï�>G‡Ï>¢ô:>1Ÿº½RÚ¾î"¾Ï#-¾kbŒ=‰Îƽ‡\|>iÉÂ=×Þ=[(§=ç’½füƒ½ 8Ž�ñS¼•óŸ½ïÛ;9§Ì½LO>"Α½D->ö¾!Ç뻲ф=Ïo=~›½Æ�S¾-Êß¾Öf½Í¾ŸI¾<¤­Å½v±j>Dú×;sÊR½Àþ¼7ñ=Š,B¾µ»4¾ã™�¾ñ–!¾ÓV>þ+)¾ýYw<F>Kú>’¡7>uÖ ?FÀ»=À¾qfP>/¾?ø¼{z>dʾ3vÒ<²‰N½¶®¨=7€=Ôâ;¾ÌF¶=¡Ý‘=F¶�>3(,½¡ËD>sq½ý d½&žš=ø>ÃÙ˜=î¡G>ŠÝ½ÇŒr¾ØÌ¾bz‘¾¿N„½©B2>ß«š=$E¾}i÷=–â½Íëµ½3åT½|ÌŒ»%S >�F¾½>ÔW:¨¢°¾[ñÖ=Ñ¢>F-ü=׫½X=ó½ñ¾^ÜÔ= м>˵õ¼Íê§¾»ò¨½¡ì½š>=køa=¾ü/%×>S¦½Kx¾™iC¾ëap¾šL“Ɇô=5 >D>@×»c9�<ìÉ>ÿVÒ¼î¯æ>N‹å>jVT¾4sñ=ßZ½Ä~T=]q<:�U;§ÀB>Ù%½í~Ó=G‰S>R™>¾$ÆÎ½e·7¾*º=®d¾ÑeŸ=�Ÿd>ˤ/½fÿ×½*Î>ˆ"§>@*Å=Óƒ>Z$¾Gí>Rþ_¾åp: ˜ó¼Oß!:B°ƒ>hua=é¾Í=�‚Ô=þD>îÔ¤<"‡ô½ “½a ><ý_&¼'–�¾vöD¾µ6÷¼»zR¼,E¸=âRw=¾˜Ø=„FP<x!>áT=Ýš <�/>•úu¾_kˆ¾ñî�½ÊRY¾ Y!½,k½Àþšç«=̈½}ÅX>?r¾Q´Ð½Ê‚>vR¬½@Uß=çö¹=áÛe¾õ€½ÑÏ>;j¾Yªá½D ²¼,÷¾ cW=MC>-Ú'=Å> Ñ!½±à#¾»¯)<óᾟ’¾Õín>x˜>¨Ü=TG¾™)D=­“.¾XT{¼i8a½´ÊL¾ œ‹>�›6=í,>c·=×Ç8=¨Ô'>X%¾M…’>§Œf½D˜N=Šƒé¼‰Ëç½IV€½L�=d<¾¿ÓZ¼¬(Ô¾Gâ4<ÞÝ ½–— >²º ¾˜Ï>Ÿò±<‹¾1;urf½¾Ž–>ƒ[g>%¾&u¾¶

Ê^ñ¼¢¡�¾ü*;=bµð¾tÐW½®³>,Ü¿½Í°ä½ôŒ8>žm¼Þ=‹>–νÚÏ >9á=UiA>Å>uz¢>¾T =ÛÇ•¾J¬>žJнZ®®¾�k ¾°ì½^µ(¾œµ>ýÎÅ=â�…=j’Û=M°n½–3‡½«â^¾W§¼j(3>¿XŒ½9ÛÓ<ºã%=Òa¾¾RǾ=}5L¾Êi>Ýq޼÷; >Æ™€½«¶=Ûችe8ä½Ãǰ<~UÆ<3ÅT>w‰7½ã\ ¾Ç?�¾2;\>Vá9u4¦<í‰ç½­N¹>5A›=Jþ¡½šßz¾ž^•¾)ôǽª&.½µ5!½ÈAνxÉU=ñå>je¾ƒª©»Å ¾YF½ï ¼BÄ*>c¾ ¾”5[½Ï‘´=å=9Y½º£~>ކ5½@W´¾W}=Jz¾ü•‰=a[">AÕ’¾$@>ÍZ޽Ïs>�j6>_{U>x{½­à£=RÆ>+O®¾Û_¾)º8>S<á½ñ(x>OÙ@¾6[¾¨äY=lO×=ð¸D¾AõA¾>¬Pоúhâ½w|¼ñÇŽ½ÊÖS>’Æÿ=" =Æ >µ ï½�Ÿ�>D«ª>‘/ż]Ç·=4Æß="�=n“w>S<2>âý“>Ù�=€‚ì½4šÈ=ß�¡¾kÔȼ‘Tš½˜“4½�vJ¾‹”'¾VÎÆ=%�;¡æþ>ʽþù•¾4Œ„>WZâ=þ ¨¾âí=vñ†>Óšn=Sxv¾m Œ=¾Õ¼ …½³ä½€[®<å›:>¤m'>D±‘¾VRýlƒ¾¼ q½Ü>–Iè=Ô-«=Ç®ˆ>Šˆ>.h >¬}7= —>>;2¾Y¶ß¾ö|Œ<ƒ;>^±�=uz¬=î2Ô¼E»]¾îP¾€r:Q¹{¾[qZ=­ 2=%À½Ë4뽊 ­=.BÁ=ÞlD¾WZ�¾Wšd¾$ù–>¦Àù½Ój�=°Ì“¼üÊO¾kÆ#>bgÛ<,²`½‰:Ø» *<-»ª¼(>¶§Ù¾X{½1d(>½Ì=�)>N�=Ó?;%û•½’C4½žÎ¦;ãpI=ÿ=°¾¯Žž½P°Ž=RÁ’=Ò·¾� :O¶Š¾RÑY;‰a¾åh»=K»>ùô€='¹=ZU,¾íIÉ>¡²ò=èî¼¾v[�¼5�E¾ý5½ƒ4¾Ò|“½ß ß= ¾ �²=Š5e¾ÐJÐ;\š½ú«‡>jð°½R,>ZE>6ü7=ElŸgp¾Eƒ¾�>¾:œ.>¯p%¾Á=¼ež¾+ðl½Â�7>\qç=Àž®¾©8> ¡¼»u ¼(²¼¼Wq»m >Në¹;pݽÖʽDº†=�ß´¾©±¾¼°b#>Þ¾ÅãÍ=�Xo=r}>¥¹¾>�>ö>°Å=¾Ü”нƒI|=?'>×®Ç>,p0>¡y¾+}�<œ‰½Lm>›û¾8>B‰Q¾9.‰º­ÊÖ<½?>zá|>_úc=}!¾)’>%³¯=ÿøª=ˆaî½Ào¼8ã½îÕÖ½ÉS"=ô¾Ÿ/>`便{޽R³N>Ï5Ì>øÕؽ¹à¾·¡½ù¿½¯ß1='\‡¾´ç|½Û6"¼>ƒ>3¯ >g�‹>~vZ>ˆ…½æ ¾Ua­=?2ѽÁ^<º>¹°x¾!ZG>Ï9޾c-´½Sý¢;´X¾·"¾Cší½Ö>{µ½ˆ+¾ž³^¾¾·‚=w¯=Aß6¾ÈÊ·½¦ÜF¾Cc>(]>ë‚„½Í­a»;Ò±¾�€•¾þPڽθU=ø9¹½^_T¾î‘»½sµ >] ­>˜ÅI¾5S>Å<î»d‘>‘çÖ>Ctm=�N°¾.z ½õ_%=´ªÐ½œŒZ>Ótß=Ý_¿= ra>§I> Y9¾¨z½¸Xï½ ’@>.Èn¾±0‰=WÓB¾¾-¥½ �¸<š‹Y¾2ݽµ—/¾‡²à=E³½¸5l=Ÿ‡¾J4Æ=ü¶=m›¬¾M»=±$q=Ïç2>O¼È½w{ä"“Ã=ºV¡½5Žq=‘:¾ºX3½Õû=d-�<>"€=š‚>N>@Š2¾É[Î=k�>¨i==ÕdŒ>¯‚;vW>qõ=)×À>ˆÃ½ûÇ;½@d½p§H¼8¨H>4e�=ä•=óª>n8e=<ËÑHÓ¼‘'½Láã=4|€½b�½9£¾I—ò÷Í>)4n½%Я½ò¾B;Ò=dœn¾Œ¨½m€¸=qKé=ÊÈŒ=¾`l»* ¾„H¢½4^¾XÌ>Œ#Ä=ˆT¾Av¹=h‹½},x½4!¾½M°÷=så€>¾½E>ý�x>³E”=Œ)½m�;¾†9½¼e=>5WP¾Û×¼Q_I=—ã¾ò½ “㻿ۻâU�¾xN4>ä;vÑC=·7á> Ê|="|'¾œ‘¾©Ä=jY.¾íÁ½(“f<^g¼½É–š>¾Á=‚Åú½z†>y¨¾†û‡=‹>µUL>úã¿®¢>Km�=Äú¢;ØÙ=»Ô$>h�’¾Ê�4=c ¾‚ľ۬A>õs©½r…Ï<­“Ÿ½ªV¾Èì½>J¯½w·b½Kx ¾«Os¾9-…>Æ\¬>Ú-¡=ÇEE¾ô‹»Ò@3¾D+¾ªL>�›=Ó°»Mņ=¯�ª¼¤�>]¼O¾:ïF¾oŸ<>¸™.=E„[=åÞ½ {¾}x0>j¦�>x­e>bF¾àÛ>«>ܽfœ=¹�2¾—M¾ùBù¾F©=—' ¾²&A>܃>¬ºk=¥þ>?÷Ó=ù²v¼®ÜM¼\ÿ½‹J½êTÃ=¦ëÿ=óVK½ùó%¾�T½gÚ>êG=´ê9={Ê7>¯› =§o¾s¿—½ÕVå=ÒOn¾ùá²½A»'¾ëÅE½�m�=¢M´½:B§=O01½““­=ö{½3Åʽ¬@´¾Eh½\Ô>œp½¿ ¾[®©¼SÓ¾Rçl=@ ü½ÚY*>±P½ �ó=✄>G§B=AÊq¾ž—°¾Ž%Ú½5ær½•îì; ·½¢¨½3Ü>ì™?. Á=½!ó½�W¾®ðv>‹€¯>’s¨=w“œ>>Ž]¥Ì¾=¨ >1‡¾Ø¢> –y½ËsJ¾Ä6ˆ½V&‹½ó² >½Àž=oÛ¾wÒ½N¦ >´R¾°n=q‰>¾ÃA½'=j¹¸>nžp>&à5>*Nf>å4÷½€*ݾFuK½a@K½/ïm¾ûƆ>C¦¥¾Þ¢ç½_ÉE¾ÊêÛ=<#>¬€>§Ät¾Ûs ¾´ÎS¾‘4W¾ƒ\>µ~?¾}†™>€ˆ@>"rÂ<ލ=µa�¾ÊG§¾æøÔ½gØã¼‰>Éôͽ/Œ=F, ½ò(À>’Ež>D³?¿ƒƒ©½Œq =�VÄ=8ù2½ßlÑ<žFO>ô={Žx¼ ˆðºš�>Ó¡“>©}>·�<çϽ+Ђ=8øC½&´ã=­é¾êˆ(¾Qi–B9V<±ìô¾õ—¾-[>†Å¿¾ÃÙ=m�½Q»Ì”†¾ª �½4…;>�dt½�‰¶¾çI:>�ŒU¾Nfº»®S¹óÞ…¾7kœ=ÿ55=Ø =©¹Ä=í>t¾MK=>¤GD½¬ù>„½s)/¾óÙW¾ÀY¾Æ„¯½º8>ñÞ¥>ðKܽ<ýa¼Ý´°=O_>3­Q¾2<Èp¾LR¾ˆ9¼�—�¾YWÉ=î½(77¾ñò޾z Á>r„�¼¦ ›=mK”=0ŠÕ½&�^¾MKÙ=Ó?*=ã-r>q€q¾,’¾‡Ÿ�¾´ÿé¼k6>/U>´Šm¾ºáÆ=8F¸> gÌ>�Ž>¬|>uJ>�Ž>ª3B=+D>t}¾u# ¾K†Ÿ=;Ó—=ünˆ=˜Z>¸SÒ½É;¾´¦>vNó=�2>Nc—¾t Þ=rÏõ½Ø¿J>1<°¾ˆuw¾©*¾[!Î=Þ<=À­Ç>²é¾é�¾’½îðŽ>«ñ>އD>x_Ëï=½+8i¾VUQ>M•¾rž€½q>¦>1J�>u7оA!|>ڰͼ7?]hA>\&=§T=òÙ°½k‘>iÿó=ªó¸¼iwŸ>ã¬M¾¬Æ0½bò=Tœ¾ÎÁö=é[ =þÉç½Ã-æ½s¹Ó>\½†½Â³ò=×®Õ¼ ´ð½4çC½šš‡>ë ð=~]í¾¯Œ=�¾Ú<£=ãÄ<›¥½ðµQ=ʌݽÒj÷=³Š•=£‰Æ>‡µ>”˜=)Ó—>Žÿ轟|$¾ùl‰¾EÓË=’ö‹½AÍ>ÑáÀ=ßlÉ=¿F�¾Óða>Ì�I>–›¾†Tþ´º;,iw>7.‡>×hT=÷_>óML>`§½Eª½¼sоʾ:äÌ>>Ôv¼N9¾I³)>—ô½ã;¼~®i=\¼=ñ�Ä=Íà¥=@�<›&ž>›|ݽ6’¾…“ˆ> ­ä½È¼Þ;DTƾ­B¾î(> §+¾Uq޽™T>ê<ú=Àݘ½¾ô>±y�¾ pö½y’>¾Þ„Ù=î§Œ>�“¾  Î<Ýþˆ»ëQï¼AÚ»=�>-÷o¾ßv^>o°3½÷µ½ P >V ¡=NP²½»K>9ß; �= Âû»�v=N7Q½ÖX= ,¨ºêÐ+>OÇY>À�h¾Íu�=ÐZ>7ÆK>¿|¾ÃÄܽ¶_P=Ð~”=¦3뽫 æ=MV(>㸪½ýß¶½!Öm¾f¼v T=\#¾Â�ž¾ò›Ò½ñj?;Tl—¼·Ñ‚¾qqˆ¼)*=BŠP=»üÃ>Œü½ºì°¾œa<£:|<¯)>b~¾ÿF½èg¾¡Þg½Mª½”‡=èï =¦'Ž=±½£¾˜¬½Z/¦¾ý¡+¼úé°¾c�c<ŠtÁ¼“ë=ÎXÏ= æ>mr�>ùœ=>i}è½¾º¾‹_ˆ¾ƒ‚E=e˜ì½b¨‰>!f�=Óû ½Yn>¿ÿù=š†¯<ÀO¹¼ø=2�t>E/7>\[¾ö•Ó<ߨû½&O£»@vZ¾ßz>l”¾šmŒ>^ªÓ¾Ç¹8=%êN½ãžê½×òª>ÛQž>\@¾‰1>Ly=Ðú½ìWM½ù‘ްÕd=Ð&>Œ‰Õ=Öúˆ¾Å¦½s7 ¾Âç]>“‚¸=Oˆé½©¬<> ¡N=œ@¾½Ìû< ºU='h¡¾3„t¼[×J¼O˜ž¾`)õ>u ž½Ì‰¾4RK>÷f�>¹E >¥˜½µhò¾~¶[¾æPŒ=ÎÒá½t�$=:·»\�½a«½¬¿û {½~X>’2>›öR=lm‹>U½»®¾N‡Ë½Vþ»;q¤¼DÛ¿â+ý<Š­¦:Áß½w¤¾0-¹= ?M“¯.ý|=p>lÌ×½Õݬ½ß7>­ƒ >l.ñ»‹Q¾÷�2¾0”¾IþŽ<�¾� ˆ>6?½‰D�»ÖŒÃ¾På=žo¾©y¼>ß¿>jµ”¼xq=GÁí=—=?ß8뻉h�¾«)~¾5ʱ>x>Ï<ˆ¾šûƒ¾ÿy¾íöÔ½ÿ3�>ª‘½±ð#¾`i¾Žƒ=/Þ«¾sE¢½LG¼7,g¾—h}¾:û-½ž.!¾C²n>õ�ˆ½U¸¼l¼Ë=mß¼š¡>FÕ¯>Ì6“½ ÞÀ>¤˜==®¾„ä-¾°jJ>0ÜY>÷fǾÐ*–¾c%><ú{>ÖN4¾7¾Î鿽�nË>‰8Ð<ò¾<Ó<¬™‡>~T=Õïÿ½TuÂ=8W»=lô$>1í½(¾)ÕÙ=©wã<Ïc>Þy‚>Ëî4=mY½ß*ˆ=ž¤e½h�= àµ>ƒÏ>–ºš=àñ¾·ö>áðF>Mìϼ•_\>HD¾Ô ‡>`´˜>è¬ï=~ù­¾Þšr¾/h[¾€n“¾¹C¶½ �>ÇÇC>3¼�Ês¾9¨½%;�¾Îz‹½¯Jî¼¼ŽÆ=ʈ½Ñ>jу¾Y'\¾vˆˆ½Lò¼Ô‡>�'ƒ¾ü)©¾ áD½;O-¾È⾫ùn<¸’9¾Ç™=#ÕÊ>BÁz>PªN=ë[j¾%¾Xš= Ÿ>OãL¾ô_£>#S=g!ÿ¼Y ľ‘ÄM>� ½¯8>ÊóE>e_< fü<ë=Äß<~­–=Ñ_L¾Ææ > V>#¶™½H¡½�+`½ýÿý=lƒ¾õEœ½HEƒ¼ía>¤�’½ÌÙ9>^1¾¸¡½¹Öm>êš¾n>A>vüÅ<Ú¾»>"N¾Ãä»yǘ>s¾‡Ë?6Ÿ>â%>‡Õ¥>ÝHi¼·[¾•z–=Ç W½4Z½ªèÊ=+.>à8ؾ]}{>4o[>‚šÃ>!æ=bJª=ôÍ¿Y¾ïó”¾!åö=»–Y½�çN¾è¿Ú‘æ<³~C¾¿S5>R‘>xN¾y쌼úë¬M½‰ µ>tùt¾ SL>]9°¾ntË>® &=Äx¨¼ÿæÑ»ë\>žÄt=ç À½u¬¢¾ÖÕ¾ÐuQ¾¦t€½•\x>–ØÊ½Bp±¾èóé=QŽÁ>„ùÚ½ 挾*j„>ha9¾ ¡½«Ç>æŽï=Fæ¹>–ª >ºѾ¹Ì.¾ü­¾§_=Ês¹½Pú½ð³J>»©¨½ºð%<Ô݃>{ØÔ;-9½†ñ•<�¿»=áª<¯§ >¨4W¾Æ+ò¾ï2Ö=^ñͽXp>}bÓ=Êå³¾Ù­í=Ž£(;bš†>JÄ´>Øy€>\X›¾^ï.> ­¾”½ãš>O!µ=’ ¾ñ*>Õú½:‹—¾!|>¤Ð½›ÿ÷=ð—6>x_>«œ½ºÉˆ¾{rp>cú=Odì½ì‘=�µ�=ž²x¾jÈÒ=§#¯=Pݾ m¹>pŽ¥=aª¾Vø½Y¤Ý='£=)Œi½…oV>ÒA+=KïU>ZoÖ½\ü¾H�–¾hdI¼Šå¸>©È9½ð� ½ôr¾RÊË;˜lµ¾§v­=都½èt!½´ÍC¾ø1Ä»¹>s¾]½=oT>½ ”>Ï®�=÷#>茱>ÄX ¾|¾�ê®’¾_©Ž¾Z'T½ñsq+“¾æ/½Y…!¾"ñº8n…¾Ž=…¾˜ÖO¾õ�¾hH�½ëL™»ØàB<ÐÔ½˜Â=]Zê½jÛ>ßžY>ïYn½á†=kþóª>óÜv>{í’<¿>ô¼™�¾ÏA}>ÄZ>‡6W>”Žæ½`E ¾ˆª§½ìÜK>siŒ>Se¾¿iú¾5ƈ>ŽN꺋1>¡Ö ½¨ >1–„¾‰<>*2†¾óž=f™>“#¾É¦®½wÓ§¾i8>‰ PêIÿ=}\5>çªL=¡ؼnì'½Cœ¾ô S¾îË<àg:½4Å=>#$ö½y!Š<(rD¾þªÑ½¬µÚ=+\è=9„">¦„Þ¼s~e¾œÁ>�ãð>ÂÂ>à>"?T>�¾Ëc¾ÖÛ­=ix:`.ì¾ãÒx½3¿²=ö*轘Áñ½gK¾“ñ�½à'9¾šºµ>B­ =³ >½—æ�¾m‚=a‹v>þ©>@­W>ÑR´¼\Ýh¾Ô½]>*c>|$±½ ž{¾Û’¾>'E²¾: ù;ˆOë½Ö�Ç®¢¾œÂ!¾áal»°Ç ¾ST]<8£�¼ ]H¾d•J< ’‹½#½M>û¡<‚ë4³ö¨>;|>DCl½ø >–Y–½*�·=~*`>Ž(>)¹½¸ÂY>+èž=Qâ¾×¹¾*—?¾{òƒ>·™ô=Y¡Y>!ݾ¼4N̽Ï®½Ï 6>˜V޽Öø½Šè>©«V¾;¿‡»‚)ѾUlL;»ÝJ¾N$E>Iì¦>$�¾¾¡üi>]À:>½ê>=(#Ù½ˆ!˜¾U)¸=2³£>Šlì=Š-û½Od½åþR=Ö�¾ðÙ¼€@@>{³½ã¢[¾QÎh¾¾Ø†¾åeb¾p@$¾eÊn¾¾ž›¾ `¦¾ÕfÝ=’Þ=ÿf>³rÐ=“t2¾wêǾÒnú=È&>`°Ý=Lj�>÷ª½ì6¾¥4B¾úŠ´½ k¨;3ÀZ¼Û‹E> e >À >õ>=>%?S®�>g=¼ùȼó2>|jô=³«=Ôß¼úld¾1[¡>L!<¾š›Õ<ïL>ªxݾªˆ­½�LÁ=¢ˆ€¾qžî1;¾X`‰¼³“)¾O䆾‘ñ½“ˆØ<‹�Ó½ÚÙ[>Ïý>Â…$=ìEì=õˆ¾È…ª¼{o =cB‚½›± ¾»}µ=fÈ”½xÇ ½ZÙ½êS<¾ëaë=t2†¾Ýqƒ¾vãa¾Ù–<¾wU'¿{˽♗¾¢dß=Kßn=W·n>¾j ¾�¯«=þ‡n½r9ä¾&A“¼®ŽÅ=Àö»¥9L> 0>œ¨>`d(>{­é½+Žœ>|رdÜÂ>ûÈ…>¡H¯>A>šq¾{~C>~=$Bº>X2¾%|�>Ñáï½Íê=r¤Þ¾î[!?·Ç—¼Qƒ]¾Ö®½Vo>eÌ’>çÆ=@;¾Yy+;�¾Î› ½d‚¾�]ˆ=~ ·½Uo*=`éà<ñ¯=�»s>HuI½e•�¾‘úÙ¾Or£¾¤,o=Pˆ1¾9 €=ŽÑô½[j¢½ÔæN¾Â0>~X“»rk,;.|š½‚r£>n¾MEæ<…øê=†U;H I¾uÁÐ>zyõ½Ÿø¿Ñ‰÷=¡±Ì¾¤Ä•¾¯J“¾tó½ ×ï»ëj¾b$`=…'¾WKÍ><¯;†½zŠŒ¾ÏG'½ˆ3>Ù:`=±H_½_{⽇’];S%«>Öæ=å%¾ä`꾃CA¾ÝU=N†¬=Ìœ=ƒ9È=l½Hãš¾?íá=±yŒ>›–¾Ï*ÿ½±é›>ÃÈ>¿%–½þÒ†>p ƒ¾d¸Î<ó—<¾]{=¼‡p½½U½Òƒ½Iy²¾ó;Õ½'îj>äO�½k Û½´S}¼ŽN±¼�¡>ëª3=õ�M¾FÀ°>>N•½¾c¿>®[w¼°Wâ½ÇZ‡¾Å…2?ß�T=“?SL£¾2šâ>Ÿë½½Ò6>¼~|½Èk;¾_ì´¾ÛF¾ð…¾ÆRÙ½ˆƒ>œÿn=äð½gÍF>`±"¾’‡¾ 7�>^Ù·½¤c>Jð½Šf >ëº>u,G¾Š<â¼�Æ=䥠½ÙÛ¾=ècÛ=⨼f»B¾‚é/>)u`½â€j¾!h ? Â:¾ì¹+=ò2¾VfV¾ËI�>ûô�½½¾35¾÷¬>Ù±>ˆr—>Ð¥½±S1<ê$ˆ>Ü:<:i> ×½bÏN>uÖæ½Ð~�=¼¿µ½Ç¢»¾ëÀ¡¾Ÿ2ß½Þž>‰Nc¾‚øâ=šœ>»¾ÝùŠ=òÛ·=g·>:^>¯õ…<&5¥½Ä¿ ¾^†=pZ>€);¾¤tμÙúŸ½ÊÕâ½%f_¾ñìÔ½ã�¨½Mu¾¼U[>”CÀ;M{>`½½.L¾*ï°=„O¾¾®)²>b´>?ÜÃ=J«\¾”ç< ¾éôç¾ßÛ=+Oq¾ÙšŸ>£‚¾¸×g¾]Ñ5>�PM>ìA ¾Ÿ¾ >n½�H×>ñý¾¥˜>XZ|=õiâ½%¼Å¾Þí¾”³¯½®¿=�c>Æ“¶¾E�9¾—9 >žá2¾Zн>ð>*~‘=P� ¼ÎñĽ¨E‰½Ò{òÁ&Q> !¼¾ÊÞÔ<Æøú;œ4>tì·>doF¾ü_>�ò¨=òö¾¢=6Âc=1Š>{">ùuP½¡µ=¤Ú1>("(¾m³ð½C&½ ¯>jØ¢½¿'о—R ¼aù0¾t4A¾d·É½7 ¾�N½Az±=Ђ>®`¼Óqé½û¬¢=ò“>�„>ЩŒ>¾¥T¾–q³<`Äh¾—}¯½Ò—½¥hÄ»rZ*=„d•¾¶8>ý�=�øð<Àݾ½öôH> Q,>„4Û½Ùˆ¾U¢¾r]O>`ß(>£™„¾¾—ĽòøS¾6dÓ=¹a»f\=¼²Ð¼ƒñ>«ž>�m™<î’=C æ¼d䨽©2 >ã!r½éÍ9¾ò¡°¾;­¾@xÙ>% ¾bé ? 8A¾<�¡½õi;¾(ŽÝ½1Z¾‡¾XŸF;µ™>OnB½¸UÀ=©œ=£>¢Æ„¼›nm¾àa =…ÑÐ=Œnƒ><ý²>•å§½L~#¾_o>@;=³ Ò½{ÀÀ=Þ9¡¾‡§!¿LÒC¾»Ýñ=�­¿¾v¼´½Øå¥>¶ë½—‚W½)ǽ¦-¾ñµŠ¼"L¾•á?$Š ¾\£'=YV=¾z9ô=l¸/=&,‹½ƒU¬½ í=/Óš½Ì&ɾÿbé<1ßÇ>‹É†½å³Z½·Ô½¿½ >$Ÿ½Ø5¾a!þ½zü»=Ôù>-uݼZvœ½føè½& 㾑!z>ÅÝ/=‰id>,x®¾/œ´>(X`>æeR=–ˆŠ<”Õ>dÅ€=?ž�=n"µ¾œõ!½¤W>hŸ< Ö;áx‹½mé%>øK >3®¾ûê¼Ð‚¾Šï=÷ì¾Ê#¾¢ö½Ÿ­>ºg°¾ÃV½´é«>èå;>Æ|$>t�©¾³ú‰>CÏ>šÄw¼È#å¼&Ç=Þҽ̊Q>Ƀ¾ j.¾Aƒë½…—>RT=¾º¾:æ�½1+Ù½<5l=Ä>«1 =ƒÐ�¾ŽŸ¯< ‹>}š§=V”¹¹¾ü¾ú¢¾Ho¾úï–¾|·ª= l9>Z)Q¾‡‚>4øE=­œ˜½¨—¦>]Ü@½È? ¾WF¸¾Ú‡¡;Õ)Œ=-Ð>æ÷›>ñWÁ¼ïbX¼Ö$սƶA=ù ¼tä=àMÚ<“gÌ=!Í™>„+V>¨M ¾<–6=oÆ6¾ù„==œ‘'½}@¿½þD>eÆØ<Ø\>¿¾�;Å=W?>66D>ÿ=t<æŒ=>AÀ`¾‘3ƒ=>{&½Àþe<T>áò{>A‚‘>-oº=p�ž>AVÐ>k~>¯n°;è DºhΓ=È}=ï¬I>(ÎI=Ïhm=Zlr>géü½Y¨Û¼I›¾éÛ ¾j9º=ñï¥>²!½�õ_¾& C>í4¾þ#À¾+³Ä¼BE>ëþ¦¾�¦Ý¾ßŽO½„6½e»ü½�±†= Š½x)=»¾š5>/ÌV¾¤&¾5¾é•A¾Šæ>1X/¾yI.?³`¼=-.½²P[¾Æ.a¾ñ(¾­9a¾wâ&>­ÿ¿É—>¢Å¼Å¢>�³e=å¹B=rL ?¹1T>¯>!¾q!ξUäß½¾°E¼Q½m¾aÿÿ½‰ø ¾£Ç>ÉÆ¾û†=,)‹>/ß>¥„¼t…¾ß”«=™>�>wî=+¶>ÁB…>dê½Að”¾8 É>B “½ö¾×w¾Ý^a¾yÉ6=Åaf>f€š¾Jx×=;sO>2(½]1>h >Ox¨>¿v2>HÈ#>z=;ªÇ>£!V¾Ü²´=V�½5¦Ã> ˆ¼Œ¿ .Â;MK^>éø> “½lö$½ò» ¾/™æ¼4d¼<›[_¼¢ç,=�‚ó=2ý­¾a/>'|5½lÌï½�‰Û=Ñ€-<ªp�¾ö�=äBN>éOš½˜ “>ç¦é<:½Ø¾7Ÿa=iÎ.¾L<×½ Õx¾F+>м[>»^¼G‚8>› +½9 ˽V]�¾ÅÝ€>ø×[½ì£ä=Fïo¾×Èê=°Ö>˼„¼í¡¾™s]>Ó¦½w<œ=·û!>ÿ†¾r6°>X‘¹½À¶Š½¬W>1Ĩ¾š ¥¾e�Ç=‹\Ľ%˜=î½PšW=W§=Ÿ¸Î¹h½ãÚ‰>q¾`½ª´½®òZ>¥¿=¢;>ªê<Wë¼bz6¾Q“_=¥8n=!Îì=§f�¾le޾ïŒ>Îg>Yìn½©‹³¾€x¾¸¡¦¾”œø=n>gb©>ã¶Œ½ivŒ¾ÃA½ëó—=φ�=s Q>áÇM>š8x¾öÍ©ºe|ý>ÊÎÍ»R?Ž="wò=ïêð½Ú̾Ց>•ô½©7%<2½>®Éú<Ä š>H&½¾»G’¾«õ>wÑî½òžÅ=¼Õë¼_瘾 5f=ˆ¯½ ·=‰¤>âî$=#PM¾¦«½¾<½qƒ>ÁÁ‘¾©Zá=g÷Œ>¶ ?æ× >˜.N=-q¾a0½>&ˆ…=œÓ½àÔ˻Ȧ#¾Ã»i>ŽZܾ�Ui>Õžè½¡)¾c�E>6ʺ=‹FÒö>H—=ïψ>�V?n%)>îüw¾!á1¾ÉË/>-K̽Dö\=tEH>mKz¾D�>Y†é½]œ¾Ãü˽3NÒ<íán»—a>CGw; …>ƒÖ¼½Y—ý=<ö]¾/ù¼SC¾ô¼´½hOï=ä0>î>tþ=i!«>¨·µ¼œ::¾©¬°½½y>Àw¾Mdâ»üK£¾,:>&Õ¨¾² =‘Ä�=ad>—;@¾y9‹>€Á‹½*Q¾#]�¾”z >nCc¾Œø+¾yA>O>Ä»=ò.¾ñ.B>1„ä½ï*½l V>¡oß=Šw®>ÜKí½‘>ûÙ->˜{â<(o.¾”,À<±x$¾èy ½¬ø!>Ôr1>$¢=ÉIƒ=ªE»=Ì_<‚þ"¾ŒOª=`ù=½76>âÏ?¼¹÷¼do־˺D<ùéF<íX>‡gš¾›ä)¾d\á=g¹;O”�=LÛ¾]¿¾×ä ¾ ÛJ¼§Q°¾=Ô»->l, >CÜ8=Äl½p ¾=A·¾:«Õ¾éF<íý>>¤�¾¡"I½‚„ñ=E8µ¾¦›3½W.%¾•v¥¾�É ¾i¾æ=K .>>¢²½ð¶>¾z<Ç=lÅo¾1Ñý=½Á½Øf>á¾>+sÐ>°T¾ ñ=�ü–¾ö·Í=³“`>ÊÅ4½À„¾@o>»±>¼žÁ½{îZ¾ ãw¾~’B>r¬P>Ô–X=»B.>ë�Ÿ¼—Ùûø2{½ ^`¾*Á½Uù=¼‰y½qÀ�>ÂVt¾Öqú½á"¶½„�ï½0iw½†‚'=ÒyL¾±š‡½«òó=ˆ,>ùC·º~Œ=¾Õ2¾`ݽ*=>Ý·>r—S¾½pÕ=Š ¾ñ‚_>Æ�c>Rr½Ý“>¥™¾s({>\Ú„<+˽-_Ï=³›VGÄ»XÝj¼…!5>Â"1½²5½¯ä^=¥²�¾¦c0=šZ’<¥ö ½ô££½„sž=äð7¾íc½K°J¾Ÿ>ÔØ„¾ŽÓ¼;s×N¾Jnù=ç=Æà�½’u<¾ÐÙ¥½¡Ûƒ>¹ËD<9úó¾dƒÏ>f1?¨îÑ=jü><æk¾!‰&¾ ªÔ¾g菉GŒ·½qúa>»y¹=Ñ£>>ÁÜ>rÔ#>ãY¾™…‘¾7²¨<¨w¾°½$㙽:f= yÙ= ³`½Üá?;I¶Ç=Dž.½û—ž¾rG{>?¾�I¾³›Ø»¦W\>ɍ޾Mú(>#í®¼>*œ¾HžB=*�a¾¹¶¾ïx<>ÌWܽ¬»K¾Òv§=?ãÌ=…jýQz*½ËçŸ=Û§Y¾�i>Zj>ƒd>v¾!ë9¼¦:�>3 ˆ¾=M´¾\·=.â=«—H=®‡=€0—>ï f¾õ×<^Û‚½g?¾ƒŠJ>5Ú=gí=¹Æ‹¾­�½Éù#¾pã=gÔ=÷T¾F„à½G�„=©Lv¾ìµã½CÛp>Чë½ä\=€”>>”=˜µ¸¼º�>10½c >�G˾Íçá½ßZ=>Dºt>!€r¼¿¥€»7¾[·¾Ãq!>še¿êà›½D[ª½ U>´à¬¼ëñ½ÀàÔ=A–'¾MQH¾�9Í=t3‹½ÕyE¾Øz¾…�½3¡“¾éü`¾ù>™Êà½,}Á=ù š½¥¥Ê=ùF)=NO =º&¾�¯¾©éɾþšä½Ÿk ¼ Ô¼Lfé½€‰¾è z¾»·Õ= P\=ijŠ>…=pN컀’"½FÙ}=ú·‘¾`>ƈ=÷ü=úP<>¿¾sª`¾èï®=ÏßÖ½MDR>�®m=RŸ½@p2>½ö¼eì<DÒ¼¥W>MÛŒ¾5Å>/|8¾&¢=3æ(½Ý± ¾�eÄ=“+ÿ=R —½“o‘=Ιk¾Ù`->‚w¼… ¾©¼S>X}½eм£Dº=l¼|½D˜D½’<ý=7}S¾ õ)¾Ká=i_'¾qÍU<#d¯»$€ÿ<„1ó>°>xåhG>Û²¿¼ Ã<=°5½W?V¾–Ç­=~ñý½Û]¾àޏ;¼Ô;»ü <�^¾=ϾßX0¾‹u»ÈŸc=&о&”&»Ð´!;�z<µÈX=·A;¼{6 <\Ùh>‡h¾à’.¾#Ò==PA¾Sñq<§L¾Í¾ó‚ç=›·P¾þ|�>–Ãc=}‡=3‚޽]Ss½$ƒ¾†‘¾˜!á¼´¨½‚\‘¾ïÚŠ¾Âw> —½fQ:¾WÒP¾¦;7=ÉT> &>ÒÓ >`v‘< :¾<ý5-¶¼VÊL<SÚ½ à?=ª¢Ð½Þ.8¾=(Ó½k¾Ò3%N½�ïF¾2>�Gs½Gr«¼Ú–V¼§“†=†Š>�™½³X>£²û=y\â=Û[ ½_Ž>›(>«Ê=¸µÌ;…¶ä=<Œ¾æ Ä=É;©S�<®|,¾ÑþÛ=¦æ+½/×=Ÿ8v¼çÁ=¨¾§>ÈÈ€½“_v>¾Gd>²Ô-¾øÉÞ½.?½V‘…½6Zp=Íýh¼Ž¾¼›Õ>8·˜¾ÄÁ:¾{!€=ãݾ�0Œ=6¾EöS½gåS>­G>3ML½×`ù=/Q–=Ù8½‰3˜½B¿Ð§½Áµ€½†c/½°Ôô¾4Öƒ½-ïª<É)Ï–ˆÚ½nŸ¾f‡É½·�>=è?š< S>ëµ]>¡>ˆ=ˆè>ßÄT=<¼�¼ÓÀ*¾¿Ü¬» n¾½Ãî ¾6HS>9@×½ëó޾Â3œ>ùÇJ=Ã?=>‚í ¾±M”½¸¢Ì=°óO½º>À3>ð­§¾µ•Ÿ¼Þ|>nâ=³Da>Ê‹�½„ƽÎXµ=Òv> #@¼ÙûÚ>(¸`=¾`D½Ó´>GÖæ¾ž©:¾Êk½ˆ×i¾ŠÉ>ÛW�=Ô'ަž¯>Ï *>j �½:ä>}s>Rýø=¸L¼Ì㉽"�¾ 1º>¢<x‰>:¿U=8Ìb>*�>o"¾D¾x´4=z;Ê<9ä½t8£=L)§¾;`�¾ˆ,t<Ï2#¾2´F¾ÐjŸ>Lš«=n.ƽÚa@½EÃn½ºÙá=ªÞ�>/×=‹D>.ÞL¾áȾ®T=a4¹½sì¼/ŠŽ=A5¶½ ¿>ÝË…¾¸¬Ì¼cý¾ýFë<Sn»—9¾œ¨7¾ i>¶û¿“¹%>˜%M=ÖVZ>æ ¾§>š³•:[Zì=6ëa>õB·> ½0>V§^>Ía=½�’¼Û ï¾€?=XQ½¡:¥=t?å¼Å_>r :>ŸÔ=S5>¿µŠ½(ê+¾É¥Â=�]Ƚ">(ÿv¾ž{Ó½îe=°¹W>™}¾5¾`N'¹,‹§¾¿»#>À‘D=ˆÆ>Ðç*;·¾>ŠU=ÀQê½à8= !¾*Š‘½o®¼Õûl;@Y >Z|z¾ºè€¾�®¾S³N=cÌ*>Dó¾G¸=™zu=böÊ=xà�=GÝ ¼ÞZµ½8Ø2>äà=Â÷å=;.¡=S†>Yœ.½�î%>X²=Y“k>lË]½VB/¼Pœp>…aU½¡Áä½y_„½åÊ>ÏFÊ=øâŠ>錨¾§h„=Uà(¾õ€¾ÌÉ„=±|³>DR=!’>7<.}�=n�†½ÿ#¥¾ZP>³lg¼ú«L¼ÚðŒ¾âf¾r¸¼ús¾gœ>pŠ€>x/>"!»¬ú*½‹¼øR¾Uï1¾~˜)½0; =¾ðt<±žM¾b’`¾©�>1hE>Rè!;Ŧ'>&5¾îû==9оf�xºEŸ<)¾Ì¥º½écϽPš¾bÄ^>¶‹Ó½É…9–þj¾�5>õ!s½vÞê>)ÖG½³6•½p>ƒö¾ŠÖ©¾È×ܽ6*)>¬öX¾ä³Å½ÿâ>ž1¶>WMD>«¹b<Û¡*¼Óú¤=�–¼È=-¾¢V—=Ezˆ=EìØ=m¯þ=ªv¾ÕH¾£ÁÃ<žo=ÐÅ>8®< SÃ=ŒD¾[9¢>¿iz½O ¡=ò>j–W<Ç�€»O‰·>‰ª'¾‡êÓ=ÝÚ>ƒ‡>éG> H‡¾­>0f9>¹ñ1½Wö ¾È‹Ð¾6Ü»=%QY>-ý>Á½õ6¾¼kF<ü'D¼* ¾y¾ç1¹>Ø]½aã>�߆¾&!N¾[>U >Ïø>ºçY¾á˜¾ç>#¦®½×H4¾æ¨½šrŒ>â›è½¤:m< öP={騺v±õ½4˜>lY5>c0>”äð½kœ½É’¾­†¼>ó‰=T§Œ½š1G¾Òe�½‘¾>Q”=7R'=öQª½ôœ¾¹½…®›¾Ê(ë>lÛv»Ñ�`¾,àÁ½¯c¯=H)<½,µØ>ño¼=ÿ\®¼éˆ<»D>AÅ^¼i¾ ¾tã½Ç[νÈÛ< 'õ;è3Ó=ãÿc¾‡^>ž“=k}=£»™¾M¾æ°`¾ß,=ô¢`=å×>ºX£=¨�»¾ž°Ÿ½t{">Øq!¼£§¼H¤>ì×=w‰ >­Ü0¼ e¾ty¾ÄòQ<�9»¾< =½Zƒ¾¼+è½�·•¾p®i>yÿs>¡"=i=ôÒ6¾Ò° >Â¥Ž>J^Ì=ÇÉ%>~ʾÍñ‰> î<¾)$£=mЛ¾ÂA~½i¶÷½Ýø_=údë=¯Ï?>.O¾ÃÝß<›ë¢¾²^3¾ó]¾\S=‹l ¾¥s‰>€¼>€ «½%[ǽ÷ >é7¾®’$¾÷¿ˆ=ýä±>"û+½�±½e2¾…oˆ½ê쎾æ³'¾’Ó¼ycp>¹Ÿ=X埽� ž=Ðð)=7ë¾8PF>´'>Õ4B¾»È­=#.™½ž”¶=æÛŽ>囑½R¾¯½Dr´=P ò½¿™O>ÜJ>œ‚㽸>™àä=s†¾K_î¼ìy©=�D<¾ºR·5±=_R½õñ¾J0?¾¿ô6>Õ¾/’Ô½aÀX>~)–=Tó=óóW=%r=+ ޾$÷Î<µ&D¾]ÚŸ>è=0*“>¼@|=Û ˜¾hÌ#>ϾÏ˧=jXq» 齂�*=|dÂ=ð“̹E|>Œèá¾ß‹<þ*û½+Ò:>-龚Í!>Ÿ=`ÊÔ½ˆ;#¶¾Aʈ>j%G>a*>9š=½!ª9=Mk`>Rü–»¥££¾’�¾×;3½÷B=�J¨½úÚú¼éú ?°Œ¾ŸݽP:>•Û–¾»ò�¾*gc=0F#¾›a‰>þµ=ˆËû=E >@9e>ͱŠ=(5&¾Z$>Mna¾Ü‘>‡²õ=º­ò½1`›¾ÕW3>¨=}Ú»½Æ¬O="Ùì>¦¾éàȽպê½ .>/�>Ïï=�}D> ìÞ=Ï—=)�Œ¼áfr¾…I0>X�ª¾xó>=iP=Œƒ7¾S¾a>†xP>×á>½®S©½ÈB>ÍÞ�>Øñ/>Í‚¤<>Mú½£_[>Á¨Ì>¯“¯½Nn˜½>!Å7wR¾·].=æ#š=d¾œ:ò½‰±¾x…½G•!¾¦ºX¾‹‹+¾ œ‰½9u=&R*>Bþ�=Ý8‹½ñb�½Ž˜w¾n—C½C[Ò=H,±½VG&¾5Çо©s-¾X•Á¾}Ʊ¾Åb§=Í‹ޏ½bb2¾HÒ¾½+�ˆ=ƒ¾Ò…ñ=’Š>Aˆí=ïó˽\=>Л=Ÿó‹¾ |¼—õê¾°º=> t¾ÝH€½n¾| ³½Ò¤C>×¹>Ù” >jgÅ=ØI‚>û¶Ž=ø1¾õòà½óc¶¾x>0ÝD¾ËS%>‹½Ç“B¾Î†¾´Þš=RÞm½W”É=÷ôå½?)¼=Â�›=j>a>ÎLK=BŽ\¾zj=‰°Ú½~£¾jTa=”hÕ½d}VºÿP¾›ò¢=!œX>îé¾R?v½‹"ô½òjƒ>RiÛ½‡1<¾³e=ÄÓݽ<3¼|¨[¾ßu>”\‰¾ðº7½Hê = Ù½Z2÷=-ÛE=”ŸP¾Šö½`ˆ¾«ô {M>æ¨=®V]¾.-ä=¢û±½Æ.>”¾`H>÷‘©=® Ö¼:ƒ§=kÏ<ò3¾&[g>&^¾°½Þ S½}]â½S®!>îa<5þã<Áë ¾Eq/¾b&ù¼Nô"=:øq¾"®�¼GÛG>·ªv=ÙòA½°4;¶õ@>6b.¾¨�®¾š>õX=_Ñ“=r­;¾%Õ=Ä¿¾ðý>ýƒÄ=Þïl¾ "ͽ%ì¾5ò„½5·¼[Œç¾¬È8<ì>HM2;­¾<[m3¾­� >2Ù¾0UW=˜)½Ó/‡<ι-½§uý:\ƒ‰>$¾ =Ñ»\w<ìcù=šn¾ºØZ=Äž¼!6÷½Š]>J·B¾?‚¼ôÀž=?2º= èø½Ð� ½j†µ=váɾ “¸<¸ó²½ìx‹¾ÞÁ¼ÙÌ{>—»¼:¬ó=Ùv>»üÔ=A¾3E> K•½¤">åWË=¸³—>×·+<0¥ ½üÃé=Q$>­)p>å�f=_E½¼¾5Æ>Ä?ƽ®ˆ,>Ú+ð¼«+½ÒNø¼ì(½­M!=*¼=ã™—<Æ ½:!€>Ú‹>ï‘æ½×d€¾<ÞO¾jdC¾!�¾Ï]’½Óÿ0>s5Ǿwã½´Éó¼ŽkQ¾ÀNC=Ÿm>:k¾=B¯ ¾y«½Äò±=ÈÂD½ßǤ< :оAÛ¾¼eÕk¾UŸÿ:‘”À=ãìÑ»ÃÇþUœÌ½F¯>vº¾½Ó+>;•`<¯£™¼¹Ë=ÜVy=eR€=G$€>HÌ뼜O[¾ôhA>Æ>X §½¸"¼½\ý>Ós¾ä>?Vú¼FVÇ<\Z};©Õ><äϾ1_`<Å·)½uµ½Ö”§¾œ=ç=¼öø¹<9/i=&YX=Ã0¢=|*ì¼%D¯½nð<3§Ö½cìJ¾¨”…½HE³½Ûýx½£ >;îä½ÛjT½ªx=§õ¸>«ôâ½÷´æ=H­…>›%\<Êã›>²‚6¼‚:Â=n�½B–Z¾SÅ_¾Á¾å=e–g¼¢\½ }‹>[}ì½ó+>¾¬_>9>¾(š =ĒϽKÙ|¹UÖá=¾‘ô=Û¾@¾´>“S½<*ªv>(p•;Pã¾²ô§=|o6½õ.½–…h=úh(¾¶Ü´=`Öà½h¡C¾è‡“>ËLê½ò_=ÙÅ ¾×=ãâï=l9Ô=Õ½n|¿’-â½D > +w=(#m¾4-¼¶š¾!Ø ½>_¼',Þ<ÔÐo>V÷‰¾ Û½ž,ê½èô=9‰—¾úŸ<ùÒ¾!§=zCaÍ�2¼ê_¾ÕÓÈ;²„½ä�/>—D>ø6¶½~¬#>—j�;¥–|>—‰¾5,R;oí>�Á¹ò±È=6n@>™�¥=r’=xÛ˽§à'½ {½l½»¤=ÎE�½§«=Ø<ƒ¾¼]¡; ™Ü½ŸÖ=ò5¾9¤¢=ÈK=qQ“½nØ-¾Š„X¾Óu*=ºD²¼‘=<6Wq>q¾ªô2>¼W©¼áC\=î`±>`Í»ÿ\�¾a¶„¼…ß–<)‡C=íq<Ü燾 <�==ao½ÏF¼h&e;þb0>æp�=B£=™u©=ƒ„¾T%�½¹S�¾¶ƒ=_ÐW¼.½7¾îéU>Pßq=l€k¾(‡¾Ó†<ÓŽ>�‚>vV+¾H°G=;õ ½Ïó+>!M>Þ{ܽ®‚w=óy�>™u=Ž»Y½Ü…o<‘¢=÷Å=Ú`½7¤½�6¼ÝÁ³>Q]ž:éYǽóß�½&\<|½½�X=Cj>%au½?ø»sN€¾^ºÌ=âûî=ÿJ>½½]ê=õ–ɽòyd>2ØO>K5>îÏ>Š«¥¼Do¹½>ì½WÊŠ¾9÷¤¼÷.>ššÈ¼²\M=á=k¼ñÙ=þ"¾œ­¥;®J¾9Ð˽$½„d>•誽�‚j>áv=ÒX >,N´>t-=¼x>Æxy½l¦‚>¾¾æ‡¼ýéM½çäÙ¾©Ö¢½H«ñ='¤a½.ˆ¼Þ7¾>µü!>«V¾×Áf½’•�=Ϋ¼/ž =�N½©–%½|ðh½Ø�³=í³$¾òl ¾’[ùózɽ³�>€Í> 1à=@¯A<ú‹¦½$J>\è­=ÖEƒ»Z¿ÿ=§õ—½ÊD¾µä‡¾ÛÃ�½Hó0½}Æ >ª'ݽ¡¹0¼obh=©Ëó»”!L>Vã=OZ½“ˆ>Ö\½»vb¾ „K¾×2W¾2é¼Ù*Ô½v‰ª½ôÿ»Ö»…²«½C<ƒ>Ã¥Ñ=9õ=í�>þÙ7>É“6=×´½­2]¾„²=Ènã=á2¬>ôo+>��¾^ÖŸ>p0Ö<o˜¼¾¹œ<Úò>Í l¾ªèsø:”½¬%`¾ãh>"Í�½áœ>{%N¾.ª‹=‚µ¾DN¾ædG>‘'5µ?+½¶D½®ør< f>~bnÃØ½s¾�µ¾8°�¾Y|¿ ·¬½’èU½‘5¾ ‹<Ýìz>é¶’¾`×X¾ßÛ½�ž•>|[=²åb¾“Ý–=} d¾›Ê«½�§Û=Fx"=G$¾ç\5>€W=¤Ð <Ùw¾J¡¾¬½í­Æ½è¤¯½Ž+轕Èà»+>l6¾GŒÉ=¡ ¸>iØè<• ‚>÷Ç‹¼”÷=sv\¾OØ=ù`�¼K6G=86ɾÎû)>T0¾Æ¡—½ú5¾‘Tȼ¿,>�qâ½îñK¾,C…½y| =Ý€‘¼d‡¾ò½nœ;¿k¾C¿Ÿ;–½©Bͽ»gO¾cÛp<ÙNB>Ëh€>paÃ=þ©=\LE¼7è¾±W½x©½Ó?Ú½o:Y=­»¾ßÖâ¼MÉV<òI ¼½3÷=ı­=[”¹½’‚=‚ï‚:Ζè½&_ ½dµf½\?ʽIZÓ¼~œ>¥ˆ=ï<È>—Õ½‹ÜX>†¢è½Ø×�½aâÅ»=Iì=Åã�¼,PO¾!çB¾`Y?¾°­Ç½ />kÊ$¾`^ý¾÷fe>b·©½ƒu<;,þ;®v®>‡†½ ýнøz…<�‚Ÿ=‘¶b¾�ùѽéx:¾,€=Q,ì=ýX•=� >½p­Š=ž]5¾z ‰½7Kí;GC>�…�=ˆq–=.ˆ´½]F”=«#<¾3>ÌÍó¾Ý¦”=R]O=Qˆ>GOn¾((‹<§¶>pdn¾œ½Pød¼ÿQ—= ác½Ós‚¾Mîâ½Ûò�½tz÷½kâ=úQ†=°ue¾ `>y¾d#s¼wí_¾gí¾š>¼¡e>cV½©K¾ðn=øŽ¿½Öf¸=°¨A»(F)>ž,”<31>L�=5Í…>½*Š>Ä_¾5qß=ü•—»7û‡¾>Ð;ÊY"> è(<–ò‹=z¡"=EV9>ZÚÎ='É0> —È;î…�½:/Ì<Ý¡0=ñ&½—c‡½å ¾V‰»Øc«=_‘1¾¯f¼0P¦¾æb¿;¢õ< &s>CW¦<&\¾È=Œ¥ƒ>œ‘±>!ZK>â|Ã>§¬r¾åžÜ=„<Áu(>œ¼I=Ò›¾èb,¾/Ê/>Oþ‚¼€G*>Íä=äÊŒ¾þÖ=¼„¾Tü½{ÄÖ« >£‹=Þ/>e9™>JÕ³¼ƒI™½÷»<Ë1&¾r½.Ô >µ'¾¥›o¾üã­¾„mܽ ɾßFC>°ëH>ó{.½tøÈ¾TD½ƒ<×¾QAR>Xí=fµ‘½¢‹S¼]Æÿ½ñ¡I>¿Æà½^'C<”(�¾gB¸»ã¸R¾K³¸=q›¾5So¾§‹¾Ú†ö¼ûèe¼`ån½;›Û=Ò–Ÿ¾°K—½ÙN©==g5¾|N*¾È(‡¾Z`v>ÿOƒ=Ögq=(ǽ·`¡=ë«)>{Ľڧ¾}R<ˆQ,¾S¢–=Y "¾.b=…½8>q>']¾ÿ4 ¾¼Ða>—¥s>Ò”/> â>:�>¼êò¸=Ѓ̽>ì·Z=¥³î=¯‹½½u!¾ó1+>ç%Ͻõ1é=ë+>~»2¾HÀ<¦—ß½[ññ=,,=Ï[>«˜X¾áó >؃Á>ïÂa½=y‹½KÍ6¾,*�>B1¾z=o=/Ê<ø>Wë¼d¾�è�=Ý w¾H0)¾þù«¾‰ ¾ÒÀ->d\>ü>@Â>×…½›¼ ¾2¸§¼Œý¾É›>Ÿ°>xk=÷ 7»Jǽ£ëc>Ês»¼ó5¾:ž�½ÖÞ„>¹œþ½\[Z¼ØSê=44a¾Q'< �>k™Š=VŒ­¼?ò¿ˆ_Ê=¤îÖ¼<i½Ó®P» ‡i½‚kÔ=q“¼y~Ó=.­¤=ÛøA½C¸U>çþ<þê¾ ÀÑ==…ª>V²>[c½ v«½.Úþia‹¾ÙI=Iª½xåk>¾•f!=Iiq=9¾H>„¼’ݾ\ÉÁ½½º�KN>é@¾$;˜=‚| >i¾Æ«£=»ˆ¿½¾D½ÞÏ’½§y=C?Ò;¸rð¼òƒ;o…+¾„åZ<8æ¾àˆ»×¶ã½¼È¾S) =àì<çbW=óX†¼‹€½Hf ¾Î°¦>]®7½Û">Ì£3>Uï;ò O>uø+½”¯Ç½Vq¾núå=0ì)¼Ü}ºÏ~¶<:®>ŸËоÇO¾ï} ½0®Ò=Ø´K>’�Õ= BP=tØð=�(O> O¾EB>'ªì¼V;ï“=Ð\>Jµ>=oäT½K.>l±¾ý =/ƒ�<Œ8©=E<>z£š½¾ú†=Qš=F5K½£ˆ=ÿ…>Ýõî¾ìÏÇ·þ»�”�=�ÆJ½Û޾‚:O¼Ý˾gO½œæa½ÊS�=¯{=?Éì=­@ø½6»Y¾€’à½:‘нQ�¼|’3=10>’·ð¼¡ô>¾ë ¾JYª½‹½z/G¾!œü½ª3Y>W!X¾”µ>>¿f=X=V>·/„¼÷—5<݇=¥V¾RUÖ½î¨ø=:çó=Ëoн»ü=© &¾a¨>þXj<�õ3_æ¡=ÝÏê¼W >cÒµ>Hêµ½ö‡¾ÝKA=Cš¾=yX¾ð¿½WÎ[>è‚Õ<œr<¾@²r;–¨>r« >e)B¾×_½ÊÌB>�›¼3½Û•º¼ä=ò=cû½é¢g>YÈâ½w–—¾Îö=  é½Ìm·¼À9­¾Ç‰¾Õ±>óU5<úå >k¼’•=Ú$…½ºN¬¾Ãq¾">¶>g1¾eó¯=œb>Ž:_=uù¾�>´<[Hw»ñ> ¼ ½”§¡¾WÅ!=ZÓž¼¿ù¼¨·„=à =™¼Í=pÕ= Œ™½1V*¾�êù¼�Ì+>Wv¾.€½:×½Õ†&½ks‰¾ÑÑT>Pü=@ê½;¼D=ïž#¾Ï‚â;ìa]½V¾Gn>0ˆç<rŒ¾ª3Ͻ1h–»¢ >>Ü.ß½— p=þ.‰>Øì~¾¦9O>¹~¾•þ¿`¯¼4ž'=!Nž½€œ‚= à6>^y¢½1,Å=4w¦=ê>‚û’=«ö¾�­Æ¼â�b>dó¸½ÁM=GM�=íq,¾ˆM©½×�s¾`i‰>‚\†¼2J„>·Ø ¾ 龑¢0>¦JÔ½7Ðc½‚�œ¾Õ}¾I¨­=Üù¾=µÁ*>T U=ªÑ‰<Ý:½bó½Ïª¡¾±œ>;¾É‹¾%ïϽ”'U>S›Q¾Ø¸$>ƒGF¾Ü3>M>‡�¾­Ì>½‹VF½ZŽI<’U&>ŠÊ¡½‹Z¾Ñá–>ì¡Ù= N<-)z¾ÃÑ=>a²¾© ;Œ›e½Ñkj>¬[¾*ú¸=*�½xT¾ Ú=®bk=Ön\»Ñ¾9!‘»Ðƒš½°nM»‡É=þ½ã;„|˜>í­>vH1>陽@T¾ŽN¼Vч>9›½àûÀ½¹Ñ>’@">QþL¾p7=3º>L!Ã<½D>EC±»Îôž½Ûb¹ºöhn>ó‡c=—ó;>ôÁ»½4™[>w´3>ÛM²½�ƶ½ )·½…´Œ½/°P½E⸿öµ92¾q› >JR=oN¾2„·=ˆiD¾žf^¼ˆ”>¦úˆ>Åὕ¢<>“Ò™½n+ ¾‚¶%¾ õƒ<̽CFš=<]j>5±À=.uJ=ÑE~¾ÀC¾+9½f1¾Áž¶Ö<ýŠÅ<‰Ë>¼££$ >ùtD½øÃ ½ÅÚ¼CŽ= â=É¥<7�}=òÍ=ân!½œÇ8¾©o/>},»å2¾Ìå¾(Í#½>«0—;]c½<­->Ã{Û½ _½—+ؽóq…½ Sh<2X<r±»vN>µº= €>x‚=¸2§>10b>k¾Ê Ø=ž±ù¼å> ‰¾2 �½Êc=’Yï=®²�>Ï]>•¾¾óS¬½)!¾¥(=›½=Øm>“�y=[¡½””¸»ÿ™>*ƒâ½½å¸=˜Vɽk ¿ÙüؼÑìž½Û˜Ò=MÓ�= É’=z%;U»ß;ÆÒÜ=?×=0ŸÒ¼OU«= íé½z¶6¾Ý–¼KPo>õn¾Á�¾â¡<ÖÊÿ=‹ÿ½¬‰¾F¤>6꯼d˳»Yͽ÷u==iä¼Ú”¾÷j>Ëw=³}=U&<>ˆ�ø=�Æj¾Ã7Õ= A˜¼r½ ‹Ñ=â®±=eª¾HA>×:>Æã¹¾Ã\мʈ!>f!D=yJM½±¼d>á!4=ž >yïå=r§œ½³Õ†¾•3o>l d¾²­o»+¾3¾Tœÿé=¨>k¢½mñ(¾à2ò=w<‰½‰»þDÛ½.°µÙ’=p=kÒ†½YÄÞ½C0<¾zG½jÅÙ=1Ú<Ïû¬=ýêµ>¼4M>Ü�= î=Ö^¾wŽ‹0Œ½›FS>äÛ¬=Tž4¼ÅDa¾$¯„¾ì…U=²àª=Ƴ¾5m#=·�ݼ}ãO¾[k켃p²½:ã=©ñŒ¼%ƒ> j=t)>Þà¼Ðh?¾~£½æ_„½Ö£O¾ÀõK;! =%È=lðñ=£—µ½ä6m=fÊ1¾÷"äŠ"�¾v0™½˜cÎ<Äa²¼ü:¾÷–½É±‰»ËнëhO½@ƒ,½{[<Ⱥ(=+>éÔÁ½¥hf¾ì~ýî!ê=Õ8š>í­³½ýó]>K>9~>tñ-=k5J>Ú²>dÓ½=�=„•½’[/>(~"½¢ x½\‰‰=såÝ@?W=dúr½ï~“½Øô½ìl<<„.½@»'Pì»I­½.dD>ÍL°=wkä½v2>i2º¤”½=wͽ ÍO¾4]q¼º1W=ÌOC½Ý´ª>kUQ¼BD“½®¾M‰k={t%¾)ȽCc½PÐu= /j<å¾�ÎŒ>‡>£V”=yí¾¬½=;™¼î_>¼r*¾øÜú½¤Ã_¾»ô¾Ö½�½x‡5>&¾��:>ÚŒ,½ˆx�¼ïõ4>5žP;ù%%¼Ñß½hå§>Ú =šù½ ˆ¶¹AÖ½Y#=Ú@>& м¹åè½xÀ= ƒ¿¾þQ-¾³éV>™¶r¼V %=ÇeH=ŠæU½�ó›¾ô›È½‹„8¾ ú\¼n›=诪¾˜0R½íÖ(¾Qžú½Hðø=脉>O5™½OÕ¤=¡/¼¢¨ƒ¾¼k¾ïÁï=Ö >“ÎH½7/.>ˆ½Ä½}’ž=”Þ?>£A;½2¿·»v é¼x‰=‘“Ú¼vÀ½RBнïî¾–Âļ­J¾%ï >A—‰½[ƒ<½�‹7¾ññ_=±~³=Ê->6E”½"y‰>•Y²=®0¤½'Ý€=Á»;…NŒ¼ô'D<öEø½Jœ‡¾¦+ö¾Ï;=›´…=ñg½a ØGžX>ã =ÆQ>1�}¾nÂ>褠=¼l¾`ù<¾Ìw¾ᘼÓ7=–†¾b…½¾ë»½6 ¤½/ô.=�¾š½éßȼ`:>bR> ˜H>³H:¼Ò¶»=1͇>|õ=”‘Ö½`uQ¾Ö¾\šÒ=ºg™½h=l<=C¾èy> …Ô=I±½}¼9½¼L⺉š3¼7[R=b†Y¾ß6;TÞ>÷e[; %°>³·O=ˆì=őʾ ú>Tžw>Zç%>à2“»bÆ­= ·=“Ç=2‡¼¤2Þ¼SÕÉ<#1J=ãâ—>V+>Ò·³=ç¾ó<=">;E‡=s�¡=M7�<„Ó‹½õf>6ý²<ÛB>Ì”ƒ=½*>9>�8v¾ŠB}=¨I…¾·/¨½1ÆR>yJ¤½$ýñ >Ëa-½ñ†> ç‚>ö(<'¥«¼^s¾RSM½Ùu£ºÛܘ½m”˽,r!½×˜g¾ða½FT÷=RšÖ=‚BN=šÜ>Y|á½;¡ë½KfܽÅÔ¼üÛƒ½øk˜>% <’ƒ¼8¼£=8=5ZÞ‰YŠ>ÝÏ>‰äH¼Zaœ;„O¾Þ`½¤z<�J{¼xùC¾ˆ=ȼ'ê¾iãA¼N/¾¾�V>|?=( ½pž’=±½¿.š>[½9>En>PpW>¼¹ç<ßÚæ½0¨ƒ<_¬¿>yÕ7¾•RJ½|¸½ 14½nò½�½1>äû=®ü ½“ 0>’P[¾¿>óú=T ó='O_>óm>-�p½�ð ½C/ ¾¯«<¬!�½‚@ ¼&ñ^½#3:ŸÛ>`Á6¼6òç½Lî ¼b;‡=óB¾ښ>�…D>"‹&>yq=(‘½÷Ü<¿U>l�>>²Ä½0X;¡ ˜= x>œøÎ»¦xν ¾úQ­=Gµ�¾|[ô9­JH¼_=¾c J½šVS>öÔ>µÃú<ÉD˜=ƒt‡¾Ê­»½i¨ “¼ÔÐݽ«Ç0¾Íþ¾=/ƒ¾Iâ•=ÛË'¾%¨z¾¾pš½–]%¾4v >ðî.>}wŒ=ex¾“ãÓ=/­æ¼x‹=D]½ Õ¿>4q«¾ű=Ô#'>b]™;T@¾»µ½{‘ ¾áV¾Žcu>.¾»>°f=д²=Ðz¯=d{…¾À9å=Øú¾=_ ¡=Zïs¾ï¯¾ª�> N‘=¦–…>�Ú¾_**¾É$–¾@´½–˜Þ=æ x=!í�½ÙOp=fUÔ½°@«½…ù½Áî½,¾¡½Ž,­;~‚’½ñ�.=7¬>1~+>íÚ¾âÜÖ»V‹ä=±wƒ=Óê*>‚!=/è¼[ëá½B°<â¿3½„E¾mEÞ=¹ö'¾u�>=†=`¾\½1½D¾šú�>ƒº¼=œãÌ=~“>¦h-¾ˆé=‚¾—¾§4=ª½ò¾jÃr½žj“¾uVÿ½Ád> €=vJ=»œ%½Ý)¥¼-g>àñd¾ 4¼Jê¾Ìwæ=ùƼ÷¾ƺ¾½{(¾¿¾~=|c¼ÃÙJ>›î†>V%½7)Q=�Ô¾ ¶}>¸“¾ç2¾®w ¾%.>Т>¬åý¼wãª>óK.>fg=åŸ{¾Š=ì2»½¸=“¾dUœ¾w¶>n<½¬[=~ö&=íÇ÷¼¿ÜP½¤¾-^1½+ؼp…&¾;Ö½çô¾ƒ‚8<æ¾ñ½¨[ ¾ú›}¼2>E¼�½Ë¾L¢ë¼Žg½%�†=Þ';Ag¼Ÿ!¢>Åß�¾©g>-ò+¾¯ ˆ¾>ùK¼$”<¢ª=Cš= ¬~>b³¬=Eë�½Œ\•=3 >çá3>r&�<)‚-ʾ­<ºí8=ä.½yßà>�Ër½¨�ò½ÀÑ[=9¼þ»¢žŒ=U©‚=ÉÙÚ¾0°¾V²0½2ÚU=¥ /=e·ì¼¹À½Í";mH3>…Ú)>‰úÓ=n9 ½*t&=/¾,Xs= ß‘½ssý¼ê³±¾À ¾¶(>0'>ÇÄ =¹; ¥q¾Î®Í=l‚=X§Ï=ˆ3Y¾š…f½]-†½nf½ÌrƽáYc¾FÔº=܂ȽÜbé)ª=üL¾/´7¼Ý?h>áSˆ½Ìæ =³=Õ¶>¾;:„¾2Y>S�=O3½™¾Œh>VD¾T ’>$z>3_¾Ìö½SL6=‘£¥¾9ÍØ½ ¶¦½®��¼�¨¾ÚÀ½”�>ST¨>n(#¾¤£ï½�[­=Æs®½þÛ<çÊ >$wf»|^Ù¾^Ëg¾ÂSÕ½K‚¾vÖ$½‘ O¾¤ÿ*¾²%˜¾¼ûн¡D>ù%>±÷ݽïK‰½¨D.>|Äì=k¯+¾X“½3õ(;h >Åý¾“Ë�=^¼�=õÔ¹>„Km¾q1½1 W¼?b¾ñ>«=áÞ>SP¾ªip>„‘>œŸ˜½\l£½ª¾cß×½mIe¾ÜÄÙ½ÔÌU½FÜã=Фº–½k½‚ý½vÎi=ÒÑš¼¶&\>Æ•I>ÌR"<Ç&®=à;½Â?O¾œbs¾d ú¾£n½wÚ¸=”Ø ¾÷Ìb=Â'>­¯n>Ộ¾ì�=oJC¾‚Ì>æÃt>í8¡<圥½“nÒ= ÀI>Ÿæ½Xbï=žÆ=àê¾Rõè=¼ž>Æpp¾1í-> …Y¾ÇI ¾<Ÿ½�_Œ½ò}q=Ý;ß¼F½mí ¾–=>òõL½å×K=ˆ·q>9¾¾Ãe½Nz$¾HV¾¾Àf ¾Y<ð;Q¼ü½+¾œ±œ=v.>S�û=פA=f¸ì½"È.=©*$½a¢¾ �н¾ûÆ‚="ð=Q-{¾¹->\‘†½|¦sü¡ò½Ûôý=¶ë*>ñd¹½ùS>ß.¿¼N¾¾Ó>Œ¯¹;+=ˆ2h¾QRà=õ‰Ú½„ >¹¨ãcR¾â¦=¾#L´=—(J=/~>ª7æ½^€Æ=ò)¾¸d ¼:¬¼¼r=��±=î–´>÷>�=ôå”=Êò&¾"Œ¾Å-æ>{q¾š%¾_=ü“j>–z¾/þ�½ëJL¾ƒ(>yH>”±³>)²C¾mR¿½Ìô½p£¾P£>;ù|½ãxb¾:±¾‰­Í¾“½+5¾®2©»ÇInYü={ô,>Åz²–§»Æ{c>+>t ž¹  >¥Ã†¼n=  ¡½ý-<ïg>£¬p>fד½þ5¾ãlнå,’=¤Y¾ \Q½_|0¾üØ>¾½0½|7ç¼4\,> "O¼÷¡º=�(³½5§Q½ëô«>Å쯽të’¼JJŸ¾ÅÕ•=o¢8¾öH轪M«<:�Û<ÛËð=?>ãm>­z|½ÿZ4="ðX=ê³§=»åé=ÓÉg¾éS¾E°“<÷䫽ä¾qc,=Q9>…Ù3<”>_м?¦å=|}Õ>¯H ¾i>Y¢‘¾Ùä8>ò§ ½5Xá½ôê‹=?ì=M﮽ÆZ÷»’á§¾m;̽߰¦»ßoÇ=$^ ¾˜·¿=?óX¾tÜÆ<©|ž>r�>ÑÆ6¾Áó=©è–¾¢Ú ½Ûx?½VtÙ»€u>:Ê6¾”w$>#ú¾)iN»»¸1=Tö5½dÅE>"½¢=ÞÑ?½ó”ó;¬b‡=éàå=�ï=¾›.¾™ç€:%³N¾5¨Ô¾"Õç½øÜ<â–ó½ðƒ¸¼6!½’=x0f=¦æ¼…U<ŸS…>… ¾«9;>ƒÅÞ<ú¥5>ðŠÉ;¥³r=daľ!N>×@ñ¼I÷|Ô =`¸¾ØJ>ä~…½Ú –½>.k¾dsB=_P)>œìw¾J¶T=„7ö½ +¾mоKå(¾KÐÁ¾(ò¥=Ê'…>¾Io=•ÿ>¼ ¾•0 ¾i:Ò½ªçâ½áÉ!>FÚ/>Kí<>d±>a¤>sì ¾ŒŒ:¾c`°<�F»¡›T>y¸2>0‡Ö=�/`¼ÁæÍ>¥ÞF=!}9>é€k=œ+_»˜öí¼pÁÊ>Ê®|=|¤‡½¨çy¾󇾨yž;�æ >:>¨=>w—>I»>I�=k“D¾¦Jï½—Û{=Åòe=K\>«„¾Âg½ç¥¾fc�½I>¾6/>‰JÅ=`ž=d\>ó,=S}ç½È‹=е=43 ?Þ<3¾E’]æ.‹=Zu¾Íé½ÛQ˜½Õ©µ>ò#¾Èí½‰y;·0p=0–º=|”ü½œÄÎ>Rqã½�þ< ¨r½d©½!È–=ØÎÝ=K{½buÔ»§¿>Ü*�=£›„½Ñ®C½rsò=˜Ñ�½üµ1>â¼ ½Cõ½K{”>ìù¥¼à7=ýÜ…½¦û¾Ãð=8†°>ô]µ½çö½¡©�>¼—>2Þ«½Ͱ=0Ǽ¯=\_ß½¼·¦½YD¾Ão¿½sÌÌ=êñ{>ޝ¼ó|@¾í#G> ±@><™¼DÅ=® P¾æF¥>5Q.>ös4=rˤ= àú½œn¾;: ½}Cw;ȊŽ!4ó=4³˜=[r‚=)ÎI>ùÈ5½ôò¦=µ+>'D2>Yÿ[¾1ñb½Ç0ξJp„¾¶¬�¼z¿Í>Ѿ =i~¼ lõ=ôbŒ¾É�=§jó=4Ýý¼…ö·½"3f<),¾Ùº ¼Nw >Å¢Y¾„qm½qYÚ= 諾Ѹ=yï—=& {>¿¤¡>Þ >Jòô½Xˆ=ºHr=”ä½1ýä¼–£i½„íË=‡è]¾xͬ>Ônš¾±/¦=u<*> ¾Uʼb²S>‹^_¾›—½nYO¾–ÌD¾è‚¾€+½@}Õ½5ô|=Ô�‹=Ò×–»º-¾³å:¾å3>þÀ´=©_½.N`>q-9=–p&>è±=äÖ�>„@ ¾³d޼ɷ_¾Œ¾â¹½Y~!>�H½K*=£?ù¼ÑÛû~Ù�>á}¾É¬ >.¦Æ‡‰9><¸¾6¾è¡º½­ÛÃ=-¾I�)¾þ $>ѱ›½)pB>Ú¸¼-:¤½0Ùô<Îbõ=ˆ$ >‡8o=._z½´r ¾òUe>A¹¤=]=‰…¿=gÀŸ½7.ã>;TY½1A©<…«³¾¤!•>‚|c=f‡¾Úߊ¼èF¾èH»»_,¾Ð˜¼�ôÿ<¯–Ê>�…½šù•>If½u¾=¨%¾Ë ‰>Bàø<Šp“½Ùe¾9v>u–©>û�ñ½]>È];¯Ð=Ê`õ<”A¾Fˤ¾‘©à=Ôê>Q)G»T¾ú½‘0Ÿ¾šô8¼•ã´>Pï>�ÿ ½œ~>Ù¶{>³N³»;U¾~ƒ£½�î’¾ýÆŸ½4±¾^ñ¾8Ó™¾Âe>Îfý=1~Ç>š©>p×g>'“¼ÔÕ…¾zÙ±½˜ãñ½·P{x¾^z¨¾¿{O=#Up½�\#½×ƒr=¨ú¨=”Ì<—ŽL¾€qˆ=V1£¼÷ü¬½9—>Ò[;½-¾/½>t^>õæä+·�¾×QS>ðÏ/¾;÷°½.„½ÿ Y¾q²›;�#ï¼<¾pSº½�…X¾}©U=ÂÆ >•“º< ªÏ½Ý–=¤V¾øèÿ=[>&¢—¼Àù´½f¹¾yÕ¾¢ô#¾¨,±=ˆ[¾wÉæ½n€^>Û^¾Ò0v¾G,¾‘ÛнAÌì¼Á~ >t=>ÈY³½¥í¶¼3’¼xÓ¾",Î<¬q˜= ’ýºÐ ‰>cñí=¼?×<¨9ç=î™%¼ŠWM½ |m=�Û=pu=leG¾¶�€¾Òó>z¼É=Ò»É=SNC¼5=ɦ[>”°!¾ á?>‚E¦=¿J½±®¾SÝѾí(¾9u%>°ø>‰e޽O{­<\Ýß<ÙÔä½€ë™=˜i ¾[P1½‡Þ°½�|E>ìÜô»fÂò½Oa¿’êG½¢‹6½ãZؽȕ ½�X½½ìF®¾u(=—wK½Õ½Ë>¿°I>j—Ç>Ó°†<®ß9=ܦ>¾¹Þľ?õ&=ÿmQ¾Ì½0<'˜€>ðSõ½~¸=Åj=íÌ:¾Þ¯ˆ>„fo¾½½µ&r=Ãóù< £4¾T}­=í‹�¾r$>ËÚ;=Ö'>²ÞŸ=W5 >nj*>¡û"¾Y½¶=Ì-¡> …½–ìB>À5¡¾("O¸½A= ÊX=ÈX =™4M=4˜,½ÜÜ9¾:œ‘½³#¾åý•;Ä1³=³¿â½¢xÃ>"Œ >ºÇ=!*©=oë¾-ëí½‚^1=J¹= ·ñ;ø>hÏš½fÇ®=�¾q=+¯=Mäˆ>ÀÞ‘¾»Ñ>4î¾µ¾Û(>3 ¥>EmU¾ÓRнla>âðR½ât뽌Ca¾ä%*½þæá½M쑽b_¾½4é½3g+½¢¾«¼�æ=þv>£>ûµ==GÈ=ê}ü‚UJ<$ŠŸ<¤y;¾;>­¼½Žn¾¨­•ºú@‹¾¡x>‘¾=Àú|½ÑT°=õ¨µ»(1­=?Ù¾ñzÛ=¶¾Ý´Ð=€lE½.¢½³?1>½@k½˜]â>º©æ=0í�=Ñý½_¾$¾€®³¾JpW=fâ˽Ñ� ½š=¯„¼=¯…¯¼Š„å½p€¾XNW=�E>¼k±³=n”«½Ù%¾ë¥¯½¾J¡¾œß™<¶Ù ¾àmW¾)€>®žP=ª†=—´á¶Å3¾"DŒ>M¡Ÿ¼X+#¾ú^‹½.}Å<âŠ>”�µ=N½¾=-¬¾óg>ë]¦½Þ=ހýXIK>¦Ÿ¼Š�2=Éá`¾ ㊽ÿ@ô=Ÿ}“½“½m�.<›î¾€–=úûK½š<½ÄpË=~ÃG>6>r¿)¾_¾œ¾Jœñ½Ã�¾Ì°‚½h@6<õ¼…>tE¾7 *¾DÛG=[=ÆŸ¾øµ-=`¹½ŸÔ¾[ãv¼Ak¯¾4 ö½ ¾ŸÕÕ> V½Sk½ùIi»Óæ=òò<.iìºégr¾2Li>C1>¿‰‰¼ˆÈ ¾ªÃT¾pœ¾Š”ˆ¾*Ï$>¥Ÿ½mš�=–UǾ5 Í=0;•=j½I>¼«½p£C¾sO>`Æ>c�¾­³S>œˆ> g>¬¸¾'R¿½S‚½¹(½±v²½r†¾@ß>š÷<û\½t±Ø=åwˆ=P˜W=fÛ¥¾-º†»¶ÂL>¾ý*¾pþh»R”Ü<ÏÛ1¼È€0=øZ¾2 1½5 ?=õx¶¼¤‹¾yY‰=bx£=z*¤>I–µ½”2 > ƒ¾}É<îÇB= (¾z¹%¼=ªÌ½�/¾¾s½Mié½Õ�Ó¼ùž~=ñƒ½½ÁÈA>èQØ<‘Ò‰¾²|¾Î#A¼;¥.>n6<Îs¦¾ú<[. >@º>/ç¥;ïPÐ<ˆ„¾°k=ëÛ=á*¨¾ô·<0’¦=©!ƒ½…d³<  Ž¾¾yý½†Y¼½ö”¦<‹�‰»…ü¾¼}<>HÅ3¾çHD½aÆ=?I½W(à½ô|W>·<¯&µpÀç=M¾ûJ5>ÒÍÞ»CŒx=óÇ>\|н›åµ½ÿ¨ù=‡šº=Cn=zÂz>]ú<±.b¾Ek>;>«�¾Üüÿ½µšç½¨\ú½C`;×!€½òo>��½½R F>T=¤=¾P£½Ð< <” •=�ñ…½J ¾Ÿ#¾–i€¾{S7¾òžÜH¾B8å½Ó�3¾õ‡:=…cž=Vv*;2b(<Îãô<Û5o>é)†½�À¾H§ˆ¾0О>®)ñ=—E3=èG¾ž®à=Ùæ¡½Ïôw½®…=$1K>ÞÄú½›5½yܱ;ÉÎ>¸¦Á=Â"½cA½ï=Á¯7›}R¾áßâ=FZ‡¼ ­Ù>Rê�½(R¹½ž+c<Œ–I< ÷¾?v{½*í½^_½Sô =ìW¾—OY¾3S‰½{¥9½þ.ž¾âè.¾[s¯»ëú½9FF> Ƚ„—=B…j¾m½Å>i5¾h|¾<ÑB¾÷…�=]ày¾£šp=µɽ²+Š=çZ𽩤G½œ¯V>ŠÛ)¾á2Ï=Žä\¾¼ð =°\n¾Kù*¾HV†½á÷ ½•(­=]<œ–‹½ef(¾á 9=ci»„…=í›&<üî½H¨º=nVß½EŽÎ᪾ï.r=.m=,—h¾óƒ.¾jé=ÐwV>»ê<�4#>ˆ,d<<Œ >Ñ<ˆ½9·r=€R[½+É=F‡Â½9´º7� ¾?»Ü=гl¾£‡8¾äæ$;¶íè½÷Æ>äǾéß=Î.½=oÞ½�ª„¾p¸¾¥@>Xô ¿à½ï=�¾_ÿ¼Ö]=ÆkнN=zä¡=¦oŠ>q±ï½Æ1=3ØÐ>Iy½4«!`�€¾îF>ç` >`DŽ=Øž‹½,ÉÌ=�¢%>ÔÁø½‡EŽ»½ÙŠÁ¾jh“¾É k½aš%¾a…!>ÉX‹>¸â•<ŒX>°q¾í€>>‹q~½CYÐõ=b±B¼M˜õ=W¥ô=$•”<4.>¶æt>­ý?¾X`F¾Y$E= Y¾º±È<Ò²$½Êçå½ÞS¼õÁE=Óð_¾é Ÿ½©{a=>CG>²Û ¿àä(¾´E޽ƈÖ< =>Ýl5¾BÁ=Š"½Ôž•;ŒÕ¾Qbí=q•½kµ5=™ö½Gt=ל=@·C½e½6>GÑ ¾*#¾6�Z¾á)€¾ëU\>Ç1‘=‹=½07ö;Vc»¼ôæ¾tñ�>ÅD>ÏN½™.Z>ÞÆa=+W¾¼¶ÂI>К[½Dz𽈼’=ÿ×Ì=¸½^½ê@>¹g༥Ç<ôV{=ÿ9�=dF‰=“oÒ¾ Çn» ¥)¼*÷½ņ:Áཪ=_B:¾Ÿ� >—b¾»L¾ÔGJ¾‰y(½ µ_¾z&½¡\>Ð_Í)f$=[·½À½3Œ>à¹\¾–e½ÆA¾åªu¾Ù·Ž¾™Àí¼äd¼ट=ûG’>ªúš;ƒ#h=Ë™ˆ=—ø ¾M›-¾;Gn½ðâ?>I‡ ½“;œ=ˆ�ù7õ¾›Œê<‘½–=<¢Â<ò/ =6µx>ñ/<>Þÿþ½p‡ ¾3’Ž=ãÔ½E+Ÿ=«ž#>o­ƒ¾ïJ$>ZÂy>ë6%¾„Ù^½‰ð>«ªZ=ìt‡¾5j&¾œçL>Þf-¾‰P=“ZÄ=ˆ2½¨.=7)²½[Š<”90=�½‚$¾†;…½fJý½«z ½Yâ@>N®X½�Ñ-=òº¢½t^=ز¾YûŠ=-Ü×=[$¾11 ½�œÖ½¨l¼=víY½Ix½¡S >Qj5m®>Wk<™�½|åê½~–&½Ùñ>¢§¾Â騽¸½€¾¸Ï'>×¹Á=:L=õË=<íò=;ó(>WG’>ÿ½v¨q¾‘ç<ù›¾ßôˆ<�7B¾¦()=Â�=èYS=>8 ;3é½I¾ÛNª=»\¤½, ¾(“¾gÇ)½sÉ=üV™=…U¾µs„¾”ÀŠ>û½B¾jÇ5¾zµ‡>ãæÖ= ÅýÆW>ë= >]¢“>ÍêC¾M+=­¦â½t:A=Ïb…»­Iнû4y½®ç½*>øK¬<ÈD7>X~Ý=5@‹=I® =Å}«<§º€¼HÜâ=éÚ>�¼>ò/B¾ÈW¾Z•H½m¾ì„œ½Ðò˜½©Ñ<+Uó=òu‡¼•ñ‚=±|{> Úî½þ�š=¥G€>V¾î½»=á >4¢u>º«C¾¬ë½§‘=Ý„f¾dÄi>R.Ã=‘¾½†�½ÿ™>úò€¾ã½•à˜½Íå^¼Šë–=²$I½Ã  ½EE½{Ÿ)¾s²‡¾®X¡¾’A¿½/Ã=˜Aô=2µO½ß‰µ<:Û­¾BоÂx�¾üg½å«ˆ½ÄJr>T/ =š4Z>[ø=í¶Ë<=hi¾Qw5=¢jv¾jq‰>³d>®�h¼0ˆR½¦7Ǽ-¡2=6[¾³Oc>›ãÚ=ÀB{>½Æ´=«a„>ÎÏŽ>;7®½o¿¤=êš§¾ÑC>Ag =ê¤À¾è¹¦>v'¼»T“_>»6¦<0û6¼ØY¹½Œ�a½°rD½ˆù¿¼ ýG;h½Aå9>ÌF¤½£´I¾$"¾ë®–½ð·=·Iê<à —=yŸd¾¤0…=‰³Œ=k^½\öÙ¾§@n¾Ö�½ïžŽ+>å1¾~/X>5ò½ç¤>næ½öZô=Ü£>rˆ=z.j¾ 4 >lq�½/Ž=•Yf>ˆÜ ¼ó´ >ãóÀ=G Ã¾Æ&>Œ=M•1¾#eн˜.t>0 ¾çô=¤51¾Ý•†½l¨¬½"@™>-(y=ô·Ž>nq+¾‹×�¾Æ >¯~ð½§³»�wA¾ñæö=³¯0¾Š¤·½ãëÑ9ŠyŸ¼­¥¾˜Mž>a+’<©¸=w !>J¡ô<É:;½ªÛ¾©ŒÊ<(?K½R7w>��½ýí!¾lX=¼„C¼ó›¾="=|C€½æ$C¾×aŒ=ìf®½€ã½´ä>93>…Ü=µõq=RÅð¹ I>Oà~>Hr>_½yí ¾´¤<5=Ø"^>a�_=6>«ëн}_ͽxkd½l§Š=t8F;ÙÆn=þ ˜>ÿ¶�½¹¹=×ýR¾• ]½l½=îG`>‡ÙG¼Ëì�¾¯ݽ„§ƒ½5¶,>7Ã>êøÓ;-‹�>ÌFO=˜’½=ò(×=²¤„=*`¤½Ý®"¾5š=?bŽ;„`½çˆ‡=4%Q½ô©>7n�=áW/¾ •…½•cx½xb³>�ý >*_>¶¡°<¾”]S¾ÀG¾ø½í»/V"¾ŠRë=¼‘b>ãO#¾ÇÉ>T5q½ÁÓ½‡¦=³=x”>ºö�=š¾d¢¾ÈQ>5\ø¼ cã=*õ½ÉÇ>¾ïÞ½Þ8¿<@{ ½B¬l=1„p¾áËq>Cs°=Òý>4¾?D‚=R³>³Yz>e†Ï½Ój·½#Z#=-;-¾˜}�½ÕòZ½�0‡¾™©ì½µ­�»›]\½ ’¨½]©/¾.0À½õ“~>º›>’Ÿ¾³¡=r9�¼Â»¾"L5>H¨‰<¬í=/—�½Mø>�µ*¾‘¸õ½¶ýf>’•Ï=œY¾”ž>’—R¾—u·=”WÛ½ÿ¨_<«·P½6¬$½Œ = ¼d¼vêˆ>ê”Ó½vÀ(<6Ð<2=>�G½™†%>ê!¼Í ¨=¤d ½%ÍF¾ÍKÚ=Ž£>nÿ ¾ë¯3>ø}m¾D§½Ý+�<™# ¾v—r½Î>´È=r6=+Þï<í7M¾üfV=ÄJ©½f„9¾ñz>ºÀë= 'î=§¤>Þg=GH ¼µ’=‡¡(>Y‡¥=ÿ-c½%,=øm¥»˜¾‘x˜=¯Sé= oZ¾ y=ñr>sÛ�;h+Ü=Öa¾k/>>ªH¾Û„³>žR$>:¿è:'uš¾rº>#£�½ˆ@¾-D¾Ð&W¾²º*=Ò4>™p»=7AÚ½]ú¹¼%ˆ>g ‡>£–H>ýf•=©Ç=tòš=êÀ§=!áѽ!Ÿ ¾Ä0x¾•NØ:ûc�=ýŽ™½yb¶>S�t½EfW=t ¾–�>‘¾ ï@>âh¾S¿-¾—Ô–½“þ6¾œ×t>¿œ>>¶ñ®=‘ã½4z¾©ϾJào¾+ø½Œ¹ç=”}æ½.Ú<Àu¾öý¾ßái»’÷=Ã}¾(> ˜=Êa9>«¶|¾*”¹=êE¯¾ë”ö½u¾é=Á�]¾#°�>uÀá=Mm¾µÃ;rbB¾û’œ½Å…Î>Ÿ¼æºZ?½<ß!>; ³½Dx)¾J#<Ìv2>ºøË=´J>œ*½» \>˜¾$膾 ¾xñ=bÆ1>Õǧ½üw�¾ŸÛÓ½p~[¾åé*>Yˆ¾{l{>3á»/€7=‚ŽY>ÿÆN¾ö³½@Ä(¾º�»¾ºC[<`(]¾äÑ»·� ¼ý»Õ=_HÉ=tqœ¾YI½+Œ¼¸†E<>–=øìe¾Ä—¨½ûài=‰­Ø¾àÿ¾šÎÞ¼Xj�½Ú�¼rÙ1:°R*=tÞ�<,C|¼Çz=Rѽoa¾{04=‡Ø=š¢¼k8 ½Ñ2>ßV@¾ ¹¾$³�½Ä,Ž=îÏ3¾ÞÁ=�]¾o+ì=þñºz �>K±I>ÈÔ½3õä=ˆöÈ=ȇˆ½å{=\´×=åÈ€»ÐI¾Ðô…¾bd9>,1½U¯û<°ª> ¶'>ÂmK½Lµ½5òL=êÏ=(dx=L0d¾B#Z>—S¼î ½ñº¸>Ç =k¿"=vÔ|½÷5“¼¶š6>ØÔ&>àK½ ¼8¾ft¾¬E’=u\T½öF‰½“Ùb>U\¾hE>)gö½8iC¾à‡?¾X¸<½·B»\½©�¾É¥»Aðã½X >F:¾X1»á[’½a[:¾!'s½ÿ†¹=HÊÞ<,‰=œô.¾8Õ=´ëŒ½�¸=fÎõ<}Øü½ºV±½Éx(=Ñ<ð¾Ò›¾È?>í±>6C¶=ðÛ°¾|.¾ÿä+<*B†==á¼J,w>u¬<>ïW=”%ƒ¾Z“>�X=x…½a«¼T<>º‚Z»‰ ¾F9û½ .¸½¥ºb¾#¤ˆ¾�·r=VlR>±/>æ"]=†ó8>ªµ<œ²Ç½@�@>`‹<^à=û/>ƼV�X¾É„=’Q¨>a ¾Ö7®½»§Â=èæ½H=Ôü½º—õ½ùúÔ½s«¾—HI½Ô$û;öZß<%ða=¦/è=ªõ²¾¶ƒ½ÇK¾;Lã½3'@¼Ñ¼g¾!œ¾ “>šª‡¾Í,¾lc¾÷£E¾€™ˆ½ÆÅ<4¸&¼–͉¼éI>+„j=Mi<½ÿß“½¨0»¾?O¾ó¥½44>‚a½=�ók=Ü­C¾ìÒó=ÊȽ¿u½'R=ª¾Åòb¼ øõ<`Ü~=^*…½"`0½´œ¾þ8Õ¼ÿѽ0¢8=IŸÌ»€2(<Ý*=~@e<h!½µðŽ=âÿ"=|J >hQ€»K½O}ÞËY°=tÍ#¾+é¼2—=Aìæ½K,.;–6¾sܘ=Ì5/¾dÚ>•I¿>—Ø<Ÿ`e¾A*Ä=Zˆ¾œ¾ôD³¾C†y½ú–�¾ :$<

b‹˜×W½aÎ½ŠºØ<~c4¾Žª½SË·¾î( >¸Ô&¾g0O¾ uP¾P=}ÿ³=8”>r­Í<ºßG=òXŠ=ºûÒ½!̃=¾Õ/+¾E~±ý0¾=ÎT;>éz+¼–¤½jaß½ï¾ù=–�½Ÿ¦·½¿Á»“‘M¾˜F=Ùžë;K췽ʻ†=‘öu>Е=¯Ñ½šš¬=\�´½;§¾uh<ž3N<ô{Ÿ=ÑQN½Nƒ”¾y]�>éúÔ½U†;ïü <4ê˜<õCÁ½ôè½÷,|>4q?½è•‡½±™Ð==`Ó¾;0½¡ >AH¾c¼ÀL'N¾gG2>»“8¾_²=™¾9¾ç2¹½rc>áÙ¯½{4>g�½g‹=…’L>Üâ= �<ƶ=Öá�=â¹½Qv¾Áðø=“aÑ<©‹ ½ßŸ�¾úi>¹ˆ^>›eL>£°v¾‡-Z¼|AC<ó>m—¿À1¾Äf=,Í>“„–>›ú<%G>Nµ›<É–æ=‹¾nL>% ]½­d‘<#.Ø=“€)>Ò£Ú¼>¶•>£³—>dHÆ=¼ž_¼¦W±=jKW¼ÍGÁ=å>ï)оÙj®»trC>ƒ.º=ªŠ”>ÅÉ,¾ó$>µJ>¢�»s˜¼Š „½sö½»�ð<ĵK<º–='¤¤;-~ý¹=Þc=HøŸ>z'=8²½i�¾ù)É=v—w>¡(¾|èé½€Àâ½=ýÓ=ŸÎ�½ ¾›Q¬½ªŸ¤½)§‡¾gF)>ˆm]¾Â׉¼˜hj>–?½;I½µL]½»Z˜½eÔM¾¿âØ»Ýþ×=Ìôo¾– m¾[Ná=Cw=þ‘”<­åI½˜Z=¾0d¾š‹1¼œ€P=ËŸ¾,õ»ÑĘ>AJ}½†þ$>ðœƒ>‘ F:ÀÓ›¼;Er¾òê<õ8F¾Êâõ;œÉl¾‹±¾Çn¾ÅŸ½µ_|=ø"==�ß­< ?¼Ÿ…W½å÷ȶ™=:¥n¾s/Š=—ü=ÕB¾½Ë¶=ýˆr=;¾üî)>XI…=mTz>ŠýE½¹Ãj¾÷‡¡>ðF¾Ìeú}šì½a±>ª°Õ=ô?5¾ÿþÛ=Õn ¾.Ã$¾€`»½ò_œ>>óÕ½Dp<xb½YŒ)>HMÛ¾ã'=öDš»ÿP«¾2/I>—!‰[ŸE¾—°Õ=‰´G¼.�ɼ²8>ƒÄF=‚Z>Ñ[[¾äöt¾­¶¼TÂ>$á<{®¾^1ˆ¾…†[¾«å+>­gM¼ï ‚=E5=½ÕÓ½QÁt>óì0>–ON=Þi‰½[îD½O‘^¾¦~Œ>5´T¾|\Y½îf>5¯½¾>Ö¼éæÓ¼X½>p[ê¼þ°½ñïØ=2dŒ>ÀX«>5s<4}d½þç <í.�½w2¾¶ãƒ=ÌÚ½„à}¾Pº>…V'>•N�¾¼ÛöºUPD¾ ©U¾Ã†§¾pºD>äü1>¿¦�¾¸9= ªh½¢Ï„>³r‚=5¾�ˆ½.á½eÍ=½M&i½¦¿ì=Dvõ½‰H«>–’_¾´ƒé=Mƒ[<ጼjî�¼�&ß>ÜT¾�õ£¾÷yÈ=ê/ù½ç6N¾!¾l†¢»LÀ®¾·ÃÏ<æ�'>€¾>"¸L½›¤º¼ƒðQ>þŽ<ÿ�ʽ$C>*œÂ=qú½î�I¼ü\7¾8ÇÛ¼(æ±;Q$6�á¼O¨7¾_ùý=n¨u½â£½ ß^=âÈ…>Çh>­6J;ºÿ >pŸ*»Û!¾½4Ñî½½ �¾>¸·=jÖ=6˜=DÙƒ¹ú ͼ'p!¾D·B½}ྛ\>På×½PÚ¾Ü4>„˜ð<\þã=¾Wx¾ÁÏŠ¼4úJ¾¸ÿ>ò²{¾åHþ¼Ãtí½èJ7;õ‹E½èx3¼dNd¼Çÿ÷¼Tó8>¨"<>æÂê=Þ\Î=CÚ%½ÄwÔ=¼ï½ª/‚>RÀνÕÀ >`¿S=ÑÄ�¾Å ç=]Å,¾�}ý= ®>ÃÇð½Yy>úŒ5¾áí༆ÔV=fý >Xgˆ=OÝB>q>ª; %;¾«öi¾ b8>¹�\>b"ö=“�˜=�Xû;Ê0u¾³Žœ½À;´¾Í÷C¾(cO<¨™Ì½õù>ä1{¾BŸ¡>÷3 ¾Y ³>3פ½öð>¥7¾v…Ê=òlͼj_°=þ ¼G<]¥Ü<¨…E>L¼S; wD>ÿb¾ÙlU½m³!>¹�çܰ½+ì> 7¾¹#¾è´ >ãO¾Jþ½X¹ß½qái>1ò<Ë^1=ÂÙü=¾š¤½Æ):‹—¶¼žŒ�½8ùŒ;Ž D>öè >°ðŽ=¾às½ÆéÇ=Äì¤=Îr�¾Pª¬½èÑ%¾Àɨ=Ò#½!îþ½Z ¾ŒÆ—>OAF¾åÀ‚> ‰€¼xf½¾@’Ÿ=!.¾ßÿ=,Æ�<·™=»ñ>F×€=Õ‚ï=¸Ñ*¾;z->±Öl½ܬ¼]{Ï=¹ã(¾L3 ½ê3ô½ÎG>Ùµ¼(Ep=ÞΔ=¼h>}aË>©—§¼þ�l=/Ô¾f9 ½R–¶½äŽ@>Tì¼%£\¾¹ëž¼Y>Qà×½ù`˜>Cü>›Oà=(ì×¼—'>g8¼J¬Âösè½ÇÛ}=ƒ·¾´*>Aæ=\¡ó¼ X>°‹=ÑŸ3>Õ.©<ݦ=k1‰;eï >%¸"=B�¾I¸O=ÞFR¾äÕݾ•†m½$’^¾ˆ²µ=˪¿=®dj¾u÷½AÓ¹¼‘�¾Ì�ݽñ{¹=3°Q>�£ ¾œ™¾t¼½pG0½õŠ1=«'½dGe¾èá¾’^½� x<ãw†=S4н¼È…¾©_>N¤»»±:s<Ê•}¾âï ½H-'5½÷›>ÐΖ¾"À©»mr|»aTS¾õ0>´‘½¤Èé=8ÈØ¼+ãI=O˾½uG'>ˆ%>|1½ ‘<2-¾|ù$¾y½n f¾ŠAн#sà½k¾þ¹¾D >Snœ;rËâ>g†Ä½Rܾ™�@½Bÿ>0E˜½�Ý2½4>¾0(w>Ì«¦½´ã/½6ùl>Z¡�»En™=ÌW= ql=âéð¼ÙÎð=’ë­=§á~¾äÇ@¼7¢ ¾²zn>úTå=Ÿõ‰¾W´ ½Dh|=äŸÏ½èu¾i@ =3ô¬½´Ÿ ¼ü›»*c=ª“W»‡ý%¾¿Éy½¥xú½|`)=:<ÍÁ=>ÞÕ<ÏN>¥Ó¿:3¤Ô¼Ï›5=,/½ñ—Î;î.<xÔ=/½= ­¼8ƒ,¾¶©ã=b¾‹ï)>'ôÌ=éd½Lr->ô,À¼•¿­½ÌÀÄ=£|„½¦¸1¾^|Ž>qŸØ=ãç½+(G>ŒLP;C{€½AXȼ2[:¾FÈ—=ž,>ìëX>bàà=fÄ(¾•f >f¶p¾�-># Ü=Ÿ¦ì¼À ü½ ± <ÜN�><€¾Úo„¾|˜�>­BMM¼<¶}>pv>üñø½r>öaˆ=’n¾C)½·öB¾©~<‚§ÿ=B²C¼•S>›ê›>À©á=«iv½[M:=Ùa–½85=_ì½ü¦]­>^0¿=¤ªK<—¡ž½:__>;û9¾ø¶½›Û¬¾-… >Ô¶+½ÓK˜>÷õñ½1í½UU¾½»Ò›¾ˆãà½r!”>(쟾üá)>`>u¾7‡óA:>Iµ.¼×¸¾\oè<ò“~½Úà=¨F¾Þ š=»5\¾�f`>säN=ä ¯¾ò<¼;{¼Ò½ÆG¾õj=Í•¡½z$ê=.«=¥¾=χà=oK`¾Š»h½^Q>R¢;¾Åñ=$7мOÉ<>ϲ=JP{>Él¾XÒ羫d°>ÿ‹>«-¾Ð�§=¦§Ò½R¯»½sE”½i¾O¾+ª€¾àH>OfA¾UÌ\¾ñçE½l¯”¾Ñö=ÀEi¾f„·<ï(¡=§½]¯À=î×<ðb >Úy> 9÷¼Õо�ž=hñ0>¬$Ÿ>UP>‡|ä>!M½�Z,>‘vÞ<§âµ=ÎüŒ¼œ¥ñ½Ç>o콘2‹¾A>4艸òV�½ïâæ½æ¹·½¸™=é°\½á¾Ùi>Vò]½`še¾Ü±Å»Ê*<½¥8Â<“Œ>²�¾ÍÞØ<μg>e=»;Ý©Œ=q°=S(á9·C½³…ù»j¡2¾�/ƽ¹ø¼÷¨=ö3>4/¾À�Œ>m�¾Žˆ>¾¥Tç½ý3=hNS¾M7+<>nß¾8œ½.%š=Á­�½”Gò>ºÖ•¾ÄUe=N©e¾#V½±X6>ÃßB½Èµð½( ¾=0ŠuU¸½á‚N¾Ç¾³<Œe©>®œd=-Þƒ¾°1€<0¾œa[>iÄ‘¾¨Œæ\­=i¶¢½1‚i=YÕ½~ H½Â…4¼Ÿ·a>¡éD½1 Ì=$ÅG¾Òž=|*¯¾‰~¾• ¥=ºÇŸ>ºÜ™;µjõ=E0à�ð;¾ìk½ S¿FP½½¥"ø=“…{½¡Ï@> ¹A=Cô>GÞ1¾‘‘V>¬Æ\¾÷ñ}¾útǽ”=½h½½1Ô=Ù# ¿¾€œ¼†Áî¼ ·[>n ;=¡‘¾»s"¾%XÃ=“†‚½uˆ¶¼ P¾™Ý‰¾µÚ¾üEW>T÷¾Y‰¾½5¨;¾ð.ö¾»Ò!¾ž¨v=Þ¿/<ì·›¼Ãªª>©…>º’g>ÒÁ%¾f]…¾aÆU¾¨'=Þo¹¼2á\>¸šB>mϽæhÊ=³¤=|ÁQ<6¶r¾ë~¾²LW=k¡Ò¼˜æv>Ø�=ÐŽÇ»âjö¾ü>¢–t¾šïÛüOô½â4>�d=AN–=Š› ¾5ê)¾»f>KE_>NL̽Uâ<¾Ñ�޼‘¾0p'·[Ì}<^tG¾h>â…5=ØZ¾ µ>�¾å–¥¾á[€=4F¤>‘�¾¸Ó»ã>Ö L>|ÙQ= •9¾N”�<á»�¾™+>a>»¨®¾Ÿi%¾W³³=/96>)�¼ ¯Ç>zÆ= 2k½Ý^¾Sîÿ=øU‹½U¾FÊe;§áJ¾n�¼­xˆ½v{½s‘¾ ÆG>’†Ö=jÃý®7x¾üï‘>;CÅ=å†,>ÓÓ<¾ª’³½€ŽŸ=¹éþ¼;Ôw>ä(”½¡cl¾Ä5 >9o—>M;>ײ©»UA]>Ò½‘ÄE½õo¾U¨¾—¥§½?Wæ=¡ë#½›¢>îê½é°’>éi£½:Þæ½'™½ã{7¼Ùg½^æÎ½¶ÿ%¾–KØ;Ñ ¾ Jƒ¼n“»½î ݽ�·=AK=ÿL=�W½Õü¿=Ì~—½ùï}¾ÏÝ¥>–7œ¾?ñÀ=ླ¦f>e$6¾1¼½!"‚>½gž.´„¾�10¾Ê¶9=©ì =}t‚=˜Î3>ö‚�¾Õˬ=�~³¾ý,>a±2¾ÿ†½0îÉ=’ç@¾ˆz&>Íý�=P‹d¾�iô=/xÕ=&¯=”O=9K¬½œ}§¾àà½[e½‚ˆ$>è3ã<àß¾q >Ã=Ãå~‰¾8H¾áë=Z¦ï=š¿aƒ¾£q‹=Lࢽ^ù`=HUußZ;¾Æ·…<•Eç=€Ç½Ô’µ=¨Ô¢½ �=3’Œ=a'P>m®¾î˜ˆ¾,ð2¼$ß/½¸Ö¯=| „=Uéó½$á¾[ë�>n&½=ɾ>—ð»÷4½Y >éƒ*½ºO¾½Y>„òÒ=בr¾’�=××o>)hq=þ,­½eç½ÛÄ>(º½ öW=Šv�¾ú_±¾iP>× ?{#X¾¾�e¾j½´H¬=ÿ(æ½Þ.2¾QBø½äùê=4oнqª÷=‹K=WW­½cŒu>×@8=&Ô¼ÑK�¼“Š0>Ûߘ½ H>ÙI>ÝÎ&¾˜€ô½Ýµ½ˆÚ=løÁ½§Œt>SÙ¶¾õq½'ä=F]ç= ¾Æ·½ä$>Þ:É»ð¢t¾z8R>UZ~½Múž½Ï�é¾qøÊ¼Ä¶ù½Lœð½šSˆ<ç6¾ŠP.¾/,Í>g¶[<Îtн5'>�Üc½ÝzX>œ'´=¾¸ >Ó!†»àjܼ´í½ú2Y¾J0½x Æ¼3¦¾yLP½¥0,=¥�½Dtq¾À¶ê½w3‰>Âß‘;ؾF¾¥;>c$¾«&¯=Fð¾„D>°™M¾Î¶=n%[>#Ø�½_H¾½§ v>æ~-¾ew=•qU¼�,¾'£ =¾õ>bºl¾6§¾f&‡>Í�Ù¼ÄDH>òL‘¾�äÖ=.9¾ÛoA>˜ðö=;¿´½î²+>QÔ¾¾�¶à=ƒÆ<uÁ<[N†=…§ô½A€ƒ¾·…z½Ï¼->ú²7¾ÿ%r>¶-¨½9i³<À$½ì“š>T"#>ÁÖé½—Zν?av>\Æ=~Ö¾?D¼¤q®½Uw»dxŽ=Áp>ðü¡=�Ñ.>‡@¾™ a¼“¾Ÿ>îú=ž—™¾ù¯ý½‡¤<, ¾Ý¾'~b=€‹,>+<ò½½ƒ>žÆ�¾ƒµ•¾eºœ½Š’h¾c�ؽ²j‚¾Òzæ½Ï~K¾ý*!¾´Yþ=&ƒ–½;„M¼•9M=²-V=2Ž>òÜI>ÐaŒ½GÓ°=P[8>\Ç=F†®= +Ô½_¸J=æÌ >/ »¥0>⤿;4«Í¾9Ë&¾°•¾<–w¾ôM=?=ZA«½ÒÚʽª_Ë»�ì;½Ê,§>Æ�½ýž²½¹éè=Ë‘ ¾6M >¨Óƒ=‡!±=[Ì.¾Ô7>Y'“;—Ô=s8p¾úƒ“½ÈšÍ¾_ ¶½Ö¾Ñ™4½õçÀ½ (�½Ò̵½KV�»wþm¾ÒÄ2<§½ô]…>Ð7½4ÿ:¾ø`½ˆª<ep¾½ôÀ½Ðtï=lp;µ×q>@Ð%¼êغ½l8=¯�¾c2¯=ˆ‚"¾kcæ½¾Œ>¡˜)¾ï�ˆ½;¾Y7¾­<ïÅ‘==‰¾é¬˜¾RjA>�êŒ=-6Ö¼òéì¼Ûô…¾CÜ=½>”¢“æ¾Î¤Ý¼Ì{d=‡Í=yTš>Òõ­½>ë= ml¾O�Ծȇm=Þ6�¾¾]<ý)k½´ 6¾6.ø=Šþƒ=r‡>¾Ñô½ñD¼±š>½§Å½ÒVe<ò‰=Ä_˽à ¾Dý£>ÿN¾¼C ¾ÅÔa>ÉD¼=Ìå%¾à÷Ƚ¶‹i½·íé=ý;¾�×3¾Øš#»#m >Å>‹˜Q½È©>á+‰>eÉÖ=ŸF®½bA³=0}Õ=wOu½�,>\qK=£õô¼¢³~>¨J½áИ½Ûíå¼%ÏO>Õ§=]41>¶SÒ½ [>÷X¾@“½aÝû¾‚²>¯)2=qν¹…>r‹=ILk¾Ì*0¾’é>Îܾ\ö=Àè­¾$c*¼î¼:½,¾b½ô¨ ¼Ú©=„“²>Mm1½o9e¾G“$>,p½=ýp"¾f ¾^R>k ÿ=UƒŽ>QÛ˽'µ ½¿‹Z½ô>2 Î=¸Ö=cÔn=¾®¾^ºñ=�>Èâ"½®O龩<«;ofܾ«ñ¾]Áæ<6³>ØÝr½,¾Ä‹Ã>� [¾`B <@²ä½ûí½’ú€¼�Úl=\†=¾>–tÈ=ŸÑ²½‡Yi< �=‹Í½ÙÆ>ÒÛ‘½o—›½'‚x>®�J>´È…=Å}&>çk>g!³=ç4“>a�¾;u;½Xä½ç×;í)K½‡A¹½(eÂ=£b²¼'O9½¤Ø@;Q`7¾+'”=Z >^m&>ã0ð¾^Û�>ã:ƒ¾vb‰¾~r¼º‘¾<¬{†>ÏŽ >VŽ ¾�"»¾’3¾H„L=uŒ–½î°Ê<#¡n>@„ˆ=Î#ã¼Íñ=ÕŒT¾˜¸½@5È=ê]¾ƒ¸¯¾ú=ª>�Ö²½ ‡(¾'ð=:V¾íá2=JÄZ¾�ªƒ>'$¾J¾špi¾´¸=LC§½¨l>¶ô¶<º$¾C½½TU¥¼;©Ù½w�¡>I.ͽoûƽ5ë˽}>¹Ý¼½Àû4>.€‚>ñ �¾Y<Í>î¨o¾à¦J¾r2¾:¬j¾@ëQ¾@½\Tñ=ÄË<_4M¾8O¶½ÒbŸ>� >1%y>å|‘==0ç=�ñ~¼?õ½÷Xú=¾Ý0»ÀuʼªŸ4¾)Y¦>ëÊO:î0>–Xx=„šÛ½  Œ½Ujݽ:>Ø´N¾þ»:¾j´‹=XÞÈ>ëÃ~=l^E¾)ŽY>2¾†ó½±]]=·¥½ÄŠ•½Ùh>'Öè½(·]¾0ûç=Áüõ=<Ý,>Á^z¾nÙs> p¾Ë�?¼1ؽã >LÙ¼¥à<>t¾oH¾–ÌM==º2>¢º=Û=Ö[ÿ=‡¢É½ ¼½–€é=çk­>·í¾™]¾>ˆÂ= /=Ä!©¾ko•> »2½Ô„J¾^ƒ¸>>"ûG½6™R=8îa½]yª½ã$¤=‰! ¾Ec½À«=Fö`>‰Þ¼ >OÀ>·t6>yn¾T»Æ>ä%¾�E˜=,ª>§±=©~=J¾ƒ ¯½G*‘>' �½aeŸ=$=¥¿‡>ûŸ€½…)¾ðŽ>g†¾+x>»'“¾ž@x=puh½¼ E¾‚PP>˜Ç >kb€nÔ¸<Ýš3>÷õ½Vʾ Ê=ôD2¾PžS¾¼¥¢>˜?!>áM»^ å½x~>èà½èT‹½šñb½ãZ2½éD]¼Î]“½9¿¥½õ㢽ªHоN;Ò¾ ¾x€š½Û²D¾º%8>)†>ÄR><þm%¾\‡½Šó¾�»K>HÕ‡>>¼>„)¾&A¾é•ê½²š`¾mCŸ¾]ݽG$¦¼"‚!¼�{£½T©­¼Ä#¾:0%¾!½,>ÃÎ�¾­­¾áÖ뽓�¼1¡1>Ãþ¦½\~H>�ì½õÕ#¾ï>>Ž4c¾ÕŸ> Þ¾Mº==H¾뮾ÉûÏ>lÎ=ùP¸>Æ"U>Ú½£¼X _¾N½v:‰¾€`¾£þ—=�¬µ½9 ¾ÿ£¾E ¾07Í=ؾ û>@²>£¾ê³±>>7!Ó=¥q$>:F`=´Þ¾<Î,¾qæÄ¼Q’>Å,>"8ò=�¿ü >^‘b>­à‹>õJ”=[j=ÉÈ�>U‚>°ˆ½ µ²½ ä>º@J>~/C:åØÑ¾Yê>–#â<›µ#>CÂÖ¼�3w¾žÚW½óCÒ>:J½³üã=-@•>\¾  ©=‹ä™>ãµt¾F=½|è¼ê3>-.¬=ïI>"Ñ¿=þ—>v>ð‰˜½ÿ¾+>¡?(>ó>eKÌ=íF< {�¾ñg>ZTš¾Kç ¾ÖµG¾†pU¼&ç�¾0Ô½>_éè¾2= ½ï‘>jáÄ=ˆç4=ƒ”¾SÚñ=ÔO¾N.¾Î!”½ÛÓ½B¤=‡1‘¾K 0>�Ìp½°ŒB>¾²¥×½Ì ú¾.—>Á[Ò=Â�¾ÝÝ4>Æ =ؘ'¾ùY㽉;•¼ý»>2Š>ïïÃ6>!Ë˽žû#=s€¾{Ü«½UÅé<*¶s>Ü᡾·(H>éi¨¾híýWþ�¾¼óž¾�%Â=câ>(d5>GãV=(‘ǽèm˺ Ó¹¾Cgb=ܳH¾7.·=”}V=P ¾�Tˆ=jc}>ù9º=@xù=]Ø ½YœÌ¾E)¾ž…„½A>h�T½£�;ž‘K¾A—V>¨ñѽ(g(¾e�¾òí:Óo¾ç´õ½fà)= 9>x»ƒ¾>î8¾«øü½àÁ=%çx½[z0=¾8z¾™w½./�¾Û1ƒ>„§»½IÌd=¡Q÷»*2>Õ 3>+B¾‡X—½ ‡•¾nF¾LAƒ¾S<>|~Æ>XéP¾mid=�¡=ÉÊç½ ¦!>÷4[÷9¾«•ÿ¾½ß¾“G+>­¼>ö‡¾H†î=Énš>þb¼ƒg%¾¬¥>Àgѽ"Æ =9;7¾Xhç;�àê½ÇE¾í<¢¾3®½Í¶i¾áŠ>퀸¾®t¥>S0C¾¸¾´»¿½-â¾ÛäÕ>ð•N¼šÂͽUH¬½(6½Yò4¾µÜ0=�íÖ>d”¾s>`,<»n;ºôg >ÑqŒ¾À¢»=¯O ¾¥„=ºç/>dÑ ¾—D3>a81>WÓi=%j>>2h>ý#B¾³ +¼ÁD¾¹c>´�{¾hª‡>!M¶½i�“½ØD™=Hö&>„ìc¾]ó¾N>�>Ž[É>n°¾ˆN¾¢¨>ï“J>�#(>žÞÀ¼sý�¼ª5“=ñÓB>¾¢>‘$>]#B¾O¦¼A°Š>3óä½Wèu¾\®ü=1"¾¾Ùã<Ì{_¾å¾ Þ[¾† ½Ã)Ð=2'¢>8qp¾?À>Ekª½Ï£ù½Ýü¿½*m}¾ ƽ£2½Ðx<¾ù i=7ÔA½�Ç=&%£½¤¹Ê½ô§>Çì=í[•<¾_�<üj%>ݪT½ö >W¾-¾²ž�=s ¾¦‹Š½r¨3=úãR½»Üå=5ñ<(i½Ø>Ó&;QÑ¿Žâ->¤ë0»a>�+>A›£¾¥’i>*2ý¾l‡J¾šI&¾‰³X´ï<þE‡<9í§<è@Ë=g#R>Ô0ß=³‚ ½ªÉ >†äy<{]‘¼’µ2>…‹ë½�~›¾±s}¾íº2¾ £>Ü#¾!ÀŒ¼CØA·pQ±=x3À¾ë>ñĹ=lÌ>4>¢©s½äPn½å›K>òæT> �¾„^R=Ûó=u'˾öP>Æq÷=É V>šÀp>é3e>&¥½ÂU™¾ X¤>ŸC§¾*y“>MvT=~w>å©'¾/ù\>dˆ�¼E«B¾0«þ½ùî-¾¼´ž>xŸ½(�'¾,ú˜½ì”×¾©¬ü½Š|½:²a>�ôÔ=ä½U¾�©Ò=úŸƒ¾rwB½µô =»p›¾Ù®x¾ÀQ>1‚>qa½§6‹¾ M©¼Îß¹=ʤ?=¾nq=áÆ„½cª?Éô¾ÃBa»†n°½Úû.¾p6<>üé;¾àˆ;Á`–·N<�Qã¾ô1½4HÙ=\°½JÐͽ›¯d¾Uˆû=ž›´=Üâ�<�T‘=@¹½ÌTc½×#¡¾|ºð½8gm¾ýн/U�½J”¡¾Þ*�½@“ì>Œ"©½hÕØ½·ë=�b»=Ð�ž= Ù)<»a;=¯¶*¾ ‡”¾Øâ¾ñá<¾;Hp>ÿ%>ɾ«æä=ÛŸ=/2¾ˆ+¾9Öh½›¶Ç<¢´½Ïr¶½îù,>‡Þî<¥ï>yÐ�¾v­¬>?‹ ¾fîû½uÕç>ì>Øÿy>²´t=?��>×¥¼‡ƒ‡=Ö†½S¡)¼<3>¼Ž >ÀY¨½Ü ¿ûu>‰ë|;öÖ>ù0é=+œS>y¦½#Ka>8r½3¡J¾�F5>*Jv¾e\•=Õ‡½Rx¾÷ÄR>¨š[½±�=�!˜½�L0>ƒÛH¾ú7V>à¹A<Ôø)=ÑE4>ˆÂ,>Š[.¼ßºì¾Œ<Ò="Ó$=4&e<ÉÉ̾ǯÜ<ùY¾+rK»äе¾Ÿë:YÛ ¾'†q¾ˆØ¾ÕÉê½Öβ>[?�ôÈ믩<銒¾Ÿ¼½´Õ3µ¤>kä½B ½Œ>ÒÎz>øˆ ¼Õµw¾ñ/>‚Fp¹W=ÕT¼¾˜zZ= Û<>�«Œ¾…÷0½Sþ9>ª�r>i2”>7ûÁ=þ.À;­^©¾ïÚ“¾šî >?™O¾p ­½zx:>!³Ã=Êa4¾3Ý6=ÌHª¼‚v­»dÙN=f´‚¾TA¾è£€=F„=Ú ˜»Õgþ»öb¿¾á‰Ó½¼>Ó�º=éð>©²~>µ®ó=XØÄ=?ˆœ=øÀ>Þ„ ½Ríÿ<ÂâV=¡"£¾N¼“>±=½P>ýټݮ@>ºŸK=—£­½:ûý=“±”¼4`n>•ž½}²e>¡›•<ª‹N=‡%½Ëiž=^¸>–M ¾}tm¾W£?`L<>‘³m>KD½À6@¾·!®½.¶�¾{ t¾dÏŸ=`y>C¡”>Çî_=U�>v…åºì‡Þ½þ¨á=õú‘>̶ä<²´¾Õ±ão”¾Æ">Ù9w½ê=Ä<‰�R¾*†Ú=­Û¬¾únL=w3º¾3–¡½ˆô”¾‹¾rr†>ð(Î>ùî =`Ê׼Ė>¤#¬¾²Ëš½¶«¾ã±½© =ÀN®=fÀ=½úï½NX²>F@_=^.¾eü½eSä>xT”>WÀ><8~мSIA>‰YC>@¢B¾GÎN>ê4¥½À{>b½E 5>±Ñª¾W,ž!ÿ¹<\Ó>ç§ã½;>ó¾öii>¬‡¾#Ez¾;>ºÚX>3®_>MA>$®½,a½ Y=¢‘ò>6^,½ý稽ðYиÖt‡½œ÷¾LC˜>ŠP¾²{…¼w‹¾Àò¼;Í>¸é¾%Ù¾?l ½˜i¾ ªµ=¤ºÆ=Bg½pŒ½˜í�¼|d½¾À‡Â>³·»Ø©è=7<¼î L>¼õc>n}�¾¢ÔÂ>¶šU¾Bëµ½ ÍJ>é¡<÷ª =Aw›;]xÆ=Wß=ñ“™>‰~"¾„e¢= A¨¾&4>P=>“ºv½¡h<¾ñX@¾746½¢ã̽o'�½¹H™½tU¾!àÔ¼¢”+¾–Ì>ܱ®=„•Å<áƒk>L‘=¾¿°¾Ø¿*½'ÒÆ½�yg>彎P�½&¾!oñÊ#<¾™h<5À¤=�Yý¼ˆ™’=(U=Û�ü=‹¹…½Fûp½þ¼V=#/ ¿Ž·ª>™i½ÓáQ<¼€¾j¦½&×½‡Ç ¾ ¾Æ>â|Â<”ü?§ ¾Ÿ¡ì½Š¾8ºý=ê"¾3Œ½û1>à}$¾´Gè½èéS>,‹�>yœ6> ~J=i‘>Õ=䫱½6¤„¾M36>lo>¾²¢ä=ûßå="ð=s¼bTõ=N|à>Ç«¶<òÅ÷=ö…»¾8ÂI>}·¬<ÛOð= L¾Ính>«É½+´v¾Bój=YÂ@ºþ*¾ZP=d;=Øe·½ƒâ¼+e¹<í(¾�˜>ºQˆÎ=½Èf¾öX½µV‘—»¾�ð>§y_½kw‡> ý«¾ `B¾ûAñºµø=ð²›=~N¾eþ½Ñ@>‘Wä¾ÛÚ·=Šk>æì'>�ƒ¾)=�¾àkR>ᕊ¾:|ø=scikit-bio-scikit-bio-a3beaa6/skbio/embedding/tests/test_embedding.py000066400000000000000000000230651520735541300260770ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt import pandas as pd from scipy.spatial.distance import euclidean from skbio.sequence import DNA, Protein from skbio import DistanceMatrix, OrdinationResults from skbio.embedding._protein import ProteinVector from skbio.embedding._embedding import ( Embedding, SequenceEmbedding, SequenceVector, embed_vec_to_numpy, embed_vec_to_dataframe, embed_vec_to_distances, embed_vec_to_ordination ) class EmbeddingTests(TestCase): def setUp(self): self.emb = np.random.randn(62, 10) self.seq = "IGKEEIQQRLAQFVDHWKELKQLAAARGQRLEESLEYQQFVANVEEEEAWINEKMTLVASED" def test_id(self): emb, s = self.emb, self.seq p_emb = Embedding(emb, list(s)) npt.assert_array_equal(p_emb.ids, np.array(list(s))) def test_embedding(self): emb, s = self.emb, self.seq p_emb = Embedding(emb, s) self.assertTupleEqual(p_emb.embedding.shape, (62, 10)) def test_str(self): with self.assertRaises(NotImplementedError): Embedding(self.emb, self.seq).__str__() def test_assert_length(self): msg = "The embedding (62) must have the same length as the ids (63)." with self.assertRaises(ValueError) as cm: Embedding(self.emb, self.seq + "A") self.assertEqual(str(cm.exception), msg) class SequenceEmbeddingTests(TestCase): def setUp(self): self.emb = np.random.randn(62, 10) self.seq = "IGKEEIQQRLAQFVDHWKELKQLAAARGQRLEESLEYQQFVANVEEEEAWINEKMTLVASED" def test_repr(self): emb, s = self.emb, self.seq p_emb = SequenceEmbedding(emb, s) rstr = repr(p_emb) self.assertIn("SequenceEmbedding", rstr) self.assertIn("62", rstr) self.assertIn("10", rstr) self.assertIn("IGKEEIQQRL", rstr) def test_str(self): emb, s = self.emb, self.seq p_emb = SequenceEmbedding(emb, s) self.assertEqual(p_emb.__str__(), s) self.assertEqual(p_emb.sequence, s) self.assertEqual(str(p_emb.ids.tobytes().decode("ascii")), s) def test_bytes(self): emb, s = self.emb, self.seq p_emb = SequenceEmbedding(emb, s) res = p_emb.bytes() res_str = str(res.tobytes().decode("ascii")) self.assertEqual(res_str, s) def test_init(self): emb, s = self.emb, self.seq # sequence as string p_emb = SequenceEmbedding(emb, s) self.assertTupleEqual(p_emb.embedding.shape, (62, 10)) # sequence as bytes p_emb = SequenceEmbedding(emb, s.encode("ascii")) self.assertTupleEqual(p_emb.embedding.shape, (62, 10)) # sequence as skbio.Sequence p_emb = SequenceEmbedding(emb, Protein(s)) self.assertTupleEqual(p_emb.embedding.shape, (62, 10)) def test_assert_length(self): msg = "The embedding (62) must have the same length as the ids (63)." with self.assertRaises(ValueError) as cm: SequenceEmbedding(self.emb, self.seq + "A") self.assertEqual(str(cm.exception), msg) class SequenceVectorTests(TestCase): def setUp(self): # Create some sample SequenceVector objects for testing self.vector1 = np.array([1, 2, 3]) self.vector2 = np.array([4, 5, 6]) self.vector3 = np.array([7, 8, 9]) self.bad_vector = np.array([7, 8]) self.seq_vectors = [ SequenceVector(self.vector1, "ACGT"), SequenceVector(self.vector2, "GCTA"), SequenceVector(self.vector3, "TTAG") ] def test_init(self): vec = np.array([1, 2, 3]) seq = "ACGT" # sequence as string obs = SequenceVector(vec, seq) npt.assert_array_equal(obs.vector, vec) npt.assert_array_equal(obs.embedding, vec.reshape(1, -1)) npt.assert_array_equal(obs.ids, np.array([b"ACGT"])) # sequence as bytes obs = SequenceVector(vec, seq.encode("ascii")) npt.assert_array_equal(obs.vector, vec) # sequence as skbio.Sequence obs = SequenceVector(vec, DNA(seq)) npt.assert_array_equal(obs.vector, vec) # input is a matrix, not a vector vec2d = np.vstack([vec, vec]) msg = "Only one vector per sequence is allowed." with self.assertRaisesRegex(ValueError, msg): SequenceVector(vec2d, seq) def test_vector(self): # Test if the vector attribute is set correctly for i, vector in enumerate([self.vector1, self.vector2, self.vector3]): npt.assert_array_equal(self.seq_vectors[i].vector, vector) def test_sequence(self): # Test if the sequence attribute is set correctly for i, sequence in enumerate(["ACGT", "GCTA", "TTAG"]): self.assertEqual(self.seq_vectors[i].sequence, sequence) def test_repr(self): # Test if the __repr__ method returns the correct string for seq_vector in self.seq_vectors: self.assertTrue(seq_vector.__repr__().startswith("SequenceVector")) self.assertIn("vector", seq_vector.__repr__()) # check latent dimension self.assertIn("4", seq_vector.__repr__()) def test_str(self): # Test if the __str__ method returns the correct string for seq_vector in self.seq_vectors: self.assertEqual(str(seq_vector), seq_vector.sequence) class EmbedVecUtilityTests(TestCase): def setUp(self): self.vector1 = np.array([1, 2, 3]) self.vector2 = np.array([4, 5, 6]) self.vector3 = np.array([7, 8, 9]) self.bad_vector = np.array([7, 8]) self.seq_vectors = [ SequenceVector(self.vector1, "ACGT"), SequenceVector(self.vector2, "GCTA"), SequenceVector(self.vector3, "TTAG") ] def test_embed_vec_to_numpy(self): # Test if to_numpy returns the correct numpy array exp = np.array([self.vector1, self.vector2, self.vector3]) obs = embed_vec_to_numpy(self.seq_vectors) npt.assert_array_equal(obs, exp) # skip validation obs = embed_vec_to_numpy(self.seq_vectors, validate=False) npt.assert_array_equal(obs, exp) def test_embed_vec_to_numpy_raises(self): # input contains non-vector lst = [SequenceVector(self.vector1, "ACGT"), SequenceEmbedding(np.vstack([self.vector2, self.vector3]), "AT")] msg = "Input iterable contains objects that do not subclass EmbeddingVector." with self.assertRaisesRegex(ValueError, msg): embed_vec_to_numpy(lst) # mixed sequence types lst = [SequenceVector(self.vector1, "ACGT"), ProteinVector(self.vector2, "MKRPL")] msg = "All objects must be of the same type." with self.assertRaisesRegex(ValueError, msg): embed_vec_to_numpy(lst) # lengths are not equal lst = [SequenceVector(self.vector1, "ACGT"), SequenceVector(self.vector2, "GCTA"), SequenceVector(self.bad_vector, "TTAG")] msg = "All vectors must have the same length." with self.assertRaisesRegex(ValueError, msg): embed_vec_to_numpy(lst) def test_embed_vec_to_distances(self): # Test if to_distances returns a DistanceMatrix object obs = embed_vec_to_distances(self.seq_vectors) self.assertIsInstance(obs, DistanceMatrix) self.assertTupleEqual(obs.shape, (3, 3)) self.assertTrue(all(isinstance(d, float) for d in obs.condensed_form())) d12 = euclidean(self.vector1, self.vector2) d13 = euclidean(self.vector1, self.vector3) d23 = euclidean(self.vector2, self.vector3) exp = DistanceMatrix([[0, d12, d13], [d12, 0, d23], [d13, d23, 0]], ids=["ACGT", "GCTA", "TTAG"]) npt.assert_allclose(obs.data, exp.data) self.assertEqual(obs.ids, exp.ids) obs = embed_vec_to_distances(self.seq_vectors, validate=False) self.assertIsInstance(obs, DistanceMatrix) def test_embed_vec_to_ordination(self): # Test if to_ordination returns an OrdinationResults object obs = embed_vec_to_ordination(self.seq_vectors) self.assertIsInstance(obs, OrdinationResults) self.assertEqual(obs.samples.shape, (3, 3)) self.assertEqual(obs.features.shape, (3, 3)) reconstructed = (obs.samples.values @ obs.features.values.T) npt.assert_allclose( reconstructed, embed_vec_to_numpy(self.seq_vectors) ) obs = embed_vec_to_ordination(self.seq_vectors, validate=False) self.assertIsInstance(obs, OrdinationResults) def test_embed_vec_to_dataframe(self): # Test if to_dataframe returns a pandas DataFrame object obs = embed_vec_to_dataframe(self.seq_vectors) self.assertIsInstance(obs, pd.DataFrame) self.assertTupleEqual(obs.shape, (3, 3)) exp = pd.DataFrame([self.vector1, self.vector2, self.vector3], index=["ACGT", "GCTA", "TTAG"]) pd.testing.assert_frame_equal(obs, exp) obs = embed_vec_to_dataframe(self.seq_vectors, validate=False) self.assertIsInstance(obs, pd.DataFrame) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/embedding/tests/test_protein.py000066400000000000000000000134321520735541300256360ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt from skbio.util import get_data_path from skbio import Protein from skbio.embedding._embedding import SequenceVector, embed_vec_to_numpy from skbio.embedding._protein import ( ProteinEmbedding, ProteinVector ) class ProteinEmbeddingTests(TestCase): def setUp(self): self.emb = np.load(get_data_path("embed1.txt.npy")) self.seq = ("IGKEEIQQRLAQFVDHWKELKQLAAARGQRLEESLEYQ" "QFVANVEEEEAWINEKMTLVASED") self.invalid_seq = ( "$GKEEIQQRLAQFVDHWKELKQLAAARGQRLEESLEYQ" "QFVANVEEEEAWINEKMTLVASED") def test_clipping(self): emb, s = self.emb, self.seq nemb = np.zeros((emb.shape[0] + 2, emb.shape[1])) nemb[1:-1] = emb p2_emb = ProteinEmbedding(nemb, s, clip_head=True, clip_tail=True) npt.assert_array_equal(p2_emb.embedding, emb) self.assertEqual(p2_emb.sequence, s) def test_str(self): emb, s = self.emb, self.seq p_emb = ProteinEmbedding(emb, s) self.assertEqual(str(p_emb), s) self.assertEqual(p_emb.sequence, s) byte_s = np.array([b"I", b"G", b"K", b"E", b"E", b"I", b"Q", b"Q", b"R", b"L", b"A", b"Q", b"F", b"V", b"D", b"H", b"W", b"K", b"E", b"L", b"K", b"Q", b"L", b"A", b"A", b"A", b"R", b"G", b"Q", b"R", b"L", b"E", b"E", b"S", b"L", b"E", b"Y", b"Q", b"Q", b"F", b"V", b"A", b"N", b"V", b"E", b"E", b"E", b"E", b"A", b"W", b"I", b"N", b"E", b"K", b"M", b"T", b"L", b"V", b"A", b"S", b"E", b"D"], dtype="|S1") npt.assert_array_equal(p_emb.residues, byte_s) self.assertEqual(str(p_emb.ids.tobytes().decode("ascii")), s) def test_skbio_protein(self): emb, s = self.emb, self.seq p_emb = ProteinEmbedding(emb, Protein(s)) self.assertEqual(str(p_emb), s) self.assertEqual(p_emb.sequence, s) def test_str_spaces(self): seq = ("I G K E E I Q Q R L A Q F V D H W K E L K Q L A " "A A R G Q R L E E S L E Y Q Q F V A N V E E E E " "A W I N E K M T L V A S E D") p_emb = ProteinEmbedding(self.emb, seq) self.assertEqual(str(p_emb), self.seq) self.assertEqual(p_emb.sequence, self.seq) def test_embedding(self): emb, s = self.emb, self.seq p_emb = ProteinEmbedding(emb, s) self.assertTupleEqual(p_emb.embedding.shape, (62, 1024)) def test_assert_length(self): with self.assertRaises(ValueError): ProteinEmbedding(self.emb, self.seq + "A") def test_invalid_sequence(self): emb, s = self.emb, self.invalid_seq with self.assertRaises(ValueError): ProteinEmbedding(emb, s) def test_repr(self): emb, s = self.emb, self.seq p_emb = ProteinEmbedding(emb, s) self.assertIn("ProteinEmbedding", repr(p_emb)) class ProteinVectorTests(TestCase): def setUp(self): rk = 10 self.emb = np.random.randn(rk) self.seq = Protein( "IGKEEIQQRLAQFVDHWKELKQLAAARGQRLEESLEYQQFVANVEEEEAWINEKMTLVASED", metadata={"id": "seq1"} ) self.vector1 = np.array([1, 2, 3]) self.vector2 = np.array([4, 5, 6]) self.vector3 = np.array([7, 8, 9]) self.bad_vector = np.array([7, 8]) self.bad_vector2 = np.array([[7, 8], [7, 9]]) self.protein_vectors = [ProteinVector(self.vector1, "IGKE"), ProteinVector(self.vector2, "EIQQ"), ProteinVector(self.vector3, "RLAQ")] def test_valid_protein_vector(self): ProteinVector(self.emb, self.seq) ProteinVector(self.emb, str(self.seq)) ProteinVector(self.emb, str(self.seq).encode("ascii")) def test_invalid_protein_vector(self): seq = "$GKEEIQQRLAQFVDHWKELKQLAAARGQRLEESLEYQQFVANVEEEEAWINEKMTLVASED^^" with self.assertRaises(ValueError): ProteinVector(self.emb, seq) with self.assertRaises(ValueError): ProteinVector(self.bad_vector2, seq) def test_invalid_vector_shape(self): msg = "Only one vector per sequence is allowed." with self.assertRaisesRegex(ValueError, msg): ProteinVector(np.vstack([self.emb, self.emb]), self.seq) def test_repr(self): pv = ProteinVector(self.emb, self.seq) self.assertIn("ProteinVector", repr(pv)) self.assertIn("vector dimension", repr(pv)) def test_to_numpy(self): # confirm that Protein objects can be casted to numpy exp = np.array([self.vector1, self.vector2, self.vector3]) obs = embed_vec_to_numpy(self.protein_vectors) npt.assert_array_equal(obs, exp) def test_to_numpy_raises(self): # assert that all types are the same lst = [ProteinVector(self.vector1, "IGKE"), SequenceVector(self.vector2, "EIQQ"), SequenceVector(self.bad_vector, "RLAQ")] with self.assertRaises(ValueError): embed_vec_to_numpy(lst) # assert that all objects subclass EmbeddingVector lst = [Protein("IGKE"), Protein("EIQQ"), Protein("RLAQ")] with self.assertRaises(ValueError): embed_vec_to_numpy(lst) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/io/000077500000000000000000000000001520735541300200715ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/__init__.py000066400000000000000000000275551520735541300222200ustar00rootroot00000000000000r"""Input and Output (:mod:`skbio.io`) ================================== .. currentmodule:: skbio.io This module provides input/output (I/O) functionality for scikit-bio. In bioinformatics there are many different file formats, and in scikit-bio there are many different classes which can read and write these formats. The many-to-many nature of the relationships between scikit-bio objects and file formats inspired the creation of the scikit-bio ``io`` module, which manages these relationships transparently. For general guidance on reading and writing files and working with scikit-bio objects, see the :ref:`tutorial` section and the `Reading and writing files `_ notebook. For guidance on a specific format or scikit-bio object, see the documentation for that format or object. See the `IORegistry docs `_ for guidance on creating custom formats and registering custom readers, writers, and sniffers. Supported file formats ---------------------- scikit-bio provides parsers for the following file formats. For details on what objects are supported by each format, see the associated documentation. .. currentmodule:: skbio.io.format .. autosummary:: :toctree: generated/ binary_dm biom blast6 blast7 clustal embl embed fasta fastq genbank gff3 lsmat newick ordination phylip phylip_dm qseq stockholm taxdump sample_metadata Read/write files ---------------- .. rubric:: Generic I/O functions .. currentmodule:: skbio.io.registry .. autosummary:: :toctree: generated/ write read sniff .. rubric:: Additional I/O utilities .. currentmodule:: skbio.io .. autosummary:: :toctree: generated/ util Develop custom formats ---------------------- .. rubric:: Developer documentation on extending I/O .. autosummary:: :toctree: generated/ registry Exceptions and warnings ----------------------- .. currentmodule:: skbio.io .. rubric:: General exceptions and warnings .. autosummary:: FormatIdentificationWarning ArgumentOverrideWarning UnrecognizedFormatError IOSourceError FileFormatError .. rubric:: Format-specific exceptions and warnings .. autosummary:: BLAST7FormatError ClustalFormatError EMBLFormatError FASTAFormatError FASTQFormatError GenBankFormatError GFF3FormatError LSMatFormatError NewickFormatError OrdinationFormatError PhylipFormatError PhylipDMFormatError QSeqFormatError QUALFormatError StockholmFormatError .. _tutorial: Tutorial -------- Reading and writing files (I/O) can be a complicated task: * A file format can sometimes be read into more than one in-memory representation (i.e., object). For example, a FASTA file can be read into a :class:`~skbio.alignment.TabularMSA` or :class:`~skbio.sequence.DNA` depending on what operations you'd like to perform on your data. * A single object might be writeable to more than one file format. For example, an :class:`~skbio.alignment.TabularMSA` object could be written to FASTA, FASTQ, CLUSTAL, or PHYLIP formats, just to name a few. * You might not know the exact file format of your file, but you want to read it into an appropriate object. * You might want to read multiple files into a single object, or write an object to multiple files. * Instead of reading a file into an object, you might want to stream the file using a generator (e.g., if the file cannot be fully loaded into memory). To address these issues (and others), scikit-bio provides a simple, powerful interface for dealing with I/O. We accomplish this by using a single I/O registry defined in :class:`~skbio.io.registry.IORegistry`. What kinds of files scikit-bio can use ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To see a complete list of file-like inputs that can be used for reading, writing, and sniffing, see the documentation for :func:`skbio.io.util.open`. Reading files into scikit-bio ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ There are two ways to read files. The first way is to use the procedural interface: .. code-block:: python my_obj = skbio.io.read(file, format='someformat', into=SomeSkbioClass) Here, ``file`` can be a path to a file, a file handle, or any of the other objects with read support listed in the :func:`skbio.io.util.open` documentation. The second way to read files is to use the object-oriented interface, which is automatically constructed from the procedural interface: .. code-block:: python my_obj = SomeSkbioClass.read(file, format='someformat') .. note:: A very common use case in bioinformatics is to read multi-line FASTA and FASTQ files. For examples on how to achieve this with scikit-bio, please see the `FASTA documentation `_ or the `FASTQ documentation `_. As an example, let's read a :mod:`~skbio.io.format.newick` file into a :class:`~skbio.tree.TreeNode` object using both interfaces. Here we will use Python's built-in :class:`~io.StringIO` class to mimic an open file: >>> from skbio import read as sk_read >>> from skbio import TreeNode >>> from io import StringIO >>> open_filehandle = StringIO('(a, b);') >>> tree = sk_read(open_filehandle, format='newick', into=TreeNode) >>> tree Or, using the object-oriented interface: >>> open_filehandle = StringIO('(a, b);') >>> tree = TreeNode.read(open_filehandle, format='newick') >>> tree In the case of :func:`skbio.io.registry.read` if ``into`` is not provided, then a generator will be returned. What the generator yields will depend on what format is being read. When ``into`` is provided, format may be omitted and the registry will use its knowledge of the available formats for the requested class to infer (sniff) the correct format. This format inference is also available in the object-oriented interface, meaning that ``format`` may be omitted there as well. As an example: >>> open_filehandle = StringIO('(a, b);') >>> tree = TreeNode.read(open_filehandle) >>> tree We call format inference **sniffing**, much like the :class:`csv.Sniffer` class of Python's standard library. The goal of a ``sniffer`` is two-fold: to identify if a file is a specific format, and if it is, to provide ``**kwargs`` which can be used to better parse the file. .. note:: There is a built-in ``sniffer`` which results in a useful error message if an empty file is provided as input and the format was omitted. See the `sniff documentation `_ for more information. Writing files from scikit-bio ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Just as when reading files, there are two ways to write files. Procedural Interface: .. code-block:: python skbio.io.write(my_obj, format='someformat', into=file) Object-oriented Interface: .. code-block:: python my_obj.write(file, format='someformat') In the procedural interface, ``format`` is required. Without it, scikit-bio does not know how you want to serialize an object. Object-oriented interfaces define a default ``format``, so it may not be necessary to include it. For more information on writing to a specific file format, please see that format's documentation page. Streaming files with read and write ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you are working with particularly large files, streaming them might be preferable. For instance, if your file is larger than your available memory, you won't be able to read the entire file into memory at once. One way to get around this is to use streaming. Scikit-bio's ``io`` module offers the ability to construct a streaming interface from the ``read`` and ``write`` functions. ``skbio.io.read`` returns a generator, which can then be passed to ``skbio.io.write`` to write only one chunk from the generator at a time. .. code-block:: python seq_gen = skbio.io.read(big_file, format='someformat') skbio.io.write(seq_gen, into=write_file, format='someformat') Support for stdin ^^^^^^^^^^^^^^^^^ You may stream files in scikit-bio through stdin. To do this, you must set the ``verify`` parameter of the ``read`` function to ``False``. This will bypass scikit-bio's sniffers, which is what enables piping to function. However, the cost is that scikit-bio is no longer checking that your file formats are correct, so the user must be confident that they know the file format they are working with. For example, if you wanted to pipe a FASTA file into a python script, your script could look like this. .. code-block:: python import skbio import sys for r in skbio.read(sys.stdin, format='fasta', verify=False): print(r.metadata['id']) This would then enable you to do the following. .. code-block:: bash $ cat some_file.fna | python script.py """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from importlib import import_module from ._warning import FormatIdentificationWarning, ArgumentOverrideWarning from ._exception import ( UnrecognizedFormatError, FileFormatError, BLAST7FormatError, ClustalFormatError, FASTAFormatError, GenBankFormatError, IOSourceError, FASTQFormatError, LSMatFormatError, NewickFormatError, OrdinationFormatError, PhylipFormatError, PhylipDMFormatError, QSeqFormatError, QUALFormatError, StockholmFormatError, GFF3FormatError, EMBLFormatError, BIOMFormatError, EmbedFormatError, ) from .registry import write, read, sniff, create_format, io_registry from .util import open __all__ = [ "write", "read", "sniff", "open", "io_registry", "create_format", "FormatIdentificationWarning", "ArgumentOverrideWarning", "UnrecognizedFormatError", "IOSourceError", "FileFormatError", "BLAST7FormatError", "ClustalFormatError", "EMBLFormatError", "FASTAFormatError", "FASTQFormatError", "GenBankFormatError", "GFF3FormatError", "LSMatFormatError", "NewickFormatError", "OrdinationFormatError", "PhylipFormatError", "PhylipDMFormatError", "QSeqFormatError", "QUALFormatError", "StockholmFormatError", "BIOMFormatError", "EmbedFormatError", ] # Necessary to import each file format module to have them added to the I/O # registry. We use import_module instead of a typical import to avoid flake8 # unused import errors. import_module("skbio.io.format.blast6") import_module("skbio.io.format.blast7") import_module("skbio.io.format.clustal") import_module("skbio.io.format.embl") import_module("skbio.io.format.fasta") import_module("skbio.io.format.fastq") import_module("skbio.io.format.lsmat") import_module("skbio.io.format.newick") import_module("skbio.io.format.ordination") import_module("skbio.io.format.phylip") import_module("skbio.io.format.qseq") import_module("skbio.io.format.genbank") import_module("skbio.io.format.gff3") import_module("skbio.io.format.stockholm") import_module("skbio.io.format.binary_dm") import_module("skbio.io.format.taxdump") import_module("skbio.io.format.sample_metadata") import_module("skbio.io.format.biom") import_module("skbio.io.format.embed") import_module("skbio.io.format.phylip_dm") # This is meant to be a handy indicator to the user that they have done # something wrong. import_module("skbio.io.format.emptyfile") scikit-bio-scikit-bio-a3beaa6/skbio/io/_exception.py000066400000000000000000000060621520735541300226040ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- class IOSourceError(Exception): """Raised when a file source cannot be resolved.""" pass class FileFormatError(Exception): """Raised when a file cannot be parsed.""" pass class UnrecognizedFormatError(FileFormatError): """Raised when a file's format is unknown, ambiguous, or unidentifiable.""" pass class GenBankFormatError(FileFormatError): """Raised when a ``genbank`` formatted file cannot be parsed.""" pass class EMBLFormatError(FileFormatError): """Raised when a ``EMBL`` formatted file cannot be parsed.""" pass class GFF3FormatError(FileFormatError): """Raised when a ``GFF3`` formatted file cannot be parsed.""" pass class BLAST7FormatError(FileFormatError): """Raised when a ``blast7`` formatted file cannot be parsed.""" pass class ClustalFormatError(FileFormatError): """Raised when a ``clustal`` formatted file cannot be parsed.""" pass class FASTAFormatError(FileFormatError): """Raised when a ``fasta`` formatted file cannot be parsed.""" pass class QUALFormatError(FASTAFormatError): """Raised when a ``qual`` formatted file cannot be parsed.""" pass class LSMatFormatError(FileFormatError): """Raised when a ``lsmat`` formatted file cannot be parsed.""" pass class OrdinationFormatError(FileFormatError): """Raised when an ``ordination`` formatted file cannot be parsed.""" pass class NewickFormatError(FileFormatError): """Raised when a ``newick`` formatted file cannot be parsed.""" pass class FASTQFormatError(FileFormatError): """Raised when a ``fastq`` formatted file cannot be parsed.""" pass class PhylipFormatError(FileFormatError): """Raised when a ``phylip`` formatted file cannot be parsed. May also be raised when an object (e.g., ``TabularMSA``) cannot be written in ``phylip`` format. """ pass class PhylipDMFormatError(FileFormatError): """Raised when a ``phylip_dm`` formatted file cannot be parsed.""" pass class QSeqFormatError(FileFormatError): """Raised when a ``qseq`` formatted file cannot be parsed.""" pass class StockholmFormatError(FileFormatError): """Raised when a ``stockholm`` formatted file cannot be parsed.""" pass class InvalidRegistrationError(Exception): """Raised if function doesn't meet the expected API of its registration.""" pass class DuplicateRegistrationError(Exception): """Raised when a function is already registered in skbio.io.""" pass class BIOMFormatError(Exception): """Raised when a ``BIOM`` formatted file cannot be parsed.""" pass class EmbedFormatError(Exception): """Raised when an ``Embedding`` formatted file cannot be parsed.""" pass scikit-bio-scikit-bio-a3beaa6/skbio/io/_fileobject.py000066400000000000000000000050221520735541300227070ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io def is_binary_file(file): import h5py return isinstance( file, (io.BufferedReader, io.BufferedWriter, io.BufferedRandom, h5py.Group) ) # Everything beyond this point will be some kind of hack needed to make # everything work. It's not pretty and it doesn't make great sense much # of the time. I am very sorry to the poor soul who has to read beyond. class FlushDestructorMixin: def __del__(self): # By default, the destructor calls close(), which flushes and closes # the underlying buffer. Override to only flush. if not self.closed: self.flush() class SaneTextIOWrapper(FlushDestructorMixin, io.TextIOWrapper): pass class WrappedBufferedRandom(FlushDestructorMixin, io.BufferedRandom): pass class CompressedMixin(FlushDestructorMixin): """Act as a bridge between worlds.""" def __init__(self, before_file, *args, **kwargs): self.streamable = kwargs.pop("streamable", True) self._before_file = before_file super(CompressedMixin, self).__init__(*args, **kwargs) @property def closed(self): return self.raw.closed or self._before_file.closed def close(self): super(CompressedMixin, self).close() # The above will not usually close before_file. We want the # decompression to be transparent, so we don't want users to deal with # this edge case. Instead we can just close the original now that we # are being closed. self._before_file.close() class CompressedBufferedReader(CompressedMixin, io.BufferedReader): pass class CompressedBufferedWriter(CompressedMixin, io.BufferedWriter): pass class IterableStringReaderIO(io.StringIO): def __init__(self, iterable, newline): self._iterable = iterable super(IterableStringReaderIO, self).__init__("".join(iterable), newline=newline) class IterableStringWriterIO(IterableStringReaderIO): def close(self): if not self.closed: backup = self.tell() self.seek(0) for line in self: self._iterable.append(line) self.seek(backup) super(IterableStringWriterIO, self).close() scikit-bio-scikit-bio-a3beaa6/skbio/io/_iosources.py000066400000000000000000000151161520735541300226210ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io import gzip import bz2 from pathlib import Path from itertools import chain from tempfile import NamedTemporaryFile from skbio.io import IOSourceError from ._fileobject import ( IterableStringWriterIO, IterableStringReaderIO, WrappedBufferedRandom, ) # NamedTemporaryFile isn't an actual file class, it is a function which # returns _TemporaryFileWrapper around a normal file object. Instead of # relying on this implementation, we take whatever the class of the result of # NamedTemporaryFile is. with NamedTemporaryFile() as fh: _WrappedTemporaryFile = type(fh) def get_io_sources(): return ( # The order of these source is significant as they will short-circuit HTTPSource, FilePathSource, BytesIOSource, BufferedIOSource, TextIOSource, WrappedTemporaryFileSource, IterableSource, ) def _compressors(): return (GzipCompressor, BZ2Compressor) def get_compression_handler(name): compressors = {c.name: c for c in _compressors()} compressors["auto"] = AutoCompressor return compressors.get(name, False) class IOSource: closeable = True def __init__(self, file, options): self.file = file self.options = options def can_read(self): return False def can_write(self): return False def get_reader(self): raise NotImplementedError() def get_writer(self): raise NotImplementedError() class Compressor(IOSource): streamable = True name = "" def can_write(self): return True class FilePathSource(IOSource): def can_read(self): return isinstance(self.file, (str, Path)) def can_write(self): return self.can_read() def get_reader(self): return io.open(self.file, mode="rb") def get_writer(self): return io.open(self.file, mode="wb") class HTTPSource(IOSource): def can_read(self): import requests # type: ignore[import-untyped] return isinstance(self.file, str) and requests.compat.urlparse( self.file ).scheme in {"http", "https"} def get_reader(self): import requests # type: ignore[import-untyped] req = requests.get(self.file) req.raise_for_status() return io.BufferedReader(io.BytesIO(req.content)) class BytesIOSource(IOSource): closeable = False def can_read(self): return isinstance(self.file, io.BytesIO) def can_write(self): return self.can_read() def get_reader(self): return WrappedBufferedRandom(self.file) def get_writer(self): return self.get_reader() class BufferedIOSource(IOSource): closeable = False def can_read(self): # `peek` is part of the API we want to guarantee, so we can't just look # for io.BufferedIOBase. Despite the fact that the C implementation of # io.BufferedRandom inherits io.BufferedReader/Writer it is not # reflected in an isinstance check, so we need to check for it manually return isinstance(self.file, (io.BufferedReader, io.BufferedRandom)) def can_write(self): return isinstance(self.file, (io.BufferedWriter, io.BufferedRandom)) def get_reader(self): return self.file def get_writer(self): return self.file class TextIOSource(IOSource): closeable = False def can_read(self): return isinstance(self.file, io.TextIOBase) and self.file.readable() def can_write(self): return isinstance(self.file, io.TextIOBase) and self.file.writable() def get_reader(self): return self.file def get_writer(self): return self.file class WrappedTemporaryFileSource(IOSource): closeable = False def can_read(self): return isinstance(self.file, _WrappedTemporaryFile) and self.file.readable() def can_write(self): return isinstance(self.file, _WrappedTemporaryFile) and self.file.writable() def get_reader(self): # _TemporaryFileWrapper has a file attribute which is an actual fileobj return self.file.file def get_writer(self): return self.file.file class IterableSource(IOSource): def can_read(self): if hasattr(self.file, "__iter__"): iterator = iter(self.file) head = next(iterator, None) if head is None: self.repaired = [] return True if isinstance(head, str): self.repaired = chain([head], iterator) return True else: # We may have mangled a generator at this point, so just abort raise IOSourceError( "Could not open source: %r (mode: %r)" % (self.file, self.options["mode"]) ) return False def can_write(self): return hasattr(self.file, "append") and hasattr(self.file, "__iter__") def get_reader(self): return IterableStringReaderIO(self.repaired, newline=self.options["newline"]) def get_writer(self): return IterableStringWriterIO(self.file, newline=self.options["newline"]) class GzipCompressor(Compressor): name = "gzip" streamable = True def can_read(self): return self.file.peek(2)[:2] == b"\x1f\x8b" def get_reader(self): return gzip.GzipFile(fileobj=self.file) def get_writer(self): return gzip.GzipFile( fileobj=self.file, mode="wb", compresslevel=self.options["compresslevel"] ) class BZ2Compressor(Compressor): name = "bz2" streamable = False def can_read(self): return self.file.peek(3)[:3] == b"BZh" def get_reader(self): return bz2.BZ2File(self.file, mode="rb") def get_writer(self): return bz2.BZ2File( self.file, mode="wb", compresslevel=self.options["compresslevel"] ) class AutoCompressor(Compressor): streamable = True # We can' write so it doesn't matter name = "auto" def get_reader(self): for compression_handler in _compressors(): compressor = compression_handler(self.file, self.options) if compressor.can_read(): return compressor.get_reader() return self.file def get_writer(self): return self.file scikit-bio-scikit-bio-a3beaa6/skbio/io/_warning.py000066400000000000000000000011341520735541300222460ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- class FormatIdentificationWarning(Warning): """Warn when the sniffer of a format cannot confirm the format.""" pass class ArgumentOverrideWarning(Warning): """Warn when a user provided kwarg differs from a guessed kwarg.""" pass scikit-bio-scikit-bio-a3beaa6/skbio/io/descriptors.py000066400000000000000000000126771520735541300230210ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import types import skbio.io class Read: """A descriptor class to generate read methods for scikit-bio objects.""" def __get__(self, instance, cls): if "_read_method" not in cls.__dict__: def _read_method(file, format=None, **kwargs): return skbio.io.read(file, into=cls, format=format, **kwargs) _read_method.__doc__ = self._make_docstring(cls) cls._read_method = _read_method return cls._read_method def _make_docstring(self, cls): name, supported_fmts, default, see = _docstring_vars(cls, "read") extra_params = _extra_kwargs_docs(cls, "_reader_kwargs") return f"""Create a new ``{name}`` instance from a file. This is a convenience method for :func:`skbio.io.registry.read`. For more information about the I/O system in scikit-bio, please see :mod:`skbio.io`. {supported_fmts} Parameters ---------- file : openable (filepath, URL, filehandle, etc.) The location to read the given `format` into. Something that is understood by :func:`skbio.io.util.open`. Filehandles are not automatically closed, it is the responsibility of the caller. format : str, optional The format of the file. The format must be a format name with a reader for ``{name}``. If None, the format will be inferred. {extra_params}kwargs : dict, optional Additional arguments passed to :func:`skbio.io.registry.read()` and the reader for ``{name}``. Returns ------- ``{name}`` A new instance. See Also -------- write skbio.io.registry.read skbio.io.util.open {see} """ class Write: """A descriptor class to generate write methods for scikit-bio objects.""" def __get__(self, instance, cls): """This gets called when any skbio object accesses its ``write`` attribute.""" if instance is None: if "_write_method" not in cls.__dict__: cls._write_method = self._generate_write_method(cls) return cls._write_method if "_write_method" not in instance.__dict__: instance._write_method = types.MethodType( self._generate_write_method(cls), instance ) return instance._write_method def _generate_write_method(self, cls): def _write_method(self, file, format=None, **kwargs): if format is None: if hasattr(cls, "default_write_format"): format = cls.default_write_format else: raise ValueError(f"{cls.__name__} has no default write format.") return skbio.io.write(self, into=file, format=format, **kwargs) _write_method.__doc__ = self._make_docstring(cls) return _write_method def _make_docstring(self, cls): name, supported_fmts, default, see = _docstring_vars(cls, "write") return f"""Write an instance of ``{name}`` to a file. This is a convenience method for :func:`skbio.io.registry.write()`. For more information about the I/O system in scikit-bio, please see :mod:`skbio.io`. {supported_fmts} Parameters ---------- file : openable (filepath, filehandle, etc.) The location to write the given `format` into. Something that is understood by :func:`skbio.io.util.open()`. Filehandles are not automatically closed, it is the responsibility of the caller. format : str, optional The format to write the ``{name}`` object as. The format must be a registered format name with a writer for ``{name}``. Default is ``'{default}'``. kwargs : dict, optional Additional arguments passed to the writer for ``{name}``. See Also -------- read skbio.io.registry.write skbio.io.util.open {see} """ def _extra_kwargs_docs(cls, attr): """Build parameter documentation from a class attribute dict. Parameters ---------- cls : type The class to inspect for the attribute. attr : str Name of a class attribute that maps parameter names to NumPy-style description strings (``"type\\n description"``). Returns ------- str Formatted parameter block ready for insertion into a docstring, or an empty string if the attribute is absent. """ extra = getattr(cls, attr, None) if not extra: return "" lines = [] for param, description in extra.items(): lines.append(f"{param} : {description}") return "\n".join(lines) + "\n" def _docstring_vars(cls, func): """Generate variables for dynamically generated docstrings.""" from skbio.io.registry import io_registry if func == "write": formats = io_registry.list_write_formats(cls) elif func == "read": formats = io_registry.list_read_formats(cls) else: raise ValueError("'func' parameter must be 'read' or 'write'.") imports = io_registry._import_paths(formats) formats = io_registry._formats_for_docs(formats, imports) if formats: supported_fmts = f"Supported file formats include:\n\n{formats}" else: supported_fmts = "" name = cls.__name__ default = getattr(cls, "default_write_format", "None") see = "\n".join(imports) return name, supported_fmts, default, see scikit-bio-scikit-bio-a3beaa6/skbio/io/format/000077500000000000000000000000001520735541300213615ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/__init__.py000066400000000000000000000005651520735541300235000ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # ruff: noqa: D104 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/_base.py000066400000000000000000000166571520735541300230230ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import re import warnings import numpy as np from skbio.util import cardinal_to_ordinal _whitespace_regex = re.compile(r"\s") _newline_regex = re.compile(r"\n") def _decode_qual_to_phred(qual_str, variant=None, phred_offset=None): phred_offset, phred_range = _get_phred_offset_and_range( variant, phred_offset, [ "Must provide either `variant` or `phred_offset` in order to decode " "quality scores.", "Decoding Solexa quality scores is not currently supported, " "as quality scores are always stored as Phred scores in " "scikit-bio. Please see the following scikit-bio issue to " "track progress on this:\n\t" "https://github.com/scikit-bio/scikit-bio/issues/719", ], ) qual = np.frombuffer(qual_str.encode("ascii"), dtype=np.uint8) - phred_offset if np.any((qual > phred_range[1]) | (qual < phred_range[0])): raise ValueError( "Decoded Phred score is out of range [%d, %d]." % (phred_range[0], phred_range[1]) ) return qual def _encode_phred_to_qual(phred, variant=None, phred_offset=None): phred_offset, phred_range = _get_phred_offset_and_range( variant, phred_offset, [ "Must provide either `variant` or `phred_offset` in order to encode " "Phred scores.", "Encoding Solexa quality scores is not currently supported. " "Please see the following scikit-bio issue to track progress " "on this:\n\t" "https://github.com/scikit-bio/scikit-bio/issues/719", ], ) qual_chars = [] for score in phred: if score < phred_range[0]: raise ValueError( "Phred score %d is out of range [%d, %d]." % (score, phred_range[0], phred_range[1]) ) if score > phred_range[1]: warnings.warn( "Phred score %d is out of targeted range [%d, %d]. Converting " "to %d." % (score, phred_range[0], phred_range[1], phred_range[1]), UserWarning, ) score = phred_range[1] qual_chars.append(chr(score + phred_offset)) return "".join(qual_chars) def _get_phred_offset_and_range(variant, phred_offset, errors): if variant is None and phred_offset is None: raise ValueError(errors[0]) if variant is not None and phred_offset is not None: raise ValueError("Cannot provide both `variant` and `phred_offset`.") if variant is not None: if variant == "sanger": phred_offset = 33 phred_range = (0, 93) elif variant == "illumina1.3": phred_offset = 64 phred_range = (0, 62) elif variant == "illumina1.8": phred_offset = 33 phred_range = (0, 62) elif variant == "solexa": phred_offset = 64 phred_range = (-5, 62) raise ValueError(errors[1]) else: raise ValueError("Unrecognized variant %r." % variant) else: if not (33 <= phred_offset <= 126): raise ValueError( "`phred_offset` %d is out of printable ASCII character range." % phred_offset ) phred_range = (0, 126 - phred_offset) return phred_offset, phred_range def _get_nth_sequence(generator, seq_num): # i is set to None so that an empty generator will not result in an # undefined variable when compared to seq_num. i = None if seq_num is None or seq_num < 1: raise ValueError( "Invalid sequence number (`seq_num`=%s). `seq_num`" " must be between 1 and the number of sequences in" " the file." % str(seq_num) ) try: for i, seq in zip(range(1, seq_num + 1), generator): pass finally: generator.close() if i == seq_num: return seq raise ValueError( "Reached end of file before finding the %s sequence." % cardinal_to_ordinal(seq_num) ) def _parse_fasta_like_header(line): id_ = "" desc = "" header = line[1:].rstrip() if header: if header[0].isspace(): # no id desc = header.lstrip() else: header_tokens = header.split(None, 1) if len(header_tokens) == 1: # no description id_ = header_tokens[0] else: id_, desc = header_tokens return id_, desc def _format_fasta_like_records( generator, id_whitespace_replacement, description_newline_replacement, require_qual, lowercase=None, ): if ( id_whitespace_replacement is not None and "\n" in id_whitespace_replacement ) or ( description_newline_replacement is not None and "\n" in description_newline_replacement ): raise ValueError( "Newline character (\\n) cannot be used to replace whitespace in " "sequence IDs, nor to replace newlines in sequence descriptions." ) for idx, seq in enumerate(generator): if len(seq) < 1: raise ValueError( "%s sequence does not contain any characters (i.e., it is an " "empty/blank sequence). Writing empty sequences is not " "supported." % cardinal_to_ordinal(idx + 1) ) if "id" in seq.metadata: id_ = "%s" % seq.metadata["id"] else: id_ = "" if id_whitespace_replacement is not None: id_ = _whitespace_regex.sub(id_whitespace_replacement, id_) if "description" in seq.metadata: desc = "%s" % seq.metadata["description"] else: desc = "" if description_newline_replacement is not None: desc = _newline_regex.sub(description_newline_replacement, desc) if desc: header = "%s %s" % (id_, desc) else: header = id_ if require_qual and "quality" not in seq.positional_metadata: raise ValueError( "Cannot write %s sequence because it does not have quality " "scores associated with it." % cardinal_to_ordinal(idx + 1) ) qual = None if "quality" in seq.positional_metadata: qual = seq.positional_metadata["quality"].values if lowercase is not None: seq_str = seq.lowercase(lowercase) else: seq_str = str(seq) yield header, "%s" % seq_str, qual def _line_generator(fh, skip_blanks=False, strip=True): for line in fh: if strip: line = line.strip() skip = False if skip_blanks: skip = line.isspace() or not line if not skip: yield line def _too_many_blanks(fh, max_blanks): count = 0 too_many = False for line in _line_generator(fh, skip_blanks=False): if line: break else: count += 1 if count > max_blanks: too_many = True break fh.seek(0) return too_many scikit-bio-scikit-bio-a3beaa6/skbio/io/format/_blast.py000066400000000000000000000043751520735541300232100ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import functools import contextlib import pandas as pd _possible_columns = { "qseqid": str, "qgi": float, "qacc": str, "qaccver": str, "qlen": float, "sseqid": str, "sallseqid": str, "sgi": float, "sallgi": float, "sacc": str, "saccver": str, "sallacc": str, "slen": float, "qstart": float, "qend": float, "sstart": float, "send": float, "qseq": str, "sseq": str, "evalue": float, "bitscore": float, "score": float, "length": float, "pident": float, "nident": float, "mismatch": float, "positive": float, "gapopen": float, "gaps": float, "ppos": float, "frames": str, "qframe": float, "sframe": float, "btop": float, "staxids": str, "sscinames": str, "scomnames": str, "sblastnames": str, "sskingdoms": str, "stitle": str, "salltitles": str, "sstrand": str, "qcovs": float, "qcovhsp": float, } def _parse_blast_data(fh, columns, error, error_message, comment=None, skiprows=None): read_csv = functools.partial( pd.read_csv, na_values="N/A", sep="\t", header=None, keep_default_na=False, comment=comment, skiprows=skiprows, ) # HACK for https://github.com/pandas-dev/pandas/issues/14418 # this avoids closing the `fh`, whose lifetime isn't the responsibility # of this parser with _noop_close(fh) as fh: lineone = read_csv(fh, nrows=1) if len(lineone.columns) != len(columns): raise error(error_message % (len(columns), len(lineone.columns))) fh.seek(0) return read_csv(fh, names=columns, dtype=_possible_columns) # HACK for https://github.com/pandas-dev/pandas/issues/14418 @contextlib.contextmanager def _noop_close(fh): backup = fh.close fh.close = lambda: None try: yield fh finally: fh.close = backup scikit-bio-scikit-bio-a3beaa6/skbio/io/format/_sequence_feature_vocabulary.py000066400000000000000000000276211520735541300276540ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import re from skbio.metadata import IntervalMetadata from skbio.io.format._base import _line_generator from skbio.io import FileFormatError def _vocabulary_change(format="insdc", read_in=True): """Return a dict that converts between memory and output vocabulary.""" convert = { "phase": {"insdc": "codon_start"}, "source": {"insdc": "inference"}, "db_xref": {"gff3": "Dbxref"}, "note": {"gff3": "Note"}, } if read_in: return {v[format]: k for k, v in convert.items() if format in v} else: return {k: v[format] for k, v in convert.items() if format in v} def _vocabulary_skip(format="insdc"): """Return vocabluaries skipped for auto disk output, given a format. Return a list of vocabularies that should be skipped when auto output to disk for the specified format. """ skip = { "type": ("insdc", "gff3"), "ID": ("insdc"), "translation": ("gff3"), "strand": ("insdc"), } return [k for k, v in skip.items() if format in v] def _yield_section(is_another_section, **kwargs): """Return function that returns successive sections from file. Parameters ---------- is_another_section : callable It takes a string as input and return a boolean indicating a new section starts. kwargs : dict, optional Keyword arguments will be passed to `_line_generator`. Returns ------- function A function accept a list of lines as input and return a generator to yield section one by one. """ def parser(lines): curr = [] for line in _line_generator(lines, **kwargs): # if we find another, return the previous section if is_another_section(line): if curr: yield curr curr = [] curr.append(line) # don't forget to return the last section in the file if curr: yield curr return parser def _parse_section_default( lines, label_delimiter=None, join_delimiter=" ", return_label=False ): """Parse sections in default way. Do 2 things: 1. split first line with label_delimiter for label 2. join all the lines into one str with join_delimiter. """ data = [] label = None line = lines[0] items = line.split(label_delimiter, 1) if len(items) == 2: label, section = items else: label = items[0] section = "" data.append(section) data.extend(lines[1:]) data = join_delimiter.join(i.strip() for i in data) if return_label: return label, data else: return data def _serialize_section_default(header, obj, indent=12): return "{header:<{indent}}{obj}\n".format(header=header, obj=obj, indent=indent) def _parse_feature_table(lines, length): """Parse DDBJ/ENA/GenBank Feature Table.""" imd = IntervalMetadata(length) # skip the 1st FEATURES line if lines[0].startswith("FEATURES"): lines = lines[1:] # magic number 21: the lines following header of each feature # are indented with 21 spaces. feature_indent = " " * 21 section_splitter = _yield_section( lambda x: not x.startswith(feature_indent), skip_blanks=True, strip=False ) for section in section_splitter(lines): _parse_single_feature(section, imd) return imd def _parse_single_feature(lines, imd): """Parse a feature and add it to ``IntervalMetadata`` object. Parameters ---------- imd : IntervalMetadata An IntervalMetadata object to which the parsed feature will be added. lines : list of strings A list of strings representing the lines of text to be parsed. """ voca_change = _vocabulary_change("insdc") # each component of a feature starts with '/', except the 1st # component of location. section_splitter = _yield_section(lambda x: x.startswith("/"), strip=True) section_iter = section_splitter(lines) # 1st section is location section = next(section_iter) feature_type, feature_loc = _parse_section_default( section, join_delimiter="", return_label=True ) metadata = {"type": feature_type, "__location": feature_loc} intvl = imd.add(*_parse_loc_str(feature_loc)) for section in section_iter: # following sections are Qualifiers k, v = _parse_section_default( section, label_delimiter="=", join_delimiter=" ", return_label=True ) # 1st char is '/' k = k[1:] if k in voca_change: k = voca_change[k] if k == "phase": v = int(v) - 1 # some Qualifiers can appear multiple times if k in metadata: if not isinstance(metadata[k], list): metadata[k] = [metadata[k]] metadata[k].append(v) else: metadata[k] = v intvl.metadata.update(metadata) def _parse_loc_str(loc_str): """Parse location string. .. warning: This converts coordinates to 0-based from 1-based GenBank coordinate system. The location descriptor can be one of the following [1]_: (a) a single base number. e.g. 467 (b) a site between two indicated adjoining bases. e.g. 123^124 (c) a single base chosen from within a specified range of bases (not allowed for new entries). e.g. 102.110 (d) the base numbers delimiting a sequence span. e.g.340..565 (e) a remote entry identifier followed by a local location descriptor (i.e., a-d). e.g. J00194.1:100..202 Notes ----- This does not fully handle (e) case. It will discard the remote entry part and only keep the local part. When it parses locations across strand (e.g. "complement(123..145),200..209"), it will record all the span parts but will record strand as negative. References ---------- .. [1] http://www.insdc.org/files/feature_table.html#3.4 """ # define the tokens operators = ["join", "complement", "order"] LPAREN = r"(?P\()" RPAREN = r"(?P\))" COMMA = r"(?P,)" WS = r"(?P\s+)" # A single base position, optionally prefixed with `<` or `>` to indicate # that the exact boundary lies before or beyond the given base (issue #1666, # e.g. "complement(<23231)" as seen in the NCBI lambda virus record # J02459.1). a = r"(?P[<>]?\d+)" b = r"(?P\d+\^\d+)" c = r"(?P\d+\.\d+)" d = r"(?P?\d+)" e_left = r"(?P?\d+)" e_right = r"(?P?[a-zA-Z_0-9\.]+:\d+)" illegal = r"(?P.+)" # The order of tokens in the master regular expression also # matters. When matching, re tries to match pattens in the order # specified. Thus, if a pattern happens to be a substring of a # longer pattern, you need to make sure the longer pattern goes # first. master_pat = re.compile( "|".join( operators + [WS, LPAREN, RPAREN, COMMA, b, c, d, e_left, e_right, a, illegal] ) ) scanner = master_pat.scanner(loc_str) bounds = [] fuzzy = [] metadata = {"strand": "+"} for m in iter(scanner.match, None): p, v = m.lastgroup, m.group() if v == "complement": metadata["strand"] = "-" elif p == "A": fuzzy_s = fuzzy_e = False if v.startswith("<"): v = v[1:] fuzzy_s = True elif v.startswith(">"): v = v[1:] fuzzy_e = True start = int(v) bounds.append((start - 1, start)) fuzzy.append((fuzzy_s, fuzzy_e)) elif p == "B": start, end = v.split("^") start = int(start) bounds.append((start - 1, start)) fuzzy.append((False, False)) elif p == "C" or p == "D": if p == "C": start, end = v.split(".") else: start, end = v.split("..") fuzzy_s = fuzzy_e = False if start.startswith("<"): start = start[1:] fuzzy_s = True if end.startswith(">"): end = end[1:] fuzzy_e = True bounds.append((int(start) - 1, int(end))) fuzzy.append((fuzzy_s, fuzzy_e)) elif p == "ILLEGAL": raise FileFormatError('Could not parse location string: "%s"' % loc_str) return bounds, fuzzy, metadata def _serialize_feature_table(intervals, indent=21): """Serialize a list of intervals into a feature table format. Parameters ---------- intervals : list of ``Interval`` A list of Interval objects representing the intervals to be serialized. indent : int, optional The number of spaces to indent each serialized feature. Defaults to 21. """ for intvl in intervals: yield _serialize_single_feature(intvl, indent) def _serialize_single_feature(intvl, indent=21): """Serialize a single interval into feature format. Parameters ---------- intvl : Interval The Interval object representing the interval to be serialized. indent : int, optional The number of spaces to indent each serialized feature. Defaults to 21. """ # there are 5 spaces before Feature Key starts. padding = " " * 5 qualifiers = [] md = intvl.metadata voca_skip = _vocabulary_skip("insdc") voca_change = _vocabulary_change("insdc", read_in=False) # sort it so the output order is deterministic for k in sorted(md): if k.startswith("__") or k in voca_skip: continue v = md[k] if k == "phase": v = str(v + 1) if k in voca_change: k = voca_change[k] if isinstance(v, list): for vi in v: qualifiers.append(_serialize_qualifier(k, vi)) else: qualifiers.append(_serialize_qualifier(k, v)) if "__location" in md: loc = md["__location"] else: loc = _serialize_location(intvl) # the qualifiers start at column 22 qualifiers = [" " * indent + i for i in qualifiers] return "{header:<{indent}}{loc}\n{qualifiers}\n".format( header=padding + md["type"], loc=loc, indent=indent, qualifiers="\n".join(qualifiers), ) def _serialize_location(intvl): loc = [] for bound, fuzzy in zip(intvl.bounds, intvl.fuzzy): start, end = bound start += 1 if start == end: if fuzzy[0] and not fuzzy[1]: s = "<%d" % start elif fuzzy[1] and not fuzzy[0]: s = ">%d" % start else: s = str(start) elif fuzzy[0] and fuzzy[1]: s = "<%d..>%d" % (start, end) elif fuzzy[0] and not fuzzy[1]: s = "<%d..%d" % (start, end) elif not fuzzy[0] and fuzzy[1]: s = "%d..>%d" % (start, end) else: s = "%d..%d" % (start, end) loc.append(s) if len(loc) > 1: loc_str = "join({})".format(",".join(loc)) else: loc_str = loc[0] if intvl.metadata.get("strand") == "-": loc_str = "complement({})".format(loc_str) return loc_str def _serialize_qualifier(key, value): """Serialize a Qualifier in a feature. Parameters ---------- key : str The key of the Qualifier, representing the type or name of the information. value : int, str The value associated with the Qualifier. """ # if value is empty if not value: return "/%s" % key return "/{k}={v}".format(k=key, v=value) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/binary_dm.py000066400000000000000000000157001520735541300237020ustar00rootroot00000000000000"""Simple binary dissimilarity matrix format (:mod:`skbio.io.format.binary_dm`) ============================================================================ .. currentmodule:: skbio.io.format.binary_dm The Binary DisSimilarity Matrix format (``binary_dm``) encodes a binary representation for dissimilarity and distance matrices. The format is designed to facilitate rapid random access to individual rows or columns of a hollow matrix. Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.stats.distance.PairwiseMatrix` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.stats.distance.SymmetricMatrix` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.stats.distance.DistanceMatrix` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- The binary dissimilarity matrix and object identifiers are stored within an HDF5 [1]_ file. Both datatypes are represented by their own datasets. The `ids` dataset is of a variable length unicode type, while the `matrix` dataset are floating point. The shape of the `ids` is `(N,)`, and the shape of the `dissimilarities` is `(N, N)`. The diagonal of `matrix` are all zeros. The dissimilarity between `ids[i]` and `ids[j]` is interpreted to be the value at `matrix[i, j]`. `i` and `j` are integer indices. Required datasets: +-----------+---------------------+------------------------------+ |Datasets |Value |Description | | |type | | +===========+=====================+==============================+ |format |string |A string identifying the file | | | |as Binary DM format | +-----------+---------------------+------------------------------+ |version |string |The version of the current | | | |Binary DM format | +-----------+---------------------+------------------------------+ |matrix |float32 or float64 |A (N, N) dataset containing | | | |the values of the | | | |dissimilarity matrix | +-----------+---------------------+------------------------------+ |order |string |A (N,) dataset of the sample | | | |IDs, where N is the total | | | |number of IDs | +-----------+---------------------+------------------------------+ Optionally, the file can contain several matrices. In such a case, the 'matrix' dataset will not exist and we will use 'matrix:0' instead. .. note:: This file format is most useful for storing large matrices that do not need to be represented in a human-readable format. This format is especially appropriate for facilitating random access to entries in the distance matrix, such as when calculating within and between distances for a subset of samples in a large matrix. References ---------- .. [1] http://www.hdfgroup.org/ """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import h5py import numpy as np from skbio.io import create_format from skbio.stats.distance import PairwiseMatrix, SymmetricMatrix, DistanceMatrix binary_dm = create_format("binary_dm", encoding="binary") @binary_dm.sniffer() def _binary_dm_sniffer(fh): try: f = h5py.File(fh, "r") except OSError: return False, {} header = _get_header(f) if header is None: return False, {} ids = f.get("order") if ids is None: return False, {} mat = f.get("matrix") if mat is None: mat = f.get("matrix:0") if mat is None: return False, {} n = len(ids) if mat.shape != (n, n): return False, {} return True, {} @binary_dm.reader(PairwiseMatrix) def _binary_dm_to_pairwise(fh, cls=None): if cls is None: cls = PairwiseMatrix return _h5py_mat_to_skbio_mat_stream(cls, fh) @binary_dm.reader(SymmetricMatrix) def _binary_dm_to_symmetric(fh, cls=None): if cls is None: cls = SymmetricMatrix return _h5py_mat_to_skbio_mat_stream(cls, fh) @binary_dm.reader(DistanceMatrix) def _binary_dm_to_distance(fh, cls=None): if cls is None: cls = DistanceMatrix return _h5py_mat_to_skbio_mat_stream(cls, fh) @binary_dm.writer(PairwiseMatrix) def _pairwise_to_binary_dm(obj, fh): return _skbio_mat_to_h5py_mat_stream(obj, fh) @binary_dm.writer(SymmetricMatrix) def _symmetric_to_binary_dm(obj, fh): return _skbio_mat_to_h5py_mat_stream(obj, fh) @binary_dm.writer(DistanceMatrix) def _distance_to_binary_dm(obj, fh): return _skbio_mat_to_h5py_mat_stream(obj, fh) def _h5py_mat_to_skbio_mat_stream(cls, fh): with h5py.File(fh, "r") as f: dm = _h5py_mat_to_skbio_mat(cls, f) return dm def _h5py_mat_to_skbio_mat(cls, f): mat = f.get("matrix") if mat is None: mat = f.get("matrix:0") mat = np.asarray(mat) dm = cls(mat, _parse_ids(f["order"])) return dm def _skbio_mat_to_h5py_mat_stream(obj, fh): with h5py.File(fh, "w") as f: _skbio_mat_to_h5py_mat(obj, f) def _skbio_mat_to_h5py_mat(obj, f): _set_header(f) b_ids = [x.encode("utf-8") for x in obj.ids] np_ids = np.array(b_ids) f.create_dataset("order", data=np_ids) f.create_dataset("matrix", data=obj.data) def _get_header(fh): format_ = fh.get("format") version = fh.get("version") if format is None or version is None: return None else: return {"format": format_[0], "version": version[0]} def _parse_ids(ids): if isinstance(ids[0], bytes): return _bytes_decoder(ids) else: return _passthrough_decoder(ids) def _verify_dimensions(f): ids = f.get("order") mat = f.get("matrix") if mat is None: mat = f.get("matrix:0") if (ids is None) or (mat is None): return False n = len(ids) return mat.shape == (n, n) def _bytes_decoder(x): return [i.decode("utf8") for i in x] def _passthrough_decoder(x): return x def _set_header(f): """Set format spec header information.""" f.create_dataset("format", data=np.array([b"BDSM"])) f.create_dataset("version", data=np.array([b"2020.12"])) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/biom.py000066400000000000000000000102671520735541300226670ustar00rootroot00000000000000r"""BIOM-Format (:mod:`skbio.io.format.biom`) ============================================ .. currentmodule:: skbio.io.format.biom The BIOM-Format (format v2.1.0) is an HDF5-based format to represent sample/feature counts or relative abundances. It is designed specifically for sparse data. Internally, it stores the data in both compressed sparse row, and compressed sparse column representation. It additionally has support for representing sample and feature metadata. .. note:: Internally, BIOM describes features as "observations," which differs from scikit-bio's standard terminology. Throughout scikit-bio documentation and APIs, these are consistently referred to as "features." For more details about terminology differences across formats, see the :ref:`samples_and_features` section of the "Table-like formats" document. Format Support -------------- **Has Sniffer: Yes** +------+------+-------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+=======================================================+ |Yes |Yes |:mod:`skbio.table.Table` | +------+------+-------------------------------------------------------+ Format Specification -------------------- The official format specification for BIOM-Format can be found at [1]_. Examples -------- Here we will write an existing BIOM table, and re-read it. Note that the Table from ``biom`` implicitly gets the ``.write`` method from the IO registry. This ``ByteIO`` object can be a file path in a regular use case. >>> import io, skbio >>> f = io.BytesIO() >>> skbio.table.example_table.write(f) # doctest: +ELLIPSIS <_io.BytesIO object at ...> >>> roundtrip = skbio.read(f, into=skbio.Table) >>> roundtrip 2 x 3 with 5 nonzero entries (83% dense) References ---------- .. [1] http://biom-format.org/documentation/format_versions/biom-2.1.html """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import h5py import skbio from skbio.io import create_format from skbio.table import Table from .. import BIOMFormatError biom = create_format("biom", encoding="binary") @biom.sniffer() def _biom_sniffer(fh): # this can be buffered, in which case .peek will return the buffer # so slice just in case magic = fh.peek(8)[:8] # From https://en.wikipedia.org/wiki/Hierarchical_Data_Format # Note that Wikipedia specifies: "\211HDF\r\n\032\n" which is an ordinal form: # >>> ord('\211') # 137 # >>> ord('\x89') # 137 # >>> ord('\032') # 26 # >>> ord('\x1a') # 26 if magic == b"\x89HDF\r\n\x1a\n": fp = h5py.File(fh, "r") url = fp.attrs.get("format-url") version = fp.attrs.get("format-version") if url is None or version is None: return False, {} if url != "http://biom-format.org": return False, {} if list(version) != [2, 1]: return False, {} return True, {} else: return False, {} @biom.reader(Table) def _biom_to_table_into(fh, cls=None): return _biom_to_table(fh) @biom.reader(None) def _biom_to_table_default(fh, cls=None): # skbio.read('foo.biom', format='biom') # will return a generator, that subsequently iterates the table. # returning a single item tuple yields expected behavior such that: # next(skbio.read('foo.biom', format='biom')) == Table return (_biom_to_table(fh),) def _biom_to_table(fh): h5grp = h5py.File(fh, "r") return Table.from_hdf5(h5grp) @biom.writer(Table) def _sktable_to_biom(obj, fh): _table_to_biom(obj, fh) def _table_to_biom(obj, fh): # h5py needs a file path, not a file handle if hasattr(fh, "name"): fp = fh.name else: fp = fh with h5py.File(fp, "w") as h5grp: obj.to_hdf5(h5grp, f"Written by scikit-bio version {skbio.__version__}") scikit-bio-scikit-bio-a3beaa6/skbio/io/format/blast6.py000066400000000000000000000306521520735541300231340ustar00rootroot00000000000000r"""BLAST+6 format (:mod:`skbio.io.format.blast6`) ============================================== .. currentmodule:: skbio.io.format.blast6 The BLAST+6 format (``blast+6``) stores the results of a BLAST [1]_ database search. The results are stored in a simple tabular format with no column headers. Values are separated by the tab character. An example BLAST+6-formatted file comparing two protein sequences, taken from [2]_ (tab characters represented by ````):: moaCgi|15800534|ref|NP_286546.1|100.0016100 116111613e-114330 moaCgi|170768970|ref|ZP_02903423.1|99.3816110 116111619e-114329 Format Support -------------- **Has Sniffer: No** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |No |:mod:`pandas.DataFrame` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- BLAST+6 format is a tabular text-based format produced by both BLAST+ output format 6 (``-outfmt 6``) and legacy BLAST output format 8 (``-m 8``). It is tab-separated and has no column headers. With BLAST+, users can specify the columns that are present in their BLAST output file by specifying column names (e.g., ``-outfmt "6 qseqid sseqid bitscore qstart sstart"``), if the default columns output by BLAST are not desired. BLAST Column Types ^^^^^^^^^^^^^^^^^^ The following column types are output by BLAST and supported by scikit-bio. This information is taken from [3]_. +-----------+------------------------------------+-----+ |Name |Description |Type | +===========+====================================+=====+ |qseqid |Query Seq-id |str | +-----------+------------------------------------+-----+ |qgi |Query GI |int | +-----------+------------------------------------+-----+ |qacc |Query accesion |str | +-----------+------------------------------------+-----+ |qaccver |Query accesion.version |str | +-----------+------------------------------------+-----+ |qlen |Query sequence length |int | +-----------+------------------------------------+-----+ |sseqid |Subject Seq-id |str | +-----------+------------------------------------+-----+ |sallseqid |All subject Seq-id(s), separated by |str | | |a ';' | | +-----------+------------------------------------+-----+ |sgi |Subject GI |int | +-----------+------------------------------------+-----+ |sallgi |All subject GIs |int | +-----------+------------------------------------+-----+ |sacc |Subject accesion |str | +-----------+------------------------------------+-----+ |saccver |Subject accesion.version |str | +-----------+------------------------------------+-----+ |sallacc |All subject accesions |str | +-----------+------------------------------------+-----+ |slen |Subject sequence length |int | +-----------+------------------------------------+-----+ |qstart |Start of alignment in query |int | +-----------+------------------------------------+-----+ |qend |End of alignment in query |int | +-----------+------------------------------------+-----+ |sstart |Start of alignment in subject |int | +-----------+------------------------------------+-----+ |send |End of alignment in subject |int | +-----------+------------------------------------+-----+ |qseq |Aligned part of query sequence |str | +-----------+------------------------------------+-----+ |sseq |Aligned part of subject sequence |str | +-----------+------------------------------------+-----+ |evalue |Expect value |float| +-----------+------------------------------------+-----+ |bitscore |Bit score |float| +-----------+------------------------------------+-----+ |score |Raw score |int | +-----------+------------------------------------+-----+ |length |Alignment length |int | +-----------+------------------------------------+-----+ |pident |Percent of identical matches |float| +-----------+------------------------------------+-----+ |nident |Number of identical matches |int | +-----------+------------------------------------+-----+ |mismatch |Number of mismatches |int | +-----------+------------------------------------+-----+ |positive |Number of positive-scoring matches |int | +-----------+------------------------------------+-----+ |gapopen |Number of gap openings |int | +-----------+------------------------------------+-----+ |gaps |Total number of gaps |int | +-----------+------------------------------------+-----+ |ppos |Percentage of positive-scoring |float| | |matches | | +-----------+------------------------------------+-----+ |frames |Query and subject frames separated |str | | |by a '/' | | +-----------+------------------------------------+-----+ |qframe |Query frame |int | +-----------+------------------------------------+-----+ |sframe |Subject frame |int | +-----------+------------------------------------+-----+ |btop |Blast traceback operations (BTOP) |int | +-----------+------------------------------------+-----+ |staxids |Unique Subject Taxonomy ID(s), |str | | |separated by a ';' (in numerical | | | |order). | | +-----------+------------------------------------+-----+ |sscinames |Unique Subject Scientific Name(s), |str | | |separated by a ';' | | +-----------+------------------------------------+-----+ |scomnames |Unique Subject Common Name(s), |str | | |separated by a ';' | | +-----------+------------------------------------+-----+ |sblastnames|unique Subject Blast Name(s), |str | | |separated by a ';' (in alphabetical | | | |order) | | +-----------+------------------------------------+-----+ |sskingdoms |unique Subject Super Kingdom(s), |str | | |separated by a ';' (in alphabetical | | | |order) | | +-----------+------------------------------------+-----+ |stitle |Subject Title |str | +-----------+------------------------------------+-----+ |sstrand |Subject Strand |str | +-----------+------------------------------------+-----+ |salltitles |All Subject Title(s), separated by |str | | |a '<>' | | +-----------+------------------------------------+-----+ |qcovs |Query Coverage Per Subject |int | +-----------+------------------------------------+-----+ |qcovhsp |Query Coverage Per HSP |int | +-----------+------------------------------------+-----+ .. note:: When a BLAST+6-formatted file contains ``N/A`` values, scikit-bio will convert these values into ``np.nan``, matching pandas' convention for representing missing data. .. note:: scikit-bio stores columns of type ``int`` as type ``float`` in the returned ``pd.DataFrame``. This is necessary in order to allow ``N/A`` values in integer columns (this is currently a limitation of pandas). Format Parameters ----------------- The following format parameters are available in ``blast+6`` format: - ``default_columns``: ``False`` by default. If ``True``, will use the default columns output by BLAST, which are qseqid, sseqid, pident, length, mismatch, gapopen, qstart, qend, sstart, send, evalue, and bitscore. .. warning:: When reading legacy BLAST files, you must pass ``default_columns=True`` because legacy BLAST does not allow users to specify which columns are present in the output file. - ``columns``: ``None`` by default. If provided, must be a list of column names in the order they will appear in the file. .. note:: Either ``default_columns`` or ``columns`` must be provided, as ``blast+6`` does not contain column headers. Examples -------- Suppose we have a ``blast+6`` file with default columns: >>> from io import StringIO >>> import skbio.io >>> import pandas as pd >>> fs = '\n'.join([ ... 'moaC\tgi|15800534|ref|NP_286546.1|\t100.00\t161\t0\t0\t1\t161\t1\t161' ... '\t3e-114\t330', ... 'moaC\tgi|170768970|ref|ZP_02903423.1|\t99.38\t161\t1\t0\t1\t161\t1' ... '\t161\t9e-114\t329' ... ]) >>> fh = StringIO(fs) Read the file into a ``pd.DataFrame`` and specify that default columns should be used: >>> df = skbio.io.read(fh, format="blast+6", into=pd.DataFrame, ... default_columns=True) >>> df # doctest: +NORMALIZE_WHITESPACE qseqid sseqid pident length mismatch gapopen \ 0 moaC gi|15800534|ref|NP_286546.1| 100.00 161.0 0.0 0.0 1 moaC gi|170768970|ref|ZP_02903423.1| 99.38 161.0 1.0 0.0 qstart qend sstart send evalue bitscore 0 1.0 161.0 1.0 161.0 3.000000e-114 330.0 1 1.0 161.0 1.0 161.0 9.000000e-114 329.0 Suppose we have a ``blast+6`` file with user-supplied (non-default) columns: >>> from io import StringIO >>> import skbio.io >>> import pandas as pd >>> fs = '\n'.join([ ... 'moaC\t100.00\t0\t161\t0\t161\t330\t1', ... 'moaC\t99.38\t1\t161\t0\t161\t329\t1' ... ]) >>> fh = StringIO(fs) Read the file into a ``pd.DataFrame`` and specify which columns are present in the file: >>> df = skbio.io.read(fh, format="blast+6", into=pd.DataFrame, ... columns=['qseqid', 'pident', 'mismatch', 'length', ... 'gapopen', 'qend', 'bitscore', 'sstart']) >>> df # doctest: +NORMALIZE_WHITESPACE qseqid pident mismatch length gapopen qend bitscore sstart 0 moaC 100.00 0.0 161.0 0.0 161.0 330.0 1.0 1 moaC 99.38 1.0 161.0 0.0 161.0 329.0 1.0 References ---------- .. [1] Altschul, S.F., Gish, W., Miller, W., Myers, E.W. & Lipman, D.J. (1990) "Basic local alignment search tool." J. Mol. Biol. 215:403-410. .. [2] http://blastedbio.blogspot.com/2014/11/column-headers-in-blast-tabular-\ and-csv.html .. [3] http://www.ncbi.nlm.nih.gov/books/NBK279675/ """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import pandas as pd from skbio.io import create_format from skbio.io.format._blast import _parse_blast_data, _possible_columns blast6 = create_format("blast+6") _default_columns = [ "qseqid", "sseqid", "pident", "length", "mismatch", "gapopen", "qstart", "qend", "sstart", "send", "evalue", "bitscore", ] @blast6.reader(pd.DataFrame) def _blast6_to_data_frame(fh, cls=None, columns=None, default_columns=False): if default_columns and columns is not None: raise ValueError("`columns` and `default_columns` cannot both be provided.") if not default_columns and columns is None: raise ValueError("Either `columns` or `default_columns` must be provided.") if default_columns: columns = _default_columns else: for column in columns: if column not in _possible_columns: raise ValueError( "Unrecognized column (%r)." " Supported columns:\n%r" % (column, set(_possible_columns.keys())) ) return _parse_blast_data( fh, columns, ValueError, "Specified number of columns (%r) does not equal" " number of columns in file (%r).", ) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/blast7.py000066400000000000000000000345421520735541300231370ustar00rootroot00000000000000"""BLAST+7 format (:mod:`skbio.io.format.blast7`) ============================================== .. currentmodule:: skbio.io.format.blast7 The BLAST+7 format (``blast+7``) stores the results of a BLAST [1]_ database search. This format is produced by both BLAST+ output format 7 and legacy BLAST output format 9. The results are stored in a simple tabular format with headers. Values are separated by the tab character. An example BLAST+7-formatted file comparing two nucleotide sequences, taken from [2]_ (tab characters represented by ````): .. code-block:: none # BLASTN 2.2.18+ # Query: gi|1786181|gb|AE000111.1|AE000111 # Subject: ecoli # Fields: query acc., subject acc., evalue, q. start, q. end, s. st\ art, s. end # 5 hits found AE000111AE0001110.0110596110596 AE000111AE0001748e-305565567169286821 AE000111AE0003941e-2755875671135219 AE000111AE0004256e-265587567185528468 AE000111AE0001713e-245587567122142130 Format Support ============== **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |No |:mod:`pandas.DataFrame` | +------+------+---------------------------------------------------------------+ Format Specification ==================== There are two BLAST+7 file formats supported by scikit-bio: BLAST+ output format 7 (``-outfmt 7``) and legacy BLAST output format 9 (``-m 9``). Both file formats are structurally similar, with minor differences. Example BLAST+ output format 7 file:: # BLASTP 2.2.31+ # Query: query1 # Subject: subject2 # Fields: q. start, q. end, s. start, s. end, identical, mismatches, sbjct\ frame, query acc.ver, subject acc.ver # 2 hits found 1 8 3 10 8 0 1 query1 subject2 2 5 2 15 8 0 2 query1 subject2 .. note:: Database searches without hits may occur in BLAST+ output format 7 files. scikit-bio ignores these "empty" records: .. code-block:: none # BLASTP 2.2.31+ # Query: query1 # Subject: subject1 # 0 hits found Example legacy BLAST output format 9 file: .. code-block:: none # BLASTN 2.2.3 [May-13-2002] # Database: other_vertebrate # Query: AF178033 # Fields: Query id,Subject id,% identity,alignment length,mismatches,gap openings,q.\ start,q. end,s. start,s. end,e-value,bit score AF178033 EMORG:AF178033 100.00 811 0 0 1 811 1 811 0.0 1566.6 AF178033 EMORG:AF031394 99.63 811 3 0 1 811 99 909 0.0 1542.8 .. note:: scikit-bio requires fields to be consistent within a file. BLAST Column Types ------------------ The following column types are output by BLAST and supported by scikit-bio. For more information on these column types, see :mod:`skbio.io.format.blast6`. +-------------------+----------------------+ |Field Name |DataFrame Column Name | +===================+======================+ |query id |qseqid | +-------------------+----------------------+ |query gi |qgi | +-------------------+----------------------+ |query acc. |qacc | +-------------------+----------------------+ |query acc.ver |qaccver | +-------------------+----------------------+ |query length |qlen | +-------------------+----------------------+ |subject id |sseqid | +-------------------+----------------------+ |subject ids |sallseqid | +-------------------+----------------------+ |subject gi |sgi | +-------------------+----------------------+ |subject gis |sallgi | +-------------------+----------------------+ |subject acc. |sacc | +-------------------+----------------------+ |subject acc.ver |saccver | +-------------------+----------------------+ |subject accs |sallacc | +-------------------+----------------------+ |subject length |slen | +-------------------+----------------------+ |q\\. start |qstart | +-------------------+----------------------+ |q\\. end |qend | +-------------------+----------------------+ |s\\. start |sstart | +-------------------+----------------------+ |s\\. end |send | +-------------------+----------------------+ |query seq |qseq | +-------------------+----------------------+ |subject seq |sseq | +-------------------+----------------------+ |evalue |evalue | +-------------------+----------------------+ |bit score |bitscore | +-------------------+----------------------+ |score |score | +-------------------+----------------------+ |alignment length |length | +-------------------+----------------------+ |% identity |pident | +-------------------+----------------------+ |identical |nident | +-------------------+----------------------+ |mismatches |mismatch | +-------------------+----------------------+ |positives |positive | +-------------------+----------------------+ |gap opens |gapopen | +-------------------+----------------------+ |gaps |gaps | +-------------------+----------------------+ |% positives |ppos | +-------------------+----------------------+ |query/sbjct frames |frames | +-------------------+----------------------+ |query frame |qframe | +-------------------+----------------------+ |sbjct frame |sframe | +-------------------+----------------------+ |BTOP |btop | +-------------------+----------------------+ |subject tax ids |staxids | +-------------------+----------------------+ |subject sci names |sscinames | +-------------------+----------------------+ |subject com names |scomnames | +-------------------+----------------------+ |subject blast names|sblastnames | +-------------------+----------------------+ |subject super |sskingdoms | |kingdoms | | +-------------------+----------------------+ |subject title |stitle | +-------------------+----------------------+ |subject strand |sstrand | +-------------------+----------------------+ |subject titles |salltitles | +-------------------+----------------------+ |% query coverage |qcovs | |per subject | | +-------------------+----------------------+ |% query coverage |qcovhsp | |per hsp | | +-------------------+----------------------+ Examples -------- Suppose we have a BLAST+7 file: >>> from io import StringIO >>> import skbio.io >>> import pandas as pd >>> fs = '\\n'.join([ ... '# BLASTN 2.2.18+', ... '# Query: gi|1786181|gb|AE000111.1|AE000111', ... '# Database: ecoli', ... '# Fields: query acc., subject acc., evalue, q. start, q. end, s. st\ art, s. end', ... '# 5 hits found', ... 'AE000111\\tAE000111\\t0.0\\t1\\t10596\\t1\\t10596', ... 'AE000111\\tAE000174\\t8e-30\\t5565\\t5671\\t6928\\t6821', ... 'AE000111\\tAE000171\\t3e-24\\t5587\\t5671\\t2214\\t2130', ... 'AE000111\\tAE000425\\t6e-26\\t5587\\t5671\\t8552\\t8468' ... ]) >>> fh = StringIO(fs) Read the file into a ``pd.DataFrame``: >>> df = skbio.io.read(fh, into=pd.DataFrame) >>> df # doctest: +NORMALIZE_WHITESPACE qacc sacc evalue qstart qend sstart send 0 AE000111 AE000111 0.000000e+00 1.0 10596.0 1.0 10596.0 1 AE000111 AE000174 8.000000e-30 5565.0 5671.0 6928.0 6821.0 2 AE000111 AE000171 3.000000e-24 5587.0 5671.0 2214.0 2130.0 3 AE000111 AE000425 6.000000e-26 5587.0 5671.0 8552.0 8468.0 Suppose we have a legacy BLAST 9 file: >>> from io import StringIO >>> import skbio.io >>> import pandas as pd >>> fs = '\\n'.join([ ... '# BLASTN 2.2.3 [May-13-2002]', ... '# Database: other_vertebrate', ... '# Query: AF178033', ... '# Fields: ', ... 'Query id,Subject id,% identity,alignment length,mismatches,gap openin\ gs,q. start,q. end,s. start,s. end,e-value,bit score', ... 'AF178033\\tEMORG:AF178033\\t100.00\\t811\\t0\\t0\\t1\\t811\\t1\\t81\ 1\\t0.0\\t1566.6', ... 'AF178033\\tEMORG:AF178032\\t94.57\\t811\\t44\\t0\\t1\\t811\\t1\\t81\ 1\\t0.0\\t1217.7', ... 'AF178033\\tEMORG:AF178031\\t94.82\\t811\\t42\\t0\\t1\\t811\\t1\\t81\ 1\\t0.0\\t1233.5' ... ]) >>> fh = StringIO(fs) Read the file into a ``pd.DataFrame``: >>> df = skbio.io.read(fh, into=pd.DataFrame) >>> df[['qseqid', 'sseqid', 'pident']] # doctest: +NORMALIZE_WHITESPACE qseqid sseqid pident 0 AF178033 EMORG:AF178033 100.00 1 AF178033 EMORG:AF178032 94.57 2 AF178033 EMORG:AF178031 94.82 References ---------- .. [1] Altschul, S.F., Gish, W., Miller, W., Myers, E.W. & Lipman, D.J. (1990) "Basic local alignment search tool." J. Mol. Biol. 215:403-410. .. [2] http://www.ncbi.nlm.nih.gov/books/NBK279682/ """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import pandas as pd from skbio.io import create_format, BLAST7FormatError from skbio.io.format._blast import _parse_blast_data blast7 = create_format("blast+7") column_converter = { "query id": "qseqid", "query gi": "qgi", "query acc.": "qacc", "query acc.ver": "qaccver", "query length": "qlen", "subject id": "sseqid", "subject ids": "sallseqid", "subject gi": "sgi", "subject gis": "sallgi", "subject acc.": "sacc", "subject acc.ver": "saccver", "subject accs.": "sallacc", "subject length": "slen", "q. start": "qstart", "q. end": "qend", "s. start": "sstart", "s. end": "send", "query seq": "qseq", "subject seq": "sseq", "evalue": "evalue", "bit score": "bitscore", "score": "score", "alignment length": "length", "% identity": "pident", "identical": "nident", "mismatches": "mismatch", "positives": "positive", "gap opens": "gapopen", "gaps": "gaps", "% positives": "ppos", "query/sbjct frames": "frames", "query frame": "qframe", "sbjct frame": "sframe", "BTOP": "btop", "subject tax ids": "staxids", "subject sci names": "sscinames", "subject com names": "scomnames", "subject blast names": "sblastnames", "subject super kingdoms": "sskingdoms", "subject title": "stitle", "subject titles": "salltitles", "subject strand": "sstrand", "% query coverage per subject": "qcovs", "% query coverage per hsp": "qcovhsp", "Query id": "qseqid", "Subject id": "sseqid", "gap openings": "gapopen", "e-value": "evalue", } @blast7.sniffer() def _blast7_sniffer(fh): # Smells a BLAST+7 file if the following conditions are present # -First line contains "BLAST" # -Second line contains "Query" or "Database" # -Third line starts with "Subject" or "Query" or "Database" lines = [line for _, line in zip(range(3), fh)] if len(lines) < 3: return False, {} if not lines[0].startswith("# BLAST"): return False, {} if not (lines[1].startswith("# Query:") or lines[1].startswith("# Database:")): return False, {} if not ( lines[2].startswith("# Subject:") or lines[2].startswith("# Query:") or lines[2].startswith("# Database:") ): return False, {} return True, {} @blast7.reader(pd.DataFrame) def _blast7_to_data_frame(fh, cls=None): line_num = 0 columns = None skiprows = [] for line in fh: if line == "# Fields: \n": # Identifies Legacy BLAST 9 data line = next(fh) line_num += 1 if columns is None: columns = _parse_fields(line, legacy=True) skiprows.append(line_num) else: next_columns = _parse_fields(line, legacy=True) if columns != next_columns: raise BLAST7FormatError( "Fields %r do not equal fields %r" % (columns, next_columns) ) skiprows.append(line_num) elif line.startswith("# Fields: "): # Identifies BLAST+7 data if columns is None: columns = _parse_fields(line) else: # Affirms data types do not differ throught file next_columns = _parse_fields(line) if columns != next_columns: raise BLAST7FormatError( "Fields %r do not equal fields %r" % (columns, next_columns) ) line_num += 1 if columns is None: # Affirms file contains BLAST data raise BLAST7FormatError("File contains no BLAST data.") fh.seek(0) return _parse_blast_data( fh, columns, BLAST7FormatError, "Number of fields (%r) does not equal number of data columns (%r).", comment="#", skiprows=skiprows, ) def _parse_fields(line, legacy=False): r"""Remove '\n' from fields line and returns fields as a list (columns).""" line = line.rstrip("\n") if legacy: fields = line.split(",") else: line = line.split("# Fields: ")[1] fields = line.split(", ") columns = [] for field in fields: if field not in column_converter: raise BLAST7FormatError( "Unrecognized field (%r)." " Supported fields: %r" % (field, set(column_converter.keys())) ) columns.append(column_converter[field]) return columns scikit-bio-scikit-bio-a3beaa6/skbio/io/format/clustal.py000066400000000000000000000300741520735541300234060ustar00rootroot00000000000000r"""Clustal format (:mod:`skbio.io.format.clustal`) =============================================== .. currentmodule:: skbio.io.format.clustal Clustal format (``clustal``) stores multiple sequence alignments. This format was originally introduced in the Clustal package [1]_. Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.alignment.TabularMSA` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- A clustal-formatted file is a plain text format. It can optionally have a header, which states the clustal version number. This is followed by the multiple sequence alignment, and optional information about the degree of conservation at each position in the alignment [2]_. Alignment Section ^^^^^^^^^^^^^^^^^ Each sequence in the alignment is divided into subsequences each at most 60 characters long. The sequence identifier for each sequence precedes each subsequence. Each subsequence can optionally be followed by the cumulative number of non-gap characters up to that point in the full sequence (not included in the examples below). A line containing conservation information about each position in the alignment can optionally follow all of the subsequences (not included in the examples below). .. note:: scikit-bio ignores conservation information when reading and does not support writing conservation information. .. note:: When reading a clustal-formatted file into an ``skbio.alignment.TabularMSA`` object, sequence identifiers/labels are stored as ``TabularMSA`` index labels (``index`` property). When writing an ``skbio.alignment.TabularMSA`` object as a clustal-formatted file, ``TabularMSA`` index labels will be converted to strings and written as sequence identifiers/labels. Format Parameters ----------------- The only supported format parameter is ``constructor``, which specifies the type of in-memory sequence object to read each aligned sequence into. This must be a subclass of ``GrammaredSequence`` (e.g., ``DNA``, ``RNA``, ``Protein``) and is a required format parameter. For example, if you know that the clustal file you're reading contains DNA sequences, you would pass ``constructor=DNA`` to the reader call. Examples -------- Assume we have a clustal-formatted file of RNA sequences: .. code-block:: none CLUSTAL W (1.82) multiple sequence alignment abc GCAUGCAUCUGCAUACGUACGUACGCAUGCAUCA def ---------------------------------- xyz ---------------------------------- abc GUCGAUACAUACGUACGUCGUACGUACGU-CGAC def ---------------CGCGAUGCAUGCAU-CGAU xyz -----------CAUGCAUCGUACGUACGCAUGAC We can use the following code to read the clustal file into a ``TabularMSA``: >>> from skbio import TabularMSA, RNA >>> clustal_f = ['CLUSTAL W (1.82) multiple sequence alignment\n', ... '\n', ... 'abc GCAUGCAUCUGCAUACGUACGUACGCAUGCA\n', ... 'def -------------------------------\n', ... 'xyz -------------------------------\n', ... '\n', ... 'abc GUCGAUACAUACGUACGUCGGUACGU-CGAC\n', ... 'def ---------------CGUGCAUGCAU-CGAU\n', ... 'xyz -----------CAUUCGUACGUACGCAUGAC\n'] >>> msa = TabularMSA.read(clustal_f, constructor=RNA) >>> msa TabularMSA[RNA] -------------------------------------------------------------- Stats: sequence count: 3 position count: 62 -------------------------------------------------------------- GCAUGCAUCUGCAUACGUACGUACGCAUGCAGUCGAUACAUACGUACGUCGGUACGU-CGAC ----------------------------------------------CGUGCAUGCAU-CGAU ------------------------------------------CAUUCGUACGUACGCAUGAC >>> msa.index # doctest: +ELLIPSIS Index(['abc', 'def', 'xyz'], dtype='...') We can use the following code to write a ``TabularMSA`` to a clustal-formatted file: >>> from io import StringIO >>> from skbio import DNA >>> seqs = [DNA('ACCGTTGTA-GTAGCT', metadata={'id': 'seq1'}), ... DNA('A--GTCGAA-GTACCT', metadata={'id': 'sequence-2'}), ... DNA('AGAGTTGAAGGTATCT', metadata={'id': '3'})] >>> msa = TabularMSA(seqs, minter='id') >>> msa TabularMSA[DNA] ---------------------- Stats: sequence count: 3 position count: 16 ---------------------- ACCGTTGTA-GTAGCT A--GTCGAA-GTACCT AGAGTTGAAGGTATCT >>> msa.index # doctest: +ELLIPSIS Index(['seq1', 'sequence-2', '3'], dtype='...') >>> fh = StringIO() >>> _ = msa.write(fh, format='clustal') >>> print(fh.getvalue()) # doctest: +NORMALIZE_WHITESPACE CLUSTAL seq1 ACCGTTGTA-GTAGCT sequence-2 A--GTCGAA-GTACCT 3 AGAGTTGAAGGTATCT References ---------- .. [1] http://www.sciencedirect.com/science/article/pii/0378111988903307 .. [2] http://web.mit.edu/meme_v4.9.0/doc/clustalw-format.html """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from skbio.io import create_format, ClustalFormatError from skbio.alignment import TabularMSA clustal = create_format("clustal") def _label_line_parser(record): """Return dict mapping list of data to labels, plus list with field order. Field order contains labels in order encountered in file. NOTE: doesn't care if lines are out of order in different blocks. This should never happen anyway, but it's possible that this behavior should be changed to tighten up validation. """ labels = [] result = {} for line in record: split_line = line.strip().rsplit(None, 1) if len(split_line) == 2: key, val = split_line else: raise ClustalFormatError( "Failed to parse sequence identifier and subsequence from " "the following line: %r" % line ) if key in result: result[key].append(val) else: result[key] = [val] labels.append(key) return result, labels def _is_clustal_seq_line(line): """Return True if line starts with a non-blank character but not 'CLUSTAL'. Useful for filtering other lines out of the file. """ return ( line and (not line[0].isspace()) and (not line.startswith("CLUSTAL")) and (not line.startswith("MUSCLE")) ) def _delete_trailing_number(line): """Delete trailing number from a line. WARNING: does not preserve internal whitespace when a number is removed! (converts each whitespace run to a single space). Returns the original line if it didn't end in a number. """ pieces = line.split() try: int(pieces[-1]) return " ".join(pieces[:-1]) except ValueError: # no trailing numbers return line def _check_length(data, labels, num_seqs_check=None): """Check that the lengths of the clustal sequences line up correctly. num_seqs_check: The number of sequences to check Return True if all of the subsequence lengths are equal or if data is empty Return False if one of the subsequence lengths differs """ if len(labels) == 0: return True num_subseqs = len(data[labels[0]]) if num_seqs_check is None: num_seqs_check = num_subseqs else: if num_seqs_check > num_subseqs: num_seqs_check = num_subseqs subseq_length = len(data[labels[0]][0]) end_lengths = set() # subsequence lengths at end of file for i in range(num_seqs_check): for label in labels: seq = data[label][i] if len(seq) > subseq_length: return False elif i + 1 == num_subseqs: # Last subsequence end_lengths.add(len(seq)) elif len(seq) < subseq_length: return False # All trailing subsequences must be the same if len(end_lengths) > 1: return False return True @clustal.sniffer() def _clustal_sniffer(fh): # Strategy # The following conditions preclude a file from being clustal # * It is an empty file # * The whole sequences have differing lengths # * The sub-sequences have differing lengths # * One of the sequence ids is not immediately # followed by a subsequence empty = True if fh.read(7) != "CLUSTAL": return False, {} fh.seek(0) try: records = map(_delete_trailing_number, filter(_is_clustal_seq_line, fh)) data, labels = _label_line_parser(records) if len(data) > 0: empty = False # Only check first 50 sequences aligned_correctly = _check_length(data, labels, 50) if not aligned_correctly: raise ClustalFormatError("Sequences not aligned properly") except ClustalFormatError: return False, {} return not empty, {} @clustal.writer(TabularMSA) def _tabular_msa_to_clustal(obj, fh): if not obj.index.is_unique: raise ClustalFormatError("TabularMSA's index labels must be unique.") clen = 60 # Max length of clustal lines seqs = [str(s) for s in obj] names = [str(label) for label in obj.index] nameLen = max(map(len, names)) seqLen = max(map(len, seqs)) fh.write("CLUSTAL\n\n\n") for i in range(0, seqLen, clen): for label, seq in zip(names, seqs): name = ("{:<%d}" % (nameLen)).format(label) fh.write("%s\t%s\n" % (name, seq[i : i + clen])) fh.write("\n") @clustal.reader(TabularMSA) def _clustal_to_tabular_msa(fh, cls=None, constructor=None): r"""Yield labels and sequences from msa (multiple sequence alignment). Parameters ---------- fh : open file object An open Clustal file. constructor : callable, optional A callable object that constructs sequences. Returns ------- skbio.TabularMSA MSA containing aligned sequences. Raises ------ skbio.util.exception.ClustalFormatError If the sequences in `fh` don't have the same sequence length or if the sequence ids don't properly match with the subsequences Notes ----- Skips any line that starts with a blank. ``_clustal_to_tabular_msa`` preserves the order of the sequences from the original file. However, it does use a dict as an intermediate, so two sequences can't have the same label. This is probably OK since Clustal will refuse to run on a FASTA file in which two sequences have the same label, but could potentially cause trouble with manually edited files (all the segments of the conflicting sequences would be interleaved, possibly in an unpredictable way). If the lines have trailing numbers (i.e. Clustal was run with `-LINENOS=ON`), silently deletes them. Does not check that the numbers actually correspond to the number of chars in the sequence printed so far. References ---------- .. [1] Thompson JD, Higgins DG, Gibson TJ, "CLUSTAL W: improving the sensitivity of progressive multiple sequence alignment through sequence weighting, position-specific gap penalties and weight matrix choice. Thompson", Nucleic Acids Res. 1994 Nov 11;22(22):4673-80. """ if cls is None: cls = TabularMSA if constructor is None: raise ValueError("Must provide `constructor`.") records = map(_delete_trailing_number, filter(_is_clustal_seq_line, fh)) data, labels = _label_line_parser(records) aligned_correctly = _check_length(data, labels) if not aligned_correctly: raise ClustalFormatError("Sequences not aligned properly") seqs = [] for label in labels: seqs.append(constructor("".join(data[label]), metadata={"id": label})) return cls(seqs, index=labels) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/embed.py000066400000000000000000000305031520735541300230100ustar00rootroot00000000000000r"""Embedding format (:mod:`skbio.io.format.embed`). ==================================================== .. currentmodule:: skbio.io.format.embed This module provides support for reading and writing embedding files that are outputted by sequential language models such as protein language models (pLMs). Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |generator of :mod:`skbio.embedding.ProteinEmbedding` objects | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.embedding.ProteinEmbedding` objects | +------+------+---------------------------------------------------------------+ |Yes |Yes |generator of :mod:`skbio.embedding.ProteinVector` objects | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.embedding.ProteinVector` objects | +------+------+---------------------------------------------------------------+ Format Specification -------------------- The format is a HDF5 file with the following structure: - ``embeddings`` (dataset) - ``embedding_ptr`` (dataset) - ``id`` (dataset) - ``idptr`` (dataset) - ``format`` (attribute) - ``format-version`` (attribute) - ``dtype`` (attribute) - ``dim`` (attribute) The `idptr` dataset contains the cumulative sum of the sequence lengths in the hdf5. This is used to index both the sequences and the embeddings in the hdf5, which can be useful for iterating through the embeddings and avoiding the need to load all of the embedding into memory. For protein embeddings the `id` is the original sequence used to generate the embeddings. The `embeddings` dataset contains the embeddings for each sequence, where the first dimension is the sequence length and the second dimension is the embedding dimension. The row vectors in the `embeddings` correspond to the residues of the sequence in the `id` dataset. The `embptr` is an optional dataset that is used in case the `id` length is different from the `embedding` length. This could be do to string formatting, for instance for dealing with protein vectors, the id is a full length sequence, not a single residue. The `emdptr` is used to separately keep track of the individual embeddings in these scenarios. The format attribute is a string that specifies the format of the embedding. If the ``format`` attribute is present and has the value of `embed`, then the file is a valid embedding file. The `format-version` attribute is a string that specifies the version of the format. The `dtype` attribute is a string that specifies the data type of the embeddings. Currently supported dtypes include `float32` or `float64`. The `dim` attribute is an integer that specifies the dimensionality of the embeddings. The `embed` format currently does not support storing embeddings with different dimensionality in the same file. Examples -------- Here we will read in an example protein embedding file and write it back out. Note that the embedding from implicitly gets the ``.write`` method from the IO registry. This ``ByteIO`` object can be a file path in a regular use case. >>> import io, skbio >>> f = io.BytesIO() >>> skbio.embedding.example_protein_embedding.write(f) # doctest: +ELLIPSIS <_io.BytesIO object at ...> >>> roundtrip = skbio.read(f, into=skbio.ProteinEmbedding) >>> roundtrip ProteinEmbedding -------------------------------------------------------------------- Stats: length: 62 embedding dimension: 1024 has gaps: False has degenerates: False has definites: True has stops: False -------------------------------------------------------------------- 0 IGKEEIQQRL AQFVDHWKEL KQLAAARGQR LEESLEYQQF VANVEEEEAW INEKMTLVAS 60 ED """ import numpy as np from math import ceil import h5py from skbio.io import create_format from skbio.embedding._protein import ProteinEmbedding from skbio.embedding._protein import ProteinVector from skbio.sequence import Protein embed = create_format("embed", encoding="binary") @embed.sniffer() def _embed_sniffer(fh): # this can be buffered, in which case .peek will return the buffer # so slice just in case magic = fh.peek(8)[:8] # From https://en.wikipedia.org/wiki/Hierarchical_Data_Format # Note that Wikipedia specifies: "\211HDF\r\n\032\n" which is an ordinal form: # >>> ord('\211') # 137 # >>> ord('\x89') # 137 # >>> ord('\032') # 26 # >>> ord('\x1a') # 26 if magic == b"\x89HDF\r\n\x1a\n": with h5py.File(fh, "r") as h5file: if "embedding" in h5file and "id" in h5file and "idptr" in h5file: return True, {} return False, {} @embed.reader(None) def _embed_to_generator( fh, cls=None, constructor=ProteinEmbedding, obj_constructor=Protein, kwargs: dict = {}, ): h5grp = h5py.File(fh, "r") embed_fh = h5grp["embedding"] id_fh = h5grp["id"] idptr_fh = h5grp["idptr"] has_embedding_ptr = "embedding_ptr" in h5grp if has_embedding_ptr: embptr_fh = h5grp["embedding_ptr"] j, k = 0, 0 n = idptr_fh.shape[0] for i in range(n): idptr = idptr_fh[i] id_ = id_fh[j:idptr] if has_embedding_ptr: embptr = embptr_fh[i] emb = embed_fh[k:embptr] else: emb = embed_fh[j:idptr] string = str(id_.tobytes().decode("ascii")) j = idptr k = embptr if has_embedding_ptr else None # type: ignore[assignment] yield constructor(emb, string, **kwargs) def _embed_to_object( fh, constructor=ProteinEmbedding, obj_constructor=Protein, kwargs: dict = {}, ): h5grp = h5py.File(fh, "r") embed_fh = h5grp["embedding"] id_fh = h5grp["id"] # assumes that there is only a single object in the file emb = np.array(embed_fh[:]) id_ = id_fh[()] string = str(id_.tobytes().decode("ascii")) return constructor(emb, string, **kwargs) @embed.reader(ProteinEmbedding) def _embed_to_protein( fh, cls=None, kwargs: dict = {}, ): if cls is None: cls = ProteinEmbedding return _embed_to_object( fh, constructor=cls, obj_constructor=Protein, kwargs=kwargs, ) @embed.reader(ProteinVector) def _vector_to_protein( fh, kwargs: dict = {}, ): return _embed_to_object( fh, constructor=ProteinVector, obj_constructor=Protein, kwargs=kwargs, ) def _objects_to_embed(objs, fh, include_embedding_pointer=True): with h5py.File(fh, "w") as h5grp: h5grp.attrs["format"] = "embedding" h5grp.attrs["format-version"] = "1.0" max_idsize = 1 max_embsize = 1 resize_by = 1.38 resize = False for i, obj in enumerate(objs): # store string representation of the object # that will serve as an identifier for the entire object. # for sequences, this could be the sequence itself # for molecules, this could be the SMILES string. # The entries in this string representation can be used # to index the row vectors in the embedding. # For sequences, this is the positional index of the sequence. # For molecules, this is the position index of atoms in the SMILES string. arr = obj.bytes() # Store the embedding itself. We are assuming that the # embbedding is a 2D numpy array emb = obj.embedding dtype = emb.dtype if "dtype" not in h5grp.attrs: h5grp.attrs["dtype"] = dtype.name if "dim" not in h5grp.attrs: h5grp.attrs["dim"] = emb.shape[1] # resizing if necessary if i > 0: # we don't need to resize for the first object if include_embedding_pointer: # Checking 4 conditions for possible resize: # if (new ID/embs + old ID/embs) > max_size if ( (len(arr) + idptr_fh[i - 1]) >= max_idsize or (emb.shape[0] + embptr_fh[i - 1]) >= max_embsize or ( i >= len(idptr_fh) or ( # check if adding obj exceeds id array size i >= embptr_fh.shape[0] ) ) ): # check if adding obj exceeds embedding array size max_idsize = ceil((len(arr) + idptr_fh[i - 1]) * resize_by) max_embsize = ceil( (emb.shape[0] + embptr_fh[i - 1]) * resize_by ) resize = True else: # only check ID size conditions if len(arr) + idptr_fh[i - 1] > max_idsize or i >= len(idptr_fh): max_idsize = ceil((len(arr) + idptr_fh[i - 1] * resize_by)) resize = True # store the pointers that keep track of the start and # end of the embedding for each object, as well as well as # the corresponding string representation if "idptr" in h5grp: idptr_fh = h5grp["idptr"] if resize: idptr_fh.resize((ceil(i * resize_by),)) idptr_fh[i] = len(arr) + idptr_fh[i - 1] else: idptr_fh = h5grp.create_dataset( "idptr", data=[len(arr)], maxshape=(None,), dtype=np.int32, compression="gzip", ) if "id" in h5grp: id_fh = h5grp["id"] if resize: id_fh.resize((max_idsize,)) id_fh[idptr_fh[i - 1] : idptr_fh[i]] = arr else: id_fh = h5grp.create_dataset( "id", data=arr, maxshape=(None,), dtype=np.uint8, compression="gzip" ) if include_embedding_pointer: if "embedding_ptr" in h5grp: embptr_fh = h5grp["embedding_ptr"] if resize: embptr_fh.resize((ceil(i * resize_by),)) embptr_fh[i] = emb.shape[0] + embptr_fh[i - 1] else: embptr_fh = h5grp.create_dataset( "embedding_ptr", data=[emb.shape[0]], maxshape=(None,), dtype=np.int32, ) if "embedding" in h5grp: embed_fh = h5grp["embedding"] assert embed_fh.shape[1] == emb.shape[1], ( "Embedding dimension mismatch between objects. " f"({embed_fh.shape}) and ({emb.shape})" ) if resize: embed_fh.resize(max_embsize, axis=0) if include_embedding_pointer: embed_fh[embptr_fh[i - 1] : embptr_fh[i]] = emb else: embed_fh[idptr_fh[i - 1] : idptr_fh[i]] = emb else: embed_fh = h5grp.create_dataset( "embedding", data=emb, maxshape=(None, emb.shape[1]), dtype=obj.embedding.dtype, compression="gzip", ) resize = False # resize the datasets to the actual number of objects max_idsize = idptr_fh[i] max_embsize = embptr_fh[i] if include_embedding_pointer else max_idsize id_fh.resize((max_idsize,)) idptr_fh.resize((i,)) embed_fh.resize(max_embsize, axis=0) if include_embedding_pointer: embptr_fh.resize((i,)) @embed.writer(None) def _generator_to_embed(objs, fh): return _objects_to_embed(objs, fh) @embed.writer(ProteinEmbedding) def _protein_to_embed(obj, fh): _objects_to_embed([obj], fh, include_embedding_pointer=False) @embed.writer(ProteinVector) def _protein_to_vector(obj, fh): _objects_to_embed([obj], fh, include_embedding_pointer=True) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/embl.py000066400000000000000000001524471520735541300226670ustar00rootroot00000000000000"""EMBL format (:mod:`skbio.io.format.embl`) ========================================= .. currentmodule:: skbio.io.format.embl EMBL format stores sequence and its annotation together. The start of the annotation section is marked by a line beginning with the word "ID". The start of sequence section is marked by a line beginning with the word "SQ". The "//" (terminator) line also contains no data or comments and designates the end of an entry. More information on EMBL file format can be found here [1]_. The EMBL file may end with .embl or .txt extension. An example of EMBL file can be seen here [2]_. Feature Level Products ^^^^^^^^^^^^^^^^^^^^^^ As described in [3]_ *"Feature-level products contain nucleotide sequence and related annotations derived from submitted ENA assembled and annotated sequences. Data are distributed in flatfile format, similar to that of parent ENA records, with each flatfile representing a single feature"*. While only the sequence of the feature is included in such entries, features are derived from the parent entry, and can't be applied as interval metadata. For such reason, interval metadata are ignored from Feature-level products, as they will be ignored by subsetting a generic Sequence object. Format Support -------------- **Has Sniffer: Yes** **NOTE: No protein support at the moment** Current protein support development is tracked in issue-1499 [4]_ +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.sequence.Sequence` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.DNA` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.RNA` | +------+------+---------------------------------------------------------------+ |No |No |:mod:`skbio.sequence.Protein` | +------+------+---------------------------------------------------------------+ |Yes |Yes | generator of :mod:`skbio.sequence.Sequence` objects | +------+------+---------------------------------------------------------------+ Format Specification -------------------- Sections before ``FH (Feature Header)`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ All the sections before ``FH (Feature Header)`` will be read into the attribute of ``metadata``. The header and its content of a section are stored as key-value pairs in ``metadata``. For the ``RN (Reference Number)`` section, its value is stored as a list, as there are often multiple reference sections in one EMBL record. ``FT`` section ^^^^^^^^^^^^^^ See :ref:`Genbank FEATURES section` ``SQ`` section ^^^^^^^^^^^^^^ The sequence in the ``SQ`` section is always in lowercase for the EMBL files downloaded from ENA. For the RNA molecules, ``t`` (thymine), instead of ``u`` (uracil) is used in the sequence. All EMBL writers follow these conventions while writing EMBL files. Examples -------- Reading EMBL Files ^^^^^^^^^^^^^^^^^^ Suppose we have the following EMBL file example: >>> embl_str = ''' ... ID X56734; SV 1; linear; mRNA; STD; PLN; 1859 BP. ... XX ... AC X56734; S46826; ... XX ... DT 12-SEP-1991 (Rel. 29, Created) ... DT 25-NOV-2005 (Rel. 85, Last updated, Version 11) ... XX ... DE Trifolium repens mRNA for non-cyanogenic beta-glucosidase ... XX ... KW beta-glucosidase. ... XX ... OS Trifolium repens (white clover) ... OC Eukaryota; Viridiplantae; Streptophyta; Embryophyta; Tracheophyta; ... OC Spermatophyta; Magnoliophyta; eudicotyledons; Gunneridae; ... OC Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; ... OC Trifolieae; Trifolium. ... XX ... RN [5] ... RP 1-1859 ... RX DOI; 10.1007/BF00039495. ... RX PUBMED; 1907511. ... RA Oxtoby E., Dunn M.A., Pancoro A., Hughes M.A.; ... RT "Nucleotide and derived amino acid sequence of the cyanogenic ... RT beta-glucosidase (linamarase) from white clover ... RT (Trifolium repens L.)"; ... RL Plant Mol. Biol. 17(2):209-219(1991). ... XX ... RN [6] ... RP 1-1859 ... RA Hughes M.A.; ... RT ; ... RL Submitted (19-NOV-1990) to the INSDC. ... RL Hughes M.A., University of Newcastle Upon Tyne, Medical School, ... RL Newcastle ... RL Upon Tyne, NE2 4HH, UK ... XX ... DR MD5; 1e51ca3a5450c43524b9185c236cc5cc. ... XX ... FH Key Location/Qualifiers ... FH ... FT source 1..1859 ... FT /organism="Trifolium repens" ... FT /mol_type="mRNA" ... FT /clone_lib="lambda gt10" ... FT /clone="TRE361" ... FT /tissue_type="leaves" ... FT /db_xref="taxon:3899" ... FT mRNA 1..1859 ... FT /experiment="experimental evidence, no additional ... FT details recorded" ... FT CDS 14..1495 ... FT /product="beta-glucosidase" ... FT /EC_number="3.2.1.21" ... FT /note="non-cyanogenic" ... FT /db_xref="GOA:P26204" ... FT /db_xref="InterPro:IPR001360" ... FT /db_xref="InterPro:IPR013781" ... FT /db_xref="InterPro:IPR017853" ... FT /db_xref="InterPro:IPR033132" ... FT /db_xref="UniProtKB/Swiss-Prot:P26204" ... FT /protein_id="CAA40058.1" ... FT /translation="MDFIVAIFALFVISSFTITSTNAVEASTLLDIGNLSRS ... FT SFPRGFIFGAGSSAYQFEGAVNEGGRGPSIWDTFTHKYPEKIRDGSNADITV ... FT DQYHRYKEDVGIMKDQNMDSYRFSISWPRILPKGKLSGGINHEGIKYYNNLI ... FT NELLANGIQPFVTLFHWDLPQVLEDEYGGFLNSGVINDFRDYTDLCFKEFGD ... FT RVRYWSTLNEPWVFSNSGYALGTNAPGRCSASNVAKPGDSGTGPYIVTHNQI ... FT LAHAEAVHVYKTKYQAYQKGKIGITLVSNWLMPLDDNSIPDIKAAERSLDFQ ... FT FGLFMEQLTTGDYSKSMRRIVKNRLPKFSKFESSLVNGSFDFIGINYYSSSY ... FT ISNAPSHGNAKPSYSTNPMTNISFEKHGIPLGPRAASIWIYVYPYMFIQEDF ... FT EIFCYILKINITILQFSITENGMNEFNDATLPVEEALLNTYRIDYYYRHLYY ... FT IRSAIRAGSNVKGFYAWSFLDCNEWFAGFTVRFGLNFVD" ... XX ... SQ Sequence 1859 BP; 609 A; 314 C; 355 G; 581 T; 0 other; ... aaacaaacca aatatggatt ttattgtagc catatttgct ctgtttgtta ttagctcatt ... cacaattact tccacaaatg cagttgaagc ttctactctt cttgacatag gtaacctgag ... tcggagcagt tttcctcgtg gcttcatctt tggtgctgga tcttcagcat accaatttga ... aggtgcagta aacgaaggcg gtagaggacc aagtatttgg gataccttca cccataaata ... tccagaaaaa ataagggatg gaagcaatgc agacatcacg gttgaccaat atcaccgcta ... caaggaagat gttgggatta tgaaggatca aaatatggat tcgtatagat tctcaatctc ... ttggccaaga atactcccaa agggaaagtt gagcggaggc ataaatcacg aaggaatcaa ... atattacaac aaccttatca acgaactatt ggctaacggt atacaaccat ttgtaactct ... ttttcattgg gatcttcccc aagtcttaga agatgagtat ggtggtttct taaactccgg ... tgtaataaat gattttcgag actatacgga tctttgcttc aaggaatttg gagatagagt ... gaggtattgg agtactctaa atgagccatg ggtgtttagc aattctggat atgcactagg ... aacaaatgca ccaggtcgat gttcggcctc caacgtggcc aagcctggtg attctggaac ... aggaccttat atagttacac acaatcaaat tcttgctcat gcagaagctg tacatgtgta ... taagactaaa taccaggcat atcaaaaggg aaagataggc ataacgttgg tatctaactg ... gttaatgcca cttgatgata atagcatacc agatataaag gctgccgaga gatcacttga ... cttccaattt ggattgttta tggaacaatt aacaacagga gattattcta agagcatgcg ... gcgtatagtt aaaaaccgat tacctaagtt ctcaaaattc gaatcaagcc tagtgaatgg ... ttcatttgat tttattggta taaactatta ctcttctagt tatattagca atgccccttc ... acatggcaat gccaaaccca gttactcaac aaatcctatg accaatattt catttgaaaa ... acatgggata cccttaggtc caagggctgc ttcaatttgg atatatgttt atccatatat ... gtttatccaa gaggacttcg agatcttttg ttacatatta aaaataaata taacaatcct ... gcaattttca atcactgaaa atggtatgaa tgaattcaac gatgcaacac ttccagtaga ... agaagctctt ttgaatactt acagaattga ttactattac cgtcacttat actacattcg ... ttctgcaatc agggctggct caaatgtgaa gggtttttac gcatggtcat ttttggactg ... taatgaatgg tttgcaggct ttactgttcg ttttggatta aactttgtag attagaaaga ... tggattaaaa aggtacccta agctttctgc ccaatggtac aagaactttc tcaaaagaaa ... ctagctagta ttattaaaag aactttgtag tagattacag tacatcgttt gaagttgagt ... tggtgcacct aattaaataa aagaggttac tcttaacata tttttaggcc attcgttgtg ... aagttgttag gctgttattt ctattatact atgttgtagt aataagtgca ttgttgtacc ... agaagctatg atcataacta taggttgatc cttcatgtat cagtttgatg ttgagaatac ... tttgaattaa aagtcttttt ttattttttt aaaaaaaaaa aaaaaaaaaa aaaaaaaaa ... // ... ''' Now we can read it as ``DNA`` object: >>> import io >>> from skbio import DNA, RNA, Sequence >>> embl = io.StringIO(embl_str) >>> dna_seq = DNA.read(embl) >>> dna_seq DNA ---------------------------------------------------------------------- Metadata: 'ACCESSION': 'X56734; S46826;' 'CROSS_REFERENCE': 'DATE': 'DBSOURCE': 'MD5; 1e51ca3a5450c43524b9185c236cc5cc.' 'DEFINITION': 'Trifolium repens mRNA for non-cyanogenic beta- glucosidase' 'KEYWORDS': 'beta-glucosidase.' 'LOCUS': 'REFERENCE': 'SOURCE': 'VERSION': 'X56734.1' Interval metadata: 3 interval features Stats: length: 1859 has gaps: False has degenerates: False has definites: True GC-content: 35.99% ---------------------------------------------------------------------- 0 AAACAAACCA AATATGGATT TTATTGTAGC CATATTTGCT CTGTTTGTTA TTAGCTCATT 60 CACAATTACT TCCACAAATG CAGTTGAAGC TTCTACTCTT CTTGACATAG GTAACCTGAG ... 1740 AGAAGCTATG ATCATAACTA TAGGTTGATC CTTCATGTAT CAGTTTGATG TTGAGAATAC 1800 TTTGAATTAA AAGTCTTTTT TTATTTTTTT AAAAAAAAAA AAAAAAAAAA AAAAAAAAA Since this is a mRNA molecule, we may want to read it as ``RNA``. As the EMBL file usually have ``t`` instead of ``u`` in the sequence, we can read it as ``RNA`` by converting ``t`` to ``u``: >>> embl = io.StringIO(embl_str) >>> rna_seq = RNA.read(embl) >>> rna_seq RNA ---------------------------------------------------------------------- Metadata: 'ACCESSION': 'X56734; S46826;' 'CROSS_REFERENCE': 'DATE': 'DBSOURCE': 'MD5; 1e51ca3a5450c43524b9185c236cc5cc.' 'DEFINITION': 'Trifolium repens mRNA for non-cyanogenic beta- glucosidase' 'KEYWORDS': 'beta-glucosidase.' 'LOCUS': 'REFERENCE': 'SOURCE': 'VERSION': 'X56734.1' Interval metadata: 3 interval features Stats: length: 1859 has gaps: False has degenerates: False has definites: True GC-content: 35.99% ---------------------------------------------------------------------- 0 AAACAAACCA AAUAUGGAUU UUAUUGUAGC CAUAUUUGCU CUGUUUGUUA UUAGCUCAUU 60 CACAAUUACU UCCACAAAUG CAGUUGAAGC UUCUACUCUU CUUGACAUAG GUAACCUGAG ... 1740 AGAAGCUAUG AUCAUAACUA UAGGUUGAUC CUUCAUGUAU CAGUUUGAUG UUGAGAAUAC 1800 UUUGAAUUAA AAGUCUUUUU UUAUUUUUUU AAAAAAAAAA AAAAAAAAAA AAAAAAAAA We can also ``trascribe`` a sequence and verify that it will be a ``RNA`` sequence >>> rna_seq == dna_seq.transcribe() True Reading EMBL Files using generators ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Soppose we have an EMBL file with multiple records: we can instantiate a generator object to deal with multiple records >>> import skbio >>> embl = io.StringIO(embl_str) >>> embl_gen = skbio.io.read(embl, format="embl") >>> dna_seq = next(embl_gen) For more informations, see :mod:`skbio.io` References ---------- .. [1] ftp://ftp.ebi.ac.uk/pub/databases/embl/release/doc/usrman.txt .. [2] http://www.ebi.ac.uk/ena/data/view/X56734&display=text .. [3] http://www.ebi.ac.uk/ena/browse/feature-level-products .. [4] https://github.com/scikit-bio/scikit-bio/issues/1499 """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # std modules import re import copy import textwrap from functools import partial # skbio modules from skbio.io import create_format, EMBLFormatError from skbio.io.format._base import _line_generator, _get_nth_sequence from skbio.io.format._sequence_feature_vocabulary import ( _yield_section, _parse_single_feature, _serialize_section_default, _serialize_single_feature, ) from skbio.metadata import IntervalMetadata from skbio.sequence import Sequence, DNA, RNA, Protein from skbio.util._misc import chunk_str # look at skbio.io.registry to have an idea on how to define this class embl = create_format("embl") # This list is ordered used to read and write embl file. By processing those # values one by one, I will write embl sections with the same order _HEADERS = [ "LOCUS", "ACCESSION", "PARENT_ACCESSION", "PROJECT_IDENTIFIER", "DATE", "DEFINITION", "GENE_NAME", "KEYWORDS", "SOURCE", "REFERENCE", "DBSOURCE", "COMMENT", "FEATURES", ] # embl has a series of keys different from genbank; moreover keys are not so # easy to understand (eg. RA for AUTHORS). I want to use the same keys used by # genbank both to convert between formats and to use the same methods to get # info from Sequence and its derived objects Here is a dictionary of keys # conversion (EMBL->GB). All the unspecified keys will remain in embl format KEYS_TRANSLATOR = { # identification "ID": "LOCUS", "AC": "ACCESSION", # PA means PARENT ACCESSION (?) and applies to # feature-level-products entries "PA": "PARENT_ACCESSION", "PR": "PROJECT_IDENTIFIER", "DT": "DATE", "DE": "DEFINITION", "GN": "GENE_NAME", # uniprot specific "KW": "KEYWORDS", # Source (taxonomy and classification) "OS": "ORGANISM", "OC": "taxonomy", "OG": "organelle", # reference keys "RA": "AUTHORS", "RP": "REFERENCE", "RC": "REFERENCE_COMMENT", "RX": "CROSS_REFERENCE", "RG": "GROUP", "RT": "TITLE", "RL": "JOURNAL", # Cross references "DR": "DBSOURCE", "CC": "COMMENT", # features "FH": "FEATURES", "FT": "FEATURES", "SQ": "ORIGIN", } # the inverse of KEYS_TRANSLATOR, for semplicity REV_KEYS_TRANSLATOR = {v: k for k, v in KEYS_TRANSLATOR.items()} # the original genbank _yield_section divides entries in sections relying on # spaces (the same section has the same level of indentation). EMBL entries # have a key for each line, so to divide record in sections I need to define a # correspondance for each key to section, then I will divide a record in # sections using these section name. KEYS_2_SECTIONS = { # identification "ID": "LOCUS", "AC": "ACCESSION", # PA means PARENT ACCESSION (?) and applies to # feature-level-products entries "PA": "PARENT_ACCESSION", "PR": "PROJECT_IDENTIFIER", "DT": "DATE", "DE": "DEFINITION", "GN": "GENE_NAME", # uniprot specific "KW": "KEYWORDS", # Source (taxonomy and classification) "OS": "SOURCE", "OC": "SOURCE", "OG": "SOURCE", # reference keys "RA": "REFERENCE", "RP": "REFERENCE", "RC": "REFERENCE", "RX": "REFERENCE", "RG": "REFERENCE", "RT": "REFERENCE", "RL": "REFERENCE", # This shuold be Reference Number. However, to split # between references with _embl_yield_section I need to # change section after reading one reference. So a single # reference is completed when I found a new RN. The # reference number information will be the reference # position in the final REFERENCE list metadata "RN": "SPACER", # Cross references "DR": "DBSOURCE", "CC": "COMMENT", "AH": "ASSEMBLY", "AS": "ASSEMBLY", "FH": "FEATURES", "FT": "FEATURES", # sequence "SQ": "ORIGIN", " ": "ORIGIN", "CO": "CONSTRUCTED", # spacer (discarded) "XX": "SPACER", } # for convenience: I think such functions are more readadble while accessing # values in lambda functions def _get_embl_key(line): """Return first part of a string as a embl key (ie 'AC M14399;' -> 'AC').""" # embl keys have a fixed size of 2 chars return line[:2] def _get_embl_section(line): """Return the embl section from uniprot key(ie 'RA' -> 'REFERENCE').""" # get embl key key = _get_embl_key(line) # get embl section from key section = KEYS_2_SECTIONS[key] return section def _translate_key(key): """Translate a single key from EMBL to genbank. Returns key itself if no translation is defined. """ return KEYS_TRANSLATOR.get(key, key) # a method to translate keys from embl to genbank for a dict object. All keys # not defined in the original dict will remain the same def _translate_keys(data): """Translate keys from EMBL to genbank for a dict object. Translate a dictionary of uniprot key->value in a genbank like dictionary of key values. Keep old keys if no translation is defined. """ # traslate keys and get a new_data object new_data = {_translate_key(k): v for k, v in data.items()} return new_data # define a default textwrap.Wrapper for embl def _get_embl_wrapper(embl_key, indent=5, subsequent_indent=None, width=80): """Return a textwrap.TextWrapper for embl records. For example, write by providing embl key and a string. Wrap text to 80 column. """ # define the string to prepen (eg "OC ") prepend = "{key:<{indent}}".format(key=embl_key, indent=indent) # deal with 2° strings and more if subsequent_indent is None: subsequent_prepend = prepend else: subsequent_prepend = "{key:<{indent}}".format( key=embl_key, indent=subsequent_indent ) # define a text wrapper object wrapper = textwrap.TextWrapper( initial_indent=prepend, subsequent_indent=subsequent_prepend, width=width ) return wrapper def _serialize_list(embl_wrapper, data, sep="\n"): """Serialize a list of obj using a textwrap.TextWrapper instance. Returns one string of wrapped embl objects. """ # the output array output = [] for line in data: output += embl_wrapper.wrap(line) # merge dates in one string. Add final newline output = sep.join(output) + "\n" # return comupted string return output # Method to determine if file is in EMBL format or not. A uniprot embl format # can't be parsed by this module (at the moment) @embl.sniffer() def _embl_sniffer(fh): try: line = next(_line_generator(fh, skip_blanks=True, strip=False)) except StopIteration: return False, {} try: _parse_id([line]) except EMBLFormatError: return False, {} return True, {} @embl.reader(None) def _embl_to_generator(fh, cls=None, constructor=None, **kwargs): for record in _parse_embls(fh): yield _construct(record, constructor, **kwargs) # Method to read EMBL data as skbio.sequence.DNA @embl.reader(Sequence) def _embl_to_sequence(fh, cls=None, seq_num=1, **kwargs): if cls is None: cls = Sequence record = _get_nth_sequence(_parse_embls(fh), seq_num) return _construct(record, cls, **kwargs) # Method to read EMBL data as skbio.sequence.DNA @embl.reader(DNA) def _embl_to_dna(fh, cls=None, seq_num=1, **kwargs): if cls is None: cls = DNA record = _get_nth_sequence(_parse_embls(fh), seq_num) return _construct(record, cls, **kwargs) # Method to read EMBL data as skbio.sequence.DNA @embl.reader(RNA) def _embl_to_rna(fh, cls=None, seq_num=1, **kwargs): if cls is None: cls = RNA record = _get_nth_sequence(_parse_embls(fh), seq_num) return _construct(record, cls, **kwargs) # No protein support at the moment @embl.reader(Protein) def _embl_to_protein(fh, cls=None, seq_num=1, **kwargs): # no protein support, at the moment raise EMBLFormatError( "There's no protein support for EMBL record. " "Current status of EMBL protein support is " "described in issue-1499 (https://github.com/" "biocore/scikit-bio/issues/1499)" ) # Writer methods @embl.writer(None) def _generator_to_embl(obj, fh): for obj_i in obj: _serialize_single_embl(obj_i, fh) @embl.writer(Sequence) def _sequence_to_embl(obj, fh): _serialize_single_embl(obj, fh) @embl.writer(DNA) def _dna_to_embl(obj, fh): _serialize_single_embl(obj, fh) @embl.writer(RNA) def _rna_to_embl(obj, fh): _serialize_single_embl(obj, fh) @embl.writer(Protein) def _protein_to_embl(obj, fh): # no protein support, at the moment raise EMBLFormatError( "There's no protein support for EMBL record. " "Current status of EMBL protein support is " "described in issue-1499 (https://github.com/" "biocore/scikit-bio/issues/1499)" ) def _construct(record, constructor=None, **kwargs): """Construct the object of Sequence, DNA, RNA, or Protein.""" # sequence, metadata and interval metadata seq, md, imd = record if "lowercase" not in kwargs: kwargs["lowercase"] = True if constructor is None: unit = md["LOCUS"]["unit"] if unit == "bp": # RNA mol type has T instead of U for genbank from from NCBI constructor = DNA elif unit == "aa": # no protein support, at the moment # constructor = Protein raise EMBLFormatError("There's no protein support for EMBL record") if constructor == RNA: return DNA(seq, metadata=md, interval_metadata=imd, **kwargs).transcribe() else: return constructor(seq, metadata=md, interval_metadata=imd, **kwargs) # looks like the genbank _parse_genbank def _parse_embls(fh): """Chunk multiple EMBL records by '//', and returns a generator.""" data_chunks = [] for line in _line_generator(fh, skip_blanks=True, strip=False): if line.startswith("//"): yield _parse_single_embl(data_chunks) data_chunks = [] else: data_chunks.append(line) def _parse_single_embl(chunks): metadata = {} interval_metadata = None sequence = "" # define a section splitter with _embl_yield_section function defined in # this module (return the embl section by embl key). returns generator for # each block with different line type section_splitter = _embl_yield_section( lambda line: _get_embl_section(line), skip_blanks=True, strip=False ) # process each section, like genbank does. for section, section_name in section_splitter(chunks): # section is a list of records with the same session (eg RA, RP for # for a single reference). section_name is the name of the section # (eg REFERENCE for the section of the previous example) # search for a specific method in PARSER_TABLE using section_name or # set _embl_parse_section_default parser = _PARSER_TABLE.get(section_name, _embl_parse_section_default) if section_name == "FEATURES": # This requires 'ID' line parsed before 'FEATURES', which should # be true and is implicitly checked by the sniffer. This is true # since the first section is parsed by the last else condition if "PARENT_ACCESSION" in metadata: # this is a feature-level-products entry and features are # relative to parent accession; in the same way a subset of a # Sequence object has no interval metadata, I will refuse to # process interval metadata here continue # partials add arguments to previous defined functions, in this # case length of Sequence object parser = partial(parser, length=metadata["LOCUS"]["size"]) elif section_name == "COMMENT": # maintain newlines in comments # partials add arguments to previous defined functions parser = partial(parser, join_delimiter="\n") # call function on section parsed = parser(section) # reference can appear multiple times if section_name == "REFERENCE": # genbank data hasn't CROSS_REFERENCE section, To have a similar # metatadata object, I chose to remove CROSS_REFERENCE from # each single reference and put them in metadata. Since I could # have more references, I need a list of CROSS_REFERENCE, with # None values when CROSS_REFERENCE are not defined: there are cases # in which some references have a CROSS_REFERENCE and others not. # So each reference will have it's cross reference in the same # index position, defined or not cross_reference = parsed.pop("CROSS_REFERENCE", None) # fix REFERENCE metadata. Ask if is the first reference or not # I need a reference number as genbank, this could be reference # size if section_name in metadata: RN = len(metadata[section_name]) + 1 else: RN = 1 # fix reference fields. Get RN->REFERENCE value from dict positions = parsed.pop("REFERENCE", None) parsed["REFERENCE"] = str(RN) # append position to RN (eg "1 (bases 1 to 63)") if positions: parsed["REFERENCE"] += " %s" % (positions) # cross_reference will be a list of cross reference; Also # metadata[REFERENCE] is a list of references if section_name in metadata: # I've already seen a reference, append new one metadata[section_name].append(parsed) metadata["CROSS_REFERENCE"].append(cross_reference) else: # define a list for this first reference and its RX metadata[section_name] = [parsed] metadata["CROSS_REFERENCE"] = [cross_reference] elif section_name == "ORIGIN": sequence = parsed elif section_name == "FEATURES": interval_metadata = parsed elif section_name == "DATE": # read data (list) metadata[section_name] = parsed # fix locus metadata using last date. Take only last date date = metadata[section_name][-1].split()[0] metadata["LOCUS"]["date"] = date # parse all the others sections (SOURCE, ...) else: metadata[section_name] = parsed # after metadata were read, add a VERSION section like genbank # eval if entry is a feature level product or not if "ACCESSION" in metadata: metadata["VERSION"] = "{accession}.{version}".format( accession=metadata["ACCESSION"].split(";")[0], version=metadata["LOCUS"]["version"], ) elif "PARENT_ACCESSION" in metadata: # locus name is in the format # .::[:ordinal] # and ordinal could be present or not, depends on how many features # are found in such location. Such entry couldn't be found in others # database like NCBI (at the moment) so we will take the version # relying on parent accession (hoping that an update in the parent # accession will generate an update in all feature level products) metadata["VERSION"] = metadata["PARENT_ACCESSION"] # return a string, metadata as a dictionary and IntervalMetadata object return sequence, metadata, interval_metadata def _write_serializer(fh, serializer, embl_key, data): """Write serializer to a file. Append 'XX'.""" # call the serializer function out = serializer(embl_key, data) # test if 'out' is a iterator. # cf. Effective Python Item 17 if iter(out) is iter(out): for s in out: fh.write(s) else: fh.write(out) # add spacer between sections fh.write("XX\n") # main function for writer methods def _serialize_single_embl(obj, fh): """Write a EMBL record. Always write it in ENA canonical way: 1. sequence in lowercase (uniprot are uppercase) 2. 'u' as 't' even in RNA molecules. Parameters ---------- obj : Sequence or its child class A Sequence object or its child class representing the biological sequence to be serialized. fh : file object A file object open for writing. """ # shortcut to deal with metadata md = obj.metadata # embl has a different magick number than embl serialize_default = partial(_serialize_section_default, indent=5) # Now cicle for GB like headers (sections) in _HEADERS. for header in _HEADERS: # Get appropriate serializer method or default one serializer = _SERIALIZER_TABLE.get(header, serialize_default) # headers needs to be converted into embl, or matained as they are # if no conversion could be defined. embl_key = REV_KEYS_TRANSLATOR.get(header, header) # this is true also for locus line if header in md: # deal with special source case, add cross references if needed if header == "REFERENCE": serializer = partial( serializer, cross_references=md.get("CROSS_REFERENCE") ) elif header == "LOCUS": # pass also metadata (in case of entries from genbank) serializer = partial(serializer, metadata=md) # call the serializer function _write_serializer(fh, serializer, embl_key, md[header]) else: # header not in metadata. Could be date read from GB? if header == "DATE": # Have I date in locus metadata? if md["LOCUS"]["date"]: # call serializer on date. Date is a list of values _write_serializer(fh, serializer, embl_key, [md["LOCUS"]["date"]]) if header == "FEATURES": if obj.has_interval_metadata(): # magic number 21: the amount of indentation before # feature table starts as defined by INSDC indent = 21 feature_key = "FH Key" fh.write( "{header:<{indent}}Location/Qualifiers\n".format( header=feature_key, indent=indent ) ) # add FH spacer fh.write("FH\n") for s in serializer(obj.interval_metadata._intervals, indent): fh.write(s) # add spacer between sections fh.write("XX\n") # write out the sequence # always write RNA seq as DNA if isinstance(obj, RNA): obj = obj.reverse_transcribe() # serialize sequence from a Sequence object for s in _serialize_sequence(obj): fh.write(s) # terminate a embl record with fh.write("//\n") def _parse_id(lines): """Parse the identification line of an EMBL record. From EMBL user manual (Release 130, November 2016). (ftp://ftp.ebi.ac.uk/pub/databases/embl/release/doc/usrman.txt) The ID (IDentification) line is always the first line of an entry. The format of the ID line is: ID <1>; SV <2>; <3>; <4>; <5>; <6>; <7> BP. The tokens represent: 1. Primary accession number 2. Sequence version number 3. Topology: 'circular' or 'linear' 4. Molecule type (see note 1 below) 5. Data class (see section 3.1 of EMBL user manual) 6. Taxonomic division (see section 3.2 of EMBL user manual) 7. Sequence length (see note 2 below) Note 1 - Molecule type: this represents the type of molecule as stored and can be any value from the list of current values for the mandatory mol_type source qualifier. This item should be the same as the value in the mol_type qualifier(s) in a given entry. Note 2 - Sequence length: The last item on the ID line is the length of the sequence (the total number of bases in the sequence). This number includes base positions reported as present but undetermined (coded as "N"). An example of a complete identification line is shown below: ID CD789012; SV 4; linear; genomic DNA; HTG; MAM; 500 BP. """ # get only the first line of EMBL record line = lines[0] # define a specific patter for EMBL pattern = re.compile( r"ID" r" +([^\s]+);" # ie: CD789012 r" +SV ([0-9]*);" # 4 r" +(\w+);" # linear r" +([^;]+);" # genomic DNA r" +(\w*);" # HTG r" +(\w+);" # MAM r" +(\d+)" # 500 r" +(\w+)\.$" ) # BP # search it matches = re.match(pattern, line) try: res = dict( zip( [ "locus_name", "version", "shape", "mol_type", "class", "division", "size", "unit", ], matches.groups(), ) ) except AttributeError: raise EMBLFormatError("Could not parse the ID line:\n%s" % line) # check for CON entries: if res["class"] == "CON": # entries like http://www.ebi.ac.uk/ena/data/view/LT357133 # doesn't have sequence, so can't be read by skbio.sequence raise EMBLFormatError( "There's no support for embl CON record: for more information " "see issue-1506 (https://github.com/scikit-bio/scikit-bio/issues/" "1506)" ) # those values are integer res["size"] = int(res["size"]) # version could be integer if res["version"]: res["version"] = int(res["version"]) # unit are in lower cases in others modules res["unit"] = res["unit"].lower() # initialize a date record (for gb compatibility) res["date"] = None # returning parsed attributes return res def _serialize_id(header, obj, metadata={}, indent=5): """Serialize ID line. Parameters ---------- header : str The header of the ID line. Usually 'ID' for EMBL or 'LOCUS' for GenBank. obj : dict A dictionary containing key-value pairs representing the attributes of the sequence entry. metadata : dict, optional Additional metadata information, typically extracted from a GenBank entry. indent : int, optional The number of spaces used to indent the serialized ID line. Defaults to 5. """ # get key->value pairs, or key->'' if values is None kwargs = {k: "" if v is None else v for k, v in obj.items()} # then unit is in upper cases kwargs["unit"] = kwargs["unit"].upper() # check for missing keys (eg from gb data). Keys in md are in uppercase for key in ["version", "class"]: if key not in kwargs: if key.upper() in metadata: kwargs[key] = metadata[key.upper()] else: kwargs[key] = "" # version from genbank could be "M14399.1 GI:145229". I need an integer version = kwargs["version"] # version could by empty, integer or text if version != "": try: int(kwargs["version"]) # could be a text like M14399.1 except ValueError: match = re.search(r"^\w+\.([0-9]+)", version) if match: kwargs["version"] = match.groups()[0] # return first line return ( "{header:<{indent}}{locus_name}; SV {version}; {shape}; " "{mol_type}; {class}; {division}; {size} {unit}.\n" ).format(header=header, indent=indent, **kwargs) # similar to skbio.io.format._sequence_feature_vocabulary.__yield_section # but applies to embl file format def _embl_yield_section(get_line_key, **kwargs): """Return function that returns successive sections from file. Parameters ---------- get_line_key : callable It takes a string as input and a key indicating the section (could be the embl key or embl KEYS_2_SECTIONS) kwargs : dict, optional Keyword arguments will be passed to `_line_generator`. Returns ------- function A function accept a list of lines as input and return a generator to yield section one by one. """ def parser(lines): curr = [] curr_type = None for line in _line_generator(lines, **kwargs): # if we find another line, return the previous section line_type = get_line_key(line) # changed line type if line_type != curr_type: if curr: # returning block yield curr, curr_type # reset curr after yield curr = [] # reset curr_type in any cases curr_type = line_type # don't append record if line type is a spacer if "SPACER" not in line_type: curr.append(line) # don't forget to return the last section in the file if curr: yield curr, curr_type return parser # replace skbio.io.format._sequence_feature_vocabulary._parse_section_default def _embl_parse_section_default( lines, label_delimiter=None, join_delimiter=" ", return_label=False ): """Parse sections in default way. Do 2 things: 1. split first line with label_delimiter for label 2. join all the lines into one str with join_delimiter. """ data = [] label = None line = lines[0] # take the first line, divide the key from the text items = line.split(label_delimiter, 1) if len(items) == 2: label, section = items else: label = items[0] section = "" # append the text of the first element in a empty array data.append(section) # Then process all the elements with the same embl key. remove the key # and append all the text in the data array data.extend(line.split(label_delimiter, 1)[-1] for line in lines[1:]) # Now concatenate the text using join_delimiter. All content with the same # key will be placed in the same string. Strip final "\n data = join_delimiter.join(i.strip() for i in data) # finally return the merged text content, and the key if needed if return_label: return label, data else: return data # parse an embl reference record. def _parse_reference(lines): """Parse single REFERENCE field.""" # parsed reference will be placed here res = {} # define a section splitter with _embl_yield_section function defined in # this module section_splitter = _embl_yield_section( lambda line: _get_embl_key(line), skip_blanks=True, strip=False ) # now itereta along sections (lines of the same type) for section, section_name in section_splitter(lines): # this function append all data in the same keywords. A list of lines # as input (see skbio.io.format._sequence_feature_vocabulary) label, data = _embl_parse_section_default( section, join_delimiter=" ", return_label=True ) res[label] = data # now RX (CROSS_REFERENCE) is a joined string of multiple values. To get # back to a list of values you can use: re.compile("([^;\s]*); ([^\s]*)") # search for pubmed record, and add the PUBMED key if "RX" in res: match = re.search(r"PUBMED; (\d+)\.", res["RX"]) if match: # add pubmed notation res["PUBMED"] = match.groups()[0] # fix RP field like genbank (if exists), Ie: (bases 1 to 63) if "RP" in res: match = re.search(r"(\d+)-(\d+)", res["RP"]) if match: # fix rp fields res["RP"] = "(bases {start} to {stop})".format( start=match.groups()[0], stop=match.groups()[1] ) # return translated keys (EMBL->GB) return _translate_keys(res) def _serialize_reference(header, obj, cross_references, indent=5): """Serialize a list of references.""" reference = [] sort_order = ["RC", "RP", "RX", "RG", "RA", "RT", "RL"] # deal with RX pattern and RP pattern RX = re.compile(r"([^;\s]*); ([^\s]*)") RP = re.compile(r"bases (\d+) to (\d+)") # create a copy of obj, that can be changed. I need to delete values or # adding new ones obj = copy.deepcopy(obj) # obj is a list of references. Now is a copy of metadata[SOURCE] for i, data in enumerate(obj): # get the reference number (as the iteration number) embl_key = "RN" # get cross_references if cross_references: cross_reference = cross_references[i] # append cross reference [i] to data (obj[i]) (if they exists) if cross_reference: data["CROSS_REFERENCE"] = cross_reference # delete PUBMED key (already present in CROSS_REFERENCE) if "PUBMED" in data: del data["PUBMED"] else: # no cross reference, do I have PUBMED in data? if "PUBMED" in data: # add a fake CROSS_REFERENCE data["CROSS_REFERENCE"] = "PUBMED; %s." % data["PUBMED"] # get an embl wrapper wrapper = _get_embl_wrapper(embl_key, indent) # define wrapped string and add RN to embl data reference += wrapper.wrap("[{RN}]".format(RN=i + 1)) # now process each record for references for embl_key in sort_order: # get internal key (genbank like key) key = _translate_key(embl_key) # have I this reference in my reference data? if key not in data: continue # if yes, define wrapper wrapper = _get_embl_wrapper(embl_key, indent) # data could have newlines records = data[key].split("\n") for record in records: # strip after newlines record = record.strip() # define wrapped string. beware RX if embl_key == "RX": for match in re.finditer(RX, record): source, link = match.groups() # join text cross_reference = "; ".join([source, link]) reference += wrapper.wrap(cross_reference) # RP case elif embl_key == "RP": match = re.search(RP, record) # if I have position, re-define RP key if match: record = "%s-%s" % match.groups() reference += wrapper.wrap(record) # if not, ignore RP key else: continue # all the other cases, go in wrapper as they are else: reference += wrapper.wrap(record) # add a spacer between references (but no at the final reference) # cause the caller will add spacer if (i + 1) < len(obj): reference += ["XX"] # now define a string and add a final "\n" s = "\n".join(reference) + "\n" # and return it return s # parse an embl reference record. def _parse_source(lines): """Parse single SOURCE field.""" # parsed reference will be placed here res = {} # define a section splitter with _embl_yield_section function defined in # this module section_splitter = _embl_yield_section( lambda line: _get_embl_key(line), skip_blanks=True, strip=False ) # now itereta along sections (lines of the same type) for section, section_name in section_splitter(lines): # this function append all data in the same keywords. A list of lines # as input (see skbio.io.format._sequence_feature_vocabulary) label, data = _embl_parse_section_default( section, join_delimiter=" ", return_label=True ) res[label] = data # return translated keys return _translate_keys(res) def _serialize_source(header, obj, indent=5): """Serialize SOURCE. Parameters ---------- header: str The section header. obj : dict A dictionary containing key-value pairs representing the attributes of the SOURCE section. indent : int, optional The number of spaces used to indent the serialized SOURCE section. Defaults to 5. """ source = [] # treat taxonomy and all others keys for key in ["ORGANISM", "taxonomy", "organelle"]: # get data to serielize data = obj.get(key) # if key is not defined (eg. organelle, continue) if data is None: continue # get embl key for my key (eg, taxonomy -> OC) embl_key = REV_KEYS_TRANSLATOR.get(key, key) # get an embl wrapper wrapper = _get_embl_wrapper(embl_key, indent) # define wrapped string source += wrapper.wrap(data) # now define a string and add a final "\n" s = "\n".join(source) + "\n" # and return it return s def _parse_sequence(lines): """Parse the sequence section for sequence.""" # result array sequence = [] for line in lines: # ignore record like: # SQ Sequence 275 BP; 64 A; 73 C; 88 G; 50 T; 0 other; if line.startswith("SQ"): continue # remove the numbers inside strings. revome spaces around string items = [i for i in line.split() if not i.isdigit()] # append each sequence items to sequence list sequence += items return "".join(sequence) def _serialize_sequence(obj, indent=5): """Serialize seq to SQ. Parameters ---------- obj : DNA, RNA, Sequence Obj A DNA, RNA, or Sequence object representing the biological sequence to be serialized. indent : int, optional The number of spaces used to indent the serialized sequence. Defaults to 5. """ # a flag to determine if I wrote header or not flag_header = False # magic numbers: there will be 60 letters (AA, bp) on each line chunk_size = 60 # letters (AA, bp) will be grouped by 10: each group is divided by # one space from each other frag_size = 10 # fasta sequence will have indent spaces on the left, chunk_size/frag_size # groups of frag_size letters separated by n-1 groups of single spaces, # then the sequence length aligned on the right to get a string of # line_size. Setting left and right padding for semplicity pad_right = 65 # there are also 5 columns for indentation pad_left = 10 # sequence number will be in the last 10 columns # get sequence as a string with lower letters (uniprot will be upper!) seq = str(obj).lower() # count bases in sequence. Frequencies returns a dictionary of occurrences # of A,C,G,T. Sequences are stored always in capital letters freq = obj.frequencies() # get values instead of popping them: I can't assure that the letter T, # for example, is always present n_a = freq.get("A", 0) n_c = freq.get("C", 0) n_g = freq.get("G", 0) n_t = freq.get("T", 0) # this will be the count of all others letters (more than ACGT) n_others = len(obj) - (n_a + n_c + n_g + n_t) # define SQ like this: # SQ Sequence 275 BP; 63 A; 72 C; 88 G; 52 T; 0 other; SQ = ( "SQ Sequence {size} {unit}; {n_a} A; {n_c} C; {n_g} G; " + "{n_t} T; {n_others} other;\n" ) # TODO: deal with protein SQ: they have a sequence header like: # SQ SEQUENCE 256 AA; 29735 MW; B4840739BF7D4121 CRC64; # apply format SQ = SQ.format( size=len(obj), unit=obj.metadata["LOCUS"]["unit"].upper(), n_a=n_a, n_c=n_c, n_g=n_g, n_t=n_t, n_others=n_others, ) for i in range(0, len(seq), chunk_size): line = seq[i : i + chunk_size] # pad string left and right s = "{indent}{s:<{pad_right}}{pos:>{pad_left}}\n".format( indent=" " * indent, s=chunk_str(line, frag_size, " "), pad_left=pad_left, pos=i + len(line), pad_right=pad_right, ) if not flag_header: # First time here. Add SQ header to sequence s = SQ + s # When I added header, I need to turn off this flag flag_header = True yield s def _embl_parse_feature_table(lines, length): """Parse embl feature tables.""" # define interval metadata imd = IntervalMetadata(length) # get only FT records, and remove key from line lines = [line[2:] for line in lines if line.startswith("FT")] # magic number 19: after key removal, the lines of each feature # are indented with 19 spaces. feature_indent = " " * 19 section_splitter = _yield_section( lambda x: not x.startswith(feature_indent), skip_blanks=True, strip=False ) for section in section_splitter(lines): _parse_single_feature(section, imd) return imd def _serialize_feature_table(intervals, indent=21): """Serialize a list of ``Interval`` objects into EMBL format. Parameters ---------- intervals : list of ``Interval`` A list of Interval objects representing the intervals to be serialized. indent : int, optional The number of spaces to indent each serialized feature. Defaults to 21. """ # define a embl wrapper object. I need to replace only the first two # characters from _serialize_single_feature output wrapper = _get_embl_wrapper("FT", indent=2, subsequent_indent=21) for intvl in intervals: tmp = _serialize_single_feature(intvl, indent) output = [] # I need to remove two spaces, cause I will add a FT key for line in tmp.split("\n"): output += wrapper.wrap(line[2:]) # re add newline between elements, and a final "\n" yield "\n".join(output) + "\n" def _parse_date(lines, label_delimiter=None, return_label=False): """Parse embl date records.""" # take the first line, and derive a label label = lines[0].split(label_delimiter, 1)[0] # read all the others dates and append to data array data = [line.split(label_delimiter, 1)[-1] for line in lines] # strip returned data data = [i.strip() for i in data] # finally return data array, and the key if needed if return_label: return label, data else: return data def _serialize_date(embl_key, date_list, indent=5): """Serialize date line. Parameters ---------- embl_key : str The EMBL key ID corresponding to the date line. date_list : list A list of dates associated with the sequence entry. indent : int, optional The number of spaces used to indent the serialized date line. Defaults to 5. """ # get an embl wrapper wrapper = _get_embl_wrapper(embl_key, indent) # # serialize date and return them as a string return _serialize_list(wrapper, date_list) def _serialize_comment(embl_key, obj, indent=5): """Serialize comment (like Assembly).""" # obj is a string, Split it by newlines data = obj.split("\n") # get an embl wrapper wrapper = _get_embl_wrapper(embl_key, indent) # serialize data and return it return _serialize_list(wrapper, data) def _serialize_dbsource(embl_key, obj, indent=5): """Serialize DBSOURCE.""" # data are stored like 'SILVA-LSU; LK021130. SILVA-SSU; LK021130. ... # I need to split string after final period (not AAT09660.1) # deal with re pattern. A pattern to find a period as end of sentence DR = re.compile(r"\.\s") # splitting by this pattern, I will have # ["SILVA-LSU; LK021130", "SILVA-SSU; LK021130", ...] # I need that each of them will be in a DR record. # get an embl wrapper wrapper = _get_embl_wrapper(embl_key, indent) # serialize data and return it. Split dbsource using re. Add a # final period between elements since I removed it by splitting return _serialize_list(wrapper, re.split(DR, obj), sep=".\n") def _parse_assembly(lines): """Parse embl assembly records.""" output = [] # first line is header, skip it for line in lines[1:]: data = line.split() # data could have comp feature or not. First element in data is 'AS' if len(data) == 5: res = dict( zip( ["local_span", "primary_identifier", "primary_span", "comp"], data[1:], ) ) elif len(data) == 4: res = dict( zip( ["local_span", "primary_identifier", "primary_span", "comp"], data[1:] + [""], ) ) else: raise EMBLFormatError("Can't parse assembly line %s" % line) # append res to output output += [res] return output # Map a function to each section of the entry _PARSER_TABLE = { "LOCUS": _parse_id, "SOURCE": _parse_source, "DATE": _parse_date, "REFERENCE": _parse_reference, "FEATURES": _embl_parse_feature_table, "ORIGIN": _parse_sequence, "ASSEMBLY": _parse_assembly, } # for writer functions _SERIALIZER_TABLE = { "LOCUS": _serialize_id, "SOURCE": _serialize_source, "DATE": _serialize_date, "REFERENCE": _serialize_reference, "FEATURES": _serialize_feature_table, "COMMENT": _serialize_comment, "DBSOURCE": _serialize_dbsource, } scikit-bio-scikit-bio-a3beaa6/skbio/io/format/emptyfile.py000066400000000000000000000022331520735541300237310ustar00rootroot00000000000000r"""Empty Files (:mod:`skbio.io.format.emptyfile`) ============================================== .. currentmodule:: skbio.io.format.emptyfile This format exists to make debugging simpler, often an empty file is a mistake which can take an embarrassing amount of time to notice. This format has only a sniffer and no readers or writers, so error messages will indicate as such if an empty file is accidentally used as input. Format Support -------------- **Has Sniffer: Yes** Format Specification -------------------- An empty file consists of only whitespace characters. """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from skbio.io import create_format emptyfile = create_format("") @emptyfile.sniffer() def _empty_file_sniffer(fh): for line in fh: if line.strip(): return False, {} return True, {} scikit-bio-scikit-bio-a3beaa6/skbio/io/format/fasta.py000066400000000000000000001122531520735541300230350ustar00rootroot00000000000000r"""FASTA/QUAL format (:mod:`skbio.io.format.fasta`) ================================================ .. currentmodule:: skbio.io.format.fasta The FASTA file format (``fasta``) stores biological (i.e., nucleotide or protein) sequences in a simple plain text format that is both human-readable and easy to parse. The file format was first introduced and used in the FASTA software package [1]_. Additional descriptions of the file format can be found in [2]_ and [3]_. An example of a FASTA-formatted file containing two DNA sequences:: >seq1 db-accession-149855 CGATGTCGATCGATCGATCGATCAG >seq2 db-accession-34989 CATCGATCGATCGATGCATGCATGCATG The QUAL file format is an additional format related to FASTA. A FASTA file is sometimes accompanied by a QUAL file, particularly when the FASTA file contains sequences generated on a high-throughput sequencing instrument. QUAL files store a Phred quality score (nonnegative integer) for each base in a sequence stored in FASTA format (see [4]_ for more details). scikit-bio supports reading and writing FASTA (and optionally QUAL) file formats. Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |generator of :mod:`skbio.sequence.Sequence` objects | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.alignment.TabularMSA` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.Sequence` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.DNA` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.RNA` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.Protein` | +------+------+---------------------------------------------------------------+ .. note:: All readers and writers support an optional QUAL file via the ``qual`` parameter. If one is provided, quality scores will be read/written in addition to FASTA sequence data. Format Specification -------------------- The following sections define the FASTA and QUAL file formats in detail. FASTA Format ^^^^^^^^^^^^ A FASTA file contains one or more biological sequences. The sequences are stored sequentially, with a *record* for each sequence (also referred to as a *FASTA record*). Each *record* consists of a single-line *header* (sometimes referred to as a *defline*, *label*, *description*, or *comment*) followed by the sequence data, optionally split over multiple lines. .. note:: Blank or whitespace-only lines are only allowed at the beginning of the file, between FASTA records, or at the end of the file. A blank or whitespace-only line after the header line, within the sequence (for FASTA files), or within quality scores (for QUAL files) will raise an error. scikit-bio will ignore leading and trailing whitespace characters on each line while reading. .. note:: scikit-bio does not currently support legacy FASTA format (i.e., headers/comments denoted with a semicolon). The format supported by scikit-bio (described below in detail) most closely resembles the description given in NCBI's BLAST documentation [3]_. See [2]_ for more details on legacy FASTA format. If you would like legacy FASTA format support added to scikit-bio, please consider submitting a feature request on the scikit-bio `issue tracker `_ (pull requests are also welcome!). Sequence Header ~~~~~~~~~~~~~~~ Each sequence header consists of a single line beginning with a greater-than (``>``) symbol. Immediately following this is a sequence identifier (ID) and description separated by one or more whitespace characters. .. note:: When reading a FASTA-formatted file, the sequence ID and description are stored in the sequence `metadata` attribute, under the `'id'` and `'description'` keys, respectively. Both are optional. Each will be represented as the empty string (``''``) in `metadata` if it is not present in the header. When writing a FASTA-formatted file, sequence `metadata` identified by keys `'id'` and `'description'` will be converted to strings and written as the sequence identifier and description, respectively. Each will be written as the empty string if not present in sequence `metadata`. A sequence ID consists of a single *word*: all characters after the greater- than symbol and before the first whitespace character (if any) are taken as the sequence ID. Unique sequence IDs are not strictly enforced by the FASTA format itself. A single standardized ID format is similarly not enforced by the FASTA format, though it is often common to use a unique library accession number for a sequence ID (e.g., NCBI's FASTA defline format [5]_). If a description is present, it is taken as the remaining characters that follow the sequence ID and initial whitespace(s). The description is considered additional information about the sequence (e.g., comments about the source of the sequence or the molecule that it encodes). For example, consider the following header:: >seq1 db-accession-149855 ``seq1`` is the sequence ID and ``db-accession-149855`` is the sequence description. .. note:: scikit-bio's readers will remove all leading and trailing whitespace from the description. If a header line begins with whitespace following the ``>``, the ID is assumed to be missing and the remainder of the line is taken as the description. Sequence Data ~~~~~~~~~~~~~ Biological sequence data follows the header, and can be split over multiple lines. The sequence data (i.e., nucleotides or amino acids) are stored using the standard IUPAC lexicon (single-letter codes). .. note:: scikit-bio supports both upper and lower case characters. This functionality depends on the type of object the data is being read into. For ``Sequence`` objects, sciki-bio doesn't care about the case. Other sequence objects do, but all provide the `lowercase` parameter to control case functionality. Refer to each class's respective constructor documentation for details. Both ``-`` and ``.`` are supported as gap characters when reading into ``DNA``, ``RNA``, and ``Protein`` sequence objects. Validation is performed when reading into scikit-bio sequence objects that enforce an alphabet (e.g., ``DNA``, ``RNA``, ``Protein``). If any invalid characters are found while reading from the FASTA file, an exception is raised. QUAL Format ^^^^^^^^^^^ A QUAL file contains quality scores for one or more biological sequences stored in a corresponding FASTA file. QUAL format is very similar to FASTA format: it stores records sequentially, with each record beginning with a header line containing a sequence ID and description. The same rules apply to QUAL headers as FASTA headers (see the above sections for details). scikit-bio processes FASTA and QUAL headers in exactly the same way. Instead of storing biological sequence data in each record, a QUAL file stores a Phred quality score for each base in the corresponding sequence. Quality scores are represented as nonnegative integers separated by whitespace (typically a single space or newline), and can span multiple lines. .. note:: When reading a QUAL-formatted file, quality scores are stored in the sequence's `positional_metadata` attribute under the `'quality'` column. When writing a QUAL-formatted file, a sequence's `positional_metadata` `'quality'` column will be written as the quality scores. .. note:: When reading FASTA and QUAL files, scikit-bio requires records to be in the same order in both files (i.e., each FASTA and QUAL record must have the same ID and description after being parsed). In addition to having the same order, the number of FASTA records must match the number of QUAL records (i.e., missing or additional records are not allowed). scikit-bio also requires that the number of quality scores match the number of bases in the corresponding sequence. When writing FASTA and QUAL files, scikit-bio will maintain the same ordering of records in both files (i.e., using the same ID and description in both records) to support future reading. Format Parameters ----------------- The following parameters are available to change how FASTA/QUAL files are read or written in scikit-bio. QUAL File Parameter (Readers and Writers) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``qual`` parameter is available to all FASTA format readers and writers. It can be any file-like type supported by scikit-bio's I/O registry (e.g., file handle, file path, etc.). If ``qual`` is provided when reading, quality scores will be included in each in-memory ``Sequence`` object, in addition to sequence data stored in the FASTA file. When writing, quality scores will be written in QUAL format in addition to the sequence data being written in FASTA format. Reader-specific Parameters ^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``keep_spaces`` parameter can be used with any reader. If set to ``True``, all spaces in the input will be preserved. If set to ``False``, all spaces in the input will be removed. Default is ``False``. The following reader parameters differ depending on which reader is used. Generator and TabularMSA Reader Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``constructor`` parameter can be used with the ``Sequence`` generator and ``TabularMSA`` FASTA readers. ``constructor`` specifies the type of in-memory sequence object to read each sequence into. For example, if you know that the FASTA file you're reading contains protein sequences, you would pass ``constructor=Protein`` to the reader call. When reading into a ``Sequence`` generator, ``constructor`` defaults to ``Sequence`` and must be a subclass of ``Sequence`` if supplied. When reading into a ``TabularMSA``, ``constructor`` is a required format parameter and must be a subclass of ``GrammaredSequence`` (e.g., ``DNA``, ``RNA``, ``Protein``). .. note:: The FASTA sniffer will not attempt to guess the ``constructor`` parameter. Sequence Reader Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``seq_num`` parameter can be used with the ``Sequence``, ``DNA``, ``RNA``, and ``Protein`` FASTA readers. ``seq_num`` specifies which sequence to read from the FASTA file (and optional QUAL file), and defaults to 1 (i.e., such that the first sequence is read). For example, to read the 50th sequence from a FASTA file, you would pass ``seq_num=50`` to the reader call. Writer-specific Parameters ^^^^^^^^^^^^^^^^^^^^^^^^^^ The following parameters are available to all FASTA format writers: - ``id_whitespace_replacement``: string to replace **each** whitespace character in a sequence ID. This parameter is useful for cases where an in-memory sequence ID contains whitespace, which would result in an on-disk representation that would not be read back into memory as the same ID (since IDs in FASTA format cannot contain whitespace). Defaults to ``_``. If ``None``, no whitespace replacement is performed and IDs are written as they are stored in memory (this has the potential to create an invalid FASTA-formatted file; see note below). This parameter also applies to a QUAL file if one is provided. - ``description_newline_replacement``: string to replace **each** newline character in a sequence description. Since a FASTA header must be a single line, newlines are not allowed in sequence descriptions and must be replaced in order to write a valid FASTA file. Defaults to a single space. If ``None``, no newline replacement is performed and descriptions are written as they are stored in memory (this has the potential to create an invalid FASTA-formatted file; see note below). This parameter also applies to a QUAL file if one is provided. - ``max_width``: integer specifying the maximum line width (i.e., number of characters) for sequence data and/or quality scores. If a sequence or its quality scores are longer than ``max_width``, it will be split across multiple lines, each with a maximum width of ``max_width``. Note that there are some caveats when splitting quality scores. A single quality score will *never* be split across multiple lines, otherwise it would become two different quality scores when read again. Thus, splitting only occurs *between* quality scores. This makes it possible to have a single long quality score written on its own line that exceeds ``max_width``. For example, the quality score ``12345`` would not be split across multiple lines even if ``max_width=3``. Thus, a 5-character line would be written. Default behavior is to not split sequence data or quality scores across multiple lines. - ``lowercase``: String or boolean array. If a string, it is treated as a key into the positional metadata of the object. If a boolean array, it indicates characters to write in lowercase. Characters in the sequence corresponding to `True` values will be written in lowercase. The boolean array must be the same length as the sequence. .. note:: The FASTA format writers will have noticeably better runtime performance if ``id_whitespace_replacement`` and/or ``description_newline_replacement`` are set to ``None`` so that whitespace replacement is not performed during writing. However, this can potentially create invalid FASTA files, especially if there are newline characters in the IDs or descriptions. For IDs with whitespace, this can also affect how the IDs are read into memory in a subsequent read operation. For example, if an in-memory sequence ID is ``'seq 1'`` and ``id_whitespace_replacement=None``, reading the FASTA file back into memory would result in an ID of ``'seq'``, and ``'1'`` would be part of the sequence description. Examples -------- Reading and Writing FASTA Files ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Suppose we have the following FASTA file with five equal-length sequences (example modified from [6]_):: >seq1 Turkey AAGCTNGGGCATTTCAGGGTGAGCCCGGGCAATACAGGGTAT >seq2 Salmo gair AAGCCTTGGCAGTGCAGGGTGAGCCGTGG CCGGGCACGGTAT >seq3 H. Sapiens ACCGGTTGGCCGTTCAGGGTACAGGTTGGCCGTTCAGGGTAA >seq4 Chimp AAACCCTTGCCG TTACGCTTAAAC CGAGGCCGGGAC ACTCAT >seq5 Gorilla AAACCCTTGCCGGTACGCTTAAACCATTGCCGGTACGCTTAA .. note:: Original copyright notice for the above example file: *(c) Copyright 1986-2008 by The University of Washington. Written by Joseph Felsenstein. Permission is granted to copy this document provided that no fee is charged for it and that this copyright notice is not removed.* Note that the sequences are not required to be of equal length in order for the file to be a valid FASTA file (this depends on the object that you're reading the file into). Also note that some of the sequences occur on a single line, while others are split across multiple lines. Let's define this file in-memory as a ``StringIO``, though this could be a real file path, file handle, or anything that's supported by scikit-bio's I/O registry in practice: >>> fl = [">seq1 Turkey\n", ... "AAGCTNGGGCATTTCAGGGTGAGCCCGGGCAATACAGGGTAT\n", ... ">seq2 Salmo gair\n", ... "AAGCCTTGGCAGTGCAGGGTGAGCCGTGG\n", ... "CCGGGCACGGTAT\n", ... ">seq3 H. Sapiens\n", ... "ACCGGTTGGCCGTTCAGGGTACAGGTTGGCCGTTCAGGGTAA\n", ... ">seq4 Chimp\n", ... "AAACCCTTGCCG\n", ... "TTACGCTTAAAC\n", ... "CGAGGCCGGGAC\n", ... "ACTCAT\n", ... ">seq5 Gorilla\n", ... "AAACCCTTGCCGGTACGCTTAAACCATTGCCGGTACGCTTAA\n"] Since these sequences are of equal length (presumably because they've been aligned), let's read the FASTA file into a ``TabularMSA`` object: >>> from skbio import TabularMSA, DNA >>> msa = TabularMSA.read(fl, constructor=DNA) >>> msa TabularMSA[DNA] ------------------------------------------ Stats: sequence count: 5 position count: 42 ------------------------------------------ AAGCTNGGGCATTTCAGGGTGAGCCCGGGCAATACAGGGTAT AAGCCTTGGCAGTGCAGGGTGAGCCGTGGCCGGGCACGGTAT ACCGGTTGGCCGTTCAGGGTACAGGTTGGCCGTTCAGGGTAA AAACCCTTGCCGTTACGCTTAAACCGAGGCCGGGACACTCAT AAACCCTTGCCGGTACGCTTAAACCATTGCCGGTACGCTTAA Note that we didn't specify a file format in the ``read`` call. The FASTA sniffer detected the correct file format for us! To write the ``TabularMSA`` in FASTA format: >>> from io import StringIO >>> with StringIO() as fh: ... print(msa.write(fh).getvalue()) >seq1 Turkey AAGCTNGGGCATTTCAGGGTGAGCCCGGGCAATACAGGGTAT >seq2 Salmo gair AAGCCTTGGCAGTGCAGGGTGAGCCGTGGCCGGGCACGGTAT >seq3 H. Sapiens ACCGGTTGGCCGTTCAGGGTACAGGTTGGCCGTTCAGGGTAA >seq4 Chimp AAACCCTTGCCGTTACGCTTAAACCGAGGCCGGGACACTCAT >seq5 Gorilla AAACCCTTGCCGGTACGCTTAAACCATTGCCGGTACGCTTAA ``TabularMSA`` loads all of the sequences from the FASTA file into memory at once. If the FASTA file is large (which is often the case), this may be infeasible if you don't have enough memory. To work around this issue, you can stream the sequences using scikit-bio's generator-based FASTA reader and writer. The generator-based reader yields ``Sequence`` objects (or subclasses if ``constructor`` is supplied) one at a time, instead of loading all sequences into memory. For example, let's use the generator-based reader to process a single sequence at a time in a ``for`` loop: >>> import skbio.io >>> for seq in skbio.io.read(fl, format='fasta'): ... seq ... print('') Sequence ------------------------------------------------ Metadata: 'description': 'Turkey' 'id': 'seq1' Stats: length: 42 ------------------------------------------------ 0 AAGCTNGGGC ATTTCAGGGT GAGCCCGGGC AATACAGGGT AT Sequence ------------------------------------------------ Metadata: 'description': 'Salmo gair' 'id': 'seq2' Stats: length: 42 ------------------------------------------------ 0 AAGCCTTGGC AGTGCAGGGT GAGCCGTGGC CGGGCACGGT AT Sequence ------------------------------------------------ Metadata: 'description': 'H. Sapiens' 'id': 'seq3' Stats: length: 42 ------------------------------------------------ 0 ACCGGTTGGC CGTTCAGGGT ACAGGTTGGC CGTTCAGGGT AA Sequence ------------------------------------------------ Metadata: 'description': 'Chimp' 'id': 'seq4' Stats: length: 42 ------------------------------------------------ 0 AAACCCTTGC CGTTACGCTT AAACCGAGGC CGGGACACTC AT Sequence ------------------------------------------------ Metadata: 'description': 'Gorilla' 'id': 'seq5' Stats: length: 42 ------------------------------------------------ 0 AAACCCTTGC CGGTACGCTT AAACCATTGC CGGTACGCTT AA A single sequence can also be read into a ``Sequence`` (or subclass): >>> from skbio import Sequence >>> seq = Sequence.read(fl) >>> seq Sequence ------------------------------------------------ Metadata: 'description': 'Turkey' 'id': 'seq1' Stats: length: 42 ------------------------------------------------ 0 AAGCTNGGGC ATTTCAGGGT GAGCCCGGGC AATACAGGGT AT By default, the first sequence in the FASTA file is read. This can be controlled with ``seq_num``. For example, to read the fifth sequence: >>> seq = Sequence.read(fl, seq_num=5) >>> seq Sequence ------------------------------------------------ Metadata: 'description': 'Gorilla' 'id': 'seq5' Stats: length: 42 ------------------------------------------------ 0 AAACCCTTGC CGGTACGCTT AAACCATTGC CGGTACGCTT AA We can use the same API to read the fifth sequence into a ``DNA`` sequence: >>> dna_seq = DNA.read(fl, seq_num=5) >>> dna_seq DNA ------------------------------------------------ Metadata: 'description': 'Gorilla' 'id': 'seq5' Stats: length: 42 has gaps: False has degenerates: False has definites: True GC-content: 50.00% ------------------------------------------------ 0 AAACCCTTGC CGGTACGCTT AAACCATTGC CGGTACGCTT AA Individual sequence objects can also be written in FASTA format: >>> with StringIO() as fh: ... print(dna_seq.write(fh).getvalue()) >seq5 Gorilla AAACCCTTGCCGGTACGCTTAAACCATTGCCGGTACGCTTAA Reading and Writing FASTA/QUAL Files ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In addition to reading and writing standalone FASTA files, scikit-bio supports reading and writing FASTA and QUAL files together. Suppose we have the following FASTA file:: >seq1 db-accession-149855 CGATGTC >seq2 db-accession-34989 CATCGTC Also suppose we have the following QUAL file:: >seq1 db-accession-149855 40 39 39 4 50 1 100 >seq2 db-accession-34989 3 3 10 42 80 80 79 >>> fasta_fl = [ ... ">seq1 db-accession-149855\n", ... "CGATGTC\n", ... ">seq2 db-accession-34989\n", ... "CATCGTC\n"] >>> qual_fl = [ ... ">seq1 db-accession-149855\n", ... "40 39 39 4\n", ... "50 1 100\n", ... ">seq2 db-accession-34989\n", ... "3 3 10 42 80 80 79\n"] To read in a single ``Sequence`` at a time, we can use the generator-based reader as we did above, providing both FASTA and QUAL files: >>> for seq in skbio.io.read(fasta_fl, qual=qual_fl, format='fasta'): ... seq ... print('') Sequence ---------------------------------------- Metadata: 'description': 'db-accession-149855' 'id': 'seq1' Positional metadata: 'quality': Stats: length: 7 ---------------------------------------- 0 CGATGTC Sequence --------------------------------------- Metadata: 'description': 'db-accession-34989' 'id': 'seq2' Positional metadata: 'quality': Stats: length: 7 --------------------------------------- 0 CATCGTC Note that the sequence objects have quality scores stored as positional metadata since we provided a QUAL file. The other FASTA readers operate in a similar manner. Now let's load the sequences and their quality scores into a ``TabularMSA``: >>> msa = TabularMSA.read(fasta_fl, qual=qual_fl, constructor=DNA) >>> msa TabularMSA[DNA] --------------------- Stats: sequence count: 2 position count: 7 --------------------- CGATGTC CATCGTC To write the sequence data and quality scores in the ``TabularMSA`` to FASTA and QUAL files, respectively: >>> new_fasta_fh = StringIO() >>> new_qual_fh = StringIO() >>> _ = msa.write(new_fasta_fh, qual=new_qual_fh) >>> print(new_fasta_fh.getvalue()) >seq1 db-accession-149855 CGATGTC >seq2 db-accession-34989 CATCGTC >>> print(new_qual_fh.getvalue()) >seq1 db-accession-149855 40 39 39 4 50 1 100 >seq2 db-accession-34989 3 3 10 42 80 80 79 >>> new_fasta_fh.close() >>> new_qual_fh.close() Reading multi-FASTA Files ^^^^^^^^^^^^^^^^^^^^^^^^^ Suppose you have a multi-FASTA file and want to read each sequence into a ``DNA`` object in a list. We'll be using ``io.StringIO`` to make a mock FASTA file in memory. >>> from io import StringIO >>> import skbio >>> from skbio.sequence import DNA >>> fl = ">seq1 Turkey\n" +\ ... "AAGCTNGGGCATTTCAGGGTGAGCCCGGGCAATACAGGGTAT\n" +\ ... ">seq2 Salmo gair\n" +\ ... "AAGCCTTGGCAGTGCAGGGTGAGCCGTGG\n" +\ ... "CCGGGCACGGTAT\n" +\ ... ">seq3 H. Sapiens\n" +\ ... "ACCGGTTGGCCGTTCAGGGTACAGGTTGGCCGTTCAGGGTAA\n" +\ ... ">seq4 Chimp\n" +\ ... "AAACCCTTGCCG\n" +\ ... "TTACGCTTAAAC\n" +\ ... "CGAGGCCGGGAC\n" +\ ... "ACTCAT\n" +\ ... ">seq5 Gorilla\n" +\ ... "AAACCCTTGCCGGTACGCTTAAACCATTGCCGGTACGCTTAA\n" >>> mock_fl = StringIO(fl) The following code will read the sequences into scikit-bio. In practice, ``mock_fl`` may be replaced with an opened file handle, or the path to the file. >>> res = list(skbio.io.read(mock_fl, format="fasta", constructor=DNA)) >>> res[0] DNA ------------------------------------------------ Metadata: 'description': 'Turkey' 'id': 'seq1' Stats: length: 42 has gaps: False has degenerates: True has definites: True GC-content: 54.76% ------------------------------------------------ 0 AAGCTNGGGC ATTTCAGGGT GAGCCCGGGC AATACAGGGT AT >>> res[1] DNA ------------------------------------------------ Metadata: 'description': 'Salmo gair' 'id': 'seq2' Stats: length: 42 has gaps: False has degenerates: False has definites: True GC-content: 66.67% ------------------------------------------------ 0 AAGCCTTGGC AGTGCAGGGT GAGCCGTGGC CGGGCACGGT AT References ---------- .. [1] Lipman, DJ; Pearson, WR (1985). "Rapid and sensitive protein similarity searches". Science 227 (4693): 1435-41. .. [2] http://en.wikipedia.org/wiki/FASTA_format .. [3] http://blast.ncbi.nlm.nih.gov/blastcgihelp.shtml .. [4] https://www.broadinstitute.org/crd/wiki/index.php/Qual .. [5] Madden T. The BLAST Sequence Analysis Tool. 2002 Oct 9 [Updated 2003 Aug 13]. In: McEntyre J, Ostell J, editors. The NCBI Handbook [Internet]. Bethesda (MD): National Center for Biotechnology Information (US); 2002-. Chapter 16. Available from: http://www.ncbi.nlm.nih.gov/books/NBK21097/ .. [6] http://evolution.genetics.washington.edu/phylip/doc/sequence.html """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import itertools import textwrap import numpy as np from skbio.io import create_format, FASTAFormatError, QUALFormatError from skbio.io.registry import FileSentinel from skbio.io.format._base import ( _get_nth_sequence, _parse_fasta_like_header, _format_fasta_like_records, _line_generator, _too_many_blanks, ) from skbio.util._misc import chunk_str from skbio.alignment import TabularMSA from skbio.sequence import Sequence, DNA, RNA, Protein fasta = create_format("fasta") @fasta.sniffer() def _fasta_sniffer(fh): # Strategy: # Ignore up to 5 blank/whitespace-only lines at the beginning of the # file. Read up to 10 records. If at least one record is read (i.e. # the file isn't empty) and no errors are thrown during reading, assume # the file is in FASTA format. If a record appears to be QUAL, do *not* # identify the file as FASTA since we don't want to sniff QUAL files as # FASTA (technically they can be read as FASTA since the sequences may # not be validated but it probably isn't what the user wanted). Also, if # we add QUAL as its own file format in the future, we wouldn't want the # FASTA and QUAL sniffers to both positively identify a QUAL file. if _too_many_blanks(fh, 5): return False, {} num_records = 10 empty = True try: parser = _parse_fasta_raw(fh, _sniffer_data_parser, FASTAFormatError) for _ in zip(range(num_records), parser): empty = False except FASTAFormatError: return False, {} if empty: return False, {} else: return True, {} def _sniffer_data_parser(chunks): data = _parse_sequence_data(chunks) try: _parse_quality_scores(chunks) except QUALFormatError: return data else: # used for flow control within sniffer, user should never see this # message raise FASTAFormatError("Data appear to be quality scores.") @fasta.reader(None) def _fasta_to_generator( fh, cls=None, qual=FileSentinel, constructor=Sequence, **kwargs ): kwargs = kwargs.copy() if "keep_spaces" in kwargs: kwarg = {"keep_spaces": kwargs.pop("keep_spaces")} else: kwarg = {} if qual is None: for seq, id_, desc in _parse_fasta_raw( fh, _parse_sequence_data, FASTAFormatError, **kwarg ): yield constructor(seq, metadata={"id": id_, "description": desc}, **kwargs) else: fasta_gen = _parse_fasta_raw( fh, _parse_sequence_data, FASTAFormatError, **kwarg ) qual_gen = _parse_fasta_raw( qual, _parse_quality_scores, QUALFormatError, **kwarg ) for fasta_rec, qual_rec in itertools.zip_longest( fasta_gen, qual_gen, fillvalue=None ): if fasta_rec is None: raise FASTAFormatError("QUAL file has more records than FASTA file.") if qual_rec is None: raise FASTAFormatError("FASTA file has more records than QUAL file.") fasta_seq, fasta_id, fasta_desc = fasta_rec qual_scores, qual_id, qual_desc = qual_rec if fasta_id != qual_id: raise FASTAFormatError( "IDs do not match between FASTA and QUAL records: %r != %r" % (str(fasta_id), str(qual_id)) ) if fasta_desc != qual_desc: raise FASTAFormatError( "Descriptions do not match between FASTA and QUAL " "records: %r != %r" % (str(fasta_desc), str(qual_desc)) ) # sequence and quality scores lengths are checked in constructor yield constructor( fasta_seq, metadata={"id": fasta_id, "description": fasta_desc}, positional_metadata={"quality": qual_scores}, **kwargs, ) @fasta.reader(Sequence) def _fasta_to_sequence(fh, cls=None, qual=FileSentinel, seq_num=1, **kwargs): if cls is None: cls = Sequence return _get_nth_sequence( _fasta_to_generator(fh, qual=qual, constructor=cls, **kwargs), seq_num ) @fasta.reader(DNA) def _fasta_to_dna(fh, cls=None, qual=FileSentinel, seq_num=1, **kwargs): if cls is None: cls = DNA return _get_nth_sequence( _fasta_to_generator(fh, qual=qual, constructor=cls, **kwargs), seq_num ) @fasta.reader(RNA) def _fasta_to_rna(fh, cls=None, qual=FileSentinel, seq_num=1, **kwargs): if cls is None: cls = RNA return _get_nth_sequence( _fasta_to_generator(fh, qual=qual, constructor=cls, **kwargs), seq_num ) @fasta.reader(Protein) def _fasta_to_protein(fh, cls=None, qual=FileSentinel, seq_num=1, **kwargs): if cls is None: cls = Protein return _get_nth_sequence( _fasta_to_generator(fh, qual=qual, constructor=cls, **kwargs), seq_num ) @fasta.reader(TabularMSA) def _fasta_to_tabular_msa(fh, cls=None, qual=FileSentinel, constructor=None, **kwargs): if cls is None: cls = TabularMSA if constructor is None: raise ValueError("Must provide `constructor`.") return cls( _fasta_to_generator(fh, qual=qual, constructor=constructor, **kwargs), minter="id", ) @fasta.writer(None) def _generator_to_fasta( obj, fh, qual=FileSentinel, id_whitespace_replacement="_", description_newline_replacement=" ", max_width=None, lowercase=None, ): if max_width is not None: if max_width < 1: raise ValueError( "Maximum line width must be greater than zero (max_width=%d)." % max_width ) if qual is not None: # define text wrapper for splitting quality scores here for # efficiency. textwrap docs recommend reusing a TextWrapper # instance when it is used many times. configure text wrapper to # never break "words" (i.e., integer quality scores) across lines qual_wrapper = textwrap.TextWrapper( width=max_width, break_long_words=False, break_on_hyphens=False ) formatted_records = _format_fasta_like_records( obj, id_whitespace_replacement, description_newline_replacement, qual is not None, lowercase, ) for header, seq_str, qual_scores in formatted_records: if max_width is not None: seq_str = chunk_str(seq_str, max_width, "\n") fh.write(">%s\n%s\n" % (header, seq_str)) if qual is not None: qual_str = " ".join(np.asarray(qual_scores, dtype=str)) if max_width is not None: qual_str = qual_wrapper.fill(qual_str) qual.write(">%s\n%s\n" % (header, qual_str)) @fasta.writer(Sequence) def _sequence_to_fasta( obj, fh, qual=FileSentinel, id_whitespace_replacement="_", description_newline_replacement=" ", max_width=None, lowercase=None, ): _sequences_to_fasta( [obj], fh, qual, id_whitespace_replacement, description_newline_replacement, max_width, lowercase, ) @fasta.writer(DNA) def _dna_to_fasta( obj, fh, qual=FileSentinel, id_whitespace_replacement="_", description_newline_replacement=" ", max_width=None, lowercase=None, ): _sequences_to_fasta( [obj], fh, qual, id_whitespace_replacement, description_newline_replacement, max_width, lowercase, ) @fasta.writer(RNA) def _rna_to_fasta( obj, fh, qual=FileSentinel, id_whitespace_replacement="_", description_newline_replacement=" ", max_width=None, lowercase=None, ): _sequences_to_fasta( [obj], fh, qual, id_whitespace_replacement, description_newline_replacement, max_width, lowercase, ) @fasta.writer(Protein) def _protein_to_fasta( obj, fh, qual=FileSentinel, id_whitespace_replacement="_", description_newline_replacement=" ", max_width=None, lowercase=None, ): _sequences_to_fasta( [obj], fh, qual, id_whitespace_replacement, description_newline_replacement, max_width, lowercase, ) @fasta.writer(TabularMSA) def _tabular_msa_to_fasta( obj, fh, qual=FileSentinel, id_whitespace_replacement="_", description_newline_replacement=" ", max_width=None, lowercase=None, ): _sequences_to_fasta( obj, fh, qual, id_whitespace_replacement, description_newline_replacement, max_width, lowercase, ) def _parse_fasta_raw(fh, data_parser, error_type, keep_spaces=False): """Raw parser for FASTA or QUAL files. Returns raw values (seq/qual, id, description). It is the responsibility of the caller to construct the correct in-memory object to hold the data. """ # Skip any blank or whitespace-only lines at beginning of file try: seq_header = next(_line_generator(fh, skip_blanks=True)) except StopIteration: return # header check inlined here and below for performance if seq_header.startswith(">"): id_, desc = _parse_fasta_like_header(seq_header) else: raise error_type( "Found non-header line when attempting to read the 1st record:" "\n%s" % seq_header ) # will remove spaces from each sequence (but not quality scores) trim_spaces = data_parser.__name__ == "_parse_sequence_data" and not keep_spaces data_chunks = [] prev = seq_header for line in _line_generator(fh, skip_blanks=False): if line.startswith(">"): # new header, so yield current record and reset state yield data_parser(data_chunks), id_, desc data_chunks = [] id_, desc = _parse_fasta_like_header(line) elif line: # ensure no blank lines within a single record if not prev: raise error_type("Found blank or whitespace-only line within record.") if trim_spaces: line = line.replace(" ", "") data_chunks.append(line) prev = line # yield last record in file yield data_parser(data_chunks), id_, desc def _parse_sequence_data(chunks): if not chunks: raise FASTAFormatError("Found header without sequence data.") return "".join(chunks) def _parse_quality_scores(chunks): if not chunks: raise QUALFormatError("Found header without quality scores.") qual_str = " ".join(chunks) try: quality = np.asarray(qual_str.split(), dtype=np.int64) except ValueError: raise QUALFormatError( "Could not convert quality scores to integers:\n%s" % str(qual_str) ) if (quality < 0).any(): raise QUALFormatError( "Encountered negative quality score(s). Quality scores must be " "greater than or equal to zero." ) if (quality > 255).any(): raise QUALFormatError( "Encountered quality score(s) greater than 255. scikit-bio only " "supports quality scores in the range 0-255 (inclusive) when " "reading QUAL files." ) return quality.astype(np.uint8, casting="unsafe", copy=False) def _sequences_to_fasta( obj, fh, qual, id_whitespace_replacement, description_newline_replacement, max_width, lowercase=None, ): def seq_gen(): yield from obj _generator_to_fasta( seq_gen(), fh, qual=qual, id_whitespace_replacement=id_whitespace_replacement, description_newline_replacement=description_newline_replacement, max_width=max_width, lowercase=lowercase, ) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/fastq.py000066400000000000000000000536051520735541300230620ustar00rootroot00000000000000r"""FASTQ format (:mod:`skbio.io.format.fastq`) =========================================== .. currentmodule:: skbio.io.format.fastq The FASTQ file format (``fastq``) stores biological (e.g., nucleotide) sequences and their quality scores in a simple plain text format that is both human-readable and easy to parse. The file format was invented by Jim Mullikin at the Wellcome Trust Sanger Institute but wasn't given a formal definition, though it has informally become a standard file format for storing high-throughput sequence data. More information about the format and its variants can be found in [1]_ and [2]_. Conceptually, a FASTQ file is similar to paired FASTA and QUAL files in that it stores both biological sequences and their quality scores. FASTQ differs from FASTA/QUAL because the quality scores are stored in the same file as the biological sequence data. An example FASTQ-formatted file containing two DNA sequences and their quality scores: .. code-block:: none @seq1 description 1 AACACCAAACTTCTCCACCACGTGAGCTACAAAAG + ````Y^T]`]c^cabcacc`^Lb^ccYT\T\Y\WF @seq2 description 2 TATGTATATATAACATATACATATATACATACATA + ]KZ[PY]_[YY^```ac^\\`bT``c`\aT``bbb Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |generator of :mod:`skbio.sequence.Sequence` objects | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.alignment.TabularMSA` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.Sequence` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.DNA` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.RNA` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.Protein` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- A FASTQ file contains one or more biological sequences and their corresponding quality scores stored sequentially as *records*. Each *record* consists of four sections: 1. Sequence header line consisting of a sequence identifier (ID) and description (both optional) 2. Biological sequence data (typically stored using the standard IUPAC lexicon), optionally split over multiple lines 3. Quality header line separating sequence data from quality scores (optionally repeating the ID and description from the sequence header line) 4. Quality scores as printable ASCII characters, optionally split over multiple lines. Decoding of quality scores will depend on the specified FASTQ variant (see below for more details) For the complete FASTQ format specification, see [1]_. scikit-bio's FASTQ implementation follows the format specification described in this excellent publication, including validating the implementation against the FASTQ example files provided in the publication's supplementary data. .. note:: IDs and descriptions will be parsed from sequence header lines in exactly the same way as FASTA headers (:mod:`skbio.io.format.fasta`). IDs, descriptions, and quality scores are also stored on, and written from, sequence objects in the same way as with FASTA. .. note:: Blank or whitespace-only lines are only allowed at the beginning of the file, between FASTQ records, or at the end of the file. A blank or whitespace-only line after the header line, within the sequence, or within quality scores will raise an error. scikit-bio will ignore leading and trailing whitespace characters on each line while reading. .. note:: Validation may be performed depending on the type of object the data is being read into. This behavior matches that of FASTA files. .. note:: scikit-bio will write FASTQ files in a normalized format, with each record section on a single line. Thus, each record will be composed of *exactly* four lines. The quality header line won't have the sequence ID and description repeated. .. note:: `lowercase` functionality is supported the same as with FASTA. Quality Score Variants ^^^^^^^^^^^^^^^^^^^^^^ FASTQ associates quality scores with sequence data, with each quality score encoded as a single printable ASCII character. In scikit-bio, all quality scores are decoded as Phred quality scores. This is the most common quality score metric, though there are others (e.g., Solexa quality scores). Unfortunately, different sequencers have different ways of encoding quality scores as ASCII characters, notably Sanger and Illumina. Below is a table highlighting the different encoding variants supported by scikit-bio, as well as listing the equivalent variant names used in the Open Bioinformatics Foundation (OBF) [3]_ projects (e.g., Biopython, BioPerl, etc.). +-----------+---------+----+--------+-----------------------------------------+ | Variant | ASCII |Off\|Quality | Notes | | | Range |set |Range | | +===========+=========+====+========+=========================================+ |sanger |33 to 126|33 |0 to 93 |Equivalent to OBF's fastq-sanger. | +-----------+---------+----+--------+-----------------------------------------+ |illumina1.3|64 to 126|64 |0 to 62 |Equivalent to OBF's fastq-illumina. Use | | | | | |this if your data was generated using | | | | | |Illumina 1.3-1.7 software. | +-----------+---------+----+--------+-----------------------------------------+ |illumina1.8|33 to 95 |33 |0 to 62 |Equivalent to sanger but with 0 to 62 | | | | | |quality score range check. Use this if | | | | | |your data was generated using Illumina | | | | | |1.8 software or later. | +-----------+---------+----+--------+-----------------------------------------+ |solexa |59 to 126|64 |-5 to 62|Not currently implemented. | +-----------+---------+----+--------+-----------------------------------------+ .. note:: When writing, Phred quality scores will be truncated to the maximum value in the variant's range and a warning will be issued. This is consistent with the OBF projects. When reading, an error will be raised if a decoded quality score is outside the variant's range. Format Parameters ----------------- The following parameters are available to all FASTQ format readers and writers: - ``variant``: A string indicating the quality score variant used to decode/encode Phred quality scores. Must be one of ``sanger``, ``illumina1.3``, ``illumina1.8``, or ``solexa``. This parameter is preferred over ``phred_offset`` because additional quality score range checks and conversions can be performed. It is also more explicit. - ``phred_offset``: An integer indicating the ASCII code offset used to decode/encode Phred quality scores. Must be in the range ``[33, 126]``. All decoded scores will be assumed to be Phred scores (i.e., no additional conversions are performed). Prefer using ``variant`` over this parameter whenever possible. .. note:: You must provide ``variant`` or ``phred_offset`` when reading or writing a FASTQ file. ``variant`` and ``phred_offset`` cannot both be provided at the same time. The following additional parameters are the same as in FASTA format (:mod:`skbio.io.format.fasta`): - ``constructor``: see ``constructor`` parameter in FASTA format - ``seq_num``: see ``seq_num`` parameter in FASTA format - ``id_whitespace_replacement``: see ``id_whitespace_replacement`` parameter in FASTA format - ``description_newline_replacement``: see ``description_newline_replacement`` parameter in FASTA format - ``lowercase``: see ``lowercase`` parameter in FASTA format Examples -------- Suppose we have the following FASTQ file with two DNA sequences:: @seq1 description 1 AACACCAAACTTCTCCACC ACGTGAGCTACAAAAG +seq1 description 1 ''''Y^T]']C^CABCACC `^LB^CCYT\T\Y\WF @seq2 description 2 TATGTATATATAACATATACATATATACATACATA + ]KZ[PY]_[YY^'''AC^\\'BT''C'\AT''BBB Note that the first sequence and its quality scores are split across multiple lines, while the second sequence and its quality scores are each on a single line. Also note that the first sequence has a duplicate ID and description on the quality header line, while the second sequence does not. Let's define this file in-memory as a ``StringIO``, though this could be a real file path, file handle, or anything that's supported by scikit-bio's I/O registry in practice: >>> from io import StringIO >>> fs = '\n'.join([ ... r"@seq1 description 1", ... r"AACACCAAACTTCTCCACC", ... r"ACGTGAGCTACAAAAG", ... r"+seq1 description 1", ... r"''''Y^T]']C^CABCACC", ... r"'^LB^CCYT\T\Y\WF", ... r"@seq2 description 2", ... r"TATGTATATATAACATATACATATATACATACATA", ... r"+", ... r"]KZ[PY]_[YY^'''AC^\\'BT''C'\AT''BBB"]) >>> fh = StringIO(fs) To load the sequences into a ``TabularMSA``, we run: >>> from skbio import TabularMSA, DNA >>> msa = TabularMSA.read(fh, constructor=DNA, variant='sanger') >>> msa TabularMSA[DNA] ----------------------------------- Stats: sequence count: 2 position count: 35 ----------------------------------- AACACCAAACTTCTCCACCACGTGAGCTACAAAAG TATGTATATATAACATATACATATATACATACATA Note that quality scores are decoded from Sanger. To load the second sequence as ``DNA``: >>> fh = StringIO(fs) # reload the StringIO to read from the beginning again >>> seq = DNA.read(fh, variant='sanger', seq_num=2) >>> seq DNA ---------------------------------------- Metadata: 'description': 'description 2' 'id': 'seq2' Positional metadata: 'quality': Stats: length: 35 has gaps: False has degenerates: False has definites: True GC-content: 14.29% ---------------------------------------- 0 TATGTATATA TAACATATAC ATATATACAT ACATA To write our ``TabularMSA`` to a FASTQ file with quality scores encoded using the ``illumina1.3`` variant: >>> new_fh = StringIO() >>> print(msa.write(new_fh, format='fastq', variant='illumina1.3').getvalue()) @seq1 description 1 AACACCAAACTTCTCCACCACGTGAGCTACAAAAG + FFFFx}s|F|b}b`ab`bbF}ka}bbxs{s{x{ve @seq2 description 2 TATGTATATATAACATATACATATATACATACATA + |jyzox|~zxx}FFF`b}{{FasFFbF{`sFFaaa >>> new_fh.close() Note that the file has been written in normalized format: sequence and quality scores each only occur on a single line and the sequence header line is not repeated in the quality header line. Note also that the quality scores are different because they have been encoded using a different variant. References ---------- .. [1] Peter J. A. Cock, Christopher J. Fields, Naohisa Goto, Michael L. Heuer, and Peter M. Rice. The Sanger FASTQ file format for sequences with quality scores, and the Solexa/Illumina FASTQ variants. Nucl. Acids Res. (2010) 38 (6): 1767-1771. first published online December 16, 2009. doi:10.1093/nar/gkp1137 http://nar.oxfordjournals.org/content/38/6/1767 .. [2] http://en.wikipedia.org/wiki/FASTQ_format .. [3] http://www.open-bio.org/ """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import re import numpy as np from skbio.io import create_format, FASTQFormatError from skbio.io.format._base import ( _decode_qual_to_phred, _encode_phred_to_qual, _get_nth_sequence, _parse_fasta_like_header, _format_fasta_like_records, _line_generator, _too_many_blanks, ) from skbio.alignment import TabularMSA from skbio.sequence import Sequence, DNA, RNA, Protein _whitespace_regex = re.compile(r"\s") fastq = create_format("fastq") @fastq.sniffer() def _fastq_sniffer(fh): # Strategy: # Ignore up to 5 blank/whitespace-only lines at the beginning of the # file. Read up to 10 records. If at least one record is read (i.e. the # file isn't empty) and the quality scores are in printable ASCII range, # assume the file is FASTQ. if _too_many_blanks(fh, 5): return False, {} try: not_empty = False for _, seq in zip(range(10), _fastq_to_generator(fh, phred_offset=33)): split_length = len( (seq.metadata["id"] + seq.metadata["description"]).split(":") ) description = seq.metadata["description"].split(":") if split_length == 10 and description[1] in "YN": return True, {"variant": "illumina1.8"} not_empty = True return not_empty, {} except (FASTQFormatError, ValueError): return False, {} @fastq.reader(None) def _fastq_to_generator( fh, cls=None, variant=None, phred_offset=None, constructor=Sequence, **kwargs ): # Skip any blank or whitespace-only lines at beginning of file try: seq_header = next(_line_generator(fh, skip_blanks=True)) except StopIteration: return if not seq_header.startswith("@"): raise FASTQFormatError( "Expected sequence (@) header line at start of file: %r" % str(seq_header) ) while seq_header is not None: id_, desc = _parse_fasta_like_header(seq_header) seq, qual_header = _parse_sequence_data(fh, seq_header) if qual_header != "+" and qual_header[1:] != seq_header[1:]: raise FASTQFormatError( "Sequence (@) and quality (+) header lines do not match: " "%r != %r" % (str(seq_header[1:]), str(qual_header[1:])) ) phred_scores, seq_header = _parse_quality_scores( fh, len(seq), variant, phred_offset, qual_header ) yield constructor( seq, metadata={"id": id_, "description": desc}, positional_metadata={"quality": phred_scores}, **kwargs, ) @fastq.reader(Sequence) def _fastq_to_sequence( fh, cls=None, variant=None, phred_offset=None, seq_num=1, **kwargs ): if cls is None: cls = Sequence return _get_nth_sequence( _fastq_to_generator( fh, variant=variant, phred_offset=phred_offset, constructor=cls, **kwargs, ), seq_num, ) @fastq.reader(DNA) def _fastq_to_dna(fh, cls=None, variant=None, phred_offset=None, seq_num=1, **kwargs): if cls is None: cls = DNA return _get_nth_sequence( _fastq_to_generator( fh, variant=variant, phred_offset=phred_offset, constructor=cls, **kwargs ), seq_num, ) @fastq.reader(RNA) def _fastq_to_rna(fh, cls=None, variant=None, phred_offset=None, seq_num=1, **kwargs): if cls is None: cls = RNA return _get_nth_sequence( _fastq_to_generator( fh, variant=variant, phred_offset=phred_offset, constructor=cls, **kwargs ), seq_num, ) @fastq.reader(Protein) def _fastq_to_protein( fh, cls=None, variant=None, phred_offset=None, seq_num=1, **kwargs ): if cls is None: cls = Protein return _get_nth_sequence( _fastq_to_generator( fh, variant=variant, phred_offset=phred_offset, constructor=cls, **kwargs, ), seq_num, ) @fastq.reader(TabularMSA) def _fastq_to_tabular_msa( fh, cls=None, variant=None, phred_offset=None, constructor=None, **kwargs ): if cls is None: cls = TabularMSA if constructor is None: raise ValueError("Must provide `constructor`.") return cls( _fastq_to_generator( fh, variant=variant, phred_offset=phred_offset, constructor=constructor, **kwargs, ), minter="id", ) @fastq.writer(None) def _generator_to_fastq( obj, fh, variant=None, phred_offset=None, id_whitespace_replacement="_", description_newline_replacement=" ", lowercase=None, ): formatted_records = _format_fasta_like_records( obj, id_whitespace_replacement, description_newline_replacement, True, lowercase=lowercase, ) for header, seq_str, qual_scores in formatted_records: qual_str = _encode_phred_to_qual( qual_scores, variant=variant, phred_offset=phred_offset ) fh.write("@") fh.write(header) fh.write("\n") fh.write(seq_str) fh.write("\n+\n") fh.write(qual_str) fh.write("\n") @fastq.writer(Sequence) def _sequence_to_fastq( obj, fh, variant=None, phred_offset=None, id_whitespace_replacement="_", description_newline_replacement=" ", lowercase=None, ): _sequences_to_fastq( [obj], fh, variant, phred_offset, id_whitespace_replacement, description_newline_replacement, lowercase=lowercase, ) @fastq.writer(DNA) def _dna_to_fastq( obj, fh, variant=None, phred_offset=None, id_whitespace_replacement="_", description_newline_replacement=" ", lowercase=None, ): _sequences_to_fastq( [obj], fh, variant, phred_offset, id_whitespace_replacement, description_newline_replacement, lowercase=lowercase, ) @fastq.writer(RNA) def _rna_to_fastq( obj, fh, variant=None, phred_offset=None, id_whitespace_replacement="_", description_newline_replacement=" ", lowercase=None, ): _sequences_to_fastq( [obj], fh, variant, phred_offset, id_whitespace_replacement, description_newline_replacement, lowercase=lowercase, ) @fastq.writer(Protein) def _protein_to_fastq( obj, fh, variant=None, phred_offset=None, id_whitespace_replacement="_", description_newline_replacement=" ", lowercase=None, ): _sequences_to_fastq( [obj], fh, variant, phred_offset, id_whitespace_replacement, description_newline_replacement, lowercase=lowercase, ) @fastq.writer(TabularMSA) def _tabular_msa_to_fastq( obj, fh, variant=None, phred_offset=None, id_whitespace_replacement="_", description_newline_replacement=" ", lowercase=None, ): _sequences_to_fastq( obj, fh, variant, phred_offset, id_whitespace_replacement, description_newline_replacement, lowercase=lowercase, ) def _blank_error(unique_text): error_string = ("Found blank or whitespace-only line {} in FASTQ file").format( unique_text ) raise FASTQFormatError(error_string) def _parse_sequence_data(fh, prev): seq_chunks = [] for chunk in _line_generator(fh, skip_blanks=False): if chunk.startswith("+"): if not prev: _blank_error("before '+'") if not seq_chunks: raise FASTQFormatError("Found FASTQ record without sequence data.") return "".join(seq_chunks), chunk elif chunk.startswith("@"): raise FASTQFormatError( "Found FASTQ record that is missing a quality (+) header line " "after sequence data." ) else: if not prev: _blank_error("after header or within sequence") if _whitespace_regex.search(chunk): raise FASTQFormatError( "Found whitespace in sequence data: %r" % str(chunk) ) seq_chunks.append(chunk) prev = chunk raise FASTQFormatError("Found incomplete/truncated FASTQ record at end of file.") def _parse_quality_scores(fh, seq_len, variant, phred_offset, prev): phred_scores = [] qual_len = 0 for chunk in _line_generator(fh, skip_blanks=False): if chunk: if chunk.startswith("@") and qual_len == seq_len: return np.hstack(phred_scores), chunk else: if not prev: _blank_error("after '+' or within quality scores") qual_len += len(chunk) if qual_len > seq_len: raise FASTQFormatError( "Found more quality score characters than sequence " "characters. Extra quality score characters: %r" % chunk[-(qual_len - seq_len) :] ) phred_scores.append( _decode_qual_to_phred( chunk, variant=variant, phred_offset=phred_offset ) ) prev = chunk if qual_len != seq_len: raise FASTQFormatError( "Found incomplete/truncated FASTQ record at end of file." ) return np.hstack(phred_scores), None def _sequences_to_fastq( obj, fh, variant, phred_offset, id_whitespace_replacement, description_newline_replacement, lowercase=None, ): def seq_gen(): yield from obj _generator_to_fastq( seq_gen(), fh, variant=variant, phred_offset=phred_offset, id_whitespace_replacement=id_whitespace_replacement, description_newline_replacement=description_newline_replacement, lowercase=lowercase, ) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/genbank.py000066400000000000000000000634071520735541300233520ustar00rootroot00000000000000"""GenBank format (:mod:`skbio.io.format.genbank`) =============================================== .. currentmodule:: skbio.io.format.genbank GenBank format (GenBank Flat File Format) stores sequence and its annotation together. The start of the annotation section is marked by a line beginning with the word "LOCUS". The start of sequence section is marked by a line beginning with the word "ORIGIN" and the end of the section is marked by a line with only "//". The GenBank file usually ends with .gb or sometimes .gbk. The GenBank format for protein has been renamed to GenPept. The GenBank (for nucleotide) and Genpept are essentially the same format. An example of a GenBank file can be seen here [1]_. Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.sequence.Sequence` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.DNA` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.RNA` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.Protein` | +------+------+---------------------------------------------------------------+ |Yes | Yes | generator of :mod:`skbio.sequence.Sequence` objects | +------+------+---------------------------------------------------------------+ Format Specification -------------------- Sections before ``FEATURES`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ All the sections before ``FEATURES`` will be read into the attribute of ``metadata``. The header and its content of a section is stored as a pair of key and value in ``metadata``. For the ``REFERENCE`` section, its value is stored as a list, as there are often multiple reference sections in one GenBank record. .. _genbank_feature_section: ``FEATURES`` section ^^^^^^^^^^^^^^^^^^^^ The International Nucleotide Sequence Database Collaboration (INSDC [2]_) is a joint effort among the DDBJ, EMBL, and GenBank. These organisations all use the same "Feature Table" layout in their plain text flat file formats, which are documented in detail [3]_. The feature keys and their qualifiers are also described in this webpage [4]_. The ``FEATURES`` section will be stored in ``interval_metadata`` of ``Sequence`` or its sub-class. Each sub-section is stored as an ``Interval`` object in ``interval_metadata``. Each ``Interval`` object has ``metadata`` keeping the information of this feature in the sub-section. To normalize the vocabulary between multiple formats (currently only the INSDC Feature Table and GFF3) to store metadata of interval features, we rename some terms in some formats to the same common name when parsing them into memory, as described in this table: +-----------+-----------+-----------+---------+------------------------------+ |INSDC |GFF3 |Key stored |Value |Description | |feature |columns or | |type | | |table |attributes | |stored | | +===========+===========+===========+=========+==============================+ |inference |source |source |str |the algorithm or experiment | | |(column 2) | | |used to generate this feature | +-----------+-----------+-----------+---------+------------------------------+ |feature key|type |type |str |the type of the feature | | |(column 3) | | | | +-----------+-----------+-----------+---------+------------------------------+ |N/A |score |score |float |the score of the feature | | |(column 6) | | | | +-----------+-----------+-----------+---------+------------------------------+ |N/A |strand |strand |str |the strand of the feature. + | | |(column 7) | | |for positive strand, - for | | | | | |minus strand, and . for | | | | | |features that are not | | | | | |stranded. In addition, ? can | | | | | |be used for features whose | | | | | |strandedness is relevant, but | | | | | |unknown. | +-----------+-----------+-----------+---------+------------------------------+ |codon_start|phase |phase |int |the offset at which the first | | |(column 8) | | |complete codon of a coding | | | | | |feature can be found, relative| | | | | |to the first base of that | | | | | |feature. It is 0, 1, or 2 in | | | | | |GFF3 or 1, 2, or 3 in GenBank.| | | | | |The stored value is 0, 1, or | | | | | |2, following in GFF3 format. | +-----------+-----------+-----------+---------+------------------------------+ |db_xref |Dbxref |db_xref |list of |A database cross reference | | | | |str | | +-----------+-----------+-----------+---------+------------------------------+ |N/A |ID |ID |str |feature ID | +-----------+-----------+-----------+---------+------------------------------+ |note |Note |note |str |any comment or additional | | | | | |information | +-----------+-----------+-----------+---------+------------------------------+ |translation|N/A |translation|str |the protein sequence for CDS | | | | | |features | +-----------+-----------+-----------+---------+------------------------------+ ``Location`` string +++++++++++++++++++ There are 5 types of location descriptors defined in Feature Table. This explains how they will be parsed into the bounds of ``Interval`` object (note it converts the 1-based coordinate to 0-based): 1. a single base number. e.g. 67. This is parsed to ``(66, 67)``. 2. a site between two neighboring bases. e.g. 67^68. This is parsed to ``(66, 67)``. 3. a single base from inside a range. e.g. 67.89. This is parsed to ``(66, 89)``. 4. a pair of base numbers defining a sequence span. e.g. 67..89. This is parsed to ``(66, 89)``. 5. a remote sequence identifier followed by a location descriptor defined above. e.g. J00123.1:67..89. This will be discarded because it is not on the current sequence. When it is combined with local descriptor like J00123.1:67..89,200..209, the local part will be kept to be ``(199, 209)``. .. note:: The Location string is fully stored in ``Interval.metadata`` with key ``__location``. The key starting with ``__`` is "private" and should be modified with care. ``ORIGIN`` section ^^^^^^^^^^^^^^^^^^ The sequence in the ``ORIGIN`` section is always in lowercase for the GenBank files downloaded from NCBI. For the RNA molecules, ``t`` (thymine), instead of ``u`` (uracil) is used in the sequence. All GenBank writers follow these conventions while writing GenBank files. Format Parameters ----------------- Reader-specific Parameters ^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``constructor`` parameter can be used with the ``Sequence`` generator to specify the in-memory type of each GenBank record that is parsed. ``constructor`` should be ``Sequence`` or a sub-class of ``Sequence``. It is also detected by the unit label on the LOCUS line. For example, if it is ``bp``, it will be read into ``DNA``; if it is ``aa``, it will be read into ``Protein``. Otherwise, it will be read into ``Sequence``. This default behavior is overridden by setting ``constructor``. ``lowercase`` is another parameter available for all GenBank readers. By default, it is set to ``True`` to read in the ``ORIGIN`` sequence as lowercase letters. This parameter is passed to ``Sequence`` or its sub-class constructor. ``seq_num`` is a parameter used with the ``Sequence``, ``DNA``, ``RNA``, and ``Protein`` GenBank readers. It specifies which GenBank record to read from a GenBank file with multiple records in it. Examples -------- Reading and Writing GenBank Files ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Suppose we have the following GenBank file example modified from [5]_: >>> gb_str = ''' ... LOCUS 3K1V_A 34 bp RNA linear SYN 10-OCT-2012 ... DEFINITION Chain A, Structure Of A Mutant Class-I Preq1. ... ACCESSION 3K1V_A ... VERSION 3K1V_A GI:260656459 ... KEYWORDS . ... SOURCE synthetic construct ... ORGANISM synthetic construct ... other sequences; artificial sequences. ... REFERENCE 1 (bases 1 to 34) ... AUTHORS Klein,D.J., Edwards,T.E. and Ferre-D'Amare,A.R. ... TITLE Cocrystal structure of a class I preQ1 riboswitch ... JOURNAL Nat. Struct. Mol. Biol. 16 (3), 343-344 (2009) ... PUBMED 19234468 ... COMMENT SEQRES. ... FEATURES Location/Qualifiers ... source 1..34 ... /organism="synthetic construct" ... /mol_type="other RNA" ... /db_xref="taxon:32630" ... misc_binding 1..30 ... /note="Preq1 riboswitch" ... /bound_moiety="preQ1" ... ORIGIN ... 1 agaggttcta gcacatccct ctataaaaaa ctaa ... // ... ''' Now we can read it as ``DNA`` object: >>> import io >>> from skbio import DNA, RNA, Sequence >>> gb = io.StringIO(gb_str) >>> dna_seq = DNA.read(gb) >>> dna_seq DNA ----------------------------------------------------------------- Metadata: 'ACCESSION': '3K1V_A' 'COMMENT': 'SEQRES.' 'DEFINITION': 'Chain A, Structure Of A Mutant Class-I Preq1.' 'KEYWORDS': '.' 'LOCUS': 'REFERENCE': 'SOURCE': 'VERSION': '3K1V_A GI:260656459' Interval metadata: 2 interval features Stats: length: 34 has gaps: False has degenerates: False has definites: True GC-content: 35.29% ----------------------------------------------------------------- 0 AGAGGTTCTA GCACATCCCT CTATAAAAAA CTAA Since this is a riboswitch molecule, we may want to read it as ``RNA``. As the GenBank file usually have ``t`` instead of ``u`` in the sequence, we can read it as ``RNA`` by converting ``t`` to ``u``: >>> gb = io.StringIO(gb_str) >>> rna_seq = RNA.read(gb) >>> rna_seq RNA ----------------------------------------------------------------- Metadata: 'ACCESSION': '3K1V_A' 'COMMENT': 'SEQRES.' 'DEFINITION': 'Chain A, Structure Of A Mutant Class-I Preq1.' 'KEYWORDS': '.' 'LOCUS': 'REFERENCE': 'SOURCE': 'VERSION': '3K1V_A GI:260656459' Interval metadata: 2 interval features Stats: length: 34 has gaps: False has degenerates: False has definites: True GC-content: 35.29% ----------------------------------------------------------------- 0 AGAGGUUCUA GCACAUCCCU CUAUAAAAAA CUAA >>> rna_seq == dna_seq.transcribe() True >>> with io.StringIO() as fh: ... print(dna_seq.write(fh, format='genbank').getvalue()) LOCUS 3K1V_A 34 bp RNA linear SYN 10-OCT-2012 DEFINITION Chain A, Structure Of A Mutant Class-I Preq1. ACCESSION 3K1V_A VERSION 3K1V_A GI:260656459 KEYWORDS . SOURCE synthetic construct ORGANISM synthetic construct other sequences; artificial sequences. REFERENCE 1 (bases 1 to 34) AUTHORS Klein,D.J., Edwards,T.E. and Ferre-D'Amare,A.R. TITLE Cocrystal structure of a class I preQ1 riboswitch JOURNAL Nat. Struct. Mol. Biol. 16 (3), 343-344 (2009) PUBMED 19234468 COMMENT SEQRES. FEATURES Location/Qualifiers source 1..34 /db_xref="taxon:32630" /mol_type="other RNA" /organism="synthetic construct" misc_binding 1..30 /bound_moiety="preQ1" /note="Preq1 riboswitch" ORIGIN 1 agaggttcta gcacatccct ctataaaaaa ctaa // References ---------- .. [1] http://www.ncbi.nlm.nih.gov/Sitemap/samplerecord.html .. [2] http://www.insdc.org/ .. [3] http://www.insdc.org/files/feature_table.html .. [4] http://www.ebi.ac.uk/ena/WebFeat/ .. [5] http://www.ncbi.nlm.nih.gov/nuccore/3K1V_A """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import re from functools import partial from skbio.io import create_format, GenBankFormatError from skbio.io.format._base import _get_nth_sequence, _line_generator, _too_many_blanks from skbio.util._misc import chunk_str from skbio.sequence import Sequence, DNA, RNA, Protein from skbio.io.format._sequence_feature_vocabulary import ( _yield_section, _parse_section_default, _serialize_section_default, _parse_feature_table, _serialize_feature_table, ) genbank = create_format("genbank") # This list is ordered # used to read and write genbank file. _HEADERS = [ "LOCUS", "DEFINITION", "ACCESSION", "VERSION", "DBSOURCE", "DBLINK", "KEYWORDS", "SOURCE", "REFERENCE", "COMMENT", "FEATURES", "ORIGIN", ] @genbank.sniffer() def _genbank_sniffer(fh): # check the 1st real line is a valid LOCUS line if _too_many_blanks(fh, 5): return False, {} try: line = next(_line_generator(fh, skip_blanks=True, strip=False)) except StopIteration: return False, {} try: _parse_locus([line]) except GenBankFormatError: return False, {} return True, {} @genbank.reader(None) def _genbank_to_generator(fh, cls=None, constructor=None, **kwargs): for record in _parse_genbanks(fh): yield _construct(record, constructor, **kwargs) @genbank.reader(Sequence) def _genbank_to_sequence(fh, cls=None, seq_num=1, **kwargs): if cls is None: cls = Sequence record = _get_nth_sequence(_parse_genbanks(fh), seq_num) return _construct(record, cls, **kwargs) @genbank.reader(DNA) def _genbank_to_dna(fh, cls=None, seq_num=1, **kwargs): if cls is None: cls = DNA record = _get_nth_sequence(_parse_genbanks(fh), seq_num) return _construct(record, cls, **kwargs) @genbank.reader(RNA) def _genbank_to_rna(fh, cls=None, seq_num=1, **kwargs): if cls is None: cls = RNA record = _get_nth_sequence(_parse_genbanks(fh), seq_num) return _construct(record, cls, **kwargs) @genbank.reader(Protein) def _genbank_to_protein(fh, cls=None, seq_num=1, **kwargs): if cls is None: cls = Protein record = _get_nth_sequence(_parse_genbanks(fh), seq_num) return _construct(record, cls, **kwargs) @genbank.writer(None) def _generator_to_genbank(obj, fh): for obj_i in obj: _serialize_single_genbank(obj_i, fh) @genbank.writer(Sequence) def _sequence_to_genbank(obj, fh): _serialize_single_genbank(obj, fh) @genbank.writer(DNA) def _dna_to_genbank(obj, fh): _serialize_single_genbank(obj, fh) @genbank.writer(RNA) def _rna_to_genbank(obj, fh): _serialize_single_genbank(obj, fh) @genbank.writer(Protein) def _protein_to_genbank(obj, fh): _serialize_single_genbank(obj, fh) def _construct(record, constructor=None, **kwargs): """Construct the object of Sequence, DNA, RNA, or Protein.""" seq, md, imd = record if "lowercase" not in kwargs: kwargs["lowercase"] = True if constructor is None: unit = md["LOCUS"]["unit"] if unit == "bp": # RNA mol type has T instead of U for genbank from from NCBI constructor = DNA elif unit == "aa": constructor = Protein if constructor == RNA: return DNA(seq, metadata=md, interval_metadata=imd, **kwargs).transcribe() else: return constructor(seq, metadata=md, interval_metadata=imd, **kwargs) def _parse_genbanks(fh): data_chunks = [] for line in _line_generator(fh, skip_blanks=True, strip=False): if line.startswith("//"): yield _parse_single_genbank(data_chunks) data_chunks = [] else: data_chunks.append(line) def _parse_single_genbank(chunks): metadata = {} interval_metadata = None sequence = "" # each section starts with a HEADER without indent. section_splitter = _yield_section(lambda x: not x[0].isspace(), strip=False) for section in section_splitter(chunks): header = section[0].split(None, 1)[0] parser = _PARSER_TABLE.get(header, _parse_section_default) if header == "FEATURES": # This requires 'LOCUS' line parsed before 'FEATURES', which should # be true and is implicitly checked by the sniffer. parser = partial(parser, length=metadata["LOCUS"]["size"]) parsed = parser(section) # reference can appear multiple times if header == "REFERENCE": if header in metadata: metadata[header].append(parsed) else: metadata[header] = [parsed] elif header == "ORIGIN": sequence = parsed elif header == "FEATURES": interval_metadata = parsed else: metadata[header] = parsed return sequence, metadata, interval_metadata def _serialize_single_genbank(obj, fh): """Write a GenBank record. Always write it in NCBI canonical way: 1. sequence in lowercase 2. 'u' as 't' even in RNA molecules. Parameters ---------- obj : Sequence or its child class A Sequence object or its child class representing the biological sequence to be serialized. fh : file object A file object open for writing. """ # write out the headers md = obj.metadata for header in _HEADERS: serializer = _SERIALIZER_TABLE.get(header, _serialize_section_default) if header in md: out = serializer(header, md[header]) # test if 'out' is a iterator. # cf. Effective Python Item 17 if iter(out) is iter(out): for s in out: fh.write(s) else: fh.write(out) if header == "FEATURES": if obj.has_interval_metadata(): # magic number 21: the amount of indentation before # feature table starts as defined by INSDC indent = 21 fh.write( "{header:<{indent}}Location/Qualifiers\n".format( header=header, indent=indent ) ) for s in serializer(obj.interval_metadata._intervals, indent): fh.write(s) # write out the sequence # always write RNA seq as DNA if isinstance(obj, RNA): obj = obj.reverse_transcribe() # always write in lowercase seq_str = str(obj).lower() for s in _serialize_origin(seq_str): fh.write(s) fh.write("//\n") def _parse_locus(lines): """Parse the line LOCUS. Format: # Positions Contents # --------- -------- # 00:06 LOCUS # 06:12 spaces # 12:?? Locus name # ??:?? space # ??:29 Length of sequence, right-justified # 29:33 space, bp/aa/rc, space # 33:41 molecule type (can be blank): DNA, ssDNA, dsRNA, tRNA, etc. # 41:42 space # 42:51 Blank (implies linear), linear or circular # 51:52 space # 52:55 The division code (e.g. BCT, VRL, INV) # 55:62 space # 62:73 Date, in the form dd-MMM-yyyy (e.g., 15-MAR-1991) """ line = lines[0] pattern = ( r"LOCUS" r" +([^\s]+)" r" +([0-9]+)" r" +(bp|aa|rc)" r" +(.*DNA|.*RNA)?" r" +(linear|circular)?" r" +(?!.*DNA|.*RNA)([A-Z]{3})" r" +([0-9]{2}-[A-Z]{3}-[0-9]{4})" ) matches = re.match(pattern, line) try: res = dict( zip( ["locus_name", "size", "unit", "mol_type", "shape", "division", "date"], matches.groups(), ) ) except Exception: raise GenBankFormatError("Could not parse the LOCUS line:\n%s" % line) res["size"] = int(res["size"]) return res def _serialize_locus(header, obj, indent=12): """Serialize LOCUS line. Parameters ---------- header : str The header of the LOCUS line. obj : dict A dictionary containing key-value pairs representing the attributes of the sequence entry. indent : int, optional The number of spaces used to indent the serialized LOCUS line. Defaults to 12. """ # use 'or' to convert None to '' kwargs = {k: v or "" for k, v in obj.items()} return ( "{header:<{indent}}{locus_name} {size} {unit}" " {mol_type} {shape} {division} {date}\n" ).format(header=header, indent=indent, **kwargs) def _parse_reference(lines): """Parse single REFERENCE field.""" res = {} # magic number 11: the non keyworded lines in REFERENCE # are at least indented with 11 spaces. feature_indent = " " * 11 section_splitter = _yield_section( lambda x: not x.startswith(feature_indent), skip_blanks=True, strip=False ) for section in section_splitter(lines): label, data = _parse_section_default( section, join_delimiter=" ", return_label=True ) res[label] = data return res def _serialize_reference(header, obj, indent=12): """Serialize REFERENCE. Parameters ---------- header : str The header of the REFERENCE section. obj : list A list of dictionaries representing the individual references cited in the sequence entry. indent : int, optional The number of spaces used to indent each line of the serialized REFERENCE section. Defaults to 12. """ padding = " " sort_order = {"REFERENCE": 0, "AUTHORS": 1, "TITLE": 2, "JOURNAL": 3, "PUBMED": 4} for obj_i in obj: ref_i = [] for h in sorted(obj_i, key=lambda k: sort_order.get(k, 100)): if h == header: s = "{h:<{indent}}{ref}".format(h=h, indent=indent, ref=obj_i[h]) else: s = "{h:<{indent}}{value}".format( h=padding + h, indent=indent, value=obj_i[h] ) ref_i.append(s) yield "%s\n" % "\n".join(ref_i) def _parse_source(lines): """Parse SOURCE field.""" res = {} # magic number 11: the non keyworded lines in SOURCE # are at least indented with 11 spaces. feature_indent = " " * 11 section_splitter = _yield_section( lambda x: not x.startswith(feature_indent), skip_blanks=True, strip=False ) # SOURCE line is not informative; skip it _, organism = list(section_splitter(lines)) res["ORGANISM"] = organism[0].split(None, 1)[1].strip() res["taxonomy"] = " ".join([i.strip() for i in organism[1:]]) return res def _serialize_source(header, obj, indent=12): """Serialize SOURCE. Parameters ---------- header : str The header of the SOURCE section, obj : dict A dictionary containing key-value pairs representing the attributes of the SOURCE section. indent : int, optional The number of spaces used to indent each line of the serialized SOURCE section. Defaults to 12. """ s = ( "{header:<{indent}}{organism}\n{h:<{indent}}{organism}\n{space}{taxonomy}\n" ).format( header=header, indent=indent, h=" ORGANISM", organism=obj["ORGANISM"], space=" " * 12, taxonomy=obj["taxonomy"], ) return s def _parse_origin(lines): """Parse the ORIGIN section for sequence.""" sequence = [] for line in lines: if line.startswith("ORIGIN"): continue # remove the number at the beg of each line items = line.split() sequence.append("".join(items[1:])) return "".join(sequence) def _serialize_origin(seq, indent=9): """Serialize seq to ORIGIN. Parameters ---------- seq : str The sequence data to be serialized. indent : int, optional The number of spaces used to indent each line of the serialized ORIGIN section. """ n = 1 line_size = 60 frag_size = 10 for i in range(0, len(seq), line_size): line = seq[i : i + line_size] s = "{n:>{indent}} {s}\n".format( n=n, indent=indent, s=chunk_str(line, frag_size, " ") ) if n == 1: s = "ORIGIN\n" + s n += line_size yield s _PARSER_TABLE = { "LOCUS": _parse_locus, "SOURCE": _parse_source, "REFERENCE": _parse_reference, "FEATURES": _parse_feature_table, "ORIGIN": _parse_origin, } _SERIALIZER_TABLE = { "LOCUS": _serialize_locus, "SOURCE": _serialize_source, "REFERENCE": _serialize_reference, "FEATURES": _serialize_feature_table, } scikit-bio-scikit-bio-a3beaa6/skbio/io/format/gff3.py000066400000000000000000000445561520735541300225760ustar00rootroot00000000000000"""GFF3 format (:mod:`skbio.io.format.gff3`) ========================================= .. currentmodule:: skbio.io.format.gff3 GFF3 (Generic Feature Format version 3) is a standard file format for describing features for biological sequences. It contains lines of text, each consisting of 9 tab-delimited columns [1]_. Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.sequence.Sequence` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.sequence.DNA` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.metadata.IntervalMetadata` | +------+------+---------------------------------------------------------------+ |Yes |Yes |generator of tuple (seq_id of str type, | | | |:mod:`skbio.metadata.IntervalMetadata`) | +------+------+---------------------------------------------------------------+ Format Specification -------------------- The first line of the file is a comment that identifies the format and version. This is followed by a series of data lines. Each data line corresponds to an annotation and consists of 9 columns: SEQID, SOURCE, TYPE, START, END, SCORE, STRAND, PHASE, and ATTR. Column 9 (ATTR) is list of feature attributes in the format "tag=value". Multiple "tag=value" pairs are delimited by semicolons. Multiple values of the same tag are separated with the comma ",". The following tags have predefined meanings: ID, Name, Alias, Parent, Target, Gap, Derives_from, Note, Dbxref, Ontology_term, and Is_circular. The meaning and format of these columns and attributes are explained detail in the format specification [1]_. And they are read in as the vocabulary defined in GenBank parser (:mod:`skbio.io.format.genbank`). Format Parameters ----------------- Reader-specific Parameters ^^^^^^^^^^^^^^^^^^^^^^^^^^ ``IntervalMetadata`` GFF3 reader requires 1 parameter: ``seq_id``. It reads the annotation with the specified sequence ID from the GFF3 file into an ``IntervalMetadata`` object. ``DNA`` and ``Sequence`` GFF3 readers require ``seq_num`` of int as parameter. It specifies which GFF3 record to read from a GFF3 file with annotations of multiple sequences in it. Writer-specific Parameters ^^^^^^^^^^^^^^^^^^^^^^^^^^ ``skip_subregion`` is a boolean parameter used by all the GFF3 writers. It specifies whether you would like to write each non-contiguous sub-region for a feature annotation. For example, if there is interval feature for a gene with two exons in an ``IntervalMetadata`` object, it will write one line into the GFF3 file when ``skip_subregion`` is ``True`` and will write 3 lines (one for the gene and one for each exon, respectively) when ``skip_subregion`` is ``False``. Default is ``True``. In addition, ``IntervalMetadata`` GFF3 writer needs a parameter of ``seq_id``. It specify the sequence ID (column 1 in GFF3 file) that the annotation belong to. Examples -------- Let's create a file stream with following data in GFF3 format: >>> from skbio import Sequence, DNA >>> gff_str = ''' ... ##gff-version 3 ... seq_1\\t.\\tgene\\t10\\t90\\t.\\t+\\t0\\tID=gen1 ... seq_1\\t.\\texon\\t10\\t30\\t.\\t+\\t.\\tParent=gen1 ... seq_1\\t.\\texon\\t50\\t90\\t.\\t+\\t.\\tParent=gen1 ... seq_2\\t.\\tgene\\t80\\t96\\t.\\t-\\t.\\tID=gen2 ... ##FASTA ... >seq_1 ... ATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGC ... ATGCATGCATGCATGCATGCATGCATGCATGCATGCATGC ... >seq_2 ... ATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGC ... ATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGC ... ''' >>> import io >>> from skbio.metadata import IntervalMetadata >>> from skbio.io import read >>> gff = io.StringIO(gff_str) We can read it into ``IntervalMetadata``. Each line will be read into an interval feature in ``IntervalMetadata`` object: >>> im = read(gff, format='gff3', into=IntervalMetadata, ... seq_id='seq_1') >>> im # doctest: +SKIP 3 interval features ------------------- Interval(interval_metadata=<4604421736>, bounds=[(9, 90)], \ fuzzy=[(False, False)], metadata={'type': 'gene', \ 'phase': 0, 'strand': '+', 'source': '.', 'score': '.', 'ID': 'gen1'}) Interval(interval_metadata=<4604421736>, bounds=[(9, 30)], \ fuzzy=[(False, False)], metadata={'strand': '+', 'source': '.', \ 'type': 'exon', 'Parent': 'gen1', 'score': '.'}) Interval(interval_metadata=<4604421736>, bounds=[(49, 90)], \ fuzzy=[(False, False)], metadata={'strand': '+', 'source': '.', \ 'type': 'exon', 'Parent': 'gen1', 'score': '.'}) We can write the ``IntervalMetadata`` object back to GFF3 file: >>> with io.StringIO() as fh: # doctest: +NORMALIZE_WHITESPACE ... print(im.write(fh, format='gff3', seq_id='seq_1').getvalue()) ##gff-version 3 seq_1 . gene 10 90 . + 0 ID=gen1 seq_1 . exon 10 30 . + . Parent=gen1 seq_1 . exon 50 90 . + . Parent=gen1 If the GFF3 file does not have the sequence ID, it will return an empty object: >>> gff = io.StringIO(gff_str) >>> im = read(gff, format='gff3', into=IntervalMetadata, ... seq_id='foo') >>> im 0 interval features ------------------- We can also read the GFF3 file into a generator: >>> gff = io.StringIO(gff_str) >>> gen = read(gff, format='gff3') >>> for im in gen: # doctest: +SKIP ... print(im[0]) # the seq id ... print(im[1]) # the interval metadata on this seq seq_1 3 interval features ------------------- Interval(interval_metadata=<4603377592>, bounds=[(9, 90)], \ fuzzy=[(False, False)], metadata={'type': 'gene', 'ID': 'gen1', \ 'source': '.', 'score': '.', 'strand': '+', 'phase': 0}) Interval(interval_metadata=<4603377592>, bounds=[(9, 30)], \ fuzzy=[(False, False)], metadata={'strand': '+', 'type': 'exon', \ 'Parent': 'gen1', 'source': '.', 'score': '.'}) Interval(interval_metadata=<4603377592>, bounds=[(49, 90)], \ fuzzy=[(False, False)], metadata={'strand': '+', 'type': 'exon', \ 'Parent': 'gen1', 'source': '.', 'score': '.'}) seq_2 1 interval feature ------------------ Interval(interval_metadata=<4603378712>, bounds=[(79, 96)], \ fuzzy=[(False, False)], metadata={'strand': '-', 'type': 'gene', \ 'ID': 'gen2', 'source': '.', 'score': '.'}) For the GFF3 file with sequences, we can read it into ``Sequence`` or ``DNA``: >>> gff = io.StringIO(gff_str) >>> seq = read(gff, format='gff3', into=Sequence, seq_num=1) >>> seq Sequence -------------------------------------------------------------------- Metadata: 'description': '' 'id': 'seq_1' Interval metadata: 3 interval features Stats: length: 100 -------------------------------------------------------------------- 0 ATGCATGCAT GCATGCATGC ATGCATGCAT GCATGCATGC ATGCATGCAT GCATGCATGC 60 ATGCATGCAT GCATGCATGC ATGCATGCAT GCATGCATGC >>> gff = io.StringIO(gff_str) >>> seq = read(gff, format='gff3', into=DNA, seq_num=2) >>> seq DNA -------------------------------------------------------------------- Metadata: 'description': '' 'id': 'seq_2' Interval metadata: 1 interval feature Stats: length: 120 has gaps: False has degenerates: False has definites: True GC-content: 50.00% -------------------------------------------------------------------- 0 ATGCATGCAT GCATGCATGC ATGCATGCAT GCATGCATGC ATGCATGCAT GCATGCATGC 60 ATGCATGCAT GCATGCATGC ATGCATGCAT GCATGCATGC ATGCATGCAT GCATGCATGC References ---------- .. [1] https://github.com/The-Sequence-Ontology/\ Specifications/blob/master/gff3.md """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import re from collections.abc import Iterable from skbio.sequence import DNA, Sequence from skbio.io import create_format, GFF3FormatError from skbio.metadata import IntervalMetadata from skbio.io.format._base import _line_generator, _too_many_blanks, _get_nth_sequence from skbio.io.format.fasta import _fasta_to_generator from skbio.io.format._sequence_feature_vocabulary import ( _vocabulary_change, _vocabulary_skip, ) from skbio.io import write gff3 = create_format("gff3") @gff3.sniffer() def _gff3_sniffer(fh): # check the 1st real line is a valid ID line if _too_many_blanks(fh, 5): return False, {} try: line = next(_line_generator(fh, skip_blanks=True, strip=False)) except StopIteration: return False, {} if re.match(r"##gff-version\s+3", line): return True, {} else: return False, {} @gff3.reader(None) def _gff3_to_generator(fh, cls=None): """Parse the GFF3 into the existing IntervalMetadata. Parameters ---------- fh : file file handler Yields ------ tuple str of seq id, IntervalMetadata """ id_lengths = {} for data_type, sid, data in _yield_record(fh): if data_type == "length": # get length from sequence-region pragma. # the pragma lines are always before the real annotation lines. id_lengths[sid] = data elif data_type == "data": length = id_lengths.get(sid) yield sid, _parse_record(data, length) @gff3.writer(None) def _generator_to_gff3(obj, fh, skip_subregion=True): """Write a list of IntervalMetadata into a file. Parameters ---------- obj : Iterable of (seq_id, IntervalMetadata) List of IntervalMetadata to write. fh : file handler File to write into. skip_subregion : bool Write a line for each sub-regions of an ``Interval`` if it is ``False``. """ # write file header fh.write("##gff-version 3\n") for seq_id, obj_i in obj: _serialize_interval_metadata(obj_i, seq_id, fh, skip_subregion) @gff3.reader(Sequence) def _gff3_to_sequence(fh, cls=None, seq_num=1): if cls is None: cls = Sequence return _construct_seq(fh, cls, seq_num) @gff3.writer(Sequence) def _sequence_to_gff3(obj, fh, skip_subregion=True): # write file header fh.write("##gff-version 3\n") _serialize_seq(obj, fh, skip_subregion) @gff3.reader(DNA) def _gff3_to_dna(fh, cls=None, seq_num=1): if cls is None: cls = DNA return _construct_seq(fh, cls, seq_num) @gff3.writer(DNA) def _dna_to_gff3(obj, fh, skip_subregion=True): # write file header fh.write("##gff-version 3\n") _serialize_seq(obj, fh, skip_subregion) @gff3.reader(IntervalMetadata) def _gff3_to_interval_metadata(fh, seq_id, cls=None): """Read a GFF3 record into the specified interval metadata. Parameters ---------- fh : file handler GFF3 file to read. seq_id : str Sequence ID which the interval metadata is associated with. """ if cls is None: cls = IntervalMetadata length = None for data_type, sid, data in _yield_record(fh): if seq_id == sid: if data_type == "length": # get length from sequence-region pragma length = data elif data_type == "data": return _parse_record(data, length) else: raise GFF3FormatError( "Unknown section in the input GFF3 file: " "%r %r %r" % (data_type, sid, data) ) # return an empty instead of None return cls(None) @gff3.writer(IntervalMetadata) def _interval_metadata_to_gff3(obj, fh, seq_id, skip_subregion=True): """Output ``IntervalMetadata`` object to GFF3 file. Parameters ---------- obj : IntervalMetadata An IntervalMetadata object. fh : file object File object opened for writing. seq_id : str ID for column 1 in the GFF3 file. skip_subregion : bool Write a line for each sub-regions of an ``Interval`` if it is ``False``. """ # write file header fh.write("##gff-version 3\n") _serialize_interval_metadata(obj, seq_id, fh, skip_subregion=True) def _construct_seq(fh, constructor=DNA, seq_num=1): lines = [] for i, (data_type, seq_id, L) in enumerate(_yield_record(fh), 1): if data_type == "data" and seq_num == i: lines = L seq = _get_nth_sequence( _fasta_to_generator(fh, constructor=constructor), seq_num=seq_num ) seq.interval_metadata = _parse_record(lines, len(seq)) return seq def _yield_record(fh): """Yield (seq_id, lines) that belong to the same sequence.""" lines = [] current = False for line in _line_generator(fh, skip_blanks=True, strip=True): if line.startswith("##sequence-region"): _, seq_id, start, end = line.split() length = int(end) - int(start) + 1 yield "length", seq_id, length if line.startswith("##FASTA"): # stop once reaching to sequence section break if not line.startswith("#"): try: seq_id, _ = line.split("\t", 1) except ValueError: raise GFF3FormatError("Wrong GFF3 format at line: %s" % line) if current == seq_id: lines.append(line) else: if current is not False: yield "data", current, lines lines = [line] current = seq_id if current is False: # if the input file object is empty, it should return # an empty generator return yield else: yield "data", current, lines def _parse_record(lines, length): """Parse the lines into a IntervalMetadata object.""" interval_metadata = IntervalMetadata(length) for line in lines: columns = line.split("\t") # there should be 9 columns if len(columns) != 9: raise GFF3FormatError('do not have 9 columns in this line: "%s"' % line) # the 1st column is seq ID for every feature. don't store # this repetitive information metadata = { "source": columns[1], "type": columns[2], "score": columns[5], "strand": columns[6], } phase = columns[7] # phase value can only be int or '.' try: metadata["phase"] = int(phase) except ValueError: if phase != ".": raise GFF3FormatError( "unknown value for phase column: {!r}".format(phase) ) metadata.update(_parse_attr(columns[8])) start, end = columns[3:5] bounds = [(int(start) - 1, int(end))] interval_metadata.add(bounds, metadata=metadata) return interval_metadata def _parse_attr(s): """Parse attribute column.""" voca_change = _vocabulary_change("gff3") md = {} # in case the line ending with ';', strip it. s = s.rstrip(";") for attr in s.split(";"): k, v = attr.split("=") if k in voca_change: k = voca_change[k] md[k] = v return md def _serialize_interval_metadata(interval_metadata, seq_id, fh, skip_subregion=True): """Serialize an IntervalMetadata to GFF3. Parameters ---------- interval_metadata : IntervalMetadata An IntervalMetadata object. seq_id : str Seq id for the current annotation. It will be used as the 1st column in the GFF3. fh : file handler The file object to output. skip_subregion : bool Whether to skip outputting each sub region as a line in GFF3. """ column_keys = ["source", "type", "score", "strand", "phase"] voca_change = _vocabulary_change("gff3", False) voca_skip = _vocabulary_skip("gff3") voca_skip.extend(column_keys) # these characters have reserved meanings in column 9 and must be # escaped when used in other contexts escape = str.maketrans({";": "%3B", "=": "%3D", "&": "%26", ",": "%2C"}) for interval in interval_metadata._intervals: md = interval.metadata bd = interval.bounds start = str(bd[0][0] + 1) end = str(bd[-1][-1]) source, feat_type, score, strand, phase = [ str(md.get(i, ".")) for i in column_keys ] columns = [seq_id, source, feat_type, start, end, score, strand, phase] # serialize the attributes in column 9 attr = [] # use sort to make the output order deterministic for k in sorted(md): if k in voca_skip: # skip the metadata that doesn't go to attribute column continue v = md[k] if k in voca_change: k = voca_change[k] if isinstance(v, Iterable) and not isinstance(v, str): # if there are multiple values for this attribute, # convert them to str and concat them with "," v = ",".join(str(i).translate(escape) for i in v) else: v = v.translate(escape) attr.append("%s=%s" % (k.translate(escape), v)) columns.append(";".join(attr)) fh.write("\t".join(columns)) fh.write("\n") # if there are multiple regions for this feature, # output each region as a standalone line in GFF3. if len(bd) > 1 and skip_subregion is False: for start, end in bd: # if this is a gene, then each sub region should be an exon if columns[2] == "gene": columns[2] = "exon" columns[3] = str(start + 1) columns[4] = str(end) try: parent = md["ID"] except KeyError: raise GFF3FormatError( "You need provide ID info for " "the parent interval feature: %r" % interval ) columns[8] = "Parent=%s" % parent fh.write("\t".join(columns)) fh.write("\n") def _serialize_seq(seq, fh, skip_subregion=True): """Serialize a sequence to GFF3.""" _serialize_interval_metadata( seq.interval_metadata, seq.metadata["id"], fh, skip_subregion ) fh.write("##FASTA\n") write(seq, into=fh, format="fasta") scikit-bio-scikit-bio-a3beaa6/skbio/io/format/lsmat.py000066400000000000000000000236551520735541300230660ustar00rootroot00000000000000r"""Labeled square matrix format (:mod:`skbio.io.format.lsmat`) =========================================================== .. currentmodule:: skbio.io.format.lsmat The labeled square matrix file format (``lsmat``) stores numeric square matrix data relating a set of objects along each axis. The format also stores identifiers (i.e., unique labels) for the objects. The matrix data and identifiers are stored in delimited text format (e.g., TSV or CSV). This format supports storing a variety of data types including dissimilarity/distance matrices, similarity matrices and amino acid substitution matrices. Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.stats.distance.PairwiseMatrix` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.stats.distance.SymmetricMatrix` | +------+------+---------------------------------------------------------------+ |Yes |Yes |:mod:`skbio.stats.distance.DistanceMatrix` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- The labeled square matrix and object identifiers are stored as delimited text. The first line of the file is the header, which must start with the delimiter, followed by the IDs for all objects in the matrix. Each of the following lines must contain an object's ID, followed by a numeric (float or integer) vector relating the object to all other objects in the matrix. The order of objects is determined by the IDs in the header. For example, assume we have a 2x2 distance matrix with IDs ``'a'`` and ``'b'``. When serialized in this format, the distance matrix might look like:: ab a0.01.0 b1.00.0 where ```` is the delimiter between elements. Lines containing only whitespace may occur anywhere throughout the file and are ignored. Lines starting with ``#`` are treated as comments and are ignored. Comments may only occur *before* the header. IDs will have any leading/trailing whitespace removed when they are parsed. .. note:: This file format is most useful for storing small matrices, or when it is desirable to represent the matrix in a human-readable format, or easily import the file into another program that supports delimited text (e.g., a spreadsheet program). If efficiency is a concern, this format may not be the most appropriate choice. Format Parameters ----------------- delimiter : str, optional A string used to separate elements in the file format. Can be specified when reading from or writing to a file. Default is the tab character (``'\t'``), and the format is usually referred to as tab-separated values (TSV). Another common choice is comma (``','``), used in the comma-separated values (CSV) format. A special ``delimiter`` is ``None``, which represents a whitespace of arbitrary length. This value is useful for reading a fixed-width text file. However, it cannot be automatically determined, nor can it be specified when writing to a file. dtype : str or dtype, optional The data type of the underlying matrix data. Only relevant when reading from a file. Default is "float64", which maps to ``np.float64``. The only other available option is "float32" (or ``np.float32``). """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import csv import numpy as np from skbio.stats.distance import PairwiseMatrix, DistanceMatrix, SymmetricMatrix from skbio.io import create_format, LSMatFormatError lsmat = create_format("lsmat") @lsmat.sniffer() def _lsmat_sniffer(fh): header = _find_header(fh) if header is not None: try: dialect = csv.Sniffer().sniff(header) delimiter = dialect.delimiter # csv delimiter " " is equivalent to Python's str.split(sep=None) if delimiter == " ": delimiter = None ids = _parse_header(header, delimiter) first_id, _ = next(_parse_data(fh, delimiter), (None, None)) if first_id is not None and first_id == ids[0]: return True, {"delimiter": delimiter} except (csv.Error, LSMatFormatError): pass return False, {} @lsmat.reader(PairwiseMatrix) def _lsmat_to_pairwise_matrix(fh, cls=None, delimiter="\t", dtype="float64"): if cls is None: cls = PairwiseMatrix return _lsmat_to_matrix(cls, fh, delimiter, dtype) @lsmat.reader(SymmetricMatrix) def _lsmat_to_symmetric_matrix(fh, cls=None, delimiter="\t", dtype="float64"): if cls is None: cls = SymmetricMatrix return _lsmat_to_matrix(cls, fh, delimiter, dtype) @lsmat.reader(DistanceMatrix) def _lsmat_to_distance_matrix(fh, cls=None, delimiter="\t", dtype="float64"): if cls is None: cls = DistanceMatrix return _lsmat_to_matrix(cls, fh, delimiter, dtype) @lsmat.writer(PairwiseMatrix) def _pairwise_matrix_to_lsmat(obj, fh, delimiter="\t"): _matrix_to_lsmat(obj, fh, delimiter) @lsmat.writer(SymmetricMatrix) def _symmetric_matrix_to_lsmat(obj, fh, delimiter="\t"): _matrix_to_lsmat(obj, fh, delimiter) @lsmat.writer(DistanceMatrix) def _distance_matrix_to_lsmat(obj, fh, delimiter="\t"): _matrix_to_lsmat(obj, fh, delimiter) def _lsmat_to_matrix(cls, fh, delimiter, dtype): # We aren't using np.loadtxt because it uses *way* too much memory # (e.g, a 2GB matrix eats up 10GB, which then isn't freed after parsing # has finished). See: # http://mail.scipy.org/pipermail/numpy-tickets/2012-August/006749.html # Strategy: # - find the header # - initialize an empty ndarray # - for each row of data in the input file: # - populate the corresponding row in the ndarray with floats dtype = np.dtype(dtype) if dtype not in (np.float64, np.float32): raise TypeError(f"{dtype} is not a supported data type.") header = _find_header(fh) if header is None: raise LSMatFormatError( "Could not find a header line containing IDs in the matrix file. Please " "verify that the file is not empty." ) ids = _parse_header(header, delimiter) num_ids = len(ids) data = np.empty((num_ids, num_ids), dtype=dtype) # The default separator of str.split (consecutive whitespaces) is equivalent to " " # in np.fromstring. sep = delimiter if delimiter else " " row_idx = -1 for line in fh: line = line.strip() if not line: continue row_idx += 1 if row_idx >= num_ids: # We've hit a nonempty line after we already filled the data matrix. Raise # an error because we shouldn't ignore extra data. raise LSMatFormatError( "Encountered extra row(s) without corresponding IDs in the header." ) row_id, row_data = line.split(delimiter, 1) if row_id.rstrip() != ids[row_idx]: raise LSMatFormatError( "Encountered mismatched IDs while parsing the matrix file. Found %r " "but expected %r. Please ensure that the IDs match between the matrix " "header (first row) and the row labels (first column)." % (row_id.rstrip(), ids[row_idx]) ) # np.fromstring is more efficient than str.split then float row_data = np.fromstring(row_data, dtype=dtype, sep=sep) # The code `data[row_idx, :] = row_data` will raise a ValueError if length # doesn't match. However there is an exception: when row_data contains only one # element, it will be broadcasted to the entire data[row_idx, :]. Therefore, an # explicit check appears to be necessary. if row_data.size != num_ids: raise LSMatFormatError( "There are %d value(s) in row %d, which is not equal to the number of " "ID(s) in the header (%d)." % (row_data.size, row_idx + 1, num_ids) ) data[row_idx, :] = row_data if row_idx != num_ids - 1: raise LSMatFormatError( "Expected %d row(s) of data, but found %d." % (num_ids, row_idx + 1) ) return cls(data, ids) def _find_header(fh): header = None for line in fh: stripped_line = line.strip() if stripped_line and not stripped_line.startswith("#"): # Don't strip the header because the first delimiter might be # whitespace (e.g., tab). header = line break return header def _parse_header(header, delimiter): tokens = header.rstrip().split(delimiter) if delimiter is not None: if tokens[0]: raise LSMatFormatError( "Header must start with delimiter %r." % str(delimiter) ) tokens = tokens[1:] return [e.strip() for e in tokens] def _parse_data(fh, delimiter): for line in fh: if line := line.rstrip(): tokens = line.split(delimiter) yield tokens[0].strip(), tokens[1:] def _matrix_to_lsmat(obj, fh, delimiter): delimiter = "%s" % delimiter ids = obj.ids fh.write(_format_ids(ids, delimiter)) fh.write("\n") for id_, vals in zip(ids, obj.data): fh.write("%s" % id_) fh.write(delimiter) fh.write(delimiter.join(np.asarray(vals, dtype=str))) fh.write("\n") def _format_ids(ids, delimiter): return delimiter.join([""] + list(ids)) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/newick.py000066400000000000000000000477001520735541300232230ustar00rootroot00000000000000r"""Newick format (:mod:`skbio.io.format.newick`) ============================================= .. currentmodule:: skbio.io.format.newick Newick format (``newick``) stores spanning-trees with weighted edges and node names in a minimal file format [1]_. This is useful for representing phylogenetic trees and taxonomies. Newick was created as an informal specification on June 26, 1986 [2]_. Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.tree.TreeNode` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- A Newick file represents a tree using the following grammar. See below for an explanation of the format in plain English. Formal Grammar ^^^^^^^^^^^^^^ .. code-block:: none NEWICK ==> NODE ; NODE ==> FORMATTING SUBTREE FORMATTING NODE_INFO FORMATTING SUBTREE ==> ( CHILDREN ) | null NODE_INFO ==> LABEL | LENGTH | LABEL FORMATTING LENGTH | null FORMATTING ==> [ COMMENT_CHARS ] | whitespace | null CHILDREN ==> NODE | CHILDREN , NODE LABEL ==> ' ALL_CHARS ' | SAFE_CHARS LENGTH ==> : FORMATTING NUMBER COMMENT_CHARS ==> any ALL_CHARS ==> any SAFE_CHARS ==> any except: ,;:()[] and whitespace NUMBER ==> a decimal or integer .. note:: The ``_`` character inside of SAFE_CHARS will be converted to a blank space in ``skbio.tree.TreeNode`` and vice versa. ``'`` is considered the escape character. To escape ``'`` use a preceding ``'``. The implementation of newick in scikit-bio allows nested comments. To escape ``[`` or ``]`` from within COMMENT_CHARS, use a preceding ``'``. Explanation ^^^^^^^^^^^ The Newick format defines a tree by creating a minimal representation of nodes and their relationships to each other. Basic Symbols ~~~~~~~~~~~~~ There are several symbols which define nodes, the first of which is the semi-colon (``;``). The semi-colon creates a root node to its left. Recall that there can only be one root in a tree. The next symbol is the comma (``,``), which creates a node to its right. However, these two alone are not enough. For example imagine the following string: ``, , , ;``. It is evident that there is a root, but the other 3 nodes, defined by commas, have no relationship. For this reason, it is not a valid Newick string to have more than one node at the root level. To provide these relationships, there is another structure: paired parenthesis (``( )``). These are inserted at the location of an existing node and give it the ability to have children. Placing ``( )`` in a node's location will create a child inside the parenthesis on the left-most inner edge. Application of Rules ~~~~~~~~~~~~~~~~~~~~ Adding a comma within the parenthesis will create two children: ``( , )`` (also known as a bifurcating node). Notice that only one comma is needed because the parenthesis have already created a child. Adding more commas will create more children who are siblings to each other. For example, writing ``( , , , )`` will create a multifurcating node with 4 child nodes who are siblings to each other. The notation for a root can be used to create a complete tree. The ``;`` will create a root node where parenthesis can be placed: ``( );``. Adding commas will create more children: ``( , );``. These rules can be applied recursively ad. infinitum: ``(( , ), ( , ));``. Adding Node Information ~~~~~~~~~~~~~~~~~~~~~~~ Information about a node can be added to improve the clarity and meaning of a tree. Each node may have a label and/or a length (to the parent). Newick always places the node information at the right-most edge of a node's position. Starting with labels, ``(( , ), ( , ));`` would become ``((D, E)B, (F, G)C)A;``. There is a named root ``A`` and the root's children (from left to right) are ``B`` and ``C``. ``B`` has the children ``D`` and ``E``, and ``C`` has the children ``F`` and ``G``. Length represents the distance (or weight of the edge) that connects a node to its parent. This must be a decimal or integer. As an example, suppose ``D`` is rather estranged from ``B``, and ``E`` is very close. That can be written as: ``((D:10, E:0.5)B, (F, G)C)A;``. Notice that the colon (``:``) separates the label from the length. If the length is provided but the label is omitted, a colon must still precede the length (``(:0.25,:0.5):0.0;``). Without this, the length would be interpreted as a label (which happens to be a number). .. note:: Internally scikit-bio will cast a length to ``float`` which technically means that even exponent strings (``1e-3``) are supported) Advanced Label and Length Rules ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ More characters can be used to create more descriptive labels. When creating a label there are some rules that must be considered due to limitations in the Newick format. The following characters are not allowed within a standard label: parenthesis, commas, square-brackets, colon, semi-colon, and whitespace. These characters are also disallowed from occurring within a length, which has a much stricter format: decimal or integer. Many of these characters are symbols which define the structure of a Newick tree and are thus disallowed for obvious reasons. The symbols not yet mentioned are square-brackets (``[ ]``) and whitespace (space, tab, and newline). What if these characters are needed within a label? In the simple case of spaces, an underscore (``_``) will be translated as a space on read and vice versa on write. What if a literal underscore or any of the others mentioned are needed? A label can be escaped (meaning that its contents are understood as regular text) using single-quotes (``'``). When a label is surrounded by single-quotes, any character is permissible. If a single-quote is needed inside of an escaped label or anywhere else, it can be escaped with another single-quote. For example, ``A_1`` is written ``'A_1'`` and ``'A'_1`` would be ``'''A''_1'``. Inline Comments ~~~~~~~~~~~~~~~ Square-brackets define a comment, which are the least commonly used part of the Newick format. Comments are not included in the generated objects and exist only as human readable text ignored by the parser. The implementation in scikit-bio allows for nested comments (``[comment [nested]]``). Unpaired square-brackets can be escaped with a single-quote preceding the bracket when inside an existing comment. (This is identical to escaping a single-quote). The single-quote has the highest operator precedence, so there is no need to worry about starting a comment from within a properly escaped label. Whitespace ~~~~~~~~~~ Whitespace is not allowed within any un-escaped label or in any length, but it is permitted anywhere else. Caveats ~~~~~~~ Newick cannot always provide a unique representation of any tree, in other words, the same tree can be written multiple ways. For example: ``(A, B);`` is isomorphic to ``(B, A);``. The implementation in scikit-bio maintains the given sibling order in its object representations. Newick has no representation of an unrooted tree. Some biological packages make the assumption that when a trifurcated root exists in an otherwise bifurcated tree that the tree must be unrooted. In scikit-bio, ``skbio.tree.TreeNode`` will always be rooted at the ``newick`` root (``;``). Format Parameters ----------------- The only supported format parameter is `convert_underscores`. This is `True` by default. When `False`, underscores found in unescaped labels will not be converted to spaces. This is useful when reading the output of an external program in which the underscores were not escaped. This parameter only affects `read` operations. It does not exist for `write` operations; they will always properly escape underscores. Examples -------- This is a simple Newick string. >>> from io import StringIO >>> from skbio import read >>> from skbio.tree import TreeNode >>> f = StringIO("((D, E)B, (F, G)C)A;") >>> tree = read(f, format="newick", into=TreeNode) >>> f.close() >>> print(tree.ascii_art()) /-D /B-------| | \-E -A-------| | /-F \C-------| \-G This is a complex Newick string. >>> f = StringIO("[example](a:0.1, 'b_b''':0.2, (c:0.3, d_d:0.4)e:0.5)f:0.0;") >>> tree = read(f, format="newick", into=TreeNode) >>> f.close() >>> print(tree.ascii_art()) /-a | -f-------|--b_b' | | /-c \e-------| \-d d Notice that the node originally labeled ``d_d`` became ``d d``. Additionally ``'b_b'''`` became ``b_b'``. Note that the underscore was preserved in `b_b'`. References ---------- .. [1] http://evolution.genetics.washington.edu/phylip/newick_doc.html .. [2] http://evolution.genetics.washington.edu/phylip/newicktree.html """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from skbio.io import create_format, NewickFormatError from skbio.tree import TreeNode newick = create_format("newick") @newick.sniffer() def _newick_sniffer(fh): # Strategy: # The following conditions preclude a file from being newick: # * It is an empty file. # * There is whitespace inside of a label (handled by tokenizer) # * : is followed by anything that is an operator # * ( is not preceded immediately by , or another ( # * The parens are unbalanced when ; is found. # If 100 tokens (or less if EOF occurs earlier) then it is probably # newick, or at least we can't prove it isn't. operators = set(",;:()") empty = True last_token = "," indent = 0 try: # 100 tokens ought to be enough for anybody. for token, _ in zip(_tokenize_newick(fh), range(100)): if token not in operators: pass elif token == "," and last_token != ":" and indent > 0: pass elif token == ":" and last_token != ":": pass elif token == ";" and last_token != ":" and indent == 0: pass elif token == ")" and last_token != ":": indent -= 1 elif token == "(" and (last_token == "(" or last_token == ","): indent += 1 else: raise NewickFormatError() last_token = token empty = False except NewickFormatError: return False, {} return not empty, {} @newick.reader(TreeNode) def _newick_to_tree_node(fh, cls=None, convert_underscores=True): if cls is None: cls = TreeNode tree_stack = [] current_depth = 0 last_token = "" next_is_distance = False root = cls() tree_stack.append((root, current_depth)) for token in _tokenize_newick(fh, convert_underscores=convert_underscores): # Check for a label if last_token not in "(,):": if not next_is_distance: tree_stack[-1][0].name = last_token if last_token else None else: next_is_distance = False # Check for a distance if token == ":": next_is_distance = True elif last_token == ":": try: tree_stack[-1][0].length = float(token) except ValueError: raise NewickFormatError( "Could not read length as numeric type: %s." % token ) elif token == "(": current_depth += 1 tree_stack.append((cls(), current_depth)) elif token == ",": tree_stack.append((cls(), current_depth)) elif token == ")": if len(tree_stack) < 2: raise NewickFormatError( "Could not parse file as newick. Parenthesis are unbalanced." ) children = [] # Pop all nodes at this depth as they belong to the remaining # node on the top of the stack as children. while current_depth == tree_stack[-1][1]: node, _ = tree_stack.pop() children.insert(0, node) parent = tree_stack[-1][0] if parent.children: raise NewickFormatError( "Could not parse file as newick. Contains unnested children." ) # This is much faster than TreeNode.extend for child in children: child.parent = parent parent.children = children current_depth -= 1 elif token == ";": if len(tree_stack) == 1: return root break last_token = token raise NewickFormatError( "Could not parse file as newick." " `(Parenthesis)`, `'single-quotes'`," " `[comments]` may be unbalanced, or tree may be" " missing its root." ) @newick.writer(TreeNode) def _tree_node_to_newick(obj, fh): operators = set(",:_;()[]") current_depth = 0 nodes_left = [(obj, 0)] while len(nodes_left) > 0: entry = nodes_left.pop() node, node_depth = entry if node.children and node_depth >= current_depth: fh.write("(") nodes_left.append(entry) nodes_left += ((child, node_depth + 1) for child in reversed(node.children)) current_depth = node_depth + 1 else: if node_depth < current_depth: fh.write(")") current_depth -= 1 # Note we don't check for None because there is no way to represent # an empty string as a label in Newick. Therefore, both None and '' # are considered to be the absence of a label. label = node._node_label() if label: escaped = "%s" % label.replace("'", "''") if any(t in operators for t in label): fh.write("'") fh.write(escaped) fh.write("'") else: fh.write(escaped.replace(" ", "_")) if node.length is not None: fh.write(":") fh.write("%s" % node.length) if nodes_left and nodes_left[-1][1] == current_depth: fh.write(",") fh.write(";\n") def _tokenize_newick(fh, convert_underscores=True): structure_tokens = set("(),;:") not_escaped = True label_start = False last_non_ws_char = "" last_char = "" comment_depth = 0 metadata_buffer = [] # Strategy: # We will iterate by character. # Comments in newick are defined as: # [This is a comment] # Nested comments are allowed. # # The following characters indicate structure: # ( ) , ; : # # Whitespace is never allowed in a newick label, so an exception will be # thrown. # # We use ' to indicate a literal string. It has the highest precedence of # any operator. for line in fh: for character in line: # We will start by handling the comment case. # This code branch will probably never execute in practice. # Using a comment_depth we can handle nested comments. # Additionally if we are inside an escaped literal string, then # we don't want to consider it a comment. if character == "[" and not_escaped: # Sometimes we might not want to nest a comment, so we will use # our escape character. This is not explicitly mentioned in # any format specification, but seems like what a reasonable # person might do. if last_non_ws_char != "'" or comment_depth == 0: # Once again, only advance our depth if [ has not been # escaped inside our comment. comment_depth += 1 if comment_depth > 0: # Same as above, but in reverse if character == "]" and last_non_ws_char != "'": comment_depth -= 1 last_non_ws_char = character continue # We are not in a comment block if we are below here. # If we are inside of an escaped string literal, then ( ) , ; are # meaningless to the structure. # Otherwise, we are ready to submit our metadata token. if not_escaped and character in structure_tokens: label_start = False metadata = "".join(metadata_buffer) # If the following condition is True, then we must have just # closed a literal. We know this because last_non_ws_char is # either None or the last non-whitespace character. # last_non_ws_char is None when we have just escaped an escape # and at the first iteration. if last_non_ws_char == "'" or not convert_underscores: # Make no modifications. yield metadata elif metadata: # Underscores are considered to be spaces when not in an # escaped literal string. yield metadata.replace("_", " ") # Clear our buffer for the next metadata token and yield our # current structure token. metadata_buffer = [] yield character # We will now handle escaped string literals. # They are inconvenient because any character inside of them is # valid, especially whitespace. # We also need to allow ' to be escaped by '. e.g. '' -> ' elif character == "'": not_escaped = not not_escaped label_start = True if last_non_ws_char == "'": # We are escaping our escape, so it should be added to our # metadata_buffer which will represent some future token. metadata_buffer.append(character) # We do not want a running chain of overcounts, so we need # to clear the last character and continue iteration from # the top. Without this, the following would happen: # ''' ' -> '' # What we want is: # ''' ' -> ' last_non_ws_char = "" last_char = "" continue elif not character.isspace() or not not_escaped: if label_start and last_char.isspace() and not_escaped: raise NewickFormatError( "Newick files cannot have unescaped whitespace in their labels." ) metadata_buffer.append(character) label_start = True # This is equivalent to an `else` however it prevents coverage from # mis-identifying the `continue` as uncalled because cpython will # optimize it to a jump that is slightly different from the normal # jump it would have done anyways. elif True: # Skip the last statement last_char = character continue last_char = character # This line is skipped in the following cases: # * comment_depth > 0, i.e. we are in a comment. # * We have just processed the sequence '' and we don't want # the sequence ''' to result in ''. # * We have encountered whitespace that is not properly escaped. last_non_ws_char = character scikit-bio-scikit-bio-a3beaa6/skbio/io/format/ordination.py000066400000000000000000000350341520735541300241060ustar00rootroot00000000000000r"""Ordination results format (:mod:`skbio.io.format.ordination`) ============================================================= .. currentmodule:: skbio.io.format.ordination The ordination results file format (``ordination``) stores the results of an ordination method in a human-readable, text-based format. The format supports storing the results of various ordination methods available in scikit-bio, including (but not necessarily limited to) PCoA, CA, RDA, and CCA. Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.stats.ordination.OrdinationResults` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- The format is text-based, consisting of six attributes that describe the ordination results: - ``Eigvals``: 1-D - ``Proportion explained``: 1-D - ``Species``: 2-D - ``Site``: 2-D - ``Biplot``: 2-D - ``Site constraints``: 2-D The attributes in the file *must* be in this order. Each attribute is defined in its own section of the file, where sections are separated by a blank (or whitespace-only) line. Each attribute begins with a header line, which contains the attribute's name (as listed above), followed by a tab character, followed by one or more tab-separated dimensions (integers) that describe the shape of the attribute's data. The attribute's data follows its header line, and is stored in tab-separated format. ``Species``, ``Site``, and ``Site constraints`` store species and site IDs, respectively, as the first column, followed by the 2-D data array. An example of this file format might look like:: Eigvals4 0.360.180.070.08 Proportion explained4 0.460.230.100.10 Species94 Species00.110.28-0.20-0.00 Species10.140.300.39-0.14 Species2-1.010.09-0.19-0.10 Species3-1.030.100.220.22 Species41.050.53-0.430.22 Species50.990.570.67-0.38 Species60.25-0.17-0.200.43 Species70.14-0.85-0.010.05 Species80.41-0.700.21-0.69 Site104 Site00.71-3.080.21-1.24 Site10.58-3.00-0.942.69 Site20.76-3.152.13-3.11 Site31.111.07-1.870.66 Site4-0.97-0.06-0.69-0.61 Site51.040.45-0.630.28 Site6-0.95-0.080.13-0.42 Site70.94-0.100.52-0.00 Site8-1.140.490.471.17 Site91.031.032.74-1.28 Biplot33 -0.160.630.76 -0.990.06-0.04 0.18-0.970.03 Site constraints104 Site00.69-3.08-0.32-1.24 Site10.66-3.060.232.69 Site20.63-3.040.78-3.11 Site31.100.50-1.550.66 Site4-0.970.06-1.12-0.61 Site51.050.53-0.430.28 Site6-1.020.10-0.00-0.42 Site70.990.570.67-0.00 Site8-1.080.131.111.17 Site90.940.611.79-1.28 If a given result attribute is not present (e.g. ``Biplot``), it should still be defined and declare its dimensions as 0. For example:: Biplot00 All attributes are optional except for ``Eigvals``. Examples -------- Assume we have the following tab-delimited text file storing the ordination results in ``ordination`` format:: Eigvals4 0.360.180.070.08 Proportion explained4 0.460.230.100.10 Species94 Species00.110.28-0.20-0.00 Species10.140.300.39-0.14 Species2-1.010.09-0.19-0.10 Species3-1.030.100.220.22 Species41.050.53-0.430.22 Species50.990.570.67-0.38 Species60.25-0.17-0.200.43 Species70.14-0.85-0.010.05 Species80.41-0.700.21-0.69 Site104 Site00.71-3.080.21-1.24 Site10.58-3.00-0.942.69 Site20.76-3.152.13-3.11 Site31.111.07-1.870.66 Site4-0.97-0.06-0.69-0.61 Site51.040.45-0.630.28 Site6-0.95-0.080.13-0.42 Site70.94-0.100.52-0.00 Site8-1.140.490.471.17 Site91.031.032.74-1.28 Biplot00 Site constraints00 Load the ordination results from the file: >>> from io import StringIO >>> from skbio import OrdinationResults >>> or_f = StringIO( ... "Eigvals\t4\n" ... "0.36\t0.18\t0.07\t0.08\n" ... "\n" ... "Proportion explained\t4\n" ... "0.46\t0.23\t0.10\t0.10\n" ... "\n" ... "Species\t9\t4\n" ... "Species0\t0.11\t0.28\t-0.20\t-0.00\n" ... "Species1\t0.14\t0.30\t0.39\t-0.14\n" ... "Species2\t-1.01\t0.09\t-0.19\t-0.10\n" ... "Species3\t-1.03\t0.10\t0.22\t0.22\n" ... "Species4\t1.05\t0.53\t-0.43\t0.22\n" ... "Species5\t0.99\t0.57\t0.67\t-0.38\n" ... "Species6\t0.25\t-0.17\t-0.20\t0.43\n" ... "Species7\t0.14\t-0.85\t-0.01\t0.05\n" ... "Species8\t0.41\t-0.70\t0.21\t-0.69\n" ... "\n" ... "Site\t10\t4\n" ... "Site0\t0.71\t-3.08\t0.21\t-1.24\n" ... "Site1\t0.58\t-3.00\t-0.94\t2.69\n" ... "Site2\t0.76\t-3.15\t2.13\t-3.11\n" ... "Site3\t1.11\t1.07\t-1.87\t0.66\n" ... "Site4\t-0.97\t-0.06\t-0.69\t-0.61\n" ... "Site5\t1.04\t0.45\t-0.63\t0.28\n" ... "Site6\t-0.95\t-0.08\t0.13\t-0.42\n" ... "Site7\t0.94\t-0.10\t0.52\t-0.00\n" ... "Site8\t-1.14\t0.49\t0.47\t1.17\n" ... "Site9\t1.03\t1.03\t2.74\t-1.28\n" ... "\n" ... "Biplot\t0\t0\n" ... "\n" ... "Site constraints\t0\t0\n") >>> ord_res = OrdinationResults.read(or_f) """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from skbio.stats.ordination import OrdinationResults from skbio.io import create_format, OrdinationFormatError from skbio.table._tabular import _create_table, _create_table_1d ordination = create_format("ordination") @ordination.sniffer() def _ordination_sniffer(fh): # Smells an ordination file if *all* of the following lines are present # *from the beginning* of the file: # - eigvals header (minimally parsed) # - another line (contents ignored) # - a whitespace-only line # - proportion explained header (minimally parsed) try: _parse_header(fh, "Eigvals", 1) next_line = next(fh, None) if next_line is not None: _check_empty_line(fh) _parse_header(fh, "Proportion explained", 1) return True, {} except OrdinationFormatError: pass return False, {} @ordination.reader(OrdinationResults) def _ordination_to_ordination_results(fh, cls=None): if cls is None: cls = OrdinationResults eigvals = _parse_vector_section(fh, "Eigvals") if eigvals is None: raise OrdinationFormatError("At least one eigval must be present.") _check_empty_line(fh) prop_expl = _parse_vector_section(fh, "Proportion explained") _check_length_against_eigvals(prop_expl, eigvals, "proportion explained values") _check_empty_line(fh) species, feature_ids = _parse_array_section(fh, "Species") _check_length_against_eigvals(species, eigvals, "coordinates per species") _check_empty_line(fh) site, sample_ids = _parse_array_section(fh, "Site") _check_length_against_eigvals(site, eigvals, "coordinates per site") _check_empty_line(fh) # biplot does not have ids to parse (the other arrays do) biplot = _parse_array_section(fh, "Biplot", has_ids=False) _check_empty_line(fh) cons, con_sample_ids = _parse_array_section(fh, "Site constraints") if cons is not None and site is not None: if not np.array_equal(con_sample_ids, sample_ids): raise OrdinationFormatError( "Site constraints ids and site ids must be equal: %s != %s" % (cons.index, site.index) ) return cls( short_method_name="", long_method_name="", eigvals=eigvals, features=species, feature_ids=feature_ids, samples=site, sample_ids=sample_ids, biplot_scores=biplot, sample_constraints=cons, proportion_explained=prop_expl, ) def _parse_header(fh, header_id, num_dimensions): line = next(fh, None) if line is None: raise OrdinationFormatError( "Reached end of file while looking for %s header." % header_id ) header = line.strip().split("\t") # +1 for the header ID if len(header) != num_dimensions + 1 or header[0] != header_id: raise OrdinationFormatError("%s header not found." % header_id) return header def _check_empty_line(fh): """Check that the next line in `fh` is empty or whitespace-only.""" line = next(fh, None) if line is None: raise OrdinationFormatError( "Reached end of file while looking for blank line separating sections." ) if line.strip(): raise OrdinationFormatError("Expected an empty line.") def _check_length_against_eigvals(data, eigvals, label): if data is not None: num_vals = data.shape[-1] num_eigvals = eigvals.shape[-1] if num_vals != num_eigvals: raise OrdinationFormatError( "There should be as many %s as eigvals: %d != %d" % (label, num_vals, num_eigvals) ) def _parse_vector_section(fh, header_id): header = _parse_header(fh, header_id, 1) # Parse how many values we are waiting for num_vals = int(header[1]) if num_vals == 0: # The ordination method didn't generate the vector, so set it to None vals = None else: # Parse the line with the vector values line = next(fh, None) if line is None: raise OrdinationFormatError( "Reached end of file while looking for line containing values " "for %s section." % header_id ) vals = _create_table_1d( data=np.asarray(line.strip().split("\t"), dtype=np.float64) ) if len(vals) != num_vals: raise OrdinationFormatError( "Expected %d values in %s section, but found %d." % (num_vals, header_id, len(vals)) ) return vals def _parse_array_section(fh, header_id, has_ids=True): """Parse an array section of `fh` identified by `header_id`.""" # Parse the array header header = _parse_header(fh, header_id, 2) # Parse the dimensions of the array rows = int(header[1]) cols = int(header[2]) ids = None if rows == 0 and cols == 0: # The ordination method didn't generate the array data for 'header', so # set it to None data = None elif rows == 0 or cols == 0: # Both dimensions should be 0 or none of them are zero raise OrdinationFormatError( "One dimension of %s is 0: %d x %d" % (header_id, rows, cols) ) else: # Parse the data data = np.empty((rows, cols), dtype=np.float64) if has_ids: ids = [] for i in range(rows): # Parse the next row of data line = next(fh, None) if line is None: raise OrdinationFormatError( "Reached end of file while looking for row %d in %s " "section." % (i + 1, header_id) ) vals = line.strip().split("\t") if has_ids: ids.append(vals[0]) vals = vals[1:] if len(vals) != cols: raise OrdinationFormatError( "Expected %d values, but found %d in row %d." % (cols, len(vals), i + 1) ) data[i, :] = np.asarray(vals, dtype=np.float64) data = _create_table(data=data, index=ids) if has_ids: return data, ids else: return data @ordination.writer(OrdinationResults) def _ordination_results_to_ordination(obj, fh): _write_vector_section(fh, "Eigvals", obj.eigvals) _write_vector_section(fh, "Proportion explained", obj.proportion_explained) _write_array_section(fh, "Species", obj.features, ids=obj.feature_ids) _write_array_section(fh, "Site", obj.samples, ids=obj.sample_ids) _write_array_section(fh, "Biplot", obj.biplot_scores, has_ids=False) _write_array_section( fh, "Site constraints", obj.sample_constraints, ids=obj.sample_ids, include_section_separator=False, ) def _write_vector_section(fh, header_id, vector): if vector is None: shape = 0 else: shape = vector.shape[0] fh.write("%s\t%d\n" % (header_id, shape)) if vector is not None: fh.write(_format_vector(np.asarray(vector))) fh.write("\n") def _write_array_section( fh, header_id, data, ids=None, has_ids=True, include_section_separator=True ): # write section header if data is None: shape = (0, 0) else: shape = data.shape fh.write("%s\t%d\t%d\n" % (header_id, shape[0], shape[1])) # write section data if data is not None: if not has_ids: # Using np.asarray to handle any input, pandas/polars/numpy for vals in np.asarray(data): fh.write(_format_vector(vals)) else: for id_, vals in zip(ids, np.asarray(data)): fh.write(_format_vector(vals, id_)) if include_section_separator: fh.write("\n") def _format_vector(vector, id_=None): formatted_vector = "\t".join(np.asarray(vector, dtype=str)) if id_ is None: return "%s\n" % formatted_vector else: return "%s\t%s\n" % (id_, formatted_vector) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/phylip.py000066400000000000000000000362071520735541300232500ustar00rootroot00000000000000"""PHYLIP multiple sequence alignment format (:mod:`skbio.io.format.phylip`) ========================================================================= .. currentmodule:: skbio.io.format.phylip The PHYLIP file format stores a multiple sequence alignment. The format was originally defined and used in Joe Felsenstein's PHYLIP package [1]_, and has since been supported by multiple other bioinformatics tools (e.g., RAxML [2]_). See [3]_ for the original format description, and [4]_ and [5]_ for additional descriptions. An example PHYLIP-formatted file taken from [3]_:: 5 42 Turkey AAGCTNGGGC ATTTCAGGGT GAGCCCGGGC AATACAGGGT AT Salmo gairAAGCCTTGGC AGTGCAGGGT GAGCCGTGGC CGGGCACGGT AT H. SapiensACCGGTTGGC CGTTCAGGGT ACAGGTTGGC CGTTCAGGGT AA Chimp AAACCCTTGC CGTTACGCTT AAACCGAGGC CGGGACACTC AT Gorilla AAACCCTTGC CGGTACGCTT AAACCATTGC CGGTACGCTT AA .. note:: Original copyright notice for the above PHYLIP file: *(c) Copyright 1986-2008 by The University of Washington. Written by Joseph Felsenstein. Permission is granted to copy this document provided that no fee is charged for it and that this copyright notice is not removed.* Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.alignment.TabularMSA` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- PHYLIP format is a plain text format containing exactly two sections: a header describing the dimensions of the alignment, followed by the multiple sequence alignment itself. The format described here is "sequential" format. The original PHYLIP format specification [3]_ describes both sequential and interleaved formats. .. note:: scikit-bio currently supports reading and writing strict, sequential PHYLIP-formatted files. Relaxed and/or interleaved PHYLIP formats are not supported. Relaxed vs. Strict PHYLIP ^^^^^^^^^^^^^^^^^^^^^^^^^^ scikit-bio supports both **relaxed** and **strict** PHYLIP formats: **Strict PHYLIP** (default): - Sequence IDs must be exactly 10 characters (padded or truncated) - Characters 1-10 are the ID, remaining characters are the sequence - IDs **may** contain whitespace (e.g., "Sample 01 ") - This is the default format for both reading and writing **Relaxed PHYLIP** (optional): - Sequence IDs can have arbitrary length - IDs and sequences are separated by whitespace (spaces or tabs) - IDs **must not** contain whitespace - Enable by setting ``strict=False`` when reading Header Section ^^^^^^^^^^^^^^ The header consists of a single line describing the dimensions of the alignment. It **must** be the first line in the file. The header consists of optional spaces, followed by two positive integers (``n`` and ``m``) separated by one or more spaces. The first integer (``n``) specifies the number of sequences (i.e., the number of rows) in the alignment. The second integer (``m``) specifies the length of the sequences (i.e., the number of columns) in the alignment. The smallest supported alignment dimensions are 1x1. .. note:: scikit-bio will write the PHYLIP format header *without* preceding spaces, and with only a single space between ``n`` and ``m``. PHYLIP format *does not* support blank line(s) between the header and the alignment. Alignment Section ^^^^^^^^^^^^^^^^^ The alignment section immediately follows the header. It consists of ``n`` lines (rows), one for each sequence in the alignment. Each row consists of a sequence identifier (ID) and characters in the sequence, in fixed width format. The sequence ID can be up to 10 characters long. IDs less than 10 characters must have spaces appended to them to reach the 10 character fixed width. Within an ID, all characters except newlines are supported, including spaces, underscores, and numbers. .. note:: When reading a PHYLIP-formatted file into an ``skbio.alignment.TabularMSA`` object, sequence identifiers/labels are stored as ``TabularMSA`` index labels (``index`` property). When writing an ``skbio.alignment.TabularMSA`` object as a PHYLIP-formatted file, ``TabularMSA`` index labels will be converted to strings and written as sequence identifiers/labels. scikit-bio supports the empty string (``''``) as a valid sequence ID. An empty ID will be padded with 10 spaces when writing. Sequence characters immediately follow the sequence ID. They *must* start at the 11th character in the line, as the first 10 characters are reserved for the sequence ID. While PHYLIP format does not explicitly restrict the set of supported characters that may be used to represent a sequence, the original format description [3]_ specifies the IUPAC nucleic acid lexicon for DNA or RNA sequences, and the IUPAC protein lexicon for protein sequences. The original PHYLIP specification uses ``-`` as a gap character, though older versions also supported ``.``. The sequence characters may contain optional spaces (e.g., to improve readability), and both upper and lower case characters are supported. .. note:: scikit-bio will read/write a PHYLIP-formatted file as long as the alignment's sequence characters are valid for the type of in-memory sequence object being read into or written from. This differs from the PHYLIP specification, which states that a PHYLIP-formatted file can only contain valid IUPAC characters. See the ``constructor`` format parameter below for details. Since scikit-bio supports both ``-`` and ``.`` as gap characters (e.g., in ``DNA``, ``RNA``, and ``Protein`` sequence objects), both are supported when reading/writing a PHYLIP-formatted file. When writing a PHYLIP-formatted file, scikit-bio will split up each sequence into chunks that are 10 characters long. Each chunk will be separated by a single space. The sequence will always appear on a single line (sequential format). It will *not* be wrapped across multiple lines. Sequences are chunked in this manner for improved readability, and because most example PHYLIP files are chunked in a similar way (e.g., see the example file above). Note that this chunking is not required when reading PHYLIP-formatted files, nor by the PHYLIP format specification itself. Format Parameters ----------------- Reader-specific Parameters ^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``constructor`` (required): The type of in-memory sequence object to read each aligned sequence into. Must be a subclass of ``GrammaredSequence`` (e.g., ``DNA``, ``RNA``, ``Protein``). For example, if you know that the PHYLIP file being readi contains DNA sequences, you would pass ``constructor=DNA`` to the reader call. - ``strict`` : A Boolean indicating whether the object IDs are in strict (``True``, default) or relaxed (``False``) format. .. versionadded:: 0.7.2 Examples -------- Let's create a ``TabularMSA`` with three DNA sequences: >>> from skbio import TabularMSA, DNA >>> seqs = [DNA('ACCGTTGTA-GTAGCT', metadata={'id':'seq1'}), ... DNA('A--GTCGAA-GTACCT', metadata={'id':'sequence-2'}), ... DNA('AGAGTTGAAGGTATCT', metadata={'id':'3'})] >>> msa = TabularMSA(seqs, minter='id') >>> msa TabularMSA[DNA] ---------------------- Stats: sequence count: 3 position count: 16 ---------------------- ACCGTTGTA-GTAGCT A--GTCGAA-GTACCT AGAGTTGAAGGTATCT >>> msa.index # doctest: +ELLIPSIS Index(['seq1', 'sequence-2', '3'], dtype='...') Now let's write the ``TabularMSA`` to file in PHYLIP format and take a look at the output: >>> from io import StringIO >>> fh = StringIO() >>> print(msa.write(fh, format='phylip').getvalue()) 3 16 seq1 ACCGTTGTA- GTAGCT sequence-2A--GTCGAA- GTACCT 3 AGAGTTGAAG GTATCT >>> fh.close() Notice that the 16-character sequences were split into two chunks, and that each sequence appears on a single line (sequential format). Also note that each sequence ID is padded with spaces to 10 characters in order to produce a fixed width column. If the index labels in a ``TabularMSA`` surpass the 10-character limit, an error will be raised when writing: >>> msa.index = ['seq1', 'long-sequence-2', 'seq3'] >>> fh = StringIO() >>> msa.write(fh, format='phylip') Traceback (most recent call last): ... skbio.io._exception.PhylipFormatError: ``TabularMSA`` can only be written in \ PHYLIP format if all sequence index labels have 10 or fewer characters. Found \ sequence with index label 'long-sequence-2' that exceeds this limit. Use \ ``TabularMSA.reassign_index`` to assign shorter index labels. >>> fh.close() One way to work around this is to assign shorter index labels. The recommended way to do this is via ``TabularMSA.reassign_index``. For example, to reassign default integer index labels: >>> msa.reassign_index() >>> msa.index RangeIndex(start=0, stop=3, step=1) We can now write the ``TabularMSA`` in PHYLIP format: >>> fh = StringIO() >>> print(msa.write(fh, format='phylip').getvalue()) 3 16 0 ACCGTTGTA- GTAGCT 1 A--GTCGAA- GTACCT 2 AGAGTTGAAG GTATCT >>> fh.close() References ---------- .. [1] https://phylipweb.github.io/phylip .. [2] Stamatakis, A. (2014). RAxML version 8: a tool for phylogenetic analysis and post-analysis of large phylogenies. Bioinformatics, 30(9), 1312-1313. .. [3] https://phylipweb.github.io/phylip/doc/sequence.html .. [4] http://www.phylo.org/tools/obsolete/phylip.html .. [5] https://bioperl.org/formats/alignment_formats/PHYLIP_multiple_alignment_format.html """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from skbio.alignment import TabularMSA from skbio.io import create_format, PhylipFormatError from skbio.util._misc import chunk_str phylip = create_format("phylip") @phylip.sniffer() def _phylip_sniffer(fh): # Strategy: # Read the header and a single sequence; verify that the sequence length # matches the header information. Do not verify that the total number of # lines matches the header information, since that would require reading # the whole file. try: header = next(fh).rstrip() _, seq_len = _validate_header(header) line = next(fh).rstrip() # Try strict format try: _validate_line(line, seq_len, strict=True) return True, {} except PhylipFormatError: pass # Try relaxed format try: _validate_line(line, seq_len, strict=False) return True, {} except PhylipFormatError: pass return False, {} except (StopIteration, PhylipFormatError): return False, {} @phylip.reader(TabularMSA) def _phylip_to_tabular_msa(fh, cls=None, constructor=None, strict=True): if cls is None: cls = TabularMSA if constructor is None: raise ValueError("Must provide `constructor`.") seqs = [] index = [] for seq, id_ in _parse_phylip_raw(fh, strict=strict): seqs.append(constructor(seq, metadata={"id": id_})) index.append(id_) return cls(seqs, index=index) @phylip.writer(TabularMSA) def _tabular_msa_to_phylip(obj, fh): sequence_count = obj.shape.sequence if sequence_count < 1: raise PhylipFormatError( "TabularMSA can only be written in PHYLIP format if there is at " "least one sequence in the alignment." ) sequence_length = obj.shape.position if sequence_length < 1: raise PhylipFormatError( "TabularMSA can only be written in PHYLIP format if there is at " "least one position in the alignment." ) chunk_size = 10 labels = [str(label) for label in obj.index] for label in labels: if len(label) > chunk_size: raise PhylipFormatError( "``TabularMSA`` can only be written in PHYLIP format if all " "sequence index labels have %d or fewer characters. Found " "sequence with index label '%s' that exceeds this limit. Use " "``TabularMSA.reassign_index`` to assign shorter index labels." % (chunk_size, label) ) fh.write("{0:d} {1:d}\n".format(sequence_count, sequence_length)) fmt = "{0:%d}{1}\n" % chunk_size for label, seq in zip(labels, obj): chunked_seq = chunk_str(str(seq), chunk_size, " ") fh.write(fmt.format(label, chunked_seq)) def _validate_header(header): header_vals = header.split() try: n_seqs, seq_len = [int(x) for x in header_vals] if n_seqs < 1 or seq_len < 1: raise PhylipFormatError( "The number of sequences and the length must be positive." ) except ValueError: raise PhylipFormatError( "Found non-header line when attempting to read the 1st record " "(header line should have two space-separated integers): " '"%s"' % header ) return n_seqs, seq_len def _validate_line(line, seq_len, strict=True): if not line: raise PhylipFormatError("Empty lines are not allowed.") if strict: # Strict: first 10 characters are ID, rest is sequence ID = line[:10].strip() seq = line[10:].replace(" ", "") else: # Relaxed: whitespace-separated ID and sequence split_line = line.split(None, 1) # Split on first whitespace if len(split_line) < 2: raise PhylipFormatError( "Each line must contain an ID and sequence separated by whitespace." ) ID = split_line[0] seq = split_line[1].replace(" ", "") if len(seq) != seq_len: raise PhylipFormatError( "The length of sequence %s is not %s as specified in the header." % (ID, seq_len) ) return (seq, ID) def _parse_phylip_raw(fh, strict=True): """Raw parser for PHYLIP files. Returns a list of raw (seq, id) values. It is the responsibility of the caller to construct the correct in-memory object to hold the data. """ # Note: this returns the full data instead of yielding each sequence, # because the header specifies the number of sequences, so the file cannot # be validated until it's read completely. # File should have a single header on the first line. try: header = next(fh).rstrip() except StopIteration: raise PhylipFormatError("This file is empty.") n_seqs, seq_len = _validate_header(header) # All following lines should be ID+sequence. No blank lines are allowed. data = [] for line in fh: data.append(_validate_line(line.rstrip(), seq_len, strict=strict)) if len(data) != n_seqs: raise PhylipFormatError( "The number of sequences is not %s " % n_seqs + "as specified in the header." ) return data scikit-bio-scikit-bio-a3beaa6/skbio/io/format/phylip_dm.py000066400000000000000000000432761520735541300237340ustar00rootroot00000000000000"""PHYLIP distance matrix format (:mod:`skbio.io.format.phylip_dm`) ================================================================ .. currentmodule:: skbio.io.format.phylip_dm .. versionadded:: 0.7.2 The PHYLIP file format stores pairwise distance matrices. This format is commonly used in phylogenetic analysis and is compatible with tools in the PHYLIP package. See [1]_ for the original format description. An example PHYLIP-formatted distance matrix in lower triangular layout:: 5 Seq1 Seq2 1.6866 Seq3 1.7198 1.5232 Seq4 1.6606 1.4841 0.7115 Seq5 1.5243 1.4465 0.5958 0.4631 And its equivalent in square layout:: 5 Seq1 0.0000 1.6866 1.7198 1.6606 1.5243 Seq2 1.6866 0.0000 1.5232 1.4841 1.4465 Seq3 1.7198 1.5232 0.0000 0.7115 0.5958 Seq4 1.6606 1.4841 0.7115 0.0000 0.4631 Seq5 1.5243 1.4465 0.5958 0.4631 0.0000 Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.stats.distance.DistanceMatrix` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- PHYLIP format is a plain text format containing exactly two sections: a header describing the number of objects in the matrix, followed by the matrix itself. Header Section ^^^^^^^^^^^^^^ The header consists of a single line with a single positive integer (``n``) that specifies the number of objects in the matrix. This **must** be the first line in the file. The integer may be preceded by optional whitespace. .. note:: scikit-bio writes the PHYLIP format header without preceding spaces. Matrix Section ^^^^^^^^^^^^^^ The matrix section immediately follows the header. It consists of ``n`` lines (rows), one for each object. Each row consists of an object identifier (ID) followed by the distance values for that object, separated by whitespace. Two alternative layouts of the matrix body are supported: **Square matrices**: Each row contains ``n`` distance values (the full row of the distance matrix, including the diagonal). **Lower triangular matrices**: Row ``i`` contains ``i`` distance values (only the values below the diagonal). The first row contains no distance values, just the ID. .. note:: Empty lines are not allowed between the header and the matrix. .. note:: The original PHYLIP format also defines upper triangular matrices, although they are less common and currently not supported by scikit-bio. Object IDs ^^^^^^^^^^ scikit-bio supports both **relaxed** and **strict** object ID formats: **Relaxed format** (default): - IDs can have arbitrary length - IDs **must not** contain whitespace characters (spaces, tabs, etc.) - All characters except whitespace are valid **Strict format** (``strict=True``): - IDs occupy exactly the first 10 characters of each line - IDs **may** contain whitespace - IDs are automatically padded or truncated to 10 characters scikit-bio writes in relaxed format by default. For strict format compatibility with legacy PHYLIP tools, ensure your IDs are 10 characters or fewer and do not contain whitespace. .. note:: When writing, any whitespace in IDs is automatically replaced with underscores to ensure compatibility with relaxed format. Format Parameters ----------------- layout : {'lower', 'square'}, optional Layout of the matrix body. Options are "lower" (lower triangle) and "square" (square). Applicable to both reading and writing. The layout of the input file is automatically inferred during reading, although one can explicitly set this parameter to override. Writing defaults to lower triangle. strict : bool, optional Whether the object IDs are in strict (True) or relaxed (False, default) format. Only applicable to reading. The ID format of the input file is automatically inferred during reading, although one can explicitly set this parameter to override. Writing always uses the relaxed format. dtype : str or dtype, optional The data type of the underlying matrix data. Default is "float64", which maps to ``np.float64``. The only other available option is "float32" (or ``np.float32``). Only relevant when reading from a file. Examples -------- Reading PHYLIP Files ^^^^^^^^^^^^^^^^^^^^ Read a PHYLIP distance matrix file into a ``DistanceMatrix`` object: >>> from skbio import DistanceMatrix >>> dm = DistanceMatrix.read('input.phy', format='phylip_dm') # doctest: +SKIP Read with strict ID format parsing: >>> dm = DistanceMatrix.read( # doctest: +SKIP ... 'input_strict.phy', format='phylip_dm', strict=True) Read from a file handle: >>> with open('input.phy', 'r') as f: # doctest: +SKIP ... dm = DistanceMatrix.read(f, format='phylip_dm') Writing PHYLIP Files ^^^^^^^^^^^^^^^^^^^^ Use the standard scikit-bio I/O interface to write PHYLIP distance matrices. You can choose between lower triangular (more compact) or square layout. Write to lower triangular layout (default): >>> dm.write('output.phy', format='phylip_dm') # doctest: +SKIP >>> # or explicitly: >>> dm.write('output.phy', format='phylip_dm', layout='lower') # doctest: +SKIP Write to square layout: >>> dm.write('output_square.phy', format='phylip_dm', layout='square') # doctest: +SKIP Write to a file handle: >>> with open('output.phy', 'w') as f: # doctest: +SKIP ... dm.write(f, format='phylip_dm') .. note:: The choice of output format (lower triangular vs. square) is independent of how the DistanceMatrix was created. You can write any DistanceMatrix to either format. Working with Whitespace in IDs ------------------------------- **Relaxed format** does not support whitespace in IDs. If your IDs contain whitespace and you're using relaxed format, the parser will treat the first whitespace-delimited token as the ID and subsequent tokens as distance values, which will cause parsing errors. **Strict format** supports whitespace in IDs because IDs are positional (first 10 characters). To read files with whitespace in IDs, use ``strict=True``. When **writing** files, scikit-bio automatically replaces any whitespace in IDs with underscores to ensure compatibility:: >>> ids = ['Sample 01', 'Sample 02', 'Sample 03'] >>> dm = DistanceMatrix([[0, 1, 2], [1, 0, 3], [2, 3, 0]], ids=ids) >>> dm.write('output.phy', format='phylip_dm') # doctest: +SKIP >>> # IDs in output will be: 'Sample_01', 'Sample_02', 'Sample_03' Common Errors ------------- **"Inconsistent distance counts detected"**: This error typically occurs when: - IDs contain whitespace in relaxed format (use ``strict=True`` if needed) - The file has irregular formatting or wrong number of values per row **"The number of distances is not N as specified in the header"**: This occurs when: - A row has too many or too few distance values - IDs contain whitespace and are being parsed as distance values **"Empty lines are not allowed"**: - PHYLIP format does not allow blank lines between the header and matrix or within the matrix itself. References ---------- .. [1] Felsenstein, J. PHYLIP (Phylogeny Inference Package) version 3.6. Distributed by the author. Department of Genome Sciences, University of Washington, Seattle. 2005. https://phylipweb.github.io/phylip/doc/distance.html """ # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from skbio.stats.distance import DistanceMatrix from skbio.io import create_format, PhylipDMFormatError phylip_dm = create_format("phylip_dm") @phylip_dm.sniffer() def _phylip_dm_sniffer(fh): # First line defines number of objects. try: n_objs = _parse_header(next(fh)) except (StopIteration, PhylipDMFormatError): return False, {} # Remaining lines define matrix body (ID + distance values). We will collect up to # 5 lines for validation. lines = [] for _ in range(5): try: lines.append(next(fh)) except StopIteration: break # Must have at least one object. if len(lines) < 1: return False, {} # Sequentially test four combinations of format parameters. If any of these passed, # return immediately. If failed, continue to test the next combination. for square in (False, True): for strict in (False, True): try: for i, line in enumerate(lines): _parse_line(line, i, n_objs, square, strict, float) except PhylipDMFormatError: continue else: return True, { "layout": "square" if square else "lower", "strict": strict, } return False, {} @phylip_dm.reader(DistanceMatrix) def _phylip_dm_to_distance_matrix( fh, cls=None, layout="lower", strict=False, dtype="float64" ): if cls is None: cls = DistanceMatrix dtype = _check_dtype(dtype) square = _check_layout(layout) data, ids = _phylip_dm_to_matrix(fh, square, strict, dtype) return cls(data, ids) @phylip_dm.writer(DistanceMatrix) def _distance_matrix_to_phylip_dm(obj, fh, layout="lower"): _matrix_to_phylip_dm(obj, fh, delimiter="\t", layout=layout) def _phylip_dm_to_matrix(fh, square, strict, dtype): """Parse a PHYLIP formatted distance matrix file. Parameters ---------- fh : iterator of str File handle of a PHYLIP formatted distance matrix. square : bool Square (True) or lower triangular (False) layout of matrix body. strict : bool Strict (True) or relaxed (False) object ID format. dtype : type Data type of distance values (float64 or float32). Returns ------- data : ndarray of shape (n_objects, n_objects) Distance matrix data. ids : list of str Object IDs. Raises ------ PhylipDMFormatError If file is empty. If matrix body contains more or less rows than defined by the header. """ # parse header and determine number of objects try: header = next(fh) except StopIteration: raise PhylipDMFormatError("This file is empty.") n_objs = _parse_header(header) # allocate array space data = np.empty((n_objs, n_objs), dtype=dtype) ids = [] # parse each line of matrix body and append results for i, line in enumerate(fh): id_, vals, n_vals = _parse_line(line, i, n_objs, square, strict, dtype) ids.append(id_) try: data[i, :n_vals] = vals except IndexError: raise PhylipDMFormatError( f"The number of rows in the matrix body exceeds {n_objs} as specified " "in the header." ) if len(ids) < n_objs: raise PhylipDMFormatError( f"The number of rows in the matrix body ({len(ids)}) does not match the " f"number of objects specified in the header ({n_objs})." ) # fill upper triangle of the array if not square: np.fill_diagonal(data, 0.0) upper = np.triu_indices(n_objs, k=1) data[upper] = data.T[upper] return data, ids def _matrix_to_phylip_dm(obj, fh, delimiter, layout): """Write a distance matrix object into a PHYLIP distance matrix file. Parameters ---------- obj : DistanceMatrix Distance matrix object. fh : file handle PHYLIP distance matrix file. delimiter : str Field delimiter. layout : {'square', 'lower'} Matrix layout. Raises ------ TypeError If dtype is invalid. PhylipDMFormatError If file is empty. """ n_samples = obj.shape[0] if n_samples < 2: raise PhylipDMFormatError( "DistanceMatrix can only be written in PHYLIP format if there are at least" " two samples in the matrix." ) ids = obj.ids fh.write(f"{str(n_samples)}\n") # square layout if _check_layout(layout): for id_, vals in zip(ids, obj.data): # Here we are replacing whitespace with underscore on write, but we still # need to be able to index the DistanceMatrix object by id (which may # contain whitespace) so create a separate variable for writing the id id_w = _remove_whitespace(id_) fh.write(id_w) fh.write(delimiter) fh.write(delimiter.join(np.asarray(obj[id_], dtype=str))) fh.write("\n") # lower triangular layout (default) else: for i, id_ in enumerate(ids): # Here we are replacing whitespace with underscore on write, but we still # need to be able to index the DistanceMatrix object by id (which may # contain whitespace) so create a separate variable for writing the id id_w = _remove_whitespace(id_) fh.write(id_w) if i > 0: fh.write(delimiter) fh.write(delimiter.join(np.asarray(obj[id_][:i], dtype=str))) fh.write("\n") def _parse_header(header): """Check that the header line contains a valid number of objects. Parameters ---------- header : str The header line being validated. Returns ------- n_objs The number of objects in the matrix. Raises ------ PhylipDMFormatError If header cannot be converted into an integer. If number of objects is zero or negative. """ try: n_objs = int(header.strip()) except ValueError: raise PhylipDMFormatError("Header line must be a single integer.") if n_objs < 1: raise PhylipDMFormatError("The number of objects must be positive.") return n_objs def _parse_line(line, idx, n_objs, square, strict, dtype): """Parse each line in the matrix body. Parameters ---------- line : str Line of text being parsed. idx : int Line index relative to matrix body (e.g., 2nd line of file has idx = 0). n_objs : int Number of objects in the matrix. square : bool Square (True) or lower triangular (False) layout of matrix body. strict : bool Strict (True) or relaxed (False) object ID format. dtype : type Data type of distance values (float64 or float32). Returns ------- str Object ID. ndarray Distance values. int Number of distance values. Raises ------ PhylipDMFormatError If line contains only whitespaces. If object ID is empty (strict only). If there are non-numeric values. """ msg_plus = ( "This may indicate that object IDs contain whitespace. IDs may contain" "whitespace only in the strict format." ) line = line.rstrip() if not line: raise PhylipDMFormatError("Empty lines are not allowed.") # Strict mode: IDs are 10 characters or less. if strict: id_ = line[:10].strip() rest = line[10:] if not id_: raise PhylipDMFormatError("Empty IDs are not allowed.") # Relaxed mode: IDs are separated from values by whitespace. else: try: id_, rest = line.split(None, 1) except ValueError: id_, rest = line.strip(), "" # this could happen in the first line # Convert cell values into numbers. # `sep=" "` can handle all contiguous whitespaces, like Python's `str.split()`. # If `rest` consists of only contiguous whitespaces, output will be [-1], so it is # important to strip it before processing. try: vals = np.fromstring(rest, sep=" ", dtype=dtype) except ValueError: raise PhylipDMFormatError( f"Non-numeric cell values encountered in line {idx + 2}." ) else: n_vals = vals.size # Check if the number of distance values in the line is expected. For square # matrices, each line should contain the same number of distances as defined in the # header (n_objs). if square: if n_vals != n_objs: raise PhylipDMFormatError( f"The number of distance values ({n_vals}) in line {idx + 2} does not " f"match the expectation ({n_objs}, as specified in the header)." ) # For lower triangular matrices, we expect 0 distance on the first (non-header) # line, a single distance on the second line, and two distances on the third line. # So on so forth. Therefore n_vals is equal to the line index (minus the header). else: if n_vals != idx: raise PhylipDMFormatError( f"The number of distance values ({n_vals}) in line {idx + 2} does not " f"match the expectation ({idx}, which is line number - 2)." ) return id_, vals, n_vals def _remove_whitespace(id_): """Replace whitepace with underscores in IDs.""" return id_.replace(" ", "_") def _check_layout(layout): if layout == "lower": return False elif layout == "square": return True elif layout == "upper": raise PhylipDMFormatError("Upper triangular layout is currently not supported.") else: raise PhylipDMFormatError(f"'{layout}' is not a supported matrix layout.") def _check_dtype(dtype): if (typ := np.dtype(dtype)) not in (np.float64, np.float32): raise TypeError(f"{dtype} is not a supported data type.") return typ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/qseq.py000066400000000000000000000243621520735541300227130ustar00rootroot00000000000000r"""QSeq format (:mod:`skbio.io.format.qseq`) ========================================= .. currentmodule:: skbio.io.format.qseq The QSeq format (`qseq`) is a record-based, plain text output format produced by some DNA sequencers for storing biological sequence data, quality scores, per-sequence filtering information, and run-specific metadata. Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |No |generator of :mod:`skbio.sequence.Sequence` objects | +------+------+---------------------------------------------------------------+ |Yes |No |:mod:`skbio.sequence.Sequence` | +------+------+---------------------------------------------------------------+ |Yes |No |:mod:`skbio.sequence.DNA` | +------+------+---------------------------------------------------------------+ |Yes |No |:mod:`skbio.sequence.RNA` | +------+------+---------------------------------------------------------------+ |Yes |No |:mod:`skbio.sequence.Protein` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- A QSeq file is composed of single-line records, delimited by tabs. There are 11 fields in a record: - Machine name - Run number - Lane number (positive int) - Tile number (positive int) - X coordinate (integer) - Y coordinate (integer) - Index - Read number (1-3) - Sequence data (typically IUPAC characters) - Quality scores (quality scores encoded as printable ASCII) - Filter boolean (1 if sequence has passed CASAVA's filter, 0 otherwise) For more details please refer to the CASAVA documentation [1]_. .. note:: When a QSeq file is read into a scikit-bio object, the object's `metadata` attribute is automatically populated with data corresponding to the names above. .. note:: `lowercase` functionality is supported when reading QSeq files. Refer to specific object constructor documentation for details. .. note:: scikit-bio allows for the filter field to be omitted, but it is not clear if this is part of the original format specification. Format Parameters ----------------- The following parameters are the same as in FASTQ format (:mod:`skbio.io.format.fastq`): - ``variant``: see ``variant`` parameter in FASTQ format - ``phred_offset``: see ``phred_offset`` parameter in FASTQ format The following additional parameters are the same as in FASTA format (:mod:`skbio.io.format.fasta`): - ``constructor``: see ``constructor`` parameter in FASTA format - ``seq_num``: see ``seq_num`` parameter in FASTA format Generators Only ^^^^^^^^^^^^^^^ - ``filter``: If `True`, excludes sequences that did not pass filtering (i.e., filter field is 0). Default is `True`. Examples -------- Suppose we have the following QSeq file:: illumina 1 3 34 -30 30 0 1 ACG....ACGTAC ruBBBBrBCEFGH 1 illumina 1 3 34 30 -30 0 1 CGGGCATTGCA CGGGCasdGCA 0 illumina 1 3 35 -30 30 0 2 ACGTA.AATAAAC geTaAafhwqAAf 1 illumina 1 3 35 30 -30 0 3 CATTTAGGA.TGCA tjflkAFnkKghvM 0 Let's define this file in-memory as a ``StringIO``, though this could be a real file path, file handle, or anything that's supported by scikit-bio's I/O registry in practice: >>> from io import StringIO >>> fs = '\n'.join([ ... 'illumina\t1\t3\t34\t-30\t30\t0\t1\tACG....ACGTAC\truBBBBrBCEFGH\t1', ... 'illumina\t1\t3\t34\t30\t-30\t0\t1\tCGGGCATTGCA\tCGGGCasdGCA\t0', ... 'illumina\t1\t3\t35\t-30\t30\t0\t2\tACGTA.AATAAAC\tgeTaAafhwqAAf\t1', ... 'illumina\t1\t3\t35\t30\t-30\t0\t3\tCATTTAGGA.TGCA\ttjflkAFnkKghvM\t0' ... ]) >>> fh = StringIO(fs) To iterate over the sequences using the generator reader, we run: >>> import skbio.io >>> for seq in skbio.io.read(fh, format='qseq', variant='illumina1.3'): ... seq ... print('') Sequence -------------------------------------- Metadata: 'id': 'illumina_1:3:34:-30:30#0/1' 'index': 0 'lane_number': 3 'machine_name': 'illumina' 'read_number': 1 'run_number': 1 'tile_number': 34 'x': -30 'y': 30 Positional metadata: 'quality': Stats: length: 13 -------------------------------------- 0 ACG....ACG TAC Sequence -------------------------------------- Metadata: 'id': 'illumina_1:3:35:-30:30#0/2' 'index': 0 'lane_number': 3 'machine_name': 'illumina' 'read_number': 2 'run_number': 1 'tile_number': 35 'x': -30 'y': 30 Positional metadata: 'quality': Stats: length: 13 -------------------------------------- 0 ACGTA.AATA AAC Note that only two sequences were loaded because the QSeq reader filters out sequences whose filter field is 0 (unless ``filter=False`` is supplied). References ---------- .. [1] http://biowulf.nih.gov/apps/CASAVA_UG_15011196B.pdf """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from skbio.io import create_format, QSeqFormatError from skbio.io.format._base import _decode_qual_to_phred, _get_nth_sequence from skbio.sequence import Sequence, DNA, RNA, Protein _default_phred_offset = None _default_variant = None _will_filter = True qseq = create_format("qseq") @qseq.sniffer() def _qseq_sniffer(fh): empty = True try: for _, line in zip(range(10), fh): _record_parser(line) empty = False return not empty, {} except QSeqFormatError: return False, {} @qseq.reader(None) def _qseq_to_generator( fh, cls=None, constructor=Sequence, filter=_will_filter, phred_offset=_default_phred_offset, variant=_default_variant, **kwargs, ): for line in fh: ( machine_name, run, lane, tile, x, y, index, read, seq, raw_qual, filtered, ) = _record_parser(line) if not filter or not filtered: phred = _decode_qual_to_phred(raw_qual, variant, phred_offset) seq_id = "%s_%s:%s:%s:%s:%s#%s/%s" % ( machine_name, run, lane, tile, x, y, index, read, ) yield constructor( seq, metadata={ "id": seq_id, "machine_name": machine_name, "run_number": int(run), "lane_number": int(lane), "tile_number": int(tile), "x": int(x), "y": int(y), "index": int(index), "read_number": int(read), }, positional_metadata={"quality": phred}, **kwargs, ) @qseq.reader(Sequence) def _qseq_to_sequence( fh, cls=None, seq_num=1, phred_offset=_default_phred_offset, variant=_default_variant, **kwargs, ): if cls is None: cls = Sequence return _get_nth_sequence( _qseq_to_generator( fh, filter=False, phred_offset=phred_offset, variant=variant, constructor=cls, **kwargs, ), seq_num, ) @qseq.reader(DNA) def _qseq_to_dna( fh, cls=None, seq_num=1, phred_offset=_default_phred_offset, variant=_default_variant, **kwargs, ): if cls is None: cls = DNA return _get_nth_sequence( _qseq_to_generator( fh, filter=False, phred_offset=phred_offset, variant=variant, constructor=cls, **kwargs, ), seq_num, ) @qseq.reader(RNA) def _qseq_to_rna( fh, cls=None, seq_num=1, phred_offset=_default_phred_offset, variant=_default_variant, **kwargs, ): if cls is None: cls = RNA return _get_nth_sequence( _qseq_to_generator( fh, filter=False, phred_offset=phred_offset, variant=variant, constructor=cls, **kwargs, ), seq_num, ) @qseq.reader(Protein) def _qseq_to_protein( fh, cls=None, seq_num=1, phred_offset=_default_phred_offset, variant=_default_variant, **kwargs, ): if cls is None: cls = Protein return _get_nth_sequence( _qseq_to_generator( fh, filter=False, phred_offset=phred_offset, variant=variant, constructor=cls, **kwargs, ), seq_num, ) def _record_parser(line): fields = line.rstrip("\n") if fields: fields = fields.split("\t") else: raise QSeqFormatError("Found blank line.") f_len = len(fields) if not (10 <= f_len <= 11): raise QSeqFormatError("Expected 10 or 11 fields, found %d." % f_len) # If the filter field was omitted, assume that it passed filtering: if f_len == 10: fields.append("1") (machine, run, lane, tile, x, y, index, read, seq, raw_qaul, filter) = fields _test_fields([("filter", filter)], lambda x: x in "01", "0 or 1") _test_fields([("read", read)], lambda x: x in "123", "in the range [1, 3]") _test_fields([("x", x), ("y", y)], lambda x: int(x) is not None, "an integer") _test_fields( [("lane", lane), ("tile", tile)], lambda x: int(x) >= 0, "a positive integer" ) return (machine, run, lane, tile, x, y, index, read, seq, raw_qaul, filter == "0") def _test_fields(iterkv, test, efrag): try: for k, v in iterkv: if not test(v): raise ValueError() except ValueError: raise QSeqFormatError("Field %r is not %s." % (k, efrag)) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/sample_metadata.py000066400000000000000000000333051520735541300250600ustar00rootroot00000000000000"""Sample Metadata object ported over from qiime2. =============================================== .. currentmodule:: skbio.io.format.sample_metadata This implements the Sample_Metadata format which is identical to the Metadata format implemented in qiime2. (see: https://docs.qiime2.org/2024.2/tutorials/metadata/) An example sample_metadata file: .. code-block:: none id col1 col2 col3 #q2:types categorical categorical categorical id1 1 a foo id2 2 b bar id3 3 c 42 Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.metadata.SampleMetadata` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- Metadata Formatting Requirements ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ QIIME 2 metadata is most commonly stored in a TSV (i.e. tab-separated values) file. These files typically have a .tsv or .txt file extension, though it doesn't matter to QIIME 2 what file extension is used. TSV files are simple text files used to store tabular data, and the format is supported by many types of software, such as editing, importing, and exporting from spreadsheet programs and databases. Thus, it's usually straightforward to manipulate QIIME 2 metadata using the software of your choosing. If in doubt, we recommend using a spreadsheet program such as Microsoft Excel or Google Sheets to edit and export your metadata files. The following sections describe formatting requirements for QIIME 2 metadata files, and how to validate your metadata files. Since there is no universal standard for TSV files, it is important to adhere to these requirements and understand how QIIME 2 will interpret the file's contents to get the most out of your (meta)data! Metadata Validation ^^^^^^^^^^^^^^^^^^^ Sample and feature metadata files stored in Google Sheets can be validated using Keemei. Select Add-ons > Keemei > Validate QIIME 2 metadata file to validate metadata stored in Google Sheets. QIIME 2 will also automatically validate a metadata file anytime it is used by the software. However, using Keemei to validate your metadata is recommended because a report of all validation errors and warnings will be presented each time Keemei is run. Loading your metadata in QIIME 2 will typically present only a single error at a time, which can make identifying and resolving validation issues cumbersome, especially if there are many issues with the metadata. Leading and trailing whitespace characters ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If any cell in the metadata contains leading or trailing whitespace characters (e.g. spaces, tabs), those characters will be ignored when the file is loaded. Thus, leading and trailing whitespace characters are not significant, so cells containing the values 'gut' and ' gut ' are equivalent. This rule is applied before any other rules described below. Comments and Empty Rows ^^^^^^^^^^^^^^^^^^^^^^^ Rows whose first cell begins with the pound sign (#) are interpreted as comments and may appear anywhere in the file. Comment rows are ignored by QIIME 2 and are for informational purposes only. Inline comments are not supported. Empty rows (e.g. blank lines or rows consisting solely of empty cells) may appear anywhere in the file and are ignored. Identifier Column ^^^^^^^^^^^^^^^^^ The first column in the metadata file is the identifier (ID) column. This column defines the sample or feature IDs associated with your study. It is not recommended to mix sample and feature IDs in a single metadata file; keep sample and feature metadata stored in separate files. The ID column name (i.e. ID header) must be one of the following values. The values listed below may not be used to name other IDs or columns in the file. Case-insensitive: - id - sampleid - sample id - sample-id - fetureid - feature id - feature-id Case-sensitive (these are mostly for backwards-compatibility with QIIME 1, biom-format, and Qiita files): - #SampleID - #Sample ID - #OTUID - #OTU ID - sample_name The following rules apply to IDs: - IDs may consist of any Unicode characters, with the exception that IDs must notstart with the pound sign (#), as those rows would be interpreted as comments and ignored. See the section Recommendations for Identifiers for recommendations on choosing identifiers in your study. - IDs cannot be empty (i.e. they must consist of at least one character). - IDs must be unique (exact string matching is performed to detect duplicates). - At least one ID must be present in the file. - IDs cannot use any of the reserved ID column names listed above. Recommendations for Identifiers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Our goal with QIIME 2 is to support arbitrary Unicode characters in all cells of metadata files. However, given that QIIME 2 plugins and interfaces can be developed by anyone, we can’t make a guarantee that arbitrary Unicode characters will work with all plugins and interfaces. We can therefore make recommendations to users about characters that should be safe to use in identifiers, and we are preparing resources for plugin and interface developers to help them make their software as robust as possible. As developer resources become available, we will announce them in the Developer Discussion category on the QIIME 2 Forum. Sample and feature identifiers with problematic characters tend to cause the most issues for our users. Based on our experiences with QIIME 1, QIIME 2, and other bioinformatics and command line tools, we can recommend the following attributes for identifiers: - Identifiers should be 36 characters long or less. - Identifiers should contain only ASCII alphanumeric characters (i.e. in the range of [a-z], [A-Z], or [0-9]), the period (.) character, or the dash (-) character. An important point to remember is that sometimes values in your sample metadata can become identifiers. For example, taxonomy annotations can become feature identifiers following qiime taxa collapse, and sample or feature metadata values can become identifiers after applying qiime feature-table group. If you plan to apply these or similar methods where metadata values can become identifiers, you will be less likely to encounter problems if the values adhere to these identifier recommendations as well. To help users become aware of these recommendations, the Keemei metadata validator will warn users about identifiers that don’t meet the above recommendations. Users may be interested in the cual-id software for assistance with creating sample identifiers. The cual-id paper also provides some discussion on how to design identifiers. Metadata Columns ^^^^^^^^^^^^^^^^ The ID column is the first column in the metadata file, and can optionally be followed by additional columns defining metadata associated with each sample or feature ID. Metadata files are not required to have additional metadata columns, so a file containing only an ID column is a valid QIIME 2 metadata file. The following rules apply to column names: - May consist of any Unicode characters. - Cannot be empty (i.e. column names must consist of at least one character). - Must be unique (exact string matching is performed to detect duplicates). - Column names cannot use any of the reserved ID column names described in the section Identifier Column. The following rules apply to column values: - May consist of any Unicode characters. - Empty cells represent missing data. Other values such as NA are not interpreted as missing data; only the empty cell is recognized as “missingâ€�. Note that cells consisting solely of whitespace characters are also interpreted as missing data because leading and trailing whitespace characters are always ignored, effectively making the cell empty. Column Types ^^^^^^^^^^^^ QIIME 2 currently supports categorical and numeric metadata columns. By default, QIIME 2 will attempt to infer the type of each metadata column: if the column consists only of numbers or missing data, the column is inferred to be numeric. Otherwise, if the column contains any non-numeric values, the column is inferred to be categorical. Missing data (i.e. empty cells) are supported in categorical columns as well as numeric columns. QIIME 2 supports an optional comment directive to allow users to explicitly state a column's type, avoiding the column type inference described above. This can be useful if there is a column that appears to be numeric, but should actually be treated as categorical metadata (e.g. a Subject column where subjects are labeled 1, 2, 3, etc). Explicitly declaring a column's type also makes your metadata file more descriptive because the intended column type is included with the metadata, instead of relying on software to infer the type (which isn't always transparent). You can use an optional comment directive to declare column types in your metadata file, either manually or through the q2cli developer tools. For manual specifications within your metadata file(s), the comment directive must appear directly below the header. The row's first cell must be #q2:types or #sk:types to indicate the row is a comment directive. Subsequent cells may contain the values categorical or numeric (both case-insensitive). The empty cell is also supported if you do not wish to assign a type to a column (the type will be inferred in that case). Thus, it is easy to include this comment directive without having to declare types for every column in your metadata. Number Formatting ^^^^^^^^^^^^^^^^^ If a column is to be interpreted as a numeric metadata column (either through column type inference or by using the #q2:types comment directive), numbers in the column must be formatted following these rules: - Use the decimal number system: ASCII characters [0-9], . for an optional decimal point, and + and - for positive and negative signs, respectively. - Examples: 123, 123.45, 0123.40, -0.000123, +1.23 - Scientific notation may be used with E-notation; both e and E are supported. - Examples: 1e9, 1.23E-4, -1.2e-08, +4.5E+6 - Only up to 15 digits total (including before and after the decimal point) are supported to stay within the 64-bit floating point specification. Numbers exceeding 15 total digits are unsupported and will result in undefined behavior. - Common representations of not a number (e.g. NaN, nan) or infinity (e.g. inf, -Infinity) are not supported. Use an empty cell for missing data (e.g. instead of NaN). Infinity is not supported at this time in QIIME 2 metadata files. """ # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import csv import re from skbio.io import create_format from skbio.metadata._metadata import SampleMetadata from skbio.metadata.io import MetadataReader, MetadataWriter # newline="" is because otherwise csv.writer will write blank lines between rows # in Windows. See: https://stackoverflow.com/questions/3348460/ sample_metadata = create_format("sample_metadata", newline="") @sample_metadata.sniffer() def _sample_metadata_sniffer(fh): # Strategy: # Check if first word in the file is in the list # of allowed metadata words try: tsv_reader = csv.reader(fh, dialect="excel-tab", strict=True) # sample id and feature id are not separated when reading the tsv # since they are not tab-separated. possible_ids = [ "id", "sampleid", "sample-id", "featureid", "feature-id", "sample id", "feature id", "sample_name", # Technically this should be case-sensitive ] possible_ids_w_leading_comment_char = [ "#SampleID", "#Sample ID", "#OTUID", "#OTU ID", ] # We need to find the actual header row # so we loop until we find the first row that isn't empty or a comment for header in tsv_reader: # Skip empty rows if len(header) == 0: continue match = re.search(r"\S+", header[0]) # Check if first word is a columnID that starts with # if match and match.group() in possible_ids_w_leading_comment_char: return True, {} # Skip rows whose first non-whitespace character is a # # since they are comments. skips empty rows too. if not match or match.group()[0] == "#": continue if any( [x.casefold() == header[0].strip().casefold() for x in possible_ids] ): return True, {} # if the first non-empty non-comment row doesn't have a valid id as # first entry we conclude that this is not a metadata file. return False, {} # In case the file is empty and has no rows that are non-empty non-comment # we return a negative result. return False, {} # if we run into errors with the csv file we assume its not a metadata file except csv.Error: return False, {} @sample_metadata.reader(SampleMetadata) def _sample_metadata_read(fh, cls=None, **kwargs): if cls is None: cls = SampleMetadata return MetadataReader(fh).read(cls, **kwargs) @sample_metadata.writer(SampleMetadata) def _sample_metadata_write(obj, fh): MetadataWriter(obj).write(fh) scikit-bio-scikit-bio-a3beaa6/skbio/io/format/stockholm.py000066400000000000000000000705441520735541300237500ustar00rootroot00000000000000"""Stockholm format (:mod:`skbio.io.format.stockholm`) =================================================== .. currentmodule:: skbio.io.format.stockholm The Stockholm format is a multiple sequence alignment format (MSA) that optionally supports storing arbitrary alignment features (metadata). Features can be placed into four different categories: GF, GS, GR, and GC (described in more detail below). An example Stockholm file, taken from [1]_: .. code-block:: none # STOCKHOLM 1.0 #=GF ID UPSK #=GF SE Predicted; Infernal #=GF SS Published; PMID 9223489 #=GF RN [1] #=GF RM 9223489 #=GF RT The role of the pseudoknot at the 3' end of turnip yellow mosaic #=GF RT virus RNA in minus-strand synthesis by the viral RNA-dependent \ RNA #=GF RT polymerase. #=GF RA Deiman BA, Kortlever RM, Pleij CW; #=GF RL J Virol 1997;71:5990-5996. AF035635.1/619-641 UGAGUUCUCGAUCUCUAAAAUCG M24804.1/82-104 UGAGUUCUCUAUCUCUAAAAUCG J04373.1/6212-6234 UAAGUUCUCGAUCUUUAAAAUCG M24803.1/1-23 UAAGUUCUCGAUCUCUAAAAUCG #=GC SS_cons .AAA....<<<>>> // Format Support -------------- **Has Sniffer: Yes** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |Yes |:mod:`skbio.alignment.TabularMSA` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- The Stockholm format consists of a header, a multiple sequence alignment, associated metadata (features), and a footer. Header ^^^^^^ The first line of a Stockholm file must be the following header: .. code-block:: none # STOCKHOLM 1.0 Multiple Sequence Alignment ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Sequence lines consist of a sequence name, followed by whitespace, followed by the aligned sequence. For example:: seq1 ACG-T-GGT seq2 ACCGTTCG- Sequence names (``seq1``, ``seq2``) are stored in the ``TabularMSA`` ``index``. .. note:: scikit-bio currently supports reading Stockholm files where each sequence is contained on a single line. Interleaved/wrap-around Stockholm files are not supported. When writing, each sequence will be placed on its own line. .. warning:: Sequence names must be unique in the Stockholm file. Likewise, when writing from a ``TabularMSA``, ``index`` must be unique. Metadata ^^^^^^^^ Stockholm files support storing arbitrary metadata (features) about the MSA. All metadata described in the following sections are optional and may appear in any order. Metadata "mark-up" lines begin with either ``#=GF``, ``#=GS``, ``#=GR``, or ``#=GC``, and each line describes a single feature of the alignment. .. note:: Stockholm format supports generic features. [1]_ and [2]_ provide a list of common features output by Pfam/Rfam. scikit-bio does not require that these features are present. These features are processed in the same way as any arbitrary feature would be, as a simple key-value pair of strings. When writing, feature names, feature data, and sequence names are converted to type ``str``. .. note:: When writing a Stockholm file, scikit-bio will place the metadata in the format's recommended order: - GF: Above the alignment - GS: Above the alignment (after GF) - GR: Below corresponding sequence - GC: Below the alignment GF metadata +++++++++++ Data relating to the multiple sequence alignment as a whole, such as authors or number of sequences in the alignment. Starts with ``#=GF`` followed by a feature name and data relating to the feature. Typically comes first in a Stockholm file. For example (taken from [2]_): .. code-block:: none #=GF DE CBS domain Where ``DE`` is the feature name and ``CBS Domain`` is the feature data. GF metadata is stored in the ``TabularMSA`` ``metadata`` dictionary. .. note:: When reading, duplicate GF feature names will have their values concatenated in the order they appear in the file. Concatenation will also add a space between lines if one isn't already there in order to avoid joining words together. When writing, each GF feature will be placed on its own line, regardless of length. .. note:: Trees labelled with ``NH``/``TN`` are handled differently than other GF features. When reading a Stockholm file with these features, the reader follows the rules described in [2]_. Trees split over multiple lines will have their values concatenated. Unlike other GF features, trees will never have a space added when they are concatenated. A single tree without an identifier will be stored as:: metadata = { 'NH': 'tree in NHX format' } A single tree with an identifier will be stored as:: metadata = { 'NH': { 'tree-id': 'tree in NHX format' } } Multiple trees (which must have identifiers) will be stored as:: metadata = { 'NH': { 'tree-id-1': 'tree in NHX format', 'tree-id-2': 'tree in NHX format' } } .. note:: References labelled with ``RN``/``RM``/``RT``/``RA``/``RL``/``RC`` are handled differently than other GF features. When reading a Stockholm file with these features, the reader populates a list of dictionaries, where each dictionary represents a single reference. The list contains references in the order they appear in the file, regardless of the value provided for ``RN``. If a reference does not include all possible reference tags (e.g. ``RC`` is missing), the dictionary will only contain the reference tags present for that reference. When writing, the writer adds a reference number (``RN``) line before writing each reference, for example: .. code-block:: none #=GF RN [1] #=GF RA Kestrel Gorlick ... #=GF RN [2] ... References will be stored as:: metadata = { 'RN': [{ 'RM': 'reference medline', 'RT': 'reference title', 'RA': 'reference author', 'RL': 'reference location', 'RC': 'reference comment' }, { 'RM': 'reference medline', ... }] } GS metadata +++++++++++ Data relating to a specific sequence in the multiple sequence alignment. Starts with ``#=GS`` followed by the sequence name followed by a feature name and data relating to the feature. Typically comes after GF metadata in a Stockholm file. For example (taken from [2]_): .. code-block:: none #=GS O83071/259-312 AC O83071 Where ``O83071/259-312`` is the sequence name, ``AC`` is the feature name, and ``083071`` is the feature data. GS metadata is stored in the sequence-specific ``metadata`` dictionary. .. note:: When reading, duplicate GS feature names will have their values concatenated in the order they appear in the file. Concatenation will also add a space between lines if one isn't already there in order to avoid joining words together. When writing, each GS feature will be placed on its own line, regardless of length. GR metadata +++++++++++ Data relating to the columns of a specific sequence in a multiple sequence alignment. Starts with ``#=GR`` followed by the sequence name followed by a feature name and data relating to the feature, one character per column. Typically comes after the sequence line it relates to. For example (taken from [2]_): .. code-block:: none #=GR O31698/18-71 SS CCCHHHHHHHHHHHHHHH..EEEEEEEE....EEEEEEEEHHH Where ``O31698/18-71`` is the sequence name, ``SS`` is the feature name, and ``CCCHHHHHHHHHHHHHHH..EEEEEEEE....EEEEEEEEHHH`` is the feature data. GR metadata is stored in sequence-specific ``positional_metadata``. .. note:: Duplicate GR feature names attributed to a single sequence are disallowed. GC metadata +++++++++++ Data relating to the columns of the multiple sequence alignment as a whole. Starts with ``#=GC`` followed by a feature name and data relating to the feature, one character per column. Typically comes at the end of the multiple sequence alignment. For example (taken from [2]_): .. code-block:: none #=GC SS_cons CCCCCHHHHHHHHHHHHH..EEEEEEEE....EEEEEEEEEEH Where ``SS_cons`` is the feature name and ``CCCCCHHHHHHHHHHHHH..EEEEEEEE....EEEEEEEEEEH`` is the feature data. GC metadata is stored in ``TabularMSA`` ``positional_metadata``. .. note:: Duplicate GC feature names are disallowed. Footer ^^^^^^ The final line of a Stockholm file must be the following footer:: // .. note:: scikit-bio currently supports reading a Stockholm file containing a single MSA. If the file contains more than one MSA, only the first MSA will be read into a ``TabularMSA``. Format Parameters ----------------- The only supported format parameter is ``constructor``, which specifies the type of in-memory sequence object to read each aligned sequence into. This must be a subclass of ``GrammaredSequence`` (e.g., ``DNA``, ``RNA``, ``Protein``) and is a required format parameter. For example, if you know that the Stockholm file you're reading contains DNA sequences, you would pass ``constructor=DNA`` to the reader call. Examples -------- Suppose we have a Stockholm file containing an MSA of protein sequences (modified from [2]_): >>> import skbio.io >>> from io import StringIO >>> from skbio import Protein, TabularMSA >>> fs = '\\n'.join([ ... '# STOCKHOLM 1.0', ... '#=GF CC CBS domains are small intracellular modules mostly' ... ' found', ... '#=GF CC in 2 or four copies within a protein.', ... '#=GS O83071/192-246 AC O83071', ... '#=GS O31698/88-139 OS Bacillus subtilis', ... 'O83071/192-246 MTCRAQLIAVPRASSLAE..AIACAQKM....RVSRV', ... '#=GR O83071/192-246 SA 999887756453524252..55152525....36463', ... 'O83071/259-312 MQHVSAPVFVFECTRLAY..VQHKLRAH....SRAVA', ... 'O31698/18-71 MIEADKVAHVQVGNNLEH..ALLVLTKT....GYTAI', ... 'O31698/88-139 EVMLTDIPRLHINDPIMK..GFGMVINN......GFV', ... 'O31699/88-139 EVMLTDIPRLHINDPIMK..GFGMVINN......GFV', ... '#=GR O31699/88-139 AS ________________*____________________', ... '#=GR O31699/88-139 IN ____________1______________2_________', ... '#=GC SS_cons CCCCCHHHHHHHHHHHHH..EEEEEEEE....EEEEE', ... '//' ... ]) >>> fh = StringIO(fs) >>> msa = TabularMSA.read(fh, constructor=Protein) >>> msa # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS TabularMSA[Protein] ---------------------------------------------------------------------- Metadata: 'CC': 'CBS domains are small intracellular modules mostly found in 2 or four copies within a protein.' Positional metadata: 'SS_cons': Stats: sequence count: 5 position count: 37 ---------------------------------------------------------------------- MTCRAQLIAVPRASSLAE..AIACAQKM....RVSRV MQHVSAPVFVFECTRLAY..VQHKLRAH....SRAVA MIEADKVAHVQVGNNLEH..ALLVLTKT....GYTAI EVMLTDIPRLHINDPIMK..GFGMVINN......GFV EVMLTDIPRLHINDPIMK..GFGMVINN......GFV The sequence names are stored in the ``index``: >>> msa.index # doctest: +ELLIPSIS Index(['O83071/192-246', 'O83071/259-312', 'O31698/18-71', 'O31698/88-139', 'O31699/88-139'], dtype='...') The ``TabularMSA`` has GF metadata stored in its ``metadata`` dictionary: >>> list(msa.metadata.items()) [('CC', 'CBS domains are small intracellular modules mostly found in 2 or \ four copies within a protein.')] GC metadata is stored in the ``TabularMSA`` ``positional_metadata``: >>> msa.positional_metadata # doctest: +ELLIPSIS SS_cons 0 C 1 C 2 C 3 C 4 C 5 H 6 H 7 H 8 H 9 H ... GS metadata is stored in the sequence-specific ``metadata`` dictionary: >>> list(msa[0].metadata.items()) [('id', 'O83071/192-246'), ('AC', 'O83071')] GR metadata is stored in sequence-specific ``positional_metadata``: >>> msa[4].positional_metadata # doctest: +ELLIPSIS AS IN 0 _ _ 1 _ _ 2 _ _ 3 _ _ 4 _ _ 5 _ _ 6 _ _ 7 _ _ 8 _ _ 9 _ _ ... Let's write this ``TabularMSA`` in Stockholm format: >>> fh = StringIO() >>> _ = msa.write(fh, format='stockholm') >>> print(fh.getvalue()) # STOCKHOLM 1.0 #=GF CC CBS domains are small intracellular modules mostly found in 2 or four \ copies within a protein. #=GS O83071/192-246 AC O83071 #=GS O31698/88-139 OS Bacillus subtilis O83071/192-246 MTCRAQLIAVPRASSLAE..AIACAQKM....RVSRV #=GR O83071/192-246 SA 999887756453524252..55152525....36463 O83071/259-312 MQHVSAPVFVFECTRLAY..VQHKLRAH....SRAVA O31698/18-71 MIEADKVAHVQVGNNLEH..ALLVLTKT....GYTAI O31698/88-139 EVMLTDIPRLHINDPIMK..GFGMVINN......GFV O31699/88-139 EVMLTDIPRLHINDPIMK..GFGMVINN......GFV #=GR O31699/88-139 AS ________________*____________________ #=GR O31699/88-139 IN ____________1______________2_________ #=GC SS_cons CCCCCHHHHHHHHHHHHH..EEEEEEEE....EEEEE // >>> fh.close() References ---------- .. [1] https://en.wikipedia.org/wiki/Stockholm_format .. [2] http://sonnhammer.sbc.su.se/Stockholm.html """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from collections import OrderedDict from skbio.alignment import TabularMSA from skbio.sequence._grammared_sequence import GrammaredSequence from skbio.io import create_format, StockholmFormatError stockholm = create_format("stockholm") _REFERENCE_TAGS = frozenset({"RM", "RT", "RA", "RL", "RC"}) @stockholm.sniffer() def _stockholm_sniffer(fh): # Smells a Stockholm file if the following conditions are met: # - File isn't empty # - File contains correct header try: line = next(fh) except StopIteration: return False, {} if _is_header(line): return True, {} return False, {} @stockholm.reader(TabularMSA) def _stockholm_to_tabular_msa(fh, cls=None, constructor=None): # Checks that user has passed required constructor parameter if constructor is None: raise ValueError( "Must provide `constructor` parameter indicating the " "type of sequences in the alignment. `constructor` " "must be a subclass of `GrammaredSequence` " "(e.g., `DNA`, `RNA`, `Protein`)." ) # Checks that constructor parameter is supported elif not issubclass(constructor, GrammaredSequence): raise TypeError("`constructor` must be a subclass of `GrammaredSequence`.") # Checks that the file isn't empty try: line = next(fh) except StopIteration: raise StockholmFormatError("File is empty.") # Checks that the file follows basic format (includes the required header) if not _is_header(line): raise StockholmFormatError("File missing required Stockholm header line.") msa_data = _MSAData() for line in fh: if line.isspace(): continue line = line.rstrip("\n") if _is_sequence_line(line): seq_name, seq_data = _parse_sequence_line(line) msa_data.add_sequence(seq_name, seq_data) elif line.startswith("#=GF"): feature_name, feature_data = _parse_gf_line(line) msa_data.add_gf_metadata(feature_name, feature_data) elif line.startswith("#=GS"): seq_name, feature_name, feature_data = _parse_gs_line(line) msa_data.add_gs_metadata(seq_name, feature_name, feature_data) elif line.startswith("#=GR"): seq_name, feature_name, feature_data = _parse_gr_line(line) msa_data.add_gr_metadata(seq_name, feature_name, feature_data) elif line.startswith("#=GC"): feature_name, feature_data = _parse_gc_line(line) msa_data.add_gc_metadata(feature_name, feature_data) elif _is_footer(line): break else: raise StockholmFormatError("Unrecognized line: %r" % line) if not _is_footer(line): raise StockholmFormatError( 'Final line does not conform to Stockholm format. Must contain only "//".' ) return msa_data.build_tabular_msa(constructor) # For storing intermediate data used to construct a Sequence object. class _MSAData: def __init__(self): self._seqs = {} self._seq_order = [] self._metadata = OrderedDict() self._positional_metadata = OrderedDict() def add_sequence(self, seq_name, seq_data): if seq_name not in self._seqs: self._seqs[seq_name] = _SeqData(seq_name) self._seqs[seq_name].seq = seq_data self._seq_order.append(seq_name) def add_gf_metadata(self, feature_name, feature_data): # Handles first instance of labelled tree if feature_name == "TN" and "NH" not in self._metadata: self._metadata["NH"] = OrderedDict() self._metadata["NH"][feature_data] = "" # Handles second instance of labelled tree elif feature_name == "TN" and "NH" in self._metadata: if feature_data in self._metadata["NH"]: raise StockholmFormatError( "Tree name %r used multiple times in file." % feature_data ) self._metadata["NH"][feature_data] = "" # Handles extra line(s) of an already created tree elif feature_name == "NH" and feature_name in self._metadata: trees = self._metadata[feature_name] if isinstance(trees, OrderedDict): tree_id = next(reversed(trees)) self._metadata[feature_name][tree_id] = trees[tree_id] + feature_data else: self._metadata[feature_name] = ( self._metadata[feature_name] + feature_data ) elif feature_name == "RN": if feature_name not in self._metadata: self._metadata[feature_name] = [OrderedDict()] else: self._metadata[feature_name].append(OrderedDict()) elif feature_name in _REFERENCE_TAGS: if "RN" not in self._metadata: raise StockholmFormatError( "Expected 'RN' tag to precede '%s' tag." % feature_name ) reference_dict = self._metadata["RN"][-1] if feature_name not in reference_dict: reference_dict[feature_name] = feature_data else: padding = _get_padding(reference_dict[feature_name]) reference_dict[feature_name] += padding + feature_data elif feature_name in self._metadata: padding = _get_padding(self._metadata[feature_name][-1]) self._metadata[feature_name] = ( self._metadata[feature_name] + padding + feature_data ) else: self._metadata[feature_name] = feature_data def add_gc_metadata(self, feature_name, feature_data): if feature_name in self._positional_metadata: _raise_duplicate_error("Found duplicate GC label %r." % feature_name) self._positional_metadata[feature_name] = feature_data def add_gs_metadata(self, seq_name, feature_name, feature_data): if seq_name not in self._seqs: self._seqs[seq_name] = _SeqData(seq_name) self._seqs[seq_name].add_metadata_feature(feature_name, feature_data) def add_gr_metadata(self, seq_name, feature_name, feature_data): if seq_name not in self._seqs: self._seqs[seq_name] = _SeqData(seq_name) self._seqs[seq_name].add_positional_metadata_feature(feature_name, feature_data) def build_tabular_msa(self, constructor): if len(self._seqs) != len(self._seq_order): invalid_seq_names = set(self._seqs) - set(self._seq_order) raise StockholmFormatError( "Found GS or GR metadata for " "nonexistent sequence(s): %r" % invalid_seq_names ) seqs = [] for seq_name in self._seq_order: seqs.append(self._seqs[seq_name].build_sequence(constructor)) positional_metadata = self._positional_metadata if not positional_metadata: positional_metadata = None metadata = self._metadata if not metadata: metadata = None # Constructs TabularMSA return TabularMSA( seqs, metadata=metadata, positional_metadata=positional_metadata, index=self._seq_order, ) class _SeqData: def __init__(self, name): self.name = name self._seq = None self.metadata = {"id": name} self.positional_metadata = None @property def seq(self): return self._seq @seq.setter def seq(self, seq): if self._seq is None: self._seq = seq else: _raise_duplicate_error("Found duplicate sequence name: %r" % self.name) def add_metadata_feature(self, feature_name, feature_data): if self.metadata is None: self.metadata = OrderedDict() if feature_name in self.metadata: padding = _get_padding(self.metadata[feature_name][-1]) self.metadata[feature_name] += padding + feature_data else: self.metadata[feature_name] = feature_data def add_positional_metadata_feature(self, feature_name, feature_data): if self.positional_metadata is None: self.positional_metadata = OrderedDict() if feature_name in self.positional_metadata: _raise_duplicate_error( "Found duplicate GR label %r associated " "with sequence name %r" % (feature_name, self.name) ) else: self.positional_metadata[feature_name] = feature_data def build_sequence(self, constructor): return constructor( self.seq, metadata=self.metadata, positional_metadata=(self.positional_metadata), ) def _parse_gf_line(line): line = line.split(None, 2) _check_for_malformed_line(line, 3) return line[1:] def _parse_gs_line(line): line = line.split(None, 3) _check_for_malformed_line(line, 4) return line[1:] def _parse_gr_line(line): line = line.split(None, 3) _check_for_malformed_line(line, 4) seq_name = line[1] feature_name = line[2] feature_data = list(line[3]) return seq_name, feature_name, feature_data def _parse_gc_line(line): line = line.split(None, 2) _check_for_malformed_line(line, 3) feature_name = line[1] feature_data = list(line[2]) return feature_name, feature_data def _parse_sequence_line(line): line = line.split(None, 1) _check_for_malformed_line(line, 2) return line def _is_header(line): return line == "# STOCKHOLM 1.0\n" def _is_footer(line): return line.rstrip() == "//" def _is_sequence_line(line): return not (line.startswith("#") or _is_footer(line)) def _raise_duplicate_error(message): raise StockholmFormatError( message + " Note: If the file being used is in " "Stockholm interleaved format, this " "is not supported by the reader." ) def _check_for_malformed_line(line, expected_len): if len(line) != expected_len: raise StockholmFormatError( "Line contains %d item(s). It must " "contain exactly %d item(s)." % (len(line), expected_len) ) @stockholm.writer(TabularMSA) def _tabular_msa_to_stockholm(obj, fh): if not obj.index.is_unique: raise StockholmFormatError("The TabularMSA's index labels must be unique.") # Writes header fh.write("# STOCKHOLM 1.0\n") # Writes GF data to file if obj.has_metadata(): for gf_feature, gf_feature_data in obj.metadata.items(): if gf_feature == "NH" and isinstance(gf_feature_data, dict): for tree_id, tree in gf_feature_data.items(): fh.write("#=GF TN %s\n" % tree_id) fh.write("#=GF NH %s\n" % tree) elif gf_feature == "RN": if not isinstance(gf_feature_data, list): raise StockholmFormatError( "Expected 'RN' to contain a list of reference " "dictionaries, got %r." % gf_feature_data ) for ref_num, dictionary in enumerate(gf_feature_data, start=1): if not isinstance(dictionary, dict): raise StockholmFormatError( "Expected reference information to be stored as a " "dictionary, found reference %d stored as %r." % (ref_num, type(dictionary).__name__) ) fh.write("#=GF RN [%d]\n" % ref_num) for feature in dictionary: if feature not in _REFERENCE_TAGS: formatted_reference_tags = ", ".join( [tag for tag in _REFERENCE_TAGS] ) raise StockholmFormatError( "Invalid reference tag %r found in reference " "dictionary %d. Valid reference tags are: %s." % (feature, ref_num, formatted_reference_tags) ) fh.write("#=GF %s %s\n" % (feature, dictionary[feature])) else: fh.write("#=GF %s %s\n" % (gf_feature, gf_feature_data)) unpadded_data = [] # Writes GS data to file, retrieves GR data, and retrieves sequence data for seq, seq_name in zip(obj, obj.index): seq_name = str(seq_name) if seq.has_metadata(): for gs_feature, gs_feature_data in seq.metadata.items(): if gs_feature != "id": fh.write( "#=GS %s %s %s\n" % (seq_name, gs_feature, gs_feature_data) ) unpadded_data.append((seq_name, str(seq))) if seq.has_positional_metadata(): df = _format_positional_metadata( seq.positional_metadata, "Sequence-specific positional metadata (GR)" ) for gr_feature in df.columns: gr_feature_data = "".join(df[gr_feature]) gr_string = "#=GR %s %s" % (seq_name, gr_feature) unpadded_data.append((gr_string, gr_feature_data)) # Retrieves GC data if obj.has_positional_metadata(): df = _format_positional_metadata( obj.positional_metadata, "Multiple sequence alignment positional metadata (GC)", ) for gc_feature in df.columns: gc_feature_data = "".join(df[gc_feature]) gc_string = "#=GC %s" % gc_feature unpadded_data.append((gc_string, gc_feature_data)) # Writes GR, GC, and raw data to file with padding _write_padded_data(unpadded_data, fh) # Writes footer fh.write("//\n") def _write_padded_data(data, fh): max_data_len = 0 for label, _ in data: if len(label) > max_data_len: max_data_len = len(label) fmt = "{0:%d} {1}\n" % max_data_len for label, value in data: fh.write(fmt.format(label, value)) def _format_positional_metadata(df, data_type): # Asserts positional metadata feature names are unique if not df.columns.is_unique: num_repeated_columns = len(df.columns) - len(set(df.columns)) raise StockholmFormatError( "%s feature names must be unique. " "Found %d duplicate names." % (data_type, num_repeated_columns) ) str_df = df.astype(str) # Asserts positional metadata dataframe items are one character long for column in str_df.columns: if (str_df[column].str.len() != 1).any(): raise StockholmFormatError( "%s must contain a single character for" " each position's value. Found value(s)" " in column %s of incorrect length." % (data_type, column) ) return str_df def _get_padding(item): return "" if item[-1].isspace() else " " scikit-bio-scikit-bio-a3beaa6/skbio/io/format/taxdump.py000066400000000000000000000315421520735541300234220ustar00rootroot00000000000000r"""Taxdump format (:mod:`skbio.io.format.taxdump`) =============================================== .. currentmodule:: skbio.io.format.taxdump The NCBI Taxonomy database dump (``taxdump``) format stores information of organism names, classifications and other properties. It is a tabular format with a delimiter: ```` between columns, and a line end ```` after all columns. The file name usually ends with .dmp. Format Support -------------- **Has Sniffer: No** +------+------+---------------------------------------------------------------+ |Reader|Writer| Object Class | +======+======+===============================================================+ |Yes |No |:mod:`pandas.DataFrame` | +------+------+---------------------------------------------------------------+ Format Specification -------------------- The NCBI taxonomy database [1]_ [2]_ hosts organism names and classifications. It has a web portal [3]_ and an FTP download server [4]_. It is also accessible using E-utilities [5]_. The database is being updated daily, and an archive is generated every month. The data release has the file name ``taxdump``. It consists of multiple .dmp files. These files serve different purposes, but they follow a common format pattern: - It is a tabular format. - Column delimiter is ````. - Line end is ````. - The first column is a numeric identifier, which usually represent taxa (i.e., "TaxID"), but can also be genetic codes, citations or other entries. The two most important files of the data release are ``nodes.dmp`` and ``names.dmp``. They store the hierarchical structure of the classification system (i.e., taxonomy) and the names of organisms, respectively. They can be used to construct the taxonomy tree of organisms. The definition of columns of each .dmp file type are taken from [6]_ and [7]_. ``nodes.dmp`` ^^^^^^^^^^^^^ +----------------+-------------------------------------+ |Name |Description | +================+=====================================+ |tax_id |node id in GenBank taxonomy database | +----------------+-------------------------------------+ |parent tax_id |parent node id in GenBank taxonomy | | |database | +----------------+-------------------------------------+ |rank |rank of this node (superkingdom, | | |kingdom, ...) | +----------------+-------------------------------------+ |embl code |locus-name prefix; not unique | +----------------+-------------------------------------+ |division id |see division.dmp file | +----------------+-------------------------------------+ |inherited div |1 if node inherits division from | |flag (1 or 0) |parent | +----------------+-------------------------------------+ |genetic code id |see gencode.dmp file | +----------------+-------------------------------------+ |inherited GC |1 if node inherits genetic code from | |flag (1 or 0) |parent | +----------------+-------------------------------------+ |mitochondrial |see gencode.dmp file | |genetic code id | | +----------------+-------------------------------------+ |inherited MGC |1 if node inherits mitochondrial | |flag (1 or 0) |gencode from parent | +----------------+-------------------------------------+ |GenBank hidden |1 if name is suppressed in GenBank | |flag (1 or 0) |entry lineage | +----------------+-------------------------------------+ |hidden subtree |1 if this subtree has no sequence | |root flag |data yet | |(1 or 0) | | +----------------+-------------------------------------+ |comments |free-text comments and citations | +----------------+-------------------------------------+ Since 2018, NCBI releases "new taxonomy files" [8]_ (``new_taxdump``). The new ``nodes.dmp`` format is compatible with the classical format, plus five extra columns after all aforementioned columns. +----------------+-------------------------------------+ |Name |Description | +================+=====================================+ |plastid genetic |see gencode.dmp file | |code id | | +----------------+-------------------------------------+ |inherited PGC |1 if node inherits plastid gencode | |flag (1 or 0) |from parent | +----------------+-------------------------------------+ |specified |1 if species in the node's lineage | |species |has formal name | +----------------+-------------------------------------+ |hydrogenosome |see gencode.dmp file | |genetic code id | | +----------------+-------------------------------------+ |inherited HGC |1 if node inherits hydrogenosome | |flag (1 or 0) |gencode from parent | +----------------+-------------------------------------+ ``names.dmp`` ^^^^^^^^^^^^^ +----------------+-------------------------------------+ |Name |Description | +================+=====================================+ |tax_id |the id of node associated with this | | |name | +----------------+-------------------------------------+ |name_txt |name itself | +----------------+-------------------------------------+ |unique name |the unique variant of this name if | | |name not unique | +----------------+-------------------------------------+ |name class |(synonym, common name, ...) | +----------------+-------------------------------------+ ``division.dmp`` ^^^^^^^^^^^^^^^^ +----------------+-------------------------------------+ |Name |Description | +================+=====================================+ |division id |taxonomy database division id | +----------------+-------------------------------------+ |division cde |GenBank division code (three | | |characters) | +----------------+-------------------------------------+ |division name |e.g. BCT, PLN, VRT, MAM, PRI... | +----------------+-------------------------------------+ |comments | | +----------------+-------------------------------------+ ``gencode.dmp`` ^^^^^^^^^^^^^^^ +----------------+-------------------------------------+ |Name |Description | +================+=====================================+ |genetic code id |GenBank genetic code id | +----------------+-------------------------------------+ |abbreviation |genetic code name abbreviation | +----------------+-------------------------------------+ |name |genetic code name | +----------------+-------------------------------------+ |cde |translation table for this genetic | | |code | +----------------+-------------------------------------+ |starts |start codons for this genetic code | +----------------+-------------------------------------+ Other types of .dmp files are currently not supported by scikit-bio. However, the user may customize column definitions in using this utility. See below for details. Format Parameters ----------------- The following format parameters are available in ``taxdump`` format: - ``scheme``: The column definition scheme name of the input .dmp file. Available options are listed below. Alternatively, one can provide a custom scheme as defined in a name-to-data type dictionary. 1. ``nodes``: The classical ``nodes.dmp`` scheme. It is also compatible with new ``nodes.dmp`` format, in which case only the columns defined by the classical format will be read. 2. ``nodes_new``: The new ``nodes.dmp`` scheme. 3. ``nodes_slim``: Only the first three columns: tax_id, parent_tax_id and rank, which are the minimum required information for constructing the taxonomy tree. It can be applied to both classical and new ``nodes.dmp`` files. It can also handle custom files which only contains these three columns. 4. ``names``: The ``names.dmp`` scheme. 5. ``division``: The ``division.dmp`` scheme. 6. ``gencode``: The ``gencode.dmp`` scheme. .. note:: scikit-bio will read columns from leftmost till the number of columns defined in the scheme. Extra columns will be cropped. Examples -------- >>> from io import StringIO >>> import skbio.io >>> import pandas as pd >>> fs = '\n'.join([ ... '1\t|\t1\t|\tno rank\t|', ... '2\t|\t131567\t|\tsuperkingdom\t|', ... '6\t|\t335928\t|\tgenus\t|' ... ]) >>> fh = StringIO(fs) Read the file into a ``pd.DataFrame`` and specify that the "nodes_slim" scheme should be used: >>> df = skbio.io.read(fh, format="taxdump", into=pd.DataFrame, ... scheme="nodes_slim") >>> df # doctest: +NORMALIZE_WHITESPACE parent_tax_id rank tax_id 1 1 no rank 2 131567 superkingdom 6 335928 genus References ---------- .. [1] Federhen, S. (2012). The NCBI taxonomy database. Nucleic acids research, 40(D1), D136-D143. .. [2] Schoch, C. L., Ciufo, S., Domrachev, M., Hotton, C. L., Kannan, S., Khovanskaya, R., ... & Karsch-Mizrachi, I. (2020). NCBI Taxonomy: a comprehensive update on curation, resources and tools. Database, 2020. .. [3] https://www.ncbi.nlm.nih.gov/taxonomy .. [4] https://ftp.ncbi.nlm.nih.gov/pub/taxonomy/ .. [5] Kans, J. (2022). Entrez direct: E-utilities on the UNIX command line. In Entrez Programming Utilities Help [Internet]. National Center for Biotechnology Information (US). .. [6] https://ftp.ncbi.nlm.nih.gov/pub/taxonomy/taxdump_readme.txt .. [7] https://ftp.ncbi.nlm.nih.gov/pub/taxonomy/new_taxdump/taxdump_readme.txt .. [8] https://ncbiinsights.ncbi.nlm.nih.gov/2018/02/22/new-taxonomy-files- available-with-lineage-type-and-host-information/ """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import pandas as pd from skbio.io import create_format taxdump = create_format("taxdump") _taxdump_column_schemes = { "nodes_slim": {"tax_id": int, "parent_tax_id": int, "rank": str}, "nodes": { "tax_id": int, "parent_tax_id": int, "rank": str, "embl_code": str, "division_id": int, "inherited_div_flag": bool, "genetic_code_id": int, "inherited_GC_flag": bool, "mitochondrial_genetic_code_id": int, "inherited_MGC_flag": bool, "GenBank_hidden_flag": bool, "hidden_subtree_root_flag": bool, "comments": str, }, "names": {"tax_id": int, "name_txt": str, "unique_name": str, "name_class": str}, "division": { "division_id": int, "division_cde": str, "division_name": str, "comments": str, }, "gencode": { "genetic_code_id": int, "abbreviation": str, "name": str, "cde": str, "starts": str, }, } _taxdump_column_schemes["nodes_new"] = dict( _taxdump_column_schemes["nodes"], **{ "plastid_genetic_code_id": bool, "inherited_PGC_flag": bool, "specified_species": bool, "hydrogenosome_genetic_code_id": int, "inherited_HGC_flag": bool, }, ) @taxdump.reader(pd.DataFrame) def _taxdump_to_data_frame(fh, scheme, cls=None): """Read a taxdump file into a data frame. Parameters ---------- fh : file handle Input taxdump file scheme : str Name of column scheme Returns ------- pd.DataFrame Parsed table """ if isinstance(scheme, str): if scheme not in _taxdump_column_schemes: raise ValueError(f'Invalid taxdump column scheme: "{scheme}".') scheme = _taxdump_column_schemes[scheme] names = list(scheme.keys()) try: return pd.read_csv( fh, sep="\t\\|(?:\t|$)", engine="python", index_col=0, names=names, dtype=scheme, usecols=range(len(names)), ) except ValueError: raise ValueError("Invalid taxdump file format.") scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/000077500000000000000000000000001520735541300225235ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/__init__.py000066400000000000000000000005411520735541300246340ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/000077500000000000000000000000001520735541300234345ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast6_custom_minimal000066400000000000000000000000111520735541300276420ustar00rootroot00000000000000subject2 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast6_custom_mixed_nans000066400000000000000000000000651520735541300303520ustar00rootroot00000000000000N/A PAAWWWWW 8 1 100.00 N/A 0 query1 N/A 8 1 N/A 8 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast6_custom_multi_line000066400000000000000000000001611520735541300303630ustar00rootroot00000000000000subject2 32 0 100 N/A subject2 query1 subject2 18 0 100 N/A subject2 query1 subject1 19 0 70 N/A subject1 query2 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast6_custom_single_line000066400000000000000000000000371520735541300305140ustar00rootroot00000000000000query1 PAAWWWWW 8 1 100.00 8 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast6_default_multi_line000066400000000000000000000002171520735541300304770ustar00rootroot00000000000000query1 subject2 100.00 8 0 0 1 8 3 10 9e-05 16.9 query1 subject2 75.00 8 2 0 1 8 2 9 0.060 11.5 query2 subject1 71.43 7 2 0 1 7 1 7 0.044 11.9 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast6_default_single_line000066400000000000000000000000571520735541300306300ustar00rootroot00000000000000query1 subject2 75.00 8 2 0 1 8 2 9 0.060 11.5 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast6_invalid_column_types000066400000000000000000000002151520735541300310570ustar00rootroot000000000000001.2523 subject2 abcd 8 0 0 1 8 3 10 9e-05 16.9 query1 subject2 75.00 8 2 0 r 8 2 9 0.060 11.5 query2 subject1 71.43 7 2 0 1 7 1 7 G24TL 11.9 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast6_invalid_number_of_columns000066400000000000000000000000441520735541300320520ustar00rootroot00000000000000query1 subject2 75.00 8 2 0 1 8 2 9 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast6_invalid_type_in_column000066400000000000000000000001371520735541300313650ustar00rootroot00000000000000query1 subject2 string 8 2 0 1 8 2 9 0.060 11.5 query1 subject2 75.00 8 2 0 1 8 2 9 0.060 11.5 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_custom_minimal000066400000000000000000000001351520735541300276520ustar00rootroot00000000000000# BLAST 2.2.31+ # Query: query1 # Subject: subject1 # Fields: query id # 1 hits found query1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_custom_mixed_nans000066400000000000000000000006141520735541300303530ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 # Subject: subject1 # 0 hits found # BLASTP 2.2.31+ # Query: query1 # Subject: subject2 # Fields: query gi, subject gi, query length, subject length, query frame, sbjct frame, query id, subject id # 1 hits found 0 N/A 8 13 1 1 N/A subject2 N/A 0 8 N/A 1 1 query1 N/A # BLASTP 2.2.31+ # Query: query2 # Subject: subject4 # 0 hits found # BLAST processed 2 queries scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_custom_multi_line000066400000000000000000000006321520735541300303670ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 # Subject: subject2 # Fields: q. start, q. end, s. start, s. end, identical, mismatches, sbjct frame, query acc.ver, subject acc.ver # 3 hits found 1 8 3 10 8 0 1 query1 subject2 2 5 2 15 8 0 2 query1 subject2 1 6 2 12 8 0 1 query1 subject2 # BLASTP 2.2.31+ # Query: query1 # Subject: subject3 # 0 hits found # BLASTP 2.2.31+ # Query: query1 # Subject: subject4 # 0 hits found scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_custom_single_line000066400000000000000000000005711520735541300305200ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 # Subject: subject1 # 0 hits found # BLASTP 2.2.31+ # Query: query1 # Subject: subject2 # Fields: query id, % positives, % identity, alignment length, subject gi, bit score, q. end, query seq # 1 hits found query1 100.00 100.00 8 0 16.9 8 PAAWWWWW # BLASTP 2.2.31+ # Query: query1 # Subject: subject3 # 0 hits found # BLAST processed 2 queries scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_default_multi_line000066400000000000000000000006501520735541300305010ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 # Subject: subject1 # 0 hits found # BLASTP 2.2.31+ # Query: query1 # Subject: subject2 # Fields: query id, subject id, % identity, alignment length, mismatches, gap opens, q. start, q. end, s. start, s. end, evalue, bit score # 3 hits found query1 subject2 70.00 5 0 0 7 60 3 100 9e-05 10.5 query1 subject2 30.00 8 0 0 6 15 1 100 0.053 12.0 query1 subject2 90.00 2 0 0 9 35 2 100 0.002 8.3 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_default_single_line000066400000000000000000000005041520735541300306260ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 # Subject: subject1 # 0 hits found # BLASTP 2.2.31+ # Query: query1 # Subject: subject2 # Fields: query id, subject id, % identity, alignment length, mismatches, gap opens, q. start, q. end, s. start, s. end, evalue, bit score # 1 hits found query1 subject2 100.00 8 0 0 1 8 3 10 9e-05 16.9 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_invalid_differing_fields000066400000000000000000000006371520735541300316320ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 # Subject: subject1 # 0 hits found # BLASTP 2.2.31+ # Query: query1 # Subject: subject3 # 0 hits found # BLASTP 2.2.31+ # Query: query2 # Subject: subject1 # Fields: query id, subject id, q. start # 1 hits found query1 subject1 4 # BLASTP 2.2.31+ # Query: query2 # Subject: subject1 # Fields: query id, subject id, score # 1 hits found query2 subject2 4 # BLAST processed 2 queries scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_invalid_for_sniffer000066400000000000000000000000711520735541300306410ustar00rootroot00000000000000# BLASTP 2.2.31+ asdf # Subject: subject1 # 0 hits found scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_invalid_for_sniffer_2000066400000000000000000000000651520735541300310650ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 asdf # 0 hits found scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_invalid_gibberish000066400000000000000000000002201520735541300302710ustar00rootroot00000000000000aphanbrnaweoowehapivaborebaweo;aweifh[fapofh29r-2u-23 adjapignqp9rghp4hq2hrq93phq9hqwhpehoweawe aidgpuhp0eh9q2yrq02r9q9euq9rhg93fhqefjwphwpahw] scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_invalid_no_data000066400000000000000000000006301520735541300277450ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 # Subject: subject1 # 0 hits found # BLASTP 2.2.31+ # Query: query1 # Subject: subject2 # 0 hits found # BLASTP 2.2.31+ # Query: query1 # Subject: subject3 # 0 hits found # BLASTP 2.2.31+ # Query: query2 # Subject: subject1 # 0 hits found # BLASTP 2.2.31+ # Query: query2 # Subject: subject2 # 0 hits found # BLASTP 2.2.31+ # Query: query2 # Subject: subject3 # 0 hits found scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_invalid_too_many_columns000066400000000000000000000006321520735541300317270ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 # Subject: subject1 # 0 hits found # BLASTP 2.2.31+ # Query: query1 # Subject: subject3 # 0 hits found # BLASTP 2.2.31+ # Query: query2 # Subject: subject1 # Fields: query id, subject id # 1 hits found query1 subject1 subject2 query2 # BLASTP 2.2.31+ # Query: query2 # Subject: subject1 # Fields: query id, subject id # 1 hits found query2 subject2 # BLAST processed 2 queries scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/blast7_invalid_unrecognized_field000066400000000000000000000002631520735541300322010ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 # Subject: subject1 # 0 hits found # BLASTP 2.2.31+ # Query: query2 # Subject: subject1 # Fields: query id, sallid # 1 hits found query1 subject1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embed1.txt.npy000066400000000000000000007602001520735541300261440ustar00rootroot00000000000000“NUMPYv{'descr': 'Ö:J¼û/W½Ð0½ž½*¾t@¾8Ýí¼¬w>É#§>B…b>ñÄM= �Ѿ‡~ž>È™^>˜ë¥½\UN½ZL½%ب¾R³§>¿MÚ½&ß½ƒ`½ôß½ ºº#–2¾g®§>­P�=‹Ý£>8G[=™í¾Ø»f>Eù¾Ñß±½iœÄ¾Ƀ½ @==•°³¾ì~¦=å‰à>ЍÕ<—î>Ÿja½ä}M>ì >ýŽ7`ý½qß2=ïv¢¾kñ¾ÅVÚ>+a¥=úî€=éW>‰T¾2Ë=Å Œ¾aݦ½ù-´¾ª/(>òXô½o$K=@ÈN¾Ï÷@>]Y¨½8uu=§Þ8½Ñèx<éGª¾Ë´Y¾—'¾Ä��>F %=)ê=ï‹=A¶>®R¨>"¾ñJº½ûàP>Lzç=Žª‚>»õ¡¾Mü“¾öaP>[HE>c[=öJ2:R´¾ÛØt;Û¤]¾šó=òõo>™~ξU 0¾œ^¾¶Š >þ/Ù;„¥û=¡‰“¾r1S>ÀM>t±�=«Ò°=»Î\>9æž¾£‹=·ƒ> t¾Ùʰ½¤“¼Í�›¾�ˉ=ºo =¡-½â²¤¾¥¿>¶ÓÞª´E>ó:<UÓ=4¤&>|{ñð>H~›½rói>ÎÒ<•>Ct¾Ô‡=ú¦‚»6Ý»ïP„=öX”½Fø§¾=Â�½9é…>AŽS¾ª±u>“P¾;`æ>w½­>*æÚ¾ï² ¾9ÉØ¼ªÚ½þ-;¾ÂŸ˜¾:¾°¾ )E>óÃy=Ò»=÷#Ÿ>Ja ½w ‹½Ÿ—>Sh€¾?&¾Y¸¦½!é7¾ºIf½™Ê½(šv>ôŸs=óÎ>{/9¾ ¹�>/Ü >^>®'=îµ¾!�±¾Ï&?gbͽŸÉ<–¢½”™=Cc¾€È‹¾Â ¾ k¹¾ye>¬jN:p¬|>ƒ¡à< í¬º ê(=hø˜½¡€Œ¾=h ¾Â_ë½x¯>MHµ<õ„¾w½Å³ =,ˆª¼rì½=@ž>ª„>%Al½w·½½OêÅ=i¡¾V’f½¦Åâ¾µ�¾ Ôþ=†1ˆ¾©ǽ”c¾>çL\¾�>óLW¾‰”>픦¾Õ=Ƽ>_mM½ð¡¬¾ƾ:ÄÜ»>în¾Gÿª½RmÁ½¬äN½b G>ømº>4ó½‡Ã">®‘H½èÍO¾rÍ¢=u¬Ç½>—ß< m½ç_¢=¹±>й>š6>æfj¾é‡*¾nk¾“p>¡¡½‘ô�> ¾Ç>¼èÙ½�Aß>í}¥¾¢œ>>8«{¾õn > Øœ¾š¾Evn>bÂÓ=(>¾¹€º¡éû½x`¹½z¹m¾2{Ÿ¾´]µ¾Ó1¾iW¾×L*½aǾ…B ¾ –ê½ `–=¤È½ÿ´+<ó…{=ô×ö=¯,̾Bèp½�®>Û›M>‘tD¾CmÊ=öîh>S >;�o½cÙM½~î »¥­ ¾kr¾)=8>ƒÍšºö)l>u?Fƒµ>^$�>ÎCؾ«u1>H»€<´¾¹=K¹=ióI>‘G{=Pð’¼³%¾Óê+¾Ì,†=d”ƒ=‰óç¼äŒ= ¢\¾ ÅŠ>ߨ ¾Zè¹=-o[½6>kÉœ½2¤�¾Ò�Ë>ö»c=¿é;½‡S>­�;²·½Êº†<’Þª¼WÌG<øZm=æ „½Å, =Ùc•>î�½ÂŒ>ÞÀò½øù=½[-=É|ƒ½¾d ¼*‚¼ì@O< Ü–= )>ŠåÕ½¬1y¾þù*=•<§¾"û³>LM7¾Rý(>Ð65>Û•+>6Ü´½îž¾ë¨ä½"¸>åN‚¾0×$¾ ™=B­¤=é‘ý=a1]¾¨X>>M$`=ÑW†¾I«¾ðä§;Ú¶¼&[©>*²á»y–É= ½½8¾©§Ò=TëÉ>ôq’=a\c¾ 5r9z)>øg>�˜�>`Œ�<$>'>ãͽ€{=."­¾ 6>û<¾‰õâ>¯o¾ýVsË¿(=úF½LÕ‚¾×¾ =Ñ­ˆ=aË@>þ{½Žt”¼²å½=3Cp<“¾Í·¾Jè>]T¼àýÂ<¿”˜>ÍS¿¶wC¾%->? ¼µÞ=Iå>ß7¾�º>Œ!޽·Eç½Ú/p>8�>WL>ÊÕ˜½Ež> á ½^�A½{€T>Cþà=d8½fŸ=IǽqÔ-=‘¶Èç½Q½.w>¢ž ½Š]™¼¥ )¾Wj>x¢?PfÔ½ÂO~½Æbƒ>ò’y:ºu›½›u0>Ce>Mž> ŠÆ¾Ž�¾¸oš¾Zg�>Ї>ù½)¨>'û€½8>#=é˼>üD}>öÚ…>Âæ7¾,>!=…p¾ùNþE¦q½oð·½<† ¾a�„½\ÿè=¦ì¾Œv½�4>¼Ä*¾ËAo½!&=’¸J¾I�¾Yv¸<Ãp¡¾óΆ¾þر=(ø•=6¿Ü¼ÉÕð½NE�¾à¸¹;÷<õ½�Ý–½èH¾×æ¼<¿´>q�r¼e#8>…¾å*Ë<Ë%§¾þúß½œÜ¾¬ç-¾Åq�=w䓾‡¼€ôk¾z]ñ=æ=.á;Bq)>ãU½¼"¦�>W¿vŒP¼ª*�= ‡)>Î*ê¼ ýмܧà¼8½¿Áº½sèô½gï³¾VB˜<ÈSü2,ë½®ÝÑ=Ã#·>†@“>;’#>ý¿§Ãʽ ¾óEv= ¾âH¯½ 禼 Îš=¨‚½¸Y>�40=Èxu=àØ©=8?L= W>™‘…>j¾ò|å½øm">l�=7'É>†Å= –¾6®>xðÖ<)Û‰¾ì™‹>ª¹ð=ÊT>6Þ>¿Fͽ:yø¼]ÿJ¾ 2Ý=«»Š;W›=!$?9»‘¾FÀ¾¹HÐ>çøÂ>zÍÞ=»3 ¾¸ù¹>ì꽌ì3=X©½�¤V½N,F>k ‡¾÷²m¾2°¶¾¹s¥¾™Ä ½_:Ó=*ðW>òš2>Ó¾Ób¼¾Ö—>¾\¦�¾ö²É>‡d¾¸`U½:þ´¾–—'=r->Õ¶›½C²½ü,Z½+"->ॾ¾fî¼ÿ ³;Ô0‰<Ä÷*>×Û=Xø?<¾X¾Ì¾D='ËŸ=Î¥ ?Én'¿”.�¾I·š¾!7_=ò2¾Kß’=T�™½Z�»è_ò»¥“=*¥=Ï™A½ús¾ã¦>Ä…½Ò$î½u£¼¾®äc=0ѽ$ªI¾ñ”ì>tt">j¯$=�_F>3l6=°¹�<Ý–»9Òz½’κ=¯�;�v¸áµ¢½ãÈ–¾CÌ>vx1¾®¸>X;a>íý§½±{ü½Æ™¾üsò=hñ=ÁŠ´<€í™>`ç½GWé=7À]½ç!A>³a—¾¥ö ¾S? ½*tQ=¼ýÓ¾ 6 >aJq¾¿,<û!L=VEš>o =WGö½( ¾_^�¾§ÞP=iIQ¾ i:¼Óï¸=(N>)þ½Ùe€>]Ô„¼pH¾"÷½öGß½�J½Y[È=J9Û¼EË€¾Bɽf9²½ qÿ= Ü5¾•%>i%Ê=‚œ‚>P‘,<°ñоÑn¾¶® =K?Z¾®ì�¾˜>Fµ¾==CX¾¡àT¾PðC¾fýϼúhí½Ak³=Œ¾‚¾à]~<|�U>¯–‚>ƒô=,Ó…=ðëY¼��à½ò 1¾CŒƒ=�ôx¾Êö�=�½ê'Ñ=Ïêļ—'‹½OÃ=¾åŠé=I%¾R·@�÷1>cDc½wä >´Gì¼ÌŠ>�„¾~ôË=nDø>®ù’¾ €>73Ê=Œ@>O 7½e—½¢…¾ë˜ý¼käè¾½´V=óò™=�ì8>Ð;:¸>yõ=’ÿ…½fÉýÔð¼c…]¾òQÝ=Ø g>/ª¾=‚>Õm¾ƒüw>ßÕ=�2˜>yû=h‡=äà?ídó½?oF={e¾šüä¼z>R>iG$½ëz>½bã¾¢Œ<=ü¾>0@«=…»¾`=¤õ >TÍÚ½ý'Á½ˆ–C¾÷IÓ½wE�¾sžš¾°Îʽ9ƒ°=ôÑS;®Ø>:‚=ÚBK>@È>´HÝ>ɲP½\ÜØ=�ï8¡½ È>~ÿt½!áh½¯·Ü=¢>™AN>ÿé—½³�¤=zê=i Ò»qà«=s`=½ø…­>T=h>F==ʶÓ<:½q¾¯)•;Ðãb=p™>aÂ¥;Ñ=©¼à�Å=ÄØêM'•@¤½uÜ>ùXt=<“ï;™.—½ &'¾yŸ4¾ÚŒ;½S!Ô½ †>Ö(7>ƒÊ>ÊŠx¾§A޼>Ò½÷5¾ Ew>˜c/=2?>“wƒ>Öæ&¼A…õ=@ö½Ïœ½¼[ >B·>3¿¾�›©½½5<¾>Zý=¬ê»¾›`³½Æ3„<;Ç¿t§>/íÚ¼®Õb>sÉὋ…¾ˆZ½êš€¼Ì¬ã½Y¨>*˾ׯw¾ÿºCûó=�Ç'>úþ¿2@æ½—YÓ½¹Qñ¼ ó¾×õƒ>Ô ’>Ÿ‘y¾��¯eµ�>52ƒ¼‚Ÿ>¨™2>� ¾QG>Fª�¾xñ/«Ï>ÇiS¼í½€h>ö,¾Ø½{ÀH=Ê>Ÿ¾Sm¾4#e½ ôÞ>õx`>“ ¼ÚÙœ½vÿ/>¥Òɾ@DV¼ô?I>'SÑ<'÷ð½Sdž¾Öq£=°a>¼Ún>õÙ‹>z™½ëŒÓ=CÚ&>V¥>]|,<$^ò»ý£·:7h«>ö�n¾ÇÑ…¾ ü;>k¶3½N‚)±íc>D) >Wb>2A–>O4ž<`ï°>ÅP‹½éŸö½þ]q¾ý,H=[ñ½HC¾Ö‚½ŽZÙ=ÃKŽ>,éa½¼,"½op—½y¡(>lR ¾jgô=à÷ѾÁ2W¾Qï§øÆ„¾'L¾Uc ¾>+¹½e›=êTÅ»jX>÷–‚>1×¾FNC½€°¾ª>jŽ–<†}P¼ô/>.h¯;êཕ˽êú=ÂÛ7¼ óì½Yþ=6ç?<'*9=Ìý/>ÂOŒ>¾L>h4u=!þºŸ?qê ¾R›½=‹×C½4A^>f`1>"¿a –=¸I¯=ß]¾.Õ‹>“«î½8o ¾‡p>Æ{L=å²½HD+¾Õ³¾ÍéW;›/9<[Ú½Ö©½áco>XD“½I²¾¢ï’>©F2>ñÒ»¾¢b·¼Io¾æ…¼=Û½o¾\ª�½k Ï=V÷Ÿ>�ø‹>ÌØx¾ØVÒ¾zO‹½Y>¾Cu%>¨ì+>™w=*öÿ<ótM½`H5=dÿ½„l®¾œ›¥>{ø}>×Ü1=$›½¿:ç¾L>GÙ?¾–kI=j[¾‚£™½HãÒ;Ü é¾O>¼ 8=«û¦¾bAƒ¾}޾ ~ùàwá<“û\=9> /¤=æ„*=T‚>òêt¾?~¯>ïFø=Ò¨=“̼94Ù>{"¡½¶¥U¾ps²>WdÏ;Ö¬>ØT'¾@íÂ=5ºá=úòè½Ëæ½>ŸÄè»BW²>_0ê=CžÒ¼Ÿö=•߯½ª§O>Jç®>䤽ãPK>z¾ªß�=$“>’T¼>&ü7¼~Y™¾-_«¾Óbá;´£Ú½SØ=F”À¾ Á‚»¤0Þ½ºl>ˆV>d‡#>"³¼B:ÛƒÞò=‰îÆ>ß*ø<‡)¼;—=fÈc½,5²=Äõ>>s«è¼çZˆ>-G›=/fŒÍJ(½o5–=vÍã½^> w)½ŒÆø;úíí<�nŸ½|¤> I¾Fµ$=»üœ¾Cb¾¬·“=ª¸=°^ù¾HÌоa%¸¾qj½v„…¾³a¯¾åâ�½?A>Ž}¼Ä�^½ßh/>e%>øÁÌ= `~=Û£i¾ck?ñ?Y½¹±"¾^/¾�Ã>u/º¾èä¾™¾²§½ËM¾ß0 ¿Iâó=X;:¼ýr©¼¡b?¾{�Á¾ª”y=Îçñ½a¾ið�=îY¹=Ãü ¾¹÷ƾKúؽ§žk¼^ù=Fe¼“Ú¡½]/>ÕêH>“dš>„U?>Äþ½iƒ7¾Ï9ʽ¢ë#¾N¹½.D·½bì*>)�P>#éÏ>=§E¾79¾NT£¼Azn=À|Û»Üq½¾�@=óõ>¢ê¾›4=Ôæœ:�7P¾#ï-½˜†ð©ít½µd´¾”ǽ’ãï½<Œ$¾Yùº=™I‡¾_ŽA<”>5÷Ç=*ÖR½š×!¾ Àž¾ày´¾gC:={À½äÈT<ýâ =㣾Vw(¿Vk.>С¶=óņ½Z<¤ƒx=�O@>i€¾É…´»7 ²>õg¾¦Û¨¾$Çì½­ù6=±ŒV=Ç©m[v>÷}>Wè<Ûº =|¸®=¼ ”>¡.¾>Ý=‰(á=[™Y¼ZƒV>=^¾ÝwW<«� ½�p¿×I0>¶Û½ÕÒ´>RÆ ¾*C?<">2¹½ù.b¾Sï>Ju�=êj˽ŸR/> žÕ>¬¾Ä_=Óÿо¨(ò¾Es=ü¸…=Ôƒð;`NØ=lâ@>.ߨ¾3=…>+Œ¾ŽaÁ½Íá=ù‘>&Ÿd>hù=&¼ƒ=K/m¼–K�>ßT5>À!p¾³‰¾IÒ=§B¾[ÿ�>/Ù•¾,aÒ½ƒŒ¢>¹E; R<¾€ü7¾šÏ=Ro+>à@g¾v9j>Çýl>Ø´-¾ÿo�¾6¤“¾Ê²!¾$×Ú¾¹àA¾žf ½µÀ ½µŸâ¼ÿ—†=²T-¾tù•½ œ>J¾‡=€<½ß¸ì>ët‰=z@f>·ñx¾C“á=F£>¸¤Ú>?ÑE<Ê‹¾8E±>¿8}½¤Ý²¾Þ ƽüÛ=¾¿A8¾€3¾wµ;¼Ña>º®.¾sS¨½Àžm½²˜Å>†§ë=ØjW½Œfu½ˆ¹Ô½óÜ5¾Œ¾H)�>†¾±ñs¾ObÞ½¯cå¼!kª<ÄC×½åÕ’=öS3¾·(Qº‚¦> þªÆÈ½‹eÞ½Ëëʾi×ï=Šì>ðú½À@F>ggÕ¾n&½jÚ¾$Ý >�ñ<>'i¾û83>Ó΋=Ñú¾Î�¨>ØÛÜ=Êm-¾Rt«¾u¼Ô<”j ¾°HF¾ëy,=âÁ>EäÇ<ã‡r½“�‡>‘f¿½bÈt>¡£7>-j¾rœë=Òê?ùŽ >þ |¾b>>i•u> +R¼ýÈ‘=«ú(¾­Û:¾1¬ >ái½Ý³¢½üÑ>3º>¾‘L>ën ?ýz[>ò ?wxù=lUJ>»U¿%…–¾üSf¾¾‚m=žò>$´�¾|&W¾Úä=>‚"l=þÊG¾¬¶ô¾i ù¼.•<:#¯¾ï‘N¾'Ö=°,³¾ mÌ<Þ½e2>[ †¾Ôà¾5Äš¾à >šª½¤G‡½•�½dC”¾ƒ >ô�>­Ø<°'(¾ö¾jP¼yó¾¡}Y½®µ¾öÛq> ~ç<¡ƒ=­Ä[>ÿ1Ô=g*O=G –<ê�,¾µY»<¡Mþ=z,ѽkÚ!¾p÷�<[A.=×lä=‘z8»�<~¼å x½"m-=ÄUнP»‹¾ø`W½#e€¾·r>R¤Å=þk€=‰-2>'-®>•æÿ¼6¿‰‹Ù»ÚB ¿8¯>~JÖ¾SÝ"¾é¤k¾N­>c}¾ug¾=Ksè½Ä|޾xÜ8=Ç;µ>Ì/¾»®<¼mL¸½oc}> ô6¾|÷-¼§§P>¼óv>¾t-¾Ž‡½õ!î=“Z9¾?*¡½â,ƒ½Êp¾NJ€¾¾9>ùµŒ¾A!X¾ö'Ÿ½ì–H>ض<¾��+?(K¾"Ö€¾y�’>æ>äÚG=†bº>=kÞ>E‡�=­¾©=ö×_=:'ú½Øð˜½ˆæ9¾Ön¾MÀ—½‘XE¾ýH\>¥®‘½<>8 >„S�¾W± ¾m3Œ=©¼*¾$M=¥åÙ¼P3Y¾¿Q3<Ç$�> ô`=s%Ÿ½ÎÒä¾·ˆ¾¾E’%>DQ5¾%Œ|»âñ™=ߨ=:ˆ½ ?Çíš¼dÄi¾ù<Î뺼ċ‰¼Ýÿ‚½êp4=¿c†=Å&¾ ²ª¾ën[½)›X½r�e¼ÔîK½È=£#R=@w™½™Ÿ¾k°•>Lz…½£ÔѼ¤kÍ;ç4Ë;¤à|½ÙÁ¾qÕ>HÚ=Bà½Ö—нñ½=@žµ>,ÌQ>\gI¾æÓµ¼ê5†½Á¶â<¿.Œ=NC«½H2='菉ÂG->™$½=ñ}®¾G9 Åݽª«½>è>å(Â>:3¿†ð–¼E…U¼h�Ù½3¤=0à=ŠN±>𑼂C8=±åž=úí>ŠpľÂZm>g=Ò$µ<>Ko¾¼™>$Õ½:}î¾ØÉ½ô‡C¾¹&H¾x!¹>Æ ¿¾�Þÿ='i¤>âZ/>"‹F½du ¾A°Ò<ƒ³‰>¾ˆ¾EL�>Q_U>±’¾«>/=ÁE>î÷ >µªB>·í=©è$>ªT>™ú>¾œ£â¾ïD侩 ˆ<¹z¾ÃÚ!>§þ>“Ñ7>#âë½">³S¿=ű½u‰ü< P/>"ëd½Í†8¾¸E¾àlW½™^¦»¥N>~À·½ç ¾u[t=é¼>0‘1½äè=- ]<1:¼öQt½›˜¾œÐ‡>Ízx½åµ=p ?â~´½îŠM½_"Z>c6ò½ØP >~;¼�î^>hT¾o©’>g>¹JŸ=ªÊa>ð™ý¼É㣼”²½ªq¼=×)�>@Ý>vð¾>~z¾F…w¾"/C¾Mòž¾¬Œw¾Ì~ ¾ Ôf¾Î¹âÖ!>ZªÐ=¢IŒÙöí½O`¾ó-޾&Ð>¥JP>�be¾5MŒ=~æ@¾:º¨½+�ÿ>Ck=oƽ×z¾÷yݽÁé¾05»½pÚn¾ ø.¾Õ�ö<|­><¥�½Ö*нКZ=K>AK>Òæ½ŽúÕ¾™¡þ=&ŒÁ¾ / =E¼=0–T>6þn¾·Å­=r¿Ž=dþ¼¼Y_¢>Ë89>ÌTê»)§>¡_–½ž&Ø>*+�»¦ex>‘gß<¢ A¾B=œe¾�Ú¾œ®>Ò’å=>Á)>´‘l½ã^b>/:¾“3Í>°ÄÔ½ ‚š¾ÜÔ£> <+¾5š>%þÓ<7ëļ¾® =žÈ">UƒH>ÖYì¾}ÙܾW>¶÷†>¶�¾‚(Q¾U"?¾~½½q�->ÈÝ>× >ÕBÿ>ê¯>N¾§>Ãd†>ez9¾BåÁ¾Aÿê¼C{�¾w,Ä>…þ—<³*>êEå=‰Hú½j8«¼#%3¾s‚Ò¾;mC>ÒJ>Š«T¾x&8¾ïŠb>$ƒ€¼´¾½Á#Xåg¾@ò=иê>µÌŠ>A· >û ¾Ô >ý½XŸ\:Wˆñ=‹ï¡;ÒÍͽÇY¨¾Ùyh¾Eœ ½’·œ½$S¾·\ ¾!1(¾ é¼X%`¾-›i¾N<�¾Á¤m='…;” ª;ññƒ>,=wl÷½÷-m=ëœ=ð<Š]�½‡Û€½èWí½‚¶¡½: Խݔ½�JP¾N•?>½¢¾ZÓ<ÔkÉ=Ð&D>?*h>Ï�M>Ç$�>:Ù >QÅ<>/½�¾GWs>)„�=Un•¾—Û}½Òió¾Ô6>Kê=Ómš¾rå½Zþß½øúA>”î$¾²ƒ?ÁÚ¾vYF½;ê=»¬½Mò‡½£‘½�N>µ•Ï=q´ > ñn>3럽 ½�½—ÇŽ½ÏîÊ>x£=Ä™Z¾åÁî¾ÄÔ�>M0¾ÊZ%¾†_=œ#¯½ë)§=´�å=hJˆ½�Ÿ¾+ˆB½<“>vmý=‹9°>7¦4>Öøš¾2nù¼Ï5›¾ã¢¦¾ qνâŽì=£�v¾÷†Ä½¤$Â>ðŽæ¼‡ >Ææp¾O?¾ŽTI¾›ÃÚ=½šˆ>³<‚¾&¢íñ z=„ýÁ>%¥â½•*y=˜‰¾aÄá¾{,¾n‘¾N—>iÔ±¾3ˆ¾Ka>ª†>¼}¾ß½õ?É/L>c"Œ¾ o};&r„¾ÈF¼]¨¯½Ö,">æeɾ¯|>‹>3¾ªW¾z�=>€>‰ôô>aç=VÔ¾V(¦=ƒKÆ<ŸU^>z¢j=ê&J¾þd¼ðìÜ=ƒ4š¾Ý±W¾¥°¢¼ÈOˆ>Øc=y3¾'ªz>‡Ÿ@¾0‚*>Š[‡>ⳑ¾0“[=›¾/—¾>)î÷½æ„˜<=Ÿ¾A׺>�>V~¾âû‡½¾Ôj>!3Z¾[UM¼^f’¾*‡�>hâ?%s½PÂÓ½@š½?›æ>J�~½¸}>{>‚E£>@¾‚>è^>ç{>ó†>¦ëÿ=_–ˆ½"1¾¡Ã½õœ…=X%¾%,"¾Qu¾ ý¼4#ò=M=¾Xn¾µ >‘*¾Ÿ³6¾nÈ„>íEѽV›ð<¯0:> ½Fè½¼Hã¾Ý †>|ïX<Äý*„1= ð(¾•²>\£<>–ºÊ=,Eõ=q#¿Ë@>‰óܾâ“x½_[›º¤9¾Vk«vµ =.립�C¾šá<ÙÕØ>%ýÐ=¹»©»^˜>s>€¾Ü=â~®=bZ=g‘>Âbæ½8bµ¾‹f�>l…ï½1û>ö‚3½¶¶Þ>ºÑ“>ƒ›>–´Ž:9¬ >¡Mè½ßÙY=e&ܾÚ©>%©½òlÂ>bX =Ò0’>BÆB¾ ‰S>;𙾆k)¾É4¾»ÀW¾uç¬=##]<½O¾¿A?¾>^â=’D>ÇÀ>­za½fXÛ¾Ú¾ê]Î=ÏPÒ>HO>èP¼Ž¿R¾° €½‚é€>0 È=5p.¾8ü›>Þ•³>‹>§~>8P,=˜•f>Ã�tÿ£>nl>n½áX.=íÈ>È6`¾œÏ>³Íª>�ÎÀ½ÙZ¾F}^¾y7�=ׄ ¾w>¼½?3"½¬ ç=FÀ¾tl¨>ʦ>’ò ¾\1¼¨…é¼É’о³q½ª6y>±ï)=ëßâ> ûb>\Ÿ ¾0‡k¾è;=Ù²>ýÇS>Ι¾е>ú‡E>Çn›½Û×">pc®=óÿs¾~ ʾ«§˜½c$©=Œ]«=нí<ݽ”ž>—ý ¾ô§�½#®‹¾°¤k>pó½ÏÄP>Z]=ÿøŸ>“>b»¤¾*?ѽæMR¾ã£¾ÀçÕ½G‚¼�Ö«>%«Y>IC"¾œ˜©½æļÁ˜i¼¾Ýj¾DXê<�G]Ó=¬"W>´&þ>;6Ý<Ÿ×»¾�Ú€>$íÊ=9u>û7N¾áF–>S/>+¼2=â¥=(£u¾|¼ö;¢9Ÿ¾/Û¯¾!ž~¾}õ¾‰B0>Eê{=~õ€¾•“`>á-è½ïd>±¢>R&¾l6q:ð€=¾Sñ½\z}¾aª±¾ ‡¾ÊÈ”>ÅoB¾÷×D¼ÀÔþ=?JÈ=“ü¾¬Å¢¾Ê4¿a˜¾ ˆ:¾Ÿ^¾Í k[J>Âì…=4b6>L»=9B>¦m*=.•>ߖѽsë"?5)=Fƒ'½v<•>Ñf„;ù”&>m»Ê>¤Éœ¾[Cº<†�$>.>l"¾l¶:>sHt½Úàœ>×x½†ßܼSËm=wõ¡=¢;>–«“¾Tr=�í%>ø©”¼T˾)¤=$8a=Á�ñ=Ò¦¼§—0½„ÙT¾ó.>y†&=³'½Þ/>Ô@#¾–r>ýÖ ¾²&Ÿ½ «­<·¡>J4¼:áY½ž –=Ï…‡½;ò(¾ÍîT>êk�¾�µœ>1>±¤ ¾,sM½Ùgz¾îw$>"Dã½2ð½Ç.‹=»5ù½ÄXW=‹@¾¶˜a>mIe>ó$¾tM‡>ÏÞ>Èe=oêC>î¢e;½ž¨ÑK¾<±Ÿ|…½*L¾IäÀ>㌼!Áo=°)¾Ýþø½v.¾�È�>Keš¾bн‹'”½/7†½QÅ®=�<ý¾³mʽkUƒ½ÍYa¾J€½PÑo½Ãć¼Ef¾!O@>RÎ1¾�Õ>Ø¢v¾Í±<ó„í¾/CB¾èZ¾ÀY޾eïÿ½u^¬½ÚA+¾‡†¾´‡ ¿�ÄÕ½NŒ>ÞP¡¾µAd½¯ºÚ=…Í ¾�¢5¾¶1Õ¾à¥>Ä[ª=Pä8=¹>öóç¼ð‚оAæ=•-ú½%l�>©íâ=R[¾¨Õ/¾Öô÷=“�¾JÕŸ¾íÈ¢¾% ¬=å§¥=c³¥¾Îþƒ¼g>äãÇ=g½ï”µ¾bˈ=t­b>—T(>"€K=_ɬ=Ä´–>yã ½fúS¾ˆ±¾¾�çy½ZÇ”>ËŸ�¾2¨½Þ=ÿ­½Q¢>‚c>΄Ã>Á>¡ðœ½8¼³>�ò=Jg¾V)½½‰\L¾ñ.®=šÌŽ1*ô¾½;‰>¦åç>rýŸ=ìí…;TC¾afš¾«e>G�2=-ñ€>Úÿå<â §½òl½ì°½—Ê>Õ@/¾'·>~Ò$¾Êîò>¡¢>þؤ½…]7¼"K=Mç¥=Á£¾ßûC½ÓôS=*có¼¨ >DÀ5>“1ƒ½œi�¾ λFøw½�5°=�bs=nC>ñù‚>ƒpg½ôÞB>¶û½dp ¾“¤•>@@Ó¼˜Æ=³Ü=Á¾þ•¿…³½2Þ¼ä©ë½éæc<‡ô£¾ ¿Œ½ŸÕ>ôŠ)¾#i ¿æ$‹½F©Ø¾¿µ½kF�½çU ¾[ d;@àö<‰�Œ¾�¬·¾¤Þ¬½ýˆ¦½|�D>6r½ÿþ‘>0#p=Œë�¾%�™=Pê-=>Q€¾œ=Ñ>Æ’X>¸èÜ Ô±¾þŠ™½3k6>"³O>®l½8Æ<„̾LLž>×S]½š£O=Žw=;æo'?’Tоvã?=œ Ì½âëÁ>ÄF½î,>GK¦½ÐC=R¦ž½R!°=Øv>yΛ¾«?b<à¥P¾fÒ8¾Xν¼ÿ>vͽô?Ù>»°G>kúݼJ—{»¨Ÿ÷=ü¨¾i¼¡½ê±Ž¾Ntö¾dõ$>+[½4•>¾Â«¾Àh; ß¾Ði'>/L±½*]D¼Ü.}¾Ge{½É¯>\Ã>rä,>¿!Ѿ•‚*¾ Ù>È{:>bä¾úv½,Íy=<y¾oqc¾Y¾[‹¹>K®ƒ=:Ù=xA¾žyY>™å·=” ¿E|Œ>iá>–Ió½gÑ™=�Ô>ô¾Ä=¿£G¾#Å<~‘¾œ)h¾ìút½­ž>¼9¨>·A¾~z¢¾?™»½„™£=šù7=Sí§¾Z~[…=6<6>"d”>áôU¾œ ó>Y1Y>Ã̾» Í=åõ1>Òõ=ÄÕì<Í)ö=\õ•>µ·€=Õô}¾V¼¾a¾vék=.ÁF½:‹>€»ê½9 Ë½×Â(�¢>ã4î½Zz¿S.¾\ÄJ¾ç­¾²Ó=êoè=äØc¾â‹ ¾}ø”>æ³›¾i½—¾Ï!3¾ô³½¡'¡¾k¢Í¾&�½"'i>¨Ž€¾)¾=½µ˜¾P¸k>O{ ½Û=—r>ï”<=îQ½tk–¾ŽÊ\=‹ðì=º´>9J›>½ÁŒ>¸¬›>RQ¾zàÙ½Eã=ëX¾„7º=“u¼@Ž>†‚.>ª8“º=¾Ìm?½�lYfL�=àáν¬«É=·V=þ²Œ>œ¬£<“K¾Ý°£¾ˆ¬9>Ç)½ I6>¹þY½1� >‹S8>é¦*>,³k¿X£½%”½Ž÷µ>*M‚>¤w9>QÌ«>±‘ ½µª ¾ø,A¾²îN?ù¦¾Ø’k=Ðh£>­*°¼¥nn>0 :>5…¬»Þ}’ʼn;pÝ–½;ß>Ç:E½æÔ=!y�>ÇÅ=Ù¯å¼�]½9¾¬GŒ½?ê¤=X•;>–j<ë ž>E”›>—­¤>7F>±.’½Ìk°¼‚¼Þ ¾ç:‘ú=9H¾úz�=›X¢=y¤÷½>‹ƒ>Õ £=íió=‚"h¾; 1>I«w>nP•< Ñ€=ÁT>%‰â¾,rM¼hc?½‰õ½ýQ¾20á=ÄóÝ=®ñ¸=-ˆ¾%6¾¸1¾¾ëž=ã.>‚#=œPo¾çË‚>ÏN8>[–[>p¥½8N»:G] ¾Kõm¾»¿Ï=ÂEO¾q>뼬Q¾¿§”¾qX¼½ÆÞ=yM�¼Õy);�c¥=vŽ>£>KU>ùd¾˜¡2¾êU%¾@Wx<Æ €>±¾1=ºÎ;½½‹>% ,>nËf>•ï'¾¹@¹½pÎ>ÞRè½pÆ2¾Á�S>ê�½Ÿh=\‹ <ú²¾L¼%¾”ˆ¾øœI½XN>@i½$?yù$¿­Íx¼p =€ýã=-{==íÃ=U¥‚>½ËŸ½U`m>^ä>¿Ë´>f¤> Ë]¾œ+ú½oQ¦½ª½è=¬¡= ,6=i >N¦±¾N…>kr‰½xJ ¾y6Z=S¶>~™„¾laZ¾*œ¾é‹‰½”W¾¹¹¼ê¤§=W¨G>~,{»÷b¾eÜ‘½íú†¾\ÜX¾3ž½ÇM£>;³ç<šy¾ŸÙc½×r¾;H‹<Œš?MP‚½Úç3>C‘t¾Ç;>ܸ’= Íм] ¾@öß>u´o½x£D¾á)¡>Íþ‚>(m̾>ÏŒ¶:ßV¾M©®<ê¦2¾$ñ½ À=ª¥ê=˜³¶½)_³»T"Z¾‡É�¾‰àÀ¼cX¹½¨¹Û="¼ÿŒ:Ÿ�>½²$¾u =¥Òå2ú¼Z× <@/K¾ û½=vPü= I½¥�¨¾ekD>ªci¾‰/F>|ø=Xl>×]Ø=_ â=ªþØ;E!Q½�˜½„G¾çÒI>´]$½ZL•½ã>M¾:ãî¾An½…†«=Ý?IòŒ=ô¾¤¾ªJ޾ïÆ¾"®Ç¾çÄî=“ñ)¾¬ À¼Tݸ½9Í®¾> A=ˆ–>o>©”C½&Q?p�†=° ·>½ ½·‰ò<6¾~@5¾]/x½É+!¿Ëº­ >_xÿ¼­AÃ=Vo,¾ðÀ¾KäU¼y6!>LJ¼¼2¾µ+¾ž¹×¼‘¤»òPÚ=urš¼ñ­ˆ¾ ”¾Ý¯>öS�ßoX½6¢?¾ àõ=#~ƒ¾Ñ¡«¾KŠ>•3V¾Wq>¹´¾!ì¾}öä<.!C¾8H(>x®È¾ùGC¾+O=ê‹‚¾á�"¾Jú]>”éa>e¹<"‘ ¾MÒ =0×¾�)‹MÐÝ=lšv=Ò ¾æú>�˜>,[,¾²u)¾yÛJ¾*:>>">�d‡=~§âºÈø´<¬(=§ßf¾ñÕp>û�<¯ð>×Pº¾ãbN¾ ½7½ Á¾�ø¼œ_C¾‹eÌ½à·Ø½¸ŠÔ¼¿”™¾úÂ>Î>>&_Û>”„;Î$Ç=É6=8.÷=rjQ¾½ºm¼ž©>ô­J¾ïAµ=¨ñ=›§=Ã6Ý<ø–+¾jVA>tµã=¾ªÒ½&ë¾oé�¾n„¡=M1h½þDV=èC¾v_…=оŠß¾êRö»*'Æ=$®Å¾±óû½V½¡„$»œ1>È‹½éŸˆ>¹ >Í'©<ŽöÝ> Cå= l–=úê}¾·á=Ç^>‚ 3½{›¶½”¸¾ñÄ´>ô”½—__>jíu>j�¾©uu>_™©¾"Fç½»Ñã½Ëæv>Üø_=~­u¾•4¦¾|âù½X¾šŽ€>;`ý=Œk>>Y¢õ=+B[¼–­O¾CAÒ=ÅàĽÅ³>G&%=•ñ›½!9p¾ d>ã’¾õ:–¾×Iõ=Çîß¼'‘#>â¯>•œ8¾´t3¾5²<ã;Ѿ;á7¾b e¾:ëu>ag>³+J¾¡})>Tá1¾è*>Y2ª½–滺‹¾8¾;1—½õšb>hg¾ç¦Ž>&O)>s¼‚>MÉA½ X?0½Œ™=p@à=ÐÍ{=ݨ½¸)l>š‚½}�A<Ÿ+¾±êï;Yô*>/H7¾•–l>k.�¾Èh(>íç¾AÅ*>õ]½·‘¾»—Æz¾×[�¾œuš>´ùÄ<�>h±m¾Ä÷è<¿ºƒ=PÌô=‚¤"¼�–K¾49>Ï�’»Êø¼P‡¨¾Þý=eÿÍ=�DV>x{á½1˜=¥£h>侘>Æõ¬>ì¥Ë>ÞM¯¾ ᓽ@H=©Õ;½&s>´*y¾6±ª½,I >3`¾ö†”¾ mm¾rX ¼M%½qµ-=àlö=™¬yóól>ñ†Ò=uŽV K>Úl(¾£ÅǾÉõl¾Ö ¿³¾‡¾©¨™>qùŸ>e3�>&�O¾•®Š¾Ú¬¡¼n ¾J�Ü>ðð3ÖÁ>u¾”²Ä>”²¥¾¿nP¾üѾ9k•½R`s¾õÙu¾?�>/^?,Hc¾/Äx¾Âò½7¿J>f5 >[<¾<0d¾[»$¾,Jy¾¶²>xi¼C!¾Ü´Œ¾çtÉ> <> ª:t&â=ÎX-¾u-|¾Ä¹$>*¾ßÓí> Gµ½ W|=¿kz;~3>LŒµ¾|¾Î……=Ľ ¬Ó»‘ÿ½X%-¾|uŽ>vn�>+½@½q”?>Ní�>Ž¥>ÜÕŠ>Q2Ô=~s§=u<Ö=ÍÏ>/¯¼xÄœ½�…¯=zñ<½aA¾Å¿�§=ŸÔc¾æÔÂ>¢‰.½1´¢=‰¼;¾[ÈL¼º›¾F¼QÀu=‘�Õ½Æ2¾f5 ¾¾d¾L”0>9êù=½gã`½Ç6À=à†>TÆi½“^>ÆX<íH>ÈÉÑ=8l?ƒ�P=*ïÀ¾m†7>U>œ¾œx`¾¯M >Ê´¼>ð¾¬çƒ¾$ ³½bñ>y|m¾9�†>oX7¾�Æ›>Ës‰>Nž‚=µØ=r �>¾ £½®“v:œ5c¾Ã× ¾\we>nˆ¾ŒÁ"¾äYç¾aÿʾ_3¾H(>¸“òù=ÈÆ8¾¨g»àÈ1½xÃò=Ròœ=Ŀ޾ÅH>˜,–½Þ½Q˜^>ïqÓ>1*¾õX‰>w­>=Í:ë½Ë�€¾Û��¾¨Š¾¤©�½þ¼¾Ûr¾Ï¾aMÖ¾r‘ý½Ô²½oŒU½n~P> g½u¤�¾÷yq¾[×T=•>A¾Ôý±½ùñ*¾mÞT>¿q±½–Z侟“š¾ÿ„=™ýò½2„½àä¾ ñ—= –è¾Epœ¾„î>L'`6Ü‚y=bRÀ=ò>=µPD¾ÛOp¾Ëc¾ؓ§½TO>‹B>J¬‹=w½Ø½ÕOÝ=™>«d¿<›�Ç=ž=ÐWѽÖɪ>û¦¾r^i¾i?/=RWþ½†Tö=žº½Ñx2>„÷̼«V•=~�â=šê?¾¯†Ý<ìa=a°e<åξeˆ‡=Ã7œ>ut³¾ÖùÇ=yf2¾Ü}8<ȇ,;gC>Vʸ½:^°= G½ 0>® ‹>†ºó>o:Æ= _¾>ã̽¤¿å=2µ¡½ë|¾žâ3>;ˆÄ<Y;ȵ.>^¦Ñ½ß�>z4>rZ—¾Nm„>ÁÉ=Ã"¿q, ¾¿-­¾rk¾¦½ˆ>�óÅ<ƒð>N’¼¢V¶¾úsE¾ò<6¾ðþ�¾°é½ƒ�ö=R‰>x’¼Ç[¾>'P¼ˆ+w»HQ(>=j‹¼kšs¾ó¤¿½.{‹>÷L�>ïd1>�P->Ÿi�>_½ë=@$ž<�ãð½¯Çõ¼vQ¼…Ñ>ˆyx>·ÀÜ=€Y½(ò~=LQ`¾0¸>=i4>ކ½¨(¾äÇÊ;f ¿¯«5¾™Ý¾š¨(¾V^4>ÑwÙ¼a>>­’¡>š;ÈòL¼4Ÿ�>‘ÎG¿4b›=º| ¾èôh¾•!¿ð[Üœ¾Y[™>ö@¼=Ëp1¾Ãµ¼QëÍ=Eþõ"¦>&°Ä=oŸ½.—ô½õ–÷=o-1¾>·Œ¼Æx™>º�¾ì=�ï>áQ ½_­Ä¼tN¾±êQ½6t•>.7z>ú½Èõ›=Ä1¢>dbþ>Ð3>.MP=ÝÛ ?C»=�Š.>&™=*ݾ{ÃV¾Û›¶½öa+¾C½ü=k—H¾Ã4->}q€½È‘>X}¸½DÚ¾9¾�f‚<ðòä¾óÙ>øë6¾4L̾@U„>Ä})¾!‘Ù½>éY½GÆ==Á;#> ù/=º ¾.Ú+>¶ ¾› é½íì•;þ#G=Cd/=ž“¬¾"9È="z(>/�’¾¢¹²¾á9Ú¼ó£×¾Ní®¾Š% >=à >[¯=½3{=š ]¾…úÕ>vqc¾«ãʾ÷S=�âÆ¼A¤½•æP>+ú?0¨ß»œpº½ržd¾v[¹¾Åµ¤¾§ ¡¾?È¢¼¥=v=SÔ½=.�M¾·¾5áþ=†ž>¸ ¿”Jž½÷¼Ô=*’νp•ê¾X2Ÿ>Ïuƒ¾›ü½Ï`¾ÅK�>8†½z�1¾®òÃ= &ü½ƒÙä½²É= =êÇ'¿2L½Èçy>‰8K<Áõ¾rü<½—‚†¾^x<Î%<îÅ>ŸÏ̼wŽQ<»X^½Z3™=Ñ�¾w£Ÿ½Y�>GT=ký‘>ÿí%¼äpÓ½u­¬>n`½_S˽j>[¾t>/½ý:U¾ä÷Ï=ë¦@=PV>æ*ì<ÜÕ¢>÷‰›9€d=<ôD¾Úü†=«œ;=¢›ë¼ ˆ¾'<½«×»;zŠ>ìmA;[ ø¼Þ͹½wán=݉’=Ì�½ÓÔY>ÆrŸÓí= 3;½Ð»t>f±½¹†”¾'ø¼m7)¾'d>¼t¦w¾$ʱ¾LÚ>Û ƒ¾eŸ_¼Ä;“¾˜ÅS¾…=j_�>8Ú±=oe‡>)9Õ<Ú¾[ûž½cÝ>".+¾»„½Y‚f>>Ìð»ÇÞy=TN¾0Û¾‡ÜŸ¾RQñ=wU9>“­=¾ >$YW>z¾œš!½·®ž»ì’¾OáU=£?€„>b(ù½%D/¾ði ¾ãt>zÐÒ½}¶»sÒÛ<$³ ½ï5X=ÆÅ ¼§?>Ì==f©,>ûž§=Å�=šŸˆ>®{´½¬JE>ü²>KYo¾,,…<)W[=¿Õ >HÎL½S^Y=6>Ž‚ƒ>'»¨¾Ü™1¾û¿Ù½ŠÑ ¾ÄÁ½°«; ƒ¾ÿÿ =õz?âÄY½£Ä\¾}4«=Ÿ?ô=ÂíD¾Uçú¼èˆØ¼vm½¸Ã‘¼Ds~½†&�¾@¸:>½Ô›>Ô´=Iõ¾­N>Õ/E=Xu—>V ÷=O;>ÒŽ‡¾ ,S>R¤¾÷Ë ¾ržB¾# ?âÒ}>òÎè½”3="`ó½ùÇ~=ˆˆ>R¢½ž¾4~>£y÷<ÒÀæ½ ÃÔ½=&Ú=Û+¾�T­>óè >Lm�½@…¾ƒÈ"¼‰оŒîK¾Þކ¾»~¾SÍb½PÞj;à=#꽆ÎD>°·0?j>\½*¾ „B¾|ùݼ0Š#½¿G½ûÈ>_%?½™è¾Úý?>¸’¦½{ß}>ψ¾û»Õ½‹Æ>Mé½=ëû=’ ¿y˜9>A§[=„ò?½ù\Ä=*õG>`[¾�±¾÷“ž>Ы=Ñò˜>É4x=`1¾ÜA¾Ôb¾3^ü=¼|¾n³¼Âù’>S×¾ZôL>8–l½e‰ ½œï5>Ptò½s8R¾5=ønj¾xW<¾W•¼}î¨=ñŪ>Ë ‚<ƒ8¾>N½$]=:'¾m-´øò½“8ª>ÐTÛ¼Ë ¾?ï¾VÈ'†?¡ ó»ùaÒ= €€>Íß6=ïÓ¾m|¬=Aiß<Ýò=ƒ‡q¾¿<;Ï^轈÷è=o%= �=7a>ìÚH¾'!¾ ®¾½Õ>ž¾CF½.?;O:V= {÷=†–½M¯=MÙÎ<ìï˜=!#³¼åf ?ÄÇž½TçM>¾” ¾T¿­½-1¾(rR½.—±¾mI¯=Ä”½z6>”Ùm<¥�ƒ¾½#{¾,£»¼}´<Ég\¾ü‚2½,°<>H§½lÚ>;nß=¦ç§½JÁ¾´•�¾‘ýÔ>5xê><è=Z¼j½×îÖ¾¹ô¿+M†¾õ2 =“/‚<©e½=8Zk½”F¤¾¢Ý?>¼ÌØ= �>"~“>Ǩé=¾L÷g»JR¾9ð*¾ó˜¾¯²¼,ˆJ>¸½BUò=!/6=ÆEç½�4¼tŸˆ¾°ñ›>*!¶>´<Ý8<¬‰Ã¾Än==ß0§¾ƒð÷=Øi¾3d¼Z«=+$¾Ÿú<>m§ä¢¡¾íÙX½8¿1'8¾ç’>>ó²î¾BõÛ½û ¾@ =&¼hM˜½³˜t»"9O¾£ñ)¾34½ë䨽–U<^"€=ÔTÀ<þ‡Ô=b÷ ¾uÞ>оƒÜp>A¬Ø>R°¢<˜£i>Ñfp=cí->Lì½½ýÌŒ¾�˾<êSÒ¾` >î/q=”>ª>k§=f/b>-aú½5>¾‰ü“»Ö“~¾2 ï=º ¿%ྠ|¿½ÜY+=šW)>²Ö¾X}ý¾ÊżAæà=I=ë½µ¶-¾5‘’>’"h=å@ï½¶�_>uŸ¦½ ¥½ª¬Œ¾‡mó¼FMf>ƒ v¾¡©½Ñ"ê>èE>å悔p½~‰> Š>#ò¾�ª¾Y’ÿ¾x¤x½uûa¾^ós¾tÉ©¾âÍ1»ÏŽ =ܦ¾‰Í¾š#ž=”mY¾©`p½’Ç"=·à¸¾¥9�=z¶g¾Ç´½Q[�½ìµ>Âi?0ÅB=Ëp =Kì´¼kQv¼HY½gûá=^V¯½7Ÿ=”ñ=«°ˆ¾ÔC¾�˜>Éù4¿lœŠÈнó­>Ñ>§¾w>{ú–¼qÝû<�Âí=wÆ$>íQ3¾‘»=ßu±¾bñ^¾”Ð,¾ãÑl=�Mí<Ž�¾øb:¾NÔ•<žÒ‚> ¶> ¾þ<œÆV½µ‡=V™%>õ&f>ÒØ+¾îr>kòI>ºB¾÷#¬¾ª ‚½–’½c¿TK¾r”k¾,Ž–½`pŒ>ë =æ>jŒ°=´kŽ>?—¾„.y>Z¬=Rk ¾ð 5ºS>'ji¾z€>¬Pê½EÑ)¾6E >qe¾–O>>Åt ¾¤ÔÞ¾éýª¾ÜJø½Ìèq>ž©Ø>u®»½ßÍ–=�+½¦ù‡>i†"½+ÔÁ='ÂN½‚»D¾Ä =š¾=¥ÐŠ=ݸ¾bK>û!¶=­±¾ÄH­=O:¿¾8˜?Ü}8޾‹Æ¼û¥­>mÏa>e”>½Õ>~2Œ= $h<_±Ú¼¥U>ÃÑt¾1ì½J&Q½þ ²¾è€y¼*/0<æ4Ø»û{>Õ=Y¼dŸ¿yrú½#W+>zE>Ÿèk¾�#>ø9)‘𾹨 ¿2Ê=7e‘½OJÎ<ú0Z½ˆá½–&=­ÝC½û[‰¾þØþ¼ná¿f5�¼?L¾pÀ¾ØkN¾<ÿu=ëîD>øêŽ=½S2¾&„¥>žmJ¾ÖŸ¾ Æ½på>JX½=Œ£d>©Œ»—’¹¾žŸ–¼Å2=a®×¾ä¢"¾±Ú¼ì—�¾�%¾é—À»8œ=>çje¾ >¾$Ëë½ }ˆ>¼\S>µ*l<¢²É½c$¾† ‘¾ ¾ì @¾-òE½N¾×¼è<>Åb‡=!Ò€¾ tv>ŽÔ¾²¿ˆ=ÐɽÍ8¾:ºe¾ËlM;œT¼=!Û½Ç+¤½�úl¾æ]Ž>£2¦<ˆ‘¾Öh˜½ˆ =î6e¾ÇI>[bÔ½£ {=Êœ;>^ûl1|>[µ1>C¬Ã= ø#>"Ù9¾Âǵ<çæŒ¾‚=¾Ú>`ìó¼ pï½d64¾%ŒD>D2ؽà#ÿ=ù¥2¾ž^ƒ>Ìár¼nP(¾x… ½ZÀ£=æQ¾ÏÆð½Üa2½Ö˜…> oY=Â’+> ¥½î¡=&Ýò=&nß=ù—›>i‚i½)÷8>§f>r&)>aa›;ŸÀ>Tb>Äë‰=ÙsT=!ÆS½áÝ*> ">P×:>òr>t~¡¾O=μ‘j>óÃ!>¬´ >0<‰à³€½cÏN>}¾þ[<—ÖX>λ#=n¢½½4Rr¾Ÿ!¾êc�¾ÒôP>ð ; i¥>à‚»¼ Á½ Ðð=S‰a¾u¬ï> v ¾(~>p×Y>¨¢à¾�1Z¾Þ•<Êü•½S/)¼\/Q>>]¼á뉾N§½0¿Á½h½ûfQ½À¢U>ªX�½”’½–¿”¾MÐ>0’¼âOB¾ðD×¼çø±>;4F¾^a:½Ù°¼Éz>ý,’¾üÔ"¾Y4?¾mp’<v[¾°r¿Ýœ>T¾-u0>ÉI¡=ÎÇû¼Y€¾!-ǾM¢±¾þðN£>ÒÜŽ»#&�¾>ã¼`Yê>ä¸>âpË=Ó6½Ü›š½¼‹»½yQ½½­îD¾³È=qá>óP"<–Wx>Pú8½ûr¾íeå=ÌEN½Ù�d¾1n>S{Õ¼iнm\<AÊÛ=Ö¤‹¾_ß�½R,µ¾\¾4»¹b=jew=ÎÉP¾òšÏ>1Õg½1•œ¾¸ùG?‰¯2?ì ´='V=m¾q…€=ž^Æ=ÑŸ ¿'ú>hµã½ ÚÃ<4§¨¾žc–¾©Ït>à7e¾ã™¾º. =†X<éÏÓ¾t± ¾}!E>Ѳ¾õÃÌIP;=´ç›½5±¾1—¶½°½‚½¿V·¾òy‘½°ÜG>1 Ã=d-U<Kt™^­=ŽnV>ãöè½=Y�¾�S”½9.½=ªÛ¥>ge¬>øŠ>¬þ†>?Ma>ôL= Ü3=;¯ö¼É2¾Fáf>À£½=�¸Š¼ê@½Xƒ½€¤ù=2¡O½ê ð½ixÞ;’Ë/?2>‰½Î¦(¾Í¥=› ¿ÇŽ\½@¨Å½N¿cÔŽ¾My.¾uéj¾òp–>'ÂÝ=Xù¾(„=ÕÒ>¼¡=>½¬' ¾j=ü²p>RAš¾?Ð?r€#=-“B¾ ^«½Ò3¤½†”¾Ä2†=Úõr¾›"«½}Q¾JŒ½…`®¾¹ƒýºáÆ\¾"Á4¾3ç$<¯íH>X8¿H–>7ë>¾•�>òT=æÅ�>åÌ?Ò%=©.æ;#‰=<ëì¾�m¾’€à=¾u\¾\Èj½stÅ<]Ï >�.†¾³÷Œ= w’½“޾nľ.á¤=ïæk¾Æ¦ù½ó ¾ –s=Za;�ò½®’½ñ >Æ,º¾È_¾íF=²Ì™½Vþ(>ëP�=/�o=½t'¾V?3¾Â­D>�ˆ¾¼¥²¾ÊÒ·=(¨Î¾0D‰¾3ݰ¾M¦>j¢R>Â"^».`Â=s…˜¾Žó>ýú=–ÃŒ¾éî°>–¹"=>Ih;1H%¾Ý€€>ò¡>'?…=ry”½ p¿@lö¾\¢À¾Nãj=ÇÔ,<“ni=ð·M¾9x˜½©¨é= —½2—½rʾL „>M¦¾ `¾,>>Ihª½Rw*>®Rʾ¿;#?e»�=W¹=¸à¼–¼’ßm¾lÍOºÀŠ3½ u®¾ÿ- ¾Oƒ>r£ >n‘6¾¨�ú½^ ~½àü8>¿�~¼8™ ?àÙ¢¼Ñ o¾íC ½¸j4>_ã½ëö„½Ü{ ¾WW³>|jè=,Ì¥¾‹X<à¢ã½”És>´2²:Ev>à …¾X]½‹8®½-‘3½ò–b>t/¾X¼w>bˆÎ¾…ý†Hß=Þq$>9=ø=Þ–±<"‹g¾˜³:¼ðä/>X?Û½?¦{¼Æ=ê‹ä=ù•>'¨¾ ˜±¾üßd¾VÜ*¾¾Ï½Ã™…¼pFŽ=-:>3Û®>|þ“>B}>ËB>ªóѾ[%>ú’å¾ëqÝ½Ö ˆ=ë{«¾�(=´rz¾kËǾì~>_èð¾6 `½÷u*>´å̾Ûó>é†>ÈR?¼Þ6S>NKµ<z¿ÑvÝ=qM^>ôŽ0¾Õá½ø“¹>t·½[£¼ÌÕ½ ¯ó½Eå´=x‘²=Èü=hZ^>ë­M=BÁ½È0�½òÄÞ½ ,=û½^Þa>uÁ>¹™ >�÷�¾H«=¾ÂW¾_à×=aF�¾ŒM¼ pW>nü=¤Rv¾v|¾®(>fЦ=â�w¼fva<­4 ½ÏÎ0>I‰¾oE8½>D5¶¾g.P>ã1 =àÕ>Gñ=¨Í>>%/Ü:�–{>Õ@@;ñà½"€Z½&~F=×­o¾v ¾½’�ï=Êý¼—„>Q?Ÿ= 1¾…¥.=‘Vô== [¾{•µ>Æó›½Šä=ˆGË>’›®¾¥UȾ‹’>ðßñ>åd>ç)¾«Âg¾¢Õ*>&J>a$>£ô ?j‘F¾àáª>ïì ¾ôÂõ½n˾}‡[>ùŸ–>šsp¼Ç¿>ò]‰¾©¾’)=ãO>ûd‘¾‚<±>ºCÚ›d>1Ÿ�=ˉ‚¾I¾{hÿ<»>Ö½®ÿj¾jå¾³ Ö¾¯´á½ ä<ïm>%V ¾ü I>éð>ã¥�½I„>>=»°=¾%¡y>MIz¾nðõ=ŸØ½=‰ùx¾cä•>>ð²¾îˆ6>NÁÁ¾ÜF¾"О=�Áñ>þØw=?ô;¾6!¾4º<Ö„·¼ávc>°¸”>iÌ÷½éD¾êë>ÝŠò=ÝŠ> oÀ½1§¾·g޽çâ¾ödá=OD¾ËD =ƒI?ö¸¾äHª=¹Íé½"ëT¾²,œ½P„=F �½»©·¾g• ¾×±t=§l½æ}z=õ3>Nh«=˜@,¾à©/>i>Ÿ½ ®í=qq`:�Ð�¾‹¢…;\¾!á ¾ÛýK¾·Iú½EÑ%=H 4>§Ó ¾‰¤<>T¬+¾DÕç¾åÑ=èÄ]>åO¡½= È>t9ͼ¾Êp¾]õã=>î{¾€Cð¾Ð=Õ=Ô‡£=Ap?σ⽿@>ªüñ½Cˆ©=qi>¥ñC¾NœÜ>Xr¾ß¯º½äx¾/ Ò¾Æ,½¼wlò½£¤æ=ÖÒ›½¹c>¾#7=½«Ï>�§$¾�ò2¾¤)?‚w§=ŠÅ`½4âç¾j„.>Mj¾s�ç>„Íì¾2í½/£½‚ƒ?>‰*­¸êž<¾³º¾#¹ý»-›D>ú‹Û=êZ¸½ÎÄj<‡½h=ÈE >TBö¾˜û3¾õÃÝ>¥¿‘>S"-=¿xнH|î¾½×ܾïvõ¾#l=C{>lõ`=’qè;…­C¾2½‚= ŠN¾×û=BLL½$´`>¡4>0">¢ÐT¾{þ¥¾†u¥¾äáæ¾2 ->€ÿѾpf=r!™=ï-f=?Ì�½½’¾¥óË>ùÏ>C ¼ R‡>¸¾–ƒ> ó¹¾[Õ½InÓ<ú{•>æ’†½ðÔ>SìUªG�¼¾1+¾#µ=[¸'=½Ïb=Tàå¾�H¾êоúw`>‰È=‚#1>æ5>J)ß» Ü!¾Ÿ¼'½Î(¬>Ë{>Y‘�>ß4>4½Œ}—=è[¾&y–>ë–ó½Ü¢Ø»¥±%¾99g=—ï:>.ྠ[>G Û=9è >ôˆ/>õ.¾ôç¥>äë¾A:5>ú–¾9<Ø=˜š >ÖT‡>œaC½oh¾îá=óa ¾/½A=TÁ*>É.,=“›½û©¾ÉG½¾YϾ•�=¯±¦·=�=IH·¾¬YA¼ i¾÷êU¾ÕC0>¸êr>Bm|>�,=Ã>N|¾qn^½ØK0>kd9¾Á/¿°–Þ¾k�>D4»'ui>•oD½Ñ‰©½¬nH>’懾³~>$$J¾ õÿ:kvоù€¾Y X½Р½Dêz¾nSƒ½+è=ƒÿ>"Bî¼Ó ã>@ô0=XeŒ¾ÿ{Þ¾‰¿¾î ¾OnK½lt”½…3€>È>>�—=€…„=X*~>³Š<‚ ”=ýÒ?>ºø>|O.>gª< pn>F œ¾H}[½Ãª¶½£!=ÐlÆ<�Ï‚>gÁâ;ß4�¼e<ç=1ì]¼’P½|GT¾´ÐR>CJ¾ûl¨=ž¬¾Vð›>ˆ>¯¾Õ½‚Q=¾Ú•¾©ëV>ÛÎÒ>K>9…p½N8ƒ=Éùœ>8Ùñ;¬5¾4)¾I�¼T½ ¾•<�¾Ç޾Ñ-0>ªH¾ì“>iõ¾½ç„q>ƒ¡c¾ï-¾-®½¬¿>D§=³>Qµ+>u,5>Q�ƒ>F«,¼þè=yµi½b >'<@¾@˜?=—':¾>÷µ½*ÃG½¹0–>&Ý=ôJ>ª¡Ê=á•>¹F€½×_¾Ð›·=“{ =Ö}>�É+¾U½½³¾+½ÎÆ©>þP®>‹×>ÆZ¬¾ð>>ª?I=šæø¾Óé½à>¾åS=ŠÞ:>óª¬>€ý<¾Zjɽ?Ô=[Ej=¸W>Ò¶á¾p›5>…%ž>¿ðµ¼ãÌ™=}«=…bi>Îyõ½%t>Xä¡>Ѽo>LŠ?Wø<+×˽‡ ˜=€N¿ªÈt½Ù¹>¡V]¾M”®>fb¾híy>ô–õ¼™ê»+C×=D|š½Lk¾ô~ä½VÌ€>ýÀŠ»Þà ½è9þ½ZaÆ<¥P4>ú:º>ÿ€Í=û¢µ½,{>,n–¾Î“ž½² ‘¾jIÌ½Ž‡¾,»«=§ž>;Š>‹Âd½àJ>öì?>ñq%>ZÂÕ½ œF>³ð´=WšÀ½õ;(ek> G ¿UNà>Ì(?gy”¼µ>ë/ä½XÚæ½É«¿>=€à=@ |>ù>ù=@ ¾ ݈=9¾Ý= mT¾Ìú/=5G?¤LɼY¦Ä¾¦ìB>uN̽0�=§›N>àh/¼P×¾²0…>"¯$>ý®%>v¾Ómµ¾ºÿ&¾t¾ñÄ[¾+«¾îaø< r*>º’œ¼ÖÇ1¾”KÄ>yN¬¾†&ç=îg‘=´d1>-â½Ô<)ؾ1Ñp<¸16>!×>„>.1A=[2ä½™cf¾V˜Í>É¿¤¼ÉÆ6>o‡=Ê¡ä¼ýÀ2>PÞ…>f©‘¾5�ýe½U>´¸4Ë{¾F5k=Þ{S>K>UéÔ¾*Œ_>6ü~>yÂ>z”è¾ä(> ®U¾·7¸=ò¼¶¾ä›É¾�GŽ>´°=#¾|%ì>lW>çÉx=Fo‡¾ÜN¾Xç"=&SÝ>_Ÿ¹¾À?¾^tg½Rt ¾ì?ÏXO=«B¾ö©Ç<0a¾ÛÈn=!äµ½^õ>¸£�¾Þ‹¾ÉÚ<Û?ݽ%¹î=îÒ~½2Òô¼æ^4>?’¾a—ý=üy¾�F¾Íѽtz$¾au=ÁM¼˜õb¾$6ó½ Á©=�õ¼ð[ë=•É´½ ìO>7DÀ½]æ=×*h>}‹L¾ÀÃɽÇZ�ºœÞi¾Lh„¾âj¾î묻O =>n@¼ š—½_X½¾Âo=Ej„¾Ÿ»2¾Iq¥½PѤ= 2—½búþ=Ð¥–¾ŽÞ±½ê>¬>ýëê>èɺ=ÿ3À¼U%�¾7oð½ Р¾C¯¾üËT¼æYá½È£q¾ŽþI¿M.±>®оF‰%>ò·…»VŸ>>ý»o½qÀľ/-νïG0½nÔ>Ìþ�>É-a=;Ú-¿£i¾½ñˆ>ãè=zfÙ=Ì I>U0ƒ¾„Oy¾¿A�¾UWþ¾FC½Cd=BWû½Ã!3=L ï½?b >ôç£>Æ`=2Q¾ÌÌÃ>nï<¾dë‚=R­>ÓÖ§¾E-×>¥+¾®Ï=‡þG½— ‰>q‡1»˾«ÈÚ½Ô”M¾Ô–T¾‘•¤¾&ùë=Õ±> hš½M§ >„{1¾t­¼=ëÎþ>)Ž=ùwœ> Î>ø¥>«mÖ¾„PW>&—:=}ê¾$æ9¾í?ô¼S=Ó‰>G7–»°0>G¼j¾¹-޾èw•=¾�=Ú¾uo•½e³½\À§¼”>o¾rŽ™>¢ŸÂ=îÐÀ>ðÓ=sQ>ÓKÚ½—³½<¿˜>δ<÷z¾Ú¶î½L2=Y¦¾"Ï"6ÔÎ=<ß=gø^½–W¾J˜ã=·:=É�U½Ùn·½Î¾;¾ÊÙ–½Óit>—ý=»ÃH¾Ý?>Î><0о¶ù>$É꽯対Ÿn÷>ø>û¶º½WGI¾“^ü=35¦<£<7<ͬ¼·R�¾V½NMy>‘á¼²˜‰>ÈÃ=¾ªž½‡Ã`¾¬öƒ½&×9>™ÆÎ<±£="}ܽ}m¾&ï­¾ÿSS¼’6ø=Rù½ÔºU>åh>gô>ªh§½�#«½8\¿X�d=ñ‹>þNG>œsì½Ó뤽jâ—¼[šè=%£h½ëˆÁ½W*«¾nf>U>†¸/¾Dúo>6¥þ;¿>1ª'

–aâ½^tÆw¼=H๽ R¾ê>õH“½R¤�¾ö Þ=6¬>œI@> ƒæ»*¶¾+Å´½Â¶¼+¤º´ày>Uð½>˪½Eï´>Ïw>sľд%>Œ5>^ra¾Å§ì½s½L< º»Dóq>–Ÿ¼¾öw7¾oi¶¾­p�>?„z>ôFɽ“zc=Ü�†>4õ�>¬R–¾Í¾Ž¥z½?Œ�>¡$§¾ó¡j½—™C¾”î7¼B„´;ð?j ò>[Òx¾“º ¾a{š>u¾ß½�çƒ>x=ä½ì>A¨š¼øZß=��=a�=:=>=jÎ;Aƒ‘<ak=wD>Ò¼=>3¾³ X¾ µ½íb¾!¿�½Ž-ò½}ê¾Ò™U>óA=?i9>úà…¾oO4>ùHð>¿Åо¢ê¸¾"¥\="ð<7ÕØ= 1†3©í¾ºÓ¤>¬G)¾åŠ¿>õ>¬=‘ŽÃ½�K•>솽éc½¾°5>Æ�>†½#>«»„<Ì„ž>¡âü½¼^J¼R}%<‹e?-¾:¤¾E´Ë¾3¹>}µf¾_¼ ¾ w?ÜTO½Ìk‹=¿¶´¾Ù‡Î= KN¾�b=RÛÕ½rLµ>6é#¾…¼>Ò\Î>†X=•—È»gOÃ>†9h>Ùaº=äA>Gi>‡ ¿½*ä†=Q®|¾Ÿµ>eß­¾v¾›=´�ù> ?`Ø¿æ°=wµü=¼ÖI¾lã¾£ù¼¾Ð}=£Ç¬rÑü>n<×;{?È>ÆÈ¾$"¨>¾zœ¾À¾o¾ ˆ >¦ÊOg>ÂÁ:=¬‰%>¦j<¯ßt>š2|¾ÈÚU½Ë-a>Äs>¿Ãü²ã'¾�å~>’@<]§*¾PNÒ>þÉP¾M¨¼÷ �>ä¥P>¢Õƒ=l­¥¼Bž¾`gœ¾nnZ>õŠó; z½ë–¢½„5a ¾Ð/r¾y#°=N«Ì¾f;¥†=B¦=½‹f{=»´v¾‰èÝ>(©l<"þø=°‡^=/]¨½é=Ü=`“=Òƒ?Ì�8¾ƒ¿S¾<º=Ôkþ=Y¾œ¾ßš ¾Åµ½�¼Ï½rÑ9¾ãƒ>»ê ?U$=Óþ>)ð’¾{Vª¾ >º'=ò;Œ>i_ß=—;=4“ñ>n¤™½; ¾½Þö¾S ½à'>Æ8H=âA‘¾¢O�=éX�¾©]¾>;Y¾…ø"=»õL¾Kµ@>>ûU¾ Ö=Úü€¾®d-¿U!ø¾ûæ0>€½=õŽ;>A^D>Q^“=+þ=Ö˜ë¾QtD¾©rÅ>¶ q>v\’>ÉZ;›©D=,]×>Mªé=!UE=ø+¾¦ýi½¶¹Ý¾+ê=¼îÈ=BíR¾‚²?=°¾«�¾!�¾9ï=+ý4¾:4½åK«=Øn�¾Aj©>!¾„Žé=çžõ>ßf?/h¢¼e”Ö¾TÈ=f`þ#ô€¾N‘>1Pà=, �>Û˜½Ëˆ½’À|=V‘ˆ>褾k”½í…½Fñ¾‚†¯=l½p½ÇѼ` >¦5“¾³f¾9|;{ê´¾ïï×½ZIl>¹É>C5G¾=P¾Aú*>Þ•¾Oîï=–ì ¾æ¥Ý<¨W,?.¾@³=>È¥K>†,[¾Q#¾î2.>ØC‡>0ŒÈ¾ÃÞ[>Øk½w�½½+�J=€ØŸ=–‡�>ßÛ˜>»X=õ°¾³ƒÁ=K×±¾6– ½�Úù>­Ž¾°ß¶¾z7‚=SNº=¯Œ¡>+þ5¼Ä©?Í\¾úo¿ºXÞ½äïv¾â±±½Í,´¼3º©>Jþ·<Ê›€>; ¾Šqî½=;m¾Ä† =Ó>pŸ—>%c¾ñg>€ú9>'¡½›�½¶ˆ ¾—$×>°yŒ½‘“Ú='¶¾Ÿ®'¾Væè¼ÚjÊ=ðý½=h g¼œÚW½ªi†< ÷¾¡ ÷;x˾?ù½¹8¾\޽ê½¾˜ò)¾[yÈ>°8á»ÑË¿á;Ǽ��\¾ßÒÝ=Ir²½ø¼%=�F�=wlR=ï?½�'Œ½¸òq¾×Ž+¾—Ä=#몾Ǹ\¾=)>oÓ+¾¤ˆ=uê>®‚ͽ/™9>Fð­>‰äŒ<„Y¾ó+p½GÆó»·�>®Ž¾se€º¾‘V»Ü*Ý<»�¿>ÔÈß½ÜZ=�¬`¾ß„C=<ó‘= �=¾Öa›½Ä €<½Cñ½\È·=û-¾‡iò½?AD>Éy¿½«¨>>¨<­¾^ë|»üC8> §¼Ë¨A=ÍâA>Al‘¾07‘=Ww ¾þ³¾k ¾„Ö¾>e�‹>hÆÊ½‘ø~<“"s=˜ä!?Ó¯w¾±l&¾šào>gP¾vé>w.½ºˆ>­=²¾q[¼ß�à>÷÷̽®ŽÓ¾¥¹=踆>†?ø<5õ·»«‡Œ»ß¸w>¶CÙ¾¢;%¾™uD¾ÒÄM¾ ?¸½1@ؽcRØ>à=k¡Û>7üæ>f,½Æ¢›¼ „ë=sQ1¾Hÿ¾c*¾ðâ°=t %>É6M½dñ!>[í»å´ð¾}@K>†Ñì¼yÚ>æJ¾ZÇ!¼"•é½í´½«í[=�ä@¾ø`(=?�±½k?h¾,( >nÔ<Ú#¤=íò?Èr3>JÖª>Ð#!>IèK¾çt†½i“½‘jã<§.€¾$¥¦>—Ȫ¼Pƒ>Û™­½Cä­=©r1>Q¬«¾×Ö<µ‹½Ü½F¾”?=[>¤ªŒ>t®—¾s's¾z,>ä =+›>.¢œ>+_>W>.C½ Õ½=â�¾™±²=<Ók>š¥=¸J>Åa¿�œ¤>¦È=„Ž=kþ’¾�h§½JëS;ó³$>éÆÌ=|Íæ< />ø > &о}E7¾Usì>åg>5”÷¼èÈ>›9ƒ¾ôË->q‰¾„7ÿ¾¼À>µª>–Íž>7ø5¾Âßg¾q»‡>�”œ>þT5>{m¹=<Ì©=}k >­ ޽�ÿ@¼©f>$±>ÂÌ‚¾6O½²Žü¼q�9¾y#S>Aý¡¾$ƒÈ½ªˆ@¾´µ"¾öo¾i/~¼4u޽¦w9>³Ã_º%D">·)Q=\_(=¶Ð>ä~½;å>C\V½¸Z&>eÞ¤>ÏH3|=õ¿ƒ½aˆ)<$¯=ÆK§>@â”=yb#>Ãtí½ŽN>rµÃ= Ã=S#н :>ßHä½ûà™>`.s¾µ¼�>ÜLˆ=P‡f¾�”½·e1½lÿ=7û¾½°<3»ª?ó¢"=ÅÀ¾Ÿ½A­>>1Û;¦E+>Ûù–=‡<H«=n$>Uß½—X¾$¾Ä?¾UŒ¾DÆ>,EÆ==¼#VGźz%&>œF¡¾N0>táí=²;>Ù)>&v£>ÝNŠ>Ë1´;¼tž>¿ï²½m{M¾DL!>h7½Þ¿‚½pF–½AwÂ>û(¼½xþ9=aa>>*–ê½åˆŸ½t™>†‹€¾FÊ6>:°F¾Ý_R¾ú1Ç=Ø‘A¾õL¾¨Ñ-½á2༟ñú½ÝeÞ=Ñõ>çð >|‹¾©�;¾­œò=BD½pd»7µ=Σ†=Gnƽ™U'¾ç”¬<‰tͽ½ÅG¾(´¾©K½Í¶þ½ÈöL;'ɽÄ,¦½Q˜@¾Ð�>82�=‰ß¾„J¼Éç%¾ÔŽ}>˜Ûâ¼ßsT¾BA¤=;Vg>‡B<Ùë<}Üï¾Â0«=U‹Þ>*@�>X�½Ü3-¾Ó)9=˜÷Â=§ý½�Q}¹MV…½ÿ21>@#оM4ª¾€¾M)i>µ­Ú¾a‰Ÿ¶m9W=2ÙÏ=œH>e=Žüö¼'K¾Ìòž¾�V�½²Í½>³t>^fE>ÌIµ>§q>çð’¾Üíµ=/¯J¾®� ¾j5¾›±#>ž=u­1=ŠüD?µá½�! ?P$é=¾ËZ>8•<žÃ3> Ñ»=“–ê=¥ÔÌ»’Ð ¾ìæ¹¾•¼ÁVK¾å ½¨³»y ß½&™r½�.®=7/3ßÜ< oƒ>2Fý»±':= =ˆ>$^ä¾›�9¾ŠÒî=o™š>½DŸ½rsR>õ?a¾‰‰ß<Ë�>Ò j½x™¾´œ–>ŽŠ¬¾og×=kO¾â’Ö½²<]>û’¾–lß½üƒ&¼¢ÝF¾Jôz¼vq:½ç�¡>o:?¾^jS>[A¾ºôŸ>Ú y>"r¨>Õ¾x?¾ñ ä=ñ2L¾TŸ¾]¾„²¿^1>Žªþ½µ^¼ºÝ¨>½/—¾ÚÃJ<ч›¼?¦½*m°=Â#~¾S$ö;b—Î=jþ™>2h>˜­>®Cˆ<-pW>“0$>Ùuø½�TÙ=tî'>aDß¾:ƒå>˜ê¾9òB¾ÁV�¾ôr8>¯m>¦îÆ=$��=ñ�%>S×¾h­Ž>M�¾g�2>Ä«¬¼qFW>¯1&½¡GS<=ã=b¿¾ 䜺ÆŠ<ì‘>Z ‰=ñd=6Xæ½sjm>Np¿½Õ á=Ö£ »–¶’>Èn†¾¸…q=¦>˜…]>ÝX-¾êk޾šiP=L”{>fMn½}üœ< s >öRÎ<Õô£<ºÐâ¾}K’=ù ×>L¨¾ ]V¾ 'ç=‰Îd¾¸1'>ˆ�=T’>Åñ=xð¾àªa¾ØœÉ½ë™>'=‚¾ ¼’>d„¾´ª>»,ò=áØe¾JŠ7¾^éô=rÛ÷½^ý¢¾C° >Ô0>žë¶¾»1>´Ëо˜<‹=GyH»5‡¼æl¾U>¿¯æ=‰V}>ò¿ä=þ’“¾ƒˆ•¼F®a¾5pD¾¼”ý=„² >œ�³>ý<�>‰’ß=™¼³œD¾,;¿ÍS\¾x˜ª>AZœ¾É§¾éä�=H'>¿ø[>¾µš<o”¾øÜ¼½0üO¾40½â C¾.±¹>ëƒ*>Ò®P½�L >A83¼M">�Af>U•O¾•ýÍ<̇¾|Œhºø¹ã>q<á¼x>�nª½n½œ*6¾¾/q>E—X½ÄÞ?QÙQ=I�>ð£¾â÷p½MŽ—¾X,¾YľâKê=Ⱦ…ëܾý±ˆ½CY=ã b=Åa.>û–Z¼ìü¸=y^Ã>hjû=0W÷½<š>qÔ­¾¥‰f¾¸µ¨>w×¾’àæ½‰m=÷¹=¦Å¾/[?€ìv¾žy™=︩<¤‘‡¾ïk¿¼a¾ÇL½!‚¾F•뽉>ª¾:Wþ¼�‰ ¾ânϾÉÞ½ïT >nN0½îFɽ+òe½éR‹¾øg6=‰ZF½Ü”•=¥B>ÅJà=øS>VUg¾cð¾šd+=Ô$>¾¶“%=‘¾g¼sß >‘®¦==Pö=¡ˆC¾ ¶®>2ö¾§ì$¼]å¦>V³e¾p0`¼åÇ>W1?Âä®>¾V±¦>À“²¾±é¼Ð3ø½95¾)í3<¸ï >[m]¾ÍdÞ¾FªØ=5ó>DŽY½ ¶»ËŽ>o‘…;ÇŠœ=6?ì=”hº['ý=Ú¯s¼°XÀ>,¯Œ=ýŽ>­0¾ÊB =4�K>— ó>ã}w<&ƒ¾ 17¾W·5¾ ø¢=³œE½\“ñ½J¿Ê½ÍxH>ñb#=p¨îu·%>™Æè½8Û½³&ƾ:dí>´>ÖÉf¾H•>’f¼½Uš´=«ÉÙ>Ô8!¾Ó¾>ù�=ŸÝ'>ká¾mæh¾Ë]G>'«=E•€¾8Ž}½‰=¾ô²ö½Ë›Š¾pøé½5ƒ>xf<¾‘‰¾ ÷>�m³=>¹™¾�Ì>yc²>x4>X$¾øñ:½ÔÀß½×¢ <éh{½ñŸ ŒAõ=wI>R>«¯7> –¾.Ê ¾¿¥<Æi¾ á ='Ð>JŽ‹>˜~½&‚#½çü+¾wÛ¾XÖ—<]Ù¤¼›áQ<¯«'>¬p<2wt>UAA¾¶é¨=s 2>uf¾®{#>—`”¾&{¾€Ö>Ëc}>u~õ=l”½6g,¾æs—>·>=œæÈ¾J×Í=ÂJ?¼í;<Ô^¶¼(ì½=·”=Î)­½Z3g>Ýß›=òÝ+><Ë_=!R>óÞ>!=àÂÒ=ZÁ0=.¥U=;x»<± Õ=¸}‘½~¾5>dþ�b¦¾ªA< ¤ì<�•'¾%²Ž¾Ê�š>\q=èÞ¿>£!«=’ZB¾^t2>k*>ӂɽAÄ1½`»Í=ð±9>†‡¬=Ù ç½4*¥>-=Õ>ðk¾y5Ç>9畾¤8>c˜D>]#>õc…=}›á¼üä¦>Ö¯¾>É]w¾A?’>\Ä$>úm=‹,/>³<]ó<ÈuÔ=Лô=:á>êë’¾‡�>ï\>3žò¼nÌI¾ö_>§T>ˆy¿‚‰ ¾%‚¾CC¾ÛB¹=-D>-kA½féV=ÇÑO¾H…L¾H ¾?tO=Å2I½­˜}=ê�¥>!MŒ>^3�¾sï‘>�„¾ iº½ Ì;q;>ª[�¼m¸ ¾¶¿�=N¼¾芾îû=Õ›¸½±œ­¾þj=Ø™;) p½¹XѾÔN•= )9àzt¼¨Ì™=ÿ“¾Ò¾‘RÛ=Í®U½ÒÒ¾¼'|¨½qY ¿ãr>…N>ŒPŒ=º—¼·œ=™±Ó½’!K¾U <üÞ¾@u>‡Øó½ÊÍ�=%Õ¹¾ì?…¾Å’ø=¾Wð">=)7½ðσ¾ôÕ=3îÞ½z|¬=W~�>\ #¾¾½H=�½è½¤œš¾ÄG@¼ž°é=i<=Íi<‰Ow¼U“%=³=ÜS>°X¿rïP>öŒð=–ðÍ>æ'*¾Ý¾>òD0½ø¨Ù=0p¼=wÔp=4c>ýB\¾n%€¾-+õ:Î:½· ™¾SŸ=x(>Ôë4>6à/>„U>÷ä¸;û½�>l¦"> :н;&d=Œq½}ê½ÒÔžv‰¬=—Cž½©·®>d‡½w¼v¾ô÷-ƒ#«<åº>íöã>\å¾ÚsO¾„3>�¯<›v½].¾E}Ã=l Ó¾¸5¾”gè½·¼¸=/®°½‘ŠG>·)«>µáB¾~^o¾~pt¾øä¸¼Eì>9KP>³û¾O댽*o€=mØé=2g½×aÈ=6ľEÞ6>–¶¸>V#½u-¾°`¾0 ¾—»V¾ÊÀ¾ÝkF¾”f†<éö ½—=Èq>Ó²†¾‹>$ŸŸ<%�>¦ƒ‘¾(ä;¾QA>t”½ì ­½Ù08½´ƒ¾Ö&€½ŒäM¾bÖŠ:°ŽÄ¾Ÿ±Î½91‹¾3ÝÖ½™�1½ƒv1>°t7¾3[½¾!|`½«Ñ5¾ÈÇ>“üõ¼_3Ù=áZ•>ªaj¾@Á>¡�¼ôò=N£r=Îó`»ÊŸ6>šR=+⥾ŠÁ=Ó{>‚Å#>Í·¾œ4©½Œ"U>,Å.¾Îq½B]A½^i`>tù³¾‚« ¾Lë%¾uTʽC¼Y=|+=g ¾£ÿܽaq ¾ô�?1¢>™”ô½‡o)¾³÷w>%{=E]>$ù4¾¾z\¼± �¾-ù=¾÷\=“¢Ñ>ªtg¾Éÿ+>=l�>Þ›n¾y`¬>ƒ—y>>À¸>ü÷'>÷ß ¼')e¾^«T>ke9>Á–Ľ+<9¾nø ¾�±» »*ív>­VA>è!‘=Ð|ˆ> T€¼?,>J9í=FÒ2¾|� ¾‹×r>«ÞÀ½Ê˜=ë“�=߈—>Œ\;>4¡´¾cT¾“Ž>޽‰Ä¾Gá½Ø-+½S“I¾ú'=²t »Ú$9½B放ÆÈ\¾Çó(¾pÛ¼>‹þ�¾g¬¼—Ï»½T|Ù¾„}ˆ>Ø%K¾1t>t> çè=Þy>l V>jÕD½��>�ÕÞ½w¶9=Ö€Ó¾}U®=̾s]>˜4ß¾ôÿ>ɆÎ>|Y˾LÇ>š í½¼šó½ü ñ=Å”—½²ž¼¡¸ñ¼"ʾ¨TŒ>ƒ‚ê<6e½Ò÷Ö=àq“=*ñ€¾Ë«»uû¡¾™†Ž¾U¥¾‚‡½/=;S¢�>‡di¾üT¾çìf>â­�¾B½{•<8¡|>«¨=¡Ä!>Ò–5¾½d3=V]^>>ˆº¾x¶Œ»€ZË>=>T„\><Ÿª>–¶A=u‘<™Ü ¾$vé¾²†ƒ>l­þ½½vµ=‹«L¾Æ¾œ�Æ>�ˆ >ü  ¾ZG>ç¾.”>h$Ñ=( N=þf¿½Ü=_Ɖ= 9r¾c )>Æß`¾ãUJ>$*u=K°Ý¾å¯¹¾ÉªÖ=¥A0¾±Æ>Gö6=› G=|è¾l¶Š>aî>¦g=¸èç=°€�¼ó—Û>j˜°½ðù=à†>=¬’=&9‡¼Ó—ÿ½“¹š>#�¾.“>Q€!¾Øì>>Ôó<†7̽Ü×=êêd>uy’>Ú¬æ=¦óc¼k9.>ýŠ>}=À¹ ½Žâ¨½Áä=o¥Â½Á'=G©Y<ÁU½£´ˆ>Á_=䳿îw½¾� –> —¸=S[µ¾®B@>ÿŒF=ïÞ�>X�T½Óø»=/œ¼Ð>ÃzݽXä¼Û\=TòÒ=w|¾â¤>34µ¾×NÓ<›<2¾II0¿)…»Axe>‡‚8>Ç�H>ºŸ>|2>®=+UŠ=R¦«½ç!�>‰’9½<Žb=Q›0=?!•¾¯Yu>“´¾à5Œ½•Ý�>4kÔ=ä7ú:"j~½jâç½ðZª¼Waå=Ôí’½uò½Z�*=ð<û=äfN¾/€ ¾jPA¾1˜¾‚Ú?>xŸ¾†Ÿ¾TC=©½N�¾Ê<°¾:�ï>Ú`=>‡=V›À½8ÕY=Ò„‚=RÈ|=’mÅ=¸®ç½º|‹¼UK>ØN¾w¡i= À>—†¾ê…|½uR€¾î3e>ÂÙ>’Ò>Úˆ ¼"â�<F;>ÉŸ¥¾4"»6Ô;>¬×b>ö•�>JV)=ai1¾ÔÝr>�õK=eÀ£;ßa3¾M�‚>9 “={:=¼™S>‘¸>©œª¼è€”=¢U§¾DÖ<=Ú!»½®˜K<àö�¾H)§<Ü”<|Ât>&£s¾ågh¾†s½‘"=ˆ>Z’=ôô>‘?€õ?Ñû›>Â…‘½Ö–#>f¡ž¼:¥¾þ;=Í©>½k&i¾èl'½Í³Ã=Æ@>ù,´> ÿ¸½�EÙ>uff¾½W®½gK=Þ¦>‡Õ¼H’W<r7¾§B>“ =ô¾{ÿâ¾4†¾^I9º´’¾–_Ž>+­¾`Á:>ün>ò6,¾|ŠÕ=½Ý@>i!B>|½¦Ò¼h� >õ (>™P>S‚&=æ[•>UîQ>Ù= �¹=+Þ½3Kd>�µp½áú¿®A¾€é9>•fT>íê¾=¢™­½_è}dY½&ÝŠ>¹ø ½B´Q¾p�q>(ƒü=ˆA½á¼±½ ®>Ûk¼öؽ¢u‹>‚‘k¾9á²>* ->¼ν½ÍÝ>ªˆ"¾'FŒ½sv >“•¾s» =å;&¾¦0á¾D×C>Ùù=á>UYɼ³® ¾z6½¾0ÿü>ï뽓¸=]å_>‡Ø�½5öÆ>'« ¾¯x¥½v*ž¸š>øƒ�=Í ¦=íp3>;7—>¯T>ÈíÊ>ð<Ö½Œ>*$¾½}¶ô=I®x¾ZÀË=aýý°�½¾‹ü�>s œ<ÔkÑ>*¾™‹Õ=©ï:¾ /Ö>3Æ~¾ÿ¿I¾hçÙNa>�Ïç½9¶=üq/>±î„½z…¢>ß=³<85=û½¦Ló»¿•=¾†ù\¾V'�½U�¾ÅôW½Õj>ñ˜={o}>"Ê�>‚Œ¾Ã ѽƒõ¿¾–Z¾JÑL¾$×’;ÞŽ[>åç¤;LÓg¾µ7ä¾$Ñ>æ+>²2º¼-;¾-œ©=}óϾÂF)¾†—ƒ=û+¿¾!½¾üv=÷ù=n“;=2$¸=‹=¥·©>†6>6}º¾1�¾C�¾ÙϾŽA7¾*~>‚%6>=3½5ÿÓ=HÈ„½À¹½½Å¾Ú õ½Q… >„Ð’½5cÕ¾ÍF>ËK~¾½Ô½%3:>d_¥»I">+оOB¾43¾Yù†<ù؈¾]3>ˆ h>\@Ƚo*>ä-J=(’N>i›=XsܽË=‡êy½_>¼}*¾=£¶=j˜/½®È2>\ä=ïd¾§àI¾$áÕ=Êyè<ƒv{¾†¶<¾$܃<šî�>6½B¾ø:¾tÞ4>:–ù=�̉>@Z>ÅÍŽ½Ïéè>D*]=¯²í=µn=k/ˆ¾¿5E¾ñ°¢½YZ×=9¥¼k¶”=Ò�>™´A¾2\?ýë½vI#>.A¾¡:¾¾òå�¾˜j–=á >Œ=¶¾›Ž=Oq=‘+›¾Qah¾FŽB>Åé½èP>Ÿf¾ó§a¾»ó$½¯¹>Ú¤>©~ë½¹öÕ½¹˜h>>3“=Lž½£+(>HÝÅ¾é ‰=ÿ¿Ð½P‚¾©ž¾:÷<êrr>éâ=IÏD>MŽ7½SœÞ> V€¾,×½!¢0>ë{€=³±Û¼8ð>±Œ¼Hžì=¼5i¾‡»×½?_¾‚Ó2¾²x„=:>_Äa½›eÃ>ÖÚ—½¢0¾? X>V„>Râœ;"¬è=Hü;<“‡½ù7¾S–­=^+¡¨@¾�í?…Þ@½�[½ÚðV¼1µ8= â¨=ÅŽ>¡+f>}Žˆ¾v!¾ú�8>]s�¾I»¾¦¤½`}½Ò’¾id¢<:¿F>_Âù½!}&=çG ¾ÐJ|¾Ú@¼¾æ9>Æ;f>ÿÚø¹[¯½ðѽ…;>M€H¾x³>®“½Úû >WkŸ½=�À>¢S?×*[>åé.¾ 0¾š.=ìÕÿ<#È}½ÛïF¾«¼ƒ¾¾¼N=L%¾æ—¾>àw<¾'œ;‡’Š™�…¾'jv¾•Ÿ¯<[áݽïÿë=&i=7ñ¾°K>½0…>Ž©õ;ªÍ‰>í«²½¤ç> ÷H>l%t>ÓŸ�¾œ¾är>=ßÿ[¼ñÌû½ï¾˜<�~ú>­(¿½4½·~7¾Rô¾„«Å=yó»–Ž'=Ï�è¼j��½Lh°¾îç»; P¼Õwi½¡Fß<)Ñ”¾üB >¡Ò‘½ÍWƒ¾OS̽=Ÿ=L¿š ¾ß:ó;8˜>­9½yj°½œ½�éX½K}y½ùF’=ù'Î>ï" :!%­=‹´!½›4̼ÁpÇ=U¾};“>Õ˜'½ÀB½€_¾0ëH=âH>­õ½]yÇ=¸U»=†8¬¼É }=þt¤¾Ç³>(E‚>»`f¾¯è¤¾Ýé.=•Ù%>�&¾d0¦=¡øF¾ï4Z>ÔI¾¾èŸ¾M\¾ò�b¾žØ�=íDâ½ê[š=Ø6¾4¹†>i2½àT°=㛼òÙý=é?ˆ¾hU‚>¨–¾Õƾ0½ˆ>N·ž=-n¿¥•>M ú= ¾Fá^=£ë¤¾.W>ó7•¾›îy½ßÿ•>÷"È=j_½až¾¶Õ*½•šü½T½‚ ƒ>@𢾠ØT¾’ý·»³ó½§ì >’�$>?Ða>xlš>›l >Us¢=ÓˆE¾d\‘¾T†2¾Jÿ¾>eS=ÂEj>·¥Ò½þ"®=»m�¾ô|ä½Ú`á=戰½]S=2¿C¾e+>õ9¾Ñˆ¿ÿ q>S,<݉¾m—¼ï’Œ½'ñQ¾¸d«¾¿P{>[ëI=$Îw>ÒËþ=“Ƚºkž>æ+°¾píÑ=èAe<7X÷;rñ >ºp꾊¾G¼Øìé½Í¯‘½‰îˆ>Ÿ Ã;D¢>Ò8>)>½k ø¾Ö ¹§‘­½î€¾=Ú’¾Ïéó=¯ˆÑ¾- >-+�> û…¾¾�ã½9ah½k ¾ŽeW>ò½Ø—Õ=s"´=D§¾mŒÀ½×³þ<¸Ñ=ž3<fÒ½º’½’}Å=—î/¾a<¾Ñx?–ª9>‹=‡>?�¿CU½ =ìk½þ¦2¾¶¯p>wf9½�;¸=O}¾ Ø<¼Ø—½B6:½Óµ ¼Åô¯>Ùî>¾™‘>7%>�s ¾ÝÒ¾0;b>5”>Ù ´>£-I¾c!A¾wùë½vÈQ¾��>ր輂肽�m°=_oƽŽÂ>¾ÒL¸¾ë5½t}¾ÒÙ>¡>KBf>Hùó½Û�½Š @½Zä¾¾…åæ>Öóâ»Ú>7¾ó#‚=X47¾c2½íoǼ»о}F³=•Ö=ÚÛ>Õƒ>”‚¾&Y‚¾‘¥6¾qx=kÜ='5>®É>Óh¾¹Q¯½¥O>�LÚ;ßà<ë½ñBU>‰è•>ÃbW¼�ZÕ½B½¾ðyʽ»S­¾cÃ=×ô ?·z¾˜ßµ>£>ÌŠ$½„¸©<Ô>ï,>pi>˜Hß;èë =÷Ð¾Ž‡¾µr¢¾Áóc¾•½øi‹½¬¥æ¼ÛÞ >l†¾½KÓÍ=PëU=3V»¼©>¢#A>¥…Q¾Wò¿½tDN=>6:Z R=¡’¾ƒ½>�!&=jŽè½ju>ÖN®¾æ~Ñ=æ´½~:æ¾úº½û¼ ¿<_¼ÐƒÊ½ˆ©Å½ 8±=¸|°¾»Û½– ¾q„<áµP>a·=TÍ<>ÀѼ¢è>KŒ¾{€;>½ø�½G=;¿õ½EQ½× ¾!„˜>ó&á>6_C=`o;¾U°½?8ø<>é=¾=#C�8ª>Ýš¾¾=¤g¾\Ds¾v”>WQ^<ŠÈ=u'=Ð[ ¾Ò?f=œŠ>¾P>Â6>=½YŒ_¾ÇÅ.»ö—)<0©Ú=DÒ½^a?—–Á>«Š¾Ìú¨=×j ¾K’˜¾ùÇ=(´ø>N¯>-Ž>@Ÿ‹>laF¾ïJ“=Vªä½àœÅ>åçì==# ½q¾Xÿu¾ÎÜ3¾Ìô5>4_7># Ï=;hŸ¾Í�&>%’½Ç;¼î#>áa;¾­o<½X¬’>!Mm½0ðò½Á”¼½‹�>øOÍeꋽ?Ñ>’ô7¾x½�æ5½³>M½‹ÿ5½·~„¾úW–¾¡OÕ¾¶ q¾•U6½�Oö=ÐOÈ=æt~¾&U>ñ?ð=‚x‹>‡ôþƒíª¾ŽD<>ø8ß½®Ÿ=ŇŒ½ã›�½ [Ÿ¾¼)Ú¼KŸ"=“ÿ=Øzx¼Å޽å!ͽÌ>‚>W¤<¾e¨=ýÂ¥½Þ«À<ím‘=k4�=VŠN¾Hy¶½à#¼h)Û»øNS>ó}¿øÛH¾GÙÛ>P—>öä>”ሾ^úÛ½š¢½ð>“åÛ=å·¼O¼±=˜,è>Ä9²¾ÁD:½{¶Ñ½2ï=QØ\¾;ñ.=`…>“i¾Ðð¡½@ÃV¼à2þK™Î=J!£½>æR><1¢>(ˆ>âã¿r®f>’Ù.¾1†r¾ˆÓ¾óŽ >ùŒ½=™Tæ<8Ê›¼Ñ¾�‡>Døy>½Š¾’ü=À|a¾jù>›WA¾@vQ¾Ö(r¾:ãg¾…݇¾È~š¼ï|Ì=2G_¾7">Í*¼¹š>âkª¾± ½¦èš=Ó >ÖA˽г•=+õ]¾�\™¾€9•½hg¼=¢\r=ožY½o³ƒ>ˆ ¾š6¶<øiA>"Ò<ët„>!»¾¡îù¾º®½qKÈ<Ù ü=/è¯>›’»Û!½DØ ½¿ˆ¾Ð#M=« ?{ͽaS¾õ€,»èÜñ½>ÙM¾ÆI(¾�(º¼Änm=¿'¼¾*ë;.Ÿ ¾Ûe ½ôúÜ=ËXX¾!ؾ%×0=Ü!=[0=ÒAµ=eg>³J²½Iͦ½º ={ô‰¾Ãm¾ÝE ¾¤&”¾]š¾£ã½Åþª=þ©=XоÊ>>N¶>ȯ¾ÿVú=?±ù½Ö˜�=ÕHT½ÓÆ…=¥E-<‘¡>!�M¾ñ1?—r ¾T‹½èÄ‘¾*n¾pÒ>œ”¾ûg >ErŒ¾‹<3=ÒÛL¾ûšy½ÜSí½ >Ðò=}6z>Ž”M¾ã2z=_q‡>­ã¼=øk>¾ãQ¾‚~>èÛ=Gòy=,_=ÜjÚ>2+N¾¦¢´=k8T>Ää½Ö)>½’¾º¼ç½Fo>­¥Š¾¬+>Iþ?¸í=Öÿ4½¿#Z¾v>ˆ>ïe‹>÷ê(¼&Õ0=š4¡>ðç^¼ûQs½x(½Í± >œ}p¾î¿}=éRY>UÀ²=7ÂŽ=2‹b>Dzˆ¾ôI>~?‘>Ûˆs>åïÜ=¸¼»#ªU¾!”h½Ù˜nd>޼ö¼@Ë>Ò*“>W{¾éW=¸@€½Ñ@><ì�¼'ÃF>˜O>½—n€½‹N>&öz>iéX=$%¾˜G=÷ØW>…•½yX >ÌI<çÛÙ½«n�>M>f=J6¾÷ˆ¾ô¿ z޽¾©�d>ñ>­:�>úHÒ¾†Nÿ=CC¾g•‘¾†õ›>pÿ(>î¾F{U¼)úÞ=îw2>{.¾=ˤ>5W‚½™¸†½vˆ>ØDÿ<±p¥¾HŶ¾ï:ý=tQ°½x¤Ø½‘€¾†"ì½&h¾²{È=èžS>ïñ¢¾oÎ=±t½ÛõR¾ €g;“3>–º ¾÷ÕÞ=p¼±½t±½©îo¾œ‘¸ººù>s!b¾åû=EÈ<`X>Ü ˆ¾€v•¾È£Ê½ö’—¾ÀrÉ=+¿‚>Êéß¾:§ç>çо?¤>Á%Ç=Ùp‹¾ÓŒy=½}ؾ¾Ò¾—À¾ 3¿;¨(>NïݼE£Ž=èíÔ>2”ê=j5½¥Ò=0ÇŽ<,eϽܙY>ËW=¶,¾kM>ÔÄy¾Oá½­`@¼([ð½ÔìŒ=tà>z-¾ˆb?¾#Qß>ò%‰¾Âñ:¾Oæý=™Y>;\>^ª¾·ò>í�”¾$UQ>óíw»Åg€¾`aœ½ 4y>Óÿ¼æå‚¾�©�=Õü =š«Ç½ÖÈÌ=7�‚½œSܾ¿^¥½Ü ±¼ÐÈ>r‚ä>¶ ¼îAu¾Ð˜�>=¥�>*Úô¾~Œ¼HD�>yª^¾™¾t» >ud™=!H½‰ÖϾÈbº¼R=Hú“½1˜¾jÍ‘>˜â¿6ŸÊ½[N¡¼ÖLï½~ܽ>5ï±=â5 >÷'£½Þ-s=ÝT>û›¦ºú{Æ=5¿?>Û´0¾uZ>+ææ½rÁ‡¾Õ>åª=3="½‹¬½½¸–>ðZØÕ°Ë Òǽp:¾)Ì˜ ¾ÒÇ0=SL$>φ¥;äÞu¼w·¾>V¯–¾Ö±ã¾IŒ¾Ïý]>ƒ > >Û™7>ÿ¼P¾’y…½C@%¾ÞM‹¾Ûî½/ú<¤Â´½DÄ>)cS=*¼xN:¾É)¬¾Ž$<< I\<”7<{—v=Šžµ½/åd¾@�Š>I[ÐD>Ù"¼y4ݼ½9Ð<.—ó½©1¦¾ÌŸÐ=Ú*<'ßf=&¼¼æô¼Õ«½úZ¾VÔX>/Þe¾ÖØ«¾– ¾ª!õ=÷Jƒ>>Ãõ<úÛÊ>œÆ°=¸5¡>ŽÛ<í–ý¼0=ŒÚº½Ê�̾×Ù´¾í’(¾–©7¾Îa‘¾½œº¼ª°Ð¾aÞ>l”\>‡Â¾ÅFƒ=ÁǾƒ›_¾Yš/¾esè>¿’>Ú¤½z‡>bàÙ¾Ø��=I{¤=1æ¼_>¯kÌ<]¬©½ÑÈÁ=/ƒ <Ý;×=ÐjͽƒáI¾:~‰½ Æn>Ôû½ex§=øko=æþ‚=Ó|Ð¾Ø°í½´�•¾G\r¾,¶P>*38­¼ÑâÑ=c&>iG¾»i‚>,ŠÇ¼º‹=�˜£½ˆ€>œ©A¾j{s¾¥Ÿ=ÖMF>¢,=µØ`>šÒ¾pèG>®E>OBI¾OPy½Xí×=M¬E>ÿ¾â†„>®¾íK™>0� ½ƒ�Y;™§‡½ŒOg>ŸâË>Fƒ¾a˜Š=ˆƒ|=2ãu¾Q³i>מÕ=:ã;>D‹†>{„>}"¾V¸ ½ OV>.å¬>Þ*¢¾ñ�;>T«< lû>Õßp=Þå½½„è�>iíY>Ž”å=7¼>£E™=Êb>òÛW¾SeŸ¼€.Æ=ï¡K¾Ó>Óä/>;·ô<ˆ†=ì•>;�yº>d3�=û”ë=Ö>[¡ñ»vÊB>çÞ™<±V»øƒ¼î̹½^Ù;á�ø¼èR½¨H>øub>wýz=çþ)>˜Ÿ>ù±>Ý�M.°µì&à½ØãD>!zU>Ð.¾Wwß=ýkÿ<¸‰>×; ¾b3<\ÅØ»:ºØ>EOK¾­£ »ùŠé<ý•Í=2+=Îñ¿+a�¾çB=Íúê¼ól<>:¥Y½¿´¾Ëòv>ôØg>ÈÕ>=ÎÞݽ1¢à½õ9l¾x«×=òì�¾m˜¡>P—Á=›�=ú`[¾²·½°UI¾í�©¾ÿ“R=«ÉR¼Ï²ß¾- Ò½¦šI¾âb=A᫽½Ú=6�¼ÊlŽ> 6‘>9¹?½>cŠ<&¡¾½²¶>ò1Y½y¨Ô¾³X>OÁ½{õ•¾)ù¾�Až½Ÿ'…¾Ö¯U¾Sld¾Ç—,>.¢˜½ ͉½æ›f¾èmÓ>©}-¾�¾«Ð1¾,C¤½R"ñ=˜t¾±Pͼòi�>Æ|§=änĽùèB¼ž�>üÌ ?…²¼ÇÙ®¾Ø`Œ½‚¯>FV.½±"´½|…Û½]¶G=²ì:>Y�¿]qT¾ î«=þô*½>Ó;)š¾2ß ¾.%…¾6Y�>Á옺+f<3q~>˜<.¾„Q4½�À½c%=<Þß=¤=¾N9)¾V¡½/�>螆>nåJ¾7Š·=V‡2> ÷¦<ÄiP½�’½Ž±{¾iUØ>yК=´o>ÔC…>ì¼wb½G£=YH”¾ìMc½0&3>t‡>�c ¾€Ã >ú^‹¼'̽·²Û=¬ ö¾–>¦Ð‚½2XÀ¹ÿüž=Â(‚¾b%>*æµ½‘k‘½Ì/>¨ÄC>Î>JP»½+sô½:¸¼�)¿=éñؽ;;5Ïj><>ãð½^ ø=±8—½[>EÖ¾ô®½¸8†>¨ƒ=Â]Æ>ž½¾×­/=ŒÙã=Úº-;1"Ø>¿¾‘»gù¾jÞl¾­›”½&7;¾„ºŽ>§BÖ=N!޽›W½­ÿ)>u*>y±H½F|=±÷Ô>Ë\>:}ؽzÐ6>R]W>$–¼–Œ=lƒð½õÜ=¼Z°¾‡Œ=Ê×½,Â’½8êu�>Šžz=-줾ï( ¾æFó¾àï=®�[½”f‘¾ÃÕP=0ù?á)>nÃ->‡2Óyþ�Wš¾� >LO‘½G2D¾›ü½S“Þ¾ãoý½ãa?>ö_œ>·ˆN>ÆÂ޾u˜R¾ 5™¾óâÁ>$CÝ=½`‡>/ëy=Ûaa>jS ¾Ìöû=€v…=肾à >?•�=kÍÃ=¨Ü½¼k$ >Yœ¸½¨JW=ä‡Ã¾!ƒQ>œ ÿ¼áyƒ>(Ë#½â¡®½yý½¾½Ý¾ ¥�¾iÄ„>Ùã>Ô2 >kz¾ÿQÝ=bfÕ=ê]ÿ=rÞ“>ÈY‡>‘ê¶=ï G>€Ž\=G=þ½+Ñܽ —/¾9.>;ͼ×'Ú>ý„½�ºö¼º)Œ¾}Òµ¾Z±¾]¨>»ó“<«QÓ¼YõÜ>ÞL¿¾»Ù:¾}q�½¥NؾÚV¬¾.—¡=Û,¾�¬q>k`= q4=zêÇ=1ƒ>§É ?Øïñ=4ø×=-¿u<+Y½>p¸C>)ýòf ¾sšX¾S¡<[YC>Ôý0½@ò¾±£µ=PïI>»å">š =¯ª�=Åói¾¤½ä=ÿ† ¾¯AÖ¼˜’ý½žñ]¾ÿ=½¾ÆBž=Ûá>4ò[¾?¨~>Jk¾uö¢=Ø|D>þÖ<¡w>þ±¥>�B:= «ç¾nh˽G8.>¡£½�Ÿ½òy�>7«ª=ý>£¥;>ø|½7–¿¾¢ q½P„«ºb.$>=é!¾¿;.>…2µ: à1»½®¼Ñ˜T>ÊO½Å@ï½ý‚˜¼°ýs­¢²ã%¾Ø=ÿº_>Y)¾£†½ž‘_>pñU>¦Z ½²œ%>)�\=‰#¾µñ™½þΚ½Œ+¾HP�>éÛ�¾¿ÉJV¾œå¨¾šÝ ¾ï¯>énÞ=4Ú{½á­°¾rd¶¾˜ì¾­°=®øÈ¾*ß?zu>|‚ä=l†›=ª¶�¾á ;>�¾„u˜>W™¾ü==Æ=–Ø>š»=; =WU¢½më½6µ>¤ÌÕ<ƒ™½¿0G¾v�Ú=ÄyL¾ñP‡¾ýµ£½Ë¬½_Ѫ¾&‰+¾…)¾óåÐ>Jݽ›S¹>'¾à +½3ã½õ€å½Ø?÷Z¼f>LYȾw”ð½þ М–\½]UJ<ä=ÊO™>+2{=ö�*=,t³½I=’=N¼Ê=µK>µLÅ>ˆ7¾Yrt=­ï�;Í[¾öK=b�½ÌHÖ¼•¨Ä= Ã=çôe¾Â6ë½cÍý½J佨y=”ç=Sv’=ŠT™=Ær=Ãâ>þŠÆ>7V»^Q̼¤Ñ=(‰½H/¾îË>ÄÆ>¶\¿8~Û½àÂ>¬hL>™´=p3:>c²(:4–¾?«>RŒI½ˆkE>C²£¼$†¾¥ \¾§zA¾»r‚<ÔÙ†=Þ7 >b´í`!g>àâþ=XøË= :–>R‹½–t.>µðª=Ö½–©½ÿø ?[Ò„¾Ôm,>¦Ï½G�>HÓ­=Vu|¾P£]=ñýô¾‡S�;=?f>¾ÝÍ<Ä¡#½2^˜=Uv*¼«'>ZŠì½QrU>J_L¼„„7>;T¾…¿<§¶¾ d¾•Ì ¿?­¼½—?@>l_¢=¸®§¾YAs=+^.>&âs¾Ì¶¥½Š7D¾\n…¾¯sŽ=ë§j>´¨b>±Rq¾=08?8È®=Þ�½ÐbŸ>ךð½ºkƒ¾`ýÑ>ê‡Ê=¼ƒ§=Jɪ>~¨6¾å(V>´Ï¦=+â¾f§ö½ú%g>ab_¾jº6½Ÿ“M>Å>¸>s°à>�¥=NxÚ¼á1¾\“ž>1ç>·†‚>Kyš½¶i…¾ó¬>ãîì½°9¿¼‚É=>Ì�=®�*¾c�‘>æ;¦¾%çp<±B=‰º›=¹—Œ=¤›Ì=v½t½õ¸5>ƒk> ƒ}=@FS>BX>æìœ<`ÚÅ„>Æ#›½d4À>íRã<Ü3->‰î.>ñ¹s>»%*¾J­#>�ÆU= ’ú½q‘‡<&uQ>…X[>{’>H�>Šj½dÄ¥>X÷J¼ ソ&{·<¿Q¿îp¾›¯¼j´>ûE…¾Z›P½ª‰:>`ù½½”û ¿²¾}w½/eÑ>T$>}ã>S ¾Cñ ¾Þsò½¾›¼ø­¨>ì9H¾Û?>½C=�U>Õ‚#>®÷$¾B!¹¾:Ü-¾ˆÓ>¡~Û>SaÎI¶é½H4¢¼1¾Ôj?¾âü~=V%4¾Å:s¾ŽÞ9>b[›½½e>ÉäK¾u‡œ¼Û)ð½¶?Eù]¼¨¾°g�>H^×=öë¤<—eg½ >>¸dË=˜/>6õ8¾é‹>/%”½ç}ã=d¹ =ÖÈÙ=h´½OªÝ>¡„\½~t�>G£†¾1€œ<© ½û*$=^ >|ê;¾”ôT=_‰õ¾æP¾ÿè¨>jl¾\ŒS¾ãž>´.-¾oYc=;Ô±<žr›½[m>.>[p½Ïê>X'¥½Ì½“>ºz«½+\>%>>¾`?ØïS¾?tì=BTå=Ha>ö¢;¾Y�”¾¦¡Zž.>´Òõ½‡F�¾ òȾªA>ó=>âý½IÂG>ísú=,¡ˆ>W¤½ I¹;ÓÎp>w¿W>dÜ=¾b¿p>?ó5>oW ¿ªÊï=r;´/�=¬[�¾¡:„½É-Í=rÞ=Ìp½�¢—½Aå>¯¥¾X‹ÖF¾zÛ�½=³ç<ú¶>c7 >öÚ¿É™Þ=IÄ ¾0·à>ˆØ>_X‚½¶";�F?ßë#½ëU4l½Dá­¾]`>DÔ½"ª=Ùé>!r·><+Æ>ëî¾ o�»ýÞÜ=ºèã=ë&’>¼v;üŠç½¹±O¾4 a½Ö0½kÅè>ÌÉŸ=Kb`=«&¼’/i>ùkɼc¿h¬n½N,>#îI>œ¾ºfé½-oP>ÓXï=ËpÁ½ÓÖ�>Ì.`¾ý˜}>‚‘^>]-R»æ+b¾–=§ï-¾FMœ=NË->ý ¢=Ó´>Ä{i>nð=�ƾÚ:æ»,\†¾x?`ª¹¾Ú/›¾Æ ï;=Ó½XJ¾„G„¾ßzÁ¼³l›¾ |ü=¾$â½Ù›ä=ÉZ…½ø2>¾‹À2¼+ÝĽ›®õ;$íæ>¯Æ¤>X/“½ñÙf>ïNx½+‹8½á­¾;)[=:=é÷½2‘T= R¶¾Ÿ`¾ U=7Π½?µY>xÀð=Ð�X>Ihg½Ü^d=²Ø>0_„¾š®”=è£Í>¡1¥¾ ì+>|P.¾cR¾,žœ>öÂô=†è³¾�:0=«x˜½³C >vãï½÷ر¼±y‚¾©û¨>>2Ó¾¦1½Ûȼ=øM‚¾ çϽ{Ë>ïž6¾¬ƒf=𕬻n,ñ½¶'>L¿^<¶O¾Ã�‰<ʆ>uJ"¾� >ß,9=p­£½ˆ�=„%¨¼Žpë¾b+Ù½7=+M´½÷±¼ùc'½¢)¾nƾÀµ6½À©û=ì ¾t­;KA€>�Î5>Î[«=+úS¾2==“>�½]®O>Ü¥5½s˜Ó=܈˜½Ç÷´=èß¾3=É(>–o•=ÑŒ>¦;m¾Ó}A>±¼×\/>FŒ>Šlù<š*L=ÊÉŒ¼@wõ½<<Ÿ>£W“>�†>¼‡h¸;Õ,b>zIÌ=ï >'¾Ø¶[=Œ¿½µJZ=ájN¾l»<¾ -ã;‡*G>–y€=H;=ÿÊq> øÁ»kJ\¾s†Ä¾lòâ¾A¶¾8ço¾îè{>hzû½Ù?¾)½Ž¾öv=½àj�>ªP¾ËÐj¾÷™•¾ß)<>¡˜Õ»55>-È>z‰®=d ¾’Ù¾¼TEx¾üŒ¿½†W¾­ƒÎ<-y¼*¹¾íßT>í„=`[>QÅ=”ͯ=4ö¾>XXŠ»{Ï,¾í?j>ǹ>Òo=§_¾ñÉ‹>y´&½âÙ®½„ƒe¾äU½DûÅ=|ë>£­Z½öõˆ;£‹? ½B ô>¦É“½Ã°9(Öd>vºô`¾~{¨<è"ª¾Y�@¾ÏW¾ûwŠ>ùÎÄ>˜à¼�’ð½Ôÿw=ªsÓ=ùv¾]ƒ =œe‡=»¦‹<]J�<OW>~5‚»ñ¹¾V¾�>Á:»=¹_(¾œ�â9ä ð½ß£>½ÁP½&Çý¾U¬ ¾X•‘>àý?†û=v†~>©å×>´wa½GU.?tÒ;½­HP>bäÆ>†2¾°xÙ=·¾Ê•q¾°¾sB>”:e¾ÃA¯=†£§¾Ò$ù<®ã•=FIÁ<í[�>ßõï½§ï<à²Ò¾ã^=ú¦{½e¢=ʘ¾"(H>f¹,>«Í+=¸(K¾Kšg>Bú;>'[¾à÷žyÒ<_•‹¼Xš>=Jæ;ñ6�½§s>û �½PÖ²>xT�>üùæ=ñÝ4>ì×ñºt8?>Rs»¼‹d¾Ã‰¼¤ÛðºëU–½D«=•†–=í0>›4콥Ѿ·*¤=*>ú=<î>tY°>ÃLM>_mÆ=i„1¾KVƒ½[ˆO½¹¢¼=”?¾Îû+¾î¡Š¾Ô` ¾�)¿ ¶`¾Êd¾Êàž>¢Û­=¤ç¤¾‹ß¾¡F$>„çô=ÝF>ì”î<#p3>Å+޾=Y_>Óì=�k>YÚb>’Ì!¿w|>ך>«Ã>U˜½Hú½Ájš½Õ¹½Ê�¡>R_7>PæE¼�̽¢’”¾(§j=M¥>ͦ=,^&>ñ@¾Ñq´½n” >Mã2=4ȇ¾-(.> &ñ>4sµ½<”‘>ÅÞ¬»^Š >YÌ>sŸ=Fƒ…9Å >µ¸ã=:�‘¾Ö¾z>©¿½¦y=&V>3½€<“`>ˆ*>òlâ½¢㽎Ë>R�ú¾Õ5ͽ"%<¾1 º¼ñÒq>™ÅJ>|"ϽIÃ>0M¾¶L¿G =&Ý >-Ͻ9‡’½õ‘€=sfÈ>�ÍK½ É“>ž°¼Š �½uX>*Õ�=°NU¾Õ±o>U¾Ö‚·¾¢Q¾€L ¾É+�>(æ>ÝÒi>�”M¾3¨¾>r€¾ö*‰¾z¿©>*Ü ¾Gÿ½t´c½æÛÿ=ô¿Ú<�?ö-+>¶ñâ¾åØr½å,:>mïø=~>l9$>Wrü™AD>&r&>)<Þ½­m³=÷¿K¾œs;ºÙ>ö&¶>Iþ½¹À>¿is¾´—v¾#`¾_Â>pýÂL®>{Ân>ãè=¡Á<ú!ä»Vß>Žm�>ˆ¾è¾Ý¾çÇþ¼T>àø¨½mðÎ;� “¾\:)=ïÑ£>?1f=À8Î=Ä}'¾Þ]c½ †‡=-„­½÷˜=0Ü>ñ�¥¼Æ=½Çj¶¾¨:4½^îþ=-µø=®3V¾1Ú€¾f(–½Ã©ä=Óyƒ>çTнhí®½?†¼Ur¾�®k>2ÛP>ˆM½Çt¾³x×=ªk¾ôA꾿‰>Ûvþ<ív1¾Y,O¾9ÿ½=Ì †¾o"*¾Û‚=à.ü=­¼Å¾lÙˆ>¢ß¹=<ý½ðÝ?=c¸�>v<½M#e>ÓB¾Íiô½~O>¸,+¾ù–< TC¾åâ¾½Xý<=�"˜¾5ýˆ¾E u>ž2e<;‰Ë=“¾ó>LF¾1L^>;¬<> Hݽ”—Ð<ܸ=“±¼>X™=r‰>³:¾å =Qf¾€¾R@=�Ô~¾»Á¾º2¿:–Ùè¾C¿á½TÛ'<#Âð="ag=È4ϽÉð�»jˆÐ¼{|¾$…½üºÇ½¨ÇÞ<ÎùW½Ä‹“=‘r>n*%>^Þœ<ÙýºX«G¾•-`<­jQ¼œáʽ‰nÿ<õ3>Ig�=G5è=0A1>ÅÿV;’b¿=´1³½†^¹<H@¾a¾Â¢¶¾Øª‹»8ò ¼È{U¾×{R>©Dj=ÈçD¾\>”Dé=ð%½W`Ð=ª~D>ëW>áHÒ=¨gÙ=�ï»–¢=>[=0d@>˜¯%¾¯—=ᇑ¼¸Bÿ=9ò<Àé¦<­‡=Š]ä<µ_…>ú¹@¾‚Ñ&¾€!=u™¼Ô9¿¾ôl‘=¥q>¨Jœ=ÇY,¾Vûë>ÍÞŽ>øùºš�˾h¦½:ýªš> ­Í>ê_¼> =£xœ¾�×ë=©Oٽ˱£¾<È�>0,q¼6«[¼¶>Ì�½å|ß½6 ¾÷^z=¿µà½ö¹…=×_¾ÍÄf½å›–=ŠáÒ½_b½8·o>ÌP½D™)¾þU;Î7¼މ>÷Of>½S“¾Ž >Éþ½ Ǿ�Wõ=³ò%=­}>[Y ¾r8¾[Ƚ[Íø½È€+>"G”>&2Á¼Õ«@>éËs=:<¿âü=ŠÃ<ã&¾�¥�>L ‹<î–”<ø�>7\¦=$±.>1î¾Å]­=’Tоø´ˆ>®q­½9| >h“%>ø.>ï #>a¨?êÍ>)¸”=6%T>:^÷½Œ—=hνwX>- >äèµ½Tê„>àß=|áG½¿‡æ½bl>¬ã»s>ô££½/lP>j“=¾œÃa=‡{,=O$>‡*¾�)R>»†¾uϼ=i?s¾¬¾ä”¡=bñl<-8¾½Cà½Ô|d¾çÎ×¾®Ù|½I¿=^¡R<0v¥=h!Á¹vÚ>.h‹=8]W½®¢½ÆÌ >Jÿ™½ƒò•¾¦ßx>Û­O;x‡ ¾‹4¾Qõ“=Ð@#=ð‚¾ ‘³>S¿@ô=p}—=üÀ\¾¸Z0>)v=]b>j1½—c�½§äã)¾ñ¶<½ÜÉ=åÚf¾°8=n §<–Ýr¾Ëˆ–¾ Æ=-j>°�=hüt>88ã>>îú½Ù4&¾­;„>òx ¾±vǽVÂ>Iáâ½ €]¾˜û½ûÉ<½åx¾@uø=m>§#O½†)¸½.ý)¾ä±ù=Ï!þ½HúǼ,“V>�V¹½Åg˜=éÉ>޾öÏϾ»òÉ=–Ló=€j ¾]sÁ=Å¥¾=¬l~=~©Ó=%Š[>Þnø=H ,=膬=Qn'>E н’ì[>È"£=óc*½íÍ*\¾io¼ÿ´^½ÞO6=9ˆÂ¾óP½öS½¾0Ë+½9ñl¼nŸL>dŸ½’Ó²<›-=KO%¾S¬â<ÎI]¾®w/=µ¢¾Š8¸<µG·>¹¹“>Þ« =ÓJc½ ¾qÀ­¼\U’¾l"„=°ȼ`3¾,½}qå½D%m>æ„¡;>N§þ¼8ă>+Å<ó”�4Ÿ¾$¼]>£'>Ï—º¾hi�½eˆ>"É•¼óY„>Lf‹¾8•?¾0+Ë<º`¡>ðZP¾ž‡=‰!¾tkc> àŽ¾rľå¬>Ü8¶=SÞ2>:š=$·=ÝO¢=‚Öx¾dõA¾Y¦[¾;‚¨>Jš¼ã�{¾ä½Tó?¾¬+’>!&õ½˜½ý[Û;uã°½a ¾¥V¼}øÈ=e&`½�Þ5=îÀ=P¾/¾+êœ=Œâ=½^ð¾ì—¾qf'=Å‹>ü3¾ W?½I´¾˜/•¼dh�¾œç½,Ë>U�g>'Ë=-S>Ešò½¡ g>ÂÈ >UîÎ=¯¼½ =èW¾GÁ#¾ÈF>²¿ >§$—>%î½»‡>ÈÀE¹ìw²½wÚ=lù$>/Ž'¾�|>ðÞ�½䨽D>úý½Ðm9>?�½Ì·î<64*½¡l#>/n®>sWŒ8¶)¾x(ë=åËÜ=5�Q>Œ”¼åv¼¼kšM½0�>CÈ@¾z�¾ƒJK½t!M½v¾|$¾ç=ž=Á:½!X.¾køV¾m™>B>åÒ=Ôo>R�§½#Ì ¾rB¾Ó*î<¹].>ÿÙ>×'ƒ¾ÉçÖ½$/c>)/>½èV>–[�½ën‘>è7ƒ<áÚ†¾OEB>’¼#¼û†.¾ÕT9¾%R ¾ë!¸½L‚¾ê‡?< "Þ=#uâ>[K¤=Z)¾Ö'½’2=Š�¾!u¥=˜¯">Áù¾x2P>I =Ú@ô<Û9E¾ÚD ½Ô1"¼Ô#>x�+¾®*(¾5Ú¢¾·!> ÿ=ËNê½bà,Ãc½n±ç9zÞ]>Ù¬«¾¶Ç=æG>ê-ÿ½b<£=á7E¾“…¢½Ê O¾Cà@¾–"¾Gqœ½‡Ó¯½Šç™<ÎÚŒ> 3^>Ém‡<Ðô>"ÒO¾–¾²½®ºØ=îYç½Û¸V½3o ½¿r=C𥽱„½šl»>I°¾ú(Þ=Ÿq­>¢›–= ]½R’!¼\"¾¸³Ï¾Žê->'Ø$>23۽Ɨ¯>\*à=9;½½]«�<Õa>L£î½ô[Ê>T'üº1k=qN¾<1&¾­ŠJ¾õÒ!=7‹º3ä:>ª7”½È@“½f©©¾/>b“º'L¿>ïò8½±Y¿_�:¾ Çš¾Z>)I…»Åi=ï ¾ÅÕ+¾"oA<#³E¾¢ ¾fÖ!> (¾KÐ<»´ò\8½]¹~>e3;>lá.¾ØK¾v7­½Xš(¾}À�>²›¾L�Ó½Kˆ=¦ê"¾oE¼½þÙ>piÈ>©3T¼•w÷@\\>35>„>D½ ¾@õo¾¾üä½_ÐÔ¾u¼<>… �¾B¾&>­ª£½«޾ …¢<´×d>4¾´Êæ½ïØÝ½5 > œ¾ñR×¾­¡�½zÑð=êi,=—Ø=³�K=ã¤=•�=j·b;V]Ç=Y&X¾Lr¬>A‘¾{#…¾ãY>x—3½Èò¯çuß½F¶®;ŸD꽄ƒ½+¾²>è„=D¦/=‚>/€>ø=>ÆØ>õ1ø=„;;=Õʾ(»èxñIç1¾q K¾ñjß½­g>²`¨=ð�>o'g=SȤ¾Œd¼ÆÇµ½~h¼½-×d¾Ò:Þ½ þÈ›>_í=6C>i7> } ?½|ù=�æ‘=‰óæ½ç:ç¼}¸š>”c›¾[»l>fh¾S­‘=+:­¾6ؾī1¾ØW<>9k˜>;ܾ³±=bxJ½®6¾þ¼)b <-Ò:>‰U$¾>v=TÁ�;�ÎH½”)=>.¾@4¾ƒ“=©“Ú¾½LŽ>çÎ…½' ¯½º1Ù½A {¼áJ¢:J-÷½’;¾ìgp<¼•Y¾SBÅ=ë¶½uÂ^¾òK÷<#÷);¿z†>F¿»Í/>=2>½ú‡>û•=j¤ ½vÕk=G¯�½e'=¾Ç¿O>ÛlÄ»•+ƒ>޽‚ о§A¾Uc;>#ذ< ]>£ÓI¾2Á¾N á½ûZ¾Dqñ½» Ÿ=l̽:ÉTi>­þ½ÿ_0>xÿX=ƪ">…Õ½h€º¾nª >_l½N^>{ŵ<=Ò½®u3¾%¢3½—ÕÁ¾—= =¬Ê.½Yí3>±²>\8¨¼¼Æ�¾8 Ô¾* ?+Bâ=Åe¾tÎÙ=üsj¾23š¾�,;×i?½=Ë=œ(l>�ª^¾G��½O¾òè>©á-ë�8>8É�<þŒ¾i4>{™p>²X�=þ@�=&H²=Í‚’=>Z–½ñRô=íý0Ì}¾ì¦Ž>5pâ¾#{̽Ð-¾t‹k¾¼÷¾Š š¾àmy>¿£¾/>IŒµ¯\®¾�°£áˆ½Ú‘6>`IS>²$c< HB½7‡P=Á¢H=L�¦=o¤‹½2ì=<[ >jrn>g>q>-�Q>¬_�¾õk¤½5� ½(2g½D‘½&ž‘¾žÍ‰= ÿé½å~н}ì¾�!Ľ 5>~Z«>Ešã=“æi¾h >ã%M=Æ|t¾¦/q½ÞvÁ>´¿=Û`�¾§ÿν`öB½XÊ=CMÒ½�–>­p;4yA½‘¾FŸ‡>)I‹¼¹æ?=3½²d>Hºê<h¿<휽,'=9+º¾Ë!ˆ=—<‚ö=Ôg°½Ù >¹ìæ½dJ=+�¼Ö�º\0 ¾í„r=¤†è½Ó=)/=õoA½Ý,y>%V1>SVü¼Wm½Œ»i>ùF>0iÃ=Ôa+=jŒ¥½ò@ =´ÞU=F³ä½cð²½B›½›“F¾œÊ¯¾<îc>³ß¾¶—3>ò.‰>_齓yP¾Áª4¾‚�'¾CÁ >Ž6³½Ùr­½/O¿CiY<ô"G»ò¸Ö=øÌ™¾We&½Òl=õ4M¾¶JÀ¼Q0Q½%´½Š×¦¾³Ö”=ff¬¾úRû®TÔ=Ïe­½RÝ�=‡ôN>¸Ó‹=R >�ùN>å×�½XÖD<`¯�>f¬¼Äw¾úwc¾{Ѹ½ñy½òܽ†ž»\?à=aÚ½Õ¨J½ç†>Ç*g>Òš$=�–Á=Ë­)¾�§ª¾øNÃ= Ul»Kø€=�‹½,®i>èVX>þ„;¾o\>ëS¾Qº7=lðª<\J<¨z>o'<¨—¾©m³=yJÝ<ªw><¡¸¾shb¾üUŒ»ÔDv¾­q÷=§Q†=ºàk=b™Â½îwS¾ûñÀ¾»'*¼‹€€½zä=“¾ïñ„½ŒÈ ¾Å=š>ão‘>þ3½ 0¾­Ta>ŠÑÖ<¯VÑ;s%s½*�ニtc¾IÃÚ¼6J¾àX>èpá¼ÅÌ„>uå=”i=Ýó>áW5>¯º->^•u>~’¾üÚ¿týˆ=q4Ï=¸²¼>Œ�¾}f'>½¶·¼mÖ=’a>/ >±J}>®¨Ý=R¯¾-»>>ô!µ¼#ÄU¾œ_²¾wfo½`’´¾N³©=ojØ=YG»=BI>н…ñû½wùn=°õ–=J ¾0Ý=ÿš#¾m޾7Äð¼i1¾Ðÿ8¾7Çä=¢UÔ½‰Ï>LM =b=‚Ñ><ij½¹<¯¼�ï©>}À¼¾'.¾‚¾òqF>T£œ>¥’¾,)j½ÖŠ÷½™Ùò½¦òA=YJp½…@¢>E=)¾«:}¾Çê¾ á…¾® Ø<ô¡l¾:#’>X½´44=®W>åB6>ÂE¾·Z=Ćé½öp>©›A>ѱç<ĬÄ>n§0>±{ë½#˜j½W¼ öˆ¾1™T<…Úí¼ª®x¼¿)>îšy¾~ä½=© >ݳX¾éDÊ=Ös'tÔö=��|½åz>ñ)×>á즾<´6¼ )0>Ô÷°=¶ÕÅ>ý@½­™Ü=w"‘=-ƒ¾žà»¾P6æ=µ�‘½4ÊE¼ú\°¾ÿX>ØÏ*>Æô½|Ê >NB³<.€¾ê]>^ù…½‰â¯½”MľE'gJÉܾ q>˜é¼Áný=��P>¶e¾Š}8¾’JμÝÔ˜½Å4ú>98Õ>jF�½ßms½–\Ô=UD5>,!==ú›i=@ñB¾m�‰>®Ö�¾D>à$½½Œ;7¾O/?¾Yhû=t´ù>—R¾•ó…>Â�”½Q·>UÕ¾“'>|H¼;rô=ƒûÿ¼'|ù½L:¾ÐÚ&¼ED0>¼GÁ>$—ͼXe¬¾6œW¾)惾¬ß?¾‚ü>™é=-I®=ôŽ…>Ÿ ÿ¾#W‘¾FT>Ý#¥<T¾†Òÿé—>æK=�н Iî½²œ5¾“!¾BŒ…¾hó/¾’82>æ/y¾8º=ãz~½‘¨¾"6=:é[@½Í¼=ÈÒK¾ktF½ *\=•ø>.Y=.dë½RP=aI¾¤} <¿¯¾¾cÙ¾ ½)>I¿“>MÚ¾‘O=vf¾cDà½þƒ>·Ì=(ºü½‡S”=ýÛc=J™«½”€¾]Я¾½å€¾E÷’=ñ;„Ó&=ÒK>¶«= ;Ƚ̵½œ`…>œ/²=?¸>ÈDë¾é/ɽ÷¤>¨ã >w]>¿yj>&­„½¨ü³½vÈ<=ºÜc½‘2*=•±nñ¾Cë">"ð¾lz0>o£Ï=i‰>ƒÑK;$7>•òǸtŠ> KŸ>0>=¼˜F¾¶D&>ç8½„ZY½Ã¬‹>%mS>Zm/¾Ñ…½ÄI5¾�# >m‰U¾»C¾Ÿ8’¾?`í;k>`½Ú<�>H¥p¾$�¿}>î-û<Áå°><®Ã½fõã=ÕÓw=³‚¨>“ùð>=oŽ=Äa¼>H·É»PBÔ=‚£q>’ÿx=˜° ¾Ù³4>(=;нj@¾pS0=vˆr>/Mý;ðb½�² ?�“ˆ=Яľ6¡¾?¶=S©Œ½™ºL=ãf=bôû=åp>�ꓽ~¥š¾‡î�¾•µ>Hù˜=‹ðO=¡ú¾Ò é>Óe>UR¾p™>¨×>V.¸½y ¾b¾Rº>Árž=’Ι>Aݽ�?3Ø!>üí{=Sn½ëè.¾ò�b.›>:­Ü=��¼ÜO<;Xž<æùô½�û¾ãñL¾â8>°÷½K¹>tDнÄÏ…>Å è½R½¥½ ~˽t¦>• y¾W¡™=Œëž>Oh¾;pO¾4W5¾rØð¾üð4>âÃß>È|.>*�>0ÕŽé¬î=”ÈÅ=T°T½M¿¼Ó<ó½c}Õ½‹‚ ¾=7ç=#¶¶=6Ï<Ù®>¤Ä¾¹æÔ>�—þ½„Ù¾=Qü½³>Žâ>®qã=´5“='—¾öˆ>wl>” %½B3­=«š£>sP_=ÄÞ%>ºì>±ùT>§Í*¾w޼ꎇ¾m`4>YQå=À-X¾x…=ç½=ÚœÃ>m¾­eν6¾ ,>Ì>e–I¾@$½œ¼¼=.À½*ú ¾I6=°?à<ù->ûr·½Vów>›}¾[ë;Ïýá>eä†>Èîp=Ï7™=ö=½­·=ãAʼ�±·¾B¯5½4ð=¾ßjÝ=Ü4¢=$«#>‘=Ì=žèö=68¾+—>ÂZß¾µßÖ½i)¯½à×I¾E\¸=îÊý3’¾N I¾ýÚþ>ÆT»³Õ=÷½°?¤gȾó´?>EQ=R¸Á¾ø²Ñ¾ˆÉ�¾ æ=ë(=×ôÊ<� >=’pS>Ùn˜=j6‹=I̲¾éæô¾m±´¾iµe¾7H%> i>�‡½FËL>·cÕ¼Éÿ ¾ úÿ¼,jϽ Wu½*'½ ûü½Q’è>§á¿= OÕ=íª>ò4¬½Ðôç=än>CÁ?¾Œ,�¾´‡}½*{�¾>>o¾€#>Q—­¾I>ì>=D¶â<»÷J=ªÎ¾x?œ½ÞÜ ?ou?¾o� >ÂÚ.>¨Ó4¾HÑÝ=ÎWX= øÈ¼|Û¬=ð…ä½î͉½šŒ6=ðý¢¾ Wཿ R¾‹›·¾ Gu¾‹õýê'ü¾ç“^¾-»>\'¾Vú¥>°,a>Ì3b=Xýß>ó@�=fäv<&=ø8¾öM¾þ­[=¼>¸H)=‹ ‘>?î”>—[o¾·-O?|µÌ¼‘O<לּsÿÙ½C_½Çþ�6>Vޤ¾9Z¤= h%>û‰^G;j±!=ú�>§°£¾>ç½à¶2½«åÈ>˜Q.=å¾¾Põ}½ì‹1=•­�>0¤z½Pp¾Çä¾1Ò<=¼yL>’€‘¾G²¾|8=6Üj>„ë\½¢dò=ÜÔ=ó›?¬½–¾º$é½Ð C=«‡l>Z©%=å"½#zH>i¬=¾øA¾Û ¾ÅI+¾¼¡Œ½mÔ=[ô~½ÐA>ÔŸ†¾EäË=1m�>Ƀ±½FÕû=#�ϽºM&½Ù=ÂÒ:ß3o½+ó >2´¿=±q¾bÁ >I¬ù�Œ@>ßÌ">ý™d¾¢Ç¡¾ÚQ°>DKq¾®_�¾°®>¾?0 > Ø»¼õ¼‘^G½;†l=à:Ö§W>Æñb=RE¼©8<†=Pv,>5nã½*M—¾ÒY•>_Bͺ¹X>Ö ƒ=`©>�“B>Ê׋>= ±>L¾0�¥½ãé�=ےྠ²¦»¨�¾ÅäÉ<ê;ƾ•ùM¾DÌï¼€›Ó>à 彯žl>‘Þ ¾´‡Ç¾ ¶@¾¿À1¾'{>Òˆ¿Nj¾š;½‰³N¾\› ½K&—½kB>µ9F»)¡t>¶ £»rð%>½�Ú½�< >ÿP>¾f>“N » E,¾»E™½Ú»-¼œÇ¡½Wå|½ð=?q׿0«½â·¾´ ³¾V·_¾Îü˜>�Ôß=3&}¾§�=½hZM¾$g_>?ša=yš¼�̾p¦¾ˆS =©Úk=gî½b2=u  =[ŒE<¯<¹¾þŒ/>fy¾ªÑ¾›O-½y½"Ú)¾µ2¾ä${>k•½ó�è½âÅ ¾õ'½†>Q°>*4/¾N+½Ù4qt½>B>¯D@¾Ýž ¼És½{Ú£¾å+±½*û†>ló&½^PZ¼Á½Ì½ÀÒð=Þ7ľ ¶�¼[XO¾jfì=i/k=Œ;\=kãê½°wk¾²¾->ž‘T¼þö:<‘_À<Ù Ñ=ŒmÙ=$v>®NÛ»äÔ>윅½ªÏg>Ž|X¾UúÆ<‰Ä°>~»?> 9þïçß>=öU™¾L½¼ä¾É¾tÔÀ=ñís¾÷œH>!„´=;•C½ÿ >ø~¼¾+н ¾Œ¿½À>ã=pØ�¾#+¼Iü$¾\ ¾ gQ>¦mÿ=¢^O¾™´>õP>–>ÃR ¾Ï5±½HÖ—½éÎÅ>’Ñ»‡p�>ó ½C”D=‹²=åYþ½(Ÿ>Q ½bg.>þO¾¿+³=ÒHͽ  ¿ü!Â>,ؾ.i!½(ºo½QE…¼rе½î&å¾rw’>8q8½b==þ¿n>0ûνò©è>šY5¾â°¾ÝÀ½ r">‰&A>J “¾5À›½I¢!¾C/£º²¾ì=•Ž>hm>RE¼ü“´=ªöƒ¾æ=Ó=‡v>nF¶¾åÕ²½ `]¾O‘ï="¥6¾ï‚s=*ƒ>�Ç™¾cdt½Ä}—½¯`$¾s¤L>üY�¾•/>=�'ֽʿ· ½áY¾gµL>Á5‰¾¨q»=©÷J=xÓ„>l3n½f‚W¾–-¥>Üðh>øx€¾%øþ¾¸.">ù‡*=òì½¶–¦¾ ŽÚ=ž¸;ÉL¾rg›¾¾n½Ö=Û½rz¨=3(—¾üèó=þ‹.>-;¾DÙ=%B=r–½¤8ç¾f•Õ½£Ö=$‡“¾P6�=wð½àÂ=¾½´„>@­1½qÙd=vC=Tp2½òfD¾µ¢Ú¾ÅúŒ>ãùt>`TC>RŒÔ=†f_>Ë g¾W >„çL> wN¾9 ?2™z=aЙ¾ÎÏý¼¸î�½%|Û=çò½‡\ã¾¾ßk=ÖÛ<Ó>v¾ª=*mÕ¾Õçe¾PdL=ˆ›¢½\uö>*f2>ÍzU¾l¡»tÞâ¾»6®>Ø•= ,Î;Tg¾¥�ƾ?h!¾|…þuùã=¸çÖ>öL=u±Ë>e9l>>ë=¡Ú•½6oý=M�q>vc >Š�q=‚¼•=–ç'¾¾˜¾‡­•¾Ò„Y¾o\¾Àž ¾híz>rt>Y6]=ØgT½ë½$õŸ½(}¾›?¤=P�;½?Z§½¨i>µˆ›¾ßËô¼h±=�E>¿l;¤?I¾—¡½¼”q˼úr2>Tâ–=ñÙD>u3 >"rýN6†=å<¾‘0X¾'¦¸¾J%¾hƉ¾îÛ¥¾m+>�—>•i²¾e�>§æ”>²É�=Zÿ¾(—‚¾Öêå=Ÿ�½=ÌKý½[ò<-0¾®9#¾ß‰½¨�ì½ÑN ½1Ä…½‚Ü>&ÑÚ½v+>®Uº¾âGA;¸¶š>Y/|½Ìê=¾-¾ö/<>ÂWí½a’A>רè;<=¹ïÿ=¥ >†ñ¾˜xF¾Ç¿ùP<=gFx>×o]¾–²=� ç=Åw=«0»Gw>> åW>ñJ>x¾ :‰¾A„@¾rŒk¾ö=;� O¾Ú—Ë=þ&= ò ½•õ[=ô.˜=¦º¹½àV$¾âœö=0{)>šg’°J)½ì¹Ú½¯á»Ó­¯»G+¢=÷€Í½ºéѾ— �¾¿ô¾”ºô½ç6Ì>ìN>�(ú=tåó¾½l>뇪»a>½mÔV>^8v>úÜ=ÎÔ½öB$¾(’>ᆬ>0q«½n”ë½j,•½°, >”Êý=Iw¢=;§ƒ¾}1,>XÚ½�í*½…‹ž¾úº³>qP·<^‘'¾° ƒ½Y—i¾ 4 ¿†2sÏU½>ŒSd>uê;©’=Ô¹H= }6¼B´½«½ó ¾ Äe=Pv¹>Ï< ¾z-ͽ±@=Áqä½"›½Åïÿ<ûVf>Bö*>�E?z6?µ^{>S¹[¾žnb=}]¾álk>ñ�;iœ½F‚>uŒô½!B•¾ÓÆ'¾!•¾*2=4%>~¤¾‹Ÿ½£ZK¼…Ï׺Jý>Ñ©¾æc¡=¼´>>�³¾ÇA ¾ÈÛP>w <×—n>Y¿¼ ÍL>²¡½Œ$½²†®<3™½0²>•½Ô>k2¾#6>¢Ú‡>û†={ç§¼qY?žTó¼ŸÇ5¾ô˜>W*„¼tæ‡=CdȾ–|¸¼Ì'Þ¾yýa¾pñ$¼c%þ<+Ê×½TB¾HX¾»®Ù>‰Œ½-3>…ô¢¾Uù½íñ“>ÈãÎ<úù¥=&ô¥>ˆÜ`¾W,>ò»à½ 3<>¼©°½ç¢>rg¯½Tú ½…ýR¾ƒÎÍ=•½�>o¯™¼{þ¯=ÜJž?�¼ÐœÙeý$š;ÌZ‰¾’ã¾?ª>±úó½­B´>`{'¾ç+µ>K{p>Þ¾X½Ÿ¸ý=!ò>P¯³¾#¦¸¾Ÿ?‰:Ó¾˜*-=^�³¾*Ã">[<þÔò=e–>b›�>^?p.ö½M`½ÜÑ>‰ëƒ>ç>SR§>(�Ñ<{zW>wn>ÛÝW ,­>¥:Ý=(„=¡°½âªš=ªì=A͇½’ ¿¾/£®>o9»>×€.>\Ö&>Uzƒ¾M³¾.ïϽv¾ >ìl¾€!“½!3={Òž>J,>½n ½7¥<]L—=âB޾Êp¢=lJ~>ØÓ½�zr¾U>>[&½<žÜ=%³N=ŽÏr¼Lå�>�M…¾þ×)¾{Ä<>4ÐÑ>ƒó0¾õ)>Jc¬¾˜&Ù¼+¥?”>5C =n/=¨†o=î.�>vgÒ¾XØz= L>_¾l=â¾Â­‹>1%Ù=¸2–=½ì¾Ï ½‰Þz¾Ó _>5Áõ¾~;!¾© e>E>;ܦ¾Å]/¾^3ë½²¢C>õ—Š>Èÿ=>}t >›§^=šóô½�B;>`•œ>OWœ¼X5M½dªœ¾–¡O½2 N¾®O3¾Å80¾dX¾?>S–>{Ÿ�>eøÀ½†‘½*’°>?Ó½œ®�>�¦¯=¸3È>™à½à|Hž†<È&Ÿ=Qÿ_f‰¾á>¼Ï{“¾Fkl½õz >±—a¾ººÅ=Ì”I>績×ð6¾¿i©¼4w%=`Ç`>] 9=J•>X•½6ß3>ˆ�€½­Q¾Ü»’½’V�>Ñ:®Œ>Ík+;¿:«¾ðî8½¯f‰>åüæ=ÞKw¼ee…<¯K¾† ¨¾ˆSs¼C<&½|^¹½Að•>r­´=âü>œ5¾¨wê½E‹=áÒ”=åŽ;Ái7¾©jˆ>Þö†½içĽɋ4>Z€T>¾ÈS•¾MaÄ=ÔÕ¿=©l½¿¾íWx¾²Ò÷¼¨n>’•½‹¾>ÄΊ¾øÌоd'Y>Ýf±>¹�>(É> =ò2?h„¾‡`P=à¡G=ð•þ<Ö÷Ò= [—>i:;ûŠv>£…˜=×B½«`¾ 3J½Q᥼¼X®½I¼=ƒ*ˆ>z£¡=§�>n^P>úõ­½6-ô=‰ÿt¾Í¶i>ÃÚþ>2»‚¼µ£>¯¯ž¾Æí=Ê3ƒ¾Èޱ¾€âÌ>2&¾´î@½«D!=Óƒ½ª’?y�>ôáÇ=°½=/>¦Ö>¾’™ ½F°Œ¾@Ó±¾<N>ƒ…½5ëî=ñÁý>{Ã>¯ §=C¨–¼²“ö½:¹È=ç1ϽY·„>m›> ¿)™¾7zÎ=¢%Ù¼iv>Þj;= Z=Á #¾Ö¤>°ƒ½ÅÖ|¼ŽÐ™>W›†>³º¾©Z­>’‰Ø>¸L@?á2Ñ%>raœ»<ñ,?™2Ó¾þùœ=oWå>Šÿ_¾ÆM½Ï ½[t½æ²½¥|²>ÌG>g×'½Kr½(n¦¾‰HI¾ÒÖ½®­S½�å¾=ÒfV¾q- >ß­¾:F`¾Pö¼½‹ðX¼æ=Þ(=áÆç½a¸¾WÐÏ:8=ÞØù¾œ~#½œ¹®>{‡ý>|"B¾Ò⢾$‘->· <•’�½\Ë=I–E=¥±¾¿™i>2é½*¹‚¾[›8=¿ËM¼ë=;>fÞÄ= !‘>V'–¾ð" ½ ø°û꾿}'½îp¼'­l=”Ò¿½g€\=ÔF!»þ ø¼¨]¨ƒ >g·U¾¦¾õ5}¾âèÞ½ÏëÌ=6ß¾ås¾”"=Q„?A$>ç… ¾Á#Î=X6¿=ÖJ°>}Ÿw¾ 9¾¯œ:>‘¬‰¾79‚¾öª�½Ä&=}ä½%¾Òz>@�µ½ú„н»ß6>÷,À½ü‘­>Ø™d¼ÁRŽ>“^Ý=�dU¾GÅÀ¾ok�>C¼\&æ=“Ì>¿ ¾7h>ð;’>о9ø¿:Ï£¾îa>14º=u“Ì=6¶½¾í¥Ò>‡Ã¼!<Û=\>Æ,½)ãê>ßúѽ.Ĭ¾7¼#>^¸e¼Òž(¾˜Ž>ôÁP>¢Ê漡ä¿}e;�°>Ì,ñ=÷x€=o‡ø¾ñ+Ü<Ùðª>¸-¦½(·½<íÕ¾¾„¾c›z¾�R�>ξ�¾à ¾þ–¿¼1j>%[?�u.¼½$ÿ½ƒ�n=òêl½'µ,¾KU9>>Z˜>ìàH>ˆ±¯=Éa¿ä!¾Šx¾½ˆ„>Ì0>ö»Z½8Cö=O³E>)Uº=}ÿˆ½�U>uJ�=Fn/¾´»"<“â°½ða,>�¥<=+cÎ>ì1š¾Ï°“½Õ4Ê>lY$>ˆšI=þ>¸ªý½Ü,?;®Ÿ½ÈA¼Ä¼O¥¾4D@>‡LI¾›ú<Äd¾7úí½N�`>?‹B¾H¢–>ÐQ–¾¸ê¾V™>IbÞ¾ù6 ?­x7>LP¢=õ¾tD>¬å¾*~S½s8뾂f¶>ô 7¾wr}>B<>ɰŠ;—´¾Ìi>Ÿæ ¾@>¯ ¾£PO¾úͼÚo!>°©‡½ól¾r¥•¾,ú|>.cL>^“�¾�%Z¾–‘>à×¢=ˆ|œ=È2¾û½Î½~¶>³}Á>Bç!¼ŠXß=·ß%>¦0œ¾“ç ¾vZT½ E> û<^'‘½œ=��„¾:S¼Û¥¾¾ž‚�<4¬™>ƒ‹°¼]/#>c¡½<—Þ>Æ®¾�@¾ ¯O¾Óß¼ûñ޽øU¼/ƶ½Ä~7=ëO>Ƚ½»ö>K>,Úl½';‘¾…饽âjˆ=€¬½kf->Cƒ¥½Ž>'>?:¤½±ÖU>«ûš=Íš¾T¾=%"D¾$åè=úû’=5ì¾.H°> á�¾ä^ê=QñÐ<$ ·;e=6>ÕÄ^>äÌì>0C$>•‰=qs=&HJ>Ô.¾Px˾Kk¾qŽ ¾Á›5<‚ÿþ<ú�¾@On¾a ©>m.p½�ìI=!“©>âô|>H“¾t1”=)‡#>^™ù=&u>Z¨o>�-ú=m,¾Ÿ,ª¾H>a½Èžƒ>~¨x½ /!>³§®>’ß‹¾Ã§N¾ÌΤ=$ð¼ TÃ=Í{’>‘¦ô½1óܾèÓ•>áó¹>¥×B½½9B> ª½s¾Ê <‘-·=‡‘#¾ùÊ>!"ˆ=Õˆ>¾JA3= èѽÓt=ߨ½K˜Ç½#š·½CÿÜ=âZ½Æ#—>âó=&à˜=T5J¼¼ »Ùz!½PÚ‡¾~1D¾Ã†ß;Ô¸µ½nçÐ>b¨Î½Çx»¾<•?ºÃjP¾rX>iw3>H«8½�9¼©�­½ŽØ=jH ?ƒ2>­w¥½ØÝ=S¹>6½‡k=e³�¾{[޽|Âd¾uÖŠ¾É!?¥¥3>3Ö½1%¿´r<4x)¾´K=>‰ß@> ¬�>ã=¾˜O¦¾°L¾oD…¾š¹A½iÇߺÙoý½œ>ðñ½Ó<ée+>À!½­Ê‡¾ ɾÂë,>¶[Ľ×c…> ºã½ç'½mÔ>Žõà»'ê >w`L>ìp>(c1¾ä±>"J€>*eÙ¼¬…¾™ Õ½ÂÀ=)!Þ=°¤¾\Oh>FYß<»k˜¾M¹ç=tpR>¬Üš;|¥ª>ü\>XBh¾F¹=¹%B½@Ê >µJŽªþ<> ݾ ß=Äiq={™ >4\D¾Y¯½×‹=dÆ>kL¾á×>x>>æJƒ=ˆ,â½äwÕ¾^´e¾©zÿ="»=9­¾c—6<þ=zpJ>XB#½Nbt¾ÀÞ5¾SX1¾@—¿&l™>'-ž>‰Ð¾>O=�pò=«62> ¤K¾Q†û=X¾ºY>,ãî=}|] Ÿv¾nsƒ¾d ¾›±=A“£¾e ¾D\C>N{½½¤‡º= ¾Ž>Y÷<½�œÀ¾ f…>³±Î½2 ͽ;×�¾(Õ½ŠCá½+7¾íúþ¾šÑ<ó`k>…èð¼Óe˜¾VA¾ Ôü=ôò>Wi¾Á³š¾d ¾ðT=ÿK½s“¾)<;>(¬P>’g¬>F(˜½bè:ÄP«½#¾'={‚ =x§9ËvV;ÇÐͼÈ넾�ä<Êtø½bÐ[>GŸ¾†ö >æk>8z«¼$í=�Hç¾·†¾ z»¾$]=ŠÙ0¾wC½Šœï=€…ð>ߎÃ=E?&à?>Í2d>u¢¾ËúD>Ô©ô½pò=—œ¾óf*=ÿ(ó<²=”¾hÓ“> ºt=¼Œƒ¾05õ½–»­¾†"®>42ã<-Q`¾ß¡’=á =“J6¼Ø4=½ì�>†?žF_=G)_>š“=¾a­>Æo”=�2¾ÍbL>bm¾@Ÿ½yÊ\¼f³¾:ÞV¾QW8<O¾]˜>z£T¾ŒË2=·Í1>­(¸>-àë¼|8¾Ì"¾ÉÝò½`ü®½å^÷½­5t½T䡾I_¸=æf½\[²=�˜²=2ù½>— ©¾-w>ÄVž¾±Ìº¼Íš–=tÜÎ>¾ŒÒ>¯ô£>aŽÊ>iW½ÃF+¿ŸÃ±¾èÌf=œ§q¾ÔÛ½²ð‡½X<>Δ­½-I>ìše¾Ôï½»3ü5¾Ý�>èÐÀ¾/óZ=ËýL¾Ã">åá´¾ýÓ¾`.²>ÿl¼´w¡½¹K¾Å²&¾“é>H\½�<½J ú½]3ü¼Õj3=Òˆ ¾G´¤½Ö-­=þÑÅ=øØõ½Ÿ ¾‰°³>°¾ö³Þ=’&¼ÑÃE½ðêb<šu>½R¸V> X>¤»„R‚=ïªÀ<¸½—�<ꎘ¼Í>Q™|==8ì=qþŠ>,.£=ô¿˜½ý´=tž >xn¾à)>”ŽQ=¿lœ½F<>Þ+£>†ˆ>d[ž=j¹(?¤c¥>¶ås>š+>ˆÇñ=PG�>ÀÔ¡¼ìê½+²=V�>ûï´¼ƒwÎ=àq«=�U ¾ -˜=uî=Ûj>Û½°ü%>~R¾Ìs¼íÎ>ÞÊ�>Æ‘>Qy‡½ÚË�=’~d½ß™©½Rœ>½ò<Í£X¾KAr¾‹í ¾./¾­¥¾`¬[> f–=«I4>[݉=—X¾zO<캾ãÁÑ½ê¡ =7cç¾cV'>² =ú¹½‚«ø=7œ·<×:>wÖ‡>†ªÈ¾ƒ,�¼)Ì>©×ɽ€»½(�a>z6æ>„¶ƒ½S¤¾²¨>ζ¾VZ«>–¨ ½À¢¾9¿´>.;Ô>ç÷¸=ãwp=£¿r>ù}¾LÇ2¾µ”>ú[v¾à•Ô½qW>½·Yq¼H~Š>¶:…=Þ| ½i‘�½=Xƽp„¾E¯ž=Ê`>J`«;{m>”�»<æH8=åè8¾Y¤æ=û=ú0ù>^}|> !¾C¼=ÎGÞ½Wnz¾šb»¼©ån>AW¶=ƒ¬=*¸·=‡Ž¡½ê?–½T- >{Ìù= &h=>0F>mþ=·<¾Çq§¾u}j¾kWB=v§¦<¡w*¾IRÑ<¥½f½\¤6¼$ ¥=…ãH=MØ–>Ș¾U$ï½µ‹ >‘ *¾P}‚½ßpϾ «>üQͼ² �>.£…½:…>Ñ:5>ˆæ!=¯³=™¦¾8‘}<)‡>B‚7¾&¡S>Ë?L¾ò³> ïZ¼ÒåM¾×Óè>Ëž̋{>LJ>å½QC¿"™Þ¾ÍÜ»IÕü=wh)= EÕ=�®�>›è±¼*ÙT>s” >J=¾÷cǽk=]%Š»b­?` @<½$:¾ä%½ýÅš>XÏ¡>ŸÅ1>—š½¥ ='8D=—mD¾s/®=à.>È‚ >( ¸<Ç/Æ=¶O>¶w ¾´¨½÷{>¥0›¾‘ǽéÆ7¾÷T‹½ÎøŒ¼ Ñß½÷Èü½`ø>¾&Š>osô<¬][=õ4=>É<6 ‘>Ò®d=†ÈÛ¼·j¶>èáo¼6³½XƽyÍ�>«eÔ¾—�;:äD?´˜'¾æ©>ò ¨=Ùɉ½ðäxp¼q¼µ+¾Î@�>8·X¾e ¥¾­¾Ó#K>Õrx>-b>(ª>–ff>uß»\v¿<Ç™‘=„ä´=+,:¾7)Õ=Ôw¨=ãGW¾´‚»©ä,>ュ=‡kn>G ?È�¾€5¾oÏ=¼À[”Ò½¾À>>¯´·>s ø½æ#[½çK�¾½\P>ï‡6>»3i=¨¢½Öv®>÷=±>é Å=îq=žçs;^}“»4›€½èõ ¾Ò&,¾ÄZ‡='nÓ=´0>Λí=jÿó=x«ˆ½Ã+¾ÍCG¾=¼õ<ÇdÜ>‰ö¾ ü¾á5e¼>ü¶>î#‚½»ûŸ=ÀÅê>û4Q½ïËA>�…£=ÕZ"½•’ ½Õg=s·ºáÄ­½¼H‹>ò¦I¾ËˆP> y”½ÆY`½ô †<…v>à ‡=^pO¾Xe=$‰>7—>Qvͽ� ¿½*"¾}9«>+È=Ì\I¾±Þ>55e>ÍÞÉ=áÁ#>±Ù>L(Ô>}|S>«©÷=,Ë=%V‡¾‚{<©r <Ò¬=åUù¾50›=BYP»Á‘ÒÛ‡½éS>˜¥®>XƒÞ»ýËz>ÏíÀ>ªó³½Ãïå<,Ü=>s1º¾UoT>g¯ç=3¯=4±·=]:=ƒÕ©>O4¾.•ð½ä·½lY‚¾&u<>¬{ä<\²Ë<2G¾¦}D>Ò§k>¢:Ñ=$K‰½~ÌŸ¾Áõ0½¦ˆ¾§]œ>Bñ•=L©b¾rþ½2™r½8J‚½�"> òN¾‡¯�½BeË»u}ν-Ó?€ãž=È×—>ê�¬½¿?>1-¾_†M=Íñ ½šïH¾2‰©>ëK½ÓJ¾žŠŒ>à#5>‚ú‰<¦n©>—K@>¸½˜é„>†ÜY> +=¾çx;< @–½UÖ >�ŸW¾O&D>�·®½ý-§>pgê¾A•¾ÈK> Øq¼’%|¾K|¾Û8é½ A²=s«½\ˆ= é~>Îjï¾1A¸¾»“¾œå˜>¾cM>¿R¾æ,> *™¾mz©½Ý~5;²á¾k«ë<¡}W>.𻽠L¢½u†H<ý8¶<Û¤ ¾ù^¾ÄR->.‹>}’`¾>¹õ¾®d¡=Ì`o½Ph¦¾“´>>�Ã3¾AQؾ”o-½kº<›be¾a’±¾?ö>AHH=^±w>ìZ3=Wfö;ÉŽô=1ý>Ç‹ä½�N‹=ÒòľW|(¾ÃÇ >9y¾@ll½>£>4Ê?¯ ¾ùÈH¾�ËŽ>’{%>�þf>�na>AC^º/}Á¾TN ¾£Ü½òØÂ>òŸ½Üv»“q)>Ë©�=œÏ½ß6<„¦ª¾ã•c>N7¿þè>JM¾ C‚<úœ>-p<‡W‘ÃÏX½•L‡=§è >Ö‹‘=vÏÂ<+ãÀ½��÷<© U>ĉI¾åT½½d ú=|Ș>%˜=«"z½ˆ{>È[>ÐM…¾‘2½ÃÂ= `¼Ê $½•é–¾Ñ÷¿ _ô<�ð„>¦€=4»ü½~­ë½‚Ü#½„òð=§*A½Î#ž½ã±Û= 4ؽ˜�%½’ ¾)N½[*¨>sB^>5�¾)½¢<ÉéV>£Åµ¾�þ«½@`3>ÉÄ^¾YO>J ™=İ2={Ç?/mÔ=«HV½àƒ>ce¼Tš>Rk¤¾ø;³Hܼ‚^>øå¡½¥í½ˆý¼=J®¾c>m�¯½P¯,>zȾ]“¼= U(¾<¶½Ò‚�=}¯)¾ÆYá< F<¾¼}…½BÞ>)xû=Mé=¹‚U½L°Ó½}× >>³>�ɹ=—Q²½ðYú»î[>‘;e¾-ì ¾lßø>€«½�¯Ö¼.4„=Ûʼ½„˾R‘н»…®=$#S¼4b-=ý)Š=3‚y<Ê¡`>±úľ™… =¸t£>‚ú³=gqÜ»/¾ª€>æ�²¾¶˜m¾Ð/¾½Üˆ>{B ¾Óœj½I( >c§ý½€™†>'Ѥ¼Ž“´½®YŸ>Þìà¾Ñ”Š=SÚ‡¾è=žxs>�[€=Äó>_Ñk=åY >²`>bõ>_eš;³Áû=Ãü•¾h½QÒQ>3àz>ëùV>õŸ>ƒ—Í>¹Bß>Ll޾y“Î>¥u>ƒ¨Õ/<]¾�Û=IFV>±’>oè•>ìD¾gÓî½õ™4;ÄŽä>·Pù½Àä>™%>J>Ë´Œ»ÖO¤¾‹Ô>`z9>ݯS>%>»=ö`>:Êb=._Ÿ>üß1>%å+¾ï¾žï¾€•×½ø6Ã>˜f >£EK»-ØŽ>JFæ½îQ7½UŽ£¾E#»RkJ; §>× ¾§”¾²å>[Ò½ÊÓ…>bB¾—¢é½ŽúȾ4/ž><åu9³Ž=R[½¾èôE>à˾•êl=Kèü¼Ef½þçŒêèJ<)ZE¾veÆ<@¹*¾çÖ‰=ÿí¼¨5¨t>Yñ>'£®>Ú0[¾¬¬N½T®ºŽ}´>ÐE¢¾Ú1Í>)¹ß¼¨þñ<™Ûº>"Ï!»ÉŽÕ=ÎÜk¾óHË>Sè/>í¯�½âpa¾&9Ú=¡¾½Ð>uT­>Çh¾o!¾é1�½”Dí=�½þ;dž>ÿÂØ½¸As=²Õ†¾ð >6ÉH¾VK6>¡ÌÚ½Nw�½ä.>kȾk�U¾$ØÆ=|“¾mQ¸=kEü=Îpë¾]Ý'>…Dv¾Äh¼½iý!¾fÎ=>\X—>í$>;E4¾ŒWö=ýØÚ=ó%“¾˜½=�÷†¾ è ¾tQɽ œn>Å$¸;Ë—�>\Ò>ø€:½’çvH/½ÔЬ>ÖÛ9¼¹é£¾Ÿ7L¾0ß)¾ÇØ>lp˽~Ћ¾®›ù¾i/d> L¼>¡´;¼Ï ¾ïôŸ=(à¾ëº‰=?GI¾~ú=Íÿ=Ý€ ¾š«ž½“©Ç>|PS=>móÛ=.;о±ãN>Þ)>Úr¼¼�)N¾(õ¼j»=mH>5´¿9‚<úF¾(Pœ½áÊí¾Zg<Ÿƒé½0­¾ÁÔ·>íŒà<3W¦¾½v¾Çp¢½¥½¾à>Iìü> _¾É–m¾ÞˆU>+¿Œ<¿é•½eŒ>ˆ%¾Š»<½-0-<Ô&Ã>ž®%>îÓF>ѱƒ>†ðоåÙ�½T½HǾ9~Á½ÉƒK>©½¾¸$¾ÞÔ¾KüY¾ŽÂÓ<žé¤>òÉæ=¦ì¾… >}å ¾îZ>_Bc=¨€Ÿ¼ÑÐS¾¼Au>Ẕ=õ”\½ù¾âë¾f ¶½™þ§¾+žÂ½‹™¨>X>¢2@¾Þð=j|å¾.ŠŠ¼Ã® ¾Zc>¦²&> 1˜¾ͼ=©_¾”ù¶¼ŸcZ¾×›Y=¦á^¾Ì[¾¾B>ÀMr>VbV>|Ÿ>>e>¬0v¾–‹v>*ùr¾öeN¾£Õß½èôƒ=‚ †<ßo¾ ˜*>ˆˆ>á3>,°½³Ó>Ä¡=-¾ÿ=WÝ–¾�ε½²ÃÚ½U a½tÕ<¾ ]¾ïZ{¾MÏñ¼Ëšn>Ìc>Ð|>AŸµ>‡:†½Èg•¾Jvå;.DD¾–Œ>“ܽ«öæ<v|<þ„I=ø.‹¾Ižq½”TƼK‡»@k*>YAà½Á›T= Qú½ b¾éŽ<§Ø>RH ½±L‰¾Æžã¼´f—>æ ¾Ù $¼Öù=–‹=¬aV¾Ù#M½V$¼¾·a‰>¨:¦>/³³>x>Ÿl‹¾pà=· ¼;yµ¿ñR½‚Ñs>üD>¿úO¾Š—ȾÍI˽ÊîV¼…>‡°½t¾ì<º…H=䮼¡W¨½˜q¾�B�=<¬Ž>Gâ1=½ûX½�/"½’­>ÿš¡¼ˆ—=‚7½!\?ØHG=E9„:Mp.=\Ã<&–H¾‘µÒ¾0­“¾ÈiR½{ ¾]z+>N×>O‹ø=�u>/öû=/7'= c!=ĸ=·T¼½p¾ÍäŒ=ˆr·>@žÜ½JOú= L�=Ææ�:o-Z>å�U¾~ªÐ½g‘š¾U%½¢Ï‡¼¨]…¼ˆÅN=ÕÀ´><Œ>¯Ó ¼Ü§?ï'•<Íãg> å½ô>^{=<@ É=CÓ??ý½‹`<½Ùd)¾ûö\>èwš>À‡c>ݵ ½Á·•=¡nW¾ä' ¾;>Q>›,>÷>Þ4—½ßߢ=�z½eÎ>ˆeÇ=¦�¾›f”>U»”>~à>�—;¿“ Ò=gšÄ>ƒÇã½@B ¾_-Ã="°U¾Q„=Ì´q¾ãWþ»”Jß¾Å2Z>#ÑÂ=¿">è26=A–á½»Ž ¾�7>4ÿ÷¼òÐ=˜J’>h]å¾§è¼ðx­�ŠG>wGµ=„抽CÒU> ™“½uý†¾=Âê=d>X²½9*z>WAä¼îhq¾c #¾©* >”&¾H;é=ÐÛž=—¾½÷d>®Ÿ±>’8¾Á¶>*óp½§<­7Ó½z‘ ½=M…¾b>Šøþ½ß€¾}+û»jXC>ÝFM½>B‹½ýë¡=%±÷=0þš½ôÊa=©ßý¼1g1>¢6 ¾ÞvÕ=“«°=‹ ¾Wy¬½C¾8½ýQ ¾Ífe>1Œ>–gV>lD‘=f >’¡ý½ä£!¾>¨–=¬‰”=Rƾ>|;§>!ªë=î8_>˜›ºÁÀ=¹_<‘úã>Þ[<|ž³½¸í¾ŒV½èj >Ç=µ8q½CÈ>À”ѽ^Þï»ý5¾sn½¡Êû½iÂþ=›¡î½ýÀ(½ÙÌ=�\ >me=üé:¾Ál„=§E#¾3û­¾ä‘¾‚™P¾V¶L>ó–>S&Ü>säÖ>�€=0±ó<Åá½êcø¾sÉ=QB>ÓÀ3>Ö:‹¾ï�¾.úݽ³ük>ˆ=~>häl>ª=@Æ^½qj‘¾Ñͽ¤˜¾´°ë=zÉ<Ë“>CQS¾ÇXb¼ög„>š%¼’€Q=:O¾ˆî;=–+¾Ñ³~> ­¾Ê”a>O÷Ľ|a/>4è8><Àã=”œï=AÎÛ;ô9€¾\_?=‰´4¾» =zÃk¾! ÷>Ö9¯=É»'<½õC=)•F< Ö¼>æ8š¾¾O¾,D¾ þ<>ðj�>;–=šT²½Ü3>n¨ñ½¯®¾¥7€¾¨Yf½*A>à�1½§,¾¡uv½Kc>l8\>ÅÞ2¾?ÕÙ¾Ëd>Æ©==€L ¾ò €=É̇¼a~$¾ õi½ÞP½]ëÄ>5t\>W8X½3O>fcν¡…7=° ³=ß@Þ½p’¼ v¾s¾ÇŸ¾9ñ,=ñÈ=aŸh>!Nä½ÄV0½¯Md;¦½¶²•>m=*娾~ÜÈ»Ì7“>)ô>­co>—£½Sm=qUé=ºcÐ>‡Ï�>£:&>ÓÄ›¾ÞS�>ÿÐë½U¶»:ðØ>jv¹¾§-G½š/õ=eZ>êT?½ ›§>™Ü!¾(<„>z>¬P­¾ˆŒ½õBœ=ŸîY=9µ=”îÐ=•E¾þfM¾< ¾’Ò6=l,¾Lî¼ ž=ÿŒ»Æs£½¶q =;E>«ÔY¾7_…=‹±Œ¼VžM=ðæ>£Úº˜B©¾k™Ý¡¾‹b[¾p>™>ã93>yy>¶ªF¾ySÙ½Ó w¾ Zl¾�F>Ÿ© ¾"Ÿã¾úê_¾Ý™=¾ìÏp=04”¾×‹�¾Ž�äº6Š]>ð0£=ØßþM¬(¾š…c¾ml–½†8;>rjå»y'¼\ï€>}ÓÁ:‡x¾Kà$¾8ØY»iH8¾¼Ý>&Ù6¾›w—¾0­f<®Í¨½nF¹½o1’>¢Ÿ¾ ¸U<¦Ùž=ÃPn¾f:Þ¾GŠš=-7:>Ÿêc> ÷> O“¾ëô=ÞDs>™fÆ>Q‹ì=E_Á½ßvL=�¡ >9“»¾zðD¾¾ ½¶J>šá ½Œo=>h�¼[ì,¾*¹>Ã\’¾.‚Å=Xª¾Ø±ð=I†Ð½T¤ =?½Ê¢>b¦¾Gm$>;>(§�=İ–>cÕ£>óïi=‚œ«>y¶Ó=즋>åß=_¼ç¾§F¾îk>„b½=tåE>îz¼xر¾-Òœ¾&Ð=vÎ=Æ0>ïh¾ˆÄ޾1Ü�¾òë ½Íë>äjê=,;¡½©!Ê=…‘¾ ƈ=u÷/¾Šõ¤½$v>Ìà%¾Yʼ8¾û.>´V‘=8Ç•=ž^M¾ä×Ò½Ùg¦=iAмŸgB>;i‹¾lW¾–#¶=¸Ü&¿GDŸ½œñ<™m?¾žBß¾ÚÐý=¾_8>ÍÐU>G¥è=°'ü¼02<Ó²&Ç=f”™¼eT¬=-£§>L7¾Gƒ>~·z=‰¾ ¿¡½æM+>½�±=•Žò;ºæŠ½˜A¦½Éº6½¦é÷½=Ã>¾œœš>šèæ>óåB=jH¤>[‚4>Ã¥�=/ T»sB|½D%X¾µ>à—&½%É‹¾ÊÞμ�^ú>uD)½Ñ ¥¾5¦Í¼\ïA¼µ{>»sž½^w<>çaD>OÔ’>i8'½ «9¾bP�½œKù½N“½ Ãê=D�i>�È>r\ß>ßv>Šû>–ML=G³¾‡8¾6x-½.ã5>pu¾ýpí½†ôʼܖ¥>H,)¾æ‰¾gn„>`ÌŽ>Þœ¾o±3<ïí{>“dM=ÃÚƒ¾Ù\>¾�FF½Ž»¾†×9>“‹"= �ù=[Ñ8>BÖÉ=«>öÃK>>a~=‡v=çoU¾1ÅZ>qç>˜Ç§>cÝ‚¾ð:¥=é%>‰0³»|†€½�ýÿ¾³¦>6�©½Œ ½¼ä0¾-ÅØ¾îB!¾ï_>Zwß>“E–>¿¤½êtލßO=AÈ/>wsB¾½½H�W¼sˆ·>¬ºZ¾Åˆ>ˆ_¾uü´<÷øA½O¨>`$ü½RÀI=–åx½cR">nŽJ>»ì¾¾Åα>{6†=T ¾MPÔ¼]¦=ÔȽýn�>Å®™»Û[½Âؼû0 ¾·ž’¾±ïоO ­:Œß:>AW¾ B¾)€=p,>aQ꽑»qɾ(s>`ǾA�=.ù—¾¤> #F½šX§<·xY¾€Ll=îaJ>2¾½T¾ò#‹<7âí¼áÏ*½ºôe=±Ž¾ú6^=ZÕž>›Ü>ªÒÅ<ª– >�…–>pA/¾—ž; 9�=ÀËö¾^×È>Fäâ=0 >È>olÃ<$g¼>Å|Ö½Úu¾Ã³:½ÄEã>HA>ŒG¶=9·>e±§=vD»Ös{½ŽË·Y+>¶¨½Ô¸ª½m#J>�Ô,óÝ=¯R¾|´)¾š‡>»z@¾·Ù¶>YLû¼þBȾ]ë„>ØNµ>~Ô> �=Ôˆ¾ÙMF¾À›S¾Ï >³º¸=CÖE½–^‡½‰ÚA¾Gcƒ=“¾{Ò·<Æcd¾�ê=HÙL¾Õö’>-–¹< žÅ=ûûQ>çÜ4>¶˜ì>Z4ä½KA<>ö�¾ÛÕƒ>N@¾ˆ=´¾ZÖÞ½ÿ~¿½¡²½îôŠ>ÿG >ÁR[¾Ð/ ¾/½ÜC+¾” :‹6>›º¶>aÑ> œ½î…þ=°Õ½ö×7>yÖâ>퇾, ¾�¿%ºŠ e¾U¾ôë¾7ï2>žr ¾å¿©¾\K^¾‰ïí=& >ÿ=̦=¾X/×¾@“é<ü ½ £=4þ½Ô?úÏ">æ j¾Òn>ÒˆF¾ƒ×=­‡>xÿ¬<ö½gè´½**þ½€<ºÚRË=¤}ˆ>ðŒ ¾¾‘.>ê_’>ÄÝ=ç&Ï=ýù"¾ÿì¿¥°!>OÊ=Iþi>ã…¾¹FI>»ø½<±½'BÞ=Y�j»Áÿ½>Ë+‚½<)´ú|½Où>ž7¼¬<½"¾�¢¸½¨ç[½Ôl >?¹Ë½oÀ>¤çG=Õr}½.;k:ð9+¾…­Ž½B·å½ËC¾ÿ =üœ ¼Éñ0>{ت>«…’¾(·¾—€–½µé`¾¤‡,>‹Pa<¬ý¶¾ñ ¾)˜Ð½†Ð}=o)Ö<@“ø½¹£<¥M2½TÎx½;=£9O½®Óͽ ©S¾|¢@¾?­ >å΃>çš…¾¿%¢>Kߎ=u_–>ÜËܽ·M>9Pq>2ó\¾a“+¾pÇ+>Ò#'¾Ô� ¿hÑH¾L0T¾æ“,¾f«™¾‡}ù½ñéõ=L�½ÿ…@>Ër“¾¨"¾lἺò=wž^½/¯á½jv=»#>ãð>‚ʾh^´=’úJ¾àWh>æ-×½ÃôŸ=޼ >¨÷î½ ¨}½7f'¾ú?¾9`齨0®½ ˆì>íV0¿Rn3¾ÙR>Ù•½XUG¾EÌi¾%,>M­Ï½2â½ðð³¾ HM>ßN>7±=wàý½røÕ¼$þ¾Ñ‚€>É>|˜Ý¾³j£¾Iu¾Ü–�½ÈM¿<±ý¿ân§¾§W)¼¾”ž=ÂR½1`>eªª=ôtÉ=—$ >]d=c6W>�W|¾xà‘>#õ?GQ¾V=Y ©½h|·½ÙÚÿ>ˆ�=): ;Ú�=w©3¾%È/>H9C=Öë:ÂiQȽ{ã<½;“¾e޾L‡‡=�üŠ<ÿFp=äa¾�ñõ½¡ûé=,K,=¨Šú¼uln¼3~>/Á½óB¾™§¾GøÉ=–îX¾{¬P½ÉžÙ¾²Ò?tÎv=ÞCÈ>ÛǼWN½>17¾Y²·¾"ƒ>Þz÷=yQ#½ž®¾x+ >  ð< Êü>¡9¾—ˆ½‚±ã=¸\C¾éŽÿ=•9˜>¸˜×<ÿÕ½ŸÔ<¾¼ß1¿5 ¿J•›>蜾¾B¾w¾ÿ»¹7éú‰¾Îá3¼Ôsš¾±?•¾”„?¾D¼ª>*øÞ=Pü²=m�>Ýêù½äÂÝ>Êà·>TJ>…V­=±®°¾`vоðÍŠ<äV*>Nê½¼¾�@>ðè¶>ºN>�ð>Âñ5=’?J¾C±c=×/¾7–šµ£m>ø¦ø=™ɾiP ¾T¥ô=ÖÓ>Lm< ¨¾$>-€<ŽÄt>r³æ>[˜o¾u\G<å ò>¸_¿ß 6½ ¤5¾ú¯=C$>;õ¾éx¥=͸§>?‡>O†Éº¡1 ¾>kN¾¦$¾yÌ®¾Óÿ>5ßѽ",�¾Ë =O� ¾ìj}=W¡½ÕäÀ:�½.ξD—h¾Õ¹1<µçº=,\«=l¾½òû?. ’>B¦>q>Ñ‚½ªv½fJ¿i_õ¾ C>Û¿0?â=¬<‹¼=Ò· ?·Á­>¢@>�/€>(å5>õ±U½Ý"¿WZÄ=ÚqÕ¾âF3¾[œ.¾ºÀü<n½x¼œ¾¼á.¾ xÞ¼•~„= M½/i˜>íIw¼ˆs¸>Ie¾[ß»½ y¾O^¬=€µF>@ü“¼Õe'¾yÔ{=†Ä5¾¡y ½›Óм™<`ðË=·]â½K®]¾±°¾W6>oÓê¾aÕ¼z¼k¾­ >Ö[¾¦¥¤½à�M¾ËEy>;på½Ì¼ ?!þ�¾iN¾Ìù¸½>(ž>{,j¾¾«£Ð>–D=mW<Õ2¸=Öt‹>Á•>•´Ë½üÖM=uXÙ½¤>[*> ¼À=s©>É §=.eð½±Þ‹>]á¾å2>y›S¾ºü½╀¾F|¡>r¨N½h²¯½+=Õ>tš1¾à¾ní�¾yÚ#>å²ð½ã å¾�i~>ù™¾V¤¾)2Ü>yw>_�>>ZD>çß�<;€²=~Ú'>)š¾|> >¦r€½¬“C>ÜQ¾º¼´à>\I>ýÜï½þ5>µM>Òö5>X…ç¾gJF>ëD�=ñÔ=»½7=Ò‰g½,s¡=ÉÖÃ>˜¿w=êf½ü3 >N„‰¾q™¾]v_=T#Ľ�Õ¾«@!>©N»>>¾£=X÷<:ïk¾Ø¥Ê>Ù-¾çÒv>I̽dÅ?>¡@>œæÑ½‰/¾Õ >*+n>Dí¶>4ÀK½8›[>ò`F¾% ·>Üö >;“Ç=Ù/·¾õC¾ýÞ4¾Ô>†½V¾€¾&°=ó µ=H÷>‡Ç6?¬‡£>Ñ0þ½…Mî¾>±©¼ÀÒ(; >€½ -=Z¯´F¹€¾~xè>µ@Æ;øhà>JÿÑ=ÐʼBe?½Uj>>d¾VyX¼Â$ؽNÆ>Æxð½·�‰¾80 >£6¾$7ï½· =õ >R_n;ËM%¾ÄªÎ½ê¸½­Ö+>½2ZB=4§>|ýï:ßl·½ŒiE¾Èð-¾â�¾òÔP½ŠM=Ȉ}=©o=\¾t¾[o=�ˆ¾=“D&<ü~¾È�¯½!>“Í(¼ˆN¶¾Œ ¾3ØË¾-ó=ÎÅë>}'> (C=½ç~¾w@D`=Rx!½g´½Sö¹¾sÁ„½üë >ÈB=´A+=W,>[©¾Ófˆ=ôöÌ=_—>�¾’(U>B“£>Sy¾â¶>%¿¾Žµ½¾W½ÖOn>¬]ç½´Ô<%Pê>w¶¯>$æÓ>œyS>Jj¾„6]>Þ]¸½xùG>~; Ç¢¾v#ó=.¯±>Ã$<îP>‰µ<2“—¼¤�A>㶯½{|h½Y`)¾dÒ%>F½|=¸²­>¨f½×Àç<«�† ¡=¾¿Cæ>]®Ý=ÕJt>Ûž¡½M >c¥O½ÚÈ9=ÓS¾G罂øw: £<Žš­=­[¶½ ( =‰[>Xå½Î¥š<¶ ù=-@–½%U£½ÆÁ¾Â®¼¾Cê =§¤0¼èS¾Í>|=²ŽË½?¦_>*‡¾©ÚȽÑwØ>Õ"c=fVh>K2œ¾sˆ¾Há>ã76<ôÁ½Óèþ¾Ú1%½»±—<‡0­=²º”¾.—_=™Ø'¾ <"¿E‡`¾âÒ5¾‰‹=¥Â¾2}­=AžÆ=‰v¤=éõ¾nû>‘æ¤:ªmӼˌg;ÂQ=>ìÖŠ¾3ìØ¾ãˆÓ¾ë¾U·¿¯‰>ÖS˜½ /ʼXŸu¾jN¾hži¾z˜0¾Ò°˜¾ˆ2¼=KaY¾8cÁ>x½¼Ÿ¾\ÝÁ>t ¾¢¹½ì˜d¾c >G ‰¾Ê½%bø=x £=6ã÷½:—¼½Í9 >Ý`‡>Ÿ¨2¿ì0¿»:W¾”f?¾/ß&>Ô8ª>`ÂÙ½@nã¼5¥’¼{:v¾Hòù=~ó=TÕi=[´¦>Ѧ·=q¨ ¾ÒkŒ=~Š‘¾¼“ˆ:Ö¬\¾äp̾ÕkÖ=ñ·.¾˜6½ŽŽß½yS>4¾=óÙ7¾·.±;6¸B¾ÄÖi='^=ý̼>±uË>R˜¡¾_�h½N„ƒ¾WÞx¾°Ïç¼°]=ÿq>o—·¼­_Ö½¾0=>±AT>ɘǻybÂ=I¾ T9=½;£>=-¾nÀêºän[>g;|>4q=,ù0¾9¥–¾¨7ï=AR½dŽo<˜2Ö=!°Å<�ëÂ>ª•‚½ø «> ž¾n�«E>î¾rh¦¾ Ø*=*°h>¦›>uÐ=ŒÀ=u²u¾(®Â=ý˜‹=È/¾øºs>®ãùs>GëG=¥Ã?>܉¾Mš>“tõ=?�;Ô=¸ø-¾µÖp>tš]<_ñx>ë¨â>«@H¾ìr‡=T<½=:ª)¾.~q>¬’'‡É½�?ÛB>¿ž´5½ïŒ…»%Ê–>’X5=“ʽý0?bÐ>E£>›¬1?7]%=ùª?ôsY>=�>Y6•>ÅæŒ¾‘;/>S@ˆ>Û(ã=°éF=ee�>…tº½¥�>Nî–½a4Þ=… ¾w?!r½ƒ¾½¾áE¾Ûà<ëÒº¾•ž½äq<ØØà>n²Ø=~Ž5=¯>ö=z ¾?§È>ßʼ¦a‚>\†�¾á‰ì=0>?3¾D8.¼ÊÍнÆý¤>ðÏð½` ë>õ0h¾ ‘¾ë3>p{ô=n–=§]J¾ Âw>T¬a>ì1> Ö@½¯S«=³=>GI=>g‡ >Ÿ£Q¾…'4<ôìÓ¾rY¾,>é¼hòÓ>€s[½µS¾Zç;Èp>Á‹K¾ž j>]æ¿?ë½y5¨=S\–:�ˆ—>²_>ør=I ¼~~=�6>ÈܾYë½Éœ;½)ˆ¿>ÿ’K¾¦Öc>Öl’>ª¼Œ>� ß½ÌòÃ\د>2ÈX¾•WL½Kz½\¹=t{½´f¾‡ €¾}<Ã=[îd9€ó7¾%/”>ÔÚŸ=fƒ¥½y�‡¾¡?¾ÝÐ4>!€²;5÷¾ôƹ¾–¾º>hüO<ÛÞM½‡á¾'Û½A�=ÖÛ=ä‚¡¾œff>{•ó=²ý¸=f&>s Ì>`™¤>[„>·é8> g=ÆË>r~ÿ=¾Æ”¾òx½Ñ�îL¾n� >Ë4Ä>i¸ß½"¨}=†Ä»¾W€û½gÐó<® ¥>óɼ¾»ºÓ½U_*>˜Ó¼'â=1Û½óEB>.è>l^¿…胾¤z³<’ÛÔ=�©=÷ÿ ¾?…>[ÿh>­x2¾vˆ­<5ƒ7<`  ¾×d­;Ú½¦¦-¾³»¦>ýÓÀ>"톻–¼~>Æg@¾Ÿ�¾U«Ö>5®>/“¾½\®Ê=WÇ�¾b¦%½`i­>g¦•¾¯{¾tSÝ>’_Ù½vYR>²q&>ìȧ=ì¾>oÓè=ºI ¾'Qʼ/¬ª¾XŒ=}§>Gk >óý�»Ÿ¯>>ñʽy¼Š¼lR<÷ô¾&“½xL¾_>¥»Õ½à%¤½É&ú> ¼½4=J,>ˆ í=të=1bŸ>à)3>ÖžÕ=Uof>û�d½vÏ9¾´Q ¿*Ò=‰ŠŽª¬¼= –¾Fús>ûؾQ”•>Õ¯½¹ï>XÛ‰>„ÿ+¾ bª>Çj¾W9ݽ~ow¾�=Ž—ò=:¯…>Šø·=²k?•g˜>j·y¾?7«½;³>ìð¾ïw.¾‡É´½"iJ<ÒQ°>»ØÕ>UŒ5>5ë>*(V¾Í¨Ï¼d¾gr ¼%Þx¾‡ƒœ¾vZå½}¤#¾½Ì‹‚¾+„Ù=;DRºÎv¾ =–¼ØZ¯¾°¬ð¼ ïf>|‹ß¾Û&Ö=0&§¾þ j¾hŸƒ=�Ç >°²u>hT¬;¤Ž=ù›Â¾wü‰¾ô½œõ>¢nV><²¾“Y¾c‚>ò—Ç=Æ�Õ½üྌU=,>¹>¯9¾• ?_åA>œ2ß½Ù›u>Ⴞ^…ÿ=bö=§;¿Å±ä¼|p>�Èž>)´®=„~½!!ÄïF[=sMÅ>ö¯Õ»8\o>Í`>!‹á½�¼&¾÷šó=<Êú½CT�> Ý[>åk¾"ÝŒ¾=Ò¾WŽôö½ðÓaÿÔ©<ˆÄ‘¾ñÞá½�¬‚> Ô>²Ñ?=‰A­½F�¾PŒå½§¥ë>»xï½ë–'>¾Ä3¾Ø�¾L}¤<å&&¾Å®ô<ak=ª»e>ó)>›F¿É÷“¾ÒM>›¯‘;vf’½ORã¾/\ì¾GÃ>°›�½×—?`”©=-N ?/`E¹#´½›‡I¾I½½Íy�=8'‚½,R~½öDÞ½Žð¾“à ;h;>¬«>·A™½0j¾ ;-¾Ùbu¾ÀWó=)~>��N>Ô;¾q¦½=ht½_Ò=K>f´j¼p­¾‘�<½�³‰=Ã÷¡> ãô>eÝ=ƒáö¾?9>覽¦NÜ>-ñ¾‡Ú=�°=v:ú¾JɼÑÐs>޶ñ=‘G>c”¾4>Ç<¡|…¾Ë8¸»î6¬¾’Ú <ìÀ >âêl¾\If¾_Gq;¡G¾XD×<àÆ> ¨¾¨mp>Žg¾éíݽqÓœ¾û==þ[½>9¾j¹”=ñ6&>{ñh¾'Ò+¾rUi>!>¾pÆ‹¾ŒB>À*‚¾f¨7¾Ž>°â ?V¨‚>�/>QGèJŽ>pÀ>~La½¯Š»z*N½Âèò½½¢Ÿ>?U½H?|Fû:£¥ß:ÿ˜2=%ü’=lcz<Ödï½qÕ¾>«r¾ðâ>U*½9á>OW>L%˜¾2äˆ=èòÖ½¸v>¬þD?æ<1¾_¹˜=�Ì”°|‹¾å./¼ ‘)¾Q0 ¾‰˜”¾V==ìc¿«×˜½a›=ÒÝó½™o>!´=ØŠ^>tq=£H½Ó›>Zľ7|ý»Ì)&¾‡�¼‡õ6¾Cà½(¿¦¾+n=zö¶>Îùw>È’Ë=õQX>Ãs»7 ½ç=½­�¾”|.>¥Ÿ ½æ·Z¾Ÿ�Ð=ôÇD>j­Ž¾_c¡=á­:½•T.?³›×;òø=óU¾öÏÆ=5¯ù=è*±:BÃY=&^ö>¸3>ƒ?“> _<_î…¾¹‚|=—õñ>›d²=Hù¸=“I>‡¨=ì,>¶ôž>|£þ={¶^¾{qÑ=Àû>IG >¡[>RêÇ>n)Œ<ÜóW¾+y†¼\V¾ÝZ{¾z˼¹Æ ¾Eù”>ùu ¾\wc>/Ú=”,“>¢â >©Äø>|-¼ƒ ¾dξ^Ý!¾Ç1¾i’ó=éɇ=¹ÊÁ= ^¿Õa¬¾U>>G¬0¿‚à¸= †ÿ=XAY=äC{½/ 1¾Ú¹>Bk> ÿóe> 6K¾*fƒ¼x¥½Ì|I½OP´½¹7ó½Ü/5=Tñ2¾ñœ´>ÀœÀ=r ¾î~>FY,>ò™™=ÖȾ‹8>+ôé¼cy”¾C¥X>)R ?…¥Ä½! n=Þ¾=hâ=À"<>ٹ꽧G”>ÄOè>�‰À>Pt•¼ :‚>è˜Ý¾ðk½wFž=2Ú@=Ùž >�$>Gÿæ¼î—¼<Öœu½$”½4Œ�>–>ˆƒÝ>v-¾E b>q^>�¸K¾Ï\1>F1¿u¸U>Å. ¾� ÷½þ¡Á<¡H¾¨rª=¡Ö±> FĽ¢¸Ë¾Iö>W(m=Þª”¾NÀB¾ŒÔ¾\XÑ<­—?§pÿ=ÂNÓ>qôY=µØ¾îL¾ ¢§=Ü ¯>Û8ƾUö¾Ó=/>€ø?=ê¨O=‹¾6b¾o N>¯`ò¾QÝH>ÖÎe=±Ü=.‚k¾Ø«¾˜,e>¸xš¾CႽRÙO>�ˆ2¾›�í=‹Š½2܃>ç†{¾7È¿SuŽ%þ¿êj”½Ží¾Ã^?8嬻i ¾¾Tcã¾´ù¼ÚE€>YÅX>ØðY=ˆÊW=Æž�>:~¾<â >3X¾Ðy¼>™æ—¼‘Mu¾e5¾ÝÞ>îš;9#¾€·¬½O@õ¾N7>_º>`ËÞ=;¨ü½î(ë¾áHC>É ˆ¾?ëB?e?¡¼a¯Ñ=VV¾;¼¯½Ro˾L.<žï½2­¾×žE>}žÏch¾(Ï>OÎͽûÅ>8e!? »à>6r¾Á)©>c�>ÿ=õC¾Õz<ì0#¾ R->Õ+„>F΄=[ãS½©ån>M-˜>pÕ->¡ù¾¡vu>4m=3P–=ˆ°Á=�i½§XT>j3�>JÄa>¤¬ž>IÊ�¾‰/‘¾Q×n¾þ¡4>íòW½û½¾õ¯^=O¼¾s¸¸¾áå>F7Ÿ¾½©=¢º¬à™=éª>žz>>¼–¾Úÿ=>+ðÐ>ú¾=?ç>&�­¾«ÝY>QÁ³=W'0¾-xõ¾�Iɽ¯­>âf¿ J0>GÓY½}‡>;²>%ä=– P>–>>%Ž)¾xÉ]¾Ôr|¾±7ĽMC>y¨¾£˜}=¾§uâ= 'j>[¿="ݾîêk=§ >ÈSF¾çËà¾Þâß>X‹¾5ÕÔ>‡Ž€Lƒ¾ÎÚ¸>y鼎„>>kï ?Ž-J>]ª0>I.’=Mg>ZÓ» B>fÖ>š&?T}Ž>(£=Ë“¾»‘Ž>5Á¿½~È3>Å�ö½ãt¾7M�=Š»_=†>ždž¾Û·Õ½¹²¡»WlD?Ùb>@¥þ¼5u7>Œ¢¢¾ÂQ;ÿ[P¾THl½�ÁU>Îí±>zê¿ÁÊ=³Îè>õü…>¸Û >£*Ï=W¥n¾Ñ!½Í8½ŒRË=]y)¾ö‚?ºÔ½’ §½b)w>®Š>£N¾Ùs3¾Á¦½¬D[=uv0>6 [>Ý>VE’½ª ¾°9,¾(‡¾þ„Ǿ’¾d¾žÍ=<šqŒ½Yì=Ñ¥>á†>úfιŠ]>Œ%>>ÇÈ#¾ÛEѾøCœ¾Õ€¾m™¾-¾“Øw¾\ˆÍ½à«û½qmÀ>a(¾a#…¾?–ª¾6ºü=Áih½:T¾Yîo¾¶�‡>F‡¬¾B ³>ެ¾#+ƒ¾þ�¾ šó>Óòɾ »’>pwb;9Xˆ>ÑD?|Õ‡>§~½cCξH¾�ݾ©Ð¾gÁQ>�ó¯>«…¾à!�¼ c>�  ½$Rë¾9ÊM¾ƒÐ£=†^*½c3c¾—”•¾Kb>h­ô>tÒ"¿@€w¾?å<ƒkï=¢†›>Ìä‰=NáÛ½4} ¾,Ès=°‘8½Æ8=Z" ¾lJå=›Î=7«¾ ¢�=Ö¾Îm€¾6H ¾³$Ò¾HŒ¾f+ž½m}='–`=ŽQ¾’Ÿý> .œ> `e=›«Z½3�ª¾¢o¢>“—º¾ÃR5>F…½žù‰¾ªÖ>íÔê½§a>i·]½¾š“½Ýù=©?òªŸ½HǽyæX½Mÿú=¬ôC½½u ¾wìŸ>!�?#>ølº=+¦é½€I!¾mc>ÝŠ->F�­;s+™¾.€>̰%>E¦È=™Îê½ú꿹Ë,>"=¾Ô…>­DK¾J�ô ½Ýj¾L¡¤¾ÓÉ•¼oѪ>”á:?ÝJS¾;]>ØÔ½”.ä½X?e] >mÒS<ƒ[> 1±=�ƒÁ>:Ÿ¿dA >$M>•²&¾un~½žÌ>€9£½ÙúR½À]¾hð ¾+Ÿg¾ÒÕt<�’·¾e¯#¾˜ø==wœ-¾È”m>R“=1v£=ŸÔ‰¾ø#<²!½<ÂO¾ ó9¾¯ð#>€Ž>Ýn>Ṡ>{… ¾_+ ¿�R„>1>ñ¾�蟽�& ?W°½(�T<`Ï”>À£¾ Ë<«þô½Î¨>Zfœ¾Mö]¾ºwU¾#§‹;¶q�>fØ(>ÒÉÜ=âòë»ß.×>â&>T™=Yõ’<±·›=âeR;• ¿SWt>sU'>�™£=Ùã¿i½è¿ñ5)>ÂB ¾¤ì€>Ø$>s“€¾·3¡¾±3œ½†ŸY¾©Ü½jSÕ¾µ”@?û\Ð>=º£¾~ùu>ˆ{‡¾Ü•½/”>üÎð> Ã=i¢²½zà½[ä>',–¾{f¾]]ò=þä>zû >V„!>m-¾I¨*½›µ˜¾@º>ì„ =G¶>Ú“q>f¥€>p$.>ÿÔ͹ž£ ?ÔO>n-=]â³¾êh£>Rpµ¾Ù×H=ùî³=À†ƒ>%R-¾æ/=>™*¾¨^Ÿ¾û˽ù›F>쎾›ð¹¾ÃW¾fŽ>@Œì¾[Æ=÷¨ª>-ô&>�ã¾Rú ¿šÂн#+Þ> }>±´>bBw¾ú½g>Ì %½ëBŸ>ÚFj¾DV½£¶#¾yœk¾’U¾Ñ»<áˆX>¦ŠÁ½DÚ\¾OC«½½Ç ½i)‡½¥i2>~Š =ßqνÙDh•¾áu½‘àø¼ú…½ÚÔ+¾�8ã=¢.¾¯j´>ž`–=ZF™=‡Ìã>%Fu¾á$>9v>9>›í½ƒ j¾hŽ™½¢=(qó¼Áà>ú—’>Ço+½$r9>VõÝ=x?">ix=Ø·“=ª/×;,Ƚ±ÊO>» ¾s­�½‘™<úºm>˜·R=@p*>ˆçg>Â(¾w½Ç0®¾Ã™o>Èd°¾Á…™=dq='¿za=AÒ½o1]¾Jã,¾§2¾æ¶æ>'nk¾øU3¾ü"œ>ôN^> è>ŽC->««P=�Ò=Ü5>ÉKP>úG|>£-a> À§½y5F=ן½H­¾si.¾Ö?ï€c¾ðã&¾ D¿t÷=Ôæ)¾¿¾ŸD…¾Í¤®>Ç‘=  >by-=¦J}>Ô´/¾ßH>B�’<˜À\>˜vn¾KÏ=?:©œ¾Xfœ>üq¾€U»>‘½>œ$£¼c–i>Í8ž½jA½è6¹¾ó¤ >!Võ½îR(¾v#�¾ô}½W¥>�öü½šL ?Dü>«Ã¾‹¦˜¾ßwP½s�ö=¶I¦½H†6>@í’¾Èã >Š8,>Ä;¾kžÝ=;†>âv:¾Õ™>œ�ú½¼Â >œ¾»¾m O¾OêÙ=¼ƒ•>Þ¥$;¼e(¾l5`½ç‡6>Æ¯Š¾Âg¾ è½"Ï�>…·¿_ Ç<�E?ì�> fâ>¨ø§>ÕX¾Q!k>÷xƾÃU­½•S¾Û¿Â>µš¾Ö—š>\2<>Ñì >Š˜ ?ÉBB<Û×2?Ýe„>±Ýý>º¡>Ût¾Åï8>þ–›>¶RÁ¾1åø½�^å=²X«¾¶ö—¾*¥!¾Ùi=¿—3¾êS½÷$=…å`¾à 8>xNÅ<�©K¾xÚ�>Œ�|¾gÔU¾ðL‰>‘A¹¾�T$¿âE¾iD}¾§z‹¾Þ2^=lÙ.=–…“>­Ðͽ"‰Ï>÷Ìú½îðľ �š>°]ֽͪ=ð<7<ý¨V½×µ¬¼¾?µ>Á²Ù>Án>ú†¾N=]>ki=Aø7½ÙýÞ<á4¾ûû.¾ˆì½>Ø>q=Yà•¼õ¾K)�¾E�—>`Ão½<œÂ=w¾áæ�¾‰Ø¾EÀ ¾$˜£=¦[8¾óòð=l>å ¾÷SºY&ľøƒ‘¾KN½,Ú!>Ó>šü—½¹øH¾bJ†¾Hÿù=�°½Ä3=„ÊS¾òP>�…5îš=TV9>Ó€~=�œg=Ýt=¾ESS¾Òý<Æ,6½�·'¼X‡>µS >[Æ=ܯÝ=–Iz½6I>3l½Ø{¾¦‡A¾ì)Ì=ÈI‚½qn>8A4¾�z¹>µƒ>Fûó¼¾}ê…Ý=URð¾yã>=e‘�=43´½ôl=S%E<­;D¾Öàâ<’ >W2¨¾¾Í-½Þ�I>ÄÞ¹½V(¾2U‚<kj¾2‹€½›A>à ½Æ°m=×þ‰=?^t¾.Æ ¾p=þ>X+=`¼—>¥ú>í h¾¿ê~=D§M½sè">�ê½ü¡´=ïÁä;®¶¾Ô}=>¸Y<²�>dE?=íúú½|7\>IìÆ¾KÃÏ>›Ö÷=‚쌾«áX¾Äå½òÒ½�J†>Ñ¢¼<­¥=Þ8í= Z6½%¾¾ÃÇu=ÂÃâ½ýOý=Ú¼DïT¾ó� ¾û¥¾BÈн½ªb¾ ûr>Éð¾?"N½J÷½ÙؽÐ�`>^· ¾ ;Á½Ç̽K…>Í Š¾ ]¼" ¾Dù:>Ÿ¯>1ö\½Kn>iô>‘ž€>>!°¼q=¶¨>>-P ¾îŒ>¾=¯��=.™8=Ýd·¾|Æ =êùÓ>ˆ:—=l}¾g¾¨½4k¼û¦/=wbA¾B «>¬¸¾>~æ¾S�Õ>l€`>œ'N¾àÐL¾Q-Þ=ÐV½>·~(>G-?r“X=Qù=jÝm¾“ó~>¿ó3>}+>àËP>¹ˆ¼=Y{(¾½¤‡>¥V‰>G§¾xd†>ˆÚ@½B×½‘Ç¢< =…Í>ÍŒe¾r‡g<~ >s «>°•¼¯>%¿ Iš¾2ãY=å 1?5Ú¾¬²`>q)Ó¼:?»E¨=AĽ½A ñéÍ=�v>u=èEŒ¾›Þ^¾òÏj=z-¾áÓ�¼æ0ö¾#¥¾Œ+ >{¬¾tª?³ÎÙ½ßÇ®>úSf¾…zA¾¤ƒZ¾áT>¤=°»XJ¾ƒªB½�†Ý=¢¼<� ô=Øy¾è@†¾e]½�`p¾½(¾o.N¾-ŠË>” ½Éœ,>2Û†=²]ö½¿ˆ¥>µ ¾„’]¾­,>^ {½/äÁ¼7äf> {¾þ?¾nÖ¤½hLÃ>É’“½|™<ãx=uܹ³ä ¾«[=Ê!U=€d]>�Ž+>±Æ= …À<'Ò=tó)¿rŽÓs>;Ñ`¾gk¾qU¾Œù4>Dù’> ~,¾})¡>ªÕ\=PÂÜ=‘>¤Í�>žãì=bÍ�>lmI>^r`¾&ëÌ<*Æ­½ÇÐ$>A?>0Ýf>¹=ò"Ï=Z+ï=tC=s­X>-½¾5V¾±'R> ¾³C¾/ƒQ½T8¾‰Ç«>5份JG =NŒ> ƒ¾\£²¾ Ç=›¼¾t"¾ÚïÖ<²Î€>ÈF>¶ßô=þ(=¸H>S+û<Ð&£¼¸aļMë¾L>W®õ½($¾x]b¾§.޽*v½�>c>©i= ö=¥ÔI< Á*>t±½uBÜ=šÊÊ<Â(e<щ·½`të>íp½*Ž>"�¾Ï~…¼ Ÿ»ã€Î=CfÅ>;ÿ> ¸¾÷Üu¾">˜}Ƚ `:>ªæ>t4>÷Qx>ŸÜI¾XH¾¹´=W|¾Y¶ ¾±ñT>¯}}>ÊzÜ»Çe©¾NW¾¡ÅI½¯Þ¢=Èê“=X:¾ÚÈ1>åßî½ÉB=Tû<úCܽq6>YW�»Ó ¾ýÖ½°�i¾ª+²»mj¸»Â á»=Gð;Úü ½»ß5>R¹!¾Îÿ–¾Is»©>>%~À¾ÏZ>ÃÍ@¾]L¾\Z=u¯½®Yû=â0Ì=/b潨Ók>¡×E½¶¾®<—m =  “=¼Ñ*¼Š*¾ß{¢¾±Ì½2¢´=û—�>åî;½E=w7S=¸¾0Ì£=DUð=®¨ì»åC¹>/²¯=¯¶Æ½LÉ­½Ÿuk8Âv*¾ ³J>KÆC¾eJ•>j`õ<5ô;KÓ·¾©q>®þœ>]ëM=il½ŽL?¼å§‚¾Ë8�¾«E-¾•�ަ|ˆ>åõâ»Ìv>âÓ<›U°=FåνšL:¾óg>‰’Ô==lY>……I¼š°={e>Ö÷<1é�>:v™¾\éü=ø}_>ñ �¼‡Ö¨<ü="l¾É騽¦È¾T!3¾vÜ>¡‡»×¾'=Oj½ae%¾h->Ê)y=]¹µ¾0ñ6¾Ý™=Òö½©Ó“½DTv¾�x侇°Ú>:%>žs½úù'>]É=½f?h·=rSV=Õ5ܽ_!¯½ëW¾º>Ÿ§¾ŠËã½µúV½Xy‘>bà Àl>>B:>tȾ{0€¼¾ÌA¾ìP0½qm�½ûŒ ¾Ó«V¾”†Á=H¶õ¼hß“>À|_>³8U¾Å\»¾ü>&>N�b¾;çà=•>|[q¾þ=› »¿ç¾—ì º³ðÜ<–á=>c8œ=:¹ë½a¾ð=ú�¾›+¿x­=IÌá¾¹¾nž5¾k$½K[ >&{É=IÌ=0Ö>À ¾{ON½Ž>þ=�A�½ƒÚk>RH§½¶á>’a¦¾Ü¾@ñQ¼Ý<½™w>Aß$=p"ʼâŠh<Ç{Ž>1~нË`N=-’Ç=üVê=Ý/>öt9¾º}¢½‹�(=…(ÿ½Wj¾=¬’>þ†“>ëÖ'>¦ìI¼Í$’¾%–¼=,°o¾I²=¾ïmˆ¾… 0¾=lß¾ð�c½Þ3 >êý*¼íf½ >@ßA¾ªX´½¾Ã$>ü¸ú½þ>ÕýùK¨¼R*î=T¾ñè•=ìýš¾1‰<®”=‚©¨¾¶)½^øÀ¾Zª«½!O“½¯þ±¾éã‰>y,(>,ç©;[±k>©»È½\¾¨½î >˜=�}­>‚©=6Á0= ‘¾°Œ¬½¾¥¾Æã¾0±¾Ýa/¾ôi[>fÛ¾Å)û»iEò=g\×>=›¾„ú„¼ò÷D½ôŠ©=9a¾»ø>§2ü½—_=½�3¾“S½NŽ—=ûH™>óŒ>ü#&=}½¾ˆ{ƒ½±H¾ ˆö®B5=õ�Y>ˆE¾Ìí­¼Á?©ó#>I¥ƒ>ª%Ú½õŸ>:B�¾ìšN¾¹[è>EYº=dyY>Pm¼~2¾lÖ>=95;åé<ج.>4+¤½r»&¾ C;@V™½Ð™š¾8Ÿ= +µ>ìªÂ¾­4«¾u�‘½€µš>Ä=ƒÑ>o‡>µ¹—½©ö¼R [>¹yx> B�>‚“>X n¾¥;æ½®¡�½¶Ä>ïÀ=-Ü‚=`á)¾ÆUa>eYj>)ê^¼2aO>ÒÇ<¦¬Š½î%Ž>s¤l>AòÑ>îûÌ=�*¾L> Ä¿¼²ºl=ˆþ©Ó_>Jd =o?ò¼|Èh¾.�о@‘=½5é=€Õq>èh̽vÎ5¾9«3¾Sæ¢=¹(‰¾f>C¬>^ Ã=Ã�×=¶‹†>ÀŒ[>,BR=�±�¾ÛÌ©¾ð\¾> ‰_¾E§’>ô]¾Ý8ˆ¾Ðæ‘=C…í=þ²=ÕØB=xÜÈ>LŽ >{À�¾³Ø½k W>·qŽ>œ¦ƒ½‹ï¢½"á¦=Üy£=R5B¾Ôݼ(N4>{Q¬½'€�>EØP>\ʰ=Gª¹<· ¾‰å!¾-&{>\ŽdT¾ò/¿¶#>uT¾™Þž=Ä:?>ø*V=š¸¾ÿØj>»Ý¶¼»›Ø>,l™¾ü¡ß=ÈÇÔ½º—ü>åE>ðW´=jr¼8‹�>ƒ>Øÿ>¶3™=!e‰» dâ=”ÒU¾®j¼>Q±8¾âtw=×?¾½ !c¾Eˆ™>õ޾‘¾¹…ê=c4<>ƒ˜ >ÃȽ[>9� =Õ�æ½÷Ø©½˜4>„Ü>Û)´=ÐÔ#¾C<¼¿Ã�>˜€Â>„E¼ã=¾Šã=òn=šŽœ½•> ™´½_§Ž=¬?qsH>�m›>ì¹½q`)>ng5¾Þ†½½Äçå½ËiR¾VªÌ½²xÆ>¹žê= r¾rÒÀ½JÙ½‚ƒÎ½rq£¾ÞM�¾§±­= –‡=Gá>¡™Å>‚é€>ƒ¢À¾:i²= a!>ÉW>†»<Ý#> Y‚¾¡”¾>tš½Bïü¾OD"=©½8+¯<•Å=ûô=oR½6Mœ½-äµ¾\ ¾-´h½?´È=ÿ�¿½£Ä>À÷¦¾&€>ð=ð½µ·?=ãwQ¾åÙ|¾·ñ¹¼' =ÚÕ'¾ Ú‹¾ª¿ý½Ê=^‰½>Ov=:+“½¦!ê=D`f>Yî½Ú¾hdn½‡”k¾ÔûÚ= œÊ½K-Ž>žՊš>¾Ï.¾r%,½ïua<²¾¾Nc•=ï¹>šŒ¾‘�¾)�½T£v>nÄG¾ÜKØ=a|µ=²<˜>cå/>·Îg>Oªž=´ç5¾@ª;Ð@€>²*ª=;¾?‚ˆØ¾ >½#×½Yð=Fc„½½?I=/~v¾0aÇ=+3轋pÊj+½Œ¤6>Á«>E‰»>òG‡½¹ >У$Ѿ=„Z"> ‡}=½¨½æ÷ò=ð_ž=uþE¼° G½ 41¾1½ÐuH>V—>j¢³¾,f >Á¶ê½I»t>…=K¦¢½ F€¾õB›¾›u/=ñk=£¢i>1›¦=gh<1±m¾ŒY¹>ìíæ>Œc>YÍ= #¾bß=0ó?’g¬@¾Ú‡Æ½l€°ÝºL>ÀS}½Û‹º½È¾…=©Q>¾P4>j7Ï>ŽÞ�>[Nu¾NbK¾·u>�Þ½–Q!¾6F�½„_Ös¥­¾îÇç½þ•�>=ç½fzB=zßG¾]p”=[m¼� Ÿ¾á}•¾ƒÕΤeÇ=›ã¾nê½±%¾I)y>?C#=~:оI›·¾ ˆ>Τ<ƒ½óf¼ê>“¼Ã³£¾¼-ö=Wè…¾®=JÏ‚<–—½¾Lƾ83;=3CÉ=K‹ >‡Õ>…Ù>Ô÷=)»�¾¤ ²=%es>»•k½´üz=Y‘Š>_îϽÃÄm¾LRé>Pš=%ÈN>NBf<Â'½müË>϶¾ÄX¾­äš¾1„¤»p,u½/Ãú¼?rp¸5L=½7@U>ŒƒÔ½fò¾8¸¶½§Ýô½<߈¾Ë4»¼ÍÃѽœ¾ 8þ½�Fœ¾e§¿=÷d:>êñ†½ ;¡Az=ë>[¤°½‘Ãǽ<�c½]¶•½ Èà<¡†¾“PÁ=×û<Rí>E´Â½Eçå½(*u>P¾?>„! =­%´½¼e+¾|Ü.¾û?>ûý‹¾Ya¹=Ž^=„x•¾Ü[õ½Ò‘‰½®F›¾ «=h|t>p]ó½pbž½,2d>�åç¾6Q}>÷à>(6×¾[ì±<ù'v=kΟ=Pp±>l]Z¾ø_Ñ=ŠÈü<½n¨>7÷¾ÑǾ¨o\=¤Ùg½tỼŽW=¡w¨=ñaü=W¢f>˜s\¾“ʽ Ìú½:y ¾+wŸ½$Ò7¾4c_¾rg½Ûµ¾I»>œ#¾v«>´ä+½bt‡½r±¥=®”Û<'{§=f¸{¾Ü11¾ùKd>s_¡>¦š>½˜Í=Ö¨g¾t¨½ý"À¾®½ä¾P‰>7mV>×LI>CI}½�:ö¾ü²N½Ê¾¾@ì½½¸åó<_'>jP¾gÇm½DUç<¸°¼±ö> ü>摾 ¥>_ìG<=´ÿ“¾ô««¾"ì>9ú¸=Ž1?P˜D=mìù=ůŸ½ K¾>(y>v(>S Ñ=h\­½'b*;}c¥>R ½†€ƒ<â->ã ã=-A6=¹˜+¾MŽ\>õ<�¾ý€æ½“�·=±j>–o€>é¿­>‰½ Ìμ—&>86�½Z¡Q>Ô†â¾èh9¾²˜=Gù4>=k¯1¡÷º”H>×ß]¾ŽÌ¤½³Äƽ¸¦l¾x/ƾˆ5>ßA‚<)-¾;!½@,˽"ö¦¼Ïï¾¶4@¾Éܳ½‡…¼‹õñ¾¶µ+>kðB>™c¼|�>_2¼ÿ>Œ¾`y•¼7ǾÁüŒ¾Ë,>�Î6=é–;p‰w= ç»:£€»¦m8;oßû½7B:>¤á•½®b›>RÙ>\ò¦=vB§¾Ùy?¾ìлK)=×A½)[%¾‡W½#1O=Z&>d—I>lz¾6-¾vpž¾f…w=àöd={O >Œ¢ ¼vý½þÓ ¾µxÕ>—Š>¡¯±= -<‹Â ¾Ä-Ÿ½¹ï=>%ÒÚ½!²9¾€»>4>=·þ>Zãš>�o™>O1=7>l;!¾¢Ñ›¾w¿™¾ 8Ê=�‹â½} >dòs½í]•½À +=ç,¼”¾¼œœ<�~¾øU™¾ñ�Z¾ 7½ê·=æ«’¾¼/н»¹ >HDe=è¾’>¶ê˜¼œÕǽ�”i=�¹)½€÷v>À$¾…[›>}&‹¼l[?NÅ<á)Ø>ÉÀZ>/A*= ¨q½íS±¾öèÚ>ª ž…¶$>:º/=ƒ¾Ö�º½KqÚ=‚Õu¾þÁV=Ù ‰½.ÁE> I>;‰å>¤é~>惿³FÔ=œõ²¾¥Œ½áx9¾Þl•¼3-h¾ ž¡>¡^8>ñÀ=\¦>ɯ¾ÕÉ”=Žw¾4Ï< @_>i¾ÈÚ“¼gP£¾”›^>„ >q~ä=»!¾V Q>Ц:>éÉQ>™êf¾'½©=“j<±æY¾ú=Ò]½Iê¼®h<¤.Þ½œØd¾ Šb½Îÿμ¿xH½Ðg>{b¼©C>D£¾í#-½Ó@€¾ì໎mQ>œU¾S ”>¨¹ <'í£¾àº>¼òš¾¥™L>Yïú<î}¾ a‹¾ $ ¾/~+¾ªž6=6¾[ݳ½é£> á¾›ey¾¹}‚¾Øê=¾æ§>åuh½˜ä‹>dÎÁ=àäñ=#¾=FÞ>sem¾#_½4™ú=÷! ¼Jå™>( K½Ö¯¿»·?;âc½¥¥R¾Ãøj Ǿ„ˆ>ÂW:¾½ÄR=Íì >ÊO}>楖=¹û½ŠE°=é臽}‡¾>1!L¾;v�>™F9¼Ÿs½!Cá¼òq‘=_M¼½O9d= ½™½ ˜·=Ó+Þ½DË=5š„¾D->m l=éþª<¤�õ½éš>pQ ¼ðs>÷)M¾ÅˆÃ=òé5¾�tá½(l¾åýuðž=’ùa¾kX޾œDÈ=³Ëš>.¾4x½"н`Ëɽ1ôÓ¾¶ÒF¾†•ƾ®„>‚1¾ãK¿sÜ›½­ä>ðus>.Ë‹¾Ðö½l‘Ü=ί½Ž->ÿ>»Aöh¼Ðg >k}å¼2hÔ¼™xã¾'!+¾ïM=|>\úH=F>òÏœ¾VîU¾©¯¾šâ=}\Ž<ŠV!¾ßQ�=é4ˆ>ý(5¾ ƒ¹¾Æ-<¾©5¾ G°>޳½ ‚”¾ˆº/½�Õ> ÷¤¾æ¸ó=L³¾�­À¾þÚ=žŒœ¾ƒ/š¾û>Qªq¾¢ip;­§¾®�ž¾¿ˆ>^l‹>Mˆ>ço£I >í›’¾“B¢;L®=»L¾;q£½«ïö=^ÏX¾Œík¾ÀÑÇ=¹Ç¾Ž >Fš®¾PÏ >(CÛ=Õ¡%¾í‹¾y[Ê>ŒξáÖ/=Qæ8;€ÆŸ>º(2>uƒ>S’“<©¥œ=jˆ>¿C½Õ£×=Ÿ¢l¾rÌ⾤6v>ex ¾àO˜>##£=¡;¾é�¾ªÈ=üë¾$ö;Ûx3½T¦%¾6ù`¾œdœ¾»ß¦=Zku¾EŒ¾m=¸c‘¾©[‰½M¸=½lþ*½2_>[æ•<ÐË¡½vµÑ>Z+'>˜àä¼l ¦½hš¾/X>콚½<_j¾­®o¾¢fi¾m´c¾Äy¾ª0¾f]“¾im­>Þñr½—ÿ ¼nB±=læ=På°>eê‡>Q�¾ö�W¾™›ã<ý&>Ï3ð½Ü8>±GS>ÓÐ=íBï>H¨Â¾ùó8¾pãµ¾Î1= .ѾÆ”=_\˜½îϽ,ï,>‰âù=]Ø>žu¼%P‘½G?R>ý®h‚Õª>¢ù‚¾"–›>e ÿ»z%�½¦(¾w»Ý=ýÐÌ=H„½Á‡¾ü�½½–³e=";Ž>±Ó/¾Ònƒ¾þí�>H>(P>îéļøv†>o’½•´½ìʽ¼³·>D‚ü=\ö›¼ži²>X¡=ÿBD¾Æ¦P¾Þ6>Ö<¼‡Á»ÙÎw=Že}>ˆ9l=^Ÿ.>86•;böµ¾J̵½›Úh>^vZ>§P¾÷uǾþLP¾O© >Û ¾ñ=nI»=Yvß>#ò¾ D¾4>å¾/~d½ÄÃ>öjK¾ :¾¼àã<äò=½@§= ¥<õ¸ò¾E›½ß/å¼öì¢>U»Ò½6Ê=:3T=SUC=5 >»-V>‚Å;º¨=ÑC=…™z¼±EN¾_.…¾ÕÞú>›|>´‚Â;¶A­=Ækû½ª„ã¾Còw>xŒ>ÃŽi¾|½À+ò½Ç¤+>e@{>¬;þ`‚>¾$áö=ŽwÄ>½QÙ½‚E>+±½+ª¾šÌh> Ãú»lš¾oŽ=À�¾ë1ò¼È†à==³¾9@U>>7Œ=Cåõ>zÊ�=2s¶=š$8½UŠ >È÷µ;]²¸¼MÏI¾M•=˜¾½~ãö¾ªA¾—{><(´¾„é]¾†ƒð>¿ëi=ùr.>÷§L¾8pé¼WiV>g¦_=âe>¼ñþ¾·ßº>•û=}ç<ÓF,¾ …=ò Ò=¶ë)>;+[½×{½�ýÌ=Ó—;=f>$ßǾ Õ‘=ŸŒJ¾¸^Qó- >¸gß=òŠ�¾Zén=ö\–=Õ¬=€>f|]>v°´>ÀÎÏ»žîÄ>騽™ɽOç(>Kîµ>øª=«Þû=É ?1ñ=Ž{1>6�ø½-g±½�Ä¢=ÙS¶½ £c¾¥6b¾Oß«=¦i€>^fY½©Û4¾^Åw>M&0>&ÐÝ½Þ Z>¹Îµ½Bá>þfË»ÀB­½ºE*¾ºøã¾ÆÐJ>ÎÜ’½§ú÷º(ô@>;¥¾cÇ8=õü->ÉÔ=íæµ½Ç@\=ˆ�@>iŽ_¾ú0¼¶¦¾äMv¾ð©Ò¼·g&¾‡H…>xì®>�&¿¾…”�>÷Õ=j³>W{ñ=ܲӼG5½£u¼%Ÿ¾¼Zý¿¾n¢`>ݧ¤> ¡„¼ÄÄ´=|Á >€'¦¾^0¾°ì>;áÎ;³ÒŠ>ú£™>kag½y[>7`‹½èþ= .¾ê5>3úÆ>‡�¾õàX¾ËLo¼h;æw¾j1™<Žº?½ÖZ¾iN¾cÐ:n� ¾ã¯ˆ>žz¾Îe¨= ôO¾8Ü0>—¾<þ>Ú(Ê>Ш¹½SÕV>#ã;×_à=yYz>2gV>šH½Ñ·I>wÛ;¾$ó=Œo;'ãÙ¾qÉ-¾ƒ†=¢7o<Ü7Š:ÝJ># ô½°ŽM>þ·œ>̬¾d䢾p?>ä7¢>&¬¯¾ E$½aŒè½(>udÏ=‰›j»Ù–E<¦F¼:Œ&½'¾]+@¾ó>T É=u‰Ÿ½x[´< Ÿ7¾äÝœ¾p%<ˆÎX=Ñ?h=`Ð?:­=å¨E¾sâš½_}|>÷ñH¾J-¼aú<:Uí¼ Èf>F>ªj·½¹¿…½ãc5¼Ñ„c¾™­Ã><>¾Ù§3½2g¾°÷�<ÐéÃ=¤ô4¾´~¾¬àའA>‹D>ê:=è¾èÔ…¾VÑë¾ý ?¾ÍÕJ¼òé¬=Éì¾�Y=t®<¦¶Æ½ÎÑÔ<ðªù=˜ëϼIú̽BMN>Ù³i>Güx<ÓÒ¾(jº<꨾㲓>§?ø¾Oa?d>Bæ»í9 >-¸–¾ì7˜>AS•»§(½-û™½ª5+>èø¬=§ž¾|¡Í>•¯½:ù»à!ä½ü“½Ã¾WQt=®^G¾\Ø9½pê*½*Ò—½ B¾¢�8=�*=>$õ¾ŒW5¾»F=R1>Û«Ç»>€ƒ>¾Ú#¾QV'¾gDM>¾:¾Ü#™½>ù¥¾%%5¾á-¹=.¢!=ºt¾Î´L½T¾çrŒ=Ö¬þ½Tëá½K6¼é{ã½ h»½ˆ(޾]4=¹/˜>lù¾cŸ¢>"k¾¬—¾��ýΉ=èǾø�ͽaоƒ†×½ûx¾|W„>M ?> l¾;øM>ÂP7<˜45¾„cC½ãyÒ¼Âë>Y­s<“¡½ci‘=øÓÓ=hl¾mß<>A]¾Åx>¾ö=ݽ 烾¤È'=Ú“‹» K%½(ú¾G¸@¾™ÅÔÓ•,>øy¾Œ £=³‘½—”>êì3¾�âr¾G’Ƚ ûŸ½º ¾i(p¾G�>a�q>ì.<•à뾫$=”úƒ=*5å½8ν“…4>±qî>­¾/¹_½ <>U¶ê=vŒ�¾Ýé>$ –¼Ö€>“î+¿4² ¼×…‚¼Y!½ë»S½ —ƒ=vø>˜3%¾�%ë¾äwȾ ¥.>v}·¾Øß7½tW_>ñpƒ½oe½�“½;LT¿>WåZ>Öð½]?n½*Ê>™3y=Þ_a¼ƒÂ‚¾!è{>OÌß¼sª¾M™½¼}÷½×Vƒ¾íÇŸ¾õ)>ÎF½.û¾GSQ=ÃH¾´i¾bv8>¹ý#>O0нäóx¾6ßL¼Gi¬½)ó¯=�›Ñ=d/t¾²8Ö½ï ›>�¼»øÞ÷½ò³Û½¼Uû½´D˽½’¼¢ª�½ùk.<ÑÂ,>h}Õ>®Jƒ¾ôÚ¯¾–«>X&¾M>»Ñ= À–¼4»¾ý±=Þ==xl>¼gÒ�L>ß{§=²¾é<>œEß¾¤Z‹>Ez ¾ 鄾8> ŠÓ>0\@>õ¦a=" Ö>A_=5n×=†ËŠ=NÕx¼ì)¨<¬!œ>|qD>ª ¾»¿=Ó°R<:òѾ»‘?½“ÃÕ>óc¾ ¡ë>ºC�½ý< >Ë]Ö½Ô(>l'¾ø â>qïê½Ð#D¾ÿ`Ù>uO¿<.™;EZ¾w ½²l>±0K¾®å‡¾ù3S>�=«×ª=þw/=Ä2¾<®É=õÞ±¼ä*ν¥ìǼ;3büá’1¾f¼=Òö¾y';¾Ïw>ÄÌ“¾rãÌ;†•о–µ?;·=µT½.K<6P@>ܱš=‰f¾­ÜA>>¿¡T½©ÜÓ<Šfi<ľߥg>æüu¼i©Š½^C!>ë÷ù½ö‚¾o„<ø/@>¤º°= c²>ïym¾N9,½ñ’>Qen<cI½±Î6=6!C>щn½ç¾¥àÇ= €H¾âx˜>ÍWp¾‘c™>ÞÈy>>8>#wª={Iý½3·½ÒÆ&¾ î1=—a;Óõ7¾ÈX>Hé.>hÓ¼¤¤;¾—Åk>1Cº=�¾óó�½7â >ûÿW>\{½ B>™g/=b¹ƒ>šÃT½/F›½7•>7˜á=?û=8uw¾ ôß<½�ú®=_Ä}¾—À=¦S¨=‚“õ½}<=NËx½ÊQ ¾6sJ>ÔŽ…>Âé3¾ña>å›h=I©>µF�=H|Žž“ܽ øE¾4O�; Û%¼ïÝn¾¶U¾­`5¾Å$%=$j™>ùØ,¾«ï>u>¦c¾ïàù¾ŒcŒ<—=hV>„*b=²Ô>~�×»ØX½ÆT>{µ½=Lz;>y5>û™€½,{ë½>i–½ôªÛ½ÚŒÔ=!FƽÝ*�¾©HE>ý¾’Q™>Üú =ž³¾g�,¾pF!>›W@>T+ºñ ¾‡¾*0˜>ì~,>e΂¾þ?�o >hÛy;ºy¾¸j>—EH½y“°½ù"õ=*\¡=ñE>±ëc¾x¸‰½Ic‹<ª&�>ëu“»¹‰™=–w½Vf>\Bð¼ôé=ˆª:½÷=$dã=<ýP=ä¾¹‘o¾›æ&¾ÿ|”¼öÍÀ>J7ã¼¥p ¾–$¯=aÂ!¾�*“>>ÿ5¾ðÔ_¾©b>:Ö“½ª;¾»“§½�ÔÓ¾N Ü;8°> Ûª>Éú!¾ÓD>(Èþ=T(|>a•> v>�'©½„íß=©‚M¾N!¾6v¿ªØ(>—ñ~½q"¼:¥±=t:‚¾,û+>s×½1àí½È=>: W>ß’"¾“c> Aq=²ry>Z¼ý<÷äF=’†9>Ûàà=èû(>—\b=â½ù¼áý¢=¼Õ½áq(½'…í½—pK= ¥>À+À½¥úŒ¾ÍT½Ü½¤>Ÿ®>`>4)>àzÒ=Z®c>Bo{>tºÆ=¹Va½'Oc>dºú=Gñß½/pí¾žAì=ƒ<¨Ì7>ñËÆ¼î+v>AÇ(=ñ{¾R©a=å3q<õnD¾9*Œ½°Ù >=ž>¼ž¾ÛM½¦÷ =ÿ÷>ž´=>ƒ—¾(Rw½GóǽÀ"…½æ€>a>AtÀ¾çü¼¶¼†½Ç‰l¾î…4=&V½sÄ ¿\Š)>Pc)¼¶:�¼À[œ½²_˜½9^=Ê•€>X`G¾ȼĶœ>ÃN€<¸+¦¾kp>�E�=;z¢=(k¥½¤�|>°pA»±N™>Pî°¾TZ©¾Ú�¢>1v™¾QÊa¾RjJ½òL¾»l–Œ¼H¾µS‹>K">iJý V§<‡>ß½åêd¾Y�¼¾—±½®­a¾iXŸ½:7˾—¸Ï¾>¿¾ŒóÁ=cš ¾Ô-»>/`-¾\›•>µv‘¾`¾³™½M2¾Ä²´=Ú:>wó¦>~eö½ ˜±¾ã7½=Œ\Þ½™è¤½øJ¶½’ë‹>¬’>o0“>ïð“½a0½¾ß§Ë=Þø=ai¾+®ë»¤3À=å÷`¾º{"=vbM:¥2ݽšF=÷b.½Åµy¾B#>èêl»vjì¼PP]¾½Ç=yÇ⾡M=€„<} z¼r×G¾ÈæH=5¸Ï½ ,»¾’Å>Óv=>ð¢=²´ c.>Ö¨í½²žq½�hZ¾ÓœÌ<Œ‚Y>àœD¾Aù¾³À™½DV¯= –>®U°¾KžŠÉ±r=7æ�¾% <ÂT<ùòj¾ Ëþ»šåO>õþþ¼Žw½Ä•`=Ói¸=Ê5-¾¤‡ï=€›¾Uýb¾Ðìà=pÍ‘; W=˜Ì¥¼ÙÂY=Ï8·"|j>ÄH=‡Á½¾d°=¾fäî<Û�®½óîê=4]Û½ŸA¾‹èg>©�¼½ÅÕŠ=ór3>ÚŠ=B¯Ò=G��¾_?>0Í=R©˜>`r½7bžß+%½…í¾¬Ê ?”dÈ<æ§»,u×½¿Ân¾ý¼Œ¾ Äž>rw>¸9”=ÄàÔ½ÞÐy=ÅÁ'½°«¾¾B³Ô½Ì?>^Ö¿ÇìæÃ½�ʰ>ñm³½e�¤¾¹.C>ÈÙ=x8f¾7?:»0>êI>·:æ=6ÇU½B­»½yçí½WÜ.¾4Â\>i‡£>(þž=½÷Ÿ>D¦®¼„˜´½~ù—¾‡î£¾ï¬�=ÉS¾Lec= Ž> 1ª>çF›=hž½çØT]u¼R“½�­R¾a¶¾>ý5Q¼Œ�¼È'Ö¾±ç0>Å¿u>Hñ@¾aÉý<;Ûû=¶?$>¨ö ¾v™>ó«>¦¡»¾¼p‰½,‹¡½.þ„¾< d¾=ç4>Ö/Å=>7d=#9½ÀPä½:­¾ )¾G…>ܹšèOm>Û.²¼¢½•<(´ðÚïš=ö{¾ª”W½ã„)>/6>_œ=¾À'¾á”¢>¨ðp>„X¾¥m€=ß Í½¾²ò½øÙï=x”˜¾&”;>6³?kù¢>ëP?*÷+>Ð(¾ó÷‚=™‘ô½N²½5ž)¼ª¶ª½“H¡½Ò<Í=¢àé=@)5¼—;ܼ¢kí=ùD‡>¸é:¼Zì> b¾=')=Ýɽ æü½½ðh>ai=´ãS=‰>]ß̽ä>¯B¾eX‘½;`A=[êº<^ˆ>0£Ø½ 4˻퓅>›½o">€ ½’ë$=�!¾¬)›½{ø:öç!>XöX¾j½Q>#w˜½Œ&>ø˜÷=$e¾B‡»>²~¤=˜ÇÔ;?YG¾‚Y->( мM3V¾AK¾%M™¾÷ô¦=\ÇN¾–¸¬<¿­Ê¼—‘Ô¾`;¾»G–=ÕŸß½!ˆ¾¹CŒ½Ût‡=·ƒ>õ�º>‡u>Ã=H¥<†|;>-· >(pÖ=úľOÇ‚¾Í¬À=–žÈ>Rxç= U…=bäF¾¬I½¥Aj>ˆ‚¥>âY9>ó >ý® >3�‚=_Œ¾åä›<é£4>Ê”I¾Ë4>ììe¾"u=J—m½0T¾nc>͹½yŒ€>&÷‡=Q\½s ô¾u$=RÑé=·–b>½Wo>I‡ñ=? Õ½5$>Êñ-=å �=8­>àvï»!p<â�v¾é½‚½Ì<è½Q()½cŒè>v€1¾ä=Œ¾&DÅ=¦ë‘¾rÒ=‚¶¾Ý,Â;¤¦+½ç9/½’Y=�ßÇ=mœ¼×¬=­úü½Lb>Öû÷= ~u¾ mª½á¼Œ>î>Z>ÔÔ®>ôôV¾É2F½c"̽rññ½cçÖ¼Õ<Ã; %¾^ Q=`tê½v½Æ= Â#>áEú½Ù“’¾®Ÿ²½Wü¾ë;¿¼êaI½ØV›¾�zi¾ û{>b?a=*ο=Š÷�¼°x”½…2üvc¾/Ç=õ"¾�>ëA{¾ýÃ>,±½ˆ«<$ƒŠ=´v¢¼(սξ¼<¶I@¾8$¾—l‚>zä¾`Ús½þ)L='™è>;m:=¿Ë–>¿ ¾< Ò½¸Øå¾Ó¤½{çÔ»dÞg>jÿ >ϱŸ¾zki¾ÙÖ,¾Wì0>soÇ=š}=qkø=üx>Fؤ½ z¾JЬ¾”·¨>« ö=ŠL2<愾¶‚ù=%®Ð½rί=\¤=hâ…='˜¼Ø&û¼õP=go…¾Œw>†³¾ùy9>‰†>Ú'£½-Ù£¾ :›=²�½t/1>ïÃ�¾¤½do>¥©=Ûéi>]�½bô[¾×6I½ZËr¾&Dʾ#ÅÙ>T“==Í ¼Ò¾œ˜>FBo½aK>÷ì?�½Ï>Ž¡ˆ¾·ýe=OE»½Sm½¹ŒE½:q‡=8­Ð¾¿Uê½3Ñ(=Rð >ì|¾äý;¾œ8s=n4¾™Âå=×ü¾7G¿~Ô¾•ºg>3X½=æMA¾ÞE@½ZM½Oâ->âK¡¾¿}\¾p9¶¾\¯á½�Æ#>·4¾¢Ú.¾¬-¾WT�¼P13>Xf¾ëœ˜=æÑ>¾œt€½œXT½Ï>q{ ¾íB=֣½äÝ—¾6.'=ÌΖ=+Yl<–'¨>±>ï]%½Iù=R„>–޽ä~½Æá+¾±¨¾Rõ%½�¤i=˜FË<¯û¼½Ú3°¾ƒÚ*¼M0i>=ž>®lw¼­øº½#—½½‘ = ;´¾iª >�q=‘‘Ø<žòE>²lª¾÷â›=D”¾�¼ßr@¾Œ@�>TR¤¾Æ«7½îO=†„0>Ù}¾z¢E>¸pϾ°2Â<æ¦<Û‘/>:Z¾Àÿˆ>x1>ÿêÿ=›n›<˜¸Ì¾ÝÀu¾s[û>Y{g¾�¬í½Š‰=#AX=·©¾>[4>âD–>ëh—<Ž,ž½e¯5¾Ò„•¾ÿ¤>öǽßÑ¥>4+Ÿ>ùm0>ûã,=‘=8Ð><†Q>Z\à½`Ð\¾›áºñ$S=+“«>%W½ÛPÏ>åhÑ=;ç.½¾çP¾�Q=O…V¾ Ûï½y¾Æ¢Š½Ëž*>™Cѽ×mH¾Á…·½mÖ2>¥??¾E‹¸<;=¾¤·½ž N='ÓŸ¾ž=¿¾Q†>–+¼¾Rš<¾Šk;<·È¾>Iî,>d…]½²-´¾Â+N>È.‰¾KÓv=wm€¾ù•·½YÙ¾•Ê5¾>Ɖ=Œ¸È=¦ò¼ç¢™>7ôÿ½QቾÎD¼ÁˆÌ=�<ò} ¾«r˾{ú¾

C˜?‹ÚU¾)r@>—- >ïgð¾{a|»i=Óâ¾Ëÿ¡=N× >¤>z«½=â&ƒ¾1®>¡&�>ðçï=ʵT½nY—<a¾¦­©>¶J°>øë=>Á‘?oLJ> ,Ÿ½†"7½"§\=qJö=ix¾&®×¼ë|C½# >…#r¾œfÀ=Kú;¾eI…¾õ³>Žx£½Q¬h>¯áw¾jev=CäL>}î >®Âš>QZZ¾¢¯=ƒ5>û©“¾æ¾G¾¼=€¾~³`>.ŸÊ½"$ >ú6 ¿S”À¾¸e=e¨·=‚{œ>ìAq½ñfÌ>C¤Ö½K'¾ÒB¢½±‹¢> ݽU?c=œ&»¾§#=¾C•>Ní­; ‚‘¾ÞÎE¾Š8»¾�¾)�>#³L¾�ü†>ÐÚD>©·=»@¤ú½.y™>Cƒ½ `=>œFg=.•=&^]¾²Ûž= ޤ¾>Ù¿<»ª“> qü¼YF>uî§>Iþ;>u¾ï½.Y™¾pZ=Y0õ;w×i=ûÇv½¢¬¤=·b<{òi>sâ=­Å=®cнDsþ½ö4$¾bâM½P7¼n[½ƒæ¾L~ ;!ؾˆ:Ṻ>˵¾³Êk>fê¼½›÷½Á[½"Z’½_¶W>zÛs>$·=Œž¸>Vek¼µ‚>ͯ< v¯¾éM=G7�¾m@¾®Ü2¾å³¨¾?>‚¾8¼¾ƒb½´>¶z¢=pýÞ=4õf>:´T¾ÖSm¾·�=m\Z¾£áH=òÒ=<´½Ÿ½y½oôe¼Í�ž¾]êc>™¼>ÀE²;R7V>¥†¾¨Î–>Š!ç½*쓾7˜�¾.Û§=GTŽ=Ãäi>#�Í=ZtÁ>fão;d(>Krɽþ¡D¾‚ ½=”6&¾†^”½QEÓ½â­=6�>_Tó½7‹¾ßñ”>o,G>ræÈ>)]ͽ#Ðv½vg!¾�Èé>ð]–>A]NºÛ¸U="x[¼ô|>ñÀA¾Ë¡=mk’>Ä’0¾‡×4¿œN>$Šn>⌽ÕmG>ñ$‚Y>\%+>8¼ñ0�¾Çû´½u� ¾Éj€=ìÜç=¢Úä½ýŒ…½·u¶¼>àC¾˜@ ;n³½xôϺs¹=Å:½Î Ö=)Þ >æZ�¾vÖI=3Ÿ²½ü±œ½Á§O>Oz¾?iÖ¾ãq«¾Díš¾œÚ$¾ØtÀ>Ôäß½ˆR>ã°=ëp¾ä‘^<à >Íb= G>e©é½'ÞE=âZ=^>‡šŠ=û9>åÒÒ½ŽÿN¾÷1>“ÛÊ=µ‡±¾…œ½‹K®>Ä—è¼Ýh‚½~™ž=)£›=/Ï =µš‰¾7À¾É­À½”~¾1¡ã=T>F¾Šp™½‰®{>×t—=�8‰¼erƒL ‰9<@³>Çļaú¾÷tï½{°=sh}¾ÿ>óoú=”Èý½ŸÖŸ¾ê’ ¾h¾â½5$ä¼<*ª>ê¾ Uv>¾÷=mŠ£¼Jg>íÖÂ>®½Ï¾¦\ƒ>’H->ƺ¼½#bÊ>Iñ¢½[™¿e2.½~ò=d$t>Yé¾DÒ×=oÜ»Bá@¼tÈ�½óä½tÃc¼¨ í;,+—<ñãѾY+ ¾Õ‰T>寀>ÜB¼1h‹=iN>šÐã<žÈL½, ÂÅG0…=2 }>/¸ù½c¼�HÏ„>¢m¾ÞG|½3ƒ¦½ ï�¾Šf ¾Xñ¾ú¼e~ؾ½É>1ɾÚçÏ>Ã>å�=¾&Ù•¾.†Ä=®Pø=5Ÿ†>.q>ã j½7±T¾_þ=¾•º¾Yf>0ž�]'¼¶Ã<(ôf¾]1í>78>¾‘‚=úÊ>¸ |½”Ña½)jg¾“œQ¾ÛŽA¾ ¡X>æp‡> Ÿº/=;éè½P.µ½Iã½s >¾tè½¶Ö>8³²¾È὆†>9ï‰=aÚ—>ô®·=À ¾ˆ5©¾nVO=b1ò½F—õ= R>qŒG¾ó$-¾“­ˆ¾šW�=?V>WŒ;/ܼšgÿ>í|…>rã2½¯‡R¾_k¢½òÀ轸Vé=冞>òZ¾åÑe½Äk›½SâÕ½¿xä½Þú‡>KY‚=æm>¾À> ';½f’`¼0+½5=±¾ë¬$¾ûÓÀ½v‹¼ôW¾ÐzÏ<:¯‰¾Áî¾fÓ(>eüô½`G<ØGm½~½ÊÖ¿½ÀÀB¾*(‡=¥Ñ>žö>Œj`¾•G;Äf(½¸gÓ½ÚË >¶wë½óÀØ>¨¦½‡;¾AÛ=$çÕ½×`ÿ½0ÊÒ½ºÄ>³E”=Ç3¡=° ¸¾=_í¾E=t¾Ù=>««>Æh=²-O¾��^¾V«Y=† Å¼ðÒ>��¬>�=Î4>ͱN<§:‹>æûG¾†C/>@@¹½\X³½½Ç%?7E>©Àa=ñc=(àG=á×¾?ê=ÖcÝ= Ý<=B¤>©jD½Ý™¤>¬¦ã½ÈBr>ƒm*>1¾µ‘>åò¾ÞT=£g)>ЇA¾lm©¾ãš½�;2¦Ž>7Ë=¢>à¬4¾Í-„¾V A¾�ìW>o "½2‘="¼¼j û=—»P>å/‚>*m�=û‡¦;¬½0½s<£ô½i¶Ú¾îgÒ<`'l=ÓE½Èû=>{˜ >¢ÚÓ½"}<$Œ�¾6x_½,L=Ì-È>¯)b=+ð;¾;>Ÿè½�¸>¶Ë¼W�=\pÆ=<Àؽ®¶“=¬^=7*>¾ã¼j»FjϽën>U5§¾Š¿¾zÊ»&¹=¼€R>är2¾N¤">w,5=ÛÅî=kj™<†½„ �>�N.=ìhª=�†%>xª´;I>Œ�>]˜­¾·оI(>É&L¼÷Û=‡«W=ÇÒ�¾ßºh=³Ú�¾åÎ >º` ?Ÿ¦=Ü·‚¼½ —¾l‡=È·ï=éâ¼*°�>v>§¦ ¾Þ§Â<Š™�>ùѽ=Ÿ÷>¢·¾×h°¾ ÚJ>") =¸?¾ï‚±¾ˆ>e„>Y <ûq-¾Ã¼¸=Åã=ˆ‹?¤*¾(±=~н &Þ;¯·o¾ó×><·Ö=[ >WÕ«>Л?¥.>Õós½“Á<¹ªs<õã½ñ$>� g=®q†;!1>•_ë¾KŒ)¾Õ C> 0>½†�!¾+H¾‰1>bƒ=Dgñ<£ú¡>ͦÑ= kœ= ×¾�…P¾ê5H=°x ¾Ã¡ê¼Î!’¾ü†Ÿ>ó=¼�¾@‡¼¸F ¾•= ¾ÜF¾$¢6½/®Ž½á “½øj›>(ý>f]¶>K2¾ S]>ë#L>ÿ ½§¤¥>‡Ú�¾sX,¾I“ ?Y…“=ó3νnÕ«=¼€!¾•2Q¾fg‘½Ð¾¾îP>ÐK^>C‡¾þë[<ô,©=]Èã½µy>÷i,>²2=‰˜„=wºk¾—â½BÿŸ>—!D½&©¾ßlƒ>• ȼù ‚½©ÍQ>E>'>ˆ=è‡=]¯<‚ëI½Mü½®Ÿ¾£LJ¾Û >†ú0¾–Íü=Ž¾Ý¼C´Ó=]’>.Jƒ¾Ð¼×>ìŒb<Qš=ô/=¾ÁF�¾Gš¯>2Z¶½ÜÆR>ôGø½‚©7¾x_i>Vuù=ËðB¾I+¯½ˆgæ½’Â>>e.2>#{©>ë•<8Î=» U¾ C>9Ö–¾1ŒA¾Æž>4Y÷¼E‘|¾�^Ⱦ?Ë<>¢@¦½€5ÿ½Û­L¼“™c>µ)½ì¼Éº�7�=r)Ὤ7P>ò…½â{½º=Ò=DÒ¸¾P>,”Ù½ÞËC=ãÈÔ=1Ο½pОSgˆ>‚¾ƒv ¾™Y„¾ëAÕ=}tg=ÂF.¾ºyP½“l%¼È~¼Ô,ñ=­Äë>WšH>>È!½ËÞ«=æ½ûøú=vª»>3-¾´ý7¾®‚>ê% ¿)=gUo>_ŒÈ¼>߯<Ї½…˲½!€i¾Ls?"�>žÀ¾š”Ù½ ÆÚ½Ã±k>ê ì=÷»f¾Š—n<ÌÛ%=Ì(K¼>¾R>Ã!ýb¨é½‚Á½¾ˆr’> ƒ'µ>,û>¶¥í¾;02=Ëk >eãÆ>-‰Ë½µ&>Á»=õ¯¾áö$¾qÆ�¾hè¹>ƒàs¾Am•¾!ê¨=™½c‘„¾ μ~ 5>ìç½Cc¾roŠ= •¾ú ð>K{a<ßê†>q@½™Û¾IYÌ>˜4æ½ h¶=N d¾Ø¢=¢“="2>ZÆ ¾®¶j>’Žˆ>Ÿ«Œ>/^=Áv@>6lC>cC¾RÉD=ŠI=u× >y�¨¾R㥾Á*á=Ò÷ª¼(ÏU=UÃþ=Iæ¾2̾˜¾éú>ÝÉ=}­¾:”M¾¦¦=Ö‹�½âµD½¹Ý澆°­¾ †¾hü¢<¼µƒ>2æ%>©ó„¾plä½Q€>âW½ò<Š>™•â¼  “<Žèü=Ú�¬¹$�¾Ð9)>:†¬½}zz¾Îɧ½GÒí=aJмcÙÞ¼Ÿ)t>¸ €>àŸ€¾À¤²>¤ÇN¼›*2?f ½òý½Ê9¿Hヽz(½.³X½Õ;¾ �¢=Yæ–>꓾Ý`í¼oO>oùa6}¾n¬Ü½§¬ì½‡D>¬˜<yͼU. ¾ºÞþ½¬*¾ôö>a¹I½knz¾ËU¾Ó(]¾}„->°OI¾Ü’>,wZ»Ss˜¼Ä�6>§<žT©½oÛŽ=ëÍ›=3bd>Ä–¾)ä½Àp¿}–ª=Ö‰j¾ä¼=Ä>ä)E½ E¾` ,>yyP>€ñì=¢Q㾂�”½{l¾uè{>Ç?0=ÕžD>eò1<‰¾XLg>S‚6¼®vî=#Ô±½€'Õ¾*Öc=FJ¼TÙá>¬iQ>¼V±¾�73>.¯=kS„¾�Hƒ>³H¼=\>>Œs¤>/*¨½ôÓx¾ÆÂ½Óåÿ=Á?¹¾ÏD =›XÆ;ÝLY>:<ˆq>Žý=«€.¾åœ¾7Pú¾ûâš>3Õ¶=ÁÛ7½ÝiȽgëh=ºÞW>NÒ9>Ö˜½=¸•¾2S"½—°ç<ÖÀó=TKó=Ú”%¾2ù¾Lä=V2¡¾z>·O¾´Éõ>˜/4=ôž¾×rƽ\½½õ+þ“Æ•>Ð}E¾[Þ¾ÆuÉ<ˆAÓ½pz¿e>>Q´F>JZ ¾;Îi>ˆ¾>n;è½Vrâ½3©=¨E´=–u:=b?= 5¾°ÛÔ=—oļ—ã¿>�7 ¾niÊ=i¢§¾ÿ„w<••¼ÄA>S)>&>êEš>:i=Ž÷�½Ä+Ó¼L|F=h>O>›l#¾ç)C¼“)�¾xLŒ>Ø—�=W¾Jx¾Àã­½_û>fJǾ}N>̾è^>¸–Ä=¥•„=€¬>_Úœ>ɳë>×nV¼ZVQ¾° ¾%ûë½ÐS>šÇœ¾Á2¾åúç½â‰h¾9 ­=Ñd£;‰z>ª€*=5ÝE½aÇ¢¾—Ãß=|3¾Ó*>½�æ>UÐǽ¬z¾þUB<0åT¾ù„3=]Ò¿ãZ¥¾ß ¸¼ÔF>>Ô€×=g“ƒ¾ïøK¾#_ɾÉöý=ÙÉæ»Á*þ½êÖ|=v}=0à=¢@=\^¾¾a¬¾ËY-¾TLß½CØ= ó>nØb=kj¾Y/t>m�Ç>d½<_B�¾Eæ-½'ÈÆ¼â®>µ1•¼Û©==p¾j½{k¾—2>³G‡=r>>Z½¾< =Ðâx¾~”½|‘a¾µ%۽áW<´ÿ…<[]º=Mq¾Vz–>¼¹9¼Ì“¾>¹Üû¼HNF¼�zZ=;T¾ ½ùÈ:¾ˆ¾Ý¼u=V’>rܽ 6Ðh&°<¬‹~>"Ã`¾Ìõ’¾™½9í¼ÜÍ==kÅc=q8 ʃ¢>«‚=ÓA:>rÃQ=g³í=`œ–=BÕ­=©¯o¾•7©½¤V’½Æ‡(>>½�> â,>… >ýäy>Ùœ¾ÿ;¢½Á¸ú=Ü †>ƒ¾ày=á{Á½boƒ>ºðî;6Ùº¾i„¾Í�y¾%xŽ>¿£¾{ü¦½m_[¾YÅ™=•Ræ=µã½Û´³¼ˆãY=d#½õ‡�<Ï‘>'Ƨ¼q†{½¦|ä½V0¹_v•=q]¾Í˜8>¦Ú�¾¢‹?Àl�½{ˆ¯¾Ø#¾ˆ_¾å=p½Ùá=åǽ}· ½ õ�¼ìè½jhe½VÆŽ¾K½XÕ°½$Âå=Ýk~=`×Ä>½¤kú<|bX> ùÍ=߀ç=�8¾áù�>ú‚à»NsD¾@ß<-öd¾­JP>yÐ3>EŸ|=¥ ð=±©¾Ëâ�¾¸—=�‹á¼Ÿ™—<Švm=Ý÷3¾6ÈÕ>T„ >�6Ó=€~½CŽ5>Ã׎¾šØª>�~—¾J^©=Ê…½—Èp=vÕæ=Û.¾…X9a–ǽˆ™¬½ �=:>@‡§=0à> —…½²7>zõG<§ >í¦¼ÝÁ¼ Õã=sïL¼Ú=±½/FoÊ*¾ìð³>æ‚Z=oò¾Æ¹1>þÏ>ñN,=ÑäF¾¶u6½¿_ô=Æný=5€¸=§ñ¿¼ðÚŠ>Oî=¬b¢=�•E¾¢"²>µa†>P=Ë%>ºbK>UÊZ>‚r–=¦D=­ªÂ¼ƒÜô==¾ )O>'v�=SÚh<å#<» ™=–굄íí=gž¾k6½ÜË>}86½F¾ØÞ¬<1’¾ÿÿ¾¸´@¾ºr(>/Ä=;B¾eLR;ó)’>[¤¬=!ú¼K�¼vw¾àH�¾±×¼@ö—>f˜>ùŒe¾ï@d=ræT>úªž¾kŸS¾³ki=Y> ‡=ê‘y¾¢K�=½“¯0>¥;É>}ý#¾œ¾¾ ,?>H8P=�Ÿß½ÂŠ>‰µ…;Pº…¼Fd‚;ìμÁ\¦>Œƒ5>©B©½ÿ°=,vô¼¬£Ý>ä!ѼŸý¾È•ž=‘À=Mâ½.ˆb¾Þå…<µ¼å<`r>6é7½3Z¾±œ>έw¾¨Ò">Ëx²¾x ½ÿÙY¾ªŒg>É36¾<ß¾94x>äà>H>"Ë:=öÁ&¾á=46f>,ê=idg=Ì˰½L7¾“§WH�>£•äNƒ/¿0Bè¼ùQ½<Ɉ½¼>×S2=�r’=4q>D<8˜‡½¼>0¾'ƒ{=H#4=°sí½y½â�.>ˆªW¼TÊ¾ÄøT¾9„“¾†¾œÃˆ¾/è ¾Œù½þ>>Ž1ÿ½A޽Ú=6=/÷Œ=NBÕ>·e¾}H©¾IÐ*>ÏbJ¾Žƒ=‘v ½]³@>!>îºG¾ôj™¾GEͽ V¾hä¤=j>Ú/¹¾^Â>§œ>Žûý½÷Ú¹=f¸¢½YWþ¼ƒÈE>›Á‘¾-ß+>;%Ó¼‘yà<²øô;é˜ç=p#¾Ë°½áTw=¸C@= O§¾€Ñ}=b#ð»ëY†>ÞpC<_¾z¡ø½B‹½’+¬¾ÉH=G²c½Þj%>\ �<Ôÿ!½à[à½OÌ…¾eî½S}ª»�‡š½ÒûÃ=ùÄ;‹Î>�¾õ}µ½å¢ =Wõ=¢~½3H¾½E°<)Oo>ÛÕY=ý=.=˜>†'>K­o½˜ D¾éû¼mA«>\rQÐÊ>Òнa¢¾.Øh>aʳ¾ó5b½:ª½¯R½o:Ò¾ D„¾€­Æ» 6>HϼL­¾¶‚�=ðŽ> +7¾„¾Ý£3¾Nïj¾TRÐ>Ùî>V‚=Z¤»¾·Ò½�v>ö_+<>>©½y¼= Þ > 3�=~*>nK#¿´$I>ñŒ½ÿR>ÃÎs» °�¾^–)¾ã¦1¾qê÷=“;¾×$L½ŽÔì=¨Ùl¾†\=_™“¼Hè½ýðƒ¾I¾ƒzð½ìb¢=‡ —<Ø­>·'Q¾ÉB¶¾ÉVݽÛ>˜'Ò=5¹y>±7 >E¾Ø-½Êêb¾�©>E#>äež=Ó¬Ö½ïð�=SD¾7\N¾b =§5>’ ˆ¾dc­=ìc6½ ƽ�Á>åþª¾t©w=vƒ>¶=¾�ÿ½§Ÿÿ½µã¾@Jû=KÖ=Ç™Á½Ûbê>©Ëe¾Ñ9µ> Z¾')½UR¢>s Ò½I¾s^O½¦"=!Æí½Y‡>'«©½6(>6¬T¾ÀóÜ=âñ6¾¿Êµ=µ3V;\>’„ ¾BgŸ>‰ŒË½ŒÀ”½­ƒ±=šŠ¦¾±Ö¼ªJ>V·Ÿ< `=WŒò=��q>›3f¾ñ@?>_¾5<°>‡©-¾þŒž¼¿s^¾Bç<=²›H>ÊT'¾î¤y>šÒ¯>Ý>½†½çV¾Zgľ�¾I¾’û¡>ô>1ºs´>L²/¼äd>|¡õ½_PúElm>øry¾—–‹½9q,½ÀÀ¼=ì Ľ,è�¾çm=40=Íû#¾>6=Ö!s½Ã2¾O*™¾Eom=¤ßŒ>òW =TÇ>:Û€½\üÀ>f¡Î=i!ß½š¾üÕ£=6%ؼ¼© ¾4M5<‘D¾úL‘½2â=mHL=™ð+;9¹(> í²¾rkǾß2k¾?‚u=·4¾œ†Y½½Ä3¾åú>ÔÖ¾%)b½[L#½'½…¾$«w=ÓÀ×¼ý!Ú¾ü#r>J<·½fɾP¾Ã曾~ii4‰½xE>4™Ñ½a¿2¾ò½.‰‡½ ±¾ g້*?3ª½{8k¾Õ‡¿Tk[¾„ü2½¦¸O½�m’½×ÅW>èõ®½Ï}Ó=�ï½JþK¾GþBH(>œ"a=ÏŠ/>UJ3½iÉR¾*ä>¯Ð¥¾uÙ¡¾R¼,Û.¸ •¾"!Ó½šÕ½×ñ±¾øNI>¡ÿ(>u�ô¼u€0>1½½ÅA¾õ¬š¾ûÊ =‚?³=ǽ½èj&>(¶f>:`=È:нsF4=#ñ»(N“>®>dø½NÀ#>Ü.\=Pn¾V>G¾±¿¾ÀŒ#¾£CÉǃ =øVò¾^(¾ÄiW>÷n½˜`š>\Z‘>R!m¾¾é=Ïv=>GØ�»b )=–O½/çнÐÑ9>JiK>ßFÎ=� þ½�ê6¾ŒEW¾o@¸¾g²=/!‚½–±§¾ ªÆ=­wˆ>[£§½�PŽ>6>Ó¢1½‹9<‚9«=)“ù¼0{˜½1!�½øÃ&¾ãå;¾ùÈ=Šä=é3>3>烉½ª>ÐPy>ƒ !¾CŽ>öz•>º$ï=�Ö@½�ó=˜Ä :XÜt>â0½²”9¾"ÈI¾FdB>º/<,¹½ ¯;>W­¨<ë`¾è½„¾ØŒñ=3)î½z¾•Ð=:`X>hY�>�û”>:�h½É!ã¾ËQÙ=Ã�>ºýU¼Öóe¾Z]¾£¬j¾qˆ€>ŸBv=,ľP ¾\;XU•>6–µ¾>^’¾\l�¾Ô‘Ñ óJ>¼s=Ž ¢¼‹ãоäV%¾ýÃ;¾‰%U>lè>´Õž½z7¾Ü@ɽãJ= b›=‘8¾Œß?;Úî<Α>ö«==í½+Ë–>Š2P>Æ #¾u(¸=š™â;+û™>Èa>�þñ½Ç|Þ¾4‹>¹cn>”çI¾({¶¼ä»È<ÇÜ=†-¾êÙˆ>éÖÑ>}¯:>Hø¨>Ýõξ¦2å=ÀC¤=£…¢¾�€ =‘z†>ò\>Ž¿H>“нj#¾8êJ¾ÌƇ=ø^þ=«Äù»òi½ˆ©L½˜±=Ö{(¾é½#½ ÆU>FÎ�¾Ÿ‘½½ðà;‡+ž½”Eó=q¤E=BgB¾èq¾QL>#ˆ¾3䕽˜˜›¾žAž½BL�¾]i¾øŸ„¾¼c�¼’)I<Ójï=¤ø¾°<°½w­>—S>ìi¦>¼›Ã½�·½ ýÎ<Ê^Y>� > ]�»"R½+•¼R*>r4a>=*�¾z-Ò=ô>Ý,о¿Ì>/3>«Q‘>ì0�=ž8f>¿�½(©‚½€•À=>½¡úi>/Ïq= ÃN>Ýy‰=ˆv¾ñ6¾ž·Â¾[v¾})½v0¬>"�ž½ï Ž>^Ÿh>î\s>›tE¾2´†>¿4N¾}+¾&,=6õ޾¸xÊ=Òè¹½<Ý,>´@ ¾Ô~4¾±”w¾¿fu>ÍPB½†þî>„Qr¾·KľIÀ >¡l©½@3 >Ÿ0?¾”hš½òv¾ºŒ»žK½7ôÞ½KYÖ<ž¼™>a†÷½åÌ«>å:¡>Lµã¼Úž»b•‚½7 ¾ü=¾“é=F³Ž=ü->;Uê=RHƒ>]çX>(7d»ÖwÄ=Óûú=:¶a>�'>Òò½0ÀÑ=S¡½«- <½">{õp½Ñ^¹=|/¾Çec¾ñ9u½z>ÀX>Mfk»ÉØ =hõ!=¿¿Å½{ι>n«ì½TUU>‘qS¾áÏݾ�ý©¼i¢=wYξ,µ<‡™d>j½�j½ŒŸ¾©#A¾ö—Z>”Š¿¾-°s>åÄ=W„d¾^,¨¼5òœ½ñqK¾^Ãn¾Ó¡¾|‚®=vmö¼ƒÍ> ì?êf>з<&ºÄ»Ãü3¾òZE>„^¾Ît¦½({6¾F E¾ºàW>h‚¸½`]�=Ñ£›¾Ùý‹>ì- ¾ÉpŒ>„|¾¯›·¾ëc|¾²R‚¸'¼è„,½ž²Í>�©¾¨ò½9¿d¾©äÏ=}Ä»= dï=»Z¨¾EQ½á¼>fÞ‘=ó[×>’ ‹¼G�;Tˆ0¾m+A¾Jò¶;$%>l»6=µ. <�ʾ*Œ6>(ÉF=ì|ò>+ÔÇ=1q½Ú‘>�êZ¾tIå½Ì²=—‘–<Š£>Ï=¶B[¾4­Ù=j ý½;Œè½“qμ[ËY=BO>줕¹©0c¾Ò«¢½�ŠE¾ d6>ó,6>>켺x�>a´K>‡±�>74K=W*=hì·¾ðùؽªø9>Bž> 7>Užq»ûîA>ÁM>á½6?�Eý½ü½6>¤áJ>Š?‚¾áu�½å…‹¾ð>4øš<^Æé=âü(¾F5&¾â >«)½6¹–½ßÉb¾'{ >ºW6<ú¤¾.A^>Œº�½}½D¾Y ¾�cG¾ÒÌþ½½T“¾ý¯Å=;Ló¾  ¾Ø¹8>ÞØÚ½R>[‚»н¼^F_½VÍ=,âì=*:‹¾¢p½µž½\ã¼D¯„=~2伃aš<ʾXT©>Ôúr¾ù¿Ô>î^V¾Qb£¾ bI¼¯a¥¾ÍÚ¾/Ñ„¼È½©=Ü4œ<&É^¾2£§½ˆe%¾(ܼe ½ÿ=ѱ~>‰@¾O'™>:h¾Ë¿ø¼Ï*¾¯!}¾�RG¾ñ½ò>»T¾­G¾ªŒ«½—w¾Õ¾­¡>h#>d¼˜¾ë/(=È©¿½h±œ=1ûß=w”½ãE¦>Š�=88R>JîØ;¨„>Ï6û¼G×£=l#=@J¡=^ºž>ß(Ò=�Á>«Œ=Øs)¾×qî½,�½.¶¾$¡ÿ=a�(>Qä¬=‰;¾ZS;¾‚P6>¤’¼,ü|¾]ö?Ó<,>.§½ÁÁ¤=™µ?=,¢¾öd/¾ìzû=¶¹="5·=¼Èv=œ¹r=½ÖJ=cèÄ=2"«>ÇŸ�>]<©½)@W¾²„Ý=‘³ >éÊ�¼¦>Ø3‰¾Rx‰>‰7‡>^½@É>;V&¾\6^½¶U3¾Ù/t½¯#*¾b0> Mƒ¾|pX>ŒÑ(¾—sf>õ2=�åô½�]=> \½+2e¾Ôôð:îßõ<„VT=u¸­½7�‹½¶"¾]2¦=i}½wG¾ ? >ÏÛ‰> ï!= ¢>¸¥=öËU>H_׃> ¢¾�èÁ¼fdª¼¢ó¢½Š6¾3ßá½Ê(�½2M޾7Ó‹½{G¤=áT¾“}Í><êt= ‰¹Œ}¾†àa¾w°Ÿ¼Ví·¾þ:œ¾•^9=e^¾×Þ5¾ € ¾ö>8­�¾Ýâ¾6e¾¬Ù˜½,²Š¾)®>É?½½7�½*ÿŸ>û�¾Lå½ k�ºu‚¾©�ƒ¾}?Ž Î~½µÁ½@üR½B_v½™Ûp>f¸½=Éé;¾A^h½§¾gW=»AU½Ø9¼>¾R°:õ-§¾žÜ²½Ã ¯½Øx<>é¶ó;¼s¶¼4ž'= t=þQ¾È·;Š])¾* ¾8­»9Úϼ~ÐÔ½ˆ7‡>¯á¢½a\= u¾zfp>UŸp¾±Å½ÆÈm>&^Ú¼�à’=?Ñ>ˆ¨+>¸à–½dj >ß>U—>ƒ^x>äµ]½f>ª†Š¾)„k¾~#Œ>WV>p-/>a;'¾4½À½¤¨—½í{¾œU̽ºƒ.¼êÝ®¾tøš]sU¾¸> ÷V¼å?¼\¯ì= ÉŽ>õ>b^x; ;ý¾‰Ÿ©=–L„¾Ú›2½�j˜½ËÆ0¾Ä£¼Ãñ’¼×ÚÑ=óà»�ÜF>£¯=°áO½KÄ>¦ñ=MÕq=â�ƒ½¸ô¾1‹>jåU½Î‡¾º‡>˜Úü½7̃¾1wg=Бt>g ¾"gG=%u‹¾€šâ½ºK‰>§y=AÝ>F0½1é„=£j=”´¾NÎì½íì§¾Ñ5=k¤¢½ÏÍ�¾ðؾ�Mw=žãÙ¼â c¼8Lü½”9b¾3«™»ZOô=ƒX½J›>F/>H¾´]Ú¼¶°†¾Ôƒ>Dš>>7ö=í¾!A•¾úߥ=Äâz=š_>_ëû=‚aÔ;ŸDè½—s«½+Ù½I~¾ =żö½tX½6·>ð¯> q-¾ñHE>ê,º=Àö>*%>ó >Šêz=W¯<(ÛB=�/= 껾ÊÙâ½:õ”>gà< -§½�“(=#¼)©;½g™¾�…;�Dé½H�>³t‰>tи¾r'Í= ™2>$5¾oÿB¾å\>8¾å¦y¾ÔÎS>c%®>.0V>¸Š‚= Û¿¾&=Ì5í>ÏeŸ½-—>>þ“«½�În=Šñ„¾M¨†¾²Q ¾Äh*½¬´«>c5°>„>=B½òâ~¾\ãŽ=ÎO>(€ >mþ¸=·Âþ½.Ô<„äm= Ä$¾¤M>ãž>ôH¾S¬¾˜-[¾le ¾ÁÍ„>ú¹•»$“ƒ¼þu >Y�¾´k³>Wù‚¾”˜Â>âô…>üµ½Ý<¤>óŒ|>',À¾çH>ßÈŒºdl>a$ó= ÓO=st>½bHf=F+±>ãtH¾Á¡X½¸®«=ø‹>i ξª̽p¾šž€>ÁxÖ= è˜<“ëY¾«b >W¢Q½rkÍ=,Å = ­¤=ý¾H/Â=F¯™>³…>ž*·=>áC=lù¾ÿ±¼=Þõ ½ký‰0p>—9¾Üœ,¾'ˆ¢¾AôÙ½ˆïǽ<‚üª0É=‡Óð=À£>FïÆ=wo>�x̾ñZ„=»âØ= Ë¢>Û`ä¼ý¬×¾U¸­=·”w=´¿î<r%>nº¯¼–M)½Ús‡½½K3>—‘¾ ,%½!·¾–Ã4¾-ó¨<´ µ¼Ot`½ÈC£½þVY¾ >.º«>µq¾¬xð=&4²>‹�m;PÅu=Ýëb¾A®B=z¡ó=šY[=z/´=o‰Ò:î==:!§<Ä Z¾xŸ¼=Yåm¼š¬v>÷Že> ™–:³¿Ø �==þõ½®%Í> ¿0>N�ÿ=t_?>°Œ:™>甜;& W=„g½‹’¾‚N?¾ËŒ>ý�¾PT›¾z:>V(«>«ñ»¾®ÀL>„¾u=Ø7B<»‚нƒØ ½-ÿ½’tü<¢ºÁ>2¯¿óN.¼îˆz¾&S¾lÒ¨¾J9Ý=º°·<µ#?�¾Oà½ç†¾™ =ûhнv•X>ËŸ=Jþˆ>“ÒÀ½ ë†=üYã<ÜàY>èeq=éÛô½Ÿ‹¾w‡>ä Ñ=ßš8¾�Ëä½R ý½Ë;>Ô$†¾ ±ö;�ür¾rý¾°_=«ñ€½«í=>Ä">JKd¾Wˆ-=½…š=tmd<\»0>Y˾Ů>–½ž¾Æ;Á=:¾¾”«¸½KkÏ>iQ¾`e>¨æA½*e½mX¾“VT>6#ì½ ô ¾¬SÊ=ªc̽\¼ý½‘ÜÄ>̶ê>¥�¼R4¾!úÒ<ø›¼æ>K¾#�9½&¬í½ËæL¾v³S½‘í/>ò-y=¸G<=RñƾiÙŒ¾ç9ܽ|ý¿¯Þb¾4Y=pôÓ=@ƒ=Úy\¾º‰>‚6¿=ÎçW=t�¢>Úô®=ž¢„¾R®³¼s ’¯´ð£0ƽŠÝ€=c,w½?Þ�¼‡tY¾öJ¦¾ô¦š¾ä.š>‡£^>„°Ç½ý ¾(�/¾yWнÅ"0<Ð:ê=�El=¥LнŸŒ ¾'3¾ê q¾œc5¾ë7<™×>5h±½Ô$¨;ÄÞ–¾•’b>'Mž=0ǃ½Ç"I¾› Œ¾ñÖ>"ü½ìd†='à¾UC¾‘ñ¾¹U½ê>¢=ÌX®¾GBù>ïÿt¾0ï;¾*M޽zÖ_¼z¾á™¢¾G’¾5ô>pìµ½³ø>ÏÍ >˜„–= Ms>;+Á½©®½Pðì=‰g>üþ’½Ÿ½SX¾M?f=çI¾ËÙ;=ÆÃ?ëª5>ìr¥=ç=²½×Ér¾iÉ¿_µ€¾F'±½T¨.¾äЏ<µ»¤=™I”=w´¾bË–¾òÝ:½¿*M=mÑÓ>°˜>ô6|½†pݽ&ľcI€>¨íD>6‚=ÌÛ‘;-B!¾œÆý¼­æj¾+�¾>FN~¼¾­j¾xÓ÷½@3¿wÆ`¾Šý†>×㢾¤øª¾Ö%�¾>ÀE¾rçþT﬽pc¾Ã÷!½ÔÞu½þ7°=v/ý¾­½\¾L²r=VêM>Ò`>”g¾7 ½zÝ¥>&1½ùÝ=Co>®?>e®¾äÇ>4ž}ì–>ê>Q¾(1?Z÷7¾ûœ=¬Xʾ„Fh>Q&G>7ì=îg¿¿G¾4^ɾW8T>â_=ÚP"½O�E>޹½õã½^>¬­Ó=1мÕz^¾ðS¾ÂÄ ¾ û<]oJ¼Õ•ù1|æ½æCüë*¯=ºÖu¾Òý¾ük€>p@_½:²½¾ÉÅ÷=à'ö=V�!¾¨·½€!ð»df ÛŸ9>ˬe=¾õW=H¹°;ð\;v+½9ü¼=»¾ å½¾�7�¼ª¡“=È·Û=BBѽ•r–>°Á4=Õ$*=Ðä·> /‡¾>[v�¾b®½%Lc¾{f=A†›½ý,£½š_8>G”O>j�¼6Z¾G�޾â\•¾Çaƒ>Ð6ƽmžŽ½`A½vÂN=¼‰m>–¥3¾‘>2ÑÚ=fÕ>õu¨¾j† ¿tùºÿ ¡>*€I=Z’=½]>°x‚>®ðy¾; ʽ•>ßô ¾3)=|^#½<ª~¾U�>Y’'¾k�¾8âÂ=º¢½»´»dû7¾Z„½á%‰½x­�=g¦�¼§É¨=Ÿ†½äÏp>4þŸ½(57;„^>­%< ëÿ¼ø»’==ä±=º9)¾’¨!>Ä…e¾„7M>½š�<5ì>OÐÞ=nõ¼—ˆà½•¦¾\õ>ºã^>7Þž>ðC:hy½™w¯¾J«¾>èq„>º!¾r™¾Ÿ‰$>âT3¾"ëɾ8•Â>´$1¾þùn½èæ=Áœõ¼j}+<�ºû½Úˆh½“߃¾À„E>0`8=ÿk¯>¢:P¾ã’¾^z<ÿhŸ=‹À>¡˜g>•ª>gU�>œL¾ ˜¾NŠ<ÿ;Ò=?¹<ˆQ†<7>æx >F•�½äЕ>y•>ô^<Q‰>‘Ô¾®Å—½7—‚¾+VU>/‚‹¾‹´x=9s™¾´š¼µÂi½Ö.eÓ>`=ÄÑŽ¾íw?½·1?>—D9½â=t<ò–½h²Ÿ>æÑ#> >ä½¾,f¾qV†¾B»>NÀ¾üÅý<[!5¾Ñоmè–¾£oF=ÅÔ^>ª3a¾Õ?Š>uŸ6¾¦>¼—¦¾ì¨»2Ø=º>>c»<Ì�á½ðÕ=ãX>+E‡¾íS{¾mµ¾$>>ç†�>9’/¾¡ñ²½u´>Nlr=|a¹½2lr¾çØ5>20>–¥¹=R餾֙>ö©>®¬Ó¼‘Ãâ¼ÓJ¹=$¨¾•}F¾•›é=R$¾Y«=Óà >è‡/>�QÊ»ï¸Ú;5Ì>Òº1>¼¿¼½1çÆ<³H=¼mø¶>PO>—U½Ç%¯¾¿—½'Ô­=�³Ñ>|S‘=éP¬=é˺=»J1¾åcª½ŽL�¾÷0i>®Ê:=ñæ>Ç®¹¾Ñíf¾ÔŸã=¹ŒÌ>*„i¾¿íð¾¸*™¾áÀ»ë‘;>sý<œJý;N+j½ÞÃ>.�>ä¡�½’÷†¼·'^>šªÓ=%´±>—`W>8äG=]`¾ÙEâ>ÙnŠ>PhŠ>ñDo¾èk>S$ ¾‚N©½  ±=\St¾>ǽ¶º½ ;ܽL‹þ½Øw½-·)¼GÂU>V§½êr>o¸ª>Ý+�;é/³=©ç‚>è¸g¾°Ê€¾]d:>¸ì>Z>‚Gå=µ½ŽÇÁ=]*‰¾aóX=ˆb[½j*q¾W[v½Ô^/=€C>.É8¾Ü¸S=L›Þ=éž­½?åÝ=£&‹>IÖ¿>—qÔ=žÛ=‹ð‡=ñL >Çf>Ä:ÿ½†.n>W&™¾Õg>,)>OƒŠ¼ù“Ú¾A˜I<·[­=Htè=òs’=7E@>VD‹=yÄõ¾ŒÖ¥>F�>ZËî½…K>ÖÒ/>J*>›+뾤Òù2‹G>êî¿>Ã�g<·r½þ·…¾lâ@=_,x½¶x”¾´¥>ÅJ–¾Bq�>­@¾›œ½î>¡=¦�3¾DÔ~=Þ:/>-Äž¼•W·¾ä‡Ü=u0ö="©>À+%?Îÿ¦½Üb¼¤h7¾Úaž;ZÔ®¾Õ�„¾¯›>›Ô3=¯<½=�q»¹\ù¼û¿^¼{!›½v9Í=bá�>3ÁX=#·¾¶æG>â¦P=¦q”=zò½ÝI‘¾íÿ<¾FJ�='R>Kö½Q_C>± >R$¾ôáš½*ÝÖ>-¼¼;\`€=¦�>½uåZ>g$¡¼“ï=|ä·>‚†9>Øñê¾_.¾MD+½Þ<½t�¾Üî>ž ¾¹ H¾È >ÆŠ'¾‘¡>·Ck½Ô*=—)Ç=Bø¾qÉy¾‹'¼Æòñ½º$>ÙÚ>‚YJ>‰¤=ýÊç=ªƒà¾’ô”>›1´¾4=½FÒ$½¼ÿ>•A—>Ž^B½†v7¾•Kí¾ ¦“½Y*o>ëH,½§?¾—=‹õ¾jí=c:ä<^Ìh¾“½lù>D�ƾlÐ�=ËA|=¾Ò¾uÉ>;÷¸z=(“Š=îl"=¡¾Šx(¾>‹§¾8K6½oqÀ¼Ù5Î>ÇË=ˆá>ÙÎ >M�?e `>xÕ:=”´`>ïì¾LG<Ç䋽‰›½«ê³>&­¤;С–=PvÓ½5K.>®©q>¯‡ä>‰8‹=v,†>j~¿b­=ðÕ�½LCÅ=¢¨N¾o¯¼ãÝ÷=E¯Ä>GõY¾DE>î%°½m®z>²E7¾Ÿñ<Ã�¾¯ý¬¾Á3>}·=ð ]>Ì©Ã=Ì%U>ZàÎ=e"¾,è¾ÞR¾êξ©üŽ<âŹ=µw‚>|­‘¼=d/>³Óœ>B€°¾Øvy¾>£½=u¾½õ‚´>í~(¾q?þ½â„¶¾f)¾æ<ˆ>Á‚<•_¾à$>Ø(½=-I½éY>²ßË=�ÁK>pø$=²Û¾:ãâ½Ä·—¾–_`=ˆ»4¾mƒö½Ð‘̾“¦>ßÕ/>mNÁ=O†¼ân’¾®›¾ÈK/= í2<£¾½Ô#(>“\½L>Tq¾7n?i£á~Û‚½4‡«½ *>÷ºž>;”»éGŽ=âpä¼F¸äUC¾®–.¾9à.>>>�ì=¿æ¿½%.d>¿Öw>Ç‹™¾í×D=2d¡>ðÒ¹½" 7=„åe>TŒò½¬OK½IÊ¿ôò!=ÅC?>â±Ç½b™|<þq>’L‚½Î*>ÀË#¾c;©>󳬾lCÈ>´ŸÖ½Ö…=Ì›{>§¾‡×=ð»@>Æ3¸¾cÑ�¾ #E>?0®¸»J3¾é¢Ž¾wc¾ü­Ï8ç.™>W,œ=õÐ�> pH>홽®� ¾Ð u½µˆˆ¾×ĉ>|dL¾�ì>w@‘=ñ�=ˆ4¾†¤=·Â)>çSW¾­ìµ»®Þ�¾Îš=Öå+¾ê=ªˆ>¾Ð=/�j½j©°=¸Ç¾ò�ャkɾ‹£w>‘dœ¾Z°÷=¨Ü„>¤¯»"¦ä=ê@l¾§øÇ>·N²=¬÷½La¿½5”â¾^€&>*Ͼ¾µ€¹=8¼‘¾Bš¾K!o>¡¸¾ qÒ<7轎•>À·>?û >�¥¿mö ¾\æ<íÜ>2£=¢£¾bz ¾¾’5>8E¾¶GÐ=rWa¾">}‚=/O7¾ª$%>¤ÊS>н¨=µ"—>–Të½×‹Ï=9|®¼á}K=”ðg>¡Ýƒ½>?,=€W;>]`=ÈÇ•¼£Š¾AuÚ½a+ξÊZš=¢-½n…>N½>Æ®½áÃÀ¼¬Ìù>L4‹¾’T·¼ÓÊ¿ðH´½}-¼�åI=ù}$¿ {ý< ^¾Ë1>¼ˆ_=c¤”>Bí¿ùzo½Ò°¾mH>Lâ¼Ï4‹>æu¾9±½Òœ>±¼>ZáÝ=2…3>ç8™=%±L½³a“¾/¿K>fÒÞ=�eÜ>žë[< ¦t¾XÑ=Pav»ç<1=fÏY½‡ô¦=S³$>,mÈ;8 ù0¾ðsó=ˆ]Z¾µL¨¾³�®=¬{!¾ËV´>Ô�)¼m‹h>Íu¾Ê‚½&Fƒ>_Hù½+n>]羚}¿¡À>nZ¾ç°L>hïx¾†bq¾ ä®½Ê¡>ÉŸ¼=lC>-¾)s¦¼rˆ>ºüs>I#¾²Ý¦=+·¾îrÒ½%Í®>Äê?ˆÙˆ>%óq¾µIR½¨’¾òúI>dwA½ ؾ�¶~½~ç¾rLƒ¾ÙͽCS>m­L> L€>ú2è¼ÿmà½s08>ü™ß=\Ó2¾À¢Æ¾í“N¾ØÞ•¾í ¾¦G;=.ã³>™I¥½‹šL¾T&%¾.OM¾3 6¾¶½‚¾Á×4¾tÒØ>:?æ½�Ø¢=Å‘¾¦Î>L;(½èf,>½÷¾s&™>Ûw¾�fq=½ýC>çl¨¾¸Ñ>µ®m»æÔ€=…n÷½ì¶Ô> R>²¨—½yݧ¾)–=H'ð½*l�>&ã!½ïÍ&>нiÏÔ¾Pbj>ï‰o½§+>YS¾¢Ÿ¼Éþ¾4 ¤¾:Â<½#3Ã=Ò>>',¾Ô a>5ø=ØÍ< Õ…>D¬Œ>ú‚<œ¼;<ý |>kK1½½×¾‡«=|�¾A¯Õ=£û˜>íX¹½¢­¾{>µ¹j=Š#¥=>Z½S²Ê¾@ý½SÊ»}ö=¾ÛA¾žã9=ÑÖ¾':¾æg>>™Š¾©¾–Å=äx>à>Ö½&x½c„/>§Ã”>qöÞ=7j´½õë“=ÑË1>ÍÉ:>©ð¾†°¾¶Oò½J"„¾Kµ=ú‹½£ ¾ü~v¾øpF¼#·;>P`¾™¶“=_Ⱦêê‹>�zÿ=Xð£¾9÷¾û±°=~Ô>£Ï¾¿,ļsƒ+½ÿÙ�¼‚Èl¾i$¦=i“U½‹µ]¾™¾^°l=†^®½›Ì?¾TÚ¾’ýö½Ì¡o>E:¦¾òHº¾&åX¾ðÌ£¾3)�½UÁ ¾êû@>8ý{o¡>ÒH¢>ZòD=2Ê)¾÷Äâ½ÁÛß¾Ò�‰<Êdî=¯Î˽·YH¾ÿh¾QÆ=�‹–=”Âò¼y =>øÈò=²R >DÚb>�Γ½zK�½RT>A ¾L�.>“;z¾Ep3>ÐË}½Â½'>è‰r><*¾¨L@¾£c“;UA½©Ÿµ½+~l¾.–×=ôÇE¾4p<~{ê½2G>w®/¾'…£¾¤m¾ÞÝ:%sQ=ÁDê=Ÿ#¾Q|¾(u >« ½þí½ZÂ6¾[ŽD=„>,>þÀ|¾Ÿ¿¾í¦½B·Û¾Ó×µ>¢Oõ½6#8½�âr>Ï/ĺÂ=ÜFõ½Sd ¼¤G=<³Ã=5=©=Zé‚>�%£¾»“ÑD8T>O¿ùüP=g³I½õ8¾™§ ¾ûÉü=åž=Cpi>’S^ºOÙ�¾~í>D¬Î>±àŒ=µU¾½B>¿¼Ò=?[~½ýpd>áž;¾�cØ=•c½CgA¾ ‚Æ>0¦¾ß;þ=»Z"=´AÐ=]M­=±V =õ–™>9ž›=‘Q˜=¨‡Ô½ù$Ä=VÂ1=hJ¡½g d=Wó¾rã;å2ª=^í¾ÚЏ>όȽ°NŽ>Âc½½LM…½  )½ÛX~¹[RU½¸,Ƚâ)>v½½©³(¾ìÈ >5:l>‡O'¾½<˜�¯¾+jî¼Ì4>Z\“¾ö’>�Ë>¾k=Ì`W’>¦£¼Ø´¥½Ú•G=|h½[ ?½9˜=%÷‹=ŽA¾òÃÛ»÷Ù¦½ÄÎñ½îgþ½çUò½^¾¾›¼»go<š„½-Ã>Ð蛾hÉã½Ðë̽œ^6>3ø]¾O”q>¨½Û#�¾,U =m‘?>ün†¼#M•=b½>ºøì>˜½™»²¾3,¾û±E¾¾Œÿ½81¾-ßõ½ï)¾Ÿ®E=8Y>¢+N½¾`>KÁ>m§Ì¾ä½yl¤>ÎW%>]Æ >B¨£>¤R=CÜ�¾­›~>—V>|Š¾Î†q¼M+!½V¾©ÿ ½ø¥½@åE¼Ýg=)=na>¾Œåø½‹&½Œ‡Š¾‘´¾� ¾tã=Db;¾'¾’Î/¾jhÕ=‹ê?<‡f·;f‘>)Õ=-§å;‰É[¾ g|¾B^>Õxi½þy½›'μ6c¼=dÑÂ=h©D>2�ò=²5¼C>tµP¾nï ;ÂÄI¾ÊEØ=[Þï<ÐÅ>ªº�½¾û\¾rjx>¹Þ@¾ÂÎe>&Xç=å·œ<ƒó<…-¾Hž==û�>�*�½'S¾¿/G¾š�½tɽ/˜¦¾L¾1±¿ZmĽ\—¾9�å½W¤/¾½a>¾\‘Ã>þ¾‹™ê=Ža‹¾€¬É=Í'¾t`�½pÍ ½3gµ;{¤7¼å¦’¹[/½ ¹%>H�‚½?JÇ=Ñm?i�<¬Ë=á]=äµ¾/k”<'™Z=yû>‘Ž*¾¯€¨¼�ó弑=Š(9¾”G[>†Œ€>Mš9½ß4ʽØg=@¯œ¾¾í¾®~ì¼në=0Q†»¢v¼!¾ð=Ö î½Ê9Ó=Q-ü=jß’¼Ø£°=ÇW'¾‡j>Æ’ð<¾7.>_ÂI: , =š(`½-—å=<>¾Y`=ì x>ðݼA+ > 䌾ƒö%=u´=ò ¾Û™¾cžw¾/†ß>‘Ø¢¾?tP½ò¡¾[ÒŽ¾ÿè’=êe÷¼OÞø¼Êj]>Øœæ=­Ðè½ J¾=¹€Ž>_<¾–òy·ˆ¾T;T>† ¾Öu>�ˆ“=…²èËö½�*˽Ðú޽}ŠÐ¾²{ =A½½*j½$(£=5B½ˆB¾¯T>f9k>}Ѿòé°>É„¾Ün¨¾+XR>t >â=d=>a¸=€¥¶½ýö—> —×=žU4½ÊÓþ½­ÏT>K°D¼þ)ô ’>HÞ¡½àg¾e+R¼¬DQ>¬¾&?>|€>—Me¾ [Ò¼˜p¾´ m=!ç‡>M=c¾ó1†=^^\½ôz»÷æÄ=ÿ6<%ܸ½Nw>µ|ƒ>Œ¼´ s<0y>PÐ{½)|P¾7庽+—V<-ql¾!T®=,ƒ¾U}/¾m3Ǽse7¾^£¾Õ¦!>d÷å½#�»½fÛ½¡[¾CeP¾/¿L>öÄ[¾š[£=VØw:‰ªP>æa¾Î=J>Š=#I(>š.½ÿ$¾¿Øt¼òh¾aÁ¾½ƒ!½†1¥=°+f<ŒdÙ= ŽŽ=ÁÁÝ<49?à§3½Bî£=øÊ‘=¼G…¾è)¾û’=§º.>>È`=3k&½Ço)½ù>˜Ãß½s"¦:†=3R>Ðý”=,�øâS>”·>�ƒ¾ÙE®½æªã¼ïœÁ¾)¼>K”=¦Úö=³x=>y>4=ŠÒ€>ɼ½¾Ùr¾î7>Za£¾=N¼¾�ï>‚¾†¾dó‘>]¼‘>Sò•;Näî=Šfã=›ÒJ>¿ä¨=¥‘D=Vsl>ï² ¾;™Ö¼À'ƒ=È!3<^°a>^á>�»·½î<°½ €ž½^\¼Ñ0î½T׎¾¢âž½X,0>T›�¾ÎŸ’>X±¾`Ân¾B›>Ô< o#¾0y>¥×!>Û´I>:s>ÜT9¾µ©W¾0ã=d”„=Æ8G¾[l¼~§O½®A>¥i=lrÁ¼JÔó½m¶¶èCž¾vj^¾·!‘¾ý¼¯¼¿µ>f*¼‹ý„¼z ¾&*´¼'1> ¯Æ>av�> ×(>‡•=»cÙ=/A‰¾k–½“­>±PX>ºXް«î¼SÝŒ½³¡‡¾™²í=ß¿¾œhÅ= *D¾5rh¾Kf¾ä©]¾$��½h»½a¯Œ>¬f»Q~0=C?@½×½0#¾çÛr=î)½[ô½‹~M¾&Ž8¾D†¾„&„¾`g>NE <ûà¾ÁD>ƒS½.þ=ÝX»æ…¬=À–Ž=ã߀½lÒ>Õ¿[¾�@~¾™Z[¼‡r¾¤”>÷o={2̼ú3H½àƒ¼<Ä‹=Ô°:“±�¾@ª= Ý4>f)¾þ(I>+^©>GðJ¾T™>¹»>Ý•¾Ü|¡¼GoD¾É8ë=ôd;>:—<¾¬Öª¾·?‰½ÍoC½UÉÒ=üÐÙ<&ƒ><�ñŽã’2>ÄS¾e¾‡Ÿ¾œ<Î=¹á½UÖ¾ ¸¾îpp¾XŒU½ñW_½l¦†>æ:¾¬×˾Åôý€§?>Ü¼é½ ëܽŸ~¦¾Pª8>h]>ß±=xc™=â¸=YYǽgÜ<>*Yˆ=aÁϽo½‹w:<¢Æk¾ÿ?X¼}ú¸>øs‹½F6 >Ŭ辉Ve> ãS¾ùÐ>ªÙ@>tY´=+>¨ßü½EH»GÝY;[‡ú½ž5ö¾>2¨=�'L>¶h¸½%O>O͵;¥Ã˾ʣ^½R{Œ>E#Í=2§O<…@ê¼vœ>ž» >Ä•‘»ë§â»5ëR»!!U>Ï«¯>†·s½ÐÿP¾µ‰A¾ìî½Ry–<ç <¾ $µ=tòœ¾`Ÿ‹>òa¾aë=Ǿڸ>>jд<ðJž½R€�½LL_¾lÌ2¾"~Y>€�m½((>6Á\¾§§V½°ñ˜¾‹>.¶š=߃½â„=kH ½œz¤¾K‰/>ý£À½o—�»ø&Ó=ó,Ÿ½Ê°Q¾¯øþ<Û#>ɦ1>¶0V>™Ñ¹½`>¨…½Ákñ=~R½o:ò=R>l¾›[•¾jç¾$Ú4½ÏÐc¾­>®¡I>¢Å¾É½O¾Cgš=Bü >Æ.¾µ3ã=ãy<¾Ø>¹]…>.1¨½Ôé=s½»=Ç/G>ÃSˆ½93ˆ¾ôØÓ½¢÷¾áKv>EH¾z7�¼¶&z>pK>»Iɽ&Е=÷¯†½ÛÐ>óQ!½@¡>Q_‚½„”½«?»О=¸X>­žÛ½¬¡¢= \}¾Ý€ð=ŸÆ½S¿â½JÖ¾?�ܾËÝ„½Ù_7<ÓÀ>¾ã�Œ½ÿê½ Ê=�Ÿ ºlf³½8ïp=2>¨">Ÿ„ ¾ÖÐ=cg>]�Ô= „,½ Š:=NÏ=7‚‘¾ù¨Û½e¤>¢‡v>eˆ•½§kUC8 >:Ñ5½O³x>(o¾ÁY¾ ¬–>ö‘Î;¹d¾æ â½PÏ>mk–>V£>Úî�½a‹¼Ë°½ÀW>CE9½Ö̽A�…¾°ïo½h¹Y>ªiL>Žá:>çx¾V¬â½g€y¾+ë½aO¾:¶á½s;> ?�>ºEý¼ú->ã·6¾F.}¾²¶�=ª^¼ ‰<¢8z>!¬y¾Y[&½Ìо׀¾ª,¾â$š={ô>§¸>-¤>޳»=úͽöØf>F/>Ñß"¾Ì³5¾Ë=*뾕’v¼2ÝK½Çà´>á¦{<,,¾¾×>v)¾p4R>‹i@>Xë>±�?Õ¶Ô½0ªü;W§¾‘ËA>Äu¾õ°0>({Ͻ£Ÿd>ßëo¾Ÿú†<#°$>gû=èĽÿ„8¾^²½©K˾xc=GŠ9>k&®¾¨&�=2+_½> ë<ߎ>Z˜¾¼½Ž<ûU¾®,ˆ¾¿v§=¨ôI=C>?> ­¾ Q»GÄ¢¾ ª•¾PYt½ÇÛA¾L­>}hð>NåÖ>%> Ü‘>O R>ø›»ÌàÓ>6w=iBh½p½–½/žI>V+¾Þ°”=5ÿ>Òæ;-ú¤¾ie>´f>W.>Ú«Š<4”°¼“à–¾K½=èX½—f>楽Tß&¾"*­½ XR¾ >œŽ:Ù‹R¾+ôh½Q䈾#åç=~uÐ=¢óÊ=>0¾¾š¾LÑ ¾®�>žR¾®¼t­ë½(-4¾Ô,¼L#->îƒ ¾Ñ‰>kè¾qJ%>&TÌ=¶ö½›ŒÉ½µØ=³$>t ½síɽùzU> /¾ÂX¾Õás>v(Ï>Öy¾?b ¾SËK½›(@¾-Þ>阊½Tô=ÊÊ9¾k›�=Õ$ë¾ÿa=ZÚY½³àþ¼ñø¾¬P>P‚¾^ Œ>É‘˜>X7=ñOœ<ÂcÛ½W”¾v�š½Ü >Z$¾©3¼ú|a½Ì†¾g¾X@¼6P>^Qô=‰*ˆ>þX™>Yð­>˜)�¼yk~¼H³�¾ÖS>†X·¾:x¾�ª ¾0Ï“½ªŒ>+ª5=󣽎�>õ �>®"…>³4½ß�m¾`kº= â=ýà¹T˜©=Uº•= Y=¾Owþ¾¯Íz¾[i<Ë 5¾ùŠ·¼¸ŒX¾Š.‹=¶á'¾ìÍn¾V.½Ú”ƒ¾Zë¾=uÔÿ¼ª¨”¾ðSí¾¡bD=(ÂÕ¾sõœ>ö\|¾g„P¾C>ã¼à�>qŽ >Ï >·@�¼þ)Á½Œe<Î=Î<¬Éw>êÜ,¾jŽ“>7—¾’€¾ÿ§j=[Ï�¾¯·Ô<ñU¼’«Ò(ô=qûš>”M»= ”>NÝ=¾Ì‹¬==óÝ>”<>㺥>¿¥E=¤>2Aé<&]T¼I�‡¾¢A="ÿì¼µ¢=|`·>!k ¾–ƒ4¾{{½š‰=š\æ=È!š¼ˆù>á�Í=`ŽH½^U&¾÷¥=b[¾=à꺴wè½¼º*¾ ™Í¾Ô�‡½Á“Q¾+ð�>Α=þ >ŽB[<i ½&šL>/"¾©>½Zì)½Œ=¿?>¶â(¾ð:>þQ>K‰¾“þ>XQ¨¾dû2>xi^=0ë�¾Ìâk>-éÙ½ÜvÄ»¡³=R²Ä=�—Ü=3Ѩ=­tÞ>þ¡7¾ÒU×½Si!>±m =´ÿÿ¾UªÃ<Å´…=>•‘¼¾*¾ /¾V<þ=j²>ˆè¶¾±³Â=6gÕ¾Þj†<\+§=`cf½°O™¾E©‡>a˜n½íø�¾ø>d_÷ H‡>’Ð=­!>¦»b=Æé;>L>ë=h¼½W%9½Âöi¼û¾¬‰rºkp>}‡¿½JH:�”Î=q0>!«®ºï‚¬>qÝh>γî<‘L=ò�¾þEÔ¾¥Þž=�8©=£ßt¾�oñ¼QÔD½Tô�½bsྎÒ½ÿ¼¾L­T>.nŠ>é!p¾xõ¾•£ó½Ø›i¾¸0¾Ã2½Z#!¾Þó©½�8¾ýQ¨½•Ä<Ú˜X¾ä‹½Ý;¾¯þ¸<� ¾W…¾&Ö´½Õ2^=ê›1¼&Dð¼&>×-ª=lÖX¾äfQ¾;Fÿ¼!½ >ŠÙ’¾åH‡<Õ3‚»> •¾·Q½oºB½�¬º<µmH;’0>›þ=º¤¾E�Œ=«e3=!vèòƒÛ=bñ»<¤Ëh>F-½_Û‹¾Çx…¾mþ�¾üâ¾j‹¢½Ñ̾zW™¾ô¶"¾Ùß´½Æk ¾°é‡¾÷0½‘.Ï{¾¨Ñ§=�{½Õt1½c>£½>6"¾)}$>ÍäÆ<½¼¦>‰½àÄ”>…A‹=Ó¶h>§9j= †\¾¤Ù›¼d¤;ìÈÀ>åPµ½¡§9=+ÿ¾)g¼…Á¼àÏP>@ï{>= =ÏÅL¾�y9=]ã²¾²AÛ½€î¾wCn>Œ2¾|>>döÂ=ÐZ£¾•{oº‘½ >ä¸<5›”¾Áå=ÿY…=×V>ùj>HÇý=0F¾o·ø»R‡>2œ¸½ß �¾Žµ÷=L!i>T…>mÞ½ô�>sµû=M�¾erÒŠõ¾V†í¾Ä™Œ½¬§¾½SG}½4ÜH½ƒæU½lÑR>MÍe=Ù)õ½W W¼jW>‚¬8¾mõÅ=Y&>|“ν?f(>ÎSl¾~\K¾]$ؽÊ/Í=¼lÝ=µì=gx±½QÕ ¾`ê½$2>8:l='ö>¥ß½jq>aŸ=]Žº¦WÓ½â`8>Dšñ=LÜ4¾›ˆ>ˆmÁ=¹Òt<‰y=€ÂÉ=eòA>Ü!¦½n<+=õ=ÅçŠ>÷UÈ=>o>—û¤¹üj>œ©†»–WÜ£B·½P/f>\—�½·×>,…¾á?Î>É ñ=mδ¾!á«=}%²™!>̲`=ä¡Û=:àN¾K¹1=åœg½…½ìÈ>n³> ˜>‰> 4�¾ù>¤VÃ=zg¾R½Ù瘽…Q!¾Ëóż¢ñE¾¸{†½ ɽÁ ¾=^¾Ð€=>9о½np=õ6»ä<¾^ Û¾d)£>eŸÐ½9 ¾Ì좼×Á¡=B_¾^®½¥üx½ŠK>Üb§¾G5¾›‘¾Jx3¾Ô¾úlo¾#À£=½!¨>Öz3½ÌÓË>õ0w»œª< (¾{Ç£=Ì90¾^Þõ½ 4¾EϽ»J =v¯é<3Öó;7J¼Æ¨>µ^ ¾¬À¾j½Õ{ž=7É”=n´‹»¶Ïæ¼#¸!½Êú”½>t‹”¾‰`ʾ�Se=«()>* ×½µ]?u¹&¾‘H>xÚ_¾Œi¾ v¤>Dïæ¾ÙR¥½Ú€b½q�ÿ=Ìõ=‡Ú¯=ç0Ó=)®X=r�>WN½G&N<.þƽ¨òã=‘ <>ö]½4P">͘©=5þ*>¥=ƒ=�—>RŠŒ½{:µ½¯…�¼•ܧ=êi–¾”´Å¾-µo<ëNK>б#½0eA½µÞR¾ †–¾a2=ÆäB½Óý2"Ò=RÕ7>™¯½Íxù=µá)½ùƒ¾5“š>qWü=RrÞ½‹Õ6½¦·¾vVM>~�Œ= ¬<³_½èSO>ªy3½¯—̽•G·½-¦Ã<ô2=gS=y0¾¸¾Ë—=ø¹Ä>BÆŽ=üH>6«Á¼'bÈ<`Æl>r`Œ>t]>.$'>* •¾67Q9ðûa>çuù=Ó�ó=敽@@Žڢþ=�.ï=QgN¾jZ”=ÔʾÇ-=‹Ö€>9ç1»Eßi½!>öav½´â¾û»ˆ=xé�>o>gk>_i<•o÷½ûz½w,>·‘¾Ñ߀9 ʆ¾vº)½?/©>WØS¼p’½( ž¾Ü½N>'S)¾æt×½ÚZâ>iU{½‚·�½çý³=*©ï=tu)>‹J<¾SX�¾­ ½Iÿ�¾¥•»›ͽ¦9¤W½Þ=:Fª¾s• N^» T¾¾æU,¼5)½(2=þ*‰>‘Ó¾kýs¾þÇ�<‡’Î=¥SH=àv¾L¨ >è±P½€�A=l4 <Žr½Àöé<–ˆõ>³¸q¼÷�;¼ŒÏ¾Ã2½_;§=6e„>Óx=S§‡¾‚1>6Y¼ûN½†üÇ=Et±=òuy½Ä�= �ö½ç8¾‚©½»Râ<>ø3!¾í•ˆ=Ô[›½Œ¶„¾sÐN=IòU¾ÕZx½ƒ½nMؼ[LP¾ñÔn>™W¡<TC½Þi6½zÍÛ=È€…>œâR=—(=¤Š >„—¾xÇ>Î:=N·¾MX©¾¢¾÷¼N¾aV×¼—V°>Œo½./%>IÛ¾_U—;»¯…½ =¹QŽ>û–^½â!¥=+ ™¾³J>•f¾BÀ[¾_L¾5*Êw ð½I¢>ìíy½*ÿ0>Ÿé½]R¾º^>œÏ¡<–8�>Ìcì>@þ¼ÔòؽtNµ¾M[½¦¥¾–«O¾GѸ=ì]s¾íÙ'>†>òÍQ¾�¢‘¾²i>ô޽â~¬½7>!�…¾ Œ£;E.x>«€¼ÑÔ'>CJ½ýº<=�à½|a®=Ù1ˆ¾^–¼prŒ>{˜çg¾ýfÇ=™½¾Õÿ½ÊE²=*Âî=ùw>Ñ'L¾Ó,=H²@= =¾ug¾ä¿>–s“¾`>zµ\¾é}>v¨=BX¾(Ö½¤¿Ö½T�F¾ )‹=Šо¿e½X½¾æ–Õ½zF½’Eµ=áÄ>É¢>ɳ½×j^½çd¿½? >Ð[>‡A¾Y6Í=!iƒ¾N´[¾Åƒ>›äŠ>'ÃÁ¼¼A»=JÉ�>X8ª=*ìɼd$�¼sž=›2/>—lÚ¾%S³=>w =É®¢¾CZA¾!þ=–Ó>zÍ^>aö‘½&ܽ=ÝN>©ƒŒ½^–s¾4¾Ôn4>¢uQ<#>MUK¾Ä >¾F×®¾‰Ó*>t)>ñž‚¾#r]=gú¤>5c<½[r\=bÏ=8“=¤¡Ò=Ô•ºj´¾6!¾ "¾zb¤½X&.½nF°;²‡½1:R<±rf:@ÍC¾ýŸ~¾”?G¼&ÌU¾B^>™¡m<“Ì >kú¿ºñ¹Ý>Óu̽m3T¾9W¹½s§Ø<:ƒ¾ð`×=æ§<=®A ¾Ü¢^½*©=_¡Ô½néü½4é8>²yd¾L n¾Q•;¾…þ½þ̾ÈjÄ=ø¦Ý=cøZ¾?—§º¾ò–v>™ú<¾ö ½N±Û½ôý>ÝX,¾,½ÚwY½˜Ÿ¾á] >ÇÒª>‹’‹½£= >ãHí<}©*¾ý½l½­Ü;½®ž ¾ ƒ½wÄ= s�>Dc¨>B§.<”~ǽp=1>¯6>rÚ™¾8ªª¾R³6=.�н õž=™·Ž=ðL«¼âþk=Ò!…¾$ô¾ÔÞ¾S¯ >í7É»€ýÍ<¼ Œ>ƒe<´Œ=î#ȾhnC½^üñY>B>õð½Ï†¾²>ãìß¾¾–u½À•ܽƢÿ½§†'¾†ƒÆ½Åõ> /E¾¡¬ˆ¾é¼¸½oÙ‡;%Ri½$íH¾£R¿=˜ ¯¾rY=£¢>³T>ú (>{ã긂洽šV¾Z±=ßsï¾Ö×"¾ »§>˜5‡=»;;>½ >d&#<Àæ=õÅî>––ä>,‡¾½¬8b¼K$^¾(¾(bË=ü(„¾¹nÑ=k¾|>„†¥=»‚‡¾–£p>|St>.dh>¸d<l”=õÙŠ=›²×=‘—>·Ÿ>“�½Œ·¾r¬¾¶Öy>Êu1>4D¾D]*¾À:I¾¥É²½ ½-(•¾‡°c>Ÿ�€¾0‚"¾W’é½…‰S¾·|¾Ç¸Œ½&g>ˆÃн4üö=*t¥¾‰+>%Ä=¶Í=,dh>ÒV˜¾–Ÿ½=%ô˽ˆÛ=û€ô½†ãU¾Žš¿ê½½­C‹½›;¾³’¾¯¬�:v¿¥=ø?q>aé#½ &Ì=å'À¾ÃºY¼ÐI’¼!‰¾'Ü¿=Ž:—¾–èÜ>”pU=.Ž4½}c=>&."¾8Ã>yx>…/!>ª½æ‘ž=¶b¾/y¡=Iú>#_>( j>£?0ƒàºîv|½ÚM¾¢©–½Y„¾á ?û²>æ#>Pô¹=,‡=CÈÿ<˜ …¼±$�<®+’>@w¾Õ />²À�¾ìà÷½ÌÄ>îS‰>`] ?«»¸=½-ìA=˜¿�=W÷¾í䂽µF¾®Ì+¾ðQ>Üf&¿3æœ=|ff¾î;¾;ÞH>*‡¡¾’á³¾¬}¾œÎ¾‹«×»°Ä=�d>ܦ´¾ˆ¾¿Hîœ=ä‰p>Ì,À¾ûž›>d©=Ãld½$Ó×=®¡G>/–¾·ÙÖ=t=ZýF¾‚ϼf\¾ _ª=Ð�޾€Ñˆ½¾¼;¾X²>d‹>Bd#>xǽé«>�’>�«>5L‹>Ⱦ¢L©>I›¾¾-Pо œ�>6Û¸=ù=÷…޽Tò\=‘}w¾ñmE½I ;�»>Wñç>R=¾>—·=ëp¾+z®½ŠTB¾´:º»Ï=Ýq‰>XÒî½ö·ž¾Îi;½ØÿÁ¾ó®ð=ï 0>Í"w>vTi>%Í€½ Eˆ=_·µ¾›�«¾Œ¯u¾èlu;ÈÔÛ<©…ƒ½ÌTŽL"¾õ©F=¦m¾Fîz½[¢0>G&û=·;+¾ˆíù=\§1½ùÿ½*Ö¹½Í§š½­ýŠ>&É>_ŽD¾¬I¥>õÌ€=@Ý’>MB¿f“:¾…Ö°>ÛªR;˜‰h¾Zb)¾‘¨½8|¡½³…¾‚´À=A\>òC¿½á C;!s¾VOo<�>j>&×™¼T}¸¼¨#=ÔLt> @ȾLOx=àêz½Ê ß=‡›'¾È™¼‚1½è×">Ú²k¾J¢®~Â(½3v”½+Û°>IÍ=Ñr¾ Œ>œ‰(½ìǽ ÿ ¾k�{¾Ð�L<È8=µó½&1¾¥g§=%• ¾ü;h ?<Ú˜>#H#>�«ä½%Ú>_t(½ò¾%9¸¼]1=ßû…¾(¯a>pé]¾4 Ÿ=trÃ>”ºû¾-쓾uYë=©bó:=% >ˆñ½@‘Œ>d>h¾ä?1Ò²¼³,ƒ>,¢î½}PT>ÕÑ=ò^týØÌ>’Lµ=‹¡È½-7¾o࿽ ¯a>µÚ…>ÿÂ�=MÜð=ìè=›úê;~º?¿Ê'°<“7¿ÿì�>g€Ü¾�!ˆ¾P™t>HÌ’¾ ‡<6ãƒ=@¾·áŒ>5Ø ¾wâí½×5<éï?>ÜÝ<œ›ƒ>Y\ƒ½ë9û=Úiý½~�½Û =‘ëÝ=û׼½ê³¼¹à½�Ã>2 n¾HiÇ=ÿ ã>Ò‡ ?Z‰W¾\Ïe>ü}Ï(t»=6„=Ñ’®=â^=ÛN}=`àX¾m(6=(€ü¾¿t¤»y_>Í À<[C,¾íŽª=Ûg-=@Ÿ¾Š¿¹=«½‡>…4™=Úœï¼FrM¼C“z=ž£>()>ØL8¾@vw>Eò>ˆdŸ>5´›½©Vï= €¥> nž=¤�>Qˆ�¾I¤#¾¯£ï¾óþÈ>*œ¶>;Œ½/f–>Ä\Õ½k =F›L¾_—ò<vž½‰¿?¿ƒ«¾*‰È>ÖRÊ8û>†5R¾¢{=¢S¨<'(0¾ëèX>>$÷¼ZcP½{ø�¾hažî—<Ï^e¾¾@ܾ bn¾�hÚ½8‹§<ôÍ’>›É >בd<ýo‹½¥Ø0¾ªÏŽ>™Ø>€É<,Mƒ¾TD4½‡¦Œ>Ýæ=œ³Ž=�hE>¯8¬=i{2¾tà;> mQ=[ ·¾(—¾¿ž¾Û{_> Š`¾Ëò1½ík¿?"/¾¹ ¾Äë¾ì>Û=íz=Þþ޽3Q£>‹Uµ>µ>ÖøÃ=ëñH> ÑR¾¹p�¾¡­s>ï±¾O¼ÇøÇ=N[x>GÈ='z¾ò™¾ç¾ ;+=ì� ¾ÃÄ;¾I;§=® €9òÌp>ŠçÚ¼o£�>X⯾Üaº>¼Hœ=Hr½Ä´ž= xaºúaR=À]½žf@¾~6»½C¯Õ¾‚”�>Úº=çÐ�½jé¾ CŒ»=R =Eò¾-lö½Žlñ>Õ·Á>cî=« ¼¾C*>†öÎ=¯;½‚lž>…ÖÖ¾”ʾŠÀ>Öµ>®T¾ð#½è3é½â.Û¾z„>ïÎÇ>Q¢‹>ºü…>ÆYŒ¾ù3¼¸N ½ÛÂ>¾ ëPº[ ¿>?áܽÜ'¾Îнv€>¨¦> fv=ì³b>Õ�=•—>¾&f==<ö?Šš¬µôj½$;L=§gj¾l&g>†==äà½;Ï«=P>MI¾¿'6<-µ>ò:I¾B•>ì}o=nAp¾ôƒ¾W ¾¤,å<í£½…\�½G#¼¾ ä½”»¾ž v¾:| ¾½Þ²=¥Ü?•‡Ò< y‹¾xÀ¾kå+¾3my¾�y¾ ‹¿( ¼l\_¾k“C>??/ô>ôiA¼ì.ž¾2�Õ¾³Þ ¾óî̾&É»>S¾Œ´¾á° >Ãa¾ÆH¾9QϾW-ü½%²Ž¾¢l¾ÚÇ ½b6€¾é”E¾�÷a=^2«½­Û>(oæ=„Ÿ=T™¾–eÖ=ˆ‚Ó<„b¾xµ¾º¾³ëÝ=%‰ú>(‘‹¾sW½7B.¾sŒ> K�=÷„å½íçX=ø[j¾õîÁ=©9ð=6û¾cDž=µG¾9™½=¦�#¾4N¢>нF>ý O½Ir¶½´È}¾H‚G>²ªÝ>èÕA½yað=¡<�=íyE¾g3>Ý æ>(çè>–>««f¾°=b†v=«ðû=Æœš¼g"½wâ½ü´x½ÿ«†=­‚3¾-~½ò ‡>^b~>ñ~°=@³>¡´ƒ>%øË8›ÕÁ¾ö—ƒ<üi½žŠŸ¼ Îä½x¹‡>ËwÛ>á ¾ê�º‘>^¨T¾8á¬>{òì¾}cɼýñÉ>à5‹>��;n…œ>„™ >¨Ü…>zw½ȳ°¾Kâ�;mn¾sîx½ÿ|<<#u¾S �=øpÏ=‚°½f±ø½Ã¹s>°Ë ½b7=ÞG½?Q,=¡=>¯ø”>ÇZç=¤o‡>,µ =ô¢¾Pà[>FA·½¨—†;™î ={¾Ï=žJœ¾ÇN¾V)×<¸�ܾÀP>Ç�³=%¤½Cp>ƒp¹¾Ü0ð¼®��¾`ÌX½ò>]¥Ô=­ §½€@ ½‚ <É»<]£�>÷8r>5{.¾";S=úZU½¶À“½m>ÙÙ<Ê’²¾/g>Ê|˜=×u‚½-¨I>Äpü½GH¥>ÿãc½Ïì}¾0Mô½N=$?N!?]!>´½Ÿ¾ ”d>§ ³¾ãâÅ=i ¾SŒ¾v7Ù>^Û½ò‚>  ?j�‰¾*~º½ë=†Ëj='S½t ®¾¸Š?#»¾^�Z>'½N¼?ªÊ¾ ñ�¾ö½…ä�=½>"ž�=‰G=ó%á½Â0æ;?N>�…<Ûè–½ܧ¾Ì{¾Åè½½ª!=gÿ–½¼lž¾´§=FQ¾#º>‰eI>—¦½Šµ?a?½@Õ;¯FÌ=ªuh>×Á4¾�¶¾FÍt¾æP-¾¤Š—>@”J>3$¾fD> p�>¸]>‹@ò=GW€½1—½— ?…G*¾îMƒ¾-ýF>|«Ö½WŒ³¼Ë•4¾�°�=äLš¾¾²–½«l¹½×àô¼žÛ?°ö=òÙǽu D<‘Æ/>õÁ\¾{‘>^_L=€a!¿Þj¾>ðæ > j;>êÀˆ¾¸I½ÁµF>TÔ?½…¡<<óxœ½GB>wÒ8½;ï>œ°Ñ¾�lg¾5z¯½yp">ס†>=)“<¤$k<„HX¾õq">vq÷=8¿dY>n‰D½ ¡½˜=®>•9½vÙn=³£>Ü`i¾"!|¾¢MͽÎf–¾T“‡>\=ànl> ©½V‰®>¬&y¾mÈh¾vŸ´½/== ãA¾C®½~ï'>&v½�§©>ú‡û¾ÕÞ">^/¸>Þi¤=¯FŸ¾‚�†¾Šô_½K&нüÛ= w=G5>ñU>Ý­=—h?ûi¿½\Ö¾>¾½Å<|«¡>2ðS¼'h¾¤·”¼î›»wS[>§:F>³P>T«»=Hð•¾e“B>/Dp½M²´¾JW•¾\¡­<43¬½ ú ¾v™à<«N¯½+´ñ½ò“¼2Y"½ã]+>#—¾(I>äÞ½÷LÍ=eUœ¾È“Î=‡Õ>P"ñ=8[•¾{0�¼_:ˆ½¢"¾¶¨;¬´ºZ¹:>n±e¾¡åÆhÉ>SÖ=Ë8>=ž{½/.¢=ù ¥=�nºù°�¼#xS>Ü6½SUù½Úv;¾ûŒ¾à<ß½-7¾Ú<¼D´Ê=2^1½zC¤¾Œ 転 @>ØU‰¾æf›½)¹”½Dýï½p*>ti½ÐG=QÌ3»æ&>G¸4>öaÇ=µâÔ<è’¶>ÌxÏ>dú•¾�þ⽘ÞC¾’|0<·gm¾e‡•¾1 O> ©á¾Ô¿¼ly½ä±°=õ‚¨½Ü³9¾Ô(ì=$B7½š„¦¾ç…>½<áØÛ>Ö–>ÎÇ<*'¾œɽ(?b¾Í-¼>oþf¾|[ê=j(ƒ¾(X¾¹Ä.>Ê.Œ¾;(=ŸHd¾i±¿�"Ó¾’óU;|Ð+?.i->–ͽë‚Z¾½†=ˆ�>*¬¿>ÿ›É>ô¯¾±·Í¾ij>Huî=õ{Â>’¾y�½B¹e>ÑEí¼‡»Á¾¤>·ri¾b;¾wù_¼¸+ñ=ýt>LùI?®öï>éŸÜ¼üK¾©S‘>0{r½Áÿµ½Cœ½x«x½¹ÔK>jCȾA=¢½šân¾a—¾×²º>c®> ½C¾s¼8½ÞrK>à6½¶><—>OAc>ë†E>öÇF¾†þØ=‹O£>2 ˆ=�6¾Nßà=á=Ä È½2ï=Ko´>öÙ\=Ÿ~¾ãÿ>ðþ¼õ�Ï»pÜ >úÆv¼ÅŸ>T󄾌 A¾¥Ÿž>8ñ=!-">·¾bœÅ½5"8>$Œÿ½¬ð�>‰ ¾*ä>m%=‰mß=z@P=˜þJ¾—û.> �5¾iå?dûø>�T«½TÁ]¾®ò>M†¾´©¼‡¦…¾åÍ,¼yj½Ç9¾¾Q,„¾q^Ê;mSà<Ö´î½Çîð=\÷Ï=š:1>jîR=G…>}Ó>ÌZ½R2`¾…?p½/¦m>é�¾¿†Â¾¢C3½È9 ;Oì)¾«E›½~Ð%»58o>eF¾¿–r½ºv«=d¤>˜ëA>Ï•Â>ÇŠq¾'ô>x§¾í�U¾Y–> îh¾fE¾ñq�>©�=¿Ñn>}.^¾.ªó;p½ªÓ�=ð©-¾1¡¾Ù¹R¾ižÇ=¬þÖ=¶[.¾[((½²ðy=ö†> �¿=¹“¦½6¾e”¾Í=¸=¦ë¾y_¼‚3?>»ô¤¾®>¦¼ŠÖ½!­>=fÿï¼&W¾ ‹…¾ÿßn<Å)\¾I>†œ0½ $õ;Øø½P—=t~ï=5¿ ;è¾å‚>†Ž=X§¾.ûâ=�¾Æ=@ßç½µ5)>ðÛ>¶y<¾R†Œ>µ%R¾Ðz½�/¾Æ)¾=jР¾JÎõ¾„=çL¾¨ÁÞ=¬Z>8ó¿=Dƒd>^ x=ßy<È/ñ=™"½‹p3¾št¾_è¾»ù>¾WÛy¼¼Õª½£Ó3>=}¾^'¼»�t=®áÐ=ùk¾"¿¥=ïàú½¸Ñ>Áì*>áU¾ëÐͽøø=ºö¼�„?¶/>Pvu¾¼£ì½ ²½ :º=d_>JG>Ì•¾¼=•9¢=é¢O¼W=ß§½ÄŽ>Þ{?äD¤>¿ýâ½kо«Ú¾n5[¾JÍ’>¢äý;½ “>Ä‘v=ô%Œ=uñŸ=›’t¾±¾L5>¡y¯>�Qd¾=‚´¾¼ÍͽÕ±=€½ÞÞE¾¢.P<Öw&>2Úú½ê߼{ö>Cš>Ãþ>Ud¾Kÿ»=")¦½e’¾FëS>~ó>Ùš ½Ø¯œ¾ˆ˜ï; Ž„½zïS=a¼•>¬µ0=—û >¶lD>¥�«=Sb¨=û×]¼Ÿ¾»>j¢’=o•“¾9»D62<�A >TZ/>y ,>ÇÍ)=¶^ˆ=×ï<ØãC½ÊˆR¼âÏ-=Ñq½•¯Éñ1R>ýÑͼV‡=ÔàE¾'B>½zy˽u^m½l…3¿¼š,¾´_+>’Ÿ›>‰z&=´„ >ˆÍ›¾N›¾ñfö=ìëž¾è:ü½a„ ¾öºÜ¾:›>>¯4Ÿ¾ˆ}>éï…<ë~D¾ƒqŸ½Þmk½Üc¾>Ò=¯W=d¬u>ÊE>â+™¾æßª¾¥ A>a@•>ߟ¾u‘¦½WA®=?Ëe>ÍFm>lí^>!¯W<ÁLU<à=/R�>`뾊y>Ô3?¾…•>,Õz=!¾—6{¾ª«®=�íZ¾eTÿ<­`Ÿ½H˜¾ì�ÑÈ\¾„á¾?L¾»˜ø=Îǘ¾v}¾¯PÞ¾ÏP<&•¶½=(I¾Þ�U=\gʾ¤Ií=¶ßy>­­<ò>~%­¾°8ü=ŸÜ¾¶õÈ»ZžÊ½Å:<½'�O>çc>¾á†Æ>\Z¾N‡Ê½Ã¾œR<ée³¼£¥d¾ÒSc>nn¿œQ�›¾¨�µ½Ë¨>Š\¿†%¾½Ý�b>ÊS<>æ¾ñ™=K¨x>hÑ ¾Rq¾±b�¾þÚ¾v >�+œ>� >I… ¾Ì4§>á¦.¾7vN½’ >tÌ.>ïÖÛ<)¯>ê >iÑͽíÀñ=ñºD½Gݤ=‹½½-á/¾Äú½Vf‘½�œ=ù©û½g%m>…m¨½€ª´½ôÎæ>µYÙ½ûÿ=ú½|_î¼óC—>Kxú=ónÈ=OñȽÕës½W9d¾¨ÿ†=æI=ÉqÙ=c ¾åœÁ¾ëÏÂ<©,>»�5=0Hܽca½5Œ¾òE„¾W€*>H"Z½ã·=Z½x!R>Äí½¯>a>·ì=�$T½cW¼¾Ü¾öÀ­>¢Ý=uÒä<³X›<Íâj>hm >ðÆ&>Ë=g¾öv7¾¥*Ë>>ƒÖ>c>y|¼½1ÙV½<äø½Îè¼¾å~b>…œ>‹ÃǾó}å=®F<{Fâ=�+¹=W¨N¾Ô¼÷>ÌOœ=ñ²h>ê_.½q•’½LE.¾«q>Ì Ó½huw¾ÿ¼¸›þɾµ>ö²(½þü!¾W8ýæ—P>qb˜½m=>Iħ½Žu×¼t…€<�é°=Ÿ!¾¡]>­L¾›Á½}B¼¼ç‰U=_¯¹½YÎæ=×x> ØD¾�S̼g=¾£J5¾ž¼`j“¾zþ¾ª¯‚¾=13=ˆWN¾}GN>Á_¾9òé½Ç†™<”d콞\=F^¾&Ÿû=Ì^>¯ýؽ„‘•>&¯u¾><3>áHÉ<ÿZÆ=á²ã;¤(¸»[ñ½ËL>>²+Þ<Ù]½ã¥�=šN¾³…œ=Êf¬¼óP®½7�•=‰žÎ=ŠB”¾¹�½À:e<^ ®=IÆæ½ ­=°ó@¾hÅÍ=mF¾‰‘¾~8 ½b\¾/çc¾ ³‰¾…¤E¾�Pm;“àì>:ü½þPð=KG¾FL½4’¾åZQ>ûè~¾Z µ½Ò`Ô>ÿ² »Ê…T=nèI=ë>™Íß½^í'¾'¾Ž<> ̆¾Tp°=ì8{¼)Þ‘>"”>­Y§½3š¾G€É¼L>”[=fw´¾'ZÑ=«@�=mù½¢ÊC½>ƒB¾ŒIœ=ú•ž>í|6=^ø‡¼¸g+¼ÌiÀ>fŒ¾·¾I²?¾H”$¼èȳ¾7nl½[1='©!½Ã˜>剨<O辡®Œ¾-Ú¾²(㽜(>lR‹=°£ƒ>Štv¾6^³¾G;>'â¾=³·Ã>ªG>£>¨¬=ÚÅÀ½Fñà½�N ¾¼Ù=F%³¼nš=x÷„>ñf‹¾š1 ¾ÉÞŽ=ðžÛ¾Þ�>¢XÅ>ê—’>¤Òù½ƒl¾[º)>˜¥ð=�¥->ŽS%½X2*>«§¼h¸}¾¥Û\¾•ì<ú¯¾²K¬=Š{¡½ÑÏ|½t>›x>ÍÚN>H×S¾ÿ޽´Ó‰>ûü=ĉ>"¡×½«¡h¾�Pa¾J¾·k¾s£¤½ÁkR>òP>½‘#=bbû=™L>™v„¾M^í=«çã<@ø1>‹['>ãïh½½ê >Éά½sO£>ÊN4¾ž-B¾Z¬=ðÁÏ>àŠ=µ}G>9A½Üø½ØÎž<±�ƒ½ÐöO=ÙŒ>…lb¾ 0Ë>½éã=6¥­¾«¬*>Ž…|½ãMU<·ÓÃ<Ë‘‚º�õc¾PÁc¾„ïŠ=¼–w>hÅÞ¾;P$¾ÎŽ)¾¦Yª¾>È=+`b¾àˆ¿½üĨ¼ï“·>\²z=?ÛV¾‰-¾1Ôd¼ôØ´¾9~>\P=_;¾M­>%n¾=€0ê>ç#¬¾æ'‹<  ‘¼Ï Ý>'î/>>´=”ذ>†U¾›=H½NqÞ>Åߨ½–�‡½3 Ͼ]ož>ï4½†î¼âÜ©>¤d¾÷�>Ɔ Àê£=–‹j>õ{¾çi>/c¿>ì(H>;½½>ªÆ9¾&ý»½m›¾+~¾7r½=3õþ½¬L>§st¾qv�¾�¥m¾0 Ø>°¡Á> ‹Ò>_ò½sÚt>¥P>¿Ô½¾?¤)<‘[j¾Ø¢>°>¢½LÕF¾Äbоd.û½sÓ<*©={0#¼Åêö»õGŒ=Ý|u>—:ü½°Å>Ñ ô½Kÿ;>­\'½ð¾V [ºDwĽSü^¾|¡8>�‰“¾ :‹=¸ê¼¦ƒ ¿çÓß;Ÿó™=“$¾>¬£k½ýFk¾[[¹¾Zµ¾äü\>]µž½ >”°=:�Ò=Ù2¼Ã3¾žï§=¯c>õäY>U¨–¾Jü>Á¦Ÿ¼2Þ=å³Ç=áø<€„®½¿9¼¿¡Å½|¾DGœ>xæ5>)g£½ê¦=å=­‡Š>‰;¾òN¾6�ç>3Ÿá<à!>ø)?ƒ¾¤r¾L‘Ê=“‹„>æ2Y¾IÆ=ÿ@¾í+>­î€¾)Z=S(ì½YÔ�>Ñ¢>�r?:�¾�ØÖ=á#-¾€wÚ='³B¾ q3;_Ú\=Æ£»� ·<ƒß ; Î=¤ôí½Ë}¾ç°=ú6½#–%>²wF¾]o`¾ÕV¾UƒÛ¾2>€Ö–¾ÌwO=¼Aµ½Ha<¤[¾°›J>n]½ ³3¾½ì(¾ß =ýVþ=ZÕ<=¯Õ«>kbž½ü|é<ÓJ >¸�‰½„]˼‹PÁ¾¤>Ž·?«¾íų=SÔ >*±>EŸª¾Ú…¾�¤>ÐG¾²} >¢Ù¿Æ–H=ż=bŽZ½F7½¸ê¸<œ}c¾´o¯¾¹”½ŠÎz>øq„<Ý»¾UÆ“>þÐ&¾I[>�O¾ƒŠ`=į >ôœ=ýã!>÷7Î=g£>�´B¾l¶§>*‹=µ½+¥`=2-d>^`:uâ¾D� ¾â§š>†Âg>zBa<ÐK;¼Üü¾…úû»§[k¾¼¤>L7—>uS—¾)˜�<‡Ç½Ô ˆ=Æx¾ÈÏÊ=d±!>d³à½ábŽt)Ľ�ê±=6—‹<Çé½U‹¾¡¥›¾Îª�>±å§>^°>ko=×ÉV=hL=¶!">;ÔÚ<º^̼Žlž÷ux»è•°½h6>hŽ=æ°>¬�¾‹D9>ßZ¾£d‹>Œ¦à¾Ø+¾íBn>«·e=@žÚ¾;×1¾¶)¡¾À>{¢�>D}ò<5Å`¾Õ¸1¾Dé<ǧT=ìbœ=£üÿ½ož=¥ª¾€)>„+>r¿º^ÖÎ>®o”=^Dh¾ƒáá=•Iñ¾t‡²=Ê§Ž»wü»½Né¢>o•?qW>bŠÎ=±#Ö>Я¾ ¾'¾Å/¾{À=¢{œ=™ïA¾÷¶ž>S;ͽ”>Ñ,ãG8=Ì >$`†>81¾Ø³½ï—e>ksª>Å·b;¬“>Q�=¶ÆW¾W÷­>ôÕQ¾î&½É:¾óÙ>¤$¢=§ê„=ºK¾Ý€>çÏ=£ãD>ƒÙ“<‡Z>eä¼×’e¾î*=~y¸½Õ£4= #¾ùZ�¾u*‚½’%ˆ½ß1¾™;6>.; ¾c ¾Ó° ¾Ò½ú>>bž>‡ó/¾Æ«ö½‡én>y%¾3K¬=íš¾5> ËB¾Bl‹¾Dªè=AÏ�=Ì>»=Úc>^—ð;[Œ?¾È-Ý>B¡>q7>>±=Š=£¼[§ôÁ½ú�½ëûä>¨ön<” f½j,>DU†>÷0€>Þ;½}À¾Í¸¾Ø™½›l(¾Ê¨¾/¬¯=Ñ'f<ŒWí½ñ´ ½‹‡À=Šü{>Ö½W¾?¿*ž>¾“=–+c¾}šÔ¾y ô<Ê€¾Ë–>š¸9>•L7½X%«½ƒ7¾xf=¦²�>ˆ ¸¾4Ž›/è½e ¿Å§R<& h¼*=r,>ÁÙ‚=*N™>xe<ºZ›=r3b>r{|¾Uâ;Œæ';÷øI>gAÒ¾ƒ®î=3™-¾½0"½ùú>¢5 ½tDKù=×\¾o©h½´;Œý¼�˜ ¾e�¾¿Ö¶»Iúí½áÇ:>Óþ?¾¾‹ù=³™?ù‹j¾J Š>ß<¾K¡¾g&Ü`:©¾f˜>‡·s;�µØ½¸Õz=kƒ<Ðúo>6€>‡Ó”>” ;Êâ]9熾ŒK¤¾Õœ>I ¾€¢½tʘ¾ûÔ<Ñ‚H> Þ=¯>c–=Ý6¿œ0À>}‰>âú¾=•†&¾Ë×Í=J>â=:®=&ŒÆ¼µjí<½nã½t,¾}0=I‹t½ªMà=ºƒ¾g̼Ü¡=R¾Ú6’½ç 2>»&B>®j>J Ä=Ëà)¾Èn¶º×˜¿¾N&> Å>.ìY>ÐC¶=.I!=àúg=Ô´S¾-õŸ½¥¾bÚÆ=­Ï>¢á¥é¾Ô“;¾† “¾{â'=Y%¾–y½½&$Ú<äj> 1,½JC¾­ù¢>,g#=qò¾ ³¦>tzÿ¾ò£½]l> >¸AÏ=¶œ{>A¿z>a0 >�œ=±åѼV]¾íÖ>µ {>a @=ÎÛ<áh�¾:¥à>Q¾P‹¾3´½BLV¾ô>Ú‹>BK1>ºq¼èPÃ=U\¾=ÊM>ÿ(‘º¼A¾±z2>�¬P½0 @¾Ÿ6W¾p̃=‚Üœ>ÿ¿·R>t Ã=½QT=o(¾˜Øƒ¾MºÑ½ÂFž¾�ý‹>[n¾[ªó½¶¸Ÿ>É­²¸wVu>ô‡[¾ *¾0èi¾t~ ½¥ ¾ðGù½ £-=™V>ÛÃ>€A�¾ D�>|c‡½(Ú½Žô´=lîÂ=3"´½Z+>D°=!:Ù=ÞÔ >†ms½ ¦½ Ї=2’=à ¤=z´¼V­å<°×¾ûø>ÏÜ©=¤Ç·<€}²¼ñÚ=tI¾+ß󽨏»ó¦Z=SÞ=� A>Dƒà=9„Q=~Y =^µT¾Zà�¾à+,¾è°C=SØÝ¼Aö¾H„¾¢�>½>ŽK¾=¨›¼±¿d¾¤ú¼<çX?>ÞL¾Ìë#¾€¬™½›Z>„¾K¾Š½Uä¾¼¾…½+ôÝ=Ÿ^½*Œ>q'p>ȹz>PX½X�˜>ç">á0t<îW\>Žàº½˜ãj¾‚šU>Ù_+=ÓQ›¾›^½D�û…=•},¾Î—+¾ó6:=»šû½RË>ž™¢½D>9÷ž¾¡C>Ò| ¾µº¾¼Jò;¿T+¾L<Ÿ>Îñã½|•>lð÷½)~½ˆ¨>ó2)¾&¢>Y�>œr‚>Š­£½2.º<¦7\¾Ô�">¬ìò=ûÑ©½Ž#Œ>uYâ=tÅT½Ô-—½ˆ1;€ì¿>’"k¾mð¾W�#> ú ¾$Fi½Š¬�¾Žšš½ ž˜=ð:¾¢�+¾æ²·½y|Ì=Q?>u¸P½Itî=Õ½½oæ¯>èM\½ Þ´=Gñ½=éÒ7½i¶Î¾‘Ÿ>WZ™¾aáá;M33¾Öø¡> ¿Æ>t8>±¿=Îx5=˜>­{Ͼ¡ˆü¼$µ’>O>º=OK>6ï.>Þ>ÊgH¾T�¾ð&Ô½L‚>='7ˆ½b *=‘e'½ËKš>[>å²>ó‹¾àŠ0=¿ÜÓ<R¾¼9²½¡Z3¾¼Ú…>÷¨i¾'Ò‰½ôû}½Â»­>zH™=P‘e>o¡½XRµ=„d¹=9¸Å>ˆô¾ë l¾²ˆ>e"6=Z‘¾jŸ†½;°0<Û¨ý=7†~¾¦Lºõd½¾h·>Á¾º“=xf[½®QB>)ÃÕ=o}½³ç">M—À½�½�ty>öG›>-Âó½0I>ؤ=œs½A_"=Ïš¾!�¾×di¾Êá½YaÙ¾³^y:æ¿…¡¾Ò•É>TÆ.¾º~ü<ýÂ7¾‡>fÂ>ó ->Bß½I;u=/™¾�P¾X>¬—F=°�y=qý¼Möl>3Û=´¹¾o;N>4\Z¾RÞ"¾d‘W¾b“Æ=ý�=È ò½âÀá=âüǽß"å¾õø½¡‡¥¼ªúî ^0¾ G½¢~“>íz´<¨t>Q >UuB½äø¼-Øï=,6¶½<¨½åŠN< °>ï*;5šà½KªØ¼Dêp>z6¾ƒ—M¾}å—½$&L¾c>Í›™¼Ù2E¾€è5>GìÁ¼m;“=bÛ%¾Åž½P¡¬½ ³<å½£;’½Ã´Š½>ך>$†>.[=½Ò–¾d‰^>Á¶=™ÓP=»·ÿ¸`¿$½°Þ‰>[Ù>uê =%+¡>bò½DMš>ykÔ=ðTŠ»ß�>�Â>›&¾Ç ¾÷Wœ¾6]¾Cƒ>„„¢=ñ#>¹-N½^V¾H�»½Oº‡>`¯Í>Þ3#>Xè–¾ÅÌ…½MJX½Jµ=>á_>åWµ<>±B;Œœ>w³£½•¿k¾ÅýI¾w¿T½n㊼‰ Ç=Ÿ>¤f^>:x ¾ƒ¼+>”0™=ýY=˜'©½”‹>Ú-Q>`C¾´�½èJ=ÞÚ0¼ó=l{%½®o•>%õþD¥I>Õǽtà¡¼ÍÆ�¾·Ä¼:!Ó½ªE}>‰²=.0¤½X ¼;K°=ÏiÕ¼�ôK=rŸ¾ÚR ¾nòõ<�,K¼¹üË»ˆa�>�È"½�½=Z‚¾,E¾Ù}�<Їw»(ðO>Ïw=‰›B=Á½Ù:Ý…¹¾¹žo>ëÉ5¾›¶ >�\=F�Á¼ùÐ3¾–®B<õŸV¾·L½l9\>/Ëâ½§í{>]sÊ=󇼰"¾-Xß½¹4F¾¯JÀ=x9Ÿ>Ô* ¾c›¼¾ÒÄs—€½Fã<ã“>-d&¾DŸÎ½3–æ½?#=Ó4\=d@%½mÏ`¾"Ûß¾  ‹>¹*—>“Kí=ÿD7¾•>0¾ w ½þåk½SV”¾à÷> W½a‘M¾õ;Yð–>vr]½'K]>œ ³=-m=/Ot> 7é¼Y¿=¼{Ã�¾è C>í¦=¯ç­=�QR<@޾MU>2X°¼õ^‰¾[ä’½Ó­›>y¾o¾uG‚=iÛ�¾�Õ„>(Õž½2Çì<¢–�¾Í×í½žï¾ q¾¹�=~ÙT¾ üs¾°-=�jY¾©…á½Þ4×:Oÿ—¾Çê’¾°�U>àV‚=Ú®”½=£=¾7 [>üξ=³M°¾®Ü�>ätÿ=ðx>N˱>}™„=jÝ}¼Íã\½ûG¾2’ª>ï6*>¦š<ì1¥¾’>�¾MO¾È„‰>g ž<«E½ìŠi¼ôP½a›½½B#v¾Ôˆñ[½9½À�¦¾p§ô½´v€½Í|n¾ý[ ;8g=-̆>¯õ཯¾ >LЧ>mæ¾ÔÜ>ô=Oq9=›’!¾��R=Àâ�>F�¥>a‚¾yƒ >ªI"¾ôÜW>¶÷½i�<Âq¨½õ=Etü½ñô½C€í=kéq< ¿ªžµ¾Ý~¬>£k\>Ðvy>ÞA<»^?Ë.>§²= ð»>›»a¾TÞѽø�K>W%¾ŽÂɽ³2”¾Ç/>�Û=ë¦7¾Í.>‰³–>æOß>@¼a@¾\Ô¾£³>'`;¹Ø0¾Ê�=“q¾º1=OÎm¾ É~<Ö“ž>/‹i½³ æ½Z:½¸”=ü'¾“ä–¾«²�=ó˜³=+ŽG¾õ><=%=½4Zä¾6c�¾•oT>ó 8>‚Q½t>¥Sõ=§QI>rÅ“¾AN[¼. ¾ñ ¨=¿V¬>ÒƒÕ½\œ½•ñ¿‘�½Ï <ç >¤¾XãB¾ÚÞ½Uõ¾}�>šOt½â¶]½5à9¾ÏJĽ&: >’©ñ¾kƒ>Ÿ5”½:ä|¾ÕRD¾„l]= Ϲ¾ÿŸ="’/¾Jã<áÃg>tº½-¾=ÚEg>L.>¸‰¼¾u+㽈í=x .=AÄq¼@ôu=ŠÅ“> ¾jkž¾—γ¾N¾x=6B®=P è½Ð�o½]œ½¸½¾ð"›½c«½#±•¼0Ì=½¦r¾0Ö¾wö¼\�F>åbâ=ìk‡¾[S=YX#<.¢§=ÔL­>ìDí»Üá½ XϽMª}¾vÓk>Dz½»<©º<3@-¾iÃ.=OU¾”Kf¾K½ž=}w ¾ô>©¥Ï=Õ¤�¼8ÃÖ½s9n;Zm¼;´Í“>Z“j Œõ½"ª`½]ÕA¾æ½ôã=¯Œ¾: «¾võ½Ó•¾í6 ½4nÕ½sN>>’Ó½‘îR½¡ú¥½&$Ì=ˆa< GE¾$œd¾$Æ�>îÔ{¾Ê +>Ñ…p¾ª‚A¾ñ…Ù½Dý7¾²†>ñó >s˜¾cö >^œ>Îz?=0ä]>‹>º5K=,ÙÉ>,Oå½Gj³;>ob>ª¹Í½à T¾„¾ÓÎ9‚Ç£<Ü>…�=ƒ–:>T‰š=W€“½½8D>»î%>`vÏ=fð‹>,o�ºí>Á/½å:¾C˾>›‰>…Xz=±™>U ¾6,"¾)†ê½lп<ù+>r‘¥¾–¸±>ÜŒ¼hB¡=}†':&+%¾Hôð½¹XW¾‰`­¼&Ÿ$>`n$¾!>?Ig¼=ñJ>Ý=;åŽ>«¿ †*>7¾ 2ó=¯Î ¾ðö)½m„m>&=�¾<+¾Þ.=Ÿò >4W¿<Ô ü=8b>U>¾ _̼ŽÏ>·*¼¬¡o>¿j�=g[¾ck3¾ð¡º>›h„=Þy¦½¹sH=õÜ=ƒD¿ž¶>Ñ“>­Ád½Ù^ > ¹}=N6é<õVŽ>Cðp½‚G>í8Á>„Ò5¾"tY¾Ñ€¾Ìu¾|P�¾HÛ4½/‘¼…sz>âb¾>›–½[ >e<¨¼Àc>‡ƒ˜=-$>c¯½†³Œ;’P#>™ž >¦±ö½a ¾>nö¾Ú>6«r½vÃh¾5)¡=]'>™„Ç;¾i!>è]B¼íåD=šúä=D>=NdÄ=}ç–=®@u¾ ãx¾ª£Æ½jrq>³�ˆ¾ÏY<©Æ>Òô1¾©¾ë�Î>‡ÂI½Â\9¾¶�>Å¡.¾L>°¾h±”¾£¹Õ¾�±>C~Ib> >î8©Etº«+¼®V>;ZK’>À†¼�r ¾"±ƒ>œTI¾™ >!d¿(°¾c"É>�½=A΂½Z$S>çv>}bf¾‰ø=´Oi>M >‰ }>TᆽÄç¾¼<ç]¾èÞ½µ�=º1_=V£>Õ­>FÅm=;½r#>¾<œ¾Á,>±¬Ü=X±“=Ù >H7C>¡¾N¬Ü½‚Šü=k==Ê·=Wcv>¬¨º=ci >o~¾½½/½z�¾òn彺@¼øö#>”’ð¼*æ¾Ò ½ÿ…>+[¾³û¾R5>{¶Í>Ê z½æ(¾CïA>0CÛ=TøÀ½�¾˜¸:=¹ö<èx¾íÈ ¾¤ö–½q&L¾çÔ ¾'¶6½ Ýó=RøA¾ÜGu:6üÁ½÷kâ»?!>,ˆ/¾.�Ù¾n�¾ž˜ð½ðJ‡>B$Wº~q{¾wãÒ<7Xú½C1¾`²4;ÔL½Ÿ+]¾hм=§�”=ûG¾µ@=há!>š* ?Ö°»’û=yMŸ½ôÊ+>Q?£=è¸>¹8¾>01<ûì=ö»]=¯êê<[B#>Åõ½ÿl¾Ôо^µC=‰ŸŒ=±ž=ê*ƒ¾',£=²�§¾ Pˆ-‚N>E8>鯑½[É ¼/Þ·¾ë�P½ò?Í´ä½>é¾hbÕ¾=¦_ƒ>»lâ;fßý½�VG>¹O½J$Î=©ôä<‹r½°ƒ¾ ¾%¡X¾¸2D¼œ!j¾q—v>~;á=kÏ>dz|>Ïó•¾þ²¾‹0î=µ­%¼WA<½WûʽiÜã=™Ú¹¼ÆH‹=Ä�»Ôþ�¾¸Â`>‘ª¾=Ò’>ÉÒ½Ägº<™�-¾Ê޾�ûÃ>Ñ–2½Ïµ>2ƒ > Í =5Ûo>˜+£¾ãØ?>–\&>° ‰¼‰‚½=Nð�>î=<" ¾>ê�»[n>!Ì�=ùü™¾œ¸;àà½Ä ¾^ >>´j¾óŽE¾3Õ�¾ƒÆ^>Åb½¢µÄ½äC>¿˜¾H8Ï>C.×½&\†=a•š=Yyð½I< —>y6ƒ=Yà½|”>ÅÒ“= í§¾ž?9=HO¾:Ü»?Ù8½›6½�É®½Ô�c=¶Å½¦$½ �>ÙÊ>>/§A>ˆé_¾|ù§½>M‡>Ÿç.>^}c¾?´#½Y¾�>V¯g½Z>U³X¾ì0…¾ä;Ô½íŒ>Tš”°=¥½ 3(¾aû)>Hb¾ŒŽª½FTÄ=.�>Štè=`>+D²=Ì­^¼ÕN=n¾Ì÷=½ùÂåÖj>½ø¾Ò%¾!Ôª½S*ß=з=¦ê>ä°³½sG,¾ˆ�>\úã=Â(•<Ãr><“7½ð[˾E™�¾c}L=9e=™…=W¾�î)¾^];k³ö=¼FJ¾·I> üî½~ÛQ=5›–=ìz¢¾ÚD¾"Ã'¾ÌJǾâ >fþL¾®T¾+¹=(™Ö>n_ >'ík¾0qñ=†—z½™Äm>¬ˆ=¤+¾~Þ=ò0á=jÀ>Ié="˜=þâ‹=ײҽlu‡½Z�¾�1¾¯šÍ=í*?¾”öÁ=ÐQN;¿;�<~ò¾߉>õBÁ»¯Å¤B°„¼òu�\Í=Q^|¾ú^i¾Lœ>P\>�Sc>æÇ=>ð‰Û½6Y«=ê>ѽ 郾@¾>üD¼$‰„>øŒ�¾Bor¾>äQ>sê½6(>.ÉX>˜HÆ>Ášh»¼y]>¼´=ì=ô=û*$¼”âºól€=c€#¾9xå:Zõ"¾üꣾŠê‚¾#½W½ô÷ö½F½Æ¼š¦£º¨¡Ï½ X>æ‚Y=÷û+¾µ”>Âm‰>ãªx¾)”©=HÑn¾ E¾Ð�2=å´X>`«_½˜Í¿½Ð3>"?ä½ ‚;¼•f®¼V^¾¤Hà¾Ë­ö½Yµ5=dgǽ ºo½É´!½Mt=ò~¯¾¹”g¾Óf¾zô€¾P>¶o§<7?>dÒ§½j:0=ˆâï»fm >;QŸ¾n­½&ó¾üK%>^Ýp>V:é½§¨1¾°˜)¾ô6¾d�½†Èù½KgU>çD,¾›ö½«œ†>FvÛy¡~fn¾Bž;ô�¨>:ú>R…a>Ÿ§¾‡qS½‚I¾A6®<ñõ�>Š‹3¾Þ·Œ½‘À#>ìù÷>~¡-¾~3¾ìln¾:³»É'!=ˆnó<¯2ó<¼t>,B̾姽Uׯ½;�>,L›¾œŠ�>q­Î=òfà>å�Ž>š >^·=TÔ¿I»v¾†Jä>U„â<îÛ>¯å=¯N½\°Æ=8è¼?c>5Ç#>Ô¸ ¾M—½‹âž=� @½…ls==`’½Ä&;=p‘=Ñ7©<,‘¾Ý�¾ì¾îmѽ Ok¾e]>ä\2>ùœ¶¾L“§=e€7¾+–~½�<ÿ=Å]‰Ä\ð=`=�>͇±¼<ßæ½_?>س(¾½bÀ½Àa»>)ök>Ê.U>Á€.=Œ‡"=]½>£Äþ;f˜S¼Íæ²=ò“Œ½¢s”=ê¡g>¾˜Ë=Ã~‡=t„½‰ ¨>~®ó½h¾µ>V%R½`z4½øë<¾áw¾Ä̽­Áa¼²8æ<ÙÚP>ȼ =°ÄL>%Ln»¶Ù¾N¯³=CA–=v –=Æò;WæC»Ü¬ö=äS]=ê<£¾:îмoà;>Vžè=;Ž>*œ>Š­ =&$�¾Dl=9·¾ •¬=u€¾Sšx¼¶Ï$¾ BÂ=©‰ >Ð)°¼w®0¾çô=àF¾~=6½¦ã°>ðªõ½"�&¾�[œ¾Ñ®ê¾­ö+¼ÿ:T>žìP=e“6=œͽԘ“=ÿáU>L…>~쑼6•|>m÷>rÕ¾•r<É&=~uŽ?[Æ»¯Yu>}Ñ;=ŸíG<òýL>DM&¾ùåê½vs½{O=Ö˜½C¿�¾úàÕ= E©½Q)8>ŒP ½Ÿ^ª>òáù=ýl'½ÏÏ=¼0¾2ľb=uö¾•Be½�ÈɽLl<¾-œ½Ðõ¾C% =)Õï=D=³^¾;ÿ½…�-¾ 𿽊PX=XÔ¼éË„¾œ+P¹úÙ�>x³–¼ðÊI=¹æ£¼Qgb¾;Ô®=£[R>,9f>UCí½�ðr>¯–¶½B½ZT&>,¾Ñ>TÎ >�¥>eÿÄ=!�¼¿Hî=§†—½ÃA¦½cId>o�¾ä2L¾”¾ãù¯»òYþ¼öt©¾W…S¾@sN=tú?ƒ»==D¾õ‡¾ñ㉾i²ç½i»y>N�U½)½ë > &ˆ½ؾÒGª>œ% >`‡…=€>ð ¦=|¡„>ËáÝ=&• ½ä->»|…¾|“ð½F• ½;Ò>f½)±g¾D½”»i‹Ö;“C©Š‹¾‡ •¼'$œSß•>JnŽ=¶ÿ>v?!¾Þ9‘½nê>}绾kF=žt¾¢¡A>±>ìØÎ½ñ^¾”ºÔ=ý6‰=¢o>â¼==¯°ô¾ÏÁª>(¥¨¾vὑ’r>þ×8¾ÝNͽלX¾Ü¤±=õs�>5×]>§xt¾5²·>ºó·=›§÷½>w>–‡¤½’÷ ¾ÒX¾}Ù¾Áó>… ¾NE¾7ݬ½B¹°>Ÿú½µº>—éF>ãø<¾`i¾%Ï<3÷¾Y3<Óô>Ûc¾”ó¼=þ…6¾@Rn½¤§<˜ma½9;�>³ª)¾)’<ˆH¦½³ �½Ü|â½~Š=)î=T2>y�>ÀGû½±ûv>`o‡=�)¾…ðê½\+Ä;FU¥=fu>k¯ü<ý‡,¿Kä] &Z>"Ù=‰h >k»8¾UÎ>¦‘Õ"Y޾‚É‹<[`b¾¡mé½e/¾©…¾ô[’¾˜i½dLû=ã×¾ ž³¾×Ä=>rz>ïÑ�>€Þ<¾ MX½•‘—>:ɽrHÝ=^3<Äɽdx¾ös½Ò¨>¾‘†—=t‘Ö=ز‡¾!Áñ<'Õ¾¸Uù½ïÅ輓8ô»ã¬ý¼\óN=GÐ˽SÿÒ<Ÿ´#>Zá¦>¬¹Â=y»<=#˜¼x%>êç>æâÀ>*A#½Å�¼ˆ�m¾))’;€S6=«.¾àÛ >ž³§½¼R©¾¨oû½ßÞ½®-ô=õ!¾ïˆ¾°F<=p">ês½iÅ>…¿ô=�eþ¼vþ”½Ùp{>ÎRs>8C潺e{½Ë¶ ¾Í>ö½§½Ô3/¿t�v¾ÊI¾äRÔ»TÂX>œ¼ >*Ͻ^E¯>TÀò>-/𽇆½4²U>>>ð¼äx£¾TžZ¾KG޽7�·=T$‰¾²á«½)²·½¹Sý½'í¢>{ç½Hˆ˜=Ó»½¢x@?k@*>i�(>š„>ít(<¯de¾ª{¨>¤ï˜>Tc6¼WÑÖ¾;åÏ=lb=>õ<Í>M?%=% Q=»¨u>öL=ýöZ<¯y•¾Ò×g:ÿ/Í=�=§¾ÒÂé=°Š>Ǿ‹¾A¾Ãka> Ž>T 8>È/&¾p©f»ÔO=x Þ½�Ð$¾ã÷½àt>hæÚ¾Ë1M½ŽÂÄ="Œ<ôæš>'*;>(±ò>ùÆâ=ÓLž=~)½‰k`¾n“½úƒ¾$é�¾�‹§½»V>Ñ߆½I}µ> ³¾ Çá<¦‹Ë=ê5¬>úïÇ>Ø=É<[Žü=Fì<Ô²�>à”Z>ç={/λqó¸=õmº>[”¾t]ø`èh={J+¾E¬>™¸>o³È½¥¾�>‰¡>Û§º¾`,™=Hô9¾‚µ<~Ù>WL_¼`¼=^Um>áŒ>¦¾ÔÀ‘¾¡ >ì1¾$\?xN¡¾¾q»>ekx¾ A¾PKï½ù¾ˆ)“½Tc�¾½>¼ôÙ¼�-;VÓë¾0Q=rNa>p¿Ì=ßô¾@r¾…¿½[¾§LŽ>8«>•?½|0=æwн<|=däú½{ ™¾¸W¾}ÌX¾Sf=Øó©¾#• ¾ ¾×$ð¼轪8¿½¡QU¾‘z¾ƒ(9>»u=> Æë¶µ„>¥¤¾�Ô„¾ž„>½Xw=øˆ­¾©Ô�¾&æí=@@q¾µU>tÓA>eA;£Ã2>¬V¾m]>Ʒݽ·¹>Æ& <‹û†>ÊQ;ÒÃ>w»;½q¾&¤¶=®ß±=7~;<‘=VÍ%>ห½L#|¾J�‘»î€½ß/4>÷/ؽ©÷=Fè2>¤\Ú½C=f=ÍÍ–¾/z¾8°>Hò¨¼Æ>�½"ÿ4>mLx¼[[„¾­bv¼xX§>ç¬=°Õ<ÑWý(%ç>ÅUß¾ôôÚ¾öTP>‘,û¼R¨ª¾ò¾ì ?2rE>ƒ÷7¼-°;¡H•=kÆ�;bZ€¾ 0¤<Ãß¾–È=…Ä;>‚µ¾ˆò’=Õ`>ciν>C@¾{C>”‰Ì=˜½õºI= ÷w¾ˆÂ½r]Þ>°½½' =ȹü½8¾5Bé¾×bÒ>ïȇ¼g f¾_aö=?u”=¸¿¼Vu >/�)>%¬.>žBI>¨v•>Ù÷“¾Òss¾×­Š>6…Õ>‚ŽKÏ8½n£¸;%wu¾öv>«Ú»î)½óñ¼†±t>óÓ»=4™f½XðÒ<|1g¾[/¾Oݽê}½|»=ýÓa>u™ˆ¼á¡=È>X¼nÚ“<¾K)¼8WT¾Ða=b”N>Þƒ>T,>z �½=�̾wv·¼br1¾°ö½¾ïj¾ ?˜=U>>û2?½J®!¾ß™J¾¬•$¾Hxx>œÜä=Ý H>C>ÔÕ3>-·Á½rP«>õ ¿óŽ1=PµÓ=À,¾1L5¼r„¾�§>™¦Û>—~‚;¼W‡>Öú½"ü½—C>½ Õͽï)s»@ >4�ê½.±>A×—=àe¾Óã]=ÞsJ¼ÄK<Ìû�¾‡žA»ß^=ó¼ü‘x¾§ÞÃ<ÝIR>—bq=» ¾ÿ T¾|ºÆ<•†¾º¤ð=ùžM¾=剾 Y£¼ê­;òY6=DÝ =…¿º©Þ<À½>­Ù_½ÛÖ�>EßZ=wä½W_Ã>²Ç`½‚2w¾\t„>%¨Ø¾+9>5Y»í[£½îÇ’¾#eP=Ü0¾m-á½|jØ�}¿¡¨¾N¼Œ½“((=Åw½~„=en‘¾"„‚½1³¯¾‡$N>I¯k>$û{½)Ý<ã~>\cƒ¼©ÔʽNg&½Šù1¾Kœ¼þ’—¾‚¿ >úæ\¾}dl>i€Þ>Ut >g>‡²>ÔPü¾¢¼¾žÆ_¾j&K¾‰]=å²ý=Oh·<|=œFª½†ü¯¾\Q ¾ gÎ>Hr>ÙÁì=î7£=+»>¾së=wï˾�Ô4>__¾]¾ÇíP½ ÚJ¾âz> µ”>h¨ð½í´Ï><=W½f\¡½ ÒܺbɾÌÚ:ð>á˸=%¾´½¹)Ͻ—Ž¾ÉŒ=Ù” >±Øn<¿]$>ï¼d¾ÑŸ½«=¸°e¾Åô=Ck½æ,’¼ÅÙœ¾!o¦¼¾ð½ñJ¸½¤k(>74>Ì1w<|>|ÒÜ>“M>úi7¼ŸC[>¸„€>ScÝ>}ý�>E«E>–=®§È=’øH> zŸ½î;)¼-œ¤>ÞÃ0>«Œý¾J�¾ñ¼œ¾_nI¾[÷e` >z>@U=s³‰½&ã!>KÌ>FÐ=Ϫn¾ '½6-P>wŒ¼XBE¾ Uˆ¾U^X½ÎŽp¾Ÿ'J½â©-=ÿøŽ>^è¶¾êò:ÒîȽþä/>Av¾)r*½S(õ½ 7¾³‰>Ò!½’ÖÆ=¤ >¯R€>$蛾Niƒ>Þ$·=ŽSH>¡ÑÊ>>{°>rKF½³tî>fD¾Æsý=ýûT¾0f¾É]= ¼¾q¢‚> W0>�(7>©¯J½(F.>‡‘3¾ˆÍ!½Õà<ͼ>$×= e ¾ŠEð½ÆL¾Mƒ…>Y³˜>3‹®¾15\> ˽ílx> ©¾ã9¢=®Qž¼¯¨­>Ê×G>˜íÂ=ò”�>¯¢0½NJ�½±S>O‡'¾Ž>¼¾†•¸>¶èƽ«ì´½Y\>ê䦾5¸¦¾dÖ»>�tŸ¾ Í�¾¹þ‚>fݽýíd¾¼oû¾}R€¾lRl¾ÿŒ&¾_6Z=Úp’>Ÿ•Ý<¡ëξdhˆ=,ÐØ»ß<¾­ý_n†>Y#>¯Ðx>#@†>+  ½£p’¾0 H¾ ¸>îÖ¼½—R^½úüG>Qì>ú¸¤¼û?½ü·¾k `½ªòݽð䥾ý ¾íü½ù +¾,¢<×ʼ‘ú‡½2ëg¾\RK>û;y=3tf=„/¡>Ðy¼¾ˆb<0Û8½1¦Ì>«¥f¾ÉÀ¤>!¢¢=Oö¾ :>x¾Ó±™<�›ÆÜ7¾F>��…>xÕ>�j%¾'DŒ>`˽>Žz > ÔS¾0‰¼ÍGý½ñ½;¾j>¾9M=-ÔX=¼3o½ç¿Í>•é=¾Ï‡S>«­=iea>Õ*ß=8{Œ¾§±H¾TÊ=ö '¾Ú>ÐÞ0=ÓŸ)¾ðQž=Í_|½k Ù¾D`o:w>8®í=ñ…À=™‰’¾¬¾K¾¢i=¼è¥=ãá¿Îat=.âq>�I>_9â¾¼' ¾vH¾§·æ=Ö3,¾i›¾Ûµ¾ˆƒÃ½¼"f¾ï*¾Ìkõ½z¨>Æ’$¾”ûõ¾‡|¸>Àê¬<œtE=œ ¾¹î¸= ¾¥��½]‰&=ºÊ=Í[¾p¸¾M·§½”�"¾12%4™<Žg³¾)èï¾DÖ«>1»Š½g#ƒ>wx·=OQá¼—Gß½Dä/»#ÎÛ½úÕ;>}7[<”ä–¾mÙ>&Õj<‚A:×”:’¾#w>‘UT>ð8>]ø‚¾ÖŒ¦¾ Pá>ãwª¾Dg‡¾ëDx¾²&¾3‚2¾>{…=¹Ø¤>Ï*º½å¬>ðÅÍ>�Á�¾Û¶â=îÑZ=�“÷½Š ´=×Ü«½þ_>&É]¾Ô¥e>t¦³<´Á ¿l½m|o¾£�[¾¯é¼à‡ >ž3ä½u‚9>èÌ®>jùó<`Å»<Ólž=›ó>j©,>‡?Ær¾w‡¬=‘ý½L£½ù‡Õ½R:¾]4Œ=¢ã˜=¸¡Î¾å.>rS†½mp”=o®>̳λ;�<>&¿¼á‚i¾!nm¾aç:=«ò=KN?goŒ<Œ=°ÝM½K©<ض'=¼Š¾ëS¤¾ZRˆ>ÎÒ•=³[9¾Ê«¦=¡M¾úa>›8h½\ >�)Ÿ¼�y½s>ꉵ=/›A>Fûi¾‡�=Ÿ -¿¿Ò>R{*> y§=T“»3çw=—�>¹> JT>ˆß<>6/Ž<ï2å½Ì�7>R{­¾1ÿ¿9I‰=Iê¦>’×K¾ཷ�½^”=IK�¾ï9§»BÉS=ëå²>)­=8 >Å¿Y—¾ ®µ½W³*>†0„=-¿ á…¾¡‹ >ìæÛ=ÅdI>V4·¾íè>½¨µ¾ c¾Ç‰_¾^’¾+tî½1L6>&O‡¾¬·¡>Ïì¨=ÑŽ<½æ¿®>‰>Ôl”>½Ê—¾$Û>…g¿É ¾B’¾Àž¾”1‡>¨Êð¼Èwξ“¾ Ò»ºÇ¿·#¢»Ì†,> Ü_‚,¾3À=ØM>Ðþ͓d¾.ؽdDÛ=tˆ—=²-’>)�v=êK�½=Ç3¾þ =XPK¾˜^Ö¾-§i¾¾wDõ== W¾2Mj>Œæ}¾­‡ð¾8Ì9¾4™>ÑÓy>ûÐù<øÇJ¾•bÅ=�Ð=­—3½€–ƒ½ƒ\¿ê�¥¾7Åo¾e&‚>*ë½!ù¨>tœ=�Ÿ6¾5â>Ʋ={íÛ>ö+ô=†”=e{0¾Z~%>® ¸=5øš>t¬Ñ<>ˆ¼½ãÜž½Áp¾gwˆ<¢“>ª�ý;Ò‹Æ=~üмmo=¿WW>WvL½”@;Ïe~>‰>Ü´ž>46g=ƒŸ$>Ñq¾J ¾‘þ>-3罓üc–½¼ùƒ>R²È=x%¾K)Ø>ÌÚ<0€­¾×e¾¼û”>ªkŒ=lm >Ðñ¿>ÿ÷̽`:ö½­äÀ½ºÝm>Ó; ¾¢çà>Þû=S¸ì¾6©<þÕì½/iƒ<î#´½ïeô½8vL>F,¶>u¯W;Z×[¼Í˜b>U�½ó6̽½ô¡=ð»Á=�Ö=‘Pá¾ÿ Ø>¼Zé¾@ND>"»½h’¾l7e>šø�¾`€B¾Ù?o¾C¿n¾½Éjë½ø#¾Æïæ»ãyf¾©““»Šúø=Ú Å:I@‡¾+Ö½™å½–ñb=8 >&|£½×–ƒ=¥b^½j\ =z'=𦡾¦™>‰Sg¼êYŠ=(‰M>ƒ³´=b†ì=`ù³¼+Ÿd¾�Á­¾·W�=ã„é=Œsm>óA ¾_’›¼Äb»½mâŒ>—¥N>÷ÇÛ½¤Ó|¾Bø¶¾ã"Ë=$Ψ½¤‰§=PÈó¼6HM¾Éö½JÍ ½8ÓÍ=Q.>j8(>Yy>¡P>u¡ñ½©ÐÍ>Ö”½íØ(½yC>}q›>H½y'¾,°:½VÔ¢= §3»1�>£År>²Œ½(P¾fò÷½Á„¿>Öû¾w*%¾òï¹òÌê½ï—¯;ñŸí½_Þ=›5>¾�¸G¾·–¾uR=«L=Üù»ºæ“¾ßÁ>–ú>´j%<Š6½k*Y¾"M‹¾ÄªJ=oîÇ=Qàz¾3{¾ùÛ=W#¨=7“[½qÝ“=³LØ= ˆ7:øv^¾•U=U{½ô¥º>7) >KƾÄ/½eQÐ>®/¤<ã)¿½…¾…�">É1½,ÙÎ=!§½pká¼› �¾Œ¼1¾iø³¾–®¨½=—›=ØÜª½*ÿ»N%ª½šÛ9>ð’=ð?Í#‡¾æØ ¾„M±¾eŸœ¾Ds±= ¾È¾ï-q>Î8¾+—>ØS©==ï >Ô>j¬Õ½é?46A½›=¾> ¾?χ½!m‹<êL‹¾¿m¾×3>4zñ>±ÂW>[ ½'8�¾Ü¼=¾ÅÍe=W¨g>@¦þ=Ç6…¾žJ¾ÏÃT½ ¨ˆ=<õ5¾C‚.¾ª”.=[­¾¸09¾"A:½c¾•>aîX>U­|¾56¾>¿ù¼ín“¾l4Á¾Üù°>×R×=瓜¼.Ãå¼D–h=rˆR½­—…½à­ý¼^¾U~1½â­™½ýÌW>Ếçl¾~'¾�Ì«=dœ…½PM€>~’ê»vê'¾õ{ݼg¼>,•½¡�Q=žN޾Ò^¾XO>0Ì»:-E¾«]F=úO[¾µ$=Jåt½‘ >º]>”�½£Ü¦>¿äJ>¡U‹‡>'Þc;[És>­¨Ò>Óv�½QϽj>Ez²>ÞX =ú¹‡>C ½ÓŒ¾üQ¿ÖØH¾°�%> o޾‡v2¾#³‡¼9M<7bï;¯/¬½µ`:»ÎN‚ºf °>u->Ù뮸,Ãa½Oj‘½hÀ0>¾Ïç½®˜x>¬Ç{>"í½“R®½÷‰¾�–½‚Ë”¾A¯>˜âp=Lñ€½'dÙ¾!/(½ðÎP½>àL¼"¶=Füé=!k;>hÛÒ=EK�»u*À=óŠj>ª¢þ<Üÿ¾©�j½90>=f!½üñ2>øÕ¾)c9½¡5©½^‹B=<د;,zF>C:±=h徉7<¾ !C=ïwi= oR<¿�’=8Õs¾ŽD¼Ð‚¾6ƒ>ÓÇ:>4ãc½[Zï½®v£¾Â¿a½ë.—;•V>änÓ=I·.<ë6žEZW>ÍB>÷‚C¾ú';Ágô>Yhª=�7¿i¨Ë¾by½ü¥½¨½ò5ø¼ïYÒ>Þ¤a½ûã;†¨â<Ý‹¾>0û½™l‹=˜î¾yƒÏ½ÿ¦—½ …ù½Û�+¾¨9¢>§i:¾@µ]½Í’—=”»>&jH>éI½¥ÕE=ÂŒG¾6¼ ¾”©¾ù^¼˳¼¶̾aÜá=n�=/ü>=åÕú½à›=¦Ú={Ï>”>oç#>ù>ñ‚¾×Q>}}>Æò˽,’ >"‘›=Šî->õ™¾%û=p‰¦¾uGˆ¾Ã ¾A‚Š¼ÏŸÀ>p…�½TP>þ-´½£ÝC½Ö‘&¾N‡=Óçy¾ÒÐI¾  ¾ÉľYøU¾‘_ó½á*¾Ô˜�½Eþ’¾á=¦=¿‚¾˜>Ÿ[³=ã(–=Ïê½Gh¹=²O:=ãe½5¿A>BÁ>T!�>‹v=AòQ>Gºj>Y.�>¬Ãs¼BˆD¾ á=Êó¢>„Er=O<¿yó¥½J™¼ÄÅû½œ6½Ù=�c>bó¾¤èƒ¾î¢q>lh ¾[YÊ;üÒ&=Šö= ƒV<~îÛ>݃‚>GƾK÷¿¾“ˆ³½¢‰ =gg³»[ª¾5l²= %™½Ë=½Üú¾cËÉ>,'=Þ:8»çŒ½iú>|/>°Æ=¾7Ǩ¼8)1>D$¾í½dûˆ>8®¾{GQ>¬¿¾>as£¾Ó?<¬ˆh=}>=󸫽ÊÕ÷¼ôœà<åÂ"=áD½UÂʽX!¾R;…=´ü˜> å+=3V%¾¹Ã,½žÍä=ô”=r`œ>¶Ê‘½Öd$¾åi€¾óe‡¾ä/>€; ¾ÑS¾8_Ú½KÉR¾ñ ì¼A ñ¼êé>Üá=ÚÛ4¾ºq¾8­`>¥Xö½Ô8½qW¾ž3¾Žû›=*Ï(½z¼=gâ±=¬y£>¯c»-å?P8µ½BÉÖ=$®>tçR<« ~>¸ŠI=°`4>‘?ܼ™@¾Åˆ«=¾/$=c^p½ên¾9\ü¼ò·´½—æò¾¡ìM½P Q>0éF¾M'p½Æö½;Ðù=Ž4ú»¾¥6=åܾùxq=åL”¼—44>Û,Q¾¾¦>¸kˆ>¦²¼_=;&7½ý:¼^7£½è3ѽÂ;@¾øG½µö>Õ5º=sqË=÷…Ë=¤hY=ô¸H¾rÖ>ß�¾T´Ø=�û�>J»^=1ã§=ƒ/œ<Œ€=—ʽpK}»¨›½›`A>Ð Ù¼ 'Q¾ý ‚¾;©ö=²þ ¾Œt¾J0�¾É�x¾ñMÅ=,ž…>þº>‰@¼½Ô:½¡1‘¾à�ª½ân=ÿ‡>P‘>UϽ9Ї¼ݦ=ê°¾Í\Ì=àáÆ½G:¹=ø8«¼£:½{M>±¯¤= ú¤»0 =O‹¾ýp >'õY>+ ¾Hy°<€A»=w¹�>—ŒÖ¾½$Ö=L)G¾äB‚=Å5¾á(ƒ>´[¤¾)º½sâ“>ö‹ñ=xܾ>“¾H{D¾uÙ¿¾Eb¾†n8>ô>=™Ž=k{è¼÷K�=_tè<êm>O†�>«ý—½«¬!½W’=:t­>(=°¾ Ëy>šìÔ=©¯|½Ùd—¾.WC=ؽäÇW¾ô˜å='÷ ¾»ï½Þѽɾ¢eŒ=5Ò¾¬±{<ÝyÉ>gQ¿lž>Hx̽8â>Ñ*–=o)[>QÜ#>R<Óc>Þ¢²=øL ¼ç9>å?›<Θò»Àî>pÍ{>É¥J½çŠ>þ²Œ½�ÌŸ<šUg½^ñ>³ùo¾þ"O¾é ¹½ÔK¾Wè¼>I6\>íJ»> o¾bùâ=CT‡>ãg?ï™k>Ñ[%>*áš¾`Œ¯=i´“=œ€„=e:Œ¼=~:>²=½=×Ý<ždª>(̽ª³É¾lDª½•i¾8~ô¼~­>‰ÿ»=–3‹>PbM;÷ô½Ý>L3£>näò=ˆJô>¯cg¾(­X¾9´—=ð +=r®¾w÷“>¼Ìt½¾`ƒ¾b²‚¼[89¾ýšo=üZ¿Çå²¼^¥¾¤Â ¾Vcƒ=ä ¿åd=÷£E¾æþ0¾ª&¥¼üAx»†­>¼I)æ½zõ½×·9¼KØ>9åݽ<„>$U3¼ñvœ½êöç;öÍÿ=Q%Â>…;1W$½Äå'9©|¾tÎâ=ß<_@,¾L³Ÿ¾Ó.²>ËÁ>Â’ƒ=”»JÌ4»î}°½g'{¾¨Ç½àOÖ:�â=’5g>^Ó¤¾¨)D>i>Fy>Nn4¾Ž0©=P5оÐð7¾ ë�;;nƒ>Úaû½¦Kñ=Ëà†¾È׿=p$½ë:ü½ah¾õý·;WÆÜ=<ë">ÐÅÖ¾egü<=2=Z¸Â=eC›:)¦A¾­EH>;>r:7=¸“´>°ä˜½ÌS”¾¶˜‡=?ì>Ô&¾ZÂÅ¾Ö Ê=oOø;ï�m>¼µ=ÄÖ̽ 2s>u°¨<# ¯½ä{оӨ˜>yž¾¿êŒ>¹/ ¾`Œ€=K† ¿m¶Ë>y $¾bŒ¯>+ë¼»¿ S­=™q>fO�¾Äu8½å¼h»+>²‹¼Èä—½¶Åª¾j…u¼ŽÖ=¾P«=²Ç>©o�½ŠH¾®vo¾Z ˺F ½&|>Y°2>”¾ì'�»‚£Å½µþá¼GÍ,>˜ ©>žVo¼NFµ=JâÁ=�]°¾üwн'òŸ½³`ˆ>c|†½èÂH¾²Ô½O«‡<¹ÿ�<{‚[¾ýMa¾¾¸=øQ¯½Š%x¾|Ž>½ºK]>h =?€¾=07¾m’µ=†¢(¾6¥>ΣB>ONH¾¬{¾ÓÏs>/hŸ¾{îH¾N¤c>Ê9R¥ïJ¾æ� >­9B¾TÄ>mq4¾2Ä >xSÉ<¾¢:¾†¯}¾Û¥Ã½û0—>%:‡½ù¾¾S�›½­œ,>ßÍÎ=uï?=>Ľ¼´_�>ÂD>Ü$(>Ew€>¿Ÿƒ½Á ¾6!Q>Úäy>-‹ ¶uÁ=³û/¼-ÈS=ÞƒG> þ°½Sá=t>œ¾vYJ>Wá§>�¤–¾\:Á½ŽÜ>Ÿ²¾=û¿½6Ê9½h4³=Ñ;=¾]ÓÉ;+Aн\�­½Ú =¥;¾§¾•u`¾C³ý¼]5>î2=JRz¾ÈRª>ÊõÏ;š¾5|¾ºÊ>Öà¼RvŸ;#½[6M¾ÌÆC>â¼è_¾½õ c>j±h¾�ä]¾ÀЛ¾‚¢½NZ¦½::>šÆÁ¾A.½½êº�½<ƒ…=O>Ø>t·Ð=}K>µ½A¾y©ˆ¾t1+í`ǽØQc>Žù<µæD>܇½Ô1=c=[¾Al½�ª*>ú¨î¼ ßž=¤œ;<œ¾ìýE¾IÁƾ'zu=:ø¡=…mÍ>KÕ<˜"¿zpB>s¾çù™¾ö<~·õ=ªgÝ=Õ¼]$¾4'¾ñ4ç<$Ž�¾^Ì>€ð(¾Wo­½Ã"ܽ'B%;ý)>Ø2'¾uP¡>³6¥¾tÿœ¾J�9>µX‹½ö�=:†½X§C½ò¡û<±/•½Ï€=…8I½W~Y¼uÊ™=¶˜¥<Ûä=Yb‰¾7|¼>Ø=#>†-š¾N“ ½u¢½-¦>½½qm>úÖ~=àªÿ¾Aš¾Ô¢Ü¾öﯾOëõ;:8“º^ À=9*š½ÕH•=pÛ9>ÂØÂ½@I"=;Ѭ¾S ޽Cg¾í¾…ž=®åâ½Fç½!u²»gˆ½#ÿ=¥|?‡£>Ï%#¼38 >'©«=ï= >—Q½,“-½Îc<½ÓV5¾M¾9îV>³ø³>ôK—¾ÏM>´\¿»E9¾{Å>ô¹d¾¹ >/Ý«>Ú󇾫ïû=ObݼY÷Z¾ôëM>†+>„Á–>×J4=z\�:U˜¾»©;ó²½ýšŸ=wë<Ö�ø¾œÀ`¾`úZ½j‚½2Òz>„Ö»ÂnN>f{Ⱦ¾&1<ïn�>a^‘¾¨XÛ; Í–=€?;=KÕ¾gR=m²Ö½2>/¡ ¾éc*¾� ¾®Ó‡>Ÿ}>màI>Cß¾>V>¨�®>ÏÎã<}ïã=8ßo¾ˆ¿½ÃƼ½d„È=j:X½=¿ð=‡«>´L_»éý¼�ºr>ÑWâ<‡ÔŸ½7׸¾ume½Í\P¾B''>«Â>…¦$¾GŽP¾^�œ>™Ú½ ½Æ¾GŒA¾'@>´$n¼ÝǽCÉ·½ºˆ�>7;R3¾Ñó¾ŽèнZÞ„=Ô$,½úZƒ>G��½º• >­c…=z®Ç>Öš>sôŒ=ú¾åð¦½~Ã>.RQ¾ %ß=^M¾–W>9™¾8Éð=Šr³>Ô{ß=§Ê­>PÉy=/×¢=¥.ž¼1zí½Å¡W¾ñ&‰¾ø‡#¾°Wå=‘ÉÑ>ôÊ=äÅ‚=øJ>ŸÊʾ÷¶Ò$ô@<õÞ¾‚ñ~>ß57¾ö#¾¾_V(>¸'½N€½…Á£¼Ùêž½‹®¾¤v>ÏEñ<œA¾^$ú>|%=ß“¾y¥¾jâ>4£Ó<<€g>KC`½¡�l>*€/¾­¥>¬‘8¾²�¼¼ðr¾qÔ~½Ðö>°y‘¾­Ä£;J¨x>&f›¼ö´›>›üƒ>_Ä‚=Â0x¾ø™>þ‡Ó>ïnŠ>„b>cWò½?—®¾�l“¾#^¾åg/=†R<”�‘¾°­¼Ž°¦½Ú—_>›[>˜�ë¾ £Ñ>À÷=£l4:\6­¾~Þ‚>$cl¾¨ÞŽ>‹©?ˆR>¼Hñ=£ƒ>#U>–âÆ½‰‡‰>@u¦=©!ª½=G-¾õØ ¾]‰>Ú�„½xµ—¾ ¥u¾bò“=R~K¾,œ ¾S‡>'²>ƒ>.=ˆ½…ûe= â=Ð�N=Eà >ï›=[ó>ÚJ¾sª�¾® +>ä…7¾¯•µ=Ë€’¾tÎË=£|˽޲=檾ˆš“»½”`=�1�¾!–Ý<9f¾�=ö¼~Ð>B"½i¾!ßb=0e©¾Y”<}ª=áïˆ>šž¾ÜI>Mƒ^½$b€¾½±Ï¼=>ðbâ=暴¾i— ¾€Ù²>=ľÀ 8¾‘\¼!Kξ{Œã½Ð 8¾(5‡>þÖß½ðS¾…t!¾þ›î=_†Ã<P<¼Êy½d’>Î&æ=dR ¾øšÞ=}{>•a¾cÌd>[.>VQ¬½ö–ºÄ ¾;!†¾…É)>E;¾$f=ó[½¬cµ=:©‘…ùv>Ãؾáó½]ƒ>#õz½7›RÁËæ½;ð?‚œ™=Ï<“>²¨¼õ_X¾1£Œ¾Fç<9àr¾6ìá¼ÿcó=:Ø{¾8 k=ß(™=-Šº,k5>ÚZâ=`'?€=> (“>k" ¾-É-¾¨¥Q>È>¡ô >¾#2>Ön?Ƥ–>=稾rÂɽVy>�K>GV=§Å/>,ð/½¶…¼9êW ½4x…¾Þ£½UÝ4>lo¾Zz¾sŠ”½bR¼U¤Í»Q/>’ó—>ÖÕݾ¯Ü]¾µâž½&Û> À÷=âÄH> >Ø® ¾uÌ>SëÄ=jÔ->ÿÀ¨<�¸ ¾±d–>bÌ“< y¼>ðÐ-=¤Ž½�Eº¼ßg¾½ÐÏ>6ž8>7ð¼Í6k¾´ê=7±B½M—p>0ü´>6p‡½®¹³=\Ò¡¾ œô<x‹>ca¨½ˆ¼¾HБ½ýÅ!>÷<ž¼¼¤¾Ê«^>÷Žä=b�½V{†½§^>u|D¾¯V>EÂF>ˆ´l¾üh]èPy>Ër=�mܼJ‹b>ÚlÔTnê>S‘¿›÷ <ŸáÅ»‚¥k½ D<>ëK¼£:‚=òÀ¾ƒP<½¢ýÈp�¾ Ï0=Æ&É>}m—=Ìã =)޼ñ,½ð*¾Åp×=f8�¾â¹i>Œ²Þ=PÒ¼A“ø<@˜ó¼È·<ÆíľêCn=Ä7sÎR¾~=Õ.æ=s£m½â¾=ÙS¤½�â±=†�ª½ç£>l%>ãž>Ö¢‘½†BÕ=š6[>ýÈÅ=1yF>ú<ÐÅü=F~¼i0`=ê¾5ð´=…¾ÐžqξºrM¾ò/u¾±‹¦>ÆÄ¸=Î ‰¾ûf ½ùý¾¼_>ÄjŒ<Ðû¼>Îû½­º®>LRa=€åà§á+>Ñ»Z¼ ¯:¾âú½€E�½Ž³ß=úÅܽõ° =óJ6=a/¾¿’Ó¾Ó[‡>ÝÇ8¾$ÖŸ=Ø7>Aœ&¾ P:>«N¾ñô²=,DÅ>»r;¸I—=HÏC>µ>=¾O–>�®½È߇=Î,¾°¾Š¾t`¼ô%¾i(ˆ¾­ÔP¾­€â½÷ÞÇ=ÅŒÊ=#ܤ½58¼) !>ÉRÙ¼ Ãþù!>¬ùG>耾`á°="õ’¾Ò)›½‡ ú=AèÞ=QÄ{½‹¥¼¢c(>gpF>èÕ˜=i”=€g8¾–_×¾ ¦£=M½UwÓ¾äaš¼9á¢=ãgî=® ß¾¬õ¾qJ¾Ñ2¾3 í>HØg>Yh�=!y<X=­±Ù;ß¡U>lhÕ=ïÌù=QYø¼Š¾¸¢=¢e¤¾éªá=apb>\j¾]‰1>Iú>¬—b½šŽ.¾8–w½[å ½f÷C½Ë>¾áW=@оVÚ(=„A“¾›„>ø„Ó¾Ö”> –Y>»¾£½iW¹=÷Ô¼ñŒ =á‡*½òd“>’åØ>Jóa¾K®0»ùé«=ªòŒ>­37¾!æ7=¿{õê:½øÔ>ÜL >ÂvD>Ù™'>º5)=M”ß=3 ž>“=\ú¾:œÏ½„ã¢>Ù­¾6¼iþé“(>>ÔT>×€O>€&&>DO >ó[^=»ôŠ> .=Í謁G¾$>µùA¾Nï¸=H—€>É=Y ¼+5X½.¾ù‡À½CÎÆ>œ>½Šg¡½ºk„¾§B<˜û.½2à< †> L=>W_ª>—+½u�˜½.‹>„D>Áø}>¤Í¾Üs½ÊÎb=JQ=>[4¼}´?½ªå<‘B¾rÍ=7—¾Øw�<{;\=‰€¾½°Hm¾.̽U0½¨E­½³9Ö=fÔãqª>í0ç<ªe³½IÌ1¾ûY{½�vÂ=¨µ>>içK<ŒF>÷Ý\>àáÉ=A¾Æ<¥è̾  ½Ö&’>…\>-T>r)U¾Z 1=ô ‰=ÿE.>â¨R½š¼=��¾Ìºð=— =�àÅ=ì)š>‰¼u> g¾%XV>椬½Ñ· ¾}ë1¾pû=•ëʽµï‡¼£•¾ê">gû»>Y{’½+^·¼uD6¾"ê¾Ñ:û¼cÛ�¾h-í=–Št½žwº=ø3¼³þK=A²-¾þ …½g“o½²k>ð‡¾£Ò8>mK ¾‹¶c=võ#=HK%¾�Ø{= ½½kVÃ>B+̽!2¯½Ïb‰=;+v½:.¾äìŽ=�K;¿O®½ø•‰¾pKø¾q ~>ðc“¾aE�>�G@½¾ä�½Ÿìú¼Co;Á–bº�ÿ>€óš¾qæf½;>kZA½ý)_½èE¾´f¾¥¢¾®¨d¾^3½Ûð½gÈ´¾²�g¾üѾC£�>D>Û’½¯Ýâ¼ùD…¼Ó‰Ö½ÌÂk>Òq½ÆGy=¬ía>ËVºöÀ$>ã┾§ä >d7M<Ї>—³8>fˆ=eš½>8@<:ÇÙ=R„•>P�º¾ƒK~¾øC½„å*¾í¦‹=¨&Þ½Ù{1:îú¾øˆ;+ø*>Ý�÷=K³½ßé>äi»½­³¾HÒ‹=H5º>F ¼gmÉ=øß™¾�Û‘>÷]r>O±²½ªè >ÖÿÒ¾Né¼÷0ú½°Î:="ep½•M‚½!ü=Ä¿×>ÿË7>Ó7Ú¾ËU¾ÇU3¾‘õ;Q“¾Ô€>F©>#ZM>:½¬=¢V®>£w½$²X¾)}™=¼›>ÞÀˆ¾YFß=†ôå¾qy(=n§ö½¥È¼³jÀ½¾™Ù=ýø¬=“¢�>‘ßë<Õ÷’¾ýs>Œ`Y¾æ›¾Àh£¾ À;<à×A>=×£¾¿¦T¾8nÛ=çe> ”…½ ?É=º>ÞÓ½ »½°ÆA¾K²Ë½úlû<”çJ¾ãŸ©½€©€=—Uc¾b�Â=|o>N`¾v?�¾±>&Ý0¾+ûx½ï½Ù½‚½®½\¾K½Z’€½Ö >�.¾ü%1½È�º>ÈÙZ¾×Ö$>÷×ê¾lL’=3ýS<Ÿó>^î¥=I¹õ½6“<óY&>â.> Â)>ËW§½Lôc>‡A¾r1�<º!;¹¨‘½Í¶w>&-}>Xœ¾ ¨>IÚ�¾IòÞ=¾sý=¶í$> O÷=fŒ>ïÓŒ½Ïx„¾NðÜ>¯Â¡¼Äùy=®;¾~(¾¡yh¾`Öª¾øC¡½ºV/>˜e¯ºag¡½­ßž‘É>s"_¾Œ„Ÿ=D…t;R;?@ù½kÜg>h¸ï½°û¼;g×s>kœ½Û¾æK¾É„@>-ÞÂ= ^.¾¼­c¾% ʽø ­=:iu>¨ƒ¦¾–>=Có¾×Ò²¾E<¶‹½ÿêK=½Y½•ž¾Ì]¼«Oµ=WC>£*¾Öº˜ ™=Nb¸=h‡Ö¾ Ä>ÐV>}ù”< R¾ÿó>’-̼ïp)>Í…>�ô«=Ÿ˾aœø½mØN¾ o»¼l?¾a(Ï=u*ѽžÕ7=².>C³> \¾ÞÝù:Ò ”>îj>Ï ½–¢5>˜9¥½Uõ ½ yȾ¡ h=“P²=f;>?¤<¾r5;¾/ö�¾†¦ø½¶•_¾·Â>ÊÆO>±°=ò0V>:ó<úS<‘ä ½‚F‚½ùÂA¾ ß’¾]…‡=!?}>‡ƒ¾s7=<¾ü«=j÷‡<·CW>ËJ…=> w>ö¬=`ŸØ=S,> Î#¾òI¾1«�¾¬”&=À»¼ï³@½(Ç®¾Öt†¼ÀÉ>kàļ;úļŸt“¾¢ò7¾í7m½÷ì=ƺ¾ŸIh¼-Â6>+ï¾7"?>H¿8?}#¾$�¾Ûm«½gýe>�ì½Ra[>X[ ¿ùa>㎾‹ k>Z{¾O¡=¾û½ÃS¾*@轤>``×=qø6½V„ß='`c>2ù¾Ó?i¾º4 ½”-¾û@V<†wZ>Ó…d¾@W˜=]ï’=f*¶=`m¾¸;H=¾Z·Q=JŽª=l�>”à^=ù)F>¶޾¸lp»Ñ5>$N¾¼ú¼`8=$-j¼{ƒ>{>"ó½Qï9¾î_Œ¾&Mœ½Ì™Ü½“>Ù½)›> F™¾ÉU©&»�Š ¼=®k¾²‹>.ôž¾"ξ$›¾©á�=«Úv>p.¢>·‹Ñ½O'¿=A8û=…Kü<'ÃN>ö¼%›¡½îL@¾H≾; 6½/нÆj§½±õ¶¼gq½2?4¾‚�;¾9>¼µ5>'×T>ãÁ|>Yß”¾jù‘¼Mf¾= ѽþ¤¿¾¼mú<+ê¾ ä¾C~ >³µ=Pôn=<Þ@=±m=†Þ´½‡�¯½¡ñ¾5W >,éÌ=ãg½ó6“>›ZƼ¢^¾Gq%¾·€¾Ðf�=ö‹·¾çÖq=ý¹±<ÇG%¾æ†½„†5=o8r<Õ)Ó½'Þ§=ü÷Ÿ>2õ2¾²!AºZ,?s,Æ»qÒ´=–„•ºK!ç¼T—¿ 02¾DZ=2‡E=7=#>â3¿9Râ>è¸Ù½3Qo>«À¶>+j¾Pgƽœ÷B>´�=¥?D½›kb>}S¾(W¢<œW^=Yžu>^…‹>Æáp¼†/3>}E�<¢š°½ïV¼"�ò¼Ô—=/Ã>·�¹¾"BĽBs>"�='“•¼1<(¾ýd’=âbE>ùD ¾Ù¾ŸvL?72^¾¶È¾~Æš¾Ñïã>lÚ>=Öݽv &¾ˆ½îû×»sõ>†%ê¾à¾Ë=O¼(¾í>>)Nh¾/u<½¿C\>]už¾A½¿¾d >±Y¾àf!¾õ¾æq¾»–-¾¸„>�s齩…>ƒ@Ü>(½¥ïé½%f­>š}E>ØL¥;´;”%½Ñ¶—½»³E>–" ¿µjùºL„¾cÅ�¼á¡¡½?ç ¾"ÄV¾þØÒ>av¤=þXn<ìm½;ú=ri>“>p=Š/>u5…½vƒÔ=OÙ=“ >#¼T¾ÊƽK>F�1¼˜Y,>x²B>üÑ=Ú\>E�ὓ n>‘¯¾Ìò¾Æ¾§!ֽÜ>ˆÔC¾{qÄ>G‘a¾ú4�¾ T²=ê¬>-½õ½>¾ç=vµ�¾/;ݽ•O >þ¶>¿~޼·bÓ½²ä=~¿Ë=7MY>¾=¼ 9>÷$•>w«X¾ƒ©¾aÆy¾Ú?å½M4ª½‚‚e¾òû$¾Q]ö=^1C¾ FÆ=ì×É>æì¬=æço>B£¾óm»LF¾Û6‘>œ4$¼NÚN¾òC>¾s®½(£Í=ɹ½©ó\>+¶;²q ¾¾X«¾Íо)ʱ½Ó)¾ƒ‘\½™T¾¹¥¼¾ÈÌ>Ù¾Ù"¾*óŒ=¶J>a?Œ¾Q¾ÓGW>ƒƒ½#K;xô>{)+¾U¯J¾ˆÉ‰¼Ú§î½úX=©òù½”N‰½vØ‘½t�>à%¿Qw¾Í>™½‹?>Â7û={ë^¾å§±½ògC¼æÒ‡½Ûb=ÌþØ=W.нµ÷”>Û¼a(>dî(<ߌ‰áÿ ;`@:>¯¬¾AÓì½1&ž½R·ê¼žC›½£À8>VûI>1?>;}T¾H!ÿ½®ÿǽ9h>¾ÃËŒ>×>ŠÌ໢d;¾ž¥d>jÅ¢¾Ã;Ž>=c¾µ!†½¬°™>M[ÉÆ«>øm@¾]l½s=5vè>ë¨;¾^¼=7@W= Óû>zµ‹>¼Á>»O”«;< >¥lW¾,�N¾v1˽õ±î=l;>_û>æ €>5Ã�½¤C×½ÚIJ½úëì½^\ú<èÍ–>Ë{;½¦Á7½Jë̾Šý/¾ì»½=í]µ¼ñÃ=q— >á ¾<¨#Ë=)xŸ¾«‡ ¿â¯œ={ˆ¾¢-Ï=rUÖ½ôk›½œPȽøÍÛ¾ï,A>�Ää½f•¾™–d=üf¤>“°½—D�¼X`>9O>'Ïž>¨·Ÿ=E|½Î8´=Äûð=¶"ú=³.½5°è=[sÞ<ÝÖ…¾1{u¾ÀÑí½dÓﺸuº¾•ö.>–�=þÒ‹¼é%&¾| ï<‘ïW>V ì=U�À>p‚ ¾ÆŸÄ=Û£ž>×¼>;;<ÿ�Ó=E²¾aã=Û�=g%Á¼n&ñ¼c~ƒ<23Q>ËŸŸ=Rz�>fÿ¹=«8—='T¼?ðƒ>±Ï&¾‚�«;�R¾¿•¼¨¾-¾ñ"K¾·Çè=U > se¾"¸£=€½›‘½)âx>l K>(H�¾Nm>´(»>>M>èÂD>ç™»Õ>ß”¾£ë¦=D±�>€G¾yЍ½UB¾/èK½Œ> F¯½è…n¾}í«½SÇb>²ÕÇ=”Ðù>³)’½ð]ç¾µ¼<‹®>?<>ÔŒ¾Þs">²Kö8u ¾›Zš;Ï�]»øm$>jÑõ<ü¾=��^¾¤'ö½ÒGÍ<¯Ͻmz1¾ c”½ ¸>ȳå=õOr¼ï£>ºÂ‹>Cƒ6>4C¾2«—¾y‘§¾÷X==þu½F@½68=àK¢;YÁâ;å[¾ߪ=‰ö}¾!×@¾äIǽÎÜüui¸=œ�¾Õüº¾çÑ&¾I°1>}{¾{ˆ¾§“‘½P?Ž}�> è4>+9f¾ëPj>¢n¨êW‘=GËð=½Cw½Ù�c;/%e¾ñƒ¿Œþr>ƒ�P½?¢<¡%G>�pܼ%(Ê>#�ˆ½1¼›;I¾;Ã_>¼À%=?Ϙ>ìœà<©¥¿¾á>ü >˜3¾jRÄ>Ó±@¾!ü=.šT=̲¾-¢D>Ù>Éâ=TKÙ½��]¾(È>¿>þ<½¾ßã=%®=P’+½q$í;¼Kß¾=©=œÎ#¾®óÅ>“j½„Á=¨¾]4>Æ�¦>êÏÚ>$ó¢>4KÒ=°VÜ=m¶E=ó »=’•ƒ=ÖP{¾~è«>iì,>$ò<}W¾½[:Ý=À¿ž=Â�>›P—½ª@T¾?=§=•´£=ÕÁÚ½HÚt¾Þå\=û(¾‹Ê±=Hr¾ÇB(½ÌŠ”½:F“¼5³¾(ǰ½¥%½ì® ¾Í™>°ˆ¾ f~=C¾b§=[ÓÚ½Léì½% ö½)¼*¾)�޾³W—=Õèå>[ e¾oÀž ¾ÔA÷=Ÿj¶<ú€¾ºW>>“==Æ!c=êÌ྅g¸Vb)¾#:½:ш½'% >àÖ}>ïd», ¾r–`>Iv„¼‚>×Ãt½R€×»rÇ7>c ?=0û'=¡ª£½Ms½™££>¿þ°½qXV¾ž®O=ÍYF> ¹V¾¯É‚ Ú_>®àü>ëý¾D°<ùÈ„='O >à)>5¤æ¼ùù¾=Ø”=ÁÔk¾Ý#^=4S>.iM>Ü0>ñ'”=Ûœ½Á*¾‡/ô=X¾!®¾ ¦ ><9=áª>>åtZ>n(=¼K>>cNQ<°ùÀ¾iò»X–=ŠZR>Ò%X>lÓ…>ã1>ˆ§>uàÒ¼ñÖ=7,F=¼¿Ù¾Ö>uµ’½á!c¾Ÿ‚˜Pïß> Sc>Ö»Î>(9/¾ÿÑœ¾:n–¼àå%¾–�Œ¾Ë5®¼´ :>»>ºÿ@¾Uã=?Ò²½–þö;H�N¾]Ò�>ô¼¯=Í<ë= éø>µ64>Ÿ÷5=¢ëŽJ­G¾™J}>ìU[½gE¾6u´¾[-¾ç˜¢½yëS½ºß:¾ûXT>l›¾šu >gœ¼ g†>'ø¾B :; X,¾‚�Buœ<»->k×°¾ûbŒ<óTX>\ê~>6‹B¾­¹t¾ŒO=�fϽ ×­½0¼€¾ê„¼T[ƒ=Ëô€¾"Ñ0¾%2B>–°Ç<{;`c†¾"¸¸:V>ç=5LǽA¾±Õ…>¹xˆ¾&™¾Â¶r>éò]¾ÑГ¾Ñ½*½ú\”¾p�ƒ¾K=‹ÄÅ>è;>5Uy¾´�=ÐÆ>¾}%>‡0½‡Ãˆ¾µ5‹<,y-¾â¥@½^HI>4ˆ½MøÔ½âCy=g">º÷¼½q¶¾qÎÔ<íêm=Oá—=ªj>DsŒ>ˆk>!¥½&穽^îT> ä´=öæ�>Ì�è½êL¸¾'꫽]ÐC>b(ï½êˆ~=Ç*>VÌ=ÔË»ø�=zˆ½u(>‚·¾ÜÐ=ù½y�»¾¡è>“(>ÁAö¼ªëT½¨w>Ùlμßpÿ=¬¦¶½ÓÂÎ=ÝU÷=;Z¾O§�=£€‚<ÕGÊ<þ=�aø½�%â¾Q•½�o•>�òé;v¤œ>ß=Í?¾¸¾øw�¾¯¦¾_€>A>d⎽q¥];‡~U>´ å=×~¦½œAC>´,½Vª(=Å¿N>jÛ¾Tæg>¬G>ÅÁ—<¤…¾°m¤½#9™¾†ü5¾Ô>ß¼¼Æ½k!G>…õq>Gì+>Üþ">uÔ=¹™Ÿ¼øh>=ÁÊǽs®c>­>\·=^ƽ?ß½G?¿xJf<7ƒP½ð˜K= 1c=@s.¿bÎt=4 €>},8>OÙ<ë!5¾qßî¼t—¾ªóW»¾®´=àg˜¾—*ô=ŸîŽ=`µ¾@—?¾¨m/=3[È=ÌZ½?¤‰>§¦8½Y­‰>Aý2¾º9¡¾ óÓ>Þ×\»Õ;0>©d±=VÎ=8d)=ízH>ûÝ=|q½&Ya>eª>OÄj;8¾y>ÂdÁ‘¹?½ßú>Ø,C>½ïݽ¤:»=\= ¼ÂÛ½)oB¾«Õ½‚Æ» ßW=Ø_Ÿ¾²>~‚¨<`°c¾ÝçU>lõ7¾RÕ(¾lé½8ç=0¢â=bœÀ=»¿�¾ïf=³îоíáž>ËÕå=4þë:×M—¾Z4Ø=CåU>EŠ>U÷‡=hg0¾¶I/=¾m(>I€V¾t‘,=Ȉ=ú2>x#ê¼öGå=Á—q%½2wÖ¾4Ø=‰Â`=sŠƒ¾ø™Ÿ>Â÷o=Z¾E;9¾u[ ¾¦>¬Â<=}§ï½ö¬ ½)>m%=Ï�‚> Š%¼ÿS€¾Rr«½]c¢=>Ò±«¾ôw�===B=\½{¿\¾}›>å8>ÃÙ½@·$>žL¥<„™Q>ùŠW>IñJ=+‘¼ Ø:æØè=·¤k= o>Rçf=HòR> k‰>x‘µ¾˜%뾸˜“½Á¾ r+¾¾ˆ§½dC‹=aN†>yo‡¾r?I>ªº!½?¹Ò=³«B<�o‘>3u=¾SC›>�•ž¾j¤G>QC>7o›=Œm½ zß>>%zq¾¥‘½8}ѽ.º¾¾D÷þ>¯Êa¾©¬>Wó*>Ï~q¾�A,¾¹Í×¾Ÿ¢˜¾œ?= H�>üŽ+¾1Â>±Ë‘¾ÿU'¾yÉg½Bva¼ÈÚ=ùZx=\ù¼ŒmP¾âž*>é¿B½¿h¾ðn=M}Š=˜¤|¾’ :¾–û!½ÿ`E='[L�±>ÑÔ¥¾ò´½»Wn>—y{>%�'>,aâ=î¿SÐd½Ü«¾Ù§K¾yù>ìÂÍ=» =áÆ;=¡K[¼E =’Io¾ï§=YSʾœ,¾hÂϽ k¾M(>@–p>kK;¾£º9=hdî>ù6§>#·Z>JV³½* ¡¾§…>ÿ¸¾ÿÍ%=Ìÿ5>Vº¾ W#¾ðÐ=cà‘>d†<>?­0=yÒÛ½Q•×½ >\j�<’ØÒ>é¡ ½±¤¼�G>Û‚Ê>Vgç=�¿>á€=P1A> š¾÷òA=Ä»g>0¹+¾˜ƒÝ¼ÖhŽ>£n�>½S¼;¼ ì =ø×·½á^÷=_å>½ >þ½é>A�ú½®K§>�¯=ta>ðt ¾JEݾîÎ>°T¨»½â@>Û¾Ó#>ͦ¾¼1˜X¾+ë½´ùÏ=¢¶>~­]¼d©ï¾xž¹>¢ ¾Ð,·½›Ê½=4Úœ=ue§=Pqæ<W¾¾x?$Tœ>ÿ¸à<9B¾T>=š2>lN°¾å:}¾L½¼u!Ú=þ¾öŶ¾Ýl>åC½Ê„>‚޽”>ý >ÆT@½Ç�бg>ÿcé>ô’f½E>ؼ˵+>ÈÔ9=B#½¼zN¾R_…>¬i¢¼É™[>ÊmÜ=܃¾jf>j„Í< Xô>­°§¾Åv>?f¾Ìâœ=$Ž–¾hTվʊ¾¥@û½&Ÿ/>?¯‹¾º›/½=_¾÷]¾^í;>¦’ͽ¿Âi½®,`>cØ)>7=ÄĽ Äö½ö 4>PQ>Z'p¾š+ =VÛu½2öu»~ç½=§¤W=Ss»=áÎo¾™u¾<ܾs,¦>àá]¼ë"¾¹ý‰>Ú{>p*>‡€¼ Œ=ÿ>Öa´xˆû½�&i=�J…¾l9= êâ=ø”¹½Ï(2=Éå¾HÆJ¾4æ¾ô >Îþ'¿�6=eÇ.¾§š¾=ù =›ø8>¢cn=E–y¾?¼6ø�½ù\¾!ä’=+é=liF=*€¹>¬ç¨>84ñ½Ñâ=ß÷\=e-ê;@£®=¦ÚO>†>¬u>ëAÓ>¶ú ¾�ðz½#}¾L¥Ê¼aü˜¾Ñçœ=z ;>¯T~¾ÓŽÅù²=‰Jr=\,»õÔ³= Á#>ñW�=ñ”¾Î-¾¾Â)½%x¢<@t,¼W;s<'f¾¦iL½ÞnÙ½�5ž¾%_¾¾�§=)Òt>*íú=ØÆ9¾`A„;š<¾Hõù½ñN¡¾Ü b½´˜£=8ÿ¯½ ¸Î=ÆÙÊ=iÕB>µx(¾”6¾ªF(> ¾åÙŠ<Ñ)¾É蕽Så­½ÿ«m>±¾5¾ š&>ICŽ>Ï>¾(u#>)ö=>9ÖÖ=ì¶}½ɲ=€¹½/Y8½Œ“U½óè» †<äÔ>ûâ:=bJ¨=ðw>=DÂ=hé=þàš>Dm¾§ee¾^Èú=Ï¥=Îv½±˜U¾iâK¾¢ï�¾zÝå=z+V¾®^€<´·°½n)¾‚nn>ÿͽ&ì-½_»$>ôtɽèŒÓ¼r Æ=”:>§9 <ñ‘>Ìz ½Þ²Ò>à¿Â<uÐ=l£W>¥®#>ŒÙ‰>ŽQ@¾èqz>Ä–~>ß0B¾³¬‹¾: 5>o‹¼c9½NÀ>}Ìɽ¯O\=&S<¾«Uy¾²~Q½’ÿ£¾î‰—<5IV¼J”½hGç¾�÷ ½oÙ‚>{$¾�p >�L?©—¾42×¼..“½ï`>ˆÀL½�á¿è >>ëÝÕ=y5ß=2YJ¾0V·½ŒŽÜ< ½¾Öãt¼:ùŒ¾ôL¾3ˆ!=YË‚¾?T[½Ñ>Š<¾Xn¾ì™M¾‚üw=“4Ì<i¸¼O½ Âª<ª®'¼LÀ½3g ?´g8=勾øÀ¾IÕP=ƒ¼³±=Eòðóiü=¾Ü?¾½A¾º6>¡‚_;Ÿó™½Ð¤A>œ[¾Ê* >•¡ ¾Å3>Ók’=št>š+™¼â7D½÷y>C4¾Ž|¨>‚nï=¡iÅ<Û3¿'>FC—½oÂ>ÃFü<Ÿ=ïžd¾þ‚>gL¾{éսݯ->2ðq=$¨¾¦�`>>ä½ /ª¾|"ž=û'н(k¼8±Ñ»ñZ%¾†™¸=0Ëê¼ÔB§>´wC>²¢½øÀa½øè>>ð)=íÕ=#¿=K$g¾Õæ·¾°ª-½lÚ»»D”Ï=ê1‡½o/U>4~†=PRƒ=LqU=w.i½Æ¤„>As> ‘ì½xÙ >Y{ ¾ù¸=wtѽ$(>±Ì>)¹Q>ÆŒ>Èw”=ŸÍ<4ã+=|2½9YI=,”½/F’¾ò 0¾ûµ¾zªê»Þ,ƒ>cä¹=˜!w¾=wV>­rY<½ò_;™AË>žJ°½Bœ>a©> �—>w >ËÂ3¾s,¼j᯽'êP<|–>þ>m‰¾«9’=‚<1>yè¾³ü2¾:Ä);ÆØŒ½r…=ƒ¶>ðçˆ;øœ›>ZÍýO_½>_>܉<^óg=iHÂ<Ñ‚f¼yP½;V>Pe >¦ ‡>Üï?¶½=°˜ª½€±½+M=O0¾­”½YF¾Ø „¾9êÿ¾Ài7>S•Ó=¤)º¾Œ=2a ¾À=Xa¾ŒñL¾V}Y%ù;v˜—=ñ½Œ=É}¾åId¾ F>2+¾^Dˆ»xZ»½ ªÛ½‹²F>ðEh=Ëp˜=‚]e<.> >��½©P?êa’¾…•½¹VI¾pXýLp!<…=¾R]û½9F‡=´.«¼åJ¸¾Ö¿Œ-(= î;>ÌP{>©M¡=Z¦�><É ¾™—á_ñ=µ¦>¶F£¼™ÿr½ÌŸù= ù£¾]§¾íª½P×½l‰¾ ¾.ø6=‹¢u¾“;(=>Š6Ÿ½MA¾·€Í¾�´æ»7û™¾)–ü¼-Yù½Ø`Ä>íiŽxd‹>Ø/j½'’"> y½=Ê—-½¨Æ>@.„=#„w¾€.z>ÿ¦¾‘ =XRI¾»zü¾8 @=q%³¾Ã+¾ –¾/õ€>*èý;V]¿=Ñ^ý=xD¼~â*½-„¯=ˆY¬=·‡¼¾ìô=£]�7‹‘¼FQ~½ >-¾Ôœ½µÎĽöºŸ=:½¦ T¼êÝ"=¼>¼œƒ;¾ Þ<(?j>ï¨::´Œ½›º»Ë”q½ôói=a^™>C(¡¾ð‚'>áå½gX¾� ¾Óâξ´�>? …¾uʉ>`,‡=�²à=”±å½ñ´½80>cÇW=‰>ÃV =÷àg><Õ>ØÝ™>ðê¾ÇW3>䶤>)&>åɤ¾hˆ1=*–¾Ù#ǽÝÓ©½u©‡=-¿¾½“Rð< ¢Q¾^†¾:#¢¾…«½Î6 >jmû<ܶ�>º3A½ö@©=PD¦½´¿Á=ÕO=Õ¬ê=§¶Š½f >‚=¾'SK>/Í}» W½·8оö±½Ü›™<7§’>Ïç¼ç—¾¿5ê=CÞ�>ß½ôþº=Gíȼ—}�½='¯>ÿ"„¾> -:“Í·>d;f=UŸí=Ø«M>¡Bà=jÍ>Û€ø½i¶ê¾í+d¾HäM>;ð½k£o>—^ã>Õß> �¾=¨N=$ >‚¾�þ³¼ç$Ÿ>Hú!½N~Î=@™¡=ö�=±Ji½ÚËñ<5 °¼f¾{ßh>�Ô^¾ÝÀ·¾jž€:”A־Œ–=·¬½¨¹¼£Ô„½ŽQ¾Î>>Syü=lJ>¨ee>½¬>YÛ÷½ rœ¾Ë>Ç—¿<áÂ=½4==¡ñ>Ù—¡¾›=Ó# ¼'N¼Ëa¿¾5¨G>§ÆD¾#·=b†½ÉÓK>VÚC¾}%1>Ä»8>' o> œ>ÕÿY=üEK½JÙ:¾¨–·½—�ͽj@ª=Æ–;×>³½Ñ‹;õ¸ã½�ñ×¼üŸ6½Kܽs?9ùõ=T×p><’C>ªÊ‚¼Jn^¾H$7>9®Ý½rØÉ=Ø›g½n6¬>CÅ'>I싾BëK>jƒ¾vc¿=ú3ã=-þ¾1>…½*@ª¼¼©=•¾sš>�<~Ñ…>fÔ[>›áÈ<“`¾lˆŒ>-VÓ=ÀQ¾ç7>/©Œ>7J=%”ཽ'¾þ^>w!C½g~<=6—µ½\tÔ¾4ö%>úüö¼'Ж<°·2½É÷;¾8 ½x›‰>ȸ¢>Ò0r=ÕÝ2¾%` =ã(=S>Û¢=ys¸>”¡¾¾`“ =¶‚Þ=oèP¾ïèO=±A"½‹W’>31;€J¾¹ e½h>Ͼ°Ó‚¾t–½qK§: 6>tI†¼¿£=„_u;Úrq¾<ÃT¾¯é?>–®Æ=åŒa¾påŸ=þ(j>ùz>)JO¾§²¾t¾f‡=ÿïÖ½hZ>†Œ½µ¹=Ð;¾‡Ã>ðV½âTz½4瑽L 8>¢ç¡½‚ÂØ;¹?¡;â½]¾�Ëù¾z<‚½k8=Ï:=%+¼O³¾È3¿e’L¾íà�¾ô³3>(,n>05o¾Â->À›n;k==n¢*>øªä=Çäc>ò®j>«Æ<§Î«¾¿3Œ¾Ò¼»Zª> –ð½唾ñ†õ½F¹›=|/´¾šŸ^n¶½oÝú=àë½vzû=T2=»‘U=ÞÍ<"Ví=ËL ¾´(æ½_¾Ö7œ>øÍÉ>”µ˜¼ab¾’Í=_ëc½­ §=E«c¾ñ;¢¾/E_¾Ú™=;<½‰l<¾Ž\À½–C>×úW>ð$ê½v…]¾ª€c;xGá¼¹X&¾´ÓÕÇ2‹¼²)¾˜}œ*Nø»»B¾oÕ½ªI½‹qÚ½*AH¾ŸK¦>Ê>b #>»Õ>2Xì>«ÖŒ=Û=Ø®½¦/v¾½„ ¾ §¾ž( >Ônô½`It>©ž±¾zä¾G2ê=üܘ=T#µ>ð É=H)z>Ÿ‰ ¾FF¼xGZ½Ä(—¾ ¼Óq».dÆ>?º‚¾Ÿ’ὦòÊ>—¦½ K6¾©Óô¼$g'<ô‰u¾±“À>ÈeV>iÐ:¾‚'¡½æz¾ðí<�„¥½ØW¹º´�ß½³ý�>¬³>Ýe¾ÎïN>Ú…=C"޾V—,½v4=Åá0>ä~Ì=Ù�>»¥¾,:¾Ö³=¾/Z¾Ò�A¼**u¾øW™>ÖŒ½= æ²;9°=ñOS½AD=§&¾Ù/¿>¯½–þŸ¾w…’='eþ='Z¶;wü³=¤)¤=�û¾±Äµ=´ø¦¾Ïó¾w~\>ù|¾”z½Ñ95¾¸%>ÿÀ•>?\£¾w Ì>PŽ>÷Þ½“_¢¾¨�½lbÔ=X Œ>Uÿ«>H�‘>¢4½$À7>| N¼¼”¾¢ëa>�›K>þàù¾æˆ�¾N$=¾™•�=쇽˜é;PØå½Äü–½C8Ò½V¶K¾8ås>Ù=¥¼„ÌÀ=¸Õè= ,ѽ @>¶ú™¼.¶>g o¾N¹ > µ¶<¿Û̽€úˆ>~§¾õ%¦=‚ö >Ø1>�¥=A“©=fÓª=s!@>ÿ=r¾Ãì,>Á›.¼®Œ>¸šC¾G‹>û`Ê=LÛ‰¼=ù’=l»¾|¶¾9z¾¼ÞV>åU3½‰º&½¾*Ó¾ Qy>Ô¯^>R/=“”оFª=i*½záö¼9mv¾)> q¾­9Í=€ô™>Íîÿ½ãož½—=P//>¯=}޾%ª½È]W>‚:š=“M±¼T1¾ªO>ÞåM>=ç?= ¥u=QÛœ>¯[]=Ÿd>h>XÓ<=Öá#>†Y™¾·ü ={’>ÚâZ¾•ÌA>/‹=Q_í="]Ó½�©ˆ>*Ù¯8œÞ>…½½Ó$¦½‘æý½J Æ>c>ß=µ»¨¾T²½�b“=d ¾©á–>“)½ôA™½�šã=snÑ:ÎØx>­ê–½,& ¾Š=ê=-ϽüÑ ¿²ÁÛ½.<=T¾á¨>sP¾Œ4‚;¹,#¾¡¸>>Œ‰>µcÅ<¶l{>ƒ~>ÂÇJ>Ð|t=03‰<–Kœ>îéf¼ýt>¯Áv½€J¢>A¶=Ï¥t¾ $Œ¾…¾F•>Ÿœ;½s½]>ö>¾Ø"¾6%œ½ÑpM½�½1e¾àÃ>ò'½Á¦‘½]>+vï=ªŒX>Ú‰>ÀF¾ªY”¾1wf¾H±>X¹ÅÛ�>À¯½gÈ >ýl¯=Ó;ƒ¾JÉX¾ ¬>s¢‹=;€>71<–xW>ôd¾ic;ð ü¼ã‡¼~#{>�=CŽó½gë¼Y¤ >#=>`Äâ>0“F>0¾„˜õ½Îl…=7MB¾€›d½‘ò­½CÇ‘>+Ò+½»ÜS½)èÁ=Ó~:¾DÌ=%‘?¾çžhÉÿ>ð’(¾‘=謢½&€i¾YU=5ƒ=ÝS'½8üi>á‹›>Á™¡¾�Ó�=ذô½–sH<èP¾DÑ<³"¶;å†;½Üñe½â·õ½SRp¾y;¡We>}xÍ<#ÑZ=F¤Á=�¾=k=Ú=ž&>®ÐC¾Cï\< Z�¾Ü³R¾jn`<•­>L\÷½¼²9¾4Ž«½³e*>%Œ~=´€½ôª=ßo‚¾| >¼r>á6�¾úù‡½­¾#iľ»Ì佺<÷¼ (9=|Fó¼(Qy>êo=>e.¹=.¿c>›¤Û=,>º>(èB¾q˜­>ýý½.£t=hž=ÁŠm>Udp¾Š¸ > >¼¼`æÀ½{)ä½bµ½¸þ¾5z+>õâ ½3Ù'½*cí½%Þ@<ÀM`½ÕÎ*¾ÔX=¹_¾s%>L!u½S*+>ž›f¾Á>t¡=±­¹= p‚>%nˆ=†þ¾ó¬{½ Èe>s^®=�Gz>Šlà=M¯€=Ó·¹¾ÓÀ2>…ÊT¾I®½×k…=ÒØÔ¾¥9º>æÚ¡¾SÕ!½¸‡0=ソ(\t=t¤=Ѝš=2Ux=�4>€­p=C×y=ݺ®½á.a>a±Ž½°ð ¾¿» ¼>5Z¾,½Dï>‡=…Úv¾�MO=n0›¾9?¾õÍ,¾÷5™>Yµj>À»Ì =×1 ¼½Ã=îIª=cÙ¾. ‡½øÊ¸»*Xê=*+)>[Òh>@I>‰šÅ=‰Åj¾e×ݽ˜¼Ž½’¤Ç¾›Îh>œw ½/n“>ý4¾–_¾“u¾M©¾½R€>¡É<¿Õ×¼Z„=öÁ_=Ý«š>š0¾m¦½…»Ó; ѼÍ{£<’«þºí6‚¾õÛÓ>uâ½øþƒ¾³°÷=C5ö=ð޾;.@=;i̼á‘=Íþ>¾¿É¾Âåo>J½ ·B½ÆUʽˆÐ="d”=ˆ’¾�j=ô¦†=Ãh0¾e9¾Î6¾ÕõŸ>|„¥¼ªš=Á4O>êÀ¾¢=Y¾¡i޽‡wó>Â<˽wÑ>п½•� ¾‰0—=™&I>´Þ•Ã�Þ½æ£=== >c�@=⺠¾ö‘u¾ƒ;†=xæ±=é|z½"Ï£¾SÖ½NR_>‹’ˆ>@G>DÓ=P½€¾} R>ƒdp¼+g>Ñ@#>cýÙ;‚„º=WS>>PÇð½GtF=›“²½ø#§½€�>‰°>ígF¾lž}¾õ®½Ù”„=D‹¾¥">–Vn:Âé°>S²Å>‚Õ„½ðÅ$ÎÎÛ>A›L>Ê_þ«Ó¶¼±°•=¢ºH=üV9½2ܹ¼iN¾£Õ„¾°?Å=‰?¤¾ÔΩ=Jk…¾œšÆ½ ³¾Ð¿Q€¢½þ啾wö¿¼¥Ý�=] Û½ÔØ@>Çsý½S†¾”*v¾›ä¾kJ‘½ªÂ{>›j½:b–?yK =¡ ½i¢£¼vW5½˜¯x>':P½Ož€>±å©¾ÙƒÈ>WW½PU>¶â(¾a<>:mç½E;G¾®‚r¶†=œér>÷á-=d¡>š§-¾Z®¸=q=7y>8¾ࣽ‰Ç/¾„…0> �>‹Ó%¾²g¾wˆ+>v¼¾S¢¾Ò«j>Ÿ�>ô)¢½ž³>Â5Ö¾�3></=|ýä=''#<Ý~—½;¾z´î½�^x¾1š#>6Ÿñ=?ê=ŠJ6¾� >„å7½ˆö½]`Û½É|½õâ/½¶‚>ü ¾§Ï¾¥²¾ã V¾Ræø½ÙÜs½‚%?Õm¾Á‚½Ü+ƒ¾•Â<¢⽉Ë+=L‰œ=(”¢½…ë±½Œ6¾ÃXU>$¦¾åù?-C7¾T4¾1ºñ¼Q2ð¼Ò’²=ä‚»>“ý®¾F˜Š¾>=v4¾{dr¾Vþ½¯Ö¾ÄEs¾!e¾‡W�>=Ö½‹ W=ËÑ>>ñh¾XéÌ=ŠÁ½#Ž>xC,==1‡=,�½è×=a•¾º²üB=¹õÆ=¶ß½¸â=D_]=u„>M@ø½²Q{¾Ž„>EÀ>p$>ÊFÇ=WzÞ=¿…k=bª£¾¡F¥½P�4½SY‰¾J}^¾ Á¾0 >YϽö©š¼Æøz¾ï;=ý‡_=OOš=¿‹æ=±H@¼£ðg¼—3r>X3¾¼ §= G•>ßÒ˜>3Ù”>j¯Ñ½ú# >ö¨�½l�Õ<Æz0¾_£€=Gð¾èœ >Ö©8>uS\=>‚>(�‚¾÷Њ¼³Ù¶=§e;¾ò¹¯½ŠÜJ>‰?¯½NCi½$b>Ü÷>­¬�½Ö¼½iã~>Gx±=zlì=zE:¼K_¾â)\¼Ôï=‹®Ê>J F=}Èó>AÀh>—š›<T�½ÕT½ ›0>Q³†½ð–˼iU•¾ÅK=X >6–¾Ù ½›ðp¼(£¾<^˜™½x½°mð=RY¾ aˆ½ô¿7 P¾¹ Þ>¼¾!…b¾Wä\=‘¼=ÎËQ>)¹_>庼Žpy>`—½B>Ïçǃ›ü¼)´>L`q¾:(Ê=$w>9—&¾ÿ>ç½»ûž>¢á5¾ì·R¾NÉP¿rÅ’¾U.¾2~>¨ù½™s¡¼¢Ã½Ñžü=¥ÿ=Q _>Ú¿=8\W¼Òæ°¾VŸ­¾ø'= ñÎ=~fP>Â}>@q¾ ,¨=n(l¾ä…y=ñ¹ä¼O¯6>~�_=øCt>s�о>™Å¾øŠ6½Cª¼ /¾zà¿?á>̾Œ;ë6¸¾¢´+½ŸÃ†=צ=÷Ÿ‘½†T¾Î%•>"ø¾nòº¼œ‚=åá>€øì¼'b?²Øb¼ã_>‹S5>KÅP=+žì=©¯=²—6¾w~×<ÌlŒ¾·-›¾?´Ü½?Ç>Ž'Ý>8þ½Å§>æÐæ¾Á²¤¾|£ô:VÝC=k“8>W½=¸«¾Ð->ú´U=û™½Eɲ½n·(½ʧ=MÖ=ÜÓ>Óÿè¾ÎŒ>LTp>CÕí=8ù>võô¼.¼\O¤>wX;>³½±1�¾VZ>Rzx>Ò×½:¼¾rz´>ËAî=>rU¼éC¤=À¨¾ÅÁ7¾æ8¿¾R²È¼ÒfÇ<éh=}éC> zß=PG`¾k,š½°&§=°9>�!u>÷$>5g�=‹£q>mè=Ã:¾5Î&¾7ov¾)gî½#ݰ=•Ó¸=¹&¾8«,>¡në=Ý�c¾�ÓË9p´;)¹ž½ ç>qÆ>©ìÓ=ÐÞˆ¾S0¾†­¨>ïS¾½:õ=d›½ï.ʼ¿xª¾ÁÊA¾ÉÔ6¾„0þ¾ÃÏ«=³ ½œ¢]¾‘À¾Ã<¾5=µ¼ŠYÍ>Z>WX�=9K(>’ˆb>ôøŒ½È;(°I½CK>pÓ©>Õ×!>Ý(�¾õAö=Áì½_þ^=Ÿì¾÷ˆ¾Rê¾±5νìÑ“=nª‰=VT½K\=½Äû>?/“>Jbš>ÐÚ½ù1â>çÈ“>™ò=põ^=š[>ÑX†=sÚì=¬yY¾lPD‚Q½^_®½.†ˆ¾Â*S>Â˼Øý*»ß€ž=~7 >ÁS¾ +齈æ�½üÊ:¾˜>ZMŽ<�ëľI)¾kl¦½µç½2×ë½æhñ½î²•>÷a¼¸Û=_&I¾{Þ�>ó‘‘=�L—½Œu¾tÛT>ÞŸ=wJ>`º½QŒ½’3 ¾PöF>˜¯½²cî=*¾ˆ_˜>è�à= ÊÎ=v5¿¾r胾”ö½‰Lˆ½e$3>N[ž¼X—¾‘à…¾âù×½žr»>Ò¢<Ë2›½ÍïÜ=5f>Ò >x$@> ½XàD¾ŸIN¾ÙÉоöe=RŠ#=²¾ï½})¾›¾Ã>nþ¨;É<=ŒŽg¾?”!<F¾­{D½Øk‰½É]Ä<Þн>‰>\‹½’ö½@¥÷¼Õ.>$L>Òˆ{½Ì«>ý> ï">�K¾µZ’=ÝÂä:;€†<Un¾| î½EÂO¾Äh\¾d�?f·Ù¾©5>à}ì½4�O> 󦽑²Å½&½í½}ñÇ=W±>>ŠÚ”>*k³½Ý(M½•?¾H$>³½¾=À=mw=¡ý¾⟾ªN¾²)C¾ÊÈ�½�Ëø=f-4¼‹[}>Nñ¾.¡=¥^½õºN>F^U<À¨ =âyÞ·l[>ÊUÜ<‡Y÷¹IƒT=»|½PÈ)¼�l=�ŠŠ>Ñ& ¾W»½�ª�¼µí?Q¯=ˆKs>dß�=´gš;}’†>~´�½ýÀN¾X„=˜1[=Ý)½]Lo¾k=Ôfž¾.zF>Zìâ½Çñ >FB•>ôãÀ» Í>§|(>$ª„¾Ñ᪼ Ñ)¾W{¾Aì@>8Œ¾=‡ñý®t3½2Ða=½<·½AÂ>DÅ)>€Ô¾>ÏæN>?†¾/ñ =ï-D¼¢½ìír½Ù°ò>•û½Ṅ¾v¹’>4s¾oM&>N|==7µ>xl!>,Å[½Èc>>Á ¾7 >úÜç½ÉÆÉ;Žzx¾3%$>u^>n%…½ ¾9=v�™>ãF¦f‡¾]þ?>i­=‘°B½4ø¼Î½¸u¾=�Üâ½Ý}Î>{·»¾¯M¾†ß˾ï;M¢´½÷ÌA½0¬ú½×óU½ê,¨>±Œs‡§^>¶—-½å:w¾/©½ag=9¸©>ß ¡=0d‹¼Ï,ô=$%=4y>vL¾’ à=Ûd�½ô‡¾p�o¾´Ä>À±¹¾Ã?.>ònÊ=Ñé[¾7Ú¾|µ|> ßœ=~ã¤<Úúf>w±Ð½â-Ñ>… >²"Í=3¯,>:é¾*�´>£ÿ±<Òù¤¾ø_=$…�=Œ‰Í¸E=ïˆ={¾Á+©=Ól=} =G*[¾~a->xÂç=“¨�¾¿1¾#á>ËD¾Ã�>®·�>󼿾%Mâ=æL=Þ(>Ý r=&`½y >µ� ¾Üd4>Uµš¾¡¿«¾ V>u4@¾4˜>˜‘½ª¿d¾>Êœ¼�-¾u/?§;;=i+> ¾ƒ%´=à >4È >°óU>§ÃÚ=’ªJ=ÕÏàØü(=K6¾â ’¾,$^¾l›�>µì�½ò p¾Fk¾ˆ ;À“ŽT³°<ÎÄf¾Û>£÷i>Ž‹ü='±Æ¾Ô¨Ë½Ü\ ?€KA>gZ»=¼ôºÉ�j>"£Õ>úÛ8½c¤½ºóÊ=~t=n‚f>íܾèÑ�>{¡û=æû;Ô§=…1¾'Ê=½&%>´€+½¡G/¼HÊ£½ƒvÓ¼eßX¼rÅÚ=”ša(>¾^R=Tõɾ–¾bá;ò·´=9EŒ½-¥ª¾Ï“�½gê·>Ïbö¾µg‡¾Z?>ì� ½b>>uʾ0Љ¾0À[¾v:(¾âµa>Ìç\¾  ¾=½ ɼÐ.¯¼¡�ží}>’‚={¾ÆG�¾ õ.¾Dº½g9Í=9LK>Õ΄¾ÛÛ½ü“ô>侕U>x’>Ô_ ¾™Û=@½„>ð,b¾T¬�=éð >~ê«=ïFI>-K¾ì4¾~ s½0sl6B¬=Êw-¾×„W½¨yÅ=ÒK=Æïá<�Ó½†—{¾ñ¿½°®…>0î;B®¼H´e¾!=¹»G>¤^y¾i µ½„�м89]¾eI꽶Ʀ>z©ÑÖU>ó3½ø˜¾I–½¾¶g½~X>]´ø=rÑF=¸±>pËë½7(™<¸$¯>G¾.»aIh»Ýĸ¾E!0<Hª>О¾ä¤�¾Ce¼êN>‰-½©Åÿ¼™"G=VKP¾õ^Ê< À>>½ >Ìh…¾ Y'¾¹3£=*�¯>’Io½|¦”¾!ÕZ>^æ> ¡Ñ¼Ò½P&P¼ Væ=Ÿ¿“Âu•¾Ö’3>úe½:¼½Mh)>\Hö=<*=I¼=4J?Þ4¾xŠ.= Ï×¼‡5¾~þ+=–®×¾Í{y½ÕÁá>žiS½<«Ÿ>ã;«¾Ø‘á>³.½ƒÑP>–Å“¾¥k¡½žH-¾,ˆN>_= Zš¾°È³½«[£½ã#¾ �¾À­+>ͺ>—̼Hïç>Í›J¾·«=p‡l¾ª´Ü½Œ`#¿à8£>ßȾ4 ú½k{­=8ŽÎ>Eg©½±9´>�ç=¤Ê‚½‰Þw>ǫ̂¾u�X½Øñ„½§–©¾£©¼=÷š¾¢ž>Öà†>ɪ†¼‹?Y%#>ƒ°—0þQ¾6m™¼žD�>uÿN¾c3½Êñž>ÁŠt=7Å?ݾ ²+½D˜W>n="¾ÀÂö¼~¼B¶Þ¼ÕQ•>‹yw¾3fÊ>Œû>ÐŽG¾¯Ñè<Éa¾W[½qM=s==ëã¾î±=?µ¡>µ½š:,>÷Ç8½"f<Ÿ Ð>b¸C>òªÛ>Êé‰;ç >Ðïþ=硨½‚³Ó<ªË½~ºù½]Vk=P€¼ù­¶¾Õ"S¼Žâ&¾‹Ä ¾,§¼¾“¾jÖ<>' ¯¾Fz½°L¾dãÜ=[Ó¾’&Ñ;[ÚK¾ú\¾ñŠl½‡%=ì„°¾kä€=¡.>¶U»½7U'=œ½³_ ½�Þ8>(ªÏ=ܘw>íë=¾W\>‡¶ú=ðV¿¾V¤ã=“Ê’>LbÆ<_m¾µC¹¾kYJ=„;?=ö«k>>Ù¿Ï«=I¾ê*}=d=¾;/F=1Ö=åνŮ>¾gY>Ìu¸>hór=AD¨>]ýŸ»G_½¦=JÆ ¿6)£¾Îžœ½½?¬G¿=ãc½PF<*ú(>{W,¼ssÙ=9]ˆ¾yô]>§o‹> Š¿œ«½2Š-¼Ç«B½@Ð><á‚»Tê¾>WŠ>>½rj¼¹,7<¬Þ?ç+Ÿ=®H–½I ":½Ö²¾‚�½[¤;>�3>O./»roò=xûZ#¾º'>·;S¾Ÿã1¾Q³Ö=èS:=Î++¾¿o¢>h¦>äs ¾{L ¾Î¥µ¼Áã ¾/@‡<(9f¾òš/ºÀÛQ¾J †>@š>Üȼ�,^>.ɬ;¼•¡¾î™>¼f¯¾qõѾ®C‡>G(¾úz޾I õ=í§8=^Ó�>ªR�>‹ ?N-¦=˜¡Z¾$?>òX>4¥<,—}=Áxî= VÚ½•Ň=®|1½çÀ>±¦½“Ýn>u3°¼‹j&?HH ½2�Í>Â:>/¿§½Hc>޾KÂN>Z¶“= ½Š ¾ÿkã½ùaa=,á§¾†5É=h×7>^.‚¾Nç ¾{ç¢=§²|¾Š³g¾Â¬®¾Ý²C½v M=UR>]øí=«KξË->bl+»Ýh—¾Oý>b…ø¼à>”ß½Ê`�=S§„>�ö½t;X>Û6>¤gÌ>|à=äD„>ëID=ô¾|®>åÙŸ¼km†¾!�‘¼@˜< h�>9Äi¾÷åe¾­—‰½ý¥ý<ûž:¼·>øí ½z ½UG>�²³½:ò&=“ š>2Dò= P‹=êt>óä¾>MÝ£>/Èu¾'—ļ6!=»È&>ºÔì=¦¤/>¢Üì½�µ=¦‚�>ºê¨½lt]>ìR^=žÝ—¾Ú•U¾Í�ì8é>И¬½öh½¼§¾úÿÏ>^¯ ?,Ê >û¥R>Vè¿ÓÔË»Oô ?tÂK¾6ÿ?¾¦œk>Rõ×=æ¾H6C=s|‘½Õ©T¾?¨š½‚.«>_õ�=U$W>B–v>b¬=w™"=~d®>74<áÄØ>òüò=ÓöÓ¾ì À>Óf"¾l\=˜½¸ó¾=¬ðž>`Av=÷s½=ÀLC½¨>~ç7»3€ö½ØMb=ú�=Ö÷®¾1 ò¼U€g>IÕ¬¾+€^½§e�¼Ñ .>ñ…¼öyé=°Q>vÂÒ½öÂŒ>å´Š½ª¿<[ª˜=„È>Mh°>9|½b¸š=Æ´é=»¯‰;ùeG>cb=!¯ì<Áj¯>þËi>@a?©äP>†w?7§®=ÎÛ¿G&d¾;-½{eì½:×½�¬{=�~D¾C`0¾µø×=6¿Gë­½jÔ¤> „m¾¦v£½ùùC¿jƒ=%û‘»?æh<Ã� ¾¡À—¾´ze¾#ùˆ¾ÄIs=lMš<>‘¢»G—[>Æ ¾ãK¾l¡+>…ré=!ª>Ù`>ùÈ#='³{>ƒ|¾òw¾ö4©>¬Ñ¾”ÄŽ¾­ÆQ>éê=ŸÙ“½í ½*~޽&ã½ið¼Eûi¼m±=À€ý=CÅÅ»>B¾aï�=ØR >u+¾ó0Ò=“°J¾r¸á½ëÉ=v%˜¾è‚”¾$>Ýï¾ö—¶<˜�:<ñÞ›>-ÇK¾}Ì%>sÛz½'÷ܽ<俽¶­¯¾“à¾X°À<ƒBk=Ýjq>[¾àjï½&“=¾25µ¼¨î|=Z§>½�^>Þ …¾r¬O>C÷ï½ßìϼñS=Òt,>;¥>´›¾V\¾Ñh´=íc> ¥};Ào?½eŒ‘¾âA>;žm=¯Ú‰=šÊÛ½°á�>o27=Ás?=Ëà>@hM;¢�c¾×ŽJ¾ì5½�Â=_“ؽÆ^½½BÔ>Vィ”¾³¦ ¾·Kо'Áí>4tȽ�Á=þ>{W>†ç>==c>$É­=×Õ¾$º†¾øœÙ¾F¡=¦ŒÛ½¦çÏ>ÐùY½Xƽ»î—=®ì7¾~¹c>K»!=(œ…;&²·>xp?DßÙ=å§½]”]=<[<}õv<Ìi=M‡‹=°W?�ê~¾o>ÝVŒ=È 4¿ î'¾ƒÄ0>n*¾*D ¾O~3<×i9>Fo#>…>H>«¶á½BÓ>7¸Ž¾"?JU™¾XÛ=,¾d\b¾ƒ—r>�C�>‡3@=Œà­¾]O�¾¯Ê!=nìN¾�š½5Èø=¾Ì™>\ƒu¾�bZ½z„9>ôK=*¯ =T°½x/>ò|¾Ï e>®¦¸=Rû�>GD½P̾Ðåƒ=–|˜»&(Á=a½­‘’<ž¾bjƾè~C>€©=ޝºÈM¿wžê½ë¸È¼î¾ä»‰£F× >@“¾NŠÂ½f绾-×¾D<4î0> f¾ Íå<*ß½„ÄÆ>JU�> i½=z?>€]±¾Ð ¬=¬·¾¤ÓR¾˜§>�aH¾Ý¿Ò=,3n¾-`Ó¾Y‰ ¾a8¾Åõr>ÿO?>5M’½«ò½¼ö+¾àœ½ˆÚ¿ºŽ‘> +=‰”ê½ >°¾aká½ú0@< >t—Ǿ�нrÄ5=@¤d>‰ö6¾ÄU>kP>< €>Äß&½MÕr>~†Ž½h&?<–¾Z½•¿º=K¯>äkL>,Ÿ¹½Ó&S=”¦ö;c\|½CÚ¾�ï=Ψl<œBe½ÂO»U¥>Ú}¦=°Ì¾$5>ÀݽB–m=$½ší¾Áµ->X�¾…�7¾ˆa/¾ü¢F>ÍĽÚæ=c3¼>öþÿ=nï‰>ÏOJ=þÓ”¾àŽ‘>$üg>sx>lóv¾²r˜=P»›=k5S½(ÂB<¨7$<B¾Ü“f>>ξݔ½æÃ‰>oÓX>¼ þ¼!x¤¾ª!Ú=…Š®»šî½ÅÃ&½ör½>«½F.,¾¼–>/µ›½†¾Å3>ÿF¾ºjd>ÑŠ7:ð‘¾&—Ѿۀ{=©U¾£Rº>È>AU>Û÷ž<çar>ÁQK¾—U=¬–¾—Ï>£Ù>ëÐ×=¥]S>eÂJ½Ô1Þ¾R=�@u= þ¼I]ü¼{t>Q¥>ä'¸¾=¾Ý}T¾Z¿û½‚EÜ>[ç–=™®s¾R†>óO‹>Nò¾`è>uÝ&¾o9è=,+=—�¾´Þ;¾Vž¾ F‹>Ù0?>j:˜½roǾñk?¾GÞU>FÏ>Rn>&¾NóÑ=¨9D½Ž3¿Ék¾ç'’>н ƒ>”ÙC=Ãó5>ñ0a>G|!>20�½çz=Xª¹½üƒ‹¾´› ½ùÜ*¾\Z×½O¯¾÷¯í=ÞP¶¼Ç*A>p.ͽSì¾™¬½ëÊ =÷ôc>7)¾žCˆ=›öJ¾­:>A@ë=Ѿ†$¯¾ngÓ¾5j=Ú�¥=hkƒ½š%ϾÙáŠ>Òó–½AÓš>´‹¾fµ}=>[y>ô6½@Öd½¥þ§¼Nž¨=0Wá=’_>N;>x wlÎ=Û¸7¾f€¼=�j¿»²aܽ? >j‡y>‚¡´¾B7¾²9”¾¼Ò ¿3€b¾fc¾Õß8>¨ª¾•a¥¾„w·=ŠË˜¾`y•>Ûÿ™¾¿®t¾áu0>·¢…»§úL>ÛŸ>&ÓÍ=XÙ·¾³"¤¼fbR½xQ\>Pg›½Ä–>¥�›>+�V>…S"¾©{=.¦¾(/d>Š€g¾ur>å¾h|>t@¼á‡¾¥Ù ½µB¥½þ— ½v<|>1z!=R¥=þ=¾Ž¼½6½¿½cX½;Æ?y ¼£"´>`l,¾8e >»re>‰½“ >=äqb¾Vͼ³•=jì1½¨Þ+¼.B ¾rÃ1¾†KB>/‰Ì½w#ƒ¾¼}v¼�S¿„„U=P•!¾¢>X¾=±‰î>Y×-¾˜Pï=|¿¾‰#Ö=˜hŠ> k¾X®›=n4‡½¼¯²½ÈTå¾^eŠ>cx†½®71¾vÕ¡<Ä�½¢Š¾¶gŽ>2�=¤=|ÛL>Ûz >©RÚ==G£½ûó˽ÏJ =j$¾:¾ù¦¾$g‚¾Wª»ß€o¾w¼�>†¨Ö<‘}Ÿ>�ªü½døk¾Wn:¾xÑb½-.¾¤p¾=v´½L²+¾^l)¾‰Ã>¾P½Ô¤>2Y›>F|“>£a‰¾@¤ä=»²1½‡×Ÿ½ÁÁ½úž|¾§3ý�¤»½æýz>9•«;Úë·>06=CƽByß¾*l¥>_ >­Û½æãt¾(¢e¾{5E=U é½ïTc¾æþê½�½0¶=pk¾ÉÀ9>P8B¾|lL¾dP3><0 >˜ôE¾h4¾‰Z> ‹>F5>¼@ؽ4m<ÊÖZ>®û>Ç’¡=IÜä½ è¥>¦Ó‹¾Âóò=ÜWr>úp¾ï�>øk¾m—½Áá²<�,½!>{£@¾ "å½$ÝĽÑÒ̽v“>åŽ=s¼=+‡•>'ü>ÕÊ\¾âr�>'ÆK¾º|>´¯=å­+=ì%ƒ¾[aþ<ÿí�½7˜è½·“Í=~/k½8¡Õ=1d¾­ì>~„Æ=2 ͼH ¾Ðñ:¾1y³<7¥¦¼iœ>ÔŠ>PN轨ml¾È8O>ÝB¾s©Q>k•ž½�ﯽö1¾Qùý½?ê>Oh'¾_•C>þG>™Ç½…±Ý½+ø¤=0±~>aÉh>EÈL½@žÖ½Np¾©Pƒ¾;�̽"H=,�>@5m½°Ö¡;y,¾À¼<>³°Û½ƒ¼¬¾àÊ}¾ÙÃi>¡›×¾sš >y±0=J“À¾­¤Á¾¯Ö=vy?Å8>ßp>¾%±½í.¾Hov½0Û+¾å!¾Ð¹ª¼nôT>·,‹=t>oÙ(>$Ľ¢í>éÆ<Ï4$>É}…>¢‚>>kì=ᚯ>4h>>þuK>LÌ>Îma>2{=9âž=øXº¾@G>ùI ½_*R¾Â``¼fÆ!¾eð$>j‹Û6>¢‰¾ƒæG>P=_¾k€=>ŠtO>’1»üÕk½A½¤G>Š >'âA>9­ <«Ap¾ƒÃš>¸EZ¾Óx¾‰`W>Ma•<,xP¾Jð">«�f=:¦K>1Ei>{ֻ릚½4>¾"¼¸¼Äs=ßMA=PÔÆ¼§zâ¼q@ݼjÎË=2¹>V‹½j{=¾«·ª¹£F> À>EБ>mmä½¾çp=ñóp={lÔ½´k>Iä}¾.”»VRè¾#i½ãÞ꼡ã#=[Q> O]O ¾�­ê»Ò”³=¹Ž�½Ø™¼›ªë= 戼9ýd¾Db½ÛFˆ=fU½]ؤ>~ø×¾öoˆ=l>kDx=ôä½Eýµf*¾š³ˆ=³ÿ”< >³¢C=­±�¾*]>wœû¼ßM�¾}_>yÛ«½ÒÿȽ¼¯—=¦o>â婼¦¢=ÛÝ>‘¬=CÞ-½V“>LMŒ>„«O=Sç¾*œŒ;jÀ=)Z:!x½§5š:Qô>;Äc½îC¾ë‚7>¥"ç>gY/¾-j½È^¾ê<¾ì¢˜¾Y¹½9–Ž<ì©Ê¾õN½U¤¸>¶ª>it&¾Ze¾½SJÕ>J'¾^]N¼q“Œ=Q�>{™¾Ê/=eˆ¾À¿^>8W$¾�•›¾ 2¾¨JA½iA�½:Ÿ ¾U")<™· ½ßœ¼Q|,½ßW×¾¶Ï޾¾)¾Ûœ=�—P>‰*„>òý¾•ù+>jŽT¾ë¸¾Dt">yA�>„ÓÝ>j\$=� >®‘©¾îÞd=›d>e•½ÃÎ> ¸)¾“œ-=þ·^¾awï=YÝ\¾(O>¸‰>ÖZ¶=\AŽ®£–½ ½>F=e �¼X³$>{Xm>°ƒ½1"¾‰°“<2¸ù=j›"¾�›½œTØ= ±¼¯¼Ú+¼½€®©½ÉQ>ÆÑ,>Ê[þ½ÈH@>†¼>y:G>0L¦>_ã>À_¯½ç,©>rp4½–Ò1¾øÎk½5’½oÉ<>¸Ê¾ë¸!>ø›E¾@9è½ÍPP<Òi¾»ÙK>ê©?ÍeÍ=Hñb½&.ؼV]½añ=øTa¾yxš>_²L>tË·½æ½½7:þ>’`§¼¢�ƾEsc>—­>¹ë©=›'=ö[‘½æ�†=8®ö¾™€¾T`>��´¾CŠï=a‡w=ò"¾é£½EAÑ<T¾ �>ì�y>Cý¸¾Ðð ½ K¥¾7,¾j_t=š_>äA^=ž†­½ø9U=Òê^>’“#>ÝŒÁ¾áŸÖ>Ä|²=�ÝÛ½�6[¾’z>�&4¾'n>­¥¾üg“» ¤”½ÍíN>/8>dõP½ñ£¢=Ec‘>¤'ã=GÓ¿v©®<ÇA> &>‚š'>-¬¨½@×e<*õ•½sè4=«Å—>Ðj ?L8&=¼2†>>†ñ>õé> ]¾4¡;½ˆæ=ؼ>=;øØ½8Ô4¾ªGï½m’€¾”��=æ‹J½ùû¾¾Äž¡½å4¾œÚ#¾3‚˽ªnf>DWn>Ÿ\">ŽL >'KÓ<›nÒ½ø"$=ÃðU½âJ½=½¿nþô½»Ü¼¾*0"¾syÉ@¶=}îÀ<d�¾{ZÓ¾èí†=¾ ¾ÐL‹>H�=*œN>Ò}=¿Ž>­—>*¯±>}ð¼ƒ( >¿Äµ>¬U">1ï·>.�¾QL¯¾õÛ¥=á¼–½�““>øš�¾]hQ½dü ¾Ú}•¾êuw¾Çy>· Ô½*Ï> y޾ /D=¶.å½@Ñ=ÀuO½Æ’/¾éÔ^¾À1£>*‹¿ ¤½�ì½l;>Ût>¾F'¾Ç¦g>xÀ¿¾9½>o‹¾Gj¹=;M[¾SEg>ÁM@¾‘WQ¾Ú§Ó>U$&=´IL>8ÿ½Ht¾�÷á>Ú‡�>Ä>8½ !>O �¾Þ’&>ƒí!¾!�‡>¡u·¾zÊ >ÿ&'>˯½P˜>Yt >¾Ù’=T<�¾É²#½oHê¾ÖÇ ¾ÿw¾7Z>ˆH¾# t¾90¾Š@=;S>Z°ÿ¼ÌˆJ½õ>L>$+�¼¼º;½¢>`ÌZ<5äo¾�B{¾ç¾d¾œ¼\¾÷O"½’áͽp‹•>¢âѾAÓ½=íM<½û[4¼…—½[.>Ü­�¾§ÍŒ>޳æ>iBg=ÿpò½û¥†>Y1ì»M´~=:¨”>™X+½„x�>Û.è½4,¾ž³Ü>€¬¾(a(¾sLC¾º">/¾€UD¾eN>¹~<}ä•>é->äí°>—:'=Ó÷>UP‹¾ËAg¾XS¾�QA¾Œº¼úJI>ª“ü¼Ïlí¾`å�¼8íȽì×Þ½¨/’;7ûR>vh¬<ˆ¦Ò½UŠ?½Mq <Âá½K>²GÔ=¼�‚=éË>K8¾”ɶ¾ Lª>¹¿në�½Ñ^ ¾‡¼ u ¾‹~f¾êu‚>qð?½\†L¼MÌž¾|íœ>ºÇ¿•…¾_Ñ‚¾Ø ×=Ý3¾"‰à=T׋¾s‰l=ø1�=HR©»Vû•¾aÏA½ ¨¸=”¾Y¾Ô“µ½úªD>kÀ=c@4>U „>ª¼;>ÅÌ.¾àÌ�=4¼�Þ˜>Æ ¼`—7¾çjö=®…=€TϾ5³=ârW»z[²>MƒÙ>gE>‹åÚ<Ëûi¼A—·ç] ¿Å W>?ƒ=rèÍ=Zñ½“Iš=­ç7½7Õ/#'>’ >ÚY»Î‹>ÎÎ >?྆PX>šç>˜Rµ½ƒkÞ;Úѽ݋$=/F>¯l=Å·>Zûn>S“c½Šq¾"‡°=;¬Ø<|}È=÷u\>Œƒp=´I¬=lBr¾É¹ã=lA¾Ú �=‰o½'Ϩ¾zv>£šõ½8š<Þ(½V/¿>—¾1f=>Œ¬?>à:=õV±>{|¾Žë=p#¡>,l{>í§ò»–Qw½Õ”q>¯5B¾¥åh½$¡%>‰YǾ«R$½’'¾%�ô¾ˆØ�>ð¢>›=üp†½«…@>`Óv¼‡�f=°Ž.¾{*÷>UÉ =a L¾w_Û=s]è=÷ví¾ÀòÍ=é; ¾w–>ò8Â=çf­=ÚP¾%QὊ®V=ÊÍü½€µÅ>T1á=¬á½PŒ>¥Üæ>y \>’�À=]ñ>Û>|°> –‡¾V÷ >M;¹<~kí¾cÒ]¾ŽåÇ>œr.>Dˆ®=‹I�>‚od>ÄÕ²¾§±Û½ Ýì¾Ûâ¾¥ð>Mª¾ÁX¶¾Gòè¼Î¦ ¾vJ ¾Z8â>ñ2j¾€Gã=-1Y>N$Í=ûJ>¿n ½U'>¿rz=W¼á½^�¾”¥–¾oÛ=Æ97»¿r>FÐŒ¾™ðe>¬~¸¼-°§=MÚm¼t¹_>L_Ⱦäz¾H#´<Ü Y=›ßš>Öp£>BÓ=ŽÒã½wv¼%õ�¾1lÂ=GÏ,¾=Ð>�€$>qô>1Ǭ¾é§>bx›½½™*=`K¾V¨�=jž¾ºÜ½Óg—>8¡5½(~�=Âl½v`É<µ>™<í=t¿À¾@ j¾gf¾IT=övf=0žé¾ ý›½T0½j3 >´Ì=}ïZ>ßðŒ½ûvT¾$‰>¯‡>‚±j>ŸÜð=‹ѽ;uc><Å"==¨¼=…q=¬÷1>×."¾9Ä<Ô�U¾a?>;ޏ=Å‘>"&£>ì¤*=±v ¾nÊ ½¥“R>^±u<‡1î» qŒ>“S®½æ^µ¾ªL¾"b"VšÁ½7ÇŸ¾Ë~¾ÐF=j·Ð>èõ¥¾Á7>ǃ'>vO¾8$o¾ïzý=zŠ>'4¾_‡¿½msí½÷ç¥=”§“=Çä"¾a£¿@ÏA>Xê§> oH¾Gs‘¹™Œž<Ëó>rò>X¦#=ʦ‚=ZPÖ½ÕGQ¾÷¸Ü½zU¾øÅI½&U3>æú©»”+¾Vs<�”˜»õH}¾“q#>P3…>bðU½rl[¼î—.¾°S>‹ż&mx¾êsÇ,EÔ;ÈÙ½› =å}½KÝü=ã”;>K̽nk5»œ¦½»ßL¿,|ö½Ç%½bw=êɆ¾BßÖ>,Ž ¾³Â?ž½ašÎ=ž„>J”’½¦&>k*…½“I¿;Üðô¾µ0¨>Ssо¦&'¾ âPºI)=>hN=¾žh“½°O=ʺ=H%=‰â >ëš= Q{>Dl‹¾‘?̾Œ=¾JHÜ=i—¾±àݽ�º¤¾Ì·¬;Í<™>æîN=k>‚¹D¾WFNÉ;¬<·gÔ»„cͽí;>î„'>dƇ¼8¾Cç¼ÒÎ)½›ê=Nª‚¾vêK>£$N½_£¾%Þǽ¬Ç>{Ué=1Â>2KAý¾ —½©C >c´ >yæ=×®Û»Êêí<8À�>œ…н‹I¾²~ϼ©½ œ¾àZ>£&×=K†ž½Áß^>úp¾mÀ7¾K&=ºjR¾³ßð;~~½>·¦¾wˆÊ=[Ù�;Ñ ¶½‹m°=oQŽ=#…&>VY½FYl¾·•$>öéJ¾ü™¾ i>Œ_ ¾¥™A¾›ý >z³ã»ûòF¾�K‰>][¼(® >ÞÜÍ=oP›=Ðö�½ZŸì½Û(-¾â²L¾¥Ê;GÓ¼æê–»w�¾·æ#¾Lvº¾T¹>Ê¥`½�ðC>Å'¾6xq¾^e7¾Dþå¾ÿ«•¾p‘t= ÅÚ>xB>†ñ”¾ÛÐ6¾Zp»¦…õ=‚©=bÄêk5à½ðs¼Œ'6>¢ô=A+ >@ĽE1%>¼y›=ŽP¼\ f»3醾%ÜÃ>ŽÐ¼\>Äô€>ç®’½p¤¾pz†=kG‘>Gï>$=ëO=HÇõ½&û=$c>Æóù¼)~Í<ÉÂ>o=½ ¾�wY=ç=m¾Öñ>ÇA¿bR§»Áo<Û^Ñ<îºÂ½pÒZ>Ï÷->.ÝW;8ºÎ>ʽ¨‡½Ö),>6þ># >84¸½v©9¾=nâ=_?ô½Z®ü<[j¾ZÙ×=•Ëé=7C²=8îð¾k?Ö»&�>˜yJ½³z¹=äïá=Q�=³Ñ >Ñ^s½Òøµ½kÕ+¾-=¾˜L>¡Og>é¯=˜i+¾Ë‚¾mŸâ¼Œ¾þöï<†j�>=gŒ=\5>cÈP½Šb>WMâ¼+1¾–@ܽ¿ =ßÏ= ÏÓ¾žd=û\Î:*޾ƒø>ñÃ;•»Þ<À&™>ì6;¾þDL¾Òä�½ÿµ€»#¯ñ=Üï=» ¾=ÃY&¾Oé>Š+>Û&d¾‰ÑÑ<ïÓB=Êȉ½|´–¾-Ä ½ÀW²»Ï¿^½=œ"¾»™U<ö¾5ü�)=¸qµ=ßx¾†¿=½Jä>¾ŒÇ¾ŸôÚ½¸ƒ¾Iäv=Üq‘¾°OÁ½,ÿã=/–œ¾±±:¾w*=#‹¾C F¾á¤¿½|[¾�ó->‚šþ¼òª¾[I½ð&;<´³I¾£޾^6V>Ëà-¾¬Ï&>朽3�½Q<Œ½"d>Å蜾BÅ;äµ>±LC>O™=µŠŸ>ùÌ>x¸˜½f¿ö¾ŽiM½ƒa?>’Hò½QQ.<² ¾æÎ9½‹‰¾Á_½½›’å½ 3¾à„v<¤3¨½Ž…d>sÁ™>ÐR¹=FRì½Eèq>ÙG ¾­ß\>i.f>Ù¾Ó’`>öÓ>Vb`¾8ò&¾Æ”¾ên’>"¡þ;vpξæP>¦³@>oè ½Œú¦¾Ý1O¾0S/=s2»1�\¾×b¾©)‚¼"à‡¾À•A=Þ&ò¾r™A¾ë|>4;ƒ>äìQ>Þ¶*> Æ*>Ù=,½¸Ëã½·$Ä<:ô›½ PM>l9´=ÛúÒ=Pe>n¯E½Á¾>Eth½£"4½–¥¬>¾ñc=*mN¾"I=•çŸ=•�[½;§Ý<'¾©­³=•t¾E ½�©Ú=ƒžÐ>§>⪽¸†;«™õ½_æe<ÛB=½¯�Ç=fL6¾ÝÇ=đؽö`þ=f5=^Ý>÷Qp>xï§>±8ƒ¾ø“€¾LŸ>¼ú”>f Y½s�j>^˜ž¾�î½9Û¼�푽üD(=Ú«<`ìl¾‡€k¾HÈ=ÿ1N¾Jýq¾qÝ’¾a²�½JM#½E} >†ûν+ ©½Ñø ¾Ç..>·F/>&M6¾À{Á>»HÃ=å?X>þI¾CŠo>Š—/>V.û=·ìÁ=2¬>>6úk½[ù.¾\ѽ�.»<ÁݾÌPÞ½ô;­¾™çÀ½ó€å¾ò˜ô= Jã½�[¾¢P¼·j‘¾5jô=,ÿå½XнH³'=v»«¾ÇFH¾L¬äËÑð»&ZL¾þK‰> ¿ÛŸ”½Åd€½¢£(>[•€½TÈ(½ÐóÑ=롾�[‡¾´—Œ¾vSV¼4`ξÒyC>®] ¾³;E=HCc=b¬ì½î›§;|c¾t9�=n¯™¾µà½¿н¾ª=›qÃ=|¾~ù<<ã ­>ESÃ=M26< $H>°®©>£ =–}2¾½ái>X Þ¾bí%¾†ÀÙ½4w¾3‚>«*ì=!¸>¿�½낾¾Õ¾ßu¾-Ã×=%õ̽.%>ñ{:>?×[>g2ˆ=×å=-@/>lh >Ô@=Tš§=uê¿;>\>[Ó4¾èÎ<2UÒ>¶“f=³*–½¡fö=‰Ô�>Xàͽªq�¾† ‘¾ŽN„¾²Jò½0³4=_½î5=Sà>`½“>©ûs>1d¾©à=,ãʽB+>ŽÜÃ>_Za>jp‘=¨d¾p‰.¾ÍÓ�¾,Ó½ãú™<*Š’½ ÿƒ=éx>tf½×…>{>6$€¾‚}ѽ’í9¾îɹ½¼›=%•Á=Lç0¾ÞÌ ¾}@\¾L÷g>Ò+¦¾_½u>‹Å=aÈ.>#YI¾d&¾7p¤>èxݽk±Š¾¨dl½RDí½ÈÚ—¾IF>î•h>ßÍš¾ê]°>Ù�>5ÂU¼uUͽ©,¾®õ°½oë¾/=7Í:>´ž=žp¾Р¾+Ö½‰€P>™�yµZ—>¶·[>ëÛ@»8L•=9¥I»2¾H  =Ç:ýPUu>;ìõ½z¾Æ€¾x(î¼GÂ�>¾[€¾5„>rŠ˜º[‚½U¾U‘>´ÏN¾dfØ=x…¾ñË(<!¾Âÿ⼉eŸ¾²Õœ=y>=™¾uÚ=¦-r>3 $¾×ÝP¾ ¤°=Üá¼¶¾·¾ã#¾êù¼–ZU=̲™>·Æ=½e =ì¾Z� >xè=§Ÿã½G"í»c¡Ð=�D¾#v>™“m>¶®I½Ö`:>Ø¢½7ó=0ÿ‡>õ^¾ª0->Ýkj>®ÞÇ=J-«=b Î=˜ >æ£>Ú¹¾l>bºÂ>I²æ>^¹ß½íí�¾~K˜=á­=@�‚½c7a¾²Û:>áXî>Ü›†½ä®œ=KZ>�W3Ô…=�Œ«>"Üe>=ˆ =⣲=^¶-¾Éª¼Xù=ŒøÎ=«rb>wQÐ=ú‘>¢·¾½J`¾l¥¾k›x¾.a-=Q=>2`W½úQÚ½‘ñÓ¾þoŽ:©–—¾ ž>ç/Ë>ý®¾ ¥.=QÊ¿½¾>£® >!y›¾çÀU¼ØO<©óÌ=Çü0¾“1=óYt>…§K¾¯\½½1„Ý>2x>5u—<©2«¾š¿D½©Tâº2úJ½pª•=Ñ©„½_îå> ¨=U`n¾éá齃v’;"5O>‘ å> ½ý·¼ðd�¾]]¹¾ýÕ½tÈŠ>Lë˜=+º»½0Eš¾Ï5>ùP#=6üµ½BÛÖ=– *½oÊ)<2eç=æǽÔóŽ>�0J=9ÿë¾PC/½ï/§¼èt¾x`>Ã|';Lj°¾F¥ˆ¾b€f½&•´>1{¥=¾èG>Ñð,½o&*>âŠ>âNu¾ ù¾ )¢¼ù}¹:÷“�½^ÀÚ>T>Z'¾U>Œ>r­=Œ9C>·�u< Ǿ¤SÒ½ã7¼¸ÿý;`[¾Ø¡~½ycž]X0¾èK>½3�=03Ì>žã¾Yñ¤¾¶½’�Ÿ¾¾fÙ>½³¬>Ã¿Ž½-þB<&•½U,z¾  ¾?(Ë>žu=óUf>jù]¾¢‘=ÊUS¾äµe¾æê ½ô $>Ð*>Èa >v„h=ÿ*J¾�Of=“¦»<±Š.¾l7?¾-<¨=Ï.�¾i½\W§>Ȭ>§êàkŸ‘¾ÏÆÑ®V=�!¾'^A>ÉÛʽ4C >¯ly¾àƾç³¾>µ>|̾…;¾¿U•<´¦ù½N`N¾f¬=–$=¿·î=. š>è8£½e¾ÂRˆ=.‚�= 6ˆ>/,�¾’¼x>«ÕŒ¾duî>VÉμç—%>!ˆ‘¾E†>Gç<òÍ3>Ú¿‹œ9¾Œƒ¾VÚš¾=’¾Ñò²>›‹½Æ?f>Eœ?RyÈ<¶„>;û>�Q>EH±>l˽nK½ív¾,ü½¾óýq>@ÊA¾éë=¬å–=L¾¢Á=ú‡È=Þ)&>îf„=Ƀ?¾öûU=–ÈÔ>²ß”¾ˆv> ð‚>mSX½Èò¾ñãf½©§ã¾ ¾FžX< �=¢e;:h(®¾34>Â_‡½Ÿ>[žpF>ùø½\B¾ƒ t¾@1>ý²½‰ˆ3½¦Çš=î,>y Û>’/?äcƒ>a <Ö>¾††>æÍ©=‚6K>³Àý½\½Å‰>§Á=N×¾·|–¾â:»½VÏ)¾¨óÌ»�ŽØ½0=‹=Pù‘<¬9¾:c>ßéa¾jJf=ܿƾûÇh½þȾ½SŠ>¾¥¥†¾ÜV2>Ði>õÔý½�&_¾é:¾L’4¾™1Ú>½rŒ>LÔÿ¼¢c¡>À�¢<´->¿Êa>¼’M¾5í¡=îh=©‘J>oz>$äT>e5ö¼èvú½]ÿò½ŽO˼շ‡>Vª¿UPѽ崇½I�Ú½~£C>ËF`¾^¸5½PÅ=v?`>ðª>Ê�¾Žï¾\ ¾ÄɾH–B½¸‚¼¾þ8�¾'U½ƒV¿)\ƒ>tL¼¼^¾—½·Ü1¾h×ɽ"¹i½_¼D¾ ‘l>›¾z½º½¦ŠB½T‡C¾‡nm>`ìξrÐ>»@¾ž6ç=žuν-à~¾»$G¾RÄ=¾ž÷=ŠÊ€¾R?Y¾Œ+>ø\�¾ìr>cŸþ>ä(¿Ò¼š>�+²¼Ï“£½·8>ÔÙÒ=>U=fê;J](¿�Ô¾¦d>=¤-½µâ>¨U>o+½ñ8q>™ˆ>óH?>"g=ç†.¾ã÷�=i¶=‰qÒ½Õy+¾RÀ=;-0¾<¢=x´†>™ª^¾±÷¸>¹]ˆ¾ø—š¾<šS»¾bW潬=¯Òp¾Ú•]>Š>òÙ!>ôº½ û=Wœ$¾ q¤½xÓS>¼è$¾³P>>·‚=hª‰×Æ» ’½}e¿<<&d¾"°�¾™?�!ݼÈS¼¾%G>üíÄ=¥Ìa=ÈÈ>çî½]!:>ÎÍ>®‹>n^�½Y÷½q=½®Š‘¾ÙâÛ½W>¶>fs?¾„>«Žç=u,;>�ìc¾Œˆ<½ ÑC<Üe ¾ß*¬=ößy>ç$m¾SºÜ=œµr‘Ž>Ù¡¥>¡ŒÐ>+‡=›‚=¯Õó>Âdè¾HRO>}S»tÒľb&½gU‹=*.`¼bÀ³¾6,¾4Ë$½ú,\½ôÈq¾ƒ(‚>¿âd>n¬¾‘ ¾5‚õ¼„3r>|#Á¾pzN>r± ¾ñ?§å¾: ½hÅ­>2zº>¨+¾½¹=ú½±¾�¤’=æì·<¶Fþ>?>y’¾ 5¿¸ìؾ]ð¤¾-à?ƒé=µÚ¼*Hï>Æ·>OgX¾š¦ƒ=«¢@¾Z¼>ß9`¾¶;Ô=ª_‘½Ø ú½kÄ=aw·=Co�>#&F<+¾’Ÿ=Uw5½ÈŠ>¥‹>£µÆ>ë—c>à3€½§ ?‘ž >$¥¦¾ÿWÞ=Úd¼š¾E;ï•­=×½6¾iÄ/¾’5þ==Lo¾~èÙ½b €½Vü>á0¾\Â`>uH%=‚»Ž>-ök½ÁAø>�Œ‘>ŇU¾Æ|õ<–;¹¾*Œ¶=L³½\Õî=é ¾K4š=3 •>� ?>DH¿Ú�,½Èä’>±Ÿ=g!å=c¶¾âúf»’Ké½#�‰= ̤¾³K¥>—°Þ=is > ›¾H >ÄxU¾¸mÏ»‡c3>äe<;Ç>�¦€>îÀ>ÏZ¾Iñ:=ÛÓÔ½Î|ú=y²<Þ.À½Žì¤½/Öľs¾4¯Í<^j<]¾é°= Ù;çÐ<)e‹¾¤3Ð=³œ>ÚQ‹=y‹Ä<ž:¾/+g½©ŒB¾\”‰¾Cײ¾.€=âÊk¾L«=Rls¼&t>«�©>FÆg=Í�)²>Eœ>(êH¾O/=dÕ½bè�=Ï.w>¤å–¼îíŠ>3a>Àù«¾o[C='•">Ëÿ,½ÊÊ.>~?T½Hq޽&-Z>!ºŠ¾iÀ¾M?WŸ>/$l¾RоÂü ¾óÑG>s ®> cè½w�C¼­�">Âßî=«¹Â¾F/ß½±rf½Óg½�½°ZÙ¾s¬±=sо+9¥¾²s=B¢ö>‡ìŽ>�Å»¾îH›; 6I>°ÄE¾K̾d>º‚>vó=¾ŽÙž½¼‹«½¦b>h¾�w!>Ø£¯¾‰·=÷ó€>ÄÆP¾áõ¾©D ;ßR=ø ¹=½\¾=LNø¼2÷_>¾u®¼œÛ†>“·d½­†¾[~оšs-=ºŽò=* r¾ºŸ¾ƒhT>öhZ½C<Â�:¾Ž I>ìøu=Õ]‚½‡ ^>£N´½çM�½½@Ù=PD>¥X¨=ŸÖ ¾P=‡¤½áâc>þÍ,¿f,F>ú¡ý<@Ž<Åöo¾]Œ>S÷>¾h—¼Uã½¢Ó€¼K÷é=¾åo=>O®½<î¾ !œ>ß:µ=—Ü0¿Y¹>[ >æâ¾ÜݽébI>“±&½žKÁ>jËB½ø ­>­„=úʾŸ• >Me>$T­½±}=¾¹¡5¾'ï«»~gÖ½êSÞ½r1¾PŽì¾Ûžý¼Â/@>Lä=çØ}=áR?ˆ! ¾Ù'Ý>C—>¬)C=úT€½C$X½edD>çÛ½>LŒ8>ö¯¼§7½{r=¸£m¾˜¼5¾ÂBs>„ å½ÓÙ¬¾ØÅ©=„]ÿ=^Ñ= ì¾&©\>G_F¾Wâ=oŸD=£¢`¾ýòn=RAŸ¾ús=ÿp˜>Pß=S(é¾Ð`‡=D­½·6†>”í�>æ >¹…j>‹§=*Å4>\bȽ&=>uŒØ=æ+‰=l>p¾Ì=9¾>Aå½ìf¾ù÷ü>4�Ž=ÿ.>³U㽦ù´=Ýö¾—²M>Z—÷>÷û?¾ðÁÃ>«Û=vX!=²Q >ôoϾ,äá<úソ Ã=…í—=t$>Ó>B¸Ž¾–”+>£ª¾:ÎýÿÍî½3Ñ•½ë##¾‰â™¾ŽŽ*= Ú¾zú½«â¾(g:½wÍѾbB¾ßto¾'½B_=>×­R½ |Ö½[%|>éI‚=©h =Yù0>k=²¼„Ò‹=^$³=Œ0?UÏ7½öŸ2¾h÷‹¾åØ¥=õ¾=ž$�»o ä=3ž<CϾ,>h>_S>8 ¾%cV>ëM> aj=7âëºu‚>ò>Ò¾õ<›º[ ¯>˜qª= è=t¥¾Çø¨½"ì¦>»™ë= 2¾Ù­»½”£‚=«w½©ßÑ=˜æ>Z¡±>t>¨u>ä[t>õžG=Ý0á¼J� >ý‘>�<,¾„�<0@½ ¿n>glú;� J¾QÏ£¾)@›>òž8>Z¤…½£�—=Ö =Д‰>ùÛ¾W!$¼ ­>—Q>B¾ÓóÄ>|`Œ½� ›>¶¾ÐE}>sè„»ìYǽ§£ ¾/•¿>˜I¾dñõ=Ö«S>{ÔľrN=ð*R>ÎM’½�ô\>zæ>¾/£b½ÞPŒ¾HŸ‰¾‘æ¾ �>xû5>pø‡;]ºq>c¶p>½ ã=ŸˆG¾§¾"b> �½S6P=�F½RìǼ�á¾L>8‡¨=k =FP¤½`‡.¾¤~ù½ p¬½Ì­Ž>ª´†¾oC¼8ð ½ØÂv½�K€=ͽ¼õLÙ¼„¾”½k?½— ½½ïp»å.>1¾í|�>Ô4¾N׆=’úH¾›éÛ½"þ×=Kf.>8°?&Àã=žK>éd˜¾�K ¾!�O½ßÒP=ꃾoŽŽkî½ÈM>ŒÂã½B2î=úVU>¸ã9½н^̾÷->¥£¾{¶=œt>³ k> ZÖ=LVL½iÏ;tÀ>>–%v¾ <@>È£”¾À9�½jc?¾²"à½ó­½½¥"¹=2œ4<Þ¾{Êo¾µÌ©¼ð¹4=8Š/>OÅë< ¨Ä>k>q0¸>5–нV®Ø=u:>L éªd:>—³^7?½Ï<í¢¾9 ¾v‡ž>KØ)>ô4>6²Š>×~6>+•k¾ÝV˾ ŽŒ½©Vٽزî;Y¦Ô¼{tî½”–N>ç>=`‚&> ™½P´¶=ÿý´>~$4=΢½U&оY-“¾Ë ¾¼Ÿ¾M«½ûœæ¾fz½tRǽ}Œ =±§|=‡Ê�½„’`½Ÿ>±²V=h‘8¾žFú=E±ô½‡�¾¬.¾MY=QÀŠ=[º^>P@ɼÌsC>}Ø—>kay¾Òõß½Wp¾IŽ„=Pù"=•g>¼‚³‰=÷Òq¾|©ê=Mðz>{l+½ŽŽŒ>¤Ž÷{¾3 š>x ¾U¥+¾‹¾Ç›F>ß-ȽÕ£½µe®=ÎíÊ=ŒO¾Œ�>ûÊ}¾ïòÔ½Ðö�½Š ½) ¦¾šÞ¾>³d;¬+m=g[Ù=�}½š†¾yã[>¨3<@��»ïý2¾­ý<š\м'M>‚ð¾XM¾øuȼ‘“¾È|¼TÕh=±Éü<ô¦À½k”½½»&½À±,½Æm>ÿ›O¾÷]¼yP%½mVk>†3&¾"8â¾Q[š½Øë>侇¾Wí¤=¦×ð=Î�±>Ûø=¾M>=ƒ&Çúˆ½œ�>&z>è\Y¾ª�¼¦&=qad½ðÁ½³Cs>¦¯¾5ß6=¤$Ô¼³Ú.½_t¶=ÚE>W½ ž;ÿ¾=`°=fáݽͣ7>CŸ=lEù½Â0¾-½sq¶¾x©¹¾É2©>¯œ ¾ýpr½xwƽ¶Ò-=å{º;F5¾^?–<Ð?½ÖŠß»Õ¼á=¡Óˆ¾®´\>6ݾúg°>g®º;}„>¿±Ã½¶¶×=ŽÃ—>s�•=ÕÓ‰¼'»+¾†Ÿ½sF>H—õ<âÖ(¾+9>;Ïž>PDt½1 ¼+€ê=&¾ÌQ¾Ë,×¼8¾$1¥¾KÏ:„/—<|@½w�Ì=Ðtà=Œk“=¥Ä¿M�½=ð¡>ÈCà½9ÕŒ>µ�0>³~ ¾EÒ½Òèb=ƒBŸ¾7Pò=ûd=/Ò½X¯…=,Â5½$ɦ½²Ìž=Ų­¼…`8>UÅð»@¼@><\t>ny5¾ÿ~ =_ ¾-Ù=[–G½~ñ9¾˜Dн¼0 ¾;Lç½àꄾÕæ½ì–8>©á9¹Vð¸>~î½5% >ÒP§¾F½A;h¾rÓå¾°Pž½V×>Ëæ©>žâ€=,8ó½˜di¾çß�¾2ûD<ˆœC¼êˆßU<Üå,¾1=ÿÙ»Ö”Ï=p4> ô >ç&”½­‡ö¼|4ð$Üø=ó¦u<`«‡<Özª½)‡ ¼…h¾ðþ‘=Ža=.8^½@¨=ŸZX>êáÉ=ËN½í.J=ßd:=Ò(¾µ ‚½W•=`Ø›=b©¨;}cm½àÕß½mì¾R5>p¬>=�þô¼[¾æÐ¹¾—PD>0CN=ƒË ?l° =™ÿ5>,öä=,Œ…½B¿½’’¯½|¸>äͱ½‚¾@�Q¾Îµ—>:4>u‘нÜWŸ¾@t¾q¿Ð=üÎb=X]¾xÍ>Ôvýj×½à²=š)¬½|ľ¡Ü¯½Ò6=¾'œØ>ˆ¾¥~¼Wm!=(ǽcV½ƒ.¾‰þ=Yp;FÍE¾�—Ú½ÒÚÆ¾,P½È†½H¾¾ø~¾`&Z¾EUʼ S5ºÝn#=Ç]§¼�ŒV> ìô;¸Š>À}�=4=3 &>Ìç¾¢Wd=±5¾�Ù >ˆ=q¾Ó->½u2½<=�uH½"BÙ=ƒ3®>m””¾¥6¾<¡‡=“"7>šZM>Œ”ѼåÈ>…¼—¾}s >IF<©n]>*Õ4>¦õÂ=°ľ"\&½¾cÍ>O¾vÂR>™`½cL>ÍÓ˜½Ýà½3Õq¼:!½ˆ >yŒ ¾0œ÷<]U>k~î½=¡À=gpû=×úœ»#˾^ i¾(I¾Ù"&¾¬<<¨�›¾Ü@½Zc€½ÜÙM>V®¡>èM,¾­ƒÀ½+˜=¢®¾ J}»X¤=­!c=ÏB=[;=ŸÕé<†gà=Ê C>Ö)–½¬Èô½=Ôa>0Ç8>:y3>^¿¾¼ï™œ½gƃ¼Þ‡E>Ùe¾í�>Tñí< •†¾õ5¿<*ç„>€óŠ>ÿN¾Ég+¾Ü©š=N)>³–Æ=œBнד„>ö ñ=G@U>“·‚½$*¾8䓽)^ï½qq½(>µ=ˆý†>X²=wV(>t)¸>©µÛ<(B—=|3 >ÅHq¾a{B=�P3>¼Ý™=QŸu¾ù;L½KæÞ=Tk¡>U{ä=¦´½ÞÃ=%G>.’C= Òw¾óÿ‡½¾A�¾í Å=žÓ/;ÈŽ°½b á½:e°8»›Î¾Í⃾4Õˆev›>?„Ⱦ‡¦Ñ½lôç=Ì›–¹; ¦=ç†>tFÜ>&Ï!>èf">»|Š>Áòÿ¼´=‰ŽË½ÖZx>×Ða½­#…<Åj9>Ùþ"Ô=ñh�¾ŽA@½úŒD<ÌŤ>ój&> ÍS=ÒĽÔÁÄ="³¬=¸Çº=ÁYð½~�¾òM%¾ˆú½š5 =qmR½C„@=RÒ軫¸á¼XTG>ËÝÄ>'Aò<Šàa½  ¾)5>bÅ>2Yj<#ËϽÕ½=ÂèÛ>ð">ýV6¾zß ½Ïï¼§€Œ k=i;¡FÑ<“ »%n¾|—¶<|�¢>suK=•·à½?À�=£÷Š>ÇÂ9=šdü=f0ô½etò;"n5¾˜PȽüö¾YD$>νUO'¾(ü†¾êiô¼•:>÷H�=G¯Â½gu½\5€½ÜëÅ=U‹j=öØ6=ñKi=<·Ü½�6Ý=êL*<éwß<5ÉŒ>ui=/l8>JŽ]=qûN>4ip>GÔ¨¼› �½ãšÝ¼4(®¾#ÈŸ½W2>E[Ä>au¨½¶7>ë\R¼ðŠK¾�Œ9=QV¾\(>QÓ[¾4qà<¢¬½‚%Ê<È•½ô±I>h`½7à'¾#7…¾[�½©Ž¿º5*¾ñÔM½Å/|>1sF=ç¿L>ªÓ=¼´0о?¬<ì$=öŒ½Öðo=;B >€$¾ÿ»Ù½_ܽ£þ=[­Â½*õ½¾c2‚>~}>̧콱§ª=õüǽÛ{Š=·í>=(F“½È,ª¾X?ô½®bµ¾Ð±¬¾Ó𧾿`x>Uý{‹Z= f�=Óe3>,ßð½†TÖ»{ÛY¾�4>‘§”¼Õ¬¾ÚP¤<üƒa¾>µ½í˜�>Â1,=‚Ÿ]>ú¢<{=:¦P=k5¾SIž=Xò¢=®Ù·¾2�u>¸À˜=e¹{¾"ð=¾óø%¾r¤F>A-D= �>¦z:>ª´½<€7>Ÿº;{q¼3¬ç½ ü ½i)>îÅ>!p¹=Š{‚>þê½·¨‡=¯Å=qÔÉ>\³6>¬òæ=S`>©'ñ½x¿ÛšÕ=“¯¼¥ûU½#A =å R¾ƒ\综�e<–!:• -¾Kb„=j¡»äô”>¹Ì½q“ ¾ÕWȾP-Ž>¦Q¾}«x½Š¨r¾õó=Ó[=¸¾0ŸL>…é >e­ >ú¼ãÑš½u£¾¹[¶<{nH>Š¢½Ô‡>‡ùd¾yêH>‚ã<¾Ö¢ì=Úå¨=qÒ= ~è=ª¥¾¥â>¨©¾ I ½µ>Æ|„½r¬¾<;>¾zÐ<Ìå>.:Š=_r…>Ö¤>aÄ>¿ÝU½ÀðǼãŸN>&}R<²Š¾ŽJ¾:�½O�Ì=èCi=0c>Ën½v%>vKÖ¼Qz$¾À£}½S‡†¾Ý�‰=·H˜=é²E>H µ=Ö]ñ½s÷żõR—=úND¾=Ù§>…¾n>ŒÆ ¾íV½x-½-ý~>‹šL>©\0½`u‡½™é>ŠÔ¼=ž>Dœú¼P‰>ˆ‰½Ìåx=æ )>n&ü=ôjm½8éM¾�M ½æ s½»=&½h3¾ÃPм¼ëŠ>€o¾\°‚¾GìL>LÜÔ½Œ7¼ØH­=;.?âæ;´Ù³>SA;¾áç¾D; >"qÒºÜpR¾Ä’=Èä`¼z¡¾úâ5>Å?î<ÿžÐ½‚õ½u>½ÁU>x»=²a!¾ñ%½4¦¾Q„=èÀµ>ò¼¶<9ò=Q‹Û<åø¢:š:š=+=m´¾éä>w„Q¾�°½ -¾±Q¾¯¾¤í¾†C=#W¾þÊ×<ÌA^>³-�½8˜�=�Çô=zã�=è ¾�b> ‹½¶£u=Žgx»‡=>ôº–>­Ø>äËg½� è½Î|>·ÇÌ=]«»>õŽ>€&V>í'¿öá`¾ Yž>\帽¸YܽÔ_v¾8yò½Áq ¾�ºìŽ=ú�¾ o>„ˆP=F¨™>Ö[£=ã›l¾©ë“>O,$¾UÊ\>Í;FÅS>š[œ>!œ¼iÞî=ß „½%Y†¾ A`>‘y³½ÚYy=JÄ=Å9>ã3^="~Q>€©¶>n†k=dkν/~¹½¡¡Æ=Ž'>_(»1~ù=¤ˆí<Ôѵ=â=У=Z¸¾¾„›¾fÿd>ÌŽ>[”,>€²T¾†Ü=à‹ñ½õ„¸½ˆÆ¬¾+X/½6Š/¾T�¾Tî4¾›>¾Të<¾Î� >ˆì >/æ=UQˆ=­ U>}þؽu¸‰>>ž8¼Å1¼÷Ê™¾¿B=p2‹¼m?8¾¾Â ½ø”¾XÆ£½eŒ=,º,>&tm½úü_¼Ä)¾s ½º§í½pϾ‰ß={<ؽ ÿ<!–¾#‘ÿ=º�λ ,*¾<²Ù»lï,ƒåx½;‚¼ÐÕ‘½Ld8=È+W>¾Š½™Â=‰)7½áu‚=Ũ•<ÑV�>–à>˾„üC>:† ¾Ã7>ŠÌ=±æ>ð¬_=ôiƒ¼ò®‹>Dª@½ì4S> cÏ=Ãx3¾Ø%¾¹¾g¥`¾i>œ\¾7Mó= œ¾»p>¦Aš¼/ıɾ—ÿ=ŹJ;ÆO¾¹m ¾oe&=!ö½¨´Ñ¼%:ϾÊ;¾„>ÂB¾úÃK¾ñ‡S¾iOÅ>C[½÷}a¾#9> p7¾¶áƒ>¹>«í•>æøY½#ôE¼ÉR ½�:�=’�K½TxÖ¾ëMŽ=¬Hˆ¾l^<>'T…½ -A=”à=%V¾ <Ö=ÿ¤½0¹ ¾qú^>¨‰š>.ìv>DÊï½]h�<³—ñ=eɽ˪‡=¾g:¾âˆ�¼é¼¾ë%«»au¶»Ù² =­<¾Ïr¾uL¿ç^¾’ƒ½7݈¾þ½[¥Î½»´½pû9¾êRà=Ÿþ ½o–—=þþ½ì¨¹<Í�N¾¯J`>•pß<šŸ¸<»‘>…:š¾�¹“¾2h¼½˜@~=û˾«§P>{{„¼s=>Tk…>lèоt>>ŸÅ½­!•=j9¾pƒ)>ðΩ½ü�™¾ëx0=xl>nO’=Ì>t¾Ì=4>">2¿�>LKà=öz¾BZ>s?¾ Ê_¾ß؃=±¾6¦¿=ƒ�¯¾ö‚>èÐ�½–ì½g꘾ž¡±=ËU/>[ºV>ÛP<•br¼N÷»Õ�½ ãÑ=±á=­¢=2ω>ïfk>ٕнÀ£>J‡ü;½_=Š`½„ã¢>ãÔϽWjº´pî½Ýw=ÌjÏ=*=޼Ü/½Ï®×¾³}>–²-=ýD=å^ͽְò=<^'¾,w¾)錽ښ¦»q½0¾²›�¾Šì„=Uá·>»œ=ßPó½Ç>+ýP;`7:>=;¬¼_ìê½ýpº¼@\¼y`½½Ç½µ>&PP>|›¾â,¤=ÖË™=g'Ó=à˜«¾goŽ>õGc¾‹»q'»åƒ+>$hh½˜ >‡ž�>¡u]½…‹/¿Êö=@zË<âk«<@_¤¾¤Ö•½×!쾄ª¤>ïÿC½ŸW¾®‘½ >™ó ½€?¾¾ µ;°Ô§½¹aô=ªÉ¸=‰ <¼0W>؃†½2óö=ÀÚü¼®N‡>×ÐÜ=ÃÓÜ=Šc½A˜’¾^ s=dø¸¼oËz¾Áœå=fñä=ù£N>'T#>¤JÐ=GË=�¥!>fDؽLu.¾%}q½u€\¾Œ¦<¾Ì�¾*gõ<N>£3c½�v4< ¸ï=Nm¾O´}=»°M=øÏ<‘ξó)�½hv.=ÖC¯=¹hý>³…½Àgè=k¤k>g>>ip/>à…=ãe¾1”\>ª¢Ç½¶=Õµ<]éQ>«þ½sI‰¾Dw;>®~¾¡>rœ„¾‰½³H:öo¾u)‡¾|Qû=0˜�=Éè‡>ûOc½Ò˜Ï½ÜúÞ½ªaL=$¹M=‡¾L²½½9‡½Òš¼j >wŠ/¾‹GK¾œ9‚¾SÒƒ=«·>‚á½~˜¾´¾¼wÔ½’Bâ¼õ¨¶>.ó>Ÿ,=ä>¸½™à˼�»¼>�_>dk ¾¯+>zÔ5¾Gp¾`€¨½¯Ï­>],>ímÎ=@l¾B@"¾Âpe>z6¾8B>¿a‘>«‡œ½> Þ;@kó=͜ϾÂ\¾w½tx‰>Û[¾Å$þ½–pZ>å;c¾6ǽ;™Œ>u\]¼:Ç8>ëÃ\¾ØqŸ=Þ3>¯wz>ŒÃ½¸|„>+OS>¿Ý‰=Ô”á=»«�¾ÕÓ><ô8¾-pA>©è½¾á®?N7µ>Ëž¥ú¿³ n¾Ûg2?·ÿ¿2©j¾¸@/=‰<¾™`Ÿ>ß0=7_´=5•^>Šéü½ÄÒ½ŒŒ¾àßK>ªÉå<�̼2ÿ=Cç½Ôw¬½q—M¾?â>°&<Í _½í ¾ óø¼b‡½ã[Á½¡6—¼ÃÍZ=�ü=Bk<>04ó<¯–"¾}0B=øµÐ<æ6½_�>uE*>Ñ‚>f§t½âÄ,¿­ؾbj>o>cà¾mÈ >ô¾ÊZ?Ç<4ZÁ=]€y½‰.x=§L$>WÈk=asŽ>b~^¾Ù<@y=–Jؽ£‚¾ì ½m#>‰ Ü<�[>C‡=G Ò<±æ<Ú¶¾ª•‚;¿5œ>ö'¾‰u¾gؘ½J3è½r½¾‚#>„f;¾-v“>å œ>08>8y¾Ø9;=‚Ã⦅ ¾¡’ç½l퟽‘Ì=P˜°¾J3\>r˽…øÐ=\è~>"ù¼xú>Yèf>Ö¾Td!=©�¾{ǯ¼y°í<�Š,¾–�æ=‰³J¼œß«=@µ¾2M8¾É,>5•�>ù~=ˆMÃ<¹2+½Hõ€¾>„¾ÜX‹½Âq'>ÉX=ƒ漘‰Ð¾‘Bõ½ÎK›>Ç·¤¾¡6?cat<›#>2vN¾jl=Êb>ä>†M•>ÿ×y¼C¥ ½L ½&!‰¾Ú[¾$ùa>ÖÏ=4� ¾¾Ü�=ù#@¾,œ>S,ὓà�½ŠŒ²¾o ]=ÖÜ;Sù;fû¼#¤¯½B�>f~=·7þ;¢C¼zz¸½Ó‡¨>Ñg…=1€¾-ZÒ: ,ê¾[±3¾¡ÎŽ>4OؽJkß<б+½ÔÎLÏ<S@¼ÎÛ>½·;¾ AÁ=u„>¯h¾÷�V>ü,C¾è¡ê=à Ã<�·è<$=>O�½VU½ÚÆ&½@²b¾Nøn>å&¾ñiÜ<­„½H$=¦§“=óÛ×>�ü¾¼N>@!�¼¢ ª=n‘•>!J:¾w¦= ¾L¾à„¾´��¼«0f½3ùÖDi¾eyN>u{=d ¾²¯>ö½Z̳>ÞI¯>–1M>§M…¾�Tº=~¬¨>ž›>�©Ç½W˜=!>pÉA>ÑQ$¾Jü=gª”½r>)Ô·=÷ >¡Sƒ=MÁ#¾”ƒÐ½›Õ¤½[6¿=¤N¥>È2�½¿%½·¡=MFR>b†J>7T"¼#äø>Ýþ½1¸¾�·Y¼o[�>–v='ß½úi¬=}�¹;ŠD»>ïl[¾ÉÉ%=™Q(>¡@·=êÌ=¾/ˆ¼Ôž‘>Ì~û=Ýš~¾.›=�Gm½µ1³½ÞêŒ9[(¾ƒîi;´^½hH_>u¿ù½ŽN> Žƒ=êT½„ûü½bª>7Øå;ÀÊÅ> CÎ<=Ùp>›F6>PĽTž;>³ìH¾“‰g¾÷»‚¾Ÿ23½ƒ÷À=À5=uwX=葾ÔÙ¦=­‹™½„šÇ<Ê…i½Ïù½d¾Wª½zæÄ<·>d“=t÷{¾%í©¼ÈÅR>+äK¼Ñ…WºÌ…ç½WÛ½¦,¾Hõ¾AÞǾ}Æ7>é¶“½ðË㾇>,�ª¾¹F½ÖšÑ¼{tÄ=­œ¡¾¦A2=ɾR>¬Õ8¾©õ »(Ù¥¾=¢`¾ùA¾]L¿#]’½l–µ½¦vÚ½ÿË;>àŠ÷½C­’¾À »F¾ðs[=Î[‚¾�!½vËÙD¾«Œ�>o�j>n5L>þµN¼Wx,=÷ž¾ªV=f¾ý×­=O ‰¾ü|ó»¿ß=dP‹=%Âa¾ùS­¾Tü=å�œ¼w(¾—ˆ>@¤÷=þ5~>ôM¾=¼�ˆ±½iì=yy꽪x3>Ó!µ;q¾­¨G¾öX#¼$‘¾2½hpx>J žŀ0>2[¾¡/L¾ñÙ’¾ã¿½¾$™«;R�ľ×|Z¾Œ&æ½:DW¾FŠ>a(¾¤.ϽíG޾Z! >n„½©„�¼ü¼Ô½²>„XÓ¾AŠ>Ž�¾ï;²=¦¿¾ê´%¾`Ñ›½ ¾=ì[<ùË2½ÿ³¾ÕÂľ´ ‚=pͤ><_¾�5%=3¦:=q"=ˆ?Â=Á+ÿ=G,>;d¼>%z¿=Pù]½q† >l2;ðÄ<ùw>¯ÊÕ=?Ì¥=Äi>Â’=¢«â½ts¾{»‚=ma?>�¼¡=È{(=~‘(½Õ­'=\1~=‡¢½¾*.G>.$À>,¢Ó½òQ¿;u*x½Ÿ$Š>E]¾ô<¾½w)“¼G>ÿ >êÊp¼ ‹—>´¥”>Pz=˜ ¾?D¾ õ¾*±t>M,6Óþ½L– ¾: M¾•׿½S«Ø½þ‘>lß�½<ô½]•h>"cù9·¬€>Ýñ4¼ÈâQ>`”Œ>×?Î>�šœ=Ú4=>}Y@>He½&Oh¾2Er>۾ػ4¼fò¾òÿ�¾‚Y`>>³–‹½Y(>ÒÎ^>)©>Nä>pYO>Nf±=·ìÒ<:ƒ¾†é1>¾TE=U]ë»´›½KWj>¿´½2rð=ÚÖ¡¾×›=NÇϽ_—P>ê›>œ=�>Í«¾Ž–ª¾ #'¾<ú½f. ¾~ʽdè¡=ºTs½rm´½Rhâ½³bP<îÑã½d½.´(½WJ¾¾ŒÈy=U±’½“ˆ¢>(�‹½Û×ÿ=Æcu>‚v>ÜúÖ¼³†<.d>¾¾³å½žã¾Z¿Š>ö*¾G�<ÊØ½>Î'>)D!>qN©¾Ö&=&¼1 #¾A}=:¤×½æœ>«‡»=ê;">)/ò¼³½=îÛ>"”= ±û½! ?…*=�ƒ¯=ïÜ­¾\²½k©k¾>¶x>4a>¥ó޽^hú< I>†Wý>ƒø·<§»l¾À|">�¿=èD:>Õ{ã=©T½¡q-¾¦ ô=³Vo>øÚR½gw�¾�¶>Á®‡>f=$÷Ú=k~“¾ð`ü=Ï)“½=㮾,}ô¾üŽ-¼›°„¾jユB+>;œA<§Ô >*ú>PýÆ=T<«< vR¾–•>໓¾ñ]\¾Cù»Ìwý=ôº_4µ=•«<¾ÛZg½ÔD-<{vä½7¾ÒŒU>¾dP>®²“½Ú>ó½{ç/¾"b¶¾ð³„½´=¾ó·^>på½wÀ½ä~o¾SMé=óc€¾+È�¾:)b<¯v¾Ä£¦½G|W> ?Š@">q¬¦=È'<¾eG ½1†P=À=j¾â£á;´2?:@›½ëy‡=·dk>f°Â=Zc÷í„«½é,>ú3¾håº>‘0¾Û�>,á;xe'>Ï‚¾â��>Æ÷W=$Þd¾4 ú½ä¼]C^¾°Jžúp$>ª,˾¢Ãy»|3 ¾ïÅ’¾k‡¾÷'>J\<5w/½™�¶¼°Y8¿Å¯¬¾4ª®;¹ÁË=)3‰>áJA½J¹=$q»·a€¾@˜T>Vû¦¾€Ô€=ÓϼÉ,>´X9>ê…½(•~¾G„‘¾…Dé=ˆa¾ûÑ€½jó\=°õ˜¾�C�>†É>‘Ä>å¢>‚cð>è¥ñ>‰%·¼¾Œ§"è™›¾Åp >S&æ½JíV>d„é½ðx=RS®==L>Á<à>E!¿½n»À=²»8>ÝB¾Z\;øˆÃ=¦6Š=Sð$>lÄÒ¾@wÅ>°<¾9gl=¶)É>zŽŽ¾Éj#>÷ƒz¾÷�¾é¸‘½XëO¾ãåô<r¾ˆ V¾õ+‹=< ¾FuÐ<0>†ci>È>)=¬¾úBÄ=fIú=Eß²½ß1ð¼ =3Ù=¶ >êT¾Ý•½Ü%&½? C=Ñ‹§=¨a–=Í載ÄÛ:ÙÔľz™=¾ào >›>±±6¾œë)>˜.>j~™>‹>_ÙŽ¾åå¾ÔL¾Â޾ý+à=—�X½†ÛŽ>|õÇBM½ð’C>GÀ7<®Q�>nSv=–å.½±Á&>#$ð¼�Q€½vnç¼ñͦ> >¿=‡0@½ù->64Ö>jq<‚3¹=. -½‹6?>y$¾ûÆ ¾ d&>ž]Ó<8í̽͹­=¶~`¾"Dù½`H¾Báà=@öN=béº�ËI½6ŸM»™yp>ïU”>¥d´¾]m½>J½§çH¾ç¾1¾üf¾ˆ‹¾ÂX¼ª6q>Åk~=eð¾D<¾Ë$™½vR>q“{=‡•�>ÏÀ¾Þ€’>âæ<ˆô½ÇÒ’¾�,¸½µlL>¿±H>k-h=vIð>2ò>D¸¾ Ǹ>Ž»G¾ž>”Ú\>ÔÀ=V’\=dê­¾×9°¾¸¾Á{6½vi>Œ’Y>!]ê¾üÊоx>ͽQ)>É㋽Ž„>&Q‰=.ýÑ;8[‘½kàͼ6Ý�>Ì‚+>«i]½(à¹,ì—½µÝâ¾ïã@¾ˆA>5S>ÉL½Ø3ü=¡¾¼­#|=î%;>Bãð»ôœ=Ê8A=¢(²½3]T¾’µü½zPa>öȽò©É=A¡¯<<ûÿ½>ÖJ¾èʘ¾`͘¾†Ç¼-ñ+<Ãû�>ÝY’>!”>š·½Mx->¼™Ÿ½¢w0>>tÕ•¾y ‘=”ï¾ýœ…½8®½'¾˜>ñ5=×sü=P¬U>½r>íå–½(U>é@,>v=àö>O×ù=ÀÚ=¥´¾æ&"¾#(†>}@�=Ë[b;õ>U—8½¾Kq>M�¨¾úxÂ<„ùÒ½IÑû>Ç…º=w·=�V>ó­¬=Ñóa>\¿!¾q6½Ö»÷ÞK<ìؾœ(¿¾®›=ýHG>k™>Ö®l= ,¿Ÿ~»:wÂ$¾Ï})ž=máƒ=^w©½úO ¾8¦>º˜¢½Ú�œ>3Z¨¾MA>4kKºÔ—¾8Yn½‰=Ž>;Óg=×|´¼Ä)“>-ðQ>é ?ýq¾cë¸<µË=CÓ=xô%>›=uå”>�°>«t±¾…>ˆµ?=ý(,¾c¥q9úM½O_7>/÷Ô="¼†¾} 3¾ßÌ>Ž+­<Ã9}¾ˆã¾§Ús<,pC¾O?z>Γ§>«^›=S¬>}ì,<µÆƒ>Õ“ù=Ï–€¾*B5 ?…“M=#¤È¾¿#¿.ƒ9½sßÐ>jóO¾Ü]¾®o‚½œsоcœL¾Ø”R=ãå=ß·O>&¡¾½d¶½E¾ `I¾5ꈽ4¼iò=±ùå=—]1¾ãÒê¼×CŽ= ? >T¡¼Ÿëܽ@|â=qæM>LY=F7Œ¾øà1¾At¾I>']¾¯/>8Ç*>­_¾½³ >šã‚>6Tˆ¾T×>dT‡>¢!¨¾ÆÈ²¾»2½e¯Ø=Oo>ä�=44ɽùO£>�§> ªÃ=(Û¼ËÜa=$¾å;‹¶5¾ïÞw½eÌ >²ƒ¾'›>Õá�;êgZ>ˆä™=KÆÓ=ò›=µÛÅ>G>¾ü¯>‚;>¼i ¼¿�„=ÍäŒ>ÍøÄ>9ò�>RÄ=æ�Ç>îÒ¥½.]=é† ¾ ß³<6=dS¯¼£³Ô>hŽ¡>Igg>Š$=K.ª½Ìÿ¾üÍz<±p$¾ÅmË=›½£� >šá¡<>}‹<¦]p;nù–= ­m½š›�½Z3C>ySν¤†,½£ó¾”¶�¾‰Çƒ½ƒ%Ô=XåY>ê‰Ñ»Ü±¹=H|=õ7D¾Ã‘;o¾š;³Q"½~ =!„óº“n±<`U¨>¢Ò�½ÛËþ½&]¾äÓ‘¾ÉÓ¾7â³½-I™>ݺZ=ËÈ`½Ñîë=ÃÜž>B~>±¤Ë>®ï¼1ჼ«¬Ë½,vÓ¼¡Çk¾ŠR™½ÜGø½È<¼k™=ãEÕ= '®½*Þð¼ù %½ùñH>°í�¾´j_¾½¯'=˜=>˯5½ØgÞ=K£˜>ÑË>4�b¾ƒ0„¾ R=ð«v>[(<t¾„ÒM=| õ¾¿ r¾U)>£;>Âþľ“Þ¾¬ä¾åSº½gjo<û¯,»ÉÐ>A¼ö=0ÍÀ=¹¨ ¾½ƒ½Æ 3¾sYJ½0ý!>,µ>}ûK½Yƒ >ZÙô=N¥½ æ<¾(½2¾à§>˜YG¾—׃=8*“>�çb¾ú”²½ÆI<S¼o¡3¾)Ü>#‰„½ñ >,©Í¼¸î¼�Խ㵗=Õì„>RIH=Jõ =9y•¾wâ¾Èÿ@¾]D¼¡‰õ½ÄÕ>Ï»ð½[G=j¢=ù“M>kŠ>½ÆÁ=8#=z±¿=5 5>V>ÓR[¾–(^b>\>Y¾�l>)™>ÐÁô=2Y¢¾¾÷V<Ÿwã½vÅ©¾Œ£)>}Ž%=< Ã>Ò(¾Ä3C=!2²» EŸ>þ  >bˆe¾±A>¿* ¿©üª=Öä1¾�GW½†øg=[ ü<Ÿ ‹<'̰½”Þ=à¶½ÉQ>SZs=hD¾y ¯=WU�¾MPÆ=ÿ!œ¾Uø½ìÞ゚a/¾@t>z�À½?)%¼³¾Râ®>”M=R¾:¾2nRMAƒ=B’ˆ>Xp>´ÿ3>Ë>l$>¦í@=,>üá8>¹í>3ÞŒ>ß„(¾šõª=ãü¾”Ø>ø.=ÆÞ=CÝ;>K–½=Ä+¾(Ñ=jG½n2L:»ù¼ðëÑ=-�<ªé\¼ð从½¾Ü(Ü>Ã�‰¾¸ ϽlP6¾ x½³º½úî6>:­—>¡el¾�ˆ·<âé°=‹Ú�¾X'®<©Ú̽6´¤>ü½�Ò=H……>Qa�>ÿÓP>²¾4½44¥¼Ñ|˜¼@ª=ÄÏ?ÇÜn>áde=D´8½½ƒõ½´;ä¾Ê¸Ç¼“‹½Š_[>°�¾}ÉP>Ÿg9> +}¾ù×À=ç>þê*�½x|=.B¾ ÖÛ¾gãË>s»‹¾ ]h>¤öp=ÑK™¾®é=½¬ñ‚>²¼o=Y]½# ¾Œ^Š>žö�½/½wW">ËíI½ÈÖë=¾=Î>Ù^b½âŽ->*#Ä>¦âà=“­¼½ƒh ¾{7t½MgM¼¢U&¾Íqt>¤vK¾i™í½¿B¡>”d+¾ãt½†8t=Ѱ=ýmN¾´)>í¦L½ð÷£¾ æ¾`‘¾ÎÑm½]óq¾éjA¾í ½�©´½Ë|�<(…¬=?«—¾•ǾGó‡>_? ¾î½öm¾¥ü=&ÿ¤¼}`”¾?±¾LÀ.¼âW”¾ ˆ�¾ÖPâ¾^ŸN>«¶1<à\à½öaŠ>éç¯>;Ò‹=ï'¸= =)p�¾5ãµ>�â7½Ã¬ =A?í>õ²³>óä³úâ3¾y� >€Bˆ¾f¬…>½=mR¹=àq½¥eô>®¤*?…½¾e¢ž=]V>mÒ’>EPÖ¾>äèÞ=@T¯½õŒ+>¥>b¾â9=¨ Ý>=ˆ ¾ža¾%ù‹½7Nv½Óç„=ëDú=ä4Ÿ=Q©Ü=gÕ'>/Øš>0ÜÝ>åÐ]¾õû|>ùÔ>€¾�ñ´>È�€¼®%»½|ð�>pSz<+¥>÷ Š½1%>½Ž<·<½Ð >8*�¾Y‘<>Îïá<$â¾/ œ¾FÐ<W×>¦Ð¯>8྽’¾Äû=‰âƼ¥6>v17=›m®¾Ù‘I>î­Ñ½'A�>Œä>€ži¾³y¾Òp>9,u½…L„= ®¾Ølð½,z,¾²¸j=ÑÓ‘=P€à>áë1¾½Ü6¼p½¾»‰‘'ÇÁ€¾óŒ’¾ ¾½×?=�oK=·¾~=ü¾øU2¾»EG>Jgi¾}7w<þ© ¾ð°[>¢�´>“sí<„û²¾•˜¾o‡=T\–½Û�ݽìéð¾—51¾yû>½ þ€¾ü�+½«Ž=fE™=Ç|­>õ%==Çãн#¶¥<¸¤Ž½t×A¾92^>T·=Ui㾦›»è§½ Z>¼¶¢¼Þt½¼¼m#>+"¿Ð¾(XG½ðq½wÿÙ½©¾ºw½X ½Cäô=^0£¾?Ÿ¥¾7š½ŽˆÀ½ö•μ W>¥kF>~æ”=„;œ¼Zæ�½íê­½kå>äÄ?𙾉ˆ >+ɾ̽ šc>vaA>¾\D>ñUü½äjL=pÅ=~9K>È×ç>Ä‹ò<ñãϽ•w@¾n‡#=`-ï=¤ý¹½œí½^X ¾WÈ>Í�;>Л>»¢Y;´ís¾šÐ<‚µ=Eñt>ðO‡¾GÎá¼D€*=žwü½r…=ž?ÍI>ûs´¾[w]<›@%>¯=í=k>}¾½à%Y¾¯ô™=†+¾½v®¾ÁCa¾ml›=æ‡x>9G?>|”¥=Å B¾3¦¡>ŠyC½Q@·>-Òò½×Œ/>y›¾¾¬�>6e/¾ 5¿¼Ѝ=›i¾õY¾+Pg¾cK3¿¿è¾jü4>ïç\½áOE¾pž¾{ƒ=]²´¾ttp=ág!¾Š‘T½˜ÚÞ=.7->¨ƒ½Ø�>”÷�>ÄN >À¯>ß$=o$ˆ¾ ½>N‡í½™�‹>0Mþ½X4¡>«ñ¾vz >ÞŽ>ù§Q¾¨@¥>ïI>úŽ=AȾKŽ+ö¾ZG>º”‹=‡(‘¼…òI<øJQ=ü?à%:½s)`¾¢]4¾iÐ%=ß^W< ï<Ö¸>·D«<„Oï½Ö¡Ñ¼ý( <¶»µ”E¾ó¯¹½†·µ¾Øš¾¶™Œ¾“Í=ÿùK¾^ñ>''Ù;èõ)>�7â¾È슽a Ö<©’4>PÊh>–ß�½<â�>hÄb½×ã´>›L?Œí<âÌ¡>©"s½ I>2á¼ø¾Ø€÷½2 >�͸¾šúô<"6v?�‘/½¾·½bõ;¾žük½eމ¾:¶=ˆ×#¾u„S<\B¾�D�½‘mt½õ—E½sj¦½³²j½ŽžŠ>¾„È<œÏ>Ÿʼçßp¾’’¾ÈZ>öŽƒ¾V£á=› ‘¾Öc›»T-¬>©&‡>m“¾¿O=6 >³ f¾ +”½kƒ‰¾O`�¾˜Š½h®+½õ×Ǽ6j°=Eìg>f»>våf>#I>£ˆ(¾M÷ݽßX=ï²¼_Áª½ÌŒ¾õ!+>n·8¾›™>CŠª>”¿=<æ&{¾f »=uó:¾5ž=¾!AȽÿ�ž;z®!=´Nç=×Ué:`f…¾×ié½e¿?­·½Ô•=ö52>£Æa¼Ù¬=ùêÊ=WðEºµÁ—>ùz>ie¾vœ½KT§½® ú=1A:>ÌŸ‰¾/SR=ϧg¾ž¼R=2zr>k¼¾&^ñ½b2ì=ßDö<•1;¾Éuó=ë¢kºÇ¾Ès¾xÚ£½Œc=1�;ô¯n=´O±¾PQÇ>õ?Š>³\E¾rV<¾ f´¾ö#¢=]Ñ:¾0UÓ>¹µa½y >惋½ìßó½Û¿¤=36¬>)¨›=„D>°“ª¾µy¹>_ÓÅ=\¯p½ ‡Ö½Ï„à½�4¤>O$.>}‰u>�gØ>‚Ât¾`k¨>Ýü >Ýô?5ˆà½r[Q¾²�S>Ò½½a«¤=Œu0½¾Ü˜>‡;ç¾[‹ˆ¾öS—½¤g¾í;‘¾©£!¾7üf>zXq>œ`ˆ¾èä >KÆû½‡%é½—€ª>k霽íôc>– h>VÎ?=f6:¾óö콿Ä=õèÚ=áx%>ù>Ô!½Ô|½LQ>?9> ég¾A¾Ó=6j‰>@†Ì<ž¤>‹ÏS¾ãؽ¦Ú>—õ:¾ ì÷¼x‡>(  ¾¡ð¦¾D>:®[¾ƒ€¯¾@ø>>–g½Ç¹¿«¿ >ÑP¡¼bùÅ=ƒ~½jsu¾ówú=>íͽeN½”n=ì-=£¸$=çU5>Ʊè½FE>ó÷Z>Ë#޽éÏi¼_˜Û=Kb`=,˜?÷¼ß[>à’½)l«=`G�>,œ¾o†Á>Á>I½)%'>hÆ£=ÉBоp¡l¾`ûŽ>JÎ{>ÚU¤>…½Îö¸½CÙŠ>š8J=þ‡Ã¼y컽#˜¾å¼;ÑËo=v@¿¤F¾&u5>zò>™`O½Ó3k½†6¾¥ǽÑ�<ì¹>ô¿w=ÇWˆ>Êr9¾g¿G¾ÂMŽÀ�½ºŒ†>Æø£¼±u/=Ik�¾&±ä½°Ý¾©½¡+‡¾I”‡¾öÔ¼–-–¾›sG½jm­¾ÑP¾˜;>YK$>–2}=;�ù¼À¯>{,½Ð¸™¾:†�>Ú6û¼ô¾ôx°½êKÔ=tòn¾ÀÎï½~rF¾A˾÷�>S†.½¥I=Qä3¾¿ã¾4š(¾ •<>'å™=n=‰>Š<>°�¾IÉÌ>÷£1>QÖ¢<ŸæW>‘ÛJ¾n!~=M¼ð=h>q½¢b˜>-º*>ú� ½%š½Dü$¾vн ¾td.> Ý�>î`¾?ÐŽ¾ù=im:>fh¾ñ,>àáS½ì=F=i²> ŸÝ½< º½ã— >�Å>øG™=ûke½öà’¾6÷=)ºÃ½Ï¥1>ŒZ ¾n¾-­Ý>-~�¾¹W ¾A××½“ú=˜ ª¾:>Ó¾o¶F=Xެ½e@s=£f=ÒHT¾ñ›ºÐ‰0>Gvz¾#!„>Ê`/¾ÏýT�b�×=ØX½Õ„ݽ:éݾ�(¾š¾Åµ“½ªÈ¾¤si>ZÖ«=éj>>ÓÊž>tu>žk1¾$ô.>O†³¾ªǾі+>§f ¾n#„¼ú[>Åe>Ù‡¾:¾”k¾(Ãg>?Û?ÄN>¾PbÁ¾¢Æ�>xQJ<[9²>m>gÄžE>÷¾¢ñŒ¾¿ ¾8gͽM¾¬Dt¾0Ú?>½7ï<ú+þ=|ê<寧«Ô=¯">iä_¼<&§½ãõ¾û:>Òã½Øîл»N>1^l>|æ½{n6¾¹¦C=†·£>Î_ƒ¾÷jN>’S¾ÍwN>ù̾Ì*`¾Ó)*½�ŠB>Så">ˆ7Žî«ä¾§E�½S>©ˆŽ>ë[Ê=Û³Œ>Ú˜Þ¼)Á>rEÞ½î1 ½†â-¾Cµ¾”‹u½{Ó=ëå=�¥>d ¾kÎ¥>V>Ä� ¾(zÓ¼Ç0Œ½Zu²><>“~T>ˆˆÖ¾o=†RĽaé>|é:;”A¾o±º>ñ¾_>^³>¶�~½×°I½¬êµ¾’ƶ»kC½Y‘½ŒÞ¼Uμ!ji¾Ns ¿­µS¾¨ž®½·ˆ¼$GR= k–>õk&>|Ý|¾»†=*±‰:ýi“=ÚG‹=µ>éÙ>„N> Ço>¾¸>jîT> ×4>–º“½Ï—7>sD>͘Ç=¤ Í>¿®B<”˜Õ½cÖϽފ|>�ïN¾{Ðw>?Y½»$Ó¼_Å‹½ù*—=^m>›€u¾¯a¾*õÏ=Îä-<}Ò×=%/¦<Š‹Ò=h¹-=›ÞA½p¾âNÀ>Ô}Á>oáÎ= ˆ€¾-Zœ¾°v>M�¾ZˆJ>µRT½Báé¾AŸ”>.>>=£’» J¨»$¡.=®g>qÑ¿�9¸¼í¾š­�½Dd|=ˆðܼ1þµ>θe>º|½t.–>��²> *½>2嫾û}³>XÖi=€iL»ë»B¾En©½å@=b�нØ�¾ Àý  >™Ô\>S/'>zÁ¿=¥â;¾‘᩾ˆÔo½—{5¾ðÜ�¼N3¾>ñK>¾nx>¤ò¿=hã=£É¾7!:>¸œF>7Y¼3áo½“³ >#œj>89]>(nË=@VÌ>¸¸³¼v‘𾉵�>ÌCľd ¾Ñö#¾(>¬Á¾lò‹¾ÄB¾Mt¾[J§½¹Ñð;T ¾Mh”¾zûù½ü¶ª¾ b¹=â¿®¾‰ê³>X8>'Ñé½µ`=>a±=Ÿ>=b_†½ÞWw>¤@Â=ñd=¾Ý;¾X¾ØG>2ú<³¨c>¯±ë½°xº>ÔÁ]>ÔŸA¾ðÒ>ã�%>ÆG> ñu>‚Ò„¼1s>W˜’>tUd½ìûR¾ói¼rKè½A;a>_&ĽòFJ>ö .>AξrŸ¾”û6¾Çof>Ä>ؽ«K¾œPZ>¬Õ½‹Ec©Ð¾(bU¾ V·½œr�>4>½¯v> Â =ÑJ6=–•A>X;è=`Xæ=ø>Âm¾!“x>YÏ=<û€¾–!2=½Õ¾ZÖ´>,!¾òÞL½ç»[½ßÉ;Np&>W@¾t7-¾€¾ðè‰>o-3¾1|õ=ÞÍZ¾{Ò^½h\Ò>Óc=¾âò>¦Y™>ÇI¦>ö¥W>“€¾c…¾½™)¾YîÀ½TåK¾&œ½Z�U½-,N½Ø½ös.=Ͼñý@¼Ü)ù=NU—< S4>´]±=‰ÎZ>¿!ß½5–>NоhÌ’¶íŽ=Ñü=•:Ÿ¾D5*¾£Ç ¾iÔ&¼f¯¦¾¶lŸ=BNt¼îv'½/ H¾%n{¾„ÿÕ½É >#™R=P=)I²"GÚ=�ô>Ÿ›,½¿²ô=�òS>½Å@¾?ùÝ=L§½kéо7XV>†¯>Aûq>`¸?uG ¼ˆÏ¾b§#½@s®½¯=×½+\.¾Ÿ ±½j+Œ>ìΕ<›Ûþ=òa)=NÁÞ¼?%Ô=;(…½L4£½xºº<D\>Àb>^Ë·=à®ã½õ°ö½#p>.…>=€"¾€e}>Y•y=å†"¾]6ƒ¾FØÅ¾âš!½É›»ƒG=¡�A¾;™½¿EC¾Åw=¾6š=—Z¼>êø:½„=};=_©…½ôcÖ='¡@¼lô ½²ý*=v즽ëöù=Ħy=ö“>Nà ¾ §D½.D¾`ѨK½<÷·bd½”y2>Ö•¾úi¾n ‡¾Í>LôC=Iä{¾cOí=1Ì•=)ýe¾à:W>ÿ”¨¼É×Ê=÷ŽÏ=ÓVŒ>”q³½‡ =ª‚Ÿ=ÃéV½ã�„>Ú$B¾5Ô>ŽÈ,=ÎA„:9q£=Ú(R½y¼¿¯�¾t)†¾FÍ=”=ýã=¦©„> ,i¾¯ ñ>8?K<0(¾Ë2¾PÇ>µÉ¾6¼X=›°N>ji]¼§§Ä½iÁÂ=;̾ƒ¨´¾òñ·=n¥a=Ò¶œ>—å‰>ï ¥>o92< ¼½%BÔ>3>½Ý÷½œÖ½0©Ž½ç‡¾Û‚¼Uø>óïØ¾$C½%CŒ½þÜM>¸À=‘§L½� ¾l`-¾!‡-=:¢ ¿¹ã-<㌓>¼š¾·¹=°V¯½Fά½ƒ<,Íœ=æ¦ãº©›´<º*gº°Äz½cí�>LÈì<ú/j>üZ>«M×>¶KÖ>Q�=ÑZY=«¥¤>²=²üսݑ>¾† =²OŸ¾£©4¾0^>�Z‰=Í€9>àV„¾õ>ˆ>jàª>ˆ’õ=J{D¾Hhc=¯> ˆ–>k{¾í×=eø,¾øßÿ=‚²P¾fO[¾5kö¼Ö¾aÜÓ½@7—>¢ÐJ½ã-P¼Zo"¾²¢¹¾dU‹½i¶Û¼É.§½µ{¾JK·=Ég]¾o#½êͤ>ul¾uéF½Î™;¾D¢§>åx¾y ¶>H&¾»ÖŒ>á¶=[§D>=G¾”ñ£¾ £›¾sT>¾a4¼LB>“û»÷Ì�½ ��¾‡Û=0æ7>Å�r¾èâ…¾Nó±¼èÌ3>æT¾ö²i>«O½PP =xÑH=c)9§§¢>[U‡=}¨¾2­¾Jô ¾Û¡>L t½IªÔ½ ޽Ã~>8>d_Ö:ºŸ>.Ÿ¿% æ¾ Z±¼¡…Çv†É½Âû=®`w<�¹Š>Q­>ð ¾-Ù罈öоb¤½9~v½F޶>j0¾ä»½ðo¸»ˆÂ½Nw‡½:¼¤Šì¼Ô/½saJ¾ì‘@½>w>-\Ý»W´c¾�@b½e{ľwC¿=�R̽†FL< µK¾6]‰>¾±Ó>¡›¨=.”%½y¶h¾¤Jî<S>s!ô½Ç/½ù6B½GTF¾\†C>…ÓE¾Éc-¾–’ÿ½|ÿÚ¾bs_>7¶Y½½>t«¸>Ú#Ò<ͺ= [{=S=¯¼¦úã>)3¾=¼6ŠX¾#Ф>=Ï$=‚°ß<{m>�˜¾gª˜>P‰¾a§>bÒ½¹Èž&3¿=‚]¼uz)¾S Ë»—Â=9 "=â®&¾þbÌ=)¸¿²�4;ͻ½�1Ÿ<Ãôy½ä¢¾ ž½½?¾�ˆ=—¸Õ=¬*2>ýX¤¾µv ¾S=< ²>ˆGX¾"â@¾I«K¼MÀV=¦¯:Rн÷£�¾ûŸ>�]>8ÛB¾ìüW¾åÜ¥= ÓO¾<0Æ=”‹½•’¾<>È9ú½Xþm:·46¾�BÖ¼›Î•¼¾X¿-œ>·¶p>=B½7¸L>rY>ÖV€>^Ð>ö›ƒ>vÚ÷¼lt`½u¼Œ>"u>Àêû½àc»=ªq7¼5ʾï„-¾¥·ˆ¾¶k®½7»²¼ˆÐo½ƒ�—=Æ2G¼‰ôò½5€A¾EY\=êr´=ß– >‡²½d¦q¾Šù­>8Æ^¾ T>µì&¾õ®�¼£M@¾˜Æ®¾¾f’¾mn'¾³Ý�=þÄB¾5$>H ©¼‹‡P½°‚ ¾ Ów=C>âñ¤½&ø<êÖK½äëv=5Ƙ>ûÙŽÜÚÈ<"�ñ<þÓZ<ÎØã¼³i<•t>B‚F¾lÏŠ>±�·¾æ¯™=²Á¿½>ML>¸¤Ü½Åõƒ>K8Q¾<ÒØ½­?¾Å4=Êz¾‡é]=Þ f>3{½Dì2¾š��½ŽÄu¼pQ=§HJ=²þ�=$ô¾Í‚¾\²z½*[!½» ³>VtB>F¶Ò½) ˆ=º&;>Aî�½úÅ=ÏÚ>l€:QÌ>:Ûg¾m)ľèD¼o-Q½ÎXF= ;ɽ8ƒÏ=ÊÙ¾œ�®>R>=lŽ>â¼�Ⱦ唾YLí=bd;=bá¾¾>zEdQ”½cÔ‹½c…›<]#Ö=¶~\¾' ´½»Î'¾]Š<ÑbA>oEˆ½�àÓ=Ž%>—õœ¾ÙˆV<<¨>ø@S>ŸrG>hÿ=Sr>®È¾8­�;÷àx>Shy=bÅO½¨íª½@9�>Š\V=Må?<;7w¾Õ¾6¾ žl=¼ž=à°6½³q�>åïŽ>+¾z>N†¾%�>¾*>¼j2»0Mp¼ð냾|̾5–¡¾ ú$¾Cn‚=âìs¾•ê=E(ؽúUá½äÒÕ>¬6‚<9Ü.=$Jg>3;o¾Û Ð<‡ä)>R¸=ܱ¾É%>è«T>û•M¾6ðä>à޹Ãñö=†#¾{ ¾ F´¼’mJ½SÑ}=‚¾d–'¾¶½'`u>nS¾ÿª?ùìà=øN%¾XR0½ˆË•>r_¼¥Œ¤½¬[½¤>©Ÿ€½›¿Ú=7ýW>ü1¾Y@�¾þD¡¾ÆTo¾ôv@=À¨¾ó@>x)8>ê²=ëØJ=Zòœ>½„>›>ò2­½›l@½QÄC>!Æ¿t >ŸÒ¿½¯Dö>õ¿�=Z’*=F0¿pß">Ï+ª>�$¿êw¾  ~=ð¢-¾­ˆà½¦Zˆ=Òf\=¥Aˆ>¾àÎ=s"ʽ^{¼¼Ä8]=ѧ+>¬<лy®¾æÙ·=•µ˜<ž¡s½è„e>ñ£/¾b˜—½Nãµ½W¼ð¾® o>ì>še¾«�¥<ü(̽Ë[`>$Û9¾[ºQ=‘–à»`N=�FÞ t#>ªw2>F"¾¸]¹¾8£¿¾mY¾ñˆ>“‚¾R ê=œ¼>öàY>2è2>ýª°=®C¾ÙØÊ½Rz°>ÑŽ>,–>=…Ò¾½åß¼ïÀ½7w>EQ¾¤C^¾„°†½Ð^â½M¬’>Ï‘ÿ¼Ø€½÷°…¾³èϾ%>Ù=“4ˆ>ƒþè½Û,+½*˜È¾¾¾ÇnÌ=`>ƒD¡¾G�;=Lîí=P Ï¼Ø�F=ÅÏ>±|¾¨ì�½Ã‰¡½�ßC=“½yÒ:¾õÞÛ>¦.¾¾[Öw¾�•¥n¼HhÖ=éŽT>�_½tÌœ¾_l:=SÉûôã=Ö …¼Qé\=éø=Ï+¶½i‰ >à�¿ÆR½«½Â=ž?–¾�hìÝA�:â7ù¼É£ž¾Ç B½>–¼U„’=¿ >=Íÿª½¼—ò¼Q¥½qñ³=i3:>„@½ÜÄ“=jȶ½ëª==ê_>Þ>Ð�t½f =b¾ÔlE¾<…(>¨Ë ¾nRe¾/‰>¬—Ë=?ÿ²¾õ ¼=Ôâq¾ÝB„>Ù@ä¾TG>²ÓŸ>ÜT>%Ň>ˉ–<÷?ó¾«n½ƒÛ8>Ë1«¾òÉ‚¾â³Á½züp¾—ÆŽ>zG«½ÏÂ)¾Öª½’È)>ç¨Ü=)lS>1È¿'K™;æf´=7 …=©|¼1«¾àcN>ZÕ>¼µ>-Ï]¼ø m¾ïõ>ÌŽ¥¾-’W>tÇ¡=TÁp=VOQ¼SXñºe0‚¾‘á½äï"=mô¦> U>½t'R>¯Ê¾>CÙ¡½{.½yÔå¼Â£z¼ ú½´¾J½…M¾Æ[«½p»¼2·§=TN2½ ê£>@æ9¾AW¾Ð˜Z¾éJ¾<°¼Bʾ§›W¾ 7™½]¨¯> Àš¾oß>䆛¾0ˆ½�~=Ƥ>@SL=Ìi¢=ÚüK>vPN>&2¢¾„¿>@*5¾¥½Ý >™Ù�=]7>:÷½;ØZ½21>­"‹=gü¤=¤Ü>{>n°>>Ñÿ½ÿÃk>˜-x>nœ£½ó߆<êA½úô=úo;¼£!z> X�>Š3_¼Hxξ¯Â±¾6 ¾¯6(¾UJ!¾U?޽˜¬)=´î;– º½P—’½l¢,>�òY>Iã>Þr¡>Ú=r½éÏ…½C¹‰½ì¦c¾~zô>ùs=þñ>â>À<àžž¾7Ýž½ºü>~lß>½TÔ½*¾�m²¾E¤;>å¾bô3½Ý4u½Z ¾À*¢¾Ë)Ó¼i™ó<W�=sDK>û ½lL >IXã>&�¤¾WÕ?°ù<<ͼ!¾&>Û‹¾•f½14¾ hF>ø‚c>:u"<Çð7UÕ;=8`;¥�>ÈtŽ>;)ý£ï"¾.Ⱦ¶¼�> ê=uш¾,@º¾D®«½¹±^¼\¾ôÍ:Z^D>Ov…½Øí“<º#¾¼Õ$—¾Òßš¾¯H>*Žø½¾=ÎYš>¸ç›=�-f>¤é-<™vm½y·|½‡^C>ö<&¾¹Q³=aò?½À­›½í'©½€|>#•Û>a§›=á½Øn–¾º×#>À•>¸Q¾;8=>k?>`¾âŽC½fƒ>ãf“¾jtû½HNß;³r=‡°i> ø¾¾]‡¾”ðö¼Ý >^¾¯¾oÚA½!w=è£ ½Ì„¾ú&B¾Ž>é¾éŒO �A=îM$½Èpô=†Š=�ú1¾3´¾Ê-£>ª«E>wH“>kÚÔ;M=ª=0å<䨑¾âv¥¾¦=®¼ÝÒt½ª82½÷Bq¾Š¤“=wH¾óz”½Õù8¾ËI¾ó³½9‰%¼`C¾ƒºÛ¼POo½Bl¾br >SƱ3±>0ýò=¶_ì¼ÇÔ>‘˜>‡ü¢=�ž¼:�¼Vo~½`D>ê¤?»Œ¿¹þ®>ù˜»ÊJ�øÞù½"gĽ>ÝN½>ÒŒ¼å`<Ý,˜½†É%>=¦½™(‘<¢un¾®M‰¾x:k=“Â>ð^Ç>þ‚ó½ ‚¾>�Ó£=¸�ô=(¿>þäG>v o=—Fò>Y¦<½×½¾°Ë¾ Ô={Ô½�$=Ì㑽2{é< &=Øât=–8‘<çåZ¾­0½>ZA)=Á—Þ=!”6½½Xa¾Û¨¾ƒi¼(¦>?><>ºçÑ=0¿á± >®ù¼«“> hƒ=0>�l&>Òþã½ôK³¾¥P> Λ> :8>A¿M¾5>Œo>NA><ºÑ¼éªJ>¢P¾m >íy¿QW’½p|½jêÉ=±$ù=šÉŽ>5Y,½ïÈ>pr°¾šø¬=Îth=ñ@>nD�½À¾—–0¾îî=¯ƒ>è9‰¾•˜¤>bÈn>�y¤>Æ}Ö>ÀÀ¾)íx¾õëË=^´u¾O€(>² >¨W=u1 ¾Fõ¸¾ ÎT¾�Î > @‘½¡c[>û½V¾1‘=>š¾âf½6/ö½BN>ë@�½È71=s¯½a‰×=ÑÕº¼HÊ¢¼ªëÛ¼‡ß9>b_œ½6�?;M�¾€ßœ=<ÔѽÁg€>ªÁˆ»ìʹ¼�¡ß=g/ž½�•¾©P›¼–—å¾Ü*&¾n» ¾�/l>éòÈN¥l¼$G=¼¾f³Ü=�¤ÿ½)—‹=…/—;ÓX¶=?Q½Z>�'Z>ij‘>G4½¾Dã#¾¥9¥>Ì÷>éw6" *>^•^>¤pj½üD¾ßvŒ¾Êég=0">‚½4½éb >À—¨¾×�˜<7SоŸŽüŒÇ¼‚2»�5ò½±½ö+a¾Œ®>ª?>2ÿÿ=‘<>⻸½Pmû8¢k‚=¡•R¾Åžʪ†½ˆ‚y¾|ÇZ¾DT˜¿Ÿ>”ÛD>ïîå;{88>qùýY·O=;j7¾Á“=öÌ:>Åkñ½þʹ=Ó"Ø=p( ¾>y³¾º¾ò=ß7>k—>×ã:>ˆÄz=‰2L<‚;¾-´>b0)½xh‚=Û�.>Ul*¾¥j>Ib=›]ä½3“G>.Gú½Šw>Í`(¾8„G=cÀ¾…W=½Ú¼ÈNö=3Á?-°¿w®¿¼=©I>µã’½|A’=-¹¾2e >þTL»Ð]ô=¥é0>e@¾X2¾ú+o¾sƒ >Þ‘>WtÞ>+yA¾{½>¾Ü:{=Cl=/;;e˜Ý=çO ¾ºÔ�¾%€‚=15�>K ¼>Cšv¾ÛÁ…¾ ¾°Lf>q�¿=½"`¾OÃ">UA#¾›É�>¹pR?^]…½S{Œ½hi“¾1€»$翼îô®¾å!޾5³<¹e]½\Î=ƒ]9¾Àð;“M*¾ÜòE¾»ü=)¾‚½Êm>®2>îÓ¾]ÄË<ê~‘<ظ¾�$ñ½Uÿ?®¢=¤ß3=ç<½¯¿Â>i¾øU¡¾è•Î;OtÀ¾”ZF½„Qx¾b<È=Ït <0¼ê¾·²Ì=dñ;Þ4i=³Üñ=.´…="�ê=ôR³¾4Ü={v�¾ù—Ô½HpV>ÖÆ¾XT>0GZ¾ðR½é¢€¾ùû�;:›ð>;ʆ>5æ¾yÔ½„&ë>‡@Å=Aäÿ<ƒº¾ 3~>MU¨=ZÌË>8¬¤>0s=Mze¾ƒŽ>qµ> ¥t>W¾m–[¾»«½9—°¼½škF½˜P=4ú>;Ö#½þªœ>ð‘Ⱦ=ˆZ>w,è=>òt½ú*=øñ¼X'ï>‘»_O«>œL�=Ö¦½´Âq>ÖÙ6=Z�¿ýÆL=³˜Ù=Œ4¾p"c¾��¾Ép=XòÖ½»¾Ÿ* ¾5Ò¾tªd>Zè>¸~?_Œ¾ã¾äI>üðS½Öð·=˜(£¾*OU>"Á¾½àR«¾þ2Ý=KŸ½$ °>•7ɽa¾1>ÿ5˜=|{¾mIݾ]ïä=ÛÜ<=”¾6=wâ=ÜŒM¾úÿ"m>tse½Žb¾‚=²ÃX=¯îr=“X�½Ãþ<Æ›¨¾ˆÅF>2J̾e>R> 6:¾X©Ä=„è¢=.f±>¼#¾˜µÍ¾Áq`¾Æ¨Q=8¿©¾GŒ =?a >­<,¾½Ë½ TùºG}'>¬G¬½¡Ú>¢ø>J9…¾£³ï»žÕˆ½Èäš½ŒÈ>’Ec>• =™0?wº·>âŠó½J_‰>—)¿x—ò¾¤Jo½Ñn>‹>ƒÝ_>[!¾9u;¾2P‡=mw½T/�>Ѹ=*3¿¸=ô½©$t> Z5¼i €¾+E[=Jíq=&é9¾Çƒ¯» @¯¸"ã½ è¡=¶ìú>˜«>šAt=àó‘½VŸˆ¾‰R#½ëþÞ>Σ¾»îGú=tϽb0’¼ÿ6€½J¶5>»p5>ùÈd>TÕj>Âsƒ>àÿϾ~�=õv=¶‘T>Ÿ‘½/¼´¾8>BÚ�>õG¾²H‹¾Ü¾j§½•�>‘šè½sI>þÌ©=JÆZ½C¢¼<^/„¾&]C>Rû¾Xëó½-¸®½mD¶¾â}W<:h@=’-罸×½�mr=ÑXÀ=ëö×¾òL?¸’=s°z½<ÝS>Iû½LŒµ>TЪº+žq>Í^ˆ¾ê±j¼/•>Æå½TëÊ>3c>çrν¢ž˜¾Ùuœ½™\¢½0=†=¿…>Å-ž½¨7˜¾< Ú½ 4È>;95>(o©>àïz={öé¼a‘�¾Py¦>cáj¾½�=š¼ù½ªyöºw9­ÜV½g°\>­‚¿• ‰¾3T= DƼ¥Æ†=ÃÇ”ÿ>iJò> rí<Ù)>¼ûØo¾OS=Î埾 ^>ä�’><?=eW‰¾Y¿œj�>+žU>ok%¿›Èн!Š> ¾Ó¼½p"¾²‰¹=tq1>ímÆ=0d!>„=™½–© ½˜€°=ô§3>oiˆ½O;¾jà^=ÿË>} ½®·4=Ž„=„P½»()ç<œä-=Oôº=N¶­¾SÐø½ñÝ=.¿>öÜ®>q–=Y2.=ÖÚÕ=é[¼"Ÿ&¼¡3„>+Zž=ÖçŠ>¤1 ;^Ñ¿Û�ø¾Zé ¾6Ö >Ô”-¾j‚¼4òq>~“Œ>“ª‘>…æš=B©¶=]&g¾li…> ì ½û£>Êív¾V˜P¾{©¤½ƒdå=‰H >íÍ£½óOÚ=é¡r¾i¢¨>­#Û<¯)ͼ]Ï�¾ã$Ù¼ßþä;•2g»°ï‡>Üæ»=&iž,>ßÀ>˜õ”<á.y¾u±£=VO½ôÒ‡>Ÿ°Ï>õk>7Ç­<�›Œ¼û9]¾-c‰>”ÍN½š[ü½ñ�*>7ɾaÉÙ=VÂÔ½¢‘½µ·š>¹6>ÃØ}>B3=J×ø½€Ê=’H¾[Ò�=FDô¾!©î¹äZÔ¼þµª=ý?Ì<*"í<õ'±¾@^½ÿ„¿VÐ@¼,¾¾¿�?=vÔ˼¢5E>·5D>©�§>Íá=®LÒ½/믾‰[¥¾Ûî}w0¾9¿„¾Ó|®¾ïŒM>k3>‹w¶»1A>¼Ó¼ÜË>òs¢>kà >ÿ–=¨Ù­=!M¾ÔPã>Ú½«[0½ðÛ=8p…>.ÛÄ;Suy¾‰¾’€†¾|¾�>>Lܽ¿ö$=$f�>ÿ;\>Cm¾:¦‘½¡À¾YN­;–=cJi¾b«&¾Ü}¾Y˜¾Ù—•>Ë«¾ƒ[‚»8ˆÖ½SºŠ=‡é¸>_Ï>E,<ÅÞ¾§©Ã>:M8¾* >¾¾Î¤=�é@>£+*¾ �A> s;>³}4¼Ùž$¾™Ý ¾ÉG\¾$о¶µ™½b'.>›H½¯.W¾ˆ1;Ks˽çö>¾Òx!> û‰>´øÒ=#Âæ>®+оä�Ò½õbô½m£¾MZ½«Ð9½üµ#>£ò½MzÍ=ð྽KÑ(½XùH>TN½U)>…¤½j˜Û<�+z¾4×ý¾Êû»öÅ‚¾äÍ‚=ÅH—=G±¢=ÖË=3½ê<†Y‰¾@‰=æG¡») >27W=<¾1>Q·Ç>2`Y>ß]A:2eb>ú5¾«Ò)¼9,#>>¾;ñý½hò&¾‘6î=ËP~¾çÇ\<ñÉŠ¼ÊÞ¡½[Þ&>�c�=œx>¿ożWŒ?_æ;>£Í¾úˆâ+>¾–ò½XÉù½«3>­Ï1¼­QÔ½ Ì­¾7Ÿ2¾ÜŠ‘¾ñ·×º¦ó¾Kps¾Ù(<_ºÜ¯=³U>ƒRµ>Ê—<ñkš½;辟¥=r’?Ì(ú<ôª=Œ±Ê¾œ7¾=6â‡>æ(0>@Ó®¾ÿÉ.¿Š ¾&Û=.-©½ÆÒ¾Œ-=±ÄM>jû•¾qD¿yd=|ý¸}å½³ ê=Pï#?LJ>ÝB¾1î>tL¾’*»>Í:½=éè=¤Ãß¾©à½ñ5 >^¡L>G0Š=vfå¾!˜¡¼-o >­Y¼1̾°™�>R ?]+j¾�À >显VŸ”=Ÿ9…>µç/¿Ôdͽ»ôÔRH-¾ÚvY>a©�>jv>_?•¾ÉVľF¨¤¾ˆ’9=,”‚½àüß½0ï½j�K=BÔ¾xe™¾µ$$¾Êž¾ b> ž;¾9ú*½Ålð=ýã=©�q¼'©ˆ=ù³»Ö‘¥>V4}>\wY½µÐ]½ÊS>à´³¾Mï5>ð„¶>ûi>8•=„i™½\ꣾÀža=QL‹>!ÁS¾Nò«>�Ä>è>A¾Ã÷ ¼Óf>].þ½¯K\½ï•Q¾!”G¾ðª_=uD¾�ÞÕ¾ùN¥½ð¿>>´‰¿íy¼êo§>çw­>l7˜¾MˆÅ¾pð¾uÉ—¾>ƒ`b=maR½» >"Y/>¿>µ¾µö¢½·/Y>Œ‚^>,pª>Ьâ½wÏÓ=Â>d»¶¾p§¾éÐd½™ÏK¾%®M>·–¾'N¿=oàW½’2=^$>Ü9_>_RÇ=É‘†>ýw-<šG‡½� \¾Õª½½ã¸¾ŒŸ=S>ºý‚>�W̽æW>= Ðû=6p->ëð#=8ôý½×W=�·û½æ& =D36? >o¾oÇ>Å ¾m¹<^ÓÁ=;¼m’½^µÞ=Ph޾'­M>t»’>™>½ZÙ=}™¨¼V <>É…K½.¸¾ªxB>¼N¿…€­½¢'`>oó/??”Ô½Ezð>O«=À%>³ƒ«> S)=ñ.+?|¦>ãðß¾¯u¾rI5¾îÔ?>˜¿W¾Æ€¾ÆŽÙ¼s«>:y²½l´s>%Ç™=¹M¾L¨M>̾ (x>|å²>EÓÊ=b•¾ä„å>3Žß£>«wƾ6Ör>«ëú95(>ò›p>µì2>¡6)¾�æ>8½>¿ñ•>–ã>¤ö¶>;¿!¾Ñ•¸>2?¾xº£>äl>.žŠ>èÍ_>n”=rÍÕ½CE›=ߊ¾z(½™Þ=‰6¾(Æš¾è•Ž>‘Ѩ¾Ž >ä�¸=°Œ½–>(&œ½½Ýa¾¦Jì=†·¾»%'¾“Ѿ4 „>”w?ž�">Å 6¾:#¾n1¾Ê”A½zha>–)¾Ô�>›5޾sŒ¾€ m¾¦9¤=V}?;ƒƒZ>&(½'4½  ¿âž`¼`Mb>ùg!>·ý¾ª¾=d\�¼�åŠ<§€Ë¼)ª¥=¤‹>¥“î;Ü ¾”ÀX?£4=dȽDཀ">ð²¬=ÕÐ=²>¢Yq¾î‹={¥µ>U*>iO±=˜¼”>*Óª<Ž8ó¾?7 ¾°Ç½ÿ‹t>›Í¾Ðx0¾ÏHa>VK1>½o¼>{4´>Pß;9‚нpÈt½=úí=x7ö=} 辕0\> ¬=Ó>ô°½–eA¾÷�¾å­±>�Y>Î=Vîl>†Ä«¾�Ï ½a�¿ÊD¾qÁð½C¿œ>£·6½3xè½ÍíÕ=ùîÇ=Ÿü=5Öì=$†=8ܯ½" ¸¼Zœr=&_E¾9i€¾ôTx½ ív¾D6†¾¡Ô½HÑV>ðñ?¾2µS=Ìõì½ïÛY¾u“®>Ó¬>ðê�=!= L"<´ëb<Áá•ÁJ€¾Ü¿P˰¾�ÆÆ>ÂJS>8þ²½ïò>"³W> ý¿>1מּ¥¸=jƒg<·WJ>·@x¾À ½3ªŠ¾•:™=ÔnÁ½ùHÝ>¢ë½±¾“çÞ¾:ïí½bâ>~þ3¾=Ñß¾2Ü·¾k޼e‚½zÓ½Ú½îN>xó/¼“K…>Ýýà=k¿>>𳂼âÄc>ù›½]X¾t# ¾D}à¾HìÖ>ÒjǾZO°½h(u¾ñ™‘¾C2>d½²“=z<@¾À4�½é¿Û½»{ >¥qØ>òM>ii¾Ð‰H¾Å!<¾$¾èÈÜ=Nô¾^Â¥>÷(Q¾âT…>á<¦>Ùi›½öu8¾®_ú¾è¹>‡=ƾ¤:¼¾+Û½Q;Ï>7‘n¾gˆ3=¼\W>¦�¾”r%>:§t<ÞôX¾¥¶Î>}8 ?uì¼ÖÈn¾Œdš=/�=Y³½õi⾱ɔ>Cü$>fw½èM¥> Î_>\++¾t•¾1I:¸äÌK¾ A>çD¦>¾�{¾$6¾ð˜¾XnßÉ/½µj¾¾¹Ï-=¢D>-X쾯¾ê=ª_‡¼ü �¼W¬=P>%¾Â¦ñ½�‰â½Xþ>ð¼ƒ>0Š\>úÄ›>ª°=9U ?·R'>”ö;ý¾£Ò=>¡D >�|ùÚоJÏ=%>ÏuW=Þ°½î›Ù½®–÷¾ÜI©¾,ˆV>�s>Kýr½”úD¾t“Ô=|¶’¾˜ë™½Ä®ð¾(ø®: í>¯_>Èß’=+„¾ˆRš¾9þØ>Ù©¶>ð‡’¾… ½™“}¾™™+¼Ù‚ ½çyŸ½ò�¾WÛ:¾‘F¾EX†¼ý®Ê¾^ŒÈ>�ÚÖ>û G>¿¶‚=z@U¾Ê¾¾?ÆŸ;ïâP=¤¶ ¾…‹x¾ ”6¾m=½½ú¹‘¾ô¦¾%¢F½îß¾D„½=¶ï ½�½¼“>}V®=HPº>!fN>ÆÕ×è×­¾)³Ý<–ò>Eñ¾Û¾b;À>U }¼ˆ'¡¾ËÕ=äNÆ=7p¾=ÉÂõ½›7ó>¼¸y½àKì1ó�¾Žõ)=G=?x[Õ> i¾^‚]¾/�‰>.É">E#�½Èá¼E1¸>kÅF¾vG^¾èËa>l2D>#ö¿ûu×ÿÒÓ=À-™¾,0¢>°6> ¿•?Ž>휽°lA½�éF=¢€E¾Ké½{• ¾1 ?S®”½BãÍ>dt™=¸$Ô=¡ôÝ=Ͼ›�³¾ ¿•¾->ZÎ>œo¾ÿ—о’Ö¾ÉoØ>1ó¾6Ãû¼ã Õ=3Í{¾?Êë½] …>›>‚m>9*¾ô=? =¾‘Ë‹<× ]>Ký½);¨¾S‹>hB=‚">E½í> ìñ<�(3¾òÇö<*;!>”¼†>•1>?æ#>m>í=99V¼ ½˜ê྅«?=~¾Ù?dÞB?/�¿„’¾µù=å¼Ù½èZü¼¬jR>mÿ¡=’‡Ì½hi¤¾Îí½æWë¾w;¢>sIÁ>©t˽£Â ½]V’>°å>jÒ‰>]R²¾«@:=Ö~T=tÉ�¼Õ=¿ —¾¦cƒ<ƒ&>ö¯3>n�v¼»½`“½#4=Ú1™>ãùÄ¢ï¾C=€¾iá¾FÏ>çô/¾ü ’>a{f½”LG=̤¾»q³>e)>EÚ¾´Õ3¾>•¾D£¬¾±H<¾2äÍ=Õ1>‹ÓP>èç8{¯;á%º½þ9¹¾­—¾{+ ?­×2¾¿êd¾Àû>åQ}>qO¾jK¾äÙ�>PÕ®½¡4´>3rž=£ÿ¼JÒÈ=é¶¿D%¾={ å=Ƥõºa±>]ÏY¾LÀv½B ½b?ªè½£¨Y¾1/$¾êŠÇ<¢¥¼ ž¥>Ä{ß=ÄÝ!>~žZ¾“9¼>ž—Å<¢½t½Ž±> ÆB>ñkx¾û�¾‰¤=�ça>%c©<ãº>“]½‡E=Eœµ=—Òµ>‚i¼�qœ>y¥…>ˆUÖ:®â„½ÛÓD¾ÞÔf½«õ=ßî ½Ô >DÑU>¡4¾2ß·¾Ä�É=K>:>Nöš¾Éƒ>†Nù>ºÔ?>§þª½û# ¾÷¥Q>¨^O¾ð8¾_/ؾ³Ã„½ÆÔW½ë0ɽø•9>)ßc=Q]–=‹¢ì>ýçn¾âR½œÀ®=ú¾’>Atå¾6оTÎ(¿þÇê¼,0>ò$¾…õ1¾Ý¾í�œ<ßî¾1wS¾§å/>*@Ú>ù”…>Ÿù‰¾ÞÎj¾¦Ê½WF=>ÔîO½»$…½®�ò;´V‘¾ÒH¤¾’>Í™š>%ËC¾t2¼­€<èÑ>½—r>#>xǾîZ]¾ŸƒX>òøå<íó�=¹_Å=[}¡=5÷¾ËìZ>ñ ’¾„!ç=¸7±>.k2¾?ªÙ»^}Ë=<Ê(=š >ÛSÌ=°±¤<�K¹=a<Õ¾Çú&><¨F½M•³½…Q|>Ü o¾ '¼u²½¾.4„½EÙL¾EX>¼>,†½ÿ%*½&‚þèñ>ಾDµã=Ëù<º½¢¾¸x�¾ 6‹>S\7¾GÚÜ=3Óf=Êê÷=ÁÆÌ>Ûn>ñ­·½Oõ½Bˆ>¹îú=²qw¾»f/½ùMŽ>÷W½ �¹½ ³h>\¾·3�½1\P½–_»½¦�È<ø ’=1›Ù>MR¾¾QÞ>£–t¾Pß÷=-{H>�>½3ZB½ ‡¨=¬†>³=e[>¢i ¾è(>ßK‚>î6†>â—¾w­°½PÚv¾ˆìe¾œb+¾?ûü<ž+²½äÓp¾¾Ÿ,=šàA»WÞ]=☰=¾œ{½lNÆ=XKç½o ?ȧ…½¤3É=Ô¿¾›H>z÷Œ>§¹½šÜ=¶WÚ>QŒ ?/G’>‡!Å>Œ =’O‰= ·N¾…³`¾8=¾o)¾�;g<"¢ ½ñ+†<+ši>¨\â>;›7¾V€>ÿ[ò>J?å(¾“Ψ=°µO;é[�¾_s1¾jú½V¿±H¾å;į¾\:¾!ÚѾþªŽ½7‘i>4!>ã Ž>¼Üν¯îô=séi¾ˆw‚>)~õ=`«>XΓ¾¡ø=öÞ½ `¾±>‹½Ù ‘>QU¹=Z¢Š½TŬ=û�B>ãxµ>¬q8>Cƃ=�]Ì<{„>ð‡Æ; 軽âœ"¾!æY<š÷[¾²Â< âp¾ tÍ<5Ú¿¯›ï¾µ2>Íb½ —c=µÂ¾X†¿½ïp™¾y$#>¶‘¾`a>þü«¾Ê0E¾Æ9Á½'«G>¸jŠ> 1²= È€>Lš¶= xÜ>éϾD¨_>Q;>¨«=MŒ¾µ*P¾gÈ ½r°>·ñ¾ö°=÷Ev¾œ羡{¨¾„2š>•ö»¾l¸~Ó>´¶=´ž½0—= ê¾Ç½¦½¦>²_‹=î&%>½s´¾¥ð°> Ñ=¿¨G=Õà>=¸±¾½pŸ>vMc¾É8? *?>¬ j>,a?·Tø=à·ˆ½0ÅÏ> (D>(@©>Ö§#¿èO<>羋 |;n@‘>ZÓ0¾d ?87¾’m0>@¿}¾ÊƾzM8>ÉÔ>M•³½Žf>|÷”½}GZ¾„�>èÉI=W18¾øõ=fu]=©^¾ÒU½©÷•>�``>²Ó?>¢Âu=Úž@[?ç¯ù½°ãA>QXÿ½öY>–0>ÿ’=¾‘€�>¾ãË>ŒO?$¬�>Rš$¿K]£¾ºxG¾$ãܽiB§¾†?>¼Ø¡¾‘A=p�>ë„=ha¾“K >b¡™>· ‘>»*=Íë×<™%)½� æ9“[j>0Ýv½]ï‰=ï  >Dש;÷÷о¢p:>uyS>…?ï>ª¾ŽR>‹L޾P¾%ÎŒ½ æ?³‹t> ë>áì‘>�"‰>ŒLÐ=B/:>3j“¾Z� ¾g†‰½Ýö&>éIg½ ÍH>Eˆ¾Ý#¾Ý­>Œ Ù>Ÿ5¾ºa²>¼Žm=…µž>›ÂT=‡l¿«`=xdß¾Ê�E¾G~ŽÃ%4¿UU>ni¾Ú£ù=9,1>,ûü��>Dt¿KÛ*?-Wм B¿ƒg½¾·³¾!]—>sÏI>Âô¾@·¾ñ%;>ƒˆ¾1Ô§=½Ó-=zÞ<ðwµ=b7u¾h"á=úh­¼�PÉ>C,÷<”Cá>1f.¾çW3=ÄZÁ¾Qr°½mèV?l>êo<#%C¾` ÷=Íù/¾T£>#’&¾¬¼¾Ÿ£½60><éR=çÄP=º°M<¨m}¼:eK£)¿±Ù>®X ?t´?Û”*>eÜ‚>)ÿ>$ÛÒ=ýŽì¼§"=ñÄù=££½Ê*o>„ã?=u�i:8¦:¾çÚO¾l厾óÖ%>0BH¾W=úž%¾Þ­h>¥¸ >eü>f<¾’k$>c7>1§¾Î值0>Ǽ!¾bðs<0)Ø=²Ï·=W¿äͽ„À§¾Å‘¾>µ—>»”;3¿(½¨Hž¾^$Ⱦ\d¤½ò?þ;ŽO“>Ë'>Ft³>o©¾�Z�¾'*=¸Ý)>�}¾¿œG¾O#®=„°¢=—)>LAƼ¹äP=sb±>P¥½“¿É½v<í½”J>{~>8Î;™Æ4¾ÈRe>`UÁ¾hÚÉ=#C¿[‘þ4Ò%=ÿ\?P×X>ßÙ==j¿vÈ>Æy‚>aü½8ðï½å«¼ÏŠ�½´ÊX=Ÿy|½²y¤='U ¿c�¾Í t=Vß°¾uš'>½ë<$~‰>ˆ�t¾ý�¾š–>/= >É ©>Ï|ƾ»ñ5>TÏÇ<þgÛ½@EÉ=ës�¾<ø¾A„’¾SÚf>�²P>Y‰›>O6’=j#¿Frž=Uaù=qý²=Ì„¨½~{e¾…-Ê>Űã»ãt¾‰r�½Yw>}„L=žÈó=Ž}î½?Sæ>:`c>¤<ô¼¬š¾¾Î°½Ì">(f²=ç(”>ÞPÛ>—>c]¾×ˆ*¾ôƼÙÜ= ” ưܽ?£¾{Y>Z…´<¶ Ç=/Ï~<꥽€Ž©>…í}¾œHm½jUÒ½•¡>:`é=†é¿>“Fâ=’Ú=Ä'†¾dâɽ×`>æG¾kÕ‘>&]¾UǾŒÙ‹>à(¬=™É>Lã¹=Ÿ¥v>|ç`¾Ð1á¼Om=@ï-<¢ 2¾M±Æ½ÁÁÎ>ÅZÖ¾™zó½Ö‹> 3ù= ý<Ø{â¾_è >*L@½TËW½è;¾â¥ð<²¢ß=ö³®=³^¾¨k=…d¾„ >îá…¾Ðjm¾“—·>âoà>ÛÙ)=Bh½ˆŒ> "¦¾úàã¾ór3<ȇÕ=CÔ=�‡?F¥Q¾Ó@n>ÖK�='g?»Ô§½3[¼œ¾V¾‹.,¾aÅ$?bÈ‘¾ü^,¾´¥¡=ÅW¾®´`»>럽)9Ü>4¤;N‹¶=àý9&>ΰà;™•¼>ým¨=z„¾îü¾<[ ¦¾‡®@½Šw@¾…ÿ–=tC¾J-¯>Å!¼�D>ü+>j`˜¾V¾¥Û5¾^p"¾±NF=k@>qR7¼õg1>yM­=7)¥¾j¨=ðx×=‡L¼ŸÇ==Ád=D»…>ì`>Ý�¾ä<¼Ø*o>b·š=2K,>=3C>†>š=´?�¾�´ž¾½L¾ñ/�½ÕÐR=–[>s@=Mjf>Œ.¾¯ŠM¾¿þŒ¼kx5¾|Ò¢=[¥€>—̇¾5j¤>rrܽL±¿VT,>�öJ¼/>’]�="[>-þ‡ F=º½À½Z F>K]>Ø„*=»±V¾÷ à=+IÜ>§ϽÀò¢>ãŸM=yíO=[ƒ‹>oif¼j«>$ËX¾…z™=Û�€=>dB¾Vê@=„:’<×fϾÑÅB>ë¶½�Ý>£Ã=à韾Aa´½|ßB½M>ƒ>Èv¸¼Xv¾XÛ>Å[8=øÉK½U”§¾ý×½&Ÿ½ _>¾ÍŠ>îKǽ¦ÿ&¾NÒ¾=©ï¾«�=¸}ƒ=AÕ¾â:O¾P?ɽ_¿O ã=fYF¾Œ…¾4ñ½É3½Sk3¾à==t<<5u#¾#iˆ>~—ô½K”,>x˜�½Ú¤¿¾oU°=¯8à¾!Ï¡>þ}罸Ô=q\=ÆÍT½¹>‡~=½…M>áÀ�½H† ¾l ê½¯>z®ˆ<5 ×¾J¬¾Õ�¼èŒ>K½ÆdÉ=¸¥½!¦"¾ -—½B6>I°K¾­qp>ÁtÙ¼ü >©‰*¾ô™½Y6>*<^½•�¼CÓ<ç,½Î–­¼¹Þ½Ò±Â>ÎÑL¾O_†¾�Úë<®Ûã½’ØÛ>>î½!R:¼ÃÖ>z >l…Ó½>2Á¤½€i<µ²¾;®Y–=-F‰¾ÐsK¾ÍަM#¾&ð ¾tq}¾³?×½’é•> ÷ >´€<ãú˜¼¬³¾A`¾¨ý>”a�¾~ý×;/ÜH;+Ûì=\3k¾_9\½˜‹¾½¾T">wH<ÕcƼkH5=Ó7³>¥Q=´1ø=©Y¯JL¾6ÑϾò>Ô®¿ó;¤:Cl>�Þ>ïn=”>ôÏ1½#K?`S¾0ʼ&8>üؾ ×W>‚‡V=ëš�>€X¸=zß=ز2¾åá¾.ö ?%¸ž=¢¥Ó½°™™>™Ž=Ð[Á>–£Ú½PZò¼?‹¼õÅ›½ bB¾å÷‹½AŸm¾¤{¾ ò3=…(¾l‡ê½üÚ)>p®S½EÉ/¾kÚ>—= >¨ ¼À>t/¾€&Ô½G¾º?h>“X°¾(zç={Œ‘;«P±>­�¬>: š=YÔн„8\¾hm¾|±À½‡´º½"s­·1ž>^xì=s«= Ï©½€´À¾ ó²¾ä³Ž>±{=/†O=0Úk>= ÿ=�qÂ= &½6”T>袒=j D¾ ¹f¾kv¾ÙÚ9‡�“¾ð®m>°u>×:û>xƒI¾³e¡î½ i0½[MÁ=&MJ¾€>‰Hñ¾þdœ¾ „W¾ \Ž>–˜¡½ø¢¡½šR…¾¯Æ’>��>M3–¾,�>ŒÒ½DV>È+|<ݦ=ܧ=ÜGï;ë­=zD›½½k¾™¥¨=í—†=Î$½2áQ¾Xæ+>v>WÛ>k#>kC­½ih«=Y¥†¾#÷¸¾Î÷V>Ö½œ7�¾ûç'½“`Œ½Œ«�¼BgC>:ì=“ö=>®O=|¬º=*>쎽oB¾Q¿R¾3¥h¾]­Å=kT¹½$ž>Ý:>í+@=HåÈ>³"¦¼[E×½2éÕ=^̳¼l‹¾ñØ€=úØD¾o»M>Ï¡:Zu>Aå ¾Î�¾´ùu¾÷á�¾mWk½/O7¾¼È�>ÐÏë½ éÞ=B©¾Ï¾a-�½¬ê½ú¶J>ˆÁX¾Ý ¾ƒ‘³½Â¹ò=ßaY>a¾‹’‚¾ ÄS=E«U> d´¼$Šƒ>,µž½¶«�¾m�¾¾‚ï'>ƒ›6¾û—¾‚¸}>4¡#¾14›½“4ó=Å4J<¢�ã=hi=œJ=›�¾‘d¶»Õ�=N ñ=v8P¾Íݾ´/Ü=%ê>ŠÖí=»œ²=­5=È  ¾ý«ò½>Þ+¾-�¦½‚Ý%¾–«½ÞéB>fU>XÇ«=ÖBï¼�y‡=�•…¾v6q<‹žEd¾et¾k°>Õ¥™½ì7<‚¾‰R>¢.\¼ýn¨½4ig<îæ¾ÍÊy>óÝ+>аּª°&<ÚÔÎ;VçϾbû<>öÛ`=÷€J¾˜82>á�¦=܆¾¾X¶>7c€¾ÆÎÜ>¥ª¾öVë=eã¼²Q‘= Üå=¥£=üy¾ ¾�ãÞ»¹Ér¾�d“½î¸’¼4k­=aËN>1>öÜi¾®³Á=Úld>Œøi>&öa½÷Nï<Î9;:¹õ‰½™‡>’s>ïµÇ=2] ½þªÊ½Ø×Ê< SM½X¤>‰Üν:~å½ O�¾ óª<„¾Ž> ‡J=3h½,“µ½ËÛ§½@Ä=c5»KËl> ­ï=ÌÛ�½g®¯>lo„»ñþ½Ú᜽ðkì¼yfá¼ý™¾&c¸;¨!Ð>¤v>5¾Ô½×y>Ø™E>-½­ˆ> 'i¾pá+¾7ìQ¾Ô¼œ¾ûp†>êKÎ=ÙîY={0È>†t�¾’½þz=Äñ<<˸/>A‹æ½‹ >�àa>L®Á=ú¶½é_>Œ ¾½X>(ö9¾¬o¯¾Úïš<ŒÅh>@·¾äÓ=Ÿû©=f”ñ½MUö=8+3>²»>ƒˆµ¾ô{>?kk>°ç ½'aÝ>«ø­½ƒß‡¾A†Ï½‰ˆÇ½ìUÿ=8Ày¾`«>ªÕ¸†wÁ½=@ã¾—ô·¾½n«½ƒP)¾K =Œ±¼Wòñ=zõi<žÁ9¾V±Œ%l>nš-=û×»>&T¡>gÏD¾¥·=„?^=®øE?Á÷”½Þ�ÿ<…̾CÁ˾‰á=å¤A>iŒö>㉌»\¬=g¤h¾–y> áZ=ó�ì=!d3> ^>rE>„ j¾á3±8Õ…„=`û^=>W½¸“\>)äb;“›X¾EO(¼-¬ =Ýúž»ƒ@€¾ k†=ÒÙŒ¾[Èà>:W•½Å'©=¢gš>•r̼æྺÖ<Š3W=J¬¹=5¬‚¾Ø]æ=Î>7·{>ÊŒ>|¾ø=„˜^>£L–¾mJâ¼´³=ªôÿ=�}¾˜@%½òK>tÌ-¾_‘4=«áŒ="]ƾâT¼�‘Æ=™>Ô®>ªÖ\>³Z]½{H†>„Rž®ìŒ¾#¾âÐ�>›ñû½.¾˜t>ÆC‚>¤™½\ï—<Ži2¾h™¬>uÓ"¾}ã =z6¾m¯_>±çð½ËaR¾>^°>¼Žµ>*8ì> Yç<—^¿r€i¼ì}¡<»˜ ¾» >n¾°>Q‰=ð™õ¹&KV>sÿ´¾²«¶˜Š‹wR%¾`ÐÕ½]¾=.æ½N¥+>r“=,…«¾¹Ý�=zþ>͇¾3ž>Mðm>�Èž½ÂŇ>«XÞ½E,§½Z:=¦Ý½>ß„>äv*>�Öø½øZÔ>Я‚>?VM>‡Z¾€»�¾˜K= ¢]½lHæ»S:>qGq½o˜D=º3/>çíF¾ï w¾×£>HCs>_§Â¼cfνhø’¾[01¾¼ ˜¾­D=\¥½w>CAª>L¿¦½"Z >ª»>~M3;U]<7yf½Uµ=b8¾«s>1Ð<ø·l>¨j¾\>ƒ=x«B½IÆW=_D>B¢= è;½ÜÏ=¸%=Šc=õÑ=Ìù½þ+£=ëg*¾ÃCP> ½ ½uR¾ÂwË=¡àŠ>êËÕ½xI¾¨Ãn>¥²7¾Ò:M½ _ê½{è¾'Lß=±|å>œÈ¾û÷¾žr•=H3å>�–_<*.=ŒúŸ¾žï_= 1„½zÞ½1KE>K*A<Ê�.=ó@Á=E9È<0Ãv>^°l>qoë>J=3µ=Þ¶�½Åp:>wM�>k5·<¥z6=? t=£š¢¾ž=Z¾¹¢6¾;ÜW>ª·Ñ½²>Ö9­½�€=Кw>õÒ½-±¶¾�ú>>=5~¾f… ¿¦•Y¾O´�¾s–¾¬h=8¡ý=;'­¼*„°¾8‚†>ò~"¾ùwÁ½.Ï€=V­!¾çPì¼ ¶-=?Ñ>Y‹=‘†=½‚½_^É>5do>{¤>u1X>Ѹ%¾þàͼpà§>…+¾ùdŠ=(Õ¤¾OsÇ>1½7>caD½ïoÙ½^öé=¢Ù<õÍÓ;»f;¾ü‚=½­í\¾YÚ ½þÍ”>|^ç=&�§½ù’>Z<¾†X&¾h~Ñ=:wµ<�ŒÐ=�õC> X ¿›ÈT½œãf>�Ÿ÷½Qáï½Îâó=È‚Ý=âÝN¾Û”˜>Øo>™ÄؾùÛ½+œ=üÄR>å†�<á᜽ɯ>m¤a¾O+ú=Уj=‰ ¾=³›ð=c•™ðSI¾é¹G¾hT޽Öý7¾r†<>U8a>º$>ì s¾�˜&½Þ²Ý¼Çð»4È«>]qß¾ÓÛ =“’>–?˜= vo½©ÕO=k‰¾vÙs>óJ¾ ¤<>L>À“Š<îrJ¾HŒÌ½œ£<ºNÔ=—B= Kl¾4DŸ>õg[¾ŠÀŸ>‹ 8¾°Âö=�ý²>Õ½=á݆½–åT>ï\l¾B×·>!#£¥>9ï=Ó~4=î ?<Ö>{�¾/BN½.†"½ŒÐœ=J¶™¾fV½×÷§¼þg=T”:;Ò{,>µÝȽm\Û> u#>—ž¼1ã½SU>j­F>´Z—>1ž®>{´¦¾Eç¬=iM˜>Tü¡½6R½ÉVÑ=­/©»&HǾDAݽÈ/f½kMÁ:Òw=ô;Ý=Q ¾¯>¹ƒ¾¡%µ>¡mV>‰Iñ¾Dr'½? Ò= P=ÆÒ¼•nTBù½ä„m>WRE= �¼½/k¾ IZ=Ðäà•‘½è»ˆ¾8Šœ=@÷n¾Kª¸½c*¾Þ (¾A÷g>ÐÄ·½þ:ß¾@ O¾`¨|=¶ß¥¼´>ø\*¾ì”™»gÓ >DP\>SÈP¾Îy½m0ç½A-¦>-->Øý6=ƒá>>Œo¾ºrF<{z¹¾Ü÷²½¥C¦¾/�¾<$=¾ºÁ¿=æ‰(>È“Y>RM0¾x«2¾†¾ðêõ=T¶=� ³½„Ü=cA¼êSº=`äÜ==Ú>Yu¬½·xl¾˜#3=÷-¾ ˆ½ 1;¾Ÿ}ȽMÁÚ½{Ò¾µØ­¾ßr]¾¾ ª=xÆb>ùC‡¾Ž:=™‹¯½¤ß²=B'™¾nn> ß›¾ÝBŒ=zy Ù#U>·'½qª=À6¡½ÿñ/¾ä“=4ý Ÿ½ç«½=èÅ>è‹£<µ¥C¾¿R½Y�w¼pÒÔ=¬\Í>º×=šÃ;=c’>O¾ŒŒ¾̘>ágн’�s^YÅ=€k=aÐ^>¥úCº_&=¼�ê=s*Ë=(±½�È=JE;ô ¸>Z+/¾Ê²>猾µ©¾¾…˜þ¼¼³= ½I‡•>¹;=¯T¬='Yý½Hw£>H6v¾¶z>ät¾˜œ‡½ä>å=QC>ôˆ=ÿAŒ¾áŸV¾N‹ˆ¼är¾íg¾œ�‰=‰¥é=•F¾¶eX>ïP¸¾”ÓV½�±�<~Ôª½ô²¼ù5ª¾{íÉ>ÈÌ-¾$ ‚½"„½ëš²<†¯^=jÀ¾òŽ>fܼ“Ð4<çÇy¾/Ê=;ø›¾ÔfȽÇ�V=%wI½m�¾2ð>¾x7¾Tâ >Q°=á=ÏÒ8<ØÌÕ=ÑùË<,Ñù¾,e—=N™¾©IоÝCc:µ�+=–H¼Ä|�>�B„<÷Ù=¹wѽ–¼ýT¾�áÙ½aA­¼øa˜¼Ö¼½€�×=Ôß±½�7£½Ü¾¸J1½È%Ý>z.ˆ¾•=Ͻs¯ >wÔ;§Ý˜>ºcû»qÑ�½.a=JÄ®=°:>j‰­=[½6kV¾31¸<Œ¨w¼–ÿ†¾(ý`>d”¼?=³¾—£¿¾Û–=™:+¾ç�p<Õu>À#†¾GQ¾ý£®¼Ç\¾ˆOϽ¾Æ�¾Åav¾�2Q½R'‹¼Ø³ý<Ï“d> Ä;¾ M>¾GÚ;¾ñp=¿qM¾¸G~¾”GD=õ#¾-–q¾&¯½>P>?A¾ø?=Õ¼ vÚ½là>”Ú½�cƒ½ƒ~¼Kn¾!RѽǬ®={àQ<ÿÔ ¾ø°¾>‰>9ä¾ÏËá=E½¾ô¢²¾³�O>¸IÄ=+Pœ¾Î‘²<ý‹½P£¾ ‚X¾õ ‡¾á‘< Ä­½y!¼<ðUÙ½`ûš¾—º<ßÞ½í =*m½ù‡Œ=|—§½m�ƒ½[Âb>Ù@_=Üž¾×K‡¼ìý*¾ý’̼xAu¾ßq”½7@ ­Š¢>úfñ<ñÓ"¾Ëú9¾†ó¾æÆ¿½„>< •<+XR¾)‰l¾Ð]¾hc> ï¼ ‰>œø,>¶”‚¾¹‚½)޽'±¾žiº;ÐÇ=Ð >Žø‚¾UÖ¾’|'>�c ½%±]¾F+>¦@Œ½T>p¼cÌk¾1T«½¡8ö<‡7Æ>� ì½Þ”¼,¡9P¤‰>f¸š¾éÓ½¾Þ(L¼æÜ+¾ã•¯>?,Ì<ù4i>�é8>Ò�¾Ù@9¼Go[¾6!?“ö™½_Ñ�=ж½½Æî½[ÉT>è)™=1=y=ÐÆ>–¡>k„ƽFäI¾ò,>]Öª½²—o½=Ñ.=°T½k�°=:™¯½f1¾=Ù'¾¢­µ<Âé=ýR¿]1Ú½~¢¾ª¢i½Èj¾Œ‰ð»äTx> “<ц¾’k^>ï÷É=ÑØ=õS>ïÓżøÌ½án°½õwª¾{ >sG>™Ü >�¼ÙÍ€¾â´(>wæÙ½¡ñ½¿Ò=§Ñ>åÊѽï¡Õ>©@Û=Di½®8»½|}½[¦Ä½wÛ!¾Ÿút¾O¾Ü¼¢4Ž>Jåɺ¤…\>“Sνóë˜=L�_¾i—ñ¼Bõ½ë…•>Ãç½hA×¾(fнɇª<T¥½%•�>�J½•™ê>ŸÞ¶>½Ñ;V>b¾äå½½”p¾±»Ò¼Î{$>S\¢½ÏP4=ÀÓ">ï€*½ K>™�->/r>* ¾x™½L[/>åÛL½½¹<Ý&Œ»š7œ=4ƒ ¼X]>_á>Lœö¼á®Ñ;…€¼ø1½ u�=Þ–A=õÄ=¾M—�½€º¾îÍ�½h”¾•�Ô½{-q=ÇÿóÒ¼ÿ=u>zí=­±ã½]ð¾ï™[>óA ¾‹| >B-•=ܯ=‘…<�¿û¼èN;¾·ï>¾<�½I. ¾ýj²<%>÷½Ž›=ƒE =iÙ&;ëx]>Ù—¾Q¾Î½ >Âß>?M}»®�Á=|à±½¬-O>r�r=ƒi¼–®ž>Ü]¾ÏJe½s‡%½©5½8¡A¾?MÓ¾’ #¾Ò¥>;¨9=bšº½¾‡4>‡i>µ·>Nç½$Àp= Xr=?w> •̼VɾÜþê½U#J½£ú½3q‰=K>3·%¾Ïß > ·>’R=›Š>· z>~«s¾·>K(”¾eÚ½‘êî=½1š¾š^g»�·=š³¶=å¶A=Ã6¾4Ž>$~0¾N,N=øí˜»™ª5¾ê’>ç(<(¤V<¦9�½ÿ<†½»û½cø÷½lïu>+Îù="ƒ>H ¾½c–¿ÝJÌ>¡$ýjU>á+”>¢y³=h…]½ç Ò½5ç=AjÓ=…©À½°Ÿ>€ô¢>¨½(ÏA>-îi>¨t‰>W°>L¢¾qzu=Od¾,×¾y¦/¾o$#>†Í/½\ýæ½M”‘½KYé=퀫»vQ¾ ,>¥a>G˜„>VÆ>z¡¡>œ]O¾˜k¾MP8ºUœˆ>>º;=™·9½PÒ¼§T>¥�k½øk–¾Aq*¾*ð ¾7…‹>¾˽~Sk;VÄ›>^j¥¾Æ…ƽ¥m>ù*˼V‰=¸;¾c&=Ç!·¾¢Cb¾€<þ¼’ôü=8е½PÙ>7šš¾Áv€¾ód.>h¾4/>P¾2Te=ÿ(¹=@L¾ðA>Ø>¾�N—½ 5å»´Ñó½U88¾ˆÄÿ<ÑÊ=“Û{¾9 ¾Ê.¥>ëC>`û{¾¼�Î>xÇ>Kº =SÝw½g=¦=þñ’¾ c>O‹«>¬`#>©Äî=‹:¤¾í�=¾øªˆ¾Y¾?>ÞÇ=§œ>ñäŸ>k1<賨½)?útp¾Cð.>Æè¦=Íüg>‚Å~»®à¹=Ð|>I�>môs>{ÑŒ¾õâȽ]&�¾Ÿ™¾ 0ö<è]�½£ø2>M½ö̵½=ŠÛ<0sŸ>Éã½RŸF=ØS0¾E‡Š½¦íþ½—·:¾Ð•�½¸6f>a¶=GK}=LáB>D1>;f>%™½X\ì½zn>Ö8/¾FíÅ=Ä� >Aü‹>À™u<6O£½­d ¾2 s¾Œ~нïn‚=й›½»‰ ½žî…>Fܽw¹>Êó ½[© ¾ÆöR¾0�>6)½=.¹š>Ó»m=-å¹½¼Òá<‚¡¦¾9Ñ>_Ác>ržÑ½ô½ƒ½ *;>q𢾢Su¾OK�¾uÁ`½t–Û½ž�¢>®›ž¾‚­Þ½–¼*>Í >ŽÛ¦<ï%¾kí³<ÌC >RS<c[>�,3¾øŽ§=+v ¾Ö¸;¾îÑn¾�ô>½œ#¾‹ÙV>Ȥõ½^9¾ÙV­>B¿û=Þmî¾xT¥>N¾‚Eh¾Hd…¾µ 6=ソö}‚>TP¾Ïh=€5 >fNܼ̿†=¹ß»=j¸½>v¼ìÇC¾V5v> �½¤¢½™|ì>”(Ò=(™#½’×¼ÚE°½¯è•<<îL¾o ú=¦‹À=[C„>:vb=f$•½¼+Ó>à[½áZG¾þÅÁ¾%[½ÞÄ&½ ØG>HCÁ¸<ç�>…Nx>>S!¾/Œ~¾®æ„Þê>ƒÛ´½ Oʽó8•¾è™Å½×ÜV>0}=ì#©>è-¾»5¾9>=Gaa¼}RP¾|(¾¸.Œ¾H8輸,½®¡U½+#q½9 (>­M>¦ Ž>˜9�=¼¤�>*™S>§À½ø….>o÷œ½¡œî=e§£=Î2”>²³è;ºë1>·Ÿ >º w½è!¾ Û¼ÀY¼ôq”¾I²©=€V�¾'­ ¾ÒU½=µÖ ½tUh½ÿ ½òü=�{ë4�=`ä[¾ä<½¦=®üö¼—É<›p̾Ҩí=sŸ"½kS…>µ1>ÿ·¸=ó—€¾ö�—¾�Ý>¯.¾…¦M>Q‘;™Á>BÄù½qáÔ=ÞÔ¾g+³<²q½U”Ç>�3ê=03ý×¾rµ‰>™ˆ¾�H=¤8‹ºð‰ >ñ%k¼HÀñ¼”=;¢Û­=ïÑž¾j0£»¬ëd¾òNJ>Ï=f=m½GJÛ½~^¢>b\Ì=> ½½&56Š=¯h½#_ü=-Ü�½,¸= -®½ßŽŒ>H>^£Ì½ü©·=qó =_§Ä=’K½Ðv>׃ˆ>¨ÓU<ª•^=¿c<=�>³\¿>ÑÇ=Î9»=ýaÑ=4©‡½ÀU=1¨j¾öî =Œ-¾} À¸Ð=òÞ=9Ù©¾"Ÿ>Øá½|i�½’¢Ý=î�¾àã>³Íû;F ¾ä(¾KȾba½K”î=œÍ>Jé_=3P‰>\‹>´t ¾tw=c¸Ìa=ž­i¾%c�½ ú¼Š œ¼‡+|>W¤Ó¾”>#Ä<†{q½¤ÌS=DAÀ<5¯H>j©»>uX<òö¾Álá:`%ʾ¶2ª¾Æ—Ý>òRñ¾óm§>˜€¾6`¾�øƒ>´ ˽Žáï=n³¾ Þá=ÁÔ¹½l¡¾¾«ÂB> />™ r¾æyˆ¾C"�>U¾j>s&?F¸­½´+6¾—>^/ý=ô§¼@ÿÕ¾z�^=¤½*M½*GƽGzÀ¾qLü>[|ù¼¨ú ½,¦>dg*¾Ÿ|4<ï¢5¿‘Òƒ>¾Ü½GÄ—=ã¬=‡Î?džc?\ñS>'~¾¾2®>ÚE¡Ž5ž¾ct.¾yÒ­¾m‚.?ÆÏ)=? ‡¾¸È…½™ŽÃ¾S¾¢ҽDzþ¾Mš=Î>>É…:µŠ?¦¾Ÿ¾³3d¾z3�>?~ð¼óó½;¢>ï+¦¾ãÿB>C�´¾NèýÁPú=N…O»Vñ>ã‚>Öõ¾ØÜ>æO÷¼D¾¡¾I¦ ¾qà!¾‰Ê£=ùžI¼þµÉ¾ä�(=éžž>)ªA>Ýœ>Õ8x½%B&¼ÿn?¤5Ì>o(j¼«Ÿ¾qý‰¾}�q=TÄO?@°™>�"¾ð>î�¾-¹À>àÝÛ¾¡ð>’×Ú;ñ2ã½3 —¾ÄªÈ=¾pYµ=šO?âø|¾~Ïó½Lþ?l¥½6CÔ=•".>\� >Mp¿ÀK » F¦=ù\e>Í~ö=Ѓ²>&Ö½C�¿øì½ˆÁ>O —=þÜ>@(>­ÉG¾¯ w>bC‘=.€œ>w@U>„?ä’q¾`Tq> C->Š}¦>dm¾ˆð;Jµº=\°^>DÙc>4É™> …>a‡¾æŸ�½@X>Ü‚‹¾á™Ÿ¾ÿ>:? D=ßj½†v�<ÉÅ ¿D¾_ÝU¾0݉¾Læ<ýµZ>@c?6>æ×`¼7H€¾Ñ9»= ¤¿vI¸>[ݯ>’Øÿ½Ne=bc=K1Ú>ÄMo½eª—½u‡¾Oß>>‰åD>èÊ=¶)¿1ÿ¾kU5¾ŒŠ#=›s‡¾z¼=LÔ¡ƒ¾ª�I¾ù>Îo>a—‰¾WjǽUÞš½M;ĽúT¿«I뾿¾<4Ìྕ�µ»•_< dF¾­o€>³£h¾R…œ=6¨‹>‘Ó~=¯‰ >´R=ù£¾ò=fZ‘<Áö½:.?Y:Ÿ½Ìá/¿iÛì¾ ƒ¾¿Uo½–Üÿ½Í ²<_Í\>º‡9¾÷=±¾\E¾¾Ha>uÈ’½ãçs¾‹TC¾J¾/ؾ­˜>tÙª=8Ű=8–A>¡ÞÚ<Á|Z>8©2=\ŠV>Añ>·¸¹¾ î ?ƪå=޾>øž=Á‘¾ÜÌK>ï�¿“€#> «>�+>¿fÓ½®áœ½ZÃV½SÈZ>ÎÓ�=U`�¾H2 ¿p%c¾ÃÄ™>‡9Ú=”Ã> N3½@Ä>n6ý¼Ì„¾¤ÄU¾y5¯>ÑR…=B‰ñ=�H´¾á-;cˆ>ÓW¾ >Rì¿Yƒ½aI•>ݽ,> L!=¹Æ¾½l¾r K>-Bs»ã:?¶•X>ð#ù½d†¾+¶¿‰€D=VÀ¾/»<¦L*¼MG˜>å¿×½áX¾M…C>z3š=‰›p¾¾¿çö®½ ÃP>þ�q¾¶o<>Rfо/x¾¼„>�û‰¾‡Æž>Ú»R¾«Só¼w¢=¾)×:=jF$>8ë¾"l=üäþ½Àø>ÝúÔ=Îö!>Ú:ž¾å1뾑ž™¾N¡>b&¿¿ï:¾Ìdm½E ×>%}J½˜©½9mÙ>ÓGã¼Å�ç>ˆ«Ô=<t½ 9Ô=i]U½í¬¿ …é>TÁþAÀ¾ã]�<Ÿ²o½´ëT=?³=!u�¾þ]>Z«Ã¾v9 ¿W-l¾ç–�¾Ë˜•½Ä‰Ä¾Â¶¾qˆ >õ\=ÊÁÀ>&ÁÕ½S/b¾„€�½œdó=˜í¾ñ‚/>™˜¾“À¾€&—½ò=FL;ÌM@>% ;» ¾Kº?f׉>åi%¾8×<'О>Íß•=³¾SÛ½¹€>áns>‘  > ©X>¯ù+½¨‰½ø¯Ù>|Ð= è½OÖ‚>ÆÚ˜=~è¢=„ÖÊ>Wh½²Gp>#Ã=ámƒGÈO>¸ú½”;>I²¡;pD.¿ð5”½†ò¾„‡¼g]Ý<±\½Ù¿>>QT½)9š=´Ÿ#¾éa¿>F›·>Ý1¾n­7>4e¡>“<,;“¾0Ľæn>=3Œ=Ô9¿\›Ë¾3, >®µ¾MLJ¿sÂ=ºP…=gy«½ükr>]Æ=YÎ*?ysL>¦å¿hÕç¹sÒ½˜ì¾æg�>f—–¾Ë5®½o™Q>w\�½“~,?[>N¬•=aå¾RGν¡ü§¾?¤¾¸²Ë>K­O>”¥î¾/üÓºgE»d&”>Íš¶>4Ëh<И¼×NÌ=Aî>§È ¾rNi=«ÒѾ�CW>Ùž½ÝB›>’,<�Zå>Ĩ�¾Õà;�°>� ³¹¾ž­õ½VsнšC€¼õ¬¾*¸(=Tÿþ=ÁÄî=òlµ>*–ˆ>à�> ÏÝ=4ÿc¾TìÁ=ûn·½ûɽ±!½Ï†>jnˆ¾»<æ¼súõ>£M~>Wâ£>¬O>”‘š¾Yñ_¾²¼ö½æP?>íS®¾~jö½ø³©¾½i>ªô“>œ€‚>g!¾ŠyG=µ^´¾ˆ¾Ä¥>·üG>Æ;¢=ô™¾ª¿úï…>‹r_¾‘•x¾eæ½YAž¾‡2ý=% =÷¹Ž> ?9Öb>šϽÅl´½”>®<9ò¯¾#g>�¾à¿¿ ·>a·¼ºÿ-H=YaÐ=·×\><>¤/ ¾±tN>H–µ>–ؾB È¾É>š>°á¼6‰¾ƒeI>d�å=<à’=É„>êG‡>°Û¾¢7¨¼Ü}¼‘B¹> ó>!–<½ÔE�½:&™¾YYÖ¾ìe•¾­ƒ¾ <ý½s´>�j¯½ÉS¼µì¤¼$fÐ>€ë4> (=,>üÉQbN�=¢f½ÔϽ>«à¾i<¹ +?ÓžÒ¾Žs$>kîŽ>=�>Cü >A·Û>å>�½&é >&¬¾/�Œ½FÆ=0>É‚×=]B)½?}ø=Mª ¾ 6ƾeœY¾Ó2”>Y5¿ Þ’=ñ<™=�v»>K„=¦ó ¾;?çû7=8œy>6Î�¾)Òh>C§½�~ ½í6=#å>*¨8½^º”½ò Á¼i¾³û½=Å…>|½>½l`š. =5‘¾” «¾˜Ÿ=`? D>¹÷->Dü!=Æœ¾BªŽ=ˆF§>¸6¾6Õ¬=òC(½Ûyµ>ýˆs½ÝB¾± :¿¤ˆ>U+ë¾@W¨¾æ�¬¾ =3®Ž¾žº:>=g¿£2¼OU.?|E=—:ª=ý�¾!“>[ד¾ÔýÑ_>x>®>ë.u>¾9ý>?Á>:xº¾ñ╾õ0Ô¼ çc¾¤Q ?ùSL</5>t—¾�KÀ¾…ŽA>¥W%>ˆˆÀ;,ù!¾wKº½ž|C¸T.?»2J=¿m”<¶æ;¾ÿlà>5Ñ‹=ʾ̟·¾)`> Í=�·þ>Qx»=i/Ò=ሾ¬­>¸´µ¾X¤¾ ìò>\ð½µ—0?jðœ½n<�-�=† >† �>dåýä¾W¨">/3>¢y>û3»½S½—}¾c‚í¼2>ª‘¾iSt=Ø�Œ¾å ö½:‘¾P>ï:õ¾Ï‚=ÚÓ£¾^¿;¾Eý>F½'>­ü*¿)þÐ>»�>Š?’>ÀDJ=�XξvQ�¾ãÚÉ>•,C>ƒL ¿‹¯Ü>ü<¢=x½£>"å)> ¿!>Á¾AàϾj_>S݈>±ó¶¾3‹�=Ž.X¾fÿ3>³xµ¼ˆ={>ñM¾ ¾áP‰>FÓ>•]>¸À>2= €@¼-ކ> K ¾Cs½Ù‚¾{3B?éMý¯Ì§=á°Û¾Y>Ñj½>–&€=�|‘>S¾iWľê�·=ðI7>êb¾ÚT>I@>¾¿’E=™š¿V9 ½h‹{=5Më= m…>‰â•<ý£½¼w·=»¨¾U½½.7¾4º%=š„¾pË•½ÔH‚>»E[>‚žÓ½2=±=djs¾qW¾íÒ{¾Èa ¾ù¼>þhʾö=·åîϾ³ú½±›0½‚‡+¿“�¾¾³b=%i+>ÿ…‡>£÷>(kë>˜l_>RUâ=ÐZQ½W:¿ŒßW½µ‚ê½ÿ¼í¾3M½Æñ¥>äö‰>`P;‰³>Ÿ=±DÆ+FÕ=žT?Å+>,[Q>öy€½jj�<Ë`œ>;Òÿ<úü=Á©Î>)̲>¦ t=þÅC>¤ ->L‚$½h¦œ=ØÒ“¾Bœ½H„}¾"Z„>Áw\¾fÏξFù9¾ {¿SB’¾¯0½çG>ba{¾JÎd>Ríí=CÑÅ>»¾Œk*>ä¿X¾ö”­=U •>9¾ÀÖ¿¾â¶¶='å¾Åà>ï°¾Ð,¦¾q"f½ "å>Ý®Ÿ¾²P]½\b°½STø>�¢"¾û…º>B0”½ãùí>¨x¹¾Çä=ð­=&uƽto«¾:ì¾==Ü=‡*n¾-ùý½Ø¾€µ†>I>ó>ÿðè=Ü_7=#jŒ¾®Ö*=é¾(ýLûÈ=ÅŠ=‡”¿#(Ô¾ñ¨¼ž }¾ˆ“½}Ô=Bh·>ο�º˜>q»¯>L²¾ìœ¾ð2Z<ø¢>HpÍ=Ç{ ¾~À¸¾ÿé=4zÃ=Ç»¾ÁòX=«�>.ýŸ½ðÞ>£}Ô½lïë>�¾§¾�1?õ²¾kí¦= µ"?òY½µz˾Üìë=Ä4>?¡Ú=Ýä¾ýB2¾ú„x>Û ‚¿n9³>æ:¾ØÃ™>R1(>]K>>.‹äºµ�½rþ=‘ȼèÈd=âI�¼˜N> œÐ¼…ê¾Ky—¾Ô†>@ªÕ>K܉¾öí?=|ž½Â©œ>ƒŠ ¾ñ­M;Þ( ¿Ê™Þ=&g‚½ì™š¾¢éÁ=Ý­¾�Æò¾ìÞç<á×=‹Ò=)<¾Þ6¾=s|d>KÀÝ=P�q¾üÙ ¿¥¿‡>´ÿ ½æqš½FF?z†¾ ›¾³ž<ÃùÆ> 1;>ìþm>µðȽ�] ¾1E>W¾Dê®=Ðï²>…új¾ø?½”s¥½Ðxg>�$Š>¤Sž=H±Õ=‚6¤>ú¬¾¦1Æ=ËG¾Ä¿=óݾlÅr>ÀT->šÎ½ånA>fWb¾C%'>€¸P=dïÖ½ ‹>~iÁ¼¾ß9=¸Ë¾Õ³u>ð㾟R¾[»ƒ¾Xü=ÇL?Ñj=§Sm>}ÈL=ãú]¾V`³¾åؾ¼�##>Fƒ½/1½Œ<¬¼v9>$ ¾ àá>çi§½¨Â½m*Ã<êX‰¾¶e>Ö 0¼�b(<±œ©½²RI>1%¾JȆ¾Æ�½ >Ï ?»Œ?|¾¯¾ç=)7e½ÊÞ#¼¼#”=žªÓ½±Í\>R}:>>M'>øÚ>¾|#¾5>šô/>(G>’¾Ö>P¾ÇE9>ã�r>Ê×¢=fº>ØhE½[g£½û3>&µ¢¾‹(�=ÙPÎ=ûÎÙ¾¾>-ì¾M­T>˜"ò=ÐØ:¾AB>þÓ˽H¦­>͘¾ç¨ˆ¼ í—½‹è¾ÌE½k”=uRCºr‰6½SXY¾Ä|E¾êãÎ=ÄRr=Òˆ<”N"¾Á)>Ü ö=�_F>k„½¸!²¾*ä½>4½èÄ5¾‘>‰“d½ò”Ç=³kÀ½h(㽣ì¾ìü5¾R5j>泟=†µô¾!¸}> Iö¼PÝ>~Q>´·¨¾ñ·É=7{6>`ÞÕ=È!o½ä =ïᕽUIu¾uW<=VE{<çæÇ¾MW“>n²)½ƒš¾ëªD> e>¾M^‚=‡l€>ŸÚܾú>ÁAB½Ó¥=Îæ¿×}Õ>ySc>b9ã>dg/¾sI޾˜ù€¾ P…¾l'®½.¡S¾¸Ÿ#½n£—½ 3 ¾$#>ž¢à¼ôë¾-U&¾«gæ¾qtѽÅÜÍ=Ãb>3:$e=±i ¾Ü!˜½£…¾D->91ç¼{mȾìò¾{ǾEØ>“¿=e­¾N¶™¾‹ªP¸Í=æe>ÉêÆ>âYK>4¶¢¼á’?8ƒ=´æ›=Ͼn«½ŸÞ�=»e"¾mUx>v5B>¼¬)=ŠGŒ½~—½ sÒ=nôƒ¾¤Jý³[?_�½]櫽úê>Š=©>ûŒ>à „>D'T>�å¤=•ú�=+È ¼"áL¼Š‰g>Dœ™>p狾\€•¾3Ù�½2¾s¸»!Ó$)ûB¾@~A>3W†=*>Šd¾VXî¼�þ=׬š¾ ö½]‡D¾ß›Y¼Ò¾Ø¼:u¦¾%àºñ:½ífK>MB¾‚�Y>õ±¨>Ô;¼HIA>ó£”½L7ì½ãšh=­?Ľ÷bh¾!Ûî½#’°=‡èß¼-ú®=ᄍ㓽üô½öë’=(œÿ½ÇR˜¼P¡0¾Ý\Ú<!¡>fT¥;e¼ß>�.á=ú+½Žw½Ë]Ø=ï—†=~ôD>@Ù)½"ƒ¾½Â>û=)D>˾2½œCÁ=uJ¬>ÌÉ%¾3‡Y½}\9¾T|ž¾W¹�½÷šî¼R³<æà>œx®½Ìa¾Wµ=gD%=†£â½,%…¾týô½ u">6\=íqž>°”i½'d#¾Øb3>üU¾xä=Ÿœú¼qø¾¡Ñc¼ëý<Ò•ñ;/HN½êá½Eý½qv=‘­>óÞ½Cª™Ã�>ŠË1¾�Œ¾Ô„½G º¾±<‹7®½€èX¼�õ*¾(JO=ƒƒ<–Н½ Ód¾ø‡s¾ÕŸO>y¼‚âœ>hÞÚ¼@g‹¾X=ô¾§ ¨½ŠÎ>÷ço>`\þ¼8̽ÜËŸ< øX=¾¥ö¼Ü̓¼ë�¾‚ñ:¾¿M�=¿\½¾$K¾2v¼Æ˜†½nà_>…ÔʾîÓh¾ÃŒ=ÏK>êI.>ÐZ¾î}-¾Vj¾”ü)¾1Âå¼™Ö¶=T+¸=u/Ê(>Ô†> T½‰ä<Èù5>_8>‘ˆ-½eü>…ƒ”½ʲ9þ9½a¥€=eê̽i á¼ãc>üD>¤Í½·†¨¾ìôa>ú+.>Ú¸g=~‹ñ½G²>f@‡>Á�s¾`ñá=Ìe ˆÒ½!<)½ŽÄæ½Þ¬�>-—>I©Ž¾0ù>—æ>ORþSÄ{¾Oø‰¾�Q>>uFÎ=äoä=$Ð_¾e;E¾ó)>äʽ ü½ \=Œ@Œ¼T•#=Mýk½Ù­d>†I¼u¿=ò{G¾k@¬¾b½g‘\>Ìk¾ï1¾ñÂ<Öqo= 0޾ÞË‘½  ¾¦R°½”ˆ«>‚;}½Þq½Ãñp>ÚF¾PT9¾©C(;$N÷½®ñ½~¾aw>×þ©=è� =ŠŽq=¨¹¨<ÄO„>�¼Â�¡<ýn¾Àá=SŒ¾NO³;Qý½Ô;B>‘¼_^ϽÉŵ=h0•Í=O‡,¾]0®»óçÕ>E¦=ÙÍ|>¸Ó½Ï <½(õÔ¾Û±<»p…½bök¾§üÚ¾˜Í\¾&þ#¾– Ò<-< >JÖf½‚]d¾¾Öl>!/°½Jí¯¾?€¾/œ¼kÒ×<£Ôz>–’νe½Ë½.b¾½�+’¾½Î>8<ç=:Y ¾¡Lʽ¸K‡>?À>æ¼�<^/R>ゲ¾Òí彇i+=„þ'” ×½.ªŽ½Ç¯ÿºðp>ž¥¾Úü!>ü먼å”1¾‚A”¾µò’½ ¦é=ø‚p½D#=� s>ñ µ>QÛ‹>¨ò!?‰*ýÿ°¾I†>Ï-§½‚,L¼b†½^u¢= ‘ ¾ç“=8Ý¢¾·°?>—xO¾Õö·¾¶Ò½ý¹½tK‰<úƒ½;-É>µo/>ÔÓ›<…Ÿ|¾õžŸ=îæ{=eÝ—= M½LÖ½ðÓR<_u�¼-‡æ¼‚ç>!;ö½ðÀÚ½(c¾€‹³¾ìèÓ½>^>Ú‰¾�ß*>Ó´ >b¾M?¾q/>–ð¢=,¬<‘Y{¾Úð¾­#µ@ú–>S±�=?$?fðÐEнßN¾&R4;ó’Ÿ=y£ú¼rø‹=ýx2¼’û=Zý®>ûÆ•;ªl!>;1>=‘žm=“”޾Œ^À>So'¾óôk>®âT=˜_ ¾ìÈ.>­¯½çïw>25>W¬k=*} ¾*ÿ¾�u>%p¯=©¾ ûÍ=&·=Û!Ð:3\½‹"v¾EÍ”>í¾m6�½—ì�=ë±�<4M|;×´¾Üh8>ˆ„ƽJs"¼3L€>ìq€>üX>FUÿ¼ �=Ó[Õ½Sÿ=®í½/¼8=%8>%r>,ð�½¶Ú£¾d�M¾A½V:/¾ä~¼Ûk–>¬ =S?S>ñq‘½$4(¼oVÝ>ÏH&¾qÆ›½ÅÌñ¼z°“=æ]Ò=vê?Ê”Æ=.3=ï… ¾Þ�>¨Â'>þé…>§½y½p œ>ˆƒÂ½Ù=6úQ>Œ‚ð½ûRì=�ªÔ>¾å½&a¾]ܽêsË>ÿ/¬½ËùN½¿¤½Ý.M>² «¾ÉX®=0eŠ=‰/E¾,›/:#ô>å­=½Â.¾±‚Ã<¯†ø½9˜½óݼE¸9=ç«ú¼Çî">}â >Hdž>3ö>cm�>˜›ª=e†q=A1½+q=u°¾bãz>?8‚=& 6¾ÏƒÆ<Âó>)Û>J´š¾CZ¾¢Xj½<ð»u&¾q´½°>¾T‹ÜÌQ>–ˆ>cξkÝe>ˆØØ»¦nb¾®œà½C®F>ù\­<6ª½0`ò½×Á¾­yu½‹Ì?ª¦�½6UçÞ".>ljo>f«ö=Ì‚§=ò�f½ÑP >um`>è¦;>#Ø@½»`X>h>'ñ½ïž=Ñ6‚='ɾÒ3p=æHB=$>Þ¾]‹á½éü¨<%ˆh¿{>më´¼†Ó‡:°½Ï:¦=Hœ�¾sFº¾ÊXk¾þÂ=^ؾóJýjʳ=,Ÿ“>†¬2½•¡‡=R’Çg¾})L¾¼B½=Üí!>Ô“=x€�>J –¼Œ€>>K=—n¨=ñOâ½hø>t”½%¡>}˜¿1µ–>lò¼=pçå¼Ë~=œP4>Ø&վDZà»VêB¾K^t>£¿O>ãV¹=8£½êdQ¼¡· ¼O.Œ½èG>q ²>Jܾîß2¾,­½2_=š\™¼Ô¿–=J¼&>�‘ß=› [>+•ÿ½2‡½ä{;>x’{¾êý;v:8=v(9½U Ù¾˜¦‘¾ËQn>ØJT¾º<Ú¾}z¾éÓª½=Ù\=фԽs9¾ìp‘¾™�ó½[�>-" ½úT}=¿I¼!,G¾ü4™¼²Ð(¾á´r½½ >^›°¾××H=›#¾­1¦¾ Bo¾no³=î7">é“ͼԣ>Q]I¾'% ;F‡N>§fœ½X ¾Ú «¾K=µ;7>°=B>�H�>­Ýx¾\ÆS½Uú=^æ¹½!= ½dŒB=õ¬ˆ¾A±œ>ÓR|>?å¾)’_¾d¬ñ=´Yà=6ø½‹ë$>�o=¥†½Ë»M>ˆÔɽ�ª¾'„¾Ñ ¾vøä>7Ù[<¹Ð >rå³½lN¨¾šè-½fô¾›cٽ߼>â3;šl+>dT>bW¼=rðÒ¾ß;¾³³É½y =•¤u>ñב½{>‰û ½Û'a>˜Ìh=•{½hr>iݲ=ã% ¾EìJ<€Q¼¼VÎØ=€Z5¾¶6=_¥9½vì1>[-¾I/¾W†=©V =ßÎ/½Ü1®>À‹'>ïÿ̽°¥…¾{SŒ>¢4;>hbP¾�™�¾˜Bm>¸½>á=ÒÒ™¾·«™½Ïó>g<°½Ý…i½ÑAï=nGI>ú]>§•ˆ¾jZ¾s“Æ>‡ÿ ¾m7‡>#˜>‹üM¾ÖÎ=¢¶“=ÆïA¾_E½0A>3—3¼pôÈ>»i†=£4�=Õõû<>æf¾åeJ>[|o½Û1•=\±�=ãò=ór>É1¢>е>­K¿>CE ½Þ»ä½à7d½—˜D>>ð�>c‰R½d7Þ<€Îr>}—¾Îú¼z� ¾J*о…+_>òù>$Úw=ሠ¾$.3¼{Œ ¾¾žV>!’=¾u¾¨m"¾�Ñh>†}¬=>ƒŸ¹z!½Ö댾Æï¾˜}’¾“½…=$w佃û=­àÓ½ë÷†¾t?œ½„Z½Ûä¾A>Á%Ù½ôFu>¨Ðž¾Ü´<½fz^¾ê‹J<Žª½Üs|=�4à½X, >l`>ùwW½…8Ô=ˆW >·Y¾4Àn>#ì=R!�½ôY£=­>c>àዼÑȇ¾96å=ÑŽ†>e{]=Gßl=º… ¾ÿ—€>üÿ»+†$¾ð“!¾ ¬½•…[>²©=A¸½·)>Û—=¸¶V=ªl-½Ó‰;*r=†¯Ÿ½F�A½ç3ÿ=ˆ±¢=?r>uù>å]r;©Í½…Žƒ><|J>®^ƒ¾¸7½:gm=¿À·=ÕÝ«¾}ü½A´?=bQ'¾Ôê-¾h½^I >XÐÖ¾2e¼y„>Ù…¾Ç0M½�n†={×<¶f|><Á¾"¦(¾(r¼=6.½Å®>"úµ½­é7>ï¬ïº|J[½×dÓ=A™>e¢¹<(h¨¾â >DL;=2O><ªpÖ½î©R¾U_�¼YÌ*> ùö¾ ‹=P�˜>‰t0¾†™û>ù ϼ°V=õ=§Ã¼¼† ¼KÆ->zr8>%¾`p5>W¾‰Û¦½FA¾’°‘¾i”™>–ç=Ú´9>ö¤=¶‚Ü=|DÚ=Ö0½o»m=:xK>®ik¾ò•§¾x… ½ˆ·¾hϼ±m:n>£«P¾9y ½/ɽEC>a�ƒ½�¾(>Ö!<`S„½RHD;Ý™�>מ¾ŒG+¾–fÕ½E9œ»#nо^3\�@�=í å=/ó¾»Ù;¹Me>”Ñð=_ ½zɸ½ÇLœ= ZR=2ƒ>ÎvŒ¾ÔáR> â"½ŽÇ>Þ|€=RÅÂ>|b*=‘P4=WÞº=@Œ�¾¼‰³¾òÈg>’Ü>>¼;æ9T¢G>Ðl‰w<Üx^>6]>@`Ǿ�²I=Ž„¾C2ù=6î1>¾ž´=Øa«½÷®)<àòF>›‰¾¨çn¾î•î½+~->>˜üøcK¾jH ¾§Õ=’¯š¾a¾÷¾gÖ¾^5Ø<Šù\=2± ¿ôo=ɘ>>dF<:¸½�²¶>jQg=Q.a>ö {¼põÇ=Ž”6=9_+½Ý]ËN1ã½Ç~>gšZ¾ólݽï�>G‡Ï>¢ô:>1Ÿº½RÚ¾î"¾Ï#-¾kbŒ=‰Îƽ‡\|>iÉÂ=×Þ=[(§=ç’½füƒ½ 8Ž�ñS¼•óŸ½ïÛ;9§Ì½LO>"Α½D->ö¾!Ç뻲ф=Ïo=~›½Æ�S¾-Êß¾Öf½Í¾ŸI¾<¤­Å½v±j>Dú×;sÊR½Àþ¼7ñ=Š,B¾µ»4¾ã™�¾ñ–!¾ÓV>þ+)¾ýYw<F>Kú>’¡7>uÖ ?FÀ»=À¾qfP>/¾?ø¼{z>dʾ3vÒ<²‰N½¶®¨=7€=Ôâ;¾ÌF¶=¡Ý‘=F¶�>3(,½¡ËD>sq½ý d½&žš=ø>ÃÙ˜=î¡G>ŠÝ½ÇŒr¾ØÌ¾bz‘¾¿N„½©B2>ß«š=$E¾}i÷=–â½Íëµ½3åT½|ÌŒ»%S >�F¾½>ÔW:¨¢°¾[ñÖ=Ñ¢>F-ü=׫½X=ó½ñ¾^ÜÔ= м>˵õ¼Íê§¾»ò¨½¡ì½š>=køa=¾ü/%×>S¦½Kx¾™iC¾ëap¾šL“Ɇô=5 >D>@×»c9�<ìÉ>ÿVÒ¼î¯æ>N‹å>jVT¾4sñ=ßZ½Ä~T=]q<:�U;§ÀB>Ù%½í~Ó=G‰S>R™>¾$ÆÎ½e·7¾*º=®d¾ÑeŸ=�Ÿd>ˤ/½fÿ×½*Î>ˆ"§>@*Å=Óƒ>Z$¾Gí>Rþ_¾åp: ˜ó¼Oß!:B°ƒ>hua=é¾Í=�‚Ô=þD>îÔ¤<"‡ô½ “½a ><ý_&¼'–�¾vöD¾µ6÷¼»zR¼,E¸=âRw=¾˜Ø=„FP<x!>áT=Ýš <�/>•úu¾_kˆ¾ñî�½ÊRY¾ Y!½,k½Àþšç«=̈½}ÅX>?r¾Q´Ð½Ê‚>vR¬½@Uß=çö¹=áÛe¾õ€½ÑÏ>;j¾Yªá½D ²¼,÷¾ cW=MC>-Ú'=Å> Ñ!½±à#¾»¯)<óᾟ’¾Õín>x˜>¨Ü=TG¾™)D=­“.¾XT{¼i8a½´ÊL¾ œ‹>�›6=í,>c·=×Ç8=¨Ô'>X%¾M…’>§Œf½D˜N=Šƒé¼‰Ëç½IV€½L�=d<¾¿ÓZ¼¬(Ô¾Gâ4<ÞÝ ½–— >²º ¾˜Ï>Ÿò±<‹¾1;urf½¾Ž–>ƒ[g>%¾&u¾¶

Ê^ñ¼¢¡�¾ü*;=bµð¾tÐW½®³>,Ü¿½Í°ä½ôŒ8>žm¼Þ=‹>–νÚÏ >9á=UiA>Å>uz¢>¾T =ÛÇ•¾J¬>žJнZ®®¾�k ¾°ì½^µ(¾œµ>ýÎÅ=â�…=j’Û=M°n½–3‡½«â^¾W§¼j(3>¿XŒ½9ÛÓ<ºã%=Òa¾¾RǾ=}5L¾Êi>Ýq޼÷; >Æ™€½«¶=Ûችe8ä½Ãǰ<~UÆ<3ÅT>w‰7½ã\ ¾Ç?�¾2;\>Vá9u4¦<í‰ç½­N¹>5A›=Jþ¡½šßz¾ž^•¾)ôǽª&.½µ5!½ÈAνxÉU=ñå>je¾ƒª©»Å ¾YF½ï ¼BÄ*>c¾ ¾”5[½Ï‘´=å=9Y½º£~>ކ5½@W´¾W}=Jz¾ü•‰=a[">AÕ’¾$@>ÍZ޽Ïs>�j6>_{U>x{½­à£=RÆ>+O®¾Û_¾)º8>S<á½ñ(x>OÙ@¾6[¾¨äY=lO×=ð¸D¾AõA¾>¬Pоúhâ½w|¼ñÇŽ½ÊÖS>’Æÿ=" =Æ >µ ï½�Ÿ�>D«ª>‘/ż]Ç·=4Æß="�=n“w>S<2>âý“>Ù�=€‚ì½4šÈ=ß�¡¾kÔȼ‘Tš½˜“4½�vJ¾‹”'¾VÎÆ=%�;¡æþ>ʽþù•¾4Œ„>WZâ=þ ¨¾âí=vñ†>Óšn=Sxv¾m Œ=¾Õ¼ …½³ä½€[®<å›:>¤m'>D±‘¾VRýlƒ¾¼ q½Ü>–Iè=Ô-«=Ç®ˆ>Šˆ>.h >¬}7= —>>;2¾Y¶ß¾ö|Œ<ƒ;>^±�=uz¬=î2Ô¼E»]¾îP¾€r:Q¹{¾[qZ=­ 2=%À½Ë4뽊 ­=.BÁ=ÞlD¾WZ�¾Wšd¾$ù–>¦Àù½Ój�=°Ì“¼üÊO¾kÆ#>bgÛ<,²`½‰:Ø» *<-»ª¼(>¶§Ù¾X{½1d(>½Ì=�)>N�=Ó?;%û•½’C4½žÎ¦;ãpI=ÿ=°¾¯Žž½P°Ž=RÁ’=Ò·¾� :O¶Š¾RÑY;‰a¾åh»=K»>ùô€='¹=ZU,¾íIÉ>¡²ò=èî¼¾v[�¼5�E¾ý5½ƒ4¾Ò|“½ß ß= ¾ �²=Š5e¾ÐJÐ;\š½ú«‡>jð°½R,>ZE>6ü7=ElŸgp¾Eƒ¾�>¾:œ.>¯p%¾Á=¼ež¾+ðl½Â�7>\qç=Àž®¾©8> ¡¼»u ¼(²¼¼Wq»m >Në¹;pݽÖʽDº†=�ß´¾©±¾¼°b#>Þ¾ÅãÍ=�Xo=r}>¥¹¾>�>ö>°Å=¾Ü”нƒI|=?'>×®Ç>,p0>¡y¾+}�<œ‰½Lm>›û¾8>B‰Q¾9.‰º­ÊÖ<½?>zá|>_úc=}!¾)’>%³¯=ÿøª=ˆaî½Ào¼8ã½îÕÖ½ÉS"=ô¾Ÿ/>`便{޽R³N>Ï5Ì>øÕؽ¹à¾·¡½ù¿½¯ß1='\‡¾´ç|½Û6"¼>ƒ>3¯ >g�‹>~vZ>ˆ…½æ ¾Ua­=?2ѽÁ^<º>¹°x¾!ZG>Ï9޾c-´½Sý¢;´X¾·"¾Cší½Ö>{µ½ˆ+¾ž³^¾¾·‚=w¯=Aß6¾ÈÊ·½¦ÜF¾Cc>(]>ë‚„½Í­a»;Ò±¾�€•¾þPڽθU=ø9¹½^_T¾î‘»½sµ >] ­>˜ÅI¾5S>Å<î»d‘>‘çÖ>Ctm=�N°¾.z ½õ_%=´ªÐ½œŒZ>Ótß=Ý_¿= ra>§I> Y9¾¨z½¸Xï½ ’@>.Èn¾±0‰=WÓB¾¾-¥½ �¸<š‹Y¾2ݽµ—/¾‡²à=E³½¸5l=Ÿ‡¾J4Æ=ü¶=m›¬¾M»=±$q=Ïç2>O¼È½w{ä"“Ã=ºV¡½5Žq=‘:¾ºX3½Õû=d-�<>"€=š‚>N>@Š2¾É[Î=k�>¨i==ÕdŒ>¯‚;vW>qõ=)×À>ˆÃ½ûÇ;½@d½p§H¼8¨H>4e�=ä•=óª>n8e=<ËÑHÓ¼‘'½Láã=4|€½b�½9£¾I—ò÷Í>)4n½%Я½ò¾B;Ò=dœn¾Œ¨½m€¸=qKé=ÊÈŒ=¾`l»* ¾„H¢½4^¾XÌ>Œ#Ä=ˆT¾Av¹=h‹½},x½4!¾½M°÷=så€>¾½E>ý�x>³E”=Œ)½m�;¾†9½¼e=>5WP¾Û×¼Q_I=—ã¾ò½ “㻿ۻâU�¾xN4>ä;vÑC=·7á> Ê|="|'¾œ‘¾©Ä=jY.¾íÁ½(“f<^g¼½É–š>¾Á=‚Åú½z†>y¨¾†û‡=‹>µUL>úã¿®¢>Km�=Äú¢;ØÙ=»Ô$>h�’¾Ê�4=c ¾‚ľ۬A>õs©½r…Ï<­“Ÿ½ªV¾Èì½>J¯½w·b½Kx ¾«Os¾9-…>Æ\¬>Ú-¡=ÇEE¾ô‹»Ò@3¾D+¾ªL>�›=Ó°»Mņ=¯�ª¼¤�>]¼O¾:ïF¾oŸ<>¸™.=E„[=åÞ½ {¾}x0>j¦�>x­e>bF¾àÛ>«>ܽfœ=¹�2¾—M¾ùBù¾F©=—' ¾²&A>܃>¬ºk=¥þ>?÷Ó=ù²v¼®ÜM¼\ÿ½‹J½êTÃ=¦ëÿ=óVK½ùó%¾�T½gÚ>êG=´ê9={Ê7>¯› =§o¾s¿—½ÕVå=ÒOn¾ùá²½A»'¾ëÅE½�m�=¢M´½:B§=O01½““­=ö{½3Åʽ¬@´¾Eh½\Ô>œp½¿ ¾[®©¼SÓ¾Rçl=@ ü½ÚY*>±P½ �ó=✄>G§B=AÊq¾ž—°¾Ž%Ú½5ær½•îì; ·½¢¨½3Ü>ì™?. Á=½!ó½�W¾®ðv>‹€¯>’s¨=w“œ>>Ž]¥Ì¾=¨ >1‡¾Ø¢> –y½ËsJ¾Ä6ˆ½V&‹½ó² >½Àž=oÛ¾wÒ½N¦ >´R¾°n=q‰>¾ÃA½'=j¹¸>nžp>&à5>*Nf>å4÷½€*ݾFuK½a@K½/ïm¾ûƆ>C¦¥¾Þ¢ç½_ÉE¾ÊêÛ=<#>¬€>§Ät¾Ûs ¾´ÎS¾‘4W¾ƒ\>µ~?¾}†™>€ˆ@>"rÂ<ލ=µa�¾ÊG§¾æøÔ½gØã¼‰>Éôͽ/Œ=F, ½ò(À>’Ež>D³?¿ƒƒ©½Œq =�VÄ=8ù2½ßlÑ<žFO>ô={Žx¼ ˆðºš�>Ó¡“>©}>·�<çϽ+Ђ=8øC½&´ã=­é¾êˆ(¾Qi–B9V<±ìô¾õ—¾-[>†Å¿¾ÃÙ=m�½Q»Ì”†¾ª �½4…;>�dt½�‰¶¾çI:>�ŒU¾Nfº»®S¹óÞ…¾7kœ=ÿ55=Ø =©¹Ä=í>t¾MK=>¤GD½¬ù>„½s)/¾óÙW¾ÀY¾Æ„¯½º8>ñÞ¥>ðKܽ<ýa¼Ý´°=O_>3­Q¾2<Èp¾LR¾ˆ9¼�—�¾YWÉ=î½(77¾ñò޾z Á>r„�¼¦ ›=mK”=0ŠÕ½&�^¾MKÙ=Ó?*=ã-r>q€q¾,’¾‡Ÿ�¾´ÿé¼k6>/U>´Šm¾ºáÆ=8F¸> gÌ>�Ž>¬|>uJ>�Ž>ª3B=+D>t}¾u# ¾K†Ÿ=;Ó—=ünˆ=˜Z>¸SÒ½É;¾´¦>vNó=�2>Nc—¾t Þ=rÏõ½Ø¿J>1<°¾ˆuw¾©*¾[!Î=Þ<=À­Ç>²é¾é�¾’½îðŽ>«ñ>އD>x_Ëï=½+8i¾VUQ>M•¾rž€½q>¦>1J�>u7оA!|>ڰͼ7?]hA>\&=§T=òÙ°½k‘>iÿó=ªó¸¼iwŸ>ã¬M¾¬Æ0½bò=Tœ¾ÎÁö=é[ =þÉç½Ã-æ½s¹Ó>\½†½Â³ò=×®Õ¼ ´ð½4çC½šš‡>ë ð=~]í¾¯Œ=�¾Ú<£=ãÄ<›¥½ðµQ=ʌݽÒj÷=³Š•=£‰Æ>‡µ>”˜=)Ó—>Žÿ轟|$¾ùl‰¾EÓË=’ö‹½AÍ>ÑáÀ=ßlÉ=¿F�¾Óða>Ì�I>–›¾†Tþ´º;,iw>7.‡>×hT=÷_>óML>`§½Eª½¼sоʾ:äÌ>>Ôv¼N9¾I³)>—ô½ã;¼~®i=\¼=ñ�Ä=Íà¥=@�<›&ž>›|ݽ6’¾…“ˆ> ­ä½È¼Þ;DTƾ­B¾î(> §+¾Uq޽™T>ê<ú=Àݘ½¾ô>±y�¾ pö½y’>¾Þ„Ù=î§Œ>�“¾  Î<Ýþˆ»ëQï¼AÚ»=�>-÷o¾ßv^>o°3½÷µ½ P >V ¡=NP²½»K>9ß; �= Âû»�v=N7Q½ÖX= ,¨ºêÐ+>OÇY>À�h¾Íu�=ÐZ>7ÆK>¿|¾ÃÄܽ¶_P=Ð~”=¦3뽫 æ=MV(>㸪½ýß¶½!Öm¾f¼v T=\#¾Â�ž¾ò›Ò½ñj?;Tl—¼·Ñ‚¾qqˆ¼)*=BŠP=»üÃ>Œü½ºì°¾œa<£:|<¯)>b~¾ÿF½èg¾¡Þg½Mª½”‡=èï =¦'Ž=±½£¾˜¬½Z/¦¾ý¡+¼úé°¾c�c<ŠtÁ¼“ë=ÎXÏ= æ>mr�>ùœ=>i}è½¾º¾‹_ˆ¾ƒ‚E=e˜ì½b¨‰>!f�=Óû ½Yn>¿ÿù=š†¯<ÀO¹¼ø=2�t>E/7>\[¾ö•Ó<ߨû½&O£»@vZ¾ßz>l”¾šmŒ>^ªÓ¾Ç¹8=%êN½ãžê½×òª>ÛQž>\@¾‰1>Ly=Ðú½ìWM½ù‘ްÕd=Ð&>Œ‰Õ=Öúˆ¾Å¦½s7 ¾Âç]>“‚¸=Oˆé½©¬<> ¡N=œ@¾½Ìû< ºU='h¡¾3„t¼[×J¼O˜ž¾`)õ>u ž½Ì‰¾4RK>÷f�>¹E >¥˜½µhò¾~¶[¾æPŒ=ÎÒá½t�$=:·»\�½a«½¬¿û {½~X>’2>›öR=lm‹>U½»®¾N‡Ë½Vþ»;q¤¼DÛ¿â+ý<Š­¦:Áß½w¤¾0-¹= ?M“¯.ý|=p>lÌ×½Õݬ½ß7>­ƒ >l.ñ»‹Q¾÷�2¾0”¾IþŽ<�¾� ˆ>6?½‰D�»ÖŒÃ¾På=žo¾©y¼>ß¿>jµ”¼xq=GÁí=—=?ß8뻉h�¾«)~¾5ʱ>x>Ï<ˆ¾šûƒ¾ÿy¾íöÔ½ÿ3�>ª‘½±ð#¾`i¾Žƒ=/Þ«¾sE¢½LG¼7,g¾—h}¾:û-½ž.!¾C²n>õ�ˆ½U¸¼l¼Ë=mß¼š¡>FÕ¯>Ì6“½ ÞÀ>¤˜==®¾„ä-¾°jJ>0ÜY>÷fǾÐ*–¾c%><ú{>ÖN4¾7¾Î鿽�nË>‰8Ð<ò¾<Ó<¬™‡>~T=Õïÿ½TuÂ=8W»=lô$>1í½(¾)ÕÙ=©wã<Ïc>Þy‚>Ëî4=mY½ß*ˆ=ž¤e½h�= àµ>ƒÏ>–ºš=àñ¾·ö>áðF>Mìϼ•_\>HD¾Ô ‡>`´˜>è¬ï=~ù­¾Þšr¾/h[¾€n“¾¹C¶½ �>ÇÇC>3¼�Ês¾9¨½%;�¾Îz‹½¯Jî¼¼ŽÆ=ʈ½Ñ>jу¾Y'\¾vˆˆ½Lò¼Ô‡>�'ƒ¾ü)©¾ áD½;O-¾È⾫ùn<¸’9¾Ç™=#ÕÊ>BÁz>PªN=ë[j¾%¾Xš= Ÿ>OãL¾ô_£>#S=g!ÿ¼Y ľ‘ÄM>� ½¯8>ÊóE>e_< fü<ë=Äß<~­–=Ñ_L¾Ææ > V>#¶™½H¡½�+`½ýÿý=lƒ¾õEœ½HEƒ¼ía>¤�’½ÌÙ9>^1¾¸¡½¹Öm>êš¾n>A>vüÅ<Ú¾»>"N¾Ãä»yǘ>s¾‡Ë?6Ÿ>â%>‡Õ¥>ÝHi¼·[¾•z–=Ç W½4Z½ªèÊ=+.>à8ؾ]}{>4o[>‚šÃ>!æ=bJª=ôÍ¿Y¾ïó”¾!åö=»–Y½�çN¾è¿Ú‘æ<³~C¾¿S5>R‘>xN¾y쌼úë¬M½‰ µ>tùt¾ SL>]9°¾ntË>® &=Äx¨¼ÿæÑ»ë\>žÄt=ç À½u¬¢¾ÖÕ¾ÐuQ¾¦t€½•\x>–ØÊ½Bp±¾èóé=QŽÁ>„ùÚ½ 挾*j„>ha9¾ ¡½«Ç>æŽï=Fæ¹>–ª >ºѾ¹Ì.¾ü­¾§_=Ês¹½Pú½ð³J>»©¨½ºð%<Ô݃>{ØÔ;-9½†ñ•<�¿»=áª<¯§ >¨4W¾Æ+ò¾ï2Ö=^ñͽXp>}bÓ=Êå³¾Ù­í=Ž£(;bš†>JÄ´>Øy€>\X›¾^ï.> ­¾”½ãš>O!µ=’ ¾ñ*>Õú½:‹—¾!|>¤Ð½›ÿ÷=ð—6>x_>«œ½ºÉˆ¾{rp>cú=Odì½ì‘=�µ�=ž²x¾jÈÒ=§#¯=Pݾ m¹>pŽ¥=aª¾Vø½Y¤Ý='£=)Œi½…oV>ÒA+=KïU>ZoÖ½\ü¾H�–¾hdI¼Šå¸>©È9½ð� ½ôr¾RÊË;˜lµ¾§v­=都½èt!½´ÍC¾ø1Ä»¹>s¾]½=oT>½ ”>Ï®�=÷#>茱>ÄX ¾|¾�ê®’¾_©Ž¾Z'T½ñsq+“¾æ/½Y…!¾"ñº8n…¾Ž=…¾˜ÖO¾õ�¾hH�½ëL™»ØàB<ÐÔ½˜Â=]Zê½jÛ>ßžY>ïYn½á†=kþóª>óÜv>{í’<¿>ô¼™�¾ÏA}>ÄZ>‡6W>”Žæ½`E ¾ˆª§½ìÜK>siŒ>Se¾¿iú¾5ƈ>ŽN꺋1>¡Ö ½¨ >1–„¾‰<>*2†¾óž=f™>“#¾É¦®½wÓ§¾i8>‰ PêIÿ=}\5>çªL=¡ؼnì'½Cœ¾ô S¾îË<àg:½4Å=>#$ö½y!Š<(rD¾þªÑ½¬µÚ=+\è=9„">¦„Þ¼s~e¾œÁ>�ãð>ÂÂ>à>"?T>�¾Ëc¾ÖÛ­=ix:`.ì¾ãÒx½3¿²=ö*轘Áñ½gK¾“ñ�½à'9¾šºµ>B­ =³ >½—æ�¾m‚=a‹v>þ©>@­W>ÑR´¼\Ýh¾Ô½]>*c>|$±½ ž{¾Û’¾>'E²¾: ù;ˆOë½Ö�Ç®¢¾œÂ!¾áal»°Ç ¾ST]<8£�¼ ]H¾d•J< ’‹½#½M>û¡<‚ë4³ö¨>;|>DCl½ø >–Y–½*�·=~*`>Ž(>)¹½¸ÂY>+èž=Qâ¾×¹¾*—?¾{òƒ>·™ô=Y¡Y>!ݾ¼4N̽Ï®½Ï 6>˜V޽Öø½Šè>©«V¾;¿‡»‚)ѾUlL;»ÝJ¾N$E>Iì¦>$�¾¾¡üi>]À:>½ê>=(#Ù½ˆ!˜¾U)¸=2³£>Šlì=Š-û½Od½åþR=Ö�¾ðÙ¼€@@>{³½ã¢[¾QÎh¾¾Ø†¾åeb¾p@$¾eÊn¾¾ž›¾ `¦¾ÕfÝ=’Þ=ÿf>³rÐ=“t2¾wêǾÒnú=È&>`°Ý=Lj�>÷ª½ì6¾¥4B¾úŠ´½ k¨;3ÀZ¼Û‹E> e >À >õ>=>%?S®�>g=¼ùȼó2>|jô=³«=Ôß¼úld¾1[¡>L!<¾š›Õ<ïL>ªxݾªˆ­½�LÁ=¢ˆ€¾qžî1;¾X`‰¼³“)¾O䆾‘ñ½“ˆØ<‹�Ó½ÚÙ[>Ïý>Â…$=ìEì=õˆ¾È…ª¼{o =cB‚½›± ¾»}µ=fÈ”½xÇ ½ZÙ½êS<¾ëaë=t2†¾Ýqƒ¾vãa¾Ù–<¾wU'¿{˽♗¾¢dß=Kßn=W·n>¾j ¾�¯«=þ‡n½r9ä¾&A“¼®ŽÅ=Àö»¥9L> 0>œ¨>`d(>{­é½+Žœ>|رdÜÂ>ûÈ…>¡H¯>A>šq¾{~C>~=$Bº>X2¾%|�>Ñáï½Íê=r¤Þ¾î[!?·Ç—¼Qƒ]¾Ö®½Vo>eÌ’>çÆ=@;¾Yy+;�¾Î› ½d‚¾�]ˆ=~ ·½Uo*=`éà<ñ¯=�»s>HuI½e•�¾‘úÙ¾Or£¾¤,o=Pˆ1¾9 €=ŽÑô½[j¢½ÔæN¾Â0>~X“»rk,;.|š½‚r£>n¾MEæ<…øê=†U;H I¾uÁÐ>zyõ½Ÿø¿Ñ‰÷=¡±Ì¾¤Ä•¾¯J“¾tó½ ×ï»ëj¾b$`=…'¾WKÍ><¯;†½zŠŒ¾ÏG'½ˆ3>Ù:`=±H_½_{⽇’];S%«>Öæ=å%¾ä`꾃CA¾ÝU=N†¬=Ìœ=ƒ9È=l½Hãš¾?íá=±yŒ>›–¾Ï*ÿ½±é›>ÃÈ>¿%–½þÒ†>p ƒ¾d¸Î<ó—<¾]{=¼‡p½½U½Òƒ½Iy²¾ó;Õ½'îj>äO�½k Û½´S}¼ŽN±¼�¡>ëª3=õ�M¾FÀ°>>N•½¾c¿>®[w¼°Wâ½ÇZ‡¾Å…2?ß�T=“?SL£¾2šâ>Ÿë½½Ò6>¼~|½Èk;¾_ì´¾ÛF¾ð…¾ÆRÙ½ˆƒ>œÿn=äð½gÍF>`±"¾’‡¾ 7�>^Ù·½¤c>Jð½Šf >ëº>u,G¾Š<â¼�Æ=䥠½ÙÛ¾=ècÛ=⨼f»B¾‚é/>)u`½â€j¾!h ? Â:¾ì¹+=ò2¾VfV¾ËI�>ûô�½½¾35¾÷¬>Ù±>ˆr—>Ð¥½±S1<ê$ˆ>Ü:<:i> ×½bÏN>uÖæ½Ð~�=¼¿µ½Ç¢»¾ëÀ¡¾Ÿ2ß½Þž>‰Nc¾‚øâ=šœ>»¾ÝùŠ=òÛ·=g·>:^>¯õ…<&5¥½Ä¿ ¾^†=pZ>€);¾¤tμÙúŸ½ÊÕâ½%f_¾ñìÔ½ã�¨½Mu¾¼U[>”CÀ;M{>`½½.L¾*ï°=„O¾¾®)²>b´>?ÜÃ=J«\¾”ç< ¾éôç¾ßÛ=+Oq¾ÙšŸ>£‚¾¸×g¾]Ñ5>�PM>ìA ¾Ÿ¾ >n½�H×>ñý¾¥˜>XZ|=õiâ½%¼Å¾Þí¾”³¯½®¿=�c>Æ“¶¾E�9¾—9 >žá2¾Zн>ð>*~‘=P� ¼ÎñĽ¨E‰½Ò{òÁ&Q> !¼¾ÊÞÔ<Æøú;œ4>tì·>doF¾ü_>�ò¨=òö¾¢=6Âc=1Š>{">ùuP½¡µ=¤Ú1>("(¾m³ð½C&½ ¯>jØ¢½¿'о—R ¼aù0¾t4A¾d·É½7 ¾�N½Az±=Ђ>®`¼Óqé½û¬¢=ò“>�„>ЩŒ>¾¥T¾–q³<`Äh¾—}¯½Ò—½¥hÄ»rZ*=„d•¾¶8>ý�=�øð<Àݾ½öôH> Q,>„4Û½Ùˆ¾U¢¾r]O>`ß(>£™„¾¾—ĽòøS¾6dÓ=¹a»f\=¼²Ð¼ƒñ>«ž>�m™<î’=C æ¼d䨽©2 >ã!r½éÍ9¾ò¡°¾;­¾@xÙ>% ¾bé ? 8A¾<�¡½õi;¾(ŽÝ½1Z¾‡¾XŸF;µ™>OnB½¸UÀ=©œ=£>¢Æ„¼›nm¾àa =…ÑÐ=Œnƒ><ý²>•å§½L~#¾_o>@;=³ Ò½{ÀÀ=Þ9¡¾‡§!¿LÒC¾»Ýñ=�­¿¾v¼´½Øå¥>¶ë½—‚W½)ǽ¦-¾ñµŠ¼"L¾•á?$Š ¾\£'=YV=¾z9ô=l¸/=&,‹½ƒU¬½ í=/Óš½Ì&ɾÿbé<1ßÇ>‹É†½å³Z½·Ô½¿½ >$Ÿ½Ø5¾a!þ½zü»=Ôù>-uݼZvœ½føè½& 㾑!z>ÅÝ/=‰id>,x®¾/œ´>(X`>æeR=–ˆŠ<”Õ>dÅ€=?ž�=n"µ¾œõ!½¤W>hŸ< Ö;áx‹½mé%>øK >3®¾ûê¼Ð‚¾Šï=÷ì¾Ê#¾¢ö½Ÿ­>ºg°¾ÃV½´é«>èå;>Æ|$>t�©¾³ú‰>CÏ>šÄw¼È#å¼&Ç=Þҽ̊Q>Ƀ¾ j.¾Aƒë½…—>RT=¾º¾:æ�½1+Ù½<5l=Ä>«1 =ƒÐ�¾ŽŸ¯< ‹>}š§=V”¹¹¾ü¾ú¢¾Ho¾úï–¾|·ª= l9>Z)Q¾‡‚>4øE=­œ˜½¨—¦>]Ü@½È? ¾WF¸¾Ú‡¡;Õ)Œ=-Ð>æ÷›>ñWÁ¼ïbX¼Ö$սƶA=ù ¼tä=àMÚ<“gÌ=!Í™>„+V>¨M ¾<–6=oÆ6¾ù„==œ‘'½}@¿½þD>eÆØ<Ø\>¿¾�;Å=W?>66D>ÿ=t<æŒ=>AÀ`¾‘3ƒ=>{&½Àþe<T>áò{>A‚‘>-oº=p�ž>AVÐ>k~>¯n°;è DºhΓ=È}=ï¬I>(ÎI=Ïhm=Zlr>géü½Y¨Û¼I›¾éÛ ¾j9º=ñï¥>²!½�õ_¾& C>í4¾þ#À¾+³Ä¼BE>ëþ¦¾�¦Ý¾ßŽO½„6½e»ü½�±†= Š½x)=»¾š5>/ÌV¾¤&¾5¾é•A¾Šæ>1X/¾yI.?³`¼=-.½²P[¾Æ.a¾ñ(¾­9a¾wâ&>­ÿ¿É—>¢Å¼Å¢>�³e=å¹B=rL ?¹1T>¯>!¾q!ξUäß½¾°E¼Q½m¾aÿÿ½‰ø ¾£Ç>ÉÆ¾û†=,)‹>/ß>¥„¼t…¾ß”«=™>�>wî=+¶>ÁB…>dê½Að”¾8 É>B “½ö¾×w¾Ý^a¾yÉ6=Åaf>f€š¾Jx×=;sO>2(½]1>h >Ox¨>¿v2>HÈ#>z=;ªÇ>£!V¾Ü²´=V�½5¦Ã> ˆ¼Œ¿ .Â;MK^>éø> “½lö$½ò» ¾/™æ¼4d¼<›[_¼¢ç,=�‚ó=2ý­¾a/>'|5½lÌï½�‰Û=Ñ€-<ªp�¾ö�=äBN>éOš½˜ “>ç¦é<:½Ø¾7Ÿa=iÎ.¾L<×½ Õx¾F+>м[>»^¼G‚8>› +½9 ˽V]�¾ÅÝ€>ø×[½ì£ä=Fïo¾×Èê=°Ö>˼„¼í¡¾™s]>Ó¦½w<œ=·û!>ÿ†¾r6°>X‘¹½À¶Š½¬W>1Ĩ¾š ¥¾e�Ç=‹\Ľ%˜=î½PšW=W§=Ÿ¸Î¹h½ãÚ‰>q¾`½ª´½®òZ>¥¿=¢;>ªê<Wë¼bz6¾Q“_=¥8n=!Îì=§f�¾le޾ïŒ>Îg>Yìn½©‹³¾€x¾¸¡¦¾”œø=n>gb©>ã¶Œ½ivŒ¾ÃA½ëó—=φ�=s Q>áÇM>š8x¾öÍ©ºe|ý>ÊÎÍ»R?Ž="wò=ïêð½Ú̾Ց>•ô½©7%<2½>®Éú<Ä š>H&½¾»G’¾«õ>wÑî½òžÅ=¼Õë¼_瘾 5f=ˆ¯½ ·=‰¤>âî$=#PM¾¦«½¾<½qƒ>ÁÁ‘¾©Zá=g÷Œ>¶ ?æ× >˜.N=-q¾a0½>&ˆ…=œÓ½àÔ˻Ȧ#¾Ã»i>ŽZܾ�Ui>Õžè½¡)¾c�E>6ʺ=‹FÒö>H—=ïψ>�V?n%)>îüw¾!á1¾ÉË/>-K̽Dö\=tEH>mKz¾D�>Y†é½]œ¾Ãü˽3NÒ<íán»—a>CGw; …>ƒÖ¼½Y—ý=<ö]¾/ù¼SC¾ô¼´½hOï=ä0>î>tþ=i!«>¨·µ¼œ::¾©¬°½½y>Àw¾Mdâ»üK£¾,:>&Õ¨¾² =‘Ä�=ad>—;@¾y9‹>€Á‹½*Q¾#]�¾”z >nCc¾Œø+¾yA>O>Ä»=ò.¾ñ.B>1„ä½ï*½l V>¡oß=Šw®>ÜKí½‘>ûÙ->˜{â<(o.¾”,À<±x$¾èy ½¬ø!>Ôr1>$¢=ÉIƒ=ªE»=Ì_<‚þ"¾ŒOª=`ù=½76>âÏ?¼¹÷¼do־˺D<ùéF<íX>‡gš¾›ä)¾d\á=g¹;O”�=LÛ¾]¿¾×ä ¾ ÛJ¼§Q°¾=Ô»->l, >CÜ8=Äl½p ¾=A·¾:«Õ¾éF<íý>>¤�¾¡"I½‚„ñ=E8µ¾¦›3½W.%¾•v¥¾�É ¾i¾æ=K .>>¢²½ð¶>¾z<Ç=lÅo¾1Ñý=½Á½Øf>á¾>+sÐ>°T¾ ñ=�ü–¾ö·Í=³“`>ÊÅ4½À„¾@o>»±>¼žÁ½{îZ¾ ãw¾~’B>r¬P>Ô–X=»B.>ë�Ÿ¼—Ùûø2{½ ^`¾*Á½Uù=¼‰y½qÀ�>ÂVt¾Öqú½á"¶½„�ï½0iw½†‚'=ÒyL¾±š‡½«òó=ˆ,>ùC·º~Œ=¾Õ2¾`ݽ*=>Ý·>r—S¾½pÕ=Š ¾ñ‚_>Æ�c>Rr½Ý“>¥™¾s({>\Ú„<+˽-_Ï=³›VGÄ»XÝj¼…!5>Â"1½²5½¯ä^=¥²�¾¦c0=šZ’<¥ö ½ô££½„sž=äð7¾íc½K°J¾Ÿ>ÔØ„¾ŽÓ¼;s×N¾Jnù=ç=Æà�½’u<¾ÐÙ¥½¡Ûƒ>¹ËD<9úó¾dƒÏ>f1?¨îÑ=jü><æk¾!‰&¾ ªÔ¾g菉GŒ·½qúa>»y¹=Ñ£>>ÁÜ>rÔ#>ãY¾™…‘¾7²¨<¨w¾°½$㙽:f= yÙ= ³`½Üá?;I¶Ç=Dž.½û—ž¾rG{>?¾�I¾³›Ø»¦W\>ɍ޾Mú(>#í®¼>*œ¾HžB=*�a¾¹¶¾ïx<>ÌWܽ¬»K¾Òv§=?ãÌ=…jýQz*½ËçŸ=Û§Y¾�i>Zj>ƒd>v¾!ë9¼¦:�>3 ˆ¾=M´¾\·=.â=«—H=®‡=€0—>ï f¾õ×<^Û‚½g?¾ƒŠJ>5Ú=gí=¹Æ‹¾­�½Éù#¾pã=gÔ=÷T¾F„à½G�„=©Lv¾ìµã½CÛp>Чë½ä\=€”>>”=˜µ¸¼º�>10½c >�G˾Íçá½ßZ=>Dºt>!€r¼¿¥€»7¾[·¾Ãq!>še¿êà›½D[ª½ U>´à¬¼ëñ½ÀàÔ=A–'¾MQH¾�9Í=t3‹½ÕyE¾Øz¾…�½3¡“¾éü`¾ù>™Êà½,}Á=ù š½¥¥Ê=ùF)=NO =º&¾�¯¾©éɾþšä½Ÿk ¼ Ô¼Lfé½€‰¾è z¾»·Õ= P\=ijŠ>…=pN컀’"½FÙ}=ú·‘¾`>ƈ=÷ü=úP<>¿¾sª`¾èï®=ÏßÖ½MDR>�®m=RŸ½@p2>½ö¼eì<DÒ¼¥W>MÛŒ¾5Å>/|8¾&¢=3æ(½Ý± ¾�eÄ=“+ÿ=R —½“o‘=Ιk¾Ù`->‚w¼… ¾©¼S>X}½eм£Dº=l¼|½D˜D½’<ý=7}S¾ õ)¾Ká=i_'¾qÍU<#d¯»$€ÿ<„1ó>°>xåhG>Û²¿¼ Ã<=°5½W?V¾–Ç­=~ñý½Û]¾àޏ;¼Ô;»ü <�^¾=ϾßX0¾‹u»ÈŸc=&о&”&»Ð´!;�z<µÈX=·A;¼{6 <\Ùh>‡h¾à’.¾#Ò==PA¾Sñq<§L¾Í¾ó‚ç=›·P¾þ|�>–Ãc=}‡=3‚޽]Ss½$ƒ¾†‘¾˜!á¼´¨½‚\‘¾ïÚŠ¾Âw> —½fQ:¾WÒP¾¦;7=ÉT> &>ÒÓ >`v‘< :¾<ý5-¶¼VÊL<SÚ½ à?=ª¢Ð½Þ.8¾=(Ó½k¾Ò3%N½�ïF¾2>�Gs½Gr«¼Ú–V¼§“†=†Š>�™½³X>£²û=y\â=Û[ ½_Ž>›(>«Ê=¸µÌ;…¶ä=<Œ¾æ Ä=É;©S�<®|,¾ÑþÛ=¦æ+½/×=Ÿ8v¼çÁ=¨¾§>ÈÈ€½“_v>¾Gd>²Ô-¾øÉÞ½.?½V‘…½6Zp=Íýh¼Ž¾¼›Õ>8·˜¾ÄÁ:¾{!€=ãݾ�0Œ=6¾EöS½gåS>­G>3ML½×`ù=/Q–=Ù8½‰3˜½B¿Ð§½Áµ€½†c/½°Ôô¾4Öƒ½-ïª<É)Ï–ˆÚ½nŸ¾f‡É½·�>=è?š< S>ëµ]>¡>ˆ=ˆè>ßÄT=<¼�¼ÓÀ*¾¿Ü¬» n¾½Ãî ¾6HS>9@×½ëó޾Â3œ>ùÇJ=Ã?=>‚í ¾±M”½¸¢Ì=°óO½º>À3>ð­§¾µ•Ÿ¼Þ|>nâ=³Da>Ê‹�½„ƽÎXµ=Òv> #@¼ÙûÚ>(¸`=¾`D½Ó´>GÖæ¾ž©:¾Êk½ˆ×i¾ŠÉ>ÛW�=Ô'ަž¯>Ï *>j �½:ä>}s>Rýø=¸L¼Ì㉽"�¾ 1º>¢<x‰>:¿U=8Ìb>*�>o"¾D¾x´4=z;Ê<9ä½t8£=L)§¾;`�¾ˆ,t<Ï2#¾2´F¾ÐjŸ>Lš«=n.ƽÚa@½EÃn½ºÙá=ªÞ�>/×=‹D>.ÞL¾áȾ®T=a4¹½sì¼/ŠŽ=A5¶½ ¿>ÝË…¾¸¬Ì¼cý¾ýFë<Sn»—9¾œ¨7¾ i>¶û¿“¹%>˜%M=ÖVZ>æ ¾§>š³•:[Zì=6ëa>õB·> ½0>V§^>Ía=½�’¼Û ï¾€?=XQ½¡:¥=t?å¼Å_>r :>ŸÔ=S5>¿µŠ½(ê+¾É¥Â=�]Ƚ">(ÿv¾ž{Ó½îe=°¹W>™}¾5¾`N'¹,‹§¾¿»#>À‘D=ˆÆ>Ðç*;·¾>ŠU=ÀQê½à8= !¾*Š‘½o®¼Õûl;@Y >Z|z¾ºè€¾�®¾S³N=cÌ*>Dó¾G¸=™zu=böÊ=xà�=GÝ ¼ÞZµ½8Ø2>äà=Â÷å=;.¡=S†>Yœ.½�î%>X²=Y“k>lË]½VB/¼Pœp>…aU½¡Áä½y_„½åÊ>ÏFÊ=øâŠ>錨¾§h„=Uà(¾õ€¾ÌÉ„=±|³>DR=!’>7<.}�=n�†½ÿ#¥¾ZP>³lg¼ú«L¼ÚðŒ¾âf¾r¸¼ús¾gœ>pŠ€>x/>"!»¬ú*½‹¼øR¾Uï1¾~˜)½0; =¾ðt<±žM¾b’`¾©�>1hE>Rè!;Ŧ'>&5¾îû==9оf�xºEŸ<)¾Ì¥º½écϽPš¾bÄ^>¶‹Ó½É…9–þj¾�5>õ!s½vÞê>)ÖG½³6•½p>ƒö¾ŠÖ©¾È×ܽ6*)>¬öX¾ä³Å½ÿâ>ž1¶>WMD>«¹b<Û¡*¼Óú¤=�–¼È=-¾¢V—=Ezˆ=EìØ=m¯þ=ªv¾ÕH¾£ÁÃ<žo=ÐÅ>8®< SÃ=ŒD¾[9¢>¿iz½O ¡=ò>j–W<Ç�€»O‰·>‰ª'¾‡êÓ=ÝÚ>ƒ‡>éG> H‡¾­>0f9>¹ñ1½Wö ¾È‹Ð¾6Ü»=%QY>-ý>Á½õ6¾¼kF<ü'D¼* ¾y¾ç1¹>Ø]½aã>�߆¾&!N¾[>U >Ïø>ºçY¾á˜¾ç>#¦®½×H4¾æ¨½šrŒ>â›è½¤:m< öP={騺v±õ½4˜>lY5>c0>”äð½kœ½É’¾­†¼>ó‰=T§Œ½š1G¾Òe�½‘¾>Q”=7R'=öQª½ôœ¾¹½…®›¾Ê(ë>lÛv»Ñ�`¾,àÁ½¯c¯=H)<½,µØ>ño¼=ÿ\®¼éˆ<»D>AÅ^¼i¾ ¾tã½Ç[νÈÛ< 'õ;è3Ó=ãÿc¾‡^>ž“=k}=£»™¾M¾æ°`¾ß,=ô¢`=å×>ºX£=¨�»¾ž°Ÿ½t{">Øq!¼£§¼H¤>ì×=w‰ >­Ü0¼ e¾ty¾ÄòQ<�9»¾< =½Zƒ¾¼+è½�·•¾p®i>yÿs>¡"=i=ôÒ6¾Ò° >Â¥Ž>J^Ì=ÇÉ%>~ʾÍñ‰> î<¾)$£=mЛ¾ÂA~½i¶÷½Ýø_=údë=¯Ï?>.O¾ÃÝß<›ë¢¾²^3¾ó]¾\S=‹l ¾¥s‰>€¼>€ «½%[ǽ÷ >é7¾®’$¾÷¿ˆ=ýä±>"û+½�±½e2¾…oˆ½ê쎾æ³'¾’Ó¼ycp>¹Ÿ=X埽� ž=Ðð)=7ë¾8PF>´'>Õ4B¾»È­=#.™½ž”¶=æÛŽ>囑½R¾¯½Dr´=P ò½¿™O>ÜJ>œ‚㽸>™àä=s†¾K_î¼ìy©=�D<¾ºR·5±=_R½õñ¾J0?¾¿ô6>Õ¾/’Ô½aÀX>~)–=Tó=óóW=%r=+ ޾$÷Î<µ&D¾]ÚŸ>è=0*“>¼@|=Û ˜¾hÌ#>ϾÏ˧=jXq» 齂�*=|dÂ=ð“̹E|>Œèá¾ß‹<þ*û½+Ò:>-龚Í!>Ÿ=`ÊÔ½ˆ;#¶¾Aʈ>j%G>a*>9š=½!ª9=Mk`>Rü–»¥££¾’�¾×;3½÷B=�J¨½úÚú¼éú ?°Œ¾ŸݽP:>•Û–¾»ò�¾*gc=0F#¾›a‰>þµ=ˆËû=E >@9e>ͱŠ=(5&¾Z$>Mna¾Ü‘>‡²õ=º­ò½1`›¾ÕW3>¨=}Ú»½Æ¬O="Ùì>¦¾éàȽպê½ .>/�>Ïï=�}D> ìÞ=Ï—=)�Œ¼áfr¾…I0>X�ª¾xó>=iP=Œƒ7¾S¾a>†xP>×á>½®S©½ÈB>ÍÞ�>Øñ/>Í‚¤<>Mú½£_[>Á¨Ì>¯“¯½Nn˜½>!Å7wR¾·].=æ#š=d¾œ:ò½‰±¾x…½G•!¾¦ºX¾‹‹+¾ œ‰½9u=&R*>Bþ�=Ý8‹½ñb�½Ž˜w¾n—C½C[Ò=H,±½VG&¾5Çо©s-¾X•Á¾}Ʊ¾Åb§=Í‹ޏ½bb2¾HÒ¾½+�ˆ=ƒ¾Ò…ñ=’Š>Aˆí=ïó˽\=>Л=Ÿó‹¾ |¼—õê¾°º=> t¾ÝH€½n¾| ³½Ò¤C>×¹>Ù” >jgÅ=ØI‚>û¶Ž=ø1¾õòà½óc¶¾x>0ÝD¾ËS%>‹½Ç“B¾Î†¾´Þš=RÞm½W”É=÷ôå½?)¼=Â�›=j>a>ÎLK=BŽ\¾zj=‰°Ú½~£¾jTa=”hÕ½d}VºÿP¾›ò¢=!œX>îé¾R?v½‹"ô½òjƒ>RiÛ½‡1<¾³e=ÄÓݽ<3¼|¨[¾ßu>”\‰¾ðº7½Hê = Ù½Z2÷=-ÛE=”ŸP¾Šö½`ˆ¾«ô {M>æ¨=®V]¾.-ä=¢û±½Æ.>”¾`H>÷‘©=® Ö¼:ƒ§=kÏ<ò3¾&[g>&^¾°½Þ S½}]â½S®!>îa<5þã<Áë ¾Eq/¾b&ù¼Nô"=:øq¾"®�¼GÛG>·ªv=ÙòA½°4;¶õ@>6b.¾¨�®¾š>õX=_Ñ“=r­;¾%Õ=Ä¿¾ðý>ýƒÄ=Þïl¾ "ͽ%ì¾5ò„½5·¼[Œç¾¬È8<ì>HM2;­¾<[m3¾­� >2Ù¾0UW=˜)½Ó/‡<ι-½§uý:\ƒ‰>$¾ =Ñ»\w<ìcù=šn¾ºØZ=Äž¼!6÷½Š]>J·B¾?‚¼ôÀž=?2º= èø½Ð� ½j†µ=váɾ “¸<¸ó²½ìx‹¾ÞÁ¼ÙÌ{>—»¼:¬ó=Ùv>»üÔ=A¾3E> K•½¤">åWË=¸³—>×·+<0¥ ½üÃé=Q$>­)p>å�f=_E½¼¾5Æ>Ä?ƽ®ˆ,>Ú+ð¼«+½ÒNø¼ì(½­M!=*¼=ã™—<Æ ½:!€>Ú‹>ï‘æ½×d€¾<ÞO¾jdC¾!�¾Ï]’½Óÿ0>s5Ǿwã½´Éó¼ŽkQ¾ÀNC=Ÿm>:k¾=B¯ ¾y«½Äò±=ÈÂD½ßǤ< :оAÛ¾¼eÕk¾UŸÿ:‘”À=ãìÑ»ÃÇþUœÌ½F¯>vº¾½Ó+>;•`<¯£™¼¹Ë=ÜVy=eR€=G$€>HÌ뼜O[¾ôhA>Æ>X §½¸"¼½\ý>Ós¾ä>?Vú¼FVÇ<\Z};©Õ><äϾ1_`<Å·)½uµ½Ö”§¾œ=ç=¼öø¹<9/i=&YX=Ã0¢=|*ì¼%D¯½nð<3§Ö½cìJ¾¨”…½HE³½Ûýx½£ >;îä½ÛjT½ªx=§õ¸>«ôâ½÷´æ=H­…>›%\<Êã›>²‚6¼‚:Â=n�½B–Z¾SÅ_¾Á¾å=e–g¼¢\½ }‹>[}ì½ó+>¾¬_>9>¾(š =ĒϽKÙ|¹UÖá=¾‘ô=Û¾@¾´>“S½<*ªv>(p•;Pã¾²ô§=|o6½õ.½–…h=úh(¾¶Ü´=`Öà½h¡C¾è‡“>ËLê½ò_=ÙÅ ¾×=ãâï=l9Ô=Õ½n|¿’-â½D > +w=(#m¾4-¼¶š¾!Ø ½>_¼',Þ<ÔÐo>V÷‰¾ Û½ž,ê½èô=9‰—¾úŸ<ùÒ¾!§=zCaÍ�2¼ê_¾ÕÓÈ;²„½ä�/>—D>ø6¶½~¬#>—j�;¥–|>—‰¾5,R;oí>�Á¹ò±È=6n@>™�¥=r’=xÛ˽§à'½ {½l½»¤=ÎE�½§«=Ø<ƒ¾¼]¡; ™Ü½ŸÖ=ò5¾9¤¢=ÈK=qQ“½nØ-¾Š„X¾Óu*=ºD²¼‘=<6Wq>q¾ªô2>¼W©¼áC\=î`±>`Í»ÿ\�¾a¶„¼…ß–<)‡C=íq<Ü燾 <�==ao½ÏF¼h&e;þb0>æp�=B£=™u©=ƒ„¾T%�½¹S�¾¶ƒ=_ÐW¼.½7¾îéU>Pßq=l€k¾(‡¾Ó†<ÓŽ>�‚>vV+¾H°G=;õ ½Ïó+>!M>Þ{ܽ®‚w=óy�>™u=Ž»Y½Ü…o<‘¢=÷Å=Ú`½7¤½�6¼ÝÁ³>Q]ž:éYǽóß�½&\<|½½�X=Cj>%au½?ø»sN€¾^ºÌ=âûî=ÿJ>½½]ê=õ–ɽòyd>2ØO>K5>îÏ>Š«¥¼Do¹½>ì½WÊŠ¾9÷¤¼÷.>ššÈ¼²\M=á=k¼ñÙ=þ"¾œ­¥;®J¾9Ð˽$½„d>•誽�‚j>áv=ÒX >,N´>t-=¼x>Æxy½l¦‚>¾¾æ‡¼ýéM½çäÙ¾©Ö¢½H«ñ='¤a½.ˆ¼Þ7¾>µü!>«V¾×Áf½’•�=Ϋ¼/ž =�N½©–%½|ðh½Ø�³=í³$¾òl ¾’[ùózɽ³�>€Í> 1à=@¯A<ú‹¦½$J>\è­=ÖEƒ»Z¿ÿ=§õ—½ÊD¾µä‡¾ÛÃ�½Hó0½}Æ >ª'ݽ¡¹0¼obh=©Ëó»”!L>Vã=OZ½“ˆ>Ö\½»vb¾ „K¾×2W¾2é¼Ù*Ô½v‰ª½ôÿ»Ö»…²«½C<ƒ>Ã¥Ñ=9õ=í�>þÙ7>É“6=×´½­2]¾„²=Ènã=á2¬>ôo+>��¾^ÖŸ>p0Ö<o˜¼¾¹œ<Úò>Í l¾ªèsø:”½¬%`¾ãh>"Í�½áœ>{%N¾.ª‹=‚µ¾DN¾ædG>‘'5µ?+½¶D½®ør< f>~bnÃØ½s¾�µ¾8°�¾Y|¿ ·¬½’èU½‘5¾ ‹<Ýìz>é¶’¾`×X¾ßÛ½�ž•>|[=²åb¾“Ý–=} d¾›Ê«½�§Û=Fx"=G$¾ç\5>€W=¤Ð <Ùw¾J¡¾¬½í­Æ½è¤¯½Ž+轕Èà»+>l6¾GŒÉ=¡ ¸>iØè<• ‚>÷Ç‹¼”÷=sv\¾OØ=ù`�¼K6G=86ɾÎû)>T0¾Æ¡—½ú5¾‘Tȼ¿,>�qâ½îñK¾,C…½y| =Ý€‘¼d‡¾ò½nœ;¿k¾C¿Ÿ;–½©Bͽ»gO¾cÛp<ÙNB>Ëh€>paÃ=þ©=\LE¼7è¾±W½x©½Ó?Ú½o:Y=­»¾ßÖâ¼MÉV<òI ¼½3÷=ı­=[”¹½’‚=‚ï‚:Ζè½&_ ½dµf½\?ʽIZÓ¼~œ>¥ˆ=ï<È>—Õ½‹ÜX>†¢è½Ø×�½aâÅ»=Iì=Åã�¼,PO¾!çB¾`Y?¾°­Ç½ />kÊ$¾`^ý¾÷fe>b·©½ƒu<;,þ;®v®>‡†½ ýнøz…<�‚Ÿ=‘¶b¾�ùѽéx:¾,€=Q,ì=ýX•=� >½p­Š=ž]5¾z ‰½7Kí;GC>�…�=ˆq–=.ˆ´½]F”=«#<¾3>ÌÍó¾Ý¦”=R]O=Qˆ>GOn¾((‹<§¶>pdn¾œ½Pød¼ÿQ—= ác½Ós‚¾Mîâ½Ûò�½tz÷½kâ=úQ†=°ue¾ `>y¾d#s¼wí_¾gí¾š>¼¡e>cV½©K¾ðn=øŽ¿½Öf¸=°¨A»(F)>ž,”<31>L�=5Í…>½*Š>Ä_¾5qß=ü•—»7û‡¾>Ð;ÊY"> è(<–ò‹=z¡"=EV9>ZÚÎ='É0> —È;î…�½:/Ì<Ý¡0=ñ&½—c‡½å ¾V‰»Øc«=_‘1¾¯f¼0P¦¾æb¿;¢õ< &s>CW¦<&\¾È=Œ¥ƒ>œ‘±>!ZK>â|Ã>§¬r¾åžÜ=„<Áu(>œ¼I=Ò›¾èb,¾/Ê/>Oþ‚¼€G*>Íä=äÊŒ¾þÖ=¼„¾Tü½{ÄÖ« >£‹=Þ/>e9™>JÕ³¼ƒI™½÷»<Ë1&¾r½.Ô >µ'¾¥›o¾üã­¾„mܽ ɾßFC>°ëH>ó{.½tøÈ¾TD½ƒ<×¾QAR>Xí=fµ‘½¢‹S¼]Æÿ½ñ¡I>¿Æà½^'C<”(�¾gB¸»ã¸R¾K³¸=q›¾5So¾§‹¾Ú†ö¼ûèe¼`ån½;›Û=Ò–Ÿ¾°K—½ÙN©==g5¾|N*¾È(‡¾Z`v>ÿOƒ=Ögq=(ǽ·`¡=ë«)>{Ľڧ¾}R<ˆQ,¾S¢–=Y "¾.b=…½8>q>']¾ÿ4 ¾¼Ða>—¥s>Ò”/> â>:�>¼êò¸=Ѓ̽>ì·Z=¥³î=¯‹½½u!¾ó1+>ç%Ͻõ1é=ë+>~»2¾HÀ<¦—ß½[ññ=,,=Ï[>«˜X¾áó >؃Á>ïÂa½=y‹½KÍ6¾,*�>B1¾z=o=/Ê<ø>Wë¼d¾�è�=Ý w¾H0)¾þù«¾‰ ¾ÒÀ->d\>ü>@Â>×…½›¼ ¾2¸§¼Œý¾É›>Ÿ°>xk=÷ 7»Jǽ£ëc>Ês»¼ó5¾:ž�½ÖÞ„>¹œþ½\[Z¼ØSê=44a¾Q'< �>k™Š=VŒ­¼?ò¿ˆ_Ê=¤îÖ¼<i½Ó®P» ‡i½‚kÔ=q“¼y~Ó=.­¤=ÛøA½C¸U>çþ<þê¾ ÀÑ==…ª>V²>[c½ v«½.Úþia‹¾ÙI=Iª½xåk>¾•f!=Iiq=9¾H>„¼’ݾ\ÉÁ½½º�KN>é@¾$;˜=‚| >i¾Æ«£=»ˆ¿½¾D½ÞÏ’½§y=C?Ò;¸rð¼òƒ;o…+¾„åZ<8æ¾àˆ»×¶ã½¼È¾S) =àì<çbW=óX†¼‹€½Hf ¾Î°¦>]®7½Û">Ì£3>Uï;ò O>uø+½”¯Ç½Vq¾núå=0ì)¼Ü}ºÏ~¶<:®>ŸËоÇO¾ï} ½0®Ò=Ø´K>’�Õ= BP=tØð=�(O> O¾EB>'ªì¼V;ï“=Ð\>Jµ>=oäT½K.>l±¾ý =/ƒ�<Œ8©=E<>z£š½¾ú†=Qš=F5K½£ˆ=ÿ…>Ýõî¾ìÏÇ·þ»�”�=�ÆJ½Û޾‚:O¼Ý˾gO½œæa½ÊS�=¯{=?Éì=­@ø½6»Y¾€’à½:‘нQ�¼|’3=10>’·ð¼¡ô>¾ë ¾JYª½‹½z/G¾!œü½ª3Y>W!X¾”µ>>¿f=X=V>·/„¼÷—5<݇=¥V¾RUÖ½î¨ø=:çó=Ëoн»ü=© &¾a¨>þXj<�õ3_æ¡=ÝÏê¼W >cÒµ>Hêµ½ö‡¾ÝKA=Cš¾=yX¾ð¿½WÎ[>è‚Õ<œr<¾@²r;–¨>r« >e)B¾×_½ÊÌB>�›¼3½Û•º¼ä=ò=cû½é¢g>YÈâ½w–—¾Îö=  é½Ìm·¼À9­¾Ç‰¾Õ±>óU5<úå >k¼’•=Ú$…½ºN¬¾Ãq¾">¶>g1¾eó¯=œb>Ž:_=uù¾�>´<[Hw»ñ> ¼ ½”§¡¾WÅ!=ZÓž¼¿ù¼¨·„=à =™¼Í=pÕ= Œ™½1V*¾�êù¼�Ì+>Wv¾.€½:×½Õ†&½ks‰¾ÑÑT>Pü=@ê½;¼D=ïž#¾Ï‚â;ìa]½V¾Gn>0ˆç<rŒ¾ª3Ͻ1h–»¢ >>Ü.ß½— p=þ.‰>Øì~¾¦9O>¹~¾•þ¿`¯¼4ž'=!Nž½€œ‚= à6>^y¢½1,Å=4w¦=ê>‚û’=«ö¾�­Æ¼â�b>dó¸½ÁM=GM�=íq,¾ˆM©½×�s¾`i‰>‚\†¼2J„>·Ø ¾ 龑¢0>¦JÔ½7Ðc½‚�œ¾Õ}¾I¨­=Üù¾=µÁ*>T U=ªÑ‰<Ý:½bó½Ïª¡¾±œ>;¾É‹¾%ïϽ”'U>S›Q¾Ø¸$>ƒGF¾Ü3>M>‡�¾­Ì>½‹VF½ZŽI<’U&>ŠÊ¡½‹Z¾Ñá–>ì¡Ù= N<-)z¾ÃÑ=>a²¾© ;Œ›e½Ñkj>¬[¾*ú¸=*�½xT¾ Ú=®bk=Ön\»Ñ¾9!‘»Ðƒš½°nM»‡É=þ½ã;„|˜>í­>vH1>陽@T¾ŽN¼Vч>9›½àûÀ½¹Ñ>’@">QþL¾p7=3º>L!Ã<½D>EC±»Îôž½Ûb¹ºöhn>ó‡c=—ó;>ôÁ»½4™[>w´3>ÛM²½�ƶ½ )·½…´Œ½/°P½E⸿öµ92¾q› >JR=oN¾2„·=ˆiD¾žf^¼ˆ”>¦úˆ>Åὕ¢<>“Ò™½n+ ¾‚¶%¾ õƒ<̽CFš=<]j>5±À=.uJ=ÑE~¾ÀC¾+9½f1¾Áž¶Ö<ýŠÅ<‰Ë>¼££$ >ùtD½øÃ ½ÅÚ¼CŽ= â=É¥<7�}=òÍ=ân!½œÇ8¾©o/>},»å2¾Ìå¾(Í#½>«0—;]c½<­->Ã{Û½ _½—+ؽóq…½ Sh<2X<r±»vN>µº= €>x‚=¸2§>10b>k¾Ê Ø=ž±ù¼å> ‰¾2 �½Êc=’Yï=®²�>Ï]>•¾¾óS¬½)!¾¥(=›½=Øm>“�y=[¡½””¸»ÿ™>*ƒâ½½å¸=˜Vɽk ¿ÙüؼÑìž½Û˜Ò=MÓ�= É’=z%;U»ß;ÆÒÜ=?×=0ŸÒ¼OU«= íé½z¶6¾Ý–¼KPo>õn¾Á�¾â¡<ÖÊÿ=‹ÿ½¬‰¾F¤>6꯼d˳»Yͽ÷u==iä¼Ú”¾÷j>Ëw=³}=U&<>ˆ�ø=�Æj¾Ã7Õ= A˜¼r½ ‹Ñ=â®±=eª¾HA>×:>Æã¹¾Ã\мʈ!>f!D=yJM½±¼d>á!4=ž >yïå=r§œ½³Õ†¾•3o>l d¾²­o»+¾3¾Tœÿé=¨>k¢½mñ(¾à2ò=w<‰½‰»þDÛ½.°µÙ’=p=kÒ†½YÄÞ½C0<¾zG½jÅÙ=1Ú<Ïû¬=ýêµ>¼4M>Ü�= î=Ö^¾wŽ‹0Œ½›FS>äÛ¬=Tž4¼ÅDa¾$¯„¾ì…U=²àª=Ƴ¾5m#=·�ݼ}ãO¾[k켃p²½:ã=©ñŒ¼%ƒ> j=t)>Þà¼Ðh?¾~£½æ_„½Ö£O¾ÀõK;! =%È=lðñ=£—µ½ä6m=fÊ1¾÷"äŠ"�¾v0™½˜cÎ<Äa²¼ü:¾÷–½É±‰»ËнëhO½@ƒ,½{[<Ⱥ(=+>éÔÁ½¥hf¾ì~ýî!ê=Õ8š>í­³½ýó]>K>9~>tñ-=k5J>Ú²>dÓ½=�=„•½’[/>(~"½¢ x½\‰‰=såÝ@?W=dúr½ï~“½Øô½ìl<<„.½@»'Pì»I­½.dD>ÍL°=wkä½v2>i2º¤”½=wͽ ÍO¾4]q¼º1W=ÌOC½Ý´ª>kUQ¼BD“½®¾M‰k={t%¾)ȽCc½PÐu= /j<å¾�ÎŒ>‡>£V”=yí¾¬½=;™¼î_>¼r*¾øÜú½¤Ã_¾»ô¾Ö½�½x‡5>&¾��:>ÚŒ,½ˆx�¼ïõ4>5žP;ù%%¼Ñß½hå§>Ú =šù½ ˆ¶¹AÖ½Y#=Ú@>& м¹åè½xÀ= ƒ¿¾þQ-¾³éV>™¶r¼V %=ÇeH=ŠæU½�ó›¾ô›È½‹„8¾ ú\¼n›=诪¾˜0R½íÖ(¾Qžú½Hðø=脉>O5™½OÕ¤=¡/¼¢¨ƒ¾¼k¾ïÁï=Ö >“ÎH½7/.>ˆ½Ä½}’ž=”Þ?>£A;½2¿·»v é¼x‰=‘“Ú¼vÀ½RBнïî¾–Âļ­J¾%ï >A—‰½[ƒ<½�‹7¾ññ_=±~³=Ê->6E”½"y‰>•Y²=®0¤½'Ý€=Á»;…NŒ¼ô'D<öEø½Jœ‡¾¦+ö¾Ï;=›´…=ñg½a ØGžX>ã =ÆQ>1�}¾nÂ>褠=¼l¾`ù<¾Ìw¾ᘼÓ7=–†¾b…½¾ë»½6 ¤½/ô.=�¾š½éßȼ`:>bR> ˜H>³H:¼Ò¶»=1͇>|õ=”‘Ö½`uQ¾Ö¾\šÒ=ºg™½h=l<=C¾èy> …Ô=I±½}¼9½¼L⺉š3¼7[R=b†Y¾ß6;TÞ>÷e[; %°>³·O=ˆì=őʾ ú>Tžw>Zç%>à2“»bÆ­= ·=“Ç=2‡¼¤2Þ¼SÕÉ<#1J=ãâ—>V+>Ò·³=ç¾ó<=">;E‡=s�¡=M7�<„Ó‹½õf>6ý²<ÛB>Ì”ƒ=½*>9>�8v¾ŠB}=¨I…¾·/¨½1ÆR>yJ¤½$ýñ >Ëa-½ñ†> ç‚>ö(<'¥«¼^s¾RSM½Ùu£ºÛܘ½m”˽,r!½×˜g¾ða½FT÷=RšÖ=‚BN=šÜ>Y|á½;¡ë½KfܽÅÔ¼üÛƒ½øk˜>% <’ƒ¼8¼£=8=5ZÞ‰YŠ>ÝÏ>‰äH¼Zaœ;„O¾Þ`½¤z<�J{¼xùC¾ˆ=ȼ'ê¾iãA¼N/¾¾�V>|?=( ½pž’=±½¿.š>[½9>En>PpW>¼¹ç<ßÚæ½0¨ƒ<_¬¿>yÕ7¾•RJ½|¸½ 14½nò½�½1>äû=®ü ½“ 0>’P[¾¿>óú=T ó='O_>óm>-�p½�ð ½C/ ¾¯«<¬!�½‚@ ¼&ñ^½#3:ŸÛ>`Á6¼6òç½Lî ¼b;‡=óB¾ښ>�…D>"‹&>yq=(‘½÷Ü<¿U>l�>>²Ä½0X;¡ ˜= x>œøÎ»¦xν ¾úQ­=Gµ�¾|[ô9­JH¼_=¾c J½šVS>öÔ>µÃú<ÉD˜=ƒt‡¾Ê­»½i¨ “¼ÔÐݽ«Ç0¾Íþ¾=/ƒ¾Iâ•=ÛË'¾%¨z¾¾pš½–]%¾4v >ðî.>}wŒ=ex¾“ãÓ=/­æ¼x‹=D]½ Õ¿>4q«¾ű=Ô#'>b]™;T@¾»µ½{‘ ¾áV¾Žcu>.¾»>°f=д²=Ðz¯=d{…¾À9å=Øú¾=_ ¡=Zïs¾ï¯¾ª�> N‘=¦–…>�Ú¾_**¾É$–¾@´½–˜Þ=æ x=!í�½ÙOp=fUÔ½°@«½…ù½Áî½,¾¡½Ž,­;~‚’½ñ�.=7¬>1~+>íÚ¾âÜÖ»V‹ä=±wƒ=Óê*>‚!=/è¼[ëá½B°<â¿3½„E¾mEÞ=¹ö'¾u�>=†=`¾\½1½D¾šú�>ƒº¼=œãÌ=~“>¦h-¾ˆé=‚¾—¾§4=ª½ò¾jÃr½žj“¾uVÿ½Ád> €=vJ=»œ%½Ý)¥¼-g>àñd¾ 4¼Jê¾Ìwæ=ùƼ÷¾ƺ¾½{(¾¿¾~=|c¼ÃÙJ>›î†>V%½7)Q=�Ô¾ ¶}>¸“¾ç2¾®w ¾%.>Т>¬åý¼wãª>óK.>fg=åŸ{¾Š=ì2»½¸=“¾dUœ¾w¶>n<½¬[=~ö&=íÇ÷¼¿ÜP½¤¾-^1½+ؼp…&¾;Ö½çô¾ƒ‚8<æ¾ñ½¨[ ¾ú›}¼2>E¼�½Ë¾L¢ë¼Žg½%�†=Þ';Ag¼Ÿ!¢>Åß�¾©g>-ò+¾¯ ˆ¾>ùK¼$”<¢ª=Cš= ¬~>b³¬=Eë�½Œ\•=3 >çá3>r&�<)‚-ʾ­<ºí8=ä.½yßà>�Ër½¨�ò½ÀÑ[=9¼þ»¢žŒ=U©‚=ÉÙÚ¾0°¾V²0½2ÚU=¥ /=e·ì¼¹À½Í";mH3>…Ú)>‰úÓ=n9 ½*t&=/¾,Xs= ß‘½ssý¼ê³±¾À ¾¶(>0'>ÇÄ =¹; ¥q¾Î®Í=l‚=X§Ï=ˆ3Y¾š…f½]-†½nf½ÌrƽáYc¾FÔº=܂ȽÜbé)ª=üL¾/´7¼Ý?h>áSˆ½Ìæ =³=Õ¶>¾;:„¾2Y>S�=O3½™¾Œh>VD¾T ’>$z>3_¾Ìö½SL6=‘£¥¾9ÍØ½ ¶¦½®��¼�¨¾ÚÀ½”�>ST¨>n(#¾¤£ï½�[­=Æs®½þÛ<çÊ >$wf»|^Ù¾^Ëg¾ÂSÕ½K‚¾vÖ$½‘ O¾¤ÿ*¾²%˜¾¼ûн¡D>ù%>±÷ݽïK‰½¨D.>|Äì=k¯+¾X“½3õ(;h >Åý¾“Ë�=^¼�=õÔ¹>„Km¾q1½1 W¼?b¾ñ>«=áÞ>SP¾ªip>„‘>œŸ˜½\l£½ª¾cß×½mIe¾ÜÄÙ½ÔÌU½FÜã=Фº–½k½‚ý½vÎi=ÒÑš¼¶&\>Æ•I>ÌR"<Ç&®=à;½Â?O¾œbs¾d ú¾£n½wÚ¸=”Ø ¾÷Ìb=Â'>­¯n>Ộ¾ì�=oJC¾‚Ì>æÃt>í8¡<圥½“nÒ= ÀI>Ÿæ½Xbï=žÆ=àê¾Rõè=¼ž>Æpp¾1í-> …Y¾ÇI ¾<Ÿ½�_Œ½ò}q=Ý;ß¼F½mí ¾–=>òõL½å×K=ˆ·q>9¾¾Ãe½Nz$¾HV¾¾Àf ¾Y<ð;Q¼ü½+¾œ±œ=v.>S�û=פA=f¸ì½"È.=©*$½a¢¾ �н¾ûÆ‚="ð=Q-{¾¹->\‘†½|¦sü¡ò½Ûôý=¶ë*>ñd¹½ùS>ß.¿¼N¾¾Ó>Œ¯¹;+=ˆ2h¾QRà=õ‰Ú½„ >¹¨ãcR¾â¦=¾#L´=—(J=/~>ª7æ½^€Æ=ò)¾¸d ¼:¬¼¼r=��±=î–´>÷>�=ôå”=Êò&¾"Œ¾Å-æ>{q¾š%¾_=ü“j>–z¾/þ�½ëJL¾ƒ(>yH>”±³>)²C¾mR¿½Ìô½p£¾P£>;ù|½ãxb¾:±¾‰­Í¾“½+5¾®2©»ÇInYü={ô,>Åz²–§»Æ{c>+>t ž¹  >¥Ã†¼n=  ¡½ý-<ïg>£¬p>fד½þ5¾ãlнå,’=¤Y¾ \Q½_|0¾üØ>¾½0½|7ç¼4\,> "O¼÷¡º=�(³½5§Q½ëô«>Å쯽të’¼JJŸ¾ÅÕ•=o¢8¾öH轪M«<:�Û<ÛËð=?>ãm>­z|½ÿZ4="ðX=ê³§=»åé=ÓÉg¾éS¾E°“<÷䫽ä¾qc,=Q9>…Ù3<”>_м?¦å=|}Õ>¯H ¾i>Y¢‘¾Ùä8>ò§ ½5Xá½ôê‹=?ì=M﮽ÆZ÷»’á§¾m;̽߰¦»ßoÇ=$^ ¾˜·¿=?óX¾tÜÆ<©|ž>r�>ÑÆ6¾Áó=©è–¾¢Ú ½Ûx?½VtÙ»€u>:Ê6¾”w$>#ú¾)iN»»¸1=Tö5½dÅE>"½¢=ÞÑ?½ó”ó;¬b‡=éàå=�ï=¾›.¾™ç€:%³N¾5¨Ô¾"Õç½øÜ<â–ó½ðƒ¸¼6!½’=x0f=¦æ¼…U<ŸS…>… ¾«9;>ƒÅÞ<ú¥5>ðŠÉ;¥³r=daľ!N>×@ñ¼I÷|Ô =`¸¾ØJ>ä~…½Ú –½>.k¾dsB=_P)>œìw¾J¶T=„7ö½ +¾mоKå(¾KÐÁ¾(ò¥=Ê'…>¾Io=•ÿ>¼ ¾•0 ¾i:Ò½ªçâ½áÉ!>FÚ/>Kí<>d±>a¤>sì ¾ŒŒ:¾c`°<�F»¡›T>y¸2>0‡Ö=�/`¼ÁæÍ>¥ÞF=!}9>é€k=œ+_»˜öí¼pÁÊ>Ê®|=|¤‡½¨çy¾󇾨yž;�æ >:>¨=>w—>I»>I�=k“D¾¦Jï½—Û{=Åòe=K\>«„¾Âg½ç¥¾fc�½I>¾6/>‰JÅ=`ž=d\>ó,=S}ç½È‹=е=43 ?Þ<3¾E’]æ.‹=Zu¾Íé½ÛQ˜½Õ©µ>ò#¾Èí½‰y;·0p=0–º=|”ü½œÄÎ>Rqã½�þ< ¨r½d©½!È–=ØÎÝ=K{½buÔ»§¿>Ü*�=£›„½Ñ®C½rsò=˜Ñ�½üµ1>â¼ ½Cõ½K{”>ìù¥¼à7=ýÜ…½¦û¾Ãð=8†°>ô]µ½çö½¡©�>¼—>2Þ«½Ͱ=0Ǽ¯=\_ß½¼·¦½YD¾Ão¿½sÌÌ=êñ{>ޝ¼ó|@¾í#G> ±@><™¼DÅ=® P¾æF¥>5Q.>ös4=rˤ= àú½œn¾;: ½}Cw;ȊŽ!4ó=4³˜=[r‚=)ÎI>ùÈ5½ôò¦=µ+>'D2>Yÿ[¾1ñb½Ç0ξJp„¾¶¬�¼z¿Í>Ѿ =i~¼ lõ=ôbŒ¾É�=§jó=4Ýý¼…ö·½"3f<),¾Ùº ¼Nw >Å¢Y¾„qm½qYÚ= 諾Ѹ=yï—=& {>¿¤¡>Þ >Jòô½Xˆ=ºHr=”ä½1ýä¼–£i½„íË=‡è]¾xͬ>Ônš¾±/¦=u<*> ¾Uʼb²S>‹^_¾›—½nYO¾–ÌD¾è‚¾€+½@}Õ½5ô|=Ô�‹=Ò×–»º-¾³å:¾å3>þÀ´=©_½.N`>q-9=–p&>è±=äÖ�>„@ ¾³d޼ɷ_¾Œ¾â¹½Y~!>�H½K*=£?ù¼ÑÛû~Ù�>á}¾É¬ >.¦Æ‡‰9><¸¾6¾è¡º½­ÛÃ=-¾I�)¾þ $>ѱ›½)pB>Ú¸¼-:¤½0Ùô<Îbõ=ˆ$ >‡8o=._z½´r ¾òUe>A¹¤=]=‰…¿=gÀŸ½7.ã>;TY½1A©<…«³¾¤!•>‚|c=f‡¾Úߊ¼èF¾èH»»_,¾Ð˜¼�ôÿ<¯–Ê>�…½šù•>If½u¾=¨%¾Ë ‰>Bàø<Šp“½Ùe¾9v>u–©>û�ñ½]>È];¯Ð=Ê`õ<”A¾Fˤ¾‘©à=Ôê>Q)G»T¾ú½‘0Ÿ¾šô8¼•ã´>Pï>�ÿ ½œ~>Ù¶{>³N³»;U¾~ƒ£½�î’¾ýÆŸ½4±¾^ñ¾8Ó™¾Âe>Îfý=1~Ç>š©>p×g>'“¼ÔÕ…¾zÙ±½˜ãñ½·P{x¾^z¨¾¿{O=#Up½�\#½×ƒr=¨ú¨=”Ì<—ŽL¾€qˆ=V1£¼÷ü¬½9—>Ò[;½-¾/½>t^>õæä+·�¾×QS>ðÏ/¾;÷°½.„½ÿ Y¾q²›;�#ï¼<¾pSº½�…X¾}©U=ÂÆ >•“º< ªÏ½Ý–=¤V¾øèÿ=[>&¢—¼Àù´½f¹¾yÕ¾¢ô#¾¨,±=ˆ[¾wÉæ½n€^>Û^¾Ò0v¾G,¾‘ÛнAÌì¼Á~ >t=>ÈY³½¥í¶¼3’¼xÓ¾",Î<¬q˜= ’ýºÐ ‰>cñí=¼?×<¨9ç=î™%¼ŠWM½ |m=�Û=pu=leG¾¶�€¾Òó>z¼É=Ò»É=SNC¼5=ɦ[>”°!¾ á?>‚E¦=¿J½±®¾SÝѾí(¾9u%>°ø>‰e޽O{­<\Ýß<ÙÔä½€ë™=˜i ¾[P1½‡Þ°½�|E>ìÜô»fÂò½Oa¿’êG½¢‹6½ãZؽȕ ½�X½½ìF®¾u(=—wK½Õ½Ë>¿°I>j—Ç>Ó°†<®ß9=ܦ>¾¹Þľ?õ&=ÿmQ¾Ì½0<'˜€>ðSõ½~¸=Åj=íÌ:¾Þ¯ˆ>„fo¾½½µ&r=Ãóù< £4¾T}­=í‹�¾r$>ËÚ;=Ö'>²ÞŸ=W5 >nj*>¡û"¾Y½¶=Ì-¡> …½–ìB>À5¡¾("O¸½A= ÊX=ÈX =™4M=4˜,½ÜÜ9¾:œ‘½³#¾åý•;Ä1³=³¿â½¢xÃ>"Œ >ºÇ=!*©=oë¾-ëí½‚^1=J¹= ·ñ;ø>hÏš½fÇ®=�¾q=+¯=Mäˆ>ÀÞ‘¾»Ñ>4î¾µ¾Û(>3 ¥>EmU¾ÓRнla>âðR½ât뽌Ca¾ä%*½þæá½M쑽b_¾½4é½3g+½¢¾«¼�æ=þv>£>ûµ==GÈ=ê}ü‚UJ<$ŠŸ<¤y;¾;>­¼½Žn¾¨­•ºú@‹¾¡x>‘¾=Àú|½ÑT°=õ¨µ»(1­=?Ù¾ñzÛ=¶¾Ý´Ð=€lE½.¢½³?1>½@k½˜]â>º©æ=0í�=Ñý½_¾$¾€®³¾JpW=fâ˽Ñ� ½š=¯„¼=¯…¯¼Š„å½p€¾XNW=�E>¼k±³=n”«½Ù%¾ë¥¯½¾J¡¾œß™<¶Ù ¾àmW¾)€>®žP=ª†=—´á¶Å3¾"DŒ>M¡Ÿ¼X+#¾ú^‹½.}Å<âŠ>”�µ=N½¾=-¬¾óg>ë]¦½Þ=ހýXIK>¦Ÿ¼Š�2=Éá`¾ ㊽ÿ@ô=Ÿ}“½“½m�.<›î¾€–=úûK½š<½ÄpË=~ÃG>6>r¿)¾_¾œ¾Jœñ½Ã�¾Ì°‚½h@6<õ¼…>tE¾7 *¾DÛG=[=ÆŸ¾øµ-=`¹½ŸÔ¾[ãv¼Ak¯¾4 ö½ ¾ŸÕÕ> V½Sk½ùIi»Óæ=òò<.iìºégr¾2Li>C1>¿‰‰¼ˆÈ ¾ªÃT¾pœ¾Š”ˆ¾*Ï$>¥Ÿ½mš�=–UǾ5 Í=0;•=j½I>¼«½p£C¾sO>`Æ>c�¾­³S>œˆ> g>¬¸¾'R¿½S‚½¹(½±v²½r†¾@ß>š÷<û\½t±Ø=åwˆ=P˜W=fÛ¥¾-º†»¶ÂL>¾ý*¾pþh»R”Ü<ÏÛ1¼È€0=øZ¾2 1½5 ?=õx¶¼¤‹¾yY‰=bx£=z*¤>I–µ½”2 > ƒ¾}É<îÇB= (¾z¹%¼=ªÌ½�/¾¾s½Mié½Õ�Ó¼ùž~=ñƒ½½ÁÈA>èQØ<‘Ò‰¾²|¾Î#A¼;¥.>n6<Îs¦¾ú<[. >@º>/ç¥;ïPÐ<ˆ„¾°k=ëÛ=á*¨¾ô·<0’¦=©!ƒ½…d³<  Ž¾¾yý½†Y¼½ö”¦<‹�‰»…ü¾¼}<>HÅ3¾çHD½aÆ=?I½W(à½ô|W>·<¯&µpÀç=M¾ûJ5>ÒÍÞ»CŒx=óÇ>\|н›åµ½ÿ¨ù=‡šº=Cn=zÂz>]ú<±.b¾Ek>;>«�¾Üüÿ½µšç½¨\ú½C`;×!€½òo>��½½R F>T=¤=¾P£½Ð< <” •=�ñ…½J ¾Ÿ#¾–i€¾{S7¾òžÜH¾B8å½Ó�3¾õ‡:=…cž=Vv*;2b(<Îãô<Û5o>é)†½�À¾H§ˆ¾0О>®)ñ=—E3=èG¾ž®à=Ùæ¡½Ïôw½®…=$1K>ÞÄú½›5½yܱ;ÉÎ>¸¦Á=Â"½cA½ï=Á¯7›}R¾áßâ=FZ‡¼ ­Ù>Rê�½(R¹½ž+c<Œ–I< ÷¾?v{½*í½^_½Sô =ìW¾—OY¾3S‰½{¥9½þ.ž¾âè.¾[s¯»ëú½9FF> Ƚ„—=B…j¾m½Å>i5¾h|¾<ÑB¾÷…�=]ày¾£šp=µɽ²+Š=çZ𽩤G½œ¯V>ŠÛ)¾á2Ï=Žä\¾¼ð =°\n¾Kù*¾HV†½á÷ ½•(­=]<œ–‹½ef(¾á 9=ci»„…=í›&<üî½H¨º=nVß½EŽÎ᪾ï.r=.m=,—h¾óƒ.¾jé=ÐwV>»ê<�4#>ˆ,d<<Œ >Ñ<ˆ½9·r=€R[½+É=F‡Â½9´º7� ¾?»Ü=гl¾£‡8¾äæ$;¶íè½÷Æ>äǾéß=Î.½=oÞ½�ª„¾p¸¾¥@>Xô ¿à½ï=�¾_ÿ¼Ö]=ÆkнN=zä¡=¦oŠ>q±ï½Æ1=3ØÐ>Iy½4«!`�€¾îF>ç` >`DŽ=Øž‹½,ÉÌ=�¢%>ÔÁø½‡EŽ»½ÙŠÁ¾jh“¾É k½aš%¾a…!>ÉX‹>¸â•<ŒX>°q¾í€>>‹q~½CYÐõ=b±B¼M˜õ=W¥ô=$•”<4.>¶æt>­ý?¾X`F¾Y$E= Y¾º±È<Ò²$½Êçå½ÞS¼õÁE=Óð_¾é Ÿ½©{a=>CG>²Û ¿àä(¾´E޽ƈÖ< =>Ýl5¾BÁ=Š"½Ôž•;ŒÕ¾Qbí=q•½kµ5=™ö½Gt=ל=@·C½e½6>GÑ ¾*#¾6�Z¾á)€¾ëU\>Ç1‘=‹=½07ö;Vc»¼ôæ¾tñ�>ÅD>ÏN½™.Z>ÞÆa=+W¾¼¶ÂI>К[½Dz𽈼’=ÿ×Ì=¸½^½ê@>¹g༥Ç<ôV{=ÿ9�=dF‰=“oÒ¾ Çn» ¥)¼*÷½ņ:Áཪ=_B:¾Ÿ� >—b¾»L¾ÔGJ¾‰y(½ µ_¾z&½¡\>Ð_Í)f$=[·½À½3Œ>à¹\¾–e½ÆA¾åªu¾Ù·Ž¾™Àí¼äd¼ट=ûG’>ªúš;ƒ#h=Ë™ˆ=—ø ¾M›-¾;Gn½ðâ?>I‡ ½“;œ=ˆ�ù7õ¾›Œê<‘½–=<¢Â<ò/ =6µx>ñ/<>Þÿþ½p‡ ¾3’Ž=ãÔ½E+Ÿ=«ž#>o­ƒ¾ïJ$>ZÂy>ë6%¾„Ù^½‰ð>«ªZ=ìt‡¾5j&¾œçL>Þf-¾‰P=“ZÄ=ˆ2½¨.=7)²½[Š<”90=�½‚$¾†;…½fJý½«z ½Yâ@>N®X½�Ñ-=òº¢½t^=ز¾YûŠ=-Ü×=[$¾11 ½�œÖ½¨l¼=víY½Ix½¡S >Qj5m®>Wk<™�½|åê½~–&½Ùñ>¢§¾Â騽¸½€¾¸Ï'>×¹Á=:L=õË=<íò=;ó(>WG’>ÿ½v¨q¾‘ç<ù›¾ßôˆ<�7B¾¦()=Â�=èYS=>8 ;3é½I¾ÛNª=»\¤½, ¾(“¾gÇ)½sÉ=üV™=…U¾µs„¾”ÀŠ>û½B¾jÇ5¾zµ‡>ãæÖ= ÅýÆW>ë= >]¢“>ÍêC¾M+=­¦â½t:A=Ïb…»­Iнû4y½®ç½*>øK¬<ÈD7>X~Ý=5@‹=I® =Å}«<§º€¼HÜâ=éÚ>�¼>ò/B¾ÈW¾Z•H½m¾ì„œ½Ðò˜½©Ñ<+Uó=òu‡¼•ñ‚=±|{> Úî½þ�š=¥G€>V¾î½»=á >4¢u>º«C¾¬ë½§‘=Ý„f¾dÄi>R.Ã=‘¾½†�½ÿ™>úò€¾ã½•à˜½Íå^¼Šë–=²$I½Ã  ½EE½{Ÿ)¾s²‡¾®X¡¾’A¿½/Ã=˜Aô=2µO½ß‰µ<:Û­¾BоÂx�¾üg½å«ˆ½ÄJr>T/ =š4Z>[ø=í¶Ë<=hi¾Qw5=¢jv¾jq‰>³d>®�h¼0ˆR½¦7Ǽ-¡2=6[¾³Oc>›ãÚ=ÀB{>½Æ´=«a„>ÎÏŽ>;7®½o¿¤=êš§¾ÑC>Ag =ê¤À¾è¹¦>v'¼»T“_>»6¦<0û6¼ØY¹½Œ�a½°rD½ˆù¿¼ ýG;h½Aå9>ÌF¤½£´I¾$"¾ë®–½ð·=·Iê<à —=yŸd¾¤0…=‰³Œ=k^½\öÙ¾§@n¾Ö�½ïžŽ+>å1¾~/X>5ò½ç¤>næ½öZô=Ü£>rˆ=z.j¾ 4 >lq�½/Ž=•Yf>ˆÜ ¼ó´ >ãóÀ=G Ã¾Æ&>Œ=M•1¾#eн˜.t>0 ¾çô=¤51¾Ý•†½l¨¬½"@™>-(y=ô·Ž>nq+¾‹×�¾Æ >¯~ð½§³»�wA¾ñæö=³¯0¾Š¤·½ãëÑ9ŠyŸ¼­¥¾˜Mž>a+’<©¸=w !>J¡ô<É:;½ªÛ¾©ŒÊ<(?K½R7w>��½ýí!¾lX=¼„C¼ó›¾="=|C€½æ$C¾×aŒ=ìf®½€ã½´ä>93>…Ü=µõq=RÅð¹ I>Oà~>Hr>_½yí ¾´¤<5=Ø"^>a�_=6>«ëн}_ͽxkd½l§Š=t8F;ÙÆn=þ ˜>ÿ¶�½¹¹=×ýR¾• ]½l½=îG`>‡ÙG¼Ëì�¾¯ݽ„§ƒ½5¶,>7Ã>êøÓ;-‹�>ÌFO=˜’½=ò(×=²¤„=*`¤½Ý®"¾5š=?bŽ;„`½çˆ‡=4%Q½ô©>7n�=áW/¾ •…½•cx½xb³>�ý >*_>¶¡°<¾”]S¾ÀG¾ø½í»/V"¾ŠRë=¼‘b>ãO#¾ÇÉ>T5q½ÁÓ½‡¦=³=x”>ºö�=š¾d¢¾ÈQ>5\ø¼ cã=*õ½ÉÇ>¾ïÞ½Þ8¿<@{ ½B¬l=1„p¾áËq>Cs°=Òý>4¾?D‚=R³>³Yz>e†Ï½Ój·½#Z#=-;-¾˜}�½ÕòZ½�0‡¾™©ì½µ­�»›]\½ ’¨½]©/¾.0À½õ“~>º›>’Ÿ¾³¡=r9�¼Â»¾"L5>H¨‰<¬í=/—�½Mø>�µ*¾‘¸õ½¶ýf>’•Ï=œY¾”ž>’—R¾—u·=”WÛ½ÿ¨_<«·P½6¬$½Œ = ¼d¼vêˆ>ê”Ó½vÀ(<6Ð<2=>�G½™†%>ê!¼Í ¨=¤d ½%ÍF¾ÍKÚ=Ž£>nÿ ¾ë¯3>ø}m¾D§½Ý+�<™# ¾v—r½Î>´È=r6=+Þï<í7M¾üfV=ÄJ©½f„9¾ñz>ºÀë= 'î=§¤>Þg=GH ¼µ’=‡¡(>Y‡¥=ÿ-c½%,=øm¥»˜¾‘x˜=¯Sé= oZ¾ y=ñr>sÛ�;h+Ü=Öa¾k/>>ªH¾Û„³>žR$>:¿è:'uš¾rº>#£�½ˆ@¾-D¾Ð&W¾²º*=Ò4>™p»=7AÚ½]ú¹¼%ˆ>g ‡>£–H>ýf•=©Ç=tòš=êÀ§=!áѽ!Ÿ ¾Ä0x¾•NØ:ûc�=ýŽ™½yb¶>S�t½EfW=t ¾–�>‘¾ ï@>âh¾S¿-¾—Ô–½“þ6¾œ×t>¿œ>>¶ñ®=‘ã½4z¾©ϾJào¾+ø½Œ¹ç=”}æ½.Ú<Àu¾öý¾ßái»’÷=Ã}¾(> ˜=Êa9>«¶|¾*”¹=êE¯¾ë”ö½u¾é=Á�]¾#°�>uÀá=Mm¾µÃ;rbB¾û’œ½Å…Î>Ÿ¼æºZ?½<ß!>; ³½Dx)¾J#<Ìv2>ºøË=´J>œ*½» \>˜¾$膾 ¾xñ=bÆ1>Õǧ½üw�¾ŸÛÓ½p~[¾åé*>Yˆ¾{l{>3á»/€7=‚ŽY>ÿÆN¾ö³½@Ä(¾º�»¾ºC[<`(]¾äÑ»·� ¼ý»Õ=_HÉ=tqœ¾YI½+Œ¼¸†E<>–=øìe¾Ä—¨½ûài=‰­Ø¾àÿ¾šÎÞ¼Xj�½Ú�¼rÙ1:°R*=tÞ�<,C|¼Çz=Rѽoa¾{04=‡Ø=š¢¼k8 ½Ñ2>ßV@¾ ¹¾$³�½Ä,Ž=îÏ3¾ÞÁ=�]¾o+ì=þñºz �>K±I>ÈÔ½3õä=ˆöÈ=ȇˆ½å{=\´×=åÈ€»ÐI¾Ðô…¾bd9>,1½U¯û<°ª> ¶'>ÂmK½Lµ½5òL=êÏ=(dx=L0d¾B#Z>—S¼î ½ñº¸>Ç =k¿"=vÔ|½÷5“¼¶š6>ØÔ&>àK½ ¼8¾ft¾¬E’=u\T½öF‰½“Ùb>U\¾hE>)gö½8iC¾à‡?¾X¸<½·B»\½©�¾É¥»Aðã½X >F:¾X1»á[’½a[:¾!'s½ÿ†¹=HÊÞ<,‰=œô.¾8Õ=´ëŒ½�¸=fÎõ<}Øü½ºV±½Éx(=Ñ<ð¾Ò›¾È?>í±>6C¶=ðÛ°¾|.¾ÿä+<*B†==á¼J,w>u¬<>ïW=”%ƒ¾Z“>�X=x…½a«¼T<>º‚Z»‰ ¾F9û½ .¸½¥ºb¾#¤ˆ¾�·r=VlR>±/>æ"]=†ó8>ªµ<œ²Ç½@�@>`‹<^à=û/>ƼV�X¾É„=’Q¨>a ¾Ö7®½»§Â=èæ½H=Ôü½º—õ½ùúÔ½s«¾—HI½Ô$û;öZß<%ða=¦/è=ªõ²¾¶ƒ½ÇK¾;Lã½3'@¼Ñ¼g¾!œ¾ “>šª‡¾Í,¾lc¾÷£E¾€™ˆ½ÆÅ<4¸&¼–͉¼éI>+„j=Mi<½ÿß“½¨0»¾?O¾ó¥½44>‚a½=�ók=Ü­C¾ìÒó=ÊȽ¿u½'R=ª¾Åòb¼ øõ<`Ü~=^*…½"`0½´œ¾þ8Õ¼ÿѽ0¢8=IŸÌ»€2(<Ý*=~@e<h!½µðŽ=âÿ"=|J >hQ€»K½O}ÞËY°=tÍ#¾+é¼2—=Aìæ½K,.;–6¾sܘ=Ì5/¾dÚ>•I¿>—Ø<Ÿ`e¾A*Ä=Zˆ¾œ¾ôD³¾C†y½ú–�¾ :$<

b‹˜×W½aÎ½ŠºØ<~c4¾Žª½SË·¾î( >¸Ô&¾g0O¾ uP¾P=}ÿ³=8”>r­Í<ºßG=òXŠ=ºûÒ½!̃=¾Õ/+¾E~±ý0¾=ÎT;>éz+¼–¤½jaß½ï¾ù=–�½Ÿ¦·½¿Á»“‘M¾˜F=Ùžë;K췽ʻ†=‘öu>Е=¯Ñ½šš¬=\�´½;§¾uh<ž3N<ô{Ÿ=ÑQN½Nƒ”¾y]�>éúÔ½U†;ïü <4ê˜<õCÁ½ôè½÷,|>4q?½è•‡½±™Ð==`Ó¾;0½¡ >AH¾c¼ÀL'N¾gG2>»“8¾_²=™¾9¾ç2¹½rc>áÙ¯½{4>g�½g‹=…’L>Üâ= �<ƶ=Öá�=â¹½Qv¾Áðø=“aÑ<©‹ ½ßŸ�¾úi>¹ˆ^>›eL>£°v¾‡-Z¼|AC<ó>m—¿À1¾Äf=,Í>“„–>›ú<%G>Nµ›<É–æ=‹¾nL>% ]½­d‘<#.Ø=“€)>Ò£Ú¼>¶•>£³—>dHÆ=¼ž_¼¦W±=jKW¼ÍGÁ=å>ï)оÙj®»trC>ƒ.º=ªŠ”>ÅÉ,¾ó$>µJ>¢�»s˜¼Š „½sö½»�ð<ĵK<º–='¤¤;-~ý¹=Þc=HøŸ>z'=8²½i�¾ù)É=v—w>¡(¾|èé½€Àâ½=ýÓ=ŸÎ�½ ¾›Q¬½ªŸ¤½)§‡¾gF)>ˆm]¾Â׉¼˜hj>–?½;I½µL]½»Z˜½eÔM¾¿âØ»Ýþ×=Ìôo¾– m¾[Ná=Cw=þ‘”<­åI½˜Z=¾0d¾š‹1¼œ€P=ËŸ¾,õ»ÑĘ>AJ}½†þ$>ðœƒ>‘ F:ÀÓ›¼;Er¾òê<õ8F¾Êâõ;œÉl¾‹±¾Çn¾ÅŸ½µ_|=ø"==�ß­< ?¼Ÿ…W½å÷ȶ™=:¥n¾s/Š=—ü=ÕB¾½Ë¶=ýˆr=;¾üî)>XI…=mTz>ŠýE½¹Ãj¾÷‡¡>ðF¾Ìeú}šì½a±>ª°Õ=ô?5¾ÿþÛ=Õn ¾.Ã$¾€`»½ò_œ>>óÕ½Dp<xb½YŒ)>HMÛ¾ã'=öDš»ÿP«¾2/I>—!‰[ŸE¾—°Õ=‰´G¼.�ɼ²8>ƒÄF=‚Z>Ñ[[¾äöt¾­¶¼TÂ>$á<{®¾^1ˆ¾…†[¾«å+>­gM¼ï ‚=E5=½ÕÓ½QÁt>óì0>–ON=Þi‰½[îD½O‘^¾¦~Œ>5´T¾|\Y½îf>5¯½¾>Ö¼éæÓ¼X½>p[ê¼þ°½ñïØ=2dŒ>ÀX«>5s<4}d½þç <í.�½w2¾¶ãƒ=ÌÚ½„à}¾Pº>…V'>•N�¾¼ÛöºUPD¾ ©U¾Ã†§¾pºD>äü1>¿¦�¾¸9= ªh½¢Ï„>³r‚=5¾�ˆ½.á½eÍ=½M&i½¦¿ì=Dvõ½‰H«>–’_¾´ƒé=Mƒ[<ጼjî�¼�&ß>ÜT¾�õ£¾÷yÈ=ê/ù½ç6N¾!¾l†¢»LÀ®¾·ÃÏ<æ�'>€¾>"¸L½›¤º¼ƒðQ>þŽ<ÿ�ʽ$C>*œÂ=qú½î�I¼ü\7¾8ÇÛ¼(æ±;Q$6�á¼O¨7¾_ùý=n¨u½â£½ ß^=âÈ…>Çh>­6J;ºÿ >pŸ*»Û!¾½4Ñî½½ �¾>¸·=jÖ=6˜=DÙƒ¹ú ͼ'p!¾D·B½}ྛ\>På×½PÚ¾Ü4>„˜ð<\þã=¾Wx¾ÁÏŠ¼4úJ¾¸ÿ>ò²{¾åHþ¼Ãtí½èJ7;õ‹E½èx3¼dNd¼Çÿ÷¼Tó8>¨"<>æÂê=Þ\Î=CÚ%½ÄwÔ=¼ï½ª/‚>RÀνÕÀ >`¿S=ÑÄ�¾Å ç=]Å,¾�}ý= ®>ÃÇð½Yy>úŒ5¾áí༆ÔV=fý >Xgˆ=OÝB>q>ª; %;¾«öi¾ b8>¹�\>b"ö=“�˜=�Xû;Ê0u¾³Žœ½À;´¾Í÷C¾(cO<¨™Ì½õù>ä1{¾BŸ¡>÷3 ¾Y ³>3פ½öð>¥7¾v…Ê=òlͼj_°=þ ¼G<]¥Ü<¨…E>L¼S; wD>ÿb¾ÙlU½m³!>¹�çܰ½+ì> 7¾¹#¾è´ >ãO¾Jþ½X¹ß½qái>1ò<Ë^1=ÂÙü=¾š¤½Æ):‹—¶¼žŒ�½8ùŒ;Ž D>öè >°ðŽ=¾às½ÆéÇ=Äì¤=Îr�¾Pª¬½èÑ%¾Àɨ=Ò#½!îþ½Z ¾ŒÆ—>OAF¾åÀ‚> ‰€¼xf½¾@’Ÿ=!.¾ßÿ=,Æ�<·™=»ñ>F×€=Õ‚ï=¸Ñ*¾;z->±Öl½ܬ¼]{Ï=¹ã(¾L3 ½ê3ô½ÎG>Ùµ¼(Ep=ÞΔ=¼h>}aË>©—§¼þ�l=/Ô¾f9 ½R–¶½äŽ@>Tì¼%£\¾¹ëž¼Y>Qà×½ù`˜>Cü>›Oà=(ì×¼—'>g8¼J¬Âösè½ÇÛ}=ƒ·¾´*>Aæ=\¡ó¼ X>°‹=ÑŸ3>Õ.©<ݦ=k1‰;eï >%¸"=B�¾I¸O=ÞFR¾äÕݾ•†m½$’^¾ˆ²µ=˪¿=®dj¾u÷½AÓ¹¼‘�¾Ì�ݽñ{¹=3°Q>�£ ¾œ™¾t¼½pG0½õŠ1=«'½dGe¾èá¾’^½� x<ãw†=S4н¼È…¾©_>N¤»»±:s<Ê•}¾âï ½H-'5½÷›>ÐΖ¾"À©»mr|»aTS¾õ0>´‘½¤Èé=8ÈØ¼+ãI=O˾½uG'>ˆ%>|1½ ‘<2-¾|ù$¾y½n f¾ŠAн#sà½k¾þ¹¾D >Snœ;rËâ>g†Ä½Rܾ™�@½Bÿ>0E˜½�Ý2½4>¾0(w>Ì«¦½´ã/½6ùl>Z¡�»En™=ÌW= ql=âéð¼ÙÎð=’ë­=§á~¾äÇ@¼7¢ ¾²zn>úTå=Ÿõ‰¾W´ ½Dh|=äŸÏ½èu¾i@ =3ô¬½´Ÿ ¼ü›»*c=ª“W»‡ý%¾¿Éy½¥xú½|`)=:<ÍÁ=>ÞÕ<ÏN>¥Ó¿:3¤Ô¼Ï›5=,/½ñ—Î;î.<xÔ=/½= ­¼8ƒ,¾¶©ã=b¾‹ï)>'ôÌ=éd½Lr->ô,À¼•¿­½ÌÀÄ=£|„½¦¸1¾^|Ž>qŸØ=ãç½+(G>ŒLP;C{€½AXȼ2[:¾FÈ—=ž,>ìëX>bàà=fÄ(¾•f >f¶p¾�-># Ü=Ÿ¦ì¼À ü½ ± <ÜN�><€¾Úo„¾|˜�>­BMM¼<¶}>pv>üñø½r>öaˆ=’n¾C)½·öB¾©~<‚§ÿ=B²C¼•S>›ê›>À©á=«iv½[M:=Ùa–½85=_ì½ü¦]­>^0¿=¤ªK<—¡ž½:__>;û9¾ø¶½›Û¬¾-… >Ô¶+½ÓK˜>÷õñ½1í½UU¾½»Ò›¾ˆãà½r!”>(쟾üá)>`>u¾7‡óA:>Iµ.¼×¸¾\oè<ò“~½Úà=¨F¾Þ š=»5\¾�f`>säN=ä ¯¾ò<¼;{¼Ò½ÆG¾õj=Í•¡½z$ê=.«=¥¾=χà=oK`¾Š»h½^Q>R¢;¾Åñ=$7мOÉ<>ϲ=JP{>Él¾XÒ羫d°>ÿ‹>«-¾Ð�§=¦§Ò½R¯»½sE”½i¾O¾+ª€¾àH>OfA¾UÌ\¾ñçE½l¯”¾Ñö=ÀEi¾f„·<ï(¡=§½]¯À=î×<ðb >Úy> 9÷¼Õо�ž=hñ0>¬$Ÿ>UP>‡|ä>!M½�Z,>‘vÞ<§âµ=ÎüŒ¼œ¥ñ½Ç>o콘2‹¾A>4艸òV�½ïâæ½æ¹·½¸™=é°\½á¾Ùi>Vò]½`še¾Ü±Å»Ê*<½¥8Â<“Œ>²�¾ÍÞØ<μg>e=»;Ý©Œ=q°=S(á9·C½³…ù»j¡2¾�/ƽ¹ø¼÷¨=ö3>4/¾À�Œ>m�¾Žˆ>¾¥Tç½ý3=hNS¾M7+<>nß¾8œ½.%š=Á­�½”Gò>ºÖ•¾ÄUe=N©e¾#V½±X6>ÃßB½Èµð½( ¾=0ŠuU¸½á‚N¾Ç¾³<Œe©>®œd=-Þƒ¾°1€<0¾œa[>iÄ‘¾¨Œæ\­=i¶¢½1‚i=YÕ½~ H½Â…4¼Ÿ·a>¡éD½1 Ì=$ÅG¾Òž=|*¯¾‰~¾• ¥=ºÇŸ>ºÜ™;µjõ=E0à�ð;¾ìk½ S¿FP½½¥"ø=“…{½¡Ï@> ¹A=Cô>GÞ1¾‘‘V>¬Æ\¾÷ñ}¾útǽ”=½h½½1Ô=Ù# ¿¾€œ¼†Áî¼ ·[>n ;=¡‘¾»s"¾%XÃ=“†‚½uˆ¶¼ P¾™Ý‰¾µÚ¾üEW>T÷¾Y‰¾½5¨;¾ð.ö¾»Ò!¾ž¨v=Þ¿/<ì·›¼Ãªª>©…>º’g>ÒÁ%¾f]…¾aÆU¾¨'=Þo¹¼2á\>¸šB>mϽæhÊ=³¤=|ÁQ<6¶r¾ë~¾²LW=k¡Ò¼˜æv>Ø�=ÐŽÇ»âjö¾ü>¢–t¾šïÛüOô½â4>�d=AN–=Š› ¾5ê)¾»f>KE_>NL̽Uâ<¾Ñ�޼‘¾0p'·[Ì}<^tG¾h>â…5=ØZ¾ µ>�¾å–¥¾á[€=4F¤>‘�¾¸Ó»ã>Ö L>|ÙQ= •9¾N”�<á»�¾™+>a>»¨®¾Ÿi%¾W³³=/96>)�¼ ¯Ç>zÆ= 2k½Ý^¾Sîÿ=øU‹½U¾FÊe;§áJ¾n�¼­xˆ½v{½s‘¾ ÆG>’†Ö=jÃý®7x¾üï‘>;CÅ=å†,>ÓÓ<¾ª’³½€ŽŸ=¹éþ¼;Ôw>ä(”½¡cl¾Ä5 >9o—>M;>ײ©»UA]>Ò½‘ÄE½õo¾U¨¾—¥§½?Wæ=¡ë#½›¢>îê½é°’>éi£½:Þæ½'™½ã{7¼Ùg½^æÎ½¶ÿ%¾–KØ;Ñ ¾ Jƒ¼n“»½î ݽ�·=AK=ÿL=�W½Õü¿=Ì~—½ùï}¾ÏÝ¥>–7œ¾?ñÀ=ླ¦f>e$6¾1¼½!"‚>½gž.´„¾�10¾Ê¶9=©ì =}t‚=˜Î3>ö‚�¾Õˬ=�~³¾ý,>a±2¾ÿ†½0îÉ=’ç@¾ˆz&>Íý�=P‹d¾�iô=/xÕ=&¯=”O=9K¬½œ}§¾àà½[e½‚ˆ$>è3ã<àß¾q >Ã=Ãå~‰¾8H¾áë=Z¦ï=š¿aƒ¾£q‹=Lࢽ^ù`=HUußZ;¾Æ·…<•Eç=€Ç½Ô’µ=¨Ô¢½ �=3’Œ=a'P>m®¾î˜ˆ¾,ð2¼$ß/½¸Ö¯=| „=Uéó½$á¾[ë�>n&½=ɾ>—ð»÷4½Y >éƒ*½ºO¾½Y>„òÒ=בr¾’�=××o>)hq=þ,­½eç½ÛÄ>(º½ öW=Šv�¾ú_±¾iP>× ?{#X¾¾�e¾j½´H¬=ÿ(æ½Þ.2¾QBø½äùê=4oнqª÷=‹K=WW­½cŒu>×@8=&Ô¼ÑK�¼“Š0>Ûߘ½ H>ÙI>ÝÎ&¾˜€ô½Ýµ½ˆÚ=løÁ½§Œt>SÙ¶¾õq½'ä=F]ç= ¾Æ·½ä$>Þ:É»ð¢t¾z8R>UZ~½Múž½Ï�é¾qøÊ¼Ä¶ù½Lœð½šSˆ<ç6¾ŠP.¾/,Í>g¶[<Îtн5'>�Üc½ÝzX>œ'´=¾¸ >Ó!†»àjܼ´í½ú2Y¾J0½x Æ¼3¦¾yLP½¥0,=¥�½Dtq¾À¶ê½w3‰>Âß‘;ؾF¾¥;>c$¾«&¯=Fð¾„D>°™M¾Î¶=n%[>#Ø�½_H¾½§ v>æ~-¾ew=•qU¼�,¾'£ =¾õ>bºl¾6§¾f&‡>Í�Ù¼ÄDH>òL‘¾�äÖ=.9¾ÛoA>˜ðö=;¿´½î²+>QÔ¾¾�¶à=ƒÆ<uÁ<[N†=…§ô½A€ƒ¾·…z½Ï¼->ú²7¾ÿ%r>¶-¨½9i³<À$½ì“š>T"#>ÁÖé½—Zν?av>\Æ=~Ö¾?D¼¤q®½Uw»dxŽ=Áp>ðü¡=�Ñ.>‡@¾™ a¼“¾Ÿ>îú=ž—™¾ù¯ý½‡¤<, ¾Ý¾'~b=€‹,>+<ò½½ƒ>žÆ�¾ƒµ•¾eºœ½Š’h¾c�ؽ²j‚¾Òzæ½Ï~K¾ý*!¾´Yþ=&ƒ–½;„M¼•9M=²-V=2Ž>òÜI>ÐaŒ½GÓ°=P[8>\Ç=F†®= +Ô½_¸J=æÌ >/ »¥0>⤿;4«Í¾9Ë&¾°•¾<–w¾ôM=?=ZA«½ÒÚʽª_Ë»�ì;½Ê,§>Æ�½ýž²½¹éè=Ë‘ ¾6M >¨Óƒ=‡!±=[Ì.¾Ô7>Y'“;—Ô=s8p¾úƒ“½ÈšÍ¾_ ¶½Ö¾Ñ™4½õçÀ½ (�½Ò̵½KV�»wþm¾ÒÄ2<§½ô]…>Ð7½4ÿ:¾ø`½ˆª<ep¾½ôÀ½Ðtï=lp;µ×q>@Ð%¼êغ½l8=¯�¾c2¯=ˆ‚"¾kcæ½¾Œ>¡˜)¾ï�ˆ½;¾Y7¾­<ïÅ‘==‰¾é¬˜¾RjA>�êŒ=-6Ö¼òéì¼Ûô…¾CÜ=½>”¢“æ¾Î¤Ý¼Ì{d=‡Í=yTš>Òõ­½>ë= ml¾O�Ծȇm=Þ6�¾¾]<ý)k½´ 6¾6.ø=Šþƒ=r‡>¾Ñô½ñD¼±š>½§Å½ÒVe<ò‰=Ä_˽à ¾Dý£>ÿN¾¼C ¾ÅÔa>ÉD¼=Ìå%¾à÷Ƚ¶‹i½·íé=ý;¾�×3¾Øš#»#m >Å>‹˜Q½È©>á+‰>eÉÖ=ŸF®½bA³=0}Õ=wOu½�,>\qK=£õô¼¢³~>¨J½áИ½Ûíå¼%ÏO>Õ§=]41>¶SÒ½ [>÷X¾@“½aÝû¾‚²>¯)2=qν¹…>r‹=ILk¾Ì*0¾’é>Îܾ\ö=Àè­¾$c*¼î¼:½,¾b½ô¨ ¼Ú©=„“²>Mm1½o9e¾G“$>,p½=ýp"¾f ¾^R>k ÿ=UƒŽ>QÛ˽'µ ½¿‹Z½ô>2 Î=¸Ö=cÔn=¾®¾^ºñ=�>Èâ"½®O龩<«;ofܾ«ñ¾]Áæ<6³>ØÝr½,¾Ä‹Ã>� [¾`B <@²ä½ûí½’ú€¼�Úl=\†=¾>–tÈ=ŸÑ²½‡Yi< �=‹Í½ÙÆ>ÒÛ‘½o—›½'‚x>®�J>´È…=Å}&>çk>g!³=ç4“>a�¾;u;½Xä½ç×;í)K½‡A¹½(eÂ=£b²¼'O9½¤Ø@;Q`7¾+'”=Z >^m&>ã0ð¾^Û�>ã:ƒ¾vb‰¾~r¼º‘¾<¬{†>ÏŽ >VŽ ¾�"»¾’3¾H„L=uŒ–½î°Ê<#¡n>@„ˆ=Î#ã¼Íñ=ÕŒT¾˜¸½@5È=ê]¾ƒ¸¯¾ú=ª>�Ö²½ ‡(¾'ð=:V¾íá2=JÄZ¾�ªƒ>'$¾J¾špi¾´¸=LC§½¨l>¶ô¶<º$¾C½½TU¥¼;©Ù½w�¡>I.ͽoûƽ5ë˽}>¹Ý¼½Àû4>.€‚>ñ �¾Y<Í>î¨o¾à¦J¾r2¾:¬j¾@ëQ¾@½\Tñ=ÄË<_4M¾8O¶½ÒbŸ>� >1%y>å|‘==0ç=�ñ~¼?õ½÷Xú=¾Ý0»ÀuʼªŸ4¾)Y¦>ëÊO:î0>–Xx=„šÛ½  Œ½Ujݽ:>Ø´N¾þ»:¾j´‹=XÞÈ>ëÃ~=l^E¾)ŽY>2¾†ó½±]]=·¥½ÄŠ•½Ùh>'Öè½(·]¾0ûç=Áüõ=<Ý,>Á^z¾nÙs> p¾Ë�?¼1ؽã >LÙ¼¥à<>t¾oH¾–ÌM==º2>¢º=Û=Ö[ÿ=‡¢É½ ¼½–€é=çk­>·í¾™]¾>ˆÂ= /=Ä!©¾ko•> »2½Ô„J¾^ƒ¸>>"ûG½6™R=8îa½]yª½ã$¤=‰! ¾Ec½À«=Fö`>‰Þ¼ >OÀ>·t6>yn¾T»Æ>ä%¾�E˜=,ª>§±=©~=J¾ƒ ¯½G*‘>' �½aeŸ=$=¥¿‡>ûŸ€½…)¾ðŽ>g†¾+x>»'“¾ž@x=puh½¼ E¾‚PP>˜Ç >kb€nÔ¸<Ýš3>÷õ½Vʾ Ê=ôD2¾PžS¾¼¥¢>˜?!>áM»^ å½x~>èà½èT‹½šñb½ãZ2½éD]¼Î]“½9¿¥½õ㢽ªHоN;Ò¾ ¾x€š½Û²D¾º%8>)†>ÄR><þm%¾\‡½Šó¾�»K>HÕ‡>>¼>„)¾&A¾é•ê½²š`¾mCŸ¾]ݽG$¦¼"‚!¼�{£½T©­¼Ä#¾:0%¾!½,>ÃÎ�¾­­¾áÖ뽓�¼1¡1>Ãþ¦½\~H>�ì½õÕ#¾ï>>Ž4c¾ÕŸ> Þ¾Mº==H¾뮾ÉûÏ>lÎ=ùP¸>Æ"U>Ú½£¼X _¾N½v:‰¾€`¾£þ—=�¬µ½9 ¾ÿ£¾E ¾07Í=ؾ û>@²>£¾ê³±>>7!Ó=¥q$>:F`=´Þ¾<Î,¾qæÄ¼Q’>Å,>"8ò=�¿ü >^‘b>­à‹>õJ”=[j=ÉÈ�>U‚>°ˆ½ µ²½ ä>º@J>~/C:åØÑ¾Yê>–#â<›µ#>CÂÖ¼�3w¾žÚW½óCÒ>:J½³üã=-@•>\¾  ©=‹ä™>ãµt¾F=½|è¼ê3>-.¬=ïI>"Ñ¿=þ—>v>ð‰˜½ÿ¾+>¡?(>ó>eKÌ=íF< {�¾ñg>ZTš¾Kç ¾ÖµG¾†pU¼&ç�¾0Ô½>_éè¾2= ½ï‘>jáÄ=ˆç4=ƒ”¾SÚñ=ÔO¾N.¾Î!”½ÛÓ½B¤=‡1‘¾K 0>�Ìp½°ŒB>¾²¥×½Ì ú¾.—>Á[Ò=Â�¾ÝÝ4>Æ =ؘ'¾ùY㽉;•¼ý»>2Š>ïïÃ6>!Ë˽žû#=s€¾{Ü«½UÅé<*¶s>Ü᡾·(H>éi¨¾híýWþ�¾¼óž¾�%Â=câ>(d5>GãV=(‘ǽèm˺ Ó¹¾Cgb=ܳH¾7.·=”}V=P ¾�Tˆ=jc}>ù9º=@xù=]Ø ½YœÌ¾E)¾ž…„½A>h�T½£�;ž‘K¾A—V>¨ñѽ(g(¾e�¾òí:Óo¾ç´õ½fà)= 9>x»ƒ¾>î8¾«øü½àÁ=%çx½[z0=¾8z¾™w½./�¾Û1ƒ>„§»½IÌd=¡Q÷»*2>Õ 3>+B¾‡X—½ ‡•¾nF¾LAƒ¾S<>|~Æ>XéP¾mid=�¡=ÉÊç½ ¦!>÷4[÷9¾«•ÿ¾½ß¾“G+>­¼>ö‡¾H†î=Énš>þb¼ƒg%¾¬¥>Àgѽ"Æ =9;7¾Xhç;�àê½ÇE¾í<¢¾3®½Í¶i¾áŠ>퀸¾®t¥>S0C¾¸¾´»¿½-â¾ÛäÕ>ð•N¼šÂͽUH¬½(6½Yò4¾µÜ0=�íÖ>d”¾s>`,<»n;ºôg >ÑqŒ¾À¢»=¯O ¾¥„=ºç/>dÑ ¾—D3>a81>WÓi=%j>>2h>ý#B¾³ +¼ÁD¾¹c>´�{¾hª‡>!M¶½i�“½ØD™=Hö&>„ìc¾]ó¾N>�>Ž[É>n°¾ˆN¾¢¨>ï“J>�#(>žÞÀ¼sý�¼ª5“=ñÓB>¾¢>‘$>]#B¾O¦¼A°Š>3óä½Wèu¾\®ü=1"¾¾Ùã<Ì{_¾å¾ Þ[¾† ½Ã)Ð=2'¢>8qp¾?À>Ekª½Ï£ù½Ýü¿½*m}¾ ƽ£2½Ðx<¾ù i=7ÔA½�Ç=&%£½¤¹Ê½ô§>Çì=í[•<¾_�<üj%>ݪT½ö >W¾-¾²ž�=s ¾¦‹Š½r¨3=úãR½»Üå=5ñ<(i½Ø>Ó&;QÑ¿Žâ->¤ë0»a>�+>A›£¾¥’i>*2ý¾l‡J¾šI&¾‰³X´ï<þE‡<9í§<è@Ë=g#R>Ô0ß=³‚ ½ªÉ >†äy<{]‘¼’µ2>…‹ë½�~›¾±s}¾íº2¾ £>Ü#¾!ÀŒ¼CØA·pQ±=x3À¾ë>ñĹ=lÌ>4>¢©s½äPn½å›K>òæT> �¾„^R=Ûó=u'˾öP>Æq÷=É V>šÀp>é3e>&¥½ÂU™¾ X¤>ŸC§¾*y“>MvT=~w>å©'¾/ù\>dˆ�¼E«B¾0«þ½ùî-¾¼´ž>xŸ½(�'¾,ú˜½ì”×¾©¬ü½Š|½:²a>�ôÔ=ä½U¾�©Ò=úŸƒ¾rwB½µô =»p›¾Ù®x¾ÀQ>1‚>qa½§6‹¾ M©¼Îß¹=ʤ?=¾nq=áÆ„½cª?Éô¾ÃBa»†n°½Úû.¾p6<>üé;¾àˆ;Á`–·N<�Qã¾ô1½4HÙ=\°½JÐͽ›¯d¾Uˆû=ž›´=Üâ�<�T‘=@¹½ÌTc½×#¡¾|ºð½8gm¾ýн/U�½J”¡¾Þ*�½@“ì>Œ"©½hÕØ½·ë=�b»=Ð�ž= Ù)<»a;=¯¶*¾ ‡”¾Øâ¾ñá<¾;Hp>ÿ%>ɾ«æä=ÛŸ=/2¾ˆ+¾9Öh½›¶Ç<¢´½Ïr¶½îù,>‡Þî<¥ï>yÐ�¾v­¬>?‹ ¾fîû½uÕç>ì>Øÿy>²´t=?��>×¥¼‡ƒ‡=Ö†½S¡)¼<3>¼Ž >ÀY¨½Ü ¿ûu>‰ë|;öÖ>ù0é=+œS>y¦½#Ka>8r½3¡J¾�F5>*Jv¾e\•=Õ‡½Rx¾÷ÄR>¨š[½±�=�!˜½�L0>ƒÛH¾ú7V>à¹A<Ôø)=ÑE4>ˆÂ,>Š[.¼ßºì¾Œ<Ò="Ó$=4&e<ÉÉ̾ǯÜ<ùY¾+rK»äе¾Ÿë:YÛ ¾'†q¾ˆØ¾ÕÉê½Öβ>[?�ôÈ믩<銒¾Ÿ¼½´Õ3µ¤>kä½B ½Œ>ÒÎz>øˆ ¼Õµw¾ñ/>‚Fp¹W=ÕT¼¾˜zZ= Û<>�«Œ¾…÷0½Sþ9>ª�r>i2”>7ûÁ=þ.À;­^©¾ïÚ“¾šî >?™O¾p ­½zx:>!³Ã=Êa4¾3Ý6=ÌHª¼‚v­»dÙN=f´‚¾TA¾è£€=F„=Ú ˜»Õgþ»öb¿¾á‰Ó½¼>Ó�º=éð>©²~>µ®ó=XØÄ=?ˆœ=øÀ>Þ„ ½Ríÿ<ÂâV=¡"£¾N¼“>±=½P>ýټݮ@>ºŸK=—£­½:ûý=“±”¼4`n>•ž½}²e>¡›•<ª‹N=‡%½Ëiž=^¸>–M ¾}tm¾W£?`L<>‘³m>KD½À6@¾·!®½.¶�¾{ t¾dÏŸ=`y>C¡”>Çî_=U�>v…åºì‡Þ½þ¨á=õú‘>̶ä<²´¾Õ±ão”¾Æ">Ù9w½ê=Ä<‰�R¾*†Ú=­Û¬¾únL=w3º¾3–¡½ˆô”¾‹¾rr†>ð(Î>ùî =`Ê׼Ė>¤#¬¾²Ëš½¶«¾ã±½© =ÀN®=fÀ=½úï½NX²>F@_=^.¾eü½eSä>xT”>WÀ><8~мSIA>‰YC>@¢B¾GÎN>ê4¥½À{>b½E 5>±Ñª¾W,ž!ÿ¹<\Ó>ç§ã½;>ó¾öii>¬‡¾#Ez¾;>ºÚX>3®_>MA>$®½,a½ Y=¢‘ò>6^,½ý稽ðYиÖt‡½œ÷¾LC˜>ŠP¾²{…¼w‹¾Àò¼;Í>¸é¾%Ù¾?l ½˜i¾ ªµ=¤ºÆ=Bg½pŒ½˜í�¼|d½¾À‡Â>³·»Ø©è=7<¼î L>¼õc>n}�¾¢ÔÂ>¶šU¾Bëµ½ ÍJ>é¡<÷ª =Aw›;]xÆ=Wß=ñ“™>‰~"¾„e¢= A¨¾&4>P=>“ºv½¡h<¾ñX@¾746½¢ã̽o'�½¹H™½tU¾!àÔ¼¢”+¾–Ì>ܱ®=„•Å<áƒk>L‘=¾¿°¾Ø¿*½'ÒÆ½�yg>彎P�½&¾!oñÊ#<¾™h<5À¤=�Yý¼ˆ™’=(U=Û�ü=‹¹…½Fûp½þ¼V=#/ ¿Ž·ª>™i½ÓáQ<¼€¾j¦½&×½‡Ç ¾ ¾Æ>â|Â<”ü?§ ¾Ÿ¡ì½Š¾8ºý=ê"¾3Œ½û1>à}$¾´Gè½èéS>,‹�>yœ6> ~J=i‘>Õ=䫱½6¤„¾M36>lo>¾²¢ä=ûßå="ð=s¼bTõ=N|à>Ç«¶<òÅ÷=ö…»¾8ÂI>}·¬<ÛOð= L¾Ính>«É½+´v¾Bój=YÂ@ºþ*¾ZP=d;=Øe·½ƒâ¼+e¹<í(¾�˜>ºQˆÎ=½Èf¾öX½µV‘—»¾�ð>§y_½kw‡> ý«¾ `B¾ûAñºµø=ð²›=~N¾eþ½Ñ@>‘Wä¾ÛÚ·=Šk>æì'>�ƒ¾)=�¾àkR>ᕊ¾:|ø=scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embed2.txt.npy000066400000000000000000007602001520735541300261450ustar00rootroot00000000000000“NUMPYv{'descr': '˜¾ø�‚=øv.¾â„,¾º<¾„’<–L>'C­=§Y=­é´=cfë¾�1é<òÅ;¾Åj½˜FÓ¼Û]r>=ö?|N¬>˜j?>û|¾§ †>ŒÁ=Tåi>qå>>¦­S¾GN¿gÔ¾Šº—>·Ð>|_µ½(o½„ô½ðÁF½fû½¿Äþ¾å½ç[å½ÿ¡½1[Ÿ>Ḭ̂>r—�=;™ô¼Xu>Hg¿Ò|̾G:Ƚ«ö‡¾0[¤¾—Ž»êR)>šü?>¹P=ÙuÕ=½ãÖ=éúÀ½®Ó”¾à£<çQ>¨ÄÔ=º¯Ï=ðî9$žè=OÉì=8Ö¤¾Rx?W: ½¾³¤»‚Ü >7!>))¾.·‘=r’¾²޾è+“¼P•�>©Í<¾ƒ#s¾Ý}>™]D=if>bü?KÂ,¹¡«ƒ=|ાéJ¥>×¹“½ûÞ¾}½>BñÞ>¡�í=*’¾¦¹>bAϽ 1%¾mÄE½ñ)¥¾P>Œ•(=´„¢¾š¿>­˜X½IêT½'zR>_^�½ž>ƒù>ëþ<>‰5›>³Ì#=¥¿$ø?J;Ù¾6â8=Θ–¼×Wc>Y=µ=át¾²ˆ>¸Ý-=ñK;¾ˆ‘Y¾­½Ásm>V±Ÿ¾LϽ¾n�¢=»�Å= æ9=Óɽ¯â½O"ˆ¾} ®=ë„4>˜3u¾„P?n:¾+ ?I­>OÄx¼ôXM>št>át¿w¤Æ>@Vན¸v>#ç½^'…>Àc“=mN¥>C�s>§?_\Ø<"€�¾\>0©+=O}ù¾Üˆ<Ú >Л ½µ«Þ=}Àâ>Á 6>0·¡>¹çä=Œ„¡½š½Ò>!5>½á^á=Ü'Ú>Ü”-½„Æð=[™*>Òâݽr#¿AÐ<¯ƒ¤>÷HǽË8=Æ > Sé½ò%>ß>ZÑ^>X$æ½Ùö¾î>V9=é;¾”Zx<™ >,½E+>34¶=òåp½S+#>gDˆ¾}ë>²O-¾ÙØ‘>h%{¾;D>I^˽yǽ¢*ξÊH˜¾eS±>•>>v t=¹?Þ½ÞPÄ<ø½Cé¿�ð<Ö�¬>¡‰t½úN'>Ì8²½ÁÆS¾Â¸=p¡Ï>Ö·•>&s“>lþ²>5ä6>/ ¿¾¬šø¼,‘>¾jÞÚ>e°5¾%�¾œ‹«<½Nˆ=âÂM¾Ø±%>V¶½«i—=ßÁÆX�#>þï:½Lœ†=éû¼]$>þn›>{Že÷ý½…ÏB=>w3¾ŽÔô½|˜¾o‹»æŽÁ>nÀU¾’•y½Frp>uuݾxŠ®=*�¾šÏ•>¡ið>±Ì-¾ ܹ½!Ë\><³«½[>ݽ†< ¾T_°¼a™ =?È?>äbh¾JÆ­½øHŸ>kŠ=ƒÅÁ>=d˜»”·p>‰ëk¾™8J¾½­W¾€}R¾Œ�>áú½ñ&>¾› Ÿ½N#Z¾gMó¼Yo´¾Jcƒ=ÑV=&« =å˾§Òw½ìf¬>žÃ¾´´¾¦þ«¿¾q Y½Ý…Â=Ž)½¼^½ÈÝœ=)%¥½ÎݾrÝ+¾Â¾½ès…¾‚ =r¡”¾¿· ¾?g¾S® >²ÒK½ó#¾dz·=ä¾W¾NnC¾€6J½Uq(½‰¿`½©î@¾›Œ’=7È >”$B¾P%¯½=ß½=lCÞ½a�¾¾ƒ;>Óz>›Ð”¾½¼y#ʽ�é¾%ƒ/>w`>OœÝ>¢z½Ï`˜>ÃDI¾³‘Œ¾‡37=yn�¾À¦8>fÔð>üÚ¿AÖ>5æ¾ïu=láÿ¾Ë‘m>m©ý½ç@�> R”>O;Õ>Ñ´ ?“õ4¼h­º/?(¾BÝá=¡$£½}å= Z…¾·mǾˆˆu¾`ȽëýF¼Ò’·¾±‚ê<:æÀ:œÓS¼hþ¾€$=ܾµÃ7>oo>bȽÔw¾B³R>øR¿¾ ê>¤îý>ð\V¼ ȃ½�Ëô>.4¦=´DI½Ê+¾kMн"1>½¨d=E¬‰½ç‚¡¾³©#>Ž$•=FÛ.¾›{´½Máä;Tü¾4Ó|¾�ë½µ¿šð´=ÚÄ8½IÝ“¾ó ê½$Mμúä¾qg!>†˜ƒ>žû¾O§>e|¿\½ì=„lÞ½FW;¾}—¾G´£>±T»=u¡=- >ôýó>ÉLŸ¾jôнxĽwyê=ЇÎ>çw>›Ó‰¾zʤ½�*�>Ç0Õ> (A¾Ã-&=ÀNؾ…\>Ó�‘½„í<­]ºã“ܼ ñ¾z«/>0̽¾öéz¾x¤<$a±½bj>¬&Ë>Ê>„Xv>wýI>~Ö©¾ã!é½¾5c¾ÿs> 5š>µßô¼ïbÁ¼±³à¼ÿ÷½5QY>o²†¾û!@¼tò>IªN¾mœ„½$Yœ¾ù$I¾ ª>ß‹=äVÆ>Ÿµœ>‹ÏÂ>¸Ð|½¾ä=¿ƒ*>~\C>D̽@úc¾>Æ’>1½3= Â7½îOx>&ª¸¾u2<ü·Q>[&%?×K<¼sN>ÅV¼“§Ó¾’_>kë?þ—½ŒÞž’¾7œ=[2¾p�½æî¾Ê$$>óÿ½2ì; Æ½-¥í¾½;À>]¾À¾]];ÔÂå½×Î >84½$…½r:;½›mâ¾iD>r±>¯=ݽtsš¾7|½võ3>ÌA»ó¡Ó½3Ž=bŠ<>µô>�2>°’>ÑØ=WÜŒ½‘�.>.1ç¾QゾŒ†>á¶ ¾ðê«>«C<=�ù¬=9…¾’â¾…þÜ>Q—m½­öº>j€_¾©O·¼Šèï=ÌÙê=Ñ Á߆˼zYñ½nÐŒ½¯¿¾†{«<æŠÃ>¦±>e²»µÈ侇¾Å÷=‚¯º=çÓª½øvß»pü?ù³êÇô*>Ž>[ÿ>µñß½¡½,>Ë/F>¬ *½¼º>å½á(¾e*Õ>¯3>¿ð»ŒÀ\>uW‘=Çû ¾0èå>™„|¾Íš>¼¼Ô>ŒœW¾j¿Ç;ý˜n½Árî=]£N½%ýH9hF¿¾Wô¾Ï„–>6®(¾;HA¾$ö=nP>¦Y�½LÎ�=Â->>Ðõ<*Tи«½Þ°>ª…$¾°µµ½[«þ=d›->¬o<*“­=©:½,çL>V½{G>[(>ïd9>Œ.*½ ´ƒ¾Šò >Óp>Á.¾A\Þ¼ª^Ù½¢Ë‘<=>‡{¾ùžR¾ïÛ©>P;?4;C_>3÷0=‘¿;=J¾:œ“>À•)>™»X¾ã³å½dE>@6i> W¤½ññ >îë=>—%½¥³.>6\ˆ¾( 2¾¶•ļ }羋Ïͼ¦nÍ=ÒAI>`þŒ¾Ü1¿E澚%0½ã¬‰>�”>°9>í$£¾Ž>%y ½"+>§6“>R­M<ù<Ú¼‡�½¬Å™¼©ƒ?›b¾íï’¾…&ó=Üë ¼B¤Ç>Ô¬Ú½9ê¡=Û=ò×<-€ß;œ%v¾ÎN?>w¶u¾–¬ ¾g[<½Ðq=K2¾08�¾|²¾£¦Q>:pø¾Ûn/>ÕϾ¼'�>cyY¼àgÇ>:=ù Z>"ê<«`¾„›¶=u>(„ç½,2¾S9¹¾á¸°¼Zœm¼Õ>P~²½ôùc>™=þûÂîÃ>w~>|Œ<¤úÿ¿´[=ËL¿ ’Ó¾Â<ä³?<óŸý½Úç >àQ=!á¿þÁ>'+8>>Z–½žà±=K 8=�©K½„OP�ËA½¢•¾(Ð;>‚㫾۴K>qŒ½‘ù ?SÍ>JÁ_>ýp²¾³Ÿ¾¿q¹¾¶f…¾Z�h>| ¿µ£>>Ö>vÊ¿N 0>ܬ�½422¾–ò½Å# >ãšI>öÆ ½g·2=“²ì¾µõ ½ü@«> Dͽ®æ¿0¢@=¾Z¡½"ØÆ>»Ô>SæÖ=¡Ô=¡K=n½¡¾ÓÞ1;×>V¾ÒŠ2=?$ ½0¶>J©â¼2¤>>h„<œì½¹Ë>’3ä=ê²½¾|Ê=2> ¾³]¾Îߥ½t¬>¶Œ¾¥n¾°lÈ>t]ƒ>]H6¾É¹Ù>eÿW¾wž>â#]¾Ùr ½ÕÊØ=# >ßè˜>È낾ë5‰¾K§;>õ>öU ¿¢ªz>òï½=ø:¤½Ö½¬,B¾,º>¦�¶¾R³=пݶ>B¯x< UºÀÅ‚>Îai=“q¯>—{·Ÿ¶½ë�¾Ì¯¿‡k­½æcd¾Ê„�=ÝЇ;gD?¾î_ì;Ò4)>>¶;¾Çq!>™1*¿Æé±=nœ¶=e_=>Ëšš>½7 >î—=¶„“¾aP½ L̾ÿõs> Fã¾¼Ôµ½Â�Þ=«¾ü7˜=m#>2ð¾ðé<ƒ”R¾¯ÌÎ=k#Š>Û>‹¤½WÞB= ž¸¾™™¾Ë_’>$ ¿ÃQÃ=�¢ ¿C³Ô¾¸‡¾¼¶3¾ü,;>¥u‡½Î‡¾ÌÉ÷>ƪu¾êÛƒ=g½=ò¿I¾ÞÑþ!Ì!>æ6Á<úÆÁ¾­AÔ»ÕØr¾O¾#¾Z�—¾Ûë“=P9½Å«Z>ùô ½’£=9龋8_>ì§ß¾|ÃË>yÄå¼×$¢=Ê?|S„¾{Yé>Y)>#¯=gÒP¾-Ü=qê§¾0¥Œ>R:Å>©W\>E–,=(V¼hô½Pà¾kÒ¾X„ >Gò«½\á>™¶�= Ó¢>âø€¼(n¯<€Œ¾äàŽ¼ á…¾žËœ>°^r¾<?÷{¬½QP¾J•$¼Ô4î½i!ˆ¼ÄTZ½œXÙ½Ö.M½·B¡>(Ï,¾U²–¾žáo¾bmé½å¬Ý>›b=b‡ö¼#Ї½g߬=,½äd¼…<}½üæ¨=� v=�è­½gË¡½¾m²½³‚>:n£¼„ ¾èË<µ€>=£ô¼axݽñ™º½jpÇ<�Œ\½â�½’Õ—>o/¾*˜¾âY?z—ð=‘½·>q5¾Ã3̾~�Ľð“¾¡F°½ à¾ÿ‹<¾\R(="!z>“.÷¾óîØ>§F^¾œ¾¯ÈÏ»­ë¾Ìì½ù ?t›ã»ÿp‘¾} ½/ Ô=4iw¾Pßÿ¾eʃ¾¶¸–>PkJ>6ç>#›3SM>§SM>Cb€½Ücà½S�¾Ö+o>¡9í>þÌÌ=·Š–¾4¹]=lÒt¾øqÚ»s&3¾AT’>ûA ¾ .e¾©>çž!>8Ø@=pp¾ê¼|Kн3Â�¾Lò½é¯÷½­:‚>ì«¶>цû¬=R»ž= ½5í6?ÁE–¾[<¿[¼>¿K¸=‹eƒ¾k·¦>Bã¿^!+>u(“>ày¾›a½`Íø½ï«¾´ú¾ÿÙ=µœª½Bw«>°¹ƒ»ùÕŠ=jÍ>J ¾½7D>æ=F$;>$p›=$0¾Ï;'¾¦b­½7¹y¾¹=Ô¾ ÉL>ax½ÚʽaXÈ=í‘_¾d˜5=ºîš½Ýݽ ¤ë>\c4>‹–Y»Û¶&>!s¾>ªÆ¾?æÊ>bœ?"Æ’=¶›=+QÍ>ÀÈÅ>@0¾ÇD¾”>E¾¬ª>ãT­¾4·à<ÿe9<=Ëñ½ñÍ(>Qó<=¿yê>ZúZ¾P%?ÑWk=ø—t=¦5�=k°è>‡ =%”>Å{¾`f¼CÔÜ>á³½d÷>¤Qð½Ìh>äÞ/¾ûû‡=Ôè=�uþ¾�< >Ýì>“¼=¡¥‚¾Ïž½Ïd‡> ¾—'4¿V[‰>°‘¾Ã¯s>çÌ…¾'‹¾ol>Æ1ã¾›ßM>â¾õ4¾6•?¯ ½<ë=©pÁ=¸z>u-G=Ñn?# Ü=òZ¸>ªä¸=ñ5Œ½õj³>Ø©>ê­±¾ê—¾?èá¼×/Õ¾èJ¾×€þ=¥j´½óG>üó8¾‰™½½1w¾8F)¾êô ½ºDß=�;.< .)=þŹ<-´,=R0Â=-À>ÈQ¥>rcr=ø^l=£,;>eø=í[>ij>‚HU½˜.P=b`½jY½/Š+½ì¾x¾ŒÐ¾Þ.Ý>e‰¼à|;?Nܽ@Ï>Ƕ*>·Ä¿íå„>+�#¼î�>ãTd¾Ã¨£=&!+½#pK¾¡VF½v:�>ãT³>ù2>&¾>ãí?ÑíŸ=Ùé¾ýÿ齸¥Á¾±Œ>Oо&‚½çž½\"¾À1Ù>GY>õòƒ¾êTš>óæ]¾ÐÁ=…³ ¿ÐøÍ>Ëõľ¡"½ ¯¹¾ %˽hW½U3/¾~¾Z¥­»½S¼6¢`¾Ã:->l0;+DtÐ̽e—ç½sQ\¾Ø“°¾äÄ'={_ƒ>iB§¾>€½½\š¾ìn>µ;¤Ž1¾]!>n™#>Œu*½êq> ?â°Á½dþn½¶‹u¾¨Ì<I’>ÏÓ'>+íÚ¾?Y€>ç½�>X�©=Š®s=Ÿö´> ¹>q½*>C!¿ˆð±½üÛì=|ñ„¼‹.?öa ¾¢¥…¾·K�¾lj³½bÅŽ=öx‚¾}³¾w¾øÌ,¾Ù” ¿®OSºä�Á¾ár¤½”k¢<†ÀÇ>1a¾º?s>ú§¦½_¸Ö¼¹u{>Ø…~=oKñ=N(G¾6$�=ªë-½ „ÿ=&lˆ>_p>3_œL¼²>¯x¿öåì=*cá½Å¹�>@ÿ¥¾y›½Ï,½ã'>¼Y¾rMV>lD¯½«»‘>�ÝÖ=ÕÖξ¢´í½×«$:–Œ?a«£=ç>½â£¤>ô–Í>(W¾Û>Ö3²¾@a±¾ƒ»H²¼Z¦‚>¢Ý¾‘í^j¤‰>¥¦>T–½>Þ ¿ž;¼=«i¾s£C¾¨Rþ¼rq¢¼;[¹=CJ?ußX½Žàý±(Þ=‹Ÿ?@Ä£¾s°—=‡*>Ï‚º>.w¿ �>Eá>$À=ž¶y¾ç¨>°ªV½²$§½¨Ë>ÊÙ¡¾˜mN½0¤0=·7¾“É»éñS;êÁ޾h7^z½‰O=¨S†>ðçʽ\ý->t¯¶¾»0\=òª">/“Ø>O¨¾k>�¯=¼à„¾¤§"=jC¾Ý§ø;!ʼtØn¾×† ¾«{¾åÎ >==—¶*<Ù¯D¾l9=¾¤bU¾­P/=-sA¾Ë@>Σ¼#_u¾Ù½¡-®=êé¾h¦>X�:?°?¿Ó=¾iª>j­>»Ñ7>èÔ¾k*=³GËÍì?…Ôͽ»3¾˜çà=]¾ëO~¾�+Ù;£»’¼C}-¾îKí¾ <†>¦~Æ>Î×e¾´•>ÂʾR“g>8ó¤¼Ñ6A=ÑY>{¾Àþn徿â3=þ=©¾EA÷>„•Ƚ§P>œ”?ÎN¾>ô_¾Nèi>iˆ¾Ó‹> V/¾–'Ê>m7½‡y2¼eSµ½´€ ½.a< >•[ ¿Á˜õ=¬ÿ:}ݽÎ$ù>¤§ü<ûì>©0¼=‡¯ >ó÷:>TA¼>êŠ>5ù¾Cý>Y™;½QYµ>Ûí>ØBÔ¾ò×2>{d½$š$>ÁÖã<í X¾}A¾×‰E½ð_¤>Ȉœ¾¶5¾:� ; ¿�¾møm>¹Ë6=mƒ)¾jH±¾ í¾aFô½ Ê…¾>I¾N8C= [>Iî>¸±>T½>é·¾à\§>_®¾‹Jξ ˜@¾ä5×½ª7°¼™ÊQ¾¹8?y…Ѿ(žr>ÇÆ~=œîå¾ š½Øý½¯->™ÔU>¨œ¾ »í½ ñ>t:²<×Á�=°Ľÿ¦„>¶¿=˜<ˆ>f§›=N`¾œSÀ> g�¾á5>„ô>¢w°=ÒA>_­8¿;©–¼!Lb¾ø®C> ‚�¾$«Ð½&P=À;³>¥«¾¶é˜¾|Þç¾íO…:I�ý~ƽkWÁ¼Ë9?¾ÄÜù¾_m¼¼0x½>»^Ö¼²¹I=>Å#¾¬JU¼é�)>@†Ÿ>"t%>lì†<3 ?c�æ½.ñÑ<ÝŠ½†™–=oE�¾KK¾î4T¾¾EÕ¾{T‘>]†F>ÀSª¾š¬ú=+Üú>Û\¸>:¥-=�,@;mp£>c%ç>…Uƒ½…ˆÁ>A˜¿¾¾b'¾•fo>šˆ?Eg>7W£>dm®>T¯½³¦Ð>¬ ྱę½�õ0>>8-{¾Œ©*¾ga•>k{?fæÇ½nht>ÉrÃ='F?ÈB¼¯Ú¾Z'æ=;~=E2>Úò÷=XP>۫Žeñž¾t-P¼º¼ˆ¾£™½;�?}ö?¾œ Ÿ=À¾>Ö-‡>ɷƼé–ñ<´©¯½(ã¾ìÆï>¾E?½ÄÃF>‘ >®*>&9¾ˆà³»í[™=h!n>h�·¾ëZM¾!?'æJ=¹9•>긾SÖ¾#…>3®1?}Ó¾§™G> ;¾Z„>®ì=U÷®>¸£*>è�¾»>Þäy>Ì >¿3M>SÚU>ų¾¬Æ@<¸½mª¾šçY¾sýˆ¾bÿõ¾ì<1>=Š ½/[{½@ôÙ¾SSG¾wZé½åöô»‘:¾ x»=j‡>ÁP/¿xA>ÄL¡¾ã >'á=½>j]â¼d�+>•d(>ñ?ÄÜÎ=Ên¿Rï<´2?�‹>ò¹�=DcB½õx”¾ïðP=Žg¾=A€ì½Î¾˜Ël> >WR¾šÝ€¾S³Z¾åÜ*½SØF¾‘ž->ÿ¨¾Å;>>Á‹=Q,q¾n›Û¾Ú­«¾n3g>}êš>šÃõ>À*=¾æ¾„‡¾`¼¸x¸:h;¤=+›¾wë ½˜æŒ¾Š�>®NÛ= †‰>­ËH½�9 <ëì¾ ¾øU?¾BÖ>ü`˜=•ŸºöH½úY«¾$¶¿}Ë=8-»½˜Š‚¾úh¯¾£;¥=î`¾‹>¾5%û=‚øö¼0©‚½Šüû=äç7>E³ ½Ô±¾ÛÐï½àÊ<=¾åá”= ;/=ê[È=‘6™½†=ï=mh=¾½ s¾Ê%˾@Ù½ ko=�ÇŒ>®Åµ>«ëÆ>ôÏs¾Çb½+*¾w<†>t¡<øNؾm`�>þ]F¾«F�¾é¾h}C½­¸t¾SYœ>”0¨¾l=xæ3¾vª5>B�}¾p¹Ç¼Â �>8e¾Ž¶½Á6û8�)>Ç==?e8=ÏÞÒ¼ì>)Å»>ÞH ?4t[n‚a>ˆ‰(=œ)=9Nè>™E^½çÛ= ·ç=�ï;‰Q¾IçÓ=èj2¾ŠÉ>wü>âÀ¾­T¢>Óy¿=^%¾=5‰½>Ó±Û½–9ÏÚ10>®ñ»»iž¾`»™Dz+¾L%F>sg¾âöì ¶˜¾½µg> yP¾æ %=½hi¾�îハ­¯<ª ø¾^ÿv=pÞ—>ÕË=Jý½¼Á1¾0u޾'®ñ½z3ß=†h>=HÂE=‰v½[ËŠ¾·…U>�x>{»ß¾bP½Øͽ ?7ȼ>CF€=å?>,ŸÉ½œ Ý=]» ¾€yʼÚ2ݾÝ+V½¹~-¾)H½T??¼��=lÍI¾fć>0s¹¾ -¾»z펽N0N>n i>ÿóÅ>ôT">N+³¾‹²o>Ûbî¾ô4¹=O·Š¾2ý¾1Q>Îõj¾ø5½ Ú®½ßA›=Ç¡?ȇ>ÿv޾,Žº—Y¾ü/Ž>B¹Ø>û³C>ft¾øŒŠ¾ž ­>É¢ƒ>Ü4оþ„¾ÚI¬>Œ/‰¾N¬¾)aa>rcP½�k}=}dc>>^ >o¤¤=‘Ái;âC¿Ùw,>"êÛÐé¶¾ê-\>1Ü ¾êès½�~;NŒa¾³^É=`/x>x¨€>¼ƒ=ø)ˆ>}�ö½\ž¾õ낾ñ„›=€]9>¥ŒM>%pP¾ù>„=I½Ù¯O¾<;¢¼çcÿ½ºgM>~�>ZÉ?Ûø¯zf.¾,ú§¾;jý¾Ì¼t¾Ê§J>o÷Ð=Î�=bÐ ¿‘”0¿=B>Eø½e^;Ù ¾ “Æ<�E(=D¾ð·ù½Àn¡>+kܼ¨Ã>Ϊe<´%ܽ&Ï >ὑ>Õ婽†ѽe_=3I=‘Ý>q«Ô½ê䜼Ž!’¾§3D>Æ.J¾9æf=¨ Œ=ïPª½ˆŸ­<ØP`¾Å¢á=~z'?~ê0¾°¢.¾Òd>‹V>!»­¾Ùä ¾yãó=¾Ó¾6I>–³<¿Ié>).ð»S¨&>Çìø½Íð¿ÙG¾5=Á¼`?­…½ Ð%½”·>ØGŒ¾›>øÐ¾÷ÚÓ¾#½¢‹!¾=;§>æÈ?SÐ>Ÿß¸>ê >‡Â¤>¸¾÷æË>ss;>OäѼ®I[>–«¾/¶>ª<ƒ>‘ñ{¾ëë®>@7 ¾L0Å=‰s>Ad>%9–½ˆæºü‘Ƚød”>xÀͽb¾¶=½Ó:·°%>¬¢ô=D@,¿Mâù½ßâ�=¢™¿O|i=•´7¾°’½ BȾVj“=Vô¥>à(ø¾è'‰>ò½vŽ…¼V^->–K¾b3E¾Â‰º½i†þ=ª>�í¿\‚¡>2 Ý>HŽx>^¿�>IZã>â_C>Bœ¾VJo;kdŸ¾hjb¾;"¼¼Î!¾Ÿ�V¼Möоèv>øJ›=�ª˜>2,®¾ƒÈ»=:'¾0é-=È9>ûš½± ¿S7Œ¾ŒB®>#›rž¾Éð>§)¯¾\•?’J†>Ë?¬•�=8êƒ>òŠ2?$;­>vL¾°6–½÷9Î=†z =¤¼¾Ê›ù½ÿÛ†>�¾¸½.I¾¸Åu¾tL¿á[ÐD¨²¾OD€>2ú¹¾À(q<®·¿ƒ1½¤º=AgɼNYã=æH¾ó*C>¾À¾;¸Ÿð½¤mù>Ø[»=ó K>W@O>ý‘¾C//>(_T¾ŽÔ¤¾ªÎÆ>b<±=T‡?ߺᆪs> Û|?¥>n @¾¼ü™½!1ë=¥â^¾o ¬>r¦±>¯t�¾ò®¾ƒ…=«n\:i³½û¾Ɏ�½ñBѾ ×м m‰>¨Û=‚›½m«>Í„Ÿ=:#/¾¤1¾y�¾¾9¾wÖ‡>“ࣾ�†¤¼Ew>æÇ?]´½)ÈZ½éNˆ¾•Ð>™Ñ‚>‰˜�>BÒ>™Ï•>^vC=²ê =—<¿Ù³¾N^½I½Üs£>×À>q¾Æ«½b(?„­>üõ_>õá>ƒ³¿=Û­†¾B°>¾-n¾+ü ¿¨RW>¼´½‚ÐÛ<2¶<×b¾=˜èa?�³m¾'>-Íã¾¼”g=xÚ“½Ïp„½0T¾…nÂ>ƒà>æØØ¾Ê­¨½RR¸>ÑúÀ¾?Më=yÏnºÜ2`=:‹>žQM¾ô´…=ó¦Â<ûÖ¾vÆi½žM>Z“d½¦ÑL¾/ÖC½vž½'¾î4=mJ=>*O‚=ös1¾g±>™#¿!Ò�¾*õ³>˜’ü½Ï=%¨]>¤¼¾†l€¾A�´> ×î=Ýq¾½"ï=·pѼø“š½Î¡¾ëŽÄ>Íúоì”y½ÒN¥=g½µe>S›¾x-ä>‘Ê/>3â=TĈ¾ÿ„9>MÀu¾cþŒ½KDƒ½ u\¾�V…¾jùÊ?8ý¾šÄ™½½¾Òô‹=þ=Ϲÿa‚> J¥¾ �>Fý¸=–Y=IL>¤"õ¾LÛ>%›+>� ù=üÙ=µA¾ÊÀ¾ ¯/¿``3?×ß=Nˆ½6ð‚½¥eÕ½Uʈ¾+¹i>îÊ×>ùÞš>èÖã=ùôž¾ÿÅS¾¹žˆ>È¥F>_Dî¼ß¼+¿Bú=4Q ¾6ɽÔ,¾U!=ù3ʼO� ¹^òø=‘ ‚=ù6> @€=qÞ ½3cÕ=‚Ñ>€¾œ'»¾ð”=§ßô]N4¾¬S}>|Oð¾Ï&ý½€ÿx>€¾V£½ˆ«¾\;±¾y8³>Á›n>rÑÎ=VÓí=¦“>Ãòk¾ýZ>ા~�ý¼hûæ½|sn>AŒz<Íð¾Ä¨&¾E±=~.æ=,u¾¾þb»)Ö$=è:>žw|¾‚f=9,%¾Ÿ Ñ=öÐ?>¦q ¿`Õ?åóË=´t̽°Â¾ˆI>=Êô½ø.>Çô?6 Ï>*°¾:18¾åø÷=·.½� µ½ÚÇ£>Ù–U¾ãÁx¾À™%>UX„>³Ÿ³¾c2ƒ¾¹Ø(;ݹ?Æþµ>»–>ÂU> Ñ£¼ÞZ‰¾@óÍ>æË•¾Íõ¾¾ß¾<Çø:½»ð~>ë²¾p÷â>¤ ±>6ó½ÃC>‰äª¾ö�b½Œd>Í[�½ß=ô=e5(¾*êþ=ɪ¾ 2¾[¹P½'¾%ɪ½gq¶>;r€=ð’s¾®>ü²?€¨=†³•½ž@:=á=¡0 ¿i‘®½#f ¾ÚHǾ�­•¼q ñ¾ˆ!½[ëo½JØŒ>ßñ-¾ßó€¼{øž»º?1=[ÖÐ>æ×¨>“Õ>êUÎ>?¾oS³½:©¿ß�M¾5~¯¾@€=´Ó�¼¾RÒ¾Ùº…>é7k¾UöÀ=Äÿ>üš>Šy2=N¦ ¾ž0">£Îì<ô*ƒ=„DÌ>¬ >Cwо5n?SV¿dT>PUê<� R¾¢i>›Å£=/>�:¶¾öÜu=̹=‚&>AÀC¾÷ÞS¾ð²r½Úº?>_‹±>a•Þ¾Ëî =þMÅ=í¶Œ<: ;? ’ ¿ƒK·¼AS>Z ü¼§|¾¼ß9ð=ë; ³é=⩼m¾eŒ>xp>12‹>8šý¹#Ë|>�¿$¾Ç©º>&¡º½DxP¾{;‰¾ÃdÞ¾] ê>˜V$¾¦ ¾„»B¾V¼„=€©=>U8Š>ðó^>¬3t¾˜.N=âI£><ê=Ò¬o=*À7!ŽÊ¾>þÖ½@0> Þ¦>ÿÌç¾ö°L=#A¾@Ƚ~Œ½FÜ>Æ1>[?t ¼~Ï{>Ú€ê¾&—g¾J)½êŸº>)&}>ä:=Áz>@Rõ=4c‡½Ç-Z>ôã˽ë©î>³§>mƒc¾IM½\9ÿ½r;?¯çž¾sÿ;>èo¿¾)&Ò²‡t¾ C'¾�D>øóy>Áþ|¾ä¹¦¾hõ?Îä9¾ÉÖ"¿õu¾î?,‰=¢Â@?nÖ¾#ÜI¾oW‚¾E‹¥<íI¾5˶½£Çx>à�>åu>\/Ù¼r•Ë>×5’:uþ¡>-Í—=À½ˆž >ÂRP>9™¿–ÌÚ¾ Ã%<ž´½ž¨Ü¾#“´=²0#¾§>[Õµ=UñÍ>l.T<²–ö¾[)þ¾¤Ä>3QB¾ÁÑË>¯/-=HÅÚ½Ž?|:f=ô¾Îê ¾Sà×>Œ‰Ã>öP'¾ ý·½!�¬=ød¸½ ¨½­+{>;¹�½ºeн‘ ¾k‚¨=@e÷½52á=L÷�>°Ôñ=Ãj´½­+ ¾þ¾:Äœ¾Å­Q<P?jŒ'<Ëæ»>^À>Vû;¼J~Y¼ãN€¾¡2”¼Úž%¾õ ¾³0Œ=¸iO¾‚]ݾˆšT=ò÷�>c:?*\>ã†2>XžÝÿ>-p'=K™Ý=Ô›ê<ýÄ辉Ù=vÁo> Ü>DûF> Ò½­Zˆ>¸2¾¾õÞ×½.à�>˜7Ê>{(m>Zíº>sæë>Š9‚=X Ö½�-£»•ë½V� ¾(Š·½æ§À¾Ý'?N~“¼Ž¸a¾W—>QŸ>¢Ÿ…=?M–½BÔÏ“ >hVV½8Ž>ÇÎ@½{Çœ>úŸ¾¯Ÿq½ñ2¿¦ ›=ÓÕ³<ú#Œ=÷5b=þ)V½p°e¾¨ÁŸ½ú…m¿�€>ï«g½jľmx^=èO½y‹¿Ò7,¾Û§£>™ ?[$?\Ž =x$>I ½WÝ ¾pÉ‹>Ë¢ã½�³º½÷ü±½ª³ ?4yy¾Å"¯=Yôà½Q>\=?qw‹¾¦Ùà>9+>|A¾¡Ýª¾Ý t½<°Ë½’ÚJ>@Ú“½-ð½�Ž®<·P ¾Ÿ¿ '¤¾TÖ>¾­ ³=I3f=d¸›>ì4õ½Rÿ>:AQ¾)ƒ>²Õ>‰Ñõ½Þ€Z¾Ÿ`þ>xb¿³û¬>i[\>ëâ¾u5ú=®Ÿ>ŒO¾Þ’ ¿sT�<x±¾ÜëÚ>²†¾Z×í¾TܸI¾gŸ>JÅŒ¾‹Ü ?Èe̼žU�>úס¾81Ÿ>^—=•Yê:pæý; ½¿‹‘ú½ë¼q>£š)¾çVe¾Ä]>”V–>AäͽÝOÐ:J—>ûÂ=¼oþ>ø�ì<°Bó½fý½YUT¼wí>¦$Ÿ¾Îƒ¬>ÍB§½š,=Ñ-=*ö>Us‘½T )½À£æ½=ëÒ¾~Å»JK5?y°>"Á¾„Ÿô=•8½éþ\½Fä¾ g‘>o‹Ü=�ë#;V %¾žg; _=õ0½> ²š>Òö"?y¿{lk>#:=ðK+>5›\½K|¾0´¼P¡;Ú½¾¬¾ìÜ_=WÛV>ðúL>ɰ½¶«? ,É=\ �>Pß>Ÿ>‰>Ò@«=´ä�=솼t´)¾]Ä=ô±�¾8¹¿>Âù>=œÿš< À>59š»è–:ÖàÝ=×C½YÑ»>¬ÂÐ=Bmv=˜ ½ó@¬>4� ¿¬’›½Þ¯e>HÀø¼0Œ–¾eÙ¾>^¾1“«=#Xµ¾rVÓ=®bð¾µÛ½r¥š¾õ˽0…½‘”O> 2Ï>¬ë½‹šè¾¨è ½D„#¿@Q�¾…ïQ>¼e?=t´½6+>Ì*:=S‚??k%A¿p¸l¾še=‹\Q>Fø#?ÞŒ >éS}¾`2®¾¹Ð½�Äó¼reŸ=ù=>ÿ[÷>¼Îö¾ï0¯¾e,>+;W=Úó½¾¾ùl¾H«>^H²¾j±`¾—j¼¾™û>¾Õ5«>[Õ¶=¢o_¾ ¤¿i ½¾‰½u¾+ë[¾×'¿9÷u¾EðÙ½ºÉs= ʾ ä�½Qþ¾jø^½°Ö0>8þœµ¾¨½al>{½½¾¡›¾W—¥¾lO‘½Ø‡Ð=�ù¾õs¾ ï^=Ó+å>让=‹¥>èâ•>5#Š>V{¤¾ ¿…¾Õï¾d”½æßs¾à½=p…G>÷û‚=ú<�¾ÅùÈ=B"?ƒ÷>h·=ï²�>>ö;=4ëA=¶Œ==ÿ?BEí=xÅ=Z½×½p,—¾ü<\’œ>»Ý‚>'�(>žAÐ=c”*> C#= ~1¾)ñ�»"Ï¿—WŒ>mw<=ªoξÞY1>v�¼?ÕѾº3Ÿ=ÄÎ>O¤;ˆ‹ >S-ƽœE?'²¾dM†¾ú3˽g‰=¢å™>KMÌ> Ñ6?Ö °¾nDŠ=êb»>\ž“>+覾�\{¾Ý­‚¾ô,Ú¾ïQÉ=u°>Rfµ>—HÁ>¯°ù=T‘|¾Ôhd>¤ñª¾:g]¾n]:ð‘¾<›\¾u3ú>?ê�=žyè>µ¨>@ÌJ>Š»¼¾mÝ=ÌGš>pnš¾”–=¬t²½K8Ã>¿ðï¾ÚÖ¬¾b�>ü3®==çC>/Ú¿>LKf>KÅs¾¸>#>u»,<ŸáÔ>>6É>¯±}>g:Ò½s›§¾NR¾ijò=0 ‚>™Pø<G§=RŸ>¢®¾¦œ ¿ i¼FŒo>é`£>ÚEt¾ðq5¾ ³ñ½xÖ•¾Œ¾M#@>ßm¦=ëÝ�>Þÿ?5L¾ó¥?ú5”>så>=rŸa¾ �ó½»F‘=Ø >áÜ\¾•Uù=øx.>®Å ?ŸZ·=i¿>†¥ý<ñ›e»b÷¾-_нsv¯¼?µ ½�tL¾iQï<©d¾ Ð,¾Óm×<Œ�é¼w>Ç>‰Âp>ÅOZ]3>°À$¼—“õ¾8 #¼ Ó>Ÿú4>š>ãÓí=“è»=2>‡GÀ>$@œ¾ý;®úw¼hP>ÚSO¾Ê�œ¾8pR>¡‘¤>‰·ç¾º·<Ù¤=æÓ=¾†§¼|è=&4�>–mÁ½J¯×½ô¨�¾§i½Kõˆ=h¼¢=†¾Î“^¾ðß¾W©=¸û"=Æoz=P‘�½ó•¾%x·¾ñün¾ù>xP²¾«N˜>Ùs?¼>µÒC=³Ï"¾Æñ½Æ�¾#w¶¼'¶G>dAè¾í<>©ö#>‚==¬<°>Ù€þ½{%½íY*¿�A>Ð÷ ¾ –½3Ó`>ÕÁ=ý&Å=× >[޽?†ª=‡k•>0Ø�½g[¿¬³p½`Ž>)ð>Tõô½Í%?ˆì½^/`¾‚›E¾ôrß¾Ó®½G±ö¼]9½v#¾TŸ½·¿R-�½Ç”3>A Ö=íÒe¾°9Þ>l½K»�6�>îî£>8õ€<Ƶܼog ?qN¾ÔS>ß °>OÇ£¾é¶ú;6ï¾=FÀ‘>6$p>ì�Ò<1¸K½ÐF…>8c½y >›Ð_>u” >ëbnº›–Í<®c’>ó’U¾¶á‡¾˜<�¼I ¤¾˜§ë=ã; ?ØÁ<¿î�¼=®¾©)L¾[�<ÒmF>¿j>×K.¾öïä½|a­>è6¾Î~’=“™6=¨>hÜ=l—̾–›>”¥d=Ö° ¿iÞO>8Ê@¾€ð`>&õÝ> a×>ÂLì¼™�~<¿–Ÿ=NÎË> X¿4äö½Æf¾„’¥¾8äè; x«=i(>¬$Ï=É쯽å¯ý½¾*]¾ÖPÌ>Ü™O¾‡¾]Í“>d„Š>M¾^À½(&~¾LØÑ½ûôY>¨'޾4´<ÏÛE=5Ò›=½›¾^@º=w¦B¼÷ÆŒ> „7½ÑÔÙ¾Lÿ©ºÀAˆ¼�¬¿ïoÉ>o¢�¾¡s>Û©?Eï_½ú4W¾©p�¾�¿°_>Bh=Êœ<=þ³>@F÷=(Q7¾‘X ½‘·8>W½õkù=’‡¿>­å¾.°¨¾P?¾J›‘¼24…¾&ÒR>W;;0ѽè0=ð�Ù¼?ËÞ=æ¡ô½k¿b„½pc>ëG>]öνÿá‚;®\÷½9µö¾ª¾dº=±™¾³`‚;Úâë½T¨ò=¸Ô¾&™<ÒµX=“yÓ>o·> 4™<“>™Ö©=òÁ¼½ñE¼H™-½'´=²"¾…"¾©%°½.ÓÒ½8v¤¾ (ß½¸D½ 耽Â>UÈ?¾®:œ<‘úÛ½À‚…¼¼ð…½œß¡<Åí <=0?÷\³=æb&>¬S3>L-ϼ€Cì= '¡<‹D(¾& §>¨;¦>¾< �Ù¾o°>,)‹>7îB¾¤¡½8w¢<Ô9Œ>V3¾–ct¾³�¿Õ®½+²«=™Á-¾Ãã½ðã=pÄ�>fôz¼Ž}!¼Lö ¾¿_½¾ë+Á½#À:=bÙ˜=; ¾÷�½r徆«¾>{¼§>—2½@­°¾ä½ÙÒ«½ ÿ?#…>¸¤¾¯’•¾UdýÀ>²i�= æO>òâ½"5Ë>¼ á>Ûè=6“A=Áeq>·A ½Á»õ>´i~»\wQ½¾ÅS¼Exƒ½V¶¾|°ª½sܼ½Äœ¾�#U½þŸH¾sÁ½â�¨¾f׿ì¤y¼'N >m½€E1‰¾|Ì>Ýçs¾lÔ˜¾èÚv>¯†=!Y<ˆ«Ò½ƒ”²¼[@y=“°ƒ¼ù92?§QÏ>j#™>âµ>«�½Ô»½`Ù ¾Jb =Âòñ¾<™r=[k†=´®¿�„> òÅ>š_¼½ÛÒc¾q71=¬ì‚=w¾@>å6=ºÆU¾²X�½¬àÔ¼‘7Ž�ɲ½®Pœ½dÉÑ>g€î=AD4>ú“_¾îQà>%­ž<Æb‚¾‰]4¿ð:>y£c>ÕOq>ÚÐ=Nn±¾_ˆÝ¾wöa¾3Ѿ‘<[|›¾zü2¾ngx>2V–<ÖÊU>%í>þ«²¾¸¢­½â4O½“½h>Ù=Kà�¾O²¸=›C=¾ñ!ô=¢¦r¾pÍ>j”Ž>9}{>;†=?K¡>Á�·=ÆÕ =ƒš ¾²1¾:2Ì=¬>G]¾ko�¾I†Ÿ=8?Y> èw=ôO?½q×j¾æÞ½(>`>¾"¾WTR¾¹¾‘½‹î <²ð6¾Ò¡‰¾0´>~+¢>˜�ù=«¬=ÌY¾o¹¸=—£c½~Ô“½XÖÆ>‰åš¾Ü>K(­=Yú�<ƒ Sºn†À½ìŸ>ü˜d½eÌÊ>hÑô=ÇÑu½9a¦> >Ó>¦ú�>hE4>÷°¾Tû˾ˆ?¿šå=ò??mႾôâ�>ˆ>Žã•¾2Á¾Ù%ܾ÷>ŠIT>}a˜>íÁ¾¾oä‹>²}½eØr>èÀ¾1>9(�==ño¾ZçÅ=Á÷½cYQ¾�õ¾<èŽy¾£õ‡½#ú|>œ0f½àM‰¾½yν3¾«D–>b•�=WÄ=°Øß=?aô>Ы¿cîM>ÃJ¹=$–ª>#=FSA>\—í=Çc޾y­ë¼š‹Ì¾£¸]<¶ql>Nà ¾ªõ=Kî=h€Ù¾ö¥«¾Ž6>ÐPn¾Œ?‚ú?Ú^‘¾BLú=–6:=è”>Fµw>lc¹=L2D¼É>-Ä?Í?Îy=dD=ü¢½ó§»P—2¿/¯¾'«©<Ï%:¾çd¼©-¿Èüñ½_;¾þ“ã=©$‰<ÿºG¼ì~i=º+&¾™�’>2~>%Ý >‡–ƒ¾þÄá¹>ß›¤¾�Š¿½»³>Xc/¿GD ¿Î¢é½öºÊ¾„�I½}¼Ä¼ z=ë°??§Šº9Ûˆ¾·^¾}P»¼a^>õÌ>@¾­Ñ>7°™¾R "½“l>¾Kw ¾×oö½»«½>R=•'�¾åi¸¾ÄÔR¾ÜòD¾fkª½› ?ä!ƾï¾3SO¾çÅ>Ýöÿ¼¹Ó�½Æß¿À™i8Ggˆ»©g ¿V >ºR=l©Ì½Î¢½>dÈ·¾y <Âä–½Úd¾ñéþ=ôÅa¾ÂT½¸t¾QíÞ¾#±¼;Ä€A¾ç‡¨=3K>‹,º¾þ–½öÔ¾”m?*Eí¾'¾¥]œ¼†Y`¾'£à>׊¦>»áˆ>ZŒ&?7UX>»»i½Šl=ø´="Cê=� >Dº>šn¾£̽,¾¾¦î¿‡Y<>G>–4 >$é¾¡ê ½¶ "<>c³¾‡-´¾©U>&¥~>O ?°H«>Ù¾äó6¾~оnÉ >¢`L¾ý\>FU¿&?3¾…ŒH>‚º…¾sõ¼Be0¾¬rõ>�Uh½¨d�=Ë7Ÿ>f>Wñ.½`ô¿¼»\=>y>…F½Ù…B¾¹ d¾+ >1è:°“[¾˜n>ƒxµ>Ö²g½õ#¼Öè;‘_6¾<옾I¨½Í ?ä a½× >6M>ªå×½mžÑ>a޾–!µ¾Ø?~ ¿Å‹™¾¬ÑB>,„>.d‡½UDï<ºýϽQ©…¾Ù>¢ë= ¼Í=¶þŸ¾„7¾zÝ>«0À¾Ä;å_C>KÜ(=ÿ'>ÁÏ0>•ɹ½È¤s¾%å½M}Y¾MÖ•½Çsÿ=¡sô¾vÖ2½œÐB>ý¸¿_L¿Äàâ>Wcã=gXö>KX®>Õ;§>a¡{½´ì¥<ö�ª=""¿±œ;u%•¾ƒ==^ꆾ+í—¾žå>  ‡=Û�=VPµ>�Ì=exü=x{¾:…¤¼´Š ½¦ÑE¾õz>&Ô‰>cU‘=äú½�0ß½H°½üíò>¬¸0=1»K>ú¥s¼6=¬¯š¾LÅr=ퟥ>Þ\½ cоF¹½ мmå5½ßˆÔ¾&Ñ9½+=A=ìàÙ=,(1>À=?·v5½nx>C§n¾TQö;*G�>qï=ÁëW==ݾ§¡> � ¿æ— ¾ªß#>æ,¾_Sœ¾òþ;{´Ð>/ö=(xB=�uô½¥A ¿ðù¤>fõm¾­t±=²¯Ñ¾SDؾΈ§>¯«þ=õ/k>© F>}qY>Á �==«Ö¾úú<�bQ¾´6νŸKø==T>Ü„¾¾˜è ¾R¼š9½qý¾½Íþ�>f·Œ½±e½| œ>r§¾[ªl=DÅ>Ö’j¾ò3‡>‹Œ¯>c£&½^i¼=ä=”>௼ …þ�V[¾f»:?1d<¡¡å½Î¥{½ØK¾Å¹É»é¸»½¹·H>Š¡´>ý !?W*è=û–?\KO¼ÊÓa>É3û¾}¼<m ¾¬±z>PW¢¾pK‚»l0?G%‚½çŠ×©Lr¾†ì6>3´>QUÅ> a>›Èè=,÷¾=;k>‹O’=±~�¾SÂ#=‹†>H /?UQ =B“ؽ Ôâ>åÌX>� Ê>e÷Ë= ;�=}ž½¼î%A½OŸî½ô?…Ë̾ՊT>„ÊÛ½çB½‹F½_ö>^iœ»LC|=î¼\hX¾™U?ü=ºˆ >± ã½3¼nj—¾ ]Z½L/µ¾&œª½r?bš¡>ÆJÒ½¥ý¿':>X/2¾tí9>¡s >ÿâ?h+>‡MU¾’R>‚ŽT¾C¨Š>ŒˆÉ=—#ž=Ÿé™=ü9<èø>€À˾%å—>w>âôu½ü�=Vô|¾D¿N…~>»Ú >\äÿ=õ?¬™½Ï@¦¾õm`>‰:>ÌM¥<>Û’¾¨GZ¾lýr>έ>2 ü¼G=YE£¾—6¢=ðºÒ¾ö±o¾FjI>'ýÏ=æIœ>äq<¾3Ñ=ý2½4²ì½Û,µ>2ܾIš§½11Y¾°½ì^Û=›º<4ò>>ù6’>Ýä�»ð§ð=¬ß8¾+޼[ƒÉ>w>†žœ¾ öå½sý=¯9Ã=öÀä=ÙV˜¾IŒ¨¼Jp­¾ì>>Ðܱ;¤ B=“!€¼Xª^½¤Kü½ =’¸ý½ø‚ü½‹&U¾}v*¾Ô�=f8¶½|í‡>­J¾¯`€>­ÿ ½½ï›¾z¢>tÿZ¾R›ä¼Þlx¼ÂØŒ¾ ±[¾•®¾²„Ñ<ÝøN¼M¥ƒ¼r™^¾)ž»¼/à¾ã›ã¾'N\¾F¬½#Œ½ß޽)÷[> ¡¼âÈÞ>Ð{2>Ý4>>ëàõ¾�hq>ùF¶½^Œî=™Tv¾Äü§¾Š!W> ‚v=E))¾Â½f×¥=׸ >´/N¾r Œ>àF–¾ðÆ2¾ú©¾õ`¹>·Àà¾O\™¾08JœK„>ƒ >Ãýl=Üü‘¾ëݸ=Ç·j¾´ºÔ=`©&>Г>60?§8 ¾'“M¼¢Î:½ÅÍ3>–Ç(¾Ñ¶Ä;ì�>;+=/Œ=QÅä=Y S>—™ð¾yÚ<²Ž¡¼õfƒ¾¹î#¾ˆ›>¾«+ƽOÍ>JÖŠ>Jkɾ×±='Ÿ¾Šƒ$>Q˜½ˆ�žn\‰> ®‘¾mO¯>rD¾y•¾ÿd{>úÜ–>;K&=E‹Ú>¤ÇÛ¼„ÿö>J^ >—ûŽ>Ú¿> Qä=Mè°>6Ù=•׎¼ìw¾"l¡;¸ŠÜ>l¯¬¾É1«½Ìs>g*K=Åû >›ò"½XºO=k¾˜>¾°\=ð(=>.>ak�=7Ó¸½•wÿ=4û;äp¾y–Î>uù�=ו¾;(¤>Îëî=$i”¾U„Ú>“Y,>]¸>¾D$í>ÂÞ‘½Gú�>ä9˜–‘>KÏȽ"^Ö½b/W½‚²¾<�§¼IÄ> •Ľ!Q|¼×Ç¿îî>-GG¾?ÕÖ»K¯;呪<;oY>qÖé<ŸÃS>·¬€>Ú¼??»×¼�°×½Ò'î>˜J>„†ø¼äð¾öSß>_å³>wSf½.N¾¯‰1¾ðKð½ q½¨ ý=—ò¼>.™½´Ø">)/J½Ú>b¾[¤¿Öóò¾Jüã=]‰¾æÆ½Ý„>5…s¾á¿ í…>·%ã>B{ÿ>ŸS¬»]xþ¼j [>¬>0*y>Gˆ¿".ë½ß¾è¦±>7ÚH;˱S¾�§y¾H·B>ÌF¿“½>¸»(¿”¬*>GW >í“>âÀ�»­ > û½•¢Z=�é¼jó·=ÚÏã=z4q½ôÞ·¾ ´�=ÛsR½gÀ/¾L�¾;\-/¿z>”Xf>ÀÑ'¾öá²½8°A>“�9=ä�=ûÅ�¼qùÚ=|Yþ *?C8_=7¨ ;Hþ*>O>3±§¾¹Ó>>0:�¼˜,�¹*†=Uc4¼|™P¾Ö–>ÃÙ ¾ݽG¾Ȇ¾ÝO>×ð��g¾~Ê0>ãØ¿ã޳¾ãÿ½t>¾V,<ôvH¾¤™ý½Áž¾ *? úνWƒ¾äܧ½õ�g>ZÑ|¾ {(¾Ö¶D¾Ðˆõ½X«w½€ñ%=jÂ=Uÿ`>(p¾¨0‡¾Q/>˜>Yó~¾Ü¾^Ð ¿VZ£¾Ýˆ4¾„$’>Ça:>©-üî•=vù‘½yЬ=B멽h“ž½Ø²¤<¢Œ¶>“²½ð ç>ÑýÊ=¡ûU½êeÑ>î=†K…:p ¾[÷S>"·=´H†¾÷bS>ìaÚ½ÏÛ½·½ì&t½Mi>c<[¾Æ¼:¾kRe=Š[I½ˆ¸ä¾¹5­½¨¶¾¿@²¾Ÿ�>oF½­ Õüú<¾ºJM>�5¢>d×¼>tƒ=OCZ=¶Í?¾Ú_ý=Ät¾G½ >}Ùj>ð!æ¾û-Ÿ¾q46=Á»V<ö@> – ¿ØÙÖ>®s$¾Ã“S¼x¬›½FÅP¾‹·ð=.7b¾œ\½m¥~½Dêµ½Þ„®½ÆQS¾= f½-싼 k½}¢½”�p>o >¾{Ô<>Þ�辇sp½K„÷½4Ø< ÿæ=É—¾F�K½&¥¾ Åõ¾:¤>«;¦=¡7=x'–½ˆw]<Óñ¾ÿ &<¨M�<Dͽ²<½½ëi¾×§P>Òþ+ ”ìÉ>ËN^¾ôš]=´Ñ©=³ìE¼•á!?gI$=j¥‹¾ŽоÀש=¢°¼(~W¾éî?£’í¼ä1¿>²Æ–>»Ç_¾¯¢«½Â4I>Å¢x>š¾N¼U¼åJ¾Ì�k> ¸>zó¹¼q罋º8¾»Ê=¾nÿ=>Ý¿êl«»—Ú‹> '¾ª½ûÎ~½ž,?>ä�>Âw-> qö=2¼,½ò_š=1gÕ=aw=¾Á:Ð=¶ >çò>0e¾^û—=›ê¾±È¿XíѾM7"<Þ:j>\ë—;>¶r>bú5=©HϾêª>@ÕÄ;¨‹§½Jo¾\¬¬¾°ÉG=Fs>ÛìG½6©e=xº>ìÌ¡x0>±‘X½�<¿¾c�Õ>OåÝ=Ÿ"â>’õ=ýa©>×Ê>åÍ>,¸_>ë-¾ãä^¾4諽 \I>»¤&¾TS3>ʵF¾ñá=óΔ½Bš½Ž¾­“À¾E‹¢=Ãs?‰4¾Þ½’B±>¥Ý’¾E½=ÓœX>»ãl¾\Ù‹=öEé¾-6>xT'>û4>Y?p>pEö½Ñ}z¾Ù­t¾®÷νZ­Ð¾ê½ ¾I «½QY=2|ϺÀqA¾Ë´Ø¾Å&½‹” ½,5;>’a(?FfA=@Mª=kƒ >¥ÝÍ><® >&Ö!¾ipÙ=,N¾wZ¾‡Ö¾×�¨=³ÏN¾Ï}0½iè•>‹\X>Î+A¾ƒ®O>.…¾8ë=É‹V>Gp? ]¡>Çp¾hº?=–s®¾h×m>VeB¾Ñ<’>y‰k>€™¾³®½�³>¸;p=Yò> Û½ W :«¥¾ü›Ô½¤q¾ Ÿ2»zA¼ü￾·ô²½aÛÜ=‰¯�¾¹oÇ>©b¾º™¡¾@†,>ùT�¾×”2¾áq>>§>£I3>:Ǩ¾sL�¾'g|¾þã½Üƒ÷>ɽŒãò¼ Î¥>özé¼7â]½Û`L¾·)f¾20¶¾PÌV>Ykb>3QN¼¼ïî;è¶>>Ϊ¾—‚_>棾xDù=†ÜC>0‰·>J­=¾+™> ƒÉ¼q,’¾F¢m¼?ña¾wf/¾„.CÜ�½jV=4¬H¾$å-½’TX¾®ª‘>r>PB˽:¾j%?=JÄÖ>\‘¾£q¾…¿Ï(3¾ñÞ/>®7@¾/ÂÙ¾ó„¾0¿µ+™= ¹= ` ?þ ¾B¾QÎ>Ÿ8“=<–뽋…O>#Áͽ¯뾧“æ=$ĽßG<kH½7”E=ûw5¼ˆ ¾8j¡¾åÍš½Âþß=Õ¾‚Z5½žÚ@>%F#>?g•=T$³<—‰M<¦F4>Õ5޾bÙâ½7ÒJ¼Lƒ¾Ö5!¾à3i>vˆ™¼zŠ×=Dlw¾ýˆ>.ÊD>Œ9H¾A¸°>­>U¿Sg">ý€¶½ ˆ>uåá>íšM>^b¾#û>½z×§= /.¾M9¥=±“Ô¾K¬¾D~˜>�õÕ½@»g=I&¾îÝ ?û䕽aT=9ºÙ<¥õ:¾bä;ŠCL¾âÞ³=wOœ¼\~Š;@™v¼æÕS¼Ïï3>Ù¶?•ú½' ›¾Dnz>ú>ô}P¾úoÁ>$¡¾\ñ¾“Z¾Pˆ¡¾ßÚç¼}ßã=kÇ€¾jQ…¾’�˜>ÈH¾䎌=¡H‡=Ë ¶½V9W¾Õ@«½O‹m>+Í�¼Lݱ¾b«b½Ó&?]ØÂ>œú=ö?”=º¨‡>]8Ͼ¥\νùZÅ>Pç&¿R÷À>tÖX=ó¢·½£�¾sÔ¾ÝX)¼„gà>† Š< ¬>/@£¾èX>z׉¾;ûŒ<Ÿ3q>gIo¾•:Ë=f^½ûèZ>�í>²Ý=Q¹9¾ U¾ÂT>6ŸÇ¾Ÿ^>ã.€½‰V¡¾"5>cÈB>¶(ü;Îߣ½~„–¼�>ž“ñ=ó¸n¾_6¼½äNV¾ä¶=-Ï>S"¨>$¯Ì¾5僽Å$Ô= Y—>øAB¾rØò½ɼcŸ[<²¤3>Dè->÷´=ˆ«¼u½)>Á|Ÿ¾¾k½5<=µ¨¼ÖWG¿›>“v=ñÇh¾@µ‰½'>õTÁ½T˾y4�>ë Æ¾–OÇ=H»}¾Úc›ðÜX»DŒ¿¾Ò=)5¾‘b(>ró ¾¥;¾9C‘=…­W>W˜J¼òµ`¼P? ½—!‘=ðF >¿¼½¼NF¾Æd=Bf̽<‡c¼_•¾z4@¾ €Ö¾u‘Ò»¤Þ¤½°áB>ÖÚR½?z²¾P�Ì=äh ¾D0‡¾°>g A¾og6¾y ê=µ¾äݺ=0‹>™ã½¬ò´>½L ¿Fá¿è’½Ó¬)¾Šr?|'T¾–�Ö¾¶š#>y¾FF>å<Ú>ÉK/>e�=7aо¾é€¾ðÞÛ<]3>¾ÆUK>Ò5+>§]ì¾üvƾ¬ìÅ>»¾[jó½°â¥¾â=•=ÜÀ=ÈY„¾-¥=ëK�>•£ö<Ý0¬>¤¨>Ov=¾KC‹>ŒI—=”m¾ãXÂg¾bÓ>>;Ò�¾ïó½ÛÝ¿<€hY>úÒ�>‚…>{éz¾Ä× ¾ÆƒÒ½ >¾w,>n(¾w„¾è„Ó½în?¾Eâ½°ë>¤?ý=A<½ì]¾‘G޾~Ù8>èª0>kk>ÊR¾±5ÑŒwm¼szÁ=ŽPœ¾) ¡¼‹Ð¼¾ø™¿ áÕ>)uÚ>ï¹<Žyx»� „½ý€¾±G?>ìU‡=ÕM<>M. ?Tˆõ¾ÿBg>½¿ñ¾�1‡>É£>¾OȾûÍo>‡á¡¾}Ó¾©,†>"'ä=>CÀ½ñ…N=/¾Ý„¾úÉ =™}½BWù¾>¾ô¦£>�6ɼв ? 5¾X¾ G¾»ˆ¾aä5½°:>å'¾¿`½C|å=���>†VÂ>©ŠN¾jõ›¾7A�>R’‰¾Ê­É>Õp©½WÜ'>ÊI>ó ?/Ü¿¾)`ɽmÉ =6¼Â½º© ½<3B¾¶i5¾åFe>Ù¯?ˆá”>®Q7> ×Ñ>ÛùÓ½¾^ã=us¬½]B–½–>O¾p缈âç½:±2¾†nݽJÕ<ÂÏC¾­Ì=uˆ;=vs0½ìFK¾›qC=»¾{€>ö…>Ù4j<¦§¨=¶t >KÞ=úý=÷tÀ¾8y¾jÔ»¾À¼iašĽQ(H=×òT>vJ=Ò¤Ò=òT=fÞÕ½ƒª€¾†s¾‡%å½—ñͼwg\¾«Ô¶½M¿v>1;¿½ÍK>•Ÿ-=jÄ‹½\3Æ=f½µ½"±ä½XC:¾&¹¦>}S»¾~L¾½–ÁŽ> lk>Ïþ=/Hß>±è >ú4†½"¾:’Ï=)G…¾xË-¾`$½A¡9?I¾^ÆV¾,ˆ¾.õ>W¸Ï¾`0Ⱦ„,8¾õøF>�À¾æ =h`C¾�ox<·C=𳄾Wøë=/~ ?3§‹¾1!¾Á¿þáÙ=Hî¾S6¬;ÎìN¾H1½.üœ½Hi¾ 軾6n>¶Ù†=FŠ.¾ªá�½ T¬¾6uª==ƒº=öaH¾>�¿ m‘½w†6=–M=K()>[µ_¼r:[¾è=>­c>zu†=ù™Ô>¬A€½ŠG¾A�=>°¡<«©R=:½-¾*tÉ=ò|>B �>'žê¾ë%5>T‡"¾+O²½-º¾q»>ôK½û=¾�u½‡w,>ÑÅ£¼§º€>}¿=¾Ê’Ͻ{>û O¿,‡ó½W]”>ÉÅÞ=~Öõ<õ¦¿ ?¯,•¾¥'®>–jÔ>‰¬#¼I7ˆ; ;¾øI5¾}?µb>øY6¾;ŸÛ¾äW¾YØâ=ÌÃ??~¤º¾@Ás¾G^A¾0±Ú¼—û¼Á¾¡¾WCþ=eš>0g€¾3O?¾ôV¯>�V¾&a1½ÆÆ>é1–>j >¸š=¾^0±>#ÄÌ>iŒY¾w¾¾E¶Ç>—6n½Àu7;,õ =n…>¤";Itá¸Sqr>F�}>ÅG´¼×´,¾çß)¾ÞÌ)=Yô¿¾¼Ç;¼ˆRþ=H02><º¨¾gþ¾Ñ¶=é(!¾@àq”óX¾ü“/= KÜ=yÞH=–yì=ù">»lP¿×Ï ¾ÖG§>R8ç½Od¬½´»ê¾b W>u¨g>¨G�=aC>¿ˆ>¡œ­¾’´'>²(=B_żJK—¾ö“ý>5z–¾g/>ƒ/ó=�Hƒ=F¯R>or ?ô²Š>Œ‘Þ¾DØ�<'Bº>Õ—A¾ Õ…<8G´½|J¾lRE¾Ã…»Q_<ˆm‡¾xÖ1¾+Qû>Ý9<œѽ9mß=—ç)¾Uþ?'_é½€Ü>Ózr¾ÚÁ>Âó™¾|®ù> i’=霆>kÊ—¼39©=‰.P>‰,¯¼Y­4ºzÚß=l㫽¼½@>[J>‘l>±¾Äl}>pù=à±Ý¾�Ð3>•h\>§b¸¾›ø£>&_=¾a—Û½k¡>9ïa>ìrš½�éu>ø8%>7`>}�†>Cý ¾·žŸ¾Ç–.=gœ>[âA¾÷¶¼’o™½%2À>âýl½ˆJ½Ìü’¾©¶<|ž*¾Yˆà¾Bhg>BY>_É+?É`1>•ù½ó ´< Sé:Y­¾!½›o8¾W×¾eŠ¿¾Ì–¾™¶>„tÞ½|> ®¶½ª‘³>±€i¾˜Ì0?�#='„3>†„¥¼ˆBƒ=’­¨¾|Q.¾Öƒã>¡õ?ç>šG4>ª8½ùЫ¾ÚÔ'>Ü>½�Dµ¾“²¾–¡µ=çV ¿¤ =X·Q>.€>°»…¾øÛ¾¿s�¾×W¿� üº;Ã)>n+¹=ŸìÕ¾8@æ=¼ P¾ÞQ¼>èŸÉ¾›­w½Ã%ˆ>G“-½^a ¾þÅM>8 ¼òq¼·2ø=R–>4]¾v—½ÿ¡=‹(>j2—½ôþ�>µE½ ûʾ ¾�Çã»B׌=ÿŸ4>+Ø;¬)Y¾J8+»—©)<Ç�T>{òÆ=Þ†¿T[·>–ýïæB¾>ò£>ü¼K�¼½‘~¼<1彚kà½1´b==D¾ª¿–¾û¬¾í>½Ë[Ò=áñR>¨õÁçy¾782=ÁœÚ>zJ½n…B¾=¼Ú õ=l¤¾º{d=Íbu=‹¼¿ü¬>V>Xõö½>=µ%ë>ßö¶½ºù½Ø>•¿1‚ ¾PÍ>Õ¾>ð&p>wÑé¾z™Ú½¥>x\¢¾µ×Ô¾f· ½kšƒ>dÑy>Ï>¨½×®'<,¾zµ­»î[żÿr<þ7½Už?>§‰­=_â~¾À†¼¼ê§¶>U­¼¢ø>ëг¾€;n½”íg¾Äÿ=(§<>ª‡>àp@¾”PÀ½©­G=ÄÕw¾]°~¾šEŠ='_—¾ôÁ†>¤¶ ?Ž%ˆ¾$MÔ= P�=Щ¾�¡i¾Lí¼9£&¾CwÙ¾žÆâ¼|Ò½Ûñ>¹ýؽ𠣾¡cP=©ÍÙ¾ìIؽhfg>k¨ý=§jö»mt:½Ê> ?q¾L°¶½�Š>ºHÒXx[½‹ÊÓ½f >¸ Ë=:£½j7#¿ž€¾Ó‚>õk†>§“ܾ6Ùä=ã=®m"½•b>?¶K>å‰>|Õ±> :5>ªKÿ½ôÃ2<ôÒÙ=†g >œ’¾(Ü=!‡«>\T=Ú¡¾$›8¼å§}>Þþ$=FØ">(e™½$Ÿõ¾¬->Xd]¿§È[½I�>ŽXßÛÛ&>Œ:/¾’/…¾–æ½Ü›Z½«ËÂ=¯x ¿× ¨=MÊ>¢>Hß,½èqc¾ã®Ì¼Æ»Ë>÷ú¿ãYz¾”XÊ=]²“=ô‰½!Œ"=¼«É=>-›>ü*Œ½Ý+”>UÊ¡=ë²ë=Øe2;¾Ÿš=\C[¾‚¦E=ô骾-âA¾Ó/¨>êÕW½01“=Õ•¾¸¨P=�Æ©=u"òþ8?‰þ>å9\>ÄR—½â_B=M1Ï=ÉhT=œhp>—f>YùM>¿Ÿ°¾¼ªõ>jL.¾ã}“¾–�›=½1–?½Ÿˆ>óex>n�¾ufü=<®f>¾9B¾D€¾œÔ>óYE½ÃKÕ¼¢U´¼£T“>pYe>Ø¢ø=B¡˜¼®»¿>µä->ïa¯¾~=ƒÝ#¾f¾¿öW>A…¾­ª{>x è½ïh%>Ö¯Ü>¤}ѾÖ÷ý½ãœi½ƒÁ‡>s`æ>G¾N;°>¥`>>fÓÚ={�™>ÁD„=�½Y?ŠáÉ=d�“>ç½.½žo²<27œ>+ó¾­ ¼S¨ä=£%1=”ˆ6¾hh1> >ÿy>c»ˆ¾o>k¿¦¾�Nœ<Èb>J/£½ ž¾ãщ>O·<¾C¶7âøƒ¾(D¨½jè¶>p?½= ­>ýÑ> ³è¾l�K>(¡½¨ º¾?ëQ> O«¼^�Ù¾—4ˆ½À•!¾Ã¿˜$‹>'ž¿û'ƒ½E¾=T×¾hÔ¼=Æ4Ï>_ò¬¾­p>„Ó�=#Ú?a¦½½\.f>E¶î¾æø¾Še½§ ý=Hp–>g)å¾Iež½fä|>r(l–¡€¾4­ˆ>š¤>Ó/™¾$žû„ɽk6È>àÁÁ>aÅ¥=xFA>¡§¾BB¯>·Q¢ŽI¾á>,âô¾íà)>û1ì¼ÜDF=¡«¾HÈ>ûæ“<“¤t»M^¾ôÿ¿!ÊÓ¾”�<B…>en>ïÉ=¸‰M½ÌÊ“½÷"Ž=ÞQ ¾kÚ¾Õ¶>©^ì½öYÒ¾­ò¾Ãº³>ý3í=:½í=�vŽþGS=(¨é½ÜÎM½Ç2þç ,;QÞ=£?+䣼3^¿=a †½Â s¾Ÿ©­>’çe»%H>H{¼>¨´>3§¾jG†¾ü¿Ò>‚>C>/|->É`¾Ç‰<=²Sž¾‹]>)iÕ>™N>ÿâÓ>ú­Ÿ>k©{>à?=) ?¦Æy¼:xˆ>'Ï&?rë$¾ØÏì=©–~¾ ‹¡¾ ÿH¾ L¼c”%¾ÁB:¾b$Õ¾¾I'>ˆƒR¾ubó¼@Q>¢™ø=Ôiÿ<Òg”¾™™_>îÍ>¹ì¾Kb=²¨¢¾+T¿e»!=M1L>I¨R>.>/%º<'·J¾h´‚=)£A=©Å¡¾ö_)¾ Q…¾+8M¾<úq½T ¾[M²½ ¢/=�í¾Ù>Å>œÂ`ºÖU½Äbã=6–�>Ì}§½P$!>19Ö=ßã9¾°¥Í¾ˆ�>0\É»²1·=!ì¾]ý)¾þo½¾å`x¾Z„M¾¡âž=Øq¾F>ÂV>"#¢=&Î&>g; ¾Š©ì¾É> ¤š½µ)B:G ¯½õD”¾Vq¾…®>b_,>ŸòD½¬B>Åâv½uÁ¾p&>®�>Î2˜>s&•¾ �í»�>Ò%>"[ö>Ûi»=b;ª>Lø½—ƒ>7×¾O¾ÇÙ¼¬t–½< ˆ=pÊã>ÃЛ¾ùþ;U‡A>LðȾðU¦=Ê©¨= È=¼cž¾ïIô=>þ(¾¨X1Œ¾ÙE>öU/=a¾¡¾áÑv>ìu†½©$?¾óÕD¾Ü–¨>2sJ>oZà<ü<Ò=P»%>®\<¸¯,?Öñ€>Ú"d<¹>ÏÒf>?˜=X’l=Ÿœ’>p'“½È>s2¾Í Y½Z¾æ …¼nˆÐ=Ù¾ùcç<Ô)>7@•¾ü”¸¾qÔÈ>2õƒ>þó.>Øq¾*•œ½jZÔ½ÕK¼¹ì{¾o�º¾é’¦=3ž¾Püv¾Ï’º¾á¬U>Ãñ¾·â+>ûú;¾± M¾âÌs>Šø0=lT ½Ì}Ù½ÄÙú¼€èó=€qß¼Áß>n•¾\Á#¾”µi=û¾ó1¾ºà’¼›ýÃ>¥cŒ½“lç½Áhû¾÷Ýê¾cWa>ì>e>öÌ<öñ(>M!¾–º<èˆ>7ˆ©½OÀ‘½Ã¬¾¶Ö˜=øj‹¾{€â=þZ¥>J›>å¿‘>z‡é={÷±»Ìí>m—f¾iû=nÏv>Ò±¾mæ<…ßÁ=Ë�½ˆ3¼cO>½È„¾Î}f=;0þzžâ;ôÌ ¾=âŽ<î–W¾ã°Õ>¾Â¾Oò.¿ïå9>þð±½øJ=ò +>-”%½#4¾ôË?^ [=(}³>dDX>èµÙ=˜^X>€¤¾>é¾¼A_¾Hû½m†�¼~pؾšˆ¼j)¾Ò`¾D±ž=�Á½'ö?¼�î=‚(½ç Ú½_ =Kݽ\^½ìÌy¾Ó²—½Äú=ŠÈf>k´¯>Fj>Š=Ǧ¾³Já¾U޾˾€ª=/\ü¾ü)~¾ Úð¾Zí¾¹ý¾U „¾l80>êu½¾ç§�¾9çN¾g �¾DŽï½Ê5¢¾‘õ˜>X‡¾WI>|Cg>È6Õ>öø>%0Æ>ßáÇÏ%¾“Ðô=^Š{¾öøJ=Îxu>ZÄ=H?>¥K…>p3‚¾ ÕÌ=²f®=*ÎR>�Ó•¾À8 ?üXêeÅϽ¯ [½Hÿé¾�BÅ½Ò >Š~ô½F×é>¶y¾0뽂¨ ¾JÀs¾båT½¿¾ˆ¾œDu> ÿ¾Ê¯�½�˜|½ŠòR>CÛî¾¹{‰>ÏÖk=ø“¾ ȼ¾!æ=…¸>Ý2ª½<Ïæ=‡)å>„®—>M"c>8äÀ:ó¼䣽äe¾F¬å=µ®>t&I=kὂü;¾D£¤¾æk¼>û›>¾_F¾íj”¾ËÖ¾ â\=üÄ?wøh¾GÓ˾„�½SÛû¼Ú÷ð½§î\>Mÿu>±@œ>}Î¾Öæ¿%ÝÖ½K¬“> ×…¾¢@> þv¼;½í¼"ZM½KRô;ÙKÆ>éá½{Õe<…鋽8Œ`¾·d¤¾‹ËÚ=lÔ?­È¸>ÈIÃ>+>>É{ɾ›!Ó»’,Z>`x°>××ý½èO¾«žá>㪾Nå¾È8ˆ½"¯¿ÐÁÃ;ËE=èœû¼(—->» 9>lžK=qÔ;IÕj>¼»¿¾Ðrä=‘6M>}ª¼ñ:ž>Ä¡ó¾Ð…=AkŽ>Võ»=Å8>-øK¾Ê>"A> Àо‘}½€ ?é3ã½À�¾Õqy>L¸œ=„Ù^¾!¢„=˜ý²>u%–Á±¾[ßQ¾�Q½>µs ¾±i3»î£>[…¼Üq>坿=Np>@.X=»†=Cü3¾àk½Í ¼b®‚=ß½õük>¬•>DáU>3C¿bÜȽ’¨�Ø á¾§.¾!΄µÍ¾äþÌ>nµ1>-0�¾EÐy¾Ú³s½>ý¶¾ÿ‹¡>UŒj>þƒÜ¾Ó®6¾·þ³½‹8�½â[ç>O8i=v#…>i2=]>z%�¾0AŸ½ô" ½4K"¿äA>­Q¡>¢« ¿.´:<êÀ¾eÈÛ½Z=I÷¸¾U9>½6¾»Ûä>4ì=õ1o>È*¾ÆV¿˜*J¾XÝ=ÔѾ¨Œ´½±+1>»U½hR>ŸÄ¸½žÁ`¾ð0„¾ýj¾Œä@¾¾£ü=ÛqL>�4º¾ð£Å¾—¯Ò½\¯ý=S›½z‰ø=ŒLE=S�¾ã}·¾¢ŠR½¡[(<ºš>‘b=#οñs>@°�¾~cÒ¼ì3>1WÂ=[Ñ;�òè¼™Š4¾Ëöw>jÙ>’ÅA¾"о3=�;í²:>~¹Æ¾©Rµ¾ž·�> n7>ºÂ->U¯e=¾j™ïȾ駢¾qÝ%?ºëÞ¼BÈ=»Z½ga,=*¼î>ý{d>»Ø½ÿ·¾h¥�¾˜î“>ƒTV¾±>¸½ÿr‡¾Ã;Å>GÁ—>lI!¾1­>Óp¨¾ŽÚ=ã>o±¾q ü½–?>Ô<+?ó7¾Ò{œ¾³íð>þ…>†Þ¾ö_J>„¶)¾v·Ì¾…2‘>žf(>øüͽa>qâ.¾7Š(¾¿q¾á¢G?”ÚØ>|¥ª>ž,g=ª?¾ÍVû>ÆX”=n?›¾ÛŒq¾ÐϾ£É¾|1?¬ì>�݉>?¿ÀÁ*>¼É꾺Ç|¾ñLY½3/ =“ë>ÛiV¾8Á¾¹«¾!¢È¾ô˜%¼œYH=*�¬½†Õ¼‰½ž¾ªãG>ó„D>Ï7Í>xl¾âÞo¾[O>t‘ ¾æR¿B\‡>±­™¾ä箾Áp>~.�>“§Â>w»M>Iåh=XMr½ié¾=Ñn0¾Jˆ>ðZ&¾W§N>ݦÖ>:¦œ>1ò½[Ü?@“æ¾—>†–I>U1"=AJŽ>nÄé½P ‚¾@€¼œr’>xf¹>…£>aÈ>Ùë>,O?À0W¾V@s¾]ÔÝ>¹­ò¾ Z#¾²²>^øÔ=Wë«>Á =$lQ>ó>+é…¾÷7>ˆð¿‡º>–Ëk>3¦Æ={úQ>Žñ×=Z'‹¾ò*f½Àx‡>‰'G½öλ:�¾¹­K> �$>‚`;ÝAÑ>ˆã¾>p¤ö½À>©‰¼¬‡ >ľþ»CÂ"¼¾¸>MS¾Ÿnâ¼á¨º½>•½‚âá¼tœ¾ˆ“>m³¤¾Ç<ˆ½�x¾×'¾Ã£¨>›9ä=¡(•¾˜>1Cs½btV=ûIÅ>ôä=ä ‚=._'¼mé‘>M›½Í`«>úB÷=Hþ±>„ ¥½ÚÖ?¤¶|¾3ÛI½±,>hŽÝ¾¢ò¾½œðb½Rf>*e½ÍM¾Igý;G(€>Iô=ãÿ¾<Êê>×#¾ÖÙñ<4й> M>qh–½¾› n=Öz>6T‘¾r 9>Ò)ž>¸Ãþ¾ýG>t >&Å>=nñ¾=?('<1é>ßQ¾ñ\†>q—=V0ù»É¡¼½Ãæp¾mß=>Ii¿… ¾§ ¾C¬+¾'DT>©Ë¦>)šó=ˆ>‰å¾È«Ø>» ½Â�Ð>lÈ™=`“#>©¤¿ÔV�¾¨N½`hÁ7@º[>!U«½gÚ¨½„!¾¸eO¾<Ù·¾†ÛÇ>.7™=”¸2> t>¬�>`ŒÄ½&d?sÞH¾Á»>Í Ø=5Ç9¾%ͽÈÎ>ïîÙ¼ØÑ>m¼ª½‡½�üØ>¾ç¾X4h=u’;Òj¾’Ê®¾."´¾ex·=C‰<�Ù^>?þF¾»®¾5‰M=h`)=¾:ø½ã¢ä=bJ¶¾¦ÂE>Ó ¿>Od¡<Û“¾¿¿õZ!=Tf¾0„º>kAß>i§Ì>¤l.¾Aö>›xc¾C-|>8ìc¾à6¿|B>äLr¾‡¹~=¯!W>žk£¾‚rª>íÕ ¾´»H>ƒ¢=>÷îX><ç ¾ {.¾ã«¢> ËŒ¾'+=e½­þL>Í»¾Ð@û=ï…P>ÝÜ=ƒ±²½ìª÷>øwx> ]›½uê>ŸÍ«>8x!?•› >°3>Ù“Lº}5½[h˜¾Æ’™½˜M‰>Œb,¾­œ,>ÌŠt¾W§D?ôŒ*?ÀÍ–;Ó«><¤¾4#½€kå=±¸´¾^<ø½i¡¾aN>ø €<[ïÏ>‹Z_¾¢eå¼^Û¼Ä�<0ÓO¾øÄå¾Ïs²½Ã˜ˆ>}�=vk§=[ú=“žà>¼7,¾7âö½êåнôÿ]¿×,¹»ïµ¾Ծʣ >™³ç½ïÔ�¾ñÕ¿ª>˜Ž¾ê�<>L=ú½º¾!ªª¾.oO>{¨½š±?FrÔ½Êô=Õ9ë=¬ë=Ó¥=–§O¾žÌ>¤ò¨¼�D>µZ=¡eü>aO¾€£9½)eé=­ã»˜(?Èö¾Aä&>e \=cÖ=2 ‚¾ÇH#>ùÊ<"\> “ü½€^r>Hj>�Wc¾Ø2½½â>#U¿¾Ô½°v>„T ¿»Ú=…ç ¾Õd=¸ ô>ÄSE½�Ó ?Üõ’¾¤Võ>�á>S£¬¾étо>…º>Œ‹<µ|G¾¤<¹šî½E«§½Z÷Ÿ¾”ìò½S–‚¾º© ¿š†a¾i•?ä‹ú=2i;¾ÚŽ0¾}U=âÏ:¾}m¿Zî}!ñ°½|{l¾… ¿Jîz>�r”=\ï=Äw¾nJN+ ²=ò$Ê=¹V‡¾™y¾ËÕ;;Ý˧=¦Ü„»…yÊ>’×½(ÿL>Çb>õÀr=¥>læ½Ä{'¾ u?2¾\éÕ›=>7· ¾Sx¾Cˆ•½(„˜¾¼Cœ;IÕð>¦Ü¾àw¿ Ð=›œ`>¡‡>ëî½Âÿš½S÷%¾¼R¾T©½µ8=´1¿=¸¾QXø¼Ÿ“¾�~$¾6_™>/�C>ˆM;<×>¤m›>Ä$>ÕÞV½Jf�¾ ]>ÐÙ¾“•U> 2!¼¦î’½¾’¼`R¾=8S5¼cV†¾,x¾FZM¾­ûƒ;ôS¾¼ ¿û—Ó=Z_ؾ5Æ>9nI¾(*½¥�Ù¾lŒ>b¼ÑÒ„>‹�¾�—¾Ê6Ñ=@×¹>ŒDj>¡]û½³É”¾ðbƒ¾Ì³_¼¶Öf=B¨À=;)x>øƒ¾—’š>‰·Û¾¬[>SÔc½ &¾�/ü>³ß-¾ËRÁ>碄=c�•¾ã'I>IežÝ�õ=òQ)½úÈN¾+k¾äŽV¾ã8_>O Û¾¡F›=ÈQÀ>÷)ä>žTÆ=|{ƒ>Æ60½ ¹Z<àRœ»Óâ@½°³s>'@ä½!('?=ãͽ¼Ù�= W¬=Э >9>h '>äòL¾-X(>€ù>æ4©¾q”Ú½.ߟ¾XÉ®¾_½¿>®sa½ˆ!æ½F7>$ä�>zÈj¾ L'»|¢:½‚=¾´»Y>&¬¾>Ýs¸>xZõTM=K…+<Éä­>.ü’>ú•)¾Wã¼¹G\¾”›Ò=ŸñÒ½,‰?¢�¾@wV¼Hƒâ¾„ ¾¯y>V!½.�Ÿ½ªÝÎ>c/þ½¾@=ˆˆa>SŲ>“�c¾ÉŒ¾TÊâ>MŸå=Né >BËË=;Áé>Yû›¾ì<¾¶Ö­»;%N>l!?›õ¶=`K¼yeľ^ôÂ=É]å¾Ã]$¾©2Æ=¼Æ ¾¸ÿ¨>&Àe½*éÜ=[€ú½�ì@=S=Ó̽ìû'>Œ˜þ>ƒô ¿nmQ¾aÄh>!�Ä<ñ¤½ŸÌ¼½ÝѾÖÜ ¼Ñ{Ø>¤¾Ûäýœ¼+¾Wš>>�¿¾vM-<½;5¼”ž%ÒM¾E4̨\Þ=Zľ´k>Nö¾yh>…„ >¨ä¼‹Ÿ>¥½¾=Õ=Ssƒ½’ÆÒ>ÕÑ ¾‰-=ñeü;F¢Ž>[á°¾}5e¾Àý¼[ÆO>&y?>?¹Ò¾�ñ?=Å�¾#ˆÝ¼(Ò¼ø‘=ÌK-½Šè½xÈ?¬±A>4X�=)Óƒ>l„6>Ó">ís<žm¾ð4ª¾eûï¾ÒhÝ>`À­=|_O¾þïß;véÈ<äu¦=ˆÅª½a >¥Sn½©öQ>7qú¼ñÚÀ¾Ebݽ檀½ZÔ`¾{3?æëX>/¾p… ¾<̾©×�>O¬= O�¾ ¸½ŽéÁ¾]gÞ=×;+Âï>’>>G<>>A ¡½Ö¥æ>w/>Å–Ì=>¬¡¾‹/½¡åŒ½n´=ôò½“‹£½‹•¾�š¾Ö§}=ìG¾Š„½Õï-¿AÛ½2u@¾­t2>À«â½Áz½ >,3.=,µ5>u­Å¾$»;>Ò½(=V>d¹x½¡?¿]–ñ=JŽ>¿H·<Úö¿²ðg>„/ó>Y7¾èbè¼2ýÈ»)v>³Â=îÞé>ƒ¾¼‚²¾Å—-½ ýàLé=•7>=z¯]=†ƒ2½ÚÔ¾--=’Ðý½­¾u¾„ýü>;]©=ø¸>Í}}¾*ß½š�…>Á»«=}¿»RX>ówb½Ò´j¾ŽϽ7¿¾÷Ô=üZÕ>Wºž=bN>{�ß>¿Ãe>ìǽ;"¿§OÇ>7ܾÍ›>x½þ¼¬¼dð„¾ÌÏݽ„¦Š» `q>À£�¾ ä´>P ½Z—å=ÙT>‚8¾®<~wU¾Îú~>Y«E>'?>Ùß¾˜Êr½vب=òC9>Q? >èã“=pɘ>Ðâk>—:0½d>¾"…A>ç¢>�)8½ôZ=äé^=\ оÀɾVIš>õ�o¾Â)½¨˜§>^²Y¼Ò÷Î=ØQ×<¥¤¾¼�ŒB¾”>d[ˆ¥£¾¤ón¾§üª½ôó$»ú;/¾›o¦½5†¾'¯ã=žÌ8¾˜À <›úw¾�®=%–v>r®‘=ÕÞ¡>ºG¢>„¥>­p�=Ì⑾- @¾\»ð<§$Ù>ñ¨Å½i¡>…O>«Ì˜½ÁA†½¾œu¾fþl>‚ð£>[”¥¼´ºå¾håw>a4a;TPн<¢.>p6Õ¾>§t¾–üb>‹¾[½œ›^=‹h>gøO¾Âîq>TÑ>ˆ¯ù=Ÿø >9D>$Ã?|XÔ¼ö`-¾1b™¼¶XÑ=»> ¦M>ü# ¾6=f¾SK€>NÙ¿˜æ=ûò¾5\J<îuG=õÉé=|b ¿�T­½1h¢½lèG¾°Ze>éB>Ü5 >K$’¾YÚ�¾g{…¾N¬d¾õ'j>‘K=‡ß©>Ú=>üý=ns>Wt¾¥æÎ=ýo¾J¹|½,¾ãí½m&>Ðü?±ú<«b¾aゾò`Í=ËžEY8=Òh>+hy>ò!í½GG¾ä6…>~.½°e7>.\= ÙŽ@Á½ôܨ¾ûûÖ¾w“0¾+I𾎯9>é=%Ü>-¾½[Ö=l7=˜£¬¾.-[¾'ƒ0=t±>,‚=„Uؽ]JV>aA´½øW>ó¤(=ÙI®=%é>–j)?;�=à|P¾Îl<òè¾ 6z=é›*¾ÃÀ¶½Œ“_¾°Iš¼¥žÃ½>ù?½½„½*>�N»½­DÍ=��;½|[í=¨t1¼†[~>)]ˆ¾Hܼ¼Žù,?"Áç½µB¯=䀾í¾Ž>©¡>”~¾´‰$?P=º¾¸ ¾õÝò¼×ó½Ú_d¾/Àœ>ݟý"R°> WŽ>rO>IJÖ½~˜þ½ J=i>´É >RÝ9½>ľç¼Â>¥è=˜ï·½2=$…í>m¦â=.–=?b ó½“öÞ=üÌJ> ½½-‡A>CS¾ýݽÅM2¾O5>×¼V¾ãû6¾9&¸¾‹�Ƽw…i=©¯=_Ð�½@0½�Q½”;-¾'а=¸S>pò&>C޾ñ½a¾'”¨¼ï|Ð<ïû©=—�¤>C¤ÿ=mŸm½ïtò>]ú‰>M+×=»²J¾–ã½k$¾Äw <;Sñ=ðÌw¾½¶²¾”½=>ú‹²>X<¾´ V½€¨q=”[�>PçÏ>'î0={x„>­uy¾?YÁ;¸¬{¾'±¢¾‡áž>" »>Kˆ.?Xm™½úq‰>ËÝå½'Â>Òðk>`KÃ;Ð2Ë>—.&¾$^L>È·°½÷1$¾(äœ=ˆ¶@¼·Wå¾oì> o4¿¸\=ʘ>ê×#¾Up?�¾L>>! ¾±4ï»Ñø¬=1áé=í>ؼ"¾Ò�P¾A==žñH>/q´½ñŽ¡>üÆz=¢ðe=Z©‰>´ÑX> ½„‰#>Ck3>@‡f¾ ?´Óö¾Îÿ¹½è[#>ÁÚG>•ò¿=)µˆ>o'%¾ŠÂþzž=v‹Á¾ýX¾gÒϽû¨ ¾ƒI¾u¨\¾FÞ¾é A=9Þë½Áq#=*ùȾ‰¬½³€ê¾aK¤=|r�>?÷}½7™â¾ß‹¾¦»1>²t =15¼}¾÷¾Qš>?»>žÉø½ÞSa¾Ì0 ½·’¨>ü[=›•Ž>ðÃE>5/¾žB›¾ú¶¿ G‚¤D¨>›¼{½½jÊ>a¼š¾F!? e¾æ½Àã¡=»þe>º«*½Ç‹ ?iì>E{¶½Ìt†¾ /è>¼Ø‰¾°Ë¸¾zo¶=xȵ=Éáœ>õ©¾Üé{¾_н›�¾¾[§=Tÿ;Ëq ¿å->¸Ðú½ˆÅŸ=ö³—¾6ÀÌ<…Üš¾%û0½Ñv¾ž·k¾±Õ]>©ÉÆ>`y±¾æ„d¾¬,¤=^ƒ¾$Z¦>Æb> Uí¾(Ê=䈇>¼�³=¨¦•>–-Å=hÓ…>V« >nþ[½a¾¡ù%>ûã&¾b.s½=é«=>9¿1yQ?Ëщ¼ªA>ÜJ¬½1};Q¹r=Qïq¾ÐD¾øÐ=¾¡ݾ«wD<¡ù ¾¤¬>°>8¢>gbj½ýôc¾�´¦½æuž>}Lt=›T6=óF>$(‹>ð+>¶?F¾"¼s>>ô5ü=©9¾aý‘½Iv¾:Gä½^ßõ=êq¿½ít©>Z>ê½¹ ¾=g¾=€x‡¾¢@&¾±L«>¢] ¾*ûh<+tê¾8Y¾‡l¾?%7á¾ü£¾k+=p–¾°C½û… <÷óv¼ µÛ½f˜œ>]5]¾ R(¾DY„½�V�»o¾½{‚,¼G›‚½/ZA½ I~>‰�>t†D>ºSœ¾,¤Õ=�>ê>µR{¾ìH»;`ìɽImŸ¾[h>Ö²1¾^*6=+¾´jß¼E»zý¿;‰Ü=[b¾ï ½])ô>ëL¾uP¾îö?>¸KÓ¾!n½I¡#>}"¾t`b>UÅ>¨ –>¬Éš>—i½‘Ù ?îi†=­È¬½ J8;¾7¡>²Å ¿¡Ú£¾ôㇾ=À§¾>#4©½§‰ê>“‹—¾¯hʽ: †>jé¾wä¾+Ná>éK½~*/?(†¾ªx=>„{‘½Å*˜¾Jý ¾sh’½RP>Ì~ç¾}Y£¾µs§;ŠFë½ò¦¾KVÔ¼áïˆ>5’>âa=ö�½×v¾ó™¾3®Ì½('›=¶ѼÛ >Ò~]½­¿¿)¶>r…½Bj;º>œB#>zXa¾‡êg>÷d>Sx§¼ê̾<Õ ¾)Ž=ÍF×¾±|>¸B>0ßô½TŒŠ>hÌÒ>H/Ÿ>5£¾5S?òÞn¾<= ð=;£?¯`�¾|ßb= Ô<ÁOÂ<åƒ'>- ˆ=ùx¼:±O¾Ct÷¾Ïé�='&¾ˆ:£¾) h=“-›<ì“> iI=SÔ¤½Ä®>pži¾åo ¿(ÀH¾Ö¼_=óëz>À@/>7Ÿ‹>urA¾j´ï¾AˆÞ>ƒ ¾ òL=§¬?‘ù= ºë>ÀF=5rš>Äb˾~rµ½Ü ?‚@Â=^î'>ÍK—¾bÿý½ñ=?&¬?¿Þ¾c¦Ö=´¾ ¼L=v+´¼rB㽕BÙ¾‡â�¾dRÚ»X2¶>*_/¾·Ê?)RؽÊíè½F¿'?£Åé=¬5j¾Î�Î>v‚>‘_À>p‹ö¼ç&½‚w»Ôˆ>q>Ç�Ž;ëÉ”»å/ >õ8"¾š½¾¾ä=nÞ­=BÐ/= mÐ=hí~¾W¿=ïÜ>œ,…=÷?È=\3½ªô>W/ξ ü¾²G>ó¶>÷6™>G>k¾¶³i>€>n:x§O>8â½Hãõ½³®Ò>ÞÁîÑ÷�>Ò3=þ'Ô=/H£>ÇÕú=�„½Ì§ƒ>ýf¾f�>ÞG>Àtä=Äô¿¾p¨_¾‰~ >Žó‰½sƸ½Ëz×=áôè¾÷7ݾc%¦>YY¾Ëǃ¾y¾Ýó¼6«»×`=—Zæ¼k½Ê=%ââ¼ÛàÙ½†É®¾èǾ4¶ž> Pò;Ž?¤¾Ñ*¡¾˜È^=YÈŽ>÷Øú=µ y>OÂÃ=01õ½ÚŸ£=EC=UºO¾À9W>ÔòG¾®p¾’1�=hõ¼]é§>é“n>¹½™>·Ùh¾\ �>}>øO8¾Ný’²§=A´=>w`Š> 5�=-?=Àùd>Ëç>°y”=þ†Ð>m=º&%=é:ê½[¯¿¾èr6¾>Îe>_Ç´>w0 ?£½ >³ÝܽõV?d +½oЏ>«ú\> >þh–=X$(>á&Ö=‘œÝ=t'¸¾£tþ!Ô†¾k0<-u–½I�¿åq¾†¤Ñ=J¾DI:¾¬,�>Rë½`õ¾§›¾g{:¾â}𾺮¾n·3¾Í+½™…?ãH·=‚pF½«X>xî®>ʘ>Oª?ÅÆ>rrº>ÏÂY¾ ¦Â¼ÇÁ‰>¯×>=H–Ú=“—±>¨¼ >Þ²A¼«ùI½®Ö=#)%=(ý¹¾6¥o;êéå>¢@õ»¡ÁоÓ?=¾(z?ó=ò= ¬>”K ¾‰¿;%Ûû=V],>åÀ» ݸ¾KS¾œ‰¾ì ¼ZË0¾-]%=‰; ¾Ü »Wîv=+Íb>ºØw==S=ŒM¹=à¹û¾‰€¾rI?ù!"¾m�;ÂW¿Kê>{¾�½Cëä¼~P�>“V(¾p½<@ˆy=·t’¾M_)>5�?=¼îýÖ=€zç¾?>ÔA]>Üü=–*P½”þ¶=Ü¢v>µÔQ>ïÐ'=âÍ4¾$ªÜ¾™¤…>od¾BÏ6½j̹½ªº!>ܽzx¦>X€<�:>#wá½*J8>üÇ®=·‘g>TMà¾IÛ�¾6¼Â}¾,ó½Ib|>¯Uß¼?šM>�°Ž¾OÜî¼à#Ó>€L>în½ŸÀ…¾È|à>zu/¾âÞˆ½pd¾‡ñ=òz‘»â8¾¸ô6>ûO¾�“i>e+�>#¸¼ŸF¡=Ï̦>Øcü¾ÿN®>x—ž¾Z˸¾é�È>NÊø<·Rø=T<6¾Å(ª¾^¸G>¥ £¾‡ß,>º¸–¼œÆ^½“”×=È1Ã=K7s½¯Z©;|Ú‰>!�ü>ùǼàË>þÙˆ¼‡¬¼b! >KÇ ¾ýÒ·¾F('¾8?�>4›ó=eØ>�7ž>je =õW ¾£œþ½HX½Ã…‹¾« ¤>o">oVº=á>²>nˆ,½ݸ=ðÙ¡¾/&>iúÅ=`Ýb½Ôµ¡½ÁC>q™ >–EØ<]øß=IKÌ=é8=Ü9¿<˜ <Ü?®<>¯D=a²½—ƒ@>¶hV¾5„o¾q¾N´½¾^À½1:g¾"™Ô¾¾³?Æ->M>ð¤<¦I>_ç>ùN€=FÃn>‡É¾\v>6²=Ôï>¬É´=ke[¾†Ô²¾ˆÜ(>Ä<ø¾ƒœ*?KE¬»Õ¶,¾³Ìü=‚yë½^¯�½ â+¾_‹™»&Wµ>ˆ&>¾åm�>’ôƒ= Š>" Ü>ë¯÷<Îݳ9\ëI½�ç¼�ð›> �/¾9¤>²WO¾µ •½h<>s·!¾ª¿©½« ~½(G¾œX>*Ĺ>N¡ê½§°|¾ž�>ø2¾z`&¾êî;>Ù½½£{§> Ë=î&>ž<©Ôa=h÷>à4½òv¾º<®s½†@þ> ’Ù=·ÿ;hk“>ßÄ´>à Û>�–Ò¾æ#S?vùB>ŽÐ¾ÓΔ>K+#>bÌ/>’:x¾ˆî=iîJ½0@¾1žÓ½C²£½¯®v˜a½:6¿)!>º‚ï¾¼b<¨È=󳃾?v½÷5¾>{;=,9ž>§ì¡=‚¿¸>)¢£¾œå³>^ µ¾+`:>çy¾õ+.¾YÌõ¾³½d5×;ˆU¾bݾî �;XŒ2½ˆv¿¬’½Ã>,·Ù>3Üt¾Y‰>ê‰<ˆ[>aCžQ¿»¾df ¾ÁeÅ>T~v> ª}½òèÞ¾Ó]º¾[Ÿ¾V ¡¾ºÒª=Û›�<‘,©=”=)>¿²C=󯪽 +>0F>gª>HL½>jý¾Òž˜¾ŠÖ‰>e¾í½ÚçM;0…š¾G¼ö½Jоs?>µŸ•½ìÂ=Wv?ï¿ZQǽmᾋ2ý¼dT¼ ’÷=´=¿�% ¾G¶¶½ õÔ¾3`­>Ù8>TA¾„€\<àts½AU'=oÍŠ>^œ=iò=Ò\ˆ½¸¶+¾”¿r¢s>“޶½ Òú¾O&•>kñž¼>^x¼æÞ¾ý?÷>Û4q¾ÂŽ>lm.>ò[Â>‰J>¶˜ˆ=ê´„>Õ¯>×¶¾Óû¸¾éZ3¾�½¾Q-Ç»ð+¿[/ž>Ÿæz=EʽZAÉ=Qûç½ÜºÑ½-¦?YI^=s6¶½·;Ç>œÑo=óT™;ľyÒ?玠>šå½k›¬>Œîq¾‘p†<5û¾'k�½ áV¾[]¿=ŒŒÿ>D÷ü=ÁjÈ=w‰›\*½>ÕξW>ñ �½ÉL>z뉾�Ôn>Íu¾ñÑ>b¨Õ¼ã;‡¾�W’>¯dѾӧh>·¡½ û¼Ãd >­à{>Ï©D¾ŠC¾3L½†=9=ÇKH½4wñ=L¢U>/<$¾r-¾“Çš¾0;¥U)¾ b>°Ó8½â;£¾L�ì<óAà½Ú�¾Æy2¾�¥V= ú>¡°^¾ÓžE¾ÅÜx=·ä ¾îjê¾Løñ<è®®>aZù½Ï3½Îgc;b5š>Jßs¾ÈÓr¾ž‹¾1«=¾Ù梼W�<>ºoõ¾¸Áz¼§�†¾úÔw¼øàW>»ü7>-¿ >â”l=åD†¾�‡ù½ñ@«¾Fb½<:¾�.ô½Ð¿ÌÃR>Ʀ>7A=ad1?J˜g¾�A¾õ«þ>˜ =JöÓ>•&º½Âÿ¯½Pr5=9®…=R|9¾Q¯>)6¹=rÖ =VÊ݈>l¦É>Сt¾à­Ð»mÀ¿æZ? 1Î>î›>´µø<¥¡7½ƒ?$>ô÷I>oáF½ïm˽©½éà½îÙ×»8Åä>aÄ>ú¦='ü�½�Õ,¾Nì/>ê+½Q*¾!V><¬{=&H�>ðÔ=BÔ>�ùF>Ÿ8½7ÞG>r'>–9¾ÞÜ�>+Ô¾ˆy>Ú×#¼§@¾=ë=k ƒ¾Âϸ>ÜlS¾0Ǫ¾‚Áö½ ᕾï^¾ƒHû=",m½cSþ½ÉØâ<†>¯=a1œ>ô쾞“æ=öÚ¦¼ýž¨>'1ؾ9:=r•x> „?úA½ºV×>!¿J´ž>n1»={Vô¾ÇF뽘Å)¾DíO>“ò$½9Ìœ>DV²½`ž=\Ðf=ª®ñ=;€>I™F>üŸV¾Q»Â>Ž}>§€¾¾Nû¼ª[½Ã/,>ÉB?òD÷¾;Ò ¾£©÷½¼ ç½5ˆ;ŽÊ¾£¤>¿z>¬A¾½QV¨>UbÙ¾¿Ö>_V=ºˆ¾#Öˆ¾úο5ª¾Èíë¾oX ¾Èqä½vt¢8b£>¦¡½×Ñ#?ß|z½º‰½GƬ>}þ >]µý½ O>þŽF>Å„W¾¸™Â=�D¾ziL¾/ªT<>¾�V½áÞ§=´Ì³¾�Y ?[W1½Úí̽î”^>Õ>>b÷­¾ñ?»:~¾ d©>WNÐ>+ =qG§=èÖ?ú¹ã»[Šú>jû1>-#Â;ÝT‰¼ð¨<½ü·Ç»U9B>”N¥=‡‡ô¾É¿©u›>|´¯¾]�,> \≯¾—�¾�L³=dh½"iÑ=Ø.–¾òP�:ô¹>ˆG£½�W\=‹•[¾?�ô=»þ‘¾þ† <ö¯“>»ªV>ýB¾�y9;î)Ó¾c>Ô)+¾kŸ†¾î Ó>Û½T='m�<°«1>eø¾^2= ¥½*7Ú=Èm"¾—+">#�>Á©7>ȳÿ;ð¬ƒ<ÛDš=@ÐT¾ßD;hy¥½DAà>�‰>s±ê=¶¿=o¾Ä<¤…d;_¬ð>ÝŠ>V…¾¢=ãáÙ¼–±v?Cú=ñXþ½Ë5Y¾Œ†Ý=Ø!¥¾k±½ÿyF>µ–l¾ÄŠŒ=›z¾BÚ>šÍ>d7o>‡]a¾¢¥w=@°#¾�ëG¾t¹=H,R¾m;*¾Má>;p¿½‘k?ƒŠÍ>¼§›¾¿bˆ>OV¼\=Ørr=ì*a=Ù$ï>L/¾§.ø>Xô®>l>4¶=65¼¼¬«>­‘Ï>¤Æ�=ËX¾Ò}A¿ðÀ:\×>÷x¾fŽ>WŠ˜=ž}d>a‘¾ˆ�Ú=Ñ /?®œî½ÇÙ:>­Kª»_o޾K ¾Ëò=¾ŸÿJ>q9c½Î½“/×<<24¾¬F½¿ľ`yˆ=ÒᎾ0"�¼ðFÓ¾‚B>®ÞÒ=GÓ­<‹c½K˜ì¾¬¨T¾z‰M½Sˆ�¾«äO½UøN>þ6½ýé=Üü¦¾F„Ò>³8d¾wd@¾†rˆ¾aÌ=U‰¾«;¾=7÷¡=b ”=.1=`¨Š=)9>¾R‡>û8¾ŠŠ¾æ‚ù¾ß”¾ê£‚¾*kŸ½|Ý<>‘[? © >Ô[½ïPï¾ôô�¾` ÿ¾ç >L‘>x@”¾Ü¼ê¾\‘¾ß•>NˆÈ½Žê¾¬½ƒ=Gš‡¾Ð€N¾Þ¿Q+`>üê>¾ïˆ+>o€<>$ÁY¾æ¸Ù½„f«=þÊ>ˆÎ´¾ê@D>´L¾¦™¾A†½Mò�>ñBx=‰Ã­<—B†>ˆ¥²¼ˆô>›cÙ¼×ãa>S.¼=Ñ»ç>Ó!G¾œ)Ê=ŒÄÍ=F»>₾÷Ä$>׿¾�Ф¼^£u¾éÔ*¾V–¾§}¾�@=Öï,?�e=¦§Ã>Í8�¾Y׆¾½`ûÒ>ìÆí>0½>â&=¾vB{½Ge=ò@·¾bªb¾®½õÏß¾ãNê¾Y0;¾Þôß=�\_>K¨>±È¾ÛP´½K旾Ǽ)>TFà»fëP=Iy>¨«£=ÊDM¾\ë§¾S ->÷óq>Èçt>\1 <ãG ¾÷«;>yG©º”e,¿<û\>^_²¾wÀÂ;Pç½gys½" ¾b`]½³ÙM=Qpf>*ù|¾Ö®>ãʲ>’fB¾Iˆ¾Á�=Q–ϾÑÙ%>ø¨Õ¼’ݾVv¯¾ gV¼åFp¾Ç�Œ¾xR‚>Œ¬œ½Ž5¾ Ù/> ¾¼‹¶t=z;™¾HÙ?¾wßÅ=èd°¾OŹ=Á¸Ž>┾ 7›>¼ã¿ v¾LÉg»;ÊŠ¾?E8!¿Àÿ$¾6ß�>»�>Ö5Ü>²©½>= >Òk¾xaÁ¾Øèá<äBb¾Ëê¿jY>Y¿¾ä6¾g2¾Wž¢;Ch¾U¯õ½Ñ&>·¼$;Ïx{?–l>®/³¾G9$?}t¿½° о�>´ªU¾!í½:ž=P+g>C¹>M{H>˜K¾J‰Þ½&Ξ½l*§¾Ljõ>[¢k¾y…¾@ ?ÌÑ7>�~½¾ÉÝ=¤Þ(½ú&¾Y_n>f›_¼á™‰;`X•>]‚=ðxQ¼mÌ¥>>wµ½Ç-ɽ)?‹K—=üÓ9>õJf¾¼9—¾Ùmç=..Ô>×›>êªC>¾F¿Xn¿ª‡~>g¤V¾¢�½þ«,?La ¾cXï= ôͼÚU~>Ô�->>ŸOò=#Ÿ¸>ÛÙ>¿p3>ƒoݾ®‚>Ä=Q>ò2Æ>cY™>>Aº>ÛÉ!¿} •½.jà¾0Ÿ[=ÝuÇ»-I>¬%½”€Î¾Xì佉v ¿öñ=ˈ>.Ô<2•}½;aÊ>%Îz½xZ¾–z¿‹i˜½i_˜>|Y|»©½>c�Û¾ꀾ[>è´Q>ö¾Ñ¦ó<%/\¾0 ‰>4³ >¾·¾è'Ë<ÕáѾõ¾e¾‘(>Á°Â¾Vaż W¾t7è¼Y½××Ä>Qá[¾,´®<è0>òZc=ñ2¾^ž‹½3*:²J`>¾†>‚æ>šM‡>t7¾Y–é½3­¨½$Ÿ¸¾m ¾<ÖÊ>ˆm;> ³Ô½�´#½f5ò½ŠÔ½ÀÚ½[Žz`¿ÞPý> È2=G{†½€'¾²Â=–¹½Ò®n¾ÔÒo>S•="£a> Õ`> P,>H'>t>SxE¾UIÀ½}µC¾-6µ>:]¯½™ž™½u“Š>ÚŠK¾“žÉ>�îB<®’?D�…>..>­ú>�vr>= T>xNã¾�?—½þჾÕÝz¾0sE>(¾Lm…<ÿ˜J>?ˆü½?Í&½fz�>+쀾ó�ž=îNï¾nƽ•úê½Ck€>_J÷¾¨t½ú?UΔ>W�½ÎGè>%\·½(õܽüÀ#½Žs>½è½0ðè½™ú#>C•>[8…>Ë7�>_›¾‡Ï>2ξu…Œ¾�޾Øè=3lG¾­нT_Z¾‚䯼o¤ ¾Œ#|¾kêq>Hüò>2“¾ÿMt>·ô±½g >^"¾aN¢»o|5¾.q­¾Â’M>°ob>`ˆ;GA¨=m±Ó<.Å¿®ÀU>‰“㽪&Î>˺…>¶;›¾Ò{¾°ùz¾ˆj÷¾ðd‚=…Ò™=^PмZ¢¾¯ëN>ñæ=ùS6=ÅKÁ½ÄÇA½Öš-¾lD»Vm¾à4>?Ÿd¾7Ã=Øc#>�iâ>2KH¾Z—Ç=4Ë ¾ÑSý©}[½7Æ>¸ôÕ=䀺æUå>Û¤<¸l=�Zp>=é/¼E=ç>=¸�>X22¾=¿¤$¥>9ò«=VE>2C¾{’¾|\æ=ß(>¥ï½VM[>ÙÄŸ½TÒ >cÔ >ð†>dö >ýÆ>û»™¾1W¾?N®>ôä¾½cî#=òO?ëd“=È8d>?il>Á!„¼$¹ƒ¾·&Ã=úÃ>öýž¾8Ò >ÿ.ã½Ë >Á¡‰<’Àö=µ?Ãèb>¬Ò’½«üí=TÛ‹¾·(ù=Û Ÿ½j€¼®p ?:¾.íq¾.‘½lj>øùÒ½}Ý ¾ ‚4¾ÑÚà>Ò*b>,fL>áÄ|>¦D>ˆ<>¾�Þ¾$Ç<>œÑ?¶qξúz�¾j¾èzO¾cbR>@�œ>^W@¾ƒ±M¾‹=¿"=©¡ ¾ÇÚè½@Áнl„>ÔT:>vG:¿‡ˆ¾- Í>óÆ =)óæ½³Ëa>Úr�>zн=ÅR_½O__> ë¾€¶å¼õ¤½T~¯¾@ þ=ߣ²¾p”2?Ó½8�‰>}ÝV¾vÄ>¬Õ=æO^>Dú> –޾Bý¼Y·Œ¾¶äí½zË=S)·½M]‡=Óµ¶>$&k>ÜÈk=ññ*<õ1³=Æ/n>�¾2Å>—o&¾¢vL=+?á>´½Af½;¨¼x.=ºY¾gæK>A·�½H]»'#˜¼Z ä½KtÏ> á >½…O>ne†½XL‚>ÉÍ=–Õ­¾Þ'�>C°É=ŠÙN¾ÊB�¾û!¨¾Žz۽ǛÅ;²Ë¾ŸÈ´=–vϽE&> O$>Q´a>Ûþí<<7’>ŽP>_F¾Ôkݼf†@>6¿%ñ­½íŠ˜=h:Ð=JqÁ=ý„�>éô>,5‹<¢‡<û0¡¾*\¤< !±¾L/ï¾3(©>IF8>A­Ñ>™ ˆ=J>=x­…¼‘¾ª=ÛˆQ>.ˆ=ñŸ¾q¤¾W¹¨¾>“¾òFˆ¾’k)½bz@=ÏY¾»‡«>†=$>è7K>W&> Ò¼"ü¾Ù ϾCÑ1<ñ¹¼&Œ> ~>ìQ>ÒI >Ç#>£T½ôÖk>A.?Ô龇 œ¾ðõú=î䙾¼ ¾ Ìt¾9+ >–Í©=/�£¾JÖ”¾w¤‹=ŽùŸ¾ë™‚>k7D$ ½¡‡¾Šô¼> 2>ì�€¾üv޾£y¦¾Ùbq½½ Ÿ¾�侑�F>|ú½ba>°þ½Ÿ1¾†v�>5P7¾‰‰®½À¾,à=©Ê¾Šg‹>efE=ï ¼¾@NܽQF<<+î[>WjC½H�•¾_„à>O¦d>ø,—¾r{¾Œˆ=ÏìÎ¾ÇØ½Ã#ÿ=+¬¾0e<= wß¾î!a>PÎF½r·(¾š^ɽÐBu¼‘rÈ>_ïŒ>Ù`ë>-Ú½¨ >±ŽÅ>‚À=­±¸¾­ŒG=Ÿ^™>\ÿ¿•=bß«=¾â •¾m %>AGÖ¾jé`<¨­8>ˆcB>†Ñ*¾èg=œ^õ=$ì÷½q‡>Óʤ>|Zˆ¾l½‘¾É ϾšÓ¼n¹.>Xñ¦¾Öî*>/9>†û>ß2=¾,–™=µÈ‹½dªÝ<59¿ðòÉ<|Dø¾2†4>Íæ#?¦®=s÷Y>@X¾œþ›>ÂÑ ?æ9Ó¾‘œ¾£•­¾E<>f—+½ÉVÈ;Á^¾\Úš>ËéN¾vr¾¯ìå½ß›2>©a¾í½V>Á07?�éµ¾Â&>Hˆ„>M&ܾýs¼ø«�½ ú½èùë¾eßoêd?ç9м è˜=U+k>vA¾¨u�¾8¦¶>G]ü>…�> Òà½z‚=�×$¾Xµ½Áà ?¿Åù¾-pÎ;y½‚>]�Ÿ >étÐ>þ�÷º¬£¤>Yý]¾Ä<Ö=‹×¾­³>ˆ=€½äî>È©€»³3†Ÿ¹8>Ó‘Á>èJ ½˜Ë¶=Y·]¾f >µH…>Z˜ ¾*C¾@ü�>,Þ²¾¹;½Ir8>€_þÖ쨺‹(Z>s­f>–c¾p?€>/Õ²=¤q«>°­2¿.`¿;dPˆ>¹ÄJ¾Ï\ÊN|A¾í>÷bYºæë¿0Is>,ã<{uå=½åx>‹É¾S½÷½½¿c>ϯ¿‚l¾81N¾ìx>Õe‡¾�Ê5¾$v\>“R=LÇj=R3i>pü¬¾]$½ÊT>Áõ‹½‘y>>Ä«>•yÁ>°&¾‡|X½èI½o(+¾=�k>°i§>'F—>®>‡<}¾Yc¾'�Ä»I}@¾ØÛ>ƒ�&<>p¯>�ë¤=l‚¶=ë–Õ>†m½kÇ>xi¯>7)×¾¯ž >Æ´"¾ˆï=mB†>$$2?�›Ò<]k/¾’ø½P ¹>{Ѱ>¥:ؾIÌv½™:³¾'¼ #˜½¤Ò.¾Þ¹Ì½Š!Ð>Wi|=�³¼jK¤>“„í>�9 >{ñl>æìB¾BZÉ=gmm¾I(7>ù›;È @>9& ¼£lØ>§ð]½ñ(D¾‘q¾U�޾ŽM�>Ÿ=?hO¾ÁÒ(?cV¹=¦9x>­8>ï ‰>áäL>Îp:=âø¾éì)¼ª¦>Âv\¾€A >€ÛÚ>NïÊ>¾£•:«H=Ì>òª<ä¡J½¿ß¾€ðª>‚Î=ÛýG>�ú+>$‘î½Úœ¾Q�•>3Ë:ü1Ì=Õ2ó=™1.=d]켸1±>ÿQ>ñ=ó¶>ò멽^)½%‚¥½þµN¿@�B>R @=<Ç@=Óÿ¼Ê¾,¿�<™=!¾Ö¾Å�>†&·=X&}¾õH>,©Š>3:¿ð6Ø>ºC=ÔÙ>š9p>MœŸ=IÍ¿*¿B¾ š>h?Û½B?ß±½¤9¾@Ó‚>b>ƒ=4dJ¾QX>m;>¾x»·¼ >Å=Zßá¾ò·¼y�¾~¶ç¾t¼>$¤>�)Ó=,kÙ=Mu>ѯa>XР=)f:>’~`¾VÉ>Ã+)?Ät\¾->ªÃ¿›´ƒ>“Øó>ª= >7� ¾Çz!=m’\=&?H˜…=üuоßG­>>Í>�\0>¢¼ [Ö=Œa„œ=S¾�Ã?> #ø¾ a>}Êë½ «8¾B>¾iŽ>R]¾Ë<¥¾è5 ¾«÷™½Ùö¾Ü³W>J4¾Ês>Ä7t¼v¦u>$Æx½©8(>·T;>€Á%¾3Šú>ž~9>·à°>"ðX>Òµ=¸^¢½2�»Òœ ¾|ñŸ=Q©�½Ô‰‚½œXÜ=¼¦¶½]�V=?>Fµ=Jz¾ (?‰P©=´µ¾ß¡>¥Eƒ¾+šR¼¨7¤¾õß�Z¨½Jä]=Z¾‰µM¾´*>�9?A£µ¾g�¾>‹n0¾“^z½%°ú<ý—»½QqJ¾�“Z¾Q½ Û ¾em"?v]Ѿ¹Bï¾Öκ]Ì|> ?]>Ònd>“•Ã>>¶¾aÚ>�ÿ|½/… ¾äœ¾ëoý½ ®ç¾_纽¦ƒŒ¾¦€Ð=€€>óD¾Ü±?Yr>Ph>ôšz=K”¾Æ””>3=?½×ëɾ7"ù¾=ñ¾¦j>}‘=á⨽˪¾M�Á±†>+Ü!¾´v»½ŸC­»gÐI>�Èè="n�>øÆ�¾$?*0ø>Þ#1¼65‡»=N:½GÚ©¾çV½Þãé½q%Ù>´ZƼnëþ=†ÉØ>÷Zå=Çh…=þl¬=ìé¾!¼š>ÁXý=`.¼%“­>‘j=¯Ùš¾¨i½´¨š=µß�¾©Y™½%e­¾Òè¾� ៑>A@æ¾âÁÐ=² À=á ¾Ë½¼·Å=Ïó0¾öäK<™>JT6¾á;3ïñ>ÅM>…¢S>.fƽe*D¾åg <Íð>½Ž·½þo¾¿`¾¶�=6«¿[y7½5¾Úš»€.;¾+w›¾.&.>›?„µƒ¾4Ý>c˜>Ü,�=” Ì>Ø€¿=2q¾Äß«¼4x>äø¾%¥=¿�$=ìÏ®¾æÖ ¾áu©=-Bé=d�÷¾^9 ?ùª½ùsu¾Ëj>a_>E÷Ë=f图å»2>bƒØ¼éÂT¾ ,�¼Gx2¾-p¸¾ØL=7m°=ös²½‘'>Oê¾û·¾�A¾ð5„¾úcð½Sk>Ñ�^>Ö8®¾£Y°>Èà=ª ;ɵœ>‡_ª>ö·ö=4¶>{Áˆ¼D^æ>äC@>Í©O>F_š¾�ð׽܎Q⻾ì«>ãz ?ÉýF½ ð2½ˆ˜&>Ù¸/¾�ƒÄ¼¼eï=F4‰½Hqœ¾§Zâ¼\lÇ>ø¸=•¤¾Cò½ü\>yнØIÉ=W&µ>Wß¾ÂH¿z(Þ»…ê&¾¨VN>*Œs>Ö=ï½% >œŸ˜¾¥œa¾0€L½ûq>¥tÔ<ò==>|�1>#$ݾˆ«�¾M ¾¹ ÷=ïBÏ>¿]Õ½ÈÌS½d! ¾Wx?ZS¾>…*¾¥GZ¾dû­½Ïl)¾Üe·=~ð'?wÑã>»¿«½ÿù‹½@ß¿âŒë=:ŠÔcÒX>…!¿µ=Ñ'¾®¥Ô½dZË‚A>l ³> åw½ù„·>%¾:¢=>›|u¾f­‹¾X±¾>7[2¾r‹Ÿ¼¢¯2½>þÌ>H¨’>No>$²i¾Á^™¾™Üþ ± >fÍÎ<ŸÚœ>¶ r>lõ>¨D™¾ßL¾æ#¾d¾¿œ`¼ XY½‹޾ÛžW±¾ð…¾‚Éâ½X¿ë½¤ºQ>¯>'>P·ñ¾>F¾IŒ=‡ã'>Ûò7Ꮎ*g¤½<>°f¡¾Ð×k=bY¾X>b=w¼c»l‰�¾Vó<Ý›ì½v€¼ó¤(?X8¾=W¢2>ƒê–¾«r¾=Ãqì½0C¡¾î¾>ò¿mƒÉ=_í®>?¥¶>ž¨ê½ã}c¾ò …¾%”‹>°åæ<öþÖ½²¿¶;�>|t÷=¨[õ=N¢ú¾Ïžº;VÖ7¾Æ½Åf—¾ÌMë<_E ½¿¬×½•AX;�v½ÌoÝ=†e¾ÖK@½²¥h=½¾Ö{—¾‰x¸>{j½Ý×>SD?÷¨ß=� >t þ½?ÑL=¢�> f>)�¾ÌX~>,vZ>æ±½=‚…

&”=È„\>bõ=òä�>8ܾÓÕƒ¾b(‚¾·ð弽˟¾­|É=ˆ´=L7½ÑmÁ½ïl>Ü*Ù>�ït¾Ô5 ¾õ¤=þs>¥ü�¾d;¿[„'>™í ¿ …>‰)ú=e‡>;;>6ð =¬ >Z ´¼ý=ÔdÃ=5p¿ �=Ød¬¾€-g¾U<Ø!ã¼a×.=GqY¼&µ¼¾p”r>L˹¾¤^O>èðf¾hÕi¾ÇSÂ=ÞÑÀ>Ù¾<õ¾½ã½Ý^¾£ >È©š¾%p'¼ZܼTß’=UÓ€¾è)½ù~Æ>Ú]”=&£|>Ý̾As=ád9=¨ú3¾„“A>oz¬¾�‹�>T¹)?ÎÐó½1õ#½äÚ#¾�”L¾wܯ½¥Õ¾•+~>�ÝÏ> æÈ>¼�½¤¦½© ¬>ÿ¾c¼Kê>¤ãÓ>Rùl¾ŒG(¾˜­g¾¼#l¾Hô¾af¬¼« ¾a÷Ð> â3>¨d¾¾ü€è;/€¾HæÅ¾¿”:>{ >�ð¾h‡½ôTC>Á̧½a4¼¾§‡&¾½ �<õÌɾk{ö½ÏŸw¾ÄÉ¡½™K>ët)=p®í¼˜?Îή>o�B=œó³=B">¿æ=ªÚ½ô �¾ç¾/”]¾…É(>ñIC¾R…c¾�J[>Þš¾uÜk>e¾=¥·=�Œ²¾££½ïø¡<À¢ç>-س¾‰ä�¾•c'½—Â?¶Þ¼¾ ²>MÒŒ<ß.½è s>ØQ÷><1>3…Ä»Š(µ>ª­>¸µ¾A{ ¾�™½N� ½ð¬©D’�¼�B®=¡þ¿¾ã>š¾;ô»‘Bm>šóú¼ÃÐ,¾ÇRF>\¾\𣽧¿)j¾ßk~¾]¾/;Ú=M?Ç>Ÿ¶¾' ?ôì‚=Ã5ľ'ˆ.>p>Ü—º¾ZÏd¾Þaº>ƒ%>{Ïa>7YÌ=S.Ò¼ªJ{½†tÇ=÷8>ÓÚ�¾�&¾SÆ ¾Ðº�>_Rì½³™>ñ)ÿ½ ½¾1b§¾WU꽯d�½.„i=•½Ä½§BT¾¿Ëj<ÍM><¢¾½zøV=~­»æ¿½5·»=¼¿î:’>5.¾7�d>;Y¾}‡›¾‚G½”—½Ä$E¾ìcM>NÇ=s˲>�°„= Û=•̳>ò¾ ½³è™>£æ~½Sìˆ>iyl¾,꛽—†¼suï¾ý}>™2Á>;¿é=|ö!?Ï´®>�¤>A;½øZ==CäÂ>»±ƒ¾8Ú^¾–P>µ/¤¼‰2Ñ>ã—¼=Œ>€°$>TŠË½KÌÄ=kbÚ>W�>0ž‚¾+•ñ=jÞD¾pbN>çÄÒ=µC½vÿ¤½ˆ«>BÉ­¾jý= ‰Á¾ ,̽G´>QMD¾Ê|½)ö‹=� н۳ >Zm(½&Æl¾pw>÷üY½ØQ§¾W! =Ç4õ½2-š>š>[sܽ§÷W>…�i=Þîa>¶ÎĽ¾Vä=çzy=0w½p$޾å?G>û[ò½y%}<ñŸB=Ô@°=!Yy¾4ÙȾaê>Vëó¼HmU½‹L:¾›ß3¾à\Ä=’¼«q^¾B†B>Cê¾ÿ >"T=52>‰î½ŒÅʼ¯]§>¤6—½‰z >½‰¾Ôè>Õg=žÓ¾Ÿ<@<\¥K¾ýÍ&>6ô½Ð0»½æüµ¼R#©>e½¾í¥{¾ºÙ�>g¹¾U9²¾Æï×½hˆÂ¾ºÔ¾€m?féÒ½µ„½dó>óç-¾9¾DµŽ½M"»>Þd¾ÉÛ€½ ξ�Vª=DÖ�¾àiÑ=mtþ—Þ¢¾Ún”>ËKº¾¶C&><š\¼­#½Ü+‰½b$¾ÔI#½5�U½w�¾;Пa¾Æ¾X±¾ý:¾H„> ͘=¯¥»= TC=gž½Õ6>ðå¿=G7[¾dˆ$¾ÿlÊ=³d5¾îV?>¯ä<8Ü™=0Cg>‹°¸>¿Ü(=�Ôï>n¿[=o¿Øã�=²Í‡>ÒÞ`¾XÈ£>¥ª>LÊW½ûßH<푞½@(>_ÃA¾Äóg¼,÷†½S°Ö>o­¤>óØB>1¶Ä=`™~>cÑø¾X¿ëk<¾Àj ½¨è¡½ÑqÓ½Uúd½¯9ë¾R%¾K8�¾ó¿ñ=øT½ �Z=yÞ9¾dIý½H.Ø<Š>³õl>½åƒ>>L´>3�>=X¾à-€¾l,>&Ž¿rã�=€mö½qî¿tÕU¾ïÖ0¾ùøí¼¶X?>ž*X¾þ n>$mŸ>È1¾¾vM>»w>1u]<Ï ?JÏõ¾T|‡¼Ýà!=+{Ñ>…ã•=l 8>6 ®½[:¾_“í½“Y=½š¦¥¾í€¾5ú ?nE¾ ž:½h~…¾¥Ú_¼ƒ†¿>.ªð½L¶½šK€¾&sý½P૾ɳ±>ô½Ã =’(#>l¾£„U>Vî¾®òœ<‹�²>àá_=•Ûå=*…>{Õ¼F5>ÍŠ=c“‹=¦ð ?÷YÆ»tÐ#¾!ðÁ¾–‡]>ÔÔ’¾×æª;h¦>5%>cƒ¦>X“Æ<À>O�%?DŽQ>j›‹=×!»‘W?úx¾=¬¡>³<=!{â¾(d[>?9®<ܾQLƒ¾ÚmÃ=eN©=ji™¾U6{¾k÷Ñ=º¶„¾Ãâ´¾'Öý=Ÿ"_¾H¬�>•…¬>)ç=ªf*¾·Q’¾”,a=¶Žu>™ÆÅ½Î˜¿§ÿ²¾:¹#½Kñ¾ÀÎÖ=æ9+½^Õ¨>�>l?[=ìŠÝ½÷Á¥<Ô¼‚¾«,T>FL´=Ý¡Å>¤F>Ño†¾�µÀ½¼Ï>Aœ7¾{˜¾–œÖ<¤é¨;á�¾ô߯¾~f�¾C)$½ÒRÓ½‚V>¹ 9>/ê™=”ið=—úê>Ý”_¾y¡¾³°>)«ß>vt>Tçw= V¨>„޽±4ç>; ½½4¿BJH¾By¾­K ?Ïz¾\1V¿É0W>ŠZ«¾©X~>�¾kI»<À �¾‡L•½˜a�¾ü¹û½œë"¾z—b¾RO�=˜>µŸ¾¡ò[¿í:„½ ¾…>ª%뺖>Ö§&>½~=Ljä¾é즾l¬�¾)“=\5>™«d¾pwî½!¶t½¡M>ý>/æ˜>ž8U½¥Âç=hȽ?se¾'ê�>íV<#Æ=;ô?=ƒX=ØS=n&??#½w7¾Í:¢>@1¾úUŽ>ͽFfȽ”�ľh&È>áý”½¤¯"½ÿf¾Ñ>>^FÀ=±Íè=%»¸=Røy¾ëñ†¾ \¾dãˆ>•ì)?5X¾´ ¼ñ¢L¾>È•½ï庠6>½äs¾²¸§¾~y�>}×¾«¾hgнº/彧³¾Lù¬=Od=¹a¾�½5>ÒÏZõú—½�·;=·þò¾ÁNó¾@ÛÖ½k¯>z–«>û¾p§½©ÊŠ=꓾y&ˆ=c(ñ¾7Û!=·Å…¾šÄ(¾ô%> ~î½óÜm>ƒ!*>.kk¾DB=^Oc¾8�½±1;ÚåÞ½ B€½ÚÒš>4dʾö�>Y¼Œ½GÆN>æÖ=ž¬\=®4½Ä¦Ø½n½•¾æh>þäE½0O<ƒK*> —¾¬‹>õc¸>q¶>R!8½¿De>Ú Ç=Óab=­ÿ#¾ãó=”è¾™Õ:=FrL¾¥>…V¢>ª/>[ú?ÑêD½Ð¸–=Âm½tO<½W>¥‚ß¾ŒÞ¾Ò”>sÖ‹½d‘:¾�w??÷æ½`÷=á?A>¡¤‡>pè•=B¾��ò¾’ö¾\Ýý½Ø%½ãÊê>í•{=oß½ Ðd½%sE¾íèà½�ú޽¢ \¾äCe½,Œw>:¸¾µÌé=c²T¾fÚ>«F¾{ƒ>µ”=—çÉ>�Á>£ÚL½ ¦D<]'¾Ù\®>Žý :Û_½&ô>ޏ >Å¿g„¾Ü3/¾‰×¾4¶C>´l„=©ØÕ½ Ô\¾hv×>þ§ê½îö¾:`h¼41>rÞ7>!i7½†z_>ä ª>^¨Œ>Ä�? |œ½ð¿=±B-½ô™Y=Þm ¾|šL¾ôìX=À|̽ÇÖ{=m9†¾ZÁO?#î>ï–ó=µ*a>HHœ¾Ø]è¾»�<•ç >VÒž=®Ù¾ÞBƒ¾db >‹b=©k?H­½­,Û¾þÙ½}™=¾Òë½4¾ =MY¨>®¶Å=ÃI¡¾ˆ„=Ù£=Ç­°½/ÛÐ>ŒâÚ½DÕU¾8òľmàû¼ò­û¼8(T¼(§½îj>¿¾r"ø=Ïæ¾…Ú²½�6½ò>ÆQ>LA½„Ä2½øù™=‚ûν�jZ>¡µ)¾)Ç5¾ÀCɼD"¾Å ‡¾2–/½#�(»ÛÞù½ ‘™>Çí¾ÄiE¾A| ><ÿÚ¾D³ ¾Ç >™s>Í&.¾ò¥˜>â£>§ô9½x+¾ã=Z°—½q°ä½��¿¿ÆØ­¾6æ>½ÀL½*ê#>¨b�½�Ü…¾r9‚>n@ü=’J`< •…=O–²=Ü=ɦ¾‘='k²½Šî>eJ<;¾9¾(<¿m†Í>Þ¸”¾©VW¾‹vf>Ç ä¾¹, ¿àLÝ=�š½ :>l�;¤5޾g;d>Kí¼g¥î½¹¶>¤£œ¾(оSþ>Çk¾îYÂ>8ß|¾píƒ={qã=ñþ:½Ú„½+CS¾†È^¾•®=CûÏ>‘Q¥>\ÿâС¾$2 ¾]WÚ>j�P=úéX=ó¨�>Ø[�= *ä<à>Xð[¾ °4>G‘½ÍëÐ<Þ \>ÙJ„>S(>¯ñ—½¶ö>”ìm¾-ŒÌ½bÒÃ=92z½†Òš¼;b,=—�K¾Gžª=ì!>Ë5Ö½*¼É=¡ªØ¾[â=_th½Ä•¾ ²={#H½Uû½æµ@¾À>=]Nã=ÎÍ÷½“¯ø¾?lt>èj¡¼S”Í>SÔ¾K4->ý‰=wå=…âì>u'E<.Jè=¸¾_iµ¾‡G¨½b5!¿hÖ¾œÑ>ÌŒ¢¾uå�>_ ¼´\©½I$N>D¸Ã¾­7 =Þ‚:½h(c=¬=C½[“B¾mž•½s˜®¼#??3v«¼K_À½n>R‹°¼y̾)‚¡½›}ï½"’">)“>w"z¾K×"¾ò x¾ ,>ûͧ>+ž>qúó½D½#8 =è‰<>Ž ">™ß¶>Ó�˜¾M³e>Vß]½æäË>¬ƒ>æÉT=²:ͽê6=F~>X³a½ôÜ{½ "Z>ÄÂŽ>`„>-½<0\W>îá=BYª>zyk¾ ©8>j> ^â<Ìà>ºÝ ½9oýˆR ¾°¨ß>n©@=}˾¦¢¼>äÞ=‰Zñ½¦Ø¿]HŒ½Äȶ>—¦¼¼å8`¾_¦=¤¬¾¼8 ¿À‡‹>écä½Ä„…¼•‰>½}¬¾!q°;4í¾2#Õ=Ī%>�<®Ö°=¿á¾,E„>Œ‡ß½œC;¾Šd1?J&¿s$½óYǽ9îõ;ærï=ƒœ™>–¬B>rÆž>´ØU=£7D>�Ǿ û½D.?郡>¢TD¾Ø¨G½ð?6¾MXB=4x›=`Ô÷¼÷¸!>Îl>ö§½ŒÕ°½V¶h>�‰Â¾sX>5"›½¢Sν–Õ¯¾]î,>³0!½,¢¾Ê>Ĺ>Ï©$>w }½ü°€½Q">z¢=þ8]>—[½¾œ ¾Í½OSå¼ÊéO>ÛÃ.=¾;£½b²>«Á®¾òf‹>8_‡=¸I>‰2/¾r>¾Ÿ”½äU©½ü´¾†g�½ö:>ÿÑ>ûL¾¤^ ?õöC¾½fõ¾ÀÀ’½�Sê>³´*¾ò=ÄY=n­5¾•ß\¾�©Ï>®>ñ0½” >em޾¹lé½Ã$!>j]¦>7˜‹=2Æ=uT¡»Ëø†¾®z—=ä/¼A:P>ò¤w=Ôöé=ÞM�;Ò€ˆ>‰e½ X¿½kÅn½U>mO©½Ÿ‰s¾ÀT„=?S=P ¾¦†ã=н#½8=“†·¼PNü½0“ö¾.d'¾Ý|´=üÞF¾ä£¼WfŒ¾6È=—‹>cÕ›¾øÀ7>òë=ÝJ†=©§¾õ8‡¾Ê¡ã¼ÃÏñ>µÆ»åð=ãÆ¾>˜j™=ì´ª=w>˾þp‰>eÒ.>BY„¾â€·¼g+>iÜý½O# ¾ÚÙ>:$¾Âˆ5>ù:¾dg§>]Xô;⎾\’D½þœâ= ²é½„eï>8Ñ­¼Û›¡½Ì尿¨Þè=N¾ é:¾�¬�¼Ç?hò¿¼ƻƚ¾™‰>¿ ÕE>H“ >ù_$¾—ƒ‡¾³áF¾UõÔ=IQ‡½ç…ɾð6 >Y×¾½ä9?¶ë>¦†¾§=ѽ+¾z˜¾€\¾#zؽƒ>àuô¼bð¥¾[»š¾¯…¯>°Fº>J€`¾£a¼SU5>&áß=ëÛ ?@û4=‡˜©>Ù3[¾3>oõœ¼DP]¾]I>ÖCº½’è0?“Ñ�>ë5!<³‘x>dK�>� ? ž¾Îß3¼pë)<ã<8§D¾úi"½5ž�½YT2¾2‡©¼`F>ÅË>§Í©=<‰ž¼êÐ;èÓ>³J¾]â8>î�=Õõ�¹¼qz=bß—½ÅH>¸Å¾4ëO¾l c½ÖÁ=Ë>M<¡Î‹½¨›o=øþÀ=ÍÂ?ÇN>ØR¾ªÊ½Ö¾šŒ ?Qƒ½Ð'¾!`¾½–¸¾œ£p>�Á÷½ˆ‹¾Ã¾%J¾.ب=ƒâ–¾Oн0ì¾,=ßÏŽ½·Y¯=}|>>€Å=kK¢¾M{¨>Éþ¾ïŒ¿m瀻gnz=Ëó½)ä>°HV¾ûåM>5D>n}{>Rº½³¾Zèå=/\>îO÷½¿ï&¾Î¹Å>›d¾c§ÿ½q’ñ=]Õ­½½ÄQ>@�ˆ¾·–쾆+¾ïÅé>="×¾L*Þ>‰æ²½ê<¿ÐF>ż™>°êÓ>xKI¾�¿½”À·>4l>•»·¾¡™ ¿)÷Ø>`gÚ¾+>�µ½ÐP¾Å½9¾ µ¾Z�ð¾HÍa¾E�'½Ïr¬¾«#>èÜp¼Ëà¿+¶l>ìi—>ê( >†ÿT¼ø}!½ŽÇ¾>1¾>Ôž“¾•š9½·5¾‹“¾C#>`ݾ²¾�ÏȽª¸„½ÝM== �>Û�r>ˆR.=!>>ÀYY»·8><€:O>=FT½ðͪ>yÁF>ïEq¾/Å´½1u>·´¼u¯>k}G>cÉb¾VÆï¼* ž½¤ =˜ó:<Œº1¾~n>*…Ú¾¹Gõ=F¼«½‰­@=­7>]ˆ¾ÖN>>úœ?¾ |¾Ÿ¥ÿ=®î>n뢼·¹>$’>Z‹)¾2-}¾Z =³²>á—€=âS­:q0Ò¾žn½‚D½b¾L>Ó�³¾Ý¬½\na>•–‹>U‘è>R�¼â6½Èʇ½¹ôÚ;°üE¾rf¿'ùÝ=ff’>5=/_©=‘S‰>S«\¾¾"‚>}±Œ¾ hZ<GǾgá4>§‹ ¾¯¡E>–§½à¾°7Œ¾Nô<‘Y‡¾¾I¾ð3˾]ù¾#ÅÖ=Â8€½ðY0¾ÜŒn¾pñÍ;”" >QôI>Ð:¿´VN¾Üç<=qNF<$† =ül9>Eµñ½- I¾á$Y>Èçð=F‘ᾬëÓ>½#¾=• ¿bÂþ=_†½Šž”>¼Â>YÅ„¾3厾DÁ;Gf¾ºÒÚ¼°>¨Öî¾xsT¼ óí>tÝ»�Rc¾ó{ã=5·í<9¦>6 ?6È>*©¾©q÷¾žß/>ß12>›¾‰;“O¬>=lV¾�ä>LD‰>9ÿ½P-¾IÅþ½Áêø¾æ¬!>è·½ì�>½ú ½oú…>xOþÁü,½%k±=ª¸$»n†½�{>a­^¾ŒàŸ>Ifœ=òÀv¾àhª<„hš>ús[>‹Zh=Z”8¾÷ºÜ½/=e¾/&ð½2=^ ¾êx¾â<›>Q]¾"Ö›>Û¯E>¼ >!q<¯Ë >8Z ¿3º¾ªã‹>íÐX¾ñ€ü½nÉÐ;ÿؾá¤ÿ½Ã�Â>̾޼ႽƒG‚>\ù¾Šì‘>Ô­ê=OÊ�½0Nƒ=ý½¾Ýì=YHU=2 ‰=§Lò½x–‘>Þ/>îD%>ô€¾�R‰=“Œ>¿±b¾Õ)�>¨«¿°ˆs>Íb•¾ß 6¾ñ˜‘¾!‘…¾Ýõ¹¼eÄ$¾à¿È=õ=²º0¾�Ä€= ãµ¾­ä©¾ôÅj>CTç¼±º×½·C ½KÆ>sK½0 >ðP„>ÉÉ=€ß3>E4Ë<*¿Ë>Ôôq¾u½¾ò'Ò=Â*³=£x©>¯@p¼Uj>™øÌ½¬\™=²çï=Æû½Ú…<ÿW¦<…ˆè¼Šþ¾¢”9>ÁðݽuÑ.>þ¼¶>d¹ì>ç—&¾_Û<ÈmÃ=‹K6óŸ>¬²>vÎ>tìÒ¾*i;¾½ï =T>0&‹½E<„>¶í›¾•çK¾Àë½íœè½<†â<2®Œ=6Á¸=‘™ÿ¾8>ûW>櫽Hp­> ›¥¾b¨�¾Ù ò¾(©§=�p>:ÊŽ½ßwq¾Ì¯‰¾óþ¯¾Ò]‰¾œ¦•>Ì$>w辺€a>J|±½…eT=måS¾ôfɾqíë¼HÇ=Js(>çT�>m²Ç=�~ô=‡by>Kr>W¤¾Á𢽾8ɾIDµ(ç½ ¾€û?V’*½· ¿,s}>¨6l½“W¶¾ñ;=[¸¬=‚¬½=ÉÒ ½�lÚ½œ#>4Hо(ï侞/I»ÅVs½Äë–>ÁÁ/¾¤>…Õ˜>¨‹>Å|Æ>.1é¾÷Y{>6SÚ¾”‹=>ïŽU¾^ˆL¾åξùO:úÅó½úØœ¾ûÕ’¾|È]>ªZ¾Âpú

¥ H>Ò$Ÿ>ûÊ?\�A¾™ˆ>ò¼>�²h>ƒF >ɳ…¾ÀT€¾Q¾¦F�½lϼÈgâ=Ù[>ôáþ½Ó¦i>Ô¢½EßÈ<bø=i¾2v2=ÕÛ:>½”>†T÷½¨nK¾Ì7Ù½-d2¾èþ?¾Ê.š>ˆ­µ½ SÍ=“}C¾‰äÁ»˜ÊK¾•F„;)lÁ¾qV>µ¡Q>=¤û½i¿Ê¾ˆ4¿Ž`W;6Ù/½çî¼ n±=ª¡’»¦0c>Û#¾Z� ¼ç*+¾¿âxÙ=ÜC|>—¸†½‡ž>)Ü›¾Í¾§ª >Ñ5>èŠU>ë_ˆ¾WpT¾unw>…ž}¾�šœ= †‹½åÞ=;¯>R´½ËS=›P¾ýYà=ó?1Ú=Åc¿› E½Ôú¥=v5é½Ü§¥¾]¶ù½rïž>3¾T_T=WhN¼N\ó½Á#$¾r>O>¾Á�¾­Æ˜`uy¾×Si¾ ýæ½Hó…½¶º>¶Ú¼Qñi¾¼�>n…—½[<=|¾½ð�ê>OX?ÌÐ>ϛ⽀0Ͻuíþ=çMÊ="#ý>eš@>¡�¢>^Ë=«4>@D¾w^R¼ìˆH>}«í=Þ`9¾Q="Ñʽ¯dJ½9þ̽¤øm>î¤9>~aо-]>¿Á/<�Š9¿×1ê=8¸ ¿à‹–¾Çu>P >î€Ä=Ý%>þQ»>™Úí=¬x«¾Õ{Œ¾Ð¨8=�xL>ùAC>ÂÒ‘½Òx> ëê>;T¾#ľ�û½uåð=M=×=0èA=yOþ½ÜÌ{¾'ã�>t_->rï7½i š>h¹J½ <>\X�¾ª:Ǿ²@¼Tz^=ø¯�>L\•>Âè ¿t‚9=Ðܾ„>áa„½Ð 7½ïd>Úœ1¹:c¦>×¼Ñ=ô ”>‚>󑦾I(>šÓ<·ÁI>r5_=‚�Õ»)ðÉ=àé…>îÇ{=âž—¾N8Œ¾2¢>\Ì#=§›¡= V±½Nʾtõ ¿€—<“¾í½[µ9¼¡ã¼=Ž[>‹Ðw<©ó¸¾ÍD{½.Ͼ£�¾‡G�¾6‹/>!™=E¥)¿)Ͱ¾lB£¾pDÈ<× '¾Mã?u*(>ÔJ?�‡£;æ„'>T >|Q¾�úô=Î,¾6 ¾ <€=V”@=:N>ó%1?CŠd>(¢�>=X;è>X˽L a½Sj>’õ%¾ª¸¯>Ûü>�E?î˜=O ƒ=Ò©a¾€h}>oƱ¾ÞìÛ=cr¯>m!u¾«Eè>8áY¼×ß½¯*Á¾ÅÉC>_q=z ½ð:g¿Ž"*<0|U>Ä�»½Ú(Ñ>z–°=ó$??]Á½ /É=]ó�½P+u>®Ž¾‘ю社ø`Å>˯Õ=è–F<Ö5N>t«¾Öå?²•=*Œ>mL#¿¶¿w¾àX&¾Ã>âBË=òšP¼Žpí½�3G>Ô ¾Y³>W_Ð=¬/<î‡õ¾Ÿã­½SW—¼:J5¾j¼=û–&>@Œ¡=ȉ=AéÖ¾v|¾q°¥={ú ¼Žï#¾Ê«G>Íb"?‰*˜¾ê‘˜¾U¦?ps€¼zà¾Üô¾è×é>õX.¾÷(?>üi€¾kÔ=4iø¾sëÅ>5V$>ô¹‰½t¶¾æÑ9>“T`½”ù>,ŽM¾P^(»Às¾äTò942¾¤+¿z ¾/µÏ=ÛϽYʧ>ø�±»ì@> |/¿ ïo>4dx=É#¾ˆ d>“e» æ>N6¡¾ÃCD¾cî!?»%H¿al¥¾Xâ¾ ™¾ùS/¿Ï¢=¬¯>uCÞ=iɬ¼13?Y¾F¾/Ñݾ*X?÷\¦¾k¬p½hø=>-‰.>ª+Ú< ½Ôö”>Diy=ýí$> ‚>d@Ò½¹v¾½0½:¸6½¾ØÊj=ðøW½j€‰¾Ž�W>óÌ™>.z ¿�«¾)Æ¿M ?P0s>ç$Ô>‘ÙÓ¼«ªR>� ¿U©Ÿ¾½Ù–>¸Á>à€š½FŸÈ>ÿÈE>ÓñÐ=û�˾õ:D>Dߺ=­ß>ú6¾¶ v>Q-¾fy¾¾¤r¾PÁ[½�Å>sN¾¼¼d½’O>qн>eÖ`>^h?Cá-=C „>»É»ÞÐ¼Ü œ=v{õ½ÿß?'ÜŒ>M�ؽ%b†>Ä�꾌?Þ>ÐØP=)$¿b ‰>¢ =¾<ë ¾1�Ô=Lî½èç¾ËËñ><œ¾$™;¾a;Ö>‘ëá¾Ôü”¾Ç‰D¼ª=”>Á"?пè^l¾W<Ÿ¿_–4¾>8å<ë\¡=9=>ž:?„ ‰>ˆ�H¾«_>Vg¯=¼…ž>Þí>ñZ½TY¾ ÄÃ=õš½}í¢¾kÅI¾œÈ�>â$ë¾´ú£>u¾¾C®3>¾Ä¯½ ”7¿c¬/¾ ”–¾.¸–>¡ Ž=õÊÐ>™�ƒ½N‡¾ ¢¾"*¾LHg¾6—¬>:Ž>ÓFê¾x L½p�>£Ž ¿'²F¾¢«>µÑr= =`k¼|÷¾y–¹¾ìÕg¼«äï=»êÞ=ß'²¾¶x¾FÎ=}D�¾l ¿’….;f, ¿±—t=ü¢™;5_�>ì¾â �¾l Æ>'™¿>K£t>˜H„>ßµx>É”›¾ë~ɾqÄ%¿�›¾2ÎÖ> !2½€h–>e/C¾Òi.=|�B¼± .¿uñ?ó«»¾,x]>L_š>ZXn>©Ì>@3,¾¦Òz¼W$�¾;æ'>A�¾¤CŒ=n®?‹—¯¾m`¾„)Œ>×=sB�½Š�§¾¾’¿Àsc¾•Xh½‚>¼i�½ŒÃT?®ú(¾£&m¾HÔÕ½t²b¾I÷t>aæÅ<°½M»5>"z‹>ùÎø=‹Ý¿>Þ<н,й;�”¼k¢d¾©O0¾/N�>ã4R>Ø ½Y(T>³0>EU?¢»E¾z¥<>L®¾“H <"ëä¾ëÞ¡=­V·¾M&Æë½^æ-½<îs¾ë´ó½KG¾ØÃN=RÜÍ=Òž|>g�¾i…u=¸<�¼dµƒ>$ÒŠ¾Œé�½ ò¿ðå›>¹ï�¾}+/¾Õ0½A¾ #†€'ø½õ“c¾;�»¾µæ+=€B̾«QÇ>¨Ó”=À*>ÏØJ=�\£½–þD>D²Å>S =Ô½€¾Žé >lÙ>-]˜=’(¥½îü‡>�k=耾¯éw=à*ýÃÅš>l8‡fÀ¾îW̾Õ%X¼g$J¾"p>]Ò¾� U¾¼3?[vC¾Qñ•½Ý¥p>É ¿8t§=�!¬¼‹©,¼uLÿ¼Žfa=à�¾.g£>Õ¿¾2³ =›c¦¾þ_¾ê`8¿Y¦>œÈ·=ÛÉ<uu>²m˜>ÖGV¾ÿò<=ìÛ¾°¶˜=Ž%¾±°Ž>›âÒ=ìË’>¼ê$=í¼X¾&£¹=«ã»½�n–=ÿ!Œ='‡¾/=O.Ó;µÁ¬>"ÔF>®~ü_ ¥¼“qí»ªMw=TãȾ×� ¿#}¾»>ºwî=ûøä¾+3…=Hº½ˆ¶=)X>û¿ß¼¿.¾ë~Å;sjÒ=æ´F>þæê<]¶!¿k½¾-†ê=¦\O=Üæ€½ q¾~{×>•f>GuŠ>"@ú½åN ¼W,ß> O½A$[¾ôTÀ¾šz–;MЉ¼‡Â¼÷ÁÃ>[¿P<ìæ<¾�^Ó¼¢Ø³>ì¾%�D>‘5®¾è]‡¼Šëນjé>ÍÚd?`þ>”‡;!´j» 3¹½´kœ>ž^¾*"�=ßš½\¤ ?ýú<¾úIÅ=Üh>˜ü»�µÚ¾‰6]½!§à<8ïþ> ¥ã¾ôÌ;½#©ª>øiÕ=ÕÚ2>�/>h?T=DñŒ>½�‰¾Rõó>ÆEw½ziã;)ù>pµŒ¾8û>îAË>=Õ=÷8 ?õa=GÿÖ>4M>¥„>ЇS? M‘;Ýú$>Òîü½|â<¡¿¼äæq½ KE>FG ?5½¸¾ ¨^> ³ >à÷ ¾)){>½!þ>ÍWn¼ÐÞÁ=oÉ“½•¼¾=!š^½¹Uœ>ƒNš¾ë/P½ç¤>É >2»ó ‚½ÿÌ=iÂB>ûq¬=ÿ¤ý½r°3¾ÒEQ>t›|>KµŒ>�¶¼¾ÔC²=.‚.¾“ �¾Iɾ1"%>¢i‰=;çÀ½cOܾɹµ>Úl¾š |¾‘ý­¾x\¯¾â¶—>�2¾©¸×>mûæ=Žw¡>¯XE¾dá§= Æ>të½Ý«Å½Aq¾½ô^™½üŠ>ÜØž<£äŽ;Aö>3ûŠ=‹¦¯¼†»¼rç:¾>Ö×>ßc‘¾ªZ¾T�Q?¯›I=×Íg=¦S�>~¨=¿o¬¾Ø=íõa>Ç?Ÿ¶Š=Q«¾ö!¬½Aœ>>]"=Tµ”>NFt½)üg¾Õ¾6Z> #Œ>ÙT˾¼Tˆ¾o�³>kÅÐ= ‹0½ÆEã½ÁS¾RQ¾‚Ê=Nô ¾Ù@³½Þù¾ú¾Ë~(>möL½•7¿‹ø@<)Ã->}½? fԽߣ?¤ˆ>j8•>)[¾`Ý=²+¾€–=ÜYy=j‰é=j¶Š¾Éà¸>Q€–½9k¾­6«¾§Þp=ƒÂv½¯s>·7ž¾$Dõ=Ðæ¬>Ž2ʾ g»¾™òL<�I˜<%ñ©>�D¾8.ž>øÐm>üÛÏ=J'>Öq⽫ü$¾v‡¾¾‘ ¿·¥/?¨æ=eüξIv´»z¦¿�‡9½²Ïw<ñ圾±Í¡=dfK?¡Èã>¨Þñ>‡2)>ÌùǾj_Þ¾¬n>äë¿ð€¿>ñú”>vX ½¹ ¾¦•ï½.lO<�Ú‰¾Lï—¾Ý{�=¾Š¤¾'l-¿US>·˜«>Àô÷=Õš¥>MF̾ ï>¿ÈU’½P¨¾uï¾Óã<²˜·>oGc¾P?¦ ¾aϽ¾œ'? c¾(³B>ñ‰V¾ºì>k“ó>Â_?>Ñ=¾ºJi¾Þ�Z>ņq¾_ÜÊ=�ô >«_,¾|G–>à¾Â¾Ì>9>„6*=›‘¾ÌZµ¾„N¾d7¾¾Fk>öF>‹³®¾P'?§…>ì±K>žÍ¾ÛøÀ=Þ‹¾~Bݾdž"¾ƒôƒ¾'á²>ÃÕ½7ŠL¿¼f>$�=qVö= ƒ =”u¾ÏP*»ym(¿b®>$î¶<·u)¿vÿš>1Û¹¾á,$¾Ïí>ÛV‹>Ón=2{>¡F½>™S<>x+³>_%d¾8¼ÅéH½<ݽ®2á>Ï=V1v¾W-µ¾Ž¹"¾­¾ßi¾¤¥j>§¹A½²äc>¸v>…Óx>ÆzŒ>èh¾-~¾=|ù0¾EѺ>Eå"¿H.¾Ó–>¨óì>y$н«®Î¾~�…¾ÌI>©ñ½Öõ0>, (½_€ß=¾>Öñ÷½Û��½m_»> ½¾Þ=•d>Áîà¼Ü>‹0>êM¨½[�A¾Å1>ÝÚê¾·lä¾BÿW>C”=ýµ‘>¨×¾9µy¾ônŸ=§ ?écv½é<~>I5„¾ìî!=H9˜¾Ø¸â= Sÿ>^Û½æ|ž»·§+>>}ø(=iŒÅ¾ª!ï½äk«=4°‡½ËÚ>ä17¾LÜf¾ßÚ°=* ½;ºo½¾•!>!ø!>Eëz½è?»½¸�Ø<±>ÄQ/¾7$¿®Võ½z}6> ƒ>OÿŠ>ü©Î¾ŒRh¾>%ý¾\øV¼y—ˆ½ý(½=¾ÑÀ½C`ž¼”Ñ=o²X>½f¾Á7>P’™;op>"%>º>=¦˾þË×­;ò[‘>{È”<£†”¾Xf½Uâ½³`Ⱦ ÎFa<ê`°:†Í>îâ‹>¶w>|×ß>¼Úœ=¹í|½~nã>LXݾêùL¾¬©o>]Ñ©¾Ÿ…¾˜—޽0e›>F®è½[¬´¾8m=~}½Ï4¾u§Ö¾×��¾¨Ý½”1BZ"M¾62">0½Ç¾?´´>…2€>÷´³>~ +>�ö˜:£ºÔ=ê}R¾íx”¾HÊB¾„ªm=S×>ž¤>£Ñ½úãU=¾_ü–Âm½´Ï]>óÑ>RîÂ=lÃÎ>¥AÂ<~>DVO>Ÿm?Ï·<‹Sæ¾ûF¸>qwÉ>>=¾¤ÁQ>_L¸=嫽o¾¤jú½T”¹>Þç\;»¶“¾‹Žô½á*¾·½Ö¯/¾P>›6÷½£Â=J®�¾êp�>݉l¾†ÈJ¾;$¿­v¯>® 0?æ¦Ð=âê=Öþ,nD¾Ï޾ ˆç¼ùÓ•= ™C½Ø×O>9ì=a‰m½œÌ;»_f�=p“)¾5 5¾ïn¾1z ½,äh=ÑÎZ> æ{>×,é¾À ½ì<Éož>ô™•:�&¾Áò@>2è½Òl8>£™2¾r�=‹³H>J™Ÿ>jkl½>a>’T¾lõˆ=A > ¶8¾[Ÿ ¿äfƾÀg>=D^¾�±º>)§ë<„œ„>VÜÔ¾ÈK>yÁî=©½àK>9E³>ì=ú> d¾;é�>2g¾J§†¾––=�5½´e¿iÙÁ¾o¾n?‚°> Òj½8ª¾w•-¾—…-¾ØúS>Ùu>xš=°½9¼þv?>SÍ¥>¡‡½¼:= úŠ>½)½Ö÷«½÷̺½šñ ?#Ψ½ D‡½š+¾år=û÷ú½}#³>]Ík>Þ_i>θ¾Öâ ?žk^=Ðæ¾ õD½ö”¾Säš>é·Ê¾w4Ž>´Ì;½àé¾'"é>”R¥>V§Ÿ¾L‘¾É0½Ñ—Î>ÓÍò¾�¥–>q„‘¾e'==¼ú&>£”¾Î=£[¾+Ľ0b=bˆd½[+´>Hk2=×xñ¾ì'‚½"ù·>´�=w=¢>yÎ>=d¾P}À>Më~¾ÊÝß¾8èq¾Oý#¾K6¾HÎâ>£6ê¾V%3>^­#¾AæQ¾Ò¿‡>ÖÎ~>½›z>Xq¾#.¾Âžì>”z:-¤¿Î¸»½˜·>›~>[Õ:?ðu^½�t ?+¾?ü2>�´º¾Ø,¦½ÝÌ=R… ¾:¨˜>NkL¾£™&¿”4 ¾�˜=e×»z}ƒ¾7½OYܼ羦j1>ï–7>,wè;ù¾ä %»èT >� ¾Öí={MнG)=ꈷ<0 q¾3-мô8¿‹ß¾µôó¾ÿŒº?>>`?CO ¾7Þ@9Ð)ø½çÂÝ<æs�¼è+¾çæÀ>°®O¾dIã½=W¾”s ¾`°½BIÎ=ø•ì½jk¤>˜^F½ÑÖå½À0Ѽ-̼¡¹›>¡óð�k?¥$¾¿R$¾™º»cÄM½iE=´á½ü„>Û31¿V<>%5½a¦Ã>䛯> õò>YMš½Xï#¾—Ú©¾Qˆ¾1›«¾‚#ؼS2޾ E>ŒP‘>¶ɯ=€ò$½]ƽ—T^½—Á½ÂÀO¾/ý¾r$?ë>š¢�<Ý?È =`*‹½± i>:™*>m¯Ç¾’Æ=¾2é{>†yR=ì€{¾¼(>˜Þ.½Zy >-} >/Ÿ¾U >ÔU>jXÊ=|ýA¾6fŒ>ÏŽ>†}ó¾…tå>R«>ú^×»ò’Ô=†x>Oe¼¾ Ep¾–œ!¾g’Ú½(ËÉ=üyÿ¼Ë‘>ô5‹<®>=Möž>kY/¾¹Þ�½{t¯½¡·A>Í<¾TYÖ=t%a¾ñÑ®¼:é4GËš¾ Ò›>Þ¡Æ>–Gã¾ìŠó½¡±¼)…6>`«É¾úD¿íÔ}>3ü¤=ÿ°?!t´½=Ô¸>öÔ%>/¾÷½îΛ>˽(¡=¦A>" >šŽ¿>!x"¿ÒH >Íή>À ë=\vÃ>òú‡=�i™>(Ù²¾[%J=Dù¼=)Ö_¾cJ\=0ɽép¬¼#øû¾†í½k«>™ð…>ýòä>at>䔾ö5Š=Ã$¿Õ仾dÈ`>”ÚÁ»Q˜+¾Ã.q>›®ž¾D¥@=û¬½ë2?˜š>Ýsž>°_*>ÓJŒ>1Ø!¾¡Íª>K?:?Ø•>:»K>ÜǽYô=H|¤>LL>nØÇ¾Iz¶½¤a½»Ž_¾ÊZ¾Ëü¾85ª¾Kl =Y '=“#>ŽÃ¾ ¾§».½9úL>l\ ¾Z3|¾SŒU½©.ؽܡ'>‚­->btX¼,Ï\>XíŸ=Дa=Þ½…7¿ó<£=<½¾\w>]»!?sè¾`m!¾e+W>ê8_¾ž©£½±3r½S¥q>�á=‰¦‡<ëˆÛ>s?‘™†>�ð¬¼?Å=ãâC>¡ô¿Y96>zá¾àÙ½é&6> ¬ì¾ýAw>̲ö¾Aj½Ì}>96j½¬þ]?6� ¾óŠ>ÿÁÙ¾Îê¿m¦4½Hð‚>Ñ�¥>Γˆ½A[l½˜¾¶=?hÁ¼ˆÞ±;Û¡¿÷i½™ ª¾ÜB¾c�Ú=Qß”=ŸBì>bŽ"¿ �ľv#�>V+F>)ó=ñ?Sü>«Ê8;OK¾ná�¾WD>Y@º¾€hÅ=@Ò¾+º›¾3‡•¾à½¾;:ã=¸Qº>{§;-‡>uû½>ú‹¾Ý8š>Av�>ÉÔ–¾�˜ >ÕA¥¼­„¥¾ŽIª½´û>'õ¾0¤>™[å=ìD¾½Aç=ãn¾N¥¾¹ ›=Mq^P�½Qc¼€È?ÃF¾Çw¾Yƒº2Ï>œ¿î½«Í�¾Ã³é=I-:¾µ>( z>.7ƒ=žÙ¾‹<ܾ …½Wo=¼F28>°˜Þ>n½R-¾5e"?ŠÁͽnæÊ=£óž¾zÔ}¾5$\¾·J>J26=\l>E³Ÿ>›À+¾…ý3¾uÛ½ˆÿ¡¾sñŸ=Fö�½è¯j>K>œy#= Xž(v£¾‘ˆŸ={uå<Ç¥> yü¾©ï¬>–Rm¾( b¾Õ‡¾d1Ò>#¯ö»~˾iõ¤½ipõ>\>He�>~Ž=Äæ:µU¬=—Çʾ—Ê=÷ŽN½¾¼—¾?ø¾›>æ#?:^±=["¿ÞâÏ=Ç’¾¸;.¼}ÇE>g Ï>“q>Aüp½»ßÙ=£1>ÒË~> „ ¾c™Ã=C9ö=ò´&¾ í2>…Ñ>‚W‡=fà;AÆ$>Æöí>óù®> Õ'¾bW!=—•½éïɽ Åb>½Á =$u�=eŽÎ½ó¤=(3O=“e]¾¥t”¾ÔTä½.‹<®ð®= <1>ỾSù>óz¾½lr”½.OR½§^¯>dȹ=ƒÐu>Ÿûǽ,fú½]þ>¾ucD>¨½f ‚>²¬0=eMŽ=¯RϾ8â-¾þ¸×½Xž<³ô¢>Hž=뮾îËÌ>Vü¼oÖ/?Ê+¨= ľf¥>‹q¾Ûº¾ºh%>¥°~¾tÔ¿zÿ=Os>«t>4™=œ¿> ›¯¼Þ©b=-0=ãC>!*„> PŒ½×‡é=ƹ4¾YW¾NW)>ßú>dñÞ>ê�V>[P>¶�½•Z>wQ3¾â!*¾ùæ·¾Ÿ>ž°d½¾Ï[=Î5¾'eš½ÇÖľNȱ½Û#_>Í迾ˆ$\=;4¾´€¾~u¾Ñ ¥½³¡r¾]fÒ=¹-þy/>uEN>¯ˆ¾™•¿@”Ì»Œ >ϳ½ã²§¾`¨í½ó“>¹X²>æi>TÍ>~k<œQ@>#¼ó=sðλ# E¾|ù#>�{Þ="�½ ù> m>|±†¾!¾Å>nCj½ôNâ=Bÿ€9d=Àú =¸ðN¾†ôû> ü=Î?žG>¼?UÀüï ³>�¾ÓS>X¾¢\Ò>†f„¾\aï>H7ü<–Ôã¾á 6¾\Î*½ŸÞæ=#D¾ ª>ŒÖ,=ü>AÆ‘·¾jkŸ=] H¾½ª>bêR>òa;‡Y‘>õ¶¶¾>sœ>Ã\¡¾¼ÿ=>Çh©>Ó­L½QÀ̽馾ˆú˜¾EIE»¨ÃR>!½G•¦¾9«_>C•¾IŸ›=xwœ¼v•´¾ž ”=ƒ…‰<òAÓ=H>B‚—¾ÛÐw=D_Q¾ïM§¾ኾTÇ=½™G>¬>¥Y$¼!;¾áy¹=µ¼>”N¾º!?߿ý«“꽟ìÔ=ä'Ð=&pÔ¾féà½ç‘¿O‹i¾Zœ¦ïè?ÇLz½4Û½3[©;V�޽ó ¾n.>]™v>1">è�V½E»;ÛÅ€¾ï.8>I:í¾‹( <¶Ks¾:¾ˆxw>òŠ>>²àÔ>OA¾ œ¼= ÖÖ¾î{€½c±ò¾sƒ˜>RΨ=À„†¾\h_?·ľ�Fq½îmѾÞ}™¾Û};ù ¿em=z¢ˆ>"ã>;o¼½‹L<>YD&½5ê½ó«¾&-ʽ“Å€½Ϧ=¦ù™½,¾¾ðo=¶XŒ¾ˆ 6=dšt½ç!å>Oþª=ûØ'?%ªq½)‹7½ö¤>Wg�¾X誾¶JU¾û÷=ÁÁ¾zZ¢>›R¾ò‘¾_eϽA'O¾uvl½WÎ�=˜fÞ¼'‰½î,'¾ù ¸>ªr>Þàÿ=´«=²1´¾^�?Î, >ˆ¢û¼G£X>ôyÙ> .Œ¾ t½µæ‘½^BP>Êúæ=,¨‹½Nþ•¾jÛ]>Pל½ e£¾ñŒ²¾Å}Ö=2ý3¾”h)?ü+½’jè=ß3?SÕž½ý€*¿œ Å½b½>Qy>õ”¾3ýï½¹u‘<{í>õ°%¿XV>5¿¾`¢>@°½Ó¿|Á×¼¡ð‰>àÛ¾­ô„¾4/B¾ÿ ½e*>´”>_Î>Gªz>%Cå¾xu>~ÿâ½úh=>‰q>»Oå>tû½Ì5Ñ>˾€>‡‡×=Y¸´>É€8>š¥¾Îᙾú)>ÇÆƒ<*? Ò½<¯X–="[M¿}‰E¾]o½ê™Þ=+>ÇV{½¤ò½ž�>)Ǿ@W¾ò>at½7—Ú>>*/>ØŸý½éD>ôl½‚ðÎ=XéÓ½CÁÿ¾I4S> $¾.h½Ýë�½Àa=ò ª¾‰™“>0ñ½—ìš½.­â¾�Ü€=­*«>�<´ľù”h¾ßÖJ¾ÍÁ\>8R >ô‚ ¾1’—>¸E?>!¨Š¼XüÄ=›Îÿ½Üa2¾Ó2¾•šm¾ [¾rÙ>ºþ–>(ên½Ì*¾¸r¾Ò¥Ž>Ý*o>ë$¥½ô[f>ÃUô>³h¾€&>#´»½0n¼üš¼>€4P>Ó¤ç¾f€¾s*?@<¤½Èó�;)º€½àÞìÑRž΀¾¿Ù¡½âü>Ö¤½^­=¾h݆>,9¢<£}¾îT¾lSÏ=øn>ç¡`¼œÐS>+Ÿõk¾<Ë8¾¾ú<,¥Š¾‘+½<3!á½7˼rÖÿ¼³_ ¿jèW¼j‹>8ѹ¾X?í²½’ͽ�е½M"½Êüe=°º‰>ž7¿ž¯è»ãNã¼YÙ�;òN�¾$h=½ �•=¥çœ>&M¤¾ï"Ü> áԾś[¾0!B¾²ƒ¾ |>êç½ÄÒ‚>åe‡>–±>äF³>\ ;¾ŽÐ>K°è¼žÀL¼hÄ•½Ð#‹=TÍ0>Çå´>ÀÿÒ>‡'ç=7<Õ½#3e=ÿôâ½öŒ>DŒ]>â<_Û¡=Ðò[>/k>^ú¡½1‘«¾Lýï½ïνȅ4½ÆD ?¼Ï>¯ÛϽٚ:»6{>¸ù><„…½ŽýÑ>Ž"F½Ü¦ì¼{ =w˜|¾@( =YV”>Í2Ô¾`Ôʽڟ—½çS]¾w¢�¾ÅbȽ'Š™>"“[¾(?˜ñ{¾ˆéw>g4–¾Àbþ¾¸Nì>×?÷=?’œ½ãl.>佑›=¾�s’>‰í<—)Q>ÑE®>΋u=º;q>ö¬×½Ï¾UΪ½»4>âÿ>xÜU¾œ)>�%)>w0ú=Cž•=“’‰=-8@>?Kf¾8²¦¾;ã>ÃàU>Hq>Ö3>vøß½^\·<”í£=šGZ>g¤è½[ù½£š«<ÿö¼<@‚’¼ W¾EÜÔ½.œ½Ú®Ï¾tõó=œ±�¼tª(¾Â]’>LX2¿äV0=Éiò>X´¾’½¼¾êZŸ½,÷½WP޾ }ܽs1¾ƒÉü>‡Æ0>mE‰¾ãÑ­½˜Ó¼aÂw=¶>M°O½·C½í+=>¿™ŸÀ½­x˜¾†¨>4„x=àîC=UW3¾ÛV£>µ]˜=f´“¾¤ai>ØR¿†ºá>¾Û¾–j¦½ôóú¼¾É¾j}½ùº¾@c¾C¾÷ÕÚ½3;‚>D5X¾äç½U¾¿Þ<Ä™¢ž¾îR¾ròý½TB�¾±e=>1‰�¾—™®½"\G>œ’’¾¹×½v´Á>:¶5>›êç>à÷æ¾'û½_a>¨6>õé¿+ >Ù5!<–F¹»æð¯<K‹>¢¹¾ B ¾Œâ½½ß¿ñ½ ¿M¾e ¿½Ð¾†>\)<¾váa>”…>ˆŠ•>LUk>'þÛ½ÿCš=5øÝ>ù3|¾ö5©¼ù7¡¾‰1>€¾ÂCX½÷ä¾kÐÛ=¼Â"3¾36½c¾¯D/¾K˜¹¾š�<><©.¾§|(¼”uf½A‰b¾Vo¼¾eô½H÷>þT>dº4>¿¦º>#ôO>a]?‡lì<2í ¾ÜùÞ½‘*>tôØ>î©,> •…>«éu½Y¶€>"¡2>5p=6!ß¾û|?¾;Hr<2ç@?&{«¾qµH½Ü‹q¾‰¼O»Œæº¾x¿9=D襽‘A/¾!v8?*.`¾ÇÝí:�ó™¾Ú›Š¾&ˉ½šÐ­¼åQI»Vª=ëûÈ=Œ³R¼ÂNì½yg"¾Ö+¤»i�½âq'¾xÓ >~~â½QÁÄ»#z½ $Ç>Zô—=—½ý>TR<@£½•™a½{—�½'Ä ¾îÐ$<©êµ½-Òê¾&¾ø¸£>›•¼>bÂð¾@9ž>%@X<Ë Á>Ú/>­Ú=½bé=5ã¼W,=©>¾½?`†>žM„>ûýr¼¢#>?„„¾²À>ýñ�<‘·?Ó>Ö>Öiþ…gù;x¶@>zGd>#L)>Çy¾³nX½Åƒ¾ ¢^¾þiž=G˜¼©Ž½½{­õ>jñоj9>ï³�¾È—M½‚àÎ=¥Â€¾н><Ô¿<Ü[¼´Šz¾iTž=k̇=GET;ÐÛÚ>)¡½‘§l>D³?nˆx>¹ˆÈ¾ :Q>‹óÙ=‘¾ˆDv>y‹=@Ôv¾Y˜¾ð#•¾*Ýæ=ð'¾Ú÷.½.¿þ¡…½~e÷=²Ùi½úËD¾¡(¯¾œÖ=$Ó�½Âˆa>�ª¾ku(¾m`Ì=—¼Ö¾½’¾X¼Y<¯¨Î=Í�Ø=ZY ¾¬  :Ï]¹¾P$ü=H@>;ø¼òlú½ñõѽý"U>‘©=ÓD>û½eG>M¼‹¾ ý{>C×ð>ͯ½þ}=úˆƒ½§�¸¼F¨3=î»Þ� ¾,^< =ÿ×>:Dç<ã6ù¼ÃVÂ;´4³>±½£�ɽjŸ¾º°¿Š>!¾w÷¾§¨*½‘©¿Î9>¾êµ¾X @> IJ¾Ó°¾Ðf”½ö–Ÿ½¹F7>«áô½KN÷½U‘¾ßß¾†R2>ë”ý½šÌ>#¿¾Ú¦˜9‚�¾›Õ�½ëð²>w¯½»Ã>bž"€ž¾*¹©>ÅPQ¾�K­¾\&¾ÇÂy>Z"—>§$–> nX¾æ­Ù½ݶ>Ôýܽ“wÇ>÷\>m¶‹½pÏ«¼ÌPy>»?>å°¿¼?›Â¾"ͼDŸ ¾A¾´°>� œ¾Æy¾¬S>wUc¾Ðk½6 ¾ë¸·=ˆöv¾Gûõ¾¤)¾5À?¾æšÍ¾oÈõ="¡W<òu>³ªµ¾Ú½}=zº1>ã= c½ÅÁ>j˜s=bí>×Ù'¾s ¾dÒ=ðÔ*½ÛmZ>}D½Z宾ý�‚<îlÉ>qðl¾ü¥Å=) ³¾’=ýˆ ½õÏÖ>ƒ ,½®‚лŸ{«>û}…¾á`ù½é½n>1)=µš›½e$þ©È>ºÁC>ÈZݾ_S¾æC; î™<¿�>]��=‹,=› ?¸¨Œ>>ªn½».j½óÌ€>ik¾=î¾ 5×½ÉC[½¥‘œ½ ƒm½ È=ºð=úa=4ü´¾E� ¾"P‰¾B¸½Ÿ.f½ÊGv¾¿Ñ¤½8'÷½�§�½U,Ò¾Mê4={9!¾0²¶<$ù>¾ë-=[q�½}[=Mé‡>-G³=Oß>–¡ç¾Ìn¾z,�>gZ>Ô‚›=¾¾ þõ½±»7>ï§ ¿ˆW>ÝB¥9)K¾±>Eßö½•1Ü>UY…>BR~¾„…¾ÓÂ>„J®½ðfÛ=·Å/>Œ8!¾ÿ.à¾ÿ 9½“J=Ä2¾$)Ú=ؽ>åO†½(í =Þ±>]·Þ½Âþ4=:€>Ë%¥=9��¾�Ÿ¾̘¾(Z=¾n±¼­°V>£%ܾ§ðɾƒÍ»>p�½÷·²>~˜ä¼¼¾Â¼˜"¿Ó3¾íèn½ß0ͽ“š“¾h‡o=Îk¹=i§Ì=Z#A=:—’»Ã©Á<óÏ= aæ=©ãd¾_k[>Û’¨>§´f=M£¶<êÐ?><4>ñNœ>Lñ”¾Ðºc¾†@½!l¾¾¤»¶¾ø8˜¾Ùö½Ã>C´ì¾Oäc>5¸A=�{6½x‡…¾Ìü¾¬)›¾L‹ ¾qÏm½ý#¿E?<"8¦>hœµ¾Ýù½>It¾¦ŒP>þàŠ>U�> IŸ>­R˜<¦}‡;b½#F1¾P^1¾ñ�>‰›>È*#¾þÐx¾¾£³½S:J¾ü�=åé¼Êà=—O²=ÓK>ar&=¼ä5¾šl»ò�>—*¸¾jIb> Þ=Oб>°*½sÅë½Åæ:¾©c¶>°¨¨>ÙäT¾LÞÃ:v«�>r㟽gwG>(o¾ Ÿ¼ÏMI=Øhž¾•õ’½BR>='„¾÷µx¾ímQ=‚O1?G> ¬?$�ž¾²)>²m£½c¡*>Ýɤ=óAÚ½¢¡½§¦Í½I”ø¾’ßȽÃg�½öó½b0¼. >ùé>ÓÛ~>h¦¾æIû=”‰Ð>MɈ> ƒ>‘xh:‚Ô½E„ξç罾徎ƒ>k‘ <§H¤½³Íl¾ Š=3O ¾Z?ú½´Y„>Ñ€î>êè„=zU¾Ãý=ßYß¾GËš¾- ª½Ö�¿s€½=¶š/¾¥â¾½ð½þëx¾o>iÏœæÑ=>¡9k½¡�S>x-¾lL>s½#�¶= V¿¾´“µ¾PˆÄ½ˆMn¾âªe>ç߬I ¾Ö‚>Gky¾j6J>ègŽ=˜ã">,‘¦<,¿‡>$&/>î"|=î뿾ٚݼœ >à=M¾ôw‚=K` =q$P½åƒÉ¾šˆB>óÉ‹>£L>y‚.>9ôè½Y£ä½‡!>ãàÙ½TG«>v�®¼:}�¾Ob¬½ÏÕ>;Þ¸ä>Š9=`OÞ¾qé}<°þ�=ëÒ¶½:¡Ø½—ÒS¾j€Z=vla>)ºq=7>޾$g½>9 ÿ½¸O>ć=+²Ÿ¾]º¾]T¼Q™=kÄå=ÊãA>g²œ>¯‹…=�©¾*]@>ÃrÌ>uχ½¹`>gS>k_>$fˆ»?A}=6¶ý=œvm=öä=gËG¾‹+Õ=·Ö¹=¶�¼­r’½[b2¾[Ü`>µS¾Oƒ‰¾‘ ¹>6Ì�<›Öè>ü¶>¨õ=�Ó>èê¾ûuؽkÍ>.=Ú¬ >Éì¾J¯¦=¡ \¼£€$¾.o¾ ¢ ;-m¾¬Rµ>¶o¾®Þ‘=n8�;7D>¼U¾ëÃ÷¾­Û¬=І=5;Ó½Ô?f>ÁOT¾ÅR!>’Ä=Ù6>¶–¼¼ëô=z�¾ÎÝ>UŒ|½‡1P¾»�¡¾¯sY=[;­Eš<)ʼìʾ>C ¾±¿¢=ò¿½¹?�¾e£™¾Å½C¾Ÿm¼wá´¾ã\>Z„©¾uù·»ÃՌ<;£ø½Øñ?CqD>ô*�>‘f–=\G›¾û]½€‡I¾•‡‡¾±(>ä×½3¬©=6ù¬½Eþ<œbi½r2=JMm¾´¢h½A![=3¦µ½\n8¼Â[(¾�¥�¾l¤¼¾P"»¾PHo¾À§¾A #¾L ú>pUg>`²£<�/>׺ä>9Æ>�Gõ½²¥2=Ô?„¾Q)9í®>]0‡¾½K.¾Ëv(¾nx«½´Íš>)p佌5Ø=qͰ>›«©¾qØN>ò >´J>Q÷>Ü\½³þk==Ûø½(œo=.í*>I¤>&\=;}B¾§öÑ=ƒ�‡¾ùoý>¥¹–=q̾ïíÛ>–½E>ÄÐ}½ãä>�¶$½<‡¨>º½‚I½úF¡¾ d?À¤D>O==ù£Â=\y=—,}>²ïÁ>|7â¾ÅHÏ=eY¹>¯Ž£=˜d?Ë ö=H4¬¾Œ¾=9:¦½Õj¹½“–E=7"7>ÈÜ齑²Ä= ×:>RÕÁ¾[E¾¼;è>F-S¾sý»Ê0Î>åJˆ½‚Ç‹>¡8Y»ÊP�>ô.d½9±?vl>ªZø>!j½î=2¾e,†¾Ò¾¹´ƒ;nÇǾÎè+> ƒ«¾]Š6½f¨ˆ¾ý‡¾mbº¾úu�¾í¬Í>=î˾›+÷=Ûþ)¾ˆøÚ=?œ$¾¢€Š=rN�>¦¡ã½0/Šº �»½1 ¼¯Uf>R?>nÅ=Õ&¸>ò¿(‚ƽn.>8p°½Ž—J=NIν� (¾ä�3<—P ?6œ¾„÷ >hº >!ž>m .>nK¿;d“=Ž‘½¶•¾ÁØÖ»í²µ¼JÚ¯=ñ©T¾ Δ>Ksû>Ë ?î1‚>Õ`+½*Ç ?kå=Õ÷甘¾q‹Ä<;ç¼ùÍ=f�>EB\>6«=¾û®d¾o>ñ>ù½ ¾CY¿€‘„¾)˜¿ë»p>@l(=6¥§;l¾;]Ƚm¢->�+6>é€?>%lg¾¨ò¼½úE>�'Y¾Æ–ï½7l®¾ÒW=œ²È=éÀ> Š(>Hpa¾è ¾àì½áĈ½´×C¾™ý¾½÷åx=5£>e-ë=å�·>X¬¾— >c=E½§†¾÷ 9z;¿>µ�¾ùL�½‰V=W` ½f±>â¡�¼ª¥?<”>@J@¾Ç­»½Ísõ»KáN>Q|†>¶#¾.Ž"¾s#¿þ”¾ ¥º=Lîj±õ½ÃË,>!l=Ùz">ÎÄö¾Ô'}>F0½ç-–¾ã·=в¾cðj¾Yóë=ѥľÍµ¾ðžÈ>�«R¾])>~ M¼ØxÕ<”I„={ 8»›¾|>2X8>:+�>ØÇ¿ÅL>Ì{›¾´ ¾nÝh=Yõ$>ˆõ™¾ÄÅŒ>HúǾ*Q`¾Ý[=@—Ó½ñ®Í=zeU>„—œ;°¡…=:?Oë>ÁY¾sµÏ»<Ò¿'Ã=­%=Ø›>ímš½K»!>ëÅb=¢U>ùxCÑÈÚ½Ñc>¯L(>4¿¾á®�>¶<̾&:Š>ÚmN>zU xŸ>¸où½s¶v=Æt’¾ªT¾‚ûø¼ôæP>é'l¼À®¡¾\ŽÜ<üì²=*Ày¾§­>x ð¾„Ê®¾¢ªÿ½/Ä´¾ÄôÇ;{;¾͉=ÍÍ·= äb=bwú>œÚH>-+¾›|,¾A;à;Š&¿)(”>—ÞQ¾Ä˜Ô=ïâ¾ðiB>ë­ð½1Û‰¾›‰ù¾«š#> t ¾Ž�Œ¾åp¿=c¤i>㣠¿…—=šW¾Î¡0=íÌû=Ù©x>#+¾K4¾qN-¾,g„>hÄý­‡F> lf¼ÿ½›\¾]�>¼sÅ=66¾CÕŽ½pVé¾þ«=ÕѬ<Þ¿0ñO>ÕÒ¾‹HÝ=Y +>+»Ï=zL¾ãF¾Þ‹‹¾ °¾fbZ¾hD <»3¾´+°>.†§½”7”>b�­>Wû¼AÂþ>Œö(=e©=üàÔ>TôY=AüD>PG²½cöh½rƒæ¾±¤8¾i!->!#]¾Ù�¤=.ºæ>Q³,<¿m5¾#´=`¬ ½Hý•¾|PA>X(¯¾ Kd¾>av¾B&�¾’>åNe<$¬>ý›×½e¤¿ÙÚ¡9°ö¼¾Æ�½ÉâZ>¼>ЯÆ>Ô‡!>ªÆ�¾+@¯>¡ú >Eó�>E>é¥E>çs±>uŽ*¾­æÆ½üh½½R¦=¸ˆ§¾;ƒj¾Úê�¾põ×¾v ¾æwù½Þ>ªü£¾ÂÇo¾akg=ì¸=¾ ÙY¾r�8¾\·¨¾ÿÆŸ;÷Ñ6¾<0Ú½¿Ìо3)€¾Î²½©À>e£ö=Å,¾½Ûk&< ¤µ¾Û’­¾·|ò¼vwI¼ËlU<òè>þ€??›¾Ï6Q=©ó…=Øò¿‰Ô1¾�Y½A~ß=ßq³½K¬¹¾Fp†¾|¬¾)á>¶!t¾šéF¾¯£¾ØÝ8> Ê>ŠÒS>³t >ê¸ ?™R°¾F?¸Iñ=ÿ㡼�=ß=Hc ¾U)¢=Ïs1<"Rþ¼Cva> Žv>-Bú¾¦‡ð½vÂ�>Æä­¾RE§¾— &¾> ¾ý­Œº»Jð=ýu°¾o¶‹¾øÐ½ûÓË>iè‰=V«–¾øj>ÆÍ¶>C=‡¾4S<>–óˆQ°= º­¾Õó{=�IÐ>n¼>ß~¼Þ�>s1¾0½É>-öò<š1Ð>~dè=§’¾8#ͽW?9¾ÿ>ü0ú=…F0¾Ql ¾¯ ¹¼M�K=„o0½¡�=u2–¾hºÉ¾Y�ƒ½—øK>#rŸ>=~E¼õM•>‚f×¾³º(>�[˜¼kÙj¾Œüð=b5>¬ú[>—ç0>ê³[>ø¾(w„¾@¾Xfª>lä÷çÒâ¾|uÞ>]�€>Ð�³>0¢À½J­x½@Az<’ÁQ>®â>‹M< Œá=q²g>®BÞ=¹/»½è*¾l£~¾7q>³@f¾„‹¾�öß>«Áx>ªO>óâ¾��P¾jî¾õ6Â>ëùl½Uð.>7r¢¾ö¥‰>¸¯�<„Cé=š†¦½ç’½$Áܽ�?4>¼L>Ü!¼½VÏ3¾“>å½Õ=ç<˜¹=¨ºF¾�¹Ô¾M[L¾–´½ùŽº?Ÿå¼k`>¦ßd¾'¶½&Ö>ø‚ž<ãýå¾öDÌ=€A>Üš)¿<5Õ=Óì¾Lî…>î≾e >Y†…½õʘ=“¤.¾áä»>g|¯>…=¥½…’™½+óó>ÛR>þ�½²ˆ1>H_P>pQ@½õ  ¾ÙǼm¾…?>Ç‚½c•1;s ¾¾*á‹=ýÌ< ?pBF>bÒ;¼jN>Æß€¼Qýj<ÈP">¬ïľ¡œ½ô´Ÿ=I³>è"wºJ®�¾//¾³ˆE¼Òcܽe” >l<;¾ó¤ ¾(7ľjzü½Ò²Ð=Rî>ŸvJ¾''å¼A_Q¿þky¾á™ ¼ÝË=”£î!½òѾ¦˜j>αê¾S:‡>¥!f½>ãJ¾!„=‰ÀÞ><ס¼[ø˜h�%¿ÑÒw¾Uvâ¾Qf½C¶½æM°¾×wp>ă2¾µ'à½FÄ=®ª‡½° î>/ü´¾}a¸<‡o6>�8¶¾Þ?F¾¬ë<Õú¾¼*0ª½´Ò¹¾‡ÁY<ž],?ž‹Á>J¨š¾¯¾uqh¾‰çK¾…?,>÷Å=Öê½:Ø|>js> ÑV>¤G= y`½*+>á²>“�‚>­“›>¼Û^>Çdõ½�e½Qí¶=±Ü¾>3.(¾ßšƒ>ø×»=sh> /è=X•‚>`±Y=%N7="õŸ=¨Úż#Ø>CÈy¾Ÿ0=5œ©>(Å>6��>:X< ê=:Þø¼æð>Ã~ž¾^–9¾#t½­¾¦�š=ÍÞ¾¹i>y>U0¿7 £=µ¾‘Æ¥=óÿ:¾¹¦¾‚ ”¾dM¶;3½‡�¾Ö%?cR»ùr¶ºñ¼÷7·¾z{¾Oóâ<™V3>‰u›=`:›=Ôµè½*ÌÀ¾8 ¾¾£½1%;>0…ϽÑùC¾vy?OÁ`½:j>þ\þ²sK¾Š$’>°Ä—¼š“>Sâ3>ôï½¾·›>P•t>Šhܼu½}ýõ½ûœ4=?hn¾¡µ¾²œ5¾rÞ½åÙp>°cš½Ô\Æ>Ú4p>Õ€£¾ã‚¹<¸¢<Ñ[N¾]>ÌT’¼Ýk¨=.Áw<�¾~+¾=·@Ê=6¥É¾4ø¦>5ú…¾¬%ð½è�‚=Mѱ=º¥&>ðÇ4½Vð¾(X�¾q >i3y>>€ñ=%º>>º¯5½ÛI7>c£f¾›tä<üU>lA”=xo¡<ÆCO½´áj¾’{Á»ä8ð=ÖV>-8¾kRr>6˜X>öÆ ¾Ÿš=|F">[(¾Ø(¼ƒëÉ>VQ½²5½K¿¾5¯¾*�>›?¾W$–¾í,½FÔž½·j°¾6dâ>Jj.¾*  ¾å\G¾¯ò=ÉÊ >/´Z>’X ¾IŸ»¿“0=¼ðV¾l™¾=ɇ)>’]ù½[©º¼³Gï½ÂÀá½Qb§<ïw§»Óï°>#M�>XR6¾4ü’=®Ø¿i•>òXµ½S÷B¾Àtc¿\K¹¾Ãúr<~F^½ãw—¾š'”½€Ó¾ª5>Î]†¾‚[]>ø�–½Œ8!¾Ë3>àÓb<²þ½=By½®2O½º9=C Ü=Ñþ–>ãjh>å½Ç_¿™–G¾’üR¾y᪽äŽG6½MuX¾$#¾‚R=ƒkª¾ºJÞ¾ç>­=ÿ%`½竾TV?¸2�½[ýw¾#=ü=О¾Q^Ø=¿¸½ L³¼VA£;c;Ÿ>‘B£½!1 >¦ƒŒ¾&i£> Æ:>¦/ ¿0, >ƒJ޾A1K=Ú„¾Zn?gÄ>@·€>í®¿qð>$.¿©!Á>§ï¾±Î?>"R½ }=]D‹>À7Q>‚šæ=¹Gñ>¬¬+>OaH¼I9|>%÷>ßÎ.>ìˆ<æØ½“/>„6ý鞕=#·j¾úb>:á>Õu >Þá¾f\¾®‡¾~c¨¾èÔØ>Dò�>„ë>#í[;ܨ>aN?ÒD¾js¼ÀÏ™»§޾33Â=žPî;‡?¢¾á‡>„0S>™†>‘… ¿~‹Ð>Кµ>37u=Ý1>úôa=0]>Œk¿GLð¼~ñ>ßP#½r׃½5J#¾úáæ½·Þ*¾Ôƒë=l,¬<ÈëV>E)¾ªýB>ë¿9±W¾9xÍ=S•¿¹�¾ (½7 ?Cê6?&"Á½]Þ×8u“½=á=L•>¼›<½Ä_—>¢ã«>=N4?®ý½Lo½¾‰¬>þd=kJ$¾‚7´>”Ñ)=ôŸÿ=I3¦¼L‹¿_ù¼�‰U½çˆ=pÏ–½ùa4>ä¾j˜Î½®�>:áºùþ¸=îvô½‹Pè½Õ¶ ¾)*¾°¡r¾¸m>ä,$¾ykA¾@Ñ=‹ª>ì&‹=ÆÍ>-¯»>[:•¾ùù<ðW‰¾Ð½ú^>~¦=¦¦>¤êžÖ,ž>Îk>¦òÁ>l'=Wì´½K!›½7}å=ÚÛô<(o>Áñ:ÌÂj¾Ž‚ >x`:¾³ ¾±o‡>t$Ô=#4$>÷Ï >F¦>’X¾(ã¿÷6X½Â°;¼˜ƒR¾'g~¾fòÉ>Rê>°v>˜¾=Õ‡½Gˆ]>Ù¦>�v�<”’0>ºðÀ¾§s>È>�!Ÿ¾F�>¡ä½uË>‡l!=›È >µ>¾=dù=ã‰R>¨Ì/>™Y>{á1¼Î?8=%¡%?¾¶©¾c);2g‚>qè̽yÛݾ(y>´!¾¨Ï˽“-ö;S«>' >LºÊ½u¤7>CkY?åãp¾¡V¢;YXÙ¾p[´=�j8>°½(7¾ ûr?Ä…Ð>þy>\‰£¼„¡¹>.`3¼SÓæ7>Òñ[>}3¼ÑK‰>s¶¼2¾= Ù>Ös#>cäɾÔ@¾Ðɾ8èZ½pŽ=CKY¾”è®=«‰=B=ò©ë=]6¸¾Ð)‚=�°*=Ç(>žmù»Mù<h~½7V>’“H¾bç߽镰>g|¥=G >nhÞ¾wŽž>h©¾ž£�¾ûB¿¼Í2Í»ÿ>1 &¾¢2Ó>ƒ©_=0è=¦,w=95~>·Á?½G­ƒ>6±>�åC½nI¾êÎø¼yÊ¡½O* ¾vz¥½¼e¤½ q=Í]¸<-!¾ÌÏ.>"yª=z/u¾ÚôIÉ;JG$¾1âE>iy½îÓ5>Kì>´T�½0M ¿Õ,Ž>†"€>|{>ü÷I½¼ï!¾ª°=É=¯Ã¾¾M�=t *¾0{Y¾;Û½áø>ÒÓ­>ÃÌ˾ć¾¾Ýåݾ‘+g¾ã�÷¼‘ZB¾O*Ú¾„P½ìl¨>Üå>j¸Š¾ å{<Ò¾ØÔ�¾ÿ¤a¾S¯u¼s*ཕ´1>~ß¾RÓ½ �€¾MŽ�ÿï˜>©n¨=ÿζ> ÷ ¾ø1Ä>YR2=ņ,¿]¸Ÿ>iŽäë>Ð/»"kÙ=¼ûë¼û=(¿3À=ñ‹B>ˆO“»üýž)1>QéW¾Wû¬¾3 Ÿ>—÷J½dx0¾2�—½«³=”ïY;uP–=‡S >˜r¾ç)<*â > ×|¾A©?~ÉÄ=…Ž9¾VÔ‹¾Í6È>�<À? >Ï�Í>“ß>[�}¾%„1¾¶Ø=¢=‹¾“ÓμÂåõ=+s¾)òf½üÈÕ=Û_Ä>áZ¾½f>1¾¢ڼοI>½ø½h{e>zô¾nп]5§>1ü,½éi¾ãü6>9^˜½Ýº¨>eaS=p<%±>Ærȼ/¨½�+w¾Yõˆ=�¾d5¾¼ëH¾Ô»¼»‡»›ËǼ«Ôc¼:lM=I=ÁÔ¯>Ò–V>âׯ<ÔÓƒ>ê/?ж>ú»h.­½ о+¾ʣ¾e\M½‹þô¾äož½2Q¼¾IžÐ½6š=°¾"`Þ½Áî¾;=Å=ìÒØ>5 Ò>kN#?Ú¬>,ÊÜ>Æ »>¯pϽõ=o>ëÑ>L'པ͂=h¶Î½Á‚¿µ­-¾¢°Ú½«Ì;No­<£_=Ã�r=$1œ>*ÜX¾R¾gŸ•¾Põ=×X‚>oȾö˜ü= ªŒ¾ÎW�=?Ò¼3èÜ<¯Ûc>#߈¾o–¾!Ò½¯»x½U?½î�=d’7¿;·m¾·Ã‹½Ú'7rš=ÐñÕ½$B€½¹¥S½­nB>Ñý>Í`⾈¦¾¥ý¸¾ÆÁã½ÆAV½ kN>‹ñ#¿=kÚ=vl¢>F’ɾ¢v_>‘"3; ¨¾×È=âq¬>¢Ï`>±=>° “>Øf ¾_W¾œýb½)°=ÛL¾V >¾0•3>`Ia½2~M¼y1¼/íc>©¾!Èæ½ÝIé>vï…¾“÷<¤ò½ê•¦¾Ï9¼: „&¾=F*>¹:ؾšj>­ —¾[…J½›º½‚¹f>½3Ö¾¥^œ>p€ï=§ÆÈ¾ÛëG¾ y¾Ôr޾¬% ?qÒt>“‚Æ>ý\ô=í{.>4øP½öѸ>¸é„½A€¼=û?ÁKʽ˜Ú+=[ª†>Ò ?8ŽŸ(+>èŠ_¾­ ³¾HÆ>)Í”¾bD½w¤=9˜Á>ö¸¾}'½ˆÎê>p®º¾o‰ã¾x»½é‰>ª@¶>«²n>'Ô=ë’“=ð~ã¾i>S¾5M�¾\1Ÿ¾Âöï>rJ1>ª®ü¼Ÿ¾ô=‰lm>‘9$½¥ÿ>lɾêgJ¾ü�b>d ¿`Šî½‚¾Œè�=n³ž¾ßC޽>gª¼Ó H=ùg~¾À� >“¯;¾Þkš½§ Ï·çE?�‡‰¾LÄU¾üš>%AÃ>�0L¾®ù^¾Õ/<>ŸÎ�½ �>¶ž«½³b—¾}D¾Ä‡Œ=©Ä>ª–È™²=ñ8“¾ �>A¢�=ÜŽ>¬Âñ¼º$оMù¾¬ š¾Œë=@)?“`½½œE¾Î¾í22>¨&>%÷s¾Ä¡„>í¨¼=Uj¾æ²=‡¦m¾�ì̽[œ¼¾ƒƒ>II�>¹b¾¶‡Ÿ>z­›½l¬Å>vH½«‹<�:¾m±=½[’¼P­&?GmÃ=å¯?ÓXع¬=ò=¾øW>ºÉ?×n_½eêË>UW?»O =Â�—½á…¿½`ª—>œ¯à¼„˜“>f+¾9¥ª>Ý’I>œ’a=\I~> ÷Î=¦ÒA½«m†>F˜#<¾)É=ÂÍ`=†½¾‡ã„½úx > ²¤>3­#>N—½ÇJú½Nœ> V¾Vm>5Õ¡¾‚µ~>¸æ¿(Eš>ûï5?õñ=«Ö/>Áÿù½…Î}=92É;iäT¿²Ÿµ=²1¿ãŠ ¿\ãl>(æ>c׿Ø{Ú¼ªå’=òl’> Bc>œü=„L?>±<¾ê@õ=$º¤=æ &>!R*¾”#f<Á´„>€B>â=wq†½pYH¾ Ø?Ü]Á¾²>}m>LÕ>«ÿ¾¾”ú¾¸ï¾x(>-²x¼suŒ¾Fõ½Zo ¼ c…¾9˜¾Î#ª¾ym¹=ì¦s¼–wé=­„d=2 >¬¶½?†½µGÁ¾óz&?kÅ ¾â+á>¡í¿… S>Â7ð>ú“>x�P¾š�³½M17¾gø�¾›õ“<ü�Ó¾éš{>…M@¾xÍ“½ieô=‡ËŒ¾uoϼ9.ˆ='ò@¾ãÿä>ò�¿(Mû>¼¿ž½Mµ”=Ä }¾hæ¤>è2 ¾á=¼.í> *¾uNž½Ða¢>P8>N¼>ØÏ”>â˜×>�2 ½iU >0�Ò¾E#i=õtÈ>€ ¾$Wd>>|G=UL>úéË>”䑾}Ý >±â?=jÆ¢=š—=ýúÏ=Ó¿FÚw>óÒ>o‘¾¨ð®¾çpV>¼·™=í7—¾Y͵¾Mf™¾ÿ:X½"I{>&¿ ¾´Èî=#*?žB%=]Ÿƒ>¼ùG¾Û¡>¶ƒ =ll2?ì&§>Ãpp¾Å�œ¾Y¿g>™¾ÖN’¾ovS¾ƒ¥ >Än²¾Ù~¿µëÚ=ã²¾üÇì¾OÅÄ<4®“>ž†>¬VI½ðû.>¦¼‰¬é=ò”Y>’R½ ºþ=PD!>ñá+¾·×»= i„¾ D>v}>4þ½X¨õ> �2>ûÒa>}m?(¨y¾Bò=p⻓¸>sbl½Î]¢¼†)E>´]â½È-:¾™Ð0¿N6½ÁKѾ?¬’=J¥¬>êXžÂ[¹¾õ¬¾Ÿkµ¾ÆX ¿|T…>xQ–=8¢°¾Šês=aöõ½ï}Œ¾J¾k!á¼ g†=i®j¾¬s>r ͕’¿a>ÁJ¾ã´O½>ûl>оœD>W×4¾Š�m¾5’¾âÑž=R‡Š¾‹v6¾�Ô½@Š;>”éå>¿ÚÝ=¡Y¿-`¾bK>On”¾ nž¾¼—>›½¾âŒÉ>¸XÀ=ij½8:¿ »ñ¾J½?�Õ>î!¢¾ísu¾nM ½ljÈ>¡2̾B\œ¾‡Ô2¾G'=JH–¼#æQ½§)¿7½a=�‡Ä>û;>ˆzU>|Æ«¾®êÖ¾ŒS?>ô¾öZ¨¾ªx>øî>X£=§*Ø=„h\>v€8º–ž3¿Rº‹¾G¾ÛŽ£>Ïã0¼E¶{< Y’>Ý— ½d«¾�gÞ{·>@ÖŽ½s�ç=AÈ6¾ÛÙ›¼(1?ž a¾œ“º”fk¾Ò�¾N5>Å�þ=—äɽÌ�T>Ý‚>©,¾‘‹Æ>pÿš½÷â€=#E>ƾ>ÓP=þ�ؾ)¼!½e€ ?ê,>³Îþ&jñ>{‹c½R>-OÁ¼m>ZŒa>c††¾íéB¾~Q|>s£Y>kKÃ=à>Î>|¦‡¾ý›¤¾2[2>M?‹==}»ÇH£¾¾$<Íw¿b‹Ì=o³A>€³>Î_—<h®=Çûª½™v‡> ó¾ƒR½µ¼¾1–½÷èv¾ß‹> óx¾ž§¾VJÏ>õƒ=3ÔÛ=¡ôÁ¾ ïܳ¾¸¦“=‹bL½©Äj¾ã¼=ˆg8> $…>4úç½À½÷îŒ>5gY=8¹v¾Ó�C¾…à-¾ F>PU^½÷†¹* ›>w ¾ŸÑ‘¾û†³¾`�M<0<ï½)b?¶10>[@U>`9¾|’m¾›;û½$L> Õ¦>÷™¾»Ñ澇)š=€Çú½\½~>.þ=.Ư=µ†M>šÑ!¾áΈ>² «>Wj�=ô­=’ ”¾ô�Y>1»½>yf+¾75‚½•»¿f?7>éñË> •>¾¤Ø¾ü¶Å¼SØÇ½@¾Pô ¾“G»½Ö°Ù=?4I¾óî¼¾oé$¾dú[= ž¾P×Ç>rcZ=Þò.<›ª>¤d£¾¡ÖP>pDì=ÕT¾2+¾Kï<‹Ä‡=ÝĽ9t?�Kp>ú2>ôS>Œ¨á>o0=[ µ=2½…=Ï1�>¿r°½�»»> �¾ý,R»wGÖ¾£ãe¾qH›¾ÃdнÖR¾»]¾’$Œ¾õ5‘½»¦½BöYº˜ñ¾¹ ù<`•w>f•µ¼T2S>Þí¾Had>\P^¾çâ¾>'±^»›×¾‚[®>4–&¾3#>tYz¾ˆ~>çp©>íõå»—>rc ½�] ¾.G>ÔA>Qˆ‚¾³k¾Å'›¾Ðë`½Jø´>³ô|=AVÚ=o0e=¤—Ÿ½j¾â=ß7³¾—Y=,–>h÷i½¢9‰>-ؾ'd>ÖÈ>d]9>«#Õ¾©`«>ŠTS½Å'í¾“õí=6äó=Îùæ<–^=a >‚b%=;õd½>ô>%Ý•½Å¡g¾Al®>iE9¾†W…>»_¾�­¼è¿:È9½‰ïf¾°©/¾¶˜š¾»A>Äêb•4¨>Çkç>úÒŒ¾9˜‘¾ùÒº>2�+<ñm»¨À̾=�e¾Ø¾K{½îŒ•>– >?ÿϼçàÉ>¥o.¾¥—=Ûæ€½c±>˜ï´=,ÿ‚>žÑÛ=t%®¾lš¿Ê­ºüžM=1&°="z„>è—¬=É.—<žóa>Õk0>I‡;7‘e>€Ø<íãÆ¾:ó½ÉŤ>(†>üÒ’¾"´¾ëVO=…H=PtY>Þõ¾9`É>a~í¾eÏà=þ ¼â[¾�^(>€lƒ=rÈž>Ž>ò­ >¹lZ¾üÕæ¾2 ܾz}¾n!>]§I¾QïÇ=Å]’>—ɼÁˆk¾‡ò…¾¯™]¾ø~> ž<È[Û½ó'ˆ>�AH>oš¾× å½þZc¾ª¾e¾AµÂ>Èe¾j\„¾8$нº° ¾­½}¾Š¬‹>–‚c>nÂ=ã¥:¾5jÏ=©bç>LŸŠ=+á¾[›Î=gãŒ=/?­iª>Ö.Î=5àv¾›Ê–>wßæ¾ªØŠ½Mª÷¼!$À¾R ½ X»>ë—1¾+—¤½Ï=Ô =¨Æ>=0ç¨>DX>n?ʾ¼3©½çŒt¾S¾0)î>…öV¾‰�N>窗>t¼=•ßv<•Þ]½ ý(½Ãyß½!$Î>õ0)¾aNe½ï"=(0ÿ>Lÿ]½¾ãâ¾é˜>�«¾»½¤¾OƉ=Ö,=ÿ:¥>N]‰½}u>ãT�>÷©‰>à޽@O ¾Ëò;Ìxò½G~>=îe= ²>°•¾«>^?]¾Q, ¾"s ¿G9¾aàŽ5‡F>\Ÿ->ΈÉ=£ÂŸ¾:æº=1Ú³=2Á´¾[˜¿3/¾½M W>œ'³>+4×=êÜc>°�¾¦>aª¼âym>†\ö>UþÈ>ÏmŒ½BX>GÓ6=’þѽ¬d£>Ñ–E½l0†=�€¹½½CK»ÐK¾%mœ=Üd ½6¤?½Í Ú½vxp=‹‰¹½…ÊÚ½�´¼Ù7h>ƒ=�<–p=ï®>eìè½Ê A>–d¾ 4¼ù½öÔ¬;óÔ„¾?ül>T‡“½TÓ{¼Ý‚=z”¾„q¯>�¿N=lj¾ô”¢>Ê‚n>üª<¾a¾¾Ð8‘¾å”B=yÓÞ=΀¾héñ¼«pc>YûS>Ë÷½¹ÉÛ<1G/?r¶>aÒ)?ƒÐ�¾Þu†>Ú^D>.Æõ¼Nž>ªUº>9Õ½ü<½‘œ ?EIV¾`ÐH¾$óA¾ k�¾‘¶<¶—?ž‰<Á0½4¼>Aõj½g”\¾i†>Æ|Ü=í¹�¾†ö¤=MÂÀ=;¿ð=É%ñ=£‡3>â’¯>Ár>„j–>‰Ì>`ËÄ<˜jP¾W·ü½pÉ´¾sG#¾XÆM>ͽ©Õ½¸æX>&†¸>hå½ø¼š½lÄ…>#åæ=a…>]0=”>âYd¾$¨=UåÔ¾­™¨¾ÁØÜ>~ØW>-øž>‹_±=Í*}> Ø´½OG˜>}}�½é&Ú½m§ß>å*½^½C>b7 ¾pˆ“¾¼<Ž¢l¾t�µ¾B ‰>3+¹¾Z†yºÛ“š>ÏAZ¾"5ª>;p޾X¥»¾š`>¡f¼=K}‘>÷ͽã-¾šJ‡¾×y�=óí=�ç¼>.EÁ>�ò¦>·–>ñ3½½=6©>Yƒ<ž°>¾á2=ìQC¾O7>iWµ¾›f¹¾$§¥¾n»¾ñ&>¹Õ�=’%q¾H�”¾³jD=—²¾Ài³½F5ú=t_¿š&ξ‹I¬¾+î> º>ææ¶=Çh;¾I”À½p¦Ÿ;ü0(>|§¾„ó“¾|;¾¢¯š>õv&¾ÞkÙ½Û­E½+ÙŠ¾%½˜>^kz¾µ-œ>‡éî¼9¦Ÿ¾)lù¾m-徎ž½]Ÿ…> C†>xoé½ÖË>ö�½ P�>’¸º¾‹7õ<­Y ¾gäQ>ò¾™ïb>Yñ>[ãE¾­(¾ª§¶=·í®¾w¦l¾Ý”=Ãßc=mÚ>Ç(¾¾”³½òg ¼¹Ä´¾ á½9Z޾ʘ̾‰(Z¾£c�¾uRž=ȇø½“<-?Bp’¾ \¿=,1%¾P‚Ô¾ËÔ<¾¢Ö>÷WB¾Ú°ð½ XH>†Q>Þ=±>*õä¾–ô=ˆ(â½ëâ>t;æ>ß°¾¾dRè<¤€>¸ ¾\ž�>^°^>ûHù½­Ê¾ÞOk=¼†w¼®¿>ꤞ¾ÃâJ¾çëx>Ju~¾­h?g*³»µ!¾ùu«½Á>ê½H}b¾K±®;Î]I¾‰x¾ÞVs¾Üç ¼É>²½î»„={¢õ= «4¾[p=Ÿ+¿õ¹×½Zc>œB>Úª<=z½?>ªë½ ­=¤3¾#;Y>þQ°>§S¾xÇ›¾1ÔϾF×¾#ñ×¾¼ƒ>D½mDµ>Ý!«¾d”ž¼÷{Ú½qÇ1¾y?Ó¾_K>ê8¤¾Ôqó=’¬9¿þ%¥=L ¾¯+Ö>å[޽ø²|¾>'x»äÝ ¾@R‡=)8¾d«î=ËŒK¾àî?eá3½À€½ ©:âè¬=ûu2>²é>'®~>…>»½ø[x>7ºö>Í&a> ¸½y;µ=)‰ª>¦Ï¾LM¾!86¾–ø6¾¹3Ì=$1<ôšL<‚í½Mk½‹ ì=èk{>¬q”=m±¬¼Ñ.R¾º’„¼ßÄ<ÌÀ¯=¸ ¤=þg>&Ã(›¯=LÛ“>3™/>l¥ß¾ÎB>ˆ¯? W¿È+¡½—×½Š~²¾AFœ=55‰½å?<€Z¾fà’=fÀš=²g¡¾àËW¾¨y¨>QkÞ=T—?¾_·½ÀÍ ;@œ½’»¾?ɽU¯€»³¶7>¯=’¾¤w¾bÀ8>0ê:¾Mþ½4s°=µP¿=I‰ý>Vì¥=7œ®¾™¸¶½cÆl½/R”>øk=þ[¾z¸¾å¾o¾E\5¼vr¯>5Y>Y˜Û¾ð?ëGc=ƒF¾„Òè>W©ƒ¼G´î½ß�½ZϪ¾“úμ÷¨¾ï”–>Åh>£{€½kñ²>¥Ú�>U‹>;¨W¾º¯›>þƒ¾íÔ²½hŒy½p9Ç> † ¿û¯�¾+uš=É# ¾Mò½l†½øS¾"n®½>ç­¾] ͽ‰J ¾I–¶¾�¨¯>ñTí=f1=VŠe=KZ伉ۤ=ˆû½Žfÿ¾*¸0¾—`¾öµ±>8>ÜÕ™>aj¥¾žœ ¾›¯Ú<† Œ=rb=û1•>¨†²>M>úb¾Jé >¢DÓ¾Ö“>ÚÚ¾>žµ½–Q>ŽBä= ‘½sšÌ>Iû´¾äTN¾C¡â=Åì¾^fK>0¾l¢É½1_޼iÆ<¾,Y7¾¿:Ò>3›�¾ÿP>ß­ä>ðÖ,=Ëgº>ÇÝ >ƾà0k=ƒnï½L—³>n뽄NÞ½GǬ=*Ë¢>ï0> ½vlˆ¾"Òµ>e?z=�•¼ä°D>Ø>IÎ6¾w >F­(¾ï¦ã>ú¬¤>eí<Ò¤@>nÔp½Ú¹>T�ƾ·—8½ßå¹¼ÅÑÐ=žeå=¬ç>+H>ŒÌ[>%G>üé*¾(Õc¾�Ø> §m>#[’¾Iù�¾Ó»—¾Æyƒ> m¾>÷‘¸¤ÓBº•D…½YI=„X±¾œ­›=07Ý>ÿüƼlö¾lèc¾Ý:‰=4/;GL1½AÁ=IHŒ¾=ZÁ½xc|>:’¶<©\ò¾Í§Œ¾ÒmU¾ò‘i>·)¾ ÌS¾SïË=ºê8=¬ý¾$b¼ˆñ½lë =”„‘=4Èn>&@z½"õ¾×†Å>ÌZ’½ýˆ>p¡Þ½ëv\>c˜>œ:ª>Œ3¾©]>ãÈ�¾vÀ»>Wê§¾]—§=³QÞ=[z/>WÏ#?ÅÍŠ¾ò<Ï>¸¾#¾q¾ûqe¾[>T@è=`»Mü^>ÈóÄ=ýýhèF>V »=”!.¾K‘¾+„ ¾oô¤>K<?°O¡>„ˆ>ªšÚ½ÎÇ¿>C�>æ¥,>o»¼HÝ«=›ïl<™ùó»YT> ™)¾Óhã¾|–ž¾lOϾ+P¿ÃÓ¾çœ6¾! `¾} ï>Éã÷½Hó=kõ%¾óÜ>HÉ޾꒽´’½±N;þ<?—�>]Yi=½"Ì=?l°>Œ©*>Ç}"?…Ã>ÄA"?þ >µ ¾¡›Ú> òµ>ÿÒ:>³|Ó=´‘ˆ½ù<ü=õ䌽�‡‡¾'­½¾Å«[¾VÅŸ¾Ñô<(2È>DþB=‹û¹½Àš�>åAÅ>ùÍõ=[Œë=oU¾8»=é g>µº–½1Ö%=³rÙ¾ßG¾ß1¾Þ™;•Ô½ÞJ!¾1æA¾ÚS¾�´h¾"Ùå¼ä ?,±Î>Ø5¦==“½`>k2i=VCY>˜PÙ>üT¾Õ �>|½F¹=Z Ü½šÊì<Á–«=ÃØ�=¹En¾ù¥G¾Î”¾ÑÅb½€8>5³>ÀV¾‚ko¾ÚÃ^>p£ >˜#à>ç#Ý>1 =Í(ɽlx†¾ž€q¾Â|o>msÎ=¹Cs½˜õ½jàý=°/ý½®(>»<|vœ¾\«ž½�6>˜é=1¶Õ=Ú@©¾ºO;<Ö¾ÚHâ=>cƽ"åâ>˜¬k¾Ή¾8k„=µsl=‡ ¿+½`AB>l4t>~––=¹Ä•½÷}·½¹Ü?¾æ¸ß¾¬›†¾Um¼-š>Ve¾¹x?,ph=êÌ?¯Ú=–°â;Ü’\¾ë»ë=��x¾u7…>Œ�=>î*ü½Ú ¾ììø<2C>U¾–>'Ô�¾¿/¨½¯:ξõ,½{ªÏ=>cè>÷¦¾Ìôl¾ƒóƒ>¶¯¾u„>¾<:Ñ=|)Æ<�.ë½,U>'R ¾0]¾-x='‘ >‹¾�(‘¾‡.>ˆÇ¶¾“Å>ly ¾Zèh¾aó=!¡n>\{Í;dˆ&>RœŽ¼[¦Ä¼oô޽{•\>cz>ýiL=B„C>ðkŽ=~h½=I̸¾ô>R5R=YrF¾ˆ€ä>¦6¾È´¾ E?MÏÐ>‡¤Ù¾^$'=ìm&¿yè¾õ霽 ñû=YÜm> G¾n=2=d¡š¾È“˜½ó9ó=M¾ðJ¼ v >fð¼§x�>wW>PSʽÜl¾·K¼lÍ>>´ï×»ü}‚¾Hý^½p§/¾0Îb¼ÝMоrò ¾Sd@¾<�}¾ 5>õpB¾•B:>XÕ©¾z&�½’–½·;�½˜ag>­`3<*AW½Ù³>ƒ<7¾¸‹ƒ>ê@>¯Ø­¾¾Þ =šÆ ¿È a¾b0›¼¶$„>ÔÜÔ¾ÁÔÙ>$L¶¾dø=Ѻ콇' ¾‹Ü6=n¹>Å~¾ëéÉ»Sˆ›¼“¦*=ãÒ˾+âÌ=�оbÑ>)®‘=íÅ>Z �¾KÇe=™U÷>ÛÀE>'�?ßN»`g‰¾6¼Ì=N•?LA>�©Z>¨éó>ÎMR>(Ü¡=y¾úK+>D¨v=Q%ß¾{1=OÓ.=Ô!€¼‚޼ò> Éj=«©¼Ž<?ºHr>.(?=œI¨¾4Kƒ¾¿hJ>¦¨¾×÷=+CQ>¨ù¾}\¾š2¨=°QH>E5r>~÷½*ÌÀ>À߯<Ÿª >~¬5>"eÙ¾â�ç¾<=Ä=Ë”>ÑL=Ȳ)½{H?¾TpÚ>4‰Ä¾îXÿ=‹¾º‰S=£ž>Y„E½\P­=×D>I_ ½�˜<ˆè—¾ž³–¾ûé˜>Á\ººï¾�>VX<·�–=¤°Ý»•‹|¾…þ-U?¼:¾|©½�¢)=غ½5”>w>¢p4¼]�¾ÉXS¾U凼ܤ½[^O?�Ðs½�×¾oÜ=®ü<Ì1Ž>¾2Ê<¦tž¾¬Uò½e¡¾8Ãù¼°¼È>�„ >ÝÈ‘¾Ç>=�b×»q$ø½?ξj @=[b¾î >>d:¾Œà¾°¹š¾'ü–½©æ½HŒ>ÑS>óú†¾jýÓ>Xð½¢ØÜ¾=‹*¾ÓŽÿ<·f9¾g2>Ô6`¾’$¸½P™ˆ½¢‘ƒ¼û?¾ä=± ¾èZN¾pº>yÊ–=�˽ž¨>Û…<°#Ž>ÒAR>É™>’Œ…½Åa¾=¶<7¼c½èN >VDõ¼s¯>{¹|;¬’R>’-¾mû“>ÁÔ >pRF>bØo=õ½÷½·¾=Ò‡¾§”Ä=o©¶>½ŽÜ½ÊI5>gOv<Ƹž>&Í ¾Ž–U>T…•¾‡Y¾ž‰y½•Üá½– #>¤ø�½rg€>q¾ >µ¾}E1> Q*¼ Äæ={ð�¾ÃkM¾h±½'¾1Ë=SÔ> HÁ<ç¼õ½š>ç½P~K¾ÔÎh>Š–½=²>€“>Nð ¾=�ݾ×ô0>X?>,G�>•Ö˜=“S?> 9Œ="d¬½˜Æ½¸D±>/vL½iVv¼ÁZ>W°Z½§�>2€>iœL¾óç¾¾¾#¾ÉI>F¤¾‰+jÀ=¶Õ*=ÖZo=æÁæ¾/Øä>O²¿¾ ž�¾h…~½äE¡¾/La>Õ%ì>Îõ‚¾üñ�½%sнð'¼=Ï=н=Œ¾:G>Àf>=š7¾¡™>ª§®=ý{­>œt¾¬¤½Ï½t½í9ù½†N#?ÉÑ==#hȽ”²¾Cߘ¾kQ‚½ªAz¾O6Y>åùð½ÀŒ<ö’?ë$ѽ÷¼…µž>ã9? ÒѾѿ£½~G¾ÿZ†>$?¹>E~¡¾v ¼‚‡ä½5p‡=âHŒ½,à5¾åV@¾ÃÑ »ô+X¾æ¬Ü¼m¸I>^77½�ø�¾Æxò½­ÎZ>nK>~Ùø=óm ¾r.¿”¿ª>ÓÄU>{#¾Ja§=Ál/>œjÁ>ˆp†¾~媽¢‡L¾ÅZ±¾‰ÓÞ>Çþá¼)í>Vu·¾FR½¾/£Ì=6Ún=°ØS¾†w¤¾»µ|½Œ²_=•|¾YU¾"Ú°=VWµ>&¯{½ß÷“=?Úb>j~>ú|ë=›®M¾H²¿eð=È%?|²~<ñI¢=ò^³=1ÆJ¾ *½Òçq>rÁb¾Š»ê½ ŒÐ<åxž=²à—¾ÇEk¾²ÀľáW¾d3¶½ «‹¾~dò¼#™¿®i2?Kƒ½ ]<½×É™<­Ú2>u±ù¾{^ ?OÎ3>� w¾½z½àº‘¼~‡:>|)‹¾ Ò¾Nèõ½>B»-º‹¾yÛï¾{χ>äÞ¾q¦•>cŽ.;³G¹< §¼=W@>ÿ�ý¾é"¾!Åä¼Ç0>G–Y¾úoν\×�=š�m»/ªŒ>^¸>$ì<,û+>Xµ¡½¸þB>c:(¾{Õ¼{NB>|¾a>@6Ìñ–‰¾�'â½ØÊŒ¾W‰¾E�¨=ß(p>þ >Ã6y>IL>ž©¾�íº>+1,¾IrÇ>W‰<Ë'¾ŒÄ$>ˆT�>Z%2>9Nt=�·Ë¾Ð-e½€‰•=«u¾ )½²E(=õI¾ ã½�˜2¾-G»ošï¾:J">rã¾¢·¿Æ¤Ç½ ”R¾^‘¾6qê=èS!>«ÿ«=õ`ɽL¡’>«m›=ç{;¾l3¬½7­Ê>ºL>€ü‹¾ŠÂË=ΰ}¾Cª$>�k6¾`-ѽ!;§+c>uW,¾–—Q>´P½ŽÝŸ>JîL¾Žü1>9ýϽµn”¾¾M¿½Å‚…>„i�=B‹Ý½£<>±”=Å`t>ö–º¾*›¾Hç¾N³»>“(�¾Ýb>K t¾a-¾€Ùá½à/c>bŠ>>²«Ï<èÞ€¾îYÎ=î“>1…$½¯2d¾œÀ@¾H°p½ÚM²=·d„>s@½Ñ �‘ª=¦8>„¶= úA= —‹=&Ál¾¹A\> Ý >ïÒ¾ûý´=ChÅ>–üó>´.¼ÿVÀ¼Lu¾}㓾ԥ9>F#>j·’½µšŸ½nÀ˜¼ƒ9—=äY¢=o,潃@>´2í>§Rˆ>\Ñè=g~£¾S ¿¡‚G¾›û]>EÃ#>‘­‡¾º#ú½˜Çã½²í«>¡º¼s F>Ýѽd{>p—š¾ÀÖŽ>BÈ>E@·>“2Ê>xI�7l¸=¹h•¾ˆ¾.£–>çuÁ=*ß‹=n"ó½$\½ZÍk=Yƒ“>R¶=ˆ7¾º>m®<Ïó¨½ú¤™>—*?gG=üf�¾Ü½«7¥,_¾è÷ؽl¤E>ßC >.©½-.&>“Ïó¾%éĽ-ª—>®±=„Èq¾Gyà>C#>òŽ®>§�#>šÑ˜¾0þ-=%hžIü>ú¾Ÿ=Ü  ½nØÓ¾ïí?íã�=~M¼1¼ ¿ß&ˆ>™‘¾',ª½?ðV=ê¿Ñ‹¸¼§ËF¾e6Ú=fâS¾®[ܽ`û-½2�¾”T}= · ¾hØQ¾qH¹½�7x¾=³½b×Ç>á׈¾M'Á>ªQ=îKØ=Ÿöi>Ý ™>)瓾¹=«1>³Çî½À�Ý=ßÓ ¾#Ð�¾ßÂ(¾Ä2漨ôB>D+¿Éø2=) >ú.¾õ"ô=Tò=<Ùb>5Âa=Wúd=)ˆ>!ûË>�Œ¾Ý>Žr›>h ô=1û�>íÞO>PP’=i+<»˜¼ƒ½î<{o¼8z=>øH¢>Pn>*œè½ç>|¥½‡ Û½G®&?db‰=Å@=Rao½wb=7O…>Bµ,¾—ç°>ÚÆ‘¾¬õÛ>9dì¼*¡à=Rs„¼@¾÷6�¾Ö«¾ 77¾r3\¾qý¾ž´#¿™¨’¾ÿDŽ=ì™Ö½“>B]Ÿ=WYd¾¥…‚>Úh>g½<=ž>Û$×½xÍŠ>4ðP>n ɼ_dÈ>µ%¾2´R>ŠªÑ¼ œE¾°Ín½©Z>œo�¾É¶½�Ý=íý: ›¾ù:.¾�œs¾¿ë½¼Nô;íµY¾Žâò½½°w¾º‘&¾iÃ?>ÛÇ ¾é+`=§‚R¾~¿¾Û¼=æú3=àû¾"_½I)Ⱦu—{¾òŸ=ÙœA½=Ð:>±@b=²´I»41j=Tœï½©ÉW>�CŒ>vº)>Ôƒµ¾.Õ¾}c�¾½Hä½Ý½ˆ_Ô<¡¨«>›½ <>·`=ª,>RU¾utk=e¾Zl½¶——½Sƒ»<­g½"Í> ¾G¡Ô=÷’ô>R9X¾éË=»Ó!½ÉC> êj>·ƒÒ½Ç ¿£7¦> ��¾+S=&S>ê>«<­ÿð½ò!==  >ç—Þ=Ð[Í=÷C¼¾Ã¨>Ùˆz=ž W=FG½Ä�˜¾Nr,¾âÙ½t•¾�¾}>«?ŸpY=�z¿ ³‡=ÓçÊ7Ûq�<ö@Õ¾zö¦>~¾ìe‡»£lv½Í$“¾G>AÍ”¼«ÿ¾ÊüO>3vd¾Oa <[>¾?’>8v¾w©ß½IiÀ=nÍ>.]Ͻl>R¢�¾hØD=O¦É>já¼¶ð%>eŠ1¾3% ¿+2g¾Wq¿�U˜Ì�=±aC=#Kž=Ý¢c=¬I>ÿ¼ê=¿]¾éé¾ox�¾=€û½ƒÄ_=ûZh¾°Cõ¾ûWv¾­IO>KkȾԌ?¦�ž>Np_¾Áÿb¾õè+¼ÔZC>¯ýP>ŸK>‘W;¤£ ¼·pD½+¬>_I¾ØÏÙ¾ani>·¦¾Q%>ãH<¾^±h>qïš¾¨÷ ?w’ª=æDнڪv½Ã®³¾5=î·ê½˜�÷»eRõ>©¾=Æ >5ª\>V&V=5ÃÅ=ŠCå> &­=Õ<£áÇ=„d>½½”U=Ð×M½ÿˆí½%6B¾ˆÛ½âM>ƒ€1> ¢½ÇÓÍ»ùîÞ½:§¾§‘½� Ô¾ÔÙ?§ œ=”õÈ>0yH¼i. >â§®½‘gs<”ìk¾æéÀ¾|ê¿F^^=Z">1¼ >aÕ€>i�<½Ip>«57½ÿ' =B¹ =ø©æ=mW>¹è¾ÿk½ŸÊ½•½0½õñ =÷¾·¡è¾à¿€¼äûú½lå¼MÒÅ>È­?¾Á&¾fÚ©¾|g1¿h² >w¿y—¾žß²=h©=v"½ßÄœ¼Éu»>"ä¹=”Ñ=ƒ¯°>YW–;vA‰=©C’>ôáu¾¼Åýõ…ì¾±A˼xç?–2(>«.‰¾|#¾DÜ?žì½jg¾7ʯ¼‡zÍ<e…¾&¾õ‰µ½·Æ»Ótû¼ê;X¾�—?G(°=é8ѽFp¾P°º¾nY¹=Ä" ½mo>/â+¿0mœ¾`(À¾d® ¾–ѽžu½?½½©YË=þl×=s3]>®Õ彬÷)¾�ê$=>GŒ¾"Þ¾¼Ð4=~lu¾…ù{¾l¾®.<šÀ“>^î�½ëR°>†nâ>¼f½j“¾ b†>­Áá¾¢>þ ä½Á¶‹¾pQÕ¾±u¾�¼ô¼ýÏ‚>èȪ¼vQÌ=–-‚OÍ‚>É=Yâ>ù¹9<¸Hy>‚;>Piê¾_ü==}>ŸÉ?jÍù>ôL=ÒªF>1®„=¨ÒÞ= ¼^[=çQd>Ž»Y>¶bÇ=mªU¾½Ó´½¼�¦>ºœ=)Þ‹¾¼Ñ™½b¾ÐmP>‚ã¸>Rß¾w˜>|é=ó–¾EþÄ;�³Ñ>Ÿ?>¾E¿¾;ò¿f>¢a>•A¾ÿž:ƃ¿=d”>>Gü>Y¹=¾�;ÛÌ'ú½™@š¼ÿ]0?޾‚à>âþ !>™lD½s¿>mId>ÃI¥=d3Q<~q=Ü'›¾Ü]™>›ý8¾ÏÜ>Ô~>5Ù>‚¡K¾q :½‡õ;šB<¾§R¼š÷½.žÆ¼Ÿf ¾„õ±=ða½{ü€¾ �U¾?[è» ľ1:'½ £–¾V™é¾ ?¾e„¾ŽÝ ¾ž&Ô½,–Æ>MWŸ=wɲ>ùl�¾©�о¨Jù¾æ‚‡=&¡h¾bî½8�¾±È>qоáÖ=AñV>M×�>%¾H½ÑÓ>ä¡Ó>F>콯®Ý½†æX>¾…”ºhÎ;½¡ý¶½ÿüˆ½áª¾à›§>wo)¾â«ðé8½ åC¼(ùQ>ltz¼s’Ê>ÙcнH—?=;>¨ÿ½Ç>>=ö÷É=$m>3¥ë>’Ç3½·U½œ8€<_³Ò¾FM>z>Wí8>�|§½ã0:>àE¸½ÿÁؽ,OH<Äe >–ÎŽ¾0¸½ãÍ·=¨'½¹�¾UϾx5½­¢®>Q*M½ô\7>쟰=ûu ¾Wof<–ͬ=o៾øúù½íwýõÝ®>Ï ¿@Hí¼l¶>L}œ=ÂŽ#=Íñ‰>Z·³¾©u6>·V9>ma'¿…´Ý>´>s‡^>ƒÇF¼”§½Õľ2—ß¾M5>¢%½:®¾hkP¾æ„]¾i�о B>4FÉ»¹^>)`µ¾M¾€¬ ¾ë°«>æ�>&»?>Ìâ<¨Z¾Oþ>«ú_¾9Ìn>7B´>Åšõ>ܺ’>ã*?I"º¬á_>jly=¸Y¾*Š‚¾çØã9Œ*»½íI½*>憼!M ¾}U—¾1è¾`Ùd=×`²¾õ_f=¦š*½0ÿ=þH^>!®$¾‡¨Ÿ½73»¾Ÿ“½ÔÍ¥½wö×=»5¾:sÃ=»c>OH¶¾-lj;²RÞ¾§=b¾vùž<"qD¾Âço>¶Cù¼�>F>®t°;+É ¾Ž ¾ˆøÊ¼öõ󼉼Π¼J)½aX>$‹V½âÄ‘>%=Ì«½ëmŸ½jG`>|â<•$½IKy>’â�¾|y»½JsP=Þz\¾ �¦>äÅÏ>kE>ïµÔ>ö7¾NÍ4>“ƒ¢>ö Õ>ãòw¾§¢=ó—>‹*/¿íR‘¾�è•=vOܾö ¾-dƒ>×˾ÕèÀ>G/n¾“†�½?³g>Yß >0e…>Â!”=‘s¾(Öt>»2=¦Ib¾ÿø>¿±>Iº1¼ìU>Wn½¿ÑX¾‡ST¾'‡=Òò�>/`u<“Â2¼Ê `¾øíþ=Þ†¤>ÛÓ·=¥Zí=ZÐÙ<%<ë=6˜¾~‡9¾*î"<°">àP¾9BM¾gá„> Ûõ½ª¢C½èè¨>W{Œ½S! ?·!"¾KÁ¨=Ÿ[Ž=Û>ƾù¡$¾°Ã‘>œ¥à=ç&̾€!¾¼cL¾‡4m¼z™ >Àó–¼y²Ô=³±y¾µ·H¾)F¼;s®;¥½¹½õ?t¾J ¤¾n°i¾¯)l½(Á¹¾áõѺ.B>ziÊ>.F̽–ˆC½D묽â÷=µ­< £¾¿ÉN¾ÿiW½ÔL¾ñ:¾®îäºU"M¾«×›>à$O>AØù>mh7»ÿÂ>v\´> ¯Ê>ñv°>Óá½<)>KÀ‘=tÝ—>dù˾ùb‘¾HÜþ<+ö8>ÚQ>§̽‡Vê=Æ�½>•µÖ=9П½-¾¡ \¾¾C¹½Ÿ1¿�¶Ù½)Ö=y“þ¾²ž&>mþb¾õìÉ<Ër¹½í¾/ü=Û«�½v½zŽ�>ýá>ŽÂš¾û�‰¼¨p8½mþ;¾É«½1à>åB>@‘'?Ža»¾F©»¾åµ¼Ê“¾|™>ï"p¾8ä#<ÚQ…>|罋›`>ꥬ>€æ¾#MK¾h…=‹È¾Ì’¥> AÚ¾FfP¾n™>–­›>¿ Ѿ—~º²Û{>¶ÁŸ>†>‹Pß¾ž¾Jpö>•]}½a™Ú½!¸E>ª«>!è´=  =Ñæ‘=j¥n¾�z> ¡f=ðuä>tõ¾m㣽º½C-Ë>@MÚ>Zˆ”½ËúP=ãÖÙ¾î œ>k\½„“Q>úšª¾z¯©½t¬�½~§¾ÄÎÆ¾N;C¾ã:Z>çï¤=´ì½ôø >c= ¾í%¿¸4‰¼7}®>I祽ÓXµ½m)[¾½>ÌÔ>-‡>o;š>8iX¾R­¥¾P›©½¬\=\=P>t€‘½ï‚>.fƒ> ø>µšê>•‰z>äA?�mÒ=ž£J½Ô=$?U ž½n>³>m§Š¾ ž>–sÙ<ß#‚¾í ¾´��>ê—¾‡´¼ ™¹¼üN<�Mÿ=ô =ã…�½pçk>œ¾$¾þÕû¾JçU=ò§Ì½ß…z½E¯>‹ö`=H å<ù¼÷<Ý]k¾¹'>Bo‰=ÅA}¾��E>Ûä¥>u1¿b­¹>SžÎ;X(¾M*»¢4®>Õû?ey»¾²Y[¾= ?V|›>4n5¾.ñ÷=g¹½ A›>ÜvDóÝŠ¾Ÿu>€ñÑ<=eñ=êpоnä>Ø”â>?Oò»~„�¾7nñ=ûyf¾ÔÜм@Ô8>âå'¾§3½‚d^¾Ž„£¾7 Ž=~>�½Võ¾=gÞ ¾Æ,¾±ö>'ƒ.¾êÙ>0W¾]lξ¦%>©ðá½­·>)šÑ¾¸²„=Âáb=ßsB>d’…¾t9¨=”H <o¾>²]s;qÞ|¾~«,½ë%¼+ြú¢>ºë¨<�q…¾´A±¾}…h¼)’)½Ò⥾È_>h¬¼>€ ¾Ë D¾“�H¾k T=ʰ?Ec¾sú'¾_ܾБô¼=�"¾Õ[‰¼%Šë={Q+?…£ì¼‰¾|"P=»Kr¼M>7^÷¾ýg¾>’ž¶=-Þû=¢ß½#޾4‘=#>L¬>X¬H>F(<‡Ã6<ÞL¦¼ 1 >Íq>Ös£¾ /ü>À%{=üľ„H�>‹šÊ½ I¨½U¦¦>E‡�½ùð=æ1k=£Y¾êxß¼1â=‹C6¾y*q>ðËí<Œ;>¾îÃ>Lç™>SÚ̽ó8°=*Ýã¾›p¶½Ïê¡=dõµ ¬~B´›¾¥ÿ;¾ME‹>œt�>Q&Æ=]O,¾†Ú¦>�­½sY·¾o¡Š>\Ðʼ‘¶¾Ùs¿ñÀ–<"÷®½vÍp>uÍø=¶(ò½ 9ò¾Åcø½ß“–=Jk;¾—>…‡:¾#0>¾‘Ô#=Ey ½_ÌP¾ß²>¢Ð}¾Òìd=Wþ»e|‚=�ŸÊ½§Êß½ûæ&>d¦?‘H)¾ŸÃ¦¹…e ¾c«¾<–=HS)>V¾sb`>ìÀ½=<š ¿atÖ> ]¾µö ½PßG>ø5ä= Ø«¾Ç‡$¾»Z÷=^ �¾¬+¥<•½*?l¢ù¾rÔ̾nM><]>jáü=��¾Ì˜L=mŸ½*SA>�N¾ò1Â>¾»Wξ˲À;� ¾Ï¾¤8|=M(ý>Æùå¾>Aï>¹!O>»�J>ÐŒŸ½Nkã>(J�½®¤Ä¾þV>lJ>–è=¾ç¿GÆ>I+>ó:‹¾oß�=gXɽTº2=öÀ¾[?¾öÖ‘½ÝžE¾­2Ú=Óÿ•¼|\‡¾ í=R‰9>ß œ¾üKy>x4¾Ÿ³>ä?Ã<öÃ+>ü�¸¾c±Z¾É[Ý;ͦ-¾ìù¾2ûá¾O_ѽBhp¾°ŒÊ=€*ü¾žÃ:yœ¾z)=ä y=(‹ž½ŽZÏ=$x>Y‡>:´i>fØë=®ü}>�L¾ð¡Ž¾ÝfN¾ÕÝ+¾Kß>ù�{½á¦–¾Õ½Ä¾›) ¿³èj>ä3à=ÝdͽX…ļ\^Q>ìÓ:uT=AÚ<[H=>MÍu¾}[G½‚yº¾ºã=Á}W=+íb>]8Ƚ“p¾~`¬=Ñs}> Ñb¾Å¾Aܽ>¦¾ÊR˜>—õ?•*Ó½ÈÏ‘;¢×,? Cü½ÇÅß=ìu‡¾,³¥½d ó¾Ÿðê¼A�Ì>`Ýã> ‹©¾HÍ¿(Ë>оŽ >ùÞK=S§¾Ð‾Rq ?M«¾aÛl>ûxï>ƒãÃ<m–¾=ó�<Ÿµ=D¾>T!"¾ªt+=v=(¾ÿî“>x»J½TC»TËO½"Õï¾Åî¨>ù6_¾c½¿Î½•¶Ÿ=§oѽZ% ½t4½®Bï>Ž@S>BÂÖ>¿¤q>�7>ùl<(�꼓áÄ»q˼˜•†>�Ž>š¡z¾ÛÓ§>í»¿½I&¿‚ †¾©\!¾Ï5å½C A¼�`>rá€=ý–5>+þ¶ÈϼÀ  >Z8n¾bã=Æô¸<…Ã>ÿa=2Þý= JŠ>†«¼>Šm¿6 Ã>\.w¾Ù—¬>Ð'Ê>‰¡€Ÿ¾§µ >&¾IÆ�½?ñ´½qÐi>»(£½K b>¾>¤ï>v²v½}5à»]k?õ=:>æv„>ySß=Û+®¾és¡¾{Ð@¾™‹.=”hé=)R>�r�¾H‡¾“,³¾†=Ó>?Nj¾.>gNž>¿‚)<Ø}Z>]÷G¾Â¦Þ½»~¾˜ãY>Ú7>@�®>Lg= A>éËÔ=ÃN©¾q’¯=Tn4¾u$Ÿ>ÑéM¾Ë™¾ :>4>MQC¾œÄ•>ò‘[;ž£Ä½ Ú¾£ ¾¾l=;w} >;w»G¤c¾²˜¾>—k<W(>S ä½l÷½=Í=Ú;½hü]¾ÆÀ¿º->¾tåú=¥hÌ>%b@¾W ¼¾”6¾²m£=V5¿¾I‹>?�uͽ\1Š¾Þ“Æ½r·S¾H¯‹=2l³¾öÛ>V8�>†šÃ=ë)>¸9>Üáî=¦‰+?áÝ"= -D½H̼9üË>ß¿›=€`/¾ö[>ÃÕ5¾ ½v§¤¾Äk¾õG¢>:ߦ½jE&>htÇ=…Þ¦¾Ë\>LGû½à�?Žm»òê=ÈÛ=¶{š¾gô>@¾Fù=ŒD>]è>²—d¾!z†>¹ÃŽ>>Ñ&Ž=7>>d?ƒ>«¾Àä½3YØ>Àߺ>³û;nð>ZG >¨V˜=V Š>-Ϋ>IO^¾]æ½1ôx¾1OܽüËV¾öeß>Ž}+;'¨=jä¾#"š¼/.Á>Èпß:ó<Ó°«¾¤„ ½úÑ&>æœT¾Ã<¹<û >약�Œ>8Zˆ¾ÖþÛ<Ú©¿6è¼¾.Óƒ½Lu ¾OËv¾»ƒ¿¾}­n> ¶â=³Ë>¾13¿$Û¾p-¼3zs>¯r¾·>qwŽ=’&>áQ`¾ž&`¾Ü‰Ÿ>Jç«=žY‰¾Ù€€½×狾–�ð>v<£>v¿ó¥�=Q^´¾·¾ª©û>ÐLá»›r?~+¯=† “>b1Ǿj¢”½±`>¥L¿®ô\>óºŸ=29-¾ñõ‰¾Ýw#>·Ü¼ٹ�;ZNq>Fó€<>྘Ó=F`¾3¾Šªš>%–¿~ª¾Î‚Ѿª¦=Î[«½ûÝE¾;G >˜F2¾i„|¾(ʾÜv¾œ½¾¨4¾'̽<�Ä>6iþºF¾Ñ¿}½DýH¾‰ˆ>Å�€½wB ½Ü|¾xS=X`ˆ=½tƒ¾ñ=A4!½Xš½¤ì†>H¼¦À�=fí>£“â½#Ù>’ö«¾½Æ#¾·½È½À4Õ¼°¶ì¾àÚÆ=[ôi>‘•–> Ó=�¦À¾øÃ>ÐÕ=Én<7�½Ö>ùRU=aY‚>Á» >…æY¾”xÌ<Õ•P=„ w>pVK¾+�?…¶->n×&½%xâ¾%ç÷¾ásš=Ñ�>´)¾;ƽ‚Ô;>Ñ-ù>q<==–w¾ãmê>åϼÌáµ¾èÎн¢¹³>ÐÇ<|LÊ=!ÜD>ÐÖ¾¾“ à¾Þ ›>ä¸>­÷Å>À‰/½{Ó´=r‹Z¾Ö&K>þ·¾e¨>(8¾ä%>]륽1i>©/ż�Õ)¾Èö¹=¨‘(¼\·=ý8 ¾ò›n>hëš¾K�Ù¾:Ć=Îa¾¸jD>' ¨>‚tB»zi¾X@ë<Ï>Ó& ¾�î;ãÕE>m×h>�3¾QÆÀ½ÚÏ^¾&¡,¾zWu¼Ù΂>ÎâA>{oN>$^´½D?Êä÷¾aLô¾Þ•˜¾›K ¾¯¡Û>)ª¾¯¡Ý¾² :÷{ ¿åN>©Ž^>¶0 >L½Å=qª=!íš½p(¾&νÛç¯hS—½tª¾B®Å>Y‡±>¿"="Æ>î@Ó=;‰"¾¥Xh>™À=„)¨>:=¤¾Zß½Ö¿u¼ƒó¢>è�Þ½!Y„=l�>ºq,½ö-€¾Y~l>i¦=ã·?¼w¾ÜàѾo~>jž�>™9#>Ÿã�½s§ ¾Œ…‰>œн"#»½É½r=Eî;m•ž¾¸ß0¾Mƒ->ÔíϾëÎÍ=Ùk‚¾XPº½ð‰N= ¡O¾¦]=üò—¾ÊV >Hô¼>‡¼>îÌí¼?ò”¾A÷¯=“ŸÚ¼¼’Š>�>ºo‰¾'ÿ»à˜Â½gôü>¥»¯=Ûþc¾µ ¿ô„˽5«A>8©Š¾ÜñW¾ÿp$;5…h>#ü/罤ȅ¾WJ¾|Í ¾09>2…>¤¿æðb>@Š>zÝ4>FB¯¾yrö½sçY=�ã0>r<°>*©©>]¾Ò‡µ¾kéª>µáõ½GTZ=�b•½‘ã >Æ/°>¯>»+¢¾ À?á|À={4†>ÎI?„ +=²ï>ËÒ�½1ñ¾ÕM¾Íã{» }8¾¬F7?qý ¾^ü¾–g¾�+c½ìœ>й=IQ–>/#´¾ƒ"Š<ÇM¾‚M�>Ð…½jÞ&½î<ë¼ˆÛ >j‘“¾{ƽC¿1¾¼¦¾Kg¾ÿ¾ ÑÏ;çb¾ »¾àÙ¾c „¾…½6rZ>HtÊ=ÏZ½z–¾9k =D½C¾v­¾õ ? 4`¾¢Ã.>ðd¼=0@$=‡„¢=v‘�¾N>¶?Ö½·[‹>¨Âˆ>÷ŠŽ>®®…¾Žö>�{T¾ìðö>�OÛ½ÉÚh¾Æ¡¨¾‚Ñ€>“�ð>e@•>‰¼?¾¤°¾Î];?ÓJ>ÉWž>¶n#¾ó�¾üZ>×À¤¾w>Ó$¾g¨½b ð=çOɾɣS=±!>'{½ZÕ=^1>hþ½œrQ>Jr?=Ô–¥¼D‚¾›Ä]=húæ½Ì$<9~Þ·>IvÀ¼P£Œ¾bZ´>PξHˆ¢=/Ý`¾â€¾”ÓP¾3¾>¼qq,½¾Ã»=ó:¾åŽ£¾�-¢¾Ù¾t7ÒË1¸½Yïè¾4D»=Öñ½×–À¾_4/¾ÔE}¾ôaÃ=±˜$¾Ïš&>¶’ݾöš½ßzû½O¯>_�E>­^‡¾óv<Ð¥ > ºî>¤Ÿ¼c&S>à>æ=Œ›=¡��¾¢W?‡¢ì;¬o¾ùžß>?v7¾‚AÂ>ìé?xëÙ¼§g¿lµg¾Sè8¾!›K¾ŸB@½=ü>>…¨¾ŽÐý=Wú=$ý>£ÖC>a;¾©EÉ;ü«/½‘怽XÑH>yöý½÷C(?/vr>DNµ> ?îû¾•©a>Ø•ÿ½ZK§=–òú>ßM>�?'¾)ÒÛ¾ °= ¤Ï½á­ƒ¾l“¥=•`ƒ½šå–>BÁî>ÖÃM=-Ÿ;î�½ŸR�=Ç<¶>­ªu>ÂÜý½…2P>^ÌJ>ì…½‘’@½@ÙŠ¾o¹½€/ø;+W=àÙð½®Ln¼A$¾¯M€¾¥`r¾Ü½>®^›<îN=Ùq¾A#>É+ɾڥØ>c4n= m±¦i+¿4Ø<È”¼M”T>Æt'¾(õ >õg(>Q½µ¥¾Õ¯¸>\¢¦>ªæ>hi•>-¤=>ŒÉ-¾6ÉÎ= e==K¸¡>³)Ø=VÞQ>—§�¾%�ξƨs½–õ�¾ A¾Ã¸> †¾µ€=щ�¾r"6½7Ì=yÈœ;Ç™Í>aÛо»rc¾¢ŠQ<¨qh>hß#>ÿñ ½[ìÙ½]3~¾íý»ÚÊ%>5ÑZ<¸¾úÇQ¾˜Ø¤½Š7'>«&h¾pR_½>©>+�>.èã;Øä>7ò‘¾ËÄ–¾`R¹½Ó(‚='XM¾x0F¾A‡¾‘ØZ>{Å”>‚ �=wås>¨r½ß1!>±º6>À—Ú=–²=®÷=¸;ƒ¾Ûƒ0¾€«¦¾D/‰>�Ô‰¾lÆ<­Ç\½ ãÀ¾œq:>�{û>µ)‘>?*‚>(௾…O¾ÉQõ¾öø›>I~º;ë>R=¾F&ú¾êÈ<ŽÎνúƒ3¾M °=ër¾99„¾Í T¾—?¡{ü½úÁX¾™–Û¾™Æ>…× ¾¤O5>O >»u,>ļ>9C¿]%´½ýu>%½-Ÿ‚>7c·¾Ã¡¾LTà>ßc>‚о+Öu½¡?­>‘žI¾\üO>$º½±{"=k,’>Eô ¾”½€è<-×§¾ÅÃö=­÷==xŒ¾L꾈ëM½»E ¿�~Õ>µ Ÿ¾Mû¾ñ…²¼R>íÀ{¾Àb[<`ÎN>%¬ä>ø>l¾n >d~m¾zÛ•=¶–ø¾ë >¤¾t¾D;¸[¹=å¼ J¹½d S><ùq¾bÁ/?*+>–t ½o«?€›Œ¾8M=MQð½{’•>xÒ¬:‰ì>½Cït>,$³»I!š½×¾G>Gæ•»PÏ�<…Ÿ(¾^f<• Ê>=Eô=‰VK½7ïƒ=#À˜=ŠŠÓ¼uy½‰{?’Ö:¼[0h¼] ²>}…&»¡›Ò¾Kð¯ÝSø=¥É><­s>ü±B½oÅν’yu:=I‚½UdS¾ûùœ>-—½Œù¾VB?q©>BX>¢H¾ñS˽©Ò­½PPV<ŽT½ÿÄ~¾‘ø"½ï,ü=ǘ>“…Z>? š¼% «½±Ý>˜l2¾¶ ¿Y�v¾jt�¾æ¿þC'?ÌÇ^¼²ëZ¾¢n¾Ã6¿@#3¾ûåÜ8@µù=M4S>ÖÖ½žÛ{>±Ÿ·>«fc»ÑmÆ>P3Š;Ô€”>7>¹ú=5{ñ>á/V¾Æ[‚>IA„>Œ#½ðX\>¨õݼ�þ–¾È´¾%TM>(}O>Ókܾ„ɽÀ]c<ø%¿gÌï>’Ôg¾Ò”à=´ù¾Í� >âp¿…4¥>Øã„<¾[[=øk£¾oà~=i¾POV=`ë,½�Ë˽%(»¾`Ù½<íÌ>”�¿¨›= Cl>1&z¾¶ß+¿ñÚ;Ø<�> Â>Žìß=5j¼[ú®>.ú¾X¦s>ñ!�½2V³=wÕ¿3�@>cþ�½ƒUŠ>A;o>98ô=à‚š½ p½¤ˆ= ¸*>±¢ù>‡¢:� ­>°¦=�šÏ>Ý¿¨vÔ¼ê`3=Œð¢>·5M<ƒîɽÄâÒ½RªC>( ù½V–µ½¿¼?>sÕѼ€“k>¥LÉ>Œ<¾¬/°>¿)�=ŸbH¾á»š½ªÿÿ½XXy>:„G=„¥c½ï¹¤>Ù†M=…xœ¾Ô>Þc½Šjѽ~²U¾9Z¦>s >‚‡¾Œž¾qßý=ò*Ò½ß3>j�Ò=²D�¾å”>ôüÅ>íݽ@L²=~±´>°a>cj¡¾ü#¾À¨Ã¾=ÿ6½Ã€ƒ½´½yGm½Ö!š¾xÀ�>[¿h9É>0`>ah¾ÕËá½,Aæ;v°Ï;™˜=Û>©%µ>çþ²½äò;u7>«¬Š½²èÝ=8Ð4>QÙ½cË@½<¨«½r…â=^¤¾Y½gö=$Gº¾0=…½zËÿ½ zt¼²=Ø™>ó“s=Òw¾ÚpJ¾Ú:½¦âµ=ô½Í�8>~>{ñ>:±¦½¿¬¾ýJà>´«”¾ ;ƒ¾™®]>}=¾½U�=êj =´è ¿îºƒ=âËï¾b©”½XÕ¹¾�>&8m>�òt¾Fω=¬aÂ>÷Ϭ>-¢®½_"v¾C§¾D‡A>ÙÇB=Å4Õ¼ '¸¾].ȾÞ÷×»�{>ŠkW>n €½)ßJ¾^Ù >Nê>C`?Y>0þ—>�ˆÜ<…X½-ν½l¯‰¾òHT½�‘é<ÛBŒ¾AÀÊ>Îv?§’w¼Òçb½£½­>bsW¾�³ø>1¬å>ž¶>-u‘¾evX>m ƒ¾ð‡Ö9ã98¾þÙù½Z µ>�M2½ê<徿S=•–À¾ü±¥¾”™b>K>?'18¾Žœ½€W£<¾Ôî¼Ø�½×²Ò= Ö =dó>K(¾$‚½_ò> ]¼U G>†Yl½J#à<Ì+¶=À½l:»>QªŸ=¶·T=wÏ ¾ÏSš>Ž—Œ=Mñ¿Iðˆ>9ý‚<+ð >“õ=Uå+½mJ™½F|©>: ¾Œ—–=í��½à¼É¾Ÿ‡ž=Ý追ð]¢¯Ñ½´{ >ôá"¾–=ì+…>AB,¾£ä?t?³=£ìŸ>Š>•<¨P�¾§ÁÈ>½~¼D¤Ï¾Œe*½}¸¾Ýw¾XÕª¾­�˽éuj>¦Õ•¾º•<E�>rÒ>ZG9G:=¾��ľ¨€$¿⾫-õ½Ý;>À¾P>£ìF>†T•>´âؾž½s)•>üiN> 5‹>˜ä²>‹Ó³½k¥Y¾Ó•¾ÔGÙ½ï^K½¯�8>«z>T˜¾~b�>sïj½Éû ¾]-b>ñ2[<@“+¾‰MÁ=6¼<§i®½M�'¾ž¦¼3�¾Üý‚½ªh�¾Ú+¾ÕÜýË=ù…= ° ¾n»€9¸«·¼+Â�>7½9µ‹=ž@s̽Ešk¾Jü?LM >¿õ I¾ _>¤_y¾bØ!¾¸½†‰½ª”>3¸ç=Y?C&ð»ÂÚE¾‚3ž¾R¾½=Ï¿Kr<¾lþ¨½8­j>wñ¤½…Á¾þþ¾>Z¨½©ÃǾ26&¾�•¾1§P>z"Á>ðúý½¿M>>K¬´=Ï<@ª¥>^{e¾9Œ=¾ñ‚>½Öq=Kr=þwþ¼ÅD�=˜Ý>k[}¾àé¯<>5>F.×>•§Æ< Œ¾ ±·½å®¤¼·O¾«û=ÅxÔ>â¹áŸ¾­�>°74>Bú@;[, >ò,¹>�^ù>ú�?/«™¾ °$½¬¼?¾Â¨'½•®¾¾­¬¥½�ò·=¤>>Tqí Öz½©åâ¾KÖx>_Bˆ½v[U>-ˆ/¾æɾ€>•g=ƒš¾ŠÇ,>d”’½ë�°¼sºÅ>i¡c¾~,’½moI¾9øÎ¾eøÀ¼Ÿ¡ê½p)i>º&°>l=¬=“6>Oc—¾´žó¸ç½�‘ø< bÔ>™nµ¾p¿;.Áy>û=õeæ>l»> –ú½Ël >÷Æ ¾ç; ¶ä½V¿Ê½K[0=-A½O쯾~j8º½ŠÉ>l7Ë>ø¾?Êd½2–Ê<Ú± ?yÐ>¾<¾Ä�=!­Æ½raѾ9•¼Ù=A½&~�¼ƒü<Y¢> Ù¥¾`�<Í—¼ï‰Á>íh:?úÚ¸<4€>)$¾óÉŒ>%RË>_³=:­Í=Ôþ¸>«â޾ý†$=f‰á=Íg¾�Ã\»¶ï‡¾¿âм&—a>c6e¾…\¥½ìø¾xs¢½òé:dñŸ½þgr¾Àð¾½»¾À³Œ½¾ï0½;ó÷=òV�>eŠÂ=UÕ ½n«`=†C_>ÍSX>R0§¾–YÅ>@3�>èmø½r\¼¾*«¾ .—>Hß<¾E(¾Ö•¾Íu¾rǾ2À¾Xd ¾«¢‚<™�¨>‚‘{¿)•=¾Ës>› $¾Ì5¥¾lzH>”¨Þ½Œi;>Ÿ€ý½tµ7=S¥¿xeñ=F³·=Ç –=xET¾ªÀ¾q)>¶"?Ï3°>ž>q¾¥n?þz¾®—>lîø>L`š=Ûì'=$3¾>Ð=½Ýö½ê{ë>l@¾¼»>DõÁ½b-澤eª¾ZR>ŽˆÛ=ÑwJ>`á>Ô<8>’Ðþ<ï¸Ã½»õ>1r¾8—ß¼¯Õ>�4¾ÑÄê»OSh<÷´ >¦¨¿"mN¾˜X½Ùý >*þ½­6¾q�Ô=í£¾–A…¾„Y…=ž?U;† Ä=€ Ç>Vk(=Σ!¾o�å½ß¸œ>r0â>ûœÚ½d[t¾#‡¾–½=y,Ò¾£;>Î?FU€>5Ñ??ä#½iS¾JRÌ=ã܈>¯S+½Á‘?$6Ö>²I¾fU»=�[í=Ìwƒ>Dw`>@¾½œν¿u>„µ£¼rºõ=_u˜½h:Ͼ-¸­½/×½�F;=™5¾¾¡Ì�>v}н¦Ñ»¾J1=¬žW¾¼w¾thÎ=}=>#ðM½¥á ½ˆ¨)>ºtå>'Ê ¾ŽÙô=hU©½u†>M²¾È¨x>¢”޽íÄ‘¾"Î=¿Â‘ ¾Êk¾@b¾œ´Ù¾ ÙÆ>èò½“ez>ÄNs½`Îë¾�sX¾}޾°Œ~>P–J=Ã(¾s‘w½+C>!!±=Sµä¾Bgý¬2´½ö°—>ï¤>Ó¤Û= Òu>ÅÁ4=‘Š9¾Àë`½UR}>H*>RëQ½ÞÛ¾,}Æ>*¼š3 +¾Þ8ƒ>…)¹¼ZvÌ>m@>]êk<†Ý*¿ßë½ÚC9=Q½¾€Ä¿{¦>²Å¼=âMV=óX¾â¶¼¥‚>c»¾£²>®W=Âùu½«º'>JŸ÷=h3�½»�>‘€¢>FK½¤‰¹>~i>úOC> Þ;>ͽ=@dÈ= 3ͽAG¾ì¾ù&7=£W= �¦>&>Ýi½¨ ×>Èd+>òçµ½iZ¾U¼s¿]¦ >ücn>ýœã=n >¨‘>ª¿~µí=Tò�¨½ �ù¾ãD…¾› å=/Ç=]l„<3d=G{н´”¾ªŒ—>L_¯=ÛÊ=ì‹O¾äñú¾Úr0¾§tù=†x¾äî ¿jQ¾Ã#ô»¸¡ ¾ ñ`>¼i>¶Fœ>f!�¾«¹Â½0²ˆ<‹—¼„`Ÿ=Šè ¾­OŠ=ÞÎ >ï:Œ=u¹=6”£=ˆ½“=¥ H>í1”¾¹�¾{ªˆ=‡" >Ê\F¾èbT>5#æ=\úÉ>i“̾o‹>kw�¾}Ⱦ=Gf>TÔʾFØ ¾†m ½ý‚¾qP¾4 3¾��ª½ æâ¾†x½®‚>ìªç¾hʺ;1 ó¾Ûñ ¾¬,Ì>3ï¾&›¾S\>*—>kŠ©>¡¾>‡ú_>@–X½œŒ ½Ïs¾“t`=;¦¾Sd÷=„ù^½ª <ô�+¾²W{¾â€ú½At½¾­¾é1Ê=ò‘¾k ‹>ÞNÁ¾Å‹¿½ä4¼"k>kb™¾È8 <ù Ý¾–~¾}JÀ=† Á=^ˆ>Çó¿>0r¢>�R°¾vËÞ½·î½ ‰¾<}È>•7k¾œ¬‰¾Š¾Â¼å¢3=“ù¾o'£¾{Ÿß½Pâ=–¨=Z.?®'¾é9>t5æ¾ ªv»ó,¦¾$È>æçK?E‘ ¿‘½¨`¿}X>:"L¼éQï¾0ý“¾Ê ½nî=*mÇ=‡í.½ðÝJ>¸_7>»¾°{Ê>¦¬G¾÷›=½b½â=+ Ñ=Ūp>Ìé?W +¾êLN>ðÈg¾cHɽ«ØM¾ß¹¼ê„ª¾GT¾Š\ô=/Ÿ¿|Kô½‚¾Æ½!ò‚¾ÔI�=€Ë!¾t¡ú=OY ½›Ô=‘óÁ<6³³>Ï È¾mê½Kª¾ßºÃ¾}³=ë£e¾H)H¾È�L>jÄW¾ØKœ>·h‹=ãã–¾¤U>ud«¾æµÚ;B•5½µ.%¾–N>’69½•½$>{–u½!W1=«:7<Ëx–½bν纤;üË[>‘Ù¾Äx½–[œ¾B/=Pö=œ×Ç=º!Ô¾šª>p8d=«–> �>ìKY½à ¾ ½Ó¼jh€¾(µ*=zJ…¾­Îñ½¿™É=‹-½qX ¿ìÕß½=ÿ>j÷¾§?=D˜¾t0à½ûvó>–a>ùÁ¼>Ø{ ¾SØ ¼YNÒ½®P¾4i½òŸ¾¾;¢¾‰1Š=3u¾IS7>ͽÌ>š¾àª>¥y>^ùM>C>€¾šã=YzM¼ë‡|>?|º¼^`¾mÕ¾[ïÀ¾Â/  C•>!½)¢Œ>amq½ôU*>ùƒ¼>*’輂==îž¾{­�;±û“>.‘x>LC>áé>:Ç¢¾qòé½ì!‘¾Â=tÅ‚½V*¾]Åß¼úì*¾þ¬>5˺>E=î=¹QÙ½ÒG¹¾lzÚ¾ÖWÄ>6¾LX"½' ¿æ{¼”N=Ed¯>ºû·>½Pæ>ë .¾íÿe=翲=�!Ò½/‰L>Cs@>/ Õ¾>⾘´ >ñâ >”]¾G"«=ƒWG¾Zôâ>Ò@ü=<Û½éqc½ö²O>¦'½-ì>׸r¾!dн?‡>H ¨>L¥Ò>‡@‹>ŽV¼\Ƚk¾Dî½®‡A¾T«<e ¾ æ�=x™£<ÛŸ›¾e¯€>J�?2É¡¼�æç½éy=46å½tý;�ã¾å^ç>’•™=(u>D&¾`»½xV‹¾h] ?¸9ܽk!™>Œ%>h^{½èÀ¾63×½mF¼½8¼K>쀄> ò¥¾ Òs½} B>s%Œ>ÑMè<”†¿Q½„¾½CŸ>œŒÄ<ÆFâ½]t‡>IE¾c›>ÁÏÌ>ç}Û¾q?Õã?*s5¾Æt>úM¾¥ºµ>^Š¢>ÇÛ<<“K<yq>Çw¯¾|!>›™E¼-`w=µ�?kÜM¾x#f>�,>.¬'>†oA>$Þz>ÏJ?žÏa>œÑê>Ên$? s¾Óðƽpb¸¾æ�_¼h\“=éË=tä¿H¢y¾¨jª½4Óƒ»}Ñ»¾ªžµ½’fA½N‘W¼a¾OÅ|=¶²Ñ<'�e=½®B¾Ym>()‡¾`¡Ü=sé…=Ë>œ¾v¾HÝà=¡.f½¶Þ ¾¶xà>¯á>± ²=­D¾6®Ÿ>±Íñ¼µŽ>±Œ@>õi—¼¯v=Î N<�Á>"Ū>øÕ1¾®¾Lžœ½x™>u<Ѽ=̽…›¢½3Æò<ÎßžF`€>J;=¼ 0ù½5iø¼Ó×¾–+>xn>Av¿o®�> ¡ˆ½ܦ½F¾›9`¾` ">Z×¾ ñë½bú¾ÚÆš¾Ì—¹¾S=.ül>FÁk>Èq>A/g¾ßüP>è$?‡1´½L§L=*-‹>7²i>øS> èÏ=¯Ð”;Ì£w¾G®½'Û$>–F;½Bv?8`Ï>}†™>G�™¾ În>¨fݽ‰.4½Sì>ô~ ¾Âø{=GTn>5I¬¾ˆ69>GšÅ>ßâ¾)L>݇½>±ÑƽvØ7:·Qý½Ü8²>k@€¾0Ý>âïÓ=¯ó;u¸>ݲÕ>¼í›> H[½/Û�>Vß;>œº >«Ý–>B­—=ò>^ôý¼ä�N½0 ¾8äY¾U�=¦] ¾‡o ½ÂV•=V½ˆËë= Ì‘=þ™>½¥¿¾C6Ç> /]¾ufº=K>‡‹¾}÷ä¾T©~¾ýp=rû>á�Ê=á’>]b>eSÏ>z´Æ¾B€ë¾‘k¿KøÇ=ñsÖ>Ѱ.¾�õ�¾®›4¾ýR'>ܶ¡¾�3Í;u—â¾%�¿½�ھĂ>òZ=éýŽ>a»—½„ß•>­æ¾™ ß>蕾 ÿ|¾�›Ò>Чa¾™¶­=, z>m¼Ó<—†½EÍ>ðΓ>^´X¾Óؾ½,…)¾eƒ=…È›>P²Ÿ¾™“¾<â:¾Øižºsê“=ÿùö=%+°¾8†¾Ôý¬¾“Ï<¥k¿½§Þ³>ÆML¾5‡H¾Qž×¼% ½T‚¥=¾Š’½=@.’>Àw{=„Ô¾pÿB>2 O¿_ ¿d(Ë>¼ȽêÅR>œóª>k¡G=ª6¤½´Çr>‡ ‚>ɔѽSXk¾´†¾¼‘%»¢Pø¾�}¤¾­x‘<¥ª÷=zÕÀ½ªS�¼™¤Š¾ˆþE¾¶¨„¾ÎÊ.¾Ý–?èóÎ>â¹¾F-ü>€½>Ÿ2¾£m>±ÜK¾{!S>‚É=æŒÞ>–>¿>NK¥>':¾üƼ˜6¾Ù¤�<0i½_ã= 4ñ¾dÉk½×Å•>ªb’½>Û€=BEC¼ ùõ½s­¨>9"½ÏqÔ¾Ýï†=¡ ˜>fL==õ =û“‡>>‰¾T\¾½@¾Dº¾]¢;‰¾§âB¾ 7‹>S¾ÏžR>4#?>-ؾvx ¾#ž‚¾·•½<îu¾eºº½™OÀ¾1�¾�°ª¾€IÎ<À…�½mëU>’Á§¾ûû.¿H…>=oŸ½[%¥¾3Ñ…>³×�>ûm¾Oá ¾•Ƶ=þŒ<ýD¿·ÒÁ¼Ò+•= lX½Ãõö½93Ÿ½øú=@<½5€¨¾gç: °;¡¡¾ù#>Jâ3¾�h�½© G¾ ¿}½Zß½'&d»©šÍ=¾Îó.<éC«=ñçF¾›ŠR¾4¸¾ ³|>ä6�¾îÀľË">I‡Ø½"ã >e¼>\î�>Óbë=:Êp¾+A²>(–¢½œå›½�BÁ=ŽTF=9ø>•Vѽ;§«¼°Ø¦>7;¾–j->&vH?<:A>B‹ª>%Q=¦]Q?ݾM4¿¯ñ¾8惾Ó_g>„_e¾é+ >‚ŽÀȽ£Í¼V=ó»R>=Äb¾™mÐ>¡¡f>ð([¾×“H>,>Û½%о:==µ¡¾CÛ€ºç œ¾æv)=œfƒ¾À÷•<âB¼º´<¡«Y½/̆¼†œ(>®H>þe†>ˆF¦=JJ-¾L‰½v‚ü>f˜>°?u¾ÕŽò<ÆÃ�½`¤½™²½!m¬½‚zµ½MZ¾+Bn¾ ÌG>įW>>Íí¾¿š»z4&¾ð1…>T”k=¸ï—¾Áº<(¢„¾}vH¾×«Ý¾ZÅ‚¾S°¦¼Ì[×<B©¼T¢�>ié ?ç„?* D¾ÁÙϼ)o=™ft=ÈZ¾}ìE> ô6¾ý¶y>üü…¼=Ãf¾\Z=ô辉Í<"‡¾h¯Y¼È§¿‚ê¹>_;̽â4l>^�À>§Ê#¾Ê%F¾hÌ>ßÛI<4: ¿•æ™=½‚¾<Ï>ÂTÎ>‰ŸG=™A¥>Þ>…>’e½x±«½¨SÛ¼Vÿm¾7 §=ÊTÃ=)®>+›{½ä¦´>¿”½„‡>Ÿ!¿÷;ü%l¼ÑÈb>Õ8ã=4G�>ˆ<�¾å²±=æÂ‚>GÇD¾Þš�¾ÿ}оL?9�¾îí«>–>›=Ľ€½!bò=Á°n<¯”ô=Ý呾²¢ª¼ÊýE´ù¾?ô3=ÔÜ6¾Ñåû>íÏV¾î²½ŠŽY½�0½ž>é†�=“㈾JŠò¼¿ê¬>÷Q¥¾îi˜>~©¼yƒ<Ì#G½"éŠ>fHµ>8 d>ßÖD¾‡³ª½Uµ=@}e=Xîþ<ˆ ½�°½BS(=éo¯½ò$?"ð¸>ÂÀ”<ƒ‡>íSæ¾DzÚ>Š› ?Šk0=bß=êjz=XÆ=º«=8 >gr¾1&Õ½^7œ½ Õp>å‚T½{·>G­%¾q6‹¾ó8>qá~¾Uãf¿k¦´½æ…½Å:‚½úR‡¾Ãf�>Äæ®¾�:}¾3ú ¾Ÿé <9áG¾M…@=q)C¾‹Wº=’'оý—>ŠÇÙ¼ Ø2¾¦Ž<¢+I<àKˆ½öÐ=>®x‰=Äso>³ES<�ù¾TVU>Кá=EäO¿÷G=½’¾ý˜¥½ÐV >+¢,¾Í·¾]´½mU†<`M“½ãZp>Gk„½ƒ'νJ|Ø»8;–¼ÓÝž¾,¸ü=Ü“U>•ÖŸ>kÝU¾WN‡>„_6¾»Æœ<èÜý=©Vâ¼nh¼m.>MRö¼ƒ&|>,ãŒ>®e>4w>){D¼%]�= Ö�<Ñ…¶½4¢>DÝ»l=¾p˜o>²:„»>Þm=üʼ»¥|> :x> v€<ïýi=NÛ>Ÿ+¾Þד=õ�>i~>ѢܽR(‰>µm€½Ü§¾e>®½<ù,¾Ø=�˜‰¾ÓgÁ½>$ ¾?ùu»qnq>=fF¾¡Ÿ5=‹Êd¾Oç½÷�¿ ”©½àº¾¾믽ïèO=Ü´ ¾Á0Ô=‘,¥¼Ó:Ú¾~S>ÕœI¾l¤Ý=‚¬½‹,ѾY/2½“uú>�ŽÆ=é)ѽê�¾‰â5¾Ç(¿==¸F½ѽøm¿¾ož=>º°¾¾'>,ÿS>üÁ>³ö<åÄ4¾ÂÍÒ¾  î½.Œ>�`ʾØ÷=½]�J=ôÛ<>ì1>®Ô½Ë.>cÃ0¿•Í|>>¿J¾Fâ7¾{ñ>Îvâ<—">±TÔ< ›<=±�™½ZR•>¬6ß¾€ ¦½¸ËὈö²Cú= �c>,õ0=öÍO¾Ì¹Å>(ø)?S§¼=c¦f>Þ‰>ìJ;»´BÀ½º8?yô½‡ŠŒ>d/m¼›¯½F×´¾Èpý>}õ=©Œ>·tŸ¾wû�¾5Žê=Ê­=‡jx¾Qd]¾BË=¨v¿½F£,¾x>nKÎ=X°<°è?ã(>„N•¼æªq½`f°=9ǃ½Ì“r¾†þ=…Rõ=HP,=Þè{¾_¤T¼O�9>ÊçÌ<ª1ó¾G ¿ô®1½¯¬">é9=¾O:½9 >þ°Ù¼½Ô>اQ¾¢%S?Ý¡¾©çò>D$e=v ©½,Öû½,/¿ü·>á—=V×£<&»ð="±ß½þMe>=ñ<7V¢>+Ò¾Ž ¾á{? E@¾…ž>B›Ï½Áq�¾´2(>,?¾6‰=×Öœ>rà°¾ØbŽ>Û.½–�€¾Cû=4æð½Ÿ¤¾ �Z>Ò¶ß¾6�©=w-A>:5¤> ¡f½ï–¢¼EØ>Ãc ? ѽ›½˜>t�æ½ô#ÿ¾Õò=¡@ >8{n¾ýjû¾Å=¥=Q?ß’0¾…”¬½4‘>ä‚ì=‡"&¿t²h¼ßþDWT¾¿½)¾`e ½VE>Hy¾4¹P>Aç‰>#A>$ô¾ù´>÷7¿¾‡×!¾œÊP>Kju½Æž¾FÍv>FZü¾Ø~[<Žƒw=9{>îØK>äM¬¾î÷›>ö·÷>x9> =½BïØ=el¾¾Ž› ½Uy<÷ZW¾ò 6>LyºÓ¢÷=] ä½VL¾¦¬¾©«.?&¡ˆ½æ�þ½ …`>9Í2—¬=ú�¶½œ Ó¾#F¾(Z¾u–¡>Ï5;¹Q`¾0>>o «¾3Üo>$–ƒ¾ÏRá½5T#¿05d¾û>·yÍ< öT>\òÀ>�˜x¼T)K¼ëÄŽÝȪ>ÚûŒ>˜)¬¼ê\=™Þf½Ivò½ID—;;]¾"€¬<õ3 ¾àȇ>�h>tå&>’èÛ¾HðÚ¾óù‡½ÿ}<½!!º¾ ÁR;Öð𽈰¨¾ýš…½SÐO¾9Þá=G02?iÊ/>â„9>+> Dl>Ù"a¾^¿¾æ×‚½7í¾¹=ush½®j~=›°=Kx¯=ÈQÒ>l羫¦>)oG¾ ‡? ¤*¾¨ ¾C™p½¹$¾áj%¾›�1>ÜÊ1¾ h¾y|F¾8“�>PF�¾ x ?~ó½è8>˜³v¾fÂÛ½ãú};¢XÐ>J¾™„p¾±BÞ=cWÀ¾–†>«Q>> ôž¾\ @> Œ©>Ýß¼m&ˆ>P/L¾q•Û½‹ûH¼›õ½�ð>³ûÔ½EO¾¾BÈÔ¾Àvì=%ø>F[¾Ú…¾rúŒ¼y–Ѿfó}¾Súr>ZÃ$<óCÎ=j]<½Ó¹3>gÍÐ>à¾Êz?AYU>IQ7=Òþh>d`¾¦¬�=…(®½œ_=An¯½9E¾%2>è@œ>Òýßì³>]#>ëý¥< ¾a¤»�\)¾šŸÑ¾ÊÚâ½W_ ¾ý k>!1k½)ñ¾Ä“¾¾à)=C�,¾ûjG>Øö?>/©’¾>Þj¼ 8˜¾Ç�ݾâS<’‡>:Ûb>ÿ9n½-2½‹ÚA>úñE>t‘;(%»ÌpU=µç>=о@m½õ ’=×¢>À<¾ïÒµ¾Ëk{¾À«¨¾bŸÌ¾Ù‰l½¯¾‚¼ZCؾö ¿e÷_=: À<%Yœ½›Ä)>’àg¼Ï!>a¬`¾í<¥Â>­Ý¿¦RD¾W–¾·tb=Xra=8v´>Š9œ<‚�>“Ž=¾x>íš’>O ?^T÷¼\«> Ñ>Ç�À�ìQ¼ÄnÃ>‘µ%¾y0·=|“>N’>þ¨¾ŽÔ¼S÷<Ú¿»¾U§>±>zÖý½´8b<�L¾C›¾›# >sº=ÄRí½æ�‹>áÖ½\iG>pc¾±N‰½=b¡>+Hø=¿Âƽ!Ö—¾$Öú½Œø>‹m‰=ûMÚ>ò­<¾Ýëy>F¢>¹°<×ļ¢Î¾fÃj>�b8> D>¾Â?e=­Ãa>ù�X>^̦>ßK»>Xòý=r0P>²ók>9�¾Aýq>^Á¼ƒìG>¦•’>ës¼Ùû«=D >Ø»×¾Å5O¾]’j¼Üo=D”ï¾Ý ˆºê�`>ÑÙ°½d¿Þ½û’>òò$?é½+´º€Ô=IbN>i8?*'u=ƒ ½TH>ÖûÄ>‚5—=ºÉ>6Ù ¾©ÚG>Ü0ø½(°…¾î]ª=[»0>ßi¾-ƒ=/%©=øL¾iK$¿;x<"©Ã=®|s½_—r½v=)¾ž8½ï€˜=�uÈ>,ßÊ>U¨¨¾…mI>)ŸÓ<,‡¢=p¯e¾ètb¾ó@¾pŽC>÷›6? õ¾IÝ> zÉ=÷­†½w0¦¾p Ê=ðM>Åñ8ê•]¾œÚ>¸¼D=¾éÆ>~G=ž ¾ó±<‘õµ>3­>&·´¾íäF=»Ðͽ{YY½ú̾Yô =H=#…½½£ >¹Ç>b—½Ž°^½0$¾z7‰¼,±X¼›¼½ñ\4>‹è½=㾎?#8°»]ž="û ¾ &>L¿8>އ‰>U˜Y½bL˜½IyÆ=A?Ͼ;þ}=}ž5O†>„¼½‘ó=¡(¾]?>¬ÇT>B –½‘Þ¿!ô¾îÝáaÁ >ÁT>ýƾ«½eú¾™Œ¿åû=¾øÊA>È›¾ k6>-dS>ó�(¾%¼.—¬=aÌö½…ˆ>(:Q¾ {…=Ûº¹>ä=>ì¥>kp¾§ê;¾ °Õ²C¹¾ QŠ¾È ž½ 3Õ¾{Ô¡>‰|¿v£œ=¤cµ>Úg>ö*¾0¥«½(Dq¾ôý½z|º¾ùl¾Ó-¿œÎ0>ý–²¼ÀT¾Ð'=NÆ>wœ ¾Õ|�¾ÄáŽ>‚h)¾uŒ�>€š0>ëk>`å{¾Ì!>cb€>”?ˆM->Ô˜õ>Ò@Ö½q»V¾䉾ʵ>W¡=]wê½?Gv½ÿ„Ù>jÚ>¼<☽£å´=o‹¾†Ì >Þ´Í=ÔÅ8¾íŸµ=íöù½ƒÒ¾M0·½³R�>‘¥"Úî°=‚£¾o(a<›/£= S«=г¤¾8Í0¾z€½ �>ãD¾µ•–;â;?ܧŽ=XÍ,>O•?M ¾mÕ˜¼:??ö!‡=Ó㶽̵Í=ÓK>±âï¾�Ù©=v`l>Y9i¾ Ëk¾´X ¾1ȾÃs½�Òp½)Xv½uaß>Š×¾‘r>ùéè>¤ÿ?Âd¢>Æhî>ä¾?>ûKK½ r¸½œ—>ÅuS¼6!v=ø›÷¼žbÒ¾cǾ²A>á—Ó½ .‘=òœŸ¾«Â >Í�K=; ¾™]>PPÈ=×¾n£?Úû½>VÔ>U:8¿jß7½hz@¾ÁAM¾!Ϧ={¢>vÜ >û÷­¾'�{>l^)¾f…Ê=QN˾¼á=±ó¾$>p>=课jöª=Q¿Jà½(ì§>üK ¿÷5!¾À�½,Ýh¾M°y½Â�{½ôÄ)¾ U½á˜ˆ¾}0龤W¼>®±Ÿ=EÓž>̬>ûù6>¤Ë¾<>heP¼Çpľ1ºK¾&�½8„¾‰L¾Ý:1¾ C>ØvI¾ˆä3>1w`–‡=m¥Ú=�V?sâ®;V›—>wC^¾KÙà>¼!¾Æ+¯=uÀ•>™",¾:x”9mÎ=!a¾€h½¦ó¢;y4à¾T³À>ªî�¾aJ¼¼¨¿-Ò‚=]˜§¾+&J>Tâ½}»õ=h>Žzk>V’â=Ø9 ?=8=(o>rÝ=$«>ɾ"1>@=DÖ¾åB>`Y/>+aÆ=“âw>ÝÂཅò)>m^‘½0ÿ¸>«·²¾Û¶>]§„>ÿ�?œù¾±Lr:1q½È¬«=“¥ë½`<>6Œ—>$›>°ÙŸ¾Å¶ä½¦/µ½ ;~s> Ö>}¡ø½0.¾[–<à d>I< >-Û ½'7a¾ZRT¾s×û½Ž>¿§Z½yû—>u?!¿쪾ñ5B>…I>‘©¹¾²-²>6ƒ$¾æL>aúg¾9Æt¾%*~>ˆè>{”‚¾dñ½Z!?…žD¾ÌȾ™6¾]'¯>–š>8G >5JR½A¦¾Ñ½­½�½ï_ö=úæ>Ìó ½tîÿ=㋯=•8>•Nç¼ß‹¾5Ö*>B„¾c•>R\½Á¾p;è¼ÎÉâ=æ­½r“¬½ÌH¦=ú7Á½¶[>²‰b½°Jæ>I}¾f奾ÌòT<¥’R=̾aO5¾K®ò=‰ãS=ên¼äpÄ>�+m¾^k?û½´¾T+Ý>ìQx>+7¿Û�=W#Z¾y‰­¾4ò…½Å׺>Àˆ>¬õ¾À(¾H›”=‰4·>ÁÎ×= " ?÷€À>AÅ=o!¾d?=ó·L>÷W̼Q«¦¾ HÈ>]"�>seÛ½¿ª€¾õÃ)>–.>xöb¾:u‹½Ñ€9>ê½4”>ŽðN¾¹“­½~¸=Á>|Y8>½â(¾ùzª¾p>Þ>XvI>¡I ¾®ž½Ï*¿×8m=ú'½k8¹>8>!2°¼ÇÀ>‚G¾‡±=šõ¿ÿ>ß¶¾S![¾Û‡ ¾m >Ó߆¾Œ”@¾!Љ<ÚêÀ>óBä½R„’½¸?âä=â‹=1rÐ=”JU>‚ÐȾ$Ñ"> Î7¾Ôh‚¾(w>iö=BæÚ¼Åü[=³¢ó»»Áp>²r0>¿Þª>è/־Ķª¾r뽞d¾¼Ò">÷.w¾á•n½þRœ¾}#˾.‰½>¾+XŠ=Ÿ¢ >R(Ù>ûYÎ>T">“¾­†¾(ÝJ>ºx¢>޽�=ÔE÷=j!¿\Z> ×Ë=Uü=o§£¾pµ~> Îw¾Ì9„¾_©–¾óÖ—¾lœ…=ü’>[Ø=>-Tç>yÀq¾`à(¿åß°¾�Œ;½–#Y= „¢¾€»_>0šÔ>àÉU>Y¸§¾ Ñà>a ¿W«>¡Ñ >’S¾+v£¾¡õ³>cÄ’<:.Á=J�>Õý>ëõ½"öë=¶«þ½Bàô½rR>½†%¾Þ2 >ò¸“½F>Üüø>ø±¾mø>¼¹F>Z->�À=9=š>„¤å;•¤¾e˜ç½Ù›ç¾ Þ>·a¾¶&¼²0¿ =ÖÀ:¾}g[¾}>Ó2=®èî=–¯´>8¨,> †= k;@þ…>ñ£þ<ñ½¦>~χ¾àÉ'¾äÞ<=a!¤>IŸ•>Š ¶=43l¾“xÝ=1¾šÄZ¾ªJ™>Ò¶= S¾d¨T½.þ=3š >gú€¾¶âw¾nñ£½<˜>-—i>è™ >“Ê-¾%¾²P"¾ÂºÐ=ÁN=>üÃû>½jG>4„¾'å3>ÛÒ=€¹'>†â?*?å=ñG>ÞÜ?¾çòÿ>ç¯/½8t¡½ƒÿï>„Ð"¾{R>ྈ‡á½,¹ > |¢½gK„K>�œ¾ºW;½EÁƒ= -=¢â=/^9>´�㽢ǔ½æ9>'нõŠ>A.g¾i_¾·•¾½:‰>hˆo=“Ÿy¼¬é¬>±->ú”+½º'¾WŒ°=µa¼ïJû>ŗ¾Ó4ݽЙF<(eg>E¢Šö°ý¾÷½l>0¼=£õ£>§°¿¬K¾µ‹T½=Ú.¾ò§x¾îŒƒ¾ ZI>ê^#¾0›F½ê†Á= Ð¿O¾jl4>ãAL>S/¿kÉ>Ù¦=§90>€ƒn<¦Ž<“P4=uñ==bß¾Û2¯½¾¤<��ª>;°E=O?¾˜‚_½9¨C>µ†¾vL¾ÅN¾¤“>­Æ;r‹h>ᬓ¾�s{>"ôn¾Ù"‰=³Æ »[šÖ¾\>„6õ½¹¾«HÛ¾À=à·>y²M>ãVh>gi¿zJ¾xäZ=Œ, ?{÷>Hà›>Ïã;>ù�½Æ‚>ÑDý½¡ Ú=Ã\t¾ò:Á>]ØÀ=û¬ø¾§M†<å™>�½½}Þh¾Rp>™Ùí< =>½ø_½½›�½“õ—¾ |(¾2%>“ô\>SÒX¾YÛò¼]„y>“$¾Š˜Š<#£= ´¬¾‹ð¬¾")Š>à=¥ƒ¿4°Õ=Ò�×=z�_>ß=gC>¯°}½ j÷>™ú®¾Ñ:1=-ÆF> X—½f@ɽü�ú>;VԽڹʾí0f>Ô2ö>áðÆ=Âð¹=â^þ>¿ô¿æ$u=É"½«|1<ô‚>¯c)¾v À¾´$¾bÏb>ž¥=m—E¾—|«½¸å…='õ½Úš>5óç¾Ø±‡>2�Ò>§u¾å¯¼¼}�ï=–>Ö=¸=EE¾c(’º}=ö¾“0Ÿ½LÕ¾1!̽N¾p»3þؾÕ8Ý»ZÔ¾™¦ >ô¾“ÓY¾¼ >šòß¾§®Ï>O„.>�&‚> º<íq�=’%u¾Î_;æWн�8¾AKͽ´‹û½ �G»w¢=u½b½è]�¾!v+¾Y¤i½·%+>ÚnW¾¸\¾e;¾V׿M|]>ÚM2¾¸¡ >æÓï=dwÁ¼¹Àé>“}Ú=âDc>:s!>ü¨=HÚy¾g›h=I’G¾h#¾%ŵ¼_>¾¯CÔ=üÑ£:v3P>Éa^>å3±=�3j>P¸§½ˆö…=k¼ßИ>m®¾Yým=€]Ó>Ç£†½;¿ZÄT=ö+½~ð=ýÞÖ½?c<,4h¾OÉ>jG–>¨¦u»Akº½"ò>|᤾“6I>ã¹¼= ½Ìyª½“nz>¼Ây= R#<>…¾¾þÙ¾ð8>Æ^=¥³¾@?@>{a0>%ÀV= x>¶ŽØ=-ØE½“­Ž½ƒµ">¾Ø0<=DZ>UÕþ¼¦Õ?kB¾DÝ_>“¶9=Ü6”¾ÎZg¾hIþ<›¾LwÔ>h¹€¾k>:$Æ<% ¾Yº”>Œ¯=ˇ¾AR>‡Oß¼!ô>s±B½\d�>#Ñ ¾_ÿ�>¯ƒŸ>(Ô"¾Ef£¾Fn¬½€O“¾ ³#=ιʽ‚p¼ûžl½ío$¾F>I9e¾‰Ç~=•>ì¾}e“¾xv?AŸ‹>z>Aã?Ý\=m :>ßç˼+ >2h>>˜¾}Sq=ï#§½•^2¾tɆ½iE¾Åq>Rüö½$¾ˆ\½`,¾ÿX…¾F,$½ü»>J¾m!—>X±%>õ±¯¾øg�½vùp>õ&k¼(ðð=þt‡¾gnV>kŠþ¼`SÙ½öO¿=h;õ=µ >¾ ½.`¢¾ñæ<¾¾¨½>q×<X ¾Î¡®»wÃ=Ó¨®=�ÅY¾:s?¢¾¾Xu< »¾{r ¾½� =àá>Ø®© ž=TÎb>ç๽ß}¾=%¾(À¾‰É×½ù¬=}‚å½xŒJ>v’½<¨‰=\CQ< ¨t<üh?’<À<’æá<Å\C>vü¾ßî{½‹w9¾ŠÓª=—¶›¾ê8‘¼t$=)Ež¾ÉÈ´¼D>`ê¿” ê¼I¨Ü½vˆ½WUA>mÛÈ=FWÇ<âÓ-> |ƒ>0n>nGž½¸Ô~>^—õ>Ê (¾|],¾Ý�ƒ<Ò(Ï=$v¤>u‡½ôÞ®=S¦¾¬Ž>ò‰Õ½�°½]?Óìx>y?%¾‘¥¾ñü<½À'¢¾÷dQ>m/r¾ûìŒ:‚Wã>’‰>~S=å œ½Ï9«¾ÔÚ¾,åÝ>*ñ{=æTľÐgW>ëJ• ½Ã_>ã3E>©±Q¾(±¿ ¾ÚŽ™¾ŒªÑ¾$-+¾YFG>¨¸„>uGð¾x‘=ägû½YÛ;¾¦OO>¼ï(¾r¸P>¬‘¾yúÆ>¢>'¾‰î <ë×è½"Ò¬>+õ¯¾ƒ ï<¤«¾IR¾‡¾>…ji¾U¤>Í¿–Z¾úci¾àÙ“>4:2¾tÁ¥<v‚>çt{¾YÖ‹=¼Ž>fÿ¯>¾¥Ï¼ â>Ê‚ö½S4†>#>ãä'¾Ñ±˜¼æt½Ðl¿:d¹Ÿ<ï¡>Šôœ½­Él¾c8½Økð=1pê½Lò#= ’Ø=!Už=jp,¾©Œ >@Qk>ÃS>lÇ>yÛI¼-¨£¾6X‡¾Ú\Ⱦ'~Ì=¼Œ>HÅ­=ÓÞ�½heð=v<®¾�“>rîk¾’<ƽx¾.ü¾¾Ê�¾–©ˆ>ÔÁ>é y>^{4>ê¬ ½Bm>Õ—Ö¾>w„‡›ë½]õ=PW¥¾²w?ÝÐ÷;:€4½W¾xce>)ê¾Ýоhƒ³>Çò«¾EZ)=õõ?, ;ow¥½kId>tÄ·½œrR¾Q¾sEL¾6Öõ=Õg¼`eë=rù=Ïs¨>–£¾×„>¦¥R¾ÂÕ̽ˆÕ=»ú,>ÖHB=¢`*¾¯þ½Q‘¯½öÑc¾®�}>­Q+½*ܾ£Û ½Ð‰Ð½Oc½òF,¾ ŒÇ>�±Ç½±K…¼q´Œ=$R¬¾@é ?ÙO³>É2Ÿ¾qE>_]ø;'Ö¼+R>þ2=q×=¹ê¶½óuù=OK¾¤Ši=íÍ8=4|">@)¾„=A7>Wó¾]Ê >Jï ?„|Ÿ¼ƒm‘>O"¾a’ˆ=Žÿ~=÷Û�¾ÔÆ÷=_Ÿ/¼Âû¾��=¨´­¾¯À7¾{,ĽB‚¾æ©5=V Èí-µ¾Pò¸=rÜg“j½$¿L>£�¶¾ƒ›ƒ½§Â>zúÕ¾„/‘½3¿Ì½®Xù½²Ç>‘l">#ž½e¾‰7¢=Êü==9|˽¢#R¾� J¾(þô½ã»½Å~¤¾ÛÓF¾xк<�ÔU=:*-=ÝBM>d>§=R×n»�g>+  >;g¢¾Z×¾P'>“¿>:p¯>„\>í(¼µŸZ>¬X“>ƒ¢=á55¾ Ò½Ôí=³á[>¢HL>%ó¼Z~ƒ½§å¥=¾Ï`>åv¿¨½=Δ½8‘³¾«=!= è;>+7Q¾qlJ>î¤>b‰X½ª'x>ç~;�v4>‰º¢>`TD=l˜­½­‹;¼g´–¾ ºý¾¿Æ >Æs$=�í¼|vx>Æme¾‰H±>lQ¾à¢›¾ƒøñ½â�Q½¨^Õ¾]eÁ=•D½™½ÞzY½B¢Â½ª³G=ƒàç<´jv>¯r>o)ν¨CÕ¾£��½*#•¾†+ß=¦Î;>6ï°ºÛ§m¾Ê’U¾*²S¾ß^?>“ �>Fé=ÊMÉ>ÚFN¾ü3œ;|‘;[&:>¿_S¾ÂÖ>¾ çþ½›îi=Ôcš>€,‘>üÄÿ½ž ½½\* ½h>)=1bÀ¼H‰>2&½e,½t»±=V!¾½y>aß ¾ŸÞ¤½–_æ¼�lš¾-}Y>Šx>«Z½|~÷=Ä�Û>Ù‰¢½þw¾ˆú¼>U�Ý=ŒØ†¾ß÷i=>>¬…Ô='2T>἟>èÛ=‚m>AK]¾Ãjõ¾Ù¾­’¢>�‘¯¾|—Í>™d·½aH->W–€¼$¦Ü½Ð)“¾vϯ½ºA¾È<>ìyæ=t€D¾@c†½p‚H>ûu¾:"´¾�Ÿ>]Š>ù°l>!ˆ;½ø�>šDN¾[¤¾>#¡½fƒ“=Rú+<Èl£<¿äj“>*ľP´ =Æ-ĽÈÞ‘¾d=(½(vÉ=@e$>"ܾXô™=L(×¾Ì$d¾Žš¤=nçÂ>¡Œ ¿§I¾žú½ÓØÛ½uq¿=­sR½ž¡¾Ö%Ó½±N¶=$¾-ób¾p¾¢½ië)¾ÊS>^þ­¾u¼)z–>z½A½Ò¾x$—>ÁÍy>˜uO>ñý]šP=¶µ£>�‰º¾×ËŽ=ŽÑ=¾Æ›a¾ú�¼ï^J¾„ì‰>Ã'f>>>VÀ¿>†×=!B"¼j>е˜¾çáÞ¾*‰=ñH>½w�¼¼0>T<å=�aZ¾Õ#>yT>§£¼T—ª=ØK›=z¯å½q«?V�&>…fà½÷ ª<ÝËÖ>À‰Š>I㡼#䆽W=G½Š’¡ê¾ªw>Hé=ÿ–²=êUÙ=Oű>F…Ô;x•¾½&2ª¾©Â˜¾°“¾�Tƒ>¡WQ>ŸÙÉ=ú‡=¥½Í°²¼½1½[Ñâ=zg>ï$K¾�¯£¾ã:>i-¾9a¶<áG�¾ºò]>–T>Ű=”¨�½Ø>½ »9¾tã½éçÕ>n¬Ø¾ÉOf¾¹;à½ÖÞ=&y0>øz+¾ÏU™¼“ÇÊ»®l >½;¾¤†0¾‰Bؽ<Á™¾ê+½Âªº>ĺ½�ÒR¾Ét�>7c=W’ñ>B×>üÁн³M½ou½AP½NO>‹•¾)¾¾¤£ó½] 5=»»&> ëK¾è0Õ>#%%¼œ™™¼æ;ø=¶�—½Cr=£ò½µ"2¾ža=r4E>°ºb¾�Â(=Ÿÿ=õĆ2Ü»vAê»bØ2>S;¾ÄM’½ýÌ®½axj=äŠÓ;"ãh=•DºÒPµ=T<Ô_”=šŸ½îm¾Œ…�¼ÉÁ#¿SÖƒ>«b±=‚Ú¼½ñø³>À›¾"# ¾ë=¤Vã½ÈP>J† >œ5,¾Q‘¾áA =Æ,>®J¨=r*Ó½=êq¾ð°X>eù¾q ¾ âN¾7ƒ¹¾›`’>ÑpG=¢É =?Ë=`"q¾›Ã"< �§¼Ô{>ûƾ¬í ¾¢ô½}Cˆ½u"¾1ϾÉo¾©u±¾BbL¾�®¼>¾¦?–¸¥=¹o¬=ZŒ7¾"¥¨¾V€þ>£×޾è¸E>‰¾¡òŽsÓÐ=Ï3b=“n¾i?•>b¾M¢�¾�’É=®…< S¶=tl'¾Fõ=èÝà½ÞÁ„>̲¦=C9º=¾zb>™­Å=b�–½ {„¾IÀ¬½aÇ·>žнBn?>Å8Í9‹Ü…¾»êW>qPž¾L #=aíõ»ãà <½ne½Àå»») ð>ïX ¼]˾Ε=I ¢>0‹Ä¾ä‹ð>N=¾c>ìD²½nÕ̾¨�¾¶´½o«È>½zÏ=øyd>F¸½Çë½65>ñ†*>x%€>e*’¾ =¬¼­+y½Ud+½,ç¾Ù\\>2b¾µH¸L d>ü“ù¼ºE«¼5¿â@ƒ¾\n>z�†¾Y>´þ= +d¾fp¾õB ¾Ø|½tß½,�ð= Ñ >ßJ«½ÿ/“>6€Ç¼Þž¾sæ.¾¯nõ¾DÕ5>­ >™n¾‰>£'¦½öõ7=ˆ¶,>q�ð¼ç=¨!|½Ä¤¿E@G¾o=޾¥iÌ=žnr>cA>Ñŧ>]ó½w“?é'ø>+_÷=öy—>qÓŠ>ñÛz¾k¾Ùÿ>·Â£<Úõ¿¾u{X¾>]>­ûf½Éõ>LPÌ>}l(¼{Y²¾¨í±¾ÞÏ>ŽN>Dù­¼Ö… ¾–r-¾o3>Áܾ8(ˆ½Âë?>ㇾÖk>�—¿+ËŽ¶QÍ=@­r¾qÞ>6 L=:Î6¾Ã�b?«ûì¼É=¹¾pk·=Þ˜Ö½‹ù�¼†¬â½hpj¼^B[= ¶½°§¼¯V¾(@>˜o$=4H,½œz¾FÚ >â ð½"T‘¾@Ñ%¿Åt >@ヽƣ¬>S9>d~<žxf=뙨> Ë?¿)Ô;½œÍ&=#·>uS<™|y¾nÒ¸¾�“¾ùq¿™y¾–¨õ<äqž¾Í²<¼s"ë=}¾t%¢¾k!.>Ò´°½¼9o¾´ûš9Ü( =-šÑ>94 >îmH>Y ?k«>^H)>ë¼¼|D¾£P> ï/>c½£¾Ò§ =CH-¾kò¦½”(>C+¾z<Þ={A =ݓڽ‚2r¾x+ë½Qž2¾”‹Ö½¨'¾cQ™>dâÕ=¤¡²¾D?¿=SÉÔ¾nº7¾ªIf>¶m>*Y{¾¿C>µ3¾Œp°¾_µ;>Éÿì½ß¤Ø½:Ù¾òJ¦½ZZV¾SM„¾úÍÆ>+ɽ½ª=­¾¨–>95½ˆt ¿ky¾OY<>Ôß¡>e¦©=ÀB=¶ŸI¾Ò$A¾&QV>Y\È>ƒ.Ô½ Ò�¾* €¾¾ =�â�>.>HQ¶¾f+(>qÉ¿èO?ß'ÃØýÃ=œ=n¿=¾í¶>‰Ý;Mû>vöã=H¤>y3P=z1¤>[‹<>¾àà=‰i¿©ùœ=[Ãq½Z–>îq{¾ W0¼tè=Ü�+=êäS¾�U´¾Ć>¨´;½çp^>: ޽´S?âÕ>÷ôg>â�—=(�0¾.óº=C¸= >F–0=åÙ‚;c'¿ï[}=OY°¾çbI>~Œ/>ÌÚ&>³æ¼ö$<ÏëN½$D> ŠÜ>À¾çï½yêÁ½ak¼Qš¼‚a> ?á¾:W=),ç=µŠ<}>�‹¾�Ã>Y¿U½þ1¨>”½ x­¾¦¥l¾*—¿>ûS€½‹�«¾psš> _½>–aÀ>(…p¼²‚>!!½êÐX¾^©l½ö>Ø>Ïjüg z=IJ€¾å½¡½&^Ó>ó ¦>�âw>Oâ<“Dœ¾×Óz¾†«Þ=¢ ²=|A?¾Ôl>rx{=Ò1ľ±sJ>·¾wøÙ>áž‘¾«n?k"<¶N»>”üë=4Á«½Ê¸¾¬~3<]>0Tt½Eþb<àÚ˜½–P§>^ä¾³–Ø<ç;¶¾à@©=¡=T¾—’x¾Ø+;> {c¾ 7½G$½(ÛÀ¾ËÁ«>ða”=ª{¾ÊŸq½¯áì=pcõ¾Ofz<t¥¾_ÝP¾­1>¬OÚ>™sؾê̵½Ðà#>âü�¾U ¼=¼LƽÉݤ¾±„y¾´û¾R£4¾F[%=ð§¾=²‹ð=[dо�oÛ<ˆ¾™„ø½·1U½6…h¼®Wݾà�œ½¿i¾!½2Š”<'¾ÀT‹>å﬽uEƒ<+°¾ªE“¾éï¥>$™B¾½­0¾«éê¾zÿÔ=J<†½½Vt>5ÿé=\§–=²Gf¾ü[6¾@`Ÿ>f_c>}±>ý>¼ =>0ô�¾•§{=ywF¾ýT>i�²>öÿ<е!=É78>œÏ~¾üÕ½36?¼:'¾ô�E½7Ò;œ >ïŠ;µ”>æ÷ª>·H>´Ì‘¾Kœ¾½ø Ì½0“Ÿ¾Nìz¾àMнvS¼‘îT¼¹æ.½�Û–=Q‹‰¾ÆC=T6£>H€6>=ñ“>0N…¾�³�>ó‡F>Nm0¾Æs = ¦"=!/0?h-<¯ÏŠ<-�þ½Åʾþ±Œ¾³š=¾Hf>CÅ�½Ú‚‹> –¾\™¢¾jq>`9©>v_ˆ½�å–>%�¤<ЂоÊ�3½B±œ>‹Øï>ÖÊÁ=^™ž>éÚ¾F¾(¾¾Ä´ >*ˆ¡>j¦=Õ:5>-¸Ã¾¼¥½šq›>eY«= H€¾sš:°0R¾þÄz>�ÒÁ½¦ç¾¹c³»¼»ˆ<“’>@°�;”ÍѽmT=±çÂ>uU¾ÍW¥½Öö÷=󊶾-U˜¼`¶?ñK5½Ðcn½X-Œ½û,½¤¯0>\!>Aœ¾ª�¾nß ?¥:“¾5bg¾iš½šÄÀ¼ñ³�>ñ¯è=pÒs>콃l9¾µ²s>`y½ñ<)¼:¥¾ZÐb>þ®¾?ý¸½HŒV> &Æ>‚½=>§ê�> It»bÑ>ut³>“'P=Þ¿>û/\¾®}>½ï5¶¾”+…¾ý@½=“2H;5->°�Â>ÝÔ>R>½³D»Wx=ð­:Þ=¶u·½–?%> ˜�=Eö>Äu‚=Þ±×=ÌýrXN>ÈÆÍ¾lht<à‰À>^ع½@UʽŠf";�WY¼�/�<ÄãÈ=í¦¬>¿Jã=-x>²}\¾™ë>½Wc¾õ >9É—¾®+,>0â= üø¼yší½aˆÏxî=›E<0v¿¾óóŸ¾3õâ=²ˆ¾â¾‘ ¾[ú,>u̦¾Q>>éÞ½è“n½¢œ¼Æ%ò=`‚¼¼æ«?ª4ÿ=´;p>ªJ÷½ƒ%+¾/>ù$?"¹ =TX0>Rà:¾PF¾ÿèƒ>ðCœ<íî`¾èR›½luƒ<.YÔ¾«C­½Œÿ==$@à=¸"<×i€¾…ÈÖ=j ļÙî(>øG|>¼g2¾ t¾ãº>xË–>ú¯r=@»:>\¦.>´=Ͻ¦¾¦tµ½cr½±2—>¯l¤¼Ú�Ô¹¦#½|‡ˆ>µÈ�¾w&½Å& é^�>G‚{=ÊÕL=…뾂ƒ¼Ú�Œ;;=,°`>²­o½X`=i¯³<ö¥{¾�ê4>Šϼփֽ)ìž>ÛË̾)y”¾#Å—¾ÎöH¾¬¯=Åj•¾¼>¾Vj©>Þ/½íU¾›ÿG=+{S>z— ¾b�N?²Q7>s?¾$‘>¡É¶>ßM¾Þ×y>1g½SϾ5O==ÈC€>»�½¥âi>èè`¾œb8¾¶s>"d˜¼´`¹»,å=òJ>͈۾ªš<‚‹=vÒŸ=Ôµ«:Å˱¾Hd¿Í«½p€¾.æð¾Ës>æ!‘½Ó:p=£Å‹=<ãO>bÀ5>Îxƾ˜³4=}>£ĻѤ=V,>@ª¾.iª>«�@‰µÇ¼S#¾=2á½4ôƒ½£öÀ¼þ‹¥¾O)È=Žq«<Ý^>› 6>qÁ¾JŠ�½7Ín>ûÌ»=öü<ØÑ=}ßü½Ï¡L>Ô¡9¾e+I¼Z÷ý¾ñŸŠ=LjȾCa8>¯´¾Ô}Ì>þù½”]¾ú^j½U¾>LÑë<ÿO­>½ó¾´Õ½Øo­¾n]½q½¡%оH¼É=;5>>µ?=ÏW¾ó 2¾.¾ÞÉ¢<Û7Y>ƽöI<ô¨>¶ò<‚à…>~¼?Mîh»!± >·Ž=SÜ>‚4¾,í=p =zΆ¾Ý�о*x>A!L>nxÀ="yç)¼]¾ˆŽ>º½‹à¯¾D%¾/ñ>*æ?KÁ2_¾aA‚¾UG½ïÒ&»ÛG’¼�?þ¾éåD¾Í¸™>ƽ†EO½ŸɽÌXð>RúB;Mt0½SˆW¾¸Ø={&ˆ¼ãO¾(y¿=í$»>�?l¤Y<¥|½–5ñ½yš˜< ý־ξ;Õ ¾¶L>“˾P l>à‚S¾yùä¾ñ�½üG >®v†¾hõн——¾Ük£=Æ9y>qÝX¾e5e>Y†n¼~C>t½>gÕ ½ýY½ ñ�½¿´‚½à©²¾’•”>]t›>¤Õ9= ‡Î¾x#©¾xjt»‚˜¡<_:ô>ž4¿6ÄØ=jï–½`7Š>�¸X»N¼÷ìT=•Ô^=µ�A¾rŽI>§�¾@1ï½¶É�>Iò=­Áq>—z^¾ÝR¾dû³=M€¹>Ô럾v>y=°÷ƒ>`ꪾRæ§<q�¾,õ¿•·¾˜)>ÙÕ¾R±Ð½Â�=Ò)b½÷ê>ø=àÒ–<Ìf¾Å[½ºÏ=û¼“>x+ž½ý´Z¾t¨¸>8Œú½Xÿ >mõؼÙX–½ŠùB¾³¬>·¾u4¸=6·¾- >ç´n=ó$‰¾{ú½ªT¬>Ôï¯<z ¿Öÿ=göÍ>‰VU=x…ž=Q,µ>ZØ?†UͽõÐ"¾ƒ$3¾½Èj>(q¿oÉã>¾.¾ ¿£L¿>¨þɾÚ,!>�à½)˽¼Ið¾ ¹…>‚í,>°rˆ>¯o>ô¢¾y£ú¾‡B>ïÖ>«&½k4“¾ï¬¾$f{>þn¦> G>–´G>imW¾÷!">– =a­­¾©i¼ì™‹¼Bç·¾XïØ=úÃ=²>Kj*>Hx ¾¥?]½DÕ�=ÿ»ó¾åpi>ꢋ¾ù ¾1uq½kñ‘¿½,ý€¾ñÊ­¾•¼>ù©¾:\ϾÞ?P>ž>�¾˜³V¾�w>XÖ¬¾ ¼é{¾[§U½¯:Â>È�¾{k;拱=ÇÝR=�ô½<¢Y>r =S¢<)HW¾O|_¼8x—=+ô¾·œŠ½:B¾¢Ö‚>w̾5�.>ˆbX¾¯á½d>èšò>ÎtÈ>–º½‘©)>ÝO…=νÐK= F{=9[D¾Xš{=̳¾s1‘>Á+ ¾U�>Û?>™ú�½�ƒ�¾Áì]¾T>f>|[g< ¢Æ> 2â½ï^V>(Ÿ5¾ºH¾U;¸=lš»+´ø½ï>>®´ˆ¾Gû=¯î²»ÀV­>$(+½8,¿ê;¶»®8½c%¬½•.ȼÒO=Šˆý=u>a³1?Ïž¼Cþ¾Ð-Ò¾­Ú¾óúw½9¡2¾|¼;¸?!>‚¾ ? Ìë=bð=*‡½êY²;A(>[aY=1y¦¼¢ë"½~ľ1Lí½\©•>­\¶½0¨?!ï>>Íüå½Y—ç½Ô�¾'ɸ¾oe >‘l½o,>œ†>‰" >Cô>ŽZü˜‘½ù'�<3Ÿ¾îìM=ülñ=tì�¾¸º—<ç ?Ï7º½ÿ ¸¼¿%r¾ä€±¾põ2>ßսȅ¯=m]ô= `&>·'‘=-•L>\ Þ½#Nœª“x>îÃ=ï'O>$„J=p‰½Q½‚/î½^Á.¾dLæ½_RP¼ŽR<¾QÇö=£Aä½²ü¼ä<¼½!:¾ºuU¾;?‹�Ä>!íˆ>‹–6¾× I=€ZŒ½þ9'½¸˜¾ˆÐ¶¼ÿ7>÷¾ <‚Ú=àãË>=Ý…>¸Ê³>+Ão¾hü‘>äÅ<>©Ý÷¼# §½ß] >�b»=Jê�=Y/>€>¶)@¾E¸>>ƒc§¾²6=ìÃ/¾Q¶>ðÏÚ=Ý™=És±=ï¬0¾ó`¾[ø=Tý;¾wX½g=>0Ó(>"ƒP>ô¯¾Ò»>ŸÁ:lÎ0>øå> ´s>Ñ�š¾1Ô=idp¾í±¼XÓž¾’‘W½eü>qM¾Cc"¿ƒ/¾¾ä)?g_{=œs¾z½¼½ÊMŸ=ñÞ𾤢۽¹@®¾„±¾ÍÀ�=ˆªO¾Ñy\>¢nÑ>‘д½†&¨¼ÆVû½Ïdf9¸ ¾+w">¨s!¾ KÄ=…h3¾ýéÐ=€‘¾Ÿ~Š<‰M>#'”=N�Ô½9_>Žn¢¾Wq¾jF¾=Âyмàdð<·Y½z\ø½MÒ]½Q寮ô>*¾¿7¬>x8ǽ¨Ýê;á?Ã;s§¢½Ìôü=‡´;=vìß<èÌT>�ö¾hDÃ=›]¿à‡>g•�¼²ï¾ û¡>f ¿>H²¾›�m>êA?>OF>n² ½ Dÿ¼¸»¨¼_ `=˜Ù>>¬?�÷ ;ËÈ·>ñ#(>e'I>>~^¾÷kL¼;G>Óp†>Ɔ=lN¾ô¹”½ª?¼õÊ>Ç=�¾û¯¾FB¾¿ >8»>€ÃF¾ix'¾?X³= Ì€¾‡²„¾c’¸=±Ñè> S0>[c¿a|Y¾Blœ;Ö#C¾ 4â<ó‚;X&Î>Î.˜>}>g ¾›ç=ï =ÖOî½ÔØU>%· ½†AÁ½¥�>‡§>/uR>ÞZ#>e¹8=Qt›>6Q¼á¼zk>¦f›>Ž­½W`´>)Ä=lâ>n¦¿‚$„¾êG÷¼âw ¾,þ¯=ã„`¾%�޾øtŸ¾©ÏS>Lòw¾A.F¾Ë W¾‹á=µŒ½šíï½oÁ¾™Èº;Z,=…9>˜[½´³B¼ò>�Q–½4é=>fÙu¾Ç°¾…÷c¾+U1¾ê" »ëce>ãiÕ¾>‰>»„è½¹Ñ=¨Cj=ç(è=1;ּ؜j>÷×H?8\À¾ °=zç¢>] ë½›W–>"u´½é=ƒ½™sÖ=tÕš=Œ{¥¾7j˾�¯¾ìï]>ŒÝ�½)c•=Käì;H«™½&Y˽˞d¾—C?6›¥=™MÚ½±ö¾J>®Ú"=äŽã>x¼¼6]Š>IŸ=B¦Š¾—F0ºÁ°>ƒ6÷¾Š=>õ?¤@º½-¶£¾kA4½¾“ñ=ž~þ¾FÄ><*h=�m ¾Š)@¾õB¾†Y2¼ƒÛ?à^4½ ’>MF¾ëJi¾tùˆ¼ïr ¾—ª’¾ ë¾=««½™»Ç¾š!¾›ìN>0?Ò‹�=ì$ ?K#�¾ä‰?½;݇J>œF�>Dæƒ>»ºŠ>·Ç¼i€¾ËÒ;¾E޼¾Õ ÷>ùŠD>Žú°¾ u×¾^¾{倾41G¾) <=�š=9´¯¾Î—:¾“b†¾üý�>7?ž= mb>^Ý<½ç ½Œ½ÿSü=bö<žz~>Rü>ÚP‚>6x§>ît®<9§Ž>5#о*´Š¾ws¿¾ëÛ¾çn7=l‹£=;‘“½ŒÅ¾ –œ¾y±¿–¡Â½Óû=aèh¾¿,=ýŠ>“¹¾ØÓL»Ra½¾v‡¾½Ê=£àÖ=q)†¾Ù˜“¼/ä›>ॽH©Ü¾àê ½‘bò=.O¾ŸÚh½Õ�W>Çg>ûNO>ì�>—…€½_ ¾Ì¬Þ½Ë®¾g­¾Á¢Š<]š×¾ù…>L™‡=œØ£>Úˆ6»›Ö©¾¯Ö_>OÁ>÷á{>@M ½t„½}�¾~\ò¾·ÿ>b´˜¾6ž=¢—½„(:½š ö¾7˽‚÷ç¼�°59,Ó>s ̾˜&?ú®¤=YN=Dä>Œ7á=0L…»óS >ÂË.>çCb¾‹wƒ=¡IŸ>{¨ì¾y6›½ýJ=¿]f¾�Ì`¾§„=fg­¾ ¤õñî�>l·>§ñ¼:¯U¾$Ï>‚§¾î®Î¾*ü¼ø”Ê>h>¸rj<¶’>Œ•)¿°úx=k7ÿ½e(!>dÃk={•á<à'ß=ÁÞ�=ött>>¯ö={ƒ½¤½ÍM>Q¨§>ÿoº¾"‡ ¾¦g\<-|�>›Î¾ÒX®¼]=>�éϾƒ½±=:Ò=QW—=Jþ¯>‰v˜=y,¯½ø£¦=`H->i8;|qé=ÔÒ@= Ùo¾�º¾o¾æ!Ÿ½¶Úî=t^8»ÿQɾh¡ž½ lc¾sØb¾K²Û>µü’>7Yã½è퀾Í⣼åöy¾¿0�=tdÈ=µÃk=ª×=2@Œ>ê�¾u~ú¼§§'½ÏÚŠ½gzÃ=Ò»ç¾z]‹¾9Ú?wNG½*s¼¾ +6>>;½¾éé¼% r½Íÿ°>ò†<½²�>2J©>WŒ#=flÓ¾V ?>ù÷¼†¡|>A\=®¬ ¿ÐöU=F§t>ùc™¼ Åõ½Î&0?•ƒ>h¼½>4ym¾R¯k¾Hξ7ë>pv¿ÙK™<ן=+À¾Þ…�¾ÈDN¾½¤€=um+½ºH©½öðѽ²Ó=Ól<b >ÆiU¾$þº¾´ð�>AÊJ>箾…zŸ½Êƽ�̽ÔÎ9>—ä¿÷*±¾�bÔ=ùù<�î…=ŠE‘¾SGÜ>”ö»>¬]?¾ÎŽ�>œ± =toÉ>úÿ¸¾–0�>ts辑Ó2½›wî>“á>²ßö½d–m<íÙ£¾ ½Ë>¾�Þ>ú$m¼ñÕ¾¢“¾u�Ï>Ý@d=pwÛ½Mâ>ÕŒ²>²Ý¬=>ÈÀ½Àd;¿Þ.>áÌK¾ø&Ú½ä‚?ÕÔë½s)<¤z×;êKÑ>‡K ?éŽB>œAS½ìý|¾¡ò1>÷uC¾Ì‚=¬¿¥ûš¾+Ɇ¾‹±h¾Sʼ¾,©¨¼�˜>îü>{|]>¯^¬>áoZ>˜• =÷µ¥¾í8>m»=+º¼ØxW¾E$â½ Pã½ ~œ=9eù>>t¿ '¾án޾Iо÷dl>@ŠÖ½‡]’<â>eâÀ=¸–>F�ç< u? 1›>O×B=Eì>p ú½!dT=�n¾¾D¥¦=ìä=Cs½ª¿½Þ‚?uºª¾¬²ô>�Ò†¾hñq> Ÿ¹¾�>t–>r˜¾­)¥<v>9,*¾ N¼–ö":ðó¹½ r>�Ö4>øµ¶>B£=@‹,½ºƒ¿�ë«=ÒI>‡ =s¾XÞU=BŽÌ¾øo¾?D½ƒGW¾¶$ͼÇC=hyc>1Á’¾ðG ¾œY¥>h’?A2¾öAï=‹b¿½«;u>‰Ê?���¾í8V¾‘›¿tµ>¼œç>`c˜>¢`¾Q ©=?ÍB¾¹$<�Îq>÷4‘¼]-ý=·�Ž>epö½–¨½1\—¾�¾¾\ý`>LdÈ>„g =Ù¤>¾ -½sZ'>û1¥¾çé™­ô½?Ê%™¾˜Ó>å3h>Óôú½Úz¾À¬ß=¡ ¾šê¶=y ³5×= ð=HÈ>ìç�¾]¼(¾q@&>á§³¾K7Ó¾vˆ€½el"=Pû¾?öO¾<Z=‹Á…>º�N=‹¬>GRŒ>�ÙŽ¾:;ë=}òj¾¤GÓ>–Ç7=Á x>:mɼ’“¾çB<þb¾Cž¥>„¶‘¾íg‘>ÛÙ/>ä‘Ü=A>øN¾C¯E>5dø�ÑÒ¾·'á¼”¾®á—>!‡à=Ãàý=Š(õ=¢ðG>�V>¨å‚¼>p>M«Y>ýË-=¯ºŸ>�ðÞ½6-ü=%ý½Ü.Ù¾©äa½ui#<×Ê£½Í±´=#´i¾‚ã¹;ÆÞŸ½-DÁ>·;7¹~$¾„U…=ÿÊ¿ý ¾ÖW0=C°r½[6>e¹M¾uèW¿75½Z#×c3¦½Ce¡=ƒu;Žeº=àŒ÷=j�¤¾@n>5n–¾º?X½\�‰¾â•¾´<ª=&‹ð=øC±¾«ï•>½ b>s™¾m¦>{ÿÒ¼q⼇ãZ½·ÆV>kÛ¾¿qL¼Sк>w/%¾ÊNN¾CMø¾D1ã>&~·¾eå’=¢y¾À~V½s9¾º˜¤¼~à{=Ü\c¾{ø”>/�ñ¾<Äû¾šÔ]>Ô{“¾)¢½<ò¹>¹Ù‘½!±š½&S€< ˼1åºo3¾ù…×>¿›¾Ûܽi,²=ä—=?Ö¾xR>šÇo>Z;§=kÜœ>QkÆ=zÖ�¾Àe>rL ½zÍ=)Ô¼{/><‹¾t°W¾!•Ç=U¶u½y8>Ù>J‡¾ãJg>ƒlÙ=,Bü>àÆ„¾jLŸ¾O;j¾vDE>Ã(Eº1g¾ŒÓº>FܾLA(¿é¡$;RÈÀ½lS>k}ß= ‘þ=•¥í¾ZŽ6>ŠÚȼÞ½&ß›½Ó™ð>/ŽZ>Çì<2=e½K s>•Xø¼¤8¾¬€=Õµ²>²œ¼=ŸEÞ½Tu‰>é›4õ½Ã¢`¾�U>By]¾¨Ë»>¼—~¾Ë $¼9@>ðEþ=Ùa¾^f¾ðŒƒw¾=1îØ½p‚8=\ Õ=‡}ˆ>¯cÚ½M™†¾ø1¿�T¾Öóž>É�½®=˜¾@¿Ù ñ¾ÜÂ@>>ÚÀ>mâ=äẽ¡À´¼Î¶³=)?¶-�¾B‰½¼Ì¾g†¼Á ’¾H”Ô=K6¡>ç�O>(÷³=÷z•=ÊŠ>Ó£>§*‡¾ {×½Q=dÑ’¾3°•>eu>›F~½KSŒ¾×Œ>¿w¾³'£>Ïý¯¾_m!>• ¼c»¼ÞÑ>o$>Þó<¾O-¼¼æ’º<¸ r=™~T>®'ƒ>äs�¾*0¼ù«©>“©ë=íƒ>U>›Y-=~~W½Qd¼›¿Õç=@¾D¼= qƾ– ¾*‡F¾†v>LP¾?êO½£è?'¾Ø®6<òÎî½F8¡>$sô½œÁо ¶U¾'u>2˜`½ƒ~¼>èf?ÕÕC½\.n=<°>Vhª¾/ƒ˜=ƒù%¾Ê…¾Z�¾Ýß”=ÃÓ¾?Ãb¾Ñþ·½ƒf�¼˜uh> ¿•> ßß= ¬ñ>o°a>× ¿˜Á¸=u‘ˆ>à’½”Ÿ¤<An>Àx¬> ¦>¾^F> &>oà˜>ÄîÆ¾5§>«ø<¾hÿs>T9¿>Õ޽o� ¾A-’¾N.Ø½Š½)>ÛÞº=–£n>Ç[¾xµ†<Ìw©¾g²o>©ü½�e'?•ø"¼‹Þ/?9g¼¾mð¾¿Ç<ª-º¾Ƕ=Q9p>ÀÊu¾ä‘“¾ñ6¿œG >n`¾Âê£=ö¶D>N�Ã=¯á®¾³¨º>e$¾ÑS8>öÞ!<3Ì+= -%½2‡Š½¤h1»#Z‚½¶œ=¦\Ö>Ö«±=˜‚1½� >8 y¾¿h¾ìD¾‰ÊŽ>”¿€>©�¾]±‹¾†øË=Ä!¾œÈ=òž®¾aþ˾±2Ä>ÿ :½B}>:S{¾®Œ¾†Éš>2k½¡�„¾0§&¿< =ô%>Ã~>ÍI¾ØS¿û,k¾�Ær>¢ý ¼Þ+?´š`¾¾Aô½‚t¾ ̽=¸ <×B¾ L >ûѼ¤@Á:{.³=ÝL÷=÷¬;ýtÞ>pkÏ>ÿ7½þ‘.>“e>w/z½Œ>Q‚>D%!¼rÈ>x½D"Z¾h`½ÂÀ>=Ñ>§µ6½ÐÓ5¾þoô¼G°²¾$#³=§î¼–tü=Xù¬<Îãh=|˜>Uá~½`2e>Ê3>/¦><ä½4‚©½Ørç>un‡>ªø¸¾Ì4h>Ç)©>%³¿ƒÜ•½ÞÑè>ôÖ]>±-�¾’fˆ=JÂ>;e>ŠnT=ˆ¾4þ¦¾Çƒë½)Ok>Xü½§±¾8X½>±îd=^œ¾O¤Ü¾þ4¾Ý�>]Ìý½®(²¾‘y¾0ä ¾›z“>Ý„S½hÈÝ=P*">S‚©>i'Ÿ½ž‚=_a>S.˜¾n/¾&‰ ½|zƒ>»¨\>ðˆ¿þÕ>£P*>i†žº›­#¿ó½¾û ;c§N¾PNE½K´È=wû<[)¥=æú¹)Òp¾hiü»âº >Ÿ$Â=ÏÍ—=ÞÉн­!+>õ«a>#䫾w+ <¥£<êÀ¼õ…¼¼£I‡¼ÍF>*Ƽ·YQ>CÈ=S{®½ f.>W®õ¾bJô;3'¾ •¾ÂÂ)¾¡O?¾wYQ¾÷ªr½ b¢½gC�>bvƒ=‡¸> ”$½9‚U>ûSE=À/.½‰1‰½dØC¾•¬n¾È[нüê+>§F§;Bc�¾/û¾k>–¾‚XS¾6~˜¾˜¯[<_gN¾ík ½ÄÔP¾46޾>ŸÉ=Þs°½ŸT$=ÆØj½h>?Š\¾äõ¦¾oɈ­Wÿ¾Ép²½X¾Ë ¾1ú>>—j>‹q>û‡Ó½{Cz¾J}½3½ñ>0Õø¾K_m½ÿ¾Å>"œÉ>¾¸„¾Jâàº92>ͫ;ÌÔ>é^ ¾,Ê >‡Ø¿=ºðQ>îÛ†>}‘Ò¼…‚Ÿ=Œƒh>–·Ç½ã ü½{íµ=|’Ö¾ ö}½W%¿ž„=.‡8¾ž}½P$¾â >Sh>øA¸>v2•>–μ¾¨ó‹¾Ìú·¾ì¸�=�$>0É>x3q=…“ë>‹Õ”¾ý×î¾!"=½ö¶²<¥•¨>±š¾Âý¥>n@)¾‘ôÚ=wè7>d`¾ì@«¾æã/>õè<ëzm¾ý×a>ÌE}>>¥=§/ˆ½™5¨¼q®Ì¾ú¬Š½¬I³¾læ¾ P¾–¬?¾†ÖZ=Õ ¿>+Æä>6࿹p>Ç6>¾Å4½ÚC½c~F?ïG¯>þ,¾DG�¾(0>x >Jµw½#;e>B)>>i >€%•¼ï^µ>Ö°ž¾O¹›=ÞB¸¾ Ô°½ÏuË>b¨¨¾‘_ß¾2–¼>�»7¾Ì,a=T†ã»Œ]]¼¡Í=c«)¾‘È>Éó½nJŽ> r =T8d¾á±=—I¾G%S> ½¡>@¥D>ré??Ùö¡>C……½e‡Ç=•„u=rU²>-Iû¾�9c¾ó2º=qÏ>ä»Â>kÚI¾­�Ö>רd=è\ ¼uà<—¹…=+ú?¼ Ö¾ëê¤=+G)=cLã=�˳=ü⾨â’>ö0>½�½hŽ2¾4½a¬=$ò¾0r²½9Sj¾è;}Ðu>™NH½�=&4F»n–V>ÙËÀ=#Òõ½7¹¡½ó#È=ÈÝ>6i‘>�¿–¾®ÉÜ>Kþ±½Ç,Ò=6ùƒ¾dç—¾À!x>NÅŒ>J0z½¨ !½£H½xfɽf$>¾g >�÷¼¾N9’¾åWO¾Îæ>+`Ò> Â¾ÄØ­¾e€=â"¾€ú�>a’`=¡&½LHn>‘=‘>”#>ļ�ZÃ=×ê<’ÔÜ>$»=…hj>Äy">]:¡=ÖA>’Ì‘¾è¯>>²°½Î’@½Ur ¾ðïQ¾~ò!:}Gƒ¾1¾+,e¾bø¼Ôôƒ¾t|õ=ߊ>ó}.½ÑDY¾‘·Ø¼!‘à¾ÊO>+s>ƒC!¾� ¿µ0 ¾šô¾yš—½NåϽì6*¿H=2Ó¾ {Ù=pâ>ÈYÖ½Çá->íS°>2b¾þF¾Š¨Œ>ãnª½³õÖ½i~&žÍ¾ìï¨=c^’¾ðAG¾òJ>@ïâ=e†‡>x`œ¾ø°Ù½!¥h>Þ¾g@N>倾è¾�½×Þ�=ÓL >0åû=J£s½‰<¿=Ç¢c=Flï>Ôûú½¹ý\=öØÈ¼üë¢>�>ÒȾéÝÕ>ìÛ¾;‹ŸÐwÚ>dð‰¾A:¾åÇI=QnA?dˆO>”¸>'pH»5¿!¿=œ=4³¿ÉŒ·>@Àç=tMé¾þ ¾ì2»¾B${¾'´>�Õb¾bfê=’%>Ç,>“œ=ïQ>u_>>(J4¾Ð;º(ªÃ>D >ù>� ’=ÕU¾Í1Ù>¶ë€¼�ãÐ=rˆ=¯ö.¾ ·Ž¾Á ¿ôúÕ½A6>.¤«>IJ==Ö/ ¾tˆ[=À8~½ä¼Å=\µ·>>¨�>„qõ¾.½ˆ�º=¬óÔžŽ¤¾¼-V¾�!t¼‹Óx=|‚‡¼Hçù½ìŽb=Fam¾%"=J.>_�Í>ÚÑv>š¨m>�Ǿ¼>ç½8$¼¦ò@=KEÜ>C½ë@>™³Å=×|5¾Þo‚>M­1?/S~¾W7-¾–¼Lº¹A�>.'?Ô¤¾B‡>Þ%½;Á>ÉÞM>nŠ>±yx>qƒ¾ ôk<&o½ýÝ>¨Hõ>wy‹¾!H>{b©>5Ù>�� ?>R)½?òk>‘¡<°Ÿ+=Ù¸¾½]ºŠ>¤Tµ¾!®¾M½²”>ŸOоêoݽ/ô�>4�>Çz‰=€µÐ½ËÖ‘=ìó ¾gXÿ<ë;¾eœ¾´°»¼þÇ>Â>ü=5E³=æ7¼)åw¾ª â=’>Y¾¾4¾Œ‚¾3.Þ<—d½dªºê½Ä=Ú¿>ÈÓ½Öüº¾‹»3>™u×½ŠË>Õo¿=³ß®>´u>Do¿j@>ŸP½íl=¾ý~™¾ÓÊݾç])»uÀ½—-p¾ƒô;µÓo‹R_¾2<.¹~>@>31`>û.�>)Þ…¼ñuÒ>/¶>@â¼óû¨¾ã—½q‰�>Ø>ÑgÓ½¸¬�>CØ>=7”5½§g¶=‚"’=è>½xI=>�> 6§¾ @C¾itð½11>>{Ä&>ö­¾ñì½em•<Á …¾Ƹ=öåÞ½s޾ìw¾ð_©½'^L>¿“\>"�¾vÁÆ>2PÁ>p:#>˜Ä—¼è‘¾Q­„¾×E>0¢'>®Ÿˆ=Ï>Ž=L뺽#%=&œî½zk>ëG¾Ä#>j �>ô´¾/óñ=½—w¾�o½Ÿ:¾�Ÿ½ø.½ç½#½²Gš¾=[>ÏJØ>$%¾º4[>CÙ>,ó‡¾,¾¡>bEb>âW½g–Ñ=½& >+<ü±‰§¾ª !¾ÄZ¿»VÓ½½™½Ú–˽‹]¼:¶áV¾KÍǽ ‹’½É¬î=d«¨½Ø–‹¾…Ñé¾íE˜=y2!¾[0>^ÄľÙZ+=ŠÉ²>"ù¾}’>€#Q¾Ï²½û'?ÌÅŸ=½@)ú<{st>Êò†¾lo>ê*d=Ѹã¾à ¦½І¾9-œ’Q³<üø¼ÞB¾ò+l½¼­ô=& ò=æ(¾{×r¾ Pù¼2¬¾´Í±>TX¾u52½«ÈW=Wm >Û¾3¤˜¼Õt’>Ÿ�»,x,½.bÂ=‡ÿç½<ž?¾lš½¾³:“±%þ½Ìûð¼ˆ.½(�‹=£Sн¼pS½ƒ¶½.ûÞ¼*@>!OʽSÀ}½÷­C½õ›‚¾âè>w1ª¼Ê~º=ÿ\¤>�>ÿ›>ÃÑ>Âù>'!ä:›�>pê>XÊ‹¾MB.½w­=0<½==¾P×软úT¾ßøÜ¾Ð÷Q¾å´ >L¾=y;µ=œ²A¾-&T>f«=Å¥J¾vh>Ã% ¾tºâ½™w`¾Áœ9gW‘½a»"<×·¨¾¡¨¬½¼!<.šl¾–ÂÌ=”0=™ >Ý›N>¨>@ì>K´ý>A]>¥2v¾<�˜¾Ž~¾´>Å<‰=;œ’>OÌŸ½�*¶<ð&3>H¿…ßœ¾»�½ýã&¾cb>� ’¼%æè¼¿µ•>‹úÍ='ù½ãˆØ¾¾-¹=ï’x½H̉>CÁV>†û†>�«,>œu.¾ ŽÏ=xd>àÚ±;c£;\vª¾È¡¡=ß¿’dܾ‰•n¾ÿ�¾]½Ö>%ôâ>”dô=¿\ù= Rš½À}Ѿ‡Šž¾0gð½¡<f¾ÎC>Œ˜==£'ÿ ,¾‹˜´¼Nùa¾ xQ½z.o¾‡Á^<&Aç>Üu>�øÚ½©L˜=QË´¾M(èº*( >¾!¤>èá>>Hç’¾êÐ;>Èå#>,¶˜»[û�<Ò^�¾>ä½¢èÏ>•b†¾gÃç>‚mÈ= ï=$Yú½¾‰¾µPb½n×ã<ßoJ¾ÿ…á=I Z>còú½ô� ¾6¾Q0m=²pâ=õ²Å<•m¾è§>O° ¾È“½ºµ´>+� >v 9ú`ë¼ëŶ>�z'>Ä�›½�Qj»u\¼½ïÃt¾«?¤>U­j=Ö{ø=í^¨=ÆÀ¸¾|f�¾ñƒY¾üÄ˾OÕ¾®Ø“>7'Õ= ʼ¾áÚ=sývá—>±1¾C÷5>ôY�=k›¾Åí>LjŒú}N½(øŸ¾]é·=liо|<\¾ù ê½ÛV½Ö ¯=TÛ=>™«Û½pv>ä7:¼„ <åï½>hÃ;¾êÖ£½Bë<=ãH¾#áØ;±9¾g½�n[=W›¾Ó=±µe¾#º=¹ë¾cB¾æ•0¾Esš¾…¯> <~¾E;‰>z7>å?h½œ¿¿¾Lƒ¼qUõ=�Ä,>’=�>:=¥ö‘¾Í-=Â{n=—ä»>”Æu¾@c¾iV™>ôïò½NÝD> E>Ôq³¾’B&<†‚�>Û÷·½?ÑL¼;Âx½Œœ=>Lz > ŽY¼læy½vj›>èa?í—¾4…²½ø›´¾µƒ7=ÞQƒ>$<:é°¾mÐ>Îì =v�+¾à@>¾á=|=3‰½û2>4Tn=Ýd?>Jd¾Ï%™=-Ä—¾«DD>fvS=à´ì½;¬<¸I=gø>½u®>‡#­=Äú¾J�(¾}1#>ȹw>xk ¾Ä¾p§ˆ> O½�]Õ>'b6¾k�÷>‘—½²Á½¥(“½Çmå0Š¡>Glì½J±j=ÞÑ>tD>¾Å{û½K´à½»¸,>tp.½�/‰=»9<�R¾?=gây=*¾?½Í,j¾$>½WËT>l½½–Û¾½Ëzôš5§>ªÀ<©Š¾ù)9>ºòu>³·r=´°¾sä†>­”ç=©±�>®é4¼4½=ãþQ]n>îó¬<Ü>HÞf>tß=Tm<¾À¹Ì½d>í¾©Ë7=wœ±=Ý>c>í… =éøF½ª×‚>GÔ½øøÍ=úÔ?%­={×;>­Þ<ñJ>Ï-=šX>´–C¾mV¾1Å=w*Ù»Öµ½ÿT°¾ö�d¾ïýPÒ”> ½ÕܾЩ½½Mg>zˆb½×~×½±¬¾óuÖ½èTô>¬K‘>»ˆ°=¡H•¾S©E¾Ü51>°®5¾Ä‘�½K&3½º×é¾êbÇ>¾w¹¾m ¹½ö�>*+N>¦£=Æz¥½‡ƒ{¾}z=d¢_¾"Ò˽>¾ßéÌ>gž-¼¹B>gU#òY4¾C]”½À3ó<:�ó½¬Cv>ٽϪ>Ï]>„G>”Ûg½_Ïí>êuv¾÷º´<�Ø¢¾K`b½JÕ�=f½ >ã@)>óf�>gо�Ê€¾Â(=²Ðè»—íý=ðvͽp¿Œï]>·Øó=+Ñ€>.C]¾lòû¼¥¥R¾pùÚ=&Õ=vâ>rŒ<™A‚>å=œ>€Zj>iÙ>)uœ¾AßP½íi1>Ÿ^�>ñ(£=Oµb>XĆ>U>á=ª¾¢¾¹!p=s­¡½šº’½'‹> bª½wFÔ¾9î»)Ÿš<ïÛð½ü`²½â± ¾é5½½“@>”{Â?cÅ=-0€=GÑX>þá½ZQ2½”`¾9ê=Nàg¾Jнs‚Ø;è¹Í>šØØ=)÷_[æ¾]Ò¾X �¾, ­½  _>Ôµq½Œ•v¾Lm½ªË0¾, å>–á⽌uå½2ˆ`¾þ0? ‹V¾O_‰»s±}¾#ˆ+= Õ×»ó¹ñ=Þö >A;c½……>æKQ=­I†>цƾâÎ>¿o½]ó<ä§�>Bç½^M>Íi>î >§¡»ZO9>ã.|½%B§½ù¹¾!pM½Aôƒ<çÌ/=Éç=—-­¾†ö9¾YÁ> ï>•†£½ïóŒ>Õk�¼šO�>�×>íê‚=�þ5><0�¾QÖ½/1=Ë !¾g>Ë�]½í?U‰=�È,¾G"E>~À‹>Çâ>õ’޾Ê}t>>Ò¾ÿ+G½”£´¾È¤­½œTI>0"Z¾…`-=‚I>¨ô1¾t‘l½P›>Y#L¾àž >(�)= Oœ»Ï®Ù½ƒŸ=/ݾfûH<V„>NE‰¾"}¨»w_ʽP¡>ösh½Í.=ö¿­=¤ûǽöº­>Ào¾[ß ½9F>41 T¸¾¤¸F¾3ƒ\¾µTÑ=P*2¾©¨™¾c'½½‡ëŒ¾Œ8‰¾Ë´Ñfdš>“z+>‰=ÕØÙ½Pg¿\¯Ž>êY;>~P=4ѧ=‚°W= h¼€p >ÎI¥½б¾Ñú½Õ˜S=`MS½S] ¾O˜Z¾u؃>~BÓ½…z/>MÒ®>„¦¼ƒøl¾ ›x½©­ó¾ÖÙ½µy˜>†¨�º8y/=ËT}=Ä÷½<�>ïÒ=Mi[>FÝŸ>2>¬]¦¾ç¥ý=o¤#¾‘å¾Üà;N‹©=^T¼î=û¼/8>‘9ú¾Äô»>p½JÇ&¾£é<ŠÇœ½ñmƼóÜË=¶z¾2¼q½7,¾aR=¾»oW=~ZÂ>¤4=‹Á½Â"W¾ô�®¾!ݽ-Ä>¾Ú¾ÜT[¾r> M>ê?éSá>4Pê=X�,¾‰ÔÈ>ïœv>N¿„€?_�Z>åw=ce¥>Ý>˜†¾¯k¾ø‹>îh¾Îð?Eªi>ùnüܹ=ã¿,þ,>ÉÄ·<ÅF¢½ë³I¿“"o¾8LJ=^6>˱h½)B¾k ã¾ s½£�r¾–œ_¾ ~ù=ª ²½Lsg¼H/Þ;¼‰%>æ‹g>öÅÛ½±H½<{ÒŒ>¦ÖÂ=¿kw¾³ÝÞ>€ ´>ú€=þ©–=£Ô¾.Ÿ;—<öç‚<q’½Og(½"'M>ýx7>•›R¾ˆš]>´zŠ<�œ¾è%>…êÃ>Lì­¾,ü>›­>«¾l¾hÐ>õÞʾý¿v©�¾Á�B=íÕâ=®Òo>1¾ßæL½ü±Å>«Ö¾–Ÿ=ì¡™¾Q^õ;4Ò¢¾mh¸¾r·¾^â"¿Ý³>²ÔK>eâ>O†•¾Øo›>›2½]G¾^½££j>Àü—¾¼Ò >޾8XÙ;¦ëµ´³>§©'¾Ç•Œ=×ñ¾÷oz>L3¾&b=eN> ·D>¾|¾¿·h>:µ?t¨ù=‡žÆ¾µ³‰>ËDÞ>––>°B²<»ûS<9É„=€u¬¾ñc�½Óº§=‘:>?j5=¨7>*¡ƒ¾oÉD=Dáò¾¡ä»=…hÓ½Suå¾M®=>QŠ}=�+¿½`ˆÇ½7Gì>�(Ö½RÚ=Ñ炽£Ê¼N ýîÙG=?&¾=Ç=¥Z�=ø1¾Ø ¦<õg½‚u>ÁC½ò×S¾!W=o™¾¥Á?=(Í¡=Áþñ># T=zçR¾fd޾ӄM=b´–¾ÎXI¾E†Ø½e/$>Q¡“¾˜Ñ½B÷ñ=O`ž¾nw¿i¾²7›¾ž‹ >Í�a>m½[ ë>2e¾�©@¾�E·=ÑéÍ<¾dz¾ÄU½¸1ĽÛlq¾Êf@¾{ <ð6 ¾w>Âż�‘¡¼_”½Ž†/¾/Çã»N=mǾàF€<™\˜¾F¥T»�ÑŸ>ÜQ°¾Cœ¾™ö¾=Á.Z¾³É¥>]Òs½ô¯Û½›â¾+Κ>¦î">$"N¾rFؽC@ë<›ë>Wìú¾†ªR=óg€=ˆ}¯=l=;:ù=Õì€=øpO½¯$¬>„☾/¼»=D@>£ s¾Ec¼iük¾ÿxû½™+ö¼^•ô¼Þ4Y¾³­½Égˆ½E×½ÍÍ…½¹ »åx >ÁÊ<>­!C>Ì�½giù;MM¶=ä�^¹¾Š£=¹¾F2>$)�¼Ï•™:Þe¾r[{>‰©¾·<•¾>_Õ=Ö64¾½°š¾]Õœ>?ô½@…Y>±Ëý=œo»M,A>$ñ]¾qðL¾¥Ì½WE¿o`]>ûƒw>Ÿ;3>3Ô—=c>I>^Ì&=v,4>T ½ÔÊ×½ÏÒȽ`×E>E;¾Fo¬¼ƒ8¾ë;¹µË=�9ƒ>RÏ-=z㦽ÛåP>&CÄ=A�°=ÏнÛDK<Ö¿¼½¨¾Càw¾Ó޾pàB=΂f¾¥�X¾ ¯Œ¾<“V¾�·‡½;=îI¹¾ýM�¾^¢Á>éü >Q ;>f3C>…Ô%½YÁÝ=Ý©¾÷Ù½0â>m™�¾Ut&>E8ý=±Hœ¾0À>¦à¼Ç×s> :>Sh=4æ½>N¾k®ì=pRz=Ãöè½¢õ¾|„”¾|Å×½ ù`=þõv>”{¾s˽JÅ�¼›½*•p>Šn>aܾ<=÷h¼l¾í÷À½2÷D;M½‡”'>(0>,>>§ºÈ¾̉<æe•½3\s¾;д¾'D=Ô,Ë=b.¼x¥€=4UÈ:èãé½V=Â>úÎM>ØÊ>ëa=a«d¼¹È=p›“>`—ˆ>˜¾Žžö¬¾€…S¾ãàé>;ÕT¾·P^¾-–¾„H¾ h¾G˜<¾­Éx=ƒØ>è%#>¶"¼'«£>ݤ¾¢(í>-à½ä(ǽÌ8>UGñ<�!F<Øï�>Ô+>„ã=�¦8½˜›”¾ h²½¼ø¾²«8¾Ç7–½§Ã¾á"¡¾Õ[¾™ñZ»&´ê=Š}>?8Ç=Ñ?—¾“…?¾n³Î>Õ†=ˆú½Ü�ʾÙô­¼ÀEŸc>Ί<{Æ=A¼ö¼Y&r>á¾Gõ›=õ-ݾ ¾ë¾¾‘j>ˆl&=zÖY?m¾?¿)¿+„E>‘”w¾» [= ½=t_½Á“@¿e ?¥rŸ½I ¾Ìx©>�G¾^}S¾•½Ä€¸¾_÷E> »L7->ï" =oB?Ç A¾&t‰½ÈR½�ƾk~Ü>Líw¾¡‰Å½)]ǽ¥’ƒ¾Ö*×½`y>>Áž¾$è>¹£C>ãÓJ>~ü“>q4~½J­°½Féó¼uÓ`¾À ¼ZB9>ÒŠÇ=±¥½+¸=>F >G´>ƒŽ>ù—>R ={´„¾éþp>r塽[{û½V=A¡8>€—Ø<>0ξ€ûC=�àó=0®#>#æ±>óàR½¡´>ù×^>ÒA ¿¼Žu¾POg¾Ó²è=øO(¾BPˆ=iÀ<P+=FÇϽ“>`¸P¾Ÿµ+>D­"¾Þ±Ž=�Ⱦ*æ7É›>ͨ&?n¾xô=ìð>þó̘>ÿƒ€>Öþ4<ÖXp¾”H >IJê¾;M.¸^yG=Æl>ÈÁý¾ˆ¨ö= ¾‰¾Mb–>[;#>ùtH½|ç =,µo½Qùš¾‡À�½6½Î㪼[ª6?‘ê=àç,<Ž'£¾¤@j¾Â‡¾¨Ñ>™ß<=¹¥¾Ä’>@»=»Ößò>“–½áìË=iE;=�à,¿moT¾Æ‡“>ŒØS¾ß>[À5¿Æ »¼CºÀ=Lè?XvO>:%¾XÍÀ¾r€‰>S”y½+‘¼>�X¾¤œÙ=÷�¼Ô¡´>®®r¾þT{¾¡>¿�®¾.,ï½:B>é噾Ú›¾f;ƒ½Rp_¾P——=Ü_¾v¢>ñÉ>ïÏ>M‹=‰D«<Ö9ì=Â?ö>Bõ�<ÿb¾‡.š=©–Þ>�Üf>LKr¼E±•>/�¿•‹=Úß…¼†>ix½ô%@>-"¡<’*}½§û½–Ñ”>1â="·–>r®B¾x¨/¾�í'=S>>w¦Å=¼™>·“·¾™î">_™î>ÛÕ“¾þ‡™=ó¡¾ÿ­ö=ƒU ¾ôåF?‚¥>ö¥¾Û`>?ɰ„>„” ¿ÑvѼÉ�¸>Þ¨¾=�½¼“Ø!>�ü�¾ZȾJ_(¾fá…=Ãúú=‰®½½¼¦í=Js£½ù¨;>Šb>öÂf>�¼¾=Òó ¾^º¾Ø£=£:^>0‡>–<æsè=Ÿ­%¾xü*>££!>Pª?Ç`!¾Ò C>” >þ‚'>'È•=Š`è¾³‚å¾-Ok>§iÆ>lèþ=¡hu>·ôŒ¼Z–>ox)¾”;$¾d=>ÏK¾eßÔ½G·º¾�êš½øI¾”5 ¾¡J>Ę¿Œ½/¦­=ŠTÁ¾ž¯º=QŽË=kAš¾fXÛ=ª±¾±/L>÷~®<Ãá´=¢º"¾XÄ¢½Bôþ½hT£¾WŽ’>°ˆ¸>5,Ú¾?¬¾ëíp>‘ì½x!>=ç|=¼ê–a» ÀŸ¾ >d¾ºÚ¡=óJ¦=ŽØ�¾«â\¾”<>¯yC>G]’½;7†>rŽˆ¾ü²e¿˜ºj½9𤾶°¾!6ª=II¾Ý÷™¾MÑR>¥Œ¾Õ/>‡ù*¾P—à=Íà"¾ž²?;¼´b†¾¢mÕ= IÖ¾‰(̾þ­M>&vw¾g¤=HÉ‚½ç~Á½ä a¾èš(>@$e¾®S1¾èel¾K7¾8»<>WR£>Ï0›¾¶¤?ò³÷¾@ &?a¥=1�Ç<™ò=9m€=N û=Ôd¼ñka³¾;�û>0år=Il¾•×F=;§>ÛÝ�½Dy£½5Ya¾œÖè>¨> g>=‹Š¼¾Ý[­¼ ˆx>Ðýð½Sæ®<n>Š?YW¥¾n=jA½dŒ¾Î¾œ§e>›]¼«Ê ¾ëÖ>~Ö¿>DÇ¥¾Bæ¾Ð�">»²>¡H™>‹²>h�=êZ×¾ÝÓ¼O ?–¾sy ?=!õ>Ù!>½GW½´Q¾ÈŠ+= (6>ð4…>fè¿zh>ý*>µ¹¾I<Ó¾ÿ�>ëa=!ÐľÁÓ’>44оµ}>‘‹­¾Ë #¿H2>›Ñ‹<Ž‘Â>oÑ:>SÞ%¾x4½N’¾ß9¿î“¾Ù¬=[è>@«¡¼Å—×¾µ÷b=)uS¾nz”½3õ^¾º(ɼ ÝÏ>/<ô¾›D¿™£Î=z�¾>ͯ¾û7±=r%нH¾e=ØÕW¾™P >2R¾Y|=žr.>ø#+½ûsë>I#/¿%¡A=ú¯¢>sª¹¾M›ž>c{>, ˜¾ ~=š`E=»ü•½ƒ¼„ ¿aÝ`½|·´½´†8¾^&>ÝྣW >­Ð¿Œ6?¦‡ô;K“‘=r!꾎”¼p>”ðï=’j?ˆÝ¼ô ê=x]­>ýÇξ,郾˜&§½mR º“mŸ¾…y =*L¾´†>ö€>ùño¾FZ¥=©ëa>­?ÑÆ‹;^W¾Nýý< €?)Ó>(Y¾õÐü>L¯C>ô >*(Ľ¾Q3>KEM>[¤=Dœ€¾tû>š°ô=†9o¼hî‰>3õ’¾%èK>P•â½›²¾b" ¾Ôm¾’– >D,=nÔ¾|ý½d1—¾Íò9>ra ¾/£Ç¾�ß ?š•½8ÿ>w` ¾èl>YÏï¾�±æ=ýÑ>‹Ûؽwa�½˜/<Å¢½ý ¾iÌ·>6¹�½–¿¾¾ t >7j; Õ=š"m>³b,¾t '¾²r¾®ô¾�‰š>iz¾o}F>‚Þâ>”Äý¾0‚ξ%ì”>3rî½?×=öヾVí½J0Ñ>ˆàÖ½¨µ/>8¢s>LÒ¾¾0ò‡¾•ËJ=å8Œ¾¾‡Ê¾F1j¼}>Ý ¬¾ñjÌ=Á@ƒ>äv<<¹оc«=~÷<ö#W=%×p>”ãÍ;B©|¾DÙF=œ(¿äî~>ÞB]¾ì´W>‘i¾†U¾$¼½µ½ì¼ëÙ¿6›¾ïí¬=ö>Î�޾1‡P¾· I>˜Dj>ÙX1¾ À ?w˜G¾ÆcÔ>VÙô>…8<¡=¡C?jŽÎ> ú,½2*¾@—c={rs>C|Õ>ÈŽ>ÓŽÝ>1Nν¼Ú'½‹y9¾$lã>À¬Q¾Ab¾9o;>Åb>îd÷¾;ÿ?ØÎÿ=oå�>ËñV¾K=µ<”yÙ:½w"“¾}Âû¾�1p¾z1X>^Kʾzüt¾ùQ�¾jÕI¾Šg¸¾[-b¾‰m¾é�>4Y½…�B¾3¼ä¾>£t=Z €>¤a°=k'?–jŸ>ò�¼½D,>ýÑ=fÚ¾a¼@©Æ¾ÔÈ3=/à­:…“H½‘Èe½>t¾žÚX<_Ü‚=…Mx¾q4¾‰‚á<]÷õ=èÚ>�}—>-s•¾œL¾ã„>í†4¿ô¬®> 5>Uœ<“>ì=Å;@=7Ý ¾Ów/>ñ94>CJ¥¾$˜à½zw>Ô |>ç~>IBÃ>Ú‘ª½U ú=\"?Û«;?êAœ>jI=SÚ—>æ?¡<&³¢>Ö>bÁ¾s÷á>øÊp=hu5;~±>J@ ?O�‰>« y=æ½2}£>FLã¼ JÆ<•t�<Òk<=ãN½Z–ºÀÏ>½…ƽw8Ë=ý�=Ë1?½ƒ>bÄ{>H´ó=m»W>âî>eΛ> =à<-¯½â,é<îIÉ<³-è=£Ï’½i1Ž>æi*¾Í•Í>ªܾ"ƒ>èX齑‹-¾Ò´#>WC.¼Dî’¾O@>BìÎ=æü+>xß½ÜT½Û˜Ã¾�y¾bv¼¼ö¤¾RоO@[½}‚}¾O^¾=?Éy>Õ1!¾y*>® Š=§ …>« 9>t�=ÅÄ=>žØ$>´¤“>&+ë>桼7;f>²QY>qd)¾L]¿/q¾�›V¾ÍP‚=Éçx¾'“E>ôå>ûº>WNʽ‘á)>u"—¾±•½>¤?Hí¾²ÕÛ¾æÝþœÓ¾)¾jû<>¶óñ½Dut=.®*>�¾É=›’ë¾21>ž¨é=‡þ›¾A\\>[Ïœ>HLj¾¡�¾¯Ù¬¾^v>3}Ù=9b—>È^t>$ϽËó½ü�>}zÊ=‹ÓG>ò–¼¬ò0¾v¡A>çç»<~›]<Î-&=á4¼Æî=}+¬¾Š}§½½ŒŸ>€*è=Ù;ô>ß^�½-îA>V¿¼RX¼4íÙ>�\«=gך¾\Îȼî!>5B ¿"ØA>ýæ=`Öå=öW>>Mž¯¾Ýp> ¢Ý<,Òk=À6½7‡9>u’½ígZ>6è8¾S$¾—¼3>s€½®”y¾¤£•=rÝ·¾pƒò¾r*>ê Ò;¦U>³”i>¢©‹¾âó¿$‡º>É�d>­÷;¾á@0>½ä‡¾ÅŽ�>ÿØ»½é¸=Q�ˆ=ç—¨¾„5_>êÀ¾E´*¿º$:¥<<ÆU˾Ú!÷<# ¾Ë.h¾�¤]¾\ž=­ø<¾ÖZ„>†.?ãƒ<†Õ¾:ã ¼uíÀ>*>k¾;߯¾¶Y¾>3Ú)¾:Ç¿ç¼=íG�¾g¤>˼~¾«›p¼û†@½Ôuî=§G¾l=>ËÁ¤½uU±¾`å½Ds„>èÎ?]Kl=o©E>}êR¾®ô]>>F=ŸI-¾cs¿:Ó—¼<ØN>pZ*½(=|~ž½› “¾Gû>c:€½ãe¨ ¾æ¿ë¼¹™w=­Á==/&¿?YŒ½~.¯¾ž!-?Á®=R#í½»„'>­��>Žî¼>45½ÿ¡+¾Õ5d= zÚ¼!I…½†Pj>4u½§¶¿¾°0=¾P>D¤¾·x?WÆ‘>žàô=Ú8ˆ>Ê€¾M¹m=&+¿iw >E͉¾èßë½jïʽA‰j¾ï3ö<Ýû½±Jˆ>E‚Ù>Eâ×½Åôe¾nqá½}ÄC¾…CD=4D=åîk¼á¤…>e]8¼�i÷½cj©¾…U:¾Í=V=¢ÎÃ>~c)>¿|æ½#æý=!ñü¾ù =7^>Lã7=Çf»<’âu¾½ôþ¾œº»=C ¾¾ à=T‡D>gBh>‰òä½{f‹>’™>v»¾Æ¦Â¾L�}¾ w>‹ŠB¾½–Ü>6>IUP>3g7½:ö<ÀȾýùÔ>ÿ$7>«U¥>s¬>=u½�h'>ˆ?¾ÛÊ×½Cú>/™¾?!¾¾íT¼Qq¾ÝÊh½�è#?;B?>R\ƒ>·?e= =è¼Gö>w*@¾k2ñ>±ñ>pðx>$â > N©>k) ¾Œg°¾#¾û½p3¾2 ½*5Ë>£ÛP¾XFŽ>V_n¼®�ò½On¥¼|ã½C€¾÷Z½‹¸s>«œm> ›¬¾6ú ½-°o=»:»‘'>í?Fj>�¿½³g ºÒ:€>‘Ī>¢J<™õì=hrF>µë¾§ò<Ï‹>Ç—:=Øz¾=˜gH>5á�>"¸“¾°WÜ>ÞŽã¼)·4=Ù\?�W*½]w\>nM…¾‚¥Â¾ÕqF¾&˜ ¾êÒ½06¾ï>Çqt>vòz=¸3W<ˆv<’Åé¾58Ù=j¢Ò¾Ô(·¾lS½ˆúÈ>Mh¾ïû>ÈJ?MÉj<Á‹9¼i ~>R_†>t·ß¾ 7½/ª >*+�½#G]=RTp¾ºìØ=Öñ®>Ì«p>Ó¾65£:ÉÀ½¤-¾¸…e>]«>î ¥=ª9'¾Ž¥Ú¾'1-=œd >\D¡¾¼�Î>p}ú>¾'Óè>á�š½Q�w>\¬<üTݾn/—¾ó}×¾HÅ»Nt>ûù=e�h>+慨›s¾4©w>¯ ?�$¼4In=ØHk=áU7<`“x¾Õ—¾»6T½?ô{¾ú—/½Ô@¶¾bV¨½}æä½Å?m>º³Ô=Ëý¸»­�¾¿(>¡Dd¾^19>ºQŒ½én¾R×¢¼Ôü|¼‡1>­¦Œ>u³¶;ø‚Â<Çùõ½ª­Í¼Q4n>±Š¾X™Ç>Õ"ù=õG>`uǽü�k>¹èý>Ähy=nº…¾ç&ã¾Æ>Î¡Š½µ² ?b\U¾OÏϽÙE5>û0Ë=F@¾Œ·œ>cñ�½’Lï>c)»>ån^>ÈUk½�ýL>W½¾KŸ(¾¤·?þ)¸½ª$V>ø‰Œ>qND>³a¾¼‘> Z[>󸔾ÞÉ6> ½«>¿š¾&6Ú<-4!¾ó ¾ôPR¾(p>Lt'?Ì K½˜§—=àz3½^Rs¾#�ë½ ’¬=ˆY>¬í©>¼`¾œ(à=é¥=ÎLŸ>Ñs°½ÍÞ=´7c¾åÙ?¯«.¾½EïÆ=0»‘½ë„ã½p3!>ÙЈ>â§ ¼,_4¾+½»h»â3€¾�Q½¼Æ‹¾m\�>¼ÀÔ¾Ö�¹¼R™ÿ»UÏå½ì,G¾›¢q>íHÿ½ Tb¾Ùâ¾¾¡ÏR=dǨ<ú®½> ¾éìÞ=l2R>«= ôͽ¯Ká½³)¿Æù�¾­¤š¾P~O¾±$?ÎÃØ¾À¬V?µˆ¦¾_5>ö,+¾tË¡>Æ5⽫^þ¼8°Ï>H¡J¼5¶j=&ö�¾êBн9Ë@¾ ȽKܱ½…—®>ïx>4Ae½Q¯>}æ|½Â“¢> *=ì¡=Çê<>¼Î=`–|>‹¾Ï$?,îF=þ¨½Ÿöm½(E½ÜOR>:ª!¾Ø®½rþ}¼=+$>;V¨»ýË’>[Sy½%ο< CÁ>Þ«R>5è4>Øy+>_!>¾�?¿É-(¾y—�¾ù×]=ú©Ù½ºÁ¾Ûμ=›9b=¹¯õ=[ñá=u7‰½„›=›­½˜ä…¾èV�½,9=öb¾wn=>Ã߃>£g¬>�E¾ÇÑP¾ð?"½æ¡Ö>J¯¤=ˆ–ξŠU…>Zc2¾Vª¾YV>e~6>“‚ >J¾õ�z¾è&W¾Óyû¾¬'Ž>Zqÿ>횥:P&�¾öˆ>º¾WŸ=¿F�½rII=f"|¾þò=Sq$<µû•<� >»=R�¾.)¿&s=8.X¾19ò=Ôïƒ>zȃ¾Ðו¾Œp(>Y)~>Ï9�>œ=l>®Ãd¼H^ž¾f˜~¾'(Í=šM-¾ÎϽÙ@>Ok>/cª¾Ú‚Þ¾�vŠ=i¾)¡‚¾í«¾]ÆŸ=·ð�¾=Á±>|Œ=¨=]¾ÿö¿uÖ=ôÒ§=’ö¾y5Ä>ã”×=ïH¼å±=\Õ6½^N>9�<>&j‡>1¨\>p¾ŸÓß½sÕǽ@÷ø=²3´»AF«=Iùî=Ì<޽†k=·1a=VŠ«¾¦?m>œ×Ú>n¾R½…¼›=øK¼ | ¿iè>%Ã<>©l¿'˜>Ô¸P¿œPy=– ӽŮ=¾³‰¼nt =În¾»¶hÎ=�%?£kM¾®mU>(ç>3¤“=ââ=—Ö>´ŠX>²2*¾¨g‚=Òy̽2쾡{¹¾÷qy=“ú¾ë¼r¾`t=ôwà½ÚL8¿ë™ ½Ò•=jѾs ë=| ,>sÖ½¦ÁI=V`ü¾˜k÷½õCv=j‹f¾“y>ò²>�›b½ú©i¾ÇQë=ÀA½°ÚZ>Õi¿ö««=%˜P>0½|ÎÆ>M‡ý<ÚÙ˜>ôJ‘¾`Ãh½¢S¬>^P¾=Q®�¾2“v¾Ce >âÈ8>s5>ÿ0<¾Í^> ”ä½K3©¾ZD»>Óy½Í꡼ t•=^Áƒ>cIñ½ÂdZ>û»¾h>¹2®¼mg=׌ˆ¾›È¾P%–=LÕ8?ƨƒ=r �¾`Kå¾É®Œ>úú>œ ”>!ZÂ>Vò>¯[S¾% ½Îżë?$=ò�?¿b‰¾ìù˜=q¬>G©Å=†r¹½ÿû—½Ñƒ‡¾Öii?ˆ×Ù=> “¼¢Á½ñb7¾C~¾›Ìò>Ù¤ù½b—ž>½É_¾Ã¸‹>cØ¥<÷S¼>aSQ>ÑÂ2¾3Œ¾>hÖ»¾¿®8>Þ[\>A¡°¼·Ž¾š9l¾Éªr¾5ÊF¾™KW¾¶%^¾_ì¡=)­R>½‚íºÔ ¿Î = "¹>g¹?¿®b°="µì=[ƾ¼Y=Îȧ¾è·l¾ÔXn=â)¾š¥$¾ :¼½þ œ¾ 꼌ã–>¿Y =Ùt’>¾b¾¿� >¼sÉ<ú…>È"�½�ð>‰‚о�·¬¾R=>}£ï=Ó ¾ŸÝ�¾—š¾‡OZ>潋öt>ro‰>ˆÏ=‡�:=£T²¼è7˜>š ?ô=V>›â¡½> ?Iµ¾5¦÷=&ð%>%É>ºuú>žk…½s8¹½rD)¾Œf�º9ˆi½ëø=b ">ýÂq>®6¯=ÝÂá½—޹¢†=š„3=ÓÍŠ¾” >Þ™½` =‡©=å,�>ùò¾,Ç;õÇ„¾îGî=ûó>äL‚¾^tû½Äí¾¬º‡¾—û¾U÷ê<¡&/¿n/¾älÒ½$¨«¼/þ'>è´¸>³[츗€°=ÞÙô½ÇZF¤]e=¥ ç<C·õæ“>S[3>aW2½ñ¦?òÊ;¡óª<|­¾àÔ>ÐQŸ>™8=íßJ=yË>½®>:6´=]Ï>¥¨8=H’n¾e1‡<‹ˆñ=˜¦’½iʃ>/\?7û$>èʾ¹8í¾ŽÃƒ>52>÷Aê½~IŒ=1¤®½ "r>ÞÙ>šy>™ÂC>£‡ª=#E˼ÔÇõ=`‚·=™í¿-Sç½ùÄ<Ù~¤¾ì—&>M�Á>qòœ¾–ª@¾´¥<²£e>#¦�¾ü1#¾už»=œ/µ½­ms¾C­³=b²;®­>¨º½½€U¾UÞ‡>ßSl¾©�i>m/œ½¾™>{>ü=ôˆŠ==�>J&=; ¿Ûî-¾³p™¾÷'›=£i<¼:¡¾{b\¾‘>4\€¾¢]«>›6]>jPe=EÔd¾t‡>3Ã>•UC½Æ`=ûÃ2¾4£´¼z�¶>˜TW½ Û:¾¸á~¾£úË=ü—î<··<¹A€½JF‘¾föÿ½Û°W>«ì6¾W6J¾Þ>W|u=©Ø™¾QœO<Þ+ò½“—C¾;âÚŠ>Dä=Ô‰o¾Du/?ï:׽ɹ×>­i4>&æL>­¹“¾¥&d>&W´=öÁË<.¹ú=ʃ@>ªú¡<0¤ž¾Ýºä¼7#>Rq¯>C�†¾µî‹=–`¸½ÂUaŸ¾Xe�>žæ">|0>îžÿ�>¬m¾Gk ¾Ä�%¾­Oɽ¢Ðݾ/8?ªgå=§b쾸¹c>±Ü¾öX¦¾s~U=Ä}(¾õ=J¶>Þn¨=/.6u?à-é¼ñ�¡>NŽ£½Ü×§½ùÄ�¾|³t¾71L¾èú¼O…‚¾½³Ú¾+Ñ{>¼w»¾&ÿ¾È€@= çM;¿/0> ‡Ë>s¾ ¾ô²>Ð;x>kì«=žªQ¾å[‘½”]²¾W3‡¾_Ñc¾w³>‡Úà=ް¾ n?²½—>†ÒN=5äx>�)ѾYz>üzÀ½€è ¾ö½”½f¸Ò¾‰#¹>9„ ¾2\#½¸¢m¾ é¾� ¾wå¼Sç?Þ°¾¤¿›P/¾’iF¾¹À=L{¯>V�˽^è5¾ÔXU=† †¾å7T¾t…>п½Ç‹ò=û>?*® >Á˪½*å ¾°Í>;‰w=<óv½ÄZ»õ�ì>ß <>=ž ½Dçê>Çìj=hyä=Õ(´=¿|L)>[à ¿AÚ =G_œ=ñnl>x$¾zÖ¥Ö=r™>(@̾’aë½ÐŽ”=8Ê9ÎpC½&ý¾Óë>¬Û€¾±?â¾s>õ¼‰TŒ=®Ï¾„>™>³Rv½á^U¿PüC=¯‡= B¾ HE>Ò}!¾m|H¾“«‡>ì„€¾vP=½­YÙ=lî?ʲ=¹œ±=<€b½½:¡>öwß¾¥T<;¥¾3;N¼b4–>Úû>ãn=G5j>_ŽŠ¾ ½D¾án�¾}r·¾ßgœ>ð08¿ùÏ…¼Íð�=:E”>Ô[½9Hb=|ýû½›Çs¾+É„¾ÀXô; ê°>N�I>°ŒÏ>²¦£¾ ‚=áÒs½×$¼¼™f­=Ú’�½±>ú‹è=ªÇÀ½»Eš½8Ek¾$q”¼AT,½Ø¤¦=p¾¾ñ%‚¼çn¾!辊;ë¾�z3½×ö½ú°Û=�œ >¹�$>7L<7(>px�=s�«¼Çâξ‰¾Z%r= þÞ>y¥¯¾ü à= 7S=§T =ë“6¾Õd„>A?>Ô~>ïq¾-¾Ÿ½:޽÷ß1¼¥ó>�ˆ>üË=¹ÙX¾gÌA>uS1¾W[=zŠ�<ž6à>)±¿:Ž>ÌÜ=âÞ½p=Ô>–z>ZM4¾—5¾DW™>6c>ën½û9ª»ëš‚>óÕ’¼wÅ>�3¾Ü«¾ŒSï=~*7½vù>Mˆ‰;Í×�> ¤W=3ó¾’Ÿð=”ú޾×4¾»&…¾d¨®¾T0>࿹½àR­¼H¥¾ˆ ¡>MÞû½!dá=¸¢B¾i޾ÝÑL>EÂ>Q&?П½DbÌ<)Á–¾�Þ¾v°Ó½zÏ·½ï(¿¾�›Ö=N§“½W&Û½�:”¾SVl¾Äq£¾ê�¼µ€>êe>�རׇ<ëÞ¾Òç>>G¼½Öˆ¢=Y¹;HßÒ½ Dà>÷0…>íÆ©>îÃEºø®Ä=núä¾K¾üo¾³�¾šâ>.ÈI¾ ÀؽQ`±=7Œ)¾M£R>“ÿ¹¼4™¼ns7>pô>ê@°¾8¥6>ü©’¾_©¾öè>ãû®0K¾5a[½¡Ü=Ú±o¾Œ1A>Á¾~¾HÌi>k'>{ £=h 0½ß2¾ «À½'ÕL>;Á>aš%>†>xÇ¢>4;å=Ûòr>ºâp½ŽËP¾É?Ò>׉±½zÛ>£—¾>Ö¼©µJ>¼mÐ;…1N=Q <©F„=ZÉÆ¾œ˜ž½a¸¼¹:½¤‡>°ðL=�&>�¢¼¶Ú¹¾�÷Ù={`»¾ø�¡= ÉÑ>G,Û¾?‡¤½ ¿ø½á=wá±>êÚ¾ž3Ⱦº^>–iK¼õrk>/Jc¾.Ž-¾]R=ŽŽ¾É� ?%\m=ÏÓn¾¼Ï̾«Îi¾õg¥>�‘̾¶��¾Ám{»¿œ3?­ƒ½ñç=Û€°=Ÿˆ¾rTâ=tC:ˆµÔ¼—¯œ½¨>N›>‚B}¼£Æ>7;½ú„= Â_½ð¾ºáH<‹‰ñº¬~½�ƒ1>éÅ<ßžA=ÍÏ=’(¿:¤n¾F“=í ½Ö£¬½ì*>ã¾P¦¢¾/€ˆ>Ƕ'=#®1>#g»½h¾K"=oCb¾ÄOè>9º}=‹·á=K£¼ú¹½�웾j¾(¾ö8ª>~{>WDS>4\Ǿǃ¼ñ]->äÎã½?z_>@a=°&à»�˜¾ÿ4¾àT÷¼*¾=唼!dÉ=ÜèÔ=ú­»¾ìÿF>o'Q¾�©¾¥x¥¾-.t¾�†¾¼µk ½ã¨'>ûj¼=©Q€=ô �½J>öŒW>¹ç9>°ðÖ¾¦B6>��¾BFÿ½V„¼Zܸ>Gžq½ í©¼i©Ê=½ /¾ˆ×ͽõÙV¾Dõ޾¤²ž=Q½]½³k¾¢5¾>v¾×à7=F#a>�ª=ëª>¶Ê¾´>ü^¸>^L½6M½4nÆ<†*Å;øŸR=¼-�>–˜Ø¼j@™½let>2ø=Ʊ½ÈC>ý‹ä=¿š3¾�Ù¾ q¸½gàs¾�“> X½KÛz½T Â>Î哽TÝÎ=4ˆÍ½Tfb½†LO=Nªº~óð>7Ÿ¾©§u=:65¾?W‡½Lf>3.›=Ϊð¾~ޏ=J_“¾,4Ù½L_¾oy=l’à"3€¾ëê”>¸º¾=&츾¬ÍJ=6�o½±ó½æXf=%Ž|>Ú,¦¾¢½E§É½ŽË?2u�¾³ÿƒ>Á½|¾6¨f¾D]¨=#3C¾™VÔ><¼¾¿Îœ¾'µ ¿§XŸ>µ‰Á¾üÁÔ¾J—>­á¾4,>`Ž>æô>¡Z>5À>¡¿€¾ð=¬Á/¾¹z »%ˆ¼pNÙ½4–þ¼âG½=]�Y>…¾å�K>— =×7M>'{°¼W)~=×3=*ˆQ¾†„¢¾yÒ=�¨–<8–Ÿ½ŠÏ½¼”ù=:ò˜¾b”“¾Í­%>בG>Ñ3‰>vH :^6¾$¨‹¾ œŽ=xíϾ/øB=q…)¾r ¾qË®;°õ>·v¸> Ø>¼AÌI>šRT>-}Ÿ=×ëÚ¾W¾Yÿ½§þ^>Ñ‘¯<º[Ñ>Â|w¾à0V¾TŠ>”÷>¾‘þ9~i‘>~Æ>m :=Ä>î½Où¾p™F½¤Åݽ�Ä‚>Rm$¾–ÛÆ½©yæ=¤hª>;NH¾=‚¾ÇCß¼cn=&Þ¯»�ú¯»ÛÊ=NÿÎ=;„¾_'Ž>`˾èYs¼g’K¾Õ³Ñ½3x¼Âµy¾¶f ¾tÁ•=ƒ ”¾·[»>ÁO½8­4<ÆÄë<¸àǽÀ®¾›f;¾–ð�>¥1Œ>ª_D>Vƪ>›óɾ¦œ?g¶>Aý�¾G@Ó>Rh‘=·"¾¾5^O½IO=ßJt¾¬¹?¾þ^Ò< ÁQ>¥®=@Þí>çÔâ=Ï�ß>7¾¬-¼Ùi²¼P#]>›2>˜ƒU¾ÓGνëég<¯Ç=ëˆ2¾ƒ¾j= `¾Ôdɽۛô½VY—½Ä­ƒ½ä=¤½ã7½=õJ{¾ðPҽ߄Þ<³&>ÖS¾^áX¾ ½nê�=qC¾Åƒ›¾ÎÑç=Û^½Ò?¯>Ú5>ª&;=¸xn>õ½QwD>ØLe¾úd½i,>üÑ=ƒå>²ôó=ÎZi>_‰ž½Î[P½¿Õ-=4¨,=}F¾„F¹¾ê>=’Ÿ=,x¾·q¾{}�¾³/€¾WÜ,½™›>�¹©¼P§¾8qO>îyA<çøŸ¾U“†¾XºÌ>v› >df>å¿�=KÉ£>€¾wM>¸$3¾”ʾØú¾‰4•¼ŒŸ«>ÊÅ>Å. ¾ÑMm>óXp>“£i¾:Õm=—½¾ �;h敽Ü¿3­N¼·™S>âÓv¾2–=Ը¾¥E¾€ñ}¾‡µ½ e>«LÞ=+R*¾!á½cOü¡ùb¾[„¿ˆðÂ=áZоEt†=¾:æ½@Ã%¾¯î;bί½JÞ\¾*Ê< è¿�¾¬gu¾ÃÉ´¾ÓÁ¾ë³_<{K<ƒ¾â¤‹>Y¿#�@¾wͽÜû9=^Ó�¾üD¥¾ÆR�>ùI�¾UT·>h¤æ=À¿!>e€>Âyð=�N>m& ¼ÀI5<æí}½4“Œ¾58W>Äì< ô³>F�0¾Ï½>Ûíž½=§…>“â> ª•»PBŒ=¦i1>ré¾ wþ½Ê-¿z÷ž>Þ§�½màDZ³’½¯Eí½L õ=ãœÏ< ú< "0¾ ;ÜÕ„¾?ZM>b™>mŒé<[¥¼îvM½ÿ '¾íÑ�½rH¾ŒcŽ½Ë¾¿¾’1¾#² ?E¿¨O“>d â¼uϵ>óOÖ¼7Â8>[™¿ÊòÚ½ø�^>º6A=wÝ=>‚2 ½U"y>¹†¼?Ñ,¾ý‚œ¾ˆ=d '¾%dD>£R”¾B2¾7,¾òb뾸Ê}¾Ôlœ<·³å½òw½S)¿©©›>ô¾o.c¾€Ah½o=bGj<ñóó>�WÜ>•÷¾“Ï9>ºX=á”þ³[>Z˜>+%D¾xö±¾vGJõÂq>ÈÊ >ùþT½…8Î=]õd¼‚@—¾L>?¡¾±Yš½Ä¨D<ï]‡¾Œ w>Ô( ¾v ƾ¤vU><á??©¾<0ü¼¾Wh£>‡§E¾oæ>„�ð=z<>îl²»¹ù`¾¬_‘»¨w½ÎõŸ>lé=-¡Î=¿Ê">ib>¶V=¬Å?>›CA¾´±Å½’??K¹ƒ¾‡¨™=Nj׽%ô¬½é K¾n(?½-–¾o¸>¿6ë=‘>C>¸šl¾Ö—>5�½‰ =ÉIJ½övÏ>�¤ø>;_¾sìó>Ç"¾Ö`»=uÄô= ‡¢=”¯å½ ù¿¾~޾¶¾)©#=w&>wx=?~ؾF2‚='Bº¾ r½•­E‘±Å>e«¾é—9>…õª>ˆbT=eǽ½PuÊ<>;žºê½ØÃ½˜ð¹¾|J >콜¼6 >ªø%¾29&¾ñÍ:Þ„…¾ËŠÅ½~€N>ªQ9>eƒÞ¾Ä–¾»1�>L•3¾Î)ƽf\¾üÉ<ÛàA¾±:+¾ë>«¦i½Ý‰½B¥¼¾èBD¾Þ °>¨å><}Û§¾é½=c«¼ƒ¢k>w®G>�`y¾¬yk½µïѽ{¿sk>Ú‹=ø›%½öq½>é¼½)@¼>wi¾é…³>‚Ì“= ›Ù½­ò=Þ< ¾^iG=¡®6¾IÒ…¾ÓG½Ôº¾L«­¾š*ƽT¹ž>M²½îrç¼sí齉R>Þf>� Ý=¾¿i>¢“=¾xÁ,>X>Pƒ$¾8ù+¾VC=¾Ô&>)Û>ycÆ=�²¼06“=‘õ%=ž�ð½2Û›=™s¾+¼=­)ê¾Ø’>µ�=Á(�¾ô”Y½C ¾�EǾlt�¾‡Áñ½�Tð>ý?G;ñ°¶¼é½(°#=Õ�¾t(]>ñD¾‘ )¾¹“=Ò)¾âRE>A«¾Hf®¾•-½²¾añ¡=ˆ˜´»7úV€´¾¬^¾4Xº=õH>¸éÀ½8Ê‚¾¡t¦<În~¾çYŠ>$w¿j…�>Kö™»š/B¾ÖÉ= ¦>Ôz&¾ì�ê=u¾¿]‘>OÄ—=¿®é="Y¾JƒÔ>¾à*¾ßœ>jc¨»B�½_“|>øæ±=e>½'ƒ¾Pè½kÒ�=Ú¢=º€+½¾½°¼Ò\h¾§Ì‹>iξkÉh>Þà8¾¤fÑ>Ÿè#¾%\?¾¦>‘§~¾}ë‡>¯È>tï>Jy¾'Ť>dƒ½4=ûž;=w6¸¼¶¿Š™½vx¨½rK=>?GȾfB&¾4Ë彈¸à½Š¿½Ÿ*_>ϰ= S޾ʵ+=Yª >‚£G¼z.1=9sº¾†¦N>‚I¼£d=R<=Âî•>Â6z>L¦¾/d}¾9[�¾ÖHª=FY‡¾ëÅÃ>ᶨ=Rؽ|š½Vpݽ;¹…¾€³–¼a7½vòn½4Ö®½_—‰=xÆ3¾w‹‘¾zÂ6¾ùú¾MH—½Di >4yj¾§™e>Â2Þ¾ž½V¶¥>|K¼�(]¼ÿ,¸¾…]þ¾¤о‹�X½{™=Öÿ{½w >˜¶4>SÙ½½ûFï=TÕJ>ì8ð=ÕWk¾rû¼›Ï‰¾üL”½5¯¦<¨Tú½úˆ•¾z~½1 f>êcV½~…>%ùT¾£è‰=nê…¾ëZ»>\ã”>!Ñ‹=&;">s\…>×Ü侯=‘>U,9¾<æ=”µ ¾;üà¾'–>½œ)¾H*†>xê7¾dë5¼¢Þ¾UFv>‚à›=Z=Ž˜ >;e™>Õ¾è2:=È¢£¾©ðN\=¦ ½“?�=Ñ/–>be¦½‘ÝÀ¾{›¾:~‹¾q66?³8¾L“½±î½oÖŠ¾�í½ ~½Ú½ž¾U{?12>ôÀµ>‚Æç>‰>­½D‡H<˾Ô-о¸e¾ê_•>ϼwI<>-õ>­÷Ì>²h/< Y)¾æ7J<•ØR>¨Ø…¾g´¾ãýq=3&=lœ¾ÓÌŒ¾3† >}’­½ÕVí½K"�¼2¹$>0ž>ª¢õ>Ž)?(Mç>?Ãg¾$5мR}޾mؾŠ3M=­¦­¾±»>ioG>à:î½eNõ=ô_2¿~q¾È2i¾MZ¾¹ÒK½Ž¢Â¼G™¾C½¾võ;SC¸>w6¤¾ŠáѾì‚~>:'=à>}¤?d¯¹>yñå¾W™ >^Ÿ¾4FǾ¬sž½4QÙ»9ê�¼Ó>'Á¿L"ê½p>"�£=‘é½Ù• ¾Ä¾Î_¥¾Ý ¾;){¾„¹Ï½EÆ?ƾ«ØR>ü/u½< ±½N>\¾`Ô!¾O䫾»½aœ>$iÇ>J ¨>ìxÕ=lŠ¾Î˜_¼”྄ …=|�>fˆŠ> Ì·=®¢Â½ÞÖ¿¼)Œ>?1v>2ˆ®½’)"¾H ½å©Î>™Ä¢½eyä½ý‹½èˆ=ßúY¼‘”>8¬ì==XÅ´¾‡ðŒ¾’S*¾|øI>Ò#;^yí;'½I]’½þID>lÞú¾ÍAT>«A">y' ¾²—¬½Ÿ¡�>—�¡½mã[>—mè=>“›;! >;âª><”(> ½Èoj>úȾ‰¾�À|¼ ¼üTŠ>>êÆ9¾Syv½Fž.¾Ð¬ >O—=d?s¾^ å½(8¾å[= +>˜H½1)d<îŸ >åÞD?·‡G¾�Ó>…!>šâ£½Ý3Ó½à¨0?ê]=à ½¾´’·;®Õ»>=­½À¶L¾ƒ·Õ½å•Š>܉>…È5=œ!> ˆ>½˜œŠ¾j_>HR?>Ë,t¼¦ǽžG¾Qð‘¾?©>íU~½NŒ;u½ù™†<;þ›>usp>¡|Ê;ã!=pSf>!×JLú½Îl—>÷¡> êÊ»Éã„=@€K¾$uȾ 9®½Û4>F ½ 5„½òÏÃ;E&éJXy¾¬“u¾÷äÞ”ÜL¾Ã‹ >�('¾ÈÅD¾�¬Š>Ùà=Vkä¼øZ>oY§>ʑ˾i™½ä0X>�…v¾œI¼>;K™>$M羆M¾qw§¾ÂõŒ=ª!¼Ä`?O6¾ ´‚¾øPؾ¸g½åÂ>‘'(Д¼©P”½šqÖ=F¹Š¾a ¾¾äj2¿�m¸¾Ô;‘0 >§—?â*c>Ú¾L¾!Ñ,>CI5=,3>&×X¾Ã¾’”Ï>q›°=…Øí¼H�°>B¾>¾y?Í=ÖU>оÆw¾¢`T> R—¾`73<¬V>$Ÿ7-¤>ž%¼³f>¾B»ˆ¾­>J^½±¯½ÜY¾æ¹>‚q$>z`ƒ>[Ž…>Ûˆ.>8à€¾|w1¾wø¼5Äw¾ãÆÅ># > óf¾Ä2S½J}õ=+*Œ=ò+�>ÐØ ?î}Î=¨¼1¼k >‘5¾¬3Ü=˜™>ãí¾Ä]‚½§›“=Éí+?�ž ¿‡7=¾bƒ¾ì1]¾®…¦¾|}˾v%½uP¶u_`>�¼¿>V¨²>\†¾ïv¾EåÞ>‚P?¥>š€?HFŽ>Š\ª¾¼K¼¾Öø ¾Ú,Ø=Ô >DÜÐ>- Œ=˜2Ò¾¬�*>ë=‚¼Ru×¾8Ÿ>7 ­¾·¯ã>JèÆ>‰fg¾z >¹v‹½x6¿x´j>Ì×§½¬£>Pqz>äjE¾Õn¾´¥F¾ex¨¾,õ¾½oAˆ>ä�<>ÂÂ=ÎݾmØ>@Þ½Ë]½Ðêõ¾»>¾@U?±k¹¾jG)¾Žõ‘>Rݾâ‘Þ½>ÁŸ=ÎÈ[½:†>`Ó€½õ_É>Ü&¯½RÊ�¾Ÿ…˜½�¾ íd>o:¾-¬§>«“�>Ûª¿Ç¢Ó>É["¾•Ÿ3>[>¾=¶D8¾Åü‹½@J޽L-»>S“p>Q„>OËØ¼f–Í­v¾u¬¼>k¨6=Ôa÷>¤ ¿wåÿ½ÕüP=�„©=ó^‡<A…¾P'<>CQÌ>"ܾÑܾQAš>;(ƒ¾Çˆ=ã ¾Ó¾½áç"=ë½>"2À¾v›ª¼}{�>ÿó@>éžõ=[H½0_0¾´Mf¾ƒÉp½x_v>„ ø>¦©~>œ—îºA~è>ìVÐ>Y˜Ï=n¨=E*Ô<}À>û>ù2>ûµš¾PE^=bÓ|¾ÞŒ]¾ú“™¾¶+>õ<+=š:"¾ÀÚ¾gðþ´½vÔV=/`Ê=x²š¾¬Ù/?7 x>mZ=ùí;¾o4‹>L¥>¿«Ù>¸y¾w_q>ïâ¾ÆÐ4¾rÞ,>þ8޾£á!¾àg“½–Á§=”¹>M¨Â½Îû>À€÷<ƒŸ¦¼È‰`>Ú)¼s ±¼«¦ñ¾v. ¾Î?ÿ˜¹¾E-1>TGå=šgE¾â즽2Á =í‚c¼ï¾`×¥>{J¾M“?ñDå½÷9#½ÑŠ>Â6•¾–àï="s½$�‚¾…H¾= r*>:[Ö¾�¼¾}gé=} >†+“¾›�¡½Bj ¾þ²P¾‘�½^û–<::Ž =Å=೚>¤gž¾¹<>"sH¾üÁ꺢n¾»æ¬¼þ¿=î÷Q…a>NÅä¾iBõ>B‚Z>íxå<|„¾�£Æ>}P¾3RÐ>ë‹u>hÞ˜½¯Ú8< +¥>üæ…>K<3¾l…–<0E>ªÇ%=`ŸŒ>Þ|o½fÑu<ªÿ;v<¿³òç;|tx¼Æf >Æ€s>ü’Ž©¾ ½¤.½ë¿µ¾Â<Ü=e(¼e‡»>�ë?òð7½HŒ<_êx¾…>|Î3¾wer=ßñ+>o‘ï¼ÚÑ¿~\=¡Ù·½ÌݾĪú="¹¶¾‡ *oMn=­g‰¾wö$¿=G½FXƒ> ž½L†Á½Èà(½³£‰½ØZ¾5?E>¨7’=&D>§;¾è¦Ô>êùª¾Á¾ÕD9>±Ôν~êH¾z>— ݽçñ޼á<ѽ5d«>zeÿ½e8¼¾)ëê½ö¡¼¾][‚=�R)¾ìå=5Û‰>f]>nè±>è6Ï:ÙË<Ôa>í>e>â ¾_@¾4Á÷=/=/Õ¾ +>;g<ãû©=óþn>…àš=æÙ=†…¾o=^¤ñ=Ô”>Zø°½P�J>‚­>ê,ž¼3¦Ì>×CM>z`õ>-Ú¶>ؽ’¾|C>ÌÏ.>K+Ý>­!¼¾ÞÞ½½pe>E,=‚w >àÞ�»hY¾šñÄ=|è÷<À 4½Æ?ž{Ó½(J™¾>™¾÷¥>²­…>ƒ=5À™½Ìܤ¾;6˜½±«8¾#+�=(^k>LÓ)¾‘g<¾®´>ôïp=[==<c=…În>4=�>IØ<¾]¨¼–òD=œ´²=¥½Ñ »= oë½å)v¾Ú�> (h¾ÛÆ:½È,->hºÝ¾;<¾‡zå= c…¾“»Â=e5>¼o€>c®¾ûÝ€½5*å=úª�¾S¡A½Yœ:>õ¯‡½–ÄŠ>Áã?f4T¼…ù8>g?+¾�ûü>ùŽ™¾Šë¸½G >“нéy•¾ž¾ï½¬ Ï>Çnœ>þ±½M(n¼B¾><+½½Ú ?ñ—À¾¹Ô½ÿ�s¾ìuQ=»Oɾ¹4…»É#Y<œ°"¾çK¹¾ˆKa¼€bƒ¾µB`º1¿áO»ËÏ0>K\”¾ z>�ŒB>.á=ÅÝ >ƒ¼�>T$ >½M¶¼w-"¾O»«=—±¬½Z‰ ¿[1Íx¾‹Ö.¾¼d>âƾ„Ý ¾£Ó¼>šÑ¸¾Þ³Ó=¡=ëû>rF¾›½²û{>&7|>0c>ƒ"?¹™ ¾¢6¡¾GÏJ¾_—>lÅ+>X¹÷>|QÝ>Õæ=»,¿%Õ ¾r \½Q)j;r0Ó¾£þ˜¾¡ ð=Í,½ Ö<ü5½ç*š>`1«=ý|Ò½{"é>d_�¾ᓽ€Î¤¾ /–>/g=ÆZa:•4ˆ>†ƒV¿Q½>Üü¾‘@›¾1!È=Eî`¾ó"Q¿ª.>žhî>Èïq¼Û%†<0Ô¾C“‹¾S«?`=|½ 7>–ŽW>„)¾Ñv�>¨8ŽYÀ‡>ì >_Œ¹> ©Ÿ>p£æ¾Úë>Þw½± —¾ŽÕɾ¡âÙ¾h% ¾Ÿ?A¾ s½•¾«c=¾¸O´>ïh=à z¸±k:F6™¾®oy>Þ‚O>Èèú¾_"¹>bµ>ç¶Ò¾ª½=ð¾´¿…¾gŒ²="¿´¾«l>‘Ž=i³#¾CÁ>/xt=9¦R=ÀŽš½¤ð½þ²A>ò§e¾›F&>YÀ^¾Ë,™¼Õdß< ·”½¸ —¾MùÙ½“Ì >ïi‡¾—‡¾$u'¾|Ƚ�¶¾®Ý¶=4qg½LæS¾‘À¼÷³Œ¾ ¢S>ÌtS>T},>Ìl£>Òྎ1=âÄ�¾�²7¾a'x> ü ?>F9¾¡v¡¾3 º½¬É̾҅ª>Z=j¾c©á½Å>2?yP>6ê½P?<¾x1ç='c ½Z󺈓³>5a‡¾(ÓQ=sa¬¾è®>­�…¾b®…>`Þˆ¼Ð²„.¾~âL¾Ô쩾ÿÁ×>£Mh¾Y­>á®4<MÞ¼Hóнð©½-%Þ»ÝTi>^6¾?„o>ž’“>úGà¼�³¿=ÏV)¾ô³‚>:o>J+>ªñ5¾õÀϾñ*¾{<°=ØË>T•·¶™>¬…D½Ùoþ«I»ªyc=õªº¾vxC½´¨6¼J¾–¾‰¸~>È'ô< µé=Âçñ¨ó<Ñn·¾Ù ྀ}ƒ¾Èg´> 5)>V#¾>ßÕR>ƒˆ1>©�t½gë¿ÅT‘¾D�>©ÆY<ò‘¢>¬^$¿‡]C=é©>Ùn?ÞC>¾c>nœ„¾¯Äñ½B¡í½Aâ;=�E>ؾÆC>>4Îõ<ã?ä²ñ¾µ§˜½“R>\¹¦=m �½篽í6¾ƒmü=0Æÿ¹€jŸ¾Ï�=z×*¾dx¼«óé>Ée¼;*[­>0; XÖ½5YL¾/Þà½Bí8¾ÁÇþ½ÝÛ>WS¼|Ñ´¾˜l@=�RÁ¾JM´½Eû-¿bÆÊ½éi@>c_“¼iß ½ÌÑ¥½€ˆ¾ì@÷=}î½=÷d ?‘è>ðú¼#> p=ÏÂ?>•Z¾v§o¾×ÝǽQÝ•=c[>@�½aÉݽ¯„€=s¿¬>G݃½íÉ÷½xw>mÏξ7Ãg=°â-¾L޾Óÿ¹¾‘úû½æO¾íj½Kt ¿6W=¼q~½óµ ¾q>Š=æ##>œ>2�¾NpW>sоvÙa=âÏý=Ôrÿ¾’jË=• é=…¶Þ½hнEsž¾a‡Å¼í�?RFu>H{G¾ûh ¾Ñtï>�:¼½ñe~½Äê¾�E�<&‡–½¼E¿x¹½*ÿ’¼DT ¾¤Ö«>)Ð>”Q>(mË>N\¾—T/¿µe¾]+:>&jѾ®cǾ�U¿?2¿*Ce½ç =ùÒÎ>Tí'¾¼ŸÑ>ÁE¿ñú{>öÑL¾Ó°R>aß¾æë—=ì×&¾ž& ¾I¬„¾UÈ’=cs>B.?’­G¾v`ô=ÐÁ¾ /(=v>¼×¼–>Ö¿™>Ö…Ú¾·º—>’æò¾5ËL¾¹CÚ¾eéÒ»\6Š>†Ž>’äS¾ñwF>;Ö¿=�Ͼ1|£¾Äýâ>~!f>ÍÜ¡>·Iˆ> !><ùоÅë³¾3EÙ=rG›=IÛÈ>XE�¾8GE?lÖp<>¦½e�B>•´¥>�8g¾˜?Ô¡>5—X¾X;¾!øž¾®j€>:ͽ+¦½iÛÃ=Ž_ >ööœ½ç~”¾oõ=UÌ>lÎN¾â|ù¾.Æ]¾ïKÁ½ˆ\î=u˜,¾éâ¯>¹æ¾¥™¾®º¾“A4½™t¢>¹Zš=,µ½ Ì?VÔ>ŠF8¿À¯ä=÷ǽ ˾À{W¾ nÙ>æq ¾{¾¾AÄÜ>Ô™Š¾ÔZZ¾m+ž¹ÅŒg¿"{>^F‡>öµF>±�ó>Ø›¤½¾À>þo =ººÜ¼ð�¾*“‘;¯"Ó¯˜X¾^«>šñà½i»¿³Ë;>mB6>ÐÓ̼Ht¾“Iñ½Ð>u¾‡,'ºfj-¾Êï<\N¾P�=:�Å>ÔæØ½�ŽL¼ì/;>Ó訾¶82>|²�¾Ð¹;…Ϋ¾À �¾8ßÒ½Jîu>m3z>+¡¼‘Ûʽplf=¦æ=m+¾w뢽}e¿% ¾4¢�>²RZ>?›j¾÷ZA>Q)5>¬#3¾�Üé<%—ÿ=C~’¾­¡¾»RT= Æ?$¬h=;¿Nû§>Vÿ!=ZÂå>€%‹=c^Û½¢€¾”0‰¾Å§Q¾YŠq>Û�=ÛÚÕ½§.½’%¨>xÑß½tÊ¿‘‹™¾ÍÈŸº*N>—Á…¾¨d½¡e©¾µc/>ß_ð¾±�>&Yc;�þ}¾è0>oɾR½ÀO“¾Ìð=�€L¾L÷Ľ©Ø°¾®O[>i︾@�=1›x>Fà¹>…»£¾'AC>SSd¾“Ž—>[¶:Å`!¿~Ñ¡=†]#¾£@»½�ò½õÐÐ=V2¿,ÿº>îh¤>f÷>ex=œÔ=æV^=Џ‹>ʆ¶¾8&9?�RŠ>Û)=†³>Sò¾[›ä¾‹×O=ï>ýð™=¡Á=Ue¾O÷ö°¾Áli>ÍéI?’<>™°G<­Œù=Q\>iuཹ…ˆ¾�GH¾Ýrç=¡²½_ùÀ¾KȤ¾w.¿«kÆ;ƒß>úF«¾ü®>õü½ú¯N½‚á½ziM=èN¾)Õ¾=ö“…>üÝå¼ÙÙX=iÏê¾€Qˆ¾žYÁ½¹=-—>¸ø¾k­¼§Œ=ò?ä=�œW¾Ä“1=2ÅýÙG=ƈ¾q>‘Y4¾æf¾+w¾ŽT¾î•T»ñœ¾ƒÖC>ª+S¾©ö|¾ç˜x¾§oP>r>!~å*Ñ<”á¾.d%>ú¥j½=np¾Ÿsa>&�5<ôN¾)Ù¾¶m¾–b‚½¨ç6½ßÏN>ÀÚ;¾l7 ?öy½dŸ¤>R®>IŒ¿s’>aÎÙ;–ν—…¿F^=ÿ.)¼5(è¾QÂ>N¨½RI™>Da/>i¹ >WpÔ¾Œ{A¿×#<ž0P¾’kÚ<)ë�>‘E>M÷>‚úY>´I<ñÈ"½„ù<ÙŒ¡> oª>P‰¢>yK©=Rà4>t@Ï=׎ë½"©¼”Kܽ¸¥½y[+?åÒ-=#n¡½�¡h<žÚ•=ÃLì½|ýž¾:¾>­Ã=?—i‹>F›4>à…¡>Z¯½ªÒоnc%>œí‚>6<¶,ë=Ôe’=q?5{Ó>Þ ½@$’>ò©½üp ?ò˜¾3‡n=+wÓ¾ð‰�½Úœ>æ)>¾Eð¼¾÷¶�¾ulT>”ƒ�>qf¾8Q‡ÛK¾Ñv9>I „½öd8>|º ¾Ž$‡>ær÷<ëa„>êÔĽ¿È·½J×;¾š’�>2ÞÄ=¾ÄüF°É¾Bá½>O¢2¿ÄN…¾›è¾Ò—(¾é³û= ¿½›Ì³=Œmо�m?¥>¾™K=„Õ=ûÙ’>cÿõ=Çv„¾ô…>„± ¿™îM½7àÇ=ô•¾'(–>‹§Ü>oiº¾aO¬½‡ñJ<ñXý¾^s`¾| o¾ xI>ØC$¿&±ö=üöµ½W¿U'=½yX¾nÏœ¾yçE=@m&hS¾c¾ù2Ù=|C¾rÿä=`7c¾Ê:4ºÇ:›>g.…¾6ñü¶sƒ>ãÖ’½¢ ›¾7ôc¾ª‰¾Ä[?‰—˼‡Žv>@óŽ=^ ¿>É÷h>zm¼`ªq>Ö9Þ=dPñ¾ƒ;n>ñŸ<Ìö�>îöj¾Ï2=Fª»\'0=ªÊd=} >`üZ¾Ëôü½3嘽 Ô<>¬dV>o'ƒ=úÉâ>;®=Ÿ[འü>>ù~¾:2Á½I¹<»?‘ßÓ=÷Ö1U‰>êµà¾—|ð<Ã>Ћ¼;ÐИ>Å ½¾Cྒ>Ó•¾ZÁ1>ƒ ¿àfß¾¯ˆO½›E½‘ùe>Övÿ=&-t¾—J¼�ç¿-LM> ±Ÿ½C¡¾VK>bή>™Ï>Ù˜>}>jÌÂ>\ù¾ë窽:ª¾6dþ¾Á!�¾n±*¾£u§>Ó? �b>­J¾~‹>k¥=D{¼¼âFŠ>äs‰½Ub¼ÂÈ:¾´Æ.>MÃÇ>ÞêÀ½r£¾b‹}=~�#¾‰+ï>èƒÞ=ë³|=j=¿>,‰ª>u=>¸¿æX¾6pŽ3ð=MJ;½SÅоÔi¾2º`>¸¾»>Ö¹¹=Àyz¼hR¬=ÀJD½H�£=}Ô×=¨°¼£lÆ>fl�¾ƒ€.>Oi&?#T¤=Ò;&q¯>ë??’�c¾:Æ�> \>Æ¥s>D�jº6­]>‡0:¾ÍGS?$/޾ŽÌZ=1¿J¾ Í/½J2¸½‰õ9?ºÌ>Jp¼Ð%�>IÕE=Ÿh“¾¦'€¾:ó§>®M³>ž»ò½¦®ê>ı—½'˜¾ï{œ¾'Ý¥¾~~¸=_u�>•–�=ĵ…¾¹t¾sNÚß9?<˜>„®�>6{^¾û ‘¾oï[½<ç:¾+�= ºé¾-{¾�Œ2=Ti>º9ļcÃÛ>  ?2=¾Í%î½i?퇽ÞÛ=§3z>ŠÑ>fž ¾"�¾#»A>8n%>ž‹N½®€?¢Ä>XN�½Cr#¾§�b¾È*-½¸Áë½´^‡>ˆd½”Ìw>&!ᾜ}½�Hœ=(7¾£³>)ò˜=´9;”M¾D|°¾åÏ>>ìÇ“>sĺ>Þš>Ø«ˆ>´š¢><{¿êh<îûؾ•…5¿]®?¶ ”>¹‚¢>C >uTÎ=*>>L*>÷>B=Ü!Í=-×$¿[±¿5¾`­»Vñq>r§Î<‘ÓŠ>ºÅ�½†©˜=ùìa¼=¤=>WÖÌ>zÊz>dg¾È†ò½·�¿>(¤¾üÞå¼p#Ö¾C‡‘¾Ö½×ǾÆ�>-bF¾’±q<»>:™>6KؾŒR»¾Ñ¡Ä½$àñ¾§·ñ½†ù>Ý ”¾/�>Ç„÷¼Š»²½Bø‹>ÿòU¾`б½Ûþ®>B˜Þ½ÂÿHôk¾f +>žú=Dw(¿–·�>í+þn05>¸Çi¾lw˽5v ¾½–> a¨»Ç%½á¶#½8½xà½n-?*ˆq>œã†¾ƒ§‚¾ MÇ=p *¾Þé>aR¯¾P#€¾Ÿ®>…±‚—>}ý¼½BM…>ÖîF>9•¾ž`=LQ¾ƒü\¾ùC!¾‚ù¶=‡Û꽉ä8>ùµ½Ò‚Z=»Ì�¾¹Æ>"¡»�+Ä=´3 >T.K½ßÆv¾Ø¬“>¼á¾ôíl=Jp>ý6j>Ñ))½£¾’½}`ç½ÚnK=ý%>bND>|ÖÀ>™f¿¾s-þ¾º¶ù¾üy³¾¼èP½è>X>�ó¾þ9¿òó�¼‡l›=Vb�>Õ^c>™ l¾ú>±ŠY»›I½>�V3¾Dh¾®}оƒ/Ê>h´=8¦Þ>¶Zɾ(PÇ=¾¡¹½úCÚ½òó‹¾N�¾p*l>Žæ4½ç¨˜¼ÛF�¾Þ›ó½äH¾&Ö >)�ƒ¼mÆü¾Å¨Þ>7OG²>�Òk¾u f½ÄGÚ>}Ϳ¾¾t³@½J¡ˆ ž<ûR®¼iP>¯‘Õ=P2¾Kem¾;òÇ>‘>•‡z¾ßl½tª¾ ë¿]Cu¾½Hw~ý?ß¾àD`¾ÖÈâ=„]U¼@𙾑ÓÊ=èúm¾¢!‘=vÕ½œé–¾FyѺQç2:9¾6XÑ>3O·;hU¥>Ÿ¹–>–þ=û'¾W>$½ÝòÇ>3â'>Љý½� ÷½ˆ]*¾ï:½„—~=•‚„=ƒjº=ˆâ ¾†ÿ>�1Š>@;éY™>ÿ2¾;B$¾c”>î¾þl¾æ`]>=b=ø�R=6C½%Ú±¾à¸ï¼‹Ü^<á{Ô>É4;=|Ÿ>àß½‡­2>lR›¾[à½ð¼oI¾p B½bé¾ëü=iø¾ ÞÃ>1f>3KP=kz ?]E»z¢´¾ÞN ¾3SV=Ê=¾�ž½�à꾬íN=Åν¥|> Œ–>P¾c»ï:š½~Ͼ{;†½Z¥*>æ—k¾ävø=èŽÒ½õhé=pƺ=¦SÎ=Él€¾š"‡<Çý>ŽK>�<›=Clê=Tùs¾O±Þ¾’½5¬¾«ÑŽ>î"§¼sÖJ=†Ãн…>Q¤9>Ì„>Ë…ì>%’+¾†�¾°´z=Õv˜<£½Ž"=áÞ|>ªs‰»F®š>›É¥>eV¾ ha=äSG¾âR¾¬Õ3¼÷ˆ >£�½uQ­>Ò *>„ºD¾ÈƒÑ="Žã¾ä¾| ¾ïþ‘¾8c<[ʽ4­ö>>.z>qèÛ= èš½¦°„½`1Ð=D°'¾=Ãý=i¶T»#›‹»B ½e½CR¢½*ϾÈQ¾JÀO¾3ÈD¾…v¢½£¼’¾ê¬;ü6R¾è«Q=z$e¾(Ü >é‡{=ƒ>kN¥=@Ù¿­µ=ºs¾ç~¾/Ó=Xé=)7­¾DÕ{¾@”æ<ê&½Û˜?¾}Ð[0¾â´8>b-™»ŒbÇ>ù’¬½ V9¾Ò¨ÿ=ôK¹=ÉT7¾²D¾£>nr>¾²E–½\³=j¾L >ä ë=[Lý½(Ò£½¥jO¾ÎT>G]™½5ñ >f¿>øs/¿º¼*¾š$7½_>’¿}>¨?¾âf—>À>Ôbÿ¼\Üd½8º?ÇÍ¿>c¸x>Íß“=J¦�½Q ž¾>q½¢Ñà=Æ7½P³±> �Ø<Ï’»êõ>.¸Ë>~«Ö>6½/¾}ÐÝ>ç=>‰ºC¾Ä„=ã÷ >p\>’#Q>E½>YÿA>ëY–>_'„½ƒ¾U\á½w-Õ½!6â=Õbf=$ˆ=Cª­½`g¾†s·½‘^å¼Ô�ç<œÄ=T⪾åó½ÜwÜ=ܽ�ᇼ s/½6S>{¹5¾4=Xñ¾}V*>ÍäS>ci¿¢àæ\³‹>Ë^½¢ð<¶®²¾í¬Š>ß}6?j^¶¾ ò¡½àѽ¯8€¾çŠú>`Wå>Á~=,,>´h‰¾fš­½„Ï„½³Ôñ½•M«=<Á>n¢’½îl>ì¼½°�¾þ›½jÎ>ÞÍ> ¸R¾OUº> …�> ¾ÓÔ€½Ö)Ô»‡X¼½g’潄p¥¾)ξRj ; �¾EgÊ=�Úf>s�?¾þö&>Èq›=Ä÷\¾Š d¾nƒ½ oæ>*Ò–>u€¾ñ�¾«¾ò턾wÕ•¾¯å˜½K7x>¬ZÉ>}B?ÜÛ‚¾hçÚ¼JD¾dë*¾RM1>Ñ­Š<~r�>Ò»½ë§A¾Åz(½C¹A½Æ¼B>,´¬¾è¿í=)½9Ï¼Ñ Ë¾l]{¾HÒ=o°ž½íNÙ¾Üç™<‘¾Çg¾z|=£š“ª:>HK ¾«7½Ó§¼_IÓ¾ 87¾omL?—J�¾È¾C¼YÊ=4Ž¥¼æ² >yÑ>t+‘¾¶Ó>ʆ'¼!cã>;‹½–•L>‰_½G5š>Ðm=!Q¾GÐá½6]m¾[ZB>?Ð>øD$>v¾�µ=yëë½(»¼Üe¾V×ò½ÿ±½¶â×=K蔾ìÑv¾àb’>¡à¾Ì•ç=mÿ¢=iZ >µcˆ>ÿw|¾gÜn½ÎB©=£Í™>]�Q¾”ÿL>“s¾ÀÆ=½ >h½Õ‚b¾òZ$?žÊ�=ˆK!¾š›•¾0­=“â>wë>µ–£=“Gâ½UÀ =À£¹¾aJY¾è…O½È&ユÚÙ=²OÞ¼pÁ¾=ü�Á¼�‡_½�’M½~Ò¼sĽÍó콘ÎÍ>Ï*™¾ä¿¾â)�¾Ø>؉4¾‡Åš¼V“>Bn='Zi½nŒ=¸ˆö=GJ[>Ì[>xš‘¾\§½½JÁ¼¬$©¾ˆA¾I\¾Z­b>úˆK>XHœ½›|=~i»=h]Þ=Î8l=ïÿ¾2Ž›>�Pë½ï8Â<}7¶¼_ˆÇ¾ÄÁ3>¨Ï±>²zy;dÒ?môú>Å+¾™Åá½ûÓw=d`˜=ô;s¾e—�>{ô€=ù9Ä>"L>˜S ½u÷†>Ó²"¿¸>>½jȽ[^‡½õL@¾F¾® e>¸œ;¾çgg¾ˆÅ£=t]¯½ùwú½ü1S½}ú`=Lƒ¼Y눻®{ >M”�½Žm–¾Kî=}e·=_¿P¾je,>0{ê=Ý-¾:‹H¾[]\¾/¹»d]�>üÚÊ>Âzb>}†Q½Ã?Û=ÔÍ=e*½8P>ÁûX¾ *>ïhC>µ'†¾·c„>yH½`•¾s[þ=oÂ=4¢ó=îìz¾Ç t½s‡>ÍP?Q >jãʽÊé{>�q¾5:Ñ=™%Ö½,á>T™ý>ÿ¶>T¼½?Ë’>±¯ò¼Ã7»>p'Â>OäÖ<{2m>0Üj¾¹óƒ>L§1>ꪾ]½Ø´�½?ý=yk>¼�Öì=ì…¢>OÚƒ=µÜZ>Ì3y<ºß»<�ÊŽ>/¾GÍJ½ò3ˆ¾r©¼a…Î= X =úb–½q—\¾Äó€>¯ñ™>…Ïš¾ͽ˜?Ÿ>ô$T¾÷ >„+¤=Ý 6>=„Y¾$by>l¿ª¼Lþ׿{¾±Ñ%>kLl> =DÖ=a5�¾r>:àM¾˜‰ž¾¶Ç¾VÙ§>,™#¾Ë¾Ýuv>Ê¿;¾�’Ô>èr=e"¾Yrç½U¸ =°™¥>æ >ðz ¾y À½9{Œ>%¾Ucj¾¹Ô¾<Ü >àP ¾DÔŸ¼µéâ¼@…½’þ´=Ê"É>‡]2¾Ps{>¾PT>íM>¤—¾?2W>XÉM>¹á=û4>Ôñ™=3”Š>ô# ¾9ÖÜ=rz=s\€>Ëÿî>î©Ÿ¸²¢z=œ°¾&­¾ƒ9=p@ >SÉñ½ÇYî=+\¾. >ÎZG>B÷¾GͲ½"œ»<@0³=‰‰J>µ¢½<ø=vß·½,Kɽ 1�½BT>¹FнÚΛ¾=æk>ÙT¢>-{˜½ -•½xÀ?Ã!¾Êí½Ê˜;¿·S—===\¾o£Ë;S°/»Sn´>1X’½•ÿ3½ý=¢¾4…m>k傽½¾ó=Â);¾Hà¾>bŒ…=¶MÛ<Ž>%d{¾ƒ ´>ãWó¾N¤*>'$Á½¬8Ç>$Š>òçÛ<Šë=m7ù¼õÏ�=Æý*>šº?�ƾêþ½1³ ?œd¾ËÚ<øÌ>: ˜¾£þ4¾úô�¾èšò=m,Q>jÇ ¾‰=Èe¾x­f=z]Æ=kGؼMPW¾�õx={Ž=Ÿ’ô>’?=„3¾ª*¾ë`Ô={Š>ýG›>°ý$=㤞½—¤s>.Î>fsî»rïK<Ðä¬=z�m¾Ù…Á=üŸ>9�†‰y¾žGÊ=ß=½»*mž¾é¨>&Co½®ñ_¾2 ¾D>–¾Ü>�¾ã•μ%—> rD¾ÿáh¾O0æ=8¾+“¼Rµ¾NïÀ½@×¼‹KÚ=z1ö=eej=c¾²¥·½Ž˜ß>6,¶=ÓÛ>ŠçA=°èĽ<ø=A›�¾Ï¾Oî¨=QÏð½üº�>b‡>‘@d¾n8”¾ ;º¼à8&½Wѧ½Áæd¾ÈÍ<у<yG>µ¤\¾ú£|½CDá½­‘f=ž¿o>;íŽ>y¥¬>ÎÝ~¾^^/¾úQ¾4+v>Vé->#x>4¦>Ju£¾çtŸ=º5¶¾ÍÈ?-À-=/E…¾‹på> ƒ ;€•|¾¯À‚¾ƒ�¯=EŠY>à�ç¼í®÷=º ¾.A¤>z¾ÆÃн—/n> D‡=]×#»Ð�'=µÎÝ=JÒË=â·ß¾í-‘>ç[?#tà½%{Á½¤ÎP¼¢3%>ïóپȪ¼>/Ý�½¿Ú�>)¬ä¾`5©=ëD ¿¬¼}>Ẍ¾Ø�?"9�>£+½p&ý=>Á½Eæ]>™[b¾úº¨<’¾`¦Ì¾zQ½ëKo>P•>%¨4;0·¥=«9·>2öz¾À´>«íy¾>¨ƒ9d‰û¾ŒÂ½¨Þõ½6°Q>dÌ“<ßy¾¦Í‹= í�¾a›U>‡¦"=Âç>–þŸ8LŠ>²Iü=.s==3žô¼²*/½¤vo¾Ö/޾Á[<$‡5>¿”X¾²Š>1•]>XÑ5?+£>1l>gf ¿™¡.=”±œ>¶¨¿àÎX;Jr”=m1ƈ´×½&J9½üç$½2I™>m[û=¾æY½É¿îQ‹½ ó·¾€>�š¹½i¾¾·å=âëî>ÏFe¾4r‘¾–̇:»%ɾX:>MŒ>U»>TEϾÕe¥>Ö¬€¾ÔÝ­=’g¾»%´½ÇM >(Õ½�ïÂ>e®è½Ž‹®¾&æ/>B>EîÔ>…mž>—Î…=Œø=”#˜>}ˆ>åêi¾øëø>È>yR¸>ÞÎ5>n¶S>:$d¾ª­Ù=õõ >ö¢è>±Y5>E̽êÀ³>Œ>޾ŽÅ>`K>�d¬=É£+= h@¾ep0>³´Ô½ 6–¾;(¨½”�¾ù¡+¾’€:¾šß¡=yÏ^¾™>7S=‹qˆ¾–,i¾ _½Û9=b¼à>6þ—½Š?Î:q‰ ?âɬ¼À…¿€M=,Y›>Ì�}>£¼DN>BTt>‚ˆš½#.ļ]Χ¼P >ƪ<=‰–½[ÚQ»A¬†¾µ*ä¾ý«m>_kŠ>Mµ»¼�{¾F‹j>d ¾¸S«>–]ž¾‡©¾Ð”¿­],¾¿ß}¼¬•Â>;—†>ü=8ó =’o̽¸l¾5a+>êËÔ¼?5T>jW�¾ç§æ>&a<Ö2b¾xÞ‰½Ù=ž¾·`�>¶¼¾Ž«:¾°+¾C`>ðr‘>V®>Î}޾Ÿ@¾š(¿¾ã9>¶— ?�•=œ²ê<Œ‘R¾Èâ¶; &½?s±=ü`> �`½âåD=¿�Â=ÛÂï>r>¾‹sº>ï<¾òc½ÖI¾þ¾o¾c³Äºš@Ì=@x–<æšk>¯Š¾�- ¾­>Œ¾èr0>í8>>˜·v½»·¾³Úu=c¾úÑC¾$¥¾ƒ/>d轨ýÖ=gi>È;½;nê½Fë¾éÒ¾<Âä¾ë¼î,¼�©«>:ýÞ¾ÖR>'¥¾WI=ÐÏ$¾Š „=C¢’=Ÿ÷™½Í‡Û¾½*•¾âˆW¾òP½ê±=ȱØ=êËD½VÂ=h»>ªÀÿ=ÌŠœ=F"K<%J¢¾à€;¾Ä˜H¾GšO¾h)·¾$ˆ’>úâò½˜+{½ó3ï<Ó²C<<ž2>.å=Â¥„½¶9Ù=žø=½œ¥b=!Ë�¾`†b¾Å¤ ¾AĽ>V•¾x=e=Û"¿„íH>C»½î ‹¾Yˆ=‘æ¾VO¾[Ñ>òe¾©Õµ¾8¢=<˜¾É ã½kcÖ¾ª7�<˜‰==,Õ½ú)F?Õ²_=4f6¾a\>eõ]=öž;ïå$¾çO=釾¶ {>׿r>¥#~>Ò¤ ¾qd=kþž½s앾[Dȼjg™=,‹!»q¶>kÕ½fÛ²½3}�½d¡Ú¾°gž>Ú£$¾šý.>é;¾¤¼+›°½üc½¾¹á½-7a>õÕ8>ºÒí¾�âK>£&O¼ßY©¸e£=�sê<Ÿ:¾‡€½¢Xç> ÑÑ>¢"¾Ç>%t<þÖÀ=Ô5 ¼J, ½žÀ@>ϦB>ÿ?ƒ>`ó4¾äu¾ëí=ð&B¾Éûè=š“£=Ò¡=•> îR>\]0>'ÃJ¾[äÖ½Êê=ôV‰=ù­=Ûo¾ÜÕ¾©¢P>„Ññ½Ûß¿¬ð¢>ÌÅx>E;¥>‹°J½tæ/½�^ª¾q¼=(–¾7Š|½ v¾Sæ…¾Ù”Ì=ê–7½6lÚ¼@?¼Â—¶½†¹=Ös¾ã–†>«à=€t5¾^ò¯>v¨½g»½½¬:о7áÕ>Zõ4>ÜÓß=Ľ>¾Ú=âG=è~¾*]J>Ù ä>_‘=`8?˜â˜=ÿf¾~F(>ý1ë=¦õ>Š[Ü>·>‹—9=Zò¼ƒ·J¾è-<¬>‘65¾ýŸb¾©Â–>¬xÀ½jô­¾@mð§¾™>ö#·<óQ€>NÀ¾«·?Äy±½h¾l(l»‚™Ü=Xoð>ãüq=ƒÑ>¾ÇdȽªþ¾ƒÀu¾�ν~Ø1¾¯Ë =:1�>¡-Ž>†[>oî8¾o¾\¥¾¼ŽR»½L@Ì> %>‘Û>»·®Ö¾Á`e¾¦²O½¥ ¾O{–»J£!=”§–<^Ǿ½³ß=µêï=Ü=x½}ñS>Ñe’½Á³¶¾ÁG�½?_½X½ç¯H¼e¶9=Oâê²é ¾873½lÑ;½âbK¾Iź=«7i=‡ñ•¾‰޹â¡>GpH>(Ó™=ñ×[=¯#Ͼ˜äq>bȰ½¯¡!>TØ7½u¾;2Q=�­ =Q¸?¸èW¾†YJ>©õi½åV >Tøü¾¤¾<=rz¿‰É <- ?G:Ð>Ë”>O?l>3O…¼Ñ󉊾Ùs•½Ž¥_>}"ؾU¶f¾ÑÀ‚¾âuW=†Æx>ø3|¾Ztˆ¾ Ó=Çao¾Íÿ½çyW¼ºSF>ÕŠ>ÝK™½cM>Íè%¾®ã€>:ß:?-7�½âsõ>©û>Ñ­.>Óòj¾XW‹¾+#<î=eB= W>÷�£>sx*¾‘%A>yU“¾e’&¾êþ7>¦{â½R)Åd ´=5Oݼ!¹U¾é�¾ä†¼‰:?ÀÜ<>à%>•‚^>í‹â=]ƒ>«a¾ ,¾Kù>¸ù°¼�V= ®Í=Ñýû=s–ö¾E’­>`­Ç= G½iÀÙ½Xi=½XÝ>q“¾Ùd ¾YQ>¾B>l/ò>µ�Ú»•¬¾˜`J¾qé–>Ý3c¾•UO¾‘ø´½Î¹�>–޽T> G¡="!¾ øð=þÎܽb±Ò¾ñŽ=µ-o¾çÚȾž>b"¶½>žŒ¾Mß}<Ï+ü=–&޽e0w¾„|u¾O´ >§ÂS=€:ͽÊJ5¼#=H뫾ó–€=4ÄX=Û´#>]Ã?>µ>lÒí¾…1Œ>†Iྒ9d>Þ›>ÔD@=×Ô<½IôM¾&°>¼‹w>îË~=Šz™=õ">­xF>¶Ù>I¿iª¾·nb>€ž=ø®>½ƒ6>D>–¾é”>ÊEß½Åê©=¯>‘&>õM>&(>Çš½d?¤<ãÜô»=ª¼Òz‚¾´ì¾”>½LlF=оžbé=M¦=¶“Â> eF=µt¡½ð‡¾/ <šG$¾A1&>;wN>3 à¼ïEx¾Ö#ã¾¶‹V¾ò׆¾¾ÒÅ«šX=ò•¡>'›ö½b£¾Å^$=R¹ã½Q½0¾9¬§¾c×Ü=‘yÑ=õ Á;º±R½ ò@¾H½¼ß^¼,Ïæ½’è1?†Ëf½³ â=GTv¼Kݾho„¾�¦¶=zà?y“™=á«E>õÏȾZh{¾O(û=6ô„¾ ©¾¥JÞ½C”^=•û;><×í¾n™C½Ä ?\F¾Nû<<˜>±¿ñVÂ=ã±¥¾ž¾Hh>�% ?Ú ;¾ñP‡= _«½Sþ¾¿Lw¼ÉOh½F>Ö>Šx¥>3Ó=šÐ¾Ó‹Þ¾W¿©É=ûáh¾ñ—Ò>Bwš½§">ºûë½0Àp=8ľMɘ½®Œ6>\©¾¡O¾•Ó==ìw%>¸ÒZ½eW¾Ÿ6Ð=æ—¾Æ"ñ>�À>P >7€¾”ˆé<ÂTľ;!j>VÁ½†G>-æ>œ™=u¾m>/,_> _w>ÈŠ>@2Z=¥îµ=Xaç>^Y£>A&/½“þ¨>VGô½pGÉ=:2=å[°>úo>�0=P!–¾!˜ù=ßïh¾}¿½jÊä<(ÜÂ=䨕=÷~â¾½p.½Hø”=óß«¾“~><.¾Â´¾ÙpR=»C5¾íaö»m¡õ=‰ ¸¾%o>º¾ÔB=ÛÆž>b\> û¯=‘È�>Þ|¡½Û`-¾5¾?-‚>~§ë¾>’u½Øý½y᛾yÈ=lȼ‹ƒ<8 ½¨ˆ§>ÿKO¾˜µ‘>xx½Æ<\>ÔH>–x>¢Í&¾ý·È=�!>×Þˆ¼¦Ë>vä >qb“½0ÐÓ=aü=‰+^>äs½Ñ'C¾­ˆ¡½Í3 ¾@b>~¬¿ Þ&=󨡾[^>ïç¾Î�C¾Mcˆ>®3Ⱦª9O=Ò¥´>…Š>>¾ÆF«<]Áì½ÒÕ°¾à‰À½UÔ ¾ÐF¾ÈeÆ=‰‡4¾óGÑ<ß ’¼lÊf¾-I¾|‹Ž¾ï·Î=˜Í(?DÚô½²ºÊ=Ÿg¾Q‘®¼¸ËÙ=Ñ·º¼Rv›¾’_=C¡:¾ð)ˆ¼ŒŒ>¥Ã ½ÏÚ~½i¢¬>åÔš>…1ä>m}O¾³Ò=�T½¾3¿òê>þ“μÀH»½n >ª]ˆ¾0Ý?óå>=°§À¼›4•=ZéA=­7ƾõI‚>ÚÛ>$=(d+½{ö½=rEy¾ìÚ¾:÷\>fAv>ü�†­>Õ;õºË>æfÙ½¯Ó潑–0>,Ä'> êG>H…$¾<§Ã½×Ú<2JÀ>ÝÍ>ö+Æ=;ë-¾>7¾˜B>%Á‚¾¤A#>ýñ>x7?>w楼հ6>4Ë ¾áýo>A> ¾f娾 d�>]F¾Ë¡a¾…mo=髽�Œ¾?Ë»=\ȾYYÓ>/~†½çȧ¾Ï3¾D°\¾!¾`…™>K†¾Øu¾wI¸>÷¿¯> ŽÒxq>\îr¼ý¿¾’{;�ž¾UÞ¾´(¾ÔÏ轘#¾ 6±½|�Ò¾¢=Œ=¼Û4=È!º<ó ¾`Û¾F\­»”ì˾3€é=?ˆî=Θn»jnu½ºý;ž’ >L@>–[7<#銾²÷„=¸yT¾~&¿ÑPÄ»¤�>^-³=ðå7¾ªz8=n¯<~+“¾ ë;3ýY=ÔgÞ½SÓü=Üø½¾nN.¾‹w¾Pá¼4•…>ºUå=4 ˜¾Ü‡…=|òJ½¼î>½¾m¾*�Á½lû¼`=&—b>¸4=«(æ=¶Û4>¯Ôz=úÑÒ<§5¦½‡bŒ>4¥Ì=cXŸ=% T>L¶¬=�óò=2”€¾ã6¥=“¾²¢ ½& ?³Å½àŸ4>nÿH>ÌZS=h�^> ²2¿1¿¾1ŽÉ=¡4“¾»¼DÄÓ½Äõð¾¼[¾9¼>Ç<�Lj=^Âr¾¿™Œ¾7ÉX¾Kýø}g¼ç7 ½N>m¾¯ ¾Ñ)ˆ>M�F>$ѽA p¾¡=­<‡=àlù>èž¾ãø>]óN>.Ž¿ä¶u¾c5,=՞̽3«¾è:¾Ë£A>Á0¾SÏd¾½$¾]Kâ¾u[q¾åû„>½z >¯îÅ>ãñU=û¢–¾Ç€Ë=hä�½ •>Ãù{>r¥Û¾õ|š¾^î¹=â� ¾Ö˜>>iB¾Ôõ½àw¤½ å:>�þ½Û’W= Úu=0“J¾1†=”¸¿&_þ,¡ü½�t„>Àéì¼Õ¿Ÿ½ý¤r¾û5X½Äzd>€Öeºà§o¼Ž²=>rº>É�?½ÛZ3>`h >±!$=ß2>ãä¾;®Ñ>žè±>ºC€½im½Â™Ü:F‡U¾V4¿X >.ç=Á ³½V�‡=€!g¾�Xê½ÏÊ�¾>¯Ç>3à&>d�–=ÙM7>Èá¼dh>Zô=»ëž<ÁmÚ¾õ9¡½K”S¾Áº>.7l=ÀM%=Òæ=4¾‰–å==¸)¾õ†ß=çà=š{°½u¸`¾¬q >Ð &½�€Ô¼ÍM9>LLš¼9¹>FòF=�}�½zR0>Ô—m½PÈA½É^f½ ɾ ‡<ûy¦=ûnŒ<ºˆ=ÅS>øÎt¾/u¤½\¥>SvB=Ôµ›=ö¾6è>hõþ Êļõ'=¾jµ¾J¿=·Ê{>�*½†â‡>+ ô=ÈŠ¾Ää¿¥ˆ¾Y³Y=ϧ½âþá½àm¿™Ô\¾‹z¾.Or=ö§U=lºR>ˆ©ò=5‹½LL¿ ¦=-1T>@ÏG¾³ËI¾ÍÑ ¿ƒØo=«#»ä¨c>¨UD>±Rf¾ Q[>òD&>�KŸ=Ù€>ú2¾QÜr½U ¾;›¾,™¾§�ƒ>:ç¾�×>žA-¾þ×/>ƒ.K¾çG½ؽ½?B“»6ìp>K=¾$­Ä>xÒ^¾¸!&½¹á>[Ü=e …½Ü˜¾±n>Õ•î½;íŠ>Ý÷ؽ`qp>2®¼é ¾ƒž>á]U½}€B¾3"?YTw»F¦W>b‡>,¢½ß†Y½½о³”<>¦©=ûÖI>·Õ÷¾×–¾=ö+¼ >âF¶½4 <¾qB <ôª>5v¾êC=<8½"�j¾Ô“>'ûw>yÙ§> …€<Õ4? ܾ®�½ç�¾¬Šî>åŠl½Í4¾sa¼=ã~ G¾@j=«L>–/·½zÉ×;_iD>‡ïC½ˆ] ¾õZ¥=#›]>îš¡>— «>‘ô=Šâ‰>ì >z‰j½þ43>wͦ¾#á>½4ôU¾kßÒ>#¥¾Ð£t;”Ë=~Ý´¾#=µ=L,y¾&šë=;?ç?M>’!¼¼Ñ`7>³Ýð=IÌX¾Aˇ½ìúT¾ú>ä¾´ç´=˜ö ¾ÛF¾Øh廨Û/½L0Ú¾«NÖ½OO¦>”rC>µ;Õ>Ö¾aÉÿ¾es¾$ªZ>Ü;N¾Gçe¾cc‡=h¼÷¼®‹½½}ž8>Ѓš¾°¥=„p2>2¿B|œ¾Ñ‡<4Ð=CIÒ¾J'e>ü‰d=Ï!ú½æƒw>¹ˆE=t_>9œ>>ÊáY½ èø¼‹0~¾H¿»‘ns¾Oй;.ß°¾ûæ‘;ÖÈT¾á!4=®”W>Î ¾%‘=ê‚m¾¶>ÓU»>ú.a¾ý~€=’5ë<¨¿?>g+Žƒbž>í…>G?M‹ª>Ù≾nß UÇ0¾61N>F§>WÞ¾—|¾»s–=m=È=|>œ’>,¬¾Œæé>%¸é=e|r=–÷½ÄL?¥^Ù½¤÷[¾c�ø>´>mêÙ>�”>�L�>g >»G>æ‹æ=B*%¾2͉¾F;÷x9<%ÁE>sé=;œ¾‚Vú½EÖm½÷Ä`=˜_<º¿¾ µª¸ai¾£�½I�©>Yò¿®ó>WE£>t³D¾›Îå½Jù~¾›º>°ãT>²M¾9Hð½cÁ<‡´ø=£®¾å&¾§À5¿;‘€>º/ñ>�ö=Ïꟼ4ÃK½&ñ�=åå>YJ–> Ñ ¾k‡/=­Ý¾�|?¢˜ð= f½÷ä¾Åt?—"®¾:®ë½ué„=5/=fpù½ú$ >k'F>Kò5>ËR�=Þéu9Ï=0>þKнNÓ•¾¨'·½)=¾I=ºÒ=xA =ȧ3¾ÃŒ½x­Û=ÊB†f$?åO‹>핦¾RоK¾s˽ �d»e?½úß>ƒ“]=”õ¨>À½ó½ÜEy>M3;>¨¿zþ£½ðõå½Ý'ë>œT*¿�¹¾p�‚>4�¾u’)½èlc>ב!¾ŸeI¾Gá>iÄ6¾•æË½3_»½"gú=œyÿ=¢Ò?õÏ ¾5Ùx>µ[<† >rA>±Â¼¼“3=žo#>#2>¥z¾’M(>€o�;úõï=ÝO?j8¾ ô%¾ï‡>jº¸½� �= U¡>÷/€=� œ>–í£½ùù¿=éJ󼀸©>ˆ1½%8é=ô€.>àÝ»>Nܾ~ž¼Õq÷¾'Ε¾X®¹¼£³¨¾ØTÐ=¾�BŠ>P £>,š„¾>AÀ»ŒC¼÷«>úyÔ¾y�=}Òî½­ˆÂ½"÷=Z�N¾ »¯¾S�@?&³÷=0oï¾$…¿å˜W=G V=玂>õ?²>� U¾ƒ�œ¾Yïq=¡ì½|î…½ØÑò»xƒQ>R*<œÍ¾ÿ ¾qDe>ܼM½uO >ü»Û½9þR½HÉ[>dwš=o$*¾ Ÿ”¾yÇH¾ÅÃŒ¾}X†½W›÷<Æœ=éa¾èH‹¾hã¾0vë>§Ö=EP×¾R§¬=¹�‚>Ò�u½¥µ¾Ó¢ ¾µ} ¾`ؼH«’=âQ> íj>Ô�‘¾Ã_>Ý•æ¼6Uó=·}Õ<…P‚¼Ì΂>h9ó¾X0‰=ºõš>z¸Ö¾{,¸>¬y¢>Øý=¿¯Ü=QN=]e>$ˆÈ¾|‚†¾÷gô¾ƒ”>õÁp>‹û5¾RÄ >ꇰ=.Ú0¾§R¾à_ó½¿Vº>øf¾ÂiT>‰ÚY½\©®=œ˜>òN=D>< x> Y¾9ùq¾S㽌®�=½Uj¾€3h½‡Ùù=ð¿=¢ÒA>~¨»¾ÕÐT<Ô�>)²[>�ï«>9•{¾ñ >k>?ן>B™¶< {N>¯Kæ={¨=´ÏÀ½POE>‰)�=s>g�<‹#´>JA>>ç½úéô<ü¥ ½³V<…¢>Tõ�¾‚ %=„öl>%ÿ ½Kí&¾Jó]½iŸ]½——¥<1w]=ÄÔ½«Ÿ”>J#?2—Ͻ™M=�oU¾(�¯=;4º=1ÀÉ>¡8=�Ù¨>}﾿ꅻ­R<.jþ¾—üÿ<˜p½ÝŒ½¸¡]¾—7î= F'½J<½¾ù>63©¾”u¼e:«=–ØP>­Yý½ÆDy½¤ò=x F½0³>ÎT@¾Xpo>À�š>óL>5+W¾ÆQ,¿�6¿º¤a>†Ä ¾ÌW”>G >ë�•<дï;‡Û»½7 b¾IJ¾*T¤>’�Ï=x-’¾SêÏ=ë´¾€£•>·ô±¾è–¾‘p=g3ô='Z£¼6 ¿ßèõ>–oƽ:¡ƒ<:žÉ>Eüh¾¥¥¾»ß½;½ÑY>wì¾ ± ¾±¸½QG޽wQ>»C ¿Ç¦ò»¨±‡¾óö¾¾.Íz>/„„>±Ò¾ÿiè>¥É¾r±_>pi?hþ«>ÕµÓ>*Uå=·öû>-éw¼éÌ5¾:&>ÉÆR¾É{ª½½�¼¡ö=“H˜>8Ì >òŠô¾÷b–>eÛZ>þ²‡7> ½Ë±>¥¢$?æý†> Ýà=F $¾t>U'®=Jeî½À„<žåm>!?~=á#I>Ny3¾cÉ=?C,­>Ge¾f„»½ì¯ï»5òy"¼ ·"¾Ôá¾(ʪ>:Óo>n¾p;Ê--¾„Ô®¾f>Ÿ9V¾;y½ {J=ó½3>?Â�½Ž2å½õ+q¾yá¼Å�ò½k£Z=Ù¶þ=T>_ ”>^�K=Õ4†>¡«¯½�g>„qƒ½¶ª?>޳>O*B¾Ã ¾ó¸/¾×�=ž<Ð;¹Gd½ƒû=>�í½p‡¾lÙ&>˜÷X¾%L=Õ#ó=ÉΞ>$¿;¼2Åë=‚–G>x‘ûO—>÷(”=½ú×>2Ÿ>´ >¡@>Ö�Ç> -G>cà>§vD=dáË=±3S<®(¶½ðG¼ïŠT¾ ɾ�óX¾ðåé=ïÜa¾Ðöò=çZƒ¾§M@^-Ü=ëJ*>ýÈ;>¦Ý³½/¡þ½»{€¾ò¯Î¾ÿÞê½âý¾…ð*> îü½÷Ɔ¾§õo¼5º9>—?:—)%>¬Ø=®5½™‹¿¾=ž.z>ŸÏ�¼Ëí�>V=+-©¼?6ï<óC³½<µ½³ S>]ù¼$0Ó=Ç7>gŒ™¾Ò¿Õ¾f–@?å5Â=œã½Ûx„¾½Z]>© +¼ÅB¿ÊH‘¾zeý½ 0[¾Ëþˆ<–NμÎ_?S¸<˜{¾óÛ»#à¾Í>œÑ2¾'±@>ŠKu>‰GX:Q£¢½÷”²¾}:½=81£¾Ê¦í¾h•\>Á©¾ Òç¾¥\¾êA ½‡É>”Œ¼Å<�K½ ?]^¿~`±¾mj³½cÇݽ] ™>—�*>rÌ>X¥*>_²¼M›Å>¥R>¡€œ=€�Î=ø¨=Fï±¾0#°½DUO?§|¾¤(I½C�¾ÖD'>éúK=Üö$?0œm¾QÊí>;17=XFÔ¾ŒRá=Iü¼>&슾Ù޾¦Dˆ½àèh½d=õ½òɉ>…ó�>–£¾&[ˆ>Þûò½E²I>Õi¾›“Š>9 ½Èig>¥x¿V5s<ï�¾Ôú >]ïY=ÔœÐ>×L=>òF…¾wÑ›>”°�¾$.q>nÖŠ¾¬b¿b2 »¢²<>Û¨€><2N¼ÊV^?ªMC=Eî¥= W#¾‚ ?=Û¾Þþ¤¾£¬ ¾ª%>—\¾Yú¾Ê¼<šiò>ÿ>„i,> Ó¾|`O¾|€ó>w…?¾°Éœ½=<š>ALÖ¾p ‰>�sͼgB!=$º¦>oZ¾Ig=ºŒ>ã.ѾöU�=ÇÁ%½Œ ¾⠈<ËȾãî÷=á í¾†ºB> …¾†‡ã=q”>­í¦>d¥<0‡>M‚7¾>^š½7e¼„”¾!Gä¾/aÚ=KOM¾&–”¾ßGl>ëÉn=æ¯ò=WP>í ¤¼ŠI½>š²t>›’ò»Ì§>¾S¦>øÜÛ½a¾5º >^û¼½@ò=Ét ¾×›’<‹+¾˜g§>¢ch^½l¾(|>p ¿Rð>Û+±=6¡¼Oðg½õYæ=–_µ>–>±>ò»(¾Td?D›b>º…ª¾†þž¾~²“>Ñ£›>ÁJÊ=çÏ<¾BÛî¼Èmr>½:^¼îÈ3>Ë2?`wU¾Éë½³º½Dˆ€>Aù®½•&�¾%Ê“¾Â5Õ¼‡‚Q¾m`̽`aC>°âö=f&> ¯;¾�eͽ„¹ç½£Òˆ¾V.t¾D¬½>!ÃŒ>z›o¾Ñæ¾ÁŸ©>ÂÚ|¾²Ù¾¼t˜=F¾[§O¾B½}½·z›>Æ` >$î’½{Èê>€±ª¾->ï=1s�½)o™>�”£¾ÿ2œ=âÏ6¾‘½i¾#Òž%¢¾S«<êà>O^:<§WC¾9üD¼5O<¾‘ú ¾¨�ª¾`£&>‡ð‡¾þd©½¹ =uH>Öl�;f¡ê=š×Ù>à 7>*L>íZB>×M>�ƒJ¾ i¾ÊR#½PAL¾­c¿”üp=òâ>×a?Å›[>š‘¾U¶ ¾¨£>\ù‹¼‚—¦>ú&Ù½IFZ¾Y½>;@ =Üaü¦$¿Ño¾TÃ]>Þ>„·Ï¾Eü?8Rý½à;/>€f�½¸3C¾eN¤¾×8à>ÀÌ­>ßh@>…‚ï¼s~Á¾–r³= „ýI¯¹¾§ëW>ÐN,?„¼Ÿ¾Â�>)d¶=$ÿ&>‰<ð¨á½Æ7ý>¾¤ç½½¼F¾�Ïa¾°^,>öÀ¼úÈ>¾…¾¢¾¢:$¾™+Þ¾‰H>­½®>¬).½Y©Æº3#½ˆD’>©gß>áöí½®§©=ÝA½ø##>Á€>ß]‘½Lê^½‚>„öÚ>"œ=K|‹¾ó¶Ð>R?]Çi½k�>E/)=�>N¤«;E¾·ν•-.¿W/R>ææ¾+ͽaŒø¼}³5>xç½Rµ]¾—‘¾¾G‡c>Ì©¾ÆÍ<¾=; ¤<1í½Pˆ >8©>°M·>;þ =}ξ½õó¯½àú^<‘›¾óÁå½î/7=b!Œ½�³…½®�½"d3»¤µì>:^7¾£¹E¾Y¨Ô=«Y¸=ñm;¾„ã‡=ð߈¾+‹n¾ìÍ„¾">Ž!>…K¥>±4"<žºx>i’x¾_ÿ=,™½¹æY=ëT=µš¿_X¾¾á®Í½ùhù=–¾çzÂ>4«’½ÄØ»0„–¾AŒö>õÞ‘>3zº=–?}*¾ ÌŠ¾“ý=šå@¾¤ÌÏ>Á³š¾È…!?`#> Y„>Fˆ¾ÿâ»>O¿ò!&½@Íø^’D>Ʀ¾·£¼yj=ÁâǾ.~:¾dh=d—Ó>Z¼Ü½Ú4­¾K{/>C`°<ª�f¾:Å™¾²†4¾Õ:0¾—Æé¾¦C>>TTĽõzV>C¬>&êK¾+�%==â)>«{N½§K¾0SѾúR?¬P•>SÑØ¼`ɨ½”<6=›#¾:qY;xa>À]‚>S^=ãek=Š×�=_¾=�ƒü½1 â<ÛXî>N–«>¸$‘=8AG?ï4¿N4ð=ÿß2¼åW®>}ß·¼Ü¼%=~&<Ñè �tG>×Bù÷;M‘¾q*?ì�Ý>ÂG¡»é�º>1P.=¼âp=â·%¾Â»Ç£>æëO¾ÛÜ•>mBy¾|¬?¾J#<½ÁºY¾ÄN¾¼ýr¼€s¾Î�=‰tç<Ái¯ºŒú ¾ƒØÄ½’•¾5Ï_¿èy¾{W>ÒüÇ>0 `=¿y>ýu'=t!ë=qõ?ZQ޽#†>üyo>AG¤;¢*˜>­¬’>t4®=7Ë|<=,.>Q%¾ö%d>¸­"¾l” ?¨о&(©=;w©¾Ó`±>[w½å2:¿�øñ< Éõ=f>*>\‡½Dç’½FÊ®½±Õ¶½íF>ã°>ÇB=Afb=½`í>ù³’=Ycö>…¢¯;èÒ>©æ0¾+B½ò7­>Y?§½ex“½èÀ4=²‘E¾Ø&L¾Æ7â<éï5¾ø_½òp­½é�>f8ݽ�>÷D¾\†>² ?hé ?Í«?>ᆹ½~a²=65¥¾@¿¾+Dr¿*¯!;TJ˜¾Ñ‘¾¸ÔX½.Y=@¾i¼æ³»¾‘c‰>½¨6½éLÕ½«X5=e¾qŸ¾jAB=ÔÊ2>z®Ž¾˜¹„½>D?=¡•¾M¹>±Š>BU·>’Í:¾[ðC¾Q[!¾î;çcX=¸x‚=–ýZ‘¤¾dmA¾ÃAX½Ú8¥¾Ó»Ý>sÏ>ÈC¦¾0«¾ÞÖØ>Œ_@¾$wO¾©Ôv>k%t½–о(ö>â >6̾Ê*Ö½bŒ =SC‘¾f¾Ó ÷>à±8¾Ây9¾Ö«ê=l?$>–n¿¿¤ÿ=éñ™>3Sž>í¬/¾÷�³>RŒ#=IÐ�½õi=ÒR>ož‹=¹Š>gÒ=ãST¼;r€>ñ¾ž>¼¾v·$½qð‘=¤˜¿>†Š >úì[?Ò->Ô�g½\&`¾Vd>˜9À½|Ó(¾%ã€> +W>…QÈ>w*A=iãJ¾N]>ÏX>ÍŒm¾dy°½·Øa¼WW€=©¥�>]=4½‡'¾jê¾ÔS,>3®=�莺½ˆ{@=Ç>)½ùþ.?ü¤½™z»=ÿcÙ>? ¤½4é(½H·®¼±¢ù=ìÿ¿óAøºJ[š>®í¤¾ÎN‚¾ƒ'¿¡É½;§ëi¾’D4¾¬®½˜ÔÀ>|¤h¾å>\>‹“&½Ï9>Çáý>lÂã>wwA¾ý¬¼ ÁþÑíû=yÿ;lîY=g<ø ¿íÊ ¾—œ�>MZ>jKë¾£;¼¾iÈ/>yÛ¿ÿäœ>`…E¾’üÓ<›G—<°ìG>6E/¾„•L¾?R˜º·Ð ¿¾<�¼Ç¶Q>¸Ò=íþ½Ýa'>n0D=°ò>û¾lŸ¯=˸¾õ¯1¾� »=|ˆ¤½š»Ê¾xø>%‚½„ï<©C¿Ùe?så5=Q.ؾ©£;i�=ð<€[û>ÈsH>Jmj>Ì¿�>k R½»Ÿ×>þàì=�t¶>¾Ëd>W¤`>jò̾ö%Ï>ñp ¾ýc¾gá¾,y?PK>²/2½­<¨½Ów±>»@U¾ >-2P¾! Ï>J¾=Nù½Ò®Ú>œC¾Ò<‰<[ï�½iæ‰>‰Ä¼<ГB>éá¾ø·D½%vO=bW>¨‡½†c&Ãp¾†å¾¤Ä¡>ŠƒÅ¾Wþ=Èsa>×Ù=`¯÷½¬Â=•¸¿4h?=G¤;q”p¾Š!z>*&.¾)ó>W¾Ó2N¾h@A¾¤±›½z¾l½‹Q˽һ˜==¾T7´=¡ F>¾Í¿>ïÒ¬½ì)î½o{©= l¦>�g¿CÞ\>\æ¼<‚©;C�[>.&½þf¾è2¾pý�»ÚÊÆ¾\ÖO¾}Ã<ÜÃÝ>,²‰¾Q…¿>ÙÐʾ~ºD>ë>ò\;>GJª=KÙ<¡h>J¾¾¸¹a½L‘S½�2¾€¿.¢<Ïú>–Ê’>~Lê=`w”>�悾L¥�>“BG¾†ÿ>ÛâT>¦§>;“ !¿‹�>á‚ ?Ã܇=Ø~‹¾¥›¡N ޾UX¹¾�6 ¿(¯=:wa¾íîë=¬Á¾[n³<Äå<½ Q®=ÕØ`>q>>ãí">"‘>tÚý ì<še¾ð˜+¾ÿ‘;³Uˆ>.ÊK>†^›>æÄ»½jûp¾ƒ–�¼8ʼn¾züŨp¾ÂZË<À?G¾ªóü=§">¸o>¶÷’¾`I?Ý­>θ>»Õ>¨•Û¾ó®½M‘<†ðæ= Ç>­=BßE?Iù?×?’¾KƾÇ�>Ÿ)Z>%æ…>0Ð>õBɽÓ+ ?Oô©>|Å“>¿=r`L>�/ç>K‰Á½�8ƒ½Óx�=·úȾ5”¼=Ó"Y½.޾�ãø=“ ½½n ï=î?Gö¹¾y.#¾çÎä½#P=<úvl½PPð=èù.¾ùƒ½‚éŠ>Å¡>»>ɾQ„c=¼¾aƽ ]é¼ÿ �¾íLý½àw“½µB‡>Ï/O¼ 1>TÈæ>U‹>èÅO>>¹ñ½e8™>)Îþ¾â ¥>ÛÃ>þÁ�¾wïþ,³J>{Á ¾Ìƒ=ãE÷½Úû¤½õ±�>Žº²½´å’>s;? Ù~½�VJ¾“#.¾ž�¦¼ý"¡<¼·½3F´¾“ëX¾�p¼[„j>}n>f÷›;†§=^Å�>UÔ>ï9>v‚?µw=D¶Ò»ø�æ>�Õ¼¥†Á½© z¾n†«<áI>Ñlˆ>üaÁ¼å“Ž=t±O¾Õ^–¾>ƒN¾_"½»„d¾>g=Ò¢”¾„=a�ˆ>”›C½cè=¡Xq½÷¾5¼»½PcX>~(?zÍö=Z2^½²à¾8Ç=lv¾�C>°{>‰{J>"!ô¾§5î< = «>£Œ>µí¾ÕMܽé\‡=&­Þ=`•¬½ E™> wx¾cnž>#©F¾Á¢½Ž}ú>øŒÛ¾ó.?$à‚½h#†>‘‡ ¾Åp>vð\¼VÀ.>:AT¾9(i½F[¤¾r%ö=J§h>Wxݽ�íþ½oñ­¾*Ü–¾`Ýp>Ï'ƒ¾ > Œ=s‘z¾‘w«=û• ¾/"â>�p¨½…Ëå>3uª½¼Zþ²~‰½¿›9=á_Ô½�v‰¾îȲ=FÛ'¾Qà¾ÿ†¾e’éÚG­>™åj½{»‹½„>©Ñ§=×µ½=‹C½€ -¾qDZ¾÷ÕŒ¾7¶¬>£Ýø=l=¾šÒí½ÐëC>æ+­>�B?=5˜ö¼Ü’Ý>¼(ý½àO%¾<¤>)P¾Â¯= »=J6¾~ÿ½r2¾ÿ°@>,4¹¾›­Á=ò¡y¿§ãÔ9yã²½™>S/¨>{Ò ¿¾¾N¥¾èƇ½æ¿˜Ý->È´ˆ>Ëe½De{¾Ýã;½èÙÀ¾®[ª½Iù¥=|@¾ŽD¾æ­N¾àÍŒ½S'7½¶y=¾`‡Õ=ë!6¾3v2>¨¸¼Í$›¾Þne½õä¯>îî¶½ì  ¾*é²=�G*=ƒF‹>õ¬ã¼÷å >µµ‘¾Å\>?E¢>u[:¾o$‚¾r==m(ˆ=DϼC~Y¿?½Ë>翇=¿8ú¾ƒ8\¾Æ•š¾v.B½ f¿>{Š=*µ¾HÁˆ¾'bø=7 =—FE=”ľ_Qc>Ç}>>�£E>” ¿"—�½ZUú¼ÉS=‘=>ñ‚=¥ÈZ=ªÎþDº½À·´>¸#k=lг½>“~=Э¯=Vƽã!?¡ˆ†¾‰²®¾Ä|ó½�‚)½IN>x$˽Äò¬=aÒ‡¼õ†¾Ûß:‘•!ºû’¾øÞ®=-nk=áLB¾^*.¾ú+l>[Ý�½‰XB¾Þ¾Ï–˜=-…¾Ò3‡¾„ü7>€~Ã>~ßý=oß=G‘>¿Ÿˆ¼þuËÄ<á >þ¡¾¾�É <™~ÿ½–ëô=°>bù/>Я¼0æ>7ú%>è[«=ë8-½G€/½v…œ¾í…b>É`é>áú¸>¶¯>›qG¾üž¾Õi€½NØ ¿•”C¾‹.4?u)=¼P¾=ÐÛ=Pv¾DË>_‡½Xðí½~7l>˽¦>&<~¾CC¶>Š6ª¼ú K¾C¢>!…>†>Ï`>vpŒ½à½Ø½/A<»ï‰Á½s M>>Ø ¿‹Ê¾ª´¨>‰€š=[y½!‰‰½ Ì=½"‚½ýH°>Ô'=cSÕ¾¬¬%¿ÀÀ<¾‘ê¼mÊù>·×Û>š~½Wº6½ªþ6=^=6õ¿¼S®>UÁ¹<’ Ï=Þ>?Ås\¾ X–¾ç�>?Y*>‰r¾ÐjK½ óÞ½E�9==Žõ½'> 3¯>¼ÎÖ¼/AK>M„¶>Œ¼$>Gù >\{(½�¼a=F\¨¼]нœ\—¾Úì~½8S>¾ôê�>õ�½ä=d¼ÈØù=d5£½:Üͽ8õÁ<Ó »LT«>utf<›n½L…¾Xˆ¾÷˜¿¼1÷ê¼í€l¾fò¯>mˆ>**ð=wF-¾íçj<…™Ÿ¾TR?>1§t¾G8 ¿ž}6>ýû£½¿2¾1I5<)æ¾%øf>ºìþ6ˆ@>Ë×…>ÙWÂÂYY¼£¡‹½ :a¾ThɽÜY> Ó>ÌWo>ïn>£Ó¼)>±ÕܾgaV»µ¨L>÷›G>•¤»=#ÛY¾tk>Ì¥<*å³>ÈÜ0¿­,‘¾Â"Ò=Bˆ½!¯’>xf¾§î> ]}¾Ó6_¾£<¿­\Ë=D,=xb•>Ø#¾Á§¾ÆÓ¡½‡Gª¾øu½Çm­¾ô‚´¾J ÿ>÷º!=uÃá¾&Ké¾Â�ã>Ž>÷×>i¿¢I&¾�¿¨¾ðF<ÕHñ<@6`¾uV¾�«Ï<¡o�>ô�ö>¼ ‘>}„¾Ý‡>µ^K>,‚Û>íÚ¼ 2­=Ÿ(—<?£; ·,=¶/à¾y,ì=I÷T=H´i¾½Ø„> [>5H=¾¾ç»ÓK>!r6½;Ñ7dMœ=ˆ¹c½«‰ˆ>.Ù"¿Á[‡>“¦¾Œ^v>n$?�쾬Kq¾‰ ­=´¿aK@¾d>­Ú]>I¯9¾`«‡=¨Ã—½Nëé=Gòå=&r«>8_�>~C ¼z¦é>!Ë¿ôt²½æŽÝ¼k ¿ýEn=ÞÑÓ¾ï.ý=|ýP¾ß«=Ù/?>ÃB>e}9=šÕ¾ý׈>ƒßm> ¿sŠA=—ă¾>ð¾>ÒÏ;€=0¦–>m̾å½ZV»„pÛ¼Áo¾×tÕ¾˜ž¾$�º¾ŒðZ¾Ç‰|=�ñ½=o!G<ÝÃÚ=æ4?Ûƒ§½«Í¾Ë(=@¾ó©f¾ë/‚¼Èw�¾HÁÁ<´hË>Z0L¼o›<î¿ØnŒ+>*-€¾ü¾|6½Œvƒ?4ké=*­°<‚ >©Ï=·Ÿ>=Lྠ(&»ëöE¾g†HœN=½¿E»=æë¡¾ý–½S–j>G²ä>s�¾ímt>Ó0T>�®Œ¾Í>rJ�¾OS½ê=Â=v&‰½Î’8¾Å2>ï Š=n[o¾ÆÅƒ¾|¶E½óø?¾&g¾nçò=�¾��z>Ùë?ÆXÈ>~÷£½l²ù=îä;=à+¼n¼Ç'€½�žŠ;)%w¾0˜ô=Ø š=KÄ^¾°­½1%¼=<¼¼t›ú=:re>‘½>(h�¾ÛNw½‰Óõ¾-!>Ð�R¾ùf¾*ò#>´\¦¼8‡>\>W+"<þCC¾"al=üǾmzn>4 >䚨>+;©¼~ö¾j?…½3¸5>¹V?,ž¾P�c>(“ƒ>’¹G>Skr>X%L=�н{¹Å=}_Ô¾öÖu½éÈ/=2Ã=òý>± 佺ºñ¾Ô*Ö¾÷nI¾\y½¡%S>U<9=j(#=L-޾·P=REQ¾N½¦ÅÒ¾^*>ü4’=‹>ñÔà>wÅ ?=tñ>¶>îp{¾þu>ŠuJ¾W¼¾$e½Ç?¶>UÙõ=HA>TÀö>ÑlB¾Ï“§>§Ó�½’­>_¶.>å>@n«=L¹¿uK‚¾|Kn¾g¾»òÓ¾à^Ò¼6Y±>Û¦t=’G¾­é!½ÌªA¾<¹Q¾ÊÂɼP>(½ƒkI>Óh^>ù�ļ–;¸>Š­’½ Öܾg¶¾�>>Fä»Âtû=žÝ‰>`¤o=Ná¾û,Š>�€ƒ½µCµ½• „½—À¾(I¦½Ø‘½‚�ò=+ªI>î’E¾“Ñ*¾�£¾ÃÞ?7ñÏ>ì*¿‘ž©>PÊË=$Äb>`m ?­Üª<à 3>ðQ>—€>B&û>¿bª>~$Ò½ß>‰¾�±>r;¼¾Ò&Ѽӎ�>œðœ>1ô­>X X¾ô6=@¾ ã >ï�@¾{¾_^>&—=¡i¶¾P 9¾ÔEZ>cÊ ½TF¾¨lE¾‹%¼=a)°=VË¡½†›=é}¾j »=xÉh¼}�í;�a¾`±÷¼!K½ŠÇ±=à>Œ¡>'c�>ò L¼^='>LyS½…Òº>ç½z$?hq°>Ýíî¾jç¿3t ¾`?N>ÊCÞ¼x¾Wûæ¾%œ>,~ξ~Óq½S Ò¼kó-¾©ÒÅ>z®â="ëe>Ú ¾ ¨=»ð;)¼ >Tö<—†‰=Xô.¿\j½íÏ >K†Ç½¶êñ¼¡?¾ª2^=B? ÇÁºµæ¬=må>>Ø"¾ìg“=ee?ž™¬¾Zu.¾”,ؾ<|¹¾ß‹Å½ª)ä=ð׌¾}ä·¼|Y¾ýØ=´¬¾­O¼l¾}Œ ½í~‘>íŠ-> É°>ƒe¾.¼Ï¸r=o¼¾L¼ˆ= Ò×;f¼!>¼i=¾Ž#=¾„A¾´c‚¾>>Õ^¾(¡¾…šÔ<�Cÿ>=ŒÙ¾£½ ¾,4ƒ¼¹ >N¶½̹¾?g“¾Ïû/½;‹½¢³¦>®Ý8>óF>mã0¾r×½¶�˜>ùEu>FL>�½�¾(šk>©ºÎ½z;¡¾óKO½ä=‰>ðÊ<>wÚ>�à;S ¾�=(€�= )H>×ÌP¾È–q>½6H=ÙÜ»=¿=¿¾��·>²‡ò=À2}¾l®Ö¾´Ë¿Ùµ½¦Äõ¾¸W”=‡[>L6̽S½¬¾÷3==Žˆ¾xªÂ=Øè§>�!ü=ß6f½Ä´Ç½q ?Ê_½›¹ß=�oP>^•>z¤½BŒ4>íYÇ>¹KÙ½Rv¾ìɾU>=(ò¼Lm¿b–ã>s”o¾ÉM>jüù½9`¨½Èȶ¾ê`é½ Óþ>ƒŠ=KEÏîÕ¶=iâ½Rr>Ñ”É=Ê�F=á^ž¾D^Æ<Ð…-¿rL¿½æj_¿@Xþ>âį¾LÀß½êQоò)z¾®;x=!¾>)å¹=‘­„¾¦?õ=óž>Œaj¾¤¯š>÷ä�<š5>µ+½¾²²€¾çO>mÜ ½‘ ¸¾fSà> ß¾Í:Ì=„¿¾*æ ?­¿ëŒÄ>9Çi¾tHþf²=Ô°¾jë¾@Z > ð$?²Á =%Xß<Å”L>OŽ¢>ê>viI>R~>]¹½Fþ¾=1$>¢Y¾ÿ©¾žÉª>—Ξ>¾ÏоW†­<.Q¦=˜>â½¾H¿9�¾¶iF¾w5¦½Ì­=äÕ>—·|=>Êà¾ö…ν“gU>î%f=,뽇‰Q>÷ò¨=ùg‹>PS%>‘ÆÕ¾•ˇ>iL><ù=oJ¾•—�=#¿|>üN€¾ÙÞŸ>¾ì=nõ”»È6ƒ½x¾ˆ¾Kl¸Ä_=?†¤½–½½áL¤¾ Úû½sæ¿iŒ?Ôî=ü¤Õ=^†Ê¾j=NJÓ=1[¶=9!¿>ò¾tì>n߉>¨¡=/³¾í‡C>Ôhý»}öm½Ça5;@)&¾�ž÷lü>' >F:ë=wƒ[¾�g›¼C˾`³Ž¾^Œ�¾{÷íºùŠ1≯¾T¾·S>Щã=0Ù@¾ìÉľ¿î:\Rž¾�°¡>NW#>uéH¾1 >1—º¾Ru`½ÞÜU>Â…¾¡o¿K ¾g%= 8ž>ƒR™<2N¾6c¾²`x¾\:„¾6Y‡½fZ¾¨¾æ— >›tÇ>…м±éù½ýYô=Ïé}=ÚÜ¿´"Æ=Ä÷­¾º„>U¾‹ i¾ð8=_Ò‚>š*½š^Ͼ3ÄL¾iîZ¿º °½Hb=wŽÒ½óÉë>1�=ù“a¾!¤=Ö®¾Þ/ ¼öÚ%?�ŽF¾D ¾\±¨¼�;>¨¬>¾¸m­¾j*=¾É¢D¾«¿ã‰¿>fU¾R§ò>ŒRÙ¾·ãe>hÕD>>É=JÜ0?H;;ÂÃ�½î?p¾8i¿yA?x®„>åÚ•>!é½ðÒ>;ý•>$=º¼œD¾È¢K½Ø­—>K¾#¿Ô8=ô}j¼˜°k¾¢�Œ>/ 9šñ‚>é>Í|¡½E˜£=uçµ=“/Õ=öò¾CÐû½Jw!¾›§¼c]ˆ>MÅ¿;êÕ¾Bš¾zŸ¾ã <= 8â½v£¾X<òÚ¤<Ìè¾ÕÊ>Äó¾ö°2>h”= 3 ¾ Å=`XZ¾‚-¿¾±©=ÝÓͽ~'a¾£<¼=ÉÔ>l�t>ûæ5¿€ ?‰½!��=RÐW=ëò>6–>¥©>K‰?•ôR>Y¥¾¿^>€u¾22ˆ»Ó0½1«®=Ц™>§WG<Ç;…=Û]Ô½ºî= )õ=:l&>ò5 >îY¤¼Ää�=Ýù¸<ڨнĞž¾¦»=ŒBv=d‰>�›,½ys¾ „�¾ø˜=;j»¾Ë)D½8†­>¡÷ ¾r–Û½8,‰>¥dê½™'>Ñû>Iïp¾*Az½â˜5¾àȘ=Ch¾Ó1®¾´™5=h:°½æX+>c>2¬é½ÍÅLë)}=tœ¾#~>‘Ñ¿‰*™¾ž‰�¼–,¡½½t}¾XÑV>ºÁ³={T>> ýA¾CÁ> è‚>Q²Î»È_¿>‡>×ÝB>z(¸¾òn>âÛb>H:â=’{Ïns½7¢„>ï.ø=ݳ!¾èÞ›¾t�¿½ñ>ëN„=Å�d¾¢æ|¾*„î=jŒE½f›à½0½…Å)¾÷О=Š�±>{=Õ¼©>õö¤»(GÁ>m£”<>š[¾dÿx¼f#&>LK>ÒƒC=*ɽ·¾ì>tê³¾? 2>´½=¾±0Ñ=ûq�¾+‘X>®ˆ»?2>ÏÚú>͹=RHÒ<¦=ª>Ò=ƒ½ùvà½Õ#¾–d†cŠ—= â< ÅŸ¾×¡/¾Í|>¸2¡>6º¾ï‚M½¿|Þ½�9R¾tÔ¾è¡U>Uú¾Á`�<üv >—W>€CL>ßD=rè ¾Êõ˜¾QQº½H�Q¾RÉZ;("‰¾ÝÍÿ½gü¯=¥_zzp>÷zȽõ¶©¾g¥Ð½Ü=ão½C¶´>d@@>Õ–s>‚©�¾) ½)µn¾Þ>o4C>ÿ[7>÷¸q=—?Eºb¾¨êÜ=ú¨’¾ù®½¥ö×>GÀÖ½cÓ«½¶•…>¥¿¾ö–‚>¯ˆ¾GÙà½äÈ=Zx¾ Å<=¬ ÈÏ$¾üy[=£mà>nI³½üƒè½”]=>¤yr¾–½öÝŒ>Ôm»=Íá¿�ÅP½QÜ ¾’&f„û½J Ô<"ø™¾�×<Z|½í m>ž…F½†éI¾'’m½¹»…¾»õ+¾¬’¾ó N>Y¤a>Âý˜¾³“>YuW¾Oç¾_òo¾ZU ¾ûÿ†¾_ÒU>\Ô(>.:…>£â>Ä—°½›6о‡p¾%ŽS¿ZËF¼†¼™S©>•Ÿ½/“§¼‹Z¾ÞÌ:>M{º>Dz]=õÉ?¾uí7¾µÁ†½w±y< ƒ¾Os#¾îˆj¼Š>!½~â„>™j!>~w=ö̾á[�=l`ƒ=ŠB‘=- ¾ï𡼠S½óÍ�>ÇÊÙ½gð™¾(FZ>²‰œ>“9;¾‘R>ò¾·>Ä%>ì^ò>‡ê8>aí­½žåU=Zkç>š1½¸�a‰M�¾­�¾ÕŽ–¯ÁC¾ë»:=Ç‚Z>`•½úˆm>Å›>†‹™¾—€½×0κ0å#¾ºï”>g Á¾|�Ò=éX>þ ?H¡à¾³½í>¢bd>Eu-¾õœa¾ÑJF>ÊÔ6>¯]ê½3bð¼M’>?;ñ½…TöºIò‘>†ÎŠ>#“£=Ñ0¾`ñ>s0½ÏõÀ=%¾> «Ã=ö3³½�«®¼‰ïç‘©c½7Õ•>^8‰¾‘Wn>rÞ½¤ ¼”ò7>û�¦¾‚‰7?b Ü=óË >0$¾2'g=%½Å:Í=»…¥¼ám#=ò†÷>pá+¾ìо”,= Ї>:©¿üG=´p> 6>ÃÛ�¾¨»�>ƒ=ÌŽ¸>$[ν¹šW¾kdô¾‚}É>bdÙ>Ÿ¾›<"ľ Ñ»¾fŒG¾'fÃ=´:?>ÆiÃ=J{¼ºUÚ²½Ï�>ÀdZ¾ôÁ±>�ë]>—Þf=‡9•¾j"e¼Ce³=œóï=ñ£á¾ ²¿½XÂú¾·â>B‘¿ø;¾Â³=˜~Q>ÏKܾ½pÆ=ƒx¾Úªr½ý8¾ˆ±/=ûªG¾QY¾ûx’½½3l¾—=C>šÜ<âB(½Äά=V¤½éåÀ¼75F>A>xc[;Ò¥ >í˜Ì½™Pã½0Žê>}/‘½­QE¾"˜>‚i¾ÚÖß½Ô)„¾#µM>_Pƒ>À£Œ>?I ½9§Ü<ý -¼ªýH¾òà¥=•¥=ohø;S!ù¾Ò=EŠ>™¢½bú=nßj>1Ø<€3´¾¾x¾¹#R¾Tu>dŒ¯>Í{¤;Ý»ù½¼è—>šUØ=¾Ë=ØÁ÷>,”½>“0-¾EåŽ>—¨!;]j>S+½Dý¿¾ž�¼¼r ò=¹š€>ë—½ùU«¾P?ª¾�w›=<@¿P<‡½ ->žXH¾Î½%>Ô<ÜÜŽ¾¡ÈX>¶¾¾x¼ËÇþ<þ0B¾¥„Ü>ÇÚ=2hä>— >dZc¼kbÁ<'Z¼ÌÅG½~+ü=Ž‘œ>ÆBº¾(²?΀Ž>x6;¾ºÞé>u=ˆ„0¿|¼=wæ ¾Wë`>L6z¾Åðß¾ë½bòÔ½�Û[¾üŸ†=a�›½ÖCT¾ûœ>`)O¾¶²»=:";§,¿Áí\½wÑ–>�±<éžœ>b÷8¾pnF>Hñ󼃿鵾N{n¾&Óˆ>�qÖ½_4V¾38¸=iK�½ú b>r÷#>Ðé‡>Ñr= ž•¾. ¿=…»Ábö¾NÙy¾˜b½¼–¥¾G(¾]1>RÕª>ÛWk¾’¿½-›)¾8ˆV½z'?±SÄ<­KC¼$Ç”½ép>«bd>©l„¾aÖ>¾ŒN5<ƒƒ�>иS>ï œ¾ÅK ?ãЀ>'Õ>¸Kô¾ûÁ¾…—i¾ë(>š¿'>uÊ3>@×ñ½�í=Ô ½9CQ»Òÿ>Ö¤m¾ÝO¾$KP¾Óö>l«ð½¼â¾„PZ>�û”½=:>IkR='þʼÖ6ì½Dͳ½»â‰=EòN¾ÜÿQ>EA¾#öÉ=hêì<%$Ã>v>>éÓ‹>0|«=›2B½}Ÿ™>[Øí=W ‚¾Ð–'>;(¿àÜ">ù©½uÃm½+…\¾$Ò¼§«4¾]ƒ= ¶½Cš¾júÑ>H¥>,@=O§Œ¾“zñ>ަN=€sv=èâ¾^·½«Ú>#×ê<ôhî<Ëo =vì¾è=æ€^>L"8¾×”š½ºõ¾½ÒýeºÑâ>¯?¾‰Q>šëÂ>Ü¿¬¾RΆ>L ?Ð>#´ó=;ÂëUáø;¼’s¾!âH¾,²|>|s,¾¾{†¾€@–>~¡.½Ôí)>Œb¾K޳½Uµ&>‹U½=G ¶>qÛ>û[Ô=•Û$¾ZB»¾¼éo¾‡§¯½´Î�>Ó` >ÞZV=æÌ&½ó¸?bÖ±½/ɆX™è½kËü¼0“Û½ ¾»GX½˜³h¾X¨m½ ±½®yY>kt›>Ÿi“¾‰Lº<ÃZµ½,˜;=l˜L>v¶*¾PB >|ƒ*>Ple¾¿y=øG–>+p¾k·>õœÑ¼ÖÁ¾J“©¾Ù…ž>zÌ >•ÛB=UéT½~î;dRy¾ËX½™ËF>”ˆ>mÀ^¾ <ɾµë#¾>·½½‘’¾“º¢> ^8¾ûoè¼35=Ìk¶<Þ”›¾N±Ý=°J>n <¶€>0Ó@=Zá ½=F‰¾ã2>þ4­»<`¼ÿ 4>µÄm>ßá¾¾Ïsí½£jõ¾i愾bÔG>±à§¾»—=ò>0E¾ÄL>¼øÕ½°Gž=Ú(¾¯Ò‘< ± =ø»:>•Y>4ð>Ë}9>QÙQ¾ýv¾@—¾T@ܽL¶ >|ž¥>&x;å�¾[0>mSó= ;7¾Â'—>õn¾Œƒo½º‚¾ž±²>q�>Üô½Úº”¾�‡Â¾…F=Ûgú¼E{Þ>r't“M¦=Î×µ=B7©>C[#¼yÆ€¼MX‰¾‚�N½Zj¾8 û½7Z<œì½‚§=Ì�½¢{>s—d>_‹œ¾Ïú‹>㟾L¼>»DT¼âÀd>]B™¾!‹ÊÙO­>À^ê>Œ>}>󠟽�Âk½F<÷>Mh�>´ìϾŽ]Ô¾`_>TÜô=‰Ù¾;s¾ÒˆE¾(2¾cx¢»\W'=‰µ=o½J†�¾=΋½—E4>|R”>Ü¡ ?‹DÆ>Àõ¿Šó6¼›ž¾¶‚ì=àî˜=pRȾ¸Ê¾šd¤=–vÉ>nòʽª¥ð=a">^a¼¶›<¾üÐ>%ŸG><羳譽Ÿ³=¿‚=Àð‹½m{õ‹_€¾ÿ76¾ªp>>XuH>�¾½¸~®>G*>»�¿Å�ˆ>µ¦;>yM+¾ŽÁæ=ó¦\½×p>Hu^=¶éq¾ÄU¡¼#ØÔ½g�·<ÐsÊ=íw€¾w�æ¼Ö» ¾öâK¾Å½&¾Ó…>ú¯=ÓµT>#u’¾Öó½ób¿Äwž>ªÞË<©ñ¹½Ty¾³bξ®žš=tˆó½zÖ±½±“>w'¿Àøz>^Þ–¾dõò=ÀÖ>ÃÖ ½Û�f>w�³¾Âs<=-(I>¤E×=^�=¾}ï= ã�½*À ¾ì:^¾x[*¾^§j½êÏæ<Ÿ8À>GF¾Éƒµ¾ôFÛ=ßåw½¼-ß=¸¼Ñì]¼ �¾îÙ8¾éDa½M-‘=½ï=ªTĽC‘¾Ò²¾‚ý¡¾W§>”"º=# g=ɲ¹½{!5¾pvd;®G”>�g½šO¤>Ô·f¾·À·¾’<ǼþQ¤¾ó|>€Ux¾ï#¾Ÿ6ô=©É¼N á> Ê»XÐ÷=öG ¾ÜQs>oˆ>¦ˆS>$!ð>ê0²¾«Z„>ò4ȽˆÕ̾æKØ=,›&½¨(Ð=º#s>rd·=ß'ì=¯.¥¼Bν#p¶¾<‘>ô4½Oh >Œv½6å�¾âCé=K>�1Œ>¸nG>z©¶½MY4>~ ^}g½°m>¶øÔ¾¼l�¾YdE¾à?m¾4ì>ÓR¾3Ýž=öÌŽ<›Ÿa¾î²¥¾p><ª„¾=\¦=[êõ¼Û‘ä¾L*Ü=ÒŒæ=dX½GÂ>[U¾„c »˜vy=ÈÆ¿tƒ?tO»¾vÖ=(—Á¼pï¾à� >¡7�>¨ >´ñ ¾A+þ=º7»=‘”¾À¡—¾.�„> ¦X½Cê¾Îi¼;>ë`1¾gå¼@Ú?>Ñ=Ä)?öà¾W°†¾éq±>@1ý½}«ª½áH¾tä< ›Ô½Gk¾+²\>ö!…½°¢>ͯ¾ˆK¥=¢«¾ nš¾ÜoD?¸ë¹¾+±Û½»¸¬>”k£>_Û›½fÞ>概¾nd¥½Ìkw=ΉľÍÊ¥>_æ:½Ok�>¬¾.Á¹>L†Ê½’&Q¾h‰>¦b¦¾ŒF¢>�ª^¾Z�=ò0¾©O>ª³Ø=v̽3B«»ž>Õð޽k¯¾¶ƒÂ>ûrm>„sÎ>5×Ê>NÄ�>A‚=¸*ë¾g]‰=ε=K‘ƒ>þsY=›õ>X³{¾åÄ©;Ahý¾ÅîF=¯å ¿ê€>³h%>,ðg¾iÀk=Eò½½ý=­ö=î´!¾tß¾ U?ìw¢=A¾¢/Á¾:Ö'½hÜÑ>Aæø=a'«>¹z¾é�A>A%e=7aM<ÓÄk¾kü=µVA>è…½6ç>—5½Ïü>qJô¼È¡“;óá‘>¿¯¾òÙ>‘ÝS:ƇR½Ö›½��>$2±½0*>>h¾?‹‰¾ÏH½pì3>Ò†6>  “>l5½ëê>Ôm>��¦¾öÛ”>ªÒ=.ë >ÿ ¬>ù=˜N]¾…W½×‹ä½E§ö¾!CÖ½ú@E>µ\'>#nø½®«¯¾�ð¬½ßßU¾NmŸ¼•ˆ¾„§‚> ¯î>^”<>.¿æ=o:0½V\Á=£ ö½o¾Gì¾*PÓ½D+k>¤�¼,f·=x<>�– ¼œŒ= •%>Z‚?|VÅ='3>-ÎY½˜<¥ªÏ½ê1:RÄö½SgN½Ç�#¾S&m¾!}#>îì ¾¥Ñ]>Q>À¿A>¹c¾Hõ=ïhº¾ á1>7¦G=%$ë½"K¼$ˆ=µû<ù þöäý>¨�=Ô�½ý�í>åë´;{ ²¾ Qœ½Þꀾ7ð̾ ¿¬�P=ZX0?£]B½™Ï&¾:¾¯M?åω½7÷½ÌÒK>x¾�¾�V½.þ×½·ƒº=ú×o>«¥¦½XºÀ»V½‚>¦E6=Ïeñ½ ±(¿•Ya;Üê¾t€í=íö½ ¾óKa¾—Ý'>…ÿÞ=w“‘¾8Ò:=øM¾t >…jŒ<:§Ì=#ä‹>Øj†=Æâ”½µ(7>žáÃ=BPÀ§ Ú½-܈<4‡‹¾��¼;1¾ês?.Á>¾ÚU�¾üNí½†–Ü=ñÌ�=©>e¼¹R=‹›>³òù<~W¥¼¤˜¿<å²J¾’ >è­¾pÖ7½Ï)¾½`ì>ª¸y¼ó߉=ƒÛ¼Az ?¸óR;%9‘><-¨=:»Ë>nfñ¾ÌD½ò4`¾î_“=Þ½ ?Gô ?¢+¿’¤Ë¾Þ±Ï¾ƒ€&>j%Ç>m=õ½C¾‘½`šº½Ü–C»Òþ=s.#¾ƒ ¤>]Ð=ä¹¾.$L¾ûp¶½†~¿&ž½ãu>´Ä“>°L=LH‚¾ÑúO>$°ê½öU‚½H=ð¦}>~F¾ò2‰¾ÌšÆ=±g?ŠmY>ܽŸÙ˜=½3;R>Nä�½óÚá¾Ó�·¾ðk�¾î 7¾jßú>¸›¹¼Ž^¾ q>N×®½˜~¾—ÿ•¾{¥�=_`=4ñ¾î÷þ½†žX¾r ¾}¯¬½5‹a>+±�=3••=¥„K¾%o¿"A ¾™ë>�˜¾Ÿ](¾vÌ©>¸Àˆ=�Ó_>¨`�Âe¾ŒuG¾¬˜b>Á<�¾Ó¾SØH?«s¿xÚf;¸à#½,¸>±gä¾îM?ƒ=>k€½[ ƾnª:?fD½zÓv¾Ãẽdñ¾¡Zq¼2ºÊ<õÌ>·€¾ÉL;¾G™ >ýÛØ= |å=µ «¾Mók<·øq>aͧ>_8!?tÔô¾+оšÊ…½�Ö>·¾È.p>Nõë¼h{>“ƾpàœ½YÉ~>yK?è=ž.>†Ø˜»ª<�¾à¶¾ò‰Õ>·5”>“t‡¾wÂõ<(i>.Ÿ¾b½|ŽÀܽÀdX>{ÝM¾¥]¸v>VE">Q·=ZL¿d˽½½6½Ç‹¿�ªß<ìf/>†Ã>þ`=ë~?Ù+.¿ì«>Ñk^¾“;¿²¬d>}{h>,˦>$\�¾`´6¾°‡=¾fÙQÅ;¾è?>¨XP>ɰ�¾ÜÓ=PÈ==ÃY>i‹¿zyø<0À¾·Ih=c.È<ž”š>r 8¾Žâ ¾µ ¼¾¢½#Ô>µ’‚>qš ? žQ>g�;4D½4žÓ>´ÚQ¾2Xé¾j�¾qÝw=¨†™¾€š“½’Í3>•­>7<­½kc“¾M"Ö½TS8¿8�¬¾ ðŠ¼ ¼u¾¬¾Í½Ò­¼™¾°²=Ü•L¾�vj½Eþ>ð$b¾c~‚¾ó”,½ü);¾AD>¹Æ)¾éZ¿ûø¾Ã–>ã9«¾Gt¾ÿ Z>×…i>tw½L{½|ξv/<TY¼<›é¼ =SGؾÝVû<]óã½Úc?ývo¾�辯˜Œ>º/ž½Ç¶¯>¢…î½q&?È. ¾¿N�=ä~Y=–-­¾`ªN>˜5>mÁ†½d$¦¾¸ ɾ7¶1;|áP½  Ý>eŒ ¿N^>–U>±Œ=<ºçÖ>H�¾à@“>|3˜>Z?íCá¾Xðˆ=Î>Ev½¾×–É=ÿà,>ZÞ>FÀ?¾Cª ¿éT2=¹Ï+½c}³¾ð*>°O?›�ļwô>+Í«½g¨ ¿ß˽wû½ÏȾ&–">mæ ?éŽ>ì­¾ÔOD=‚û®>î1>J,ý»Ñ4¾»zN¾¶¾«²=.äš½MBÕ<Ñá­½v�>ë+‰>âž¾fG¡>î!>™i>3“>çr7½­ø¨=¡gA>JÅA=˜ž²¾c®¾r î=UŒ{½Úݾvû²=€ =nGh>ä > ž¾Pû ¾ˆ¿O…徨T¾× ‰½PSž>'Ų=ì>E¾½" ¾aãë=ÃÊW>o¯>W@¤=ÿêŸ>î3<éͽ¼ê¸¼X�±= ±ç> Ñû½ÿÕš>Ý)¾lÊy½Lº¾Mík=¼Q8¾gˆ½ÖÛj=Ü18>Ñ´;ï�³>øŽ2>èA~>¤F=ho½îár>4³¼›5®¼ö‚¿…ý¼²Œ¬¾˜B•¾E^ȽÆ-œ½õµ¼ïgM¾ê>¿~9;»ú¾W ¿Xþ>n�¿àÎi>úó�=7í¾ÏÓ½›Ñ—>¹øÔ¾#y¸¾Öâ軈U ¾ìN ¾ϲ½©÷>©âÞ>¥vľԺ߾HOê=95³>ž­¿$_Š>Íf›= ¸p>•¾rF}½ÈÜ(=Œ°?½9 >®a$¾„{=„åÅ>«¯Q>é3>É Â>«}¾¥t˜¾‚&£¾ %Ô7̾{0’<s—=ÏÎ>¹^ѾÉz-½(àŽ>}m}=åè…<˜ZF¾\¿ã½ºÝ*>³%× ›«½;ëߺwL.>ñÿ·=K�Ì>$Þ ½”@I¾PIR>cW½¯˜'?È^h½[‚½ÝöÉ»ä1�>¡ñí=Gî`¾ªºå¾ZJÖ½rò?sA+>¸6*¾Q¯;¾¾¿ >ó(u¾Éi€¾Ëë ¿TG¾]•²>²¢½mg=H)“>â=¯ê½ÃÀù¼ !«>…}p¾ Ø=Ÿ90½´â”>ß*º>Ì(>½Ìо¨W¾CwV>ÒË9>Ÿÿò=6]�>|2A¼b能çEV>Q �¾Ã¾ ?þe>à31¾Æ¯¦¾ž»=A¾ØåK¾¶ß2>Ñv¾€¯¾ÇIû½�÷¼=p�¾ˆ’J>§ E¾ÛøJ=ÚR‹¾ì}è>éÌü=*,>%Ú¾_‡> ‹§>Âpü¼b4¾ø=Çj3>;ã ?ÞˆE=îDm=ÅÇY¾M&z¾¿‹>ºKñ=�ñ¾±A>>c^©>;f#¿LÓX=©nœ=ËX>ÇÆ·=Ôú\>ìË>>¯æ½�R\¾q…b>¤Á,>#-¾îìé=ãB>z7?Öj½¤>¿ÕbÝ<áÌœ¾ ê"¾‰ß“> ,D>�Ku=ÊR½¬h¹>çœ'>žóC¾2K‡>è$„=û]Ÿ=CÖE>?†¾Œ¢†¾�'œ½R3ؾ$¯2=˜U[=tq9.ø>ò‘>yD?]È =à3>zQ˽úë·½G ½ ¤)>ލ+¾ûÿ:¾ø­%½‰�ˆ¾6� ½«:¼÷,C¾Å�l<òà`;�‚¾Òòµ½c”D>¸|>o%>¸<�¾\À¾«„·¾äp=ý>»·=œ€5¼´[Á¼| Â=¼ >ÅW½î=A‘Ù=9š\¾n<'>(•Q¾å·q¾O2¢¸JkÛ>;úx=ÖÐ&=ð6—>âò¼¼Ùä=‰ê½å.’>vD¯>œ½àhݼmC;}ùa¾Ç&è;Iº‰>¯ÂȾ œ¾žþ[¾p9í¼ÂXµ=º>Ó—¾P°¨>t<>ð°o>Nƒ>á¯?�©4¼äBí=)\¾°†í=ªlk¾{.�¾© ð½sÓ= �ç½ i¾ä†‚¾½i±=6ÿ=»˼²2e¾Rv‚½ë½ÝÛê¾Ãç¾=Vh½*-³¾Õg>6$×¾Ø~¿ÿŒ¾<¹Öu>wG>lß¶¾K� >Ù^™¾H >æÎ­=7 U¾¾ ®¾çؾÇŨ½ißM>B:F¾mì=¼{¾ä�`¾S'y>¢Ü£¾É-‘=îgo>Ï p¾¯Ë¶¾ñœ´¾gë>¨È¾®¤¿ïëq>ßQE¾ÅÒ>Õ ¿éJ>•íD¾ê¬¹>hûÙ½B}>k£§½Þ¤>"3=*½¾DŽ~>œY>’ŸÃ¾«Ž±>TÌ»¾³¯4¼Ôˆ2>û¹j½ï€>�@>;m¦¼Ià½a`>crýgç>lj4½}Ü'?ŽL>ù^9¾¾‘ ½ÒZœ½7úŽ>‚³½=o7�¾byÔ½î_$>7¦C>˜õµ½Ïîü=nf¾ý²"=†€?¾2u ½½>»é–>9»¿¼NH¾Ûy >xR?ü¯>ú ¾í÷O½f ¾ÊÇ3½Þ×¾Si|>yrÚ½]Ò¾. ¾ÇF¹¼4}¾ã3P=¬4ô>µ?�¾ kU=?"6½ a=L©<šÇ¥=a¦k>”<¡=m�>FИ>wÛ6;‡‰¯=ôR>É>ֽ̙½2d>âV‰>»´ÉpC¾M|˜»?ÙK>‡í>�[­¾“ ‡¾0X>رC¾ïá�¾!/¿GV>q­ö¾ÿ ü>w¾üñµ=Zc<>Î\§;(̾‘¤{½.0¾t<>ÞXö<¹õ?3\²¾rŒd<#ˆ >¹;û½!ÙD¾—fؼk×,¾-Ÿ½W‡Ê¾/i5¿dþ‘¾`]™=xx>)> æ=¸á=Soh¾á�>p{³=¤î¾a ¼u->Å×ϾÁÌ=†Œ<©º·¾zÑ‚½½É˜>³µœ>ÆCH=�±p¾Å²Ë= »<ßϬ¾‘OÜ>0 ?>–þÄ=UéY¾Æ±>ùó¿®„�;|‘½ÉI”¾iˆ>Ï-½7±¼¦Û!>ý�¾>ä¾GÊ>ª²­=k>¤@‹<öä>¾×›¾±˜�>žý=[Ƈ=ߌ&¾ëúͽ@WÚ½ï¡I>ã�g¾´m‚=_5¿­">ì}>³jÛ= é9¾ö~±>6…½èÀ²>ºŽZœ¾£È½9A¾Ïì‡=¹Š¾†ê(¼«{º½üT�>cd§>U”=±|‘>?‡—¾ë·L¾åÔ‘¾èÙ&¾+Û¨¾[˜¾¿mY½ZP¾Ï^›½á™>9¹)>û­ƒ¾œ&Å>;á;@jÏ=p S¾)ˆD½i+‰¼j…¾Ì{�¼5Öç<}K`=B14¾/Æ>O‘¾ïëø£w*¾5,=Ù>Ѿör%<` {¾€­„>‡ÝP¾ÚÙ‡>Þò=Ä…`>C)¥>1�(>è¸Æ>aj=XFÔ¾uÇ—¾Ì�2>ü¥š=8æ´;ƒ�›=˜Üd>ÎE ¾—Õ>äæš=­=Q¿¾Lèê½%”_>Ì‘`>Rwýƾ2¦Ó=ÞŸo=Z𑽄Ú7¾SU¼J§%>nâ›=Xš¾#ßÎ=ý�é½OýÚ=uð¼>û…¾Ö6Œ¾´ß=k]©»&µ>»æÜ=BP¼€·¾v0¼½ð§3>6©½ð½§ >"Œ'<Ü¡G=Žjf¿5¹>/§½4÷»ìÍ{½vÎO¾>½¾÷œZ½n¢°=ç›ö=xÊ >¾|¤�¾ƒ'�¾‡0i>²7_¾qç`¾€u®¾0„½Eº>ÿæ¿ûÉ6>uôè=Ÿv>Àʺ1gª¾éñ¶=q�¾UƾÁ°½K×¾¥�‹¾¢Ï=¾Ò‡€¾kË>Í‚Ÿ¾¶½'¹/>ñ1¾Vn²>ë…¾¾d¡>9ùÉ>ÖGA¾!›™>Õ¶Ô¾²¤<¾ð¶ƒ¾þé½~÷�>!޾·ŠN=…K'=¾7°¾Ï`>ןӽOàz;ùϾ`üa>ÈœÀ½P8½žu.¾à¶(>õ“>@Õ=wN¿>IV`½oþ>9r×>ÏÚ›¾[š¾Önð>‰0È>Åïe>(&¤½ª¨U¼~æ„�É?º¥j<¥˜f>¡¢§>‰—Å=J]À¾s/> ý ½@0¿‡c�;ÙS>H”¬½…¡¢>è¤>ÄaF¾_oº=â÷•>X_=6³ö½)¿ëí= {¾‘{Þ=C�L¾Îcƒ=�¿ç½S© ¿Ë¾p²>OéB=§S¿Š@ɾ2¾©>ù9Ø> ޾Ó@f=û6u=O¿Œ>C®Ö>Ê9%¿@ ÿ;îþb½×AX»L8¾â7�>XSὋ½>—)¹^=ŸtÝ>MüÖ<¤ç�<¦Æ¼>\5¾oÓ‰¾ž †¼#‚@=¼Ï½’ ÷½i<Þ=Ó¿ >]=÷ü >ç´½„�v>H¶¾AË:=¤‹>§õÔ¾UqK¾½/Ž>'k<·Êž½bl>5ʆ> Í|¾Ôb'>g3†½Õ}¾áŒÔ=Ÿ9¾Ú#¾ß†é¾qK½#ï§½³õ›¼ñx˜¼/u ¾ˆ) ¾÷’J¾Ýoj9DkA¾Âgj>e ¾�V©½ls¸yßp>_x½õ&ª¾ÃWÙ=ÛÅ>ß² >Y™[¾WÍ‘½;»þ¾âQÛ¾62½\‡=¿.ü½+ ™=žâ¹¾»QD‘>&S¸>Ž®€=ÆT¾m+>êû½¼üD½&h’;À™U=©¾œ>9¨�¾µ>¾ËÛ‘½ì-½£R> #?'Úµ¾�´’»`‚¼/#½nà”¾/PY>T�<™÷{>ަö>™н�Dj>ֺٽ夦=qŠœ>ýS¾1q£¾Ùn¸¼sx(¾ðà;Ã�ž<¦xÞ½=1Þ½2VS=ò-©¾$e¾sš>ô±,¾ßz>xF>‰—­>t*>‡¡¾Žž‰>îÛ>f#â=QؽP–¾(÷ ?";$¾Ê¼²>*mŠ=¬"I¾)7M>îÑ5>÷R¾¾î7ˆ½$¨õ>ùÉ>”H“½ôUˆ½…i¾½{lH=xKW>¯½Á¾ã§}»Í�¾œ�i>â7d=@v)¾U(¢>êy=Ý’¾N8®=鈎<ùtŸ»‹¡¥>Aïü½—"¾ÚÁš¾W̼0U?èP°½ä®}>Ö;‰=Hê'¾ÍaL¾Öw°>”†V¾E<0>c²¾Ff>?ýû=~ƒ=¥Â+¾I°{>ün´>ºû;>Än>J9½o2ʽÉ|§=�þ ½s£„½.)T>]­½ñøo¾c�Š;¡D¾ùx>ê>è?ľÂÏ­>³Ðp>ŽØ€¼ü >²¸K=Ù¾C¾‡˜¾éTÁ>�?U�„>”ºç;DÔ½5­>±ª­½®$l<8Ä¥¾Ð=yÒ›=Å'¿±©Ú½�y>Ù£0¾�]ϽÿE½_†»�ؽÀ‡k¾Ò‹€=ÞÍX½›Ý¼�ÄR½#š3¾ýHß;­‡½%º>ààÔ½‚œµ>6»¾=›A¥<Œë·<ÓS>½œ=­‰�>“bb>lP>-Ü=ù]‰¾ÜòQ¾ºã>?Bˆé¼”´*¾³8>zI= ó>#iK> Ók½�V>¾y¿u¼� ¡=vœ[¾ÿ¾ËcP¾¿-ž½«Ëé>ºe˜¾‘½©,?¹©=ÿ´2>Hàå>Ÿ²>‚²>À]˜=VúÏ=DÚ—<³¨"¾�Ç>)=1=2Œ™¼Ñt»>A>>‘¡>î6Š>ôV:½gó>Ê‘‘½»ì…½¾a>‹åV>¼,�>·‹ ?³)F>ðÒæ¾åý¢=­çQ¾Úþ >y6·¾M>¾¸RK¾*„>Ë ¹¾½#Œ> A྽1ç¼*M€>W¥¿¾¨I?’þÇ>#S¾u{ÿ½^³§¾dd¼¾�%¾¾èw†>}?¾}ÿü¼˜“D½ÜtS<+Ã=h«g¾¼U¬>;É9¾ÊQ7>8œ]¾ûòñ½ìÓK¾¡È->=㩽û…!½€ä.>Þα=ÆZÁ=�ÊW>N-–¼ÄH�=�Ï=RÍK¾}]¾¥q´>–Ǿә缀*½~ªö¾`¼h>á8Ò=ь׽’u𾍩ï½ñÉš=N$à¾ÁÐ>«R—ÂXE¾¯¥Q=�¦ë=‰À$>hú¼ºŽô½¢P.½'w*½�Š„>úŽ;–ù ¾íæ"¾æÏ¾Å>²V¿Ÿ�˽r³‰¼Ü<¾‚:¾¬3f=d]>â�¶=Ú:š½Zð=ÄÑ >Y›=±÷†>ZB=Ök†=.æ½1Ƽ<ê%U=X�J³å³¾ ÑO¾¦éˆ½Ô 9½ÃE½ãH£>—/=D{v>¿,?#y÷½ûòX=L6ž½p7¶>¢¥Ó¾¾µ>NS¼èw‘>˜æ™>X¾ˆ>tcƒ>íh=êá=øS¹¾Bdµ=Žð¼ýx½“UĽn¥è½{¹Í½�Ùœ½¤`¨¾äS¦>U¾Ü{-=¤>fü?ìü>ÆÜ¼U‰–¾¦Ÿ$¾–Œ!¾e[K=0Ø>E�¾Ø]¤LR¾<¸@½¸mü>>ë¾\¾ ~>Í> L$> <œ =û6(>¾Åm=KH5?wáž>Ĭ%=;½5x=§ì!¿û�ë>„ >ݼ­Š¿»?+>€W=]ß̼ã¦s¾ki >fáÌ<ë“K>R½¸¹ >',š¾ÖÍ>‹b>l¡¾`çÆ½%é<íî(>ÒÇ‚>Ѱ�¾äéŽ!yö½;â½4Ë%>gò¥=p¾‹ö;xä/>ïLŒ¾×„L¾S8â¾_�˜¾e�¾ôŸÌ½²oï½ô$¾bÞl>#”5¾lƒñ½tû==b…º>Ûƒ>¼•�¾¯�(>OŠ>xž>sö®>89²<Å_¾õ<¤-La¾ðÔ¾-ðï½1ÑϾ¢ *¾ˆdÚ½fK ¾Åég>q´3¾,D=o8¾‘ôã<,í¼"Jé= 7‡>.÷1>�>[>΃¾@K¾½¡

u³+¾ûÎM½ˆ(Ⱦ9¾oâ¨=ÝÈ´=ìù¿yF§>,©?ð;;òþ…¾‰·¾)ó>ô°Ê½¨ ¨¾UZº½©ˆ@>Åï,>±>Ú¼³"ˆ=Ôó†<⦾<Ùµ½L˽ð9‰½”Gø<ÃÂ=‰d>Mgy<$É*¼sIؽBI¾3µ¡=¼cô>?‹¹>FÅL>nñæ¾>忱¾Âj>\D½3áL½{\+?Þ©¾2éò=–“<ß}$>ñ@¾bö¾ú‹>{�Ñ»²ÂŠ=Öe¾>`x¨>|ØmÀ<¶­>¼¿˜b<ƒS>’ò—>pFy¾ðr>òãü¾1t>?bC¼ºT{=VÅ¥½;–¼ÿ ;P¨J¾Úáø½Åaš=:g(?rØP>Ý޽‡¯o¾†óº¼E)¿!tÚ¾�«ú=†&«>Wð½ƒÕ>¦Å¿šs‹>MlJ<-�E=C “¾ÞO¼>—î>Æ¿ª;¾»­K>/’p¾¢« >–ª>Ôa>€új=!q=}!=[󓾯ÔG¼µ=m>îÇ?¾ì•> XÛ½gá�=O§u=A-1>i~½=r1]¾Óá¸>o:½Wì7=à v>��¢<–ô¾‘¶S>4y§¾9°=›|m¾²8�½aÏÇ=ö¨ß>ÆNa¾Vá‹<óì ¾îr¾Æ=mœ <Õ5´>5j²<½´Š=#ëƒ>„º=>’>pf¯¾#i`>ê E¾I»>1û¾Ñò½%¿>¸Ý�=Œ‘F>¬ì²>B7Š>ÂGß> ÿ}>h7_ºù º¾‡?´c—<š–>>¾;}=Žc=Iaƒ¾¢Î�>Tû¼=ßÕë½Cš>"W€;ï>T 4>‘ÿA¾ Ý»†½½EŽý½Uz9>» }=;4ö».ùë½:!=p¶›¼87½jQø= õÛ¾ï¶iÛ½|hj=몯>·[±½ü �>Æ]b>«-¹»Ô{(;ÀÇz¼eÈ~¾ZÓȼÃ$¾°H¡>¹Öß½ZÇ©¾@l> Ñ@>ð“[¾Ó�3½¾/¿>g´j¾Ì´= 8z¾Ž?‚=Æ¢¾¼ä¿¨o¾ÇÀE<•â:=–yϽ_Õa=Ùî’¾ð¨B¾?*P½o&t=˜ñ4¾,˿ڕZ¾Ø¾¾gžg;WQ×½K¿°ž¿ê4+>¾¤d¾Ÿ<‰>òÂ<>ªÏì={JÊ>âm¶½µÖP¿1Ï2½ V$=Fê³=Ž�¾®.“>*)¾E¾…¾îƒ>Bnµ¾¨jB¼ÐF=œ€Y¾ˆH¾$�Í>8TS>Ù�–¾Dšì=\éJ¾åû¶¾w: >Áâ‘>Õ™ >qq€>j†¾ØJ8>@fç½›ûˆ=þe > _­>XZ<¼CÛ>õ½”>õu:>bß?JÕ >Ξsâ>__½ˆ¸´= ÝÞ>€9伩è„=ʻɾ¦:k¾N~Z>6(ý¼¤Ý¾9¨ž½„º ¾±ó]>²¾åm…¾éá“=µ\w=‰ƒ>ß”W¼?Ú>H¨—¾4õ<˜x.¾îȾW¼¾uÁt¾úƒ6>"¢¾:Ë|¾3f >¸ö˜¾âZĽÁtm=pòÓ;]*£¼ßÖy¾-ݾl¯z5—V¾#àz½fÛ÷¼Ro™<¼hx>÷�ë=!yU>ñ©=¬_s¾¥:[>¸ÎŒ¾ù£{¾оKÚ±¾& ‹>…�¾ÑZ3>Y_$¾# >µýT½‡E>˹ò=AÕ2¾_gì½r¬X>å8ʽÄη½Õy�>�Ôœ¾v§–¼,“¾éÖÛ¼¢g¾‰M ¾^|8>ÿνÄɾHA#>}÷Ͼ*냾M�6½¹e>dzÌ=àB½€ÎB¾}°"¼P¾ýÌ=?šág½±'e¾Ð�/½Eq ¾r²½\<¾> °=m�¼¾º¢¥=gu9;àO=u�’½pML½Â’Ç>!lϾè§R>OH7¾ R‚¾”bö>c¢‹>ßù¾G0>‰ß¾J‘>BM>mP€¾¼)?Df¾˜ª0?ŒÁ—¾Q=¨)>/>mÒ®¾¦ø.¾È”!½|õé>{/µ½.íå> ´¹=ñõ³=çh?2ª>ÀÎ> ¦½ºôq>¤÷=Ô¼>×íã>�q¾ææ×=0ûÜ=ç7»¾Ë[“¾^¤¾Ö£¸½¹z½ïfg>ßgO¼n;È=‚â±¾jŸ&> ®´>Ésµ½!޾v'­=_î>D„Ú=. í½–£²>è?ÜÂC>>嫹+bU=?Âí=ާM¾‹#C¾Oxá໽šÅ³>?ŽÌ=ÑR�¾ê\>¾thÔ½¶–�<�¼ =Ôó¡¾f±1=ä ¾ /½Pý¿¿Ð>/«>4L>{}><�UÍ=® å½.x ¿öyþ=â�t>ôcÍ=¶Š÷=Qy ¾}=¾ßr^>ð—o>2¤&>Œñ?×3Ù½î¹Ê=÷%]=hÇ¿è÷½ÛKÙ»=SÓ½;ºF>2 >Å>–= f¿Æã„> Óª½¹+>ñÓξ; �¾rò—=Õ÷2>yó×¼� ¾Ês9½ Ø>TÀã>¹ü#<μ3=,.¾ãT[½Ds•¾êŇ½?ù(¾�wN>Žs*=YZɺžBÉ>“F,>±&µ¾ß[?;å;éÕ—>z+H¾2N«¾É?¬½Ù„a>BZ¾P&žþzf‹>S)7=ŽïϾªô¿½Ÿ_3=¶%_¾ú‰’>¢#=NÞb¼º?ƒ¾Hk¾&n=»_8¾òÕZ>ñ:}¼Ðœ´½!i>‰Ü§»‰kü:ò]{¾:må>áxÖ½[*³=ò´ ¾ÞÑ‘½Âtñ;xó´¾÷1”=ÖDÖ¼ÖÕ¾^í*¾æ¨E¾ÃèW:ÊÞ„¾©ÿ6;/„¾©3Á>…%¯½Â&¾e™½€s:>Φ>!„ >÷e£=M>ä¾ ê?¾íRœ¾P”>Ò§“¾h O=gÓ¾ï�ª=)›k>+¶)>Äɽ‡[Ľ"Y¾Õ÷…¾ÐÎ=ñ§‚¾õw†¾Êc¿$tÑ=§ña>rõ>>çÖ¾i2½r­H¾a§*¾X¹>|îA¾-“¹>ÕÈý½E½À¼µŒ½U§£½7ž ?ÿЄ>Å =Õøà½ñ~‡½ö:›¾é¯¾Ä6(>ÓC¼-ă>hg=Þu%>ÆÝ�=%«&¾Ê>ñ¼e¼4¾“Ú>M¥¸=ó‰<`uJ½ßwê¾äR>ߥ½‰Ó= ¨u¾Þ®w¾ç¬=-I›>õš>¾Í´>(&Ð=a¨ÿ>õçy>Fv¾Œ×ܾohˆ>ÇQZ>§i€¼ÙX�=B„/¾øÌÊ;�“>ÉZ ½˜ˆ¿¾ÄȾN�×=æ/†>Íkõ¾ö)>à×ݽŒkQ<×™B>6ûº½fÙ½‘ÉýÉyœ>M4W¾<«B¾žøÍ½Zo^>ž›Ö½#~½æè½Øûm>h°½y8½=îKb¾xu=©Df>»½¾Æ´¥½Ò9#½›Ò½ÃD¾iºû»% >ËOs=,é/>™>uå¢=åd¾b3=[>Lºß½²“½F¾Ìg…>f)ç>/Â>—Ö ¾�Ye>ÙOm¾Î‰>å‘=š5=[]Ö=H©¥>þIª>†f°=WÊÎ=€s?>‘>3N4>ÎÒ¿oÈä¾�^�>üÆ%>N‡v¼²}7=o¥Â=5ÏP>ZVN=ûŽð<©sº>[F'>¯¸!¾Žý=�ÝÖ½te;ë¼ê=ª™[¾¬Ð;u)¾¿÷½K̘¹b³õ=A;š>_Û¸=jm’=P¼½«â�¾IÖ =:Üá¾¶¤Ó½zνR6= ”ž:�®_=©îº¾¦Ø¾–�¢¾ÜCG>² Ý>"5>i š>Þj¦½ '�»4³J½ˆ¬=¿þ½ ²¾ûø¯½êò¼¦y#¾xǤ½&ܲ¾¹…> ¥;bN>G„á>û�•¾ÆÚÌ=ðk¸¾Eå½t��½;V½� E<ò¹ >Çíh¾m«(¾ÞE½2÷>$9Ô=Rv÷=ì"ƒ¼~R•½§%e>ÓL1¾Å$¾§>ê¿9¾Wô½¯ŸA>.MG¼¥ã�¼®üÁ½ÛKн±Àl<­ ¥>Ó0D¾· :òá¾e¥—¾7k ½y ¾•5�½ÄÜ=.Bs>`z{¾á8*¾õ³�½üI¿™µ>÷»¿â*½º@¾l§Ø= ÝѼu¿Ä<䄽rŒŠ½c±+>./’½#d­½�Jå½a�™¼}bM>%¤‚=É *¼ËS¶½E'Ó> ½ã%‚½ K¾ì¹=‰ɾ90¾G±½8ˆ¾Ú³h>g=øäˆ¾[Ïš>ªŽ¬>¶ý…º×\‘>Ñß >‹•£>g%#¾Kmp>XÊ·=’ó¥>éí罈š\¾Øâ‡>#ƒ{=¾EÚB>µY ¿ ­û­öY<ÛsŸ½u¢=×U=„µ•¾¯Q <2OE¾#v¿Õ£š¾Î¥S¾Â•Y>Ø6Ë¼Üø"¾Ñ^9<"i¾ÔlP>pL¼ ™‹>ùà >KªÁ=S™ƒ>ûP’= ¾T‚`¾Feó>ug!ºqE‡> H¯;Å �½"Š©=¨›ì>•–¸<ˆú7¾î›ý=Y•-¾ SC¾pï:>cè⽡À¯=lH_½Fv‚>澄®¸¾™‡�=iÁ&¾Æï>þt£½6ÿ»«v¾®[x>aBƒ¾õª½iÍå;ÃÚê=}êä<Àz‰¾bø™½X5>å6‰=í«æ½•³½óüï<éŸ=ÌÞ>yæ¾äç=µ$)¾D²K¾^ö ¿®¥¢=¦`„¾ Ù–¾K{Û¾ÓÛ˜½^¢w>Ó6޽¹ij¾9(>© X>_y‡>¾44(§j>q·>²s(>¬oE½-ŽÌ¾÷,!>¿m•;ÔK¾lð/>ïV�Á=KŠ�¾lÙæ¾—ÀQ>Ú¤Â>O¬X<¾hÒ¾Ô¯¾m¯­>§ã¾kÁ$>Ù}&½Ÿ��>aaL>†—v¾z7¾z ¬¾ÿrÐ=<<Jµ=I<¾¾ïè=š‹>hzI½“qª½4#z>¶È£¾$ì�¾¡i¢>fŒe¾{ü°>h�V=»Û½3›Æ¾ˆãÿ=P•±½߃¾˜ÍŸ¾¾´Ÿ¼(ÎB½Ón>Þ¤N¾¦O¿<-=Íßã½Bn7¾¹ÖŒ½åM¾/:=Š‚s>l¾ù‘>ñ™Õ>š]›¾M!ˆ¾˜ò¾`Í%¾&²g>É£H=¦æÃ¾`¢Û½0_>ƒ¾V>ŽÓF<ã%̼޸½Fð½<¾ò=#ÀǾ¶Òt½h©±¾J=…½Ø>†”º½ùó×½#B ½Àm>MÕ˜=3©>P¨´¾K`W¾7æ<|gž¾ ºî½Š!V½œ~f½¶×�=lS½‡œ!¾²f)=Ûh¨=ˆY¾Å•3=¯:ù=笾¶¹_½”^’½)­c¾ñ’>Y”Ú=¬['¾ +¶>x¬=±¶>¼§Ú¾+ ¾x–¾Æå*>à]ƒ>§i.¾Š�0>›¦â½Uü]:ènñ=׳¾}"t>ØkŒ=þ:…¾:TÅ>Bòk½ÈƲ»¡]¾²Šž=v&¾>z7½Â§Ø>Ç´=Uu>Љt>ow½¨�¾–d�½ëÀ½ø K>—gá½>e¸>ÏÜó½œnˆ¾ùǾ”·>El—¾«Ó©ñ­½L=>©­7½Q`ò=IÜê=á ¾5Ш>uë@¾iÉE>s"¾¨kw½TÆ?¾=U½èÍÒ¼@6†= ¾2dß= ‘¾«…�¾Õ X½!÷=#ù9¾ú§>Á§ >s‰Œ<–ŸÂ½ + ¾HÐ= £±¾X•½öÕd>ü¿n½î|=ÒCŒ=_§¾b=>Åݾ¬×>–“[>iœ–¾�¹>òí=+ˆ8>²š¾s¿K>ÿ„о2¼e¾«Ï)½DÇo½ªãÖ=–â¡>}”¼û°¡Ò�>Dzâ<çjÃ>Øþ=ÊGé=â)>Ÿ4ئå¿ /=Ðõv;=Àö=–å•<~²ä½©Ï±½2iK¾ „1=�ɧ>±`¬½&°<ÄÝ�¾)ê½ ~¾ïã?¾N>> W«»„ñ@¼ø,= „�>DØ> œ½ñµ¿J+>1+>›lF½Îð¼¼…l>¯Ç=>ؾG8½¿³¯½UËÑ=º#Õ½ 鑼}³¾^(¾eà=•5µ=µ=�½=N×?–¨é½†%I½œ’õ¾­…�¼¢Rd>.Á ¾ ÁŸ¾ƒõ–¾-Œ½å×¼ƒ¸j½·f>ª´Ý¼àʶ½wþ`>&n?½z­¾’­#=ª †¾›Ö<¥`“=q`ݽòV¾]þâ;Mª‰>»2¾é0>‰Xì=زý½�h ¿T¨¿ÎJ½²]±<(ZÙ¼Rþоî'=Pj‰¾6M>�•¼<Ÿ†Ç;X7â½i (>‹]Ù½-¤;¾±îs>A~:>íj_¾)¥i¾Ev{¼‚Ý1>i²€½Ë$ô½$Ô^¾ïW=Énb¾ÃC€>¯„>´zy½ä>fO=^ÜÕ½o5¾2‘ɽ†º½�Þ>ÿ´)>n°½ÿÁm>êQ¾NI©¼ôøÚ½’ø.>Ñ­’¾*_¿)Œ¾8'>Õ¹‹>øÖ¾ ;…½˜Të½Ä�=¾Õsð½õ¨>ÞC‚>ײÃ>õ�Î=Ï+>Èt>H¾Ý7 ¾z¸ ?èx¾ˆÚ¿Ü¿H>Ah>+ø¾ðs>“î=ù1¼>ÕÍ>ºûS<D|¾9å ½’«¿ü]æ¾Èzy<,‡X½:¤´>KüU¾¥>‘u�=0ä]¾Øþ‰»X�g>% >°[>hjï==­3½¡§¾Ña¾Õm‡¾þg>ÐÆ=£”I>†„=9b+¾†@Ò=u"²;˜XB¾p0R>nW}>Gÿ/;UW >ú<>>?_c¾K�2??vh>9>=‡Áν"}æ>FÆ©>ÂN¤;' 罯E¾e¹ >èmS=Hæù½ÒÑ€½E–�¼’¼>„½�½TÛA<›�¹>ö ¾ªA>þÜM>à›7½ù»¶<-1?ùgö»:ÿ½½5’¾-è¾YVÝ>•ƽ™à=µ—Ó¼çèÌ>I¥`¾ô,g=LfÐ<Ý ‡¾ÕÚR>é>ìÉŠ>Š*¾²ò-=,“¨¼úßh¾õV§¾¦w“¼­C4½J±>š‘¿¾Q¾m>¸§÷=P;@¾“›Ø>$ã<�N½¯?¾¹¿¼L®N>:™—>ü®?-ž°<߯Ü>1˜“>]?�‘=F&¥½àe]>Kܾ}ɾ[Ͼ”m>žy‹¾ôü¯½Mð=‹“¾›»IÑì¾iå�> E‡½Ǭ½R�c>~;¾dv3¾›üÜ=ÞEc½3$f<Ì™s=sŸÉ¼ÓI=™Z¾µG`½(#�¼<¡>ˆpÓ>Q`;þê3½¼7?¾eŸu½¹ä_¾-š->è ¤¾ ÷Ò=(g?a¢:¼*oG=GV¾ ÿ>«4>¯H_¾²Ž_ºÄÕ[=ý‚=‡×þ÷L|>Æ6†½ ©¾{=G½ÒN=7‘¯>Êo3> 㢽`ž?�•‹>|�½ª¿ÞÑò¾ó‡>}>{½%H=•–L=Ý®™½&UÉ>n‘>1R”¾„}9>›[»¼’Os½†Ï¾u»={¦¾J’â½E;.ó¾G¿={å3¾¥÷ؽ�<ν�%i¾«pô½Ó …>Ôo¿ ˜ ¾^Î >éZ¾ÇIa>aì½Ä–ý½¯ ?st¥=‘Mj¾ @}½Â;¦¾ü´—=E¦>Wðþ½áOe>Oš1½/¬Ë=/T>Ypç>ô—0=]8t=~Qнý;ÝÈ\”>)±>¡wÒº�”½´‚3½�¢'=½r޾¼>À½¦­(>ñ†˜¼qX‘>œœÃ¾y½6¾Hsº¾Ð!u¾]#=_V㽉0‘¾uz޾[¹Ã¾«1¿/ Ú¾„|¾ïE´¼ß“‚>ºª½Ì÷µ¾>‡>%ßM½Ä–‰½n ê½f?¾Ö�‡¾*9¥¾ïØÖ½BN¾Ív#=õ]¾U�>a š=¶þ>†î¥>·/¢¾›Iª=¶³T¾òä«>\²i¾°Mx½¯�ú½ðÅ¢=Ε ¾�:í=ö¢2½†EŠ>œP¾ƒ1¼½åÁ=&W„=mGŒ>Zt½¿8¾=/ÛU> Ýæ>ŒØ=U0>“NO½�1í½"9>ÚÔH¾ˆ �=ï¼…¾v[Õ=­u¾±¦™>=@w¼›Ly>@ÄÏ>}]¿ÿ­¾NÊ®¾a�t>п:= <;•Œp>_�>?öL.>É‚½ø;>^_ì>ýl–½ç¦>M|M>õŸà>8Ÿ¾IVå=ˆ/K>K„> ý’¾¤�>µ>8†Þ¼þ¥Ú>»o¾C±Y>³*¾ ­¾±''½Ób¾]Ÿ¼.•½ãš=àN?ö ¾Jp¾ˆ`-¾½Tï¼sui>sª_¾¹td>RX®¾þy¦¼�u >I0 >ûóT¾±¤‚>Cî¼5&ɾ{>!J޾ÈX›=6ç¾€,î¾ü˜)>v(½¾§ÿ? »Í<ÂÛ½ó¾Íü…¾êöK¾> ¾Î¢¾Ë&¿>¸¨»p®õ¼œ—W=ú³E>—yµ¾Iò÷=xcC?aØï¾nŸƒ¾A=Œ_Í=Eãw=…¹¾‰Ÿ‰»=ッ}¾=Á¤¾>Ë?3—¾çU½*DN>¸ùß½ü5¶¾�È•¾… (»8�”¾NŠ ¿K'¢>†!²>ŸÞ<Ér> ò(¾0úD=ˆ†¾Íf=Ë¢?ãbJ¾V‰Ê½ëÄS¿‰ã»"Ëõ¾}ü¸>¾ðý½ž*>h¤¯>ÿ5˜2”¾áaW>”r¼¾ b�>ü¹£½7¸„½€º>�Ó\=ÏÌ–½„Ú>Ýо÷>Í�U¾A*B¾¶° ?L޾ÈVy>‡H>Ç1ƒ;’©à>ë@>�>•>Ô–}¾¾;n>AÜÎ>Ú;q>;�>Ó>›¾�½,è\>°ƒ=¥ØC=¹më½Á‚¾ø¾L¶°>¿ ÿ¾U£ˆ¼Bnì½o×Ó½i H¾?…=’=§½ªF¾1c…¾W«p¾köR¾»€¾¼¹"ǽuGX>îóöº\÷£>A¡•=9 o¾ù©ê=ïbäVŠV>�÷ ¾×ãh½©Å¾§#>õ×€½²¥½ÓX€»xl�¾ânÿ¼à+>`>Ø´=v�=UC¯>‘‘½“>‡|ó½ïçI½R È>Ö`�½Q'>æÊK>Ã0»½W_£>¦ì…¾eŒ‘¾vœÀ½T!ú=޲ ¾Ä'½îË„=Õp ½ >¡Î1¾Èð¾ˆ0>¢^9½팽h›r¾“âá¾>꿸b]>™j =ž ¯¼Ä J½¯»¾ Ó½è:#¾Þü¤>h¨5½A-›;c9¾>‰.D¾š=øXæ¾\H¾¬É²¾pa=N僾嘾tT¼ú¾Œ¾^~ª>´âÚ=§‹>?±�= “¹>Ï’> »¯>Ì3â¼õUÑ>샿QZ�=Ø+=]²¸>A`*=l=">C1>ʽcþ§>.´²¾\ú¦½æTR>;+º@‡ø½%¾uýŠ>Jü>\n8¾�Õf=vwž>÷T¿>세<ÑeH¾ãùâ=«áÚ»öE>£¡>2ã«>97þ½ï(©¾ÿ•˽C�¾Û+>G¹>(cÝ<ä=¼ßGü>),>àÿ�½r·ºÙ¿Q¾•Aͽˆ Ü>µ%/¾ýº=m=?rõõ½Q•Œ¾™Ä<ƒb!½¬µŠ>â ¾2A¾ô¨Ì>˜c*>˜ƒ>øо–© ¿î“¾Ì?¬¿¿”½ÇÀ¡½ƒý†>“Ð;>o‚>Ûà9=Ø÷¾iÆØ½E­w>|>iþ<�š>'̵=)š©>í" >ý£³¾ƒÛ¯¾h¼Ã¢¾NÔÊ>€Ø1½gÁ]¾ ©ž¾Ç_>Ž6Y¾†È=Oƒ¾ÿs_¾§(¿>©n†>?Bº>·ð¹¾KRó½–¶å> çà>/•†<2à”= ¤¾-:0= U=>? >WÙ½>V¸=A°¼¤´.¿�9Œ¾}Q½›¾<¾îb“¾Ï±>Õþ=ôÄ>y5“¾9Í=NZ¾l˜J¾”™ð=f,‚>­í>æ™ß½]ð >qÅ›¾™¡\=ï’ ¾_ª€£>Æ[¾·"–¾¾~T¾@`㼓�¶½=²=g.¢==,¾Ê º¾bP> Ä´¾»€>þʽ5+Œ¾Är1¾5(>%£È=)r?ép…>©%¾¬‘ ¾˽m\½>BmŠ<裾Šo3¾œ·£>뿾~Ø=Ýê>½U…=N�+»s)±¾‹3á»Ï^f½Õ±¾zç¼ã¥E½«UL>c S>¦Ð>:Ž�¾'Ñ$>÷ß=¾àÁ–½žw«>/8í¾y»?bE«½jÃ\¾™Ñ;‚ïb¾2šÓ½KEˆ>á%¾Ï›½¶¿Î½÷ U¾Ö×½™®F>Jÿ=ø¼°n½ƒ>>²³>ã7ƒ=ù€ >Ńß>äÚ¡½x®>0øÊ>� Á½©Žþ<Þ†=©«f>O9>Põ=?*D> ß§½Äp¥>�Z–¾)ÔÞ=£Å4>¤µ„¾¿¦<¾:qÁ¼ ñ¾•€À»O2„>H@e<€]>â‹Ö>”b½³ Ø>�B¾²}·<׃h¾W-¹ÚÇ›½»®´>–^"½KFã½ÙÅ`¾È0>öD6>G ô¾73¬>‚ó�¾’È4>I1n¾½W{¾ÝÐ6½y*p½ÔÖO¾ÀI¾yÜ>Ó²=K”¿=J ¾Í¶ ¿ÏQ_=ÙÉY¾÷ > ¥ô>< ]¾bš3¾Kо³¸+¾ÄÔä<Ÿ”†<ó(¾’Þ{½�É=â>‡n<}Å> ¼¾ýxš>Ï" ¾­Âû>‘ÛF>l×,>©9&>=ÕüäÅ„= /¾4A¾Mª�¾pv/¾DÞ+¾d¾m#¾qr> ö¾ó#Ž>*¶<ßÙ>=Ž®È¼íæ¾)¡¾C޽¼ºùE=ù®¾$|нg¿¹ŒÊ=»™D;ÄOp¾{ÊR=Ò¦í½%û½5º—=iý=F]?†Ëû¼‚섾ÆXO½d:¹>�¿r>>Ç™>É>HKó;ô¿Ð6>|cM>‚)¾4Uñ¾pt-=9zÕ¾Õ¹—¾½">òq½_¼T>qˆ¡>ÑŒ±=ýz-<ÄÌ>¾‚B̾¯'Å+ñ›>|0©¾ôËy>e†¾Dò={3¼½¦ÚоÉÃø=w])=>æX<¾[I¸>r¯„½™*¾³ò€¾Ûë³=©›F>‘±ç= L¾.9†¼©½‹½ï6ª¼ií¾‘Ú­»ú=–c½4D?… 0¾>'þ¾Õ驼tP=1¥Œ¼ “¾o²�¾âñ¾å.>%´=€nN>¿9ß¾6$Ͼ{ÙØ=?DR= 2-=‚›¾+ƒƒ«_¾g¾£å>&¨%>0:>÷Y ¾*Jë:Þ¯—<*;9>uvè=lI¾ô©Á>Ý׌½ÔØØ>¢L+½ó¾’:¨¾ .¤=([]>°£<7Ó>½·V¾Mð0=*Qè¾È’Ý=·<'?À?=éË®¾7>nt1>3M­¾¥êݾ¶7>ABl= )Ǽ»½E¿þ«¥Ç&–=°¤¾Ø ¿ÛðƽMý|>Ö£ =QÑ>ˆê¾¢�½9]©¾ªû>õÄ!¾Á¾|-p¾ú°µ»T$¥>Q(ƒ>‰ŒJ?Ä�3½‚| ?H1[¾K¿ó>¹p9¿ÌëÝ=R„°>Õà¹='Ì–>Éо�«Ì>ä ?t}¿UBü> Ã’¾*9¾w¡>ùÀx>÷«’=ü?ø¼ »½q`Û> Í˽S·S=â¡”½q¬=y 5=veO½ßq*¿^@¾‰1í¾‡d-¿·zÅ=�+оÒûr=o‹Þ¼(öË>Õç>9éh¾ºM>ËY4>BÉQ>cYO>òˇ¾Ù�¾ö1›>Û&Ö½i�t>¶È%¿òˆŒ>£’?¤f½S[ß><�Ì>Âø4=*àȾe ²¾É°½ïa³¾‹�…¾Á¹¾@š=R•¾âPN>áHx¾ãe”>ß³¾ˆK>l¯¾'1¸<�j¾š<>ùϾY ¾˜¸º>I®p>�ž©½Ö— >]A=`’Þ>n¾¤>Æ=é?¶³>™"K>3¡½CÊ»> ا=úW9¾xÝq¼[ýh¾§�¶>�6Y¾… ܾù¢™¾_V>¾nʼ]Û˜¾‡çN> @½ŒÑŽ>}o�>ƒ&ú¼V6 ¾FTU¾6,¡=©�ª¾¹¾¾„µÔ½Èdœ>¬^“<*”>©¡œ¾~/9¾Že}¾ŒØ>È#>Ù$8=6~)? ‹¾‰¨—¼½x=ž´Ñ¾,‘>Ò{ì=Œ¾u?‘Î9¾­†>Œ‰?¤Yú>Ùt¾ÄNõ¼²í>dî½h§$?¦-)>4\¢¾Oh=_³<»š½Óá´=Ua(=4@8>tü¼m%>`A:½E—>J£n=oø ?aa°=ùX�½›>´¾”�ƒ¾Œ£Ó¾±"¨>±.¾ŠŽo¾(Sˆ>#·ò=ÉCA¾Y¾Ë½q¿Ç û>ÐÙ ¾Ó…>ªê>§/§=bá’¾2À{½†+Ú¾n…=´U—=N¸¬¾ \>b¶f>¾\¾‘}¼p?nÙy>Š >i…²>y¿>xU˜¾]]¾vƒ¾=Ô&¾MsŒ>‘¹¼´TÔ=mH{¾À.û<s2?¿¾ûˆ>§Î̾ic >û÷9½™z˜=Û>x¾sù>éž©>Ó’è¾¹M¥>¥�è=ÿ;u½ ‚„½©ø=|Ï >¬øÁ=]È@½# {½zÏP¾Ù8±=Ý\¾ÆÜ©=ÿ>B¬¿½›¥¾X¢Ì½+‚E=³Kt<˜Ã^=/Dí=„Ò„¾ÒDz¾,-<sÞ¾¸$½jG=̽–ÜÓ¼8< uɽ#§”>¸©>2Œ"¾ÿý½¦î¾ÅÜw¾uoi¾µAŠ>¾¾Ë“ <�↽J„!¼s>Ú=t|?p@&¾õŠ=Pžh¾èì¡=»õ޾?jÚ=K >Vd½XÌ„¾Žšn½Cs>΋ý½ˆÂ¥½!x#¾IÝß<«½=d¼õ)Ê=À8C>O¦>à?É=PêT>Çÿw¾|Š>ŽS©=’`>”É*>¤$L¾C "= J>¿LÅ>›0è¼iß½4œ@½j¾ û½µ‹½DOÃ>‹3‚>Øgý¼ÝAÔ½Ê�³¾3l$>ã >LA…>ß¿Êìʾ¤öŒ¾âÜ–¼ÞöÔ¾�nñ½j>�=Ⱦ\UÐ> Œ0¾Ï'>Œ«Û½¨ô¼!±J>¦T´>²9^½ëóD½2Í=ú™Ý¾ûø;>q'Ã<`z>rê¾9•v½�Õd½±ö5¾½Kí¾µë·¾ þú¾‚›>x,sCµ»]‚Q¼1K>6Ÿ?=Û¾T¾°�;ƒgœ½Fy»=/§Ä>ͥ㾋)þ> ½Áã�¿³ÑR>u,'>j8>,²?ÌF3?¶y�¾ù·»Îƒ=-Ó.=m'�¾y¼­>Åû�¾ö×¾Le•>'›­=‘Óè¾|ϸ½;=ä><ºÂ>T]]>Ë÷Û>¼32=–Y¾ÚÂm½×7>‹$'¿­¬V¾e¾b½ùÜ罡Ÿ>j§¾qzU>ý>ï@¾;v <¾º6o¾U9>8ÓO>:¶–>TbÛ=›u¾µ'E¾kÞÊ;͔̾…Ì›½ŠJ¬¾åÝÑ=œH‹>f?*7¾¾jÚÍ>Ô?» ¾$oŽ=ü+N¼Ô±W>öÍ¿‚=8=4뾲ɿ’Qž>C¾¿Ì°€=!ðù=\k>%/½ípû¾zÉU½Ó½iÆÄ>£L?¥n¢>hT×>Õ?¼½Ï#t¾w°ÿ¾í�¾ç7d¾ÊâX='’<Žê¾ÞÅ1>f¾Á™>ŸÙ°=b6|¼ùåÞ½L`¹¾ø �¼z±Û»o¶¾€Ÿ`>2 S¾>'¾"W>FoB¿öXÓ=ˆ�Ë;hœŒ½®ñJ=c’>–Îg½W†½ÊQZ½×‚ï<��º<q¾ï+ ¾+wó½Ì«Y>7$=E¸ ¿Þ›×=ê~½}ÚÔ>'?,µ®¾z¢¾S{Ó=H–¾‹¼!¾S]>c\Ù<å39> ?‘>‡Ù}¾M¦‚>­L ¾Ïªö=ÿÛ€¾¾h"?¹ ø½†Oï=•Ôâ¼úÙº½ÍŠQ¾®…¾Ûlä>O&•=._„=$H†>ˆõÿ>XXy=‹¼=?›¹±…r¾Ì”-; @%>{ö=p’®>ûÔ¾Z�Ù¾3kX>E2J¾{é¿>ÙÒÒ¾Ã:>»%½Á§þ=y+R=齨ýY=Ÿ à>½"þ=ßG>ÿ¿#Ù¾ž<ͽs¯V> B–>1sœ>œCñ>xŸ>|ôõ½“`P>Ž%Ø=˜äè=Üþò>&ˆ¾Dnt=›v¼¾S´?WÖA¿À;“>�ÜȾy˽”ž ¾[n}½œ.^½üœˆ¼¿C†=vœ¾]>œ½ÇÅ¢>NÌ=(Y¿§µY>Cnï>$øó=Þ=?²‰™>fb¾ŠSȾƒè޽ÿTC¾Ý ¬¾ ͪ;×�°>òæ™>Œ&¢>&W>Ƽ>º{N>¿Nù=ÓüP¾Ù%½Ýמ½aß„¿¢ý¾>È0>2’x=HÖÚ¾Œ¶¦>¯ë¾l¤">¥˜B½ù4¦>¬”Þ½rH>�ü<¾¯n¸>bÓa¾ÀÔñ=¦üE¾mê;ðœ>µÀY;–Jô¾•ì½ 7²= ,?쌾àÄ‹=bßÖé Œ>ªšB>©Òu¾Cß6¾¹wñ½˜ŸÎ½0>8·?@”H¢–•=Œ·i¾��½ð;á½²=ԾɎ¾ŽÃ>þÄ7>ûkº>[b>$­ƒ>Pä´¾¡±>�*g>+ÖZ>.¸‰>xO!¿´#3>Ùć>_S>²'<=n¬m½˜ê?︾-CT¾›T¡»ÝQ?Øw>TÀ?hTò>G�‹>“¾Ö8µ=3-³¾‚—”¼S�->ÿRB¾joÎ>ó�®>b€�½žÞ¾>€ > ã’>qÆ>(#‘¾›½6j›>¼&G¾mS=i”?Ñvm>ÚÃÅ=�´‰¾·À>;2Õ>ÍrA½о=Ëdî¾��K?_T¿6ªp>×ú4>äiø½öß�¾¾c=HÓ¾â<çÁ€¾„”½£cª»z÷w¾ÍÎȾ | =ü÷ë¾yO²½¨1?b5Ô>âÈÜ>Ñ|‹¾P©¼¶j½¬XÂ;ü­ô=’ĉ>H¯é¾l¬³¼�“½Þvƒ=k˯=js> ²>D[ ?‰ò’¾®÷£>…‡)>´h>¾.쬾}l’=7¬½ØÆ�>*6b½ì³¬¾36Ÿ¾&öœ=7 ¿<³}½Í¾Ü¼¬ƒ=Y Ž¾Öºa»RR>P0?Ä^m¾g¤<¸Œ[>UA@=⾤ù>cîÊ=´ƒ7>ýv>ÃóÏ=~ú=˜Ðz½ÿKz¾�Ê¿®‡ >ؼ� €>+¡›¾%v¾ÏW>Ë…¾,Û/½ÿ³>²„ý½ÕZ“>µó7¾yǺ>bäÁ<µW‰>áô¼¾Ï¢m>kâp>¨NA=ÃÔ5>Ší ½ü¶¾ôÖ?[2,¾ê.8»§œ(½ýÅ;¿-‚½³©�¼sƒ¾í™D>œùÂ>Õnî½þLe¾Úê>ÈÏ!½x;>EÂ˽ÚW>å2ì½IÞ•;F÷>�šC>|;£G¼²Ðì½Ý·µ¾Æ>2"Þ>çç¤>ÊɾÊv¥9IÍ>kc¿¾¿Š<Æ_”=†\Þ=ݤM>ÒFœ=ž«"<–ý‚½g¯K>g¦È> U?·»›¾°Ád=¥‰‘>®Ã¶>HË­>Iõ¿á¾Q¼ )>vò¾Ëø˜¾™›í¼ä¶!>Ú’¬>ÛÕ½Pì¸>«ò¨=+Ü"?=^°<ÆÏè=)A~>L4›=ëÙš½8æz¾wÑš=î!õ¾²¬<>ó¾x¼ƒ¤€>ð݉¼I™%½Õ:Õ>o¡ >r‚ó>=PÛ=‹‹=˜%™>'óì>z÷ð¾°FD¾‹÷-<&]Ÿ¾m~¿·E˾4‘j¾ µ¾ xÿ½�>S0å¾ú¬Ö=-ØÝ¾àÇé½ïúV½E´>hZä=€KÍ:}¡m¾4×^½Au“¾µ_«½Q7?;µ™>Ïøo½à©ö=…Ó/;.rª>€á{¾F,ø½u1=kÑ@½…¹i>¯2˜¼—¾­v¿ϱ¾À6оý•£=¬¼=Í'Ê>@€¬¾ D˜·Ý3/=GåL>hb�½hèb¾UÔÞ¼¦�s=ô$;¼Go«¾§|„>—[)>žÅ¾˜^A¿4é ¿0¤­½uÎ=ö·ù¾+4¿¤¬¾ía>‹¥¾Ê€½ –¾ú­=6S�>xͽ0$¸¾¨pl½�©>½ß�¾MO>yÝj¿ïÖ=¢Qž½ û¿Ï =Bg’<³�Ø>™ƒ¶=*|¶>±Ô½Ž´¿>®!o¾OȘ¾¹Úû½­•¢¾tì[½©?B¾€Ò�¾‚B…ºÜ?f¾/E =U»¾>w¾¯_€>¬ß…<Öj÷<<g¾¨¹>xÁŠ=gG>A¨B> W½Îé5¾Ê{=K`�>åZL>ÐßH>9yר“‡½} †=Ë&¾ë!õ=Öì(>2Õø¾g½-<_“>Èi¾å”>Öì>é9¶>ðÐ>oS=‡_.>ßQã¾/h ¿¡Ýɽõ¿t½B¨Ë¼'>Ž]Ã> ƒ*¾º½]>úÙß>¼x¼×:z¾¨k»•¦Å¾c«¹¾¬HÄ=a^‘>ƒÂ>Þ|œ=×Ú=‹c-¼¥€†>yz¨¾ u>‚öø=#¢¿d6J½Øÿý>ÀöR>®?6²¢>A²>mé=Õs$=ævÝ>êD>ŽæY=`q½÷o$¾E\7>…E>à�©>:ßü<˜ÄJ>g¢G>¤X>гD¾]¤Ô½£š9:ö(¶>¥o¾ŠŸ>äŸ[>ûy1½)2Ó¾~¡ô>E¢">uê<ò?^Äl=¶ì’>b–h¾óý�½å&?R“<¸×9>~ºk½+¾ ¿’=˜B¾Sö=D ?ƒn >éÕT>vy¾=Zš>�ür>k�>—1>¬S›¾¯6”>ÂïνæÀýý`5?‹¢w> ¾Ü¦�½Su5¼Â¤á½Gìª>�ß>Ÿо4 Ã>û+“¾'µ½{„¬½Hßz¾³Á>]:*>yzÂ<Ì“Ž¾¤4Ü»Pì>s^>ÌÏj¾2퟾€ãœ¾´ð>T¤¼û3>lÜ>:¼ „p<˜²Ö> /f>ŹM=÷û³>2³“=ìBÀ½…ú¾É‹>™Ý»; |¾ä„ ¾ÆVϾŽF¼¿¾Ê-™¾u©#>@N6>(í¾µËF¾½YH¾ŠÿÔ>a >¯y>�¿vÄ´½˜J¢½aäd>æÖâ=Ф¾²�¼¥Õd¾:P€¾'$¿è`§=>êÑ=…Þ¾¨ü ¾¾˜E-=#šž½ þ>+H¿½¯Ü>™C=åJ|¾†�¸=•[/>¸‚¾¼b>T&>�ÑÚ<‚<;±A$?AsÆ=¡?À¾™°Þ>!#¿Á­÷>ß$t=M’¤¾qs¾Ðl>¦\Õ¼àŒÕ;ãc:¾€z½VéÛ=ø¾Bå=[E�>«$Ž>K›7=“j5>ÿÅb¾ëŒ¥=>‚¯¼E7>nŒ$¾”Õ,¾¿d±¼¨ )¾¨|¾„¨·¾ Õ«½#,>!F¾ÿ<Â=F„>–ÓÆ>æ[p¾;øU¾@›½™hx¾Hõ>'ú(¿âê?Ɉö<[(/>…¨N>íaí<Òæ> ÔÈ=hv¨¾Éx>fé½¾ÀÏ=¶uˆ½µ·œ>‘E>Ôli¾ÄZƾqC>P€´>ÛM">Üögêà‹¾½Ë:¾,VÄ=½'̼‚'¾`>p>äA¾yL�½¨™È¾Si>îFM>µdK¿üî×¾ § ½V…¿Åû=rj©=þO½/±>;±¥½½'%}¼†�±¾™yZ¾Çоàü¿rm…¾BÙ¼®øÅ¾Œão>z½M>Œ‘j½×ÐF¾ž•¬½öZ¾¯¢¬½\é]½Ùÿ ¿Ø„¾˜^4<¿Ãä=ѹ >-оg¢‡¾Fç×>íJ¿V…ˆ>\ž”ô¬¾õe=ýÁ>ä«?ÓüK>Õ0¾û¢¥¾-Yâ=päG>�‹¾ÍHŠ>&d½˜ˆ>‰[¶>�£;¾˜3›¾Nõ >XÜ‚=ôÞ§¾6.a¾…ÿý¾lO£½ª»˜> ¢ƒ¾�¦¯½è€¾¾öb >ŽÔ<ð¸¶>VÍK½È¦¾Õº»`†½ÿ 7¾žº˜>ÀF—¾ˆç>¾&¬k=.O>x"%=¢Ô/½ÄÒ~>°½ù½êM½w_™>¶9•½‚I:>ê?›*á½€Ó�¾._ù½þ¿l¾�Ì;¼,>®pž½£à?>„ÚÁ>Ú> FÈ=ÃÞ >q ǾJ,>ö,–=ó™Ö=6¡µ;Žw¡½ Ûݽ~7‰=¥+e¾‘ É¾wTó¾<¾¸fT¼Ž{“>Alô=ð¨P> /=÷[ʾA™µ=°Z9¾Œ„Ö½÷lÔ¼NÅ>O­M>wÊ>á›>µÈ¤¾oþÐ>ÿ«ü>—}?%‚ɼØ}¾´ �=tJ>QC?àr¥¾8äܼ/å>bÏÙ> Yû½}”}<ø—¾e�>ÎZ7¾’�= \ÿ»Ù쾂5 ¾¨É3¼G®Ë¾S0¿·‹>Ö¬ø¾,‰ˆ>×À}="/½>4 >W‹ <£Mª¼�ÊA¾›a´¾“A=(¸.¾À9­>µ�¾©–&?¼Í™>¦ùj¼Ò¶Â=,²¾à7þ½ªE'¿Å$[¾dчº;ÀL>¼n^>R=:>£´½S!ž½$<»½hgü=*0Ÿ=´U ¾Â¸ò>r¾[®;¾wb—>GX˜=Œ²š<™ ‰¼}•ϽÂw.<�=—ÜF¾¾�¬¾`T‡¾A% ½ï�½&óÚ=lø‹=¹ÿ½>k%>Ö&á<«<¾`Í´½W^}=JýZ5=!4^>Ï‹º=Ð ?7ˆ¶>—åÇ>ò޼>õ’=nù´=Ç>!^T½0Õ(½¨a¾ž¢5¾ôGƒ¾/Ÿ=æ ¿�\•>êZ»>ʶ’¾¿“->G9Z>ý‹Ä=&<ü=ÙoO='§W>-’ª½þ è>â\1>ËáZ=]óq¼°«>‡H>�ý¾eª¾š}i¾Y/ð>ƒb >Œúg¾¥Çó>ÌHƒ½¿_>�º¿u°#¾OÊ=Ì8À¾—cœ¾Æ§ˆ=�Ⱦá}™¾U§¿>ѼJ¾Ô¶º©»4>)]•¾b×¾EË6<�è=�]e¼ýR”=¤’¾ÖF>O%¾ë/Ñ<‚SÆ=ÿÄ=n^ ½oX¨> í´½Ý©>ølê=âÝ…¾†ZÈ=û¿Q¾\ÖÞ¾W«£¾dO¾˽÷å×>,dš½ç±‚¾K}>C[о‹¸¿¾½dƺšf8¾|Ùº=© €½‡€x¾{Ò7×b‚¾é¸d>v ¿.x¾áPžO�…=ÕZ= –¤>¸eë$·¾c>XX¬½@>7Cà=„y�>[Ÿ=`òó=2þÎ>sS”¾ËZ·»�X°¾p0�¾»ç¿ïJˆ¾½‰½�x¬>?¹7=K½Áį>F½ ¾‰{lgÆS·°›�¾4¼IP¾ÿ’Ù½Ì��¾Xh¬>ž¾>7—>«¾ZÅ ¾þ4>N’¼¸8+¾Îñ€<¦Ð¾‘†›¾S|�¾ZÖt>>a¶e]¾¼y•¼�µ¨=£ù»0åF> …4¾%tŽæßf¾Wd0¾j >çœ ¾:õ½8tº¾þ��>4¡>· ¿r£º‹S>¦´¾ùvª>hƒ­=ç X>»‡G¾å©¥½̼¾J4¾ã¡$¾Ç¨Â=RÂ4>�[޽ª 2?hp/>×|€«8‘¾ò:,¾4I¾ öV¾7Û˽™Vø¾üp{¼TÏŸ=zT½¼¦Ú=‚1ý=­ÆR>Vý̼Ö�>Ÿ=Vc>Œ<ôt>=ö­½ê¢¥=\ëç¾N)ˆ>ÖÌ÷=NŒÜ¾Àl¾üÇ­½” 8¾KÞ¾E>Æëf¾¤Í¡>á(�¼1Ù™>½³s=f%n>¥—ð¾uu½�ˆ>=!¾®Fõ¼ë°S>³À ¾‡”d=`8=*h=Bx¾µ@�»ŽX>i…о佫>½»¾_vT½ ¥2<ƒ[ž;=[š¾ß± ¾Ñ u¾6:¾³O*>éqª>èìæ½·@µ½#‚>T_Œ>$`¾d¸¨½f´¾±§¾Ì;¾Ý¿ó½rKƒ>ð�‘=¸[ ¿¡†[Ïh¾ÓEŸ¾û¼Ïm?zµu½/à+>­O=ƒƒG>ƒ4û¾¨5>…)º>v¸½`(?V½|ìY=âÀ·=V¬Œ¾gCÆ>•̽ «;-®×=ŸI2¾µ ,> ˆ>|iæ>`ò³¾Õd¿¼é±½8>î-¿HÌz¾fça>§‹¾ìù<ÎÔ=Ž]¿ºD§¾ù‹û¾â<½É¢§½—¯½"j¾kÜP¿Þ¼^–žf=è!>¹»j¾ø˜ò½Ë×</«=%ùµ>"-O=-‡g¾a£J>™•¾Ê†~>Ó­=²‚I>fYÕ½&Ì‘»Œ/E=&ZȾøà?@Û÷½f¥…»¨VȾŒEÙ¼[6»½Êù½bè4;—Pƒ¾YLï:¥7&¾žXE>įÙ>C¤?¾³T>¯Àì¾” C>gG>©¢1= iö½Kˆ(¾äž¾ýMm¾èˆt¾ï>rÌç<ˆaϽÛ¾>Í«=I·d¾K�@<ø3¥>6å >D»Ø½nϽ©‹¾½›C>TE°½Y4¾¥½‹=s^“¾f%@>3 >é3Þ=‘]û½ Ã4¿0ú(={1‚<ü»>Né=:{-¾�Rà½ËœØ¾á®0¾ ƒ(¾Ê…À><9ì=|0¾Ýã^¾ÒO=ôÖƒ¾ð8"¾'•€>R å¾=#Þ=Ú­¾«�Î>¸+å¼Ò[|¾¼ê}>O‰¿á+¼ªÿŽ>úkú¼S¥»ê"H<>H=0ß(>5 ?tÁœ¾R.*>@X‚>̽¬¾ë@>P‚> ÁD½ÙÙB> |‡<•X<÷ÅI¾bqˆ½÷…:å_ª=[U>P¼¦{¾�à!>,�ß½8@?0¼¯>“ÍM½š†™¾Ý•h¾¤Tæ9zú¿¢SB¾ìo> C½/oè>¬ØE>‰í>{‘¾!›<*›E¾íQó=C?Bë⾩}¾·„j½7N÷¾Gƒ¥>+àd=2@ª>ML>£ý?³…=ÈhÎ<²¹þ>Ô¡'¾©Dü=‰·ù=в½Ÿýq=L ¾#}¾áî=,O¾uÑ:½ÿ=×o™= 8‹>¦ϼr2£¾¡é÷=�)μtúº;z,¾Y ¾oÃ=J�´>±EA¾§þe¾i>2§>+ˆã=²(ô½ à|¾^hY½¿ÑØ=ÉR=Og�=/A0¾òYÑ>²¢n>Eo�>ƤŸ>4û½ö`ݽLf> ó‚¾m>ñï½H…”>qG­>»ér¾×æl>î†s<Ì>z¸‡½/ïŒ=º˜>8g–=ØÀ-¾à…>ö�¾ÞkE>Þìl¾È ½ÈZð>Â>>Ńӽܯ>`ä¾ë÷5½�Ü?ëw>‹"=Þ,Û½ì$–¾µv=<&�¾®yÛ»k¨¾¿!¼„´Á½®u¾àÑR¾2‹¾w™Ú½«J+¾ª%Š>‚\Ì>T‘¢¾lþà¾ÝËG>½TË=ÛiT¾¾”�=—Œ=Ô5«>Uú¨¾œ÷½®ÂÜ=…ˆ½‡E¾ øR< *?zÓƒ¾¾Ç½ÓM ¾C�>tÔ�½²æ¾Ê†>ò¡£½ò=ó&{¾ÐÙT>R0¾·Ï ¾DÆ<ãáØ>ÏY5¾bㄾ„N¬>Â3º¾j¼Ì¼^�¾Ý‰Ê=ú>¾K‹¾�f„>ê_»ˆ”š>[Ëç=±X¾ãKí¾ÊíϾ°‹<Ô> =¢²å½‰Ƚ— >üX¾ë¹¾»Šö;WíP½ Mù½ mj=;û¾Æ”Q¾úçË>®[?üC—»\P¾B4{<[po¾øÑk>L >lz¾ç;?’ä¾R´=Çé=(œ¸=}k >Äï�>äº'<¦!’>ùoÓ>€ìÖ¼!äÿ==7>6¿·[æº6_ǽµ?ª=ýfÆ> c·>Ø¿¡>]Aá½Bj¾¦Ð0½{ó>Ä f½¢Ý¢½¡Œê½´¾ý\ä½R›Ã_à»5>©=¦•ˆ¾grª½clå¾2ûÍ¾ŽøQ>Ãï_>yŸâ=Í, ½?#¼Y==ï’š=íª¬>A`/½õ¿£W=ÓϾr =L°k>Beƒ¼Z á=ñ…l¾K9˜=¦2>„y¨½¬¢=‘J¼• þ=Àø=ØR¨¾™Åо -€¾†„>»Ü ?6Fz½$R¾.E>ƒr¾=V->ZZ—¾ ȽNÖˆ:”[­>Ôrs<™•\>%=½šÅ½î²à<=™>)H^=»«¾ð O=̚ݾR€>A–½U*¹>pFê½ÉI¨>¾Çƒ¾9#„¼²cë½*E >šô~½ù@¯>cOξ0ì†=î]4½bN?Ó\…½Ý\¾þD?ÚG6¾a Ü¾iEl=èKe>Áù">§X#¾Q“‘>FÝ)>�ºë¾yÅx=^¡¾û»¾¾[¶–½ dé¾4g!¾¡cß>¥ÆÁ>üB¾? >X¿ÅLÄ>ˆ°¼¸¾(´Ê>ZPƒ=Š«¾~&¾AX<>O�<½þNà=¦m“¾aÚG½ÎYÓ¼Ž`†>t#_=Šÿê»� å=WÎa¾­½Ýª¾$®¾?%¼ R¾ÀÃ>ˆs+¾EyV<äkŸ½‚Ž>Åæ�>ä‘Î>¯î2¾¼üÔ=‚CN½9-À»Êóö»ià= ÔÑ>*…>ó5è>ú6>ÂÙÃ> 3�>o˜Ž=6¾©= ë­¾™ù¾/.�<ðþ(¾à5ë¼69u=Ëšâ¾,HJ¾çÖv½àW&¾NI¾¥vP>�õ¾­¢Œ=C8%»¬j§½�–̽�¦×;®'¼qæ0>3xk>@¨9½o€;ô'>€ˆ¾¯»ø¼™ù&?/5½Pó–¾dœ�¾¹Yê>ÌH’¾ I¾ûW >ûû€>6¬¾–¤½ÿL >*a—>¹M«½V®ù=y†½R ľÜ^=�, ¾/ÕU=‚¢›=dÚ.>æuV¾(óî=Iõ¾,Ù%>ÃYE>“2u>}ß<ü’ž>G·þ»“4®=ßÔ_>н{ñQ>œ1ˆ¾°í«>ªOû¾}c¡>;ÑZ>ލH¾ˆpb¾æQì½ý?m ¾¸¾¦ ‡½™Ë-=�…�¿ >'<ýÛ¿&…Ú>¡¯ø¾ß ?@âw<–¯Æ½¨¬]¾ÈýÒ=$¼¿¨Ô>V±¼>c&¾!­º<>ß”½Ó·’¾dCc½zž4¾ÑŒ ¿¬ÇÆ>Ig >ó†Ú=ê­§½Í\ã¼j’³¾\W·>#Wa=uëý¾x�཭M;ZCª¼ø2�<Œ�»ñ·x>˜«D¾n®£>TãT¾|Ãq>hÉ>HZ´=Ö;¿c†É>ÝP…¼Xn½àk¡<�#ƾ«¿÷¼©4ó¼mB«½ÖOc¾®Ðݽî:>e*®½ÃPî=�-¿q~=Ùf“½i¨Œ½·t³½>© ¼„ô¾^¦ï½“X>*&Ù½¸gä¼x²à=ÿì=g‘¾·ñ¬=˜}>‡ˆ=¹Á]½".»>722¾Bv%?Ñ"¾ge�¾€nˆ>^¬¢>^å¿ÔŸ¾´$ʽm1ؼÂå<`Ô=ÑÆ=÷ë>⟾Éþ=‰Ç¾Ê`R=äú=T·½ÕŸ0>zqv>â& ?æËy>>ÊÆ>¬‘?í<Ç>ûrŽ>×=J½uõ=¶?½¾âÿ€=d’¼¼…]>ŠÁÁ>ÅF5¾ˆ¢—»%'ɾ³\¤½�L>ÓÖ>au½5L�>v¼Ä½)“R½D¾bTÉ>,¯�>%Ǿn’Z½à¾L§„>à ¿¼í³é>þ”>ŠPE¾T�ñ½Âæ1=cÆ ¾2Ÿ>Ò�£>Ã�>\‘c½?—>¿ð<^��>ÈÎç<þg¾tj†;tü¾8G>@dýÒþ*¿âTë¼×]G½ú’¾äX>è²Ü½ýW¿=;yž>xÀo¾ÂàQ¾,?U¾D_¾ؽ½Œ`…>ðÖÆ½Î…>Ýž >cAR¾æã“>ñI¾Cîܽ; ¼¾ÿï=Rç>žÌv¾9v¼>Dg£½+ß >‚þ>F=>.|£=dq½è#Á=ý$½Ò;¿ˆëM¾±—½ðß…¾k€�=ÃìÝ>x¥>: ™¾ D>`ê¾k�©=¶â1?­I(=g�)=°ØÜ½c³=íÝÖ½dÌ=¿l>»…Á>'dÅ=£˜Ý<ÜÂ�½ ç™>ðš–>`ç>"YÁ¾šÐ½c´]½HK>?Æ’=þ…¾>üîg½¢ù…¼=Ñe>Ìoó=¡/?©ëX¾ÑÄ4>QÐk¾�`ì½lSL¾W´É¾g²;¾ë-™=â²·=™p|¾ÔWa¼$ù”¾lP3>{†)¾øl=‚~>:R#¸�>¯Þ?'Ž~¾]âû=Ž k=}àI<–•—>¢Kù=OÝ=`½<‘¹¾,c>=¹Q½VÛ=õG×¾·x»sµ>@¤2>¦M½¿‡3½‚›“>‰l¾•·»>�Ïݼõ)‡½;^= ðÞ¼ûÏ¿·&ç;?Nû=Ó]6>[=³=ezj¾Ÿ „¾™=¢ýš>äA^¾Y\¬½I´Ú¼jup½Jü1¾¥8¨½ä¢<=4�?[1ľ2(¿ßMà=�k‚»ÜeE§´j>ÖÐ…=“¾>dm½sŸ#¾9�ȾªB<o>ÌŽ[¾Ô�y>‹< ½›'¸=2”m¾_m¹¾ûµ\¾P`Z=£fþ¾‹·¤½çµÇ<õ­>ROç¾ÞHÃ=•kà¾ð!‰<ô,>Ö}�¾QøÐ>_dÀ>/ˆÀ>�ñ×½˜B{½HЧ=´³=Ñ`>Jœv¾m#>žh¾¡ÿؾ.𾩖½Y>ƒ…¼¤’<½b=äÖa¾ŠWW¾‰gƒ[�Ç>¤´z½¦Ëi¾;œÀ>n�¾©K¹>2Ê/<˜ðc¾„È�¾J¹ú>±½ÄzC>O;�¾–IÛ=IB·¾!á ¾Àzj½ô�ˆ= ¶3¾(�)¾ó½„¾Éc‚¾,É¿=h4‹>cïʾ€ã#¾PêN½k„‹¾Ñ­z¾Eø=iy¿qs>Ê6�¾.µß=*c¾Õs¾F½¾ó=a:±½• Ò=½€“>*aZ¾ 5�=){ó¾¬Ð¾ï'¾ÝË—¾d­4<ðw¡=ø2²¼/þ¨>Ά:=ÿ g>å‡>Eá¥>"åð<\Ò=ªs ¾óPr>S¯–>G"‚¾?؉=|~[¾Áÿ½µ!оZSÉ>eË˾ˆu)>F4Ý>x4¾¯}¾A´´>Ô�>:3Є?OZ­¾*M>[8¾#U>PT*>0��>rð½ÕH»½×?°>yæ=­ã6¾a–=$œ>¯p©¾ Ÿ¼¾¶_>�嬾�SH¾#i}¾6Œ¤=‘=}¾¾;4Ó>F+Ó½d‘–¼Ê–=2y¾¬Ù“>Å”™¾»Ò4=6‘¿¾TK¾ÊaÇ=ö¹-¾‚FY>‰‰Ø=u5ѽè�—>ÕJ">O”'>¿á8á¾#°>]êñ=ñÙx>a‚/¾-ï ¾")B¾›q[¾�Ý5¾®`’>2œ½�wæ½ÇR¾5í½ïߊ<¯¼¥>ˆÅÁ½ÜÄ¿e#å>Í®—¼“Nˆ=¤>�>\Ƚ:¥¼e,^>‰Û>¿ÏL=zR>åŠå<—¾Ú”¾µ[Û>Óê<*]¾•¸y½˜ÈÄ=þžk¾P±ž¾ŠÆ;>À‰¾™ó/¾3ì"?�õȾðs(¾* z> ß¶>€Á’½-ψ>É ¾Ï·¡¾÷ã>xQ’>:ï?¾�Ó¾°ÊA¾_5>¢`ß¼ ZÛ¾½ˆ >¦>§¾-:i¾ ê¾I¦,=ýsg>Å¡H>_°k=|7 ¾Å.?+4Ë>ýÔ½7=§¾x‰i=/ÐG½–Ľ®V¨¾…Ìð¾P3ƒ>b̆=Jƒ:¾Ê.¤¾4‡A½}¡§¼&Í¿=~%•½§úU¾Ô!¦>è0$¿o‡=n—•½¥ÐU¾çÐ ¾rÏ4¾‰ö”=Œ¾znì½J[ÊEB{¾4p¾½ Þ½û⥽µæò½ZÆ>�Ž!½îò=Qgp¾iïO¾`½Ö/>V°¼Q ®>~�†=ðhÇ==ßV>*�=U³ ¾ßâ?¾^{‡½ÖÑ�¾ÑËW>2>�=¾1�é¾²=2Ò:>(®>¼ ï>Å1¾ÕóN>…Ÿ>舻@2>Åq¿ úò¼Å¾�ò™½µV>Ûe=�M½ú.>Z€#>¯’—>B8ä¼=Šk¼°G ¿·®—>顼æ¼lP³½N<¾Êàš¼U’f>ö}Ó;œ>q@¾»ã;®¼Ï=*5>(0¾¶ùò¼elž¾4ÉD=0è=ý‡¾¾&T¿Pó½Ç¢5¾xŸ¦>^v¾ßÑ+¾ï>«ÐB¾�¢¾@#•=#–ø½©ûÞ¾†å¾Ð å¾¶ Â=im±½ß­É½ €>äý;îß¾�¾<ê3”¾+4w>Úu3¾b+¨=G!6>12½Qlƒ> ­Ñ¾$Z>&ľ³i ¾*¬à¾˾½Ö]D¾¹-t¾ŽÏ>°¨1½”C¾ç(R¾ùœ+>Ά”>ÚúÆ>9w³>¿¾dꩾ·—ݺ&¾Fà?Ú ‰=‘Gq>ÍÍx¾PWã¼”½¾¶�¤¾‚ÓW>ú ’¾±õ÷½-¸ ½Hì´<÷2 ¾¡% ¾îàe¾Õƒ>,-ɾ·„=äj„¾ïæû=èqo>ïa=~ŠÉ=Éb›½µ€Ë>åqž¾p »�¶;¾µÓ?àu=úú>2;~¾è D¾�L©>ù¸:½æÑµ;f ÿ>(]’½"-2>Š)Õ½ }>j¾³áf¾òfI=>Z?4»Ç=xÍ#>= >†Íƒ½Y¿½½þM¾&€Î¼­m?my¨¾øk'¾*j¿éŸ=#�¾Y½_tÁ¼—:¾Tˆ|¾Q§ä¼]¦ã=àû]¾*VT=oO¾3ìK>tÞÛ½Ntç=! Û¾èü½€¬!>½ßF¾Ýɽh‡%¾ôº;¾Þ}>ü$>˜È=†,˽ ¾um¾aü?±í`½-´?�¾]=]4ξ䤒=ïÁº¼æ>«%½õ#:>Ó+=/•Ó>� v¾Uk]¼y}”>.fw½�ùK¾‘Š+¾9¥©;«ŒÈ=.>”…?“˜>3š>‹>è�Í>‹¶±<ßÞ ¾£Nu>$«$>Z…˜¾<½Ÿì½À=¿‘:ǽ·¥G>¹íu¾ô¿N¾Õ4”¾ÀݾÆ%¶¾öV†¾Ð¿(b½Ú'?�¹€>Ä >Fè…>4|á>¶Þ¼jvà=H,]¾çå¤=4D>GQO>ˆX>?ïƒ=²ãp>N‰‚¼$ÕM¾‰HÃ>ë=¾på(=• y»´V7¾Ž¹@½Ï ¾²ô=˃ҾãÔŸ¾<ó½=¥ãŸ¾J9¾9¾?²b>¤A™½¥ Ý<;Íf>¤=¾ µõ=#x¿-Ö¾÷fÞ¾!àÁ>ù~Ù=Fc€¾š+À>DÅ|>­‡=ü5P>Z®À=É É¾§½ž¾\@= s�;¥¾sÓ¾g.?¹» =�¿y¾=·”¾êŒÙ>C{A¾{Éœ¾¨9=HR–>\Ù¿À5¢½f‹Ê=>é5=°ŽU>_B¼†/:?ì:=Š‘KÂàÖ¾½ó€¾ÇØC>ß¿QÙ¾€¿Æ> La>%)>&Öœ½a”½”¹œ=)œå=þËã>�tŸ¾¼qo=:–L>‚Þ\>ãv >ï¡r¾ê$=®Ñœ>y.¾Š:“=€G2½Á7¼…¾ñð>>›t¿¾ÞŸT>�¶¾�ã>Z¾Fß|=úñÖ=Œ“^>ÈqF>±DV>ä˜è;ðk>5JX>§t ¾©ò>>øÒ>ᇋ¾‘ú†>àK¾Œl¾°q->êJ˾¤|ݾuÞ>j!û>{àé=½Å½}œ=“M9>oL½¢>ÏŒg=³ÏÎ>_ka¾Ê|†¼@u›>~8¼Gš?D;º>Ž2ݾµ«ë¾‚§¾J8ƒ>1Nž>ë\»9S�¾ö¨{½ù<l1>^˜Ù=>?M?ën½Ø\*¿$ǽ…6x>Œè ¾“ˆ=‡G>žòà>úz>\€Ö¾5u‹=YÛ—>´÷\=’¥¾ ?&f >Cռǚ*>ßuB>ˆÁ=A1>þ=qV™¼{ˆn¾›�ؼ’�4¾[ Ž=�oö>ä§`>Ò é¾š§Ä>;Þμ`àJ½@w@>Š9I>Çή½×Qý¾“ƒÏ>È$=_ç¾sо½¾<ö‡ ¾®a´=nn¾*AF¾Gün>ú§>û_¾Ýu=£rì½Åú=1ðé8ÖA?( ?ªÕX=2ºz=ÞÚt=—¾Ô¼²=ðô²½U¯²¾P7R¾pJ>=|œü½â™q¾ñ)|¾%Tš>Õ8Š==÷Ä=#M–=ˆ§=„YÌ=Ô»–½n»ý>h™þ½3¾bEâ¼R‘>Že{½ �†> D:¶4×>™¥‘=Ú“Y½î…í>)Õì>Ǽ]<•/­>Ú×I=Dè]>{Ï™¾»Î˜>äÿ­>jo¿‡ü“>‹x½ë�ç½JW€Hk²>Íî,>Œ3ˆ¼£¹’¾7N>wÄå½\«Ë½ÊF=zÎþS ;>­FÖ¾Y¿¾¯R˽Šó1½k k=X�µ>Ûõ¡>¾e¾©¿»>(¸Û=›g¸¾–t>X_¯½Á‡>uŽZ¾^ˆ¾kež¾Gï=k[Ú>›db> VÞ½À7‹¾ÍQ̽ ƒ¾¸$Ä>Üæ ?®W�=ï¢Ö¾?på=±Û‚¾Õ©]>p¢’½Øæ‡>áªR>§\(>Êâï½´,�>6!>ŸT±= �>?XHâ>_<<Í">¡>H>ˆî>£�$=èþ¦¾�’>;8¿¿S¾Ö®K>&êø>Пg¾C&¿céܾ¸ ò¾=¸€½Õ†>Ù¤Ÿ>º¡É½jmm¾°\‹¾+¦>|Qé½­Œ=`i&¾)*º¼+hÀ½>g>Ó\¾~¼8¾ üè¾™=ƽ²»Ê¾{C!>êóq¾ õA>e„Á<´S€>òÔ7>cœ¿á¾Yн½ y=h#¾9²/½Öݸ¾æu=ÃJo:a÷>où²½œì½W?Ûo—>«ç£>B™O¾òlv=‹Î¾gÜÞ¾ÞМç?µ¼Ÿï½)Žp¾Sað½½X'¼E­=èi?jZ+¾4ËY=¤4B>ºä¼aCË>\¿–<ÅÞ ¾\®¾«S-¾Óš ¿,ô“=%> n¿‡’Ÿ>ý‰=z”­¾ÌM5>Zîƒ=o(Á¾r‰>P©6=l ¾Ú8¢¾7Hø>‡ê=ª‚=×c’¾<–L¾¤U>ˆ?;×Ù½rÑ ?ñõ½éG~¾��Ÿ½ªI¾•3¾Ó­)¾Ø�>&¿=Ž…;¾€Ù½ ã>Ù—>—-Z¾ž�¾[vżÂÝó¾è‘x¼œ4་ò>º£Ö¾%ú»½JÁ^>wÖ¿R´½?ì ;mZ÷¾H~=AÇ“>/”}>#¾Ƥ=q±+¾­ä„¾Sæg½®­%¾%C¬¾ýãÌ=ÉÐZ=p=x‘=A©½ÿ‚ö¼¤@¿Ž £¾n‡¾g¾3ÚÀ>Ð �¾?¼¾ä¶‘=¼G/¾±Š=ƒ» >à—.>ò?½È==ð&¾iJ¶½…2þ»ì#¿©âÀ½¾Ľ‹+¾;ö¾Z:…>”cò½Á1X>Ï™>qvÔ>qͯ¾€ÃC>¢8?·;=]Ãß=´‹X<}.3>ye~¼ ²^¾e0¼=(Qݱ-A=ÑÙ=2ð×=­Ñ‹¼ÀŠ>Aﯾ|ü=¬>Ô¼Ö¾à›?<3Å¾ÚØ.><Ó? c½"º˜½·I>uŸŸ¾ r;›K5½áɽ @½š•b½›ß=¿u>LA•¾o{Há°ì½¸9ß¾ ä<�ýI= ¤Â=bdؾ„oξ+ãD¾ù÷M;ËnƼx>³„ ½j±*>6,f¼´´[>¨ªè>9-Ï='‰ä>–t'¾ÿH¼µ·Š>IÒѾ¸Œ=(9Î>Ûý=›rÕ¾ýòÛ½4q�½¸´³>ŽW¤>ñ.®¾®½wò½'4Æ>ÿéà=Šá$¾yZ�>©iÄ;‹ƒ¼=‰Â±=B=®ZÁ=A >k޾F¶?ìŠL¾äV¾/½�>à4.?^<$>Ç+º=5¾õê>”~G>…7">{ƒ¾i„=+ ¨>ü|¾[A¾>/Ò;ý°>³ìÙ>ôÆÑ½O4U¾ŸåÒ>5Má>9é4¾å½O'½y»©¾éȽðcù;‘²½-3h½dzò½ÙÕµ>Pè¶¾--¾½–q¾éWˆ>¡Æ?U—‡½Š³>´‰>�Ǽ=\£ã=w–°>órK?‡×†=9=¹éd>'Á¾x 0>!ù¾H@?z�=„žL¾ü=D¿Í>¥,¢½iÌ¢>ÙヒÁ >» ¾�©><Ç=äÒ.¾™U<\J >�">xce>�¯ø=w0Ô¼IŸC=9<>AºÎ;àQ¸½ñŽH>Ýùؾ83B>ÑÅ‹½È'µ¼¯k=¹«B?C0¿<K>L7>Ç’ ½¢Ç>_rg¾)-±½½¥À½¥ø½åxm>¬B>'Ⱦž½é?L–,?�Ë<=,så¾ENl¾…8¿å¦ƒ<<Ó»>‡¼ Ü½Õð½¨S·>€Gü=ðò½ÇÝá>F㺼�3€>IG¹¼+\.¾S#¾€ïJ½3/@¾#;ý>)ý;¤áf=eói=Ïä¿”-?nÈÑ=&8�=¾—>´®—½ÆŠ¼>c°=ß·î>õ‰Ó½>„Ä>˜è>ð¢Ð<…�2=Ö¾O~>—oí=H “¾�5¾š%;¾ï4¶>_ø’=t"¾Ù¾ï?¨¾Ž—’½“ä >D R¾w)¿.MÞ=% B=!{µ=F²°½/ ð=þ^k>–Úg> =ú|Æ>Ó3¾˜n> ¾Š;ÈêÀ½_t8?ƒG;är=î¨<œp±½à�ó>k�—½‹€>Å»Á>K¤½™�>¶î.¾~Š>V ϾjÖž¾¥7³$’¶>Ò6–¾½·>Zß%>œãd>ÿHm>~©Ó=?«=ŽH%=K’D¾ÿOï=;ȾTK†¾�ˆw=Ëе½×A½¸B¼†v~¾Rþ½£½½VµT>¤sE>"û¦>ãO‰¾ û©¾]n§F¬=h9 =%45>Žeº¾÷Ëo>¾›¢=œœû¾'¦ »9Ǧ¿tñ>¾¥Qã¾'y >Œ¡%¾ç-¿r¤ > £‚> œÄ>ZÖL>_š¡>µùξè²¾\>fæ[¾ ‹¿?úƒ=¿/˜½‹=¾Vݾ á’=±õ¾êÔϽc6¾| >l¢Z½eÛp½Ž\{>@Â'¼c�Š>¯ïN¾,«ê¾1©>A½¤0h¾ÝQH¼¼_ê=F³Ú=Rù[>¬µ(>ä¼ ¾Ò ¾$Pý½÷ˆ‘¾¥©¾N$Í>=µ>|j¾¿­Š=Éù´»´ù=§æ]>ôaµ=1Ð�¾IÌ‚¾Ý6>ÀŸ}>#…˜½ >¯)ʼ ãh¾Õ)>Y½¸LI:þƾ½°¯¾_¨Ê¼êP>>8°¼àÛ>Ôm1¾m��½å "½!:a>È"‚¾P…>FØ>}è!¿ï`\>ƒ�<‹¾½� Ò½*îI>p_³¼r%^½Í!>¤œí>þ <Þ(a>ÆÆ>ò¬D¹®4?•J‹>±÷C¼ŽW�=:’P>vU6=\‹i¾é¤Õ½1ç¹¾=x >qÚ ¾·-E>ñoÀ=s×½«Y÷¾!ã »öæ�¾d–ã¾�Κ>vR>Zf\>Ý (¾N“W>æñW>´C>ð¼a¾Ù=Ý<‹ºI<°ý½Ü¦¨½¸ß¾`çA<»í¿O®9<;ÿê¾&�ã½PÒl>¡—<>Ô�ºÐ}Ý=}òò=Ô¹Æ=JÍ ¾s×ï>Äã¼�žè¾Ë4¾Ì"´¾^;‹½™Sô½VcÅ=Á¬k¾�4Ͻýl=¿,{â¾ò`½„ù=£ìʾè‹Ê=ÇÂ=ó(¬<¤>?#Å= ¾YÌÁ¾½ÈF¾*¨¸¾Ò½È=™”ؽz‘c=Ba*>úëD¾¶¼=‰Lm½º� ¾ÍH>C\¶½ZÜò¾ýÙâ¼½`õ=ùÀs¾i%Õ=�CÚ>Q†¾¡� >>Ì>›æ¾2&>Ó˜2¾û¯¾çÛ`Y¶>H$.¾u:è¾Í&a>•Ž$»dƒ€½TÓ>4a=òqi='5¾›8¾ô°;=J“&>8âT=MÄR:38ö=¡2 ¾ko½´Ä÷¼P´½"H=9Ö�¾Í‚�½bEç½�Â-¾àç½*¤=šLÁ½¨Å•=À6½”�>_á�>©ˆN¾;ºæ½Rªq¼éY•¾¹o̾?#�<(¾ØÜ¾CÛ;¾Ñ­”»Òü½¨®¾E^±¼ghb;Fæ[>OH‰¼{�²¾-�á=ÞÖÕ½¤ªå='¢f=ʾ«®¼½†ý¼ƒ<�Hc=lŸ¸=Ù5>¶}¾`)"¾`Ù¾+Ëi¾@U£=b¿>ظ`¾ð+²=j‚=žk=gÉ =˜wÁ:�‹ê½P5Í=(?Ñα<ã>Îax½ŠQ~½ô:Ê>i¯è>#î=›Ý˜¾$¤M<§7�>cOi>†±â=i ¾ m¾æ3¥<  ?Æ6Ä=:÷Ÿ>7þ°=Ù N=(§=¿ê?°ñl¾¾k!>°'§>ÀÓ=Ö¸·¾‚LÍ>Ne§¾†6—¾4¿-¾»Z>�Ý«¼¡ʽ*ü+>çD>½ ½ªå¤½‡½‚¾;g'< Ê@¾NÀ쾫\è<ó£�>­ÿ>ÍŽ ½åº =íÁ=¹×M¾7HŒ¾qA=FŸž>;¼Ò>�ß�¾^Ñp<ý­=6ƒ¬=· ß½lÄI¾äcã=QW½3T=(Í(½ÄÚ/¾¹ä =Ô¤l>ÖOg=Š2H¿ppC¾1�W>[ƒÒ=G1?<‚5½]÷=ø³®¾…à~¾Ï“D¾ýSÛ>®ç%>‹Ì=G½3Ù–>µP„¾Ý>ÒÒQ>4œÝ=†ð=ç[+¾=VŒ=r9í:û¿eò=YPð¾é@=,¾è=Wå¾¢ I¾#rü<ÁŒ÷½ôyº¼^ãû¾Ë|/¿¼Ï¾¹^>œ}C¾¾ë¡>|f> :M»�>Rû½»³>¬ ›>m¡¾6a|>¸(<+>'?Õ™0>§^�>ím<Ù6±<å6U¾Ž�T<ÄÕú>“ÌÏ>ÌÖJ¾1bý>x«>1…z>ÜJl¾mÒ‚¾g;>QŒ5¾,f<½¸G-¾Ó=A¾×þ ?Jk9­Æ€¾..§¾‘ñ„¾„t¾h•R¾–Q=-:¾À|�>ŒÝ(>ì”ê¾­‘�=¼ o¾¥8²<æ!ˆ>ùX=oQ ½³–Ͼ{ë½8ø*¿‹Y¢½´Ž�>†ö=wÞƒ=˜±>€·4=ØÕ#¿Àc3¿‡1<8&¾‹ݾ¬¯L>ëáÒ½ã/?€{½Ÿ�(>²îÔ:ȶ>u›�>D>.aÚ:¨Ï~>¨Ä‘½ùÞ«¾4ä¾|ɘ>RaÄ=¤“ï=iló=>k?Bû.>+ž>O$÷¼Ø®´½˜! >Ÿ$ ¿€AZ=¶hf¼tc»¾" ¾À!>¤\Ó½Œ5§½±qñ½jè-½'q˜¾"D>:³ö½êƒâ½L •> ¶È<;ôǾß ¾�­¾L1Ͻ¥M†=­¼$>ŽA>g1g¼5W�¾«.u½•m˜¾ÂZˆ¾ü‘œºdD>«½_«Š¾¼lI¾±rоg\¨½ ô„¾‡HѼ„%¢¾‹V=R¨»¾´’�½÷÷¼›V¾o¢·¾X+Ù>`6ê=ª¢Q¾”'?8â>ìA>£„¿»ð‹=̹¾˜L‚=ß»½ø‘ˆ¾ÊÓ°>Üþ9¿õ¼¾N4̽¾)<=Q—ˆ¾ˆ6>% ¾…¶¨>è^—½ H>Ш*½Ž´=ÎÖâ= SŽ>ŒG%=¾å½/…�>*ƒt>‚?ëZ'>ѨÚ>yM>=úÓ>Vä+¾|º<1ˆ°=ù;Ú½¹)½†¾Îµ@=û�>ó¼›<Ь�>ÁC>×ì#>KÁÔ¼¯´»û_ཽÿH¾^’�=ÈûÜ>¹S¾Ín1>· ½|MR¾þP>/Âá=3§>ÚÖ�¾‚ø>ÿté>S2ü¼b '=ü»4<8c¼>|¿ ¾aá;?_¼m¾Þ6o=dŸ™¾ëè=e‰¾w¾¿½ªK½ªÁ>�:¾¾§×D>9ú¾ÇŒº>Çо£>½ºš>b"C¾“ûB¾}*¶½–ý½þ&ê>Œ*ɽQ1/¾¬ð‡=UÑ{>Úúá¾ï˜q>Î I>7ïø¾ê&ƾֱù¼¬B>w0d½†º ¿Åd´>«Ï¾uÕ¾_e¥>±Y >Öø˜»$‡¸-x“>+¨½ Î?îf¿|¾/šž½Žd=Jž=ð A¾¿…+½tg>„¶€>üÔ¾ @h=š€Ï=r0¾ss‘>œ.­¾Åft<.Fó=Øì¿ÊÔ¾íȽÚ >’'µ=ËŃ>,\">Ê ~>«Õ¿¾ Rÿ½ÆØ%>šË½½üºx=W¾¦·\½¶F¾k”ü=­MÔ½â¹=ð4f>Χ›ïŒ¼`ɾ‚>q¿ð½ëáI>ïr¾ÓAÿ½¤5’>u9:½ÍN>µ…­¾Er­=&GÓ¾77>:Óî½Ó�I½ ð=[Ûx½�R8=2Ý×>'†V=ââw¼M…w>ŽNb¼n¨c>M×Ò>,ñ%¾š +>lÍ«=»þ›¾XíV¾Å‚E>¦x¾  E=˜Ú¯>¹>æ>æ2%¾NŸ}½›Åš>Výƒ¾…P&>ÌAb½×0½µp?ø›½@µ>‹2ä>L¤#>èË;ì‘…>Ð]Œ¾� ޾óâÞ>e >å¾îÕÀ½"Žå½mÙÐ>ßÏ”¾à‰­=RŸC>NÆÀ¾ÈÇø>RÇÙ=ª2ë¾=•œ¾¾Z—¾¶y=œAʽajÁ=˜¦R>^™=y†ú½cP–=Ïg¾ŠÙ¾HU¹¾é^§½»s>7 ©¾íaO>i¿Ï>dF̽‰s¾Ò¢¾p>WØX>ðå’>�Ú?C8¯='Îa¼Ê—¾Ëؼ=¥`0>£–º¾¡Ì'¾Rt¢=ùB‹=èp>Ôýð½ú…7>èEÇ>s—½*~?ì’l¾†×à>Ãy«<8wa=Aùœ¼”È>ùG6¾ŒT9¾[øù½O›Ë¼eÛ?}Üξ7ëÚ»Ib`>r ±½í«ê>¶oC¿PY'¾îz²¼@U>çú=³š�=¬¨=O³·=¹˜K½jcâ=º-9¾vÄg½çÉ=rgF>Ä8c¾”�4¿Þ µ»M|=òÐ>y I>/4 >†½'ç�>æ æ½/ÿÏ>�¿>¼‚> °½ÚAû>>ú™½Œ,½í¡x½#,â>�ø½Ý“Ò>S™¸®–¼ 1a=ùÝ>Œâ¯ì”¾89u¾™c>¸R˜>©~©¾7x³>‡ >>fQ ¾=!î½Xÿ?íµ:>üCf½‘ >%w?Â�ß>^ Y;'fŸ>‚w¸=)‰›=F›¼ªÂ‘>”¤á¾N²1¾B\©>,,'>�O4?­i ?Žxè½Zª€¾û$®¾6ä¼ãC¾sk'9‚Jš>m׆¼‚c>YÁô>ev%?'Ú5¾¸°|<Îfk<˜·Ð¾P°>Ým>µ—z¼â뾸_=2@’>Êì%>§ò¨¾1m�=Võœ>�ʼ;ñp>š±x½3*ɾ×uo¾wö?V†¾c ý=¤™Š½ŠYc=Œ  ¾ÀI´¾vù(ºãS ¾RØs¾ï“ݽn"y¾0Šã¾Í`�¾ß6¼A2a>³â©½€š¾Ò|6¾úNˆ=mb<Ô¹Û=±¼ ¾Ü> >OJ¶½Ä2 ¾î~�=QcÛ=´8¾¦’š=²,Î>£ð>¾™n¾e£.¾Oµ£¾(Ѭ»X˜>Ó¹>Àª¿[„½�ò]<, z¼¯Ný½ª>óJk¾éÖ^>ïK>îÔv½œ¢>14�¾cl> ‰�=ù¾n'¾0ó^>g€™>Ö¦½žÉ>JØû½–ª½š/q½’ÄT><+¾ŽÉÛ>¦‰à½RêÁ¾”O¾à‚]>¾Ú«â½ú4‘>‡P¾D&¾¥Ñì¼¾`¿´ŸÄ½NÖ¾á¨@¾@„¾™ÛŒ<�É?•¾ýs ¿‡†µ¾Û*½ÆÄ ½Å¾>“�¾eê<Ó˜©=nœ’>-‚½Y=x¾Ò V½�„£>Ô¤É=A"Ÿ>þ#K>rÁ=Ä9pݺ½óƒZ¾² ?oÔ!=Î…ð=<ý—=:+?!Ü�¾8 9¾ãŒ±>*¼?ç =g9‘=RÀA>}÷®¾&>SN;™0ª=(M½ÁÁ¾c�«>à!–¾;Ÿ>S2Þ=Úfü=BU¾r¨Ú=Ð?;ó%?>ú$~>!ôÕ½Ù>>gx¬¾¸œ¾“Nž÷ýÄ=·÷�½øÒ¼—µ·¾#U¾Oت¾#µø=m«Y>WÖu½êr?F,p¼ü쥼Ѡ�¾£À¾t:l¾Ã«T½H¡½«/¿Pþ=ãÖÁ>ùd½çš`¾ð×�<.æQ>S ½Š±M¼ìؽaH®=§>J`¾‡p¡½½8_>Î0½¾OS�>&�¾~(ÿ=fôè½dw¾É{¼D>ÛÅV>Þÿ<ªª*½xP°¾�q>¶@¢¾êøŽ¾ý{¾p®¾7BÂ=»Ž~>bâö¾€å…>(B/¾Ã¯Ý½ÅR²<Dø=)t`>Øy4¾Í™>ô1ˆ¾Õ§c Ô¥¾î5·<ª9==дl=Y2>ES¸=¤a[>ô} ½@A¼=¸û5== ®¾òÑi>¬e¾¬�>ªue>Š>¦›:½@¿Ý>PH¾ÑB>H;ĽË&�¾C…—=A;>Xš;>„j'=}S;¾ €"=ÑÊþ<ø—ç¼ß¢ ¾ªýª<Õ쿽À‰ø½:ñ²¾—dP>Âþ½\’/½šÀŒ¾6¹i½¶8z¾ '@¾ÞiÎ=Þ¡3=Ë�T>Ó¡l=̬€>=m»nH<>3#ç½¶UʽK™²=)`^¾Þ $¾iï¾cŠ„½²ðú½ªaK¼ ‰;¼Ç´ >(ž¾’ǽ}p™=0�¾îp‘= Ši>HÊ(=hªÐ½ÝÓð=>R„¾Zjã=™! >çÕ> ­">ï'Þ£Éu¾/¤1¾YY¸½¼½Õk=a¼ ³¾i%¾<]Ð>" >\²ƒ>¹o> óå=h�>D®9¾¡z¿k3_¾~(¾bˆ·>ºá_¾r¹´º*Œ¾ S½xbÒ¾—½æ>DN�¾Æ±“>ª5ü=h‹œ¾Ëý>ˆcâ=½“¿wþ< 2œ¾Hà†½¿¶;>º<]’+?MÓÞ¾~–Û½šŸ=€®!=â#!>`¥½“Õ¾ù®>ßÂ>Mx°¼CÀ>T^Í=94¬½�¨�=#Î>HP¾êÜ>Ž7(™Áú½Ú¸Ð¾D†>$f¾ºwz=Ì{·=Zô>>ºÞ¼½ðå >.Î>¤÷ï=§å;'Q;¾z >‘2�¾;9¾¯ÐZ>óŠ2¾ntÎ=!º¾Ö~6¾*Y>0ª>ÿà>MnA»°”b¾íð^=ՆоÇœ¾=!¾8¥ÿ¾-bI?º.>Ó—\>µxö=Æúò=§oˆ>qÜ`¾¥ùv¾xtº>÷OT>üË×½|‚Ⱦ??Ž>. >UÄ>�t›=�× >=‚Á>Jk;>Þ'÷¾¿W„¼7aº'W;Ø�å¼9€!>Õ2r>@@“>bá’¾¬Nç=jç<}Š:¾Î€·¾¸Zž=ÛVÎ=l÷<÷Wѽá�¾Ïn¾M’Ú¼˜€Ö½dh»˜ü¼p_ؾ¦c|>s×@¾Óæ ¿‡…ྃŒ¼>ÑôB<ÁÕo¾$Øb=rž¯¬j3<âÙ?'Nʾñß¼1; ¿ó°‰½z ½„¢‹>° ¿£“•½Úì`=5É>…¤ ¼>Ž{>cÏ">Mp�>fD0>„Qþ›Xø=.‹(½„²æ½ [¿þú]<Ͻ •‰¾¢’T¾_Gä¾Nß=Dò=¹)>Å0�½ó}>GFF=qÅ= Ò¦½‹É7>9¥> c¤=êÔ€¾éT¾U¢,¾¦m¾iÿн õK>a$&¾›g>öî >í¾Rm½oỽ£4r=nVO>€Á½îÖ*¾Ý€=µ«¿¢û¡>�"(>‹¿=0õì=`QD>¦ˆ>óé‚=:‡S¾N¹{¾Äº¦>!ò¿>ªž½¡>�>2L&½�9„¾'�=HŽƒ>À¸s=>“ôy>¿q ¾Òßâ=Ìîé>xpæ½ešÈ=fW\>KøJ½:(³¾øE§¾=•�>ÅT¾ó¸)>õö€¾ W>õZ·½Ÿ»¬¾Ñ"’½÷Í=ÄÚ#¾¶¼ˆ=K¬¾º‚¾ÔΧ>6ò¾ûÊÙ>$ËW>½À ¾×5¾^†Þ¾Žôq¾ò‚S¾$¿ê>ŽV>§ÜȾà�Ž>(Îõ»虾÷ù®¼ )=× Ÿ¾\ë1¾âˆ¦¾ÏÁ½a]A¾°ˆ¢= —ú=åôé½¥î<œ+½B<=S?¶½Ä;†½Ö+=Šm'>®®G>i›Ï>Iƒ>ÅðO>’ ­¾!)>óAs>ÂnX¾×Õ¢>pÚѾm´<.Kg¼P}«¾ Nõ½‹/½¢�è»T1â¾( ¿=»w¾ìn®>͈ö=´¢l¾¡2¾½vO¾5{…¾�¨-¾q¾zÈ>±’ˆ¼È= >0!}¾×\š½}=óÛ»¼C•½J�;>î…>¡ç¶=_i–¾¾.ê>¶Ô˜¾Á6¾©©>Jsš½¹&¾½Î¤>ç2>Å#7<ï5¾Gt>¬•ü½X�¨=Šõ0¾‘ö=€îÜ>¬m>óp>AÕ€>ý÷K½÷@N¾½þ'‹>SÚ&>$[®¾¯K彊ÿ–½�¦@>ñ“û<‚Ó¾Dñ=ÂB黈a ¿¨c/>Š<×><>78"¾žù¢½wO�½“¢i¾| {¾fw¢=šWk=ÁÓ·»,©‡=bÜG>ËFÆ>îš½}ƈ¾gD>`œË>Ü›’>Kù>³‹¾eA¾¼ÓàÇ>gë½-,νGlV¾ÙÎ>âh´>-O½œ­>Ølœ½s”š>ů²¾²õr¼‚Öu=!~;!ý;ç—–½Ó¢Þ¾†��¾¯Ã>•ý¾–gm>–fŒ=ÖN’¾Ld�=ò@÷¾M ܽÕu‹>¨ÕÛ½×Üä¾ù9¦>§ÁݽÃq޾8h^>›?©>af?x >² ‹¾¢»¾xÙÖ½¸µ¾ßĉ*AÚ=5 =ïV”>zR½úX‰¾Š+¾¨-=®?Ί ¿•¤¾ÌR>ÞD>ÉtμªNø½§Ô³½Å!b¾ÒÅ>†¸L¾µè„¾Nc ¾€=Ü:D¹Šºæø#9îë‘<ý<>–F#>äØv½F5¾ãäF>|ƒ‚> ¾¦Õ>®Óõ½&Uí=>ah>GŸ–>Øg¹>í£›>–ñn> =@½£ö(=˜ †>þº ¾œä#>§@Á=„Pß>Ó•¾ˆB>Lës>/·º>œþ¿Ê¨š=¡?Ó½˜5l>ÉæP>^Ò==v0œ>‡¸á=N =Ä¿½ÄŸ>yo­¼Ÿ¾8œ™>+�޾Ž=оèlà¾"°#?xé¯>ù¾>>¾‚}b=1¦>[Õ~=ºÚ<ÖÀù=€<6Sx¾BCؼ¼Z±¾‰<.û½>ôõ?¾cc§=ö)"=ˆ�™¾–»;(g5¾AD>±lÒ½õ>·s¢¾ï�¼ês½N©½=žD>ï|Ã=íÒR½$>üO–½ÂR<œ°Â½æ+›=Âx¾{ÚÓ>ˆ>Z|´¾¬ß=~—#¾ëÿŽngß=†‰P>Ú“�¾z <¾¾Æ.¾l¦½&Û0=zÁ¾C¾Â»‡¾—>4>„ã^>©‰Q>…½yÇ¿Ãp?¾ñÂ�¾äTì¾ `f>#5Ò½ý;=¾êM¾R¾žr>k«,¾K<ļ5þh¿>^ÊŒ>¥dô=äË+¾{?e=u½Ù$¾uu­=ýìC>—%¾EΗ¾Ê侄H ¾íQ>ý–¸>‡‚ò½:•⽺¹D½œ'=í›À½½&©¾2R¥¾Fâi>�"¾L5·=™¬Ä>„×Ó½*˹¾œ…0¾ž¬B»-阾=¨Á>ð¬Á¼Õ�|> 2q¾ˆ¾P%x>µ�¾°P½ƒƒ?¾ÞYǾî=k½5VF¾ÙA>6·½ôQž>x\=)î«=^=‰¾ü·x>Üœ>èâÅ>fÝÙ<�||¾ÏKÉ=­Qµ½�z/>.11¾—e/¾cB^½Ed�>�{�=ÙÒź9®_¾Áž>1çB>»IŸ>¤žÈ>‡è·>ÒíʽÈ[¾ûT§½ÃìL¾ªþ->/Ú,=b½=øL¾PD?Šðt>Í"E>¶ Â>kö¾ÖÉ÷=)qQ»IQ®>†3F>¯Á˾¸ =As>í»z>�Û>W†Ê=á7¿½¡‹¾ß:Ö<&Œ”>ŽÇ=Jãp= $>uÚù½üäd>¶A£¾äœô<„ça½¼~Õ¾ÞΑ¼Ün–¾d\.¾c™¾b$V>±$¾ç =Ãw8¾S,¾žÇ¾»ð¸¼®¨>[œè=ñ¶Ô¾,ùŽ¡gG¾5t¾4ãa¾™Úf>*æ¾Äª.¾À_(>p#¾Èx">?z}> Uá¼Á¾9¾ª6Ó>8þP½ƒ×½ìÓ$¾¬Ð3=Ф¾ðù×¾@ü“>gxÞ½äSS>=»à=þw+½ô¾¥÷f>|%$?g'�¾`f”=„Õݽ'=Ý=‚ðˆ¾] ¿_P¡<°˜þ½¦R½«s¾ˆŸ•½ðÜ=ò| >ôÝ9¾ˆZ½ r=ê½jk½úܬ¾„_»¾ˆ'=Xt¿Ÿóh=6 ‡>¨ìá=û0>´»ò‘v£>Ï÷ƒ¼Vœª>䣿h§¯½òto>—y>þÿ¬>é >Ö>I4;&�Ö=ÎÑŠ¾‾— ‹=f¹¼ ¨>p©�½ g<1œ¶¾ŒÕ¿ å0:Þ:ž>H  ¾ž²¾z±Ê¾MØþ>ñ>>rg…¾„Ô�>L>¥¾u$Z<\‡¾Qcª=ps»:%lR¾¿A)¾š¶=hQŽ½Æœ¾•Ó¾Sé~>?A>@¹>p(±½´®½òš¼Tpd¾ò«4>E½®f0= _ï¾å<š>Ü0¾v䃾ò¿Õ¾»œ¾ÃKU=Wýï=�Ÿ‹>xä5>Zþ¾á|r>üòÊ=q ¨¼v1ɾ¡>vÅü?½Ÿø<ç-X¾¸–˜½Bˆ®½¬F¾5©¤¼T¹ƒ=•²¾”ôϾ`«O>PJˆ>AWœ¾“[²½ðO°>pÖ½ }‹½[”¾tŸ—>úº½)I‰>wZÈ=’H*;G€Ú=‘2½F%å¾’@>ö/‘>û_¥¾¸:Á>~öî;”5Š>ès¾U¥>ë#Á¾]¡=©ñó½ÚW3>l�>wéâ¼Á'>jôB>B ù¾ì7s¾3ùå=èoº/Ni>;G}¾¼z¾l2™¼VY¾¾­ß¾t¨ >,Z®½wû­<,ºY¾LŽø½u×·>Œ«˜>8–ν©,Œ=» ¨>j>6n¾zˆÚ<£çb¼[`¶>¹÷?=F´f½¡Óe¾ìäl½¯ =çk¾Í•ñΕ·½\»=�#>³×>ÅÀ¡½U@„=mX¢=eÙ¤>Dˆ«< &î>ñNõ½ö‚> â8=‚�<#!q¾`Þ©>'¶)½&R>Ài> ^Ê»M{ž¾K‘�½ŸK/¾ûdÞ=Ú÷|>™�Ö>ê¢Ã=J¦¼<˜´Ø>2T¾v >�"¾Ó0>®é½@µL=luØ=öå ¾I¾ Çs¾=<¼¾et->×Ñ…=#­¹=¯Hœ½’{Œ¾=Y�>ýW.>’ØA¾ÖÒ½@é¼=€·=Ñ13¾Ëé>æ>Xäf>‚³Z=¯ ¾Ã46¾"Sy¾þ´>½qܽß+¿½ß™É¼ÐeÖ¾ýëS>A`ݾ­‚c>…‹³¾C½\Ͼ¤Ì�½ü”>’;´>OÄ�½§¤c½Ãÿ*¿%]²>¯v/¾‚“>3âÃ=º‚>€G¥>Ê=�>mÈ!>ÒùŒ>>ý‹¾G;½cÌ‹>Ú6Í>ñù ?“¢¼Q‚M>lõ侄�›¾òþR½LA?àFó=Ï,ްã½)¶€>†yܾ¼e>~H¸¾r¦_=�*g=ïžF½wv>à÷²¾þ/ʾ¬)¾>¦Éœ¾ï®$½eÜë»ð¼§½¯úã½÷˜=¼ü²>8öi¾_�²½³4ô½ZDT>X+½J¤–¾xË>ßÓ¾=Ê™…¾¤×K=ì2²>#Å¿HæŠ=Ž•½ræ£>ÿ~I>iZ¾ ±>m¬k½_ͽ²ªâ½XÓŠn¾˜D¾»wƾ?®½Ùï>àK…¾˜š�>í’½›;´>&·4<&Í·=’]N?S¬ä=êl“½ga£¾È]¼9 s>Ž“ï<�>3¾t¾Þ ·óǽJâH>p¥‹>I‰‰>HΊ>“šF½rR›¾ðŠ¿œþ4¾NJ?=^ê½x™>”Aû¾ÌÎ>Ôö¾¬�§=nl0¾n<¬ºT¾Î‡Ô¼‹÷Õ½Ãy˾ Ê?�<³½IÞù=oT޼Là<™eO¾Å+O¾kº¼‹��½è½N&c¾‡–¾M´î¼J› ¾MÂ*?7»¾îÏ/½,ÎŽ È=ryнhy©>Ë.>÷®>¼|0>|„‹=WQ4=eyç=€š=¿Ší’>JDb=_¡ƒ½Óê�½yé!>þ>´)=b‘g>aý¾眾8²¾Atp>ÍÅU¾š£f¾Ð2>']9>„б>C =/½Ž¾�L¼‘§?ÈÀX>ÖÄ<k­>Ö¾E¾W =—�¡¾ae†¾#.?~S¿¾b‹W=tjÅ=–rÀ¾{šê=a޽'qμª¿¾ Ù¬¼ô0Ͻ¨´¾F�½Õ#¾�-?hÜî>×5¾ ½>.‹t>)8ˆ>&e�>I"±=²² ¾÷=’¾èó“>y$j<´ U½fí=ÿtÒ>fé¾yȽaé>�’s¾Ãj>¬¶0½éxr=«(Ü>¡?ä>£ƒÛ¾wž°<ד\¾�Iî>ÌýÁ½rÅŒ> ' ¼»Q?Ð ý>�¿…=ökýËMˆ¾úÔg>½E*?–©?OéÓ=$ü6¾»ÛU½’4½41¿¾·<+¾y(½>@5ݾIí=ïƒP>Üþ?4>ê(¢=6z·¾ê{‹>A Ý=ž<ú¼“šŒ¾ÏQм¸%>"�=´”ä>äjM>u¾GøŠ<Ã!Ù>"•?>d]>hti>ïž´½<(”=žõ½õ¨>éb ¿ö�¬½»ƒ£=1ó1=¬Ë=>§®¾èxç=ض?+д¾´^ ;ø�™>ú®É=>ÍX>ªR¤¾ÕDý=ª½’¾ÀW =zÏ=Z«/¾×–=·®•½ã¨Á½þß`>$’?¾Ya¾оiÆß>�¢°¾fA=GW>"å<½/«L<ïp>=¥´>^={Ð=<È?¾ÕŸ�=ðʉ>è½Ü¾üȼ>·>uü†ß¢E>Ekξ¦A?òÑâ>É$l¾;8ͽ9” =>̼p}ñ¼©Xä=…¤½o牼FƘ=–uò½‚o¾xþx=ßþ¢=q%Ÿ;Ê]¾Ù#¸=×÷ž¾ùï'=èÏ*¾¯Y¢½3>«tƽºŸŠ¼­z ¾Vž¾aç¤>d¯Ÿ=+š²¾¼¾î[پ﬽ʸ½¾z^>Ù�-¾Òç·½g‚½gâ=2a>\øò¾4P¾ÎX2¾à2Ø>G"™=  2=pD>=¼›Ë>NH@¿¸½©½‘Åf>¼�¿=\Ša=V“Ù>]Ó)¾ÝÀ¿:Ú¾¾5Í<Í/ ?¶Â¾]¬Ù>£˜>Ø�7>6!µ½—Ä“>oT›>s“˜>CÓa=äd™C¦=¥"оÜPm¾ê¾Ós:;^È¥¾‡ƒ¾7¿>¿í>ò7®½9Œ•¾¯õÚ>¯’ļ¡S¾FJT¾×ŠÚ¾`o¶<|S"¾N¿ ¾U+(=ªð>Sz…=a> lè=Ä–Ï>Pd¾þÑ>÷öD>–ô¾ξ’ ¾w4>¥‰¾Ò´Œ>a½q Ò<æs:>h¾h>9«*¾]G>Ï"^>HºW>è`ø=v8 >kÀÇ=ª?xùw;ì+>Èp¾ù†¬½ùÎÏ>X(T¾Ë£4>¾†Ë¼ˆ¾$í9¾¸ò=‰Ä«½NšA>b ì>þ¶¾[›¤=ÜWÓ=ýÀƒ=Mf¾Ÿí#?”[Y>=¾9E?w¾‰»éÔ;%Ö<øÜ5>n¯.>µ³–¾£°H¾Ñ˜–¾H¿½Èt¿r�=>Ÿ%¾EÍ�½�p$>BŒF¾, >šy—¾…款H‡¾åž¼…úù¼á˜>«ÿa¾…y¾é÷'>\Ìm> *ú=„T£=³Ð4>·¡´½Jô²¾!÷€½]°ð=ç9á¼^"'?h¶=ûñ‚>w¤=Åƾo�±½½˜v¾ò¢ ¾pî;ž´À¾ZùK>ڭ˾ŽÂ�”=R$ =¿‚;>.,/½ ÷2¾5+S½2½7ªµ¾éQÌ<–%¾>$½-¤=þ#o=–$#>@™Ë½ã�¿Zìõ¾x«;â…¾>$†Œ=ôZõ¾cå¾ý ¿fĆ>Í>¹þ=I³«½Oi¿½8v‚>Li>¾3»æ¾IQ�¾ø¾wÊ=à Ծܫé=‹…ª>¦û½à/7½jˆ¾¶À¾w�ƒ>$ï-=¢†Ñ>’1ѽr-ÿ¾R ¿¬Ce> Á²¼9ëö½ˆê/¾CY¼¹\ë‰>æþù=£ì¼‚>Áí¾®Ÿ=ᔵ¾ ¹.?ÿ ‘> ¶f>¿Ww¼»š>Õ¬˜>Žºï½î¡@½–ŠD¾m{ë¾úé’=Ò~X>µ«ž½S&¶=h>w!£½�vÚ=>…>Äù¾é—Ƽc×¼4V„> SÊ<õ¥>¡ƒ”¾ÓÕ*¾†kξØò�¾ã‰ ¾à*2==S>sÞ¾ 4õ»  >Í\>ap€¾ý½¬Gf>¼˜­¾Ø¨©<»Ç°½ê>3>¯ ß¾{€«½�Q<¾K¨¾  >Æ­r½E�>Ùån>Íë=í…}>°lY>Ôö¡¾³9·>5€¾·ßd¾’›>e«>uǾÿq¾" >x¡ ¾ý?ý½_¿¾©‘»½øÿ+?�¼©¾JòO¾åB>Û“>b²»> h´=_æ¹>tؽ½eœ1¾ª1ø=£¦¾ø}Å>W•U¾#(?*~>úîÛ¾�`/¼Q4£¼²;ˆmö=× ^tȾ$Ô7=gúv¾e>˜Ö½a÷”¾ƒÑ‡½Aúj¾b¹ø¾¼W*¿‹:3¾B�ˆ>ˆ ½Vó=ì<„½Â…€>­â>’S¾^M5>ëè=”NÚ¼ÛÆ¼>ˆ§™¾&"½>¡oo¾ç!þ½¾äÓ¾n!$>ÖÇr½?I…¾‹¨>øG€¾}¾Î *>�ê2=¨4=z˜1¾Qe8>⓺<¡=?‡ ¼69í>~Œ¾«TB>8–¿€6?\©8>´¾þ»Ê*¾:s–�¼pÕоМÊ>‘�—>>kU>þ¶ÿ½ Y =€în¾ BÕ¼µy‡½]Ný>ž4?1 <½¸OľÛåã>X_a¾ýË= ¨½bÆ=£0=¾=¯O¾~q½»io¾o½U4Ô=1ʾS‹==³ê¾ró> >Ý—¼f,ˆ<;de½i^¿RU˜¾Ö’ì>�>¾u�6>iòg¼ÀøW¾9‘è¾–Q‡=áç’¼xnl>À¼R¾,¼ƒÜ½7^™<!¸>hü˽6° ¿†Æç¾_÷>&^¿öY½BžC¾�>¯D=Ij0>h»‡>K©¼¾%q†¾^Q“>5 §>' ˆ¾Nn>Msº¾ <º>>!©½7™¾t:J=Zð½¾,É>µxˆ=œM?ª®½>6�›¾­^>Úú=å´ ¿ý­Ä¾É_>fU¾×t>Я½vÈ?klS>|h—¾zŽ<©*S¾š›B¾uj¾*;Ù>}¼~¾>Ž˜¾C ñ>³ »>÷`>†Ë—=C¸¾ÆÄ�>'*7¼¼óe>ÿwľ(bþ½;ŵ=þ<»½p辨ý¾Ê>«Ÿª¼ÊW»²À>y†˜=Z€~¾…QнK¬:¾ß;»>hr�½(3�>kˆ§>½À¤¾G¾ð=+Ù¾ø]�>Þ�ݼë¼D>hW¤�¡ð½<-¾P@ǽ.Ws¾�B7¾¸{j¾:ë>Oˆ0¾p½í½"jš=/Uˆ½,@¾n}ÿ½»é…>^¦n=“Íw=ª¿¾Œ}»¾ì�*½v¶>iÙU>¥Œ>µ!¾ÉM¾J>d±D>ëA€=¼O¾>ƒä9¾¦pÞ>q�ó¼ïÈ<Ðû“> S^>.<¿J=¼ à¿ñ¾G(=z€Á¾ÔTï½nž¼5¦¾=®Z¾‹”¾_ÿe½×^[¾¼p¾†A>�ŸÆ¾b‘¢>´`�=‘ ¡=sŒ¾'ÐC¿im<‡`%¾~­Å¾5ü̾Ïч¾Ñè<ÐÈ…¾aNܽn8j=¾Þ:µ=Ÿ=¦óå> È">>™ø¼Ä›==¾H'>¥ø}¾ãÑ>[3=O½Y„”>àßT;QŸ€>,žÌ>ÒL>C1½vDx½ ùË=欈¾³Ô=W+«>о¾jѧ¾@u ½Lp~½ýô >·r‘½dS¾HŽ¿JV¶>íʱ=âµ>/¬>Qb›;f²Å=ÜÃó¾ïËV¾ˆ1Õ=[ƒ¾ÀçÐ>3¹/¾hDW¾Âì=˼µ>)¯Ï¾©×÷¾ ò¥½W¶‰¾üRྦ?@¨t>颽ô�Ǿ÷ê™>–i›=ùañ» ¸Õ>ꄾ\õ’=_2­¾8F½}{«>üSV=ië>¨ëX¾çb™¼ñ±?º¾Ðƽͷ$¾9vë>ú}Ÿ½‹�á>ù$'¾G–¾*´õ=”Å?>ü(?λ>ž™¾(ˆ>Š?H¾Ñ�—>£¥i;Á!½ ÅQ=fuƒ¾œ“�¾¯3‡¾��¾sƒ†½–ÆH=ÚÇ´½/ >,÷ƒ>}å>�²(>w”°> ¨½2‡#>:,‘¾ ±=ûëC=kåܾvDê>Ü™¾Ðà;„õÔ<8™p>› „>aÜî¾…—äöã™>p¥q>”¼·«ãø=l^Z<ÕÌí<–¶½]æ:X[ ¿À‹�¾L Q¾†O�¾JËÅ»�éã½ E?V&̾`E¾Ï“¸>—4ܽÔ�¾Ã‡½<Ëü…¾òÜм½9x¾êŸ¾�Â^<° =>êß‘¾ô¡™¾_L[¾ýà¿´A*?t67½8* ¾vŸ>(Ú’>¨h»“Œ…¾Õ¶¼®Ô¨½xÙ—¾pÀнö·¾µ•Ù=¦î‹>®9‡Wž>{Ü>FY­¾O×X=$Å’>×\¬>x¾pȾ ¸ ¾c×=Cw>0�Ƚ°¯!¿ÆTe¾•ˆ_>  K¾Çj’‘=ÆÕf¾�ÓÑ=Êý¾bë<’ÆÛ>’ƼÄz<°@â>s0x=§Ÿ½µô�¾‘.ŽuŸ¾ÆÕ>Âø¾Y+?*ÍJ=��¾á½¿d­ >Ðû=.¨.½C8½0½¾;”U¾luƾß=Ñ$Ê>£Q>qÎf¾Ï…Ý>‡×¼úh¿n-K¾Èa=oVR½QE†½7ei½1é°¼j ¾ÑÒ= I >§• ¾÷º+DK¾¡±¾‰°>�핾lź>¶¡ò¾z]û> Ño>ŸË羶Þ>âk¾ø†½Åuü½}…? ªP>`uã>RC¾A?úõ¾‹^£>y«?òÜä>Pù)½!Ù¸½WTR>ÔT;èó”¾¹Yë>¬–¸>BØË¼b2¨>”ï5>xY^>Ð9×<�wͽ¦Áâ=̽»8!½5i¹¾â{>—àx>—¾7ß¾ß5¾Ïô¯¾k´¸½ÏqÕ>ÚK>€j½\¼Ê¾c/[>ÈÙ ?†Û“½@Šý½¤*>‹kν¯ô>Ê~ÿ=ARG¾%‘u>'Á’>�íÌ>ˆ¾2£Ü>¼ÅÛ>7Ú¼/q=¹á>$q‹>]Á¾Oˆp¾‰Â½âŸÊ½×b“< ¾EÔ4¾ r×¼kr•>2Ç`¾Ú~f¼•L[>œž=˜Û¿ã¬�½éØ¢>ýª¿8.è¾>ûM?QQ>5eH=ÜÚ/=Û?ÆÈj¾|ry>3å½Ú(—=%Z›½¦H†h×2>,ñ¦½ò7о1uï;¸(¾$ت>:S‡>f./<èÀ¯½ê �¾<ã=P™p="O">Úâm=>^J¾iÌ-½n-—½díÚ½AGÙ=aíî=0š½Þá�¼MǽãÞO>^ž½‹œª>k÷q>UŽÉ=â1a½Õ�>yž=F˜Z>½Ü?Hé�¾ö°1=æ^°½y0¿ƒÁ¶>žÇZ>;Ï1?Ó¾òÇ×>O“F¾›¶>ìÄa¾ˆ¼_²…¾p$о0X”¾œïh>‰æß»ñ~b¾ZhL>ßx¾Z°½æµ ?1#>1ν/§=Šc>¾ïàw¾27¾UWî¼Ö˜ê¼Pß5¾×s�¾þ?ty–>W)@>Yö†¾j` ¿:ý˽jØÙ>•ö>4W½#‘5¿EÚž>´ºá>¥áº½ï<�>µ@¼+ì=Dg¾)l°>�ÝŒ=t?·½•á–¾H‘½¢6,>ÍŸ„¾ÃZ>&2U> ZŒ½6•p=›Ö>¼0>üÂ=¾â“>ù8#¾›<›Q¡>@4 ¾×ØÁ=£>Z·O>–-[?Úº½­úݽÇi¾ n=v4¾è¼—½óœ¿/¾F?¤÷•>w·<ýÒ>›T ?¾/¾R¶Ó½+Ÿ©¾°ŽF>:’,=Èò.½ 5Ä=ˆý½2ä|>#ž‘äQ=7Ý>N ¾”ü>°ÆJ½õ�>ýμísà¾è㥽â€Ä¾üÆ?&=Æ@¤¾Ÿ»¿URÿ:T®^>¼¢<Æ<8¾ʃ¾!‚�=ø¾¿Nõ¼­#þ>«o«¼Öû»Û²|;_Ï>¨#V¾©c½½q*¾Á߽ܽÍ9§: õ&?vô¾«ðv>{&é¾�N>Gɾ²o?ic?vm>ÔQ¾ŽÜ<@7œ<‹&¾*Ó»½0Ä…K'>¼cï¾ò Ó>)[v=eòý=û¦ÿ=ˆ�–>Nh¾h„=ÃÑõ=oªJ>u™½�Žƒ>¿§<_Íç¾Zßî>X$ù½4Š>×ë!½0á³¼ VÅ=�è¾}¥n>¼¶Ð>SM„>ê ^>ÐB�¾Ü#–>Ñʹ>Ãâ’>ôí’¾}ܾcÒ¾ù†0¾WÜl¼ dȽXB¾Q(„>_ÊB½¤žñ½m,¹=ý̆½ c¾Æä¨½S€C¾Éíü½ÖìU¾%-¾ãj¾–ð>è>½˜²>‡Ì®=¤Ì:>ÐÇ?ñˆ*¿5a”=9ÂK½‡Ú¾$ï�>(µ >6±¾þ‹¾áíæ½ù÷Á>‰¾¿"ˆ½Åu= ‰û½HÔ=.�‘=B+ó½°¿ê�¡=ð™s¾[|›<;Z¶>ñG軠˾ìÐù½Ši!>”D¾Þ,¥¾gº§>� *¾” ‡>’jµ;TÂཀ¿XǶ>öø�>‹ü=_¬à>�[¢=v¾)K¤¾-Æü½8Åç»eAD¾§¹�>-‹+¾~ ¿ÔW>?àÃ> ¿¦Îr=»‘c¾ÐaÆ>B¼Î=¢*½�ò‹>ô�2¾ ò¾áœ‚>ê Ž¾_ľÁÖ°¾°xŒ¾¶üÛ>|2µ½¹Ñí¾:ï£>¾=º½Þ0νÕª¼ŸWj=£E>¶0.>'‰©¾ìp*¾Û<¾®Üs9ŽÉ=Ô„Ö¿Ì>ÞÛØ½‚ò =€(>²/ð>ó�Ž>a¸Ö:sä~>¢¤ù¾êÅ>”8½CÅÓ½o'>©©¼¾r=ÑPˆ<�ѧ½ï諒ZAt=Ù<¦>yÉY>’²Ð>CkÀ>á¡>ý%Ä>h¾>œ½¾ÀòŽcÿ-?ÖÔ >‰–r=»­“½…´¾xŽÙ&‡=ÌG0=&È£½wý­¾…fð>S>FÅʼ "¾4–w¾%¼=¨`h>>zû¾V €;ÓÖ¿–‘¼.™”½¿ñ=v9¥>J¼3½æ0g¾ƒr8¾£.=ZP¿¾YÆ=ÇV%¿uï8=EðÕ¾Jêµ<èö¼»E ¾8¾Ù€¾TYË>­&†>‡fp¾í( ¿h©»¼Pk’¾T9#>¤ =é¿‹ã¹=l– >׿±¾£Y?¦0n¾’c2>Ä.“¾•‚ì>9ê¾+m=ŸwN=–t¨½8¦.½Lå|¾ž»›¾ò3°¾'£=òn{¼[—t¾h?ì»&§œ¾A·>#à‚¾ÒµÄ;³å >XëI½èšNƒ¾W´€=â³C¾?Ùµ½Õa¬½™?G½ÖI¾ªHz=j2E>äÊ0¾BM²¾FÐS½ý̾ÅeÝ>ÏÞƒ¾bÁ> J”>¬r%>Â7¾’|ˆ>P`>º×l¾³ã4>%p—¾«éº>üy^>[€8>b#°¾-VÀ>«Yw¾u숽ÒlÑ>nR¯¾Q¥.½°ê¾&sñ>þÚľ«ç>(¼£>óäå=÷Eò¾ËC[>—rq=wu“=<[®>÷_·=‡cK>!à¾èíÔ½êt€¾¢»¾§»¾:vX?BÀ©½¸>H¸ =¿=}>Ò>%A>õõ ¾Í8>#�K½šR¿@¦¾ 5Y½£�Š=2þžºå >”�œ½õ=¾¿†¾–Î�>v1¾·š€=⣳½73V>dÃè=;f?¬’¾gŽÅ=R�¿=P!u>×Öç½Èm™½�V>”>'½1>§Ö-¾öì<¾T™è½—‘w½õv%;ã…>S™=)Å?UØv<ì˜3=vŒ>jå¾g¨Ÿ¾ñ¾ãø?Nži¾�ä�½D¿+XÀ»Š>È´=æ÷¼¼ÕðF>ÂQPaV>|P½cÝ™>-¾ýFÛ=^>#‰G½•2½ÙSλB‹•=YÝÍ>¢Ñ„;Ý7P<ƒ±�¾—èå>ëf>e¼O¾¡v½[Æ�>òßÕ½2áâ>hD?,úF½²°R=†NϽ¾1>B‹^>¬R€=óo¾Ÿ»N>™s¨¾ãJ0>ú v>l?Ð>Ç£T¾”ŽÏ>zš¾ß�œ<ì/£=v`¾­ÆÕ=ñU¼8D­>ðp>?Ä¿ƒƒV¾q¿ê>Í=½UÖJ¾~—½r¹#>­F�¾‘=>ðµÎ>vh°½û¾=ß«‰½VE;>y!¾‹S5¿¡há=ô�¾¯~™¾u8”¾nHõ=�³Ý¾R.ܽƒ(g>Q|>ÎT�>R/>�¸¼¶Œ ¾›¾}g1>YÍá=æã1¾´Ç#¾p§,=Ù¸¯½M À> k½y_Œ=? ?:ž[=¥‚3>/?¨{½&‚ø¾û³›>ßS—¾’Ô=®mé¾w{¥¾½ØR¾ œõ½øaO¾ ;¿Ç  ¿iéø<Úˆ:Ââ¢=r‡=¥E ?uÛ=¼¸XɽØó=RDÁ»ª¦Ó¾Ë |>ᦶ¾»½=Û„?ümÁ=Ñ”�>η£¾8ɯ¼¡Áì¾”þ¾ÐXó½Ã�>=‚5¾Î…> J> �Q¾`î�½‘Ux½”ïɽ±ƒ…>`²¸¾4-�>Å]Ú<«–Ÿ=î�ª½àý >Ÿ!¾¸a‡¾Äµx>˜Ž¿‰‘¾—Ê?!�Ì=˺½±ƒt>'d•>4O_½÷R<>E1ľþOÞ=[±?—ÜÞ½¶H{>Mx+= é‚=:¼Ò>+S޾¢$®>l´=‚¬>w ;Ÿ5y>­6õ¾]d¦>LÀ >”Ÿ¾|–¾‘SW<¿þ >uù¾ã½; F>o<Ǿ‡Ð½�–I¾B™ì==i»>jQ×=?‡°½9¾ò_>+)”¾$•-?º¦Ÿ½9àÔ½A‰,¾ê)>V+¾Þƒ´½.!ù»=˱>®RU¾àç�½0û >Xž¾«Á¾àÇ@=I½˜>®L³=é:w>ª�N¾Õ š¾ Ò>�žÜ>�A¾‹[Ä<�d‚>¯Æ¾'@S¾((‘¼ ó´>Ö>+—L>žï(?o(4¼x@ »DSÜ>²_¾çY[>üá><÷E¾Ûâa¾Ãe˾ïà½ÛäL¾w·�=?4¿ß4(¾Ar=c³¾¢9=¢ñ‘¾`ö¿ÙŒ=Mô`¾ „¿X³_>®Î>Á I<8">›W-¾íL¾½Ý b¾ø‚�=OöÜ=®¦a¾Ûƒc»[Üú»Üùë=u—O¾×™õ>Ýa¾X‚ˆ=qà>â¾6$?E˜Á¾¨ ½bK¡¾ôãª=K§È¾bf�¾WRÏ=–’T>Þ鎾3÷ >½¾ž|‘¾ö ½ …½äDǾ¼¹í½G…¾Û˜>�/3>/Ò5=ã[¢½¨ƒ[¾9¼S>oc÷¼–kÕ¾{¢¾%ç¶f¾N¿µ~Ù½û’í=›±=”ÉÊ=�¾¿y  >9Í?º± ?ÚX2>âM¿ÇÎÕ¾|.ü½W1¾¾k¶¾3 z=õ ?Œ°Ÿ½äº�>;�©¾j¸=„°›¾œFh¾¾˜¾W¥>x ª¾n’>+ß¼>Д<´çX¾+ì/¾˜=›¾Œt5<ë>ôN=èÔ“¾Ì™+¾OU•>ÇW¾&¿›¾êΖ»)‡”½*Çm¾¶þJ¾"9^>, »’,?‚ò>;Á=×\²> ¾P¾ŠÖ¼@о¶›J¾²:Ñ=²¿`çW¾42å>2ç�=—Í'¿5h?\œ>¦Èp<Ép½¬n5¾Ôù>‚µ,¿. ޾‡Â‰½p ¾(g=V?² ='ɾ¾Ód=ùH^=9H¾�оN5�¾©è÷¾Î=}9x> œ>Ú+R½““=¶;C>ìL=‘¥K¾‚Þ >U‡¾%»µ½z)¾® ¼>‘·‹ã·¾±³ ¾¤Ø,>°g¾{ý½pèß<° i½nÐ=�û4> æ$> â%¾�r>Iäì>0S�½ÊáW¾n…†¾Ðôw½JnÎ>_ɾD±À>[B>À›¾MÈ9¾Öþ@½â3¾µËë¼c­Õ>ÔO)>'Ó=Ì‚©½$ßC¾Ýã¨>ÜÁò¼%î½ ~³þ©$¾^ Õ>ßY^>ž/f¾û"|½h ½�îè¾]à >ÿ€Ñ»£Ï&¾6ßH½mêܾÛ¥>›+>1q+¾ÍºV¾it=VpÇ;(Z¾T>s½6¾-¾¬>¤Þš¾f">P§_¾ëe¾…¯—¼µ½¸C…¾ö<>¡”¹lBd¾øC¦¾ãÚ=¢‹A>Ù$Ê=!~¾ö6>BX•=¯ÖÌ> vë¼}ú¾>k̾ý¥*=äýQ>šÈM¾H\޽÷ÖÕ=* £½ÜŽ>‘н Œ¿S=�¾uyÄ<+ûнÛ\†=õs¨¾ V8=ž‚=>Rç:¾QfÔ½L:>ë꼈wn¾X”“¾Üß=Ðõ#¾Ë˜Ý>|>¦Eù=*¤Š>ïÜ‘¾ Ép¾ß嬾…úD¾]¹J=}¤>¦öS=e5A>஽™R;!Ý…>z¸½ë°=-µí¼_Ö=™@ƒ>+5æ½Ïœå<óRò= é[¾>öí½â–™¾$+:=,¤1>Å–¾÷"ð<ËÚ]¾¼qC>®d˜>O8Ÿ½†G ¾ìãнî¦;v¡»¾cŸ"¾ÃE©>6n·»Ðöv>ûŸ½Åf=+ŸÉ¾%’>̘¾U(¼22>o *¾ðä¾,¦¶=nn>¨f>áíÈ»¡ñ´¾¡Çå¾Lÿ>_#É=x¨4¾Â†>™O�>µ Ø>¤CÄ=b"q¾UaŸ=¥ø„¾¾‡M>öu—¾’N> · ¾B>.¾×²½B‰¾U�„¾Èf‹>Çv×>=ˆ¾.›¾èHY<„\V¾4³C>ÌP ½gb >>ø¤¾ ç<½ÛÀÓ>2•U;ã+§¾Tx…¾àBµ<Þ<=ñ5›¾hn=Ñ%B¾0‡S=Ó/ؼO¾w4>Ó+º>öõ�=EfŸ½ ŸV>‚Ê"¾<Ÿý½/#¿Xsº=¥ND¾Ò‹>d‰œ¼.Í�¾µÇA½ÿĽE4>�ÕG=EKÿ=ŠÒ¾d…¯¾(j®¾-«æ½Î ¤¾•¯l¾ïóÊ=œ+š>Uð;Ý#ѾäÞ1=|ò›¾„â½Òü‹>/«:>g6“=Oª˜=…Ä<¶­§»Å‡í=b²—¾¤ZJ¾’¿Çô½9ÉÔ<¢û۾꥽­M>I&?gÒ§½¤.ļ9V?½´¤¦>/¿¼>ïS¾5ë¿<€–¼ê{=@ë±>ŽÔ�¾‚œf¾ó>{¾“Ѭ>{Š<¾’œ=1·›¾l¿nŸ>‰Ùì=m1ǽ¾i?Gý0>—d�¾ÊP=°Ú½&¼q½­Ôk=ÊbB¾HC½´Ø¿>§Q¾(|á>ïR¾Vód¾-%Ò¾³ñ]>©êB¾ã;½~ã=!­,¾Dýˆ¾DäÒ=q¾¶p>™I3>R@î>)j>�¢½ö&I>úbÁ<ß,>Ä Æ»æ¥N>«'¾S–¹=®h|¾ws>§)Y¾;Êн詡½ Çî<°«>êÙñ>b,¸=´éã=io�¼P6¾wÀ>ä`ŽòB¾§nd<.~¿½—?œ9)>Z¨·=OÐV¾Î„>I ¾$ж½m^7>Ñ2J>¸�¾–-Â=©¬>ej=šŽÁ>–Z”¾“„>Õs¤=ærc>‹¯½=DS>€U<��8½È ¼g—î=¯ž4>¹ >>Œ„>��(¾€Æm>{ƒ´½tA¾'/¾€~$½òœ>WÔmì=JDÙ>ëP>“�»=£Þ¾"B¦=Ž¹Ê¾Nu.>£WÊ>Îö¾¾‚:¾ùż± %¾õݪ>ל�¾ïŒ„½ôxI½ö‡5<]în¾Ýê±½R„ƒ¾…^Ô½Ö‚G½(Ë»½°º¼ ã®>š'/>cQ>lÇP¾®L¾-î/>ö’½U;§¼'ÿ>$¬v½¾§ÿ=2ÿ¶>SôÂ>×Ûˆ½ß‰Ž¾ÃÕ=óv4¾~,¶½< Œº†µ™¾�á½cd¬½q‹¾‘²Ä>–‡²>ÓÁy¾Øœ?ßCX¾T£Ðߥ==ÁD†>q‡¾N¾9>Øé�½Yþ޾Ânê»ýÔ½2Œ»>ds4½]©½b•j>iuÔ>GKɽEÆŒ½¼ ?6ÅZ¾-×>>Æ º¾vÒ�¾ÈºUP—þY�A¾ç]î=(Aq¼�E‰»»>ì¾¹#¤=Šô0¾1×…=ü¤g½›¢•½ôߨ¾�{£=g²f¾÷•˜>mîJ¾R£“¾ù®ð°1¾Õ¼ r >SÑí½×¿ ¿ò¨£¾�‘ ¾ú -½rG�>©¶ó¾i;Ú=¼WB¾¢“=Ë š¾8¨]½:¢-=ëx*<�ž¾vQ=wx¹¾2²>}à½>W>ò;’?Ÿ¾à¥•¾EéZ>q†a>~J‚>²>^=ÇÒR>†º;>ë¸I>Pq½Š´ ¾Ú­,¾Gb=‹�¤;¯½é¾€Z‰<¬Ü>>Œj>07·>˜9<¾Å³{¾N�ܾP¾’d޽°âz>H­�¾é‰5½%Åë<�Ò{½ ð?ëáÕ½`Îà>2­‡>ÎhQxà�½fh¿adνÖø<Ïä>¾œLy:&LÍ:ôo¾™£‡>VrA=ñо\ ê=¨¢É½�Rë¼,m½w¢“>Œþ½Ô•,½jоHƒŸ=åí‰>+IÞ¼±)³½`°®»DóË>Éò¿Ùý=o^�¼5I¾«ÏÙ½´:¯¾œK¬>Ц<þÐμUi¾Hñ?`�¸»Å1½¾^Y=ት>4Z¾<¨>¤ >ásŒ¾g©¾ •B¾Pî½Ða�=5˜�=ê|=KŠ|>šLç¾^V8>þ±=\ >ä϶¾À.º½Ê¡¾nC=®Ä�½f\¾_ƒ—½»ß½¾¿O½ë=¡¾yÞ=«�6>œ«½~·~¾ü›M>üK>Ÿ½š<5ý�<€#>Ø7½¦æ�=—Jä½Ä-±>­«½A«V¾�AL¾yht> =á ¾ñìð=´º›=j ¢>£>•ü‘>™«ô> Ý¿½¾Ä¡½Ú~/>Î".>‘c¾.ûÿ>LÍ&¾�U#¾¢äŠ>¾%F=¬6¾‡/A¾›%¨¾÷?O¾iî‘>8qØ;yؽNFÒ>ðÕ‘½éôß=s"ؾ¢Æó»:$½=Ü€§¾b?’¾2 ¾N¸>Ø¢°>ÆÁ€>¢0ʾÕᢼ(¯=*#¾Ì3h='¹¢=â'(¾=÷á<‘%:òˆ>;/6¾«�¾ù«±½ií0=QïÅ=yœ(½$Ñš½Ü5R½%Ì€¾î²>¹fŸ¾ÀDV> Ƽæµ@<òâ¾ßDO>VA¼>èÁ¾§j�=©,Ù<ú‡E=Òsõ>t�‘¾(4‡½*‰¼ÿU¾å’½J]†¾¢ü=R ¾'‡ñ> Áa¾ó{F¾_�Ú¾r�!>RËX¾ nk½¥Ñž¾ÜŽ!¾‘£=éMÛ=#‡==cr¾�PÕ¾ U=ÀP™<®&¾(ý€<ª^˾‹R=9À½rJ ¾ î̼gÕì=~: =ƒo“½åòS= P>ê7H¾3õ½GYX=™:Ì>r/Ì=¨c+¾¦L½œºf="¤¾OÜ™½ÙþÆ>>Zw½¼«¾«¥>� ¬¼jÎá½Õå½³,¾Ä�¾j4¾©Þœ>LÕ¾¹ò½>^¦1½ìÔ…>úÃJ>dFU½^­œ=ÿ`•¾ùŸ5¾AZ»¹Q¾XCɼg½r¾@K<Ý£]¾hŠ>º–‰¾™ Ǿ¤|Ͻb¦5¾AïQ¾�ìq¾žÁ¿ÃÏö>ºj=ð~½9z澞ä&¼€gT¾ã¬q>ÄÑ=§p‘¾ËG•¾qQ›>A§=ÛV8>n®¾ãf¾rB¿¼ñ£>w7.½Wü'¾l·á=Ài?=\£Y¾t�ؾZ(ž¾2Ð>’ŽÂ<Ò‡¸½�*Ú½ œ+=ƒ;s¼6‡ >­‘…>É¿;vãù=L7¾úù+>¥t ¾ê®w¾ >øø¿šð<=9&�¾ty®¾¨¿«>Ñã&>ÂG¡>À̼}(¾˜OÕ=›(ž¾Ÿð)½ˆY=?¯=ü^Ͻ¡’ä½m ?óÊw½ù`„>«i¿î �»[R¬Ú»1о>~î¾BØë¾ë.¾®—+>>q> êÄ>Þ[¾!¼C=é4>L· ¾'[k¾ôj+½x…,¼4`œ¾EB9½¾‡%¾Êlž1ò>ˆ-Ê>åÍ>!^V=O¸O¾§ <þCo½n¿½>ð0´½æQ½Á?R°€¾Ì}½úþ´½%â¾ )L¾Í[o¾°›É½~R¾ðx>3™g>çüH¾‘é¾Hé=üÈ”= lk>þ†7= _>ÔkÙ=â~†><ìò=Ò×à>º­ˆ¾Fô¼LÝ =$D>¬r0¾‚P…½nI‚>éè³¼˜|�>ê“¡=L®>‘8>x�>D ?½»q¾S1K¾ÿŠ=jM‡¾ß³>d£ =,ªW¾¨Å,?ÏHg¾ŸÜ>K…(>Íb&>uÚe>ržÔ½•ç½óP†¾èç=` ¾È$Œ¾O^‹½*C>6@ž$Q>€å”½ºf�½Ë„ ½Å³X¾µÇ÷NòC>ÒiÔ½>�Ç>öfH>ÄÄ=¦v[¾®º>H³;ÜÔE¾Š[M>Ë|¥¾äq­¾ê™Ø¾­y“½Â¦0>ß ¾á‹Š¾ë�§¾ H>q„¾¶ƒ¾ÈZ×= 8w>†C¾Ræ‰>0Õ=¹¡¾¦ø>ÀY½½ípè½9æÊ=ãG‹¾ü$–¼œž¾ÂS ¼ô¨¬½OqÔ>+Ú ¾åôØ>'”å=nê°½üÊÍ>WÀ>ò>8Ë$¾oꢾͽ7wR½ëå@¾Ç€¾íÃ^½¿âÈ=2Ù(¾ßT>ï¹">Cåä½K’>¬š=Þr¾‰ƒÚ½§µ->§�g¾¢cÔ=k¤Ô½$È÷=í�¯=éª+>WWǽz�Ƚñ»z½ã@>Ù�Þ¾É'¾>Œvw»‰ž•>Â�¿æ“é½òÌ{= ps½îT>ó?«Ju¾xÚi>ḣ¾/G·¼ö•Ÿ¾Ab ¾u‚‰¾Ö]ƒ>ñê=°?>ðÒÝ>GU¾lÄÌ>AO>.Û/¾P3‰¾ü§z½I�‰=·àD>º0·½ÿ¤@¼Î®á¾æ˜¦»K8I¾·¿«=º­½|½v½¢úü½Ô�°<(ìþ½ù–ƒ¾lŒ¢¾ð‚½ïÓ+¾úÜ€>Dq6=al_½ò+‹=ì[¶®æ½… ,¾Í�½àlb¾á¶b¾‰t>©Á6¾pî¾­ØÎ½WÀ-¿�7¾…É[¾ *=·p�½ýÔ½Åb¸½ $E>ÉÞ>­¹¼/¼¹>G•н ßX¾ +í½DÍ�¾Š1=¾Ë¸*>õÈ ?Âf<¾¼Q†¾Óê1=b[‘>{B¼½èŒ=—‡…>9Î˽Ûké½á¸¢> AŠ>>ÿ¸¾Möq>{ˆ­½‹Uq½µâ7>�쿾е£½&˜z=‚ ¾dbx<�ß¼-¥Ð½Þ�œ>нU¼°½Œ1¾Ûk¾Ñû�¾)À]¾P> ,´=Ù#Ð=öG$?:A¾tM>ZQ+> T»½ÆÆ€¾Vï(<YO>¯L[¼�}S>ë¶¼�‚„>|<¾IS7>~*0>)Ï¥½Ë¶Å>s+¾qøD¾ ?¿óª­¤å=Í—I¾œØ¦=áÉ=f ¾QþCÚš¾\ï¤>³:>¼¾ð»c½Á*ĽOß‘>«?§}e>”ãÃ=²†™¼^&X?ÞˆŠ¾bž>†‹O>Iã†>�˜˜=§¾ê:3¾Ž£’¼ìnë=ž Á>­ý£¾5̼j&4¾V¿R¾Ž…p=74Ô½‘e‹=/Ø„> c#½Þj“<  ¾÷OÛ¼ˆ@J<Ì^Ì=€Kþ<ŸR˽ŸôǾ›Y>Öç ¾§ºô¾Nwn>Dø½>³m[>\£=Rì>H;÷½¶£j>OÜg¾cµ<Â4¾½é’>ii=¾‚Ÿ=³n ¾î0®>�·‘¾¶)@¾¨þÊà–½ë l=öIϼË>?2)½©a˳à¾ó*±>nÿ”=÷ùŸ½2¾Ëh¼=�i)>ðEæº]Ö^>¹³…=Ý'¾>¸ ¾8ˆ>âR�½UOh>d:•>HÚ½ù#¸>‘h,¿³¨.¾•Ò­=p‚�¾Üð=“Kq>¦ '¾¨>º¾+ݨ>í>2 X>·¼¼©Ý ?É…>eÿä>é”{½8À¾))•½ÐJ�¾èÉ£>"¾m�¾³“é½ ²>6‘6¿Î±ˆ½´�š¾`À½¤%x½¾S7?œ}Ç>¹¶¾– ˼W–(;†p>¾öò>…Ä>>âÜØ<Î꯾:u4¾QxG>k›Œ¾cØC¾û§›¾/;M<Þ_>({¼ :À½Ü>“>}‚ʾžRç=…2¾YŒ½Jtü¾£mO>#ëW=ž;>°÷Ÿ½‚Ûa>.ž¾òPÂ>x¨¾&ÊŒ¾p…¸>+¨d>œ+£¾ A¾QU¶½Aܼ$½‚¼âȿ⠽Ðާ½¶­²<æfU>I¦V=¯·§=8�¬¾I}>:˾bð>ˆ¶½î¨í=¸p½tN�=ÌÕš>z�¾o´B? ð2>Û¸¨=T)÷=mj9>¦_,¾°åÂ=¯þú¼eam>CËb>£éJ>ä“J¾ÄÁõ=2l ½m2»=)ÜÓ>F4½vñÞ¾Ä-†>Šý…¾É6Ž`³=‹/>ÌÌ‚>žá’=H'�¾žs€½�½ò¾€w ¾¿×Q¼ÇDa>å]–>�Yä=W‹›>‰Ô¾‘ñ>>FN)?[”6=¸ô�>$�¾¦Î—=&ÓH=¶‹Ô¾øÍ†= Ó;¼¡Œþ= Œ ¾_±¥>á>‘Áü=�µ,¾ 5¾ŠB¾!ž½jò)>ÉÇܾ—=¿õD�>ÒŸ<tK>žvÙ½ÀÆ«¾´½�?i�³¼Í¿>ö¿>[x™>~ï¤>9ù-½™›»ÉOp>޲”¾ÛŸ=Y*½Ò—Ä=(`þFìÃ>Ü ¾Ï.=´(–¾÷Å>=5×¾gÆ¿�œ’½!]M>‰>Fx> Ó—=–^޽ÆÓ >]ÍÑ=¼[¾èbe½u¥È½”óN½¯ÚO½|&ú=aKA¾Bµ=Èë=¾b9b¾:˜¾Ò©E¾‰èë=I ɾ‘öy=•©=¾?b¬¾„Kç= äÚ½)½?|)>Ðú"=e k¾“xÑ=ø#ë=Ö“z¼{ê<àÀM¾}Bñ=—íO=¨>¥™s>f¦>®�†½¾|¢>MÛ¿ákO>T¢¶>Ç’M= Ž=7h>Ìq7¼¹¾<‡Ó¾™Hº>Íÿ^>™¨~=“÷!?N?ó¾å =þEô>Ö`W¾ñ2B>¢L=Ú¼¾Â±«>:—˜½Aéß½ýô=~~½{Uq¾_5E¥P>_C?EáB>˜vÚ=—J >¸¾‹¹‡¾3û>^‹ì¾Öÿ½�US=Xͽ¾uoT<Šë<Ûi÷¾½˜‹¾‰‘Þ½88Î>UË»ê¡V¾Œ1¾( š¾ý¾½¾@’¾_Úõ= È3¾£Ã€=¶š2>3‡.¾Tkî=í¹Ñ�>åÿ‘½ ÷%½°­?'ú?Lî*½�ª�>9À°¾£²ß½˜Íÿ=ÐÆä=…þy>>’K>c8f¾¼ì¾®8Œ> );¾­�¾üÇv½ô{ý¼™R>>Àž¾üŒL=òNʼ¡º:¾"dE>¤A´=—ÓžH~(¾ î<=χ‰=Iž^=”ô¾>3\½�Ÿê=˜o>æ"¿.Æ~>(€ð½sÉ=¯,>Xä>]u•>¾ôD> ƒ¾’Û¾Rœ•=&#>‘c½UŸ?>sœÚ½íf¾§@?¾�ýû¾ÖpH>ýé&>UͽƒÃ4>ø>â²¹> y\½Qó”>^¼ð=Ü$à=�LR>KF¾[â¾ÕÒ^¾T©=<é_ʽ/4½JÉ9¼·ãl=´±e=xަ½ŠŒš¾ý¯¾©�>½°�=ü­O>(j¦>$ÕȽp~$½¢š>ݽô‘>òž_¾L¿3$¾B—›>D¶=ñø°=PŒ<êzº=x¨¦=Bÿ›¼Ö¢6½4ˆ>LpŽ=B‘¶¾üŒÒ=¯¤‰¾íÙK½#[È=ls½TN²¾JXœ½€§W¾'Ó½ÐÁü=غ¦¾Y¿™7õf>òIÔ¾ØÐǽY&I>y7Ò=á}Á¼œZ>^h_½}GF=ÉÝŽ½80q;¸›¾î±ä½ÁWʾVïͽ[|~<�e½gñ”>|æ?òP=5w>ùоÞ‹>= ù=v�§>ë=Ei=ÀZH=ÈŒ†;«B=Xʾñ8=†…νny<ËV¾HؾAâC¾´ð›>¡W6¾ÎRš=×ÎŒ¾V½÷¼Ø?ÄJ¤Ã¾Š<†>|?£;ˆ¬5¾Ê\­¾‚‹¾@â=¼Ô¼‘ ¹>©Ê•=-È=–Å'½v<ç¬Û¾©Ä†>XÀÚ¾|Ÿñ¾ÑÅþ=¤­>ЂD>FA> ¥ËôE ¿äÝR¾£2ƒ¾jJ`¾n†Â>Öñͼû3Ë=nÏ=�£’=1mØ>6I»=ßsæ½°Hs¾è‹µ¾qAê¼6Â==oz¾xñÝ=„{¹v/? Ès½t*c¾-ö‡>ì'*=Ÿ¤«¾Ý¡ò½·¨>܈Á=Þ±­>áß>ôùȾP%¾Ÿ(l>d>r¼ÒÚÉ=·°«¼×k¸>Ã…=Nèb>(ç>éÖL>°ô@>Q콑F£¾°¥ò½ =ö=[¿Óc!=â$:¾)ù�>&v»÷x =Añ+>ZõD>!Žª=!Ïm>ý?>’‹õ>„jH¾üÌ>Åy?ºé¾¿ o>”r½,6{¾ÜÈ >²¦¼-÷ ¾�e�>M}Ú¾Ú™�>ÝÖ½)Ùڽ؎>¼[¾Œ+Ô>!Êr>O¿&¾*"¼¾;l±>iú>À H>z¾Ì=tðú½®Îz=‚q´¾{œ®¾QÄM¾e[|>8¶É=�½~,:>$”½ßÛ'½FœÞ¾¯r…;ÁÁ¼@T¦¾[B:>œœ¾ò)½¨�bgaw>Rdn¾¸v5½ð—=„yŠ>-zü=˜ôʽڅ­={(¾4“D½)ue>^á(>–¿O¾e•¾ˆ6Ã=6º‡>ñð==(>¾ê¥¾½Š½y Ó=WnÚ=Ù½š= .>@3¾ñ¾Î'¾,@>,ƒ¼ü)Ⱦ{å<(øƒ½F”“½3Ì)>ȵھ�L*½N5Ž>Qµð½ŠŠÆ>û†e>_“q=6U">J¦=¿ˆ;�{;¾†½ß­º½­Ÿt½}8E¾å�"¾X`ؼ#é£>A4¾n½½kè¹¾Pb>�à£>õÄá½Ò¼‘¾7â­¾¹*<>kÝf>2Ç>�Âß½¢l¾MO½HëÒ>  =E’‘½Ó�=> ¾Î†O¾� r½Æö‚½í{L¿Š¾,0ó½*™_=ˆŠ£¾¼Ü“¾WÆ?>6 ˜¾Ä¢t¾Õ!Ý=$Ä >Š\º=»°1>Yo̾ŠÏÇ=‚c‚Ðð¾~©W¿~*=`¨d¾ ÅÒ>œ«�½šŸË½·<¼‚Nܾի{>8ød>Ç®5>.­¼½îoö¼£¾¢¾�X'¼!פ½g:E¾»W(>ªÄ�½ýr\¾}¥.=±{= ‚½>G}¾Ø >¼Ÿ¥=†¢!¾Náï=ÙÜŸ>p¸I>‹j> oç½+� >I>“½€7…½ë0»?µ„¼VšÁ¾¾¿ˆ¾ýÝH=mRŽ›$`>ñ4ž¾ÖYç½=Àž¾\iÓ>*ë½:EpB¾uˆ>~Óˆ=—U¾*¢û<¾f¥=ší½«J>="S²¾b_Å=q*8¾G˜>EÐ?!v¾pòñ½Ä)z¾`Au¾ÄÄ…¾’}¦¾gß¡>Ã&>]Å¿—4->ä]l>ôÉ€½—% ¾äµF> è!<¾ß_>Ìb¾­l*¾ÈHS¾øq¿[¬B¾Tù–=wSÎ=Mq‰>ÅmÖ>.ˆ;½^¥á¾ªû^<ȾÐê>±‹Ÿ¾5!ð<²×¾‘ >ÚáQ=h>ñÀ¤½„*ÐN““¾º¦ƒ¼Wô=jp¼=–Ó•¾§È†½¡:>Ð¥'¾WG9¾à«>?nO=T˜÷>ç/X<”§†¼�fk=Û麾t)?ì$ö<åMŽ=chl>\Ú?Öíz½9Œ=·¸¾2aš<á“v='lR¾�R“½¾gø>Îä==ˆ›Ê>Mó<>‹é¯=–zÜ=¶šg>8•<‹½a½�<Ï>Ýi´=¬ _¾Ì½s—í½æN¾›Ͻe—A=ðj¿‚+Y=Û½`¾xZ:½ºX¾N�¹=˜ØÀ¾–›ƒ>zã¾>çv >ÚÔ)>#�±½� ¾{QÓ=Á<¾^ ¿ht¾Ôáu>ߌ~=Û¸>6$á<©>Ÿ§ú=Þ®½ÖnË>2s@¾@9„¼­Ï²½[*§=Æ* =¡˜¼½V÷¼‡ x¾õsw¾?€/>¼=x¾ªy.¾«>yŠX>Òºb= Ê=ïØ„¾Vgß»ÈÀP½?í½ØÖ®¾(E‰½‹8">sý¡¥=¾¯ ½>ȲL>ÞO�>îâ÷>Z >{@¾S=> –¾$ ¾@cæ¾pǽ›ç>Ö¢>[<“¾9´É¾Ù>èe‰»UMƒ¾äÜ�<€‡>·�Ѿ;)‚¾ïæó½–ç÷<Ǧ¦= õì» ¨¨¾Ï±Ö½æ³£½±Ñø¼rîǾ­^'>Ï?ª<Ƙ>ºØ‹¾TQ¢¾ÌQ„=E†¨½ñj%¾ƒy?�×e>`€¤>d¸ã¾þD>½k×=“y½�c½�æ¾¾û£½LIX>kßs¼oEĽFTœ>¡,¡¾MÇ$>Žc]½ íM¾z_=ÐÌt¼æ©•¾ÂÐ>A¿¥¾w>Üù»½³ìb½Â¾ÑŒ>š¥ä>V’‡>?ÔB¾¶Ô>¼@˜¾_úÖ½„V>LÓ¾öo‚>iB3>]…¾Él.½9ÿþ=IÚ=S#>| 2¾~‹½rm#?¬ÖÅ>R!µ>k¿¾I7·=»-š>n­°=~Ÿ×½§ÑY>VXw¼kTå½Âàú½‡ô=è—T=½|·¾.¢¾ã"¾’4�¾LŒ¼ØÅ(>ou>°»¤>/: ¿§à]= º>¤‹!¾ºÒ½Ó >Òà£>Ðp>Ñ%v>³?>Y÷¬>¨VÅ=‹V¶¾‡p?i¤ƒ=7Ìo>é±P>ã½>§c™>�]f>€T„½Ùî>‘v�»Ík>Àô'=É6<—ÿ¼<‹N>X)Ñ>ÿÛM>¡ ª¾‹^ƒ½NR(>ué'¾Àâ¾ ÓŸ½��þ»´ÿ¾óœ³=-]¾ÍL2½#ô½çD<•q:=kw¼º¯Ý¾Z—¯¾¶Ä’½Ü#>BñF½3é=\®�>Ï/>°Éq>-©^½î—W½ž_F¾Tpü½™6¾‘ãx¾í­}¾ÌqÕ>¢Åɾý3>€E„>Ñ˾±¡¾˜©Å>ØÇ5?j&·½Â|½ÈõW=ÑE…¾UÊ(>„4ýÇ_>RÃþ»�>‡®G¾>-³¾¦ùâ¾,¦Â>‡=œvó=«||>¦¼»>6»4?ßxž¾^;½Rn=¾ÇŽ>4Γ=Í-—>7Þe¼�c«>¶w4=Þ0о'Al>96½>¨J=u4>ê’>GMm¾²¾Â=v¶#>ñÙ2½Ñ‰¿›>B¾é$ž´Ó>ñŸâ=áÓl¾)B§º0È=R].<=p >â) =鲯½ôº =z"”¾p{±¾c°Ø<}×w>óBž>íx³½¯Ek>æ“1¾<® ?!¹=á§¿¼®¹ >šd‘¼`úÂ>ìá4¾ ³¾%êÕ¾ôœ¾Db)?é˰>ZŽÛ<Í®¾Yè¿Q>c¾Ò”Š<7|ð=™ν½ž¾К¾iÚ½¨hÚ>e¼�=•ÝX>Ì!ô¼7ß<=X¨^=¶ˆ=øí3>5s�>uë*>4'|½˜€Ê=î,„<Î|¼>Q�¾™R¾"�W¾Sqe=üy³¾�åŠ=˜w£‹¾I³¾g‘¿ëU¿è9%>0¨>"åã<øƒ¿€›ð>Ü¡G=±_­¾k°¿vÛï¼�ê²>ª*þ½XÈk¾<•´>à Ÿ½6Y5¾ô¹€¾oWоè]ª¼ÐÝ<>ÁX¾n6 >!§©=Q1„>Oh|>àE¥½¢!¾n‡™½\I4¾ÅEê½JP¼¤ø½$|$=­…¸>îñ?ˆh[¾.�¾¡™­>"Ò>çŽ=Ve#¾N7|>Ðb«¾·9Ú¾Ó¢~;#e2¾XŸ">äµ½þ¿³P‘¾."ß¾9E½½Â‘>ó¥>Èn†¾iô(>Cë½°©í<[gÍ>šß!>ˆ\B½T`–=¾Ü¶>ê‡Û¾°ìx=üîÙ>$·Ì¾Âú½˜h¾þØÄ¾ 0–¾m‹A>,�`¾¹¬->dý&>�¼,œ¾;¾f4¥>ÿX×=)†½Òòξ¶Ê/>.M¾Ðð ¿qM»=C­*?;d\»§¼Uÿƒ<Ã-˜¾æË¦=ØÔœ¾Ö"½ n¢=°ŽÊ>‰üÙ=q+à<˜>+÷�>ö-¾ù’–>v\Ù½ö@&½’ã4¿?Éྴ¾jÃÐ=mœÎ¾±2J>›§È>¯ãa¾TÙ¡¾ø=v“¾Îëh>„x¥šL^½*%ó=‚‡Á½»~¾š~œ=Énæ½cãÀ¾UÒ=— =IŒ“>sù>Û1‡¾‘ B¾ŽÝ¶¾›ø;=€<>³)Ü=ख>ª»½ž†Å¾Q˜X=‹ ½8Y…>V„Õ½Ò>øH >‹Î,¾´Î ½à’�½÷I¼Írk>ëMÙ¾²=¿TÒo>\Î1>3𤾉:>Ë�L½\®¤>ƒÐy>7Âý>DÀ6=Èt>ºÒó>sU—>%b˜>H<�=‘’;Õ@[>Ä÷j=Nѽoõ?¾páÁ>ƒÂ´>;ë+¾ÎK´¾QÎ>§­>9«:; 3l>1 ¿tÚ=94Ó¾Ü)>¡O>™Y°=-¸e½{=®½A諭Á‰í½TUà= 6½( ¯½ÄÇ<9¬Æ»ôßF>h¯½v[U>ä5è½ÉŸ½=«Ã¢<ؾ¾Ä½¬”>ëÄ¿cFÔ¾=¨h¾‚Åî½�ûǽœÏ�½ê¼;n  ?§W¼=v>ßúï;ëì½õL >Ì .¾.¼˜“òº>Ò¿”Œh¾Êh=äŠÙ>2 ?2%8¾} —¾£¿Ù½¬Ã>®rN> èE¾<Äì>{)>HŸ=oÀ¥>ègý»áW¼ͽ’�‚¾+!×>%¾Ë¾y¾F>Oñ ? Š‘>=?X8 ¾¨„Œ½X¬>ouö¼vk_½Îé>ò±ß½ï2Ž<è ê> e‚>l~d¾/R�¾ô%A=œ ¾E×ɽ+_†½nnƒ¾Hž]¾®ˆ ½/.m=W°Ó¾î j¾Œ¸Î½¾¦•½¾¯ƒ> ûŠ=‹†Æ>Y¢2>èü¡ºo>„QÀ>Ub?68U>Ò²ë¼6G¹>û�ˆ=TÁ}>¿·¾9Ä>èÃÚ½¸H³½C@,>»`?°D“¾]Z>w°¿¬Ñ=’Ü«¾º)>Œy&>á3¾Ÿd=½Šù>u±>nø�¾½‘¾ÆG&>š3Œ=ïÐÞ>ÏœL>脼9>Ž¿¾ŠV>VU•½)æ¾:Á>2r>Ç8¿MνV©o¾µ*º¾øa0>?¯¾î´Ä=ó k¾Èù»�U>\³„>‘|º= ¼">¶D'=SµÛ>Ð�¾:¬½QI(¿»Û=¾>?¾=¡Øi>Æ½Ž”ß=>²>·À½²ˆ¾É§†>X>À¾†8Ø=ÊÙ>£›½Õ'¾»~¾žõ·½!¬Á>~M=ïM= Ó2>º%þ½äáI?Qö»žÁ>q¾>†€¾T˜?¦�¾›Ôè>"ø¦¾\H_>ªA¤>7Cƒ½ñ1C¾RìĽ÷A>mZ¬>n#W½äžÎ»Pþš¾Š…$¼hQœ>f >.ò<=š ¾ Ÿì¾*t©=HdZ¾ ú¾¸>9áµ½}y‰¾-ϼI©=Éx&>œõŽ>8�#>ÖŒ‚>Æðe½æŸm>Ç£æ;�gÖ½WL>ƒ>Ú½þË=P’/>ìm)¾Ã8¶>÷°æ¾ºÂÞ>z�Ù>>¨=ß®›>[î9>§X^>Á¨9j=Â=z¯¾Añq½-­Æ¾á£ª=­u>½"?ŒÍ˜¾¥Fœ>u»Ã=–W¨½sÅ�>9�F>ì—Ò¼Ö°.>´ -¾ßý=Ùh¡>ÁÒžaî½@½°Ôƽç'> Á½Âº‰<_\’¼– Y>óÔp=�­Ë=/P ¾*¹¯¾�¾T¶ˆ¾2>¡¾ûg�>Œí£¾åû4¿]4Œ<>z›= ãD>?UÝ>˜ q½Ì鄾*“=5zˆ=íUɾ-—¾üÁ ¾VXá¾n|¾V—R¾2_ä>%0>|vû¾"Ý>† ¼±ã>œŒõ>×Éa½ÊK�½�5£¾Œê>6ßû¾’¹É½ê«ƒ=T㾘;Ü>-J¿ª"½þèľ²_½.�Y½c³¼Šfð½ØxÌ= Õè=K¸�¾’AŽ==î­¾^3¿EBÈ> Œ(¾�óæ=|°=P•>^ 2>Ј”uy½ðš5>ɰƒ>í2ì=)*á>J¾=h§¾°Dj¾¨:>mcÚ=Šª¼­äÏ=æ2‰¾aç­»àLè=‰Ê–¾Í’A=zk²>Þ)˜¾=Ä�½|Ê1>ROŠ>F,%>ɾÉT=*>2ˆh=NpŸ¾wßi>Óh’> �¾ ɽš¾z"¤¾…§œ>t.§>3$ó¾áD¾`w>¾Ý>eªØ<˜ä|½q Y>Y7)¾¬�¢>¡�>EmK<Ïû¼d"±>#Z�>¤z0>$6F>Ú/¾NÁµ=ûÕ ¾‰àF¾åâª>û 7>&îD¾±z!½ª£T¾ôœà¾4yœ½ôt¾Þk“>"b¾%Š>@aÙ½j�°¾÷̈½l¦[½¦y&=¸‘ä½:Á�¾Æ– ¿Ä÷¯>õ+@¿Ið>`yоrvj¾·jT>¡%é=Q©¡¼:H†½Ö2r>ºOÀ=êÉk<¥Ùà=ã;¾^‡¶=ñ †½ ¿M¸½f�6¾OO\>q؉½Zj¡¾¨+å¾Ù‰¾K†¾Á>….L¼Ü䈽( Á=ç�νW¨t‰>¹?7¾<¦@< K˾ªŽÒ=b ½ý{ß<…™<†´>>X‘=Ñ >5j¦½³Ùž=-šž=Z>6¾’8«>zc¶½Ÿ~á¼¹#ù½~m�>nΤ½–$c>„,½3¥»ÀÛ”=xi1½3f3>@ßϽµ‰?V‡%¾@™¡=üýÙ¼ x;>ˆé‡½>å”¾å† ¾jæ…<%' =�½¾\J¾”x>½ðd5>/p<„>¬/½¿¤¾n1¤=î2Û¾^…›¾:èe¾’9>ääÖ½ZÄ(¾»Æ= øi¾ãî.½šÈï½b„J>ÈKý½NñŽø(=½Á=w=¯ë= �>±Š-¾�Âñ> ö;¼»EÙ½ðB`=,cľ‘V¾ø²×¾,Êá¼ÃPÿ¾Ÿí$¿èâ¿ø6=�"°<{–>7è=: Q¾‰¹ê=s V¾Q%¾ :>ä·"=V`¯½q± ¾pF]>ìr:=n%Ì>§` ¾/1¼pì=¾—³`½oÌ?¾u=>J¿¼=^CC¼ªß=üMc¾’S>þ ³»‹A¼ÿ�=ȶٽ¼Öj½ 丽‹ƒ:>£_z¾üp¾³ö*>-A¾½U‹]>:<{>0NX½%S>ƒAH=Ø5>÷×<™/ƒ¾hcŒ¾äæD=¹2¬>^TD=a,=ÙaE<¸B>p•?Ã*‰=ý*¼´’}>Ë=ËË1>XO¾Q+¾=™ÙÊ<;¬½A2Y>G¦·½%mÛ¼øëG½sæ/>óûm=¿±½=úžb>PÜä=Òq¾_É�¾6¾½yë> ’Q½«j»äV>"øã½$•”¾£ù`¼+»x¾{ðr>¯ŽL½Î½J¾ü_¾«k‹¾[è>o�Ç=�޼¾Ö…½fC½gì>fÊ:¾å�"¾o¸l>I.b=úV�=¾]¿Nkp=Â>ê=|’¾~ú¬>™€ª¾ÿv©¾ð»¾;¯¾PŠ~>š›˜¾Ócd½·üv¾’ ô¾RŽš>õW¾¥O.¼«ª½:y®=Õyz>pu‘½þeˆ=—ܾã÷.¾0eF>ì ¾á ¹»@×í=ýýs¾ãC(½â$�¼á.ý½%¼=lÇ€¾/`”¾æ·­¾àèú=Å׆¾Ú½X>¹b™€ü»cR÷¾si\½qÒ½`Ú’=�âê>–??>tÝ >iá©=•y½F®<Âìã>é·ñ>s†¾Ó Å>_%,>÷è<Ý›½J_L>Ü6d> «Ú¾A½k¯¾ÿœR>[à?]ÕT=ÌhÁ=Y¨G½D†�<‚íÊ=ãrp>òßâ½%JA¾œµ¾¡´)¼¨” ¾·>ú=Zо…ž¾#ÉR>�Ö¸=€¥Œ=¤Ø™¾¼­Ž¾Æ}>\›¥½o<û½6[H¼!`£>wG—=VÁĽE”¿¦„¾á_³¼üÜ;ó¥’¾‡¹5>㎙yæ=¯g#>E)Í>Ê•ø=©�á>ó=æ8´>àw>1ù#¾[WR>ú‹¾®P³¾Ütn¾Ñ=p©r>·Ï>Ÿ>Ú[�¼6gN=Ïct½ɽäXä=Mƒœ¾‡J;>—¨½—M¾ñŠm¾™ >Äd»Ý˽j;ÉV>�è·¾bâ¦>è¼ýF°<ô¬ä=”3¾j>Å÷í¾øXH¾$«n½_ò½ x=ÿT†¾ƒ+ú>ò'9>VO‘>½8­½ìEl>`,‘¾!:ç>½r×¾¾Ž=.…½û•¬¾#½z¨>Eש=g¤¾ì[B¾Kh¯½†”3;Е%>L.Œ>•i_¾»Á?ÊŒ¼9<…½kØ>µ¡,>œ@>êÍ,¿KU]½ìø¾Šæâ=Ÿó±¾Iel>àƒÔ>Boݾ‰«<åJ>¥íù=ê">Í¥>ý ˜¾¹�>5Òh=úZ">âþ>í7‚½µ'’>“">N\�=áÓz¾�a2>xøý½©Êó½l%9™wK¾y ¡¾ž^Ø<’k®¾L}ü=g‰ß¼ Èš>”>JªW>îÈ>Ú–�¾¡O½ÐM÷½d‹Ð½¬CÊ=³=Ãxÿ=Vìz¾d©i>UÎèåo ¾*žZ¾@—=ê1e¾v†š>JxX½˜ƒª½Ýò½Øó…>öë@¾+@á½U 5?Ú ¾Õ|=¨u >Y0=½¢Ê©¾�¹ø½À¼Ý¾7¼1¾#’þ½ÎŒƒ>;Þ>RÍ~½”²b> Äã½¾õÖ>ŸÒ±½èÐâ¼D;?*i‰<=§<¾‘©?¾ ‚'½Ã5³>Cü9FÖ=¯½Q:—>99@¾};C>„ÌŒ¾Â°¾Êþ¨½žŸo¾þ>h>Îù-¿*Ì=X~>¾¨a¼½Vsƒ»R(B>—Â`¾F ä<`¹ ¾ðWò>C�Ô=¾ÁR<½Í¢Ú½t?H>7â >Õ´œ=Àz(?h¯2¾@si¾}JƽÇca=KFÎ;–ƒ¾ô+̽{.½½[|7>œ®=_°}><Ç;=�Z?>³¨¿Bà^>¯z½ÐÁ¬¾†Y½ÇLÏ=s™¼,""=�±¿<=ù½ù[{¾7 ¾Õ»>b ½ë“½tžµ>´r½›É>æ;½�;¾E(># J¾ü=ý>cÔ§¾G~¿¾ Ü>œ¶®=£Í=¬´Š¾é¾>{vó¾Ž}æ<”óÿˆ·L>ÈSš=™øÓ=ì¿>ûØ$>™8¾oãQ½˜?¼âï½àþî>@Îþ>‘�º>7ù4¾Lʇ>ѽ­¾é¸ƒ=[Ýp½¤DJ¾r5ß>´W¾æz÷½žÓ½íc¬½k)Ó¾„‡ >Ú½ ¿Þ…i¾¦èÄ>><þ½)$Ľ¨�/=~µò¾·ŽÜ>Çá¡<»Ñ=½h€=¿]W¾«„S>f¼¶ì¾}�î¾õh ¾f>Œ6³¾*&�>ÓºÓ=ÞâO>ö€>-‹M¾1.Ð<Ò0¾+‘¾²oè½»Ë<>æ5 ¿M9½ÅÄâ=Cˆw¾ÂŠž¾"¬ ½˜Y=Ìfº=1ZÔ>CJ0¾BÎ&¾àñ‚¾ÔV×½¹nº÷ÜU½Ji‚>Hm=vÅ ¾÷Ÿó¼“' ½È‘ >ˆBྗMÚ½¤2>)×¾E?ßåÌ;(«×>m H¾|Íä½н(>°>— ½9ÔÁ½Wu¾+?#=³‚Ç>Ÿì/¾EÖ…½—ê²=Žvp¾l'P>É+@¿ïÄJ½"-Œ>mH ¾qä…½�}¾FQw¼‹>p@¾°=ë=“=C©­¼W€½œ¯=Äã¾ åO¾Ð¨‡½îëÉ>=Ò„>_ >{ˆ-¾†‹>Eã½Ä¿¾bŒÄ>©¼µ½ýÇ>¼ñŽ;Ì ù>Qê¦<Ù¡„¾ Aã;êØ?{>A={@>+ˬ¾ÓÝž>N­™=‡Dˆ>]Á=V%»!�>iþɾg„¼µJ¿3@Â>ÄF¾b ½°z|¾',¾1}¶½s‹©>‰äÖ= âö¼²k¿½{ˆ> Å<5’‹=(GÕ=*�¾£å–»ƒ�´>"Éj>I¾•Ë3¾ëÜd=ÿ§¦=‘Üü>íÆ ?ã¸H<÷ Ê=².'¾‹Ô >‚aK¾‰^M>è±½8¾î¼~ 2>Ðò?·z¿>q,u=F9‰½|D=� ¾!˜=È`<©ßI=úD3¾ã=Ñ á>q5*½YÓ­¾FϽõÎ ¾8¶=¿;>:šö½÷„½¾§�-¿³ì½î¸½Àºb>‡.J=ë­°>¸?HÌŒ½6V̽Œ.�>W¿r¿;»m'¾Z"¾S–¾íª>›¨C=5â²½þ¿á ˆ¾M¤8>Ûð‚»§a>©\”¾,i>ƒ€[¾"þõ¾®'ÿ¹a9­=§Y=]%¾Çо“šâ=ÆžË=²ú-<‡g…=|Ÿ¾Üé‘>ÉDg¾Ê²>Æ‘�=Òü>aꆾ*ǾaéF>úá=0“x<Š*D>)?¾@t޽¼{¾Êˆ}¾6:w»£ á>@”=P’²=!¬¸>”<�L½ %û>´+ ¾¸ 9>Ãô=Ü?+¾u $¾nϽ'õ½�[¾>J=À¾8¯= Ýž½H&=1è½áÕÇ<Œrý=Q…о»„¼fk?=oU>o�?¼ó¯Û¾¡E"¾ñÝ(>vË«>J*?\Y'½̨¾¼bk¾x}XºkŘ=I¡yºQ.`ëˆ:;Ìå¾ø!¤¾:">›æ)½:~>›ãó>œ7¾V%/>Ÿ`p½×u�>^£¿¼žì;°¬‚>üE>-ï >åý<ÌÅ(>Їš¾;€�½€ŠŽ=²z°= ¥¾Å¬L¾c½ª>ûÿ¦¼‰ºZ½+Œ�<ñ~z>&X>ü¼a¾ç¬Ö>­¶c½Cµø> 8°> m¾|"¾IV˜¾vè=½•…n; K€¾ø+=é’n>òæÛ¾OGd<¦¿½Ñ˜4¾>;¾žx=¾ªYó>�J>&²Å¼zäC¾ì ‰>³)¿ê£ú¾5g¿>¹[7>òrÁ=½µœ>óT¾  *¾²Ps>¨ü¾õ(½Â–M>Ó=­¾Á¾ˆ•Ï<˜Sê½èÖ½:>AœD¾iMu¾‚&è½,âG>=,'>&Ä»6Œ»= F˜½Fã¹>ܾiúý3­s¾’ä&¾(óý½<‘€½üà=Ctt¾Ýx1¾®5/½Øæ÷=òæÔ=ÉFè¼ÊL ¾.ÜÉ>>µf¾ý’ξ꘶çF*¾;›°>DŽ=Çî.>$³ð> =|>f‡¾^¹>ÄÞœ¾özŸ½ý=˜> 6†º·Þ >åý>¢Ï½ Y¾,.e¾äõ÷>ì Z=3´½í]Ý>ùµ¹>§×�=nêˆ>Ÿ½/¯�¾ Þ¡¼ ä}=ÆG>†R¼Ýa¾¹¥V¾Ü+�¢ 8¾Òy½½*-,=3yf¾¸Ï1¾¤=¿º>.6§>�u<¾BƒŸ=¢ñ×>zuŽ»Š]ʾB¶†½C!¾6l¾‘Kô¾P¶>Ç€åÊ|r½�Jƒ¾Èvᾟz¼kR<=çÕ½ F±>õl;½´¾`¬…z9¾ ‡V>‡ˆ‘¼>Hæ=ô¬Ú»7˽Œmý¾Ù‡½õ¥”Â�.;ÿ§}¼*¨ >yÛl>"M<>ò¯ª¾eÅ(¾wr½ýÁB>¶">Ä”ú=D >E‰¼&Õ¾'� ¾+[?PIY»6 >Vw×=7Û?½æ¹¼1Óœ>éý¾¬&m½ç¤)<ªýÿÊ‘½‚´u>õÛ?½™µ>ÜÌ)>N_>üzG>:zý=+?59 91ʽµö^>^�>i«T¿ZÍ“¾™›>¯xå>uh‹¾£o°½©Óν#5¥=䯾¬:¾-Åš>/'Ê=ºÉH>–mò>3>§<º²=Àºg=}.6=ré|¾yUW;‰ž¾Æ½«¼ï¶Ë¾.}>~ê¾@&¿/oQ=yu,>ˆ¾ÎÒO>»»¦=DŠÙ>¸üµ=âÎ_¾ý(¾æ,¡¾šð>6]»;[7‹¾ãȤ>1=Â=þ¾!¦½û>«Žº;q~¾—„¾s7ˆ½��j>(÷ >òû#¾ð:->͉/>¿ú)=AÈØ¾!gµ>‘ǘ>ì[­=ö*Ê;4ý¾4œå¾¤€¾KF…>ÂÒk>¬hk¾uë¾ã�ê=d¬ˆ=¶HÞ=ࡾ„•€>fé¾€_оmRe>ˆ©�½g¾iZV¾_ؽ§Y¾FóÆ>J >˜Ô+>2's>>{0¾ÃŠÝ¾ªw½t_½;¾g½70·¾U½¬xZ>#×Q¾ý‹·¼Ka�¼÷Åf>"ï¾I�b¼æ;¿»:Ͻ#We¾1Ÿ�>N%:½MÌU¾ ßB¾öžB¿˜ÏU>z/¾Êå½´Ý•>ꌾ8¼Ý¼ Ìò>õN>ªÏ!½¼‚E>޾ë½ÛˆÉ;9T=�Ø-½˜Í©¾ã8T¾¥j&>e.(>˜Y>ÛÇ€=Yêã=¿±5>󌾸€^>Ø`s>Î"g=()Ö=ù½&Iá¼Õ¾EJK¾ ¯ç¾˜õL¾â‰•=MïŠ>¶Ùy¾éËæ¾Î��¼z ½u°¡>Åþ>13V>“}—¾["¡>zÚþ€r>ëHö½„Tp=£Ü?Á‚<¦€´¾XÀ5½&¨¾>�n¾b�^>QU>ÐI¶¾Óo>¼š9ÿ½�.޾¬õ@>1F'>jF=*&ˆ¾Yh>S¨è¾r¶‰¼ø°Œ>ϟʾ3T@>Âá >Þjª=жý½ÿjø½ õˆ>5E@>% †=x;Ÿ¾;»Æ>eÔ€=˜Ã½õ5å½Ý3¬¾ß›ºV +¾tx½Ý …<£ž?dL¥=ó¸¢;z©>8¾„¸”=F }¾L{”¾Ô«¾™)2>¶�˜>¹…¾þk>/“½Œšl>u9�>BE¾vžŽ>x»<°K½¾Ÿ>6·ˆ¾^ØT>'h>H~޽Ån�¾hb?¾OÑ&¾A(¾Eùõ=ê'>ÃRF¾0†:.9?3"¸=¿ô=ò·€=˜U7=BÕh>o©Ä¾ïY¾C¤Í½É/>¶>�]ê½K5¾Gp›¾ßÛþ¾@xz¾$XE=jlÒ½ëo¾Àf >î²¾½à³½œÂ>Ÿú”=[`‹>®·½¸`>6}Æ¾Ž“8¿h†8¾3Óö½—: ½•p?04Ⱦ¿«¾Se¾=ß½½ìÞ=c$>a眾+ŽU¾l,í=н鑾8ËF<ÒÉo½<5x½°Ú½Õ”C=_º ¾3)Ý==B½ £x¾ >–<«—½¹Âˆ>‡¦>¾|÷¼:`›>G°ˆ½ÔhR¾GË >t©\>Άæ¾ì�w¾lµZ>v¯Ï½kŸ½<ÝÉ<¯™¼~åœ=¦Â>¼tú>ê*R>÷†ò½!о{ËW¾;Ͼ¾øA=ÔÔ1>ö»Ö¼™Š½8$>�jE>ô·—<ìÒý½¡j�¾�0)¾° —<,¢U>Ûý,>W¾¢h®>wôÕ=ahO½0§E¾ñÍâ>…0–=× D>‰.�½$jŠ=Â1¾Ý4?Ɠܾì&±=²ø�½!‡.?å6?”Uؽ”H–¾ d†¾Øº=½H"¾³\>©�¨=N�=ÝØ ½Çu‡>Ñ<”¾’/>Vþ¯¾ÅÛ>�¬y>E1&>Sæâ=™4Î>ˆÜ ¼!o"?Zïƒ=Å>‚s>¢ž¾Éc½+X‚½©óü½x̦>¼òŸ>[ E½Ñú>ѹ¦½ø”1¾6>¾>>õ>1¡ ¾]”µ¾ß$¾e¿@<á»�½tÉ×½y…¢¼ÀLÑ>¹Ø?7N¾�>Ï ¥¾ú x½ b,½� Ö¾¤×<ïãÍ>Üæj¾Bè2>О¾tö,;‰qνª>í8¡= �=×ÇQ½°Åp>ÅeL¾¾ú7>è†î=‘{=×*þ®³>Ð{X¾~¾&¿¾•ÈÀ>,1¦>ºŠ£<ü o=г²>Ìí¾g¼‡=Ýë>Oº™½Ó‰C>’X7>¹–‡=ÊûÒ=^ò€>ð`?¥µ> x¾'?¤>E(¸¾¥æ>%z¾üÊ~¾¨#‡½z�¬=@ç©=îò8P=âøÛ¼ÉžK>Lù½Œs·>î­–=õË›;ºÕ½öLÖ¾rØ;¡6¾>ùÅÅ<·=ÎÔ=êü�>6Åܽ\]‘½Œß½:Þ=Û>ן>˜³¾²ïº¾a—Ü<¸,=Š�û½‰rù=kÉá¾sZ�=Yç�¾É(á»`Ò=5|K¿Ô+ë>»>û½e’]>ªɾMÂÖ>œ-¦>`Õf¾Ìྡྷ?D¾O9h¾BÕû½s*=J‹t¾IŽ¿,Œ¾^©P>yK4=ICm¼Rö½yŒ>< gN?¯íB¾c^ó½âla>Z鸽HBÍ>ý?)&"½*½Ã͉¾“Ò'¾QÁƒ=¬så>Ò‰¾Sb'>’2†¾'£¯¾š©`¾òøU=CSM¾Ky¥<á>?‡‹7¾pƒ]>·¾êŠ�>¶›¯¾¤#¥¾£—>'o½ @Ü<÷ˆ¾ò‰>"Už¥=ˆ¾@÷o>…Oµ¾Ì‹m= ‘s½Ô¹c<ˆ›œ¾Œνq}<� ¾úë{=e^©¾í™¿/S�=…޲<‰ƒÏ>:?_â½>œ=�=ä>›¾”I�>�‘o>ÿ<Æ=Çvç> K =óà>½·—½µw¿L¨=OcD>³¤d>ˆPË>­=>û„¾RHF¼Ÿóå=?š•½LS„¾ª>O>�‡X=U •½š"`=_’ ?¾þÌ=Q®.¾8H¾{+¾¬Œ@=ݾ헾sÐ>²�¾¡¿›%t>ˆø’¾æÔ=XŒ:Üõ#½¯Cã¾|5²;hš?ÿ›¼8‹¯=^ #¾,Œ“=wGP¾Ò,n½/Ó²>ïnh=úŒ�¾b–L¾©Ç˜>gQñ½ ‚¾YØ¢> O<—Î;ðÝ|>¦Ÿ”¾³Ø-¾\š¾wÁ!?CM¾=qeJ¾¯ì~¾yÕú>*;‰¾°û†¾²A›¼¨2d¾Z¾èt>6T{¾zŒM>Ÿª5½0Œa>_È_¾ ²>KCŸ<—Žn=d¿* Ã>ÊGÒ¾H\¥¾"Œ¾×7q¾©Ùd½{j»>yòP<¦‹ü=A”Ø>˜E¼k¿:¾ –n>Ùùƒ=#ÚÔ>8^›¾U»·¾âkb>´§¾ñuɾñš÷>Ì–©»®Né=çÖ¾ Õ©½%“>)H)¿× ¼Î’¾ºmŒ½6ƒ >6't=Zô¾)Ü=Æ¢Ë>3EÖ½Î?­S”½Þ3^½ œ¼Š>· ®> ˜8¾‰"í¾ZoJ¾z°U¼Ä B>Š U>—Ÿ¾>OÀº¦d×>Š8m¾÷Kþ=ž ¿¾Q¿é€ñ¾Â:‹½æÔ7½ƒN¢>8Œ=/�¿]þ%¾‘sc>š6$>оÜX–=—5¾aì~>`0Š>ô‡¤¾[c‡>âV”>E鼌ཬƒØ½F%̽¹¾¢•]½¤>ÑÄ>“½Nì¿$Gº¼8Ür=APÜ<éô¿´ãR¾t8­=é�–¾jd>¹»>*7o=ÿ?¿Ú’=%Ü㎎¢½œðd>¡¨> ×´>Ò6™>°Õ¿½ˆ#¾`K³<Âb‰¼M™¾�G±½±¤>0ÁB>åÇÜ<ºæ5>TÕÉ>óÄG½-ô=¦y‚¾m­½YaH>�¹¶¾ù$õ>/å ¼©B‡½ïN¾½ j¥<«Úw½¾ù¿È¾öÇ>៾“¿7>Q“Y¾¸5 ¾¤ú>ˆh¾Yê ¿ƒ,“>æäA>ÿ�y>B%U>(=/!™¾V¹½=9Ý)¾i½r Ë=ª&a='>£ç >ÈC9¾TÔ¾÷ׯ>üÒO¾ò¹¾/Ú= cr½¥‰×>ø§Â¾¥x¾½%—¾ì&">ô+{¾´Jû¾a3;¾ß£S½t³V¾)´`½HØÅ>j^¦>W¡I=vÊý¼²ÔN>Ã4ü=Ì5™=øfê>ò�¾ï¤â¾à¡‚½Ž;`>¾è˜¾�s�¾…›m¾ËèºÁ ¾” n>³w¼è ‘=ôC¿×¨v¾Çù�½��¹=áPA?{ǰ¾ÆðO;ëÀ½¾��¾˜"Ë>†œ>KçN>ü)R¾äNÌ<¤ø>A è½èCF½ç„†¼°ý…¾¸²K¾ç›$>yoý½§à ¿qê�>ZÉÓ½÷Dã>FÎì>RÓ=3)�;št=ÏŠ=ÜоÝ3>§¿×迼,åp>³F�¾ì J¿Ÿ•н²¡J¾QÐ>¶¸Ì½[h\¾€ž2¾ÕX$¾]S¾)n>‡è·¾Ë è»Q4¼<ÊÄw¼gãÀ=Èè×¾OLø¾?]>›P¾ ’¼éîw¼¨^½£g¾{üÓ¾Ýk>:޽¸©7¾h««>7>0ê/>Ó—¿ØP¼:8I>hÒ=Óû�¾µ;%¾nsn=^H”¾€"·>uZ¾øÕ|>p¥À=c¡¾Õ�Ó=B”=£¿£>Qû¼îò >*ú >nÁê½IS«=^´‹¾VGñ='Ô@> ^>&æ'¾9 >rÒ¶¾×`Œ½73¾  >nî=\ˆs=QØÕ½Ii ?`æe<µ F>ZJ¯½ÊT¨=æ�½ñ蓾ÎÇš= 3�=GÀ½¾:.=j }< #�<Ç‹ =’Ò^>G]U>Ž8¾ho�=�`J¾¹©¾ƒæx½?k¿>cr¤>^Êî¾}ÿr=ªRö¾6ˆQ¾ŸÈ¡B: ¾ýþú>_?fûs½Œh·>^–:jLÙ¼¥î¥=«gá¾(Â>œŸ=镾=OSͽNU½M™Ã= \>†ì=`r<Õ ±½�î€=~ý6>Ž×í=Uξçø=•ó=9‰M>wiÕ¾Ö]¿D)@?D1e=7/¾¾•R¾p ³=r;©>÷>®=ð~¢½a‰Æ=y&><Ø9¼†­>| ×<ê½â™ �>ãѼ0\'¿v[ñ>W*º=T:>g¿t¾+)T=x󾌟ã=mõ‹½*톽çv0?û¼J=N̾¿\p=Éôh>/»=©‡&>Ü=ûØ>»Ç½HÄÈ=‡^H¾0¾»ï|¾ˆO~½'оDÍ<½»½Še¾(ãí½Dc�>7è�:ÌÉÎ=E(¹¼õxT½âx¥=ªæÇ¼‰]¥½î8´¡=¤ñƼnƒ¾þ J½®]=>¾À=a·ø¼¦®*>úºü>ÿb¼¾#£½³Þ\> 7½¤Ù= qä¾ U>Þ¼_>øý—5¾¦³Ö¾'–û<ÕÕB>46Œ¾-žy=¤p<:ϼ¸¡½+Tœ¾*#Û¾*>6< =y«}½Ži>Ý'~½Á0=¬¨º¾Nz>1ÖÀ=®U;>î£S½È°l>F�‡<ê\™½Ð&ý=r¼Ì>X°‚;úFõ>€B>xz ¾•¢B>0/˜>öU½_çz=b ©½B–=$äÍ=&ÿ½[é">�޾V�Ï=^3Ë>UA=&Û�=�DǼSK>h\>Ńƒ¾T>á)µ;¨¬“¼3®„>HV·>q-%¾Ð¬~>¾h>²{/<¶¾·gR>Ÿ‘¼½äé꾎ñN¾ÈG>¹¼?Jù±<(¼½. ¾œc‘¾xDà¾&{»¹|!>>v¾{ ö½Z )¾Ùl?hâ>Î5¾½•˜½P;c>?Ð?æÈ'½`‚>Û/ô»-Œ¼<Þ)>ᱬ>z~A½öS¨¾’⩾o$ö>�u >|á¬>w³l=(d-½A³)¾ìD9¾¦ÈŸ½ÜƇ¾?uù½^«Ô>>¾*Ë�>GÓK¾Â>³*>4gU¾>/¹½1‘¾Ù•>‡ó >0î6=g›M>Bjt½™zè½:U›=üM->æ×>¸÷�¾¢D ½÷4‡=oº`>Àð2½n@½éL>ÒãÛ¾Aeb¾ø:L½z"ݽþà>»{ê¾Ù 4½$ä£>2®»¼&�¾Œ{ç=œs¹½—§³¾¡V—¾ò®¨>©²=6@-;}¯’>¯ñ?ºž½¾`g¿Bð>÷‹>�Vc¼wÙž=ÂÏÓÿà¨>\çu>“¦�= ûô¼õÓ�=¥@<>/ƒ>0¹/¾žä§¾÷ �=ïó(¿‘'>³Vˆ¾�‹½Ï1ÿ>-y>p®8?ÅáW;¼6?¦+~¾ó’>8^¾×ák¾9>Šó½íòþ=øDÃ=Æó½öLɾÊG»¾AM¯¼Bj¨>E¿H¿›½ ¡Í=š2Þ½ =>¾ ƒ>€V¾eèH>q+Ö¾ý˜´<ï¸-½ùçÍ;š >´[Y¾]€l=`sÙ¾`ת¾m¸÷½Ê­>ã!¾Ó–%>‹öz=¹AZ>*Z®½s®¦>3ϾŠä>ê– =ýKȾMo²¾>—*½Œ €½piK>Òò¾(@w%¿±ôÇ=:à̾<Ÿ½>Ç¡Q>Oò‚»2Çè§„§½þê¿F¾a¹>¿OÄè»Ðؽi8¿=NãѼ)ˆ¾�ºz¾F?2½¢«•¾6hÑ=�u�©:2¿á\�=fMB=*Ø¿ß3Ç=ñŠ»;¦I¦;§¯ì»~Ãó>àB›¾ÂѸ>¯a)>q‡¾e½C‘Þ¼ iÊ=!Èú=>÷²¾cÝ >^�8¿¾É‡½‚“˜>Uc77ºð<µ=Á€W¾jiœ=ÄØN>¿VN=ˆ´h¾çg¡>å;2>+³J=J?ä>ñÙ� >Úuֽɘ¾Wk¾â})>íu¾e¾#¾ë�(¾L}À¾7’>Àê%½Ûè�½›½8»C²=c^¬;è¡•¾�¡=÷.5=+*à½ïS*>Ê ß>Õ%~>ÐÚ³¾Þ´Ç¾Œµ1=²Â¡wdÛ¾÷à2<Ã�¾´‹>¾zF½×r{=ÏþH<¿­”>„t6¾d/·=¤×S½k]+¿NSW –½Ì�ã>›Ö«¾8 £¾Ká3¾¿ >0ç>!�¯=à5¼¾¢‹Æ=ž\—¾~óC>'J?ýÑ=+&›¾àþÁ½ `j½BQT¾q£¾^Ùʼú+>´缚¬Ë¾ .X¼ F²> _r½‚•‰>*y!>eñq¾í>TG=5Œ<œÌ[½Ç¹H¾*ù.¼rÆÎ=p�ö¾Áâ=ô§Þ½Ÿî…>­:ö½P3´>YOʽsÆë¾|�±¾p >A¾™V~>+±‚>Ò°U>zd‡> ‹‘<Á4>̲›¾äÍù½¨Õ¾a°Ö=wÿ•»6 >#H>NÒ=ù§8½0wÖ»‹G½¾ ƒ{>øÝ%¾ò7¾�™Ø=&zœ>ÀæQ¾à´:=s‘>ÌKD;$]à=öû>ÆÅ›½Ú5²¾t&“=0s¾Pz•>QÉï=c2¾Gýt½¿iè¾J÷÷=®Ô½uN‚=Ô‚¾«ß½¿¡½“½ŸL>�òÓ¾ÔE}=Vw >#…Î<C°¾©€>ù€™>j»½�ñ'¾Š±Ü=Žgã>¬‰½Y®=\à¾>}ßâ¾ÔG¾`·>d¢q>io%½öù½™pÚ½[âÛ>O@> Ö½u I¾¯‡Õ½Œk¼>¼ôÝ>Ág„>Árn¾otz½õϤ½gKG¾ €X=Þh•¼«ÿå>y…>A¾Ž¸ø¼8äÖ>L½q?�>v¹N>Évp¼%�ýº•æÆ½ûV>Z�>Ø­Ñ<˜�þ½½Øo=xS¾û¼¾ÈŽñ¾±Û¥¾~¾é|8>’Dµ=1çϽ7¼½ùå†>Scå½bò»=©3>«‡ =¦!¿í È=6ËϽfÀ?8u‹>¿ÖE>†¾Šx ½G¿= %¾•Â\½õ!E¾@t¾³s!>ÃWÄ>á§¿¼Ê=ÄM>ý‘™¾§pÿ> Þ–½ã{Ú>îó¨>¤±»%rÙ¾Pˆ¼>ˆé¾ŸXÏ<ó½û”©=–Ey½<+ß= {y>eóÅ>äξ˜"‚¾„V¡¾=‹¤>]u\>îÊ.>´=ê>ë(½~4»¾zès¾‹î¾VÈÐ=O>S+¼’L½Õ·—•mª¾x+½£¯=U"¿¾)À‡¾yP ¿µ©ï½ºë"=O:¿”B¦=0M£=—¢É¾õ ?>’a½>ø>µq¾n;ʼ‘¾C—W>–¡ä¾`Fø=¯l¸>~Ú<…‡>{à\¾ãmá½`”¾.ü9½^cÀ¾øo—>•ý¹¾©½ð¼ä'ʼ|ZY>EŸ=·'Ñ=¶p¥<œ(•¾Ÿ_¾4’š> ?ÞKñ»^þz¾|N�¾8©[>‹ä%½�7>#ü==Hi¾Rsu>I·û»èÉE?œéò=�ÉŠ>ªÁ÷¾¶×”>ݨ>ðݽ{õ5;*Î=°P™>^<'>”Yª=NEà>š®ž<"žs¾>e>æƒ$¾±>ßÒ‚>»gC½~»r>û¬¾Ë u>Î.…½»û ¿Ê�/¾\ �¼b£@=!¢¾�qN>²Mj>2ß|=tXwT¾Ó`È=Þâ<ë{Ô¾ª›r>oL¿>ÖÓv¾7> ‚=Ëÿ>fx9>m>ßC¼<3¾°¾«!?̽ξáÈ;hYó¹ÍC�¾âú3¾ÓŸÉ¾«dÞ>„…ï¾2>v>øiÒ=y >3òÔ=º# ¾³*»>»½”¼Ì³œ½‰Š[¿Ç|€¾e>©¿ô=>„\>š»ý=Á ž¾‚�j¾\3…=„eg>s2ø"Œ ½jIœ>:—n¾šEb>œN¾Ñy0>%\ƒ¾•²’;µØ¢¾PZƒ¾@oѾ 9¾ÌÇã½BL;Á ½ÛO[=DH‹¾N†~>hc¾1¤C>Áœ>§g—¾¦>w=´ú’½ïB=ö §¾Üxݾ&ƒû½Ά¾ _º¾}gÜ=gQ³¾á¾U>Ø]ƒ¾°Ïa¼0>½ä\¦>ÿJ>öÚ/=ï¹0>á~q>rá9>‹üŸ¾z¥‘<]Ñ=zÿ=‹í=l�>‹„? óĽr`ž>LÀD½€\à=“w«=­a¢=&¨¾º·8:V2¾Èx|=Li¸½ »ð¾è¾éœ®½™R¾ãVë>SÄÄ><5“¼Ñ­¿ÏB¿În>zº^=ŽWä>B[™>ì`޾�ùj¾Ê,º½%›š¾†2'¿¡ä˾‹V>#¨½ö>¾éƒ0?dUF=œwð=Ø»B¾+»™>Ñè=�V¼mm>ëg¾Ž…>+±ù½­¿6¾2uŒ>X×Û½æoo>t�¾\Û·¼vä€>RÁ.¾‹9ð½>.‰¾Dʽ¼ñ€‰¾)š¹=ó‡�¾ÿe¾¼P>/×{=6Ž>ù·°>³J>>ï©=„¾{—Ð<-;$Г><о:™U¾‡2ž>á-¼�QY½"晾•¹_¾½ð=f`Ì>ÀѼ”\H½;~*½�ì:=ó�¾t{±¾X%€>-ʾÛï¾µ»=•R¼=ø$8¾ß¿ø>r޾éÐ�¾¤”¼Þ‚’¾ãqÿ>+ ¿ªñÞ¾chš½Z5¾q S>þ">!9q>á :¾–ϽۄÉ=Î|¾­:><4½>� Ò½(Ðû¾/"w½y%Ò¾m4�¾—Íû½°òé=Ôqë=:í­>s¸¾�ƒì½”×Ñ>G7¾ºD¿›h;¾[½š¾_‹¾Ø$=:[c=ñÔh=î-þ>M¦3®®ù¾>?q¢¾Œé½æÇ�>¼¬•>Ðô=ané<Ú'¼”–²½Jw�<غ ¾S\$>;ÃP>g\>TGç¬K <8L°¾•$ñ>—C¾�ºn=¤ƒm¾¥¼>¾( ¾$**=å»{½÷‡¾ô&½»Hs¾ÁоðL9¾#O?=¥·?ÏÚ&¼W Í¾âl ½ežŸ=3Î>‡$º=5ð?Ó(v>ˆ2w=±vr>Úþ¿Ù³>u �¾he%?vêr½o͸>Ý Y¾ÜC‡¾"ó”¾k}í;ZFæ¾dn¾ûö»½¿)޾[,¾Ÿ¸¿ò=Ž+T=Å“‚=øç¾ÿÃ>‘xÚ½"U¿Ž=9>*è:¢i³¾‚5>ªƒÔ½j/L>þ¿ ?§¶¾ô.Ÿ>¾C‰½Ãñ’½8€¾²¹¾P÷½h3½YF½Rï›>ºè8?Ó„¾ð>žØÿ¼ŠUí=ºì‘½åmú¾DÂ>‡·`>yù=´+ž¾tÔ>;`±¾°û-¾:×s<&œ¾ÖIU=:¦ð>´*¾8Ôô=gó\½ànô½¨¿ÛBÛ½µÁ¾=EšL½Ú³þ>y­�>åµ¼<±=ßs= ¾öÊ >6 >Þ v>ç&˜>˜²>%]º½"Ž|>"¼óF¾˜b>íl¾–0ü'˜¤>®&>y"�>Ÿ9¾×kc>æ%t¾4x§>ß0H=_†½Ú?ç™>|®^>ôâξ˜#Gºx¾`¥<Îχ¾†¶ÿ½X�•=\2�>3ˆ=U—꽩ñ0=ll¾;’ê½æ ¾2wk¾Py];SPÆ>=ó½�r/<&·æ>`ò¼>b•P>å³Í>þ,�>HF¾’¾üÛM¾b)¾¿ˆt¾kÑb=Á?“´™Dc)¾ip½úý<¿’¾T¼½=&=D²Œ½Q è¼i›J<\ã¼8¹T>ô^¯¾„× >`Žˆ<_S¾Ù ?b’3¾U €>"+œ=Þèf»‚Á¾ÎG¬¾5¼#<žŽ¾'˜û>4y—>¹<¿½ÚsI¾6Õ£¼�š>93‡=wÜÊ=óʽ¿‚Á¾BݾâŸÈ¾Â�f¾¶¨û=tïM\¢š=¤�W¾ñM•>µƒ¸œö˜>þÙØ>tŒR>'˜¾Ûfͽ¹Ã•½÷®Ÿ=S‡¾¿ï×>Ô‰7=þËâ½A�*¾üxå>ƒÀ>‚~;2X(¿Ô¿‹É’>ª·\= ?¼æ!¾ª߽鋄>ÓP‹>–¬A>4¶ê>–W‚¾“°>|I+¾w>y™É½l„Â>úmO¾¼«P¾«ä>ïLǾåÔ>Ü:�>øÖ¬<:2¾¿–>¾b;c>½z‰¾m>q¾>ج<½›>&Ÿ¿¾Hfæ<'¾8æý=EBÍ>ÏêѽEñ>:ÝÕ¾¼™—z»¾ÔÅo¾¾]m=Žw>Õ¢ç½rZ´½…>J¾~– >+=�=œ(ˆ½mb+¿ªKg½Àîß½GNœ¾‹ý >‘ „>ÁïѾæÐ)¾Š7=;­´½sq>•Š>’Ê=•-„¾]8>ñ®>#lš¾üÔ¾‹¤>¤D¾•V>t¿^V=¾íY¾ôHļƭR¾R¯>Q? >Ob5>}õ$>{§¾ áå¾]wÖ½^D)¾€Š==Ôêú>Üá­¾ÿ«?%l(¿òó=zSžٛ£=¡ü…¾ygä=td ? �=;¾¿+¾K³„¾<ðã=̳½ÍF¾”ï£=Û„ƒ>9Âz¼Ü-9¾œã=Æ^½€!a>]¾-=&{R>©3æ½–¾€;Ì>µz3>Ú/Å<µû�½áˆ€¾.æ=R€9= í=­ö->h1c>Å ˆ=Öð޽2Aë;òT>“Ào¾¿R&¿•¸¾:‹º¾*#Á½¬„½1ýz¾gŸŽ¾–нš2J> [^=[A<¾qL>§Ñ½mÚ¨¾IV6¾£mË= h©¾ o¾ç9Ä>ó4T>E|ë;ƒˆ¾ ¶ë½‡·=¿ð?<ú¿½X~=OÜ©½aìʾÎRt>õÀ=Äa?ÓÇŽ¾ýTü=7 ž¾¡‰Ú¾·T™>êWˆ>ŽûS¾Š˜Ñ¾Ó…=ŠÏî½g&¾é¹Ó½#ÇU=ÈÒ¾çi}¾F=Ôçï9�´<´¤<¾‰@å½hÛ°½DM%¾ÿêd>þë¾3Þ0>E˜> Bg=¾ù¯>[Š>^üŒ¾�¡ƒ¾òXɾ-ð=¼ä9$YL¾’ÛÓ=y¾¼©¢¾+#¾›èÔ=„ô ¿¢¾÷œÜ½¼…¾íÂâ½Y„¡<Ÿ{–½Fn¾k¿¸Ž>w9O> ¼ ¾ööн`) ¾|Mä=Åç¾ZŒ'<ˆý’¾…öȽÀR¼½ÜWŠ»$6�¼Á7g>šd¹=ŽN>èÖ¾û t½ ³Š¾Î÷;>^‘È:3pY¾Júå½wP> ”¤>³¦:e¦¾ÙÃÂ>Í�&?îci=Ôé#>Í6d>„噾Ô(>2î »0±¿mÅë>Sü‰¾H†±¼£k =nàØ¾xF­½*'g½6ĸ>nB§=ü1?x–>j�~>|ßî> ë½€ì >gîá>Ïo ?®…¾¼[‚=Ï—>w~¾G½’¾{¸?¾Ë‡µ¾ñv™¾ªY>Ë^ѽ7Zõ¾3Ïä=HR¾í¾4#̾�>¸¾oû½¤ù¾°Öd¾=ÕÒ¼ÍâʾÙϳ>08¯>›� ¾Ûì]¾Å©>aÜÒ¾¿Vd> Ù¿Al>Í@q¾¶OP>3G=b´'>1�ö=éY§¾„O¬=›Êå=×´ >».“¾à�d¾›™ª>€Ðƒ=•é=?—ä¾# w½aDL=ßøñ¾�eÔ<£vi>H¾|A4¾ñOô>ä-ó¾!‹¾â»œ½¬"¼Öõ:¾mŽ>ßQð¾%?Q>¦õ0>º?W™=æÆ±:U§¾ƒ©ƒ¾;o7>:><í†>Ñ%&? c†¾ 5I¾íÎ%¾©o“1«–¾y2>!“>à ‡½F¹‹½4–U½©`”½1U‡>ûò—=Ûv0½ŒÖ=àµB¼Zý‡¾¡Þ�>@…콕‹u>7½nÙ >üè0¾×>ëÑE>l¾o›>Š�ó¾.kÅ>ã€Ñ=¶Ç>]`=<½mD>¼ ɾ3P¸=´À˜½iP•¾t×S½,`Ú=.ëÔ>â 7¾�Õ=_.>ß Ú>±‹¿0z>þwß>Éo¼¾pbe>K�€½ÚH¶¾2¼<�- ¾~0¾s­&>ãÇß¾[ú´>"Fò¼`Äé=Léµ>ŽÏh½ÙLƒ¼ªñ¬=K<‰=5Te½B§©>ýc¿Mç¾Ø¤=\Ð=­ó%¾ŽP˜¼É6¥¾ÁÜ|>?^½–òY>—P�=¥tÿ¾íÁk½õXy¼óín>xˆ>öa‡»¨¦¢=+ìu½%3,>À›†¾Û9¶=}l>8Üÿ>á5?P“€¼½2€=q,µ>Þ¡ø¼•÷½]‚¾aæÈ>æ×.½pM¶=¦G'?ô6u¼Ý­R=å‘Ò>ýq¾¨íR>LN¾«í8>ð»C>nQ>½Ü÷¾O9Ã>ôüK=ä�>ç>|gW½c±)¾âºñ¾]>Vƒ¾ÝØþ=]Ö8¾~ÀÓ½–2(½Õ�‹>ÅŠ=òB¤>ÚV/¾vèÂ=í¶Ê<¤Žo¾™Ëe¾ö3<þ…’>0ì�>q¨>½²">Ͼ0!ʾH]½=È Ò½+²=òsÊ>Ám<>�&?Ÿ‡0>1Ñ>I>•À>t·|>/Õ> ª¸¾ZåÑ=«¯¿>˜¶Æ¾Î‡¾‹~Ç>ÃØ>¼ŽÀ=©zÍ>Çî¾t¨€¾ØÒ˜=P;¾½|>ÝS!= KÆ>’">a°¾T—¾i/>œå¼=­¬v¾Òš>›Z=ö”‘> ëP>þŠ¿>½R0<�”>¹Fn¿Ðt½9g/¾ÁÏ¿ãèy¾³#¾ŒÝß¾œŸ>ôÝ>ì�¿7N>0ô¼QÛ?nš½tÛƒ¾¯”S>> »=ìæ¿ud>ZB=mÍ£>‰·¢½CgÖ¾€Œ¾-=½6çN=4úÄ=,i>pì»ñF^=j#ª>Z �¾ðþÒ¾“tÚ="”�¾{ð=näf<×Y¾õ÷0¾° >n½pta>ã Á½’ô=¨ó—½ôÚ ?)þ};/›�½Ïhv>weϼ�ôbhp¾•lU½ IѾãV>µ°>°ž#¼úǽ?²@¾ˆ» >á,>ekù½È­#¾÷/νJüC¾YLE>f ¾aÂ)½›‰¾IŠ«½ü½¿‡å¾Œ¡¾eü=ÖÜ5<ú:ß=rÚ¾7ƒ>–N‡>{Hÿ=]ïv=-Ýð=‚]¦¾ úÐ>KO¾TK�=[=ÇÔý=’·:¨«=ÖmÚ=r™=ÞWÝ>Ð×¾†˜Â=ØÃ>L|=,Ë?Jœ!>dBw=!¥>{+O>Ù Õ¾`ì ½m•ë¾é�½ã)S>ýl{>Ó³µ½4¡¨>“>�ÿ{¾Óì�>_V¬¼ƒ0u½8'W½*¾Â±î=Žp,¾ý¿Ê½:-¶¾:ô×½¤êƾßÉP>ª“Ÿ>e@´¾êß=³æ¦>® ¬¾¸xi½0ßå¾Î‹�¾­Ù¶=›|»¾Ê.˜½ú:+>-•¾XÿÀ½Âyé=§ø�=χ>xù¾}榾°X>ó Ü;yæ!¾€úœ½µšE=M¹�¾ä©‡=ýÖX¾Šð>ä>¢„‹½xù>°ãɽ�)<›$‰>­8>@m=2.ü½5©G¾û·u¾œ]¿š%=xv«¼ §>Pôð¾—‡k¾÷i澡¾ôý±½§¾©ñ0¿nˆm=�uѽ&[ì¾sý/>¾ÂŽ>Ý> F"½ôìë½²Ä>]*½`¤n¼P™ë=�áO>j4ˆ>Å'‹¼²M.¾|€’==é®>‘æ¾¥àt>r~�>8˜¾r„3¾%”|>šˆp=ê.Á>Åò«=ö%¿ì+”>$K¾·!ù=íÒ>úa=Êw‚¾a@î<䪼7Sœ¾¹¶¿½N§È¾�¿aý‹¾+å>w`C=4’ ½ÄQ=¾]e8>‹ ¡½™›�¼ä¬Î¾!Ò‘>TÒá:9v¿©ÿ¬;ÊÜ=5%k>ÑêE>0fy<Ç1¿¨<^>f•=ÎGâØ)¾Ý5?Ó¶�>º8˜>asN¾è ç>¼Ë¨½«!]¾úó ¾è/¾^­>p¾V±>ì\?)f¾½Ÿ¼¾‡é#¾…�‰={Ì¡>T¥¿¥³>˗当–;Œ¾#D©<å~½=®l0¾äǃ¾Ÿ‰é¾ïuÙ>‚ /¼úî�>ySw¾CX>ÿ»å=RÀ*¾pq=¤X¿Ðà<¾Cb=>ô¿¾¼+ ¾Í<À>ök>(z ¿Aì¯=f½}¾¾R�»’k½%óq¼Z‰¾  ¾¾'šµ¾`’½÷ƒ>KFÓ½å¦=CÅ#>Wkêà¿åÊ=o| ½1¯À½è3S¾>\<>¥,i>¢m˜>úñÓ½Õÿ†½È­š¾Í¡h¼iõ>8™>\Á½ið•¾5?„=4ü ¼„ê½€li¾É,�>Ù,½çüü=\ÝP»Ñú)>|‡q=ÿ¾¾ÔêZ¼6ǼÎð4>£!µ>œ¢ ½[ŸT½,Âo>@‡½¦“–>v’H¾”P§>#Ä«>¯4C>î‰S=µ€¾­5­½@4T<ìʘ>vaã<Ê¢×¾’Y¾l¹›¾^ >~õÍ=m±Ö½F6¹¾Œ ¾ºØ#>} ¾ÒIW½Òó ¾\�x<Ÿï$>,€F<�¢ø>€aG>Eý¾~�¾\Q›¾]hN¾ÛÅ©>?ûñ¾¿]¾»á‚=mßL¾ªâv»è’#½½G™¾\Ÿ†½ ‹—=¤e¿¼·�R¾ Ü=áâ ½6 Ú½ÒÆM¾Vðô=Ѧ½‘%ͽ<±>i'¾<$3¾¸úýãL¾®Œ=Eè�=àS¾§&0¾÷M> s¥>žT:=‰Ñä½,"½"f0½ê“>—ô·=§Ö= ³Å½t&F=ž/p>=hk¾•6d¾•$ž=*›> G>Ýæ=:“z¾%­¾+•½"Õ=yx®½Ÿ³Ò¼)ÝF¾kðÂ= b�¾Ó,>¾clœ¼Œ4ê=󾹈½ûÊã¼T@>^”?T6å=›†š»XŸÈ<ÖôG¾ï_$>5ÊF¾Å“®<:”Õ=i�Ã= ìI>Ä‹b>ŸwÔ½IŸ>åãò>Ǿ¨¾ì ¾Èd½} ù>Œgy¾,Ø >Ôl>Îù¦¾m›¾=ïSp¾5² >møx>Ïãï¾j νöꜾ–C>ˆS<×¾¡½s¶½Üµ�=Â9ô¼×lɽ �¾˜Ž>S ><Œ½Dª=B[ú=÷ü¼4±=º�/¾x¨>ZY˜=Þº;¾Çe^¾ˆ¤J=a5™>qîm> �˽𡆾¥b̾…E»½–öUâ>/ÛË=;…¾ˆIŸ½çl†¾¬%>²‚½~Ì´>ï5>=0/нo+Õ½ð5½¡1K¾Ö=>´‘ñ½ þɽá¿ÿ¾ía«½ï›…¾BÔ=/C‹½8þ—=H´½É_¾"€>�á6¾{š¾,v¾öö=1¨±>‹‚¾)r¾j°‹>ß^†½WZ¾¸½X Í>¶I¬>¶x>rF¾¾×Øú=|0á½Úš½47 ¿ƒ2>c¥f½r~Ž=�x>¹C¾T ”>aS5>˜„Š= Uœ½‚À�¾L÷-½°*¾Th”¼²‚½u¾ûVŠ<Ãx–>v¥>¤,¯=ÄŒ¾\ç¤>"F4¾–À#¾oe>ýBS½eœº¼^ç>ëǨ¼P>¾µ&>H ½‰O=MJå¾=û½ÑAv½F¯€¾6ؾs>úr¾xÎû½ïx�¾d„:¼õ4)>ê•§>嫟½sü½ðâQ"¾J±9¾†•ƒ¾¿íë=r�_¾�,>D¤½"¹¿²Î?>ÓË>ó¼½¼X > Ç#¾{‚í½3&=ÝôѾÙå¼ñøH½0„º½ŽË ½w–½>�n›:Lwn>|¸-¾àiá¾’\i¾¨|Ž>“^*¾Zá©=?�N>IÑñ½|±Œ½bć¾D¥¾mB›¾_2ì¼öë>ôæè½ £¹½ÝyÕ;eŒf¾‹Ê¹=ÛY =x½>¸>>év ¿ó1 ½3¾£vI<†óš¼êón=ü•Ÿ¾ÕV¥=çë½è,Â>¥û¾˜>±O>n7¼“sº>ïð>¾[b>‡S=+J¾ðã=U5¿=ft¿‹±P¾»ç¾3bè¾Á+§>UÆf>dÍ¿=å¯�¾uK½Ñ:—¾d]=±ó=—¬1> ç¾c·»Ìg/>èžß=nb >£çj¾Šg¤>vqÞ½ (?j´ø>H~>Šï,¼‹m<“›Ô¾72->Â,=»ݾ¾¦ Í<öFE>¹Qô¾óæ]=ðÍ”=,—=ó f½Ýy켉2N>5M¾ÖžÖ¾á î½o§R¾Xø½•;>'>9<ÀÌ >Zf㽘Ì2»áã>ÉRº #½ÑÞÌ=ú^0¾G¿k¾ê? ½» ¯>  ¾�©ê=ᕜ>ÙAÊ>øJf=» ˽X‡Ù<D´¾X>Ž÷Þ>DT2>{µ¢¾¼à*¾L ¾3uÔ>l ¾ŸO¥½Ð_P½×h>¡Žb¾°lœ½&§¾Õ•U;£zÀ° =Ðë>'¾›:'¾ýÕ ¾à§¾DÁ¾pM[>47U¾ËÖ¾>2ù=Cp¤>‹Zœ>cÞ>~ó¾¼pˆ=/Í­=“Za½OÁf=ôªi¾œ¸Õ½ÌF3¾¼75=›Õ‘>By»>7v+¾³°,?¿�a¾´zˆ=Œ]ã=w49=Y “;‡ñ½M>¼Ÿ•B> Ò�¾õ–˜>˪=ž\Š=¹�¼½w÷£=¸»�=úúþ>þ¶˜½à¹„¾OÔ >ä{¾.D½=?Û÷½ËGؾ ®<>)ªˆ¾óÁ›¾ïö =͎ž%g¾ŒY*>L7i=EÑ=>jÁ€>™ °=­%¤½é¯>­Hk>ºì#>´=‰R“¾ÍN>´&>MàZ>Ô®m=e¦è½½›‚<‚ >¾T.š>›´¾6€‹¾Î!=�}=”#>¼ÂÛ¾Ùž�½ÂJ¾ö�$¾-¬=~Øö½Û,¨=õ?ê¾F«>e¥Z>#‰¾¢×Ç=�¤5¾2Ð ¾€[†»G$Ƚ‡A„>öm;< Uï>‚?²¼Uçý c¾¹><±P>?+!>²$�>¼9>Ð�.¾œ¸>Wˆ—¾+昼¡3$¾m°™¼ÙU ½or?¾pÑ/¾Ã0†=nÿ=�Ì�>ÈÍ>  >Þò´½Ê²ë¾âàr¾H]Ú½ÄZm>€Ú¯¾Ñ‰=§—á»È=>§Ë®>.–q¾Ò*2>ß6ñ>V&¦>ÎH¾‹ôÁ=Ÿ¾¾OAžo‹Ñ½k­E¾�Û¾ßè²¾b¥D>àóA¾yQ->Œp§=cÚO¾³>õ)`¾a«F¾¨‘=g2�¼f»½€ßõ¼³b=ñpu½3S.=É·G¾Cü�¼@rŒ>•æ=±»¾ç¥ ¾ªv>B0L¾Óßc>êxÀ¼ÝÁ=1}+9JYH¾°æ>sž< ~M;Á…‘¾!Þ½€0¨>n�ؽPãž>º°Ô=ýSɾéf¾SZÕ<’S¾Ê³H>øi€½Q |¼<"ø=üS¾ „F>޵þ=2P6¾ ¢#¾{ëm¾õpB=å¬S>ß�ܽÂݾ¢&>¾`–‚¾ÐE‘=¯À•¾sæü=’\(>NȨ=”µ¾‰K>Øn>wSî<¡<á<�¼=’è>?䃽4@¾ÌD>Û₽V‰¾{h˜¾Ià¦=ûÍõ½.¦Ž½5¸ù=§*P;Î Ã>ÒUg>(˜¶>)d‰¼¾ñß¾òc)>þ*¡½ß| =TŽ> _ ¾Æ@>ZÏP>Oc_¼hÑ�¾ ξ=æ½¾NÒ¾Ç^_½Sƒ¾ž£µ;Ò|’>†ƒ<[¿ˆ>· ¾½ë >_6‚=ˆ¦ë¾_¿¾öF{¾ô `=5¾¬=üð¿>å$ù½r¢¼ Ÿ=¿t½6Tì=:�Ç=Œ¼¾÷þ½Ûôe>h6ƒ>RAý¼ˆô~ŠÁ½Âj£¾CRŽ¾Ñ¶¦=LƒÉ½‚Œn>`ø)>Jzj½}p¾Þg½:7äå>þÜV¾p@«;úP½»c>û|J>¹»�¾›×>¯–N>gz¾ $9½qãá=lì˜<`Ï¿½’f>Rš¾~¸<�k¿Åž=>&tr¾¥@=¾ËEJ>ôï¾f+ >cœv½nz¾‹|νl¨µ¾«T ¾½Ü‡=¹ñ½@xg;»I¾˜#ݽw†:>̽Շ¶=˜>¨§A=S@ê½ïÀu=³ð=„[ѽHÝ>®ð‚=Cy¶>虑==7޾ûå½&¢=êh¡Ë¾Ÿ·•=‘³ä¼×2O:¬û=~j¸¾n‰¾°9+½Ó²>xE�¾t±">Œ¦¾¬Ž8>dXI>×I<­½¥5¾"¼]¾›ò :1ô•¾×¯ ¾50z=€´“=¬_¶=¢ö¿¾ ôR¾k«¨¾cÊ€=ÕÞR½Ûëo¾£¸c¾ ]s¾bg�>ý'M¾)Âéº#k¿¾0R ½pu¹=Æ =Eâ—½+°5¾‰t¾;Ž!> =}=~9>N@,»|æÁ¾]�T=öi>N¾º=¯Ë>¾7î¯ ,ÿ½äI„=ï]~¾¨K2>sÑ­½…3Æ=T’ò>•™>ÿ�>Þ½A¾¹">W™¼fýô?%>UtŒ¾›7Ó¾«žç¼š^¾j‘>¨=8t„=Þö…¾H{„¾ >z½0¶¾±øO>æHV¾]»£¾‡3;¾ðªµ=²V<½Ð@?MɾÍÅ”=Ô*>ѽ(¾]‹¿>ó =Á$¼¿3]=’Ê,¾Â½>=Aš>2˜=2bÖ»û¾õá¿ôcm¾Âš�=¨–>¦‚¬½õ7r=~*ê¾Ô×E>Œ<^>9ê¾æ®.½n¸ò=$Ìt¾/Ô¾”j9½UË >�âÔ¾ùë#¼>ìõ=³>:3L¾©*4¾Â„¨=è·> Ò¸½²UÇ<2÷m>&tþ ~½ì삽 U¾úN½`ÁH¾ç; ¾ùâ½|%D>Ɉ >R_¾…´¾º=U6¾¬Ðm>E篽„]è½ÛÕ=_¦=�Ϻ½&�Ò½^²o¾=Éù=u‹�½¯A½œA<0ý<"wÔ=&‚Ž= ¤ ><4ܾô]O>Œ÷�<² >/¿ ¾Äõu½ê~¤¼ì½¼èÚ=Eõ}=Xf½‘Ï>4°á¼¹'Ž=Ku >êr»>Ú? =ð›w¾Cá)>û ‹½ˆâm½Øf¶½ÏôÕ½OŽÍ:(£“=4ͽ–r=@†œ½Ê!¾­ ľ± „¾Âòâ¼…ºç>XÏ“=€A:=kè×½ë°>ʹ>ü•>d;#½|nö=‘©ó;g8¢½�+> ~ ¾Éc£¾oÛ̾0gÚ½Ìl>"¾´´ö<ÎÂù<€v»–À£¾r<¾nüI½Áǧ>Œ¦Ð½ìÖt>7”V¾÷ž¾Íl…<k¦¾à—½½±­¥>ñgR>y>¤=£!¿d€¿¼ #I½} >z'־↠>ÙlQ½X‘ƾµ¯@>6�9=åÒ8¼�û¼‘²”½äI™¾YôÒ¾ËÐB¾ÎI¹¾…F&¾<Ùm¾gÖI¾Hº|¾§­¾7­µ<¥>fÀw>Xb>›H»TWì¾#®²½vdb>K+¾cv>q/¾dŽŒ>üª=ùß÷=eRb=íB ¾`=½'Už>€;¾°\ª> >>ŒY«>yŒ<'�Ò<´ÂC½r.µ<²ËK>µ=Ù>où“¾Ê¾V¸u>ÓŒq>΀î½äs=ˆË²¼£› >�+=êR+>Ÿ¹>�õ>Öæ>#G>᪊½Qû[¾I˜Ê½™†=ˆÄr;¡gÒ½|ØT¾a 侚%y¾w±ç¾%i>eÚP>žd½é„¾Lgï=žï¾à‰¾ð!Ù¾ü¤>ÌÐ*>­–œ>qŒ?Ñ1ë½.²¼ó}=¾á4‰¾×ݾ|cë½/ ;>¡#Q½  ½ôX=¾yþ°¾ë¢>âŸÁ½þ«3>Ü7ö½á@ ¿¤ƒ3¾¿TÒ¾ˆŽƒ>Á`]¾¬b=È<Ð;16>Ëì…>[°'<ÉS¶>?€J=°�´¾A™¾ƒJc½çJM¾KQb½Ÿ6Ü;ûN4¾^œI>š2r>ཛ=ó�½Å¶Å¼užž=”s>»·=¥¸>j±Ì>I ‘¾ |X½c8S>G^º<ôR*>C>-¾C.Ç<žpÄ>þë÷½©3ð½8N <œÉ7¾øvm>,6>|Â}¾{s½Z=D¾.a¬½Ǿ¾¨À>žA&>ÜÓ9>(ð?ˆÑ >¨“g>âð±¾ÿN/=/œ°>Œ§f<”?:<³Ï³¼,5>@§C¼™Â>»&¾dï³½ëž>5÷)¾q½`>Œ†½°ñì¼;þ?ú²÷½Ãò•¾»h„>Y�¾ëy>­ÂŸ> þ¾ ê>î(¹;ï(‹>Éh¢½%r7¾ë¦2>ª>|϶¾ö#½³ný‡æ>mË€½rXÆ=oª¾=.ÚÔ="×ê>3D²>§VÂ>SzS=™^½¿å">¨V¦¾7¹¾d¶V¾ï œ>Yë>f“P¾â|ã»HŠ´½Fĺ¾a~£=ù–�¾«`J;ÖîO>aB6>·.�½Áà_½p#ª>Òë’½Ÿ�"=L:¦<:­è¼i’¾½¤>¦”ë½fnƒ½µY?>êç>I½ølN¾iÁ)¾ŒÕ³¾åd»÷M~¾mÆ›¼KJú½þZ2>ôþ=W¶Š¾zãD¾zÁK>og̾ž6¾%˽R1͉˜«>¦rÒ<½‡>Ê4�=÷£!¾–;r¾°Ñ ½ê+=>v>ºq–>i”½*¾CT$=Uÿ¦>?ç]>éFÕ>ͨ»\ �¼WÔ¸>¢€¾&Úç½Z%>Œǽeõ>ì6‚>`!V¾Ý‰¾­@ö>Ÿï=äRD¾&P>ÁW×¼AùL=OÒ=>©:½¾%˾¹\Q¾¶ï¥½Ú„n>Ía >*‡¿k¾e+m>Øáp¾ãS=ðT꾚˜‘½ã^j¾.Oò>{Sq>ñpq>a…=þa=ÖJ¬½Ab½=Vâ“>‡Î|¾äzß¾R÷?¾l'Ø>®rã½ñëü;_" >ŠF>ˆµt>÷Z ¿D�¶½7Ì—>Õ]¿—µ&>„2e¾ømN¾jͯ¾ÒåŽ>U›=½©<¤*±>ñ©¼w–#>ï J½Ñ½´í=’€>Zé=Œ³'¾Gá*=á¶;>C–½l -¾·ä¾ËÁ¼‚®4¾·Õ>’Ö¾NŠZ>usŒXØ>�ñx½æq?)ÿ½R4‚¾åœ,<ý† >€nG¾˜Ëµ>}ྔ;½u{ˆ=0h–=G^§½üªÅ=#¨#¾ÝÜ<ûD¦>Å-½Œ�@¾eR >湿Eɽ%qB>H-R>Ìœ¢½5>vF†¾?K=­Qí¾$Öu¾8ôŒ=Caã=Cߨ>�>qa'>#À̽É~?úÍë>½Âœ=(? ØÓ½;¿ >¨:¾s ¢¾5’n>k„K>œ­•>ZY¾Æ„.>äF¾Ž8à=„vª¾+�½+oœ½‰þ½áP½ ɰ¾>¿”�>|Š ½¶â\>çxæ=f®Ü¾�Bn½z¿¤>ÞµE>>LX>9€>û�ý>"¶ð>>¯,¾Ïrš¾ €Ä>ÖÓ½z‘="I.½/"O>\¾ÎŒà>ê¾aµ±¼<¥6¾ÚÓ#>ÿ¸é½ -p½ ¹£¾å¡=+I,¾˜cí>pÞ&½UȽ+¾tv³=ü­[¾ ̽šU½ `}>Í ¥¼t¥ƒ»Øi<¾ÄCl>»¾��>íy0¿{}¾ÙÒ½<_¾d¼»W(`½(즾î·R>zè,¾7(=>Å}:åZ€>oÎB½»¥0>©�¾b½1¯Ê=8›h¾§_> . ¾ ã=ïš×>ャ>~û¹<ÿ‡?ƒAî½=x>%؆>%s= J>¦ÈÞ½½šo¾,î‚= ¬Ò¼ty£>»Ç?�E¬=&ê‚>8¶Ø¾$ÂE½,y?µE€¾[ô‹=_¥@>ÐlŽ=ÑŠ‹>ÈÏ“½ –¾²/�=(Æ$>�‹¾ìÈ,=8+š½í4ü7¸½:±Á<J–½„ƒ;ò 2=úvq½’߈<Œ¯>_ ">gÝ<^0¾d•Ò¾ƒW=¥�ȾزT¾Tt¾‚ª>â´>áä�>Q=T¾¾™ÿ¾‘¢²¾Ì&->â™? Á¬½ur»o¼n¾}…s¾g�˜½'¯±¾ï=a}‘¾¼±>uq>�°<¾ƒy>g7“¾‰Š=âïk>sÆP>ú(Ö>,8>¨—>ÚÈå=ƒƒ’½'øÞ½P).>*ÿ�>¬4·>œf >öS¾}›Õ¾œ÷Y>Ñ >=„âR¾÷$޽±:=ÒsH>â›=¶?È<,æ½A¾I½Þ;ô.}=%>T¾M:8¾(Ÿ¾Óh¼;’ =Äý8?Áĉ½T£r>O ‡>Þ‡¾N[>h½Ý퟽!a¤=fÚ¼ìõl>U*>#“*¾.f¿³¼+>÷?¦¾‚ľh>½ˆª!¾ä®¾7D¾Þ5J¾²?>U0>®§à¾ŽÄ’¾gmZ>ôÖV¼GvÁ°B³=‰Ç=Í3p=ºDç½ïT¾ e�½·Ì„>£:¾°±˜½U§>Ã<¶yÌ=kh)¼{­°¾pMB=d“@=Þ×�>óÕZ¾%tP<üm޹Bq½}?Öø×½ý9¨>lJž¾�¾HC¾>ÐÞ>7Â?<¡/f>ÁŒÇº–,=pŽ=YÂ>Ó]¾ºÂ>¶o ¾z_¾ ��>ú¤p¾7¢¨=¯ž>±<> Ó¾•�­=¥ú¤¾s¾bÜ>'Î<Ñü¯=˜Qd¾»¢‹>RaŠ<ì2¤¾·ëå½üûN½¾€æ>‰TP¾…œ¾*³=­é½+nB<'˜^½êP½C޶½Rq½mÀ¼ª½Ù½lÖ‰>ÃJ>·ÉŽ>8²�½¯">{ú�¾þ >¡q½qã­=W)Û> �—9–é’>õ ¾zÇ<¼–¾a“>6ͽb¬¾u M¾ºE¾¨[ƒ½�M›=×¥¦½„úŽ>Ìå½�¬¸>Ø)»½µë†½-Ž3<´þŒ¾l“+>Žè=†–>‹æŠ=š”û½>bŒ½íá¾ÄzÅ=*� ?�„¡=�‚{¾T’‹>A>Ì�ˆ¾ýé>eê=Iw>¾5¥=Ðm¨>ºRD¾õoä=Ÿ½¾ä꡾2Ÿû¾ÎPL>¦§½<̾1iŽ¾Ê¨H¾Z%>~ó¾ëyƾªÒ:½,K >›‹ª>•¾qŒ->B.k¾Y�:¾Jýç¼0+™¾d>UÁ>q�å=ÏÞ×>Áþ€=ÛF†¾Â”^>äD¾<·¾çr>®¥=“c¾ì›e½-¶«=ž¤¾(Þ¬½[ç‰=±É=9)\½hv‡¼ÃQo½?V²>>AϽ¹{Ú½/e?]%%>¿'½A8£½èOµ¾‰=”¾ s¢=– ¾}Æ&=lì�¾¢¾S½½±>¤Š½ÄÅö=帼ЯK<!‰½.؇>Rw†=Ld/¾z{¯=ÁÖÎ=Qcª¾œ¾´ž’¾¶Ðо¡“�¾ÅE=ç[‚½ÖÆ<]½i^±>q§¾»UF¾¾HY½P ½¾H¹�½-ºF>²Tÿ=¼GD¾Zȃ>Ó ç>µ;hN†¾õÂ=Îv®½„§ ¾8“»¾èý‰¾@þ¾™õ½ð€ƒ¾ô‡m½x”„¾X¿µ½È>$;©¾ô(¾í°¾-V‰=£å“¾³3M=”[!>·Åt=<@�>D©¼9m©¼Ä²=#U£¼ûuš=r{¾‚á>Ç€¾�…¾ŸÚo½þ{¾ÅI¡½M« ;GA‡>+k¾êÖ=* ÿ=Ü6>ûåö=ö€¾ XÞ=N¾�k¾5ÚÁ<ß>¯]¾ó?S>#'=•Ò>³h¢¾Âê¾°÷5¾ÊÓ½•]ʼéûÖ½h6•=¤¡L¾bо%ŒÄ¾�2‡¾ÆÃn>Lh¦Q\Ÿ¾H“ >Óµ…¾½K¸—>ò›î<ÔÌÃ>ª>+ìÔ=G©/½�%¿}ã¾ ¾X÷¸¼vÇ=vî<áþ¾)í�½P¿å½4k9>ô(9¾[T¾2 €;œ›‘¾‘‚´=RT‘¼‰†=ô >ë_ì½öƒ½âa>{Þ=‰ ¾ü3û<ÑI¾´ŸS¾­¾sO1>¼ƒ0¿NI<¸=¾�ÍØ½¡<ý›‡¾HÄ¥=>¾¾\Í…= 1UЬ½H¸:¾ªÇ=LÖH¾«0,¾m² >`뺾ú¾ƒ±»½hr;m �>ÜÀˆ>�Þ®=²R–>˜‚‰¾ƒÐ>¨#�¾ìÌ>óܽC™Ó½£F‡¾Q…1>28+==š¾Ü¬«>èÜæ½�о-é=½g?=X>#¾=¾±?Rk¾ZS‚½1» ?�„=¦¸4>‹>ã~Þ¾”o>‡“u:Äü½=»½Á¹t<Þ.°¾˜‰Þ¾C¯¾Ý‹K=ï 0¾ Æö<Ì©ô¾Ú5ò½€{$¾©µt>ãÒE½’å�½xߢ=œ‡¸=ú/>ô†�>*‰>Ú¬H¾ò#¼µ�A½Ñ3üuÍŠ>ƒ,½d{½N§x¾æÍ̾ɺ–½ì¤A= î=G´Û½¡²8=ù >–›¯¼ŠJ½‰>¬1 ≯=6CI¾»“¾YjÅ< í=w>¿(�=¾*ðk=è\(¼™ÅÚ>ÛöÝ>¿˜\>˦©¾íüà¼ÏR!¾Q¶Û¼ä…1¾DÈ<¾—˜,¾KÑù=ãЕ>î½Xô¼¾ýñà=9üí<�+Žދn¾$Uå¼ú¾õ¿>³®½K†²½J#>oì>�|½V«#¾s-§=Õ. ¾g,Z>5ª+¾“¥Õ¼PÏ«>A¸Š>¶.g=ñÄʾ ¯>±¾ÜÉ=xaÂ>‰Š<’>ë:K¾ % =;ü= ÝÖ½+¾kð;=Ny¤¾{½>Ãüù¼“Z¾¯L/>=€=ÎA6>é½½ÅÛнxJP¾>„¡�>òÈ„¾Ën;<þ�Åè=>K¾�²>©à ¾Xq>kχ=_:½qQÉ»R²>¦¿ (A¼0'œ¾ëÞ<‚e>V K=ç½>†>otQ¾Ïe¸>=Ü<ØÜ>¤hñ=6²W> $>ÉÖ=jn?¾ì/Þ½gA>zœm¼Bª¤½²V1¾+ >œ\>ÓÏ£¼;¾S–�¾ÏÄG¾i ¾&1#¼~l¾|F¾dVj½÷¾C»:>3c¾äV‘¾2K*¾§Rs¾=™½þÇŒ¾Yf@>"t ½"¶-½Ð×i=]ªÅ½f¦ç>\÷Z>‚}�½Û’>%ÏȽ¡§>¾Ž¯ú=˜d¹½ÅÓå½]“=âÅ>´Õ¼=%( ¾U¨ë=)¦H>©íÂ=°Ê¿[5¾Gº½w4ξŽÇë>·™V>BóE>3¾dÖ<#… =Ž>i¡P¾-ò£=GÉL¾Jþ˜½áV ¾/-¾dtݾÐYå= ¡b<àÕ¿=KOÕ>æ„+?îõ&?«³+¾(‰)>ÀN=h“^>ÚUK=Ú¤¾&¹Ú½{¨œ½2é;¾nEÆ> ·(¾îÆ>¾¾·a>Iùê½…oÌ="$2>-Þ½Ëû4=iSæ=ý;‘=)K >``†=6B–<†‰·¾‰@¾kÙš>~8h¾f¾Ì=µI¼Â’‘¾C(s¾Æ00=ô¼Ë>œd=q� <¬R–½ÚÓ¿àM¾)‚À¾[ã ¼áÛi=J¼Rnª>p>;>U¾—Œ$¾®5> Ç =yRK>©£>ªw"¾Ðx ¾5Ü„>õ”!?9׈¼;1>¸~¾Ø÷Æ<Ä¿¼`h·¾(­÷$èǽ�Ô-¾Ä²2¾°µ{=(«¾…Y·¾”¥«>ã%D¾rš†º–ßa¾Î쾤,3>Ã辯b¾6ˆ>ªé­>ÚÂ�=¡áä¾k.E>BÀ>B.^¾´J>�!é¾þXG½â)³;¾±¾l$J=?U >yòð=…¾[ >JF³>JÏǾŠ<ÕÙW>V×½«)Ǿõoy>gR> \ÿ;%U¤>Á¶¾û_ž>×=p?(¾`õ¾ø�†=ÛÉE>ûqB¾eÞ%>=*¾1E> ý`>Wd>B]w½$`¾pºî=Væ�½ˆ'?>Ê {>1.š½ò  ¿nÊ>&lý=EÌQ>§.¾Xíð=ÏÎé=ýŸ¾éù<ûG>we1¾7‹æ¾ƒ‚>{'->Zg¶½"[ ¾qç¿»e°Š½êV‚=·Œ7¾Ö×P¾ J’>e1¾Ã ;>9Öf>Çx›>ˆÆ=ôøV¾"*ý=WPϾÞuͽ'Ué¼È—=Ünݼ‡h¥½ /¢=–&¿Òi=Z‰>øÐ—>ÕI’½]‹ù<@ï>3cœ=*L›¾åÜM¾…&{¾È•F¾™¨Ç¾¥�‡<%¥¾1¶¨>¿ó´6>õ5å½ð¼I¾+q´=^4×=7™ò½N¾Ðªì½Ùì|¾[ö>ú< ½ªÂ> f¾‰…½�bÉ>[Ô‚=«\'¾Müy>!*K¾÷õe¾í¼(>³¾¾xÒb>¦5™¾¡Œ¸< �w¾a#¾F`¾”b¾¾A–?Y[>�B³½@Ǻ¾çlÙ=¸ü•¾E9B¾ ì½Û…™=V,4=CLâÔq>8$}=ÒNù¼`ª•>Fý½t5¾fŒ®=è¾T>¸½l!�>4$´¾"-¾qCë=H6¾Þý¾×Â>²Éw¾œx+¾ÖX¾5O=ýè½ðö¨½0È>åm>ºØŠ½®\;¾»OÒ==S²¾¤\=?³;>/<¾ƒ™/>Ýؽò¤?š•`½"è ¾u”¾pf=®>¾h÷ >nU«¾Þå‹>¥[˽ˆêR=Ï3¥½Ž û<±¾ Y<»–X»;[ºÉ©Š=ÀjÃ<§ Z¾^9•>§)F=×Íú¹ ]Î=ãÙÎ><—q>?[½¿R">²?C>}v¤¾žÛ{¾((N¾=^¾Qî>C¦¼h!ª¾BÜH=DÎN¾�ŸÂ½éáZ>Y´½ “¾àO¾w°¾Å>P­ß>ƒ‰7>[Œ?$>«9½Ûw¾U k=¹?Mñ˾€X¨¾&š¾i�½ùê6¾ÁAE¼Ä ¿I?$¾¹¥¼"=¨¡k=àX·º5 Ÿ¼±8ã>#Ì…>¬Ë"½³ˆF¾Ú{�½`V»>‹…>sâ>ìã›=^m ¿ŸÅè¼x0¾J~�>d”¾¥>ýÛ?�ó¶>QØ«¾yOÚ=û­]>¼ƒy>ô2 ¿Kð=a12:ÚÂZ>œÓ=BFA<´B$>Ϋ½ºà(¾`C½½ð�:>®Š^¾¸N=º­Ô=Üؽ`à>„å ¾éP>ÑÀþ·íµ¼BÎp¼J—d½;]½½½@0½3s>§Ð#>Œ�ý¾•Sh>[z‚¼ºà¬>ýé0¾"Œ>ü©™>œôʼ‰z>“&½Ÿ^®<œ¬R>³`>~Â;¾™á̽Є >Qˆ;¼ZÇÈ<'å¾²åÆ;EM×–ž¼¥ô½–¯<*¾yhþ½�j‡¾!'9>”% >î@Ö>Œÿ>©7�>A‹‹½+å›>�õ™¾¢Úß½F£­¾'šZ>nØA=ïþ>$ô—>|’½ÉUG¾ŒÏÚ¾*%†>t�Ä>>l¾»²½âª‘¾†z,>¬ú÷¾šn>)ÁŽ=}m̾ç�0>?)޾ 3о"¥½æ‹™=M‚¿¼0,½ï>ß°³¼\S>¤ >Ó$o>Í«¾[Ž=Ã@¾àLî=÷8O= .N>Úó×¼]é>üç³=iA¾_Ö¿L$L>ñ“'>·ŸÆ>éë�<¼©”>4n½óÿÓ½è ¾c^Ë=»ÏA>E‚>œ®|½¦Bw»�̈>�?+½E"ó½½õƒ¼¬T>¬+G½-"Â>ÉgŒ¾Qp»k“ì½§�6»UÝí=¾kAw>Xo»½è=²ÿ=–*7<¼=Ÿ®>}á ¾µOe>[Hp=Ró¥¾_qm>™ÏY>ÂR>ÃyÙ=ЭÇ=d8Ð>6ö_=q>;º�>¬ž½Ñ'¾Å.½+÷P>>o8¾í)¡>^¼ÁI½ŒÂ„=gfX>¿®ë½2r>Êæ¿A ƒ>¡™=…}¿^Æ`¾}è¾8S.>Ìnަ-ÿ¾s½a>þ­º½þƒ½{ÖH½™!Í=l?Ò<@@>…zP>±X¤>6 ˽±©å=‰u=§_6>Ú ³>–Ë>çxrÙúª¾J�¼íþ¦=θí>æœ =Àa‘¾ÅÞÁ¾¶® >Ôt\½šªX=¨—n=®Ä>>åê5>F¯´½Ù™ƒ><òš¾òëì½D½U¾Héq>¬*hŒé†¼ï3ï>Õ⌾œó¢¾»p]¾ÄÆn¾&¡)>¾U¾SC¾³¢½!Å= r›¾ «¬½ò/k9Ï¿,?ø9ÿ¼óæn=Û±> ïÞ=ý *>þ3¿ÑГ=&!>, ¢=J¡:¾9“=.`¬¾úݽã/ß>pÛõ=ÆÎ3¾e2>*¢Â¾õÍm½RÝm½†8]¾©VÔ¾!�±=$xm>Ѭƒ¾wT¾í¥o¾™L<¼'�Y>Kø#>{š=‘G>d´ù:MWp>ÀóǾHÑ¡<ôã¾ö½ä!k>š”:>þ÷@¾ÜôѼ¢H>z{‰>`<¾`Ui¾Œ½Æ=A€¾9Ò¾¾Õ¦½Ã v½øÖî¾Ó?E>‡Î¥>Í,~>eò™=ÆS¢¾�¨G¾– ¼8ø ¾G=b½hÕß=Öšþ=Û½øB¿Ü°I>Ðò=ní">Ù¾6ÿ|;¤�¾æ¾œ¥ª½ Ù½Ó3>„b¹=Óc÷½BR²>ÿ ×¾¶í‘½PLZ¼Ps ¿&Õ>λ>´"#=N] >ùV­½ûд<äP“>F†>¢Sä=4©4> Z,¾ü¡¾oº‹= Æ÷½”㽡7Œ½ÔÑž<èºâ=ŒÑe>ˆ½Æ÷=–™p>1~¿> 6¬½ý¤¶¾ ïE>gY¬=G4³>j9¾`ˆ+¾ðhT¾dö;ª”¾Ý=‰ÞN½ ‡L¾^ i¾0ëC>ª¸y>‡>ð/º=œ1S¾Ó9�>2c·¾Òß½…?>�‡¾’­¾ª¸6¾éû‡=Íß?l‡<èý/¿à&¬¼z¿>ø\c¾.•Ð>^å ?oÂk½h'•¾õ[$>Ùc¾`þ—¾ÔÕ×½E^[½7…>£0m¾âµ�=𑱾ÃÔ==!Ð/¾? Ñ½n ¾åŒ”>“§=Ýô‹=×r�½*1‚½˜=}¾9 Þ½T~J»¶uQ>©Þ¾…�Û¼þô‹½kõ‹¾ Ó£¸ÓÍ®½:Ð>9¦>@0ö=Ê ¿º '»³Dr½äp_¾æ,>ãW½ 2½u¾¾F§ß=÷#¾‡Ó½=ØR2½à4ˆ½:‹=ã�v½¬†Ï¼/·>‘^¡<-Ïí¾Tçž>BÔ">n •;\§¾&n>yu¾æ%Ë="¤¾“Ý„½Í<>®¾*½Ia·½¾pc>»×¾˜<+ôe¾_Ѿ¬L>½OC>;î>¾2¾6×W=S=¤´S½zHb>ŸØ6»Ãؽ{kŸ=ï?n>±Þ=ße¾¢e½Asc>®¸<ìc©>ûæ=žm>¡ò/¾¬ö½�@>àÛ˜>T¼IÝ“¾†›<>÷?»¢š¾H±N>D›™½3u̽›w ¾Þaü=Ü0>¾1�¾–++½Ü¾Õ<ñÞÖ=“o§¾'ˆ¾LD[½%–>‡ 7>g"q>X]¡¾¯—�½ _”¾² 5¾ëWƼõ>ðÐÉ>ÏÕá=�î¨=¾¯D=´B°>×`< r¾ ù�¾½P=6 °½¦è®=Zòξ”<¨>`V�¾RÁÃ=ur‰¾¡TL»åV’<ÛÓ¾x‘k¾Ü×a¾…³‚>¬˜Ì¾d¾óËÁ>…Z>¥›¾ä¬ø=^�K>Ã)޽_*>9Ì–>Uº&>LOD½›Û¡½C>M¦Ð=àŒ½½�“G¾©u€½¤/>jk ¾à³»½X¹>®Æ= !–=Uî>scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embl_constructed000066400000000000000000000021211520735541300267070ustar00rootroot00000000000000ID LT357133; SV 1; linear; genomic DNA; CON; INV; 140 BP. XX AC LT357133; XX PR Project:PRJEB12116; XX DT 18-SEP-2016 (Rel. 130, Created) DT 18-SEP-2016 (Rel. 130, Last updated, Version 1) XX DE Spodoptera frugiperda genome assembly, scaffold: C262451 XX KW . XX OS Spodoptera frugiperda (fall armyworm) OC Eukaryota; Metazoa; Ecdysozoa; Arthropoda; Hexapoda; Insecta; Pterygota; OC Neoptera; Endopterygota; Lepidoptera; Glossata; Ditrysia; Noctuoidea; OC Noctuidae; Amphipyrinae; Spodoptera. XX RN [1] RA Landry J.; RT ; RL Submitted (16-MAR-2016) to the INSDC. RL EMBL, Genemics Core Facility, Meyerhofstrasse 1,, 69117 Heidelberg, Germany XX DR MD5; 90c05497c7cde972dc52b8d06097f88c. DR ENA; FJUZ01000000; SET. DR ENA; FJUZ00000000; SET. DR BioSample; SAMEA3707213. XX FH Key Location/Qualifiers FH FT source 1..140 FT /organism="Spodoptera frugiperda" FT /mol_type="genomic DNA" FT /cell_line="SF21" FT /db_xref="taxon:7108" XX CO join(FJUZ01138823.1:1..140) // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embl_feature_level_record000066400000000000000000000075231520735541300305450ustar00rootroot00000000000000ID LK021130.1:74067..75610:rRNA; SV 1; linear; genomic DNA; STD; PRO; 1544 BP. XX PA LK021130.1 XX PR Project:PRJEB5701; XX DT 02-JUN-2014 (Rel. 121, Created) DT 04-FEB-2016 (Rel. 127, Last updated, Version 5) XX DE Vibrio anguillarum 16S rRNA XX KW . XX OS Vibrio anguillarum OC Bacteria; Proteobacteria; Gammaproteobacteria; Vibrionales; Vibrionaceae; OC Vibrio. XX RN [1] RA Holm K.; RT ; RL Submitted (26-MAR-2014) to the INSDC. RL Norstruct, Dept of Chemistry, University of Tromso, Science Park 3, NO-9037 RL Tromso, NORWAY. XX RN [2] RX DOI; 10.1186/s40793-015-0060-7. RX PUBMED; 26380645. RA Holm K.O., Nilsson K., Hjerde E., Willassen N.P., Milton D.L.; RT "Complete genome sequence of Vibrio anguillarum strain NB10, a virulent RT isolate from the Gulf of Bothnia"; RL Stand Genomic Sci. 10:60-60(2015). XX DR SILVA-LSU; LK021130. DR SILVA-SSU; LK021130. DR MD5; afd116bf2c1a13acbf40d63d82f0218c. DR BioSample; SAMEA3865288. XX FH Key Location/Qualifiers FH FT source 1..1544 FT /organism="Vibrio anguillarum" FT /chromosome="1" FT /host="Rainbow trout" FT /strain="NB10" FT /mol_type="genomic DNA" FT /country="Sweden:Baltic Sea, Norrbyn Umeaa" FT /isolation_source="clinical isolate, Rainbow trout" FT /serovar="O1" FT /db_xref="taxon:55601" FT rRNA LK021130.1:74067..75610 FT /gene="16S" FT /product="16S rRNA" FT /note="16S rRNA subunit (checked and believed to be FT right,based on 454- and PacBio-sequencing)" XX SQ Sequence 1544 BP; 386 A; 344 C; 493 G; 321 T; 0 other; aattgaagag tttgatcatg gctcagattg aacgctggcg gcaggcctaa cacatgcaag 60 tcgagcggca gcacagagga acttgttcct tgggtggcga gcggcggacg ggtgagtaat 120 gcctaggaaa ttgccctgat gtgggggata accattggaa acgatggcta ataccgcatg 180 atgcctacgg gccaaagagg gggaccttct ggcctctcgc gtcaggatat gcctaggtgg 240 gattagctag ttggtgaggt aatggctcac caaggcgacg atccctagct ggtctgagag 300 gatgatcagc cacactggaa ctgagacacg gtccagactc ctacgggagg cagcagtggg 360 gaatattgca caatgggcgc aagcctgatg cagccatgcc gcgtgtatga agaaggcctt 420 cgggttgtaa agtactttca gtcgtgagga aggtggtgtt gttaatagca gcatcatttg 480 acgttagcga cagaagaagc accggctaac tccgtgccag cagccgcggt aatacggagg 540 gtgcgagcgt taatcggaat tactgggcgt aaagcgcatg caggtggtgg attaagtcag 600 atgtgaaagc ccggggctca acctcggaac cgcatttgaa actggttcac tagagtactg 660 tagagggggg tagaatttca ggtgtagcgg tgaaatgcgt agagatctga aggaataccg 720 gtggcgaagg cggccccctg gacagatact gacactcaga tgcgaaagcg tggggagcaa 780 acaggattag ataccctggt agtccacgcc gtaaacgatg tctacttgga ggttgtggcc 840 ttgagccgtg gctttcggag ctaacgcgtt aagtagaccg cctggggagt acggtcgcaa 900 gattaaaact caaatgaatt gacgggggcc cgcacaagcg gtggagcatg tggtttaatt 960 cgatgcaacg cgaagaacct tacctactct tgacatccag agaagccagc ggagacgcag 1020 gtgtgccttc gggagctctg agacaggtgc tgcatggctg tcgtcagctc gtgttgtgaa 1080 atgttgggtt aagtcccgca acgagcgcaa cccttatcct tgtttgccag cgagtcatgt 1140 cgggaactcc agggagactg ccggtgataa accggaggaa ggtggggacg acgtcaagtc 1200 atcatggccc ttacgagtag ggctacacac gtgctacaat ggcgcataca gagggcagca 1260 agctagcgat agtgagcgaa tcccaaaaag tgcgtcgtag tccggattgg agtctgcaac 1320 tcgactccat gaagtcggaa tcgctagtaa tcgtagatca gaatgctacg gtgaatacgt 1380 tcccgggcct tgtacacacc gcccgtcaca ccatgggagt gggctgcaaa agaagtgggt 1440 agtttaacct ttcggggagg acgctcacca ctttgtggtt catgactggg gtgaagtcgt 1500 aacaaggtag cgctagggga acctggcgct ggatcacctc ctta 1544 //scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embl_feature_level_record_no_FT000066400000000000000000000061241520735541300316260ustar00rootroot00000000000000ID LK021130.1:74067..75610:rRNA; SV 1; linear; genomic DNA; STD; PRO; 1544 BP. XX PA LK021130.1 XX PR Project:PRJEB5701; XX DT 02-JUN-2014 (Rel. 121, Created) DT 04-FEB-2016 (Rel. 127, Last updated, Version 5) XX DE Vibrio anguillarum 16S rRNA XX KW . XX OS Vibrio anguillarum OC Bacteria; Proteobacteria; Gammaproteobacteria; Vibrionales; Vibrionaceae; OC Vibrio. XX RN [1] RA Holm K.; RT ; RL Submitted (26-MAR-2014) to the INSDC. Norstruct, Dept of Chemistry, RL University of Tromso, Science Park 3, NO-9037 Tromso, NORWAY. XX RN [2] RX DOI; 10.1186/s40793-015-0060-7. RX PUBMED; 26380645. RA Holm K.O., Nilsson K., Hjerde E., Willassen N.P., Milton D.L.; RT "Complete genome sequence of Vibrio anguillarum strain NB10, a virulent RT isolate from the Gulf of Bothnia"; RL Stand Genomic Sci. 10:60-60(2015). XX DR SILVA-LSU; LK021130. DR SILVA-SSU; LK021130. DR MD5; afd116bf2c1a13acbf40d63d82f0218c. DR BioSample; SAMEA3865288. XX SQ Sequence 1544 BP; 386 A; 344 C; 493 G; 321 T; 0 other; aattgaagag tttgatcatg gctcagattg aacgctggcg gcaggcctaa cacatgcaag 60 tcgagcggca gcacagagga acttgttcct tgggtggcga gcggcggacg ggtgagtaat 120 gcctaggaaa ttgccctgat gtgggggata accattggaa acgatggcta ataccgcatg 180 atgcctacgg gccaaagagg gggaccttct ggcctctcgc gtcaggatat gcctaggtgg 240 gattagctag ttggtgaggt aatggctcac caaggcgacg atccctagct ggtctgagag 300 gatgatcagc cacactggaa ctgagacacg gtccagactc ctacgggagg cagcagtggg 360 gaatattgca caatgggcgc aagcctgatg cagccatgcc gcgtgtatga agaaggcctt 420 cgggttgtaa agtactttca gtcgtgagga aggtggtgtt gttaatagca gcatcatttg 480 acgttagcga cagaagaagc accggctaac tccgtgccag cagccgcggt aatacggagg 540 gtgcgagcgt taatcggaat tactgggcgt aaagcgcatg caggtggtgg attaagtcag 600 atgtgaaagc ccggggctca acctcggaac cgcatttgaa actggttcac tagagtactg 660 tagagggggg tagaatttca ggtgtagcgg tgaaatgcgt agagatctga aggaataccg 720 gtggcgaagg cggccccctg gacagatact gacactcaga tgcgaaagcg tggggagcaa 780 acaggattag ataccctggt agtccacgcc gtaaacgatg tctacttgga ggttgtggcc 840 ttgagccgtg gctttcggag ctaacgcgtt aagtagaccg cctggggagt acggtcgcaa 900 gattaaaact caaatgaatt gacgggggcc cgcacaagcg gtggagcatg tggtttaatt 960 cgatgcaacg cgaagaacct tacctactct tgacatccag agaagccagc ggagacgcag 1020 gtgtgccttc gggagctctg agacaggtgc tgcatggctg tcgtcagctc gtgttgtgaa 1080 atgttgggtt aagtcccgca acgagcgcaa cccttatcct tgtttgccag cgagtcatgt 1140 cgggaactcc agggagactg ccggtgataa accggaggaa ggtggggacg acgtcaagtc 1200 atcatggccc ttacgagtag ggctacacac gtgctacaat ggcgcataca gagggcagca 1260 agctagcgat agtgagcgaa tcccaaaaag tgcgtcgtag tccggattgg agtctgcaac 1320 tcgactccat gaagtcggaa tcgctagtaa tcgtagatca gaatgctacg gtgaatacgt 1380 tcccgggcct tgtacacacc gcccgtcaca ccatgggagt gggctgcaaa agaagtgggt 1440 agtttaacct ttcggggagg acgctcacca ctttgtggtt catgactggg gtgaagtcgt 1500 aacaaggtag cgctagggga acctggcgct ggatcacctc ctta 1544 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embl_multi_records000066400000000000000000000151351520735541300272360ustar00rootroot00000000000000ID M14399; SV 1; linear; mRNA; STD; PRO; 63 BP. XX AC M14399; XX DT 16-JUL-1988 (Rel. 16, Created) DT 02-SEP-1999 (Rel. 60, Last updated, Version 3) XX DE E.coli alkaline phosphatase signal mRNA, 5' end. XX KW alkaline phosphatase; signal peptide. XX OS Escherichia coli OC Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; OC Enterobacteriaceae; Escherichia. XX RN [1] RP 1-63 RX DOI; 10.1016/0378-1119(85)90319-1. RX PUBMED; 3912261. RA Gray G.L., Baldridge J.S., McKeown K.S., Heyneker H.L., Chang C.N.; RT "Periplasmic production of correctly processed human growth hormone in RT Escherichia coli: natural and bacterial signal sequences are RT interchangeable"; RL Gene 39(2-3):247-254(1985). XX DR MD5; c9b40131b8622946b5aafdf5473b3d43. XX FH Key Location/Qualifiers FH FT source 1..63 FT /db_xref="taxon:562" FT /mol_type="mRNA" FT /organism="Escherichia coli" FT CDS 1..>63 FT /db_xref="GOA:P00634" FT /db_xref="InterPro:IPR001952" FT /db_xref="InterPro:IPR017849" FT /db_xref="InterPro:IPR017850" FT /db_xref="InterPro:IPR018299" FT /db_xref="PDB:1AJA" FT /db_xref="PDB:1AJB" FT /db_xref="PDB:1AJC" FT /db_xref="PDB:1AJD" FT /db_xref="PDB:1ALH" FT /db_xref="PDB:1ALI" FT /db_xref="PDB:1ALJ" FT /db_xref="PDB:1ALK" FT /db_xref="PDB:1ANI" FT /db_xref="PDB:1ANJ" FT /db_xref="PDB:1B8J" FT /db_xref="PDB:1ED8" FT /db_xref="PDB:1ED9" FT /db_xref="PDB:1ELX" FT /db_xref="PDB:1ELY" FT /db_xref="PDB:1ELZ" FT /db_xref="PDB:1EW8" FT /db_xref="PDB:1EW9" FT /db_xref="PDB:1HJK" FT /db_xref="PDB:1HQA" FT /db_xref="PDB:1KH4" FT /db_xref="PDB:1KH5" FT /db_xref="PDB:1KH7" FT /db_xref="PDB:1KH9" FT /db_xref="PDB:1KHJ" FT /db_xref="PDB:1KHK" FT /db_xref="PDB:1KHL" FT /db_xref="PDB:1KHN" FT /db_xref="PDB:1URA" FT /db_xref="PDB:1URB" FT /db_xref="PDB:1Y6V" FT /db_xref="PDB:1Y7A" FT /db_xref="PDB:2ANH" FT /db_xref="PDB:2G9Y" FT /db_xref="PDB:2GA3" FT /db_xref="PDB:2MLX" FT /db_xref="PDB:2MLY" FT /db_xref="PDB:2MLZ" FT /db_xref="PDB:3BDF" FT /db_xref="PDB:3BDG" FT /db_xref="PDB:3BDH" FT /db_xref="PDB:3CMR" FT /db_xref="PDB:3DPC" FT /db_xref="PDB:3DYC" FT /db_xref="PDB:3TG0" FT /db_xref="PDB:4KM4" FT /db_xref="PDB:4YR1" FT /db_xref="PDB:5C66" FT /db_xref="PDB:5GAD" FT /db_xref="PDB:5GAF" FT /db_xref="PDB:5GAG" FT /db_xref="PDB:5GAH" FT /db_xref="PDB:5JTL" FT /db_xref="PDB:5JTM" FT /db_xref="PDB:5JTN" FT /db_xref="PDB:5JTO" FT /db_xref="PDB:5JTP" FT /db_xref="UniProtKB/Swiss-Prot:P00634" FT /note="alkaline phosphatase signal peptide" FT /codon_start=1 FT /protein_id="AAA23431.1" FT /transl_table=11 FT /translation="MKQSTIALAVLPLLFTPVTKA" XX SQ Sequence 63 BP; 17 A; 17 C; 12 G; 17 T; 0 other; gtgaaacaaa gcactattgc actggctgtc ttaccgttac tgtttacccc tgtgacaaaa 60 gcc 63 // ID KX454487; SV 1; linear; mRNA; STD; INV; 743 BP. XX AC KX454487; XX DT 02-FEB-2017 (Rel. 131, Created) DT 02-FEB-2017 (Rel. 131, Last updated, Version 1) XX DE Ruditapes philippinarum histone mRNA, complete cds. XX KW . XX OS Ruditapes philippinarum OC Eukaryota; Metazoa; Lophotrochozoa; Mollusca; Bivalvia; Heteroconchia; OC Euheterodonta; Veneroida; Veneroidea; Veneridae; Ruditapes. XX RN [1] RP 1-743 RA Yang D., Zhao J., Wang Q.; RT ; RL Submitted (27-JUN-2016) to the INSDC. Key Laboratory of Coastal Zone RL Environment Processes and Ecological Remediation, Yantai Institute of RL Coastal Zone Research (YIC), Chinese Academy of Sciences (CAS), 17 Chunhui RL Road, Laishan District, Yantai, Shandong 264003, China XX DR MD5; cbc730cf7a8d694b50fb7dd6b993ae0d. XX CC ##Assembly-Data-START## CC Sequencing Technology :: Sanger dideoxy sequencing CC ##Assembly-Data-END## XX FH Key Location/Qualifiers FH FT source 1..743 FT /db_xref="taxon:129788" FT /mol_type="mRNA" FT /organism="Ruditapes philippinarum" FT CDS 58..444 FT /codon_start=1 FT /product="histone" FT /protein_id="APY18893.1" FT /translation="MPGGKAGKDSGKAKAKAVSRSARAGLQFPVGRIHRHLKNRTTSHG FT RVGATAAVYSAAILEYLTAEVLELAGNASKDLKVKRITPRHLQLAIRGDEELDSLIKAT FT IAGGGVIPHIHKSLIGKKGGQQAK" XX SQ Sequence 743 BP; 241 A; 147 C; 145 G; 210 T; 0 other; tgtgcacagt ctacgcgtca tcttgaaaga aagaactaca ctactccaaa aataatcatg 60 cctggtggaa aagctggtaa agattccgga aaggccaagg ctaaggcagt gtcaaggtcc 120 gcaagagctg gcttacagtt tccagtcgga cgtattcaca ggcatttgaa gaacagaacc 180 actagccacg gtcgtgttgg agctacagca gccgtttaca gtgcagcaat ccttgaatac 240 ctgaccgccg aagtgcttga gttggctgga aacgcaagta aagatctcaa agtaaagaga 300 atcaccccac gtcacttgca gttggcaatc agaggagatg aagagttgga ttccctaatt 360 aaagccacaa tcgctggtgg tggtgttatt ccacatatcc acaagtcact tattggcaag 420 aagggaggtc agcaagccaa ataaattgga catactcatt catcagggaa caatgtgtag 480 tgaatgtgtt aaaaagaaca atctcattgt gtagctcttt agttttatat gaatgtgtta 540 acatggtcat tcacatcgta tgactcatag aatcatctgt gtatcatttc atcctctcat 600 tttatagctc ctcattttcc ttagactcat taaaattttt atctcggaaa aatgtttttt 660 ctacaatttt agcattcatt tatcttcatc ttgcttttat gtttaataaa acgaacttat 720 aataccaaaa aaaaaaaaaa aaa 743 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embl_single_record000066400000000000000000000100501520735541300271710ustar00rootroot00000000000000ID M14399; SV 1; linear; mRNA; STD; PRO; 63 BP. XX AC M14399; XX DT 16-JUL-1988 (Rel. 16, Created) DT 02-SEP-1999 (Rel. 60, Last updated, Version 3) XX DE E.coli alkaline phosphatase signal mRNA, 5' end. XX KW alkaline phosphatase; signal peptide. XX OS Escherichia coli OC Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; OC Enterobacteriaceae; Escherichia. XX RN [1] RP 1-63 RX DOI; 10.1016/0378-1119(85)90319-1. RX PUBMED; 3912261. RA Gray G.L., Baldridge J.S., McKeown K.S., Heyneker H.L., Chang C.N.; RT "Periplasmic production of correctly processed human growth hormone in RT Escherichia coli: natural and bacterial signal sequences are RT interchangeable"; RL Gene 39(2-3):247-254(1985). XX DR MD5; c9b40131b8622946b5aafdf5473b3d43. XX FH Key Location/Qualifiers FH FT source 1..63 FT /db_xref="taxon:562" FT /mol_type="mRNA" FT /organism="Escherichia coli" FT CDS 1..>63 FT /db_xref="GOA:P00634" FT /db_xref="InterPro:IPR001952" FT /db_xref="InterPro:IPR017849" FT /db_xref="InterPro:IPR017850" FT /db_xref="InterPro:IPR018299" FT /db_xref="PDB:1AJA" FT /db_xref="PDB:1AJB" FT /db_xref="PDB:1AJC" FT /db_xref="PDB:1AJD" FT /db_xref="PDB:1ALH" FT /db_xref="PDB:1ALI" FT /db_xref="PDB:1ALJ" FT /db_xref="PDB:1ALK" FT /db_xref="PDB:1ANI" FT /db_xref="PDB:1ANJ" FT /db_xref="PDB:1B8J" FT /db_xref="PDB:1ED8" FT /db_xref="PDB:1ED9" FT /db_xref="PDB:1ELX" FT /db_xref="PDB:1ELY" FT /db_xref="PDB:1ELZ" FT /db_xref="PDB:1EW8" FT /db_xref="PDB:1EW9" FT /db_xref="PDB:1HJK" FT /db_xref="PDB:1HQA" FT /db_xref="PDB:1KH4" FT /db_xref="PDB:1KH5" FT /db_xref="PDB:1KH7" FT /db_xref="PDB:1KH9" FT /db_xref="PDB:1KHJ" FT /db_xref="PDB:1KHK" FT /db_xref="PDB:1KHL" FT /db_xref="PDB:1KHN" FT /db_xref="PDB:1URA" FT /db_xref="PDB:1URB" FT /db_xref="PDB:1Y6V" FT /db_xref="PDB:1Y7A" FT /db_xref="PDB:2ANH" FT /db_xref="PDB:2G9Y" FT /db_xref="PDB:2GA3" FT /db_xref="PDB:2MLX" FT /db_xref="PDB:2MLY" FT /db_xref="PDB:2MLZ" FT /db_xref="PDB:3BDF" FT /db_xref="PDB:3BDG" FT /db_xref="PDB:3BDH" FT /db_xref="PDB:3CMR" FT /db_xref="PDB:3DPC" FT /db_xref="PDB:3DYC" FT /db_xref="PDB:3TG0" FT /db_xref="PDB:4KM4" FT /db_xref="PDB:4YR1" FT /db_xref="PDB:5C66" FT /db_xref="PDB:5GAD" FT /db_xref="PDB:5GAF" FT /db_xref="PDB:5GAG" FT /db_xref="PDB:5GAH" FT /db_xref="PDB:5JTL" FT /db_xref="PDB:5JTM" FT /db_xref="PDB:5JTN" FT /db_xref="PDB:5JTO" FT /db_xref="PDB:5JTP" FT /db_xref="UniProtKB/Swiss-Prot:P00634" FT /note="alkaline phosphatase signal peptide" FT /codon_start=1 FT /protein_id="AAA23431.1" FT /transl_table=11 FT /translation="MKQSTIALAVLPLLFTPVTKA" XX SQ Sequence 63 BP; 17 A; 17 C; 12 G; 17 T; 0 other; gtgaaacaaa gcactattgc actggctgtc ttaccgttac tgtttacccc tgtgacaaaa 60 gcc 63 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embl_single_record_lower000066400000000000000000000004201520735541300304010ustar00rootroot00000000000000ID M14399; SV 1; linear; mRNA; STD; PRO; 63 BP. XX SQ Sequence 63 BP; 17 A; 17 C; 12 G; 17 T; 0 other; gtgaaacaaa gcactattgc actggctgtc ttaccgttac tgtttacccc tgtgacaaaa 60 gcc 63 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embl_single_record_simple000066400000000000000000000076661520735541300305650ustar00rootroot00000000000000ID M14399; SV 1; linear; mRNA; ; PRO; 63 BP. XX AC M14399; XX DT 02-SEP-1999 XX DE E.coli alkaline phosphatase signal mRNA, 5' end. XX KW alkaline phosphatase; signal peptide. XX OS Escherichia coli OC Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; OC Enterobacteriaceae; Escherichia. XX RN [1] RP 1-63 RX PUBMED; 3912261. RA Gray G.L., Baldridge J.S., McKeown K.S., Heyneker H.L., Chang C.N.; RT "Periplasmic production of correctly processed human growth hormone in RT Escherichia coli: natural and bacterial signal sequences are RT interchangeable"; RL Gene 39(2-3):247-254(1985). XX DR MD5; c9b40131b8622946b5aafdf5473b3d43. XX FH Key Location/Qualifiers FH FT source 1..63 FT /db_xref="taxon:562" FT /mol_type="mRNA" FT /organism="Escherichia coli" FT CDS 1..>63 FT /db_xref="GOA:P00634" FT /db_xref="InterPro:IPR001952" FT /db_xref="InterPro:IPR017849" FT /db_xref="InterPro:IPR017850" FT /db_xref="InterPro:IPR018299" FT /db_xref="PDB:1AJA" FT /db_xref="PDB:1AJB" FT /db_xref="PDB:1AJC" FT /db_xref="PDB:1AJD" FT /db_xref="PDB:1ALH" FT /db_xref="PDB:1ALI" FT /db_xref="PDB:1ALJ" FT /db_xref="PDB:1ALK" FT /db_xref="PDB:1ANI" FT /db_xref="PDB:1ANJ" FT /db_xref="PDB:1B8J" FT /db_xref="PDB:1ED8" FT /db_xref="PDB:1ED9" FT /db_xref="PDB:1ELX" FT /db_xref="PDB:1ELY" FT /db_xref="PDB:1ELZ" FT /db_xref="PDB:1EW8" FT /db_xref="PDB:1EW9" FT /db_xref="PDB:1HJK" FT /db_xref="PDB:1HQA" FT /db_xref="PDB:1KH4" FT /db_xref="PDB:1KH5" FT /db_xref="PDB:1KH7" FT /db_xref="PDB:1KH9" FT /db_xref="PDB:1KHJ" FT /db_xref="PDB:1KHK" FT /db_xref="PDB:1KHL" FT /db_xref="PDB:1KHN" FT /db_xref="PDB:1URA" FT /db_xref="PDB:1URB" FT /db_xref="PDB:1Y6V" FT /db_xref="PDB:1Y7A" FT /db_xref="PDB:2ANH" FT /db_xref="PDB:2G9Y" FT /db_xref="PDB:2GA3" FT /db_xref="PDB:2MLX" FT /db_xref="PDB:2MLY" FT /db_xref="PDB:2MLZ" FT /db_xref="PDB:3BDF" FT /db_xref="PDB:3BDG" FT /db_xref="PDB:3BDH" FT /db_xref="PDB:3CMR" FT /db_xref="PDB:3DPC" FT /db_xref="PDB:3DYC" FT /db_xref="PDB:3TG0" FT /db_xref="PDB:4KM4" FT /db_xref="PDB:4YR1" FT /db_xref="PDB:5C66" FT /db_xref="PDB:5GAD" FT /db_xref="PDB:5GAF" FT /db_xref="PDB:5GAG" FT /db_xref="PDB:5GAH" FT /db_xref="PDB:5JTL" FT /db_xref="PDB:5JTM" FT /db_xref="PDB:5JTN" FT /db_xref="PDB:5JTO" FT /db_xref="PDB:5JTP" FT /db_xref="UniProtKB/Swiss-Prot:P00634" FT /note="alkaline phosphatase signal peptide" FT /codon_start=1 FT /protein_id="AAA23431.1" FT /transl_table=11 FT /translation="MKQSTIALAVLPLLFTPVTKA" XX SQ Sequence 63 BP; 17 A; 17 C; 12 G; 17 T; 0 other; gtgaaacaaa gcactattgc actggctgtc ttaccgttac tgtttacccc tgtgacaaaa 60 gcc 63 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embl_single_record_upper000066400000000000000000000005301520735541300304060ustar00rootroot00000000000000ID M14399; SV 1; linear; mRNA; STD; PRO; 63 BP. XX SQ Sequence 63 BP; 17 A; 17 C; 12 G; 17 T; 0 other; GTGAAACAAA GCACTATTGC ACTGGCTGTC TTACCGTTAC TGTTTACCCC TGTGACAAAA 60 GCC 63 63 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embl_uniprot_record000066400000000000000000000044351520735541300274220ustar00rootroot00000000000000ID 001R_FRG3G Reviewed; 256 AA. AC Q6GZX4; DT 28-JUN-2011, integrated into UniProtKB/Swiss-Prot. DT 19-JUL-2004, sequence version 1. DT 17-FEB-2016, entry version 31. DE RecName: Full=Putative transcription factor 001R; GN ORFNames=FV3-001R; OS Frog virus 3 (isolate Goorha) (FV-3). OC Viruses; dsDNA viruses, no RNA stage; Iridoviridae; Ranavirus. OX NCBI_TaxID=654924; OH NCBI_TaxID=8295; Ambystoma (mole salamanders). OH NCBI_TaxID=30343; Hyla versicolor (chameleon treefrog). OH NCBI_TaxID=8404; Lithobates pipiens (Northern leopard frog) (Rana pipiens). OH NCBI_TaxID=8316; Notophthalmus viridescens (Eastern newt) (Triturus viridescens). OH NCBI_TaxID=45438; Rana sylvatica (Wood frog). RN [1] RP NUCLEOTIDE SEQUENCE [LARGE SCALE GENOMIC DNA]. RX PubMed=15165820; DOI=10.1016/j.virol.2004.02.019; RA Tan W.G., Barkman T.J., Gregory Chinchar V., Essani K.; RT "Comparative genomic analyses of frog virus 3, type species of the RT genus Ranavirus (family Iridoviridae)."; RL Virology 323:70-84(2004). CC -!- FUNCTION: Transcription activation. {ECO:0000305}. DR EMBL; AY548484; AAT09660.1; -; Genomic_DNA. DR RefSeq; YP_031579.1; NC_005946.1. DR ProteinModelPortal; Q6GZX4; -. DR SwissPalm; Q6GZX4; -. DR GeneID; 2947773; -. DR KEGG; vg:2947773; -. DR Proteomes; UP000008770; Genome. DR GO; GO:0006355; P:regulation of transcription, DNA-templated; IEA:UniProtKB-KW. DR GO; GO:0046782; P:regulation of viral transcription; IEA:InterPro. DR GO; GO:0006351; P:transcription, DNA-templated; IEA:UniProtKB-KW. DR InterPro; IPR007031; Poxvirus_VLTF3. DR Pfam; PF04947; Pox_VLTF3; 1. PE 4: Predicted; KW Activator; Complete proteome; Reference proteome; Transcription; KW Transcription regulation. FT CHAIN 1 256 Putative transcription factor 001R. FT /FTId=PRO_0000410512. FT COMPBIAS 14 17 Poly-Arg. SQ SEQUENCE 256 AA; 29735 MW; B4840739BF7D4121 CRC64; MAFSAEDVLK EYDRRRRMEA LLLSLYYPND RKLLDYKEWS PPRVQVECPK APVEWNNPPS EKGLIVGHFS GIKYKGEKAQ ASEVDVNKMC CWVSKFKDAM RRYQGIQTCK IPGKVLSDLD AKIKAYNLTV EGVEGFVRYS RVTKQHVAAF LKELRHSKQY ENVNLIHYIL TDKRVDIQHL EKDLVKDFKA LVESAHRMRQ GHMINVKYIL YQLLKKHGHG PDGPDILTVK TGSKGVLYDD SFRKIYTDLG WKFTPL // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/embl_w_beginning_whitespace000066400000000000000000000004221520735541300310560ustar00rootroot00000000000000 ID M14399; SV 1; linear; mRNA; STD; PRO; 63 BP. XX SQ Sequence 63 BP; 17 A; 17 C; 12 G; 17 T; 0 other; gtgaaacaaa gcactattgc actggctgtc ttaccgttac tgtttacccc tgtgacaaaa 60 gcc 63 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/empty000066400000000000000000000000001520735541300245030ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_diff_ids.fastq000066400000000000000000000011401520735541300274500ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_124 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_double_qual.fastq000066400000000000000000000012351520735541300302020ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_double_seq.fastq000066400000000000000000000012351520735541300300300ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_long_qual.fastq000066400000000000000000000011411520735541300276630ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWYY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_no_qual.fastq000066400000000000000000000007421520735541300273460ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGC +SLXA-B3_649_FC8437_R1_1_1_850_123 @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_qual_del.fastq000066400000000000000000000011401520735541300274670ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_qual_escape.fastq000066400000000000000000000011401520735541300301630ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_qual_null.fastq000066400000000000000000000011421520735541300276770ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_qual_space.fastq000066400000000000000000000011411520735541300300170ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYY WWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_qual_tab.fastq000066400000000000000000000011411520735541300274720ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYY YYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_qual_unit_sep.fastq000066400000000000000000000011401520735541300305510ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_qual_vtab.fastq000066400000000000000000000011401520735541300276570ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYY YYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_short_qual.fastq000066400000000000000000000011371520735541300300700ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYS @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_spaces.fastq000066400000000000000000000011641520735541300271650ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAA TACCTTTGTA GAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYY YYYYYYYYYW YWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGA AAGAGAAATG AGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYY WYYYYWWYYY WYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTT GATCATGATG ATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYY YYYYWYYWYY SYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAA GTTTTTCTCA ACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYY YYYYYYYYYW WWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTT AATGGCATAC ACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYY YWYYYYWYWW UWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_tabs.fastq000066400000000000000000000011651520735541300266410ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAA TACCTTTGTA GAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYY YYYYYYYYYW YWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGA AAGAGAAATG AGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYY WYYYYWWYYY WYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTT GATCATGATG ATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYY YYYYWYYWYY SYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAA GTTTTTCTCA ACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYY YYYYYYYYYW WWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTT AATGGCATAC ACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYY YWYYYYWYWW UWWWQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_trunc_at_plus.fastq000066400000000000000000000010441520735541300305660ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_trunc_at_qual.fastq000066400000000000000000000011061520735541300305440ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_trunc_at_seq.fastq000066400000000000000000000010121520735541300303660ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_trunc_in_plus.fastq000066400000000000000000000010621520735541300305700ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FCscikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_trunc_in_qual.fastq000066400000000000000000000011371520735541300305520ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGCATACACTCAA +SLXA-B3_649_FC8437_R1_1_1_183_714 YYYYYYYYYYWYYYYWYWWUWWWQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_trunc_in_seq.fastq000066400000000000000000000010271520735541300303760ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_183_714 GTATTATTTAATGGscikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/error_trunc_in_title.fastq000066400000000000000000000010011520735541300307170ustar00rootroot00000000000000@SLXA-B3_649_FC8437_R1_1_1_610_79 GATGTGCAATACCTTTGTAGAGGAA +SLXA-B3_649_FC8437_R1_1_1_610_79 YYYYYYYYYYYYYYYYYYWYWYYSU @SLXA-B3_649_FC8437_R1_1_1_397_389 GGTTTGAGAAAGAGAAATGAGATAA +SLXA-B3_649_FC8437_R1_1_1_397_389 YYYYYYYYYWYYYYWWYYYWYWYWW @SLXA-B3_649_FC8437_R1_1_1_850_123 GAGGGTGTTGATCATGATGATGGCG +SLXA-B3_649_FC8437_R1_1_1_850_123 YYYYYYYYYYYYYWYYWYYSYYYSY @SLXA-B3_649_FC8437_R1_1_1_362_549 GGAAACAAAGTTTTTCTCAACATAG +SLXA-B3_649_FC8437_R1_1_1_362_549 YYYYYYYYYYYYYYYYYYWWWWYWY @SLXA-B3_649_FC8437_R1_1_1_scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_10_seqs000066400000000000000000000002561520735541300260130ustar00rootroot00000000000000>seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 A C GT >seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 AC G T scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_3_seqs_defaults000066400000000000000000000000771520735541300276250ustar00rootroot00000000000000>s_e_q_1 desc 1 UUUU >s_e_q_2 desc 2 CATC >s_e_q_3 desc 3 sits scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_3_seqs_non_defaults000066400000000000000000000001021520735541300304640ustar00rootroot00000000000000>s*e*q*1 desc+1 UUU U >s*e*q*2 desc+2 CAT C >s*e*q*3 desc+3 sit s scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_5_blanks_start_of_file000066400000000000000000000002261520735541300311330ustar00rootroot00000000000000 >seq1 desc1 ACGT-acgt. >_____seq__2_ A > desc3 AACGGuA > ACGTTGCAccGG > ACGUU >proteinseq detailed description with new lines pQqqqPPQQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_5_ws_lines_start_of_file000066400000000000000000000003151520735541300315030ustar00rootroot00000000000000 >seq1 desc1 ACGT-acgt. >_____seq__2_ A > desc3 AACGGuA > ACGTTGCAccGG > ACGUU >proteinseq detailed description with new lines pQqqqPPQQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_6_blanks_start_of_file000066400000000000000000000002271520735541300311350ustar00rootroot00000000000000 >seq1 desc1 ACGT-acgt. >_____seq__2_ A > desc3 AACGGuA > ACGTTGCAccGG > ACGUU >proteinseq detailed description with new lines pQqqqPPQQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_6_ws_lines_start_of_file000066400000000000000000000003311520735541300315020ustar00rootroot00000000000000 >seq1 desc1 ACGT-acgt. >_____seq__2_ A > desc3 AACGGuA > ACGTTGCAccGG > ACGUU >proteinseq detailed description with new lines pQqqqPPQQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_blank_lines_between_records000066400000000000000000000002351520735541300322500ustar00rootroot00000000000000>seq1 desc1 ACGT-acgt. >_____seq__2_ A > desc3 AACGGuA > ACGTTGCAccGG > ACGUU >proteinseq detailed description with new lines pQqqqPPQQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_blanks_end_of_file000066400000000000000000000002301520735541300303130ustar00rootroot00000000000000>seq1 desc1 ACGT-acgt. >_____seq__2_ A > desc3 AACGGuA > ACGTTGCAccGG > ACGUU >proteinseq detailed description with new lines pQqqqPPQQQ fasta_description_newline_replacement_empty_str000066400000000000000000000001131520735541300352020ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data>proteinseq detaileddescription with newlines pQqqqPPQQQ >foo AGGAGAATA fasta_description_newline_replacement_multi_char000066400000000000000000000001551520735541300353110ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data>proteinseq :-)detailed:-)description with new:-):-)lines:-):-):-) pQqqqPPQQQ >foo :-):-):-):-) AGGAGAATA scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_description_newline_replacement_none000066400000000000000000000001271520735541300341770ustar00rootroot00000000000000>proteinseq detailed description with new lines pQqqqPPQQQ >foo AGGAGAATA scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_id_whitespace_replacement_empty_str000066400000000000000000000000211520735541300340230ustar00rootroot00000000000000>seq2 A > a b UA scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_id_whitespace_replacement_multi_char000066400000000000000000000000651520735541300341340ustar00rootroot00000000000000>>:o>:o>:o>:o>:oseq>:o>:o2>:o A >>:o>:o>:o>:o a b UA scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_id_whitespace_replacement_none000066400000000000000000000000351520735541300327410ustar00rootroot00000000000000> seq 2 A > a b UA scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_after_10_seqs000066400000000000000000000002721520735541300307000ustar00rootroot00000000000000>seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 A C GT >seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 ACGT >seq1 desc1 AC G T >seq1 desc1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_blank_line_after_header000066400000000000000000000000641520735541300330320ustar00rootroot00000000000000>seq1 desc1 ACGT >seq2 desc2 AAAAA >seq3 desc3 CCC scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_blank_line_within_sequence000066400000000000000000000001001520735541300336020ustar00rootroot00000000000000>seq1 desc1 ACGT >seq2 desc2 AAA AA >seq3 desc3 CCC scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_blank_sequence000066400000000000000000000000561520735541300312230ustar00rootroot00000000000000>seq1 desc1 ACGT >seq2 desc2 >seq3 desc3 CCC scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_legacy_format000066400000000000000000000000501520735541300310520ustar00rootroot00000000000000; legacy-seq-id legacy description ACGT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_missing_header000066400000000000000000000000201520735541300312140ustar00rootroot00000000000000seq1 desc1 ACGT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_missing_seq_data_first000066400000000000000000000000561520735541300327650ustar00rootroot00000000000000>seq1 desc1 >seq2 desc2 AAAAA >seq3 desc3 CCC scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_missing_seq_data_last000066400000000000000000000000571520735541300326020ustar00rootroot00000000000000>seq1 desc1 ACGT >seq2 desc2 AAAAA >seq3 desc3 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_missing_seq_data_middle000066400000000000000000000000551520735541300330730ustar00rootroot00000000000000>seq1 desc1 ACGT >seq2 desc2 >seq3 desc3 CCC scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_whitespace_line_after_header000066400000000000000000000000771520735541300341030ustar00rootroot00000000000000>seq1 desc1 ACGT >seq2 desc2 AAAAA >seq3 desc3 CCC fasta_invalid_whitespace_only_line_within_sequence000066400000000000000000000001051520735541300356360ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data>seq1 desc1 ACGT >seq2 desc2 AAAAA AAAAA >seq3 desc3 CCC scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_invalid_whitespace_only_sequence000066400000000000000000000000711520735541300333260ustar00rootroot00000000000000>seq1 desc1 ACGT >seq2 desc2 >seq3 desc3 CCC scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_max_width_1000066400000000000000000000000401520735541300267330ustar00rootroot00000000000000>seq1 desc1 A C G T - a c g t . scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_max_width_5000066400000000000000000000002261520735541300267450ustar00rootroot00000000000000>seq1 desc1 ACGT- acgt. >_____seq__2_ A > desc3 AACGG uA > ACGTT GCAcc GG > ACGUU >proteinseq detailed description with new lines pQqqq PPQQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_mixed_qual_scores000066400000000000000000000000631520735541300302420ustar00rootroot00000000000000>seq1 desc1 ACGT-acgt. >da,dadadada 10 hours AAAAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_multi_seq000066400000000000000000000002211520735541300265320ustar00rootroot00000000000000>seq1 desc1 ACGT-acgt. >_____seq__2_ A > desc3 AACGGuA > ACGTTGCAccGG > ACGUU >proteinseq detailed description with new lines pQqqqPPQQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_multi_seq_roundtrip000066400000000000000000000001621520735541300306440ustar00rootroot00000000000000>seq-a a's description ACATAGGTA >seq-b b's description TAGATAGATAGA >seq-c c's description CATCATCATCATCATCATCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_multi_seq_spaces000066400000000000000000000002351520735541300300750ustar00rootroot00000000000000>seq1 desc1 ACGT - acgt. >_____seq__2_ A > desc3 AAC GGu A > ACGTTGCAccGG > A CG UU >proteinseq detailed description with new lines pQ q q q P P QQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_prot_seqs_odd_labels000066400000000000000000000001201520735541300307150ustar00rootroot00000000000000> DEFQ fp > skbio S K B I scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_single_bio_seq_defaults000066400000000000000000000000221520735541300314000ustar00rootroot00000000000000>f_o_o b a r ACgt scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_single_bio_seq_non_defaults000066400000000000000000000000251520735541300322550ustar00rootroot00000000000000>f-o-o b_a_r A C g t scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_single_dna_seq_defaults000066400000000000000000000000221520735541300313710ustar00rootroot00000000000000>f_o_o b a r TAcg scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_single_dna_seq_non_defaults000066400000000000000000000000251520735541300322460ustar00rootroot00000000000000>f-o-o b_a_r T A c g scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_single_prot_seq_defaults000066400000000000000000000000211520735541300316120ustar00rootroot00000000000000>f_o_o b a r PqQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_single_prot_seq_non_defaults000066400000000000000000000000231520735541300324660ustar00rootroot00000000000000>f-o-o b_a_r P q Q scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_single_rna_seq_defaults000066400000000000000000000000221520735541300314070ustar00rootroot00000000000000>f_o_o b a r uaCG scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_single_rna_seq_non_defaults000066400000000000000000000000251520735541300322640ustar00rootroot00000000000000>f-o-o b_a_r u a C G scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_single_seq000066400000000000000000000000271520735541300266650ustar00rootroot00000000000000>seq1 desc1 ACGT-acgt. scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_tabular_msa_different_type000066400000000000000000000001101520735541300321060ustar00rootroot00000000000000> aUG >rnaseq-1 rnaseq desc 1 AuC >rnaseq-2 rnaseq desc 2 AUg scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_ws_lines_between_records000066400000000000000000000004251520735541300316130ustar00rootroot00000000000000>seq1 desc1 ACGT-acgt. >_____seq__2_ A > desc3 AACGGuA > ACGTTGCAccGG > ACGUU >proteinseq detailed description with new lines pQqqqPPQQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fasta_ws_lines_end_of_file000066400000000000000000000003511520735541300306700ustar00rootroot00000000000000>seq1 desc1 ACGT-acgt. >_____seq__2_ A > desc3 AACGGuA > ACGTTGCAccGG > ACGUU >proteinseq detailed description with new lines pQqqqPPQQQ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_5_blanks_start_of_file000066400000000000000000000001341520735541300311510ustar00rootroot00000000000000 @foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_5_ws_lines_start_of_file000066400000000000000000000002231520735541300315210ustar00rootroot00000000000000 @foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_blank_lines000066400000000000000000000001321520735541300270320ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_blank_after_header000066400000000000000000000001301520735541300320350ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_blank_after_plus000066400000000000000000000001301520735541300315700ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_blank_after_seq000066400000000000000000000001301520735541300313750ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_blank_in_seq_at_symbol000066400000000000000000000001311520735541300327540ustar00rootroot00000000000000@foo bar baz AACCGG + MNO @QR @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_blank_within_qual000066400000000000000000000001311520735541300317510ustar00rootroot00000000000000@foo bar baz AACCGG + MNO PQR @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_blank_within_seq000066400000000000000000000001311520735541300315770ustar00rootroot00000000000000@foo bar baz AAC CGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_missing_header000066400000000000000000000000271520735541300312430ustar00rootroot00000000000000seq1 desc1 ACGT + 1234 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_missing_seq_data000066400000000000000000000001471520735541300315770ustar00rootroot00000000000000@seq-1 first sequence ACG T + [[[[ @seq-2 second sequence T GCAC + [[[[[ @seq-3 third sequence + [[[[[ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_ws_line_after_header000066400000000000000000000001431520735541300324120ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_ws_line_after_plus000066400000000000000000000001431520735541300321450ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_ws_line_after_seq000066400000000000000000000001431520735541300317520ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_ws_line_within_qual000066400000000000000000000001441520735541300323260ustar00rootroot00000000000000@foo bar baz AACCGG + MNO PQR @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_invalid_ws_line_within_seq000066400000000000000000000001441520735541300321540ustar00rootroot00000000000000@foo bar baz AAC CGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_multi_blank_between_records000066400000000000000000000001371520735541300323110ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_multi_blank_end_of_file000066400000000000000000000001361520735541300313670ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_multi_blank_start_of_file000066400000000000000000000001351520735541300317550ustar00rootroot00000000000000 @foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_multi_seq_sanger000066400000000000000000000001271520735541300301160ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_multi_whitespace_stripping000066400000000000000000000005131520735541300322210ustar00rootroot00000000000000 @foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_multi_ws_lines_between_records000066400000000000000000000002371520735541300330460ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_multi_ws_lines_end_of_file000066400000000000000000000002671520735541300321300ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_multi_ws_lines_start_of_file000066400000000000000000000002371520735541300325140ustar00rootroot00000000000000 @foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_single_seq_illumina1.3000066400000000000000000000000411520735541300310150ustar00rootroot00000000000000@ bar baz a C G T + a b c d scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_single_seq_illumina1.8000066400000000000000000000001661520735541300310320ustar00rootroot00000000000000@EAS139:136:FC706VJ:2:2104:15343:197393 1:Y:18:ATCACG CCGCCGGTCATCCAATTCATTGCGAAAGGT + n%OiP]XgBh]u:9jO|KN4Op~7Ry;-&. scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_whitespace_only_lines000066400000000000000000000001731520735541300311450ustar00rootroot00000000000000@foo bar baz AACCGG + 123456 @bar baz foo TTGGCC + 876543 @baz foo bar GATTTC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_wrapping_as_illumina_no_description000066400000000000000000000015651520735541300340670ustar00rootroot00000000000000@SRR014849.50939 GAAATTTCAGGGCCACCTTTTTTTTGATAGAATAATGGAGAAAATTAAAAGCTGTACATATACCAATGAACAATAAATCAATACATAAAAAAGGAGAAGTTGGAACCGAAAGGGTTTGAATTCAAACCCTTTCGG + Zb^Ld`N\[d`NaZ[aZc]UOKHDA[\YT[_W[aZ\aZ[Zd`SF_WeaUI[Y\[[\\\[\Z\aY`X[[aZ\aZ\d`OY[aY[[\[[e`WPJC^UZ[`X\[R]T_V_W[`[Ga\I`\H[[Q^TVa\Ia\Ic^LY\S @SRR014849.110027 CTTCAAATGATTCCGGGACTGTTGGAACCGAAAGGGTTTGAATTCAAACCCTTTTCGGTTCCAACTCGCCGTCCGAATAATCCGTTCAAAATCTTGGCCTGTCAAAACGACTTTACGACCAGAACGATCCG + \aYY_[FY\T`X^Vd`OY\[[^U_V[R^T[_ZDc^La\HYYO\S[c^Ld`Nc_QAZaZaYaY`XZZ\[aZZ[aZ[aZ[aZY`Z[`ZWeaVJ\[aZaY`X[PY\eaUG[\[[d`OXTUZ[Q\\`W\\\Y_W\ @SRR014849.203935 AACCCGTCCCATCAAAGATTTTGGTTGGAACCCGAAAGGGTTTTGAATTCAAACCCCTTTCGGTTCCAACTATTCAATTGTTTAACTTTTTTTAAATTGATGGTCTGTTGGACCATTTGTAATAATCCCCATCGGAATTTCTTT + `Z_ZDVT^YB[[Xd`PZ\d`RDaZaZ`ZaZ_ZDXd`Pd`Pd`RD[aZ`ZWd`Oc_RCd`P\aZ`ZaZaZY\YaZYaY`XYd`O`X[e`WPJEAc^LaZS[YYN[Z\Y`XWLT^U\b]JW[[RZ\SYc`RD[Z\WLXM`\HYa\I scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_wrapping_as_sanger_no_description000066400000000000000000000015651520735541300335340ustar00rootroot00000000000000@SRR014849.50939 GAAATTTCAGGGCCACCTTTTTTTTGATAGAATAATGGAGAAAATTAAAAGCTGTACATATACCAATGAACAATAAATCAATACATAAAAAAGGAGAAGTTGGAACCGAAAGGGTTTGAATTCAAACCCTTTCGG + ;C?-EA/=60,)%"<=:5<@85@7@8+8<<3;=4:DA3%<;=8-9.A=):B=* fastq_wrapping_original_sanger_no_description000066400000000000000000000016021520735541300346460ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data@SRR014849.50939 GAAATTTCAGGGCCACCTTTTTTTTGATAGAATAATGGAGAAAATTAAAAGCTGTACATATACCAATGAACAATAAATCAATACATAAAAAAGGAGAAGTTGGAACCGAAAGGGTTTGAATTCAAACCCTTTCGG + ;C?-EA/=60,)%"<=:5< @85@7@8+8< <3;=4:DA3%<;=8-9.A=):B=* scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_writer_illumina1.3_defaults000066400000000000000000000001361520735541300320740ustar00rootroot00000000000000@f_o__o bar baz AaCcGg + PQRSTU @bar baz foo TtGgCc + WVUTSR @ba___z foo bar gAtTtC + TUVWXR scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_writer_sanger_defaults000066400000000000000000000001361520735541300313170ustar00rootroot00000000000000@f_o__o bar baz AaCcGg + 123456 @bar baz foo TtGgCc + 876543 @ba___z foo bar gAtTtC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/fastq_writer_sanger_non_defaults000066400000000000000000000001361520735541300321710ustar00rootroot00000000000000@f%o%%o bar^^baz AaCcGg + 123456 @bar baz foo TtGgCc + 876543 @ba%%%z foo bar gAtTtC + 567893 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/genbank_5_blanks_start_of_file000066400000000000000000000001251520735541300314400ustar00rootroot00000000000000 LOCUS NC_000932 154478 bp DNA circular PLN 15-APR-2009 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/genbank_6_blanks_start_of_file000066400000000000000000000001261520735541300314420ustar00rootroot00000000000000 LOCUS NC_000932 154478 bp DNA circular PLN 15-APR-2009 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/genbank_missing_locus_name000066400000000000000000000001071520735541300307200ustar00rootroot00000000000000LOCUS 154478 bp DNA circular PLN 15-APR-2009 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/genbank_multi_records000066400000000000000000000030761520735541300277250ustar00rootroot00000000000000LOCUS AAB29917 9 aa linear BCT 23-SEP-1994 DEFINITION L-carnitine amidase {N-terminal} ACCESSION AAB29917 VERSION AAB29917.1 GI:545426 DBSOURCE accession AAB29917.1 KEYWORDS . SOURCE Bacteria ORGANISM Bacteria Unclassified. REFERENCE 1 (residues 1 to 9) AUTHORS Joeres,U. and Kula,M.R. TITLE a microbial L-carnitine amidase JOURNAL AMB 40 (5), 606-610 (1994) PUBMED 7764422 REMARK from the original journal article. REFERENCE 1 (residues 1 to 9) AUTHORS Joeres,U. and Kula,M.R. TITLE a microbial L-carnitine amidase JOURNAL AMB 40 (5), 606-610 (1994) PUBMED 7764422 COMMENT Method: direct peptide sequencing. FEATURES Location/Qualifiers source 1..9 /organism="Bacteria" Protein 1..>9 /product="L-carnitine amidase" ORIGIN 1 gsreildfk // LOCUS HQ018078 9 bp DNA linear ENV 29-AUG-2010 DEFINITION Uncultured Xylanimonas sp.16S, partial ACCESSION HQ018078 VERSION HQ018078.1 GI:304421728 KEYWORDS ENV. SOURCE uncultured Xylanimonas sp. ORGANISM uncultured Xylanimonas sp. Bacteria; Actinobacteria; Micrococcales; Promicromonosporaceae; Xylanimonas; environmental samples. FEATURES Location/Qualifiers source 1..9 /country="Brazil: Parana, Paranavai" /environmental_sample rRNA complement(<2..>8) /product="16S ribosomal RNA" ORIGIN 1 catgcaggc // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/genbank_single_record000066400000000000000000000020761520735541300276700ustar00rootroot00000000000000LOCUS ECOALKP 63 bp mRNA linear BCT 26-APR-1993 DEFINITION alkaline phosphatase signal mRNA, 5' end. ACCESSION M14399 VERSION M14399.1 KEYWORDS alkaline phosphatase; signal peptide. SOURCE Escherichia coli ORGANISM Escherichia coli Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacteriales; Enterobacteriaceae; Escherichia. COMMENT Original source text: E.coli, cDNA to mRNA. FEATURES Location/Qualifiers source 1..63 /db_xref="taxon:562" /mol_type="mRNA" /organism="Escherichia coli" CDS 1..>63 /db_xref="taxon:562" /db_xref="taxon:561" /note="alkaline phosphatase signal peptide" /codon_start=1 /protein_id="AAA23431.1" /transl_table=11 /translation="MKQSTIALAVLPLLFTPVTKA" ORIGIN 1 gtgaaacaaa gcactattgc actggctgtc ttaccgttac tgtttacccc tgtgacaaaa 61 gcc // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/genbank_single_record_lower000066400000000000000000000001321520735541300310670ustar00rootroot00000000000000LOCUS AAB29917 9 aa linear BCT 23-SEP-1994 ORIGIN 1 gsreildfk // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/genbank_single_record_upper000066400000000000000000000001321520735541300310720ustar00rootroot00000000000000LOCUS AAB29917 9 aa linear BCT 23-SEP-1994 ORIGIN 1 GSREILDFK // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/genbank_w_beginning_whitespace000066400000000000000000000001221520735541300315410ustar00rootroot00000000000000 LOCUS NC_000932 154478 bp DNA circular PLN 15-APR-2009 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/gff3_bad_missing_directive000066400000000000000000000003161520735541300306010ustar00rootroot00000000000000##sequence-region ctg123 1 1497228 ctg123 . gene 1000 9000 . + . ID=gene00001;Name=EDEN ctg123 . TF_binding_site 1000 1012 . + . Parent=gene00001 ctg123 . mRNA 1050 9000 . + . ID=mRNA00001;Parent=gene00001 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/gff3_bad_wrong_columns000066400000000000000000000007131520735541300277670ustar00rootroot00000000000000##gff-version 3 ##sequence-region Chromosome 1 4641652 #!genome-build European Nucleotide Archive ASM584v2 #!genome-version ASM584v2 #!genome-date 2014-08 #!genome-build-accession GCA_000005845.2 #!genebuild-last-updated 2014-08 Chromosome chromosome 1 4641652 . . . ID=chromosome:Chromosome;Alias=U00096.3;Is_circular=true ### Chromosome biological_region 148 148 . + . external_name=Promoter thrLp (RegulonDB:ECK120010236);logic_name=regulondb_promoter scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/gff3_dna000066400000000000000000000001521520735541300250240ustar00rootroot00000000000000##gff-version 3 NC_1 Prodigal_v2.60 gene 1 9 . + 0 ID=gene1;Name=FXR ##FASTA >NC_1 species X ATGCATGCATGC scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/gff3_multi_record000066400000000000000000000015611520735541300267570ustar00rootroot00000000000000##gff-version 3 ##sequence-region Chromosome 1 4641652 #!genome-build European Nucleotide Archive ASM584v2 #!genome-version ASM584v2 #!genome-date 2014-08 #!genome-build-accession GCA_000005845.2 #!genebuild-last-updated 2014-08 Chromosome European Nucleotide Archive chromosome 1 4641652 . . . Alias=U00096.3;ID=chromosome:Chromosome;Is_circular=true ### Chromosome regulondb_feature biological_region 148 148 . + . external_name=Promoter thrLp (RegulonDB:ECK120010236);logic_name=regulondb_promoter gi|556503834|ref|NC_000913.3| Prodigal_v2.60 gene 337 2799 1.8 + 0 ID=1_1;gc_cont=0.427 gi|556503834|ref|NC_000913.3| Prodigal_v2.60 CDS 337 2799 333.8 + 0 ID=1_2;Parent=1_1;rbs_motif=GGAG/GAGG;rbs_spacer=5-10bp NC 7 Prodigal_v2.60 gene 1 100 1.8 + 0 ID=1_1;gene=FXR receptor NC 7 Prodigal_v2.60 exon 1 50 1.8 + 0 Parent=1_1 NC 7 Prodigal_v2.60 exon 56 100 1.8 + 0 Parent=1_1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/gff3_single_record000066400000000000000000000007711520735541300271100ustar00rootroot00000000000000##gff-version 3 ##sequence-region Chromosome 1 4641652 #!genome-build European Nucleotide Archive ASM584v2 #!genome-version ASM584v2 #!genome-date 2014-08 #!genome-build-accession GCA_000005845.2 #!genebuild-last-updated 2014-08 Chromosome European Nucleotide Archive chromosome 1 4641652 . . . Alias=U00096.3;ID=chromosome:Chromosome;Is_circular=true ### Chromosome regulondb_feature biological_region 148 148 . + . external_name=Promoter thrLp (RegulonDB:ECK120010236);logic_name=regulondb_promoter scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/illumina_full_range_as_illumina.fastq000066400000000000000000000006521520735541300330640ustar00rootroot00000000000000@FAKE0005 Original version has PHRED scores from 0 to 62 inclusive (in that order) ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACG + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ @FAKE0006 Original version has PHRED scores from 62 to 0 inclusive (in that order) GCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCA + ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/illumina_full_range_as_sanger.fastq000066400000000000000000000006521520735541300325310ustar00rootroot00000000000000@FAKE0005 Original version has PHRED scores from 0 to 62 inclusive (in that order) ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACG + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ @FAKE0006 Original version has PHRED scores from 62 to 0 inclusive (in that order) GCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCA + _^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"! scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/illumina_full_range_original_illumina.fastq000066400000000000000000000006521520735541300342650ustar00rootroot00000000000000@FAKE0005 Original version has PHRED scores from 0 to 62 inclusive (in that order) ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACG + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ @FAKE0006 Original version has PHRED scores from 62 to 0 inclusive (in that order) GCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCA + ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/legacy9_and_blast7_default000066400000000000000000000007711520735541300305230ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query2 # Subject: subject2 # Fields: query id, subject id, % identity, alignment length, mismatches, gap opens, q. start, q. end, s. start, s. end, evalue, bit score # 1 hits found query2 subject2 100.00 8 0 1 0 9 3 10 2e-05 9.8 # BLASTN 2.2.3 [May-13-2002] # Database: other_vertebrate # Query: query2 # Fields: Query id,Subject id,% identity,alignment length,mismatches,gap opens,q. start,q. end,s. start,s. end,evalue,bit score query2 subject1 70.00 9 1 0 1 8 4 9 0.025 11.7 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/legacy9_invalid_differing_fields000066400000000000000000000006241520735541300317670ustar00rootroot00000000000000# BLASTP 2.2.31+ # Query: query1 # Subject: subject1 # 0 hits found # BLASTP 2.2.31+ # Query: query1 # Subject: subject3 # 0 hits found # BLASTP 2.2.31+ # Query: query2 # Subject: subject1 # Fields: query id, subject id, q. start # 1 hits found query1 subject1 4 # BLASTP 2.2.3 [May-13-2002] # Database: other_vertebrate # Subject: subject1 # Fields: Query id,Subject id,subject ids query2 subject1 N/A scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/legacy9_invalid_too_many_columns000066400000000000000000000004061520735541300320670ustar00rootroot00000000000000# BLASTN 2.2.3 [May-13-2002] # Database: other_vertebrate # Query: AF178033 # Fields: Query id,Subject id,% identity,alignment length,mismatches,gap openings,q. start,q. end,s. start,s. end,e-value,bit score query1 subject1 80.00 7 2 0 0 9 4 9 0.023 14.4 0.145 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/legacy9_mixed_nans000066400000000000000000000004501520735541300271200ustar00rootroot00000000000000# BLASTN 2.2.3 [May-13-2002] # Database: other_vertebrate # Query: query2 # Fields: Query id,Subject id,% identity,alignment length,mismatches,gap opens,q. start,q. end,s. start,s. end,evalue,bit score N/A subject1 N/A 7 1 0 N/A 8 4 10 N/A 15.5 query2 subject1 90.00 8 N/A 0 0 8 N/A 9 1e-05 N/A scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/legacy9_multi_line000066400000000000000000000005311520735541300271340ustar00rootroot00000000000000# BLASTN 2.2.3 [May-13-2002] # Database: other_vertebrate # Query: query1 # Fields: Query id,Subject id,% identity,alignment length,mismatches,gap opens,q. start,q. end,s. start,s. end,evalue,bit score query1 subject1 90.00 7 1 0 0 8 4 10 1e-05 15.5 query1 subject1 70.00 8 0 1 0 9 5 7 0.231 7.8 query1 subject1 90.00 5 1 1 0 0 2 10 0.022 13.0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/legacy9_single_line000066400000000000000000000003731520735541300272670ustar00rootroot00000000000000# BLASTN 2.2.3 [May-13-2002] # Database: other_vertebrate # Query: query1 # Fields: Query id,Subject id,% identity,alignment length,mismatches,gap opens,q. start,q. end,s. start,s. end,evalue,bit score query1 subject1 90.00 7 1 0 0 8 4 10 1e-05 15.5 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/longreads_as_illumina.fastq000066400000000000000000000203041520735541300310260ustar00rootroot00000000000000@FSRRS4401BE7HA [length=395] [gc=36.46] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=95] tcagTTAAGATGGGATAATATCCTCAGATTGCGTGATGAACTTTGTTCTGGTGGAGGAGAAGGAAGTGCATTCGACGTATGCCCGTTTGTCGATATTTGtatttaaagtaatccgtcacaaatcagtgacataaatattatttagatttcgggagcaactttatttattccacaagcaggtttaaattttaaatttaaattattgcagaagactttaaattaacctcgttgtcggagtcatttgttcggttattggtcgaaagtaaccncgggaagtgccgaaaactaacaaacaaaagaagatagtgaaattttaattaaaanaaatagccaaacgtaactaactaaaacggacccgtcgaggaactgccaacggacgacacagggagtagnnn + eeeccccccc`UUU^UWWeegffhhhhhhhhhhhhhhhhhhggghhhhhhhhhfgfeeeee\\\\ceeeeeeeeeeeeeec^^^YRPOSNVU\YTMMMSMRKKKRUUNNNNS[`aa```\bbeccccccccYUUUbceeee\[`a`\ZYRRRPPP[\\\XXZaWWXeeeeeeccacaccc\WWSSQRPMMKKKLKKKKKKKKPPRRMMLLLPVPPPKKKKKQQTTTPRPPQPMLLMKRRRPPKMKKRLLKKMKKLLKRTPPPQRMMLL@KKKKLLKLLLLXKKKKW\KKLKKKLKKKKLLLQUYXYTLMMPKKKKPPNNKKKK@KKPXPVLLKKKKLRMKLLKKPVKKKKLLLJPPPPRMOROOOOKKKOSSSOOORUZXUUUQMNNZV][Z@@@ @FSRRS4401BRRTC [length=145] [gc=38.62] [flows=800] [phred_min=0] [phred_max=38] [trimmed_length=74] tcagCCAGCAATTCCGACTTAATTGTTCTTCTTCCATCATTCATCTCGACTAACAGTTCTACGATTAATGAGTTTGGCtttaatttgttgttcattattgtcacaattacactactgagactgccaaggcacncagggataggnn + eeeeeeeeecccceeeefecccca`````\[SSSS__a\TTTYaaaaa__^WYW[^[WXWXW[WSSSQZ\\RKKKTPSKKKPPKKKMKKQPVVVTTTTPRKMMLLPPPTVTWMNNRSSWW][[ZZZZXXSSN@NSKKKTVWTT@@ @FSRRS4401B64ST [length=382] [gc=40.58] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=346] tcagTTTTCTTAAATTACTTGAATCTGTTGAAGTGGATGTCCACTTTTGTATGCCAAATATGCCCAGCGTATACGATCTTGGCCACATCTCCACATAATCATCAGTCGGATGCAAAAAGCGATTAAACTAAAAATGAATGCGTTTTTAGATGAGTAAATAGGTAATACTTTGTTTAAATAATAAATGTCACAAACAGAACGCGGATTACAGTACCTGAAAATAGTTGTACTGTATCTGTGCCGGCACTTCCTCGGCCCTGAGAAGTTGTCCCGTTGTTTCCATTCGCACCATCCAATGGCCAAAGTTTGCGAAGAATCTGTTCCGTTCCATTACCAATTGTTTTTCCATGctgagactgccaaggcacacaggggataggnn + hhhhbbbbh^^UUUhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhUUUUh`hhhhh^^^hhhhbbbhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhUURRRdhbdYYRRW\NLLLLKW\]]^^YQLNNNNV]bddhdhggghhhhhhhhhdZZXXPPPXXa^^^habghhhhhhggghhggghhhhhhhhhhhhhhhhhhaabbhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfffhhhhhhhhhc^\\\chhhggghhhhhhhhhggghhhhhhhhhhggghggghhhhhhhhhhhhhhhhhhhhhh^]ZXXWW\\TLLLLM__`dfhhhhhhhhhgg^^^^dhhheeXXXZdhhaa@@ @FSRRS4401EJ0YH [length=381] [gc=48.29] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=343] tcagTTTTTGGAGAATTCCGTCAGGGACGGCATGGCATATTTGTGGGTTCGGCACGGCGTCCTGGCCAAGAAGAAGAAGACGAATTAGCCCGTTAATTTAATGACACCTTCCCCAATTTTGCAGCAATGATTGGTTCATTCTTGGCGGTGCGTTTTTGTGCTTCGTCGAATTGTTGGCCATTTTGGTCCACCGGCCATCATCTTTACGCTATCCGACTGATTGGAAATCACCGCCTAGCATTTTGCCGAAGATTGTTGCGTTGTACGGCCATGTGCTGATTGTTTACATTGGCATTCTTGGCAATTTGTCCTTGGTCGGCTTTGACGGCAAATTTGCGGTGTTAAGTctgagactgccaaggcacacagggggatagggnn + hhhh^^^^^hhhhhhhhhhhhhhggghhhhhhhhhhhhhggghhggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggghhhhhggghhhhhhhhhhh````hh]]]]hhhhhhhhhhhhhhhhhhhhhhhhhhddhddZRRRRRcVhhhhhhhhhhhhhhhhhhhhhbb__gghhhhhhhhhhhhhhhhggghhhhhhhhhhhhhhhhhhhggghhhhhhhhhhhhhaaaahgbcbghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggghhhggbbchhhhhhggghhbbbg\bbhhhhhhhhhfffhhhhhhgggggghhhhhhhhhhhhhhhggghhggd^^]]^dedd^NNNNNZYWOLL@@ @FSRRS4401BK0IB [length=507] [gc=49.31] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=208] tcagTTGACCGGCGTTGTGTAACAATAATTCATTATTCTGAGACGATGCCAATGTAATCGACGGTTTATGCCCAATTATTCCCATCTATGCTTAACTGATCAAATACTATTTGCATTACGTCACGAAATTGCGCGAACACCGCCGGCCGACAATAATTTATACCGGACATACCGGAGTTGATGGTAATCGGTAAAGAGTTTTATTTAATTATntattatcnctattaattattgttancaacaatgtgcacgctntgccgcccgccgccgccgtgtcggtaggaccccggacggacccggacccggttcgggtacccgttttcgggttcccggaaccgtttttcgggtacccggttttttcggggggccccccggtaaaaaaccggggaaccccctaaaacgggtaaacgtaccgtaagggaccccctaaacgggggccccgaaaaaccgggacccaaaccggggggaaacggttaaaggggggggaagtaggngnnnnnnnnnnnn + eee`__eeeeeeeeeeggaYYY_aeeeeffghghhhhhhhhhhhhhhhhhhhhhhheeeeeeeee^\a`_PPPWWOPP[[WWZ^``accb^^^cc````c`UUUc^ccc\\\\\``]^]][[[\[PPPWW[[^^^``^XTTT\`aaa__^\]]^__PPPSQYYcc`^^^ceeeeeeeeeeeeea````[[OOOOMQQ\NNNNWKLLPPPPPP@QRLLNQS@RVYUUUU[ZWQQNMMS@SUTQPPVVTTRMLMQR@QRPPQPPPQKKLKKQPP\\TLLLLLLKPQKKKKKKLKKKLPKKKKLKKPTTLLKKKKPRPPPMKKKKKKKKJJPPPMMPPMMPKKKKKKKKKJRKKKKKLLQQLLLLLNNLLLLTTNNIINLLQQLLIIKKKKIIKKKKKKMPMKIKKKKIIIKKKKKKKKKKKKKKKKKKKKKKKHKKLKKKKKKHKKKKKIINNMHKKKNNNKKKKKKKKKKKMHHRRLLLKKKKKKKKKKGOKKK@M@@@@@@@@@@@@ @FSRRS4401ARCCB [length=258] [gc=46.90] [flows=800] [phred_min=0] [phred_max=38] [trimmed_length=193] tcagTTATTGCAGTCGTTCCGCGCCATCGCCGGTAACCGTCCGCGTGTTATTCTGTGTATCGGCCAACCTTCGTATAACTTCGTATAATGTATGCTATACGAAGTTATTACGATCTATACCGGCGAAACTCAGCCGAAAGGTCTCGCGGTAGAGCCTATGAGCTGCCCGACCGATGCATTTAAATTTCCGGGGATCGtcgctgatctgagactgccaaaggcacactagggggataggnnnnnnnnnnnnnnnnnnnn + eee[WYY_ceeeeeeeffecb`````a__OOOOSU[ZUURQQRUUVUQQSRRSW[[\^^SSSTYY]`a```_[[\\a\YTTTYaac^^\acccceeebbbbbbbeebccceeeeeca``\\WWWWOOOS][[[XXUWWZWWX[WWX^aaaa`\^^^ccaaa__^^WWWWXLLLQRVVVPKKKKKKKKLLPPTQ[[OOPTW`_][[[[[SRQVVVPPKKKLLRV\\\VTKLLLLRSUUU@@@@@@@@@@@@@@@@@@@@ @FSRRS4401CM938 [length=453] [gc=44.15] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=418] tcagGTTTTAAATCGCTTTCCAAGGAATTTGAGTCTAAATCCGGTGGATCCCATCAGTACAAATGCGGCGACAAGGCCGTGAAAACACTGCTTAATTCTTTGCACTTTTTGGCCACCTTTTTGGAAATGTTGTTTTGTGTTCTCAAAATTTTCCATCTCAGAACAAACATTCCATCGGGCTGATGTTGTGGCTTTTGGCGCGCGAAGTGCTGCTACTGCGCGGCAAAATCAGTCGCCAGACCGGTTTTGTTGTGGACGACAAAGTGATCATGCCTGACTTGTACTTCTACCGCGATCCGCAAGCGCGAATTGGTCACATAGTTATAGAATTTTTGAGCCTTTTTCTTGACATAAAAAGTGTGGTTTTAAAAATTTCCTGGCAGGACCCACGCCAACGTTCAGGAATAATATCTTTTAAAAAGctgagactgccaaggcacacaggggataggn + hhhhhbb]]UUUhhhhbbbhhhhhhhhggghhhhhfUUUhhhhhhhhhhggghhhhhhhhbbbhhhhhhhhhhhhhhhhhh____hhhhhhhhhhhhhggghhhh^^^\ZhhddhYYNNNNNVTSSY^haaVQQSSdWddbdab\_______gghhhhhhhhhhaaahhhhhhhhhggghhhhhhhhhhhhhbbbbhhhhhhhhhhhhhhhhhhhhhhhhhhhhUUUUcdhhgda^^c_VVVVVQQQQcWXddhhhhhhhggghhhhhhhhggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggghhhhhhhhhhhhhhh\\^\\hhhhh^^^\ZhURcccWQLLKKKRW\\YYLLLLKKLLLJJJRROUUZ_URWOOOWNYWWX[Yafhhhhhhhhhed[^eTTOOLLLLLTYZZZY]^_b[[VXXXdddddd____ddddd@ @FSRRS4401EQLIK [length=411] [gc=34.31] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=374] tcagTTTAATTTGGTGCTTCCTTTCAATTCCTTAGTTTAAACTTGGCACTGAAGTCTCGCATTTATAACTAGAGCCCGGATTTTAGAGGCTAAAAAGTTTTCCAGATTTCAAAATTTATTTCGAAACTATTTTTCTGATTGTGATGTGACGGATTTCTAAATTAAATCGAAATGATGTGTATTGAACTTAACAAGTGATTTTTATCAGATTTTGTCAATGAATAAATTTTAATTTAAATCTCTTTCTAACACTTTCATGATTAAAATCTAACAAAGCGCGACCAGTATGTGAGAAGAGCAAAAACAACAAAAAGTGCTAGCACTAAAGAAGGTTCGAACCCAACACATAACGTAAGAGTTACCGGGAAGAAAACCACTctgagactgccaaggcacacagggggataggnn + hhh^UUU^^ggghhhhhhhhhfffhhhhhhhhhhhfffggghhhhhhhhhhhhhhhhhhhhfffhhhhhhhhhhggghhh____hhhhdhdPPPPOOLLLLQQ^\WLLLYLLLLLLLKKKKRRLLLTYRKLLLLYPaadddghhhhhhhhhhha^^`PQQOOOMMMY^\OQSfhhhhhhhhhhhhhhhhhhdbbgga\NNLKKQP^^[TLOOQ\Ueaa^YX[\PPNSSSSNNLNNVV^^fdhddgh`bbhhhggghhhhhhhbbb`hhhgggggghhhhhhhhhhhhhhhhhhhhhhddPNNLLWQQZLLLLMVVV_dhhhhhh^^^hhhhhhhhhhhggghhhhhhhhhhhhhhhhhhhhXXSQQVVVTTTT`dZhdddddhhhhh^^XVTT]_\\YRKKKKKRRRRU@@ @FSRRS4401AOV6A [length=309] [gc=22.98] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=273] tcagTTTTCAAATTTTCCGAAATTTGCTGTTTGGTAGAAGGCAAATTATTTGATTGAATTTTGTATTTATTTAAAACAATTTATTTTAAAATAATAATTTTCCATTGACTTTTTACATTTAATTGATTTTATTATGCATTTTATATTTGTTTTCTAAATATTCGTTTGCAAACTCACGTTGAAATTGTATTAAACTCGAAATTAGAGTTTTTGAAATTAATTTTTATGTAGCATAATATTTTAAACATATTGGAATTTTATAAAACATTATATTTTTctgagactgccaaggcacacagggggataggn + hhhhbbbbhZZZbbbbhhh^^^ggghhhhggghhhhhhhhhhggghhhggghhhhhhh____hehbbbhb``ZZZZdc^a__cUUSSTTTT[[[fhh]]``hhhhhhhhZZZYYhhh^^^bbbhhhZZZZheehhhhhbbbahahddcbSSSS^Saaad^dhhhbgghhZZZghhhhhhggZZZgghhhhhZZZhhhhggghhhhhh]]^^]hddaffYYPPPPNSUeaeaa^\Z\`^XVVVPPPXYd```ccacVVVV\NPPPPQQc`__aUWZZZhWgghhhhhZZZZ^]hdbbbaNNNNNZVST\@ @FSRRS4401EG0ZW [length=424] [gc=23.82] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=389] tcagTTTTGATCTTTTAATAATGAATTTTAATGTGTTAAAATGATTGCATTGATGGCATAACCGCATTTAAATTAATTACATGAAGTGTAAGTATGAAATTTTCCTTTCCAAATTGCAAAAACTAAAATTTAAAATTTATCGTAAAAATTAACATATATTTTAAACGATTTTAAGAAACATTTGTAAATTATATTTTTGTGAAGCGTTCAAACAAAAATAAACAATAAAATATTTTTCTATTTAATAGCAAAACATTTGACGATGAAAAGGAAAATGCGGGTTTGAAAATGGGCTTTGCCATGCTATTTTCATAATAACATATTTTTATTATGAATAATAAATTTACATACAATATATACAGTCTTAAATTTATTCATAATATTTTTGAGAATctgagactgccaaggcacacaggggataggn + hh`XSSSTddhh\\\]hhhhhhhhhbbbbhhghhhbbZZZZhhhhhhhhhhhhhhhhhhhhhhhhheZZUUUcchhhhhhhhhhhhhhhhhhhddXSSSQQSS__UUUbb[[acc`\LLLLLQ[KKKKUTXNNOO\\\WbhhhZ]]\\ggZZhhhhhhbb__^^^hhh____hb^UUUghccbh^a^^bb[ddPPPPPaSaccbaZ\_aVVV]NNNNL\RQR^SQRKKKN\PKKKKLYSdZ^^dhhhhhbbbbh]ZZZhhhhhhh[[__^\NNNNV\`XXXWW[[SSTThdddhhhhhhhhhhhhh[XXXghhhhhhhhhhh^^^^^hhhhhhhhhhhb`bZTTTRXdhhhhhhhhhhhhhhhhggXXXgggh`\`ddee_\MMMMM`c___ccddddehhhZZZXVVeebbb_QSSSX^ecc@ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/longreads_as_sanger.fastq000066400000000000000000000203041520735541300304730ustar00rootroot00000000000000@FSRRS4401BE7HA [length=395] [gc=36.46] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=95] tcagTTAAGATGGGATAATATCCTCAGATTGCGTGATGAACTTTGTTCTGGTGGAGGAGAAGGAAGTGCATTCGACGTATGCCCGTTTGTCGATATTTGtatttaaagtaatccgtcacaaatcagtgacataaatattatttagatttcgggagcaactttatttattccacaagcaggtttaaattttaaatttaaattattgcagaagactttaaattaacctcgttgtcggagtcatttgttcggttattggtcgaaagtaaccncgggaagtgccgaaaactaacaaacaaaagaagatagtgaaattttaattaaaanaaatagccaaacgtaactaactaaaacggacccgtcgaggaactgccaacggacgacacagggagtagnnn + FFFDDDDDDDA666?688FFHGGIIIIIIIIIIIIIIIIIIHHHIIIIIIIIIGHGFFFFF====DFFFFFFFFFFFFFFD???:3104/76=:5...4.3,,,366////4<;!!! @FSRRS4401BRRTC [length=145] [gc=38.62] [flows=800] [phred_min=0] [phred_max=38] [trimmed_length=74] tcagCCAGCAATTCCGACTTAATTGTTCTTCTTCCATCATTCATCTCGACTAACAGTTCTACGATTAATGAGTTTGGCtttaatttgttgttcattattgtcacaattacactactgagactgccaaggcacncagggataggnn + FFFFFFFFFDDDDFFFFGFDDDDBAAAAA=<4444@@B=555:BBBBB@@?8:8<<;;;;9944/!/4,,,57855!! @FSRRS4401B64ST [length=382] [gc=40.58] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=346] tcagTTTTCTTAAATTACTTGAATCTGTTGAAGTGGATGTCCACTTTTGTATGCCAAATATGCCCAGCGTATACGATCTTGGCCACATCTCCACATAATCATCAGTCGGATGCAAAAAGCGATTAAACTAAAAATGAATGCGTTTTTAGATGAGTAAATAGGTAATACTTTGTTTAAATAATAAATGTCACAAACAGAACGCGGATTACAGTACCTGAAAATAGTTGTACTGTATCTGTGCCGGCACTTCCTCGGCCCTGAGAAGTTGTCCCGTTGTTTCCATTCGCACCATCCAATGGCCAAAGTTTGCGAAGAATCTGTTCCGTTCCATTACCAATTGTTTTTCCATGctgagactgccaaggcacacaggggataggnn + IIIICCCCI??666IIIIIIIIIIIIIIIIIIIIIIIIIIIIII6666IAIIIII???IIIICCCIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII66333EICE::338=/----,8=>>??:2-////7>CEEIEIHHHIIIIIIIIIE;;9911199B???IBCHIIIIIIHHHIIHHHIIIIIIIIIIIIIIIIIIBBCCIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIGGGIIIIIIIIID?===DIIIHHHIIIIIIIIIHHHIIIIIIIIIIHHHIHHHIIIIIIIIIIIIIIIIIIIIII?>;9988==5----.@@AEGIIIIIIIIIHH????EIIIFF999;EIIBB!! @FSRRS4401EJ0YH [length=381] [gc=48.29] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=343] tcagTTTTTGGAGAATTCCGTCAGGGACGGCATGGCATATTTGTGGGTTCGGCACGGCGTCCTGGCCAAGAAGAAGAAGACGAATTAGCCCGTTAATTTAATGACACCTTCCCCAATTTTGCAGCAATGATTGGTTCATTCTTGGCGGTGCGTTTTTGTGCTTCGTCGAATTGTTGGCCATTTTGGTCCACCGGCCATCATCTTTACGCTATCCGACTGATTGGAAATCACCGCCTAGCATTTTGCCGAAGATTGTTGCGTTGTACGGCCATGTGCTGATTGTTTACATTGGCATTCTTGGCAATTTGTCCTTGGTCGGCTTTGACGGCAAATTTGCGGTGTTAAGTctgagactgccaaggcacacagggggatagggnn + IIII?????IIIIIIIIIIIIIIHHHIIIIIIIIIIIIIHHHIIHHHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHIIIIIHHHIIIIIIIIIIIAAAAII>>>>IIIIIIIIIIIIIIIIIIIIIIIIIIEEIEE;33333D7IIIIIIIIIIIIIIIIIIIIICC@@HHIIIIIIIIIIIIIIIIHHHIIIIIIIIIIIIIIIIIIIHHHIIIIIIIIIIIIIBBBBIHCDCHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHIIIHHCCDIIIIIIHHHIICCCH=CCIIIIIIIIIGGGIIIIIIHHHHHHIIIIIIIIIIIIIIIHHHIIHHE??>>?EFEE?/////;:80--!! @FSRRS4401BK0IB [length=507] [gc=49.31] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=208] tcagTTGACCGGCGTTGTGTAACAATAATTCATTATTCTGAGACGATGCCAATGTAATCGACGGTTTATGCCCAATTATTCCCATCTATGCTTAACTGATCAAATACTATTTGCATTACGTCACGAAATTGCGCGAACACCGCCGGCCGACAATAATTTATACCGGACATACCGGAGTTGATGGTAATCGGTAAAGAGTTTTATTTAATTATntattatcnctattaattattgttancaacaatgtgcacgctntgccgcccgccgccgccgtgtcggtaggaccccggacggacccggacccggttcgggtacccgttttcgggttcccggaaccgtttttcgggtacccggttttttcggggggccccccggtaaaaaaccggggaaccccctaaaacgggtaaacgtaccgtaagggaccccctaaacgggggccccgaaaaaccgggacccaaaccggggggaaacggttaaaggggggggaagtaggngnnnnnnnnnnnn + FFFA@@FFFFFFFFFFHHB:::@BFFFFGGHIHIIIIIIIIIIIIIIIIIIIIIIIFFFFFFFFF?=BA@11188011<<88;?AABDDC???DDAAAADA666D?DDD=====AA>?>><<<=<11188<>?@@11142::DDA???DFFFFFFFFFFFFFBAAAA<<0000.22=////8,--111111!23--/24!37:6666<;822/..4!46521177553.-.23!231121112,,-,,211==5------,12,,,,,,-,,,-1,,,,-,,155--,,,,13111.,,,,,,,,++111..11..1,,,,,,,,,+3,,,,,--22-----//----55//**/--22--**,,,,**,,,,,,.1.,*,,,,***,,,,,,,,,,,,,,,,,,,,,,,),,-,,,,,,),,,,,**//.),,,///,,,,,,,,,,,.))33---,,,,,,,,,,(0,,,!.!!!!!!!!!!!! @FSRRS4401ARCCB [length=258] [gc=46.90] [flows=800] [phred_min=0] [phred_max=38] [trimmed_length=193] tcagTTATTGCAGTCGTTCCGCGCCATCGCCGGTAACCGTCCGCGTGTTATTCTGTGTATCGGCCAACCTTCGTATAACTTCGTATAATGTATGCTATACGAAGTTATTACGATCTATACCGGCGAAACTCAGCCGAAAGGTCTCGCGGTAGAGCCTATGAGCTGCCCGACCGATGCATTTAAATTTCCGGGGATCGtcgctgatctgagactgccaaaggcacactagggggataggnnnnnnnnnnnnnnnnnnnn + FFF<8::@DFFFFFFFGGFDCAAAAAB@@000046<;66322366762243348<<=??4445::>ABAAA@<<==B=:555:BBD??=BDDDDFFFCCCCCCCFFCDDDFFFFFDBAA==88880004><<<99688;889<889?BBBBA=???DDBBB@@??88889---237771,,,,,,,,--1152<<00158A@><<<<<43277711,,,--37===75,----34666!!!!!!!!!!!!!!!!!!!! @FSRRS4401CM938 [length=453] [gc=44.15] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=418] tcagGTTTTAAATCGCTTTCCAAGGAATTTGAGTCTAAATCCGGTGGATCCCATCAGTACAAATGCGGCGACAAGGCCGTGAAAACACTGCTTAATTCTTTGCACTTTTTGGCCACCTTTTTGGAAATGTTGTTTTGTGTTCTCAAAATTTTCCATCTCAGAACAAACATTCCATCGGGCTGATGTTGTGGCTTTTGGCGCGCGAAGTGCTGCTACTGCGCGGCAAAATCAGTCGCCAGACCGGTTTTGTTGTGGACGACAAAGTGATCATGCCTGACTTGTACTTCTACCGCGATCCGCAAGCGCGAATTGGTCACATAGTTATAGAATTTTTGAGCCTTTTTCTTGACATAAAAAGTGTGGTTTTAAAAATTTCCTGGCAGGACCCACGCCAACGTTCAGGAATAATATCTTTTAAAAAGctgagactgccaaggcacacaggggataggn + IIIIICC>>666IIIICCCIIIIIIIIHHHIIIIIG666IIIIIIIIIIHHHIIIIIIIICCCIIIIIIIIIIIIIIIIII@@@@IIIIIIIIIIIIIHHHIIII???=;IIEEI:://///7544:?IBB72244E8EECEBC=@@@@@@@HHIIIIIIIIIIBBBIIIIIIIIIHHHIIIIIIIIIIIIICCCCIIIIIIIIIIIIIIIIIIIIIIIIIIII6666DEIIHEB??D@777772222D89EEIIIIIIIHHHIIIIIIIIHHHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHIIIIIIIIIIIIIII==?==IIIII???=;I63DDD82--,,,38==::----,,---+++33066;@6380008/:889<:BGIIIIIIIIIFE?@C<<7999EEEEEE@@@@EEEEE! @FSRRS4401EQLIK [length=411] [gc=34.31] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=374] tcagTTTAATTTGGTGCTTCCTTTCAATTCCTTAGTTTAAACTTGGCACTGAAGTCTCGCATTTATAACTAGAGCCCGGATTTTAGAGGCTAAAAAGTTTTCCAGATTTCAAAATTTATTTCGAAACTATTTTTCTGATTGTGATGTGACGGATTTCTAAATTAAATCGAAATGATGTGTATTGAACTTAACAAGTGATTTTTATCAGATTTTGTCAATGAATAAATTTTAATTTAAATCTCTTTCTAACACTTTCATGATTAAAATCTAACAAAGCGCGACCAGTATGTGAGAAGAGCAAAAACAACAAAAAGTGCTAGCACTAAAGAAGGTTCGAACCCAACACATAACGTAAGAGTTACCGGGAAGAAAACCACTctgagactgccaaggcacacagggggataggnn + III?666??HHHIIIIIIIIIGGGIIIIIIIIIIIGGGHHHIIIIIIIIIIIIIIIIIIIIGGGIIIIIIIIIIHHHIII@@@@IIIIEIE111100----22?=8---:-------,,,,33---5:3,----:1BBEEEHIIIIIIIIIIIB??A122000...:?=024GIIIIIIIIIIIIIIIIIIECCHHB=//-,,21??<5-002=6FBB?:9<=11/4444//-//77??GEIEEHIACCIIIHHHIIIIIIICCCAIIIHHHHHHIIIIIIIIIIIIIIIIIIIIIIEE1//--822;----.777@EIIIIII???IIIIIIIIIIIHHHIIIIIIIIIIIIIIIIIIII994227775555AE;IEEEEEIIIII??9755>@==:3,,,,,33336!! @FSRRS4401AOV6A [length=309] [gc=22.98] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=273] tcagTTTTCAAATTTTCCGAAATTTGCTGTTTGGTAGAAGGCAAATTATTTGATTGAATTTTGTATTTATTTAAAACAATTTATTTTAAAATAATAATTTTCCATTGACTTTTTACATTTAATTGATTTTATTATGCATTTTATATTTGTTTTCTAAATATTCGTTTGCAAACTCACGTTGAAATTGTATTAAACTCGAAATTAGAGTTTTTGAAATTAATTTTTATGTAGCATAATATTTTAAACATATTGGAATTTTATAAAACATTATATTTTTctgagactgccaaggcacacagggggataggn + IIIICCCCI;;;CCCCIII???HHHIIIIHHHIIIIIIIIIIHHHIIIHHHIIIIIII@@@@IFICCCICAA;;;;ED?B@@D66445555<<>AAIIIIIIII;;;::III???CCCIII;;;;IFFIIIIICCCBIBIEEDC4444?4BBBE?EIIICHHII;;;HIIIIIIHH;;;HHIIIII;;;IIIIHHHIIIIII>>??>IEEBGG::1111/46FBFBB?=;=A?97771119:EAAADDBD7777=/111122DA@@B68;;;I8HHIIIII;;;;?>IECCCB/////;745=! @FSRRS4401EG0ZW [length=424] [gc=23.82] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=389] tcagTTTTGATCTTTTAATAATGAATTTTAATGTGTTAAAATGATTGCATTGATGGCATAACCGCATTTAAATTAATTACATGAAGTGTAAGTATGAAATTTTCCTTTCCAAATTGCAAAAACTAAAATTTAAAATTTATCGTAAAAATTAACATATATTTTAAACGATTTTAAGAAACATTTGTAAATTATATTTTTGTGAAGCGTTCAAACAAAAATAAACAATAAAATATTTTTCTATTTAATAGCAAAACATTTGACGATGAAAAGGAAAATGCGGGTTTGAAAATGGGCTTTGCCATGCTATTTTCATAATAACATATTTTTATTATGAATAATAAATTTACATACAATATATACAGTCTTAAATTTATTCATAATATTTTTGAGAATctgagactgccaaggcacacaggggataggn + IIA94445EEII===>IIIIIIIIICCCCIIHIIICC;;;;IIIIIIIIIIIIIIIIIIIIIIIIIF;;666DDIIIIIIIIIIIIIIIIIIIEE94442244@@666CC<>==HH;;IIIIIICC@@???III@@@@IC?666HIDDCI?B??CC////-=323?423,,,/=1,,,,-:4E;??EIIIIICCCCI>;;;IIIIIII<<@@?=////7=A99988<<4455IEEEIIIIIIIIIIIII<999HIIIIIIIIIII?????IIIIIIIIIIICAC;55539EIIIIIIIIIIIIIIIIHH999HHHIA=AEEFF@=.....AD@@@DDEEEEFIII;;;977FFCCC@24449?FDD! scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/longreads_original_sanger.fastq000066400000000000000000000223721520735541300317030ustar00rootroot00000000000000@FSRRS4401BE7HA [length=395] [gc=36.46] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=95] tcagTTAAGATGGGATAATATCCTCAGATTGCGTGATGAACTTTGTTCTGGTGGAGGAGAAGGAAGTGCATTCGACGTAT GCCCGTTTGTCGATATTTGtatttaaagtaatccgtcacaaatcagtgacataaatattatttagatttcgggagcaact ttatttattccacaagcaggtttaaattttaaatttaaattattgcagaagactttaaattaacctcgttgtcggagtca tttgttcggttattggtcgaaagtaaccncgggaagtgccgaaaactaacaaacaaaagaagatagtgaaattttaatta aaanaaatagccaaacgtaactaactaaaacggacccgtcgaggaactgccaacggacgacacagggagtagnnn +FSRRS4401BE7HA [length=395] [gc=36.46] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=95] FFFDDDDDDDA666?688FFHGGIIIIIIIIIIIIIIIIIIHHHIIIIIIIIIGHGFFFFF====DFFFFFFFFFFFFFF D???:3104/76=:5...4.3,,,366////4<;!!! @FSRRS4401BRRTC [length=145] [gc=38.62] [flows=800] [phred_min=0] [phred_max=38] [trimmed_length=74] tcagCCAGCAATTCCGACTTAATTGTTCTTCTTCCATCATTCATCTCGACTAACAGTTCTACGATTAATGAGTTTGGCtt taatttgttgttcattattgtcacaattacactactgagactgccaaggcacncagggataggnn +FSRRS4401BRRTC [length=145] [gc=38.62] [flows=800] [phred_min=0] [phred_max=38] [trimmed_length=74] FFFFFFFFFDDDDFFFFGFDDDDBAAAAA=<4444@@B=555:BBBBB@@?8:8<<;;;;9944/!/4,,,57855!! @FSRRS4401B64ST [length=382] [gc=40.58] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=346] tcagTTTTCTTAAATTACTTGAATCTGTTGAAGTGGATGTCCACTTTTGTATGCCAAATATGCCCAGCGTATACGATCTT GGCCACATCTCCACATAATCATCAGTCGGATGCAAAAAGCGATTAAACTAAAAATGAATGCGTTTTTAGATGAGTAAATA GGTAATACTTTGTTTAAATAATAAATGTCACAAACAGAACGCGGATTACAGTACCTGAAAATAGTTGTACTGTATCTGTG CCGGCACTTCCTCGGCCCTGAGAAGTTGTCCCGTTGTTTCCATTCGCACCATCCAATGGCCAAAGTTTGCGAAGAATCTG TTCCGTTCCATTACCAATTGTTTTTCCATGctgagactgccaaggcacacaggggataggnn +FSRRS4401B64ST [length=382] [gc=40.58] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=346] IIIICCCCI??666IIIIIIIIIIIIIIIIIIIIIIIIIIIIII6666IAIIIII???IIIICCCIIIIIIIIIIIIIII IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII66333EICE::338=/----,8=>>??:2-////7>CEEIEIHHHII IIIIIIIE;;9911199B???IBCHIIIIIIHHHIIHHHIIIIIIIIIIIIIIIIIIBBCCIIIIIIIIIIIIIIIIIII IIIIIIIIIIIIIIIGGGIIIIIIIIID?===DIIIHHHIIIIIIIIIHHHIIIIIIIIIIHHHIHHHIIIIIIIIIIII IIIIIIIIII?>;9988==5----.@@AEGIIIIIIIIIHH????EIIIFF999;EIIBB!! @FSRRS4401EJ0YH [length=381] [gc=48.29] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=343] tcagTTTTTGGAGAATTCCGTCAGGGACGGCATGGCATATTTGTGGGTTCGGCACGGCGTCCTGGCCAAGAAGAAGAAGA CGAATTAGCCCGTTAATTTAATGACACCTTCCCCAATTTTGCAGCAATGATTGGTTCATTCTTGGCGGTGCGTTTTTGTG CTTCGTCGAATTGTTGGCCATTTTGGTCCACCGGCCATCATCTTTACGCTATCCGACTGATTGGAAATCACCGCCTAGCA TTTTGCCGAAGATTGTTGCGTTGTACGGCCATGTGCTGATTGTTTACATTGGCATTCTTGGCAATTTGTCCTTGGTCGGC TTTGACGGCAAATTTGCGGTGTTAAGTctgagactgccaaggcacacagggggatagggnn +FSRRS4401EJ0YH [length=381] [gc=48.29] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=343] IIII?????IIIIIIIIIIIIIIHHHIIIIIIIIIIIIIHHHIIHHHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIIIIIHHHIIIIIHHHIIIIIIIIIIIAAAAII>>>>IIIIIIIIIIIIIIIIIIIIIIIIIIEEIEE;33333D7I IIIIIIIIIIIIIIIIIIIICC@@HHIIIIIIIIIIIIIIIIHHHIIIIIIIIIIIIIIIIIIIHHHIIIIIIIIIIIII BBBBIHCDCHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHIIIHHCCDIIIIIIHHHIICCCH=CCIIIIIIIII GGGIIIIIIHHHHHHIIIIIIIIIIIIIIIHHHIIHHE??>>?EFEE?/////;:80--!! @FSRRS4401BK0IB [length=507] [gc=49.31] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=208] tcagTTGACCGGCGTTGTGTAACAATAATTCATTATTCTGAGACGATGCCAATGTAATCGACGGTTTATGCCCAATTATT CCCATCTATGCTTAACTGATCAAATACTATTTGCATTACGTCACGAAATTGCGCGAACACCGCCGGCCGACAATAATTTA TACCGGACATACCGGAGTTGATGGTAATCGGTAAAGAGTTTTATTTAATTATntattatcnctattaattattgttanca acaatgtgcacgctntgccgcccgccgccgccgtgtcggtaggaccccggacggacccggacccggttcgggtacccgtt ttcgggttcccggaaccgtttttcgggtacccggttttttcggggggccccccggtaaaaaaccggggaaccccctaaaa cgggtaaacgtaccgtaagggaccccctaaacgggggccccgaaaaaccgggacccaaaccggggggaaacggttaaagg ggggggaagtaggngnnnnnnnnnnnn +FSRRS4401BK0IB [length=507] [gc=49.31] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=208] FFFA@@FFFFFFFFFFHHB:::@BFFFFGGHIHIIIIIIIIIIIIIIIIIIIIIIIFFFFFFFFF?=BA@11188011<< 88;?AABDDC???DDAAAADA666D?DDD=====AA>?>><<<=<11188<>?@@1114 2::DDA???DFFFFFFFFFFFFFBAAAA<<0000.22=////8,--111111!23--/24!37:6666<;822/..4!46 521177553.-.23!231121112,,-,,211==5------,12,,,,,,-,,,-1,,,,-,,155--,,,,13111.,, ,,,,,,++111..11..1,,,,,,,,,+3,,,,,--22-----//----55//**/--22--**,,,,**,,,,,,.1., *,,,,***,,,,,,,,,,,,,,,,,,,,,,,),,-,,,,,,),,,,,**//.),,,///,,,,,,,,,,,.))33---,, ,,,,,,,,(0,,,!.!!!!!!!!!!!! @FSRRS4401ARCCB [length=258] [gc=46.90] [flows=800] [phred_min=0] [phred_max=38] [trimmed_length=193] tcagTTATTGCAGTCGTTCCGCGCCATCGCCGGTAACCGTCCGCGTGTTATTCTGTGTATCGGCCAACCTTCGTATAACT TCGTATAATGTATGCTATACGAAGTTATTACGATCTATACCGGCGAAACTCAGCCGAAAGGTCTCGCGGTAGAGCCTATG AGCTGCCCGACCGATGCATTTAAATTTCCGGGGATCGtcgctgatctgagactgccaaaggcacactagggggataggnn nnnnnnnnnnnnnnnnnn +FSRRS4401ARCCB [length=258] [gc=46.90] [flows=800] [phred_min=0] [phred_max=38] [trimmed_length=193] FFF<8::@DFFFFFFFGGFDCAAAAAB@@000046<;66322366762243348<<=??4445::>ABAAA@<<==B=:5 55:BBD??=BDDDDFFFCCCCCCCFFCDDDFFFFFDBAA==88880004><<<99688;889<889?BBBBA=???DDBB B@@??88889---237771,,,,,,,,--1152<<00158A@><<<<<43277711,,,--37===75,----34666!! !!!!!!!!!!!!!!!!!! @FSRRS4401CM938 [length=453] [gc=44.15] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=418] tcagGTTTTAAATCGCTTTCCAAGGAATTTGAGTCTAAATCCGGTGGATCCCATCAGTACAAATGCGGCGACAAGGCCGT GAAAACACTGCTTAATTCTTTGCACTTTTTGGCCACCTTTTTGGAAATGTTGTTTTGTGTTCTCAAAATTTTCCATCTCA GAACAAACATTCCATCGGGCTGATGTTGTGGCTTTTGGCGCGCGAAGTGCTGCTACTGCGCGGCAAAATCAGTCGCCAGA CCGGTTTTGTTGTGGACGACAAAGTGATCATGCCTGACTTGTACTTCTACCGCGATCCGCAAGCGCGAATTGGTCACATA GTTATAGAATTTTTGAGCCTTTTTCTTGACATAAAAAGTGTGGTTTTAAAAATTTCCTGGCAGGACCCACGCCAACGTTC AGGAATAATATCTTTTAAAAAGctgagactgccaaggcacacaggggataggn +FSRRS4401CM938 [length=453] [gc=44.15] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=418] IIIIICC>>666IIIICCCIIIIIIIIHHHIIIIIG666IIIIIIIIIIHHHIIIIIIIICCCIIIIIIIIIIIIIIIII I@@@@IIIIIIIIIIIIIHHHIIII???=;IIEEI:://///7544:?IBB72244E8EECEBC=@@@@@@@HHIIIIII IIIIBBBIIIIIIIIIHHHIIIIIIIIIIIIICCCCIIIIIIIIIIIIIIIIIIIIIIIIIIII6666DEIIHEB??D@7 77772222D89EEIIIIIIIHHHIIIIIIIIHHHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIHHHIIIIII IIIIIIIII==?==IIIII???=;I63DDD82--,,,38==::----,,---+++33066;@6380008/:889<:BGII IIIIIIIFE?@C<<7999EEEEEE@@@@EEEEE! @FSRRS4401EQLIK [length=411] [gc=34.31] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=374] tcagTTTAATTTGGTGCTTCCTTTCAATTCCTTAGTTTAAACTTGGCACTGAAGTCTCGCATTTATAACTAGAGCCCGGA TTTTAGAGGCTAAAAAGTTTTCCAGATTTCAAAATTTATTTCGAAACTATTTTTCTGATTGTGATGTGACGGATTTCTAA ATTAAATCGAAATGATGTGTATTGAACTTAACAAGTGATTTTTATCAGATTTTGTCAATGAATAAATTTTAATTTAAATC TCTTTCTAACACTTTCATGATTAAAATCTAACAAAGCGCGACCAGTATGTGAGAAGAGCAAAAACAACAAAAAGTGCTAG CACTAAAGAAGGTTCGAACCCAACACATAACGTAAGAGTTACCGGGAAGAAAACCACTctgagactgccaaggcacacag ggggataggnn +FSRRS4401EQLIK [length=411] [gc=34.31] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=374] III?666??HHHIIIIIIIIIGGGIIIIIIIIIIIGGGHHHIIIIIIIIIIIIIIIIIIIIGGGIIIIIIIIIIHHHIII @@@@IIIIEIE111100----22?=8---:-------,,,,33---5:3,----:1BBEEEHIIIIIIIIIIIB??A122 000...:?=024GIIIIIIIIIIIIIIIIIIECCHHB=//-,,21??<5-002=6FBB?:9<=11/4444//-//77??G EIEEHIACCIIIHHHIIIIIIICCCAIIIHHHHHHIIIIIIIIIIIIIIIIIIIIIIEE1//--822;----.777@EII IIII???IIIIIIIIIIIHHHIIIIIIIIIIIIIIIIIIII994227775555AE;IEEEEEIIIII??9755>@==:3, ,,,,33336!! @FSRRS4401AOV6A [length=309] [gc=22.98] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=273] tcagTTTTCAAATTTTCCGAAATTTGCTGTTTGGTAGAAGGCAAATTATTTGATTGAATTTTGTATTTATTTAAAACAAT TTATTTTAAAATAATAATTTTCCATTGACTTTTTACATTTAATTGATTTTATTATGCATTTTATATTTGTTTTCTAAATA TTCGTTTGCAAACTCACGTTGAAATTGTATTAAACTCGAAATTAGAGTTTTTGAAATTAATTTTTATGTAGCATAATATT TTAAACATATTGGAATTTTATAAAACATTATATTTTTctgagactgccaaggcacacagggggataggn +FSRRS4401AOV6A [length=309] [gc=22.98] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=273] IIIICCCCI;;;CCCCIII???HHHIIIIHHHIIIIIIIIIIHHHIIIHHHIIIIIII@@@@IFICCCICAA;;;;ED?B @@D66445555<<>AAIIIIIIII;;;::III???CCCIII;;;;IFFIIIIICCCBIBIEEDC4444?4BBBE? EIIICHHII;;;HIIIIIIHH;;;HHIIIII;;;IIIIHHHIIIIII>>??>IEEBGG::1111/46FBFBB?=;=A?97 771119:EAAADDBD7777=/111122DA@@B68;;;I8HHIIIII;;;;?>IECCCB/////;745=! @FSRRS4401EG0ZW [length=424] [gc=23.82] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=389] tcagTTTTGATCTTTTAATAATGAATTTTAATGTGTTAAAATGATTGCATTGATGGCATAACCGCATTTAAATTAATTAC ATGAAGTGTAAGTATGAAATTTTCCTTTCCAAATTGCAAAAACTAAAATTTAAAATTTATCGTAAAAATTAACATATATT TTAAACGATTTTAAGAAACATTTGTAAATTATATTTTTGTGAAGCGTTCAAACAAAAATAAACAATAAAATATTTTTCTA TTTAATAGCAAAACATTTGACGATGAAAAGGAAAATGCGGGTTTGAAAATGGGCTTTGCCATGCTATTTTCATAATAACA TATTTTTATTATGAATAATAAATTTACATACAATATATACAGTCTTAAATTTATTCATAATATTTTTGAGAATctgagac tgccaaggcacacaggggataggn +FSRRS4401EG0ZW [length=424] [gc=23.82] [flows=800] [phred_min=0] [phred_max=40] [trimmed_length=389] IIA94445EEII===>IIIIIIIIICCCCIIHIIICC;;;;IIIIIIIIIIIIIIIIIIIIIIIIIF;;666DDIIIIII IIIIIIIIIIIIIEE94442244@@666CC<>==HH;;IIIIIICC @@???III@@@@IC?666HIDDCI?B??CC////-=323?423,,,/=1,,,,-:4E ;??EIIIIICCCCI>;;;IIIIIII<<@@?=////7=A99988<<4455IEEEIIIIIIIIIIIII<999HIIIIIIIII II?????IIIIIIIIIIICAC;55539EIIIIIIIIIIIIIIIIHH999HHHIA=AEEFF@=.....AD@@@DDEEEEFI II;;;977FFCCC@24449?FDD! scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/misc_dna_as_illumina.fastq000066400000000000000000000013771520735541300306360ustar00rootroot00000000000000@FAKE0007 Original version has lower case unambiguous DNA with PHRED scores from 0 to 40 inclusive (in that order) ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTA + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh @FAKE0008 Original version has mixed case unambiguous DNA with PHRED scores from 0 to 40 inclusive (in that order) gTcatAGcgTcatAGcgTcatAGcgTcatAGcgTcatAGcg + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh @FAKE0009 Original version has lower case unambiguous DNA with PHRED scores from 0 to 40 inclusive (in that order) tcagtcagtcagtcagtcagtcagtcagtcagtcagtcagt + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh @FAKE0010 Original version has mixed case ambiguous DNA and PHRED scores of 40, 30, 20, 10 (cycled) gatcrywsmkhbvdnGATCRYWSMKHBVDN + h^TJh^TJh^TJh^TJh^TJh^TJh^TJh^ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/misc_dna_as_sanger.fastq000066400000000000000000000013771520735541300303030ustar00rootroot00000000000000@FAKE0007 Original version has lower case unambiguous DNA with PHRED scores from 0 to 40 inclusive (in that order) ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTA + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0008 Original version has mixed case unambiguous DNA with PHRED scores from 0 to 40 inclusive (in that order) gTcatAGcgTcatAGcgTcatAGcgTcatAGcgTcatAGcg + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0009 Original version has lower case unambiguous DNA with PHRED scores from 0 to 40 inclusive (in that order) tcagtcagtcagtcagtcagtcagtcagtcagtcagtcagt + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0010 Original version has mixed case ambiguous DNA and PHRED scores of 40, 30, 20, 10 (cycled) gatcrywsmkhbvdnGATCRYWSMKHBVDN + I?5+I?5+I?5+I?5+I?5+I?5+I?5+I? scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/misc_dna_original_sanger.fastq000066400000000000000000000013771520735541300315040ustar00rootroot00000000000000@FAKE0007 Original version has lower case unambiguous DNA with PHRED scores from 0 to 40 inclusive (in that order) ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTA + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0008 Original version has mixed case unambiguous DNA with PHRED scores from 0 to 40 inclusive (in that order) gTcatAGcgTcatAGcgTcatAGcgTcatAGcgTcatAGcg + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0009 Original version has lower case unambiguous DNA with PHRED scores from 0 to 40 inclusive (in that order) tcagtcagtcagtcagtcagtcagtcagtcagtcagtcagt + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0010 Original version has mixed case ambiguous DNA and PHRED scores of 40, 30, 20, 10 (cycled) gatcrywsmkhbvdnGATCRYWSMKHBVDN + I?5+I?5+I?5+I?5+I?5+I?5+I?5+I? scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/misc_rna_as_illumina.fastq000066400000000000000000000014061520735541300306450ustar00rootroot00000000000000@FAKE0011 Original version has lower case unambiguous RNA with PHRED scores from 0 to 40 inclusive (in that order) ACGUACGUACGUACGUACGUACGUACGUACGUACGUACGUA + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh @FAKE0012 Original version has mixed case unambiguous RNA with PHRED scores from 0 to 40 inclusive (in that order) gUcauAGcgUcauAGcgUcauAGcgUcauAGcgUcauAGcg + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh @FAKE0013 Original version has lower case unambiguous RNA with PHRED scores from 0 to 40 inclusive (in that order) ucagucagucagucagucagucagucagucagucagucagu + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh @FAKE0014 Original version has mixed case ambiguous RNA with PHRED scores from 35 to 40 inclusive (cycled) gaucrywsmkhbvdnGAUCRYWSMKHBVDN + cdefghcdefghcdefghcdefghcdefgh scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/misc_rna_as_sanger.fastq000066400000000000000000000014061520735541300303120ustar00rootroot00000000000000@FAKE0011 Original version has lower case unambiguous RNA with PHRED scores from 0 to 40 inclusive (in that order) ACGUACGUACGUACGUACGUACGUACGUACGUACGUACGUA + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0012 Original version has mixed case unambiguous RNA with PHRED scores from 0 to 40 inclusive (in that order) gUcauAGcgUcauAGcgUcauAGcgUcauAGcgUcauAGcg + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0013 Original version has lower case unambiguous RNA with PHRED scores from 0 to 40 inclusive (in that order) ucagucagucagucagucagucagucagucagucagucagu + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0014 Original version has mixed case ambiguous RNA with PHRED scores from 35 to 40 inclusive (cycled) gaucrywsmkhbvdnGAUCRYWSMKHBVDN + DEFGHIDEFGHIDEFGHIDEFGHIDEFGHI scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/misc_rna_original_sanger.fastq000066400000000000000000000014061520735541300315130ustar00rootroot00000000000000@FAKE0011 Original version has lower case unambiguous RNA with PHRED scores from 0 to 40 inclusive (in that order) ACGUACGUACGUACGUACGUACGUACGUACGUACGUACGUA + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0012 Original version has mixed case unambiguous RNA with PHRED scores from 0 to 40 inclusive (in that order) gUcauAGcgUcauAGcgUcauAGcgUcauAGcgUcauAGcg + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0013 Original version has lower case unambiguous RNA with PHRED scores from 0 to 40 inclusive (in that order) ucagucagucagucagucagucagucagucagucagucagu + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI @FAKE0014 Original version has mixed case ambiguous RNA with PHRED scores from 35 to 40 inclusive (cycled) gaucrywsmkhbvdnGAUCRYWSMKHBVDN + DEFGHIDEFGHIDEFGHIDEFGHIDEFGHI scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_L&L_CA_data_scores000066400000000000000000000005371520735541300311010ustar00rootroot00000000000000Eigvals 2 0.0961330159181 0.0409418140138 Proportion explained 0 Species 3 2 Species1 0.408869425742 0.0695518116298 Species2 -0.1153860437 -0.299767683538 Species3 -0.309967102571 0.187391917117 Site 3 2 Site1 -0.848956053187 0.882764759014 Site2 -0.220458650578 -1.34482000302 Site3 1.66697179591 0.470324389808 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_PCoA_sample_data_3_scores000066400000000000000000000030601520735541300325200ustar00rootroot00000000000000Eigvals 9 0.512367260461 0.300719094427 0.267912066004 0.208988681078 0.19169895326 0.16054234528 0.15017695712 0.122457748167 0.0 Proportion explained 9 0.267573832777 0.15704469605 0.139911863774 0.109140272454 0.100111048503 0.0838401161912 0.0784269939011 0.0639511763509 0.0 Species 0 0 Site 9 9 PC.636 -0.258465461183 0.173999546883 0.0382875792552 -0.19447750562 0.0831176020844 0.262430333201 -0.0231636392235 -0.0184794039581 0.0 PC.635 -0.271001135391 -0.0185951319063 -0.0864841926349 0.118064245315 -0.198808358437 -0.0211723599535 -0.191024027565 0.155646592377 0.0 PC.356 0.235077898175 0.0962519254489 -0.345792726714 -0.00320862577619 -0.0963777675519 0.0457025386953 0.185472813286 0.0404093971793 0.0 PC.481 0.0261407664325 -0.0111459676533 0.147660603015 0.29087660853 0.203945472801 0.0619712384758 0.101641328709 0.105690998719 0.0 PC.354 0.285007552283 -0.0192549888483 0.0623263375385 0.138126799852 -0.104798602423 0.0951720730628 -0.129636097542 -0.220687170372 0.0 PC.593 0.204636326241 -0.139361150932 0.291513819623 -0.181566786821 -0.159580132715 -0.0246412130162 0.0866252404441 0.0996221476871 0.0 PC.355 0.233482403212 0.225257974068 -0.0188623096268 -0.107729981831 0.177108999572 -0.192905835151 -0.149819471408 0.0383549037465 0.0 PC.607 -0.0949631911323 -0.420974802495 -0.154869454869 -0.0898427509281 0.152618194488 -0.0334232691501 -0.0251224777303 -0.0508988536409 0.0 PC.634 -0.359915158638 0.113822595435 0.0662203444138 0.0297579972788 -0.0572254078183 -0.193133506163 0.145026331031 -0.149658611738 0.0 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error1000066400000000000000000000107311520735541300270210ustar00rootroot000000000000000.366135830393 0.186887643052 0.0788466514249 0.082287840501 0.0351348475787 0.0233265839374 0.0099048981912 0.00122461669234 0.000417454724117 Proportion explained 0 Species 9 9 Species0 0.110350890177 0.282399990052 -0.203028976154 -0.00192462284409 -0.082232863384 0.0857314258364 -0.0122038907184 -0.0425198793666 0.00466719926338 Species1 0.141359038961 0.303495645402 0.395441211576 -0.14126625534 -0.0268859204718 0.143253061936 0.0430260301697 0.0476377655759 -0.00228172378295 Species2 -1.01552204222 0.0958317865043 -0.198262718034 -0.104801030067 0.130025239749 0.0244045261332 0.0464701211285 0.0269279200532 0.0350103177576 Species3 -1.03620650502 0.109624974112 0.220984718362 0.223640072997 -0.243745876054 -0.0259064859794 -0.0534088909011 -0.0315611195993 0.0256448427552 Species4 1.05371722248 0.537178749104 -0.438075060322 0.223480553581 -0.323948461806 0.124644870822 -0.119275907223 0.0416254660329 -0.0381955235096 Species5 0.998558655 0.573960582723 0.679918103399 -0.389963380717 0.299077945999 0.328451006171 0.21215881857 -0.0829871883001 -0.0439653996462 Species6 0.255245719879 -0.178168259149 -0.204127155429 0.433397565801 0.0707099230629 -0.18817306522 0.126908756045 0.0044937289123 -0.0122511718244 Species7 0.146555872394 -0.857362497037 -0.0152499051659 0.0527604990862 0.354475793915 -0.0416813697787 -0.199011239586 -0.00213723187073 -0.00782946141667 Species8 0.413705102117 -0.707948964322 0.21569736034 -0.690314241725 -0.148431001217 -0.334251868558 -0.00628707445028 -0.00364123416731 -0.0122722164511 Site 10 9 Site0 0.710587311248 -3.08166800613 0.219651379947 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.584771352278 -3.00669301091 -0.947448656768 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.762734278287 -3.15258603503 2.13924426714 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.11230735331 1.07150585141 -1.87527740873 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.979116769996 -0.0603144289026 -0.696277367656 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.04322560423 0.459426970165 -0.639802790578 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -0.954490118162 -0.0847021660539 0.132509124411 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.947268764751 -0.108370567311 0.526107182587 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.14808173207 0.490449274267 0.478353666755 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 1.03291557934 1.0350490304 2.74691777314 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 Biplot 3 3 -0.169746767979 0.63069090084 0.760769036049 -0.994016563505 0.0609533148724 -0.0449369418179 0.184352565909 -0.974867543612 0.0309865007541 Site constraints 10 9 Site0 0.692138797603 -3.08053663489 -0.328747278055 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.664559513865 -3.06214571808 0.230249303805 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.636980230127 -3.04375480127 0.789245885666 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.10887578995 0.500396915484 -1.55606822404 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.970016224052 0.0654867737684 -1.1206070781 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.05371722248 0.537178749104 -0.438075060322 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -1.02517479153 0.102268607388 -0.00261391438256 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.998558655 0.573960582723 0.679918103399 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.080333359 0.139050441007 1.11537924934 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 0.943400087524 0.610742416342 1.79791126712 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error10000066400000000000000000000004621520735541300271010ustar00rootroot00000000000000Eigvals 2 0.0961330159181 0.0409418140138 Proportion explained 0 Species 3 2 Species1 0.408869425742 0.0695518116298 Species2 -0.1153860437 -0.299767683538 Species3 -0.309967102571 0.187391917117 Site 3 2 Site1 -0.848956053187 Site2 -0.220458650578 Site3 1.66697179591 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error11000066400000000000000000000107421520735541300271040ustar00rootroot00000000000000Eigvals 9 0.366135830393 0.186887643052 0.0788466514249 0.082287840501 0.0351348475787 0.0233265839374 0.0099048981912 0.00122461669234 0.000417454724117 Proportion explained 0 Species 9 9 Species0 0.110350890177 0.282399990052 -0.203028976154 -0.00192462284409 -0.082232863384 0.0857314258364 -0.0122038907184 -0.0425198793666 0.00466719926338 Species1 0.141359038961 0.303495645402 0.395441211576 -0.14126625534 -0.0268859204718 0.143253061936 0.0430260301697 0.0476377655759 -0.00228172378295 Species2 -1.01552204222 0.0958317865043 -0.198262718034 -0.104801030067 0.130025239749 0.0244045261332 0.0464701211285 0.0269279200532 0.0350103177576 Species3 -1.03620650502 0.109624974112 0.220984718362 0.223640072997 -0.243745876054 -0.0259064859794 -0.0534088909011 -0.0315611195993 0.0256448427552 Species4 1.05371722248 0.537178749104 -0.438075060322 0.223480553581 -0.323948461806 0.124644870822 -0.119275907223 0.0416254660329 -0.0381955235096 Species5 0.998558655 0.573960582723 0.679918103399 -0.389963380717 0.299077945999 0.328451006171 0.21215881857 -0.0829871883001 -0.0439653996462 Species6 0.255245719879 -0.178168259149 -0.204127155429 0.433397565801 0.0707099230629 -0.18817306522 0.126908756045 0.0044937289123 -0.0122511718244 Species7 0.146555872394 -0.857362497037 -0.0152499051659 0.0527604990862 0.354475793915 -0.0416813697787 -0.199011239586 -0.00213723187073 -0.00782946141667 Species8 0.413705102117 -0.707948964322 0.21569736034 -0.690314241725 -0.148431001217 -0.334251868558 -0.00628707445028 -0.00364123416731 -0.0122722164511 Site 10 9 Site0 0.710587311248 -3.08166800613 0.219651379947 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.584771352278 -3.00669301091 -0.947448656768 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.762734278287 -3.15258603503 2.13924426714 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.11230735331 1.07150585141 -1.87527740873 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.979116769996 -0.0603144289026 -0.696277367656 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.04322560423 0.459426970165 -0.639802790578 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -0.954490118162 -0.0847021660539 0.132509124411 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.947268764751 -0.108370567311 0.526107182587 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.14808173207 0.490449274267 0.478353666755 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 1.03291557934 1.0350490304 2.74691777314 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 Biplot 3 3 -0.169746767979 0.63069090084 0.760769036049 -0.994016563505 0.0609533148724 -0.0449369418179 0.184352565909 -0.974867543612 0.0309865007541 Site constraints 10 9 Site0 0.692138797603 -3.08053663489 -0.328747278055 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.664559513865 -3.06214571808 0.230249303805 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Bro2 0.636980230127 -3.04375480127 0.789245885666 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.10887578995 0.500396915484 -1.55606822404 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.970016224052 0.0654867737684 -1.1206070781 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.05371722248 0.537178749104 -0.438075060322 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -1.02517479153 0.102268607388 -0.00261391438256 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.998558655 0.573960582723 0.679918103399 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.080333359 0.139050441007 1.11537924934 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 0.943400087524 0.610742416342 1.79791126712 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error12000066400000000000000000000030411520735541300270770ustar00rootroot00000000000000Eigvals 9 0.512367260461 0.300719094427 0.208988681078 0.19169895326 0.16054234528 0.15017695712 0.122457748167 0.0 Proportion explained 9 0.267573832777 0.15704469605 0.139911863774 0.109140272454 0.100111048503 0.0838401161912 0.0784269939011 0.0639511763509 0.0 Species 0 0 Site 9 9 PC.636 -0.258465461183 0.173999546883 0.0382875792552 -0.19447750562 0.0831176020844 0.262430333201 -0.0231636392235 -0.0184794039581 0.0 PC.635 -0.271001135391 -0.0185951319063 -0.0864841926349 0.118064245315 -0.198808358437 -0.0211723599535 -0.191024027565 0.155646592377 0.0 PC.356 0.235077898175 0.0962519254489 -0.345792726714 -0.00320862577619 -0.0963777675519 0.0457025386953 0.185472813286 0.0404093971793 0.0 PC.481 0.0261407664325 -0.0111459676533 0.147660603015 0.29087660853 0.203945472801 0.0619712384758 0.101641328709 0.105690998719 0.0 PC.354 0.285007552283 -0.0192549888483 0.0623263375385 0.138126799852 -0.104798602423 0.0951720730628 -0.129636097542 -0.220687170372 0.0 PC.593 0.204636326241 -0.139361150932 0.291513819623 -0.181566786821 -0.159580132715 -0.0246412130162 0.0866252404441 0.0996221476871 0.0 PC.355 0.233482403212 0.225257974068 -0.0188623096268 -0.107729981831 0.177108999572 -0.192905835151 -0.149819471408 0.0383549037465 0.0 PC.607 -0.0949631911323 -0.420974802495 -0.154869454869 -0.0898427509281 0.152618194488 -0.0334232691501 -0.0251224777303 -0.0508988536409 0.0 PC.634 -0.359915158638 0.113822595435 0.0662203444138 0.0297579972788 -0.0572254078183 -0.193133506163 0.145026331031 -0.149658611738 0.0 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error13000066400000000000000000000030411520735541300271000ustar00rootroot00000000000000Eigvals 9 0.512367260461 0.300719094427 0.267912066004 0.208988681078 0.19169895326 0.16054234528 0.15017695712 0.122457748167 0.0 Proportion explained 9 0.267573832777 0.15704469605 0.109140272454 0.100111048503 0.0838401161912 0.0784269939011 0.0639511763509 0.0 Species 0 0 Site 9 9 PC.636 -0.258465461183 0.173999546883 0.0382875792552 -0.19447750562 0.0831176020844 0.262430333201 -0.0231636392235 -0.0184794039581 0.0 PC.635 -0.271001135391 -0.0185951319063 -0.0864841926349 0.118064245315 -0.198808358437 -0.0211723599535 -0.191024027565 0.155646592377 0.0 PC.356 0.235077898175 0.0962519254489 -0.345792726714 -0.00320862577619 -0.0963777675519 0.0457025386953 0.185472813286 0.0404093971793 0.0 PC.481 0.0261407664325 -0.0111459676533 0.147660603015 0.29087660853 0.203945472801 0.0619712384758 0.101641328709 0.105690998719 0.0 PC.354 0.285007552283 -0.0192549888483 0.0623263375385 0.138126799852 -0.104798602423 0.0951720730628 -0.129636097542 -0.220687170372 0.0 PC.593 0.204636326241 -0.139361150932 0.291513819623 -0.181566786821 -0.159580132715 -0.0246412130162 0.0866252404441 0.0996221476871 0.0 PC.355 0.233482403212 0.225257974068 -0.0188623096268 -0.107729981831 0.177108999572 -0.192905835151 -0.149819471408 0.0383549037465 0.0 PC.607 -0.0949631911323 -0.420974802495 -0.154869454869 -0.0898427509281 0.152618194488 -0.0334232691501 -0.0251224777303 -0.0508988536409 0.0 PC.634 -0.359915158638 0.113822595435 0.0662203444138 0.0297579972788 -0.0572254078183 -0.193133506163 0.145026331031 -0.149658611738 0.0 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error14000066400000000000000000000030601520735541300271020ustar00rootroot00000000000000Eigvals 9 0.512367260461 0.300719094427 0.267912066004 0.208988681078 0.19169895326 0.16054234528 0.15017695712 0.122457748167 0.0 Proportion explained 9 0.267573832777 0.15704469605 0.139911863774 0.109140272454 0.100111048503 0.0838401161912 0.0784269939011 0.0639511763509 0.0 Species 0 0 Site 9 0 PC.636 -0.258465461183 0.173999546883 0.0382875792552 -0.19447750562 0.0831176020844 0.262430333201 -0.0231636392235 -0.0184794039581 0.0 PC.635 -0.271001135391 -0.0185951319063 -0.0864841926349 0.118064245315 -0.198808358437 -0.0211723599535 -0.191024027565 0.155646592377 0.0 PC.356 0.235077898175 0.0962519254489 -0.345792726714 -0.00320862577619 -0.0963777675519 0.0457025386953 0.185472813286 0.0404093971793 0.0 PC.481 0.0261407664325 -0.0111459676533 0.147660603015 0.29087660853 0.203945472801 0.0619712384758 0.101641328709 0.105690998719 0.0 PC.354 0.285007552283 -0.0192549888483 0.0623263375385 0.138126799852 -0.104798602423 0.0951720730628 -0.129636097542 -0.220687170372 0.0 PC.593 0.204636326241 -0.139361150932 0.291513819623 -0.181566786821 -0.159580132715 -0.0246412130162 0.0866252404441 0.0996221476871 0.0 PC.355 0.233482403212 0.225257974068 -0.0188623096268 -0.107729981831 0.177108999572 -0.192905835151 -0.149819471408 0.0383549037465 0.0 PC.607 -0.0949631911323 -0.420974802495 -0.154869454869 -0.0898427509281 0.152618194488 -0.0334232691501 -0.0251224777303 -0.0508988536409 0.0 PC.634 -0.359915158638 0.113822595435 0.0662203444138 0.0297579972788 -0.0572254078183 -0.193133506163 0.145026331031 -0.149658611738 0.0 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error15000066400000000000000000000030071520735541300271040ustar00rootroot00000000000000Eigvals 9 0.512367260461 0.300719094427 0.267912066004 0.208988681078 0.19169895326 0.16054234528 0.15017695712 0.122457748167 0.0 Proportion explained 9 0.267573832777 0.15704469605 0.139911863774 0.109140272454 0.100111048503 0.0838401161912 0.0784269939011 0.0639511763509 0.0 Species 0 0 Site 9 9 PC.636 -0.258465461183 0.173999546883 0.0382875792552 -0.19447750562 0.0831176020844 0.262430333201 -0.0231636392235 -0.0184794039581 PC.635 -0.271001135391 -0.0185951319063 -0.0864841926349 0.118064245315 -0.198808358437 -0.0211723599535 -0.191024027565 0.155646592377 PC.356 0.235077898175 0.0962519254489 -0.345792726714 -0.00320862577619 -0.0963777675519 0.0457025386953 0.185472813286 0.0404093971793 PC.481 0.0261407664325 -0.0111459676533 0.147660603015 0.29087660853 0.203945472801 0.0619712384758 0.101641328709 0.105690998719 PC.354 0.285007552283 -0.0192549888483 0.0623263375385 0.138126799852 -0.104798602423 0.0951720730628 -0.129636097542 -0.220687170372 PC.593 0.204636326241 -0.139361150932 0.291513819623 -0.181566786821 -0.159580132715 -0.0246412130162 0.0866252404441 0.0996221476871 PC.355 0.233482403212 0.225257974068 -0.0188623096268 -0.107729981831 0.177108999572 -0.192905835151 -0.149819471408 0.0383549037465 PC.607 -0.0949631911323 -0.420974802495 -0.154869454869 -0.0898427509281 0.152618194488 -0.0334232691501 -0.0251224777303 -0.0508988536409 PC.634 -0.359915158638 0.113822595435 0.0662203444138 0.0297579972788 -0.0572254078183 -0.193133506163 0.145026331031 -0.149658611738 Biplot Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error16000066400000000000000000000107431520735541300271120ustar00rootroot00000000000000Eigvals 9 0.366135830393 0.186887643052 0.0788466514249 0.082287840501 0.0351348475787 0.0233265839374 0.0099048981912 0.00122461669234 0.000417454724117 Proportion explained 0 Species 9 9 Species0 0.110350890177 0.282399990052 -0.203028976154 -0.00192462284409 -0.082232863384 0.0857314258364 -0.0122038907184 -0.0425198793666 0.00466719926338 Species1 0.141359038961 0.303495645402 0.395441211576 -0.14126625534 -0.0268859204718 0.143253061936 0.0430260301697 0.0476377655759 -0.00228172378295 Species2 -1.01552204222 0.0958317865043 -0.198262718034 -0.104801030067 0.130025239749 0.0244045261332 0.0464701211285 0.0269279200532 0.0350103177576 Species3 -1.03620650502 0.109624974112 0.220984718362 0.223640072997 -0.243745876054 -0.0259064859794 -0.0534088909011 -0.0315611195993 0.0256448427552 Species4 1.05371722248 0.537178749104 -0.438075060322 0.223480553581 -0.323948461806 0.124644870822 -0.119275907223 0.0416254660329 -0.0381955235096 Species5 0.998558655 0.573960582723 0.679918103399 -0.389963380717 0.299077945999 0.328451006171 0.21215881857 -0.0829871883001 -0.0439653996462 Species6 0.255245719879 -0.178168259149 -0.204127155429 0.433397565801 0.0707099230629 -0.18817306522 0.126908756045 0.0044937289123 -0.0122511718244 Species7 0.146555872394 -0.857362497037 -0.0152499051659 0.0527604990862 0.354475793915 -0.0416813697787 -0.199011239586 -0.00213723187073 -0.00782946141667 Species8 0.413705102117 -0.707948964322 0.21569736034 -0.690314241725 -0.148431001217 -0.334251868558 -0.00628707445028 -0.00364123416731 -0.0122722164511 Site 10 9 Site0 0.710587311248 -3.08166800613 0.219651379947 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.584771352278 -3.00669301091 -0.947448656768 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.762734278287 -3.15258603503 2.13924426714 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.11230735331 1.07150585141 -1.87527740873 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.979116769996 -0.0603144289026 -0.696277367656 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.04322560423 0.459426970165 -0.639802790578 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -0.954490118162 -0.0847021660539 0.132509124411 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.947268764751 -0.108370567311 0.526107182587 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.14808173207 0.490449274267 0.478353666755 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 1.03291557934 1.0350490304 2.74691777314 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 Biplot 3 0 -0.169746767979 0.63069090084 0.760769036049 -0.994016563505 0.0609533148724 -0.0449369418179 0.184352565909 -0.974867543612 0.0309865007541 Site constraints 10 9 Site0 0.692138797603 -3.08053663489 -0.328747278055 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.664559513865 -3.06214571808 0.230249303805 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.636980230127 -3.04375480127 0.789245885666 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.10887578995 0.500396915484 -1.55606822404 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.970016224052 0.0654867737684 -1.1206070781 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.05371722248 0.537178749104 -0.438075060322 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -1.02517479153 0.102268607388 -0.00261391438256 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.998558655 0.573960582723 0.679918103399 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.080333359 0.139050441007 1.11537924934 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 0.943400087524 0.610742416342 1.79791126712 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error17000066400000000000000000000106631520735541300271140ustar00rootroot00000000000000Eigvals 9 0.366135830393 0.186887643052 0.0788466514249 0.082287840501 0.0351348475787 0.0233265839374 0.0099048981912 0.00122461669234 0.000417454724117 Proportion explained 0 Species 9 9 Species0 0.110350890177 0.282399990052 -0.203028976154 -0.00192462284409 -0.082232863384 0.0857314258364 -0.0122038907184 -0.0425198793666 0.00466719926338 Species1 0.141359038961 0.303495645402 0.395441211576 -0.14126625534 -0.0268859204718 0.143253061936 0.0430260301697 0.0476377655759 -0.00228172378295 Species2 -1.01552204222 0.0958317865043 -0.198262718034 -0.104801030067 0.130025239749 0.0244045261332 0.0464701211285 0.0269279200532 0.0350103177576 Species3 -1.03620650502 0.109624974112 0.220984718362 0.223640072997 -0.243745876054 -0.0259064859794 -0.0534088909011 -0.0315611195993 0.0256448427552 Species4 1.05371722248 0.537178749104 -0.438075060322 0.223480553581 -0.323948461806 0.124644870822 -0.119275907223 0.0416254660329 -0.0381955235096 Species5 0.998558655 0.573960582723 0.679918103399 -0.389963380717 0.299077945999 0.328451006171 0.21215881857 -0.0829871883001 -0.0439653996462 Species6 0.255245719879 -0.178168259149 -0.204127155429 0.433397565801 0.0707099230629 -0.18817306522 0.126908756045 0.0044937289123 -0.0122511718244 Species7 0.146555872394 -0.857362497037 -0.0152499051659 0.0527604990862 0.354475793915 -0.0416813697787 -0.199011239586 -0.00213723187073 -0.00782946141667 Species8 0.413705102117 -0.707948964322 0.21569736034 -0.690314241725 -0.148431001217 -0.334251868558 -0.00628707445028 -0.00364123416731 -0.0122722164511 Site 10 9 Site0 0.710587311248 -3.08166800613 0.219651379947 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.584771352278 -3.00669301091 -0.947448656768 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.762734278287 -3.15258603503 2.13924426714 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.11230735331 1.07150585141 -1.87527740873 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.979116769996 -0.0603144289026 -0.696277367656 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.04322560423 0.459426970165 -0.639802790578 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -0.954490118162 -0.0847021660539 0.132509124411 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.947268764751 -0.108370567311 0.526107182587 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.14808173207 0.490449274267 0.478353666755 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 1.03291557934 1.0350490304 2.74691777314 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 Biplot 3 3 -0.169746767979 0.63069090084 -0.994016563505 0.0609533148724 0.184352565909 -0.974867543612 Site constraints 10 9 Site0 0.692138797603 -3.08053663489 -0.328747278055 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.664559513865 -3.06214571808 0.230249303805 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.636980230127 -3.04375480127 0.789245885666 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.10887578995 0.500396915484 -1.55606822404 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.970016224052 0.0654867737684 -1.1206070781 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.05371722248 0.537178749104 -0.438075060322 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -1.02517479153 0.102268607388 -0.00261391438256 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.998558655 0.573960582723 0.679918103399 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.080333359 0.139050441007 1.11537924934 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 0.943400087524 0.610742416342 1.79791126712 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error18000066400000000000000000000030421520735541300271060ustar00rootroot00000000000000Eigvals 9 0.512367260461 0.300719094427 0.267912066004 0.208988681078 0.19169895326 0.16054234528 0.15017695712 0.122457748167 0.0 Proportion explained 8 0.267573832777 0.139911863774 0.109140272454 0.100111048503 0.0838401161912 0.0784269939011 0.0639511763509 0.0 Species 0 0 Site 9 9 PC.636 -0.258465461183 0.173999546883 0.0382875792552 -0.19447750562 0.0831176020844 0.262430333201 -0.0231636392235 -0.0184794039581 0.0 PC.635 -0.271001135391 -0.0185951319063 -0.0864841926349 0.118064245315 -0.198808358437 -0.0211723599535 -0.191024027565 0.155646592377 0.0 PC.356 0.235077898175 0.0962519254489 -0.345792726714 -0.00320862577619 -0.0963777675519 0.0457025386953 0.185472813286 0.0404093971793 0.0 PC.481 0.0261407664325 -0.0111459676533 0.147660603015 0.29087660853 0.203945472801 0.0619712384758 0.101641328709 0.105690998719 0.0 PC.354 0.285007552283 -0.0192549888483 0.0623263375385 0.138126799852 -0.104798602423 0.0951720730628 -0.129636097542 -0.220687170372 0.0 PC.593 0.204636326241 -0.139361150932 0.291513819623 -0.181566786821 -0.159580132715 -0.0246412130162 0.0866252404441 0.0996221476871 0.0 PC.355 0.233482403212 0.225257974068 -0.0188623096268 -0.107729981831 0.177108999572 -0.192905835151 -0.149819471408 0.0383549037465 0.0 PC.607 -0.0949631911323 -0.420974802495 -0.154869454869 -0.0898427509281 0.152618194488 -0.0334232691501 -0.0251224777303 -0.0508988536409 0.0 PC.634 -0.359915158638 0.113822595435 0.0662203444138 0.0297579972788 -0.0572254078183 -0.193133506163 0.145026331031 -0.149658611738 0.0 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error19000066400000000000000000000004601520735541300271100ustar00rootroot00000000000000Eigvals 2 0.0961330159181 0.0409418140138 Proportion explained 0 Species 3 1 Species1 0.408869425742 Species2 -0.1153860437 Species3 -0.309967102571 Site 3 2 Site1 -0.848956053187 0.882764759014 Site2 -0.220458650578 -1.34482000302 Site3 1.66697179591 0.470324389808 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error2000066400000000000000000000107131520735541300270220ustar00rootroot00000000000000Eigvals 9 0.366135830393 0.186887643052 0.0788466514249 0.082287840501 0.0351348475787 0.0233265839374 0.0099048981912 0.00122461669234 0.000417454724117 Species 9 9 Species0 0.110350890177 0.282399990052 -0.203028976154 -0.00192462284409 -0.082232863384 0.0857314258364 -0.0122038907184 -0.0425198793666 0.00466719926338 Species1 0.141359038961 0.303495645402 0.395441211576 -0.14126625534 -0.0268859204718 0.143253061936 0.0430260301697 0.0476377655759 -0.00228172378295 Species2 -1.01552204222 0.0958317865043 -0.198262718034 -0.104801030067 0.130025239749 0.0244045261332 0.0464701211285 0.0269279200532 0.0350103177576 Species3 -1.03620650502 0.109624974112 0.220984718362 0.223640072997 -0.243745876054 -0.0259064859794 -0.0534088909011 -0.0315611195993 0.0256448427552 Species4 1.05371722248 0.537178749104 -0.438075060322 0.223480553581 -0.323948461806 0.124644870822 -0.119275907223 0.0416254660329 -0.0381955235096 Species5 0.998558655 0.573960582723 0.679918103399 -0.389963380717 0.299077945999 0.328451006171 0.21215881857 -0.0829871883001 -0.0439653996462 Species6 0.255245719879 -0.178168259149 -0.204127155429 0.433397565801 0.0707099230629 -0.18817306522 0.126908756045 0.0044937289123 -0.0122511718244 Species7 0.146555872394 -0.857362497037 -0.0152499051659 0.0527604990862 0.354475793915 -0.0416813697787 -0.199011239586 -0.00213723187073 -0.00782946141667 Species8 0.413705102117 -0.707948964322 0.21569736034 -0.690314241725 -0.148431001217 -0.334251868558 -0.00628707445028 -0.00364123416731 -0.0122722164511 Site 10 9 Site0 0.710587311248 -3.08166800613 0.219651379947 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.584771352278 -3.00669301091 -0.947448656768 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.762734278287 -3.15258603503 2.13924426714 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.11230735331 1.07150585141 -1.87527740873 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.979116769996 -0.0603144289026 -0.696277367656 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.04322560423 0.459426970165 -0.639802790578 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -0.954490118162 -0.0847021660539 0.132509124411 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.947268764751 -0.108370567311 0.526107182587 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.14808173207 0.490449274267 0.478353666755 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 1.03291557934 1.0350490304 2.74691777314 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 Biplot 3 3 -0.169746767979 0.63069090084 0.760769036049 -0.994016563505 0.0609533148724 -0.0449369418179 0.184352565909 -0.974867543612 0.0309865007541 Site constraints 10 9 Site0 0.692138797603 -3.08053663489 -0.328747278055 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.664559513865 -3.06214571808 0.230249303805 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.636980230127 -3.04375480127 0.789245885666 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.10887578995 0.500396915484 -1.55606822404 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.970016224052 0.0654867737684 -1.1206070781 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.05371722248 0.537178749104 -0.438075060322 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -1.02517479153 0.102268607388 -0.00261391438256 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.998558655 0.573960582723 0.679918103399 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.080333359 0.139050441007 1.11537924934 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 0.943400087524 0.610742416342 1.79791126712 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error20000066400000000000000000000004621520735541300271020ustar00rootroot00000000000000Eigvals 2 0.0961330159181 0.0409418140138 Proportion explained 0 Species 3 2 Species1 0.408869425742 0.0695518116298 Species2 -0.1153860437 -0.299767683538 Species3 -0.309967102571 0.187391917117 Site 3 1 Site1 -0.848956053187 Site2 -0.220458650578 Site3 1.66697179591 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error21000066400000000000000000000000121520735541300270720ustar00rootroot00000000000000Eigvals 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error22000066400000000000000000000000221520735541300270740ustar00rootroot00000000000000Eigvals 1 0.12345 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error23000066400000000000000000000000521520735541300271000ustar00rootroot00000000000000Eigvals 1 0.12345 Proportion explained 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error24000066400000000000000000000001131520735541300270770ustar00rootroot00000000000000Eigvals 1 0.12345 Proportion explained 1 0.6789 Species 2 1 foo 0.987654 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error3000066400000000000000000000107271520735541300270300ustar00rootroot00000000000000Eigvals 9 0.366135830393 0.186887643052 0.0788466514249 0.082287840501 0.0351348475787 0.0233265839374 0.0099048981912 0.00122461669234 0.000417454724117 Proportion explained 0 Species0 0.110350890177 0.282399990052 -0.203028976154 -0.00192462284409 -0.082232863384 0.0857314258364 -0.0122038907184 -0.0425198793666 0.00466719926338 Species1 0.141359038961 0.303495645402 0.395441211576 -0.14126625534 -0.0268859204718 0.143253061936 0.0430260301697 0.0476377655759 -0.00228172378295 Species2 -1.01552204222 0.0958317865043 -0.198262718034 -0.104801030067 0.130025239749 0.0244045261332 0.0464701211285 0.0269279200532 0.0350103177576 Species3 -1.03620650502 0.109624974112 0.220984718362 0.223640072997 -0.243745876054 -0.0259064859794 -0.0534088909011 -0.0315611195993 0.0256448427552 Species4 1.05371722248 0.537178749104 -0.438075060322 0.223480553581 -0.323948461806 0.124644870822 -0.119275907223 0.0416254660329 -0.0381955235096 Species5 0.998558655 0.573960582723 0.679918103399 -0.389963380717 0.299077945999 0.328451006171 0.21215881857 -0.0829871883001 -0.0439653996462 Species6 0.255245719879 -0.178168259149 -0.204127155429 0.433397565801 0.0707099230629 -0.18817306522 0.126908756045 0.0044937289123 -0.0122511718244 Species7 0.146555872394 -0.857362497037 -0.0152499051659 0.0527604990862 0.354475793915 -0.0416813697787 -0.199011239586 -0.00213723187073 -0.00782946141667 Species8 0.413705102117 -0.707948964322 0.21569736034 -0.690314241725 -0.148431001217 -0.334251868558 -0.00628707445028 -0.00364123416731 -0.0122722164511 Site 10 9 Site0 0.710587311248 -3.08166800613 0.219651379947 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.584771352278 -3.00669301091 -0.947448656768 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.762734278287 -3.15258603503 2.13924426714 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.11230735331 1.07150585141 -1.87527740873 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.979116769996 -0.0603144289026 -0.696277367656 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.04322560423 0.459426970165 -0.639802790578 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -0.954490118162 -0.0847021660539 0.132509124411 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.947268764751 -0.108370567311 0.526107182587 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.14808173207 0.490449274267 0.478353666755 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 1.03291557934 1.0350490304 2.74691777314 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 Biplot 3 3 -0.169746767979 0.63069090084 0.760769036049 -0.994016563505 0.0609533148724 -0.0449369418179 0.184352565909 -0.974867543612 0.0309865007541 Site constraints 10 9 Site0 0.692138797603 -3.08053663489 -0.328747278055 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.664559513865 -3.06214571808 0.230249303805 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.636980230127 -3.04375480127 0.789245885666 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.10887578995 0.500396915484 -1.55606822404 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.970016224052 0.0654867737684 -1.1206070781 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.05371722248 0.537178749104 -0.438075060322 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -1.02517479153 0.102268607388 -0.00261391438256 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.998558655 0.573960582723 0.679918103399 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.080333359 0.139050441007 1.11537924934 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 0.943400087524 0.610742416342 1.79791126712 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error4000066400000000000000000000107311520735541300270240ustar00rootroot00000000000000Eigvals 9 0.366135830393 0.186887643052 0.0788466514249 0.082287840501 0.0351348475787 0.0233265839374 0.0099048981912 0.00122461669234 0.000417454724117 Proportion explained 0 Species 9 9 Species0 0.110350890177 0.282399990052 -0.203028976154 -0.00192462284409 -0.082232863384 0.0857314258364 -0.0122038907184 -0.0425198793666 0.00466719926338 Species1 0.141359038961 0.303495645402 0.395441211576 -0.14126625534 -0.0268859204718 0.143253061936 0.0430260301697 0.0476377655759 -0.00228172378295 Species2 -1.01552204222 0.0958317865043 -0.198262718034 -0.104801030067 0.130025239749 0.0244045261332 0.0464701211285 0.0269279200532 0.0350103177576 Species3 -1.03620650502 0.109624974112 0.220984718362 0.223640072997 -0.243745876054 -0.0259064859794 -0.0534088909011 -0.0315611195993 0.0256448427552 Species4 1.05371722248 0.537178749104 -0.438075060322 0.223480553581 -0.323948461806 0.124644870822 -0.119275907223 0.0416254660329 -0.0381955235096 Species5 0.998558655 0.573960582723 0.679918103399 -0.389963380717 0.299077945999 0.328451006171 0.21215881857 -0.0829871883001 -0.0439653996462 Species6 0.255245719879 -0.178168259149 -0.204127155429 0.433397565801 0.0707099230629 -0.18817306522 0.126908756045 0.0044937289123 -0.0122511718244 Species7 0.146555872394 -0.857362497037 -0.0152499051659 0.0527604990862 0.354475793915 -0.0416813697787 -0.199011239586 -0.00213723187073 -0.00782946141667 Species8 0.413705102117 -0.707948964322 0.21569736034 -0.690314241725 -0.148431001217 -0.334251868558 -0.00628707445028 -0.00364123416731 -0.0122722164511 Site0 0.710587311248 -3.08166800613 0.219651379947 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.584771352278 -3.00669301091 -0.947448656768 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.762734278287 -3.15258603503 2.13924426714 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.11230735331 1.07150585141 -1.87527740873 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.979116769996 -0.0603144289026 -0.696277367656 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.04322560423 0.459426970165 -0.639802790578 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -0.954490118162 -0.0847021660539 0.132509124411 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.947268764751 -0.108370567311 0.526107182587 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.14808173207 0.490449274267 0.478353666755 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 1.03291557934 1.0350490304 2.74691777314 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 Biplot 3 3 -0.169746767979 0.63069090084 0.760769036049 -0.994016563505 0.0609533148724 -0.0449369418179 0.184352565909 -0.974867543612 0.0309865007541 Site constraints 10 9 Site0 0.692138797603 -3.08053663489 -0.328747278055 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.664559513865 -3.06214571808 0.230249303805 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.636980230127 -3.04375480127 0.789245885666 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.10887578995 0.500396915484 -1.55606822404 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.970016224052 0.0654867737684 -1.1206070781 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.05371722248 0.537178749104 -0.438075060322 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -1.02517479153 0.102268607388 -0.00261391438256 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.998558655 0.573960582723 0.679918103399 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.080333359 0.139050441007 1.11537924934 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 0.943400087524 0.610742416342 1.79791126712 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error5000066400000000000000000000107311520735541300270250ustar00rootroot00000000000000Eigvals 9 0.366135830393 0.186887643052 0.0788466514249 0.082287840501 0.0351348475787 0.0233265839374 0.0099048981912 0.00122461669234 0.000417454724117 Proportion explained 0 Species 9 9 Species0 0.110350890177 0.282399990052 -0.203028976154 -0.00192462284409 -0.082232863384 0.0857314258364 -0.0122038907184 -0.0425198793666 0.00466719926338 Species1 0.141359038961 0.303495645402 0.395441211576 -0.14126625534 -0.0268859204718 0.143253061936 0.0430260301697 0.0476377655759 -0.00228172378295 Species2 -1.01552204222 0.0958317865043 -0.198262718034 -0.104801030067 0.130025239749 0.0244045261332 0.0464701211285 0.0269279200532 0.0350103177576 Species3 -1.03620650502 0.109624974112 0.220984718362 0.223640072997 -0.243745876054 -0.0259064859794 -0.0534088909011 -0.0315611195993 0.0256448427552 Species4 1.05371722248 0.537178749104 -0.438075060322 0.223480553581 -0.323948461806 0.124644870822 -0.119275907223 0.0416254660329 -0.0381955235096 Species5 0.998558655 0.573960582723 0.679918103399 -0.389963380717 0.299077945999 0.328451006171 0.21215881857 -0.0829871883001 -0.0439653996462 Species6 0.255245719879 -0.178168259149 -0.204127155429 0.433397565801 0.0707099230629 -0.18817306522 0.126908756045 0.0044937289123 -0.0122511718244 Species7 0.146555872394 -0.857362497037 -0.0152499051659 0.0527604990862 0.354475793915 -0.0416813697787 -0.199011239586 -0.00213723187073 -0.00782946141667 Species8 0.413705102117 -0.707948964322 0.21569736034 -0.690314241725 -0.148431001217 -0.334251868558 -0.00628707445028 -0.00364123416731 -0.0122722164511 Site 10 9 Site0 0.710587311248 -3.08166800613 0.219651379947 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.584771352278 -3.00669301091 -0.947448656768 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.762734278287 -3.15258603503 2.13924426714 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.11230735331 1.07150585141 -1.87527740873 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.979116769996 -0.0603144289026 -0.696277367656 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.04322560423 0.459426970165 -0.639802790578 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -0.954490118162 -0.0847021660539 0.132509124411 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.947268764751 -0.108370567311 0.526107182587 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.14808173207 0.490449274267 0.478353666755 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 1.03291557934 1.0350490304 2.74691777314 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 -0.169746767979 0.63069090084 0.760769036049 -0.994016563505 0.0609533148724 -0.0449369418179 0.184352565909 -0.974867543612 0.0309865007541 Site constraints 10 9 Site0 0.692138797603 -3.08053663489 -0.328747278055 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.664559513865 -3.06214571808 0.230249303805 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.636980230127 -3.04375480127 0.789245885666 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.10887578995 0.500396915484 -1.55606822404 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.970016224052 0.0654867737684 -1.1206070781 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.05371722248 0.537178749104 -0.438075060322 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -1.02517479153 0.102268607388 -0.00261391438256 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.998558655 0.573960582723 0.679918103399 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.080333359 0.139050441007 1.11537924934 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 0.943400087524 0.610742416342 1.79791126712 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error6000066400000000000000000000107161520735541300270310ustar00rootroot00000000000000Eigvals 9 0.366135830393 0.186887643052 0.0788466514249 0.082287840501 0.0351348475787 0.0233265839374 0.0099048981912 0.00122461669234 0.000417454724117 Proportion explained 0 Species 9 9 Species0 0.110350890177 0.282399990052 -0.203028976154 -0.00192462284409 -0.082232863384 0.0857314258364 -0.0122038907184 -0.0425198793666 0.00466719926338 Species1 0.141359038961 0.303495645402 0.395441211576 -0.14126625534 -0.0268859204718 0.143253061936 0.0430260301697 0.0476377655759 -0.00228172378295 Species2 -1.01552204222 0.0958317865043 -0.198262718034 -0.104801030067 0.130025239749 0.0244045261332 0.0464701211285 0.0269279200532 0.0350103177576 Species3 -1.03620650502 0.109624974112 0.220984718362 0.223640072997 -0.243745876054 -0.0259064859794 -0.0534088909011 -0.0315611195993 0.0256448427552 Species4 1.05371722248 0.537178749104 -0.438075060322 0.223480553581 -0.323948461806 0.124644870822 -0.119275907223 0.0416254660329 -0.0381955235096 Species5 0.998558655 0.573960582723 0.679918103399 -0.389963380717 0.299077945999 0.328451006171 0.21215881857 -0.0829871883001 -0.0439653996462 Species6 0.255245719879 -0.178168259149 -0.204127155429 0.433397565801 0.0707099230629 -0.18817306522 0.126908756045 0.0044937289123 -0.0122511718244 Species7 0.146555872394 -0.857362497037 -0.0152499051659 0.0527604990862 0.354475793915 -0.0416813697787 -0.199011239586 -0.00213723187073 -0.00782946141667 Species8 0.413705102117 -0.707948964322 0.21569736034 -0.690314241725 -0.148431001217 -0.334251868558 -0.00628707445028 -0.00364123416731 -0.0122722164511 Site 10 9 Site0 0.710587311248 -3.08166800613 0.219651379947 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.584771352278 -3.00669301091 -0.947448656768 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.762734278287 -3.15258603503 2.13924426714 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.11230735331 1.07150585141 -1.87527740873 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.979116769996 -0.0603144289026 -0.696277367656 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.04322560423 0.459426970165 -0.639802790578 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -0.954490118162 -0.0847021660539 0.132509124411 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.947268764751 -0.108370567311 0.526107182587 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.14808173207 0.490449274267 0.478353666755 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 1.03291557934 1.0350490304 2.74691777314 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 Biplot 3 3 -0.169746767979 0.63069090084 0.760769036049 -0.994016563505 0.0609533148724 -0.0449369418179 0.184352565909 -0.974867543612 0.0309865007541 Site0 0.692138797603 -3.08053663489 -0.328747278055 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.664559513865 -3.06214571808 0.230249303805 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.636980230127 -3.04375480127 0.789245885666 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.10887578995 0.500396915484 -1.55606822404 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.970016224052 0.0654867737684 -1.1206070781 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.05371722248 0.537178749104 -0.438075060322 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -1.02517479153 0.102268607388 -0.00261391438256 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.998558655 0.573960582723 0.679918103399 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.080333359 0.139050441007 1.11537924934 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 0.943400087524 0.610742416342 1.79791126712 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error7000066400000000000000000000001011520735541300270150ustar00rootroot00000000000000Eigvals 2 0.0961330159181 0.0409418140138 Proportion explained 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error8000066400000000000000000000030421520735541300270250ustar00rootroot00000000000000Eigvals 9 0.512367260461 0.300719094427 0.267912066004 0.208988681078 0.19169895326 0.16054234528 0.15017695712 0.122457748167 0.0 Proportion explained 9 0.267573832777 0.139911863774 0.109140272454 0.100111048503 0.0838401161912 0.0784269939011 0.0639511763509 0.0 Species 0 0 Site 9 9 PC.636 -0.258465461183 0.173999546883 0.0382875792552 -0.19447750562 0.0831176020844 0.262430333201 -0.0231636392235 -0.0184794039581 0.0 PC.635 -0.271001135391 -0.0185951319063 -0.0864841926349 0.118064245315 -0.198808358437 -0.0211723599535 -0.191024027565 0.155646592377 0.0 PC.356 0.235077898175 0.0962519254489 -0.345792726714 -0.00320862577619 -0.0963777675519 0.0457025386953 0.185472813286 0.0404093971793 0.0 PC.481 0.0261407664325 -0.0111459676533 0.147660603015 0.29087660853 0.203945472801 0.0619712384758 0.101641328709 0.105690998719 0.0 PC.354 0.285007552283 -0.0192549888483 0.0623263375385 0.138126799852 -0.104798602423 0.0951720730628 -0.129636097542 -0.220687170372 0.0 PC.593 0.204636326241 -0.139361150932 0.291513819623 -0.181566786821 -0.159580132715 -0.0246412130162 0.0866252404441 0.0996221476871 0.0 PC.355 0.233482403212 0.225257974068 -0.0188623096268 -0.107729981831 0.177108999572 -0.192905835151 -0.149819471408 0.0383549037465 0.0 PC.607 -0.0949631911323 -0.420974802495 -0.154869454869 -0.0898427509281 0.152618194488 -0.0334232691501 -0.0251224777303 -0.0508988536409 0.0 PC.634 -0.359915158638 0.113822595435 0.0662203444138 0.0297579972788 -0.0572254078183 -0.193133506163 0.145026331031 -0.149658611738 0.0 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_error9000066400000000000000000000004601520735541300270270ustar00rootroot00000000000000Eigvals 2 0.0961330159181 0.0409418140138 Proportion explained 0 Species 3 2 Species1 0.408869425742 Species2 -0.1153860437 Species3 -0.309967102571 Site 3 2 Site1 -0.848956053187 0.882764759014 Site2 -0.220458650578 -1.34482000302 Site3 1.66697179591 0.470324389808 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_example2_scores000066400000000000000000000065041520735541300307050ustar00rootroot00000000000000Eigvals 7 25.8979540892 14.9825779819 8.93784077262 6.13995623072 1.68070536498 0.57735026919 0.275983624351 Proportion explained 0 Species 6 7 Species0 1.38198713901 -1.71496426179 0.632272455288 0.00712898231575 0.120512431133 -0.0723104306179 -0.00815886062344 Species1 0.919178380672 -1.25430767906 -1.1787426896 -0.00712898231576 -0.120512431133 -0.0723104306179 0.00815886062344 Species2 3.39897234869 0.446168315515 0.406691610423 0.749336668014 0.0793892812781 7.37971401683e-17 0.0329418170936 Species3 2.52353261895 0.446932822723 -0.413412046583 -0.639449029945 -0.0640330006084 3.40602185392e-17 0.0335491330226 Species4 -0.53155341411 -1.34263985744 0.464155649196 -0.412041388665 0.198336195195 7.37971401683e-17 0.00604836743485 Species5 -0.288618167117 -0.571491852197 -0.406527290424 0.206020694333 -0.0991680975973 -1.13534061797e-17 -0.00302418371743 Site 10 7 Site0 -1.48848983495 2.12675623514 0.727805340002 -0.227234564008 -3.8413042049 -2.30487725273 0.260061682644 Site1 -1.5541678384 2.37027298265 0.475523558326 1.58712629997e-16 1.39853499536e-15 4.60975450547 -1.41948353841e-14 Site2 -1.51048450796 2.19216727329 0.00519576944216 0.227234564008 3.8413042049 -2.30487725273 -0.260061682644 Site3 -0.872786591764 -2.6271708553 2.68871897067 -1.97005774092 0.948287641474 -2.0356145959e-14 0.0289185344306 Site4 2.97228673755 0.322310666722 2.50294580667 3.50264153009 0.489477682536 -1.25529566747e-14 2.11938273809 Site5 -0.879968888341 -2.19620098193 0.710888524695 -0.656685913639 0.316095880491 -4.47835211098e-15 0.00963951147681 Site6 2.64194948913 0.390104638861 -0.086230363198 -0.211189359785 -0.298609965083 -3.88762243221e-15 -4.5952222736 Site7 -0.887151184918 -1.76523110855 -1.26694192128 0.656685913639 -0.316095880491 1.21458337555e-14 -0.00963951147698 Site8 2.47314610115 0.521252384288 -2.51313331808 -3.29145217031 -0.190867717454 1.65563320466e-14 2.4758395355 Site9 -0.894333481495 -1.33426123517 -3.24477236725 1.97005774092 -0.948287641474 3.0262803659e-14 -0.0289185344308 Biplot 4 3 0.422650019179 -0.559142585857 -0.713250678211 0.988495963777 0.150787422017 -0.0117848614073 -0.556516618887 0.817599992718 0.147714267459 -0.404079676685 -0.9058434809 -0.127150316558 Site constraints 10 7 Site0 -1.48131076339 2.07063239013 1.42061063192 -0.227234564008 -3.8413042049 -2.30487725273 0.260061682644 Site1 -1.51771406044 2.22973216369 0.402841555923 1.58712629997e-16 1.39853499536e-15 4.60975450547 -1.41948353841e-14 Site2 -1.55411735749 2.38883193726 -0.61492752007 0.227234564008 3.8413042049 -2.30487725273 -0.260061682644 Site3 -0.774350145471 -2.45801536594 2.77528052969 -1.97005774092 0.948287641474 -2.0356145959e-14 0.0289185344306 Site4 2.76860070338 0.0930230161545 2.00339886045 3.50264153009 0.489477682536 -1.25529566747e-14 2.11938273809 Site5 -0.847156739577 -2.13981581881 0.739742377702 -0.656685913639 0.316095880491 -4.47835211098e-15 0.00963951147681 Site6 2.69579410928 0.41122256329 -0.0321392915344 -0.211189359785 -0.298609965083 -3.88762243221e-15 -4.5952222736 Site7 -0.919963333683 -1.82161627167 -1.29579577429 0.656685913639 -0.316095880491 1.21458337555e-14 -0.00963951147698 Site8 2.62298751517 0.729422110426 -2.06767744352 -3.29145217031 -0.190867717454 1.65563320466e-14 2.4758395355 Site9 -0.992769927788 -1.50341672453 -3.33133392627 1.97005774092 -0.948287641474 3.0262803659e-14 -0.0289185344308 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_example3_scores000066400000000000000000000107431520735541300307060ustar00rootroot00000000000000Eigvals 9 0.366135830393 0.186887643052 0.0788466514249 0.082287840501 0.0351348475787 0.0233265839374 0.0099048981912 0.00122461669234 0.000417454724117 Proportion explained 0 Species 9 9 Species0 0.110350890177 0.282399990052 -0.203028976154 -0.00192462284409 -0.082232863384 0.0857314258364 -0.0122038907184 -0.0425198793666 0.00466719926338 Species1 0.141359038961 0.303495645402 0.395441211576 -0.14126625534 -0.0268859204718 0.143253061936 0.0430260301697 0.0476377655759 -0.00228172378295 Species2 -1.01552204222 0.0958317865043 -0.198262718034 -0.104801030067 0.130025239749 0.0244045261332 0.0464701211285 0.0269279200532 0.0350103177576 Species3 -1.03620650502 0.109624974112 0.220984718362 0.223640072997 -0.243745876054 -0.0259064859794 -0.0534088909011 -0.0315611195993 0.0256448427552 Species4 1.05371722248 0.537178749104 -0.438075060322 0.223480553581 -0.323948461806 0.124644870822 -0.119275907223 0.0416254660329 -0.0381955235096 Species5 0.998558655 0.573960582723 0.679918103399 -0.389963380717 0.299077945999 0.328451006171 0.21215881857 -0.0829871883001 -0.0439653996462 Species6 0.255245719879 -0.178168259149 -0.204127155429 0.433397565801 0.0707099230629 -0.18817306522 0.126908756045 0.0044937289123 -0.0122511718244 Species7 0.146555872394 -0.857362497037 -0.0152499051659 0.0527604990862 0.354475793915 -0.0416813697787 -0.199011239586 -0.00213723187073 -0.00782946141667 Species8 0.413705102117 -0.707948964322 0.21569736034 -0.690314241725 -0.148431001217 -0.334251868558 -0.00628707445028 -0.00364123416731 -0.0122722164511 Site 10 9 Site0 0.710587311248 -3.08166800613 0.219651379947 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.584771352278 -3.00669301091 -0.947448656768 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.762734278287 -3.15258603503 2.13924426714 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.11230735331 1.07150585141 -1.87527740873 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.979116769996 -0.0603144289026 -0.696277367656 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.04322560423 0.459426970165 -0.639802790578 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -0.954490118162 -0.0847021660539 0.132509124411 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.947268764751 -0.108370567311 0.526107182587 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.14808173207 0.490449274267 0.478353666755 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 1.03291557934 1.0350490304 2.74691777314 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 Biplot 3 3 -0.169746767979 0.63069090084 0.760769036049 -0.994016563505 0.0609533148724 -0.0449369418179 0.184352565909 -0.974867543612 0.0309865007541 Site constraints 10 9 Site0 0.692138797603 -3.08053663489 -0.328747278055 -1.24528801163 -1.07293546227 -0.506241907472 0.244126652455 -3.63164833508 1.16311896657 Site1 0.664559513865 -3.06214571808 0.230249303805 2.69965142856 2.13682885838 0.813520011254 0.471530333182 0.908423015086 -1.34724387844 Site2 0.636980230127 -3.04375480127 0.789245885666 -3.1162748358 -2.30660936925 -0.698929858809 -1.39062619586 4.84117591747 0.562102984837 Site3 1.10887578995 0.500396915484 -1.55606822404 0.666370241998 -1.10153224699 1.43517552491 -1.10619960297 0.0137029328454 -0.0371803939101 Site4 -0.970016224052 0.0654867737684 -1.1206070781 -0.612646703308 0.983006619615 0.315662442163 0.574110232297 0.328630035672 0.868027697443 Site5 1.05371722248 0.537178749104 -0.438075060322 0.287156643872 -0.573935423877 -1.44980634943 1.70166994063 0.306164261447 -0.442115969758 Site6 -1.02517479153 0.102268607388 -0.00261391438256 -0.42143341064 -0.111552348931 -0.394242454835 -0.673963982894 -0.379018566362 -1.7472502885 Site7 0.998558655 0.573960582723 0.679918103399 -0.00565282365567 1.26272400228 -1.06565692165 -1.46326596729 -0.154459216567 0.778139732463 Site8 -1.080333359 0.139050441007 1.11537924934 1.17015870919 -1.00599224074 0.0735071441404 0.0860462673715 0.0417647558417 0.935819560428 Site9 0.943400087524 0.610742416342 1.79791126712 -1.28083971649 0.363002636972 1.98647950015 1.05356145232 -0.24813142226 -0.463165215106 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_exp_Ordination_CCA_site000066400000000000000000000043651520735541300322710ustar00rootroot000000000000007.105873112480000087e-01 -3.081668006130000137e+00 2.196513799469999861e-01 -1.245288011630000025e+00 -1.072935462270000029e+00 -5.062419074720000411e-01 2.441266524550000094e-01 -3.631648335079999956e+00 1.163118966569999913e+00 5.847713522780000339e-01 -3.006693010909999852e+00 -9.474486567680000526e-01 2.699651428560000177e+00 2.136828858379999918e+00 8.135200112539999751e-01 4.715303331819999944e-01 9.084230150859999853e-01 -1.347243878440000042e+00 7.627342782870000226e-01 -3.152586035030000122e+00 2.139244267140000044e+00 -3.116274835800000087e+00 -2.306609369249999819e+00 -6.989298588090000486e-01 -1.390626195859999914e+00 4.841175917470000201e+00 5.621029848370000526e-01 1.112307353310000080e+00 1.071505851409999988e+00 -1.875277408729999928e+00 6.663702419979999902e-01 -1.101532246989999964e+00 1.435175524910000000e+00 -1.106199602970000084e+00 1.370293284539999927e-02 -3.718039391010000139e-02 -9.791167699959999471e-01 -6.031442890259999801e-02 -6.962773676560000125e-01 -6.126467033079999736e-01 9.830066196150000213e-01 3.156624421629999899e-01 5.741102322969999783e-01 3.286300356719999982e-01 8.680276974430000125e-01 1.043225604230000103e+00 4.594269701650000037e-01 -6.398027905780000468e-01 2.871566438720000169e-01 -5.739354238770000283e-01 -1.449806349429999974e+00 1.701669940629999989e+00 3.061642614469999857e-01 -4.421159697579999937e-01 -9.544901181620000230e-01 -8.470216605390000486e-02 1.325091244109999900e-01 -4.214334106400000057e-01 -1.115523489309999949e-01 -3.942424548349999780e-01 -6.739639828939999466e-01 -3.790185663619999867e-01 -1.747250288500000082e+00 9.472687647509999698e-01 -1.083705673110000045e-01 5.261071825869999552e-01 -5.652823655669999593e-03 1.262724002279999924e+00 -1.065656921650000033e+00 -1.463265967289999914e+00 -1.544592165670000128e-01 7.781397324629999446e-01 -1.148081732070000083e+00 4.904492742670000238e-01 4.783536667550000177e-01 1.170158709190000090e+00 -1.005992240739999932e+00 7.350714414039999367e-02 8.604626737149999316e-02 4.176475584170000199e-02 9.358195604279999635e-01 1.032915579340000001e+00 1.035049030399999959e+00 2.746917773139999852e+00 -1.280839716490000058e+00 3.630026369720000257e-01 1.986479500149999966e+00 1.053561452320000091e+00 -2.481314222600000119e-01 -4.631652151060000056e-01 ordination_exp_Ordination_CCA_site_constraints000066400000000000000000000043631520735541300346370ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data6.921387976030000111e-01 -3.080536634890000069e+00 -3.287472780549999807e-01 -1.245288011630000025e+00 -1.072935462270000029e+00 -5.062419074720000411e-01 2.441266524550000094e-01 -3.631648335079999956e+00 1.163118966569999913e+00 6.645595138650000067e-01 -3.062145718080000023e+00 2.302493038049999996e-01 2.699651428560000177e+00 2.136828858379999918e+00 8.135200112539999751e-01 4.715303331819999944e-01 9.084230150859999853e-01 -1.347243878440000042e+00 6.369802301270000022e-01 -3.043754801269999977e+00 7.892458856659999578e-01 -3.116274835800000087e+00 -2.306609369249999819e+00 -6.989298588090000486e-01 -1.390626195859999914e+00 4.841175917470000201e+00 5.621029848370000526e-01 1.108875789949999913e+00 5.003969154840000044e-01 -1.556068224039999892e+00 6.663702419979999902e-01 -1.101532246989999964e+00 1.435175524910000000e+00 -1.106199602970000084e+00 1.370293284539999927e-02 -3.718039391010000139e-02 -9.700162240520000534e-01 6.548677376839999453e-02 -1.120607078099999931e+00 -6.126467033079999736e-01 9.830066196150000213e-01 3.156624421629999899e-01 5.741102322969999783e-01 3.286300356719999982e-01 8.680276974430000125e-01 1.053717222479999993e+00 5.371787491039999862e-01 -4.380750603219999983e-01 2.871566438720000169e-01 -5.739354238770000283e-01 -1.449806349429999974e+00 1.701669940629999989e+00 3.061642614469999857e-01 -4.421159697579999937e-01 -1.025174791530000018e+00 1.022686073880000046e-01 -2.613914382559999906e-03 -4.214334106400000057e-01 -1.115523489309999949e-01 -3.942424548349999780e-01 -6.739639828939999466e-01 -3.790185663619999867e-01 -1.747250288500000082e+00 9.985586549999999617e-01 5.739605827229999901e-01 6.799181033990000511e-01 -5.652823655669999593e-03 1.262724002279999924e+00 -1.065656921650000033e+00 -1.463265967289999914e+00 -1.544592165670000128e-01 7.781397324629999446e-01 -1.080333358999999938e+00 1.390504410070000085e-01 1.115379249340000101e+00 1.170158709190000090e+00 -1.005992240739999932e+00 7.350714414039999367e-02 8.604626737149999316e-02 4.176475584170000199e-02 9.358195604279999635e-01 9.434000875239999528e-01 6.107424163419999941e-01 1.797911267119999934e+00 -1.280839716490000058e+00 3.630026369720000257e-01 1.986479500149999966e+00 1.053561452320000091e+00 -2.481314222600000119e-01 -4.631652151060000056e-01 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_exp_Ordination_CCA_species000066400000000000000000000040211520735541300327450ustar00rootroot000000000000001.103508901770000050e-01 2.823999900520000050e-01 -2.030289761540000071e-01 -1.924622844089999901e-03 -8.223286338400000173e-02 8.573142583640000480e-02 -1.220389071839999943e-02 -4.251987936659999689e-02 4.667199263379999581e-03 1.413590389609999942e-01 3.034956454020000249e-01 3.954412115759999846e-01 -1.412662553400000076e-01 -2.688592047179999903e-02 1.432530619359999868e-01 4.302603016969999694e-02 4.763776557589999988e-02 -2.281723782949999797e-03 -1.015522042219999976e+00 9.583178650430000667e-02 -1.982627180340000017e-01 -1.048010300670000061e-01 1.300252397489999878e-01 2.440452613319999894e-02 4.647012112849999849e-02 2.692792005320000098e-02 3.501031775760000270e-02 -1.036206505020000002e+00 1.096249741120000065e-01 2.209847183620000100e-01 2.236400729970000056e-01 -2.437458760539999991e-01 -2.590648597939999853e-02 -5.340889090110000070e-02 -3.156111959929999711e-02 2.564484275520000078e-02 1.053717222479999993e+00 5.371787491039999862e-01 -4.380750603219999983e-01 2.234805535809999966e-01 -3.239484618060000098e-01 1.246448708220000007e-01 -1.192759072229999939e-01 4.162546603290000202e-02 -3.819552350960000314e-02 9.985586549999999617e-01 5.739605827229999901e-01 6.799181033990000511e-01 -3.899633807169999855e-01 2.990779459990000055e-01 3.284510061709999817e-01 2.121588185699999907e-01 -8.298718830010000380e-02 -4.396539964619999852e-02 2.552457198790000215e-01 -1.781682591490000023e-01 -2.041271554290000068e-01 4.333975658009999732e-01 7.070992306289999862e-02 -1.881730652199999909e-01 1.269087560449999874e-01 4.493728912300000086e-03 -1.225117182439999959e-02 1.465558723940000030e-01 -8.573624970369999598e-01 -1.524990516589999970e-02 5.276049908620000090e-02 3.544757939150000037e-01 -4.168136977870000315e-02 -1.990112395860000050e-01 -2.137231870730000108e-03 -7.829461416669999951e-03 4.137051021170000120e-01 -7.079489643220000517e-01 2.156973603400000050e-01 -6.903142417249999996e-01 -1.484310012170000082e-01 -3.342518685579999871e-01 -6.287074450280000053e-03 -3.641234167310000193e-03 -1.227221645110000009e-02 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_exp_Ordination_PCoA_site000066400000000000000000000040161520735541300324560ustar00rootroot00000000000000-2.584654611830000115e-01 1.739995468830000114e-01 3.828757925520000216e-02 -1.944775056199999907e-01 8.311760208439999964e-02 2.624303332010000100e-01 -2.316363922349999951e-02 -1.847940395810000053e-02 0.000000000000000000e+00 -2.710011353910000143e-01 -1.859513190630000118e-02 -8.648419263489999509e-02 1.180642453149999965e-01 -1.988083584370000101e-01 -2.117235995349999941e-02 -1.910240275650000041e-01 1.556465923769999871e-01 0.000000000000000000e+00 2.350778981749999941e-01 9.625192544890000257e-02 -3.457927267140000205e-01 -3.208625776189999966e-03 -9.637776755190000100e-02 4.570253869529999902e-02 1.854728132859999878e-01 4.040939717929999814e-02 0.000000000000000000e+00 2.614076643250000040e-02 -1.114596765330000058e-02 1.476606030150000026e-01 2.908766085300000248e-01 2.039454728010000051e-01 6.197123847580000150e-02 1.016413287090000006e-01 1.056909987190000066e-01 0.000000000000000000e+00 2.850075522830000097e-01 -1.925498884830000035e-02 6.232633753849999708e-02 1.381267998519999929e-01 -1.047986024230000007e-01 9.517207306279999723e-02 -1.296360975420000061e-01 -2.206871703720000022e-01 0.000000000000000000e+00 2.046363262410000050e-01 -1.393611509319999942e-01 2.915138196229999923e-01 -1.815667868209999980e-01 -1.595801327149999893e-01 -2.464121301619999829e-02 8.662524044409999902e-02 9.962214768709999613e-02 0.000000000000000000e+00 2.334824032120000059e-01 2.252579740679999942e-01 -1.886230962680000151e-02 -1.077299818309999935e-01 1.771089995719999921e-01 -1.929058351509999880e-01 -1.498194714080000045e-01 3.835490374650000339e-02 0.000000000000000000e+00 -9.496319113230000664e-02 -4.209748024950000223e-01 -1.548694548690000006e-01 -8.984275092809999863e-02 1.526181944879999863e-01 -3.342326915010000038e-02 -2.512247773030000172e-02 -5.089885364090000058e-02 0.000000000000000000e+00 -3.599151586379999990e-01 1.138225954350000069e-01 6.622034441379999470e-02 2.975799727879999829e-02 -5.722540781830000312e-02 -1.931335061630000127e-01 1.450263310309999887e-01 -1.496586117379999914e-01 0.000000000000000000e+00 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_exp_Ordination_RDA_site000066400000000000000000000033721520735541300323060ustar00rootroot00000000000000-1.488489834949999979e+00 2.126756235139999784e+00 7.278053400020000341e-01 -2.272345640079999896e-01 -3.841304204900000130e+00 -2.304877252729999881e+00 2.600616826439999807e-01 -1.554167838399999946e+00 2.370272982649999971e+00 4.755235583260000176e-01 1.587126299970000006e-16 1.398534995359999983e-15 4.609754505469999764e+00 -1.419483538409999981e-14 -1.510484507960000000e+00 2.192167273289999940e+00 5.195769442159999842e-03 2.272345640079999896e-01 3.841304204900000130e+00 -2.304877252729999881e+00 -2.600616826439999807e-01 -8.727865917639999749e-01 -2.627170855300000163e+00 2.688718970670000097e+00 -1.970057740919999967e+00 9.482876414740000204e-01 -2.035614595899999968e-14 2.891853443059999931e-02 2.972286737550000169e+00 3.223106667219999832e-01 2.502945806670000106e+00 3.502641530090000010e+00 4.894776825359999917e-01 -1.255295667470000031e-14 2.119382738090000107e+00 -8.799688883409999551e-01 -2.196200981930000129e+00 7.108885246949999681e-01 -6.566859136389999740e-01 3.160958804910000142e-01 -4.478352110979999834e-15 9.639511476809999382e-03 2.641949489129999940e+00 3.901046388609999971e-01 -8.623036319799999572e-02 -2.111893597850000026e-01 -2.986099650829999730e-01 -3.887622432210000342e-15 -4.595222273600000129e+00 -8.871511849180000464e-01 -1.765231108550000094e+00 -1.266941921279999939e+00 6.566859136389999740e-01 -3.160958804910000142e-01 1.214583375549999947e-14 -9.639511476980000548e-03 2.473146101150000220e+00 5.212523842880000258e-01 -2.513133318079999956e+00 -3.291452170309999925e+00 -1.908677174539999966e-01 1.655633204660000023e-14 2.475839535500000022e+00 -8.943334814950000267e-01 -1.334261235170000059e+00 -3.244772367249999956e+00 1.970057740919999967e+00 -9.482876414740000204e-01 3.026280365900000082e-14 -2.891853443079999905e-02 ordination_exp_Ordination_RDA_site_constraints000066400000000000000000000033731520735541300346570ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data-1.481310763390000007e+00 2.070632390130000111e+00 1.420610631920000033e+00 -2.272345640079999896e-01 -3.841304204900000130e+00 -2.304877252729999881e+00 2.600616826439999807e-01 -1.517714060439999901e+00 2.229732163690000046e+00 4.028415559230000276e-01 1.587126299970000006e-16 1.398534995359999983e-15 4.609754505469999764e+00 -1.419483538409999981e-14 -1.554117357490000018e+00 2.388831937259999982e+00 -6.149275200699999555e-01 2.272345640079999896e-01 3.841304204900000130e+00 -2.304877252729999881e+00 -2.600616826439999807e-01 -7.743501454710000065e-01 -2.458015365940000141e+00 2.775280529689999831e+00 -1.970057740919999967e+00 9.482876414740000204e-01 -2.035614595899999968e-14 2.891853443059999931e-02 2.768600703380000194e+00 9.302301615449999617e-02 2.003398860449999930e+00 3.502641530090000010e+00 4.894776825359999917e-01 -1.255295667470000031e-14 2.119382738090000107e+00 -8.471567395769999953e-01 -2.139815818809999826e+00 7.397423777020000202e-01 -6.566859136389999740e-01 3.160958804910000142e-01 -4.478352110979999834e-15 9.639511476809999382e-03 2.695794109279999962e+00 4.112225632900000094e-01 -3.213929153439999686e-02 -2.111893597850000026e-01 -2.986099650829999730e-01 -3.887622432210000342e-15 -4.595222273600000129e+00 -9.199633336829999841e-01 -1.821616271669999954e+00 -1.295795774289999924e+00 6.566859136389999740e-01 -3.160958804910000142e-01 1.214583375549999947e-14 -9.639511476980000548e-03 2.622987515170000172e+00 7.294221104260000255e-01 -2.067677443520000047e+00 -3.291452170309999925e+00 -1.908677174539999966e-01 1.655633204660000023e-14 2.475839535500000022e+00 -9.927699277879999951e-01 -1.503416724530000081e+00 -3.331333926270000134e+00 1.970057740919999967e+00 -9.482876414740000204e-01 3.026280365900000082e-14 -2.891853443079999905e-02 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/ordination_exp_Ordination_RDA_species000066400000000000000000000020561520735541300327730ustar00rootroot000000000000001.381987139010000032e+00 -1.714964261790000055e+00 6.322724552880000237e-01 7.128982315749999785e-03 1.205124311330000031e-01 -7.231043061790000392e-02 -8.158860623439999696e-03 9.191783806719999728e-01 -1.254307679060000069e+00 -1.178742689599999949e+00 -7.128982315759999598e-03 -1.205124311330000031e-01 -7.231043061790000392e-02 8.158860623439999696e-03 3.398972348690000089e+00 4.461683155150000246e-01 4.066916104230000051e-01 7.493366680140000069e-01 7.938928127809999347e-02 7.379714016829999409e-17 3.294181709360000099e-02 2.523532618950000028e+00 4.469328227230000006e-01 -4.134120465830000146e-01 -6.394490299449999693e-01 -6.403300060840000363e-02 3.406021853920000005e-17 3.354913302260000008e-02 -5.315534141100000110e-01 -1.342639857440000029e+00 4.641556491959999975e-01 -4.120413886650000079e-01 1.983361951950000091e-01 7.379714016829999409e-17 6.048367434850000432e-03 -2.886181671170000018e-01 -5.714918521970000498e-01 -4.065272904239999874e-01 2.060206943329999929e-01 -9.916809759729999785e-02 -1.135340617969999987e-17 -3.024183717430000123e-03 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/pdb_hits.txt000066400000000000000000000011201520735541300257630ustar00rootroot00000000000000MLYELVAYGIAQGTAEKVVSLINAGLTVGSIISILGGVTVGLSGVFTAVKAAIAKQGIKKAIQL MDKKNILPHQGKPVLRTTNGKLPSHLAELSEEALGGNGVDASACMPCYPSYDGVDASVCMPCYPSYDGVDASVCMPCYPSYDDAE MSTKDFNLDLVSVSKTDSGASTRITSISLCTPGCKTGVLMGCNLKTATCNCSVHVSK CLGVGSCNDFAGCGYAIVCFW MNNEDFNLDLIKISKENNSGASPRITSKSLCTPGCKTGILMTCPLKTATCGCHFG GLPWGCPSDIPGWNTPWAC MQKFQKLNEQEMKQLMGGYSSKDCLKDIGKGIGAGTVAGAAGGGLAAGLGAIPGAFVGAHFGVIGGSAACIGGLLGN MNKKNILPNPGKPVIRGISGKLPSYLAELSEEALGDAGADASFICSVDASFICSVDASFICSVDASFICSVDGDA MNKKNILPQLGQPVIRLTAGQLSSQLAELSEEALGGVDASTFPVPTVCSYDGVDASTSIAPFCSYDD MLNKENQENYYSNKLELVGPSFEELSLEEMEAIQGSGDVQAETTPACFTIGLGVGALFSAKFCscikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_good_simple_strict_square.dist000066400000000000000000000002021520735541300336310ustar00rootroot000000000000004 catcatcatc0.0 0.2 0.3 0.6 dog 0.2 0.0 0.6 0.7 lizard 0.3 0.6 0.0 0.8 superlizar0.6 0.7 0.8 0.0 phylip_dm_good_simple_strict_square_reader.dist000066400000000000000000000002011520735541300350730ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data4 cat 0.0 0.2 0.3 0.6 dog 0.2 0.0 0.6 0.7 lizard 0.3 0.6 0.0 0.8 superlizar0.6 0.7 0.8 0.0phylip_dm_invalid_empty_line_after_header.dist000077500000000000000000000015631520735541300346630ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data 14 Mouse Bovine 1.7043 Lemur 2.0235 1.1901 Tarsier 2.1378 1.3287 1.2905 Squir Monk 1.5232 1.2423 1.3199 1.7878 Jpn Macaq 1.8261 1.2508 1.3887 1.3137 1.0642 Rhesus Mac 1.9182 1.2536 1.4658 1.3788 1.1124 0.1022 Crab-E.Mac 2.0039 1.3066 1.4826 1.3826 0.9832 0.2061 0.2681 BarbMacaq 1.9431 1.2827 1.4502 1.4543 1.0629 0.3895 0.3930 0.3665 Gibbon 1.9663 1.3296 1.8708 1.6683 0.9228 0.8035 0.7109 0.8132 0.7858 Orang 2.0593 1.2005 1.5356 1.6606 1.0681 0.7239 0.7290 0.7894 0.7140 0.7095 Gorilla 1.6664 1.3460 1.4577 1.5935 0.9127 0.7278 0.7412 0.8763 0.7966 0.5959 0.4604 Chimp 1.7320 1.3757 1.7803 1.7119 1.0635 0.7899 0.8742 0.8868 0.8288 0.6213 0.5065 0.3502 Human 1.7101 1.3956 1.6661 1.7599 1.0557 0.6933 0.7118 0.7589 0.8542 0.5612 0.4700 0.3097 0.2712phylip_dm_invalid_empty_line_before_header.dist000077500000000000000000000015631520735541300350240ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data 14 Mouse Bovine 1.7043 Lemur 2.0235 1.1901 Tarsier 2.1378 1.3287 1.2905 Squir Monk 1.5232 1.2423 1.3199 1.7878 Jpn Macaq 1.8261 1.2508 1.3887 1.3137 1.0642 Rhesus Mac 1.9182 1.2536 1.4658 1.3788 1.1124 0.1022 Crab-E.Mac 2.0039 1.3066 1.4826 1.3826 0.9832 0.2061 0.2681 BarbMacaq 1.9431 1.2827 1.4502 1.4543 1.0629 0.3895 0.3930 0.3665 Gibbon 1.9663 1.3296 1.8708 1.6683 0.9228 0.8035 0.7109 0.8132 0.7858 Orang 2.0593 1.2005 1.5356 1.6606 1.0681 0.7239 0.7290 0.7894 0.7140 0.7095 Gorilla 1.6664 1.3460 1.4577 1.5935 0.9127 0.7278 0.7412 0.8763 0.7966 0.5959 0.4604 Chimp 1.7320 1.3757 1.7803 1.7119 1.0635 0.7899 0.8742 0.8868 0.8288 0.6213 0.5065 0.3502 Human 1.7101 1.3956 1.6661 1.7599 1.0557 0.6933 0.7118 0.7589 0.8542 0.5612 0.4700 0.3097 0.2712scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_invalid_header_too_long.dist000077500000000000000000000015641520735541300332350ustar00rootroot00000000000000 14 2 Mouse Bovine 1.7043 Lemur 2.0235 1.1901 Tarsier 2.1378 1.3287 1.2905 Squir Monk 1.5232 1.2423 1.3199 1.7878 Jpn Macaq 1.8261 1.2508 1.3887 1.3137 1.0642 Rhesus Mac 1.9182 1.2536 1.4658 1.3788 1.1124 0.1022 Crab-E.Mac 2.0039 1.3066 1.4826 1.3826 0.9832 0.2061 0.2681 BarbMacaq 1.9431 1.2827 1.4502 1.4543 1.0629 0.3895 0.3930 0.3665 Gibbon 1.9663 1.3296 1.8708 1.6683 0.9228 0.8035 0.7109 0.8132 0.7858 Orang 2.0593 1.2005 1.5356 1.6606 1.0681 0.7239 0.7290 0.7894 0.7140 0.7095 Gorilla 1.6664 1.3460 1.4577 1.5935 0.9127 0.7278 0.7412 0.8763 0.7966 0.5959 0.4604 Chimp 1.7320 1.3757 1.7803 1.7119 1.0635 0.7899 0.8742 0.8868 0.8288 0.6213 0.5065 0.3502 Human 1.7101 1.3956 1.6661 1.7599 1.0557 0.6933 0.7118 0.7589 0.8542 0.5612 0.4700 0.3097 0.2712scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_invalid_no_dists.dist000077500000000000000000000000061520735541300317150ustar00rootroot00000000000000 14 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_invalid_no_header.dist000077500000000000000000000015611520735541300320260ustar00rootroot00000000000000Mouse Bovine 1.7043 Lemur 2.0235 1.1901 Tarsier 2.1378 1.3287 1.2905 Squir Monk 1.5232 1.2423 1.3199 1.7878 Jpn Macaq 1.8261 1.2508 1.3887 1.3137 1.0642 Rhesus Mac 1.9182 1.2536 1.4658 1.3788 1.1124 0.1022 Crab-E.Mac 2.0039 1.3066 1.4826 1.3826 0.9832 0.2061 0.2681 BarbMacaq 1.9431 1.2827 1.4502 1.4543 1.0629 0.3895 0.3930 0.3665 Gibbon 1.9663 1.3296 1.8708 1.6683 0.9228 0.8035 0.7109 0.8132 0.7858 Orang 2.0593 1.2005 1.5356 1.6606 1.0681 0.7239 0.7290 0.7894 0.7140 0.7095 Gorilla 1.6664 1.3460 1.4577 1.5935 0.9127 0.7278 0.7412 0.8763 0.7966 0.5959 0.4604 Chimp 1.7320 1.3757 1.7803 1.7119 1.0635 0.7899 0.8742 0.8868 0.8288 0.6213 0.5065 0.3502 Human 1.7101 1.3956 1.6661 1.7599 1.0557 0.6933 0.7118 0.7589 0.8542 0.5612 0.4700 0.3097 0.2712scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_invalid_too_few_columns_sq.dist000077500000000000000000000002651520735541300340070ustar00rootroot00000000000000 5 Alpha 0.000 1.000 2.000 3.000 Beta 1.000 0.000 2.000 3.000 Gamma 2.000 2.000 0.000 3.000 Delta 3.000 3.000 3.000 0.000 Epsilon 3.000 3.000 3.000 1.000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_invalid_too_few_rows.dist000066400000000000000000000002531520735541300326100ustar00rootroot00000000000000 5 Alpha 0.000 1.000 2.000 3.000 3.000 Beta 1.000 0.000 2.000 3.000 3.000 Gamma 2.000 2.000 0.000 3.000 3.000 Delta 3.000 3.000 3.000 0.000 1.000 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_invalid_too_many_columns.dist000066400000000000000000000003621520735541300334620ustar00rootroot00000000000000 5 Alpha 0.000 1.000 2.000 3.000 3.000 6.000 Beta 1.000 0.000 2.000 3.000 3.000 1.000 Gamma 2.000 2.000 0.000 3.000 3.000 6.000 Delta 3.000 3.000 3.000 0.000 1.000 3.000 Epsilon 3.000 3.000 3.000 1.000 0.000 5.000 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_invalid_too_many_rows.dist000066400000000000000000000003711520735541300327740ustar00rootroot00000000000000 5 Alpha 0.000 1.000 2.000 3.000 3.000 Beta 1.000 0.000 2.000 3.000 3.000 Gamma 2.000 2.000 0.000 3.000 3.000 Delta 3.000 3.000 3.000 0.000 1.000 Epsilon 3.000 3.000 3.000 1.000 0.000 Zeta 4.000 5.000 1.000 2.000 4.000phylip_dm_invalid_wrong_number_dists_lt.dist000077500000000000000000000016171520735541300344360ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data 14 Mouse 0.0000 Bovine 1.7043 0.0000 Lemur 2.0235 1.1901 0.0000 Tarsier 2.1378 1.3287 1.2905 0.0000 Squir Monk 1.5232 1.2423 1.3199 1.7878 Jpn Macaq 1.8261 1.2508 1.3887 1.3137 1.0642 Rhesus Mac 1.9182 1.2536 1.4658 1.3788 1.1124 0.1022 Crab-E.Mac 2.0039 1.3066 1.4826 1.3826 0.9832 0.2061 0.2681 BarbMacaq 1.9431 1.2827 1.4502 1.4543 1.0629 0.3895 0.3930 0.3665 Gibbon 1.9663 1.3296 1.8708 1.6683 0.9228 0.8035 0.7109 0.8132 0.7858 Orang 2.0593 1.2005 1.5356 1.6606 1.0681 0.7239 0.7290 0.7894 0.7140 0.7095 Gorilla 1.6664 1.3460 1.4577 1.5935 0.9127 0.7278 0.7412 0.8763 0.7966 0.5959 0.4604 Chimp 1.7320 1.3757 1.7803 1.7119 1.0635 0.7899 0.8742 0.8868 0.8288 0.6213 0.5065 0.3502 Human 1.7101 1.3956 1.6661 1.7599 1.0557 0.6933 0.7118 0.7589 0.8542 0.5612 0.4700 0.3097 0.2712scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_invalid_zero_header.dist000077500000000000000000000015571520735541300323760ustar00rootroot00000000000000 0 Mouse Bovine 1.7043 Lemur 2.0235 1.1901 Tarsier 2.1378 1.3287 1.2905 Squir Monk 1.5232 1.2423 1.3199 1.7878 Jpn Macaq 1.8261 1.2508 1.3887 1.3137 1.0642 Rhesus Mac 1.9182 1.2536 1.4658 1.3788 1.1124 0.1022 Crab-E.Mac 2.0039 1.3066 1.4826 1.3826 0.9832 0.2061 0.2681 BarbMacaq 1.9431 1.2827 1.4502 1.4543 1.0629 0.3895 0.3930 0.3665 Gibbon 1.9663 1.3296 1.8708 1.6683 0.9228 0.8035 0.7109 0.8132 0.7858 Orang 2.0593 1.2005 1.5356 1.6606 1.0681 0.7239 0.7290 0.7894 0.7140 0.7095 Gorilla 1.6664 1.3460 1.4577 1.5935 0.9127 0.7278 0.7412 0.8763 0.7966 0.5959 0.4604 Chimp 1.7320 1.3757 1.7803 1.7119 1.0635 0.7899 0.8742 0.8868 0.8288 0.6213 0.5065 0.3502 Human 1.7101 1.3956 1.6661 1.7599 1.0557 0.6933 0.7118 0.7589 0.8542 0.5612 0.4700 0.3097 0.2712scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_simple_lt.dist000066400000000000000000000000421520735541300303520ustar00rootroot000000000000004 0 1 1.0 2 2.0 4.0 3 3.0 5.0 6.0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_simple_sq.dist000066400000000000000000000001121520735541300303540ustar00rootroot000000000000004 0 0.0 1.0 2.0 3.0 1 1.0 0.0 4.0 5.0 2 2.0 4.0 0.0 6.0 3 3.0 5.0 6.0 0.0 phylip_dm_sq_invalid_empty_line_after_header.dist000077500000000000000000000003251520735541300353610ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data 5 Alpha 0.000 1.000 2.000 3.000 3.000 Beta 1.000 0.000 2.000 3.000 3.000 Gamma 2.000 2.000 0.000 3.000 3.000 Delta 3.000 3.000 3.000 0.000 1.000 Epsilon 3.000 3.000 3.000 1.000 0.000 phylip_dm_sq_invalid_empty_line_before_header.dist000077500000000000000000000003251520735541300355220ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data 5 Alpha 0.000 1.000 2.000 3.000 3.000 Beta 1.000 0.000 2.000 3.000 3.000 Gamma 2.000 2.000 0.000 3.000 3.000 Delta 3.000 3.000 3.000 0.000 1.000 Epsilon 3.000 3.000 3.000 1.000 0.000 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_valid_lt.dist000077500000000000000000000015621520735541300301730ustar00rootroot00000000000000 14 Mouse Bovine 1.7043 Lemur 2.0235 1.1901 Tarsier 2.1378 1.3287 1.2905 SquirMonk 1.5232 1.2423 1.3199 1.7878 JpnMacaq 1.8261 1.2508 1.3887 1.3137 1.0642 RhesusMac 1.9182 1.2536 1.4658 1.3788 1.1124 0.1022 Crab-E.Mac 2.0039 1.3066 1.4826 1.3826 0.9832 0.2061 0.2681 BarbMacaq 1.9431 1.2827 1.4502 1.4543 1.0629 0.3895 0.3930 0.3665 Gibbon 1.9663 1.3296 1.8708 1.6683 0.9228 0.8035 0.7109 0.8132 0.7858 Orang 2.0593 1.2005 1.5356 1.6606 1.0681 0.7239 0.7290 0.7894 0.7140 0.7095 Gorilla 1.6664 1.3460 1.4577 1.5935 0.9127 0.7278 0.7412 0.8763 0.7966 0.5959 0.4604 Chimp 1.7320 1.3757 1.7803 1.7119 1.0635 0.7899 0.8742 0.8868 0.8288 0.6213 0.5065 0.3502 Human 1.7101 1.3956 1.6661 1.7599 1.0557 0.6933 0.7118 0.7589 0.8542 0.5612 0.4700 0.3097 0.2712scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dm_valid_sq.dist000077500000000000000000000003231520735541300301710ustar00rootroot00000000000000 5 Alpha 0.000 1.000 2.000 3.000 3.000 Beta 1.000 0.000 2.000 3.000 3.000 Gamma 2.000 2.000 0.000 3.000 3.000 Delta 3.000 3.000 3.000 0.000 1.000 Epsilon 3.000 3.000 3.000 1.000 0.000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_dna_3_seqs000066400000000000000000000001201520735541300267540ustar00rootroot000000000000003 13 d1 ..ACC-GTTG G.. d2 TTACCGGT-G GCC d3 .-ACC-GTTG C-- scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_empty_line_after_header000066400000000000000000000001061520735541300333050ustar00rootroot000000000000002 20 foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_empty_line_before_header000066400000000000000000000001061520735541300334460ustar00rootroot00000000000000 2 20 foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_empty_line_between_seqs000066400000000000000000000001061520735541300333600ustar00rootroot000000000000002 20 foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_header_too_long000066400000000000000000000001201520735541300315730ustar00rootroot000000000000002 20 extra_text foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_header_too_short000066400000000000000000000001041520735541300317750ustar00rootroot00000000000000 20 foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_no_header000066400000000000000000000001001520735541300303650ustar00rootroot00000000000000foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_seq_too_long000066400000000000000000000001071520735541300311400ustar00rootroot000000000000002 20 foo ..ACC-GTTG G..AATGC.CGA bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_seq_too_short000066400000000000000000000001031520735541300313340ustar00rootroot000000000000002 20 foo ..ACC-GTTG G..AATGC bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_too_few_seqs000066400000000000000000000000451520735541300311460ustar00rootroot000000000000002 20 foo ..ACC-GTTG G..AATGC.C scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_too_many_seqs000066400000000000000000000001051520735541300313260ustar00rootroot000000000000001 20 foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_zero_seq_len000066400000000000000000000000171520735541300311350ustar00rootroot000000000000001 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_invalid_zero_seqs000066400000000000000000000000041520735541300304560ustar00rootroot000000000000000 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_single_seq_long000066400000000000000000000000521520735541300301110ustar00rootroot000000000000001 24 foo ..ACC-GTTG G..AATGC.C ---- scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_single_seq_relaxed000066400000000000000000000000731520735541300306010ustar00rootroot000000000000001 24 i_am_a_long_sequence_id ..ACC-GTTG G..AATGC.C ---- scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_single_seq_short000066400000000000000000000000201520735541300303040ustar00rootroot000000000000001 1 - scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_two_chunks000066400000000000000000000001051520735541300271240ustar00rootroot000000000000002 20 foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_variable_length_ids000066400000000000000000000001521520735541300307270ustar00rootroot000000000000006 6 .-ACGT a TGCA-. bb .ACGT- 1 TGCA-. abcdefghijAAAAAA ab def42ijGGGGGG scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_varied_whitespace_in_seqs000066400000000000000000000001211520735541300321450ustar00rootroot000000000000002 20 foo ..ACC -GTTG G..AA TGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_whitespace_in_header_1000066400000000000000000000001521520735541300313140ustar00rootroot00000000000000 2 20 foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_whitespace_in_header_2000066400000000000000000000001261520735541300313160ustar00rootroot00000000000000 2 20 foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/phylip_whitespace_in_header_3000066400000000000000000000001461520735541300313210ustar00rootroot000000000000002 20 foo ..ACC-GTTG G..AATGC.C bar TTACCGGT-G GCCTA-GCAT scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/prot.emb000066400000000000000000010214541520735541300251140ustar00rootroot00000000000000‰HDF  ÿÿÿÿÿÿÿÿ,#ÿÿÿÿÿÿÿÿ`ˆ¨ˆ¨TREEÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ0HEAPX(Èidptridembedding0ÿÿÿÿÿÿÿÿ x�SNODè¨  TREEÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ0">ÿÿÿÿÿÿÿÿ ¸>�TREEÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø4">(>ÿÿÿÿÿÿÿÿ  øxTREE ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ,# ,C ,c ,ƒ ,£ ,à ,ã , ,# ,C ,c ,ƒ ,£ ,à ,ã , ,# ,C ,c ,ƒ (,£ (,à (,ã (, 0,# 0,C 0,c 0,ƒ 8,£ 8,à 8,ã 8,@>IGKEEIQQRLAQFVDHWKELKQLAAARGQRLEESLEYQQFVANVEEEEAWINEKMTLVASED§«q½¦Y½ç‘½V€'>Ö:J¼û/W½Ð0½ž½*¾t@¾8Ýí¼¬w>É#§>B…b>ñÄM= �Ѿ‡~ž>È™^>˜ë¥½\UN½ZL½%ب¾R³§>¿MÚ½&ß½ƒ`½ôß½ ºº#–2¾g®§>­P�=‹Ý£>8G[=™í¾Ø»f>Eù¾Ñß±½iœÄ¾Ƀ½ @==•°³¾ì~¦=å‰à>ЍÕ<—î>Ÿja½ä}M>ì >ýŽ7`ý½qß2=ïv¢¾kñ¾ÅVÚ>+a¥=úî€=éW>‰T¾2Ë=Å Œ¾aݦ½ù-´¾ª/(>òXô½o$K=@ÈN¾Ï÷@>]Y¨½8uu=§Þ8½Ñèx<éGª¾Ë´Y¾—'¾Ä��>F %=)ê=ï‹=A¶>®R¨>"¾ñJº½ûàP>Lzç=Žª‚>»õ¡¾Mü“¾öaP>[HE>c[=öJ2:R´¾ÛØt;Û¤]¾šó=òõo>™~ξU 0¾œ^¾¶Š >þ/Ù;„¥û=¡‰“¾r1S>ÀM>t±�=«Ò°=»Î\>9æž¾£‹=·ƒ> t¾Ùʰ½¤“¼Í�›¾�ˉ=ºo =¡-½â²¤¾¥¿>¶ÓÞª´E>ó:<UÓ=4¤&>|{ñð>H~›½rói>ÎÒ<•>Ct¾Ô‡=ú¦‚»6Ý»ïP„=öX”½Fø§¾=Â�½9é…>AŽS¾ª±u>“P¾;`æ>w½­>*æÚ¾ï² ¾9ÉØ¼ªÚ½þ-;¾ÂŸ˜¾:¾°¾ )E>óÃy=Ò»=÷#Ÿ>Ja ½w ‹½Ÿ—>Sh€¾?&¾Y¸¦½!é7¾ºIf½™Ê½(šv>ôŸs=óÎ>{/9¾ ¹�>/Ü >^>®'=îµ¾!�±¾Ï&?gbͽŸÉ<–¢½”™=Cc¾€È‹¾Â ¾ k¹¾ye>¬jN:p¬|>ƒ¡à< í¬º ê(=hø˜½¡€Œ¾=h ¾Â_ë½x¯>MHµ<õ„¾w½Å³ =,ˆª¼rì½=@ž>ª„>%Al½w·½½OêÅ=i¡¾V’f½¦Åâ¾µ�¾ Ôþ=†1ˆ¾©ǽ”c¾>çL\¾�>óLW¾‰”>픦¾Õ=Ƽ>_mM½ð¡¬¾ƾ:ÄÜ»>în¾Gÿª½RmÁ½¬äN½b G>ømº>4ó½‡Ã">®‘H½èÍO¾rÍ¢=u¬Ç½>—ß< m½ç_¢=¹±>й>š6>æfj¾é‡*¾à÷ѾÁ2W¾Qï§øÆ„¾'L¾Uc ¾>+¹½e›=êTÅ»jX>÷–‚>1×¾FNC½€°¾ª>jŽ–<†}P¼ô/>.h¯;êཕ˽êú=ÂÛ7¼ óì½Yþ=6ç?<'*9=Ìý/>ÂOŒ>¾L>h4u=!þºŸ?qê ¾R›½=‹×C½4A^>f`1>"¿a –=¸I¯=ß]¾.Õ‹>“«î½8o ¾‡p>Æ{L=å²½HD+¾Õ³¾ÍéW;›/9<[Ú½Ö©½áco>XD“½I²¾¢ï’>©F2>ñÒ»¾¢b·¼Io¾æ…¼=Û½o¾\ª�½k Ï=V÷Ÿ>�ø‹>ÌØx¾ØVÒ¾zO‹½Y>¾Cu%>¨ì+>™w=*öÿ<ótM½`H5=dÿ½„l®¾œ›¥>{ø}>×Ü1=$›½¿:ç¾L>GÙ?¾–kI=j[¾‚£™½HãÒ;Ü é¾O>¼ 8=«û¦¾bAƒ¾}޾ ~ùàwá<“û\=9> /¤=æ„*=T‚>òêt¾?~¯>ïFø=Ò¨=“̼94Ù>{"¡½¶¥U¾ps²>WdÏ;Ö¬>ØT'¾@íÂ=5ºá=úòè½Ëæ½>ŸÄè»BW²>_0ê=CžÒ¼Ÿö=•߯½ª§O>Jç®>䤽ãPK>z¾ªß�=$“>’T¼>&ü7¼~Y™¾-_«¾Óbá;´£Ú½SØ=F”À¾ Á‚»¤0Þ½ºl>ˆV>d‡#>"³¼B:ÛƒÞò=‰îÆ>ß*ø<‡)¼;—=fÈc½,5²=Äõ>>s«è¼çZˆ>-G›=/fŒÍJ(½o5–=vÍã½^> w)½ŒÆø;úíí<�nŸ½|¤> I¾Fµ$=»üœ¾Cb¾¬·“=ª¸=°^ù¾HÌоa%¸¾qj½v„…¾³a¯¾åâ�½?A>Ž}¼Ä�^½ßh/>e%>øÁÌ= `~=Û£i¾ck?ñ?Y½¹±"¾^/¾�Ã>u/º¾èä¾™¾²§½ËM¾ß0 ¿Iâó=X;:¼ýr©¼¡b?¾{�Á¾ª”y=Îçñ½a¾ið�=îY¹=Ãü ¾¹÷ƾKúؽ§žk¼^ù=Fe¼“Ú¡½]/>ÕêH>“dš>„U?>Äþ½iƒ7¾Ï9ʽ¢ë#¾N¹½.D·½bì*>)�P>#éÏ>=§E¾79¾NT£¼&r„¾ÈF¼]¨¯½Ö,">æeɾ¯|>‹>3¾ªW¾z�=>€>‰ôô>aç=VÔ¾V(¦=ƒKÆ<ŸU^>z¢j=ê&J¾þd¼ðìÜ=ƒ4š¾Ý±W¾¥°¢¼ÈOˆ>Øc=y3¾'ªz>‡Ÿ@¾0‚*>Š[‡>ⳑ¾0“[=›¾/—¾>)î÷½æ„˜<=Ÿ¾A׺>�>V~¾âû‡½¾Ôj>!3Z¾[UM¼^f’¾*‡�>hâ?%s½PÂÓ½@š½?›æ>J�~½¸}>{>‚E£>@¾‚>è^>ç{>ó†>¦ëÿ=_–ˆ½"1¾¡Ã½õœ…=X%¾%,"¾Qu¾ ý¼4#ò=M=¾Xn¾µ >‘*¾Ÿ³6¾nÈ„>íEѽV›ð<¯0:> ½Fè½¼Hã¾Ý †>|ïX<Äý*„1= ð(¾•²>\£<>–ºÊ=,Eõ=q#¿Ë@>‰óܾâ“x½_[›º¤9¾Vk«vµ =.립�C¾šá<ÙÕØ>%ýÐ=¹»©»^˜>s>€¾Ü=â~®=bZ=g‘>Âbæ½8bµ¾‹f�>l…ï½1û>ö‚3½¶¶Þ>ºÑ“>ƒ›>–´Ž:9¬ >¡Mè½ßÙY=e&ܾÚ©>%©½òlÂ>bX =Ò0’>BÆB¾ ‰S>;𙾆k)¾É4¾»ÀW¾uç¬=##]<½O¾¿A?¾>^â=’D>ÇÀ>­za½fXÛ¾Ú¾ê]Î=ÏPÒ>HO>èP¼Ž¿R¾° €½‚é€>0 È=5p.¾8ü›>Þ•³>‹>§~>8P,=˜•f>Ã�tÿ£>nl>n½áX.=íÈ>È6`¾œÏ>³Íª>�ÎÀ½ÙZ¾F}^¾y7�=ׄ ¾w>¼½?3"½¬ ç=FÀ¾tl¨>ʦ>’ò ¾\1¼¨…é¼É’о³q½ª6y>±ï)=ëßâ> ûb>\Ÿ ¾0‡k¾è;=Ù²>ýÇS>Ι¾е>ú‡E>Çn›½Û×">pc®=óÿs¾~ ʾ«§˜½c$©=Œ]«=нí<ݽ”ž>—ý ¾ô§�½#®‹¾°¤k>pó½ÏÄP>Z]=ÿøŸ>“>b»¤¾*?ѽæMR¾ã£¾ÀçÕ½G‚¼�Ö«>%«Y>IC"¾œ˜©½æļÁ˜i¼¾Ýj¾DXê<�G]Ó=¬"W>´&þ>;6Ý<Ÿ×»¾�Ú€>2¾µ+¾ž¹×¼‘¤»òPÚ=urš¼ñ­ˆ¾ ”¾Ý¯>öS�ßoX½6¢?¾ àõ=#~ƒ¾Ñ¡«¾KŠ>•3V¾Wq>¹´¾!ì¾}öä<.!C¾8H(>x®È¾ùGC¾+O=ê‹‚¾á�"¾Jú]>”éa>e¹<"‘ ¾MÒ =0×¾�)‹MÐÝ=lšv=Ò ¾æú>�˜>,[,¾²u)¾yÛJ¾*:>>">�d‡=~§âºÈø´<¬(=§ßf¾ñÕp>û�<¯ð>×Pº¾ãbN¾ ½7½ Á¾�ø¼œ_C¾‹eÌ½à·Ø½¸ŠÔ¼¿”™¾úÂ>Î>>&_Û>”„;Î$Ç=É6=8.÷=rjQ¾½ºm¼ž©>ô­J¾ïAµ=¨ñ=›§=Ã6Ý<ø–+¾jVA>tµã=¾ªÒ½&ë¾oé�¾n„¡=M1h½þDV=èC¾v_…=оŠß¾êRö»*'Æ=$®Å¾±óû½V½¡„$»œ1>È‹½éŸˆ>¹ >Í'©<ŽöÝ> Cå= l–=úê}¾·á=Ç^>‚ 3½{›¶½”¸¾ñÄ´>ô”½—__>jíu>j�¾©uu>_™©¾"Fç½»Ñã½Ëæv>Üø_=~­u¾•4¦¾|âù½X¾šŽ€>;`ý=Œk>>Y¢õ=+B[¼–­O¾CAÒ=ÅàĽÅ³>G&%=•ñ›½!9p¾ d>ã’¾õ:–¾×Iõ=Çîß¼'‘#>â¯>•œ8¾´t3¾5²<ã;Ѿ;á7¾b e¾:ëu>ag>³+J¾¡})>Tá1¾è*>Y2ª½–滺‹¾8¾;1—½õšb>hg¾ç¦Ž>&O)>s¼‚>MÉA½ X?0½Œ™=p@à=ÐÍ{=ݨ½¸)l>š‚½}�A<Ÿ+¾±êï;Yô*>/H7¾•–l>k.�¾Èh(>íç¾AÅ*>õ]½·‘¾»—Æz¾×[�¾œuš>´ùÄ<�>h±m¾Ä÷è<¿ºƒ=PÌô=‚¤"¼�–K¾49>Ï�’»Êø¼P‡¨¾Þý=eÿÍ=�DV>x{á½1˜=¥£h>侘>Æõ¬>ì¥Ë>ÞM¯¾ ᓽ@H=©Õ;½&s>´*y¾6±ª½,I >3`¾ö†”¾ mm¾rX ¼M%½qµ-=àlö=™¬yóól>ñ†Ò=uŽV K>Úl(¾£ÅǾÉõl¾Ö ¿³¾‡¾©¨™>qùŸ>e3�>&�O¾•®Š¾Ú¬¡¼¬‰Ã¾Än==ß0§¾ƒð÷=Øi¾3d¼Z«=+$¾Ÿú<>m§ä¢¡¾íÙX½8¿1'8¾ç’>>ó²î¾BõÛ½û ¾@ =&¼hM˜½³˜t»"9O¾£ñ)¾34½ë䨽–U<^"€=ÔTÀ<þ‡Ô=b÷ ¾uÞ>оƒÜp>A¬Ø>R°¢<˜£i>Ñfp=cí->Lì½½ýÌŒ¾�˾<êSÒ¾` >î/q=”>ª>k§=f/b>-aú½5>¾‰ü“»Ö“~¾2 ï=º ¿%ྠ|¿½ÜY+=šW)>²Ö¾X}ý¾ÊżAæà=I=ë½µ¶-¾5‘’>’"h=å@ï½¶�_>uŸ¦½ ¥½ª¬Œ¾‡mó¼FMf>ƒ v¾¡©½Ñ"ê>èE>å悔p½~‰> Š>#ò¾�ª¾Y’ÿ¾x¤x½uûa¾^ós¾tÉ©¾âÍ1»ÏŽ =ܦ¾‰Í¾š#ž=”mY¾©`p½’Ç"=·à¸¾¥9�=z¶g¾Ç´½Q[�½ìµ>Âi?0ÅB=Ëp =Kì´¼kQv¼HY½gûá=^V¯½7Ÿ=”ñ=«°ˆ¾ÔC¾�˜>Éù4¿lœŠÈнó­>Ñ>§¾w>{ú–¼qÝû<�Âí=wÆ$>íQ3¾‘»=ßu±¾bñ^¾”Ð,¾ãÑl=�Mí<Ž�¾øb:¾NÔ•<žÒ‚> ¶> ¾þ<œÆV½µ‡=V™%>õ&f>ÒØ+¾îr>kòI>ºB¾÷#¬¾ª ‚½–’½c¿TK¾r”k¾,Ž–½`pŒ>ë =æ>jŒ°=´kŽ>?—¾„.y>Z¬=Rk ¾ð 5ºS>'ji¾z€>¬Pê½EÑ)¾6E >qe¾–O>>Åt ¾¤ÔÞ¾éýª¾ÜJø½Ìèq>ž©Ø>u®»½ßÍ–=�+½¦ù‡>i†"½+ÔÁ='ÂN½‚»D¾Ä =š¾=¥ÐŠ=ݸ¾bK>û!¶=­±¾ÄH­=O:¿¾8˜?Ü}8޾‹Æ¼û¥­>mÏa>e”>½Õ>~2Œ= $h<_±Ú¼¥U>ÃÑt¾1ì½J&Q½þ ²¾è€y¼*/0<æ4Ø»û{>Õ=Y¼dŸ¿yrú½#W+>zE>Ÿèk¾�#>ø9)‘𾹨 ¿2Ê=7e‘½OJÎ<ú0Z½ˆá½–&=­ÝC½û[‰¾þØþ¼ná¿f5�¼?L¾pÀ¾ØkN¾<ÿu=ëîD>øêŽ=½S2¾&„¥>žmJ¾ÖŸ¾¸¾–ƒ> ó¹¾[Õ½InÓ<ú{•>æ’†½ðÔ>SìUªG�¼¾1+¾#µ=[¸'=½Ïb=Tàå¾�H¾êоúw`>‰È=‚#1>æ5>J)ß» Ü!¾Ÿ¼'½Î(¬>Ë{>Y‘�>ß4>4½Œ}—=è[¾&y–>ë–ó½Ü¢Ø»¥±%¾99g=—ï:>.ྠ[>G Û=9è >ôˆ/>õ.¾ôç¥>äë¾A:5>ú–¾9<Ø=˜š >ÖT‡>œaC½oh¾îá=óa ¾/½A=TÁ*>É.,=“›½û©¾ÉG½¾YϾ•�=¯±¦·=�=IH·¾¬YA¼ i¾÷êU¾ÕC0>¸êr>Bm|>�,=Ã>N|¾qn^½ØK0>kd9¾Á/¿°–Þ¾k�>D4»'ui>•oD½Ñ‰©½¬nH>’懾³~>$$J¾ õÿ:kvоù€¾Y X½Р½Dêz¾nSƒ½+è=ƒÿ>"Bî¼Ó ã>@ô0=XeŒ¾ÿ{Þ¾‰¿¾î ¾OnK½lt”½…3€>È>>�—=€…„=X*~>³Š<‚ ”=ýÒ?>ºø>|O.>gª< pn>F œ¾H}[½Ãª¶½£!=ÐlÆ<�Ï‚>gÁâ;ß4�¼e<ç=1ì]¼’P½|GT¾´ÐR>CJ¾ûl¨=ž¬¾Vð›>ˆ>¯¾Õ½‚Q=¾Ú•¾©ëV>ÛÎÒ>K>9…p½N8ƒ=Éùœ>8Ùñ;¬5¾4)¾I�¼T½ ¾•<�¾Ç޾Ñ-0>ªH¾ì“>iõ¾½ç„q>ƒ¡c¾ï-¾-®½¬¿>D§=³>Qµ+>u,5>Q�ƒ>F«,¼þè=yµi½b >'<@¾@˜?=—':¾>÷µ½*ÃG½¹0–>&Ý=ôJ>ª¡Ê=á•>¹F€½×_¾Ð›·=“{ =Ö}>�É+¾U½½³¾+½ÎÆ©>þP®>‹×>ÆZ¬¾ð>>ª?I=šæø¾Óé½à>¾åS=ŠÞ:>óª¬>€ý<¾Zjɽ?Ô=[Ej=¸W>Ò¶á¾p›5>…%ž>¿ðµ¼ãÌ™=}«=…bi>Îyõ½%t>Xä¡>Ѽo>LŠ?Wø<+×˽‡ ˜=€N¿ªÈt½Ù¹>¡V]¾M”®>fb¾híy>ô–õ¼™ê»+C×=D|š½Lk¾ô~ä½VÌ€>ýÀŠ»Þà ½è9þ½ZaÆ<¥P4>ú:º>ÿ€Í=û¢µ½,{>,n–¾Î“ž½² ‘¾jIÌ½Ž‡¾,»«=„Y¾ó+p½GÆó»·�>®Ž¾se€º¾‘V»Ü*Ý<»�¿>ÔÈß½ÜZ=�¬`¾ß„C=<ó‘= �=¾Öa›½Ä €<½Cñ½\È·=û-¾‡iò½?AD>Éy¿½«¨>>¨<­¾^ë|»üC8> §¼Ë¨A=ÍâA>Al‘¾07‘=Ww ¾þ³¾k ¾„Ö¾>e�‹>hÆÊ½‘ø~<“"s=˜ä!?Ó¯w¾±l&¾šào>gP¾vé>w.½ºˆ>­=²¾q[¼ß�à>÷÷̽®ŽÓ¾¥¹=踆>†?ø<5õ·»«‡Œ»ß¸w>¶CÙ¾¢;%¾™uD¾ÒÄM¾ ?¸½1@ؽcRØ>à=k¡Û>7üæ>f,½Æ¢›¼ „ë=sQ1¾Hÿ¾c*¾ðâ°=t %>É6M½dñ!>[í»å´ð¾}@K>†Ñì¼yÚ>æJ¾ZÇ!¼"•é½í´½«í[=�ä@¾ø`(=?�±½k?h¾,( >nÔ<Ú#¤=íò?Èr3>JÖª>Ð#!>IèK¾çt†½i“½‘jã<§.€¾$¥¦>—Ȫ¼Pƒ>Û™­½Cä­=©r1>Q¬«¾×Ö<µ‹½Ü½F¾”?=[>¤ªŒ>t®—¾s's¾z,>ä =+›>.¢œ>+_>W>.C½ Õ½=â�¾™±²=<Ók>š¥=¸J>Åa¿�œ¤>¦È=„Ž=kþ’¾�h§½JëS;ó³$>éÆÌ=|Íæ< />ø > &о}E7¾Usì>åg>5”÷¼èÈ>›9ƒ¾ôË->q‰¾„7ÿ¾¼À>µª>–Íž>7ø5¾Âßg¾q»‡>�”œ>þT5>{m¹=<Ì©=}k >­ ޽�ÿ@¼©f>$±>ÂÌ‚¾6O½²Žü¼q�9¾y#S>Aý¡¾$ƒÈ½ªˆ@¾´µ"¾öo¾i/~¼4u޽¦w9>³Ã_º%D">·)Q=\_(=¶Ð>ä~½;å>C\V½¸Z&>eÞ¤>ÏH3|=õ¿ƒ½aˆ)<$¯=ÆK§>@â”=yb#>Ãtí½ŽN>rµÃ= Ã=S#н :>ßHä½ûà™>`.s¾µ¼�>ÜLˆ=P‡f¾�”½·e1½lÿ=7û¾½°<3»ª?ó¢"=ÅÀ¾Ÿ½A­>>1Û;¦E+>Ûù–=‡<H«=n$>Uß½—X¾$¾Ä?¾UŒ¾DÆ>,EÆ==¼#VGźz%&>œF¡¾N0>3[½¾!|`½«Ñ5¾ÈÇ>“üõ¼_3Ù=áZ•>ªaj¾@Á>¡�¼ôò=N£r=Îó`»ÊŸ6>šR=+⥾ŠÁ=Ó{>‚Å#>Í·¾œ4©½Œ"U>,Å.¾Îq½B]A½^i`>tù³¾‚« ¾Lë%¾uTʽC¼Y=|+=g ¾£ÿܽaq ¾ô�?1¢>™”ô½‡o)¾³÷w>%{=E]>$ù4¾¾z\¼± �¾-ù=¾÷\=“¢Ñ>ªtg¾Éÿ+>=l�>Þ›n¾y`¬>ƒ—y>>À¸>ü÷'>÷ß ¼')e¾^«T>ke9>Á–Ľ+<9¾nø ¾�±» »*ív>­VA>è!‘=Ð|ˆ> T€¼?,>J9í=FÒ2¾|� ¾‹×r>«ÞÀ½Ê˜=ë“�=߈—>Œ\;>4¡´¾cT¾“Ž>޽‰Ä¾Gá½Ø-+½S“I¾ú'=²t »Ú$9½B放ÆÈ\¾Çó(¾pÛ¼>‹þ�¾g¬¼—Ï»½T|Ù¾„}ˆ>Ø%K¾1t>t> çè=Þy>l V>jÕD½��>�ÕÞ½w¶9=Ö€Ó¾}U®=̾s]>˜4ß¾ôÿ>ɆÎ>|Y˾LÇ>š í½¼šó½ü ñ=Å”—½²ž¼¡¸ñ¼"ʾ¨TŒ>ƒ‚ê<6e½Ò÷Ö=àq“=*ñ€¾Ë«»uû¡¾™†Ž¾U¥¾‚‡½/=;S¢�>‡di¾üT¾çìf>â­�¾B½{•<8¡|>«¨=¡Ä!>Ò–5¾½d3=V]^>>ˆº¾x¶Œ»€ZË>=>T„\><Ÿª>–¶A=u‘<™Ü ¾$vé¾²†ƒ>l­þ½½vµ=‹«L¾Æ¾œ�Æ>�ˆ >ü  ¾ZG>ç¾.”>h$Ñ=( N=þf¿½Ü=_Ɖ= 9r¾c )>Æß`¾ãUJ>$*u=K°Ý¾å¯¹¾ÉªÖ=¥A0¾±Æ>Gö6=› G=|è¾l¶Š>aî>¦g=¸èç=°€�¼ó—Û>j˜°½ðù=à†>=¬’=&9‡¼Ó—ÿ½“¹š>#�¾.“>Q€!¾Øì>>Ôó<†7̽Ü×=êêd>uy’>Ú¬æ=¦óc¼k9.>ýŠ>}=À¹ ½Žâ¨½Áä=o¥Â½Á'=G©Y<ÁU½£´ˆ>Á_=䳿îw½¾� –> —¸=S[µ¾®B@>ÿŒF=ïÞ�>X�T½Óø»=/œ¼Ð>ÃzݽXä¼Û\=TòÒ=w|¾â¤>34µ¾×NÓ<›<2¾II0¿)…»Axe>‡‚8>Ç�H>ºŸ>|2>®=+UŠ=nk¾“p>¡¡½‘ô�> ¾Ç>¼èÙ½�Aß>í}¥¾¢œ>>8«{¾õn > Øœ¾š¾Evn>bÂÓ=(>¾¹€º¡éû½x`¹½z¹m¾2{Ÿ¾´]µ¾Ó1¾iW¾×L*½aǾ…B ¾ –ê½ `–=¤È½ÿ´+<ó…{=ô×ö=¯,̾Bèp½�®>Û›M>‘tD¾CmÊ=öîh>S >;�o½cÙM½~î »¥­ ¾kr¾)=8>ƒÍšºö)l>u?Fƒµ>^$�>ÎCؾ«u1>H»€<´¾¹=K¹=ióI>‘G{=Pð’¼³%¾Óê+¾Ì,†=d”ƒ=‰óç¼äŒ= ¢\¾ ÅŠ>ߨ ¾Zè¹=-o[½6>kÉœ½2¤�¾Ò�Ë>ö»c=¿é;½‡S>­�;²·½Êº†<’Þª¼WÌG<øZm=æ „½Å, =Ùc•>î�½ÂŒ>ÞÀò½øù=½[-=É|ƒ½¾d ¼*‚¼ì@O< Ü–= )>ŠåÕ½¬1y¾þù*=•<§¾"û³>LM7¾Rý(>Ð65>Û•+>6Ü´½îž¾ë¨ä½"¸>åN‚¾0×$¾ ™=B­¤=é‘ý=a1]¾¨X>>M$`=ÑW†¾I«¾ðä§;Ú¶¼&[©>*²á»y–É= ½½8¾©§Ò=TëÉ>ôq’=a\c¾ 5r9z)>øg>�˜�>`Œ�<$>'>ãͽ€{=."­¾ 6>û<¾‰õâ>¯o¾ýVsË¿(=úF½LÕ‚¾×¾ =Ñ­ˆ=aË@>þ{½Žt”¼²å½=3Cp<“¾Í·¾Jè>]T¼àýÂ<¿”˜>ÍS¿¶wC¾%->? ¼µÞ=Iå>ß7¾�º>Œ!޽·Eç½Ú/p>8�>WL>ÊÕ˜½Ež> á ½^�A½{€T>Cþà=d8½fŸ=IǽqÔ-=‘¶Èç½Q½.w>¢ž ½Š]™¼¥ )¾Wj>x¢?PfÔ½ÂO~½Æbƒ>ò’y:ºu›½›u0>Ce>Mž> ŠÆ¾Ž�¾¸oš¾Zg�>Ї>ù½)¨>'û€½8>#=é˼>üD}>öÚ…>Âæ7¾,>!=…p¾ùNþE¦q½oð·½<† ¾a�„½\ÿè=¦ì¾Œv½�4>¼Ä*¾ËAo½!&=’¸J¾I�¾Yv¸<Ãp¡¾óΆ¾þر=(ø•=6¿Ü¼ÉÕð½NE�¾à¸¹;÷<õ½�Ý–½èH¾×æ¼<¿´>q�r¼e#8>…¾å*ˢ꾛4=Ôæœ:�7P¾#ï-½˜†ð©ít½µd´¾”ǽ’ãï½<Œ$¾Yùº=™I‡¾_ŽA<”>5÷Ç=*ÖR½š×!¾ Àž¾ày´¾gC:={À½äÈT<ýâ =㣾Vw(¿Vk.>С¶=óņ½Z<¤ƒx=�O@>i€¾É…´»7 ²>õg¾¦Û¨¾$Çì½­ù6=±ŒV=Ç©m[v>÷}>Wè<Ûº =|¸®=¼ ”>¡.¾>Ý=‰(á=[™Y¼ZƒV>=^¾ÝwW<«� ½�p¿×I0>¶Û½ÕÒ´>RÆ ¾*C?<">2¹½ù.b¾Sï>Ju�=êj˽ŸR/> žÕ>¬¾Ä_=Óÿо¨(ò¾Es=ü¸…=Ôƒð;`NØ=lâ@>.ߨ¾3=…>+Œ¾ŽaÁ½Íá=ù‘>&Ÿd>hù=&¼ƒ=K/m¼–K�>ßT5>À!p¾³‰¾IÒ=§B¾[ÿ�>/Ù•¾,aÒ½ƒŒ¢>¹E; R<¾€ü7¾šÏ=Ro+>à@g¾v9j>Çýl>Ø´-¾ÿo�¾6¤“¾Ê²!¾$×Ú¾¹àA¾žf ½µÀ ½µŸâ¼ÿ—†=²T-¾tù•½ œ>J¾‡=€<½ß¸ì>ët‰=z@f>·ñx¾C“á=F£>¸¤Ú>?ÑE<Ê‹¾8E±>¿8}½¤Ý²¾Þ ƽüÛ=¾¿A8¾€3¾wµ;¼Ña>º®.¾sS¨½Àžm½²˜Å>†§ë=ØjW½Œfu½ˆ¹Ô½óÜ5¾Œ¾H)�>†¾±ñs¾ObÞ½¯cå¼!kª<ÄC×½åÕ’=öS3¾·(Qº‚¦> þªÆÈ½‹eÞ½Ëëʾi×ï=Šì>ðú½À@F>ggÕ¾n&½jÚ¾$Ý >�ñ<>'i¾û83>Ó΋=Ñú¾Î�¨>ØÛÜ=Êm-¾Rt«¾u¼Ô<”j ¾°HF¾ëy,=âÁ>EäÇ<ã‡r½“�‡>‘f¿½bÈt>¡£7>-j¾rœë=Òê?ùŽ >þ |¾b>>i•u> +R¼ýÈ‘=«ú(¾­Û:¾1¬ >ái½Ý³¢½üÑ>3º>¾‘L>ën ?ýz[>ò ?wxù=lUJ>»U¿%…–¾üSf¾¾‚m=žò>$´�¾|&W¾Úä=>‚"l=þÊG¾¬¶ô¾i ù¼.•<:#¯¾ï‘N¾'Ö=°,³¾ mÌ<Þ½e2>[ †¾Ôà¾5Äš¾à >šª½¤G‡½•�½dC”¾ƒ >ô�>­Ø<°'(¾ö¾$íÊ=9u>û7N¾áF–>S/>+¼2=â¥=(£u¾|¼ö;¢9Ÿ¾/Û¯¾!ž~¾}õ¾‰B0>Eê{=~õ€¾•“`>á-è½ïd>±¢>R&¾l6q:ð€=¾Sñ½\z}¾aª±¾ ‡¾ÊÈ”>ÅoB¾÷×D¼ÀÔþ=?JÈ=“ü¾¬Å¢¾Ê4¿a˜¾ ˆ:¾Ÿ^¾Í k[J>Âì…=4b6>L»=9B>¦m*=.•>ߖѽsë"?5)=Fƒ'½v<•>Ñf„;ù”&>m»Ê>¤Éœ¾[Cº<†�$>.>l"¾l¶:>sHt½Úàœ>×x½†ßܼSËm=wõ¡=¢;>–«“¾Tr=�í%>ø©”¼T˾)¤=$8a=Á�ñ=Ò¦¼§—0½„ÙT¾ó.>y†&=³'½Þ/>Ô@#¾–r>ýÖ ¾²&Ÿ½ «­<·¡>J4¼:áY½ž –=Ï…‡½;ò(¾ÍîT>êk�¾�µœ>1>±¤ ¾,sM½Ùgz¾îw$>"Dã½2ð½Ç.‹=»5ù½ÄXW=‹@¾¶˜a>mIe>ó$¾tM‡>ÏÞ>Èe=oêC>î¢e;½ž¨ÑK¾<±Ÿ|…½*L¾IäÀ>㌼!Áo=°)¾Ýþø½v.¾�È�>Keš¾bн‹'”½/7†½QÅ®=�<ý¾³mʽkUƒ½ÍYa¾J€½PÑo½Ãć¼Ef¾!O@>RÎ1¾�Õ>Ø¢v¾Í±<ó„í¾/CB¾èZ¾ÀY޾eïÿ½u^¬½ÚA+¾‡†¾´‡ ¿�ÄÕ½NŒ>ÞP¡¾µAd½¯ºÚ=…Í ¾�¢5¾¶1Õ¾à¥>Ä[ª=Pä8=¹>öóç¼ð‚оAæ=•-ú½%l�>©íâ=R[¾¨Õ/¾Öô÷=“�¾JÕŸ¾íÈ¢¾% ¬=å§¥=c³¥¾Îþƒ¼g>äãÇ=g½ï”µ¾bˈ=t­b>—T(>"€K=_ɬ=Ä´–>yã ½fúS¾ˆ±¾¾�çy½ZÇ”>ËŸ�¾2¨½Þ=ÿ­½Q¢>‚c>΄Ã>Á>¡ðœ½8¼³>�ò=Jg¾V)½½‰\L¾ñ.®=šÌŽ1*ô¾½;‰>¦åç>rýŸ=ìí…;TC¾afš¾«e>G�2=-ñ€>Úÿå<â §½òl½ì°½—Ê>Õ@/¾'·>~Ò$¾Êîò>¡¢>þؤ½…]7¼"K=n ¾J�Ü>ðð3ÖÁ>u¾”²Ä>”²¥¾¿nP¾üѾ9k•½R`s¾õÙu¾?�>/^?,Hc¾/Äx¾Âò½7¿J>f5 >[<¾<0d¾[»$¾,Jy¾¶²>xi¼C!¾Ü´Œ¾çtÉ> <> ª:t&â=ÎX-¾u-|¾Ä¹$>*¾ßÓí> Gµ½ W|=¿kz;~3>LŒµ¾|¾Î……=Ľ ¬Ó»‘ÿ½X%-¾|uŽ>vn�>+½@½q”?>Ní�>Ž¥>ÜÕŠ>Q2Ô=~s§=u<Ö=ÍÏ>/¯¼xÄœ½�…¯=zñ<½aA¾Å¿�§=ŸÔc¾æÔÂ>¢‰.½1´¢=‰¼;¾[ÈL¼º›¾F¼QÀu=‘�Õ½Æ2¾f5 ¾¾d¾L”0>9êù=½gã`½Ç6À=à†>TÆi½“^>ÆX<íH>ÈÉÑ=8l?ƒ�P=*ïÀ¾m†7>U>œ¾œx`¾¯M >Ê´¼>ð¾¬çƒ¾$ ³½bñ>y|m¾9�†>oX7¾�Æ›>Ës‰>Nž‚=µØ=r �>¾ £½®“v:œ5c¾Ã× ¾\we>nˆ¾ŒÁ"¾äYç¾aÿʾ_3¾H(>¸“òù=ÈÆ8¾¨g»àÈ1½xÃò=Ròœ=Ŀ޾ÅH>˜,–½Þ½Q˜^>ïqÓ>1*¾õX‰>w­>=Í:ë½Ë�€¾Û��¾¨Š¾¤©�½þ¼¾Ûr¾Ï¾aMÖ¾r‘ý½Ô²½oŒU½n~P> g½u¤�¾÷yq¾[×T=•>A¾Ôý±½ùñ*¾mÞT>¿q±½–Z侟“š¾ÿ„=™ýò½2„½àä¾ ñ—= –è¾Epœ¾„î>L'`6Ü‚y=bRÀ=ò>=µPD¾ÛOp¾Ëc¾ؓ§½TO>‹B>J¬‹=w½Ø½ÕOÝ=™>«d¿<›�Ç=ž=ÐWѽÖɪ>û¦¾r^i¾i?/=RWþ½†Tö=žº½Ñx2>„÷̼«V•=~�â=šê?¾¯†Ý<ìa=a°e<åξeˆ‡=Ã7œ>ut³¾ÖùÇ=yf2¾Ü}8<ȇ,;gC>Vʸ½:^°= G½ 0>® ‹>†ºó>o:Æ= _¾>ã̽¤¿å=2µ¡½ë|¾žâ3>;ˆÄ<Y;ȵ.>^¦Ñ½ß�>z4>rZ—¾Nm„>ÁÉ=Ã"¿q, ¾¿-­¾rk¾¦½ˆ>�óÅ<ƒð>N’¼¢V¶¾úsE¾ò<6¾ðþ�¾°é½ƒ�ö=R‰>x’¼Ç[¾>'P¼ˆ+w»HQ(> Æ½på>JX½=Œ£d>©Œ»—’¹¾žŸ–¼Å2=a®×¾ä¢"¾±Ú¼ì—�¾�%¾é—À»8œ=>çje¾ >¾$Ëë½ }ˆ>¼\S>µ*l<¢²É½c$¾† ‘¾ ¾ì @¾-òE½N¾×¼è<>Åb‡=!Ò€¾ tv>ŽÔ¾²¿ˆ=ÐɽÍ8¾:ºe¾ËlM;œT¼=!Û½Ç+¤½�úl¾æ]Ž>£2¦<ˆ‘¾Öh˜½ˆ =î6e¾ÇI>[bÔ½£ {=Êœ;>^ûl1|>[µ1>C¬Ã= ø#>"Ù9¾Âǵ<çæŒ¾‚=¾Ú>`ìó¼ pï½d64¾%ŒD>D2ؽà#ÿ=ù¥2¾ž^ƒ>Ìár¼nP(¾x… ½ZÀ£=æQ¾ÏÆð½Üa2½Ö˜…> oY=Â’+> ¥½î¡=&Ýò=&nß=ù—›>i‚i½)÷8>§f>r&)>aa›;ŸÀ>Tb>Äë‰=ÙsT=!ÆS½áÝ*> ">P×:>òr>t~¡¾O=μ‘j>óÃ!>¬´ >0<‰à³€½cÏN>}¾þ[<—ÖX>λ#=n¢½½4Rr¾Ÿ!¾êc�¾ÒôP>ð ; i¥>à‚»¼ Á½ Ðð=S‰a¾u¬ï> v ¾(~>p×Y>¨¢à¾�1Z¾Þ•<Êü•½S/)¼\/Q>>]¼á뉾N§½0¿Á½h½ûfQ½À¢U>ªX�½”’½–¿”¾MÐ>0’¼âOB¾ðD×¼çø±>;4F¾^a:½Ù°¼Éz>ý,’¾üÔ"¾Y4?¾mp’<v[¾°r¿Ýœ>T¾-u0>ÉI¡=ÎÇû¼Y€¾!-ǾM¢±¾þðN£>ÒÜŽ»#&�¾>ã¼`Yê>ä¸>âpË=Ó6½Ü›š½¼‹»½yQ½½­îD¾³È=qá>óP"<–Wx>Pú8½ûr¾íeå=ÌEN½Ù�d¾1n>S{Õ¼iнm\<AÊÛ=Ö¤‹¾_ß�½R,µ¾\¾4»¹b=jew=ÎÉP¾òšÏ>1Õg½1•œ¾¸ùG?‰¯2?ì ´='V=m¾q…€=ž^Æ=ÑŸ ¿'ú>hµã½ ÚÃ<4§¨¾žc–¾©Ït>à7e¾ã™¾º. =†X<éÏÓ¾t± ¾}!E>Ѳ¾õÃÌIP;=´ç›½5±¾1—¶½°½‚½¿V·¾òy‘½°ÜG>1 Ã=d-U<Kt;Š>‹Âd½àJ>öì?>ñq%>ZÂÕ½ œF>³ð´=WšÀ½õ;(ek> G ¿UNà>Ì(?gy”¼µ>ë/ä½XÚæ½É«¿>=€à=@ |>ù>ù=@ ¾ ݈=9¾Ý= mT¾Ìú/=5G?¤LɼY¦Ä¾¦ìB>uN̽0�=§›N>àh/¼P×¾²0…>"¯$>ý®%>v¾Ómµ¾ºÿ&¾t¾ñÄ[¾+«¾îaø< r*>º’œ¼ÖÇ1¾”KÄ>yN¬¾†&ç=îg‘=´d1>-â½Ô<)ؾ1Ñp<¸16>!×>„>.1A=[2ä½™cf¾V˜Í>É¿¤¼ÉÆ6>o‡=Ê¡ä¼ýÀ2>PÞ…>f©‘¾5�ýe½U>´¸4Ë{¾F5k=Þ{S>K>UéÔ¾*Œ_>6ü~>yÂ>z”è¾ä(> ®U¾·7¸=ò¼¶¾ä›É¾�GŽ>´°=#¾|%ì>lW>çÉx=Fo‡¾ÜN¾Xç"=&SÝ>_Ÿ¹¾À?¾^tg½Rt ¾ì?ÏXO=«B¾ö©Ç<0a¾ÛÈn=!äµ½^õ>¸£�¾Þ‹¾ÉÚ<Û?ݽ%¹î=îÒ~½2Òô¼æ^4>?’¾a—ý=üy¾�F¾Íѽtz$¾au=ÁM¼˜õb¾$6ó½ Á©=�õ¼ð[ë=•É´½ ìO>7DÀ½]æ=×*h>}‹L¾ÀÃɽÇZ�ºœÞi¾Lh„¾âj¾î묻O =>n@¼ š—½_X½¾Âo=Ej„¾Ÿ»2¾Iq¥½PѤ= 2—½búþ=Ð¥–¾ŽÞ±½ê>¬>ýëê>èɺ=ÿ3À¼U%�¾7oð½ Р¾C¯¾üËT¼æYá½È£q¾ŽþI¿M.±>®оF‰%>ò·…»VŸ>>ý»o½qÀľ/-νïG0½nÔ>Ìþ�>É-a=;Ú-¿£i¾½ñˆ>ãè=zfÙ=Ì I>U0ƒ¾„Oy¾¿A�¾UWþ¾FC½Cd=BWû½Ã!3=L ï½?b >ôç£>Æ`=2Q¾ÌÌÃ>nï<¾dë‚=R­>ÓÖ§¾E-×>¥+¾®Ï=‡þG½— ‰>q‡1»˾«ÈÚ½Ô”M¾Ô–T¾‘•¤¾&ùë=Õ±> hš½M§ >„{1¾t­¼=ëÎþ>)Ž=ùwœ> Î>ø¥>«mÖ¾„PW>&—:=}ê¾$æ9¾í?ô¼S=Ó‰>G7–»°0>G¼j¾¹-޾èw•=¾�=Ú¾uo•½e³½\À§¼”>o¾rŽ™>¢ŸÂ=îÐÀ>ðÓ=sQ>ÓKÚ½—³½Ù)>&v£>ÝNŠ>Ë1´;¼tž>¿ï²½m{M¾DL!>h7½Þ¿‚½pF–½AwÂ>û(¼½xþ9=aa>>*–ê½åˆŸ½t™>†‹€¾FÊ6>:°F¾Ý_R¾ú1Ç=Ø‘A¾õL¾¨Ñ-½á2༟ñú½ÝeÞ=Ñõ>çð >|‹¾©�;¾­œò=BD½pd»7µ=Σ†=Gnƽ™U'¾ç”¬<‰tͽ½ÅG¾(´¾©K½Í¶þ½ÈöL;'ɽÄ,¦½Q˜@¾Ð�>82�=‰ß¾„J¼Éç%¾ÔŽ}>˜Ûâ¼ßsT¾BA¤=;Vg>‡B<Ùë<}Üï¾Â0«=U‹Þ>*@�>X�½Ü3-¾Ó)9=˜÷Â=§ý½�Q}¹MV…½ÿ21>@#оM4ª¾€¾M)i>µ­Ú¾a‰Ÿ¶m9W=2ÙÏ=œH>e=Žüö¼'K¾Ìòž¾�V�½²Í½>³t>^fE>ÌIµ>§q>çð’¾Üíµ=/¯J¾®� ¾j5¾›±#>ž=u­1=ŠüD?µá½�! ?P$é=¾ËZ>8•<žÃ3> Ñ»=“–ê=¥ÔÌ»’Ð ¾ìæ¹¾•¼ÁVK¾å ½¨³»y ß½&™r½�.®=7/3ßÜ< oƒ>2Fý»±':= =ˆ>$^ä¾›�9¾ŠÒî=o™š>½DŸ½rsR>õ?a¾‰‰ß<Ë�>Ò j½x™¾´œ–>ŽŠ¬¾og×=kO¾â’Ö½²<]>û’¾–lß½üƒ&¼¢ÝF¾Jôz¼vq:½ç�¡>o:?¾^jS>[A¾ºôŸ>Ú y>"r¨>Õ¾x?¾ñ ä=ñ2L¾TŸ¾]¾„²¿^1>Žªþ½µ^¼ºÝ¨>½/—¾ÚÃJ<ч›¼?¦½*m°=Â#~¾S$ö;b—Î=jþ™>2h>˜­>®Cˆ<-pW>“0$>Ùuø½�TÙ=tî'>aDß¾:ƒå>˜ê¾9òB¾ÁV�¾ôr8>¯m>¦îÆ=$��=ñ�%>S×¾h­Ž>M�¾g�2>Ä«¬¼qFW>¯1&½¡GS<=ã=b¿¾ 䜺ÆŠ<ì‘>Z ‰=ñd=6Xæ½sjm>Np¿½Õ á=Ö£ »–¶’>Èn†¾¸…q=¦>˜…]>ÝX-¾êk޾šiP=L”{>fMn½}üœ< s >öRÎ<Õô£<ºÐâ¾}K’=ù ×>L¨¾ ]V¾ 'ç=‰Îd¾¸1'>ˆ�=T’>Åñ=xð¾àªa¾ØœÉ½ë™>'=‚¾ ¼’>d„¾´ª>»,ò=áØe¾JŠ7¾^éô=R¦«½ç!�>‰’9½<Žb=Q›0=?!•¾¯Yu>“´¾à5Œ½•Ý�>4kÔ=ä7ú:"j~½jâç½ðZª¼Waå=Ôí’½uò½Z�*=ð<û=äfN¾/€ ¾jPA¾1˜¾‚Ú?>xŸ¾†Ÿ¾TC=©½N�¾Ê<°¾:�ï>Ú`=>‡=V›À½8ÕY=Ò„‚=RÈ|=’mÅ=¸®ç½º|‹¼UK>ØN¾w¡i= À>—†¾ê…|½uR€¾î3e>ÂÙ>’Ò>Úˆ ¼"â�<F;>ÉŸ¥¾4"»6Ô;>¬×b>ö•�>JV)=ai1¾ÔÝr>�õK=eÀ£;ßa3¾M�‚>9 “={:=¼™S>‘¸>©œª¼è€”=¢U§¾DÖ<=Ú!»½®˜K<àö�¾H)§<Ü”<|Ât>&£s¾ågh¾†s½‘"=ˆ>Z’=ôô>‘?€õ?Ñû›>Â…‘½Ö–#>f¡ž¼:¥¾þ;=Í©>½k&i¾èl'½Í³Ã=Æ@>ù,´> ÿ¸½�EÙ>uff¾½W®½gK=Þ¦>‡Õ¼H’W<r7¾§B>“ =ô¾{ÿâ¾4†¾^I9º´’¾–_Ž>+­¾`Á:>ün>ò6,¾|ŠÕ=½Ý@>i!B>|½¦Ò¼h� >õ (>™P>S‚&=æ[•>UîQ>Ù= �¹=+Þ½3Kd>�µp½áú¿®A¾€é9>•fT>íê¾=¢™­½_è}dY½&ÝŠ>¹ø ½B´Q¾p�q>(ƒü=ˆA½á¼±½ ®>Ûk¼öؽ¢u‹>‚‘k¾9á²>* ->¼ν½ÍÝ>ªˆ"¾'FŒ½sv >“•¾s» =å;&¾¦0á¾D×C>Ùù=á>UYɼ³® ¾z6½¾0ÿü>ï뽓¸=]å_>‡Ø�½5öÆ>'« ¾¯x¥½v*ž¸š>øƒ�=Í ¦=íp3>;7—>¯T>ÈíÊ>ð<Ö½Œ>*$¾½}¶ô=I®x¾ZÀË=aýý°�½¾‹ü�>s œ<ÔkÑ>*¾™‹Õ=©ï:¾ /Ö>3Æ~¾ÿ¿I¾hçÙNa>�Ïç½9¶=üq/>±î„½z…¢>ß=³<85=û½¦Ló»¿•=¾†ù\¾V'�½U�¾ÅôW½Õj>ñ˜={o}>"Ê�>‚Œ¾Ã ѽƒõ¿¾–Z¾JÑL¾$×’;ÞŽ[>åç¤;LÓg¾µ7ä¾$Ñ>æ+>Ë%§¾þúß½œÜ¾¬ç-¾Åq�=w䓾‡¼€ôk¾z]ñ=æ=.á;Bq)>ãU½¼"¦�>W¿vŒP¼ª*�= ‡)>Î*ê¼ ýмܧà¼8½¿Áº½sèô½gï³¾VB˜<ÈSü2,ë½®ÝÑ=Ã#·>†@“>;’#>ý¿§Ãʽ ¾óEv= ¾âH¯½ 禼 Îš=¨‚½¸Y>�40=Èxu=àØ©=8?L= W>™‘…>j¾ò|å½øm">l�=7'É>†Å= –¾6®>xðÖ<)Û‰¾ì™‹>ª¹ð=ÊT>6Þ>¿Fͽ:yø¼]ÿJ¾ 2Ý=«»Š;W›=!$?9»‘¾FÀ¾¹HÐ>çøÂ>zÍÞ=»3 ¾¸ù¹>ì꽌ì3=X©½�¤V½N,F>k ‡¾÷²m¾2°¶¾¹s¥¾™Ä ½_:Ó=*ðW>òš2>Ó¾Ób¼¾Ö—>¾\¦�¾ö²É>‡d¾¸`U½:þ´¾–—'=r->Õ¶›½C²½ü,Z½+"->ॾ¾fî¼ÿ ³;Ô0‰<Ä÷*>×Û=Xø?<¾X¾Ì¾D='ËŸ=Î¥ ?Én'¿”.�¾I·š¾!7_=ò2¾Kß’=T�™½Z�»è_ò»¥“=*¥=Ï™A½ús¾ã¦>Ä…½Ò$î½u£¼¾®äc=0ѽ$ªI¾ñ”ì>tt">j¯$=�_F>3l6=°¹�<Ý–»9Òz½’κ=¯�;�v¸áµ¢½ãÈ–¾CÌ>vx1¾®¸>X;a>íý§½±{ü½Æ™¾üsò=hñ=ÁŠ´<€í™>`ç½GWé=7À]½ç!A>³a—¾¥ö ¾S? ½*tQ=¼ýÓ¾ 6 >aJq¾¿,<û!L=VEš>o =WGö½( ¾_^�¾§ÞP=iIQ¾ i:¼Óï¸=(N>)þ½Ùe€>]Ô„¼pH¾"÷½öGß½�J½Y[È=J9Û¼EË€¾Bɽf9²½ qÿ= Ü5¾•%>i%Ê=‚œ‚>P‘,<°ñоÑn¾¶® =K?Z¾®ì�¾˜>Fµ¾==CX¾¡àT¾PðC¾fýϼúhí½Ak³=Œ¾‚¾à]~<|�U>¯–‚>ƒô=,Ó…=ðëY¼��à½ò 1¾CŒƒ=�ôx¾Êö�=�½ê'Ñ=Ïêļ—'‹½OÃ=¾åŠé=I%¾R·@�÷1>cDc½wä >´Gì¼jP¼yó¾¡}Y½®µ¾öÛq> ~ç<¡ƒ=­Ä[>ÿ1Ô=g*O=G –<ê�,¾µY»<¡Mþ=z,ѽkÚ!¾p÷�<[A.=×lä=‘z8»�<~¼å x½"m-=ÄUнP»‹¾ø`W½#e€¾·r>R¤Å=þk€=‰-2>'-®>•æÿ¼6¿‰‹Ù»ÚB ¿8¯>~JÖ¾SÝ"¾é¤k¾N­>c}¾ug¾=Ksè½Ä|޾xÜ8=Ç;µ>Ì/¾»®<¼mL¸½oc}> ô6¾|÷-¼§§P>¼óv>¾t-¾Ž‡½õ!î=“Z9¾?*¡½â,ƒ½Êp¾NJ€¾¾9>ùµŒ¾A!X¾ö'Ÿ½ì–H>ض<¾��+?(K¾"Ö€¾y�’>æ>äÚG=†bº>=kÞ>E‡�=­¾©=ö×_=:'ú½Øð˜½ˆæ9¾Ön¾MÀ—½‘XE¾ýH\>¥®‘½<>8 >„S�¾W± ¾m3Œ=©¼*¾$M=¥åÙ¼P3Y¾¿Q3<Ç$�> ô`=s%Ÿ½ÎÒä¾·ˆ¾¾E’%>DQ5¾%Œ|»âñ™=ߨ=:ˆ½ ?Çíš¼dÄi¾ù<Î뺼ċ‰¼Ýÿ‚½êp4=¿c†=Å&¾ ²ª¾ën[½)›X½r�e¼ÔîK½È=£#R=@w™½™Ÿ¾k°•>Lz…½£ÔѼ¤kÍ;ç4Ë;¤à|½ÙÁ¾qÕ>HÚ=Bà½Ö—нñ½=@žµ>,ÌQ>\gI¾æÓµ¼ê5†½Á¶â<¿.Œ=NC«½H2='菉ÂG->™$½=ñ}®¾G9 Åݽª«½>è>å(Â>:3¿†ð–¼E…U¼h�Ù½3¤=0à=ŠN±>𑼂C8=±åž=úí>ŠpľÂZm>g=Ò$µ<>Ko¾¼™>$Õ½:}î¾ØÉ½ô‡C¾¹&H¾x!¹>Æ ¿¾�Þÿ='i¤>âZ/>"‹F½du ¾A°Ò<ƒ³‰>¾ˆ¾EL�>Q_U>±’¾«>/=ÁE>î÷ >µªB>·í=©è$>ªT>™ú>¾œ£â¾ïD侩 ˆ<¹z¾ÃÚ!>§þ>“Ñ7>#âë½">³S¿=ű½u‰ü< P/>"ëd½Í†8¾¸E¾àlW½™^¦»¥N>~À·½ç ¾u[t=é¼>0‘1½äè=- ]<1:¼öQt½›˜¾œÐ‡>Ízx½åµ=p ?â~´½îŠM½_"Z>c6ò½ØP >~;¼�î^>hT¾o©’>g>¹JŸ=ªÊa>ð™ý¼Mç¥=Á£¾ßûC½ÓôS=*có¼¨ >DÀ5>“1ƒ½œi�¾ λFøw½�5°=�bs=nC>ñù‚>ƒpg½ôÞB>¶û½dp ¾“¤•>@@Ó¼˜Æ=³Ü=Á¾þ•¿…³½2Þ¼ä©ë½éæc<‡ô£¾ ¿Œ½ŸÕ>ôŠ)¾#i ¿æ$‹½F©Ø¾¿µ½kF�½çU ¾[ d;@àö<‰�Œ¾�¬·¾¤Þ¬½ýˆ¦½|�D>6r½ÿþ‘>0#p=Œë�¾%�™=Pê-=>Q€¾œ=Ñ>Æ’X>¸èÜ Ô±¾þŠ™½3k6>"³O>®l½8Æ<„̾LLž>×S]½š£O=Žw=;æo'?’Tоvã?=œ Ì½âëÁ>ÄF½î,>GK¦½ÐC=R¦ž½R!°=Øv>yΛ¾«?b<à¥P¾fÒ8¾Xν¼ÿ>vͽô?Ù>»°G>kúݼJ—{»¨Ÿ÷=ü¨¾i¼¡½ê±Ž¾Ntö¾dõ$>+[½4•>¾Â«¾Àh; ß¾Ði'>/L±½*]D¼Ü.}¾Ge{½É¯>\Ã>rä,>¿!Ѿ•‚*¾ Ù>È{:>bä¾úv½,Íy=<y¾oqc¾Y¾[‹¹>K®ƒ=:Ù=xA¾žyY>™å·=” ¿E|Œ>iá>–Ió½gÑ™=�Ô>ô¾Ä=¿£G¾#Å<~‘¾œ)h¾ìút½­ž>¼9¨>·A¾~z¢¾?™»½„™£=šù7=Sí§¾Z~[…=6<6>"d”>áôU¾œ ó>Y1Y>Ã̾» Í=åõ1>Òõ=ÄÕì<Í)ö=\õ•>µ·€=Õô}¾V¼¾a¾vék=.ÁF½:‹>€»ê½9 Ë½×Â(�¢>ã4î½Zz¿S.¾\ÄJ¾ç­¾²Ó=êoè=äØc¾â‹ ¾}ø”>æ³›¾i½—¾Ï!3¾ô³½¡'¡¾k¢Í¾&�½"'i>¨Ž€¾)¾=½µ˜¾P¸k>O{ ½Û=—r>ï”<=îQ½tk–¾ŽÊ\=‹ðì=º´>9J›>½ÁŒ>¸¬›>RQ¾zàÙ½Eã=ëX¾„7º=“u¼@Ž>†‚.>ª8“º=¾Ìm?½�lYfL�=àáν¬«É=·V=þ²Œ>œ¬£<“K¾Ý°£¾ˆ¬9>Ç)½ I6>¹þY½1� >‹S8>é¦*>,³k¿X£½%”½Ž÷µ>*M‚>¤w9>QÌ«>±‘ ½=j‹¼kšs¾ó¤¿½.{‹>÷L�>ïd1>�P->Ÿi�>_½ë=@$ž<�ãð½¯Çõ¼vQ¼…Ñ>ˆyx>·ÀÜ=€Y½(ò~=LQ`¾0¸>=i4>ކ½¨(¾äÇÊ;f ¿¯«5¾™Ý¾š¨(¾V^4>ÑwÙ¼a>>­’¡>š;ÈòL¼4Ÿ�>‘ÎG¿4b›=º| ¾èôh¾•!¿ð[Üœ¾Y[™>ö@¼=Ëp1¾Ãµ¼QëÍ=Eþõ"¦>&°Ä=oŸ½.—ô½õ–÷=o-1¾>·Œ¼Æx™>º�¾ì=�ï>áQ ½_­Ä¼tN¾±êQ½6t•>.7z>ú½Èõ›=Ä1¢>dbþ>Ð3>.MP=ÝÛ ?C»=�Š.>&™=*ݾ{ÃV¾Û›¶½öa+¾C½ü=k—H¾Ã4->}q€½È‘>X}¸½DÚ¾9¾�f‚<ðòä¾óÙ>øë6¾4L̾@U„>Ä})¾!‘Ù½>éY½GÆ==Á;#> ù/=º ¾.Ú+>¶ ¾› é½íì•;þ#G=Cd/=ž“¬¾"9È="z(>/�’¾¢¹²¾á9Ú¼ó£×¾Ní®¾Š% >=à >[¯=½3{=š ]¾…úÕ>vqc¾«ãʾ÷S=�âÆ¼A¤½•æP>+ú?0¨ß»œpº½ržd¾v[¹¾Åµ¤¾§ ¡¾?È¢¼¥=v=SÔ½=.�M¾·¾5áþ=†ž>¸ ¿”Jž½÷¼Ô=*’νp•ê¾X2Ÿ>Ïuƒ¾›ü½Ï`¾ÅK�>8†½z�1¾®òÃ= &ü½ƒÙä½²É= =êÇ'¿2L½Èçy>‰8K<Áõ¾rü<½—‚†¾^x<Î%<îÅ>ŸÏ̼wŽQ<»X^½Z3™=Ñ�¾w£Ÿ½Y�>GT=ký‘>ÿí%¼äpÓ½u­¬>n`½_S˽j>[¾t>/½ý:U¾ä÷Ï=ë¦@=PV>æ*ì<ÜÕ¢>÷‰›9€d=<ôD¾Úü†=«œ;=¢›ë¼ ˆ¾'<½«×»;zŠ>ìmA;[ ø¼Þ͹½wán=݉’=Ì�½ÓÔY>ÆrŸÓí= 3;½Ð»t>f±½¹†”¾'ø¼m7)¾'d>¼t¦w¾$ʱ¾LÚ>Û ƒ¾eŸ_¼Ä;“¾˜ÅS¾…=j_�>8Ú±=oe‡>)9Õ<Ú¾[ûž½cÝ>".+¾»„½Y‚f>>Ìð»ÇÞy=TN¾0Û¾‡ÜŸ¾RQñ=wU9>“­=¾ >$YW>6þ‹¼×ì–¾²ŸŸ=EÆ]¾uÁ?í‘ ¾šùi>™^­=ŽnV>ãöè½=Y�¾�S”½9.½=ªÛ¥>ge¬>øŠ>¬þ†>?Ma>ôL= Ü3=;¯ö¼É2¾Fáf>À£½=�¸Š¼ê@½Xƒ½€¤ù=2¡O½ê ð½ixÞ;’Ë/?2>‰½Î¦(¾Í¥=› ¿ÇŽ\½@¨Å½N¿cÔŽ¾My.¾uéj¾òp–>'ÂÝ=Xù¾(„=ÕÒ>¼¡=>½¬' ¾j=ü²p>RAš¾?Ð?r€#=-“B¾ ^«½Ò3¤½†”¾Ä2†=Úõr¾›"«½}Q¾JŒ½…`®¾¹ƒýºáÆ\¾"Á4¾3ç$<¯íH>X8¿H–>7ë>¾•�>òT=æÅ�>åÌ?Ò%=©.æ;#‰=<ëì¾�m¾’€à=¾u\¾\Èj½stÅ<]Ï >�.†¾³÷Œ= w’½“޾nľ.á¤=ïæk¾Æ¦ù½ó ¾ –s=Za;�ò½®’½ñ >Æ,º¾È_¾íF=²Ì™½Vþ(>ëP�=/�o=½t'¾V?3¾Â­D>�ˆ¾¼¥²¾ÊÒ·=(¨Î¾0D‰¾3ݰ¾M¦>j¢R>Â"^».`Â=s…˜¾Žó>ýú=–ÃŒ¾éî°>–¹"=>Ih;1H%¾Ý€€>ò¡>'?…=ry”½ p¿@lö¾\¢À¾Nãj=ÇÔ,<“ni=ð·M¾9x˜½©¨é= —½2—½rʾL „>M¦¾ `¾,>>Ihª½Rw*>®Rʾ¿;#?e»�=W¹=¸à¼–¼’ßm¾lÍOºÀŠ3½ u®¾ÿ- ¾Oƒ>r£ >n‘6¾¨�ú½^ ~½àü8>¿�~¼8™ ?àÙ¢¼Ñ o¾íC ½¸j4>_ã½ëö„½Ü{ ¾WW³>|jè=,Ì¥¾‹X<à¢ã½”És>´2²:Ev>à …¾X]½‹8®½-‘3½ò–b>t/¾X¼w>bˆÎ¾…ý†Hß=Þq$>9=ø=Þ–±<"‹g¾˜³:¼ðä/>X?Û½?¦{¼Æ=ê‹ä=ù•>'¨¾ ˜±¾üßd¾VÜ*¾¾Ï½Ã™…¼pFŽ=-:>3Û®>|þ“>B}>ËB>ªóѾ[%>ú’å¾ëqÝ½Ö ˆ=ë{«¾�(=´rz¾kËǾì~>_èð¾6 `½÷u*>´å̾Ûó>é†>ÈR?¼Þ6S>NKµ<z¿ÑvÝ=qM^>ôŽ0¾Õá½ø“¹>t·½[£¼ÌÕ½ ¯ó½Eå´=x‘²=Èü=hZ^>ë­M=BÁ½Â¿˜>δ<÷z¾Ú¶î½L2=Y¦¾"Ï"6ÔÎ=<ß=gø^½–W¾J˜ã=·:=É�U½Ùn·½Î¾;¾ÊÙ–½Óit>—ý=»ÃH¾Ý?>Î><0о¶ù>$É꽯対Ÿn÷>ø>û¶º½WGI¾“^ü=35¦<£<7<ͬ¼·R�¾V½NMy>‘á¼²˜‰>ÈÃ=¾ªž½‡Ã`¾¬öƒ½&×9>™ÆÎ<±£="}ܽ}m¾&ï­¾ÿSS¼’6ø=Rù½ÔºU>åh>gô>ªh§½�#«½8\¿X�d=ñ‹>þNG>œsì½Ó뤽jâ—¼[šè=%£h½ëˆÁ½W*«¾nf>U>†¸/¾Dúo>6¥þ;¿>1ª'

–aâ½^tÆw¼=H๽ R¾ê>õH“½R¤�¾ö Þ=6¬>œI@> ƒæ»*¶¾+Å´½Â¶¼+¤º´ày>Uð½>˪½Eï´>Ïw>sľд%>Œ5>^ra¾Å§ì½s½L< º»Dóq>–Ÿ¼¾öw7¾oi¶¾­p�>?„z>ôFɽ“zc=Ü�†>4õ�>¬R–¾Í¾Ž¥z½?Œ�>¡$§¾ó¡j½—™C¾”î7¼B„´;ð?j ò>[Òx¾“º ¾a{š>u¾ß½�çƒ>x=ä½ì>A¨š¼øZß=��=a�=:=>=jÎ;Aƒ‘<ak=wD>Ò¼=>3¾³ X¾ µ½íb¾!¿�½Ž-ò½}ê¾Ò™U>óA=?i9>úà…¾oO4>ùHð>¿Åо¢ê¸¾"¥\="ð<7ÕØ= 1†3©í¾ºÓ¤>¬G)¾åŠ¿>õ>¬=‘ŽÃ½�K•>솽éc½¾°5>Æ�>†½#>«»„<Ì„ž>¡âü½¼^J¼R}%<‹e?-¾:¤¾E´Ë¾3¹>}µf¾_¼ ¾ w?ÜTO½Ìk‹=¿¶´¾Ù‡Î= KN¾�b=RÛÕ½rLµ>6é#¾…¼>Ò\Î>†X=•—È»gOÃ>†9h>Ùaº=äA>Gi>‡ ¿½*ä†=Q®|¾Ÿµ>eß­¾v¾›=´�ù> ?`Ø¿æ°=wµü=¼ÖI¾lã¾£ù¼¾Ð}=£Ç¬rÑü>n<×;{?È>ÆÈ¾$"¨>¾zœ¾À¾o¾ ˆ >¦ÊOg>ÂÁ:=rÛ÷½^ý¢¾C° >Ô0>žë¶¾»1>´Ëо˜<‹=GyH»5‡¼æl¾U>¿¯æ=‰V}>ò¿ä=þ’“¾ƒˆ•¼F®a¾5pD¾¼”ý=„² >œ�³>ý<�>‰’ß=™¼³œD¾,;¿ÍS\¾x˜ª>AZœ¾É§¾éä�=H'>¿ø[>¾µš<o”¾øÜ¼½0üO¾40½â C¾.±¹>ëƒ*>Ò®P½�L >A83¼M">�Af>U•O¾•ýÍ<̇¾|Œhºø¹ã>q<á¼x>�nª½n½œ*6¾¾/q>E—X½ÄÞ?QÙQ=I�>ð£¾â÷p½MŽ—¾X,¾YľâKê=Ⱦ…ëܾý±ˆ½CY=ã b=Åa.>û–Z¼ìü¸=y^Ã>hjû=0W÷½<š>qÔ­¾¥‰f¾¸µ¨>w×¾’àæ½‰m=÷¹=¦Å¾/[?€ìv¾žy™=︩<¤‘‡¾ïk¿¼a¾ÇL½!‚¾F•뽉>ª¾:Wþ¼�‰ ¾ânϾÉÞ½ïT >nN0½îFɽ+òe½éR‹¾øg6=‰ZF½Ü”•=¥B>ÅJà=øS>VUg¾cð¾šd+=Ô$>¾¶“%=‘¾g¼sß >‘®¦==Pö=¡ˆC¾ ¶®>2ö¾§ì$¼]å¦>V³e¾p0`¼åÇ>W1?Âä®>¾V±¦>À“²¾±é¼Ð3ø½95¾)í3<¸ï >[m]¾ÍdÞ¾FªØ=5ó>DŽY½ ¶»ËŽ>o‘…;ÇŠœ=6?ì=”hº['ý=Ú¯s¼°XÀ>,¯Œ=ýŽ>­0¾ÊB =4�K>— ó>ã}w<&ƒ¾ 17¾W·5¾ ø¢=³œE½\“ñ½J¿Ê½ÍxH>ñb#=p¨îu·%>™Æè½8Û½³&ƾ:dí>´>ÖÉf¾H•>’f¼½Uš´=«ÉÙ>Ô8!¾Ó¾>ù�=ŸÝ'>ká¾mæh¾Ë]G>'«=E•€¾8Ž}½‰=¾ô²ö½Ë›Š¾pøé½5ƒ>xf<¾‘‰¾ ÷>�m³=>¹™¾�Ì>yc²>x4>X$¾øñ:½ÔÀß½×¢ <éh{½ñŸ ŒAõ=wI>R>«¯7> –¾.Ê ¾¿¥<Æi¾ á ='Ð>JŽ‹>˜~½&‚#½çü+¾wÛ¾XÖ—<]Ù¤¼›áQ<¯«'>¬p<2wt>UAA¾¶é¨=s 2>uf¾®{#>—`”¾&{¾€Ö>Ëc}>u~õ=l”½6g,¾æs—>·>=²2º¼-;¾-œ©=}óϾÂF)¾†—ƒ=û+¿¾!½¾üv=÷ù=n“;=2$¸=‹=¥·©>†6>6}º¾1�¾C�¾ÙϾŽA7¾*~>‚%6>=3½5ÿÓ=HÈ„½À¹½½Å¾Ú õ½Q… >„Ð’½5cÕ¾ÍF>ËK~¾½Ô½%3:>d_¥»I">+оOB¾43¾Yù†<ù؈¾]3>ˆ h>\@Ƚo*>ä-J=(’N>i›=XsܽË=‡êy½_>¼}*¾=£¶=j˜/½®È2>\ä=ïd¾§àI¾$áÕ=Êyè<ƒv{¾†¶<¾$܃<šî�>6½B¾ø:¾tÞ4>:–ù=�̉>@Z>ÅÍŽ½Ïéè>D*]=¯²í=µn=k/ˆ¾¿5E¾ñ°¢½YZ×=9¥¼k¶”=Ò�>™´A¾2\?ýë½vI#>.A¾¡:¾¾òå�¾˜j–=á >Œ=¶¾›Ž=Oq=‘+›¾Qah¾FŽB>Åé½èP>Ÿf¾ó§a¾»ó$½¯¹>Ú¤>©~ë½¹öÕ½¹˜h>>3“=Lž½£+(>HÝÅ¾é ‰=ÿ¿Ð½P‚¾©ž¾:÷<êrr>éâ=IÏD>MŽ7½SœÞ> V€¾,×½!¢0>ë{€=³±Û¼8ð>±Œ¼Hžì=¼5i¾‡»×½?_¾‚Ó2¾²x„=:>_Äa½›eÃ>ÖÚ—½¢0¾? X>V„>Râœ;"¬è=Hü;<“‡½ù7¾S–­=^+¡¨@¾�í?…Þ@½�[½ÚðV¼1µ8= â¨=ÅŽ>¡+f>}Žˆ¾v!¾ú�8>]s�¾I»¾¦¤½`}½Ò’¾id¢<:¿F>_Âù½!}&=çG ¾ÐJ|¾Ú@¼¾æ9>Æ;f>ÿÚø¹[¯½ðѽ…;>M€H¾x³>®“½Úû >WkŸ½=�À>¢S?×*[>åé.¾ 0¾š.=ìÕÿ<#È}½ÛïF¾«¼ƒ¾¾¼N=L%¾æ—¾>àw<¾'œ;‡’Š™�…¾'jv¾•Ÿ¯<[áݽïÿë=&i=7ñ¾°K>½0…>Ž©õ;ªÍ‰>í«²½¤ç> ÷H>l%t>ÓŸ�¾œ¾är>=ßÿ[¼ñÌû½ï¾˜<�~ú>­(¿½4½·~7¾Rô¾„«Å=yó»–Ž'=Ï�è¼j��½Lh°¾îç»; P¼Õwi½¡Fß<)Ñ”¾üB >¡Ò‘½ÍWƒ¾OS̽=Ÿ=L¿š ¾ß:ó;8˜>­9½ÌŠ>�„¾~ôË=nDø>®ù’¾ €>73Ê=Œ@>O 7½e—½¢…¾ë˜ý¼käè¾½´V=óò™=�ì8>Ð;:¸>yõ=’ÿ…½fÉýÔð¼c…]¾òQÝ=Ø g>/ª¾=‚>Õm¾ƒüw>ßÕ=�2˜>yû=h‡=äà?ídó½?oF={e¾šüä¼z>R>iG$½ëz>½bã¾¢Œ<=ü¾>0@«=…»¾`=¤õ >TÍÚ½ý'Á½ˆ–C¾÷IÓ½wE�¾sžš¾°Îʽ9ƒ°=ôÑS;®Ø>:‚=ÚBK>@È>´HÝ>ɲP½\ÜØ=�ï8¡½ È>~ÿt½!áh½¯·Ü=¢>™AN>ÿé—½³�¤=zê=i Ò»qà«=s`=½ø…­>T=h>F==ʶÓ<:½q¾¯)•;Ðãb=p™>aÂ¥;Ñ=©¼à�Å=ÄØêM'•@¤½uÜ>ùXt=<“ï;™.—½ &'¾yŸ4¾ÚŒ;½S!Ô½ †>Ö(7>ƒÊ>ÊŠx¾§A޼>Ò½÷5¾ Ew>˜c/=2?>“wƒ>Öæ&¼A…õ=@ö½Ïœ½¼[ >B·>3¿¾�›©½½5<¾>Zý=¬ê»¾›`³½Æ3„<;Ç¿t§>/íÚ¼®Õb>sÉὋ…¾ˆZ½êš€¼Ì¬ã½Y¨>*˾ׯw¾ÿºCûó=�Ç'>úþ¿2@æ½—YÓ½¹Qñ¼ ó¾×õƒ>Ô ’>Ÿ‘y¾��¯eµ�>52ƒ¼‚Ÿ>¨™2>� ¾QG>Fª�¾xñ/«Ï>ÇiS¼í½€h>ö,¾Ø½{ÀH=Ê>Ÿ¾Sm¾4#e½ ôÞ>õx`>“ ¼ÚÙœ½vÿ/>¥Òɾ@DV¼ô?I>'SÑ<'÷ð½Sdž¾Öq£=°a>¼Ún>õÙ‹>z™½ëŒÓ=CÚ&>V¥>]|,<$^ò»ý£·:7h«>ö�n¾ÇÑ…¾ ü;>k¶3½N‚)±íc>D) >Wb>2A–>O4ž<`ï°>ÅP‹½éŸö½þ]q¾ý,H=[ñ½HC¾Ö‚½ŽZÙ=ÃKŽ>,éa½¼,"½op—½y¡(>lR ¾jgô=É㣼”²½ªq¼=×)�>@Ý>vð¾>~z¾F…w¾"/C¾Mòž¾¬Œw¾Ì~ ¾ Ôf¾Î¹âÖ!>ZªÐ=¢IŒÙöí½O`¾ó-޾&Ð>¥JP>�be¾5MŒ=~æ@¾:º¨½+�ÿ>Ck=oƽ×z¾÷yݽÁé¾05»½pÚn¾ ø.¾Õ�ö<|­><¥�½Ö*нКZ=K>AK>Òæ½ŽúÕ¾™¡þ=&ŒÁ¾ / =E¼=0–T>6þn¾·Å­=r¿Ž=dþ¼¼Y_¢>Ë89>ÌTê»)§>¡_–½ž&Ø>*+�»¦ex>‘gß<¢ A¾B=œe¾�Ú¾œ®>Ò’å=>Á)>´‘l½ã^b>/:¾“3Í>°ÄÔ½ ‚š¾ÜÔ£> <+¾5š>%þÓ<7ëļ¾® =žÈ">UƒH>ÖYì¾}ÙܾW>¶÷†>¶�¾‚(Q¾U"?¾~½½q�->ÈÝ>× >ÕBÿ>ê¯>N¾§>Ãd†>ez9¾BåÁ¾Aÿê¼C{�¾w,Ä>…þ—<³*>êEå=‰Hú½j8«¼#%3¾s‚Ò¾;mC>ÒJ>Š«T¾x&8¾ïŠb>$ƒ€¼´¾½Á#Xåg¾@ò=иê>µÌŠ>A· >û ¾Ô >ý½XŸ\:Wˆñ=‹ï¡;ÒÍͽÇY¨¾Ùyh¾Eœ ½’·œ½$S¾·\ ¾!1(¾ é¼X%`¾-›i¾N<�¾Á¤m='…;” ª;ññƒ>,=wl÷½÷-m=ëœ=ð<Š]�½‡Û€½èWí½‚¶¡½: Խݔ½�JP¾N•?>½¢¾ZÓ<ÔkÉ=Ð&D>?*h>Ï�M>Ç$�>:Ù >QÅ<>/½�¾GWs>)„�=Un•¾—Û}½Òió¾Ô6>Kê=Ómš¾rå½Zþß½øúA>”î$¾²ƒ?ÁÚ¾vYF½;ê=»¬½Mò‡½£‘½�N>µ•Ï=q´ > ñn>3럽 ½�½—ÇŽ½ÏîÊ>x£=Ä™Z¾åÁî¾ÄÔ�>M0¾ÊZ%¾†_=œ#¯½ë)§=´�å=hJˆ½�Ÿ¾+ˆB½<“>vmý=‹9°>7¦4>Öøš¾2nù¼Ï5›¾ã¢¦¾ qνâŽì=£�v¾÷†Ä½¤$Â>ðŽæ¼‡ >Ææp¾O?¾ŽTI¾›ÃÚ=½šˆ>³<‚¾&¢íñ z=„ýÁ>%¥â½•*y=˜‰¾aÄá¾{,¾n‘¾N—>iÔ±¾3ˆ¾Ka>ª†>¼}¾ß½õ?É/L>c"Œ¾ o};µª ¾ø,A¾²îN?ù¦¾Ø’k=Ðh£>­*°¼¥nn>0 :>5…¬»Þ}’ʼn;pÝ–½;ß>Ç:E½æÔ=!y�>ÇÅ=Ù¯å¼�]½9¾¬GŒ½?ê¤=X•;>–j<ë ž>E”›>—­¤>7F>±.’½Ìk°¼‚¼Þ ¾ç:‘ú=9H¾úz�=›X¢=y¤÷½>‹ƒ>Õ £=íió=‚"h¾; 1>I«w>nP•< Ñ€=ÁT>%‰â¾,rM¼hc?½‰õ½ýQ¾20á=ÄóÝ=®ñ¸=-ˆ¾%6¾¸1¾¾ëž=ã.>‚#=œPo¾çË‚>ÏN8>[–[>p¥½8N»:G] ¾Kõm¾»¿Ï=ÂEO¾q>뼬Q¾¿§”¾qX¼½ÆÞ=yM�¼Õy);�c¥=vŽ>£>KU>ùd¾˜¡2¾êU%¾@Wx<Æ €>±¾1=ºÎ;½½‹>% ,>nËf>•ï'¾¹@¹½pÎ>ÞRè½pÆ2¾Á�S>ê�½Ÿh=\‹ <ú²¾L¼%¾”ˆ¾øœI½XN>@i½$?yù$¿­Íx¼p =€ýã=-{==íÃ=U¥‚>½ËŸ½U`m>^ä>¿Ë´>f¤> Ë]¾œ+ú½oQ¦½ª½è=¬¡= ,6=i >N¦±¾N…>kr‰½xJ ¾y6Z=S¶>~™„¾laZ¾*œ¾é‹‰½”W¾¹¹¼ê¤§=W¨G>~,{»÷b¾eÜ‘½íú†¾\ÜX¾3ž½ÇM£>;³ç<šy¾ŸÙc½×r¾;H‹<Œš?MP‚½Úç3>C‘t¾Ç;>ܸ’= Íм] ¾@öß>u´o½x£D¾á)¡>Íþ‚>(m̾>ÏŒ¶:ßV¾M©®<ê¦2¾$ñ½ À=ª¥ê=˜³¶½)_³»T"Z¾‡É�¾‰àÀ¼cX¹½¨¹Û="¼ÿŒ:Ÿ�>½²$¾u =¥Òå2ú¼Z× <@/K¾ û½=vPü= I½¥�¨¾ekD>ªci¾‰/F>|ø=Xl>×]Ø=_ â=ªþØ;E!Q½�˜½„G¾çÒI>´]$½ZL•½ã>M¾:ãî¾An½…†«=Ý?IòŒ=ô¾¤¾ªJ޾ïÆ¾"®Ç¾çÄî=“ñ)¾¬ À¼Tݸ½9Í®¾> A=ˆ–>o>©”C½&Q?p�†=° ·>½ ½·‰ò<6¾~@5¾]/x½É+!¿Ëº­ >_xÿ¼­AÃ=Vo,¾ðÀ¾KäU¼y6!>LJ¼¼z¾œš!½·®ž»ì’¾OáU=£?€„>b(ù½%D/¾ði ¾ãt>zÐÒ½}¶»sÒÛ<$³ ½ï5X=ÆÅ ¼§?>Ì==f©,>ûž§=Å�=šŸˆ>®{´½¬JE>ü²>KYo¾,,…<)W[=¿Õ >HÎL½S^Y=6>Ž‚ƒ>'»¨¾Ü™1¾û¿Ù½ŠÑ ¾ÄÁ½°«; ƒ¾ÿÿ =õz?âÄY½£Ä\¾}4«=Ÿ?ô=ÂíD¾Uçú¼èˆØ¼vm½¸Ã‘¼Ds~½†&�¾@¸:>½Ô›>Ô´=Iõ¾­N>Õ/E=Xu—>V ÷=O;>ÒŽ‡¾ ,S>R¤¾÷Ë ¾ržB¾# ?âÒ}>òÎè½”3="`ó½ùÇ~=ˆˆ>R¢½ž¾4~>£y÷<ÒÀæ½ ÃÔ½=&Ú=Û+¾�T­>óè >Lm�½@…¾ƒÈ"¼‰оŒîK¾Þކ¾»~¾SÍb½PÞj;à=#꽆ÎD>°·0?j>\½*¾ „B¾|ùݼ0Š#½¿G½ûÈ>_%?½™è¾Úý?>¸’¦½{ß}>ψ¾û»Õ½‹Æ>Mé½=ëû=’ ¿y˜9>A§[=„ò?½ù\Ä=*õG>`[¾�±¾÷“ž>Ы=Ñò˜>É4x=`1¾ÜA¾Ôb¾3^ü=¼|¾n³¼Âù’>S×¾ZôL>8–l½e‰ ½œï5>Ptò½s8R¾5=ønj¾xW<¾W•¼}î¨=ñŪ>Ë ‚<ƒ8¾>N½$]=:'¾m-´øò½“8ª>ÐTÛ¼Ë ¾?ï¾VÈ'†?¡ ó»ùaÒ= €€>Íß6=ïÓ¾m|¬=Aiß<Ýò=ƒ‡q¾¿<;Ï^轈÷è=o%= �=7a>ìÚH¾'!¾ ®¾½Õ>ž¾CF½.?;O:V= {÷=†–½M¯=MÙÎ<ìï˜=!#³¼åf ?ÄÇž½TçM>¾” ¾T¿­½-1¾(rR½.—±¾mI¯=Ä”½z6>”Ùm<¥�ƒ¾½#{¾,£»¼}´<Ég\¾ü‚2½,°<>H§½lÚ>;nß=¦ç§½JÁ¾´•�¾‘ýÔ>5xê><è=Z¼j½×îÖ¾¹ô¿+M†¾õ2 =“/‚<©e½=8Zk½”F¤¾¢Ý?>¼ÌØ= �>"~“>Ǩé=¾L÷g»JR¾9ð*¾ó˜¾¯²¼,ˆJ>¸½BUò=!/6=ÆEç½�4¼tŸˆ¾°ñ›>*!¶>´<Ý8<È0�½òÄÞ½ ,=û½^Þa>uÁ>¹™ >�÷�¾H«=¾ÂW¾_à×=aF�¾ŒM¼ pW>nü=¤Rv¾v|¾®(>fЦ=â�w¼fva<­4 ½ÏÎ0>I‰¾oE8½>D5¶¾g.P>ã1 =àÕ>Gñ=¨Í>>%/Ü:�–{>Õ@@;ñà½"€Z½&~F=×­o¾v ¾½’�ï=Êý¼—„>Q?Ÿ= 1¾…¥.=‘Vô== [¾{•µ>Æó›½Šä=ˆGË>’›®¾¥UȾ‹’>ðßñ>åd>ç)¾«Âg¾¢Õ*>&J>a$>£ô ?j‘F¾àáª>ïì ¾ôÂõ½n˾}‡[>ùŸ–>šsp¼Ç¿>ò]‰¾©¾’)=ãO>ûd‘¾‚<±>ºCÚ›d>1Ÿ�=ˉ‚¾I¾{hÿ<»>Ö½®ÿj¾jå¾³ Ö¾¯´á½ ä<ïm>%V ¾ü I>éð>ã¥�½I„>>=»°=¾%¡y>MIz¾nðõ=ŸØ½=‰ùx¾cä•>>ð²¾îˆ6>NÁÁ¾ÜF¾"О=�Áñ>þØw=?ô;¾6!¾4º<Ö„·¼ávc>°¸”>iÌ÷½éD¾êë>ÝŠò=ÝŠ> oÀ½1§¾·g޽çâ¾ödá=OD¾ËD =ƒI?ö¸¾äHª=¹Íé½"ëT¾²,œ½P„=F �½»©·¾g• ¾×±t=§l½æ}z=õ3>Nh«=˜@,¾à©/>i>Ÿ½ ®í=qq`:�Ð�¾‹¢…;\¾!á ¾ÛýK¾·Iú½EÑ%=H 4>§Ó ¾‰¤<>T¬+¾DÕç¾åÑ=èÄ]>åO¡½= È>t9ͼ¾Êp¾]õã=>î{¾€Cð¾Ð=Õ=Ô‡£=Ap?σ⽿@>ªüñ½Cˆ©=qi>¥ñC¾NœÜ>Xr¾ß¯º½äx¾/ Ò¾Æ,½¼wlò½£¤æ=ÖÒ›½¹c>¾#7=½«Ï>�§$¾�ò2¾¤)?‚w§=ŠÅ`½4âç¾j„.>Mj¾s�ç>„Íì¾2í½/£½‚ƒ?>‰*­¸êž<¾³º¾#¹ý»-›D>ú‹Û=êZ¸½ÎÄj<‡½h=ÈE >TBö¾˜û3¾õÃÝ>¥¿‘>S"-=¿xнH|î¾½×ܾïvõ¾#l=C{>lõ`=’qè;…­C¾2½‚= ŠN¾×û=BLL½$´`>¡4>0">¢ÐT¾{þ¥¾†u¥¾äáæ¾2 ->€ÿѾpf=r!™=ï-f=?Ì�½½’¾¥óË>ùÏ>C ¼ R‡>¬‰%>¦j<¯ßt>š2|¾ÈÚU½Ë-a>Äs>¿Ãü²ã'¾�å~>’@<]§*¾PNÒ>þÉP¾M¨¼÷ �>ä¥P>¢Õƒ=l­¥¼Bž¾`gœ¾nnZ>õŠó; z½ë–¢½„5a ¾Ð/r¾y#°=N«Ì¾f;¥†=B¦=½‹f{=»´v¾‰èÝ>(©l<"þø=°‡^=/]¨½é=Ü=`“=Òƒ?Ì�8¾ƒ¿S¾<º=Ôkþ=Y¾œ¾ßš ¾Åµ½�¼Ï½rÑ9¾ãƒ>»ê ?U$=Óþ>)ð’¾{Vª¾ >º'=ò;Œ>i_ß=—;=4“ñ>n¤™½; ¾½Þö¾S ½à'>Æ8H=âA‘¾¢O�=éX�¾©]¾>;Y¾…ø"=»õL¾Kµ@>>ûU¾ Ö=Úü€¾®d-¿U!ø¾ûæ0>€½=õŽ;>A^D>Q^“=+þ=Ö˜ë¾QtD¾©rÅ>¶ q>v\’>ÉZ;›©D=,]×>Mªé=!UE=ø+¾¦ýi½¶¹Ý¾+ê=¼îÈ=BíR¾‚²?=°¾«�¾!�¾9ï=+ý4¾:4½åK«=Øn�¾Aj©>!¾„Žé=çžõ>ßf?/h¢¼e”Ö¾TÈ=f`þ#ô€¾N‘>1Pà=, �>Û˜½Ëˆ½’À|=V‘ˆ>褾k”½í…½Fñ¾‚†¯=l½p½ÇѼ` >¦5“¾³f¾9|;{ê´¾ïï×½ZIl>¹É>C5G¾=P¾Aú*>Þ•¾Oîï=–ì ¾æ¥Ý<¨W,?.¾@³=>È¥K>†,[¾Q#¾î2.>ØC‡>0ŒÈ¾ÃÞ[>Øk½w�½½+�J=€ØŸ=–‡�>ßÛ˜>»X=õ°¾³ƒÁ=K×±¾6– ½�Úù>­Ž¾°ß¶¾z7‚=SNº=¯Œ¡>+þ5¼Ä©?Í\¾úo¿ºXÞ½äïv¾â±±½Í,´¼3º©>Jþ·<Ê›€>; ¾Šqî½=;m¾Ä† =Ó>pŸ—>%c¾ñg>€ú9>'¡½›�½¶ˆ ¾—$×>°yŒ½‘“Ú='¶¾Ÿ®'¾Væè¼ÚjÊ=ðý½=h g¼œÚW½ªi†< ÷¾¡ ÷;x˾?ù½¹8¾\޽ê½¾˜ò)¾[yÈ>°8á»ÑË¿á;Ǽ��\¾ßÒÝ=Ir²½ø¼%=�F�=wlR=ï?½�'Œ½¸òq¾×Ž+¾—Ä=#몾Ǹ\¾=)>oÓ+¾¤ˆ=uê>®‚ͽ/™9>Fð­>‰äŒ<œæÈ¾J×Í=ÂJ?¼í;<Ô^¶¼(ì½=·”=Î)­½Z3g>Ýß›=òÝ+><Ë_=!R>óÞ>!=àÂÒ=ZÁ0=.¥U=;x»<± Õ=¸}‘½~¾5>dþ�b¦¾ªA< ¤ì<�•'¾%²Ž¾Ê�š>\q=èÞ¿>£!«=’ZB¾^t2>k*>ӂɽAÄ1½`»Í=ð±9>†‡¬=Ù ç½4*¥>-=Õ>ðk¾y5Ç>9畾¤8>c˜D>]#>õc…=}›á¼üä¦>Ö¯¾>É]w¾A?’>\Ä$>úm=‹,/>³<]ó<ÈuÔ=Лô=:á>êë’¾‡�>ï\>3žò¼nÌI¾ö_>§T>ˆy¿‚‰ ¾%‚¾CC¾ÛB¹=-D>-kA½féV=ÇÑO¾H…L¾H ¾?tO=Å2I½­˜}=ê�¥>!MŒ>^3�¾sï‘>�„¾ iº½ Ì;q;>ª[�¼m¸ ¾¶¿�=N¼¾芾îû=Õ›¸½±œ­¾þj=Ø™;) p½¹XѾÔN•= )9àzt¼¨Ì™=ÿ“¾Ò¾‘RÛ=Í®U½ÒÒ¾¼'|¨½qY ¿ãr>…N>ŒPŒ=º—¼·œ=™±Ó½’!K¾U <üÞ¾@u>‡Øó½ÊÍ�=%Õ¹¾ì?…¾Å’ø=¾Wð">=)7½ðσ¾ôÕ=3îÞ½z|¬=W~�>\ #¾¾½H=�½è½¤œš¾ÄG@¼ž°é=i<=Íi<‰Ow¼U“%=³=ÜS>°X¿rïP>öŒð=–ðÍ>æ'*¾Ý¾>òD0½ø¨Ù=0p¼=wÔp=4c>ýB\¾n%€¾-+õ:Î:½· ™¾SŸ=x(>Ôë4>6à/>„U>÷ä¸;û½�>l¦"> :н;&d=Œq½}ê½ÒÔžv‰¬=—Cž½©·®>d‡½w¼v¾ô÷-ƒ#«<åº>íöã>\å¾ÚsO¾„3>�¯<›v½].¾E}Ã=l Ó¾¸5¾”gè½·¼¸=/®°½‘ŠG>·)«>µáB¾~^o¾~pt¾øä¸¼Eì>9KP>³û¾O댽*o€=mØé=2g½×aÈ=6ľEÞ6>–¶¸>V#½u-¾°`¾0 ¾—»V¾ÊÀ¾ÝkF¾”f†<éö ½—=Èq>Ó²†¾‹>$ŸŸ<%�>¦ƒ‘¾(ä;¾QA>t”½ì ­½Ù08½´ƒ¾Ö&€½ŒäM¾bÖŠ:°ŽÄ¾Ÿ±Î½91‹¾3ÝÖ½™�1½ƒv1>°t7¾yj°½œ½�éX½K}y½ùF’=ù'Î>ï" :!%­=‹´!½›4̼ÁpÇ=U¾};“>Õ˜'½ÀB½€_¾0ëH=âH>­õ½]yÇ=¸U»=†8¬¼É }=þt¤¾Ç³>(E‚>»`f¾¯è¤¾Ýé.=•Ù%>�&¾d0¦=¡øF¾ï4Z>ÔI¾¾èŸ¾M\¾ò�b¾žØ�=íDâ½ê[š=Ø6¾4¹†>i2½àT°=㛼òÙý=é?ˆ¾hU‚>¨–¾Õƾ0½ˆ>N·ž=-n¿¥•>M ú= ¾Fá^=£ë¤¾.W>ó7•¾›îy½ßÿ•>÷"È=j_½až¾¶Õ*½•šü½T½‚ ƒ>@𢾠ØT¾’ý·»³ó½§ì >’�$>?Ða>xlš>›l >Us¢=ÓˆE¾d\‘¾T†2¾Jÿ¾>eS=ÂEj>·¥Ò½þ"®=»m�¾ô|ä½Ú`á=戰½]S=2¿C¾e+>õ9¾Ñˆ¿ÿ q>S,<݉¾m—¼ï’Œ½'ñQ¾¸d«¾¿P{>[ëI=$Îw>ÒËþ=“Ƚºkž>æ+°¾píÑ=èAe<7X÷;rñ >ºp꾊¾G¼Øìé½Í¯‘½‰îˆ>Ÿ Ã;D¢>Ò8>)>½k ø¾Ö ¹§‘­½î€¾=Ú’¾Ïéó=¯ˆÑ¾- >-+�> û…¾¾�ã½9ah½k ¾ŽeW>ò½Ø—Õ=s"´=D§¾mŒÀ½×³þ<¸Ñ=ž3<fÒ½º’½’}Å=—î/¾a<¾Ñx?–ª9>‹=‡>?�¿CU½ =ìk½þ¦2¾¶¯p>wf9½�;¸=O}¾ Ø<¼Ø—½B6:½Óµ ¼Åô¯>Ùî>¾™‘>7%>�s ¾ÝÒ¾0;b>5”>Ù ´>£-I¾c!A¾wùë½vÈQ¾��>ր輂肽�m°=_oƽŽÂ>¾ÒL¸¾ë5½t}¾ÒÙ>¡>KBf>Hùó½Û�½Š @½Zä¾¾…åæ>Öóâ»Ú>7¾ó#‚=X47¾c2½íoǼ»о}F³=•Ö=ÚÛ>Õƒ>”‚¾&Y‚¾‘¥6¾qx=kÜ='5>®É>Óh¾¹Q¯½¥O>�LÚ;ßà<ë½ñBU>‰è•>ÃbW¼�ZÕ½B½¾ðyʽ»S­¾cÃ=×ô ?·z¾˜ßµ>£>ÌŠ$½„¸©<Ô>ï,>pi>˜Hß;èë =÷Ð¾Ž‡¾µr¢¾Áóc¾•½øi‹½¬¥æ¼ÛÞ >l†¾½KÓÍ=PëU=3V»¼©>¢#A>¥…Q¾Wò¿½tDN=>6:Z R=¡’¾ƒ½>�!&=jŽè½ju>ÖN®¾æ~Ñ=æ´½~:æ¾úº½û¼ ¿<_¼ÐƒÊ½ˆ©Å½ 8±=¸|°¾»Û½– ¾q„<áµP>a·=TÍ<>ÀѼ¢è>KŒ¾{€;>½ø�½G=;¿õ½EQ½× ¾!„˜>ó&á>6_C=`o;¾U°½?8ø<>é=¾=#C�8ª>Ýš¾¾=¤g¾\Ds¾v”>WQ^<ŠÈ=u'=Ð[ ¾Ò?f=œŠ>¾P>Â6>=½YŒ_¾ÇÅ.»ö—)<0©Ú=DÒ½^a?—–Á>«Š¾Ìú¨=×j ¾K’˜¾ùÇ=(´ø>N¯>-Ž>@Ÿ‹>laF¾ïJ“=Vªä½àœÅ>åçì==# ½q¾Xÿu¾ÎÜ3¾Ìô5>4_7># Ï=;hŸ¾Í�&>%’½Ç;¼î#>áa;¾­o<½X¬’>!Mm½0ðò½Á”¼½‹�>øOÍeꋽ?Ñ>’ô7¾x½�æ5½³>M½‹ÿ5½·~„¾úW–¾¡OÕ¾¶ q¾•U6½�Oö=ÐOÈ=æt~¾&U>ñ?ð=‚x‹>‡ôþƒíª¾ŽD<>ø8ß½®Ÿ=ŇŒ½ã›�½ [Ÿ¾¼)Ú¼KŸ"=“ÿ=Øzx¼Å޽å!ͽÌ>‚>W¤<¾e¨=ýÂ¥½Þ«À<ím‘=k4�=VŠN¾Hy¶½à#¼h)Û»øNS>ó}¿øÛH¾GÙÛ>P—>öä>”ሾ^úÛ½š¢½ð>“åÛ=å·¼O¼±=˜,è>Ä9²¾ÁD:½{¶Ñ½2ï=QØ\¾;ñ.=`…>“i¾Ðð¡½@ÃV¼à2þK™Î=J!£½>æR><1¢>(ˆ>âã¿r®f>’Ù.¾1†r¾ˆÓ¾óŽ >ùŒ½=™Tæ<8Ê›¼Ñ¾�‡>Døy>½Š¾’ü=À|a¾jù>›WA¾@vQ¾Ö(r¾:ãg¾…݇¾È~š¼ï|Ì=2G_¾7">Í*¼¹š>âkª¾± ½¦èš=Ó >ÖA˽г•=+õ]¾�\™¾€9•½hg¼=¢\r=ožY½o³ƒ>ˆ ¾š6¶<øiA>"Ò<ët„>!»¾¡îù¾º®½qKÈ<Ù ü=/è¯>›’»Û!½DØ ½¿ˆ¾Ð#M=« ?{ͽaS¾õ€,»èÜñ½>ÙM¾ÆI(¾�(º¼Änm=¿'¼¾*ë;.Ÿ ¾Ûe ½ôúÜ=ËXX¾!ؾ%×0=Ü!=[0=ÒAµ=+Y½>p¸C>)ýòf ¾sšX¾S¡<[YC>Ôý0½@ò¾±£µ=PïI>»å">š =¯ª�=Åói¾¤½ä=ÿ† ¾¯AÖ¼˜’ý½žñ]¾ÿ=½¾ÆBž=Ûá>4ò[¾?¨~>Jk¾uö¢=Ø|D>þÖ<¡w>þ±¥>�B:= «ç¾nh˽G8.>¡£½�Ÿ½òy�>7«ª=ý>£¥;>ø|½7–¿¾¢ q½P„«ºb.$>=é!¾¿;.>…2µ: à1»½®¼Ñ˜T>ÊO½Å@ï½ý‚˜¼°ýs­¢²ã%¾Ø=ÿº_>Y)¾£†½ž‘_>pñU>¦Z ½²œ%>)�\=‰#¾µñ™½þΚ½Œ+¾HP�>éÛ�¾¿ÉJV¾œå¨¾šÝ ¾ï¯>énÞ=4Ú{½á­°¾rd¶¾˜ì¾­°=®øÈ¾*ß?zu>|‚ä=l†›=ª¶�¾á ;>�¾„u˜>W™¾ü==Æ=–Ø>š»=; =WU¢½më½6µ>¤ÌÕ<ƒ™½¿0G¾v�Ú=ÄyL¾ñP‡¾ýµ£½Ë¬½_Ѫ¾&‰+¾…)¾óåÐ>Jݽ›S¹>'¾à +½3ã½õ€å½Ø?÷Z¼f>LYȾw”ð½þ М–\½]UJ<ä=ÊO™>+2{=ö�*=,t³½I=’=N¼Ê=µK>µLÅ>ˆ7¾Yrt=­ï�;Í[¾öK=b�½ÌHÖ¼•¨Ä= Ã=çôe¾Â6ë½cÍý½J佨y=”ç=Sv’=ŠT™=Ær=Ãâ>þŠÆ>7V»^Q̼¤Ñ=(‰½H/¾îË>ÄÆ>¶\¿8~Û½àÂ>¬hL>™´=p3:>c²(:4–¾?«>RŒI½ˆkE>C²£¼$†¾¥ \¾§zA¾»r‚<ÔÙ†=Þ7 >b´í`!g>àâþ=XøË= :–>R‹½–t.>µðª=Ö½–©½ÿø ?[Ò„¾Ôm,>¦Ï½G�>HÓ­=Vu|¾P£]=ñýô¾‡S�;=?f>¾ÝÍ<Ä¡#½2^˜=Uv*¼«'>ZŠì½QrU>J_L¼„„7>;T¾…¿<§¶¾ d¾•Ì ¿?­¼½ív1¾Y,O¾9ÿ½=Ì †¾o"*¾Û‚=à.ü=­¼Å¾lÙˆ>¢ß¹=<ý½ðÝ?=c¸�>v<½M#e>ÓB¾Íiô½~O>¸,+¾ù–< TC¾åâ¾½Xý<=�"˜¾5ýˆ¾E u>ž2e<;‰Ë=“¾ó>LF¾1L^>;¬<> Hݽ”—Ð<ܸ=“±¼>X™=r‰>³:¾å =Qf¾€¾R@=�Ô~¾»Á¾º2¿:–Ùè¾C¿á½TÛ'<#Âð="ag=È4ϽÉð�»jˆÐ¼{|¾$…½üºÇ½¨ÇÞ<ÎùW½Ä‹“=‘r>n*%>^Þœ<ÙýºX«G¾•-`<­jQ¼œáʽ‰nÿ<õ3>Ig�=G5è=0A1>ÅÿV;’b¿=´1³½†^¹<H@¾a¾Â¢¶¾Øª‹»8ò ¼È{U¾×{R>©Dj=ÈçD¾\>”Dé=ð%½W`Ð=ª~D>ëW>áHÒ=¨gÙ=�ï»–¢=>[=0d@>˜¯%¾¯—=ᇑ¼¸Bÿ=9ò<Àé¦<­‡=Š]ä<µ_…>ú¹@¾‚Ñ&¾€!=u™¼Ô9¿¾ôl‘=¥q>¨Jœ=ÇY,¾Vûë>ÍÞŽ>øùºš�˾h¦½:ýªš> ­Í>ê_¼> =£xœ¾�×ë=©Oٽ˱£¾<È�>0,q¼6«[¼¶>Ì�½å|ß½6 ¾÷^z=¿µà½ö¹…=×_¾ÍÄf½å›–=ŠáÒ½_b½8·o>ÌP½D™)¾þU;Î7¼މ>÷Of>½S“¾Ž >Éþ½ Ǿ�Wõ=³ò%=­}>[Y ¾r8¾[Ƚ[Íø½È€+>"G”>&2Á¼Õ«@>éËs=:<¿âü=ŠÃ<ã&¾�¥�>L ‹<î–”<ø�>7\¦=$±.>1î¾Å]­=’Tоø´ˆ>®q­½9| >h“%>ø.>ï #>a¨?êÍ>)¸”=6%T>:^÷½Œ—=hνwX>- >äèµ½Tê„>àß=|áG½¿‡æ½bl>¬ã»s>ô££½/lP>j“=¾œÃa=‡{,=O$>‡*¾�)R>»†¾uϼ=i?s¾¬¾ä”¡=bñl<-8¾½Cà½Ô|d¾çÎ×¾®Ù|½I¿=^¡R<0v¥=h!Á¹vÚ>.h‹=8]W½®¢½ÆÌ >Jÿ™½ƒò•¾¦ßx>Û­O;x‡ ¾‹4¾Qõ“=Ð@#=ð‚¾ ‘³>S¿@ô=p}—=üÀ\¾¸Z0>)v=]b>j1½—c�½�§ª¾øNÃ= Ul»Kø€=�‹½,®i>èVX>þ„;¾o\>ëS¾Qº7=lðª<\J<¨z>o'<¨—¾©m³=yJÝ<ªw><¡¸¾shb¾üUŒ»ÔDv¾­q÷=§Q†=ºàk=b™Â½îwS¾ûñÀ¾»'*¼‹€€½zä=“¾ïñ„½ŒÈ ¾Å=š>ão‘>þ3½ 0¾­Ta>ŠÑÖ<¯VÑ;s%s½*�ニtc¾IÃÚ¼6J¾àX>èpá¼ÅÌ„>uå=”i=Ýó>áW5>¯º->^•u>~’¾üÚ¿týˆ=q4Ï=¸²¼>Œ�¾}f'>½¶·¼mÖ=’a>/ >±J}>®¨Ý=R¯¾-»>>ô!µ¼#ÄU¾œ_²¾wfo½`’´¾N³©=ojØ=YG»=BI>н…ñû½wùn=°õ–=J ¾0Ý=ÿš#¾m޾7Äð¼i1¾Ðÿ8¾7Çä=¢UÔ½‰Ï>LM =b=‚Ñ><ij½¹<¯¼�ï©>}À¼¾'.¾‚¾òqF>T£œ>¥’¾,)j½ÖŠ÷½™Ùò½¦òA=YJp½…@¢>E=)¾«:}¾Çê¾ á…¾® Ø<ô¡l¾:#’>X½´44=®W>åB6>ÂE¾·Z=Ćé½öp>©›A>ѱç<ĬÄ>n§0>±{ë½#˜j½W¼ öˆ¾1™T<…Úí¼ª®x¼¿)>îšy¾~ä½=© >ݳX¾éDÊ=Ös'tÔö=��|½åz>ñ)×>á즾<´6¼ )0>Ô÷°=¶ÕÅ>ý@½­™Ü=w"‘=-ƒ¾žà»¾P6æ=µ�‘½4ÊE¼ú\°¾ÿX>ØÏ*>Æô½|Ê >NB³<.€¾ê]>^ù…½‰â¯½”MľE'gJÉܾ q>˜é¼Áný=��P>¶e¾Š}8¾’JμÝÔ˜½Å4ú>98Õ>jF�½ßms½–\Ô=UD5>,!==ú›i=@ñB¾m�‰>®Ö�¾D>à$½½Œ;7¾O/?¾Yhû=t´ù>—R¾•ó…>Â�”½Q·>UÕ¾“'>|H¼;rô=ƒûÿ¼'|ù½L:¾ÐÚ&¼ED0>¼GÁ>$—ͼXe¬¾6œW¾)惾¬ß?¾‚ü>™é=-I®=ôŽ…>Ÿ ÿ¾#W‘¾FT>Ý#¥<T¾†Òÿé—>æK=�н Iî½²œ5¾“!¾BŒ…¾hó/¾’82>æ/y¾8º=ãz~½‘¨¾"6=:é[@½Í¼=ÈÒK¾ktF½?Z§½¨i>µˆ›¾ßËô¼h±=�E>¿l;¤?I¾—¡½¼”q˼úr2>Tâ–=ñÙD>u3 >"rýN6†=å<¾‘0X¾'¦¸¾J%¾hƉ¾îÛ¥¾m+>�—>•i²¾e�>§æ”>²É�=Zÿ¾(—‚¾Öêå=Ÿ�½=ÌKý½[ò<-0¾®9#¾ß‰½¨�ì½ÑN ½1Ä…½‚Ü>&ÑÚ½v+>®Uº¾âGA;¸¶š>Y/|½Ìê=¾-¾ö/<>ÂWí½a’A>רè;<=¹ïÿ=¥ >†ñ¾˜xF¾Ç¿ùP<=gFx>×o]¾–²=� ç=Åw=«0»Gw>> åW>ñJ>x¾ :‰¾A„@¾rŒk¾ö=;� O¾Ú—Ë=þ&= ò ½•õ[=ô.˜=¦º¹½àV$¾âœö=0{)>šg’°J)½ì¹Ú½¯á»Ó­¯»G+¢=÷€Í½ºéѾ— �¾¿ô¾”ºô½ç6Ì>ìN>�(ú=tåó¾½l>뇪»a>½mÔV>^8v>úÜ=ÎÔ½öB$¾(’>ᆬ>0q«½n”ë½j,•½°, >”Êý=Iw¢=;§ƒ¾}1,>XÚ½�í*½…‹ž¾úº³>qP·<^‘'¾° ƒ½Y—i¾ 4 ¿†2sÏU½>ŒSd>uê;©’=Ô¹H= }6¼B´½«½ó ¾ Äe=Pv¹>Ï< ¾z-ͽ±@=Áqä½"›½Åïÿ<ûVf>Bö*>�E?z6?µ^{>S¹[¾žnb=}]¾álk>ñ�;iœ½F‚>uŒô½!B•¾ÓÆ'¾!•¾*2=4%>~¤¾‹Ÿ½£ZK¼…Ï׺Jý>Ñ©¾æc¡=¼´>>�³¾ÇA ¾ÈÛP>w <×—n>Y¿¼ ÍL>²¡½Œ$½²†®<3™½0²>•½Ô>k2¾#6>¢Ú‡>û†={ç§¼qY?žTó¼ŸÇ5¾ô˜>W*„¼tæ‡=CdȾ–|¸¼Ì'Þ¾yýa¾pñ$¼c%þ<+Ê×½TB¾HX¾»®Ù>‰Œ½-3>…ô¢¾Uù½íñ“>ÈãÎ<úù¥=&ô¥>ˆÜ`¾W,>ò»à½ 3<>¼©°½ç¢>rg¯½Tú ½…ýR¾ƒÎÍ=•½�>o¯™¼{þ¯=ÜJž?�¼ÐœÙeý$š;ÌZ‰¾’ã¾?ª>±úó½­B´>`{'¾ºY>,ãî=}|] Ÿv¾nsƒ¾d ¾›±=A“£¾e ¾D\C>N{½½¤‡º= ¾Ž>Y÷<½�œÀ¾ f…>³±Î½2 ͽ;×�¾(Õ½ŠCá½+7¾íúþ¾šÑ<ó`k>…èð¼Óe˜¾VA¾ Ôü=ôò>Wi¾Á³š¾d ¾ðT=ÿK½s“¾)<;>(¬P>’g¬>F(˜½bè:ÄP«½#¾'={‚ =x§9ËvV;ÇÐͼÈ넾�ä<Êtø½bÐ[>GŸ¾†ö >æk>8z«¼$í=�Hç¾·†¾ z»¾$]=ŠÙ0¾wC½Šœï=€…ð>ߎÃ=E?&à?>Í2d>u¢¾ËúD>Ô©ô½pò=—œ¾óf*=ÿ(ó<²=”¾hÓ“> ºt=¼Œƒ¾05õ½–»­¾†"®>42ã<-Q`¾ß¡’=á =“J6¼Ø4=½ì�>†?žF_=G)_>š“=¾a­>Æo”=�2¾ÍbL>bm¾@Ÿ½yÊ\¼f³¾:ÞV¾QW8<O¾]˜>z£T¾ŒË2=·Í1>­(¸>-àë¼|8¾Ì"¾ÉÝò½`ü®½å^÷½­5t½T䡾I_¸=æf½\[²=�˜²=2ù½>— ©¾-w>ÄVž¾±Ìº¼Íš–=tÜÎ>¾ŒÒ>¯ô£>aŽÊ>iW½ÃF+¿ŸÃ±¾èÌf=œ§q¾ÔÛ½²ð‡½X<>Δ­½-I>ìše¾Ôï½»3ü5¾Ý�>èÐÀ¾/óZ=ËýL¾Ã">åá´¾ýÓ¾`.²>ÿl¼´w¡½¹K¾Å²&¾“é>H\½�<½J ú½]3ü¼Õj3=Òˆ ¾G´¤½Ö-­=þÑÅ=øØõ½Ÿ ¾‰°³>°¾ö³Þ=’&¼ÑÃE½ðêb<šu>½R¸V> X>¤»„R‚=ïªÀ<¸½—�<ꎘ¼Í>Q™|==8ì=qþŠ>,.£=ô¿˜½ý´=tž >xn¾à)>”ŽQ=¿lœ½F<>Þ+£>†ˆ>d[ž=j¹(?¤c¥>¶ås>š+>ˆÇñ=PG�>ÀÔ¡¼ìê½+²=V�>ûï´¼ƒwÎ=àq«=�U ¾ -˜=uî=Ûj>Û½°ü%>~R¾Ìs¼íÎ>ÞÊ�>Æ‘>Qy‡½ÚË�=’~d½ß™©½Rœ>½ò<Í£X¾KAr¾‹í ¾./¾­¥¾`¬[> f–=«I4>[݉=—X¾zO<캾ãÁÑ½ê¡ =7cç¾cV'>² =ú¹½‚«ø=7œ·<×:>wÖ‡>†ªÈ¾ƒ,�¼3W¦¾½v¾Çp¢½¥½¾à>Iìü> _¾É–m¾ÞˆU>+¿Œ<¿é•½eŒ>ˆ%¾Š»<½-0-<Ô&Ã>ž®%>îÓF>ѱƒ>†ðоåÙ�½T½HǾ9~Á½ÉƒK>©½¾¸$¾ÞÔ¾KüY¾ŽÂÓ<žé¤>òÉæ=¦ì¾… >}å ¾îZ>_Bc=¨€Ÿ¼ÑÐS¾¼Au>Ẕ=õ”\½ù¾âë¾f ¶½™þ§¾+žÂ½‹™¨>X>¢2@¾Þð=j|å¾.ŠŠ¼Ã® ¾Zc>¦²&> 1˜¾ͼ=©_¾”ù¶¼ŸcZ¾×›Y=¦á^¾Ì[¾¾B>ÀMr>VbV>|Ÿ>>e>¬0v¾–‹v>*ùr¾öeN¾£Õß½èôƒ=‚ †<ßo¾ ˜*>ˆˆ>á3>,°½³Ó>Ä¡=-¾ÿ=WÝ–¾�ε½²ÃÚ½U a½tÕ<¾ ]¾ïZ{¾MÏñ¼Ëšn>Ìc>Ð|>AŸµ>‡:†½Èg•¾Jvå;.DD¾–Œ>“ܽ«öæ<v|<þ„I=ø.‹¾Ižq½”TƼK‡»@k*>YAà½Á›T= Qú½ b¾éŽ<§Ø>RH ½±L‰¾Æžã¼´f—>æ ¾Ù $¼Öù=–‹=¬aV¾Ù#M½V$¼¾·a‰>¨:¦>/³³>x>Ÿl‹¾pà=· ¼;yµ¿ñR½‚Ñs>üD>¿úO¾Š—ȾÍI˽ÊîV¼…>‡°½t¾ì<º…H=䮼¡W¨½˜q¾�B�=<¬Ž>Gâ1=½ûX½�/"½’­>ÿš¡¼ˆ—=‚7½!\?ØHG=E9„:Mp.=\Ã<&–H¾‘µÒ¾0­“¾ÈiR½{ ¾]z+>N×>O‹ø=�u>/öû=/7'= c!=ĸ=·T¼½p¾ÍäŒ=ˆr·>@žÜ½JOú= L�=Ææ�:o-Z>å�U¾~ªÐ½g‘š¾U%½¢Ï‡¼¨]…¼ˆÅN=ÕÀ´><Œ>¯Ó ¼Ü§?ï'•<Íãg> å½ô>^{=<@ É=CÓ??ý½‹`<½Ùd)¾ûö\>èwš>À‡c>ݵ ½Á·•=¡nW¾ä' ¾;>Q>›,>÷>Þ4—½ßߢ=�z½eÎ>ˆeÇ=¦�¾›f”>U»”>~à>�—;¿“ Ò=gšÄ>ƒÇã½@B ¾_-Ã="°U¾Q„=Ì´q¾ãWþ»”Jß¾Å2Z>#ÑÂ=¿">è26=A–á½»Ž ¾�7>4ÿ÷¼òÐ=˜J’>h]å¾§è¼ðx­�ŠG>wGµ=„抽/¯á½jv=»#>ãð>‚ʾh^´=’úJ¾àWh>æ-×½ÃôŸ=޼ >¨÷î½ ¨}½7f'¾ú?¾9`齨0®½ ˆì>íV0¿Rn3¾ÙR>Ù•½XUG¾EÌi¾%,>M­Ï½2â½ðð³¾ HM>ßN>7±=wàý½røÕ¼$þ¾Ñ‚€>É>|˜Ý¾³j£¾Iu¾Ü–�½ÈM¿<±ý¿ân§¾§W)¼¾”ž=ÂR½1`>eªª=ôtÉ=—$ >]d=c6W>�W|¾xà‘>#õ?GQ¾V=Y ©½h|·½ÙÚÿ>ˆ�=): ;Ú�=w©3¾%È/>H9C=Öë:ÂiQȽ{ã<½;“¾e޾L‡‡=�üŠ<ÿFp=äa¾�ñõ½¡ûé=,K,=¨Šú¼uln¼3~>/Á½óB¾™§¾GøÉ=–îX¾{¬P½ÉžÙ¾²Ò?tÎv=ÞCÈ>ÛǼWN½>17¾Y²·¾"ƒ>Þz÷=yQ#½ž®¾x+ >  ð< Êü>¡9¾—ˆ½‚±ã=¸\C¾éŽÿ=•9˜>¸˜×<ÿÕ½ŸÔ<¾¼ß1¿5 ¿J•›>蜾¾B¾w¾ÿ»¹7éú‰¾Îá3¼Ôsš¾±?•¾”„?¾D¼ª>*øÞ=Pü²=m�>Ýêù½äÂÝ>Êà·>TJ>…V­=±®°¾`vоðÍŠ<äV*>Nê½¼¾�@>ðè¶>ºN>�ð>Âñ5=’?J¾C±c=×/¾7–šµ£m>ø¦ø=™ɾiP ¾T¥ô=ÖÓ>Lm< ¨¾$>-€<ŽÄt>r³æ>[˜o¾u\G<å ò>¸_¿ß 6½ ¤5¾ú¯=C$>;õ¾éx¥=͸§>?‡>O†Éº¡1 ¾>kN¾¦$¾yÌ®¾Óÿ>5ßѽ",�¾Ë =O� ¾ìj}=W¡½ÕäÀ:�½.ξD—h¾Õ¹1<µçº=,\«=l¾½òû?. ’>B¦>q>Ñ‚½ªv½fJ¿i_õ¾ C>Û¿0?â=¬<‹¼=Ò· ?·Á­>¢@>�/€>(å5>õ±U½Ý"¿WZÄ=ÚqÕ¾âF3¾[œ.¾ºÀü<n½x¼œ¾¼á.¾ xÞ¼•~„= M½/i˜>íIw¼ˆs¸>Ie¾[ß»½ y¾O^¬=€µF>@ü“¼Õe'¾yÔ{=†Ä5¾¡y ½›Óм™<`ðË=·]â½K®]¾±°¾W6>oÓê¾aÕ¼z¼k¾­ >Ö[¾¦¥¤½à�M¾ËEy>;på½Ì¼ ?!þ�¾iN¾Ìù¸½eg>³J²½Iͦ½º ={ô‰¾Ãm¾ÝE ¾¤&”¾]š¾£ã½Åþª=þ©=XоÊ>>N¶>ȯ¾ÿVú=?±ù½Ö˜�=ÕHT½ÓÆ…=¥E-<‘¡>!�M¾ñ1?—r ¾T‹½èÄ‘¾*n¾pÒ>œ”¾ûg >ErŒ¾‹<3=ÒÛL¾ûšy½ÜSí½ >Ðò=}6z>Ž”M¾ã2z=_q‡>­ã¼=øk>¾ãQ¾‚~>èÛ=Gòy=,_=ÜjÚ>2+N¾¦¢´=k8T>Ää½Ö)>½’¾º¼ç½Fo>­¥Š¾¬+>Iþ?¸í=Öÿ4½¿#Z¾v>ˆ>ïe‹>÷ê(¼&Õ0=š4¡>ðç^¼ûQs½x(½Í± >œ}p¾î¿}=éRY>UÀ²=7ÂŽ=2‹b>Dzˆ¾ôI>~?‘>Ûˆs>åïÜ=¸¼»#ªU¾!”h½Ù˜nd>޼ö¼@Ë>Ò*“>W{¾éW=¸@€½Ñ@><ì�¼'ÃF>˜O>½—n€½‹N>&öz>iéX=$%¾˜G=÷ØW>…•½yX >ÌI<çÛÙ½«n�>M>f=J6¾÷ˆ¾ô¿ z޽¾©�d>ñ>­:�>úHÒ¾†Nÿ=CC¾g•‘¾†õ›>pÿ(>î¾F{U¼)úÞ=îw2>{.¾=ˤ>5W‚½™¸†½vˆ>ØDÿ<±p¥¾HŶ¾ï:ý=tQ°½x¤Ø½‘€¾†"ì½&h¾²{È=èžS>ïñ¢¾oÎ=±t½ÛõR¾ €g;“3>–º ¾÷ÕÞ=p¼±½t±½©îo¾œ‘¸ººù>s!b¾åû=EÈ<`X>Ü ˆ¾€v•¾È£Ê½ö’—¾ÀrÉ=+¿‚>Êéß¾:§ç>çо?¤>Á%Ç=Ùp‹¾ÓŒy=½}ؾ¾Ò¾—À¾ 3¿;¨(>NïݼE£Ž=èíÔ>2”ê=j5½¥Ò=0ÇŽ<,eϽܙY>ËW=¶,¾kM>ÔÄy¾Oá½­`@¼([ð½ÔìŒ=tà>z-¾ˆb?¾#Qß>ò%‰¾Âñ:¾Oæý=™Y>;\>^ª¾·ò>í�”¾$UQ>óíw»Åg€¾`aœ½ 4y>Óÿ¼æå‚¾�©�=Õü =š«Ç½ÖÈÌ=7�‚½œSܾ¿^¥½Ü ±¼ÐÈ>r‚ä>¶ ¼îAu¾Ð˜�>=¥�>*Úô¾~Œ¼HD�>yª^¾™¾t» >ud™=!H½‰ÖϾÈbº¼R=Hú“½1˜¾jÍ‘>˜â¿6ŸÊ½[N¡¼ÖLï½~ܽ>5ï±=â5 >÷'£½Þ-s=ÝT>—?@>l_¢=¸®§¾YAs=+^.>&âs¾Ì¶¥½Š7D¾\n…¾¯sŽ=ë§j>´¨b>±Rq¾=08?8È®=Þ�½ÐbŸ>ךð½ºkƒ¾`ýÑ>ê‡Ê=¼ƒ§=Jɪ>~¨6¾å(V>´Ï¦=+â¾f§ö½ú%g>ab_¾jº6½Ÿ“M>Å>¸>s°à>�¥=NxÚ¼á1¾\“ž>1ç>·†‚>Kyš½¶i…¾ó¬>ãîì½°9¿¼‚É=>Ì�=®�*¾c�‘>æ;¦¾%çp<±B=‰º›=¹—Œ=¤›Ì=v½t½õ¸5>ƒk> ƒ}=@FS>BX>æìœ<`ÚÅ„>Æ#›½d4À>íRã<Ü3->‰î.>ñ¹s>»%*¾J­#>�ÆU= ’ú½q‘‡<&uQ>…X[>{’>H�>Šj½dÄ¥>X÷J¼ ソ&{·<¿Q¿îp¾›¯¼j´>ûE…¾Z›P½ª‰:>`ù½½”û ¿²¾}w½/eÑ>T$>}ã>S ¾Cñ ¾Þsò½¾›¼ø­¨>ì9H¾Û?>½C=�U>Õ‚#>®÷$¾B!¹¾:Ü-¾ˆÓ>¡~Û>SaÎI¶é½H4¢¼1¾Ôj?¾âü~=V%4¾Å:s¾ŽÞ9>b[›½½e>ÉäK¾u‡œ¼Û)ð½¶?Eù]¼¨¾°g�>H^×=öë¤<—eg½ >>¸dË=˜/>6õ8¾é‹>/%”½ç}ã=d¹ =ÖÈÙ=h´½OªÝ>¡„\½~t�>G£†¾1€œ<© ½û*$=^ >|ê;¾”ôT=_‰õ¾æP¾ÿè¨>jl¾\ŒS¾ãž>´.-¾oYc=;Ô±<žr›½[m>.>[p½Ïê>X'¥½Ì½“>ºz«½+\>%>>¾`?ØïS¾?tì=BTå=Ha>ö¢;¾Y�”¾¦¡Zž.>´Òõ½‡F�¾ òȾªA>ó=>âý½IÂG>ísú=,¡ˆ>W¤½ I¹;ÓÎp>w¿W>dÜ=¾b¿p>?ó5>oW ¿ªÊï=r;´/�=¬[�¾¡:„½É-Í=rÞ=Ìp½�¢—½Aå>¯¥¾X‹ÖF¾zÛ�½=³ç<ú¶>c7 >öÚ¿É™Þ=IÄ ¾0·à>ˆØ>_X‚½¶";�F?ßë#½ëU4l½Dá­¾]`>DÔ½"ª=Ùé>!r·><+Æ>ëî¾ o�»ýÞÜ=§äã)¾ñ¶<½ÜÉ=åÚf¾°8=n §<–Ýr¾Ëˆ–¾ Æ=-j>°�=hüt>88ã>>îú½Ù4&¾­;„>òx ¾±vǽVÂ>Iáâ½ €]¾˜û½ûÉ<½åx¾@uø=m>§#O½†)¸½.ý)¾ä±ù=Ï!þ½HúǼ,“V>�V¹½Åg˜=éÉ>޾öÏϾ»òÉ=–Ló=€j ¾]sÁ=Å¥¾=¬l~=~©Ó=%Š[>Þnø=H ,=膬=Qn'>E н’ì[>È"£=óc*½íÍ*\¾io¼ÿ´^½ÞO6=9ˆÂ¾óP½öS½¾0Ë+½9ñl¼nŸL>dŸ½’Ó²<›-=KO%¾S¬â<ÎI]¾®w/=µ¢¾Š8¸<µG·>¹¹“>Þ« =ÓJc½ ¾qÀ­¼\U’¾l"„=°ȼ`3¾,½}qå½D%m>æ„¡;>N§þ¼8ă>+Å<ó”�4Ÿ¾$¼]>£'>Ï—º¾hi�½eˆ>"É•¼óY„>Lf‹¾8•?¾0+Ë<º`¡>ðZP¾ž‡=‰!¾tkc> àŽ¾rľå¬>Ü8¶=SÞ2>:š=$·=ÝO¢=‚Öx¾dõA¾Y¦[¾;‚¨>Jš¼ã�{¾ä½Tó?¾¬+’>!&õ½˜½ý[Û;uã°½a ¾¥V¼}øÈ=e&`½�Þ5=îÀ=P¾/¾+êœ=Œâ=½^ð¾ì—¾qf'=Å‹>ü3¾ W?½I´¾˜/•¼dh�¾œç½,Ë>U�g>'Ë=-S>Ešò½¡ g>ÂÈ >UîÎ=¯¼½ =èW¾GÁ#¾ÈF>²¿ >§$—>%î½»‡>ÈÀE¹ìw²½wÚ=lù$>/Ž'¾�|>ðÞ�½䨽D>úý½Ðm9>?�½Ì·î<64*½¡l#>/n®>sWŒ8¶)¾x(ë=åËÜ=5�Q>Œ”¼åv¼¼kšM½0�>CÈ@¾z�¾ƒJK½t!M½v¾|$¾ç=ž=Á:½!X.¾køV¾m™>B>åÒ=Ôo>R�§½#Ì ¾rB¾Ó*î<¹].>ÿÙ>×'ƒ¾ÉçÖ½$/c>)/>½èV>–[�½ën‘>è7ƒ<áÚ†¾OEB>’¼#¼û†.¾ÕT9¾%R ¾ë!¸½L‚¾ê‡?< "Þ=#uâ>[K¤= *\=•ø>.Y=.dë½RP=aI¾¤} <¿¯¾¾cÙ¾ ½)>I¿“>MÚ¾‘O=vf¾cDà½þƒ>·Ì=(ºü½‡S”=ýÛc=J™«½”€¾]Я¾½å€¾E÷’=ñ;„Ó&=ÒK>¶«= ;Ƚ̵½œ`…>œ/²=?¸>ÈDë¾é/ɽ÷¤>¨ã >w]>¿yj>&­„½¨ü³½vÈ<=ºÜc½‘2*=•±nñ¾Cë">"ð¾lz0>o£Ï=i‰>ƒÑK;$7>•òǸtŠ> KŸ>0>=¼˜F¾¶D&>ç8½„ZY½Ã¬‹>%mS>Zm/¾Ñ…½ÄI5¾�# >m‰U¾»C¾Ÿ8’¾?`í;k>`½Ú<�>H¥p¾$�¿}>î-û<Áå°><®Ã½fõã=ÕÓw=³‚¨>“ùð>=oŽ=Äa¼>H·É»PBÔ=‚£q>’ÿx=˜° ¾Ù³4>(=;нj@¾pS0=vˆr>/Mý;ðb½�² ?�“ˆ=Яľ6¡¾?¶=S©Œ½™ºL=ãf=bôû=åp>�ꓽ~¥š¾‡î�¾•µ>Hù˜=‹ðO=¡ú¾Ò é>Óe>UR¾p™>¨×>V.¸½y ¾b¾Rº>Árž=’Ι>Aݽ�?3Ø!>üí{=Sn½ëè.¾ò�b.›>:­Ü=��¼ÜO<;Xž<æùô½�û¾ãñL¾â8>°÷½K¹>tDнÄÏ…>Å è½R½¥½ ~˽t¦>• y¾W¡™=Œëž>Oh¾;pO¾4W5¾rØð¾üð4>âÃß>È|.>*�>0ÕŽé¬î=”ÈÅ=T°T½M¿¼Ó<ó½c}Õ½‹‚ ¾=7ç=#¶¶=6Ï<Ù®>¤Ä¾¹æÔ>�—þ½„Ù¾=Qü½³>Žâ>®qã=´5“='—¾öˆ>wl>” %½B3­=«š£>sP_=ÄÞ%>ºì>±ùT>§Í*¾w޼ꎇ¾m`4>YQå=À-X¾x…=ç½=ÚœÃ>m¾­eν6¾ ,>Ì>e–I¾@$½œ¼¼=.À½*ú ¾I6=°?à<ù->ûr·½Vów>›}¾[ë;Ïýá>eä†>Èîp=Ï7™=ö=½­·=ãAʼ�±·¾B¯5½4ð=¾ßjÝ=Ü4¢=$«#>‘=Ì=žèö=68¾+—>ÂZß¾µßÖ½i)¯½à×I¾E\¸=îÊý3’¾N I¾ýÚþ>ÆT»ç+µ>K{p>Þ¾X½Ÿ¸ý=!ò>P¯³¾#¦¸¾Ÿ?‰:Ó¾˜*-=^�³¾*Ã">[<þÔò=e–>b›�>^?p.ö½M`½ÜÑ>‰ëƒ>ç>SR§>(�Ñ<{zW>wn>ÛÝW ,­>¥:Ý=(„=¡°½âªš=ªì=A͇½’ ¿¾/£®>o9»>×€.>\Ö&>Uzƒ¾M³¾.ïϽv¾ >ìl¾€!“½!3={Òž>J,>½n ½7¥<]L—=âB޾Êp¢=lJ~>ØÓ½�zr¾U>>[&½<žÜ=%³N=ŽÏr¼Lå�>�M…¾þ×)¾{Ä<>4ÐÑ>ƒó0¾õ)>Jc¬¾˜&Ù¼+¥?”>5C =n/=¨†o=î.�>vgÒ¾XØz= L>_¾l=â¾Â­‹>1%Ù=¸2–=½ì¾Ï ½‰Þz¾Ó _>5Áõ¾~;!¾© e>E>;ܦ¾Å]/¾^3ë½²¢C>õ—Š>Èÿ=>}t >›§^=šóô½�B;>`•œ>OWœ¼X5M½dªœ¾–¡O½2 N¾®O3¾Å80¾dX¾?>S–>{Ÿ�>eøÀ½†‘½*’°>?Ó½œ®�>�¦¯=¸3È>™à½à|Hž†<È&Ÿ=Qÿ_f‰¾á>¼Ï{“¾Fkl½õz >±—a¾ººÅ=Ì”I>績×ð6¾¿i©¼4w%=`Ç`>] 9=J•>X•½6ß3>ˆ�€½­Q¾Ü»’½’V�>Ñ:®Œ>Ík+;¿:«¾ðî8½¯f‰>åüæ=ÞKw¼ee…<¯K¾† ¨¾ˆSs¼C<&½|^¹½Að•>r­´=âü>œ5¾¨wê½E‹=áÒ”=åŽ;Ái7¾©jˆ>Þö†½içĽɋ4>Z€T>¾ÈS•¾MaÄ=ÔÕ¿=©l½¿¾íWx¾²Ò÷¼¨n>’•½‹¾>ÄΊ¾øÌоd'Y>Ýf±>¹�>(É> =ò2?h„¾‡`P=à¡G=ð•þ<Ö÷Ò= [—>i:;ûŠv>£…˜=×B½«`¾ 3J½Q᥼¼X®½I¼=ƒ*ˆ>z£¡=§�>n^P>úõ­½6-ô=‰ÿt¾Í¶i>ÃÚþ>2»‚¼µ£>¯¯ž¾Æí=Ê3ƒ¾Èޱ¾€âÌ>2&¾´î@½«D!=Óƒ½ª’?y�>ôáÇ=°½=/>¦Ö>¾’™ ½F°Œ¾@Ó±¾<N>ƒ…½5ëî=ñÁý>{Ã>¯ §=C¨–¼²“ö½:¹È=)Ì>©×ɽ€»½(�a>z6æ>„¶ƒ½S¤¾²¨>ζ¾VZ«>–¨ ½À¢¾9¿´>.;Ô>ç÷¸=ãwp=£¿r>ù}¾LÇ2¾µ”>ú[v¾à•Ô½qW>½·Yq¼H~Š>¶:…=Þ| ½i‘�½=Xƽp„¾E¯ž=Ê`>J`«;{m>”�»<æH8=åè8¾Y¤æ=û=ú0ù>^}|> !¾C¼=ÎGÞ½Wnz¾šb»¼©ån>AW¶=ƒ¬=*¸·=‡Ž¡½ê?–½T- >{Ìù= &h=>0F>mþ=·<¾Çq§¾u}j¾kWB=v§¦<¡w*¾IRÑ<¥½f½\¤6¼$ ¥=…ãH=MØ–>Ș¾U$ï½µ‹ >‘ *¾P}‚½ßpϾ «>üQͼ² �>.£…½:…>Ñ:5>ˆæ!=¯³=™¦¾8‘}<)‡>B‚7¾&¡S>Ë?L¾ò³> ïZ¼ÒåM¾×Óè>Ëž̋{>LJ>å½QC¿"™Þ¾ÍÜ»IÕü=wh)= EÕ=�®�>›è±¼*ÙT>s” >J=¾÷cǽk=]%Š»b­?` @<½$:¾ä%½ýÅš>XÏ¡>ŸÅ1>—š½¥ ='8D=—mD¾s/®=à.>È‚ >( ¸<Ç/Æ=¶O>¶w ¾´¨½÷{>¥0›¾‘ǽéÆ7¾÷T‹½ÎøŒ¼ Ñß½÷Èü½`ø>¾&Š>osô<¬][=õ4=>É<6 ‘>Ò®d=†ÈÛ¼·j¶>èáo¼6³½XƽyÍ�>«eÔ¾—�;:äD?´˜'¾æ©>ò ¨=Ùɉ½ðäxp¼q¼µ+¾Î@�>8·X¾e ¥¾­¾Ó#K>Õrx>-b>(ª>–ff>uß»\v¿<Ç™‘=„ä´=+,:¾7)Õ=Ôw¨=ãGW¾´‚»©ä,>ュ=‡kn>G ?È�¾€5¾oÏ=¼À[”Ò½¾À>>¯´·>s ø½æ#[½çK�¾½\P>ï‡6>»3i=¨¢½Öv®>÷=±>é Å=îq=žçs;^}“»4›€½èõ ¾Ò&,¾ÄZ‡='nÓ=´0>Λí=jÿó=x«ˆ½Ã+¾ÍCG¾=¼õ<ÇdÜ>‰ö¾ ü¾á5e¼>ü¶>î#‚½»ûŸ=ÀÅê>û4Q½ïËA>�…£=ÕZ"½•’ ½Õg=s·ºáÄ­½¼H‹>ò¦I¾ËˆP> y”½ÆY`½ô †<…v>à ‡=^pO¾Xe=$‰>7—>Qvͽ� ¿½*"¾}9«>+È=Ì\I¾±Þ>55e>ÍÞÉ=CÒU> ™“½uý†¾=Âê=d>X²½9*z>WAä¼îhq¾c #¾©* >”&¾H;é=ÐÛž=—¾½÷d>®Ÿ±>’8¾Á¶>*óp½§<­7Ó½z‘ ½=M…¾b>Šøþ½ß€¾}+û»jXC>ÝFM½>B‹½ýë¡=%±÷=0þš½ôÊa=©ßý¼1g1>¢6 ¾ÞvÕ=“«°=‹ ¾Wy¬½C¾8½ýQ ¾Ífe>1Œ>–gV>lD‘=f >’¡ý½ä£!¾>¨–=¬‰”=Rƾ>|;§>!ªë=î8_>˜›ºÁÀ=¹_<‘úã>Þ[<|ž³½¸í¾ŒV½èj >Ç=µ8q½CÈ>À”ѽ^Þï»ý5¾sn½¡Êû½iÂþ=›¡î½ýÀ(½ÙÌ=�\ >me=üé:¾Ál„=§E#¾3û­¾ä‘¾‚™P¾V¶L>ó–>S&Ü>säÖ>�€=0±ó<Åá½êcø¾sÉ=QB>ÓÀ3>Ö:‹¾ï�¾.úݽ³ük>ˆ=~>häl>ª=@Æ^½qj‘¾Ñͽ¤˜¾´°ë=zÉ<Ë“>CQS¾ÇXb¼ög„>š%¼’€Q=:O¾ˆî;=–+¾Ñ³~> ­¾Ê”a>O÷Ľ|a/>4è8><Àã=”œï=AÎÛ;ô9€¾\_?=‰´4¾» =zÃk¾! ÷>Ö9¯=É»'<½õC=)•F< Ö¼>æ8š¾¾O¾,D¾ þ<>ðj�>;–=šT²½Ü3>n¨ñ½¯®¾¥7€¾¨Yf½*A>à�1½§,¾¡uv½Kc>l8\>ÅÞ2¾?ÕÙ¾Ëd>Æ©==€L ¾ò €=É̇¼a~$¾ õi½ÞP½]ëÄ>5t\>W8X½3O>fcν¡…7=° ³=ß@Þ½p’¼ v¾s¾ÇŸ¾9ñ,=ñÈ=aŸh>!Nä½ÄV0½¯Md;¦½¶²•>m=*娾~ÜÈ»Ì7“>)ô>­co>—£½Sm=qUé=ºcÐ>‡Ï�>£:&>ÓÄ›¾ÞS�>ÿÐë½U¶»:ðØ>jv¹¾§-G½š/õ=eZ>êT?½ ›§>™Ü!¾(<„>z>¬P­¾ˆŒ½õBœ=ŸîY=9µ=”îÐ=•E¾þfM¾< ¾’Ò6=l,¾Lî¼ ž=ÿŒ»Æs£½¶q =;E>«ÔY¾7_…=‹±Œ¼VžM=ðæ>£Úº˜B©¾k™Ý¡¾‹b[¾p>™>ã93>yy>>(ž>{,j¾¾«£Ð>–D=mW<Õ2¸=Öt‹>Á•>•´Ë½üÖM=uXÙ½¤>[*> ¼À=s©>É §=.eð½±Þ‹>]á¾å2>y›S¾ºü½╀¾F|¡>r¨N½h²¯½+=Õ>tš1¾à¾ní�¾yÚ#>å²ð½ã å¾�i~>ù™¾V¤¾)2Ü>yw>_�>>ZD>çß�<;€²=~Ú'>)š¾|> >¦r€½¬“C>ÜQ¾º¼´à>\I>ýÜï½þ5>µM>Òö5>X…ç¾gJF>ëD�=ñÔ=»½7=Ò‰g½,s¡=ÉÖÃ>˜¿w=êf½ü3 >N„‰¾q™¾]v_=T#Ľ�Õ¾«@!>©N»>>¾£=X÷<:ïk¾Ø¥Ê>Ù-¾çÒv>I̽dÅ?>¡@>œæÑ½‰/¾Õ >*+n>Dí¶>4ÀK½8›[>ò`F¾% ·>Üö >;“Ç=Ù/·¾õC¾ýÞ4¾Ô>†½V¾€¾&°=ó µ=H÷>‡Ç6?¬‡£>Ñ0þ½…Mî¾>±©¼ÀÒ(; >€½ -=Z¯´F¹€¾~xè>µ@Æ;øhà>JÿÑ=ÐʼBe?½Uj>>d¾VyX¼Â$ؽNÆ>Æxð½·�‰¾80 >£6¾$7ï½· =õ >R_n;ËM%¾ÄªÎ½ê¸½­Ö+>½2ZB=4§>|ýï:ßl·½ŒiE¾Èð-¾â�¾òÔP½ŠM=Ȉ}=©o=\¾t¾[o=�ˆ¾=“D&<ü~¾È�¯½!>“Í(¼ˆN¶¾Œ ¾3ØË¾-ó=ÎÅë>}'> (C=½ç~¾w@D`=Rx!½g´½Sö¹¾sÁ„½üë >ÈB=´A+=W,>[©¾Ófˆ=ôöÌ=_—>�¾’(U>B“£>Sy¾â¶>%¿¾Žµ½¾W½ÖOn>¬]ç½´Ô<%Pê>w¶¯>$æÓ>œyS>Jj¾„6]>Þ]¸½xùG>~; Ç¢¾v#ó=.¯±>Ã$<îP>‰µ<2“—¼¤�A>㶯½{|h½Y`)¾dÒ%>F½|=¸²­>¨f½×Àç<«�† ¡=¾¿Cæ>]®Ý=ÕJt>Ûž¡½M >c¥O½ÚÈ9=ÓS¾G罂øw: £<Žš­=­[¶½ ( =‰[>Xå½Î¥š<¶ ù=-@–½%U£½ÆÁ¾Â®¼¾Cê =§¤0¼èS¾Í>|=²ŽË½?¦_>û›¦ºú{Æ=5¿?>Û´0¾uZ>+ææ½rÁ‡¾Õ>åª=3="½‹¬½½¸–>ðZØÕ°Ë Òǽp:¾)Ì˜ ¾ÒÇ0=SL$>φ¥;äÞu¼w·¾>V¯–¾Ö±ã¾IŒ¾Ïý]>ƒ > >Û™7>ÿ¼P¾’y…½C@%¾ÞM‹¾Ûî½/ú<¤Â´½DÄ>)cS=*¼xN:¾É)¬¾Ž$<< I\<”7<{—v=Šžµ½/åd¾@�Š>I[ÐD>Ù"¼y4ݼ½9Ð<.—ó½©1¦¾ÌŸÐ=Ú*<'ßf=&¼¼æô¼Õ«½úZ¾VÔX>/Þe¾ÖØ«¾– ¾ª!õ=÷Jƒ>>Ãõ<úÛÊ>œÆ°=¸5¡>ŽÛ<í–ý¼0=ŒÚº½Ê�̾×Ù´¾í’(¾–©7¾Îa‘¾½œº¼ª°Ð¾aÞ>l”\>‡Â¾ÅFƒ=ÁǾƒ›_¾Yš/¾esè>¿’>Ú¤½z‡>bàÙ¾Ø��=I{¤=1æ¼_>¯kÌ<]¬©½ÑÈÁ=/ƒ <Ý;×=ÐjͽƒáI¾:~‰½ Æn>Ôû½ex§=øko=æþ‚=Ó|Ð¾Ø°í½´�•¾G\r¾,¶P>*38­¼ÑâÑ=c&>iG¾»i‚>,ŠÇ¼º‹=�˜£½ˆ€>œ©A¾j{s¾¥Ÿ=ÖMF>¢,=µØ`>šÒ¾pèG>®E>OBI¾OPy½Xí×=M¬E>ÿ¾â†„>®¾íK™>0� ½ƒ�Y;™§‡½ŒOg>ŸâË>Fƒ¾a˜Š=ˆƒ|=2ãu¾Q³i>מÕ=:ã;>D‹†>{„>}"¾V¸ ½ OV>.å¬>Þ*¢¾ñ�;>T«< lû>Õßp=Þå½½„è�>iíY>Ž”å=7¼>£E™=Êb>òÛW¾SeŸ¼€.Æ=ï¡K¾Ó>Óä/>;·ô<ˆ†=ì•>;�yº>d3�=û”ë=Ö>[¡ñ»vÊB>çÞ™<±V»øƒ¼î̹½^Ù;á�ø¼èR½¨H>øub>wýz=çþ)>˜Ÿ>ù±>Ý�M.°µì&à½ØãD>!zU>Ð.¾Wwß=ýkÿ<¸‰>×; ¾b3<\ÅØ»:ºØ>EOK¾­£ »ùŠé<ý•Í=2+=Îñ¿+a�¾çB=Íúê¼ól<>:¥Y½¿´¾Ëòv>ôØg>ÈÕ>=ÎÞݽ1¢à½õ9l¾x«×=òì�¾m˜¡>P—Á=›�=ú`[¾²·½°UI¾í�©¾ºèã=ë&’>¼v;üŠç½¹±O¾4 a½Ö0½kÅè>ÌÉŸ=Kb`=«&¼’/i>ùkɼc¿h¬n½N,>#îI>œ¾ºfé½-oP>ÓXï=ËpÁ½ÓÖ�>Ì.`¾ý˜}>‚‘^>]-R»æ+b¾–=§ï-¾FMœ=NË->ý ¢=Ó´>Ä{i>nð=�ƾÚ:æ»,\†¾x?`ª¹¾Ú/›¾Æ ï;=Ó½XJ¾„G„¾ßzÁ¼³l›¾ |ü=¾$â½Ù›ä=ÉZ…½ø2>¾‹À2¼+ÝĽ›®õ;$íæ>¯Æ¤>X/“½ñÙf>ïNx½+‹8½á­¾;)[=:=é÷½2‘T= R¶¾Ÿ`¾ U=7Π½?µY>xÀð=Ð�X>Ihg½Ü^d=²Ø>0_„¾š®”=è£Í>¡1¥¾ ì+>|P.¾cR¾,žœ>öÂô=†è³¾�:0=«x˜½³C >vãï½÷ر¼±y‚¾©û¨>>2Ó¾¦1½Ûȼ=øM‚¾ çϽ{Ë>ïž6¾¬ƒf=𕬻n,ñ½¶'>L¿^<¶O¾Ã�‰<ʆ>uJ"¾� >ß,9=p­£½ˆ�=„%¨¼Žpë¾b+Ù½7=+M´½÷±¼ùc'½¢)¾nƾÀµ6½À©û=ì ¾t­;KA€>�Î5>Î[«=+úS¾2==“>�½]®O>Ü¥5½s˜Ó=܈˜½Ç÷´=èß¾3=É(>–o•=ÑŒ>¦;m¾Ó}A>±¼×\/>FŒ>Šlù<š*L=ÊÉŒ¼@wõ½<<Ÿ>£W“>�†>¼‡h¸;Õ,b>zIÌ=ï >'¾Ø¶[=Œ¿½µJZ=ájN¾l»<¾ -ã;‡*G>–y€=H;=ÿÊq> øÁ»kJ\¾s†Ä¾lòâ¾A¶¾8ço¾îè{>hzû½Ù?¾)½Ž¾öv=½àj�>ªP¾ËÐj¾÷™•¾ß)<>¡˜Õ»55>-È>z‰®=d ¾’Ù¾¼TEx¾üŒ¿½†W¾­ƒÎ<-y¼*¹¾íßT>í„=`[>QÅ=”ͯ=4ö¾>XXŠ»{Ï,¾í?j>ǹ>Òo=§_¾ñÉ‹>y´&½âÙ®½„ƒe¾äU½DûÅ=|ë>£­Z½öõˆ;£‹? ½B ô>¦É“½Ã°9(Öd>vºô`¾~{¨<è"ª¾Y�@¾ÏW¾ûwŠ>ùÎÄ>˜à¼�’ð½Ôÿw=ªsÓ=ùv¾]ƒ =œe‡=»¦‹<]J�<OW>~5‚»ñ¹¾V¾�>Á:»=¹_(¾Z)¾Ö'½’2=Š�¾!u¥=˜¯">Áù¾x2P>I =Ú@ô<Û9E¾ÚD ½Ô1"¼Ô#>x�+¾®*(¾5Ú¢¾·!> ÿ=ËNê½bà,Ãc½n±ç9zÞ]>Ù¬«¾¶Ç=æG>ê-ÿ½b<£=á7E¾“…¢½Ê O¾Cà@¾–"¾Gqœ½‡Ó¯½Šç™<ÎÚŒ> 3^>Ém‡<Ðô>"ÒO¾–¾²½®ºØ=îYç½Û¸V½3o ½¿r=C𥽱„½šl»>I°¾ú(Þ=Ÿq­>¢›–= ]½R’!¼\"¾¸³Ï¾Žê->'Ø$>23۽Ɨ¯>\*à=9;½½]«�<Õa>L£î½ô[Ê>T'üº1k=qN¾<1&¾­ŠJ¾õÒ!=7‹º3ä:>ª7”½È@“½f©©¾/>b“º'L¿>ïò8½±Y¿_�:¾ Çš¾Z>)I…»Åi=ï ¾ÅÕ+¾"oA<#³E¾¢ ¾fÖ!> (¾KÐ<»´ò\8½]¹~>e3;>lá.¾ØK¾v7­½Xš(¾}À�>²›¾L�Ó½Kˆ=¦ê"¾oE¼½þÙ>piÈ>©3T¼•w÷@\\>35>„>D½ ¾@õo¾¾üä½_ÐÔ¾u¼<>… �¾B¾&>­ª£½«޾ …¢<´×d>4¾´Êæ½ïØÝ½5 > œ¾ñR×¾­¡�½zÑð=êi,=—Ø=³�K=ã¤=•�=j·b;V]Ç=Y&X¾Lr¬>A‘¾{#…¾ãY>x—3½Èò¯çuß½F¶®;ŸD꽄ƒ½+¾²>è„=D¦/=‚>/€>ø=>ÆØ>õ1ø=„;;=Õʾ(»èxñIç1¾q K¾ñjß½­g>²`¨=ð�>o'g=SȤ¾Œd¼ÆÇµ½~h¼½-×d¾Ò:Þ½ þÈ›>_í=6C>i7> } ?½|ù=�æ‘=‰óæ½ç:ç¼}¸š>”c›¾[»l>fh¾S­‘=+:­¾6ؾī1¾ØW<>9k˜>;ܾ³±=bxJ½®6¾þ¼)b <-Ò:>‰U$¾>v=TÁ�;�ÎH½”)=>.¾@4¾ƒ“=©“Ú¾½LŽ>çÎ…½³Õ=÷½°?¤gȾó´?>EQ=R¸Á¾ø²Ñ¾ˆÉ�¾ æ=ë(=×ôÊ<� >=’pS>Ùn˜=j6‹=I̲¾éæô¾m±´¾iµe¾7H%> i>�‡½FËL>·cÕ¼Éÿ ¾ úÿ¼,jϽ Wu½*'½ ûü½Q’è>§á¿= OÕ=íª>ò4¬½Ðôç=än>CÁ?¾Œ,�¾´‡}½*{�¾>>o¾€#>Q—­¾I>ì>=D¶â<»÷J=ªÎ¾x?œ½ÞÜ ?ou?¾o� >ÂÚ.>¨Ó4¾HÑÝ=ÎWX= øÈ¼|Û¬=ð…ä½î͉½šŒ6=ðý¢¾ Wཿ R¾‹›·¾ Gu¾‹õýê'ü¾ç“^¾-»>\'¾Vú¥>°,a>Ì3b=Xýß>ó@�=fäv<&=ø8¾öM¾þ­[=¼>¸H)=‹ ‘>?î”>—[o¾·-O?|µÌ¼‘O<לּsÿÙ½C_½Çþ�6>Vޤ¾9Z¤= h%>û‰^G;j±!=ú�>§°£¾>ç½à¶2½«åÈ>˜Q.=å¾¾Põ}½ì‹1=•­�>0¤z½Pp¾Çä¾1Ò<=¼yL>’€‘¾G²¾|8=6Üj>„ë\½¢dò=ÜÔ=ó›?¬½–¾º$é½Ð C=«‡l>Z©%=å"½#zH>i¬=¾øA¾Û ¾ÅI+¾¼¡Œ½mÔ=[ô~½ÐA>ÔŸ†¾EäË=1m�>Ƀ±½FÕû=#�ϽºM&½Ù=ÂÒ:ß3o½+ó >2´¿=±q¾bÁ >I¬ù�Œ@>ßÌ">ý™d¾¢Ç¡¾ÚQ°>DKq¾®_�¾°®>¾?0 > Ø»¼õ¼‘^G½;†l=à:Ö§W>Æñb=RE¼©8<†=Pv,>5nã½*M—¾ÒY•>_Bͺ¹X>Ö ƒ=`©>�“B>Ê׋>= ±>L¾0�¥½ãé�=ےྠ²¦»¨�¾ÅäÉ<ê;ƾ•ùM¾DÌï¼€›Ó>à 彯žl>‘Þ ¾´‡Ç¾ ¶@¾¿À1¾'{>Òˆ¿Nj¾š;½‰³N¾\› ½K&—½kB>µ9F»)¡t>¶ £»rð%>½�Ú½�< >ÿP>¾f>“N » E,¾»E™½Ú»-¼œÇ¡½Wå|½ð=?q׿0«½â·¾´ ³¾V·_¾Îü˜>�Ôß=3&}¾§�=½hZM¾$g_>?ša=yš¼�̾p¦¾ˆS =©Úk=gî½b2=u  =[ŒE<¯<¹¾þŒ/>fy¾ªÑ¾ç1ϽY·„>m›> ¿)™¾7zÎ=¢%Ù¼iv>Þj;= Z=Á #¾Ö¤>°ƒ½ÅÖ|¼ŽÐ™>W›†>³º¾©Z­>’‰Ø>¸L@?á2Ñ%>raœ»<ñ,?™2Ó¾þùœ=oWå>Šÿ_¾ÆM½Ï ½[t½æ²½¥|²>ÌG>g×'½Kr½(n¦¾‰HI¾ÒÖ½®­S½�å¾=ÒfV¾q- >ß­¾:F`¾Pö¼½‹ðX¼æ=Þ(=áÆç½a¸¾WÐÏ:8=ÞØù¾œ~#½œ¹®>{‡ý>|"B¾Ò⢾$‘->· <•’�½\Ë=I–E=¥±¾¿™i>2é½*¹‚¾[›8=¿ËM¼ë=;>fÞÄ= !‘>V'–¾ð" ½ ø°û꾿}'½îp¼'­l=”Ò¿½g€\=ÔF!»þ ø¼¨]¨ƒ >g·U¾¦¾õ5}¾âèÞ½ÏëÌ=6ß¾ås¾”"=Q„?A$>ç… ¾Á#Î=X6¿=ÖJ°>}Ÿw¾ 9¾¯œ:>‘¬‰¾79‚¾öª�½Ä&=}ä½%¾Òz>@�µ½ú„н»ß6>÷,À½ü‘­>Ø™d¼ÁRŽ>“^Ý=�dU¾GÅÀ¾ok�>C¼\&æ=“Ì>¿ ¾7h>ð;’>о9ø¿:Ï£¾îa>14º=u“Ì=6¶½¾í¥Ò>‡Ã¼!<Û=\>Æ,½)ãê>ßúѽ.Ĭ¾7¼#>^¸e¼Òž(¾˜Ž>ôÁP>¢Ê漡ä¿}e;�°>Ì,ñ=÷x€=o‡ø¾ñ+Ü<Ùðª>¸-¦½(·½<íÕ¾¾„¾c›z¾�R�>ξ�¾à ¾þ–¿¼1j>%[?�u.¼½$ÿ½ƒ�n=òêl½'µ,¾KU9>>Z˜>ìàH>ˆ±¯=Éa¿ä!¾Šx¾½ˆ„>Ì0>ö»Z½8Cö=O³E>)Uº=}ÿˆ½�U>uJ�=Fn/¾´»"<“â°½ða,>�¥<=+cÎ>ì1š¾Ï°“½Õ4Ê>lY$>ˆšI=þ>¸ªý½Ü,?;®Ÿ½ÈA¼Ä¼O¥¾4D@>‡LI¾›ú<Äd¾7úí½N�`>?‹B¾H¢–>ÐQ–¾¸ê¾V™>IbÞ¾ù6 ?­x7>LP¢=õ¾tD>¬å¾*~S½s8뾂f¶>ô 7¾wr}>B<>ɰŠ;—´¾Ìi>Ÿæ ¾@>¯ ¾£PO¾áÁ#>±Ù>L(Ô>}|S>«©÷=,Ë=%V‡¾‚{<©r <Ò¬=åUù¾50›=BYP»Á‘ÒÛ‡½éS>˜¥®>XƒÞ»ýËz>ÏíÀ>ªó³½Ãïå<,Ü=>s1º¾UoT>g¯ç=3¯=4±·=]:=ƒÕ©>O4¾.•ð½ä·½lY‚¾&u<>¬{ä<\²Ë<2G¾¦}D>Ò§k>¢:Ñ=$K‰½~ÌŸ¾Áõ0½¦ˆ¾§]œ>Bñ•=L©b¾rþ½2™r½8J‚½�"> òN¾‡¯�½BeË»u}ν-Ó?€ãž=È×—>ê�¬½¿?>1-¾_†M=Íñ ½šïH¾2‰©>ëK½ÓJ¾žŠŒ>à#5>‚ú‰<¦n©>—K@>¸½˜é„>†ÜY> +=¾çx;< @–½UÖ >�ŸW¾O&D>�·®½ý-§>pgê¾A•¾ÈK> Øq¼’%|¾K|¾Û8é½ A²=s«½\ˆ= é~>Îjï¾1A¸¾»“¾œå˜>¾cM>¿R¾æ,> *™¾mz©½Ý~5;²á¾k«ë<¡}W>.𻽠L¢½u†H<ý8¶<Û¤ ¾ù^¾ÄR->.‹>}’`¾>¹õ¾®d¡=Ì`o½Ph¦¾“´>>�Ã3¾AQؾ”o-½kº<›be¾a’±¾?ö>AHH=^±w>ìZ3=Wfö;ÉŽô=1ý>Ç‹ä½�N‹=ÒòľW|(¾ÃÇ >9y¾@ll½>£>4Ê?¯ ¾ùÈH¾�ËŽ>’{%>�þf>�na>AC^º/}Á¾TN ¾£Ü½òØÂ>òŸ½Üv»“q)>Ë©�=œÏ½ß6<„¦ª¾ã•c>N7¿þè>JM¾ C‚<úœ>-p<‡W‘ÃÏX½•L‡=§è >Ö‹‘=vÏÂ<+ãÀ½��÷<© U>ĉI¾åT½½d ú=|Ș>%˜=«"z½ˆ{>È[>ÐM…¾‘2½ÃÂ= `¼Ê $½•é–¾Ñ÷¿ _ô<�ð„>¦€=4»ü½~­ë½‚Ü#½„òð=§*A½Î#ž½ã±Û= 4ؽ˜�%½’ ¾)N½[*¨>sB^>5�¾)½¢<ÉéV>£Åµ¾�þ«½@`3>ÉÄ^¾YO>J ™=İ2={Ç?/mÔ=«HV½àƒ>ce¼Tš>Rk¤¾ø;³Hܼ‚^>øå¡½¥í½ˆý¼=J®¾c>m�¯½P¯,>zȾ]“¼= U(¾<¶½Ò‚�=}¯)¾ÆYá< F<¾¼}…½BÞ>)xû=Mé=¹‚U½L°Ó½}× >>³>¶ªF¾ySÙ½Ó w¾ Zl¾�F>Ÿ© ¾"Ÿã¾úê_¾Ý™=¾ìÏp=04”¾×‹�¾Ž�äº6Š]>ð0£=ØßþM¬(¾š…c¾ml–½†8;>rjå»y'¼\ï€>}ÓÁ:‡x¾Kà$¾8ØY»iH8¾¼Ý>&Ù6¾›w—¾0­f<®Í¨½nF¹½o1’>¢Ÿ¾ ¸U<¦Ùž=ÃPn¾f:Þ¾GŠš=-7:>Ÿêc> ÷> O“¾ëô=ÞDs>™fÆ>Q‹ì=E_Á½ßvL=�¡ >9“»¾zðD¾¾ ½¶J>šá ½Œo=>h�¼[ì,¾*¹>Ã\’¾.‚Å=Xª¾Ø±ð=I†Ð½T¤ =?½Ê¢>b¦¾Gm$>;>(§�=İ–>cÕ£>óïi=‚œ«>y¶Ó=즋>åß=_¼ç¾§F¾îk>„b½=tåE>îz¼xر¾-Òœ¾&Ð=vÎ=Æ0>ïh¾ˆÄ޾1Ü�¾òë ½Íë>äjê=,;¡½©!Ê=…‘¾ ƈ=u÷/¾Šõ¤½$v>Ìà%¾Yʼ8¾û.>´V‘=8Ç•=ž^M¾ä×Ò½Ùg¦=iAмŸgB>;i‹¾lW¾–#¶=¸Ü&¿GDŸ½œñ<™m?¾žBß¾ÚÐý=¾_8>ÍÐU>G¥è=°'ü¼02<Ó²&Ç=f”™¼eT¬=-£§>L7¾Gƒ>~·z=‰¾ ¿¡½æM+>½�±=•Žò;ºæŠ½˜A¦½Éº6½¦é÷½=Ã>¾œœš>šèæ>óåB=jH¤>[‚4>Ã¥�=/ T»sB|½D%X¾µ>à—&½%É‹¾ÊÞμ�^ú>uD)½Ñ ¥¾5¦Í¼\ïA¼µ{>»sž½^w<>çaD>OÔ’>i8'½ «9¾bP�½œKù½N“½ Ãê=D�i>�È>r\ß>ßv>Šû>–ML=G³¾‡8¾6x-½.ã5>pu¾ýpí½†ôʼܖ¥>H,)¾æ‰¾gn„>`ÌŽ>Þœ¾o±3<ïí{>“dM=ÃÚƒ¾Ù\>¾�FF½Ž»¾†×9>“‹"= �ù=[Ñ8>BÖÉ=«>öÃK>>a~=‡v=çoU¾1ÅZ>qç>˜Ç§>cÝ‚¾ð:¥=é%>‰0³»|†€½�ýÿ¾³¦>6�©½Œ ½¼ä0¾-ÅØ¾îB!¾ï_>Zwß>“E–>¿¤½êtލßO=AÈ/>wsB¾½½H�W¼sˆ·>¬ºZ¾Åˆ>ˆ_¾uü´<÷øA½O¨>`$ü½RÀI=–åx½*‡¾©ÚȽÑwØ>Õ"c=fVh>K2œ¾sˆ¾Há>ã76<ôÁ½Óèþ¾Ú1%½»±—<‡0­=²º”¾.—_=™Ø'¾ <"¿E‡`¾âÒ5¾‰‹=¥Â¾2}­=AžÆ=‰v¤=éõ¾nû>‘æ¤:ªmӼˌg;ÂQ=>ìÖŠ¾3ìØ¾ãˆÓ¾ë¾U·¿¯‰>ÖS˜½ /ʼXŸu¾jN¾hži¾z˜0¾Ò°˜¾ˆ2¼=KaY¾8cÁ>x½¼Ÿ¾\ÝÁ>t ¾¢¹½ì˜d¾c >G ‰¾Ê½%bø=x £=6ã÷½:—¼½Í9 >Ý`‡>Ÿ¨2¿ì0¿»:W¾”f?¾/ß&>Ô8ª>`ÂÙ½@nã¼5¥’¼{:v¾Hòù=~ó=TÕi=[´¦>Ѧ·=q¨ ¾ÒkŒ=~Š‘¾¼“ˆ:Ö¬\¾äp̾ÕkÖ=ñ·.¾˜6½ŽŽß½yS>4¾=óÙ7¾·.±;6¸B¾ÄÖi='^=ý̼>±uË>R˜¡¾_�h½N„ƒ¾WÞx¾°Ïç¼°]=ÿq>o—·¼­_Ö½¾0=>±AT>ɘǻybÂ=I¾ T9=½;£>=-¾nÀêºän[>g;|>4q=,ù0¾9¥–¾¨7ï=AR½dŽo<˜2Ö=!°Å<�ëÂ>ª•‚½ø «> ž¾n�«E>î¾rh¦¾ Ø*=*°h>¦›>uÐ=ŒÀ=u²u¾(®Â=ý˜‹=È/¾øºs>®ãùs>GëG=¥Ã?>܉¾Mš>“tõ=?�;Ô=¸ø-¾µÖp>tš]<_ñx>ë¨â>«@H¾ìr‡=T<½=:ª)¾.~q>¬’'‡É½�?ÛB>¿ž´5½ïŒ…»%Ê–>’X5=“ʽý0?bÐ>E£>›¬1?7]%=ùª?ôsY>=�>Y6•>ÅæŒ¾‘;/>S@ˆ>Û(ã=°éF=ee�>…tº½¥�>Nî–½a4Þ=… ¾w?!r½ƒ¾½¾áE¾Ûà<ëÒº¾•ž½äq<ØØà>n²Ø=~Ž5=¯>ö=z ¾?§È>ßʼ¦a‚>\†�¾á‰ì=0>?3¾D8.¼ÊÍнÆý¤>ðÏð½` ë>õ0h¾ ‘¾ë3>p{ô=n–=§]J¾ Âw>T¬a>ì1> Ö@½¯S«=³=>GI=>g‡ >Ÿ£Q¾…'4<ôìÓ¾rY¾,>é¼hòÓ>€s[½µS¾Zç;Èp>Á‹K¾ž j>]æ¿?ë½y5¨=S\–:�ˆ—>²_>ør=I ¼~~=�6>ÈܾYë½ÿ“R=«ÉR¼Ï²ß¾- Ò½¦šI¾âb=A᫽½Ú=6�¼ÊlŽ> 6‘>9¹?½>cŠ<&¡¾½²¶>ò1Y½y¨Ô¾³X>OÁ½{õ•¾)ù¾�Až½Ÿ'…¾Ö¯U¾Sld¾Ç—,>.¢˜½ ͉½æ›f¾èmÓ>©}-¾�¾«Ð1¾,C¤½R"ñ=˜t¾±Pͼòi�>Æ|§=änĽùèB¼ž�>üÌ ?…²¼ÇÙ®¾Ø`Œ½‚¯>FV.½±"´½|…Û½]¶G=²ì:>Y�¿]qT¾ î«=þô*½>Ó;)š¾2ß ¾.%…¾6Y�>Á옺+f<3q~>˜<.¾„Q4½�À½c%=<Þß=¤=¾N9)¾V¡½/�>螆>nåJ¾7Š·=V‡2> ÷¦<ÄiP½�’½Ž±{¾iUØ>yК=´o>ÔC…>ì¼wb½G£=YH”¾ìMc½0&3>t‡>�c ¾€Ã >ú^‹¼'̽·²Û=¬ ö¾–>¦Ð‚½2XÀ¹ÿüž=Â(‚¾b%>*æµ½‘k‘½Ì/>¨ÄC>Î>JP»½+sô½:¸¼�)¿=éñؽ;;5Ïj><>ãð½^ ø=±8—½[>EÖ¾ô®½¸8†>¨ƒ=Â]Æ>ž½¾×­/=ŒÙã=Úº-;1"Ø>¿¾‘»gù¾jÞl¾­›”½&7;¾„ºŽ>§BÖ=N!޽›W½­ÿ)>u*>y±H½F|=±÷Ô>Ë\>:}ؽzÐ6>R]W>$–¼–Œ=lƒð½õÜ=¼Z°¾‡Œ=Ê×½,Â’½8êu�>Šžz=-줾ï( ¾æFó¾àï=®�[½”f‘¾ÃÕP=0ù?á)>nÃ->‡2Óyþ�Wš¾� >LO‘½G2D¾›ü½S“Þ¾ãoý½ãa?>ö_œ>·ˆN>ÆÂ޾u˜R¾ 5™¾óâÁ>$CÝ=½`‡>/ëy=Ûaa>jS ¾Ìöû=€v…=肾à >?•�=kÍÃ=¨Ü½¼k$ >Yœ¸½¨JW=ä‡Ã¾!ƒQ>œ ÿ¼áyƒ>(Ë#½â¡®½yý½¾½Ý¾ ¥�¾iÄ„>Ùã>Ô2 >kz¾ÿQÝ=bfÕ=ê]ÿ=rÞ“>ÈY‡>‘ê¶=ï G>€Ž\=G=þ½+Ñܽ —/¾9.>;ͼ×'Ú>ý„½�ºö¼º)Œ¾}Òµ¾Z±¾]¨>»ó“<«QÓ¼YõÜ>ÞL¿¾»Ù:¾}q�½¥NؾÚV¬¾.—¡=Û,¾�¬q>k`= q4=zêÇ=1ƒ>§É ?Øïñ=4ø×=-¿u<œ�â9ä ð½ß£>½ÁP½&Çý¾U¬ ¾X•‘>àý?†û=v†~>©å×>´wa½GU.?tÒ;½­HP>bäÆ>†2¾°xÙ=·¾Ê•q¾°¾sB>”:e¾ÃA¯=†£§¾Ò$ù<®ã•=FIÁ<í[�>ßõï½§ï<à²Ò¾ã^=ú¦{½e¢=ʘ¾"(H>f¹,>«Í+=¸(K¾Kšg>Bú;>'[¾à÷žyÒ<_•‹¼Xš>=Jæ;ñ6�½§s>û �½PÖ²>xT�>üùæ=ñÝ4>ì×ñºt8?>Rs»¼‹d¾Ã‰¼¤ÛðºëU–½D«=•†–=í0>›4콥Ѿ·*¤=*>ú=<î>tY°>ÃLM>_mÆ=i„1¾KVƒ½[ˆO½¹¢¼=”?¾Îû+¾î¡Š¾Ô` ¾�)¿ ¶`¾Êd¾Êàž>¢Û­=¤ç¤¾‹ß¾¡F$>„çô=ÝF>ì”î<#p3>Å+޾=Y_>Óì=�k>YÚb>’Ì!¿w|>ך>«Ã>U˜½Hú½Ájš½Õ¹½Ê�¡>R_7>PæE¼�̽¢’”¾(§j=M¥>ͦ=,^&>ñ@¾Ñq´½n” >Mã2=4ȇ¾-(.> &ñ>4sµ½<”‘>ÅÞ¬»^Š >YÌ>sŸ=Fƒ…9Å >µ¸ã=:�‘¾Ö¾z>©¿½¦y=&V>3½€<“`>ˆ*>òlâ½¢㽎Ë>R�ú¾Õ5ͽ"%<¾1 º¼ñÒq>™ÅJ>|"ϽIÃ>0M¾¶L¿G =&Ý >-Ͻ9‡’½õ‘€=sfÈ>�ÍK½ É“>ž°¼Š �½uX>*Õ�=°NU¾Õ±o>U¾Ö‚·¾¢Q¾€L ¾É+�>(æ>ÝÒi>�”M¾3¨¾>r€¾ö*‰¾z¿©>*Ü ¾Gÿ½t´c½æÛÿ=ô¿Ú<�?ö-+>¶ñâ¾åØr½å,:>mïø=~>l9$>Wrü™AD>&r&>)<Þ½­m³=÷¿K¾œs;ºÙ>ö&¶>Iþ½¹À>¿is¾´—v¾#`¾_Â>pýÂL®>{Ân>ãè=¡Á<ú!ä»Vß>Žm�>ˆ¾è¾Ý¾çÇþ¼T>àø¨½mðÎ;� “¾\:)=ïÑ£>?1f=À8Î=Ä}'¾Þ]c½ †‡=-„­½÷˜=0Ü>ñ�¥¼Æ=½Çj¶¾¨:4½^îþ=-µø=®3V¾1Ú€¾f(–½Ã©ä=Óyƒ>çTнhí®½?†¼Ur¾�®k>2ÛP>ˆM½Çt¾³x×=ªk¾ôA꾿‰>Ûvþ<' ¯½º1Ù½A {¼áJ¢:J-÷½’;¾ìgp<¼•Y¾SBÅ=ë¶½uÂ^¾òK÷<#÷);¿z†>F¿»Í/>=2>½ú‡>û•=j¤ ½vÕk=G¯�½e'=¾Ç¿O>ÛlÄ»•+ƒ>޽‚ о§A¾Uc;>#ذ< ]>£ÓI¾2Á¾N á½ûZ¾Dqñ½» Ÿ=l̽:ÉTi>­þ½ÿ_0>xÿX=ƪ">…Õ½h€º¾nª >_l½N^>{ŵ<=Ò½®u3¾%¢3½—ÕÁ¾—= =¬Ê.½Yí3>±²>\8¨¼¼Æ�¾8 Ô¾* ?+Bâ=Åe¾tÎÙ=üsj¾23š¾�,;×i?½=Ë=œ(l>�ª^¾G��½O¾òè>©á-ë�8>8É�<þŒ¾i4>{™p>²X�=þ@�=&H²=Í‚’=>Z–½ñRô=íý0Ì}¾ì¦Ž>5pâ¾#{̽Ð-¾t‹k¾¼÷¾Š š¾àmy>¿£¾/>IŒµ¯\®¾�°£áˆ½Ú‘6>`IS>²$c< HB½7‡P=Á¢H=L�¦=o¤‹½2ì=<[ >jrn>g>q>-�Q>¬_�¾õk¤½5� ½(2g½D‘½&ž‘¾žÍ‰= ÿé½å~н}ì¾�!Ľ 5>~Z«>Ešã=“æi¾h >ã%M=Æ|t¾¦/q½ÞvÁ>´¿=Û`�¾§ÿν`öB½XÊ=CMÒ½�–>­p;4yA½‘¾FŸ‡>)I‹¼¹æ?=3½²d>Hºê<h¿<휽,'=9+º¾Ë!ˆ=—<‚ö=Ôg°½Ù >¹ìæ½dJ=+�¼Ö�º\0 ¾í„r=¤†è½Ó=)/=õoA½Ý,y>%V1>SVü¼Wm½Œ»i>ùF>0iÃ=Ôa+=jŒ¥½ò@ =´ÞU=F³ä½cð²½B›½›“F¾œÊ¯¾<îc>³ß¾¶—3>ò.‰>_齓yP¾Áª4¾‚�'¾CÁ >Ž6³½Ùr­½/O¿CiY<ô"G»ò¸Ö=øÌ™¾We&½Òl=õ4M¾¶JÀ¼Q0Q½%´½Š×¦¾³Ö”=ff¬¾úRû®TÔ=Ïe­½RÝ�=‡ôN>¸Ó‹=R >�ùN>å×�½XÖD<`¯�>f¬¼Äw¾úwc¾{Ѹ½ñy½òܽ†ž»\?à=aÚ½Õ¨J½ç†>Ç*g>Òš$=�–Á=Ë­)¾›O-½y½"Ú)¾µ2¾ä${>k•½ó�è½âÅ ¾õ'½†>Q°>*4/¾N+½Ù4qt½>B>¯D@¾Ýž ¼És½{Ú£¾å+±½*û†>ló&½^PZ¼Á½Ì½ÀÒð=Þ7ľ ¶�¼[XO¾jfì=i/k=Œ;\=kãê½°wk¾²¾->ž‘T¼þö:<‘_À<Ù Ñ=ŒmÙ=$v>®NÛ»äÔ>윅½ªÏg>Ž|X¾UúÆ<‰Ä°>~»?> 9þïçß>=öU™¾L½¼ä¾É¾tÔÀ=ñís¾÷œH>!„´=;•C½ÿ >ø~¼¾+н ¾Œ¿½À>ã=pØ�¾#+¼Iü$¾\ ¾ gQ>¦mÿ=¢^O¾™´>õP>–>ÃR ¾Ï5±½HÖ—½éÎÅ>’Ñ»‡p�>ó ½C”D=‹²=åYþ½(Ÿ>Q ½bg.>þO¾¿+³=ÒHͽ  ¿ü!Â>,ؾ.i!½(ºo½QE…¼rе½î&å¾rw’>8q8½b==þ¿n>0ûνò©è>šY5¾â°¾ÝÀ½ r">‰&A>J “¾5À›½I¢!¾C/£º²¾ì=•Ž>hm>RE¼ü“´=ªöƒ¾æ=Ó=‡v>nF¶¾åÕ²½ `]¾O‘ï="¥6¾ï‚s=*ƒ>�Ç™¾cdt½Ä}—½¯`$¾s¤L>üY�¾•/>=�'ֽʿ· ½áY¾gµL>Á5‰¾¨q»=©÷J=xÓ„>l3n½f‚W¾–-¥>Üðh>øx€¾%øþ¾¸.">ù‡*=òì½¶–¦¾ ŽÚ=ž¸;ÉL¾rg›¾¾n½Ö=Û½rz¨=3(—¾üèó=þ‹.>-;¾DÙ=%B=r–½¤8ç¾f•Õ½£Ö=$‡“¾P6�=wð½àÂ=¾½´„>@­1½qÙd=vC=Tp2½òfD¾µ¢Ú¾ÅúŒ>ãùt>`TC>RŒÔ=†f_>Ë g¾W >„çL> wN¾9 ?2™z=aЙ¾ÎÏý¼¸î�½%|Û=çò½‡\ã¾¾ßk=ÖÛ<Ó>v¾ª=*mÕ¾Õçe¾PdL=ˆ›¢½\uö>*f2>ÍzU¾l¡»tÞâ¾»6®>Ø•= ,Î;Tg¾¥�ƾ?h!¾|…þuùã=¸çÖ>öL=u±Ë>e9l>>ë=¡Ú•½6oý=M�q>vc >Š�q=‚¼•=–ç'¾¾˜¾‡­•¾Ò„Y¾o\¾Àž ¾híz>rt>Y6]=ØgT½ë½$õŸ½(}¾›?¤=P�;½úͼÚo!>°©‡½ól¾r¥•¾,ú|>.cL>^“�¾�%Z¾–‘>à×¢=ˆ|œ=È2¾û½Î½~¶>³}Á>Bç!¼ŠXß=·ß%>¦0œ¾“ç ¾vZT½ E> û<^'‘½œ=��„¾:S¼Û¥¾¾ž‚�<4¬™>ƒ‹°¼]/#>c¡½<—Þ>Æ®¾�@¾ ¯O¾Óß¼ûñ޽øU¼/ƶ½Ä~7=ëO>Ƚ½»ö>K>,Úl½';‘¾…饽âjˆ=€¬½kf->Cƒ¥½Ž>'>?:¤½±ÖU>«ûš=Íš¾T¾=%"D¾$åè=úû’=5ì¾.H°> á�¾ä^ê=QñÐ<$ ·;e=6>ÕÄ^>äÌì>0C$>•‰=qs=&HJ>Ô.¾Px˾Kk¾qŽ ¾Á›5<‚ÿþ<ú�¾@On¾a ©>m.p½�ìI=!“©>âô|>H“¾t1”=)‡#>^™ù=&u>Z¨o>�-ú=m,¾Ÿ,ª¾H>a½Èžƒ>~¨x½ /!>³§®>’ß‹¾Ã§N¾ÌΤ=$ð¼ TÃ=Í{’>‘¦ô½1óܾèÓ•>áó¹>¥×B½½9B> ª½s¾Ê <‘-·=‡‘#¾ùÊ>!"ˆ=Õˆ>¾JA3= èѽÓt=ߨ½K˜Ç½#š·½CÿÜ=âZ½Æ#—>âó=&à˜=T5J¼¼ »Ùz!½PÚ‡¾~1D¾Ã†ß;Ô¸µ½nçÐ>b¨Î½Çx»¾<•?ºÃjP¾rX>iw3>H«8½�9¼©�­½ŽØ=jH ?ƒ2>­w¥½ØÝ=S¹>6½‡k=e³�¾{[޽|Âd¾uÖŠ¾É!?¥¥3>3Ö½1%¿´r<4x)¾´K=>‰ß@> ¬�>ã=¾˜O¦¾°L¾oD…¾š¹A½iÇߺÙoý½œ>ðñ½Ó<ée+>À!½­Ê‡¾ ɾÂë,>¶[Ľ×c…> ºã½ç'½mÔ>Žõà»'ê >w`L>ìp>(c1¾ä±>"J€>*eÙ¼¬…¾™ Õ½ÂÀ=)!Þ=°¤¾\Oh>FYß<»k˜¾M¹ç=tpR>¬Üš;|¥ª>ü\>XBh¾F¹=¹%B½@Ê >µJŽªþ<> ݾ ß=Äiq={™ >4\D¾Y¯½×‹=dÆ>kL¾á×>x>>æJƒ=ˆ,â½äwÕ¾^´e¾©zÿ="»=9­¾c—6<þ=zpJ>XB#½Nbt¾ÀÞ5¾SX1¾@—¿&l™>'-ž>‰Ð¾>O=�pò=«62> ¤K¾Q†û=X¾�ɹ=—Q²½ðYú»î[>‘;e¾-ì ¾lßø>€«½�¯Ö¼.4„=Ûʼ½„˾R‘н»…®=$#S¼4b-=ý)Š=3‚y<Ê¡`>±úľ™… =¸t£>‚ú³=gqÜ»/¾ª€>æ�²¾¶˜m¾Ð/¾½Üˆ>{B ¾Óœj½I( >c§ý½€™†>'Ѥ¼Ž“´½®YŸ>Þìà¾Ñ”Š=SÚ‡¾è=žxs>�[€=Äó>_Ñk=åY >²`>bõ>_eš;³Áû=Ãü•¾h½QÒQ>3àz>ëùV>õŸ>ƒ—Í>¹Bß>Ll޾y“Î>¥u>ƒ¨Õ/<]¾�Û=IFV>±’>oè•>ìD¾gÓî½õ™4;ÄŽä>·Pù½Àä>™%>J>Ë´Œ»ÖO¤¾‹Ô>`z9>ݯS>%>»=ö`>:Êb=._Ÿ>üß1>%å+¾ï¾žï¾€•×½ø6Ã>˜f >£EK»-ØŽ>JFæ½îQ7½UŽ£¾E#»RkJ; §>× ¾§”¾²å>[Ò½ÊÓ…>bB¾—¢é½ŽúȾ4/ž><åu9³Ž=R[½¾èôE>à˾•êl=Kèü¼Ef½þçŒêèJ<)ZE¾veÆ<@¹*¾çÖ‰=ÿí¼¨5¨t>Yñ>'£®>Ú0[¾¬¬N½T®ºŽ}´>ÐE¢¾Ú1Í>)¹ß¼¨þñ<™Ûº>"Ï!»ÉŽÕ=ÎÜk¾óHË>Sè/>í¯�½âpa¾&9Ú=¡¾½Ð>uT­>Çh¾o!¾é1�½”Dí=�½þ;dž>ÿÂØ½¸As=²Õ†¾ð >6ÉH¾VK6>¡ÌÚ½Nw�½ä.>kȾk�U¾$ØÆ=|“¾mQ¸=kEü=Îpë¾]Ý'>…Dv¾Äh¼½iý!¾fÎ=>\X—>í$>;E4¾ŒWö=ýØÚ=ó%“¾˜½=�÷†¾ è ¾tQɽ œn>Å$¸;Ë—�>\Ò>ø€:½’çvH/½ÔЬ>ÖÛ9¼¹é£¾Ÿ7L¾0ß)¾ÇØ>lp˽~Ћ¾®›ù¾i/d> L¼>¡´;¼Ï ¾ïôŸ=(à¾ëº‰=?GI¾~ú=Íÿ=Ý€ ¾š«ž½“©Ç>|PS=>móÛ=.;о±ãN>Þ)>Úr¼¼�)N¾(õ¼j»=mH>5´¿9‚<úF¾(Pœ½áÊí¾Zg<Ÿƒé½0­¾ÁÔ·>íŒànŽJ>»ì¾¾Åα>{6†=T ¾MPÔ¼]¦=ÔȽýn�>Å®™»Û[½Âؼû0 ¾·ž’¾±ïоO ­:Œß:>AW¾ B¾)€=p,>aQ꽑»qɾ(s>`ǾA�=.ù—¾¤> #F½šX§<·xY¾€Ll=îaJ>2¾½T¾ò#‹<7âí¼áÏ*½ºôe=±Ž¾ú6^=ZÕž>›Ü>ªÒÅ<ª– >�…–>pA/¾—ž; 9�=ÀËö¾^×È>Fäâ=0 >È>olÃ<$g¼>Å|Ö½Úu¾Ã³:½ÄEã>HA>ŒG¶=9·>e±§=vD»Ös{½ŽË·Y+>¶¨½Ô¸ª½m#J>�Ô,óÝ=¯R¾|´)¾š‡>»z@¾·Ù¶>YLû¼þBȾ]ë„>ØNµ>~Ô> �=Ôˆ¾ÙMF¾À›S¾Ï >³º¸=CÖE½–^‡½‰ÚA¾Gcƒ=“¾{Ò·<Æcd¾�ê=HÙL¾Õö’>-–¹< žÅ=ûûQ>çÜ4>¶˜ì>Z4ä½KA<>ö�¾ÛÕƒ>N@¾ˆ=´¾ZÖÞ½ÿ~¿½¡²½îôŠ>ÿG >ÁR[¾Ð/ ¾/½ÜC+¾” :‹6>›º¶>aÑ> œ½î…þ=°Õ½ö×7>yÖâ>퇾, ¾�¿%ºŠ e¾U¾ôë¾7ï2>žr ¾å¿©¾\K^¾‰ïí=& >ÿ=̦=¾X/×¾@“é<ü ½ £=4þ½Ô?úÏ">æ j¾Òn>ÒˆF¾ƒ×=­‡>xÿ¬<ö½gè´½**þ½€<ºÚRË=¤}ˆ>ðŒ ¾¾‘.>ê_’>ÄÝ=ç&Ï=ýù"¾ÿì¿¥°!>OÊ=Iþi>ã…¾¹FI>»ø½<±½'BÞ=Y�j»Áÿ½>Ë+‚½<)´ú|½Où>ž7¼¬<½"¾�¢¸½¨ç[½Ôl >?¹Ë½oÀ>¤çG=Õr}½.;k:ð9+¾…­Ž½B·å½ËC¾ÿ =üœ ¼Éñ0>{ت>«…’¾(·¾—€–½µé`¾¤‡,>‹Pa<¬ý¶¾ñ ¾)˜Ð½†Ð}=o)Ö<@“ø½¹£<¥M2½TÎx½;=£9O½®Óͽ ©S¾|¢@¾?­ >å΃>çš…¾¿%¢>Kߎ=u_–>ÜËܽ·M>9Pq>2ó\¾a“+¾pÇ+>Ò#'¾Ô� ¿hÑH¾L0T¾æ“,¾f«™¾‡}ù½ñéõ=L�½ÿ…@>Ër“¾¨"¾lἺò=wž^½Éœ;½)ˆ¿>ÿ’K¾¦Öc>Öl’>ª¼Œ>� ß½ÌòÃ\د>2ÈX¾•WL½Kz½\¹=t{½´f¾‡ €¾}<Ã=[îd9€ó7¾%/”>ÔÚŸ=fƒ¥½y�‡¾¡?¾ÝÐ4>!€²;5÷¾ôƹ¾–¾º>hüO<ÛÞM½‡á¾'Û½A�=ÖÛ=ä‚¡¾œff>{•ó=²ý¸=f&>s Ì>`™¤>[„>·é8> g=ÆË>r~ÿ=¾Æ”¾òx½Ñ�îL¾n� >Ë4Ä>i¸ß½"¨}=†Ä»¾W€û½gÐó<® ¥>óɼ¾»ºÓ½U_*>˜Ó¼'â=1Û½óEB>.è>l^¿…胾¤z³<’ÛÔ=�©=÷ÿ ¾?…>[ÿh>­x2¾vˆ­<5ƒ7<`  ¾×d­;Ú½¦¦-¾³»¦>ýÓÀ>"톻–¼~>Æg@¾Ÿ�¾U«Ö>5®>/“¾½\®Ê=WÇ�¾b¦%½`i­>g¦•¾¯{¾tSÝ>’_Ù½vYR>²q&>ìȧ=ì¾>oÓè=ºI ¾'Qʼ/¬ª¾XŒ=}§>Gk >óý�»Ÿ¯>>ñʽy¼Š¼lR<÷ô¾&“½xL¾_>¥»Õ½à%¤½É&ú> ¼½4=J,>ˆ í=të=1bŸ>à)3>ÖžÕ=Uof>û�d½vÏ9¾´Q ¿*Ò=‰ŠŽª¬¼= –¾Fús>ûؾQ”•>Õ¯½¹ï>XÛ‰>„ÿ+¾ bª>Çj¾W9ݽ~ow¾�=Ž—ò=:¯…>Šø·=²k?•g˜>j·y¾?7«½;³>ìð¾ïw.¾‡É´½"iJ<ÒQ°>»ØÕ>UŒ5>5ë>*(V¾Í¨Ï¼d¾gr ¼%Þx¾‡ƒœ¾vZå½}¤#¾½Ì‹‚¾+„Ù=;DRºÎv¾ =–¼ØZ¯¾°¬ð¼ ïf>|‹ß¾Û&Ö=0&§¾þ j¾hŸƒ=�Ç >°²u>hT¬;¤Ž=ù›Â¾wü‰¾ô½œõ>¢nV><²¾“Y¾c‚>ò—Ç=Æ�Õ½üྌU=,>¹>¯9¾• ?_åA>œ2ß½Ù›u>Ⴞ^…ÿ=bö=§;¿Å±ä¼|p>�Èž>)´®=„~½!!ÄïF[=sMÅ>ö¯Õ»8\o>Í`>!‹á½�¼&¾÷šó=<Êú½CT�> Ý[>åk¾"ÝŒ¾=Ò¾WŽôö½ðÓaÿÔ©<ˆÄ‘¾ñÞá½�¬‚> Ô>²Ñ?=‰A­½F�¾PŒå½§¥ë>»xï½ë–'>¾Ä3¾Ø�¾L}¤<å&&¾Å®ô<ak=ª»e>ó)>›F¿É÷“¾ÒM>›¯‘;vf’½ORã¾/\ì¾GÃ>°›�½×—?`”©=-N ?/`E¹#´½›‡I¾I½½Íy�=8'‚½,R~½öDÞ½Žð¾“à ;h;>¬«>·A™½0j¾ ;-¾Ùbu¾ÀWó=)~>��N>Ô;¾q¦½=ht½_Ò=K>f´j¼p­¾‘�<½�³‰=Ã÷¡> ãô>eÝ=ƒáö¾?9>覽¦NÜ>-ñ¾‡Ú=�°=v:ú¾JɼÑÐs>޶ñ=‘G>c”¾4>Ç<¡|…¾Ë8¸»î6¬¾’Ú <ìÀ >âêl¾\If¾_Gq;¡G¾XD×<àÆ> ¨¾¨mp>Žg¾éíݽqÓœ¾û==þ[½>9¾j¹”=ñ6&>{ñh¾'Ò+¾rUi>!>¾pÆ‹¾ŒB>À*‚¾f¨7¾Ž>°â ?V¨‚>�/>QGèJŽ>pÀ>~La½¯Š»z*N½Âèò½½¢Ÿ>?U½H?|Fû:£¥ß:ÿ˜2=%ü’=lcz<Ödï½qÕ¾>«r¾ðâ>U*½9á>OW>L%˜¾2äˆ=èòÖ½¸v>¬þD?æ<1¾_¹˜=�Ì”°|‹¾å./¼ ‘)¾Q0 ¾‰˜”¾V==ìc¿«×˜½a›=ÒÝó½™o>!´=ØŠ^>tq=£H½Ó›>Zľ7|ý»Ì)&¾‡�¼‡õ6¾Cà½(¿¦¾+n=zö¶>Îùw>È’Ë=õQX>Ãs»7 ½ç=½­�¾”|.>¥Ÿ ½æ·Z¾Ÿ�Ð=ôÇD>j­Ž¾_c¡=á­:½•T.?³›×;òø=óU¾öÏÆ=5¯ù=è*±:BÃY=&^ö>¸3>ƒ?“> _<_î…¾¹‚|=—õñ>›d²=Hù¸=“I>‡¨=ì,>¶ôž>|£þ={¶^¾{qÑ=Àû>IG >¡[>RêÇ>n)Œ<ÜóW¾+y†¼\V¾ÝZ{¾z˼¹Æ ¾Eù”>ùu ¾\wc>/Ú=”,“>¢â >©Äø>|-¼ƒ ¾dξ^Ý!¾Ç1¾i’ó=éɇ=¹ÊÁ= ^¿Õa¬¾U>>G¬0¿‚à¸= †ÿ=XAY=äC{½/ 1¾Ú¹>Bk> ÿóe> 6K¾*fƒ¼x¥½Ì|I½OP´½¹7ó½Ü/5=Tñ2¾§z‹¾Þ2^=lÙ.=–…“>­Ðͽ"‰Ï>÷Ìú½îðľ �š>°]ֽͪ=ð<7<ý¨V½×µ¬¼¾?µ>Á²Ù>Án>ú†¾N=]>ki=Aø7½ÙýÞ<á4¾ûû.¾ˆì½>Ø>q=Yà•¼õ¾K)�¾E�—>`Ão½<œÂ=w¾áæ�¾‰Ø¾EÀ ¾$˜£=¦[8¾óòð=l>å ¾÷SºY&ľøƒ‘¾KN½,Ú!>Ó>šü—½¹øH¾bJ†¾Hÿù=�°½Ä3=„ÊS¾òP>�…5îš=TV9>Ó€~=�œg=Ýt=¾ESS¾Òý<Æ,6½�·'¼X‡>µS >[Æ=ܯÝ=–Iz½6I>3l½Ø{¾¦‡A¾ì)Ì=ÈI‚½qn>8A4¾�z¹>µƒ>Fûó¼¾}ê…Ý=URð¾yã>=e‘�=43´½ôl=S%E<­;D¾Öàâ<’ >W2¨¾¾Í-½Þ�I>ÄÞ¹½V(¾2U‚<kj¾2‹€½›A>à ½Æ°m=×þ‰=?^t¾.Æ ¾p=þ>X+=`¼—>¥ú>í h¾¿ê~=D§M½sè">�ê½ü¡´=ïÁä;®¶¾Ô}=>¸Y<²�>dE?=íúú½|7\>IìÆ¾KÃÏ>›Ö÷=‚쌾«áX¾Äå½òÒ½�J†>Ñ¢¼<­¥=Þ8í= Z6½%¾¾ÃÇu=ÂÃâ½ýOý=Ú¼DïT¾ó� ¾û¥¾BÈн½ªb¾ ûr>Éð¾?"N½J÷½ÙؽÐ�`>^· ¾ ;Á½Ç̽K…>Í Š¾ ]¼" ¾Dù:>Ÿ¯>1ö\½Kn>iô>‘ž€>>!°¼q=¶¨>>-P ¾îŒ>¾=¯��=.™8=Ýd·¾|Æ =êùÓ>ˆ:—=l}¾g¾¨½4k¼û¦/=wbA¾B «>¬¸¾>~æ¾S�Õ>l€`>œ'N¾àÐL¾Q-Þ=ÐV½>·~(>G-?r“X=Qù=jÝm¾“ó~>¿ó3>}+>àËP>¹ˆ¼=Y{(¾½¤‡>¥V‰>G§¾xd†>ˆÚ@½B×½‘Ç¢< =…Í>ÍŒe¾r‡g<~ >s «>°•¼¯>%¿ Iš¾2ãY=å 1?5Ú¾¬²`>q)Ó¼:?»E¨=AĽ½A ñéÍ=�v>u=èEŒ¾›Þ^¾òÏj=z-¾áÓ�¼æ0ö¾#¥¾Œ+ >{¬¾tª?³ÎÙ½ßÇ®>úSf¾…zA¾¤ƒZ¾Û‹º½È¾…=©Q>¾P4>j7Ï>ŽÞ�>[Nu¾NbK¾·u>�Þ½–Q!¾6F�½„_Ös¥­¾îÇç½þ•�>=ç½fzB=zßG¾]p”=[m¼� Ÿ¾á}•¾ƒÕΤeÇ=›ã¾nê½±%¾I)y>?C#=~:оI›·¾ ˆ>Τ<ƒ½óf¼ê>“¼Ã³£¾¼-ö=Wè…¾®=JÏ‚<–—½¾Lƾ83;=3CÉ=K‹ >‡Õ>…Ù>Ô÷=)»�¾¤ ²=%es>»•k½´üz=Y‘Š>_îϽÃÄm¾LRé>Pš=%ÈN>NBf<Â'½müË>϶¾ÄX¾­äš¾1„¤»p,u½/Ãú¼?rp¸5L=½7@U>ŒƒÔ½fò¾8¸¶½§Ýô½<߈¾Ë4»¼ÍÃѽœ¾ 8þ½�Fœ¾e§¿=÷d:>êñ†½ ;¡Az=ë>[¤°½‘Ãǽ<�c½]¶•½ Èà<¡†¾“PÁ=×û<Rí>E´Â½Eçå½(*u>P¾?>„! =­%´½¼e+¾|Ü.¾û?>ûý‹¾Ya¹=Ž^=„x•¾Ü[õ½Ò‘‰½®F›¾ «=h|t>p]ó½pbž½,2d>�åç¾6Q}>÷à>(6×¾[ì±<ù'v=kΟ=Pp±>l]Z¾ø_Ñ=ŠÈü<½n¨>7÷¾ÑǾ¨o\=¤Ùg½tỼŽW=¡w¨=ñaü=W¢f>˜s\¾“ʽ Ìú½:y ¾+wŸ½$Ò7¾4c_¾rg½Ûµ¾I»>œ#¾v«>´ä+½bt‡½r±¥=®”Û<'{§=f¸{¾Ü11¾ùKd>s_¡>¦š>½˜Í=Ö¨g¾t¨½ý"À¾®½ä¾P‰>7mV>×LI>CI}½�:ö¾ü²N½Ê¾¾@ì½½¸åó<_'>jP¾gÇm½DUç<¸°¼±ö> ü>摾 ¥>_ìG<=´ÿ“¾ô««¾"ì>9ú¸=Ž1?P˜D=mìù=ůŸ½ K¾>(y>v(>S Ñ=h\­½'b*;}c¥>R ½†€ƒ<â->ã ã=-A6=¹˜+¾MŽ\>õ<�¾ý€æ½“�·=±j>–o€>é¿­>‰½ Ìμ—&>86�½Z¡Q>Ô†â¾èh9¾²˜=Gù4>=k¯1¡÷º”H>×ß]¾ŽÌ¤½³Äƽ¸¦l¾x/ƾˆ5>ßA‚<)-¾;!½@,˽"ö¦¼Ïï¾¶4@¾Éܳ½‡…¼‹õñ¾ª5+>èø¬=§ž¾|¡Í>•¯½:ù»à!ä½ü“½Ã¾WQt=®^G¾\Ø9½pê*½*Ò—½ B¾¢�8=�*=>$õ¾ŒW5¾»F=R1>Û«Ç»>€ƒ>¾Ú#¾QV'¾gDM>¾:¾Ü#™½>ù¥¾%%5¾á-¹=.¢!=ºt¾Î´L½T¾çrŒ=Ö¬þ½Tëá½K6¼é{ã½ h»½ˆ(޾]4=¹/˜>lù¾cŸ¢>"k¾¬—¾��ýΉ=èǾø�ͽaоƒ†×½ûx¾|W„>M ?> l¾;øM>ÂP7<˜45¾„cC½ãyÒ¼Âë>Y­s<“¡½ci‘=øÓÓ=hl¾mß<>A]¾Åx>¾ö=ݽ 烾¤È'=Ú“‹» K%½(ú¾G¸@¾™ÅÔÓ•,>øy¾Œ £=³‘½—”>êì3¾�âr¾G’Ƚ ûŸ½º ¾i(p¾G�>a�q>ì.<•à뾫$=”úƒ=*5å½8ν“…4>±qî>­¾/¹_½ <>U¶ê=vŒ�¾Ýé>$ –¼Ö€>“î+¿4² ¼×…‚¼Y!½ë»S½ —ƒ=vø>˜3%¾�%ë¾äwȾ ¥.>v}·¾Øß7½tW_>ñpƒ½oe½�“½;LT¿>WåZ>Öð½]?n½*Ê>™3y=Þ_a¼ƒÂ‚¾!è{>OÌß¼sª¾M™½¼}÷½×Vƒ¾íÇŸ¾õ)>ÎF½.û¾GSQ=ÃH¾´i¾bv8>¹ý#>O0нäóx¾6ßL¼Gi¬½)ó¯=�›Ñ=d/t¾²8Ö½ï ›>�¼»øÞ÷½ò³Û½¼Uû½´D˽½’¼¢ª�½ùk.<ÑÂ,>h}Õ>®Jƒ¾ôÚ¯¾–«>X&¾M>»Ñ= À–¼4»¾ý±=Þ==xl>¼gÒ�L>ß{§=²¾é<>œEß¾¤Z‹>Ez ¾ 鄾8> ŠÓ>0\@>õ¦a=" Ö>A_=5n×=†ËŠ=NÕx¼ì)¨<¬!œ>|qD>ª ¾»¿=Ó°R<:òѾ»‘?½“ÃÕ>óc¾ ¡ë>ºC�½ý< >Ë]Ö½Ô(>l'¾ø â>qïê½Ð#D¾ÿ`Ù>uO¿<.™;EZ¾w ½²l>±0K¾®å‡¾ù3S>�=«×ª=þw/=Ä2¾<®É=õÞ±¼ä*ν¥ìǼ;3büá’1¾f¼=Òö¾y';¾Ïw>ÄÌ“¾rãÌ;†•оdo>¥©=Ûéi>]�½bô[¾×6I½ZËr¾&Dʾ#ÅÙ>T“==Í ¼Ò¾œ˜>FBo½aK>÷ì?�½Ï>Ž¡ˆ¾·ýe=OE»½Sm½¹ŒE½:q‡=8­Ð¾¿Uê½3Ñ(=Rð >ì|¾äý;¾œ8s=n4¾™Âå=×ü¾7G¿~Ô¾•ºg>3X½=æMA¾ÞE@½ZM½Oâ->âK¡¾¿}\¾p9¶¾\¯á½�Æ#>·4¾¢Ú.¾¬-¾WT�¼P13>Xf¾ëœ˜=æÑ>¾œt€½œXT½Ï>q{ ¾íB=֣½äÝ—¾6.'=ÌΖ=+Yl<–'¨>±>ï]%½Iù=R„>–޽ä~½Æá+¾±¨¾Rõ%½�¤i=˜FË<¯û¼½Ú3°¾ƒÚ*¼M0i>=ž>®lw¼­øº½#—½½‘ = ;´¾iª >�q=‘‘Ø<žòE>²lª¾÷â›=D”¾�¼ßr@¾Œ@�>TR¤¾Æ«7½îO=†„0>Ù}¾z¢E>¸pϾ°2Â<æ¦<Û‘/>:Z¾Àÿˆ>x1>ÿêÿ=›n›<˜¸Ì¾ÝÀu¾s[û>Y{g¾�¬í½Š‰=#AX=·©¾>[4>âD–>ëh—<Ž,ž½e¯5¾Ò„•¾ÿ¤>öǽßÑ¥>4+Ÿ>ùm0>ûã,=‘=8Ð><†Q>Z\à½`Ð\¾›áºñ$S=+“«>%W½ÛPÏ>åhÑ=;ç.½¾çP¾�Q=O…V¾ Ûï½y¾Æ¢Š½Ëž*>™Cѽ×mH¾Á…·½mÖ2>¥??¾E‹¸<;=¾¤·½ž N='ÓŸ¾ž=¿¾Q†>–+¼¾Rš<¾Šk;<·È¾>Iî,>d…]½²-´¾Â+N>È.‰¾KÓv=wm€¾ù•·½YÙ¾•Ê5¾>Ɖ=Œ¸È=¦ò¼ç¢™>7ôÿ½QቾÎD¼ÁˆÌ=�<ò} ¾«r˾{ú¾

C˜?‹ÚU¾)r@>—- >ïgð¾{a|»i=Óâ¾Ëÿ¡=N× >¤>z«½=â&ƒ¾1®>¡&�>ðçï=ʵT½nY—<a¾¦­©>¶J°>øë=>Á‘?oLJ> ,Ÿ½†"7½"§\=qJö=ix¾&®×¼ë|C½# >…#r¾œfÀ=Kú;¾eI…¾õ³>Žx£½Q¬h>¯áw¾jev=CäL>}î >®Âš>QZZ¾¢¯=ƒ5>û©“¾æ¾G¾¼=€¾~³`>.ŸÊ½"$ >ú6 ¿S”À¾¸e=e¨·=‚{œ>ìAq½ñfÌ>C¤Ö½K'¾ÒB¢½Cc¾roŠ= •¾ú ð>K{a<ßê†>q@½™Û¾IYÌ>˜4æ½ h¶=N d¾Ø¢=¢“="2>ZÆ ¾®¶j>’Žˆ>Ÿ«Œ>/^=Áv@>6lC>cC¾RÉD=ŠI=u× >y�¨¾R㥾Á*á=Ò÷ª¼(ÏU=UÃþ=Iæ¾2̾˜¾éú>ÝÉ=}­¾:”M¾¦¦=Ö‹�½âµD½¹Ý澆°­¾ †¾hü¢<¼µƒ>2æ%>©ó„¾plä½Q€>âW½ò<Š>™•â¼  “<Žèü=Ú�¬¹$�¾Ð9)>:†¬½}zz¾Îɧ½GÒí=aJмcÙÞ¼Ÿ)t>¸ €>àŸ€¾À¤²>¤ÇN¼›*2?f ½òý½Ê9¿Hヽz(½.³X½Õ;¾ �¢=Yæ–>꓾Ý`í¼oO>oùa6}¾n¬Ü½§¬ì½‡D>¬˜<yͼU. ¾ºÞþ½¬*¾ôö>a¹I½knz¾ËU¾Ó(]¾}„->°OI¾Ü’>,wZ»Ss˜¼Ä�6>§<žT©½oÛŽ=ëÍ›=3bd>Ä–¾)ä½Àp¿}–ª=Ö‰j¾ä¼=Ä>ä)E½ E¾` ,>yyP>€ñì=¢Q㾂�”½{l¾uè{>Ç?0=ÕžD>eò1<‰¾XLg>S‚6¼®vî=#Ô±½€'Õ¾*Öc=FJ¼TÙá>¬iQ>¼V±¾�73>.¯=kS„¾�Hƒ>³H¼=\>>Œs¤>/*¨½ôÓx¾ÆÂ½Óåÿ=Á?¹¾ÏD =›XÆ;ÝLY>:<ˆq>Žý=«€.¾åœ¾7Pú¾ûâš>3Õ¶=ÁÛ7½ÝiȽgëh=ºÞW>NÒ9>Ö˜½=¸•¾2S"½—°ç<ÖÀó=TKó=Ú”%¾2ù¾Lä=V2¡¾z>·O¾´Éõ>˜/4=ôž¾×rƽ\½½õ+þ“Æ•>Ð}E¾[Þ¾ÆuÉ<ˆAÓ½pz¿e>>Q´F>JZ ¾;Îi>ˆ¾>n;è½Vrâ½3©=¨E´=–u:=b?= 5¾°ÛÔ=—oļ—ã¿>�7 ¾niÊ=i¢§¾ÿ„w<••¼ÄA>S)>&>êEš>:i=Ž÷�½Ä+Ó¼L|F=h>O>›l#¾ç)C¼“)�¾xLŒ>Ø—�=W¾Jx¾Àã­½_û>fJǾ}N>̾è^>¸–Ä=¥•„=€¬>_Úœ>ɳë>×nV¼ZVQ¾° ¾%ûë½ÐS>šÇœ¾Á2¾åúç½â‰h¾9 ­=Ñd£;‰z>ª€*=5ÝE½aÇ¢¾—Ãß=|3¾�Ö@½�ó=˜Ä :XÜt>â0½²”9¾"ÈI¾FdB>º/<,¹½ ¯;>W­¨<ë`¾è½„¾ØŒñ=3)î½z¾•Ð=:`X>hY�>�û”>:�h½É!ã¾ËQÙ=Ã�>ºýU¼Öóe¾Z]¾£¬j¾qˆ€>ŸBv=,ľP ¾\;XU•>6–µ¾>^’¾\l�¾Ô‘Ñ óJ>¼s=Ž ¢¼‹ãоäV%¾ýÃ;¾‰%U>lè>´Õž½z7¾Ü@ɽãJ= b›=‘8¾Œß?;Úî<Α>ö«==í½+Ë–>Š2P>Æ #¾u(¸=š™â;+û™>Èa>�þñ½Ç|Þ¾4‹>¹cn>”çI¾({¶¼ä»È<ÇÜ=†-¾êÙˆ>éÖÑ>}¯:>Hø¨>Ýõξ¦2å=ÀC¤=£…¢¾�€ =‘z†>ò\>Ž¿H>“нj#¾8êJ¾ÌƇ=ø^þ=«Äù»òi½ˆ©L½˜±=Ö{(¾é½#½ ÆU>FÎ�¾Ÿ‘½½ðà;‡+ž½”Eó=q¤E=BgB¾èq¾QL>#ˆ¾3䕽˜˜›¾žAž½BL�¾]i¾øŸ„¾¼c�¼’)I<Ójï=¤ø¾°<°½w­>—S>ìi¦>¼›Ã½�·½ ýÎ<Ê^Y>� > ]�»"R½+•¼R*>r4a>=*�¾z-Ò=ô>Ý,о¿Ì>/3>«Q‘>ì0�=ž8f>¿�½(©‚½€•À=>½¡úi>/Ïq= ÃN>Ýy‰=ˆv¾ñ6¾ž·Â¾[v¾})½v0¬>"�ž½ï Ž>^Ÿh>î\s>›tE¾2´†>¿4N¾}+¾&,=6õ޾¸xÊ=Òè¹½<Ý,>´@ ¾Ô~4¾±”w¾¿fu>ÍPB½†þî>„Qr¾·KľIÀ >¡l©½@3 >Ÿ0?¾”hš½òv¾ºŒ»žK½7ôÞ½KYÖ<ž¼™>a†÷½åÌ«>å:¡>Lµã¼Úž»b•‚½7 ¾ü=¾“é=F³Ž=ü->;Uê=RHƒ>]çX>(7d»ÖwÄ=Óûú=:¶a>�'>Òò½0ÀÑ=S¡½«- <½">{õp½Ñ^¹=|/¾Çec¾ñ9u½z>ÀX>Mfk»ÉØ =hõ!=¿¿Å½{ι>n«ì½TUU>‘qS¾áÏݾ�ý©¼i¢=wYξ,µ<‡™d>j½�j½ŒŸ¾©#A¾ö—Z>”Š¿¾-°s>åÄ=W„d¾^,¨¼5òœ½ñqK¾^Ãn¾Ó¡¾|‚®=vmö¼ƒÍ>£0ƽŠÝ€=c,w½?Þ�¼‡tY¾öJ¦¾ô¦š¾ä.š>‡£^>„°Ç½ý ¾(�/¾yWнÅ"0<Ð:ê=�El=¥LнŸŒ ¾'3¾ê q¾œc5¾ë7<™×>5h±½Ô$¨;ÄÞ–¾•’b>'Mž=0ǃ½Ç"I¾› Œ¾ñÖ>"ü½ìd†='à¾UC¾‘ñ¾¹U½ê>¢=ÌX®¾GBù>ïÿt¾0ï;¾*M޽zÖ_¼z¾á™¢¾G’¾5ô>pìµ½³ø>ÏÍ >˜„–= Ms>;+Á½©®½Pðì=‰g>üþ’½Ÿ½SX¾M?f=çI¾ËÙ;=ÆÃ?ëª5>ìr¥=ç=²½×Ér¾iÉ¿_µ€¾F'±½T¨.¾äЏ<µ»¤=™I”=w´¾bË–¾òÝ:½¿*M=mÑÓ>°˜>ô6|½†pݽ&ľcI€>¨íD>6‚=ÌÛ‘;-B!¾œÆý¼­æj¾+�¾>FN~¼¾­j¾xÓ÷½@3¿wÆ`¾Šý†>×㢾¤øª¾Ö%�¾>ÀE¾rçþT﬽pc¾Ã÷!½ÔÞu½þ7°=v/ý¾­½\¾L²r=VêM>Ò`>”g¾7 ½zÝ¥>&1½ùÝ=Co>®?>e®¾äÇ>4ž}ì–>ê>Q¾(1?Z÷7¾ûœ=¬Xʾ„Fh>Q&G>7ì=îg¿¿G¾4^ɾW8T>â_=ÚP"½O�E>޹½õã½^>¬­Ó=1мÕz^¾ðS¾ÂÄ ¾ û<]oJ¼Õ•ù1|æ½æCüë*¯=ºÖu¾Òý¾ük€>p@_½:²½¾ÉÅ÷=à'ö=V�!¾¨·½€!ð»df ÛŸ9>ˬe=¾õW=H¹°;ð\;v+½9ü¼=»¾ å½¾�7�¼ª¡“=È·Û=BBѽ•r–>°Á4=Õ$*=Ðä·> /‡¾>[v�¾b®½%Lc¾{f=A†›½ý,£½š_8>G”O>j�¼6Z¾G�޾â\•¾Çaƒ>Ð6ƽmžŽ½`A½vÂN=¼‰m>–¥3¾‘>2ÑÚ=fÕ>õu¨¾j† ¿tùºÿ ¡>*€I=Z’=½]>°x‚>®ðy¾; ʽ•>ßô ¾3)=|^#½<ª~¾U�>Y’'¾k�¾8âÂ=º¢½»´»dû7¾Z„½á%‰½x­�=g¦�¼§É¨=Ÿ†½äÏp>4þŸ½(57;„^>­%< ëÿ¼ø»’==ä±=º9)¾’¨!>Ä…e¾„7M>½š�<5ì>OÐÞ=nõ¼—ˆà½•¦¾\õ>ºã^>ñœ´>ÀœÀ=r ¾î~>FY,>ò™™=ÖȾ‹8>+ôé¼cy”¾C¥X>)R ?…¥Ä½! n=Þ¾=hâ=À"<>ٹ꽧G”>ÄOè>�‰À>Pt•¼ :‚>è˜Ý¾ðk½wFž=2Ú@=Ùž >�$>Gÿæ¼î—¼<Öœu½$”½4Œ�>–>ˆƒÝ>v-¾E b>q^>�¸K¾Ï\1>F1¿u¸U>Å. ¾� ÷½þ¡Á<¡H¾¨rª=¡Ö±> FĽ¢¸Ë¾Iö>W(m=Þª”¾NÀB¾ŒÔ¾\XÑ<­—?§pÿ=ÂNÓ>qôY=µØ¾îL¾ ¢§=Ü ¯>Û8ƾUö¾Ó=/>€ø?=ê¨O=‹¾6b¾o N>¯`ò¾QÝH>ÖÎe=±Ü=.‚k¾Ø«¾˜,e>¸xš¾CႽRÙO>�ˆ2¾›�í=‹Š½2܃>ç†{¾7È¿SuŽ%þ¿êj”½Ží¾Ã^?8嬻i ¾¾Tcã¾´ù¼ÚE€>YÅX>ØðY=ˆÊW=Æž�>:~¾<â >3X¾Ðy¼>™æ—¼‘Mu¾e5¾ÝÞ>îš;9#¾€·¬½O@õ¾N7>_º>`ËÞ=;¨ü½î(ë¾áHC>É ˆ¾?ëB?e?¡¼a¯Ñ=VV¾;¼¯½Ro˾L.<žï½2­¾×žE>}žÏch¾(Ï>OÎͽûÅ>8e!? »à>6r¾Á)©>c�>ÿ=õC¾Õz<ì0#¾ R->Õ+„>F΄=[ãS½©ån>M-˜>pÕ->¡ù¾¡vu>4m=3P–=ˆ°Á=�i½§XT>j3�>JÄa>¤¬ž>IÊ�¾‰/‘¾Q×n¾þ¡4>íòW½û½¾õ¯^=O¼¾s¸¸¾áå>F7Ÿ¾½©=¢º¬à™=éª>žz>>¼–¾Úÿ=>+ðÐ>ú¾=?ç>&�­¾«ÝY>QÁ³=W'0¾-xõ¾�Iɽ¯­>âf¿ J0>GÓY½}‡>;²>%ä=– P>–>>%Ž)¾xÉ]¾Ôr|¾±7ĽMC>y¨¾£˜}=¾§uâ= 'j>[¿="ݾîêk=§ >ÈSF¾çËà¾Þâß>X‹¾5ÕÔ>‡Ž€Lƒ¾ÎÚ¸>y鼎„>>kï ?Ž-J>]ª0>I.’=Mg>ZÓ» B>fÖ>š&?T}Ž>(£=Ë“¾»‘Ž>5Á¿½~È3>Å�ö½ãt¾7M�=Š»_=†>ždž¾Û·Õ½¹²¡»WlD?Ùb>@¥þ¼5u7>Œ¢¢¾ÂQ;áT>¤=°»XJ¾ƒªB½�†Ý=¢¼<� ô=Øy¾è@†¾e]½�`p¾½(¾o.N¾-ŠË>” ½Éœ,>2Û†=²]ö½¿ˆ¥>µ ¾„’]¾­,>^ {½/äÁ¼7äf> {¾þ?¾nÖ¤½hLÃ>É’“½|™<ãx=uܹ³ä ¾«[=Ê!U=€d]>�Ž+>±Æ= …À<'Ò=tó)¿rŽÓs>;Ñ`¾gk¾qU¾Œù4>Dù’> ~,¾})¡>ªÕ\=PÂÜ=‘>¤Í�>žãì=bÍ�>lmI>^r`¾&ëÌ<*Æ­½ÇÐ$>A?>0Ýf>¹=ò"Ï=Z+ï=tC=s­X>-½¾5V¾±'R> ¾³C¾/ƒQ½T8¾‰Ç«>5份JG =NŒ> ƒ¾\£²¾ Ç=›¼¾t"¾ÚïÖ<²Î€>ÈF>¶ßô=þ(=¸H>S+û<Ð&£¼¸aļMë¾L>W®õ½($¾x]b¾§.޽*v½�>c>©i= ö=¥ÔI< Á*>t±½uBÜ=šÊÊ<Â(e<щ·½`të>íp½*Ž>"�¾Ï~…¼ Ÿ»ã€Î=CfÅ>;ÿ> ¸¾÷Üu¾">˜}Ƚ `:>ªæ>t4>÷Qx>ŸÜI¾XH¾¹´=W|¾Y¶ ¾±ñT>¯}}>ÊzÜ»Çe©¾NW¾¡ÅI½¯Þ¢=Èê“=X:¾ÚÈ1>åßî½ÉB=Tû<úCܽq6>YW�»Ó ¾ýÖ½°�i¾ª+²»mj¸»Â á»=Gð;Úü ½»ß5>R¹!¾Îÿ–¾Is»©>>%~À¾ÏZ>ÃÍ@¾]L¾\Z=u¯½®Yû=â0Ì=/b潨Ók>¡×E½¶¾®<—m =  “=¼Ñ*¼Š*¾ß{¢¾±Ì½2¢´=û—�>åî;½E=w7S=¸¾0Ì£=DUð=®¨ì»åC¹>/²¯=¯¶Æ½LÉ­½Ÿuk8Âv*¾ ³J>KÆC¾eJ•>j`õ<5ô;KÓ·¾©q>®þœ>]ëM=il½ŽL?¼å§‚¾Ë8�¾«E-¾•�ަ|ˆ>åõâ»Ìv>âÓ<›U°=FåνšL:¾óg>‰’Ô==lY>……I¼š°={e>Ö÷<1é�>:v™¾\éü=ø}_>ñ �¼‡Ö¨<ü="l¾É騽¦È¾T!3¾vÜ>¡‡»×¾'=Oj½ae%¾h->Ê)y=]¹µ¾0ñ6¾Ý™=Òö½©Ó“½DTv¾�x侇°Ú>:%>¶µ+>kðB>™c¼|�>_2¼ÿ>Œ¾`y•¼7ǾÁüŒ¾Ë,>�Î6=é–;p‰w= ç»:£€»¦m8;oßû½7B:>¤á•½®b›>RÙ>\ò¦=vB§¾Ùy?¾ìлK)=×A½)[%¾‡W½#1O=Z&>d—I>lz¾6-¾vpž¾f…w=àöd={O >Œ¢ ¼vý½þÓ ¾µxÕ>—Š>¡¯±= -<‹Â ¾Ä-Ÿ½¹ï=>%ÒÚ½!²9¾€»>4>=·þ>Zãš>�o™>O1=7>l;!¾¢Ñ›¾w¿™¾ 8Ê=�‹â½} >dòs½í]•½À +=ç,¼”¾¼œœ<�~¾øU™¾ñ�Z¾ 7½ê·=æ«’¾¼/н»¹ >HDe=è¾’>¶ê˜¼œÕǽ�”i=�¹)½€÷v>À$¾…[›>}&‹¼l[?NÅ<á)Ø>ÉÀZ>/A*= ¨q½íS±¾öèÚ>ª ž…¶$>:º/=ƒ¾Ö�º½KqÚ=‚Õu¾þÁV=Ù ‰½.ÁE> I>;‰å>¤é~>惿³FÔ=œõ²¾¥Œ½áx9¾Þl•¼3-h¾ ž¡>¡^8>ñÀ=\¦>ɯ¾ÕÉ”=Žw¾4Ï< @_>i¾ÈÚ“¼gP£¾”›^>„ >q~ä=»!¾V Q>Ц:>éÉQ>™êf¾'½©=“j<±æY¾ú=Ò]½Iê¼®h<¤.Þ½œØd¾ Šb½Îÿμ¿xH½Ðg>{b¼©C>D£¾í#-½Ó@€¾ì໎mQ>œU¾S ”>¨¹ <'í£¾àº>¼òš¾¥™L>Yïú<î}¾ a‹¾ $ ¾/~+¾ªž6=6¾[ݳ½é£> á¾›ey¾¹}‚¾Øê=¾æ§>åuh½˜ä‹>dÎÁ=àäñ=#¾=FÞ>sem¾#_½4™ú=÷! ¼Jå™>( K½Ö¯¿»·?;âc½¥¥R¾Ãøj Ǿ„ˆ>ÂW:¾½ÄR=Íì >ÊO}>楖=¹û½ŠE°=é臽}‡¾>1!L¾;v�>™F9¼Ÿs½!Cá¼òq‘=_M¼½O9d= ½™½ ˜·=Ó+Þ½DË=5š„¾D->m l=éþª<¤�õ½éš>pQ ¼ðs>÷)M¾ÅˆÃ=òé5¾�tá½(l¾åýuðž=’ùa¾kX޾œDÈ=³Ëš>.¾4x½"н`Ëɽ1ôÓ¾¶ÒF¾†•ƾ®„>‚1¾ãK¿sÜ›½­ä>ðus>–µ?;·=µT½.K<6P@>ܱš=‰f¾­ÜA>>¿¡T½©ÜÓ<Šfi<ľߥg>æüu¼i©Š½^C!>ë÷ù½ö‚¾o„<ø/@>¤º°= c²>ïym¾N9,½ñ’>Qen<cI½±Î6=6!C>щn½ç¾¥àÇ= €H¾âx˜>ÍWp¾‘c™>ÞÈy>>8>#wª={Iý½3·½ÒÆ&¾ î1=—a;Óõ7¾ÈX>Hé.>hÓ¼¤¤;¾—Åk>1Cº=�¾óó�½7â >ûÿW>\{½ B>™g/=b¹ƒ>šÃT½/F›½7•>7˜á=?û=8uw¾ ôß<½�ú®=_Ä}¾—À=¦S¨=‚“õ½}<=NËx½ÊQ ¾6sJ>ÔŽ…>Âé3¾ña>å›h=I©>µF�=H|Žž“ܽ øE¾4O�; Û%¼ïÝn¾¶U¾­`5¾Å$%=$j™>ùØ,¾«ï>u>¦c¾ïàù¾ŒcŒ<—=hV>„*b=²Ô>~�×»ØX½ÆT>{µ½=Lz;>y5>û™€½,{ë½>i–½ôªÛ½ÚŒÔ=!FƽÝ*�¾©HE>ý¾’Q™>Üú =ž³¾g�,¾pF!>›W@>T+ºñ ¾‡¾*0˜>ì~,>e΂¾þ?�o >hÛy;ºy¾¸j>—EH½y“°½ù"õ=*\¡=ñE>±ëc¾x¸‰½Ic‹<ª&�>ëu“»¹‰™=–w½Vf>\Bð¼ôé=ˆª:½÷=$dã=<ýP=ä¾¹‘o¾›æ&¾ÿ|”¼öÍÀ>J7ã¼¥p ¾–$¯=aÂ!¾�*“>>ÿ5¾ðÔ_¾©b>:Ö“½ª;¾»“§½�ÔÓ¾N Ü;8°> Ûª>Éú!¾ÓD>(Èþ=T(|>a•> v>�'©½„íß=©‚M¾N!¾6v¿ªØ(>—ñ~½q"¼:¥±=t:‚¾,û+>s×½1àí½È=>: W>ß’"¾“c> Aq=²ry>Z¼ý<÷äF=’†9>Ûàà=èû(>—\b=â½ù¼áý¢=¼Õ½áq(½'…í½—pK= ¥>À+À½¥úŒ¾ÍT½Ü½¤>Ÿ®>`>4)>àzÒ=Z®c>Bo{>tºÆ=¹Va½'Oc>dºú=Gñß½/pí¾žAì=ƒ<¨Ì7>ñËÆ¼î+v>AÇ(=ñ{¾R©a=å3q<õnD¾9*Œ½°Ù >=ž>¼ž¾ÛM½¦÷ =ÿ÷>ž´=>ƒ—¾(Rw½GóǽÀ"…½±‹¢> ݽU?c=œ&»¾§#=¾C•>Ní­; ‚‘¾ÞÎE¾Š8»¾�¾)�>#³L¾�ü†>ÐÚD>©·=»@¤ú½.y™>Cƒ½ `=>œFg=.•=&^]¾²Ûž= ޤ¾>Ù¿<»ª“> qü¼YF>uî§>Iþ;>u¾ï½.Y™¾pZ=Y0õ;w×i=ûÇv½¢¬¤=·b<{òi>sâ=­Å=®cнDsþ½ö4$¾bâM½P7¼n[½ƒæ¾L~ ;!ؾˆ:Ṻ>˵¾³Êk>fê¼½›÷½Á[½"Z’½_¶W>zÛs>$·=Œž¸>Vek¼µ‚>ͯ< v¯¾éM=G7�¾m@¾®Ü2¾å³¨¾?>‚¾8¼¾ƒb½´>¶z¢=pýÞ=4õf>:´T¾ÖSm¾·�=m\Z¾£áH=òÒ=<´½Ÿ½y½oôe¼Í�ž¾]êc>™¼>ÀE²;R7V>¥†¾¨Î–>Š!ç½*쓾7˜�¾.Û§=GTŽ=Ãäi>#�Í=ZtÁ>fão;d(>Krɽþ¡D¾‚ ½=”6&¾†^”½QEÓ½â­=6�>_Tó½7‹¾ßñ”>o,G>ræÈ>)]ͽ#Ðv½vg!¾�Èé>ð]–>A]NºÛ¸U="x[¼ô|>ñÀA¾Ë¡=mk’>Ä’0¾‡×4¿œN>$Šn>⌽ÕmG>ñ$‚Y>\%+>8¼ñ0�¾Çû´½u� ¾Éj€=ìÜç=¢Úä½ýŒ…½·u¶¼>àC¾˜@ ;n³½xôϺs¹=Å:½Î Ö=)Þ >æZ�¾vÖI=3Ÿ²½ü±œ½Á§O>Oz¾?iÖ¾ãq«¾Díš¾œÚ$¾ØtÀ>Ôäß½ˆR>ã°=ëp¾ä‘^<à >Íb= G>e©é½'ÞE=âZ=^>‡šŠ=û9>åÒÒ½ŽÿN¾÷1>“ÛÊ=µ‡±¾…œ½‹K®>Ä—è¼Ýh‚½~™ž=)£›=/Ï =µš‰¾7À¾É­À½”~¾1¡ã=T>F¾Šp™½‰®{>×t—=�8‰¼erƒL ‰9<@³>Çļaú¾÷tï½{°=sh}¾ÿ>óoú=”Èý½ŸÖŸ¾ê’ ¾h¾â½5$ä¼<*ª>ê¾ Uv>¾÷=mŠ£¼Jg>íÖÂ>®½Ï¾¦\ƒ>’H->ƺ¼½#bÊ>Iñ¢½[™¿e2.½~ò=d$t>Yé¾DÒ×=oÜ»Bá@¼tÈ�½óä½tÃc¼¨ í;,+—<ñãѾY+ ¾Õ‰T>寀>Ó*>½�æ>UÐǽ¬z¾þUB<0åT¾ù„3=]Ò¿ãZ¥¾ß ¸¼ÔF>>Ô€×=g“ƒ¾ïøK¾#_ɾÉöý=ÙÉæ»Á*þ½êÖ|=v}=0à=¢@=\^¾¾a¬¾ËY-¾TLß½CØ= ó>nØb=kj¾Y/t>m�Ç>d½<_B�¾Eæ-½'ÈÆ¼â®>µ1•¼Û©==p¾j½{k¾—2>³G‡=r>>Z½¾< =Ðâx¾~”½|‘a¾µ%۽áW<´ÿ…<[]º=Mq¾Vz–>¼¹9¼Ì“¾>¹Üû¼HNF¼�zZ=;T¾ ½ùÈ:¾ˆ¾Ý¼u=V’>rܽ 6Ðh&°<¬‹~>"Ã`¾Ìõ’¾™½9í¼ÜÍ==kÅc=q8 ʃ¢>«‚=ÓA:>rÃQ=g³í=`œ–=BÕ­=©¯o¾•7©½¤V’½Æ‡(>>½�> â,>… >ýäy>Ùœ¾ÿ;¢½Á¸ú=Ü †>ƒ¾ày=á{Á½boƒ>ºðî;6Ùº¾i„¾Í�y¾%xŽ>¿£¾{ü¦½m_[¾YÅ™=•Ræ=µã½Û´³¼ˆãY=d#½õ‡�<Ï‘>'Ƨ¼q†{½¦|ä½V0¹_v•=q]¾Í˜8>¦Ú�¾¢‹?Àl�½{ˆ¯¾Ø#¾ˆ_¾å=p½Ùá=åǽ}· ½ õ�¼ìè½jhe½VÆŽ¾K½XÕ°½$Âå=Ýk~=`×Ä>½¤kú<|bX> ùÍ=߀ç=�8¾áù�>ú‚à»NsD¾@ß<-öd¾­JP>yÐ3>EŸ|=¥ ð=±©¾Ëâ�¾¸—=�‹á¼Ÿ™—<Švm=Ý÷3¾6ÈÕ>T„ >�6Ó=€~½CŽ5>Ã׎¾šØª>�~—¾J^©=Ê…½—Èp=vÕæ=Û.¾…X9a–ǽˆ™¬½ �=:>@‡§=0à> —…½²7>zõG<§ >í¦¼ÝÁ¼ Õã=sïL¼Ú=±½/FoÊ*¾ìð³>æ‚Z=oò¾Æ¹1>þÏ>ñN,=ÑäF¾¶u6½¿_ô=Æný=5€¸=§ñ¿¼ðÚŠ>Oî=¬b¢=�•E¾¢"²>µa†>P=Ë%>ºbK>UÊZ>‚r–=¦D=­ªÂ¼ƒÜô==¾ )O>'v�=SÚh<å#<» ™=–굄íí= ì?êf>з<&ºÄ»Ãü3¾òZE>„^¾Ît¦½({6¾F E¾ºàW>h‚¸½`]�=Ñ£›¾Ùý‹>ì- ¾ÉpŒ>„|¾¯›·¾ëc|¾²R‚¸'¼è„,½ž²Í>�©¾¨ò½9¿d¾©äÏ=}Ä»= dï=»Z¨¾EQ½á¼>fÞ‘=ó[×>’ ‹¼G�;Tˆ0¾m+A¾Jò¶;$%>l»6=µ. <�ʾ*Œ6>(ÉF=ì|ò>+ÔÇ=1q½Ú‘>�êZ¾tIå½Ì²=—‘–<Š£>Ï=¶B[¾4­Ù=j ý½;Œè½“qμ[ËY=BO>줕¹©0c¾Ò«¢½�ŠE¾ d6>ó,6>>켺x�>a´K>‡±�>74K=W*=hì·¾ðùؽªø9>Bž> 7>Užq»ûîA>ÁM>á½6?�Eý½ü½6>¤áJ>Š?‚¾áu�½å…‹¾ð>4øš<^Æé=âü(¾F5&¾â >«)½6¹–½ßÉb¾'{ >ºW6<ú¤¾.A^>Œº�½}½D¾Y ¾�cG¾ÒÌþ½½T“¾ý¯Å=;Ló¾  ¾Ø¹8>ÞØÚ½R>[‚»н¼^F_½VÍ=,âì=*:‹¾¢p½µž½\ã¼D¯„=~2伃aš<ʾXT©>Ôúr¾ù¿Ô>î^V¾Qb£¾ bI¼¯a¥¾ÍÚ¾/Ñ„¼È½©=Ü4œ<&É^¾2£§½ˆe%¾(ܼe ½ÿ=ѱ~>‰@¾O'™>:h¾Ë¿ø¼Ï*¾¯!}¾�RG¾ñ½ò>»T¾­G¾ªŒ«½—w¾Õ¾­¡>h#>d¼˜¾ë/(=È©¿½h±œ=1ûß=w”½ãE¦>Š�=88R>JîØ;¨„>Ï6û¼G×£=l#=@J¡=^ºž>ß(Ò=�Á>«Œ=Øs)¾×qî½,�½.¶¾$¡ÿ=a�(>Qä¬=‰;¾ZS;¾‚P6>¤’¼,ü|¾]ö?Ó<,>.§½ÁÁ¤=™µ?=,¢¾öd/¾ìzû=¶¹="5·=¼Èv=œ¹r=½ÖJ=cèÄ=2"«>ÇŸ�>]<©½)@W¾²„Ý=‘³ >éÊ�¼¦>Ø3‰¾Rx‰>‰7‡>^½@É>;V&¾\6^½¶U3¾Ù/t½¯#*¾b0> Mƒ¾|pX>ŒÑ(¾—sf>õ2=�åô½�]=> \½+2e¾Ôôð:îßõ<„VT=u¸­½7�‹½¶"¾]2¦=i}½wG¾ ? >ÏÛ‰> ï!=7Þž>ðC:hy½™w¯¾J«¾>èq„>º!¾r™¾Ÿ‰$>âT3¾"ëɾ8•Â>´$1¾þùn½èæ=Áœõ¼j}+<�ºû½Úˆh½“߃¾À„E>0`8=ÿk¯>¢:P¾ã’¾^z<ÿhŸ=‹À>¡˜g>•ª>gU�>œL¾ ˜¾NŠ<ÿ;Ò=?¹<ˆQ†<7>æx >F•�½äЕ>y•>ô^<Q‰>‘Ô¾®Å—½7—‚¾+VU>/‚‹¾‹´x=9s™¾´š¼µÂi½Ö.eÓ>`=ÄÑŽ¾íw?½·1?>—D9½â=t<ò–½h²Ÿ>æÑ#> >ä½¾,f¾qV†¾B»>NÀ¾üÅý<[!5¾Ñоmè–¾£oF=ÅÔ^>ª3a¾Õ?Š>uŸ6¾¦>¼—¦¾ì¨»2Ø=º>>c»<Ì�á½ðÕ=ãX>+E‡¾íS{¾mµ¾$>>ç†�>9’/¾¡ñ²½u´>Nlr=|a¹½2lr¾çØ5>20>–¥¹=R餾֙>ö©>®¬Ó¼‘Ãâ¼ÓJ¹=$¨¾•}F¾•›é=R$¾Y«=Óà >è‡/>�QÊ»ï¸Ú;5Ì>Òº1>¼¿¼½1çÆ<³H=¼mø¶>PO>—U½Ç%¯¾¿—½'Ô­=�³Ñ>|S‘=éP¬=é˺=»J1¾åcª½ŽL�¾÷0i>®Ê:=ñæ>Ç®¹¾Ñíf¾ÔŸã=¹ŒÌ>*„i¾¿íð¾¸*™¾áÀ»ë‘;>sý<œJý;N+j½ÞÃ>.�>ä¡�½’÷†¼·'^>šªÓ=%´±>—`W>8äG=]`¾ÙEâ>ÙnŠ>PhŠ>ñDo¾èk>S$ ¾‚N©½  ±=\St¾>ǽ¶º½ ;ܽL‹þ½Øw½-·)¼GÂU>V§½êr>o¸ª>Ý+�;é/³=©ç‚>è¸g¾°Ê€¾]d:>¸ì>Z>‚Gå=µ½ŽÇÁ=]*‰¾aóX=ˆb[½j*q¾W[v½Ô^/=€C>.É8¾Ü¸S=L›Þ=éž­½?åÝ=£&‹>IÖ¿>—qÔ=žÛ=‹ð‡=ñL >Çf>Ä:ÿ½†.n>W&™¾Õg>,)>OƒŠ¼ù“Ú¾A˜I<·[­=Htè=òs’=7E@>VD‹=yÄõ¾ŒÖ¥>F�>ZËî½…K>ÖÒ/>J*>›+뾤Òù2‹G>êî¿>Ã�g<·r½þ·…¾lâ@=_,x½¶x”¾´¥>ÅJ–¾Bq�>­@¾›œ½î>¡=¦�3¾DÔ~=Þ:/>-Äž¼•W·¾ä‡Ü=ÿ[P¾THl½�ÁU>Îí±>zê¿ÁÊ=³Îè>õü…>¸Û >£*Ï=W¥n¾Ñ!½Í8½ŒRË=]y)¾ö‚?ºÔ½’ §½b)w>®Š>£N¾Ùs3¾Á¦½¬D[=uv0>6 [>Ý>VE’½ª ¾°9,¾(‡¾þ„Ǿ’¾d¾žÍ=<šqŒ½Yì=Ñ¥>á†>úfιŠ]>Œ%>>ÇÈ#¾ÛEѾøCœ¾Õ€¾m™¾-¾“Øw¾\ˆÍ½à«û½qmÀ>a(¾a#…¾?–ª¾6ºü=Áih½:T¾Yîo¾¶�‡>F‡¬¾B ³>ެ¾#+ƒ¾þ�¾ šó>Óòɾ »’>pwb;9Xˆ>ÑD?|Õ‡>§~½cCξH¾�ݾ©Ð¾gÁQ>�ó¯>«…¾à!�¼ c>�  ½$Rë¾9ÊM¾ƒÐ£=†^*½c3c¾—”•¾Kb>h­ô>tÒ"¿@€w¾?å<ƒkï=¢†›>Ìä‰=NáÛ½4} ¾,Ès=°‘8½Æ8=Z" ¾lJå=›Î=7«¾ ¢�=Ö¾Îm€¾6H ¾³$Ò¾HŒ¾f+ž½m}='–`=ŽQ¾’Ÿý> .œ> `e=›«Z½3�ª¾¢o¢>“—º¾ÃR5>F…½žù‰¾ªÖ>íÔê½§a>i·]½¾š“½Ýù=©?òªŸ½HǽyæX½Mÿú=¬ôC½½u ¾wìŸ>!�?#>ølº=+¦é½€I!¾mc>ÝŠ->F�­;s+™¾.€>̰%>E¦È=™Îê½ú꿹Ë,>"=¾Ô…>­DK¾J�ô ½Ýj¾L¡¤¾ÓÉ•¼oѪ>”á:?ÝJS¾;]>ØÔ½”.ä½X?e] >mÒS<ƒ[> 1±=�ƒÁ>:Ÿ¿dA >$M>•²&¾un~½žÌ>€9£½ÙúR½À]¾hð ¾+Ÿg¾ÒÕt<�’·¾e¯#¾˜ø==wœ-¾È”m>R“=1v£=ŸÔ‰¾ø#<²!½<ÂO¾ ó9¾¯ð#>€Ž>Ýn>Ṡ>{… ¾_+ ¿�R„>1>ñ¾�蟽�& ?W°½(�T<`Ï”>À£¾ Ë<«þô½Î¨>Zfœ¾Mö]¾ºwU¾#§‹;¶q�>fØ(>ÒÉÜ=âòë»ß.×>â&>T™=Yõ’<±·›=âeR;• ¿SWt>sU'>�™£=Ùã¿i½è¿ñ5)>ÂB ¾¤ì€>Ø$>s“€¾·3¡¾±3œ½†ŸY¾©Ü½jSÕ¾µ”@?û\Ð>=º£¾~ùu>ˆ{‡¾Ü•½/”>üÎð> Ã=žs½úù'>]É=½f?h·=rSV=Õ5ܽ_!¯½ëW¾º>Ÿ§¾ŠËã½µúV½Xy‘>bà Àl>>B:>tȾ{0€¼¾ÌA¾ìP0½qm�½ûŒ ¾Ó«V¾”†Á=H¶õ¼hß“>À|_>³8U¾Å\»¾ü>&>N�b¾;çà=•>|[q¾þ=› »¿ç¾—ì º³ðÜ<–á=>c8œ=:¹ë½a¾ð=ú�¾›+¿x­=IÌá¾¹¾nž5¾k$½K[ >&{É=IÌ=0Ö>À ¾{ON½Ž>þ=�A�½ƒÚk>RH§½¶á>’a¦¾Ü¾@ñQ¼Ý<½™w>Aß$=p"ʼâŠh<Ç{Ž>1~нË`N=-’Ç=üVê=Ý/>öt9¾º}¢½‹�(=…(ÿ½Wj¾=¬’>þ†“>ëÖ'>¦ìI¼Í$’¾%–¼=,°o¾I²=¾ïmˆ¾… 0¾=lß¾ð�c½Þ3 >êý*¼íf½ >@ßA¾ªX´½¾Ã$>ü¸ú½þ>ÕýùK¨¼R*î=T¾ñè•=ìýš¾1‰<®”=‚©¨¾¶)½^øÀ¾Zª«½!O“½¯þ±¾éã‰>y,(>,ç©;[±k>©»È½\¾¨½î >˜=�}­>‚©=6Á0= ‘¾°Œ¬½¾¥¾Æã¾0±¾Ýa/¾ôi[>fÛ¾Å)û»iEò=g\×>=›¾„ú„¼ò÷D½ôŠ©=9a¾»ø>§2ü½—_=½�3¾“S½NŽ—=ûH™>óŒ>ü#&=}½¾ˆ{ƒ½±H¾ ˆö®B5=õ�Y>ˆE¾Ìí­¼Á?©ó#>I¥ƒ>ª%Ú½õŸ>:B�¾ìšN¾¹[è>EYº=dyY>Pm¼~2¾lÖ>=95;åé<ج.>4+¤½r»&¾ C;@V™½Ð™š¾8Ÿ= +µ>ìªÂ¾­4«¾u�‘½€µš>Ä=ƒÑ>o‡>µ¹—½©ö¼R [>¹yx> B�>‚“>X n¾¥;æ½®¡�½¶Ä>ïÀ=-Ü‚=`á)¾ÆUa>eYj>)ê^¼2aO>ÒÇ<¦¬Š½î%Ž>s¤l>AòÑ>îûÌ=�*¾L> Ä¿¼²ºl=ˆþ©Ó_>Jd =o?ò¼|Èh¾.�о@‘=½5é=€Õq>èh̽vÎ5¾9«3¾Sæ¢=¹(‰¾f>C¬>^ Ã=Ã�×=¶‹†>ÀŒ[>,BR=�±�¾ÛÌ©¾ð\¾> ‰_¾E§’>ô]¾.Ë‹¾Ðö½l‘Ü=ί½Ž->ÿ>»Aöh¼Ðg >k}å¼2hÔ¼™xã¾'!+¾ïM=|>\úH=F>òÏœ¾VîU¾©¯¾šâ=}\Ž<ŠV!¾ßQ�=é4ˆ>ý(5¾ ƒ¹¾Æ-<¾©5¾ G°>޳½ ‚”¾ˆº/½�Õ> ÷¤¾æ¸ó=L³¾�­À¾þÚ=žŒœ¾ƒ/š¾û>Qªq¾¢ip;­§¾®�ž¾¿ˆ>^l‹>Mˆ>ço£I >í›’¾“B¢;L®=»L¾;q£½«ïö=^ÏX¾Œík¾ÀÑÇ=¹Ç¾Ž >Fš®¾PÏ >(CÛ=Õ¡%¾í‹¾y[Ê>ŒξáÖ/=Qæ8;€ÆŸ>º(2>uƒ>S’“<©¥œ=jˆ>¿C½Õ£×=Ÿ¢l¾rÌ⾤6v>ex ¾àO˜>##£=¡;¾é�¾ªÈ=üë¾$ö;Ûx3½T¦%¾6ù`¾œdœ¾»ß¦=Zku¾EŒ¾m=¸c‘¾©[‰½M¸=½lþ*½2_>[æ•<ÐË¡½vµÑ>Z+'>˜àä¼l ¦½hš¾/X>콚½<_j¾­®o¾¢fi¾m´c¾Äy¾ª0¾f]“¾im­>Þñr½—ÿ ¼nB±=læ=På°>eê‡>Q�¾ö�W¾™›ã<ý&>Ï3ð½Ü8>±GS>ÓÐ=íBï>H¨Â¾ùó8¾pãµ¾Î1= .ѾÆ”=_\˜½îϽ,ï,>‰âù=]Ø>žu¼%P‘½G?R>ý®h‚Õª>¢ù‚¾"–›>e ÿ»z%�½¦(¾w»Ý=ýÐÌ=H„½Á‡¾ü�½½–³e=";Ž>±Ó/¾Ònƒ¾þí�>H>(P>îéļøv†>o’½•´½ìʽ¼³·>D‚ü=\ö›¼ži²>X¡=ÿBD¾Æ¦P¾Þ6>Ö<¼‡Á»ÙÎw=Že}>ˆ9l=^Ÿ.>86•;böµ¾J̵½›Úh>^vZ>§P¾÷uǾþLP¾O© >Û ¾ñ=nI»=Yvß>#ò¾ D¾4>å¾/~d½ÄÃ>öjK¾ :¾¼àã<äò=½@§= ¥<õ¸ò¾E›½ß/å¼öì¢>U»Ò½6Ê=:3T=SUC=5 >»-V>‚Å;º¨=ÑC=…™z¼±EN¾_.…¾ÕÞú>›|>´‚Â;¶A­=Ækû½ª„ã¾Còw>xŒ>ÃŽi¾|½À+ò½Ç¤+>e@{>¬;þ`‚>¾$áö=ŽwÄ>½QÙ½‚E>+±½+ª¾šÌh> Ãú»lš¾oŽ=À�¾æ€>a>AtÀ¾çü¼¶¼†½Ç‰l¾î…4=&V½sÄ ¿\Š)>Pc)¼¶:�¼À[œ½²_˜½9^=Ê•€>X`G¾ȼĶœ>ÃN€<¸+¦¾kp>�E�=;z¢=(k¥½¤�|>°pA»±N™>Pî°¾TZ©¾Ú�¢>1v™¾QÊa¾RjJ½òL¾»l–Œ¼H¾µS‹>K">iJý V§<‡>ß½åêd¾Y�¼¾—±½®­a¾iXŸ½:7˾—¸Ï¾>¿¾ŒóÁ=cš ¾Ô-»>/`-¾\›•>µv‘¾`¾³™½M2¾Ä²´=Ú:>wó¦>~eö½ ˜±¾ã7½=Œ\Þ½™è¤½øJ¶½’ë‹>¬’>o0“>ïð“½a0½¾ß§Ë=Þø=ai¾+®ë»¤3À=å÷`¾º{"=vbM:¥2ݽšF=÷b.½Åµy¾B#>èêl»vjì¼PP]¾½Ç=yÇ⾡M=€„<} z¼r×G¾ÈæH=5¸Ï½ ,»¾’Å>Óv=>ð¢=²´ c.>Ö¨í½²žq½�hZ¾ÓœÌ<Œ‚Y>àœD¾Aù¾³À™½DV¯= –>®U°¾KžŠÉ±r=7æ�¾% <ÂT<ùòj¾ Ëþ»šåO>õþþ¼Žw½Ä•`=Ói¸=Ê5-¾¤‡ï=€›¾Uýb¾Ðìà=pÍ‘; W=˜Ì¥¼ÙÂY=Ï8·"|j>ÄH=‡Á½¾d°=¾fäî<Û�®½óîê=4]Û½ŸA¾‹èg>©�¼½ÅÕŠ=ór3>ÚŠ=B¯Ò=G��¾_?>0Í=R©˜>`r½7bžß+%½…í¾¬Ê ?”dÈ<æ§»,u×½¿Ân¾ý¼Œ¾ Äž>rw>¸9”=ÄàÔ½ÞÐy=ÅÁ'½°«¾¾B³Ô½Ì?>^Ö¿ÇìæÃ½�ʰ>ñm³½e�¤¾¹.C>ÈÙ=x8f¾7?:»0>êI>·:æ=6ÇU½B­»½yçí½WÜ.¾4Â\>i‡£>(þž=½÷Ÿ>D¦®¼„˜´½~ù—¾‡î£¾ï¬�=ÉS¾Lec= Ž> 1ª>çF›=hž½çØT]u¼R“½�­R¾a¶¾>ý5Q¼Œ�¼È'Ö¾±ç0>Å¿u>Hñ@¾aÉý<;Ûû=¶?$>¨ö ¾v™>ó«>¦¡»¾¼p‰½,‹¡½.þ„¾< d¾=ç4>Ö/Å=>7d=#9½ÀPä½:­¾ )¾G…>ܹšèOm>Û.²¼¢½•<(´ðÚïš=ö{¾ÜB¼1h‹=iN>šÐã<žÈL½, ÂÅG0…=2 }>/¸ù½c¼�HÏ„>¢m¾ÞG|½3ƒ¦½ ï�¾Šf ¾Xñ¾ú¼e~ؾ½É>1ɾÚçÏ>Ã>å�=¾&Ù•¾.†Ä=®Pø=5Ÿ†>.q>ã j½7±T¾_þ=¾•º¾Yf>0ž�]'¼¶Ã<(ôf¾]1í>78>¾‘‚=úÊ>¸ |½”Ña½)jg¾“œQ¾ÛŽA¾ ¡X>æp‡> Ÿº/=;éè½P.µ½Iã½s >¾tè½¶Ö>8³²¾È὆†>9ï‰=aÚ—>ô®·=À ¾ˆ5©¾nVO=b1ò½F—õ= R>qŒG¾ó$-¾“­ˆ¾šW�=?V>WŒ;/ܼšgÿ>í|…>rã2½¯‡R¾_k¢½òÀ轸Vé=冞>òZ¾åÑe½Äk›½SâÕ½¿xä½Þú‡>KY‚=æm>¾À> ';½f’`¼0+½5=±¾ë¬$¾ûÓÀ½v‹¼ôW¾ÐzÏ<:¯‰¾Áî¾fÓ(>eüô½`G<ØGm½~½ÊÖ¿½ÀÀB¾*(‡=¥Ñ>žö>Œj`¾•G;Äf(½¸gÓ½ÚË >¶wë½óÀØ>¨¦½‡;¾AÛ=$çÕ½×`ÿ½0ÊÒ½ºÄ>³E”=Ç3¡=° ¸¾=_í¾E=t¾Ù=>««>Æh=²-O¾��^¾V«Y=† Å¼ðÒ>��¬>�=Î4>ͱN<§:‹>æûG¾†C/>@@¹½\X³½½Ç%?7E>©Àa=ñc=(àG=á×¾?ê=ÖcÝ= Ý<=B¤>©jD½Ý™¤>¬¦ã½ÈBr>ƒm*>1¾µ‘>åò¾ÞT=£g)>ЇA¾lm©¾ãš½�;2¦Ž>7Ë=¢>à¬4¾Í-„¾V A¾�ìW>o "½2‘="¼¼j û=—»P>å/‚>*m�=û‡¦;¬½0½s<£ô½i¶Ú¾îgÒ<`'l=ÓE½Èû=>{˜ >¢ÚÓ½"}<$Œ�¾6x_½,L=Ì-È>¯)b=+ð;¾;>Ÿè½�¸>¶Ë¼W�=\pÆ=<Àؽ®¶“=¬^=7*>¾ã¼j»FjϽën>U5§¾Š¿¾zÊ»&¹=¼€R>är2¾N¤">w,5=ÛÅî=kj™<†½„ �>�N.=ìhª=�†%>xª´;I>Œ�>]˜­¾gž¾k6½ÜË>}86½F¾ØÞ¬<1’¾ÿÿ¾¸´@¾ºr(>/Ä=;B¾eLR;ó)’>[¤¬=!ú¼K�¼vw¾àH�¾±×¼@ö—>f˜>ùŒe¾ï@d=ræT>úªž¾kŸS¾³ki=Y> ‡=ê‘y¾¢K�=½“¯0>¥;É>}ý#¾œ¾¾ ,?>H8P=�Ÿß½ÂŠ>‰µ…;Pº…¼Fd‚;ìμÁ\¦>Œƒ5>©B©½ÿ°=,vô¼¬£Ý>ä!ѼŸý¾È•ž=‘À=Mâ½.ˆb¾Þå…<µ¼å<`r>6é7½3Z¾±œ>έw¾¨Ò">Ëx²¾x ½ÿÙY¾ªŒg>É36¾<ß¾94x>äà>H>"Ë:=öÁ&¾á=46f>,ê=idg=Ì˰½L7¾“§WH�>£•äNƒ/¿0Bè¼ùQ½<Ɉ½¼>×S2=�r’=4q>D<8˜‡½¼>0¾'ƒ{=H#4=°sí½y½â�.>ˆªW¼TÊ¾ÄøT¾9„“¾†¾œÃˆ¾/è ¾Œù½þ>>Ž1ÿ½A޽Ú=6=/÷Œ=NBÕ>·e¾}H©¾IÐ*>ÏbJ¾Žƒ=‘v ½]³@>!>îºG¾ôj™¾GEͽ V¾hä¤=j>Ú/¹¾^Â>§œ>Žûý½÷Ú¹=f¸¢½YWþ¼ƒÈE>›Á‘¾-ß+>;%Ó¼‘yà<²øô;é˜ç=p#¾Ë°½áTw=¸C@= O§¾€Ñ}=b#ð»ëY†>ÞpC<_¾z¡ø½B‹½’+¬¾ÉH=G²c½Þj%>\ �<Ôÿ!½à[à½OÌ…¾eî½S}ª»�‡š½ÒûÃ=ùÄ;‹Î>�¾õ}µ½å¢ =Wõ=¢~½3H¾½E°<)Oo>ÛÕY=ý=.=˜>†'>K­o½˜ D¾éû¼mA«>\rQÐÊ>Òнa¢¾.Øh>aʳ¾ó5b½:ª½¯R½o:Ò¾ D„¾€­Æ» 6>HϼL­¾¶‚�=ðŽ> +7¾„¾Ý£3¾Nïj¾TRÐ>Ùî>V‚=Z¤»¾·Ò½�v>ö_+<>>©½y¼= Þ > 3�=~*>nK#¿´$I>ñŒ½ÿR>ÃÎs» °�¾^–)¾ã¦1¾qê÷=“;¾×$L½ŽÔì=¨Ùl¾†\=_™“¼Hè½ýðƒ¾I¾ƒzð½ìb¢=‡ —<Ø­>·'Q¾ ¢>¸¥=öËU>H_׃> ¢¾�èÁ¼fdª¼¢ó¢½Š6¾3ßá½Ê(�½2M޾7Ó‹½{G¤=áT¾“}Í><êt= ‰¹Œ}¾†àa¾w°Ÿ¼Ví·¾þ:œ¾•^9=e^¾×Þ5¾ € ¾ö>8­�¾Ýâ¾6e¾¬Ù˜½,²Š¾)®>É?½½7�½*ÿŸ>û�¾Lå½ k�ºu‚¾©�ƒ¾}?Ž Î~½µÁ½@üR½B_v½™Ûp>f¸½=Éé;¾A^h½§¾gW=»AU½Ø9¼>¾R°:õ-§¾žÜ²½Ã ¯½Øx<>é¶ó;¼s¶¼4ž'= t=þQ¾È·;Š])¾* ¾8­»9Úϼ~ÐÔ½ˆ7‡>¯á¢½a\= u¾zfp>UŸp¾±Å½ÆÈm>&^Ú¼�à’=?Ñ>ˆ¨+>¸à–½dj >ß>U—>ƒ^x>äµ]½f>ª†Š¾)„k¾~#Œ>WV>p-/>a;'¾4½À½¤¨—½í{¾œU̽ºƒ.¼êÝ®¾tøš]sU¾¸> ÷V¼å?¼\¯ì= ÉŽ>õ>b^x; ;ý¾‰Ÿ©=–L„¾Ú›2½�j˜½ËÆ0¾Ä£¼Ãñ’¼×ÚÑ=óà»�ÜF>£¯=°áO½KÄ>¦ñ=MÕq=â�ƒ½¸ô¾1‹>jåU½Î‡¾º‡>˜Úü½7̃¾1wg=Бt>g ¾"gG=%u‹¾€šâ½ºK‰>§y=AÝ>F0½1é„=£j=”´¾NÎì½íì§¾Ñ5=k¤¢½ÏÍ�¾ðؾ�Mw=žãÙ¼â c¼8Lü½”9b¾3«™»ZOô=ƒX½J›>F/>H¾´]Ú¼¶°†¾Ôƒ>Dš>>7ö=í¾!A•¾úߥ=Äâz=š_>_ëû=‚aÔ;ŸDè½—s«½+Ù½I~¾ =żö½tX½6·>ð¯> q-¾ñHE>ê,º=Àö>*%>ó >Šêz=W¯<(ÛB=�/= 껾ÊÙâ½:õ”>gà< -§½�“(=#¼)©;½g™¾�…;�Dé½H�>³t‰>tи¾r'Í= ™2>$5¾oÿB¾å\>8¾å¦y¾ÔÎS>c%®>.0V>¸Š‚= Û¿¾&=Ì5í>ÏeŸ½-—>>þ“«½�În=Šñ„¾u0ö="©>À+%?Îÿ¦½Üb¼¤h7¾Úaž;ZÔ®¾Õ�„¾¯›>›Ô3=¯<½=�q»¹\ù¼û¿^¼{!›½v9Í=bá�>3ÁX=#·¾¶æG>â¦P=¦q”=zò½ÝI‘¾íÿ<¾FJ�='R>Kö½Q_C>± >R$¾ôáš½*ÝÖ>-¼¼;\`€=¦�>½uåZ>g$¡¼“ï=|ä·>‚†9>Øñê¾_.¾MD+½Þ<½t�¾Üî>ž ¾¹ H¾È >ÆŠ'¾‘¡>·Ck½Ô*=—)Ç=Bø¾qÉy¾‹'¼Æòñ½º$>ÙÚ>‚YJ>‰¤=ýÊç=ªƒà¾’ô”>›1´¾4=½FÒ$½¼ÿ>•A—>Ž^B½†v7¾•Kí¾ ¦“½Y*o>ëH,½§?¾—=‹õ¾jí=c:ä<^Ìh¾“½lù>D�ƾlÐ�=ËA|=¾Ò¾uÉ>;÷¸z=(“Š=îl"=¡¾Šx(¾>‹§¾8K6½oqÀ¼Ù5Î>ÇË=ˆá>ÙÎ >M�?e `>xÕ:=”´`>ïì¾LG<Ç䋽‰›½«ê³>&­¤;С–=PvÓ½5K.>®©q>¯‡ä>‰8‹=v,†>j~¿b­=ðÕ�½LCÅ=¢¨N¾o¯¼ãÝ÷=E¯Ä>GõY¾DE>î%°½m®z>²E7¾Ÿñ<Ã�¾¯ý¬¾Á3>}·=ð ]>Ì©Ã=Ì%U>ZàÎ=e"¾,è¾ÞR¾êξ©üŽ<âŹ=µw‚>|­‘¼=d/>³Óœ>B€°¾Øvy¾>£½=u¾½õ‚´>í~(¾q?þ½â„¶¾f)¾æ<ˆ>Á‚<•_¾à$>Ø(½=-I½éY>²ßË=�ÁK>pø$=²Û¾:ãâ½Ä·—¾–_`=ˆ»4¾mƒö½Ð‘̾“¦>ßÕ/>mNÁ=O†¼ân’¾®›¾ÈK/= í2<£¾½Ô#(>“\½L>Tq¾7n?i£á~Û‚½4‡«½ *>÷ºž>;”»éGŽ=âpä¼F¸äUC¾®–.¾9à.>>>�ì=¿æ¿½%.d>¿Öw>Ç‹™¾í×D=2d¡>ðÒ¹½" 7=„åe>TŒò½¬OK½IÊ¿ôò!=ÅC?>â±Ç½b™|<þq>’L‚½Î*>ÀË#¾c;©>󳬾lCÈ>´ŸÖ½Ö…=Ì›{>§¾‡×=ð»@>Æ3¸¾cÑ�¾ #E>?0®¸»J3¾é¢Ž¾wc¾ü­Ï8ç.™>W,œ=õÐ�> pH>홽®� ¾i¢²½zà½[ä>',–¾{f¾]]ò=þä>zû >V„!>m-¾I¨*½›µ˜¾@º>ì„ =G¶>Ú“q>f¥€>p$.>ÿÔ͹ž£ ?ÔO>n-=]â³¾êh£>Rpµ¾Ù×H=ùî³=À†ƒ>%R-¾æ/=>™*¾¨^Ÿ¾û˽ù›F>쎾›ð¹¾ÃW¾fŽ>@Œì¾[Æ=÷¨ª>-ô&>�ã¾Rú ¿šÂн#+Þ> }>±´>bBw¾ú½g>Ì %½ëBŸ>ÚFj¾DV½£¶#¾yœk¾’U¾Ñ»<áˆX>¦ŠÁ½DÚ\¾OC«½½Ç ½i)‡½¥i2>~Š =ßqνÙDh•¾áu½‘àø¼ú…½ÚÔ+¾�8ã=¢.¾¯j´>ž`–=ZF™=‡Ìã>%Fu¾á$>9v>9>›í½ƒ j¾hŽ™½¢=(qó¼Áà>ú—’>Ço+½$r9>VõÝ=x?">ix=Ø·“=ª/×;,Ƚ±ÊO>» ¾s­�½‘™<úºm>˜·R=@p*>ˆçg>Â(¾w½Ç0®¾Ã™o>Èd°¾Á…™=dq='¿za=AÒ½o1]¾Jã,¾§2¾æ¶æ>'nk¾øU3¾ü"œ>ôN^> è>ŽC->««P=�Ò=Ü5>ÉKP>úG|>£-a> À§½y5F=ן½H­¾si.¾Ö?ï€c¾ðã&¾ D¿t÷=Ôæ)¾¿¾ŸD…¾Í¤®>Ç‘=  >by-=¦J}>Ô´/¾ßH>B�’<˜À\>˜vn¾KÏ=?:©œ¾Xfœ>üq¾€U»>‘½>œ$£¼c–i>Í8ž½jA½è6¹¾ó¤ >!Võ½îR(¾v#�¾ô}½W¥>�öü½šL ?Dü>«Ã¾‹¦˜¾ßwP½s�ö=¶I¦½H†6>@í’¾Èã >Š8,>Ä;¾kžÝ=;†>âv:¾Õ™>œ�ú½¼Â >œ¾»¾m O¾OêÙ=¼ƒ•>Þ¥$;¼e(¾l5`½ç‡6>Æ¯Š¾Âg¾ è½"Ï�>…·¿_ Ç<�E?ì�> fâ>¨ø§>ÕX¾Q!k>÷xƾÃU­½•S¾Û¿Â>µš¾Ö—š>\2<>Ñì >Š˜ ?ÉBB<Û×2?Ýe„>±Ýý>º¡>Ût¾Åï8>þ–›>¶RÁ¾1åø½�^å=²X«¾¶ö—¾*¥!¾Ùi=¿—3¾êS½÷$=…å`¾à 8>xNÅ<�©K¾xÚ�>Œ�|¾gÔU¾ðL‰>‘A¹¾�T$¿âE¾iD}¾Ý8ˆ¾Ðæ‘=C…í=þ²=ÕØB=xÜÈ>LŽ >{À�¾³Ø½k W>·qŽ>œ¦ƒ½‹ï¢½"á¦=Üy£=R5B¾Ôݼ(N4>{Q¬½'€�>EØP>\ʰ=Gª¹<· ¾‰å!¾-&{>\ŽdT¾ò/¿¶#>uT¾™Þž=Ä:?>ø*V=š¸¾ÿØj>»Ý¶¼»›Ø>,l™¾ü¡ß=ÈÇÔ½º—ü>åE>ðW´=jr¼8‹�>ƒ>Øÿ>¶3™=!e‰» dâ=”ÒU¾®j¼>Q±8¾âtw=×?¾½ !c¾Eˆ™>õ޾‘¾¹…ê=c4<>ƒ˜ >ÃȽ[>9� =Õ�æ½÷Ø©½˜4>„Ü>Û)´=ÐÔ#¾C<¼¿Ã�>˜€Â>„E¼ã=¾Šã=òn=šŽœ½•> ™´½_§Ž=¬?qsH>�m›>ì¹½q`)>ng5¾Þ†½½Äçå½ËiR¾VªÌ½²xÆ>¹žê= r¾rÒÀ½JÙ½‚ƒÎ½rq£¾ÞM�¾§±­= –‡=Gá>¡™Å>‚é€>ƒ¢À¾:i²= a!>ÉW>†»<Ý#> Y‚¾¡”¾>tš½Bïü¾OD"=©½8+¯<•Å=ûô=oR½6Mœ½-äµ¾\ ¾-´h½?´È=ÿ�¿½£Ä>À÷¦¾&€>ð=ð½µ·?=ãwQ¾åÙ|¾·ñ¹¼' =ÚÕ'¾ Ú‹¾ª¿ý½Ê=^‰½>Ov=:+“½¦!ê=D`f>Yî½Ú¾hdn½‡”k¾ÔûÚ= œÊ½K-Ž>žՊš>¾Ï.¾r%,½ïua<²¾¾Nc•=ï¹>šŒ¾‘�¾)�½T£v>nÄG¾ÜKØ=a|µ=²<˜>cå/>·Îg>Oªž=´ç5¾@ª;Ð@€>²*ª=;¾?‚ˆØ¾ >½#×½Yð=Fc„½½?I=/~v¾0aÇ=+3轋pÊj+½Œ¤6>Á«>E‰»>òG‡½¹ >У$Ѿ=„Z"> ‡}=½¨½æ÷ò=ð_ž=uþE¼° G½ 41¾1½ÐuH>V—>j¢³¾,f >Á¶ê½I»t>…=K¦¢½ F€¾õB›¾›u/=ñk=£¢i>1›¦=gh<1±m¾ŒY¹>ìíæ>Œc>YÍ= #¾bß=0ó?’g¬@¾Ú‡Æ½l€°ÝºL>ÀS}½ë1ò¼È†à==³¾9@U>>7Œ=Cåõ>zÊ�=2s¶=š$8½UŠ >È÷µ;]²¸¼MÏI¾M•=˜¾½~ãö¾ªA¾—{><(´¾„é]¾†ƒð>¿ëi=ùr.>÷§L¾8pé¼WiV>g¦_=âe>¼ñþ¾·ßº>•û=}ç<ÓF,¾ …=ò Ò=¶ë)>;+[½×{½�ýÌ=Ó—;=f>$ßǾ Õ‘=ŸŒJ¾¸^Qó- >¸gß=òŠ�¾Zén=ö\–=Õ¬=€>f|]>v°´>ÀÎÏ»žîÄ>騽™ɽOç(>Kîµ>øª=«Þû=É ?1ñ=Ž{1>6�ø½-g±½�Ä¢=ÙS¶½ £c¾¥6b¾Oß«=¦i€>^fY½©Û4¾^Åw>M&0>&ÐÝ½Þ Z>¹Îµ½Bá>þfË»ÀB­½ºE*¾ºøã¾ÆÐJ>ÎÜ’½§ú÷º(ô@>;¥¾cÇ8=õü->ÉÔ=íæµ½Ç@\=ˆ�@>iŽ_¾ú0¼¶¦¾äMv¾ð©Ò¼·g&¾‡H…>xì®>�&¿¾…”�>÷Õ=j³>W{ñ=ܲӼG5½£u¼%Ÿ¾¼Zý¿¾n¢`>ݧ¤> ¡„¼ÄÄ´=|Á >€'¦¾^0¾°ì>;áÎ;³ÒŠ>ú£™>kag½y[>7`‹½èþ= .¾ê5>3úÆ>‡�¾õàX¾ËLo¼h;æw¾j1™<Žº?½ÖZ¾iN¾cÐ:n� ¾ã¯ˆ>žz¾Îe¨= ôO¾8Ü0>—¾<þ>Ú(Ê>Ш¹½SÕV>#ã;×_à=yYz>2gV>šH½Ñ·I>wÛ;¾$ó=Œo;'ãÙ¾qÉ-¾ƒ†=¢7o<Ü7Š:ÝJ># ô½°ŽM>þ·œ>̬¾d䢾p?>ä7¢>&¬¯¾ E$½aŒè½(>udÏ=‰›j»Ù–E<¦F¼:Œ&½'¾]+@¾ó>T É=u‰Ÿ½x[´< Ÿ7¾äÝœ¾p%<ˆÎX=Ñ?h=`Ð?:­=å¨E¾sâš½_}|>÷ñH¾J-¼aú<:Uí¼ Èf>F>ªj·½¹¿…½ãc5¼Ñ„c¾™­Ã><>¾Ù§3½2g¾°÷�<ÐéÃ=¤ô4¾´~¾¬àའA>‹D>ê:=è¾èÔ…¾VÑë¾ý ?¾ÍÕJ¼òé¬=Éì¾�Y=t®<¦¶Æ½ÎÑÔ<ðªù=˜ëϼIú̽BMN>Ù³i>Güx<ÓÒ¾(jº<꨾㲓>§?ø¾Oa?d>Bæ»í9 >-¸–¾ì7˜>AS•»§(½-û™½ª”W½ã„)>/6>_œ=¾À'¾á”¢>¨ðp>„X¾¥m€=ß Í½¾²ò½øÙï=x”˜¾&”;>6³?kù¢>ëP?*÷+>Ð(¾ó÷‚=™‘ô½N²½5ž)¼ª¶ª½“H¡½Ò<Í=¢àé=@)5¼—;ܼ¢kí=ùD‡>¸é:¼Zì> b¾=')=Ýɽ æü½½ðh>ai=´ãS=‰>]ß̽ä>¯B¾eX‘½;`A=[êº<^ˆ>0£Ø½ 4˻퓅>›½o">€ ½’ë$=�!¾¬)›½{ø:öç!>XöX¾j½Q>#w˜½Œ&>ø˜÷=$e¾B‡»>²~¤=˜ÇÔ;?YG¾‚Y->( мM3V¾AK¾%M™¾÷ô¦=\ÇN¾–¸¬<¿­Ê¼—‘Ô¾`;¾»G–=ÕŸß½!ˆ¾¹CŒ½Ût‡=·ƒ>õ�º>‡u>Ã=H¥<†|;>-· >(pÖ=úľOÇ‚¾Í¬À=–žÈ>Rxç= U…=bäF¾¬I½¥Aj>ˆ‚¥>âY9>ó >ý® >3�‚=_Œ¾åä›<é£4>Ê”I¾Ë4>ììe¾"u=J—m½0T¾nc>͹½yŒ€>&÷‡=Q\½s ô¾u$=RÑé=·–b>½Wo>I‡ñ=? Õ½5$>Êñ-=å �=8­>àvï»!p<â�v¾é½‚½Ì<è½Q()½cŒè>v€1¾ä=Œ¾&DÅ=¦ë‘¾rÒ=‚¶¾Ý,Â;¤¦+½ç9/½’Y=�ßÇ=mœ¼×¬=­úü½Lb>Öû÷= ~u¾ mª½á¼Œ>î>Z>ÔÔ®>ôôV¾É2F½c"̽rññ½cçÖ¼Õ<Ã; %¾^ Q=`tê½v½Æ= Â#>áEú½Ù“’¾®Ÿ²½Wü¾ë;¿¼êaI½ØV›¾�zi¾ û{>b?a=*ο=Š÷�¼°x”½…2üvc¾/Ç=õ"¾�>ëA{¾ýÃ>,±½ˆ«<$ƒŠ=´v¢¼(սξ¼<¶I@¾8$¾—l‚>zä¾`Ús½þ)L='™è>;m:=¿Ë–>¿ ¾< Ò½¸Øå¾Ó¤½{çÔ»dÞg>jÿ >ϱŸ¾zki¾ÙÖ,¾Wì0>soÇ=š}=qkø=üx>Fؤ½ z¾JЬ¾”·¨>« ö=ŠL2<愾¶‚ù=%®Ð½rί=\¤=hâ…='˜¼Ø&û¼õP=go…¾Œw>†³¾ùy9>‰†>Ú'£½-Ù£¾ :›=²�½t/1>ïÃ�¾¤½·оI(>É&L¼÷Û=‡«W=ÇÒ�¾ßºh=³Ú�¾åÎ >º` ?Ÿ¦=Ü·‚¼½ —¾l‡=È·ï=éâ¼*°�>v>§¦ ¾Þ§Â<Š™�>ùѽ=Ÿ÷>¢·¾×h°¾ ÚJ>") =¸?¾ï‚±¾ˆ>e„>Y <ûq-¾Ã¼¸=Åã=ˆ‹?¤*¾(±=~н &Þ;¯·o¾ó×><·Ö=[ >WÕ«>Л?¥.>Õós½“Á<¹ªs<õã½ñ$>� g=®q†;!1>•_ë¾KŒ)¾Õ C> 0>½†�!¾+H¾‰1>bƒ=Dgñ<£ú¡>ͦÑ= kœ= ×¾�…P¾ê5H=°x ¾Ã¡ê¼Î!’¾ü†Ÿ>ó=¼�¾@‡¼¸F ¾•= ¾ÜF¾$¢6½/®Ž½á “½øj›>(ý>f]¶>K2¾ S]>ë#L>ÿ ½§¤¥>‡Ú�¾sX,¾I“ ?Y…“=ó3νnÕ«=¼€!¾•2Q¾fg‘½Ð¾¾îP>ÐK^>C‡¾þë[<ô,©=]Èã½µy>÷i,>²2=‰˜„=wºk¾—â½BÿŸ>—!D½&©¾ßlƒ>• ȼù ‚½©ÍQ>E>'>ˆ=è‡=]¯<‚ëI½Mü½®Ÿ¾£LJ¾Û >†ú0¾–Íü=Ž¾Ý¼C´Ó=]’>.Jƒ¾Ð¼×>ìŒb<Qš=ô/=¾ÁF�¾Gš¯>2Z¶½ÜÆR>ôGø½‚©7¾x_i>Vuù=ËðB¾I+¯½ˆgæ½’Â>>e.2>#{©>ë•<8Î=» U¾ C>9Ö–¾1ŒA¾Æž>4Y÷¼E‘|¾�^Ⱦ?Ë<>¢@¦½€5ÿ½Û­L¼“™c>µ)½ì¼Éº�7�=r)Ὤ7P>ò…½â{½º=Ò=DÒ¸¾P>,”Ù½ÞËC=ãÈÔ=1Ο½pОSgˆ>‚¾ƒv ¾™Y„¾ëAÕ=}tg=ÂF.¾ºyP½“l%¼È~¼Ô,ñ=­Äë>WšH>>È!½ËÞ«=æ½ûøú=vª»>3-¾´ý7¾®‚>ê% ¿)=gUo>_ŒÈ¼>߯<Ї½…˲½!€i¾Ls?"�>žÀ¾š”Ù½ ÆÚ½Ã±k>ê ì=÷»f¾Š—n<ÌÛ%=Ì(K¼>¾R>Ã!ýb¨é½‚Á½¾ˆr’> ƒ'µ>,û>¶¥í¾;02=Ëk >eãÆ>-‰Ë½µ&>Á»=õ¯¾áö$¾qÆ�¾hè¹>ƒàs¾Am•¾!ê¨=™½c‘„¾ μ~ 5>ìç½ÉB¶¾ÉVݽÛ>˜'Ò=5¹y>±7 >E¾Ø-½Êêb¾�©>E#>äež=Ó¬Ö½ïð�=SD¾7\N¾b =§5>’ ˆ¾dc­=ìc6½ ƽ�Á>åþª¾t©w=vƒ>¶=¾�ÿ½§Ÿÿ½µã¾@Jû=KÖ=Ç™Á½Ûbê>©Ëe¾Ñ9µ> Z¾')½UR¢>s Ò½I¾s^O½¦"=!Æí½Y‡>'«©½6(>6¬T¾ÀóÜ=âñ6¾¿Êµ=µ3V;\>’„ ¾BgŸ>‰ŒË½ŒÀ”½­ƒ±=šŠ¦¾±Ö¼ªJ>V·Ÿ< `=WŒò=��q>›3f¾ñ@?>_¾5<°>‡©-¾þŒž¼¿s^¾Bç<=²›H>ÊT'¾î¤y>šÒ¯>Ý>½†½çV¾Zgľ�¾I¾’û¡>ô>1ºs´>L²/¼äd>|¡õ½_PúElm>øry¾—–‹½9q,½ÀÀ¼=ì Ľ,è�¾çm=40=Íû#¾>6=Ö!s½Ã2¾O*™¾Eom=¤ßŒ>òW =TÇ>:Û€½\üÀ>f¡Î=i!ß½š¾üÕ£=6%ؼ¼© ¾4M5<‘D¾úL‘½2â=mHL=™ð+;9¹(> í²¾rkǾß2k¾?‚u=·4¾œ†Y½½Ä3¾åú>ÔÖ¾%)b½[L#½'½…¾$«w=ÓÀ×¼ý!Ú¾ü#r>J<·½fɾP¾Ã曾~ii4‰½xE>4™Ñ½a¿2¾ò½.‰‡½ ±¾ g້*?3ª½{8k¾Õ‡¿Tk[¾„ü2½¦¸O½�m’½×ÅW>èõ®½Ï}Ó=�ï½JþK¾GþBH(>œ"a=ÏŠ/>UJ3½iÉR¾*ä>¯Ð¥¾uÙ¡¾R¼,Û.¸ •¾"!Ó½šÕ½×ñ±¾øNI>¡ÿ(>u�ô¼u€0>1½½ÅA¾õ¬š¾ûÊ =‚?³=ǽ½èj&>(¶f>:`=È:нsF4=#ñ»(N“>®>dø½NÀ#>Ü.\=Pn¾V>G¾±¿¾ÀŒ#¾£CÉǃ =øVò¾^(¾ÄiW>÷n½˜`š>\Z‘>R!m¾¾é=Ïv=>GØ�»b )=–O½/çнÐÑ9>JiK>ßFÎ=� þ½�ê6¾ŒEW¾o@¸¾g²=/!‚½–±§¾ ªÆ=­wˆ>[£§½�PŽ>6>Ó¢1½‹9<‚9«=)“ù¼0{˜½1!�½øÃ&¾ãå;¾ùÈ=Šä=é3>3>烉½ª>ÐPy>ƒ !¾CŽ>öz•>º$ï=M¨†¾²Q ¾Äh*½¬´«>c5°>„>=B½òâ~¾\ãŽ=ÎO>(€ >mþ¸=·Âþ½.Ô<„äm= Ä$¾¤M>ãž>ôH¾S¬¾˜-[¾le ¾ÁÍ„>ú¹•»$“ƒ¼þu >Y�¾´k³>Wù‚¾”˜Â>âô…>üµ½Ý<¤>óŒ|>',À¾çH>ßÈŒºdl>a$ó= ÓO=st>½bHf=F+±>ãtH¾Á¡X½¸®«=ø‹>i ξª̽p¾šž€>ÁxÖ= è˜<“ëY¾«b >W¢Q½rkÍ=,Å = ­¤=ý¾H/Â=F¯™>³…>ž*·=>áC=lù¾ÿ±¼=Þõ ½ký‰0p>—9¾Üœ,¾'ˆ¢¾AôÙ½ˆïǽ<‚üª0É=‡Óð=À£>FïÆ=wo>�x̾ñZ„=»âØ= Ë¢>Û`ä¼ý¬×¾U¸­=·”w=´¿î<r%>nº¯¼–M)½Ús‡½½K3>—‘¾ ,%½!·¾–Ã4¾-ó¨<´ µ¼Ot`½ÈC£½þVY¾ >.º«>µq¾¬xð=&4²>‹�m;PÅu=Ýëb¾A®B=z¡ó=šY[=z/´=o‰Ò:î==:!§<Ä Z¾xŸ¼=Yåm¼š¬v>÷Že> ™–:³¿Ø �==þõ½®%Í> ¿0>N�ÿ=t_?>°Œ:™>甜;& W=„g½‹’¾‚N?¾ËŒ>ý�¾PT›¾z:>V(«>«ñ»¾®ÀL>„¾u=Ø7B<»‚нƒØ ½-ÿ½’tü<¢ºÁ>2¯¿óN.¼îˆz¾&S¾lÒ¨¾J9Ý=º°·<µ#?�¾Oà½ç†¾™ =ûhнv•X>ËŸ=Jþˆ>“ÒÀ½ ë†=üYã<ÜàY>èeq=éÛô½Ÿ‹¾w‡>ä Ñ=ßš8¾�Ëä½R ý½Ë;>Ô$†¾ ±ö;�ür¾rý¾°_=«ñ€½«í=>Ä">JKd¾Wˆ-=½…š=tmd<\»0>Y˾Ů>–½ž¾Æ;Á=:¾¾”«¸½KkÏ>iQ¾`e>¨æA½*e½mX¾“VT>6#ì½ ô ¾¬SÊ=ªc̽\¼ý½‘ÜÄ>̶ê>¥�¼R4¾!úÒ<ø›¼æ>K¾#�9½&¬í½ËæL¾v³S½‘í/>ò-y=¸G<=RñƾiÙŒ¾ç9ܽ|ý¿¯Þb¾4Y=pôÓ=@ƒ=Úy\¾º‰>‚6¿=ÎçW=t�¢>Úô®=ž¢„¾R®³¼s ’¯´ðÐ u½µˆˆ¾×ĉ>|dL¾�ì>w@‘=ñ�=ˆ4¾†¤=·Â)>çSW¾­ìµ»®Þ�¾Îš=Öå+¾ê=ªˆ>¾Ð=/�j½j©°=¸Ç¾ò�ャkɾ‹£w>‘dœ¾Z°÷=¨Ü„>¤¯»"¦ä=ê@l¾§øÇ>·N²=¬÷½La¿½5”â¾^€&>*Ͼ¾µ€¹=8¼‘¾Bš¾K!o>¡¸¾ qÒ<7轎•>À·>?û >�¥¿mö ¾\æ<íÜ>2£=¢£¾bz ¾¾’5>8E¾¶GÐ=rWa¾">}‚=/O7¾ª$%>¤ÊS>н¨=µ"—>–Të½×‹Ï=9|®¼á}K=”ðg>¡Ýƒ½>?,=€W;>]`=ÈÇ•¼£Š¾AuÚ½a+ξÊZš=¢-½n…>N½>Æ®½áÃÀ¼¬Ìù>L4‹¾’T·¼ÓÊ¿ðH´½}-¼�åI=ù}$¿ {ý< ^¾Ë1>¼ˆ_=c¤”>Bí¿ùzo½Ò°¾mH>Lâ¼Ï4‹>æu¾9±½Òœ>±¼>ZáÝ=2…3>ç8™=%±L½³a“¾/¿K>fÒÞ=�eÜ>žë[< ¦t¾XÑ=Pav»ç<1=fÏY½‡ô¦=S³$>,mÈ;8 ù0¾ðsó=ˆ]Z¾µL¨¾³�®=¬{!¾ËV´>Ô�)¼m‹h>Íu¾Ê‚½&Fƒ>_Hù½+n>]羚}¿¡À>nZ¾ç°L>hïx¾†bq¾ ä®½Ê¡>ÉŸ¼=lC>-¾)s¦¼rˆ>ºüs>I#¾²Ý¦=+·¾îrÒ½%Í®>Äê?ˆÙˆ>%óq¾µIR½¨’¾òúI>dwA½ ؾ�¶~½~ç¾rLƒ¾ÙͽCS>m­L> L€>ú2è¼ÿmà½s08>ü™ß=\Ó2¾À¢Æ¾í“N¾ØÞ•¾í ¾¦G;=.ã³>™I¥½‹šL¾T&%¾.OM¾3 6¾¶½‚¾Á×4¾tÒØ>:?æ½�Ø¢=Å‘¾¦Î>L;(½èf,>½÷¾s&™>Ûw¾�fq=½ýC>çl¨¾¸Ñ>µ®m»æÔ€=…n÷½ì¶Ô> R>²¨—½yݧ¾)–=H'ð½*l�>&ã!½ïÍ&>нiÏÔ¾Pbj>ï‰o½§+>YS¾¢Ÿ¼Éþ¾4 ¤¾:Â<½#3Ã=Ò>>',¾Ô a>5ø=ØÍ< Õ…>D¬Œ>ú‚<œ¼;<ý |>kK1½½×¾‡«=|�¾A¯Õ=£û˜>íX¹½¢­¾{>µ¹j=Š#¥=>Z½S²Ê¾@ý½SÊ»}ö=¾ÛA¾žã9=ÑÖ¾':¾æg>>™Š¾©¾–Å=äx>à>Ö½&x½c„/>§Ã”>qöÞ=7j´½õë“=ÑË1>ÍÉ:>©ð¾†°¾¶Oò½J"„¾Kµ=ú‹½£ ¾ü~v¾øpF¼#·;>P`¾™¶“=_Ⱦêê‹>�zÿ=Xð£¾9÷¾û±°=~Ô>£Ï¾¿,ļsƒ+½ÿÙ�¼‚Èl¾i$¦=i“U½‹µ]¾™¾^°l=†^®½›Ì?¾TÚ¾’ýö½Ì¡o>E:¦¾òHº¾&åX¾ðÌ£¾3)�½UÁ ¾êû@>8ý{o¡>ÒH¢>ZòD=2Ê)¾÷Äâ½ÁÛß¾Ò�‰<Êdî=¯Î˽·YH¾ÿh¾QÆ=�‹–=”Âò¼y =>øÈò=²R >DÚb>�Γ½zK�½RT>A ¾L�.>“;z¾Ep3>ÐË}½Â½'>è‰r><*¾¨L@¾£c“;UA½©Ÿµ½+~l¾.–×=ôÇE¾4p<~{ê½2G>w®/¾'…£¾¤m¾ÞÝ:%sQ=ÁDê=Ÿ#¾Q|¾(u >« ½þí½ZÂ6¾[ŽD=„>,>þÀ|¾Ÿ¿¾í¦½B·Û¾Ó×µ>¢Oõ½6#8½�âr>Ï/ĺÂ=ÜFõ½Sd ¼¤G=<³Ã=5=©=Zé‚>�%£¾»“ÑD8T>O¿ùüP=g³I½õ8¾™§ ¾ûÉü=åž=Cpi>’S^ºOÙ�¾~í>D¬Î>±àŒ=µU¾½B>¿¼Ò=?[~½ýpd>áž;¾�cØ=•c½CgA¾ ‚Æ>0¦¾ß;þ=»Z"=´AÐ=]M­=±V =õ–™>9ž›=‘Q˜=¨‡Ô½ù$Ä=VÂ1=hJ¡½g d=Wó¾rã;å2ª=^í¾ÚЏ>όȽ°NŽ>Âc½½LM…½  )½ÛX~¹[RU½¸,Ƚâ)>v½½©³(¾ìÈ >5:l>‡O'¾½<˜�¯¾+jî¼Ì4>Z\“¾ö’>�Ë>¾k=Ì`W’>¦£¼Ø´¥½Ú•G=|h½[ ?½9˜=%÷‹=ŽA¾òÃÛ»÷Ù¦½ÄÎñ½îgþ½çUò½^¾¾›¼»go<š„½-Ã>Ð蛾hÉã½Ðë̽œ^6>3ø]¾O”q>¨½Û#�¾,U =m‘?>ün†¼#M•=b½>ºøì>˜½™»²¾3,¾û±E¾¾Œÿ½81¾-ßõ½ï)¾Ÿ®E=8Y>¢+N½¾`>KÁ>m§Ì¾ä½yl¤>“à–¾K½=èX½—f>楽Tß&¾"*­½ XR¾ >œŽ:Ù‹R¾+ôh½Q䈾#åç=~uÐ=¢óÊ=>0¾¾š¾LÑ ¾®�>žR¾®¼t­ë½(-4¾Ô,¼L#->îƒ ¾Ñ‰>kè¾qJ%>&TÌ=¶ö½›ŒÉ½µØ=³$>t ½síɽùzU> /¾ÂX¾Õás>v(Ï>Öy¾?b ¾SËK½›(@¾-Þ>阊½Tô=ÊÊ9¾k›�=Õ$ë¾ÿa=ZÚY½³àþ¼ñø¾¬P>P‚¾^ Œ>É‘˜>X7=ñOœ<ÂcÛ½W”¾v�š½Ü >Z$¾©3¼ú|a½Ì†¾g¾X@¼6P>^Qô=‰*ˆ>þX™>Yð­>˜)�¼yk~¼H³�¾ÖS>†X·¾:x¾�ª ¾0Ï“½ªŒ>+ª5=󣽎�>õ �>®"…>³4½ß�m¾`kº= â=ýà¹T˜©=Uº•= Y=¾Owþ¾¯Íz¾[i<Ë 5¾ùŠ·¼¸ŒX¾Š.‹=¶á'¾ìÍn¾V.½Ú”ƒ¾Zë¾=uÔÿ¼ª¨”¾ðSí¾¡bD=(ÂÕ¾sõœ>ö\|¾g„P¾C>ã¼à�>qŽ >Ï >·@�¼þ)Á½Œe<Î=Î<¬Éw>êÜ,¾jŽ“>7—¾’€¾ÿ§j=[Ï�¾¯·Ô<ñU¼’«Ò(ô=qûš>”M»= ”>NÝ=¾Ì‹¬==óÝ>”<>㺥>¿¥E=¤>2Aé<&]T¼I�‡¾¢A="ÿì¼µ¢=|`·>!k ¾–ƒ4¾{{½š‰=š\æ=È!š¼ˆù>á�Í=`ŽH½^U&¾÷¥=b[¾=à꺴wè½¼º*¾ ™Í¾Ô�‡½Á“Q¾+ð�>Α=þ >ŽB[<i ½&šL>/"¾©>½Zì)½Œ=¿?>¶â(¾ð:>þQ>K‰¾“þ>XQ¨¾dû2>xi^=0ë�¾Ìâk>-éÙ½ÜvÄ»¡³=R²Ä=�—Ü=3Ѩ=­tÞ>þ¡7¾ÒU×½Si!>±m =´ÿÿ¾UªÃ<Å´…=>•‘¼¾*¾ /¾V<þ=j²>ˆè¶¾±³Â=6gÕ¾Þj†<\+§=`cf½°O™¾E©‡>a˜n½íø�¾ø>d_÷ H‡>’Ð=­!>¦»b=Æé;>L>ë=h¼½W%9½Âöi¼û¾¬‰rºkp>}‡¿½JH:�”Î=q0>!«®ºï‚¬>õÙŠ=›²×=‘—>·Ÿ>“�½Œ·¾r¬¾¶Öy>Êu1>4D¾D]*¾À:I¾¥É²½ ½-(•¾‡°c>Ÿ�€¾0‚"¾W’é½…‰S¾·|¾Ç¸Œ½&g>ˆÃн4üö=*t¥¾‰+>%Ä=¶Í=,dh>ÒV˜¾–Ÿ½=%ô˽ˆÛ=û€ô½†ãU¾Žš¿ê½½­C‹½›;¾³’¾¯¬�:v¿¥=ø?q>aé#½ &Ì=å'À¾ÃºY¼ÐI’¼!‰¾'Ü¿=Ž:—¾–èÜ>”pU=.Ž4½}c=>&."¾8Ã>yx>…/!>ª½æ‘ž=¶b¾/y¡=Iú>#_>( j>£?0ƒàºîv|½ÚM¾¢©–½Y„¾á ?û²>æ#>Pô¹=,‡=CÈÿ<˜ …¼±$�<®+’>@w¾Õ />²À�¾ìà÷½ÌÄ>îS‰>`] ?«»¸=½-ìA=˜¿�=W÷¾í䂽µF¾®Ì+¾ðQ>Üf&¿3æœ=|ff¾î;¾;ÞH>*‡¡¾’á³¾¬}¾œÎ¾‹«×»°Ä=�d>ܦ´¾ˆ¾¿Hîœ=ä‰p>Ì,À¾ûž›>d©=Ãld½$Ó×=®¡G>/–¾·ÙÖ=t=ZýF¾‚ϼf\¾ _ª=Ð�޾€Ñˆ½¾¼;¾X²>d‹>Bd#>xǽé«>�’>�«>5L‹>Ⱦ¢L©>I›¾¾-Pо œ�>6Û¸=ù=÷…޽Tò\=‘}w¾ñmE½I ;�»>Wñç>R=¾>—·=ëp¾+z®½ŠTB¾´:º»Ï=Ýq‰>XÒî½ö·ž¾Îi;½ØÿÁ¾ó®ð=ï 0>Í"w>vTi>%Í€½ Eˆ=_·µ¾›�«¾Œ¯u¾èlu;ÈÔÛ<©…ƒ½ÌTŽL"¾õ©F=¦m¾Fîz½[¢0>G&û=·;+¾ˆíù=\§1½ùÿ½*Ö¹½Í§š½­ýŠ>&É>_ŽD¾¬I¥>õÌ€=@Ý’>MB¿f“:¾…Ö°>ÛªR;˜‰h¾Zb)¾‘¨½8|¡½³…¾‚´À=A\>òC¿½á C;!s¾VOo<�>j>&×™¼T}¸¼¨#=ÔLt> @ȾLOx=àêz½Ê ß=‡›'¾È™¼‚1½è×">Ú²k¾J¢®~Â(½3v”½+Û°>IÍ=Ñr¾ Œ>œ‰(½ìǽ ÿ ¾k�{¾Ð�L<È8=µó½&1¾¥g§=%• ¾ü;h ?<Ú˜>ÞrK>à6½¶><—>OAc>ë†E>öÇF¾†þØ=‹O£>2 ˆ=�6¾Nßà=á=Ä È½2ï=Ko´>öÙ\=Ÿ~¾ãÿ>ðþ¼õ�Ï»pÜ >úÆv¼ÅŸ>T󄾌 A¾¥Ÿž>8ñ=!-">·¾bœÅ½5"8>$Œÿ½¬ð�>‰ ¾*ä>m%=‰mß=z@P=˜þJ¾—û.> �5¾iå?dûø>�T«½TÁ]¾®ò>M†¾´©¼‡¦…¾åÍ,¼yj½Ç9¾¾Q,„¾q^Ê;mSà<Ö´î½Çîð=\÷Ï=š:1>jîR=G…>}Ó>ÌZ½R2`¾…?p½/¦m>é�¾¿†Â¾¢C3½È9 ;Oì)¾«E›½~Ð%»58o>eF¾¿–r½ºv«=d¤>˜ëA>Ï•Â>ÇŠq¾'ô>x§¾í�U¾Y–> îh¾fE¾ñq�>©�=¿Ñn>}.^¾.ªó;p½ªÓ�=ð©-¾1¡¾Ù¹R¾ižÇ=¬þÖ=¶[.¾[((½²ðy=ö†> �¿=¹“¦½6¾e”¾Í=¸=¦ë¾y_¼‚3?>»ô¤¾®>¦¼ŠÖ½!­>=fÿï¼&W¾ ‹…¾ÿßn<Å)\¾I>†œ0½ $õ;Øø½P—=t~ï=5¿ ;è¾å‚>†Ž=X§¾.ûâ=�¾Æ=@ßç½µ5)>ðÛ>¶y<¾R†Œ>µ%R¾Ðz½�/¾Æ)¾=jР¾JÎõ¾„=çL¾¨ÁÞ=¬Z>8ó¿=Dƒd>^ x=ßy<È/ñ=™"½‹p3¾št¾_è¾»ù>¾WÛy¼¼Õª½£Ó3>=}¾^'¼»�t=®áÐ=ùk¾"¿¥=ïàú½¸Ñ>Áì*>áU¾ëÐͽøø=ºö¼�„?¶/>Pvu¾¼£ì½ ²½ :º=d_>JG>Ì•¾¼=•9¢=é¢O¼W=ß§½ÄŽ>Þ{?äD¤>¿ýâ½kо«Ú¾n5[¾JÍ’>¢äý;½ “>Ä‘v=ô%Œ=uñŸ=›’t¾±¾L5>¡y¯>�Qd¾=‚´¾¼ÍͽÕ±=€½ÞÞE¾¢.P<Öw&>2Úú½ê߼{ö>Cš>Ãþ>Ud¾Kÿ»=")¦½e’¾FëS>~ó>Ùš ½Ø¯œ¾ˆ˜ï; Ž„½zïS=a¼•>¬µ0=—û >¶lD>¥�«=Sb¨=û×]¼Ÿ¾»>j¢’=o•“¾9»D62<�A >TZ/>y ,>ÇÍ)=¶^ˆ=×ï<ØãC½ÊˆR¼âÏ-=Ñq½•¯É81¾Ø³½ï—e>ksª>Å·b;¬“>Q�=¶ÆW¾W÷­>ôÕQ¾î&½É:¾óÙ>¤$¢=§ê„=ºK¾Ý€>çÏ=£ãD>ƒÙ“<‡Z>eä¼×’e¾î*=~y¸½Õ£4= #¾ùZ�¾u*‚½’%ˆ½ß1¾™;6>.; ¾c ¾Ó° ¾Ò½ú>>bž>‡ó/¾Æ«ö½‡én>y%¾3K¬=íš¾5> ËB¾Bl‹¾Dªè=AÏ�=Ì>»=Úc>^—ð;[Œ?¾È-Ý>B¡>q7>>±=Š=£¼[§ôÁ½ú�½ëûä>¨ön<” f½j,>DU†>÷0€>Þ;½}À¾Í¸¾Ø™½›l(¾Ê¨¾/¬¯=Ñ'f<ŒWí½ñ´ ½‹‡À=Šü{>Ö½W¾?¿*ž>¾“=–+c¾}šÔ¾y ô<Ê€¾Ë–>š¸9>•L7½X%«½ƒ7¾xf=¦²�>ˆ ¸¾4Ž›/è½e ¿Å§R<& h¼*=r,>ÁÙ‚=*N™>xe<ºZ›=r3b>r{|¾Uâ;Œæ';÷øI>gAÒ¾ƒ®î=3™-¾½0"½ùú>¢5 ½tDKù=×\¾o©h½´;Œý¼�˜ ¾e�¾¿Ö¶»Iúí½áÇ:>Óþ?¾¾‹ù=³™?ù‹j¾J Š>ß<¾K¡¾g&Ü`:©¾f˜>‡·s;�µØ½¸Õz=kƒ<Ðúo>6€>‡Ó”>” ;Êâ]9熾ŒK¤¾Õœ>I ¾€¢½tʘ¾ûÔ<Ñ‚H> Þ=¯>c–=Ý6¿œ0À>}‰>âú¾=•†&¾Ë×Í=J>â=:®=&ŒÆ¼µjí<½nã½t,¾}0=I‹t½ªMà=ºƒ¾g̼Ü¡=R¾Ú6’½ç 2>»&B>®j>J Ä=Ëà)¾Èn¶º×˜¿¾N&> Å>.ìY>ÐC¶=.I!=àúg=Ô´S¾-õŸ½¥¾bÚÆ=­Ï>¢á¥é¾Ô“;¾† “¾{â'=Y%¾–y½½&$Ú<äj> 1,½JC¾­ù¢>,g#=qò¾ ³¦>tzÿ¾ò£½]l> >¸AÏ=¶œ{>A¿z>a0 >�œ=±åѼV]¾íÖ>µ {>a @=ÎÛ<áh�¾:¥à>Q¾P‹¾3´½BLV¾ô>Ú‹>BK1>ºq¼èPÃ=U\¾=ÊM>ÿ(‘ºfð‹>,o�ºí>Á/½å:¾C˾>›‰>…Xz=±™>U ¾6,"¾)†ê½lп<ù+>r‘¥¾–¸±>ÜŒ¼hB¡=}†':&+%¾Hôð½¹XW¾‰`­¼&Ÿ$>`n$¾!>?Ig¼=ñJ>Ý=;åŽ>«¿ †*>7¾ 2ó=¯Î ¾ðö)½m„m>&=�¾<+¾Þ.=Ÿò >4W¿<Ô ü=8b>U>¾ _̼ŽÏ>·*¼¬¡o>¿j�=g[¾ck3¾ð¡º>›h„=Þy¦½¹sH=õÜ=ƒD¿ž¶>Ñ“>­Ád½Ù^ > ¹}=N6é<õVŽ>Cðp½‚G>í8Á>„Ò5¾"tY¾Ñ€¾Ìu¾|P�¾HÛ4½/‘¼…sz>âb¾>›–½[ >e<¨¼Àc>‡ƒ˜=-$>c¯½†³Œ;’P#>™ž >¦±ö½a ¾>nö¾Ú>6«r½vÃh¾5)¡=]'>™„Ç;¾i!>è]B¼íåD=šúä=D>=NdÄ=}ç–=®@u¾ ãx¾ª£Æ½jrq>³�ˆ¾ÏY<©Æ>Òô1¾©¾ë�Î>‡ÂI½Â\9¾¶�>Å¡.¾L>°¾h±”¾£¹Õ¾�±>C~Ib> >î8©Etº«+¼®V>;ZK’>À†¼�r ¾"±ƒ>œTI¾™ >!d¿(°¾c"É>�½=A΂½Z$S>çv>}bf¾‰ø=´Oi>M >‰ }>TᆽÄç¾¼<ç]¾èÞ½µ�=º1_=V£>Õ­>FÅm=;½r#>¾<œ¾Á,>±¬Ü=X±“=Ù >H7C>¡¾N¬Ü½‚Šü=k==Ê·=Wcv>¬¨º=ci >o~¾½½/½z�¾òn彺@¼øö#>”’ð¼*æ¾Ò ½ÿ…>+[¾³û¾R5>{¶Í>Ê z½æ(¾CïA>0CÛ=TøÀ½�¾˜¸:=¹ö<èx¾íÈ ¾¤ö–½q&L¾çÔ ¾'¶6½ Ýó=RøA¾ÜGu:6üÁ½÷kâ»?!>,ˆ/¾.�Ù¾n�¾ž˜ð½ðJ‡>B$Wº~q{¾wãÒ<7Xú½C1¾`²4;ÔL½Ÿ+]¾hм=§�”=ûG¾µ@=há!>š* ?Ö°»’û=yMŸ½ôÊ+>Q?£=è¸>¹8¾>01<ûì=ö»]=¯êê<[B#>Åõ½ÿl¾Ôо^µC=‰ŸŒ=±ž=ê*ƒ¾',£=²�§¾ Pˆ-‚N>¢x@?k@*>i�(>š„>ít(<¯de¾ª{¨>¤ï˜>Tc6¼WÑÖ¾;åÏ=lb=>õ<Í>M?%=% Q=»¨u>öL=ýöZ<¯y•¾Ò×g:ÿ/Í=�=§¾ÒÂé=°Š>Ǿ‹¾A¾Ãka> Ž>T 8>È/&¾p©f»ÔO=x Þ½�Ð$¾ã÷½àt>hæÚ¾Ë1M½ŽÂÄ="Œ<ôæš>'*;>(±ò>ùÆâ=ÓLž=~)½‰k`¾n“½úƒ¾$é�¾�‹§½»V>Ñ߆½I}µ> ³¾ Çá<¦‹Ë=ê5¬>úïÇ>Ø=É<[Žü=Fì<Ô²�>à”Z>ç={/λqó¸=õmº>[”¾t]ø`èh={J+¾E¬>™¸>o³È½¥¾�>‰¡>Û§º¾`,™=Hô9¾‚µ<~Ù>WL_¼`¼=^Um>áŒ>¦¾ÔÀ‘¾¡ >ì1¾$\?xN¡¾¾q»>ekx¾ A¾PKï½ù¾ˆ)“½Tc�¾½>¼ôÙ¼�-;VÓë¾0Q=rNa>p¿Ì=ßô¾@r¾…¿½[¾§LŽ>8«>•?½|0=æwн<|=däú½{ ™¾¸W¾}ÌX¾Sf=Øó©¾#• ¾ ¾×$ð¼轪8¿½¡QU¾‘z¾ƒ(9>»u=> Æë¶µ„>¥¤¾�Ô„¾ž„>½Xw=øˆ­¾©Ô�¾&æí=@@q¾µU>tÓA>eA;£Ã2>¬V¾m]>Ʒݽ·¹>Æ& <‹û†>ÊQ;ÒÃ>w»;½q¾&¤¶=®ß±=7~;<‘=VÍ%>ห½L#|¾J�‘»î€½ß/4>÷/ؽ©÷=Fè2>¤\Ú½C=f=ÍÍ–¾/z¾8°>Hò¨¼Æ>�½"ÿ4>mLx¼[[„¾­bv¼xX§>ç¬=°Õ<ÑWý(%ç>ÅUß¾ôôÚ¾öTP>‘,û¼R¨ª¾ò¾ì ?2rE>ƒ÷7¼-°;¡H•=kÆ�;bZ€¾ 0¤<Ãß¾–È=…Ä;>‚µ¾ˆò’=Õ`>ciν>C@¾{C>”‰Ì=˜½õºI= ÷w¾ˆÂ½r]Þ>°½½' =ȹü½8¾5Bé¾×bÒ>ïȇ¼g f¾_aö=?u”=¸¿¼Vu >/�)>%¬.>žBI>¨v•>Ù÷“¾Òss¾×­Š>6…Õ>‚ŽKÏ8½n£¸;%wu¾öv>«Ú»î)½óñ¼†±t>óÓ»=4™f½XðÒ<|1g¾[/¾OݽÉö½JÍ ½8ÓÍ=Q.>j8(>Yy>¡P>u¡ñ½©ÐÍ>Ö”½íØ(½yC>}q›>H½y'¾,°:½VÔ¢= §3»1�>£År>²Œ½(P¾fò÷½Á„¿>Öû¾w*%¾òï¹òÌê½ï—¯;ñŸí½_Þ=›5>¾�¸G¾·–¾uR=«L=Üù»ºæ“¾ßÁ>–ú>´j%<Š6½k*Y¾"M‹¾ÄªJ=oîÇ=Qàz¾3{¾ùÛ=W#¨=7“[½qÝ“=³LØ= ˆ7:øv^¾•U=U{½ô¥º>7) >KƾÄ/½eQÐ>®/¤<ã)¿½…¾…�">É1½,ÙÎ=!§½pká¼› �¾Œ¼1¾iø³¾–®¨½=—›=ØÜª½*ÿ»N%ª½šÛ9>ð’=ð?Í#‡¾æØ ¾„M±¾eŸœ¾Ds±= ¾È¾ï-q>Î8¾+—>ØS©==ï >Ô>j¬Õ½é?46A½›=¾> ¾?χ½!m‹<êL‹¾¿m¾×3>4zñ>±ÂW>[ ½'8�¾Ü¼=¾ÅÍe=W¨g>@¦þ=Ç6…¾žJ¾ÏÃT½ ¨ˆ=<õ5¾C‚.¾ª”.=[­¾¸09¾"A:½c¾•>aîX>U­|¾56¾>¿ù¼ín“¾l4Á¾Üù°>×R×=瓜¼.Ãå¼D–h=rˆR½­—…½à­ý¼^¾U~1½â­™½ýÌW>Ếçl¾~'¾�Ì«=dœ…½PM€>~’ê»vê'¾õ{ݼg¼>,•½¡�Q=žN޾Ò^¾XO>0Ì»:-E¾«]F=úO[¾µ$=Jåt½‘ >º]>”�½£Ü¦>¿äJ>¡U‹‡>'Þc;[És>­¨Ò>Óv�½QϽj>Ez²>ÞX =ú¹‡>C ½ÓŒ¾üQ¿ÖØH¾°�%> o޾‡v2¾#³‡¼9M<7bï;¯/¬½µ`:»ÎN‚ºf °>u->Ù뮸,Ãa½Oj‘½hÀ0>¾Ïç½®˜x>¬Ç{>"í½“R®½÷‰¾�–½‚Ë”¾A¯>˜âp=Lñ€½'dÙ¾!/(½ðÎP½>àL¼"¶=Füé=!k;>hÛÒ=EK�»u*À=óŠj>ª¢þ<Üÿ¾©�j½90>=f!½üñ2>øÕ¾)c9½¡5©½^‹B=<د;,zF>C:±=h徉7<¾ !C=ïwi= oR<¿�’=8Õs¾ŽD¼Ð‚¾6ƒ>ÓÇ:>4ãc½[Zï½®v£¾Â¿a½ë.—;•V>änÓ=I·.<ë6žEZW>ÍB>÷‚C¾ÎW%>]Æ >B¨£>¤R=CÜ�¾­›~>—V>|Š¾Î†q¼M+!½V¾©ÿ ½ø¥½@åE¼Ýg=)=na>¾Œåø½‹&½Œ‡Š¾‘´¾� ¾tã=Db;¾'¾’Î/¾jhÕ=‹ê?<‡f·;f‘>)Õ=-§å;‰É[¾ g|¾B^>Õxi½þy½›'μ6c¼=dÑÂ=h©D>2�ò=²5¼C>tµP¾nï ;ÂÄI¾ÊEØ=[Þï<ÐÅ>ªº�½¾û\¾rjx>¹Þ@¾ÂÎe>&Xç=å·œ<ƒó<…-¾Hž==û�>�*�½'S¾¿/G¾š�½tɽ/˜¦¾L¾1±¿ZmĽ\—¾9�å½W¤/¾½a>¾\‘Ã>þ¾‹™ê=Ža‹¾€¬É=Í'¾t`�½pÍ ½3gµ;{¤7¼å¦’¹[/½ ¹%>H�‚½?JÇ=Ñm?i�<¬Ë=á]=äµ¾/k”<'™Z=yû>‘Ž*¾¯€¨¼�ó弑=Š(9¾”G[>†Œ€>Mš9½ß4ʽØg=@¯œ¾¾í¾®~ì¼në=0Q†»¢v¼!¾ð=Ö î½Ê9Ó=Q-ü=jß’¼Ø£°=ÇW'¾‡j>Æ’ð<¾7.>_ÂI: , =š(`½-—å=<>¾Y`=ì x>ðݼA+ > 䌾ƒö%=u´=ò ¾Û™¾cžw¾/†ß>‘Ø¢¾?tP½ò¡¾[ÒŽ¾ÿè’=êe÷¼OÞø¼Êj]>Øœæ=­Ðè½ J¾=¹€Ž>_<¾–òy·ˆ¾T;T>† ¾Öu>�ˆ“=…²èËö½�*˽Ðú޽}ŠÐ¾²{ =A½½*j½$(£=5B½ˆB¾¯T>f9k>}Ѿòé°>É„¾Ün¨¾+XR>t >â=d=>a¸=€¥¶½ýö—> —×=žU4½ÊÓþ½­ÏT>K°D¼þ)ô ’>HÞ¡½àg¾e+R¼¬DQ>¬¾&?>|€>—Me¾ [Ò¼˜p¾´ m=!ç‡>M=c¾ó1†=^^\½ôz»÷æÄ=ÿ6<%ܸ½Nw>µ|ƒ>Œ¼´ s<0y>PÐ{½)|P¾7庽+—V<-ql¾!T®=,ƒ¾U}/¾m3Ǽse7¾^£¾Õ¦!>d÷å½#�»½fÛ½¡[¾CeP¾/¿L>öÄ[¾š[£=VØw:‰ªP>æa¾Î=J>Š=#I(>š.½ÿ$¾¿Øt¼òh¾aÁ¾½ƒ!½†1¥=°+f<ŒdÙ=qÝh>γî<‘L=ò�¾þEÔ¾¥Þž=�8©=£ßt¾�oñ¼QÔD½Tô�½bsྎÒ½ÿ¼¾L­T>.nŠ>é!p¾xõ¾•£ó½Ø›i¾¸0¾Ã2½Z#!¾Þó©½�8¾ýQ¨½•Ä<Ú˜X¾ä‹½Ý;¾¯þ¸<� ¾W…¾&Ö´½Õ2^=ê›1¼&Dð¼&>×-ª=lÖX¾äfQ¾;Fÿ¼!½ >ŠÙ’¾åH‡<Õ3‚»> •¾·Q½oºB½�¬º<µmH;’0>›þ=º¤¾E�Œ=«e3=!vèòƒÛ=bñ»<¤Ëh>F-½_Û‹¾Çx…¾mþ�¾üâ¾j‹¢½Ñ̾zW™¾ô¶"¾Ùß´½Æk ¾°é‡¾÷0½‘.Ï{¾¨Ñ§=�{½Õt1½c>£½>6"¾)}$>ÍäÆ<½¼¦>‰½àÄ”>…A‹=Ó¶h>§9j= †\¾¤Ù›¼d¤;ìÈÀ>åPµ½¡§9=+ÿ¾)g¼…Á¼àÏP>@ï{>= =ÏÅL¾�y9=]ã²¾²AÛ½€î¾wCn>Œ2¾|>>döÂ=ÐZ£¾•{oº‘½ >ä¸<5›”¾Áå=ÿY…=×V>ùj>HÇý=0F¾o·ø»R‡>2œ¸½ß �¾Žµ÷=L!i>T…>mÞ½ô�>sµû=M�¾erÒŠõ¾V†í¾Ä™Œ½¬§¾½SG}½4ÜH½ƒæU½lÑR>MÍe=Ù)õ½W W¼jW>‚¬8¾mõÅ=Y&>|“ν?f(>ÎSl¾~\K¾]$ؽÊ/Í=¼lÝ=µì=gx±½QÕ ¾`ê½$2>8:l='ö>¥ß½jq>aŸ=]Žº¦WÓ½â`8>Dšñ=LÜ4¾›ˆ>ˆmÁ=¹Òt<‰y=€ÂÉ=eòA>Ü!¦½n<+=õ=ÅçŠ>÷UÈ=>o>—û¤¹üj>œ©†»–WÜ£B·½P/f>\—�½·×>,…¾á?Î>É ñ=mδ¾!á«=}%²™!>̲`=ä¡Û=:àN¾K¹1=åœg½…½ìÈ>n³> ˜>‰> 4�¾ù>¤VÃ=zg¾R½Ù瘽…Q!¾Ëóż¢ñE¾¸{†½ ɽÁ ¾=^¾Ð€=>9о½np=õ6»ä<¾^ Û¾d)£>eŸÐ½9 ¾Ì좼×Á¡=B_¾^®½¥üx½ŠK>Üb§¾G5¾›‘¾Jx3¾Ô¾úlo¾#À£=½!¨>Öz3½#H#>�«ä½%Ú>_t(½ò¾%9¸¼]1=ßû…¾(¯a>pé]¾4 Ÿ=trÃ>”ºû¾-쓾uYë=©bó:=% >ˆñ½@‘Œ>d>h¾ä?1Ò²¼³,ƒ>,¢î½}PT>ÕÑ=ò^týØÌ>’Lµ=‹¡È½-7¾o࿽ ¯a>µÚ…>ÿÂ�=MÜð=ìè=›úê;~º?¿Ê'°<“7¿ÿì�>g€Ü¾�!ˆ¾P™t>HÌ’¾ ‡<6ãƒ=@¾·áŒ>5Ø ¾wâí½×5<éï?>ÜÝ<œ›ƒ>Y\ƒ½ë9û=Úiý½~�½Û =‘ëÝ=û׼½ê³¼¹à½�Ã>2 n¾HiÇ=ÿ ã>Ò‡ ?Z‰W¾\Ïe>ü}Ï(t»=6„=Ñ’®=â^=ÛN}=`àX¾m(6=(€ü¾¿t¤»y_>Í À<[C,¾íŽª=Ûg-=@Ÿ¾Š¿¹=«½‡>…4™=Úœï¼FrM¼C“z=ž£>()>ØL8¾@vw>Eò>ˆdŸ>5´›½©Vï= €¥> nž=¤�>Qˆ�¾I¤#¾¯£ï¾óþÈ>*œ¶>;Œ½/f–>Ä\Õ½k =F›L¾_—ò<vž½‰¿?¿ƒ«¾*‰È>ÖRÊ8û>†5R¾¢{=¢S¨<'(0¾ëèX>>$÷¼ZcP½{ø�¾hažî—<Ï^e¾¾@ܾ bn¾�hÚ½8‹§<ôÍ’>›É >בd<ýo‹½¥Ø0¾ªÏŽ>™Ø>€É<,Mƒ¾TD4½‡¦Œ>Ýæ=œ³Ž=�hE>¯8¬=i{2¾tà;> mQ=[ ·¾(—¾¿ž¾Û{_> Š`¾Ëò1½ík¿?"/¾¹ ¾Äë¾ì>Û=íz=Þþ޽3Q£>‹Uµ>µ>ÖøÃ=ëñH> ÑR¾¹p�¾¡­s>ï±¾O¼ÇøÇ=N[x>GÈ='z¾ò™¾ç¾ ;+=ì� ¾ÃÄ;¾I;§=® €9òÌp>ŠçÚ¼o£�>X⯾Üaº>¼Hœ=Hr½Ä´ž= xaºúaR=À]½žf@¾~6»½C¯Õ¾‚”�>Úº=çÐ�½jé¾ CŒ»=R =Eò¾-lö½Žlñ>Õ·Á>cî=« ¼¾C*>†öÎ=¯;½‚lž>…ÖÖ¾”ʾŠÀ>Öµ>®T¾ð#½è3é½â.Û¾z„>ïÎÇ>Q¢‹>ºü…>ÆYŒ¾ù3¼¸N ½ÛÂ>¾ ëPº[ ¿>?áܽÜ'¾Îнv€>¨¦> fv=ì³b>Õ�=•—>¾&f==ñ1R>ýÑͼV‡=ÔàE¾'B>½zy˽u^m½l…3¿¼š,¾´_+>’Ÿ›>‰z&=´„ >ˆÍ›¾N›¾ñfö=ìëž¾è:ü½a„ ¾öºÜ¾:›>>¯4Ÿ¾ˆ}>éï…<ë~D¾ƒqŸ½Þmk½Üc¾>Ò=¯W=d¬u>ÊE>â+™¾æßª¾¥ A>a@•>ߟ¾u‘¦½WA®=?Ëe>ÍFm>lí^>!¯W<ÁLU<à=/R�>`뾊y>Ô3?¾…•>,Õz=!¾—6{¾ª«®=�íZ¾eTÿ<­`Ÿ½H˜¾ì�ÑÈ\¾„á¾?L¾»˜ø=Îǘ¾v}¾¯PÞ¾ÏP<&•¶½=(I¾Þ�U=\gʾ¤Ií=¶ßy>­­<ò>~%­¾°8ü=ŸÜ¾¶õÈ»ZžÊ½Å:<½'�O>çc>¾á†Æ>\Z¾N‡Ê½Ã¾œR<ée³¼£¥d¾ÒSc>nn¿œQ�›¾¨�µ½Ë¨>Š\¿†%¾½Ý�b>ÊS<>æ¾ñ™=K¨x>hÑ ¾Rq¾±b�¾þÚ¾v >�+œ>� >I… ¾Ì4§>á¦.¾7vN½’ >tÌ.>ïÖÛ<)¯>ê >iÑͽíÀñ=ñºD½Gݤ=‹½½-á/¾Äú½Vf‘½�œ=ù©û½g%m>…m¨½€ª´½ôÎæ>µYÙ½ûÿ=ú½|_î¼óC—>Kxú=ónÈ=OñȽÕës½W9d¾¨ÿ†=æI=ÉqÙ=c ¾åœÁ¾ëÏÂ<©,>»�5=0Hܽca½5Œ¾òE„¾W€*>H"Z½ã·=Z½x!R>Äí½¯>a>·ì=�$T½cW¼¾Ü¾öÀ­>¢Ý=uÒä<³X›<Íâj>hm >ðÆ&>Ë=g¾öv7¾¥*Ë>>ƒÖ>c>y|¼½1ÙV½<äø½Îè¼¾å~b>…œ>‹ÃǾó}å=®F<{Fâ=�+¹=W¨N¾Ô¼÷>ÌOœ=ñ²h>ê_.½q•’½LE.¾«q>Ì Ó½huw¾ÿ¼¸›þɾµ>ö²(½þü!¾W8ýæ—P>qb˜½m=>Iħ½Žu×¼t…€<�é°=Ÿ!¾¡]>­L¾›Á½}B¼¼ç‰U=_¯¹½YÎæ=×x> ØD¾�S̼g=¾£J5¾ž¼`j“¾zþ¾ª¯‚¾=13=ˆWN¾}GN>Á_¾9òé½¼A¾±z2>�¬P½0 @¾Ÿ6W¾p̃=‚Üœ>ÿ¿·R>t Ã=½QT=o(¾˜Øƒ¾MºÑ½ÂFž¾�ý‹>[n¾[ªó½¶¸Ÿ>É­²¸wVu>ô‡[¾ *¾0èi¾t~ ½¥ ¾ðGù½ £-=™V>ÛÃ>€A�¾ D�>|c‡½(Ú½Žô´=lîÂ=3"´½Z+>D°=!:Ù=ÞÔ >†ms½ ¦½ Ї=2’=à ¤=z´¼V­å<°×¾ûø>ÏÜ©=¤Ç·<€}²¼ñÚ=tI¾+ß󽨏»ó¦Z=SÞ=� A>Dƒà=9„Q=~Y =^µT¾Zà�¾à+,¾è°C=SØÝ¼Aö¾H„¾¢�>½>ŽK¾=¨›¼±¿d¾¤ú¼<çX?>ÞL¾Ìë#¾€¬™½›Z>„¾K¾Š½Uä¾¼¾…½+ôÝ=Ÿ^½*Œ>q'p>ȹz>PX½X�˜>ç">á0t<îW\>Žàº½˜ãj¾‚šU>Ù_+=ÓQ›¾›^½D�û…=•},¾Î—+¾ó6:=»šû½RË>ž™¢½D>9÷ž¾¡C>Ò| ¾µº¾¼Jò;¿T+¾L<Ÿ>Îñã½|•>lð÷½)~½ˆ¨>ó2)¾&¢>Y�>œr‚>Š­£½2.º<¦7\¾Ô�">¬ìò=ûÑ©½Ž#Œ>uYâ=tÅT½Ô-—½ˆ1;€ì¿>’"k¾mð¾W�#> ú ¾$Fi½Š¬�¾Žšš½ ž˜=ð:¾¢�+¾æ²·½y|Ì=Q?>u¸P½Itî=Õ½½oæ¯>èM\½ Þ´=Gñ½=éÒ7½i¶Î¾‘Ÿ>WZ™¾aáá;M33¾Öø¡> ¿Æ>t8>±¿=Îx5=˜>­{Ͼ¡ˆü¼$µ’>O>º=OK>6ï.>Þ>ÊgH¾T�¾ð&Ô½L‚>='7ˆ½b *=‘e'½ËKš>[>å²>ó‹¾àŠ0=¿ÜÓ<R¾¼9²½¡Z3¾¼Ú…>÷¨i¾'Ò‰½ôû}½Â»­>zH™=P‘e>o¡½XRµ=„d¹=9¸Å>ˆô¾ë l¾²ˆ>e"6=Z‘¾jŸ†½;°0<Û¨ý=7†~¾¦Lºõd½¾h·>Á¾º“=xf[½®QB>)ÃÕ=o}½³ç">M—À½�½�ty>öG›>-Âó½0I>ؤ=œs½A_"=Ïš¾!�¾×di¾Êá½YaÙ¾³^y:æ¿…¡¾Ò•É>TÆ.¾E8>鯑½[É ¼/Þ·¾ë�P½ò?Í´ä½>é¾hbÕ¾=¦_ƒ>»lâ;fßý½�VG>¹O½J$Î=©ôä<‹r½°ƒ¾ ¾%¡X¾¸2D¼œ!j¾q—v>~;á=kÏ>dz|>Ïó•¾þ²¾‹0î=µ­%¼WA<½WûʽiÜã=™Ú¹¼ÆH‹=Ä�»Ôþ�¾¸Â`>‘ª¾=Ò’>ÉÒ½Ägº<™�-¾Ê޾�ûÃ>Ñ–2½Ïµ>2ƒ > Í =5Ûo>˜+£¾ãØ?>–\&>° ‰¼‰‚½=Nð�>î=<" ¾>ê�»[n>!Ì�=ùü™¾œ¸;àà½Ä ¾^ >>´j¾óŽE¾3Õ�¾ƒÆ^>Åb½¢µÄ½äC>¿˜¾H8Ï>C.×½&\†=a•š=Yyð½I< —>y6ƒ=Yà½|”>ÅÒ“= í§¾ž?9=HO¾:Ü»?Ù8½›6½�É®½Ô�c=¶Å½¦$½ �>ÙÊ>>/§A>ˆé_¾|ù§½>M‡>Ÿç.>^}c¾?´#½Y¾�>V¯g½Z>U³X¾ì0…¾ä;Ô½íŒ>Tš”°=¥½ 3(¾aû)>Hb¾ŒŽª½FTÄ=.�>Štè=`>+D²=Ì­^¼ÕN=n¾Ì÷=½ùÂåÖj>½ø¾Ò%¾!Ôª½S*ß=з=¦ê>ä°³½sG,¾ˆ�>\úã=Â(•<Ãr><“7½ð[˾E™�¾c}L=9e=™…=W¾�î)¾^];k³ö=¼FJ¾·I> üî½~ÛQ=5›–=ìz¢¾ÚD¾"Ã'¾ÌJǾâ >fþL¾®T¾+¹=(™Ö>n_ >'ík¾0qñ=†—z½™Äm>¬ˆ=¤+¾~Þ=ò0á=jÀ>Ié="˜=þâ‹=ײҽlu‡½Z�¾�1¾¯šÍ=í*?¾”öÁ=ÐQN;¿;�<~ò¾߉>õBÁ»¯Å¤B°„¼òu�\Í=Q^|¾ú^i¾Lœ>P\>�Sc>æÇ=>ð‰Û½6Y«=ê>ѽ 郾@¾>üD¼$‰„>øŒ�¾Bor¾>äQ>sê½6(>.ÉX>˜HÆ>Ášh»¼y]>¼´=ì=ô=û*$¼”âºól€=c€#¾9xå:Zõ"¾üꣾŠê‚¾#½W½ô÷ö½F½Æ¼š¦£º¨¡Ï½ê}½|»=ýÓa>u™ˆ¼á¡=È>X¼nÚ“<¾K)¼8WT¾Ða=b”N>Þƒ>T,>z �½=�̾wv·¼br1¾°ö½¾ïj¾ ?˜=U>>û2?½J®!¾ß™J¾¬•$¾Hxx>œÜä=Ý H>C>ÔÕ3>-·Á½rP«>õ ¿óŽ1=PµÓ=À,¾1L5¼r„¾�§>™¦Û>—~‚;¼W‡>Öú½"ü½—C>½ Õͽï)s»@ >4�ê½.±>A×—=àe¾Óã]=ÞsJ¼ÄK<Ìû�¾‡žA»ß^=ó¼ü‘x¾§ÞÃ<ÝIR>—bq=» ¾ÿ T¾|ºÆ<•†¾º¤ð=ùžM¾=剾 Y£¼ê­;òY6=DÝ =…¿º©Þ<À½>­Ù_½ÛÖ�>EßZ=wä½W_Ã>²Ç`½‚2w¾\t„>%¨Ø¾+9>5Y»í[£½îÇ’¾#eP=Ü0¾m-á½|jØ�}¿¡¨¾N¼Œ½“((=Åw½~„=en‘¾"„‚½1³¯¾‡$N>I¯k>$û{½)Ý<ã~>\cƒ¼©ÔʽNg&½Šù1¾Kœ¼þ’—¾‚¿ >úæ\¾}dl>i€Þ>Ut >g>‡²>ÔPü¾¢¼¾žÆ_¾j&K¾‰]=å²ý=Oh·<|=œFª½†ü¯¾\Q ¾ gÎ>Hr>ÙÁì=î7£=+»>¾së=wï˾�Ô4>__¾]¾ÇíP½ ÚJ¾âz> µ”>h¨ð½í´Ï><=W½f\¡½ ÒܺbɾÌÚ:ð>á˸=%¾´½¹)Ͻ—Ž¾ÉŒ=Ù” >±Øn<¿]$>ï¼d¾ÑŸ½«=¸°e¾Åô=Ck½æ,’¼ÅÙœ¾!o¦¼¾ð½ñJ¸½¤k(>74>Ì1w<|>|ÒÜ>“M>úi7¼ŸC[>¸„€>ScÝ>}ý�>E«E>–=®§È=’øH> zŸ½î;)¼-œ¤>ÞÃ0>«Œý¾J�¾ñ¼œ¾_nI¾[÷e` >z>@U=s³‰½&ã!>KÌ>FÐ=Ϫn¾ '½6-P>wŒ¼XBE¾ Uˆ¾U^X½ÎŽp¾Ÿ'J½â©-=ÿøŽ>^è¶¾êò:ÒîȽþä/>Av¾)r*½S(õ½ 7¾³‰>Ò!½’ÖÆ=¤ >¯R€>$蛾Niƒ>Þ$·=ŽSH>¡ÑÊ>>{°>rKF½³tî>fD¾Æsý=ýûT¾0f¾É]= ¼¾q¢‚> W0>�(7>©¯J½(F.>‡‘3¾ˆÍ!½ú';Ágô>Yhª=�7¿i¨Ë¾by½ü¥½¨½ò5ø¼ïYÒ>Þ¤a½ûã;†¨â<Ý‹¾>0û½™l‹=˜î¾yƒÏ½ÿ¦—½ …ù½Û�+¾¨9¢>§i:¾@µ]½Í’—=”»>&jH>éI½¥ÕE=ÂŒG¾6¼ ¾”©¾ù^¼˳¼¶̾aÜá=n�=/ü>=åÕú½à›=¦Ú={Ï>”>oç#>ù>ñ‚¾×Q>}}>Æò˽,’ >"‘›=Šî->õ™¾%û=p‰¦¾uGˆ¾Ã ¾A‚Š¼ÏŸÀ>p…�½TP>þ-´½£ÝC½Ö‘&¾N‡=Óçy¾ÒÐI¾  ¾ÉľYøU¾‘_ó½á*¾Ô˜�½Eþ’¾á=¦=¿‚¾˜>Ÿ[³=ã(–=Ïê½Gh¹=²O:=ãe½5¿A>BÁ>T!�>‹v=AòQ>Gºj>Y.�>¬Ãs¼BˆD¾ á=Êó¢>„Er=O<¿yó¥½J™¼ÄÅû½œ6½Ù=�c>bó¾¤èƒ¾î¢q>lh ¾[YÊ;üÒ&=Šö= ƒV<~îÛ>݃‚>GƾK÷¿¾“ˆ³½¢‰ =gg³»[ª¾5l²= %™½Ë=½Üú¾cËÉ>,'=Þ:8»çŒ½iú>|/>°Æ=¾7Ǩ¼8)1>D$¾í½dûˆ>8®¾{GQ>¬¿¾>as£¾Ó?<¬ˆh=}>=󸫽ÊÕ÷¼ôœà<åÂ"=áD½UÂʽX!¾R;…=´ü˜> å+=3V%¾¹Ã,½žÍä=ô”=r`œ>¶Ê‘½Öd$¾åi€¾óe‡¾ä/>€; ¾ÑS¾8_Ú½KÉR¾ñ ì¼A ñ¼êé>Üá=ÚÛ4¾ºq¾8­`>¥Xö½Ô8½qW¾ž3¾Žû›=*Ï(½z¼=gâ±=¬y£>¯c»-å?P8µ½BÉÖ=$®>tçR<« ~>¸ŠI=°`4>‘?ܼ™@¾Åˆ«=¾/$=c^p½ên¾9\ü¼ò·´½—æò¾¡ìM½P Q>0éF¾M'p½Æö½;Ðù=Ž4ú»¾¥6=åܾùxq=åL”¼—44>Û,Q¾¾¦>¸kˆ>¦²¼_=;&7½ý:¼^7£½è3ѽÂ;@¾øG½µö>Õ5º=sqË=÷…Ë=¤hY=ô¸H¾rÖ>ß�¾T´Ø=�û�>J»^=1ã§=ƒ/œ<Œ€=—ʽpK}»¨›½›`A>Ð Ù¼ 'Q¾ý ‚¾;©ö=²þ ¾Œt¾J0�¾É�x¾ñMÅ=,ž…>þº>‰@¼½Ô:½ ŽŽ=ÁÁÝ<49?à§3½Bî£=øÊ‘=¼G…¾è)¾û’=§º.>>È`=3k&½Ço)½ù>˜Ãß½s"¦:†=3R>Ðý”=,�øâS>”·>�ƒ¾ÙE®½æªã¼ïœÁ¾)¼>K”=¦Úö=³x=>y>4=ŠÒ€>ɼ½¾Ùr¾î7>Za£¾=N¼¾�ï>‚¾†¾dó‘>]¼‘>Sò•;Näî=Šfã=›ÒJ>¿ä¨=¥‘D=Vsl>ï² ¾;™Ö¼À'ƒ=È!3<^°a>^á>�»·½î<°½ €ž½^\¼Ñ0î½T׎¾¢âž½X,0>T›�¾ÎŸ’>X±¾`Ân¾B›>Ô< o#¾0y>¥×!>Û´I>:s>ÜT9¾µ©W¾0ã=d”„=Æ8G¾[l¼~§O½®A>¥i=lrÁ¼JÔó½m¶¶èCž¾vj^¾·!‘¾ý¼¯¼¿µ>f*¼‹ý„¼z ¾&*´¼'1> ¯Æ>av�> ×(>‡•=»cÙ=/A‰¾k–½“­>±PX>ºXް«î¼SÝŒ½³¡‡¾™²í=ß¿¾œhÅ= *D¾5rh¾Kf¾ä©]¾$��½h»½a¯Œ>¬f»Q~0=C?@½×½0#¾çÛr=î)½[ô½‹~M¾&Ž8¾D†¾„&„¾`g>NE <ûà¾ÁD>ƒS½.þ=ÝX»æ…¬=À–Ž=ã߀½lÒ>Õ¿[¾�@~¾™Z[¼‡r¾¤”>÷o={2̼ú3H½àƒ¼<Ä‹=Ô°:“±�¾@ª= Ý4>f)¾þ(I>+^©>GðJ¾T™>¹»>Ý•¾Ü|¡¼GoD¾É8ë=ôd;>:—<¾¬Öª¾·?‰½ÍoC½UÉÒ=üÐÙ<&ƒ><�ñŽã’2>ÄS¾e¾‡Ÿ¾œ<Î=¹á½UÖ¾ ¸¾îpp¾XŒU½ñW_½l¦†>æ:¾¬×˾Åôý€§?>Ü¼é½ ëܽŸ~¦¾Pª8>h]>ß±=xc™=â¸=YYǽgÜ<>*Yˆ=aÁϽo½‹w:<¢Æk¾ÿ?X¼}ú¸>øs‹½F6 >Ŭ辉Ve> ãS¾ùÐ>ªÙ@>tY´=+>¨ßü½EH»GÝY;[‡ú½ž5ö¾>2¨=�'L>¶h¸½%O>O͵;¥Ã˾ʣ^½R{Œ>E#Í=2§O<…@ê¼vœ>ž» >ÌÓË>õ0w»œª< (¾{Ç£=Ì90¾^Þõ½ 4¾EϽ»J =v¯é<3Öó;7J¼Æ¨>µ^ ¾¬À¾j½Õ{ž=7É”=n´‹»¶Ïæ¼#¸!½Êú”½>t‹”¾‰`ʾ�Se=«()>* ×½µ]?u¹&¾‘H>xÚ_¾Œi¾ v¤>Dïæ¾ÙR¥½Ú€b½q�ÿ=Ìõ=‡Ú¯=ç0Ó=)®X=r�>WN½G&N<.þƽ¨òã=‘ <>ö]½4P">͘©=5þ*>¥=ƒ=�—>RŠŒ½{:µ½¯…�¼•ܧ=êi–¾”´Å¾-µo<ëNK>б#½0eA½µÞR¾ †–¾a2=ÆäB½Óý2"Ò=RÕ7>™¯½Íxù=µá)½ùƒ¾5“š>qWü=RrÞ½‹Õ6½¦·¾vVM>~�Œ= ¬<³_½èSO>ªy3½¯—̽•G·½-¦Ã<ô2=gS=y0¾¸¾Ë—=ø¹Ä>BÆŽ=üH>6«Á¼'bÈ<`Æl>r`Œ>t]>.$'>* •¾67Q9ðûa>çuù=Ó�ó=敽@@Žڢþ=�.ï=QgN¾jZ”=ÔʾÇ-=‹Ö€>9ç1»Eßi½!>öav½´â¾û»ˆ=xé�>o>gk>_i<•o÷½ûz½w,>·‘¾Ñ߀9 ʆ¾vº)½?/©>WØS¼p’½( ž¾Ü½N>'S)¾æt×½ÚZâ>iU{½‚·�½çý³=*©ï=tu)>‹J<¾SX�¾­ ½Iÿ�¾¥•»›ͽ¦9¤W½Þ=:Fª¾s• N^» T¾¾æU,¼5)½(2=þ*‰>‘Ó¾kýs¾þÇ�<‡’Î=¥SH=àv¾L¨ >è±P½€�A=l4 <Žr½Àöé<–ˆõ>³¸q¼÷�;¼ŒÏ¾Ã2½_;§=6e„>Óx=S§‡¾‚1>6Y¼ûN½†üÇ=Et±=òuy½Ä�= �ö½ç8¾‚©½»Râ<>ø3!¾í•ˆ=Ô[›½Œ¶„¾sÐN=IòU¾ÕZx½ƒ½nMؼ[LP¾ñÔn>™W¡<TC½Þi6½zÍÛ=È€…>œâR=—(=¤Š >„—¾xÇ>Î:=N·¾MX©¾¢¾÷¼N¾aV×¼—V°>Œo½./%>IÛ¾_U—;»¯…½ =¹QŽ>û–^½â!¥=+ ™¾³J>•f¾BÀ[¾_L¾5*Êw ð½I¢>ìíy½*ÿ0>Ÿé½<ö?Šš¬µôj½$;L=§gj¾l&g>†==äà½;Ï«=P>MI¾¿'6<-µ>ò:I¾B•>ì}o=nAp¾ôƒ¾W ¾¤,å<í£½…\�½G#¼¾ ä½”»¾ž v¾:| ¾½Þ²=¥Ü?•‡Ò< y‹¾xÀ¾kå+¾3my¾�y¾ ‹¿( ¼l\_¾k“C>??/ô>ôiA¼ì.ž¾2�Õ¾³Þ ¾óî̾&É»>S¾Œ´¾á° >Ãa¾ÆH¾9QϾW-ü½%²Ž¾¢l¾ÚÇ ½b6€¾é”E¾�÷a=^2«½­Û>(oæ=„Ÿ=T™¾–eÖ=ˆ‚Ó<„b¾xµ¾º¾³ëÝ=%‰ú>(‘‹¾sW½7B.¾sŒ> K�=÷„å½íçX=ø[j¾õîÁ=©9ð=6û¾cDž=µG¾9™½=¦�#¾4N¢>нF>ý O½Ir¶½´È}¾H‚G>²ªÝ>èÕA½yað=¡<�=íyE¾g3>Ý æ>(çè>–>««f¾°=b†v=«ðû=Æœš¼g"½wâ½ü´x½ÿ«†=­‚3¾-~½ò ‡>^b~>ñ~°=@³>¡´ƒ>%øË8›ÕÁ¾ö—ƒ<üi½žŠŸ¼ Îä½x¹‡>ËwÛ>á ¾ê�º‘>^¨T¾8á¬>{òì¾}cɼýñÉ>à5‹>��;n…œ>„™ >¨Ü…>zw½ȳ°¾Kâ�;mn¾sîx½ÿ|<<#u¾S �=øpÏ=‚°½f±ø½Ã¹s>°Ë ½b7=ÞG½?Q,=¡=>¯ø”>ÇZç=¤o‡>,µ =ô¢¾Pà[>FA·½¨—†;™î ={¾Ï=žJœ¾ÇN¾V)×<¸�ܾÀP>Ç�³=%¤½Cp>ƒp¹¾Ü0ð¼®��¾`ÌX½ò>]¥Ô=­ §½€@ ½‚ <É»<]£�>÷8r>5{.¾";S=úZU½¶À“½m>ÙÙ<Ê’²¾/g>Ê|˜=×u‚½-¨I>Äpü½GH¥>ÿãc½Ïì}¾0Mô½N=$?N!?]!>´½Ÿ¾ ”d>§ ³¾ãâÅ=i ¾SŒ¾v7Ù>^Û½ò‚>  ?j�‰¾*~º½ë=†Ëj='S½t ®¾¸Š?#»¾^�Z>'½N¼?ªÊ¾ ñ�¾ö½…ä�=½>"ž�=‰G=ó%á½Â0æ;?N>�…<Ûè–½ܧ¾Ì{¾Åè½½ª!=gÿ–½¼lž¾´§=FQ¾#º>‰eI>—¦½Šµ?a?½@Õ;¯FÌ=dž™<”d콞\=F^¾&Ÿû=Ì^>¯ýؽ„‘•>&¯u¾><3>áHÉ<ÿZÆ=á²ã;¤(¸»[ñ½ËL>>²+Þ<Ù]½ã¥�=šN¾³…œ=Êf¬¼óP®½7�•=‰žÎ=ŠB”¾¹�½À:e<^ ®=IÆæ½ ­=°ó@¾hÅÍ=mF¾‰‘¾~8 ½b\¾/çc¾ ³‰¾…¤E¾�Pm;“àì>:ü½þPð=KG¾FL½4’¾åZQ>ûè~¾Z µ½Ò`Ô>ÿ² »Ê…T=nèI=ë>™Íß½^í'¾'¾Ž<> ̆¾Tp°=ì8{¼)Þ‘>"”>­Y§½3š¾G€É¼L>”[=fw´¾'ZÑ=«@�=mù½¢ÊC½>ƒB¾ŒIœ=ú•ž>í|6=^ø‡¼¸g+¼ÌiÀ>fŒ¾·¾I²?¾H”$¼èȳ¾7nl½[1='©!½Ã˜>剨<O辡®Œ¾-Ú¾²(㽜(>lR‹=°£ƒ>Štv¾6^³¾G;>'â¾=³·Ã>ªG>£>¨¬=ÚÅÀ½Fñà½�N ¾¼Ù=F%³¼nš=x÷„>ñf‹¾š1 ¾ÉÞŽ=ðžÛ¾Þ�>¢XÅ>ê—’>¤Òù½ƒl¾[º)>˜¥ð=�¥->ŽS%½X2*>«§¼h¸}¾¥Û\¾•ì<ú¯¾²K¬=Š{¡½ÑÏ|½t>›x>ÍÚN>H×S¾ÿ޽´Ó‰>ûü=ĉ>"¡×½«¡h¾�Pa¾J¾·k¾s£¤½ÁkR>òP>½‘#=bbû=™L>™v„¾M^í=«çã<@ø1>‹['>ãïh½½ê >Éά½sO£>ÊN4¾ž-B¾Z¬=ðÁÏ>àŠ=µ}G>9A½Üø½ØÎž<±�ƒ½ÐöO=ÙŒ>…lb¾ 0Ë>½éã=6¥­¾«¬*>Ž…|½ãMU<·ÓÃ<Ë‘‚º�õc¾PÁc¾„ïŠ=¼–w>hÅÞ¾;P$¾ÎŽ)¾¦Yª¾>È=+`b¾àˆ¿½üĨ¼ï“·>\²z=?ÛV¾‰-¾1Ôd¼ôØ´¾9~>\P=_;¾M­>%n¾=€0ê>ç#¬¾æ'‹<  ‘¼Ï Ý>'î/>>´=”ذ>†U¾›=H½NqÞ>Åߨ½–�‡½3 Ͼ]ož>ï4½†î¼âÜ©>¤d¾÷�>Ɔ Àê£=–‹j>õ{¾çi>/c¿>ì(H>;½½>ªÆ9¾&ý»½m›¾+~¾7r½=3õþ½¬L>§st¾qv�¾�¥m¾0 Ø>°¡Á> ‹Ò>_ò½sÚt>¥P>º~ü<ýÂ7¾‡>fÂ>ó ->Bß½I;u=/™¾�P¾X>¬—F=°�y=qý¼Möl>3Û=´¹¾o;N>4\Z¾RÞ"¾d‘W¾b“Æ=ý�=È ò½âÀá=âüǽß"å¾õø½¡‡¥¼ªúî ^0¾ G½¢~“>íz´<¨t>Q >UuB½äø¼-Øï=,6¶½<¨½åŠN< °>ï*;5šà½KªØ¼Dêp>z6¾ƒ—M¾}å—½$&L¾c>Í›™¼Ù2E¾€è5>GìÁ¼m;“=bÛ%¾Åž½P¡¬½ ³<å½£;’½Ã´Š½>ך>$†>.[=½Ò–¾d‰^>Á¶=™ÓP=»·ÿ¸`¿$½°Þ‰>[Ù>uê =%+¡>bò½DMš>ykÔ=ðTŠ»ß�>�Â>›&¾Ç ¾÷Wœ¾6]¾Cƒ>„„¢=ñ#>¹-N½^V¾H�»½Oº‡>`¯Í>Þ3#>Xè–¾ÅÌ…½MJX½Jµ=>á_>åWµ<>±B;Œœ>w³£½•¿k¾ÅýI¾w¿T½n㊼‰ Ç=Ÿ>¤f^>:x ¾ƒ¼+>”0™=ýY=˜'©½”‹>Ú-Q>`C¾´�½èJ=ÞÚ0¼ó=l{%½®o•>%õþD¥I>Õǽtà¡¼ÍÆ�¾·Ä¼:!Ó½ªE}>‰²=.0¤½X ¼;K°=ÏiÕ¼�ôK=rŸ¾ÚR ¾nòõ<�,K¼¹üË»ˆa�>�È"½�½=Z‚¾,E¾Ù}�<Їw»(ðO>Ïw=‰›B=Á½Ù:Ý…¹¾¹žo>ëÉ5¾›¶ >�\=F�Á¼ùÐ3¾–®B<õŸV¾·L½l9\>/Ëâ½§í{>]sÊ=󇼰"¾-Xß½¹4F¾¯JÀ=x9Ÿ>Ô* ¾c›¼¾ÒÄs—€½Fã<ã“>-d&¾DŸÎ½3–æ½?#=Ó4\=d@%½mÏ`¾"Ûß¾  ‹>¹*—>“Kí=ÿD7¾•>0¾ w ½þåk½SV”¾à÷> W½a‘M¾õ;Yð–>vr]½'K]>œ ³=-m=/Ot> 7é¼Y¿=¼{Ã�¾è C>í¦=¯ç­=�QR<@޾MU>2X°¼õ^‰¾[ä’½Ó­›>y¾o¾uG‚=iÛ�¾�Õ„>(Õž½2Çì<¢–�¾Í×í½žï¾ q¾¹�=~ÙT¾ üs¾°-=�jY¾©…á½Þ4×:Oÿ—¾Çê’¾°�U>àV‚=Ú®”½=£=¾7 [>üξ= X>æ‚Y=÷û+¾µ”>Âm‰>ãªx¾)”©=HÑn¾ E¾Ð�2=å´X>`«_½˜Í¿½Ð3>"?ä½ ‚;¼•f®¼V^¾¤Hà¾Ë­ö½Yµ5=dgǽ ºo½É´!½Mt=ò~¯¾¹”g¾Óf¾zô€¾P>¶o§<7?>dÒ§½j:0=ˆâï»fm >;QŸ¾n­½&ó¾üK%>^Ýp>V:é½§¨1¾°˜)¾ô6¾d�½†Èù½KgU>çD,¾›ö½«œ†>FvÛy¡~fn¾Bž;ô�¨>:ú>R…a>Ÿ§¾‡qS½‚I¾A6®<ñõ�>Š‹3¾Þ·Œ½‘À#>ìù÷>~¡-¾~3¾ìln¾:³»É'!=ˆnó<¯2ó<¼t>,B̾姽Uׯ½;�>,L›¾œŠ�>q­Î=òfà>å�Ž>š >^·=TÔ¿I»v¾†Jä>U„â<îÛ>¯å=¯N½\°Æ=8è¼?c>5Ç#>Ô¸ ¾M—½‹âž=� @½…ls==`’½Ä&;=p‘=Ñ7©<,‘¾Ý�¾ì¾îmѽ Ok¾e]>ä\2>ùœ¶¾L“§=e€7¾+–~½�<ÿ=Å]‰Ä\ð=`=�>͇±¼<ßæ½_?>س(¾½bÀ½Àa»>)ök>Ê.U>Á€.=Œ‡"=]½>£Äþ;f˜S¼Íæ²=ò“Œ½¢s”=ê¡g>¾˜Ë=Ã~‡=t„½‰ ¨>~®ó½h¾µ>V%R½`z4½øë<¾áw¾Ä̽­Áa¼²8æ<ÙÚP>ȼ =°ÄL>%Ln»¶Ù¾N¯³=CA–=v –=Æò;WæC»Ü¬ö=äS]=ê<£¾:îмoà;>Vžè=;Ž>*œ>Š­ =&$�¾Dl=9·¾ •¬=u€¾Sšx¼¶Ï$¾ BÂ=©‰ >Ð)°¼w®0¾çô=àF¾~=6½¦ã°>ðªõ½"�&¾�[œ¾Ñ®ê¾­ö+¼ÿ:T>žìP=e“6=œͽԘ“=ÿáU>L…>~쑼6•|>m÷>rÕ¾•r<É&=~uŽ?[Æ»¯Yu>}Ñ;=ŸíG<òýL>DM&¾ùåê½vs½{O=Ö˜½C¿�¾úàÕ= E©½Q)8>ŒP ½Ÿ^ª>òáù=ýl'½ÏÏ=¼0¾2ľb=uö¾•Be½�ÈɽLl<¾-œ½Ðõ¾C% =)Õï=D=³^¾;ÿ½…�-¾ 𿽊PX=XÔ¼éË„¾œ+P¹úÙ�>x³–¼ðÊI=¹æ£¼Õà<ͼ>$×= e ¾ŠEð½ÆL¾Mƒ…>Y³˜>3‹®¾15\> ˽ílx> ©¾ã9¢=®Qž¼¯¨­>Ê×G>˜íÂ=ò”�>¯¢0½NJ�½±S>O‡'¾Ž>¼¾†•¸>¶èƽ«ì´½Y\>ê䦾5¸¦¾dÖ»>�tŸ¾ Í�¾¹þ‚>fݽýíd¾¼oû¾}R€¾lRl¾ÿŒ&¾_6Z=Úp’>Ÿ•Ý<¡ëξdhˆ=,ÐØ»ß<¾­ý_n†>Y#>¯Ðx>#@†>+  ½£p’¾0 H¾ ¸>îÖ¼½—R^½úüG>Qì>ú¸¤¼û?½ü·¾k `½ªòݽð䥾ý ¾íü½ù +¾,¢<×ʼ‘ú‡½2ëg¾\RK>û;y=3tf=„/¡>Ðy¼¾ˆb<0Û8½1¦Ì>«¥f¾ÉÀ¤>!¢¢=Oö¾ :>x¾Ó±™<�›ÆÜ7¾F>��…>xÕ>�j%¾'DŒ>`˽>Žz > ÔS¾0‰¼ÍGý½ñ½;¾j>¾9M=-ÔX=¼3o½ç¿Í>•é=¾Ï‡S>«­=iea>Õ*ß=8{Œ¾§±H¾TÊ=ö '¾Ú>ÐÞ0=ÓŸ)¾ðQž=Í_|½k Ù¾D`o:w>8®í=ñ…À=™‰’¾¬¾K¾¢i=¼è¥=ãá¿Îat=.âq>�I>_9â¾¼' ¾vH¾§·æ=Ö3,¾i›¾Ûµ¾ˆƒÃ½¼"f¾ï*¾Ìkõ½z¨>Æ’$¾”ûõ¾‡|¸>Àê¬<œtE=œ ¾¹î¸= ¾¥��½]‰&=ºÊ=Í[¾p¸¾M·§½”�"¾12%4™<Žg³¾)èï¾DÖ«>1»Š½g#ƒ>wx·=OQá¼—Gß½Dä/»#ÎÛ½úÕ;>}7[<”ä–¾mÙ>&Õj<‚A:×”:’¾#w>‘UT>ð8>]ø‚¾ÖŒ¦¾ Pá>ãwª¾Dg‡¾ëDx¾²&¾3‚2¾>{…=¹Ø¤>Ï*º½å¬>ðÅÍ>�Á�¾Û¶â=îÑZ=�“÷½Š ´=×Ü«½þ_>&É]¾Ô¥e>t¦³<´Á ¿l½m|o¾£�[¾¯é¼à‡ >ž3ä½u‚9>èÌ®>jùó<`Å»<Ólž=›ó>j©,>‡?Ær¾w‡¬=‘ý½L£½ù‡Õ½R:¾]4Œ=¢ã˜=¸¡Î¾å.>rS†½mp”=o®>̳λ;�<>&¿¼á‚i¾!nm¾aç:=«ò=KN?goŒ<Œ=¡1‘¾à�ª½ân=ÿ‡>P‘>UϽ9Ї¼ݦ=ê°¾Í\Ì=àáÆ½G:¹=ø8«¼£:½{M>±¯¤= ú¤»0 =O‹¾ýp >'õY>+ ¾Hy°<€A»=w¹�>—ŒÖ¾½$Ö=L)G¾äB‚=Å5¾á(ƒ>´[¤¾)º½sâ“>ö‹ñ=xܾ>“¾H{D¾uÙ¿¾Eb¾†n8>ô>=™Ž=k{è¼÷K�=_tè<êm>O†�>«ý—½«¬!½W’=:t­>(=°¾ Ëy>šìÔ=©¯|½Ùd—¾.WC=ؽäÇW¾ô˜å='÷ ¾»ï½Þѽɾ¢eŒ=5Ò¾¬±{<ÝyÉ>gQ¿lž>Hx̽8â>Ñ*–=o)[>QÜ#>R<Óc>Þ¢²=øL ¼ç9>å?›<Θò»Àî>pÍ{>É¥J½çŠ>þ²Œ½�ÌŸ<šUg½^ñ>³ùo¾þ"O¾é ¹½ÔK¾Wè¼>I6\>íJ»> o¾bùâ=CT‡>ãg?ï™k>Ñ[%>*áš¾`Œ¯=i´“=œ€„=e:Œ¼=~:>²=½=×Ý<ždª>(̽ª³É¾lDª½•i¾8~ô¼~­>‰ÿ»=–3‹>PbM;÷ô½Ý>L3£>näò=ˆJô>¯cg¾(­X¾9´—=ð +=r®¾w÷“>¼Ìt½¾`ƒ¾b²‚¼[89¾ýšo=üZ¿Çå²¼^¥¾¤Â ¾Vcƒ=ä ¿åd=÷£E¾æþ0¾ª&¥¼üAx»†­>¼I)æ½zõ½×·9¼KØ>9åݽ<„>$U3¼ñvœ½êöç;öÍÿ=Q%Â>…;1W$½Äå'9©|¾tÎâ=ß<_@,¾L³Ÿ¾Ó.²>ËÁ>Â’ƒ=”»JÌ4»î}°½g'{¾¨Ç½àOÖ:�â=’5g>^Ó¤¾¨)D>i>Fy>Nn4¾Ž0©=P5оÐð7¾ ë�;;nƒ>Úaû½¦Kñ=Ëà†¾È׿=p$½ë:ü½ah¾õý·;WÆÜ=<ë">ÐÅÖ¾egü<=2=Z¸Â=eC›:)¦A¾­EH>;>r:7=¸“´>°ä˜½ÌS”¾¶˜‡=?ì>Ô&¾ZÂÅ¾Ö Ê=oOø;ï�m>¼µ=ÄÖ̽ 2s>u°¨<# ¯½ä{оӨ˜>yž¾¿êŒ>¹/ ¾`Œ€=K† ¿m¶Ë>y $¾bŒ¯>+ë¼»¿ S­=™q>fO�¾Äu8½å¼h»+>²‹¼Èä—½¶Åª¾j…u¼ŽÖ=¾P«=²Ç>©o�½ŠH¾Ä•‘»ë§â»5ëR»!!U>Ï«¯>†·s½ÐÿP¾µ‰A¾ìî½Ry–<ç <¾ $µ=tòœ¾`Ÿ‹>òa¾aë=Ǿڸ>>jд<ðJž½R€�½LL_¾lÌ2¾"~Y>€�m½((>6Á\¾§§V½°ñ˜¾‹>.¶š=߃½â„=kH ½œz¤¾K‰/>ý£À½o—�»ø&Ó=ó,Ÿ½Ê°Q¾¯øþ<Û#>ɦ1>¶0V>™Ñ¹½`>¨…½Ákñ=~R½o:ò=R>l¾›[•¾jç¾$Ú4½ÏÐc¾­>®¡I>¢Å¾É½O¾Cgš=Bü >Æ.¾µ3ã=ãy<¾Ø>¹]…>.1¨½Ôé=s½»=Ç/G>ÃSˆ½93ˆ¾ôØÓ½¢÷¾áKv>EH¾z7�¼¶&z>pK>»Iɽ&Е=÷¯†½ÛÐ>óQ!½@¡>Q_‚½„”½«?»О=¸X>­žÛ½¬¡¢= \}¾Ý€ð=ŸÆ½S¿â½JÖ¾?�ܾËÝ„½Ù_7<ÓÀ>¾ã�Œ½ÿê½ Ê=�Ÿ ºlf³½8ïp=2>¨">Ÿ„ ¾ÖÐ=cg>]�Ô= „,½ Š:=NÏ=7‚‘¾ù¨Û½e¤>¢‡v>eˆ•½§kUC8 >:Ñ5½O³x>(o¾ÁY¾ ¬–>ö‘Î;¹d¾æ â½PÏ>mk–>V£>Úî�½a‹¼Ë°½ÀW>CE9½Ö̽A�…¾°ïo½h¹Y>ªiL>Žá:>çx¾V¬â½g€y¾+ë½aO¾:¶á½s;> ?�>ºEý¼ú->ã·6¾F.}¾²¶�=ª^¼ ‰<¢8z>!¬y¾Y[&½Ìо׀¾ª,¾â$š={ô>§¸>-¤>޳»=úͽöØf>F/>Ñß"¾Ì³5¾Ë=*뾕’v¼2ÝK½Çà´>á¦{<,,¾¾×>v)¾p4R>‹i@>Xë>±�?Õ¶Ô½0ªü;W§¾‘ËA>Äu¾õ°0>({Ͻ£Ÿd>ßëo¾Ÿú†<#°$>gû=èĽÿ„8¾^²½©K˾xc=GŠ9>k&®¾¨&�=2+_½> ë<ߎ>Z˜¾¼½Ž<ûU¾®,ˆ¾¿v§=¨ôI=C>?> ­¾ Q»GÄ¢¾ ª•¾PYt½ÇÛA¾L­>}hð>NåÖ>%> Ü‘>O R>ø›»ÌàÓ>6w=iBh½p½–½/žI>V+¾Þ°”=5ÿ>Òæ;-ú¤¾ie>´f>W.>Ú«Š<4”°¼]R¾º^>œÏ¡<–8�>Ìcì>@þ¼ÔòؽtNµ¾M[½¦¥¾–«O¾GѸ=ì]s¾íÙ'>†>òÍQ¾�¢‘¾²i>ô޽â~¬½7>!�…¾ Œ£;E.x>«€¼ÑÔ'>CJ½ýº<=�à½|a®=Ù1ˆ¾^–¼prŒ>{˜çg¾ýfÇ=™½¾Õÿ½ÊE²=*Âî=ùw>Ñ'L¾Ó,=H²@= =¾ug¾ä¿>–s“¾`>zµ\¾é}>v¨=BX¾(Ö½¤¿Ö½T�F¾ )‹=Šо¿e½X½¾æ–Õ½zF½’Eµ=áÄ>É¢>ɳ½×j^½çd¿½? >Ð[>‡A¾Y6Í=!iƒ¾N´[¾Åƒ>›äŠ>'ÃÁ¼¼A»=JÉ�>X8ª=*ìɼd$�¼sž=›2/>—lÚ¾%S³=>w =É®¢¾CZA¾!þ=–Ó>zÍ^>aö‘½&ܽ=ÝN>©ƒŒ½^–s¾4¾Ôn4>¢uQ<#>MUK¾Ä >¾F×®¾‰Ó*>t)>ñž‚¾#r]=gú¤>5c<½[r\=bÏ=8“=¤¡Ò=Ô•ºj´¾6!¾ "¾zb¤½X&.½nF°;²‡½1:R<±rf:@ÍC¾ýŸ~¾”?G¼&ÌU¾B^>™¡m<“Ì >kú¿ºñ¹Ý>Óu̽m3T¾9W¹½s§Ø<:ƒ¾ð`×=æ§<=®A ¾Ü¢^½*©=_¡Ô½néü½4é8>²yd¾L n¾Q•;¾…þ½þ̾ÈjÄ=ø¦Ý=cøZ¾?—§º¾ò–v>™ú<¾ö ½N±Û½ôý>ÝX,¾,½ÚwY½˜Ÿ¾á] >ÇÒª>‹’‹½£= >ãHí<}©*¾ý½l½­Ü;½®ž ¾ ƒ½wÄ= s�>Dc¨>B§.<”~ǽp=1>¯6>rÚ™¾8ªª¾R³6=.�н õž=™·Ž=ðL«¼âþk=Ò!…¾$ô¾ÔÞ¾S¯ >í7É»€ýÍ<¼ Œ>ƒe<´Œ=î#ȾhnC½^üñY>B>õð½Ï†¾²>ãìß¾¾–u½À•ܽƢÿ½§†'¾†ƒÆ½Åõ> /E¾¡¬ˆ¾é¼¸½oÙ‡;%Ri½$íH¾£R¿=˜ ¯¾rY=£¢>³T>ú (>{ã긂洽šV¾Z±=ßsï¾Ö×"¾ »§>˜5‡=»;;>½ >d&#<Àæ=õÅî>––ä>,‡¾½¬8b¼K$^¾(¾(bË=ü(„¾¹nÑ=k¾|>„†¥=»‚‡¾–£p>|St>.dh>¸d<l”=ªuh>×Á4¾�¶¾FÍt¾æP-¾¤Š—>@”J>3$¾fD> p�>¸]>‹@ò=GW€½1—½— ?…G*¾îMƒ¾-ýF>|«Ö½WŒ³¼Ë•4¾�°�=äLš¾¾²–½«l¹½×àô¼žÛ?°ö=òÙǽu D<‘Æ/>õÁ\¾{‘>^_L=€a!¿Þj¾>ðæ > j;>êÀˆ¾¸I½ÁµF>TÔ?½…¡<<óxœ½GB>wÒ8½;ï>œ°Ñ¾�lg¾5z¯½yp">ס†>=)“<¤$k<„HX¾õq">vq÷=8¿dY>n‰D½ ¡½˜=®>•9½vÙn=³£>Ü`i¾"!|¾¢MͽÎf–¾T“‡>\=ànl> ©½V‰®>¬&y¾mÈh¾vŸ´½/== ãA¾C®½~ï'>&v½�§©>ú‡û¾ÕÞ">^/¸>Þi¤=¯FŸ¾‚�†¾Šô_½K&нüÛ= w=G5>ñU>Ý­=—h?ûi¿½\Ö¾>¾½Å<|«¡>2ðS¼'h¾¤·”¼î›»wS[>§:F>³P>T«»=Hð•¾e“B>/Dp½M²´¾JW•¾\¡­<43¬½ ú ¾v™à<«N¯½+´ñ½ò“¼2Y"½ã]+>#—¾(I>äÞ½÷LÍ=eUœ¾È“Î=‡Õ>P"ñ=8[•¾{0�¼_:ˆ½¢"¾¶¨;¬´ºZ¹:>n±e¾¡åÆhÉ>SÖ=Ë8>=ž{½/.¢=ù ¥=�nºù°�¼#xS>Ü6½SUù½Úv;¾ûŒ¾à<ß½-7¾Ú<¼D´Ê=2^1½zC¤¾Œ 転 @>ØU‰¾æf›½)¹”½Dýï½p*>ti½ÐG=QÌ3»æ&>G¸4>öaÇ=µâÔ<è’¶>ÌxÏ>dú•¾�þ⽘ÞC¾’|0<·gm¾e‡•¾1 O> ©á¾Ô¿¼ly½ä±°=õ‚¨½Ü³9¾Ô(ì=$B7½š„¦¾ç…>½<áØÛ>Ö–>ÎÇ<*'¾œɽ(?b¾Í-¼>oþf¾|[ê=j(ƒ¾(X¾¹Ä.>Ê.Œ¾;(=ŸHd¾i±¿�"Ó¾’óU;|Ð+?.i->–ͽë‚Z¾½†=ˆ�>*¬¿>ÿ›É>ô¯¾±·Í¾ij>Huî=õ{Â>’¾y�½B¹e>ÑEí¼‡»Á¾¤>·ri¾b;¾wù_¼¸+ñ=ýt>LùI?®öï>éŸÜ¼üK¾©S‘>0{r½Áÿµ½Cœ½x«x½¹ÔK>jCȾA=¢½šân¾a—¾×²º>c®> ½C¾s¼8½¿Ô½¾?¤)<‘[j¾Ø¢>°>¢½LÕF¾Äbоd.û½sÓ<*©={0#¼Åêö»õGŒ=Ý|u>—:ü½°Å>Ñ ô½Kÿ;>­\'½ð¾V [ºDwĽSü^¾|¡8>�‰“¾ :‹=¸ê¼¦ƒ ¿çÓß;Ÿó™=“$¾>¬£k½ýFk¾[[¹¾Zµ¾äü\>]µž½ >”°=:�Ò=Ù2¼Ã3¾žï§=¯c>õäY>U¨–¾Jü>Á¦Ÿ¼2Þ=å³Ç=áø<€„®½¿9¼¿¡Å½|¾DGœ>xæ5>)g£½ê¦=å=­‡Š>‰;¾òN¾6�ç>3Ÿá<à!>ø)?ƒ¾¤r¾L‘Ê=“‹„>æ2Y¾IÆ=ÿ@¾í+>­î€¾)Z=S(ì½YÔ�>Ñ¢>�r?:�¾�ØÖ=á#-¾€wÚ='³B¾ q3;_Ú\=Æ£»� ·<ƒß ; Î=¤ôí½Ë}¾ç°=ú6½#–%>²wF¾]o`¾ÕV¾UƒÛ¾2>€Ö–¾ÌwO=¼Aµ½Ha<¤[¾°›J>n]½ ³3¾½ì(¾ß =ýVþ=ZÕ<=¯Õ«>kbž½ü|é<ÓJ >¸�‰½„]˼‹PÁ¾¤>Ž·?«¾íų=SÔ >*±>EŸª¾Ú…¾�¤>ÐG¾²} >¢Ù¿Æ–H=ż=bŽZ½F7½¸ê¸<œ}c¾´o¯¾¹”½ŠÎz>øq„<Ý»¾UÆ“>þÐ&¾I[>�O¾ƒŠ`=į >ôœ=ýã!>÷7Î=g£>�´B¾l¶§>*‹=µ½+¥`=2-d>^`:uâ¾D� ¾â§š>†Âg>zBa<ÐK;¼Üü¾…úû»§[k¾¼¤>L7—>uS—¾)˜�<‡Ç½Ô ˆ=Æx¾ÈÏÊ=d±!>d³à½ábŽt)Ľ�ê±=6—‹<Çé½U‹¾¡¥›¾Îª�>±å§>^°>ko=×ÉV=hL=¶!">;ÔÚ<º^̼Žlž÷ux»è•°½h6>hŽ=æ°>¬�¾‹D9>ßZ¾£d‹>Œ¦à¾Ø+¾íBn>«·e=@žÚ¾;×1¾¶)¡¾À>{¢�>D}ò<5Å`¾Õ¸1¾Dé<ǧT=ìbœ=£üÿ½ož=¥ª¾€)>„+>r¿º^ÖÎ>®o”=^Dh¾ƒáá=•Iñ¾t‡²=Ê§Ž»wü»½Né¢>o•?qW>bŠÎ=±#Ö>Я¾ ¾'¾Å/¾{À=¢{œ=™ïA¾÷¶ž>S;ͽ”>Ñ,ãG8=Ì >$`†>³M°¾®Ü�>ätÿ=ðx>N˱>}™„=jÝ}¼Íã\½ûG¾2’ª>ï6*>¦š<ì1¥¾’>�¾MO¾È„‰>g ž<«E½ìŠi¼ôP½a›½½B#v¾Ôˆñ[½9½À�¦¾p§ô½´v€½Í|n¾ý[ ;8g=-̆>¯õ཯¾ >LЧ>mæ¾ÔÜ>ô=Oq9=›’!¾��R=Àâ�>F�¥>a‚¾yƒ >ªI"¾ôÜW>¶÷½i�<Âq¨½õ=Etü½ñô½C€í=kéq< ¿ªžµ¾Ý~¬>£k\>Ðvy>ÞA<»^?Ë.>§²= ð»>›»a¾TÞѽø�K>W%¾ŽÂɽ³2”¾Ç/>�Û=ë¦7¾Í.>‰³–>æOß>@¼a@¾\Ô¾£³>'`;¹Ø0¾Ê�=“q¾º1=OÎm¾ É~<Ö“ž>/‹i½³ æ½Z:½¸”=ü'¾“ä–¾«²�=ó˜³=+ŽG¾õ><=%=½4Zä¾6c�¾•oT>ó 8>‚Q½t>¥Sõ=§QI>rÅ“¾AN[¼. ¾ñ ¨=¿V¬>ÒƒÕ½\œ½•ñ¿‘�½Ï <ç >¤¾XãB¾ÚÞ½Uõ¾}�>šOt½â¶]½5à9¾ÏJĽ&: >’©ñ¾kƒ>Ÿ5”½:ä|¾ÕRD¾„l]= Ϲ¾ÿŸ="’/¾Jã<áÃg>tº½-¾=ÚEg>L.>¸‰¼¾u+㽈í=x .=AÄq¼@ôu=ŠÅ“> ¾jkž¾—γ¾N¾x=6B®=P è½Ð�o½]œ½¸½¾ð"›½c«½#±•¼0Ì=½¦r¾0Ö¾wö¼\�F>åbâ=ìk‡¾[S=YX#<.¢§=ÔL­>ìDí»Üá½ XϽMª}¾vÓk>Dz½»<©º<3@-¾iÃ.=OU¾”Kf¾K½ž=}w ¾ô>©¥Ï=Õ¤�¼8ÃÖ½s9n;Zm¼;´Í“>Z“j Œõ½"ª`½]ÕA¾æ½ôã=¯Œ¾: «¾võ½Ó•¾í6 ½4nÕ½sN>>’Ó½‘îR½¡ú¥½&$Ì=ˆa< GE¾$œd¾$Æ�>îÔ{¾Ê +>Ñ…p¾ª‚A¾ñ…Ù½Dý7¾²†>ñó >s˜¾cö >^œ>Îz?=0ä]>‹>º5K=,ÙÉ>,Oå½Gj³;>ob>ª¹Í½à T¾„¾ÓÎ9‚Ç£<Ü>…�=ƒ–:>T‰š=W€“½½8D>»î%>`vÏ=Qgb¾;Ô®=£[R>,9f>UCí½�ðr>¯–¶½B½ZT&>,¾Ñ>TÎ >�¥>eÿÄ=!�¼¿Hî=§†—½ÃA¦½cId>o�¾ä2L¾”¾ãù¯»òYþ¼öt©¾W…S¾@sN=tú?ƒ»==D¾õ‡¾ñ㉾i²ç½i»y>N�U½)½ë > &ˆ½ؾÒGª>œ% >`‡…=€>ð ¦=|¡„>ËáÝ=&• ½ä->»|…¾|“ð½F• ½;Ò>f½)±g¾D½”»i‹Ö;“C©Š‹¾‡ •¼'$œSß•>JnŽ=¶ÿ>v?!¾Þ9‘½nê>}绾kF=žt¾¢¡A>±>ìØÎ½ñ^¾”ºÔ=ý6‰=¢o>â¼==¯°ô¾ÏÁª>(¥¨¾vὑ’r>þ×8¾ÝNͽלX¾Ü¤±=õs�>5×]>§xt¾5²·>ºó·=›§÷½>w>–‡¤½’÷ ¾ÒX¾}Ù¾Áó>… ¾NE¾7ݬ½B¹°>Ÿú½µº>—éF>ãø<¾`i¾%Ï<3÷¾Y3<Óô>Ûc¾”ó¼=þ…6¾@Rn½¤§<˜ma½9;�>³ª)¾)’<ˆH¦½³ �½Ü|â½~Š=)î=T2>y�>ÀGû½±ûv>`o‡=�)¾…ðê½\+Ä;FU¥=fu>k¯ü<ý‡,¿Kä] &Z>"Ù=‰h >k»8¾UÎ>¦‘Õ"Y޾‚É‹<[`b¾¡mé½e/¾©…¾ô[’¾˜i½dLû=ã×¾ ž³¾×Ä=>rz>ïÑ�>€Þ<¾ MX½•‘—>:ɽrHÝ=^3<Äɽdx¾ös½Ò¨>¾‘†—=t‘Ö=ز‡¾!Áñ<'Õ¾¸Uù½ïÅ輓8ô»ã¬ý¼\óN=GÐ˽SÿÒ<Ÿ´#>Zá¦>¬¹Â=y»<=#˜¼x%>êç>æâÀ>*A#½Å�¼ˆ�m¾))’;€S6=«.¾àÛ >ž³§½¼R©¾¨oû½ßÞ½®-ô=õ!¾ïˆ¾°F<=p">ês½iÅ>…¿ô=�eþ¼vþ”½Ùp{>ÎRs>8C潺e{½Ë¶ ¾Í>ö½§½Ô3/¿t�v¾ÊI¾äRÔ»TÂX>œ¼ >*Ͻ^E¯>TÀò>-/𽇆½4²U>>>ð¼äx£¾TžZ¾KG޽7�·=T$‰¾²á«½)²·½¹Sý½'í¢>{ç½Hˆ˜=Ó»½°ÝM½K©<ض'=¼Š¾ëS¤¾ZRˆ>ÎÒ•=³[9¾Ê«¦=¡M¾úa>›8h½\ >�)Ÿ¼�y½s>ꉵ=/›A>Fûi¾‡�=Ÿ -¿¿Ò>R{*> y§=T“»3çw=—�>¹> JT>ˆß<>6/Ž<ï2å½Ì�7>R{­¾1ÿ¿9I‰=Iê¦>’×K¾ཷ�½^”=IK�¾ï9§»BÉS=ëå²>)­=8 >Å¿Y—¾ ®µ½W³*>†0„=-¿ á…¾¡‹ >ìæÛ=ÅdI>V4·¾íè>½¨µ¾ c¾Ç‰_¾^’¾+tî½1L6>&O‡¾¬·¡>Ïì¨=ÑŽ<½æ¿®>‰>Ôl”>½Ê—¾$Û>…g¿É ¾B’¾Àž¾”1‡>¨Êð¼Èwξ“¾ Ò»ºÇ¿·#¢»Ì†,> Ü_‚,¾3À=ØM>Ðþ͓d¾.ؽdDÛ=tˆ—=²-’>)�v=êK�½=Ç3¾þ =XPK¾˜^Ö¾-§i¾¾wDõ== W¾2Mj>Œæ}¾­‡ð¾8Ì9¾4™>ÑÓy>ûÐù<øÇJ¾•bÅ=�Ð=­—3½€–ƒ½ƒ\¿ê�¥¾7Åo¾e&‚>*ë½!ù¨>tœ=�Ÿ6¾5â>Ʋ={íÛ>ö+ô=†”=e{0¾Z~%>® ¸=5øš>t¬Ñ<>ˆ¼½ãÜž½Áp¾gwˆ<¢“>ª�ý;Ò‹Æ=~üмmo=¿WW>WvL½”@;Ïe~>‰>Ü´ž>46g=ƒŸ$>Ñq¾J ¾‘þ>-3罓üc–½¼ùƒ>R²È=x%¾K)Ø>ÌÚ<0€­¾×e¾¼û”>ªkŒ=lm >Ðñ¿>ÿ÷̽`:ö½­äÀ½ºÝm>Ó; ¾¢çà>Þû=S¸ì¾6©<þÕì½/iƒ<î#´½ïeô½8vL>F,¶>u¯W;Z×[¼Í˜b>U�½ó6̽½ô¡=ð»Á=�Ö=‘Pá¾ÿ Ø>¼Zé¾@ND>"»½h’¾l7e>šø�¾`€B¾Ù?o¾C¿n¾½Éjë½ø#¾Æïæ»ãyf¾©““»Šúø=Ú Å:I@‡¾+Ö½™å½–ñb=8 >&|£½×–ƒ=¥b^½j\ =z'=𦡾¦™>‰Sg¼êYŠ=(‰M>ƒ³´=b†ì=`ù³¼+Ÿd¾�Á­¾·W�=ã„é=Œsm>óA ¾_’›¼Äb»½mâŒ>—¥N>÷ÇÛ½¤Ó|¾Bø¶¾ã"Ë=$Ψ½¤‰§=PÈó¼6HM¾®vo¾Z ˺F ½&|>Y°2>”¾ì'�»‚£Å½µþá¼GÍ,>˜ ©>žVo¼NFµ=JâÁ=�]°¾üwн'òŸ½³`ˆ>c|†½èÂH¾²Ô½O«‡<¹ÿ�<{‚[¾ýMa¾¾¸=øQ¯½Š%x¾|Ž>½ºK]>h =?€¾=07¾m’µ=†¢(¾6¥>ΣB>ONH¾¬{¾ÓÏs>/hŸ¾{îH¾N¤c>Ê9R¥ïJ¾æ� >­9B¾TÄ>mq4¾2Ä >xSÉ<¾¢:¾†¯}¾Û¥Ã½û0—>%:‡½ù¾¾S�›½­œ,>ßÍÎ=uï?=>Ľ¼´_�>ÂD>Ü$(>Ew€>¿Ÿƒ½Á ¾6!Q>Úäy>-‹ ¶uÁ=³û/¼-ÈS=ÞƒG> þ°½Sá=t>œ¾vYJ>Wá§>�¤–¾\:Á½ŽÜ>Ÿ²¾=û¿½6Ê9½h4³=Ñ;=¾]ÓÉ;+Aн\�­½Ú =¥;¾§¾•u`¾C³ý¼]5>î2=JRz¾ÈRª>ÊõÏ;š¾5|¾ºÊ>Öà¼RvŸ;#½[6M¾ÌÆC>â¼è_¾½õ c>j±h¾�ä]¾ÀЛ¾‚¢½NZ¦½::>šÆÁ¾A.½½êº�½<ƒ…=O>Ø>t·Ð=}K>µ½A¾y©ˆ¾t1+í`ǽØQc>Žù<µæD>܇½Ô1=c=[¾Al½�ª*>ú¨î¼ ßž=¤œ;<œ¾ìýE¾IÁƾ'zu=:ø¡=…mÍ>KÕ<˜"¿zpB>s¾çù™¾ö<~·õ=ªgÝ=Õ¼]$¾4'¾ñ4ç<$Ž�¾^Ì>€ð(¾Wo­½Ã"ܽ'B%;ý)>Ø2'¾uP¡>³6¥¾tÿœ¾J�9>µX‹½ö�=:†½X§C½ò¡û<±/•½Ï€=…8I½W~Y¼uÊ™=¶˜¥<Ûä=Yb‰¾7|¼>Ø=#>†-š¾N“ ½u¢½-¦>½½qm>úÖ~=àªÿ¾Aš¾Ô¢Ü¾öﯾOëõ;:8“º^ À=9*š½ÕH•=pÛ9>ÂØÂ½@I"=;Ѭ¾S ޽Cg¾í¾…ž=®åâ½Fç½!u²»gˆ½#ÿ=¥|?‡£>Ï%#¼38 >'©«=ï= >—Q½,“-½Îc<½ÓV5¾M¾9îV>³ø³>ôK—¾ÏM>´\¿»E9¾{Å>ô¹d¾¹ >/Ý«>Ú󇾫ïû=ObݼY÷Z¾ôëM>†+>„Á–>×J4=z\�:U˜¾»©;ó²½ýšŸ=wë<Ö�ø¾œÀ`¾`úZ½j‚½2Òz>„Ö»ÂnN>f{Ⱦ¾&1<ïn�>a^‘¾¨XÛ; Í–=€?;=KÕ¾gR=m²Ö½2>/¡ ¾éc*¾� ¾®Ó‡>Ÿ}>màI>Cß¾>V>¨�®>ÏÎã<}ïã=8ßo¾ˆ¿½ÃƼ½d„È=j:X½=¿ð=‡«>´L_»éý¼�ºr>ÑWâ<‡ÔŸ½7׸¾ume½Í\P¾B''>«Â>…¦$¾GŽP¾^�œ>™Ú½ ½Æ¾GŒA¾'@>´$n¼ÝǽCÉ·½ºˆ�>7;R3¾Ñó¾ŽèнZÞ„=Ô$,½úZƒ>G��½º• >­c…=z®Ç>Öš>sôŒ=ú¾åð¦½~Ã>.RQ¾ %ß=^M¾–W>9™¾8Éð=Šr³>Ô{ß=§Ê­>PÉy=/×¢=¥.ž¼1zí½Å¡W¾ñ&‰¾ø‡#¾°Wå=‘ÉÑ>ôÊ=äÅ‚=øJ>ŸÊʾ÷¶Ò$ô@<õÞ¾‚ñ~>ß57¾ö#¾¾_V(>¸'½N€½…Á£¼Ùêž½‹®¾¤v>ÏEñ<œA¾^$ú>|%=ß“¾y¥¾jâ>4£Ó<<€g>KC`½¡�l>*€/¾­¥>¬‘8¾²�¼¼ðr¾qÔ~½Ðö>°y‘¾­Ä£;J¨x>&f›¼ö´›>›üƒ>_Ä‚=Â0x¾ø™>þ‡Ó>ïnŠ>„b>cWò½?—®¾�l“¾#^¾åg/=†R<”�‘¾°­¼Ž°¦½Ú—_>›[>˜�ë¾ £Ñ>À÷=£l4:\6­¾~Þ‚>$cl¾¨ÞŽ>‹©?ˆR>¼Hñ=£ƒ>#U>–âÆ½‰‡‰>@u¦=©!ª½=G-¾õØ ¾]‰>Ú�„½xµ—¾ ¥u¾bò“=R~K¾,œ ¾S‡>'²>ƒ>.=ˆ½…ûe= â=Ð�N=Eà >ï›=[ó>ÚJ¾sª�¾® +>ä…7¾¯•µ=Ë€’¾tÎË=£|˽޲=檾ˆš“»½”`=�1�¾!–Ý<9f¾�=ö¼~Ð>B"½i¾!ßb=0e©¾Y”<}ª=áïˆ>šž¾ÜI>Mƒ^½$b€¾½±Ï¼=>ðbâ=暴¾i— ¾€Ù²>=ľÀ 8¾‘\¼!Kξ{Œã½Ð 8¾(5‡>þÖß½ðS¾…t!¾þ›î=_†Ã<P<¼Êy½d’>Î&æ=dR ¾øšÞ=}{>•a¾ö¬=`ŸØ=S,> Î#¾òI¾1«�¾¬”&=À»¼ï³@½(Ç®¾Öt†¼ÀÉ>kàļ;úļŸt“¾¢ò7¾í7m½÷ì=ƺ¾ŸIh¼-Â6>+ï¾7"?>H¿8?}#¾$�¾Ûm«½gýe>�ì½Ra[>X[ ¿ùa>㎾‹ k>Z{¾O¡=¾û½ÃS¾*@轤>``×=qø6½V„ß='`c>2ù¾Ó?i¾º4 ½”-¾û@V<†wZ>Ó…d¾@W˜=]ï’=f*¶=`m¾¸;H=¾Z·Q=JŽª=l�>”à^=ù)F>¶޾¸lp»Ñ5>$N¾¼ú¼`8=$-j¼{ƒ>{>"ó½Qï9¾î_Œ¾&Mœ½Ì™Ü½“>Ù½)›> F™¾ÉU©&»�Š ¼=®k¾²‹>.ôž¾"ξ$›¾©á�=«Úv>p.¢>·‹Ñ½O'¿=A8û=…Kü<'ÃN>ö¼%›¡½îL@¾H≾; 6½/нÆj§½±õ¶¼gq½2?4¾‚�;¾9>¼µ5>'×T>ãÁ|>Yß”¾jù‘¼Mf¾= ѽþ¤¿¾¼mú<+ê¾ ä¾C~ >³µ=Pôn=<Þ@=±m=†Þ´½‡�¯½¡ñ¾5W >,éÌ=ãg½ó6“>›ZƼ¢^¾Gq%¾·€¾Ðf�=ö‹·¾çÖq=ý¹±<ÇG%¾æ†½„†5=o8r<Õ)Ó½'Þ§=ü÷Ÿ>2õ2¾²!AºZ,?s,Æ»qÒ´=–„•ºK!ç¼T—¿ 02¾DZ=2‡E=7=#>â3¿9Râ>è¸Ù½3Qo>«À¶>+j¾Pgƽœ÷B>´�=¥?D½›kb>}S¾(W¢<œW^=Yžu>^…‹>Æáp¼†/3>}E�<¢š°½ïV¼"�ò¼Ô—=/Ã>·�¹¾"BĽBs>"�='“•¼1<(¾ýd’=âbE>ùD ¾Ù¾ŸvL?72^¾¶È¾~Æš¾Ñïã>lÚ>=Öݽv &¾ˆ½îû×»sõ>†%ê¾à¾Ë=O¼(¾í>>)Nh¾/u<½¿C\>]už¾A½¿¾d >±Y¾àf!¾õ¾æq¾»–-¾¸„>�s齩…>ƒ@Ü>(½¥ïé½%f­>š}E>ØL¥;´;”%½Ñ¶—½»³E>–" ¿µjùºL„¾cÅ�¼á¡¡½?ç ¾"ÄV¾þØÒ>av¤=þXn<ìm½;ú=ri>“>p=Š/>u5…½vƒÔ=OÙ=“ >#¼T¾ÊƽK>F�1¼8ç=0¢â=bœÀ=»¿�¾ïf=³îоíáž>ËÕå=4þë:×M—¾Z4Ø=CåU>EŠ>U÷‡=hg0¾¶I/=¾m(>I€V¾t‘,=Ȉ=ú2>x#ê¼öGå=Á—q%½2wÖ¾4Ø=‰Â`=sŠƒ¾ø™Ÿ>Â÷o=Z¾E;9¾u[ ¾¦>¬Â<=}§ï½ö¬ ½)>m%=Ï�‚> Š%¼ÿS€¾Rr«½]c¢=>Ò±«¾ôw�===B=\½{¿\¾}›>å8>ÃÙ½@·$>žL¥<„™Q>ùŠW>IñJ=+‘¼ Ø:æØè=·¤k= o>Rçf=HòR> k‰>x‘µ¾˜%뾸˜“½Á¾ r+¾¾ˆ§½dC‹=aN†>yo‡¾r?I>ªº!½?¹Ò=³«B<�o‘>3u=¾SC›>�•ž¾j¤G>QC>7o›=Œm½ zß>>%zq¾¥‘½8}ѽ.º¾¾D÷þ>¯Êa¾©¬>Wó*>Ï~q¾�A,¾¹Í×¾Ÿ¢˜¾œ?= H�>üŽ+¾1Â>±Ë‘¾ÿU'¾yÉg½Bva¼ÈÚ=ùZx=\ù¼ŒmP¾âž*>é¿B½¿h¾ðn=M}Š=˜¤|¾’ :¾–û!½ÿ`E='[L�±>ÑÔ¥¾ò´½»Wn>—y{>%�'>,aâ=î¿SÐd½Ü«¾Ù§K¾yù>ìÂÍ=» =áÆ;=¡K[¼E =’Io¾ï§=YSʾœ,¾hÂϽ k¾M(>@–p>kK;¾£º9=hdî>ù6§>#·Z>JV³½* ¡¾§…>ÿ¸¾ÿÍ%=Ìÿ5>Vº¾ W#¾ðÐ=cà‘>d†<>?­0=yÒÛ½Q•×½ >\j�<’ØÒ>é¡ ½±¤¼�G>Û‚Ê>Vgç=�¿>á€=P1A> š¾÷òA=Ä»g>0¹+¾˜ƒÝ¼ÖhŽ>£n�>½S¼;¼ ì =ø×·½á^÷=_å>½ >þ½é>A�ú½®K§>�¯=ta>ðt ¾JEݾîÎ>°T¨»½â@>Û¾Ó#>ͦ¾¼1˜X¾+ë½´ùÏ=¢¶>~­]¼d©ï¾xž¹>¢ ¾Ð,·½›Ê½=4Úœ=ue§=Pqæ<W¾¾x?$Tœ>ÿ¸à<9B¾T>=š2>lN°¾å:}¾L½¼u!Ú=þ¾öŶ¾Ýl>åC½Ê„>‚޽”>ý >ÆT@½Ç�бg>ÿcé>ô’f½E>ؼ˵+>05o¾Â->À›n;k==n¢*>øªä=Çäc>ò®j>«Æ<§Î«¾¿3Œ¾Ò¼»Zª> –ð½唾ñ†õ½F¹›=|/´¾šŸ^n¶½oÝú=àë½vzû=T2=»‘U=ÞÍ<"Ví=ËL ¾´(æ½_¾Ö7œ>øÍÉ>”µ˜¼ab¾’Í=_ëc½­ §=E«c¾ñ;¢¾/E_¾Ú™=;<½‰l<¾Ž\À½–C>×úW>ð$ê½v…]¾ª€c;xGá¼¹X&¾´ÓÕÇ2‹¼²)¾˜}œ*Nø»»B¾oÕ½ªI½‹qÚ½*AH¾ŸK¦>Ê>b #>»Õ>2Xì>«ÖŒ=Û=Ø®½¦/v¾½„ ¾ §¾ž( >Ônô½`It>©ž±¾zä¾G2ê=üܘ=T#µ>ð É=H)z>Ÿ‰ ¾FF¼xGZ½Ä(—¾ ¼Óq».dÆ>?º‚¾Ÿ’ὦòÊ>—¦½ K6¾©Óô¼$g'<ô‰u¾±“À>ÈeV>iÐ:¾‚'¡½æz¾ðí<�„¥½ØW¹º´�ß½³ý�>¬³>Ýe¾ÎïN>Ú…=C"޾V—,½v4=Åá0>ä~Ì=Ù�>»¥¾,:¾Ö³=¾/Z¾Ò�A¼**u¾øW™>ÖŒ½= æ²;9°=ñOS½AD=§&¾Ù/¿>¯½–þŸ¾w…’='eþ='Z¶;wü³=¤)¤=�û¾±Äµ=´ø¦¾Ïó¾w~\>ù|¾”z½Ñ95¾¸%>ÿÀ•>?\£¾w Ì>PŽ>÷Þ½“_¢¾¨�½lbÔ=X Œ>Uÿ«>H�‘>¢4½$À7>| N¼¼”¾¢ëa>�›K>þàù¾æˆ�¾N$=¾™•�=쇽˜é;PØå½Äü–½C8Ò½V¶K¾8ås>Ù=¥¼„ÌÀ=¸Õè= ,ѽ @>¶ú™¼.¶>g o¾N¹ > µ¶<¿Û̽€úˆ>~§¾õ%¦=‚ö >Ø1>�¥=A“©=fÓª=s!@>ÿ=r¾Ãì,>Á›.¼®Œ>¸šC¾G‹>û`Ê=LÛ‰¼=ù’=l»¾|¶¾9z¾¼ÞV>åU3½‰º&½¾*Ó¾ Qy>Ô¯^>R/=“”оFª=i*½záö¼9mv¾)> q¾­9Í=€ô™>Íîÿ½ãož½—=P//>¯=}޾%ª½È]W>‚:š=“M±¼T1¾ªO>ÞåM>=ç?= ¥u=QÛœ>¯[]=qÆ>©ìÓ=ÐÞˆ¾S0¾†­¨>ïS¾½:õ=d›½ï.ʼ¿xª¾ÁÊA¾ÉÔ6¾„0þ¾ÃÏ«=³ ½œ¢]¾‘À¾Ã<¾5=µ¼ŠYÍ>Z>WX�=9K(>’ˆb>ôøŒ½È;(°I½CK>pÓ©>Õ×!>Ý(�¾õAö=Áì½_þ^=Ÿì¾÷ˆ¾Rê¾±5νìÑ“=nª‰=VT½K\=½Äû>?/“>Jbš>ÐÚ½ù1â>çÈ“>™ò=põ^=š[>ÑX†=sÚì=¬yY¾lPD‚Q½^_®½.†ˆ¾Â*S>Â˼Øý*»ß€ž=~7 >ÁS¾ +齈æ�½üÊ:¾˜>ZMŽ<�ëľI)¾kl¦½µç½2×ë½æhñ½î²•>÷a¼¸Û=_&I¾{Þ�>ó‘‘=�L—½Œu¾tÛT>ÞŸ=wJ>`º½QŒ½’3 ¾PöF>˜¯½²cî=*¾ˆ_˜>è�à= ÊÎ=v5¿¾r胾”ö½‰Lˆ½e$3>N[ž¼X—¾‘à…¾âù×½žr»>Ò¢<Ë2›½ÍïÜ=5f>Ò >x$@> ½XàD¾ŸIN¾ÙÉоöe=RŠ#=²¾ï½})¾›¾Ã>nþ¨;É<=ŒŽg¾?”!<F¾­{D½Øk‰½É]Ä<Þн>‰>\‹½’ö½@¥÷¼Õ.>$L>Òˆ{½Ì«>ý> ï">�K¾µZ’=ÝÂä:;€†<Un¾| î½EÂO¾Äh\¾d�?f·Ù¾©5>à}ì½4�O> 󦽑²Å½&½í½}ñÇ=W±>>ŠÚ”>*k³½Ý(M½•?¾H$>³½¾=À=mw=¡ý¾⟾ªN¾²)C¾ÊÈ�½�Ëø=f-4¼‹[}>Nñ¾.¡=¥^½õºN>F^U<À¨ =âyÞ·l[>ÊUÜ<‡Y÷¹IƒT=»|½PÈ)¼�l=�ŠŠ>Ñ& ¾W»½�ª�¼µí?Q¯=ˆKs>dß�=´gš;}’†>~´�½ýÀN¾X„=˜1[=Ý)½]Lo¾k=Ôfž¾.zF>Zìâ½Çñ >FB•>ôãÀ» Í>§|(>$ª„¾Ñ᪼ Ñ)¾W{¾Aì@>8Œ¾=‡ñý®t3½2Ða=½<·½AÂ>DÅ)>€Ô¾>ÏæN>?†¾/ñ =ï-D¼¢½ìír½Ù°ò>•û½Ṅ¾v¹’>4s¾oM&>N|==7µ>xl!>,Å[½Èc>>Á ¾7 >úÜç½ÉÆÉ;Žzx¾3%$>u^>n%…½ ¾9=v�™>ãF¦½�^>Þ …¾r¬O>C÷ï½ßìϼñS=Òt,>;¥>´›¾V\¾Ñh´=íc> ¥};Ào?½eŒ‘¾âA>;žm=¯Ú‰=šÊÛ½°á�>o27=Ás?=Ëà>@hM;¢�c¾×ŽJ¾ì5½�Â=_“ؽÆ^½½BÔ>Vィ”¾³¦ ¾·Kо'Áí>4tȽ�Á=þ>{W>†ç>==c>$É­=×Õ¾$º†¾øœÙ¾F¡=¦ŒÛ½¦çÏ>ÐùY½Xƽ»î—=®ì7¾~¹c>K»!=(œ…;&²·>xp?DßÙ=å§½]”]=<[<}õv<Ìi=M‡‹=°W?�ê~¾o>ÝVŒ=È 4¿ î'¾ƒÄ0>n*¾*D ¾O~3<×i9>Fo#>…>H>«¶á½BÓ>7¸Ž¾"?JU™¾XÛ=,¾d\b¾ƒ—r>�C�>‡3@=Œà­¾]O�¾¯Ê!=nìN¾�š½5Èø=¾Ì™>\ƒu¾�bZ½z„9>ôK=*¯ =T°½x/>ò|¾Ï e>®¦¸=Rû�>GD½P̾Ðåƒ=–|˜»&(Á=a½­‘’<ž¾bjƾè~C>€©=ޝºÈM¿wžê½ë¸È¼î¾ä»‰£F× >@“¾NŠÂ½f绾-×¾D<4î0> f¾ Íå<*ß½„ÄÆ>JU�> i½=z?>€]±¾Ð ¬=¬·¾¤ÓR¾˜§>�aH¾Ý¿Ò=,3n¾-`Ó¾Y‰ ¾a8¾Åõr>ÿO?>5M’½«ò½¼ö+¾àœ½ˆÚ¿ºŽ‘> +=‰”ê½ >°¾aká½ú0@< >t—Ǿ�нrÄ5=@¤d>‰ö6¾ÄU>kP>< €>Äß&½MÕr>~†Ž½h&?<–¾Z½•¿º=K¯>äkL>,Ÿ¹½Ó&S=”¦ö;c\|½CÚ¾�ï=Ψl<œBe½ÂO»U¥>Ú}¦=°Ì¾$5>ÀݽB–m=$½ší¾Áµ->X�¾…�7¾ˆa/¾ü¢F>ÍĽÚæ=c3¼>öþÿ=nï‰>ÏOJ=þÓ”¾àŽ‘>$üg>sx>lóv¾²r˜=P»›=k5S½(ÂB<¨7$<B¾Ü“f>>ξݔ½æÃ‰>oÓX>¼ þ¼!x¤¾ª!Ú=…Š®»šî½ÅÃ&½ör½>«½F.,¾¼–>/µ›½†¾Å3>ÿF¾ºjd>ÑŠ7:ð‘¾&—Ѿۀ{=©U¾£Rº>È>AU>Û÷ž<çar>ÁQK¾>o‹¾Gj¹=;M[¾SEg>ÁM@¾‘WQ¾Ú§Ó>U$&=´IL>8ÿ½Ht¾�÷á>Ú‡�>Ä>8½ !>O �¾Þ’&>ƒí!¾!�‡>¡u·¾zÊ >ÿ&'>˯½P˜>Yt >¾Ù’=T<�¾É²#½oHê¾ÖÇ ¾ÿw¾7Z>ˆH¾# t¾90¾Š@=;S>Z°ÿ¼ÌˆJ½õ>L>$+�¼¼º;½¢>`ÌZ<5äo¾�B{¾ç¾d¾œ¼\¾÷O"½’áͽp‹•>¢âѾAÓ½=íM<½û[4¼…—½[.>Ü­�¾§ÍŒ>޳æ>iBg=ÿpò½û¥†>Y1ì»M´~=:¨”>™X+½„x�>Û.è½4,¾ž³Ü>€¬¾(a(¾sLC¾º">/¾€UD¾eN>¹~<}ä•>é->äí°>—:'=Ó÷>UP‹¾ËAg¾XS¾�QA¾Œº¼úJI>ª“ü¼Ïlí¾`å�¼8íȽì×Þ½¨/’;7ûR>vh¬<ˆ¦Ò½UŠ?½Mq <Âá½K>²GÔ=¼�‚=éË>K8¾”ɶ¾ Lª>¹¿në�½Ñ^ ¾‡¼ u ¾‹~f¾êu‚>qð?½\†L¼MÌž¾|íœ>ºÇ¿•…¾_Ñ‚¾Ø ×=Ý3¾"‰à=T׋¾s‰l=ø1�=HR©»Vû•¾aÏA½ ¨¸=”¾Y¾Ô“µ½úªD>kÀ=c@4>U „>ª¼;>ÅÌ.¾àÌ�=4¼�Þ˜>Æ ¼`—7¾çjö=®…=€TϾ5³=ârW»z[²>MƒÙ>gE>‹åÚ<Ëûi¼A—·ç] ¿Å W>?ƒ=rèÍ=Zñ½“Iš=­ç7½7Õ/#'>’ >ÚY»Î‹>ÎÎ >?྆PX>šç>˜Rµ½ƒkÞ;Úѽ݋$=/F>¯l=Å·>Zûn>S“c½Šq¾"‡°=;¬Ø<|}È=÷u\>Œƒp=´I¬=lBr¾É¹ã=lA¾Ú �=‰o½'Ϩ¾zv>£šõ½8š<Þ(½V/¿>—¾1f=>Œ¬?>à:=õV±>{|¾Žë=p#¡>,l{>í§ò»–Qw½Õ”q>¯5B¾¥åh½$¡%>‰YǾ«R$½’'¾%�ô¾ˆØ�>ð¢>›=üp†½«…@>`Óv¼‡�f=°Ž.¾{*÷>UÉ =a L¾w_Û=s]è=÷ví¾ÀòÍ=é; ¾w–>ò8Â=çf­=ÚP¾%QὊ®V=ÊÍü½€µÅ>T1á=¬á½PŒ>¥Üæ>y \>¨dl½RDí½ÈÚ—¾IF>î•h>ßÍš¾ê]°>Ù�>5ÂU¼uUͽ©,¾®õ°½oë¾/=7Í:>´ž=žp¾Р¾+Ö½‰€P>™�yµZ—>¶·[>ëÛ@»8L•=9¥I»2¾H  =Ç:ýPUu>;ìõ½z¾Æ€¾x(î¼GÂ�>¾[€¾5„>rŠ˜º[‚½U¾U‘>´ÏN¾dfØ=x…¾ñË(<!¾Âÿ⼉eŸ¾²Õœ=y>=™¾uÚ=¦-r>3 $¾×ÝP¾ ¤°=Üá¼¶¾·¾ã#¾êù¼–ZU=̲™>·Æ=½e =ì¾Z� >xè=§Ÿã½G"í»c¡Ð=�D¾#v>™“m>¶®I½Ö`:>Ø¢½7ó=0ÿ‡>õ^¾ª0->Ýkj>®ÞÇ=J-«=b Î=˜ >æ£>Ú¹¾l>bºÂ>I²æ>^¹ß½íí�¾~K˜=á­=@�‚½c7a¾²Û:>áXî>Ü›†½ä®œ=KZ>�W3Ô…=�Œ«>"Üe>=ˆ =⣲=^¶-¾Éª¼Xù=ŒøÎ=«rb>wQÐ=ú‘>¢·¾½J`¾l¥¾k›x¾.a-=Q=>2`W½úQÚ½‘ñÓ¾þoŽ:©–—¾ ž>ç/Ë>ý®¾ ¥.=QÊ¿½¾>£® >!y›¾çÀU¼ØO<©óÌ=Çü0¾“1=óYt>…§K¾¯\½½1„Ý>2x>5u—<©2«¾š¿D½©Tâº2úJ½pª•=Ñ©„½_îå> ¨=U`n¾éá齃v’;"5O>‘ å> ½ý·¼ðd�¾]]¹¾ýÕ½tÈŠ>Lë˜=+º»½0Eš¾Ï5>ùP#=6üµ½BÛÖ=– *½oÊ)<2eç=æǽÔóŽ>�0J=9ÿë¾PC/½ï/§¼èt¾x`>Ã|';Lj°¾F¥ˆ¾b€f½&•´>1{¥=¾èG>Ñð,½o&*>âŠ>âNu¾ ù¾ )¢¼ù}¹:÷“�½^ÀÚ>T>Z'¾U>Œ>r­=Œ9C>·�u< Ǿ¤SÒ½ã7¼¸ÿý;`[¾Ø¡~½ycž]X0¾èK>½3�=03Ì>žã¾Yñ¤¾¶½’�Ÿ¾¾fÙ>½³¬>Ã¿Ž½-þB<&•½U,z¾  ¾?(Ë>žu=óUf>jù]¾¢‘=ÊUS¾äµe¾æê ½ô $>Ð*>Èa >v„h=ÿ*J¾�Of=“¦»<±Š.¾l7?¾-<¨=Ï.�¾i½\W§>Ȭ>cÌd>[.>VQ¬½ö–ºÄ ¾;!†¾…É)>E;¾$f=ó[½¬cµ=:©‘…ùv>Ãؾáó½]ƒ>#õz½7›RÁËæ½;ð?‚œ™=Ï<“>²¨¼õ_X¾1£Œ¾Fç<9àr¾6ìá¼ÿcó=:Ø{¾8 k=ß(™=-Šº,k5>ÚZâ=`'?€=> (“>k" ¾-É-¾¨¥Q>È>¡ô >¾#2>Ön?Ƥ–>=稾rÂɽVy>�K>GV=§Å/>,ð/½¶…¼9êW ½4x…¾Þ£½UÝ4>lo¾Zz¾sŠ”½bR¼U¤Í»Q/>’ó—>ÖÕݾ¯Ü]¾µâž½&Û> À÷=âÄH> >Ø® ¾uÌ>SëÄ=jÔ->ÿÀ¨<�¸ ¾±d–>bÌ“< y¼>ðÐ-=¤Ž½�Eº¼ßg¾½ÐÏ>6ž8>7ð¼Í6k¾´ê=7±B½M—p>0ü´>6p‡½®¹³=\Ò¡¾ œô<x‹>ca¨½ˆ¼¾HБ½ýÅ!>÷<ž¼¼¤¾Ê«^>÷Žä=b�½V{†½§^>u|D¾¯V>EÂF>ˆ´l¾üh]èPy>Ër=�mܼJ‹b>ÚlÔTnê>S‘¿›÷ <ŸáÅ»‚¥k½ D<>ëK¼£:‚=òÀ¾ƒP<½¢ýÈp�¾ Ï0=Æ&É>}m—=Ìã =)޼ñ,½ð*¾Åp×=f8�¾â¹i>Œ²Þ=PÒ¼A“ø<@˜ó¼È·<ÆíľêCn=Ä7sÎR¾~=Õ.æ=s£m½â¾=ÙS¤½�â±=†�ª½ç£>l%>ãž>Ö¢‘½†BÕ=š6[>ýÈÅ=1yF>ú<ÐÅü=F~¼i0`=ê¾5ð´=…¾ÐžqξºrM¾ò/u¾±‹¦>ÆÄ¸=Î ‰¾ûf ½ùý¾¼_>ÄjŒ<Ðû¼>Îû½­º®>LRa=€åà§á+>Ñ»Z¼ ¯:¾âú½€E�½Ž³ß=úÅܽõ° =óJ6=a/¾¿’Ó¾Ó[‡>ÝÇ8¾$ÖŸ=Ø7>Aœ&¾ P:>«N¾ñô²=,DÅ>»r;¸I—=HÏC>µ>=¾O–>�®½È߇=Î,¾°¾Š¾t`¼ô%¾i(ˆ¾­ÔP¾­€â½÷ÞÇ=ÅŒÊ=#ܤ½58¼˜Y,>x²B>üÑ=Ú\>E�ὓ n>‘¯¾Ìò¾Æ¾§!ֽÜ>ˆÔC¾{qÄ>G‘a¾ú4�¾ T²=ê¬>-½õ½>¾ç=vµ�¾/;ݽ•O >þ¶>¿~޼·bÓ½²ä=~¿Ë=7MY>¾=¼ 9>÷$•>w«X¾ƒ©¾aÆy¾Ú?å½M4ª½‚‚e¾òû$¾Q]ö=^1C¾ FÆ=ì×É>æì¬=æço>B£¾óm»LF¾Û6‘>œ4$¼NÚN¾òC>¾s®½(£Í=ɹ½©ó\>+¶;²q ¾¾X«¾Íо)ʱ½Ó)¾ƒ‘\½™T¾¹¥¼¾ÈÌ>Ù¾Ù"¾*óŒ=¶J>a?Œ¾Q¾ÓGW>ƒƒ½#K;xô>{)+¾U¯J¾ˆÉ‰¼Ú§î½úX=©òù½”N‰½vØ‘½t�>à%¿Qw¾Í>™½‹?>Â7û={ë^¾å§±½ògC¼æÒ‡½Ûb=ÌþØ=W.нµ÷”>Û¼a(>dî(<ߌ‰áÿ ;`@:>¯¬¾AÓì½1&ž½R·ê¼žC›½£À8>VûI>1?>;}T¾H!ÿ½®ÿǽ9h>¾ÃËŒ>×>ŠÌ໢d;¾ž¥d>jÅ¢¾Ã;Ž>=c¾µ!†½¬°™>M[ÉÆ«>øm@¾]l½s=5vè>ë¨;¾^¼=7@W= Óû>zµ‹>¼Á>»O”«;< >¥lW¾,�N¾v1˽õ±î=l;>_û>æ €>5Ã�½¤C×½ÚIJ½úëì½^\ú<èÍ–>Ë{;½¦Á7½Jë̾Šý/¾ì»½=í]µ¼ñÃ=q— >á ¾<¨#Ë=)xŸ¾«‡ ¿â¯œ={ˆ¾¢-Ï=rUÖ½ôk›½œPȽøÍÛ¾ï,A>�Ää½f•¾™–d=üf¤>“°½—D�¼X`>9O>'Ïž>¨·Ÿ=E|½Î8´=Äûð=¶"ú=³.½5°è=[sÞ<ÝÖ…¾1{u¾ÀÑí½dÓﺸuº¾•ö.>–�=þÒ‹¼é%&¾| ï<‘ïW>V ì=U�À>p‚ ¾ÆŸÄ=Û£ž>×¼>;;<ÿ�Ó=E²¾aã=Û�=g%Á¼n&ñ¼c~ƒ<23Q>ËŸŸ=Rz�>fÿ¹=«8—='T¼?ðƒ>±Ï&¾‚�«;�R¾¿•¼¨¾-¾ñ"K¾·Çè=U > se¾"¸£=€½›‘½)âx>l K>(H�¾Nm>´(»>>M>èÂD>ç™»Õ>ß”¾£ë¦=D±�>€G¾yЍ½UB¾/èK½Œ> F¯½è…n¾}í«½ÈÔ9=B#½¼zN¾R_…>¬i¢¼É™[>ÊmÜ=܃¾jf>j„Í< Xô>­°§¾Åv>?f¾Ìâœ=$Ž–¾hTվʊ¾¥@û½&Ÿ/>?¯‹¾º›/½=_¾÷]¾^í;>¦’ͽ¿Âi½®,`>cØ)>7=ÄĽ Äö½ö 4>PQ>Z'p¾š+ =VÛu½2öu»~ç½=§¤W=Ss»=áÎo¾™u¾<ܾs,¦>àá]¼ë"¾¹ý‰>Ú{>p*>‡€¼ Œ=ÿ>Öa´xˆû½�&i=�J…¾l9= êâ=ø”¹½Ï(2=Éå¾HÆJ¾4æ¾ô >Îþ'¿�6=eÇ.¾§š¾=ù =›ø8>¢cn=E–y¾?¼6ø�½ù\¾!ä’=+é=liF=*€¹>¬ç¨>84ñ½Ñâ=ß÷\=e-ê;@£®=¦ÚO>†>¬u>ëAÓ>¶ú ¾�ðz½#}¾L¥Ê¼aü˜¾Ñçœ=z ;>¯T~¾ÓŽÅù²=‰Jr=\,»õÔ³= Á#>ñW�=ñ”¾Î-¾¾Â)½%x¢<@t,¼W;s<'f¾¦iL½ÞnÙ½�5ž¾%_¾¾�§=)Òt>*íú=ØÆ9¾`A„;š<¾Hõù½ñN¡¾Ü b½´˜£=8ÿ¯½ ¸Î=ÆÙÊ=iÕB>µx(¾”6¾ªF(> ¾åÙŠ<Ñ)¾É蕽Så­½ÿ«m>±¾5¾ š&>ICŽ>Ï>¾(u#>)ö=>9ÖÖ=ì¶}½ɲ=€¹½/Y8½Œ“U½óè» †<äÔ>ûâ:=bJ¨=ðw>=DÂ=hé=þàš>Dm¾§ee¾^Èú=Ï¥=Îv½±˜U¾iâK¾¢ï�¾zÝå=z+V¾®^€<´·°½n)¾‚nn>ÿͽ&ì-½_»$>ôtɽèŒÓ¼r Æ=”:>§9 <ñ‘>Ìz ½Þ²Ò>à¿Â<uÐ=l£W>¥®#>ŒÙ‰>ŽQ@¾èqz>Ä–~>ß0B¾³¬‹¾: 5>o‹¼c9½NÀ>}Ìɽ¯O\=&S<¾«Uy¾²~Q½’ÿ£¾î‰—<5IV¼J”½hGç¾�÷ ½oÙ‚>{$¾�p >�L?©—¾42×¼..“½ï`>ˆÀL½�á¿è >>ëÝÕ=y5ß=2YJ¾0V·½ŒŽÜ< ½¾Öãt¼:ùŒ¾ôL¾3ˆ!=YË‚¾?T[½Ñ>Š<¾Xn¾ì™M¾‚üw=“4Ì<i¸¼O½ Âª<ª®'¼LÀ½3g ?´g8=勾øÀ¾IÕP=ƒ¼³±=Eòðh>XÓ<=Öá#>†Y™¾·ü ={’>ÚâZ¾•ÌA>/‹=Q_í="]Ó½�©ˆ>*Ù¯8œÞ>…½½Ó$¦½‘æý½J Æ>c>ß=µ»¨¾T²½�b“=d ¾©á–>“)½ôA™½�šã=snÑ:ÎØx>­ê–½,& ¾Š=ê=-ϽüÑ ¿²ÁÛ½.<=T¾á¨>sP¾Œ4‚;¹,#¾¡¸>>Œ‰>µcÅ<¶l{>ƒ~>ÂÇJ>Ð|t=03‰<–Kœ>îéf¼ýt>¯Áv½€J¢>A¶=Ï¥t¾ $Œ¾…¾F•>Ÿœ;½s½]>ö>¾Ø"¾6%œ½ÑpM½�½1e¾àÃ>ò'½Á¦‘½]>+vï=ªŒX>Ú‰>ÀF¾ªY”¾1wf¾H±>X¹ÅÛ�>À¯½gÈ >ýl¯=Ó;ƒ¾JÉX¾ ¬>s¢‹=;€>71<–xW>ôd¾ic;ð ü¼ã‡¼~#{>�=CŽó½gë¼Y¤ >#=>`Äâ>0“F>0¾„˜õ½Îl…=7MB¾€›d½‘ò­½CÇ‘>+Ò+½»ÜS½)èÁ=Ó~:¾DÌ=%‘?¾çžhÉÿ>ð’(¾‘=謢½&€i¾YU=5ƒ=ÝS'½8üi>á‹›>Á™¡¾�Ó�=ذô½–sH<èP¾DÑ<³"¶;å†;½Üñe½â·õ½SRp¾y;¡We>}xÍ<#ÑZ=F¤Á=�¾=k=Ú=ž&>®ÐC¾Cï\< Z�¾Ü³R¾jn`<•­>L\÷½¼²9¾4Ž«½³e*>%Œ~=´€½ôª=ßo‚¾| >¼r>á6�¾úù‡½­¾#iľ»Ì佺<÷¼ (9=|Fó¼(Qy>êo=>e.¹=.¿c>›¤Û=,>º>(èB¾q˜­>ýý½.£t=hž=ÁŠm>Udp¾Š¸ > >¼¼`æÀ½{)ä½bµ½¸þ¾5z+>õâ ½3Ù'½*cí½%Þ@<ÀM`½ÕÎ*¾ÔX=¹_¾s%>L!u½S*+>ž›f¾Á>t¡=±­¹= p‚>%nˆ=†þ¾ó¬{½ Èe>s^®=�Gz>Šlà=M¯€=Ó·¹¾ÓÀ2>…ÊT¾I®½×k…=ÒØÔ¾¥9º>æÚ¡¾SÕ!½¸‡0=ソ(\t=t¤=Ѝš=2Ux=�4>€­p=C×y=ݺ®½á.a>a±Ž½°ð ¾¿» ¼>5Z¾,½Dï>‡=…Úv¾�MO=Oú<ÔÕ‡>f‡¾]þ?>i­=‘°B½4ø¼Î½¸u¾=�Üâ½Ý}Î>{·»¾¯M¾†ß˾ï;M¢´½÷ÌA½0¬ú½×óU½ê,¨>±Œs‡§^>¶—-½å:w¾/©½ag=9¸©>ß ¡=0d‹¼Ï,ô=$%=4y>vL¾’ à=Ûd�½ô‡¾p�o¾´Ä>À±¹¾Ã?.>ònÊ=Ñé[¾7Ú¾|µ|> ßœ=~ã¤<Úúf>w±Ð½â-Ñ>… >²"Í=3¯,>:é¾*�´>£ÿ±<Òù¤¾ø_=$…�=Œ‰Í¸E=ïˆ={¾Á+©=Ól=} =G*[¾~a->xÂç=“¨�¾¿1¾#á>ËD¾Ã�>®·�>󼿾%Mâ=æL=Þ(>Ý r=&`½y >µ� ¾Üd4>Uµš¾¡¿«¾ V>u4@¾4˜>˜‘½ª¿d¾>Êœ¼�-¾u/?§;;=i+> ¾ƒ%´=à >4È >°óU>§ÃÚ=’ªJ=ÕÏàØü(=K6¾â ’¾,$^¾l›�>µì�½ò p¾Fk¾ˆ ;À“ŽT³°<ÎÄf¾Û>£÷i>Ž‹ü='±Æ¾Ô¨Ë½Ü\ ?€KA>gZ»=¼ôºÉ�j>"£Õ>úÛ8½c¤½ºóÊ=~t=n‚f>íܾèÑ�>{¡û=æû;Ô§=…1¾'Ê=½&%>´€+½¡G/¼HÊ£½ƒvÓ¼eßX¼rÅÚ=”ša(>¾^R=Tõɾ–¾bá;ò·´=9EŒ½-¥ª¾Ï“�½gê·>Ïbö¾µg‡¾Z?>ì� ½b>>uʾ0Љ¾0À[¾v:(¾âµa>Ìç\¾  ¾=½ ɼÐ.¯¼¡�ží}>’‚={¾ÆG�¾ õ.¾Dº½g9Í=9LK>Õ΄¾ÛÛ½ü“ô>侕U>x’>Ô_ ¾™Û=@½„>ð,b¾T¬�=éð >~ê«=ïFI>-K¾ì4¾~ s½0sl6B¬=Êw-¾×„W½¨yÅ=ÒK=Æïá<�Ó½†—{¾ñ¿½°®…>0î;B®¼H´e¾!=¹»G>¤^y¾i µ½„�м89]¾eI꽶Ʀ>z©ÑÖU>ó3½ø˜¾I–½¾¶g½~X>]´ø=rÑF=¸±>pËë½7(™<¸$¯>G¾.»aIh»Ýĸ¾E!0<Hª>О¾ä¤�¾Ce¼êN>‰-½©Åÿ¼™"G=VKP¾—U=¬–¾—Ï>£Ù>ëÐ×=¥]S>eÂJ½Ô1Þ¾R=�@u= þ¼I]ü¼{t>Q¥>ä'¸¾=¾Ý}T¾Z¿û½‚EÜ>[ç–=™®s¾R†>óO‹>Nò¾`è>uÝ&¾o9è=,+=—�¾´Þ;¾Vž¾ F‹>Ù0?>j:˜½roǾñk?¾GÞU>FÏ>Rn>&¾NóÑ=¨9D½Ž3¿Ék¾ç'’>н ƒ>”ÙC=Ãó5>ñ0a>G|!>20�½çz=Xª¹½üƒ‹¾´› ½ùÜ*¾\Z×½O¯¾÷¯í=ÞP¶¼Ç*A>p.ͽSì¾™¬½ëÊ =÷ôc>7)¾žCˆ=›öJ¾­:>A@ë=Ѿ†$¯¾ngÓ¾5j=Ú�¥=hkƒ½š%ϾÙáŠ>Òó–½AÓš>´‹¾fµ}=>[y>ô6½@Öd½¥þ§¼Nž¨=0Wá=’_>N;>x wlÎ=Û¸7¾f€¼=�j¿»²aܽ? >j‡y>‚¡´¾B7¾²9”¾¼Ò ¿3€b¾fc¾Õß8>¨ª¾•a¥¾„w·=ŠË˜¾`y•>Ûÿ™¾¿®t¾áu0>·¢…»§úL>ÛŸ>&ÓÍ=XÙ·¾³"¤¼fbR½xQ\>Pg›½Ä–>¥�›>+�V>…S"¾©{=.¦¾(/d>Š€g¾ur>å¾h|>t@¼á‡¾¥Ù ½µB¥½þ— ½v<|>1z!=R¥=þ=¾Ž¼½6½¿½cX½;Æ?y ¼£"´>`l,¾8e >»re>‰½“ >=äqb¾Vͼ³•=jì1½¨Þ+¼.B ¾rÃ1¾†KB>/‰Ì½w#ƒ¾¼}v¼�S¿„„U=P•!¾¢>X¾=±‰î>Y×-¾˜Pï=|¿¾‰#Ö=˜hŠ> k¾X®›=n4‡½¼¯²½ÈTå¾^eŠ>cx†½®71¾vÕ¡<Ä�½¢Š¾¶gŽ>2�=¤=|ÛL>Ûz >©RÚ==G£½ûó˽ÏJ =j$¾:¾ù¦¾$g‚¾Wª»ß€o¾w¼�>†¨Ö<‘}Ÿ>�ªü½døk¾Wn:¾xÑb½-.¾¤p¾=v´½L²+¾^l)¾‰Ã>¾P½Ô¤>2Y›>F|“>£a‰¾@¤ä=»²1½‡×Ÿ½ÁÁ½úž|¾§3ý�¤»½æýz>9•«;Úë·>06=CƽByß¾*l¥>_ >­Û½æãt¾(¢e¾{5E=U é½ïTc¾æþê½�½’�À=]ñ>Û>|°> –‡¾V÷ >M;¹<~kí¾cÒ]¾ŽåÇ>œr.>Dˆ®=‹I�>‚od>ÄÕ²¾§±Û½ Ýì¾Ûâ¾¥ð>Mª¾ÁX¶¾Gòè¼Î¦ ¾vJ ¾Z8â>ñ2j¾€Gã=-1Y>N$Í=ûJ>¿n ½U'>¿rz=W¼á½^�¾”¥–¾oÛ=Æ97»¿r>FÐŒ¾™ðe>¬~¸¼-°§=MÚm¼t¹_>L_Ⱦäz¾H#´<Ü Y=›ßš>Öp£>BÓ=ŽÒã½wv¼%õ�¾1lÂ=GÏ,¾=Ð>�€$>qô>1Ǭ¾é§>bx›½½™*=`K¾V¨�=jž¾ºÜ½Óg—>8¡5½(~�=Âl½v`É<µ>™<í=t¿À¾@ j¾gf¾IT=övf=0žé¾ ý›½T0½j3 >´Ì=}ïZ>ßðŒ½ûvT¾$‰>¯‡>‚±j>ŸÜð=‹ѽ;uc><Å"==¨¼=…q=¬÷1>×."¾9Ä<Ô�U¾a?>;ޏ=Å‘>"&£>ì¤*=±v ¾nÊ ½¥“R>^±u<‡1î» qŒ>“S®½æ^µ¾ªL¾"b"VšÁ½7ÇŸ¾Ë~¾ÐF=j·Ð>èõ¥¾Á7>ǃ'>vO¾8$o¾ïzý=zŠ>'4¾_‡¿½msí½÷ç¥=”§“=Çä"¾a£¿@ÏA>Xê§> oH¾Gs‘¹™Œž<Ëó>rò>X¦#=ʦ‚=ZPÖ½ÕGQ¾÷¸Ü½zU¾øÅI½&U3>æú©»”+¾Vs<�”˜»õH}¾“q#>P3…>bðU½rl[¼î—.¾°S>‹ż&mx¾êsÇ,EÔ;ÈÙ½› =å}½KÝü=ã”;>K̽nk5»œ¦½»ßL¿,|ö½Ç%½bw=êɆ¾BßÖ>,Ž ¾³Â?ž½ašÎ=ž„>J”’½¦&>k*…½“I¿;Üðô¾µ0¨>Ssо¦&'¾ âPºI)=>hN=¾žh“½°O=ʺ=H%=‰â >ëš= Q{>Dl‹¾‘?̾Œ=¾JHÜ=i—¾±àݽ�º¤¾Ì·¬;Í<™>æîN=k>‚¹D¾WFNÉ;¬<·gÔ»„cͽí;>î„'>dƇ¼8¾Cç¼ÒÎ)½›ê=Nª‚¾vêK>£$N½§êàkŸ‘¾ÏÆÑ®V=�!¾'^A>ÉÛʽ4C >¯ly¾àƾç³¾>µ>|̾…;¾¿U•<´¦ù½N`N¾f¬=–$=¿·î=. š>è8£½e¾ÂRˆ=.‚�= 6ˆ>/,�¾’¼x>«ÕŒ¾duî>VÉμç—%>!ˆ‘¾E†>Gç<òÍ3>Ú¿‹œ9¾Œƒ¾VÚš¾=’¾Ñò²>›‹½Æ?f>Eœ?RyÈ<¶„>;û>�Q>EH±>l˽nK½ív¾,ü½¾óýq>@ÊA¾éë=¬å–=L¾¢Á=ú‡È=Þ)&>îf„=Ƀ?¾öûU=–ÈÔ>²ß”¾ˆv> ð‚>mSX½Èò¾ñãf½©§ã¾ ¾FžX< �=¢e;:h(®¾34>Â_‡½Ÿ>[žpF>ùø½\B¾ƒ t¾@1>ý²½‰ˆ3½¦Çš=î,>y Û>’/?äcƒ>a <Ö>¾††>æÍ©=‚6K>³Àý½\½Å‰>§Á=N×¾·|–¾â:»½VÏ)¾¨óÌ»�ŽØ½0=‹=Pù‘<¬9¾:c>ßéa¾jJf=ܿƾûÇh½þȾ½SŠ>¾¥¥†¾ÜV2>Ði>õÔý½�&_¾é:¾L’4¾™1Ú>½rŒ>LÔÿ¼¢c¡>À�¢<´->¿Êa>¼’M¾5í¡=îh=©‘J>oz>$äT>e5ö¼èvú½]ÿò½ŽO˼շ‡>Vª¿UPѽ崇½I�Ú½~£C>ËF`¾^¸5½PÅ=v?`>ðª>Ê�¾Žï¾\ ¾ÄɾH–B½¸‚¼¾þ8�¾'U½ƒV¿)\ƒ>tL¼¼^¾—½·Ü1¾h×ɽ"¹i½_¼D¾ ‘l>›¾z½º½¦ŠB½T‡C¾‡nm>`ìξrÐ>»@¾ž6ç=žuν-à~¾»$G¾RÄ=¾ž÷=ŠÊ€¾R?Y¾Œ+>ø\�¾ìr>cŸþ>ä(¿Ò¼š>�+²¼Ï“£½·8>ÔÙÒ=>U=fê;J](¿�Ô¾¦d>=¤-½µâ>¨U>o+½ñ8q>™ˆ>óH?>"g=ç†.¾ã÷�=i¶=‰qÒ½Õy+¾RÀ=;-0¾<¢=x´†>™ª^¾±÷¸>¹]ˆ¾ø—š¾<šS»¾bW潬=¯Òp¾Ú•]>Š>òÙ!>ôº½ û=Wœ$¾ q¤½xÓS>¼è$¾³P>>·‚=hª‰×Æ» ’½}e¿<<&d¾) !>ÉRÙ¼ Ãþù!>¬ùG>耾`á°="õ’¾Ò)›½‡ ú=AèÞ=QÄ{½‹¥¼¢c(>gpF>èÕ˜=i”=€g8¾–_×¾ ¦£=M½UwÓ¾äaš¼9á¢=ãgî=® ß¾¬õ¾qJ¾Ñ2¾3 í>HØg>Yh�=!y<X=­±Ù;ß¡U>lhÕ=ïÌù=QYø¼Š¾¸¢=¢e¤¾éªá=apb>\j¾]‰1>Iú>¬—b½šŽ.¾8–w½[å ½f÷C½Ë>¾áW=@оVÚ(=„A“¾›„>ø„Ó¾Ö”> –Y>»¾£½iW¹=÷Ô¼ñŒ =á‡*½òd“>’åØ>Jóa¾K®0»ùé«=ªòŒ>­37¾!æ7=¿{õê:½øÔ>ÜL >ÂvD>Ù™'>º5)=M”ß=3 ž>“=\ú¾:œÏ½„ã¢>Ù­¾6¼iþé“(>>ÔT>×€O>€&&>DO >ó[^=»ôŠ> .=Í謁G¾$>µùA¾Nï¸=H—€>É=Y ¼+5X½.¾ù‡À½CÎÆ>œ>½Šg¡½ºk„¾§B<˜û.½2à< †> L=>W_ª>—+½u�˜½.‹>„D>Áø}>¤Í¾Üs½ÊÎb=JQ=>[4¼}´?½ªå<‘B¾rÍ=7—¾Øw�<{;\=‰€¾½°Hm¾.̽U0½¨E­½³9Ö=fÔãqª>í0ç<ªe³½IÌ1¾ûY{½�vÂ=¨µ>>içK<ŒF>÷Ý\>àáÉ=A¾Æ<¥è̾  ½Ö&’>…\>-T>r)U¾Z 1=ô ‰=ÿE.>â¨R½š¼=��¾Ìºð=— =�àÅ=ì)š>‰¼u> g¾%XV>椬½Ñ· ¾}ë1¾pû=•ëʽµï‡¼£•¾ê">gû»>Y{’½+^·¼uD6¾"ê¾Ñ:û¼cÛ�¾h-í=–Št½žwº=ø3¼³þK=A²-¾þ …½g“o½²k>ð‡¾£Ò8>mK ¾‹¶c=võ#=HK%¾�Ø{= ½½kVÃ>B+̽!2¯½Ïb‰=;+v½:.¾äìŽ=�K;¿O®½ø•‰¾pKø¾q ~>ðc“¾aE�>�G@½¾ä�½Ÿìú¼Co;Á–bº�ÿ>€óš¾qæf½;>kZA½ý)_½èE¾´f¾¥¢¾®¨d¾^3½Ûð½gÈ´¾²�g¾SÇb>²ÕÇ=”Ðù>³)’½ð]ç¾µ¼<‹®>?<>ÔŒ¾Þs">²Kö8u ¾›Zš;Ï�]»øm$>jÑõ<ü¾=��^¾¤'ö½ÒGÍ<¯Ͻmz1¾ c”½ ¸>ȳå=õOr¼ï£>ºÂ‹>Cƒ6>4C¾2«—¾y‘§¾÷X==þu½F@½68=àK¢;YÁâ;å[¾ߪ=‰ö}¾!×@¾äIǽÎÜüui¸=œ�¾Õüº¾çÑ&¾I°1>}{¾{ˆ¾§“‘½P?Ž}�> è4>+9f¾ëPj>¢n¨êW‘=GËð=½Cw½Ù�c;/%e¾ñƒ¿Œþr>ƒ�P½?¢<¡%G>�pܼ%(Ê>#�ˆ½1¼›;I¾;Ã_>¼À%=?Ϙ>ìœà<©¥¿¾á>ü >˜3¾jRÄ>Ó±@¾!ü=.šT=̲¾-¢D>Ù>Éâ=TKÙ½��]¾(È>¿>þ<½¾ßã=%®=P’+½q$í;¼Kß¾=©=œÎ#¾®óÅ>“j½„Á=¨¾]4>Æ�¦>êÏÚ>$ó¢>4KÒ=°VÜ=m¶E=ó »=’•ƒ=ÖP{¾~è«>iì,>$ò<}W¾½[:Ý=À¿ž=Â�>›P—½ª@T¾?=§=•´£=ÕÁÚ½HÚt¾Þå\=û(¾‹Ê±=Hr¾ÇB(½ÌŠ”½:F“¼5³¾(ǰ½¥%½ì® ¾Í™>°ˆ¾ f~=C¾b§=[ÓÚ½Léì½% ö½)¼*¾)�޾³W—=Õèå>[ e¾oÀž ¾ÔA÷=Ÿj¶<ú€¾ºW>>“==Æ!c=êÌ྅g¸Vb)¾#:½:ш½'% >àÖ}>ïd», ¾r–`>Iv„¼‚>×Ãt½R€×»rÇ7>c ?=0û'=¡ª£½Ms½™££>¿þ°½qXV¾ž®O=ÍYF> ¹V¾¯É‚ Ú_>®àü>ëý¾D°<ùÈ„='O >à)>5¤æ¼ùù¾=Ø”=ÁÔk¾Ý#^=4S>.iM>Ü0>ñ'”=Ûœ½Á*¾‡/ô=X¾!®¾ ¦ ><9=áª>>åtZ>n(=¼K>>cNQ<°ùÀ¾iò»X–=ŠZR>Ò%X>lÓ…>ã1>ˆ§>uàÒ¼ñÖ=7,F=¼¿Ù¾Ö>uµ’½á!c¾Ÿ‚˜Pïß> Sc>Ö»Î><·W½^X=¤ð?>óiü=¾Ü?¾½A¾º6>¡‚_;Ÿó™½Ð¤A>œ[¾Ê* >•¡ ¾Å3>Ók’=št>š+™¼â7D½÷y>C4¾Ž|¨>‚nï=¡iÅ<Û3¿'>FC—½oÂ>ÃFü<Ÿ=ïžd¾þ‚>gL¾{éսݯ->2ðq=$¨¾¦�`>>ä½ /ª¾|"ž=û'н(k¼8±Ñ»ñZ%¾†™¸=0Ëê¼ÔB§>´wC>²¢½øÀa½øè>>ð)=íÕ=#¿=K$g¾Õæ·¾°ª-½lÚ»»D”Ï=ê1‡½o/U>4~†=PRƒ=LqU=w.i½Æ¤„>As> ‘ì½xÙ >Y{ ¾ù¸=wtѽ$(>±Ì>)¹Q>ÆŒ>Èw”=ŸÍ<4ã+=|2½9YI=,”½/F’¾ò 0¾ûµ¾zªê»Þ,ƒ>cä¹=˜!w¾=wV>­rY<½ò_;™AË>žJ°½Bœ>a©> �—>w >ËÂ3¾s,¼j᯽'êP<|–>þ>m‰¾«9’=‚<1>yè¾³ü2¾:Ä);ÆØŒ½r…=ƒ¶>ðçˆ;øœ›>ZÍýO_½>_>܉<^óg=iHÂ<Ñ‚f¼yP½;V>Pe >¦ ‡>Üï?¶½=°˜ª½€±½+M=O0¾­”½YF¾Ø „¾9êÿ¾Ài7>S•Ó=¤)º¾Œ=2a ¾À=Xa¾ŒñL¾V}Y%ù;v˜—=ñ½Œ=É}¾åId¾ F>2+¾^Dˆ»xZ»½ ªÛ½‹²F>ðEh=Ëp˜=‚]e<.> >��½©P?êa’¾…•½¹VI¾pXýLp!<…=¾R]û½9F‡=´.«¼åJ¸¾Ö¿Œ-(= î;>ÌP{>©M¡=Z¦�><É ¾™—á_ñ=µ¦>¶F£¼™ÿr½ÌŸù= ù£¾]§¾íª½P×½l‰¾ ¾.ø6=‹¢u¾“;(=>Š6Ÿ½MA¾·€Í¾�´æ»7û™¾)–ü¼-Yù½Ø`Ä>íiŽxd‹>Ø/j½'’"> y½=Ê—-½¨Æ>@.„=#„w¾€.z>ÿ¦¾‘ =XRI¾»zü¾8 @=q%³¾Ã+¾ –¾/õ€>*èý;V]¿=Ñ^ý=xD¼~â*½-„¯=ˆY¬=·‡¼¾ìô=£]�7‹‘¼FQ~½ >-¾Ôœ½µÎĽöºŸ=:½¦ T¼êÝ"=¼>¼œƒ;¾ Þ<(?j>ï¨::´Œ½›º»Ë”q½ôói=a^™>n0›¾9?¾õÍ,¾÷5™>Yµj>À»Ì =×1 ¼½Ã=îIª=cÙ¾. ‡½øÊ¸»*Xê=*+)>[Òh>@I>‰šÅ=‰Åj¾e×ݽ˜¼Ž½’¤Ç¾›Îh>œw ½/n“>ý4¾–_¾“u¾M©¾½R€>¡É<¿Õ×¼Z„=öÁ_=Ý«š>š0¾m¦½…»Ó; ѼÍ{£<’«þºí6‚¾õÛÓ>uâ½øþƒ¾³°÷=C5ö=ð޾;.@=;i̼á‘=Íþ>¾¿É¾Âåo>J½ ·B½ÆUʽˆÐ="d”=ˆ’¾�j=ô¦†=Ãh0¾e9¾Î6¾ÕõŸ>|„¥¼ªš=Á4O>êÀ¾¢=Y¾¡i޽‡wó>Â<˽wÑ>п½•� ¾‰0—=™&I>´Þ•Ã�Þ½æ£=== >c�@=⺠¾ö‘u¾ƒ;†=xæ±=é|z½"Ï£¾SÖ½NR_>‹’ˆ>@G>DÓ=P½€¾} R>ƒdp¼+g>Ñ@#>cýÙ;‚„º=WS>>PÇð½GtF=›“²½ø#§½€�>‰°>ígF¾lž}¾õ®½Ù”„=D‹¾¥">–Vn:Âé°>S²Å>‚Õ„½ðÅ$ÎÎÛ>A›L>Ê_þ«Ó¶¼±°•=¢ºH=üV9½2ܹ¼iN¾£Õ„¾°?Å=‰?¤¾ÔΩ=Jk…¾œšÆ½ ³¾Ð¿Q€¢½þ啾wö¿¼¥Ý�=] Û½ÔØ@>Çsý½S†¾”*v¾›ä¾kJ‘½ªÂ{>›j½:b–?yK =¡ ½i¢£¼vW5½˜¯x>':P½Ož€>±å©¾ÙƒÈ>WW½PU>¶â(¾a<>:mç½E;G¾®‚r¶†=œér>÷á-=d¡>š§-¾Z®¸=q=7y>8¾ࣽ‰Ç/¾„…0> �>‹Ó%¾²g¾wˆ+>v¼¾S¢¾Ò«j>Ÿ�>ô)¢½ž³>Â5Ö¾�3></=|ýä=''#<Ý~—½;¾z´î½�^x¾1š#>6Ÿñ=?ê=ŠJ6¾� >„å7½ˆö½]`Û½É|½õâ/½¶‚>ü ¾§Ï¾¥²¾ã V¾Ræø½ÙÜs½‚%?Õm¾Á‚½Ü+ƒ¾•Â<¢⽉Ë+=L‰œ=(”¢½…ë±½Œ6¾ÃXU>$¦¾åù?-C7¾T4¾1ºñ¼Q2ð¼Ò’²=ä‚»>“ý®¾F˜Š¾>=v4¾{dr¾Vþ½¯Ö¾ÄEs¾!e¾‡W�>=Ö½‹ W=ËÑ>õ^Ê< À>>½ >Ìh…¾ Y'¾¹3£=*�¯>’Io½|¦”¾!ÕZ>^æ> ¡Ñ¼Ò½P&P¼ Væ=Ÿ¿“Âu•¾Ö’3>úe½:¼½Mh)>\Hö=<*=I¼=4J?Þ4¾xŠ.= Ï×¼‡5¾~þ+=–®×¾Í{y½ÕÁá>žiS½<«Ÿ>ã;«¾Ø‘á>³.½ƒÑP>–Å“¾¥k¡½žH-¾,ˆN>_= Zš¾°È³½«[£½ã#¾ �¾À­+>ͺ>—̼Hïç>Í›J¾·«=p‡l¾ª´Ü½Œ`#¿à8£>ßȾ4 ú½k{­=8ŽÎ>Eg©½±9´>�ç=¤Ê‚½‰Þw>ǫ̂¾u�X½Øñ„½§–©¾£©¼=÷š¾¢ž>Öà†>ɪ†¼‹?Y%#>ƒ°—0þQ¾6m™¼žD�>uÿN¾c3½Êñž>ÁŠt=7Å?ݾ ²+½D˜W>n="¾ÀÂö¼~¼B¶Þ¼ÕQ•>‹yw¾3fÊ>Œû>ÐŽG¾¯Ñè<Éa¾W[½qM=s==ëã¾î±=?µ¡>µ½š:,>÷Ç8½"f<Ÿ Ð>b¸C>òªÛ>Êé‰;ç >Ðïþ=硨½‚³Ó<ªË½~ºù½]Vk=P€¼ù­¶¾Õ"S¼Žâ&¾‹Ä ¾,§¼¾“¾jÖ<>' ¯¾Fz½°L¾dãÜ=[Ó¾’&Ñ;[ÚK¾ú\¾ñŠl½‡%=ì„°¾kä€=¡.>¶U»½7U'=œ½³_ ½�Þ8>(ªÏ=ܘw>íë=¾W\>‡¶ú=ðV¿¾V¤ã=“Ê’>LbÆ<_m¾µC¹¾kYJ=„;?=ö«k>>Ù¿Ï«=I¾ê*}=d=¾;/F=1Ö=åνŮ>¾gY>Ìu¸>hór=AD¨>]ýŸ»G_½¦=JÆ ¿6)£¾Îžœ½½?¬G¿=ãc½PF<*ú(>{W,¼ssÙ=9]ˆ¾yô]>§o‹> Š¿œ«½2Š-¼Ç«B½@Ð><á‚»Tê¾>WŠ>>½rj¼¹,7<¬Þ?ç+Ÿ=®H–½I ":½Ö²¾‚�½[¤;>�3>O./»roò=xûZ#¾º'>·;S¾Ÿã1¾Q³Ö=èS:=Î++¾¿o¢>h¦>äs ¾{L ¾Î¥µ¼Áã ¾/@‡<(9f¾òš/ºÀÛQ¾J †>@š>Üȼ�,^>.ɬ;¼•¡¾î™>¼f¯¾qõѾ®C‡>G(¾úz޾I õ=í§8=^Ó�>ªR�>‹ ?0¶=pk¾ÉÀ9>P8B¾|lL¾dP3><0 >˜ôE¾h4¾‰Z> ‹>F5>¼@ؽ4m<ÊÖZ>®û>Ç’¡=IÜä½ è¥>¦Ó‹¾Âóò=ÜWr>úp¾ï�>øk¾m—½Áá²<�,½!>{£@¾ "å½$ÝĽÑÒ̽v“>åŽ=s¼=+‡•>'ü>ÕÊ\¾âr�>'ÆK¾º|>´¯=å­+=ì%ƒ¾[aþ<ÿí�½7˜è½·“Í=~/k½8¡Õ=1d¾­ì>~„Æ=2 ͼH ¾Ðñ:¾1y³<7¥¦¼iœ>ÔŠ>PN轨ml¾È8O>ÝB¾s©Q>k•ž½�ﯽö1¾Qùý½?ê>Oh'¾_•C>þG>™Ç½…±Ý½+ø¤=0±~>aÉh>EÈL½@žÖ½Np¾©Pƒ¾;�̽"H=,�>@5m½°Ö¡;y,¾À¼<>³°Û½ƒ¼¬¾àÊ}¾ÙÃi>¡›×¾sš >y±0=J“À¾­¤Á¾¯Ö=vy?Å8>ßp>¾%±½í.¾Hov½0Û+¾å!¾Ð¹ª¼nôT>·,‹=t>oÙ(>$Ľ¢í>éÆ<Ï4$>É}…>¢‚>>kì=ᚯ>4h>>þuK>LÌ>Îma>2{=9âž=øXº¾@G>ùI ½_*R¾Â``¼fÆ!¾eð$>j‹Û6>¢‰¾ƒæG>P=_¾k€=>ŠtO>’1»üÕk½A½¤G>Š >'âA>9­ <«Ap¾ƒÃš>¸EZ¾Óx¾‰`W>Ma•<,xP¾Jð">«�f=:¦K>1Ei>{ֻ릚½4>¾"¼¸¼Äs=ßMA=PÔÆ¼§zâ¼q@ݼjÎË=2¹>V‹½j{=¾«·ª¹£F> À>EБ>mmä½¾çp=ñóp={lÔ½´k>Iä}¾.”»VRè¾#i½ãÞ꼡ã#=[Q> O]O ¾�­ê»Ò”³=¹Ž�½Ø™¼›ªë= 戼9ýd¾Db½ÛFˆ=fU½]ؤ>~ø×¾öoˆ=l>kDx=ôä½Eýµf*¾š³ˆ=³ÿ”< >³¢C=­±�¾*]>wœû¼ßM�¾}_>yÛ«½ÒÿȽ¼¯—=¦o>â婼¦¢=ÛÝ>‘¬=CÞ-½V“>LMŒ>„«O=Sç¾*œŒ;jÀ=)Z:!x½§5š:Qô>;Äc½îC¾ë‚7>¥"ç>_£¾%Þǽ¬Ç>{Ué=1Â>2KAý¾ —½©C >c´ >yæ=×®Û»Êêí<8À�>œ…н‹I¾²~ϼ©½ œ¾àZ>£&×=K†ž½Áß^>úp¾mÀ7¾K&=ºjR¾³ßð;~~½>·¦¾wˆÊ=[Ù�;Ñ ¶½‹m°=oQŽ=#…&>VY½FYl¾·•$>öéJ¾ü™¾ i>Œ_ ¾¥™A¾›ý >z³ã»ûòF¾�K‰>][¼(® >ÞÜÍ=oP›=Ðö�½ZŸì½Û(-¾â²L¾¥Ê;GÓ¼æê–»w�¾·æ#¾Lvº¾T¹>Ê¥`½�ðC>Å'¾6xq¾^e7¾Dþå¾ÿ«•¾p‘t= ÅÚ>xB>†ñ”¾ÛÐ6¾Zp»¦…õ=‚©=bÄêk5à½ðs¼Œ'6>¢ô=A+ >@ĽE1%>¼y›=ŽP¼\ f»3醾%ÜÃ>ŽÐ¼\>Äô€>ç®’½p¤¾pz†=kG‘>Gï>$=ëO=HÇõ½&û=$c>Æóù¼)~Í<ÉÂ>o=½ ¾�wY=ç=m¾Öñ>ÇA¿bR§»Áo<Û^Ñ<îºÂ½pÒZ>Ï÷->.ÝW;8ºÎ>ʽ¨‡½Ö),>6þ># >84¸½v©9¾=nâ=_?ô½Z®ü<[j¾ZÙ×=•Ëé=7C²=8îð¾k?Ö»&�>˜yJ½³z¹=äïá=Q�=³Ñ >Ñ^s½Òøµ½kÕ+¾-=¾˜L>¡Og>é¯=˜i+¾Ë‚¾mŸâ¼Œ¾þöï<†j�>=gŒ=\5>cÈP½Šb>WMâ¼+1¾–@ܽ¿ =ßÏ= ÏÓ¾žd=û\Î:*޾ƒø>ñÃ;•»Þ<À&™>ì6;¾þDL¾Òä�½ÿµ€»#¯ñ=Üï=» ¾=ÃY&¾Oé>Š+>Û&d¾‰ÑÑ<ïÓB=Êȉ½|´–¾-Ä ½ÀW²»Ï¿^½=œ"¾»™U<ö¾5ü�)=¸qµ=ßx¾†¿=½Jä>¾ŒÇ¾ŸôÚ½¸ƒ¾Iäv=Üq‘¾°OÁ½,ÿã=/–œ¾±±:¾w*=#‹¾C F¾á¤¿½|[¾�ó->‚šþ¼òª¾[I½ð&;<´³I¾£޾^6V>Ëà-¾¬Ï&>朽3�½Q<Œ½"d>Å蜾BÅ;äµ>±LC>O™=µŠŸ>ùÌ>x¸˜½f¿ö¾ŽiM½ƒa?>’Hò½QQ.<² ¾æÎ9½‹‰¾Á_½½›’å½"°�¾™?�!ݼÈS¼¾%G>üíÄ=¥Ìa=ÈÈ>çî½]!:>ÎÍ>®‹>n^�½Y÷½q=½®Š‘¾ÙâÛ½W>¶>fs?¾„>«Žç=u,;>�ìc¾Œˆ<½ ÑC<Üe ¾ß*¬=ößy>ç$m¾SºÜ=œµr‘Ž>Ù¡¥>¡ŒÐ>+‡=›‚=¯Õó>Âdè¾HRO>}S»tÒľb&½gU‹=*.`¼bÀ³¾6,¾4Ë$½ú,\½ôÈq¾ƒ(‚>¿âd>n¬¾‘ ¾5‚õ¼„3r>|#Á¾pzN>r± ¾ñ?§å¾: ½hÅ­>2zº>¨+¾½¹=ú½±¾�¤’=æì·<¶Fþ>?>y’¾ 5¿¸ìؾ]ð¤¾-à?ƒé=µÚ¼*Hï>Æ·>OgX¾š¦ƒ=«¢@¾Z¼>ß9`¾¶;Ô=ª_‘½Ø ú½kÄ=aw·=Co�>#&F<+¾’Ÿ=Uw5½ÈŠ>¥‹>£µÆ>ë—c>à3€½§ ?‘ž >$¥¦¾ÿWÞ=Úd¼š¾E;ï•­=×½6¾iÄ/¾’5þ==Lo¾~èÙ½b €½Vü>á0¾\Â`>uH%=‚»Ž>-ök½ÁAø>�Œ‘>ŇU¾Æ|õ<–;¹¾*Œ¶=L³½\Õî=é ¾K4š=3 •>� ?>DH¿Ú�,½Èä’>±Ÿ=g!å=c¶¾âúf»’Ké½#�‰= ̤¾³K¥>—°Þ=is > ›¾H >ÄxU¾¸mÏ»‡c3>äe<;Ç>�¦€>îÀ>ÏZ¾Iñ:=ÛÓÔ½Î|ú=y²<Þ.À½Žì¤½/Öľs¾4¯Í<^j<]¾é°= Ù;çÐ<)e‹¾¤3Ð=³œ>ÚQ‹=y‹Ä<ž:¾/+g½©ŒB¾\”‰¾Cײ¾.€=âÊk¾L«=Rls¼&t>«�©>FÆg=Í�)²>Eœ>(êH¾O/=dÕ½bè�=Ï.w>¤å–¼îíŠ>3a>Àù«¾o[C='•">Ëÿ,½ÊÊ.>~?T½Hq޽&-Z>!ºŠ¾iÀ¾M?WŸ>/$l¾RоÂü ¾óÑG>s ®> cè½w�C¼­�">Âßî=«¹Â¾F/ß½±rf½Óg½�½°ZÙ¾s¬±=sо+9¥¾²s=B¢ö>‡ìŽ>�Å»¾îH›; 6I>°ÄE¾K̾d>º‚>vó=¾ŽÙž½¼‹«½¦b>h¾�w!>Ø£¯¾‰·=÷ó€>ÄÆP¾áõ¾©D ;ßR=ø ¹=½\¾=LNø¼üѾC£�>D>Û’½¯Ýâ¼ùD…¼Ó‰Ö½ÌÂk>Òq½ÆGy=¬ía>ËVºöÀ$>ã┾§ä >d7M<Ї>—³8>fˆ=eš½>8@<:ÇÙ=R„•>P�º¾ƒK~¾øC½„å*¾í¦‹=¨&Þ½Ù{1:îú¾øˆ;+ø*>Ý�÷=K³½ßé>äi»½­³¾HÒ‹=H5º>F ¼gmÉ=øß™¾�Û‘>÷]r>O±²½ªè >ÖÿÒ¾Né¼÷0ú½°Î:="ep½•M‚½!ü=Ä¿×>ÿË7>Ó7Ú¾ËU¾ÇU3¾‘õ;Q“¾Ô€>F©>#ZM>:½¬=¢V®>£w½$²X¾)}™=¼›>ÞÀˆ¾YFß=†ôå¾qy(=n§ö½¥È¼³jÀ½¾™Ù=ýø¬=“¢�>‘ßë<Õ÷’¾ýs>Œ`Y¾æ›¾Àh£¾ À;<à×A>=×£¾¿¦T¾8nÛ=çe> ”…½ ?É=º>ÞÓ½ »½°ÆA¾K²Ë½úlû<”çJ¾ãŸ©½€©€=—Uc¾b�Â=|o>N`¾v?�¾±>&Ý0¾+ûx½ï½Ù½‚½®½\¾K½Z’€½Ö >�.¾ü%1½È�º>ÈÙZ¾×Ö$>÷×ê¾lL’=3ýS<Ÿó>^î¥=I¹õ½6“<óY&>â.> Â)>ËW§½Lôc>‡A¾r1�<º!;¹¨‘½Í¶w>&-}>Xœ¾ ¨>IÚ�¾IòÞ=¾sý=¶í$> O÷=fŒ>ïÓŒ½Ïx„¾NðÜ>¯Â¡¼Äùy=®;¾~(¾¡yh¾`Öª¾øC¡½ºV/>˜e¯ºag¡½­ßž‘É>s"_¾Œ„Ÿ=D…t;R;?@ù½kÜg>h¸ï½°û¼;g×s>kœ½Û¾æK¾É„@>-ÞÂ= ^.¾¼­c¾% ʽø ­=:iu>¨ƒ¦¾–>=Có¾×Ò²¾E<¶‹½ÿêK=½Y½•ž¾Ì]¼«Oµ=WC>£*¾Öº˜ ™=Nb¸=h‡Ö¾ Ä>ÐV>}ù”< R¾ÿó>’-̼ïp)>Í…>�ô«=Ÿ˾aœø½mØN¾ o»¼l?¾a(Ï=u*ѽžÕ7=².>C³> \¾ÞÝù:Ò ”>îj>Ï ½–¢5>˜9¥½Uõ ½ yȾ¡ h=“P²=f;>?¤<¾r5;¾/ö�¾†¦ø½¶•_¾·Â>ÊÆO>±°=ò0V>:ó<úS<‘ä ½‚F‚½ùÂA¾ ß’¾]…‡=!?}>‡ƒ¾s7=<¾ü«=j÷‡<·CW>ËJ…=> w>(9/¾ÿÑœ¾:n–¼àå%¾–�Œ¾Ë5®¼´ :>»>ºÿ@¾Uã=?Ò²½–þö;H�N¾]Ò�>ô¼¯=Í<ë= éø>µ64>Ÿ÷5=¢ëŽJ­G¾™J}>ìU[½gE¾6u´¾[-¾ç˜¢½yëS½ºß:¾ûXT>l›¾šu >gœ¼ g†>'ø¾B :; X,¾‚�Buœ<»->k×°¾ûbŒ<óTX>\ê~>6‹B¾­¹t¾ŒO=�fϽ ×­½0¼€¾ê„¼T[ƒ=Ëô€¾"Ñ0¾%2B>–°Ç<{;`c†¾"¸¸:V>ç=5LǽA¾±Õ…>¹xˆ¾&™¾Â¶r>éò]¾ÑГ¾Ñ½*½ú\”¾p�ƒ¾K=‹ÄÅ>è;>5Uy¾´�=ÐÆ>¾}%>‡0½‡Ãˆ¾µ5‹<,y-¾â¥@½^HI>4ˆ½MøÔ½âCy=g">º÷¼½q¶¾qÎÔ<íêm=Oá—=ªj>DsŒ>ˆk>!¥½&穽^îT> ä´=öæ�>Ì�è½êL¸¾'꫽]ÐC>b(ï½êˆ~=Ç*>VÌ=ÔË»ø�=zˆ½u(>‚·¾ÜÐ=ù½y�»¾¡è>“(>ÁAö¼ªëT½¨w>Ùlμßpÿ=¬¦¶½ÓÂÎ=ÝU÷=;Z¾O§�=£€‚<ÕGÊ<þ=�aø½�%â¾Q•½�o•>�òé;v¤œ>ß=Í?¾¸¾øw�¾¯¦¾_€>A>d⎽q¥];‡~U>´ å=×~¦½œAC>´,½Vª(=Å¿N>jÛ¾Tæg>¬G>ÅÁ—<¤…¾°m¤½#9™¾†ü5¾Ô>ß¼¼Æ½k!G>…õq>Gì+>Üþ">uÔ=¹™Ÿ¼øh>=ÁÊǽs®c>­>\·=^ƽ?ß½G?¿xJf<7ƒP½ð˜K= 1c=@s.¿bÎt=4 €>},8>OÙ<ë!5¾qßî¼t—¾ªóW»¾®´=àg˜¾—*ô=ŸîŽ=`µ¾@—?¾¨m/=3[È=ÌZ½?¤‰>§¦8½Y­‰>Aý2¾º9¡¾ óÓ>Þ×\»Õ;0>©d±=VÎ=8d)=ízH>ûÝ=|q½&Ya>eª>OÄj;8¾y>ÂdÁ‘¹?½ßú>Ø,C>½ïݽ¤:»=\= ¼ÂÛ½)oB¾«Õ½‚Æ» ßW=Ø_Ÿ¾²>~‚¨<`°c¾ÝçU>lõ7¾RÕ(¾lé½C(¡¾ð‚'>áå½gX¾� ¾Óâξ´�>? …¾uʉ>`,‡=�²à=”±å½ñ´½80>cÇW=‰>ÃV =÷àg><Õ>ØÝ™>ðê¾ÇW3>䶤>)&>åɤ¾hˆ1=*–¾Ù#ǽÝÓ©½u©‡=-¿¾½“Rð< ¢Q¾^†¾:#¢¾…«½Î6 >jmû<ܶ�>º3A½ö@©=PD¦½´¿Á=ÕO=Õ¬ê=§¶Š½f >‚=¾'SK>/Í}» W½·8оö±½Ü›™<7§’>Ïç¼ç—¾¿5ê=CÞ�>ß½ôþº=Gíȼ—}�½='¯>ÿ"„¾> -:“Í·>d;f=UŸí=Ø«M>¡Bà=jÍ>Û€ø½i¶ê¾í+d¾HäM>;ð½k£o>—^ã>Õß> �¾=¨N=$ >‚¾�þ³¼ç$Ÿ>Hú!½N~Î=@™¡=ö�=±Ji½ÚËñ<5 °¼f¾{ßh>�Ô^¾ÝÀ·¾jž€:”A־Œ–=·¬½¨¹¼£Ô„½ŽQ¾Î>>Syü=lJ>¨ee>½¬>YÛ÷½ rœ¾Ë>Ç—¿<áÂ=½4==¡ñ>Ù—¡¾›=Ó# ¼'N¼Ëa¿¾5¨G>§ÆD¾#·=b†½ÉÓK>VÚC¾}%1>Ä»8>' o> œ>ÕÿY=üEK½JÙ:¾¨–·½—�ͽj@ª=Æ–;×>³½Ñ‹;õ¸ã½�ñ×¼üŸ6½Kܽs?9ùõ=T×p><’C>ªÊ‚¼Jn^¾H$7>9®Ý½rØÉ=Ø›g½n6¬>CÅ'>I싾BëK>jƒ¾vc¿=ú3ã=-þ¾1>…½*@ª¼¼©=•¾sš>�<~Ñ…>fÔ[>›áÈ<“`¾lˆŒ>-VÓ=ÀQ¾ç7>/©Œ>7J=%”ཽ'¾þ^>w!C½g~<=6—µ½\tÔ¾4ö%>úüö¼'Ж<°·2½É÷;¾8 ½x›‰>ȸ¢>Ò0r=ÕÝ2¾%` =ã(=S>Û¢=ys¸>”¡¾¾`“ =¶‚Þ=oèP¾ïèO=±A"½‹W’>31;€J¾¹ e½h>Ͼ°Ó‚¾t–½qK§: 6>tI†¼¿£=„_u;Úrq¾<ÃT¾¯é?>–®Æ=åŒa¾påŸ=þ(j>ùz>)JO¾§²¾t¾f‡=ÿïÖ½hZ>†Œ½µ¹=Ð;¾‡Ã>ðV½âTz½4瑽L 8>¢ç¡½‚ÂØ;¹?¡;â½]¾�Ëù¾z<‚½k8=Ï:=%+¼O³¾È3¿e’L¾íà�¾ô³3>(,n>>ñh¾XéÌ=ŠÁ½#Ž>xC,==1‡=,�½è×=a•¾º²üB=¹õÆ=¶ß½¸â=D_]=u„>M@ø½²Q{¾Ž„>EÀ>p$>ÊFÇ=WzÞ=¿…k=bª£¾¡F¥½P�4½SY‰¾J}^¾ Á¾0 >YϽö©š¼Æøz¾ï;=ý‡_=OOš=¿‹æ=±H@¼£ðg¼—3r>X3¾¼ §= G•>ßÒ˜>3Ù”>j¯Ñ½ú# >ö¨�½l�Õ<Æz0¾_£€=Gð¾èœ >Ö©8>uS\=>‚>(�‚¾÷Њ¼³Ù¶=§e;¾ò¹¯½ŠÜJ>‰?¯½NCi½$b>Ü÷>­¬�½Ö¼½iã~>Gx±=zlì=zE:¼K_¾â)\¼Ôï=‹®Ê>J F=}Èó>AÀh>—š›<T�½ÕT½ ›0>Q³†½ð–˼iU•¾ÅK=X >6–¾Ù ½›ðp¼(£¾<^˜™½x½°mð=RY¾ aˆ½ô¿7 P¾¹ Þ>¼¾!…b¾Wä\=‘¼=ÎËQ>)¹_>庼Žpy>`—½B>Ïçǃ›ü¼)´>L`q¾:(Ê=$w>9—&¾ÿ>ç½»ûž>¢á5¾ì·R¾NÉP¿rÅ’¾U.¾2~>¨ù½™s¡¼¢Ã½Ñžü=¥ÿ=Q _>Ú¿=8\W¼Òæ°¾VŸ­¾ø'= ñÎ=~fP>Â}>@q¾ ,¨=n(l¾ä…y=ñ¹ä¼O¯6>~�_=øCt>s�о>™Å¾øŠ6½Cª¼ /¾zà¿?á>̾Œ;ë6¸¾¢´+½ŸÃ†=צ=÷Ÿ‘½†T¾Î%•>"ø¾nòº¼œ‚=åá>€øì¼'b?²Øb¼ã_>‹S5>KÅP=+žì=©¯=²—6¾w~×<ÌlŒ¾·-›¾?´Ü½?Ç>Ž'Ý>8þ½Å§>æÐæ¾Á²¤¾|£ô:VÝC=k“8>W½=¸«¾Ð->ú´U=û™½Eɲ½n·(½ʧ=MÖ=ÜÓ>Óÿè¾ÎŒ>LTp>CÕí=8ù>võô¼.¼\O¤>wX;>³½±1�¾VZ>Rzx>Ò×½:¼¾rz´>ËAî=>rU¼éC¤=À¨¾ÅÁ7¾æ8¿¾R²È¼ÒfÇ<éh=}éC> zß=PG`¾k,š½°&§=°9>�!u>÷$>5g�=‹£q>mè=Ã:¾5Î&¾7ov¾)gî½#ݰ=•Ó¸=¹&¾8«,>¡në=Ý�c¾�ÓË9p´;)¹ž½ ç>N-¦=˜¡Z¾$?>òX>4¥<,—}=Áxî= VÚ½•Ň=®|1½çÀ>±¦½“Ýn>u3°¼‹j&?HH ½2�Í>Â:>/¿§½Hc>޾KÂN>Z¶“= ½Š ¾ÿkã½ùaa=,á§¾†5É=h×7>^.‚¾Nç ¾{ç¢=§²|¾Š³g¾Â¬®¾Ý²C½v M=UR>]øí=«KξË->bl+»Ýh—¾Oý>b…ø¼à>”ß½Ê`�=S§„>�ö½t;X>Û6>¤gÌ>|à=äD„>ëID=ô¾|®>åÙŸ¼km†¾!�‘¼@˜< h�>9Äi¾÷åe¾­—‰½ý¥ý<ûž:¼·>øí ½z ½UG>�²³½:ò&=“ š>2Dò= P‹=êt>óä¾>MÝ£>/Èu¾'—ļ6!=»È&>ºÔì=¦¤/>¢Üì½�µ=¦‚�>ºê¨½lt]>ìR^=žÝ—¾Ú•U¾Í�ì8é>И¬½öh½¼§¾úÿÏ>^¯ ?,Ê >û¥R>Vè¿ÓÔË»Oô ?tÂK¾6ÿ?¾¦œk>Rõ×=æ¾H6C=s|‘½Õ©T¾?¨š½‚.«>_õ�=U$W>B–v>b¬=w™"=~d®>74<áÄØ>òüò=ÓöÓ¾ì À>Óf"¾l\=˜½¸ó¾=¬ðž>`Av=÷s½=ÀLC½¨>~ç7»3€ö½ØMb=ú�=Ö÷®¾1 ò¼U€g>IÕ¬¾+€^½§e�¼Ñ .>ñ…¼öyé=°Q>vÂÒ½öÂŒ>å´Š½ª¿<[ª˜=„È>Mh°>9|½b¸š=Æ´é=»¯‰;ùeG>cb=!¯ì<Áj¯>þËi>@a?©äP>†w?7§®=ÎÛ¿G&d¾;-½{eì½:×½�¬{=�~D¾C`0¾µø×=6¿Gë­½jÔ¤> „m¾¦v£½ùùC¿jƒ=%û‘»?æh<Ã� ¾¡À—¾´ze¾#ùˆ¾ÄIs=lMš<>‘¢»G—[>Æ ¾ãK¾l¡+>…ré=!ª>Ù`>ùÈ#='³{>ƒ|¾òw¾ö4©>¬Ñ¾”ÄŽ¾­ÆQ>éê=ŸÙ“½í ½*~޽&ã½ið¼Eûi¼m±=À€ý=CÅÅ»>B¾aï�=ØR >u+¾ó0Ò=“°J¾r¸á½ëÉ=v%˜¾è‚”¾$>Ýï¾ö—¶<˜�:<ñÞ›>-ÇK¾}Ì%>sÛz½'÷ܽ<俽¶­¯¾“à¾X°À<ƒBk=Ýjq>[¾àjï½&“=¾25µ¼¨î|=gY/¾-j½È^¾ê<¾ì¢˜¾Y¹½9–Ž<ì©Ê¾õN½U¤¸>¶ª>it&¾Ze¾½SJÕ>J'¾^]N¼q“Œ=Q�>{™¾Ê/=eˆ¾À¿^>8W$¾�•›¾ 2¾¨JA½iA�½:Ÿ ¾U")<™· ½ßœ¼Q|,½ßW×¾¶Ï޾¾)¾Ûœ=�—P>‰*„>òý¾•ù+>jŽT¾ë¸¾Dt">yA�>„ÓÝ>j\$=� >®‘©¾îÞd=›d>e•½ÃÎ> ¸)¾“œ-=þ·^¾awï=YÝ\¾(O>¸‰>ÖZ¶=\AŽ®£–½ ½>F=e �¼X³$>{Xm>°ƒ½1"¾‰°“<2¸ù=j›"¾�›½œTØ= ±¼¯¼Ú+¼½€®©½ÉQ>ÆÑ,>Ê[þ½ÈH@>†¼>y:G>0L¦>_ã>À_¯½ç,©>rp4½–Ò1¾øÎk½5’½oÉ<>¸Ê¾ë¸!>ø›E¾@9è½ÍPP<Òi¾»ÙK>ê©?ÍeÍ=Hñb½&.ؼV]½añ=øTa¾yxš>_²L>tË·½æ½½7:þ>’`§¼¢�ƾEsc>—­>¹ë©=›'=ö[‘½æ�†=8®ö¾™€¾T`>��´¾CŠï=a‡w=ò"¾é£½EAÑ<T¾ �>ì�y>Cý¸¾Ðð ½ K¥¾7,¾j_t=š_>äA^=ž†­½ø9U=Òê^>’“#>ÝŒÁ¾áŸÖ>Ä|²=�ÝÛ½�6[¾’z>�&4¾'n>­¥¾üg“» ¤”½ÍíN>/8>dõP½ñ£¢=Ec‘>¤'ã=GÓ¿v©®<ÇA> &>‚š'>-¬¨½@×e<*õ•½sè4=«Å—>Ðj ?L8&=¼2†>>†ñ>õé> ]¾4¡;½ˆæ=ؼ>=;øØ½8Ô4¾ªGï½m’€¾”��=æ‹J½ùû¾¾Äž¡½å4¾œÚ#¾3‚˽ªnf>DWn>Ÿ\">ŽL >'KÓ<›nÒ½ø"$=ÃðU½âJ½=½¿nþô½»Ü¼¾*0"¾syÉ@¶=}îÀ<d�¾{ZÓ¾èí†=¾ ¾ÐL‹>H�=*œN>Ò}=¿Ž>­—>*¯±>}ð¼ƒ( >¿Äµ>¬U">1ï·>.�¾QL¯¾õÛ¥=á¼–½�““>øš�¾]hQ½dü ¾Ú}•¾êuw¾Çy>· Ô½*Ï> y޾ /D=¶.å½@Ñ=ÀuO½Æ’/¾éÔ^¾À1£>*‹¿ ¤½�ì½l;>Ût>¾F'¾Ç¦g>xÀ¿¾9½ 3¾à„v<¤3¨½Ž…d>sÁ™>ÐR¹=FRì½Eèq>ÙG ¾­ß\>i.f>Ù¾Ó’`>öÓ>Vb`¾8ò&¾Æ”¾ên’>"¡þ;vpξæP>¦³@>oè ½Œú¦¾Ý1O¾0S/=s2»1�\¾×b¾©)‚¼"à‡¾À•A=Þ&ò¾r™A¾ë|>4;ƒ>äìQ>Þ¶*> Æ*>Ù=,½¸Ëã½·$Ä<:ô›½ PM>l9´=ÛúÒ=Pe>n¯E½Á¾>Eth½£"4½–¥¬>¾ñc=*mN¾"I=•çŸ=•�[½;§Ý<'¾©­³=•t¾E ½�©Ú=ƒžÐ>§>⪽¸†;«™õ½_æe<ÛB=½¯�Ç=fL6¾ÝÇ=đؽö`þ=f5=^Ý>÷Qp>xï§>±8ƒ¾ø“€¾LŸ>¼ú”>f Y½s�j>^˜ž¾�î½9Û¼�푽üD(=Ú«<`ìl¾‡€k¾HÈ=ÿ1N¾Jýq¾qÝ’¾a²�½JM#½E} >†ûν+ ©½Ñø ¾Ç..>·F/>&M6¾À{Á>»HÃ=å?X>þI¾CŠo>Š—/>V.û=·ìÁ=2¬>>6úk½[ù.¾\ѽ�.»<ÁݾÌPÞ½ô;­¾™çÀ½ó€å¾ò˜ô= Jã½�[¾¢P¼·j‘¾5jô=,ÿå½XнH³'=v»«¾ÇFH¾L¬äËÑð»&ZL¾þK‰> ¿ÛŸ”½Åd€½¢£(>[•€½TÈ(½ÐóÑ=롾�[‡¾´—Œ¾vSV¼4`ξÒyC>®] ¾³;E=HCc=b¬ì½î›§;|c¾t9�=n¯™¾µà½¿н¾ª=›qÃ=|¾~ù<<ã ­>ESÃ=M26< $H>°®©>£ =–}2¾½ái>X Þ¾bí%¾†ÀÙ½4w¾3‚>«*ì=!¸>¿�½낾¾Õ¾ßu¾-Ã×=%õ̽.%>ñ{:>?×[>g2ˆ=×å=-@/>lh >Ô@=Tš§=uê¿;>\>[Ó4¾èÎ<2UÒ>¶“f=³*–½¡fö=‰Ô�>Xàͽªq�¾† ‘¾ŽN„¾²Jò½0³4=_½î5=Sà>`½“>©ûs>1d¾©à=,ãʽB+>ŽÜÃ>_Za>jp‘=¨d¾p‰.¾ÍÓ�¾,Ó½ãú™<*Š’½ ÿƒ=éx>tf½×…>{>6$€¾‚}ѽ’í9¾îɹ½¼›=%•Á=Lç0¾ÞÌ ¾}@\¾L÷g>Ò+¦¾_½u>‹Å=aÈ.>#YI¾d&¾7p¤>èxݽk±Š¾2÷_>¾u®¼œÛ†>“·d½­†¾[~оšs-=ºŽò=* r¾ºŸ¾ƒhT>öhZ½C<Â�:¾Ž I>ìøu=Õ]‚½‡ ^>£N´½çM�½½@Ù=PD>¥X¨=ŸÖ ¾P=‡¤½áâc>þÍ,¿f,F>ú¡ý<@Ž<Åöo¾]Œ>S÷>¾h—¼Uã½¢Ó€¼K÷é=¾åo=>O®½<î¾ !œ>ß:µ=—Ü0¿Y¹>[ >æâ¾ÜݽébI>“±&½žKÁ>jËB½ø ­>­„=úʾŸ• >Me>$T­½±}=¾¹¡5¾'ï«»~gÖ½êSÞ½r1¾PŽì¾Ûžý¼Â/@>Lä=çØ}=áR?ˆ! ¾Ù'Ý>C—>¬)C=úT€½C$X½edD>çÛ½>LŒ8>ö¯¼§7½{r=¸£m¾˜¼5¾ÂBs>„ å½ÓÙ¬¾ØÅ©=„]ÿ=^Ñ= ì¾&©\>G_F¾Wâ=oŸD=£¢`¾ýòn=RAŸ¾ús=ÿp˜>Pß=S(é¾Ð`‡=D­½·6†>”í�>æ >¹…j>‹§=*Å4>\bȽ&=>uŒØ=æ+‰=l>p¾Ì=9¾>Aå½ìf¾ù÷ü>4�Ž=ÿ.>³U㽦ù´=Ýö¾—²M>Z—÷>÷û?¾ðÁÃ>«Û=vX!=²Q >ôoϾ,äá<úソ Ã=…í—=t$>Ó>B¸Ž¾–”+>£ª¾:ÎýÿÍî½3Ñ•½ë##¾‰â™¾ŽŽ*= Ú¾zú½«â¾(g:½wÍѾbB¾ßto¾'½B_=>×­R½ |Ö½[%|>éI‚=©h =Yù0>k=²¼„Ò‹=^$³=Œ0?UÏ7½öŸ2¾h÷‹¾åØ¥=õ¾=ž$�»o ä=3ž<CϾ,>h>_S>8 ¾%cV>ëM> aj=7âëºu‚>ò>Ò¾õ<›º[ ¯>˜qª= è=t¥¾Çø¨½"ì¦>»™ë= 2¾Ù­»½”£‚=«w½©ßÑ=˜æ>Z¡±>t>¨u>ä[t>õžG=Ý0á¼J� >ý‘>�<,¾„�<0@½ ¿n>glú;� J¾QÏ£¾)@›>òž8>Z¤…½£�—=Ö =Д‰>ùÛ¾W!$¼ ­>—Q>B¾ÓóÄ>|`Œ½� ›>¶¾ÐE}>sè„»ìYǽ§£ ¾/•¿>˜I¾dñõ=Ö«S>{ÔľrN=ð*R>ÎM’½�ô\>zæ>¾/£b½ÞPŒ¾HŸ‰¾‘æ¾ �>xû5>pø‡;]ºq>c¶p>½ ã=ŸˆG¾§¾"b> �½S6P=�F½RìǼ�á¾L>8‡¨=k =FP¤½`‡.¾¤~ù½ p¬½Ì­Ž>ª´†¾oC¼8ð ½ØÂv½�K€=ͽ¼õLÙ¼„¾”½k?½— ½½ïp»å.>1¾í|�>Ô4¾N׆=’úH¾›éÛ½"þ×=Kf.>8°?&Àã=žK>éd˜¾�K ¾!�O½ßÒP=ꃾoŽŽkî½ÈM>ŒÂã½B2î=úVU>¸ã9½н^̾÷->¥£¾{¶=œt>³ k> ZÖ=LVL½iÏ;tÀ>>–%v¾ <@>È£”¾À9�½jc?¾²"à½ó­½½¥"¹=2œ4<Þ¾{Êo¾µÌ©¼ð¹4=8Š/>OÅë< ¨Ä>k>q0¸>5–нV®Ø=u:>L éªd:>—³^7?½Ï<í¢¾9 ¾v‡ž>KØ)>ô4>6²Š>×~6>+•k¾ÝV˾ ŽŒ½©Vٽزî;Y¦Ô¼{tî½”–N>ç>=`‚&> ™½P´¶=ÿý´>~$4=΢½U&оY-“¾Ë ¾¼Ÿ¾M«½ûœæ¾fz½tRǽ}Œ =±§|=‡Ê�½„’`½Ÿ>±²V=h‘8¾žFú=E±ô½‡�¾¬.¾MY=QÀŠ=[º^>P@ɼÌsC>}Ø—>kay¾Òõß½Wp¾IŽ„=Pù"=•g>¼‚³‰=÷Òq¾|©ê=Mðz>{l+½ŽŽŒ>¤Ž÷{¾3 š>x ¾U¥+¾‹¾Ç›F>ß-ȽÕ£½µe®=ÎíÊ=ŒO¾Œ�>ûÊ}¾ïòÔ½Ðö�½Š ½) ¦¾šÞ¾>³d;¬+m=g[Ù=�}½š†¾yã[>¨3<@��»ïý2¾­ý<š\м'M>‚ð¾XM¾øuȼ‘“¾È|¼TÕh=±Éü<ô¦À½k”½½»&½À±,½Æm>ÿ›O¾÷]¼yP%½mVk>†3&¾"8â¾Q[š½Øë>侇¾Wí¤=¦×ð=Î�±>Ûø=¾M>=ƒ&Çúˆ½œ�>&z>è\Y¾ª�¼¦&=qad½ðÁ½³Cs>¦¯¾5ß6=¤$Ô¼³Ú.½_t¶=ÚE>W½ ž;ÿ¾=`°=fáݽͣ7>CŸ=lEù½Â0¾-½sq¶¾x©¹¾É2©>¯œ ¾ýpr½xwƽ¶Ò-=å{º;F5¾^?–<Ð?½ÖŠß»Õ¼á=¡Óˆ¾®´\>6ݾúg°>Ä)¾s ½º§í½pϾ‰ß={<ؽ ÿ<!–¾#‘ÿ=º�λ ,*¾<²Ù»lï,ƒåx½;‚¼ÐÕ‘½Ld8=È+W>¾Š½™Â=‰)7½áu‚=Ũ•<ÑV�>–à>˾„üC>:† ¾Ã7>ŠÌ=±æ>ð¬_=ôiƒ¼ò®‹>Dª@½ì4S> cÏ=Ãx3¾Ø%¾¹¾g¥`¾i>œ\¾7Mó= œ¾»p>¦Aš¼/ıɾ—ÿ=ŹJ;ÆO¾¹m ¾oe&=!ö½¨´Ñ¼%:ϾÊ;¾„>ÂB¾úÃK¾ñ‡S¾iOÅ>C[½÷}a¾#9> p7¾¶áƒ>¹>«í•>æøY½#ôE¼ÉR ½�:�=’�K½TxÖ¾ëMŽ=¬Hˆ¾l^<>'T…½ -A=”à=%V¾ <Ö=ÿ¤½0¹ ¾qú^>¨‰š>.ìv>DÊï½]h�<³—ñ=eɽ˪‡=¾g:¾âˆ�¼é¼¾ë%«»au¶»Ù² =­<¾Ïr¾uL¿ç^¾’ƒ½7݈¾þ½[¥Î½»´½pû9¾êRà=Ÿþ ½o–—=þþ½ì¨¹<Í�N¾¯J`>•pß<šŸ¸<»‘>…:š¾�¹“¾2h¼½˜@~=û˾«§P>{{„¼s=>Tk…>lèоt>>ŸÅ½­!•=j9¾pƒ)>ðΩ½ü�™¾ëx0=xl>nO’=Ì>t¾Ì=4>">2¿�>LKà=öz¾BZ>s?¾ Ê_¾ß؃=±¾6¦¿=ƒ�¯¾ö‚>èÐ�½–ì½g꘾ž¡±=ËU/>[ºV>ÛP<•br¼N÷»Õ�½ ãÑ=±á=­¢=2ω>ïfk>ٕнÀ£>J‡ü;½_=Š`½„ã¢>ãÔϽWjº´pî½Ýw=ÌjÏ=*=޼Ü/½Ï®×¾³}>–²-=ýD=å^ͽְò=<^'¾,w¾)錽ښ¦»q½0¾²›�¾Šì„=Uá·>»œ=ßPó½Ç>+ýP;`7:>=;¬¼_ìê½ýpº¼@\¼y`½½Ç½µ>&PP>|›¾â,¤=ÖË™=g'Ó=à˜«¾goŽ>õGc¾‹»q'»åƒ+>$hh½˜ >‡ž�>¡u]½…‹/¿Êö=@zË<âk«<@_¤¾¤Ö•½×!쾄ª¤>ïÿC½ŸW¾®‘½ >™ó ½€?¾¾ µ;°Ô§½¹aô=ªÉ¸=‰ <¼0W>؃†½2óö={ç/¾"b¶¾ð³„½´=¾ó·^>på½wÀ½ä~o¾SMé=óc€¾+È�¾:)b<¯v¾Ä£¦½G|W> ?Š@">q¬¦=È'<¾eG ½1†P=À=j¾â£á;´2?:@›½ëy‡=·dk>f°Â=Zc÷í„«½é,>ú3¾håº>‘0¾Û�>,á;xe'>Ï‚¾â��>Æ÷W=$Þd¾4 ú½ä¼]C^¾°Jžúp$>ª,˾¢Ãy»|3 ¾ïÅ’¾k‡¾÷'>J\<5w/½™�¶¼°Y8¿Å¯¬¾4ª®;¹ÁË=)3‰>áJA½J¹=$q»·a€¾@˜T>Vû¦¾€Ô€=ÓϼÉ,>´X9>ê…½(•~¾G„‘¾…Dé=ˆa¾ûÑ€½jó\=°õ˜¾�C�>†É>‘Ä>å¢>‚cð>è¥ñ>‰%·¼¾Œ§"è™›¾Åp >S&æ½JíV>d„é½ðx=RS®==L>Á<à>E!¿½n»À=²»8>ÝB¾Z\;øˆÃ=¦6Š=Sð$>lÄÒ¾@wÅ>°<¾9gl=¶)É>zŽŽ¾Éj#>÷ƒz¾÷�¾é¸‘½XëO¾ãåô<r¾ˆ V¾õ+‹=< ¾FuÐ<0>†ci>È>)=¬¾úBÄ=fIú=Eß²½ß1ð¼ =3Ù=¶ >êT¾Ý•½Ü%&½? C=Ñ‹§=¨a–=Í載ÄÛ:ÙÔľz™=¾ào >›>±±6¾œë)>˜.>j~™>‹>_ÙŽ¾åå¾ÔL¾Â޾ý+à=—�X½†ÛŽ>|õÇBM½ð’C>GÀ7<®Q�>nSv=–å.½±Á&>#$ð¼�Q€½vnç¼ñͦ> >¿=‡0@½ù->64Ö>jq<‚3¹=. -½‹6?>y$¾ûÆ ¾ d&>ž]Ó<8í̽͹­=¶~`¾"Dù½`H¾Báà=@öN=béº�ËI½6ŸM»™yp>ïU”>¥d´¾]m½>J½§çH¾ç¾1¾üf¾ˆ‹¾ÂX¼ª6q>Åk~=eð¾D<¾Ë$™½vR>q“{=‡•�>ÏÀ¾Þ€’>âæ<ˆô½ÇÒ’¾�,¸½µlL>¿±H>k-h=vIð>2ò>D¸¾ Ǹ>Ž»G¾ž>”Ú\>ÔÀ=V’\=dê­¾×9°¾¸¾Á{6½vi>Œ’Y>!]ê¾üÊоx>ͽQ)>É㋽Ž„>&Q‰=.ýÑ;8[‘½kàͼ6Ý�>Ì‚+>«i]½(à¹,ì—½µÝâ¾ïã@¾Q@·>-Òò½×Œ/>y›¾¾¬�>6e/¾ 5¿¼Ѝ=›i¾õY¾+Pg¾cK3¿¿è¾jü4>ïç\½áOE¾pž¾{ƒ=]²´¾ttp=ág!¾Š‘T½˜ÚÞ=.7->¨ƒ½Ø�>”÷�>ÄN >À¯>ß$=o$ˆ¾ ½>N‡í½™�‹>0Mþ½X4¡>«ñ¾vz >ÞŽ>ù§Q¾¨@¥>ïI>úŽ=AȾKŽ+ö¾ZG>º”‹=‡(‘¼…òI<øJQ=ü?à%:½s)`¾¢]4¾iÐ%=ß^W< ï<Ö¸>·D«<„Oï½Ö¡Ñ¼ý( <¶»µ”E¾ó¯¹½†·µ¾Øš¾¶™Œ¾“Í=ÿùK¾^ñ>''Ù;èõ)>�7â¾È슽a Ö<©’4>PÊh>–ß�½<â�>hÄb½×ã´>›L?Œí<âÌ¡>©"s½ I>2á¼ø¾Ø€÷½2 >�͸¾šúô<"6v?�‘/½¾·½bõ;¾žük½eމ¾:¶=ˆ×#¾u„S<\B¾�D�½‘mt½õ—E½sj¦½³²j½ŽžŠ>¾„È<œÏ>Ÿʼçßp¾’’¾ÈZ>öŽƒ¾V£á=› ‘¾Öc›»T-¬>©&‡>m“¾¿O=6 >³ f¾ +”½kƒ‰¾O`�¾˜Š½h®+½õ×Ǽ6j°=Eìg>f»>våf>#I>£ˆ(¾M÷ݽßX=ï²¼_Áª½ÌŒ¾õ!+>n·8¾›™>CŠª>”¿=<æ&{¾f »=uó:¾5ž=¾!AȽÿ�ž;z®!=´Nç=×Ué:`f…¾×ié½e¿?­·½Ô•=ö52>£Æa¼Ù¬=ùêÊ=WðEºµÁ—>ùz>ie¾vœ½KT§½® ú=1A:>ÌŸ‰¾/SR=ϧg¾ž¼R=2zr>k¼¾&^ñ½b2ì=ßDö<•1;¾Éuó=ë¢kºÇ¾Ès¾xÚ£½Œc=1�;ô¯n=´O±¾PQÇ>õ?Š>³\E¾rV<¾ f´¾ö#¢=]Ñ:¾0UÓ>¹µa½y >惋½ìßó½Û¿¤=36¬>)¨›=„D>°“ª¾µy¹>_ÓÅ=\¯p½ ‡Ö½Ï„à½�4¤>O$.>}‰u>�gØ>‚Ât¾`k¨>Ýü >Ýô?5ˆà½r[Q¾²�S>Ò½½a«¤=Œu0½¾Ü˜>‡;ç¾[‹ˆ¾öS—½¤g¾í;‘¾©£!¾7üf>zXq>œ`ˆ¾èä >KÆû½‡%é½—€ª>k霽íôc>– h>VÎ?=f6:¾óö콿Ä=õèÚ=uéF½Î™;¾D¢§>åx¾y ¶>H&¾»ÖŒ>á¶=[§D>=G¾”ñ£¾ £›¾sT>¾a4¼LB>“û»÷Ì�½ ��¾‡Û=0æ7>Å�r¾èâ…¾Nó±¼èÌ3>æT¾ö²i>«O½PP =xÑH=c)9§§¢>[U‡=}¨¾2­¾Jô ¾Û¡>L t½IªÔ½ ޽Ã~>8>d_Ö:ºŸ>.Ÿ¿% æ¾ Z±¼¡…Çv†É½Âû=®`w<�¹Š>Q­>ð ¾-Ù罈öоb¤½9~v½F޶>j0¾ä»½ðo¸»ˆÂ½Nw‡½:¼¤Šì¼Ô/½saJ¾ì‘@½>w>-\Ý»W´c¾�@b½e{ľwC¿=�R̽†FL< µK¾6]‰>¾±Ó>¡›¨=.”%½y¶h¾¤Jî<S>s!ô½Ç/½ù6B½GTF¾\†C>…ÓE¾Éc-¾–’ÿ½|ÿÚ¾bs_>7¶Y½½>t«¸>Ú#Ò<ͺ= [{=S=¯¼¦úã>)3¾=¼6ŠX¾#Ф>=Ï$=‚°ß<{m>�˜¾gª˜>P‰¾a§>bÒ½¹Èž&3¿=‚]¼uz)¾S Ë»—Â=9 "=â®&¾þbÌ=)¸¿²�4;ͻ½�1Ÿ<Ãôy½ä¢¾ ž½½?¾�ˆ=—¸Õ=¬*2>ýX¤¾µv ¾S=< ²>ˆGX¾"â@¾I«K¼MÀV=¦¯:Rн÷£�¾ûŸ>�]>8ÛB¾ìüW¾åÜ¥= ÓO¾<0Æ=”‹½•’¾<>È9ú½Xþm:·46¾�BÖ¼›Î•¼¾X¿-œ>·¶p>=B½7¸L>rY>ÖV€>^Ð>ö›ƒ>vÚ÷¼lt`½u¼Œ>"u>Àêû½àc»=ªq7¼5ʾï„-¾¥·ˆ¾¶k®½7»²¼ˆÐo½ƒ�—=Æ2G¼‰ôò½5€A¾EY\=êr´=ß– >‡²½d¦q¾Šù­>8Æ^¾ T>µì&¾õ®�¼£M@¾˜Æ®¾¾f’¾mn'¾³Ý�=þÄB¾5$>H ©¼‹‡P½°‚ ¾ Ów=C>âñ¤½&ø<êÖK½äëv=5Ƙ>ûÙŽÜÚÈ<"�ñ<þÓZ<ÎØã¼³i<•t>B‚F¾lÏŠ>±�·¾æ¯™=²Á¿½>ML>¸¤Ü½Åõƒ>K8Q¾<ÒØ½­?¾Å4=Êz¾‡é]=Þ f>3{½Dì2¾š��½ŽÄu¼pQ=§HJ=²þ�=$ô¾Í‚¾\²z½*[!½» ³>VtB>F¶Ò½) ˆ=º&;>Aî�½ºË<éŸý½‚Ñ÷½ø>¿Ÿ>”ÛD>ïîå;{88>qùýY·O=;j7¾Á“=öÌ:>Åkñ½þʹ=Ó"Ø=p( ¾>y³¾º¾ò=ß7>k—>×ã:>ˆÄz=‰2L<‚;¾-´>b0)½xh‚=Û�.>Ul*¾¥j>Ib=›]ä½3“G>.Gú½Šw>Í`(¾8„G=cÀ¾…W=½Ú¼ÈNö=3Á?-°¿w®¿¼=©I>µã’½|A’=-¹¾2e >þTL»Ð]ô=¥é0>e@¾X2¾ú+o¾sƒ >Þ‘>WtÞ>+yA¾{½>¾Ü:{=Cl=/;;e˜Ý=çO ¾ºÔ�¾%€‚=15�>K ¼>Cšv¾ÛÁ…¾ ¾°Lf>q�¿=½"`¾OÃ">UA#¾›É�>¹pR?^]…½S{Œ½hi“¾1€»$翼îô®¾å!޾5³<¹e]½\Î=ƒ]9¾Àð;“M*¾ÜòE¾»ü=)¾‚½Êm>®2>îÓ¾]ÄË<ê~‘<ظ¾�$ñ½Uÿ?®¢=¤ß3=ç<½¯¿Â>i¾øU¡¾è•Î;OtÀ¾”ZF½„Qx¾b<È=Ït <0¼ê¾·²Ì=dñ;Þ4i=³Üñ=.´…="�ê=ôR³¾4Ü={v�¾ù—Ô½HpV>ÖÆ¾XT>0GZ¾ðR½é¢€¾ùû�;:›ð>;ʆ>5æ¾yÔ½„&ë>‡@Å=Aäÿ<ƒº¾ 3~>MU¨=ZÌË>8¬¤>0s=Mze¾ƒŽ>qµ> ¥t>W¾m–[¾»«½9—°¼½škF½˜P=4ú>;Ö#½þªœ>ð‘Ⱦ=ˆZ>w,è=>òt½ú*=øñ¼X'ï>‘»_O«>œL�=Ö¦½´Âq>ÖÙ6=Z�¿ýÆL=³˜Ù=Œ4¾p"c¾��¾Ép=XòÖ½»¾Ÿ* ¾5Ò¾tªd>Zè>¸~?_Œ¾ã¾äI>üðS½Öð·=˜(£¾*OU>"Á¾½àR«¾þ2Ý=KŸ½$ °>•7ɽa¾1>ÿ5˜=|{¾mIݾ]ïä=ÛÜ<=”¾6=wâ=ÜŒM¾úÿ"m>tse½Žb¾‚=²ÃX=¯îr=“X�½Ãþ<Æ›¨¾ˆÅF>2J̾e>R> 6:¾X©Ä=„è¢=.f±>¼#¾˜µÍ¾Áq`¾Æ¨Q=8¿©¾GŒ =?a >­<,¾½Ë½ TùºG}'>¬G¬½¡Ú>¢ø>J9…¾£³ï»žÕˆ½Èäš½ŒÈ>’Ec>• =!= L"<´ëb<Áá•ÁJ€¾Ü¿P˰¾�ÆÆ>ÂJS>8þ²½ïò>"³W> ý¿>1מּ¥¸=jƒg<·WJ>·@x¾À ½3ªŠ¾•:™=ÔnÁ½ùHÝ>¢ë½±¾“çÞ¾:ïí½bâ>~þ3¾=Ñß¾2Ü·¾k޼e‚½zÓ½Ú½îN>xó/¼“K…>Ýýà=k¿>>𳂼âÄc>ù›½]X¾t# ¾D}à¾HìÖ>ÒjǾZO°½h(u¾ñ™‘¾C2>d½²“=z<@¾À4�½é¿Û½»{ >¥qØ>òM>ii¾Ð‰H¾Å!<¾$¾èÈÜ=Nô¾^Â¥>÷(Q¾âT…>á<¦>Ùi›½öu8¾®_ú¾è¹>‡=ƾ¤:¼¾+Û½Q;Ï>7‘n¾gˆ3=¼\W>¦�¾”r%>:§t<ÞôX¾¥¶Î>}8 ?uì¼ÖÈn¾Œdš=/�=Y³½õi⾱ɔ>Cü$>fw½èM¥> Î_>\++¾t•¾1I:¸äÌK¾ A>çD¦>¾�{¾$6¾ð˜¾XnßÉ/½µj¾¾¹Ï-=¢D>-X쾯¾ê=ª_‡¼ü �¼W¬=P>%¾Â¦ñ½�‰â½Xþ>ð¼ƒ>0Š\>úÄ›>ª°=9U ?·R'>”ö;ý¾£Ò=>¡D >�|ùÚоJÏ=%>ÏuW=Þ°½î›Ù½®–÷¾ÜI©¾,ˆV>�s>Kýr½”úD¾t“Ô=|¶’¾˜ë™½Ä®ð¾(ø®: í>¯_>Èß’=+„¾ˆRš¾9þØ>Ù©¶>ð‡’¾… ½™“}¾™™+¼Ù‚ ½çyŸ½ò�¾WÛ:¾‘F¾EX†¼ý®Ê¾^ŒÈ>�ÚÖ>û G>¿¶‚=z@U¾Ê¾¾?ÆŸ;ïâP=¤¶ ¾…‹x¾ ”6¾m=½½ú¹‘¾ô¦¾%¢F½îß¾D„½=¶ï ½�½¼“>}V®=HPº>!fN>ÆÕ×è×­¾)³Ý<–ò>Eñ¾Û¾b;À>U }¼ˆ'¡¾ËÕ=äNÆ=7p¾=ÉÂõ½›7ó>¼¸y½àKì1ó�¾Žõ)=G=?x[Õ> i¾^‚]¾/�‰>.É">E#�½Èá¼E1¸>kÅF¾vG^¾èËa>l2D>#ö¿ûu×ÿÒÓ=À-™¾,0¢>°6> ¿•?Ž>휽°lA½�éF=¢€E¾Ké½{• ¾1 ?S®”½Ä'†¾dâɽ×`>æG¾kÕ‘>&]¾UǾŒÙ‹>à(¬=™É>Lã¹=Ÿ¥v>|ç`¾Ð1á¼Om=@ï-<¢ 2¾M±Æ½ÁÁÎ>ÅZÖ¾™zó½Ö‹> 3ù= ý<Ø{â¾_è >*L@½TËW½è;¾â¥ð<²¢ß=ö³®=³^¾¨k=…d¾„ >îá…¾Ðjm¾“—·>âoà>ÛÙ)=Bh½ˆŒ> "¦¾úàã¾ór3<ȇÕ=CÔ=�‡?F¥Q¾Ó@n>ÖK�='g?»Ô§½3[¼œ¾V¾‹.,¾aÅ$?bÈ‘¾ü^,¾´¥¡=ÅW¾®´`»>럽)9Ü>4¤;N‹¶=àý9&>ΰà;™•¼>ým¨=z„¾îü¾<[ ¦¾‡®@½Šw@¾…ÿ–=tC¾J-¯>Å!¼�D>ü+>j`˜¾V¾¥Û5¾^p"¾±NF=k@>qR7¼õg1>yM­=7)¥¾j¨=ðx×=‡L¼ŸÇ==Ád=D»…>ì`>Ý�¾ä<¼Ø*o>b·š=2K,>=3C>†>š=´?�¾�´ž¾½L¾ñ/�½ÕÐR=–[>s@=Mjf>Œ.¾¯ŠM¾¿þŒ¼kx5¾|Ò¢=[¥€>—̇¾5j¤>rrܽL±¿VT,>�öJ¼/>’]�="[>-þ‡ F=º½À½Z F>K]>Ø„*=»±V¾÷ à=+IÜ>§ϽÀò¢>ãŸM=yíO=[ƒ‹>oif¼j«>$ËX¾…z™=Û�€=>dB¾Vê@=„:’<×fϾÑÅB>ë¶½�Ý>£Ã=à韾Aa´½|ßB½M>ƒ>Èv¸¼Xv¾XÛ>Å[8=øÉK½U”§¾ý×½&Ÿ½ _>¾ÍŠ>îKǽ¦ÿ&¾NÒ¾=©ï¾«�=¸}ƒ=AÕ¾â:O¾P?ɽ_¿O ã=fYF¾Œ…¾4ñ½É3½Sk3¾à==t<<5u#¾#iˆ>~—ô½K”,>x˜�½Ú¤¿¾oU°=¯8à¾!Ï¡>þ}罸Ô=q\=ÆÍT½¹>‡~=½…M>áÀ�½H† ¾l ê½¯>z®ˆ<5 ×¾J¬¾Õ�¼èŒ>K½ÆdÉ=¸¥½!¦"¾ -—½B6>I°K¾­qp>ÁtÙ¼ü >©‰*¾ô™½Y6>*<^½•�¼CÓ<ç,½Î–­¼¹Þ½Ò±Â>ÎÑL¾O_†¾�Úë<®Ûã½’ØÛ>>î½!R:¼ÃÖ>z >l…Ó½g®º;}„>¿±Ã½¶¶×=ŽÃ—>s�•=ÕÓ‰¼'»+¾†Ÿ½sF>H—õ<âÖ(¾+9>;Ïž>PDt½1 ¼+€ê=&¾ÌQ¾Ë,×¼8¾$1¥¾KÏ:„/—<|@½w�Ì=Ðtà=Œk“=¥Ä¿M�½=ð¡>ÈCà½9ÕŒ>µ�0>³~ ¾EÒ½Òèb=ƒBŸ¾7Pò=ûd=/Ò½X¯…=,Â5½$ɦ½²Ìž=Ų­¼…`8>UÅð»@¼@><\t>ny5¾ÿ~ =_ ¾-Ù=[–G½~ñ9¾˜Dн¼0 ¾;Lç½àꄾÕæ½ì–8>©á9¹Vð¸>~î½5% >ÒP§¾F½A;h¾rÓå¾°Pž½V×>Ëæ©>žâ€=,8ó½˜di¾çß�¾2ûD<ˆœC¼êˆßU<Üå,¾1=ÿÙ»Ö”Ï=p4> ô >ç&”½­‡ö¼|4ð$Üø=ó¦u<`«‡<Özª½)‡ ¼…h¾ðþ‘=Ža=.8^½@¨=ŸZX>êáÉ=ËN½í.J=ßd:=Ò(¾µ ‚½W•=`Ø›=b©¨;}cm½àÕß½mì¾R5>p¬>=�þô¼[¾æÐ¹¾—PD>0CN=ƒË ?l° =™ÿ5>,öä=,Œ…½B¿½’’¯½|¸>äͱ½‚¾@�Q¾Îµ—>:4>u‘нÜWŸ¾@t¾q¿Ð=üÎb=X]¾xÍ>Ôvýj×½à²=š)¬½|ľ¡Ü¯½Ò6=¾'œØ>ˆ¾¥~¼Wm!=(ǽcV½ƒ.¾‰þ=Yp;FÍE¾�—Ú½ÒÚÆ¾,P½È†½H¾¾ø~¾`&Z¾EUʼ S5ºÝn#=Ç]§¼�ŒV> ìô;¸Š>À}�=4=3 &>Ìç¾¢Wd=±5¾�Ù >ˆ=q¾Ó->½u2½<=�uH½"BÙ=ƒ3®>m””¾¥6¾<¡‡=“"7>šZM>Œ”ѼåÈ>…¼—¾}s >IF<©n]>*Õ4>¦õÂ=°ľ"\&½¾cÍ>O¾vÂR>™`½cL>ÍÓ˜½Ýà½3Õq¼:!½ˆ >yŒ ¾0œ÷<]U>k~î½=¡À=gpû=×úœ»#˾^ i¾(I¾Ù"&¾¬<<¨�›¾Ü@½Zc€½ÜÙM>V®¡>èM,¾­ƒÀ½+˜=¢®¾ J}»X¤=­!c=ÏB=[;=ŸÕé<†gà=Ê C>Ö)–½¬Èô½=Ôa>0Ç8>:y3>^¿¾¼ï™œ½gƃ¼Þ‡E>Ùe¾í�>Tñí< •†¾ÀÚü¼®N‡>×ÐÜ=ÃÓÜ=Šc½A˜’¾^ s=dø¸¼oËz¾Áœå=fñä=ù£N>'T#>¤JÐ=GË=�¥!>fDؽLu.¾%}q½u€\¾Œ¦<¾Ì�¾*gõ<N>£3c½�v4< ¸ï=Nm¾O´}=»°M=øÏ<‘ξó)�½hv.=ÖC¯=¹hý>³…½Àgè=k¤k>g>>ip/>à…=ãe¾1”\>ª¢Ç½¶=Õµ<]éQ>«þ½sI‰¾Dw;>®~¾¡>rœ„¾‰½³H:öo¾u)‡¾|Qû=0˜�=Éè‡>ûOc½Ò˜Ï½ÜúÞ½ªaL=$¹M=‡¾L²½½9‡½Òš¼j >wŠ/¾‹GK¾œ9‚¾SÒƒ=«·>‚á½~˜¾´¾¼wÔ½’Bâ¼õ¨¶>.ó>Ÿ,=ä>¸½™à˼�»¼>�_>dk ¾¯+>zÔ5¾Gp¾`€¨½¯Ï­>],>ímÎ=@l¾B@"¾Âpe>z6¾8B>¿a‘>«‡œ½> Þ;@kó=͜ϾÂ\¾w½tx‰>Û[¾Å$þ½–pZ>å;c¾6ǽ;™Œ>u\]¼:Ç8>ëÃ\¾ØqŸ=Þ3>¯wz>ŒÃ½¸|„>+OS>¿Ý‰=Ô”á=»«�¾ÕÓ><ô8¾-pA>©è½¾á®?N7µ>Ëž¥ú¿³ n¾Ûg2?·ÿ¿2©j¾¸@/=‰<¾™`Ÿ>ß0=7_´=5•^>Šéü½ÄÒ½ŒŒ¾àßK>ªÉå<�̼2ÿ=Cç½Ôw¬½q—M¾?â>°&<Í _½í ¾ óø¼b‡½ã[Á½¡6—¼ÃÍZ=�ü=Bk<>04ó<¯–"¾}0B=øµÐ<æ6½_�>uE*>Ñ‚>f§t½âÄ,¿­ؾbj>o>cà¾mÈ >ô¾ÊZ?Ç<4ZÁ=]€y½‰.x=§L$>WÈk=asŽ>b~^¾Ù<@y=–Jؽ£‚¾ì ½m#>‰ Ü<�[>C‡=G Ò<±æ<Ú¶¾ª•‚;¿5œ>ö'¾‰u¾gؘ½J3è½r½¾‚#>„f;¾-v“>å œ>08>8y¾Ø9;=‚Ã⦅ ¾¡’ç½l퟽‘Ì=P˜°¾J3\>r˽…øÐ=\è~>"ù¼xú>Yèf>Ö¾Td!=©�¾{ǯ¼y°í<�Š,¾–�æ=‰³J¼œß«=@µ¾2M8¾É,>5•�>ù~=ˆMÃ<¹2+½Hõ€¾>„¾ÜX‹½Âq'>ÉX=ƒ漈A>5S>ÉL½Ø3ü=¡¾¼­#|=î%;>Bãð»ôœ=Ê8A=¢(²½3]T¾’µü½zPa>öȽò©É=A¡¯<<ûÿ½>ÖJ¾èʘ¾`͘¾†Ç¼-ñ+<Ãû�>ÝY’>!”>š·½Mx->¼™Ÿ½¢w0>>tÕ•¾y ‘=”ï¾ýœ…½8®½'¾˜>ñ5=×sü=P¬U>½r>íå–½(U>é@,>v=àö>O×ù=ÀÚ=¥´¾æ&"¾#(†>}@�=Ë[b;õ>U—8½¾Kq>M�¨¾úxÂ<„ùÒ½IÑû>Ç…º=w·=�V>ó­¬=Ñóa>\¿!¾q6½Ö»÷ÞK<ìؾœ(¿¾®›=ýHG>k™>Ö®l= ,¿Ÿ~»:wÂ$¾Ï})ž=máƒ=^w©½úO ¾8¦>º˜¢½Ú�œ>3Z¨¾MA>4kKºÔ—¾8Yn½‰=Ž>;Óg=×|´¼Ä)“>-ðQ>é ?ýq¾cë¸<µË=CÓ=xô%>›=uå”>�°>«t±¾…>ˆµ?=ý(,¾c¥q9úM½O_7>/÷Ô="¼†¾} 3¾ßÌ>Ž+­<Ã9}¾ˆã¾§Ús<,pC¾O?z>Γ§>«^›=S¬>}ì,<µÆƒ>Õ“ù=Ï–€¾*B5 ?…“M=#¤È¾¿#¿.ƒ9½sßÐ>jóO¾Ü]¾®o‚½œsоcœL¾Ø”R=ãå=ß·O>&¡¾½d¶½E¾ `I¾5ꈽ4¼iò=±ùå=—]1¾ãÒê¼×CŽ= ? >T¡¼Ÿëܽ@|â=qæM>LY=F7Œ¾øà1¾At¾I>']¾¯/>8Ç*>­_¾½³ >šã‚>6Tˆ¾T×>dT‡>¢!¨¾ÆÈ²¾»2½e¯Ø=Oo>ä�=44ɽùO£>�§> ªÃ=(Û¼ËÜa=$¾å;‹¶5¾ïÞw½eÌ >²ƒ¾'›>Õá�;êgZ>ˆä™=KÆÓ=ò›=µÛÅ>G>¾ü¯>‚;>¼i ¼¿�„=ÍäŒ>ÍøÄ>9ò�>RÄ=æ�Ç>îÒ¥½.]=é† ¾ ß³<6=dS¯¼£³Ô>hŽ¡>Igg>Š$=K.ª½Ìÿ¾üÍz<±p$¾ÅmË=›½£� >šá¡<>}‹<¦]p;nù–= ­m½š›�½Z3C>ySν¤†,½£ó¾”¶�¾‰Çƒ½ƒ%Ô=XåY>ê‰Ñ»Ü±¹=H|=õ7D¾Ã‘;o¾š;³Q"½~ =!„óº“n±<`U¨>¢Ò�½ÛËþ½áx%>ù>Ô!½Ô|½LQ>?9> ég¾A¾Ó=6j‰>@†Ì<ž¤>‹ÏS¾ãؽ¦Ú>—õ:¾ ì÷¼x‡>(  ¾¡ð¦¾D>:®[¾ƒ€¯¾@ø>>–g½Ç¹¿«¿ >ÑP¡¼bùÅ=ƒ~½jsu¾ówú=>íͽeN½”n=ì-=£¸$=çU5>Ʊè½FE>ó÷Z>Ë#޽éÏi¼_˜Û=Kb`=,˜?÷¼ß[>à’½)l«=`G�>,œ¾o†Á>Á>I½)%'>hÆ£=ÉBоp¡l¾`ûŽ>JÎ{>ÚU¤>…½Îö¸½CÙŠ>š8J=þ‡Ã¼y컽#˜¾å¼;ÑËo=v@¿¤F¾&u5>zò>™`O½Ó3k½†6¾¥ǽÑ�<ì¹>ô¿w=ÇWˆ>Êr9¾g¿G¾ÂMŽÀ�½ºŒ†>Æø£¼±u/=Ik�¾&±ä½°Ý¾©½¡+‡¾I”‡¾öÔ¼–-–¾›sG½jm­¾ÑP¾˜;>YK$>–2}=;�ù¼À¯>{,½Ð¸™¾:†�>Ú6û¼ô¾ôx°½êKÔ=tòn¾ÀÎï½~rF¾A˾÷�>S†.½¥I=Qä3¾¿ã¾4š(¾ •<>'å™=n=‰>Š<>°�¾IÉÌ>÷£1>QÖ¢<ŸæW>‘ÛJ¾n!~=M¼ð=h>q½¢b˜>-º*>ú� ½%š½Dü$¾vн ¾td.> Ý�>î`¾?ÐŽ¾ù=im:>fh¾ñ,>àáS½ì=F=i²> ŸÝ½< º½ã— >�Å>øG™=ûke½öà’¾6÷=)ºÃ½Ï¥1>ŒZ ¾n¾-­Ý>-~�¾¹W ¾A××½“ú=˜ ª¾:>Ó¾o¶F=Xެ½e@s=£f=ÒHT¾ñ›ºÐ‰0>Gvz¾#!„>Ê`/¾ÏýT�b�×=ØX½Õ„ݽ:éݾ�(¾š¾Åµ“½ªÈ¾¤si>ZÖ«=éj>>ÓÊž>tu>žk1¾$ô.>O†³¾ªǾі+>§f ¾n#„¼ú[>Åe>Ù‡¾:¾”k¾(Ãg>?Û?ÄN>¾PbÁ¾¢Æ�>xQJ<[9²>m>gÄžE>÷¾¢ñŒ¾¿ ¾8gͽM¾¬Dt¾0Ú?>½7ï<ú+þ=|ê<寧«Ô=¯">iä_¼<&§½ãõ¾û:>Òã½Øîл»N>1^l>|æ½{n6¾¹¦C=†·£>Î_ƒ¾÷jN>’S¾ÍwN>ù̾Ì*`¾úÅ=ÏÚ>l€:QÌ>:Ûg¾m)ľèD¼o-Q½ÎXF= ;ɽ8ƒÏ=ÊÙ¾œ�®>R>=lŽ>â¼�Ⱦ唾YLí=bd;=bá¾¾>zEdQ”½cÔ‹½c…›<]#Ö=¶~\¾' ´½»Î'¾]Š<ÑbA>oEˆ½�àÓ=Ž%>—õœ¾ÙˆV<<¨>ø@S>ŸrG>hÿ=Sr>®È¾8­�;÷àx>Shy=bÅO½¨íª½@9�>Š\V=Må?<;7w¾Õ¾6¾ žl=¼ž=à°6½³q�>åïŽ>+¾z>N†¾%�>¾*>¼j2»0Mp¼ð냾|̾5–¡¾ ú$¾Cn‚=âìs¾•ê=E(ؽúUá½äÒÕ>¬6‚<9Ü.=$Jg>3;o¾Û Ð<‡ä)>R¸=ܱ¾É%>è«T>û•M¾6ðä>à޹Ãñö=†#¾{ ¾ F´¼’mJ½SÑ}=‚¾d–'¾¶½'`u>nS¾ÿª?ùìà=øN%¾XR0½ˆË•>r_¼¥Œ¤½¬[½¤>©Ÿ€½›¿Ú=7ýW>ü1¾Y@�¾þD¡¾ÆTo¾ôv@=À¨¾ó@>x)8>ê²=ëØJ=Zòœ>½„>›>ò2­½›l@½QÄC>!Æ¿t >ŸÒ¿½¯Dö>õ¿�=Z’*=F0¿pß">Ï+ª>�$¿êw¾  ~=ð¢-¾­ˆà½¦Zˆ=Òf\=¥Aˆ>¾àÎ=s"ʽ^{¼¼Ä8]=ѧ+>¬<лy®¾æÙ·=•µ˜<ž¡s½è„e>ñ£/¾b˜—½Nãµ½W¼ð¾® o>ì>še¾«�¥<ü(̽Ë[`>$Û9¾[ºQ=‘–à»`N=�FÞ t#>ªw2>F"¾¸]¹¾8£¿¾mY¾ñˆ>“‚¾R ê=œ¼>öàY>2è2>ýª°=®C¾ÙØÊ½Rz°>ÑŽ>,–>=…Ò¾½åß¼ïÀ½7w>EQ¾¤C^¾„°†½Ð^â½M¬’>Ï‘ÿ¼Ø€½÷°…¾³èϾ%>Ù=“4ˆ>ƒþè½Û,+½*˜È¾¾¾ÇnÌ=`>ƒD¡¾G�;=Lîí=P Ï¼Ø�F=ÅÏ>±|¾¨ì�½Ã‰¡½�ßC=“½yÒ:¾õÞÛ>¦.¾¾[Öw¾�•¥n¼HhÖ=éŽT>�_½tÌœ¾_l:=SÉûôã=Ö …¼Qé\=éø=Ï+¶½i‰ >à�¿ÆR½«½Â=ž?–¾�hìÝA�:â7ù¼™0?wº·>âŠó½J_‰>—)¿x—ò¾¤Jo½Ñn>‹>ƒÝ_>[!¾9u;¾2P‡=mw½T/�>Ѹ=*3¿¸=ô½©$t> Z5¼i €¾+E[=Jíq=&é9¾Çƒ¯» @¯¸"ã½ è¡=¶ìú>˜«>šAt=àó‘½VŸˆ¾‰R#½ëþÞ>Σ¾»îGú=tϽb0’¼ÿ6€½J¶5>»p5>ùÈd>TÕj>Âsƒ>àÿϾ~�=õv=¶‘T>Ÿ‘½/¼´¾8>BÚ�>õG¾²H‹¾Ü¾j§½•�>‘šè½sI>þÌ©=JÆZ½C¢¼<^/„¾&]C>Rû¾Xëó½-¸®½mD¶¾â}W<:h@=’-罸×½�mr=ÑXÀ=ëö×¾òL?¸’=s°z½<ÝS>Iû½LŒµ>TЪº+žq>Í^ˆ¾ê±j¼/•>Æå½TëÊ>3c>çrν¢ž˜¾Ùuœ½™\¢½0=†=¿…>Å-ž½¨7˜¾< Ú½ 4È>;95>(o©>àïz={öé¼a‘�¾Py¦>cáj¾½�=š¼ù½ªyöºw9­ÜV½g°\>­‚¿• ‰¾3T= DƼ¥Æ†=ÃÇ”ÿ>iJò> rí<Ù)>¼ûØo¾OS=Î埾 ^>ä�’><?=eW‰¾Y¿œj�>+žU>ok%¿›Èн!Š> ¾Ó¼½p"¾²‰¹=tq1>ímÆ=0d!>„=™½–© ½˜€°=ô§3>oiˆ½O;¾jà^=ÿË>} ½®·4=Ž„=„P½»()ç<œä-=Oôº=N¶­¾SÐø½ñÝ=.¿>öÜ®>q–=Y2.=ÖÚÕ=é[¼"Ÿ&¼¡3„>+Zž=ÖçŠ>¤1 ;^Ñ¿Û�ø¾Zé ¾6Ö >Ô”-¾j‚¼4òq>~“Œ>“ª‘>…æš=B©¶=]&g¾li…> ì ½û£>Êív¾V˜P¾{©¤½ƒdå=‰H >íÍ£½óOÚ=é¡r¾i¢¨>­#Û<¯)ͼ]Ï�¾ã$Ù¼ßþä;•2g»°ï‡>Üæ»=&iž,>ßÀ>˜õ”<á.y¾u±£=VO½ôÒ‡>Ÿ°Ï>õk>7Ç­<�›Œ¼û9]¾-c‰>”ÍN½š[ü½ñ�*>7ɾaÉÙ=VÂÔ½¢‘½µ·š>¹6>ÃØ}>B3=J×ø½€Ê=’H¾[Ò�=FDô¾!©î¹äZÔ¼þµª=ý?Ì<*"í<õ'±¾@^½ÿ„¿VÐ@¼,¾¾¿�?=vÔ˼¢5E>·5D>©�§>Íá=BãÍ>dt™=¸$Ô=¡ôÝ=Ͼ›�³¾ ¿•¾->ZÎ>œo¾ÿ—о’Ö¾ÉoØ>1ó¾6Ãû¼ã Õ=3Í{¾?Êë½] …>›>‚m>9*¾ô=? =¾‘Ë‹<× ]>Ký½);¨¾S‹>hB=‚">E½í> ìñ<�(3¾òÇö<*;!>”¼†>•1>?æ#>m>í=99V¼ ½˜ê྅«?=~¾Ù?dÞB?/�¿„’¾µù=å¼Ù½èZü¼¬jR>mÿ¡=’‡Ì½hi¤¾Îí½æWë¾w;¢>sIÁ>©t˽£Â ½]V’>°å>jÒ‰>]R²¾«@:=Ö~T=tÉ�¼Õ=¿ —¾¦cƒ<ƒ&>ö¯3>n�v¼»½`“½#4=Ú1™>ãùÄ¢ï¾C=€¾iá¾FÏ>çô/¾ü ’>a{f½”LG=̤¾»q³>e)>EÚ¾´Õ3¾>•¾D£¬¾±H<¾2äÍ=Õ1>‹ÓP>èç8{¯;á%º½þ9¹¾­—¾{+ ?­×2¾¿êd¾Àû>åQ}>qO¾jK¾äÙ�>PÕ®½¡4´>3rž=£ÿ¼JÒÈ=é¶¿D%¾={ å=Ƥõºa±>]ÏY¾LÀv½B ½b?ªè½£¨Y¾1/$¾êŠÇ<¢¥¼ ž¥>Ä{ß=ÄÝ!>~žZ¾“9¼>ž—Å<¢½t½Ž±> ÆB>ñkx¾û�¾‰¤=�ça>%c©<ãº>“]½‡E=Eœµ=—Òµ>‚i¼�qœ>y¥…>ˆUÖ:®â„½ÛÓD¾ÞÔf½«õ=ßî ½Ô >DÑU>¡4¾2ß·¾Ä�É=K>:>Nöš¾Éƒ>†Nù>ºÔ?>§þª½û# ¾÷¥Q>¨^O¾ð8¾_/ؾ³Ã„½ÆÔW½ë0ɽø•9>)ßc=Q]–=‹¢ì>ýçn¾âR½œÀ®=ú¾’>Atå¾6оTÎ(¿þÇê¼,0>ò$¾…õ1¾Ý¾í�œ<ßî¾1wS¾§å/>*@Ú>ù”…>Ÿù‰¾ÞÎj¾¦Ê½WF=>ÔîO½»$…½®�ò;´V‘¾ÒH¤¾’>Í™š>%ËC¾t2¼­€<èÑ>½—r>#>xǾîZ]¾ŸƒX>òøå<íó�=¹_Å=[}¡=5÷¾ËìZ>ñ ’¾„!ç=¸7±>.k2¾?ªÙ»^}Ë=<Ê(=š >ÛSÌ=°±¤<�K¹=a<Õ¾Çú&><¨F½M•³½…Q|>Ü o¾ '¼u²½¾.4„½EÙL¾EX>¼>,†½ÿ%*½&‚þèñ>>2Á¤½€i<µ²¾;®Y–=-F‰¾ÐsK¾ÍަM#¾&ð ¾tq}¾³?×½’é•> ÷ >´€<ãú˜¼¬³¾A`¾¨ý>”a�¾~ý×;/ÜH;+Ûì=\3k¾_9\½˜‹¾½¾T">wH<ÕcƼkH5=Ó7³>¥Q=´1ø=©Y¯JL¾6ÑϾò>Ô®¿ó;¤:Cl>�Þ>ïn=”>ôÏ1½#K?`S¾0ʼ&8>üؾ ×W>‚‡V=ëš�>€X¸=zß=ز2¾åá¾.ö ?%¸ž=¢¥Ó½°™™>™Ž=Ð[Á>–£Ú½PZò¼?‹¼õÅ›½ bB¾å÷‹½AŸm¾¤{¾ ò3=…(¾l‡ê½üÚ)>p®S½EÉ/¾kÚ>—= >¨ ¼À>t/¾€&Ô½G¾º?h>“X°¾(zç={Œ‘;«P±>­�¬>: š=YÔн„8\¾hm¾|±À½‡´º½"s­·1ž>^xì=s«= Ï©½€´À¾ ó²¾ä³Ž>±{=/†O=0Úk>= ÿ=�qÂ= &½6”T>袒=j D¾ ¹f¾kv¾ÙÚ9‡�“¾ð®m>°u>×:û>xƒI¾³e¡î½ i0½[MÁ=&MJ¾€>‰Hñ¾þdœ¾ „W¾ \Ž>–˜¡½ø¢¡½šR…¾¯Æ’>��>M3–¾,�>ŒÒ½DV>È+|<ݦ=ܧ=ÜGï;ë­=zD›½½k¾™¥¨=í—†=Î$½2áQ¾Xæ+>v>WÛ>k#>kC­½ih«=Y¥†¾#÷¸¾Î÷V>Ö½œ7�¾ûç'½“`Œ½Œ«�¼BgC>:ì=“ö=>®O=|¬º=*>쎽oB¾Q¿R¾3¥h¾]­Å=kT¹½$ž>Ý:>í+@=HåÈ>³"¦¼[E×½2éÕ=^̳¼l‹¾ñØ€=úØD¾o»M>Ï¡:Zu>Aå ¾Î�¾´ùu¾÷á�¾mWk½/O7¾¼È�>ÐÏë½ éÞ=B©¾Ï¾a-�½¬ê½ú¶J>ˆÁX¾Ý ¾ƒ‘³½Â¹ò=ßaY>a¾‹’‚¾ ÄS=E«U> d´¼$Šƒ>,µž½¶«�¾m�¾¾‚ï'>ƒ›6¾û—¾‚¸}>4¡#¾14›½“4ó=Å4J<¢�ã=hi=œJ=›�¾‘d¶»Õ�=N ñ=v8P¾Íݾ´/Ü=%ê>ŠÖí=»œ²=­5=È  ¾ý«ò½>Þ+¾-�¦½‚Ý%¾–«½ÞéB>fU>XÇ«=ÖBï¼�y‡=õ5¿<*ç„>€óŠ>ÿN¾Ég+¾Ü©š=N)>³–Æ=œBнד„>ö ñ=G@U>“·‚½$*¾8䓽)^ï½qq½(>µ=ˆý†>X²=wV(>t)¸>©µÛ<(B—=|3 >ÅHq¾a{B=�P3>¼Ý™=QŸu¾ù;L½KæÞ=Tk¡>U{ä=¦´½ÞÃ=%G>.’C= Òw¾óÿ‡½¾A�¾í Å=žÓ/;ÈŽ°½b á½:e°8»›Î¾Í⃾4Õˆev›>?„Ⱦ‡¦Ñ½lôç=Ì›–¹; ¦=ç†>tFÜ>&Ï!>èf">»|Š>Áòÿ¼´=‰ŽË½ÖZx>×Ða½­#…<Åj9>Ùþ"Ô=ñh�¾ŽA@½úŒD<ÌŤ>ój&> ÍS=ÒĽÔÁÄ="³¬=¸Çº=ÁYð½~�¾òM%¾ˆú½š5 =qmR½C„@=RÒ軫¸á¼XTG>ËÝÄ>'Aò<Šàa½  ¾)5>bÅ>2Yj<#ËϽÕ½=ÂèÛ>ð">ýV6¾zß ½Ïï¼§€Œ k=i;¡FÑ<“ »%n¾|—¶<|�¢>suK=•·à½?À�=£÷Š>ÇÂ9=šdü=f0ô½etò;"n5¾˜PȽüö¾YD$>νUO'¾(ü†¾êiô¼•:>÷H�=G¯Â½gu½\5€½ÜëÅ=U‹j=öØ6=ñKi=<·Ü½�6Ý=êL*<éwß<5ÉŒ>ui=/l8>JŽ]=qûN>4ip>GÔ¨¼› �½ãšÝ¼4(®¾#ÈŸ½W2>E[Ä>au¨½¶7>ë\R¼ðŠK¾�Œ9=QV¾\(>QÓ[¾4qà<¢¬½‚%Ê<È•½ô±I>h`½7à'¾#7…¾[�½©Ž¿º5*¾ñÔM½Å/|>1sF=ç¿L>ªÓ=¼´0о?¬<ì$=öŒ½Öðo=;B >€$¾ÿ»Ù½_ܽ£þ=[­Â½*õ½¾c2‚>~}>̧콱§ª=õüǽÛ{Š=·í>=(F“½È,ª¾X?ô½®bµ¾Ð±¬¾Ó𧾿`x>Uý{‹Z= f�=Óe3>,ßð½†TÖ»{ÛY¾�4>‘§”¼Õ¬¾ÚP¤<üƒa¾>µ½í˜�>Â1,=‚Ÿ]>ú¢<{=:¦P=k5¾SIž=Xò¢=®Ù·¾2�u>¸À˜=e¹{¾"ð=¾óø%¾r¤F>A-D= �>¦z:>ª´½<€7>Ÿº;{q¼3¬ç½ ü ½i)>îÅ>!p¹=Š{‚>þê½·¨‡=¯Å=˜‰Ð¾‘Bõ½ÎK›>Ç·¤¾¡6?cat<›#>2vN¾jl=Êb>ä>†M•>ÿ×y¼C¥ ½L ½&!‰¾Ú[¾$ùa>ÖÏ=4� ¾¾Ü�=ù#@¾,œ>S,ὓà�½ŠŒ²¾o ]=ÖÜ;Sù;fû¼#¤¯½B�>f~=·7þ;¢C¼zz¸½Ó‡¨>Ñg…=1€¾-ZÒ: ,ê¾[±3¾¡ÎŽ>4OؽJkß<б+½ÔÎLÏ<S@¼ÎÛ>½·;¾ AÁ=u„>¯h¾÷�V>ü,C¾è¡ê=à Ã<�·è<$=>O�½VU½ÚÆ&½@²b¾Nøn>å&¾ñiÜ<­„½H$=¦§“=óÛ×>�ü¾¼N>@!�¼¢ ª=n‘•>!J:¾w¦= ¾L¾à„¾´��¼«0f½3ùÖDi¾eyN>u{=d ¾²¯>ö½Z̳>ÞI¯>–1M>§M…¾�Tº=~¬¨>ž›>�©Ç½W˜=!>pÉA>ÑQ$¾Jü=gª”½r>)Ô·=÷ >¡Sƒ=MÁ#¾”ƒÐ½›Õ¤½[6¿=¤N¥>È2�½¿%½·¡=MFR>b†J>7T"¼#äø>Ýþ½1¸¾�·Y¼o[�>–v='ß½úi¬=}�¹;ŠD»>ïl[¾ÉÉ%=™Q(>¡@·=êÌ=¾/ˆ¼Ôž‘>Ì~û=Ýš~¾.›=�Gm½µ1³½ÞêŒ9[(¾ƒîi;´^½hH_>u¿ù½ŽN> Žƒ=êT½„ûü½bª>7Øå;ÀÊÅ> CÎ<=Ùp>›F6>PĽTž;>³ìH¾“‰g¾÷»‚¾Ÿ23½ƒ÷À=À5=uwX=葾ÔÙ¦=­‹™½„šÇ<Ê…i½Ïù½d¾Wª½zæÄ<·>d“=t÷{¾%í©¼ÈÅR>+äK¼Ñ…WºÌ…ç½WÛ½¦,¾Hõ¾AÞǾ}Æ7>é¶“½ðË㾇>,�ª¾¹F½ÖšÑ¼{tÄ=­œ¡¾¦A2=ɾR>¬Õ8¾©õ »(Ù¥¾=¢`¾ùA¾]L¿#]’½l–µ½¦vÚ½ÿË;>àŠ÷½C­’¾À »F¾ðs[=Î[‚¾�!½vËÙD¾«Œ�>o�j>n5L>þµN¼Wx,=÷ž¾ªV=f¾ý×­=O ‰¾ü|ó»¿ß=dP‹=%Âa¾ùS­¾Tü=å�œ¼w(¾—ˆ>@¤÷=þ5~>ôM¾=¼�ˆ±½iì=yy꽪x3>Ó!µ;q¾­¨G¾öX#¼$‘¾&]¾äÓ‘¾ÉÓ¾7â³½-I™>ݺZ=ËÈ`½Ñîë=ÃÜž>B~>±¤Ë>®ï¼1ჼ«¬Ë½,vÓ¼¡Çk¾ŠR™½ÜGø½È<¼k™=ãEÕ= '®½*Þð¼ù %½ùñH>°í�¾´j_¾½¯'=˜=>˯5½ØgÞ=K£˜>ÑË>4�b¾ƒ0„¾ R=ð«v>[(<t¾„ÒM=| õ¾¿ r¾U)>£;>Âþľ“Þ¾¬ä¾åSº½gjo<û¯,»ÉÐ>A¼ö=0ÍÀ=¹¨ ¾½ƒ½Æ 3¾sYJ½0ý!>,µ>}ûK½Yƒ >ZÙô=N¥½ æ<¾(½2¾à§>˜YG¾—׃=8*“>�çb¾ú”²½ÆI<S¼o¡3¾)Ü>#‰„½ñ >,©Í¼¸î¼�Խ㵗=Õì„>RIH=Jõ =9y•¾wâ¾Èÿ@¾]D¼¡‰õ½ÄÕ>Ï»ð½[G=j¢=ù“M>kŠ>½ÆÁ=8#=z±¿=5 5>V>ÓR[¾–(^b>\>Y¾�l>)™>ÐÁô=2Y¢¾¾÷V<Ÿwã½vÅ©¾Œ£)>}Ž%=< Ã>Ò(¾Ä3C=!2²» EŸ>þ  >bˆe¾±A>¿* ¿©üª=Öä1¾�GW½†øg=[ ü<Ÿ ‹<'̰½”Þ=à¶½ÉQ>SZs=hD¾y ¯=WU�¾MPÆ=ÿ!œ¾Uø½ìÞ゚a/¾@t>z�À½?)%¼³¾Râ®>”M=R¾:¾2nRMAƒ=B’ˆ>Xp>´ÿ3>Ë>l$>¦í@=,>üá8>¹í>3ÞŒ>ß„(¾šõª=ãü¾”Ø>ø.=ÆÞ=CÝ;>K–½=Ä+¾(Ñ=jG½n2L:»ù¼ðëÑ=-�<ªé\¼ð从½¾Ü(Ü>Ã�‰¾¸ ϽlP6¾ x½³º½úî6>:­—>¡el¾�ˆ·<âé°=‹Ú�¾X'®<©Ú̽6´¤>ü½�Ò=H……>Qa�>ÿÓP>²¾4½44¥¼Ñ|˜¼@ª=ÄÏ?ÇÜn>áde=D´8½½ƒõ½´;ä¾Ê¸Ç¼“‹½Š_[>°�¾}ÉP>Ÿg9> +}¾ù×À=ç>þê*�½x|=.B¾ ÖÛ¾gãË>s»‹¾ ]h>¤öp=ÑK™¾®é=½¬ñ‚>²¼o=Y]½# ¾Œ^Š>žö�½/½wW">ËíI½ÈÖë=¾=Î>Ù^b½âŽ->*#Ä>¦âà=“­¼½ƒh ¾{7t½MgM¼¢U&¾Íqt>¤vK¾i™í½¿B¡>”d+¾ãt½Ó)*½�ŠB>Så">ˆ7Žî«ä¾§E�½S>©ˆŽ>ë[Ê=Û³Œ>Ú˜Þ¼)Á>rEÞ½î1 ½†â-¾Cµ¾”‹u½{Ó=ëå=�¥>d ¾kÎ¥>V>Ä� ¾(zÓ¼Ç0Œ½Zu²><>“~T>ˆˆÖ¾o=†RĽaé>|é:;”A¾o±º>ñ¾_>^³>¶�~½×°I½¬êµ¾’ƶ»kC½Y‘½ŒÞ¼Uμ!ji¾Ns ¿­µS¾¨ž®½·ˆ¼$GR= k–>õk&>|Ý|¾»†=*±‰:ýi“=ÚG‹=µ>éÙ>„N> Ço>¾¸>jîT> ×4>–º“½Ï—7>sD>͘Ç=¤ Í>¿®B<”˜Õ½cÖϽފ|>�ïN¾{Ðw>?Y½»$Ó¼_Å‹½ù*—=^m>›€u¾¯a¾*õÏ=Îä-<}Ò×=%/¦<Š‹Ò=h¹-=›ÞA½p¾âNÀ>Ô}Á>oáÎ= ˆ€¾-Zœ¾°v>M�¾ZˆJ>µRT½Báé¾AŸ”>.>>=£’» J¨»$¡.=®g>qÑ¿�9¸¼í¾š­�½Dd|=ˆðܼ1þµ>θe>º|½t.–>��²> *½>2嫾û}³>XÖi=€iL»ë»B¾En©½å@=b�нØ�¾ Àý  >™Ô\>S/'>zÁ¿=¥â;¾‘᩾ˆÔo½—{5¾ðÜ�¼N3¾>ñK>¾nx>¤ò¿=hã=£É¾7!:>¸œF>7Y¼3áo½“³ >#œj>89]>(nË=@VÌ>¸¸³¼v‘𾉵�>ÌCľd ¾Ñö#¾(>¬Á¾lò‹¾ÄB¾Mt¾[J§½¹Ñð;T ¾Mh”¾zûù½ü¶ª¾ b¹=â¿®¾‰ê³>X8>'Ñé½µ`=>a±=Ÿ>=b_†½ÞWw>¤@Â=ñd=¾Ý;¾X¾ØG>2ú<³¨c>¯±ë½°xº>ÔÁ]>ÔŸA¾ðÒ>ã�%>ÆG> ñu>‚Ò„¼1s>W˜’>tUd½ìûR¾ói¼rKè½A;a>_&ĽòFJ>ö .>AξrŸ¾”û6¾Çof>Ä>ؽ«K¾œPZ>¬Õ½‹Ec©Ð¾(bU¾ V·½œr�>4>½¯v> Â =ÑJ6=–•A>X;è=`Xæ=ø>Âm¾!“x>YÏ=<û€¾–!2=½Õ¾ZÖ´>,!¾òÞL½ç»[½ßÉ;Np&>W@¾t7-¾€¾ðè‰>o-3¾1|õ=ÞÍZ¾{Ò^½h\Ò>Óc=¾âò>É£ž¾Ç B½>–¼U„’=¿ >=Íÿª½¼—ò¼Q¥½qñ³=i3:>„@½ÜÄ“=jȶ½ëª==ê_>Þ>Ð�t½f =b¾ÔlE¾<…(>¨Ë ¾nRe¾/‰>¬—Ë=?ÿ²¾õ ¼=Ôâq¾ÝB„>Ù@ä¾TG>²ÓŸ>ÜT>%Ň>ˉ–<÷?ó¾«n½ƒÛ8>Ë1«¾òÉ‚¾â³Á½züp¾—ÆŽ>zG«½ÏÂ)¾Öª½’È)>ç¨Ü=)lS>1È¿'K™;æf´=7 …=©|¼1«¾àcN>ZÕ>¼µ>-Ï]¼ø m¾ïõ>ÌŽ¥¾-’W>tÇ¡=TÁp=VOQ¼SXñºe0‚¾‘á½äï"=mô¦> U>½t'R>¯Ê¾>CÙ¡½{.½yÔå¼Â£z¼ ú½´¾J½…M¾Æ[«½p»¼2·§=TN2½ ê£>@æ9¾AW¾Ð˜Z¾éJ¾<°¼Bʾ§›W¾ 7™½]¨¯> Àš¾oß>䆛¾0ˆ½�~=Ƥ>@SL=Ìi¢=ÚüK>vPN>&2¢¾„¿>@*5¾¥½Ý >™Ù�=]7>:÷½;ØZ½21>­"‹=gü¤=¤Ü>{>n°>>Ñÿ½ÿÃk>˜-x>nœ£½ó߆<êA½úô=úo;¼£!z> X�>Š3_¼Hxξ¯Â±¾6 ¾¯6(¾UJ!¾U?޽˜¬)=´î;– º½P—’½l¢,>�òY>Iã>Þr¡>Ú=r½éÏ…½C¹‰½ì¦c¾~zô>ùs=þñ>â>À<àžž¾7Ýž½ºü>~lß>½TÔ½*¾�m²¾E¤;>å¾bô3½Ý4u½Z ¾À*¢¾Ë)Ó¼i™ó<W�=sDK>û ½lL >IXã>&�¤¾WÕ?°ù<<ͼ!¾&>Û‹¾•f½14¾ hF>ø‚c>:u"<Çð7UÕ;=8`;¥�>ÈtŽ>;)ý£ï"¾.Ⱦ¶¼�> ê=uш¾,@º¾D®«½¹±^¼\¾ôÍ:Z^D>Ov…½Øí“<º#¾¼Õ$—¾Òßš¾¯H>*Žø½¾=ÎYš>¸ç›=�-f>¤é-<™vm½y·|½‡^C>ö<&¾¹Q³=aò?½À­›½í'©½€|>#•Û>a§›=á½Øn–¾º×#>À•>¸Q¾;8=>k?>`¾âŽC½fƒ>ãf“¾jtû½HNß;³r=‡°i> ø¾¾]‡¾®LÒ½/믾‰[¥¾Ûî}w0¾9¿„¾Ó|®¾ïŒM>k3>‹w¶»1A>¼Ó¼ÜË>òs¢>kà >ÿ–=¨Ù­=!M¾ÔPã>Ú½«[0½ðÛ=8p…>.ÛÄ;Suy¾‰¾’€†¾|¾�>>Lܽ¿ö$=$f�>ÿ;\>Cm¾:¦‘½¡À¾YN­;–=cJi¾b«&¾Ü}¾Y˜¾Ù—•>Ë«¾ƒ[‚»8ˆÖ½SºŠ=‡é¸>_Ï>E,<ÅÞ¾§©Ã>:M8¾* >¾¾Î¤=�é@>£+*¾ �A> s;>³}4¼Ùž$¾™Ý ¾ÉG\¾$о¶µ™½b'.>›H½¯.W¾ˆ1;Ks˽çö>¾Òx!> û‰>´øÒ=#Âæ>®+оä�Ò½õbô½m£¾MZ½«Ð9½üµ#>£ò½MzÍ=ð྽KÑ(½XùH>TN½U)>…¤½j˜Û<�+z¾4×ý¾Êû»öÅ‚¾äÍ‚=ÅH—=G±¢=ÖË=3½ê<†Y‰¾@‰=æG¡») >27W=<¾1>Q·Ç>2`Y>ß]A:2eb>ú5¾«Ò)¼9,#>>¾;ñý½hò&¾‘6î=ËP~¾çÇ\<ñÉŠ¼ÊÞ¡½[Þ&>�c�=œx>¿ożWŒ?_æ;>£Í¾úˆâ+>¾–ò½XÉù½«3>­Ï1¼­QÔ½ Ì­¾7Ÿ2¾ÜŠ‘¾ñ·×º¦ó¾Kps¾Ù(<_ºÜ¯=³U>ƒRµ>Ê—<ñkš½;辟¥=r’?Ì(ú<ôª=Œ±Ê¾œ7¾=6â‡>æ(0>@Ó®¾ÿÉ.¿Š ¾&Û=.-©½ÆÒ¾Œ-=±ÄM>jû•¾qD¿yd=|ý¸}å½³ ê=Pï#?LJ>ÝB¾1î>tL¾’*»>Í:½=éè=¤Ãß¾©à½ñ5 >^¡L>G0Š=vfå¾!˜¡¼-o >­Y¼1̾°™�>R ?]+j¾�À >显VŸ”=Ÿ9…>µç/¿Ôdͽ»ôÔRH-¾ÚvY>a©�>jv>_?•¾ÉVľF¨¤¾ˆ’9=,”‚½àüß½0ï½j�K=BÔ¾xe™¾µ$$¾Êž¾ b> ž;¾9ú*½Ålð=ýã=©�q¼'©ˆ=ù³»Ö‘¥>V4}>\wY½µÐ]½ÊS>à´³¾Mï5>ð„¶>ûi>8•=„i™½\ꣾÀža=QL‹>!ÁS¾Nò«>�Ä>è>A¾Ã÷ ¼Óf>].þ½¯K\½ï•Q¾!”G¾ðª_=uD¾�ÞվಾDµã=Ëù<º½¢¾¸x�¾ 6‹>S\7¾GÚÜ=3Óf=Êê÷=ÁÆÌ>Ûn>ñ­·½Oõ½Bˆ>¹îú=²qw¾»f/½ùMŽ>÷W½ �¹½ ³h>\¾·3�½1\P½–_»½¦�È<ø ’=1›Ù>MR¾¾QÞ>£–t¾Pß÷=-{H>�>½3ZB½ ‡¨=¬†>³=e[>¢i ¾è(>ßK‚>î6†>â—¾w­°½PÚv¾ˆìe¾œb+¾?ûü<ž+²½äÓp¾¾Ÿ,=šàA»WÞ]=☰=¾œ{½lNÆ=XKç½o ?ȧ…½¤3É=Ô¿¾›H>z÷Œ>§¹½šÜ=¶WÚ>QŒ ?/G’>‡!Å>Œ =’O‰= ·N¾…³`¾8=¾o)¾�;g<"¢ ½ñ+†<+ši>¨\â>;›7¾V€>ÿ[ò>J?å(¾“Ψ=°µO;é[�¾_s1¾jú½V¿±H¾å;į¾\:¾!ÚѾþªŽ½7‘i>4!>ã Ž>¼Üν¯îô=séi¾ˆw‚>)~õ=`«>XΓ¾¡ø=öÞ½ `¾±>‹½Ù ‘>QU¹=Z¢Š½TŬ=û�B>ãxµ>¬q8>Cƃ=�]Ì<{„>ð‡Æ; 軽âœ"¾!æY<š÷[¾²Â< âp¾ tÍ<5Ú¿¯›ï¾µ2>Íb½ —c=µÂ¾X†¿½ïp™¾y$#>¶‘¾`a>þü«¾Ê0E¾Æ9Á½'«G>¸jŠ> 1²= È€>Lš¶= xÜ>éϾD¨_>Q;>¨«=MŒ¾µ*P¾gÈ ½r°>·ñ¾ö°=÷Ev¾œ羡{¨¾„2š>•ö»¾l¸~Ó>´¶=´ž½0—= ê¾Ç½¦½¦>²_‹=î&%>½s´¾¥ð°> Ñ=¿¨G=Õà>=¸±¾½pŸ>vMc¾É8? *?>¬ j>,a?·Tø=à·ˆ½0ÅÏ> (D>(@©>Ö§#¿èO<>羋 |;n@‘>ZÓ0¾d ?87¾’m0>@¿}¾ÊƾzM8>ÉÔ>M•³½Žf>|÷”½}GZ¾„�>èÉI=W18¾øõ=fu]=©^¾ÒU½©÷•>�``>²Ó?>¢Âu=Úž@[?ç¯ù½°ãA>QXÿ½öY>–0>ÿ’=¾‘€�>¾ãË>ŒO?$¬�>Rš$¿K]£¾ºxG¾$ãܽiB§¾†?>¼Ø¡¾‘A=p�>ë„=ha¾“K >b¡™>· ‘>»*=Íë×<�•…¾v6q<‹žEd¾et¾k°>Õ¥™½ì7<‚¾‰R>¢.\¼ýn¨½4ig<îæ¾ÍÊy>óÝ+>аּª°&<ÚÔÎ;VçϾbû<>öÛ`=÷€J¾˜82>á�¦=܆¾¾X¶>7c€¾ÆÎÜ>¥ª¾öVë=eã¼²Q‘= Üå=¥£=üy¾ ¾�ãÞ»¹Ér¾�d“½î¸’¼4k­=aËN>1>öÜi¾®³Á=Úld>Œøi>&öa½÷Nï<Î9;:¹õ‰½™‡>’s>ïµÇ=2] ½þªÊ½Ø×Ê< SM½X¤>‰Üν:~å½ O�¾ óª<„¾Ž> ‡J=3h½,“µ½ËÛ§½@Ä=c5»KËl> ­ï=ÌÛ�½g®¯>lo„»ñþ½Ú᜽ðkì¼yfá¼ý™¾&c¸;¨!Ð>¤v>5¾Ô½×y>Ø™E>-½­ˆ> 'i¾pá+¾7ìQ¾Ô¼œ¾ûp†>êKÎ=ÙîY={0È>†t�¾’½þz=Äñ<<˸/>A‹æ½‹ >�àa>L®Á=ú¶½é_>Œ ¾½X>(ö9¾¬o¯¾Úïš<ŒÅh>@·¾äÓ=Ÿû©=f”ñ½MUö=8+3>²»>ƒˆµ¾ô{>?kk>°ç ½'aÝ>«ø­½ƒß‡¾A†Ï½‰ˆÇ½ìUÿ=8Ày¾`«>ªÕ¸†wÁ½=@ã¾—ô·¾½n«½ƒP)¾K =Œ±¼Wòñ=zõi<žÁ9¾V±Œ%l>nš-=û×»>&T¡>gÏD¾¥·=„?^=®øE?Á÷”½Þ�ÿ<…̾CÁ˾‰á=å¤A>iŒö>㉌»\¬=g¤h¾–y> áZ=ó�ì=!d3> ^>rE>„ j¾á3±8Õ…„=`û^=>W½¸“\>)äb;“›X¾EO(¼-¬ =Ýúž»ƒ@€¾ k†=ÒÙŒ¾[Èà>:W•½Å'©=¢gš>•r̼æྺÖ<Š3W=J¬¹=5¬‚¾Ø]æ=Î>7·{>ÊŒ>|¾ø=„˜^>£L–¾mJâ¼´³=ªôÿ=�}¾˜@%½òK>tÌ-¾_‘4=«áŒ="]ƾâT¼�‘Æ=™>Ô®>ªÖ\>³Z]½{H†>„Rž®ìŒ¾#¾âÐ�>›ñû½.¾˜t>ÆC‚>¤™½\ï—<Ži2¾h™¬>uÓ"¾}ã =z6¾m¯_>±çð½ËaR¾>^°>¼Žµ>*8ì> Yç<—^¿r€i¼ì}¡<»˜ ¾» >n¾°>Q‰=ð™õ¹&KV>sÿ´¾²«¶˜Š‹wR%¾qÔÉ>\³6>¬òæ=S`>©'ñ½x¿ÛšÕ=“¯¼¥ûU½#A =å R¾ƒ\综�e<–!:• -¾Kb„=j¡»äô”>¹Ì½q“ ¾ÕWȾP-Ž>¦Q¾}«x½Š¨r¾õó=Ó[=¸¾0ŸL>…é >e­ >ú¼ãÑš½u£¾¹[¶<{nH>Š¢½Ô‡>‡ùd¾yêH>‚ã<¾Ö¢ì=Úå¨=qÒ= ~è=ª¥¾¥â>¨©¾ I ½µ>Æ|„½r¬¾<;>¾zÐ<Ìå>.:Š=_r…>Ö¤>aÄ>¿ÝU½ÀðǼãŸN>&}R<²Š¾ŽJ¾:�½O�Ì=èCi=0c>Ën½v%>vKÖ¼Qz$¾À£}½S‡†¾Ý�‰=·H˜=é²E>H µ=Ö]ñ½s÷żõR—=úND¾=Ù§>…¾n>ŒÆ ¾íV½x-½-ý~>‹šL>©\0½`u‡½™é>ŠÔ¼=ž>Dœú¼P‰>ˆ‰½Ìåx=æ )>n&ü=ôjm½8éM¾�M ½æ s½»=&½h3¾ÃPм¼ëŠ>€o¾\°‚¾GìL>LÜÔ½Œ7¼ØH­=;.?âæ;´Ù³>SA;¾áç¾D; >"qÒºÜpR¾Ä’=Èä`¼z¡¾úâ5>Å?î<ÿžÐ½‚õ½u>½ÁU>x»=²a!¾ñ%½4¦¾Q„=èÀµ>ò¼¶<9ò=Q‹Û<åø¢:š:š=+=m´¾éä>w„Q¾�°½ -¾±Q¾¯¾¤í¾†C=#W¾þÊ×<ÌA^>³-�½8˜�=�Çô=zã�=è ¾�b> ‹½¶£u=Žgx»‡=>ôº–>­Ø>äËg½� è½Î|>·ÇÌ=]«»>õŽ>€&V>í'¿öá`¾ Yž>\帽¸YܽÔ_v¾8yò½Áq ¾�ºìŽ=ú�¾ o>„ˆP=F¨™>Ö[£=ã›l¾©ë“>O,$¾UÊ\>Í;FÅS>š[œ>!œ¼iÞî=ß „½%Y†¾ A`>‘y³½ÚYy=JÄ=Å9>ã3^="~Q>€©¶>n†k=dkν/~¹½¡¡Æ=Ž'>_(»1~ù=¤ˆí<Ôѵ=â=У=Z¸¾¾„›¾fÿd>ÌŽ>[”,>€²T¾†Ü=à‹ñ½õ„¸½ˆÆ¬¾+X/½6Š/¾T�¾Tî4¾›>¾Të<¾Î� >ˆì >/æ=UQˆ=­ U>}þؽu¸‰>>ž8¼Å1¼÷Ê™¾¿B=p2‹¼m?8¾¾Â ½ø”¾XÆ£½eŒ=,º,>&tm½úü_¼2½hpx>J žŀ0>2[¾¡/L¾ñÙ’¾ã¿½¾$™«;R�ľ×|Z¾Œ&æ½:DW¾FŠ>a(¾¤.ϽíG޾Z! >n„½©„�¼ü¼Ô½²>„XÓ¾AŠ>Ž�¾ï;²=¦¿¾ê´%¾`Ñ›½ ¾=ì[<ùË2½ÿ³¾ÕÂľ´ ‚=pͤ><_¾�5%=3¦:=q"=ˆ?Â=Á+ÿ=G,>;d¼>%z¿=Pù]½q† >l2;ðÄ<ùw>¯ÊÕ=?Ì¥=Äi>Â’=¢«â½ts¾{»‚=ma?>�¼¡=È{(=~‘(½Õ­'=\1~=‡¢½¾*.G>.$À>,¢Ó½òQ¿;u*x½Ÿ$Š>E]¾ô<¾½w)“¼G>ÿ >êÊp¼ ‹—>´¥”>Pz=˜ ¾?D¾ õ¾*±t>M,6Óþ½L– ¾: M¾•׿½S«Ø½þ‘>lß�½<ô½]•h>"cù9·¬€>Ýñ4¼ÈâQ>`”Œ>×?Î>�šœ=Ú4=>}Y@>He½&Oh¾2Er>۾ػ4¼fò¾òÿ�¾‚Y`>>³–‹½Y(>ÒÎ^>)©>Nä>pYO>Nf±=·ìÒ<:ƒ¾†é1>¾TE=U]ë»´›½KWj>¿´½2rð=ÚÖ¡¾×›=NÇϽ_—P>ê›>œ=�>Í«¾Ž–ª¾ #'¾<ú½f. ¾~ʽdè¡=ºTs½rm´½Rhâ½³bP<îÑã½d½.´(½WJ¾¾ŒÈy=U±’½“ˆ¢>(�‹½Û×ÿ=Æcu>‚v>ÜúÖ¼³†<.d>¾¾³å½žã¾Z¿Š>ö*¾G�<ÊØ½>Î'>)D!>qN©¾Ö&=&¼1 #¾A}=:¤×½æœ>«‡»=ê;">)/ò¼³½=îÛ>"”= ±û½! ?…*=�ƒ¯=ïÜ­¾\²½k©k¾>¶x>4a>¥ó޽^hú< I>†Wý>ƒø·<§»l¾À|">�¿=èD:>Õ{ã=©T½¡q-¾¦ ô=³Vo>øÚR½gw�¾�¶>Á®‡>f=$÷Ú=k~“¾ð`ü=Ï)“½=㮾,}ô¾üŽ-¼›°„¾jユB+>;œA<§Ô >*ú>PýÆ=T<«< vR¾–•>໓¾ñ]\¾Cù»Ìwý=ôº_4µ=•«<¾ÛZg½ÔD-<{vä½7¾ÒŒU>¾dP>®²“½Ú>ó½†8t=Ѱ=ýmN¾´)>í¦L½ð÷£¾ æ¾`‘¾ÎÑm½]óq¾éjA¾í ½�©´½Ë|�<(…¬=?«—¾•ǾGó‡>_? ¾î½öm¾¥ü=&ÿ¤¼}`”¾?±¾LÀ.¼âW”¾ ˆ�¾ÖPâ¾^ŸN>«¶1<à\à½öaŠ>éç¯>;Ò‹=ï'¸= =)p�¾5ãµ>�â7½Ã¬ =A?í>õ²³>óä³úâ3¾y� >€Bˆ¾f¬…>½=mR¹=àq½¥eô>®¤*?…½¾e¢ž=]V>mÒ’>EPÖ¾>äèÞ=@T¯½õŒ+>¥>b¾â9=¨ Ý>=ˆ ¾ža¾%ù‹½7Nv½Óç„=ëDú=ä4Ÿ=Q©Ü=gÕ'>/Øš>0ÜÝ>åÐ]¾õû|>ùÔ>€¾�ñ´>È�€¼®%»½|ð�>pSz<+¥>÷ Š½1%>½Ž<·<½Ð >8*�¾Y‘<>Îïá<$â¾/ œ¾FÐ<W×>¦Ð¯>8྽’¾Äû=‰âƼ¥6>v17=›m®¾Ù‘I>î­Ñ½'A�>Œä>€ži¾³y¾Òp>9,u½…L„= ®¾Ølð½,z,¾²¸j=ÑÓ‘=P€à>áë1¾½Ü6¼p½¾»‰‘'ÇÁ€¾óŒ’¾ ¾½×?=�oK=·¾~=ü¾øU2¾»EG>Jgi¾}7w<þ© ¾ð°[>¢�´>“sí<„û²¾•˜¾o‡=T\–½Û�ݽìéð¾—51¾yû>½ þ€¾ü�+½«Ž=fE™=Ç|­>õ%==Çãн#¶¥<¸¤Ž½t×A¾92^>T·=Ui㾦›»è§½ Z>¼¶¢¼Þt½¼¼m#>+"¿Ð¾(XG½ðq½wÿÙ½©¾ºw½X ½Cäô=^0£¾?Ÿ¥¾7š½ŽˆÀ½ö•μ W>¥kF>~æ”=„;œ¼Zæ�½íê­½kå>äÄ?𙾉ˆ >+ɾ̽ šc>vaA>¾\D>ñUü½äjL=pÅ=~9K>È×ç>Ä‹ò<ñãϽ•w@¾n‡#=`-ï=¤ý¹½œí½^X ¾WÈ>Í�;>Л>»¢Y;´ís¾šÐ<‚µ=Eñt>ðO‡¾GÎá¼D€*=žwü½r…=ž?ÍI>ûs´¾[w]<›@%>¯=í=k>}¾½à%Y¾¯ô™=†+¾½v®¾ÁCa¾ml›=æ‡x>9G?>|”¥=Å B¾3¦¡>ŠyC½¦Y™>ÇI¦>ö¥W>“€¾c…¾½™)¾YîÀ½TåK¾&œ½Z�U½-,N½Ø½ös.=Ͼñý@¼Ü)ù=NU—< S4>´]±=‰ÎZ>¿!ß½5–>NоhÌ’¶íŽ=Ñü=•:Ÿ¾D5*¾£Ç ¾iÔ&¼f¯¦¾¶lŸ=BNt¼îv'½/ H¾%n{¾„ÿÕ½É >#™R=P=)I²"GÚ=�ô>Ÿ›,½¿²ô=�òS>½Å@¾?ùÝ=L§½kéо7XV>†¯>Aûq>`¸?uG ¼ˆÏ¾b§#½@s®½¯=×½+\.¾Ÿ ±½j+Œ>ìΕ<›Ûþ=òa)=NÁÞ¼?%Ô=;(…½L4£½xºº<D\>Àb>^Ë·=à®ã½õ°ö½#p>.…>=€"¾€e}>Y•y=å†"¾]6ƒ¾FØÅ¾âš!½É›»ƒG=¡�A¾;™½¿EC¾Åw=¾6š=—Z¼>êø:½„=};=_©…½ôcÖ='¡@¼lô ½²ý*=v즽ëöù=Ħy=ö“>Nà ¾ §D½.D¾`ѨK½<÷·bd½”y2>Ö•¾úi¾n ‡¾Í>LôC=Iä{¾cOí=1Ì•=)ýe¾à:W>ÿ”¨¼É×Ê=÷ŽÏ=ÓVŒ>”q³½‡ =ª‚Ÿ=ÃéV½ã�„>Ú$B¾5Ô>ŽÈ,=ÎA„:9q£=Ú(R½y¼¿¯�¾t)†¾FÍ=”=ýã=¦©„> ,i¾¯ ñ>8?K<0(¾Ë2¾PÇ>µÉ¾6¼X=›°N>ji]¼§§Ä½iÁÂ=;̾ƒ¨´¾òñ·=n¥a=Ò¶œ>—å‰>ï ¥>o92< ¼½%BÔ>3>½Ý÷½œÖ½0©Ž½ç‡¾Û‚¼Uø>óïØ¾$C½%CŒ½þÜM>¸À=‘§L½� ¾l`-¾!‡-=:¢ ¿¹ã-<㌓>¼š¾·¹=°V¯½Fά½ƒ<,Íœ=æ¦ãº©›´<º*gº°Äz½cí�>LÈì<ú/j>üZ>«M×>¶KÖ>Q�=ÑZY=«¥¤>²=²üսݑ>¾† =²OŸ¾£©4¾0^>�Z‰=Í€9>àV„¾õ>ˆ>jàª>ˆ’õ=J{D¾Hhc=¯> ˆ–>k{¾í×=eø,¾øßÿ=‚²P¾fO[¾5kö¼Ö¾aÜÓ½@7—>¢ÐJ½ã-P¼Zo"¾²¢¹¾dU‹½i¶Û¼É.§½µ{¾JK·=Ég]¾o#½êͤ>ul¾”ðö¼Ý >^¾¯¾oÚA½!w=è£ ½Ì„¾ú&B¾Ž>é¾éŒO �A=îM$½Èpô=†Š=�ú1¾3´¾Ê-£>ª«E>wH“>kÚÔ;M=ª=0å<䨑¾âv¥¾¦=®¼ÝÒt½ª82½÷Bq¾Š¤“=wH¾óz”½Õù8¾ËI¾ó³½9‰%¼`C¾ƒºÛ¼POo½Bl¾br >SƱ3±>0ýò=¶_ì¼ÇÔ>‘˜>‡ü¢=�ž¼:�¼Vo~½`D>ê¤?»Œ¿¹þ®>ù˜»ÊJ�øÞù½"gĽ>ÝN½>ÒŒ¼å`<Ý,˜½†É%>=¦½™(‘<¢un¾®M‰¾x:k=“Â>ð^Ç>þ‚ó½ ‚¾>�Ó£=¸�ô=(¿>þäG>v o=—Fò>Y¦<½×½¾°Ë¾ Ô={Ô½�$=Ì㑽2{é< &=Øât=–8‘<çåZ¾­0½>ZA)=Á—Þ=!”6½½Xa¾Û¨¾ƒi¼(¦>?><>ºçÑ=0¿á± >®ù¼«“> hƒ=0>�l&>Òþã½ôK³¾¥P> Λ> :8>A¿M¾5>Œo>NA><ºÑ¼éªJ>¢P¾m >íy¿QW’½p|½jêÉ=±$ù=šÉŽ>5Y,½ïÈ>pr°¾šø¬=Îth=ñ@>nD�½À¾—–0¾îî=¯ƒ>è9‰¾•˜¤>bÈn>�y¤>Æ}Ö>ÀÀ¾)íx¾õëË=^´u¾O€(>² >¨W=u1 ¾Fõ¸¾ ÎT¾�Î > @‘½¡c[>û½V¾1‘=>š¾âf½6/ö½BN>ë@�½È71=s¯½a‰×=ÑÕº¼HÊ¢¼ªëÛ¼‡ß9>b_œ½6�?;M�¾€ßœ=<ÔѽÁg€>ªÁˆ»ìʹ¼�¡ß=g/ž½�•¾©P›¼–—å¾Ü*&¾n» ¾�/l>éòÈN¥l¼$G=¼¾f³Ü=�¤ÿ½)—‹=…/—;ÓX¶=?Q½Z>�'Z>ij‘>G4½¾Dã#¾¥9¥>Ì÷>éw6" *>^•^>¤pj½üD¾ßvŒ¾Êég=0">‚½4½éb >À—¨¾×�˜<7SоŸŽüŒÇ¼‚2»�5ò½±½ö+a¾Œ®>ª?>2ÿÿ=‘<>⻸½Pmû8¢k‚=¡•R¾Åžʪ†½ˆ‚y¾|ÇZ¾DT˜>´‰¿íy¼êo§>çw­>l7˜¾MˆÅ¾pð¾uÉ—¾>ƒ`b=maR½» >"Y/>¿>µ¾µö¢½·/Y>Œ‚^>,pª>Ьâ½wÏÓ=Â>d»¶¾p§¾éÐd½™ÏK¾%®M>·–¾'N¿=oàW½’2=^$>Ü9_>_RÇ=É‘†>ýw-<šG‡½� \¾Õª½½ã¸¾ŒŸ=S>ºý‚>�W̽æW>= Ðû=6p->ëð#=8ôý½×W=�·û½æ& =D36? >o¾oÇ>Å ¾m¹<^ÓÁ=;¼m’½^µÞ=Ph޾'­M>t»’>™>½ZÙ=}™¨¼V <>É…K½.¸¾ªxB>¼N¿…€­½¢'`>oó/??”Ô½Ezð>O«=À%>³ƒ«> S)=ñ.+?|¦>ãðß¾¯u¾rI5¾îÔ?>˜¿W¾Æ€¾ÆŽÙ¼s«>:y²½l´s>%Ç™=¹M¾L¨M>̾ (x>|å²>EÓÊ=b•¾ä„å>3Žß£>«wƾ6Ör>«ëú95(>ò›p>µì2>¡6)¾�æ>8½>¿ñ•>–ã>¤ö¶>;¿!¾Ñ•¸>2?¾xº£>äl>.žŠ>èÍ_>n”=rÍÕ½CE›=ߊ¾z(½™Þ=‰6¾(Æš¾è•Ž>‘Ѩ¾Ž >ä�¸=°Œ½–>(&œ½½Ýa¾¦Jì=†·¾»%'¾“Ѿ4 „>”w?ž�">Å 6¾:#¾n1¾Ê”A½zha>–)¾Ô�>›5޾sŒ¾€ m¾¦9¤=V}?;ƒƒZ>&(½'4½  ¿âž`¼`Mb>ùg!>·ý¾ª¾=d\�¼�åŠ<§€Ë¼)ª¥=¤‹>¥“î;Ü ¾”ÀX?£4=dȽDཀ">ð²¬=ÕÐ=²>¢Yq¾î‹={¥µ>U*>iO±=˜¼”>*Óª<Ž8ó¾?7 ¾°Ç½ÿ‹t>›Í¾Ðx0¾ÏHa>VK1>½o¼>{4´>Pß;9‚нpÈt½=úí=x7ö=} 辕0\> ¬=Ó>ô°½–eA¾÷�¾å­±>�Y>Î=Vîl>†Ä«¾�Ï ½a�¿ÊD¾qÁð½C¿œ>£·6½3xè½ÍíÕ=ùîÇ=Ÿü=5Öì=$†=8ܯ½" ¸¼Zœr=&_E¾9i€¾ôTx½ ív¾D6†¾¡Ô½HÑV>ðñ?¾2µS=Ìõì½ïÛY¾u“®>Ó¬>ðê�=™%)½� æ9“[j>0Ýv½]ï‰=ï  >Dש;÷÷о¢p:>uyS>…?ï>ª¾ŽR>‹L޾P¾%ÎŒ½ æ?³‹t> ë>áì‘>�"‰>ŒLÐ=B/:>3j“¾Z� ¾g†‰½Ýö&>éIg½ ÍH>Eˆ¾Ý#¾Ý­>Œ Ù>Ÿ5¾ºa²>¼Žm=…µž>›ÂT=‡l¿«`=xdß¾Ê�E¾G~ŽÃ%4¿UU>ni¾Ú£ù=9,1>,ûü��>Dt¿KÛ*?-Wм B¿ƒg½¾·³¾!]—>sÏI>Âô¾@·¾ñ%;>ƒˆ¾1Ô§=½Ó-=zÞ<ðwµ=b7u¾h"á=úh­¼�PÉ>C,÷<”Cá>1f.¾çW3=ÄZÁ¾Qr°½mèV?l>êo<#%C¾` ÷=Íù/¾T£>#’&¾¬¼¾Ÿ£½60><éR=çÄP=º°M<¨m}¼:eK£)¿±Ù>®X ?t´?Û”*>eÜ‚>)ÿ>$ÛÒ=ýŽì¼§"=ñÄù=££½Ê*o>„ã?=u�i:8¦:¾çÚO¾l厾óÖ%>0BH¾W=úž%¾Þ­h>¥¸ >eü>f<¾’k$>c7>1§¾Î值0>Ǽ!¾bðs<0)Ø=²Ï·=W¿äͽ„À§¾Å‘¾>µ—>»”;3¿(½¨Hž¾^$Ⱦ\d¤½ò?þ;ŽO“>Ë'>Ft³>o©¾�Z�¾'*=¸Ý)>�}¾¿œG¾O#®=„°¢=—)>LAƼ¹äP=sb±>P¥½“¿É½v<í½”J>{~>8Î;™Æ4¾ÈRe>`UÁ¾hÚÉ=#C¿[‘þ4Ò%=ÿ\?P×X>ßÙ==j¿vÈ>Æy‚>aü½8ðï½å«¼ÏŠ�½´ÊX=Ÿy|½²y¤='U ¿c�¾Í t=Vß°¾uš'>½ë<$~‰>ˆ�t¾ý�¾š–>/= >É ©>Ï|ƾ»ñ5>TÏÇ<þgÛ½@EÉ=ës�¾<ø¾A„’¾SÚf>�²P>Y‰›>O6’=j#¿Frž=Uaù=qý²=Ì„¨½~{e¾…-Ê>Űã»ãt¾‰r�½Yw>}„L=žÈó=Ž}î½?Sæ>:`c>¤<ô¼¬š¾¾Î°½Ì">(f²=ç(”>ÞPÛ>—>c]¾×ˆ*¾ôƼÙÜ= ” ưܽ?£¾{Y>Z…´<¶ Ç=/Ï~<꥽€Ž©>…í}¾œHm½jUÒ½•¡>:`é=†é¿>“Fâ=’Ú=`ÐÕ½]¾=.æ½N¥+>r“=,…«¾¹Ý�=zþ>͇¾3ž>Mðm>�Èž½ÂŇ>«XÞ½E,§½Z:=¦Ý½>ß„>äv*>�Öø½øZÔ>Я‚>?VM>‡Z¾€»�¾˜K= ¢]½lHæ»S:>qGq½o˜D=º3/>çíF¾ï w¾×£>HCs>_§Â¼cfνhø’¾[01¾¼ ˜¾­D=\¥½w>CAª>L¿¦½"Z >ª»>~M3;U]<7yf½Uµ=b8¾«s>1Ð<ø·l>¨j¾\>ƒ=x«B½IÆW=_D>B¢= è;½ÜÏ=¸%=Šc=õÑ=Ìù½þ+£=ëg*¾ÃCP> ½ ½uR¾ÂwË=¡àŠ>êËÕ½xI¾¨Ãn>¥²7¾Ò:M½ _ê½{è¾'Lß=±|å>œÈ¾û÷¾žr•=H3å>�–_<*.=ŒúŸ¾žï_= 1„½zÞ½1KE>K*A<Ê�.=ó@Á=E9È<0Ãv>^°l>qoë>J=3µ=Þ¶�½Åp:>wM�>k5·<¥z6=? t=£š¢¾ž=Z¾¹¢6¾;ÜW>ª·Ñ½²>Ö9­½�€=Кw>õÒ½-±¶¾�ú>>=5~¾f… ¿¦•Y¾O´�¾s–¾¬h=8¡ý=;'­¼*„°¾8‚†>ò~"¾ùwÁ½.Ï€=V­!¾çPì¼ ¶-=?Ñ>Y‹=‘†=½‚½_^É>5do>{¤>u1X>Ѹ%¾þàͼpà§>…+¾ùdŠ=(Õ¤¾OsÇ>1½7>caD½ïoÙ½^öé=¢Ù<õÍÓ;»f;¾ü‚=½­í\¾YÚ ½þÍ”>|^ç=&�§½ù’>Z<¾†X&¾h~Ñ=:wµ<�ŒÐ=�õC> X ¿›ÈT½œãf>�Ÿ÷½Qáï½Îâó=È‚Ý=âÝN¾Û”˜>Øo>™ÄؾùÛ½+œ=üÄR>å†�<á᜽ɯ>m¤a¾O+ú=Уj=‰ ¾=³›ð=c•™ðSI¾é¹G¾hT޽Öý7¾r†<>U8a>º$>ì s¾�˜&½Þ²Ý¼Çð»4È«>]qß¾ÓÛ =“’>–?˜= vo½©ÕO=k‰¾vÙs>óJ¾ ¤<>L>À“Š<îrJ¾HŒÌ½œ£<ºNÔ=—B= Kl¾4DŸ>õg[¾ŠÀŸ>‹ 8¾°Âö=�ý²>Õ½=á݆½–åT>ï\l¾B×·>!#£¥>9ï=Ó~4=î ?<Ö>{�¾/BN½.†"½ŒÐœ=J¶™¾fV½×÷§¼þg=T”:;Ò{,>µÝȽm\Û> u#>—ž¼1ã½SU>j­F>´Z—>1ž®>{´¦¾Eç¬=iM˜>Tü¡½6R½ÉVÑ=­/©»&HǾDAݽÈ/f½kMÁ:Òw=ô;Ý=Q ¾¯>¹ƒ¾¡%µ>¡mV>‰Iñ¾Dr'½? Ò= P=ÆÒ¼•nTBù½ä„m>WRE= �¼½/k¾ IZ=Ðäà•‘½è»ˆ¾8Šœ=@÷n¾Kª¸½c*¾Þ (¾A÷g>ÐÄ·½þ:ß¾@ O¾`¨|=¶ß¥¼´>ø\*¾ì”™»gÓ >DP\>SÈP¾Îy½m0ç½A-¦>-->Øý6=ƒá>>Œo¾ºrF<{z¹¾Ü÷²½¥C¦¾/�¾<$=¾ºÁ¿=æ‰(>È“Y>RM0¾x«2¾†¾ðêõ=T¶=� ³½„Ü=cA¼êSº=`äÜ==Ú>Yu¬½·xl¾˜#3=÷-¾ ˆ½ 1;¾Ÿ}ȽMÁÚ½{Ò¾µØ­¾ßr]¾¾ ª=xÆb>ùC‡¾Ž:=™‹¯½¤ß²=B'™¾nn> ß›¾ÝBŒ=zy Ù#U>·'½qª=À6¡½ÿñ/¾ä“=4ý Ÿ½ç«½=èÅ>è‹£<µ¥C¾¿R½Y�w¼pÒÔ=¬\Í>º×=šÃ;=c’>O¾ŒŒ¾̘>ágн’�s^YÅ=€k=aÐ^>¥úCº_&=¼�ê=s*Ë=(±½�È=JE;ô ¸>Z+/¾Ê²>猾µ©¾¾…˜þ¼¼³= ½I‡•>¹;=¯T¬='Yý½Hw£>H6v¾¶z>ät¾˜œ‡½ä>å=QC>ôˆ=ÿAŒ¾áŸV¾N‹ˆ¼är¾íg¾œ�‰=‰¥é=•F¾¶eX>ïP¸¾”ÓV½�±�<~Ôª½ô²¼ù5ª¾{íÉ>ÈÌ-¾$ ‚½"„½ëš²<†¯^=jÀ¾òŽ>fܼ“Ð4<çÇy¾/Ê=;ø›¾ÔfȽÇ�V=%wI½m�¾2ð>¾x7¾Tâ >Q°=á=ÏÒ8<ØÌÕ=ÑùË<,Ñù¾,e—=N™¾©IоÝCc:µ�+=–H¼Ä|�>�B„<÷Ù=¹wѽ–¼ýT¾�áÙ½aA­¼øa˜¼Ö¼½€�×=Ôß±½�7£½Ü¾¸J1½È%Ý>z.ˆ¾•=Ͻs¯ >wÔ;§Ý˜>ºcû»qÑ�½.a=òö¾Álá:`%ʾ¶2ª¾Æ—Ý>òRñ¾óm§>˜€¾6`¾�øƒ>´ ˽Žáï=n³¾ Þá=ÁÔ¹½l¡¾¾«ÂB> />™ r¾æyˆ¾C"�>U¾j>s&?F¸­½´+6¾—>^/ý=ô§¼@ÿÕ¾z�^=¤½*M½*GƽGzÀ¾qLü>[|ù¼¨ú ½,¦>dg*¾Ÿ|4<ï¢5¿‘Òƒ>¾Ü½GÄ—=ã¬=‡Î?džc?\ñS>'~¾¾2®>ÚE¡Ž5ž¾ct.¾yÒ­¾m‚.?ÆÏ)=? ‡¾¸È…½™ŽÃ¾S¾¢ҽDzþ¾Mš=Î>>É…:µŠ?¦¾Ÿ¾³3d¾z3�>?~ð¼óó½;¢>ï+¦¾ãÿB>C�´¾NèýÁPú=N…O»Vñ>ã‚>Öõ¾ØÜ>æO÷¼D¾¡¾I¦ ¾qà!¾‰Ê£=ùžI¼þµÉ¾ä�(=éžž>)ªA>Ýœ>Õ8x½%B&¼ÿn?¤5Ì>o(j¼«Ÿ¾qý‰¾}�q=TÄO?@°™>�"¾ð>î�¾-¹À>àÝÛ¾¡ð>’×Ú;ñ2ã½3 —¾ÄªÈ=¾pYµ=šO?âø|¾~Ïó½Lþ?l¥½6CÔ=•".>\� >Mp¿ÀK » F¦=ù\e>Í~ö=Ѓ²>&Ö½C�¿øì½ˆÁ>O —=þÜ>@(>­ÉG¾¯ w>bC‘=.€œ>w@U>„?ä’q¾`Tq> C->Š}¦>dm¾ˆð;Jµº=\°^>DÙc>4É™> …>a‡¾æŸ�½@X>Ü‚‹¾á™Ÿ¾ÿ>:? D=ßj½†v�<ÉÅ ¿D¾_ÝU¾0݉¾Læ<ýµZ>@c?6>æ×`¼7H€¾Ñ9»= ¤¿vI¸>[ݯ>’Øÿ½Ne=bc=K1Ú>ÄMo½eª—½u‡¾Oß>>‰åD>èÊ=¶)¿1ÿ¾kU5¾ŒŠ#=›s‡¾z¼=LÔ¡ƒ¾ª�I¾ù>Îo>a—‰¾WjǽUÞš½M;ĽúT¿«I뾿¾<4Ìྕ�µ»•_< dF¾­o€>³£h¾R…œ=6¨‹>‘Ó~=¯‰ >´R=ù£¾ò=fZ‘<Áö½:.?Y:Ÿ½Ìá/¿iÛì¾ ƒ¾¿Uo½–Üÿ½Í ²<_Í\>º‡9¾÷=±¾\E¾¾Ha>uÈ’½ãçs¾‹TC¾J¾/ؾ­˜>tÙª=8Ű= 1;>ìþm>µðȽ�] ¾1E>W¾Dê®=Ðï²>…új¾ø?½”s¥½Ðxg>�$Š>¤Sž=H±Õ=‚6¤>ú¬¾¦1Æ=ËG¾Ä¿=óݾlÅr>ÀT->šÎ½ånA>fWb¾C%'>€¸P=dïÖ½ ‹>~iÁ¼¾ß9=¸Ë¾Õ³u>ð㾟R¾[»ƒ¾Xü=ÇL?Ñj=§Sm>}ÈL=ãú]¾V`³¾åؾ¼�##>Fƒ½/1½Œ<¬¼v9>$ ¾ àá>çi§½¨Â½m*Ã<êX‰¾¶e>Ö 0¼�b(<±œ©½²RI>1%¾JȆ¾Æ�½ >Ï ?»Œ?|¾¯¾ç=)7e½ÊÞ#¼¼#”=žªÓ½±Í\>R}:>>M'>øÚ>¾|#¾5>šô/>(G>’¾Ö>P¾ÇE9>ã�r>Ê×¢=fº>ØhE½[g£½û3>&µ¢¾‹(�=ÙPÎ=ûÎÙ¾¾>-ì¾M­T>˜"ò=ÐØ:¾AB>þÓ˽H¦­>͘¾ç¨ˆ¼ í—½‹è¾ÌE½k”=uRCºr‰6½SXY¾Ä|E¾êãÎ=ÄRr=Òˆ<”N"¾Á)>Ü ö=�_F>k„½¸!²¾*ä½>4½èÄ5¾‘>‰“d½ò”Ç=³kÀ½h(㽣ì¾ìü5¾R5j>泟=†µô¾!¸}> Iö¼PÝ>~Q>´·¨¾ñ·É=7{6>`ÞÕ=È!o½ä =ïᕽUIu¾uW<=VE{<çæÇ¾MW“>n²)½ƒš¾ëªD> e>¾M^‚=‡l€>ŸÚܾú>ÁAB½Ó¥=Îæ¿×}Õ>ySc>b9ã>dg/¾sI޾˜ù€¾ P…¾l'®½.¡S¾¸Ÿ#½n£—½ 3 ¾$#>ž¢à¼ôë¾-U&¾«gæ¾qtѽÅÜÍ=Ãb>3:$e=±i ¾Ü!˜½£…¾D->91ç¼{mȾìò¾{ǾEØ>“¿=e­¾N¶™¾‹ªP¸Í=æe>ÉêÆ>âYK>4¶¢¼á’?8ƒ=´æ›=Ͼn«½ŸÞ�=»e"¾mUx>v5B>¼¬)=ŠGŒ½~—½ sÒ=nôƒ¾¤Jý³[?_�½]櫽úê>Š=©>ûŒ>à „>D'T>�å¤=•ú�=+È ¼"áL¼Š‰g>Dœ™>p狾\€•¾3Ù�½2¾s¸»!Ó$)ûB¾@~A>3W†=*>Šd¾VXî¼�þ=׬š¾ ö½]‡D¾ß›Y¼Ò¾Ø¼:u¦¾_E½0A>3—3¼pôÈ>»i†=£4�=Õõû<>æf¾åeJ>[|o½Û1•=\±�=ãò=ór>É1¢>е>­K¿>CE ½Þ»ä½à7d½—˜D>>ð�>c‰R½d7Þ<€Îr>}—¾Îú¼z� ¾J*о…+_>òù>$Úw=ሠ¾$.3¼{Œ ¾¾žV>!’=¾u¾¨m"¾�Ñh>†}¬=>ƒŸ¹z!½Ö댾Æï¾˜}’¾“½…=$w佃û=­àÓ½ë÷†¾t?œ½„Z½Ûä¾A>Á%Ù½ôFu>¨Ðž¾Ü´<½fz^¾ê‹J<Žª½Üs|=�4à½X, >l`>ùwW½…8Ô=ˆW >·Y¾4Àn>#ì=R!�½ôY£=­>c>àዼÑȇ¾96å=ÑŽ†>e{]=Gßl=º… ¾ÿ—€>üÿ»+†$¾ð“!¾ ¬½•…[>²©=A¸½·)>Û—=¸¶V=ªl-½Ó‰;*r=†¯Ÿ½F�A½ç3ÿ=ˆ±¢=?r>uù>å]r;©Í½…Žƒ><|J>®^ƒ¾¸7½:gm=¿À·=ÕÝ«¾}ü½A´?=bQ'¾Ôê-¾h½^I >XÐÖ¾2e¼y„>Ù…¾Ç0M½�n†={×<¶f|><Á¾"¦(¾(r¼=6.½Å®>"úµ½­é7>ï¬ïº|J[½×dÓ=A™>e¢¹<(h¨¾â >DL;=2O><ªpÖ½î©R¾U_�¼YÌ*> ùö¾ ‹=P�˜>‰t0¾†™û>ù ϼ°V=õ=§Ã¼¼† ¼KÆ->zr8>%¾`p5>W¾‰Û¦½FA¾’°‘¾i”™>–ç=Ú´9>ö¤=¶‚Ü=|DÚ=Ö0½o»m=:xK>®ik¾ò•§¾x… ½ˆ·¾hϼ±m:n>£«P¾9y ½/ɽEC>a�ƒ½�¾(>Ö!<`S„½RHD;Ý™�>מ¾ŒG+¾–fÕ½E9œ»#nо^3\�@�=í å=/ó¾»Ù;¹Me>”Ñð=_ ½zɸ½ÇLœ= ZR=2ƒ>ÎvŒ¾ÔáR> â"½ŽÇ>Þ|€=RÅÂ>|b*=‘P4=WÞº=@Œ�¾¼‰³¾òÈg>’Ü>>¼;æ9T¢G>Ðl‰w<Üx^>6]>@`Ǿ�²I=4!¾½M°÷=så€>¾½E>ý�x>³E”=Œ)½m�;¾†9½¼e=>5WP¾Û×¼Q_I=—ã¾ò½ “㻿ۻâU�¾xN4>ä;vÑC=·7á> Ê|="|'¾œ‘¾©Ä=jY.¾íÁ½(“f<^g¼½É–š>¾Á=‚Åú½z†>y¨¾†û‡=‹>µUL>úã¿®¢>Km�=Äú¢;ØÙ=»Ô$>h�’¾Ê�4=c ¾‚ľ۬A>õs©½r…Ï<­“Ÿ½ªV¾Èì½>J¯½w·b½Kx ¾«Os¾9-…>Æ\¬>Ú-¡=ÇEE¾ô‹»Ò@3¾D+¾ªL>�›=Ó°»Mņ=¯�ª¼¤�>]¼O¾:ïF¾oŸ<>¸™.=E„[=åÞ½ {¾}x0>j¦�>x­e>bF¾àÛ>«>ܽfœ=¹�2¾—M¾ùBù¾F©=—' ¾²&A>܃>¬ºk=¥þ>?÷Ó=ù²v¼®ÜM¼\ÿ½‹J½êTÃ=¦ëÿ=óVK½ùó%¾�T½gÚ>êG=´ê9={Ê7>¯› =§o¾s¿—½ÕVå=ÒOn¾ùá²½A»'¾ëÅE½�m�=¢M´½:B§=O01½““­=ö{½3Åʽ¬@´¾Eh½\Ô>œp½¿ ¾[®©¼SÓ¾Rçl=@ ü½ÚY*>±P½ �ó=✄>G§B=AÊq¾ž—°¾Ž%Ú½5ær½•îì; ·½¢¨½3Ü>ì™?. Á=½!ó½�W¾®ðv>‹€¯>’s¨=w“œ>>Ž]¥Ì¾=¨ >1‡¾Ø¢> –y½ËsJ¾Ä6ˆ½V&‹½ó² >½Àž=oÛ¾wÒ½N¦ >´R¾°n=q‰>¾ÃA½'=j¹¸>nžp>&à5>*Nf>å4÷½€*ݾFuK½a@K½/ïm¾ûƆ>C¦¥¾Þ¢ç½_ÉE¾ÊêÛ=<#>¬€>§Ät¾Ûs ¾´ÎS¾‘4W¾ƒ\>µ~?¾}†™>€ˆ@>"rÂ<ލ=µa�¾ÊG§¾æøÔ½gØã¼‰>Éôͽ/Œ=F, ½ò(À>’Ež>D³?¿ƒƒ©½Œq =�VÄ=8ù2½ßlÑ<žFO>ô={Žx¼ ˆðºš�>Ó¡“>©}>·�<çϽ+Ђ=8øC½&´ã=­é¾êˆ(¾Qi–B9V<±ìô¾õ—¾-[>†Å¿¾ÃÙ=m�½Q»Ì”†¾ª �½4…;>�dt½�‰¶¾çI:>�ŒU¾Nfº»®S¹óÞ…¾7kœ=ÿ55=Ø =©¹Ä=í>t¾�ãð>ÂÂ>à>"?T>�¾Ëc¾ÖÛ­=ix:`.ì¾ãÒx½3¿²=ö*轘Áñ½gK¾“ñ�½à'9¾šºµ>B­ =³ >½—æ�¾m‚=a‹v>þ©>@­W>ÑR´¼\Ýh¾Ô½]>*c>|$±½ ž{¾Û’¾>'E²¾: ù;ˆOë½Ö�Ç®¢¾œÂ!¾áal»°Ç ¾ST]<8£�¼ ]H¾d•J< ’‹½#½M>û¡<‚ë4³ö¨>;|>DCl½ø >–Y–½*�·=~*`>Ž(>)¹½¸ÂY>+èž=Qâ¾×¹¾*—?¾{òƒ>·™ô=Y¡Y>!ݾ¼4N̽Ï®½Ï 6>˜V޽Öø½Šè>©«V¾;¿‡»‚)ѾUlL;»ÝJ¾N$E>Iì¦>$�¾¾¡üi>]À:>½ê>=(#Ù½ˆ!˜¾U)¸=2³£>Šlì=Š-û½Od½åþR=Ö�¾ðÙ¼€@@>{³½ã¢[¾QÎh¾¾Ø†¾åeb¾p@$¾eÊn¾¾ž›¾ `¦¾ÕfÝ=’Þ=ÿf>³rÐ=“t2¾wêǾÒnú=È&>`°Ý=Lj�>÷ª½ì6¾¥4B¾úŠ´½ k¨;3ÀZ¼Û‹E> e >À >õ>=>%?S®�>g=¼ùȼó2>|jô=³«=Ôß¼úld¾1[¡>L!<¾š›Õ<ïL>ªxݾªˆ­½�LÁ=¢ˆ€¾qžî1;¾X`‰¼³“)¾O䆾‘ñ½“ˆØ<‹�Ó½ÚÙ[>Ïý>Â…$=ìEì=õˆ¾È…ª¼{o =cB‚½›± ¾»}µ=fÈ”½xÇ ½ZÙ½êS<¾ëaë=t2†¾Ýqƒ¾vãa¾Ù–<¾wU'¿{˽♗¾¢dß=Kßn=W·n>¾j ¾�¯«=þ‡n½r9ä¾&A“¼®ŽÅ=Àö»¥9L> 0>œ¨>`d(>{­é½+Žœ>|رdÜÂ>ûÈ…>¡H¯>A>šq¾{~C>~=$Bº>X2¾%|�>Ñáï½Íê=r¤Þ¾î[!?·Ç—¼Qƒ]¾Ö®½Vo>eÌ’>çÆ=@;¾Yy+;�¾Î› ½d‚¾�]ˆ=~ ·½Uo*=`éà<ñ¯=�»s>HuI½e•�¾‘úÙ¾Or£¾¤,o=Pˆ1¾9 €=ŽÑô½[j¢½ÔæN¾Â0>~X“»l V>¡oß=Šw®>ÜKí½‘>ûÙ->˜{â<(o.¾”,À<±x$¾èy ½¬ø!>Ôr1>$¢=ÉIƒ=ªE»=Ì_<‚þ"¾ŒOª=`ù=½76>âÏ?¼¹÷¼do־˺D<ùéF<íX>‡gš¾›ä)¾d\á=g¹;O”�=LÛ¾]¿¾×ä ¾ ÛJ¼§Q°¾=Ô»->l, >CÜ8=Äl½p ¾=A·¾:«Õ¾éF<íý>>¤�¾¡"I½‚„ñ=E8µ¾¦›3½W.%¾•v¥¾�É ¾i¾æ=K .>>¢²½ð¶>¾z<Ç=lÅo¾1Ñý=½Á½Øf>á¾>+sÐ>°T¾ ñ=�ü–¾ö·Í=³“`>ÊÅ4½À„¾@o>»±>¼žÁ½{îZ¾ ãw¾~’B>r¬P>Ô–X=»B.>ë�Ÿ¼—Ùûø2{½ ^`¾*Á½Uù=¼‰y½qÀ�>ÂVt¾Öqú½á"¶½„�ï½0iw½†‚'=ÒyL¾±š‡½«òó=ˆ,>ùC·º~Œ=¾Õ2¾`ݽ*=>Ý·>r—S¾½pÕ=Š ¾ñ‚_>Æ�c>Rr½Ý“>¥™¾s({>\Ú„<+˽-_Ï=³›VGÄ»XÝj¼…!5>Â"1½²5½¯ä^=¥²�¾¦c0=šZ’<¥ö ½ô££½„sž=äð7¾íc½K°J¾Ÿ>ÔØ„¾ŽÓ¼;s×N¾Jnù=ç=Æà�½’u<¾ÐÙ¥½¡Ûƒ>¹ËD<9úó¾dƒÏ>f1?¨îÑ=jü><æk¾!‰&¾ ªÔ¾g菉GŒ·½qúa>»y¹=Ñ£>>ÁÜ>rÔ#>ãY¾™…‘¾7²¨<¨w¾°½$㙽:f= yÙ= ³`½Üá?;I¶Ç=Dž.½û—ž¾rG{>?¾�I¾³›Ø»¦W\>ɍ޾Mú(>#í®¼>*œ¾HžB=*�a¾¹¶¾ïx<>ÌWܽ¬»K¾Òv§=?ãÌ=…jýQz*½ËçŸ=Û§Y¾�i>Zj>ƒd>v¾!ë9¼¦:�>3 ˆ¾=M´¾\·=.â=«—H=®‡=€0—>ï f¾õ×<^Û‚½g?¾ƒŠJ>5Ú=gí=¹Æ‹¾­�½Éù#¾pã=gÔ=÷T¾F„à½G�„=©Lv¾ìµã½CÛp>Чë½ä\=€”>>”=˜µ¸¼º�>10½c >�G˾Íçá½ßZ=>Dºt>!€r¼¿¥€»7¾[·¾Ãq!>še¿êà›½D[ª½ U>´à¬¼ëñ½ÀàÔ=Ïï=�}D> ìÞ=Ï—=)�Œ¼áfr¾…I0>X�ª¾xó>=iP=Œƒ7¾S¾a>†xP>×á>½®S©½ÈB>ÍÞ�>Øñ/>Í‚¤<>Mú½£_[>Á¨Ì>¯“¯½Nn˜½>!Å7wR¾·].=æ#š=d¾œ:ò½‰±¾x…½G•!¾¦ºX¾‹‹+¾ œ‰½9u=&R*>Bþ�=Ý8‹½ñb�½Ž˜w¾n—C½C[Ò=H,±½VG&¾5Çо©s-¾X•Á¾}Ʊ¾Åb§=Í‹ޏ½bb2¾HÒ¾½+�ˆ=ƒ¾Ò…ñ=’Š>Aˆí=ïó˽\=>Л=Ÿó‹¾ |¼—õê¾°º=> t¾ÝH€½n¾| ³½Ò¤C>×¹>Ù” >jgÅ=ØI‚>û¶Ž=ø1¾õòà½óc¶¾x>0ÝD¾ËS%>‹½Ç“B¾Î†¾´Þš=RÞm½W”É=÷ôå½?)¼=Â�›=j>a>ÎLK=BŽ\¾zj=‰°Ú½~£¾jTa=”hÕ½d}VºÿP¾›ò¢=!œX>îé¾R?v½‹"ô½òjƒ>RiÛ½‡1<¾³e=ÄÓݽ<3¼|¨[¾ßu>”\‰¾ðº7½Hê = Ù½Z2÷=-ÛE=”ŸP¾Šö½`ˆ¾«ô {M>æ¨=®V]¾.-ä=¢û±½Æ.>”¾`H>÷‘©=® Ö¼:ƒ§=kÏ<ò3¾&[g>&^¾°½Þ S½}]â½S®!>îa<5þã<Áë ¾Eq/¾b&ù¼Nô"=:øq¾"®�¼GÛG>·ªv=ÙòA½°4;¶õ@>6b.¾¨�®¾š>õX=_Ñ“=r­;¾%Õ=Ä¿¾ðý>ýƒÄ=Þïl¾ "ͽ%ì¾5ò„½5·¼[Œç¾¬È8<ì>HM2;­¾<[m3¾­� >2Ù¾0UW=˜)½Ó/‡<ι-½§uý:\ƒ‰>$¾ =Ñ»\w<ìcù=šn¾ºØZ=Äž¼!6÷½Š]>J·B¾?‚¼ôÀž=?2º= èø½Ð� ½j†µ=váɾ “¸<¸ó²½ìx‹¾ÞÁ¼ÙÌ{>—»¼:¬ó=Ùv>»üÔ=A¾3E> K•½¤">åWË=¸³—>×·+<0¥ ½üÃé=Q$>­)p>å�f=_E½¼¾5Æ>Ä?ƽ®ˆ,>Ú+ð¼«+½ÒNø¼ì(½­M!=*¼=ã™—j‰­=[½6kV¾31¸<Œ¨w¼–ÿ†¾(ý`>d”¼?=³¾—£¿¾Û–=™:+¾ç�p<Õu>À#†¾GQ¾ý£®¼Ç\¾ˆOϽ¾Æ�¾Åav¾�2Q½R'‹¼Ø³ý<Ï“d> Ä;¾ M>¾GÚ;¾ñp=¿qM¾¸G~¾”GD=õ#¾-–q¾&¯½>P>?A¾ø?=Õ¼ vÚ½là>”Ú½�cƒ½ƒ~¼Kn¾!RѽǬ®={àQ<ÿÔ ¾ø°¾>‰>9ä¾ÏËá=E½¾ô¢²¾³�O>¸IÄ=+Pœ¾Î‘²<ý‹½P£¾ ‚X¾õ ‡¾á‘< Ä­½y!¼<ðUÙ½`ûš¾—º<ßÞ½í =*m½ù‡Œ=|—§½m�ƒ½[Âb>Ù@_=Üž¾×K‡¼ìý*¾ý’̼xAu¾ßq”½7@ ­Š¢>úfñ<ñÓ"¾Ëú9¾†ó¾æÆ¿½„>< •<+XR¾)‰l¾Ð]¾hc> ï¼ ‰>œø,>¶”‚¾¹‚½)޽'±¾žiº;ÐÇ=Ð >Žø‚¾UÖ¾’|'>�c ½%±]¾F+>¦@Œ½T>p¼cÌk¾1T«½¡8ö<‡7Æ>� ì½Þ”¼,¡9P¤‰>f¸š¾éÓ½¾Þ(L¼æÜ+¾ã•¯>?,Ì<ù4i>�é8>Ò�¾Ù@9¼Go[¾6!?“ö™½_Ñ�=ж½½Æî½[ÉT>è)™=1=y=ÐÆ>–¡>k„ƽFäI¾ò,>]Öª½²—o½=Ñ.=°T½k�°=:™¯½f1¾=Ù'¾¢­µ<Âé=ýR¿]1Ú½~¢¾ª¢i½Èj¾Œ‰ð»äTx> “<ц¾’k^>ï÷É=ÑØ=õS>ïÓżøÌ½án°½õwª¾{ >sG>™Ü >�¼ÙÍ€¾â´(>wæÙ½¡ñ½¿Ò=§Ñ>åÊѽï¡Õ>©@Û=Di½®8»½|}½[¦Ä½wÛ!¾Ÿút¾O¾Ü¼¢4Ž>Jåɺ¤…\>“Sνóë˜=L�_¾i—ñ¼Bõ½ë…•>Ãç½hA×¾(fнɇª<T¥½%•�>�J½•™ê>ŸÞ¶>½Ñ;V>b¾äå½½”p¾±»Ò¼Î{$>S\¢½ÏP4=ÀÓ">ï€*½ K>™�->/r>* ¾x™½L[/>åÛL½½¹<Ý&Œ»š7œ=4ƒ ¼X]>_á>Lœö¼á®Ñ;…€¼ø1½ u�=Þ–A=õÄ=¾M—�½€º¾îÍ�½h”¾•�Ô½{-q=Çÿó¡ÞÚ<Á|Z>8©2=\ŠV>Añ>·¸¹¾ î ?ƪå=޾>øž=Á‘¾ÜÌK>ï�¿“€#> «>�+>¿fÓ½®áœ½ZÃV½SÈZ>ÎÓ�=U`�¾H2 ¿p%c¾ÃÄ™>‡9Ú=”Ã> N3½@Ä>n6ý¼Ì„¾¤ÄU¾y5¯>ÑR…=B‰ñ=�H´¾á-;cˆ>ÓW¾ >Rì¿Yƒ½aI•>ݽ,> L!=¹Æ¾½l¾r K>-Bs»ã:?¶•X>ð#ù½d†¾+¶¿‰€D=VÀ¾/»<¦L*¼MG˜>å¿×½áX¾M…C>z3š=‰›p¾¾¿çö®½ ÃP>þ�q¾¶o<>Rfо/x¾¼„>�û‰¾‡Æž>Ú»R¾«Só¼w¢=¾)×:=jF$>8ë¾"l=üäþ½Àø>ÝúÔ=Îö!>Ú:ž¾å1뾑ž™¾N¡>b&¿¿ï:¾Ìdm½E ×>%}J½˜©½9mÙ>ÓGã¼Å�ç>ˆ«Ô=<t½ 9Ô=i]U½í¬¿ …é>TÁþAÀ¾ã]�<Ÿ²o½´ëT=?³=!u�¾þ]>Z«Ã¾v9 ¿W-l¾ç–�¾Ë˜•½Ä‰Ä¾Â¶¾qˆ >õ\=ÊÁÀ>&ÁÕ½S/b¾„€�½œdó=˜í¾ñ‚/>™˜¾“À¾€&—½ò=FL;ÌM@>% ;» ¾Kº?f׉>åi%¾8×<'О>Íß•=³¾SÛ½¹€>áns>‘  > ©X>¯ù+½¨‰½ø¯Ù>|Ð= è½OÖ‚>ÆÚ˜=~è¢=„ÖÊ>Wh½²Gp>#Ã=ámƒGÈO>¸ú½”;>I²¡;pD.¿ð5”½†ò¾„‡¼g]Ý<±\½Ù¿>>QT½)9š=´Ÿ#¾éa¿>F›·>Ý1¾n­7>4e¡>“<,;“¾0Ľæn>=3Œ=Ô9¿\›Ë¾3, >®µ¾MLJ¿sÂ=ºP…=gy«½ükr>]Æ=YÎ*?ysL>¦å¿hÕç¹sÒ½˜ì¾æg�>f—–¾Ë5®½o™Q>w\�½“~,?[>N¬•=aå¾RGν¡ü§¾?¤¾¸²Ë>K­O>”¥î¾/üÓºgE»d&”>Íš¶>4Ëh<И¼×NÌ=Aî>§È ¾rNi=«ÒѾ�CW>Ùž½ÝB›>’,<�Zå>Ĩ�¾Õà;�°>� ³¹¾ž­õ½VsнšC€¼õ¬¾*¸(=Tÿþ=ÁÄî=òlµ>*–ˆ>à�> ÏÝ=4ÿc¾TìÁ=%àºñ:½ífK>MB¾‚�Y>õ±¨>Ô;¼HIA>ó£”½L7ì½ãšh=­?Ľ÷bh¾!Ûî½#’°=‡èß¼-ú®=ᄍ㓽üô½öë’=(œÿ½ÇR˜¼P¡0¾Ý\Ú<!¡>fT¥;e¼ß>�.á=ú+½Žw½Ë]Ø=ï—†=~ôD>@Ù)½"ƒ¾½Â>û=)D>˾2½œCÁ=uJ¬>ÌÉ%¾3‡Y½}\9¾T|ž¾W¹�½÷šî¼R³<æà>œx®½Ìa¾Wµ=gD%=†£â½,%…¾týô½ u">6\=íqž>°”i½'d#¾Øb3>üU¾xä=Ÿœú¼qø¾¡Ñc¼ëý<Ò•ñ;/HN½êá½Eý½qv=‘­>óÞ½Cª™Ã�>ŠË1¾�Œ¾Ô„½G º¾±<‹7®½€èX¼�õ*¾(JO=ƒƒ<–Н½ Ód¾ø‡s¾ÕŸO>y¼‚âœ>hÞÚ¼@g‹¾X=ô¾§ ¨½ŠÎ>÷ço>`\þ¼8̽ÜËŸ< øX=¾¥ö¼Ü̓¼ë�¾‚ñ:¾¿M�=¿\½¾$K¾2v¼Æ˜†½nà_>…ÔʾîÓh¾ÃŒ=ÏK>êI.>ÐZ¾î}-¾Vj¾”ü)¾1Âå¼™Ö¶=T+¸=u/Ê(>Ô†> T½‰ä<Èù5>_8>‘ˆ-½eü>…ƒ”½ʲ9þ9½a¥€=eê̽i á¼ãc>üD>¤Í½·†¨¾ìôa>ú+.>Ú¸g=~‹ñ½G²>f@‡>Á�s¾`ñá=Ìe ˆÒ½!<)½ŽÄæ½Þ¬�>-—>I©Ž¾0ù>—æ>ORþSÄ{¾Oø‰¾�Q>>uFÎ=äoä=$Ð_¾e;E¾ó)>äʽ ü½ \=Œ@Œ¼T•#=Mýk½Ù­d>†I¼u¿=ò{G¾k@¬¾b½g‘\>Ìk¾ï1¾ñÂ<Öqo= 0޾ÞË‘½  ¾¦R°½”ˆ«>‚;}½Þq½Ãñp>ÚF¾PT9¾©C(;$N÷½®ñ½~¾aw>×þ©=è� =ŠŽq=¨¹¨<ÄO„>�¼Â�¡<ýn¾Àá=SŒ¾NO³;Qý½Ô;B>‘¼_^ϽÉŵ=h0•Í=O‡,¾]0®»óçÕ>E¦=ÙÍ|>¸Ó½Ï <½¾ž´=Øa«½÷®)<àòF>›‰¾¨çn¾î•î½+~->>˜üøcK¾jH ¾§Õ=’¯š¾a¾÷¾gÖ¾^5Ø<Šù\=2± ¿ôo=ɘ>>dF<:¸½�²¶>jQg=Q.a>ö {¼põÇ=Ž”6=9_+½Ý]ËN1ã½Ç~>gšZ¾ólݽï�>G‡Ï>¢ô:>1Ÿº½RÚ¾î"¾Ï#-¾kbŒ=‰Îƽ‡\|>iÉÂ=×Þ=[(§=ç’½füƒ½ 8Ž�ñS¼•óŸ½ïÛ;9§Ì½LO>"Α½D->ö¾!Ç뻲ф=Ïo=~›½Æ�S¾-Êß¾Öf½Í¾ŸI¾<¤­Å½v±j>Dú×;sÊR½Àþ¼7ñ=Š,B¾µ»4¾ã™�¾ñ–!¾ÓV>þ+)¾ýYw<F>Kú>’¡7>uÖ ?FÀ»=À¾qfP>/¾?ø¼{z>dʾ3vÒ<²‰N½¶®¨=7€=Ôâ;¾ÌF¶=¡Ý‘=F¶�>3(,½¡ËD>sq½ý d½&žš=ø>ÃÙ˜=î¡G>ŠÝ½ÇŒr¾ØÌ¾bz‘¾¿N„½©B2>ß«š=$E¾}i÷=–â½Íëµ½3åT½|ÌŒ»%S >�F¾½>ÔW:¨¢°¾[ñÖ=Ñ¢>F-ü=׫½X=ó½ñ¾^ÜÔ= м>˵õ¼Íê§¾»ò¨½¡ì½š>=køa=¾ü/%×>S¦½Kx¾™iC¾ëap¾šL“Ɇô=5 >D>@×»c9�<ìÉ>ÿVÒ¼î¯æ>N‹å>jVT¾4sñ=ßZ½Ä~T=]q<:�U;§ÀB>Ù%½í~Ó=G‰S>R™>¾$ÆÎ½e·7¾*º=®d¾ÑeŸ=�Ÿd>ˤ/½fÿ×½*Î>ˆ"§>@*Å=Óƒ>Z$¾Gí>Rþ_¾åp: ˜ó¼Oß!:B°ƒ>hua=é¾Í=�‚Ô=þD>îÔ¤<"‡ô½ “½a ><ý_&¼'–�¾vöD¾µ6÷¼»zR¼,E¸=âRw=¾˜Ø=„FP<x!>áT=Ýš <�/>•úu¾_kˆ¾ñî�½ÊRY¾ Y!½,k½Àþšç«=̈½}ÅX>?r¾Q´Ð½Ê‚>vR¬½@Uß=çö¹=áÛe¾õ€½ÑÏ>;j¾Yªá½D ²¼,÷¾ cW=MC>-Ú'=Å> Ñ!½±à#¾»¯)<óᾟ’¾Õín>x˜>¨Ü=TG¾™)D=­“.¾XT{¼MK=>¤GD½¬ù>„½s)/¾óÙW¾ÀY¾Æ„¯½º8>ñÞ¥>ðKܽ<ýa¼Ý´°=O_>3­Q¾2<Èp¾LR¾ˆ9¼�—�¾YWÉ=î½(77¾ñò޾z Á>r„�¼¦ ›=mK”=0ŠÕ½&�^¾MKÙ=Ó?*=ã-r>q€q¾,’¾‡Ÿ�¾´ÿé¼k6>/U>´Šm¾ºáÆ=8F¸> gÌ>�Ž>¬|>uJ>�Ž>ª3B=+D>t}¾u# ¾K†Ÿ=;Ó—=ünˆ=˜Z>¸SÒ½É;¾´¦>vNó=�2>Nc—¾t Þ=rÏõ½Ø¿J>1<°¾ˆuw¾©*¾[!Î=Þ<=À­Ç>²é¾é�¾’½îðŽ>«ñ>އD>x_Ëï=½+8i¾VUQ>M•¾rž€½q>¦>1J�>u7оA!|>ڰͼ7?]hA>\&=§T=òÙ°½k‘>iÿó=ªó¸¼iwŸ>ã¬M¾¬Æ0½bò=Tœ¾ÎÁö=é[ =þÉç½Ã-æ½s¹Ó>\½†½Â³ò=×®Õ¼ ´ð½4çC½šš‡>ë ð=~]í¾¯Œ=�¾Ú<£=ãÄ<›¥½ðµQ=ʌݽÒj÷=³Š•=£‰Æ>‡µ>”˜=)Ó—>Žÿ轟|$¾ùl‰¾EÓË=’ö‹½AÍ>ÑáÀ=ßlÉ=¿F�¾Óða>Ì�I>–›¾†Tþ´º;,iw>7.‡>×hT=÷_>óML>`§½Eª½¼sоʾ:äÌ>>Ôv¼N9¾I³)>—ô½ã;¼~®i=\¼=ñ�Ä=Íà¥=@�<›&ž>›|ݽ6’¾…“ˆ> ­ä½È¼Þ;DTƾ­B¾î(> §+¾Uq޽™T>ê<ú=Àݘ½¾ô>±y�¾ pö½y’>¾Þ„Ù=î§Œ>�“¾  Î<Ýþˆ»ëQï¼AÚ»=�>-÷o¾ßv^>o°3½÷µ½ P >V ¡=NP²½»K>9ß; �= Âû»�v=N7Q½ÖX= ,¨ºêÐ+>OÇY>À�h¾Íu�=ÐZ>7ÆK>¿|¾ÃÄܽ¶_P=Ð~”=¦3뽫 æ=MV(>㸪½ýß¶½!Öm¾f¼v T=\#¾Â�ž¾ò›Ò½ñj?;Tl—¼·Ñ‚¾qqˆ¼)*=BŠP=»üÃ>Œü½ºì°¾œa<£:|<¯)>b~¾ÿF½èg¾¡Þg½Mª½”‡=èï =¦'Ž=±½£¾˜¬½Z/¦¾ý¡+¼úé°¾c�c<ŠtÁ¼“ë=ÎXÏ= æ>mr�>rk,;.|š½‚r£>n¾MEæ<…øê=†U;H I¾uÁÐ>zyõ½Ÿø¿Ñ‰÷=¡±Ì¾¤Ä•¾¯J“¾tó½ ×ï»ëj¾b$`=…'¾WKÍ><¯;†½zŠŒ¾ÏG'½ˆ3>Ù:`=±H_½_{⽇’];S%«>Öæ=å%¾ä`꾃CA¾ÝU=N†¬=Ìœ=ƒ9È=l½Hãš¾?íá=±yŒ>›–¾Ï*ÿ½±é›>ÃÈ>¿%–½þÒ†>p ƒ¾d¸Î<ó—<¾]{=¼‡p½½U½Òƒ½Iy²¾ó;Õ½'îj>äO�½k Û½´S}¼ŽN±¼�¡>ëª3=õ�M¾FÀ°>>N•½¾c¿>®[w¼°Wâ½ÇZ‡¾Å…2?ß�T=“?SL£¾2šâ>Ÿë½½Ò6>¼~|½Èk;¾_ì´¾ÛF¾ð…¾ÆRÙ½ˆƒ>œÿn=äð½gÍF>`±"¾’‡¾ 7�>^Ù·½¤c>Jð½Šf >ëº>u,G¾Š<â¼�Æ=䥠½ÙÛ¾=ècÛ=⨼f»B¾‚é/>)u`½â€j¾!h ? Â:¾ì¹+=ò2¾VfV¾ËI�>ûô�½½¾35¾÷¬>Ù±>ˆr—>Ð¥½±S1<ê$ˆ>Ü:<:i> ×½bÏN>uÖæ½Ð~�=¼¿µ½Ç¢»¾ëÀ¡¾Ÿ2ß½Þž>‰Nc¾‚øâ=šœ>»¾ÝùŠ=òÛ·=g·>:^>¯õ…<&5¥½Ä¿ ¾^†=pZ>€);¾¤tμÙúŸ½ÊÕâ½%f_¾ñìÔ½ã�¨½Mu¾¼U[>”CÀ;M{>`½½.L¾*ï°=„O¾¾®)²>b´>?ÜÃ=J«\¾”ç< ¾éôç¾ßÛ=+Oq¾ÙšŸ>£‚¾¸×g¾]Ñ5>�PM>ìA ¾Ÿ¾ >n½�H×>ñý¾¥˜>XZ|=õiâ½%¼Å¾Þí¾”³¯½®¿=�c>Æ“¶¾E�9¾—9 >žá2¾Zн>ð>*~‘=P� ¼ÎñĽ¨E‰½Ò{òÁ&Q> !¼¾ÊÞÔ<Æøú;œ4>tì·>doF¾ü_>�ò¨=òö¾¢=6Âc=1Š>{">ùuP½¡µ=¤Ú1>("(¾m³ð½C&½ ¯>jØ¢½¿'о—R ¼aù0¾t4A¾d·É½7 ¾�N½Az±=Ђ>®`¼Óqé½û¬¢=ò“>�„>ЩŒ>¾¥T¾–q³<`Äh¾—}¯½Ò—½¥hÄ»rZ*=„d•¾¶8>ý�=�øð<Àݾ½öôH> Q,>„4Û½Ùˆ¾U¢¾r]O>A–'¾MQH¾�9Í=t3‹½ÕyE¾Øz¾…�½3¡“¾éü`¾ù>™Êà½,}Á=ù š½¥¥Ê=ùF)=NO =º&¾�¯¾©éɾþšä½Ÿk ¼ Ô¼Lfé½€‰¾è z¾»·Õ= P\=ijŠ>…=pN컀’"½FÙ}=ú·‘¾`>ƈ=÷ü=úP<>¿¾sª`¾èï®=ÏßÖ½MDR>�®m=RŸ½@p2>½ö¼eì<DÒ¼¥W>MÛŒ¾5Å>/|8¾&¢=3æ(½Ý± ¾�eÄ=“+ÿ=R —½“o‘=Ιk¾Ù`->‚w¼… ¾©¼S>X}½eм£Dº=l¼|½D˜D½’<ý=7}S¾ õ)¾Ká=i_'¾qÍU<#d¯»$€ÿ<„1ó>°>xåhG>Û²¿¼ Ã<=°5½W?V¾–Ç­=~ñý½Û]¾àޏ;¼Ô;»ü <�^¾=ϾßX0¾‹u»ÈŸc=&о&”&»Ð´!;�z<µÈX=·A;¼{6 <\Ùh>‡h¾à’.¾#Ò==PA¾Sñq<§L¾Í¾ó‚ç=›·P¾þ|�>–Ãc=}‡=3‚޽]Ss½$ƒ¾†‘¾˜!á¼´¨½‚\‘¾ïÚŠ¾Âw> —½fQ:¾WÒP¾¦;7=ÉT> &>ÒÓ >`v‘< :¾<ý5-¶¼VÊL<SÚ½ à?=ª¢Ð½Þ.8¾=(Ó½k¾Ò3%N½�ïF¾2>�Gs½Gr«¼Ú–V¼§“†=†Š>�™½³X>£²û=y\â=Û[ ½_Ž>›(>«Ê=¸µÌ;…¶ä=<Œ¾æ Ä=É;©S�<®|,¾ÑþÛ=¦æ+½/×=Ÿ8v¼çÁ=¨¾§>ÈÈ€½“_v>¾Gd>²Ô-¾øÉÞ½.?½V‘…½6Zp=Íýh¼Ž¾¼›Õ>8·˜¾ÄÁ:¾{!€=ãݾ�0Œ=6¾EöS½gåS>­G>3ML½×`ù=/Q–=Ù8½‰3˜½B¿Ð§½Áµ€½†c/½°Ôô¾4Öƒ½-ïª<É)Ï–ˆÚ½nŸ¾f‡É½·�>=è?š< S>ëµ]>¡>ˆ=ˆè>ßÄT=<¼�¼ÓÀ*¾¿Ü¬» n¾½Ãî ¾6HS>9@×½ëó޾Â3œ>ùÇJ=Æ ½:!€>Ú‹>ï‘æ½×d€¾<ÞO¾jdC¾!�¾Ï]’½Óÿ0>s5Ǿwã½´Éó¼ŽkQ¾ÀNC=Ÿm>:k¾=B¯ ¾y«½Äò±=ÈÂD½ßǤ< :оAÛ¾¼eÕk¾UŸÿ:‘”À=ãìÑ»ÃÇþUœÌ½F¯>vº¾½Ó+>;•`<¯£™¼¹Ë=ÜVy=eR€=G$€>HÌ뼜O[¾ôhA>Æ>X §½¸"¼½\ý>Ós¾ä>?Vú¼FVÇ<\Z};©Õ><äϾ1_`<Å·)½uµ½Ö”§¾œ=ç=¼öø¹<9/i=&YX=Ã0¢=|*ì¼%D¯½nð<3§Ö½cìJ¾¨”…½HE³½Ûýx½£ >;îä½ÛjT½ªx=§õ¸>«ôâ½÷´æ=H­…>›%\<Êã›>²‚6¼‚:Â=n�½B–Z¾SÅ_¾Á¾å=e–g¼¢\½ }‹>[}ì½ó+>¾¬_>9>¾(š =ĒϽKÙ|¹UÖá=¾‘ô=Û¾@¾´>“S½<*ªv>(p•;Pã¾²ô§=|o6½õ.½–…h=úh(¾¶Ü´=`Öà½h¡C¾è‡“>ËLê½ò_=ÙÅ ¾×=ãâï=l9Ô=Õ½n|¿’-â½D > +w=(#m¾4-¼¶š¾!Ø ½>_¼',Þ<ÔÐo>V÷‰¾ Û½ž,ê½èô=9‰—¾úŸ<ùÒ¾!§=zCaÍ�2¼ê_¾ÕÓÈ;²„½ä�/>—D>ø6¶½~¬#>—j�;¥–|>—‰¾5,R;oí>�Á¹ò±È=6n@>™�¥=r’=xÛ˽§à'½ {½l½»¤=ÎE�½§«=Ø<ƒ¾¼]¡; ™Ü½ŸÖ=ò5¾9¤¢=ÈK=qQ“½nØ-¾Š„X¾Óu*=ºD²¼‘=<6Wq>q¾ªô2>¼W©¼áC\=î`±>`Í»ÿ\�¾a¶„¼…ß–<)‡C=íq<Ü燾 <�==ao½ÏF¼h&e;þb0>æp�=B£=™u©=ƒ„¾T%�½¹S�¾¶ƒ=_ÐW¼.½7¾îéU>Pßq=l€k¾(‡¾Ó†<ÓŽ>�‚>vV+¾H°G=;õ ½Ïó+>!M>Þ{ܽ®‚w=óy�>™u=Ž»Y½Ü…o<‘¢=÷Å=Ú`½7¤½�6¼ÝÁ³>Q]ž:éYǽóß�½&\<|½½�X=Cj>%au½}oÙ½L�>Ò¼ÿ=u>zí=­±ã½]ð¾ï™[>óA ¾‹| >B-•=ܯ=‘…<�¿û¼èN;¾·ï>¾<�½I. ¾ýj²<%>÷½Ž›=ƒE =iÙ&;ëx]>Ù—¾Q¾Î½ >Âß>?M}»®�Á=|à±½¬-O>r�r=ƒi¼–®ž>Ü]¾ÏJe½s‡%½©5½8¡A¾?MÓ¾’ #¾Ò¥>;¨9=bšº½¾‡4>‡i>µ·>Nç½$Àp= Xr=?w> •̼VɾÜþê½U#J½£ú½3q‰=K>3·%¾Ïß > ·>’R=›Š>· z>~«s¾·>K(”¾eÚ½‘êî=½1š¾š^g»�·=š³¶=å¶A=Ã6¾4Ž>$~0¾N,N=øí˜»™ª5¾ê’>ç(<(¤V<¦9�½ÿ<†½»û½cø÷½lïu>+Îù="ƒ>H ¾½c–¿ÝJÌ>¡$ýjU>á+”>¢y³=h…]½ç Ò½5ç=AjÓ=…©À½°Ÿ>€ô¢>¨½(ÏA>-îi>¨t‰>W°>L¢¾qzu=Od¾,×¾y¦/¾o$#>†Í/½\ýæ½M”‘½KYé=퀫»vQ¾ ,>¥a>G˜„>VÆ>z¡¡>œ]O¾˜k¾MP8ºUœˆ>>º;=™·9½PÒ¼§T>¥�k½øk–¾Aq*¾*ð ¾7…‹>¾˽~Sk;VÄ›>^j¥¾Æ…ƽ¥m>ù*˼V‰=¸;¾c&=Ç!·¾¢Cb¾€<þ¼’ôü=8е½PÙ>7šš¾Áv€¾ód.>h¾4/>P¾2Te=ÿ(¹=@L¾ðA>Ø>¾�N—½ 5å»´Ñó½U88¾ˆÄÿ<ÑÊ=“Û{¾9 ¾Ê.¥>ëC>`û{¾¼�Î>xÇ>Kº =SÝw½g=¦=þñ’¾ c>O‹«>¬`#>©Äî=‹:¤¾í�=¾øªˆ¾Y¾?>ÞÇ=§œ>ñäŸ>k1<賨½)?útp¾Cð.>Æè¦=Íüg>‚Å~»®à¹=Ð|>I�>môs>{ÑŒ¾õâȽ]&�¾Ÿ™¾ 0ö<è]�½£ø2>M½ö̵½=ŠÛ<0sŸ>Éã½RŸF=ØS0¾E‡Š½¦íþ½—·:¾Ð•�½¸6f>a¶=GK}=LáB>D1>;f>%™½X\ì½zn>Ö8/¾FíÅ=Ä� >Aü‹>À™u<6O£½­d ¾2 s¾Œ~нïn‚=й›½»‰ ½žî…>Fܽw¹>Êó ½[© ¾ÆöR¾0�>6)½=.¹š>Ó»m=ûn·½ûɽ±!½Ï†>jnˆ¾»<æ¼súõ>£M~>Wâ£>¬O>”‘š¾Yñ_¾²¼ö½æP?>íS®¾~jö½ø³©¾½i>ªô“>œ€‚>g!¾ŠyG=µ^´¾ˆ¾Ä¥>·üG>Æ;¢=ô™¾ª¿úï…>‹r_¾‘•x¾eæ½YAž¾‡2ý=% =÷¹Ž> ?9Öb>šϽÅl´½”>®<9ò¯¾#g>�¾à¿¿ ·>a·¼ºÿ-H=YaÐ=·×\><>¤/ ¾±tN>H–µ>–ؾB È¾É>š>°á¼6‰¾ƒeI>d�å=<à’=É„>êG‡>°Û¾¢7¨¼Ü}¼‘B¹> ó>!–<½ÔE�½:&™¾YYÖ¾ìe•¾­ƒ¾ <ý½s´>�j¯½ÉS¼µì¤¼$fÐ>€ë4> (=,>üÉQbN�=¢f½ÔϽ>«à¾i<¹ +?ÓžÒ¾Žs$>kîŽ>=�>Cü >A·Û>å>�½&é >&¬¾/�Œ½FÆ=0>É‚×=]B)½?}ø=Mª ¾ 6ƾeœY¾Ó2”>Y5¿ Þ’=ñ<™=�v»>K„=¦ó ¾;?çû7=8œy>6Î�¾)Òh>C§½�~ ½í6=#å>*¨8½^º”½ò Á¼i¾³û½=Å…>|½>½l`š. =5‘¾” «¾˜Ÿ=`? D>¹÷->Dü!=Æœ¾BªŽ=ˆF§>¸6¾6Õ¬=òC(½Ûyµ>ýˆs½ÝB¾± :¿¤ˆ>U+ë¾@W¨¾æ�¬¾ =3®Ž¾žº:>=g¿£2¼OU.?|E=—:ª=ý�¾!“>[ד¾ÔýÑ_>x>®>ë.u>¾9ý>?Á>:xº¾ñ╾õ0Ô¼ çc¾¤Q ?ùSL</5>t—¾�KÀ¾…ŽA>¥W%>ˆˆÀ;,ù!¾wKº½ž|C¸T.?»2J=¿m”<¶æ;¾ÿlà>5Ñ‹=ʾ̟·¾)`> Í=�·þ>Qx»=i/Ò=ሾ¬­>¸´µ¾X¤¾ ìò>\ð½µ—0?jðœ½n<�-�=† >† �>dåýä¾W¨">/3>¢y>û3»½S½—}¾c‚í¼2>ª‘¾iSt=Ø�Œ¾å ö½:‘¾P>ï:õ¾Ï‚=ÚÓ£¾^¿;¾Eý>F½'>­ü*¿)þÐ>»�>Š?’>ÀDJ=�XξvQ�¾ãÚÉ>•,C>ƒL ¿’^ ½Ø½³Y”¾Œ�;=œc‰¾gRa¼ºñÁ=m•(õÔ¾Û±<»p…½bök¾§üÚ¾˜Í\¾&þ#¾– Ò<-< >JÖf½‚]d¾¾Öl>!/°½Jí¯¾?€¾/œ¼kÒ×<£Ôz>–’νe½Ë½.b¾½�+’¾½Î>8<ç=:Y ¾¡Lʽ¸K‡>?À>æ¼�<^/R>ゲ¾Òí彇i+=„þ'” ×½.ªŽ½Ç¯ÿºðp>ž¥¾Úü!>ü먼å”1¾‚A”¾µò’½ ¦é=ø‚p½D#=� s>ñ µ>QÛ‹>¨ò!?‰*ýÿ°¾I†>Ï-§½‚,L¼b†½^u¢= ‘ ¾ç“=8Ý¢¾·°?>—xO¾Õö·¾¶Ò½ý¹½tK‰<úƒ½;-É>µo/>ÔÓ›<…Ÿ|¾õžŸ=îæ{=eÝ—= M½LÖ½ðÓR<_u�¼-‡æ¼‚ç>!;ö½ðÀÚ½(c¾€‹³¾ìèÓ½>^>Ú‰¾�ß*>Ó´ >b¾M?¾q/>–ð¢=,¬<‘Y{¾Úð¾­#µ@ú–>S±�=?$?fðÐEнßN¾&R4;ó’Ÿ=y£ú¼rø‹=ýx2¼’û=Zý®>ûÆ•;ªl!>;1>=‘žm=“”޾Œ^À>So'¾óôk>®âT=˜_ ¾ìÈ.>­¯½çïw>25>W¬k=*} ¾*ÿ¾�u>%p¯=©¾ ûÍ=&·=Û!Ð:3\½‹"v¾EÍ”>í¾m6�½—ì�=ë±�<4M|;×´¾Üh8>ˆ„ƽJs"¼3L€>ìq€>üX>FUÿ¼ �=Ó[Õ½Sÿ=®í½/¼8=%8>%r>,ð�½¶Ú£¾d�M¾A½V:/¾ä~¼Ûk–>¬ =S?S>ñq‘½$4(¼oVÝ>ÏH&¾qÆ›½ÅÌñ¼z°“=æ]Ò=vê?Ê”Æ=.3=ï… ¾Þ�>¨Â'>þé…>§½y½p œ>ˆƒÂ½Ù=6úQ>Œ‚ð½ûRì=�ªÔ>¾å½&a¾]ܽêsË>ÿ/¬½ËùN½¿¤½Ý.M>² «¾ÉX®=0eŠ=‰/E¾,›/:#ô>å­=½Â.¾±‚Ã<¯†ø½9˜½óݼE¸9=ç«ú¼Çî">}â >Hdž>3ö>cm�>˜›ª=e†q=A1½+q=u°¾bãz>?8‚=& 6¾ÏƒÆ<Âó>)Û>J´š¾CZ¾¢Xj½<ð»u&¾q´½°>¾T‹ÜÌQ>i8a½´ÊL¾ œ‹>�›6=í,>c·=×Ç8=¨Ô'>X%¾M…’>§Œf½D˜N=Šƒé¼‰Ëç½IV€½L�=d<¾¿ÓZ¼¬(Ô¾Gâ4<ÞÝ ½–— >²º ¾˜Ï>Ÿò±<‹¾1;urf½¾Ž–>ƒ[g>%¾&u¾¶

Ê^ñ¼¢¡�¾ü*;=bµð¾tÐW½®³>,Ü¿½Í°ä½ôŒ8>žm¼Þ=‹>–νÚÏ >9á=UiA>Å>uz¢>¾T =ÛÇ•¾J¬>žJнZ®®¾�k ¾°ì½^µ(¾œµ>ýÎÅ=â�…=j’Û=M°n½–3‡½«â^¾W§¼j(3>¿XŒ½9ÛÓ<ºã%=Òa¾¾RǾ=}5L¾Êi>Ýq޼÷; >Æ™€½«¶=Ûችe8ä½Ãǰ<~UÆ<3ÅT>w‰7½ã\ ¾Ç?�¾2;\>Vá9u4¦<í‰ç½­N¹>5A›=Jþ¡½šßz¾ž^•¾)ôǽª&.½µ5!½ÈAνxÉU=ñå>je¾ƒª©»Å ¾YF½ï ¼BÄ*>c¾ ¾”5[½Ï‘´=å=9Y½º£~>ކ5½@W´¾W}=Jz¾ü•‰=a[">AÕ’¾$@>ÍZ޽Ïs>�j6>_{U>x{½­à£=RÆ>+O®¾Û_¾)º8>S<á½ñ(x>OÙ@¾6[¾¨äY=lO×=ð¸D¾AõA¾>¬Pоúhâ½w|¼ñÇŽ½ÊÖS>’Æÿ=" =Æ >µ ï½�Ÿ�>D«ª>‘/ż]Ç·=4Æß="�=n“w>S<2>âý“>Ù�=€‚ì½4šÈ=ß�¡¾kÔȼ‘Tš½˜“4½�vJ¾‹”'¾VÎÆ=%�;¡æþ>ʽþù•¾4Œ„>WZâ=þ ¨¾âí=vñ†>Óšn=Sxv¾m Œ=¾Õ¼ …½³ä½€[®<å›:>¤m'>D±‘¾VRýlƒ¾¼ q½Ü>–Iè=Ô-«=Ç®ˆ>Šˆ>.h >¬}7= —>>;2¾Y¶ß¾ö|Œ<ƒ;>^±�=uz¬=î2Ô¼E»]¾îP¾€r:Q¹{¾[qZ=­ 2=%À½Ë4뽊 ­=.BÁ=ÞlD¾WZ�¾Wšd¾$ù–>¦Àù½Ój�=°Ì“¼üÊO¾kÆ#>bgÛ<,²`½‰:Ø» *<-»ª¼(>¶§Ù¾X{½1d(>½Ì=�)>N�=Ó?;%û•½’C4½žÎ¦;ãpI=ÿ=°¾¯Žž½P°Ž=RÁ’=Ò·¾� :O¶Š¾RÑY;‰a¾åh»=K»>ùœ=>i}è½¾º¾‹_ˆ¾ƒ‚E=e˜ì½b¨‰>!f�=Óû ½Yn>¿ÿù=š†¯<ÀO¹¼ø=2�t>E/7>\[¾ö•Ó<ߨû½&O£»@vZ¾ßz>l”¾šmŒ>^ªÓ¾Ç¹8=%êN½ãžê½×òª>ÛQž>\@¾‰1>Ly=Ðú½ìWM½ù‘ްÕd=Ð&>Œ‰Õ=Öúˆ¾Å¦½s7 ¾Âç]>“‚¸=Oˆé½©¬<> ¡N=œ@¾½Ìû< ºU='h¡¾3„t¼[×J¼O˜ž¾`)õ>u ž½Ì‰¾4RK>÷f�>¹E >¥˜½µhò¾~¶[¾æPŒ=ÎÒá½t�$=:·»\�½a«½¬¿û {½~X>’2>›öR=lm‹>U½»®¾N‡Ë½Vþ»;q¤¼DÛ¿â+ý<Š­¦:Áß½w¤¾0-¹= ?M“¯.ý|=p>lÌ×½Õݬ½ß7>­ƒ >l.ñ»‹Q¾÷�2¾0”¾IþŽ<�¾� ˆ>6?½‰D�»ÖŒÃ¾På=žo¾©y¼>ß¿>jµ”¼xq=GÁí=—=?ß8뻉h�¾«)~¾5ʱ>x>Ï<ˆ¾šûƒ¾ÿy¾íöÔ½ÿ3�>ª‘½±ð#¾`i¾Žƒ=/Þ«¾sE¢½LG¼7,g¾—h}¾:û-½ž.!¾C²n>õ�ˆ½U¸¼l¼Ë=mß¼š¡>FÕ¯>Ì6“½ ÞÀ>¤˜==®¾„ä-¾°jJ>0ÜY>÷fǾÐ*–¾c%><ú{>ÖN4¾7¾Î鿽�nË>‰8Ð<ò¾<Ó<¬™‡>~T=Õïÿ½TuÂ=8W»=lô$>1í½(¾)ÕÙ=©wã<Ïc>Þy‚>Ëî4=mY½ß*ˆ=ž¤e½h�= àµ>ƒÏ>–ºš=àñ¾·ö>áðF>Mìϼ•_\>HD¾Ô ‡>`´˜>è¬ï=~ù­¾Þšr¾/h[¾€n“¾¹C¶½ �>ÇÇC>3¼�Ês¾9¨½%;�¾Îz‹½¯Jî¼¼ŽÆ=ʈ½Ñ>jу¾Y'\¾vˆˆ½Lò¼Ô‡>�'ƒ¾ü)©¾ áD½;O-¾È⾫ùn<¸’9¾Ç™=#ÕÊ>BÁz>PªN=ë[j¾%¾Xš= Ÿ>OãL¾ô_£>#S=g!ÿ¼Y ľ‘ÄM>� ½¯8>ÊóE>e_< fü<ë=Äß<~­–=Ñ_L¾Ææ > V>#¶™½H¡½`ß(>£™„¾¾—ĽòøS¾6dÓ=¹a»f\=¼²Ð¼ƒñ>«ž>�m™<î’=C æ¼d䨽©2 >ã!r½éÍ9¾ò¡°¾;­¾@xÙ>% ¾bé ? 8A¾<�¡½õi;¾(ŽÝ½1Z¾‡¾XŸF;µ™>OnB½¸UÀ=©œ=£>¢Æ„¼›nm¾àa =…ÑÐ=Œnƒ><ý²>•å§½L~#¾_o>@;=³ Ò½{ÀÀ=Þ9¡¾‡§!¿LÒC¾»Ýñ=�­¿¾v¼´½Øå¥>¶ë½—‚W½)ǽ¦-¾ñµŠ¼"L¾•á?$Š ¾\£'=YV=¾z9ô=l¸/=&,‹½ƒU¬½ í=/Óš½Ì&ɾÿbé<1ßÇ>‹É†½å³Z½·Ô½¿½ >$Ÿ½Ø5¾a!þ½zü»=Ôù>-uݼZvœ½føè½& 㾑!z>ÅÝ/=‰id>,x®¾/œ´>(X`>æeR=–ˆŠ<”Õ>dÅ€=?ž�=n"µ¾œõ!½¤W>hŸ< Ö;áx‹½mé%>øK >3®¾ûê¼Ð‚¾Šï=÷ì¾Ê#¾¢ö½Ÿ­>ºg°¾ÃV½´é«>èå;>Æ|$>t�©¾³ú‰>CÏ>šÄw¼È#å¼&Ç=Þҽ̊Q>Ƀ¾ j.¾Aƒë½…—>RT=¾º¾:æ�½1+Ù½<5l=Ä>«1 =ƒÐ�¾ŽŸ¯< ‹>}š§=V”¹¹¾ü¾ú¢¾Ho¾úï–¾|·ª= l9>Z)Q¾‡‚>4øE=­œ˜½¨—¦>]Ü@½È? ¾WF¸¾Ú‡¡;Õ)Œ=-Ð>æ÷›>ñWÁ¼ïbX¼Ö$սƶA=ù ¼tä=àMÚ<“gÌ=!Í™>„+V>¨M ¾<–6=oÆ6¾ù„==œ‘'½}@¿½þD>eÆØ<Ø\>¿¾�;Å=W?>66D>ÿ=t<æŒ=>AÀ`¾‘3ƒ=>{&½Àþe<T>áò{>A‚‘>-oº=p�ž>AVÐ>k~>¯n°;è DºhΓ=È}=ï¬I>(ÎI=Ïhm=Zlr>géü½Y¨Û¼I›¾éÛ ¾j9º=ñï¥>²!½�õ_¾& C>í4¾þ#À¾+³Ä¼BE>ëþ¦¾�¦Ý¾ßŽO½„6½e»ü½�±†= Š½x)=»¾š5>/ÌV¾¤&¾5¾é•A¾Šæ>1X/¾yI.?³`¼=-.½²P[¾Æ.a¾ñ(¾­9a¾wâ&>­ÿ¿É—>¢Å¼Å¢>�³e=å¹B=rL ?¹1T>¯>!¾Ã?=>‚í ¾±M”½¸¢Ì=°óO½º>À3>ð­§¾µ•Ÿ¼Þ|>nâ=³Da>Ê‹�½„ƽÎXµ=Òv> #@¼ÙûÚ>(¸`=¾`D½Ó´>GÖæ¾ž©:¾Êk½ˆ×i¾ŠÉ>ÛW�=Ô'ަž¯>Ï *>j �½:ä>}s>Rýø=¸L¼Ì㉽"�¾ 1º>¢<x‰>:¿U=8Ìb>*�>o"¾D¾x´4=z;Ê<9ä½t8£=L)§¾;`�¾ˆ,t<Ï2#¾2´F¾ÐjŸ>Lš«=n.ƽÚa@½EÃn½ºÙá=ªÞ�>/×=‹D>.ÞL¾áȾ®T=a4¹½sì¼/ŠŽ=A5¶½ ¿>ÝË…¾¸¬Ì¼cý¾ýFë<Sn»—9¾œ¨7¾ i>¶û¿“¹%>˜%M=ÖVZ>æ ¾§>š³•:[Zì=6ëa>õB·> ½0>V§^>Ía=½�’¼Û ï¾€?=XQ½¡:¥=t?å¼Å_>r :>ŸÔ=S5>¿µŠ½(ê+¾É¥Â=�]Ƚ">(ÿv¾ž{Ó½îe=°¹W>™}¾5¾`N'¹,‹§¾¿»#>À‘D=ˆÆ>Ðç*;·¾>ŠU=ÀQê½à8= !¾*Š‘½o®¼Õûl;@Y >Z|z¾ºè€¾�®¾S³N=cÌ*>Dó¾G¸=™zu=böÊ=xà�=GÝ ¼ÞZµ½8Ø2>äà=Â÷å=;.¡=S†>Yœ.½�î%>X²=Y“k>lË]½VB/¼Pœp>…aU½¡Áä½y_„½åÊ>ÏFÊ=øâŠ>錨¾§h„=Uà(¾õ€¾ÌÉ„=±|³>DR=!’>7<.}�=n�†½ÿ#¥¾ZP>³lg¼ú«L¼ÚðŒ¾âf¾r¸¼ús¾gœ>pŠ€>x/>"!»¬ú*½‹¼øR¾Uï1¾~˜)½0; =¾ðt<±žM¾b’`¾©�>1hE>Rè!;Ŧ'>&5¾îû==9оf�xºEŸ<)¾Ì¥º½écϽPš¾bÄ^>¶‹Ó½É…9–þj¾�5>õ!s½vÞê>)ÖG½³6•½p>ƒö¾ŠÖ©¾È×ܽ6*)>¬öX¾ä³Å½ÿâ>ž1¶>WMD>«¹b<Û¡*¼Óú¤=�–¼È=-¾¢V—=Ezˆ=EìØ=m¯þ=ªv¾ÕH¾£ÁÃ<žo=ÐÅ>8®< SÃ=ŒD¾[9¢>¿iz½O ¡=ò>j–W<Ç�€»O‰·>‰ª'¾‡êÓ=ÝÚ>ƒ‡>éG>?ø»sN€¾^ºÌ=âûî=ÿJ>½½]ê=õ–ɽòyd>2ØO>K5>îÏ>Š«¥¼Do¹½>ì½WÊŠ¾9÷¤¼÷.>ššÈ¼²\M=á=k¼ñÙ=þ"¾œ­¥;®J¾9Ð˽$½„d>•誽�‚j>áv=ÒX >,N´>t-=¼x>Æxy½l¦‚>¾¾æ‡¼ýéM½çäÙ¾©Ö¢½H«ñ='¤a½.ˆ¼Þ7¾>µü!>«V¾×Áf½’•�=Ϋ¼/ž =�N½©–%½|ðh½Ø�³=í³$¾òl ¾’[ùózɽ³�>€Í> 1à=@¯A<ú‹¦½$J>\è­=ÖEƒ»Z¿ÿ=§õ—½ÊD¾µä‡¾ÛÃ�½Hó0½}Æ >ª'ݽ¡¹0¼obh=©Ëó»”!L>Vã=OZ½“ˆ>Ö\½»vb¾ „K¾×2W¾2é¼Ù*Ô½v‰ª½ôÿ»Ö»…²«½C<ƒ>Ã¥Ñ=9õ=í�>þÙ7>É“6=×´½­2]¾„²=Ènã=á2¬>ôo+>��¾^ÖŸ>p0Ö<o˜¼¾¹œ<Úò>Í l¾ªèsø:”½¬%`¾ãh>"Í�½áœ>{%N¾.ª‹=‚µ¾DN¾ædG>‘'5µ?+½¶D½®ør< f>~bnÃØ½s¾�µ¾8°�¾Y|¿ ·¬½’èU½‘5¾ ‹<Ýìz>é¶’¾`×X¾ßÛ½�ž•>|[=²åb¾“Ý–=} d¾›Ê«½�§Û=Fx"=G$¾ç\5>€W=¤Ð <Ùw¾J¡¾¬½í­Æ½è¤¯½Ž+轕Èà»+>l6¾GŒÉ=¡ ¸>iØè<• ‚>÷Ç‹¼”÷=sv\¾OØ=ù`�¼K6G=86ɾÎû)>T0¾Æ¡—½ú5¾‘Tȼ¿,>�qâ½îñK¾,C…½y| =Ý€‘¼d‡¾ò½nœ;¿k¾C¿Ÿ;–½©Bͽ»gO¾cÛp<ÙNB>Ëh€>paÃ=þ©=\LE¼7è¾±W½x©½Ó?Ú½o:Y=­»¾ßÖâ¼MÉV<òI ¼½3÷=ı­=[”¹½’‚=‚ï‚:Ζè½&_ ½dµf½\?ʽIZÓ¼~œ>¥ˆ=ï<È>—Õ½-å¹½¼Òá<‚¡¦¾9Ñ>_Ác>ržÑ½ô½ƒ½ *;>q𢾢Su¾OK�¾uÁ`½t–Û½ž�¢>®›ž¾‚­Þ½–¼*>Í >ŽÛ¦<ï%¾kí³<ÌC >RS<c[>�,3¾øŽ§=+v ¾Ö¸;¾îÑn¾�ô>½œ#¾‹ÙV>Ȥõ½^9¾ÙV­>B¿û=Þmî¾xT¥>N¾‚Eh¾Hd…¾µ 6=ソö}‚>TP¾Ïh=€5 >fNܼ̿†=¹ß»=j¸½>v¼ìÇC¾V5v> �½¤¢½™|ì>”(Ò=(™#½’×¼ÚE°½¯è•<<îL¾o ú=¦‹À=[C„>:vb=f$•½¼+Ó>à[½áZG¾þÅÁ¾%[½ÞÄ&½ ØG>HCÁ¸<ç�>…Nx>>S!¾/Œ~¾®æ„Þê>ƒÛ´½ Oʽó8•¾è™Å½×ÜV>0}=ì#©>è-¾»5¾9>=Gaa¼}RP¾|(¾¸.Œ¾H8輸,½®¡U½+#q½9 (>­M>¦ Ž>˜9�=¼¤�>*™S>§À½ø….>o÷œ½¡œî=e§£=Î2”>²³è;ºë1>·Ÿ >º w½è!¾ Û¼ÀY¼ôq”¾I²©=€V�¾'­ ¾ÒU½=µÖ ½tUh½ÿ ½òü=�{ë4�=`ä[¾ä<½¦=®üö¼—É<›p̾Ҩí=sŸ"½kS…>µ1>ÿ·¸=ó—€¾ö�—¾�Ý>¯.¾…¦M>Q‘;™Á>BÄù½qáÔ=ÞÔ¾g+³<²q½U”Ç>�3ê=03ý×¾rµ‰>™ˆ¾�H=¤8‹ºð‰ >ñ%k¼HÀñ¼”=;¢Û­=ïÑž¾j0£»¬ëd¾òNJ>Ï=f=m½GJÛ½~^¢>b\Ì=> ½½&56Š=¯h½#_ü=-Ü�½,¸= -®½ßŽŒ>H>^£Ì½ü©·=qó =_§Ä=’K½Ðv>׃ˆ>¨ÓU<ª•^=¿c<=�>³\¿>ÑÇ=Î9»=ýaÑ=4©‡½ÀU=1¨j¾öî =Œ-¾} À¸Ð=òÞ=9Ù©¾"Ÿ>Øá½|i�½’¢Ý=î�¾àã>³Íû;F ¾ä(¾KȾba½K”î=œÍ>Jé_=3P‰>\‹>´t ¾tw=c¸Ìa=ž­i¾%c�½ ú¼Š œ¼‡+|>W¤Ó¾”>#Ä<†{q½¤ÌS=DAÀ<5¯H>j©»>uX<‹¯Ü>ü<¢=x½£>"å)> ¿!>Á¾AàϾj_>S݈>±ó¶¾3‹�=Ž.X¾fÿ3>³xµ¼ˆ={>ñM¾ ¾áP‰>FÓ>•]>¸À>2= €@¼-ކ> K ¾Cs½Ù‚¾{3B?éMý¯Ì§=á°Û¾Y>Ñj½>–&€=�|‘>S¾iWľê�·=ðI7>êb¾ÚT>I@>¾¿’E=™š¿V9 ½h‹{=5Më= m…>‰â•<ý£½¼w·=»¨¾U½½.7¾4º%=š„¾pË•½ÔH‚>»E[>‚žÓ½2=±=djs¾qW¾íÒ{¾Èa ¾ù¼>þhʾö=·åîϾ³ú½±›0½‚‡+¿“�¾¾³b=%i+>ÿ…‡>£÷>(kë>˜l_>RUâ=ÐZQ½W:¿ŒßW½µ‚ê½ÿ¼í¾3M½Æñ¥>äö‰>`P;‰³>Ÿ=±DÆ+FÕ=žT?Å+>,[Q>öy€½jj�<Ë`œ>;Òÿ<úü=Á©Î>)̲>¦ t=þÅC>¤ ->L‚$½h¦œ=ØÒ“¾Bœ½H„}¾"Z„>Áw\¾fÏξFù9¾ {¿SB’¾¯0½çG>ba{¾JÎd>Ríí=CÑÅ>»¾Œk*>ä¿X¾ö”­=U •>9¾ÀÖ¿¾â¶¶='å¾Åà>ï°¾Ð,¦¾q"f½ "å>Ý®Ÿ¾²P]½\b°½STø>�¢"¾û…º>B0”½ãùí>¨x¹¾Çä=ð­=&uƽto«¾:ì¾==Ü=‡*n¾-ùý½Ø¾€µ†>I>ó>ÿðè=Ü_7=#jŒ¾®Ö*=é¾(ýLûÈ=ÅŠ=‡”¿#(Ô¾ñ¨¼ž }¾ˆ“½}Ô=Bh·>ο�º˜>q»¯>L²¾ìœ¾ð2Z<ø¢>HpÍ=Ç{ ¾~À¸¾ÿé=4zÃ=Ç»¾ÁòX=«�>.ýŸ½ðÞ>£}Ô½lïë>�¾§¾�1?õ²¾kí¦= µ"?òY½µz˾Üìë=Ä4>?¡Ú=Ýä¾ýB2¾ú„x>Û ‚¿n9³>æ:¾ØÃ™>R1(>]K>>.‹äºµ�½rþ=‘ȼèÈd=âI�¼˜N> œÐ¼…ê¾Ky—¾Ô†>@ªÕ>K܉¾öí?=|ž½Â©œ>ƒŠ ¾ñ­M;Þ( ¿Ê™Þ=&g‚½ì™š¾¢éÁ=Ý­¾�Æò¾ìÞç<á×=‹Ò=)<¾Þ6¾=s|d>KÀÝ=P�q¾üÙ ¿¥¿‡>´ÿ ½æqš½FF?z†¾ ›¾³ž<ÃùÆ>–ˆ>cξkÝe>ˆØØ»¦nb¾®œà½C®F>ù\­<6ª½0`ò½×Á¾­yu½‹Ì?ª¦�½6UçÞ".>ljo>f«ö=Ì‚§=ò�f½ÑP >um`>è¦;>#Ø@½»`X>h>'ñ½ïž=Ñ6‚='ɾÒ3p=æHB=$>Þ¾]‹á½éü¨<%ˆh¿{>më´¼†Ó‡:°½Ï:¦=Hœ�¾sFº¾ÊXk¾þÂ=^ؾóJýjʳ=,Ÿ“>†¬2½•¡‡=R’Çg¾})L¾¼B½=Üí!>Ô“=x€�>J –¼Œ€>>K=—n¨=ñOâ½hø>t”½%¡>}˜¿1µ–>lò¼=pçå¼Ë~=œP4>Ø&վDZà»VêB¾K^t>£¿O>ãV¹=8£½êdQ¼¡· ¼O.Œ½èG>q ²>Jܾîß2¾,­½2_=š\™¼Ô¿–=J¼&>�‘ß=› [>+•ÿ½2‡½ä{;>x’{¾êý;v:8=v(9½U Ù¾˜¦‘¾ËQn>ØJT¾º<Ú¾}z¾éÓª½=Ù\=фԽs9¾ìp‘¾™�ó½[�>-" ½úT}=¿I¼!,G¾ü4™¼²Ð(¾á´r½½ >^›°¾××H=›#¾­1¦¾ Bo¾no³=î7">é“ͼԣ>Q]I¾'% ;F‡N>§fœ½X ¾Ú «¾K=µ;7>°=B>�H�>­Ýx¾\ÆS½Uú=^æ¹½!= ½dŒB=õ¬ˆ¾A±œ>ÓR|>?å¾)’_¾d¬ñ=´Yà=6ø½‹ë$>�o=¥†½Ë»M>ˆÔɽ�ª¾'„¾Ñ ¾vøä>7Ù[<¹Ð >rå³½lN¨¾šè-½fô¾›cٽ߼>â3;šl+>dT>bW¼=rðÒ¾ß;¾³³É½y =•¤u>ñב½{>‰û ½Û'a>˜Ìh=•{½hr>iݲ=ã% ¾EìJ<€Q¼¼VÎØ=€Z5¾¶6=_¥9½vì1>[-¾I/¾W†=©V =ßÎ/½Ü1®>À‹'>ïÿ̽°¥…¾{SŒ>¢4;>hbP¾�™�¾˜Bm>¸½>á=ÒÒ™¾·«™½Ïó>g<°½Ý…i½ÑAï=nGI>ú]>§•ˆ¾jZ¾s“Æ>‡ÿ ¾m7‡>#˜>‹üM¾ÖÎ=¢¶“=ÆïA¾ùô€='¹=ZU,¾íIÉ>¡²ò=èî¼¾v[�¼5�E¾ý5½ƒ4¾Ò|“½ß ß= ¾ �²=Š5e¾ÐJÐ;\š½ú«‡>jð°½R,>ZE>6ü7=ElŸgp¾Eƒ¾�>¾:œ.>¯p%¾Á=¼ež¾+ðl½Â�7>\qç=Àž®¾©8> ¡¼»u ¼(²¼¼Wq»m >Në¹;pݽÖʽDº†=�ß´¾©±¾¼°b#>Þ¾ÅãÍ=�Xo=r}>¥¹¾>�>ö>°Å=¾Ü”нƒI|=?'>×®Ç>,p0>¡y¾+}�<œ‰½Lm>›û¾8>B‰Q¾9.‰º­ÊÖ<½?>zá|>_úc=}!¾)’>%³¯=ÿøª=ˆaî½Ào¼8ã½îÕÖ½ÉS"=ô¾Ÿ/>`便{޽R³N>Ï5Ì>øÕؽ¹à¾·¡½ù¿½¯ß1='\‡¾´ç|½Û6"¼>ƒ>3¯ >g�‹>~vZ>ˆ…½æ ¾Ua­=?2ѽÁ^<º>¹°x¾!ZG>Ï9޾c-´½Sý¢;´X¾·"¾Cší½Ö>{µ½ˆ+¾ž³^¾¾·‚=w¯=Aß6¾ÈÊ·½¦ÜF¾Cc>(]>ë‚„½Í­a»;Ò±¾�€•¾þPڽθU=ø9¹½^_T¾î‘»½sµ >] ­>˜ÅI¾5S>Å<î»d‘>‘çÖ>Ctm=�N°¾.z ½õ_%=´ªÐ½œŒZ>Ótß=Ý_¿= ra>§I> Y9¾¨z½¸Xï½ ’@>.Èn¾±0‰=WÓB¾¾-¥½ �¸<š‹Y¾2ݽµ—/¾‡²à=E³½¸5l=Ÿ‡¾J4Æ=ü¶=m›¬¾M»=±$q=Ïç2>O¼È½w{ä"“Ã=ºV¡½5Žq=‘:¾ºX3½Õû=d-�<>"€=š‚>N>@Š2¾É[Î=k�>¨i==ÕdŒ>¯‚;vW>qõ=)×À>ˆÃ½ûÇ;½@d½p§H¼8¨H>4e�=ä•=óª>n8e=<ËÑHÓ¼‘'½Láã=4|€½b�½9£¾I—ò÷Í>)4n½%Я½ò¾B;Ò=dœn¾Œ¨½m€¸=qKé=ÊÈŒ=¾`l»* ¾„H¢½4^¾XÌ>Œ#Ä=ˆT¾Av¹=h‹½},x½�+`½ýÿý=lƒ¾õEœ½HEƒ¼ía>¤�’½ÌÙ9>^1¾¸¡½¹Öm>êš¾n>A>vüÅ<Ú¾»>"N¾Ãä»yǘ>s¾‡Ë?6Ÿ>â%>‡Õ¥>ÝHi¼·[¾•z–=Ç W½4Z½ªèÊ=+.>à8ؾ]}{>4o[>‚šÃ>!æ=bJª=ôÍ¿Y¾ïó”¾!åö=»–Y½�çN¾è¿Ú‘æ<³~C¾¿S5>R‘>xN¾y쌼úë¬M½‰ µ>tùt¾ SL>]9°¾ntË>® &=Äx¨¼ÿæÑ»ë\>žÄt=ç À½u¬¢¾ÖÕ¾ÐuQ¾¦t€½•\x>–ØÊ½Bp±¾èóé=QŽÁ>„ùÚ½ 挾*j„>ha9¾ ¡½«Ç>æŽï=Fæ¹>–ª >ºѾ¹Ì.¾ü­¾§_=Ês¹½Pú½ð³J>»©¨½ºð%<Ô݃>{ØÔ;-9½†ñ•<�¿»=áª<¯§ >¨4W¾Æ+ò¾ï2Ö=^ñͽXp>}bÓ=Êå³¾Ù­í=Ž£(;bš†>JÄ´>Øy€>\X›¾^ï.> ­¾”½ãš>O!µ=’ ¾ñ*>Õú½:‹—¾!|>¤Ð½›ÿ÷=ð—6>x_>«œ½ºÉˆ¾{rp>cú=Odì½ì‘=�µ�=ž²x¾jÈÒ=§#¯=Pݾ m¹>pŽ¥=aª¾Vø½Y¤Ý='£=)Œi½…oV>ÒA+=KïU>ZoÖ½\ü¾H�–¾hdI¼Šå¸>©È9½ð� ½ôr¾RÊË;˜lµ¾§v­=都½èt!½´ÍC¾ø1Ä»¹>s¾]½=oT>½ ”>Ï®�=÷#>茱>ÄX ¾|¾�ê®’¾_©Ž¾Z'T½ñsq+“¾æ/½Y…!¾"ñº8n…¾Ž=…¾˜ÖO¾õ�¾hH�½ëL™»ØàB<ÐÔ½˜Â=]Zê½jÛ>ßžY>ïYn½á†=kþóª>óÜv>{í’<¿>ô¼™�¾ÏA}>ÄZ>‡6W>”Žæ½`E ¾ˆª§½ìÜK>siŒ>Se¾¿iú¾5ƈ>ŽN꺋1>¡Ö ½¨ >1–„¾‰<>*2†¾óž=f™>“#¾É¦®½wÓ§¾i8>‰ PêIÿ=}\5>çªL=¡ؼnì'½Cœ¾ô S¾îË<àg:½4Å=>#$ö½y!Š<(rD¾þªÑ½¬µÚ=+\è=9„">¦„Þ¼s~e¾œÁ>q!ξUäß½¾°E¼Q½m¾aÿÿ½‰ø ¾£Ç>ÉÆ¾û†=,)‹>/ß>¥„¼t…¾ß”«=™>�>wî=+¶>ÁB…>dê½Að”¾8 É>B “½ö¾×w¾Ý^a¾yÉ6=Åaf>f€š¾Jx×=;sO>2(½]1>h >Ox¨>¿v2>HÈ#>z=;ªÇ>£!V¾Ü²´=V�½5¦Ã> ˆ¼Œ¿ .Â;MK^>éø> “½lö$½ò» ¾/™æ¼4d¼<›[_¼¢ç,=�‚ó=2ý­¾a/>'|5½lÌï½�‰Û=Ñ€-<ªp�¾ö�=äBN>éOš½˜ “>ç¦é<:½Ø¾7Ÿa=iÎ.¾L<×½ Õx¾F+>м[>»^¼G‚8>› +½9 ˽V]�¾ÅÝ€>ø×[½ì£ä=Fïo¾×Èê=°Ö>˼„¼í¡¾™s]>Ó¦½w<œ=·û!>ÿ†¾r6°>X‘¹½À¶Š½¬W>1Ĩ¾š ¥¾e�Ç=‹\Ľ%˜=î½PšW=W§=Ÿ¸Î¹h½ãÚ‰>q¾`½ª´½®òZ>¥¿=¢;>ªê<Wë¼bz6¾Q“_=¥8n=!Îì=§f�¾le޾ïŒ>Îg>Yìn½©‹³¾€x¾¸¡¦¾”œø=n>gb©>ã¶Œ½ivŒ¾ÃA½ëó—=φ�=s Q>áÇM>š8x¾öÍ©ºe|ý>ÊÎÍ»R?Ž="wò=ïêð½Ú̾Ց>•ô½©7%<2½>®Éú<Ä š>H&½¾»G’¾«õ>wÑî½òžÅ=¼Õë¼_瘾 5f=ˆ¯½ ·=‰¤>âî$=#PM¾¦«½¾<½qƒ>ÁÁ‘¾©Zá=g÷Œ>¶ ?æ× >˜.N=-q¾a0½>&ˆ…=œÓ½àÔ˻Ȧ#¾Ã»i>ŽZܾ�Ui>Õžè½¡)¾c�E>6ʺ=‹FÒö>H—=ïψ>�V?n%)>îüw¾!á1¾ÉË/>-K̽Dö\=tEH>mKz¾D�>Y†é½]œ¾Ãü˽3NÒ<íán»—a>CGw; …>ƒÖ¼½Y—ý=<ö]¾/ù¼SC¾ô¼´½hOï=ä0>î>tþ=i!«>¨·µ¼œ::¾©¬°½½y>Àw¾Mdâ»üK£¾,:>&Õ¨¾² =‘Ä�=ad>—;@¾y9‹>€Á‹½*Q¾#]�¾”z >nCc¾Œø+¾yA>O>Ä»=ò.¾ñ.B>1„ä½ï*½ H‡¾­>0f9>¹ñ1½Wö ¾È‹Ð¾6Ü»=%QY>-ý>Á½õ6¾¼kF<ü'D¼* ¾y¾ç1¹>Ø]½aã>�߆¾&!N¾[>U >Ïø>ºçY¾á˜¾ç>#¦®½×H4¾æ¨½šrŒ>â›è½¤:m< öP={騺v±õ½4˜>lY5>c0>”äð½kœ½É’¾­†¼>ó‰=T§Œ½š1G¾Òe�½‘¾>Q”=7R'=öQª½ôœ¾¹½…®›¾Ê(ë>lÛv»Ñ�`¾,àÁ½¯c¯=H)<½,µØ>ño¼=ÿ\®¼éˆ<»D>AÅ^¼i¾ ¾tã½Ç[νÈÛ< 'õ;è3Ó=ãÿc¾‡^>ž“=k}=£»™¾M¾æ°`¾ß,=ô¢`=å×>ºX£=¨�»¾ž°Ÿ½t{">Øq!¼£§¼H¤>ì×=w‰ >­Ü0¼ e¾ty¾ÄòQ<�9»¾< =½Zƒ¾¼+è½�·•¾p®i>yÿs>¡"=i=ôÒ6¾Ò° >Â¥Ž>J^Ì=ÇÉ%>~ʾÍñ‰> î<¾)$£=mЛ¾ÂA~½i¶÷½Ýø_=údë=¯Ï?>.O¾ÃÝß<›ë¢¾²^3¾ó]¾\S=‹l ¾¥s‰>€¼>€ «½%[ǽ÷ >é7¾®’$¾÷¿ˆ=ýä±>"û+½�±½e2¾…oˆ½ê쎾æ³'¾’Ó¼ycp>¹Ÿ=X埽� ž=Ðð)=7ë¾8PF>´'>Õ4B¾»È­=#.™½ž”¶=æÛŽ>囑½R¾¯½Dr´=P ò½¿™O>ÜJ>œ‚㽸>™àä=s†¾K_î¼ìy©=�D<¾ºR·5±=_R½õñ¾J0?¾¿ô6>Õ¾/’Ô½aÀX>~)–=Tó=óóW=%r=+ ޾$÷Î<µ&D¾]ÚŸ>è=0*“>¼@|=Û ˜¾hÌ#>ϾÏ˧=jXq» 齂�*=|dÂ=ð“̹E|>Œèá¾ß‹<þ*û½+Ò:>-龚Í!>Ÿ=`ÊÔ½ˆ;#¶¾Aʈ>j%G>a*>9š=½!ª9=Mk`>Rü–»¥££¾’�¾×;3½÷B=�J¨½úÚú¼éú ?°Œ¾ŸݽP:>•Û–¾»ò�¾*gc=0F#¾›a‰>þµ=ˆËû=E >@9e>ͱŠ=(5&¾Z$>Mna¾Ü‘>‡²õ=º­ò½1`›¾ÕW3>¨=}Ú»½Æ¬O="Ùì>¦¾éàȽպê½ .>/�>‹ÜX>†¢è½Ø×�½aâÅ»=Iì=Åã�¼,PO¾!çB¾`Y?¾°­Ç½ />kÊ$¾`^ý¾÷fe>b·©½ƒu<;,þ;®v®>‡†½ ýнøz…<�‚Ÿ=‘¶b¾�ùѽéx:¾,€=Q,ì=ýX•=� >½p­Š=ž]5¾z ‰½7Kí;GC>�…�=ˆq–=.ˆ´½]F”=«#<¾3>ÌÍó¾Ý¦”=R]O=Qˆ>GOn¾((‹<§¶>pdn¾œ½Pød¼ÿQ—= ác½Ós‚¾Mîâ½Ûò�½tz÷½kâ=úQ†=°ue¾ `>y¾d#s¼wí_¾gí¾š>¼¡e>cV½©K¾ðn=øŽ¿½Öf¸=°¨A»(F)>ž,”<31>L�=5Í…>½*Š>Ä_¾5qß=ü•—»7û‡¾>Ð;ÊY"> è(<–ò‹=z¡"=EV9>ZÚÎ='É0> —È;î…�½:/Ì<Ý¡0=ñ&½—c‡½å ¾V‰»Øc«=_‘1¾¯f¼0P¦¾æb¿;¢õ< &s>CW¦<&\¾È=Œ¥ƒ>œ‘±>!ZK>â|Ã>§¬r¾åžÜ=„<Áu(>œ¼I=Ò›¾èb,¾/Ê/>Oþ‚¼€G*>Íä=äÊŒ¾þÖ=¼„¾Tü½{ÄÖ« >£‹=Þ/>e9™>JÕ³¼ƒI™½÷»<Ë1&¾r½.Ô >µ'¾¥›o¾üã­¾„mܽ ɾßFC>°ëH>ó{.½tøÈ¾TD½ƒ<×¾QAR>Xí=fµ‘½¢‹S¼]Æÿ½ñ¡I>¿Æà½^'C<”(�¾gB¸»ã¸R¾K³¸=q›¾5So¾§‹¾Ú†ö¼ûèe¼`ån½;›Û=Ò–Ÿ¾°K—½ÙN©==g5¾|N*¾È(‡¾Z`v>ÿOƒ=Ögq=(ǽ·`¡=ë«)>{Ľڧ¾}R<ˆQ,¾S¢–=Y "¾.b=…½8>q>']¾ÿ4 ¾¼Ða>—¥s>Ò”/> â>:�>¼êò¸=Ѓ̽>ì·Z=¥³î=¯‹½½u!¾ó1+>ç%Ͻõ1é=ë+>~»2¾HÀ<¦—ß½[ññ=,,=Ï[>«˜X¾áó >؃Á>ïÂa½=y‹½KÍ6¾,*�>B1¾z=o=/Ê<ø>Wë¼d¾�è�=Ý w¾H0)¾þù«¾‰ ¾ÒÀ->d\>ü>@Â>×…½›¼ ¾2¸§¼Œý¾É›>Ÿ°>xk=÷ 7»Jǽ£ëc>Ês»¼ó5¾:ž�½ÖÞ„>¹œþ½\[Z¼ØSê=44a¾Q'< �>k™Š=VŒ­¼?ò¿ˆ_Ê=¤îÖ¼<i½Ó®P» ‡i½‚kÔ=q“¼y~Ó=.­¤=ÛøA½C¸U>çþ<þê¾ ÀÑ==…ª>V²>[c½ v«½.Úþia‹¾ÙI=Iª½xåk>¾•f!=Iiq=9¾H>„¼’ݾ\ÉÁ½½º�KN>é@¾$;˜=‚| >i¾Æ«£=»ˆ¿½¾D½ÞÏ’½§y=C?Ò;¸rð¼òƒ;o…+¾„åZ<8æ¾àˆ»×¶ã½¼È¾S) =àì<çbW=óX†¼‹€½Hf ¾Î°¦>]®7½Û">Ì£3>Uï;ò O>uø+½”¯Ç½Vq¾núå=0ì)¼Ü}ºÏ~¶<:®>ŸËоÇO¾ï} ½0®Ò=Ø´K>’�Õ= BP=tØð=�(O> O¾EB>'ªì¼V;ï“=Ð\>Jµ>=oäT½K.>l±¾ý =/ƒ�<Œ8©=E<>z£š½¾ú†=Qš=F5K½£ˆ=ÿ…>Ýõî¾ìÏÇ·þ»�”�=�ÆJ½Û޾‚:O¼Ý˾gO½œæa½ÊS�=¯{=?Éì=­@ø½6»Y¾€’à½:‘нQ�¼|’3=10>’·ð¼¡ô>¾ë ¾JYª½‹½z/G¾!œü½ª3Y>W!X¾”µ>>¿f=X=V>·/„¼÷—5<݇=¥V¾RUÖ½î¨ø=:çó=Ëoн»ü=© &¾a¨>þXj<�õ3_æ¡=ÝÏê¼W >cÒµ>Hêµ½ö‡¾ÝKA=Cš¾=yX¾ð¿½WÎ[>è‚Õ<œr<¾@²r;–¨>r« >e)B¾×_½ÊÌB>�›¼3½Û•º¼ä=ò=cû½é¢g>YÈâ½w–—¾Îö=  é½Ìm·¼À9­¾Ç‰¾Õ±>óU5<úå >k¼’•=Ú$…½ºN¬¾Ãq¾">¶>g1¾eó¯=œb>Ž:_=uù¾�>´<[Hw»ñ> ¼ ½”§¡¾WÅ!=ZÓž¼¿ù¼¨·„=à =™¼Í=pÕ= Œ™½1V*¾�êù¼�Ì+>Wv¾.€½:×½Õ†&½ks‰¾ÑÑT>Pü=@ê½;¼D=ïž#¾Ï‚â;ìa]½V¾Gn>0ˆç<rŒ¾ª3Ͻ1h–»¢ >>Ü.ß½— p=þ.‰>Øì~¾¦9O>¹~¾•þ¿`¯¼4ž'=!Nž½€œ‚= à6>ƒº¼=œãÌ=~“>¦h-¾ˆé=‚¾—¾§4=ª½ò¾jÃr½žj“¾uVÿ½Ád> €=vJ=»œ%½Ý)¥¼-g>àñd¾ 4¼Jê¾Ìwæ=ùƼ÷¾ƺ¾½{(¾¿¾~=|c¼ÃÙJ>›î†>V%½7)Q=�Ô¾ ¶}>¸“¾ç2¾®w ¾%.>Т>¬åý¼wãª>óK.>fg=åŸ{¾Š=ì2»½¸=“¾dUœ¾w¶>n<½¬[=~ö&=íÇ÷¼¿ÜP½¤¾-^1½+ؼp…&¾;Ö½çô¾ƒ‚8<æ¾ñ½¨[ ¾ú›}¼2>E¼�½Ë¾L¢ë¼Žg½%�†=Þ';Ag¼Ÿ!¢>Åß�¾©g>-ò+¾¯ ˆ¾>ùK¼$”<¢ª=Cš= ¬~>b³¬=Eë�½Œ\•=3 >çá3>r&�<)‚-ʾ­<ºí8=ä.½yßà>�Ër½¨�ò½ÀÑ[=9¼þ»¢žŒ=U©‚=ÉÙÚ¾0°¾V²0½2ÚU=¥ /=e·ì¼¹À½Í";mH3>…Ú)>‰úÓ=n9 ½*t&=/¾,Xs= ß‘½ssý¼ê³±¾À ¾¶(>0'>ÇÄ =¹; ¥q¾Î®Í=l‚=X§Ï=ˆ3Y¾š…f½]-†½nf½ÌrƽáYc¾FÔº=܂ȽÜbé)ª=üL¾/´7¼Ý?h>áSˆ½Ìæ =³=Õ¶>¾;:„¾2Y>S�=O3½™¾Œh>VD¾T ’>$z>3_¾Ìö½SL6=‘£¥¾9ÍØ½ ¶¦½®��¼�¨¾ÚÀ½”�>ST¨>n(#¾¤£ï½�[­=Æs®½þÛ<çÊ >$wf»|^Ù¾^Ëg¾ÂSÕ½K‚¾vÖ$½‘ O¾¤ÿ*¾²%˜¾¼ûн¡D>ù%>±÷ݽïK‰½¨D.>|Äì=k¯+¾X“½3õ(;h >Åý¾“Ë�=^¼�=õÔ¹>„Km¾q1½1 W¼?b¾ñ>«=áÞ>SP¾ªip>„‘>œŸ˜½\l£½ª¾cß×½mIe¾ÜÄÙ½ÔÌU½FÜã=Фº–½k½‚ý½vÎi=ÒÑš¼¶&\>Æ•I>ÌR"<Ç&®=à;½Â?O¾œbs¾d ú¾£n½wÚ¸=”Ø ¾÷Ìb=Â'>­¯n>Ộ¾ì�=oJC¾‚Ì>æÃt>í8¡<圥½“nÒ= ÀI>Ÿæ½Xbï=žÆ=EmU¾ÓRнla>âðR½ât뽌Ca¾ä%*½þæá½M쑽b_¾½4é½3g+½¢¾«¼�æ=þv>£>ûµ==GÈ=ê}ü‚UJ<$ŠŸ<¤y;¾;>­¼½Žn¾¨­•ºú@‹¾¡x>‘¾=Àú|½ÑT°=õ¨µ»(1­=?Ù¾ñzÛ=¶¾Ý´Ð=€lE½.¢½³?1>½@k½˜]â>º©æ=0í�=Ñý½_¾$¾€®³¾JpW=fâ˽Ñ� ½š=¯„¼=¯…¯¼Š„å½p€¾XNW=�E>¼k±³=n”«½Ù%¾ë¥¯½¾J¡¾œß™<¶Ù ¾àmW¾)€>®žP=ª†=—´á¶Å3¾"DŒ>M¡Ÿ¼X+#¾ú^‹½.}Å<âŠ>”�µ=N½¾=-¬¾óg>ë]¦½Þ=ހýXIK>¦Ÿ¼Š�2=Éá`¾ ㊽ÿ@ô=Ÿ}“½“½m�.<›î¾€–=úûK½š<½ÄpË=~ÃG>6>r¿)¾_¾œ¾Jœñ½Ã�¾Ì°‚½h@6<õ¼…>tE¾7 *¾DÛG=[=ÆŸ¾øµ-=`¹½ŸÔ¾[ãv¼Ak¯¾4 ö½ ¾ŸÕÕ> V½Sk½ùIi»Óæ=òò<.iìºégr¾2Li>C1>¿‰‰¼ˆÈ ¾ªÃT¾pœ¾Š”ˆ¾*Ï$>¥Ÿ½mš�=–UǾ5 Í=0;•=j½I>¼«½p£C¾sO>`Æ>c�¾­³S>œˆ> g>¬¸¾'R¿½S‚½¹(½±v²½r†¾@ß>š÷<û\½t±Ø=åwˆ=P˜W=fÛ¥¾-º†»¶ÂL>¾ý*¾pþh»R”Ü<ÏÛ1¼È€0=øZ¾2 1½5 ?=õx¶¼¤‹¾yY‰=bx£=z*¤>I–µ½”2 > ƒ¾}É<îÇB= (¾z¹%¼=ªÌ½�/¾¾s½Mié½Õ�Ó¼ùž~=ñƒ½½ÁÈA>èQØ<‘Ò‰¾²|¾Î#A¼;¥.>n6<Îs¦¾ú<[. >@º>/ç¥;ïPÐ<ˆ„¾°k=ëÛ=á*¨¾ô·<0’¦=©!ƒ½…d³<  Ž¾¾yý½†Y¼½ö”¦<‹�‰»…ü¾¼}<>HÅ3¾çHD½aÆ=?I½W(à½ô|W>·<¯&µpÀç=M¾ûJ5>ÒÍÞ»CŒx=óÇ>\|н›åµ½ÿ¨ù=‡šº=Cn=zÂz>]ú<k/>>ªH¾Û„³>žR$>:¿è:'uš¾rº>#£�½ˆ@¾-D¾Ð&W¾²º*=Ò4>™p»=7AÚ½]ú¹¼%ˆ>g ‡>£–H>ýf•=©Ç=tòš=êÀ§=!áѽ!Ÿ ¾Ä0x¾•NØ:ûc�=ýŽ™½yb¶>S�t½EfW=t ¾–�>‘¾ ï@>âh¾S¿-¾—Ô–½“þ6¾œ×t>¿œ>>¶ñ®=‘ã½4z¾©ϾJào¾+ø½Œ¹ç=”}æ½.Ú<Àu¾öý¾ßái»’÷=Ã}¾(> ˜=Êa9>«¶|¾*”¹=êE¯¾ë”ö½u¾é=Á�]¾#°�>uÀá=Mm¾µÃ;rbB¾û’œ½Å…Î>Ÿ¼æºZ?½<ß!>; ³½Dx)¾J#<Ìv2>ºøË=´J>œ*½» \>˜¾$膾 ¾xñ=bÆ1>Õǧ½üw�¾ŸÛÓ½p~[¾åé*>Yˆ¾{l{>3á»/€7=‚ŽY>ÿÆN¾ö³½@Ä(¾º�»¾ºC[<`(]¾äÑ»·� ¼ý»Õ=_HÉ=tqœ¾YI½+Œ¼¸†E<>–=øìe¾Ä—¨½ûài=‰­Ø¾àÿ¾šÎÞ¼Xj�½Ú�¼rÙ1:°R*=tÞ�<,C|¼Çz=Rѽoa¾{04=‡Ø=š¢¼k8 ½Ñ2>ßV@¾ ¹¾$³�½Ä,Ž=îÏ3¾ÞÁ=�]¾o+ì=þñºz �>K±I>ÈÔ½3õä=ˆöÈ=ȇˆ½å{=\´×=åÈ€»ÐI¾Ðô…¾bd9>,1½U¯û<°ª> ¶'>ÂmK½Lµ½5òL=êÏ=(dx=L0d¾B#Z>—S¼î ½ñº¸>Ç =k¿"=vÔ|½÷5“¼¶š6>ØÔ&>àK½ ¼8¾ft¾¬E’=u\T½öF‰½“Ùb>U\¾hE>)gö½8iC¾à‡?¾X¸<½·B»\½©�¾É¥»Aðã½X >F:¾X1»á[’½a[:¾!'s½ÿ†¹=HÊÞ<,‰=œô.¾8Õ=´ëŒ½�¸=fÎõ<}Øü½ºV±½Éx(=Ñ<ð¾Ò›¾È?>í±>6C¶=ðÛ°¾|.¾ÿä+<*B†==á¼J,w>u¬<>ïW=”%ƒ¾Z“>�X=x…½a«¼T<>º‚Z»‰ ¾F9û½ .¸½¥ºb¾#¤ˆ¾�·r=VlR>±/>æ"]=†ó8>ªµ<œ²Ç½@�@>`‹<^à=û/>ƼV�X¾É„=’Q¨>a ¾Ö7®½»§Â=£|„½¦¸1¾^|Ž>qŸØ=ãç½+(G>ŒLP;C{€½AXȼ2[:¾FÈ—=ž,>ìëX>bàà=fÄ(¾•f >f¶p¾�-># Ü=Ÿ¦ì¼À ü½ ± <ÜN�><€¾Úo„¾|˜�>­BMM¼<¶}>pv>üñø½r>öaˆ=’n¾C)½·öB¾©~<‚§ÿ=B²C¼•S>›ê›>À©á=«iv½[M:=Ùa–½85=_ì½ü¦]­>^0¿=¤ªK<—¡ž½:__>;û9¾ø¶½›Û¬¾-… >Ô¶+½ÓK˜>÷õñ½1í½UU¾½»Ò›¾ˆãà½r!”>(쟾üá)>`>u¾7‡óA:>Iµ.¼×¸¾\oè<ò“~½Úà=¨F¾Þ š=»5\¾�f`>säN=ä ¯¾ò<¼;{¼Ò½ÆG¾õj=Í•¡½z$ê=.«=¥¾=χà=oK`¾Š»h½^Q>R¢;¾Åñ=$7мOÉ<>ϲ=JP{>Él¾XÒ羫d°>ÿ‹>«-¾Ð�§=¦§Ò½R¯»½sE”½i¾O¾+ª€¾àH>OfA¾UÌ\¾ñçE½l¯”¾Ñö=ÀEi¾f„·<ï(¡=§½]¯À=î×<ðb >Úy> 9÷¼Õо�ž=hñ0>¬$Ÿ>UP>‡|ä>!M½�Z,>‘vÞ<§âµ=ÎüŒ¼œ¥ñ½Ç>o콘2‹¾A>4艸òV�½ïâæ½æ¹·½¸™=é°\½á¾Ùi>Vò]½`še¾Ü±Å»Ê*<½¥8Â<“Œ>²�¾ÍÞØ<μg>e=»;Ý©Œ=q°=S(á9·C½³…ù»j¡2¾�/ƽ¹ø¼÷¨=ö3>4/¾À�Œ>m�¾Žˆ>¾¥Tç½ý3=hNS¾M7+<>nß¾8œ½.%š=Á­�½”Gò>ºÖ•¾ÄUe=N©e¾#V½±X6>ÃßB½Èµð½( ¾=0ŠuU¸½á‚N¾Ç¾³<Œe©>®œd=-Þƒ¾°1€<0¾œa[>iÄ‘¾¨Œæ\­=i¶¢½1‚i=YÕ½~ H½Â…4¼Ÿ·a>¡éD½1 Ì=$ÅG¾Òž=|*¯¾‰~¾• ¥=ºÇŸ>ºÜ™;µjõ=E0à�ð;¾ìk½ S¿FP½½¥"ø=“…{½¡Ï@> ¹A=Cô>GÞ1¾‘‘V>¬Æ\¾ »2½Ô„J¾^ƒ¸>>"ûG½6™R=8îa½]yª½ã$¤=‰! ¾Ec½À«=Fö`>‰Þ¼ >OÀ>·t6>yn¾T»Æ>ä%¾�E˜=,ª>§±=©~=J¾ƒ ¯½G*‘>' �½aeŸ=$=¥¿‡>ûŸ€½…)¾ðŽ>g†¾+x>»'“¾ž@x=puh½¼ E¾‚PP>˜Ç >kb€nÔ¸<Ýš3>÷õ½Vʾ Ê=ôD2¾PžS¾¼¥¢>˜?!>áM»^ å½x~>èà½èT‹½šñb½ãZ2½éD]¼Î]“½9¿¥½õ㢽ªHоN;Ò¾ ¾x€š½Û²D¾º%8>)†>ÄR><þm%¾\‡½Šó¾�»K>HÕ‡>>¼>„)¾&A¾é•ê½²š`¾mCŸ¾]ݽG$¦¼"‚!¼�{£½T©­¼Ä#¾:0%¾!½,>ÃÎ�¾­­¾áÖ뽓�¼1¡1>Ãþ¦½\~H>�ì½õÕ#¾ï>>Ž4c¾ÕŸ> Þ¾Mº==H¾뮾ÉûÏ>lÎ=ùP¸>Æ"U>Ú½£¼X _¾N½v:‰¾€`¾£þ—=�¬µ½9 ¾ÿ£¾E ¾07Í=ؾ û>@²>£¾ê³±>>7!Ó=¥q$>:F`=´Þ¾<Î,¾qæÄ¼Q’>Å,>"8ò=�¿ü >^‘b>­à‹>õJ”=[j=ÉÈ�>U‚>°ˆ½ µ²½ ä>º@J>~/C:åØÑ¾Yê>–#â<›µ#>CÂÖ¼�3w¾žÚW½óCÒ>:J½³üã=-@•>\¾  ©=‹ä™>ãµt¾F=½|è¼ê3>-.¬=ïI>"Ñ¿=þ—>v>ð‰˜½ÿ¾+>¡?(>ó>eKÌ=íF< {�¾ñg>ZTš¾Kç ¾ÖµG¾†pU¼&ç�¾0Ô½>_éè¾2= ½ï‘>jáÄ=ˆç4=ƒ”¾SÚñ=ÔO¾N.¾Î!”½ÛÓ½B¤=‡1‘¾K 0>�Ìp½°ŒB>¾²¥×½Ì ú¾.—>Á[Ò=Â�¾ÝÝ4>Æ =ؘ'¾ùY㽉;•¼ý»>2Š>ïïÃ6>!Ë˽žû#=s€¾{Ü«½UÅé<*¶s>Ü᡾·(H>éi¨¾híýWþ�¾¼óž¾�%Â=câ>(d5>GãV=(‘ǽèm˺ Ó¹¾Cgb=ܳH¾7.·=”}V=P ¾�Tˆ=jc}>ù9º=@xù=]Ø ½YœÌ¾^y¢½1,Å=4w¦=ê>‚û’=«ö¾�­Æ¼â�b>dó¸½ÁM=GM�=íq,¾ˆM©½×�s¾`i‰>‚\†¼2J„>·Ø ¾ 龑¢0>¦JÔ½7Ðc½‚�œ¾Õ}¾I¨­=Üù¾=µÁ*>T U=ªÑ‰<Ý:½bó½Ïª¡¾±œ>;¾É‹¾%ïϽ”'U>S›Q¾Ø¸$>ƒGF¾Ü3>M>‡�¾­Ì>½‹VF½ZŽI<’U&>ŠÊ¡½‹Z¾Ñá–>ì¡Ù= N<-)z¾ÃÑ=>a²¾© ;Œ›e½Ñkj>¬[¾*ú¸=*�½xT¾ Ú=®bk=Ön\»Ñ¾9!‘»Ðƒš½°nM»‡É=þ½ã;„|˜>í­>vH1>陽@T¾ŽN¼Vч>9›½àûÀ½¹Ñ>’@">QþL¾p7=3º>L!Ã<½D>EC±»Îôž½Ûb¹ºöhn>ó‡c=—ó;>ôÁ»½4™[>w´3>ÛM²½�ƶ½ )·½…´Œ½/°P½E⸿öµ92¾q› >JR=oN¾2„·=ˆiD¾žf^¼ˆ”>¦úˆ>Åὕ¢<>“Ò™½n+ ¾‚¶%¾ õƒ<̽CFš=<]j>5±À=.uJ=ÑE~¾ÀC¾+9½f1¾Áž¶Ö<ýŠÅ<‰Ë>¼££$ >ùtD½øÃ ½ÅÚ¼CŽ= â=É¥<7�}=òÍ=ân!½œÇ8¾©o/>},»å2¾Ìå¾(Í#½>«0—;]c½<­->Ã{Û½ _½—+ؽóq…½ Sh<2X<r±»vN>µº= €>x‚=¸2§>10b>k¾Ê Ø=ž±ù¼å> ‰¾2 �½Êc=’Yï=®²�>Ï]>•¾¾óS¬½)!¾¥(=›½=Øm>“�y=[¡½””¸»ÿ™>*ƒâ½½å¸=˜Vɽk ¿ÙüؼÑìž½Û˜Ò=MÓ�= É’=z%;U»ß;ÆÒÜ=?×=0ŸÒ¼OU«= íé½z¶6¾Ý–¼KPo>õn¾Á�¾â¡<ÖÊÿ=‹ÿ½¬‰¾F¤>6꯼d˳»Yͽ÷u==iä¼Ú”¾÷j>Ëw=³}=U&<>ˆ�ø=�Æj¾Ã7Õ= A˜¼r½ ‹Ñ=â®±=eª¾HA>×:>Æã¹¾Ã\мʈ!>f!D=yJM½±¼d>á!4=àê¾Rõè=¼ž>Æpp¾1í-> …Y¾ÇI ¾<Ÿ½�_Œ½ò}q=Ý;ß¼F½mí ¾–=>òõL½å×K=ˆ·q>9¾¾Ãe½Nz$¾HV¾¾Àf ¾Y<ð;Q¼ü½+¾œ±œ=v.>S�û=פA=f¸ì½"È.=©*$½a¢¾ �н¾ûÆ‚="ð=Q-{¾¹->\‘†½|¦sü¡ò½Ûôý=¶ë*>ñd¹½ùS>ß.¿¼N¾¾Ó>Œ¯¹;+=ˆ2h¾QRà=õ‰Ú½„ >¹¨ãcR¾â¦=¾#L´=—(J=/~>ª7æ½^€Æ=ò)¾¸d ¼:¬¼¼r=��±=î–´>÷>�=ôå”=Êò&¾"Œ¾Å-æ>{q¾š%¾_=ü“j>–z¾/þ�½ëJL¾ƒ(>yH>”±³>)²C¾mR¿½Ìô½p£¾P£>;ù|½ãxb¾:±¾‰­Í¾“½+5¾®2©»ÇInYü={ô,>Åz²–§»Æ{c>+>t ž¹  >¥Ã†¼n=  ¡½ý-<ïg>£¬p>fד½þ5¾ãlнå,’=¤Y¾ \Q½_|0¾üØ>¾½0½|7ç¼4\,> "O¼÷¡º=�(³½5§Q½ëô«>Å쯽të’¼JJŸ¾ÅÕ•=o¢8¾öH轪M«<:�Û<ÛËð=?>ãm>­z|½ÿZ4="ðX=ê³§=»åé=ÓÉg¾éS¾E°“<÷䫽ä¾qc,=Q9>…Ù3<”>_м?¦å=|}Õ>¯H ¾i>Y¢‘¾Ùä8>ò§ ½5Xá½ôê‹=?ì=M﮽ÆZ÷»’á§¾m;̽߰¦»ßoÇ=$^ ¾˜·¿=?óX¾tÜÆ<©|ž>r�>ÑÆ6¾Áó=©è–¾¢Ú ½Ûx?½VtÙ»€u>:Ê6¾”w$>#ú¾)iN»»¸1=Tö5½dÅE>"½¢=ÞÑ?½ó”ó;¬b‡=éàå=�ï=¾›.¾™ç€:%³N¾5¨Ô¾"Õç½øÜ<â–ó½ðƒ¸¼6!½’=x0f=¦æ¼…U<ŸS…>… ¾«9;>ƒÅÞ<ú¥5>ðŠÉ;¥³r=daľ!N>×@ñ¼I÷|Ô =`¸¾ØJ>ä~…½Ú –½>.k¾dsB=±.b¾Ek>;>«�¾Üüÿ½µšç½¨\ú½C`;×!€½òo>��½½R F>T=¤=¾P£½Ð< <” •=�ñ…½J ¾Ÿ#¾–i€¾{S7¾òžÜH¾B8å½Ó�3¾õ‡:=…cž=Vv*;2b(<Îãô<Û5o>é)†½�À¾H§ˆ¾0О>®)ñ=—E3=èG¾ž®à=Ùæ¡½Ïôw½®…=$1K>ÞÄú½›5½yܱ;ÉÎ>¸¦Á=Â"½cA½ï=Á¯7›}R¾áßâ=FZ‡¼ ­Ù>Rê�½(R¹½ž+c<Œ–I< ÷¾?v{½*í½^_½Sô =ìW¾—OY¾3S‰½{¥9½þ.ž¾âè.¾[s¯»ëú½9FF> Ƚ„—=B…j¾m½Å>i5¾h|¾<ÑB¾÷…�=]ày¾£šp=µɽ²+Š=çZ𽩤G½œ¯V>ŠÛ)¾á2Ï=Žä\¾¼ð =°\n¾Kù*¾HV†½á÷ ½•(­=]<œ–‹½ef(¾á 9=ci»„…=í›&<üî½H¨º=nVß½EŽÎ᪾ï.r=.m=,—h¾óƒ.¾jé=ÐwV>»ê<�4#>ˆ,d<<Œ >Ñ<ˆ½9·r=€R[½+É=F‡Â½9´º7� ¾?»Ü=гl¾£‡8¾äæ$;¶íè½÷Æ>äǾéß=Î.½=oÞ½�ª„¾p¸¾¥@>Xô ¿à½ï=�¾_ÿ¼Ö]=ÆkнN=zä¡=¦oŠ>q±ï½Æ1=3ØÐ>Iy½4«!`�€¾îF>ç` >`DŽ=Øž‹½,ÉÌ=�¢%>ÔÁø½‡EŽ»½ÙŠÁ¾jh“¾É k½aš%¾a…!>ÉX‹>¸â•<ŒX>°q¾í€>>‹q~½CYÐõ=b±B¼M˜õ=W¥ô=$•”<4.>¶æt>­ý?¾X`F¾Y$E= Y¾º±È<Ò²$½Êçå½ÞS¼õÁE=Óð_¾é Ÿ½©{a=>CG>²Û ¿àä(¾´E޽ƈÖ< =>Ýl5¾BÁ=Š"½Ôž•;ŒÕ¾Qbí=q•½kµ5=™ö½Gt=ל=@·C½e½6>GÑ ¾*#¾6�Z¾á)€¾ëU\>Ç1‘=‹=½07ö;Vc»¼ôæ¾tñ�>ÅD>ÏN½™.Z>ÞÆa=+W¾¼¶ÂI>К[½Dz𽈼’=ÿ×Ì=¸½^½ê@>¹g༥Ç<ôV{=ÿ9�=dF‰=“oÒ¾ Çn» ¥)¼*÷½ņ:Áà½èæ½H=Ôü½º—õ½ùúÔ½s«¾—HI½Ô$û;öZß<%ða=¦/è=ªõ²¾¶ƒ½ÇK¾;Lã½3'@¼Ñ¼g¾!œ¾ “>šª‡¾Í,¾lc¾÷£E¾€™ˆ½ÆÅ<4¸&¼–͉¼éI>+„j=Mi<½ÿß“½¨0»¾?O¾ó¥½44>‚a½=�ók=Ü­C¾ìÒó=ÊȽ¿u½'R=ª¾Åòb¼ øõ<`Ü~=^*…½"`0½´œ¾þ8Õ¼ÿѽ0¢8=IŸÌ»€2(<Ý*=~@e<h!½µðŽ=âÿ"=|J >hQ€»K½O}ÞËY°=tÍ#¾+é¼2—=Aìæ½K,.;–6¾sܘ=Ì5/¾dÚ>•I¿>—Ø<Ÿ`e¾A*Ä=Zˆ¾œ¾ôD³¾C†y½ú–�¾ :$<

b‹˜×W½aÎ½ŠºØ<~c4¾Žª½SË·¾î( >¸Ô&¾g0O¾ uP¾P=}ÿ³=8”>r­Í<ºßG=òXŠ=ºûÒ½!̃=¾Õ/+¾E~±ý0¾=ÎT;>éz+¼–¤½jaß½ï¾ù=–�½Ÿ¦·½¿Á»“‘M¾˜F=Ùžë;K췽ʻ†=‘öu>Е=¯Ñ½šš¬=\�´½;§¾uh<ž3N<ô{Ÿ=ÑQN½Nƒ”¾y]�>éúÔ½U†;ïü <4ê˜<õCÁ½ôè½÷,|>4q?½è•‡½±™Ð==`Ó¾;0½¡ >AH¾c¼ÀL'N¾gG2>»“8¾_²=™¾9¾ç2¹½rc>áÙ¯½{4>g�½g‹=…’L>Üâ= �<ƶ=Öá�=â¹½Qv¾Áðø=“aÑ<©‹ ½ßŸ�¾úi>¹ˆ^>›eL>£°v¾‡-Z¼|AC<ó>m—¿À1¾Äf=,Í>“„–>›ú<%G>Nµ›<É–æ=‹¾nL>% ]½­d‘<#.Ø=“€)>Ò£Ú¼>¶•>£³—>dHÆ=¼ž_¼¦W±=jKW¼ÍGÁ=å>ï)оÙj®»trC>ƒ.º=ªŠ”>ÅÉ,¾ó$>µJ>¢�»s˜¼Š „½sö½»�ð<ĵK<º–='¤¤;-~ý¹=Þc=HøŸ>z'=8²½i�¾ù)É=v—w>¡(¾|èé½€Àâ½÷ñ}¾útǽ”=½h½½1Ô=Ù# ¿¾€œ¼†Áî¼ ·[>n ;=¡‘¾»s"¾%XÃ=“†‚½uˆ¶¼ P¾™Ý‰¾µÚ¾üEW>T÷¾Y‰¾½5¨;¾ð.ö¾»Ò!¾ž¨v=Þ¿/<ì·›¼Ãªª>©…>º’g>ÒÁ%¾f]…¾aÆU¾¨'=Þo¹¼2á\>¸šB>mϽæhÊ=³¤=|ÁQ<6¶r¾ë~¾²LW=k¡Ò¼˜æv>Ø�=ÐŽÇ»âjö¾ü>¢–t¾šïÛüOô½â4>�d=AN–=Š› ¾5ê)¾»f>KE_>NL̽Uâ<¾Ñ�޼‘¾0p'·[Ì}<^tG¾h>â…5=ØZ¾ µ>�¾å–¥¾á[€=4F¤>‘�¾¸Ó»ã>Ö L>|ÙQ= •9¾N”�<á»�¾™+>a>»¨®¾Ÿi%¾W³³=/96>)�¼ ¯Ç>zÆ= 2k½Ý^¾Sîÿ=øU‹½U¾FÊe;§áJ¾n�¼­xˆ½v{½s‘¾ ÆG>’†Ö=jÃý®7x¾üï‘>;CÅ=å†,>ÓÓ<¾ª’³½€ŽŸ=¹éþ¼;Ôw>ä(”½¡cl¾Ä5 >9o—>M;>ײ©»UA]>Ò½‘ÄE½õo¾U¨¾—¥§½?Wæ=¡ë#½›¢>îê½é°’>éi£½:Þæ½'™½ã{7¼Ùg½^æÎ½¶ÿ%¾–KØ;Ñ ¾ Jƒ¼n“»½î ݽ�·=AK=ÿL=�W½Õü¿=Ì~—½ùï}¾ÏÝ¥>–7œ¾?ñÀ=ླ¦f>e$6¾1¼½!"‚>½gž.´„¾�10¾Ê¶9=©ì =}t‚=˜Î3>ö‚�¾Õˬ=�~³¾ý,>a±2¾ÿ†½0îÉ=’ç@¾ˆz&>Íý�=P‹d¾�iô=/xÕ=&¯=”O=9K¬½œ}§¾àà½[e½‚ˆ$>è3ã<àß¾q >Ã=Ãå~‰¾8H¾áë=Z¦ï=š¿aƒ¾£q‹=Lࢽ^ù`=HUußZ;¾Æ·…<•Eç=€Ç½Ô’µ=¨Ô¢½ �=3’Œ=a'P>m®¾î˜ˆ¾,ð2¼$ß/½¸Ö¯=| „=Uéó½$á¾[ë�>n&½=ɾ>—ð»÷4½Y >éƒ*½ºO¾½Y>„òÒ=בr¾’�=××o>)hq=þ,­½eç½ÛÄ>(º½ öW=Šv�¾ú_±¾iP>× ?{#X¾¾�e¾j½E)¾ž…„½A>h�T½£�;ž‘K¾A—V>¨ñѽ(g(¾e�¾òí:Óo¾ç´õ½fà)= 9>x»ƒ¾>î8¾«øü½àÁ=%çx½[z0=¾8z¾™w½./�¾Û1ƒ>„§»½IÌd=¡Q÷»*2>Õ 3>+B¾‡X—½ ‡•¾nF¾LAƒ¾S<>|~Æ>XéP¾mid=�¡=ÉÊç½ ¦!>÷4[÷9¾«•ÿ¾½ß¾“G+>­¼>ö‡¾H†î=Énš>þb¼ƒg%¾¬¥>Àgѽ"Æ =9;7¾Xhç;�àê½ÇE¾í<¢¾3®½Í¶i¾áŠ>퀸¾®t¥>S0C¾¸¾´»¿½-â¾ÛäÕ>ð•N¼šÂͽUH¬½(6½Yò4¾µÜ0=�íÖ>d”¾s>`,<»n;ºôg >ÑqŒ¾À¢»=¯O ¾¥„=ºç/>dÑ ¾—D3>a81>WÓi=%j>>2h>ý#B¾³ +¼ÁD¾¹c>´�{¾hª‡>!M¶½i�“½ØD™=Hö&>„ìc¾]ó¾N>�>Ž[É>n°¾ˆN¾¢¨>ï“J>�#(>žÞÀ¼sý�¼ª5“=ñÓB>¾¢>‘$>]#B¾O¦¼A°Š>3óä½Wèu¾\®ü=1"¾¾Ùã<Ì{_¾å¾ Þ[¾† ½Ã)Ð=2'¢>8qp¾?À>Ekª½Ï£ù½Ýü¿½*m}¾ ƽ£2½Ðx<¾ù i=7ÔA½�Ç=&%£½¤¹Ê½ô§>Çì=í[•<¾_�<üj%>ݪT½ö >W¾-¾²ž�=s ¾¦‹Š½r¨3=úãR½»Üå=5ñ<(i½Ø>Ó&;QÑ¿Žâ->¤ë0»a>�+>A›£¾¥’i>*2ý¾l‡J¾šI&¾‰³X´ï<þE‡<9í§<è@Ë=g#R>Ô0ß=³‚ ½ªÉ >†äy<{]‘¼’µ2>…‹ë½�~›¾±s}¾íº2¾ £>Ü#¾!ÀŒ¼CØA·pQ±=x3À¾ë>ñĹ=lÌ>4>¢©s½äPn½å›K>òæT> �¾„^R=Ûó=u'˾öP>Æq÷=É V>šÀp>é3e>&¥½ÂU™¾ X¤>ŸC§¾*y“>MvT=~w>å©'¾/ù\>dˆ�¼E«B¾0«þ½ùî-¾¼´ž>xŸ½(�'¾,ú˜½ì”×¾©¬ü½Š|½:²a>�ôÔ=ä½U¾�©Ò=úŸƒ¾rwB½µô =»p›¾Ù®x¾ÀQ>1‚>qa½§6‹¾ M©¼ž >yïå=r§œ½³Õ†¾•3o>l d¾²­o»+¾3¾Tœÿé=¨>k¢½mñ(¾à2ò=w<‰½‰»þDÛ½.°µÙ’=p=kÒ†½YÄÞ½C0<¾zG½jÅÙ=1Ú<Ïû¬=ýêµ>¼4M>Ü�= î=Ö^¾wŽ‹0Œ½›FS>äÛ¬=Tž4¼ÅDa¾$¯„¾ì…U=²àª=Ƴ¾5m#=·�ݼ}ãO¾[k켃p²½:ã=©ñŒ¼%ƒ> j=t)>Þà¼Ðh?¾~£½æ_„½Ö£O¾ÀõK;! =%È=lðñ=£—µ½ä6m=fÊ1¾÷"äŠ"�¾v0™½˜cÎ<Äa²¼ü:¾÷–½É±‰»ËнëhO½@ƒ,½{[<Ⱥ(=+>éÔÁ½¥hf¾ì~ýî!ê=Õ8š>í­³½ýó]>K>9~>tñ-=k5J>Ú²>dÓ½=�=„•½’[/>(~"½¢ x½\‰‰=såÝ@?W=dúr½ï~“½Øô½ìl<<„.½@»'Pì»I­½.dD>ÍL°=wkä½v2>i2º¤”½=wͽ ÍO¾4]q¼º1W=ÌOC½Ý´ª>kUQ¼BD“½®¾M‰k={t%¾)ȽCc½PÐu= /j<å¾�ÎŒ>‡>£V”=yí¾¬½=;™¼î_>¼r*¾øÜú½¤Ã_¾»ô¾Ö½�½x‡5>&¾��:>ÚŒ,½ˆx�¼ïõ4>5žP;ù%%¼Ñß½hå§>Ú =šù½ ˆ¶¹AÖ½Y#=Ú@>& м¹åè½xÀ= ƒ¿¾þQ-¾³éV>™¶r¼V %=ÇeH=ŠæU½�ó›¾ô›È½‹„8¾ ú\¼n›=诪¾˜0R½íÖ(¾Qžú½Hðø=脉>O5™½OÕ¤=¡/¼¢¨ƒ¾¼k¾ïÁï=Ö >“ÎH½7/.>ˆ½Ä½}’ž=”Þ?>£A;½2¿·»v é¼x‰=‘“Ú¼vÀ½RBнïî¾–Âļ­J¾%ï >A—‰½[ƒ<½�‹7¾ññ_=±~³=Ê->6E”½"y‰>•Y²=®0¤½'Ý€=Á»;…NŒ¼ô'D<öEø½Jœ‡¾¦+ö¾Ï;=›´…=ñg½a ØGžX>ã =ÆQ>1�}¾nÂ>褠=¼l¾`ù<¾Ìw¾ᘼÓ7=–†¾b…½¾ë»½6 ¤½/ô.=�¾š½éßȼ`:>bR> ˜H>³H:¼Ò¶»=1͇>|õ=”‘Ö½_P)>œìw¾J¶T=„7ö½ +¾mоKå(¾KÐÁ¾(ò¥=Ê'…>¾Io=•ÿ>¼ ¾•0 ¾i:Ò½ªçâ½áÉ!>FÚ/>Kí<>d±>a¤>sì ¾ŒŒ:¾c`°<�F»¡›T>y¸2>0‡Ö=�/`¼ÁæÍ>¥ÞF=!}9>é€k=œ+_»˜öí¼pÁÊ>Ê®|=|¤‡½¨çy¾󇾨yž;�æ >:>¨=>w—>I»>I�=k“D¾¦Jï½—Û{=Åòe=K\>«„¾Âg½ç¥¾fc�½I>¾6/>‰JÅ=`ž=d\>ó,=S}ç½È‹=е=43 ?Þ<3¾E’]æ.‹=Zu¾Íé½ÛQ˜½Õ©µ>ò#¾Èí½‰y;·0p=0–º=|”ü½œÄÎ>Rqã½�þ< ¨r½d©½!È–=ØÎÝ=K{½buÔ»§¿>Ü*�=£›„½Ñ®C½rsò=˜Ñ�½üµ1>â¼ ½Cõ½K{”>ìù¥¼à7=ýÜ…½¦û¾Ãð=8†°>ô]µ½çö½¡©�>¼—>2Þ«½Ͱ=0Ǽ¯=\_ß½¼·¦½YD¾Ão¿½sÌÌ=êñ{>ޝ¼ó|@¾í#G> ±@><™¼DÅ=® P¾æF¥>5Q.>ös4=rˤ= àú½œn¾;: ½}Cw;ȊŽ!4ó=4³˜=[r‚=)ÎI>ùÈ5½ôò¦=µ+>'D2>Yÿ[¾1ñb½Ç0ξJp„¾¶¬�¼z¿Í>Ѿ =i~¼ lõ=ôbŒ¾É�=§jó=4Ýý¼…ö·½"3f<),¾Ùº ¼Nw >Å¢Y¾„qm½qYÚ= 諾Ѹ=yï—=& {>¿¤¡>Þ >Jòô½Xˆ=ºHr=”ä½1ýä¼–£i½„íË=‡è]¾xͬ>Ônš¾±/¦=u<*> ¾Uʼb²S>‹^_¾›—½nYO¾–ÌD¾è‚¾€+½@}Õ½5ô|=Ô�‹=Ò×–»º-¾³å:¾å3>þÀ´=©_½.N`>q-9=–p&>è±=äÖ�>„@ ¾³d޼ɷ_¾Œ¾â¹½Y~!>�H½K*=£?ù¼ÑÛû~Ù�>á}¾É¬ >.¦Æ‡‰9><¸¾6¾è¡º½­ÛÃ=-¾I�)¾þ $>ѱ›½)pB>Ú¸¼-:¤½0Ùô<Îbõ=ˆ$ >‡8o=._z½´r ¾òUe>A¹¤=]=ª=_B:¾Ÿ� >—b¾»L¾ÔGJ¾‰y(½ µ_¾z&½¡\>Ð_Í)f$=[·½À½3Œ>à¹\¾–e½ÆA¾åªu¾Ù·Ž¾™Àí¼äd¼ट=ûG’>ªúš;ƒ#h=Ë™ˆ=—ø ¾M›-¾;Gn½ðâ?>I‡ ½“;œ=ˆ�ù7õ¾›Œê<‘½–=<¢Â<ò/ =6µx>ñ/<>Þÿþ½p‡ ¾3’Ž=ãÔ½E+Ÿ=«ž#>o­ƒ¾ïJ$>ZÂy>ë6%¾„Ù^½‰ð>«ªZ=ìt‡¾5j&¾œçL>Þf-¾‰P=“ZÄ=ˆ2½¨.=7)²½[Š<”90=�½‚$¾†;…½fJý½«z ½Yâ@>N®X½�Ñ-=òº¢½t^=ز¾YûŠ=-Ü×=[$¾11 ½�œÖ½¨l¼=víY½Ix½¡S >Qj5m®>Wk<™�½|åê½~–&½Ùñ>¢§¾Â騽¸½€¾¸Ï'>×¹Á=:L=õË=<íò=;ó(>WG’>ÿ½v¨q¾‘ç<ù›¾ßôˆ<�7B¾¦()=Â�=èYS=>8 ;3é½I¾ÛNª=»\¤½, ¾(“¾gÇ)½sÉ=üV™=…U¾µs„¾”ÀŠ>û½B¾jÇ5¾zµ‡>ãæÖ= ÅýÆW>ë= >]¢“>ÍêC¾M+=­¦â½t:A=Ïb…»­Iнû4y½®ç½*>øK¬<ÈD7>X~Ý=5@‹=I® =Å}«<§º€¼HÜâ=éÚ>�¼>ò/B¾ÈW¾Z•H½m¾ì„œ½Ðò˜½©Ñ<+Uó=òu‡¼•ñ‚=±|{> Úî½þ�š=¥G€>V¾î½»=á >4¢u>º«C¾¬ë½§‘=Ý„f¾dÄi>R.Ã=‘¾½†�½ÿ™>úò€¾ã½•à˜½Íå^¼Šë–=²$I½Ã  ½EE½{Ÿ)¾s²‡¾®X¡¾’A¿½/Ã=˜Aô=2µO½ß‰µ<:Û­¾BоÂx�¾üg½å«ˆ½ÄJr>T/ =š4Z>[ø=í¶Ë<=hi¾Qw5=¢jv¾jq‰>³d>®�h¼0ˆR½¦7Ǽ-¡2=6[¾³Oc>›ãÚ=ÀB{>½Æ´=«a„>ÎÏŽ>;7®½o¿¤=êš§¾ÑC>Ag =ê¤À¾è¹¦>v'¼»T“_>»6¦<0û6¼ØY¹½Œ�a½°rD½ˆù¿¼ ýG;h½Aå9>ÌF¤½£´I¾=ýÓ=ŸÎ�½ ¾›Q¬½ªŸ¤½)§‡¾gF)>ˆm]¾Â׉¼˜hj>–?½;I½µL]½»Z˜½eÔM¾¿âØ»Ýþ×=Ìôo¾– m¾[Ná=Cw=þ‘”<­åI½˜Z=¾0d¾š‹1¼œ€P=ËŸ¾,õ»ÑĘ>AJ}½†þ$>ðœƒ>‘ F:ÀÓ›¼;Er¾òê<õ8F¾Êâõ;œÉl¾‹±¾Çn¾ÅŸ½µ_|=ø"==�ß­< ?¼Ÿ…W½å÷ȶ™=:¥n¾s/Š=—ü=ÕB¾½Ë¶=ýˆr=;¾üî)>XI…=mTz>ŠýE½¹Ãj¾÷‡¡>ðF¾Ìeú}šì½a±>ª°Õ=ô?5¾ÿþÛ=Õn ¾.Ã$¾€`»½ò_œ>>óÕ½Dp<xb½YŒ)>HMÛ¾ã'=öDš»ÿP«¾2/I>—!‰[ŸE¾—°Õ=‰´G¼.�ɼ²8>ƒÄF=‚Z>Ñ[[¾äöt¾­¶¼TÂ>$á<{®¾^1ˆ¾…†[¾«å+>­gM¼ï ‚=E5=½ÕÓ½QÁt>óì0>–ON=Þi‰½[îD½O‘^¾¦~Œ>5´T¾|\Y½îf>5¯½¾>Ö¼éæÓ¼X½>p[ê¼þ°½ñïØ=2dŒ>ÀX«>5s<4}d½þç <í.�½w2¾¶ãƒ=ÌÚ½„à}¾Pº>…V'>•N�¾¼ÛöºUPD¾ ©U¾Ã†§¾pºD>äü1>¿¦�¾¸9= ªh½¢Ï„>³r‚=5¾�ˆ½.á½eÍ=½M&i½¦¿ì=Dvõ½‰H«>–’_¾´ƒé=Mƒ[<ጼjî�¼�&ß>ÜT¾�õ£¾÷yÈ=ê/ù½ç6N¾!¾l†¢»LÀ®¾·ÃÏ<æ�'>€¾>"¸L½›¤º¼ƒðQ>þŽ<ÿ�ʽ$C>*œÂ=qú½î�I¼ü\7¾8ÇÛ¼(æ±;Q$6�á¼O¨7¾_ùý=n¨u½â£½ ß^=âÈ…>Çh>­6J;ºÿ >pŸ*»Û!¾½4Ñî½½ �¾>¸·=jÖ=6˜=DÙƒ¹ú ͼ'p!¾D·B½}ྛ\>På×½PÚ¾Ü4>„˜ð<\þã=¾Wx¾ÁÏŠ¼4úJ¾¸ÿ>ò²{¾åHþ¼Ãtí½èJ7;õ‹E½èx3¼dNd¼Çÿ÷¼Tó8>¨"<>æÂê=Þ\Î=CÚ%½ÄwÔ=¼ï½ª/‚>RÀνÕÀ >`¿S=ÑÄ�¾Å ç=]Å,¾�}ý= ®>ÃÇð½Yy>úŒ5¾áí༆ÔV=fý >Xgˆ=OÝB>q>ª;´H¬=ÿ(æ½Þ.2¾QBø½äùê=4oнqª÷=‹K=WW­½cŒu>×@8=&Ô¼ÑK�¼“Š0>Ûߘ½ H>ÙI>ÝÎ&¾˜€ô½Ýµ½ˆÚ=løÁ½§Œt>SÙ¶¾õq½'ä=F]ç= ¾Æ·½ä$>Þ:É»ð¢t¾z8R>UZ~½Múž½Ï�é¾qøÊ¼Ä¶ù½Lœð½šSˆ<ç6¾ŠP.¾/,Í>g¶[<Îtн5'>�Üc½ÝzX>œ'´=¾¸ >Ó!†»àjܼ´í½ú2Y¾J0½x Æ¼3¦¾yLP½¥0,=¥�½Dtq¾À¶ê½w3‰>Âß‘;ؾF¾¥;>c$¾«&¯=Fð¾„D>°™M¾Î¶=n%[>#Ø�½_H¾½§ v>æ~-¾ew=•qU¼�,¾'£ =¾õ>bºl¾6§¾f&‡>Í�Ù¼ÄDH>òL‘¾�äÖ=.9¾ÛoA>˜ðö=;¿´½î²+>QÔ¾¾�¶à=ƒÆ<uÁ<[N†=…§ô½A€ƒ¾·…z½Ï¼->ú²7¾ÿ%r>¶-¨½9i³<À$½ì“š>T"#>ÁÖé½—Zν?av>\Æ=~Ö¾?D¼¤q®½Uw»dxŽ=Áp>ðü¡=�Ñ.>‡@¾™ a¼“¾Ÿ>îú=ž—™¾ù¯ý½‡¤<, ¾Ý¾'~b=€‹,>+<ò½½ƒ>žÆ�¾ƒµ•¾eºœ½Š’h¾c�ؽ²j‚¾Òzæ½Ï~K¾ý*!¾´Yþ=&ƒ–½;„M¼•9M=²-V=2Ž>òÜI>ÐaŒ½GÓ°=P[8>\Ç=F†®= +Ô½_¸J=æÌ >/ »¥0>⤿;4«Í¾9Ë&¾°•¾<–w¾ôM=?=ZA«½ÒÚʽª_Ë»�ì;½Ê,§>Æ�½ýž²½¹éè=Ë‘ ¾6M >¨Óƒ=‡!±=[Ì.¾Ô7>Y'“;—Ô=s8p¾úƒ“½ÈšÍ¾_ ¶½Ö¾Ñ™4½õçÀ½ (�½Ò̵½KV�»wþm¾ÒÄ2<§½ô]…>Ð7½4ÿ:¾ø`½ˆª<ep¾½ôÀ½Ðtï=lp;µ×q>@Ð%¼êغ½l8=¯�¾c2¯=ˆ‚"¾kcæ½¾Œ>¡˜)¾ï�ˆ½;¾Y7¾­<ïÅ‘==‰¾é¬˜¾RjA>�êŒ=-6Ö¼òéì¼Ûô…¾CÜ=½>”¢“æ¾Î¤Ý¼Ì{d=‡Í=yTš>Òõ­½>ë= ml¾O�Ծȇm=Þ6�¾¾]<ý)k½´ 6¾6.ø=Šþƒ=r‡>¾Ñô½ñD¼±š>½§Å½ÒVe<ò‰=Îß¹=ʤ?=¾nq=áÆ„½cª?Éô¾ÃBa»†n°½Úû.¾p6<>üé;¾àˆ;Á`–·N<�Qã¾ô1½4HÙ=\°½JÐͽ›¯d¾Uˆû=ž›´=Üâ�<�T‘=@¹½ÌTc½×#¡¾|ºð½8gm¾ýн/U�½J”¡¾Þ*�½@“ì>Œ"©½hÕØ½·ë=�b»=Ð�ž= Ù)<»a;=¯¶*¾ ‡”¾Øâ¾ñá<¾;Hp>ÿ%>ɾ«æä=ÛŸ=/2¾ˆ+¾9Öh½›¶Ç<¢´½Ïr¶½îù,>‡Þî<¥ï>yÐ�¾v­¬>?‹ ¾fîû½uÕç>ì>Øÿy>²´t=?��>×¥¼‡ƒ‡=Ö†½S¡)¼<3>¼Ž >ÀY¨½Ü ¿ûu>‰ë|;öÖ>ù0é=+œS>y¦½#Ka>8r½3¡J¾�F5>*Jv¾e\•=Õ‡½Rx¾÷ÄR>¨š[½±�=�!˜½�L0>ƒÛH¾ú7V>à¹A<Ôø)=ÑE4>ˆÂ,>Š[.¼ßºì¾Œ<Ò="Ó$=4&e<ÉÉ̾ǯÜ<ùY¾+rK»äе¾Ÿë:YÛ ¾'†q¾ˆØ¾ÕÉê½Öβ>[?�ôÈ믩<銒¾Ÿ¼½´Õ3µ¤>kä½B ½Œ>ÒÎz>øˆ ¼Õµw¾ñ/>‚Fp¹W=ÕT¼¾˜zZ= Û<>�«Œ¾…÷0½Sþ9>ª�r>i2”>7ûÁ=þ.À;­^©¾ïÚ“¾šî >?™O¾p ­½zx:>!³Ã=Êa4¾3Ý6=ÌHª¼‚v­»dÙN=f´‚¾TA¾è£€=F„=Ú ˜»Õgþ»öb¿¾á‰Ó½¼>Ó�º=éð>©²~>µ®ó=XØÄ=?ˆœ=øÀ>Þ„ ½Ríÿ<ÂâV=¡"£¾N¼“>±=½P>ýټݮ@>ºŸK=—£­½:ûý=“±”¼4`n>•ž½}²e>¡›•<ª‹N=`uQ¾Ö¾\šÒ=ºg™½h=l<=C¾èy> …Ô=I±½}¼9½¼L⺉š3¼7[R=b†Y¾ß6;TÞ>÷e[; %°>³·O=ˆì=őʾ ú>Tžw>Zç%>à2“»bÆ­= ·=“Ç=2‡¼¤2Þ¼SÕÉ<#1J=ãâ—>V+>Ò·³=ç¾ó<=">;E‡=s�¡=M7�<„Ó‹½õf>6ý²<ÛB>Ì”ƒ=½*>9>�8v¾ŠB}=¨I…¾·/¨½1ÆR>yJ¤½$ýñ >Ëa-½ñ†> ç‚>ö(<'¥«¼^s¾RSM½Ùu£ºÛܘ½m”˽,r!½×˜g¾ða½FT÷=RšÖ=‚BN=šÜ>Y|á½;¡ë½KfܽÅÔ¼üÛƒ½øk˜>% <’ƒ¼8¼£=8=5ZÞ‰YŠ>ÝÏ>‰äH¼Zaœ;„O¾Þ`½¤z<�J{¼xùC¾ˆ=ȼ'ê¾iãA¼N/¾¾�V>|?=( ½pž’=±½¿.š>[½9>En>PpW>¼¹ç<ßÚæ½0¨ƒ<_¬¿>yÕ7¾•RJ½|¸½ 14½nò½�½1>äû=®ü ½“ 0>’P[¾¿>óú=T ó='O_>óm>-�p½�ð ½C/ ¾¯«<¬!�½‚@ ¼&ñ^½#3:ŸÛ>`Á6¼6òç½Lî ¼b;‡=óB¾ښ>�…D>"‹&>yq=(‘½÷Ü<¿U>l�>>²Ä½0X;¡ ˜= x>œøÎ»¦xν ¾úQ­=Gµ�¾|[ô9­JH¼_=¾c J½šVS>öÔ>µÃú<ÉD˜=ƒt‡¾Ê­»½i¨ “¼ÔÐݽ«Ç0¾Íþ¾=/ƒ¾Iâ•=ÛË'¾%¨z¾¾pš½–]%¾4v >ðî.>}wŒ=ex¾“ãÓ=/­æ¼x‹=D]½ Õ¿>4q«¾ű=Ô#'>b]™;T@¾»µ½{‘ ¾áV¾Žcu>.¾»>°f=д²=Ðz¯=d{…¾À9å=Øú¾=_ ¡=Zïs¾ï¯¾ª�> N‘=¦–…>�Ú¾_**¾É$–¾@´½–˜Þ=æ x=!í�½ÙOp=fUÔ½°@«½…ù½Áî½,¾¡½Ž,­;~‚’½ñ�.=7¬>1~+>íÚ¾âÜÖ»V‹ä=±wƒ=Óê*>‚!=/è¼[ëá½B°<â¿3½„E¾mEÞ=¹ö'¾u�>=†=`¾\½1½D¾šú�>‰…¿=gÀŸ½7.ã>;TY½1A©<…«³¾¤!•>‚|c=f‡¾Úߊ¼èF¾èH»»_,¾Ð˜¼�ôÿ<¯–Ê>�…½šù•>If½u¾=¨%¾Ë ‰>Bàø<Šp“½Ùe¾9v>u–©>û�ñ½]>È];¯Ð=Ê`õ<”A¾Fˤ¾‘©à=Ôê>Q)G»T¾ú½‘0Ÿ¾šô8¼•ã´>Pï>�ÿ ½œ~>Ù¶{>³N³»;U¾~ƒ£½�î’¾ýÆŸ½4±¾^ñ¾8Ó™¾Âe>Îfý=1~Ç>š©>p×g>'“¼ÔÕ…¾zÙ±½˜ãñ½·P{x¾^z¨¾¿{O=#Up½�\#½×ƒr=¨ú¨=”Ì<—ŽL¾€qˆ=V1£¼÷ü¬½9—>Ò[;½-¾/½>t^>õæä+·�¾×QS>ðÏ/¾;÷°½.„½ÿ Y¾q²›;�#ï¼<¾pSº½�…X¾}©U=ÂÆ >•“º< ªÏ½Ý–=¤V¾øèÿ=[>&¢—¼Àù´½f¹¾yÕ¾¢ô#¾¨,±=ˆ[¾wÉæ½n€^>Û^¾Ò0v¾G,¾‘ÛнAÌì¼Á~ >t=>ÈY³½¥í¶¼3’¼xÓ¾",Î<¬q˜= ’ýºÐ ‰>cñí=¼?×<¨9ç=î™%¼ŠWM½ |m=�Û=pu=leG¾¶�€¾Òó>z¼É=Ò»É=SNC¼5=ɦ[>”°!¾ á?>‚E¦=¿J½±®¾SÝѾí(¾9u%>°ø>‰e޽O{­<\Ýß<ÙÔä½€ë™=˜i ¾[P1½‡Þ°½�|E>ìÜô»fÂò½Oa¿’êG½¢‹6½ãZؽȕ ½�X½½ìF®¾u(=—wK½Õ½Ë>¿°I>j—Ç>Ó°†<®ß9=ܦ>¾¹Þľ?õ&=ÿmQ¾Ì½0<'˜€>ðSõ½~¸=Åj=íÌ:¾Þ¯ˆ>„fo¾½½µ&r=Ãóù< £4¾T}­=í‹�¾r$>ËÚ;=Ö'>²ÞŸ=W5 >nj*>¡û"¾Y½¶=Ì-¡> …½–ìB>À5¡¾("O¸½A= ÊX=ÈX =™4M=4˜,½ÜÜ9¾:œ‘½³#¾åý•;Ä1³=³¿â½¢xÃ>"Œ >ºÇ=!*©=oë¾-ëí½‚^1=J¹= ·ñ;ø>hÏš½fÇ®=�¾q=+¯=Mäˆ>ÀÞ‘¾»Ñ>4î¾µ¾Û(>3 ¥>$"¾ë®–½ð·=·Iê<à —=yŸd¾¤0…=‰³Œ=k^½\öÙ¾§@n¾Ö�½ïžŽ+>å1¾~/X>5ò½ç¤>næ½öZô=Ü£>rˆ=z.j¾ 4 >lq�½/Ž=•Yf>ˆÜ ¼ó´ >ãóÀ=G Ã¾Æ&>Œ=M•1¾#eн˜.t>0 ¾çô=¤51¾Ý•†½l¨¬½"@™>-(y=ô·Ž>nq+¾‹×�¾Æ >¯~ð½§³»�wA¾ñæö=³¯0¾Š¤·½ãëÑ9ŠyŸ¼­¥¾˜Mž>a+’<©¸=w !>J¡ô<É:;½ªÛ¾©ŒÊ<(?K½R7w>��½ýí!¾lX=¼„C¼ó›¾="=|C€½æ$C¾×aŒ=ìf®½€ã½´ä>93>…Ü=µõq=RÅð¹ I>Oà~>Hr>_½yí ¾´¤<5=Ø"^>a�_=6>«ëн}_ͽxkd½l§Š=t8F;ÙÆn=þ ˜>ÿ¶�½¹¹=×ýR¾• ]½l½=îG`>‡ÙG¼Ëì�¾¯ݽ„§ƒ½5¶,>7Ã>êøÓ;-‹�>ÌFO=˜’½=ò(×=²¤„=*`¤½Ý®"¾5š=?bŽ;„`½çˆ‡=4%Q½ô©>7n�=áW/¾ •…½•cx½xb³>�ý >*_>¶¡°<¾”]S¾ÀG¾ø½í»/V"¾ŠRë=¼‘b>ãO#¾ÇÉ>T5q½ÁÓ½‡¦=³=x”>ºö�=š¾d¢¾ÈQ>5\ø¼ cã=*õ½ÉÇ>¾ïÞ½Þ8¿<@{ ½B¬l=1„p¾áËq>Cs°=Òý>4¾?D‚=R³>³Yz>e†Ï½Ój·½#Z#=-;-¾˜}�½ÕòZ½�0‡¾™©ì½µ­�»›]\½ ’¨½]©/¾.0À½õ“~>º›>’Ÿ¾³¡=r9�¼Â»¾"L5>H¨‰<¬í=/—�½Mø>�µ*¾‘¸õ½¶ýf>’•Ï=œY¾”ž>’—R¾—u·=”WÛ½ÿ¨_<«·P½6¬$½Œ = ¼d¼vêˆ>ê”Ó½vÀ(<6Ð<2=>�G½™†%>ê!¼Í ¨=¤d ½%ÍF¾ÍKÚ=Ž£>nÿ ¾ë¯3>ø}m¾D§½Ý+�<™# ¾v—r½Î>´È=r6=+Þï<í7M¾üfV=ÄJ©½f„9¾ñz>ºÀë= 'î=§¤>Þg=GH ¼µ’=‡¡(>Y‡¥=ÿ-c½%,=øm¥»˜¾‘x˜=¯Sé= oZ¾ y=ñr>sÛ�;h+Ü=Öa¾ %;¾«öi¾ b8>¹�\>b"ö=“�˜=�Xû;Ê0u¾³Žœ½À;´¾Í÷C¾(cO<¨™Ì½õù>ä1{¾BŸ¡>÷3 ¾Y ³>3פ½öð>¥7¾v…Ê=òlͼj_°=þ ¼G<]¥Ü<¨…E>L¼S; wD>ÿb¾ÙlU½m³!>¹�çܰ½+ì> 7¾¹#¾è´ >ãO¾Jþ½X¹ß½qái>1ò<Ë^1=ÂÙü=¾š¤½Æ):‹—¶¼žŒ�½8ùŒ;Ž D>öè >°ðŽ=¾às½ÆéÇ=Äì¤=Îr�¾Pª¬½èÑ%¾Àɨ=Ò#½!îþ½Z ¾ŒÆ—>OAF¾åÀ‚> ‰€¼xf½¾@’Ÿ=!.¾ßÿ=,Æ�<·™=»ñ>F×€=Õ‚ï=¸Ñ*¾;z->±Öl½ܬ¼]{Ï=¹ã(¾L3 ½ê3ô½ÎG>Ùµ¼(Ep=ÞΔ=¼h>}aË>©—§¼þ�l=/Ô¾f9 ½R–¶½äŽ@>Tì¼%£\¾¹ëž¼Y>Qà×½ù`˜>Cü>›Oà=(ì×¼—'>g8¼J¬Âösè½ÇÛ}=ƒ·¾´*>Aæ=\¡ó¼ X>°‹=ÑŸ3>Õ.©<ݦ=k1‰;eï >%¸"=B�¾I¸O=ÞFR¾äÕݾ•†m½$’^¾ˆ²µ=˪¿=®dj¾u÷½AÓ¹¼‘�¾Ì�ݽñ{¹=3°Q>�£ ¾œ™¾t¼½pG0½õŠ1=«'½dGe¾èá¾’^½� x<ãw†=S4н¼È…¾©_>N¤»»±:s<Ê•}¾âï ½H-'5½÷›>ÐΖ¾"À©»mr|»aTS¾õ0>´‘½¤Èé=8ÈØ¼+ãI=O˾½uG'>ˆ%>|1½ ‘<2-¾|ù$¾y½n f¾ŠAн#sà½k¾þ¹¾D >Snœ;rËâ>g†Ä½Rܾ™�@½Bÿ>0E˜½�Ý2½4>¾0(w>Ì«¦½´ã/½6ùl>Z¡�»En™=ÌW= ql=âéð¼ÙÎð=’ë­=§á~¾äÇ@¼7¢ ¾²zn>úTå=Ÿõ‰¾W´ ½Dh|=äŸÏ½èu¾i@ =3ô¬½´Ÿ ¼ü›»*c=ª“W»‡ý%¾¿Éy½¥xú½|`)=:<ÍÁ=>ÞÕ<ÏN>¥Ó¿:3¤Ô¼Ï›5=,/½ñ—Î;î.<xÔ=/½= ­¼8ƒ,¾¶©ã=b¾‹ï)>'ôÌ=éd½Lr->ô,À¼•¿­½ÌÀÄ=Ä_˽à ¾Dý£>ÿN¾¼C ¾ÅÔa>ÉD¼=Ìå%¾à÷Ƚ¶‹i½·íé=ý;¾�×3¾Øš#»#m >Å>‹˜Q½È©>á+‰>eÉÖ=ŸF®½bA³=0}Õ=wOu½�,>\qK=£õô¼¢³~>¨J½áИ½Ûíå¼%ÏO>Õ§=]41>¶SÒ½ [>÷X¾@“½aÝû¾‚²>¯)2=qν¹…>r‹=ILk¾Ì*0¾’é>Îܾ\ö=Àè­¾$c*¼î¼:½,¾b½ô¨ ¼Ú©=„“²>Mm1½o9e¾G“$>,p½=ýp"¾f ¾^R>k ÿ=UƒŽ>QÛ˽'µ ½¿‹Z½ô>2 Î=¸Ö=cÔn=¾®¾^ºñ=�>Èâ"½®O龩<«;ofܾ«ñ¾]Áæ<6³>ØÝr½,¾Ä‹Ã>� [¾`B <@²ä½ûí½’ú€¼�Úl=\†=¾>–tÈ=ŸÑ²½‡Yi< �=‹Í½ÙÆ>ÒÛ‘½o—›½'‚x>®�J>´È…=Å}&>çk>g!³=ç4“>a�¾;u;½Xä½ç×;í)K½‡A¹½(eÂ=£b²¼'O9½¤Ø@;Q`7¾+'”=Z >^m&>ã0ð¾^Û�>ã:ƒ¾vb‰¾~r¼º‘¾<¬{†>ÏŽ >VŽ ¾�"»¾’3¾H„L=uŒ–½î°Ê<#¡n>@„ˆ=Î#ã¼Íñ=ÕŒT¾˜¸½@5È=ê]¾ƒ¸¯¾ú=ª>�Ö²½ ‡(¾'ð=:V¾íá2=JÄZ¾�ªƒ>'$¾J¾špi¾´¸=LC§½¨l>¶ô¶<º$¾C½½TU¥¼;©Ù½w�¡>I.ͽoûƽ5ë˽}>¹Ý¼½Àû4>.€‚>ñ �¾Y<Í>î¨o¾à¦J¾r2¾:¬j¾@ëQ¾@½\Tñ=ÄË<_4M¾8O¶½ÒbŸ>� >1%y>å|‘==0ç=�ñ~¼?õ½÷Xú=¾Ý0»ÀuʼªŸ4¾)Y¦>ëÊO:î0>–Xx=„šÛ½  Œ½Ujݽ:>Ø´N¾þ»:¾j´‹=XÞÈ>ëÃ~=l^E¾)ŽY>2¾†ó½±]]=·¥½ÄŠ•½Ùh>'Öè½(·]¾0ûç=Áüõ=<Ý,>Á^z¾nÙs> p¾Ë�?¼1ؽã >LÙ¼¥à<>t¾oH¾–ÌM==º2>¢º=Û=Ö[ÿ=‡¢É½ ¼½–€é=çk­>·í¾™]¾>ˆÂ= /=Ä!©¾ko•>‡%½Ëiž=^¸>–M ¾}tm¾W£?`L<>‘³m>KD½À6@¾·!®½.¶�¾{ t¾dÏŸ=`y>C¡”>Çî_=U�>v…åºì‡Þ½þ¨á=õú‘>̶ä<²´¾Õ±ão”¾Æ">Ù9w½ê=Ä<‰�R¾*†Ú=­Û¬¾únL=w3º¾3–¡½ˆô”¾‹¾rr†>ð(Î>ùî =`Ê׼Ė>¤#¬¾²Ëš½¶«¾ã±½© =ÀN®=fÀ=½úï½NX²>F@_=^.¾eü½eSä>xT”>WÀ><8~мSIA>‰YC>@¢B¾GÎN>ê4¥½À{>b½E 5>±Ñª¾W,ž!ÿ¹<\Ó>ç§ã½;>ó¾öii>¬‡¾#Ez¾;>ºÚX>3®_>MA>$®½,a½ Y=¢‘ò>6^,½ý稽ðYиÖt‡½œ÷¾LC˜>ŠP¾²{…¼w‹¾Àò¼;Í>¸é¾%Ù¾?l ½˜i¾ ªµ=¤ºÆ=Bg½pŒ½˜í�¼|d½¾À‡Â>³·»Ø©è=7<¼î L>¼õc>n}�¾¢ÔÂ>¶šU¾Bëµ½ ÍJ>é¡<÷ª =Aw›;]xÆ=Wß=ñ“™>‰~"¾„e¢= A¨¾&4>P=>“ºv½¡h<¾ñX@¾746½¢ã̽o'�½¹H™½tU¾!àÔ¼¢”+¾–Ì>ܱ®=„•Å<áƒk>L‘=¾¿°¾Ø¿*½'ÒÆ½�yg>彎P�½&¾!oñÊ#<¾™h<5À¤=�Yý¼ˆ™’=(U=Û�ü=‹¹…½Fûp½þ¼V=#/ ¿Ž·ª>™i½ÓáQ<¼€¾j¦½&×½‡Ç ¾ ¾Æ>â|Â<”ü?§ ¾Ÿ¡ì½Š¾8ºý=ê"¾3Œ½û1>à}$¾´Gè½èéS>,‹�>yœ6> ~J=i‘>Õ=䫱½6¤„¾M36>lo>¾²¢ä=ûßå="ð=s¼bTõ=N|à>Ç«¶<òÅ÷=ö…»¾8ÂI>}·¬<ÛOð= L¾Ính>«É½+´v¾Bój=YÂ@ºþ*¾ZP=d;=Øe·½ƒâ¼+e¹<í(¾�˜>ºQˆÎ=½Èf¾öX½µV‘—»¾�ð>§y_½kw‡> ý«¾ `B¾ûAñºµø=ð²›=~N¾eþ½Ñ@>‘Wä¾ÛÚ·=Šk>æì'>�ƒ¾)=�¾àkR>ᕊ¾:|ø=scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/prot_vec.emb000066400000000000000000000365201520735541300257500ustar00rootroot00000000000000‰HDF  ÿÿÿÿÿÿÿÿP=ÿÿÿÿÿÿÿÿ`ˆ¨ `TREEÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿxHEAPX8Èidptridembedding_ptrembedding €è @format €GCOL embedding1.0float64 ˆ¨ Hformat-version€ @dtype€ 0 dim@ ÿÿÿÿÿÿÿÿ  deflateÀhSNOD(p10(ðhTREEÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ>ÿÿÿÿÿÿÿÿ deflate >hTREEÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ=¸<>ÿÿÿÿÿÿÿÿ @)�TREEÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ( ÿÿÿÿÿÿÿÿ  ?@4 4ÿ deflate€2 PTREEÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ[õ< x^ ÉQ À ѳ-¸Ú�(¬–Hï‘f>ߨpÒ¤PÏö\g¸À…ä ~ª…•¬pmÑç‰Ãö;Ð,x^P¯ÿ%ù]½0Þ¿ñ¼Úð¿f Ì´@ã¿CyöˆžÐ?Òó,yG§Ì?>×Líˆá¿nd .]Έüˆµ’Ö¿)Üøf‚í?Sj{ÝÌ¿uu)9scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qseq_invalid_filter000066400000000000000000000003311520735541300274000ustar00rootroot00000000000000sanger 1 3 34 -30 30 0 2 ACGTACGTACGTACGTACGTACGTACTTTTTTTTTTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC ;;>@BCEFGHJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qseq_invalid_lane000066400000000000000000000003311520735541300270320ustar00rootroot00000000000000sanger 1 -3 34 12 -2 0 2 ACGTACGTACGTACGTACGTACGTACTTTTTTTTTTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC ;;>@BCEFGHJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qseq_invalid_read000066400000000000000000000003311520735541300270260ustar00rootroot00000000000000sanger 1 3 34 -30 30 0 4 ACGTACGTACGTACGTACGTACGTACTTTTTTTTTTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC ;;>@BCEFGHJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qseq_invalid_tile000066400000000000000000000003301520735541300270470ustar00rootroot00000000000000sanger 1 5 -4 12 -2 0 2 ACGTACGTACGTACGTACGTACGTACTTTTTTTTTTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC ;;>@BCEFGHJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qseq_invalid_x000066400000000000000000000003521520735541300263650ustar00rootroot00000000000000sanger 1 3 34 if_you're_a_shepherd 42 0 2 ACGTACGTACGTACGTACGTACGTACTTTTTTTTTTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC ;;>@BCEFGHJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qseq_invalid_y000066400000000000000000000003731520735541300263710ustar00rootroot00000000000000sanger 1 3 34 42 and_a_snake_is_killing_all_your_sheep 0 2 ACGTACGTACGTACGTACGTACGTACTTTTTTTTTTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC ;;>@BCEFGHJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qseq_multi_seq_illumina1.3000066400000000000000000000003421520735541300305250ustar00rootroot00000000000000illumina 1 3 34 -30 30 0 1 ACG....ACGTAC ruBBBBrBCEFGH 1 illumina 1 3 34 30 -30 0 1 CGGGCATTGCA CGGGCasdGCA 0 illumina 1 3 35 -30 30 0 2 ACGTA.AATAAAC geTaAafhwqAAf 1 illumina 1 3 35 30 -30 0 3 CATTTAGGA.TGCA tjflkAFnkKghvM 0 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qseq_single_seq_sanger000066400000000000000000000003311520735541300300750ustar00rootroot00000000000000sanger 1 3 34 -30 30 0 2 ACGTACGTACGTACGTACGTACGTACTTTTTTTTTTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC ;;>@BCEFGHJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_2_seqs_defaults000066400000000000000000000001051520735541300274600ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_3_seqs_defaults000066400000000000000000000001441520735541300274640ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_3_seqs_defaults_desc_mismatch000066400000000000000000000001311520735541300323430ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 42 42 41 39 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_3_seqs_defaults_extra000066400000000000000000000001741520735541300306720ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1 42 >s_e_q_4 desc 4 42 42 42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_3_seqs_defaults_id_mismatch000066400000000000000000000001311520735541300320210ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_42 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_3_seqs_defaults_length_mismatch000066400000000000000000000001411520735541300327070ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_3_seqs_non_defaults000066400000000000000000000001511520735541300303340ustar00rootroot00000000000000>s*e*q*1 desc+1 1234 0 0 2 >s*e*q*2 desc+2 1 11 111 11112 >s*e*q*3 desc+3 12345 678909 999999 4242424242 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_5_blanks_start_of_file000066400000000000000000000003321520735541300307750ustar00rootroot00000000000000 >seq1 desc1 10 20 30 10 0 0 0 255 1 255 >_____seq__2_ 42 > desc3 0 0 0 0 0 0 0 > 55 10 0 99 1 1 8 77 40 10 10 0 > 10 9 8 7 6 >proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_5_ws_lines_start_of_file000066400000000000000000000004211520735541300313450ustar00rootroot00000000000000 >seq1 desc1 10 20 30 10 0 0 0 255 1 255 >_____seq__2_ 42 > desc3 0 0 0 0 0 0 0 > 55 10 0 99 1 1 8 77 40 10 10 0 > 10 9 8 7 6 >proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_6_blanks_start_of_file000066400000000000000000000003331520735541300307770ustar00rootroot00000000000000 >seq1 desc1 10 20 30 10 0 0 0 255 1 255 >_____seq__2_ 42 > desc3 0 0 0 0 0 0 0 > 55 10 0 99 1 1 8 77 40 10 10 0 > 10 9 8 7 6 >proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_6_ws_lines_start_of_file000066400000000000000000000004351520735541300313530ustar00rootroot00000000000000 >seq1 desc1 10 20 30 10 0 0 0 255 1 255 >_____seq__2_ 42 > desc3 0 0 0 0 0 0 0 > 55 10 0 99 1 1 8 77 40 10 10 0 > 10 9 8 7 6 >proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_blank_lines_between_records000066400000000000000000000003371520735541300321170ustar00rootroot00000000000000>seq1 desc1 10 20 30 10 0 0 0 255 1 255 >_____seq__2_ 42 > desc3 0 0 0 0 0 0 0 > 55 10 0 99 1 1 8 77 40 10 10 0 > 10 9 8 7 6 >proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_blanks_end_of_file000066400000000000000000000003341520735541300301640ustar00rootroot00000000000000>seq1 desc1 10 20 30 10 0 0 0 255 1 255 >_____seq__2_ 42 > desc3 0 0 0 0 0 0 0 > 55 10 0 99 1 1 8 77 40 10 10 0 > 10 9 8 7 6 >proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 qual_description_newline_replacement_empty_str000066400000000000000000000001501520735541300350470ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data>proteinseq detaileddescription with newlines 42 42 255 255 42 42 42 42 42 43 >foo 0 1 2 3 4 5 6 7 8 qual_description_newline_replacement_multi_char000066400000000000000000000002121520735541300351470ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data>proteinseq :-)detailed:-)description with new:-):-)lines:-):-):-) 42 42 255 255 42 42 42 42 42 43 >foo :-):-):-):-) 0 1 2 3 4 5 6 7 8 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_description_newline_replacement_none000066400000000000000000000001641520735541300340440ustar00rootroot00000000000000>proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 >foo 0 1 2 3 4 5 6 7 8 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_id_whitespace_replacement_empty_str000066400000000000000000000000261520735541300336740ustar00rootroot00000000000000>seq2 42 > a b 1000 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_id_whitespace_replacement_multi_char000066400000000000000000000000721520735541300337760ustar00rootroot00000000000000>>:o>:o>:o>:o>:oseq>:o>:o2>:o 42 >>:o>:o>:o>:o a b 1000 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_id_whitespace_replacement_none000066400000000000000000000000421520735541300326030ustar00rootroot00000000000000> seq 2 42 > a b 1000 1 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_blank_line_after_header000066400000000000000000000001451520735541300326760ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_blank_line_within_seq000066400000000000000000000001461520735541300324400ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_blank_sequence000066400000000000000000000001241520735541300310630ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_legacy_format000066400000000000000000000000571520735541300307250ustar00rootroot00000000000000; legacy-seq-id legacy description 40 30 20 10 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_missing_header000066400000000000000000000000231520735541300310630ustar00rootroot00000000000000seq1 desc1 1 2 3 4 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_missing_qual_scores_first000066400000000000000000000001341520735541300333650ustar00rootroot00000000000000>s_e_q_1 desc 1 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_missing_qual_scores_last000066400000000000000000000001251520735541300332010ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_missing_qual_scores_middle000066400000000000000000000001231520735541300334720ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_qual_scores_float000066400000000000000000000001461520735541300316150ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41.0 39 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_qual_scores_negative000066400000000000000000000001441520735541300323100ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_qual_scores_over_255000066400000000000000000000001441520735541300320540ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1 256 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_qual_scores_string000066400000000000000000000001451520735541300320150ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1a -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_whitespace_line_in_seq000066400000000000000000000001611520735541300326060ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_whitespace_only_sequence000066400000000000000000000001371520735541300331750ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_invalid_ws_line_after_header000066400000000000000000000001601520735541300322350ustar00rootroot00000000000000>s_e_q_1 desc 1 1 2 3 4 >s_e_q_2 desc 2 42 41 39 40 >s_e_q_3 desc 3 100 0 1 -42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_max_width_1000066400000000000000000000000501520735541300266000ustar00rootroot00000000000000>seq1 desc1 10 20 30 10 0 0 0 255 1 255 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_max_width_5000066400000000000000000000003251520735541300266110ustar00rootroot00000000000000>seq1 desc1 10 20 30 10 0 0 0 255 1 255 >_____seq__2_ 42 > desc3 0 0 0 0 0 0 0 > 55 10 0 99 1 1 8 77 40 10 10 0 > 10 9 8 7 6 >proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_multi_seq000066400000000000000000000003251520735541300264030ustar00rootroot00000000000000>seq1 desc1 10 20 30 10 0 0 0 255 1 255 >_____seq__2_ 42 > desc3 0 0 0 0 0 0 0 > 55 10 0 99 1 1 8 77 40 10 10 0 > 10 9 8 7 6 >proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_multi_seq_roundtrip000066400000000000000000000002461520735541300305130ustar00rootroot00000000000000>seq-a a's description 0 1 2 3 4 5 6 7 8 >seq-b b's description 0 1 2 3 4 5 6 7 8 9 10 11 >seq-c c's description 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_prot_seqs_odd_labels000066400000000000000000000002031520735541300305630ustar00rootroot00000000000000> -0000000 0000 01 5 00044 -0 > skbio 1 2 33 123 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_single_bio_seq_non_defaults000066400000000000000000000000251520735541300321210ustar00rootroot00000000000000>f-o-o b_a_r 1 2 3 4 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_single_dna_seq_non_defaults000066400000000000000000000000251520735541300321120ustar00rootroot00000000000000>f-o-o b_a_r 0 1 2 3 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_single_nuc_seq_non_defaults000066400000000000000000000000271520735541300321370ustar00rootroot00000000000000>f-o-o b_a_r 0 1 2 3 4 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_single_prot_seq_non_defaults000066400000000000000000000000261520735541300323350ustar00rootroot00000000000000>f-o-o b_a_r 42 41 40 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_single_rna_seq_non_defaults000066400000000000000000000000251520735541300321300ustar00rootroot00000000000000>f-o-o b_a_r 2 3 4 5 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_single_seq000066400000000000000000000000501520735541300265250ustar00rootroot00000000000000>seq1 desc1 10 20 30 10 0 0 0 255 1 255 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_tabular_msa_different_type000066400000000000000000000001251520735541300317600ustar00rootroot00000000000000> 20 20 21 >rnaseq-1 rnaseq desc 1 10 9 10 >rnaseq-2 rnaseq desc 2 9 99 99 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_ws_lines_between_records000066400000000000000000000005151520735541300314570ustar00rootroot00000000000000>seq1 desc1 10 20 30 10 0 0 0 255 1 255 >_____seq__2_ 42 > desc3 0 0 0 0 0 0 0 > 55 10 0 99 1 1 8 77 40 10 10 0 > 10 9 8 7 6 >proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/qual_ws_lines_end_of_file000066400000000000000000000004651520735541300305420ustar00rootroot00000000000000>seq1 desc1 10 20 30 10 0 0 0 255 1 255 >_____seq__2_ 42 > desc3 0 0 0 0 0 0 0 > 55 10 0 99 1 1 8 77 40 10 10 0 > 10 9 8 7 6 >proteinseq detailed description with new lines 42 42 255 255 42 42 42 42 42 43 sample-metadata-comments-comment-char-id.tsv000066400000000000000000000010551520735541300337430ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data# pre-header # comment #SampleID col1 col2 col3 # post-header # comment id1 1 a foo id2 2 b bar # intra-data comment with another # sign # ## # comment with leading whitespace is still a comment. # comment with tab characters is also a comment! "# if the first cell is quoted, the parsing rules first process and strip double quotes, then check if the first cell begins with a pound sign" " # same rule applies if the de-quoted cell has leading whitespace (leading/trailing whitespace is *always* ignored)" id3 3 c 42 # trailing # comment scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/sample-metadata-comments-mixed-case.tsv000066400000000000000000000010541520735541300330710ustar00rootroot00000000000000# pre-header # comment sAmpLEid col1 col2 col3 # post-header # comment id1 1 a foo id2 2 b bar # intra-data comment with another # sign # ## # comment with leading whitespace is still a comment. # comment with tab characters is also a comment! "# if the first cell is quoted, the parsing rules first process and strip double quotes, then check if the first cell begins with a pound sign" " # same rule applies if the de-quoted cell has leading whitespace (leading/trailing whitespace is *always* ignored)" id3 3 c 42 # trailing # comment scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/sample-metadata-comments.tsv000066400000000000000000000010461520735541300310550ustar00rootroot00000000000000# pre-header # comment id col1 col2 col3 # post-header # comment id1 1 a foo id2 2 b bar # intra-data comment with another # sign # ## # comment with leading whitespace is still a comment. # comment with tab characters is also a comment! "# if the first cell is quoted, the parsing rules first process and strip double quotes, then check if the first cell begins with a pound sign" " # same rule applies if the de-quoted cell has leading whitespace (leading/trailing whitespace is *always* ignored)" id3 3 c 42 # trailing # comment sample-metadata-complete-types-directive.tsv000066400000000000000000000001431520735541300340740ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/dataid col1 col2 col3 #q2:types categorical categorical categorical id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/sample-metadata-empty-rows.tsv000066400000000000000000000002611520735541300313540ustar00rootroot00000000000000 id col1 col2 col3 id1 1 a foo id2 2 b bar " " " " " " " " " " " id3 3 c 42 sample-metadata-leading-trailing-whitespace-split-id.tsv000066400000000000000000000006351520735541300362430ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data # Leading/trailing whitespace is ignored in *any* type of cell, including # comments, empty rows, headers, directives, and data cells. # Double-quotes are always processed prior to stripping leading/trailing # whitespace within the cell. sample id "col1 " " col2" col3 #q2:types " numeric " categorical " categorical " id1 " 1 " a foo " " " id2 " 2 b "bar " id3 3 "c " 42 sample-metadata-leading-trailing-whitespace.tsv000066400000000000000000000006651520735541300345230ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data # Leading/trailing whitespace is ignored in *any* type of cell, including # comments, empty rows, headers, directives, and data cells. # Double-quotes are always processed prior to stripping leading/trailing # whitespace within the cell. id "col1 " " col2" col3 #q2:types " numeric " categorical " categorical categorical " id1 " 1 " a foo " " " id2 " 2 b "bar " id3 3 "c " 42 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/sanger_full_range_as_illumina.fastq000066400000000000000000000010461520735541300325270ustar00rootroot00000000000000@FAKE0001 Original version has PHRED scores from 0 to 93 inclusive (in that order) ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @FAKE0002 Original version has PHRED scores from 93 to 0 inclusive (in that order) CATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCA + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/sanger_full_range_as_sanger.fastq000066400000000000000000000010461520735541300321740ustar00rootroot00000000000000@FAKE0001 Original version has PHRED scores from 0 to 93 inclusive (in that order) ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ @FAKE0002 Original version has PHRED scores from 93 to 0 inclusive (in that order) CATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCA + ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"! scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/sanger_full_range_original_sanger.fastq000066400000000000000000000010461520735541300333750ustar00rootroot00000000000000@FAKE0001 Original version has PHRED scores from 0 to 93 inclusive (in that order) ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ @FAKE0002 Original version has PHRED scores from 93 to 0 inclusive (in that order) CATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCA + ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"! scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/solexa_full_range_original_solexa.fastq000066400000000000000000000007021520735541300334230ustar00rootroot00000000000000@FAKE0003 Original version has Solexa scores from -5 to 62 inclusive (in that order) ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGT + ;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ @FAKE0004 Original version has Solexa scores from 62 to -5 inclusive (in that order) TGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCATGCA + ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<; scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_all_data_types000066400000000000000000000006241520735541300304310ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF NM Kestrel Gorlick #=GF DT February 11, 2016 #=GF FN Writer test file #=GS seq1 DT February 1, 2016 #=GS seq1 NM Unknown #=GS seq3 DT Unknown seq1 GAGGCCATGCCCAGGTGAAG seq2 ACCTGAGCCACAGTAGAAGT seq3 CCCTTCGCTGGAAATGTATG #=GR seq3 AS CCGAAAGTCGTTCGAAAATG #=GR seq3 SS GGCGAGTCGTTCGAGCTGGC #=GC AS_cons CGTTCGTTCTAACAATTCCA #=GC SS_cons GGCGCTACGACCTACGACCG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_blank_lines000066400000000000000000000000571520735541300277250ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF AL ABCD #=GF NM 1234 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_data_only000066400000000000000000000001221520735541300274070ustar00rootroot00000000000000# STOCKHOLM 1.0 seq1 ACUCCGACAUGCUCC seq2 UAGUGCCGAACGCUG seq3 GUGUGGGCGUGAUUC // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_different_padding000066400000000000000000000002161520735541300310750ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF RN [1] #=GF RC A Runon #=GF RC Comment Without Whitespace #=GF RN [2] #=GF RC A Runon #=GF RC Comment With Whitespace //scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_differing_gc_data_length000066400000000000000000000001061520735541300323770ustar00rootroot00000000000000# STOCKHOLM 1.0 seq1 ACGCUUGCAA #=GC AT_cons UGCUUGGCGCAU // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_differing_gr_data_length000066400000000000000000000000761520735541300324240ustar00rootroot00000000000000# STOCKHOLM 1.0 seq1 AUCGCCUG #=GR seq1 AL UCGCUUG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_differing_seq_lengths000066400000000000000000000001061520735541300317700ustar00rootroot00000000000000# STOCKHOLM 1.0 seq1 AUCCGCUUAC seq2 UGCCUGGAGCG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_duplicate_gc000066400000000000000000000002641520735541300300670ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF ID RCR2 OSF22 TCCTCCCAGTGTCGCCCGGT OSF33 TTTTTTGGTCAAATTAAAGG #=GC SS_cons CAAGGGAAATACTACGGGAC #=GC SS_cons CGGGACTCGTGCGTTGTAGG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_duplicate_gr000066400000000000000000000003031520735541300301000ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF ID CBS #=GF AC PF00571 LFDR2 GGCCTCAGGACGAAGCACGG LFDR3 AATTGTGATCATCTTACAGG #=GR LFDR3 OS TTTTACCAATTGCTGACAGA #=GR LFDR3 OS CCTGGACATCCCCCGCACGG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_duplicate_sequence_names000066400000000000000000000002371520735541300324710ustar00rootroot00000000000000# STOCKHOLM 1.0 ASR132 GGCGUUCCGUUCAGUGCUGG RTF112 GGGCGGUGCUAUGAAAAUAC ASR132 GGCGUUCCGUUCAGUGCUGG TTL879 AGCUAUCUCCGGGCCCUUGG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_duplicate_tree_ids000066400000000000000000000001111520735541300312630ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF TN tree1 #=GF NH ABCD #=GF TN tree1 #=GF NH EFGH // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_extensive000066400000000000000000000012141520735541300274520ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF ID CBS #=GF AC PF00571 #=GF AU Bateman A #=GF SQ 67 #=GS O31698/88-139 OS Bacillus subtilis O83071/192-246 MTCRAQLIAVPRASSLAE..AIACAQKM....RVSRVPVYERS #=GR O83071/192-246 SA 999887756453524252..55152525....36463774777 O31698/88-139 EVMLTDIPRLHINDPIMK..GFGMVINN......GFVCVENDE #=GR O31698/88-139 SS CCCCCCCHHHHHHHHHHH..HEEEEEEE....EEEEEEEEEEH O31699/88-139 EVMLTDIPRLHINDPIMK..GFGMVINN......GFVCVENDE #=GR O31699/88-139 AS ________________*__________________________ #=GR O31699/88-139 IN ____________1______________2__________0____ #=GC SS_cons CCCCCHHHHHHHHHHHHH..EEEEEEEE....EEEEEEEEEEH // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_extensive_mixed000066400000000000000000000012241520735541300306410ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GR O31699/88-139 AS ________________*__________________________ O83071/192-246 MTCRAQLIAVPRASSLAE..AIACAQKM....RVSRVPVYERS #=GF ID CBS #=GR O31698/88-139 SS CCCCCCCHHHHHHHHHHH..HEEEEEEE....EEEEEEEEEEH #=GF AC PF00571 O31698/88-139 EVMLTDIPRLHINDPIMK..GFGMVINN......GFVCVENDE #=GC SS_cons CCCCCHHHHHHHHHHHHH..EEEEEEEE....EEEEEEEEEEH #=GR O31699/88-139 IN ____________1______________2__________0____ #=GS O31698/88-139 OS Bacillus subtilis #=GR O83071/192-246 SA 999887756453524252..55152525....36463774777 O31699/88-139 EVMLTDIPRLHINDPIMK..GFGMVINN......GFVCVENDE #=GF AU Bateman A #=GF SQ 67 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_invalid_data_type000066400000000000000000000000551520735541300311220ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF AL ABCD #=GZ NM 1234 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_invalid_nonexistent_gr000066400000000000000000000002671520735541300322230ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF ID ARD RL1255 AAGGGUUAUUUAUAUACUUU RL1332 UGCUAAGAGUGGGGAUGAUU RL1232 GCCACAACCGAUUAGAUAGA #=GR RL1355 AS ACUAUAUACAUAGCUAUAUU // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_invalid_nonexistent_gs000066400000000000000000000001561520735541300322210ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GS AC14 ID ARD2 AC12 AAGGGUUAUUUAUAUACUUU AC13 UGCUAAGAGUGGGGAUGAUU // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_malformed_data_line000066400000000000000000000000301520735541300314010ustar00rootroot00000000000000# STOCKHOLM 1.0 seq1 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_malformed_gc_line000066400000000000000000000000751520735541300310720ustar00rootroot00000000000000# STOCKHOLM 1.0 seq1 ATCCGCT #=GC AT_cons // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_malformed_gf_line000066400000000000000000000000331520735541300310670ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF AL // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_malformed_gr_line000066400000000000000000000000661520735541300311110ustar00rootroot00000000000000# STOCKHOLM 1.0 seq1 ACGGTCG #=GR seq1 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_malformed_gs_line000066400000000000000000000000531520735541300311060ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GS seq1 AL seq1 ACCTG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_metadata_only000066400000000000000000000001061520735541300302600ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF NM Kestrel Gorlick #=GF DT February 5th, 2016 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_minimal000066400000000000000000000000601520735541300270640ustar00rootroot00000000000000# STOCKHOLM 1.0 0235244 TGTGTCGCAGTTGTCGTTTG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_missing_footer000066400000000000000000000001711520735541300304700ustar00rootroot00000000000000# STOCKHOLM 1.0 0232455 TTATCTTAGCCTCTCTAAGT 0234323 ATCCCACGGAAACAGATGGC 0235244 TGTGTCGCAGTTGTCGTTTG scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_missing_header000066400000000000000000000001541520735541300304230ustar00rootroot000000000000000232455 TTATCTTAGCCTCTCTAAGT 0234323 ATCCCACGGAAACAGATGGC 0235244 TGTGTCGCAGTTGTCGTTTG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_missing_reference_items000066400000000000000000000001021520735541300323230ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF RN [1] #=GF RT A Title #=GF RA The Author // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_missing_rn_tag000066400000000000000000000000551520735541300304450ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF RL Flagstaff Arizona // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_multi_line_tree_no_id000066400000000000000000000000551520735541300317720ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF NH ABCD #=GF NH EFGH // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_multi_line_tree_with_id000066400000000000000000000000731520735541300323310ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF TN tree1 #=GF NH ABCD #=GF NH EFGH // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_multiple_msa000066400000000000000000000007461520735541300301440ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF AC G2134T23 #=GF ID ARD RTC2231 AAGGGUUAUUUAUAUACUUU RTF2124 UGCUAAGAGUGGGGAUGAUU RTH3322 GCCACAACCGAUUAGAUAGA RTB1512 UUAGAAACCGAUGGACCGAA #=GC AC_cons GGGACUGGACAUCUAUUCAG // # STOCKHOLM 1.0 #=GF AC G2134T23 #=GF ID ARD RTC2231 AAGGGUUAUUUAUAUACUUU RTF2124 UGCUAAGAGUGGGGAUGAUU RTH3322 GCCACAACCGAUUAGAUAGA RTB1512 UUAGAAACCGAUGGACCGAA #=GC AC_cons GGGACUGGACAUCUAUUCAG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_multiple_multi_line_trees000066400000000000000000000001431520735541300327160ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF TN tree1 #=GF NH ABCD #=GF NH EFGH #=GF TN tree2 #=GF NH IJKL #=GF NH MNOP // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_multiple_references000066400000000000000000000004771520735541300315060ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF RN [1] #=GF RM 123456789 #=GF RT Title 1 #=GF RA Author 1 #=GF RL Location 1 #=GF RC Comment 1 #=GF RN [2] #=GF RM 987654321 #=GF RT Title 2 #=GF RA Author 2 #=GF RL Location 2 #=GF RC Comment 2 #=GF RN [3] #=GF RM 132465879 #=GF RT Title 3 #=GF RA Author 3 #=GF RL Location 3 #=GF RC Comment 3 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_multiple_trees000066400000000000000000000001441520735541300304760ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF TN tree1 #=GF NH ABCD #=GF TN tree2 #=GF NH EFGH #=GF TN tree3 #=GF NH IJKL // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_no_data000066400000000000000000000000231520735541300270420ustar00rootroot00000000000000# STOCKHOLM 1.0 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_nonstring_labels000066400000000000000000000001561520735541300310070ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF 1.3 2857 #=GS 11214 8 123 11214 ACTG #=GR 11214 1.0 1234 #=GC 25 4321 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_rna000066400000000000000000000003631520735541300262240ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF AC G2134T23 #=GF ID ARD RTC2231 AAGGGUUAUUUAUAUACUUU RTF2124 UGCUAAGAGUGGGGAUGAUU RTH3322 GCCACAACCGAUUAGAUAGA RTB1512 UUAGAAACCGAUGGACCGAA #=GC AC_cons GGGACUGGACAUCUAUUCAG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_runon_gf_no_whitespace000066400000000000000000000002341520735541300321660ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF CC CBS domains are small intracellular modules mostly found #=GF CC in 2 or four copies within a protein. GG1344 ACTGGTTCAATG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_runon_gf_with_whitespace000066400000000000000000000002351520735541300325260ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF CC CBS domains are small intracellular modules mostly found #=GF CC in 2 or four copies within a protein. GG1344 ACTGGTTCAATG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_runon_gs_no_whitespace000066400000000000000000000001271520735541300322040ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GS seq1 LN This is a runon #=GS seq1 LN GS line. seq1 ATCGTTCAGTG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_runon_gs_with_whitespace000066400000000000000000000001301520735541300325350ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GS seq1 LN This is a runon #=GS seq1 LN GS line. seq1 ATCGTTCAGTG // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_runon_references000066400000000000000000000002261520735541300310040ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF RN [1] #=GF RM 123456789 #=GF RT A Runon #=GF RT Title #=GF RA The Author #=GF RL A Location #=GF RC A Runon #=GF RC Comment // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_runon_references_mixed000066400000000000000000000002261520735541300321720ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF RN [1] #=GF RC A Runon #=GF RM 123456789 #=GF RT A Runon #=GF RA The Author #=GF RT Title #=GF RL A Location #=GF RC Comment // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_single_reference000066400000000000000000000001671520735541300307450ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF RN [1] #=GF RM 123456789 #=GF RT A Title #=GF RA The Author #=GF RL A Location #=GF RC Comment // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_single_tree_with_id000066400000000000000000000000561520735541300314520ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF TN tree1 #=GF NH ABCD // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_single_tree_without_id000066400000000000000000000000401520735541300321730ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF NH ABCD // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_two_of_each_metadata000066400000000000000000000003661520735541300315640ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF NM Kestrel Gorlick #=GF DT February 5th, 2016 #=GS seq1 AL ABCD #=GS seq1 NS 1234 seq1 ACTGACCATGTTCA #=GR seq1 SS CACTACTTGTGACG #=GR seq1 AS TCACATCGGCGATG #=GC SS_cons ______1____2__ #=GC AS_cons __1___1___3___ // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/stockholm_whitespace_only_lines000066400000000000000000000001121520735541300320230ustar00rootroot00000000000000# STOCKHOLM 1.0 #=GF AL ABCD #=GF NM 1234 // scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/taxdump_names.dmp000066400000000000000000000022071520735541300270040ustar00rootroot000000000000001 | root | | scientific name | 2 | Bacteria | Bacteria | scientific name | 2 | eubacteria | | genbank common name | 543 | Enterobacteriaceae | | scientific name | 548 | Klebsiella aerogenes | | scientific name | 561 | Escherichia | | scientific name | 562 | "Bacillus coli" Migula 1895 | | authority | 562 | Escherichia coli | | scientific name | 562 | Escherichia/Shigella coli | | equivalent name | 570 | Donovania | | synonym | 570 | Klebsiella | | scientific name | 620 | Shigella | | scientific name | 622 | Shigella dysenteriae | | scientific name | 766 | Rickettsiales | | scientific name | 1224 | Proteobacteria | | scientific name | 1236 | Gammaproteobacteria | | scientific name | 28211 | Alphaproteobacteria | | scientific name | 91347 | Enterobacterales | | scientific name | 118884 | unclassified Gammaproteobacteria | | scientific name | 126792 | Plasmid pPY113 | | scientific name | 131567 | cellular organisms | | scientific name | 585056 | Escherichia coli UMN026 | | scientific name | 1038927 | Escherichia coli O104:H4 | | scientific name | 2580236 | synthetic Escherichia coli Syn61 | | scientific name | scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/taxdump_nodes.dmp000066400000000000000000000023411520735541300270100ustar00rootroot000000000000001 | 1 | no rank | | 8 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | | 2 | 131567 | superkingdom | | 0 | 0 | 11 | 0 | 0 | 0 | 0 | 0 | | 543 | 91347 | family | | 0 | 1 | 11 | 1 | 0 | 1 | 0 | 0 | | 548 | 570 | species | KA | 0 | 1 | 11 | 1 | 0 | 1 | 1 | 0 | | 561 | 543 | genus | | 0 | 1 | 11 | 1 | 0 | 1 | 0 | 0 | | 562 | 561 | species | EC | 0 | 1 | 11 | 1 | 0 | 1 | 1 | 0 | | 570 | 543 | genus | | 0 | 1 | 11 | 1 | 0 | 1 | 0 | 0 | | 620 | 543 | genus | | 0 | 1 | 11 | 1 | 0 | 1 | 0 | 0 | | 622 | 620 | species | SD | 0 | 1 | 11 | 1 | 0 | 1 | 1 | 0 | | 766 | 28211 | order | | 0 | 1 | 11 | 1 | 0 | 1 | 0 | 0 | | 1224 | 2 | phylum | | 0 | 1 | 11 | 1 | 0 | 1 | 0 | 0 | | 1236 | 1224 | class | | 0 | 1 | 11 | 1 | 0 | 1 | 0 | 0 | | 28211 | 1224 | class | | 0 | 1 | 11 | 1 | 0 | 1 | 0 | 0 | | 91347 | 1236 | order | | 0 | 1 | 11 | 1 | 0 | 1 | 0 | 0 | | 118884 | 1236 | no rank | | 0 | 1 | 11 | 1 | 0 | 1 | 1 | 0 | | 126792 | 36549 | species | PP | 0 | 1 | 11 | 1 | 0 | 1 | 1 | 0 | | 131567 | 1 | no rank | | 8 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | | 585056 | 562 | no rank | | 0 | 1 | 11 | 1 | 0 | 1 | 1 | 0 | | 1038927 | 562 | no rank | | 0 | 1 | 11 | 1 | 0 | 1 | 1 | 0 | | 2580236 | 488338 | species | SE | 7 | 1 | 11 | 1 | 0 | 1 | 0 | 0 | | scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/tiny_embedding_file.npz000066400000000000000000103477671520735541300301760ustar00rootroot00000000000000PK-!“æìÿÿÿÿÿÿÿÿ arr_0.npy€Aµœ—÷_ˆï÷Ç“¢"ZVÚCi %Õ}NÊl˜ B%¢¬ÌR*m‰¢�™H%4îs"d‹D6E*#[o>¾ÿÂ÷þíº�óËuŸó:Ïç¾îÓgyö’Ø(±ÕÀwY°O���–�àga`¢eà´>hÉšE�A¾Ëþï~Ê’UÁËþݯX²vÙ¿³á8 ­Ñæc,Fšhm×ú}rBz)b¯Ü3ã-Îê¯�7vW€ò�ã¬9`«ð.à+ÙÙñÙ7Ç+‡§‡aúþ£àÊAØw‚*|;æI{/ŽäÐO�‚–—*Þµ>‡Îcˆkû¹£™‘úªTêÁco#Ũ„á¶CÍäï"/æ/’„ÁÒy”µõx\”Áýûm¸W•?ô6ÙLßa‚Â|µÙ†cŠO¡C…®šZÂ{ú¸¢eÏ6T:+‹Žÿ‹þ!¢že5vŸÕj:èÔP7ÚÇfs¬x;nÀgK=Ùˆ,h‹ëA‚sùxöUžòΟ·�½‰>[n#a~Ôo8í¢±5Ò Æ8ü¡8‹ ØçÜ:¼e<ψ:lŒ�[ž%“«”Ý¢‹“áKl=_å)¼P¬$ÿC¯*Ï´$ñÝšÏÔ×ø½è5`Òþ4þÏÚA쫹]´Ã!eÁaáì†)ü÷ÓÐIÁH�&±÷Ã�¬»a6ÔE€ÑY-¾¤‚†³Wà…Õç†uàž| xÿì0ÖQ �ë>�3ÆèÑìë?“ÖÄ…ÖUTzÖO-V«1×Éë÷,\xn(Œ>L™îyIÚcžv¼öŒ¿L—ûĤôP~c¦‹Q/1#UkßÛsuU2z[gb?›)\ôâ�Ø9C—†v²MèTðŸ1äGÓy¯Jìrf¥÷!"»“GÏ=†À!$�>Ÿ6Æó¸§À?n‚ |sb!hÆf~°~6¦öÿ�³ÎJU)&|3äÙ)®4Ïå¥÷Ç`ºõG ,Ã7]²dòÙ†÷ù0Ë(Ÿå's˜½GŸÂ2U_úf“C¥à÷6C\uOeoûáùá¹è—^ úaÏŰE6|+ìCT }WöäCùªV×ùÈ ×džã�¬}Üzt×te£�¤ ­öï¢奸ãéag(¡ÿØ6xí¦ËêŸÊ¹¹+�ˬðÎ Sñ]u ô^Ìj¢_GsăVÐnŒšÒ# [µ‰G¯xg{Yj7ßÉ?dk,Y9«¢?×õÞ' À½–ƘjÕij%”¹[%‡ãC˜ÙÀÝëw³Ì^E5;Ÿšpv‘ÇO7yukï»x ¤Ì¡Üô�8öéyQmã ~ür¼ø\âI¹çÃ]Õƒ”:c-]�­&­lóʨÏcØ×M£‡¨Ó÷ÛÑh�bš+Ïö$ çDºî9Í[:{ÝÔÀi1¿+?86R‘WµÙ]‡€�YôØ»K Ÿ½TáåD}j–re±5?Ü–&ùú¢è$à’Bl›ŠdM9a¶6ÇH–�Ýólê CúªÍxiK2fPçÈx.»Ý„{ô·(�4JpŠóا§O6ÁǸóòæŠÁv�°äe((ÿ’ã–ª.Zsz4½Ë¸NÍePb0SŸÇ¡”b¸õ°F?£®åK¸zù"¶}û“z/ú$(ñ§1ª~“à‡«ŠÓPÄ øUCyÈ×&[ãýó7„·:Ê,µæ3»ÎꇡìÝ´Ê÷²w)oL·°;ÑŸïÖ†-É© òÒ’w�ÿÆgš€…ÿÔØ¨LwMuÐÒ}¤vª ÿˆ�èF9*Ë�¬/õ…Û�°Fâí¯·ý¡‹YzeOÞ6L>“„×åvñÜ¿ßÁnÅ@~ž¨4ôüTyâhNéUæ ãÇ}Ÿž‘ b\L)2“9{Æ¡Š·ƒÊDû�ÒxmÊ}¨ß\�bOCL°žî• FůaDQ nñØŠf)óy“Dáfm6L�ñGõs±Íeg´ïæh£tq×].Yt…ΰ/Åÿ-â¼'¬¨ ¹F Fâhåª~ŠÜ_=ç=LãÙ‹yÂV}»ßc&Á¹Sû`ÍoUÑô~– 8[Ñ]4wŸú�JO38¡a´ibšQ|ún._ªÈo†*‘wN7~œ„¥Ž¥PÞ^�åS¡y„3Èå<†håA¸T}*Ï»2PHòº�g?µ]?¸4ÛÉTP)ïO2ÞgyV¸¤xïàmÛÐÔHñü­íœrÜyâÙ;1”S=ƒŸtÃó7pØÌ×Tí¥Ê×öãî“âðÿb}îVžvÌ —'Iñ®“\x} ’Õ¾nwö)_£=ó“Ñúα �~<¨y¾›ßAsŸ(ñ›â;ø²Þ=Õ¤p ‚%¿q)Áì„üí’øþZ™puè”tu3ëþÖãD}güfh�#÷¢â|æs áS˜zˆ°¹¿.~yw z2�Ã]q˜ÝòÕ}Ødž çÍ€÷ó‰[¬T¨ƒyŸÆîë‹/z�Fõ·iî¸É¼´å4aÐ}ú‘‘Éd—˜DÖt�Ûæ¼T芩É8å×h\þŠìˆÅ·I4{é^cÙ)t?VüÉŸ—žFI<'æë^a§“FXò>ÅælP2–.Ü‹ÎÇ£DÜž3ÀgÞ´cëéÉ<ìM!§ÈÔàæ¤-Äúí^<�B÷¥?àjðBJ�Øwš!�3wáQ³ùç]=>´?ŠŸit@¤U� ¯#…ÊÝy”—;)ßÎ¥¥’µ ãîCöÎÞÿxã ]úlp¤DpiëÍŸ}Îr{· zè'Ú®0ï™òe³dds—vßÒ�øÅ„z,ø\ Oë 8æD §EÔÛ&…d 翦 ã¤p웵ÔXžÀ¦‹òùÔ¨‘‚3ç?§ÒÐ*Q¼TKV“ ?îÁ®‡àM�Þ\Ó@¦¨áÃg®xCˆ&ÑX«íÇ{¾) ÷„tΪ›Æ%ÖÌ'CÄòMe0�ÇQ÷Ìã½E GaÇâ<ø0Ôâc7òPÁLœ™ÞJoWíŸÍ1ÅÚ'~(~÷Äñm&|÷dl:uLz`àŽ·”ØÏ’TbfbÁÊ^ðÖ‘}–­Â60�üÝxA#Ÿï¾X¹¡)OLÛpSßì�OZŠÁÙønåþ¡{¸ZÅK4G±Ö,ÙªÙ3ŠÛapʼ¬s«Ò\é/I5ë±ÿ�ÝlZ„ÃsÒ(0âW/n‡Ë9%,þ rËÛÆ.?ñ×VÍåUY±ÍÌŠ®fàØù}ªÂ,Ò)ò’/^Ÿ\ùçø:¾1t/kmò ‰àúˆ±ÏÚgÄ(ÇÂmiGßTÛð>ñ¶�«Ðºy :|xFO¨° ñ!ñ+=mOË&6ÐÜ=üSx‡üÝ?‹®=–X8ÿ:îÿ/*VMÇ; X2±²£ö, kUÊ5§�¡m™9Ï쀵¹.øÌ´¦Vçb¹­_”—Ŷ *:ÕF9ƒïS¬Ädn¼´ ²;d)ý$ð5¯TŠºŸ ß3jE-Û6¸|Ý›’7ÌÁ!£§çà¾�&(7.–KY`²æîÿ©jõäÕô·5Çâxo}<èþöƒ÷6VÁx-Nù{˜dgäs‹OG~G–îÒ8yn8“T„EÓìG§kysé`ÙXÜ7ߘó÷ÏàgIëÝW�ÉÊÅœvR» dl/w†ƒåÒ£48‹hø!§bô—fªZ郕â±�mà=Û’~´HÓVŸá¼ôt{ÿyÀ$�«¾øx{,Þ)œg¥`­Í2lézN†RÿüìS( �°vòð¹úȶ(²žäã�ã¾Uj\ÚW¤ðë‰TÖ:SÌ8j@§‚µE{qtúH\?G :<¤°÷ˆ·½*–ýL4ù§B¬}™LþyZ¤G½k¬ùü¬-üßõ•¯î†!ûîbsq8o>oAI7cÈ^ÁWýtd<ŸKÃáq²¸íÔ,¿ˆ;zÃåIþö°�6zf¸²‡Ï»,E«wjÜw¿ ÊåK£lÿÖž§%�Š ¡V�g½ƒúå!¼aP^WÜÌeº$çà »clNwUÑ>)ÒuL-Ï vö£î³ T¹ ‚&Lçc�Qovå,wzP?³C_ƒlö@ÉX|ð-gºï…9Ëøó¾pÌQŒçªjxæÈo8§ö—rW+bý÷ ¼ý|+t©ºâúÐQ–­ÏÓ6wð[{�Ýý² âd¸[éã ‰<î»ö†èõ{?º÷ñãTŸ‡åøãªjlÞ‚¦³<ØÇl6;ÖÄëHsH�Ú„(°ê:)¾ñA‘Oo¾Ooÿ1m¿ÎsÕ/ ÎHÊàmÆ÷¡ýÍjÚb#i« */�K±M§jp”ÌßC('䟋�êm72'¸ÍOÚKIZc#.Í¿NÚ¶•ÕóÌ=}ª¼Ÿ5Óª'3©FÇO¼?Æ –â™È^èÕoŸó Â+‹JàÝÆHVûçPÛ­ÌØñVWù¾"ÿŸcqðâ#â«;ãäp~QbK²ý¡iÿŠX8 þZÓ‹6]’q¿'f¹²¼½6¤ >Á:ÆgX~ÈÜ噀>FØÆ�)Â_5‰lÙ¿’ÍWïÂ[×-ð˜FÞ]ä†_Ÿ ä0- ¢?ê8Fo8÷šaŒ¿$‹òûéÍc-V vEEÛþ<åÌò8ËvàE'<©¤Ý §‡Wp¿·ÄJ�TgÄòå«|áòNþ-+EW¼·à¥etJL¦UÇóÞä¹âŠÆ Þ¼-¦þ=Cæ�b9Ar ÿokßÏ‹S<ç‹—3§Ð·JãÍ{Oñ¾D6¯ž#ÚUäºÛýxg­8FA*Ô½cøW’ù¯2¸p-�ú[éAíPp¾»‚ÉdÂê)ªÜ¨#͹— mÃhxÕ}Úº{˜!‹WÅ^±#èç†AܽðMP$N9juº/èäø09[šeFcëiê±�¡ô)4.=ŽÃ0v‹%,íULu“¿ÃK™ªcq´Én1ÎÝR#Üö¿E'ä†qÎGwÔ«[ÇJÙky„Ü9ê¥/Íñr·lì2Ç’\ß[$¡+�?ÿíì±ÀU¦"Ýu>Éj9‘ ûîo—Î�úÏ&¸E-u÷?b�å�œù Zcäñú½E°|C:2Ä´½¾d„íphµ\ÙìQMpóýZ~°–‹æÒÃÙÊ<Éx5—šïƒ­=ük�ˆ�*LY3ç ËAv¼�FOŸKt$ú1©ùáÖWYâ§„‡~vK#ÖeA$bï YÂâå—xÛÀ+T¡C°~It;Råpí¾cÖ)®�Õ‘ê #Hpt€4v¿\�ÓÚŽ /|…ö)GhàŒhú¯¶Ý;‹>;šáÈÏcPÍ]À†Up~òÚ¼û¦øæY$Z.© €Ké°j×[¼2UŸ=õ�Ńқ8-l&'\E©ËÂßVy¬‰y]¹Ö1{›š`…W2ÈM_Œ�{P~ñüùÛ—‰3ðéêplß>¾5¸ª@‘ëEâèmÀÌó %ÄÚ°U£/+/¨ Ý|e�Äý§ìåúPö^tœkN¤�RM´µÕ�W;�þÍûð[ëÒÙº[,»k�ù^Q,ud%cê®�p UƌşV)àþ»?Kc�·ñö¯Ë`ˆŠ9œû¾‡nþÞÏ&ïo��²"„Õ>#Ûr‘®�¿ŠC3ylåö¼bk¸Ü’ä_Àéè2÷Åò¥änº’¿] M›+š3òÕÂ)\XÚKLp9/`ô&žrZ’‡þMÆ2›É¸r´íyÜ[p¨�Â’MÁ%ñ:ÌÁjÍtà÷@Ì.‡-k��Ýg²Â^ü»þ8F´½Õ|uÕñyÑpø³y„­iÒI¸i ía` šOçÆ*+ÇÍj­`kÓEÇææSͽIl¨õ™ó®”ó]÷zñ€›:7-èÇÚjC¸¦a… ·>Ò”†£EŽ%¹a;ýãQTøðBŒZsUüè·Gñ}o¾>›uf*Ò€ºÒß Ô)´ƒ‹ëk.3�ÂÎ1k¥‡¢<§\Qå ‹aëúZÔìN³k]±Ï·zJ¨1Á':UÓ†ï“+þägãÉ’¸/M•e7›à÷ÐOàø�j„‡ÂØ�ðÜ’KW“l®6[npæg«Cq¿éf(kÉá7ÙñìªáƒûCú¢¼|>úøG˜¬%Rì¦*0¯ 5çÎóV-uþ ‡­“›áøàEtïÓNL—¶ÁYɘþмzc]i<ö\ˆg߯*ï:óî¶o/�NG‡ã·›Á�%•ŒfS ÙR“;Öy∔(6_)øúoãÂŽ?‚ãÛûÁ3‰ºúrùªdN°Ö‡†ƒóù´ÓTV‹”´6˜Ûõ/rˆ_ýô½ˆXs�n>¿¯âV°Ò@ 8¨ÙÆKÙ@Ô~ôÖ POŸ|=úðºFõo4Ñk ÔÙÏÕ›i¨/x±nÂDqÝPÕý–zó�ÓŽ QõY§]¾aëÓíÎE…è�è Ô /äÚÇépkŒ=>n¯/HÐYÏj¼©‡b dâê‡ùœû*MÇ?…£™‘ü·ÏØÛi˱í¹�°¯wåÖWÚ•¹[®“á¾…ÔÙã�F×-ñÌâÅpZç×aÇÄ q‡a{b•ëd°ÚÖ<|b–vî\éÝÁ“¸Cu ZþXgÏ>Á#1I• K—HA”u0¼» Ê)ªì6è‰pèçZ<ËæÅ·Ö³mêr\ØÃ&*K¸ör›—Cô^}L\¨Œ/Þ¼×/×eâP~lL®Q Åéðø¨+<-7ç‡oíñNÚbž³1íõnt´¼D6× �Dðˆ>¹\»¶ƒ§}ˆ_özòß?MðÎH•§õ>Âå{lOÛM…û‰N¶%OÈëÉàá_…å.ÛñPŸB•ÓJà‡I|~k(~2 þ~§}rXÒP€¿ÏšC™ý ^QïJëG*ðEíôÅX µ_Úý¶<²ì½�ÓÏkјڃä™QT¹d÷SèºÖ1†M¼no&>é눭³ƒyÐê`ÞçvAЫZ ß½µ9Ž–SßLJ)s¦>/傉“+Åm[À%SG‚qK‘Ð>6Rü½{$^öžÄùzè~r„úgºøþÝQþª¶ ë‹<ð’äzö¯þHzÊU°$ù0‡+�åx½dÛÇ)|üñ$45?Îû¢®àÔ”R2³ùÐŽ»âµ�áÑ®'ð³0_\¼s0Ož$Š}¼ÂÙ!¾?d-V¬ê×ç˜ñ­Š"gä°Yr¨Ý€£Â¿Áñ·ÁÂLï qñ?PƬ ‹Ïž»ÑãWaTb5]L9�38³{,ü 4à®§)XR —FóÅëu´¨0GyÝí†ÛñÞ¨d‚kÕ^Úd¾›£æ;ÑÌiýY/)¸1�¢Þ:F·z‹ á²h0i5zÉóûASÈ¢}6­ÝÈt²ËŽçªM‡cÕžâVß�pÃäSåà/ò˜qY@;q¸ð­u|ü•‡¾ó3`Ƥv¡eÒAâôÂÕ4 8‘ºÒ+¬øsàG¸Ùïÿø±^½³à?òàÛþ™•¥¹jîše“A‡ÿ¶ ïm죬`µ]/œà�¨ØB‹¯õPHóK’,Ü„fÝéda¿Œ·uÖÙÞê[N7Çí£±Á;±Ùm<_ñâÞÃ¥W‡²ÅË=”Û¥%HïJáßÏàãÉq¶C~ûPýÇ>¬ï¾šÏd¸@åS_Vz÷múʰ[�$;ÞýH�Fþ¤¤¼™w-\�1tQÕ+oa£‘„[Ú{hÜt'”k KŸéòÀ#ûXÖä%­Z.:ÏÝB9Ÿž¡OT%&…¿G›º 0äˆ Ê��¶ñ¸mÁ þ,="ÒöÑûÚ!ì—?Ìe„ÄàÕàݸ÷†YcãM#q\g1Ìë­¹RB‡Öø4À;%òY«Y—·”½ôq`O ñ—"ü»¨]yl)PÅä'#0mó:^–}Õm¦ñ.�tTè3g=9 ÇÒB8WëßœM5ã‚kyÁˆ<˜¶âªh1g�ßÔŸöŸÀô*#ææ�0» ­Æòí3™âëûsyçÈ‘ÖKàïÃú¢„Ÿ‡ît›QïætsF&øJ!�™Ì Å�pZ:‹V (U¥ÊËwEP‹ýFѸ»6·õC¼8”¬ m8õ@,ðï[åVŸÀ-_góÐ'W…ä/½°Èi>Ö}s…•–XôQHË{ ‡Œšzᛚja·ÙQžÐº–·7fUŽÔ7Àiñbó_S*é·„gLÿ·G µ>"&Æ�K±•*9 Ù>Æ6GÃÌn'q9(íiæ[�îølújÞÿj ÷žAŠ»jipj?œ³B+Û¡–{)�¸³‡¯.ßβfçá†Â6>Õã‡ë| èÑï³ðÙ¿?î® @¥ª×•oe*ñŠ÷2üž8—&k<æZó›4&‰:ülxqÏoJø/ŠWia] ~›Ý¶F²4òË0r»^H¯£K‰ŽÍçW½ñѸìš:‚ûï%g‹Ÿ‚öâžxX [‡)£sT8fnÄ2¬ø«�šßmâëÊ„Œ}µ´¾0š{B¯ÓvƒOBÂt9T{p ¥—ëUÕ~C†D¢¹r9­-\†?WŽ€úSê¼ÃЛm�jŠºyx`ÿ�[I.æ@Óþ8[õ›Å[KQfX±pá ðË·BJa ”Ìž/ºîô‚G“¥«óˆY‹5@zÙ7– ­r\ëš%´î½ˆ –Ngçthë>ŒstÞAKÁ šuÝu&mcÅ1§htÞ~ñ¢é–«©hòK!°ï˜Ý>˜–dB^V’p´­Õó¯Òä²5(1-½³ÃñôrÆŒ™lqK¬ý×s¯ܹ$Ûš·/qÂg+aü繜Ýð Ϸ݆œÖ`>laÊ߆Ì'ß5itîÅ'ð_ÞMãŸká…¾|}×BžZ‡®MÚ8¯Ì� nžæ)ZsÙÈò+x¿JŸê2òzüІ5�ÓÛtpW ÷O'³c/É!÷\·½~þÒ¦Éò´ýÂ5Ì{ú®²óá+8S}âdq}³kè2ì€d Âõ±á Ÿ"!ÂÂõh¢çuÒwá¯,zSé8d0–WìŽ};“$Zß ‘Wí(jv2&®þ&¸ýH_›\£Et]“È/²¬šD¿æh“Á•Tþï€6cj:>’½" HáIYF¤âúA\¯‡Î@ˆÔ?? K‡S½Ù³× V ô¥I,YwÍ(œÒ�ÄiC1ï¼'d§ÉÙyùVsÁEŒJR€•�·AǨœFFÜý¦|Žëqưj3V<à…>ÿ¼ðɘ)øØhšŒãw÷Ú¡6î$ÀÄh´žÖ·JuméMY‰'¶ ®r»žÍÚCÉLÜÃp°_Ê*^�}J& Ýy±xñ–#¯ù¾ öýsó”' lxÁ öKÓºûS+ºÚA²¶¾2ehy̱Gt!þ½|47˜ï¦ü³å(£1gÅÞoD6ëŠÑ;†Ò‰§[@ýEõïåÌ3ŠÔÄ ?‡U:¿ÎÇåk$Ø!h/oßPMå®i˜x ¼Þœ^l”Æž;ÂK¦ˆåIV'¡±L‰·Bhô†+îIòãùT}k‚¨ði.¦4Êsé6cìT1ÂÒ ˜/yeðM9s�±à]%…4}Á8$ ß¾æ�«rP­s#îˆ Âî§µ�ë•„Sì¯A°A ©>yÌÃG±¯YÞ¸Oü×{RBq•ËsPÊ<…=³+©¨@«·æ‘m¸”݃cŠ8é|;Å̺E‡úÃ|nã _DãÉâ´Ê¯ôìL'Hý ·G1IÇ�Ö”½§5jI<®WO7æv ,!íÉÃßGÀôƒ“aÏÖ3ô´Î üGd±ÂÝ6ü°DOÛÈ‚\O.µ?†÷ßZaø¯ÓpÕãDŸÝƒ—&ã/=´.èdÏÏ`«7Oé·ï-*t°ùòm(?t<�ãu9 ¸KÐ_Xy`Ë4Ð�<�)ÓtxbÏeš<ß µ"úàþ€É WcÏÝ'ÔÅ)ÁûðŽƒ»�œkë »užõÁ¢^÷`–š¯ì¾!ÜPÌA)|, ŸÓ½ÍÓ…�OÃyäЛœëM‡jÀá—Áèx;\ZÐCw·ù‰“Ì%aè“Çp± ŸJ§c=»SÐ99�h^(»÷І”µS}ââþš¼pˆ;½�3`ÕÚ»¶Û²¬ù�‰ \tŽ«ï1ßS‡áÉÂPã#Ø�—ÎŽÖùø£Ï"–ûØßuÔ}Þ÷¥ñ¡ãÁëL6kò"Õj\ïÑ—ƒCôù’nö+¾Ç3%`¥â`Øþœb��Ê1ö]­ŒUŽÛ®‹¾ÅÍñlà”JÑUôu[¿ÒÒÂ>1–O£ý…«¬ Àgçž!·Ù \�MËS€â€ZÍaøôádÜ0rø+™Óîq30{ó¿óø>•¯5àû±3X¿S.ïß †Ý»Žê Ç �â¹®°¿ÔÓóÛ~,ní'è^ú i�iá×ÛöÞ‘wI–oóÇyit¿[癇¹"o|oÆ3£°eû¡Ëi?¿þþž¬Æ'­ñãðǦ´õy—¸Í8—=ÇÑ6'uô²�’oöçó´,×ùò1Ýb°[ �â—;¢É_ô}Õ nU0n•Ø2³û|Æ~“Žvûb}` ¬î{ úþcwPÐXš ]Æ-œ­@Ì×¹w^Ùâ²3aºnYó³âüÆ•´]¡Œw7)aÍôÿ„¶÷½ì,¶(’Gþ zýê<õ-U‰‘/a¤µ-³ ðͯÈÃÜÆzD¤!ÊØü¦üÐrÔÐøò\Ü; §üÝË»_¡ÒV[QAñüPÝJ»ÔÒ±->°¤Â ©ŸÇKëòÇ%é�| ùÛ�FìZ'ë±½Äq*o±æ�··ÓïÃ|¤]Z¼“z@xY1ú;jÃ'%löi‚—Ÿ¼¼ø2¿ÑfåTo2å�æ=XUt‘>KTàê‘6ü³t5ºï’á2ùA<0Áˆëkt¡áÚ5¸ê´˜…BÑ;„¯öçÅßóþV^û}•×=²æöÑxãñy[Ϧ‘¸sFä}ÅÌîµBØÓñ˸ð¾ã�ÈvÃNašúŠ/GšñÖ§"¤”áÖj}6ʶ†­½°ÿs»©Ó}X,ÐÆ[•ovœáåªáWÁˆÝ²8ï†6ìr Tÿ+®_Õ B@åúaXgU‡ðÝ÷èý)®Ì½Ì^Z–Œo¾ÂߘFî牯ZþÂ’¹¼â6pÄâ«ÐJƒ!èÚ\,¸§Å=}J ¬.KàÖñdYÞž†90VMš›tu¸óå^”;ÍÛ¿ãÓ0}Z\½— ¾ž1‚ë O¾µø ”[Îr)Sï'9½‰Òá|ÿþ¾yãžÍ›wÜî~v%䈲�G@'l2ªœ-Ö§Â6½,º°0Š+æ°‡Ö¾òYž}t*ª!»‰34’_�À—ޱ`ùÊ—O¶F9“íØ½Ð‡ô;Æ“<€­s*Õú¬!w©êªíÆÌÚÃßFñÅwÛxöÉDÎó÷A…°üý/íWZðY‡б{/Npú F�ÏÂcïÖ jF6N¿oÏõs¥hš02‡wÁÍìú%�–]ÜKO“ Ð[êû-!šØ­€Ã®ö@¡rUå/ÕClý~3å? Õ†‡Ø|ò:>,“@Óërý„8þú(†$G)?,örsPº8Vg8žÐÒ¡îÆ±4sÎDœùÊ—·OæD«$žõÖDHµ}×Õ8áÉRc=¸ñg~yíŽ2W×°§b#¸XäR¶W )ð&C?(X£ØËG·ŒÂ;ËVâü„0ôX¸úex¢GÕD·vÀòJ zý^Ÿ,NËQÝâê#.Ø:g ?M¼CRûÓñNV<ûÖÛ<9æª/Vå¦'g¡þD8�÷W�HùIQ¿Mð„A^ÉÇÁÜ…Cùð¶:vé LkO=—VÓ­h7\»Áˆ�JÍX¥yXgÁKåHV˜:/ûJsÝßxl0„WZ]1Ä7о/N°Q�¹"Ä�3ÔYcª½hÜmÍk»WÃÍÜ8Øù·‰¢¨ŠÞý|ö�Êœ³¥VkOÀ„¦­l¥®#N«?F�r…–¢$á°ÒhÚ×~ŸMèwjFr¬oü]mÉ;«iìYÐïÓ]C+`ÊÊ,6¯úÅñY+…ÙÃ*…‹&ï!ÌÆ «p€ÃhÚ¿Z›þl¥C—Ý@­% /ô Å‹&ݪ¿o×ÏåƒM†0À¯?4%þ‹¤2 ša¥š²"©7 s/˜¡¯É~®‘›CžN_…Z“i´qË<“‡{½ýyòéýÜp·ŸBoüx^žKÞŸàÍø¯þÄAÛñÍ»HõŠ >ÌÕ¤´fCè×iÍ— &rÌ�µ¸®D–�£�qÁ’á\ôD‹÷Œ²å«ÍÉÜ@I ©Søôø-<~N<ÊEå‘B?yN¹‘/ 5=R1?F_+¨ŠÝ·cÙTr:˜;�ǵKÎRæž…ÔÔ™.ÞúŠ_}ýøïÕûü×q§!9ï�Ùj èȪs8®1¦eIðàPUž1&œÅWõÔ×÷'I/(„‡]D­ð™ñp1ßÜ�Þ=pÆLåhÑPÔ!Û¸ À‡°ü’^Ú�Ê3þ좲ÈLœ°ý¶Ø ™Ì†›N³WðRÏ”æÆ Ó²l¯<Á¥‘;EËi‹ø¸º'Æ Æ¢ézp4ºÌNïÍRipê(ŠÉ¼1ãÂðËGuêpLÇéIó@;~'îÊü\¶ Ç7­Åa·ârÕÓTÖ?†zÕ]‡ì„DA£ooJ58Å—ÇIBý|�úNsz‘‰s5íh�cZ‹*ÿ,mªl—5ÄkGbZë6œ¬ìÈž{¥ùÀÑ ègt…c¼‚h»D ½x3 ‡ ±X�_$ªÔ.båÆ*~'Ÿ_ö7ãWeË ®Ñ#·0,*¿Âýgèã¹w}ø¬ÜHþµôÆ\ß%:»Y“cÅZ?ð!ËÉÕ‚d÷.Lþs�Ždö@²ï–{ï�wûIƒ·Çx`8ATŸ0³n#û…¸àP1´ ç018„Ÿyk°„0��þ¾!É=a.@CL4†ùWæ¬'¶JpûLe»Üé x»•HG•ƒ\¿S¼[]ÐÔ÷Äœ‰£k­ÊØá-ÃψªC eØ ê½$/¦Îǰ]Å|k•ÖÑÔ‡+Yê’k¾œÃÍïqÞ„Hܽ¨ ž#”¥æð„A{Ð(h“Ñðä¬!�½¼éÑn Ú¼åúå€Êè“ÐwÛ(JÎb—U™lô~ Xl�/ž;p-ó­ÿöð«2x½2«6@Ñþñ¦Œ.¿Žu€}Cüe×U®Fë¡Ê¤j— áN P3�Æ=ü.Y±ãº1ÿÌH¼v-ÖÖ˜‹Ê«ë©Ïê°`Ë—ÿ˜†ÛE±K^\ßކªJœk<'è{¼¬ƒ'^ÏaÅKÉ*½�ºôöa¬yu7HDÐ�±lVxŒÍ…°db=Êû˜qŽî|Œ'  “Ï#ñÓ_9PÛ<C¬XÒå—JXW=Wuá]¹Q´½Sž?¬·§¯_´yjJ9Í7ÕÁ°³=`m<½’ÏCça)�§…Ùߌh‘‘3<mFÖ ÜħPô“KäîSÒl'ÙîÓIX A¼þÛ(4ªí P¦ÜƬëCþok¸Ä$ï?<Äv—'Q÷¤Ø]—Áâê<´ÅàQnBÖ�Ѱ~ÕbX)ï€i>6“$³@Cá×TŨÔ56ÒÙÍΘ¥*ÌùZ€>z_ºS1Á²Œò+üsÅ…`¿½† ˤÓÏ—rWð"^˜ôìØ, 7 Ã;NÚÞ›§©N+àè“BþV5K qPa9²y¾x£Ÿ ~�£�×ìŨ•çà²{J«[âÖ’%üÔ`/îQžÅžkfò´ã[Dù�T;” .ö`ö°½3�ŸÏŸÃ¦µŠjr:ƒ šœ§•¦‘|£ mVf£öÄ+ÔgéqxT£‡cì÷±jû°lMèÙƒšzK1v}/ܺç:e͘ʭ¿©q›„h=%ÛÅiÇEÇ_p–à 6í;ŠÏ„èÓÜPUtX–ƒ¾5‹yú�ÍÂ¥ÂQ }ô hœž‰�'Tس"‹dlLqÞ3GAÁ>wß}'6—×ú¼‚óN:4ý„:„=û"ì´š§ÇMÁ¡*($ò5gè <Ç?bÂ}håårê耪YºÜŸ£iÍÝ0áý£*ô�×­N©³Va¾¸àV?ÜØ”D+Þ„3ÒOéãé}°öw[es’xíÕá ²Ëxÿö!¼~Ðqæ‹)0&!‚#7¨ãHí~âÙ¾—D¥†NêVŠËäùêcôÖ¸ÅGçùÓ!¡Xü}7Z+;„X¨ÆÂ°�ø[ º“þÍI¯©¤f)Ï¥£¾AiZ •üqÂg9höÑL^¹‚•$wSÞûÙÜòšu7ŽE©Ì:�JlÃc°Ò5�çîéÕI aíó�pm`ð-S\µy=>»*]£É+GÝfÝ"4ÛðýÏ9h_yBÒbÏÞZ£Á'.¥Ö'+ñjC2§¹hÐÌUݶC_vBYÛrñ{ß㬰T�Ëð¸*¾mN½j,ðË¿ìÖØò¹ÒÂ7Êæwv(Þ~Kü¤9½ûÂì°Û´P=Êl¢aÛ™",nk¦èˆQš› Køðí—áðsâüïÏV\¸ÑG 4ÅS ¯¿¸B1&Nð&w4«uþ…µ}¸<ÔÇ�hµ�¾$‹ º�lçÍݯG¥ò¦_‡Á£½º¦ó‚£µÚœ²K‡<ˆ?C?ÐÖEEøÈ´Ž,ççúÃÙµ¹Ÿà<ëþ›À'œ ¡·áÿ(4ïh.¿?€“-d%ETVd“Œç¾e¦$3”PÒ0£´K²²³"”(+É®ðyî%EVC% Th×·©_¿ÿŸsÏsîxÝ×ëœK°O莞ÂÐu‘¸©s)ѵ¢´éÍ!â0Ëj^`Ø—âËò“Œ}‰Q.óC²” ·æïÍAû) ×8 S³’Y^ù&¬>~”Â|`“t$HÞŽ'O«¤Éñ?¨Ì¿ù¸4 §gá3�Gô ß Ø{�†YZÿf6L¡4V–¼OÉ'TªÛ‹N}.‚žËmÔë·ª>ûFæ•ÃFÇb0N"òfwÍîi¡ÛíyñTU^~^Šê⃬½¨1$.‘Ä¥Çì°€·)(,ý‹Ég"áÅu*=qŠøŸ$'çe‘u½ž�p£#ÛÖ0`Ô@D4¾�ð‚VaŽ&&š~†;ÇÇ£_·PqùDöÐ!b¢�¿Z:iô÷uø&6�ð„ñ1…FFØ2ã"æÜ»þKØsnpQúwèL†˜µ #¦ù‡ au®H�É.WTQŒÃ­Q°AÇ–JÝ„ŸÄQ¹£�üì3ÁÅ¡›a5›Àœ)ã67«L§ÖªÍ6Ù·ã¬7ÙÈ»õ öƒbë¬G§Ñè¯:4Iåd½$w%¡5µŒF_².K!‘o„þj?A%bÄh6\ ‹Wä´|V꣑ Ád†½:*ͲÁû¿g€†E> .¢Ñ¢�(²W åïxcS¶¨ùŽS›°òùab^„�³…ÁÂb+Qz|ŽË%Í xX¥/&™¯Š×Têd6˜¹FBäàB²Š™5ðxšÄdÞ\LkœÌôý×±oΦ»+Ç9:]jHOœ¤ée‹aŸêUª•vžW°ðâêw’±²µ¤ráöÜ$ð2öEö8ì�ÖljTÈJJAå¿8ºêéäEÖ»m†Ëƒñôiÿ1ð>y6ë ¶¦Ì_Hû/`ˆk>6Ü5ÿpBÅ\ïß|vp]!Õ�ópÈQ™FA4ýÐ Ë{$Øú™ßa4Q”ú¯|àó�ed,¢è)Œ!oÂÓ ß)•zðC�ÿS¨ÂE›D±uy”Ú\#­/N“EQÔzÁL”— ˆÿ¡=q(·o~-»N:Æ�aeÐ^h·Àªòwd<ânåÏų»qókô]´ cV(�Tl3–ã‡âåSL¸åU˜¯éˆ³F—ÄaØvGÊ3¡Õz­G’ÜšŽ„K‚¹8eÑ Jw; Es)˜öÅ¢WÔ(|ò°n]->H�ÿAþjyÈ_U.¶³úª¡F4ç<ΆWè`ÎøéôÁ‚O®l´hž+{C_]´Ã’ p9}Œ­ÿò›¾t Ç[R?0@Ú‡fËcoÏ3ä¦ w© ;òÄùv Ûh?ϼÙÑ —fJ›ÏjÎÃ@·xtL3¡ñ�Agw&Q+Wƒ8áòÀ9{4¦é‘[¯è¢¼!ªÎÛ ?Ûçb“€{þw36º¾å Rt�þª™…%é9Ó(Øfù˜¸‡—Œ¾Xê®.�l¿ ¶o…L_ÜwP*_}¦_—À_S �%vš˜•÷1…ϚȲ¯ó!p/7|0|O,ÅY=ò1Õú�*Ã¥—‰þ:'R»÷'£›Í…Wv †± ü­¯%œ1ܽœ¢é�Ì{¨ëऑ€q²¨y#ú:#ü‰ì¦�ØÄöt†r |·W¿ƒ„¿X³I sÕ±)ª^…D\‚úµ/a½Zd0úµQ«æEÁÖÒSƒð³~ŽF²r³: Npeâ—\Ä3:ëùE�]?�Ï5å1×g6æníÒ݉¿b`#×0 › Ÿ=ºÑ­p+¾•)gŠþ¹°õ=’}“ûËàË–Nâv4Ÿê|D×í娧^˾ɓ÷w´0u”—¾¨á|¼5½\6`Nù óÅ9³aËyÌîU‡?ýmDßß„œ(½NóÏíä„m®ATjö zñ¨ÌÕ%xk}ˆ®ŸÃN LbêïÙ$Ø`†ù•­? €õ@û”¨–ŸWÓ Èɧ—BðÀu6F5„ÔÏ`OÁ5,È9cZvZžpc—ÐEÜЕ¬ÍßhæÌ8*„¥Ä!Y«‹¼tË$5«¬ ìW#Jõ)pvj�ì©.f`W8vÖƒ±l,&ø±ìÚJ$oò@â•^ O—Àþ*Kð}îÁl“Ÿ�_ýÛq°êñiv é;þxÃÏN¦ÿcÃ*ã»V±†;í›Ap͵{,ÀöÝŽgsÞÿ01 5ÇhTÔƒ-d/{Ô;�å¿OÅï$íÛwt1‘F¿·üÀ£_ß»cKY+þà9N² fÀ©#Âà·—¢ï½b”¢ñµòˆ ‚a°ÏºÀTÉñ ÅâNüÕÓÎyPÔD‚W�‘ÐÎzjËç4jÁåš Ê¯¾ˆëí$1/¹™F¾;†í³ÑÿÑm�XAæ“5¨ôí³>wõVZÑS=À[ †F…ú*º€+†Ìàu¦¥…EpCyÁ?(†&Þ�l\BoäÍÆÖ¢cÐSðj¶J�Q`.¥?`r¶­Ç]6¸5î8uqPÆÜÒ<¸–GÎnP4 }G›ô.@Kìg�|» {¹@ú¨&9¢P u*(ÓVO�·<§+d«˜xÜùö7½”áBLm/ÐÏ‘Íè(–lö*$�ÆòÀ¶Ä¹­m-çÈûS:ðÅöŽ®?AEg á×�Òæ®ã‡/Ứ.AIúgÍ ¹Š]âÁHmðkèCz)J†¹O³ý$èã&ghÒ#ÕD2Ôv‘;ûöÐO·GЦc|v9cVË£~¾‚­k´p6_7ûrÖjL–L�Hî›TðèùÎ¹Ž¤ü^H{ÛóÉÛØxÓ“Aßׯ³LÿE{ˆ~ÏÇqÔ¿È(¶Fà{�nò÷}ÄÛÉÀ÷ÒXfM}·Íiõ˜œ@¾0'£Œ\wÓ€ÞE\PpÁ}ÿËcÏn€O†óȨÎYâ§W»¬ž͘<ߦh»Ê%Ê6? ±7¨âµNº‹OÖÜ’+òÙ8¹í l=\„õªáÈ7e×ü_“cRNŒáÅgpyÉKô ºOg|ÐV¬„Êqi�Ê“ 1N°¦‚–âÖØPx<ÈMŠê±öà"H_SK‹ŒóÉçF-¶#ô)kbÜL·•'aÑ™ûÄ5è}ëM&[+ÈÒUZXR§~ÿ³Eß]©ŠO±ÈùEžéf€ò<=ÄsZc{§èíHA"ó�}J­/�ß}uðĵÜtuZR6]õ¼ý"ŸŽ;†Qîü»ôzr ¼ï ï%ð׫;ìG#E¦÷F!lƒ˜*–ö�XßmUØÜÎú¬“‡Ò/©ôÊ?/í]ˆ†÷H÷Ø*RÙ€k5®B^Ö"¿ï•5¸�J¨Ì3i0þ67£(± "íg”Íÿ.ààÈA¨oÚ@»4¶‹ïh¶Rí$vw/‡Êû"4÷w*èÔvЗ¹âÌ6)^°¸€É£mÔxŽ<›4Åë«iÏY5b¼¸DäQ¿€�_ÏOÇ='>KN£¡šÍ„Ë膬_D›ë ¸NPún5\[F|dùðe6j•;7Ñ—^Gq� (ï„ôUÜpgböK44‹gDÚá‹Í ýá ¼üY¬ÈAŒˆ <45ÁPÛEàhú‰éMÐc5÷xÑÿ>å“9M1hVáήô“�¬‰OôQK Ž™F¹ÎÄui?><˜�–¦ÝøüÔ8¬ÜMfÅUÒÈêbv9ÝEóܯ“7%ÙDynÜÏ€�MúW Öë “kC_ð%ßlR.ý„„<°ÌQì�Ñ¿ÿü‡uÿ�‡|—ƒvÏ;4)=C&ÿ»E%§‡È¹¤yؼº‘¼”H†Ñ TTS§óà ¢6ÓEÔLô?\ïÀ�[×-Çüë#ôRâ9hó5eˆãmÈ9OR–ÏÀaz»rƒá*® #ÁMfËŸ:ClÍ|˜)…Rs7ÀKcÕ5ï¦^â±=¶‡Ò{ïA}ÉîwÇ­¶´âÜ:Œ<¡/ž´Ú^t þ› %ê —¡WZ)Þ¼ƒ.òðóáÛøhí9+��_]µì—cÉš† TâÍ8»¯*EÿK =[¤àÚ”=ù„�JKô’±z/|&£¡or¡2`Š#7Ì…"½gÑdò“9] õc×hñc„ËâÉôzøløë³º®Ó=¼¢˜¥SÉœÖû××µzhÃk»›é¤²,æÏ±ÇGO»©Å« à¿ 9ŠmDb}œØ^Ëx*s÷ÎCÄeºê•QqØ ØoØ'þ@Ÿ…ÓÛ^�f7'N*âá,dnº o�͇/¯~iN59î|ùñ�ñ4JÉ¢þæ ìè†d¢â°žœ|ž o†£Há vGu³ùxäô/üÜ f³VÞÁÇå<ÀQŽ!òAOèÍCâ­�ÆàˆõF¨ª†¥ý«ð§ñ%šÑMÏþ0]7©‰K kŸòŸéÝ¿ùôaC¿{JV˃îÐIvÂ.…~7ègÜYr¢7˜fì§å.ké×M™è"^AŸ6JÁ²»ÜäÖÝ ¸:ÙHcõ"ñíÒ|’ÝN ΄1}3“°Áï>9qm”n¹ÿŸéµ³§è½�/ØUjiÛSˆ¸p�]sv�…R¼ãçDªdFÅr©JÐWú›ÑÄ“WuPÌþµÁ7¢ûÙ–x›ƒ’SÛ°ø8Ø“#ÔÈʬÕ/Æì–xÃðe°w~LgîŠg–¸Î#ëD¦ÑãLéÈbèO9à8=¥Ž ý$h[6ª—ÄÁôß�è.“ߺÄà¾k4ì^ñ�v>YˆÜ4Ð%È Î†¦_õþµ·S2»îA.É9Å Dâg¼Î›�3h«º ÞMo‡þ ™àur�ÌŒ?€úåkX¿o è]ïã¤MÒšVþ.'£B_hI/ëg· Ä­¸Í3È:|ÿz˜yáŠç¿h`½ *¥Ì5·ht‚#bk`†u#q; ³nÆÂúù¡úä5i8ƒ"OF‰ÈU@ßÈTÊgš¸†À4ó†îòÆÓ!™ìô�´s„²RÀc³0jÿ·ZZÒñ¾S}U'Lþ€=*Ì„…‡Þ`÷µYèÍoŠ/{¢aÙn:êúVû²ÇwÉÁ�1HçÅŽ<‡È;èëž‚a‚dÎKòÂUd>r”R`FêÆSã?F3׃d-;F­BS©tH+Ùvû!¬óž¢ï|¬0õŒ sÕ*Šxz?%N«µñÏÆ5 k«Otì0æu4YÙ‹ɯ.’è²8¬äöǧÍ\ø×ò'鉀ÇUE(eQ6Vx2?M펠ÞqpöüC’¬`çéR:rAîÜKÇõ{Ôpó³[póUZ›QV|·tÎGOûZò«í!ýöŸz.ª§®ß# eUôV€(„NI£ãþ "9äñ糉v?ŠË ¶ú{!ˆî˜‰¥$; Î)À}CKᘈ/€.›Ðaæ†}Ã3ñ^Ëä_îƒ"M�À±ÍY'+<.QDR¹%ðy¦>v¨Ä’ú@u6¼^…$~·ÉmðN¬Š<«ƒ¾=ŸÓ>(î|D4Îë˜>TÉ„IÎ<ºU±˜l^ˆü!‰D³/‰¶Úx ‹ûuƪ~’1äÅôe.ÌÆ—hDÑ)«ñôéxÚŸ™Œ‚<+Lm^죙Jwh©G :_EÎèEÉ_íd~Ý>ªþËcôÇÈ ¯�`ÕàDt¬¨}Ñ5rco)nµÄUkþbOžDl=�s,cPöåE²]´ lVá律¾Îøž;Fç õ«|öB«2©sÕéQ’Çmªà”ÁExºx/˜‘HfxãÞ+² %8¸“ž‘)þ�Z… òâVÓ 1UN}Dˆ`O%´ºSÂmä°Ìÿ�µJ–/[€Ÿ¬_³_:b@7ž(YŽrû\È‚Íéè;‰Ã­pžOŒÚHÜ¢e±é¨/ù‰:¤r`7ån½è"Ãè¢ÃÞ1(8ÜI|ÜŽÃßÁ4ÿ²‚ºG;‰UÐ&ÌQ?Èxä‹B’ú5’ÿdšÞ¼—FM¹‹ÀÕp/Þ¶½ýÂåìû-Œ™ì]¢«ù‰QˆøIˆ’ÈÕt‰ŠMlò$ƒÇlPÆÛ×í'Ïž9‘U³}¡PÊž,³)Æ­‰`¿u6½m·”ÌzI‡VÇm?tpcÂ/p‘°çðf”’ísgãŠßÈ£,tS¥‰S(5r™„Ïäo�>Žz‚èxÀ…˜÷G°WEGC®ÖË¥0V‚á]pó¿z¼ùõ z]Ã[Mr$/Ê í�—“ õ¸ì÷ì.ÖAÅì"Än7 –!0ñ5˜ú”̧Ck—aãø:¨~š¹6JxC½ 5õ,جòd‹šÖAÙ4ѸÞ)kï“l]¤C¥~ôûmúò‰Ï}Œž·»2'I�Cü˜ìcL_M³f »('ç;ùr;rm©›/é” ÅÛëþÒíDÚ×vª.ôoY5óV•»õ}—ئv’ü�û èt>ýk|zª¿‹£¼x%ñÓ?ׯ%Ÿ‡Î¢LÍzж›.®"º¥,cªxxt iáb+bðFð®*8ÔÍÆ�;™l\͹ñ©™ª„Ä¡òÏ£øa’ 9!‹ ÅÿUùËg~'(Žï Çóä7‰ëùHv,ä!kùzˆìÊ8`}ÖÓ ~™ä’Í]úXy³n ÞÀ“ëx¨ò°)¤|Áð¥ÑÃ׸Hì\ÚòϤ|Qì…'lJ&ó¾½#6\GAt�Ú»xÂ2ƒç˜<Eï†^!†j{àA‘-&ñg‚F§ uzj†å´‚Ì_òš-͘ÁË6௸3ý¶é›oþ4>Ì×l,à\;2ð뀫ç+â’GkŒ•‘[ÌO6j˜m¸äÃhrgBÑmx•BÅ:�F­àЉ“ôí…z–KÁNù£`’U'ó‹Ù•®šdèÁb,xlF55CÏÏL¶ó�ëÙ¢eƱùHÇÆòT�kOʦñ«oR—UDŒÝ�äW6¼UÅà¬ß{òš—çªc«ÆulQN»/ØÒéU2´Tñ~–‘€í'Nb\)*Ê®&—×½¤fmkqâv o:H ™!t¼Gìó\@¹Ì˜:AH¯\Hºf¯¢! 1o`‡’K�òJ+²Ö/#§YAícP :ÁÎ,›dªÒÙ�Ö{h¿h~U5 c}4Éùú�ßç¬åd�ÝnmÊ{­ /­¯bºúᦤNx®·‹Es`ìšHø;R»'G™mó§é£F/Ê¥ÜÇö› ÃIzn±$¥h�/¯Ø"8÷ÄGæn…>—,§.úV%ºž²­qÕdý½Û4txœZéͪéš_ÞÅ2aÙ)€âÁ+¸ƒ3´g˜¦�ŸaÞ�—@p�;”*F0�Ý”`‘ã ³" p!ÈnÜȆ£'û˜cÒ/é[ÞlruÃNÌSO�'«ôý“j´K«‚ÌN?ÏÜDßò¢çäæ@Ä+J_•Ó²²ó€ŸËé—×sñÖ>6 `ŸÑLXµk7¶k:“BÕÝÔáíxZR Vö%x Voq0îšA‹ãXòu©>¤tOø$d=;ŠËnò1KZ|@ÙzìáE£�X¸º¦™=6pgJ>¢§W0?„sØ0Ÿ2ævûêÔ©[–Ü¢“4 y…"(›-CæÔj»Ÿ³¶“=ü©Ae¢Ùás›qÔCÂ;Ûò¼^ÁÓ³3ÀÛx=vYŸ ¥§ÿ’ûñ'™ês´éý™NlIN|äÇ]Ç'ˆÐFqÂZ¤‚Í­xtPì$7ó§©±€5·GM<eÖKñt°7�(Mã4Œ¥’VgItË¢uýq”+¬¿O{ÂÒ†Tèߺ˜ž[/€:oiš´#5Ÿë�±kè߯~øQg!¹Àóƒ>ÌN$^œ""Õìî´Ô³)‘”ÔrÑ+[[ÌÊ×_†´Ê´¯__gó‘j2“ 3ÈA¡.+ü<÷5{.²Ý/3ÑoËÀ5¹�",¢)­óPç„4¥žZ;„îªåœ7+(/³ÀRëB2¬óËã¶Œ%ÏIZâÓ^Ø–¨}à(Œ>K¤SŽi°G.šÑ�-ÏÄu¬]%‹=‚Yd‹_&>(˜ üw—Qýk6žpuãtsìGúÌAg޾¦ýZLsåz,T¥÷|Öá$¿+–:=Âpå\悊.”¦÷²›Ýñ`L8ZIçZ¾žÑ¯l�×ãçI©Â2|>7…ÖžA÷9P-½–vP!à&ÐCJWˆøöÐã¥ââÝÞ¨SË;k}¨ª?:åÆÁ*­IöaésºýòQ,þ|™æ)­fÊ8$m±0[e·ˆáµ©"ç×_fWçw›9Š·Óä­Ý¸"%BÑÛë‚¥Á}im�±Æð–Rö‹Ê-²®ã.•ÿ°3ãîcóé·ðõ¡^>gàûoC˜i²�­â»Mæ5¾…ïS0�œ@΀5 ¿A.súÈÜ;ïh—¸Œ�'C¿ˆûô Tº@‰jÿAØþ)6y&ý·ï0‹o_&qÃ5T°jhH˜ ´±¥ß¾RÃÙ2TN!æî÷FÓ]wq±b >{jC "±§Ü�˜ íÄEMOØÙSÎðñQ<´·e¢ÿÙ[øÑ/‚vÿ] uþº°(R›<µÓ‡ØEë™H5z¸¢eG„!7¬`öHJâ†Q�]Œªáªõpvõh¡Ÿñô•›6øèœÀ:¸Âû>í¬^KÊebáמÖ'ÙbøzL�-þKÎ÷²öÉ÷© %ÿõÖH ›\Ð Éí)p©qÞ}Aà =ݘK½Zäˆß¯B øÓFnßìÉûÏñhÊxF7”5î§c¿¾Ð5¯‡É;1 Hqµ†%0‰3„ˆ-ZYâM÷Þi†¤>]&~¶�°­i˜¼|1ʼn‰Ú…ƒ‰$ò –_!WgG£ê q¾�BŽ¿Ú�5Þü0t)šçrH.÷aLéÝM&ê"á’äe2ºo°ç(ë ‚›4 ÿóXl‰Wô�”…Dá{<¦ë€wi%b�@ë …+TcŽr{áûaŸv�l¼‹w,Ûè…qÉÖîÙÛÙwÑ�ôK6â¶EÁ¤Øc�½ö¯Å'¬¥ºÏÈPB,‘s 13­9Oÿêhà\±Oôìc~úhÞ'*“^N÷=äÿw~²"·íáMéVÒî¹7E\æ(Ï­€‘¾çPE.¹v¨҄YCÜÖpøŸ·¥¶ÓÆ+óð9²Mëz áXÔ9&àU##ö:Œz“ATœvcØF1Òü¯I’˜Å8]°v3™Ôº¶‡,jà c9-qËœñï 1=p‘[[Ò/ QH†G�øñÞN1¬[¤�¥<ž¦6VRÄwûWÂŒIé¼mÀû¯Q_–Àãóƒ°æ} ^Zû”¦{Ë3—Ï/0¿¿ôúà%š»(Vn$…¥˜Cíp¬ö(VùëcØ•+ô·7¡Ÿ%FÉ6qäï�6+<÷‚8„�Åo^êÈsFt}¼P~áyßíMfD$²ÊzPÌ݇ÜU÷¨D%¥‘,~Ð;ÅVôg´<<²›HÑ>›]Nù†$é%­uÄ~¦`ëdÓu¨n �5-2æN�FÈÛWùBס(ð%6ÒXfÎÊ�R^ê€ó72ôÃæi¼RšåýH!|îŽ=dF¼¥—ѹ—aæcnì›çG¶n\ [ÎØCÖ àt4ÒÔ;�$Ò<÷ž‹ß[Èù¦8ÂuZ|Û-ɬK€ß`Œ2¿,:Fdïf¦dU¢¹B•¼Z®„Z'3i0ÏK²^ù>|¼ÞLŃÂ݀ϛ{àÈ+‡S–eà4¨.âó l·0ùÜÉñÿyâú{æ´‹û7Uu¨"WÝ1¹V¢ÿ9Y4SÔÃïR�ˆåóhª§2@Þn½oÚèÒ²ÃÈo¦G¹OëaÒBÎäznÂX´0{DêH‚~"Öm~ ºbgI,V7�“z—jˆÞ“�1.a¸>s’zmX¾ Ž7–áƒO øåÉUäs]…z‰‰ß¥/ô©HYûî \;ñ‘LteáU]Yó§QLű Œ÷ÆÛll|œ¾ž'––KéøÉ<}ÿ*a.Ž™¼x}ÆìÈwsâ¶X—-wÁ”йp؉�«>ÇØQö £;qÛ½ü ˜&m„FÜ"_Œjo%�þÁø.u&fÍçÇuyD“ýF^¿¨!IŸnµ¬2æîá|xþ#˜:ßGÁÚø–ÆpI˜™‚®ztÅ i|ØRMe€MÜóZ¿Ý‡Öš!\�ÅÈ­p£;}hïâ«ô¯À \~�üÚDQ%)Zó‡i|Ô=jeð�:è/„êðAPØÝN¤g×�Ç&A¸À[ —ḣ�W`Ûn ò¦y..˜û“tó]¢ ³ï‘ÚÒ#�ž~ µ‹W’cWAüüb q®dþ0ë0“9š½‘k tžûº÷/qZ7YýXöð;�·£ž.¿q¹5dq<©‰æËÃ÷H5|vb&~ï\LòÄþRÑÇ=¬LI l¯¢Çÿ­™ì†^öÊf$޹ⷻy’�è½?�†½ÿDz(b×'7<%y€vþ¹Dn95“Ãw“Ì6oJÀª€ 2èŒYù­Ô4ØžÿŒ%Úìx4J�éÃ�ìU?p‘RÂb?UÔj!&’5xýôܬ�^¸f×íb¼ê†y¯È[.'ø^'‡·ópχŸGÏ’ænXHä¦3�]¾’|ËÂ…j üË}’“±ZÂÿÒv%bï¸?§ZÍÇéûçT› û WànŸõ…&ÏÁäüd]ž(.¬¶¡ »f¯rÀqÁ\ZQ„ºÜóñ…©$®ûÄ †™”…2ø’ç1�]ßBuª mN)\úÛ ‡–ê˜9„ UÂ9ú»ä –úbGw];RŒµá5(¶,‡ ­aéYz�3•Vý¥Ö�šÐ•⢑VÔáÒGzìùZLð]€'ÆhE}�Ç7ÆQäùÑûDõú="\ˆÒüiä3å§î­¿ˆÞwMPtOäxóâø,k2kQã¥oscÉ„Ê!8™™�·E8Äù à©R,KŸ"ògvÐ“Š¼¸ßÐìžþÝIË®9ÂÕ¿Šø%é©ÈÄ{jЧÔ/ÆkòTt¿5÷ Å’;'©ëÖA³;—m¡Pæ(ûÊâÝݘ3Okßa+þdbÛÂ.J gãÇ;0³òN-m…«Óî¨$:EN»íÆš“gi›W<e0�6þGn‹BëÔJ:WhͻٽÊpY%�J>š�v„˜Æ`jò¨—±øÀnΚGC^•�•A'F¢{9 èóØŠ.I Â"Ó0jæÌ”œ°Ä3ùÍ“T$QýäeúæxùgÃÕK›¡}‘,”�Êù×´£P?Þ|±LN¼¦E ÐÐ&*„Þ¼ µ*�¾×.Â}±\°Á.™ÚÉÉÁ’�ËéËÖËàíDz<‹!kî1ÜsÅ•8}ÛCÛvïG�öKø^ê'½þn ¡¯®bè|w<çý�ž¯IŒïñ‚ÐJ3zþ«3*ä.†Œ—5tï¶j—:^)?%Wÿë$[¯¯¤.ÿ\ëÞ½~2yÌ,únrÆ÷M—›ß)êΆàaíêÕÔŸ§KÞ)cˆõ]<¼» „…Ç1/Cç{iãJ9S¬r»oFxIzŒLU`aŸÆOšÖaž{_CT¸ {eî3Æ÷·*Üù&ÓŠÿmÄ/ì-¾( >¹äæ†^x#©FV|@¹_Á(%v‰TÚ†‚‚J$÷Z)´ î'AìFÖí Øms–åýzšÖüÁˆÞ/ÔôìPsølc;¾Ê›beósÆàe=˜Ó¦²rö`é,ËDI&CBÞQ<ÔOVxÆÀÁò4àûKžôòâÀ›l0t2"9¡ßiŽ‘#¶Ž¹¡aü æR÷1ê-…~&xîÊwRÒÉ ¯?}¯™@W]Ó†5¸�Çyxo)!Úi;à4ÏUFÓJW-À=ßF­n3²f5:Dâ’S q­�>ØÍ Ü;aü�:nv5…¸ðßÄÕ½\¤ß+m!ŠÙ¾¸`ïe*t3 BWT™Ž[¶BIí ]úx <Ò#3Ò4 *(þº_%{œ.àËCÚ(‚2èæ+Üš¾{û¿½×ý¹!(Rþç¬Ê¡Ï;tpG÷8ܮت1BôØÅHè0T½5T¼û“¾Ž?õÁ‡±ûg!Í$ºàßPM¸&>Ðqÿd}àV ƶw9f¤„Xü2¡Ü†àáÐ^ÉÇNŵͩ�]Hõ<¶á‚&spóe0C@J/ПÏTš%ôÑÔ´2i.äÄvÓ Z Øž²¥Hž±ÎDÍçòÁHFÌ)WÁ]cm¸ñç\št½…^7ã‘.?4ˆ ·—8’v¿S4¹p�®{Ä`æß9»ÅçÌV![C¥Ío­";¬/aꊢ9*��&ï�Ën¦t{örì*_Qœ\[{„ž¸ ‹¼lG©)•› —Kd““"E¬väRs?¥ (RUÁ9â$úém)Ý‹%ÞU$¢ :~¨ÓK7N`ÜÊ(¦ÿp:¾Øl�Û/’%;PÕÔ†,Ýoôæl®Ö;1ÇhÕë.;á<¶ª.›¶-ΡÌ;*íÚ Å¥î(¾½€MÈW3W�úR\ÏX � ¸]²�¦Ù¾'²RÈ|RD”:XâBK§aLz´ì¦Áë›àëŽx�YgE3qŸó¶³!§Žo‡>‰ ü:Çž>õÜŒ¢"ÏÐÓ= ±U!°fD­»ŠKæÑjéÍp÷x•ö¶2[º¤=rÒaÿ¯�Øá –‰;Ù¤²·Ô|ú–ñŸÆ�mÚhQà„ö5"0Ú³~í×FàÍ&¼–Ò4Ø.{;³²‹šÈŸ¦,²ë©8îâ݊ѯ�Q+¤ Ñè÷'pÅ*At Í¢º½ ¨p¬–³)Ĉêš6Qy«wD¿×£•_#OX,üÃý�gÀuç1’“£ •Tñzàrb#|4Í÷à�+5P5®eïs¡®ô ÙN?§§ïïÂ^Ì2žO¶@¡îIü¶±�¤ü¹+ã]à‘íSzcÑ\l´ßÅYz%C³f‡üh\écìi{ �Ûx÷½RtSÝ1 —܃ݙ‡ çÄ)Íž ÿ>zÜoŒÆ�%Äý•>þ’j†»ƒúÌôM7|Ô­L–×¹}Q'3¾ÌDt{%„KD@³ÐJ0/ZŽßÒ"Á|eB=qcX  ÷uΰ\e8q#Âß•pD?  Òûù8%0"³$Ù—K颰ÂYØFäÊæC˜¬ˆð»²eî`“ÊÃDfwoêëP€ ³øZ/œßÃÄȃäçódå,!óCÛëèµï—I‚¡˜¬OÂë²h`‰$h­‰'‚õBæÏçNÒÀ 2ñ ÕþÛMW¦MP›÷oÈ[·åP´ø¹ÿ:›(VâÞBXr-Œ>_bgFC`q ·w·y—è–ß1ø-¸}ÞæâÉ弨f7¶‰¯G±êd™7Ý#t¸•Éðù àÚQL/öבú£àïÍ‚§A î vúž¦ºp:0™%æ -§ {�aíöbjݸ…ÄÌŸK¯êÀF©r¬ÿuì¾¶²a½|æ{Cëñ¹Q8Õ#Zdèé0Ó.œ J#Úp¶öªI•“Ïi:$ArØ\¡»ÅåÉÆÿŢDÕ§‹è¦W 6²“9´×ž¸&t“�ªHH?ÅÍìcC°¸dMÜà¾2)C Ý4XõP“ˆ��å®/‰cƒŸöPMž²r— P‡ãgŽÓ»&æLù®7Œ_½¼œó‚Má;±h)‰Ès·…Xf˜à:û­ðÁè£>º�]6;‰ußn�ŠIôc‹%‰9C¶Dˆã`…†…öÓjÃ%p—ÁýÎd 5K¶ÝËðéï“sÚk¼Þ´x€…E À¼cP}Ç—Ž[ù`̤d»œ²MCå¿å¸P­¿\MDµªôÛnЪ•�Õ;iÒp1µ5Ãv—|ÏCéÎ,M“<.%Fùcô؉Â÷6Z)aÊ4ìSB#¯("ÖVKmΪaÑî}ÌÅ£QpßiŠðÝþ�ŠnȧªŠÀÚ#€cédJ¾el„‰ÙäSÅ"Ð&­³,©ÚÖÂ'0A§®sF– À÷h<, &š0"VK=éy´ì9Àîüy™~£qdëÅBRov—LþÛ»ü~ Y-½â!„ƒÊ‹!îñ#’}æ koü›fJêÁÎzçB 3ívèç³0ëž<øíÿHÞzeàà�/ôY:~úm ÎrjD¼@÷h}£-� ™½D"b„®0W£½)÷ Ú̘^¿&ˆ·´ƒ±ë¯\)ÿHoY cʳŒïʳkœ-×ôPa£, •ö‘ƒ¥�è�CÞàc›‰#³HTùau;OŠ.€é‚‡X–?E»žh�a ö´ÄÐÙzªôyøöè?vÊM+"†ÌÁ¸�sôhEÚÛ­ä\]ø�=3œÈ Ùƒè)Çkr‡È“Jc€t5Üîý‡v½þBÅœv¢œž*žKëe¼öFÁZ’f «ØµKáÏ´a¸@ÝïDÌ›áE˜ôYXk(B9óÇÉ!ÝùØ&ÎÒñN„wËBékD»|#Ðpžiqc-ÞzÎ ?TQ;>›õ¼5 wÿÞM©lù�y2côÛªcÀ4+¢­‡?[7{+lŒ‹„´ç&XýÁ‚Ö7ñaº¹>É®T�Ìø:ß¼…rïM‚à –mæè<™¡œ³1å¤mã lpja~îyKn¼’„5ßÏÁηXðǘ8¬Éý×-qì÷Â}L+ ûÃÒé´@úâg *Ì9³ê½™¢6¼9ÕOÿ”Éâçm‚`©�Í'qo�&�qâ0òæÎ‡hánòn ?¶ÕÇÒ:ç xÖ¼¥; ÷p»h2¥ü6€Rè.ø6%Ç´ ÈWŽ Éçv'‰ÍË8«nÛá†DEHz‡“0os~�{Žhïíb/#Ѳ;éØÚô´�„­ld“æ%ðb=Ê¿B\/ú27y3hµõx–á�&m ïÇ|ä÷ðßù)'ï ³©}BV|ІVSOÔª¸BV«|K>ðÐTÇÍ4qq¶V#ÞÌ–1wËÕE£muôÂ× ò©�¡ÝÝx óûô¿9dzÎR ç„r|)䨀2šÂP^1˜Lžiq¸¿íÙ×øe?Ý;roÚ¤�ú‘JÔ�žb6ù‘A§5éÃWŠ ìp…ènÁ Ò²p“Û––½,`Šþ¬é")xi}½_·ý¡¹ Ðe|=7¾ŒMå]¸Ïÿ6® k!×’öÒdUžÖôkü™IǾ†ÁÛã1äí£)Ú7´“™!% Í•å¿â,�74=g1Ô,`÷\“!ž-ÈUÛL„S«ÙÌ™‚`¥¡¹aœ7sd l@ŒÈœPÇ5ù°.dŠl³9õ¯ónÐÄ[,R�ÂE5b¸¬¯�¨�ùE»<‰Êž!ΕK%8÷œ+ù¦ï¼wL®žÚŒé²°ñB ‘ÎÅÄ@5øð×ô 6¡ë½Ú<Ÿì› ç/´3Ô ±Cý í�y•H¾I…ëší^H\m¥›÷¼'‡Ÿ$¨3嘇\Ãt9–H—ˆAM;5«,1ÁíÞìŽ×ÇèÇÑyhͼ'¾kŒ`›-Ì,n„”©¼U7E~Ÿ'çý w" /îî9èËÜ™Àû¹l…ð*Œ2ë¡õ‚»ˆïÉÝœè6^¬^ˆr^TÃúœô“fß ™agJ8týHm–Aˆd>YtÝB¦ÏùOFYEBcæáÅÖ¸ëKCÃ÷ÃÞ^–º¯.dm“ŠQ…ñ„÷ó Ø.U6L†%?ÃÍ Ùø“…\Åù¸§w%0;±¹ÓTkY!ù!2B§›4ñ‘Þ|ò`‘:ðD ‘ÏîÎÍrr(3NVt/ß\Kè�4‡ë¤ðKŠ4êý�Ϊ‡ÔÝf¡ùíýh»ÁÌn-ÚYöã±g;¨tF'Ü{�‚!Vưxíø?Æž¥£-Ô×H”È&4\W*3ƒÌ�ÛR¯°ùhž«†Í–µ¤Uv\lî¡·7s·^>X޵—Ã`ç]'ÎtÜ.Óñ*\èñŽÜ®„9sÎÑ-ÿþa}„ìÍÿÇ,M7z¶t¥Ú¢¸Aë íp¼GÊsš¨îÏ% ãó‰¸_µ@û»Hß÷X°³Ÿ¥�ÀVUxÓd qfWPßµƒ)öé7™®s#9ù�Ô½“Á®�ñ”[.•^S:†ó¸î1±!fÌýó/ˆ¶ÌZot›f²+ðÀFŠï_ÿ`Ç„·¿Óut/Gå´ѤÁ(úÉ}gÎE6õiÞ›¹CþÿæH&˜<æ×¦4JðÒ�`F¡=•së†JeŸ€s–¬×€ i¦²ûöF±KÍNAŠ� Š8eÒfëx¼ám�k£4èÿß<,­YÓ¿œÝQÆä` \7쥩ÿüä¡›¾ âm ¤~1àÛº§¾  ùa`J~*�UÜ1¼ÿn{¦Á�¸>Ú #VNdsj µêî§ó ™Ý¤%hÑL«óÁ÷úL<6%L�Hœ¾@ÉØ˜ öû]ýy^Û £o’Øi/˜é¨ØzfªÜÇ�‡¨íäL¸Íµ²ÍäØQ!Ø©ƒÓ•ÿ‘„ð»f+hüöµû�÷‹€oXî)D—»[` <ÍæÇÒŠ2MÐ$õ”ÙhŽ]ñ_ít›Ù&Üӡ¨ÿ¢=<®i¾³ðð† =Þµ“¤o>� ?.†ëKãïU]h¥ÚKɦ´§4ûÖ&’æÕHÆ$uÈ¥ÁXÛ~}D¾Ñêý­$Xº™ø êaì×g4ak ©üû‡È}³ÆC1%äÍalþ¾¦ÍãñGœ¸ �Õé`Ç}’*_ýivðd.êK9aA·q ·Ç½¾×ÉP>ÌðøI.~ c«Ï§Ñº+ Ït1ꜰAþ;ñ¬ß¬g ù! ÆŸ¾ÁëG¾�yEAc§#Š)7Ñ—7›hqÌ3j\“J]çâçõ·àð%¬^u$>< Óü)tÁ“LrXŸmö·QᲿ\Ÿú9ÌF…†PÂo@~æšbê)aœ“4[3^ëfB°Í,ÐY°úÞOÓƒuÅÔ…`¯¡4£�Èðaože.”DÁCWÚá×AØñ,ü!þ•Ö.Å(…P6«¤‹’ß°Õͧ™é_?˜ÿÄçÀ°ãQxF°lW2{þb.8·;R®¥èÖÇ”Y\Ù&LðlK#éQ µ·Cþ (û›B}ûÌ´d�™¾\ó[#Öv�×»Þ²'ÿ2å…¤6ED�ñÁ‚Æn8:r~ß! öfþU28G~Š)�fB¬„™j¯“p~�:r ,BŽî6€ÆûxkyqáFø�ÏÇÈ\4¦ž¼w‰Ýà ¢V”ÑŸ÷@­|.Ùn¢Ç�±dÒ–9^âÈÈ»> ¾âqf‰²¯…`´u+á=«ŽuÑë@9µ�zG¥ö%Òüº%°W­ +&â­ù¡Ç2ø2 �ÃÈír󧦱°þq*‰%£¤aDÅŽUÑp§ùDá�#ûkÔ×Z•³Ïì'Øõs kv7ÄÝô¤kv͇w =ˆóo3xJu¡×sšÉ(2ÆMûúIŸÖ5Ú!2— nB«”£¤‚a¯Ú‘9Í å’j�@’·ù :«ÉŒ´k€Ë‘æOì¸ñæ}WXØü“ Û¾í•Ä[O\Ÿ Æ+•P¾ÿ-IýöžLöÉ£Ûü(bõü8±PP!³†ûQNÀ�ñ¬f�¿úÀ¦IGT±=Ž"�Xu£› ”VÀFf/t¤‹£[y<ë‰GW—gdFmU»«Ž £äÔ–�XMéƒ{øR„ ´‹‹hßûø®…‹–ùnÀ|št—•ºÔ[ú °#*-ÓÏ™Îv„­•XµÁœ— G~?½~îiÚm†5z(}Ož\nQÄ~ó»(*ÓÌIÙÖM3õ±z?7äLQ<a B­ïÀ£á,y‘E}?¶ÑßC1ÄoÕ!¼>~Ukµ ™ýçôþQÌëÜ2դȬª€¶ÒG˜2.�¥ÏYù9ðrýg2Ñl‰n'³@³E.ÞUÁ?ûøZ?mçÂ~�x³õ� ŒÉu“ß;-IS‚Œ}Ÿ_�k!Y"tVÙÐýÙ+ \ ŽÔ&×@ —,sed„4Óµ7‚�ÑÐÑ8Jq§LQ¿ÏÖ ^ƒ%eï)ïr<Ó¨7ÏnƒÃ¿¶‚v� {sAvG/]ãbƒøG+yN@ôPy"aÅpV`ÃÞp<«§Â¢‰áj=xø‰ÅâkmÅm¬šÕr/}¢l¶…;e]FœpYÖ2ðN Ç{zLöšYAŠÁZL9C½ƒ>³ #÷·}0ò¼™±ïh§Î¯l€³Ò ?efÑOUõ0O´”(½v‡ÿNo%gÆ#pOˈ‘ûv'Ԋ׀–À zq* Ëçò‘¿kmabÏ lÉÖÇ*µÿ1\&ìXuQ6ÏC$S*R …Ê{ö"THDBT¢ )¥Q‘y(d–2E¨L%г—¥B†¤|JE*¢¹ôùûºÎÞg=ϺoHV–2rì)íÍá09eÂÌ@(ý#eçÞbHOÙð¸ n…¹sP¿²¶ý9 }õ×pËmn¸·Û ‹Çî¡ÿ³ëdÂñ i3}YÖº˜c˜@ÝÎ=ÂÜ5vêÎRœâG‰¯¬Å„zzÉã¦+-}±`ú¹wyÀg[Z¬emÅïHçäB¨«´ î-pZÔçÄÛÄaËEêÜE+/Ÿ7†�õÕð|°â¬8r�hŽÍ€mbü˜.\EòÅÂ�B8Έã6í\tïàtGü`„…ËQ!|:¼#²íÞôíÇ»8±ò3¾?&d„'=Ávœí¹r¸Þ:_ k>€‡R·˜ÙSð—Dàöèt¸ýèÍl§šêXFžR?�Ýèí.€®�� çûóšûrA–[ëÖ/ŸÖ‚sôøX:‰õ~EÃ5xÐdÜ”G2ÑE€�w’•Øöw=´êY ݼo–mÆ]üþè�þ“ÉÓaJK¾Sͽ”'Åó·áÀ×ÝÌÃ3&ø×H†F}ÝŽ£Û¹êÞùZâÙÒ0¤Í!ìÅu~Ö÷©KÕ¹$âÎÔCPûY->¡ÃÅ¿m Vå‘�òñ¸¼/’¹þ9Åž‘Ãã°£R‘¸G~d2VÚ‚ÎûP¼vœ1.âFñ�‹H‘“¼¸Éc45o?6[]%t;×ù޳ï6 'ô®ÿÆŽŠéÀ‡S¸†Ü'éO¨á15¨ÌºÇ…!–oúÿÊT�IGt_Åc.q·ˆ½gÖÎð‡�?‰`E)9mD×¼—Fæô PŠf.�æâV7m8j^ÃQBì6A#ffÊ7–(›bÑ…›L`ùg,1ZÍÎö^=ýÎrpaµ¾ è)ª„ËêDHôB=ì–¤íz÷‘;ó|¶Øªk£¼_.“ Ò ^�Îqr]?ìç¶Ô"<´` iæû’þ#Ö'q oœŽσ¡� Ø·Br–©B²C$ìÛÍWwŸÏƒŒ™á=]¨4xB¯íé‚Å'Ï‘º§\xÕVÓËIYëqª~Á¿d•ÀÑú)"ÝB-©˜±È‰¼¸¸ –Ï 9\cñ‹>Ÿ71k3zÓïØõ,Rµ×¤°>�ôŸÀ€ïcÔ‡*�»„ž–Å0U£ jã+p|÷ u»õgh;¢Üë L† Ç.A-¢‚ëéèÍLÄùzÚ9RÇñ� FŸ]»©BA4vÖ†ãÞõõàðÝZ‰èÁ8¢hô¡<K-Âj}ÌÁ­ã‚Ä"òÑܙʖ ×ÐïY¯pQžIÿÝN„Ã{0¸Éƒ•¯Ðâõú,sߟhvJAU›>éåŒ<„· gjŸ­ùR«½úíxçSwm³&~x6ESÿeÀ§BGNó½FrBoür¾„NFÿáŽU!�¹ÀGyhšWM.&x}$ NÚá‰ÏK™\ýzt *bV¾’ïæa»\ZšL�ûn»Izš%8eŠ×½Î¯ÀßÍ*È›#LtOŸA]Ê¢·sþ½!�½�¶ÔùÓwæg‘„nb8¯30)Ì><É¢O¾«à³§½4̦…½P|“.˜¼€[] AúlgNö'ZœKw'Gbâ«„gÂ� X©N+žºP³ˆÿà´† <‚ÂâelúAÈŸq›éQë`³•/âÌ…\äIž8¸Nð‘„`g,õ´‚ä–(|´ï~8Ëh_˜*|Î\ƒáæê¸8â7]áŸV۷‰aŸÝ?² ì t•¬'.Ÿ±þðÝz–1Ú‘ º¿^³¶‡mp‡s2Ô7ŽØŒUù øz}ê4>¨ùÅ7ŠS£×pêâ:”9·ΑD´Y;Ÿî ÀñS=$Ú‚].W¨ÿÔõ�;úyqüèsŽŠn® = žç%Àät*z¼¶™—ºú8aõ¾~4—xB~O®É]ez·Øâ÷¨ì§-Àsù#{Cü8T.΄Ź€ ^CÖ«h:£"Ι�K&TĈ͉-puÃyðp,‡üý)8/{&ÈÜ/„o%¡à“?L·&§NT­Ë‹¿ˆ*�+‰¯˜Fx¾#c…DÇÏ…êÞPbw/ÌB~ûTø'¸ƒ;¬‹»VmGï^¬^т޷q‰b½Z’L;Ê÷aNX=]1W„³vM U1Û€ÎZ1uzßt.<ÎÄ*áJ8 Œ²õoYÞj^ÆÚe-ù¯kV|ª#«+ÄÐb½/,¼ÌH�›M}5ÉÜ=—HTZ fkÞe,]¢Pk…h«òÂðoÒb[‹·'ÒÐÝç^jûM¤EiJæ/¢½læò*@ÿÛ4ÈÜ<*~°FñtBˆíú � �‚· Càø“rs♋ZÕ$Ô0›zo–ÄTãcÀc¡„¾©©`qwè¯H¡Ùj`·D)tª„ Þ€îD‡>8füŒÎ\zŒˆHÔPS4]»Œ™àpc�@ è¼ BáÒë˜ù‡q³x“QÔ(î$íQ;© >€-/cøÞ‡,_/9t(�„]‰b3Ro ÞHüóY‹Mq��M{¦=Å3‘8f«àï�˜3"½6oÑS<Óï‹'¹¬kÎ#ºKÖ£,ÿcF•á@S¬-W5«íô`Ãäq1_íöQ^h>޹?=á·’î ð!ËÞÁÈ–*"Œ™æXÝ×ÏAý»žKÆ IiZi´NònÀõ0æp¶�|K?s߯oú_Ù¸®ALhmd›·ã‹‘j,ÖŸ"ë½¶2{6Iß.>›€æ;d`Q^,�µ€Y[—‰na AVÖùÇe‘±û¯Xž‹w؇æ’À£ká�A#}Æ•íùºÄ„`òí‹•÷ŠN¡ìÔ6ˆï~Hí'Æ€Ûʘh…|­-׿G*`Hçø“;'Sq–ð^Š\M>Ê£°züB<ù$zžY`ï øïÇrý’q9­øí¸´ÑýU©8™Ä�}]28Ã�õŸŠÀ�ªR÷~î(mÊÄ3|–ØW²dW»ÖÌ*ñ†×Éñx­MO<ïG¾ ²�öB’u^in##SÍô£’ ʼJ¥ù{¹ê4L¼ ŸQñzU²ÿw x}"êÙôºtH/˜¡qÛ º_G©7–Š®ÃÞ�83P/¼ êw&ˆIîK:•õŽø €øásdËP71ðÞ„zQzä&ˆÓtSAÖEg1Dø2Ékiõ—xm=HnXÏ¥ëû‚!{›ß4ëæ‘ù¡k0$®�xÙ…“·®>tƒÿ}’+QIÇc’1Å/ŃMñg7+¶u:o'›HæÒqÂyMibŽ ü×E÷Ρç•<ñÙqYèÔ¼FZô…�6~4ÃÛE!=ò2Î_ò•-Úî�ï�•p»Óz\§•AÄòÞ£°¥ÊݸÎ.+»@åË›ðú�Vzjq †ÿ‘…ó«+ȶýB`Å•I;Ê@�Ë€ KW…Ÿ$+nô}Þ[ÿj‚rp8Uˆ¡;- ]\Ãæ¸H{ÁFñl6ÆÇŸ£ˆÑ¿™PxÊœ oï§ ŽðYœ}ÑŸ‰†à%^,¬ýÊÎýê!k}Á*R€¾ŸÓA{\ßaæ]fqÒÄaqìÛSV©ÐI!ØpêT½ß ·„ÂL»…µ:MSt]ÕK¢}2“ÌŽˆƒ×[cIç,9|»)ƒ¤šD€KÏòZ>£$º+œùâ—»V0ôK æ&€nHÚmõÅ¿gU¨þ»0“,„õKóÉŸsXs{1užÁ„òã¤>¦w‡ëµ#³Pâž $ö8°–0çùXóãÜRˆÔ�pÉ0WmÕp“Ò9êÀQƒåa¡Ç»QÏî9 P�?ø2Ϙþ^¬ #ém϶]`-çr‡ö+ËÓ“æø+Œ’··.Bï© ýö2- )§csŒúW§’8?8¦Êá ~IòGá_{T¯æ`'÷;HâÅ ¹šA�5´0¦‹5øiCâ^G ìâb’´K� d÷²×ç ç�Æ#ÿäiU¾ ¥:�Àeuš1X~˺÷Â�Y(‰.ÄÉàL^x/�\ÅÓî1D¯L™Úš­„89/èJ‚® GTÌ£óÔ¦;] ‡òøêΪ¡%?iÝ�õ°!:¾•q³§”Ï�mŒÑ�X-uŒ>8¡†�Bÿ¨ÂS9˜”ÉÁ }¼àº>¯)§m6ìÆŸgé;¿£pô%(oâÅØ³ Æg74õ| ŽwŸ kä:ôéµÃ—<Ê(Æ[gvë)\,BïõðÜ®‹l³ÞLØ[Ü�gWÐ�íKiü×>âû|Í·J‚íf¸qïo&\š¿yü ’ýËA`ì�N�´þ”»�'Uš…‘¬CWH]Ú]0^ÙNF2ñÃ=/zíÜQê–í ›Ì²AHk6Ù°Î΋=¥ô¿;drT‡Ë&é¬H?òEI SC.ƒ ·òÎÓ%Ftáâ×~2‡'–8ŸÂîelˇWóÖƒ�¤ô½¿[Ä÷·ÊH;â‡íò”»æ6¾ÈϤžŽ—Qò(X݃ѹµ8Q%‰= tè–'Ä:/m1;xâ¸rvî¥õÍ!]¬ïg%âÖtèozèûH€î§f*ü[8“5·#‚ëtÈÀûÿè’Ï^àu^’¨yˆP�OD:³Œ£8C•´îºd^8^‰Õ‚Ü‘�ĸÛ�ÛgÅs^êþVë‡>°ÙÁò°I¾^„�x 2¾hSÀtÛûàçü�¼{¦.›oÃ÷÷ QÎú?júa#znZJ½¹§wdÅ º2e?xe�ov ™£k`O3ÃßáÆç÷ ÓKæ1nV¾$jÚa4..E]·*jß=Ê·<Œ7ºžQs/!0vÛÍëâá‘ò´ß8…Ãäû$lè&qœF#ÁIbi˜Ì¹4ä‚&QéTD+•ätgºî ù`¬Øùž.-ùK¾í§6Òs0Oí ³î Î v`áˆæ—Ó(Ÿ_-]$‰ 3 ðôCa,›è¤ùfÔ?IB/×hõeÚŸ^h ÝyÍ7¯Hý¢‹–\ăj6�œ\ke’±.—œ2çÅÔ4O²¯Û�·Ì§|²ûè™%vhÓ‘KõÕ¤èGµ]¸fð4Ö»FÖz+cTTûª¹It°¤|îÄ] 9äe—#ñä–ÛÒ'�јD;ÕôP?4’¿ÈË®ïñ '(±Ýˆ«çì€ï­å$(è99[ºܽ¸À¼µ–8y æQit¿z’:ÙDAÚù&bf-^7 è—»Z´10®Î†o¢¯ÉŠ·¿©} ”U†”saå"¬÷¼ ÆJç úi–\º�†ÒÐŒ³L@“c³&Šz.uÇã‡üpsÄ6¢´_wk%ü\Kˆ¥Vã>/•t|¡“UY(6 N®*iàòègÔýÀW¬ÖAƒ�*T9X‹U¬ž­>8£ø6•]+V'Î+R;Þ±¢‹® CÍ-Ü.¿Füåèç8 ¾b¡> »(ÓÇŠð¸0%ž>Ì¥ÞSôæG:¤Ú@oܽ ñ)“ÔBÿ"éù鈿 ­µ×Å{í¬·rÍ Î‹IQÉ'2Ê '…�3àUÃ7r÷j4ú)G€ºM($åÄBpo*©îùG¥l¡ÆBè‰5ÂÔܱžüÈæT%Í¢Y>ïéšÍçÈ®_›1‡©:ŸHׄnÊ‹k’v’¡Å¸ö˜HfçÛžÛ "ïá¦�v“ì{Ý�ôQÆeì2�Àľ­ô™×.ø“ý˜ð¿5$š2Vd_Äf¶´:úÜIj°bãBøé—ŽqhåÔ{Æ,ËkgEã‰R 8Õ/†‘òÑÄ;,›Ýnü G)¬Ô £k–ÿ ùOA˜¾/yË!Ï:©õí>ü¯mÊÐPí »~.%—x�ÐÕ“eôÂÊ=h}ò5i¿ê@wš€Ôm^*®ÛÇ4òÅ“�;� ÏH 4oÒÀ=aQ��ó C¡^ù5'£Åˆüê_Ì|¯U# ³ï£ñ“Õø5î;gG¼%Ú6z³ð»SƦüôpäé[Žïœwð«&µ�BaíÌw¬Þ¿“Ðݯ…&Ùðo\ •ѯ·ËÑ8߸îAúNU}‚NÞ+ä°LA4nMµG�º£DoÓIÐPÿŒÜõ_qéIö{¢ ÆÊkᧉ8¢²µ OD†Si©[ì²Lø½|òz¥qiØ*–r–3¿ó èUV�Kö»éŸM�<‡io¥˜Ç&I¢ËQ8x¦ƒ©UÅÈ#òÀsÁ 3Ÿ’dý¡Úñö¸ºë+Ù*ù†Ö�°åÅݸŒwN,vÃ⥧ ãû{ôÝkBqr²…¶||'2ê˜üÃ)˜`¿�Ù¦hNo(hÁâ’ãT,-|ŽF°®­�Hžœ-äHDQÕtuXoBÏs(Þ ýÉJ>þAB¢ÙÊFkÔ×Ñ‚¡î3TÍþ Y⺑:æïc&VëÂ¥žß¬ãyÞÚ;ã\£P@¶«É‘YƒŠ@Þ?"óçý %Û%!äãF�4 ‚¿mÆœêi÷^’—„1ï‘ .¶£\)zX9æA/擨F&Õn”ʦÀ’³µ¿×¾%JŒ¡þ¢ný‚»ÔBˆy©ß}Ob–r!ÙqˆØñ{£÷)NˬböÍÐtUWÀŽn98–t.W¬£×B¼©¤|8o�­Cj03ÌhÊ%2ï±Öùáý�e™4-q:àü+Þ¤Mçx1�úFͪæÑ¡LW| [§æ6ÕØ·#_°`ë«Â_„È»»¦xt‰$$?¼ËìJl!6Q*uõ� l‚ŠjÌÑxs�]< ®�¿dެ㯻"=˨_QŒ·„�i¥ü2Ѹ8 GN0u�A%ãKͺ‡<˜ ½KgD�§êCtÄõªJtcæÃn²wÎfÒ0Ìcd¶aÄ<ù@ï|­g tu0Ó4ˆ±ê�ÆÄ•tÕªdÜa’®M3èaqc$:øsÀ íÀð�£„±õaýò~� ‘éxH³” =5\<’Á9úKÜéafnkbNGï[ËF/Æn1öl>�›Ò6Ž9Î÷œæòqTK“³ôçÁÏe}¨;Eý^Ü J¿<áç#®–åÃñåÈþ�Ä·C¥ÄÔ`)^­�b§ñø ¸Âw‰º…º¢ºŸZM¹`]‹ÿ‰› Í?%xãYzš dÛ–|4{q;Ç5pà×_Ü’xžUþð Oýe6ÕÐ禟j§ bÜ¥Wäâï!¶/ªf®‘÷›°Þ/–(„¤Ð Œ%Zä=†›qKˆÆÜB2Â/Ê|9ã@ùÎéÀ�k? p•,�{SÃm×B†âvpÝz‘][Å<»Lz^û€|•>´L;¼mØ'*ár˜ýªW�Ò:Ú¬ÈB€H�çtþ�xšSD÷»‰AšÛ?ö÷ä|:3Œ´]b%æ ÁZÿ?T­`ó�VòŽ[‡¨¬wBWÓ^Z4_÷뺒É΋ØV}DÚL ûj(9»l5ÍÕ~D2Sø˜=EŒnüGöª¨S§I WR�·[ÎÀþÙ˜wã¼x*Ó�|ÎÚÇÚC=.6·¬‡î$Ñhc²•JLY¢Ì' Œê¹Vøæ'YÇwžìž3 ~_L{°—iy“Ï´÷IÔ�°�Ãþ½â(nm�ŽUÌÍ�ߨê%×Éà5!,ë“«ó,L¤Gr~Á£N^¼]’Ÿ9`xŽ}w”S“ÏÖ°ôåuÖ/ÈsÀ™i,q2›Óó}cÇ5Nô¦a8­ëQ¢«á–� ¸žFoR€kÚÆ¨\UòÞøJ\þÆ1É«BÉóºU `{xgœÁ SÑ$<,�kd¯oK§éÜ6@èÓ]‰Âà(·埆€úîì<xÅlk¿G=ÞûÑÀÖ8Øå|3›u0ú©!&×eB¦ÂxT?LÊÄ¡®ÇŸpUâ:›ÕÊ”"\ÃwÉÔëX|¶¦ "µŒ²£ÄPu,›tm¹Kî;’(×{¨ÓÇÙ/ªH>ˆÇÄk<Øà>½GUÖ#Ïì4,.úÎ 6C™pÚ8£ôU‚öß$È®�!hÖ—C®ƒö4{‹áoïeÈ%ÆE=g¤’ƒ‡“ñíÑ=”“¨�ãÅû˜6Êp#7 Žn¸ƒ¯âÃh ë=,m\H .Ëý>Ø,ZK®lyƒ%OÎA°À(ë8e ëÿ£–ÆÔÿ­9{ÀošùÛšàñéöõM6\û']ý* Ž—Ï‡Ú$;T7¥Ë¡dH;ô´Ã-‰ñÚ�ÈfjªîŽÒ’ ˆ¿È,°×; %ä™� ÛáI‰(ê4 3"_>€ÜàWr æá¶`!Wÿ,:_ý¯öÓ!G*oÖN6×e�ŸöZ°ÄíÆú‘JEV�æ«0ñÓÑa;œñnð '|Ѳù³,=ÃÞ$bA¥tíy3X“Ô¿8‰î`‰6níˆëj\ÜH—Þ3ŠÙC›ñöïåh(™‚“·-žh˜³ý~*À…ŽÉt¯•>¿²¶ûè’¹§tÂç»»¢�´­²ÄyØNsÉLIL^ßXˆŠ†w ¿ì4ãË¢QÌrÔZÙEezyáøõx¡æµ�™$çØRÌ»Š[Ô´¨óÒµt©‡ ¬Ã‘VìP5Âú€úê�%-—¦—Ǥ@OÛǖΆßËœˆý�p:'ã)M{£d´i¯ ¹8 Í�}ô B Såó…ú�ÌFÅa7¦d?é_ÑCÅ6·¢bf6udñK°žFcÛ–hvÄ.Œ($9ÀkÃ¥¸ù@0MàrÀ ÉùØÕPE,o¤S>«`ø”ÜH?¹ëá6¡\¦b=<¾Í?×�(¹ôQ7N"òƒôô‹!è6A²j¸„Zœ}LG+ôp™«;äýÞ€]-÷èÍáXû:o¿ô¥÷l–ÑÆ¹' óW©CT´IÛº•ÎWòÕƒÔ\gæMÞeüZ¼Þ(Gßó— L;�ÜúñÜý|²CÑ€ü:! Y[äÐÍñ­ªãîÕÆôHa%9jÒʬŸ;Õ¾²öCÁD¹•÷œŸ‘­;I€µ}ÂÕGøWÑÁü0Ç¥d´¨ü tªŽ!6:ánÐ*xV5‹pöÞCžƒ1è[ÊÑÞÕxêFœ:Ň›÷ÙaȃÛT\P‹3Tº�D1d�ƒ (ÄÄÒ³}K %è¤ äTïbzܹf­ÏÄÚÔ±æØ5Ó¹½À® ¢/fWn»AñM¨%ꥮbnóg xÍÌ È$×;º·‰mêÿ‘÷4@P¡ŒÚ\®ƒÕa•(±Sňsxò6TƒùŽg$ñÅj2η y•¥q K’<”µ†m®¸GSêÞÐmwÝÐ䌔u¨’ ò$UEš„$Ò¯Á úcžó°Söùì¬K£<þrì†CèWîH¸Óä ¿ž á1ÙÓ ¥|ˆÌ3Xïz—osd÷—-`�'I’¦®\*pö"¾Ý7 A·îÁ¾!#¢°[•ßP{õ)Ú°•d½!8Õ,;q n×Á!‡�DtÉSf›öòW$bÏ?ÁåéiP³ÖŽŒ{´±öç@>ÌŒx~Ð^ËÐ?GÒÈ®ýýP5Ó¨}B /þ�OÂv… éÑ*š|R�JZ×Ïí€^ÍÍæ”@, `\†cɥŲp욀âIIï$;Ìf£Ìþ9øæˆ2>ú!€S�J`øœ<{½7ÿ¬9½0¼Ögf ¹}›Üïx=ÿ…Ò»êqNZ*$}yŠÏ[.áç'ÒÀ\M fÒ5¬ùáïÐU¿øcÑaÓ~�è{L;6!]Ê;ESóSñN(à}µCÈÐCL´Á~ð¹b -‡Ý¼P½'ù“8ÄbÅr:ó×mæŸs3ÑìR£ë§g@ÓICòNx½ÉÏ9ñ9µ=ÅšÝöÀ›I=<šðäü6f�ãΖ”äõÑFjv±˜•…ÑYUpdÁ#r|N–ˆ]¯}z3�$ÏVFÉWæÄAÅ—,Y¦B㪣a«äL6Jïfá•7Rß,J„ËmAÀÉ“#Æ%˜0ù ²öpPìþ¹ß…¾=ð³Q ›Fý°�ïV‡pCXø:PR´ÀwÝ‹À05 ˜·sèÌÇQÃÀš¾†Âãxúñ§”/ kî··_�ËãvõÃxýR?™½Lk¸bIdƒ$åíS‡ŒP.i%ú°payzáhX¹ ßï`š6ã.êäÁˆž h÷Ç ®§I°«ì/b¬Ðw¦½h�zl¬åhÇ·1;É„{ÞLZM=‰rƒò.?Ï‹$Ô>Tϧ>‹ÖÁ“·—˜8×q,^ü+£wô¤¨'”~½ôšXðåRxwÖoŒ#¶q¸Fx‡hE½4~öÏ"ï”IãCdߌ,‚�î1¢”¶¬î(°¥µÉ4ÿשŸÇO÷T>¡{_H�V™lýÍÌÚ¯½Ø@ º8W4ªH…¶>ªÝûHöéî™üBºˆ¿�xÆŸ±b²^°Üû$ñ¤~”ÿp…^¾Îåa{ª±\2Ü—Öa6éãr\7XFïó¥àŒÏüuÊÝJxôN3;§9ˆÉ|v•ê¼ê$KúºkÍZ?cˆŸ5D©FÁ'çq¦úáS*žÿ‚1þ7IWeõ¡éŽ983«�‘³ß2ë¾1œ±8Kâ�7/áãp(Ú‰-.LÚU‰<‹� n>ˆ;V,Ã?‡Ü EÙ�<˜î¦�-YT;Æ‘õU‰ 2î ˜�‹6¡ú–«à[]Ãüm5eKfj€ðÛÙØr[oÿ�Mœ�W{ÆØŠšcûmsX|v Ýk²NïºÆ†ˆí‚w+iÂÆ}ä­Ø.Ôu•Gÿ]ùøU¾(›�GÇuáï‚ùàóç±¼•YS™®†iôq4ë%©#gÉí–~ú-ŠÇbLè÷°ùÐ"“Žý/ﳆ'áP�õ«�ž³Å¸M}ñº |ˆcíÄÌV ú˜Aº­p~[|3Ù „ἩÅtÿnË.Qغ�p±íDW%œtÕŒSÁÝaxC¹‘x§ �/{ï`ƒù{Ø¿É�XÝè£jÕ‘lç­e Æs?þk¦Z¿Ê𔟿Ǭî1¢ö[³ñFý ÑÌð¢ån‘¨qaV˜‹·&ðpÐÍvÛ€½/kF<�?�Wˈ]-ËŸµsG7ƒV¯96…GÁàp$=1ÝÁö«Õ©¤gߟbÛ«.‘Š­ éåêÖ»´–ÕRXŽaÙE$æ]5ÁÛ° ù)ÑÇ�ÙrHkalH j(÷3aXµný´» º®/&û7]! „ðD�;Ì�%HÿÌ܇/"ý¦M_JŸgm9¿˜ûn¯ˆ=ϺŠà‡µs™°—ŒÕ­ÐrçŽU<0žš’s�r'ËÂJT²ZÒO¼a…K>ÓÜŽo„ààæ’"=DlÑÄ·ŸÎÒò›;™íõ¿Ñ§u9´}î`Ív…✪fréŠäh ÐÂ%´ôº–ÎbßW�͉¬Ú@-ŠÕg3}ã³RE|~y€, 9I«u“7j¯]¸Aü]–Ãó 9´vc& Ò“Ú±DeþbXÐX…b.Ñìò`w´ylKohv°û@x„ Ñ›cŒöÝÙ‹ÆbäýÒåðW1²6(Br@„íB 7P«`Y°>ð„¾ŒÔ§*ÇíÑ…OÅF·"0{ÑùQ+iNô‡#ìÍ·4q¹”¡ïqg¸ñ̹ÖÖ~¿IS‹MÁ²J‘T~ëŬÏ[Qß¹’Nƪ`êý®þ�^÷zCf¼Ê'y:Ž0^ÅÔ%aÚ†7r§ˆKf9mòØ‰Ö JÈ•%»©ßêhb»xÍ&/èÆò„Ûí ´eß#_¸›éYqX½N.a]ÏRæÉ¿ûÈ,X û›ÃÑgƒç©U;hGËáži'L½5 F³Þ“»ü)•I?—Áséíd÷ A¢z$¿Ç þ‰Z°úUx\�rµTÃ}1¼ñ¶î9Ë2cw�‹^;#ñ•ÍŒÅ=ÅÇ¡>‡ž|™ÇäÁSì·�šƒI4go.h\É#aá]hì]D,;‘èò‡ðŸ,ž ²\2¸Bx=ÍŸÔÀ»Õ©5ññÿQÐ�ÃhAô 6`Ÿ)‡“MtÔ3…XgIÛ'v¨›*Н133mÀÁ•¾½›s®ƒ$ý0Z·7¶�ž†ýÉy”gcY-IBŸٲÀIê¦{Š3ÿ¿ìÚ¡„LF¿>ŒäÊŸb¥ `‚‹5¬Ð•Ç«ÊFì§ÿZðtÃUغP/ÙàÁRú÷¯7:_C6òÊ^ظÔ%ôãñdô~u �Õ_†yò&, ÷ke�£¦Ýr«U‘_•øä39±Á[×ó¢£ç¦>ó2îÉ1�âó±¸jÅ8ÓÅÑ‹œ¿ ;ÛåéƒcrTêíÛ�î¡(òKï9)1 %sáo€,]0g?^Øñ�žœ ‰óW£ovi›øÅxÉÏ"î‹ÒÈJ~sذOµnç{eÈÄa'°ôa טVµ÷ÊT°ò!]S*„›nßâX7€Yóz�½ÓOóJÀÉ¿\Dª“˨q_u�PÇ?C(ÿÁ•ø:= W�!¸áÙ)’Äο™žs0X¹;&ç¹½� ’šjllÆk;…8�Öö°×>^èo¤øà§h¥Ò>_ KšŒ`6å‚cY�hÐT¦nd}¢3ð¦|1öxIZXëÚ�{´ñé—�ä@€2-98Bx´ðéîE´fM Ù±*†^$m�šv*¯­‡  è;¹¶_Ú bwiI‚«�À ÍÉôÌqa#ë\4ØîT¶»â$lÞPOŸ(Qý7“dñ½Ý(š‚Oíg£_Ì ¢lé�–‰RØ-²“x"‚½§B!ª]†Øü…®×ËÈ̓d%w)~æ_'x-A|Þy|vg>5+ËÄf‡Ó`â-ŽF¢áÔ}›{íìtJ£ý^’@±ºJ×kdùæŒÉ"_fJ‚ìB{êÑ~»\Y ýûI‡Ó€™wȆ› áñˆ0x<u¿“¡ƒ<5)mƒ„Tj¶nŠT$åSÏöŸÄÚævgÁøcÎê/é¥~rÁ…Dh¶qBáézO Mþ@%I2줅YÂd]e=uézO¼¥äðfNsO°D;¶3U:X¬n‡U$ð¶ª)l¼Nƒýèy©|Hr²‡3©hÚ0˜¾K̈Sé0=‰?s #áI�Õ}lw�c暢¨íRLœ\±ä¾g,¦ºŸÝ›_I¬äF¼ùç4È/îexçÚÀÛóáPT�aôe üt]’ËÈÍ+áä±ó¬Œ51(¦Z=$é}$)Ü�/®¨�f•Cœ0î$Î%O~#MysãÅìøŠ6¬Ú.åƒÚ™Uä÷ ¹øˆ¾ºOø°¸xÿ9r⌠ݣKÙõ³aÓ½stÃõ$rNÓ³E+‰šQ|»BìÕ«¨—›+=c]Oö¯(‚Á¯3‰e’&ÎÛ9Á,±è}Ê:ÏÄÊî!xÐ*[ç¹x9*ñ\¦²]¡ŒÐó½Xü>™0ZÈþQ"fbŽåk·Ñ'®’%O §¿Q™OÛ™š`QÛô˜DO¿Q¬Œ Ì‘�¤ßÄhÿ�ªšñÐ’ÞƒÄâ�^-7&ÿîÕ0³jËñö¢@Ú ´Ž•U¾ÃÞÛ×M=s?ÐÈæ2Z³¢F¾/ºâÎ�èššV¯†‚Mò�gˆ¤F¸”¬+Þ …Š=ä×1ýÚœßÿèÙ_âä¹¹Ýõ�×¼è �&_龃÷ÈÍá¸òƒ¸v«BŒÒà†%´êöFöÝA†~|¦»{£ ¿çËÔl(�ó‚_=T mÛKspˆk)¾ÔÁ}«‹¨Y »:[’o6£›_Ê“°¾8hbM”ü44�Ö²g©~©Xq­ ÑVM ˜ÔBV˜}!�~Ì {·¼%‰-;ÑîÌ!ºõè>Æ7`Øeì§{éŸÓ;p÷} Hê~Í4 Χr!¨vR$6û#Áù’(âǯÚs˜:´är,Dç?•ƒh×\@—²|øéÖZ\›Mœ�ÆSFìÑþgKDîâ—©AâäªBxÜTàã‘öôóûœÀ»áäó¥RÚnâÄhŠÀ¦ŽH`ç¸÷¸[ÔdçCâCê‰õ¹z®Ç.>!ºY÷‰á•¯ä-º@cÊ,°LDåÍÚlÓsYˆÞSÇl�²Ášq ¬´ ÚL˱xÅ–ÚåÚñ(ú'ŸÌÕ×c›¿üeI¤mpÉ"¦^WÈ„A0Ü߇©Ø…xå„7Ì7:GRºG¨]ÿs²zÒŸ°Ú3ŒŒQ‘ZÔ¿{›~¹°Ÿ·záUÑ{é±%ŒwÒ| jpDÐ=¥gØRѨsâÃò}ýÄp®ñpvÆ*{]6Uü)¶Ê…ãËY®†ÀZúÑØ¹á ¢L¢Åk"µ Z6Ñ.ç0×3¬ö{uQ8« KÁ÷J ')7B­ôÑn¾¼±Ž R غ,‚“¸Ã«`„í~–®8® †JRMÕ28sÑÇ e¶UTt¥í¾ChìAùZxñØCø¹ˆ‰ðQRáõ‰œêÉÙÓú8»0Õ:Š™Kòüô%¤ËtѶÞ¯ü!ü'ùIAçl£';"èËvºKl ˆ~&LR!i–‰fRzÅ8š©d{ö|ºG@ïß Ç΃š�Z¥‡›íõHº�-ˆ‹‚÷D µ-&Q9 ©3·žTßz�ßßu„#0æš?±ùáC÷|Û�ÞÇÎa¬ï8;'…YyYÈ´ì¦!ó<Ñ?ôÞ©¬ |ŽòË‚á®2?¾ àƒlÿˆu€ÓqÂø~ÀŠMý¶†¶µ§O�H]Û ^¸VjKôî™c¦•TÞ@Cÿ)Ð%sn¡µx=˜ŠÆÁRëônUøa¬{¬F,FcáåÝP|xõ„}™7Ž5‘{&g!úI$퉪õÐÊEíÍ[@Ka ÑU8JÅm¯ãÐáé�N&ÎW¿ÔòÉáy—KœÕ‡K©ÅÐ}êyœ÷þY^çU­T�0Ý&½ {N€8½r@Vª„Zmµ£#óŸ�˜ðm^0¨]¾MG!fj3�óò&[W‘þiýòú ¾ì]@ŹpÁ²6¯¤^„�«4 §ÔÇ|§�ÖΘÖ{‘æ¿¥º5lìØXùŸ ðgšÃ�°rF%f/<ˆÐ&WÝ¢ãë–ÂÛfÐtD™Jý]õG�éãßáíÔ&ÒÜ>^ý¸Ä�=ßlÀÜ?�srºÇZÞ«�.=]hí‹„ÄÆ­`æ ó:ÁT™ ç Ô}ì¸FOÜOâ,ˆî¬•Ô�ÁÖÞXè½8Êôr¥Ò*î_´/þL¸µÐ°U\(ý:Šr½æ`É=À¥k–«âƒDº�öÓ|Mk²wYþ×¶˜ágfƒ§ÔdÍÆ,E|™ ·º{ 7íDý3 ä5A©�lòí–;ÖÝ� ’Jm¬GÌijžŠêâ¯qKõe*ð(îö2¥ ú1î¹TãKVÆ@cË81xìÃ,âq%ô¬š{­³Úeàß$ƒN�¼Ôaü•Ô5ÃÖÚXÿ!ž¶­å1Z†÷!ñÌuüÂJÁ/†·.¿"‡½µÇ‚&¸�Gq'ò‘.4/Ò††0 Ð~} ƒ´o¡vªþOqyøý}aÜjHöJe$IQŸs²Ê.ZTŠ’†¾ÑTÙ3{Ud‡²>÷�ŠŠ†í] ¥¡=~~À}�û:÷¹Ïó¼ÛB¶‘µ[8èŸÖ¡ªï^4ÁC�&¯©¢“YÆtÜî¨Ù?óX ص–jÇ�ÃueV¢��7c«`ËiA ÍGÎz¶}ã.ï߀â~’Táú¾Þ @[Û|úx)žy.7¢ç'¡øÖ1È,©æ·ÿ‹dúc� ¬w�°éUìTi$Ÿ½É„y´{à……Näç†ZuWà¹g,vº…¦¦¤\¿“¬¿J¢jE<ι܅t~£p>‚f·bÙ Fl{‚7u¿: •§¦Q¯ôSÌ�ÛL‡Žmƒˆ¾´&!{Z_=Ì=8´þ¸^.¸Mö×~�óøËÌÍD Of:ÂTgtòÁk§cYÞüû|¶V/e?åGð²N¯Y ‚óØÛÙÔH¦»˜ö¤ºb¿Á³íO!j»'Né Ç‚`sªÉ2 Ú„Nb¨ÚÔ�àfD u…½fÕ[Ïó"íõÚ¨L™FµôàÅNX>j}Ó”£²íù¸wÖ-pÛ´Ët„èÇO°]œŽ[Ç•ÀÆ· /¢9Üí°Lúµßî9Ѻ„i¸Qå)øK;ãŸk“@hš5ãVÄÃÎKEL齆`*BÞ–“ð�U ©µ( ç…ðÙ�T«§°Ì'ƒÜÝEÑì^x3\BVu¾4ÿ‘)æœ £Zã˜øË+$u:�dO£”A$i,`·Ôળ‡À­GÔ|Ÿx&¯Ð]D…ÿI›÷É‘µq%jNíQóƒë‰‰&«£ò›\*N¯Ãý�šÝN† ‚G4ô§Ü‡Ã›¡E°†HVÒÚ�t²37¥�š¥dòiä ¶Ñû#,ð[�{žëSÿ{i”N—Ƨ‰×ØQ; «W4÷eª´Ç6˜´Ä¢Qäb/6uÔ<¿óö:î0Õd¤‡N®íc­X«×âÊs¸Ü5Éüô+eô®ímÒ Ds-á•á$œšô�QŠÎ† u¿5Ë(¸mF—–Ó¤àùèzGŠnVÜ€mÓÞ�r£üî#8ææeæq±ƒÖ'‰Ð�‹9¬>á6íÞšO¡{çÓ(IvoZ Qø„+K�Œ]/±·s®R�Òyl%míŤZ^�k·K´ìMl`±É—YAŽ/Q§kùntvÈ�]•ûÃæ4}fEÏ? ~Ö#nû¶|8ýë4)�CnJ˜Á?æçœ“„õ#@{©ûèF5¨âü±Ù.WÞîd‡Í•ÀH4’®\ƒÓ4ú >³ žšêP‡ãðxÝKÏ>Š‘Ù{/œæí„Þ—ïÀæÞ*Vn †g>zqë²ÿ�W¸£™çpŸœ?­5†Ø:ã <ø8•u´ý;é¼.w�^tº�1Eàó;¡¸]Z �'D’Ü­^~Ž˜¹º@l¡ y®ÛMg]þ°(Ÿ×LÑ6Ã%i7ç v#žï¡³‚ž¾ £Ýã£hÙFbv|„Â#U¸oõDÚ.yn„ƒ‹éØØ�´·7ý€kO]¹ýÙ¹ô¾.q¤_Ì#›¼Ní”Áú‹ãi}‹(]Õ~Ã\zS(û”/6äL¢_‰EÜÖ,Lª0EõöÏ|‚w­lŒ`áëHíüR,~Á>O,Å-“wá¦åkáTÅ6q彿9²¾dzxô–™Ñ°¯�æÖjú_™y†<$o‰ÛT¦³M=6㎓ü�˜×›Nå#¹¨|Ç9…’¦ÛT´_9u'êÑ¡§ÓQÐr=k�ÇÏtA}º¼†ùŸµpnùv\ùT‹,ENs&Kqaš 8Ú Wȩട¸øô>|•]B—·/ÄQVåÜM% –ÉÖÜÊçWþh%£ <ÿÅ'$“ƒÿHwûå…zù±T ˜K=†•LÌ6ˆv„•âØ‰,ôÊnš}°‡t¯6Ÿ½¯>ÜÃ&”t±wæFl£À¶Ë¨‚4:*Ðf¬�I�†ë*6€ÓÕI¬§¾/8ÂþsUt.8 Ëw–ìÙÀÝIGP’žÎ¥µû¢cÓ>Ø÷;‡ÒÒü'Ö!°„Jê£ðßQíü’µ\ÚH=r/`ã‰lªÕ^�}‹ Æ�‰)©8綘ùù{¬°ú>o½q>xû`Ê÷ ”¡³œ½.›ÎЉ‡×M�üU¸Ï>ßVbY K-çq;ûÈÞý+cž‘¿ðxTNÚ›…Ê/ yÓUÖ4ÖÏjºÑâЬ¥©ŽHuCÒjþf¨°F…ÇR2•Ã˜ê½ ˜ï@[2½°Rg�|VÆÞú•½Ô9Á–Îð£ÝÛÉæÜ]ú’—ú³Ñ«O$�ž�.¡ÖœèTyæóQës�q,ÒÐ2!ë’­Ñó=¦:/äSŽãŒØ Þ§%’ c¡Ãvˆ(N‡=ÍÊü¾­‹ð!ªRXR®¶µkþ¢ÿj`¼Eì¾c‡­'ß27;_*Ú%EBv°ájü(#1rÜš‚š}QfK£Éßz5îz]C¾Þ£[†+ àxðÒF¡É^Gc^hâëûéˆßÊØææfö)#�­ºò�Zàgä&¦•?µvŽAë÷‰ì×@6�ŠnÃE³¾0ÓÐVôûÙÀRw¨ÃÒa{&³g'®N-¦æwñì�>8ªðŠj}â¨âL:>;9 3—\ç-`³O'…¶�ÅÖgTV:ÈfÎL¢Š›‰0ÓyˆoRaºÙ ´wÀ$·�á,Ú.ñ+è/¸äÛ±û›/�jT9<7Ky*ƒ—ç0V“aF×õêè—¯,½êXŠVÞèXt�ê �¯7Ô˜ÎdOÖ¶{ˆþþ餼�%0Eìޱ[I÷#9éÛU`,g@³›ÍþÎÍ‚{ß�µèVNóh‹ËÞ…�ÆÓý“üij÷>UÒµYÐw>kðöåE§²�«nšNÖ2æ­v[ æ±6šÐ¹€flœK1¢îìá“�dü´½gÉ@ÛŸEXs’^¸þc{$³q�þu¨,­nLY¡~'py¨«ÏHdáVQ~œ%†h¢k³ÿñû>Qdwg�b³WÅÃ’ƒý1X�M 9Ž¢5ݳIcB¿z4wÉÂU7Ç´¸uè³7e_XÁÉR�³Nˆãë©—{F»Vð‰Ÿ²y[ë[œææ|â1­Öå²Û¢°aw,Þ^šJNokÙÖ=?›¿>݈!rèÔõŒ×›zÆywƒŠd5Š›@K_{]öšÕ]ŠcÃfÒ[Zy¥�t˜ócšÈo#××Y�6Ö—½4µcñFòlamôª¼Fƒ‹óø”ry8‚oÁûÏt4=Ž™ör¤r;ŽþM¢%Ö‡`8ü8‹åÒб–œ›+È]`Zþ+Ác‚"è.¹�¿Ý³’êt>r*ûß2S‘r¶åA §ú7�üªœðÇ”Sô[L–E]ØK^ ‡—åà©@Z`3ÄL;¦â�?êt.\;=•ø=å<_4Š Ü&”5Ö^�kŠÁøÛo½˜ý§9Us«ôqpPŠÂ?ä�D–[uiBËèCøó*"¸òn%{Ö€‘÷›àYú ìûÀSç‘�Ø‘@�.ÝnÞ>´›ÝNPÅdO·æŒjS,òKcüÄ¡Ö'–_¿ù¼œ)‹¢ïä©öå ´s!¡M˜kó’�›]d+øoû2°Ût |Þ»”ìÎ�цFxìÖÏ£à‚PŒóÑ¢e «Ñî?;*}bF.&–,ðÏï›±‘U4 q1ê•üÙÑ[((U ƒä͸Þ×rÔ(RŒïb–CË�O,ö¹=æ?äá‡ãufÆ ÃRÿHlvËÆs¥…\濇4O¤Œ�+ýÄ^îê …¦ Xû\€-® ѽ~´§]¥Ž¬„Eß”)þ­x](„§ò=|7ijq•ޤpû~>kŒóß3ý—ÙtNû�LC¹ 8µæopI‹Ò�qJ¥T,wŒ^-©ݲ{ð ·Yïïet�ådX£â×(ˆÖÈÁ»ëŠèSÀ 8´:Ò¿¥“¶ž8ž±L…=E“ab€<î çÏ(¢€{5Ù¦©á“Ê>níûÛLrå,²Ú– y'äpTÄ_Èè,„o»m¹IYá’«(.ãÅ:ˆœ|ûBåS &::_�fÁ·ëÁßZ›þ›]ÌÎË|ÄËöúÜ6ñ³âMûHßâM¯¿�?.$Í圩Kî!SeO�©â*mKLΙŠ7‚,ñžÛú¼×‹Îc~‰�ÍÿäImÀ 3ÿ@ÌSðý7ޤðKÛ;ÐUë¸MÞËŽõ[àÅÑ-R§vâÕ, ×¹K™M߬í³�M ]ó»y÷£BÄ·‰sO2æqÊ[J1ëïÆ?HÀ� F4$dCß»†M&®n„´—+9ÿcüýÁ€Ü÷�&+¼ôÓ‰/ÌGÁ±Ÿaáñéd0½Ž]NAÅšm!a´¤;‰Y휋 Aç¡ÛHÐVoÄ‹žCìz[2´ÝOî7²G¹¬çâ&¦Y— ±msQVz=ÌýˆÍ˵Æ�Á ¼wQxÅ^Æe×}©0m/)~ÙGÏž*°™W³áwtwØü=ü~Žƒé¦é«ñØúÕd_)‰‡¼3ð�Á\²_ÔÀ²´Ÿñª�Ô¡ôGKü›o†® †-óqf‰.ìŽ÷ã²M™Y¶2:ˆc}·ú(ÜçLCÍ©äM(ZôkÑòW6èé<µâ^É-[iø[ ÜÏîãÅ%yM†¶n2§¦ÅîüÙ*MLüñ™´[§âgÁ¶»¿Å”q¹q)y{“Ïõu4ªñù~zÉRL΃¬jnsãÒçø1è 7�i1îMG¥;AHý µ8Xò¢ëºÙ¨qaÄr%èûVM|;‡|©£ û‹ìP ƒŽ“öhÞËöþ´¡[Þ±ª/9ùÏ/Xâ¢j84ÏŸÆå5°ªwÿøŸÓ!A?žôG­ Â�¹ì�°Ùî_ÉÚ¾háá}ÇñÙÜY˜~Õ�bÔ51ä˜:¾\ÇVª=d÷¶ØSÄmkrÓnáïîf“·Í¥•—·Áòu½tÒã×QáL&qì�öùyGÒ×ѱì:¶*.�ì_‘VŒ&d¬¥ßŠÑ,-î"Û=º¥¨3ÿ=×±Öñ{$û4×j³³ï…Íí æcÅñ‘4š–èÇ`‹É:ú•ªËF ½'»-kÐ$9 Ö]�µí¬ÄÜ–˜±Yz´ðBx�]HQUËÈÑð ._ƒ½âcX�ü'ÞPPþm“‹7à¾2•Íís…ù1Óaì§°&ÃÒ>ʸ‘� >M³÷�è»ìʼ­ýÖ !ìɆâ`ŸïO¶¥ê [šsíOŽa›Hx÷†Rã@NÍ=C®AÛöTøÚ;“Žè×à³_Ñìþâ6¨Z‹&ÄÛiLðµã´_F‘FW4Óþï7])[Êç1ã�‹°pÃ]È5(¢À�×l¾”)/œIú ±ÄrYÑ•*N¬°kƒ5覕É%I¡½ÞB26>ÌÕ¨aùÂØß‡©ÌÐ9 ~† £žjJç~çkÑ�°/¼Lå-nÊÍv¶ÁÙ‚í8 ï6ï £º9Í—!´ÇÔ“ÝÈô�w’ø×=bpáM¼ÑÀNøËíÌcjaý¨6¬ä£ÀèÀmpY¦�ŠS¬HÏÊ’ÎßÚØü"¾˜N â£íxËÁÍP=?ÆžfÏ——‘vCÓ= CÎQæåOn ‚ÊAï…-³øQÌf¯M6�¨“ÔÌOUOk?O§Sé«)x¤c^ýo–åÇÙÀ „¶¯dq�C(üg#Ù�ÌM={¤F-cá¾Å¨2iÄçÞˆ³ì�¨÷TŽÍŽ¥—õ'Ðo¢¤Õf[µ`·èzö¼\Í>61Õ‚#øˆO†¾þ‡ü�ßK¸ˆ>CJýšÙ|åú39AϾº‘èîI˜½l!Ipû8%ôùz›]I*Á'²[Yxò<(Éßµçf&[иm186Ë gDè¢ÀvOœ´R“{ß7‰Œ „Ù½[YxÞU•ÆÍ(A…˜È–]Jª�Ñ”(ý†ü|sy;‰v˜!ŽÂŒézc™¹(кÇ+ØÂÞ{pòûržKê—Ñ™‡ÉðìÆcÓܦé¦+çýdÿ.F¿˜b–¯"ÆJ=3(Há=mœ× ûŠØCÉ(Ï¥§{º–iÑĞܞˆ´(tQIn •o[ÇÞeÇBéŒõlkðÝHódžÃ{‹4º°‘L´.Âï;:#f“œzáQ©pKð¯3lÂß:63´"C˜UÅCvù•YMÉE¥8UìïÁlô|Èv±`ˋũlÖ#Ž ¢Ÿ²Ilm/5}"j>ÇÆçw@Cä!¬Ø9_«/ƒ=™pxÍißG)s�P—¡8þ|E^c#aŽqIU åµÛ�ó7eÄë'µd—Òªª$,²Ç[×HÒwíå¬]y63®÷x¡Í¤xnÊDCÔ?½�Sª9;´wE«Ã½Ž6sÎ!–xá*Tœñ»¾ñ{ý™É8?ºç<š“í/F£)¦¸\A~ŽW@£U.èúpÏ͘ÃÄÔë¹È“×Ùî6?&ä!J›I�&Q¥«–vh±¡W¬?‚9󄙉B5¨;‹™íÜOÇ 9ißñغf´ùÓX3iPRåt¡4ÉLhËY:*¿Oub£/¡ÉÛ!˜º:7観ç½ôáû, ßÓHnÛ1zV+—ù'—Ÿ›ßKß¡qø‚'µì²«Ë|ø›ž9¨Óµ QöpÅIÊölÖW³ÇyOáÙPÙ¬-Æðì�¬«B¿º„Áƒ�åèãBþ_« kŸ4KwÉ(ímpüF9‰H�pM)†ŽøÐuñtx�Ž|Š g&]ÂRÇz¢ž°uÿˆ£w_#X÷HÞYÏ¢›÷ 1.?‘æ*èaä¡Ì2� fãÓ{iÉo Ú¼[“ÜmMðCN )§ÄãÚqoÀ«J‹¿{R›©¦öÃÑå~�4Ÿè{ù(ø>~?fukòÊ™7áé¢0¼œ,Æ?Ò(b‰‚&fÝÛ=)eÑÈiÜB•ø™Û¥$E7®\„?|9s�µ¢QÇ.ñ?6%ƒÿ¢|î|‚Qjס§÷>Óé˜ˆÑÆªðp‹*uVv™móÚŠ§4npq×[áç¼)d.ÐÏÆ|e^áYNENÁÜ!EK@{ v°ÞŸf4ДÅ'À$ ŒEH ÐWCnö£Q”b‰n5gàáº0 œNÇÒxk�?Œ©Èa‚‰E`e@èLåžø…“ŸëxadŠhd£^ÉAÙ¹itP9†Ž©Ì¢teEšÁQÏ«vüÞ!ÂŽîˆÂßü&pøÛÍNÊ©b½ëLÚºÑ~•ŽÇÜ™n$‘èB_e²Ã]gé£D%J\é¡ ‰ç€ÆÞâwg|•ûÇ(^!çLÀæƒ%¬õÓ08 ã׈Ñ?´s#Ó²‹pÐ( oKÕ'¯€‰ÅìUï6Ê8º\õåqð[¤˜Ú£”¾7ÿ­-wÔÿèHöí?uðæÀx<¼º™ÙÇ×sŠXD¶6¾…'ê¶x²#îøÌbsJYŒNYn-§ ñ Ô_G*qRìSî ŒéBz:^˜ Ÿ]¦;¦¡x;°€×Ú^HÉg0ÁäW�ÿ±€œKÇ1c«±ÌO÷(†ÝÕbK6¨¶Œô�&» ɰúk)Õ‡�XŒ7þ¶*@AÉ\ PZI'sýYå• ²¸¯ƒíé.læYRª�oUup(y,T¯Äwð›N„ãÍ7•h$N«§† †ò/³‹™‹YÿÜuwý*mÛ¦Åôï¸}me+>]eû%6@œ�|Ð ¡÷}s˜¦ÇLLÌåJ~q4»`³Ë86¤ÐZ_ìI/ô?øY·N$¥Ðò[ñåjµn£`Ú)®iíÔÛôQÌÝáVnúΆþ@—¢~ÿp’+±õ¡óG§£^Âe/ÑßªÄ±Ëø{ó°êßEcSÑg³sW°nÕ8L‘”ÃëX¹_‹-%Ã̤|ì‘W£�ßo¡gÞÑ¥ls²0öβ ÷ê*\ùb4ñ:+Y†áˆ�æ6à²õy”ã½�ŵ¸Pp[ë2À°–Uø4}&ÅÞÀÏ_áÛÙôÎ4Š˜" ;eþ2…¼dœñm7jhqd“RkhTîW6Y4Å,nù\rÃÔá6e5ød²†ýaL-÷8®:öˆ{~q'¹ìTA—ÖÝ´þe9(7Ýäߨ¦³—¤áç¸õ˜¾ò.zÊ«DP@~9 ©q“vØá²ÑfRë³Ý³+! x&üHƒçç�Ä�*âøprŸ÷àM·!ßOPqdw³Rg˜+NGÉ3Ûh´óxÖ]˜E'D½àåÁýdÑ£ pp ^õZOyShqR,þ—¾‘›&mM/ïÖS|‰,ѹ Ô¨é@[½×µC‡å+›Fkõü)0ç([6( ïÞè“×V’=>“Ÿ;VO¥,g;^ÿn¾Vë€ý v29»:øæäÉ Q Ñž×Ë)=Ý`&m}YB¦ÿÌYBÒaÖn,eîðz ÿ}¬'I9ïfß_uaȧËLp%�x`:ƪÉPÙÊãxQò�ù4ÀD e騦1]ñ eávkñ˜vÙáv힪^ÞÌONW¢èµ‚ñD‚ô›Ú©?ç,‹hÞÊú|BÙÓ×ùÒÈÃ|Ôìì©ßF£ÓIçǹë±® 4ïÀ!æèÓ.Á‚Å{Yí¦½Ð—\@oýá­MÔÎÿÑ�àîmÆã–™Ü9íÇô@è»ZñŠs çACÆžÒoná}‚Ñ»Sq³l7­Œ72÷bš ±·ÆEìsÚ24~,‰+Úçpéàƒú UÍ&ûÌI°á “(æ4×%cCŸä )a›]!FîU¥*ïòfÍ{`§œ>›!’ˆ»ö;Ðïg|£¶�-² D7mSÌr;MN5põ÷¬IµcQsNú#|zG�ä•RX|©·YQÒ.Ô™ŠÉ6]Ãu£SñZŒ5³¾ÝŒ²¼q†ÿU´´× òY÷Ì$däÙËüåܘóÿÁïÉF4êú[tuæÙŽ)ñ¤p>ƒV�ìjóÓº":ÓªáWçh³æ¿A ­‡hÀ¤é ÿ9ûDPûšZ?™† ¥õÜ�¢@ŒyX¯3¢_ú†Ý|lŠ�WsØ’>ݯå_&æàÅ_øÙð9OG_1>ÕvÙ g­d¿o¥ékrèñ£pj}È¿WhqW/Źr“±­ÿ4;§HÓÛô!é–T=SÉørõüÒÇ» átµÿ1›ÚÙ }¾o`lË [=\�í1lcÏÇÈA7òÎ;š®ÇøÝ‚cxõwÁtÎQ åá{°±$³±€sÇÉÓ©átç`9ÎÓwƬÁd2оXÓÞI°{é<:8ž~Í.çó›ðcŠ «pÅå)Mw­“aH6ˆ øB/‹5y˜7¥í俤Á}uдS7kéà©9 ¾+�ga­½#eHóx}ósf¢*ÏŦ^&éÚÍd,¥Iž‘Èær9ý}¢‰¡@�Q›?µžDQ°„ºWŒt‘xIšg»�Ž4 iòL°RÀDÿDtÿ äœH®æ6xú�jÍ~X¤©Ñûéf£j.aÚ96�ÎΓ²£í4÷†ôï(Å÷0JÚ¦Úøß ÷¦Ä㘂3:%ñÅìQØv,Pˆ6ïZH ¹ƒãô Õr±K½¾Äš ó©ûÐõ`ÈøÖð/×:PPæÒkÏeQ§hÁÚc”áËh¡ô#ì±1À¾'Kðc’Û¾á»7:/ßAœ"XÀ#jïXŸ›–¢v—vÿzE©Ák˜×¸ç¬i©-±ÆÏ9Êüú‹mNmæ¯ë ÙH;›Æ�§ù|ÜæO¾Û«`É kJøîJçÖ>‚s�Å  JÓÌ·Ó‡öxø–dŒåC×è?Ý#\@ñAn�ô'6ó_®YêÞ=ðøwÄ섳¥štéËjÊV•à¾Å5Ó ÉNZñÍ‘æu¤’ãÞÉØ¯r—ôÀ Î<ºÈªhé§£øÎ«‚±ã‰¸7ÿ-Wßs LÆuPfP6«Ö–e]+ ˜ºS Å�Zˆ×W¯…“¿IaýfšóÊ “ÉÃÙC9tòÙ+Z\¼,øÂ')N…�£Ðæù!XõzŽ)l¥wžÍ˜ëŽ2ÔR+Ž ›‚‰kåÐîˆýù6 ZFe×_qÏ÷œË(`üß7°uÿ ’œ.J}ö? °ð =ý:ïöš‚ a?[QCg:&Ùßã�.þGO†{àÖŒwd$¬H—&7ò?¦ëÑäã/xßS]¤øë(z)’eVüu{ÃT¬ñš=·º0zÚ3ˆK3ÿ:E»;}ÁVP ¯Íd©6ãÙ-åfxžÕIïÿ&кAn™�˜i?gšoÄ[pÒ2 4å¸u³Y;Öân2Mk2»#ð‰�èŠá4]LŽ™†Gg]fÆ-6Ë&ÓÞš*' Rñ™@d®­xÏsÙΤÓM�ÔœÎÊ…aý£2ПâÚs–Ð_~3xgVµu3m U`ªù5 7M ¦nJ@õÀãp�ÆRL…(Þ<®ƒÎKiHb ¨_%1^n̽ î£ï²}N`øä5U7™Ý»áŒÑ'’ÑïíE¶Ná# p£ñ5l–ý5–õd6Î� uVËÌuƒ‹ÍúŒ–²Ÿmñ®q ·Ð×BNÌg•†á[¦¿°ä,*]©ÃÿÃú2ióØ¿ h¹/ì�N„{�/á|xȬ'û"ú|j2³�z�=P‘Ÿ cMnR�{&Ýy?oÌLƒ¿[$©Î§„¶Ú§`ëSO6ÙÊ <“3ÑÄßšîLÜNC¯È|å.î�Ë5nšu&Õ,™ ªð{þjš(Ït«¥8ÏáËØÆ)Ñ?‘0IÀš;ü-„ö4ð¢k³�âÍ£š­a89“>íwÇ;‹,ðgô66yÀެ_ÐPm2Ÿ¤sžøãR¬ýL ýqke^‹Ø¿ç¦(¹KýUg²•Ÿ6áê¼6V�—ÉnÙ,ÓåËvPmS Ì0<Œ;¿H“ÆS¼«‚'&a题òê.OŸ?€Œý[°ÿ´uxŽÁ±/\Ô­fæ p&à'½(&vÇ€Z6N»E$tЂòÈŽ,—M'e½fÖ´ÑÇÆ<æºí™Û&W¼_|†¸B¼8å$oa|QT‚«º<¯t¬f�Ç×í!,|r<¬—f�7˜áíKÍSöÈQùšhú¸aÞ™A¹îjè|¯ & Œu4�ÕrŦªñ4­æ ˆ6øRÑè‰T&ã Ço Xé1¨±i ®ªâ9ç?gرë~,?û9 Pˆ¢°=jp'àmsœ÷Bâl>±ÙGDq˜Dp0@˜D&w¿˜æ«w1Ÿˆi >ìA›B•è†j!³ 7Ó¸ê‹ö.Ç ÃAè|5ŸVYD³‚+ѵp üçz¾øåÀ¥÷ÂtE«&œ &¯U IõäåîŒböwG4}ö¯?sÝãA ãžÒÔy päSÄœuÄÅQ'ØÉ¢N–^ 7/­gº—ÄyokXRj…c–ýcoÚžŽ0©Òmzµö7ÎB—ÄßÜÇ—fÁ»T3˜]üŒÕ,EËWŽe?“tizg&@Y'ËØwŠâ²_ƒ.d"Êä¤nQåìa[Åàõ–øÚb' ù{’í¿Í|€fûé"lØV%ÛÌYnël©×¦ƒ ÷a‘Oj»ÏV|é‚ׇ_à8üü餃¬ˆIý}ÃUé¾äSŒ¿AÏÆ úäîˆ.œ �XéѼlJ3õkdÝŸù¡8]Õ&¯¾¸™Íú©ŠýS¯ƒµoÓé°ÁMI¨2Z�~ÈÅ‘ÐåËÀJöPú;3¥�…Ì®s&úÏ~b¶FK ƒª¼È»5˜;5-̳…ž¹5ÜC+!²(`2²«éYl¨NÖamÎwøùf+ ôL4ëKÎ!©[£pÏ�tvöÆyöîQ!(O.IØÎ%8Üd.Ù¸üë;Ö¸DœôGz÷}}Y<ŸÞÜül¿n7�ÄŸ7¬™ç÷û¬Ámˆ=Ø)�½iqSç³àà lW»0 éÎÁ«ó¦PÆ�–ñ°�¹ß8Ë-:A£'&”ŠXf(ý‹¹>OçÂ÷^Ö踌zr$icH =‡Öfóê»�v$ =ªâ¿È¶nïïæÇUí¼â-#¼ò«—™ÔÅ󧉃†¬SçkÇÑzÇ¥U±I:odN)íLM!‰¥ËñµªmP˜ –ãBÙ²-Œ›p n µ@ê‹Ð=æÊ 鞆 `çßÎ"¡´»ÌÏלNNb#_³ú¸Hئ7DrKH—¥°q2Ǩ®ÌŽº;±_’Rôfá~ÉÐN:þÏ o¯Aá²FÖ™¦Š?Ü\1å˘!]ƒâ)Ǩ&\ên&]§Nvâgƒ™ñ•œéÔ:ñô£z =Ì~¿ u W°“_2qþu+Ì�ŸÃün¦P÷½1ìMÃF¼Èn›Ý(2çæ¬ª„%åp<*ˆ²ö+âÄå»0�8f¦«�òþò.2W´ü e‹÷!N×Àî5|ÂŽ&ê—Ec¥F3¥4Ö¤?•V³zS8­%+Ð7ëoÐlË}»’‰î”Àº¸0ú¼07¦þàÎ ÏMë7¬zg ÏøJ¶ÆM*%åIÊú(Hz[¡jä…àêmîÔé_ƒëdðÄͬ}‡(�Õf[>1í>AR”îãvì+eÃQIP{êï”yˆZk,š§6¬ êÌ ´È4‚µ½ÃÛ�JÁýh?ô{40�œŒæ}Ã\áúßLqÓÓ,3æoz1›/Zì®J×WM/„ãù”ßz�»h 7{úN5lL¥=ºÌ×õ>ª-ÈÇ´ýÁM×Ïf‚xàå ®Ç' beNàÏæy˜Ö0 묾1©›¯@Cܽo«Ó¥™3𣋻Y¾ÓBr�‡Ûî]ç“ùhØ¥.€g´Òi¶ûfœ—¬II£µÈö³${~g¼úÃJR×sªŠ¬Ã¶ƒÖ¦¿d†§ÇP®½X÷²Ÿ�“hrÒ“�xìóI,Wñ Á7‚T%[eWñCß"¨¨?­·ìc™›3ͯ?…»#Z•Êr¤à1�øçìvv­#‘ª×ìÆqcVÒeç Jÿiв4«d?ª(ã­®I¸B¿Á NÕâ‰õônß9˜±MèÄx’«„C� ¡OÕÙ‘ x¨#œ¥OFíDqZÙ‚³ÝÇ`¬‚3Ë{¿úz+Ùn+šÝ® ɾKy‡ynCXTˆOÀøÕ§¸'ÙÁ4ýZ,È{ÏFù&�Lù)° —§ úâ6§zÍp‹Å}¦a¨k’Oi:ah{ 6í³C�rš=$A·l§Ò¡å†x]¿+–``²ðŸÙîPC O{3îÀç ×¹jм—B(¥Á$æäÏMÛBŸ–Í£�67 "ÊŠª_:PªGÎ eö³¥qÂo¨¿.ÊL–²ðŠ“¬ªrõ¼Ðîïfo㚣Xœz/{´ý>W:V ò>€\ž 0A÷q Qó‡nˆ‰gu "ä�i@¾ª€ŸÕ"ÒW3&Çü\¸m”�e@<ªSæá*ÿ p: ‡ßÌç":'€èϽ œ}‚¹Ø0Íû,ôŽbÎYÎ#Ég?�@6nÞœ}Ã6dPjF*žyÈž ܧ¾‹ ®ö˜�Í6!ÅŠB|+°�¶X“±§ Æ/Pg±)Z?æ7ð)¤\íGž ]l•ø3¶®¡wFÞÀµ[.7KjÌ㋎ó/tÁÉB�f[w°üUJ¸íᨖ-NÃpek[óÆë^Ï“¢XP!Â%^×&›;†¬èµ*:k©²çÑÔ;‚½§ÿ}�uu hç†?P}õ \mAû‰<·ö抢¸[å­ËªØÄº±Ø7~ÌC×µ„Qp*`lÓcCšì…›O�ü¯fÞ§Ì 5ÿ)qZd†*KNpWoåÒ’i#ûµ±Ãg3ñƒ»Æ²JcE”WWÅÁ©’¤gg *óeÉxìŒÕbWÂà©©ð. ¸w%S˜¿Ûkˆ—*CÚÊÊ ˜íj6°2Ms�ñkDd³­øjJаE¯+KÙi-X}c¤£ñAþîÌêX*�Êl®ÜaöòE4&:EÂö5 ÄiøÂw# ¶d]- MhÇUõ’$‘C-Nƒ¼ìµe˜ßz�vn–â]OH$c;K”7„üÖ=ôü² »ðétó3¿ŠxñzÆFÊ£ûÙiLsù7ÖX4 V½Ç ˆ�•³ ¾ËÂUs¤Àÿy ~´‘£[¿vÐ¥NM~¾ËWPø6È.«ÎÂÃ?£!w ÜLõyÁò®p½ÃÎÚßó³‡G8&šÇÀ¥óЏ§.½m�²‡ÿnÀ=?6#F�µ :±‚%6xÛ°ˆNe”ò%Â>ì¥Ök¾}ás¦ù0‘ÔôþÔXcO€¹ oƒ¯tZ8g7;±*×è7+MØ)Θ…—.\ZoŽZ'àŠò$rnÈ¥ÆöÀuV¸yë{ö`üiÊp‘£½[¬Ù‹ã2¸¢Ù…ƒÀ‘Hä—ã¢Èbêewx)ÿ!æ~¥É¬Òël>žß"®�šÇ¢�#‚{pc~oD9õÚf‰ÕÃðæ`´”¿å"ÚŠÙÓsWا“S©:©—íéìg3í³HÎÓ�]HØ„ëêØ{Ÿ)¸ì°:m¾p…âù X5õkõ’Ïù`ƒå0‹~³œ\ÌÈ´õÿ;ZÏlÒdÓ-~ò¿”#pžs3úIÖóû™Rë"¶÷—i§U1­¤%” VÉv¶ €÷X6ôeÁþw“iKÁÎM—i´r…]g;Ò‹ñ”I*[Ó¿BÇŸ%ñu¸¶ ‘%¥Éâx™xÖY€jásÉmÑ9°[/2rŸù0¿o5*/=h¦p²‹ûv ó?5;·Ðk^;RL–]²f·šÅÁUrÛÜ]™ï/QTøsœ¹Í¸Ám¯aWziËØ+fãÛKÙ™?n¤ë\ΔßJ�‹j?¬û¶NÜŒ®J^ìtÏRúzÄ™y»6¡Ö᜼�"®—38y DÎھȼ–‘ ~ÏŠ# �µT>_ÍüåáålôÓ³ðÃ\-ƒ>�Î{j*Þ‹vÿmä¾õJ°ÿ`¿q,zåñ¬ 7�…ÿËòÔp£ŸY3™ÙV8Ãh \…ЇÒtJAš&§›ãôOŠøòIkuDã¥ú´:í;Ó*D"Qœû¹kPpG”5ûå¡Õ?gTUƒÌ“vxbÛ.ºT·Ö®Ô5½—¼ëÃíhkýZîÎ_a<]3sÏÆ±Ð¥ ³ðSã~vö¨ãMýGb¡¦Rùã ¡£d¥ÿ6b¿‰Xþs0†YêÀÖNW¿b ¹»ÓW�±¼ñe <¼TĦ:»ÅeßðéNÔ/ÝO–“{W=Úf-œ_szÿØ€n^Û`þ«zJ¬ù·ºMûþ{IwÚ[ÈàÁKœ±ýMÉÕäœönúÌî×#ÙÉCŠbÎE¡‹Ê~ö_dŽ«&ŽÇÓ^²g5ŸÎ©|ä}Œïmu†óÁ>t'Á;ÆJsRã”7ÆÑe“¹¤;ïg‚úB#t¾œÞ±vÔ?¸KLŸVD’Ò“ÄDÉRiHˬ;ÁqLœjÞˆ¿>ëñs´¦Ù­gÓ?ëQ½Î,‚’ÓÁ—Â/úÀóH? 0ñ ;GOØ}üò;=4a®tJøæðñ¶¦g‰ï/WBßãmý^Û¥üÛÏžGìÊBÍ­Z°¼Ïd,üwºrɘjXnW_]´åƒiQX¢Î'7ðÙíž|pz‘(}’*}ïÀ¬=É,¹¾RÈŒð[ŽbeæYŸBiyn$'e÷A» ˆ½|„´ }„³oÏÀ5M~†‹òÜ1fxéÁpì?s1õ�³ŽŠµ"qyª9 [�ÑÞ—(÷Ü7ŠûnË^× Dó_úþ<’›—M…ÓÉüÉx�Í9À±è¢òlüKÑÊø),²ˆ§íJ™4Šx5$œ[<¼É°ñ<´?XÇŸ;N±FùE1ãµ •\ êóD«W:8RÍ�bc“hiê1Ê>ä )pIA"¼�Q5¶%øQó |î;—%“~±jë{œqÊWx¹á ”kç°B3ü“+�.Z÷ ;í:Tö=‡!žæx/¬Çç�~&šš¯ŒFÂÐÊ�8cÛ!h»êÌ[²-pxÒ\òì „¤çÁ†ÛA!(÷œÊ„ 긫òÎû¼„6ÉâÑŽÞëmeñ•×8Y¹�KµN–Л)¼{¶€„…J¨§ù«2Ï1‘ƒ‡LÂÕrýQ?$Ï yà žA�o‡ßº†¿Œ2ÀÆmþ½Ð›ç>5à´m‹Èd´"¥õ)G8'Û3ÿÅd·}"´â¿îëb§W¾‘Ù‘jëØp¢/Ø­@Ñw¥é¿i�p+Á…Mc\ÅQ؈«,�s“ë6V2ë ý7iB׋>徚#×›‚I� M÷Òb’ÕÌÞ¼±è7Mü¦Ã[kWÐÉ ‹Èºc”ßJ7ÌÅCû£†â~.ïU–fì7w"�híC%¼(Õr8¯é°ö¸]Æ5GûáFïnxWrYŒÙº‚•ƒdùå¾R:‘"ËÞr6|'s n¢Áœ\ívÊ^øˆ]%&85P›ÍüOƒã73J�^/<÷è�î{uðʤz²Íùþ£hNQ|Q/i^Û]n*­¥™\;™Ûzj>ÌŠõ_¤6™Dð6yHCêóIvôMqYëi�Œâ/‘SAw—3ü�"‚P¯Ž2q6°^[Ó~*óùi�àÁ‚U¬;¥×Ÿ¶}Œ5×`ÃÞüèNë¸+ñKÇd¬ùU!hÿœÅ³WZa­i9lŽ×†ÕA¼Ø,ƒ¼Š—‹œQÔ03œ�Mâñ~Ý�1•:¢L°ìŸêѧÍr“`¤t �;”2øá§Aq8dd’P]œ+ZŸ Åü‚‰¢l¥w©·Àî¡Ç `ø6¼ ý{öØÑʃV|% q \=|s Ë‹ï`Ê�%=|aÁÖR¡ØKCT´|¸Ò",• g”�üu}ú8¬ ¦Ý�žþÒÒ±æ(õ©ŠÓWô°KLš¨>~&_ÓÀêæøìº¯Œ»ê®|Ï|>~m†S3äñãÝ¢ÚÒ-ø$OÕžêcgA4Ý[Û g$õÔèao`®¸zå~êþ<‹Œ²DCë‚¦î ˜|»ƒ¾üÅÓö³¿ÉNªñqÁ®ÁÅ‘»Â‘,‹ÄecÄ!A¦¸¼Uç.ä™›ï¢ÂmVš§ º_ƒÝð×âÞðùr4^ÔÏÁÓVF< ±ÏÖM®j‡Î½†Ñíbw®¾å‰Ï̲X̳§i'äX³ÖNžð �³²ù©™¦g\¦­‹¥ÙæX!h>HÅS¢„ìT=’Z‘M¾{>B̰°^nJO½d õ”4ú†)óRÿ uáª)ßW¡>Ó$yå¦^8þ×Ðõx¼˜m/NlÇ [^ÐðûË9ç|2 «*ö㹋tQ‚⡃¦Ââ½ÃÑ6¾Zh:¨Jj&‹ùó¨Ï$Ÿ?ês¤Å¥º±B…­¼ƒûs/Áÿ“ïYnÅ'ŠŠ¨×—kcŽ¥ñr± ¼3׉Eãí9C ( ªFPïœ%Þ™J¸aÅhÔÒ¶gûŸ�”¾îšØ<¯îŽ��¯�ó„ÊUëøIï·Ôñ~;¤ ËÖmä‘3¯Â°5)èÞÆ¿~À2%„¬³ƒØív ÜÖ9h粦§g8D»WTýî�°M¥• ï‘„¿?+N¯Çw.r4æƒ"í:( É =X1õ÷ܯ|â4O>úIÒri[b †ŒÕƒ—?°&ø1œ: ´GiÚÍ]~¦¨* 9ï@FÓ¯½I@ÿô:—Š®¦óÚReì6J@…qóQïº&n¶{G«GIÀèØt¡÷Öu|¥Û Wì„÷'Ýy‚¡ú…ÃÉ;vT¸9ddšéý¼lšc!¢åôí!‡þ/‡P~@¼°Xêy[^ÒŒ6³ªÞlšžøš?FU6å„ñ®ŠB8oÍiâU8ü¦Öœƒ}gð¢q¸ø/Á€[ÞÚãý%^`¬ÆoÒ«À'©¦Ò铌Í_-¾�i|V…æÒ'›8 ’©¡±‘º$ñj?:U®‚?&Y°ró0Z¼#†'áÈ= ”ÓÚ#‚ifé"LI°h2‘£¶'Lœ—!:Í¥š`'Þô¤”væÝöxOƒ}û|iìqoþoW1{í8A ¾¾×ûü!\J:GáZ»hýK�'-i�kc4ÛÜ âøÝÉ}Ðon^8w¾çëbû�\ŒO,åðC|ïˆ$—_̦aëz³Ìô#®1€Ç]X…ÎzGAÆyl�ÜÏŠKãQI.‚.u,Á�÷zügæ&:Õë ‰çäñ®o“ë6ƒDýS�µ+OŒPÅšIú“éÎBsxÓݾ§6P�T?N´ÆêÐw‚ÞËax£3wo¨å3×iÆ2M<Úý‰ªïNDÉNSŒóm㘟o•á+:púÐ[p¹Ÿ,†ü–ÆäÆüè{¬õþ@ÄÁMÐ!¹™çÎÓå½í�hwÿ +¼&a¿MF0ZãJù̵t²¤8ð´—Îê%n>O…[‘ßîÈ 9²±l:ó7Æ„à'w¾úØ�–l¤Ös;þÎÕÊĪ˗DiÓ×¼pÙNpQ[Ä}g\/Usœ›’€«ïÍ«�ý{‹b&U‘rñY¶© &ˤbæµ@( I‚ðú¹43GŠÇ½ë‡î¬Î¼ø>ä�—`ƒœcðØí›0ÚIëoÑ�y|¡ƒh5ý9=î7`Óò~BÚYXô:.üÖ�]ßvpÃ(¶õžÀwÛ"Pô/ƒ¹‡š)àm– X‡��vr¿Òiw‹¶˜ªqËÇX¼Ú9_ÿM`)W?<\cD J×aWÐ{Òžñ ³—h9T9Y$>¸nʵî…Ô¹=#œVƒ²®*µËÄCZâÒן€fO z5íâO7<á‹å'ª¿‰ó»†"WzÑ„D9ûUZ£°õR¼+x 44ù£çÒñ á#�B¾nÜ›Œ™ÖµâÚX5ò»>È~îiNÒŠã·ZWéÖêk¸Omn[èŽë&.M=mûæ1ƒI{ü`v]w]h:bŶRl"ŸÀ7ç3ýÎì�¡ëĉÕýÅ]69tV�ÁWÃES7и™l×OŠ`çˆÅ45˜+rªÅƒ”ðàçÑ<>§Mñ£ÚÿöåÜßY$¢Á’“û°½÷>|u.œR6Ý6¯C“®|C5 Õ¦åyWîîyñ°sZ?… ÇóPïCôü„ZyÐÝ#vÑ®—)ÜúËU\vã:iíÓšléHËw¼õ'­ìX->�#m^bÃÀË�¬ÌGƒc\¼.öoЦÞz=ìÚ6†ç÷rÆ%Ÿ°ýª+„ö—³ÏmÞOwOEÅêñ웬N<ÓÍefsäKöÚø”–> §.µÝÜ0p?Œýžk—•çÈU.ßYw|ƒXþЗ³tš¸tP"&¾ì‚8c#äŽ4þ\Å,—ÿQÄ—z0^KÔѯ…æ½vÃåw$ðGî(qÓÌ©¼Cã ”G=¥!—NAù?Ô:nËmqO©Ä/†ÛÕ¿ÓäW*ŸûOE+}eX¹Ì¦äÓ^áÏsâ¨ÍÑ/{ú]jvìáêýûÉ)æ8üÛ0˜’b£èÙ§!Þ:C43Æîé¦:5-=Í¿ŽÝï¯0æ×�s -ýPôm�’Wê^ªW®²<±§æðþŒ!PY8+�ëÁÃÎ[bÃ_ozb[|.»nÎ÷¸ïPæx‘£¦Ësâ³»BÜ ¼ê÷.й=ƒ]‡ßàÛëdhü�d,\7¦r¨†€ûe�N\,yt—=Öäð ò?÷lƒnD©Ê·�ÉM�9БO·µ õ.% »úóÝ]Á켦ŒåÏ~ ¹×RJ?5.›ñš”Ž·ƒöû¾4}GOŽY [4gó‡-‹q—Ûè|6‡žˆf‰Ã14½]ßþôÁcoÎñ‰òÿ„SGæRòhO°<œ'´[ñÜ%ÒU¦ûTÈ0: }2xgA5N}´‚·…øbÈ Xv(‘w¼=Ư”lñ—²Üû^jCéà]ðêÔE¾þe *ÌÏ—á#»ößp—{µÒ³G ì×°ƒläTÑ2q/ž‰P÷Á�‚ò¦ ½¯.#�S?©uïjáμ=8vÅ9N”Šk%ã`a ¯8æ¥þôÍ¡‡þxJ‹2z‡íãÎs«à�ç|¼¬~³òmÝ®º�çÄJÛ·JAb�ì¾sï2ØÍ¦ãŸ?ð¨ó‡ÔmùB’îqÛ½ ê3ǦÆ\¡ÙÂV[hÆ~ùR }ŸT˜|‹ gCŸ‘{C4ÝÉc›7ÙxáÒ+*ÿgËçð°½#„µïƒx«­>½˜[M_ß DïÌ\ø·å®—H “9öŸ,Ïs6%% ÑõÌ/Ú ™È]NaQå~¾ô~äi¯åýYö<°y95õñ±;ªè fÑ›¨ôÇC ËÚ.Xû¢qT_ÔÚ]9çµ#}ùx¨òÇ-Eüš wúóokEü˜þ‹þ©Çѵ˜„ŠóO_P¡ÎjtôÙÆ4wbîã¯4rÅ^¥¹æáqñéÝPÌý}µò.REádJÝQ‰Vs¯Ñ‘Ë»é@h}ŠJÆfZ¤l­…«²ðìQ‚ùÁHèu÷ ÉXšSg9œoþúl�=§ºõá 2»aÎ<_Ô Þ Ý7ÍpñVæã Dû„d(21å}+?p»³aÕ‡‹…ͦØ)q–W)†CÒìxúž ÿÀˆ¶Mò¦¥:«mƒdS„OÇÓÄ‹b4ýyk‚ªSây�ˆ²ƒÙ.{ ÈœýLå !Kº\ˆ À2û"h‹R@å[ƒ:zàôFx]Ä�/ñ¯’5Ø=õ�ÝO©C›ö{´g•%DpVT DäÝ«”y dß>À�×nPäŠ5š«pë´(üÛÄkýrá‡î¬9VËKBû&r òLþïÄ+èÜ„©š'âð.YsŠð�:޾¢7eèi�L¯#;áä�k`Ô5HXl¾¥Æxbk\#¸ÜN¶™Â©½¥ð±£Ÿm·ãt¡Ñþ (Y?ƒ;Î’<üâVx<0™}õF×ý—©²%{&Eb¿i÷ÄP!N ¸…j •d³[÷/†ñ¦ùôÔ¼ŸSñç—¯5Ñ"j+®~²ÓÎåVoÊrÄç}dxœ§÷ÝëÅGçá>“]¸'­ü§¢d×q¬¾b(Ö~ÏEÃ�´h†!Ëi§ò {2=1S²¦RIêB\%ܲuÚÅ#ëê©õÕêí0„Ï•œåû»Ä{±54BÙǹ%@Ýû2([S §­ž áçvÚ;~7ÅHóàäãìíI]ÿ.ÑÂj ˜¤î†r…+„|ï;ðüãQ:³p nͲày)À‡>ÜÂM¦7hÓæTŠmònóéIoÅÅ}‡Ã ébÌ‹2¤½gë…^³^ö…iúxêèÀª‚”g´cï>¢ý…ÏÎä‰Pª‡ªäÄà@wMÔ[2GÔAr…£±Oáøy_ ¥+Ú…‡NÀa7K(ß|=� ò´®Õ%£”b“�å„ùüjäBHXs�Ê{îõ\gmÿ¸p­§«®zÊ{‚íAÖZLÖíÓÙËéKH=ĺÅcìÌ8ô™¼›#ŸçÁÀËüI{w…ã²P;‚óÔŠ`ݤ~xv‚—Pb}‡ú*Ë kïî›m%ðLgI4»t«�ªk;L>®)š7=Ãsƒ'`IK*]U£Ü®O¤=ç •UÄ@±£†øõ«-ÿ,³Á‘¹¹¼ý‰!I~Wß doòÕ;x`L‘Ø’êVOÚ ËeÖ ª¿¤¨î²9LH�¶×X= “¤7àƒ>ãÈZÌßÚipÚÅDÈü�B™‡‚øÖiu¬ð½,\¾ú‡bš·ÃíÏ(n\ož+˱í1PÞAžªØõKï÷÷æ†UõüiÂy ]<@¬¯]&Z¾“ç¸üË1À›Õ¨š.�¶{&éçÊ·MLàóš¥x³Ñ’»gü aê/ðº�M UCÓ¬U|Í?[0ùàŽ×Ö¢04p.ùbˆ©.´*-�|V†I†§©i@f ²+?¶–öÃMŸÆö�•%7?@‘ôÉÊ;åkxÆÆpv–ZÁ ßìù†±”ÈêKÑÎCœ²D ±´¢ÍÔi€ÄoÚl1MµzÕ!�³Ó†óÑ›}QSÇ�o±í[y»Ç²é”¨Yð dÚõøÊ¡‹v}kfàÃýx¬’öï‹ç¬W‚|�7¿#ËOÞÿX€®áyˆÖ;grȇl”è6:'H¯h ÷qÒÁŠ®—ÏÖKÑIÝ�¬;. Î�bÕ-ëðpI1kU«ÁÊ2˜ôp8ŒÌ†%Fó`Ø% x3‚⺵èú©=¼dLûߺG¸³‰¥#£øý9‘ÚjXîé>ò0’³÷=xNôÓ?c23É{Â2Ù:šÎþc¯Ýn¼:ý&©�»&G²½áy–þÔGtÚnFÏóð“c»È«+“|ûÇ“[ÿA<ºä´G¹QýŽëtî� '´Oîƙ0äž,QÜ,ú”ÒwÇ>gÐ�MÃÈCe|Ù�V£BØ|ô*V{ùMðìé�Ä+Ýä³l8_Øy×ùs£Ã q¨à‡!ßS¸—k*ëÂóâbÁycé›ÊV¹�[p–]FTò UkÞcZÎ¥ò?áÝ þ¡²ç\@öìVý÷ˆ†g5‹rn·¨{G èþR ¼';‹wn®¾Ì™š•2Üh¥Â‡¾gâ†Ú|ÒŽÍÂ&O¾ìŒBg6ø<WÝ(£�YGøÉ¤/BJÐIȽôM”>ÿ‚T!>Œ‡]¼¶^‹R@úu9:pÝnþTâwiލ;c 6|]Š—ºúV­þ– Ž�šŸ‹�% +þA…r ˜´K�Ü{âw¢íª —LÝ+[@7x$_{ÒûJsýC#´ÝÔ(ÚÍìõG»í2oéb„wj¤5BjôTr…ã•ëèUc4ª5Ž>ÆBÝêÕØY@›ÿâM×t˜—»ÐÑ-Óùü5?H躛C·²Êù»ôhf4|3üIÕ¿‹pŒßh8p\•^ÙOÄé'Ÿ ô.ap/ž8ë4GG¡òè§ Óãгº¤ø§�N×?Zâ–ãŒózæü{gûÄÇ¿6‘Ô/Ï â±³¡ñ²6^Hꇷ$'°tË]2¨N�!i6xi¼žñL¬÷3F›Au4+8”bÇcø¾#BBá(–þ‡yëò9AúVÔã w5a*�k—˜ðnëi zåݾ—ŽB± N­É¡Å©Tì%RXãy.úµ’÷�Kàñ.p¬W¾`dšÏæôååÔ¼àIåæ„�¸ºÁ†×”ÌDñ!Uv6…ó$½!À^�¢§¾HÃÇ¢¶_÷- ŸcNB“òX¾cö®*Ø=– 5RhQÎjzs}÷ú¹�5ßi`cÃ,RÿC‡FuÂ|Åà ~žÇ²)°ñh8‡+ºãüO«aȶfòÛ> 'ïŒ=Ïï¦u Kб{´u«cß Xvß'ŇngPW�j_ªf§ŸÕâë~}Q~Œ5¦êPÊ83p§Zá¡f0î,î¤ûf}ñgS(ÛxžÅç0û·1ý~¼’wçU:zÝæÖ~3XÿÑ>2fï¾s¦"=±ê@9JV`Ûü£—QÏ_šÄž»[ùá­ L—RÆè�Ò(·q¯ZCSª?Ðÿ…cLZ<ÕhµA`ÇqOŒ‚ ; ËÖý/:ÂÍ<¸ëŸOõÙXçò>7é•�vy¥Ï:L'Ÿš¡ÕÕÞ´4ñt¸ŽE*‰Åb¸À»!‡3Þ|sX!Õ¨ìeË+ÑhÀ{Ê�ÛŽ_±]°tpã¾±  wÓ—ÞYúó¬„óÔ–qO¸]äÞÁžd”*‰ª3¯Àéë0ùP¥·€àT%ˆ—¶À¾¹®¼üÐMxhPƒ–™bÈP3QÞ9Ͼ¼ÒÔеDŠßvÉ .™RXZ'�§Æ¶A\ÁNÊ�=ˆ³r?€Ü]�¶òá°+`~߃ð;}®üÀ‡oþW/­ÅÉ·ux!$ñú”,l˯ÀF›�<¾¼RÖØ™Ãå€7µdóðYbŒŸL-Ë�vŽì1ÁŽ3çpÈwXU¶Œž·÷%“§.<ØX±j YÂ…ÛWpH‘4_û/’m?(²‡\o~+í�~wÀÏ…á€Ï2~,9ÜnÍÉGbz¬m½š �;b¨®3œõÇB­Aëß9üä†1ú\Ðbuö)àÐÏV4¸õ":ZJSõ¬J>ÿAüÁº8¿Ï öPm"w¯N8žÉ»`Àš„ŠÎlMþmÒ—ã_•Ú¥Ç� ë>£qàžýpùÈYÒ™0EÈ>�Gá§EŠR¸Á±þkqzYz¶â'éüÕäê“2˜°r"Žª5å'Þ=9w¤Æÿ+Ç ó7�vìXl]BË’Y¤x[ùL‰¡Vÿ-í¦É[l²(ž�jþN¡ÏÇbØÏ\j®Éìû³—Äaû½KpÌM¾jæˆrò=9Œ'6fà×Åæ|ÔËœíOŒÆ0ûúÒáÇ¿]Ê`¾²Îûy.ƒ¸¨}8e�Ƥ´ù|F7ôšÿÙú Z[¶‚Ó²Í$ö;…¹ú<àÐYÔ-ÐǾ¾®h«+LØ6vŒÕdÛ¥CÀÃq>û9 Ùĉg¬|'s¼A~£tø­Ñvvƒ˜‡óëaۻϢJ©"vNòãk%3ù!£° áT€<t¨p÷ð2Rz2=É…ÓÚD¯¤{¢Ê¤tr�.€€u—…8SúRñ&]’Æé2åKö’WÙx: h ϧƒÿ×vx~ó6N8µ’WžÓÐ1xß3�òäËà@xfUJ‘y€?JQ„ê��SL]i‹ª±QàY=­x­ý8 OÓÄöÏsÈuÃñâoYÜj.zÎ'"÷x’Š÷tkW–­Dhú%Œ&ó¶5.BÕ…�ðAž[ÂÒhÝùdv4¹K®#rkìZz3/�–y¬=�8jÝJO¶¥»—F�ÓÁ"˜ÔÀîû`Íù‡B š@ï�8×ÐŒ_·7Ò°Aº˜©¼‚‚èº�¬½­o_qì°Ù<¼v›Çš€ßªxü–~Å»ñW¯H;ɯž¼ º�.2ãçdÉĹßëáÛmªhê8‹4^ëâ웩l~�F§%Š›Lܸä\|ŸõJ¸�D¯o,@ïÕã˜ó~‰ã¿MÅ3K÷ÂNɸçJ.Žœu²ÇÍ@‹üDÞØ Âÿ]ˆ K™C+&Æ)sœ‡”0Æ4Wüye®Ó͆ñ»úRpL0·} .ƒâÉgÁx­¦Ëúṵ̂ϳh(­{ßã =g( ó;7I4ꔥKq3áRg7L�Ø€ÖÍש<Á¨Eogr�ƺâ(|½Ðm×É&ya(W…½¦2ß4Œ ŒaQoo’¶Ä!�Ì(àâOP¸€Ú6Êx_~šYæÀþ‹?‘ÇuÙÞ°ÞÆ+ŽõÌÆë—©Æ�¡¤"­d÷^ µ8Å€â‰Ûd0T�FìÜ+ZdÍf©)U $Þ‡»¥ËXcm ï2S¦¡açIº0‚¬ÿmÄO~Á4¡iåçR86òTÌ? �G$a/¡žîÔ¤ ™½HC÷¥øÍÈ &ª¦Àý¡tM&›Ç¥€^m Y\‡ãæ ’n` _@éKÚÉN»NæcuĦ¶³ðÛa ¼n¢iÓ÷²ÿ¨ZRÞx�¿Z§rÑÒE< áuåÆk?(Ä~œZ_ˆ5 °öz'¬>#ƒµ)éüʯ—·Uf uœ<�tÚN¾’¡´{n*ÕeöçÍ&MkkÃðÅ2K6 ¹ óû­ã¹FaB�áX^¾(5Ç~\Û‰MÉ¢Vù ¬©xKX ÜWD¿�hqЇð)E„K¦fì´ÿžíÌM|I;²0‚Ï/ÚJÓEÐiº = # rBÞjÎÓ.ŒÐÒÇ‹½OÚÑè76 E•OC|Qçö�T›ØçáEhx=�¥Ç/äÚÈ•Âñ¹qP½%†LÁY®qNë)!lú)Šé°ç{s&¢Ù®ÕPÑ8Œ'Ϻ!”ÄX²µg4;x ÅÑåÇÁv¿<è¯Â7sWBÒgJ_t…ºÍãé¬ÐLj6 ´'ew4Ý¿î–Å‹;œøÚw`ó>¡pç@*m¯®¢ÌØ“d ¡ÏóY5óÈFÆ‹”j8tL'}&ã€V˜±ìÈ~¬Æ%N«ñ´a NÖ{ÆEe¶éFÅU¡yË*6çPZ¥z”ÏýM¦Qw¦Â¬ëAb¨ÃMl¶WÀ«¿ú®¼uH<—GF…µb‹ÎKqâÒ£‚ãºIdjÏ5ÇŽÂ^µ4Dû%m]ï"¬‰Sâì°T<*½qòZ0Päû<ùmæ{°ÿJ ΪKOKÊê�ÿ¸�°[,"ü…B‹h²’ÐǵÊ%äe<§Þß�ïÃÉgFÃÍÏÇð©•%(\„KÍòð¬j=Ÿéê QN¡w‹Qòæy8=ôŽ¿»›×>�¬–¨ÒޝCŸÀW»C|I>—fͬ!�\]Þ%U ÚŽá^§ÎV®æ´üÙ+nÖK×øœl5W(f ©ó-XEÆ £úf€eÿrª¨?I®qß‹ƒp\3Ú¹U‰5;~ ·âè›Rô­é ´JwÁåál˜ððèžË$¯�Ä~¢#‰¦+°·Æv1СR³ŸÏcX8#×9�µ ª&õtë¯3÷’žÆax³õäÏKuþµi®<8Ò¿¤µ É|ûi74VÞÀL÷û”9â…h¦p®ô¹Jgåqâ¿*ú4¸7¥jŽd ÇH8õ/‡~ÿM i‘‚ï=·*ÔൕË7¬åäþ§„ÿÞó<ÝYÜ8džº¦É±ï¨6T/}� +dØ{Âb¡Ÿù0ÒNžf'ý‚¶ÕýO΂Ø\úVÓk$„µ³Æ’…ý3°dËÊ–QxˬϢ×ÏûÁ0ÅÞô©r#�?ñ”Ö¿Žƒ_#¿ÓîoÎê8G®Ö'¹ñI3µî�á™!£h}ô>Ás¸…àkRŠ!A©hôJ�O»rôy Ž<§… k¾�jùÙ2}rçß—èMü®=UFJ¥0'´”’$ú¢¡¤Ë^܉†öŠâ»2/¬=¬Í†JávÊïÝá΄eóžþêÅaÛÓáÐ¥Ïx3¤VŒ¨è còÙla§xéù õq7ì|MW;Äû_õ5’l|e*?XÌw\lY·-Vð_°”Su-yAÉDpå²Pÿý†`¤4žS.ï!Étj+‹¥óû`öÃ�¬ö¡à°­XÕ7 Ò~M�ã’hTNµÝ3ÿù”±!�u–ÕÐ[·ïàëfÌq:¶l¨8†ƒüÙ9[•…ep°m©=¿‡WVûÙmÛœ#þ¸¥…ãöTÒä9 xlÃ~,SZÀÁ Ý�ì+�ù?.Ò1KîxQ —ÚQé_o>>°„¥+í0ïË#**’C�‰¨º=oa �,]¤�ÏïW@zÚ}èÕTG–±æ|R±="†Pv´ºàÒ ’·‡óãHn« É_Jë>Â×EÞ¤hMEo>Áä´Ã ÙkžZÁÁx²ÿÞpæTʼnþr<®®´F7Â8ã½`â{^˜w÷ ÷ó(ãÙkÓ ³V�óvT²ŠêlÎ^�ÁÞ‰=uÝh3ï‰>üu�«ºc¨´ù2Ì—HC{ÞÕli*7Þ_Q±ëf%æ=<V’Ö|DÑ}G!ÿ�"xL•†RRd%ä¼o§”âb8;}Ô�ÐÍ{;¿ �z(ñþO©<úZ4Ô·GÒdCw¶TÁn†ê<;<ºÁñ�ƒð × >Ý0 7Gï)ßZ>”}¾—’SˆÿZ¦Jíû¶Rø¬žÞr7Äxs;LTIa³kD{cù†Ñqq¤æXž²Ý�‚ÕéOÍjÚXà3¿wŠ‹�Hw'¿…¶‰ýqgÈJ=ù’êSzÛ—z§PЄ@4�­‚'»P­:Pô«ûW~Üõ=KÅ2âïì:í^ ?o\#í[ØÇr5gú�bšÃqjÖ<[ÑEë÷Σ?àCe ±b€Q³pu»êK•¡Aâ.:j›Mû÷©PËbDØjªÛ³<Á ;]°s^</Y "ŸÛ=|.Éœ"��=|ì÷˜,ËN ?t‡£_`:<ú�ãNåòV7>{ྠ±¶ŸwÄ£KÒÂÑiÙ‡înÐǪ1liŒ™&fü¶@žÍ·ý/w5î4(®PþOâV ôËeöih¡ TpÐèò÷>�*µ…w•¤ÐˆšÁ°1-Œ¿5HÀ­Öõà7]°;5OŸÇ“Ú„�¡ãÍæ•”ÌíJ!8n‹)Èm߈cr넽�|…ºCëx¤Æ1»€ˆ9| ®6Ú§ û7‹ò¯ yÙlIxK+—š`‘Õ3ÚuîÑKx×wyü›“?ær„ÔP\4þ0NµB,úUA¾'Z„Ú“hÁŽéôíyîþ¦JÛäDܸ8‡½Õ’±êdØ½Îæ ßòEçcNÜ,oÆó®¯ƒÁß„„Ø� Y‘Hw6ßÀ’ò—4p²±­£îYv�9™>ú=!ûèñŸ?Šœ�öåù$ˆª0h¶;ÓKÿÑf¬¾Ë�ÃGÍUOaCìL~^�OýEJÉ:Åi+GaMŸO4bê7‚45œØTLus�AâpL Pª¬Û´isL¾ªº[ÃÒ„~Ü5d¶”Èqkh#ÄíÔÃ^3 ùüÇ]Zþ‰n‰z|8Bƒ�{ÕUf‡½‡†ÄÕk§pý?ò�ëÏþ•ˆº5f|©ÌoMÃ/²+ÌÖë _†¸³ßÙiÔ—Æ-íÔÖ8}jBPíjQNHà!ÓÎ ›4ÝàöÒì ²BÎÑLv¤´Ùq’cÑêŠYBtÃAúžò\èµ^,ܱI¬Û²LÕyÐË&Ð}R(Þœ~ ”ø$¨h€æ[�08p2EÚHò¾5Ú°†oÑ\zÕ–HR‡ð·â%Ö¸3‹ZN¡QâlI�’Ÿ[Ùmý ø–k�Û¦‹*g@#z#Û¯ëOçr$XËoÏÏÒ“$+àÕæ » G ¸Í }4ë—ö䬥“ö‡mö�­Î >ÿw¶µµÒ]ø:ábiV4É®®�°ŒJ£Pmv¶Ð¸…ÇhzM‹ã¿õ�sËæÊáöÆÝbÀÛ¡¡ïô™²æxIAg³xwz¾Ðß$œŸ‡%Àóíæl0§–îÜnA™°©ÐÄüIÞ¯8õ¼õŒcxW)Ÿ˜Oå¡¿£`ñ™'´(Ú§ed ³Ô°3°:É,ßœÖâáõ}xSd *Ó(Í7›–D;Vhƒ±£2Ï5¹+j¨Mã®/öl´Œô „¿Z÷Ó"ØñS1}Þå ÷ÂÒðëš$qûª•hùÀžïñÙɃ1ÌIA¸¿ºÕöDámxUt„Ô¼L†]ûÛ‘’BýI]F8Á¤+÷ù‰Ñº´Ä û((âÝ»CìÔ{þÔ­›Àw¡‰ð±�hÄOª…ê-•Ëšr9 ä<í¾«Ì›K]m F£°ñT‹‚nY¡h1AV�ð› §抌4LSÔì6oEëÏßiúnÞ0ý-Mø\ê‡0W(«–,Â�î2p†éŒÛR|bƒ¼>!�iíŒ;¥ñ¢c‘Ýóä:ÔwÌfÝ€Ïâ×ìZÚ�gÌߪ+„*Íl¸Ñ~TÐï23oÂ÷?3Èwh ν'* Žƒ¿£bùÈ‹"²³�„eß�¹Áxø$aýïetµéŒŽuÁiR¦8ÖFÍ>ú’²|$h©.®L­Z�dg g}5üNU† =l}Ðc6þÀ ¨ê¢…±ûöâ’iÞ]TÈ 2�°©# m×bEgN›=‚—ž]­…µ=‰g7šŠœ¥¹ °ß½V±áµ'8¸æ’MßX ™~JbðæLin|zoWcç×pÐ.Ü�ú—ã1×k1 ¹Á«[`‘§>.ù' •ê×NÄ¢ÓñRü¬½5ç¥á‰¿Å2•>Ã0~c5ôzIÏß�‡ã{½ ÿû¯}7Ò‚iÜëK=Õ6"‰h–pžŒQkJöðûxs³¾Ù!‹*gîÀ_�4þ Á&´‡»b—ŠŠÊç)÷d(k^‰ ñ]8„lƒ.s ôY ±� ÐøÁ21|n!쮫ÃÖ#îÿÜ&¾¿5 â5RΫDžõû*”ýñ¡cáa<éâHýÎC¬0po/>OƒÛ&Ñ3ÏG5¡ &Í¡-3‡³ÓÛÏ`+KSþS¦^ ½yšîú}€:ënž4“¤¨âl¥ëâ½Ñcxzˆvkhá"îßÙŸªâé{mqe°–,oûbõÕã°ßËk•‡kT˜ÏâSó%Þ_¹*òçÔDîÕ¸ 6? 9 qÖš›¼¼ù,n+Å?›+ÅÖÛò(ybžpöÏŸÑÌsÆ¥Ó¦¡cÑ'5!  ²ïLýn/§~5WĽNÇÈçH%¼xæÃC ~Qìå|°·]šKš–ítneøGÌÁ…‰YdvÚžºCž�Ž­å.‰”¿ÊUxÖ±G�+ÖŽy¯_Pbðd>¹v7þÙYó§$�ÏËjò,X„ÇÏ:ÂôÜ×´âð4ÂÑRWÌ_c¸™½ð}kR噿FôÛ*[´�ž 6®»è²‰ lÝ ¾�¯¡'šùFù—௰ãMÂÒ•s0ºx:¿¸š„l†61nöq'¹¯úIe÷]¨õÙm¸{7‚fÆ^%KņÈ*ØiÈm‘f¬83•34xVÇxüpö›0rdl8(àÊ~Ê,qïY9Zc×ÑYpážü\|âæ¶T ŸÊ_�Ý1ÜC·]ÔÂÒ¤�´®v#—úG`ÐKp˜wˆ&èIP[›+}X¿>ÿVæ’#ñ©»¸&$±®Õ:ŠZÆXžz’”5á÷EðsÖ}î…"¥¡È.–¬<–b³Þ› ·²¤yÏýC4ñÞS)öÓð[$‰Óº¶Aiÿ áɇ=x-PY0š_"�ÿ-L€=÷Ú vy IŸ>úö&¸n²6§Ûá; ´Öè<¥Þ;JÑ·ÕÑ·ã²òm9Ҙɸ¡ºX²$ FÙ¡ªà6vØ'J’±Ùc>çÝ Æ!9(9¶›½s Ýg Ä mß³0mÜka|þx¸çµ—oøÛÓçU;Q[rÎè} ºÃyJA/<¯2 ]ÈÝú.4��໿磡ê=xÚí…“þyàÄv ¾à²”�]LÁìmJpsŒÙxgqYît!ZAý_Es›q!£"ð�»&lð\ í.* #šáõª¼;ù´Ø2=Ax¶#2$’©:0�Ï�Ú�õ½‹©pTh%¬ÃÕ†Ò¸D�îx]‚U¡' fž� ,Yö˜Nõ7GsG—*_-Kc¿è ò¸]Åï<$gƒx˜¸ê<9Û‡%ñIø¾[ƒO§%cŽa ,:ª+,„¿;qV| ìîÛ7…>¥�ÙÁ${åN4˜Ê¶ûµ8%Ç“OÞ %¿³wi~¹0£µZ“$°jûBRÝÅn³Fâ¿–l;s"š4¾¦gÇNÓ¾Â|ø<ÿ þŒ¼Cf.z|·×TÖZà�¼iÙüÚëíÆÌÚáxzJøµ]€sáñ€K‘Øÿkº�¼Në�æ¡ÍY|²ø~ÚÛÞ›W ¨ûœ ò'R¸[›`{?�¦Ÿ"ÿv+è³² ¶«Ê¢ãÞr8Úñ€²Ú<éÝ®~4Œyú‹ Ü¿üÉß!JtxÒ­iqèÞ˜O¢F‹'ꣅߣ4±p~†'—A’s8¿8ÇW¤)�‹îÀÓ*#ž:y£w>='‘‡÷?@¯—Ñ»Ž8¾½s¾¸5j?-çþÿöÓû¸>Tºõ4—› D�y×E‹Pcü¶z ÈOC¾­Ô›Ö]æ÷3:i�¹�X®Ë>-àÕÇ„ÍäÝD•Ûæ|ññqž¾l¶ÊÊ¢iÿøà±,Ju/¸#‹Irö\eƒ ¿¡ßØ7âù÷a\ò[�k)–fÿUÂOx«rcÂAj É�w×T8NÓ> ³7¿£’S¡éÊq¤,îçM ÙÝ�ا¯½½Î{hcV7‰ÃKÏn ŽÂHÎø¯T.§à£Û�‚Fx¥½"‚k¾ZzîžÏ?�Êéè“mؼi¸Õ©þOÑy‡sõ¾qeïQ¶¬ˆ4…sßRŠŒ4µh’†öPBd“Q! %JhÈøœûF¥¥‰Jë[iˆ´÷þõûï9ÿ=×sÎó~½_×užëÁcÒÎôûS¦ÚùQ±S<ï§�ÌÖf\ùëÎ+oëá ïlgu–Î÷˜ÓF·ÐÕ�¨sö?¡Ã}+�~Ó3w]§•;Ìy7…�Rã#y–ûðQè½-]¨10�Ÿ¹dðÏó^ ±æ†¹�ÂC‰O9þf.®Â•Ž;`lå/°yÓB7NaÉÆ}ðº¼Ó0{v{̪&q…Œ,NØ''sÚ •�=¼¦¢ˆ"ö<>'¸½ a¿ÍcåÀÍÊ­Ø7ë"ôεÇÈß“ÉÂ=Ü~f\ú/zÎDµwÿÁªÆÍxÊýœ›eEÏ{V�Ú�ó¸ô²Fö_êžâŒõ2`Föb�7 ߘiÁ辎ìm¯L¥ÕÇùšµ5´¼»Î¾âo·UIaelMÚÃßxzV޶;Í-1ukï^á w4�Þ¹-¹ø‹ rTS0_ÝjÁ~ÿùÔ™ª„•qiB¿²hvpé…+-‹ñÞʱ¬+•ë/\£m³† cŒ&9ü›SŒ2Áµd O9Ùy˜›6ŠOéÇ€F¬*�ëO�ÅQ<4OíìéOêXöSx O££×Q¡vâÐlØ­jÛ8lD>Ïqû ™[QÎwœ­XuR8E¼Í£Å¦óèL½l]Ý€JØâ|’:¿PïKɘ˜>“޼VâóY§9åüwª>fÃÍÖ h£Õh\2°œTp%Zª<}»šÄ;ÝÎ ÿëß;ûÌ“›Å›Wbñ÷Ÿ÷ k�Šy†ÂAj{,¿‘Å-Ò;iý÷�âŠÊn-²~´WY™CŸgZjÝ»iÏ‚ûÔc¿ß—TÓªkK9b® ŸY½šm_pŸˆ“f†2)¼%ãu VçOÝi` z}Û3¡*e!Äð“§zâVó0<âo‡�ɬãYLRW](¯—#ŽØëۊׇ¾ã•W*¨|ì1Ðjd·„ŽŸðW5˜{o{K'ÏdòÇ™a•�(nºò~Ëpºâ<\|æmÕ'‡Óq¸)ø%ä–‰&JG…{Ë*yüõ tÞ“‡Ÿ{ZÄ!½ƒàøÔ(Ö  Ú:ýKt³~ Xh‚?7Ñçÿ‚ùs¸¼ûÆ ¹ºÕ ê8Øo·ÄÉ3‡ùâüH-,2,ÆOO_ÂÆ¹§Å[3ÚÄýßèõ&WˆC+ÎÖ^ƒÝS`í¨vÑ{Ð`þí:šãŠÆq§�;o/å<×=Ü¿d:XNËÅ_õz8{í30¤8©u»dÞk90ÖÈYNÞ¸êÖXÞhEsâZ„/Êqêºîõàý—˜§‰ÁÝXià“·� e¶q±ÇÉÚÑ#KñÏQL�Ù^{�xgT/Ô{T�Ï„ãmÐZI“ï¿ÞŠsÌvñÅë«ùKï4ñÐvùÿ?/§Ö‚óÿÏ57AL¡mi^Æ]áÄËFÿËÅΚ�_dmxñ*Œ{u…lý©ûÃ}ÚóB›oÇÿ!ÏŸ‡à¦É&®ì£Á%šƒÄ>ïû‹=Šº\®ê'�Ã5|ë•Ë ¯wqɿƻgÄ5š1GÕQ¹èœ¨~#…†o•–­`<êÌï{ìºì–¡ÏÃ6\î2‚FW+sVh†«Ú  X¶ü¤ýë²™ïFà¼'üݸ…\Ôõð]Í[š—Oítá¿[¸ÄõŒøw‚zô¯„g†óÀß<u>·PÒº|íÁþT|ïYÅZµv±ª²žÿ\>у’ÀÑâ=Ó×ç[ú bÇP:4*ŠO¿ù fУaDŠ&ŽTýJ_Í¢ K�g1[˜ÛOóH„‰ tA.7¯ù)ŽÕšÆŸc“]áoñHO%Е 'ë3þ;–×¶ÉñžÇId®^Lv7—Qfd;Íxá‹_KŽ�¶q 4ÏþJE÷—ó ÏK8ö’޳Œ�Æ7KÀKþ}ûbÄa†ƒÃÓ(±öUªÇ=º Úžd=ðþVã–ýv|Ty}Üa€[N6b²‚HîîÀ·®îçék�ØJæ|X4W̱}"¤NJõôfº}ñ1íw‰£—ö p1ÉƾïKmÇCLC¢°ÊÕ†]îíïq·H>5›Â¶6`wf'ÎR�A»z‚ÓõŒ&Å¢¢0�ð´W$VÿzMÖ&—ᯃ ]©bX­ëÌõýúòÀ-¥$n‰Ä¨½¹øj|>ã—�àQ^Ä ûg`gc˜�ýäK�þt+Ô”<€7¡2=½Vr£©îIgü–¤…ó`ï]üvø\¤¿^ÜðÒ–Ê‚/��­'Õm%—>“ùŒF7ÕœŸÂ’¦³�䕃x©/>ž»›ÚRÎÛl\âåÊ g¬Â죶‚•æК§ËâÚÉìat&Ë áåÃbÅ KLübEŸÏêáÁ×î ›¿W¦›b¾²Éo­Èâõy邆•šÖ£N}×t~:ú€°p¢>¹ í÷�ß|wù=xcø!Ò5ØFìQǹûÙb‰VOŽà‹aáì}µ†7oýÅÛ¬qÁˆÍl>)ÖU4ƒÇ�Û {YcäøÀýšêû�®\Ù£Íx¾36àê/{°Dy?ß,›�÷N’Ç{-Þ1æ3\Ì(££¶v¼wP¿ö;Ⱦ9ºÜ’nŽ_÷\ʼn­ç„?ɪh5Úƒ:~„sïm0|€ î·œÉ-·Ýðiãe‚³xìðá|A¬_g™à©3yóŒ2È­ÏÛ÷˜×&¿ø22{H«;›ð®Z¥Î·¶™ ­ï#Ø^æ;5ìÞÆ>&?áfÎ�Z½=tzç,ýà ¦¥¢äÉqþ¼Ù…K¬7ò ”3ÔoV«˜ó!éߺŸ¦héjq¹É_ê“¿ªäK$Ï2²Êמ¸mýqÜé·ŒWÿçpÃ�+ÖMàW´¸Ï‚é<ÿP$üÝ<Fl¯áý.¥bst¬ZqŽ>9L›.íÇû £x—sn4©³ñä=£hùi]þl=Ú­t�+)°ü¶TÚÚ€Qý® œTÙÂñéI…á–'óÄ ÕxÊìÝÉ»ÃÇáéMúÜ59¬˜±è´^ß7¢ Zûp¿áGÚ¹^�ð„¾~¸ìñr”÷�Òþó¥�WdxÖW=XðÔ�ý.M¡EÝ'…sTÉã®cŒî ¾‚‚?ßãôÀáUßg°q¹‰x;4‰Û}£)ì¥+HåÍÆÖ?yôÀ¸ŠZŒ:$ø1]ý»ií¼�4ñ)|¯HÀSGè?³s0â‹-/}X926.Û å…[…½Y'¯X¬ÿT$$öÓæ·câØ*öõúœ�!}`ÔxeƒÏqÚì{ä¼²”Þ«÷WÄ¿ öú… ¤ÿE⡚��Vðõ“‡8.ô yß æ<Œæ‚ýßHc�¼¤"ì2È%å‹g ¢�/þñüÀ!ÒÒ~å© H�¦y)E’øãÚh{]óüVC”™¬)ÀôkøHëGpا�ß»£ÿͳ—'‹PtMæ �XÚ¢ùÜmü®›ðc‰t]×éôn‡/ZàƒkV� Áûj¨aB DåÍøðœ|Ðk Ü^ô½¶í†:Ͷ'çiÆ’7éÓè“ðR°™²~Žø§ Ø,`϶ì‡�oŸóÅvY|žÞ—ÖU¼¤… "Pîí{°kî)èxL‡ƒ¼ N¯û¥Ö…´@º œƒýÐòÈ.‰ÕÌn9âÈ“ö¢äW ˜_]úÏwg€É25JÒ w ™ùC(OÖ§›nõ`¤ˆê ¸öé61&ñ4Çœ åÉ_ë(=R>ÎñBô÷½àp]¤/)'V‹Sle݇‡;q�ßɸYm(¿µ·à¨æ¿ÂÇíù¨—H�ÑØXK樀©î¥8a?ñÎØ_¤<¾�6Ëöb3½BN®:C}¦�ç%>þ 0e«Ç‚óíd)=§ýTd¯wûöų^æ ,Ÿ¢*žãS‚U€1,mˆÂ“ùz˜÷fôß0„6¿„c[  ìE<šïÊã{7àø°wðOœ¤W ,•Ý‹¿_Öv—Ù…_ï‚9^ƒaȨ6*«Œ�?CÖž\ñFq†äÇÀÑÂúG^üßÛk°:¡BÊ«ð®Ž>úÊkà£ñÞ; \=6‡Ô!Ü·?îÝ3TLL”¦'eOà¦U3l;(C+rVrXÑ"–«Ÿ�ãý 4î Á�pA­MÉýÍuM¬ùr_Üñ – ëÿÐ%ùà«WLYm©üÆ®F¼»‰o|�mcBg�©˜¿Ž]cÜž‚¡3À•p©�FÕüq3:•¿ß½IOGŽâ+†}%­Ÿäñä±aèñ£PÌ}Æóÿ.áçÒPíL•˜ò$QØœÁÓMxm¨ùþëDÄ#Tã|A8µÂËË£Ý ZYÓj$“ù{0¿7ãF$‘QPD.lâ'Ái¼ý`èûô¤êŒ×°=Ëý†”]ÿ}k¼Ë²åkùæ»Ï µ0žgC;ÍZ}œŸybŽÿ65ä8n‘$cʲÝx/Á”?ð_,¹z˜GößE çæ²Âá©4V+ݽ%Çáž|wãÖPD^‰´äÑAü9<·qe¯üŸü¬cšXæ«ÿòý†ùø±Ë ^ òÿ:¡óyuÞ`ÅéÁ3ñJ�ÇçCÒ«hÚ©²3ú$дäSÂnÇ ßññT=Ö•ùŽ~ÑPÌæ|¢ý5}ƒ^œ+8ˆY>xòð-ê É$詃®m,&ÆZá¸Ý·„'A±¼Ê9þ_‡”‰.½èÊø¼¾Ü† k‡ÉÁ¸×r<© »’âèÔÄ8nØò’—O*Ìû~J¼s!ž¼3aÕ?ɰ§*š½4ù‘Ž÷»4޹æ. ¬ðÉêTÜ©<Ž'Ï×ÇÃ#RaÑO•ºµ§ðÊJ|Ù›/?1 -c¯Ã+ó¤Néœ^…ûô¯“N½F®‹BPý\KMQƒ ÿAeNÛå…%$Óï ÆUmÊd]QF½�bqưá8ð<ÑîKÅ`§µ ‚¼1g”ðŒDM6/Ä_툎tH³ì©)¬ÚL/âVQ�ÿŸ£‘?Bªã~'_E›kÆòí;d`ïÀ}NænÄfëݰ¶´ŸÉ[ðú1œ£¾ ÿ?‰ËrÐÕ™‹qñý<êøp™ýt>S¼ºnJ8D×ÿuå¡AâÏÑñx CÏeï೟.@v¾š vŹ=B(Nc9øQŽ …rÖcž£)ÃOÕ)äø\šà~TŒ­ðçz­âð¤jØ8Ú k¦/åάVÔš°Þ,ûµn ݶ9rY>«Ãíñ­]¬šy‚.z.G|qÜOÈ ®š,žå[¤ÝU O‚P‚?5¨`� ø�Á¶ˆÉÜâ5†»Ô D÷·hûb7]m”ð¸KQüRH§™åÍàî”Èï] Ùb–�hìÖ‹&($Aɲ˂’w§z�à-”È–…í®hòv!Ïñ¼Ï½¯ ‡‚ì<¦±Éh~c·ÍZÁ/VE³¡�Î=4V�òô,ÞvRÊURy›ÿuZûÌ™ë°�w¼I¦7]{XËx¸pÞö—kj§ Û�R¤Å;�xRoŒ´åå«Ý¹¿ÕR<ù¨JX²m*™Žx'Ž79G|W`\Ê%ZÒ…sFþs ‡Xá M¤ûwðéÁÿ2×gŽPb‹O?špšú{Êñ2&ýѸîÜvI|¼Ä­w—)K|›ö ë.Ê· ƒù?#PŒïÇ«ŸÏäKcÿy¡ñ¨ õw »oɱ¯Æ¡ü²P¼6•IÈ¢gýºÄX—F,;<WuB�qQÃ~ÞÝ‹v�©â†Jb÷™‰Þ{ö—Vç;Sûô#QÅç=•瑃œ2'6ËayÍQÑÀø.鯠•ø�Ò§…à§ÌÚ #W,ÇðÁL[í4¹f¹+ZnOáÿVçk£ùùÁ_P\o)Ö4åó£·«)ói Ô�#K¼ðZ­^®¥€–Â�Púü@™W�´D�ÔÁ}ø Ú¬Á>¯ñˆ„)äiˆŸ�uÒ¿ÝZfLf‡ur|×ô)û.Qü÷}¤ãMÿTq«ÇCÉϰ!°<}Ý ü ã«Eˆâú…ç@Q^‡¿˜í©KصÿpñÕü¼Æô‡è'u­}öðû=«ñÉ÷³$}@B›-|°èÇRŽß³RvBGQ|["‡fn¦bŸ…V,i{•vBÀËd· gŸ 9°�’)š´vS@Q1ÕNŸZGþƒ­8AëÉv[›&Œý“C9é¯ÄW³£é¿˜å`«ÑA'çõp? aÅžÞy±¶½ÿCq3ÎA’÷h¥àïöÁµ6‰÷Ÿák0æ¾4eB_ùû›&?n…âÆ”ö> Ef·Ö€ã²ÅØÚÄk\o Q =¸×-m#ìÖ¨�üûiLñqœÿL‹K/§ÀÖzw>±2Œvf¯â0§m6ó-˜šœU¬ò±ý’!7Ý>Ê 7H UnCžu ø|Œ#F¡0¦µR’oÙÓ=7Â_§S4*Þ�Ïì\ʶg’qÇYyî-ÔsP¬~n  ÄVYÐ <�Ã*6 Ûä 8©$™Ï»á £¾¸,ç¬Á@t©,,÷£…·þ; -»ãù×Â|޹†ßŠÂè?CP>,šÍü;è÷çC¨ùu¹8<¨�ªÏàœà9„)ž¤Ù;ƒ×ø§G¡UèïŸÌ×¼5±à¸1n{]Œƒ,ÅËv‘h±ÌßÞÌ Oþ À¬ãÙÿ¥7ßë!ðæVaX¿H¼üõ0j �Nœ<›Ö„'Ó+Ü»h¿Ž5gKK >€v÷ÛŠ3ú¡A«-öìœÄ÷êŠËÎí²ö$ Að(¼_oê‡åa]lÞxE ›wÊQ?¥a¼4ê0H¯øN»lzb²yx-U¤âYCx|`î6ª ‹òkø�n<_|–þêmÙ‰ñ,g¯*˜…ˆúV)lWNÖY�îÂd4órÀ” Ñâá‡o`¼ÜW˹‚ƒ]çÜ ”õ™0)W†Ý:rY ]H-Ò�OŸÙ;¬$0ºû<³æ£þ‹Q¶X¯iê±…A#ŽUÂó+S¹lOb0x„ 2VhéÂâ‚¡8Ã鈘xDx›sG¿¸[fíµ×fpÒb·¬wd/‡õÂ4ÿ~¬ü0 ó�Wy„cÇÇC´Ô6ݪBx·Ø%i³§°B\ÒvT2h³ U[;à‘ŽÑøìå6r[Çp‹p¥ÿ)ø~æ4[ß4¥�›_Ó.Õ8¶�± Ö-u £…˜U=ùà„.aý”à LäK¡—xñ› Z|}züŽÅ]$/9·( û¤—òfϧ¼Òªq? ¦¹N|¼z>^ûN8ðù�¨ãoÂMãâkØ"y³ÿ<5Jñî�F¿ ;e|øÔ÷!\2Þ”¿ãÊé:ÙÚCXöP§g–À½¨T M�$ƒº8ãã3Áð‰ Þº#àŠe2X–Þ‡',Îq³•µå~v�¬íÂb?Ñ…YRuOŸOv•K#Ôív£uvä¾³/Ü8•*Ê�ÙäT» s§› ªÍØã§*ÞYå‡/=`¬¯5_”ס[a›àÍÔ…ä�ýÅÍÒ?…¬Ö‹úiÀj™µÓºn¸GjðnÇ@JW:ÝY¯¡zö|^º•N9©âÄ@c¼Ö1×ô±@+Žëæ/Á}ö£Ùù¸¼o$¶‡î'Ïâr’òVžÔIÆ {è“a¼mm>9¬·rÿ5L 0@+ç›nîŽ øÃ�"rïx+Û…©d‹_4uyøÆí\mpjÊBñÖ‡û¾MÀÑë‚á÷í2vÿeÊ-vƒqûð,ñS�^îâri·éô©àÌút�ß|ùAºcôÑáùg¡ÿÓ÷DŽÇIñbtLYA”¹ Çéª2ž †279ø¥[/YkÕí›tŽÄ_äÅõ"<ìæ+yòžoŠ|*x2Í=3G7öÃ~?ô¹O?)VþD÷XãÉy`q�/ª)áÈM¾2x=~— D«ê /ŒÅ®CØ/b77»zòe—rÁ¤t4®5›Š’•ÙØ1Œµ·Wò³—t×4õ†ª¢»z^ 1&׫Ê<Ϋ ,ÓÕhí?®ôˆ|OŸ¤õű?«¹&BŸË¿†âù:;×XÏ·–~§‰¾ú(L–‹^×aóIgœ~e²µÆ`C;þ½è ¼«²åÝ%•âÚÐ tZf7�0�â¦/5Tó.˜},4jm¶×€Fv2휹²—ËbÓïQ,uÕ�Ú�Vç'áÚÚböÂNAªØMßDz�þ¨òRž[«Ò~²•¨ºÁ؇·áû2Ø3pØTÆW—|8¿â9dü˜S\�‚!ÏÀã}º[mN5�ïÅËG�ƒ‡þóÊ®×Ô}ü†¥%P»½"*6WBÛ�\:fŒƒÆËòrÓ2J? s†îg¥ˆOðXF ÕM·Cí¯_’½Šv³~)Dœ·á±ZU¢Ó«^%¡~8O4Xõœ¦rФ„ëêù·…ƒ`<ó�*®åWV 1I¥?8ö7Ùmu«º¾Gþ€>»5ñàì‘ø\N#ÖDãlÝÞþ|Œxá>£‰~€äÎËEðTûŽÙJ:2UøèË] ÎÏø{¯"ÏŒ‹f…¾ÍÔÐ�ˆ ²ïi®Æmˆ~^@Æi­¨?h4��ÁyŽIbõÜ2{#’@míy•æF˜»kn—qÂ;òA®jÇ�˜�G»þò˜‹qlòF‰·º Cǰ�né¥êÐ5e34Õ±§>ÿMáçòA¯"‰¤;è˵ž�§•Ž«/èrØhkþqGÇ­ðÆ¼³1¬�ÐZ}½CÇ£Ò…ly>ãó&Cò׈ˆ{#ôs.¼J�äE*ü@/‡Ê[eYG)B7¼M�JY·Ä„*,ÌøÅ‹DÜèÔ‹·t½âÕ=SHSZ–§xTÁñ„™ØÒðËÇÍäUšG±îÃPnË1vÁÓ˜rίæ‡ñæù¥¸·â"Ôæ�æàê’ƒÔø^úŒf¸!.–ü{>úŠÜïºÃ�Ò6ì^S .¢2»»=€v��èPÖLþC=ð§R�k׳^¨Þ•Ä…[ñǤq<=‚$†¬}©œô�ÎUóÝp\ðë‚b8<ðÍò›w³“oÁH>>âtf‰}[)7ø=μ#v=)3Ùhš™”C–ýƒÜ–Û�Æ‘nÛ`áÕC¬˜©ÀÁJtääjê[6…†,Ê RÕñ|(; Wyßã}éöÓEüvb›Pþô°Ä°h¬`úë'ùŸÂAŽƒyÈÍ[npÞ‹t|¥á‰4þW™ÛåÝ¢ó>vùÂ¦ÃÆq¤ï5˜öjöù^ÏÍ?ùyXøŒ� ¶JúŒ#›õÖ(L¦ðþ±¸NqðtY¶X²Šî¤ƒJ-9Zê²$ï û98ÑÚ—I‚m` ÑÿCŽSc!~³ ÈÏ>ÎJ)éä™[O«ê Äa�¾¼ejIeéº}ÿs“h_Ò–…¹�¯ê E¹—Äe¡«qäÚøy`ÙžqÆN/CÔÈþ »n‡>Þ¬»È†§m2éÌ"zbÜEO~ýÕÂ:<¶¡–ì'¢YÑq ¾iÒ›¾C…á#h õe­Ç+å^¬è_ b)Ÿñê�kKÉíZŠ:šMÆ]£I®¨‚®7ùòÖÁ0oO«ë¡¾^¨–úV,ï9‡�Y¬@yíÝtü“+}à‘ÉohZšº)Lý­pîHeVž …jjéYH3 ŽXŒ÷Záîjm¾ä�ƒõïËAõÚzü8`6ž™:€¾ ;Å÷žüÿþžUPX· MJã±Oð2£Ãtê»Z�UPW#WXð¤Š.…Ü¢÷y0àÉÐè§ÍïnZssÛŽ¯Ç×�6ˆ3x6éýs*§Û%´î”ëÛŸ—TõÂÌ9gá¥îM7@Z¦|LðÎù(=–Ev»² OÄb1Í~3T[Á?BÈàJ0K‚+ñ×¢¬:s -ãBêý1ˆ6í=.¶)­ÁæŠuGG‹=Syú¸¿tNŠæ–\…öÌþd‘u�§FaííEÜq8¦iIãŽ#ÇÉ×ÁÇæÏ)Å»à³×GålÅ¥çôÅŠ|_Ú³¶˜:öùÂŽÙ¹\ó/g¦”â¹YCy_¿p¾“D�¦3aÜÔO¢ÏœÁxîÂ!NXRÈn—‚0­�È3úKÐãæ>ZK.ØT¬O·­à˜Ùr¸X° Ö7ƒ¸®Á¨aÞðËœ�MÉgStd ín±Á�#v ‡y Ï�0¬Ž:ï­¦¤c…°$ Õcä܈ ñ¾®è!„¡ÂÒVxn0•O”âIm‡±S¿peGÕë¢å³Ï ÿ`ŽS-6 Óã˜�Í(‘{…ó^‹ò´/Ï~Av/ãÄÊÃßIðê<)>Õs eD}§ßýxg\?8²Úž"U¾¿G'#ìYqE,Ù ‚Ôã(”Uÿ(ì)õ…„‘qøŸ‹ÛÕÏa�Y#(ó}J/YÉ/êÕøšª)ìŸàfwÿ‡n'ì“<¤¿ÝÑøæàA~ÄpêÔ±ãR×8x×0�ç§9€ëƒ¡€óv¼ŒvÜ�#üŒ˜6«‘¸Æ¿œéÇZ_#àôáj›´�ºãeQ!M‹J¼ª1TíŸ ÆAÓ8oÏSö¾7…g>™„úšã¸@Ñã6Â7o ìáÇc�> m o©2,G-פæ{õøò…!¹,šÈÇF› ÚÇm ðÏ•ûç°e¼ çOŒÝ^XrfŸÍ·ÊšÞb×Ãàë߃�Џ'ª¢Á´ÝÜÛ1evëñuaB5ÔÝÙW˜~@oZ/Àà ›èâëG¨t©ÚK ùÃ[n·ñž&kðÇõ ÂÂ9}…¸¶Ch°v>ĽÙOÛóÛÀfZ²PÜ3ú~o‚€ÉúÜæÞMŽ#Z.Ùû6œ3" ¥á “ÒÁÇ%Tò›ïö¥Yg¡‡fÜüV›OØÄÚÉgÜ eOð– ü»0O¼!¿*3å1jŸÖ  ݧóxØ™pn/«â7²y-›â¬þÛpYÀ^”�"]: ‡Vâåó°iZ ŸS›Í]#¦°Ò§l½±[®é‘ÊžZhñ|N÷/¸Ñ·Ð³ÐÏú›|xî.˜Ë›j§Ðþ %4?n�Dþé"껨�}’ßRÞåÁ»3J8ís>°/ÖôÚÛ<Â%¡»v¾z6ÚigPut¯‰Ôä»×´¹É0W`ÏLê e×C³ÙǨÞ ïóýSZ]Ó|¦¢´[÷êÝ“CŸöÆúÄRI|· ß—.æå�-ðáOy>d<�ºFKø¿mþhqÍÛo›Ô]Yó \“ Ët!¢ÙFÔÛu¬vÈ¡Q†g¢„5W­Dï‹�xöòUz — OÏ ,4Rùk;HØ“çñyØ*£Í•ÒǸ¬øŠ èο6nfKÿƒø.Ë�ÏX­¦u‹f±Ç/s̹o JõGxµ†îô7£á;c/Ý©|dÄ:nX¿€Û®¦øÊ@®’d`x¬mlŽªé®¢"Âã…Uì<÷5•޼Ky«X©ñN?¸�¦=÷ÃWé…k|1Šf&fC7ƒõ°½0lŠ Ý6N‰{¿À¦k›¹GbDØ|‚üÀlª|RHåw¥¡2J•^� ‡S] â�3.ÔÒÆÒÉ)t¤ÑŸ}֢ljµüÖx¯DqìšíÉ›Ân£Gb ]¾”ÏÇv ;[NAG�O»Žq{fA­æd ™MªUJè>MXÄãÕo¦0;׃Íî�·’~ÃøæÐúgœœ|ZÔ’= �¯WŠážãhݳÅxap,f|¿&õß„Éýƒ¡Bï˜èú“€CwÃó©·…TÝZØê?{ú$àÇ1­ô%+†ßŸ_Õ+ ÉjMO÷ë%:â½>aø³sWû§)Ú’Ø×Rà³K½ö ãKórž ÆÄR]Ñ@º©R0;æ.”nò仫É3ñ˜9ª`ø-4Õ=%F–OcëaF‚_ÓWðR9 c}¯ó�¶œfíöÖ²îs>ÿ¤Ë³ë…½C¹Ù+Ê,âö9N^“Çõƒ¯’ÍJ5¡ìòböH郫~auk.ª�ÚOòÅ”£¯ ³bG’°èêÐ{xl†�¦gMÓÑON^ô_ˆÏÎ}b£Ù�¯‘Š\P½V�_P#¸ÛèQóT>^ãE+nSȺ…”�ßÈ)½”ñ}ÃQ‰Õô³4ãífv8óÏkÚ¶óÝs€�|·ÂÊ®T·{:%¸lˆ�û†ÿŽ Ò†ܨûeºo¡§j*ÀŠD\ôÕLò(¬æ×Ê ao•øíC‰UýhQ&­–=@bßu¬7o‚;[¦áìĵôlá1·ªu­�¶[ïê-`ƒ¤D· ßôðÅÛ&,{ÇÚ�yi§öhåVOKÜŠÆnÃ�›fá±î*·Ø£{˜ ¯y„íê^ð*¦…ìÞ ½ ɤ¨�¸ K4ñÝeTøuLóðÚ‰ÙÙ¨€Ö&[°³ó 9e0OœGiŠIÓå7™èëðÉbú²¼‹ì}nˆ/çøñÄ¥(×»ˆ¦ý�³53qߥlH�Jdê-Þ…,^7sW­òưÌs°¹§üÒÈ£i¢>+–;`ñ†A<0 ›®.õ`û²F Ÿú•^zȹQÃØ£�Ee—Q\Èñ¨¿n"ª°*fjÍ…‚„ŸP23˜¤ßÍ…#½¾ˆÛ'Â1tòM7ÐÓE'E å2l93ˆU %5¹;Bå1kÞ0ñ(ìÖRá�ëÃyEûxê3¤ ‚Ö“ôК p�Æ�|O.U·iõÇ|T\{ZÅ^üR8 åÇ51hÊpü6`?=8¼‚¬ü^“òåh! k(.ûPBç†ÃðÃß„>Yo„V…RUŠÕŸ>F™›˜þ# †kƲ¤t~0eX³Ì{a0~õ ¢ËSgó÷¢#ø)0†Žž”åW�¼ðÅHT›<�VòŸ/_áÏ]T[øŒ¥~Þ†BL�®l‡õ×[Ä”À»tÂ>{sŸ…­ÂßcÈ‘Ö*YµfPžß.¬ŸìRdM©å ³¤Š­&��ò⸚\öú¶�æ?ý&Úº ­i¦¢þê<ýCê{¦‹'‹Ax¾ê44ÍÅ×vßs›Ò{¿ÏÈÁ�NÂúßUdsÈŸ‡¹ÉsÍRC|{e77>œÂ«ÌvÐò%àa�—•®Â…E ¸¦°Ç”Šoü'Ý9�½ÔÏB‘²~·É”ܽ/rÙ¯I¨Þø\ Õ"j„º‹�£†á‡–‘4éÚ]ñ«÷i°)¾Ì(B¿EÓqã';.þ„¦WÍùÀ•$\,+Oç�×§vì*{l�…j¹{wö*ložA¹;'@@b2½L»)f¾:I×vYáóà¿`QX�›ýQ{ÀÎâ.s™¯½êjS“(EæÜ®µ ˜4RÃ/6PzOíà<3K¢p–wß×ä¯Í3ÉYÛC§Oç9úëq�k¶_ð§ÔÙù•”‚[ø‡Pê<¯�ÖŸ ÄQ¡ŸéÚæ1¸í¤öòKø”7•×ü¤]CKè¦Þ²­Í^R•ðú®-:oÛ:±râ"ÜÉÆÓ9©:^,}^­žødæ‰~c|‰&tõ ‡²‘(Ù…wÓšÜ=ðúù¼b©Ê3²bÄÇž¼|‡%/¨*ƒ`Çœ™çHãœ9Îõ_©G™ôÅtFÿ=ßœŽÓÒ'ñšêv¸+-‡y¹¯ÉL-•7ìΓö)qòl%<ö*ž¥RÓ¨•¤V}.†�C©„í¨—(S§�àC�†I ä£&jð—}‡aj{Ä–sèÍàæ)-Üx¦�Ù¨ÌCç�eãXu<\˜ŸÚTp\¶šÍÂN;´É»"¶«Ìg‰®94Þ�Âlõg\*œ—XJÙáúá5Ü^¢É!&éOMÀù�2wߎ¥�ûæáùy³ðcÝ-nëá«v§É{Ë ¾2j Ë�™Ï×dü¸j� ~í4Åò!:B>{ãü'†èSšMMŸ®ÁÑSÃÄÀg ¥S…ÃBþJæKÚÝ4¤Ær”goÝĹMIâÒ™[„~¯†ã£¢hX©É©zשô².wVT�_âDäÒØs~Éù‡ÁîÖ½ Ÿ"¶žÁ íK¤òý,ëŸÂÚªCØHCÀ%òÓyñvEœP’!îð7æ÷ÏN±âì:÷ñXoº.>¼ƒƒyýmMZ¿ê$œ˜¸œ·ôYÌÑNõ‚Šþ$|0Y G$¯dÏ¥%BÁOy,¸f GÛÆq·¼,?th�Q¹,3ß>%\¦ocÅ·m×Dõ·E<¶z_Ò�o�§i—†Âægr¤ºn¶»Yc“Ö :öt*Owüâ·²G…ºQOœ?Y‡-· Ÿ$2üëŠï VZqUŒ™kAO>&�Ò­pøyö8özV}ø&˜�ùW�Oâ§~F¼ìïwL)H¥³;>Š›®ÞFå®+®ÓDK>O ÅiÛ•ÙVj#<ƒ»,¬±ÿŽC å|’öûs2;ptä rúZ_Íf[= ãx¡eþH>Prôçî£Z«N‰]ø ØKñ'½³Ûeœ;_‰=Í|Ùªo~iÅÇ÷ Åe{!ý÷íak¥F“�óHVqLgSÏ·õ’ZPü&…ç¬äºÜ°Æž~édÓÈß§ óäYž¤™„.Úò´¤cø•ý|-„té ­Éwa‰÷¸h¦Gë~yÀ–ë=ùâq‚aŽ“CEGKx¦äÊ×Ö¢0 @feP~Ãaxk:mÆ3w)âä¿«øÃÖ˜ñçYXê$Åy>l¿²†?}†›KzÒ¹)é´ë‹õ0#ÔX0’�ÖËàÕ§AøèŽÜj“’  ¡÷Zr~o+¥§7�sÏ&auƒÆD„×Õy°pûÒªÐ`[)¼üw:¤lõ SqÍ´hAfÈÚ«ªyŒójx úç¯.¸tu7š”á³e�ú¹R�kQFï²LN¯ §¶Ž~!å Uìvå;ç÷ÐçjáÙ²T„s™pèˆ-&¦LÀ–í©‚†ŽÜù—ó-¶üüf žv�U“ѱ,œ»åløÚØTžÝ£ ]ÓÌiû­Ý'×[ñ‰�)3Ÿ¯žª™}/áó»0|­£€AF™à\¢Ë—­‰o‚GK^>Ô@‹Ý2Ü/x9 Ú�¿^† þ¹8øöª~ÞNþA­4ëj¾iGÛã‹yCèlìáë/ªe¡£Ûwê÷]‚tN£aq¤ÄîÖuzÙó H=�ƒÞ*t¿Ò‹m"ÕQ~õ`q»í1ºõv Þ©Ìæ£jù‰çN°BÈzÃðnƒcØH\ã„À¦¢êÐîÚÛ_^¬˜Ù!jnn‚ã ±Xo£°q�ß½9˜ý5vP�¡»*™ �ÇÆB¾ÃVp¼y¬¼ÔpÞ†kâ|ç áfˆ)ηRÁ‡Ó·q”#ðþ)ë„ý‹­Øe¿.ûVNEsTiÏm%̰Ôåõé|¢á#éºÏáž¡Ñh°³KØÜÒèãÇ)/¹Qó<­{ïÍ‘ÙgÅa¿4Ùå}ÄZ^…Ã�À#Už%ŠåpöëH\¿ÜΖ¤–Ä�n°¯]QÅ«½wJòŽïäEûGá³²¿è÷!UŸÇÒxafº?š›žå¢åÃ0¹×a7e?�|h€×âÛ™ƒL  xv.»"|ú¼žktSÌÏgtL)‘“s%ô(=Ëí£…,or?#¶–¸íîëÊ陨O*Á%ÅÄý:6Á»|)ŒUò�è-ãðCå`¾¿³ ó§˜ðÏwß©®Ùœú Öà…ã1Ä$ŠU{_-ÞQ¥œ™¢…&ëb0róÜ^›(¼‹xýøC‚V^‘祧¶óƒu±<¸å‡pÐÄ-öðþùV¨ü7‹wŽxOGnC´dêH})«g§aÀ›éœ~pÚŒ×âý•°ê”ë¿Îãw*¡ÌW{¾e‰O²ãpÅ_y²lS�iù/Ĥµky§Z"÷½—o~7…þÊzbÎä.º¤¢Àºé‰âîþe°Ÿ‡¼„»+lqà�íx{Ÿç4½\½­`áÕ46žßÓýoNÿPŒÀŸF_à„g=u¾&˜–£éŽ?0ªo!x>¿Ûsòäehzº vDçŠnûÚQÅp¦8ù×lö™”Aâü't ô7´ =,œ°ñâq²÷ÄEoÍp©s�°ÀC†é!Üè7‡$úó­mýøFý1ŒÙÜ — {Ð¥†|b±'ÓùBq“ûª²˜Æç�½ðvÈ!Áäæ=Þù±‘õ)Ìøx…C8—ÖÄùÒÎìQ`³î ¯ |J_Òjèįdá…íŽhCû‚ç‘Ú%nRÑÅë‚avd„äÙÀgÔ{xú¼£¸Mú¬Ö°DH«ÚÑÓÅ›×=ù[ä.²ä“�¡hÀ2¢‚ðãÞ3ÞØ/ƒî¹bèÆW´\G•ý‡HüçRVP# [;ˆ_lúÇàšo°ób³[Êe~¤Èñb>‡�Kã‚Àèߊ8  ¼Þt‡ÓWo§3§ãáÉÍ|Rº÷Ž»Î‚¬Îét : ßN%kÇNhè¹�Oçf@æ´røà^v¡©áA>4d >ÐÞ× ïS’¾Çñß“Ø{Ϩ{z õ(ÿØgÂI§.�÷Wâʃw…]ë&p³|&¼é..ø5Ht|VÓB‡ðõâÕnK44jǤ÷’›ê¡âæ1úö~2L.æŒe/ûR”[í„–S¸«>ÜóÀµ<¾ö­ WЛ×Ü3àà'øöUÁ�w»¹&o*£A=ϦŽ0Be]i¾2ø7-}c‹µºÑp~3øö:IÓû`ƒ5÷IëW˜ðñÜ]°m̃°™»ÈªÛ�?šPlg!=ªm†Â[ãyNŸr sÂò·DãÓÂúño„õ†ka{¼^üB,–Àå…¡Ñó8ÝØ_H‡®Mš&h–3+&pÿ¤‡”ùÉŠM<Ç“ù®nš×\G_mBÐbÜe·ûÜÂKT¾‚üôS0Æ/Šwßx/Ã/C7òD){0¿"‡ñw× eû@ü2K‡5 ߊæž äƒ [çÉÇ3éõfŒ{®ÂO•�F¿HzæÑE»í}˜âf¯U�¿¾P\Ù|Þ|Œ[ÆÎã&³Ìû;’ ?Áá¨À¤|yüúEóFGxXMmOUàvï,V{xN5åÃÂØ?ðãÒXœ“ͲͽÁÔó ?1lºûó»éõbRŽ­œºŸ ä…£¢&�"–¡Ö'^ƪQ²(7äÍ¿zÍ-õ]z�ÆyñÅO)Η…Ê¿ ¡¹ü1ùù´±8IèCú}�Y¿ßcÉñ�Ø`ŸNÚ`í¡¨ÚJϾóF�[m{±~¯³õ"÷ßx/ŸŸèûuy‹QlT*Äã£n³ñʹXÕã''Hù’Bw�jxü)e5Úy‚ìx;²/ä%”Ú�ÅùÛ-`ìÜ`\c,`܈Xæ­æhleŒõýŸq¯™ƒˆ†(°WçP{¦Á&êÉxª×w*Y» Ûìçñô{}èõ�^uu­‰üQé¾»�sÝøW¿">ç?ƒËçaÍjg¶¹8õœÂ}ùlôÛˆŽ­ýŽSz×ã…§·Eß ›q¹S!’Òl¬÷•á§¾ö”VZˆ%cPû‹ÄþãŠíÄ ß1Œ_:ì¶ß‘BùiýHöÇUžmù�s$;h{d'9—˜âéä�Ð9t(uö ’mC”û ˜£Ãƒ:î\w¬�óŽêºkû¡ÊÐj¡jÊO=£‹Z#Q=sŸäl3¡c®™KIqdãdqÈw.žÂ$W^Ö ûbS=d¨h÷ŸQ]lŸ.¡ÏöuVǦ…±èxÔͽ₠ŒXÐc?Ubá\o®3hàSÏCá·ñ _i‚ŽïC¸¥»Ç̬áŒ�öü LY·”Íã|Ü®¾ÚÇÒª“yhÉ~¬Ì´ç„“ﹸi"ß_µ—é&Áÿ(:ï®ß.Ž#›Ì†)”Q4ìÏû:¤R”(ÚKƒ’RQI(DöÉŽˆTHŸ÷9¢Ô7ikФ¡¢4´Sw÷_p=®ëqÎëõ|þt5ÎûŒµ›3a]ûrzt šž•Ó±†\:¶\‰Ø]_ú1û5ÜÍ Ú®8Â:‹ ð0R…ØgbœAÊ{ü¡KŽãHÆ:—Šž¹Ø¶Ÿ×ç.Ù§£«x)ÍÚ 3“½ùÏ—7‚cìhæð ‰-78)Gosa�¨$ÞG ­¸»'œÜ½6ÀC›ð¤u,}65ƒ6 êžTwÛö@Ý‹RAå®®Øç'-¹ÞA=Ôz*¿ø§ð·¥]þÂí³JdP_ƒÇúP«`'5¦†œhä½X“0z£ÂüIl¿-UîP«¸G(ï¸÷Œbë Ž€éðJz±"Œ�ÅV6?Ðf9% Ô–çcIÑ>°Œ~‡í£i‡¨LcSÙü’ÓÞ]ölê˜0 •^…÷Tõ¹^çSèpàVhg0G•£TÔGÂ"É3%¬+ñ`]Ò};ªE§ÑáöóÌÉ=+®\†O¶´UO.‡–NOJ=ÑÉÉ”bT£ˆ­ÛñÅ“�È‚ •`Üo!è¶×PÆÏ d““@ÇBŒ'ƒl21Ç+Vw9û 0ûº;´|Ìb÷•ƒ°¸¤ß/§*唯PÁ“›)Ä? zìZÙêÖN¶ª¾¸^ùçZ6ÿŸ¨”»9ÝG°¨„!·»,Sc/Û~”­ËµcêÊJ�K¯8Ò•;­\õÒô‰ºÃg=i›¢éÚ¤p–]÷Ÿ ÂE È2A”‚ϼa_o†à�ÙxÄ^…6G¢ØŸÝðôp¯ð«¾ŽgwZh¸#ƒå‚ƒ°÷¥ ÏQ¡yìYA{3«û¬÷J-Ц0–�ê…·¯|qcVuø<¥Nµ©þÒÓ–7àÁ“YЭAÙËøRs@íˆ$m\r‡|ßšB›=0Óä MÀÊã˜ø§5´EW‹í¿²þIôqQ'w+ø(.~ò½ÚdÙ¡sý,Éß ¼DÒ½i¸M¦‹vÕ‰°¸–ÿTÍô�W¾؃ (‘mLK…–˜ET‡³ŽÉ„{˜LÁñkàÁ›$?²‰‚n5³ƒuñ@q.=ÓŸA1û31¶Ü Êö}BϱzÈÍ™{ó°S5¿‰`¬6„´âä¡^æ(훾2ïà²îTæ¡ò‡%nû‚1%kHѺƒ½w{*˜8êÞÛ¿‡ÌFKÁb'y(ûá ó¼—RŒe(,×zH¯Ç½C‡ñyÿ¸ùxïs!«NŒ Ç/z�…Afpàº'öd#ÎöÎ eçO§©Ãl+nB³|6Ü;ã*ØÌ æ/¦…å&�Ð ÖÏ»µCKh­��ÁU}m¢ë¡Ø|U ’lù.XìÚ ÝqRÜ©{‹lîæJÒ¼ªtLÇßZq�d_H�Ô¦~˜� ìg�¸Öd=›}åkéãö,N&€ºKd`jù*’èî%E×ëÌ{é:a‹A<®[ZÊÚJ°­'’ö;�“²Shdжx  ¡B?šuìJæ~X äÿhãWó{LGu>¼ÙZÏΪØ¾ î<®”Ÿ ô¨ÞK‘®ÖßÀm¾áT¶ë<ÓóùÈö‹Ó¾Qÿö!埤ÍWÕm%ÞÝ$ßIÒä·÷WøS4ráì�¼¿´‘²Î˜ã:d÷>H�^¦3.Ñâ³2èÃmx2q2ÅiÚ† ;I:À\¡™‹ùã`Ð80µÜÄ›ÕÞÅo5è³õ¡‚Ü'>Æ'’·|Lìûì¦4>±YÄ̾ݧV£6ðøð�ŬÑh½ò0–h7@QÖrÖ±’gΡÅÓŒ¡©ù ­·¥!k/�O6wÁ?,š=žk7Ío€ÃoÒ¹³o-½IÎI™îÆ4ػԄÄV¢êÛ:Kåç)ÐÄ�Þo‘¢{3q÷Ø"aht&N9ú;—Þ§c5¡`¡0–LmgZß�H±ä-3:WÄñÅtÄ÷;~ ®[&Î/J½xZ ¬Ç¤CI¨/}iÔä/¹&°Q%ÿÜ;ô']�€Ãh«ÊC¯µþÜîç<¤ÎwAv<Í:4�Â}¢¡KË�D×ö°ÄK^Jä¤ò_¹�ßïla“~p¶ž(RIs•ý:L¾·.Ã"¯£¸sæƒÇ±Ü˜i‚²a>9_Šöï!wNH/Ôœpah"|Y¬@oÿá~dÌÁÛç æñ0&îP�N m$?ΑvS#Ù®âö¤*Ûþ®“'é?ÎP/Ç wEÃÃuÿv~&©_» `­÷h˜³÷1äÁ<œÞó Ä÷])ÓYaTnZÁ–¬˜IF4F;�FÜðÝÞ ø‚ñZ´ÙVçÏ\ÑÉ/¬áîeÕB»Ü ØÃy6l¹D½´Z€ ŸÊèhÂè³Ùxÿ¨)Gœ³Q:5œ>—�o ZÕ�r_ÄÁÁ2Ö V°s‰ؼ�%pgø(¸ü&�ÚÿÂä’Ñð#v1´�’ƒ;õPä¡ûZNÁ÷¨2š$nCjó ±È$šî)ƒ åtÿÚJ“jo’½AÑY‡¯v9Ûýù<Ëó‡�õÄæwüÈ­)£‘³ö‚D„È�*bò$Wy7r.˜Ò×?¡Ì/±Æ9&"t9Åã?Y1åªI¸ù¾}÷?^~ª[î°Ä®Ýpsô´Æ‰õ?¹;n¾ðínywŠÙ®�«„¾[c©eâonöES˜Ó;Z-��qó\6¸ë<\¸w�NêÊBžQùãIœòÀE^AW�]¼;™.îõX|0Ä]3ÕÑcïۣ˄bg†Ã‰]nTp¯�d×™ÙjÎ#éPÖœM#ììñ–Æ%6°õå{Éÿõ~ í5`î“aëßV¹>�iJˆÒ¶I9üÓ¹v00)¤öÞø×)–4áù6KÊ‹bÀ·ùØÍùŽAë\xýÑØbªÂNÝN—ä¯P‚õNœãö›­´üÂD£¡Ö<¨RÏg§‡æòõ‘b+<3K‡Ò•ïÀæúY8íòÐÑi§êá%$rMï:H³úkQà<¦ F¤tÀ–^¼qƒØ…¾á4?.”D [h¹È°pn†ÏóG �ÿƒ�Rer¼w]h¬c w�O㉿éÀ&g DG§ÓþŒ8 yÞÄó*Á:ËÖneUÆ´¯X÷å3»™Ã6¥ÌG‘®6Œ+ %0Ó¤ß*(ÿUÜïvƒð• ¶»Îáöé·0¦¢PØ?Û‡M< {º{`÷„ßü´²r|2³œ9ÍQƒ§M¨/mŸn„’øÓaôëKeñ üÚ<`VÛtôµVgÂÎD6ÿl6¬÷dÑuötØ´ yÃ3ø¨sY¨„’ìÍÇ슦:¨æ)Õ3ŸÏ†,@,œ´bíØ¹ çié¤|Lš­Ð8yȵëÿ½ÍÀ¸ÿ`/7w:ÇÝLf[ _¯"JEŽ <¯’ÇY�ö5rù¸œ_ìî 6k„ÅÉùTî1&e¹°R­µôëäW’šnû‡î€àùÎ$Ä•ªîöóJ�¦± z�¬Nƒö…0¶>¤„Öš‚çïB8%Ôå?U´yæ'Ü+3œ„‘°c÷-Ôñ|IÒåáÂÞ?¹ü€cTÒŽó¼Þ°ÎÊ0Œò9÷o†–ÀγŽôéãp²›ŒÜ‰S©LbÊoz1Qš–c­¯@ÝI¹±­Gœ4Þ¹A†Âèüã€Ï.?¥·çÎ >- eaö†èéY 8•*Ó˜ÑmÈ9†¢°s‹`BÝqeʧ9¼«ä¶. ÄÍAl¶nÉñ¬°0ƒíqWh¼paY5I4~ ¯N gŽ?Vâã>%š:ó.û¶U *ÏŃõÊT(M$ŸJp<¯ƒõ(%CA�}ãj¿(x|ìû±–Áæ—[`]U5¿†{“*1à«ìì#\×ñÖã¤'�pïãlväidú¿f§¤ÓÀùSäð9Þyf[UyöR—ÛóU…ÌõüqçCM�ý Ïí�i4³pÃx�«ºØgPc 'Md�{wî_JŠ7+@jè”î‹!á0 ¸®¿Ÿ×Hh€œEi$·¸÷:–’^’3‰�„m÷)Û/Þþ4W+·\~ ’Ž%¼FXTƒ}Æ~ô‹jÈwØ ¦)lUy%‰i×@bV?abªó‡¸›·*0¬ü,u—jtÌëcoÛÚ)´I£ñN™ eük�:<þnö9[Û¼ÂãÉht&¹?Ÿu/U¹U©7@ìH%ب‡žy–ô~¡<éuªÀ§ývçVK* àdøgü˜>f;À;%IZ]XÍ�Òÿ�{¼\¬ÄãJ»CL¥5†Í9žKæsëy�Mݼ�øK–5â\÷ çÎ-Lb³ m ' ò¸…Op‰ÿ'ü™JuŸK…%yi(™� 7‚g±}<t•md‡^¢3¥ü G’¿}z_ hYpùùгcáøØDöêù=:`ý—)‹„}ôe¢" ˜Mb�t²ñ–²'³»óEøûí+ÞfÀãfôüÛÉ$6þsÏAkx,¿^ȹk㯠eÜnë$Îûg,üñ�×ÜëÎt{ÞZÇ„cŸA¬xY@ïJ¡_]4» ¤MZŽkIÃTŽE²YiâP./Á¾�ÿ1=ñ,8cMo½IË»®boX)ß ÖŒÇ*ÁäŠÛ¨�&d_¨-B^ƒ×ì^¶òºÜ8&FqÑŽ°„3qÂé`\\±¼Ç®MU¤>ó9Ô!µ ÎþÇf<<Á%O‡·Rbxé®Ô¶¾%ÃêM¼Ì¯‹´Œ5Ñà ü(Ͷ BAÑ78´,$ìfÂÖ¹\ѬXRTnÇ‹.¦ÞßÊÅø>Á+®¥¼Á@+ضí6'£Ý6QôŒ‡å'ß 7� e^Áð ï0_ä°þ‹¶…Øõ‘´nE¹?\*ßsé“úE.7v,\“39'ìQu¥`ý@Œ¹›Ìî¹UÓÌ�ëM«Û&ÐöûHWò=ˈþ…¡8ók!—3œ§ÐÈ=Ìo· Õ^M€+'smb™ðÅ×…fŽl�Å{ܹlñãPÄs¿XŒJ fŒ‡½ž“È–w Öm-¸íÖ3>ËBŽïn¡ÓãrsŒ©×ʼn,æ¨ñ ößð«b�qZC7p¥ïb™¼Úzˆ™"IŠ£»QÞô$›ö'º4ñµz6pÍö>=�‡êz©œËŠcÀ©E6j}cI ‰ òÜÙýÕ‘ðüzí•óÀöüh¨|þ�õÉãÚo©ƒóÕb�ªU(’ükóNú¦;¯cF3Ýë!0íU «|ŠFœ{ϵÔõ±K‹éjâ&rÝí]Ó›À¢í(¦®|Œ[Ö_Eçsñ”¬ìsß·ÒRC1¸k/ ú¹Ì³> KâÙË‹IØfŸamûX†;`'ŠÏs¾1çgðüû úpŠŽ¶s—µ?ò Ý‘l¶Ù~šý>­šM\Œ mÕ�oœ{¯ûʆÁF×q\ÄÖ“0{Y«`ù´8MŠŸûb{\7Äž^ûo2zˆb ä¹þ¦E�ðëøTåÅ~ÔwCt¯6tu˜ÂâÊl27^�¶eôrD¶àÄD8ªGiÓ]X¶›}ü}w'“…¦(£»ßqrM…mˆ#‘e9,¤}ZdÇs±IÝØ´ñ%žÊž�‹‡ÆÑ²ð,vôF{-èä"B°¦ÿ¾uãÊ^dÑßçüôw XwŽx¯m�‰&MXfx„ξ˜Š·6)á~6•Ê_K3É©ù~Õ)äÕ’Žæû3PÒ[�J»ê™¬Â ½sùLŸ)Ò¦ÿ¶Ð`ÔœñmÓOì¤A%êîèÄaôI×#’<#œ©û#M˜7JëhÁ¨›üÙÀ~tØ“N 矅šÔ¯\Å�›Üá¡tå·��ùÍç\8‰® ÷8G‰ÏD‡ó»yqÃÆÛÀ·Š…ä7£D‡sÀqÛhD¢+X¹fó“:¹šgÞ[Èj*è׃L˜|æ#Þl.e3ê¯qòúPñøQ,ú‡£¢Œ`ýÚÇxYMÚºìráH4õ­!±PÌ[Þ…�žë7]î±I“&Òâ­Èh�áP]‡!kͳ€· EüÚ–‘0z˜%; aZ©”¼j†9a‡Ø‚ጽ}t+ÍîsAM?0´5K0Vë…;]X6G”âËð—Åì‡T>ã4GPM‘ Ü*9imvJÙWkçs 5´8©—ï“”‡_\®3—A‹G[)QW eö¸ÁäQäY儎¿±Cn~x0Š#¹à“ð×íŒàÙá4’tçSüÇ”ŽP�’48™ è‡…0³^x¥Nžî.Ƈ³6’‡Èa¦Ún@Q’+A1A ò¦fÒAŒñã /d/©HO"Ùé¯y‹ƒuÔ1°„ éÌ£åû×@€ÙjR�'�@—IÖš®C·ûÂym–¤_� ¨øvQ ƒÚÈÁœñu¨}]�½~Íó Ú1\¼Ú*~–ú:¾×ëMz¨O1°þê�€ð-‘BïYH”oGMiÊùÔŒ#k&Ðûµ‘ÌåôlXS“ˆwëY¶²§6VüžÎ¢ ŠpÑ¢þ’cûän0¯m*�0WŠ ³ï3Ú¢Âÿ=eF~³?°}ÍÊàõÙ�åô·áÀ5q[ýRŽünuCÕÙa4cß! ¶f+uÉcG­úQÃjgËQi\óð4§µòr�¶ç:ž �¥ôœd¶Žw$ö»ŒöÎb¾{¦’ƒ_+›VÿmpF[CëÎ2\’Ã|íbàŽ¼ý°?D}m“Éö@>tyœãf+N†›0~™’)>Šû‚Ú¢WÙ®~iviÀ¸Ä`rz·N˜–ƒ ÌB@qjLè�ÁE6{8åÇ(Üû˜õZOåó³€[ÜŒòßÂð˜Ã½ô2F«Ç-œMþCafÈÿXÂSJ@EU–žîegtöƒA’éµ-¢áfsà¤z#Ó?Ê {î�"½[ᛘ:Î~UÇÆIº�žs˜;ï�¯Ý…ÌÍ* f'†C¿‘:œvï/”U¸Î xþÇ‚RÞÊCpôèyÿìôxÄæŒÐe�Ê7ùË�¢4?ë>þQþ†g¯y@|O—»ë:F5ŸFû F¦=«˜ð¬ zeTÁh‰Jfœ“CïßO"Wïæ5ÅŠ÷à‚ã8ÕO™Ø6·¬3a“Óf¢\ñ�}lðŽÿ º)©dx>œw1a¯+Õ(z‡7d$ÊÁXC�Ûn£tâDlŽ¡Ù¥§ù£.3húv:² $üÇCªæ}”:›ÎRŸ©“yŠ8<úm‹§ s�ëŽíÓÙ³×hW°‘"×ea‘³ ‰ûÄÆÛX ¾¢7kº»šŽÆ*ЮðWÂÖ—ÙÏ•ÜÈà£àîw•Ïý§zÂñ’�xv<Œë-ƒàæÞ Jè{“3_ŸIK‡œàòêd–¼ÿ<³¿~§Á«±´œhV~³n0�KO0Ý÷«ùó¡Þ�=ó 7ä²�Žc)�ÿjE¶zÏÚ®æÏʲ´™‹ª?K1¼Mòks ùô tÔP‡³ÎrÜ�¡,ìYû¦Etq½¯Äl%tåÀ/s<‰çQ¶M8T?ZOºÑm´ÃO‘:+lp¾À ¦¿%‹[°`éœî›@Wu1ár}xÖ*Ñxé´•¾+bKéÏ’%,`ð.Eust¼/�bÍë¹Ö’*6+ã kyÉLþ1)W¥YÖ‹aÁŒ×(½º™ÍÕ›ÆÏ-H£‡O5a�×]æ=à +ƒ‘á¶lÑ*¶_´€ËM^€Ç˜íH÷L9›ûú;8QŸ–2eê_–µécùãQx"æä+`¿êU<ûå6. ˜�ƒ'ºYæ wáôùgXГPprÑýÇ£yìë°¹Td�ï:, &Ý‚ P w/e:x…ÞH~äôî<`›¼¶ðü´øÅTC ®}3¥í¯ké‰u1ìZ*™C äq-‚ÿ^bvHrwGåSäÁYt.2—5éÊCéuw\´K ôßËѹv‹zJÕK[¡qk"¥ŸMƒÞ!ƒ­�G…ÆŠ´õE<÷Qv\­?É\›»…£Cv1×ì>öá<ÁË'ÐkÙœ¸a4IÜ>δ”¾EÍÁuz ܬօ°õ¹¥õö²Ÿõ‰ø.Ôçv¥BíÔ ¸˜Oë]ƒØ³[#bø448T‹e·Øßá{Àn×j®~Êšºdœ,4"í ÷6šÙ!àQ?“®I¤Ðª-² 7ë9…§g2Wþ:3¼uŸÍ‰? S!9ß^îûÎÆhÓd×y ªë¶=) g¿œDÓR®M}$ä%Jã_ÅRÖ.Ňth hõ�ó¿Pô�/9{'Pàó¥t@£�zO$áÆÒzvDéÓŠ:Æbžœà¥bþu’‘VãgS3|°1ƒ^>ù�f¦™ôþ…^œÂ¬£òéQ` À}ê^ô;Û…ƒÂnwC#Žþ4Àâ7Ì [®ìäF=ÖPÈ÷–¤`zå°îîg벋áŒü–:õ4{ÒkÁÍË,Ä3‹6�Ás6Eò6h„ÂÑ·Ù]©˜ä+Äž‹ŠRP€ô•+ù¿íp_.]8iÑ*ÝDῦÒEÇü‚è© w\Þk'ðÞ§FQ‡šÚ9‡1¹ìGç- «pæ½uqÃfÿeƒA͸ï†2mÛ%1¹+r¾hQ[ï~`¦~~°¿Á™ò÷Ç ò³áÇ ×yÃä'ÐQ,O Ë|9ËŸ§á~Ý<’XáHёɔ™) b&#mkGE�mõ™„,6PÁ•ËH"Fñx¶¸óªKÐ+/ Èäs]mHÅFóþ«…YÏñ#ü볎… ‘›�42�¬¦ âû�28sï*˜ %!Cý$Êëž‚°;½d÷`3îkv+è£ok(¿_â{vm$Ý»þ…Eí0b+êËø¼O#°z¨Š¦hܤ­Û�¡Ÿ¢2M†LÎùœ�-“|Žkͧ�ô²Í´«þ%›,UŒY“û¹±ðØÎ”–íýÂo ^Jë[>²Œ®aìQÔ–F2…a÷q07�&j7Á¼oþì¶ïyÖyœ7IáÛƒéØ (DˆèÙI¦b‰Î&ÂUg_²Y?RÙqÿ¥´î'OÞ/`羜ºÈ ϯþ­øï¦U2÷˜®{ÚþÌÃrøØîJï&ä±_iò¤;À1Ûa»!h�thÉe1ù¨=T˜¾C1ÜŒw-¢`Ýúj\a¸T�hÚ)”�åpòöÅpv¾ö,9Žþï¡ÒVÜN§Ḛ̈¬@¢qNp ;bVާÔiÂk,94†ß^4•wžæDò+ãjy6ß©�5ÿ4d ¤G5ÚëEaC»=FkY’äžé�¢ù“õM�A_ÚŠaÙ«æGò½£·¶ïf±n‡™íÏ&\(gzE@õ鈶l¦ ¥ñLTYŽÌÇläghð¼ÄìÓìê�Cø_…|ßJîo+aŒP ¢•’åiE¼\¬Î¶øÏ‡,­8:hÂ’ª3aÞ«ÓÍóÊ´ælšŠbX— œÛ+A÷m? C<ƒØ “tÒ±üÉÞ 8ø6¹ g¬2¤�ò9¼•ËÒø-„Ìá40ð�Ù>O§©ëçÁ#-MVòi$ ¤!0ž|C-ž\ò”¿Ø�Ëü’*˜}�ˆ5Pïáüm…áñám¬N%³j¤ !¯™­¿Ÿ ¸îC‘×Ö³M�ÂI½1°Ìjyñ“±¼ì)ŽOYDkî#{yLqLeƒÑæä/ckf(À«fÚtl�,}ôÏB�Åìm@ Õû€¿Qwެo;¡xt±][Éaœ¹+»¢“n˜–;“ˆm"-É¡œ�‘´Æ(Ïà˜ö»T?î ´Ÿˆ)‡áÖ–6>¬o¡0yÃm ´øÌô%—ƒ“óŠ*+Ã->6°Á1—¹|Ó¤Ì�9ôøXåùx²3ÓÙÑkµxN'¿E摵’$þ9ÍÖÃ%”{¸�=³Î$ßCÖ´9OÈòo†ÒÝl'ÒíGY Õh•åCºbìȆɞb Ù‡¸MG2iÊrO|�q >gÃ…Š3¤¨šMeSÚ0“ŽÂó߬ÌXHêsA´$Ý ‚¡Ï“è´�mÿn�ÔÅð³ÑjäuÍi”X$ùÞkÀM¡Á´ÛIZ^‰ÑvË 0ê¯ËÖ)€¨W10ݽÊúòõ^<ÚÈ_Ý7ŸLEŠX†à9^ýâ@=�/ø€[ÙÌ0èÿ Ê…;Ù‚öÏ>E»—“ÆÜ" ž€Úkk™�Z¿Rk<|9_Êý'-ÇÂ.çSÆpHÜiÈD&cË…lŒº,�ø“I"p�=j±É“‘ãÊ!ô:–%­…¾½WÙ6,-Âæ3±ð{øHÄËQTÿkúweOs¤‡;Da=ÈPíñFÿ氥݈f@øÃLÔf‹‘v©3lúÁï0ŠöIR¸•,)/�¡Tµ4n~Ð’Ûå+*ù²�!CÊn¼×£ýW»(^2&d¥ œÆ:Ð��Ý$fÀ–ÝÎAóâ%¬`Ë5¶GC &ìŽä£sÙá‚akk  Sˆó­Ti×�¿å®;Ü�ò@GM4p’àÛá!Yñ?Ð'ºº”qëÀðS9л=µËîaõÎ0¨ï3d¥QIðÝæ5Ñü44Ël²ŽÂZ¯wlXÙFjl€ºƒB­d)n™9�ЩÁt·ÇAfz,SëqÄ ~]¼„Áb±bTô:‚+kÉxkx:ÆßP¶ýts*(§ËRI·2ž«Õ¡“†»9-É:²Ïx#tn3¦ÜõO8Û=b´\g&¨Û¥B¸õvü² c� VÜœ<פðS­¦€ŸÎxc�BVzô³ë8¼ñ¾yàAYºD&vºüÂÊ4öak�JÀBö/ƒŸï…[�¹ê“Åló}MÒ^ª¶»Û&¨ö…ð [šóbÒê±ÎËÀp©u4U'•šUI¯6 e4À½ä(E+Ü᧦ï†h§°‰)K‡1Õƒ£Éý°5�x²š~÷}Á±-:�“3›ñšu%ÙÈÕ³¼Y3 +âi_¥5+Iä Ä>4#‹Î?Ìé» +À“¦®ûÆ%‡Á‹ÞP"J¿¿ÚPÒÖŸØ5’¶.væC.×s‡¾e ƒä#Ö²U ÌÙ3WMMÁr-œÅIx­šÃÅç‘Û¬@H;‹Ï?O¡&2¢øø $ñ6ðÏ H+ï`�^{pRûÁ1=J»™_go¶JìF¸©›­Ë¹Îe´ê`Ÿ®5Þè�†¹JÆ,vQHü·’~õWÞáÖþ›¬sx*›’Èëw�FWõ%ä3E‰NØ Uµaä^©Áä侀?œ(k�“Pvœ,Í*Ü÷Dô!NóÖEcOéX*i”bÆóu`Þ²$ZïíJ'Cºq‰Ko²¬„‚æÞà« Þã]�3«Rš‰ªÁf‡.8ë|‘ßÑ`D瘖Ђ.-3À”ê¥ìÓä8rÎT:Š=5k@�³¶4z™-¨cû�ýÀ¹÷¸&)öË<‚¦É*’êì‘ôÍ1KO†‰;²Yy�‚nôq–£�¨«é"žèÔÄ¿s uf–j)Ðù;ŸØç´,¡C£èÛ1Ç5‡à}š#¿aí•�²øM$—“A�'$³§ª‡q»¥˜Ö¹Ó\áEüó³£ïBs©ŠÔÈ¡²›;˜øð~¶ä1þÃ%OÈj*Çm¾ËÈeøûò%–¼~Š2™Ì]+ DW®åÞE¿f7§¯¢³JY,Óü1Xû,„ÞŠÏŒ³+§“n5ÄüÞ°æJ]Êz×[«éªÌ†wÌkÝBá˜ýòL­ò# ¥‘ 룹{²·Ñù¹lõÂñ•-às Õ�p¬Še8’Ú6@Å!^E! T�ë@ò:5aâããûÝ¿1°j2ÍY¼ž.*cóÚŽ`^³;”匀†Ág˜”áÅl·-¥]éŽÖiA}\1%ÖÜ„ëâÆàûä>ãŘ`¼úaHjз%¢4íõVc£ �:ñxY} VôâîEX`<ÈÒÂ,èÎã:f}'™.½EŸÞXn‘�Eæ¡$ˆžBË"¹ÌêOL0CœôOYÒÎë_ðm²k"ã餠¿ˆ¾X.„B‰ÛØ3_„VOœ·>SGÄ€p^�*¸gy‘Ú[12Ö¯†¢½r WÊÔ:“0ÛtÜðNóºÛøU¶ûqçþ!¦p±Œ¶)»ÒÞÁZº5äšAÔ®¿ŸNØŒROO£]Ç\Jý[ÅÖéÓ£w«@ve(’] ·^{ ëñ»ã &‰;À"Ï$Ð3^–¹RlóÎ v˾ƒ?½h{òXŽ2$•¡|W‹ td˦ó�VÕØÔ`E)µ)KÓ†»þ²˜�²ñ/nâø h&ã² ,Je¨~g ÚN'™»Bvj.–‰fãíL+P½a¥£˜sB$Í*¯¼‘4K=iƒÄlî~Š:œÞ¶z#¾±ñï_áÐÄˤ1[Œ¾ê=AaÂqö·Æ…â‡×CÖ¥Íø+ Èÿ¢ÓvÃqßëxÇÓ �]Þ(9[ƒ¶7ó'®¥˜ ’p8¹„-zsŽ#‡˜WàDFùXm, ½©]è”rÎV�ÅÛé-lØ¥Û(ö®ŠÖ„Béül~}Un—ƒèSB_ ̰9à>š¿~€û´Q«Ÿ)‹2/.Ll,¹6Þ:½6Zâ�S-› ÖfJ@ƒˆ ÆßCëý>89%ŒmŸZ Ænü÷- h©s¬Â}õZZQ>…Ú“óy6¯8ki}5ë Ê•'«íMðµÍ‘¾±Bèð¹ES×:“i›õOɧ1“/àϾ10ë ã<4Ϋ_™Oe`áûØò‚ñ>¯YÞ9Qxä¢i[ó(œ<ãxÛ jV¯—Gjò`šo:æ>u¥ ãç0=6�å˜Û·Í�š÷–� ¾€•™›iäªðíð¦µêOI³º‰:«Äèròi|£*Á&¬ÅgµÖpªûî «Gµ�=ðöÀ3–¨ÛO§UDA2%‡]º–N7£Ààú=nÙ H2ëA écÛ{øìº°Z‘¼¬Ýï;Cô¡“Xø Šä‹ XÝÍ"c¾†öªçжM¯IcÂU8~$mì~àò;F-——EÒ¹Ÿ÷9«y"—QÓÚ2ÊjL¡�_Ï@fG2 kN¥Ž€g¬±O�=ÌMúx[Gí§ˆÂOø»õ;§òr%(oD>ùÅR4(ºIºqƒ¯t(%2ÏÓ/ç—Â,ɬÇç s¡íº!:¾Ø@Z›}@³œ+ó”“ø—/vÐaF�Ãÿp©?—RÃ+2™VÄúW<äÕ¯ý€ B~`I%©HÿGMK�YÊ€ øgHSÝ«.øR¡�÷MbÁsµíPëc­áæ0ݯ�m›VD"~pÔf.LœÍÇíóæw›¾ñR‡s£ Ît¦Ÿ2�w¹H ÆTs*’V˜.¤¬#†4õ‚Fñö߸s Qw±*IdÓ›wcÁ^¤žå¸!±‡UÈéÊÃÜ…â�/ýi]ïgf;? Þ¯^ó¶âÕ¦©�`[ Hº*Ñ�›UxË`E¨=ŬO=8�}ˆjvÙÓ÷9ú¤êoÊßXÑI›Í«@:r=¼Lõg­76à¶FØ– Î25à¹ó<.I¥¸Ü¹PõßK4jdS+è†M}Ð:À^0Bm©z,n à²ãF²›œ#,IÍæÕ\ ö¸ Ø”“Ä*âÏàä¿ÿ¼ávˆ™ÁÞi†Ó>sU†q6iìS®\™+O÷7W[É̉àÝéÁ:­™P8  •VIl“É}Öõš¸Ñ?ÐM)�}�EK¯Ä�îKi7'Ê®Z¦ —¾}r’h¼ÿ$FŒêÇ‹› Ô~2ȽÅ.}‡Í/Ë @¬–ÝÑ1$‡ú5tÿ•(<¯ÑÌëZǖގƉ‹qÉÑV¡Šåºj+Š6ãz™›Ü3Tkó¥Ó®H}h§áaSAêj'+š¶� ÆÍ£ ;ZùwòÐ>ç7‰>ëLj‹(Iµ ¶º“”~¹ÀþúqjuNf&7/°1gb yÃ*²?ZÈýü&AÁA*PüÖ rD²E-’L.m­¨œ ;ü)hö.¡þùl>~´±\¤sê§Bt¹+‹w�ý·óÈÚ 0ëãP0m4\|t«ö`Aƒ H+ÑgÑzNòk6+?,M�úµxèûpø TÃþ+<@Q`Ië*šÞ“ ÏÂÃ<ñª0vÁßúy¼ë4&€¿v!§xÏ�RÄöÒheG¨u“ŽÖn¦%v¾Ô÷.…ÔtLàñ“A±vu/°£éѤëqZ8ßc6ó~i ¢ïŽá{·�-1¢Ï«‚HsMk¹Íí½9BE@õ!Må8úê(JËŽ½�ïÊà~ø 7¸t).Š„3>Í|JM DWUÒïgb0Bf“ÝÀt+*`äê| êJaßÏætªzðæ× ¦ô*Ó„üe­ñ°æ'æ5ǯªÛ1ɹ|q1¡—èÐüÄêN­F‘y~(ø1ªþâ+ÿÑŒ2Õ1çÁX¦ÝÅ4ú´Ù•€'üx·¾-±³a=ZQež>e?±%ÝZª’í¦íYþp*q9™P}²•w€å'ÓÃ3±Ì]z<† ì œØ7€«ÛσÓÉQÈjÎ ½+嘕ç4({£ø,œè#MNiª� cX´æ\1<„ZÏø°�’'Q"F™¤¶Çp|EÈùÄ5<¸ÓJ…ãI5}-ü9$j»¯álN‡_yzº«äSuaFƒñºö>AwÍóá}›‹_v'íÑ6u«2•+¥lqÛ*ö4ü8‹l‘€'g¶3ŒÌ…ÉWB¹½w" ì»y*¸ñ¢É•lÀðï�2 ÜZë¹}1ÑŸŒ}¼¨b Í2úÅžºÿf�a.T(Ú˜W–ÆoœB¦Öÿë2-7ÃBMFÁâËËh f ÷áJv‰;°^ûá²êfÚ²`?µ±]L$*•ŵ*ð´÷K.®güjMÚûÕ‰*Zº™çY;<µ*ƒ�‘„i}±8JB‹T–‹Ñ§� ¶Åþëo³(œ¹„ѵ.~†|/5Œe/&}g‹�*àúÝ�`Qp`’(ûCcyD[Gm꜠@›~}¦ã×Ò!PæÊ?qc ¿sÙÏ_Xû¡ø0Í .v Îëf±™Nð9m?]øJ3 žã–wºú\Þ4VÓËËNÒm¬úµø—²G'ãà«ÛèO,Bë¿>ìÓ»Z÷uˆ;úÚÞÝâoû-÷ ¾H0£bï nÍÜxôØò�;/⪱̦|+ů ƒ‘#Ù¾—ù5Iÿ%´þšîÚ¿æ4÷£’•Y4 Ÿ=“A ±OLáD>ï�煬ż“i÷ÜbùrGÐÐ¥šÂ¾íÁ”uÊý9‰U«Þ&kŸ¥žK¾%\@ÞíßX|•&-Ÿ4ÒT³(^Gƒl�ö²·ž1wŸ_‚O«’¹¡¾wצšÔ°p;ä®=Î,{#p~|ê,÷ƒY¢ Ì yÊŒìCËKOXHÂ\Â÷ŒÏ?‘ËïØ`C8ý| Ë~tŸ¿ò� ,i‹ÃNÌ-OãfLW.£$ûHþ’B$,ßa볉¿.›Åö²ñGÿMìS�c‰®¹dºÔ ÚNc—«&û²!v~}€¡ií‚tŸVk—Á¦ŒÇ‡úôTEb‹.3O£—l÷BEZ—?„Ý&#Ù*-sÖáü¸Iú�© oJ% µY Fõ�Ã’–z�)‡ÞÌ¢âV'i2‚¥Çå¨Pkj¨À�¶�žp$ ×¼Œ«$rÑ)Ü„‰VO ñ ±|“DûçÊÂl1üS«sœh½ÈS&£jª²Qä´¶u—Üb‡•]ðo»h¶ð½7H0å#4™Ï†?Lg¿ŸÛ€JêvÒýw�3•Pôw?" UèW N÷ìŒð×ã57’.]‚É\½²‡z~à*c-ˆœÌp¼xWù½+™??ÔïÄqc!¨FHj§•øÅ#ÄÙû°Î™Q0|XK½‹ ¦ïÍqj°Õa€3±pVï¯à™ü|lØ- ·ÖïóNú‘Ú‚Î=¡é|黬N h±Ž+�Ìþ¡úöips�®<ˆƒ¥_±iÏìØÜÅ¢ÜCiüžÜ÷Ç�msr¤Áîq¸Jq1ÝØÐƒÑ~JœßäÇthÀ¬Û^á ?mº8÷ û}ì$XñçF~ÿÅëØCŽ‘„­t~ùì/Ç÷ú‡Ø_‡è’\š½w°'Bxqª›|�Ô\2¹bÅ þ’ЋŽf{ó™÷ßòojGÁÆÿýsŒvö|k®ïÉÆ”o–4kw•œð£žòM$a[Hg^Rd .��øÆòn§BÿóѰn±9)Ùœ&…zyøp†e¼J~·3‡?hÖÎëä-XžÛóa¤X0;‘°•„–@Á Î�¨L Ÿ/FÝAùp¨¾•¶ÖËÓHµ‰Û†Ç2�ŽïV…‘§.à�Ð[° «+bðYá ~LB/‰³‚»¹ lsÙJðª|Îæ{ˆÙVÔxbÇóŸìçÚÓü£HŽ甲üÔÝLí´:, ¹‹9/£éü[gúOz ûýy¿u…= YŠa�˘OÚxZ©½—ùkÊ�Wáhr¾~ô~¿Æ_VÚp+z³¹ ÷7žÅÓÍéó_zÐÕDáé2ô53™¼ÞÙÁè±£ÀYý‰°ü¥ë{8„�ÕÅxä¶/T÷±Û6ÐCqÎéb7¼¹}ŠN̼ÃÖâ?S‡-ùkA`ÊÁˆC£©^ö0Î<²‘Vyõ39�ìÉ£vÖfÎvÈuáÔU�h·z ày;h_-�-†n$3H넲ü$'€„ÉðÜ$\ >f?m"9Û–E–`ÏIÓª¢Yßy’]byE3aV×fxV_CßO'ëÂdz‡r§Áëqà÷‘vë<Ìûy•í½‡ÝSûÎÿüµ”U•ÉB`¥­Ð÷e#Äw(A‰ÄX4qËÄoÿáŒÛã×ÖÝLjk¢àÀoä]®¦²×eàªÒ@ÙCæyp xÄŸ`üÚ0|ìL¯d�±æAL{_ÃnŽGOõ|„ã|œàj N&ÛXÎì•ÌØrªðÏP„~E©EO˜›H2éNn ßÜ:Ž_Ñ¥³…efEÃ㔓,U°Ž Üõ¡åò´LL–”§Ÿ"ËÈàëÖ3{Óÿ1\žQ!þQN{�RHCVD4Þ{Ó°K…’‘RF²£�h©”†–HRJ™)’Æ{ofFY¥*ä/²÷~_çž{Îsîó$ñ˜wKyÎD.<?O9�C›Œé~{+�8[ ª2¬«š‚qG�9B.Hx/³Œã릓k�~õrϬú…ãè32œ±y?M=.nèeо‡öŠEb!œ#Þ4ì¹ÿ.�¦Ì£Ÿ/q¥Âs!W³„6e® ¶ÉO@ߺK4g#özh$zÜ›À‰&ÎhnáO5O|Éhž=zߌ¤’‡sȨè/X.ÀÏ�åb°ÛpVŠœ§nÓ72‡¯$éÒdãU÷üÅœ¼8¶¿(]»÷6ÞðîêL¹ÌÓ¬Øfœjí6'eÎ0YÀò‘;(¬×y¿�ÒúfC™í`;°/&ãIÁ.)Õ‹ZøafENŒmÛn 3⦠a}TÑÇ4^8±÷E£û®ì/(\xi€�<Ìø§ýìÜö$†FÇU Ù{] BYé0]®-%ï×wlnNVæÖ�ëyyÀðK¡ý÷r¹=|UðÕn ¼Õe烚<êeoôH;?ÛdÐdÂXg>õ¹lãf½æ\ÞÍóÇÚÀë¼™¤o�½öÈñQÿ¿pJ!�Ï—¢û1-æÝ‘¯ÇîÿÚe†<ˆ9˦õ&ääW�µãTÐjk´å÷…ãRÆàèZQ£1î*ú ãk±‚éï‚›|¡P=”þµ£®ò5úâù—Ü^ùAØš±pû§#·®ž7wËàänWöîèÀèC»a“Ömwò½ = Ïú¦ [î€t„š‡fRÇ5¾…|íVT¤÷æ�£> ×¶v@¿=�øÜ©Š'v­æ—%Ö`°?§>‹þפ á`ù\þd»tOTBXûFÞ÷Ç=GóÖêlàèCFj:¸éc,FßZGs^:ð¾ýn·> =)l¾r+|U�¸/;a½Å\z«n�õy¥øÌ¤D<“»ƒ?èF³âí(0�ÿù4Ö]؇Îõ$ÓÀZg\ý®BÐT•ÀÏãëÅÊ5^p¤~ Æ*Þ"¥¦c0#J {qKDRÍÊ%‹Y)ÀKB°j×ê8Ù }ˆõ¢ßCÛ�-ÜüÔ†FÁª¹U/LiÈæFï�ì»7‘®ìº!TÚ¦â8µNr}Ü�œyø·‰ô<0C‘Añ.t֋ÆÁƒ(a÷¸¸q îz€×ì*ªF7[cäæÃ¸©¤YX¿YL¹¬Î¥SðÑÅIFi�ð圚­BÇ&j±h¶î8pžÛºÆbŠ›À÷V$c�©!ª-‰á‡ê´¼Kw…îÁÉ[žÛ´œ*ÅKýöÀÚÄ'\rQ ¯ŠþP1ü$_-+€Um�‚‰a½–ŽŠqö|ìë?®_>¨Êo i /Ávóí0M·/†]·ÅÄ÷K šSé„O$[¡SYÇõÖà�“gqûý@TK»*&hyiT\O`¹òB�À…}fQÛ¤¤Ì¸0¡&Éh)ÒO �w÷‚äŒOÔzßYLß·ÛñPi"ª_ìÏ!’x­8TËñÐò½|îСR£^Ùª7CQxðô$‘ýŸXÊ™ì/j¤ñÆIìàÆëbõÑÃÆ°³°+±´µ‹¸ÛæD�“þÇÖ>7¡+ŠÇ1sé¬DéɯµEÐV4Â`—‚ùÓ*>(•‚vîIpov-Z…èàÒÌ}l¿®k¤ s´^ÀÙðs¢kø%z8Xž‡%à£P?Ì.¨Î™a±ƒ &-6%‹æµp§P›U–í¤[9ðñô Ú¸x¯ÕÈ4’ÄaÆ‚×ÎpÈwYŽ-..¤ï0ËÝÜðQ¤?:êØ(”Á’Àó˜£ñ„dS2!öâ,ŒÝ5#ßÓúº tЬÙx­"êkx=0¢©­%<±×)rˆÀ¦XtuÛN£Z¸Nè�Û�ÂÑ÷…xøü2~´l=zÇÀ`·Xœt>9Æ�̼G¸ÿóM�– áK?“8Z;Ÿ‹*ÿ‚ì )l¬–¦‹„ÐkëÁàO3ÖI ì—.Åy;ñÐû«¸Ò* çv³M�íwXÈ«u¸mOg�ù-i¬lq¦î’{UŠ$ø<3ý“Û0åª+-?2‰®x¯å®ýk±õz ÿ'iÇÏ•ò ;¾1꺭;‰�×eðZëqìtÞO½ZTØ¿b «Jä$Å*.ï_Ca+_‚¶A óë§Bù+sT.Á»b,ÑEùÃÕk «Þ‰%7{ãiïý6ã§«ByD>·\\Š?¨�Æü†Ñ½íiù¢Lüïó|Üø-’½f˜ˆ9>ÇHý¶™ ráô=†Lt¶‚ýáÆš±rÅì}`šÞ-Ž•cÛ„8|1Ýž–~;€ë^M…¬isÉC{!å­_ÁÃ:é}q«`=´&šÊÓÞ^'_0ŒΙf`dgžá§‡í-£ñÌ >1"‚íŽOýZÚäsäÆAv<þÈX2ÈË$')ò Ý…psá>œÑ`‹2 ÇÀqrÂáBþ£Ên�¡�Ë­8*ðÿ5}&FFlj nDñüïö´ÍÄ’7ÜýÙÖ©5e0ákÊ@CõT’÷Û- ª9 7÷͇Gß¿[IÏMB­½ÅÕð¯Ð©õÌxž”gCãŠ$éyâQêN !Ñj+]Ô ä÷ýq…Ëþ±Ù¿,Æ)ÇÏðà ÁT™6 Sö’•N(�ßLÎÉ ±äÛÔš¥êm5£o®�ÒŸàrO›X¿K .=%�]óiÐpÜg‚+òbñµŒ*§…ò²ßÉ\l‰ØôP‡ާqå.tñÁOØ�NÁJ,Qö–´u³ù½…�ÐÿW$}Ó:@“.·Íá%v§èi¯‚³l›iæáÇmªiÛÀ¯œÝн5†O�•IJ¯ö<³t)çJŠïî‰7Fàey?ؤRªžz8úY~)Ø-lú›Éo«õ¹thœèêÓE§GáÅÊ!œ5ßÛÿ¼¡A}±ûˆZ+DÒi}¥Úˆ½Ž¼U éÜ«1tÃÀ‹[¶�ß‘•à™Ý‹<†wÒ°~Tê4‡Ö˜ˆé1<¹¸�¤ÇD r?ó½°vzyäuÍ�…Ñë„?nᲸ¥ôIbX̸E+¤|0¼o¬º¦†^Âq“mÍK’˜šõÇÙ3èXöšÅ�…Têº'éâH¥PÐ;‘ƒ/•�¹~1ë}Fþ»¡ÕowÍ•„dÔ÷-á£ïï’fFnÚ/ÅR³ªaø²Ý4¸ÐœgyΤäö8Ö¹qšÃBÇqç<šóÊ'ç¬Á¤÷•bç‹o0UéoÕIa}Ÿ]0?\Mp)CûJ'ÓÀ±ƒH·È‘òb”±rÃS·@»M¯ É+ŸÐ�¡)°úvì›LcìKÄàÌò[z�Úõ¡Wäv웂köá”{™<°Ê»ÊF‚Öªk<3ï;Œ­ÿL“ÿ¤“ä,·³'çëTg6Ïú”Ùª�Ò¾155-xÂð·ìû¸çO„Фƒß3–àTŸÙ`ÓÍwó�÷¹÷T¿‡õBxØÅ�T?�ŸË!“-Õ¢ëGQ-N�µ/:bÎâ Šs:¾ÒÖl}T %4ÕHn æ¥û_PlP ç–€ü�4›·Aº’•‚ôpóà8ã¿íô£<ŸðP‹Ø[ç$ûÿ=O22¬�Èîº_iaˆ4›¿?.Œ�;•ŸÊyáŸ�“¸²Oµ•�‡•Jò$ñjÔøÏ…´O¿h×I”}‹nÌXIÏÜ)33‘šçõ„™¨tp3ÊfOåºåIö�ï*°o� ÌÈíä�ã „=_[LÅd›&Ún>'Ä©²ÁŠyè!³¿úİáì4}Øx�¯·ªG�úÍ®ýñ–Šž~½�3àúŠýè”y«§%Àü'?©âr ˜ÞŠÜ.ßbz§�üº|Ãf?ª[ypº$ðŸúÃð)¨ºæNà�ÂmažlQ‰…MAm˜mñòÚã6ÜŒ?EaÕ—/697«Á‘§â÷éáüw¥7:ްYxxØ`SløQË›ÊN±ä(ŒHôÁIÕ“ñøX'!)Y�Ÿ}ßÌ’Ë¿Còuyjé½¢_f îÍ4íÝɵ‡ñöØ›0n¡1&ŸäŽ'ß_ÉTdð‘Z"úðˆ�¶¬^hÈo Mø£wýgyV¼$÷RO—òÓù¡ìà:�úžU@ÝaµðrÔ´„ºÚ=ØýÏk{ߨ#Ú±ãYÂ+QœÃûé=ûé�D-ø^ˆ¤%Í(¡s–8Ýõ©Ò‚iªXœd råçp¥J,íŽ-†˜ éàRfˆ#üFð&?ñšË+ˆÝ£„÷Ä×xÞø7Ó_ST9ªÄ¯LÑw÷MàÎs¬µø¯RW`1âÌm‡¤GM§ܜcUÔó²ì¨çáš7÷ÎÒÚÀ“|ûC7�Q­ƒÅÕ�Kbû`0´M�¨ð0~WÅú âH¾É‰ýFæ•UûaØähÜ5[®öda*X;§«î¢@óHººù -^x„k‹4p^ÈCˆ6!T­TAÏôäôv�zÝŸ}{f,¿—àdÖ^Ót7�6ÈÏáëŽJüeÂjü³» ÔÌ °6w>Šž�tòÜ*úÜÕFU©ðÇx“Ú= ¸`GÆÙHð®ùžð«þ¢Pg™ òÅÂÑäÑ™]Ð>DÂvšoÜQ ¤éwÁaƒàÂtWS\:æ(x§“ËÉM´ÿ·œ°/¢ÇžJø\Öÿ»Q@?k5xõ TpñFÒ§ ! QƒçœÒÀAË�y~å0<æåÎÊ#A‡þk¡¥ÊWxv<žåWeÁÓAšh4ò$Þ| ƒ>ô¡úO»A÷Zª�â9+½©Jâ}>÷�6k£?¾¶—•š!¸Í˜Ò.ÑÔ«…p&Ú.nªßÂÚ`g¬xŠ´G•и5™5ÁÓðó¬.º”â >nʂǿÐÛrªÙ¢¶�öò€p“t®–žÂE¦ãã_X»7‹òÎ/a#QšÛ†îD›éÓ(à·Ü8fÏïžû¾„×1ë­H ®¦§#Åᯀ‚gØdI´ÀÌ—¢rª5ÜÊÉ‚ÿ2¡b³¢À½ŽÁ‘W…hß’ 5�~0sÞPNÿí…î2ˆ;Jù·�7ïHáÒ“9ôî�’èÞonèZMžË½¬×Ot¢7…2xSÑ™*;ô°kµËŒ’å5»grÈ'E¬„RÞ¤-m«zÉŸ?JPÕLN¾\.¾ÛLkõ%¸£ù¦x¹Ê„›Ú¡Ú9š^eØT8¸Óí3pñ¿ƒV¯„ ¦3f —UTiç,#,°2äg枺ƕíÍð‰ù¿¯ˆþŸ÷ñ�Îç‚ÌCN�J¡’ž©6*î!Ågƒõ+Iáwz%õ)=LÖ†ðýÐfÁ³ ùÝçñTúÏ»Ÿ~¼ƒ-6cÀ³>›Ê›aVéaø]f…ò7Çs ëx|ä»®´ ¤ú@=|dô�V_\d=uÝ�¬s"!µ[È6?qоX—ÄW& bƒFYâäÚÅt'ä’ tÖ7s[â’.s@©¿ÓøfÒ-8pÙÇÌ>%>ΘÄO½ú‰xt —5¼¢"MSÁ%"‡Ì~Çax̸o|¯æóÄ]øâö>Þ4]’{!ZèYr™Q9ÔÌ~ Ή¦Ø8- þD¨@líuîƒU/eHØ5ÌŒpØ|’œcѹSxŠÉ[h��Ï9µ:ørÈ4a}— ?/xH¡þk@Ç*"4“D¨&toß+¶”Ò¢+^èpk¶TªsWú.x²Ðã+ça¯,¢ÀEyWíÈ×Ú 6YâÄYO¡ÜEŽjÀïFí´–­óa5yu Ç]7ßØÜ pgÍÖXØîdÎVÿU:ç:Ìš^ÞËZÑJ7d°Ø»~ «4KZšáÐüÍ(ñíOÙR Ýwp©¯ÊÌB%}šÕ~‹ ÉéñúÙœXt ª%±¦7Ù�ËÚfŽÜ·9fê¢=‡V‰—6ÖÀYwvð'(9 þvÿ&]Éxñ}O”S›Ê玞 {ïwpŽÁœ»{è‡âqT™Ç’jpnÅEˆ©’†{oˆ‹ŽäpÀΚ¡×‹{ÿˆ�6Ü�â±ø÷ä·²þtþÛWyèS ŠšÌ1Òß`ïÛX\ÿ¡“~eÃýâ­¼­± ÜÆuy*ì§BömJØÑe€ÏŒ¡ãÍ8~£l¬ÕOÅÁÙ°n®žèVÞÌÏeòI×T8'1 g Œ­•à¹ÛÚ(ùqtU¾ÀqŠH^,Y0 ŽŸø†’fY\ß7Nø¿„Å·ì8fN-üú€MœpÀ²×6'#}iTíEª¸½~<«ä·�ç oBø{HúV.ÂnÉ©—|þÚ ZU}�WFWãè�ž-gx¦‹M̓ĵ5³¿/Ã%c1³ä)xß}Î7gcóœ‰Ü9R‰›mÏ𿋬û§˜/ü‚¥cΊã’w¢éºY‚Û'5ÔkÈ _m@·K‚lž:Lƒþn@mÇtÒÏÓlÙbágàPŽ«pׄx‚Îpiܰ, óß’Ö±�´fÅTœqu6/ vG·UÒÇ�ö[¸Õ|xÞÉÕF/…–çg(êdH�Ïw˜öjvÍ»©zdX²‘¤/ã…šh·ÃЧLkzÞºy.ÜR‰?ëû±q†›Pèo�ïŸêð¼®Hœr&»7† Òå�¸øg>·Œ2xÙ�F2»¿¿¢�ÛR9Ùû´°ðÖ)¼ù^…gfj²Õ~ $�2Ü“B÷»Òèg\ƒ°úWG ˇŸïUPÇyV…âì{yÁ‚rQêPGº)¡ß”¾lÙ�ÃY6“1ݸ¼´ÇÂþ©Z\¶ïºð=g1ÿà@I†CñääiLý”8Íñ/(�Ð!ß')à5û(Þ”‹‚‹mý Qæ. ®.á™í$\•›Í“þq»ëïBn�”ƒ~ýf ¼Liµ.�ót8–—<�¹7Zh¡ú–QÈéz?hió ¯ÂnþøÛy3^”TÃKë�9ìJ”WK!‡å^ÂXËãä0Žï{±jšjMš‰ rq‰cn¦7å\Aí—KÄЭ²h:•u¦¬â�©´Àí0쉩9tö WžÍx­eßâáh¹óá›ék¸-W‚ ­âj“<¯ÚQ¶ˆú>#A¥Ë�wŸªq3˜Ž¿b†rž´ŸßöuW·Údÿ½@�CßÁam9~Q— º�U7d„óÚqÀó®4-k¦ûR |Ðs0çÖÎÇÄår¨vÁ—W9]Æ•s†¡÷ó£Ô5ÊúÞ çE#΂ñÄ·âêÓRâÁÞ_[.!‹0¡åû°¬¿>÷^‹šóŠàvq5½;¾�º¦±Ðõ b’¸Ûø'½SYJ‡9£ÝÒ^0€K'–a¹MG†Ëð›äA8â½ ŒšdÌWK— åªÑðÊô5ey£‹uHµXUóÓ.þ`¥X“ÝmÀ›f~€VoHš˜Ï~°·ÉȃA¹Õð*Y(¨.'Ýùâô…p5)ŽÅ.Çr�@óÒ‰¬•uÞæ¯Ì7’�ÉAÜ8f#KWiðûV3ž±¯šžb‹ˆSÕ£^wS…ÔIñ¬a<�wRÄ‹÷$9ÞZ¼¡ÄÉ›@bàó[ÀiÒd6©�€×GãÐ-¿�,n>§ß½,13]Š&L)³•�|7ü §|¿Éî|}J*v;ò§³×q¤D-‡õ�Ä�{/…G Oñ:½“pÑ?'OOvezà©m)°ÛPO(lþ7Kï‡toî\ñITNµzU)§„Ž×]×k\å�ýö³UEü½\ÁÅ Eý#…�*ûcóê0²/ÞûÛц�*u‚³œ’ü¹Y¤ØVNë¶Öcç�AÅV”òL”ãÿ€ìš|öñ¿H*^a}!™7©ˆìöZàîïs`ÓYsòÈ[�ëxžÛ)òŒ«ßàð Ú–,äánmÐP¨ˆEŸ•QÿÏzµ-þ»àJ·zñ¡¡:š»Ÿ-¶c­-›ô¡Š(+qˆšgXã5›m{±7ÇÎ)æÈ~=‚ùt%¶±K­ӮȗmC7i€e»½Ñø“5µ�Ù‡‹GfñÑ­Šô÷îTîµJ‰G�ð¤)=)<¬é9í^IµsûqÙ#n¨ûHû^N⌶ßÕ³tƒÇ»�ì{&ŽØ¥_í¸9›±h•‹áAÌ>BWíqöâÁðÛÏ�=2ßÐI…÷ÔxL‰›¤ó¹ñŸì™ÈŽvÃ×Cá5Ï#¦ÀÖm�|ô«oí?^½Ñ!“àFülÙ`£òË„ Mxß�q÷ù¢ç®°ã8zÚÖ¿â"aØÄ^¬=c¸pìp"òŠÃ»ÙØïÍrI+¤+UYÍò.]P¼ Ù÷«8µé1ˆ–cØ>« úOº ŠCûâ  1§NqlPéöÑÂsQˆѺ«P¦×_"Ynw#×ïLá÷Ã6ê‹U‡ÒØ«ZŠ[n�Á£-çèˆÙ*>鎎ÃSxõIåŒÚî;©qË6–hÔÁ‚Ïrä½”ãF£ÿ¥üú¶~~0Ž%›’¹÷Ùë‚ìÃÑcê@¬Š½HRO¶P¨}Š`u@†(Ë≜»8à²!ß¡ÍN!Ðw– ç~yE5÷ŽÑ¥H�¼#�®[+©8,E¸Tt’t©á+» 6éƒ!qK ÈÕƒ•Mà°«ÿAÙðÃTš‡f-ŒC8æ©,'½…î}”¹_ÓKAn:S’Þ þë°™{vݧ�jz8ÿRo¾®)¹`AFfVøiðwð”6ä±³Z(èPtuÌ»‡À²í9ô#ë<ï|c¸êÇÐYkÊcGME‡T±21ýìËñžv ¾Oõ…äFeZ'ƒUÙ¾0u'¬ûCc ÌE´‡šá؇ý9Ê|.¾2-„—{а­¼FŒû‚—#ŽñbµAÈ 4Á§âf‡% ‹xRQÝÚÔV3`K*,Ù»ç×·ãÈÛ£!ô@öUn¦ÊÂ�Ô1pnR/l_&ËaG–ãÆÖÁ0óÉ$øïŠJûÏ ó%vòšO éѼ]ŒÙiÕñšïàDñn1¿UŒ¸M‘9Í‘*¿Ôð‚Koª‡›•‘BÏH|\äŽ�öMGí¶|-u�nI/ç=Ö¬xm£î~¦•Œ¹ÜaV€u÷×ó×Y—cŠ…ݸ~DNZ’ÄFuÎè´­�ó­–qý´"Êl-dí;GD·Ûu´|Õr”Ïq@~’'< ã9~86ß¿^ÙHóNÊqžþ6ïµ Ž˜.ÇÔÏÞ|ÿH ÎWUG÷ê+°Á²O;ÎâG–;ðíÆÓ´úB¨0!P‚×O”Ê: Õl$œ -á2ãL›-ô¨¶÷.jž¦�‹žŒùîµðº÷e µÝdž£X»�ž‰õJ¸a¥6îøÝHëd¤!}ÍìîùµõTäs€´ÊT9ãöPܲÈ`À!´W×à?y‹àLèúñÊú$ÿCGSL¸,~îE£Ö�>†§�þl[Nø}”ÖOåè^ɼub1wmHÆmÜ&Ðv¿Xñ'‘Ôú§± à±}ßQ­Y±˜³ª™•ÛËàøàg63WN#§7�zÝ÷�YÒÆÔ‹Ó¿¥Ãõ¹1Ç7ó·ó·†!|Hržr{E¥‹ÃÙ%�°)÷2ØV š+ëˆ ƒÜa0:(ƒ^�Éu¹FÌ£Ž FnïD±#�÷O<ÆΆsê”tÖöÈ­ÞS Ý{ ,ò7‡mÏîWŸ^…Vª{yó_Ä.„#‹‹yá%?¾ð=E0úüoŠ‚ÄϺørÉKJjŸÆ',œiÙ$\Ñ-~S87›Ú¹:»’N‹AÂ÷V;šq+=3Rx«m4Ôߪ #_,}Oæ=·«8T·K¸z9´f.Šâï-Gx±¤)Éií¥˜ãµTñ.œR|ò!»{‰¸cs…pÎC•#·Û𧌫˜7(ô9+c†ÝŠ€m³çRí‰Ç`ç�ÓŠ•8øTÄ4>Gå-BŸU^¸â„9õ¯É+z©!¿”fñûTNœlÉË[ÍèÚÒO´ã—!8ôžˆÏƒÇaÊ*{ü¦§Á›oÕU�ÆÑCp€fšÐ¸/—Â5"YW3ÛV+pÆ–oУóRÈ~4�­œ#ÍKæòÍ•h–¶„>¶e‰Š£µyú]^l¤ÍëôCpß™u‚ì‹hTê‚eåIt¡mlqäŒ1KðÀ”ðJ¸ZbçºòÅi÷`ëØNÒ쵓Ǹ`rÄn²ÖŠäé·J(u³4Ž©�á�Šîèÿt‘Xþý †í3ãŒc Ú¡}ì ÿJÎ ®Z9Z6y/侀nÆ?w×ü*ô4~²]TyQ’!Ž�ªñx5Þæx�)ïß­Šoƒ”xtÊx¬Þh�IûZ�•ÿ|l¯»Gž››øs‡;ç¬È„�ïêÉO£Ì7™Ðñ‡¦øºe-8ü²Œ]ÅK×mJCÍÑ2r2úºp¿i Âo÷q°˜75²ñ–mØšŠþCþ»¿³:‚ü·øaË–5œ»*wþýFæ]ËPkÜ*Úy)Î^¯&›!}måîL@ÙÄ@û+¬–zŸôåäѹ÷oˆRbó{Ÿ¹M—+î›’¦DŒõЦqË&ãâ}˜51 ŸM—à¢5 pêÄ$høÏF¿g_yÊé¹wi›Ãœ­}?ÿ(ä~�î çÌ6Ð¥7°PÔÀëÓ(4æ-ß/ч^gûÖ&ô.aÉT=\˜j¶äÐt£j æåuQÛ§ð2o,ÛítƇ_M¡ºDúµÃß^#yݧ–.„^3c»‘I0¤ÝoôDñWãß|C|KÂ}+òoÑF¿±uØ¡²o^UÂKfS( ú¦�ÎÞ|?¹”âµþŠž›þyFûOÖMÕ x�~\¸ˆfÓÙ’X^XbS \‡ò‡à£ïKùàkÜ3.B̽8 û/c¯Ÿºx3!˜*=¥5¸ïžšÌJçg±éŠ"èëýƒó¬Õ,§‹U÷_@Ø¡rÚ¾æ/QÁÖGnbCX/Êß´†„G³R†ÚnsæŽi,u&îH5âžkcA1$Œ·éñ�âSÔž[O1Útt@Æesvç1qnêP¸Ò¹þ¤x}¦KPcÐ:öÑŽcÝ5ö_Ì]_GÁ/k>ó…²?ýz��AËU‡qVåBök�%ÿìË”½-ŠÓv@\ý:Bs©c ´\Ð6"‰4RÎÛÞÐ?ã…¸ro u–ÕÐþ—hÏí›´ÐD�CëäÐ߬¾;Tc{ï~Œ!iÑ›f¹aÒ×%ømÊ'ÑÚòúìë†Ê¾«Pb°­ƒ-£qS_ÐÞÑÊä4£$ðй:¤>ŒØÌ…œÒV|úÆn aW|žîJ³�,åkæü­ïIl�Ð{]¦fý$ìŽð§ŠÑ¦°xFŒÿ›‡‘`S«%vþ‘äøY&(÷v æî¼ÃeŸTÞ�Eó¼õÄS+wó§sLø¸�º÷Å×óÜyqŽðmh2Ýܸ‡žz°0õê ›‡¦³å‹_Â#u°"-”=}6âªòO0|–íÑg»hV4§o˜�YçÆó­ã/È£í É•>¡¼á45W½vþmmôº7š Ïjñd‡­Â6¿³¤WÔ‹¾eý"�;Óñà7/Ni±ÀäåBÿ”TŒš¿­fEÙ ž±yl5ëÇŸ7$ñò¥·øÁÅm¢XOÞ‹ËÇL€Ÿ]²¶)âûî41#ªÞäycáør\Ý �z#Tm½å_@”ÉGüZÌÓºáÎýyü$ê<5<�ÜÃ09sªŽ¸NŠÖ½ñ³ÝaŒp‰änùhqÿØ©‚£ív.-qßhUräVH�¾;�¦«Ó�âŸ[CñÉ`�:TÆ.¯H&Üî[ݯ�{×Yã¬Ñ¿ö4À�›wrZOª0aþPÚeòå–@ÿ*E>|Ù–öØ�ÁŒc1ðyëm˜Q”ÂÙM¡Ü1«ŒžäD‹ÞÆé\¼r-|[耕Gó .(¢«¢½òj>vA’}Ç IÊÅb‘£:ú–ÈàÖ”û°©Z¦Nf•ò3Ø')AÆP”ÞIR«Õ±Dã© Ú'ŠO/9B¶= 1åF,†^kL¼E9ëŸPƒKOÍÓ7wkŽGes{Oôü7�'nàš×uÐx^“lR úvCq¤'�ûùšÎfà7sxÀ¶‰P?Ý”«æÎ#/aÖûB¬ºPƒbz¡Ú¥dÚ—jƒÆf¼êgiMK޽à4[— ϦVûÞ­Y€Ÿ�çÒ¬\|k”öoUYí]>P^‰g¦àušðô =¿ Æ‹gÙ[ô'<“Ûì7¢÷ut1zò'V£¦k:uá«mÔmŸ"zœ´£èñq`Ïažî{ðó•áÚÙÚ KÐèì8êÜÞ{×á„ ÓÙê¤BÍe“>¸&Þ�kJ±¬É6[\A •`½’k×ʲÂßÈîíuêì�¹�_@EK ‹ÎÚpES$=ØRI“Þ¥ñýkÂé®ZLP9Á|û¢ÂÇ/ ‡Ê¨ÿ<]‚‘RcqEe%¹LQǸwøAÛcº™ß*âmG.‹U[ðK4Nq”ÁsÊZØ�×((ò•ç¿§V…ãÆê^èób&ûÖ#kF­µº2è.�<=§]OÄȃjì8~,v¾ûHý•Ò(zkôNžÌBï~¬,Ù‰[õpµ{Äø÷4a¯ ? ‰f½ ^(�•çÑ4� 5¡CzÓ­£¸G�’fã¯[-¤ZÙ�/Ç÷ÿ¸…€¦Ý_!H}¿lŸ 7 ?ŠWÜ#1ðÝT>ï(:*®u �yRP¾úñܽ÷Vx¶)‡ië…(¡¾b1ýšwƶŸàéË…-O¬xùÌÝ<°ÁŠÿ»÷¯¶ð¼AþØ.õ‹ôìÿBµ‰4¯ÖÒåâqmb{F2ž$#¸àr‹S¢˜ É+��Xëz=´µEñσ�ðxÐhf¹K04/JŒX"…�Ÿ‚Ñck“àüJ‚¦CÙ˜©<ÇØ�—O/Å~svòª‹Uà~Í>>À¡³¬±½î4.žOyºêsZ Õ ùb‰8R2ªá¥l�2ÜÉ#¿,溫‰T¸GĨߨÍöé¬Óã:õ°nÓ@x¾M¯föÐXÁGÚ±®:›Í“rÙb÷šýô³(õ@Ï ¢7Öå´å  L|¿ÙæEy$Ùù P<™œ$hÔŠBv96+ð†wŽœª´o½M_YÛÛ•ùRßdܘ‹Öƒ ñš¦vì!ã[7y•…!>Ò/Á&Ÿaà¸> g<âÜ"Þ�N¤#'vb�d»M¬%1”Ÿëçó©ÃʤõvÊÎѳò±ÛEó¶ÿs¹ûãÐ6ã •¨ÃÄŸJà¬ËC�„€‰áôÎ,!ù¨8”Î�§¶pÖå ¾^Ú Wþ'‹![´m­ê÷ƒjØkX¸7¾}Mƒå{b �v1λ'J>ÜÈZµt~|<¸¥1M^⃎Þn|¿Ï;žw@\¶m.ÎkìS›p*E0‘1᱉²Øã9…wÌR­Ú¤»4âñÂÌw0÷X*Gg¼§Ô’&Òu@8©‘K¤Ýž: µçG �ØÞ€¡µO ì? Ú´ Âz'½Â™àˆ²ã¥le¯w Á››hý­ÿ Úî‚ðqÏp~í¯Mºïc`ÁÍRš2R‚g>ÞJý×?�úÖdôUîÍ“Œr9¿6_OWà¦y/9®êgUt«! ~D*·Ûlw5a¹ßàÜõx°q?æµäò¶Õ½°ß_ê^Ñ‹Þ6‰É“þPítŸt5—qà–©p{oíè³›gža¢›«éâ¡Üáœ!¯‹›E™Ú3“³HT^Íècv(†Å¯í?`S˜(œ”g´®´q¿àÊ?¶s¯5c郌5ªôϬÉ|,âÀÛ׸hÑül¹‹G̳ıé¸ënýø×·ï‡ŒŽ.Ó ‹r&ãëCj®t@eõp\o‘Câ¾êà‡ÿÅφx{#¾^¤'¥Jò¼Ò=xé«/Ù�‡Þ·r¯ä…Ôu´?ZíãÞ«Ç±Ç sÇ÷GPÂûËä·í f;�†¿Ç3`WÜ î» ��xŒª ñ؉)‘–üdp2·y�ш|އsÈÈ^¢üÝå¨Q»»W ÇquW@.aèªe©9'IÙ ‚‚¥f’æÞG!Fo&uFÉó±„e¸ì]™. Äëæ¹ç^M‰Mæ™aÑøä‹î?®EÝ×Ûy…Ý ´™¼€å�Q¥ÅÊy˜É3 wp`¿Û¼»=ô><†¯ö±PŽß�ÇÞwÆrñðfà Àá‹VÖX.‚3â£^¼x»4Zëê�÷Ê<§ýä)ã}—ò©#ñpºO §/ÙÇ*÷tÅ736€ýŠDŒ¸åÊuÂr¼4FÀ-æ�ÈúQ&ÏÔÁ;]þ¬úV‡ß7£ÍùÛñ‰¹7nú3ŒÂº5ßÄ8•@~ê«IgSûÃÓyŸ½µEÜ­*Y»7k ¹¾[ËEi…(�rÀ¾yÔ¾Öï›ôÂÐìþèQ±œCW‹ú##h°Þ nÿš€úÓmL”¿Qš¥7ª´ÎÅ¡=ÛjŽì1 ÷y¦¢£µ‡¼u¡Õš/aÖºxÜð¯©åÕ( 3ÅF¸ìõ�ó‡|§ –¼yÜv!8uîúŸ¢óþ éÿâ¸ÒŠJ)RÒî¾ODFi¨HEIŸDFÈhu¥"IdU÷œ¢a$d%QfÈŽDÂ×÷/x?îûqÏëõ|þpϽåÁþ\8ˆU•Ù¨…›Æ4à·B®Ãb#·¤òS¢Ý™àèç°cžÐ8%Š5JD=gŠ7Œ%…G² º§>‹B)îä¬rÐòÐu´]s”ÅKèà”á¬åv4G®äg’ÞîYÜ™ú8½&¹‡&̦¯+FAø\W<{)“Ÿ]$Çeéäôå÷ó•.¼?BuǰqïŠ;óŒ:¹¿û }Ô÷úk ÷áPÌrp‹#“]³ha‘8]µ.rEÇf1ƒò³ÌGÿÍD#\Ϙϛÿ–Ç õÑ´Ù\Vf«À™²0~R˜0¤ôÌ£%1`x5É\Ë!]ÇTÁ‰{#Ì`ù9T±¯„˜ ‘ÎL¥(³© õw¹…Rð‚dy—Ó°ê8šroÑ<ÁÍí5¡Øö=x¯¤˜8Y1j¨9 ÓÞ[ÃÛJôæòxôŽ=ˆâ²™SÞ JÞ’DóN«“Öw°öâñ¿—Xx¡HyÎg^÷èÇloH”láv/´„ •¿XæQyðØ1P7[õ$ý Œ`mw2I8ÖŽF‘â"_tÔ”€Œ‘ÍŸ¡Ú&“ì}Žq‹/E‚–õ;ÎnÒy øu ÓuxÖ]±›žÝ] eÿfI&”¾ËæòÔº±f^/9PT¿÷u¼%½Ofs³Êîоߣ錟,ˆé–cýÝ!Ë! ¨5YɧœKD¥Ÿ‚VACËiÕI5òÕ©ãY'€ÿÓÂޯ裣�#˜äuvà$œ|aFmöBǧ |x{-¸ÊïæÚ6àëöÍ�:„îyR 3Fê ¦L,¡†÷û7ä�ĵ-­J˜#j‹6fæ0npNþ:–µ~Þ7�^X5¡ãÏh !Ôêt”•†Ë"4Ó»Íäè²™j9XÔÊã·{CÌÏpŒ­±ån�É`ý‹méqX2»Þm�¥±4Mà5ëSª…]Þ¥°^ߊby‘=‹¹‚¾ÞK]š­�8Ÿé…`:§ÚLŽÓa8mr”dо±ŸõâKOà‚ÅÏÀï§ X§‡ µE­,Žà—3q²{ Nz˜FlåiSçDÚ­6�ÄR&“µÙeþ‹ÿt¬†‡[‘z›l.vír[¼s †ßè‹z6�Ÿ¥BïÇ� ^¸š½ß´ƒ^kè¢Ä_q½"vÄMâ÷ukƒÇiQ¶d°Ž!¹¢äI"q(Õ»Ú&Ãêÿ‚ÁÄ}¦EÚ×FV·ü*=ëe�GòHZ>Ä2½ö5Ô¹ €æžd]šÔ˜XÀ.Ö†ó~ÿE±sïÐæÙsÒ|þÖ·y œ{žÅw<Ãé‰Ý—»‡L’eÀ!ÕÂ}na�²s šO‘Ù‘ÔrEÙrÂm8Þ½„ž¶/€¤�¹´+No»Ïƒ�“�a­ñdÜûTŸeŽË`ù‰&Ô3–ìMÍøm:¤²–ƒ‚ÎÙ n ¢Xɹ¡ÄvæÃøázÅ·Ó÷Š5PpÌ Ä;÷@Ü£uÌæk0Å·ÕÁ¼Ÿ*¤¸!y÷v¼ê"½¹QÿCD®ÈÌ£ˆrcº%»ÌE5éÒ˜lac×UbÛ&I¨Lu×Ã+I,\¢aÏhUš‘�W6­dÉ¡X÷"‘B¥ÇóóþneVW;yA›a,²³‚ç..õm�.âi[bŽ×•©@-޼W‰qFéh�pš·81 L_—rõ ‚X¶Åf¶!=&š¾´ ÿ\Ïß›ØÅ-O9ŽÜ˧ÂñõšjXó�Ç ÃTÚüǘ�÷ŒE…‰É–¾²Ë©~P�¼ìÝ@?=Ð9l“—1«ø·ìyH>_z $ØCœêÕÎ/ÕV A[ ´�Í2e4¡ìu+>‡æ6 ÿg Mð†ì H�šDgýæÁ}øl“}0鯣™à¼i=eLÝ‚ï¬èOþhtÜöÀR¢4eª™¨ä úà{—þõæíâVÆÝ°èu(=¯Hg»�ú¡üÚ.ÒÖÚŽ›0—êG¢@¾]ÛŒZ™ŸßyŽ]ßÍ2"–SÿûH}d ínPò‡,ƒÊñ2�?Øt»]œUÍÕúA££üñ§  Ó†Ô¡(Jáü&‹ís¯qfî¾l¡n …¼ Y›ý¤üäë´ä»§N†ò‚5°ly»qHÏTײsõ²`1PÅ–¼AI¿ulk…‹Ú“ÉZ•ñõU}+¿GqìÂf©[ƒpžZ«7糫4ž&‚fùe¼é[Ðh‘‡§¶ H¹ÿ5×ðP L¶V‘t2‡SJ¬ù‡ÛºÃ±>š9>žÄóKàA´$ÜŒÇ×­WëN¦œ¤:UXT0ÖrëxsZ÷^¾ÔãéH3‹ÂйÀ>©í#Õ¡¨“5D©Ùôk“6*FE¢ÿ9sø>Z n.-Þ­20Á& …çRáLÃN‰Êmà„Ëpº… EŒŒ&µüQ`n¢„�3êCúÂàÜÙ†ýÝ'Éÿ¬]>÷„½+L‡i&Uܨ¸Ñ$¦¸œŸ=ƈ’ãóKOåYÒŒïÁnÚ˜uÿ<ŠTKCvž ×Rr�ª�0Fî·rxV\ØÌ54öÒ"öðGHK‡“�ÌM*[ìÚSiV¸5û-ÞÆvªï�æÕ©tÊÅ‹’eöcÊ8†§üáO}Øôh™¥©SKÕÓ3!;87º€j�ަ£ÎÓA×TúÚF}.8á¹ú¨|2†U~@¥�`%ÊžÊp$a¶"¦4Aó^+ú$œ U�Ò0C­›eׯPìHµMÒÁ‹#® ¬j“zL¡^ð¾×5…~+ØôùÏ‘ÙÉq mà€] ?ö ‡[ŽçÒß/î0äï %¾<Ë=n×:ïò³ßhÔ×¢iÖÝB¥:8ƒ¨VÒJ-rb´áôL fæ'¢Är ñ›ÓÈ28šôu×Ð%!&1s5$Y­§­î7qms;óvÌeé·;èèACzó�—”ÚôqY˜ s.US­(˜¶â/cÔHR¿ÄáM\çÝÖ~ÑñÂpÝï)·¨o½]¿œ[rÇŒ¦Ü0&oßò}½•i}GI©O¥bѨ‘Ô ŽÏƒX|j=ÿÂÜe²é~ràóè}úÈßÑ“‰éž¼~—/åì�¶¼«5€Um“(âôæµÈ�“×daSâ�`õ)­ÿ/Ï,­ Ï×&^¤Í�ý'� c—{°'[> }¹ �íÕ!Ù_ŽÌÐ#�“SZÈ|4•Mµ�Ë8‡(ƒš„�Nxƒs ©ÿ0{5É“©ïháŒÅyõÈ14üÚ î< £ct)"j"ÉØ'�бKd«TŠsý»‰kÒg«Z·bI‚>ܱvbS­vb­i>{ªÑMŽkt(´H êi‚Ò‹‡xÔ(š»JáÑ„|>8qœ÷>O�uálK8Ù9�‚ –Lâ– 7̆•o_£¶¤9/8q#hç8“šS,ºž"¡t«ì3†œÌb¯©¢Ûm +÷ŒßhÌ/zù‚íŽo†uâ‘ì¤ð2ð”ýˆG%ËAõ?9HتÀDÍ{HW°�}7ö²ìïi€å©›éÔ¹çôûêQHTϪ99ØšDUK¿�FM!¥ PySÌQfaÆ3a�d=ÓLOûçèû¹`lfûç“Þ P ÛÎ?\{Ž^xž†kqº¬çãé\À½\éJR:Ò4ñ‡É?æÐ¥"à`K¢Ï5ÈD:�(ÛA´ÊtîÍ/¡x´|ñ�¬Â#‹c9ßÀ–›óÝ76@“¤$Y,ùÀ6ÌË¡©Å\Îåk�ïp+¢óÉüÜcœðò#_ÐYÅ þÓ†Íð¢t)9´&Íħ.‰¬0o!è]ÝLÉâ›Èüøqê—þ }Ë2áï˜{\Ú 2�--Ùßa_×b×îÓu¡ãì÷/alZ-ªõ_¢š“à×ë�³TéAœ¬¬ýã9tG}—ÒÅb³«<\Ö'O>¶Ê $¥G²{á·]ìõ�kP¹Ùƒêü³ªÍo™ Ÿ O¥þ²ÐÕã QÊ�ýÝ÷—¦þ{ŽÀ\µ]e;‰¹Òõ½Oð¼ÿVl®zÄR"Ÿ³é-a°±Ž7ÒÎÄ   ÀÐÝ mPÁ^Zœ"éœzsä{uâ2ÎZ@ƒv^,/¬REå±òýn«ñtR ñĘrYŠ{ÕÄÈ'iJÙs7†ÜF»­Áöa(Õö(°Ö+vpdQ'|ÉúŽªýõlz_z™?aG‹ƒQdC ù8ç²”UI¬Äo:¿åÆ\et›lÃüµéP] ŸµBŒþþµƒô vu|¤¼,¦•µŽ,½V–ò?Ð,›Eè±7dk2àΜB¸)˜Ï·ã.™OM6ct¶mo~�IeÑÈþ>gOü×Q°Ü.´'˜&¬®àF\>â”ö÷¬"ö8¨@ûl*N=鬶³•RâbáØÚ B3GP§ ƒ’tup2*´›ÑÑ©W0õŽ=Ëo/gf#áIÐ3‹ÜkþÙd‚öQæPpó}¬(gòõÇieá ¬’ €_ÉOx™w—jm–v1¹?â´¾¹†Í�—ƒ¦ßâà^¹^«o‡G£¯°œöùô`©6§èdÆ’r`xêMɘJê·2¡èû>·™).ß‚<¸Þ"N‚1AFb7Õ¶&�³áãæ³¬Ê¼–ý·À”Ž›4ÓzàrX0ÝÜ-…²±ÌcÒ$*0wa5.®ìÛEl;HÒÂËaÈä/¢íÁIÑõ7I&²l½Çìð¶xÃy"ù5÷3+©!ÖTI_·!{º¢'ä®·LÎÕC�•[hªmÚ˜h°Ç¢ß,Ó•�\ÝÄí.‡['nÔCµ,:”IÁ®Šô.é¯ÝÉþ›×N7f€‡áwæ¾ÀÜšó6õ0é³ ù%¦°�_BéK’°{‰~9¬h½x§¸C¼N2Œ]}ˆ5vQr¶¨Uà’Rª¿…2ÛïâékGHZRŸEÐé�?ü1}*õу›Ü2Î Þå”Auá²>sœLÇὑXJ<˜J6«dñXiÉ~MTv¢­Cy(U:Ì¥¥-àu„ÉËé œpØ6©ÐÛ|Æ{cìÏ?xýu6ø+b›4VoR†ƒ£âÛåUd°MŸÆí å›8‡)PPq¿ÌÐ Êsñá;öÄ]ˆŽO�3jÕ”Ñ1Ÿ®ÔÒ˜ýõÂrÐìJƒ£¡ËzXF9ì T ›hÀo>š…*¼ýØì -Ûâ)Ê[›$sèê÷©ìæå3¬ïükºÑv‡%�0Í™`ãf)£P¿¤NûÈEN±…ߎ²´}¬6™iêÜ·Âpôn53ýð…æ1, MÃô_sÁH"š¸Å_™ÛØxÿÜš¥où;¹‰�‘:Âo�bSΠðáklÐÿloîÂzÿvîeº#Ù=v"׈*¼Ù—Ä÷ä&RÛ^I2ÖP¦…QcÙ"/O®¿ÿŸÄV?À=g͈¯ÃógÄ@𤠅ŸQæŠeòC‘Þú@K � ¤m«­(8$š=ÌP† ŽM|þè(rK²GÁM\ëÐ<È|8k4Riã|Šš0ž†�˜3f FÃ@V+ºéÁǧ}ÌûTלºæhê3é‚"æ5å‘å†ÂPÒêñdî/²A³ÙŠ~<úɤ߿2Ã5ó)øl¼êŽdš%(²q"&ºwâ†ÀJZ]¡I¦S©0Ì—9È`[ô«I®å%[s¾]r¦aKR3„µ·oñ³R,Øúl5ÐÓÀÖs‚ìMÁC–²ý- iÀÞ;¦ðW$ìn$`ë‡.Þ%ç!|h~ÊÙËücç´-LFä!ö*LùFm˜Ã¯¤é�s<‘í“>Ï”{žrWÿH±gãIú– ¥5¦² —LAo—.…~$¡ijØÿ0�Û5CL£1ø?q:kàNÎ R-�ÝôؽËßpÛiJU³`/ËçàÇ;™ü³%Ÿêd¯fÖoìq‘KT™ËRKZ®Ù݉é�­è_§‚Φ’°63÷&d0ͰÍ0?{ÿ¿÷ó³\­€U#™¬ÓDt~ÍE¿ìu$웇eÈ8ÇoüÙË3À#3ÅPÞê*m‹û„êQ£Iئ�û~âÈ…q\@t ͼv†y(ä°Æ­CÌõs«eý ⮓ßÜpR‚W’�ÙñüáoÚàM‹Þõâ£ë6=v\ZlgíçÂøW~Ô}â ;;õ4_°ä9J­Í¢«G°îÏ þÈÂ>|¼ ÛÇ• Ë…§LpÆ |~¢‹·É²ÃØ1¨Ø. q@6::(pÔ÷úãžóS)U9ƒŒ«cø¡Û9¸LÄ‚úV¾ÇMŸŽâ'Á"Ë»‡™èßñ˜ùL”¬Ý‰>¾øÌ]4ÛKEìI×|/„uŽƒò9 iñÇb&Õ¹OÁ,pŽŸ ëcª0A3>K— ãUrô¿Â”ïƒóªZ`÷Gl�çÓ�›ò´V(žÌV?fv)Ã�z§ŽÓÔ.v*>3v`—,¯+ÃNŠtþ,¿m_ÑjenÁª˜æÆ��Þ‰ô7dݘŸ°;]9 ºC*\¼l"ÙuïïéÙÿÉ€ø¨ëì»Åg&j|ˆ>ÊŽG#£(8î”D¡»Dè‚‚&ËN‹ÃeCߨķˆ×rÆâ•¬Møã“„¥u±æ~³ÏçBíBIÖu™eÕú@”EÚ£µhm°­¸¾‡Ýt"û¿Ó™tu'wÁ, 3fÄ€Ü#+ø´õ&gá@캨衙[謧¨V±�KÑE”'÷ÛV´òzj¤¹Á‹KáòK4]±ÉîöÐÙÊÅEB§b%ŒŠ`aÊE¬É¦‰•}°fQ¡­8fw?e9à WìéÞ¿œ;ºvv¯°ÁNó~ü¼(º•>Ä¢ÔáÁ1ŽÙUŠ3[É|²æHþsدïL22’«¥+¢ƒ(†K~ÅâݨØ4x›M7$Õ™Àät?¼o�Âv¥™aD³Ù‡CoÚTp<³“M< ÛmX†j·cÈÄÏ¼Ž—-]YMûÖì€å»]Ù‹CÒVÇ?N¡J‰P¶ó0ƒƒÍÿ‘ü‚qØ÷w2k{—BÏd²Ùb7CbK,È[G¼]Õéíô uÔ�ÙTŒ ¥•õÏ'È@¶Â~§æuÖ:ùŠý4¦u7×SÊ�Åœ@´¾L §<H(úmz¯aÄ=¬ú»§þËc� lv¥)M®µ í·Påªç=Fë ëØ™Cµ`P¹ƒ Õtë‹VX‘Ö¬0Ê™«Ïƨë¢I&u�WRôæQsÕD0Õ_Cûú%©PÅ$§?ådÞ¬‚•ré–Φílx¬ùXü·öÓñ‚ô&X|‚¨mSå=ÚLƒºÇ™ŽøÆ:}ãþÖ"ð£‹,Ktúø…ëyöe•�ìŒeS—Ñ%÷ëôjN2¹é¯¥pYÛ™@ù^F�Þ\Áå3špv ê‚I¶Œ‰§Kn@v•�å�Ãføõü,V/»Z2w³ÏƒE`R—Dç·5�ËOX%SÇÖÄžEÞñ <Ñ~ˆâᮥøà@-™îˆ®÷µ7$‘ÐH|ùk2mo2�âÖ£$Øó ü‚?âÕŒ»ÌvåIìg÷_᪗ ,{ÿv¯©ƒMmÓ'³ø ¦qa>!1�>o–ˆeô2ÜŸr÷ÍB ß/ þŠÖ¤'±‘Zçð½»-Í?‡’’´)=Õ.¤±/òñ¨Œ¼Éò€&‡|09‘žªqüõ–üÈæ8”cµ˜'¯e�ú¤7s ‘¥áÿ^°È÷ÙÐÞê Ö*áöÆZ ž•ºû:idüV:X5›Êü¶¬pHƒ}šgy“uËýfS&‡P¹� …ÄÃûÂñ ?Ÿi6ÂOÿ¥JæÄ@üC¸ün3©çA-Q k‚ô_I ~0’^Yd¿O~å $�ãÓèÓ°˳Êd«Ì/àÐ÷t\×�’e] ©ç}úŒÀÓ¼†Øl×  /¢SÁ«agè+ö3`X½É…âN=²ÚsˆTO¥@Õ§h;w¾Ü �>‹ÜbXÖÅ�;D]Ê~púà+<Õ“M;…o—0ÁʱÐî�ÃÖÑmý0ÔªT`:ç¹CÖ{ixk8äì�@KÛüè[Ëf Qd!þã™mŸ›R4†—'bÿþô6Í‹E~OaQLíz[ÍîÿZÈÊ“åèÞàÚzÉ b==iƯbvëM,_£1'20¡FâNëkPbÇìî@½I ïuCƒm«ø†’cã/,ûo†-`B�‘Tâ$†ƒÇ¡cûMæwl蜕¦g¿l-Wîoçó̵À¯8ޝëÀG“¯ùg”KQTá1üyŒ§º836v _¨ÕË%<ÛÉO~d“ËŽ0s›9´I3œåÞüHIKwSŸP »´u6È®«Ç‚ØmÔ'pŽ/ykÂ~Ë×ó{�©§:¨¯,ȪRu¹;ûÎsÁÑK¸­4€Bh(=–7êzÏzžX¦b#¶˜�¡Ï>ç©ÎûºAùlY’ôJçWö€š•(&¡ŠÍršú{)J}—ƒÄŒ\{»ôYàð¨bj°5%×Å¡l^²2d(PÀ`3ÚðIôöÂ!Ê»¸—'G-ôýò‰ù™…aj½4¦ÉaiË&Øí8ŠŽ j0±f!v×rˆŠ7ôM7ßy^èèå‹¿¯&3£$|ðqޓޯy—ÒPá÷lX6å4[Z£Ls Åu_2Ñ�[plÒ fû%“…üQ¦­˜Œnd®ræ”ß- ÓL<™™Á íã…è|ëL}"a@øEÐ7Ë`Õ§ ÐPwï–]ÀiZç/wc¾q/s™LÃg~�°G К?Vªbó£c°úé ¸SäF‹’Ì©øæH3¾ orõ@A·•|ë+ëWÚ(°q7ª™â qZù¯#üF‹Á¾'7(¬Ê,.oeÖldVâAX‡Õ¶àt\KŠŸ³Qg¶�äÖ]´²[‰–¤ÔcØ‹&œ )V޳—?6·ÉÄÌóNÛÝ!Ç×GáÙ{€ƒ»Î³ýÂC8@…$ûY¾ß–9®ˆÿª¡ÿî1ùí�|’A'ë…Ø•±�¦Á³†qƒR,ªÌ‘¦ð-šär¸žÝƒm6ŸÑäIíWɆ­`Ðã#½R•å•·ÿ¶ÜRÂéZÜq~–÷|©#kö\¥¾îi$2S–ϰ’Ð}@‹#éob7Öù¹0�·Útâš,­/Ç䪴¸^‹q´{J=[Öþ—þ™C«»ç1¿:0a�VÞ‡K ^a�¢HæêgØÚ ÅéÜþ´pÔi«Ç ÇRXxû ÿûÙC\9g)8'lÛõ ÕnÊ4–PÄþLœªMSŒ…g‰‚V3¦T‚[Ayt…³Ôç£ÁbŒ ø>b�=á¿áTÚl¥‹J+ùÃ㑃ÓiĮ̀ä$M„ÉgL#ôÆð¼×R+á/4W̓w«.€Sh\,Œ=N¦°â¯ ­¹ÔÌÎßhƒ?¯uQ˽–�ÿwÆ4ý}ìÀŒ$v<Þî &õÂhvæg„*'� ¨¶Ñ 6^O‚É“ØÇÚAþwÚ|àø×ÈC†æx0ÓNg¡Å¡‡É Õ}ršñ¯%èÑ®õ“Á¨ø*j ?cÍjópWæ].þ‹ñ{nbÝ�,¸ñÄ™®®øˆŸæ“¿½ñæ“9×¢&»Pœ_ðÚóÝŠ_~ZÂl¥'\óÃl8��E»É5Æfì<ÉŠeÕ`EõÞuä75n¾ÍfF'0ïuyT<¥�Ï÷Y:ÙÔ³žÄpx°¼³ò?ÀÒÄçœáŒ.~îæ˜²ž™+�op öbƒ�{ápÿ90®„ÖØ.{þ*Ü�º—¶-Ù¢tÀ À<˜ü³žk7¡ÃV¾pò�eU߀#¡�«2 ¢Ò¾ôëELk¤ûô` wÉØþÄÙwÖ±s{7Æßd£ÖŽj0Q†¦™Œvý¦¦%8:U�J%»©§N”“[õî_†-¦¦· ój3TޤpÝõšP¹m4ŸìÆ ?ÐûêYü&»˜{�UË~¹•­[‚œu¥§+7ô®/Ä€"SÚ r2ž‡4å¯ôæQI[tò}ÍÖxka uÁÒ�·BaõÜs@¥Lïp§Â0‡Qˆ¼²šÆˆõóÙrYd¬®‚.¸Óîß÷ùînวó ësê»XBëñ>ðÊ"ÞZpŒÉI¤S“wÂ-jÕ‘‡Âk°fœ/ö; ‰¯k-O–·q�ù&°qíÔ^Ä6Z©ÐàFöv6²'MômsÙÊo‚¹W4¨¹c�:Ð…)ËØ1ñ{dH�0^æ :¹u1m‰L°öW¦]þ2,¾Ð.”b-çK‰.㬠Rî’Æâñõ·•6BÇ£•Ð#k‰÷£zøìn¤âF½¢°F3€YH rM¡´hk*T<øÁOÿç~ÿ˜T_F›BLRqxÅdª(î¥�«³ñœÖ[Ö6í,Û+,g^ƪÇXWº:L±}Âbäì`Ò~™�,HÙÁRéƒhPƒÐ³ç:�²¿Ê¯øD´·±ÅÙ’Ægh©YË _Ц䗩غû¤²3ø*1‡šØ™eÇh}·g-w”?6ÛLJ¡¬ÛuŒ>ÓÌFÅýFOù1,–V�Rù$º½í¢Íø=+Ÿ´‹ýc­2…J2w�Ý÷գ؟ºtúE6š—fZŠ;ßfʽ®´Bµ¶ Òž�òz‹P®E-Ÿýý|ž­ùç½Ò…Q¬1?•¸ņ’¬L|%•Ͳt@Fj'êï«v~Á„wU¬bül41:ÉL:â©qi3Ÿug¸'fü"³*z5lÆ‚®g@æ©ËèÞ¥ÁjO�F+¹UT#­‚£?°Q‹òéÎKe\påïˆpûE�y†�†�{9píÊú¼«ˆÅÙi±ÌÏÕ¨q|J}­Ãµ–`aD)=õ´ä™7,»²"BãW÷Ù s?ÌŠ‹HænبxrßäFù˹°³h"°�IÌSÅÙ’ Ž÷UK©ìª¸.?Ï.‰Á=‰µ,ù|,¶åбSž hU§0W‚zÖFÑèÐdúuxBÈS8~»Œ®oðt«sxª}g'1‹I íì‚7Y[Ö—‚sÑŠ4½Á±˜ÀÛtn%�*ñ¼ÊN�¸H¯‡3ÅŸ~°âÕsRÍè‚oVïù¸˜?葱�ö½Î‡â ³àûk"E Kº¢yŒt ÏÒ”…,"ݼË0u«T¸~N�îÞ7åGò€ºÊ!ú(0î< `Ò÷-ØÂC&òx×Zõœ ]"O›VÏ¢>§ Id;eä‚„Ï1p5é=J àÄó«!ž_LÝ»ÎÁ¬›oI£( nò zêÖî<ü¸yØ3ƒÛZ[Ãæ©ÍÏöÃ`û%¡ö^b*« ±*cßqßHF<œõ�®°È‚ðîhEÎ>6fqà·éDÛ¸³dÍûß°ѵÿ:ßÚaéa¤ã ðËbwçW%»ôÒV$¯¡Ë;?`æÒST»›#óo@ôP²÷ÎÆWq54 %Dñ;J°S{2H—Lo8—9fF�«ýª*|OžûN37Úÿp¢Õ™�OÜÂUuü»ïGYÏ!mð À²²K Sw‹ÜÂ�Yš»6“pP³ òƒ7E©8k}Ëÿ€Í˜ö±X˜!ó[´h/‰Àáyã÷8†�¸²�EΘÌþ„ÑÜÊzô NÆYyÉ >?—Õ­ aÅqBìê�`àö'à®÷{à‚â*‘Ñe¢GðÑ×ÃøSP ²R6‚ü9Wú–HKίc%ÊŸ¹I÷KhxÄ~fWÀPÒ2Ï}DYå®4pø»ömNj ÜÔ›4Ò~�™N#)“+ úz f¾s€Â[‘´ú°¿˜ÍLN䲺"X­ûò¦m°£_•œ�Ø×‡¦=fÞº˜øÊ^ZnhË+Œ‘vuÖ0\Ä]lÔ‚Ö‰Íä’sÝb5èéÏp~¡}XuUR”,áÆúƒÄ¬\&¥²~#ˆ�¶›j¶Õì‹Ëaè¶ •Ÿ¾…g“bXžëRæ�s—-ý!õŸØO×Glåú5·„+õØVćÊÑäà\R”¤ª9·`ç“x’»é–³�ÉéâfÊ(¹Ï>}�B“ºo±[ùÉâô0j?N ›%øx|=4{Xú o9�O»èŒË\\ym%ëäÁû†8ê/ ÀTÝU\£z /ùÿäï$- ,‚{Ê_1äM5+o�ƒh¥òØSŒe­>(·Ò�äM¼Ù·\_ÐSyïвD§_¯[’‘Æ$œG›0²—˜Hk/~g¡:Ë(åþ\æÓÝM#’ý`qY TßÏ&ßíëÑR÷ ó鯄ÙÕàÒ në×Ó %p H!^í!I$Ð䙽œ^h:rqx)j6Äú‹7˜œ #µ½%Tm:ïÐ_¾áÏrHbåt+ú®Þü»ÖÌ'S¥"ʾ5™~.Èã³{3ab‹é¼Ç¼q–PÌÆ¡­w›A¸ë*šZ=¨s ¼Áþ†ÊÐÝLÈ�ìÂû^_-Í¥¬Zò-kÓuÔkžìÂö‹!óÙ\Jq©‡Cï'1§Úm¸Cí Ä.›Fl q\CKò˜ _­–¹6³/óªiNÎ)ÒÌKƒg/ÆBÁ�, ¾Œé:±Îg-<¹Qº›f³"·$Üo� :¡hÄži�D&&°�Ù¨%‘Û~?ªœxdWDñ†íøQg Ó¸…£.¼ãŒò‡“híç%¨øì»åÀ‰z“<­¥±¬áõ¶§£)\&éuÝaŽÕJtQ%kœi{ç ºØïýnŤ:÷{¦žL"нԧôô� Œ$¸À¯ù˜?$­¹§aT_;ÞvîdgÃ^œ¬¾ÇCìÆ6*4¶�ÿ-v[Nç'¥Â GMØz5®û¶ÂD›#,kÌ}˜_þS*°o÷Z’}?H[ìûP´8ŽÀñ>”o®á%BþpϼnR…½\7Ï ÒQÊ0T6“y “Á³È³`;Hš«±jEf¾/æß<ŠÂ·ÐÓ°fôìüþ¾?Y³Še¼)bK??cíÿßÅbRŠÝMä]2šî&³Ê}oaË» œw—=fÈ…r¿æÑì‡ó)«o§ÞZ)NÙ«�éðXq†Zó™~R R^Âíê;ô|ã-´vy�ŸA�Æ×­†üÖûüMArtáóŠãa¦q«{ÃÁü¦$Vlq�Ú6fÓI=p-,u{Ž“Ô/ÃZ… ¨bÇÊþúcÌt Ö~^—6�§îŽl\þYŒ&ʼn�ú\˜ëã ÕyД*Ûдg©9•¢ ×¥.iìãе½Ø¢+gu´¦¶ÝÔ³š1Í߄ͅCJðdå):µÿžÙçÃ�$ZCÃ`"3²ˆ��ž¦ú…JaôNÍ `.»øÜ‰�]PJ~–aø=è+Xeá_O/rú›B—ofÓZQNùZö–VPîUh±ñ¦põ®2G ´Ôiÿ '+¾Ÿ»’½Ÿ_üãˆï¯h×]’úz™-Hf‰¿_³O}ï!Ôlˆ&ð$üç"˜»m%‰ö(r¶OÉ¿# ùò7LsEÖmü×7ÆVZ¾£¡b“JC¦·m|0žn~Æï¸ý�599ÓbÌÛ— éíìãã lìÝ"ø6Ö›|V1¨ˆó¢­-Á\[!`£ÍT5¡‰ÍÚ4›æeúÿî:ôÆ®«ÅskkÙÁÍ‹ÚJíIà³Lr� @_]Ο›Q5ñäÖè§–PW\ &ëôÀF¯ëlµ¨"‹‰£¼Ë#XÓî­IL¿Ùvxüâ¶,Mûç¶*V'îþd›Ç`¾É~ÊÓh‡BƒöØBŒê qÃŒ§0mN…²v+¸,,,Vìœ suÖÃM�ˆ:Äk§Ö‘O° :8�èxºƒ™0ò"%VAxÕ¨Xðžâk¥�‹+ õ³ÔIÿãO# ­m×aÚ§i˜êa ;NcÍ­$Vöa"íþ£G'¦•±{k8È¾í ‡ýÏÀµT«3fåô1³›Þô§}Ãl$¦ ð•Mì¬Â½óp1æ@¨~œÈËÇý¯oÐýsAæ³3�½<‹uüðÂxµÜðÓ.Ë~yIhŸ™ÎÆ™L… §&Y Gó| @(wµ¿1‚¶�>pf¼Qîc‹EâöH¨]L3¢'“È/ v÷À8«:ëWlÝ„p¥N½\I5‹ƒÖ·±Ðö!ø�¡­—f1¡OΠ9=¼¸lÇé>WOnbæmÑ¥´+g˜IK(Íö}ýw™á‹lR½ p|-)=^θùýÜ•[€*ã™Ê}KøïÞgÊ]È”.L¶í¢ÇbõÏAú˜cä%<Ûêrá%6«¹•.Å¿��QpßçmÜ«÷gÐ]unÏ‚§uýˬñé]å\µ¬>yb¯˜»î‚ÅÚR¬šŽ‚µüTø¬d#²y4:`>å þ±¡lï¨IíùÿÑÒéñÌ}Û4Ê탽Á+ø�EhHfKO/ ÂÄÓÿüSŒFîL¤ä'硻ʓ­²µf{DúèÈ·UšôʲhÙ ¶ð�ü–»ˆ×αy©^n½(Ç}¡ðvV œZxÅåçögÃBbÔ§²ªçêÀ‰]ès/˲*XŠŽ{.&¡´z´n73…)èšÔ_¼[ñ]�TCÒI[ƒx¦úý6ëÊ9‹‰ÑÌ!ü:­ƒ‚v†QèG �§ ]ÜNªºªF9½,ÇSSç Q×]Ù¤�lÚö$R×z@Õµ��—ß"ÊØ}醞n*ˆÇÜ%«pªÔ²o[B ƒ’èÓŒ)T!6Ÿf¦â‹ls˜k7R‚ÁáÏ4`œE™¯Aq(�V/.¦Ë£†pèá% ¿Ï ×=ÕŒÒzáw1÷ý5VT{ >�¢Ûvw±é—&ÉGO�v‹YiL?gÒï£càϱ³l[k4 =&[x/M½ÀßÛî ¢ž¥(ëlÀ¶y� '#OR´�?u$†ú¯Õ@@¯6\ HÇóo†¶ÜBcÆ'd Ð«Oؾt2¸»¨Q�‹ Ô¾²%w%:’.ï³Ï¥íÛ‹á�ã,æ%ùž¹»�™Ásèúde˜õ4–šþþ²Ü½á<6œ?óœ»yñ˪ô˜òàMÞ]ú Bí3k‰MR‡QÉê,3< sç»ûz07Y B @xà.o™ï’Ã)±°ºOÿek½QIÀô½l!£`>Úß²c‰iþ¤æÏ �‚o?ï[f¬%«/É<7bÃf+N†-‡á”ùÓ©ðú#Æn‚,*Á1‰$rÞ\€žÞüÎÄæs2îsâŠL¬ÒôsLà‰µ•ôê‘«É«Ÿ-Œ)­Š�û²ÿ¸ð*Ê ùÑÊó](ÿÖ,ì/BÕ¹W¬`“'�Sj èãº`çɤU~°ëc[Akÿ8ø;’FOö낳d:lßàá¯Ö;�ÌA�«Œ±†ºí¾ôEö Ô†|ã_D®ÁãQ&Ü’ÏAàud/j¼7°R|“G»zå(ŵwYÓºIVL¢i s›7ÎjѾaJöf+áá1¾÷\üܸ€Inô2;G_Ø«qU_nÀÿl8³7ˆ"·ØÁG‹F ¸ln�R47üC}äîñ˜±|bÇGrVZ*Z°yj5§ÙŠÓ#í 5¦ 6Ô¶Ò+�z¾îþið5H„¦è‰!*×�ë¦A‹×&“ÊÍ*´OZŠ­Ieì÷“F:¡q šTùƒòܱá@ëá̦aH|2Èö9ºãg×z)øœÎV¦ù¥»Y’o0ÍX‘È7jDÀæÀxz{ê›×ßL/Ö�Ù®‘,í´IlêGï¡üNÛÈÞÿM¦º;KIvlÃÿÿÝŽ½§VлÆëøËpF«ÀÚ�r6\aùv¦*S7àcg-!'§³è[sÎâøà!ª ä_°œåéìÃå5´fë|–ù:~`£^�ª ‡Ï4§�EcVDr×›¾ð§;{—äÀ›Ï™„¦�XipÉ4éÐpß'ÏÑ-¬´l9†j«’œi,h¿Á{±0Zÿþ2Ïǹ¢3)í’;5Þ1§¿›7@Ɉ0l[oMŽÑŽtvÁÚt!„~¿úIΡ‰,¶« mVµqXò�šE¹^á1[ª»é.B¶¬ØC SÅBØcèÄ/¿Ê©Ä �ý—ã—CÅhÿK†•l �ò6-Œžõ õz?ðK—•qO¦©S“œ��Ü€wžóN�–P¿©�nhÍ„Ñ'o Ë«O°ûûðøº zF°½á:˲aWœÓY�G ˆ};ÇÖYÚQóû,*sÿË|ÿñÈûAMøSÎÎNf›$\ëµÚZÔ¿Ð2¡*«K¬�¿ª?§_€Î¶\üÙËÄ_LÀöô"z“¾†ŒDÒðæ/=0ð7�/¢#ÔÛ0´—Jû@ûYG¡T:akŸ�Æ�69é#Wÿõîμŭ8lÁöï úÿòªàBõ)é°°êJ9•sßõõ(¸ œ)Œn¦Ö'nôD&.¾Çõžß1zÞ’[À||ÍYÃü§8‹²yõêØq®…šMÏKÙì§údlaþ¬žDƒ‡"aKï¾+þ‰eGàýŠK܉õZ e�拎R÷Óchñm5íYô¨þ~á?oO=�iU¬Ö©§Ä¶¡ç埳{·ÕÉ+Ü×U¥;¯t©§ÏÇüãØ×1xNûºD %K1b³/]�¤þ!´½>�‚úþ²õÔSó ewkRŒålöäè)|¸3›ªzð�w[®©I 0�6.ÔÂÆg¦Œ¿2L8»n?ÒPuþ �µ:¤y4¾ �E×q�ø¼/TS掜Îãc_äRSé ú¸¹U|�qÞóÏ‚u» ™öÙgÀyxÒoìõ§šÌØ×‘^[50ÓÐzV|R‚çϨࠪ Vø›¡¼—4EŸt ïÒHîÌGm�öê³Uï¼0-N ’D„ÙS:@Âxn°¢Ø÷\ô¤ Á2M¯—ÑÜ ‘´m¥ûÐ:f¨¨e±ÐT)TõnÂõŸ¡«UÔ+|ˆ»* Z{«˜yô=Ôþzšœ^f�¸e $ôrÿ" ‡~¬÷ b äC@¼a&Ʀg U½7U¹ÂìÁ³ ¢»ˆVý4¤³‘'Y†²&3|}�£+¨µË€Æ;Þ„yù‹Ás¸úí¿Á>ÇÒ¾qÛ`ÆúTˆ­ŽœÕ_¨œÝŽm ­L(ú�–D_+Ä™a—Á~gx5ªÂÉD0¼lÓ¬"YQÞŸ§×4_Ü8B[÷¢‡e 8‹e° â¢X33Ý dhÃ�*d—ÅX³}1ñ#–®Ý£{¿Þ±àÝ�$ó±¿�ÕÁeóÊmâ£êh–¼9>lùßæ G@“zº›¶”í¥Õr;Øë<0R.e«3"ñ�ÅÊ]pœÄ†)QGÜC�Ó¶ÇÍv»aüÀoPò3fÍAiü5Õ̪ù™k»Á²_׸ZóKø°ÁÃ]ãaaúWØ1…*¾¯e[6•PáÏÙSÒňÒA82"Qn \ç‡Ö’@š¸Ó]óß?Rï” Ù‚\¶b»ìŠkêRËÃjvÿõ6!b$ŠZJãÄiUÐ%a mz5fIá±]P� m*DÙ“Ðùرñ4ûtÍU÷ÝÌ�häWüÙËö¸ÈÒ»]/¡'å(ܪ ‡á‹y·%¾Ø~›C;áéîp~j³uL€è�0tQm¢æ©±äx½·´ïÇuÎzXmð�ýÉhÃWN!(ùL•2D)KÕǧâ¶9ŽÌ<=+g4‰=šLDm0+w ’ž‰Û—ã/8X³TÕ˜t�º£¦Òµ}Á´hY+·ªb%ˆV&S�N.YÎ\â:H$7‘ÍLXÐÄ�¦Y}Ó0à}"·0g5ý[1™7|} ¾FO¤w¢á?ËT–&»õ"Ï྽ùœÛØ÷ æ5ßY¨S¦ºNSË[[š05×ÇO¤¾õŠøïlëXªb; Ñ‚™õÛ©í•nãü…§ØV™¼ñØþ¦Ôb7*וFÑôe8NeοÿfˆàÒ5³¹=:¿¸K³rØ•ܰp[¦¬Nèë ~xPƒ‡Xº£+¥\ªÔ.²¹?ÿ¾ Gê‰LÇÕ§ŠZ<Àhm¼ÀK&í‹Xåå/‚ßÓÝá¡«%Ýr¶Â¯ $)!@ŸÕ!ô¤¿”¦ßº‹NQÛ¡[zîï—àW¥,³°`L˜ÕÍ´V¤ñ¿Ýô à$ ªx×ïWáóÓ'ÌÒUEw²kùWl 7Ö7õ>òLË‹,Þëá�Ūø~þ¸¦_šþ´Ó6ßNÈb—ø0•yÐÙvº·ÑS�Bø¹°Š¿,À{›ó)")€þ³XÁžè¢gÊ©*£çL9öûârÐ(¹€eÖ+iÖ yR̦Œ¼F.j÷–²~,Wï$c+z'€V1ŒD·FPÓnY”[¸îñì³\ ÛgÙÎʹ©°.‡cV¥ûiSa¼,ob2z”pبÓ4ÞҌ6RtAÙ1Ù�‰B¼h/n+rz©LÎøÿùå”ágÊDR1J6ŠéìÇ_ CH#`!>s?ÍëRwœþð¢k| »­úʾð?æË³=ãFâ­_®ør…{»ë ÙÇtsèÖ^�ŽM#HÿÕV<´«VÀýçG¯�Bé½Ö@&Bún¦t9ð‹Ýûš¯°y‡ñ"zärç&Ówç:Î_‡këN£ŠÚIæ½%šL‡r³Êæhì[°‚ÚnàÉ�6tG6ï¼¾í’eÔÕË4eŠQæt)m²PÂÂÞe´s‚?™ßð¤É=�˜ûð5_|Ø�MšõQ¶QнñßM­ÂPnãá(úã›TÉ»‡ÿãÛ]7±˜üqÔ3o)¨…ùâiùì­º*îƒ� ”9F55® 2ç&¥¹:ÑJåý$)^Í4kL™¹òxNîä|(‘#ü˜Eú•1lîfŸ"4¸ÁÞX£]s7ü<º˜?±è;P1K˜ô;ïÿñCøl�¢ËÉÜv½í[Bÿ¶¶ò Ö©²WÚ¯aá²"N®¶€Q{וȖh_Æ.…<Tž„î6x¾EŠ5踒ÏÄ¥Tüo-¸,µ Gjqxê}<ß6ó§Â…�ÓpuæhfªßþA%,yX Ý?bGݯehÉ'®¼uLV¿F£V±—­I BxÏäJVêbƒóŽN§ëásqOT,œ@Qo]¼¥ÇNÄŸ¢§[­Ø§GkØùðÕp÷Ö0l]îŸ%dA˜¾×¦>½‚§2½© ß‹Jìñνxæ|Ê�¼:¢ñ@Ã4»·�vh›q‚SWøÚ®7 iŠ%Ê“Æöƒ¼±+‚ʲYxÈBs¢5qÊ¥(z‘£ƒƒÆ Xçö‚–=N+{óñÔ"úvn\œE—ª�1Ÿ—×ù¼$7vÄnž‹XÈ`§!I¬ŸJ"zâx>>��¾êŽß÷‰aÊ+%2ݳ›d^SÉÇt¸"V©bO™iNúí„щQøiÏrv0ºäkª|;»Þ“„óíR»N\S‹×Cv5å,{äâ„Ù PØ)æ´b�ç�_wEãø}ÎŒs>ˆ—†™Ãžf%Ïxå'Àë{´à¨–Zº�¯Þ„êͧÙkmQÜÕpœÉ¸ïŃ53Ød«мI[¼.6ÙÃDâ–‹…¯C23aφ ôd—6Í»+ÂZBFÑÙi5üŽêx6Dšá3èe ǺهëŸàızîFÓ.ÑÉôq Yç’aõˆ±ø$õ)�·',èJß7«`ÇÎ.8¸/™Œßešk>@è•§œÆ½?p¨2�‹TgçBLIÀiã`¸.vxŽóæ³SתùŸÙUTê¡Âšÿóï¯nƒ_ÏsÑ'>#[)<=–xKS¿ÒŸ@îßò›L¿GgcÅ´Ë,ï²€�Èd4汯›\¤¨�]W>c"æ¡ä‹ ,We&ÍV-ae÷[©yËø‘¯Q8…6õ/hWL LÜó-‚�áõtTÖ äýû3)Ñ*ÞêdcÂù!^]ëŠÜ££hWÏœæ#öÇßæÌh-þZ› \Òxšã ñÌ…ƒ½a¸Ö5Ÿ+‡žáÔ¥eˆnöb¥ùZúì§L•õ±h°8+l/rb•ZÂ3 íÈ(z;ïmHÝ Ù¸9°zÜIà¦sÃÑÎ%nŸÄ�4½ ¯¦É±Á}IÏÆ‹6á™[®üè5¦t'}¥$ƒ‘v.süš±ðhõfkKµOŽÐÝ�{«{96#Z…v¦1v2äbÓÜyZàò>šê—ßA/ÿ›8%!‰¿vÕ�,œnbÞÊR´Á túÚ8°l/ÄÕ%GpÚê©”çmÇÿ9áKýÿØåáU¤QßÍߎ¼Ãæ­§ýM*àíx'ÆË o[ë€ËÆVxØ—9¤ïÏHz0Œ?óz ÷V½�ÝÏ&ç€tº9Å•[®Q…=Ñ´³ÖˆŽ�°dÛ.²«fJôWS�õTÛ±©æ«ù¦óê$·Ã[<Ä Ç_„š’T�±‹Ã;{ùmoïBâ²Éð+¶˜:›åoJ°34 Ëå�ÓñUB k¼¶r$žO¾Æ&îûÌ¢‹†&®Ü$I9í$7s^içi¿ßGP9tØÞBƒÝ†xÖØŽV™ÿâ^­}e¦²ÃtQäk m�À¾�2ðí $ž1ì �#zÙÓ œa›.N¡ƒYá—Y“žVOOÀ�]Ò˜}L—ìlÀ#e{z©ð…_î©n;¼7 \¶Üæî´¤#ýzF_ÆPqr�ZFüì¨þó—pÜyje�ÝÝ÷# +eƒûo5é²™keHkÅ6üÕr“ÃfT(âÁ(´Ž¬fkè3Ui|»;€¾tžFÏô6¡Ô ¼nj“¤h3K‹w%Ë!.o|{ Mkƒ—a±­ÖxÐöEÚŵš%Mb)ó¨%ðûq�xh=~8-AcÆ`¯ÄTˆj`ŠQú3û.xͬG۶ŬQ«ŒúN^|È¹ÅÆÌÒ �¥4AKWžXM—ËCñ°­ ‹¹{g÷ýãLçù g‘Ë™%mIáÍcǸÜ'Ú˜Õâ�*‡qéÝæW·—ü¨e¨†~ñR¶O.d1ŸóÁôÎL„ÆŽk$ï½_á~y!5_†;Lw#•ÜÆSÍ"¤-ÈÄâ$ú„Y˜ü5˜¤ åèÊóoÜê&1PÒe½´ÐWÒŠ¢mP¹Rœ-¬+§ˆ¦XŠ‘?Ë)6¶3�¿%òÅü¶ û `‘ÈR¦¡� f«¨¨| å}Ë.ç�Ãû׎@ø)94þfÄÍØ%.ô˜­Œ&+D¨ÂÑ œ¦ é©}2è¤4é_ýÐ(ž7ïÏŸ‚/b6�Þî+Ør¤Švts"��™ˆx$æœàoÜÛÂþí¡üñ Ì×)>ˆ�ƒj žùwOfy°Ì·sY^…%c÷g¡ÿ±÷�Vú(¸šÏ¯RbÙ‡ƒlMÉhþÞŽÿ½7’$RkÀ2!”ž÷}gÙi&ôÆ+Õæ@Ø3Ð7ˤI+‰—]ȽÏàŽE´‚˜]&«ì$Zûfûãr�N[ïe�i—©¿¯“MWF)Âx��O_/¯¢-¯ÛYTõv³t­Â‹¨.sÿ=ŠNw«àâË(&ÇëξnYê2›bo�¤£�aØ xZÃVê0Ÿü`øX9Èo¨;¯w^‡þñ-œÃª&R¡ËÖäå3Uå£$ñ†‡qWCXÒãËP²ó+L”Â\é>;×–þÛ8—ú>–@»[ ç0Ìýãh_[3Jò„ÑQlƒU6.ÒëæÓªì0ñÄuRÙ•‡¶ÒÑ0¶R‘Ù�œ‰ù%‘el ïç9Ý•={ßÀI¨ÇPäŽ.{÷C�~'Ó*K`–ÞŸø‰kpÞö.…„}‡Û“dÙíÍatwM0râëøaFE8º�“ ú�¤‹›_žEùå6eA¹ô8[Ìvö‚×%u¼ÖbòøÉ¬ndd“Ä”Ñ}v;Y]¾Ž‡‹Pº²¢qL¾<­4©`½â7 Dg:ý=Á6þp§˜qQtóÃ×õ/—O˽Mßò Éû¥Ž—.äW<= ‘Ú²pQU÷ùkÃñZ!gñ °!ñmæQÂM³&ãÚÏ|Ö3M|VA{­µ¡yÞ :P¾…½XûDÌİ]ë³{'”Ízù9>ÀøÞ4Î'?¬|Ìæ8‚TÙp2OœA‹eùÍzw "Rž4s-ðÙ¨–v^�†¼ ݹûáTm"ä< !µ˜dÚqò{°¾d=“(GR”{~àã†Øp¬:/VäFÏ—‡å«NcË~1ÐzD>Ž¿ PC•þ(Z ªfnÞ<ŒÛ¿K CÏ =¾ŠÛ¨fá…ñåÔ*Ö–Rñª �‚[ÓhZÈtÐy�«Ûó�Fµ²ñ×Ò5]:b·˜™»}'?Ê"9äöBœf¬OÄMcuèö¢I” ù6Æßç–œäWÝÙG3—$³+÷'Q˹ÃoêKSO}`ßo­Á¢<¥Ÿ„¥‰ ¼å:I¼tÇ¹×æ@Ä·ýÐ*Ç?=]?­Äõ÷âIAøxÑ7ä3E•LOœÆËÐ#{9Κ�ÎJºøîÅvô:<Yp k‡ùGb™óK3ÚsÎ|}rÿþ45íºº�Lwí¡¥qÊøêÚ°ó>‰Msá©Ú3XþM ]†/dù-fäþ7�vÒ»O�džÏ¶ÚÝ`~e÷¸¾!\˜¢éîÝôr®³Y75¢ŸÅQòm›�mÊù´VMž}),?@#>ÜÃÆÔjn’…R© Ÿ1 ¡þ¥Ÿ¹}¹2™L,¿ˆB¹ l×ÓpÈ�ú橜‡­ã Ôclc³ÑÖ—óšÇI£ñƒ `!:¿x“K–]Ÿ1�Äxñi§È¨-˜»~%Œ›4g%\•Â=9¦h’åÎ&8­C�øhv£5×üÅ¿³eaÔêIøóÌs¼è¨`;’  ÀöGÐêoIŠ–9LaÀ6˜Yà™§Õ¨*%Ižªcè»— *M:Ç&�ÆT�1Üq›“(¿¹ÿë(fêçs¶´Ã›n£Pä´ݘ³ˆúþ´b‘@’$ÃÎB½C `ª&#qÁƒùTþ÷N)|�öê¶/nd ЬmR/ùþ3 ™È‡ù`yr>ÿqü¨¹· ý³„íqPû½Œ}|—¦Ž¤Çچ„Çzxw[/?¼EÿtŸņaÂ&ÕLÒ»vŸ¯·?ßøwùêzÜBuâÒrÃj’ü1wx Éz�¶íÚãýüÀ‚|0UŠj:ÅP:)ŒÎ¥á¶š§ËsxóÿB¸½­%´õ¶-�•\F;ÏÞæÛbW Ú–J6Ý7WÐ1ï(I)¦™›¡0SÎÏý¨hå:ôãXµÊufb1�Só¶¥/'‡2ûˆ>²zAš%8ù›>l±œjF«“Ëã|æiZ +;ž—«Ío*d³ÿØÓû \«=€¾Ï³Ù„(EÚé1‚2’êp¡ê#Xw´ßýUd"Yç@ùË\ÙC-yV\�yÌŽ&ý½Ž·åðäWOžW�Û4Và4¹·¼|‹JWÍdåGWBK§§ ãï�±ÿá߸CÛ[`œc2—Ý®Ûîbü�ßüóWO¨ëýEv£0�²ÍÞâëù=°þ²Œ0Þ¿ "UWšäxËðÑ”|X>—ª’Ë<9¡Ô€XÜFõ“Šqrz2®nòÀ¶îÑä<ág^¹Œÿ;B@ß‹ÆàÏ]1øsÉ�Î_o'óáÙM•š0ÎïŠUÙr‰›¼ÙÙ“ñüšn¶a¼,&º«cR÷%œ½4÷OÁ­Ó—BóÖmøÎÜÀ™ÿšNj‰MUsðדA.b¯]ÍýÈw�§5bp ²‘É8m¢²ÎA’ MaA##ØX#Iý>šM:º™ÜÆðQ…7aÐ$ˆ—>ñ|n쮟À¨;“6úvsoØN&°­/ÇC{ªÙ>‰yLMkFâ†óhù< ®.Å•C}š×ø–;$æ€Îû3‰9Éóc—H“ç�íôYê.ÛŸœÁ”Æ:Ð* R�,`›ÞO¥?Q¬Q‘”ÊÄiW·Ÿ‘ ƒ3ÎÐÙKhÛº�ÒÞªÙªVÎòk#šê0›×ÐÊEÖðMÕ’’r&PNÖIÐÒð¡u›öÒ¸§G¸Ÿî’Ö¼ÉP�#lºç| T´þÀùšW4øLÚ®<�”—KÂfå^R;ðÖY^&ç7¹\‹­ [M3Æl¢}nØÝ˘ßIÛçß‘Ýp%Û£*øM“ìhvîvœtñÐeñ…�r%Nì´ÿ4TŸ£ÎšîiÛ•¦ “ü]vzj¥•¬EŸgÒž¼�¥LGãg/IK¢\`ÑVK34…§Kù/O§’ï£!ýúnI¯ï«Ò�± ´ãXü™ýF÷1øxÅ”Ø*>�€¿ù§H´Ê³Lê¡Õ°šÍï®ÇbÕq,´ ˜É$àÕ§rxnm24,¥iãÃkV´¾Ûˆv^T:†† y�6i+‡ÓÞ<™®¸D/·-%·Öb–ÕÄÎg_b«mSñF t¦u°^gZ­éÊ�Ú@IËK¡W¡š�¬v—ºfZn\Cƒ§³� ‹c7seÙ4›SX$aÂl yÚY�UW@®3�÷³@Ì2œeCQ9NÓL«iCtÙ4)‘]‡.^ñãŽnÏ"§îÊ[pŽ»t³ŸA¡žûùT=¼i¼q¿Í· ÿ±þí“p¢å”/yy[Î"›® + &��ì^J´ö¢Ð»™ô:KœÀÉ»#iBîRÊQ±$3Å7È=Lä_…ÇàÕÛzØ–J8Þ=�„’HE;ÇÑþ0qáÌ5xêåQÞæª öèé"ù ÚÛ©Xaó ÇÓ”v¦;®Ç!g÷#˜»>š�Ïx…é“Äp㘦`¥ŒîÕ†4Ë£öÜÏþÖrâñ ¢ïu‚D¶НXEs¯I³Ü±Ž4e©"Û’žE±K¦ë5ŠhKÏ(è,Áçó§²ÕG’ιf¶`¦5üVê`ðÅ\¶~Éfv.~:} íjz2F‡ÏºÂØcúÌX}È»²ö`àŒ¹è%mŠŸCnÓõñP–—DvBp�®º&Äoð†0=*¥©‡Ê(èˆ ÿŠcnæp[eq“· ÿP¶ Úß$ñ×îl¤5j…jLÛ¶lFg`úqe.Î2�3ˆ)L‹[†qy ¨¿ñ6Ì–ZO7¶8Ò§/ÆÔ6›çv9´�÷�zÂÊø^f6^Aøòl:~ü.ŠªŠËáZ“"6Æ>f]FKi8ÅðÖDqÙöÓ´®7'ˆºÃ˜‡Ypÿ²7{+âfz·ÙVSÛµ�­^= =÷%1nq1ŠTýfõwÏ1†!s¶ÙÄìv­g]·qÛŸ>�òXÍ{ý9OƒÚصøOi\Ì ÖR~šéfÄ3©Ý‘Øwï¹Ö¸ Oq<�µ-°6#uçã,êÈ}ÁŽûS(áùšvô=0ÛØ$î�‹%¿5�µÛ°¯™�üpÛ.nÔmá,�HTðñÇæ¹; &{€ËQÛ‡zÂv´º™(ø¼,¾÷C÷éKi/Š–Ò¦ªÒYèWï�•y(æÐTÜZD–›†cÝæ¿ðéÔ=bòš[ì–‚}Kïó/åFÙv¸}dzgØ×JTÚžÆoùÉb/ çA¢(öÂdÝ8.ë|:í•}S¦‚o„1ÎHB¨¿=>Q Bß¹²ÊLp#9ÂEúà”z']]FNë#èWåwî¢Z WþŠ£ ´GGÓ$Oô|ßÈÛ&ø±·vC¡Z3†iÚºøvâ«‹ XЊ¸/ŒBÍû2ø^Ö—\Ò·QÇ3t)þ»öaÇïÖzy$çk=L¸tÞ[T ÓzG] %–ôB!Œ]/À­†ÁX·`59Ì÷fÇI±­ÍðêœhZ;|Êdl¢?)jèäwA0ïî-\Ös“ïr°A³q»èÃĸ¡€w%gaH«5,5ÿ �zû0mbÙôžæ>œ0¡x¡ Š>ŠcI߬„UFÅx×R�Rò%mÇDgâߌ¼–l&}{Ü�RnTV¯IW±vÕ�”´õ7ÞÊ6 ,§ ¬E.n©qÅô•ÁÀPß½\ˆùÚ�$~g*—ž‹ef£l„;±ç¼—ì@ÜV“güU²høÈ6td³£fiܹ{R b^{2�¿Èª­Ópt‹:Y܉W<*ÙZ‹ëì÷þ±˜Rv¶M Å/g€Ì¢ïlõ´ô:Óe8År4­ cµ‹ƒËññô…O­é·!Óo>w;BÊ “xß`'N)C •r5ðÛïÄ�Š Å=œ.:ä2oYæÅxúu&7)ãã¤Ï6øï >“ Ǧ×ÏÀ~±ŒÝG$EðuÌzÑ£O§ß߃é .”;ï:ìia‘&˜Fs.Í>‚\ÕðБ}äf-Kw®CÇ‘Ëp$Æ�½›± ËYî¦C8§8…VÊjâ¿)«°{ÚDú']�#žƒ_»�P0d`U™ ŠE|B¯®ƒÔÙïƒ÷BOâ2W3X¢«J‹Þ.‰† lX) MýÛÀô×¶ÐУw.Äœéúx£Ùrž×«qƃÓ3Yš� [:ɉµ&Przn«MÆF÷‹$¯ÍÌŒÄ(s]èìQÄõMºÂL–ºnöd|O’âÛCÙ¡~�p`‡/¿€ÉñQ¼û -Ú^��÷\ãH˜¥N·Ø°=ÝŠ;3ƒðŒâfš´DÓv¤a-kÎ §íA\VŒ¾)«æ‡…Ù4ÚÆàÆÜ_̯¦�»”��ôÿÿÓw£Ò�õôòüA|z…m2èƒWeà;Ìû-û ¶ øÇ@7m/–{dÁ‰‹ Âýµý<:Ôr¯}rø…!GøžKWÙâ3]C9ܽœH¿<çµTà”‘ƒ`(�ç{riB#“‹—ÿ©òB“Sû±rïÈŸÒÁžO»ŠÍ¢HG‹ÚïW0ŸÀk´åÒR ;UØëȘ3D%gâ • ¼Ò~�ï5Ÿ­¸”C�Óå鯰�ç·bhîa�ßî‚§YÜŸÙ8[É�íËØ¥¯ XšõŒYÕïGïØ9xîÀJ2M-+W:¯K.¾Åx;òS8Žu†òÁèB¬UO£,¥mGŒ2À%z©KÑ » Šhá†çÜo‘@¶NÚD©ÐèE—8¯óÔqîálcö± Ó.4 '•MR™ˆ¡áñ|–Ô;8|k,¶¯†¿’Ç(;»’ï‚ Þrlmeg"ÜAÎöÙÔ®÷gÙµÓÅ«ð‹g¾ŸÇ\йÂÞ»\ÿ;V7êy\‰¦…ác�Y�wL .>ÓÃõC|@‹��\>ÄkÙ#ï³pý¼¿Àˆ~q[ž°áí3é­¤fŽAã¼NÖ²æ7žŠDæ×b2'’Ø?l0|5Ïý;ü…&Þ0âÇ.úјJQ™¿¡g_ øHo�!Ï4‰­¦¬×¥`#ÆQÝGè�» _ÿYâò¼vè~?¬í,®9FVï›á¿ùÆd²7VýJfëîùãBõ\ün›ÐZ@Ûöuã-e)¶@ä>[7- £ÒÈÔÐ�U{Üg¼a.]ÐF.É7¸)ÿ±Á˜V¸¶ì%(iúšW‹¡åü_— ,Á”£GBeø“{¤ƒ›pÃ#=Ð&˜qY�·ÉÀ¾W'†xÿ«þ‘À®ÛÅÐ�ž‹(EÿͰ¦�ç÷â6o}.gC”tõrù«e…ÒòÉÁ[…e#±fO>¸þQÁ¨™ÏÙ~‰.€ƒS…Îhðm*´ž{›<2@õ�å(øT€Oÿʱ¥ÇÆsÎëJÀ£A‰Ÿ÷¼“Ó`\Ä1òåo�¾ð€]ZšÏÌ¢E#®ÁºžƒxsÃv û·†=OœM*7Œh•¤-]Ÿ½ -PDzln�=ÖmS*:L£ìœx¤SŽÃ…rMÕ©Ëh'�)�_O¡Uÿø„áå4nˆ‘­Jî’G†“߉!†>Ô¸…‹˜¦…jrËwðÀ‹+¬Iü+Ì<8kÓþ[Rˢ̂$c‹Ì¶C�Á-ïÒ±â?á­Þ5|¦C¢Ge0ó\7¯¶º³G@Ë)af³–_é‘'[Øà\ôŇîžävNuVò)á.x¾×—ðF^Vt£,ýlR¯½ ÕòJ´¼i ½pO¥¼ÇÊܽ2{´�ÚŒŸÚW`d©$M«ûL_¬œÙqõ�ìíU a½êôñP¦9¯à„sïób¹Qð{ÆÌœÿŽ¿µ^�„Æ^vü�ÊQ¤ï•è?GH­‰÷›(±”IçÑ�ë“YÓdkþù’ëh??KK àÖæ¨¨l‚jçKÐR»ƒ�ñ³B§mÑT­Ð£åS·Êb`M6H<ÞJ‡—ýÆÍ?±?UÞXÿ>Šë“â¶×ÓH8QIh}¯ wÖ9s/úÑä`U¦7÷ “³_÷Å“SÉ#½p”zj†¢%ilMë=š0iî“ó„åßk ä¥ñ[�9+ÈTÂö„&¥/g¹ª×?@ìí2–z¡–%[ÿb�ÔØâeút]EŸnÜHeÉ3L(øð)n ó©» Á!æ30F·Vgê ö"ߟÛii¥8çb§FÙ2çXÏ5OÖ¸à)ÉNŒ…ÛGϰ•ŒCf—Ì >3G{¹ ê2— >Ž�Y<Ž|å§á ù¥´vÏ?fkóþÕýeogè Ó+ÔV  Jã z÷f *{”ìfì¡+CÏÒWO¢žEû¡fÚLξÀÌ/ÌÃqÐÁ]ê» ýËP¡êËŸ»”¥=T¤{æk؉ëñL¹Ë„s ¬µþ÷\ö[POéaž9ŸÆ°ã>«E…ƒZ÷[‚n(¼ÆÝ’Ûèì7q¬ß½Ž¶úZaçà*’é dVâ2´þþQZ÷™%�Aÿã›Ù'sl H€��÷ "c#y‹Ô±VÃÏ,ï…<N ‚9 ëÊ‚�…衹˜gÊ Gaú-Ôi­„J¿8õG©l¶Ñ¦5b<&(ŸÃªÁ:ðõ}yx¹iã)1zùú#ËRÎÁ•R¡°Þ¥N&ôѵI�pý¦*—˜3³ÌûYÕmLoäÝCÑÿÏMVèt k"Ûx1eÒ’| VŠc°xŠ6ŽY•3”SÎÁJã·w.�[¶Œ¬ {!aÛXœè‡2nÚøÙñ>ýî|/¨r�¢´QïÙÉÂRÓ>Jå*ìö‚×·®Ã#´¥Û§î‘xvKŽÀÙƒqgw­7jAsáe¦�¹tˆY�cSŸ mžöÆÓ›ÑRܰÀ™8v�.Ô_¬'[½«Ü„Ù.ìÐø:Xß.ŽŸô×€ü¾·‚é³DéW’¾^9[°ðB‰.9ZåwÂi†õaRÝ•¤�4Ë'œ}|’³EqÉÒƒ4UÍ“œãfR$WÏúvÚ@Fvú÷O§éõ`žA:d8¦‚ų°~O¼LøÆ-j<ð ˆzX Xê<¥À=É̾—é¾3â*–Ñ'ûãdœw•E–¢nŸ û7ì^q+…:/{%•„}.©àòg$õ$l¥‚7íd³¿ ïX(B4Ãö©Ú8óå?x×WÄR'dcìs‡?zv·BÙ!Qœ¶©;dúÀos<Œ�eyÌtZŽÙ1�ÞW^—�<|Ô˜DŸT^°²v.½î$Óiàך X’©%<û§�§Œ¾eiJ´æ]:,óH¤ýÛeéýNMŠKPÇT‰‰t!Ї¬¦‡€ú™Z®îÓn�™îF·�>fS&HSîMcªûõ…%MØç [×jñN>wÀµ¯Ëš?CÀ�ExÒ~ö&ªœßdÑHßm%›wN¶ŸÌ=€ÁóÂØ¢šï�³è¸Ž€ç«Z¨âá;x0áêõaÇŒ£wk!4�ŸÄ&åGQçê[8¦g(?<dŒq­Åyä~ÿ1Ûµ÷À /”ÆýTx-ÇQ@ÃYÚô<'ÙL…�3®²+æ¶(÷å$»Ù� ›WØâ6ùsðzq-�’y„g¾£¨Ç)›Œ«�гw*÷Â_�.½ŠÁ ½ºhýk>vÙ†ðÊ‹’P©Pê¶f‚å¨ð³²›®ò¿læq�ÍK`ÑÆŠzÈ"b‹0%G–�ŸïiÁˆ¯Æ96ÕޖƳåIôá¸[Ç~2#ó"xmÖAGr6õ4�ͺ‡¥> £åïoÒQuò=ÐÊÌç<æçn`Ww~ågÒp«hª²écé&�ØéØ6á1vûØ[�øy`ýS·ßQÂã°ò‡ìøíbÁèôîváÇÅ•$h‹5úçø+Ì‘mÝñ„}ÊÞHkÞÄe)ñhQÀ•;îÀ^Sh~ÁžÞ‹$Æ Ë¯½c§ìÑ÷='PaÍg&6ó5d,ð¦Î]p°y'aÛ‡)'{“%©ÿB«;ÞŽgû·P˜°€ŸÏŸÏ©f]¿íš¬–žCÑÜ@|ýëÓ쿊�ç£aÒm7Ügÿ¾ÉóÏMê~äCÞݯˆãŠb9ùÁ¿l[²::>ÿÀŸ–¨ †WÍð²ô Û5Õ¯]ø ºðså*¼Ý&X9LK(Òa€q;iä‡::RZ ¡&Clv­�ö@¯Àœ¦îicò™ûÁÍ` º-ˆ •OUO2…Q0~­•;H¢Áåœ[ÝTL¿Ï"›kàªØèŽw…„]Ý0�wŠS1Ø#wïV[¸t/3Üú»¬Î‰¡ý«Nz­ŸG�X4‚n=· ¤÷™ âï�™/ôñÁ˳ME»)w¶!yôëBÔS1p~ª-´«|µE,b_m~ÎÝáx36ˆŠ¾j�«‰5­10aáêþð/#Œ’&ñ¯F% "ÓÅÀöÑzö¢T€Ç”Ø`&òîÑ}pH};j�…‹NŠ(–û çÇÐׄÇ,(©‡ÕŒ*Á„z ·é£}?ïÿ ŠöQ–Ãîê[á3Ír~t�œ­ðÌÜ3¼ Ü^°¿_LX]Æq¬Y‘Åü.%ûàJ8µD’"68ñ¶�Öñ.ÃFÐÞÝTèü�ceÁ$îㆵ_Ã+SuaѧŸ¨}ù�™¶ŽÝ¼ƒñyj –ú öå�¤µ±ìÓ/!‚»²xôÀG»e9í/âÇ˜èž ÞEfô«§m•µU/FŽ"›)«t4ßïP�2õ0R' ¾³g´:ó“뛘YÚI<;¥šw|ÊR²Î€÷8¼àm�ârì‹¿[qyNy|‘ÞªíB·9±øuQ,:—MÄ9úõ,å‡>H+µë}ˆŠÃ1gmÔ|¨�];�À6|.u”–q§lÞbþàeJª›@_L�Ú3Ž8Њ«,TXÛÄI¶“=UPdÑ)òÏ©¤‘Éùp7T¿å˜²§ª†M·¥É/¢ ®LðA³ß ÂïkìÉÛ<~Љ¢¦q3Ñ'ò;sÓ’ÂaïâYɵ)p{Y ÉÊžEÿy5³~Â臆P³X”6 1æÆê&‰ç»`iOëóÅ ã`üâ1d»:”3Ô�-Y³¸·ÿt¹í;1ocEòk6 ûW1ËO`‹â¯¦ )C3QZÈÎu§á7©OTÿ»Ïìŵö’ݺRökGó ûÿ¢ø±ÎÇ9Xó2¢§ØÉ=WH˜ÐÆ­2 d†ZˆÑ?�㊉XRÁ3¯éQè8ì'ÞnÐ"37YT #ôôU°mí|:i¦ä %�©³±¬ñ!mÍÚ�ÆI¤â�ÓëaŒ’>Ò˜‰ô×]­Äs°§û »îè‚z™ŸùFú^ã=¡?èè Ï#¥¿sÉoï‚ã¥pé­xþÛ1 AÔ#0™Ž?þ‹ñ–=dÚò™É�WCí[Zö3’ «pfµ³¾²1[¯€Ùç¥,Z« ª BèpŠ�⺽“%pWN0š-  ª[ç@ïp(ëCô*��UwzHa— š�ezÿ⹆Ã%¨^¾žÿÿ*2˜þŒ‹bÕïß³å?OчÉ>1U��´Ü#mïu�æ,y6ª-—M” A!“ý™3ȺöÏÆ¹úÉ ‘ÿ“³ª±Ó ‘šVþ�ß–4çÓK0û$ ê7n2Çz±äY·"ùîð¤+7qý²9è“Aùû>bî½—\tø0aSãú=‘Ò|~Ãì§°{ÿd´ÿë‰[4 KªT…�EXêFCÜùé*[·(ÔzÔ¤Mä-)AãCó¹¤sïÀpÒzör¾ÿ#ÖÚôHæåZ9ïŸ�¥+ep̹öF%‡*¾¯cbÿ>ÁïËò¸Ž+3™×¬út¤ûÆÁ‘;£…}£7Sêýäñ>OgJ£gÒ2ÁDI#ÖŠè]d XR´›Y¬øÀå§²Üg §< ²'á7ÓNç”5î¹¶ˆ”¯dQïˆxºà ­ü׌-úãèFÒAùbˆáãÁáÁð¼È_«Ô£Ó¨(’(9/&ûó“èS~>Öï8DËÛî¡dË(š½|~ÚãŽÇòw“nM·ÓZ†43Bø [~2ͼ_°TìÌgBR}¥0Õ]M¸ôbu†N¢¯õk ƒŠ8ƒ%Òô±j®Í‘BÑõì쮋|¢ŒniÔc�ñ_Úà rÊÌ^<œmMÉçX¬3›Ð®ÏEì| G,hͲ‘4ߪ G�ÛÆ4ÃXÿ¼LÚû=JœƒðDí|ʆ#`s£j¶7câ3,8íIO¼Ôð³Ë½ujNQ§•�ê¿­V¨[�VžñØgOìð¥:ºsÑ£–oã†=>…Ê> |õÌ�ôt˜=e\,¡^tekбKa:ë¢í!�È}�;Î{|ïí3� ›SðUÛ¶@!“ÚÞý=꟧,<¸s¼+drë2á©n6]Šr¶Ðc£i¶[cÚ1[.•¥X¶ð Óîã £ëØ:7Ÿ©˜%òb™ÇQyÞ=LhÈg�]¥jep];�Þ.If3¾G¡‘±œõŒ§ÌÐÛüçwvèÙËßöñæÛoÛાZZòä;kœù�šD ñIªxÈô&6@ã‚x(õÛÀÌæï$�øF^ïàqìV3eºSŒiGƒ¶¦ÍÁ�»ÓèÒL]~QÐ'W¯Å®÷�¥^ïKÀûJ‘m»û4¡ŽÞo`¹Í ´G,˜ Äðç›f*P’ ÞÂdVïö9 ôlvÀ­\L1·£)oÆ1ç™sY÷o[’•~BYq‹Ñ¾9ŽÎòçð)$6®�ÁcÊñØ9ך�9¢ŠòóF‘–ñmnCísœt`<ý-Ñë«àÑ¿.ø:ýeºj ï·6®3ä±Ð•9íÌAÊ(8$¡Û7nL¯Öpo åðT]8ûŸŽq'¹c'Ñ|&áö% Ö^‡š¡šÛ|p‘ÛPv–Y‹?ëÁ£o–tïÈsæ¯ûò–l Ë.yìWœ¾û�)ídí«,|ª’K×>¥Ò‹içXƒ{îzw�¿óßrò‹þ§#(ðt�R´¢¹ ,(â#¾¿ï`£üàÍ=[€zWïR«Â\åZ :G,©Õ@—¿|ÉÜ[§PX£-jöh²XSmŠ39ÎTš§òaQp q*¾{ý›U¨S±ÝvNJ5 Úr ñ£ßÚ2oéºé¡V[R£l[ ¤�/£ˆ¹…È’Ç’y|³ŒÊád}ÍÙÍÙe„Ò;q�ü:z}ÁÊ¡Ÿ/�·Âç³ÙÎR„Z£Aöàn ¿·fn˜ˆríUM™±tù¶ –úµS»ÍÞðÛgÞ³ï"Ü~nÆGa£n3úº i}õÒû˜v¤Ÿyl»Ë^¶«ÐVÙbÒ“k9µkäñ šô#Mh…É7þadk™¥É›YуxwÚxs¬¨xÆ’ÃññºÁ$¯|�÷;ñ‹¹þÆŠ^­ãÏ(™3¹mìRdzÁ•¼©·2Ý]¥@rrÖèþ=Fûf“|¨¤°}åsZn D †Ï0sŠ$ü üÁ":ÿc—²RaMÞ0Zô^wKÓ˜y ¬®*„Ýj« 1‹Ôq·Y&DŠÍÂÙí^C󩌣¼Pú¸ |õ‰Ùü�¢óþçêýø]²JVve4¨ìuî—DC$TȧÈÈ(•ÈŠ²·PD”URJHÞç~©$¢ ¡¤’R´5øöýÎ9�û\纞ϟÎ./œ¾2A¾ÿ!Åa¼ŒöÄ>DáJ9¡#Å \ã³D„X•4=hYþÏüa2,uðoÕÌÏå‡�«7âü?óaê¯7òQ„�ÝAÃ. ÖέøÇÐØkÚD^ù·pn�#FºÍtÙëdúEÒé3å?¨™Ó)?JWÿ®a%�ÚÑ?RO×mà ‚­ ±ö>Ã*\Ù€—2§¨�X‹íÃ~ûéºrоæ©�æ¨DÐBh\NŠä{É&®Nf‘ã Ô(0#åÃjdéƒ�èĸ—±øÂV�ö+ý K…š®-<ùWç8 ïû]Ì�s“Øõn‘ð&˜òxX`[[.nØ,Á¹&­ˆËUÌ!û¼¾ó¾HÚ©=4ˆ¨�Àq}’,Ù÷£eñ³Ç€ µ¬býIºÕ¨’´Ôþc…ùÇaõýWôk»7­U; ÎwjÁpE ÙqâYåîJwûF „=ȃûñ4tX…¸ÑÇæ'ué9ƒÞí—a“ób÷˜›|çÑåÌé㇠�±Î`§VM‘mºZê‚ço_ yq‰ôJ³4aà x$‡‰\¯þ·{ÑÞ1|ÛZÀMå(Ý>µ‹h.\ˆJ¯…�íÍâ´¬mÆÙŸTÍâ%ñ™ÿž´ èÐ�÷èq!ØÖµïj¤]³g59Gøb”j #mÍÆ% `aÚ3š´”"„ƒiG¯>t¬©G“+‘¨rPFÓv‘ô Ø—kKç‹[cÄí}Œã‘—Dú¥´_¹ ^S' Ó[‹ú‰Üèê�L/ºÆÃîÓÉÐ »œ+Ø¢¥¤¹V@\Ü}©Ûâ<Öþ‚6–¨N1‹oÏý­mfPybE j|V“«s!nôÚ€û³O‚î÷ãÐ[8šú�‚[+\Xø–ìtxAÞzšÒ+·ÜHà©Sä~X&žñCÕfê²ÎŸlؘ…§öxÂ"«]`ss>žóç‚Ç-J˜)û#ÿåìSŸ%sùÇFOßÎäeúÍ{|¯]LÀÊÎTdu–Ê.Á{·{W<Ç÷¾õ§Ñ狤pÄ#C—|&wµëñ´ä7²J_‰Î>�;g*qú›Ù¡çwé‰U©PÏs‘vžQÇëňo¥%cv=Ã俇£ç%lšZnCØÊÍÌ®}:ÀFÂ~ûFÐSyûÏi¬XGÑxNâ=i¬�‰eôOaLÊ.rZªª—Bê:#Pøk Å£ÂXÌ]Ìæos¤¾ò;ñõ° ²]dRE¶ ±ë¾-Fa¬˜3x”ŒZ`Ng@¢�ÌþMf•l#Ú[·ÀÉ>X¢sŒ1¸«‰vobÑçPÝT~ žÊA}¸:¦n(¡1UœÊéfª4.5Ž\(8pœ2Ÿ•1l¶xß›k:":H«¶JÁ}¥lÎþoÕðùßæg�ÉÁôø0�'ž_Üg,2÷‡®?$E½É¿þœZOþpî’.y.ú·°‹³é×K‚8ÿé¥bXPÉFŸo!´N‚¾E¦íÒ¡çEÇ©¦Ú \¦²·IA|N ã‘imrñÄlXÖäI F“a�C"^Ýâ‹©ºw¨hǪYc>Ÿ ™:ñ%ðÅ­ƒ ÝÐéÜ<|“! ŽCUäÌd ZlÀŽÛi4C%€_XCÕÛw2_ä¢ÝýJ°˜*Eñ OÆû „IÆÙm5BôæÑ%î¶ n½îæYƒÊw ª,0e¼Lª†ÝâXMí®±Íf·Ýõþn¼º nHÂ÷ÎÒœo™Øz%ÓÔá(Ô6‚•åH @~×7ø(A‡~Û{”q.Z…ï©í±£p,*£’oÓñÇ‘xÀ©ˆò²@Ÿ_~DÿŸ;�ÚZ¢÷_}riϺCÊš ‹…À™Y¸�X-MܧR…šª!Nœ¯ohäJÓþ¥Stt4>ôÌ�}ûÞ�˜]‡AQwš5�ì¡’§LaD3OWÚ|szw†°Þ™á;fTέ¥:e�*8cÂjsÌ „wÑohM7Á³ê01Ó¨4ÓÜ]"ä>B¿´UýNë꯲ò¹û°;gŒî3¦×{æáû¿ Tt•ìñÖÀ�ŸõTõÙ[úmì­Ò`¼É#Ž^ý0 ¿n‚»r) U.&_¬õ`yåx©¼ü£ñçõePÔ²ŽÛ=dª5†è½ô2ò!á9áv—~ª]ˆ«/J�߯›QbŽò¯°…»EhØ`ÒÿÎY‹ùì²mÚD»SÆtgë#rnÉCxµü©úqC5QýÆÜ_FEæ†bÔ>s\šE#�è‡bâQÇì*¶ÄM'¤˜£~IÊm~<Ÿ1/+ÜG�»yD˜GŸVÍnÆ5y XâAIA#k) PYULD½ÂY¤ÌDÏ@ÑôM ë!J5”¾”æ°ÒŒ¼ä �SFÈ{“‹4•¥@×ÉZŒøÆÒÛ xd.<«ïÐ>¯ùdn&Âê]Áÿ²•ŒR¾¾}Qát&=Ô¶‚:k†P-βÔÈ ÆëJèiïvªtW �[ÁØ·*òæC?Õ¬¥ ›7“z{[†Ùx ÇÛŸ“Æà&q›0βV�dzèpºþº-¯=$!+âhi»#ÕV ÄþgØ#[ˆF ‚hùÕ ~jù»ß‹Ñ…÷AÜ`Ôµ“áò¶À³ áý®+ÉI¼Ö”¼ˆ‹¢Aå¯iU÷\l/AïP›Ô+9™œsfñ¯Þ¬þSsú>ä žU*£ÎEš´kñy�ÃÌž‰ ß…¿m2Ð' ‰Ÿ·š[g�½óE°DÙæ=‡O"irüPœ½™Vð,[‰>ºRŠa|fPsÄWÞÇ{ý*¨zÐ�J¦þ{7—S0U5 ·íñ¡^ÏðËÀV’ðG‡Îy×ONU{A3mzÀ9ßÄÿ±"¼Š; Wù+¨ƒÊ¼¢§ …>ˆÔm'^¿f6µÅ˘†;m#ïe÷ÑÉ”çl†ÛÞõ‘gš�ô¢ìSòÕ¦…>üNºÓÑyë^¢EŽ1Üp„2ÏСÅMW6*�ª?Á-ò µã%¼(ƒtá@ öwcU>›c÷`:Ýö¦‹]cDžͨz|œ&es7íÈ.EX+bŸÕà�Ì*ú1W€�µ´ŠÓy@&è ^1¯ Ïµ30mŽ1ìó>Ak�àõ~qÆ \¾Ìã�à7)›« š«U9¯6ó²¹+ù!ÑE핵ð[ä"ØüU=»[hÖ&{8çrÁÄÞ¤ üÞ²�Ú�¤RH®–¾Ç)ñ4zôY*Ô­<î—?ÑôÌz’z$ŒÒ~Ò°ˆ[èôÍ“æùMƒöá(è0×ÃóeƒDâɼU°›Îþ¬Îy™ž²£Z˜s?›ÈéNS¹/¶=ó ñç†_µ ì:“¶�q»•аĂÈd{Ð[~VÐuÖ"¯U£nûW:e­ˆÇü¡2wG‘UpƒÁBÈ1jÇ{ç¶Baß#( }ŽKö7Ð*Ý|ø°ÇŒ¸!¸p+?»Mk”^UÂÒ’4|¢ëŒ ‚ÕáÊñipû•�EñXç|ÔäïH”Éç!ì-A‡K É/ZCeɣşDÞ÷Õî`~‹@ Q\ô9Ì,PòaÆ2¬HúÓ8¦oM*ÞŠC”ŒÄ©y²*³É·Œ_$Så69­�E/L–B§M}ÅDÁE�›Ì:w”}² Låb¸ôÐÆ#dú%BÊõ8t§ÑAâ½ìM±u"…ÃEd(¡†\í‰ÁsIæD o¾‘‡Á <=[¡ž^ïè¦ÏÄDaÙOsæSN(›Î'y:ÈDÜBØÜxŒ¬®°@%g†Krá…®{¬“â0 í.†•ËÔAúý+ø³,…œ³»@7}èaÒÿëBYÇa*p|œœR¼Š efÓ›b¨„Ì9»Ä”öò¾&¦w­É™Œ~úi�ʼ+ Êó•`ÍHØnÜ‚ýNXØ!H~GàYÍÙÀµ hmñ zCI/½ ¤ùL�‘öÓÆÐÒ��\ÿî1£ç³Ò­Œ:~k'‡SÙuòëÐèN©Ýþ•Öç«Bªø*b]Åcz5ð ÓŸ˜�'Aed3ü1¹ á{1¾49y9@Çr9hZŠi7 HÕILê4¢ÜO‘1áëôå`˜…@Öa{<_OCв†ò¾�äØÙKþÛ§ö�›„ùd’…:îØëv‹Úº-lÒÍlÚâ� 3ýÓhÚÕl(²Ø ·�Œ š?ç,êfÛ׳¶cú0ëÚ2Ðò€^³V"rѹˆ \éÞÍÕ�HÒ¦×$S÷4¹šÃ�÷E÷­¿Äæq¹ºõ+ä¿a‰ó~r·|u;:AeûŸÒ2»»4:°…¬žR¥‰»ãÈš]¹¬Ù3EFI¾�Jˆpcœ¨ì¿_�sËÊp|þjY½šì|gÄ-ž[oȰáäm¬4;½"Þ“~tü—(îË�¥ƒÙrM)aüôã×@<²rÆŸ˜21Ë¿e’ñ€÷©þ¤‹­±p“5Šþí¤ ÛoÀ×e%tgŸ›"<ª!`…&¸_1üÇu'I¡ÓÔH)À¬¤Y8ðb?®T”Ãä$J3ÝùéÅû×ÉáDIúþ£:Õ¾ªüzÛ¨U¾,ʼq­³îC@œõ= R¿Ñµb8æÃJæ2)£KÑ«<—8M2aòÓ@ä\^1œ�-–À—Sú¹•®Ù²šp¿ „�rBMÑ%­�"S«§Ùî´�°p¿§Vë\ã!Á7d ‰‘»7M _dãÜ¢(0^É.:Ë¡ó.Äc¸Ä,8˜EÈ‚Zì7!ot¸A9$yüù¡:Na Í—ž#VLjƒ»H®1Gín3^9¼Gn‚�PFº¸³Õ« `ã½� üÆžÖóeГgS˜¯_TAæÞLpZaˆã™\'©R:e3ƒVœÁwÎÞtëÝèÜÉ…gûRX /qÎÝ‘Çûu¬ô¦=h¼q‰8¸å©EÝi"3·ž†›Eì·@{Üì‹O#§È®Xirêù¹SS�yͶ¨¸;U2rð½k ɼ¡O¯ÎŸcÉäæë1¢t°°€n”Õ‰H8œS‡K\é�}ŸiÂ.M[ø’ž`ï13àÓzع|{1úR>„Çcм«åp<èÚfK ö~5züKŽÞÜI·ÿcT¾ÊM8QPHgúnaîG§™¼ã«À±¾Aúu¢ ½’ç à‰gÔÿË –ëx*š—CžŒ;ÇÎ4±¿�ý“<‰›®DÇð·a/UôÐÛaqd4mÍߨɲT“Ç–Ô¦:ò˜ùZÌô·x;iª…YAˈ]Ïuà‹8IÍoqÇ…¨ÖèŠö·ŽÒi�Y0ª��…ôô-%6{»ëpqp6ðBýÃ$ȼ…åï6N? yÚ¸G– X÷yÍþ ×nÆ`ÓÓVœ#ø…|¬ÜI4šJ)·@%%özdbi QsÇæÏIEg7ýõmlø›=¢Ò¸Æ8†}°]šIú¹ "ÎÄÐàW.p[5–o $×#óÉÈ@2Î=–×.Iš ,vf^Ë•cÓ!h«ÅHÑjâ§Z %íçáH|¼ÄKd%ñü¹tÇCL ކ[A_©y)·érC{jÓ|ƒ¼ÝrY»ã•¡�˜Ü2%þ;ëK ñÓiMV¤I Nè5éŸX /7�m»)S,ÉdMWBglH¦j!à\�¶{†§†Kpç” Lœñ…oi0"é_Ï΢ ’„às¤.Lß<‡|æq0¼ìÝÛ¸KÏá4}Ñå‹ËAâ Œ�—n��qm¬Î…’ð|";ë ;o»8ntÇ=³ñÀºõ°þÉUT’�¢!!\øS€vŠÅSëôFrÊq7,×LdÔŽ�n“L4[z™Üûˆr&aÐÚ² �N×Ë·Ëði쓆}oàO²dÍ|Ný# ¨†*?ᙋ±~–ˆÿ,êhaBj¹íå'òлž,#í¯ÅI”T}Ñ$ƒÃLŽ‹=Èx}føu’ÐeB+vQýhS¯?ß>Ý áa$ïä6\®û•óW=•,ˆN‚vÝYÿò¦K_ ^€ök‹A]L‚9PY ×z,AøÑ<Ów¢/ðd¡2ò·ýÁù—ŽàyµäKw3DœûÛ’4PL 5Ä~�7Ùƒ¸þ¿`N�õ>4ó¸Tós¿¯èwÂ5_”ávè",ü®lbÛ(‹†¨«˜/\QŸ¯u]àÀO1²Ò­Ú“ðòÝ­d†ýϽˆ ø|ö[욥‡‡lã�)]x4)~‡ÄñL�<¬èJ@‡Ü\üv–õ>M6­?Jýû߳Ü(Í71�wäðƒ-ÿžcVÓîÜ…ð%p&Õ·‰5VÝ`$å2]Qa„Ë ôÓ&”ÒË]›@&Ôdˆ ò²¤¼¢˜vüj¦–YÁØ9– ¦¹ðÞ;…мãEš;…·EA\Š+™aa„áêqh̾“gÙëÊ ^>@2#ÿ¹˜œ°L‡²¾ l’ô¥ ~ÑLß ^œ’oƒë0HK@�N‹>¢K–Œ½‡auèp˜¨ƒà¤*ܹ;•fϘƒ‹‡· ð†{/î S¤ï²`þVcôãjR=�Œˆ†øÒ$8à¸öó”âØçzXrù8~„š òR¦§–¾Œ™AgÕçP­îÓ(w9�©m‡ýÕÒDØ9‡„·Z3=[êP2øª™óã¨áB�Î8bâ‘!Cv>x‹­­<$øîj rÉ1ùF¿œ&znƒ>@…ð'Yáö�¬‰æf¬,t€ÔÜÚ7Ó �e÷Bùeaqp\êÓ…”À[tìg{�xìLüyý»}Ý>ü38L×dÀùtÜýã>kü'›Îp9’íD*Ò²ãäbð"Ìí¼/4» ¸:QÑ¥b¬†ÒªWíÈŽÇÈ૲L¸ùìí÷nÅŠÈCè§]?; ÑËu¨Õ*Á’Â’ð&ç÷ÃnX'U€· ’ôM/ÀT^ |´øMCjžaºqÑ�YO�t´ñ÷ÝZ,œÖò¦ðß¾,Hª¯£ Ús©ç�Tð){G²g\'É�D7“ö»%@nm)YQOøÑ "Ê<^ÓP^<¸bšª�æ2u)®!ŠWf\ÛcžO{øÐkâžY–Ìí³n0ú+ <NÁ�Eg üìg2_ó-1‰ÂþYmdH}™\Ê��®F@£¹6D‚$•‰Cïã\j¶n>æ¢"ˆ½fMxÖD ꬟ÙG/P}B™á¿�ƒÉQŒéù1lö¾C ÿÜ4d­1[/,&Ípò»’©Ï¼G4À…þ®·�À¤ë�»Š¨ÍO )w¹›ÖÝMy+”÷²DQLöåÃi#/°‡m„ç×$½nô�(§⻲š¬1@Œ Œð”º�éâ§+¯í#¾Ág©¦ÜB,ØxgtÉaíÝx\– Q[¾áeÝ¥hräñjŠGÁŸ*(SÃÊ… ÁT¯ž¹ó Ĥðg»PÓ½µ™ XŸGuʾÒó|JÈ£2Jã’:Hú‘»dûÍdøïrµïg?{’Ɉzà¬r„Ób}¨é+ˆ²™óLu¾>$ÓÝa‘OÙ1[�º¿È& ­=Øš ùܯLZnŠ�á§Ð’¾Jû�“MsÇ™¨s E¶•V{ à¼Û ƧOÃÉS§IíÞÛ´qe1<{�œ”?ƒ÷cŽ£þšN Óù(UOÆ…ðù�™¦•^FP”˜ƒÝ/9 sNÖœºB“^Ü.ž(ºþˆÌr¹ˆƒ¼Ÿé�}°‰+þtÍ%¿öó`�Ó$Ãñ ¥œŽÑ€¼8ˆI�b�‹ø›¢kÛ¨ŸVþ(¨„ÓŽgåæ5Í[¿‘¤ü'‡2Ñßó8(Ó>E^ŸÇU§á‚ß�Mnç�MéB¦63ˆõˆ=«+—‹øoG\á%½Îøqû.róký6«|p×ógt¡V6X«mâàB®Ê~£GÃø`nÆ{ëà+–Ç9�”—}9'Böwo„÷Îfä…¡9ìˆ2ÂòeŰôØEÔÛ« ³íb‘¯"ö¾ó'2Þ|ÐY¾�¶%�,aSm!O“C­qt‘óv2´uˆ4œ¿IÛBñMO;=Ï;DœÚ¨S� QÒÍë‹ÍÑù’ýÀ}~¦•16E=¤Qì$ Ì^I¼5ía8ˆÍ�3tðl ¾ñ˜cª(v•^Û 3m'ÉÝïi̘‡Îè{GŌӫ rÐí«@ºO„P6‡1´zˆwýMÑ@B”J·bQ‹«q®Ò_zZÅ„ùC±)û8¨‡´ÝM�d4«›¹áwGýséVù÷ä$·4s]·”níàÌW†^MZ!)ŒêŠÁäœ8H;r¥q¬A‹¦MɉY|øµbãr;þ©3Æ=m|f<»«¯PŽ?½¿G6ó¡„‚Òk4Ó:BK#ÏÂŒþZ�t¶€U75ñïœs¸¯ö ½¤[ÃÕùÄœåø£Æ\T°i nÁG1îsÝ/ªŠñËOÀÂ:ul¾ñ‡Á¤Îî½Ö¤V~Ø Èã£�.òò�:Ê=ɀįvÌó ZXy‹$Å×Òk+OAÍs1|ú‚“ ß¼#UeÙ ô†§ƒÐfY¤u¼¥ãMµØ·0�¬û8pxp© rãØ¬§´‘Ö’;A½h㈯*Îcãë pÑÛ‹Yꇨîávfë®&'œ£¿ŸÙ¯¶ÿ/㳬õôØY-¬ßö›3k©;ùêÀ‹ºJ>¸ÜBœ8ŠÞ&ò,™%àEý5 1zKVNŠâveEØ­ÍC >BÞoÅô—ÙgZ\Žƒý>L‰ñºvòQÔ› Zs Hë�Iæf{ ¾p{Nß”1�ÐÜ;�ãKñ‰~ùñ­\î|¦#Êaô³ÌO²-å�l¿DDV»'‰p0@L8ÙK©kŒëK©y•¥É÷§JpƇ½¢C®�¸üØWš«+ÌD¬–oòK¯e£Ð×9I¸\G_l> ö£WÈ…„Dò_Í7än“Àð*zÞì³);„`zY¯5FõgReÎF’üx#.{jÙ‹ò”hìá4ªK¿µ“Äe-]Ûp„ÐÝïh‚,¸¿¦œýo0w2?¾zF¾;ÇQç™~øù×µ®ðî™<(| Cž"¸û3K.W£çPY*ý‰èl|M?¬I§Æ³cÅ­ãDJrœJ½ ‡;•{pYþFrDÚ_v/5Ññ˜�ßoÄã‹„M·bÓáK…ˆ©ÐŠãPýYãöf¢­2ñr³"ÑÑš¤EúRÈœ_DÙƒ�ëÌcøZTL÷mæÇhRA=Dó™ÕÖ¸lu3¢f»Àò ;6dR¢È¥ß­äå²8+àa†<iŠÕRp9XL¢=bQTK6ŒÑÉ»T¬á�üÍZÝx†ö%üà‰*"#´Ò¼5T¬Ð}f#ô‹Kóõx- »<øqÞ¨:rQL}ªI­Ã÷R£ðØÆ\£ýàîÙMú5-Éâú8ª#)�}ÆËaçoItªtF;•´)ÕP¯ˆzVqØÂ˜kR^v˜’%wåñ°˜G7ª›˜ÖØ«]ž…ª'·ˆÆó“8¶ö#­þL7§iÁb‘"¬Ó{E¬Ò>’‹®ÛÑÐ5•¹`ãFm—&ÎKÃéƒ>Ób›\8ñË›.k«g<Ì*ðÒ¿-Vÿ±Þ&,!ã•GáÇg3ýst.uìæ¹6O4ði˜/ÞÈÝK6ÜÄù:L¨^ �óÁÕ}š­üçéG3�±ÙK¹«"ðÒº™¸M«�*¸ß! †ylQL ]â#†ýÜDZy7áDÍ"µú—èœÉ’Ïã@ÅjÕaQQ0׿áwǶÍ*˜‰Cè�/&e»'TíÁB»‰lÈŸ¢‹âuéz[Ü›6Åt'8ÁÊÔ`ZÓÈêÿ§C” ÐÂ!Í?z`…®0„Éž„\¹‹ô¦†)¼÷š\›õ”ýyVµIR^CL¸Èóï_ðë¸5Ù¢çÉØvÞaÂM¼ T-Œé+N¡ŸËæÂZç�oí  @ìu!¶º…ce†Ôûl<ÆÕB^l>KæÿælY»Öl-…•ÿzñ…€´šwˆž] ¿Â4šL~Ò¶Ç'qíÉ¿É[ƒJ¦ÅF �ïï`-ƒM+ýÑW× ,„†“—ÙñÍÈIeç)Lpœ«cH¦Á)”ŒhÁ+*˜±8ÜùÔðÊžŒl‹Æ·“z½tEµ>}Øäƒ[å€Z»’]ÿ:ÎÂ5 ¦ZfÀñ«™ä°ö‘û/‰µvŠÅuxv:ª¿Ì)™X\ñN¸ù瀃ÁU,ïzêa‰×ÈÐ;ºæS:r¥| {²ÀfCkaŽFóÖÁÛû‰ÅC.2ô¼‘Žóÿ"Ï[�⌌§´(°šG ’ýEl¨K4Yþg/_úζ˜n%Jä"5Vq„;†EÑfgzM3ÂãÒ ´©™ê¼öan_#UêÜMÁaܰòt$ç€T4r+QzáZ–EADÂV8°Ü•14Ž…l}{2gÏ\zÓ¡„,ËÃQåpÂm/M#6{¹“Œ�ÅSY1]<Ž@sc›Y ‰îŸ¨X¡ùÑ» |7Í€¡d JEG&¨Ì1pð%ž‡\Ð6ò!^[ê’w‰[(?<xAWz‡OÚ¢;±»Ó¡kÝ%ôz|‰|lWcj£™¢hnˆÛ J¾à‘F÷¼wë¯`þåcÌPëexèq˜f?Ê”®4r¸ñŠ]�,ØŒ–�I`üBêÊ ÀäC K*ˆ¼ëUúæN'ýšõ•¬©¬c’ßå¡Å×xöp™g–b¼à{9{^ÇfWœÃoy…Lë÷O4ƾ²1ªõ³S´“t„I[=9*ÌõkJ�?3ñb­¼YƒÏǽÉn�pVr‘'üòT¦ ûkˆÊá ÚsT�ð©êCãá@&l⌈›x‹{ψ˜iCODWÜ"éo*ðô¬d抑Øüòc2uªè—áœp_‹w¬‚ø¯ÕDMà*Ý5ÐfgâÞ’dfvÏr™Q„œõ—á˜Þ Œÿi"w´†]"r÷Š§Ñ’Õ?ˆ\xún0Â>±‹Ôáò§³ˆíûV¼Ã5@6EQÑ£Püâ†1aå!Øù,~Nn¡k jpØ:âg1Pß·‘ZœÙ�-çpòO‰Àçþ�ÐU«Œ^ƒ¼¥±¸å½7ÞÚö˜Öÿ×Á©B~(V× zvÞÈõk.9|°Öø–p<âå0{, ×ùmd<5lèêJˆ¿{œ¨Õ]!q^}¤Ë1’YóïüæJF‘Iõ Úg@ž<›f�d¥jWãìÏdŸu?™™0M¦:‰úè7âS x¡øœÚç c÷¢ÑàX{¹‡ªŽ˜3KÓŠð± ‘–.d×s’™®“§`= Òlj¥wÀ1ôý,·3×oøÇWIpû­mVVüÜ P8×—DÑÒ�&“sÛ“hOO2åÙê IÛãa¥ð:TúhýÏýrˆÁ9 zZvŠíT|J.ªï©Kí„÷D ˜ð �íÖqýúüföøój2ûÆt0<6­ ôÐ#Szð€°i©Q1ܨòÇùu/amí&üõV#·±³’é/ÝëDìå)òPÿ1I[ùƒ ¸7²eä6— ˆîüD,Í/уvÑPQ}“9{¼‹L–qX‹-I„*nÆŽÑýtÞOª;ÓMÖgà­»r`_¹�LÛ߃}Ûb±¿9<S4�Ô}ö40*��‡Eö¨½¤¶+ I¶oü1¿„_õ¬hµÌ,ºhòɺ�cNix½ñ,ØóÚdý‡AüÝÅ.³X‡¹b†`�Ýoâî°’mû€ÏújIÈù1r#ø1]U]Ën=ÅJÌÊ„oe€oîb<0{14[ÖÃã'óÁ³`.XÞT {.›ÿ³èæni,îŽvÂ ë«Øò3çý¡D“+ &£µØ¼é¥^ÇŽ[‘­G#qzN"”¬Ûõ¡¨ùi=r/ xÎ>¼ô¶[vý-�ÙŒŽF•ácmt×\Ÿ¬LߨÝb~®À�_Œð`”=Äk)ƒmãj²' c–'BÿaH�V&Wz¸q÷;!( K‡ŒmÏHêÉd¸´ÕÌW¤Óż{ÇŽqIÓÀz¡e$fÛ}LxŽgR+a“¥úkêS�«µD|Õ,ð>§HÙg—`µv.úðèÀ§§pkÍRhX¹Š~rqé…Ù´óÍÎ}»�ŸÁ %ç�€|l!qù.€9›\0@Ä šÕ„ÑõŽ0>~´ƒrތ߮ÍÄEýÅLñ|]à}žH%µoÓ±‡Œ‹}Ë+þ„èiÈÂ3Ul�Ɇ�‰¸ßÒ¿û¤c­V X,Æ\RÅV�2ê=ÄÜ+� aËò˜›FØ=[š šñmÂA¯ïdáH)i˜:N¼*ŽÑŽ=F¿NòŽÀ¥€õlXà�_:° Diޝ#ûä“Ü+€íÉ |ãUû¨O=Rñ¤ô4ª>Gfž„ïsøPqC)–Hý"{|á¯ÊjJØŠ–g“0Zj6H¬äƒ—N|`ñ´Ë<çwÞ \ç”Gâži“•wÔq‚[Œíº4DÂýuÜ�ùøñNç±=nèuÅÞ�Ì''.ÙbvÚråozŽìƒ SåT%›Þ½$ÀćŸ7A¨íGš·B‰´f¼#¼‹Cá®�:¼)í#J†á42ì%áûv ›ypóÁëÔÒñšz5S‹ŠÁž-�ÞäÒgC“d2àŒG‡^2È(A Î{Sq ã/ãÛ$y4ɽ Zž1àqFÊ$ü~',ʈʜI€î˜¿[ o*Ñ[J ;µBgþ æºnª b{W2ž^‹°sò¸õIP®ßJXÊ=IgîåÓÖÖLé’÷hëp†¹,FpEc Ý?v‡Ù¹E92ß:Þâ¾ÎVúýF¶ëw®+ظ¥ ”o­Á`�Ù⎺ÿ½BgñFÒ(¡ƒ}ïOÐÛHô?CGÜåÐî¥ñþàþ-gÈŠ§/È�E)¬QÃù*„¢þÛÀ&� ãKÂqVζV‚5Þ©ÌO§ Zܾ$שÁ5-AÔ�ÿÆ,õÃÞñ t@û/‘�>¾SbfŠMÓeÓ#­wi’Ãvv�6뺲ýy`«Z9㼂À»á2öNo>]³ÿ JMdTB�¢ç”ØíÿËÚÖ}0á^âµYÅhל…6´Ÿ/^�cz™ÃŠËðcAgö¿ëåJ„`¸âåŸ/…G/Û Áš °¼Åc*›£Š/Ö~‚Á•jØvœÙ8¯š|ÚÊ„†¹@OU¶÷(à£GÌ ´!ùq~nÊ¿mïÈÓ£÷aÅ¢Óìe{Jæuí!JÍvøÉ}-¾Y€tÝ9ìÉxOÅËwÂõÅ,¦žê "@êq68i*£^D$]÷&�ó=ÿåhA“¿L!䯬¡v¯ºMRÌ£ ׳™pÑ¡RKß�ÉçÁ8zg&£™p‚ÄÍ+‚¤gÅO�Çå-Öđӈz±Ç8›æÅ0K.«âéE?i§„ëN�™î÷èm#IZwk5ÏÅß.ux X÷tM®“ÛðTe+T`ÚQah.ºN¿=Ü…5³ÐŸlÓ )?¨ûÖ2ŸzÝð<×]â;½ k?iÑÿÎóaXõZTïZ·]™2W诃|а'—xë°Í>ЙÆ/HGßR™¶#~êP�‹?Põã9, T€üÿÿÃ#Z¿M¿B÷�™pð¤ áu�bã ¿SÎ+3\s1 9Rµ&Þ©‹ˆqI®EЬRgòlN!ݦ)†¥ôlÖ"tØm̬ëç'�Ï p¢ö73ÿ_®ù…ªqZç\Êó Nƒ½$ÂăÑÒNO{=Œ)®bK—„`æ_Óñ§eôɧ‹\Î’iu(×÷…û§¼´�é5ƒ!kZ§ŸK®f^#µ¹ÃƽQ¥Pñ½•$«'’%/Û`óΘ³¹ žVD’"ˆ¦UÉë!¤1šy¢”Èt#yÇsQï@3->ò…y"³%÷ÄcÉŸ«$1GÎ$ê;þƒ©ÿ£Ún\~ð»27ý™vо´`퓲ðÎv&L ©Ëg}ù�‡®Û˜„^†ôÀ­bB{ƒ af:ðºß¥ñÜ z­ƒ¢;?HÖŸ\X7šE³�Ø—·e›nØŒáÒ÷_0Á~²�†„½11OÞ ê†¿QYâ=é{²¸éØ3%ZÓ �Ž‚`“ai7Žpþ¾q¥f†R$èM3)é>÷2†`¢‰9¯ªÑø¿zôÆ*Ú¶n6ˆF�`»3(÷•áUq¼¿4Ÿ°Á_ ¼÷öëWÁùSºÎ÷¬Rp"¯Ê¸È—º_„çö~Ø7ÏœùÛlK¤¤#]YIã_ÐÔßݘ59±âððF *~=ˆûÍòð§L ø¦ ¬ðRò›ó;¬ÁÆ9¾¬â¸n¸v”˜”gbéîĨ”Ïx¹¥7èE™ŸB ±Ùt”.Û8Hšøâwæ_Ê�•dºWJ�Õ¿�eÕ0»ˆs�)ší?ÊœOYLÖ*IÀÛÅý0n'NB›>ÀúÓ»IÔçEôÏæ³ÈŸÇÝT¯À�ÌX(Α½F»›I'”\ š¦k&æçr –Ô¶“²v{f ÿ9œ|;—®ãֿ롌LŸ8ý[•D%ÇÊhy¬9Þ ¼ü�o„@ƒk6”åÔ 8ïRÜë'M‚¼«™WyA4àX†¼(ÇÎ¥±ÄIö3Â8=÷¤EÎ2P4t„>q3— “ñÞ¦h 2Ð…½Ñ¿Èî¾ÓdÙæÛ¤1øIäoÃuª‚¦¶k_â‰þD´UžõÏÅý0_'¢N¸¦‹ÄÐú¢}¿?®ªî„%CÈ£©—x¤u>6Õ±»óÅÁÃêÙ¾£xWià‡Gܶi%_6ÁÊæ™Óë* èk*‡o.Ú¯Ú9vÙ~l; ÅBs d$ TàçÏáH‚O�¯ª1Z++î¡pô¾¦nêøTŠtkÕŸïwj5ÿ*nó_ ³µq…�-5×1ƒn¥åt�Ú_fM¨ü'›OtƒÓioϰÙç��Yxýk<†Üh#ú�RÀÿ¥}Nù`µ[9:ýyG¿…mb™ÝF½êvè‘HÈ=Ï$ŒYKé3+�¤k3" oKúÅ¢“Dþ<¸Cß9Ÿg;æ&’¤µ]Dqa¹-ò�œ9VH¢?¡çò˜ö>¸H>>ÝKz"µPQЋ»éƒY3ÑJÖWÑ1­J €­}gQyPG'¦9|†ç‰Ã¿ïëï÷?¤n}6lüKr,sá¡` Œx§²³+´ØÃ|×`²+ÎäÕwWàW¦ëÞ(í¸œôUK�f™ zàFR‡ŸÌêŠTÈ9þŒ}}ó¯*ìCI…,H¼˜Å§T’ú´1öþ±E4å¦�láƒ{/žÑÎm´¦^ßtÃú,0 ûE/Éî¦VkOaë*YÓk[i ÜÉá(t4�¨~%Z¾ìIC1 ÊiÇ’‘È«àÂ\~p,ÕÀ“³ìaú„£$8L¼Ÿ´À*)7R¾­ˆ=ý�ª*;IW'�{xUj$ d®(tüº‰ÎŽ;`Ä3 "‚³k1ìû¯'ƒÚ—ÕVt¤õd;hå˜<ä™MR_õÐâO|p%W>?&;^✩ÕÈÞΠ¼w¸A?ÎüÊ$§½„ôù¯ð<EutÅ«÷ß1µgþƒ<AªZù¸Qvîrñ»€=&‹°ú“N6há¦ß#d~Ì0uÿ(jš�8ÜQG½ï‰#OÊsXn‰ì÷F¸vAÌ4Z=—ˆ?¿M¶NS™6)4=H!øë+z;ù,qùŽ�r ¿O›HÓqÜ1–O†¯C tö]z _«È»�›ñÆÝ˜Uj ÊW�á¢ûR¢±ñ q/L!£ºBp¶; =×»ó…Å8{ŽÌšøÊTIyÁ›ú7¸üàFÿ;N÷è7QfdI³Úйþ"TïöizìÌ (•7†ðSXc‘Iý/JÂËm`v! cÂâÁD(Š*/5„“ÃK`ðÕY¾"•îw•ƒ#|]ø\>–ݽåÚ˜>!5»dðÝÓ7Ìž¤y¹€©=µ1I–\„ëy÷+4Mú ¹ôE Ú.—Â¥¶ûxu· J(®$]²Ki™àobù»¼?0r‡kŒß»>aÃê&˜CЫ&�†~ŒÅ¸EýhjâŒu¼ÝäýT.¬UK N¹!y<W—X"jâ´L=y·Jž7«i�(…Ã{€ï߆g˜ŠÑ¤˜a œÃ �<˜s¡Š].›êëã¡V$ ‡«E°¥5\w?Ágý@µW Ó8?=²eë¬ztÄ—‡�—ÕažÛ+¶Vo˜>°{CÖwÐ’ÛA¸}ç ð_Qb½g#>x™¦v’(s„v+¹³~oÓ+|?ÿ!ÊX˜á!ñ¹Ò/Á<¦çò’š/ùЖ�DæÜÀ¥�ô³¡<ˆ’ð÷IHüϬ‚Ëh6_°É¦h˜½Z€ ké’ŒWäùƒïä•T ÓÿHÕ‚<Λ{·ˆÛ‘|vî° ì”h'wÓÜÑwâiÝý�ºøØâ§Š[¤ZøÑ &�� ¡ÌS2SþøÔmò—O.¿>g\Ч‚ª ¶ÑÝr!œ‡–üì®vDß”Mc¡ÚSƒ�^UF=愃TÙvþÖÌîøç(—ç�šoÙû]ÉÏû èPUC{®ñbDýø­(JžÞ¼F…Î Ã�­x÷/•,eé©Oʽ<ãø‰•x"Éï½IwÞ8Ž|Q²Té@s*¡³,‹ Šé¨Ý„¬ KcDÉ­lE|þl%¾•öÁáØÝ`3¦CV…iP w8˃W;�cç¡â÷~òw}*ÛÚE}§ã@�t¶‹b^ê!°»×CßHž€!ÕläkL.V„!= Ô•qÃÞ¤Jüë¬FNL,Å›™ ©ób#`x`Å;ÜVÖBo.xËÏ\ƒæµÔÍÑž¤«}$×#/éÇÏÉÅWáÔ…œ@íÁƒ0ÁëIrN"倦 ÎÁec<<çã¡¥®øÅ9þ¤‚Y¾>ù5d ‘W»™¡ï.Ô[-C´ª©OÄúRHz‹2àb¸ ýºü¾¹¬ —ö8ÂÄÙ·$¥QÄtÿlHÕ‚k<ÀWi?>{¬Þd¡ý³Q,V 7?ì8¨n<ê�ìÄáñ� ‘ºei¼Ú- ãª?â" ˜¹ó„|»Fæl÷BÕM'iƾ\®oǾV##¾ÀÃQ=Ì•%:=÷ˆØ½u�ôI¼nÊS»ó-tQ¨+míQ2-ïÛ€�S‡ÈjÙPxo´7ÏÙ>5>¬ê€¼3y†i‡ ]ÐK¥›×?‡Ž™ÅP·+‚y¾»‰=ÿFv{ ‰A[œ²¹�³!ÉN™‘ö''u1kE]?ó›q€—9ÉuœðÌû@Â.Ë5eõTÏŸÂlð y>a´Î­†íó E�…R¸zÛIÐñõÕ…ÌìŽVš[ÝF™09“â‚J5ᆇº•4ŽÛrxˆaý}»­MÔà·'³©Û©(fã’t ¿›.Àñ¦=mý�M˜–bÙ¾÷hž*ozf~u~° ·M”Ñ)aÓÚ0-¨é®¢Ë¤PI$‹8:,Ä �÷è¯ù�hê2qÜÎÕ4™œ&/e@$¦}Õü¨÷è øÝbOº&q�a"È�²$FãßÎ{Š51,0`©-á‹x ÎcgQ÷k >^Iù¾�3* (ieŠß/>‡½ä;xì M I�o›{葟gèMu ô³6¢†74IÆØMTìW@ò2¦^MM&Òi°õy4´¸u‚ÍX©ù†NÏF”;•¦µJ‘«�¢@…ªyLÝñV-¤¾«ŽA³y>é}~�“î³vlʦsvbZçC}­TþüL{øgÂù)aœn…ocGqaK5ì[uWÔ­¢7y�Ñ©¤*bvÞúfpÓ3|»ðFèæôÀØ5°ò/¨Áúû¯–ÿï¹$¥£ve@sžµ%ÁYõmx5kži®^-ôHõ€@ÚJœÌ©¤æIÁ™Q^¦R£›µÕâ6K–ñß”‰d%ýU»ƒåæ¹ '`oª&atÖ(ÓqxS¾ð>àñQalx–²1�a²ß%²Ý@+Ô‚Ö�J¢Ú7›vÌJÂi•^Zim†ûÞVÐ[~qð´…¿©S"™t‰\ 7ƒìLUw^ÄC[UM›3ÈŽ"¼0,Å«’«YÙ‹¡»@š®Í–A÷ÎL<{Ò‹z]鍸ð9 ­öaž¾\SßÅA2ç²+9�&ˆ–B ÌðvÊ|]+ŠóÝV“΂ fèpQÛŽ6^ hû݃^w ÀÖþB¥…«Ñî¾VSgÇ8|uÞŒÏFf˜m_IB¢�S€š‘º°ú¥0-p"‰Ö§á\&/\>Ùš·òÑüóg"øñ‘ù£D2ÿJãý+[@ø)Ö=É$ìè¿}kBºà•¶é�³”LYd€ÙA{š1½Ï±à¯5Ä®—ÜEnW•ÑÅL4™-†×öÝµŠ O˜cÌ…[ð[ï&„Ü¡ïŽRó¨eôòÕM°Zß›ÖfYÂôÿ(.Ï@.¿7Û›ÊY… ¥„PžsS¨)¿¢�"Ñ JҤ압"‰ŒdTVâûœ +**¥”B´DEÉ¿ÿÛó⼸Ϲ?Ÿë’ "³J Ó-ö“üP‰ÆG \<ô8•F¿5©]Ü&Ž££‘ødcŠèò¢ÖÕùð`×;üÓ>HM-åpÿAº’]K{œp~,K¢¯#?Ãóþ^¶dÞ¸œì _>Òæ>áI šÚ(z_‡’©ì·P2êÞ?�’@õÿ ÐZ J!}Ó(q*¼G²û#Q-]¥¶ñ‘4z-ƒøú\Èp¨Fƒ0)Ž^¾ (VœÆ–ŠnYëMz{ùkßA£|Š;bJÈ!›‘�M¡¹ðjã¬8xdï«ÖÞô; e0Ë·º�þm¶„�2G÷®VÖÖúoÇ�¯�ClEÅ%¬ÚÈI:~¬”Ìú�o.µ¾-�[\/1*Î÷q]J™îûƒÍÒ¨£ÕߣÁBÈÂ7öÓÚ<ÈÝ~�Æs÷PÙ•Tñy àâÎüœÝO:0hÎ+ÆÕÚ{wãçâ»ôì«põÀu¹½§ËCïò‹Žß fŒ8Ú¤­Åýr8Ú¾ x~q1õp1Šq<ñ8h¥þE§ kÓÎi_Híð I8´ˆ&oyN÷FÚáÝ·¹ øšâöèhˆy+ŽÁcC8±R:–Ù‘í¥ÿÁ.=±Úþ‚¹¦‹uÒ±÷õ¦Z¥ô#0ðw„9Õøšš¼Ì%÷Ò£až¢(gnÇ(\â³/*ÁÒó÷1ãA$�»ŪÜmÿβ‘¸©Eôõö!®ƒô^|ðÄjN¡þ‡Þàž„2äÀ‹ßús˜z‡ y­–ÏÄ_yVxýöÌÚTn8¨¶È“[G‚ñXæ ìUΣ–+ÂñrF>(£¤Ët¿µRºæÀ_^èröd‹wxcä€b-÷n½õ+‚ÔÝN¥±sqªa7ÌÞ¡�çE3@Át#1]B'k>'×*¦ †ŸÃ·%‡^ºØ�.�!:O!³Y§y¼&z;qÂù†Ü¨¢]Õ ‹—cõKˆß2—�öç~d”¾}'EÖÙàäp—êX†GŸ€Ú9C¢Øx„~YBÈ› ‚îµR&ª0_ƒ¼¿YIÆÞ%Ð-Q‹é ×% t俬$ c=Ä_3BæÄBBÂÖ@§ŸZ>Ë`·nŸ r?î³zâ"œÖ,©šF'›™•E­Å�~}™C~½ N‡Z–o \ÌÝm”DÖO,‹µ!&Ñf÷üw¯nâq) þ¦6Â~²W^©¦7ùëAJÞ˜¶J r¤ä¾Ò»CÌÚôÓ¨\ñØ]Á¦8u\Ɠ¨ìÄ­zQ¸ã¼=ˆ¯ìBvô?h~G6™Í‡ý¾\ªªµò“÷Ão#yŒ~l¢»±yëVÜt· ¨pÈþ%0±×ŽÍú²�¾Š\oúÄ` ¬«£r¤ èš Nz-$^ŸrˆB­:™±ÑªÞ‘¿Ëùjƒ8”\¯%Ñy`üÏÞ¬_·»Ž™z>Ì ß¿UàÓBG{û˜:F=$x<£MDÀ/͆dJÎSçmpAl#òz/'±«Ÿ¢ê—xrµé2¶¯zÊ¥�‰æ½œW¤^©y÷Ù‚vÙ¬é5 sÞk¢tE9N<ãÇÝ‹Dmˆ‡S$’ ®â±”g·¼ð8ù/[fã¾Xy¨PºÂ�ƒíÍã(×' gy£!úL1qØ"ƒ’'gàûQžZþ›áõCÂqߎ¢K±ÿäZºë6ºK†y£ï¡Ú˜�Š9à´û6±:�NŠœà©"<ñ\°üå.ŸðŒoU{PAåZ£PoÊ•8*¦Ãîk"tÞ¾�¨¼ë ÉŽbßZ| ‚_ƒº]uË’à”ŸþW.[Ã×â!4Ê2ƒ•fÓÑ£XUÛ>’YÑÿ¡¿šœ odÑÃÐúÛ�®ËØQÛ|â –|i‚b¼¬ 8¥ñqýh{\›Œ�ìNkfýÇ  ”Àìg.¾Ê Á:!°ÞÈ ¥"Xjº¨S°›ÜÝâK/õòÃ= BžïÄ6)7Öög>SP4\BÕèZÛ–ײ‡Ü›•Ì”e²ÿõ�$Ÿ„šéRùHdÎòSå.'ØY ™[ºñøø*˜o…?S@ÿ�píª%�г@š&ÂÓø`óìU.øA[U�S©Ê¬Ý¶¹Ríäê9lc;@Þ1ÁÀž~hÛGuÅ’iû‘ïÇks\¼}„Žx%Ae:|¥fqôírˆ®Êu¤‡ÊØ‹_øÕ¤À4$Sæ¿£ûÛ `Õà{Sõ/ qGà 6ç‚D‰´�¼%/?6ã•>Uâ®ÑŽ]ñVèÔOGy½q¼«;¤„1ÅËŠcS¡0ü9¹eËŽuƒˆš|V:DwÍæÅç[qÜfÁÙÖsÝ.œ¡±Û¥kFX²³çnñA½Yб¨;Î�ÿPýÃ4#ñ3•o|ˆ¡çΓÂàßÜÂq´uŽ&ùƼq%CØ*gEãŸ4@ÐgúÚµ–~;ú‘‘ÍíÅn3/F$l)¬?$PK.p¨Q©)¥�·­áÕi=¼¶D’³í÷íÞ“ÞÝoè×¥Œ^Ú XŸ¶neò {½ œ™ó>ÝÕ@Í%\ê}� W ÖásÁ>F’>šý‡<øû´Ótg¥ï¸xÄ‚´�u¹—¯q“²äíeÝ[7 U:çB�4¹¼õ=ä Íç—áØn-ìß±¥¶‚§‡]ìv}›¤àÑúÔûsƦeâÆv[¼²ý33ÒÖ†�LçÁ}μz5‚ÞäAi�àn¼5êÖq¾uâéò$ÅÐÌJtˆ·û¬–iî×u¸ç¸;›f$Hu�V¢ý¹¥˜Á£WëÆR+î8a]ƒª*Ñ`Ø‚|V 8õó7ù`k”ªè‰O^¤÷£<Œ™Ù�ü×¼µ™ûsèœ9«Q¶ý.SZ nçgÔú÷õÓ{ñþ8ìr€ôyeÓ¨;2l³ú.�Š“# vKs–‰5cÖm£Zkß`X´0�†Eì$+øú¨°‘8ÆÝw?©T¸¿kLñ‘ŸpmêãLXþâ6Ì™–Ș D¢ ²öœZΑñ­$<žäêp?yo²f{”w>9XÊ·2³¯±Ÿ÷ø¢Dœ*gÿw]òFð"s(,–.áØÆbƯô×L3\¿ÀÏlA|›n‰³úÈ õ`ôZÖH?$äaã‡MôOD^¥ò8;å&î^x>e�BG3Jô§Aªµ<¼ZÇ5ù Áíq$¶XìóÃîD<±Z ¾ö q´Ç층^=4µ¼Žè”©ã§£íøjí$Teâ‚mßpõÆgÔ¼ì=jÝò…ãŰ£Ý¡¶ö{ =ÓVBS¿ê’—‹"±œG�Þ Ú‚²ùˆ-7øè2×tTž~o¯mç­`üñþ©ƒY2åË´N RÛç’¤áêAB�æ@©‰%Î5,Ä[~ÄÍ=ò�]'¦kñrKye/„õÙ)@�ïèp�Èd»¬¸¤Á™�{”ó|3äÔ `WóL,óçÁä´ty}—ïŠežæÍ¦‡»g‚ãº8¸j|–þwŠƒ;ÞDW,¡Ý”þ©ß~ú�wÍ=¢Ù÷—Q10ßù†-‹ Á™Mutÿ×ésÉpjvù1SVAaÞa˜~±…L~¦ê'æcÁGÌ÷‡%:pî%€‡Õâàvn©:ìÉXCl7^Á7OZ1ìê \ì&B$Y”~u W/WÂQ›‰!W>7 bà0`½„*ÝÖ@L/¼"# �Ð=B6ć¢x«²Ùwµ_3݉ÅÕb"òL&&×`Úû>"ð*Ãg¿#]2çIͱòíÑEúºÇ·|�¦¿� `ä“~f·ÕSÌ+É�Ü�oHü®³äçS ¸úì#úK µâØœü…Èó*î{ˆ�­Â!ìÊ�oÉÅz?Ú¡Êl§kÐrr—x¿¢Ó²ç2ak´ð}¢!/&„oÜñÛR�0xM¥„½™o·ƒð„:‡Ú¼tƒÌmÏÈþy˜Ÿ§�ŠG}é,û Z;œŠ›3Oá�VÜJÅ ,ªô§š>Ü�Âãct޶6.”§ùÚrœ•9[1|ú^ ®•§N‹+éÏ%(ù¸‡ð_LÇÒ­ò°.s1±´·ÀëÆ0­?‘¦rG¸1SÉ0×ü4> ¤!Ñ·¡Åí/Œ„ŽR­•/¨ÁݧäååPlT cÝ\Íße޹¢öLyt¹éƒâ†â̺�vª¤ò€^·‰'áBå죽Øåéä%Oëêi…S;‘&ò£YM-)›z�†ðúJ!ݺ€ ÷u’Ã_êÈä1àøäqK æÕÆ_0†–YKÉ„ß ÚžâÇ?bÞÉyXåN®­:D•Ÿî¥e£F°´'ƒzi^âNx.F^ÁòEœ¯vóߥ؛VË[ËȳgAÆ|ö8«“êë�`—øL(ød ÷çf�е $0¤NÆå°?ª¯ÓÝ4 ¤Í!·o�©�ËF—‡M` ¿ùfî‡�éþøhî5öÙõÚ$�Êé9�™G6Ö¾fe#ÔÁoÚu2~OýÆ>ÑYRÕܱ¨$�µQ!têŒ[œQ®|x¥w!ŠÌ„�3WE_9x»h;ÎÏ> µÇgB½p–~ª5íÚ\Lb#k©™`8gú’²¥/MÃ~Ä¢P÷kZX#ˆ?,)N¸ž‚=?•aþ´ã�òâ:\þ{€ûÔ1öñtARb}u”�Þ”K€ ¯‹äðî¦òåw¢çQw„ÊàC”9�o A< `F©–îZ³À φ�Å_WÂþئ;}jéÖ†X\�wm?2b R!ïû1æ˜÷3ÓκÆFS§‚;qýõ<:ǃªµo |É?/š–Hßt—‹IR䈾gD°TÙ¨vã�¬[³—�€ô‡T¬á=]Y�Ž[ú™åå›á�j¹`ÇCËæ½¡?~½ùcû°xO)Qoº� ç±ÍJ·™îÁ¨úçY•ÙB7jáëbQ¼ýžù³™zï-¥™<ÿxT’Üyò”vn#Ϧõ³;”?™ÊÝ{A"þ"t»È«afàc$ín-ÆÞäRhŠ›Å2šŽ/…X:$óŠŽë1?'¬áãÉ(Z«Â 6fñ8}§:Fµj“$‹u4!­ |òÏÓ/’3Å•qï–h{²ÓÁJéÔ³êá¹/©hHÝÅH ) kî ƒ‘Q,]"—†·´ÈKÁ­dCªÞ_Ó@4œ€�¿ ·~(DC!Y2ˆúŒkä?šHý7,ÁÓq‘Œ�––`·ÿ ¹#Éâ’¤u\’Œ»­YÔÊ;„< �À¿–äÃe3 p/%�cvÿÜç*Í ³�™àÄÖEpïöuvFgzwæ× XŒ£f`tU~¬;çÝàó>ÜËþË£‘Í„ïhi9³žÿæÎkâZ¼ô¤ãJY´1ÒÈŠé(we€7Ó pïE rO«} Ì¡Ž Ã—aòbÄíçrÁ1®„ø>ÓÀ ­3â»F�êû*q2ú•­SøÉ H¸á—-ÛqX|7¼ˆç§º7�Á&qЗ⡟Âʨjº>ïz@vDåÜ›CìüûèOIxÂ�‹þ#crH陹¤MºïŸçE±«§³°Ãd#¼‹HeÆÞFÙX¸ÞÚÅḩ‹O¿„“·ëÀýì]ö›­,\ûonऒç9›p~Tærþß~øþdÜ äÁí�—¨×ç~¼Õ¢ˆ†ÅÏiOÔs:r©œÚìÓDEipPZF'µðÔë2Ӟν>%gk‚ëÓ}À³*>E&‘¯ÝpÁJýXy‚ÌÏ\Q"‘ñ/Ǻ£Àÿš2©hþ7÷®7įà •B ZUÃ#ë1øb™V¿/ØžFñ„´<:úÚ×Ëã­¬ t�©ToRD‹wQ%·t¿¸�\mKò_« >(ïc¿L‘äÇr–¸‡ÊOÜ"7g`È%?òÇÁ‚H?NÄ¢Ê÷¤²8]1=—ÚL¥£Ö£®ëE*:g�Õc�y/A]z-ÉÓ¿ɳêjê{žêÝýNvP¼†÷xçía¼}ÛŠçì1}± -œ”°º”3~v2ñùS4×õ]|2ë*¢ñ‘×Aö“Èa’ëSB;ö”�›åcp9«ÂX¯$V¨ÿŠ84üÉSûƒs‚E})¿`Ižoºöë^ð̇ù›Ì©ê‹0}¯ ˆ(,ƒb)lKÿLÇ> P#ó(ºp0‚†.âÁ•ýZÂTa©=°h.Dk>Ài•gè6Æ‹>o=Eyú°n橦f§1¶³¨’©k!Ü<bcxk/mpþŠ |Îÿ‰Œ­¨¾|sFyýaÌ´Ó†‚éE¨¸0›N•¼âæäé@åR jÜRȺ;eq­Ãíè‘ѹ´Fô�ò$f_Â$·&ý:¹­£G;;�‡@Ê*wÃCDø¤�©˜ñ)œªÄtÒ]ÿ˜wsG#)|oúhœ×1<ïñ�ív|JGv;’b� …ɱŒt¸ö8©ËÁÔ=�ô¾S[&.©FRõ¹8PTBÓÓ'©bE(ÉK�‰RÎ Ø=7”YØ„Ìp%ÍÒ°‚ߦ³Âµˆ†ÈeÐo:B7 £¿lžÂR8–ÿ‘ú¸›AXT%uô*Ä7Q—˜¸ªw “KÁÆ! U›æcµË;”Ñj¢ÓwZ·ü 2ñÖžX5 ÂÔÚ[¤/G.’*BL\g �ç~uÚãñPóXc)DêcÃQÝÿ,XÄ¢�VCÌwÏÝ(,ƒ”4ãÄž�ϯÄÞy'ØáÖèÇVáòQøÞÈ’½Z긄qÖñ©.bœYDnݤÓ,£t%¼’s­_⤾ÏÆÎ ;îÐ4Ç ¿J¢Ø4@¤+¥a¶m7I®KÄ™«^éyûÑÇÞ¤¬«%é¯ËKvG�òoÏèÉu…D3n=Ùðž^þû�+ç_�°q22ŒÈKÏ績ýüZr…èÔxà^ž' sè 4-5 ��§ašª'x*Åà��ÉXb´“¶·¨ÁÎw¹ärùjŒ¾hJþzOÀ3‰³¬G„!.ýHÎnœ�Í#—áàú3ìv©xÜ‘‡‡¦ÛÇ{Å8ºŸq,ºE®³~$lÞ#bÖzþ. fjŠPîáZÈL[Mwf¦“Œ*9:´¿…VèÏE…SGI¾©éþy—̶ýÛ¾¥bcÔõ«gž 'ÑËBáLC†S~y –·„rõŒá××:uÇÜ|'È9xâ}ï“ÉäÞ�Ä“w>üŽq†«ÜHVÛ:šÆÕká±ìX¨�ðÖ:�¾]gƒŽÔð…}JŽÒ—K®£šH,~…^R¾ê<½|8俺 xslF…q,÷4ÅAIvO™4pÃM‘.W£¿%Í °Fœ$)”¿ÐuúgÐÁ¼œ†Nm„‡w¿Mç½´tÒ�|j¦?Su Ðuæ´�ÑMS/GË6zPéÝedpž cQOEx«YåÎ,\ù§Œø™Ýg¥ÓÔáèÙmtõ¼a&®À’> ª †­‹pǧ{(+ÓCÇ;\`¢4,o†Ð¼óŸiȶÝÿxä±¹c ßu/±½ºß©­h+ï¤Vñ\²Å’¡ò¿{èš” °h޾šª`Ë÷ ß?gžÑ!C�m›¨ëZu*û‘¨µèàõÜRzlÚzôu*°òú0"’ŒG8UäTÐ%&ò¿aRá' �A§‰xÛ<ÿq™­‚Ö<¾0u�êPÄã‰6¨z�pž £Úš-#EŒ#¬à”û öÈg ö¼Ã鱸Nÿ:õæýD>Õ…{¦3† ¹BÄ–^ª*ìwLxȳ�˜ky|ï aW‰ ´NÇÁ‚:ïïô9’ÅÚÄ⦤Tœ¶M =8 ˜�wra™š)µ¾ÄnAKÌyÚÛy†FþNÀM kàçLtM¿A'¢Ø¶)’ éŽ»øÅ ¨:�õ8�5ŸÎÐë>¥À¼˜˜ìó€xëYÄjÞœ3?�l˜âBó´Åxß;›Ýa™C³[²a‘ƒÆ—ÆÐ¡TDÂ>Åbp¯.])¿ rGÇÏ»G䎠 \^ØGõN^¤;wLÃÍ®^0*µ «WýÅi'jõC’h¼'.OG±·!äZ›ýé"·áMxM¦Ð²æ?$úú*æ1ß}ñæ̲çÅ›NåP�&Ko+ý^ªriŽ9$ßúȺǨãßK]d…Ò_j¿é# Œ¯×’i2ë0ÑœKæBñ×"8u$ޏ¿ž…*ñøm¸ƒ,ªÏ25TšFEE ) �õ^Ö‡n¯%1OiªåKÃÅ&ó¥Dm�‰ }ÃÅÄí1È®µà®ß~V:ͤJГÇ÷P—Îp|í6Ÿ´Õ;“Þ�Qòá” ‰}¹ËbÓÇø±ªø0½þ'�˜j Sÿ ïDí²½¹ —3§è±Ë €…ÄáØ>Л_Ф8vÂö¸kv7o{>Þ,ó†6¶Lbt º@"–Fv’Ä7gÙO5C¸0÷©õ-Ã~×ÖD±õwÌ„k¥*(¢£�…«îàêxòäÍt4þVˆYÌ¿~:_‡Kæ–ã‘8[ôœuŸ5×|JËή¦öyÃ’‘[ðB?‡l‰XÅy›)�%Iâ˜sƒ¾�Á¡l°þá“„Ö-£ädÎZ"j6H¾{pqši,K~[3|ŠÓÑ:j™Î·Š0ÜþÛµ�‘×~:|²_Æza(Y ÀÓNEž `½Kd{©!¿;¼ù°=Õ“y?'‚F½_†ó“6“pbŒÏc¬Èà ‹§ÊÈŽÝ{H¦í*‚Ï1ŸÄm@Ó÷2ô‹‘u[;h¶n7ìì£ýmÇà@ËËÞŒ>kþe˜:Í�æÆfqzGv¹TÐK囩?)Æ1ì/æ“çÞëNPµBÞ†�Ð�—³˜Ž*¸¬;ûƒ.›ªM Ï'O!ñžäŠ.�íŒ@(Kb@õz±s[‰Fb1þ¤06ˆ½£~�KA'j)©þ3¡ëOõC%Ë2Õ o'—ùÒ½ î)`ÎŒEbåò£°¢ô-×»ÿnW·ž uÓ…G7áø¶v¿ˆÆoŸ_k¯ÛLw:Ì"ᚿȅó׈ÌáÅ1´c'ÇéÖ5E0÷ö-vÒUb°£ˆ&­äàߥäP¶+å ˆ£ÕoÑæ¼-ëMÉb Yî^¶Qd„SJ¿…”¬j¦ihÜï�I5Uˆ(µ ''W!ÿ™#`ÉÂM%[þ¹P#›ºošVœ†Ä›M¨¡šÕ .hR†{-Àg,ÐÌÍ, h>-Ù9“‹A¿Èx×tN  äŒÉ ß@6zGÆãÒ‹Äýñ,ào‚˜·Óaf} 6Î@-fðlÄ�-E7iEXÿcŒ<~¿^Kšæ \"Â?¾Ó›ŠWXM©µœÝ&­¦û{+éß9�Ì¨]Â¥1g”¨_5m�ݨ<>�¼´Ŭ5Š 6Aï ïÄg«ùk÷I}„¨½fp¡x ˆÝ§uàµ#Ö_=ºeDâ?[xûU6sy mÑÊæÜ„ýn—Ù%B'qm¶ Õ·eyjÉ¡C¨/_‚G [’©{Š©¦fýÝ"Ö9ÛqZ«#^ã«"iïÞ“ºc�ØJF*5!¯³œšŸc ºbFÃw²¾,÷€J}°UP‚öÌDòVln•@"’#ˆúç‰úövóz!LÞ8 bqä …`¥Æ/fxý Z({‹n½*él Þ8ÓDÖõÐ ­‚�ÞÑýîýpfç~øö´Ž<Ç\Jš�2}êà 4{rü`C×EpZ-H%ºô`bk¸ÂL[òo:¯Ã™…›hªXù»—9\w²ÿÝè%EüÏ‘æXTðræ÷€V™?~N«Uÿû›,9Œc(‚!ÿ â]¿@ª¾å ]ëô¯&ÿÐ\Í!º¨qD„Ï�iýרñ[oñw’#£¿1S„„ñuÐmøkC’ÌáEõÒ² ˆÄ+jPy‡Fç. §Âi qFSæ Í›HE’Åàä¶Sð0½”v\gxT?³š*MTÂ⺉ã•(v<É’Œ=9KãVËq¯­`}"Üþõè_VóÈyßÁþâÉtM¯"<К «§£îîLv“÷nȦ»P3v„êŽ/ÓïÁ(òp˜0‰¹ iX¥,NÜePÃý™®¼«–Iâ÷gwÃW¸ríVÔ4¹OótÕ°²Æ¯=�nÁ\ó>œñ·’mô’AG;/ªìÙO6,3 Ÿœ†ˆqi5;õ±Ž‘u•!We±k[0ˆÿ¡Õº2 iñ˜æ~“àx=°…ÂŒDÜQý‡ý¯ý(Þ�¦Õ‡{ÉNÚ,¦’ë;i&Ÿ2UR¿�+^Æ£ôsAÐ9¿®(O 9ºo„Th´™ãÊÔ}žé;R�ÕÍœ=3 ÝÇ–ÄúoÉ¿Îrb/ÅÈÓ®þxÊû2­¾·‘åñ,µŸ…|/ [’:wÛ1ëû†¨˜òK¦§^n wÁòok©ÖrC¼ºZˆsèêQ"¤g:ã*àëpœ�äúÄc¥2Þ]½ ¿ÿî'z®ìÿ;e8²­qc�9Ùì�uó±vA Þ9�Ò2 ”7—ã9ç-´-‚-§nP¯Ã'ˆBëO2TÔ„œk…ÐW­� âu“`óh<9lÞ~ä·¸©1`üÍÂÈÍ„!ù5‘¨mà�ù¯ji¦G),ØI½ªÔñCN =nqw}.Á± ¬‚NYWˆ¶ž‡›æX°ÑÛ–Ã=ræÙ ߉₋ñŹN;%‚Ǫ%°.ùèÏ™ £›¡ñÍ0hs¯&O*Öaˆn0$ñ”Ðqï#ô³½ 8ÍÙÏ,‘t„ç�RôúQ–š«d‚ªÁ¸Õ’CJ"át„$Öò]ßÚIÒ$±‚Ô>l¥¸Ä�<+§ æ¤/¿œsÈχn¤ùa™]Æ„ûG‚#Û ‹ÛЦÕ|�·¢kD½yú$oÁô~\&²’Vßž‡ß=úiÎÚ8tVºG´¦àšXM¼­¹›e«H»pé2TÄOŽ»è­ÝØç"ƒ ‡<áà}CTüGâ¶�¦o××/9Ǹe:Ùí\º“ï±Y=mÈ…#ÓaìÔtø`�L6¾YŽŠ…|¬Læ/S£/þ´öÞB4þìËÌ×FvÆuXÊNÐJyQœù°ÎCv7ð`¨þiu_6„ 9±p[>vmL­6œ¹l}šqû3³ÂаmMF°Bù6.O³Õå)ø|Ég*%¾,ü‹Ž'Ë7®§,Ž’a›A:."ê¬Â§-UäÅ^<¨å—ÛO&c’™4 ¢yâê4—›Kˆ  ðâ¡bŸõHü˜")g<{¸…¶-ÊÀ‹=‰÷»ò´c)'÷úXÚù¾&úF3­2_a¡s {ÿA#SR ƒâ+˜¢‚KbŠi®Íg´ÎÔ�OV= Ä^ħj0CZ›ì^÷ŒJ&W‘V‡|oFÅ6-ôá.Á€ 5r²é>ùìoˆÓ–.�}¯%aY•& hH"VãÍ$rÈM3=Ó�A�^S'î7k0i;f}ºµ|Ç~’1ãMäk¨ ìQ†o~›!þÞ [sñ/u×ø(˜K÷ÌYºöaøA.•,¾’¯¡ ¯’ µ:szM.SNÜ!üöÖžjÖ-†6ªK„4vc¤r(¼`Îbv�=Ù†–¢aÌtÔ�ºŽ:rëq»²Ëynâ´3O‘÷ñ^" ?µ�´Q�çft“VêmÄŠ}é(yû$ÝÿX‡ÉCóÏ]ľy .X‚bB¡kÆe˜¥½¦º!1OpvJ&ÿQ}Hô¼ŒÇb�xHbφ)ÒØ/FÃÂè3?<$˜D{¾>×Ó 0S=‹0Bt™ M¼ù4Êxµ0Ì…I§›$­§“îW §—ERåoÆÔ7°Ž^½ù�8h¨‘Ž��ôE!¡1f°!L}›B`i¬ +ïr Q®6…LV»£ìO*îqœŽ°—ÑÏVNë_":üáæÙ@j89Dß`k>�uÞ³�Nˆ"sÅXâ]MV‰ÿV~ ÐÎWOêd4pÕ/AÔœ &LÇ·“ÎçÄ“Á×0ë•™�†žx†ùMé‹7ìL¿ó´£}�ob1 ­Ðcçróà Í‘U¥ß év·Ïtã^I¼o'„¶nú¨¿ú y!È8¹·à½´­4å&àpì ö—ÏtÖla æ†/“–*PñI†/—�î=wiòÌŸäšÉ=²ÿûez"$•¸Û³TyÇvæA>¼›÷•ë¥aOŒàuÜy²þ˜ T_T#µJw1øÀ56êM6~úq“l»T¾RMÅz˜-–CV­Qƒ#UŽT¶ÜÚ®›ÂºPmxõ[ì^£Õ�*ZýQÖ”'@ íÞ¶=-q⯺Ü/_£;¿‚H£lÎÊ¥¿b¸ãòÂ`ÓE7jË`ä [¼÷¬”86• }•Äö> fG¬AùáMW!C�ç�ëJrð¾î⩤‹WÅpw;êã¡_ûÐù®/Žn%1OR»Ë§fª@çá7ù�éØ�ÁÜÉR£Òž~xïÖN6rƒ'M£jŸ˜êtœUM𔾒ɀé°!ö ZX–1kΫ¢ô!{ Ÿ­™° ˜Í~$op)¶ÊhPQÿSè3O¦.c$�GãàL)üÌs‘ð©Ï¢K•‚à?^#T®ÜMq’À™ÚJï~˜KâkgLÇ�“?¯¸;¾¬-Æ;LV[¨Ár…Z:¶%úä–0R½'1CðÝ2ÿ,ˆ\ßI\‹ƒ¨ž#º¤Ôb�V( zª�}¿’iKðÛ§¿ÜÑ×ûé¹eóèJÓ?¦�‡)^ûBLøþ±©#l6净­õðèÕgúŸÏwrñÑò(žWÉZÀŽPîãT°ó…£Êp[vŠ$œÆó)?1?pÙvð*Æñ Ñ€‚5Dq@ yÿý‡¢«ìï|z7Åa.=µYžß’ÄÑÖ/D®Üs›B¹ª HÊñÀñß}¬@Q'1Í'„¬BöÙlØ:åJ. ñï½ó!ÖA xœÀ(d.d »a¹L1–·†A#,»w‹úì© åvîHxw×[IX(î‚¶#ðë¶.+Þ–Hž äQÇœr쾟Pˆ»ÁOLE!áÔVÚ]NNÚÃ�ìjc:/ùì~Jk‚enÓ»ggb‚­Ѿ” C³º°ÜV�6—bxªîŒ�…þO‰ÏñLl^ú†¨ZÕ“¤‚¦mß#zßm->½ÔC¿DŠàŽ—ÿøÒèä' ®£"îÐb&ÅEØÜ÷ÈÃØÇ�|Ì]Ópûß&}Ì Nª¯¥gw»á�àxé!CölÞÎB§¸’ëOA³—mÐ=Aæ“¶Ò+•xŸ�·-#èëQ‡O®w=Ù�¬�¸«ocFœUÕÑ;âHy³ð>“ÀàôTâl¿õo³„oü4#ËÎÃouèñ^“QLÞLœÃâÉpÄtR3OÎÌÉ ©�„¨íÊ'IGgú?³˜�«ï� w:èq‘¼ÞƒsM0úM�©ƒ�1‘(ÓÀì'HHìBÔºÛA¡¼ØW@æÏJgxë>À½e¼ÌºÆùÐîÚ¦r`¡Êm°ÿF«Beø¼à§‚mõ¦‰†õø·Í†Mv Aï(�R#Ôf@ÅN\ÂKƒØ/n­ ’ ‘‹ïØÕ(š šm¤=‘ÒH™9(¸K‡µ·VûÔmÃy>Dñyp3ÀîoÃw�1x±Ø†[wÍb÷#çØV,Ÿ}ŒÇÏÔÔ <&ÚêÓ÷‚™á[:úY Õ‹ˆÖjAZ}K¼½÷³Ò±™XÂ\fàj<ù¡ÿ‚Hˆú‘õšØŸï É&1håùJÂÍvSƒE§Iwœ¶Î…�•(’¡‹k-×3�:ïQOeGp®®Æ°9,îO ‹Ü½¤,æ=Ë7¶ãó•9~:|`gÑL‡ç;»YÉàÒoHM®�€,^ô–ûBóv^añ0Õ�Þ•Ë>Œ…ÂK$eÑLÌ}òžæ_»‡kvU‘›Œv5bZÎ?BG'ò°íüúœC‹n¯Ùf_AumÈØÓRÊá:‘=‰eŸZArÙ9²ªa�κZC_/¼I—}³çUþ;"(—oˆ´œw‡:×Lšrhîòœá¸À�(Véá¦+0÷í9êè$�o`Û\�ÄàãÊúªÃ�‘ÙµÛ¢ALa{Óq \�bÐÆX›ƒÚIå­¹pÒ®…vžb_™éÂvÿiÐ{m˜Dÿí¡˜â sôÑIÇ =�‹1Æ8+l:�8,Hyÿjc�Ç]Oj¬z ÖkÀØé ô0*øtpe‡$Z&ÈÀË�³á¼Õùïw^_þ –žÒ G»B˜[#™¨Ïz°9 Z[ jjqê fLßÕᜉARêïD߬\Œå)Æ ¹÷4ìkH�{k£ëëñ'¨(§žNä­BÏí—©Tr;¬/ºEw-ÐïùYÜ“‹¥AÒ“R;És˜:VAÚÍšñÒÝ}8ê’]覉. Z3F¥“ºw°1ÚŽ¦7Ç ½Yôã©X²îœ0½©$·ƒ’��÷l¹L�úÔkcOƒi[{gvý{h5”Qsô�‘FèÏ‚wVÅ Ó$‚R�ÊT\ð)ÃôI Ä òx�'œË.LÆWóoÒ_¶¥¸k$˜^ÿL¢8^0$ –Ý ^}N}ëçà‰k¦˜,uy*m0Ot#ÊkÄÀ®Ä_ô’`(y«ÿÏçצ²;çôÒ;ÞG`óZ=êo|uÆDÀ%#R¼X…©Ÿ¦¢ÇëØûy›°QÄEžëã¾ ŒÊb{¬ËŸKnWZ�s ºðÅ›¡ýt3^~5Œö½Mú} Ó×…¬œ*/î»s ³w�ÓÍ**è5îNh©(×­ÁàKêô«ñ^,]ÜG¿F…à‡‘#ðÑÚÅ/�ë:róf]0s{$ÊBïõ™Þ]gCo+â�ytòÛòmüß�ÓøA>ü(»N a›}ücòó‘#˜:¤k=î“ú3ˆWŸ`m<¯�uØîŒFÆx1F—ž ¥®a5ÍëŠ7? @„Šh%_—?_Hâ‹ ºoHŒóÛ¸¯¶UÑkþ�¦‰Ò0ò�\éf1?â$åèâ¥3ë ùÎ….>Ÿ¾‹Æ™õ¿ˆXZÉ/?Ýàœ¼˜¡-AÇýcBýQȶËǧ[7c¦³(Ž>v �bhЂ—L»’=8½ „Îì0¬PzFF<¾SÉ€«¸d�ìê!;Û²‹ÎÝ ­�Ûð©Œ!d+íd(²äì“|*µd;®œr… â»ÁRn�Yçxžš¸dRÈõ«Õp¹Î©iïlOêñŽ<à<&7&ù1^sÕÝ…~—ÂÉŸÔO¸ÔIÀïV�";»‰ë÷jìãyIª®Þ§¹[º™}ê98#ý éª"ë×þ‡»+“òÚ›À9¥H¦«ï¡tT0IB <4ÓÛZK!÷º(^k+#£/§ÃùÓS»n“5 Té¤~ØCÄV×Óaµn$õõpÒÍv$Ÿ¡ö« 1 wŠÞ¯P€×s雲,´H‰¢ïêté=óÔM3‡Ã4¸5\@´-… mŸ2#æø©ñ.«â¨FlJÈß'û0dï*ê™%I�&òÉÁŒ»¨­�{ r>¶VÒSi&ôli¯I&‚ÍÒ°oÉ*-ÊÞ i„–—üd¢]Eçx‘Ùy‘äÙƒT\šû]F…P}0›Yí)\;سL?†€–txåƒ=Ì6ºµêYã° ¥áëºcdbÅ ÜXû‡ \Ðÿu©á>…à ´4ü1}¸é<�+ò›4[©Ô®:¡�§ÌΓ­ÿ}¡O’gã"ílˆnÿMî4Ð�ÃËÉv?˜˜ˆaQï­ž¹Ã}]pÄj.Ý% Ë3á¦ïlò9. y¶�£ëñ ÏÇr®x <ìª g-'õ³~ÓésOâñe 9ƒ{å1äùjXpðpצ.ûxvkŒµzŽM+ÀÔîçmx­pfÞq£‡v"FGhœN+\|*Žt~+Õ ¡újGAÆï°ÞSÔó¥V¦¿ÉÝé‡á°Ü kÕVK¢2îЇ íT¨ê:Þ8³dÆ.›>²['BâàË3=­kÇFiG’�âpÍû>SÑXc*ñãí¼q$ëfcéP3ÔØú±?fR‰¶¦º[GYãÝâ�0n‹ìáTâ›üø>ß&üåM˜¿w/û²È �óÁlC (¾Ar{ýqU€<ÊY…�¢ðkz69©bM7ܲ¦ Âù •° wæ°6F_ØÞ÷ÿr¡Üм>³gDµ2„Tÿt‚"¯¨üo>æÈ �’…? �P¹Èª¦"Qg}ݺú7#ž’Æ=i$Š·‚&)ÃiÅñmì²Ò/lùi&¼í|¾ÁÅ@±*º—#�jÁzµüy5ŽÊX½ Z5Åta”¼[]± à…Æ/ÈÁ9�4ö� Û´ZUNR¾"�ãb×`¥J€õ¼yœÙUQ¸Àkga„#^ˆ•äøêÚ"¯ziÀ½ì4Èå�…Ìx4Z×g⾵ϩðÂí P.C$[5ФGªöÂ�CÀÿ¾œ88.?ËMf–¯ª ï?•° ßÖÌ�,"‡‰1žÔˆÅJH@¾M»#w¬žQÀlžõ€tåc´o ¹úOP© î6ià�"“rè+TBÖÊ#V‚B0T»ômôˆµÒ]x•·bèQ¾ౕ#Ê·ž±êæÞàÔx—¹ç»Îä@š=ã*øöß{&c6_áïÁ� ?4B~ˆ\!™NgP+q&�³«OëMƒ�/CQyÏ|Vhjœ•Ù¹œ™\4ŽãýÊ Ò}ŽÈúd“É´>þŠ\µ›‰Ó*ýa_>Fz�ÀŽhÔú“,á Bt‡ðÞÃF-]vÆ‹@|°±#fτڥBµ¿†ý‰}Ðn¸YCï¼ñ@Ë&=Ú4K…ûø8+lé4åÿ1\~=·Q¦Ò�¦ŠhKŠ–’è÷}N$4”¢ˆBVV¥B6•”ö i(mZªß÷œŠBDDdôšÉžY½þƒçóœsŸûºàöIêp”$™Í�,t¶ |Àº­9‘tOH4ÝwR$SßñfQ‡¦q.LIË‘E8ÃfÏ™ìþbbÇ@©¤€m&gR¸ŠZï÷n5k™rŠ_$Qã¼Ã0sØFäÜ7•QLèr«-ÍVLØ掫H|I-K`Nâ òü‘ ¢Uè˰úù0h»ZÔª¦Ãwñ‰°feN û”›øø-÷XK­=nPýÄf,G3<�àæ’3<8_AñчI.ÿ1Þ(Ë…¯‹¶mP"Š;Éz¿›¿8|4¼”U€Îލ�SOg�°.`kQo�"Vô¥ _>V®0öe.(ÕѤÞIi<Éžô¡Ôq/q0ñ4œü ÏcÖ†áŸÉÑt k3dþ=H?Ç“õs(üä JÿÀìZŠ™qé]j–“Âg�ˆ]+sáœÏ)Âô‘Gñ¹ž�ܪ³Þcêfi”�©ô àuÚŒƒÞ5^'œ`óºÏ´-²íÔÛ©Øñ Ý™{“3²­<;¹¸²ñ aj “†%ƒþß0«ö cX$ó oͧ®µ« «kÙÐõT–«u“½S–d¿î ayÍGÎúäYZþò ŽJ<Æ7ò±� Ã÷ÞÂÙ?ÂÈj4|øý'�¨ffè°J´é‚� t…boòc V q åÞ8ÕÅDSãñ\¨=«µhQQ�jY;¼fÂÑ/Gq¤Ùo~Û0+æÝŸEØ áÆ©˜{‰'DzròýÒ‘ãÕÑ{æq?÷0}U�†ïW@”u­^�£—æðsîˆXÿ8v“ÔF“Îâõà±™æJO¥Ä«Pù’\Âõ`ýi]2ûv7­€YÐywU<ø„måC¤ug ¨�ËÂ/)§ a`.ü uìò°sd4ÿ3^¹ –*œÇI9œC‡1® ]ÉάúZâÔÉqðíýNoy6„+†3õÓ™¬ø[kY̆"ÔÉìo>ì]û…i*YcQ§ ÿº ¨Ýí“•@W�.¥Ä@¸‡ûüÎ�¶²%066;†GÀó")FÑà½ùÿÓüì·ó�¿ÚëI~Øk¼ZZ„ö®ÉºÜº»0äÚE.H²™^=!˜ªv“%6—¢ùJc’wgÚ·_ð›ÛrðfµÈj †Š…ûuÓ²ùnðbÅj¸)ò+[ÊI»ykÑ/¤µ3£ñÏ ’“à ²t�ø&0üë «O§ÁŽS} à îµÓ®õÁÀœÙ$ÐÓiDß@zIR–¯XÍéq0YÞÂNŠ5M[€;�AÅ}Mrq°‡ü–á¤÷,†¿ò­ÚÓßÂÛK¤tÁ –ŒhB½ u V¢{Óf“A��Õ¦«“X6(@Û²ýqdbõð“!¨Ä›^íibqGÇY�=7GÉÁ¬þÑìñ*ŽøGaU©'}ø/©qyܶîŸÓœêMÔ?í3ŠÈÄadßn {1Æ�¹Æö¬Y-Fß_ ¨K·…;å(rS1ýG0Û0-Í_[ƒ”¤ê~q­¾”ÞÇéÀ·–[8ñÂJt<˜Ä,×:ÒDû(îñ˜óŒnŠÒ®eÏèä�2­{!4#ö�¢Í9M¨øC]ãmhͦF²}6§s_ uîBj ZÓÛ&�v÷4¼Žùè`ž,ÝX�…‡4ØÁñ ô)7 ìVj±ßfY[oH†Æ55oÁêÒSè#GA­©Ü¦ãa\ȜӼÁË$P½ˆŽd/"ýÜÕ¬#>úS™ë�i`_¬HË=ªaÔ¶ç4Rñ³Y2 ®ú’…Öz‚õtVÑ:%í)ílæûåÝÝqVÞ4Ò&›DòCéŒá2Ú¼¶ v8¬aFÎ"$y\¶iŒä5¶æS÷öa¥?/……qF4ß2N]ía=Û?óoV¼áoú§Ð±#I <ÇörµËä1HP)œU9=�…'¤Æ6ß¶…Æq†d7Í�Bw‹¢ñ/+ÚÓpƒ]×âauÈZ°h>Ò›BÆ·w�yvlÐY‚R!�”sŽÆgÌä}ß–,ŸŠý¢Û±3¦�_òF†œÖ\`'ûR û—-fž µ2˜õFX¤«™¯þ"¯ç ïÖÑÕAEr$Þûé;æœ9�ža:+GYG¿9‚�— ¦p<ÝTÓ‚¼K ô3ÓÍRüÉóiK1*bWtWBŒ‚,Õ—EcÂÚ§ÌÁè7ç�+}ÎnM�g/l7ƒamÜ,bïý¸oA‰ðkÛ õ­œJCÅŠÖG槺k[Xú®DÁåðå4vÇw–'™ñV—±z£=û¥a[ Ãë0{”øšIå:ÓŸù°¾?„6”¬ zw ôF8ØnT¦%MŠÌÙ}.~íšÈÜy@»Äl8¼¢Ø´Ëx/Ñ_§>ާº\!)ÛFÛ§�ÇÑdy¹�EÛ„QƱÕBõ#ëQ2ØæÿͦŽÉzzèÝçWÜÌ…çàæêo\ímš�|Ž…’Ð3ê6¨7sŸ\Eé´H™KH4‹•c›C|ŽšdžwlîRÝ–V²Y³šm>:‘pté¿ý«žÄ¤4l(éT›¨ò JÊ‘M(O7ŽÕL¦à-ù\ò|osçîè)`ïm�‘ÇáEt…ãï¢z¦}ã8–§Ô3ËjÖûwEžô†³‡@2Úþ“I�íºä÷t/ü’O€U÷-˜ûËëÐÊ�ñœùü’¼}p&ˆ•?G‘ÝZ4Þ¯š3_3Ûàw¤#V‰Ÿe‰ºþ[k¯)[aÓ4Îx»:#ˆ½Ù×ËAÍ}<õí5ÉŒµ$Å…¦›—G’sb>i·¤óLY~ ìcp®Bù:á@HÎ[�K”(dÕ)h¼s Ç× s§ ³ù>@ßmÖaUFói}™2›¦¬úË™M®ÅQÛ‹à¶gl�F¿ ;)þe4F¾-ÀÉ_@°}™lׯ“&t÷X&-S¼„žÛT˜êྮõ=¥ð3á>]zŸY>¶V³Ò¢µd6ë××Ozs^²)NÐÇñí¬¨Ç]em¨Iî’ G¼zFñ#tp“C!SÞ6–ÞƒêwÁþqƒørçªT(…ù©?¹m'œhpþ.¸iŸÉT¢óqE~¾[ʬ̄¬5°“f=yÌýçYÏRSÏRÀøNîƒoð3MåN)4éûŒ›ä³™á%KÂQ`Ø’G-æSþ~ }TÈf5ÖáÇÊ,:šÊ&&Ï€”9C¨—>‡ÔÿÊ0“akÈçtÓ�7œš}øÖ¶ZAå SZg„ê#DHµ)’Þ½.ÀNëg´su4˜½Z�ó®öƒ½ÇPcOj7ëÜR‚Ϫjyåú×ì³›&¬2o¦Ý=[i^ýv_T›9Ê´’Û¦÷ø.ÓŽ�a䪌|$³Í¢V$%%Ý4з� æ©Ð]I%Ôñ}ÆË�ÍÃÒdeØ7Laƒpgr 1µK Bºü›ž(z8‹“Þð.ÁðíæIzan.×YùýPšªSÅîîjaƒk~p×B8óvd};¯þ»‰WžÄÅP Y ÃMH:%‚ã¨Æ=>ä)Ãbýá´zÑInÇÄÖ2xV@2ðeã]40–ë–gØ!ŠÛ/‹Bg½â:òÏqÙÍÃÙô‚|Úv£•)©Ñš®«ÜÐqCòüNWLÎPò·s±NË·ÊSÆ¿.ÔkÍÌôÿ±�Â'~Ã(UÈ}A 4ވݛðŒ[ïÆº�Ó©©Sþ1ð |-€aÏôØ çÛì¿�¦ï’vp¯J Ž”;ƒËþXæÿJ‹�OŽ�šsŸ¾BiʈêSN×§ò_ÆÝÀÜŠ‡4oOÂkùä3é.­ ›eGÑú¿·hØŠ)¬{ZõOׄýrpñ¨•þˆÃÛðÒñ�Îç‘“øE¶åh¯#Ô#ÓŸúlb¢(¼R‡zyø$q'å6må.ž��ŠŸ!PïoG&YÝü£òpôOÊÕ>°7õ ¦äÙrá ”Ñ¹ß»¨1=šÿyÉP°rJ1éUêÑqÚ±ð>¿á¸‰GÜ'îÒy¸²�I%ÙÆ·±Ugl¡ûéýÿ‘½ßq……Ž]‡�#áì/\Ʀ|Œ˜¡zB/Û¶­_Ø>a²æZÀv×13Ùë¬k„'=¼2Œ:Ü¢A?Ö. ;a�wŠ`¬"VP„Ê—óø —{ØÆ4&Þo]8U•î°Á iê±\äâ"éç ¢‹ÜðTÿC¶LÚ–‡ÒË=’»9^šâÌx}˜}½œMwMzuÿv¦Ó�Y/ŸÊî% 3&N\ÍÉ ÆáÇéÇ Êׯ%/K}(1s�L;âŸÍ£ƒð¥ß=¶£ÕÛþÝøi»– /¨%Ò-Ç(&d8¤»Ú�ÛšÙµRãÖšòÚ£U­‹I®IL«›žæž†XõÉT¥8—k3ƒFYâœPÑ-1š� “ж Õâf@ןhZ1ßŪRiÊc'ÈŠŽdþYièùc��PFÜóÔ"“;„¢� h­ã:ª¨»›¶e�J~Ø®9OZšàø!Gèq‘ÝrW8[=¥YÃ"èüà_œkíN~ßb˜Ì}ü2k2›ü§‡ÏK~ɱ9ÄÎn<ÄFþ™HË6ÉSÂÆ©Lj_=ðò0¼#H#M�±ðF' ~ŸEÅ‘^˜é-œ×,Ÿ«aPÚ;eui½âG¾äãDT (Cþƒ?Õ{&:Eo€wò+èâ‚çøMÑœσ“Ç1]ÅļŽbÐÐG®di8ûÕ¢BªJ-t;üwZå!7ù�5m0$3×ðFT@ùJ ôµQ‚ÖLMcÖöAš]yÖ$1u÷nÎýÍadw„Ž=’Q¹´ u`°ÿø×ÕõøÝýûqD–Û¿lm�iÅÉL'U]V7éFŒ– Ì¢>¾h;Š”CÛ�Whü¼úµ%¡LC‰²“0 o>}4Þçn³“ðsÅjV¤ªEë"�pÆgÂÉÑ)Ž!»j¸•köÒ�Á[œ­ŠtÕ„·ãY>Ÿ,Ò€²_'ò//«œ�ô|(÷šºàí rh¶Z…)}H€Žžûì÷­=¬"Tž‰Á4š}uαÇì?šõwò™¥WQîÜ7LÜûUêOsù« 1â§>Œ}¹“ÆŽûÎæº.¡ÛOÿù�,x­wdGÆ’ÉÃ+Åd*´d¶;|'S›JjKVRGÕ;îi¨Å:GñEÊÙ,áÛ(�ÔÇ!ôtõÂ×nè÷{óÙpœ&êcgfÅSå¨5pÙkñr¥°¤=Çl2%v®®�ÌÁÃUì¥iåA]Ô�xa!M~*E·, eögYúô›²êÆçq¿—ª’íž0�ô‚*ùC¤ð± ñe‚€â-˜0:„\Ö̓vÏvVÝЊ·R�ÅtÚÃQ97¦;?ˆÛ^/d{³ tÏæs4‹GŒ£o?ËÁ¦É>w$»Ú=„Æa^sŸ‹X˜‹ž0Ia4ùǹ~ðãn9�¼;‡ŠÂíYWF0{ž`Gök�ÀüÉ«èÉ…rîíÝIô:WŸ.¥s-˜Ñ\_°7ë]Oç�ÆàÀˆ#Ðû~ ø;¥1å±§!}A.éu€CÅñT#} 5#0üÕ$v°A¾t8�ìþB�x Í·Í`Uò.üR.Fç/Ųg묠2Ò‹¢D¡fø=ò_l„'—}ÄË øÁ(í#oãÝМ)´‡¤àw˜òªŠm±�¦Ù*ðÌ> —¦Qµr—ª¥Y×9Mú:1˜½{gGZl#eû²ø]¿Qû×j½uŒÝ], ÃÓ1ú„L9šû’ú™Ïf}Ø·_·ZO…Oã…š?ŠÙ‹Žm¤*¨ò7ÆÐZ[ß- Áªp<݉>…î.Ê�þ8b¥#S(ÂÑž¿9‡¼öAýÇvt­d{ƒÞ0£Wû�:“)ìë>ñó&ú~…Ó^–IófÐÕÿ±Obo8�ÀÎ4}:m<°�Ôì[Ñð}7oÿI…3™WŽE‡Øð¸+pî^(™èÉaÅœ~s¦“×£kNs)-o8h¨ÉÅ~Á¬ l–΂@ûS3˜ÕDrë ²v׿VÃɼÛ�¥ŒáÔ‡ÅÀ˜'½/L'ùi>¼Óò4X×! &ŽXéÊbô£Qå�WG¬ÄËŠG˜_kªS`§²)¬ë}ÁãC™ÇŸíü²Wðƒ±;zBk•wówŠ’qÖÈ1°´æ8¦6\8ö­¦¶l„W=IP§ã rßÃqÅœ>tþ>™L£²ÙßÖ%P¨Co$Ä ä|%Ó|.nmq¸–�^ÛÌa¾ùKNÿp9›8f).��¶YГ: Dvæa‰r~£üÃï<›c·D‘åàEPÊ¡å^´¤t?ýõiäS�¦Á]¡"S³­Ç�-ÃÀù‚'¸‚tïL§Éö— ³\‹Wu}Er½²M‡NÎa�Ö0mÑ~Ê[¦í_ÙÚm‡`¹¥ ç3&%crØþÿÌØ¬·iRR\î0€;îþP#ÿWؼì2&ºœÄU÷~±1=á˜xÒ€¼îxªKÐðªn|ù#“†Š\¡ZaI¶*Òª'aU½*Lu*b¥émz,õµçb»ÃàŒ0€í Ú#× '[Ã,*[8 ˆ5É7Œe¯ 'ÅÐHºa[ï—áN“ýÔý±—ZÖC�=ƒ£ZãXßËî¡>hoÅ·U ̪ÏGxf×u*�µJ¤‘u_ÅÇ›€æ½Ñð%d�¯‰ÚÂú–Ȃҩ'ø0§R0‘š®˜À+y0 ©ç}¦À„üù‡åØíux·\Q�sØ‚êǬj¤^°‚þ;…4(k �CÎô~¼.õšÇS†v&_ñ9�Ξע¡?‡ÙÀÞ"z8Ÿ–ÞÛË}›HºAœÆî§ÄWÁlÌÚ7|m§½;ø e¿í` ¶Wñ›¶u¨³É[ÛHrèS_z îìúÈ6ö90U£/¬ãT0S;%Ž?k’@B#e{*‚„‡Û_R²Váy_¬Ø’µ,x"ðÌôe;ôláݽã´ë{#35“¤ÙR¾Ì­|!»Ì›M“Û_öô±Ëj|$DÁŠy±Öx�)•p'Vж¸×ÐöLˆ f o„xxš!èû:CÞ½µhfk…¾ïXÓ¥:xPfMZ³ˆUËõ°OS�PÝFk.E¨KÂ'tÿã¶zæW�çǰ£³(+Óš98m¥^Z@GnÚ ŠóIªø Ìܧ‹s§‹E ûLhiéÓk_ÒäGÀ€F.–K�Ja om—.bØêðÙUï]ö‡Íä¡8TœaÃ#r ßÿbu’DëUèäž6�ï‚ÏüüÔ²P¶ ª–C¤='ŸÙMÛšó�nž�Ÿ:öÓ�ÊçlšA3l!óY|›¬ÝšŸØ™¶6lnGÇÖtè…>åÌ�BÚ]Ö`¹ï©Tí§YŠ Ì&cIY6GÖ�f•Sä.5Hvöᬧ¿Áá-¡õ—… $¡ÜÏ »Rbð÷nUÊ;ò�ÖµÉÒ¬Uz¤áû½™K­ õ\ËÔ÷�bwjQeã|”îÍ@q¥>v·GMxòf/8�žKIÆÁl’ézJ¿z˜¸Žõ¨Ú`A‡àÀŽ,ŒŽÓÈÿîNe2«ù‘ÃNHäá‹¯Æ ÒYî–FØ¡;‚EʵÂÎ5RØ[õ› °‚²5opò›ÖùNp¼vdÍr·rqƒ–)=Ú×ÌôClIT*Žæ¾äi|é,ÝÚ!˜Ü[L{e��÷¢Ý8sѶBã"ŠÛéó=?¾ÀXy Ú¤@ÅÍ”Ó/�ÝÇÀAö:z·Ï‚zŸnîkÔ{<¹î6ÿŸÃ|;›Á¥‡;™"o Fÿ毑 ùÎzõž+ýÍMÑná�\Œ*AµÆGت!?¯,ãV¬è`ÏV¿Àq›y¨œžŒãœÂL)€‘FkQ2î/,óÐ@CF¨ØoBEA:x±ô!ØØ(òœÉ-ªÅÊ¿×Àÿ±´ôî[4ùþÍ»Æ�Jú6 œðžßjž‹Z¸Í5>¼Aòz÷k 8½_Ä {ú�_ìBƒÖ{è÷äd(Ï·¡go^ É„î\Å„G›Øˆ�`y–…«`Ôß“à�˜ƒ2…e\ðÍ+BAX5Í Ñ„8ùh¾A)Ž“”­7ßmt^{Î_˜xŒ]ïᮤtk�yÝ Ú;l{ã[ÅÙ «&`ÓG™QKûxXÅ—@]¹8x¶:ÃpÑïü7åãØa8‹œìÍ öÆE\5ß•Ü^H’Øþ¿Bv¬€I¥]e¼f¾—_àè/ ÙÄ�y¯ÊÉ´$NœoÁÄK9ôûŽ=”*æRžN,Ž­Ë´çpPm©–& Ä@Øf5@~üPz g­èA e×…3Çš0v·m…�Eô*; §Ö˜Àã“9ìÜÄÿ;Õü§Sƨ$ì^ UYu¥(^þ, ËSV“¹T8Å?Ó¥f—3Ì$¤öÌ×äÌõᑨx8kÉŽb”œA£þC¯ˆ¹R‹!¶ñœ i}–X岑[ é©ô¶%ô-ßkNÙC©´wúX)+íäÒ/ÀHù˜-éAe9e˜·ÔZðЭ†U¯Ü š7ÂÌó_ñÁZœÕ Of%‚©šHøvð×Ëv1%ÙY¤´ð$\ØßŠÚOÖÂä¢=44PËÞ¿ö'QÍÜÙu�9ˆì!oa�Ðâ` ùFÐ/à P²õÀ¤>¶ýÅuÞfÙ°ðŽb;bwÐ㿘z£?W¨õw½µ…1¯ÓÉaÿOìz÷„MÓ-„º@EÐ�Hßž”clÀ0E Œs¸B£¿è†ëiTx¦F©˜z~õ¿¸²%¤öz1Œ#�”ú6)ŠÜãµhÝÊr9ˆÂå‡éI×TrŽJæµ–fã·‚jÖô^’-°rc‡ã¤èÉõCXy}K«Od7ã£Ù§¹™X=q›¾jC}~�^âÉ?LbjóÅ@<Ý�)L(e>µ©ìFÌ ÌžšÉ�hý�X*¬{áŒ}=˜Šœ]M eWkð³¯%ƒíÎß,uÞ3¼©1ìœcÎÒ |—b/ȰÏNÍ\Ní{¯ÐäC¯YM�6yÕ³i"ì�±€ª¯­¤œÍ—èøÜµ ®FQYWYµÃ 8ÿÖŒrö2ÓõVÔ¯æÃ/žÔ. Ý»ôJ§ ¾è‹Â�Ñž a�F‚cè«ú{Vy—æO}†kOçAíÙÉôpX:$›ßd 5U¨C-e&³«s1Î’±ëL.å¿,Ô4Z7§’õ×2ÞÙë;�82æ‡Ó¡¡0"'L^ùñ?ý^bÁÔ&šœÕMª‡‘½ÿ�#V¤òº!F WŦ¿÷‡*ƒV:2œÞNߥ0çâã0ðà.ì¾É»`]Y$´[«RÔ½ñMíò”¥|Š.í,í7CñyÃQ/©‡í· ´2ñ %Ë ÚlVßòM`³òf± ;½™|íž“´Uc9UýY„’y´ÞSü¤_³÷gð¹ó&Îå™8%oªÁ¬ç<¯rȘ^+´Ð¡èó4é‰9OPf7wD‘´ŠL}�@¶Ê¥ìðx޶‡�£/xõu,ݺ7Žê•? Û4ó!ntU�çãv?$¡¦m+ßHOUO1m9?~Á¬.~KˆuFÞ`íG’©5!‰¦éf³4½x˜9m^Ô WK:Y[Útí^Fƒ‹ãƒ:76ÅkIŒq¢Š-‹Q¾9<ÏÚBÇJ@—@~—+‰�õ’Ö‚å�ú˜¶h=ŽX}�ïUù•¯]B¯k³ª£?˜Uõ"¼óׇνŒ!W×K0?Gš4'MCÏ"9‚„f.¥yÇ,¨Ìh8>Ь„]ÏKØ@Š9þPyG'¹8nÑ­!æšwš$o5PaZ«¹–Ç©&ì ÌÞ6š(%ÄËÿ8ö¬hÉ¿ü,ˆô º¦ò’‰-Ã=äs#“½–Mgí#Ñãã&ñà0¬7)Å¿F§AÛNôçžo(gó­'aþuþЈbýA¶^Œ†Õò£ér£LÙ‰¹õ8âz´�!KªáÇÛRTR– V —QìðêÕtgìÀ4V85,ü(vð­`Šé<ôt-$Ïý¸]ÂÇXâe ;“?Ò�m5¶o§êõž”ùõ_ا�¦—³Hùª29—-½¬P>ä¨(«É}ÈK–Ÿ{w¸S�oâÏÆ *x»ó6&SÌcò½^ˆWcb©@ €òþiPbž„7b·’ÿŽÅðÐ6„mY–M&&Áäþ¾˜nµ(QûDÎdK~2ZŒîÒw°±¤šµiåÀ–¸îÒL®ýŸë7®’dÕéŽØ’|‡Ï8L ê*°<ˆa_J2É•¨Ó®Ü£äý=•E#°ÿ@HMÜ § ¼(aÍLàæ<¡ï Ç™ä¡Ý 7s?ó™¥Á,ö®¦ ™kÉÈßžŽ¦èˆõ´}J[ôî3†<’fôx,9¥ÜÀ³‰ƒœUXLÝ;Šv,Ä�Þ7PÞ¾Á�ØÕ¦sLÒe&4åÝf Cζ‚ëïªz¿ÿäØ\qs®úÛL^j· Yc>þ™ÌÁKoz Çž^MÒײ˛Ìè'Œd²-K©ýßÜvøÍýÇäó1cb%…»?Äâí~èÄ,¹I¾UäzåüHLb«V`«ž^†·]ÛqØ› ¼X�•¯vAÞúë¬w’�šø˜=Ìñâ¸Ac–15ýÅ/VÕ¨p릠0Z vFå¾>c½sÈ!t¸gì†q�…×ú%àCå,ü¨”Žý‰Sõ'pµ›×pûËpºr(µÛIÑ,«r<�ªJ]�³ áãYÊêGüûº¤sú+fkáð–WLyÍdø6<·>£}ƒþùî%Á¶ä î¡p?mŽ„#Éìí«Œ^>�=k‹„ˆU XÄ5Æ?¯æqea .©1âEÆÒìš=¸f×X5ä�ÎcàÌ”\pÞƒ±¦Gñ»ÌTàràÒ‘p>tÿ_Ü׳vðÇ©áo�š=Ž„vÚßäÁNX:±ÕöoXPßtÐZ›–_¾r¹N.ÿr¼�{¾iõÞS‚s#Ëé�F.~Y ï½ø�«êqÿ….þh´}Ù9@Z©ðŸR¹.¼À†ù·ÒÎ�’ln’qýA…4Èû°H`ï;‹î… é¸Iýb[mݦGQ¥Úäß¿ž}êÛÏÚç*ð·ïíÅŽ0Yâ¥:ðûé^ª‰õãÖ(&@÷ÈŒ_Æ�Y/GÏ×^ciÉVpðZ>*Ç_o™Á^^/gê›Éü¡œ€E©’øb#:`yO�³sð¿ô�¹%£v€Rn(iG0Ùû†ä'_ R·Œ!ëó',bBùM\gù¾ëÀÐRò‡mzóé|ý(Ó~Æô:ïòr#ÃX@ßVj²˜RoÌ¥ºpòÊ&·%TÖ!?Òt0—‹³{ó7E3ØSa,ö‹(‚•c F«­bGÃò?£ÁA«‡^·ÉBÄ`/óÒÂçU�8þ÷Њpa¿†ePøö?x~¡7ÍQÏãUÚ/‚AG=püÈŽ=ô#Zf:¥ tNÇìŸ+&+š3°ƒ¾­×çÔÆG‘æu-v¡¾ ÿ3=䤯0+!âÎRHüLEF5I~l€6ÉÉPÛcÀ´�OPl»+w¢GaªðÐÇ ¾îÝHMÖ±´ií þ‡�ÌÝC—n…�œÑ76²ž±e3}¨jµ"í±Ë öè +Ž9Žëm| nG2«Æ�ð¿0¬<^A.~Šä¾}4<¿•ÈÖÜEïÞÍeƒeǘc°8�Ì�zqgÚóF‘&Í‹€‰k¨þD¢Gà’:Ô~ŽÇ�eÖ¬1ü1Æ«‘»Ž†•¯æz¨ù—›Ð‚Nî÷¡M {8�Yô…€f¾| 3¦n'50HûÂþ0zË&Ã4—Xý“Ö†�lŠxê ':–Ѱ$QdGå鱺—§a‡)� x5+‰¿•\Šš¦ZôÍë.[V%B†I ggC»Ø*f�ij+Å7¹ðs·­VÉ ¢Êˆ°FÏV ’N’‚Þ…óii^6~4£¿“ÃÐë´­2_Jzõ°hS wcÃhù�ˆõ£G¡þx Ø?’·>Ô‰|R…éÂÛàÒ¹¥7ê€åþ"ðœ×�'vGó­+ØY‰õ•²Õ·¸Œ¦4ö3K†�IÀçµl«ênðnÇ W5á}í%f5×<&Ôbû…Zv)$]>òLÇÛ•zWrä�Gçb›Ù'Í{tPúë9#K›ú ëv9[÷¤��ȘCå»·°¥¾“ì’ñJó$¾gB9LÄÑ:˜)¡Äß—(øÊ­¤ÏÚï†ÖŬòÌ6úxqÍù¶ ìowsrãàå�X.tæ4°ˆ#ý »lãÜŬÌì jY6 *_ùÁ�ÃaPöИgº‚âœv«ûݫɰ£�—œíMÓ-¥˜ñûP8¶þ"o0·˜ø… lª½:L48¦ªl…Ä^tT›¯Š²ñïƒR¶ó�©×àÝ<ø{r$<–€ÍeÞL³ì4Ý ˜Ã�å ¸óCY¬QY•æÛRÓ‘¦óÝßÁNþ°0éáx(r©Jö¿eO•ôÁkœ=ýžHIs‡S™KfÔ¯}bàâðÏ‹Åj@è*’醎/Ø•.†–y#ɹhý·­ãhÆÞ~±JÉ'Œ¥™^rä˜ú‚ÖÈë@Û³P(š(EM7rH8¥™F è}²øø¨‚�ã)8矃Ëq½ ÷�Jù0H‘•‚�ê¥8òó0Š�Ùƒ¢ûÒ(n#ÁðFòò¥?'ãPÁw=bé·Ëjjò0�~%Oü1å>Ý\Dû–FñúÒy´3’ð÷¤T”9™Ã"“,àBB¸6˜q×Û'‚^¼1JôÏ&©)þduC ÜÇ%@”ù lß&M« ^ó¯kÚñå›jˆÑ”‡¯ìfa)DIž€æš�\­q9Þ(ã“V‘ò;’ú:žO#›¡ƒ´$¼ ”G\ÃàúAÌžm«ZCáDõ¿N�¬¯¡w~M‡}Þ ˜™s€¯|ú}‹Å?™XûïY´„ì(g§ó…É™;pJþÔ°š�8„vgBùµºžØ}UÈÆ\âÅårAåï1JÞ«@ ò\˜ÙÚdX;ã(ÐZðôvà¶Â ô°<ÁFîÒ�ë])”m.IÏÖ1YCó•Ž1nçVÚÍŽ¤+K¡Ô‘°å~:|ÿšG ëv@…J tœ¬Ãf¡ô¹ß¾M:Ìg,ÛOÞgôYîÜïœ|Òdú°½úT�C†òk¦yÞ –•>ªýbG%~Óû¼"V÷"„Ê •iNa!�ÂÙÆØrz¶Ð”…hî¢åz¡¼ß×bxè4�¾õ»M�˜¦³–4=†¨”aÌä‡}s�…x!Ý$ûÖœ�‹JÁìü\8¡­"M0\¤žV2ˆ.·CÇ…á,=¿Ÿ”aœÂ<ÊVô¦øügÌËQ¾,?B¶F£áçç��8!-([G›/ç’£�Øš¡ZTw‡d‰½©|Ì-s³¾“;‹5aü�~®#E–dÒPÝß—}è.äœ[Š2Ž·Ù³kúh˜Â®Tž€ÆW£@©õ)³?‘C„* âpŽŸ*¯¸À®¹r0<ð¸À'-†ÎJE3ïJ?–d»™œÒêÈÍ, .5¤qó¬\ÀCæ'SŸé rÏî³G¶×èóÄm\§ÙÑYd¦-»øVìŽnáu-ÊHnÜ=NLS@�¿uósÛ¨S/ë[¨ç�n`™J<-‰;†¤<‰‡òð£nWá.ÞD½* �ò�™'ÈPÍe;RŠ9ŒJ!lîæupÀí÷úD-ƒü¡«I{JD豊3ìÓTâúÄÃ!xócVÒ,N ã§Ó3ý¿ìIE{xPJöÖ5M•ù¿3ƒÏ¾ Œ<3qï·&æmŸ ~ë�â•¶HfµàkÞ4mmdsM£�_ê0âÄ=`÷ES>šyÅÌG1ÏT~õ¢x¸XÂVôÆá]˜¼×£G²œUXI�;ó(abDû�³ó\jž`qƒu Ëpgp*M­m®ù?=£�myq¿ï¨ÆÓ—Uðö#Ú9ó N œHEJçÑÉЇŠ?z’mp 6Ôkƒ…é´8¦{}ƒí˜óVlE¨7ØŽ"®¥`­wé;@«ÜO`Μ�\oð Ô‡OǬ°þëeÊ$Æzªà©º¯´Ï‰¾5 øaOYU·:ôîr%eƒxÚdÑ‘�"(w"]v4 gVh@ðúŸLâÔ¬=9¯'í„öÊh|ûk·-u<ëT0àBÖ~¢võ‰°òe óf3)Æâi8|aã>²½W1ÿö#xxùF´ê­„ùŠ9Ù {‚YÕìcô“ÿFsŠ–À^¯}ÜŒøkÌÄà>í‘'s›v4´4‡ÇS³É- KÄð½R9ø(h m°LãŸ#ÈÞ?‡»•ó-‘œ ¹“§Æ)”~8‰™bÉÆÉ­gé.´|CÍ¿©ÄyÕ¸ù”ê89Ü€_üÖº™lØ &,ŒÅ€»[è·ïy(h‘DûÀ÷(2û$?ÛÏ’ÚóäéŽy6®È‡3»Î¡âÐ1Ø»ñ ¤›¶bÄÌh>(*ˆBt+QeÜtæÔp“µW@-™NöP|5ÜÔÜݨI}#Ÿà½Á0£w�Ov„£;þC»Ï@3¡%¦)p>…iðçg6ÌÖ¼Õ®"$Ap«­, :WÌ»ŽÀ¬3²p‡/ÁÁÎipz·3¾­èÇÄÜ|f:äÂÿ\÷™]Ÿ–Š�œÿ£ª�Ú¬fývtïqˆL²ñ‘,jöÜØ( "D(cÌ ´š‡»>,QÛ:4‰)ÅýÓßó»W¸‚÷\ø%Í�ZwÙ0®Õî–�bkœiDÀ+Ôv�¥JS™@R•Òeö‚Žð&^d;¬Ï³ÿŠ.1Ë5ø´f€iJÁð°,ŽËhã— bx>+�©‹O¦[ѺȣØR²—½³z•Ê÷Âþñ?éà];UöÀÎG{iЧ|¦FÚÁ•°Ì/Š.4}b¢ëXÍ Ôªôi”�žÎßv™a3{°$,³ÊO²½ïY…„4ÉßÀ_¥Á`T ÔoK"Þ% ã­Hj Ó`‰çtšeÐĶ­Ë'Ç5õ"ÏcPLž£Šë{pØÎmÔb^޹%ÑLnU ¬³3#ù{ëa܉Y””¥ F�FÓ¨²Xfa[�Ê—²êÌolmáB’_±‡R¬|i¥¯¼^m¸Œ¢º!¬ÚÌ®¤±[Ÿp{Wž`¡eå0\çL*N‡ùðÏF�?=ÅbMèÑÐ1¦m7ÒŽv3¿YŠ^œ‹í›^4®j–DÓš.Æé³í:è—^'+UL£• OØÏ�|nñÔõ˜5æ,«:Ï&Wl@“M`2y1,Î4#Ëõ÷LޝÇí?Ï­> Jz™ëß¹tÄý澞E{Ub¥ù(’–�¢¤1p¶²å·Û�™�(m_ÕÏ„$!(ð"<¼‘ϯ}nK§Œk…®ªÀU›Y\e_ýjh%�+¾bSÉG8u}ôÇ?[Õ)}œ1-òõuåiOš»½û·~†E^æÔZb 5`+jI]fg#¸O’&Tö-œý¾-ÂD[kðD@'wâ¦ý6Ò¤±^+q¬¯"ÿ ô%F]›O;dÏ1Z¯µŸ5iøùfJ89ŸHª�ó:pŠ<ĺîÐR´ˆ)÷ßÄ’¦ ¦7ôåp‹Õ_NÅ»šY‹�L­‡Û"Žå*Ú°"è&¼üPÇ~ÕN¦G³ÿc;{MÐëöi¨ê?@m¿ iƈí]›ÉM‚~ö#u*$;ÀŽ5Õ¬î\,Í�ABj*ðuI'Šh‡1ÑÉ¢µ—ðòüˆÆþÛÖôÀR‡*ÝÌ¡£CŒjÇV°/;ÇÑ—ÿ62£÷~Pã''çËãäÌ£\™þj}­¯ÒCØ¡ª•çÕË »¦±°h âbÜHàì ÜìI±›n!+’#£ÔkìË•sa?*½/Œ' ^7Ÿv-õ·üg¥죋,¨dX¼_VÊZ±—f;ÉUq"þYý‡ÞùÒ¶óòÀ͉©§^ð3??|ëf‹Wš°qTàÜÄÂÆ?e†Ž7ùMcÌ K˶ú8 Ìgt*zƒ—¼#ñUéM0)ØÎn�õd"töÇtJ³=‚8w&JÌ~…nþ×y‘þ=È9K°äþHvjg6 ×ÅsK­“ â =½{´ÔGó—d­ ïƒ+ðï·‚—X4YÈZ6�+Ä€õ `Ù0 ž|žÉëÍÈáCŠZ”ðký¨«lD¥–(Zw�·Öž ÷ƒÅðŒô ¸j¨Ãd¢m kŒ6÷:O�êC'ÑÆ�ó±Êr=YàAÏÓÙG\[�2¶×Ï¢S/Ò™ß#¶EGŽ­ýÀ"Ž+ƒñÈÚÅœM´9í.ºílfñ?ØÚ Ò,7O›rnm€)û¦¢Ò„ túÅrÜ æYGb©À÷æÈ‡À°ýbÊ7§£ýÛø|ÃJ4�9B7Öò�‡Tøð�ޤ‘MßR—ãåö þ‡‡nQ0§�Ù°§_Úb‰k ç–Sj1K/]N M‹~Þ]Å�æ]yÂEþ¡Ùr#zgõÍÕáÅBäáýßÚà‘‹%=›4�Ÿ/Ùƒ²¿¦Ðê#�9Ÿ%ËÙ1EGíù1:T[@‚ïn6>�¡=ËŸòwmÎâø0oTÓM²Bc›ÞO»€J.¡ee8Îó\ˆjÉ™$£x WDzF³zN3”Ûã_ãUS%ú})®¾‡uz¢ÞÜ÷le¯x·–è0²7¸Ï|ùÂøë�´ô§1Þù¢H®¯’ Éï©Àf®þŽÍŠÎ¤æ:ÀÖ‰7¢IÇsnÚ±núºw* 8î£�»˜Cæaþû§X6Ü­L¹ÓË)áÂÞFöõ'î-ð…¢¦L˜KÏñêÎYô}‚?µ>]ƒ “ZQ7¨Ãö�Ë4‡ÝÍ4©#‚ÂgGã’Ñݨõû»»)‹²’8ÛÞ<’È�d:!ÎÌíx)©·Õð×;›pèÉ.õW;é�ôÜCÁdÑኟgÁ�íÙ�›&¸Œ½Û§)aÕ%”ªŒ¡©�UøÙS<ÉÄ]‚k+�Õ²ëpÅÅ"¦Ú¾�ö…ÝgÁ_ÏЬï¸Ì)VðçGŽû™)q÷I>[�KYƒƒôu‰IÄi:·m&Î�+T�º�WøÀÓ›iªzÖ‰Þ#ì;¦V¤i«–--ÂÅ5-ËÕ°õ[8ui*òkç Ð3é@´’KMãh¢L6”©²«G¾·�¨vU vw¦1}¡3øôØ.6¸¶‹–'R€à$H6™&~ÝcÚ÷Ážÿ´Fc5äkýbZª«ÉÔ£ ÏmÜÉ”rï0usWÒóõÀMNB–ÕwuØ.c{³ž¾_Ū×XÑ’¶L‹š”mÐoÑÁJQÁÖ•Ÿ8I—%1�;Ãyf}bR^Ñ0WG†ÿåqãÍsø’$›ª>ÿ—)Í½Çøˆn:2öÊ>„E�òø=êHGBõy·¹Ãœ"µ ªC�@$̲þÄÜo áÝž” …ͺ'IåÜG¬�ùôzNÂX˜dOá$§®fïy´wÛç‹�Ó Gyر_žúÞgeYm4wÊ=üÐú‹4Ï¢¨P‰‡T Éɾ{¡*hÝ âŠ�yç Œ¼‡ Óÿ°gUƒìr»1þËÏáüjeqÚ*)š°ß�ýÚà�úá�ã‹RÑlR ŒílŒ»�Ѫ`—£ ³FƒÌúٴ콄¾8HâË pû—ÃpZø"7y’=¨îÒ¢.ŸH”ßgMŸB.r·+G5] ´bã×>`ßbFâtö>S bó.³<%7œû©L2çB³­ ¨|¿ÄI+|…A*r?‘Â‹à˜˜$—jƒêóu¸øôY‹³Rù»,޹ç×0ù7ðöØJnºè L8 G2_ÎÏ_a«E*˜å£4nkÖ3…qV>dM÷ŽLÀûC©æ‚6E¬Ñ¦ÕÉQ8G�Y Ó~Iª|±�m7 ‡Ö49 ·ZSâÿ±¥.2é}òxaë ha7+žòþ .ám§���žÁ]œ(«',ƒƒ“K©åk-UÚæŒü‹þ»#³É5ƒ�è$ÁÚ$\t7•*?†BÉûnš0”FÎç`¯ƒ.QŠ:T/XÊNþ¦}Ï£1êº,hK_ÄDàFŠ=žïýÍä#™¥ó]rZ/DŠÆtøûBy‹Ð¼5‡Þi8Ȳ(7¡£¢á”Ý%63OKAŠJG³yR«aÁo=ý^ˆÛÎË6½o}ÈuéÂ7k¬«J&Û£Y¸¿s«:ÇÝ¿RÅYÕ]ds.HãQŸs8EN’^;»“�J&³­Î€Ã‰¡ùG˂njäyWÐ߈“L¿ó-+¸üº nÏXè;÷ðãþ–íwÞ°Øš¾É•Qäë™pöû"r[õ‰76íg¶?£©£ªŽtomâ×ß²‚-rÁ�}�P:55»—²øG=¤hžÿ&¹AÃÏ/˜&ÉðM…!´®]Ê´úq¿<©Äó-W5àÍI·ø³Wû• ùÙOv÷T;ÎS­eÚ>r‚.£ uRÀ«SŠÈþ:;˜ÿ�~µEáU™GLüè0Y¾“s”hNJ.IÖ%ëõ×¹¾L+x·6“7̧Ü) ¬êFZãM%»\XneŒ-Oô)ë?mhNø;âïÛðá…Xœz€÷ñôf{7sú\…Ú®òñ‘Aì´©(�:u¦Ôߦ¶p’žÑAuwJuqÄõ£…Aww|ã–-’ðòÞ Ô¶ÎÂùß’iÊùzØÕ›È´�‡éª•(�–lÂÞ+wÍßÅÐÍ ;›u›e ´"*$ÐIbÆÆ1äµq)ÕŒpàû‚[œŒl.}Œmã‡,BrkYó®xØ­9†4tˆ_jÄŸ4÷�ó—E-ç§–3Û)~tìÞsº¡WÏüFÏ]ývÖé>�ŠMR¹¾y’4]~ùY›ÁqGŠ\ù…ÝlbÙ­å”T+رÊÃ^ y>B8Š5ÏZÃn¼“¤ä²CP¹õ /<=€7µrN»ÖÒúÍÙ°Ëé;y¦�²¼®…�¹ñLìÖQ+y´ôc$ Ndú¤‘æh?B— ñT¹ð%\ß7‰Û>ó/ž÷M‡{ú°é]ûqb1sšS�›ÇŠÂÛpeÊ÷ÚH0o×.>YìS „[3M­¦YÖîÜ�W®œ†wM™hÜmJv_²IoÙæôq ôl„øˆ4R}|…$&ÔÉ]˜]Á.¹©Ñ^éÓ´s‚»«'Òd.>š¢•nàîp`­¹ßÊáãœøý[dõ ­BÂ/ÿÛˆ!Û¯PÐã4f?Âþ«Ï¯ƒþ?•è­ó–�þ7†þ­�O‡“�›‚¡ã ú¤ßn¿ŠjþúPšx<®™ÊIüC7 �ŸÍYÌ©/!ÿ}ÏÀWè&]<õ�:�…o×ëáÐó©`½íoCŠ·"¼ �w©�ÿneB“úuN¸â!7¦C‘^…ÔqíT(@K” T¥�Æüp‹çË—‘4¯ Gu­à¨7±ìXcа�ýv 9)Ÿ¦š¿a&fF0ñôQsÏeu /oy×: «7Ö÷ÿÀ##jìH¢Irв·‘~|?�ŽqïYä�Lìz5“uÊ(tÊRKf$Õ%L£üPQº"\M'ÞÖÐZõNó¼X°ø³|6²ÆãÓÙ¢ mø@l#Gs*}–]µú™‡D(õ ¿¦_±�ÑÕ,wØüd¦�”hÏ>GZ>Mß·ÆRÕƒ>Ò¸ ¾ië�MˆŽþß“ÀÃð×’ÛLº[Ðr¹l0Ê?Ï™ïV€E…â\à ><É{ØPôîE¾£4}iwq#̈¦@Û¦aˆß|éÜë0na:“� £x�ºýaç¹ˆä¦ŒÂæ—pK¤(պΧ óÄhÈõ÷Ãg¶h8 ^zfÉ3�a×û>Eå:½éW¦@ù) 30Äõ|¬Dô«¨zr©5gãgޢ߉Dí¹d’“D-¨õÀA˜a‘…/ z©x˜ oÅû°¶°óâd¶QþÕ¤³ÂõãÕÿ¢Ñ‘Ϭ×"Œ�ÜÁß=DWo”ÓŸ9þPöE|W¡¤7têŸ9øDRÉ¢( «-£ìˆš¬^ÊN6. Í†–40O8ÅUdgøƒ»óç gû¸ž,zdá•B‚Û³)V®ý¿ 2ŸtþÚ¬1l´Ÿ#Syó#nL£ÕŸ“AZ‡ƒx�Ì9ñ‹-SŽ€Áª-Ó; cÏ#æÇ}eªeŸÁð¸}ÔhÔ§óq¬Ž2sº“ÈŠŸ™³™Ó#©½(JJ\èÁÇ_�:×÷|3 ö£Ý°ÿ«6�›ÝÉ�|ý”­‘0ço äA�!ÿ¾v„” ‡†wÌ®kfJŸ#÷-ƒìqR"/žå-YWÈ}» =—Ï'çòé´Îï=ú,‡ÊÞóxÙ1ëFüþ …LRçÏêëÒ­Ü•¾b|¾ü[šø�Nò�é;Èÿh/ý8ZÅ,Vè‘r…&¿NW¬­‹YFÏ»" yo'3ФGœ%ò»®ó[žn¨ò{OûšSÀ{Úk~ïžrì`¹àbxwOŒ2”Ih¤bÙ«³°ÅÅ Zw¸ÁìG¶eè¨6-dk-eöWO@@ÿtöç�]äIeQ&p!UŽx5¹˜lFÓÓØ\ÃL¶ï�RH'lçòIbªÛ�nOÉ·ø·MÐw�)Hš5ѳiÓXAñ覱Ó\PHK¢™<„lþŠ®C �[ªóa·ø^p½<âÎñwáó-)êU=Êv¤ðŠC©ŸÒ·Ð¤z[þ·ÍO˜®5 Fkp,uãYŠêšÄrþM"Á°SLøb6$'ô1nÖD:Ô&Iõ½GQ6ÞƒýË"÷ái¼u€#Ð¥©MÏ#ã˜÷ \&ÿv¥'лIsÈ&·{îY€]b6 žË"ÍFì{+‘0bccélj%ðH{¦¥Šw¬.ÜŒ§¢<ØÄËåèÖ¹¢žA‘ÜM4ÎVšÜBÖ²›Ÿòa›žêÛ+ÃRá±ô�RéÚÙ°0g4�ÿöxH÷Ÿ¡^ß ~¾¿7u¢kvQK@"$\{Lv^tÖS[çRÆ+eJ´S w×tØtL‰ÿ^C‰.´~Š(¸Dë Rئ]™¸]Lœw‡‡A‰Åí…£Óªp¼wĺ¿gB}gé¾¥»NÅ?PCùÑ–”%E^ºãšÞuì�lÁÕ”7~,eôl$·«†t2Ù–nŸ{‰�Ù èøû„‚]™92Oÿဲ ÌÑ\À^ Ü€ j­$;µ?ìkàn{Ùãë*L¨(–ùüK»>6âÃe˜à;†Í<¾’¤Ž *{D°Þ3± «r”oæZ1P ‹û1æ .xäÌÔýK¸Ž|ú½a™ïš‹'çÃëëÌò�7mž%ÐÔ|ß�^+÷1ß“tÖÈ“”8 Ö{9ž³ˆC·–Á3%w²•îa O°%ß{paùøkÜGËÌÜQç¥[zð{¼¥>�+yvŸ3wèõbUKoɰLªÉr¦¢!¾x†k&z2jÝŸ€w&nƒˆ§«©C�ƒ± ð%rYŽ~dž±�½Yy‚”¯öÀɦr2p†^ãQTe=‰B6Þ†ƒ�ÀüÔiNíÜZRü÷—=u»�Vñ-äpí/h† ѬbÚ¶R…—Ѻϋ— 6Ixùáÿûè¼xWçÜ;Ý{qUÙä~�…†á²þú|»4µlñìA èj“ÛÈ?°h« Hhå¡·ÝÈ9Ÿ 7Mr*ÆŸ^~ä¯kCFÇ®³¨þs$n`Kó¼Ç@Zä:ŒêÃ=ÇêØÆlÞ¦÷è/Ic¢ ‚s½Ëf¢3¨Ä¢Í%Þ2 [pØÝ’ÖÑ_�=œOy5n©+¢¸�ò†_Ûlpê— d.­‚ôs{¸¦}MغŠK1¿ÃŒ ÖÒÆ¦CL@I65'Süº\ÊU¬i`B®è\ÛJöŸ ‚=è½µÇbºF>Vñ£�w’�©5Òµ++ òp/&\²‹Fák/úדˆ×ƒ+IºZ�:Å;0¶^šß4ý3ºßϦ»£]`ÍÕÒ|,C{Š3ñÆÀ(ò¶ëe�Îýã~ÄÅ )/¾ºx*%Žïæ´'ÎÀ=æàVŽG]Åà{ƒ$ðG¥)½ò5÷«x1݇¾Ù6üÊÛ9½ÔB2ú ¿�êiÕ4}f9½‹­s¬7áݳ)ulê°-¨Üü̆®p ÓTÁgwÒÞ$z|0d~E¡æiCXb&ÜôÏLÞòDé«©ˆÃµ”\NÅæ­+ž +o¨²˜–tqè^�gäÃÈ\µ’?p± wáx8[¢@*ýGéÖÓ1MÓêËÙÁ¨ŸlOµ7nüãªÝY|ˆ_Eo½ wæì$w¥L’¿VËÎë‹°“³$Èêï,X²$…fFÉ‘u´âȺúý^ éùñ¬oŽ>Zï…"©Höñ©Y7áÎý EÅ ¿ä±¯I–ñŠÑÔ4ë7·¶­¹±6p1)¾,´(PÈÇ­†±Ï—,ö†Qߨd¨P‡»µÁGQî`#~žèŒÝa³Àã«wc•˜8Ø£hðCJ‘Ìaß4Š ¥Ð¦Š•cÖ]50SëaâK³¹= WiÓR¨Veº»WÁÊOH*×´áeU8�Ð £—[ ùþ­ÆþåÇèÔÌ¿”¼ÿú좒!Ù¦á±êtçÂ?öpL5Nx�L»¡Çbg@¥|š¹ LcÃq§þdȪþÍÌõ¶Ââ´0ªâ st-T,<c'®¢¡VUЮÁ ¡Þp'ôî —&Ù}ÏaØ1œßÙ“Mx&ÿ^ÿ¶ �G³¨ãŒFwãÓUÇX·Ÿ¾ôP¦òšvLS»M�‹T©ÕwoNiP‹ ¢±pá×x|¯¾€ ÿ¢g¯ÄÁR î‰m`‹AÎÆët<6ž|½rp‡¤&Ó÷´$ŽÔÄ�+”Á”à� &ÿ]݇¦,ô€º(;ðNc´Ô“ž«ç’dþIxg–«Î¤3LJ·C_ W¥\2^w �¾2¡#)ép%ø"ÿÇ(¤Fî¶ÎA‹nl¦N­Ù˜�C¥ú”ß)�³~LÅÙ›SXåga‰ÿÁ&[å’hLk{½�ÄC±CÞ™\5#¢Nl®~?âj¸Ð°¯1kª ùMJÀ×âM¸©ÖfŸ¬#ßý�°qû,*3ƒè•óyƒäjØ¥ªKÌw&ix«ÐR�Ñ .@ޤCI„ ØèÃi³c�³‰ç¥v1Åõ�7•my�˜6z< Ñbòån³[¥�÷­[ÿN=cµ=A4¦´ŠQ�Œ³þÃüÙŽ"“Ÿ1egcr=ªÕxSk68÷ºÐ䯇80”ÂÆŠÊÞ­’T¥íÍ lËdÃsDϰ'ÃHiìkÌ+²€˜u �6[š=u>¦ªCÝKqèx­H›eÞQO0ƒou2$ûå,Þ §÷ŒÀ'¡Ÿ¹”K²¹·#Ø�u’uÉ„úN¤¯sšÌ§Çóâ֒ಋÝÞiCj°fã4¨¯XƒûíUÙ*¹•0ÑN‘7­¯c9íë)çòeš“ƒ–¯G�ô‹PÐg�y+t-7Ž~Çþœ$õV"í4èИr¶êÞ{¾3v<+Iƒ°¸n^Á{!mÍJBã¼DzçlEKžn‚i»*0 !"îÚ’Hž=Yn9ÉÒ¤+A»1„ÔÕµ)UÄ™×}ÍžËÛ¡÷î7üƒÇhÊYA’–¯ÆÂMÓáà;arI£ô:P²� ï±í¼j÷[–øûK~v[ʳáiã/þ!D“�á�_?$¾ÚÝðœxX?”#O!)Sè¹ÆÍÆO­Höòt ØÂɧ`¾@#‹Û¨E{Ê:qrÍ\ã$lj±s(X8€ScÁoÌ8æóQ ÿ«(dVMw±íÖ š_O/ÓgÁîÙ-x7K"c¤Q4² ;6ÔXHî)ƒ+æ;hŽfºÈÈR¯É|ôšý“%ž.§::Â.O�A,l>, Žb­‹ÓXRšmÖ¦3§`sÝõ•¼‚^7NxaιùÌ#Gg:º×�·qžnèfÎæ/Lµ&̇óVÏYJ­&‰Û—‚L€ È,{Å ðñÜuOHZæNÍ»Ûq´l47cXg4;^¡€ãb™ß¢'ìOÒ|zòÔž^íe*³sàzÒi6^H Vý½‰;“öp}‘ϘÖÅ 6ß0‡�ŽšÀ-ȽÌÞÝs¡½ÖõìßÞpãîNŒ§ž?oÙâkµæ‰^hÐ}Õâõáü®cü n;H<¾†QÏyÏðÝT‚=óWJö±1b ”é#DæÓ.Àª¨_쟻T�+â®Ã'ì úDÂDZÞPž›‹åjO-µÌ�YÁœúbáv–)Ýß9>„½åÇÌÖdA¯ËTÖ*S¼I({úT ì:°÷ƒ¥l“WÍWÂ]_òù�óH©Z›†(ÑÉ'ûø uO`Ö l/ùZ!ª˜€§G<»M…d¢v¢® à « {ô*ƒ)\NâCÛã¢æ)Оó}g.ÀŸÂI²wi´%â`E8ü:šO>n‡__â×ÅÑ�á$ k_ »+4Ú[F�Ô¥ åïí4z¸‡O–£Bà+~ÒÅ{Tô°qE“ õrã膦-Ùo­f÷ç AÂÈÌê)‰�]ù”y㤽´ƒÅOCphìljžq’Y½ Gw‹·nc]!QF�}Y) r‚\Öš«´#yŒwa[¢¦ŠºR#Íæ|ü,ÊLåî35¥R~J½d4'Rë =,²?MåC‹0~�ló2‚¾ùJô¥Ï�"«éÕSs2[þ 7ù9в„¨ÿ$t«ß`·³!-¾|×^¨dn•óùY'¸å…&Ôº-ÆL� ƒÖä¼§�YXñ"ÿ¶@}y89 Ü�­¦SAWW?ZÇ‚ÑvÆg™w²Ã(L‰ :ìÕÛbp›C“±›ÍT¼@�ª¹}¢¤æ_ÁC]¡L²ŠÏSŠc65•øí^%VꢷÞ8šcZ‹okÅšVè‚H¥�©:%M6fÓnŸd%J‘”ßÓhqïJ+ºg²}ªªôÇM„’Nž`è”Ç Ç6M<¢ ä¢J÷ÖäStì_V¶?šGøÛéä)›…�Ý y]sO¤¹—P²�;mg@�õ&Ð¥!yÏdØS6ž"Æ 3´,FùgÛ°ê­?(—s‚ßbi·HŽÏ”‡ÃêѼÂÅôõ–)ÜÄXÊ5 .ºÔ²åPÂdO4¡’ïô¸f«LŰ`¶7|I¬‡ÓÍ“!`K®þ¾©×ò§6©AYp¬q‹DM sš1[‹Î¯/`Öž‡PV3�Ý4�b;7ùÐgÌã ~yPgó3Ürõ$ ? eë¸ÇÿáËŒëìÓ$Q–©¸—ýþ0Á¸3d¹’Q•‘8ö•ÙÙýut-1�ÕI�‚ÌQ# ˆZ°·Ð"—@†¤d:?E{CZ÷ óxÉ…ä¡b„:ìçnñå)rô"u#þZŸžØÇ{GÆÀÕöNV-:@[¬ÆÄbÿê_CK>˰ÁRaníæpéõUþàÕ½àfåF¾vïaÆ™p<ØÈüoÏ!¦¾Ê‚t”«™ÇbEŒ;·[ÇM‚ýïøîkÒ°l[j×P@\Ûqßc$K÷³Û\*p_ Á;1}úV±)F+ÑÅ7ž žG÷È\êp;ÀçÔðéã1·l+…·ogßsYÐ÷l–¨x‹d{Xy�*}‡U\˜î Û´ ·¬�Çü£“¡ÚäË>òŠ;mx�/zÆo’dêT‹êÄHsÈ�^¬’ÆóÅ›±àý8Îw¡"©eÅpÝ_wÑÑÊôtÏoj¤põ¬{´øj .Zð˜u½HĵýÅÌ@t ¥Õ…ƒšÓßÅPžÐºäñ�Ú/E #î3ïÞNÙº™æ¬µLr:€Æ{�÷õ™ü2 .E<”%éI‚³Íxˆ›{2r÷S‚®"�Ñ’¯-�O'&ãœc_Ø5 ]^H; kßq`#H·‰ÑÚj¦`´œ¥å"_xö ¿ðoPƒo§çq¤`œc6ž:y#5çÑ&½+hnšÎŠoÇs�ö\Ö¹tÉ3|Ó5éÀ.1\d£¯Ïd�ÊÏø÷Õ•ìNˆ>óÉXƒË¯ ƒÒj¼«x’'_äôBÊh´áLìù°M�è�¢ã^Ìp‡O‡×P_P¶òz´T~ï¤>Äã»+˜˜š-FOE+N!›"ƒÐkM Þµâ“'i’®T:û¦‡J{¶@¯©½(¸aQÑuŸÉŸ Ï6(2ÛL³ßÈâö÷AÚÞD >I’÷âØcýh_rwŸÑ ;䉯ó²¼|Öò)ŸëI$U™9$¨ÐÌ>=žÂüoç㳈èPócïZÚ_Œ’ ÏØ©ÙålaÔ6²R×#i·Z]†ýÃïÑû™#$qÄnÜ= :ZÆ7ë.†}°ååRד nF“uK@Ñãž©ÖÅ[Ë/2¦DÐé Ï<æëƒ}r+×£ìƒ;æ�Ǧ—àhrœO>ŽSŽCʃµlsö2Ð]rƒ»u+jf9PwŸ ?ës;÷ŸHIìÏ·hMzEëv 0Q Ì–6ƒØ¿kYŸI)¸f¿Å'‡.CäJVj¦H }©iò60—s8ÅÎ�ÏR…æÒ‹”¡Ìª÷zýK£xé‰ä&ðK Z™È�îÌ‘ù‘a³&ֱ쬻h2œì­ƒ—Õ‹)dÍ8Ø7û[æ�lÖ€ÌZ{‚åí;÷U(ûq °b#û˜žÿ„—"&PʦùÐ6M8Ul{M]6¯Øõ›í˜gjCÕZcˆ—&hœÑÉÎài|¹t Ö´ð¦A–ú-–ëmL{B3@Ïu"”^:¿^q¾1J~;6]…˜hSZ>'–ùO=‚ûÿ°¹’S�z{ø{2Aà.ÿÇ\ßÄ >{ ÇàŠ~îæ•6ñ›H¡¼T_Z¸9Ÿ�i{…ÖÖØ-ù(â’BXׇ$ÁÛÁ}/aföp&ÜpÁ™âPh§Ê’]' ðY:cÇê%²?�d[¿€Ðæ@(.ÿË$ Þ“€ë´¹ñ’30>ëË·æbönM<弑Lœå(jÂ~ÚÝpØÿp™T÷EbÑ9'’-­ƒë²õØÔn �+Kió„Ç,¦5R‚KhlíFœ/¼/\Ï‹·Y¢ös|øÞ‘üÆl‚—ÿtÁÏm�J,æíœâY²“FàìoÙ³¶¢r¬¸Î^<Π”°X*{ƒñ‹ (ô¡¸ž�„  |r¿vg9­Y`„ίUèï›XŒ—4“lÛß+㙑3;v è?6¯’ŸŽ¢»„ÉÖ¡“*³Š©Åö6rk¨ä‡iϳ�¤.á¦=eÐüãNmÒÒÐ'CR«jx)Åq¨ùÎ�¹— `‘%%MMêµoеï<‹’¨`?kp¶ƒø6D×E/Àˆf&z<7úù"øìíMXª¸5^ý±t:U†îÚçy¹´ƒh$´’Ã×=lÁš»xIð»õW”~UEá÷…ò4éõjšÙÚ‹ú‘.�ixÜ‚÷³ÒÀ\þ~b1M-ÌG›ÜÎgÂô¶â7]!B¢¶P�L,¿ùû6[.§¼ÍáaÌLLqŸ4lüÃm˜ü‡&WâèèµÔä©Ѧ{Y{Á+ª–QÇQ:–t±žôsS@CÙ™V뮄3Ó;ñ«ÜVˆ u£·¿>£ó1ÜeÄÑ­’ñtòz [eZÀN?N‡ä’Ö·ÝŠt|—±Êyœ2¼¶k\Ä«]””R Ù)°î×l*wYÏ-xxlÄBhpvî»ÐÇ�þy„îJº¡Šç0®¬8Ð0ØYC�'Ö�XR›}õ›´éûÖv˜ .—’yÄ"2̸Ìês¯ã�%�T¿V8ÁÉ0 ú´5�%xÃ|˖Δ„ò9®le97õåæf’ø-oMiÖŧü{›SÐ8{\2ñ¦ÚÎåiÖo Ð»Œöþ™�¹ ôµ};Ì—&iÍJØxí(K�£ ÞM#ùÖ5,ÏÛÐÕKðÙ)K­ á걑]u¾°Aûe#yø˜muYJ>3 ˜c‚(”¸óQ¯´QàÂН8†.Ñ6L÷L9SK�¥?y}ø®ªŠ?«rÞwSYJz ŶÿåBY8«2޳è»qÂüï²á#ØHŽc…aâãæ�=Œ;6�†tm�÷RÎý�”Sµ_óÆŸÃXsq9só�ÇÞV‘e®1˜§¥`wÓ$^z­Þ“ºÉLCžáá¯éÌ8GÛ7ÓÃÿ¸ØÐe`ÄfÒµí ™ã YøOf17ISv/°‡[ŽB$UÍv¹žyfжÿàß/ž -Ž‹auáÊʃ-‡Ø†‚`ºùp" N’¥b+轪ÎbÆ|Âr[ 67®Zœf)fÓÐÃa&œz “:ÑÔ–Üç8[hÔþÀ¦´‚W/a⥠ºé«_½g>KŸàïÅcØ­å¿xñ¾›ð=é@¸ˆx3¹ÙÝÜŠ‚™Ô¥þJLœÌä�7ŒäGÍ † éC8{î2*™ä /Ҧý9×°0Î %m¼°àO$ùØ%�ÿÚf8¾Mƒ>DZÿ“Zñ•]¾šÄξ\NA…"pÿî|à%·±çë²é£ßA:þƒ/^ ÍSµ!fl {ØÓF÷Mf@ÝÓB\ 0‰{aô€"¤qn²? Œµ„ãíǸÇ]›àþÛßœ³ÖxØa¹„‹Ÿ�Ç hOŠxÃðî ¶Ìî4{î& w¶S‰l8^\ƒçú¼ ¤H2´uã•H¦ó/÷üßqP×^À¾W§â"‘$Ü:9ÃÌ+Ì�æõ™Ó�JY�]oǵ”Ÿ¢!ïŸ|kCUnþÂÅç1ôV°F•CŠlö†h:ÉY@˜^,K¡ïlÕS%>)?˜B�-ßXЖ„ûxöù3ú«jA*+Y™¼%vep§»áÇãIè¼Ïú·ìã•îùўʽdizŽ=�eûöuaÂÁRö¦£çÝÝ럛À©¦8Pž8 Ú ïÓÖ]s) &˜¦Ÿ„ö‹À€_€‡T�)8û &LÀΔ™¸­ôHìûaÑ5ã¼añE6EÌ£Èæ?äÎJ0…1¾lSO;‘÷€-/º:ÂßPàÔ[®u}>“‰·Â;UØ·�'™ã±¦×2B½ØÛ5«hÏ‘T²º$ Çn8c)?™e8Ô³ìû6 è%Æ:¢BX£À6ör"¥y<®(x‚«2¾sõ¶¯x«›×™Œ½DwÙÁá úu­LèàßfèÕ¤ìqß-r�±Hó{|ZÃ^aBÁ‡¿Î«gœH>;jß‹ÿ>Ä0ÃVK�|²�<‡#KEÊùðQA‹ß9Á ŒœÎ²Ös©œå:—•'‚~öiœ+p•ŸØú�•�™%;t©¤¨žË €sP!3ºkJ:Ï"x‹<æ¾jÏ[ˆJPWÃQr—ÓëÞá@ÎZ1o<”>ÜF³¬A DŽÙë¯b+z ŠüÉ;˃淮ƒOïá¹äi|ȬUÐ6 …?¾ó3g샇9‡—´­B—9Öpp 7&k‘å”*´û¯�UÛ²ÑtÈvˆÿ¢ó?ôN$Aûæ­o�…ËTÙ�ùìÝþMìšÖ%ú ?�©�—�=ÖGÿTïQPò´ ;…'«³ØçŸ ?%·¢ûzjÑ×¢¼¬$,†G–³Do#úêu„ù.Î�ÿ…SÑ©l˜xi&mH�å&تYžs½Æ|Üç3ñݬµóŸbÆÊ%«Qæb>NûT‚Ÿw ³„qÉlšoi%GX(Þh3—Ëd“‰bt@m£ yJ´Òì¾÷x4SŒ6L@eÁ\lÿ’ñ*_د¸ q:…±¯Oð:¾—À|}wøåA:4 µü"(Møªmmœ¹ž0Íx6‘(üã ÷XLeGË$„hß–ÔVË…]Æ’ÌD6vþ2Øš‰sàèj!¨)þ�}üûŽÍ}aGþ¬Íýõý(ô|4ïß嵫Àè•!wIº”úK5àîÌ/œZÇY&ë"kùÎMœÿp©o¶�¢GÁÂÊ€—†Ãîœ8*{1‹¬ çRÁœÑ°B©‰�\K3â7¢£‹<™V×WŠSzž,…Žº€Óœ)ÞÍ sv¯¦àÖñÌZz<ý¬õ†Ç»cXÐ]!ªtH�wQ)hã¦ÂºÏÐ>Ç\>%S“ÍM_ÁÝY°Ÿýºv˜®fl#½3g¨gñ=ÔWÌ~ìÀ%'´ØœIš`0ï2¦7»°Ä›á¾’Î÷™ RïÄ`ô_a~‹´T›¼Ä{…È‹)­Ï)�e¢j¦ÕÕè~ǧYžÇ¦í"8èãÏ+²àê§=B‡ŒHw;•ô”Øì±ÔÌYÓò®4&?:™vièâè'R›5�FõŠ‚æ9mÀëõP0K¡)¤ó!²ã9ì›ÑG”Ÿó“’Q¿àŒwþá³¼* yÌMÞßdžø}"ÜüÜN×.zƒÇì�xïPwgár¢Ò>º>t�9ýI¤ÙG^°Ð¨ÕpþŒ‚EÐÀsüwj­”ÚÀ,¦œ§àÈ‘NÒ$Óòdú½ þÿïᜊw,Èwl|.q‹ÊÒ´ÈüÓ~�‹  Î馳{r°ÖgL“ç›Õ,wð“}/†üòaN>6ƒ‹4¶§ÿ2Ëpôº–[&JGT§‘‡ÉiêøeN2a¬uÿ2йÇ-ôàç½¢.�grtn#’éì3¨=:.ÎD¥C¸‚Ê4ò“\ƒ¥—²)§ÀǬ%®†Âô¢(Þr2®º2®i_®„LCÅK²4%«£ì’Ø¥ô…3(HS7üÄÃË»Aé$±c.)˜˜G¦ÓÚaòfÄÈÅ“,ÓÃ"0RO™n-e�lÂ.¯lì{ŒµwIÃì3éi>ç§½ƒ¶÷Ê8" NW…aJr »­Öázyðj¡ 9žZŬ%DÁ¾ë·'u=d‹Ç£àš–iöîܼ‚r;Õ,§žcª¦×õæ¾û?¬¢°‘[à´® Ï(þBÊ›Oà_)œé©Âe3Îð’w«9/3”ì¦I&x–âí±’®{Øè]%˜k�Åh™&´ë+�Ç®îÂë)7qÒ�)‰þA¸^ï ì0צo‡GáÄ‚O`)cÇX*kÅ»e]Y»{-R~"¼Ë©aÓ�GÑ»ÊsÂÛÙíˆHÍÁ¼\ƒTåt*þ\mŠ�6ðÖ€$²ÏCºj¹ ö¬º#Êu¼�×~ã)BßI°ü¼FpJja—[ù0VÍ…ËX@�G:M>Å¡ßjá§ËEáÑö(¼;(ˆq|9/™ï„w­–óÌçËé•K—�Ž"ü0ýFÄHêy°ùc1/Ĉ ê‚xµª ~ÓJA§ ܤñ\Òø²WÕC@‡4ns}M�.ì,Ë:±±h18ŒÖf3ýÛ™êDóXAlÆsô9a‹¸ó0oXŸÍ}? APëA1ïn3˜ç c¾ög•H5¸3ù5FªqÈqo€KOä°IC¤ “c¹qa&ɹg�rcùÉš‰qŠ—ð‚õÉœþñ0ûmÿ }ÀºW9s[íÊFæhf|®?¹ %ó†�ܳÃx"Ûˆw—‰�v9‘%uadx ³BÐ%k7?;0û¦+P„ë%:R}˜%æÁìi*ŠÁz]Ðû\2ßžìÊÑ·÷‘ï$gIàqž;ò/çi )cZ¡…8ØÇ ’û̯×�ó!õ*Ò6E£Ò…h_¶—%Í$¥r½þ*}½”†:m$YÏÅô:# 7Þ¯§Y;ñÈ^q qÚOfæyn ´¶`n‘ø@öø‡¨9f Ÿy|KÞËaòšëv‘!=1ùù 4Æ…›[9. ž*±ò1%‡ï_zóù²x@a/ùìõâÛ.­ ÷Ò‚“‘ýF‡ãÜÍèh�Dv‘Ýþ&J˜¾XÍ¿éAü¥@–Q>+ÈìH Õò0öî/PÞPͳ³¯±$ï1_©?É'³kùoÀ9z¸×Y°€û0hÁGîµ:–Î&’üÀo4~¤ �ú¡ ÛŽbñƒ*Z½ßBª'®²ç’cЇVR‚þM”v¼ Ùu£@Çc%G �½7kŠ:»hþ�¾ŒvYPwCW÷í”`œÁâ9u‡§ív¨£¤QñB'»ÜëÚi›|/jy²§Óp|”p»o]ƒÂÉpå4,QPtØöÄMOd�|Ê:Lû¡ì0Úµ”TªÅÖ:M ËæRé+žÒ•E‰9i ¡P”~uªüË¢s˜;¹¡|ö3U®´ªË׃é~½¯\ØEå?ž‘ýץ›�ÇØJhW¿êéàÛ€×Kœø×v#|Õû%L9ŠÆÚ�¬ï㇕¯¾‘ÊÞ*\9ï4ܾ?=®*’¿þ2–ž¡âpæœ$ôº-Öõ¿Jæ+¿½øþÙ�^ Á$õ-¨xF²~ãð;Ru xÐ)þì¹ÝóF™»Þìª|ݲ¥ùÐ@Fò÷…�–‘bÁ¼5tfkÎxÅ~pêdÕp—›4®Ý°„¥#cÐáT;¬x§‚.ý(hÄîjŽN[t½·JVc§Ò‡ª«ƒàÞ½a²A‹àýÊ“?:ä`Iº5)Y‘R÷…mòÉò�.`†+ãÜê�1ׇ߭�‚Õ÷Y¥¢ŽsåªÃ}yêýþâëŸÐíâdœâ{^ø[ae™ ÿÕÊ£ÿàq�ðß²¿cÏ;«ë±çvhovHâ·áçðåü×K _t>áé¡Vö¹ çï‡ÿbu*Ú xñøƒâ”»Ð¶·-:×ÅqÑŽ@šü§†�b é {èï~EÉG~vž=(â“ú›Xv¹:ËÝXD¾cËhÁË:jˆJŤkÕ°± *ƒ¹;øüXpo){»Ž/5wð¨ï!>û¹$\Э¸6'Q2˜MxÙ»El“¶[X²,›û-r‰ è©dŸÄ£øpŽœCÒÈXáýùI;á’ 5"‚ão†Õ}c˧_ôB�³søÖ\CìSå+bX6]‹�Ž7õ�Ñâ°ñ‡Å£éäÖƒ¨ÞwŸñJrkEë› ¤š{ÜûA¤¨?{väësè–ÔpôækkŽðåë%4ÍyºpáóM(Ü  O�ï‘÷�ÕâÖ×ñËæráƒûžP8Ÿ¨nÅð{ÕâßàCøç‘¯ÖèEÙ[/Ú—\q,_²¾³ÿ®e3Ocî¬é¿Ya<¢ù2Žì°dÅY³1³C¾‹[%‡mÃüAñåjêîžÊDWhóáx7ã ùî`\ûå$?)­‡ÒÚåÂ9—+°§:„w.ñƒb}Uœ=ç�WwØ*NæÎ£àùKáã«Qì”Ås°ë”½ë�uŠ3úÝÀxU”3�'ã¿|s÷Qî³ë:ýÊ�à¿wM*+‹!&Ù�4BidS'¨>ÝÆ§¼”8zJ9„œ4Âç‰i”«^!®KÓÄ#’yO…‹PWË9c„ =àUB žÚ§Ç\’Ë‹*Î�ÛkÎ;:Œg^ŸÄI¿Í°Û8Vü°³ú¡RQìÂß²�yð½ýXu¹‚‚%åÞ7ó"å¸HU{g :VhÁcaÖ°Fì—²�û]¹‡ò�ÖØoP)¯Ü˦¶˜ÞòU²ó¤+®>_6zi®©ÚÄI—¡[ÚC®È<ÄñCÇóýWWاß~\qÀ›ZW'‚\{«Èз}q{íMjŠsàɧÍùq®°yÎs5ŸH*¡�úy^úB‹sz® ÷š¾ðeª�HßF‡¶ipÈU�¯Îû �E‡©tá <£h+\qS\]ÀÜs?•¸~a6„Cú¼%gvlÇêÿ<„ø�åøßí'ü©4ŽC]t1æä ÚØ‘†óM1ey½·ªZÎÈqµgòb[ð¬Á^*ü»S‹5T©Ïo󊜃mx¤ �o¿Ê…nr|õvoö5p*@ä©Môý¿<�d0U×VJì’`“¸{WÎÀÓGz”‹¾ZlŸ—ÌKïÌ“\•芮ï6âµ]èÝèÀoRßpKÊÔ9cÉÎßßp�ï!t!ËQ\¸ ¼GïÓ §£âÉxé¯Ï;« ‹G¨°åæè­öGÐã�=âCqtt §®�¦�QÂëî´²¶gL[ƒ“�ÊTÜë&¸‡Æ ÍoÒÜçÕà´Âƒ‡ô‚�·KÙ0tÅ®îÁɆ�Ñàºj}Ó~‡mƒ 9qD¾7ípüNjãÚ¸ ä*ª¶•å_NÃ3Ï6Šþ:ç鮕ÇEh³CøËòèbw*19 ‘�hlÏ#(ƒd£WHñ­d|êß¼(NG1¼ Œñþ/f¸ÿúäæ)üûWDù±¦Pžn2B2*S|gêã-·°)aÞÛ1<åb18mh€ž÷Kqôö.°²YLªcdz¸n+¼ì[À™qø¸Õ�/GÇÁ6©tºw0ŠÔ¶ð¹Ý¡�òµ‡˜îƒOß)°P¦B)i?µ‰ç­¾Ë¿˜üÛŸ\¸öV ÷÷»òI4¾!E(Š�ÃÙkÕyÍo7z0”?8�æu›î•…MÄu.êÜhë ®š×GL]N¨¨¼f¯¹RJ…��jl°5’&•¾CÛÂe ðD‰Së `¾]±8çn”[ÿNiDQèS-‘5 zir�óH.XxÐK‰wÞ�jI…XôWE”XDÑ’]‰tßjØý< ~+‡`ú·ðkÕ1Wq,RúàšŸ÷©OÜhòײª¢ &Ø-Ïþz�—¯:N·RPøIÎŽüg±!&œMÝ»ƒ@¹f_l°åï ”yó®Id÷>÷ôþ#”)ÁªµŸIöçka¬�š˜úì uÛ—ˆÝÖ‡¡¥Ý“²U�3ÏK„Ç ÿú7è& œìÛ“›eƱ_è6tÕR¶7ÍókÐéÆ=‰Ðk"N—$lH–…IÿUÁµÎË�ß+6,“ EqTxÜ×1¿…ÌÖCœûÏ‘zýŒÜ/CXâ$t[^ š› »;šØ<·,[Ž»53 æ¤i¹ÚsYª:æ}{’ûTGÑìÞÏØŠ­ÁêÙXÖÜ<€$æ1´úe15›HpëžÙÂìßcÅ…< ×k•Ò'guáPˆ=PÖ°lîÛœð¯T¼ ~oÅ9Qüuo„ð'Ñ–Õ÷Â&¥PÔÛ|WÝ‹ ºa•ŸTÅ?tþ•Ásò�†žx㪯ÞI(ëÑ.áøE(ºjLÑôYã m¬¸I2ëMØðM�˜ÓS›ßK¥²j±¡Ÿë–˜KNˆ®Â¶‹è{°OÍ;gÒµ¼ÐïÕ�…Ÿ›ñU|l>0Ÿ.ù ò×kEóÅMâ³åNü†r‘v$~W¿,žöxEGþëÏoçåÓþ†~˜c¯Ç_}Qñ÷iš³À.®ÝSänR•áZ ûi-аX˜¿·*r¼aùë^åQ-C`MD¹äNµËËø�0b‚ho`F1RJü©¨ww¯©´õ d5‡ŸLo5Ë ´åä´ŠbV-hŽÊÕC–c×ò ¬G@U6î8Šyð¾ÃÔ=a"8ǵR�Ù4\&»åÓ͹%4�¬^çãÅ…s%î²çð{’ÕŽ”Åg²È4ú6¥;\æÀ+_$Ž¿4¨(Z»Û ÙúšP”Á2·ŸC÷ÙpûÖ(Ú˜vP¾‚2_ß²‘,øçÊlÀ»O=MÝ sn†Á¯6ª¸÷þ¢&)Wk‘BêNÌ»$¤~«ÏÆ ågõqpíÕFÔ?§‡’°ã<~Ý l٭‘kJ,/'ˆy¥u}®|œöo–Ç$É?FO9âÚdÖª4äþךʪÞÓéï—á¾·?ÝŸdÅ,å)œ*L⚨¾ ¯-Å…ši¬>шþSÎWG™¢ýö9’Ë~�\Ž'jŠÜbi‚¾�õ0¦´^ȈýJyž�pnÅuznó<�ÎB†r4ŸÖ]Cv›âás· ¿��ø}<Ç”án�¤ÀS¹ç¸u|éz*ÜÛp7ÌÖ£ßZù8PSŽ�Šžá‰îR¶Û€OGXᬕžôòG:=^ ‡óF(—[ãÒ³(Ñ?�K+zaë:iáóÏ&º#I!A ÑowH…~¤šŽ'ð2n<�ãN·—âŒÀ�@F‘§|%áÆBšŠµÎ !,´Spê­ ¤4xÑH!èâ‚2ËÈpéãÈ›Z`n(´ݲ¨6pêÎÉáÄc œ?~€Ï>ƒÝ�Jà•ŽQÁâ¬Ú[ØÚ­&°“Ï?É|VŠj–ø¾`ʯ¼&)³ÝÆ/à:ǗƽVáÀÇÇqVÉ`|zMš—{ÞáëW ±Jw#Ę̈¥†’n¸0ôJ¹ÍÂø½~hÿµ÷ùŰ�×åW¾s~���?�ê¾íåc‚Æá@݉Üúʆç¥@g\7=–ûG¼¦Óót¸d‡/Ö®ì*_ ç¶AkÑ+h=—~t„¡+í$ }|©þä8ŽLi¡|ý ìboÌ>l¢æ­û _ øÅÃ:ÑÛäùžÔß¹Û¸G‘]iñæÉ7Öc*Å’ð"Ž4§/Ãú‡²ØkÌm ›@gÆ3ØÒsžƒ`ÞöÁ†k$�ï‹4îc]„�><ÆmÎûaˆó1ô;åÙ�α»vO^ò4·Î*£=y2Wý)†d”–€8¾n:WÏ< oöIàâÒÈ,Š�¥ñ‰’õÊ<¬˜8aÚV:Ô‰Û¼þ•È�Û'@Í�qcçbrN/,§BYËôÔ¯œä¿Ä ¾Kñpµj²¾�@›SÈk@%/þ|�R&žÄÄ‘û…M|ѱTT~Y+Ž1,PõƬÑhÍÖ¯´nÇx¾º:Wøö¡ LÔ§²¢v�`7ù,Ùþ|@'úóc/·GÚrÔñ¿ðÓí±8í”?ºr@ƒú<^ͦ-[ÂÁ<ÍŽ¼Jag§ m™S 56>xóÕGzóð"Ùi eáJ�Z/ƒ7þˆÙpç¿à<ÎY,ð¶f;Ïà4M“ ÚúSÉ�³$9†qº‘ìç“-˜©·‘qÆmj?ØLÖ×K8aÛ{a]y<¬é�E«=ɰú‹ ÷¹�­BC éŽ HgÉr�A±ãÇ›vãÔ<6®X�Ãô¶–ÏÝ‘LþsÀ7VžÝO¡D§qYÕò™¾SÑ^É4ºË]ßU �á1ÿQ»F"~Ѻ–×Ì…‚Æ@,�'—h4y8rH§äÑൂ£ònq�»_im¤5k ægŒ´(ç·�‡‚þÝ“ÂøkNÈb œ¦åJÕPrOŠÿ›Œ•b¾È2 ñû¡¿Ôªà ówyãñ¡3©¶eÑ™J®5Ëpz®¾X¿ÍRœƒÒÞëñ�oðgÙ[mkXÛðŠôvó²÷#qÁ–CâÑŸç…Ú�ãxÈWW’|ƒôG£³òØ’:D,é«[.¯¹ô®ƒ1¿T(}™^7B–V&m¹ìÈ/TxØ_èÓs+Í–ÌKW@ÜäzÄn¬¿j9ï¼³�mÑçù‡àå ˜ó§T’´ÌÎÄôæùÑ)BË�3Üyb8\›VOÕ«û�ú%uÌÞ>™FA{~<4²gçü�¬¡7�}nÈã ›Ul°DƒäžË`¹Æ¿ŒQzL#–Náp+KVí à�4êp8Ü6á�9ÞH.øRe$\4oôn‡#Ÿzñª%îûQ†6FR™Óqv–_ c*šøÃà3´xí N ªâ!6ì×aŒ~9³qä¥~|ïm!ã?S:ò+„ŸXc×Én¶Õrç�ÍâÐüCð¤,¹™?ŠjωË.½¡ßžÂD…<+!œÖIñòyùÐÏ®ÂxñÛÔ¸ûý.Ïž ·u¥ñõÐu|e±]ðh -‹¢„߯áÀt»`)¸�÷iÜûb›63žž-ô9ëÏr§2Ùný±Û¿�ëõ9oóþZ´�Þ\âžÞ¨ÿd<ÖÍ0á¢ù Ü;"‘{- á+RÄuEâåœSpäþ\ÊñJ8. ëf]Ìlfcyú8Ú:ì�¨Ñ2’“{E›}“o›1ùÆozíÖ‡�Ô‡ÑÀ™×¨Ã½î' ¢”n¥Âåߎ‘GÇ4Ôíþ �ùWÑâáF6ܤÍ6³ÄüQrI.€+TK9×g¯ø!ïœ8D¾†" ns—©4ÿVõÿZ_²|‹á,<‡:ßE—¶³â4!PÌ íOïLþeI…¨+`Y‘ ¨c³y,Žj‡ºð£™ÄPÙ� .ކ›�ÄSýicë4>&\̶\ fÏþ^Ü; ¦é­â‰%e„º½içòz˜»o;÷�Rn÷ã%Í»iFåEÈRÎP4�5&y‰c¾¦sõröôsÅÓk¼Ò¡€ÎQ£`‚Æq,4¼'Tœ„'6ÍÃ�]{à™Ø‹çÚIjýÉf®Èf�ÁЉOÉRùYœí‹Ÿ È-ÄŠ,׿³Áý`¬™ˆ•«K¶I�úÄýèwNÙ8‘ØÅñí° AúU>ß¿L]uª8dÑbá}óLv�`�»VT¼Ô4Úx²“šÇ­³�¼N׋ç¥Ç‘rl2ü�lð•9/luðFëmš1¹Bñš¤´MÂ×T‚Ïý Ùå÷zò‹îúÁ´._‘Ošëòú¸Êó/Œ”¿ ¿n¹òß�±hÝg+ªLt&EÍ0ôÔ à;ýÒP{,¼rèt±3|çÍ+—‚Þƒ(zWÛ›L'¢_5#`àôcŒŸVàùC&¤•Ã>Óî�ÑÆI|Ùüu&iÑ‹àµÐÖt<­�QÛåÈìCƒøyR¼X»SØ~φ�cQç_üý!U‘è1'^>ÚËò�¯½3qÔvÖ‘FLº\ŽpüS[^ê»�߾ȡQý¼¸u¨ ,óñ·³uàX¼ðé%ÔÔÞ„o'Å�k»…=MÏÄKÏùÒèÏåÁwSÓ²]øE/�Ò �²�[&U_O~û7Äw‡Qq’ Ö'ÊàÖÞh‘öA*‰iö&v“ÄqïK …•CׂIÂ`ž¬y—×:ÔCê âªÐáp¼áFÓ½®mäÆ#È3: âo¦°EE#‘Õ”èO }v": ŠbõãOıñß„–ÌJÒï/ø6Œ]Ó(õè$ÝSL×:(òÍú0ÞÏ í7ÔÂæ·ÞìÓ8P˜¾û1?ý}Ä–�`Woà@÷fПˆ¾Ü°t¹°U¹˜gLêÁRûtÅAÝ> f²ê|â8Á hØ ŽßbÇÙaK¸®  ŽR¯‚"Ô5…FmyV»9QÐU8@âÙ'b��)�ýì 8§íb-�Øã¿›ÎK«‘¦™!þUáM¦pú·t.›íÄ×ýÚEiíX¡¿Þ?> *æÞ¢ówtñ@Ù›ò÷ÃÃé °ùÀþ í¨Š±¾c»oÀ]ÇAœ»9†ËŒ@ÙZ¾d|€´¼Ä™{÷_áˆ@'èÔ.ÞtŸ%~‰yL{ÕÄÖ4¡üh‚&ÏSº Ç|6ѯ=&œ5l•X¤ þ}/“Žn<Ú˜ Ú^¼Èµ76¬XC%㣋†ñç|#~ì;ÖMÀVѾq £æ¡x8†ú¥Ésv¤„gü§Á\dŠ}† AùÞû ±w8O^ë„¿”ß4N£OíKÈaõ6øèäŒýÂ×â�pÏü)˜v¹7î<+Ë^©ÒðÚâ0�Éxô1’ÁʨvÆi‹yŃÞh›÷^NŸ‹Q©ÙXúm…øÛ7^xþA�û¯˜N=ç(ඃÄ�Ú¡è¦úšRšd<­ŽÃ&½T¼e¸Ó|†pû’`¸&WøñýŽà%lD·5J Xώת«³ÖòÑ,{nl¬îÉ™gáÒÙ|{x›h07;%8cÊ=RÚ&Ë3›’¹Ïèçz€o%�¿v¾¨ßü®¦–r´+`Ùîb(›/ÍA)šøh 1/×»[Jáµ×#нó�Ö]ÜŠ%OLx½O£p0ÞGç~²qWÙ xˆ »CBænqlÐî{è5Û[Dr–U’½7}ÅK¶³A²Vƒ?l˜HÆvKyîªç´êÇ5�Û4“g�TæÑÁ.èX]ORù‚å·‚òïq´éï3šØTEfÅÆØ¥2›/ÑXòýî™0 ŽýIgõÍ/Êôu¥]m†âš÷«H.Yomn¢†¨hìuò4inÎ…Y~Õå׫£x�i 4¯ÕëdøÍggJ×\†mž}pºlæ4•‘|Ú20òû Cƒ®ñ§k:lṏS= Çµ«x”×.¬{Q Ù#è´ßJ‰šÊчsíûxáÇ5ðîÔÇ[Õ¨ù/»Ö)?¥yãôðrª“°`ÖRš8r+¿}M²�ÂøåçëT<Ód†ûãˆD=ŠìVG÷¤4Á{×$Q³áäýãõ¡»ö±É¨x=¾–.Ú&C�x;ÎÖ4+¢G”,ìk¢¯sNóÄÔ¤ò[Ò«ÿÝ¡<ÝŸr¾©E 1%-$ÊJÐ]QjÏ-°Ìl&=Ü0‡¾öà¡•Šâ>§ÆòÜ’vx§gÄ>WU¹â¾ì‹<Ä.«�ÙæUGDŽâ»mÃÁòW€è§×À±ëiòÿÿcÓꂟÚSéóÝXˆµ» 2šÅ¤Õª@¨õS̽zÇ~ž�­Æ¾¿æâgß�õЗ/:„ßÈñÚ›¡¢åômŠ%F¬³ÆêÙQ”®€ìÓ’]OM¥¹¼âÀ;Ø‘-Áóqªürw <ß·ž•–ÔÐîëaÕõ/eá¾Õö¯Øzw4>Ûå -oqk±1­Ø)Ç£©ìQlé*ƒ�=â¡Ëêâ¸E×@iðmð¿€Ãwñý�Ñ jåÂ-£%üàk&-±\‡=ÿ¼¤@‹ñ\uòikÍÔõ2ßœæó'æ ›_64ƆSa•×køU�Æß~ÔùÿQе…(ù/ÆÜý`ÿì­ n[:Š¢÷ÿ¦µÒü15Mxö§–î…_%Ì ¤ì}‘´6P�Õã@Àßݰä_·ö¹uÞDo¥…#éç4 ôŒ6Ûð]´ßKðòÎMjÃ\1s/*ì‰Ý2«Ås넹&þ8úŒ9q�\>G‚›»;w¾¸)êéOƒ€OBÿE™BH‚”ƒ¦�÷-ÉAóFc÷U!óB=¼W.‡7‡ÎJ^r'Až";¹Êó‚_‘t¹r¶¡ôäZ1í_/Í86‰•­v²�b+…|‡ßÕFúI¬ûp+ë=>'œWèIó=…k³ºÅ~Á4ª\f§ Mû>ùxŒÝ×)º� æû?¶Bý]6Ëkþ1Ä£¢FˆÿÙArÖé‚×Â�<ôÑ[øߓ۬¢`ûž“£Â:FüÛû,2àwd“؃òO}á“OŒAé$þ¹ß*.Y=ÌLð—êh2îƒZïC%VãR¡ªp"ŠK ù],^ð,¥¡w;„ë%r0P1²Z® †¯F“ÛúRP²NÁ’>RÔPïÆ«ö·¯’§‹ó3¡âÕÖ¨ì ׊™c)·m#ohìÁ«ê<ØuZž‰†xµî-óŸ�5ïr`=îc7‚+êf,•¸�æn5áXƒkøgô@ÒÕ¼Š)R0""d^W/‡ùªÃ±)Ø��Fêñ�ˆ,a„j?™“K…^ê¨~‰Ê´ûâ‹€>üÈ6 N'Cé� ŒüõA´óä´·"+†þë«û´.i®®2ZßSÀw�̱~M Ÿ±9�ÛÆ’^¯*еi.“¶TÂ#>oà¼íúxÿ$Z6ˆåZêÿ¼ÔŸô�ÚàOÿ8þv¹NøšúEˆY"Í'Z³±zu<Õ¿{ˆŠ–Ü´Þ�÷�Í.%Jã7z³§êÿo@´u§à‘9�©‡ ïË3aÂw#z¨{2’0Zn;˜8‰%c:él¿TQ•”8ï‡xîŶ7Á�QoŒ§ º„‚•6|¼ Ê™Õ×fcŠŸ2¿7Á¿úB{º-*¦ #œ¯i½QeZ }îËB•Gfd†ñîo‡!¾ÿ=þë²÷�õ¥Q7$l{´7~Ÿ?Odòpß“•» ç0s’¸·+�—§‚ùóû”|¬�¶^õøÖÏ-<§ä;•wks†Ñ*¾pM�fõÀ?Áéeg~Ø.˜ÙÂuej1l=4tuun±‡Öz\û|´¸¼r›¥~Öm­ "Û¾üwÂ92K¿Î̓´&Ѥ{g…Ã{Tyúð‰ìæ Jg¾ã¶Ííƒ÷Ž„F9Ë0oÍk¸š¬)SoÐÀ>©ìŸñœú¬k¦ ²�b/!†3ïGñÐÝÜ�›E1º›(¼.4¯Øà¸ÂGØâÒ&Ù´"“|Ž�„�2úœR:Ö$@YÇNaM¼*%íÊå׿vã# 9þÚv˜'S?Þ8Ìå4E.Iqã¼^“¸éBšÏ6çȘqœÑM f„ùõEØ1l1›ŸTÅùR[Ðýf:¯ï2¦­Àým6™ÉB᪳Ðþ—ž×@‡Y¢ø¦DKÊE®LŽ[·žä–=ñ {A �¾‚¥=1zf£è]å'jE×ñ* 7^™•}1Ïqšõ•N´•?WÉ­=š¥éÊz—wÑ ýç$ÈO@«®¼ò¬a9ü¾[#Õ IÝj2ööPÁ—ëÊ»}×¼±�X,I¤­CVáô:=!Ø<w—ecT­2~~O�G�‹3ŒÐõQ¬—ާ‹—çaw–õRKà‚Iézù,ÑìNš�pŽ®iȾo%Ô{åa´JœŒq|îYØ÷KÞ‡�g³m¸&F‡�7Jóû;lo_m?ßÑ•–Iƒþõax_Ï ¼¯äêUCyÔÁW’Ö;R¸o¡9j6ÐÝ~|ã_§O©�Cªw.îjW1jÝú5õ»*ÐZ³Lñ³ÏHL·Ìâ,jš@» 6à�à7ÐË.>YHu©t7篬v�’'â€ëG8oædìÙ{ÌMŽ4gµâгý9s×Uþ¹žº8ÙE‡'ý×_+¡D%Ur±v€#êî(ÂfË¡&q=¶E�¹ eó„Þ]%ÍÈxZàõ˜æh5Á’ä8ÁX¦Æîfs°ð|ç-Ê„Hž~¬-¡>î¯0‘a?·-T7,Ö’ãC’ øÂ1 $c^Á›c2üÓc6þ9bÎO¼´pÇØð¸v4ùèm–Œx1—ONvÿ+wyÑ÷Pü/¯;Þ’ÃqêZ¬æðÔ*”{e Ç.¿Rµ6À‰÷ß f�sÄíÿíBýwJ|'y,V Ž´çmµhýë„�¼J›} ©Ê$XÜRH>åmd0ç0í7ͦ�kÌ)îkOÀá£yáåxjµ�ãêÉñ�÷©Žn7ưŽå3è}ãõ?‘Úþ*³ûˆá|åí;Ö}4JË�E�Ùv¬&W×^ï?Ö,Ä�nWéí} Ìùa)Žùo(Àïîèñô˜}ð-ì8š®®A:T/žcRŽ#h´}Ü©½õ&iôXÂÌgâ×i¤ùÀ‹ŠƒñWú[˜x‚òúÈR¹¦‘‹Å�vìžÅ.ãY÷cÄ�/”9~¾G‘‰êÐG6ë ]huXZYì¬ ®JXÂ5#•°­âEYû�|¾ç\ùì-x`ÈuÁcº;Ú×ÞÄÛ駸§€Ñ³°ý»»àZ°O ìÉ 7† ·¿kVŒæËSO1FLÀò‹­ +�õÿ¾ˆ_2¶ã“]ª|ý-òüRG¾•¦Â`Ÿ|lñÖßâ ígª¨÷í[4;'Ì~Ó)¯ÉÊqë3X÷s1-�/Iðºý.�lÍ1òòTmgó Ï ¬½$úŽü+Æy#^=)� ÿ]—d͆ÅÏ$´?÷5íß<‡þX™ã§ž´hœ?ÏzH‚æÑubO;e¨ö‘̬hAv+>!öì<+†…;Òšëd·$Ýrôc¨8F†îõ3ÇAºÃy§C/ »¿«º¥ñÅàZ:uìäÍx/ÎùÐõŽ Z7?¸<=0˜½uâ¨û豿» ›LY�Û6 ­§ŸÂ'ÇÆŽ0š3TƒåT¨ß‰ê— ¸_j�e!#øªçlT4¾CWl®ˆc¶ØâœöÇB`Їci‰©.^¶–FÛeEw-yÎé¥Ì‚‰3V=õ’÷%½ycØð}‘á9Œó5%k�WÂÀ>=õ…<ëÎÊÌÕr£·�Í‘u||ó@ÌpÒâ®@¹ô½Øm 1žII©ÝÐ^SNÁoH'o$ô©qA…1`LþSÑ5FìÎ,³ln§ù*²<ƒeÈnaW²+ÔIaÅï¨í™Œ7 bPz+~8’áá>–Bø™,~]Ö å ‡àâÂR*Lé¤öˆfNp®Æ —ìú~\Ž7=íhpÜÞòì¬Ì¿ Ï‚šÅQo†iïCר±ý]T»ˆ§S™ñHÔPXÀýâU8sbþf.±¸þ‹ŒѬ3¬\ÜôRìÔÛ(Ãw*6KôÊ;¿NgUç0.Q7�S ÉÑôÝå2]Ñ«€¸5OÉöA H:þÒ᫆üÎ>ƒ<�¯“úF_a¾õdüòjÚ[>£ï‡Ê—½w�ÜÙÔ~? 1zoñƒõ¶=ù¾é\ïˆkÚâ�¾¦N½öT€ãä]¸èÜA’‹]&…�aT–ïÛ¸N²áF ýª�ÜSÿ�´öåböoëÏ¿÷+ã š�b^±2�’-&ã3ýYÁ1¦¯…ø–޲¯�ZØ´h9¿s”POïì9þ4H'ô"·¥¯ažû¬:t†gÉž�õ{» ¥>•.=H¢MWÝù�îk*_¶9üIâ¬ñ�4nس¢øé¤xXô6 w‰ëN¯�„ R [T¢ö&x¯£LW50ø›÷ò¶á×¶G Î|ys�ædÞ$ó ¸ýa!®mí…1µüåD¥¨:«Œ^ ¡¼Ê(Ls*&CÉAñlØ]š°�ðIõ_ñé_�¿ ·(÷g,G~úF6œ…Ê¥Ž�ïØHö 3`eiklSíéÔ¿c-iű8ã¡ ¼©ƒ²“RT} äí±«ÿ–�ÛÄ~¬º÷ üükÂçëÕøå)mžûcÛ¬}g�C?= ÜÞ:‰WVÍUÏH£üªix¼9£—» eî(„½ ¤à¸•üæõ=q·Ëq–ÚÕGÍ H½•/Ѭ՟Aæ‹`,¾¸îÎÃ^•‘ë>C´ßL¶Ù`�(t�ð=�þÜ(¥Ž½,Í0Àè)-¼¤Œ�ž%ÂΠO”§+ÍóNÈÓ¶ø5À5Ý�à§³«Oˆ°ð)oMäó¾±*5o@¶‰;ßÔæŽ¸ûùq âðÁ¥ô2tE7ébÍ4CȬŒg^C³ {z.Ï?›+<QÁêŸä¬Ö7 MfÉ”ò÷©¸$ë,{lR!KUC®ÚdG‰ÖÔ?X@ÁCÅyˆŠ.#àá�õÂà=¶üwÁSÉ�¦@\—äÎïÔË@ÈÇà îÃñ>¸sx ©ZÊ¡×Ù»prï]aƒ–¹ã��à¸ÅOš]c [l‡ÂãÇÚÂØypp­n²�Ê+ ysß�¢õ¢`qÿ0SvoŸÉ%ªÄK†?…e gèj\_©Ê�ö‹Y'PgEœ¤‹}‹Éì÷!L_´ÆœOâ*»�˜Ùø€N{=©"=î�QIwŒâPÓ­ ÷G mÙ�®ÐF-m©X2Y»|ÙäÇ0lW/6žç(Þ}l!ñµTŪ–±ÂЕôzòOa~SÌ]]6öœS¬À¯Â ù=Æbu¦…Pú'«ìä†búÝt† ±þDzA؆M¾‰ü}f ¬ŠÏ*çu7Xíeú§ËÂÞx5ìm~œ”›JÑUC‰§ÉÀ­�àŽÊKè±í T=:͇OeðƆcä±õ9ïóëG׎(ádåµ(×€ú_jh¶î~ /�½ž¡•n q§u0Z_�wÇÀýUøfë¢sûiq�%,²w€g�›XNØLí¹J‚‹Œ¬UüƒçÝb+[uÙû?±`Å�^°>s ÉÌ>Ä:©¦\_î¬%õ`n•½+æFUÑŸË©/8ð˜ÀxTŸø”Z§ áš¼7|µÓYôUÐÞúŒÎ�*×áóóùP�Ìzf…'òí1<å”p{{žX®Áv»‡pÔß�¾Kž‡ß_%VíHF7ýârûÛ"õ¸“K¨�o½ûòÓÎC~΀E.âO¦ŽlþR…“2®”›m)$­q@Þ�Vñ~.¾´|Cá?ÿã#«íóÓ,YGxwîŒÇå7¯IYÃøÊPPù]/þèZÈO×ÐŽ¤ßô jŸ~ôÌiFOÝaV/„ª‘¹â¨Šé|qâ(ZÚÓŠµþ¢°+ q³Y4÷º &¿úzCU]LÎ'ƒyqÙ[7ÅYÜ }÷Ѱ‘ûÐ>/Gh£�UÙm�˜°—ZÖ~¢Ý~ƒìCWA&n*Ê÷O¹ådôn o{£�¡f�Rù<{²‘2<QêæT! þ™V&†í7Ç-‘q¸}G‡v‹üõ œX4€�—§ÁÓ³ëAÿ¼Ïú3”o«�•|”Çaû–á�œ_\û6‰}ïzQòm¶ÐŠà`ùJ\Ç) C ã¤ÀG¦Ëá’wkù FÜPL#ž/eßõÉâ~Ó_qâ�VØðÚ�ñÔ$V˜$‹µÛÄ÷=ëÀÀUG-s†ééjXš»f Î~Œ:¶9by�®X©�Ò£p\ýH”Ž×ä>+xü¢÷pxϹÚ–J÷ö|'ÿ3vœ¾c_Ä —áøbŽ|÷KÖmÁ®¬Ajh ¼˜õ…¾ �†ï× çìk$«ðÆæîc+é£Ôß/ æÿ ,œ©Ìó×…Á샣ð¼Lµ¦S£r¡´ï”»§„ÞÍÁàù§ŠZšhyÚñÆ#SÒóÛ-®©`»Þ¢ÎÊ(Š¯Ì™Å|'ñ‚]sÐr¢;´äʃwIªš®«åÿz¾(Ÿ6êɲÛý"è-­M^ãIËì�rLà{W«ÄG§‡Ð£4Êy4õ“ãcæo„ï#20¥Ð·>·c›d-ü¼ò»ømõzŒR²Ä�†%ÀH¿ÕÜ+M¤,ƒ¤ô°»fb‰Î$^šy×®k’úY"ó0Á�sï¡v‹õ[NÓ`ÿÑÿT¶&½¡×âi6ŠJ�Kf»y2¢í9)lâñô(5ÖÕSäl¯Ñ'B�m”ïÐåyÉe6Ât1÷êp{¹óƒéðù9t³å›Æ•Ã5Wœ©¿’}B¯à M´(Hm§ôA5M n=æÄÍŸ‘óR-*kWáÐ[O ªñÝ� ƒ´…ÝÊû±ÄzÝ~6� ~ÜÅy�ÿ1Þà¨c”�ž‹aåõ]´óîÊ1 ¤mͱÅ"‰®È Â÷ xuÑ..îÁ÷‹B¸z¶GÕ�åŸÁhµ#”v�Æ„…7ÅÇù Ñó¾?�-ë#Ö‚ý©Sp¢I–¯ý¯¢ûŽçêÿâ^’ŠŠRH)!#3…øÜs2Û¢D”D¥¤¥B¥4ŒY $Dƒ(ÜsôM¥¡(ÑÔPIE{ýúý{÷�û¾ï{Þ¯ç믻dOïs›^9[±tå~o±œæÉåj›ë=…©.l6¥îjŒ—ƒ¶òç¶Ø³æ œ¸·³†öDÿO‰ìúp-[4q½ü?ëT½Æ%fßÈdzÊ?oo,�]à!¿B…ÀðZQj‹.îo¼ÈÙu•<¥v —­˜Å = 9Á'�~ÿ‡ò§†¢fF�Û¾«L¹Ìh4ا _¦òÂ]£ïT~´ÌæŒÇÆD+\¡C‹Oá¤c“pÍ��|ìÀ+˜2E–½ö=À|ÝTÚ:o¬‹.`/9yl[ÿ�ÎõéÍaòŠè�7Žä†-¦©z§øòÈhÒ(èÁîó„¨s41é½h ás�ðȾõt%*“Ô4or÷=wèÊįãõ0f¤1fõ*À~_óa‹á^ìsa÷[ñ j䢹n®)—ªûK–xEð›�Vh÷I¯'©0¿ì×äð¤žÚ|~˜Ç͹B‡š¥ùcñ¸óõ‘XUm›aƒgip¸œý ÚJ�ý¼xÏÞ>ÜYùQXÔßBoˣú×4òM5j¥6¹‡ú<åB"«eÉá†Ä¯ô¡¡Žv¾ÊãËûãÉ.#NËIƼï]`ua%z˜°âÀ4ɺΡT¾�fÅ_¥ªt_lÙÞ Ç†‡ò—¬ÖrS㟵=IêÃnð_ާ֨àû4ñîpÞ/òK´çäa‹pÜÞ-°Hj&íÏ´ZúØìFî­îñï9 &žÄÃÉSØ£Ô çèTB­J çŒÔäðù�àÛzVâ><ŒÂ�½XúN˜£óž‚Tü)HÉ ^;J¶íŽäa=$ÔþŸ’ÒVh»C@ænœ¾& Ç^o­O;¼ªq®o%<þ›†½ê¶qpöiR»Š·×’lpêæ]ü¬q 7í3¥�â´ïÒQø°Á’òìz ÏZñK¿#$ÛpRT¥¾(÷ý€hõÝAHz kå§päÎ;p¼Ç<¬©Ìá€;‘�â­‹“Z7�oßíÔóÛFé1bz•"Ê,•…“h$¤š ãÌåû!ãF=ÙO‹#ý—¯¯^º°‘KÇH(öcÙõ ¸‘yÚüs±á7èë:N.…±³sh_cÙøÑ¼—f‚þØ$:¬É£þžà¿~‘ô»o�[åƒk@�†U<Öfd®þoÖØÓLúàJ=~yú&ŽLzCó>¾ª¶÷ôæÀ%ÀßÄ&rõüJA«lp›ïuœÓç4´?.H�á›ù›aưl¸P�Ý Öþ¥ðrÜ¿ou´Ììá�+¦uSÆ´…9•Ûsbh‹ÅLüÕ0Nú^£G{ܨ|ÜLˆuø ¾�öÑ®�EÐcßiØ#» O¼ßŠU%qÕÒá?@}ìAÜúÆW(ÈTÛý 2Ãä„›ý"ùÚšÏÔóó±¢\ õ%&<ß4Rœ¸t*hlº( “—çW“0áú~d1Ý^ëᯞᜎ¢¿Dšq#˜šVňŽM¥»"`eï3UJãíØ½°Ïz˜áÏé(³ò©D§9žÑ`ðጸ¾1…>ĩъÄt:¿b¯¶>^]Qº‰?>ê!XçëÃ}�Y<èíá� ³ÿ�1œ&‡êZ;xÝú÷ÂŽ¿À¯æ#ÍŒu�ƒëuñå7_áK„HÅ%p®ò‰I‹ Vä“t÷þDe'øí�[Õ“ÚÒûÏ –Kœ~QG’j~ÐC9黕 Mzrù0žâd ŠnI<ð™,ß]7Ћߣæ!óx¥»wÔš²û }ÞÖ»ƒÿu”6§>(íÞ—o'ú*DyH¨¸ÀУÇ8Ä> *çƒoÇ@ð—ÚñoÖb¨×Ëétþ¢ ¬¸dŽ.ö"hèo“¾BX]JmžD¶á¶<¼—?׃׋d¹`ž-ð1áXólþ8s)Z·]"Zx–º¤—±Æ�:A±à›ä’é_¾“)Ë“‡¸sÓÖdŽï?Hbsâ —šÈ1JÁEsG±ö‰m˜äQŠn’r&tpóþÙ^!y}qý·9’WUÞ·ª B§oK4–s�l‹is ,#»úH®«ø3™‡…q™{§p´Óš7«ý¢C5íwf8~± »‡Êp÷Þ<®PNÂ^ºƒp½=Í„û¾7YÕ£”w�,§È>¯iê¦Q¬î{—ÆD?€v—] “qI<´ò1ÊéA”Þ­êgJ€·Ë·BkŸBÜœœHvi×ÉgìCÚ¼å6趇§±ý«¸øÉ}h`Á‰³� ùiS~š£Àî¬Çi;.Òã ˜RxJ²C]k‚ž„±T¿,±ftMõŠø�,mX@™²„ÚY¡(o©²›ä ¾3ÁظPŽ»Ý‡•†Ü¨ÞTÿXÔª‘a×+±4ùB¥0ðàz˜ÑЃUû|…ÊÂsÔ²ùM6†ZŸ fð‚~^˜æžE�ù®˜ ¼S°Ê¥BðÈ÷ä5£²�âv›í@–=ÛÄ‚­_a›ÎT2VÄ`ÝI\¶xtÝ ¥q©§4\J>Fݤöϼõô¸y5¬<âÀ;z¼¢CG¿�0.­S pNÐq|p½‘?®¾F'c”`Ê»<«NÚƒ¾òÃÙfŠ/ ‚'wJ-l‚Ü¡ý©°È‹{­'”·<"1öß%qÊ�FÓð;”Õß ï§÷òÃw¤"Éõ¦36‰ö:ž«®kxàä rµ® ïÛð”8‰;ûéÑ0½94ô²*Nt‹†ås¹ø¥)oï÷NJ)c˜ý4ô]Ëê+Ž ³­çðÆ†´)Æ…æ7ŽA7ÛVЯéº/k�麻á-õ³ø*©sÔŶe¡<Üi"gÙÞ¦ãJ”µï ¬\<›göÚ!.Ü«�ž·óÞL§·'`ri&<ÉOÃ÷ ÷Oܸ?8怜ëùX{"ý�`[óip®ê�‹o¼§Ýo]ÈyêÜê§å%0 ¥‹NŽ!ÿ>«Ÿ{zÑ ùBAxøÊ›ªSz.Àï+ãyÒ òšfLv¦3xà¤Óט F­[Yâ¦OGýryõïBzTbŒÓ­¶ñ^E%go“»õ,6,Üû7ªã…o'éÈÐ ÿú}^7æÍLpˆIC‡ðþ˜:®'Ë<ÙM£’ʨ1Y—“ìúÁ,�ƒüçÑcÎ7Ø!ÈŽ/a�åÊú¾œ�y,ÅŒ{r¤E›eÇð$_98ùÄϵ'às³-âWݰ]CFÖãð‰Ê¬¼(�{V§a¶¢")j«ÓO^t2¥ë¸þq ÂòEÂÒ¬4é\.ö¾~l<_ÑÃî'=²ŽO?è6N\H%‹_nÝ-üm»-.o9CO×îmvÄAïÌ[pur þì÷.ý:F½Ö#¦:erJp÷Árüh° –…£û¾\µiOÜžJOï‚fÉYØ|0�>8¤“�Ù@N1Õåq�ëà±W?ô•ã99op†† ·ŸŸÀi³Ù^Á,ÒF0Q‰fƒ!Õ0ÝÏŸ{é�cg8^ ÉlRGc—d8SL©e&U{>/·‘¡_R¾-€Û|;ú^[IÇr¯[=¿f ‰�›)îy5æ-çŽHeÎÏ|Èö•cùÍ»Z ±MÆ�}gÑ�×ÏDç^ò¢ýò©pzŒ±h¹ñ \ÈžËE^ÀA!-l{€"M1x´4'mñm*àYá|wx�vžÅ¥;êÅã�âù’{H†§èµ¬.ï|c…Q ƒ9cÀn8ÿp M=Lˆ¿ÝHiíÊlvH¶ÆaO9¦Åz ^/tQTì�ö>°û¨f!¿ÿUPÎÞOé©/Äeú èÖ”Š÷£®‘ÆîÜL“0yÄzn•øoÒƒYkÝ~vŒÑç2��’éêZ8(ß5r÷ïpð/ˆÛ† F×ö!•š«œhÅú!¸0ø©¨š÷îIŸ£�¾]tjÀX6'‹öÏ<sn«aS¯¤Áªî<îšM_vŸ.f‚m¦muú°&0Øp‹;KLøË  1زO-H™ päûaŽÊüÁ*îçéÇžBVt¹ q÷–ãÝ̬_pÊ \Ð××?ÞP-£8�ȇðǦ84ô8Hºò…yey±’¤O ê4<Í/Ë^QþçfØœúÔ'ð…Ð�¤«6—'Ü®þùu`Îwìîã„onƒÁ$gœ—ñÆ}=È~N‘lçA;öÚáѾÄé…IVŸ¯Gí®Jøí^Û_)@ÅÒJxa ‡¾¥¢ê«M8æ—Zd6 ·Ê‡qºÙ�ËÝÁF�f¼Ôs0ËšjaU–<ÏlîÅ›f(Ð>¥‡|ë¢ ¾ S…Á?g �ÈbÌaZbšFÂÌQüïÒƒ¨Rú\“�9[Œ .à4íÛ<â²j`Gü0|¬5›w ½Ä3ëj`Ú-| ¶Ž4g†[.©€Øæ�'-Q+žpNóTxSR‰Êªý!ìš ½pÄeîÒ°AÜ<< V-Í€O5GÈN§Ô6‘n”2ŽY³H4ú׳'裵Ù_TŸÅÕC‡q7î%ÿ¸ð±he¾<Õëy‚â­ÕÜcè%ú~S}æß hX&.²Ô`—æ>x}ü>Ñ?8}C;0HO�ã^�ö_@êÛY°k†lK5º”þåI;_…â*OsXÒf<29Œ›¤K±þ[ª?X‡©yc¹)¾ˆ¿NÎ ó&[8Ùÿ?òI¹Ò˜WNØß]Ž� ZŠ'ü†cÛÓtTkSÁZ§—⌀nAF ™*œÎ1bcµ�x«Üg[• ñ?‚±Ïð�¸LÕŽ GÉpßì ׃SZ{ÒÁ*mðkÄÿÖº›+*ÇÔ¸~J§Ÿöwép¬3¼Ÿ] ›|ì¡äž«FfCõøy<ÿ|�x[n>/›„}¢(ÐR�>üË€Åmö0èØ$º˜½SŸQâÔ§˜Ç§é‚¬><‹�Ï7¬>Ã*­}’o.ŽKi”*ÃEÅÃq‡Òx1/qã¸x]Ð%§¬ã¾ŠE\ò–JÂY5 N"ý϶€ÁCQ|�úÄXirˆ«žŒSÂöÚœQÛ ?þÍ’E8$! ûôÅ?axùÐ|¾Ð§�J¤:É u>ìNugãºel97GR2Ä’õ]"Ü®i 5\Û½O‚%žÄp GOS¢]úOD íq(Ÿï î§ÎWK6ÃÅÎÛá 5Îù£L·ë׋å7(øM*ûšHðLk9«–ìÇÎ×ÅÕ9·Qß;ƒ­í´ªÌu¥ cü œÖ4ÆÛpLè|~pU#3'ã vì•Q5qðãÞ5ò²èæ· LÖ§ñþ³Ïª“•­Å{™i¸¼·¿¾�•�&Ø{Ýw*Y?Š®�¬ =WÑ‹>^<âTpGòx~VrNðT×A‹.\jn€™Iµ``c‡1£þ�Õ¹Öa¤î¨¢Ù}F Õ[÷‹›<ŸP»Ù'j›cR}kl–éôĈǶôá¦Ë/À§OQ½¶/Öç´ [ˆƒv”Ãï€Þ#—�ß�„ kÏÁâaöÜž‘s®íá굕�»W„àFG¼z¢fÕÙ±í÷5âÌa»ù90{�×6j¡÷¡Dþ±r01Œ·ªï¢“iô*ç†*�ãõ÷iç¾×`ï#Us¼Væô¹Foý¯‰UÇñô[?cZÉæu„¨;¡×Ci¼º}*]øZK3?M«’s´Yï.¸þ×g¢‚¡>&¦ø®§µ=ÍÑwKÆ�,æ×ï´à�n4^w΢YIT¼£�2¦`û‹Ûô7I],—à«—yâ5ö¬?ÄÝ=Û%«$œ¼í/5¼Wà¼Íñ|F_ {ö—Á¿Ó´@=�¹°WÔêÌâ^5•PîF2'—sÃÕY,m_JñwfŠŸ=gòš œ6úu¨é³¢wCµô3t-��ö+ÙJ’Í9sÕØòd(ZgƒõºfØšþ‘6£ )·RýÔþü¹*”UÀ,è£�¾á=«lÉßæ¢ãî¸)Ì îØ/†Â´VQ±t¶P¹žàIý~sý͆¶\•/]‡´!Öc/ª¶KqLýJnzVXÕç ï7žÌ&!¬–¼.«r�z&??:‰wîÝK»—µ�ÕNuìcx·�²f]ýaüÌë­0PÄ¡BOlQTÅìG7Íþ¨½â;Ìú ëḣÏá�u\7V¤o »iÙÏ0n´9eõú³{/má–ô»ân«Y8ˇ@ýàrÔ’9N¯Î[å8a{¬9HàôXUÊ2SÀø%©0õÓz/o õŸÆbtG [äGTÛ+gá“=s(Ùx7~±7À³Kû y㼜¦ÂZæ@&ÔR´ûWè¬?EõÛ×ý»¯DtÕL†Õî/h‰Åð›¥Kogú ¶{–PsD¦fõ!5ýصZO€´Ñj\¤ó�ìà™A|;2•æÍÇÞÃeð»E=$Ô0µ~˜BOúò¬¦2É…¡ÏiÔ�Döx8XÌ™3­ëͪ“[³±(ì0è._ΛöÛ¯éèm ñ͵^xUÑ z; æ1‹Paroü¶{oÊžÀ™›}pì…pì[½�–u�ÃÞÅÊL«0¡TnákÑ2µ“tþÜ¢é½,à⩞à¸�[Î&±aÒwüµ4<`ϧDÚivWt½"�ã Nã‹„žüø­3Ö2­“8A7[ºlxº¦3eLÑÀ+k޲ç&úÔgûÙMÅi[ß åF§i땾,˜z°jwÿÆn’éòÅÓVÏÔFbÉ  2[ôÎŒK&HwGïŇyóáоæH?·º’'CoÒ±ItÞ µ�¨È=’®UÄàÞ§+%–ù0+`9Zo§­c� ‚¶<}4ÜË}-‹1rÐqA}g8GùHQ‡Æ[hµI¡s§†Cõ:5!¿²˜µEhËÝÄÖ’”¾2õ­¤¸æô:¬ A7CM.=ÔAæ×j¬ÖÍ›€ûá]£'�3A5ÖáÖÌ Tp�‚uwþ°ÊúÝðå_÷{¨–»Ü€FÝÈ(ÛI·ûÕòÓÍüÒÿŸå«Ø³¨Ahp��Ùã57––ÐU?t^= +Ç¿fØWЧZC`Cϰ‰ÕÎÆ‡°òö(>7ð&„Øíäq·†ãd2Dù‡zt¢R‰.õŽDµÂé¸ð@…dq[*ßsíÀ«É�d¾F…ו@»çI´¼Ì¥Áî¨wºb¥&ðM'Þ+>ª.³ëÃúåò´Gmx•ËÖXhÞ„³Kª„káê‚\1@L� ¹æžÞ$>2Ñ�û°Ýª³¢´æžšgÂ9«Ó¶�½ùç„%¬æ´@ìWâÃK󦂇®)ߌ î¹#ÈÂø _ —Á�¡‘|e·kûnŒÏE\‰e·k'0ï’ÌÞ]èàìEJZC™s4AÿÊlíc…×>ÔpÏâ^l­„Û‡ÓÊ £8Ù¡‚Vmk¤*µ4öø/·j�yS±Î{}K?-d ÌÊ4pDâB1¼Ü”æZ�­¹°  ¬g,ÇÎÖɼ>mé\Í"™TMr[–AÖ#MÙâ§1Nòˆƒî ×ÄŽOnä‘3‡Ëghò�Q6°zÞÒêY‡ý¨¿¶¯m¶¨.ýy™¤õûÂ’_áÜ4x?›øj²MÏ>�êÓSœwòíA~—«/¶þu£¯�!t¯<æÙoåÞöÒ“ÊÌ/S^�ñ8µçaŒœÈ™E£ÅAVâð³†Ü¹ò ¹ßÀW‡â ¯+T„™|p“9„š,ŒÜ> Þf3¸åq kLÈ Á‡_�­³çâ^UWr…™è½ß€S¤œ8í¶"´ÜÍ]Z»àh¢=˜wÁüŸCÐ;ËœùC9øgàO©ýB]E?Ô<%�ƒyþ5>;ì!¤¯Þ+Üu_‚9�¹“:§½ep. ÃÍlj.{ï �æoÁiÖ~²×ýF/´Æ‘Þ¢¾¸óâJÌø�#ìñUÓ Úv"ÏE~–L¿ò äÿ,„ºûy<¥ö56nž.þš°ˆ}v³7<óBܰí�,þ­ÚÿD.ªï¸‚›7ÀäÁRl,•Ž—OìÀ}ouùçK9®ç¥p=u«dQA,{<Û-¦n:Âm�xÅz?oükDSnR7rwôZ6þƒà–›‰±©)ø7² þ˜ã]�¿ä©kÀ%¡ý¹ùÙNaÎÐ]8«¨7 ½g„‰4�äk^,³áÒ}³Äuiç81s>ÔüÖä{ÞY¢×•o¼üL=K�¿’ážtØ»y5¨oÊ£9özX=2¢Ì›À^¥&?ª’o:!e–Hº¦[ò©� ð{[“è‘Ò-n™¯N_”Çñï¡'áÁ)aSu3¾{Kw¤vãâÒŽ+ø×û¯x’ñIÜ·y%¼Ï«‡ê÷>øÁÈ¿*Ìà°ÏÙìþÇ‹ô‰6¿DÜ œžwì´£àabLVl€»Þ<%“èТ:ä³UÖ¹àOí§âdÓ 8YšxÔCþò2—¬ŸŠÐ[e šl‘æ½/â4ƒ¸o� ²vgè}c.Ü=ØŸ¼”ùàšÞlûë%…ý.àÉÆ§Ög³ìæ`~hãˆ]m«XÚõªàÖ<^7�,�—ÿ*óªùÃhàÓ±Ø^œ=1åÒq~ë醚G*`�íe>ôì¥äŠÿ òµ4©Ôè.�ŸÇÖIšø{±,ܯæâ•\è÷^IYâ&,%ï‚\qûmhµà+zó©¿Q0:T–U[C©àëmØ.]Lɦ Ø»3ªÏ>¤)C]yè°…hq„]ZË¡YMGÇÝáÃ]QâBß`áá̼gÊϕΠéa+y®ëqAKS™C—çÓ1ù¼íW ðäGi´ÒsÄI9+ùcÇòÕ5g�¹ÁÂOUw¶OsÀ+ûŽaî´øåFòmà�3•x½B¼°>Såü´ùAX ¦çµ GåYG±?Vå9AÚ`kœ)5 V�î¢}ôÅu:ågËsüÑ]à½;}&£¶ß�²é€±—{£gÈgØê-^Ï4û™”þÿ¿™½Å‚õ”§›dyB½)5eä@áâO¤+õ€çHsÛÃs¨rO ûø£¡¢>'êW×qÑ´°jO¼xZ wØ‚û) lØ0Sô÷0:x: ++Yb¸ [n$Ó{AŽ’slùbáeÒÛ"Ń–ó‘¼p–Vêààà_´È2 Òd A›¶â³»ªº4xQÄBtí¼ã› µ¶WaˆÃÛÙqA_±ôïv:ôx¢�°qŸxÏ�{‹Qûm‡þ,ÎÞ Aò”ÕÇïO“¶éqŒôÊ#Ò å/ 88ã ÝWAénûðÓÉO�ýßWÑc‚LXk‡‡¸ñÄ7Ý$ŒO†W—*±´é°¨<ÂŽ,€WnD€¼Ž/¿°L¤ ÑÖÕEGæá±²\öó5âÅ)óiEß7â—‘=¸£Í�¬O×—äèðV�bZw€¿:– J‹õà·í q/Öû&òˆ ‡Ä©C`¾[·e˜¢³Ÿ½°SLü�oÜ*paXôŒù�¦•Fò]EAHHH¦ùþýA(ZÏWúÙ’]Xõ›eCK^Iáý­©T^š/©ï(‡K�WøÓzŠUžDÏŠ¥ Îp=V˜åUÏ`X â~� þ|q�fó/ ºrØŽgõóÅwc¥@GcNý2®^œŠf5ÑGQžõ~A­sÏÑj�CÕŠ66 ìèÉ?ÏØðí¶5Ó›ã× GÜÞ˜ƒWäà=‡Þ5ÖÎ<¯ýÔÆ-Å›zêlõ_žh¼5Ì2½©ðñòÙ'<ŠØu¡:¦ÝUùÖßð¦ßrᤓ?> ˜O%ƒ™Òª˜m‹^��ª/>ž 3¥†àÒž&¨ó¤˜æ$3Ôn€�£—ñ5»~“î›( v´;ïaŽÒ¹OŸT‡â˸aàÄyÂÆõʬ²ú˜8JKrÏ•B¥ò}pµ7Ñ[™—üí�9höGŸâÓ°P©ˆúÞi=Fþ�š…W•sÒ)˜³l.¤ß„N�]x[€6;L\Áfû5³ÎÃó<9òÜŸFíNÁ¡;¾÷ù—«ùQº¸­_+… ¹izì½ù½¾?œ›}Ó°éÓ*TÞÃZiïPnn8ÿŠm×ÕøõâáÕÒ_l…Ñ?ÆòÆeS9rh(ܯϤœ~�Ø/R�ξŽ£ñuÔG"Ås-ÿâ¢9ªÎû “›GããþÓÉõïspZlŒv)‹é?Ëþü4I•�#ÔhðÜ··I…ú‰˜»·'ê;\£a­f5Çëyñ±ˆNzÓ#Näç³KÚ¼Y.Ï÷Ž¢-IÍ œÙïàôÉœe&‡Á·øÜ¸}xF¼À;zÒ®õá7ºL¯¥Í/ǰÏÖ~à1Ï åÓº„SÓþ º’·°wkŽªtâ —”Ø+Mý9=þ$9-íANéïé/¯âÄar›3/Ô0ã.w„×oô8úÚQºp*CØY_N[H>újm/<4—#'‹|zTtÝ+†™qtO§[rüy»è¦Ê:›e¸¬G5´¡Vé3ÈŠ8#ž½îÈZG—As{(ù¨ÚÎ�ËÛweS‡Œº�¹…mt9s †~µ¡!OyhêOªIo]Ëû4fß0þp+FTóOf}© Ã2ˆf®Á›Çb`FÝX‰×O¬Ò óÃÒûñ»Æ2 �×[aøŠ8²u,,Q^Èè3€æôKáø è8þeéž$óâï0{™,_zuU8®½ŸðÅ!�½ÅÏålXáu%\òØÇÏ®ùB¤i»Fƒ¾ ¬lÛ¯ 5æƒq·Ãf^8¯�zôùÀEá›Ä¹Ãva]íiaéÕ&¡ªòdjGS³�]oë�Çý?‚Ί·ÔøÊ« õÄw‹[hüùUpgœ;kF•ÒØÆOð°©L�6;ŒÑ½Æ2¸FsáSäµßJÐæù“ê›ÓÝx©û5þ}*Ï|ÆT;y¼ƒkõH»t1Q§·kƒ§Üpœ9[P¿¿…”Û̱Ã/è,í�M¿2ðíÞvðNœ@ÿÉHS�Ë�¤jøÌ�Â7î#Y§ŸH±ÖÜ ÷vÜÍ@ÝôÙXîŽò9N¸SúT…Å/C+Ñi^º´´pÞÓœmpZóê9Ò2rÖ©²Åò$Hð°eÿqÏ1Nð†AžÁt/5ÔP,¡5×TÄÞR ë¶:àY”Ø$.{ò/ã‡yƒk¦¬PX•=‚× 2½/ÓåÙ&¸¸ý)lP» mr/qé ܯ¸ãÑ”0È–Êj¡(¿1œx¸¢:wnÝx�¨Ü:€º·Ùà•,Cäv5ÎÉ´?ÓëNöã!®U†½“¦ùkÎbÃì>i¦„æ mpAÚF@>›…ù/& ݃€K¬BáÅ‹§BÿÓ®ðÂëŸi“§á×rušÕ³‡·fÒM—ÜVÃêÅ—ÕÜuo«ªKaGÿµX>­šåæ:ãáîYìãxŠì‹ä 9sðCÈ<²ð™5÷AʼnÛ)öŒ*íù¨MÚcÅ@ûCÔµ¾Q¨µéâ©7åpЧ7½uF_ƒËw‘ÆIgtNÙ ~­OÄ ÊïadÑœìrPR9ô…˜Q#�&«‹qÎ^CL6÷ÂÒ‘:¸^w„Þ�ð†Ú”êðä�ì¿mõ{>Š�–~µºÛ�.jê[ð.“-tëÂmê­¾“Ú•¡ë—"Ê£Å#vÓÃç+p¢�;ëì@óå·)2þ+D¿I‚]‡hÃc¤N­Ÿ�¼u5V[�7ô°S'_iÝL%Å#Lœðlø6ô�‰…JÈ„¢yyàD9xcü[èùAY\¢_B*ÛcDx¬ÌGåeøÒÄ8Øÿå7í²7a·�5•Û_\sšFIdy³‚ ^îTFûíZØbkÆáe <¾G!ß&�¼ñX\.‰&�%)ô.¡^ØÛ:·¶4SrûÎL�K¾¾\nƒu{bFôwXù(‡�ž:&ªí‡F|> 'ïZqdàv¡z8vÕHÀ@/ºó>î]ÝŽ«XÛ^ÎÿF‚édä›á»)àæ>±a…]5ÈŸE�™µpW­˜ÛZvsÌž µ±óbŽ€_ho¡Wµ9à_èΖe¥›9|i´¼ŠÁ †íT³S²¹Â  ´â¸ë]ƒt4—ÅQÚ¨“n@óŠ~1³QœlŒF7'wPœ½X¯DäB’¦"\\� ºÍÈpÊ,,[Á vê°™oAuˆåÚ™íËbMOl«ZB—kgáÚoÃ8&1ƒÛÆ‚]×>¾–`‹‹™�û¢\bßE0"ª•<†,gýq%˜“yzÐe<‘)XFëâ³9¨Z1� eâÞVì0I }Íîã·]÷é\yJ?ÉR¿‘¤F&ñKiQ0]_JñÞgñÖ¦)¼U)7ß.Cßž^ÂãIìaQÇú;R 2þø�0aýB¨3Uæ´Ãª<+g7hqæ[ß¿Ãaƒ&¸b–ÏWçÃ7É+ø­Å ÎP—½7”6¾¢ê÷{Øîõ ‹.c£œýÜ�¡„GŒâyVä Xóc7õ :€Û~6ãä_ü<.¿Ä-‚W?Wñâ3:¨¿êOMñCqƒ¹øËä:ÝaÅ•1Õö3³Ïö ÒüÔΚ?öAW‡3÷ÕµÀ¼Ý¯ÄÞ©Ö^ «Z©ÃÏ„ÇÈòÓ�¯…†¿Cù`ßGBveÔ˜Š ÊÞ¨jt låt‹2a¦Mž$Y=S¼ä¬>TŒßðõi¢y¬Ëö[ ;Æ`Ác;*�7Fß·½±3¥sqÁnŽ/ü™ˆM*T�Àg§Í¦T§;^ ?d3¡üb¨¯´Æ–Â:šj¥Ä‘'>‹cÝîY†×{NäðH[œ8üš Ø,CSôãxÌ€ ì7œ!¢ýþ �â®Z²µ¯Ã…“Ær{íTT‰WÅ�+„™J“Ì ž¢uÜ<˜Q’Wmö·ßäJ8#;…O} ƒµ{ï ·`ýŸÈR/Á§4ÞdlˆöÃtxJ]ªÐvضś@ç})|Òu™ên Ûî¹8æ§*K2sP+,O´J¾Ëû®wÓeCîlœ�e÷ð-íì1v|`‡u´£f Û6ó€UªlYЛ…®�bÈñR~;�ËJvÑ´)7éé‰gМä…Ç^áó²6(©8‚†½ŸCû�14Y}8œU‹áu;>‰ßUƒøäŠtÒ}.œ©×âWIËxô_Kú¯¨�羞…’XU´¿˜!̸_Œ*9Éœÿèªw©à†÷Ö$^ì[ÖÀ�F]<­‰Ù{øo!ó«ÜDº{œû¢¬Q,ì}�êRq˜ò²38£ßKÑÐ;s°z­€Õ†{Ñ%f›Ø6ÿ 7WÁÙ±Óx\ÿ÷œñÊ„.|O~µ+hõݼÀ®›y}—llÌ�zûE¦@ê¨*Æ>[hgMÍÿ2¿û­TMûŒÙ쥯Å׎7ð‰£+°èœ›øu°ÀZ‹(Íu &…” íÑGij£u¨tA>ž7^ÿ¬0ò©<6LÊàw�=jr#7rT¿ ˜vy7ŽIhJ/™ñ Ýa“âeÞˆggÿa… ~­$M¡á¸ù•°dÅ)\«½ û=Š$MÐæ�£¤ öbk¥š’Îú»Ï…+Âñ� ¾îþFòák"¾Yv•4›äQ¯A…�ïWqJZõŸCÑÜsQ1ei\þ¬‹¾c/ÓT§obߪ'l4åb48uÂcÈn‰‚º?'Bo :Oûa•=Pwá®hÃn¥‹øôEâÎ]©¼’ÍqöÛûSŠIù>Â�/ƒ ¶ÓK8¤a.JÔo€©n”ððä¶ýíÌ—B’ÉâãUÖTk¨v3itËz\©2–ÆŠük| êÛÑó¯k¡¥æÞƒ8çñ@ú�º çžHÂË œhè™Ç0Hÿ$Hôò�Ц¿Ùýµ9ú¼Í ãZÝBï”5œ²:• �|)bÅ1ÿb,xvãeÒìÌc$ûNƒ÷tÓ�§´²d9ƒ©®^ ÄiºCØó^_ZØ'ƒ6ͤ|™£ÂÔä%°¶RŠ�Dœ.9§Ó¤wØ3×m, )ôVçŸ9*s˜Ì2·ì„Å3_r«ã%¾oPEK çñu$›zH4’›ÀÇró9Oo ÎnPà³ÃÓiêµq+…½õ£‡9q¼'Û“•¿&²Ì™~¸jìtiv–×$¢Õçüáu�pÇùIú4¼14ß-´äŒ³‡ÄçÛAŸ>8¯Â’5Á{»ñÐé´×En:368®äºåµüuËlV)Žƒ±3qÞÜ(®1ƒ ùb• üºÒÎßB¿óí–2:w|:Úøwþ³\ Í©…~7;@I2ŽõþXò¤¸ÁÐz9‡¼_†çî^ÂþCiOH$ Ñ®pìcˆ½˜¾ìÊÀ«ê†\3å�Õá©™äyûl·+F;ƒÉ¬²Iþk æ˜ó‰”ñéˆ8]ǃ®Ê¯zþ³ÓO+¦f{.Rj£þW¹ø“žßy&¶ BÛ/ÈAM*ì·ç <‰wD¥í8·à&ÎOñG6·Û°bDÝ ô5(äò¥–|­©/¿ß–€ŒrªmÏçWI­ï¢î«Atun9Ç|q¥—¥û¡Å6U¤ óXÙ&C¯kãŒ:)a@ÝGÀÐÝÙ ¿C2°3ŠYç’9œªºñY•~LÜ Y%·ÁÙN¬göÇå¡’¦c¡ÒkÄY áÍR"›?ʱdj„…Vh|] ?Ö¾€¢Š8”)Rf/ñ2xõÍGûΠwŠgßgᦼ#Õ&ê鯾T^4aQ‚+ÇŒGãmaÂçdWô|w”|U®Àcë>|¯8Œ·Z§ñÄ�¥X~o [ÄɺsÑ^fpÕ�Ê þIrü½î&Ι�+Ø2I«Ã¯;O†jŸ¥ ûX>ðü;¹§œ æÁ_¡;†[ß(©¾§J£|ËAÃ}¤Ì ÝÉt=NÕR|Øö` y>PæÌsáÓXœÿÖJùR¹ä'¤®ûˆ™. p«ø¤$ú§:÷IzBÉ(?©#=U�~½œ~&”µƒ^k xвbÁñòjòMÕÄ®�ùK:…~½øOk]ÅÖZŽxnÓ ¼R–HêCp0þÆeíòü»wT´Ùñ‡ØJâp¾w?œ4a%�üÔ-ÔŽÈ�ײ´\óªØ¾ääk¨Ÿœ*®»ƒus7´ó¯1äŸCRÊ7±r}æ¦.´=Jlöø0·üUš³ž7r€i6YÆÜ¤»#œPˆÃ.å€}….´<ÙÉ*s•‰’Nƒß=щ"¬þþë€.dÃòS´±ÙL„‡w‹¾¬±ö ø„�r·Ð…Ì—ä!÷Ä‹¨œ>Žr”É”{ðä„�cþÒ”ñÝ*Y\ÛÝ.Œ:¸“-&ŽoÅU;-„9#§‚`hÃÿ9Ióòj^õë�Oáðý‰HBòBÜo¼’ïæbTÀ†ÑçØiíQöò_Þµì:Eʦ`çý(á€L 8ÍF¿LÃðïE¿£ê0ÍvHûñWÒƒ£·KN¾½Ž3–Û¡î136Óm&½é;ùÆÄ웘ŒÞ-ÿQ߆œ�xlseðóÄ"Jž¸“ý}J)éD1ßzè„zãp^ó:m�*ªL—™ôÓ®�ó‚äð÷–TPÛ�-;31öïCP=úAøjX…2ûjaJ¢-ÍX:Cx¿-f>†œßÿräå_X_·Køf¬Ïo®m×ß.’ö# 8°:¥Ojà± Õ¼5« åMÆ´-!t!°w�ÛŒy|£»—¤wàp˜ÑH!5><ºä¾|]ZÝÿËjxaà‰ãÉŸLÞ�¢�šÊÜSÛ•/œx]"žªnÖ>™Œ‹kVát‡|Ú «€ñ%«éõçPµÌÇoXE3möá/éÓ¸Tí¸ìÿ¼¾‡1u±Åo³¤sºL>¡ÌYëuÅù5Ñ´Pï=ºg*¢�·/Ùx­ç³‹âHµ±•ÏN à+Ò©��‚ ó•å¹â¥¡—qZ¾ôã2(ÿxT|X´^6p�-ç~{·ÏdÒ�ËÛ%Ù=#`BDM®{Ì“*Ž�k„"O ƒn\Åqo’¿”},9¶ŒM¿ƒ1ŽñٔϠdt‹Œ'¿ç�køÓ®DÉ3§-üiÚ.Vß©�%/p®Nÿô�Ǽ·Ïé`þFÔ5\ˆfçNS�y7é²énöÓ¼ÁӞΥ´}9i ?ŒDHÓt‚kϳªÕwÙãÏ(~ta3®•»ˆ;ûcžâV«Ø£­8¤ù,Œ¸ù>_-�ÿþlçWG«À:Ú†ƒªª­ ‹xãÖáü]zyÌA^„cìí¿´ây¾èyÕŠ-š4qnÃhÓðFt½SJZ+ßJüÒí1p�1v^L—ºÐiÿzØü'ZŸ;Æý ¡D?­Jzè —Ò ½Î9br´l‹g‰±%/Ú�Š?Tþ]Ë‚€�½x“×wþÕ«]Rð#oÎ¥C¥¢ø9Ì{¥[ñÒ¨3ÝžW<eÛ°iÔç`¬ø_›£(eÖV9ÝÞ™¯™V`B‰jel냷èÙÔ£´àé-’ŽI‡sëaÂøßÐs­=íW¦UeØ{÷YŽñ߉£Ç·P�n&Çmk CŽÁ¬òóô5û'Ûö‰¥†gIŽÞH¶Þ¸‡„Ü áØµÞ‡­A0G¥<%>âÙÃ3ÙÕ§‹N•iÁlÿ‰øm«<«¾táÛ#ejŒöm¤×ßákœ/%9ŸåÿPK-!¿Äý’ÿÿÿÿÿÿÿÿ arr_1.npy€Pˆíœ—é?—ïÓÆ e%Kˆ•¥‰Ï5©´k/-¤"iQY¢U¡Ù ÉiQ*\3•Ò"´j_I©”RR´Üßß¿pϳs^ç£yÍÇñN˜1oúLWi©@©­¦+=ýVl2µ74¼¬MÍ M½|7ùoòXïî»i¥çÿú=Öúyþ×÷óöØàùß{ÈsC«#­‡šn7ü•bä>[h٘˚а}$áa!*Äd³ü0Oö´ŸÎ¯™ÎiG#0QË Cœ„3w$ø<¹MH«ýM¶§òèönÀO7ã±eQ0Í�_¾¬W «TމãßÂÏÓ­•îtºº÷_û�Ôuæ‚ʹo4œýèMÏ~¸úˆ-Èœ¢a¡T>)\°8¬Ëw†öÀï=½°ûñ)lZ\ÀõûwagÜRlj­¦"ç•´M”>?36û+@Tælìã�I—ØwÓ>U GÍ1Æ|TgzU‡¢Žö,^÷I–âXV¸²„�×�¦ºtaä ïpiT �0LDe¹ Hv:ÆÂ²ܱï;¼ûw’¥fGÒÛo~˜uÒ�7DüÁçÙ¦Ô×£^|¡Ýæ|œTYìŠC^ÄrLÿ§tàŸ1ûÿpA©uýXuQ »ýŽ‚÷¬ú,�-ߣٰ͸aŸ'4tåÐâ�ò8Vz~» ÓÞIãEC{!æýxV¶uÅ$¥áØW¾W]Q¥ˆ7’ÐÌÔ'®”+÷Ú« gì)áĦ»´àɪ»ž…å]°¥Ÿ?ûõ å I‰n}:ƒs¸ÿÎ>cfÕCaÉGH™*à­â‰Ôsþ~ìi– ?wŸ“œ.8EýÖYó ¯ÕööMŽÉ�ëíälW‰îctƾŸá.fl¹Eí'oAQ™*o�Ÿ‡WËBañíQðK.´|Ú++v^ûð{’ÔIO¹0Ò—få¹â¡9׃ž³ À¶E¬4� uU…¢µÌAäe1•�sKI'ê³ µÝ‰�ÚNãî ¨Bû(GtÆSËD96·ß!:×Sì¹�djëO³ß.â;;_s�ÙSA\æÂŽá�èdc1ɵ:Ø_]O)ƒþúÕØi9¬r_rÆ)GžÞÞAóÖ*b¶ì.î}œä~ŽäÊ×w°XCæÕÝç™×†±ÆŠf‰AB½hýy.vMý%nk®c�ÆM8L÷ L�§Š£É(ã¼Ûï ú£c“F!ËÏí¢ý>’¾žOYxžF ¹Éà ð·Øñ}fåꀾŒ£ýP¥_«$f®î<û�t֣ƯHQxåÎÕáAt¦�1¿›²ç'Ÿj¤!¿rbE»–SŠDqª49}œÈ»Ç• #Ï>1 þöO‡k€U_ÿ£¹“ùÁÄðu‘-¹æôÇWrÅxÒs]±^8Ú!ÇÕ·†‘‹œ ¬IÉÉ–{; õª?ó ¿Ïdð±Lrä™ GeÁZ÷"|’zî”?'Ó@-^ós#«E�‡ )õt%º’]Æéó¯SOPëe ]4n¢ÖÂÞ|èÛZ\«ª 7ap¯pú6Ë…£ß6ñŽÚ8Õï é�§ÏŒJ—òòo(â�-«ìV…mà—ö��z`Ž:ëúaQ×X¾hü²«ŽáÃÁù�”ØFÃÛ 9<2—ÍûðoÇRZ“ù�îÕ†³ÁB9 —¦ÖËÁøPÑoÍï�z�Ýàš¼•?L å.Ç?´Ïé¾ägÿQ|°¥^ÖHãÕ× $ùOe„€¦xæE%¼þ¹”?ELféËÃAk÷Z|‘VD%ù÷I³>U\ 2 ð8‚ç´¾£k—s¦Q)­�£‚cÚ‹if²›¦ñÊGÖl\Z#”uôÅS�oˆÖîﺈn7ñƒWˆjÞ¿Ö2ñ·‡i+ˆºN“�´%~[³G/à¸C ¹‰^†Û¢àß>À1K‹á‡ì*Œ…äÙ`\,Û28¦A´¹î¤•(å7 ‡· Øó­¥PåŒ%›ùÏñô§=¿­œVŸ+­ÈS4ÂTmp„á8Þņ8wn(W«ø³ùß:Ú?&þj†þ(ùqÚ#ïõÇfyúðê->6]†þÓEšÖ]AiÁ^Øþ¬Nrúœ ›^õ ˜ñF˜Y2\¬ÛçƒûåÒ+åÀtqÊ�1sM,çÝýÖñæx)~†¿ˆÖ‡òÛΉåK>Y�Æ‹vŽòç §´ðzG2Oø=”Ÿv…Ã峿ü°ÿP^£†áZÍp»ßeAО*f.?Žwãok&$�EÒ2¶[e‚²3ßÑŠ��‡V)RdßôÆ`ck´+]èk•@m•óyö°HðHËkÛ"ÑoßÔ¤4v[Ð@|æ‡÷OÇM.ÚÖ YãKÉfö× WÝwÍŽ ÄרÇUš$]‰úg†²®éQ~†&_êQ²Ù•1#BqEQ8˜DÖ¡ÞíB„á驱¯ÐÈ;½€ÞÐ\Ü;mÇ÷ÔãÇYXúÌÇ}…¢ë˜{ðz�¿øúòÍÊhVÃ( ;mÞ½R §{¥/‰:¦EÁü_¯ù˜õ+x#•OG§¬Æ€[žP’ÓŠÕ_3y­s¢¸Ú0�– ÜážÂÆ_ÖTÞwöd…ߟ±Ãû"®± ÂC�(ÅÎô:5S³ßeÁÄiâ�VÏ›šðëË®©€_ýÁY·7‡Øâ@³o4C}^ðž~ Ùá_Ñu¢=ÞÑõÃ͇>�Ûô&øó6YoÓ&¡øêÄ>-�в|pÈDœòã'¬——4�àò…¦.û)ÔñÆ}šé˜| nužˆ> è�îdØ;̱âveâH‚›ë”AwÐIw%ì~{kod¡v¸ýÔÚOä†éß@jö=êã�'Ý<˜uýqèÍ‹ð¸m+=u äžéЙ Á¬åè¾Â]&¨äÄ•è3Ò–ŒqÀìíºXyHžç&îçù#NáêÓ0Te/zߺ)ìÖä^í¥ôÞ`K¥?ƒÄÆZº[øRˆÉxENÒíÔ?=•eïìáër«hk[©Y©a²ñiA³þmV�!—YTýMØzñömŠžúþ’þq�â?—#üû]'Õ¡ò\ ¶uMáu?ÆóÈðpŒzÝ yáO˜Ä–Ë)÷Òn¬¿ ûÌOòû–øð§«gUˆ™eô¡é0*Ý4â£2T¢"¬”WáÊÂ]¸ #4dŽb~‰Ü_ÎÚ½bì½l3ÅÀåÔïmUÈÀ«¾s8ÿß8Zi%Q–5†8ÇÀË’�¤?ç]eŸë=p>`½âeè±±öh�gcÝ´âÄv>˜¤Š/LØ®1Nœ£>ÝšœH3ψŸ‹ßàÛñaÕ›…¼÷žÕy#�»¥Ms;àÕhevÃ}xÈ݈õfG@ŸÝЧ÷l¹�oJÀï¾�4\Á˜ûæÔr¾<ò¨†!úÇhÔí<ï­ÞÐL·+4qÌ_zê¨þZ vJ²œxä»Äìz$lpã¦!Öô&x7¸®ŸÇÛäÐÚ#ú¬«… .òÐïô>Љ_‹³BÅÒƒE ôGwÎy N½ùL¬õèÏ+�¢cÝHXéÕ�Í…¯Ö§xü…™ Óf‹A°ýŸî¦VûÐ6¯ NY£�·¤ÞQ|€êì‹£q…½tÐì肎 Üñr²äïò›ðs|zÆÒÖ¬ûðgžz›Ù ߢL¿°3e?þøFp<&öx�‹Có¦!‡ù½F6.ºúìʇÀ ûaQL4õ -冯—pxõHñÛ˜l^›W;LñŠŒž y/ø¬>G¹§“¹_z˜0ÚÉ ÌÍ¡°L{ìÙ»µþF }#yÉ…>¼z…[ê :Êò…C0éï”y|»×��öÒ—£»qÕKcþ-ñ…Ùû±^¦7—¦ÍG�ÁýÄ/Ót›GMþÜ\y®ˆN*¢Vz.|¤@µù9¼³X òkúâˆïWÈuà-qC|Ÿ™8¯#.qÄ�lnÀh"ßG6§”Àz—åY⥋ŠñpsÏ—ŠÃ‘];8íc4î:dŒ £¸OË;¸)öª•vŸ,õ¨\ó׃îxßd³:’!G݆SСݙ’ ááZ”_3‡äïr'7ˆƒVŽ.`)}�iÍ [tqËû0›³…³=Fð…­#àÚ‘T.”mãWVöpV9’ûVÉ`^åAêÜmÍ…ÙcÙϿʞ¯ŒO‰ä³/ûpàé—´¼ûäšœ&³íÏÅ·®Šèù¸/›†Ì"ôþ·‹ï¨È"ûoá_J)»ï\Ü0èj�N›½¾Ò�´Í°äa[yIÅPu â3‘„wU·…5`3!éZÎE£ü{¹ãF¸6_†&üÑgåEðjd‚кZ‡ÒqpÊ;K§ÎÁòà ¶X[‹e òÿq–WŠp ǃYÚ&<ìÖ…c§y?šÂ„Ýu¹¬o±ž>ç÷Õ8GîuPü,ðÜJ,±9IŠ2«°z|Qe,4‰s_—“ô±7ÔtÀ�³ Ãm“fxþG‡©erUô`²H� r'^³^Õ4ˆ�K½180¦––µ¥QéÕ4jåx¬¤+¥7­âo}¦{[dXcê@p}øSø´3�¢fÐùNòY†Y ×°úp_xØ69�ä7d?-”±Þ*þ¡7ÍøJŸnèšz€¤ ÈÃp¦˜3`/3nI™!8_êM ±hñ¦OµÇ�ù«èsh8ö6)GãeÃ0»×y Ø+Ío‡Î†„¸›¼$ê#L|™ŒºJFX³ì�,j£ÖŸ¦hø³2ÔÜ%#.%áSå_â�()Þ��Lâî*zw{$kÜpÀ’â$庢ò±³×=WÆã•¸ÿ–Pø¢kŽZ? 9sd`Lð{Z5ý•½ � ½9zC:N^Ígüû€—|*}eDö fÒ‹[÷áðb1Ã^ FùáµÂxÞj!¶k�c÷¸jŽjªä´a)4åŽ'¿x¸—÷~õá…ŸG q˜<�ßÃM„)Ѿx¯á>íå†ãGÖUzÝ‘c�ÑÍ‚ÂòHóéMç,ýQõölAÍ0Fb½ý0=¹ïR|©²ÙËð-Ö„í§ýÓàðÐ1X·=ã{‡£û*+N.µ®L¼WˆðW¸óI—´åüÀ3í‹düü*ìxÎsG¿£ »¸:9ËÖ&‘úÃh~;ù8é“: Gª+_ÍÎŵϵ`–rôð~ ,…K4ÐuOڥͬl{<ÅæY «ý]l›;{lžLÁûÛ(z@!L¾SO³½÷Ó½†�˜5‹ÆÔøàú;zb–öèÓ2‹zG‰¥†_vïqaíS ùyÙ^JJƒ7¿¹�Y—rK”5ÛõzŒ&oO@ÛÝdš†“¹î~ ^ÎÕ c÷ÎH¦�˜Huóðòó <µÃ?º«ò„ånTúÓ�:Ïã j¼¾*†õÂðá&öUI¾´}ËiûÌ-…ü]Î ÿJ‡,§±hx(TšÒÅÉYÇQ:v#7DÓ 7învåêú¥Â¯Ç¥pðÚ?A^ï$æn™�W�ìh“‚?Ÿ]kËW�ž-1Ãç ðØŽ5cÁè¿9¯‡ªš©X9/•jÔB =q 6­¦ÒÛΡ|Ú/¯?¿¤Æöç¾}Pù‡š¶�°ó�èÜâo0=PÇÞpÇ•¯×ò¢Ø5œ0‡tûîcÍwebÿ¦K½¼¹0¨ �Æ„t“z�<&ž¸L{ý' °î Ùéíê3…¤�AôùÇ|m�·•\!RµL°Áá�òéú# ­t^˜×Sš>†¤n'Mqë˜üvä/¶fÑÅK—©Cã5l÷L#Ñ¢§… Û“Ý”‹§xÄðn*â Ù�$çk çè&:©wå3üÛK©:'pð€ ß” ßåÓßß… 3:Žº·ö‡p—Xª_°‰usäDÝ“·ànÉ=þ°£�{æÒ0OᯂjÆ© ÚÌØÞë ”xssé]Ð"�ɺ!8{ÌR’¾yn¾¸+:‚ñÓˆ#(?r7¦þȬˆ€¤=$>H¢ Íå4ÅÐ�FÄ]ÁEY c¨jPfZ3üÒÂ~ª¡Æwwì¸3·^¿#&M ¸z1í�=Ï¥§²»Ž/®ö6Ĉï¦ì)? 55>Cû’at»÷eØaÃ�Z%Ãeaš–-•º¬ÆÉSf¡bw9wôç »ƒèÚ χ[pæä}ô«Y;'ÅбŸ3Á>ªô­zã²"•Þ8bqùiÛãOE̘Ÿ†ÏçÞ.wi³ëÏÑ8oI†pâÄ ¦ e>\ª�%èÖóñ|RÓ›wÖgñ×¼yôúñ_ R‡Ñëωz5lhÇaÅà,8sb–#Èh`¨³7z_�éÒQùÊ ºæß5ï¥S}ñ8ê=Ï�=}>±Ùå§0¬v=ßòj!_ÓÍ<&×yàr¶ÞK~�ñbñ,,»Y .¯RaT¦"š|“å~—[éR©%ímÎ }LO®`[B 9¡4Oˆ†ow䞃 a@A›¨”O×?ŸåV½ÛtíÇ;z[û€¦˜aLÖ=´&¶RîìGÐ~º�Wø\oÏ>ÈmeªXbɸçF ¤9G+Þ«ó•òõ(ùPN �Òèü‹­ˆ ©²ybÊ0Ø>ƒº?Aâ—ï�2qÍ aýÈH¸f+$G>"÷R7qqÌ'*Ö(æf˜Øã=®%2hª ©¶_ÈlF’¸Ãÿf–²s‰>û= �Ý0Âü�xÆZƒó[“˜�¬ÑÞ÷¡°Áû�d�¯´�¥Ïv~ˆš¬4î9˜½Õ$ÉÆIø)wÊz}¤ ;-¨¸±ŒîÚÝ•ü–ÖÅ[ÏÓîÞqþ.`דñ‚¥K ­ùU�ï–œ…ÜçàgÔÄ�ï„¿Vɬ°Õ rsKÁ,5K¯èà¹n54Ͻ#ÕÚHýeú£âש¬Á�÷rPc1ÿ™6“ó^G½ l¨J¿ñ…Ká]06bWxROÛø?*’-äžR‹m?t+ʯDá öyÞ*Èo¶ãÍ#j1±¸+…ÓÔà .,)ªœ3¤I¿Æ…ÍæX3ß òR_’Sÿ>Øg›„ß}1óÑ'h Ù(¤ÎO'“ªd¾ {,Ï‚ú¿gùÁ±]Ä寶«¿ÈÛ |ÅuÎh^cH;<�‚Éæüãâtlk8Fqó¯Òã {L|?íÊH½@G²hH´ ®½>‘ßþ§“42Äoïé�Íú4ÑB¼{(ìlzâeP»ÿMJ‡ÏAßHkÆd(¹i…ÿlåÀÉ}yé×Qd²f0FïVÅ™oÇa÷”ô-,—Ü�}Ä…£GðŸƒatÖ[¸9¾„Õ½åÈ’õ´T«ˆ&ÞQÇ–“·Å+èÏæ ŒJ=�sÎü„íÞË+z®r« ìšÀŽeÃØÃyÍ�½$üÝmÄj^åÂòÍUx×Ü -Ñ#ñHYS6MiÓG—Ûá`qé09M¿'ø*›±A÷m¶Z8£2|’<_«/ŽiÈîŠf¸£d%ohöÁåÉßyü`‘.Z"ñõ~6tœT’tà]`?“g =‚o R>ôÔIµ²K@ÑËž¦}ùCžÑ‰ÜüÀ”ïÅeð‰OVøácÅ«,&ß?ï…æ¯RàÒ9·tcÅž“\W±Ç*_@ƒûzÐûN\† VwUÅQÇs¡¦z =Ë]�—×ÀªE|w—hcmÔÄ&sÊÒçѼkóEl>7»<ñ\óCH¸?‹f¿I¾߃ö#–>^JUj0©yßûÜO¸ô:€-º`ðõH(‹Rè§áðmš'yò¾õØ#F~ß åúK(K3O˜¬cC_A{–uöã'óÉû½ßIØÈ¥’0Q<‡&CR!óÄL~¬#Á1I¬ (ƒ•÷N“GQ&©ôÇušÆB˜\UoUF�E)°_)„ÄS�Ð{«vŒ¯caᓊÄüQ,]¼“W¬í IQ/iñ-w*š|’j^l¯ì›Ò%4$ÚCØ…‹Pÿ#‡Š¦;Ãç˜Âù²H<ç[?k>Ò…13 ÿõ�ðÎΙÞ8ݧø�J´bâ[<Ї¢w» ´ñ~Ú;4 yQþEhÚf‘Q#Hér1í÷ˆ6½ÉÁÅ硤Ô–:÷À‚‘%üõ¯.&|QkÓ0 îÌH×w:�¿$†eìž‘ü�ï°æ™/.ôH¬²C˳_é¡ÅsI¹Òcìã¦Áî™ßÊW=®Ív¾-/Åظõu;O×·¿¡+…�_|[W¥‚F”o`IS´ïÂÀ{¾(­2_¶jñ›ŸWi„÷Gr¼4‚?¸l¡T†e?f"½KÆn\¥ÑŽòAJ°äd¹Øõy?ϰÆÖø¾P¿}W.ÉÝÆ?·ÆËa«•4‹ÞÒáÛ�ùàH”4¿Ì}¶Ú°Ì­tƸbUãZKE$óÒ'^;I§'BCÁR¼;vß\´^Xóh1UŒ.‡3Ý«y_ÓJœ.u€w©OÂGnƒX»áDn$-çD¸Dƒ";'²TUÛ�įŠò¹l^ÛÊ•Ò&ÕZX>ÙãËN “±Zª ôµwÁï}°¦¥ ûâÕw.¨~wÿ¸Ûƒýí´p×Ï7$Â0H2N·ÛÇñ ¿y<ãk0<Û Âaѯ`©|î:ü\ré×=*sþM^{ Ïã ðÌÃ] S¨©1’?� Àä)öl휇¼¾@óÔSìj<Ç7…Pý2T«ð‡ä�úÂ3Saö} ¬‰yËUƒÕñ~ÕI™g6XÖ(Ü5m•œï–ç_«.'»oÓG+†å?Fà’Å- 31˜fÅ«òÐp¶RZ„–â-Xsv¿¹ö�>ý³Àœ²9<{ËHŒÖWÆAÝIp34e?¤òˆ ,™£Gó‡™òžaA¶;—Ž·�Ge¦0öVgEe¤~×…6Ç$“W&�y°+XOC�ä\ÊkÂϼ÷ƒÓÊ ¼Ûë<ú~Säë�›IuëkZñé¼}…›xî\#(éÕ›-O–bï:(øI ÓíÁ¦¨� 'c�xWf: HxAÏRiëÈ h~ý” {íàìCãÐÆÛÖÔýÂ�W"¸®ÏÀ–ÁÇáËÚbÊ~hÈEš\;_•ۦ쇺É7iÑ�h^bÌv¿Sù·^ú4ÀÊÉŒ�z¥Â�î ,¶Ï͉ع~;+oOu3§ã$?øP¿–çgGæ÷×ai‘ ½�Û“w¦Òö x~Ðz^ö¼�:Ÿd  /Ò Óål@Ç(q¼2¾È¶Â½Jcpqm>”•¡,Õ6x(«G'jîBÔ'îi;gª"–G;àÊäBT“ÊE]ƒpë"K6“R@óŠ}|Aë:lÓo SËp6Ê�ûv™s�ù§xè«RVo4�Ö½ÀWá;46,„�¿~ñXG‰©‹–ø¶x4JVõÂV­½°íÉrêkJˆaµ4Ì ƒš¶ã§qÊX=ô>XåmGI,klSÅ”×^(j*â­Ø³ ým'¾øz€å6AÛãéܳo?!&²‘ºÃ³…uZ#1hˆ9»ý¸ î¯}p×ÀQ|3ß ‹®6ây“¹¨ûç ­¶íæË5:ìs°‰d•0UNK:OT¬îN¤g†K¸Ú(Œ§8aÔÚ0}£àøÿ8Â) ']=M2UÎØ©‚¦|inÊŒÄñ«8fƒ€‹@v‚ G_¿/~XÓ´ßúò¬'ÞìƒÓŠ7rL“(Nþ:�×T{@B›‚6û ¼Ú �=?¾›L¿қ(óÐqÎOôÅyµ¢ºÉZ¨3•Á]yv\¾á/ø �zñL/œRiÖÎ$lÕXA?r|éíˆ |T«‚÷ÉÞÂï{ÓÅ>•IØß$ |� x]ã Ñ¿> ±ÿ-aàþ¥ÁAô_uZÜyR¿,³ÆKº{9oæÒ(f³ÛhGf¯_¸œ¿ êP[½âæ©ò§›[áȆ�‚ë…m•êŽe•ß-û �ÖÑhfò†dþjî·@LÒA2_‚–f‡ Áô‹dñÀ™¸oTÎÚf+vX Ä¾8x°-Çç–}*Ô½ #cYKç�p¶o(•OK§ÐZvØoƒc*‹a“µü0x/kãÇ#ê�¨cúñ ÉZ|Ø ¹tc-§ßÇŸW›¡aó,vî¢Ðõ×é?|£Ø#ÐQ=„Õq¶rÌŸEà)uŠbuß²c»"�š$=vVâ �Ëö½e­y‘wG¯Œ±!e|T{�}õȧd¡Ò ôB›ßÿ2À'ã…Ë]SH{Ùl°¡�žæß`ÍÛÞ4êëA^/ÿŸ3ô;Îÿ¥EaµÛSèèÜÁ¯+ô8ïâa¸iôŸ®I¿�ôÆú¹—è”À°p’ Z  `ÚA[x¬þ¤æÁý«Z¢ò CryËI}x¼¡7>:~¬/$ÒJÐ8ò¤dVC¥Þ¶L…�NxN«óøåPgÖwKg_óÁ4gË-J <€�î¡�–4½O¶æ-ÅTóÀ£ít¹Eå¤HîÁË{‘T~¬¥îS[¿þ´ÚÝíCûÈ‚ëÐ ý’*]ELžcD¦á\…upÞÂYh)- È¼ñ˜‘Ù&ž‰�EtMˆÒU¹Tù'Fý^OÉ/zqðõ³üôé4jÈ@IðFqc ªL\‚‹‹�pM«ÿ |A}›‚—j2–dİWî^×��›[® EKL¨Fë!=[¶K\=þÄ•ÿ¤¯�"øÚ!s’ôˆÂÒ�>°ð‰6k›ˆÙïîBkâ*X­N?Óð7Õ$\éË”ÊÛžÅcB[ ˜Í¸…m­ñ±´&{V>gé“„úé�ô®lzmñaÉ�:>l¿ž­Ã .Îà2ÁwN+$帑< åÑýÑ£J©jm˜!�ÙÇZà‘šwÅ�sÊðìÂ:òl¶ÅáT4,å¨W0AÚ ô‡£å'@¾«÷…Ÿ¥sùÅ–T¤`[Ü]µ�×KšiØ´tÔ²÷g-¥í çŸJõ<üu%Z­í…ÛSø«±=v�KU¶mCñÊeød§Îù^{“"Ú­·_¨z+ #sƒhÖ“yPsz?IöÄQß’¸ÛT“Ž�ƒÃ°¶%ŒZ¶,Áë.òTÐ «G•BÐL wÜñÃàiø!«‚ÛÖ%òª{õöVk$Ç6Þ‡í—UùÐèÇø5E �í&bñ âø¬rºµì¸Ÿ¿m·&ì(·ïÚÀ¶åjl5ö0úª­þoB)´%¹ôï} ÏÙÂôÖÑØõ¤'|Nä¦÷à¹QN|¿q5¯2ýB½Ý¸}�ôXÝy5`7_X·»?/–~+Ìߣ‹OÕ¿Cð¯Tî¸T+lª‰e³ê"Þ¯Ñ Ëgi�¥±}Ÿmä“4Þ–æÑÍ„Gð>¾Šoxø‚�«2ž½’F¹«Â¹ãü!ÁÖ+“ì#»*ïtÃP�ÉâL…3è×3bKh­Aºú‡±Ë±BÃqo6ùïæ—G’ç™�xöøˆ[ ˆisj%…º‡„eË�óy½£xqi®pàn3Ü91@¸rs›êð™Ý-7a*sXб[ŠÒ]0jº%º¿�Êa½XÝy<ì,˜Ç‡ýOC_Ó$¬Ýðß¿ö%ì(=J¢:A›“Â?C�ÑZÞç‰Jj¬k•Í×´ÚéÉÝñ|KÃY2*þ_eé=—�¢wK½8;¶vÁ£Ûûò÷ÓË™êϲrƒN0~& n�ƹªÏ GV�Ý—HNšŸ&»Cæ ~xbð#ô‹¹+>ý&ÙVg ™¶–:WNÃô%²JÂŒ!gQCPáY»ÀéF�°­Ÿ6øEeÀªÙÇ)ñ?-¶l±ÇC½ã¹;[ƒ5º¡ø4Ò‰·6xX- Wž’B‰�,è¸}¦û�yBVäü|~¶ì9Ï!=dqÙÒ~BŽÇ°Š¶„©Ë;Aaüeš¨›†×6?‡3·®Ò·úÃ3÷±OsV}¾‹OÛð ½éØtqÚ5FóÊ ô)ÈïML„ÑS2Èã¹*„Ð/úZs ÛGŒfÝe–ðQú<•¼è¢š•p1‘Èx‚,÷ï‘j^†œ¼7Wü²Ü5«pOûy’œAQ¦æ·Ÿ¸á(Q—ÏM]̽þPéµ ˆt¨¼üÉ³ÛŽã†æ7°9'’ß7yá)¥pwÅ”dçÁ½‰)ÿ!‰Ï÷‹£’f3¼¯>^èÙG‡%‡iŸO=l<{úYÌâ’´nè/o¿¥gî{ŠUr»XE)WàëUpi~å/ã—¨¡éƵԻËNm±¢ÞM° Ê…s ÿ@X¾ŸOIW‚Îì­âÎú×ÐÊŠ¬œ(Eö^ÑR/Î^ùJŒÿü”¾>Ênò¼ÿ—·Dë ƒ»þÂŒožÂ›e¦¸ííÚuiÿùÂ#54w_Œ:©_!³c£8à[:¬D«DQ7;ÕÎašÕlà´Ð¡\dºñ¿½ ¦è+u’E çPòçœà¾MŽïÇoªìwà LüF2‡øÈ: :gÅ C¿Cs`§hû¯·X¦ã‡S"ß •Ã÷‹žÐ­#ç1tˆ�ݧ´á•õïµx\¸¾˜À½�ꃶ«ÿ$ìåVk ±ÞÂÿ8m$ÚÁ$þqGt&Ù`ÆŸß«†îŒy\q½•R|ÂðCÚ8œ¸ˆ“onáü´£pàÊQÏF‚egCÐÍ–®öǦŸ�ä]4›íë›á®Ý0þñŸ_ÔicεÃìZ0ƒ±NŠýÆ›óÇ‹m—[Äð¤´<ø›6*ü…¿ž¯Å!› Aæ¹D¬ª>C?LX9¾>š’JK—É`òÓtkÍ@´�.¡w+½°up?4jY†ƒæ �}" 8P‹,WýÀśӯ€L¸=Ε܂ …Õ‡3)äÓ_ašA'…ý—fžÀ}66˜ã>«¦o…J�T6a³Ê¾& ¨\~2ê"1,Z~Ï[H›<. áõ»Dï+ðW>„¿7¾ ·0±Ýs =Ú&ž•ùO/M ´ Êå;�gíc±ìÔuYÕ5kSjëÀp^ql À‚(»ëCUpŒïþãÓÞºlñØ0å4ðßHÖ×°§&ß‹â8sægÙÒ͈~¯  bØÜ^² Lì³àQÎW*¸wŒz´0<8·N ê8|æ,vLvE[~t:„·—ìÂ2ûp–ô[LÚÊÁ¿àXÙC1èÎcxoꊱ»òž†hQç‘%ÊéºáÏØoP»@noÑád�Q,÷©/^ÐÒã-…³ìW¿ÙHoêÍè×õ(><òÝØÚŽŸ¢°l{;Èc}{‚Ï“vö–© ‰É†Âا¥Í'–IqïG;ye¼r– \Ql?TÝ'ß_>¸a"ÊŸþGuwÃyOß÷äÛ£˜”Ã7~3¹÷ÜÑä's¬rRÓEltɦgÇ é{w¿V…S¶ûq÷•³´gÝI¸èâ¿,åmm)x>O‡‹çía ¬¡úÄÅàrã*pÂpžZz Œ¶Ÿ‚CÑtbî ,v“¥š¯Eö×£«(bÔFœ2ûÞ")6n{EâÈz:nT(^WûE?óC96!×§•PÜûn‰O � {&´‹{ôéݦG¢êTU1lL7D=¹&îSpã!=-(¥G ÔùUÑÁÌbPZ$ _œƒ÷ägRÕœ.Ñ~—�¸à‰9ºïÏ‚6+¨Âh¦¨]ø×Ö»!Qˆ ž¸rMAO õNÆU½v�”w¶Ø˜¢Ï¶Xó² {¨|ûaA!e17n^Ï�À–ó0Ôí j¤�Ä_1xûÆQȘcF9Š®dˆw¨—t§W¥ÃÐåg›´X°ÈkGÙqZÍhÒ’Ç»ÕOqqäXlÚŠûþãl?¦õ)œú°€ÚŽ A²õ¦`}cîòœ‹q�y1\3Ì…É×HÞ4Kˆ{�{iJqA¢žpX‹Å>¯†ò�ø<ª ؃õûLqæmy\»ó ©/\.ú4·Ä¨Â×Åh¡²=¯`¯™ñàÒHÔ’J[äàRáE÷ÂáòìX¦«>ØlÌg§§³óT ´º•LGX±‚ŒÈ3&åТù†è¿â. ûm‰Žt/dkgƒ:¶InäÉàK¼­– |?G¥à…@#¾=H‡/n�ÄÚ Žðb(Ui‡¿ýûò¼¬S°Âô¿•Xã Wmô_ƒW]rx~™‘�ibǯگÀ±ñûÿc)Y.8+|H}Òihߥ‰YìxBå\•_Ž%–Ý fÈï3(Ïàµj}y±IœÌt«ÁÙq ¹ ¥^wc©dÝ-ŸïL—KÿAý>WÌ ÚŒ^÷Cùç+- _ŒßDã¥ÌÝìœ2çV¯`&ñÔ”<ðK7ä§G¯‚Å;]y3˜W༠É�Õi̾óŽÐ18åÔL¾Ó—0¿6ŽrÌo‰Gïç?WDÏÛà ?‹§öyï�¸Ãk�#œì]ŒBo%ÐT¼&öpL�„™†lÓ›'¢g�rÒYg]E*¼ò[ þu‰å”q�(c‰!:›!á¾û¤ëcÌÂ|°Þ)OS{åà~ìI‹Öe…Á!¬;·Ë^ºà+yþ¨wv”܆×Ccð¨M/© nøè‚åàpGÿŽ8mí4È(Û�»#åH¿D‡*ìâÑkA~[<–Û3ÕøvÜ-û÷´I:ЕzüO»íáÝÊP[_D;è‰ø53“K€¿Þÿ–m¡MšÅd¦Š8Ú*Q4h›„�U½ùé¦b°‘{›ÈÒN�ºÕ¥„®Êði›ŽÕz²X9t:'¾úCS'šaþs85°„"”ìààŠïÔJÚç|q®ëN:º¦XV­ÛÈVWsÑÃÉGsÐ�?d3åˆøñþØ(Û.Y’GJ‡¡‡ü|Ñ1ì^|� H–ß�6Ñüغ'šÄ"÷ =Tž½á(ìÿ<ý‹ò¡ƒñ‰ž^ѪDåö7ô^§Hr¾Ù»’=ðÛbOö~éËÒ;âÄa ºûo ÿ—-Ö{½Àõ6Mp¦ht¥fg8÷p„ û¯_׋á¾&òkw}ž¶_œl级‚÷Ó±¤F¥ÁTf0‚ŠgÊñKM¶Ò E'ÝA|¢s#®œ¬‹f{ÊÑ«KC²Èá$¥×x°‚åEXZ2Q³ tÎTPï¬ú4�ïÈwC×�ilY�}û¢Œ‡ /ê!Ëë°aë6L·/ƒêüqY£ïÊ}G7šë¨Q._æ)r‘—#ø³—§«>¢©“äqȈH€Uïõß(í»)%Û¨QóŠ~Ð5‡GnÅPËZa#œâ–ᴆ“âöæõ”ìz]$Ï0Ñ*.VŒO_m'ús_<üÀ†Z-UqÂî Ô VP9Ëb ÿ³è�>ÖcyÓ÷�,÷@‚ÿ„ë<éÝ qÑ¢_ý£ñ™:Ã’9éà|Àk_¥‘fð–Êiú¬Z7Ü< ]ëÄïz ˜Ø-¶»6ˆß÷¦™j(äîŪ€=üemxý�Ç3®Vƒ¦{8—½qàì¨W¼ó[%-ôýS#ðµV «u^CýLÙõtožô]€{«Î+ªã½±†üNq<¾U±ÆËƒv�ñ›³âÇ&êÑs.mëÃFóñÒ*]øPë�½K´I.¥ód,…‡«ª%ËšvÐ }(_Z@Ƕœ¢×Ï£1å^áËÍåü¢Ú;Z¥ðÙ‘ÁL;|„ñ»Mpä³Gà 4�?ö gŒ_Xží�Œ‰…Î48\ƒ{ýN�ÆCCÄS}ŸÃ•~ h|\ÜÔþ�÷?—ÿ‡e&3EB‰H¢Má}ŸIJC“’hiÑ')E!+*«lÒÐByßçTHE¢½´-%m•úöý^�×Ïëúé�‡×u,-ÔýBʵ«dë#Ø4`5õO„9™?é¤ÞwI¨½ å¾¢ç)1Þy2™ÏÅø�é”Ü6¿î8C“îßü×Óf(W=€�//€M ›HZ”ÄŸì=QÿQ¼¨rÙˆWÍH¥íçxú›zQø¯Sè•ÏcÝ^K~(†œl aØo¤7i”äv’¯B>ø�oïwP¨Ž™Û–fâX¿;üŸ­*-}D&훘ÆTb÷ª n“<ÞŒ4eä`l û@½½—C@¢À®Ëݸ_‡¿Ïx&Ù±r††æe�YÉr´ð>�šJlX¡�ýÏâ0ØIÊnØË³÷É}‡ÉöüäéCZžzG�è$Ö×îëÂ0¾ug%~ì°Æ,-}Éñ³g(tJwl_ø†$Sø`íY’i�ááúóx²ÜÓK!Ê×)xÑv�ü¾. Ô» zÙ—Û¯‘µÙÌݰúùHüÙ°ËQ{Q¦¤¨àì´yDöà<ªho€æÿŠö«Š­jW`÷µG0È{n»O:Îvý‰ódO™§ðÙÙG•t’ÇÃbÈ×}@³ AÇâ¶×Ø�aõÖX-£ÎNͺd¯Pƒ­ÇÀD«fªÒsÆÿœ…úTæ¼”­_ŽáÙnÊìxÀ„;‡$¾1øÆ?�:eÖáàmÖ‹­VcÒýy´G ‡n«TËzZ‘–ò\w­§”·A\p«å´dÁ•FV™¼ŠRv`bë:Œqz+û–ÁJ«}¤ÿ)_ü�4€ ÷ä%“;„Ëz³LÜV:·ü4í¾¦€¹iÊì7;ôŸ�Ç%£ÍØj©lüõ¬:§Ð=¿xX6úš°Èç—éüÓÍ+¦h•Öeç{W‰� ûÒ ë$¬Þw—š¢Ãi¡ïz·�Nö[BCöªó¥6 rÌœC»œgñÛÇHß>¿‚„øÁxÕqsÒtŒòŽ'‡E8Iût;4ÂÇ¥ ííÕxdØ{ü_G-í(£l�&úÛ1*¸7íH+�¯œé½´.kEž:ç§ÍSļ¯Ëqœ÷î·¥š,+6Šæ¸Ð÷:ÜÎ'M8Ï=˜‹Nþ‚®Åípæ‘ &&ÿêpOV�{DòQƒrÁ&a¬¿á‚‚‰zNBœ{d®ðe8™ë÷##Ç#Ð0û <œ¬….ƒÓáÈ»—pçÆ±y ªŸû³UóáŠo£iµw9¤ß.~€ÑQyRv~¼‡¥ÕxùÅl³tuß¹’ûVnŽª­ävµf%æ¡÷…­œdŒ� —ÐÞE {GŒäC;/°�ªXÔÁw‹ÝQ’¿ÞP"<�ßÊ% Õ1æë<ö~l³V‘ÉöLñï‰ûµÊ£í•ùª]üŽlñB–“:êiæi%pŠÏ…ƒ+ iTÞ>QÓÀ42¿ Í6>b–�×ÉÎÇZÇ{0jÇiiKC :~ŽÂg9ç‹pÌʽ£Õ‰îFiX.y ûeòŒ•¬6ã·KâÿÓà c¿„Æo_Nu§ Þ[Òy–’7;« ås¥7ÄûoŠ¥ÁƤ·ÉƒrÛ5(Ý÷7QHÕÖâš÷ÎÜ>¼/lí¹Q<™9ŸlÞ„k'0]«RâËcxFÓ>|âCëW4‹2/àE›ßÜq…VGcKïLÊêŒÅìû�°äâ3øãÝÛgÄKÖ�x�ñ)ÇxëLcÉÑBø¼3ˆº¿3çµÆFxó>“ùÕËdX‹›b*–\êÁòÄ7±ƒXrN NeËJ}ZzÚï>@Gýz”óZ\ï&Ãý3¬º§q·r#8}þ>{n9Iž�~ý ðl©5õÛÓ<ßÀß´œÛIþ¹!�&[^îv‚ì>C²ÑhLôX€Îïê$�õðÎÚ9$§iÆWbeøÏlO°fìS8Éïâ$ðÎy!F;Ëâw÷Áu°&øþÕBå>D‡à ’ŽÇEkIµ ]˜¹P‚{*Çc¹Î5á‚×'Ñþ«1Ÿ°3Fˆ ±Ñm¢¸¤O¹èöÊ4’›@¯Tƒ·Zï†HCiàùuÖÜrÐî®; “¬:àÚá BšÍá¹i.³›��îÃñ{¸9þj´$ͳqéshíÿœì7â͆^üý‚ wê.Éé"y´#AhšhG#6Ö �íâX1ê „F ÌðT¸ $hm T~>VEÔVhÅ·�áë˰pë,†mV©5Æ—cË„i3Úáfz4œÛÄCr¼p÷7˜°$ß„ï¦÷Ô&<*õäÐÍÑ¢Î�*^­´Žô[§QËŸ9bð�: ÕO0W'ŸŸ$Íà˃òìt6gÐõw9¼':CL×ï‰û§üs·Úºh0‹ÿž��×B‡o9;iÙãä±_i�� Ú 1�cƒ…c…Î#9ïBAµ š_ʺeÔñÄ�äáõ¨ äñ³/鎎�Ë6:xÞÍ­¤{*´—c”ºLUÎ…¢Z]~6½h´Ã†à'beë"–¶ï"Ö1f™¬_ ÞËDëƒÓ`c¾€Ï-£à•j/2†Y TÔòòŒÅÌÎAbkº><5…›oúÑà»1Xå“¿GMçË×Ãþñð#‘‡'ÃJßùXm½Bò[§�Ll²)ÚÓ‚^8ÑþºDØ8J;/Ù²^kŽøk�š�`kÆâý3<Üt6$?÷§�ýÅÞ# ùxùP˜§å…æ¢ÙŒÏò¯sßÕYØn/ w¾F¶çbÁ]± Üv+‰i¯Êi—»6jΦà#pý¨oÿÿ4ô9o†¯çö¬‡ÖÜT�•3q˜¬†´#¸œ�è�î®=´ðøTJ8T]ÑÛø½G‡ô­d >ÊüAëna¸i:%DF Ç¿àö�0¼ö#L°Î‚‹§Z¿èo™6’×ôûãr’Ù6Þ‹¾íƒžõã9ÃGN�éãÄ Ù#Ñfu/Îꊡ‰ÁÐ-„è¦jÊrÁ�CèkîX^§`Œ3å áVGw¥\�:­½ ‘ÃÄ·ÝωçZ�xÒúAœX2o(vÀrŸ'âº5Z¼lHf]—ÅIóo�{Q2 vÙâòº« qm1œÒ8ÀlÕ°Öû ´uÜVªù—�ƒÀKE�×j^ •G^|ÂZ�k¾÷”‡°-Q‡-�¢•…')aÉJ�ýË ‚âs^‚mÿ2PtΧ÷d\1~?ªëìÕ>›±ÃÒ”þõbüÍq˸jHø�Ã^/£ñ�O“†Ý8Vì=uûçñß*hûåÉò�bypËîÕÓu ·óñÂnìX°ŸÛíø]ØU!ÞRU4yÒ“¬àÃFÁÕ¹»Ðý¶.8Ð*Q6<(wÿH‡] ôá1:¡�b“·áÛÿòÀâûTÜ1£˜ÏÝÊûr‹éw·+Ð¥´ º_ІonßáÃ5w˜÷l;\½‹Ìæýÿ®� Ã\…ÑÍqî�"±ñ‡½¸òrd:-‚3_³…�õµtg“=Ý<“u7O‡¶•dp¬v¦®DËZØs 7ê¾|¦‡‘·Þÿ Ÿ—W­û-ædZp@”¦öà¡?ÁÎCG:nÏ|úµZ‰ƒÖý†Ý•ÚìÓQ†V Cy¦‹?ý�…ô�+nÎ×ÃÊIï ð~ì·Þ�ÕÛ!cë>’Ûl·+p §M½K{JÍñÎÁu¤È-0}@ ›�2€ÆKqÝ'SÞí$‹Óe¹ogƒx€'Ч¨::î ‹Ÿ«`Í–lÐq>‚ýU«À"ešØôo&þ½ïÕòE“T°Tý ó{\!íO*ü6ò¾øù�̲KƒÃ†ÝQ>h„0J¢ÁãGÞ“ ޽ ®Éû`þX{v2pÇ´+“ေ?•UAÝŒ�h2bL>õ˜ÊªJéú½‹¸å”=û?½×zÎáâ›#8}³+\(¼ú¼Œ}K§Cîw;L•ÛÆû}߃ïám|í¹<;79‘ÅÔ9|zè ysÛƒãQ­N ÆmÛIS�ÍÑÃë �:Y S´·HWÍCãT7Úuö-9›ÆRea®úê¾õ¬ÈwÍI0²£ìÑÅ·Y‡¡k‚ Nj¨S £a÷R2>dÇ?ba¡uE꜠°!%b>¯å>XЂ ø¢ü£ÑT9%óU `ᜠXP$‡/î¦Àçê°jÈf8PES{ΟqÂäi欰©Þ>GîXàŽ§+øü{Kþ¡Î3ä–AÛÝô43©bU—õå´—Ó}Å­b¿ý+°]HäÅ_Ó$r-ýÐÑëV�ÇS’Óð~»wŽöÀÉJéµY!iÇÃØPS~Ò+Bô¨WG²5ààšþ8´˜ÞÏŠåÿl<…Æþ³È¨<7ÇËó�Ù•¢]�3†ž‰'óT} ¼.™è·…fD]' ¯Q·8�º9¸HË<›RÝN;“ÂñÑqEܵÁ‘Û¦‹íG�¯Ù º¡^2Ö›yaxôQ°QÈ£Ëgs„ª‚µ0µå?¸ó4\nƒ2Nø8 –¶Ò…Ù”R=V<è€Ç‡ÒE÷O8ù¸ ,ß’(À:% í çÌWb×é[ìà^?Û¼`áÚA¸7ƈònDrgÝz¼öÅ›Ûí§êª®³¹K±÷ô0¸"ç´í…ìYWÙ*µ„R6C†„Q'ñ'¼]š)&÷é ¦£~AÔžmpÜE›õ8�I×i'AÕÊžüÖ`Ÿ“Giú y®Ú­ŠMÃÝ1¡í„¸Õë©ýß 6ì-ÁWÄE“ë¡Wý)TX�GÜmðËð’�b>íùõžy¸òªªÃXc@êÅ‘Pw+‚µ¦„A¬^":LêCŸoécà Ì8A‹å'ášk«èÅ£%|ìÒˆõFjú')t…*ÇÍìÖ-€}�mx{N MÝ•D.§gàŠ]õ<Ã,–ŒgGáå{%�þº…‚·8 ÚM¼ô=ý¾SrÌaè±Xe†f¡æƒíB䪉xpz"º(cÆ"zšu›‹(ðä‹àÔ,:ô äq¢ý?—ê90Sx_î›KpcØ ÇÙ Íô ts«2ý§¤ÂåÓbé÷ÊVòüòZØ––Kr“£øÆ�Ò«{`—xžÊÎöäú]v(’ Þ™»ƒöÿs©Ü�bж³ø)ÉC¥´þá ÜÐfȧç“íò›ô'|‡(¬9Gi«ã ŸnJæø}¤_ÍØÈ% ûF¡iÜè?í-ü®YJ3Ûd¸»Ÿ,›ÇÕHìnåÑ�€ÞXõDJ¶»së�ô%'™BäÒ/}{œóý|ßÿ¦}Dº÷xµ¥ó™5Ð+)ƒÍ?ëà¨�9¢zÇl>òV˜¤Hé ÷Å“ãE"¿ ÿ<‹Oj�•Ó†á¦ÕSyP¤OJ”aýø�¤®È»E‚u®ïRP€}ºsCÕD¶yüŒ>ÝŒ Ê jÁAc,÷�»*U{ÛJ;mËž=þø¨?¢mæuZ©Jµ;Áb­œ8Ôt0 ê�œUm†0¦ÍšKÙöøâs=Œ7m�Tß�1!U¼L-¤Ý>‡ßÍçꆷ¤–9W]iɶo2ųwR¡Â.42?)C§Á�$SR6½éüÐü\3�ÓH‡pW Hý– [úþé[ÉoöxÚCc.àèØÉ4Ëù¾î¯…î†øøZ9¸X¯eÛuƸO×�j…¼n¶Üxuÿ)UD÷‘O`jü=IˆKé}Ë€®®$ëoJ?[:`ñÌŸ¤¤3 i©.š.¨†G+4ÙäòyÒŽöƒ —^˜÷ÝoÍ|Fý-NŠ;gÌD±Ð—;i£Ñ·ZáK‚ ‡Þ4ÀŸI;àü‹¨sĘ̀¡‘ŸIåV7‰[Ç:àV“>xº¬Bò:gÆ>�žÑJî¼T¦wwsÔ‹mtB~•ð1<µ:nІ“Gq×–µbdí1*7óæctÿ§pqã,*ÚÝ@³eW OìçÇ&x}$K! /o&Ù_¥Í­sØ~á"ü¨É÷*­~æØ·ó4=ð½(ÆÑ@üßu’6Ïãk­»h‘×5èÊÖà§ï–`q„'u(䓚çK1×'ˆï.íÍ3Õ³aÀ§dðÝIÞëÂÝjw¾SÔ!ÚC(ëFÆ´¸âÛ«‚`~ªð±Îá³øÍ¯CÜ3p<;{QÐP|Oö—4iÈ“ò´ÍÆ&k©vÞg±øŽ9ÿ×7žÐ6‚œ~cñŽ`‚'&÷¼­Ó`µ7wàOàpÛ`‰Q=‹Ä}ŸÀP‰ ™ô^È]­oèñtU\©­ÀOÜ ñµÍ*~¥o„r½ÎÁ{Ózõ;šüvMËè{ì4Oé 7ÝÀ³C"qvéóÏ›ÕØF>Sm9 Ü£ÉkÝ�ë²"Pè/ ôÚÃ*aQxîqD^é�z¹›8IjÃJWñ�ÁIBJ\)$Û Å%?þQŠ~.A¹®Áء۹àdˆ¨¯ø†åÆþ«§ÑñX GBcñEã-éº%©üdÌOp;ê€ÙN}p_úEòrÒÀÑë¥geµøàæ‹ôàÛ ¶Éã’ßu4~xª0Oþ)œè]! ²<»x1×m³¥ÃX&ŽñfÛÁËèצh’?f9„ßEüf:êÞ¥ƒ^[YÚmÀ~ë¾ÓˆušXxͶ~«|ªàåáðòy¦d̹ Úð*Š+òž‹¹í–ì ©FåL¾ñBW¿ò_ÇÇçhò£‚t§kŒ¿L#™ÃÏŦ1'éuZ®x5ìôû2 ·‹›iY’.Û¹Âe÷ §?,e÷í˜8;Up­Þ‡YïâøcI =Ý{…&¯ÕæC2Åâåyç…µ¹ù¢ýrK®é3·PTü•å'#"(rî[äË“5ó6öþKÇ¿ÍÂUIãÈ28QH^³ÄÎýA%œ?ñ†<Ö¯Dc )g*qH)ý iµëâ'ÑÔ{…@Ù;Dh´4Ç3# cboL¶m&…‰Å¤žµ›{©Œc?un³ŸŽ› ”ñ¹»{®i3Âוv9TªëÚ o¡ÿÔ�ØÇnn®àÚK'X¸R lϨ‰CÏ{�²ô4älžCgÝ&èÿæ):CSQ4éƒ9{6⬃0õn5ø­ÓÇ„Gºüð &š¹’þçs‹ÎºH·o‡˜Äù˜rä2­�,«�c÷öcÇÐÜ4Ƙ+Ö†óÁêá´CîŒ$Îe”$ó8½LJ¿¥+Õ@Ko&Ï�Þ¥ß …õ—íøÌ’ è’ô Ëñ!õO*¿æ‚²M^˜³\�ß]ÿZ1y“<÷ð�#Ÿ-J—­¢Åh�-ÂYaëÖAd?~6ôî�œ9=‚OrÞE$ã¾ñ�¯þ\³}$%‹(n\¹�IÜZ(ÿšO ´ðGm hë›�]ÇviÜùS”8ö"M.Ëa@¡´_X?°mR7ÂÀ.´3œMÕÃΑá\ÌIÈvk”SeéZE M¿¼ß/žÉÒ<;õ__…Õ›ä¨Ör3§´/‚›ŽÅÒ+€»"EáZ^§¶Þ„‚C‹tËÙJe•x4ƒJ!åêkzÙ=þøì>fÓœ˜ÁdߨÀÏ3?CXS_wš^O¨¤þ£>AdšX?Ù&¾ZÐ W|Gà\›´;|QLß`eÆâðQñÐ÷”׆Ñò/㨴G„(>Ù/tsVâ2œ¿ýM—äŬ'a¸ZUTõ¬…éòN¬°åØÔ¹ÃÇœQX\’)\0 özP¾ã1Ú²«7îZšZüt²"~8R..‘1âËo$uÏ›O‡=¯Kq¿½”4Œá¥Ãu±í_ÎZö+†•i§`eö®V[Ìm¦[ašm¾p&á0¤h#îz)Æ¿ ƒh¡‹zþØD_&öŸH9úc×.nÚ›ŠËRÙ~T'ÙÁ/ˆ˜X kL óà 1j«Zœˆ¡WOðOé.”~æ[³¢ ß¯îÂ<¯9´´"4S{à ¹~²Ï�Ÿf&ò¶ÙM´ O]îÌŽï%¾Ö~½Žµ@Àr9òîTÄP¥IËÒ¡luOnßEÏjBÝÓƒ–0“O�ý mÛR`©ÏÆŠö$vxmÍ]’þ •ƒe¯¤zªÝùþ¼÷ðÛGãîD‚]u/>uuó‰íæ-¿ßR^Œ 6»‡;hÁ¢;´ù£ûÀÒ][ØjŒúî¥G3.Àëßs©0O—’^Çñ¾ Gû,Ã=Ú›0eãWQáE†�:` ¯,ÑFQ™¿x/¤Eý¤´.eŸ¶Ï~gfñÅž� ]9›ËJ’Û½4´öž�›>™^O? yCëiQc¸y0•ÿ„:é¿a…Ã^Ð<`‚�%ò¬ß< Š~®ÄJdjƒ©ñ–l¸|n+Èf—Ý¡˜ÖÐm‡DˆqÓuÀK²”ýõC¡ÜÎÃßì¤�–òlsi’¸dÈ0ÌË»MwJ-ÄcCì â¡.nÌ8ÅÊø‰0g*å»»|©É‘MßÍû*7©·c4ÞH,c·Ïà×ý²ôû�)t62&­ñÂú�¡è2o,6ܰëG•ùD ‡µ<þò‘�›Uy¶Í0á™óvì5+–¯\­áa�vìvÜŒm†;ÃmŒ;ãÆ¶@¶})Œ]`Àç*v‘4pªP?ÙO'^» VÔjJ¼<ß�ëK|h™³¬í?‰µMÆ•w0iÑwørú-Ä-¹K?ßo£UKáªóvpŸêŽv—~ V>Jâò¯o$[¦¿�Nx[GïÚ²‚ÕszùÎWï]Lanóñð»8,ëY�‘JŠ˜5ÙƒÜ[Å¿­¢�Ö}þ޲–µ ›gõÀ=¾‹¶«Møe•3¦»É±^¸…¸+U“-\\ÁüÏqdX­p�ææ@%\¹y÷::‘6u(Sm~Š)ì‰Â'€[x ùˆä-u+©Ulä?½úàÑš |L‘.¨ªØ½Ï’¤5޼ýùXöˆì{ ÝÃ̓DýuÙ´øœ.OÚyŽ—&m�ÞU”Ö?]Üòq­>·LGãÍçmÐõ .–ÓàÂy¾�n7Oâ]QÍQ ¿(³åY sG«+þí’È㊕ùXäÈ Ýs•ø­"ºü±±,_×om ä^÷øxOÊó(ýÄS:yJJKœü±6$^PÏI¢-éNh·Äô¾ªÁCÃÉÉ?^â9q®Y¢�Z¾ÃPÛ¸lX…“÷ÒÝÔÃxÞã$-°rÆ_;aÿ©É­Ñí¤šÁJƒå8Ìü0]ð«å#(=kÇ~¦ûa�Óm¸÷÷½ÐbdÍ9�CФRƒ(‡7˺ WÓTœÞú"ƒ5°ê¶#ˆ'¼XZ3‡þâ"< —‹Ñµ·apÁ)ÑÒx#û½Ù†ÓBuqS×H¼¶ªê–KI¹¡NOm£h­‘hpX™Ü^kòý¯XóÀåy¶xæD>œÐL¾ÛFà¹^:1¿¿]TúS¸¾Óœgʪ`vŸxz·pöY8•þN>"èø´Ó�ÃØªp£põB �ø­AJÎRØ&]>c›…E»¹iF‘Ô·j/þjh•¯ghtp7Þ^¡Ê±kŽrý²¹äR0)Ô¤O—‰Ú+ö�›d4Ü‹þý¹*ÏsU§Sߣðýà€jáäã¨ÀMv{‹¸p¤Tˆ>>ƒ;ZB°sª5|û5Mâ¿&®õ€C¼Ë¸Û«'bÝëÛ[~‹îÖ¿7«?t¨ª�&�þJ]ÕÀSª†²ïK©àcÀU: üÀ{�¨1%•öI´sÝ~æ»sr›>rzŒ[Y%Œ¬žŒ.weÐ#Ó L<· §NÆR¿CÃyªc8Û#uµRðRˆ„Ä÷ÞüèVôT'Éê‰ÉxíhlÝ_Bá?ž‘Þ#el_—)¶®5ÁÀþ?ɹw•|5<æY,]Q×Ï sÁ*Ç �³§ÓÇ¿ÁvÄQ<ÐxCùøåv"éø™ˆaÍÃqþùC”úå …4†‚¿«¶Ç¤TdzŸúYkÓ÷�V’ëþw¨n÷Aø»â3ôýt‡èÝ1l«ñ†šsÇéÊß\é\£œøB�õÎ�à׺}ѶPŸõ]BÐÄÈyþ¼¾}g]h–Ì=j9Ͻq{±)„ýùK·Çp@Þ`~õè<îÞ�ܯ-Ä^vªÂ7Ý; 6¨PÒ"ƒµOþ±ó7k<[²=ï: �7 –hƾ¹+hÞ„r|lÌôÇú±WÄc§øiÀ}!qB0n°2âìÊcð_Ý>hиŠ~[ßPkºÿ|›CÏë2¡¨6;NBóG™8B¥úi;ЂËníÁ­#³I²é ¾Ñ'ÕËK�énÁx-ÖìšBk'bœDý¯íÇš�-'Ãä|WþÛa„‰zr|¤UĨOf°>=¨¹;sôRs¡cVOîõ.¥[·±®e.çñbžÎsGe‹^à!ôÙ¬Ã% Ñ”a:�í< `ÕµCüâwïé§�AÄU÷òÅW–·émŒ*¾ïé‡GÞ–Co•ǽC#yÃ÷aÀaßáYv³0Åu .ñ×¥šï¾0·Å‡µG'Cÿ€F*›";.oð:8”ö,7 iwïÀ ßë|¡5%BPÑpÌwÞOš²më?úC|7yÖy6Õ?cÉê�ŠñK1(·'笱åû{ó–¡Q˜9Ž<Ôµ™N(x ǾN£Ëg’8}1hWzÂÏX¼žƒÁ‘à 7Ik&:ÓÎÚ÷’šÞ ¼|e‹Øú2¿Ÿd§µ‹8ªóä†OĆÛâì>Å’ìù+øÄº <¹Å 'zJÌŽ½ž¸Ì„o–I‹OOáZêø¥Í†–]Žö«!O× ³®¹òŠßÊ8ûêg¸¬Ú*Þ´ì‡Ò£‹Pýî38ïôFhY,¹óA•×s¤ˆš'á¨J´`6·JZjI‘3 ¼mK_¥ñÁ—Ï éÆ\tj;œºVNýð�á™R}ß�Zþ¯çÞ†ÒÅïS`¤ä-8” ã°.}œ5¨;”ó‚Bê3m•h÷ù.ý‘öÇ”¨¡üÞt¸p`�"—äöæ•f› 9n¾Ô­w$4܈bëWã8áO ]¨Ë¢-gßry³ ?ØÝNGžà� ÿfúf¨JýFšòéž¿`IÌ<>y�5š!\·Ž7‘ú»s¢÷ bQõz>/HÞ¢)Ý™‚Áú;xÀY+ò0Q8ÿðÓW:ôå$-²]•›^2X9-ŠË·¢Ì>LièÉ×+â-gKê'‡CPá’ÿ8T$¾ºRÐ(ÛG%Ao¡Ñ½':Vÿ«¿Ë9¸uz6¿V´eÍÿ˜(( Gõ9D:ÍÐgÿ‰ t¦Ÿ¦]êðë‘Û1@Û ß½’£›N £RiË–‚ð`:¿–8£W»„­ºyŠ;»OÅ­[Œ8ß} :ôèDz^yДm@QR_ŽYDŽÑÂ΢$šôs3™eö½=)M’„]eé®K)¸uÇò™¦üû•/S˜ ·H&Ù->ÛÝǠʪtžÞD*°ÿªÏ™´›ÆŒï‚Ò’zµÎ�ô&}Æzþ´_DÒ¨Äвi"ßÞ’Âo•ï� ¿…èô(·«—N]/Ú›ãå•QàÝ�¼jÿ1¿ÃD�ßi,>+”Jówoƒs¹Ú,k¶…Óÿ[#<ìcÎ~­óÿrhàµù|m{¬ôH¡Çƒ¢ÐAv:¸)–íhWs=–k¦ƒúÔ0ÖVµä?ç±dgO.;ãÌMÁc±åô.(üE_öFànSwÔ{jÈN–Ñe­»võ=°èº*VËZƒï±Ûj2 Ÿ‡ÇѲO­dñn&ÎŽ­$­Ûà§^\Ó.lèq‰’á�ø¦­\”»xŠ Úg‚µÍð]? VÍîÉÛV+°r÷8J›z”ã:°Úa«è9b É/V�á¿aî”ã ¸ÇnIv 8]8ÃgFÞ…DÃ†Š¼£áVÕ,ê=¥ŒVäUAêe'L:7žJGw@¨ƒ ¿|žNþÛ:…—Æþ`h(ËGæÝ¥�±ahà?Ûÿ6€Íò,Ιñ’NÔxÐKË{Ä'ÛáÉÞ`z›&ƒ¥¹×ÁUm‘àºÐ‚^{€M>yÂ%/cœ”ÐòÍûã{¥�8ëãû�Ø.¿ß®³p–d_RÛ‡¡�ÐÃ׳&ú¢æãf±G¾,ÏË âqÞ�4ì×l\ùù*=²3bµw�%ZÇr1N'Lñ1¦ñ.±Þ±ü*í¤0hû˜ÿƒ2ï‰>ŠUÐ~ù"9¶Žç×ItT/Â�VOž§†ƒì¡ã4¸ñ÷²ÓfªÑá9ÖÜtmòÒÞn…rsŠ;Ù“^oÎÈ€ºÜHÐIRd^< wjéà�¥½÷ÇOé6¶3€7þ©ãÕ²så1… ·Ÿ’Cº2Ï=1 �ôÖ‚·š?Ü©’ ë0AŒÃª¢ðú˜á¸Äè/r`ÄSÞuÀ„ó?нŠ]|»L�¬2hMÞ!ŠÒ å!£*r¢ š^CÞ1Æ£YluÃ3Ò Hþd­]‹w&öçóW´pùâ½pÞb'ižƒ“¡¥”oú‚ÞÍ‚“½» b@7žöj&®2³#°Iáð}—©Ró<5Ý,Ô‹Å‚…Ñ‚ÆVyyŠ�ÝÈ~÷ȃ}ù»ñb×jvIŽ€Û%ü8¶�ö…Ý Nb•¸“ÆÀ~~|6~phÙ<´ž¿å,â@ü3MY!�|Ÿ"Ö*�àí³=8ì´Ö}nž\´B—ïŸiõR6¸p`ñc4àG¶²﵄/°§ÎsšËHŒø}‹`õôXWS+øºjâ…­{hÑÑ`1ä�L•A##gøue _ù|‹g>ï‹&C•qÔŸ\XöÔ/:äçýŠøøæË˜úr.Ú�yà>ú˜`þ'=Ö¼m3r?Çcô·üuûä‰iŸÖà³¢e|bôDú27\†A—s}©8¡Qøî@еúµð#G�Xc\íj(xú™1W½_÷åÅûûÂýÎ|Z›’†­�ÃH¶à<–-”Ôïöº�)èL{L™Ð�“FxÝÐÊê{@הɔó}ßmâVóƒbIS˜8€N{£áã[.=”C}|\È̸*FŠž¹E8øÃ¸1;š^ºL†;K¿w¬¯œRâiÛ<á|´,¼¯÷>fÐ;G¬ö;¡çäáÙÁ:rz4•_Iò`IIì-ß�ПÄ~9¶˜|é¼Ù=ˆ'«ë³�u>�é=žu6¸á†ámB%ðô‹}aŠq éß� Pp BÌ{m…sL¡W]C9Ìf+–sò²0T>¢‚Vw«¹Þx›PÞ‡†Q/(?ΖKäSyH]<§(å�oJ£$1;Vˆx朓ÁºÂ¡8w£-5ÇßÝšȽô“‚ÇÉ¡Êé‡`X»Nšé«…ÖްãÊY’ûgn‚µó»áË{ÀÃêK0�o‹såÞ‘SsùÔ¶Rz—ôáM)2ø‹´éÂɇ0f°#î4-®|Å™7ÅnŠÜ×L]›•8;¨ BÎá׿^wg-•?H#CíA¨|n2XæÃ±O¹póµ.Ï xTš%ßÎ>K¡Ú’E*!)ý¶ð:û>m �`Öþ=tõ÷(‘&¦�hüÏN€çÒh|1šûíI…D 6Ͼ 1&­ùâuY&’hºÃìÿCÛÔ(Xå?™ÿóÙ SzL'…�½xö©RÈj—çeÎë öG�þãC i–Ë)4ÞºÕï앪›¬—¬½¤ÎóëCí¨z(Ò:LÉþÝ@!°•κÎGéÑYt)þ´Í›rkÜðûùLê1À?õLd~mÊ/Oå;f3¨±f0v/‘ÇðÚ=0ïÕ|ÆJz=@–‡kãk£Ö×_;±íQk89×WºK{©ï¿OiF]0yP—¨¾À…ž·Zòß²ŠÛ?‡Ó+�C‰¯vD•’á×^\Ô-Rö$•”oo彇K4�H¹ÏïðÃd¾cŒúêjä¾M WÇìæÜû!X8[½Ç© —uÃÍÓ'‚ÌßÅôØÞAl Ü-ø�1$ë‡cIqÀ Æ:9.-\üo®§íË´wÔ;˜þM¿¦{Ó®›?ànœ#öñø+öœz ݺ‹y&|®»¾9ñSœàõnGo…×%bÔšWÂ�Å:¬;ê½àõmWYâ­Ké´ñ‹ût3â#ëKþGÁ}?ôü}×Þ¥R**”¢-4ô: ²eD„d‹ìñAÚ¥½¥i¥$-Qï×9E6!+›ì‘IVß¾ÿÀýáõº÷ÜÇó—KeKîKÎ)|¤%i]ä�³”ö^»F{»×³šf}ÿæí©lyµ—dÓ�'´6zí}(… c{Ãó[pCª›63ÄIóx·XÚ5`!??ñÜ–Eã.ó£`äuˆ³k ]œÂUßIóø’žjËKT”ùᆒÇ�f¼óñ'ñc/¬(ñ†!±öbïKåà’nŒ š!tÔØŸ½£AW& Õ\úâ�3N®Ðæa_”Ñ'¹7öX›|*jŸ+n—ð–~ÁtT¸„~µÏhöÌP[¹òN޾¸ OÍ„�s¿Á§·ö\”oH?¯mð[ÆS`}ò·î&V­{�¹AlÊɦ·aÅ;¯ ðÒ?] REÅ`]¼�½£€�i/ÎèU$l7IEáɺ. qWã\&” M™z¼3>¶œì‰{Æ?§ôIÁûèåöú¤7‘Ó›>˜{Гýà%9½§9{GsÁ†{ÜÃå%™~ZË©�•°T;¸ü+ÅìjèØ¶ž§ü�€U•Õ0Ñ&ˆW±; Ëïþ+`×C…B¬V_+ßÍ—Ü¥„J ì?½¾<�¾.ÑBaÒXîÿy„˜ÛÑiÛÑø¬’»÷¨kD÷‡ÛuÑwã3}(A}ñn>¨ŽT¦ˆAZ/¡ÎÉ¥œóÈuÄ^üðøý÷*Œ?7Šê`ÖÒ3Ôª5—5’]àõ÷DqíUö�|¿QM¸ÕôÀÒu5ðÈ»qçóT,<°ÿûÙØ0W6·LÅØ¶^¸x²“°f¹¼u �ͯè§áØj}…¾xà, kTUò6ìvQë0¡©T2ö®.뮎kɱ´mwŽ p“´¶/¢M>º¼®ÓUè¿ô>dl\•Åûa†]¨ …ѳåÙé�2‡Ô‚/ó ¨°¸¿¦¢é�ü¤v“ø¢ÙJâø÷}˜8QÿºØsí¨ Èî÷K¦Î'{ø¨kçNãS…àæ)+Ì•ÞE®Ñ%´|÷zAÍÿ$Œ»E½ßSX] :ê=…[Î~øwõI˜{f d~RÄG_*hP¤¢¸¼W1©ê}£OÖÈÑwVñîÊ.šº©ŠÞ—ªó¹åÊÉýŽPÇoüeÎROòÉjw|z­$èî™H[÷'à]óÃ.ï »ÀÊá:ôÜCe¿pé¼>¬|ð8<?”Bš(z”÷ 3çÊëã¡)— �‹´wÜ2Ø¢¶7ÀXüúø@íÛcØý¥#Kò†ãð©ýq‘›,&-3ä†)•dXz‘e;ßк ‰è5qé'‹ëggSTÇ0Œé½R *_/¨ßõ:Ì„ÞTˆ†Xðëö4fñ ü»÷lØ1 �QÁÚO4yRˆÚ§ _ŸGp袽ƒQvØ6Xu§'ÔMzý^hò‘¸5Ôÿ.âïº<ð·Îäèì*pVÝJ>7Æ‘ÿÇU<­ë²¨T1†ŸÍ2‘œ11åÈ1ìû>]pß%<µs†‹Q¼GÇß…9À‘íþ¸+G Cr—rÛ%î£åÀ’³ü㿤‰ÔS: ›U²•Ü_±nK:G¸ÌÄz=Ù,ÿžp³¢Œ)å£îë×àµë.zG_·¹õö új�YÛWpHP_H¸ Ã5ºiœ\RFù—vaß øäéJ±s{ §ÛOƒû1îÑ ’5»ÉsÆ3úgKÇØþÕ{Øè%K°yáœ8OZLƤ¾±BÔ•c`ÿ@Wž\„JÉš°<„›­§aO«t&¥ÔÖhð�>½šv˜›S™©6sU]8»“Ž|Jƒmþ7ðå—�l8Ò òëZh¬v39§­ Éý51wþ#˜ö΄_E œNÅ¡ÌN_z×5�f¨€_·«!7¸�ÌM]ÁÔ|«0õÞ6ÖèÉ9éi›‘5{w^zæÞ§÷‘‡Àý�ÐÇK¬7_�­Çp¹C,øý›.F‘†_ÍÀ�jaØr E ÷±<ÃUžUr”ñë8YÜÜo—àq² ü8çû¦�6‚§2�Ô�ݯ´§“GÞqZ;AšUÊ?ÒÄaÖpÖü Zÿ:ËmêùôÕm o /ñ¯°G(;GÏ–qÀûK⣠Hj/nTç+ݳu™þMÜ›·C²pÙ]—€9™ì�éÂgMÕÈó~+ìYð�òvFñëèYèÿ.t:Uié²�¸ñ�"¾x´†'‚NÚwrUÚÌ;]‚þ&é‚{Õ8ûy3.m('‹¯/!îr$I󟦠ý§EB‚ë=ÚÝs¼M3ŸõBÏöoâߘH0Y¹‰äÚó«�.ì�bÌŸv_šÝ£^ìàõñSù‡¹"^�Ëç"e(pò¡,s)–r Ëé¯fâ-5*hq@Ðtæ`+MAãi/œí{_HX´'ž8.fÊ�¤Þ5gàÚœw°Á-•¥Œb»¨ƒ#l_8ãñÃõtk©.‡[îÂBßï4w~9°�'¯ôv9üf1¨?»Ïþ³ µÆ�¦õƒÕn|53MÿÿÇÞç4ÿ08…Ûð=ÕT:}wæK�~\H"«„m¸»_k¦‰‘)F|8ßy}}bEa’Ž|ügȆy&<í� צà¨*Õ.ã{ÇWÁÓ¥Aœüƪ:¸¼N·u%AÉ¿Ç`nG7Ã¼ÄæIw„…;dÀao"«ÇÜÇÝ’^¬5T®L^€‹-£°]wIÔ±ƒf¾¬Þ  �åà€þñ¨¿„çœA—^ìZŒ¿ ;I«õ0É…½#œ%ßíƒ[ಗM ¡c㢠aÅœžr ym¬r#†ÂëpÈÉpüw"úÈ `²ÔýNà›à¬¯í€§ä†Í-q˜Š€­-+©!g¢¤¹ä.Ù”µ`†ÚÞ嬚Iæ°çœ—þ�›Ô}QÞg+ŽõéžÑU™ôrÝPüòêLÜú…þ~Šg�ž`~­7ÏÊœÅw•5ÁUå<yÃñ£¬“yι)>oÿ~NšSQ@ z:õëÛD£‹}ùi½ži#yZ6úXTBƒâQXÛk8l�5De¿L�µŽÆ÷F�à{Þ‰O�‹ÆU¿ÝpËñpÌÜR&Ø-ˆ÷ïC1ûÙu<º'N*È"Çê(²2ˆKã¶r×�|¨¾�ŸLœ-yÝ1L8ÿ¹ ÒïŽäè'z¸§ øSçjÞw§Bl>zÌSƆ dò©»ÝÛ#ézkÝ�tdë÷wßÏ î/�`+|’« qþÂ8�~¸b»%øþnäuqï„ë‡üøhE"'zGRÖ‰:ûñ0D*¹ptšçu„¿<ù÷]ŽÙ*Kc×x¡¥ñe’Öo§­*‡§yÒ¢"Jj¼ÉÃçಮ¿ 1ÃŒ-®¶}5£‹ý…Ms4Yjä¬r´êŽ�{÷ ÿ¦XЬ•ÂƒŠ  04ƒ§9Š0±ÛOú¢M€ž=£šÞB£G½U[Ç »ÛºH÷ƒ�Ò” U]²8>a/k,5㉨¸¿?}­†¯|sɉסcÙy‚áüõؘzB’ò@žßžú@%2ÏàË‘þ«Â›òéV—}PÕgí‘ë1¶H% áô`h4ÜÚ8ˆß¨iáÔã>¬b7Ç]ZÅ�‚ú1GîÆÓo–ðñ/7¸ÓD ”àÑCÙt-e%~^Š™D�ÞIs6Î㛦œòzœ0w·ŽÞ¦—lÉÜÀúNŸà¼·gMè ŽÝçèO>¤�êWÅ#`ýÔûÞ”£ D>¿õè;âøY×aá³ üô@!%^,â}ÿ’)ÁRŽsmáòï0þ7«ë¤¸—u=4·öÄC�Õ‚ÃðJ^âdÁ•+þ“hÿgKÏŸ¤è£c³ªý ø >Ô Ýžñ8`Š9/•&Xõm&®ý¬ÃjùŽ8Î#_¸6.�eLF`ë…LPo�†]¶ZL­t*Å–k3?©YƒÇ†ï…—ÿMåŸÛuð²C;½þ0��ÿ-Àçß6SÅ(|<: åömÁ,»~Bºÿd|4€Æ |¾Úì¶}&V�³ÍzÒcg ü¡Ê]å²9ã…ž÷–¹¸›Ä½äúÀme¡Ð—[^ ¸O/”î®à¢«Ò|küo n}.Dåó�©½1ó? |$špzŸ,˜/'Ã¥ÀaÅoXáÊqSôE˜ôN‡ŸiSÓKaãØü;ÊcW‘ñšLÖ:|ž�­=¹ë)®Òï’×ÿß:nBªSc@&w4šÝv@߬}bNùHø¸f(y�wˆ‡fþ¥ó:ËPm>4í5¯Ž<²-6Ìt•ܲ¥h‡qa®Pý"G•?J{ñÔ¿#àÖÚž|ùÃlt=– ý‹Ä'�>¿m}qNA¤ä|±Ÿ˜RP aCU—Žñë*’Öø*1!‚§·I#’;$òöƒP§wmï‘‹c*» v_–†48Ó¼ª8(z¼/z ÕF p;³j?×ÁûvÕ¼3â;UÐGïîf“³Æ"߃Âu©GT)3‡•“dYOóªËÉÏZxJy¾Þ¿ŠÏr$Ø;ÕÃùŸÚéh¿u [DÊó)OΪüNÁ_KlïõÄ)c´iVb&¼Xß}6õ%‘Ÿª„‹±ßE�ˆôì@¶ i\z½Šæ¬°á[cqã:LÙ¥ÀûoÆb{_ ‰Ò¦#;ׇÐ]Õ§ úÑ//\I§~OâŠB±µ¯*;”jzƒð…ÓÃ`o÷ZX¢ç„…°¾Jš}€ùÖé’yËëIÚ. ×ý «¦ÀØÕ²è[¦I'æºpyòCšjÛÝ‹žI~ý=‹¡k;ÍãI¨aÓÈ!+ªá”b/N(‡èaá8#Xc½åŃ×døõó<š’·‚JÞ€Á’>ŒA­ðuÃEú+7+Ô6Á`Äî>N~YCØþˆÏ¢Ènß–Ö. ¥O]º´ís,ÙÌäï“¡0NÅùÅ’ôfZöE½«•´o¥§0á >z?Wøþá…*ª²™ú\þ5Ü�ëåÛ f·2qçßê[(SÞ6g;à|§LxÍ[HíÄ,V¾s Ô_>kT?»LÜ¥Ç gz!ך³Ó¢'tw¯N{A�£ßÁJdÇ œÍ�TþÈÍƒÔØêM;µ¿9 úö;ÀÜuNÚ+Àd�£d#zâ?Ë)ÂȾŰ5J™&vÆaCYªP÷Æ f™¿àø‰î\ˆÆQ=‚zAÿn#á�÷ ÑÇdÔ:ȳúñ?Pwj %TƒC¨7i¢Ñç¾H"‚pè“*Ô|úF˜’à@…�Q˜oM§�“XV¶‰Ê³ª¡½#GHú4”Í­Gà›23°Nh„÷š—`‡± ÈhÅS¶Ó\œlÅÏ öÓA!�•Å€¬#|DzN&,âG£¿Óð7ý1þÓfÎX~X�y²‡¿éE¸4Œz ÿmâ×µKÑ{ã[Il`?¹¹œgâÍ`ÔÏŸŒ^•CÝá´8aÌ*w£Ì·qrîdÚq26Ûrnð*\¿Æ‰[oQ¸“6¦M÷d•mBÏ÷a¸¦ê§`­¾N(Ï…éýU…_<¸5" Ûv¿L}D•÷`éÙ¹ìvç¬Ûi‹ªupç¤b6W,((ì¢}†7AfÝvòv3àEµ;D Û/0®¹êVå’O_yžý:•ýô‚”¢Ïî àÝï-xÉÕg¸Øû¦x2aW/¨NX5Ú®k ØL™5Û–“ÔÓé°¦ „zoéƒí/Ø¿p¦¨•Z ¯RÄ”Uùd–,­µ6ù±Ì*Î\2Br:#‡^ÞÃkFÁ}‹Xz^öš~FÞŠï¦úYOñ(üûSMT½Õ€ì7‚ÆôF> ÛƒwR&Ù¶ÿ Ç„…hìy�~_^ŽÚu1MmÊkËPAF‚pqQ –·xÒFÇý¸äWûGMÆ _ y™Ÿà¾-Rø½¦Kô.Nľ†Ò·P�¦Œ:ÂòË1¨Á’¿�‹çðúãðÅ&õÓ¬ù{ËBNi2ç•Á0ô3œÛàˆF-¾lµð6m”/¦®ÏRÐÛRë�3àQ‰.ª:]„û!–¼{[6-,YÎ~^·pÒz¢�³"Á5hzŸï¢Àyñlá¸[„ß>˃ÒLs4ìŠý>wI¢Ž¦“~ÂÒò5e—«¸}vOè’,¤ã7`‰ÎQ²›…N{á_áÌÚ#1¡UðRkOp®Ûw„ ìãEX 1ý|Rº[·Û¡Y1°¹y3ô¬6à¾V'à�¦ ¨Œók�q”«>gežÅí;žÓ„åPÖ°Ž5l¤›yv\>í¨Þù!ÔXoÆ-…NxÚt ôøM7µ7Bågãö•v®ñÄ‚ô´µ&ž¿Ž�š@‘êŠ÷C¾r$Ì–QåΓ±bl ^ûæ &Sò–M°ô¾üS á,›« */Ãó÷àç„f’Jn¦?öÚd9s Íɸ*,—��Wg§ðÊwalg6¬G s oÄ^—Äuó°øú8¼w%ûö0‡¡ñnÝ9º™ÿID#c-pÜTãoâ‘Þ.+�Ná»Îþ0|s\6©DbÝœC_òwQª£%¯…ÓxðÈO‰÷£v2¹ðŽ–ÆÂq×›BúeWìtßAÜz0ñ߈¥úñ’˜Wd4a·¸pUüf¾†*ÿÓc\äö’Ï›5ðSî\xÖG™¬öà§eYâïÔ1\ïhÊçš@9¿''u�§ÝyGAÉS…�Ts)€\ãº;åTüw岋Þ�âÁ.%ø�n†ê«\¤¬üðÙÁS.’½ ÷Îw.)¥ñ«žÐÛ¥§ÄÄ™J82UbûT²N { ñ�Þ@ìkoŠÎï²áfm1=23¦·3Np}À4¾n´B•RÙîù2ó6Ç�GøëîªJlCƒs@Ö.‘S+„dU7>¾½jN u-¤='|Ã"ƒ¢A¦;¿wj‡ÐÓh·Ö'ð—·—?Ü�«DIÄ™Dêl¾Í�¥ðª¸,² Í;Tûò90€¯;GsÕ‘ ÁØTÏ >"ynSÖÊqþ\U®M“Æ3ú¡ðÄë?h80—Ó­ÜqÂvM¬Ýù[˜´1J äÅÚ"M»¹{æÒÔùÓÙó?Oœv'ïXß�†¸F²rªÑ¯­«\ªß—@|ñ?*¼×SsLœ?Ç&Éþ>økÏ>2õ&ͨ{Jñ~}q€ß hÊv"=¯{5¿{Uâ1“¹hQeƒ�“nОك1p‘¾pÔ(§f†ÀCßÿPûÐ*2ßÚͶiÑ�.+4ØQ)¼hùO ÜÞϾoÞíb#}§4œÁ‘½Ü1lfÍšÃ'?; Ûfæ|‡8çsPÓ3‡'À®ô>Yß*³åàÚœ·¤YÙ«úAŸíq03‘Á¬ —$r¥Žíw ­@µ§1—j8‘�ÔtШ¾IåŸUIÉ6šKÎÛqCîNÜôù­(5²ªo�†÷Uãi|Ý`>yÃïE|�Q…»°eYÍã³’¡7Að¯ibCæMú]…›?--»a|^&ìKñåÅEìx¼‚h„‘™! u.)éeUå}ùÏ›VŠ2�¥"yÀ{²‹ØùÆCXS~ bÖÃüÁ5Œmn|ýª Ú­žA©Êž´\ý�øôŸ§(öƪåâ»í¸f]*}޳€£óÇขg´½¸Dì*H>¿+§¥qcÙ® ‹Ká°­ƒ©îÝ*Ê�K-tQn\ „ŒaÃÍiRü!Š»~[8Þ³'ÚM�¦ï7�Å3mN¾=†Ì÷Çm ?JÚO÷€¢¯ÍB�0õb÷JÎûeRá -žà3l·Ù]›�¸Gl=¸ÆD‚ïÓbrD/v œ€C[_�Mð-!.>‰ m9«Á‰�ÇDcšÌ´ jƒœIk¡.z!F­©…¸•vøÜ÷�ä«ÝA”áOQãaç€sⶈ�4Ó}9™ïÆ®Õ#¡|È/ú(ý oU¡ÏÞIüqÚ5€„£äù6‘d/ªÀÃiVpdPô¡NœœM±3‹iÂ*yªZlQ÷Þÿ„9žGåéû¸Oé`þóW Æ9qÇryj,Ë¡¥GÅå—?Òþî ]ê,Jµ¿‡”s>´en�hVwîÉFc䓵ô~õQÁ8KÃg‰?c!ÍBÊ{ðOœ¦,º¬I3Ç ™)üEÂ7Õñær�Y½R›Úc£ ¢ãsüwJ�O¤ AÏú¸[-d¹åõßkI!¢‚†ÚìC¿^KYjßUÒ}¿‹ŸIÚ`j’ ç�]ˆ¹–š_bÇkÛùAU_VÒ»GÇêâkµ{ÉÊÉÏápbßSz’­�öõ�.}úzñÄ Ož±ºTX^•3~íñ×Cµ¯ž,]Ü"Dè´BbK ÿå%cl°¶!Þ´„q½5Qæ�‘¸ñttmŽJ‚äìÏ1x•¢Ñ÷àkØe;Š ¡+ó"¸nˆ[,yú±µ.*öè�ÙbØô“.¾ŒçÄU?àÛÜK°:Fb…2zpt¿è»z]ÙIÞÇv‰ƒÕPñ„løõ]“Fz/Bל|ߌÎ7ÁñŸ³Ptðù¬Ä–¸+÷*,*Oàcr¼dç^SûÝÒ׸)á'-ÖÜ/ ^åÈÅB°ØÃ6-¤¼n»6®åR×¾>Ôö £Æ­táÍe¸v¯ÛF:`Í’mœífÄ‹GDóŠwrÍÍ#kÅA4Ú`š®£üûÏàQ¯õ¢¥ù+al[)-œ,í®=PJèvþâpl®>Êê%—ã0æŽ .1¯¡�‘zpóÞDžÜñ™ÄÖŸ’oA”u(¬ÏîÂÄý›Ù]a 5ºÍ‚™ äõÑÂa¯ÑŠ/C¨âòWR›’�¥3ôÑЯQXp¿ÛgôH%D F¦ÚãЗUbyù(Üû¼ÒŽFÝßGáñ’3 wþ°x4-O�^™ˆ�³´¹%v�ðì’*Öh*R¾ù)‰ãÝøÛ·7ØS��ÊéÒÒ¸ô¼˜àÄé#œ„ñþI‚µ’7ì�dƒÁ’<ƒ{/0Â-wL9° *Øè™¯·Í#^7�GqdH4!݉ÈXQ¿×XàÕk7¡Ô,�ƒfó�qãÉlËSÊîueÞ „¸íj¦¦ÃuYY;O´Ä£¬½ÝÝ÷¡‘BÝ•¥´¥Èƒ[5É}�nR�£Æ½Ð¤v�”&À”ÎdPLÍKQÑâDºî•ŒÆ'R�Â)¬2Ï5ZÔ¡zž>¾ØZC¹ªá|ïßÊ·rå�­’iCtùu0²é•ð8êÙˆ�âªs0ƒ¬ÜÑXÕ½Þ¶@JÂwá×£-<¿EmO\&×éÛðÊüC$g[~õx¦î =ɇ‚£X?Þ ßüÙO‹°éâ¸;·Œ6þœ†ÂÅ%;gÁ¹/…´¼@™¿–nçÖÜ8m ¾1Ï*^ü’Ÿˆÿ½É•-¡v­]ð Dާń‘ϸ§B°Ù/š^b†÷5¾‹ë4«$iwþãNÓ¹—5¬ÛßOÈÐ[YØo•Ž¿V|§Áâ!R�Ê„ÿòÖò s~|O�gÞUã1Ç–ñC…“âærc.V(¢×³†²F?kÔ±Z-ÏŠ+/÷D,«6á¿Y øút fx�Ùçð´N“ó‡TÂ0+|0m*'9>Î$·»Ä×+ñ"Ïë¾e*—ÚÏÅ^Vý¸Mc*¿ûz�d“à´åM,ú1žŸ¸Å€¹Ç1ò=—†Ã«v¯�ûQË ×¥uÅ\¸÷Ûœó“>Ò‹û^ì¹ENèÝO¤ >Pˆq8¾\9 Ž{LFã+`âœ(:5M—ê�ÜGºp» VÆßÂWí1E¦HÐ;-ZìÁU&ÖZ<掙¢\gQgŲ+ö“£1ê÷u¢‰Ä¢21áñ¼ì¸Nr r#¶_ÊK*µ ×(&ë…p[�¯Òƒt”P˜â&>¸b�¨Ðƃ̰ï9M~5[¤×Pý 9vl̯sàó-R”8âm¿�Š þ@}µÅ�7¬­*è Ôk 8~ë¤+S¯@»ô0¼[3‚åÞÒóŠÁ8&c:Oÿ"¯ŽÎ3µ�ZCÐö©3Ý›Lõ—¤¸£ó"¨ºYS§wž\äÅ?{fC¼Áqt]fŧËáÌœ‰”íÅ_W–Bê¿Ý,%ýÆåÏÛh^£žD)¥9iˆ=§µÈ°”§>oñÑÄ/oUI·í¹®^À¾‘yð`ØOQaÿò]ÒR9ˆ÷ÖÑ…Qä¿c>e俓ӡèM2'å1”&»Ä*ï£M­!´^'‘÷ëí%[»Ñ4õéQáKO o ¥'%¦¼jÄÞýZ•Ü·¹Ó�}Kqæ{6×úBüÔ�g'cäwsÊÙÔKP¼qk5јíëØb¾"ïùI#çзWŠœ-Q—YYà‰E–è:HƒÃkjIöìX/FAÃücH5½÷Q¤=÷~×»‚ÞÑxñ±çV�þ’„§µÂÍÅ”�_èí XnÜ ~ÆbÛªNº= ¡qûvY:½ãÚéDä)’ÛÉ#G¦ð¿›p‚ôgÈ·wÄÔL®®ç.F¼Ò>”NôœŠêÎM,•Èþ'Æ ~‡;ïôßDNûOƒc—_ý™Ô¶7AÑ�pþ—˜²ƒo o^WÒ¾UçY³åèÌ\ΣK—PöTiÜîW)ŽO|FÎSÖ¿éæãŠ�Ç 11 rC ðœÏg ·�âjà¡Æ"|',‘Ñ€‡j‹|ñ*½¿˜-p½HÁC’)Hv5¥ÛG^tä®pyšüW*.?"Ãf–ãYX“ÀO—‰£&hÕ9ù5AÓ­!è,õœüÞ BÂOZÙü—Bõæ1Óo†¬SWîöÇã»@sè'É2÷**U­„Ÿ,=Þ[01—…Øí›àšU™Sˆm½¾Ò¢Ì, õ?L÷NÄá•5{DKýçu6­Û*LõÆÄ{#9µT†Ž¤/�^­ª¨¶OkûéU¢*uR(•[Nš“;Áý°6ßÜäÌé·c…3MqæìixÙ:\\²% åf:C\oþÑ/ª}v³ÏðEB? äQ™ÍâŠÖ0}g(ŽžáC‹6+±ÆáT²ä~0&s,v=�qÉtýMûãFïCÐ/ô«½òÀ¯'þÀ‰Àyðú!qY—%*�qiëÈç6‡iÞ¢‘pËò™Ëç.ühñ+˜¬!Öéýn.€ ¥Öóeƒé¤�«Êß¿©QïŠhšíøqh¹&÷ãÑ>øÁm ]®B™.}Á…:áè¹B éÄU#®Ò [Ö)cŽAdÝPÅû?»}òÑìOOt©.~ZVŸóJqUÎqàz}ìHʦ¶�µ g½=Û pd‰ä¥N"€x6ú X¶7SÄs}Øô£–ëö5Þ¾b½XUØ<«–aÏ‘Åß#ñjÐ`œÕÕ #¶ˆµ³<83îuI!¯#Ù´5d�›-7ÆÐ•šÑ?ZÇØ¥sߟnü!£XüQ—Bé'ùóþÝôÊô�Ð4D�4ÔÇ¢Ò\WðzjÆ+ôOƒ� |»Ÿq7-Xu‘,¯‰/„"#UܼʉäÎ/ÄÖ™)Î΄_NÈFr¸^Å3 "0£&‡Ò¶êCy¯Ë8w!4U¢Û¤­(}÷i=žƒû§ˆ˜WHc–bú6wÖÈ,‚ÎÇuÔø0E0j6#1&Mu)è{þ[ºƒL¬[È=ÝË·ÊÖ€Î?–oß�ðs0/¹RG®“–á"ù·PV¡'Á‹œÑOwǯìLòYZ⸻éÌøVqxñ@ìðŠå®‘Øõ”/¼k^Œ*Ööü<ó1ŒqÏ÷¿‡uŽöE“aÃñµqkÞï6ÜÝëb ®Ïë®­e¸yÆX¸ð÷|MòHpáž9‚³ñ71é©9›?;kš�P‹ª>þ­š�ÃBÞ¼o ‡ÀÖ¸û)�Ò×��Ú³`¢ÆE¸Fœoz‡ê¶Æ‹Ö±Ïà0ZdÇN¶^X–:/Þ>$öÌX†ãß§ÐÃ@>·l ù–l ýKb]*û¹¢UZÅÚÉ`ÀýËÓ“µß§ßåãi½‘ˆ¶¹ ,t-Fõ¶çô¡è°øº²Lpo;N‹¦½¥¥¤Ù:4 Æöæýå2°b°>Ïyóš¥p`w¯lju†Ïõç &¸q—<{ïéÆۚhû¸01=PNrûa ¬Žˆnk×àŠ9é~n$·wÃ÷%³¸vÊñàØZ6Œf×t‚MC$^î̧Ç),¬üølîÐêù‰|ok%­Á¬U¼ÐÏÂÙ`óä_à¦üœRŸ’ÃLJý®wÛøå>±/€§>k ¿ý€Ø«¶°!MGù�ä ¡¿à[å 0ô)Gë«nð3Ï“ýŒÿR­ê+ÚP3Û:¿ÑÁP=nÇßdsÖ�î«,† ož‰Îrr<»{þWZÏçy þjH_†Å‰vò´ça/p÷.‡÷ :|Ö_Ž;ëÄøTe˜ºÀúz$Á­–58îw.:mCe²Ôvi#ÙTUáà?c$_†£É9M|0¶7ï�Žo SØô¡ Ì:æÍ¾ áTµá‚dëÄÃðÉ ì•Øáfß}UÐí½›4wÈ|‘ùŒ./N›"ÛÛÛk]ˠúgÄôÊ2‰ãÏnsWnŹ«íÑ÷–§$wp^ŽÝGÿÝØŠÖczðº+'ùüüK¢†¦”>tàM>%Úc�0£«ž{ �c«{É(ãÊg›ÍÉaÌ'áÂ1 N §0ƒf(® Çé‚—| ¯²ZÝEd4o!k�+'Mâ3©q`u«J\ü˖ݲz!5Šë£Ì@f¡*ò4}L²h„'N]iÌFl‚ó׺M«ù‚ðÔ1ûûÌ$�‡{ä _¦ÙÑ ‰g„wÐFÿ¼|]eÉÒ3Ê¡ 5ÛØG!ê½lYµ“p¥ Ã�%Ôdé–ù•qá:=~l€œ6Á8Õ"á@”uåÁ”®}xV¾šM—!�FùœosUÔÙ�zùêp¼ô½Ë¼Çt à@o)Ü?N}¤½³×�¼NG‡µPŽŸ'ã‘^¬ú֞ǿ}AãNáó¡ŸkÞ} ,Ë£é–j5…MÂÔË—`õ�p.­'¦¼Ðår÷¡üÀT†{—*ð:VIú&„«Áke±ß¥.1{ú`¬Z¼›Œvò‘:gþ[/àZ…~âmi¢·?T¿;ÌN}…· A|Oµ7†Æ•c‘G8Žön'í•Ql±y(^ ã+yñÓëõl9Ê÷Åô¤Óâ¦7»iõ篵7ô¢;y¼ök<ÇùÛà·}upÎÌ3–ðƒÞøÖû ˋƥ_ôûý!üÁg"Gž¶¦ |~w½êWmNæ — i´GE?7¦Éouá�¶œ*?&Ž÷èÃEi[ÑÆo7Äå=�õ¼pv•çªE�üÑs°ÈÖÿ¸”ÁêîŽ�(i°Uš ǾH¥#/ßSúmºÒ /6Hh¡¡½è½Rš‡< î”—µM3Å?1ËIîímòOVÀý•.dÓ :TÕQ~€+lÜNùs¿ }âK„öuœáåF^SÜ(ñþ|”Ñ@ë7ˆ"; W-�Μ͇*w |{*:·çÜyÇøzÔ´ðLÀ˜ýæ8>¹yŠí’ù"ŽÜT�oóJaø¤}ü#m=~¾œêÛ•�@ý½$186—¿5Ôâå•ëØ·y ?ZùŽfGÞ¢&‡ šžŸŽ�^�`ù#Íô"þ4 Uƒ‡ë´ðx»3[†_ÇÇ“¯‹ÏÇ'áÄU÷!hËXÜJ×;ç³îQ˜ÿD¿$¯¤7%ð£áeËsœÙNÚ2'{D¢ß–á¸íÑ{­\%Þ_^/î˜ô—+N$;�lg{óhq|=¡oä:úr°M08VJ·?ÚÜ-0Ð*š®Ÿ¼KW‹ã¸ú°9¯0]"›a„Fɽñ~¯D´®ŽÇÎ]a„ÔV:œ0û 0ÃÃ!±l[@�sŽS¬×Ì�wU¸šÂ:÷Ñßhnÿ[%^ªjå�yal8Cšæy8"ì('ó_“ÙrQvf^§5�¢P¢0�æœßMÒK¹¶5…m¬¦ˆ²£e¸±Yž]ú®¢>Û.ñ̶µ´ü «Î¯ãÛᆢ@>zþôq±Å“clèI^8o¸S×­bÝ¡�àõË¥û ¹O» ­5‚GWTÓ·CÌÔiñvr-žþéÅÕŽƒ„¿Žß„Ù�n,鋯æA�Š·w[`Ô¦ °çÌhp7m “sâã«ÏØcû P0‘T˜`‡B‹$ÀWšzœK¢ÿði=YŠï*+…ëÃ_ÒÎ)'ø§Ó¬Ú»ôÖbë4eL¹ÿ²®çRA¶È}Mßj¯¡ô›Zj|U$èÂüçMXë~ÃîÛ±”!Oüý•\®Æ ¯än€‡úZ?ø0-ß}.nüÿõ7ÿ–øƒ®j6ÌR‚…gófÛPš)Žd‹Tol’­çȾ§�S.°÷W>¯Nã²®Kv4^£eò>Ì/´a£ñ Ò\Å»2+1æ§g$�’n?–¼[Ÿÿ€¶ƒŠ¼°½Œm”Å“‡ˆ7XiòéÏkÅ{›çâ…0‚GšOhÉ×Drå È&‡Ò¥É×@«çIID·ÝòàÊWsxkøYaL@‹ËYbüU]n8&èUç@Æt Ö?´¤† ‰0£#MýÜðÉF¼?h×½L%·¤“b×�1 $æD«·d{ÞSŸ¨àwEG^ä¡ ÿzôàþsX)ÕE�éyBÊ´ø½O/ ’ù/Éõ}ðïƒÓ4dàbLŠÉ§KÿÒ„c‚$§Ü…°€pN:\_eOqi«=_.µg›Èo¼ã£!Ê7Ùbnp ÎZ·À÷¸0TÍˆãÆª€yð(n�bǽÒë…yƒM)´²?/û†Ã‡þFãÛo©ªûÏ©”c%¯˜ý�ùÙ…·ôÁÐ ½ÖÿG{wýf—j~ð’“4PÅn2ê|ù-ö«¾F™—µQ¿öŒ°ª šcÑoàöCÑ÷^0*^‚ÿ^‡ð”æhL=V«ÊsjcæÊðMŸÛ‚‡¡;×Úerí¹ ¨ó�Z4v@˲.7ÊàŸ-m’ ;nB’å^¸­âÆé¸ÔÁ”¼Û·ã‡c]°¹ÏyH콟‰øüa_¾êÜÈ.½˜çt«)LP©PÂ]ƒ†ðÑÅËñ]ìDì×ü »¦½¸„áoÇ‘#\Ѳ–i0t¯¥÷›ÍÊNBØG”3ÈryPàŒ²AŽhüE•÷)† s²jU‚ÍJs ç€žÜ8œ$†Z¬Õ< ÿ�¸N“7îþW[ÄÊÞå\”XCy;ËÈÙÄ1^ëáØ«4PIž„q$ÍÿZ?‘”ž6ë$Š££ ¾×CÏ-üOÚÌåË´Ã.¾éL‹kêÁnÐ0Ô”öâa¥÷éÆ[_:ž.O^æl¡Ðc¤Ñ�ßäþªeœ¢ú›Gaû¹¾8\a&,ö¾ƒðÀñz½«'%í ôÓfÖ³¡;aÂÙ‰ôHŃ9ÝnÈ5ˆA*‘Ô"±‡Þ–ëðÞ+oÒ'ãàè<ð•!ÿ•’Å“¶‰´a×PX�A�¿égâ;83§�Mñ&­ æœfz‚œKFYù¡(Ìš 9Î<+Î�õ—ôǯOò`Q…?Ë›-‘šD4,ØœGöà)öáxr½ŽøUo8‘‰šØËñ •zôÙ2Plù9ºfG ñ«S }öwŒù8‘Û4¿À�è9(l‡î“ï‰'çä¿êN6#�Òv,ÛãŠBÿd9Ξ×Ķòu’ßuÏhÒ¶«ànЋ ݤYp¿LÙ½W’[¿¸´ì{ü¾BËÎ!×w=ÆŒÇ áæ�]tìLv[V—ª¤GfV�ÜÃûâõ»éGPZÓMÑ7ò¯8âù0jsn¦×S6ãÚãïÙ©µšîrÄê0 œbE�3»çÚmUxy3 �6 å·ým¡}B#LK4¤�'QœóLÍŽ¥~½ƒ„j+ÏwéázÕM\±޵ùp‘ÃìØzˆ67� Ùk´eþº'ÏöÙÂÏ»¶¼c½ ƪõ£2©DTÚ¹Ÿ…{Ñ—%œó;Jâ²i(¯4}(?H`Íþ;õ,¾T.®>Vksû &µ$ô7òbËûß`ÝŽVx]ã�þ\ Ù ¸@²‘òîf`ÞJyIÝãTœ÷µ'/õñ#jyÓöÎåDû5ÔÐw.—ýqæW2îx³Ã ÃËqïh9^«±�æç¾_g9hj{GýŠLé�WTϪAÛ£®<~î_xh¿ÞšõÆS øhšû™ôçz™xù€3[Øž»å½h³™9.þWIáGð¼k Æß ›çË ÎuY< üN¸¦†I�ÿA†É2T¨;É~·Æq} >:Ÿn�Äóè€�ƒÚ\â¹('K�­Jú…'ÂçÁ±QÓ¡nE¬Ø¦ä7N;nÊ‹PÞåw\'ª× -7¦ð‹Í¡B„©–0÷?ü‘Íc[¤ù¥ÎEÔ)#áôXÞ¶Ó–þ¶Åãþ_ohBð\¼.Êå£8xz+((úãÜy}Xe“püœ;Ëhý¥?ÅÆâ¯¥¾Ý|E0»sŽY,†ÿÎNÆc“6cáøòÿb 5ö]€æ÷2ØÃÔV´¾fJ'ã§Ë•ä9#†oßœŒßÙ­Ä@rÜ/ÑÞ°¾„dWäK}»¨X}ˆ0¡µPb§7 o ´äQЍŸw]âk:¦khó¦-Cðã«Gí~�~Ü:H sÕùšúp𹤆Aÿt15'‰F/Í‚s;9yå~—±ÞÚb^½‡Ëõ2{ánã]ˆ¿k�탸_Z\±•õo_ÃôÃWÐÝö‰P0Ó’#~ ‚®ýjñvõ9è§”ÇýµêIqÜr–yÓ�Ô®‡£Ç$mÁâÑ>Œ]Os$Ó¶,Q:ÊF¬Ž8Àsœ‚Íiï±ç×p¶�Œ–†OÀ(Ÿ£TöE™³ž]v©Ú\IaYqÛ­ƒ�ù¬–F— Ç…éëx�±=èÈBÏáªry#dÞÉF+×`QÓõ¤8ê¼f� ¡dËlv][ŒFÛƒÈÜ«'þ7¢–2>Hqà&E®?4Œ/JO§ÛŸP¶ïLÞ1÷w;Aå`j,¡p®*´mçûëzP˜|Ì~,Ë��Ý={ìŠpuˆ;§$wAµñHnz¨�#*$ðÕë+ýãù;´jÃ_šy¨/ì�[-Î î#z]Ë…zš|yÎnlìvʵYÓÙÞV­®ð¡1ú-yæ²@êô81Õ ,8ur¤¬à=®º|Àtã¦8ø tÈ^šå`[D$Ÿ´Áë·ÿ‰µ}ÐóG.üÞÐÁuÄŒ•Ü+`O~³_-5 -‡—ÛýÀ–�rÜ©¶€Û2ÓùSÐ5Hx�E_M ©¬¡*ƒpöä âÜÁhU~Lð�Ò…Që�jþÊÂÆqg1XÉî:ÛÁ×)…Ào]᨞ ¼ßÚ턦b¬è1Ïî¡Ã³GqÓÕT²›ñð§#MŠ ç†ìêÓ¯’NDp@S鹟Gë”IŽÝKásë\F;¬c×Á»éyãjt~•ƽƒm¨¶¬ô󆽬…–é§iÝ›!\xp,·¥`§$‰~ý Cg¯Hšúò žÇ…~I‰8¿ö Xî®…Ìü�ètÑ…ÆGk‰.±H§™ÉÓ`’Õ?HSͤ–m#ðžÆH‘îÁÃ�OŒÀ/‹H|´ �_!8.‰§~:é¤Õ÷`Á®f˜³Ë[ý2� 5’(a`ÖM ƒÆ+Ƹ«¸™®Ì›ƒ/Ü©ùÙSèÝ!Ï+.|ÁwÃ:Å«j§ÄüþSÑ»p-]Õ•{ϧü6é¶8èt´�·[ž/h¤âýYÛ6é·-Ï1ÔåšKµ4æ”'|X¶„’>šÔÞò´£‹©>$^ŒÒ%y¥°T§8„�ÂxßhabÄ…[ö2Ï—æM‘½%>ùfüj%âºÕSqÃÙߤÈB2<ÿ ¨×,ar—(96, ž—çY#Fÿ�bó|èñý⸢´´T„†&i×ç>G2R©l!+»äkeFÚJ»4¤¡4„¢aô¹Ï‰Œ$Ù³ìÙëç÷\®ë}Þçõzpq• þÛ‚Vko\¿aí¾YúJ4V;Ž�Ïe!êÑh\®³‰-M^BkG.�Ë·Äš3>ø·‰G…c×Áé0u¶<IÚŒ{Ëa«Ònt=Â�ËÙÜv’p>§Tøã8ˆ?�»å»ø»:ªä¸"w íêíÈ[Vñ;K ü=v÷Ú{œö>PaùÞ;/“mÝ# sûnhO±M“ñõKkÔ}0‹J5z£—[˜–—øÜ_Á“F:ѵL¾»ð*l«öëU!Ög– +K®!>yFVéø¬Ðœ¿%ucóøW0þ¦’0u£*%^IçÂGmÔÍp5ÁÌ,¡¸r(o^h”À's¯�iä!ñÊÜ{Bv„Në´«% Ï uü=~&§¬ˆzŸd¬üv c^ø ÿ©ÿ�”ñ†(ß‹ÕbQ¤-îô†N‰¨±-rþ«]9Evü3ÚAºn"ûÝŽýô½" ÁþùcëXÙ€­$ªx´Õ›+êzÐNþ ³jÙaÈvô^7ŸNˆ—¼Îô¤iŽéð½á(•®Ö]¸áuó'TyC¥2º|jT ­š:�{FqqenV<*Š—ôyÜ®îBÝr9nål4�õ”vœQâýÁ“ð�FøÙí†ûïŠ+4Ø%>¬î˜²?ËzNV.-D«Þ OJ[¨nñÜ–×IÝ”j`scYµt¥.ð윱¨lK74Ã4݉\ÖºöÇ~£z“õdü7I¶»#+¬ÇÕ5æ} Ô’{ öU}ÞŸ¬ÙÇá,á™°{ä]¸Y±«ÎÅ`ø[{žbt Lg邦q�Y-(ÜWåÞ!�ßÒ Ï–6« Ó  +þº¥7züUD»U»pø�Ùt$Ó _�7Çv=gm&ÏÃ#_ñtï ûÇÿC3ò1æSËÿÙ&^ÿÖ">xG?•{ ¡ÚìZKÒöÒ„9†0_‘Kçwg_凰ú�ž˜ë¶7ÌúI—¬¬05|¶Eû \L!šl6ÀjÕñ¸ºY]L}‚Žuöã¦r,ô?)~pêŽ}Ôø�«3ø~ZHÁ•j˜T{F¶Eÿ†Zx(gì�Â�}:#góyÏ™\n1‡' H£ÒóF|5Ñ„�ï¢U44º..:õƒâÏXÐèÁyÿ”lšü5œ:†�áizó¸|_Œ÷ÈwÞ?D¥+u¹ïÅxä=’êÊ •O_:b0kíâÔÿXgÔLØ| ñVð|š‚'KÐo½·Øä w–7‰ZƒŒùíCwôV×¢'no”ÁÙ=FHÎÕ/cg¿œ3…É6�èé^›>̤ä�ª\^ñ›Ž€³puµ—$bU+ýÎŽäpsIb¢>^Í)7½PaiªÐÿÖ|>bÄr²&Øúñ$=^ãï'öooÆÌÓgÄG{ŠÇ¶]£–uÓÄÜ®hÞºÿŸß¨«RÆY\h_HÏf–á-»ô£ „m²w@û„jÖÈù6F¨Ø+”õRç(ÃoÔ[KzE÷àȈõ¬òØ�O|öâ9.£1R-Ôüƒp…«ˆU¶pkº'}$éÊèÉä/dÞ®ÆdŒp°v*öÙýæm¯¥íëQÛ~<®°Ò•~#ñ…á&¶ýŒvï³EO¥|°ËY�ïCDXsR„¿=0æj.è¥ÓÈÍ“°ºICõÑNx&^¸4g-É�FOæ§é÷ÁôÈ-ɯÎfAÒÿ%ýæß}oÀÇÅ&8÷ÙîzC ¶æ&×IöÞPìýèTÊ»cëïÙ8çb9Êžaý;º1o,¤õÝC£‡-�­t8¸B½Ôaé¡ XžÃ&ÍÂÝ{`EÃPä„hˆ(Ö�EFfàèÛ‹OD4j)î„ÝíáÉŸo°¹¢ïU^€»r YãË<î�÷ µG� ¿B«˜?j%ßÜ=Wöm [¹uðyã¼o3‘ûk&ï (Ér-ÔÓd3¥k €GS�зð%Onèàk!N+:D�(ùvƒ “Á“ fÂB“$´4:°³Î*\…@ ~´¿Hã&ajp<µ\…³°Àä uç·Å�!˜X›‚Þ3γRïqø®| o�²ÅŒš‰<;¼.v»ò«p µÞ.ŸÀY�Ñæi«˜µÿ Ï|M_~¦ã¨Â8>cë s²Xçø˜äkHNþS„­C�À+Uß©÷býÍÂ]!L°¼ß@§ub©aÿVö¶Þ€EO{K¾(öÂ;Þrp„tàMÎ>0 ûŽxG ÖWKžéîg›úÁ°îàNލ‚U3ͨ8{LÜ ¹ƒû�$Åèí¨{¤ïØ!!¯Ã>è*S+XNz)<1ÄxZÛ\ðKðZhÉZ…Â�5·Ä±ƒØA‚èö<‡Ž�Àšuãppb%?©ë}Òf É?ŠÙÆñ¸á¿¥W,ª¤0®®=ÈçŒtØcN,h‡=–,˜û".‹£/Âé…#PáÇpì´÷†{õ莲á±ð«t?åõJ�™³”ØGu64 ¹Fëö|�çP†í_2[ ±tx­O4©NóÂò‡t¢r¹Ö÷ÅøñQŒ=‚ñ‘Ä÷6× �V ü­¬Ä/ e´µn&‚4 L˜Ç�›ðOs6/2ùx"í«;´ÓC5Ód¾rî õà­£ ãdíPGï&õÏ^ÍwD‡öÀ—oòùè'‚É�îXÜ>–eV4ñ‚>§àjÞuˆ;¼ú?è»ý>B¯A~]!ÝÝ´[0X’‰Níâ)ò‹éùï>¼~»÷nMÛ·ÈSê÷Zœ'YOsݧ/AçàÚºŒ#Š(xœ<æÍ¼Ë!Kg]|tx—Š‘¤Z‹ý²wB[Èr>»‚OÈ« Þ›r¯»U¦?µŽ(ÀÞŒ\±ºà �º�„GöÛå8”óðÏ)MÝ’ÀÇ”³úãÜŸß°þ]hû.„“jCqhº‰èiÑ“aÑ,˜Vß’ׯtWé2_X½•—>Í·xâGU–ªîÉ#£ï‘d;ÇFX‹ûÊû3Ý=.Ür\›Ot£{ãˆÓg%3ú½Ûf5Pçtžù=޾� C×­.âÈvyt;^È}¨`˜¦Àgã´¯ˆ(±çÒq8iV �´ñ™èˆÑdcì&è Í“Ôzçàx¹i\32 ÅðÌMûxîØTž@Êo6b„4­Ž�¦M—HT3ZÅÉ©�Töé�Ô.âÎ.ýsSA!ó 8r�D� R³¬æÜî˜=Æ�ýœ'á/§“,5yo²ïRiî\ðV™—¸-©[ý!WŽ3„a9°oºåîÙ‚¯7� Rë¼ør=ØéŽ;C™Aû=«Yþ‚¯ &˜Ô#Ï–?å³!%ôð…#‚ƒ[ö y«`þbÓ Íüœ-l»_�'4—J»¶-Ä/â´%³áûÕµÂ-Û“¤þ¾Š-åc¨Y·‘Ö žz#xSl8e? ý·ÓÏ€Îà?ˆÐü ˫ׂNßdz•±™‡Fv�Nm ü²0ÆãƉ¢’u$$U¹RTA xÚs•y( 邚ëN|Ãdꨕ oš­Åá"”ì±Ä¡t~}”:n Û‹Á6' TLãÖ“¡øºƒäAƒ6†ëDÁÕèW$c'FŸÐz†:É2â‡U‰Òëvké·Neµ†‰Ê¡é?c/©|,€Ã‹`Óâ{äñõ/éíê%FDiðÎC¹”Ù݄㖜4|¸,ä(Ü»�eí'%ce>ˆ�Š)Ðbþ�ì^×óÛ þ>\ä®FÇßëC¢g1äø¡Ÿ™s”Gû�'AYQ ÜŒî€î{¼P™DÁ‡wâ ûƒyýúId;»­Ž�Gᦣ1Üüå'hî áˆ1ö´iã4S˜#Ñ[¾ƒMVÀŒË±œîP j¶L6�toS2Ÿ|]Dw$ó($m5yîl‡ÔùÎaõXpìèDy°¿L$5gàG%/Øv>�Þ/¹Gãªu$â?¶’UîÆÕ†1ÊA’» Nî·ƒâê\>u_ž$‡#ÃEÑCÅ”gË‹Tö xzm XAž™búÛ«¤»ò�8=m ï1h§ú´"éíÒZ<ûú}¸Æ?Ûmy“q ꋲ0<(�6v·Ä´ö…˜ú°ž*:§ÂYÏú9œPêÃB]8Uz; áð:~r¡”gN#i9ÕOËÆúêXÕsþšs £gƒÃúi0ÏÛ¢4â0¤Y­Óç2§ü%ýMÏúcHkýõ!É-ž+L³±#b-ô“.þn€]=\¨õ÷J(V š—Úp÷Ô]ü.FÓ©›»6×m袋ˆy h¶üIñð‘RáPÕ^P= œ£jáÌŽ-¤~�^§ÙЫâP©nÉ*ÎúÝ$XÜ6ÃåÇ‹Ÿ¾eŠ}¶›Á=ó�Bsð~˜o=§éxyj$FoþLï?š£SB í”뤛Sù�[±(¿F›‹þó‡ñ¿ñØ%ìÞü’6œ-‡ ;×ó’Ÿ`üÈê×Fp£í<º EWÖAÀ�rÊø¡É#öipíE3Tý3�Ufžs.e�s2ÜóÓ˜–g aCJ…a [)ã± 5��¬7�uhÁÅj¾Ñý!µŠv´,ö¸¨ ½@Ç9 Oéö”Ô¼¸egÓ­âc÷­‰®ü÷î�ª§ûSðB¯uÊ‚ïù±^Έã k.Pä¹ÙÎ�iOëJ eØoò$Þâö ‚q�÷°�–U«â·��ÄË*}-:¾:ðpgS8}ož=®›Ã±5 øOP�Ó{hžÜΛ7óó[KØ£õ9ÌQA‹=g$i«é@»Ü> $©¥pp´!iËá‰�(„=ÛJº»ÍYÇ| ÌIþ#ÆuW‚Å{¢ÿhM­Ëw57 1Ås¤þÏZh{’ ~tïë·öRSõ-ºF§at¯ïâû�Åâ™Ëé g;Úœˆ?—iñ¨qîúá‰äÚk >-y-‚ÕÅy[»¨ï¢ËÞ¼J÷o÷�Ùf�ç±r𥴄¼ ‡¤žV5CG¶Ñ¸\u\s1�¢–.”Ž‹��ÿ •ëŠ_öeýÊû²ÿÿ¹šŸfOnѳ}ü|½'¡?÷–‚C½6ŽRŠ&'³; }—GÅéƒéã¹BXþ6/ü›óŠ,A²°9Õ º»À‰l~üô(Ìâ7'® ‚;/í!|6šõ÷zŠO|ûóßÌ"NõïÉ’ãðnv"j<ò�ÚœnF¤Jt3´°È_?U4Ó³ÇÎz¿•&>� ô fìï–ˆc7kЪ™±¬– ¶ÁõplÄaÁ¥d0zv”“¯öuºP8“ïŒ5ÁµÝ"1Ó·RZû¶(ÚIgèÑèGâÕqabéÛo°c³"hÏ×çiAùlð­†úU¡æüvªž‚ÿ¼`¸¤ÈiùúÙàÒïM´Õ^ Ë¿_#¹kò¸tø^¨{Üþcœ8((QðÙ­�ëÇ}¡é¢Ûå•BúL[¶xÓ—ƒþC«Ön¸hÍtj�ÖFeý§Âîbm”ë0àÿâ"IcZ2¾tNÁn;àÞà>ßSÂRÀÌØ Ú>þ‡É³* «OÙdƒçNmeÛn#È@%bçÓ²+.{ÛÁ¼©ÇNj2r§Ë=x±¥�X|­Î�óãüÝà·ºŽÛ¿èÃù­F,_ØF–ÛÂØâüvÐ*UF<_CkRFCtM-‡kÓ¹þÙAn*ô0Æ–e øþÇ7ôjÚ,TÛ.Ç…¦…ôv»6Nq6áò”µÂ›ú…¼ÿm;�™.ŸWóz‹L[×›ÿŽˆ!½YjôóÜç=âXP±;N•°‹a7rvr ²ÿnÀïF hÉgkG¾ß¦CÆêW@ïV(,Z…ý.ÌÆ¤™“@Óc/=7Rägrç¨=h8x©Ä‡ïÛã«h¼µ"‚§žºJžŠq¨\yX8cóX8p¡ ¦*˜Š'çLÂwéd?%ung•Ga|•>:  ;FpÇ;Ü„.ÛFþk¦XœT¨ˆŠ‡Þ�#¼…É2nÙ:¼?‚œÿAoe? ìÃŽW¤uÉÞŠ8åï$�~×ÅÊ@-|ó–ÁÄ%‡U[¾Ãò;�¢šçX½cãxó¾Axêrj-‰ºËà×DH™p–K¡Û‘¾¨Xìï.J‡”ˆq™’‰º)PÚž ž‰žx%¢,ÞØsSµ&‡{–AïÌ5’×ÙOa·Ú’KNƼ¥Z§8…ö+m¬à*í¸ß ¥5&üK«�~Ávƒ`¨Õû¿oä#¥šXÜ»îKv`Ùì©ÐvD8’]G¢ùÑ©(Xí8Î<¥Ó‰‹ÉØY³4ªÄëso�üýdÚ©Ñ TO|ƒ¶³û…É–z\*= y‡õ!þê‰å‹…t8ÝHÈ7üŸ÷� ÚÌjò˜h‹Uz}Pµz+%jÍbµSp¼g8ÄX¢ÿÃq|)v#>U‰û6õÃ#“áàÃÖœöý9÷ˆÆ+ðÛ®"ššX{Ã<–Ž[KNe.¢ìÜñx|/qP��ÏÜ«�9ðhÁPÎŒtÁ®²GÒRååÔ–)þÓÀæ‰hÝgZ‡'ƒ|B›ß¯‘®ŽRâi§,Á¡ËÄ–bžsh ]ù~�Ä¢ÔšZ…/×�…‹{Ìp|ßl+¹=sÑë‰)”nÒâeŸWSà™8H/ú§oÆÑÖ³>x¡» Z² ^¨J…Á=8ů”–›¤H¢_{�P6ûßÀ_×p��áû¼IÜýäTž/�ŽæÑJ„æxþ»"ËWë“•Çt,+,%M~/äˆáð#d�ÿj+8ns€×™¡2"B:꿇â—Í�€Zv¨ë  ò“Ê9~„[Šw‚ÓŒ×4ÄàØŽ4çiÛV‰K2[Äz¿DZaŠk¬�PÔ^=” q#Ó:EVù¨ÇÚr× O�¹®¿xüÕ;c4XõHœúÑW;@–ÕçÒš³Ü‘¸Ž>�䱊°çÛîèa®�«Á‡cO Pj}A¡Ar¼û›>æºÂêõ ºfØ&Øê.„ó±ãyè†o´Nó_ä—ž…é£gråeEÐ=>“·Ž+ƒ²»óxØ�t˜kºEÚRÿ:ýçQû¼é,;ì¾Ø×Ø-í߉:«ã%óù]|˜‹ °[/MοlÈmûÁºSCù�—͘a}à {}’é¢M4,è9„Ú«¨Ô̆GmÎÄ—Qƒ(üw5ŽÎ Oƒ-¨ÛL?aºÚhºxÓ”�_ aQøýÛGøtí0}±¢ÒG¸1g ï\�ýú’íÆ¥ VpŒû©£·q4ø¤ö¢ï½é�ÙLŽü¤#C÷À/+NªŸŒG99bFØÖ´ŽíÊ«¨}ï^ÔÈÚÉúîøvñ ø ¶ÓgÏ%tÈ#’ '“žØ&DܱAßRo:ÔG[ؾÏ>ô�LÖ�[¸¾á= ¬ZÆ‘·ÅíÉ]âÝ Æâ¤úN¸~Ù”TݯQ˜ËVzðf ^P|W,1é¸:FÖØA„Ù±èÓzŸ»å.ž¶BÄ?R¼'8å��áÏ‘OaÙ6GýJ•×^Lñ<ÉuéÃç€ ¬ê; œÚÄ74•r~Cq�.:¬2 SEnÙ –Ë^…«—•xΩTú¦xÒ7<[ù|7§B¿©WÅM�Æ<©é‘˜špG¸Þ/“Ž ´ÆÈ|;T›\Žýʦaò¹mâÕ )�3¥e{\iç¡Ô½:–׳æ/+oCb°¿èpåDnk€IëžBìµûteAƒd k–gscg\Þ!`Hõ`6:tV¸yÀM_<Ö°BPÀTüÔ[�²ÔÎbt�NÕÇ–œµ»~Ÿ‚u#hæ P¹Ý‹ƒÏ\Ûª¢Å²½ þ%\5íô¹šÅ;sÁ ÿÚxß½hü¸C‡­ê·ÖÁjEîöÏÿÂ^ü~ˆÄàg …ÞO7ÂçpžKwÌ{¦Í§3nHU3ÅlÏxøãlBiS«IÛR“å–C¨[8Kå�ç¨BúX’'Yô½ü×|!‡ÑÀ7JªO|¯±–(Ê¿£*·³ÂÅ“«êž£‡ÉIHìì€Õ»�Á€” é‚…¥Ô0­'´]Ÿc¬MQÃGëË’þ: ÕŒfšê¶æD-ægªºøÊ¨F,O’W€J²AÁy?´ Ԡ‚lJrΗ>­Ïk.<££j4m³{$Û®BnØ¿^·§=µ¸o®ݘ\Æ…ÃD/õ|Ñ:/&O}¾G*ò;èÚ­j¼­Í�[µh—žÀËS’©&‹#}QÖ%tþØoö+rÔòáf´obÅî62ñò�ðÌ¥?Ôo ðLm$} ‡Ë5Òðè£ô¬—£ÜUèé {éì´,Ê�Ï,Ó#©Q¿“*u¶ S×ã~¥ÄÜ ð h,Ö /éî�qìòzU¼™È¿r'ò—ƒõà²T—ïû=¤Ø:}ŒPÎB‰–†„eѬ`×Ùî$ÿêÉúžƒUJ$s[¿J¢ËÔ9÷óØÖ»ŠäTz♼,ñöÝû°mV3m,—¡) *tÇ.—&*ÁϬžxS/F�Þ]g¹ó0È»ÖCyä[z½ÈŽþ”Å©^#¹ßââ€í«AcâgX Ú%ìïûo›ö⺼f‘¹©ˆó¢‡¢ERÜësâŠÆO°Ïê¨íÆä›,®Ÿ˧¤9¼èz$ô=C±Ìä”±ì4Tƒ¯0çË« ÄA ЬÿRÝ>ì$­›E¶«/¿i°Cí¢ý�¨oÜ€ï))ˆi#sÝ.!|Ô"Î_0ÚŠÿXl,W®÷À²G³éNÊipz2;›¡k®6;(±Þ‡¾·z^J¥Ž §¬¿j¨µ—ƒ£ßU¸sп½û×ÿûž ʇ¯IØ¢÷M»¥Â�6>vWÇÙiñ¯u1ppi¤XàQÉöëÙð©*«%ïàŒ×†<ïÉj´}œÁÙ/g ö+ƒÁAÁ™»ì¶s¥6bµF!$}̓;Îg¡¨g_èÚÓ‡#_ª‚ÚÑE~¢RÖ‹×åØ¿W:‡®,ÀÁŽ*¢[Ø ø~¹†t¹‰±{·bÍÌI¢ëŸí4ð¥&¨iíf¬Â&]Cx|b^yf —»%ÃÔñQ<[A‰g†iã—BuÜý«?–_òç� §ðû1?”Á!çPâ/uú †\ñÛñ¨)˜d¬‡Œ ÅTÛh6³ŒáŸiM$—KEOå!ve7'ðÈÂLA3,n›ë �ÂvÒÞ´ba™w°x^æméüá³·ò&ùû¢‹í!§©çþãñ×�S©iMz�+mÃ@é>²™^F®}ŽRA~¨³Õm}¬©-$?Ï…<$Þ[²­on)“ÀT#˜8³]7Í�«ºCÑ6QÏx,æÏ]½8¦@™BììÅÎ’K4úmOáÖ½l ¨n¦!»uÐyÊ:ž¾£'�Ÿt‡Ï�O[ñ‘ÀJ!]ö>y¯rÀÇžò˜°Ô·«AÇG9áóê^xýúBôS!±ÛGœõ�¡ŠcH‘§zåPQ` Ê>¶¢aCBëz²¼´‘üÞôä{KëÌ bÄÓÙÜÎ | U`Äd 6VZcÂÓ•` ³Vi˜s`ÈwqïDN®8Jót*éA÷B_©y]ò6*‰;¢ãØõY4¤«Ý?sð§Ë%ŠÜYƒ¿7‰ E� ­g)…¹�ÖÝþXY@uΑì;k:n'ÎLÙ-6)¨��†µ @ßU tß AI«¨sÜMði?IoLÂ~-žÂÔ_`ŸÇXz, ’­ŸÃe³÷BÀÕ�8謲XÒéE¾&±p²Ÿ6çd×€BÅl?ï#,{›&}ÚºŒ½FÝ]'D^ºëª5„„nf?±_W”¸ï°^9÷›ê.Aö¨0ÎÛø•>opàÛú“yis_2,¡ô{1Ûa²péç/zÑ] õŒ¥ÒêugͤÞ?�1Bs$«ËãÐAUX<³L˜Ò ý/Íã#ç»è­l5ó5ö›7‡r¶o“� ɹ°ZTˆ;'N Ý]«`Ôî*Ü7¡?«ÅxãDÕûb�a(X¤O¦IêûA±Üœ».Â]§Ùüíd ÿ2¶f_å.E‡ æå¾QáG�›�c³KèûóvzP¼‡Qg;»ÇÚâ’Ô~4 ´%òÉdR_BáMƒ¡Ù{-»9’÷Ö€:žCLÃGÑ4ß ggD¡†ïf6j"ª™isãíù°#.Ö¿ÞÊ7Ä8ê i¢êmd1)ñò[q€Ü=ø”!¶Y΂—O•¹cî`Éé9E‹!Óa¬ì"î±3Vv;-5>öä�w°Kæt=Ö,(¦äÞœ§.Uû–À:ýÕ-<>ê$Œ>hM]²Ysô<ún¿ŸøÊâ»sìÔñ�õþ«¸-æ1„þêF‰«ÏIzgç)×+µ{t÷úQ°ì„ðåj”)¤s»G5f ßñetöî.\~+OX[ß–~…ö )¬Ÿt…øš"Ü5Zµ½yìblþí‰�ûj°aö2Þd›Fó­òaìmê«ó�Î[üëã!7).·;U^ª Qw ÐíçYáÐ�&0­/@£ú:¸à‹’f]�¾“®BÝüG’b�jZåÑ�…+bG™æ¶µÂÄSQ8»Á�l×àÛó©B f5šÞ†øŠ#¿·?ä¢àò< Ò¿WY Ž\9 ½)ðô|ôà2UFFÃÖqA`q¢•lº=§‰;ùPñ)*ÜR mídU‘•�¦¬¾ÿ¸Ø™^~{ÄM«u'äNP®¹»?ÿ ?ÇØp×RþǽR¥Ãš\§£�v3„]Ù&›øY\™_³âÌ(åí²ŽáŒMh¯B—aø’"Éâ~ðs„.�hˆÁý×)¬û*Úቧ>¤ÃRUöy÷‰. šK:.ñ˜^–Д}‰æÇ®ä£aéPþÊnì±ãÓ&ë©[To²‰…ŸOeqùàHLK`¼�«x, Ýu;@îöPIÿ¿“yÐΣRµ™¾XÜ£ƒúuSg‡�e¼rá]8úN¦ü4ã3 áv�=4±í<…vø~ ­5G-a}÷1„¼ôǶ¦˜/ú=GÜ•àùÜÙàŒ3ëúàÔ½u¢¿«· ´£Ï4!ï«<þÉ/ÃÇiØòÊ…¾M¨€ªˆn<èÆ$x|r0ækuÃøø³ÂŽ;³yåûÑì\"ÿÝ]&,\pEXQ±’wE‹ó2×ãNmú5$×´\€Ìzy–ûj&ÜÓ[ÅÛõ§‹�¥Ûiˆ–¹°æ·)�Ã_`hdÉc Vp’¹Ï*g[ó5¤b»C˜p§:ûÃÆo†XbNÍÚÝs9ûk/…Kâb¶ínL»ÜÞ‘o×YéZõP(^´Š’™±gl:¹~ù×áŽxj�&Z—ý!�ÿvaªŒ.‘¨ Ú±h4s6|êU.ïw gs‹aÍïÅ4÷’ÏéþUo{ÍÂ$‹FŽà ßÚZÙñR µ¼wÀ¯Ùpcö)x›ôFX½Ü_xWÛ—p¾=ž³5çû|Ô¯ëÏK'êófß�tqãlS?C!ñWÄ GÝØéø{Ñ/îý5¾ ƒ;ÜùÇ¢dÞ%)ì¹›sOöÅÃ*òØp'—e u9%p*¬yx¦®½FÒxîb]¬]P„ãŒÃ…î��qMþ Š^¨Ê ÏÆAŸ ÷ÒÚ>¸iM9 +yîæ­�܃›Ï+â=…6³ºã¹3æ¸<+Ÿ²RtÅh×fÚÄ[é¤Áaµ]O0Þ…o¾3�Ã_ýõ3¹¨aÄM_A¡ó6Tßž«®`ò@z‡™Ó€MI¸â‡È‡ŸýÖ¾ÛU¶Ü¶@�+=¶R“¬9�éïG¯¾r�ˆÏ¥~3T)­=LØí¶ŸÒÎ(óïsê<ëÖ):êÕ(9㹆S€Ön/E¿èô?;ûÞçÆ#è<«Ê­/.÷� Ç�EÍÔ7ôáÎ!êúÜå‡ó`Mçvœ×êÃãÂ6`õ�ðNŸÍ#‡½&yïDêX�‰swI`öÝ;TgC§ò¶ðãxdÚ‡Nl…jðze¶B–î¨6¯§æ%ií=œ³*çú…ð�ã1ðjD¥ødã–5.†ù¾{hèÈ[Ô-ã"Y¹êýcI–Í×Ç'ë/PÏô)h�æÃ}ª÷IûMŠ'çɰÂGûãÜÅîürag.9'Î{ñ‰¾Å• ¼q/¤ÓÁ¯G½/m&]Ycn«Î¿f/U>}¦Êœ|¨êþ^˺�ϾU¨Þ’ ­Úë8neBí/©Þd}4,³Às-qÿR \ûQ)Žü8%7ãÄ;|¨(£¯¨]ÓtôèäŸbÁÏQAhÝõ^p ø á ªoNûŸ‘<=Øö®wQàLE‚OÊ@çùü]IÞàÍÄùì±S�4üØ(-Fx²)…‡m¢´^ÎÍÉ:A7l9$ê _éüоý×).ÿ¶KºDÃ�z ć–÷áW°¾¼I2fÛJ6zÎò�y<`‚’ðøº�ê\%âþTþn¹„§Æd !‡+Óˆ-á°îm({�IÞ¾•å�­áØãý|8Tdo ÷Kr_qjsJ!)HŸ�Mšˆ�{½…¹Õ<Îé }+^�ûŠ :¹�â�v ôÕu1b¤°O;¼¿ê _&*ò‹)9¼of gu�åt#9´_C+û$ò¶ç:ü]†6}FÞ|„‘ ;!b—#íêÈ€<Š@·ëCy࣑`’¤Æé)æ/×½7•PúKœ>Ù�WºüÇÛ´ÃHïîéÒƒ†ENT¡mÃŽ'oÓîe­$xÛ¬`¯ÁTÿB‘¯4ˆ¶çÂzÙ£äót&·þ sýGR£Át¾ÿo·ÌûÀc-Œ=ÒÄnÑ�fSE¡Ó�@¯»0Üþß]ÝÊÇݯb9çíP9W.Æ8ÙÑ—ªž©½TH^8¾3¦éy –Ëyå{\?Ç•š:.Ñîûï ùÍkÚ6d+§U�wK¾Ã3ugéuy ü²d;³Væ0œÙzc@=Û»–Ï ÓúÓ´`è x�§GDÿÀkÔ4É÷=†¥;ò¹Èá¸ø3Q‚g^Sá.w®B_u/ú|«XïnÃá­=xiw mVåÝ1ÌÙ=¼):߇ƒMgýsûI£Gw¼Kæ–²è5!™„�Æè<0¥Ÿ'ð:÷i¸VÁ�W½@sFôäÛ·Fðþ#x݇Láq’ºÛNÅ¥š± zÄ 7z �TÑE9ë� ¤J–¯ŸÙ­<@È-6aû±ö¨} �ö¥¸ò†gˆ�¦ÃÍwW ­è¯÷-ÂϪ²lÒ[SæMå]²Ç§þ>~?¶ ¦­Â(©Ö«)Ѓ¦ûpyÐ)ò)–áK##Ðù™¬vÇÒÒ×I4Sf;Gõ|H¯cúr¹õ(¾·cZ¬³æ”¡gÙöõgþ¼Á€gôKdü¬Œ[ð¡�*z‡€5ƒŠøQðEÊ+™ '‡ž&³\/üÓtRˆ {,15ͪ+Ì3Àm›"ÅcO³àcc ût^ŸÜ{(Ü•éS¬hNdo?ü�òüŸB×ò¸ñA–>ßç­& ª®Jœó˜Ì¡MÙ6qš-ÄŒ‰àä•É/‹¥ž÷Qòú£¢_nž¸A%„n”ÎãÐä Ü\@'n¾!Ý1E•&a O3’Ÿ‰[l†äΓôll>}µO�9B’�v¨ì�C2V¡]”!ê�ôãhÏ¡4w­Vö!ã5ë0í¨·µ¹bº!‰¥·_‰MÜèÎJ-T˜3GœÛö´–ˆK­vb×û>¬sõ7ÝùfÍYõçÄ�[_ ÆAÓ>'N5õF�÷é8×h+ ¿ *d£)'8—qZޤ{Z"[“GÆ›/QÚê°,«§ú›2¸±t8Ÿª¸ êqÑ&KRÿœ&ؼº"]Ù¬‰º¸‘ÝÑ‚†vq³Ii¼Î—DrÉk¥¿egátM‚x¦§5ÖObÑÞ’lÌPòÞ÷úŠØËÕŒ­+ÿJ¾›F·&±ËT~'ÙÌn9œ·:‡Ý¾´Ã–iiÔë„—$u�óÄS´:'Zn––òq,•9A׿R‰Š–~�ú¤kÿㆱhärŸJŸ B¯�Š” ‹ué¨R)gÌìž›óëõ0·bºº*àçgÓAfJ:i�‚ÛC5ÐÖ[‰æüc§)ûx¾]';è/Rçã½Çƒð†ßib95Ìžýžz9•ácÇK´Ë&œ×!ìã&œð¾'DíÉ£JAéÕj°NFw-!/,CR¨Ü:£Hîð2t»:öŒ¯ÄÍkÃ@¿¿V'Gp°Ým²Ÿ:=ï‰ÙÛÕXÞç¶àÐ;&ïÿëX SWÚcÐÃŽ µ—ˆ'¦ðÌ+©F5Nû¨b¯X;.©­!ë�´¥ïfNswä&Ûtîr=H-t…î¿�M¥q”8œ‚à `«v"+/_DëÛ. k΄PXßѼ¬¸„F¢*Ôö¶ÇñVÀâ›&|Vk˜¿É@ t™¢Å3Wâö-ÙÜ,\Â~g¼ñpÛ3ªòq¡¨.Å‘ú!#iœñq˜ÎZn!¾0�Ïçû¨Á½î»@çŸcŸïaKUÉ7iÕ¿p ÖC�×SÈî˯ÿÌ7©jG\P'ЋÚC{sÜ [N[«€íÿùBj¨ÆG]¢ƒ>Ü­Ç<0l5…½líCÜ'6+vQÍ“}˜ñ Š–­¬Ã9[ˆhDó±'Û¸kÿ\^Q™ÃûO$×G!\ kϳšS©ßîeÜ´ë?ì3§æÎdnâ�.£èÂRµéãŸùÔ[7†%�”Ò·>ÜÊ‚uaZâ–± ñ·Ó7hþà϶R4§BØ‘<ÌOžç��Â3&¢£»»°O#—VUÏEõ‘àû)û<Ц+r;áî?®=q ^:N“æ^†¯éЍ´ ûï�¯lìÈï¶=5�Ø…Ûü8êx­pö[ „ß³À)Obé�C7¼˜ÂYz¯¨ër¶tl�jZìfO3Úu„À´x$Öî6æcíÐb·­´ÐR —¹ü„–ƒÝñ©å_ˆ¯Òà ŽÇh²çWéªÓwÏmBðÝ=°ãý,œ»ÔŠ©E@�Š.FÝ @ÇAÓðˆE®:ëÄÕ/þ“¤<)¢ì™‹qêfö^¬KZß/Ó½fp^ò�Þ.²„앉|ö�>\¶ÆùØóäP¤†#·ü›å#_é~ú;qÂúØ3·¾x& êêjP¿ï5%z÷�vï–…ÑKäxà÷@8ýÅ  Ï¢jþ-Þ˜Ìz1´kÎSê³õ Õí[Fµ³ ùíÉ4Û ·ü-…ïu¦{0EÆ~�d^6Ã)c_Їú©³­}ù©@ËU­0tF”Pœ^Œœxþ„rîé…‹?£zMœ÷·&¬ÐǦ(MÞê§‹§µyHŒHüz¡xc ÿšƒ¾?®ÁúYÞô©Eìêk]ÿ ]k•1b”î)˜Ì-d9/0Gìð ì€~|bb—°!Õ¯ÆGðûþœþÕ'7XÁªÍ/„Õ_¡æŸnì—?‹CåGòy—ÚÑã$ÌX£…Ö…�'†6©óÏ«Þ|캥׎åO“�8û´.N4ø�0p îhrãáêÝŇ³úÃ�ÿ:Åç2˜[ôså>’tðI6ÖøGæ@«Ö:xó´Œ7=Ü3Ñnˆ‹q½Éeº›5]“¿€×æHš:±P’ÿkÎÖ÷v?%dŽù¥OËDÃÿd!{Z õ[Ç:-ǤQG5àõÊvAôSÁ}m³!xÂD6»Ê{±ç©Fx2c4]œ1�Œúõã¹]¥šN¸.!R\Ü^=^®¦ì½cW®ƒÄÍ1#m­®/ÿw4…Ç=A:ÿ¹9â¢ë…Dzûaýéßxv~ Îøä‹ç+—àö�}áФë´Û'u¬_�˜z„g�âß*„Î Õ¸6Úã”N‰çƒØ£?ÞÚÙL¯Ý¥Èÿfã¡»ª®°T¼ï{]°IFX?~—Ø´)ƒêߪñ­¥Yðto›³ÁëmðíC‰dŒf;„oyIq‡,ع¿3|.¼B6?>‘qþX<�Or¢—V³¿Î{*àå3‘ø,| tüNEáÐ&øc{Ÿ­ëäØ6é·èÔw5zÍÛ‚YqŸ7רÂK—~ÛÕ;{¶æÑR+äÓ�ïxŠF�[°v°)—0òË; ôîù{�镃M�5¡þìrx<»E�†ªEK¡z³5,›³�díÀðˆ\·ÕŽ­£ºSÿ¢.¨é#ÇCæçá ßq4##ÊùX”.ÝìŸGö7[„¯¹Ÿè×’LìÕSCrFó©Z#é˜äŸd_@›cäiŠ™:§&lq\Kª›¤:'÷Á샃Ñ}‹<ç?“£þïïCã٠@úˆ£=€îån¼cÝ^šˆ_U¦âò]ï Ìâ$TïaFJ©\h"Uø=ž û÷ã.á±èW%x¯Éàwâœy©;¿º0•Ç‹k¢°òágÈË)$Óyþ ï`Âṳ̂ –‚ä¿ÃØÜ{}úùLsÈŸŠåtîé]Ðÿ: ~ä}BÑÐûç õE?IÇúvú{@Ž�RÒßð‘TØç*åz§À»˜^¤¼É›éÎÜRÏÞè–e¹ÿ7 »Äuýº±ÐLz6SDç¶=¼Lö}0ÆU7Rxlz „'xvkɸ˜PLÝSHš7–ò¾È“ÕÚž˜tl—´Â{û28"—Ê.ÀÏ@ö|çŠå­§àÔ…óPëÎ]«uåiÙÔ8>r…FpXö‚4¾ÐŸTU\`e�¿&Ö­~ùï'ö[O7ÊÐñRØ èÑ0ŠÅÀúÛ¡äo$�¬8#ToÓ¯oká?W>‘»Ö"t�šÃ³€…d§ÓHR]U¼f ƒ£û‡€u•ÐËËA°²ègÌA©Gò2ÊY³Ü7ì…:-6ãB¿æñI�~| dö0�?÷fÅ=Ûyà�t¨Wy÷ës­ªÛ÷QÆ<#>²a&&ŸÈý¾ÔÙ‚ÛΈª¡katS5¹‡¡›»Ï<ëNï{ ¯Ùˆv©µ4RÕ]{uãs¯Ç‹µ!ðùãqéîÑpVg9�9ÄW â-›×ò·… 4ç_F¶¦hQSL y¼Òåç)9ä«™(döK#Ï]~ÈSÎÃÀŒo°zM6 +ÿµ#UI«íŒ =÷ äïZ ­vÚ˜Xp wIwI„7ËÉáä6ž~•Êd†¡œ¦$l½ —7K`èC9HηæË.Pìþ”SC×zÛHu[Fy}Gñ˜‘½¹’èŸÍêq?‡“Ç)óç=­t§„`iø z®P¢²ŠmøC#sò.:ïËΖœ.ƒbŸ]¸çësaÊ÷e¨:c ¿é9i âwaŠÝ�ßdÁˆMq4´ÇI\p¨'꼨””~0Ue®½Yø4Ep …ÏÏúÀÝ=Mâɸ©\7p¬}Žß=ƒïN€Í­©üfÚ"¸º¡L\§ƒ~&rü*a¿ÞExÜx�¾.‰“zÌ }FG�Á‰8gc,õ®±åûrm#¼0ò‡EŠÃm�„%çÊibªœ™� —Vð°…ñx@ôásÇ¢i{ÂdLû\ ×r5yزãt>¿Œ7|¥Ðn°äƒŠ°hJþ�þ€jíu|pb–1ËØ»’Õ{NØåÎc5ýÙȽ�ž6?�Ñö‡�¿ú+<µ^ ©E1´ä†YÄ‹ÙöI‹Ëe…ÛaE”¹3“œ)ÁâÑé|uÊ®óê�§F(cÝë³”ÄÝødøTl9¸~euCõ[MôíW¾d¡Šôî:nNã$«_°v¨ÿQlÞ\ÿ_GE’�BJf"´(>ï{e„"*‘*JÒ·¡=”MÊÈÊ…hiçó¾—†¦ö¢ÒRi¥”Ưß_ð:çuîóùx>Ϲ'È.#»=¼yK“w8ÙKCO€á&wVuþJK. «E¹T¿×RNJ“0|ó0~Ók5œÎâ“ú#xÕ»•ÂhÝBáDd#oQ}¹�³ Þ°&Ù¼¥;cŠ)^­ZñðIT›!r“ ¾/?&¦J{BˆÏA!YþtͲÁîjŠ4Jižù0ˆ.usËápýý°a³ ;^ø#¶vÿ@'üîÓÃÖuâSóÏphóqI³#y±‚cåØ=xt¾žŽGužÁÇ‚0¦´öêˆç^ÎÀ¼ŒCŽã®?±<Ã''Œ¼&¨ÛÇÁó{f¼ÿçúà¬�k}µpfóu¡9ÇO4ªþç×ó2¸´w9…/jƒGIfâWÚ÷î¹0·çk �,Ǧ&?.Ùš*tþ=}÷ä‰=Ž9‘Ö 8¶4 óËðÒápÖ>Ç ¸|6Z}*ƒiå3y‰WÎ+ýÚ)ÿÝq‚‚'ªByŒ ˜XãÐ9ÖöÉÝS°C%å ÓÈYËL©°Û4Ú£Þ ”Au3kï-dwÙe8´X$5óãô# …öÄ8ƒï÷»d£ù$]£ÄØïóq‡A0íî¥Ë3ŠVQéYoøMy´Ó. òçÒN#/h0/FìÞFnN.TXaÀ-©V8Ô2öí>&¨í§C  ¸û¾hZøXÜFë@×ù }Ó5‚-‹Frå xø>%Ï}Ú[ø*\Þ:–›dô°pw%¿ÕƒÓ¿=8ú÷tLî¥ÁúwÆs¦ •¬|I³ÆšÑòÈ'¬FØõzùœh‚KÏ»¡…¾<Ù/Ç9S¶ñ7ƒP^8a縚³rø^:ÂG\ª­‚Œ‡1bÇ%[ˆv÷âÕ£tÙæŠ2Ÿš¹Ÿ\³'-—0|¨�r+ÍqµºÆÌ�DE‹ªÄ•-» ÿ]03³'óÞ¸K`ÿ´áôiq`Üp°ÐXcS� syÕïXFúcÿ UOsÅ/+'ÂÇ�x¢Ó}|üàxwíÃo& UM¥UñÝx±o”òè+thmì UÑîP²Pö²Zh²ŠÃޝ›Ñ!îÑKé§òl²x?šß«^¦#�ñøyeâÈ XW¡„ý¶+°êŒábZU"ü�M­I£‘}v�¸)‰Ï•£>Õò¼Ãd6MýD§n¦†hšÐíÝÕŸ æ-ªžjµÑ¥3¨iéGqSáBv²Ò7ÿ=êóuߎøÌÂî{=©×˜jN4Ūoo A×À¼þY å]Šù¿Ëà³Õ²¿Å߯/Å‹�B›½›ìZ�öc¤=BsÐåýpúš>V°+‡V@Ì{¼U2ê*V±­é9Ú5À¯Öň…ʼðê(¸3¬ŽŸ«Äyúó8 gÓ“…ìu}¾s¸(îy•B½µpÂBÔ [λLÖ�t^5Ç=±Fá^¹æ~êæ¨ÀÕâ!|rö5ºt·B¼Ý+¬�å0óÌ IþÃJ¶žØFUÆl§oŠ7F¼ù—ôpÓØu½A8PžFÒýö,]™ÈM®8±çeª7ïÿ¯Ûý cÉåÖAj{b„µnèÙ’Gò¦m ðüùùÖA`ÐEˆ9FdžX€UÄLʱœ#jŒçO°—÷Õäá={¢u¾»ôë„áÈ«�/Š“ž‡£ÞcS”‘t€]u5mRÌàƒùÝÅ Ú©,ûe3Ç_V24WS¾Ö®˜¦LgœõèùÞqXÖ§;™^r ã˜ûÓ‡Ï{LjãH¥ã j^1@Åá'…}‡*QíÏpÒÛúˆFÎÙŽŸŒ³Yíà>½Ô—–_[C«eyÂäJÁýñ~vXnÌ­vÃ…]ÏPîr :ü lR¾RÝÄá8ú^&L¾:Šûãfx“¤io @·4’»‡ïVÐmG†Oß&]ÞÜ Í7ÇÀ¼ 0jóÄ3µñ˜£¦�©i/ ½±^·&tv#ç$º0> ¿þæ�.á»YÄ]q x»à*V)ÛÀAa7N²é#NO~FL…M}žSNÁAÔ1ðÑt%8ë`ÿ‚)W£ù“Ö>´/?ÁFg5ø¶Üôø½ øGñåÑ…˜û·Jøó5šß¤½¤ßëInÙD~þá­èëÉáßÃÌtO° ñbûÿ¦ñfëº1cú¡fçV”hÎ vÕÓŽ“šèï–ÀËrã!Û\¼«µ†|ÿ,Ëìd+uÜ!ÙÆ�ûH{ÅqÄÝ �¦âÑÆÁ‚|Çè©uŠow‚{°ML|¦T‹Ïä§"R¨ØçÞ~ç†ò�¤ƒTãÂáëØj‚{ËÎÀeayÂ�¹péë$þU¿vÝ,¤Œ3.,¿éžÔâ箸?û•?jû¥�êsàõ)3>¤úHÜ{t<ŸZù”.üÊ©¨hùS:AÞ’8ª%‹—#*àEñNɺA ±{{8»Ù¢[�¶Mg!ð_wz¨±Å¹øá†žL»‹uÑâÊ^Êx¨­nê¢Åù‡\}P�ƒN‚º÷e´x2À܇#húx¬ |ËfÁ7Ñ<îü�ŸB¿nî!½’Rü]#ªÈÈ@ÞîpŸªÇó§©¢‹›./\;�l©bLwMáVv�4§ï ¸·ý»ØœÝ‹]‚-IÒ¤Ï×R7ã•m_$O�~ÓßÞ ÜG)Œ¶¯"GY- ïǾ|ô½½˜¹Y vkÀ´¾9ôÑöŸM7z–Ònƒ…”ð5”î/ëÆ¦�;vÃÉ›ØÄÈmsàÎÏ1äXRÂcjJůyžâ£[ñÔÛof.ûoçW‰9?š…ý~{áPŽ1ÖîZJ XkásÒ‰©€™™ÆX¦–‹�»QáN¾ëVH§¶ŠÃÃNÁæòdò˜áÁ {§üÓç 6L‡K†_˘R ÍH‚šÎ­¼xM(Œ­ ¯³v ‡Gð†ø�t©6“ª+nÂÔ[—kíz‹Ó¿Ù�­û_À¯ÛðªÕT8©¤!Ëì„|Ýø¨Oe”ÓÔ8x—ÆVúFÔY8 µD ®Ï’“l?îÁ-Vl½è.Oû]OÂWräÑ6zâ»­Œ¸õ^:ã¯Ó´cj�_0T,Ïm­ÞÚà‰ñsñÐ1TU bïP0ÎÀq_cx‰�.†^Þ/¸m{CF·Òð­G„is48¶*„ó~!‹«³XÆvµ`ñBÓΙóéêBÁ�B*4D›‚L¡Y�»íÇŸõÃ=?¼xÖ«r0YõC}ÄföX\`ÃÅ!ó8«®z[æß‚¸#;p‰‰+†6/N—ÅÓÆ\÷è=žüŽÄÞ‡ù*Ê0{£1¨ím‡Ä_•÷ÛRgy“ÑÂÓ4»s\P\Á#Î]¢Ô» ‚öÈ ~óâ‚p}‡.OŽ£+a^蹕_K¡ô_¦O¶V ’ÚØoÉI„ÌOxi?9Ñé+ÊÅÃï~€OD ïéÂ*úù4íÙ8|œ©,¨î�ÿ±Íƒ¨ç£ˆ§•’E½S-thöN–Eü·Bƒœ‹ähŠ’1iþH•:7ÏàKîlÕÚžÜx f b`¹�-íÛºMÚ´j+G>Ÿ—_…‚¡ ìû¬v)íâÆ• ã SðVE ¨^ôG¿l&;o#Öº˜%\°Š ¸¢]´Ýn\p@Ë�+ÉT4åyÓ[„'n¥‚f³<ô¬ôã;Ç&³[YoÌØ7…Ì‹úó®ÜçÐïeÈç×KàX7ا™ í#7“lž9­Õ‰ÂA§Œ8ÉâùX(q��+[ÙSÛºfç„/‚\iࢗ¤¶á)Àm&}59Ȳ þŸ¿ím»#ìL0£ß-zìß=˜G蜲Ÿ1x¦•““‹Œz ΛM¢[¶ ü75β‰X3Î÷œ‹µŸUü¹lˆ�O—¾ÀO à¤wŸj'Ø«Á”˯Hãp¶Ì2â ºv|²çy(.³å ÃbàE½ilœÇÆê uûdÚ±³Tü•‹vÙ!lï•ݾn­/£°nÆÓÉ„™ç”Ð35 kÂ5yÈï4zë  Î[‹ÅQ߯sò«òÚ4¹!¸Ý%G\¶1~¾9E&®E´PísmÿO¾Ò㜹étŒë9·ýµ¡èõ°ÕEW¸m¤Ñ WoÊAƒ…Éü&«;F¯×ä«oÔÉt…&¾\çN½UVÒÉ…ºÞ�m’f㣊8þvÖˆçWР§K¡ìÅ)záyäï¶’üíp`yŽÞü^x¦Ý—“î¦M«R0Vc÷óçùQwÈk¤f TáÎÐ ¿W+ÎßÍgS»ûÔ}¯ŽLôÇ© î˜bR»9aÛä[aŠ÷;²w®¾.?H�ŒÂ£9mâlݺ˜=�¼•¢éà!Káù·Ãhµv3jÝ6Ù3/aÖ‡Uàùím,1FóN3n,Ï嬙¼Bs8¯‹NaÃŒ“0§½C¸÷ËæÌ+— �ºfœ¢ãWÊàøQ;ÒíS$ö:�Â6m'+½÷¸aÁì£èŠsT¬9cÉ8To= õŸ“RW^ÙAª‰ Ü‘GgdR°4‹×êõx VçãéÔµa‚ûY¬ê~‚<žíæ:mäü VÞ.EÉÄ‘¢sòcáÕâ:r{ÙA=µÐE5‹ÆÆ“MB*[û¥óô6S<9KÊàÁÜçôöÌcü+ì¢÷›'Òœ†¹äÜu“ò=»;•Pmèn{‹ pñQ`›ÜÁ\ŸM”ýÓ^ï`.Ù½Ö ²c¤àBÃYö»,ÿÕŸ‚öÝq·u'É\tÂ!oVˆ?ãG“Où_197oeµQÿD5nJÍä•q\¥±G¼3$-‹¦ªò ½ÂUÊ8â‹=¼ª²ÀâŸÎ:mÆsCÀW·Âg·éØæ}œÔïÅÛ)cð‹ñtžúý(«Ï›�Ÿ³·€«M˜k—r÷s–h¶BlϘP^ÜÜx¸?°ÃkcÐè»ûÈrÐp¾¯Ï•:Žd§ùÂnñÀž?¿;$:aé5ÔÄê_T&ñI] ÷öz ÜÝ¥�&GwçéÃúÂfÇxö¿Ÿ$l0Yˆyu{„‚Ë´WQÇg�“Ùf¯†ÔZsô»x.(R¯U‘á<¾™‚SêàašRm‚£ÍËNuÜ¢—Ã[�miÜZ/ê;?I¨ª‹� õd™ê�ÛsïÁ±C'гè¯tR¹ ¦—ºâùëK„ÙÒ›t½)� ´¥ÞkXÙn3^Õ�î­¿ ZšñLzêî[Îë»ÈÑ=„~5ì«ý9R�“–ÚÀÐtuœ72˜q<íT4ƒ¬öñµ‚‚^Ó™„#ƒŽÁ“ÙäTGA³ö/Ú´‡‚t-±Ÿì�÷›Kß¿¤CÛqö\¯ƒSþÌâºÃƒqrþzðkÜŽ[‚Ð�CîeÑ «ÞEIdUÕ¡1ªŠ=ÚÒøõÓ\ñAÓA¸6~=î´Å},î÷�¡ô/*¬J±¸/æ5.Ç�±æ0ZÇ [�FñŸ}¹í˜�ðŽÙZBuË*ܲÓ�ÓÓv‚‹Z+Œ=e€z_ÆàLꨲ†Øw ÄášM0lÞj¸evœ˜p„ÖX<˜)áŽd/ô\9Ö{38ŒÛ‡¾‹áK¹Vi,G¦·“48KÜ9·O9ËrõèiÜì= ßÎ6¦H«8tÛe‡CŽü†}Jé­¹"̳ÔåêÎaÊH]œeeÀ_þÍý}G_z9ö+ÎMæ—¯>е™Á‘�CKþ;O=^SÖ‰Û‚î]Œ�xóÃG÷©©îl(¸Nß÷ËãÀ³©n›=žò)Ÿ€õtðeŒ¾q�ÜêÄ5:}±è®6[­×Å%ýb±­ÐjŸÿ¡¹·GñÈÛÐOµ ¦vgÙ�¿)(½ˆçž¯‚²‚ñJ H#õEŸÆ#ôlê)jûì‚kû÷ã˜ßaì8æ¶ëS v[Ó(x‚ 8Ûä@Å=(¿Û«kü¡æ‚Þ~f�+®ÐFå.*X’^ ›©ÛÂêÚ¬òs4²·-G̲'£wY¸ L,ެ1­Ï<(‚íÓdØð„µ°t}ùärÜnMþPÐ"Œõ>-´ÌÝ �§yÑëãüÍh®½qĨ~(Ç+ùáÙ Çø®´šÜ�À»‰+xË_U¼·«/^S¸,šªhbåÚóB¯§iùÚ=xQÏÎNǰ¨Íd4õ&M~8 k4ñ�¥>V 3X- Ç¿=j(ëÔl’¸œ…_©Æ¸:ý¾€v³pr€X½Ç—†áºÚ¯P»'7ôòvß;$ºŒ‚ƒ.ì–S ÛÊÛáüØDâ± ³š²°~ÞükØü²½Œ¥ 'aÁÇaFçHp[>‹ŸîŒóÖ¡‡Æ ò6±{ŸúIûùàT/»ø5 I«É�¾ÂÁ{ºèñ¢9,ç; £Ú­°ìk ViðÖ�;”5?þN˜Í“z¡!¤agr %»© á fû7Ø`?ÕÙúÒ›Ú¹ÿÞKþne˜Ô`#L7Ú-Lk çË�–X¿n6y5üµ–œúa)}‹�ßÃ#YP_2‘W¤o=’Ðx²_¶‹‡~v\ñ(ŠÔ—tC‡anl±Úàya\Œ·°óCß©O€Ñ1¿ ÀÓ„CFNjى?è©ñ¡ri:$£»gÓÄÅß„›§<øï4=îñ7ÃG¤ÁŒÂr2³{/ù~֓μÞD ï{ÑÍùóDßÑx~â*Q=ë 6[²ÝìÔòiè’[¿;æRQ½Ÿ< GÖTŽX„Ó\Â8^{!f.'”Ùn£7ƒbqÙ•¡|ϺŒ/>¾Qmz(Y?’&»Ï†OQrÇ4Š~é°üÓç¤o-…Íöïõ*Sl¿iˆwÔ¦szõ,I�WˆhÒ%…ãí½>ñM5ä>Aè1°»5>‡þ÷:¥ÇÖëòÙÏêh~÷-hÌG½]6t®cŸû8ÖìwçàÙ»ÄÍùÿ:¥–2÷�L�5ÑÛxhmzŷ˰:8…å^_§Æ_gÉh}+ýVĺÿæÃ±¿(Ö@Oeù£Ãë±8> Vô«6^F?‚‰¹d2g+¶|L”ÌÿíÄþYê=bÅ,ùKJ�¥WÊGâê �õMïsGâ°z;šýç÷l|iâÄûOÕøû<[îöd;O]ô ÍZ®Í}ÑÁ1†¬²‚§ Ý™þ¿’9oñSjs< =¾)`· K$²Ç5øhn1õzuLòÑÿµ6uƒ½ùñ|Ýr ÝŒ…r8#ºÿ†·"2hé™ ÓXBo&ìöŒ:*EÞhs=•¼‰†­Ö`_ÍYòw²ÇMóÜX«Ã”­BÏâ•…ûáo‡¸V_„�b°—ÙMš°=¼VHÝž›SÆBc±zT=é‡ðX±˜–5ïSXkX4x'�¾† ©ü¾ßþ_ºêƒ“tOxñ Xÿi8-Ù–ë÷°Òë,mÒ@2©Ypü�÷û–^½ÏI.^sæ.Ÿ« kîƒãéýŒÍ ñÂ}y�¥)·*F`Û:cœnú®LïG]Ñ>˜äªˆZ×îQ�Ьù0Š.¨úðü3ºòIûHO\c¡Mî�Uø[¿2±rh¥Ø´_•ʶAík]°Wk%Í@[*9ï K5Ex¯û™n¬ŽbÃ!¯Ä3zƒû%£/‹ÍÛ4ç¼XÇO*� kú‰òWšh­jýÞà�Qƒ:¥A—ô àw ¦GÁæÂ¯ägu *ìÒøRÍ>âÅ7Ëeø4÷Àá{&²’æ<.L̦éWsaÒ|ZaÊs<ßÃ}O´7Ócx$‹ç‹Ò^©2¾u‰=›Ñ÷D4®œ¡€Ñchï$7\}z1®¿-Ùú:®Î<Àá«úÑ1¹/t?`¾y@Üÿ±$çË�º°ÛËyÔ„Vá«q Nw½ QohŸ«~76Àå‚?ZÖ}t]°±Ó ÛìÕ0²z¸dÉ¡Ùûɵo‚Óy�4„}MêéÉÌ®Ýç ²ã~yqX3çȘ*€åÅ·ô)¯Òú[ƒyœ*7FTâóÒƒâ÷m…òS #. ~Õx}Ão|òë¹ÿ÷?Ê®Á¶ê·dpB†‡¹—À‹¿Õ¨)ÄÃøÅ<Ù!“Ϊ&Bžä'ìÆ b(ô+CX¼JúPÆ Ïf5Âó©Û„é‡{C�ÜR*>Ÿ_þóÉäK^Òç�n»áLå±Cí� ï€ä©*ôqI�� |áJìDvרÄ"él®Û¢Ë«Ò8Ôg^:«‡y}# °{‡?=C óVr^ïï¶o‡˜¨޹ [p±¿R]j÷2¨1íW>�1ßÿŠòczóÃâƒbMî}ؾó­=­ô3øÇ�(Ðy¸ÏÕŸG\‚1M¯èâ Ýn[+–?] �Þ pri+5Í„±ï<9·N‹ »MïÏîn}óà �]UƒÓ>ÀÒA”f–ƒ,ÕÙñ“�»Ý ½ý­¤:ØZ,úá«PxtD¤ ”x^ŸJ~1„h�çÏ §àrK9èc�óÏaLØ.Lš ¼ìçÖ®’çîEö|ñ}úÒè'³œ{ÝÝŠ},3p‚º,÷4I¢7§âíY˜%ìÇ㣶àÂ@súfÇJ6óùŽÍ,4{¤zÔ }+µøÉ²M Ó7kðЮ‘ØÔ¯V*wòÇLyþÔ°ƒìË´ ñÅ»T8‘Yz“Ä”W2˜>s9÷ŽIe…¾Ý±Ã¸“mµŒP¿Çyšªj�ëRÀëÐQýr ¼Š¶PäzŸüÜ0\³Dó‹ýçÃÅþé~ù懹7á¦ác2Û9 ÝÖHØÔæøz-¦‹}CÅaklÈTÿ_ήŒ“ŽÊó¡vŠX´[Ÿ\wýõ†êH¦el†¸Ó[pàæ‰_jPâßç¼­ó;°øúR�߈e':A½.™Ìâ†c°Î+J:!ÏMÿôªÙ*�:WfKbÆz"¤­Ç}� g´ð¢�y�Zó&îÚZ‰sSBwn:.!þg<ˆvÍ|$þÒn'×£wIÞP‹+0M»;ŽÓW‡—su¸ÂÚŽ oDûzÁòxOl×”çÇ>Öxqy„]QÃê?Ý‚»’à§M,ÛPß»ÆqhÝuñGUÞbéÄsªŽr~øZ{ DùUè`øç�L‚ëáKèú$Œ¶“’¾q<ýg‹ã�¯”ŽrM†Ã·W²Åº*0ž‘ Æê%‚u£!?ò3ÂýOCлù0ì“‘à,�™ ¤v<{}…Sw¢Äa˜ø¥<†g¬€?3Ó“ªf1¡l&¯óºC]Qð‰·zYoÂ;'â©«ÊÜ{–6Λñ\ŒßáÀ‹mÀ å/É$m‚ÔâÌ%úòE�ûHdŸÒëÒOïÕʧÏg³4YÞ—=ýÁW´ní¤qß2jý²ýhFÅqɵv],úÝ]Êqä!#~ýÈ C7ÆâÃåš´¸B_{þ–n¯[ÌéOçQû•Ÿ`5]�£Mº kŸë²Ó“å˜[7}Nº‹ËMQY(¥G·{R¿4].�¬¥ám·ùÕ¨?¬ùwxè«) 6´_Z-lº üÞh5Oo”ÊnŠá޾ÁüiFÄŒØ@‘ýp]NOÜ\¤Å™Ö»±ã’÷Œ»I—[`¿W¦pinœxý®É©ñ’ê,Ö‹“¥Í=³ù×‘Ûøeî:ìÑ´�n)ãÏÃ$T}€ÍY%Ðè�‡ÔžAÒ‘<©wº”2µºJVSå�Õ8eëq\P3¿ÿ¾}í¡úã¸Ù¶7þtžƒCÞLçcêGé�ñlÞ• ?öLçk1á ~¹ëì¢qñ¿ìÓ­¼>^´|l>fÃÝ¿ÙÐ{[,Ÿµ“;Py"×VúB‰D¨€v~«?{üawÝiðËfb]ÀôcPZj€Û¦î¡)™tåœv¸lú<ø¤Ç3)yŒ;Oùƒïã£QQÆÁጠs‚}ÍëŠ×mÁÆ#1‚~Ï.¡½:�’¶‹‡”F“b·ó³6¦Qv°ƒä�ú4öà¯àñ¢<ÞÚ²É;_htAh]�ŒwÄC̶9¸/À ÝÌÅð�[±ªë n�Ÿ‰Ogð±MûèúD[}ó´‡ò�¥½9¬ë}÷n‡ “+èÝþ#и­œn{ð�:‰ò"ìiÄç_,åÃ=žCäÀ�‚ñÖ!4×PŠÁ™Î¸g@?ž°g¿¨É&If [GÞ“6TÆQhH ­˜°òãl1Ñèß ›‡·/”ƒgn´jª¢�¬„¯½|à¬Å:;ƒFLy ׊1uêŒ>ÄI1ðºß*öðj+;`o7ؼa,Í�ŸÌõÂ<øaµ Û%ØîgBò·‹)ç{"íõûç÷*ÆÖü•"cͱ {V$FSši$i•4âýk.<}±;�ÞV AGê)ñLøßŸÎÎÏöâý$UXò:�®lvãÑOÚ(-hæÔI•pêS:o²ê¡SžG“÷Bjèú†û4Äq+‡\œN/‚j ÀÛ•ß>_@+Ïí§G–òì©A6û6øî´âÐ7Õâ̾æ¨*âŽÒ¾Ü2¡PýîÑ¥…zúø¶¾ÌTñÃÃ%ÐÝ<oìÞ#tù•v'%a’Ñ,žž’Ä Ow ÇYœâßiïŸNö®·"xÊ÷ýH<¹úX æ¾l‚ý†ƒÇáJJ®Ðöh 7AÅÔíf•ØóäZLø/�CÉáD%UüoÇÉïÛऒ6h­%¥³2¨óO‡“Â÷>xÎþm+–ì-G ôéR¼qÆ”¬½Có #å׈½ Zaäþ 4ìÆâì·y‚Ä+GŒ-ÚÏÕN|‘–Oü@ÿßÜ1á*‡•æ�óÄF§äMBL )Njãk¾ŸØüJŸç>#ï EŠÊ#SŸQ©¶'º9&ã‡çAgŠÄõßýÿyªbèHìa¨ˆëûvcõ%nt¾ÁºÌL0gÛp.*›KáßèÎ/ͺk÷ ùúΨ3EÆagØ »@Þ3zƒÍúéŽ)Wàè­å’à3Ͱñâ>Xy溸uçnÔø{Prók5yçð´9., ÿ0O�Fs÷—ÕPqÒ�?ùµ‚{co»ŒéÚÚ¸X†÷(6bÍí‘ü!í) ¿3ü€iûÎ’x'{JG‰‚²7æå‘Öü°÷¼À·Þ�ãg�áÍ·±°¬^à¼:D<=*X_TAçeû0ÿÇ>Ð ^…'C j̸·ÎH˜þhÎX$$�#;ð†t]êl/¼ºÛLÃÚb0HÞ(­àžÂ×’+âÒ ¸µ¾�Ä«o„kÿ:f³Z5ôV K$AE§¡{79AÁ·6̧/[áñŒíœ5ó)H�OÁNKl|0OTÖN½Bƒ ’„hµAxLñÄ­µ„1ÎcpO`–�¼#AŒ{SˆY·²ðþ?1©Ç j‰Èf…¼½bHc1´Ò2¼48´Íµ¸{®K‡�!³Ê,Ñ"§P<4©^ÜYÆsøÿÊïðþ­÷_±—šb¾Šfoî’aÑ,ô;ûšÒæk E½%ª�|:Yîð#Tݸúb>¤î˜&¨ôßL§v/¦á×L¥ž:1Ü–ð‰ü¢%ÖQ÷¡¶gÌ2°"Å‚µ´ít(¯zpÏîÉz‡>�Õ½# 6ýÓò¨`n-[„k�¦àÃþžt É"n§çÊò6ÉD–i�䫵[ `[”¸óôSñ¿à ÌÚ ¿öðjÍ`èi”LÑ#A�J<Þ;y†îÞó«¨È§Nèõ[Pl�ת#°tC¶h6.<_Ï×ÉHŸèn`ñ�÷§vÀ™ j¨`z[d‰Â Z;ƒÞ¦bï™/ÅÄ?)üòò zàò]ˆ5YÍÆ£=°ðð@vröÁ7Ú¬²E] ŒI‘”M§º¡ü„qµr'ä✚xóxš| �~‹³è§Î⤦y¨î,Œ›÷\úú¿,òÖ–GGÁ;]rDiÔ֪חxcÒh¾u× S�àÙŬoWƒŠ5¡Ìø+D…D`DÙ¬~�#ì”*>±_.ü¸q ,:—Ьe=ðâŠG´sâ=˜­ç%Ýž¹&Ýl£ÚÀç’£—ŸÓÀWƒiðöx:íÌžŽrü^5‘¿Ê©£[oa·aŒp®4—Ž|’¥šU]4èW�ؼP�ÿèNàŽ}ßèír ßs%ª,¼+•GqVÁeú6hÝØuFb×<‡çŸ‡MW½q€c?Q·D®J¬ð@cß˹×|`Hœ‡O Ãi:ýèfÃXüó>œçÊøŠn›¶�ÁW'zRyœ-ÊÄ[§VãŽ×ª¤Š’¥Óá�N+Çìï�3'î§Î>Û¨[q:ÝßN�o}¶CmçVÚ*o )® hô„fÚ®"�·?t¢=$ª÷ÅÄMæøç…=Þ+Y¹2lq§]ÃùøJ÷ïo§ �æÓ¶s¸÷ìâ™U±©©‹?ý¦Œñ¹ ; uŒsо_‘0Ë·‹Ò>)âqÓql³D ”aÞ$Œý›J�”W‰ /¶s܈DðÉÈ�J·å°½ìÞ rjJâøH ~ºa$üÉ}OM+TÒcà|A3¼ù¸Møz©”öÝ)<Ê?FC&cW`ož=)Êþ e~pÍ Ï<6¤ÞpÔqUV Þƒyªs½µDÛkWÏÕvÊÂ7‹¯0fé{z™ÖMf!$gæÁ=·ëáýi½%O=‘õx76zÿ€S¶X`ˆË(ë{AXS­Kújð»ëÙ¹¬�”þ€¹ÚW„ÏœŽÅ0|¼¡ôøõ¡8ót9=Í_ŠGûã¤ô¨�¥ ×ZBàÍúX@j¶½Ð=æhvÿ?;bÿ�;Yíá"rÚ«Lw×PÃý›ÐPSýOxŠA{gÂ-ßjQÖü>Ý-(…Í—†°búyZìŽ+^”RwÓBj\¤ŒJ>$G¸±¹ ¢MðG*iM'L†¿Š)Á‹Øüèl·•†ð¶9=øQ´ kðÃløaÌ+r4Ø3Ù˜ï >½Ï£å†Ïàè°$׿Šâ"³ù}÷*Ú~‚xæ÷7tÕþ@Ìa¾pЬB®‘ö3r,¬“ÍPowíÏNÀG^^lu,Žol¤Ä¢ðü]¶ð×S»e;ˆãžªó�¡n¨òUL,«¤ñ_B\‹ [~¾¿ž ¦=JHZs“ªòæýW„ôæ`>QQÀ7Ï%ÇÐÉÿô|Wü7Ž=ËL°zê1±d—+¦·H`R¿³¸²¢oØßóoûÓ«srR¿¼«’Î ça¬{8û>ÌáQ½eùØjÌèÒÄʲmÂk­\zi0^¿Z#¼vÞBûV«òô»öúå A‰:øÈ¯(­[FæšAü"ÿ…ðxÛ+aÁ¬Atót¦u9�óÜ®ÒÚÄþtÿA/®¿v~]Ü!¼x’Ä3ʼéïâíØ²ôðÉQ�nx 1?õÀv�-›äK*-[içŠ@(›C: (ž¾´ëYm ÏÁkßrìÜU¼9ë‡dƒxÖüªjiBç#ZmªÎÃDoìÂI¼rF$—,Î¥ùCGD¦­såÌ…4*n<^4lÓM:äž*¥ËŠéšþ3qÇdœwÜõ4MvÄ™íl¬0œoe‡AªéKJYýúîPçI—äyýãç°bù]è]³ƒj"4¨º—)Ïi…/¬Ó 䦉R!BÇóV©à´Õ1üØx­™g)nšÒƒz( ¬[1ØYÜÚ\…�î4ˆ}–…²lL%OUÀEÕ�øÙt6ZTìãônlz}‰¤Ge)�j˜‹>ʺøåt8lö[††×Køvå 8rî¡Xö�…�Oì°"‚ÕN뱌àöƒÏ¡!_î\èErf`Žæz´uëQ#ñõà,*\ ý7ÛBm? ¼v#Ãn¸Æ/ágd„?�ƒóÝ5 ùû¸lÌ(I¦¥h;¨V™-öÓÊÂ熖„ûŒñR¿3Ðÿá0kÌÀ9•hží y—MÃ’Xï¿RÞùi$¸Xß{„KþÎG‡¾†S¬‚Óý'QŽKµu7—”Èâ}Y„ÉLø•Ö!Wß×jâ÷^£ØÅç_&Þ¢-ÊßÞŽUë)¼á>DÇ�‘¾û¦«” $ùŸºàï¢�ŠÃþ1¸"õÖàÛã)ìa«ÊºRª[¢ÈS 0òH’ôÊ‚T\eÀ…MÙkc1g=��Y[&a ¡%z�¬K>X`‰å1äéyZq> ü*"êaçÏn(.Å­Þ–äUh!Œ¬ÏNÙ²Ô˜“+~LÝ/äjØñ�/{`õme<­þ|¹wënÂÕ1"¥ƒç;~ÂŽ6/ŽOAsSE.ÌÜH Ÿ”qF‰7¥³*_›µ�g{U@ˆ¢2GFƒµ„e­cXæóyjn¨'ZÆC߆F §NéåƒqXR#Z8D‰­“pýaSAï�ÿþ½ƒÞöE¬‡Ø—5â wsLÌšò¯w¾&ã‰Êìó~%/ R¡hOy¬1|GÅ«Z@»›®'xÙŸUv„C56ñ|ê#AÛN?]êOi´š «ÄF]mî•i…÷ý—£k8gl4¶&ù?h£Å–]”õ&§»9ì.„Ÿ:‰üýQ<–¯Z:!?¡`ßZ3f8�u£ªÆv!"%Îçÿ‘1rÆ£Vz¼túdÒ?a¯§z`ì© ñmß7_fƒ¶'ÃÇä*Ç× Gòç{ùÜ'>…&�¥žO쮤ñ¬ÖßôsßQ•—Rï+\öi<²×—Œ¹JQÛQÕy|a­GÿÄR»V1l;ª‹kT é=ù¼»/  UëŽó™�bŽL<\.�"··¦¸Qî»°½M�Tt£Èèû´vælP8Q-)¯šÁ¾ÿeÒþHMê7ý?PÚ-À¾Koww:ÂËÖ|r-ƒbï 1§I’rŒ9eÑ|þ>P•^¤ÉÀšÖdè3ý´ÓÙ´{7´š2Ó-µò3¥êÛ¯Sqx4¼yíKZŸ pq’&Ûf"¸\Lk|yWŸ,üpÛšóô(¾_þ£0‰ ÷⎺LRP‹â*ÏdaùÖHÈ4¸ªë?J\e’á{/Q·X‡ÏNq¥ŸU÷…äÒü“°ièfI¦ž·�õ¤™„•£$ülw&�›†fð²æUØn£Bm ªämØ$N¸ÙÅÒPa¤û;X4-[”ùrÖ+ì3í+éÝ}¶ïu�ü­F‹ƒâgÒŽòØçÖU¸¹ò5|Üm…ÃÎDSÇ•ç¤}%;³ÆacJè÷†þlcxŸ‰?M” }Ú>d«ÀééÏ@ÝûÝ1Ÿ~’é4¿ç+npMá4÷ }l(é7{Ó¥™;pïþû€>+̃uæ;kóN8Òƒåæ #­��¥W…ƒN1ì4¹ž®·š‰+ZJ!¦vo­k½&kœÌƶçƒð‰ì ºàÔŸô.è i~½ñ‹B<¬™ý•®·¯Æãçû`¬õbšóí²¸4q Û übÄöK�…^ΚœyNÊ&OcyÂéJÞöì‚pÚH¾Ñ‹§¾)§KGj©ƒÔ±gãs—Sä8ñ·øöw0º†Äò™">Á…ó*ai¨;�Ô@y³b£Ò›#¿#Ê/»ŠO2rk~nmÍhÜßJû�¸KûwxÑÕ§¿þ* SâqÕv$»øy�ãÔ¸6 )Šf§Ž\×»7ÆîqäÝÆ/¥}51ªK 1ex¶ÕÀ õTáèñ¹øH{;]qäý�»óɤú6–ŸåN�–áÃùxÚzEŸ ŸU‚ÓAU<8¾ ä·Ïd…½пo­ô×À»6('A…yZN Ã†Žƒ�¿ÜQµ›Nxý’ÓX²i3Ö©!¾8ÃüCÙ.ºô'§a¯•fH±xT+Ö—¦B~š+çø~V;Òˆ« ð»5 'ÍaÕL˜»6š5+S[¥>üV™e·Ã±«It¬ë<1ÏýG7qAj·:KŸ=°fl?èfè•*ÿc¸¼£zþ£0Þ¤Ò‘RQ!*”´¾Ÿ{Ë*d”YH¡²’$DF%m©(«i†4$­Ï½2’ e5$„~Vöþùûžó~Ÿóœç>÷y™% RóðKA$?W“&—3œ(+·îê¡mô›Š}9‘4Ài7ÈUïÆd3U<2~–뎄ǩËyó×ÿIš‡Ì›I‰‘‰d7ð<~±‰ž(=¡ÀwgaÑNsõ=¥²jø+U–¯Õ1°\ŠÒþxÃøµ‹3ƒéú´EüùÞo2šx™¢ÎˆyÅUt቟PÝ�=%ëgš’Ç÷h6“JÆ7ôgÍ‚nHýèØ%?ÿ\åç; Q'sŸyã ç Pè5˜us ¿AÊëlq»Ú~¡(ŪIKiÚÀþ°áïDáýÞÝ£ÏÜñæyfãñÏÉùd½ºáÈgfÕT8Î"LÊÉiö!Ü$½-ϼ¢�%- žO§ËÑóqìAK aò›`a‡ÉYˆ½Nk—;ñPçXØÝ“S��8ïÚ*øÛЛľ…Ÿ™ëXE9–¥´^C…ôPêUÖ;4yÔZ†„i{7ˆ—]Ü%蟭„ø¼àÜÖDRCbi˜%¯Ù…cž9¡¯»*×û.c«�z|ôÙ³òöqÝbuø ,¼Õ•óg¡óô\ŠOZ+Üyß“}\†¢cèñWÊ]rò¸gר¥×êu)]¾˜+ƒŸ[”¹:Í_ösäü˜D’ò©'ÔÂU{T(tõkŠÿÜazE6/+û®ágë\„H¹P¶Í´ÂíÉ:¬•½�íìâyç­¸7ý+W÷¹%ΈØ3»Þ@œ|5¬4:*Yh±ÏÎŒ”z¯a•=ýi÷qÅ:Ü�_w'cÞ�#4X£?J»/âx­ËôÐæí]V-Ü8w «~œâÔð7´Åð‚Øß.€¥æ¥ããïY´ÙÂZTº¯I×G5þÛ/èkÌç^]¦©¸�›—C�í½ðëézÐûçoõûEP8ý¼èYø–ÎØŽwÂßÓ³ÛñÜoP S¦j„%ÁÜQÓù~AÈK/¨9a2-;rº¤vñ‘â.˜­sUâ2y˜®\ýÓuðñÍDœà'Å}l†ñ¯mEtdÞ ´qUC¹jM®o[‡‡HcÜÊBŒø: ÃKZ…OíÇ)Xf½mQ§Aþ}éð¥%�`"�»îyð�ßFtݵ…«æ'rèÕ29•ŠÕÚaXÙñl›'h5KS¡æuö›¢k�GpDE½dðÂ?âÝiÓIÍ·”ÞÞâ'”M¿ô"PbÅusø˜Q ¥ûãïÞo…ÏMgéáš$l:ì!ôîçD}Ã×£,žbóü)_¿Dà7ÕlR –Âæ¢h :�N5sŸˆ‹Ó¥1ußLaÖõX´(M£GÏîn×Á¦ëÁìD“PûeK¿m_UÐÅ&ôo|Mžá+a�NŒœ•ÑsÒéi?OP®@µã"YÞ¸Løíí&*->ÉŽ·ÎuY€s¬6aòñh<Ü”@3ºc!t×THàÜùé “¼&…{o$aÛc0iÖVîñ«�r}7²ºÛXÒ{öü†™Ö!ð­AËă¥Â|ú¶¶ B5bÍ##øpÕ>â2˜o4E§÷Nè6¨3ßæ a‰²lb2�o]ª8Æ^)påîw 2'P˜fy“_MVçãMqÊð�ØwÜ@¾c,iÛ™\û>ß×ñGæhô"ÚkÃÐõ¬€¡ù-[V^†X^BGýÝÜ¿NZ+°Ýóah»¼?Û}XÌÚãH¸8…Ÿ'ûó@YYZܱR<`ް­ì4ì9ˆN¤½›—b•E@E‰\#hwÊà—gÒ`2=7;ïE�PW‚ȵ|sV?®¸ˆGi˹asõ«Úc"Ù¾¯t@Ëã_7Kô×W¤£<ÌØË· bBèS¾pKåÃé²¹+Ë�À„ÇÿA™qÐ2,‚Îß…´¬ñ3=תáÓA§¹�5nÔþ|H¹‘(»Þ�¶Äp}©¶¸à‘%4Ð$ç7%03ñ 8ç¤ã»GÖÜ1ÇÚ z ­ìá÷_9H~ºŽ�ºÅóÍÜ@> ÅÀÿþuìMZ˜¢wƒ: ×òŦÓÝw�§GÁ7zžžAÁwŸA[øzŽÙv‰\ÖëA= ï¥'`EÙ!êÐa¡áö ü/Ç“ �ÁšªéÔËm­0Àe>Ú`ÆrS� Éç-ñü²$œºj8�‘æ3©¨t½ÚnÝ�Å…R<¥6…¾T:¢®âa_É“#ÿÑ¢×µvÃÒÿðï•d¼õΙÿ�¶—)bl­&æôµä‡f‘È/¿ˆ�VÆ1LÁù“ÐÎçæz¬ä¤W*X`qž»Z‚–~ô�œK›ß¥S ×Ÿ2Z&Œ2ßR8¡1šÓ ~À’ ‘\8†¶ ðâc�Ñè²ᆮ'פđÜ÷{”‘Ër¼ˆ3Ôn@|Øb“}F<¢sêCÀÏ&“´ iûÃC�àë‰ï¾ù`ÞÁzºYPÀÚ¹æeþr¥^üw�×w{qõ‰ñxr–Ö\¹'»Ü`cípÁâ]ú«œáeo�Qló-áÙF´:ÿŠÒGgšNž›¯€N'áæ *¥Ï9ßãáuù9ú³éÉŸÄâA?ë }¨ßNõ!3xtü7!a¥¯ô£œ¥cx³ÇQxã�fž#3ÿåP±ó<§:í¢eŸúsÏ—iâçI�ør’œŠ “µ%®Û„Õã éµR¤¸>é]ðÞ Ëàý‚öo ûo»,¾““¯ªKèi6Û¥]…'ÿÉBõm ?xGì/ͺ6ž4bw o_ÁW&´C½ê5¨ÝæÎ_ÿõ”?Cbá¡]V~z-ô¤Fa7\¹Zú )íø ÷ÏÎàÐiz¸&¯SŒ™f€�j3a4ý }¯¢8ºÿ,´É6 Œöé$•.)NÛG£µ¬0`v0¾˜R/Ô[®ÆùzyhöC7½ëbŸƒÜ‹íðpl(_ yy¨Vüœ„2çÕQn´ t] SŠ¡\1](ùqˆ¿·>À"ŸÞxÿ€.þ§û¾LU|°«¥Ö…ÓÒWÙì’ºå.»Ñ×~z¼„dA¦ºî·ÚQü讑ÂgsÓàRa\Ò/ƒ�=4zÚ7Áà§«P¯˜Ê#Ì%ôV£†_ðü œbÝ%ÞÂÎë^QÍ€3ÔO-ýf«Ñ­«nüè�„×L�¢ÇóW° /ŤWªø*¸”‚Úfà ûÌøo�ø×õEEé¡[½Ƕ¸¸íÀ_ q˲‰0šÝ`¥±9M¸ÞÇ®ÀÛÄñ¼¥;”ûÃ8ÃZ>ÔËŽBŒ�q£û0j¯i£ï¿S’¶îÁÇ5‹9_wC3*²OÁ^0“&^>Õæâ¸ns±a×[ee ç Fc~°!<ÂEà÷å4/9Ž=÷^� A*ÿxOÙ‹áYßhî᪅=NéaÄÛqh¡}Wò>÷ m•èÙþã°_ù Ù„tC¯{ú8Ý/ ¶½²á‘SD’ŒÄšE_èÝŠ­˜cS_ïËàœ 9¤àRMž+*d^Á··°)®7ÜÛâ,Lß7‚Ͼ0…-¡x}ó¨=a,ш”$÷Žd�Q²|÷Ú58:j<\ð€ÕÞâÒ-éô1UhÑ1†¸/µË:¯¢ÓgŒs”ªo¦S�ÏÙQ‘ⲺW`ýö /Ò�@Õ)öœ´X™äà?p˜?Š­WîƒúìY”à_!¬_j\¢Že,ûå€pй¿½$»ŒÔ õyk¿ž#ZØ;,¢ Q@°›­Îu¹Ï€÷vU &�Sy¿ž-ï¬o"{Ù|Xþ>‰Ã�Ù¼GlðSÚ`üsSœä[î8ž{Ë”çGcÐmñ8rúõ]*©™©Î­ËoS¢¶-;ýAæÄÒËÓ}yä€y$‡»èxå>õnº¨ÙæL­ajl#³”æ¸Oĵ¯žò·¼"F 56Øñg/#^P‹·þ«Ϲès®Ñ\Lœ~–ô™%„®î ¦¨rÓÚ-ìÅ—Î�{U­ÞUÇ=ᄂYÇ ð`×EÜ÷Ü«]uPGÎGÌ¿Õ\Ë[iã»WÔ-„QSø8ž¸·,l¢’S¨ÙÒ%HžHs‚ÑXöû',›ƒ±­“G«mÆ–"w)áÅzP¥3Ð/JA´(Š*A:¨•­�™ÿrâèá öÝ}lßÒ´TØ`#‡æRøˆç³÷ b÷ŽX:ÚœÜ^&q÷Ód´QMê⨷þ!Tí(àv%\17 ·‹Ão7 šãó„ÚÑZÜÕ>úêÆ3Nl¯º&/æPÈ«0¯¶ üÊ!Ãä|j·U¦…™peìÐý÷ A°Úœ,A ó‘˜wö�’ß„ Ù§(Rû·¸êKߊ¥½¬E·q÷¨&H �køZß^¼c¼¿»Ñ­æy9~V  ?�úJè«Æ0 :6 ¯-·„³#{ÃßIß M¸ïÜÔ1Ámw$l†°3ýq–{špR<Ä«†ì•xÄ=«PœóIð95š»ï‘õ^¨‡u†½±©Ÿ+“KçýîRèýd'çJ ¸eö>˜–yIüÖèÓˆÓt‘úòág¾åü¶X_{�½^qŒ³É.¬40fóó�Ôå×¥åv‚O÷|8ÒgÔOÄÜz :k¹\¼žeE{öB§B,»”ŽäÚ¸Ïtã›&ü· #Rcþ`̽vSØ»H[2Ü肱 ØLΣ®©ú¨Wñ”ç�Ë…#�}Ð…}ÐÑõøïý·<`òw%q§p•µ\püL#k–âÇ \QõQ¯A�ÇQ£ ¤'±à9[h¶�<}zkÇÒÆá„{‰êŽ;×øÁN! ¾_n¥ÓB8ž5KàÞ‡¾ÓÄ·xÛ¡á<¬ €]g©IZ¨çÌ~6SxTmoœ<‹ƒ£àtÁb²*1{xÄÂx…}àw;·Îº(q¿Dò)®‰Ló®…±˜ÕHŽÇ¾Ð鸯¢á…£`?N�û«TÒÁf$3â�¨³o‡XÒr�ŒÎü¦CMWÁ2YÆLÚÆ—�òÉó[ Y4Ÿ#+í*æÙ�´«ÇbŒµ˜�9¦GÄüS8ñ—'v½­è£®€µ ÓùßÚÐYs‘î'üæ;BåÇí”öf0¤¬û¹i–¼5oû¥îââ'½ B§oPì­�’ãÖðãÎ}|½3U®Á4…ÞüìÀºRT@í2}iÅœÁ\±°>�‰ú<1ø/;†„ÁîoÃxóW9 Õ)À¨-3¸óz?ŽøjÈ+ž>„¡òöT2:-¢.ñÍ ɈgNhú*“”ûcâ�3ÂÍamÏ£<ªÌ–?L¥Ï×epÿ;V²Üæ@7<ÂÈuÚ~~r±…ê‡ñv+ \QßÁoŒÌ(çÅ<+ï ]ÿ:è¦o†ðò¦ƒðÙÇ ‹´ûãö²TØ¿YBGwGqÅ“cXëý†í1ÅQ'"`Þ§\ˆ‰+©Ïj }ÁóÕ{€×ÔZh\¸šÊ|BùÈ�Õ¤{¯/^ñú!š›­¢#Gq�—»ÀÖ()|ÿÏËÚv°$Ç5Ö.„�«#ÈNi%ùã/WAðœ%OGBìÙ0Q¦r»Ÿ–[¥C|µ)¾Y»Ö-;÷Ó» õÏ þ^3Ž&n1)?û~5Ë+¢ö-\²w½Ýõ¢ý¨]7¼´¼Y­ê’زuj7“fºØø~„Ø7›PûH8/òé ¯t›O9†ê“…Gm…øÍ‰¢ÖéÞp^øãçÏ—~”€Jq ¼³BÿN†?ÒHЛËCoÖÀÇÔ¹¼,ú(éMü�7Ï�”­ šÜÓ#ï¨ðB‹[´7ÿ*9·fÚõp Á�:ào�Í>šQá2�ùûTóå>SŠäö ,x§Ð½½“Ê\BHU>ŒÍÄà}e)Þ4¾T5C –€”,û.N;®…žÖº´?cí+h¾ÇT¼Û¯ BÎÌ€½c=0pÆ&ªm˜À÷žÀï¹²hæëŒÉ/”„§SÓÈJî‰ðÖT�×ö®¥zËjÁs¬*®ÑVf›„I¼Ùà®Y9C|!·‹Ò÷ÄÒA�3S‰Mƒÿ1Ú!1ê¢Þì'ØT$“ÍÍPì½å6Ge¡)Ã<ÞVÔ§î€7•QðIs/iÇC”J.¥¦ê Gßwô²ßZŒå<Á4 ´|Û¦áp4%¶^5Å6¶S–ªòÆXU–ºÙçg,ǽ‰Æâ‘ŠtpY±®Ø�ƒÛ'[Å#C2Ñ,j9Žû›Þ³aì¼z²Ž`Ê’Å⣊±jÊ‚òé�?ÒôýÊèÔÑL©“y`kšdP¡¾»^H3W%Áæº�‚Û K¼t4�ùÄ%jS±³ö®ä‡…,È1§¹V„ÇÉ?át¦~³5ûÑ|ÓI ï�põ’÷4ÿWºfb Ubˆ ‹ î¿-�[§c�/5cÈ~ã ñÈ]Þ3„”†mµ;ÕI-÷³EÙ–Tš«Ñ7Ó–&ê•¡�o42D?In\D’qC»ˆ<ã=0x­ÏŽ*ÕÂÙ­0[ªL¼Úî€Ct1ü‚.Kω€ç‡Yؾ ^÷YÏzß¼ÄÙ‘{„ÛšU�Æù-èüÌÍÒ§Èoq‚­÷ÅŠSÌØš/XûùÐŒˆ'›gÎ0Q ÄõÏâ©qJ¸e„1Z�™Í®Ëº©õœ.“a>*+Iøš\*_¡ÅJKh½k©Ó{4¦D[Òyi¼y¨ª‡F€ÍröÍL€±ö†\ŸšRá8= 5FâÀnYž]ÕŸûåèðO÷žx¿jxGfØ ú“L£ZXùÞyááÄÍ�ê4WŒ˜D¥zBê ^h¸‚×�½„¦+vð‹é¬~!ßFÿKQœØ‚'â)eJŠ`À±xö£!jî/G+—�(ó:JXï‘6¦˜hÓëŠ �:ßV2ý~/TÊå ºÚ_”Åw¿5Ùbª9;؉ôíÌh.yûƒF~ZŠ]¯Ÿ gÎÀ¶´åÇ(ºçð‚V­½» ¶S¹ª ¦/ƒO—aùæC¼¾4�#Nïá¯MêØ¾¢ÀκüíZ¯„õŸÛyæ<#õˆæ+î4§æ£Øyi°X3Cв2Zés�ÓÐ2­'w<Þžšæ\^9›V즊?UµÔz,ÞN™Ä×öÜ"æUŠƒ;0ú_·ul“&¹‡³ áï,¸è9c « a¯6Z;çwÑèëhë׋¤¸ß’Ž[¾…G¦¢W‹-�í9GLþ§û×õ””.ÏëB<}®‚kÁpÚ+×J\‡À•gùÔq½‘ή€„~~=¯ˆí/ë%¹Ow°´–¿5àÊl%aéwS\ñÐzïÈFïà]k£8¹I‹šÇô¡AN“P}ç6èWPÄçžËáøyDZ§¥;uw÷ä¢ÞU’ˆ˜|JDd·¶¤áÎÙ1à©Å7VWtò‚†qó°³ý©¸¯ó>]hP@^ºŸ'lGýw6Ô*F|[Àõ® ñ¾ý 4ß<€�Ž> çߺiïÌþ;o…�yxsO{Çð?‰ÕJü·¶?.~ô—tÝÓaª0Š÷õæ'F'Yëísò1©÷¨|äU ¿kÞ°)¬ÔŒ±OÞX²öZ‡ÒU?YmS ^Û¤ÍQ=|1þtßýT…Eç°Ðmºn“¡.ùd¡gLXQ%¬‘;‰ ÚtøÔ8‘´/О5<ýs,n)UÁd-OŠ�¤»›×Zí>ˆÃË,i†ª~¥NɾÒ[‘T¤°ƒ=òþÒ6ì;ö´ø}€;ZÏxŒg»¡Ë�㢟½?GMgG/IfûEôkË£FàÝ5 ãù†žÙŒ¥çë(Ô~µTGôh²†w=”0¥(„•’ËxŒNµðËÑ·6'a¤•v­[€vë' ÏW›¢�ïz^8騺¨òíÖ¼|˜5^÷3äê£ÖÂçDGñNX,ß-Åñõ1ÛHÖ?*§¶‰dXk̦w¢ø–äŸ�`Õùí8Ëù °zñŒ÷ ÍÈI¸27˜3=(Çi¶°Ðî¼°¢ø xv�âãvKypÒ<¶¢‰~Ã@Ȭáx>Œp³ÿ.h)ʼnŸv’Ôú¡ß8ƒµ€·êôkLÙ89û6‡Û(½};Diç ÞU ¸¾ œ¾�±Äûq‡¡°_�ÄTá+ÙÆž¼�<Ãmµ;ßa#é�¯1}¶ÜÈr…1ÿör/÷?}+üÄðóµñFk«µX¯÷aþÔÃŽ fyQ󪯟ÎJÚNX;O‚zo‡IfDjã“�ÇøBHôéJ û¯‚9%uge 塊u¨ÚXBNûÔ„W‰ÈÖáýÙÑý1äV¨ÀÙáôö]¯ÊêçÆð³>Ž;øˆèíbOsCWò$çŸ|:HŠgû„°…‹ˆ ;xð‹l¼�cœ"ùݤt*ý½R\d->°ÒF×S9¸im*-M==í»(qå\«ÚFʇÑOÝ çW}§øÝDZbõR>) 8¾ý%»ï+ƒ�—FÁûJÎÿ¼ƒ?[5ŠvRíO];ÆKt>Â}�zøÔZÇ…z›< ÜxÆo¼.óï¿¡øªØžOïA§û�üäÙ\{É Î #9\€ ;¦<ü[¿@a¥ÿò/Éœ§ý;RaV¡"öÉ\ ÇÍ¥àêèÜÔÀ•íc±îõaš=ÊL|mÞB6^³uù0�¯»æáê ¹w€ -Õðã´Þ1þà7Ú¡²“w(ñ�‰=1úÖ8yö4 ¿>õÂzAýõ©ôŸÙ^TݤM’õJ¢º•¼Xv5wëçJaœõ3�.EÍkÚÆÒ@û9T¦‡&Ç/Óè§ò°/H _nÏEýƒv´Øê½¿¿;“‡ñ±!ó0¦56ÅcßÈõ(q9F;6á.aqåj ò’Å«ývó[yìì ½³ v˜†¶à®ÅlÚØë|å1]¡—DÕÇM6KlžRN«Ÿrj‹/Ï›s™ bÛýOWw€Ûøiòú´–’U´¹PÙyžíƒ�ÂÒ+m —â'>>aŠŠ‹Ó9w¶++üÊÄŸõ;qvX9—kF‹K¬ü�>vO™Í}Vøóñþš4Ð*ŒÎ4”}è�O&â?ec𠬪Ð1=ž:*n u2Ïiܶ×bæä¾<äÚV|•­uó™|†¦ ß ëmŒKÞ—Ó¬áœ6ć»7¦á°Ì©éR,»_“²ðe®>ç�Z†§Œ¤ø©ãVR Ú€÷G�¡.¬–èèœ$�áø0±ŒZƒ¦sÙì^xÕþ1\8g�4Y‹Ö— az—`�¶/öOwàâë°­ù:Œ|èSe·¶EpÜmÊ~*YϷаê‘èŠ?Mcñ�) 9þœìßÏ¢‡C/Ó—œ•�üÈQˆn1%‹# TìûÏ¿šüxñ]R[H—”/ˆ“ú �+׆œ„ïT7ê)®œæ(Ù(@¼àˆyòíjßI }å!Þ¶Ÿ€Å¹]Ú‘“³Úª`<óáMœbÌ·v Ã##È 2¡C{ mº“ç)(àR¯Ï^Ƈú„��‚ Š‘)0uÌ�ñ¬…÷§’éGˆ²½¡'/xcÀ²Ã6¢Ôºo0NȥŠd³š·—öbŸ’Mü�s±—Éy¬rýM%XcrM`5�²“…Ds~¯Å#+v³·{ ¿¿ƒ ¯î’CÑúÔ£€~4Žâ /й)‹ØÇVà£Â,5˜Kg‡‡—ì8áàeJ÷µÆú¯—ÄÀ´Jö?IßãXßo.î_ŽE§Œ1¿ö0.Š: ~K#±Ö&˜Û56ÈŠ=Çïæ%²ðçŸÞྌ´�Œ«¸=Äo-^Ç[WµÀãiŸ¡ò�ϯ]ƒw^!·æK£¼_ ‡6ïÃoœñq«ù¿Yï` Óff ”JaŽA’0MÅÛ¼BÀÏ:è”[ñv@t'ýß�[`eÈ&Z¹î�›öPؘØ�רO9g¯¢õuk¶�™�ulñÐa n º –^×b� ‚oÞ~j®Ãu«1ë€>/·i“üQäçýFÂnŸ-<Ôg¶üú _½†Eî~œ^6¾Lk£F–p§CÜ’”Å&Õéô£j&�Ýsƒ7ÇŒÃɱüÞû2ƒ•»dÜ»EÐÐA,dý¥�Z‚Žî 8™;Bpo¢ ‹® õ«°iÊ{qÂëx Žz›¯Å«=g@àõ74ùö´²I•ÿº™â/_ü}¤€ÌnGòóÈ}|òW¥Ešp²ÁT�7 ”2ùŠT _¿¡Ã†Y½¸.¿NèÚb�g³€Ç÷�,<Ÿ?�ìçšÂ¨U¯xÄ”ET–i@‡Ì–cê“Løµºv%ãôä˜Û„^Wõqœp·Ì’âÓŽƒp¶Y(¿°˜)¾9{EpªßŽ?ªã�ÎE¢ƒEƒ ô2T¯À3ûÒRn³S¶¾)þº¸ *{€ƒY™$s—¼8ÊA‹˜Ùƒ§íaªÚâVax‚7üËS9hžž ÃÖIJ¶ë4jiWÇg†C bª J>õÀEr@ÞEƒ=Ä@ÏèwÄ’oÇë‹û/¥–;.WÀ‘Ñûùl»ä{qÜ –²ýO�YpJ÷S2ñY€"î^”J?•EÑÙr!¿*€ ¯| ^aîåÉÞ®Y«—�X 3�^d€çY]ö~^ sÌŒÅæ•.XÖC†ËãÁæhMI¤K�ÒxnXEé]¦Ð�Ò¸éìäÆÝíÒá¶3¸am}Öq‡xkM>®÷“¶H5Fß�sÿürÙºoEwÁÎZ.à‰‹Å_ç#EûÁè!ÿ]°í~(Ãòßɸ�›|¤¡ŸD(mÐÇ�N¾0cF™ºjЙ9r´Cóˆ�—`Ãí/öƒòZwø56 Ê‘`£©)Å_àÊEƒØÇ9ŽÓúüSð„w8• |é¡™2çT­ƒcã›óNôÝñ¥¨¶^œIæqîRÓÝ jóç3d¾où÷ûL#žl·lRçÑýyÁJmºlŸ 3sÆ@î²qxnä_è: ! #È%û*�¼�O; N²WIãç>˜ž·�^v=o3#θY%nýâI-j6X¼ÁH<Q-”ì:*‚»Œ,ŸÂʵ†~ô)dþNÏWDsþà£ðñØ6qt`&9ª÷ƒÕ% Ô¬1g�Ûqiv˜0ñˆ$c{Èr/.N–ã‘Ú pó�3Ð_z5ä¶Æ²ÇžU—-à­óú49# –�¸Oƹû°GáUز[z ¯ LÅo%ÁùìuЛ£‡ _ÍA‹ktæG1uºF«/œ¡[ÞÖXN½xý¬þà4¹’à¼/ôÿ}*µ‹H¡y[øL^›LÆa3€óÃÕ¬ÛÒB ]7é�a=ÙœþImãŸÑ†-.5¸ ›Ÿ[aÇN?ž73W\ò(‰º‡[ =^ô=¹Eú“ÂñU¨?À…ª¬séuZ G,ëÎ\†5ºÉtÿb=ú ÊEW˜¼O¢ÛzqÔ·�Sóõ­qÏr?:¿8Z~&Þ¼& i¼þNM§/—†Q» ½™æV1Ü!£O^‚ßOêÄÄuë¹8í5…ßzEzé8xë&�Þ�={°ß-V:G5k€óÂý”n/Ç~¡Š ·|¼VöããùÖ4IJ>í»ƒ¡yqvˆ>.ý­FÇ4ò!òÏK~0)‚ë´ê Ÿ{äð^Û”Æ>¥}Ñi/QÌiKœ ªÈ¾©ëñJ^‡èâ· ßw nïJ¨ön½‹üFiÙj¨°¨˜ï��A9!×î<�mýÛ…x·U¼¹µ“4-Ó„c‡~“Ù+Y®º xÿGêù…ôko!ý½`+”¯³ÅJ·´*Oçz,‚¥†¡8_S “M¡à»2ô.ÝMpu&¦^‰ Ú²þÑxññŸ4üž¨†×Ê;aZú¿{ôü9 ¸�nÖôá95²œõí²pnÓ!:Úk´%ûð‡µRø­¸:W_�ñVµ3t1» Ÿ÷㌿�ÂÕ‰7)ñe ¹ÿ·÷uLg¥²©äã?4'­'RËæßsxäÙ# 2¸Á‘,-77]Ôàü>}peo<¶ÐW°�óá î9˜²-‚KæŽâ ½ŽÓ<Ã0ìí(ή·Äaaôéø^Z³ =~õdÇ·;yç#^¡ò‹¬BRèÇyCLºÐ Ðz¥zi>øoíËÃ�G -4OTÓ}HϾܦÉò'¹ð½öžp³Â÷µ/•–ØñírK0õ¿J^ÅæKæÏœINö®8æí)êåûWtŠ“ðåQ²xN»X�ô®‚Dó‰˜õ«ˆûÌÈây ‘X5âÉ~‰�öCYà&QZÚe¦Äâ>ûì«Õ £¬§qÂé�ô%Xgný C‹MxŒõæAº©¼»Ô„ò¯\“C¸Ö¼P²sS ×MÐÅœ¬Œw"hÉ‹Q¤ÔÞ…G}yàþ‘ 7‰8T¯¬ö`Ôùùü_®2>ØÓ½Zôißó ¹j·ù¶³¶iɘüCCì]Jdîҭɸ`Þ.<ú·"2¤‹t¥k‰ÞÎâƒj�0íávh ¿�68¿‚u:®SÁg%ò8þ„4²5Ðv÷ ¬möÂ­Ó øŠw'íõ”á.bƒQ/>ûj>¾Î½3ž/€žŠud°ø¨ •žÏy“Ñ:TffðПÎÜÙY$‘4~¦};ôh߯D|ap|MnK¶JÐ�_N0ï`M…ã¦/ÌŠÈןØÑÔ—Ë Û»X¬÷~@O´C`“t ÆÖ[câôe¸AÉ�®ý‰gÇ#KPýÒ¨ûòTG+ð�“øâ©hT)lqýJkä´ø{X§¤cv“hÒÞ%ê]2©Û+yêùeîO}f®Ç–; àsm:*&`TXüy ±D`­Sgøî±¹ðbÞIìzñÿ\0Àý£0¨ÆmŠ’Å97þÃ{ÏÍðƒÔ(×?^š%_7ÊÑÊ5òèç}˜d[¢peñÿœ‡_ÏßÇK[Ki ¡¥¬ê}N!"I”RY Ùíh§hÚ ¢ŒŠêó>'ÙY!#¢²}Qe†_¿?à}�{î9÷õ|>Þ�Çõ m#ò®ˆÑOHò¼&‚�±Š�{Gò7é•,ªz¡~Ärê#³�×�ÚÉ×]qƒŽ?4Þ ã¥?,øÎ* « ©äª6dôã²ÃŸ…»#2ÙËb9<}×-Ó¥ÕY%0=O=™ÄfÉõ”'šqKª&W­ùC÷ç�¤!Þ ¼Ï°Œ[)®PvçˆqðÏ3˜n¡„‘%1âßàv¸æ�½·TQô»¡ì;ù%5Zš�×”OBCÌTö¼7©p�–©<û]NËÃ·Æ Ã†ƒrøÐ¯b›BÐuu‡Y‡?€öˆè õÎû«tãÕÄ“V)œ‘©EáKh¢ÍjÎÜÒEç€�IÿsôxùÙ>úum=ѽ/î•(�Â�óYÎï6ýJTã�ö}àݯ¿ø¤ÂR^µ¢é%±r –/í‰J9Ûéf/%<÷2ž²·ŽÄm«3aiÝqrõ_�³ѶȘ‚Fvóš#}º¸ oŒçÌ>bÚó­xæÒv* ýÎ?¼ç¶Š3\Tº?‡öß ¸}Ÿ|o�ÕI�¼òázKm+@T·óÆõu;Á¾c2NÚÚíö« Яt_“½�¯í\äÍyòaä>ÿÌ(}ÁY:ÝK”ªJ=š‚x]®n)7ýöJx|.@˜" ÿšåENŠ‹9}Tª¾¥…k;­`›»-¾óøÂ�IY4íJ©î} æ¿ÃioÉqë�:8¿! šbÓLõL\e´UôTÙJó”ç W·Ïeë.Q•Üî]ÿœø�¿�í‡k]uðfw–„6¼€û±ŠØcùm6úòƒÚ��Ñ<"OlÙ~/Òy–¢6]óŽªß}€;¾©°ä½;�ÝW‰†2ÿ O2oðžÏñÖÍ90Zæªxî¿¥hª»wÉ¿ÅÉ)cÙ畺`šq›;¢Ú労['̰ڀãßá5ï«¢ÕÑ ô��}ÄN°NœÇe1úxÊü2hû*ó‰Çª¨açÌ­Åüt­+i>Šä~þh¦0„ÌncûŽÏTõ¬/•êÊÁ”©š´ªÂMopAË ¾b9ƒ›Ø÷n+=3ccW/Ìø(Ì1xBZZÕ—ËÊAÞP†>ÞØ �|øa,öV°€q*çPÊ#w<:Î%γ%3¯¥¢ïwÄ«×Ri­.yužf€ '!ÆÄÒ>Åü0&ý}Bήºß‰›g­ïýÓÄgº“8¯Ž¨Óv9y/º„ 5ã8%k%„?Ë �¹�ϱìl5þ7g"y'zñd± ¦ªæö!d=ñ)9±•ŸKû‹?*£ÿ >ëô‰ž;îØ±ž[ߟæ°ìIðdT¢xÓw?¬÷¹M*š2¨TÔ„K¶Ú�¬š†¾-‚动ž8 ó›y“]OÔ‰¹Þ§À€I¡�ÞHÜV¢ •¦$Æ­�›[kÐnþ’CÎ/IêíAÊgo –gÏS‡À2GŸ~gÝaßÖ›d¶ÌML¯ˆs¤·c^Ò5°í�H›g¨8®öï�Ÿ†î^«‰j{ŽÑˆs;`ÏK Úýv¾pW6 ŽXŒÃy3ˆC§ŠÖ~ïIÿÙ8‡QßGóÐ üP+¾U<‡S9†¬^+ ÁúlûJ“*Ýï¿�±½_o±ÿ�á<8Âí*¼oð¾ô>c9“CøÒ†4a]ænÚù`"‚T$úXqî+¾¿Æ;ÆöâïæP; Uû'£Ñ©38¯ð¬}ñ ßÎãMé„�žŽg~Á�éß&ü³Û#„«7BèÃã|ì1æ=L-,uˆ €ß[µ¸äØAñh7ŸöuÚ%Œ‰Ç²­‘\ wî §7^gï Z<è&Œ³{NZj0Ťu.šàÇI4ááYAè>Ÿ_%‰<'aÈš�á²ÿ„a†�žpG´ü{tãH De˜½í5É:`|}6a×h’NöäÍ�¸çæ5¡@) ¶ºß¦Q òpÕY?LsVã £ÊáÎzÞ<`2öùjé—¢8ï{˜¸<³kôk—‚0Û‘ W¥’ܨƒô¨¡œÌNkŠÏW®"Ãܽäñfξ>ŽM+ĤÄ$¾˜åÈÑ—Ãp—0ˆ&¯’çõa§ÑgújT ±#Óî»Ûâe.J\ñnm%œû3Ê�â´Ù7à¶—[Ö —Ô‚¢²ýŠMeó·ƒDǛդ*\Å -I°w]—$bËCÒ×JÒç¸!쵓?†À©u^“™…i§“HñÈ-”ôHÂí£iŸg ¬'iÁrE­[u�F*ðɇ«1ö2ì¾¹ LšzòÓ$eÆÓ3Xþ 5g_é)p~'x^9)Y¶ì \Nã pS`:ëjÞ÷À?Šhȱ~8ë`=L0SFêØÅ3’¯ÀËï„-'/Єà%h8©'·d(ós9OŒ60œ´á ùF6}©JKGÖƒüï<º¹h%T,L¡ûýFò¬C2ÔYµÚAfíz«cŠ1ÿæ =†M´€åGÒˆº~BßݳPÑc:lŸÆÕñ9ô¹ñžøØÉÞ­wÅ¡£l»ùÆŸòt†R¬q>=ÑûG– nvv�ó[®ï�ÑHw0|=ÐæGpäŸbȯvF‚Ùk²­/å§�ªú;Ê~Ú S÷5Qøç>'B;ºÖ¢œÄÏÆNãåcàXþ:ö}¾�ÿj-Å÷ÕaöýSãÁfY(Õ/2~â&žÜ i5Òü}ðnÐÚy‚íñ”ß.¤ï¡{àÚ�‹§7R#“éé4ü[Ùï` ìP œNß¿†Î„9srEa‘#^xnE›õÇ9J}[MxŒÇÆ«{±ëËT¼zc.ýÏÿõ;^Ãú‰Y8À¾êÛhÐgN½»·xõ‰è…‰t4‹ñë§U¼áZ–’áÓŸ°4b�?Ý}§¶]‡¡Í–BSûB–YÔ@ÃuŽ@CÍ;IªÔ>u�°qž«(Å®‹O`¶—ÀIëLúPz[±D~²zß §ú¥{SƒIýK ¬)”£>ãðà�‡`h(KXô•Ò%f"œq›§fP€J9ŒµÏ˵ƒlîQ²¡§CÅ®ô/i•(�ËÕÛÁó–<ŸpI¥˜Áâ�2)�Õ‚~ãôçK(uŒ"'–ÁÊ yN¿G1�–½(¤[çQUF¼ò(Î4ñê=Q⛳�ð[b¾¨òGøQnJ¯äµ…¢¦0.ÿdƒÙ•°×Ã;tª!ÕnÈÃÞEžùäA¨HÏ[G¯rqüŠ,´Y«ÎÍŽö<øáCvxPås'c×c–ÝÛ«¯ÌÀú]‚±êF®2>AâŒNXÔ¸‰[BŒ9ci?þà>´lc`êš±XÒõŽ&_Ï€Í «phÉ4*5 ÆÌ›e¸~lžAI¹vø�Òão±ô¬×W‡�‡àÁƒXŒÙÖI}d�}��ëõþ<évÊè¾|¡½4k_TÍïžiw‹0xÿ]žS&ê÷e­cÁÐà<Ζm"]¥“ÜCñ'e7¼ÃÎåo¡"Ð;\Ö¢Öye7¯„Zë}h¯úd6Xˆï¼Ç"/|0‘`Њ\^Q ßS�¢®AĘGÒ1Ê‹õP¬�Œ'CßœJª#‡Sž5ÀÐcÅ2/o\+­Å¹=™zíöæ{ƒîÃD…­Ô;>œjsky–å1�ëùaŠ»}¼v£è{«¿NqæÍU÷ÁöÓXv°Á©3Z¤?“í2O Â¢¿`Øvî_èK~-Š|"÷2L�.E¶£EíR8ûñ$)4ͤ†ÓNâ³û¨~ÛQ>òæYï‚Ïç.RÕpº›ª î^¢‰æµ28®} ¾R.€é%‡ÈâÉ@Ò»�û;½£{³§ˆ/tža§](>\ˆ%jðuØ JÛÆÃÿ ȸC´÷ ;—ÅוBúÊÕVQNTÖöOø÷Ò5k¨pÞu¯T\{|ŸÓƒÎÞe(ï gù�}”5~$ï¿l…‰ïFbÜ«ç‚âóD±Ôo2ÌrxJÊrŸ(pÖH®*kyÄÑÀ�ªø}ÿ#Éþ§è?ü ?cñ‰“ šŒÑåÛeëieüÊw7aÈ_R¶ÆczÆá»jkžunÈ:MêÀ›Sß“fÝ)!ôg4× Œ#e÷>}tÜ1ÅSS ‘Ò5èûL&û åJ\ˆ™œx–a‡u6–iå e“£Pª*ßïÚÁŸ– 熧AX[+”¨5@òQzÀ–Gþøž®Ò|Ëip髀ʮÓX}œ.޶âkO“ùµ¼'‡î¾Kþþ ßH ÿÎÕw¼R\=W­GÂ&iÚÑŸ†Õ¾¬_¤m’+Ý"D•#SÁ­Ô::× ë‹'áîùqõ‰ÑüåX€0¼`).�=Xè{Ì–­7âñsšh‘q�OÝÃß?„óC¢H£ç¬XŠ{·ЊWÿ™´]Ô×$Hœ†‚öójš|ÉO¾^‹? snþбˆ·ßҢ̜Ý|Vç<ö'/¬Ï0dO/iž8KŠåþ–Öˆ4þ–QƒFöçÌ©ïÀ§ëF|¹-̹ÞÍÖ?¥¿žˆÉï‰ïŸ^¢]¯>9TDv‰n×²ÞøuT»c3ìý¯>ÉÃI¶pöP"Ù[gràß“â«$1™¶aM«ç©ÂnYp~åz\'^A•~?ÁD©@¤­.°jA?xpº7~yÄ›ë« cÛ¨P¾ÝÊÚIá³-÷²™Àš=mXûF_\4yŽd¨Üh<¶_›—Î>ÃýCà[ë!q¼¨+¾²nÁ½‡’h©R(z Ù�Öðÿ7#•¸¥É zw.Ň¾ …·}qðË>™/ü3ž!Òß3àÒÏ‹ÝFc�RŒY…#ÎÜ!·:iÔœe��¿—°zÝ\®ñ/¤ä~�ź}‰Ôš§ÅƒÔðìø©¼wÔPØÅŽèvÔ þHÝg©š‡p£cM”òE]÷| õÛCžÿ‰J#BQúß#�Þ×7’wëíbµ²w‚†ž?ÍŸåÆC�-¢…Û†q×ÐS|@�FSVÅ e›¸~�'Ø,Ľ G!Å#”\\ÐèÏ þ¼RG=„öèx8¦?Ži¢Ìz'�½®$›ñÓÐd.ËŠá9]ýðØL-¤iGÅ)&üÂÝš.{€o7o¤´Eáø_¯¥8ö±7N�d�«�†÷^çÀÙRc–Ûñ–ÔÆyŠÆY'¨wV³Öq�Ëz�$¯S_D¿e>ù �—Sñ`ÿýTrg$†ÿŠÅM]ôS6äõŸã°çzk–¯näØ?>¨=–Ň!ÖÜœæJ¿/v<û½¸=e�XžÐKTÛ ††�¿À¼| ôÈ3ÿÖÁ�Ì:×V,ÆM/áÌ·iBÂõ&øQàç*»½Rú[¤KãêëRÜQ-þ‹ÑËrزn:r×.P²çoçÁîÝóQzñw¡‡Û:¶Ú<>}j­’îÚÚ/·lëMU*ÁXô­í —óãMT>Ýr‘Ñ�„•SÉíh«è'=–~ær|ÊPÖIoíw¥/aÿAÙ‡d1<7—†ïi¢”N8lèUܨp/] †ô!oÛfÔË ÇýËUÏ2ÕàL{Ež´ ‹ç»C�Qûh}`f:SmC ¨M‡F¡…Qo›–ˆî3šaÁŒvšØ!ºîÏ…(-_f-h||CKøVÁIaxÝC˜ÝlDº=—‹µç²ÝÜ Ü¢ûâÿcm¿Ã´±å _‹²‚û‹½Èjø92o5¤Ä²TÜ4j l^´‰ �JyÔ›)’̨7X\µŠŒÚE›øõhjŠmG1㲺yéJd‡Ïà3ONÂŽìSû�Ú.¯ÆÀñ¦ôçÕ¸vúÔ>?ÏKuvCBgoÜòÝš?n¼¥’sOóÛ'iþ~YŒÜvÓ'RöüJ6âðe¨<~Ú•Ç’âásÝc ¬Ú€ëîæsòÕ­è9•æfÊTOôeÑ´r#ݽbÇùµqþÉxH½²E86OÇ›Lâ¤ç'ènÿ·&批9wèÒõD.ñòÅÝ.Úh¹Ä–w&bs]/\¸¤/ü·Â«œŽ 1 3¨má~Šü)®.ÜF«÷næÀ ¾îÌ …2#^Ùö›üG¾†Úê\¸~ ×í{Bç©cgÈqø¹=(Ñ)F® ×m¯Á™© 4n�­x Ò69¤·ºÞý¢…y»É°´™$w"¥‰ðÅ{&/ òÅbÀýgOºSþ‹†Ä­Ã½)aئ«ÄÒÉ#?—šÿŠá Ò¸ö¢,Îb¹Êѱ±!ÇUT=y¨²W„‘º©-xö‚Žýóð(HáÈöL*óï»´~ÐÏÜuôÞ;\ŒµªûÇCÎâs’Ì�%¤ÚÑAëO*€v¯b¡å±5…¾¶c÷x<|òžPö¼ ²×ð¡–nvô¼‰O+v“G”6y'ï�Ž3)ùêxt•±c3—4Ø#9Ù)¥xÁ°@øUs™ža¾Mþ"ú>H¦-s§òÙpeÚT–ÄËÂq�qp àôÅú¼ÖB›ÿY™ñ�ׯB?hÇê‹Xì…)'•8ø³ŽÄ.RGìÿRj•ðGS¨4™‡NCÍ$Gž_îÍÒV¡Ö´Z!¡9)‚ãUÆIÇÑEú0ñÝÎÀêMcøâ^Œø(°ÍþD~¤”Bþ?ƒß©°oõGгŠÎßƯÝ¥ù³Ø8aô0Öl$÷2fšöåƒ8\É‘]MÙ<ݾïöÅ�îšèzâè8mþ•�ö©BF{Ïü2ˆÇ–=åAÖ}¨ê×n}zŠ\Ck Po©ÐlýšÞØÃkgÎæ´-žàûkŒ�lÚ;ÈQ׿Ðï̹bºå7’Ï= õåTž¥ñ·Ûèy=O˜ÀêÅOXCãk^›ˆÑïʨhZO^ü ¶ÀŽE¿ ÷Zc”žßÍ“Çíàfèe!és,ªëf§_Sp‹óKzÛR€×Þ ¦m»Gƒ÷Ü]pÐÖâ¤+hƒþh•V¯¼qS å/ìF÷puïð¬ï~ªÛa‡Î38mh:wïmÛÉh ÕÐá^¾š 1ƒÃíÂ�1ø¡ïyð�°]2.17Ÿ åŸó©Ï‹4ÑmÏ!6ßYÏ{\÷v÷à8x=w$½vïEÙmÛù·\·¹Ê�«!…¿#¸ìYœ¸Mõ•ðÀ.FLè#`Éz+oJöÏJŸ6G m¾À”°{Âñ—™0nf NY¤æ0Mƒš¾8£-‘�ÓT�<··¸c­q')¯ÁyÎ�1j} *%ñÃ#`óFsþâ2åW �ä–ãt¹ð5 Àfã·àßÕ?áÖôUl“KR¿7†¯ï)æƒ}ÂñŽÁ 4\v~èéC}m4XŽ‚$•N®Í?öbôV3ÌÞ•BH†b¯ÁÚ 5ã=ý~áÅ—çÙPÁ�JaZÃHaz±)¯µóà�OöƒÎ$Q2k‚?˜DØÂ7 _È58,HÏõ`Z2˜ƒÿ¥q¬ñbû¨¤J—ó�„`¸ÜOÎùÀ÷áö\ýîCÕ;×X³y¿§ÅÆîþ½é;4´ÈЯ™ùô³¥Bh 9‰—^ß{Õü+@gæ2VÞVdf›úžÊ�[�1¨S€7Zî4Lý•¨¿({ªkòÙç…¿QûÑh[8´“oÜqjÿÞìÿt½‘Ž^eÚ¨èQ,V]I¡¾êwIoÔ'šo½Öm/&ÜA·�3°§E“x*VŸû„XPÇð_4ft¾ÖÝIµžCNP2غž„´ e4k ¦mäªÛ‹R²E žpSTÔY�Ôs>5ÝÙ�^ NÜˤš2?�Äk—Ñ8-fW)8,Å*¥ëØg–+f=†Šhøu•j‰êPü•t”,×íÄo LQ¯.ÅÉà䎩ìlÕŸ³CmpBåÖºû¶Õòƒ™¼ðÝ0Pú°·*<%m#„¢ÎH\»nÍ~ÚTŸ6SÿÉdº·Z�–£Ëú|Ô(Ù)´Ðï¶Ð’sõÜ‚½k ­� ÿÚ^Œ²ó½XqÃrü¯á <Ù‡7Ôp\Îü´I–Ž~ê„ó“éûäpê9¤Ú—ƒÃÃt€M�K!^ð=4]ŒÕŠ5� 씜#Œú6’ãd»àâˆOôë™ ÇÅäó�ŽÉx¡Á¶¹á´_ÏíO¤Î@qØ:ú·»FœvÔ¥24yVŽ/'þù77ÄãÖ㲎Væ¬ãy†ÿ»"#îÚcº+ü0õUYþú ‡¿šÀ·K·y¤b 89t žŸ]LF�Ê4÷¼ä¶€›�q”_?.zàÂ~‘­pCï•ìíËêE«e»ñpiª(ôAëïèf~°CíuMÜ=P�M~(±éÝ«pÝw >–Ë…óe9hb·ƒ:-f•½┓ IÊ'”d'ŒãÆUËéæô­Üò.L47p¦Ì39cw�¸j¡/´Ì=VõEM‰ß›`ÂG>n$å‰?pÂéíxÜ'Œõkœhdå!¶+ž\ãH/VßÊ~�v˜sÊí÷^gºHµi0IŽÑÄñ2¿°YƒDe–-­$ËÅ <&Ü £�Ã#”ñÅD~¶u9P‹n�¿@öMÂB× 4NË‘¸à3Eôô†WSVa1•ócÜXiávÔM±Æ˜a ’Û;:…{¶¤Ïù×¶Óï„wQ‘X¶Á†O�î•ó¶ÐŽQhfzVô\®ÅLmÑ[TA3Ézör#¨=FŸ�@ ÜÓF›ÒhJP4l9; …©ÕB‰m4nï,‡#�x?à )¹0Ö!�ÏÎä랥tõ™>èÀÚ.x?y)mës‡šÑ Ú¿Ïà‹>x}�çתT½ �ãzÿ4Øàr…dâÒŸ>¬¯Œ7Ž×ˆ†÷cl�6nº™)jh4ŠÏ“rnåôÏq+·«öâò#8jòAêôºF3Ò�‚}2¥%™b…ÆdÐ ÝÎùÃ[Aø;QÐõÌ.ná˯m(êZV wĦÿ–@YÌjÌ\v�4ßݤó†øºlÿиKKS5xÐg]þ³~/Z»iAsé*<£´ŒCÉñëÞ ´xX:Œ¯°9µ�?¨Þ -ƒåÌ)ÓX÷ç"Î[Xw¥-=«0CªÄ¡côÐ^qˆÂ3ShøMUò8øT0ôGÐW-"k7WÒ8p­?†ÖodpTK$;úˆ¯îõÃé[ ¸kÈ$|h÷ŒŽi‡´GºènµGTÔ뉣'(à¥!*¸^Ì¡]�g ïÎòPeùõµ˜)ð�¸ZIõí™{?Þ0ñ8HY8fr¨¥dEá*zñ~ ®™8>M¢eR¿(ðÇ p—Eß]ÂAq7xœÿ ’ÊM<§¦®v÷Æ7ÏÔÞ+.ˆ�Š $?�/ÐŹ&�×¶’=†¦©�•àÓ{9ÎÔL§“Ï›$ä£Ey½pY©ÇÊÂ6.’÷âúM™â�o¾hS:_|½Iˤqõ¼vÔ97>”ZbqÖ&ªH‹`Ë%“éJ�¶Xm¾K˜|å¢�ïô;ðåË7±Ã7=ˆ_ƒÁcê„‘Qò|êg7ïšO ³2}ð?¯(ª QàŽ>+i¹ZM<ó¶Ï(€ÀTeYËIÂ?�Wâë\;ø´º²ú©!»÷`£�¥?~* ¼$€¿Ø< j~ðã}(a`+Ü‹¿c=èøæÓ°AÒÍçðîÐþ¯æ;äïBw�ŽÂi…Ûiñ¹´aRÕ4ÛБœ}´ÏO!¦>ˆÕÚ¦ Æ›�”­ìznŠ5WŸ�Ü�%0÷O;”DI+m¨´ÄŠ'dï‡Ý5sÁè¿d6j‚ص*ý¨x»æ%ù—À¢Á{º™g„ ŠPÝñAÐ8³Ž«j¿ ô‡?.fÿïGÉ« †íYÎOÜ6r¼m0/ï3³|£@wX � ‘ì?ž±Ð-¯™Ï‡ë±ð.-zºˆ6IÂ@ïƒì—s* çsêíz³b,‹;7¢†ª »YÍÆ+±ÙEâ›ß9³¬B£—BØþãìš-…ÿ™¯‡€špô_²šÅ[ð2«ÅôªS WöÉßN å·ÔvПm÷vQký4’ÜE�²Ùã°?ÇJ~Âþ/^¨5¾›ûKqÂqvåYôtñ46s´Ãµ³·‹ýߤQMùjàÛã0õð-˜uÁ]3â%úOh¹žÌ2˜M¹�nð„SÐêW»hT$�ϺñÓwæ| «”ÐÚ$%v+RÂôãk`óõl ÿ~��»,X2qðÄÅÜ>ÿ­f©À¯¯;CÛürüÖ>¿ àÂUkÔÑ=MýïHq}‡ LO—+k²ÉýÑp{‘ n¸4Š=WeSÙd.üÖýŹÇÂ>j¥òÓÅ |®V<†sŸ�F» å�™G0mð-hÛà [Ô�—î>…Z žÛuñISƒxûêŠÛ2ű…´¸¢ÖïŽ'Óú|`}*k|3¤Dßq«� †•n%¿¡ÚÑ[aËñHÒX>ä?ü�ª²Qà|0 εo˜4ŠOÈ�éž­,að£$>>2�6Í3„Ëåøj± 9uÊá•€D8Ñ'�Â2rà^õCccárŸqìiPHfªa¶ÙYaH©!¼+‹Âq�VnÞO>�£ùeòÎ1¶AI0¯h·d7R”Þ®…ÿ4àÎ#åB°ÒÒ}B–Ÿ5a嬭øß‡]<`mUMŒ’ ‰Ï�„ÆÕÃ©é² 7–ý¦Fƒ3ôäʜպnËï—¬:Kg¯çZ´£ ·Ä ?åÙ÷i!,$HzÂá»QD¦â§Â&2ÎÜÉe�¥øìhµ½žÊ |xÈq?Iv­ÁØK®\ߌþûáÈR1àè=JÌ·C%ýýøýwضôÇÄöô²3¤GÇ‹}N&ÆÆÒÂ}–\± ^²Z™'޲żš¨µ‘Åsé+…:ß7âmÛÖÿ|…¤å# øÇY(®±Áv…ð*„Á3¡2saÉüWÉÒinâ§YÞï³O(œÔeÎ’vFŸ€7d纑*ú˜àÛQ£qgÛ)Ú=á)/Ûd#Pm\=¹õÜ\µõ°_/‰à؈ÊŠ¬£Þ{>ƒWF™ž^ˆŽ sÙw‡6½¹¢@o¦žä]2Ã)hÅÈ[?™}Ûð�yF˜®YL¦û˜ô/å ¼·;ÚßMÂcs+qð�Dê2Úê#¦pàΔúÙ˜µ›¦ã’5œ+ªbÜW)ømÆu×´Ä÷žQàí÷†JCMÐ÷o+èß‹faÜ7*wÓ Í× uòµnÓBÜó¨ÞÕA9§‘�÷t_é;í` m:rEð¿6‰/ÝE;ZìoBüKÜÛž„~Qµ¢tÜH¼´=VŒRæ—ÞÖùâ�c#ç˜éïÂsÛUy®ñ îÓ[KGöà…¦áè¡ÙEÏ_ÿúÎ^ ZÃr(ø‚ »å‚¦¯" W|ÏV[”pÿÊAbļ޴øð6Þ3‡`ûïW¢”é ü«‚ÿuúDØÁä½J<^Ú�wŧ³�ÇYª,¹Nz;�/:ˆÛ§]†P½8¨›§ˆÏ ÒEÛå=Å{ E«­)ôZ?¾fãÂ='ÏÁáó±ÂcÁñÖpaùÝg ÒôTÇš¡ºÓl^5Ñ%ï÷”ä8MûS gê›sò.|ïÕLꉷtÝJŸf1M8†m½üIï…zon£§êGèaïbh^r_”DîF_פhõ‰² ¡^>å· ¢ öà®3 µQ™Ç¦ìâŽCŒ™ˆ§vžÖ…Ð/µ™ðÜç´)Þ¥Ö©üRQ‰íbrìJÖÏ@g~MÆUPº/“’w•Å9÷ÿQgvO衜G—eÔÙÁ9ZÆßƒJ·ˆ¯x /›ÎÁÒ á¸¦§îÿÏ‘]w•P†a*ž¹jD{/ßpè£ÿ€×Ûá›7Çi»‰ÕD…‹ñ¯õyžò,Ï —p…5(ô�¦EƒÖ‘vøUóðM\ 6†é Ï|ÕYßÖízßãªC–ð²� ·…¦q¹Vl£z‡GSÕqnà~q•>4À¶ ¶Ì”ÇÔ „y�Pv7D\)‘æW¿ýxä�…aÃ~sSÈõ¾5I7Ê¢Õ?Wž?G‡?mžÃôE�ÔæOl?(ú-?Fþk[éºçYÉÐ+cqÊ7>s¨™ ÀMe½qöù¡˜?{=󘊻R q:pDÏütÿ¦˜½±—o,Ï^x�ôíðÙÎþœôÆŽGë±ùK,‹Ü!è?©% SvˆŠ×WÉc]ŒŸùº U‚Ò©öï~põ#ˆqChà¦xúòܺ$�v}ðwn:´ÏßE‰µ…“·Jã�¤»¸Süì™Ï½e/P&�’ÄÍ�ÃWu>8éõ$T�÷A·…bÛQ?²êwS2/d»¸Íð±ƒã†¥8òíkújçJÛ›> >×V`{ë&6ÿ~�o+óL±×õ¹|Y©Åµžî Ž uÝò•Ìx÷ê‘Ølv”—Æ‹‹ÌaÃÏXòØâ !Ëiî¢a˜$FKZ-uÄöŒlx·P†¯ÚYñ·-ZذD•,œ ¡Ø—ÖöäuF“ñÅŽS’Ó«¡¯W ^Ë¢ájqÕ‚AxêHõ2φ}s  ÃJ‡‡&¥[/Óë×}0༠Å]r…£06B {¶ŠŽÎ=Iò¦ƒâ4¹âE ºzD¢ô¾/ýùÙå5ÊaؤaT®è€Qo­áù°o¢~w{vÏšÜ.7X¿Nž–çk²Ê+ áR�fÉ£Ç5�èÌ =^õê©ðÐK�ý�Æb»EâWóQøöù 1Pá(¯,�Äχ¿Pçßm¢æÃ·Âu¡úÝZVØ›/•™Ñê€> 0g ö|&9ŸCg7ãÜþŠøöûRõÇÞI)¤¥» oŸ&Fçà‡ãcÁåþ`~󪼺™åëò1Þþ:å$NcuÅo ;¸Œº58$RƒÌæä¢£åÊ;úÎ]TàIÚokÕÝ|ñ·3yÔ$<ÿ¥)Þ+•†vçÆrOö¿mŽ‘YsðS¥.7ô—ã{ �ÃÎ9‹pœ¦Æ=amdý+• ¾êË›þ÷qÐ�¡ø÷äOa©I覲Ǧut¿!�÷[é²NXþ¬<óÄå}§àmÜÉÃŽÌá[?ä8ûÌ~Ô;&‹ÓJ_©·³±ñ´²ãÇ ŽôøY>¬›«FŽùé’j�<ÓI†×::Hâ|ûŠÛ;À~C{ê¸úˆw=µC)QO)]°nÏ~| ÞºúAÛã¿’‹f©˜ýC�|ïd’S…'·Ì8OѦ.8ÿ� ¿tFõ²¬÷ð0¨+âã3‰�Î]‰¾^{hÁ”h�Ù7 ¸¼ÆaÇñok Mr+�»V+ñ:ƒó|¡®:8Q±óv@t›ð^Œª€Í_½ÅÓË«g×˃÷W%¼èÄ\qL\\LpàÑZX<‚WÍØŽÐØÍÃtNÃy+,>vZ˜õ¨ J¬s¿O x…×^°?`Ç­Æí¢ ¿�t—�Ü> )�¦\r4UÞ©±Í¿"ÜÙYήâìØ’‚Öƒ9Ý;‘�ùCÛ+6˜¢ ²¡¥¸�[ßÍÀHÕͨu¦š¢jE¹ÓœHW“cѼ҈ÏT&Ãð#{ùíü|qYàÜî=Ž›ßDG‚—±ùl]G£¬ï¼Cî¶ñl ºoWA÷kûñÖ; ˜ê7‹�v$bªÞ<þi¯‰£KPx’N×F¨áœ€éptôeñÕÐ x¥Ì™×Ù.²¡�"ά؃'ºÝÙUw9ËlÅÍO’qýÎ?b­âdN(ƪ®°DøTCÆaÏÈÚp,ʺÖ@{ÌN´ŽñÆ�� ¸ïF {»)â@mS¬¿?‘çm¾‹ßõ‚ñw¢8ò,|›ÀIÍÓÙDÇ‹Ü> ú} .s?�§Aý³?<°â7–üß6ŸçÍ«-ÿøá°Dôš ß‹Øc&ë�‘ÁE.\.Ùte7ÙŠÍQì”çN³²cYþÎ šŸÁÛ?ß#Ëèr*MþEùkt¡Úf/õ�à$¹õw.?)Œ mýþž@³”©P�”Ëh^A}ã�Ú?˱Aè°TÏ�UÌñkTÏ)³ãƒŸ}iU¨&ÿÚ}<¿¾AÏæfñ,zTÐ�Óñ³Ï$ždãFöÕÁü,û‚�œ’L_î&?¶Ã×[ñ<©—½,YÊF9/`×0#ÊÂ(ªrÇûKy÷NâJã]¨1ô0 ZZÉ�]€×?Ñ›õ—Ä…y%”ßþ^˜EdWx çIÒ[­F˜“½�M–O*6ƒ•A®Ü²ko�cÅêOp&XŠk®@³´NÅóþ�xÿç\¼p˜pbÌ"lžóÏ%h°·ëM:uË�÷öÍÁÇóGB¢W1:-M"SK-6‹»OKRHSJÝwLÂ‹óæ“»‰"ŸÓ̵T9Ö ‹#G ¶NæÏ‡HjÖ á¼“;·Iø¿»wiãö!�¹¸å±3=u¾ÿ6Á«Õ½xFÚ]ÑçÙB®‘Ê ?lñgÄ>œâ3gôéÇÙMºÜa€Úg Ás� Ç(g;Ü8âÆ¾}Ý*“K­ÑøàP,3|Bhœøçr tFÿE­?Fà~­€ÇEOâg¿’ç…�Ôeá‰YÛŸó7Õ>¸éõî5O"ܸ?ó^móï]¢_Ó·ó}›#PgŸk®_c ¼ŒÉýŪˆMX!—&Êùš°y¡.ú�G?¦ä ZWIw{*&=�€û%Œ»ö½_ØŠ ±Éƒ×]†+·4t_�›ã΃Q»/Þ4 ±s:nƒ;ffˆ“¼îáæÈó”©Ï£SÐÈöÎoÎÁL»D‡‹ŸžÑ˜~ Ü¿ê]ú“Hþipó„7°óH+íô—�pâ5ùÿÈæÑ¢ 6L逜>Z<ÉÚ«­ðüás˜³÷6Ý{øâ?ös(Q4ÅNµa Ñxë.5!ÀÖO¾¦õeЪUBÏç>"að|êùÆ�³³û*’ÛïGuÆ+ÿ�‡Àþí}qÈYiœSyRãø¡v£äè–XÔrü}-›@Áþ7�²,ƒÀ‹*�¾ÍÜ¢¹c,ÑÞÄ3zõåú�á^¾*ºϧß¿ÁGF{âˆðG$'ÒYÛvìòxA^OP»WXºŒÃ¤EûðGî8Éf»hK X=„_Ç«À|«Ý|¸È—ZB^ÃЫ™ÜVz„5U1÷Óóè»9éËôn¦P8# nZ4ÐE¹±äözJ&gÒÆÛ‡0Ç-�—ú dËÃOá¶ákø°Í´†±{~" Ñx‚ jlÀï·YDWIÞéÉâå'ÌÖêÁ’ÄÔv(‹SÄ…<°VWýÎá§ÖGáÍgo^ë�‹–q'Ñ©nzò6Ë�`YÌÇ~ƒtø‹b9O &ƒ›ÆX-ôâéSëàÜÚOduÐGxôЋTzdRÒ”«P¸%#ëн;Gaz ÊrDË[ŽòK¨2ñž_=ºM~=æâjÉGïi‰æ“]Ѹ$’ï(iBWœŽµ KoÉpðú}7æ’Pdû�×ÞNÀµ7O€Z«*:¶f¯ìO4j¬ u¹^uò ñ§ñìy>Ò|N¢ÑaŠ‹-_ƒŒX|6Žæ¾Qà•~»hÉ wÁíÑsúøæŽ¸<4…TTWÁõõʤ'ë9Fà­ªØ4ÿœxÅ%–=1EΖ‡¹Í†~ÅcùËB¶tÎFïGKPÎë&`×Eh½[‰Q³ÆðÇþ<%m;Ä £Ê•« =ÏbP•¶ŽÎ›SËí�ûwŠçCî³m˜‘²jΫ:ígSù° RÃÛ¶¼Ã§dåÁ$ܯ¦ŒÂŲxôl:w1×�IfÝžáÂÇ+Æ0Ét}ôi<ªò‚¶ÕÄÓí—ñÂ.“Jáô BÁcðèßÕ¯ú°O6h�µUw~ 3îÄÂN]–½.¨0TúžðwéNÛâL¦Ç@mº~ŒZÂj‡A¶ßJöN€\¿]ðX)äøCëjG\vÁœ¾û’Þ¼I’e«?ÀŽÇ2¤´žO‘Á£h†¤:™îŸ[‡Ê%:X¯ó”–ÝšÀsŸä —ŠÃÏwz¶!ž«Îóò À·çpnéšÈ–k4)ã˲ކ÷Ónñš³0¤(”~öƒŒDVzQÄó·®�r/AõÞ‘nžØÄ»2°F*�~ìÎà¥2üÄuÎ.è Kµ-hëô÷`¬5Ò�ôÃ%%a 6ÒPðy‰�ª§!$H��œGÃßiåh'íãïbþ“.8Ô6‡7=÷à{o5O?ýF_'ÞÄüãðæÜtŒØ=˜çq”ÿhļGb÷}¼àã ~·Í‹oõVt¬f&Æù‹täË4þìý–?š€í H^ÌÂ�Î)¼òAÔõ±Ã1³&°ßÄ�ØR.ÍáñÛÅù'[äÓ粸¥ÕŠŠó†ÕØ¡µ“l_¿¢¸°c°}YOܲhبŒYún<3ò0ß~ô_•ÐéÌÍ{`î²pÁÅÝë6JV³º£‹V/Œ¬Ræâ]züqMi•ìÉf¼°äšƒÞb3îq;ú ?”ÏaÁ”“(ã© Êß&^j»‹«÷©á“e+¸·—¡ä´Þy8eÏ3Ä l|VŒ«x\é$þ�; Ž‹ÿyÝ£…Z>”ÝݳÞÑǨnk?þÕ*îl�KC´xá{ Í¿¿’îÐÓ <µa"^Ë€ÙÙ¦ìùh ]O“ç­gêaRV5¯+t³êo'ã6ÙÇ0kµ’¶Ú¸$�“K&—}ôä›±ë@Î$ŠçüZÇQß‚àK›:)øŸï'܃�Î*¸Ú͈õCÚ@ê^. ¼BY»IôÍÇÑ‘‰#Ø¥RuŸÞ€y_·à¿=ƒq_÷òÿLyíÅ Ž0®Ãþoóškî¼~· ê¯táÁ›a§ÒuX_ÄbýéhžŸ/PNô7¦Ê¯iô²�ìöRÃE½‡CÃÿÿÑþ)‚ÕNÇñ±¦€§vá�W:p¤~ ‡<‚ó´¸*;[¨ý\2ÓñÖ+uü--p¿»“àLiPjÝ�C¥6ÐéäiXpn*X�ºÍ½/ÞÈåÖed¡W5Z¿‘&L²áˆ†‰z),+=”ã ×_v�¡»à\z"»'8áÞêÞ¬¥�†…>—YxP-ÞXzSH¨Ù�/6Y i¦%&�\*ªÞIg哽éÝk+NЏL×½¦ì�Sðš÷;×ïÇ‘‘QIdT(«hX¯û¨P”H©´4M•’´�=²·ÈNeDøäý:‡&!šB%•¤=4´¿¾À}ÿp®s?Ÿ�Çu݃‹FPüõ(u•âÆ,9ƒÚ¡Žtûþvx1ç¾êúŽ œ & ’äwÄššw¯€]þеç?!îÞpFσ‚ý&Ì"Ó�®yap©7ÕÜISÝfÃ(ëP˜¥³ æÌæO=ÜuDÙÎÏÙ„s5\YQ0Ì"¸¾6|ß»âÓ²|”ÍzúÌÞ8“Ó ®¿` òî0cÎV²Š g­ÖY‘ô2rX=…mëºÊRjâèáa´Ž™CtaåÁhýøÓê¥hÕ71سBŸšI°é c»–>§ï[ Qg®³dÅ4qðe®ý•\¢Ëhø¹’¥Í¿É¼DºpâiI�Ü}�Ÿøur+Âé8žgnû¨oô~}Vλ{—ÎpàöÏu+ïÇèÔ“Äìl|øë¿°Õ�lôú`N4» ïÛx°Nû±sÓAìz¼Æû­Â×Â#ð^ö<¾´"“åúH1ÿ»©°Õg]’4¤Â/fTÕ$À—·– �ÆxvS5oNÔcá¸ôÄXÛƒ"2‹Ùš·ZTUâÌÏØœN‘‡c±'²•âîâäçjÐâ,C.ggRNi3n´`FËñˆò<ú¸l=4 ±û–älûÇ_„/�ÿCçž­tOg�»Ñh³âB¡75‰:ž%â[‘(fÖç»™Ù6à>HÌ'ŸÄ›xù£¥´U2|ŒèÙˆ%Ôï)C“Ýß`¢Ç|ÎûÅqïz;4»½›â É0··¦”²Ï¿WšºnA�D(í�_‡Ó|KQÔ¿–œB'ŸÁ°� t@8 ³ã¾àÍtCî‘B5OÎåEŠLYèÊ« c#JûFÀÍ=7øÇa" Zˆß¸$¶®é I*žpçtWR¯Eû�hó}jË!%­eO#vÈ#¢rغç†�dzšÌµ“ÙºîµÜœuX³g…„ЋɑpZt -?WŽýö´í…!ý1Ô„?ájP¼` ˆhêBjÙ!” 3åT!^7+Üh¹Å8>ÿ îª8…ûnU³ï®¦§Ë“ZÙ—æ'´°#“çßI�A€�ám`ù9Ö4}©*±}{¡ ÐMVŽ·†˜Ø4J5J~B%¾šï»2²yÝÌ.6&Ál\Èm¿%غ&2¿É.®iŠ›¤7�GóZÙZ΄ÅÔÈç¦3[ߺ™íZÒ@ûš¦PóBâW1øQG‘Yxög"«mf¾îôâÈX˜*¨f×M’áä©•lÚ„lTš8/5ò/·«;­·Œ¤W"]Ü UEZþ å\³Àf¥¬*É9ïX€oÿTl6}ÍÙØóWïÎUÇ2œyø<š‰,Åœ›óqòÄqÜoOüm<�–é(£ïÚ©ä¼ÎœVÇmÄRÇf_v�-�9É G^À—&[iÍ– ô¨u?³ °„ ‡Õ$)-ÉKuŽcIûˆ×öÆq÷µ`}›Ñ<|ÖðKfªÑÉoÛhÅSÐÛó¯=å}x8XÉŒ4S¥Ÿ̽øŠ]ŠË‡†²@84» L§QµwÝZ�â3K@8ã,žÊðbZcE±Gnì–{ÎË�ºÊJJËq°¬‹­—ØÍ4/¦àÛ@;hHs„»¦ÿav¨Ûþ- Z ¦AQP5«iS§òÆ"–j�CÆûf3‰©oøçã'бI³é½¯-].rv,"ÁT#*qœÓ~Ò^$Åš¬³Ø†�®Nò þÿ‹Ë½‘ܯkbä±x9ë° ‚sŸà†½Š°µC�¿ÁÌÈ2d$@�[$ú‡I2Ã#1ú˜ª�ç«%4.±œ[‡qÉ‚'h]|�©ºó¸bª9sݶ‰ø#sAL¡ƒ[Puu$róãï$že «aB~3M¾¸˜yÿÙÏ™´j9>Ê DÁ)¨þlLdž²°B8 %RR° Ú„®è(Àô’uì“gçñŽÅO«‰´Äî#@[²Å÷œƒ˜· `ûŸ,êLP‚øUR8K,„�ýÛ½ŠX{ œWk‹d7ºz™žv0{:vÞŒ¦‰Bw™çÐù"×K7ƒÎÌ[hœ7‹ÒÓŒÁª6‰}ßãÄ›òsHmÑiÎ7†ŒÅFÂ߶ͨèSÀ©ðîlÞ\�~‘[).FÞú{,þÞS¤_¼7k¸}•Ó>Xg±t¡i…áÐ8mÝEcâ ±p[;1º�‘†ªÈ0Áž7ç± sy­uô>Ú ÝîúÐëùÀÎoÊeØt 2&ñòi[Ñp£.§ßè�â¶™Ðzlž•�¢ Ç� ¿WMš à‚”>œ.EåÑ×qjú~x–Þƒ½¦ñPñ8šŽ[zÏ4 ,÷§¢bI*+µ�¾ÇÆ]ÃÅ?×ߺðêça‹ û¼Á{ƒ,ÙZŽ¥RÒÌ6%•;S�?ygiŠá(‘X©|�Ö�˜ˆ_’ŠXÖÍçÌyò¶HÒ„æù2ÌéĽyTö, ¼Óí)¯3™ýªÝŒÞIÐ9A›©TŒI-3èSêfŠ'r\0–’]Æ#]ÁÒ¸’åMÎã$Ž‚ù»rðΊ•ü‹Çûèµ|5ð}Jä\ä}ýƒ¸Má z%£Ë’Z#Þƒ^Î#¹ºŽ÷ìÍ›ñÌŠóÀ‹ßûq³ÉòGdéäžKÌusË­Àû’ö`ÌYÿ 3~5.ë‚YúLÊHUFºlÏË�Êe&Ó1(ÌvFDZ‘VgÀ@'Œf$ŠAWb8|½#OmFð16€º�‡8ûŽ�‚Ÿk:a‘\%䬸N‹ô0æbAÅ=²¤ë9�yªäBHE¶­H…²)d/ª·%�hù=*Q ‡ÆÏ™ðº@ŒzWÁ½žœ×=m ˉeOk’)uv…zŽçåÿæÐNõܾ‡¾„Gàq»í”Y�k[Äà‚�$‹èó‰óÙtû8O;ŽÙ‡³d×d•E_]eÀÃßÚf’·®×tû{PÙ›ÆÁxÅ©Tú]”ª–Ѿü~@¹‹ìôPèÜVÓÏp±Tpð)Œ�lÆNÁStùâÁfrˆÖöpêèY¾(Ì×âgê*x9ƪ#\hÖT P.?@{%&3=•ã‚mi´kï!¶´{]–¿Åìžë,E¥üœ»&L ­Ž`îçÈu»´`]z÷s¬ÌN½�ŸÍíÈja+ú–)Òœ®"–뛡5b žÓÄZÄ X¦õ3.õÑB×3‡�įmC‘Å·Yfí\ï“™½Ęšž¦L%ÅÁÉ‚ÙLÇf0ú à¦¾SþyÚbÝ�Q”¨×ÄG…HÖ/n9ZËYgÛ»¡²ì®¶€+—Çe~/¯íøeÿ±Ê±3P´@ƒ:~ž¤¿ê®4cœ(“ì ²P~ R‹Ûqg¶=‰êåƒê|ð¬¦*=ß�ÃJ�wÃÅM>xS3©ú€Ô»†Ôu¯úWtbxDf�ô†‰`PbÄ4ÖÞçŒ6ËR«®Dý­™ß°S<:6­¡ž¦ÐhÓÏT°³ÆWÉKyÝ-§ñœU=÷”ÀIâ±lŽN ¬¸r\IS݇óU Ôw¯£èc¯ÙÝÒHÜñÅ b"7ÁÍ“"°G6>I°Úa¶õÔÿWòÔ7ý Ÿo7ˆ×òHâˆ(hJFAPg*ØfsŽÆ;èôÖÕ“ Ç¾í˜Ljòp´ÓXsw"”ìZ ê5I0d˜BüYM‹ $‰¢’Ü‹³À«;•»:V `©¾Ó^ïYiÍ3æ)¢Çÿ ±ß÷XÆÖzÔå´Èø†:w=t,_0ëè¸Îv¥4q×O¡[$¬PÿÙýœv„-Þ"hùÄ⤑´´æ» ¡Ã½x>Úì„¶Ïàtwï_ð Ï #AmÂp~¯9ƒš;BàÓ¸4øÛÿõ¤bVW9[?E°�BØ”ÊÕŒ*àgíûlË«Ìjä- :7E-@ ¢X­EwÃáòhº(#�Ïõeacûj¶ªa™ËkÑCU…ö •á•â Ô±–å—¯‡­Þ \aX¾ ÚJŒN÷ÊÁ‡Eäe[6)‡zĘÿÔLm]Ææ9ÒVÇöçE#go»–vU8À ¹ÍÏP¸,�‹60"£¼:Ü[ûÝ|õLYÒ^ý ?þ.àÍêEQÕd2M—;ƒÇÞkqSû.²»Fb°¯žmCß퀈 Ñ îýÊ;·ðqM&y$M‚9»e!$kˆùÉ×bÁ¸`Èò‰£ÆeEàêé‡WL»ážðòÌgE&dpy T ÄÙ¨�®äå &:Òäð_Ì-Ö‚]EÓè�p7þ½aDç6Ìg; óØêŽ<Ü‘pÇiÐѲÖÓ>Â2kÄ<šSë@o>EýÞ�ìAK;ßðÍ š_£¡R"L‘+@ ²ˆöcR'â‡�®Že†¤ÐÕ¾)0':ƒù?>N5“ðÂ�ÇRb¡.¿9ëºêűG2‹iäwIú¾Ký‚Ù¨û¼—b¢ Ñj2ä7 1©÷3IE}<»šKÑSÆQ÷³&�îôgmz_Y¤K›’9Ò-}9W�Är�#(³+‹ˆ’^àrPxò.›ÎLÙ(j~j�™¶´,$œ/ox(0�9CGNÍD½† ®úz(Ô}[‚ã¢kiù[1Xþ6#¯'�þ{OJqJ·èÖ1¡7ªM4?5C;màÑÁ;¨¸7’%ÈZ®y„^ƒSècU»…§«éýˆ!çSÛ¨##ŽýlÌ‹»cáéŒ|,¼6†,–iÃî’_,Aè½Ü=šÂi÷•¼eÙx:ç‚×Wm œOx•¨4:°Þ”‹g#ظÁ�Ïñ†PË?˜ìÂRVÝãï¾^…-¡úï�òà>|¶Ï4ÑÂj« ¥™æ]ôõm:ŒZ›t]ÁÿÖ±3¿³P¹è¼E…Y9:½xƒb†7Ø¢Ö~v,à'8&_eN«Ž �2v I4;ôî.t�U…4wCZß+ÁmT?Çœ†÷p1“ )3Cp{Œ-–É×Ñ+ÏÍôYI‘®wl€¾ƒ>[8FÌ¥qá =ÿ› e—…H°¥Ÿõþ„¶2Øø\™˜÷8š¨©¾6ã¶£ûXÅ7aZ‘=ª¢B¨ÎÁ.èjÓ…øä0(Â<šö`²W,-©P‡d\MW²Öà¶ÉWQuš1½Ù¢J3·ÆsÚþkaáâ8:5¤b±l×=‹ ±vÎ"‹>Ê�ëK—¯¿ÀÉѲô aYökü~'Œ>é¾ÃCëüp²m'½ñ�Õ�ÿÀwW$—mšÇ/àž‰?L_h§œ×\`o:U!Um9ו­ “(t(ž_>f9ä»Jã¬�ªàQý¿¤vXM'vHi!œiö…>cð¿C‚¢vü>} Ül6AƒiS�®mafe[aú¤½ì£¢-Ý{q…±�D®û‰€¾º +Ô—C|É6Bû$ؾn \H¥ewGb@æaتùŠ¥®.bZÊÁÐ.ÐÅÞ¡X5{.Øh=Då¤ÉýåFnDý·zt¾Q� Û;Óá‘U¼c1Á†øfm9›ú™ÇlÓúž?¥y’^t‚K±2émaeêã)Õf)X9 Zaé(5Z I¨‘ß>…UÏQeRÿò)`ê-–m ¹k}Ð<[„þ=¦i+_pö³wSÙ�ï8gâ'~R´!¥uã�Qª?ÄèÚxµwóiÌ"Nz#Sïlň iÚ•æÈÎ9Bü + -�¥º©‘ðÏ<†Š*ëal‹!̳=Ç~8ÄóvI²°oíNrP­·Tø2“Õ襡µ… ¹Í½Æåê©ÀΪ$Òu}˜‘œPT<ñC‰ŽOœq†'-KM‚YºV¤´þ,_uM^¼�cBÛÒØ÷´)qÆ�½Ùüèß‘:Ì¿w£w j®:Àáé>ló÷Yäµ^›$Œ¨¦khLÒáNqnÜõ¤ °?z%NÜ,FN¶ ß/ iÓO£“Ñ<ós²ÛáÚè6”­ÁG-@É'ÏñûÛCdXç'Ó´Ñêçys3ûÔ–;“­Þðމ°bÜé»)ùí:¶eÞIÈ¿‹5-™KÇ6.¡E¹* ¬ÉÐÃUšd‡™ëH7/}úÎ�1„½›„p>]Åê”dðFãîO»¨T¥ƒ«ø# ÷™–F$5Íð ³O…hBî EGúêR¢šw±\cŒª×†µI—-v½ÜÁfMå«FÖ±íNEÜe_ Ð ÷ż�/°›—$ñ]úܵ/�ñ‚S<-ÓƒÌÐá= ”À3g¬`BÃ7|ÞïKw*ÊøÞÑwÑX-•îo‹ÅßîßXTgNµ;Å^•´bÞÜ«Ìú˜Ê=\M¢ÚÉéN­*×pçÊ~ní—�˜»S•âï°‹ŽÌ£¼–yŠõ³Yò°Ým2ÞiÄíör„.·ö0Ü3r„¸ ‚›¸à«)�M¥þ4¦‚7a`2_›lj�á’¸,½Ó €Öd3 žúˆ¿ü© „­tàcŸ$çZÐ˘X�XVÉ‹éÕNŸ€jU)ÿ�!Ôme#úö@èÇ>4{|"UÑØ{Þ ¾šV\�Š];ÿc×UmaÞ J×°¾-Œké½…âñªðA¸K ½fùá½%ÿ±WceIõC?·³žÝjBˆíš «VñüÔq�óá:L<¯ÀeŽùÀíZŠO­—2®Â–}öªÀÑË`‰Æ48Y1 ;?JÒÄë1aÝ)Ô³T­úÓl³oø˜î#•õKQcÊ>X´…íuƒ¨"MúTîBªµ™`üh'‰NQc¯�?dN-°RÒ¶ØÝÇ�Ÿï3?N î¿HÇI7ÂåóY8_&c²¡¬t­nUÍ™ ÂŽRP|í1ï`õ5ß%á.vlU-ÈêåÛŽî˜=]G5²¹;CrìÐyEøcÕ†o[&ÐBGNá &Yf :á˜Å¥¼|–Õ_Ë5™lä’]kà¿OvqéIöØÉž:-‡­ãϱ¿§4 |©(Ù™ f©dv/\¾Œ-kÉÕb!›ðÌ��þÅËμNæ “(ñ\NMˆÀsyÊðàJ&–=k×ý)pÒü-ªÿ'GnÇ"Ðc™HÔdð5„ëUZŽÒX‘J¶7é íWe 53‡Å”æM¾…®ò™«æi Ù¬)�¤v-§C§m.Ûö;“vKKâEiXóí”_~oþéç82±ŸóØ´„»{•”øÃÒÖY2�ÎØ9 æf(C^|?{ß\X÷àéó·Epl‰ ÷_±8s ÍC­[©)ÎÔ{5h“3¾¸øê)|Ž¡ _âôŒÖåçã!³@\uÅì?tÒrˆ�úd¢=ŸÌnûÀh©¸EÜŒw¾Gší1ìzè ¦¼î1„*¢Í¢ f=p]}eH!Zï®zŒO£Ø£ö®7F–^d¯…ôÀ4k_cúÂùå‚ÄEðÁ&bt8ý|`È¥˜kÑT�Ë<ºYÍNÄÊDr­ÿÅÚQ•¿–¦Fª�[PÈh#éß)a¢–é)Ç Lé Ë©"JZKéõØ?3w Üá��«ä¿–ò7ì]h`I>q£kDIC1�©]r€“¯òXMÒ'þÕx' ˜;‘ª�ãR¸ë¬¶>•͘ò”•>Q‚ï^Eäû¹ ÿdìà?,˜Å&<�ÖÐøÛîàÞò†ÒK¦²w«-á´H›b"ÎÌìç ü7êÃàÙ=.¿æÑÑèó\”A<޽-œúè<² zÚ2xÛ“ }¿]·¨_!Nñ[°FÕ=4½#�Æ>uàG\ò§…ü·¶ç¨º$‘½æìw"#éù‰@j¿aCãçÍ„õX,~`¼A01 üÒ[HïŠÕá›ÏmÜq ³t÷RkMžêF[³¬¨ìßþ‹¹»™ñ“ZæÔöŽ¿Ý5›Þf„±%%tûõW&?ì']#YàË;°4xjÜ<—"Œ(âQ¨�ÁoS![®—ÅÈã|‘>ôغƒEÕdñ‹´V’ø�vÆUÚ£b©èu!ÚEg±È÷j´òª=)mÈc.:{qPª ›-û±ÍÍÚûàoe’~^ÎõJ¹1“F4N6’}Ihd7k[ásñ4:ã·äûø5¡vz^_³d5.®ñ$زüà j8cv ›[§C«†FÓ!¹•ôãI›9ΕÖý½@›ÒðA@0ý9»�q£ˆ©ö»r§usçPø ±Å¾“±w‹ =±,cš'e(YêTz©R×èb8Õ ÕJ• î½{ñ “Okƒ_þK|}“ üð) Ÿõ•=ÊUÄšÃЪü=k\œiþÇã )~­­;ñ¯�W~#ß�e½3ÝÌâ|4­šAòÚªd•þŠí+‘„ ¶ ÌÔCÈ`•6µ»qŽlÃ×mˆ}ب³í¼µŽ'Ðöqà7ÎR§ßG¶K�&¹¤bsi/[??„_2Cg2–„ûÚÄs"ðPÙ—ælžOÁO>pË^íc“ê9ü9%CñÝ¿RfÓ©:w­!n! ñå©çù½Ç«à‹ä¼H�xWžÎq¢àt¨ïØ€hñ>øy¨÷Ì–ä—�Wg{Aq¨l2Ja¾'‹è¤Š#‹Ì° …Eäµ8–}�B…â æš~ w\˜ ?7m£?!È7Ô‘f·^¥Œ3q,bX)ÞÁÈ=é´ÓTŠü¯ÄÁ¾c?¹[ÏKÈ7á�¸½ôçº1šìT¡vi/¶ýÈRtXDq{šr”¦-ÃÆ¿(¢1 œ’“è_ëv(ÌfYkÝiåÓ|šå›�ƒÿª8«£n¬(. k3¤yÃæ.qz§hSå_p£UähÑ–D\¾?~œP‘> V´ðUIL¥½øY½,’‹0àì*Ö^{þ]ꥬ¤åÌwØG_< ½)â |eX /&EÓH6a`9þß�Ž…"ìþ—|¬6t*‚½P ÿÙ]�–y®¯ãH©2RDl@å�)ÁÌg´¢¬€ŸdPsÔ iVÊ>r}µ fƒqá(Ì;ðÅ‹Ë@³ZæébÏ»\ñAÂ%ô±W¡7Ö�l{Eo¿*Áš�» &ÑlÒF±[wCé÷óæd'ïe½É£ºjØc¤êg%°ÈI'¨$ø,îôìá4#6AiX6sñ‡Æ.�—•í~¼Ò�“ð¾=—*=ZÐÇë0‡Ÿc£6¸ óF~[Eß7.…ÕrÚíP�‰Ìˆ5n°ץ§œÏÙÙøá°# Iýbfq°°>�]¬äd[ò:C4j-ºTóóú áBÆ –5®67üF‘7Jh‘é'pŽž Þ¬ƒ:ÁtŒ¬WÃÇÖÓàâ|ý åIåÒñT?¿6/¨~@�ÂË‚£É¢ôWü:_t_Œ{*ŒG#�ðÍBEx{p F=ÿ�:CL�ûsëoPFO �ª\OÞÏ|ð�ç_¾äÖ>÷úq8Ác·tÅ|c”6.ùIÐúÞ L,Å)îìa:ësI˜.ãÊ3#¨ã°«_M,?¬˜þÜZÇß?¼²s&âÓM)�6ç:j�!OÅ…täU KJR\ÆC¾Ùá0´_u¥§ZîL¨¾ ‡¬ƒiªn$‰Í�§ìaÏw~\�•ã&’òf*¸Õ� ‘¿PçS?Ýh3�·�K¡|ç;<¯ªAg”#Á|ô$r�n¥|i-p]y~Z¥³@õ<^ùws�–Ëýr»– g[µacïXº¼l Uu&“SÅØûGºÞñíXˆ]‘ËDׯ¥˜–',e¢©žêÀ“ŽÀÇ4([}Œ1p{ûPÐìWÄiN¢&‰¶<ÖëotÐë¹°¬4�–KÔâÛ �L$t�zéÜ7%×î¾oÝ/Ö0œÉE_Ãa~¬$ ÜŸãÝÈwéш;áå­HRgD·Óóɦ`xNü&¨šdÒ³…v,¶~Œž;ˆ¸¦ý+ýX·Šœ¥GêF~Öf%ptÞŠ]#‹@Nî꜀À#ìùnJÍŸZÙœñ°iï7~Æþd*¹ëo¾¿ N;²¯iO0í–(=²ó„’ÆþE¾ DâÕêtR‘3éúx¸ã›€µ/ÚÙ¼UG Ïu,òõâ%Íú9�îfÔ_k “† Þ/Ö‘r“�;®öKЫìl–‘²Åü?ùgT%9�„¶îļ#å(Uòƒf¦ðƒ|$«ü'‹ÖŠŠ`áÃ�^a@y÷Ca—æHxŸî¼ft²uF_Ñá{ÞU‚Üg+òx&D[•|øùM+aý¬Dè¶ õ26,}ÿ9îˆórxšÂ’îW²Ø’=‚�ÿ�|šP\6€¦àm^J/‡y�¬¯»ù|-ùpQ¯4’zC�²ýùÃnî` *.Ó˜ÛL}ˆ“=G_wRci ]’Ubó¬gA�Ô;ô_˜ kC3˜¡~6 U%S¢5&Á´/L¦Î Êcׂé%+º#©Nïµí¡yä/ü‹Ç!‰'ä.qI�²p½8¸q)>?wM«nqZGZ-Lýu¨¿Ö�-v÷¥¥´›Êu^DÑ-©ñÐ*²îLh€é]‘�â:žî=Äf?9ƒ-{&�@¦—Ô&“ð˜Ë¬V.tÊ'ñ²!¾lîïÔïÙú`žŽšð~æ7¹3qÕu¿÷6bMíÜwì(Iì*fV»5I UŒšæˆJ—c¹•"t©'€ÅäÁæ³· oòêó¤�W—kàé>´8ٯª›­˜·~È»g“²¸0y—¡ƒc½Ý:…Z]¥q»ü%õéfOFÑÃ_Alo•7*]φñ÷¾°}Fñ¨:š:ŸkÑtº‹C]¡Ýa[{o N}Š·¿Mž›íiî¶G\û¦�¨{^[Òú™«�ÎôV¥wbô5q+oßµ’Ÿ×bKrzÞ7a_Uj,Ü#KÙ”à2~Ýëst{�7é�‘ oŠ KC·±šË!å@5;¶[™ÂÊþíªo©ÕkXÛˆ)09p$?X޶‡t¸Ã+uaŽD0=¬Kæý,WÀî«ÿ±Gb¾`»ñ5E•­'Ù/™ÍœåâйSÜÛþcgC®Q×çŸ\Àò4;÷<•OÉ‚¶\l/›~°Ó’¿½ nY¿b N2ôgv>cóÝ��[“eïp‰÷…ùcÊâ°©L•Ú@�Þ/¸‰“CNa&Ëgã®ó½çbaý+Àµd+8| µH­÷‚õŸƒ§œ]±ƒ= £…Îãè_|?—�ËTæêCiûk&ˆP£´CHC"d¿ïa|„¶…Ñs#]8ãvkéd35ÄBì…9 ôUaýù—¤ú+‰Ó3ÚÂyø jM?!ü'&7Þâ�ëÉ‘¡†3}‘4༟à�g!îˆá­ÒÏè’:šk^Ùƒù*°ÿ Ò™îf*Õ™ËÛd*˜5ô£éYjÙpê¶c¶âz¸è‹óe.RzH ¸$.£ÇéSA)å>œT"í�vÏ&©.ãy»{ÓþÞ°¾Â‰ìÏ‚VöðVÜþ°Ð¬±z abh¼s9¥=HÆŽìNÌQ–Øs™)NlÅ…NŸÏ³5aÛ"–c²&ÀÐÛTW`g¿§˜+þ®£GÃþ¦Ñ@[;Ã�= tÆDv¾‰Æ { �ûö*g¦Ë׿sf”i‰j ˜”þ!…ÛZ�ç—‹ O8lü—À|•vêk*`XÞŠÙSÞp1ºþøgѨ¿_‹Á…£H&9‡yWâs¸>VQu›ˆån½é | [S1r‹+µö•cG<4ŒöEÿå,Hë'w!?†<9Á¦”“NüAžÓRfJ»,ÉÄÙ› hV¡)´zN¢ªU<5†Ÿf²e1d¦ ¢š®dØÎÃuϬ8ë¶‹ÁPL„LÄŽƒ„érf3v?|ד‚DzE›ØÆ°6S¸‰Bý>�ƒÔuuw¥áKŽ(lÀmÛ„á[ÍvJØ~—ò ¿5Ì¢-üjqRˆÞobËv±UᥬFUÀ^Gg“%%(Zw•Õ�„û¿7ÁV»ËŠêPñû7³œ©O ø] .êpÒ¤sUzAní/‹}­w±¬CF|œ‚S­—Q»*Go6Zó +‚é¨S;EFYó¢m7ÑîÚ",mÔ%oëÝì»g>÷]CšÊ4]{_·¡O à~ªñ^Úe–d÷ÇÈ4€Ù7˜4Ž$å·Pfƒ0é¬Ì…®¯‡iMÏBØö³†ù÷F²ðOä4§Ç”~åÊ®jÑ�ñ$V?'�­ï0™M®pÍ´>\=¹�E]UG¾EU0�ñµlvJ<Ü÷ó 7—¿²“6XÛqk­Ñ¯L�iÚ·±OŸ À¬nOÓ„Ÿzòh|ˆ-¯^,`­º0äv™úÑŠØjHP¹ÓÄcÖ“5kºY|ºZ÷oÓ¼Á ».€4ªVÂ}ÏÿPS:Æ™ÿÅ¹ÇÆÀ➘Ìmž]M›Ó>㚪à]ŸJäèäÅB¦çì£2Î’—¨è–T²5£# àz„%x1ïæÛØu¾œ½X'�'JU¨^Q>ª³¼™š+tAe}îr'eùU8DJTÜòûòÎAý±'4©ê3¹‹ŸãâWd­Ž¥înu*Y«Ë$Ÿ‰Àdy?«®ã¾kï�mšK`ÏðîªÃK-ϯfáå1hsy œIWƒ‘P±Ó`•u³øí;Œ0aS%µúHRµ ¿|“X¿®}þ‘æC¸’ù€6¸›Ã‰à]^È…ïFwb ¯ö{7§øó ;Òq†äŸ¼bJ­ (Ø1×Zdc¬Œ>ΰOŸGŒ¡/ Y€w!\Í/£È]©xsÙ^vìd/ŽJ¯–ä2‡:àW‹¢Î×HÎ(ç5—;J Ë6C•|^;¥�F½Gr]¾·Øåd² šG Eë—S°R/&k,A‹gwø—ÔÌî�¨»½*¨ôo9[³mÈ�2ƒWÐ×x¸ó~kRÀ(B›uc�i->Ø¿vhÁõˆFnÆãf|¿¨ƒIÌ}ÆFˆ¥â^GŠ» Ù|šùsÎ $—æî Ë9SéL¡;ùjߣÐ÷»½EáZ_-𥷅;؆"mh–z€•Rti§khLŸ‰ªÔð^…�zw‘³Ø÷|÷›sÁY÷º]á±ïû)–+ ŸW ~Q"û¬ll¼þ c³«ÕúÙ¸{HŠnl�1×@ÎåäKîö”ÞÌ?(’…¯–€Ai—6Ôm}a Š{…à� ˆáê³èTÝÅN\k²y!µpö2B’×&°ɪ¬Wí;H_¤ Sm¥-§ÒÓ!´è…8}øô›{îpÊ×”èWíQz¸s¬lãhäª@:ny‡YV´ò3íaÕæw,ã‘!äüÚ§¸zè3Š ³ÄCË0l·<$ºl…é[qÊšÁunl«cÔÛ¸ãŽ;†¬"è\S'¾µÈ}©Nú­gð'«Aù{ÓË®€é‚kìÉJŽ/8"ËFÅýÇo¯]>í”՘ƒW% ÁgO}ó¦õ™ùöWŠBû¹‰¹AÓm)�ý¾‰6\õæµ+Ʋ+sM,º—m…̹P»ü3-²¨@aŸV~LÒy*¾ñ’�53$c·"Þ|^ö’*ÈÃAvZæ g¢SljŸºÀžm*¤™¡Ìaé%ìV1¢©êºL¦t*[ß×ÌVÖ³ÓCÏØ&nˆ âKñ$Ì»µ—Ï Ýï2pºÐ#î]Š8ïùÈiÿ–€-Àx—Xg¬á…,×­�£ÿ¾Ž2×ÿ¶¯ŒUFÅä Ö‚bC³I÷±ù�éîÜ)Ì1E›¶¼E�K˜ü\t·CòºW ô¤©¹ÍŠo¶ÁÑšX_„3l5è«à:vÞêåþv«ÐËó áÒXkò™àIFçŒéÍnâWÖj€ææe(6‰#cÓ~lU\Í iQ·‡oÃl“õm6Õ?¾†{µÓÀ¹Ë̵ì@GêÍðSÁ³RŽÀ�N–l /¶Q^·.–­�‡î¿°L=�¶ýRÀ­Ú‘ŸB�%ÿ¡óA=ò5�„ö³ìßÚ�ìö:=ªý§Q¯qù#ù ³ÍŠ¿Æüè*u8±:´Š�ªßºµL \¿˜ÁË|cØ-9ÌX'*xK…Eôñë2\"íO ZàÎÝNœ>ðœ5fzƒ™ö~àk$OQß–”*ð;ì¶¥°š,oÀ¶lÄ9ÄN¨BVµHÏ2ÇÄ{i`«Ì6�ÜF&sﱂžds«Sipâ”*†ZñÐëBÖóûÝ:IÖ{/·ù‡% ÉÂq�û²G†v¾ao[$¨JÅõEQ2}fIq�LMñZy,5}þÈši!ô[L£Q}¯Ùl™ßLÑêþ{O'L?2¥2k9w“kì�o�øón îž ×ϲŠÅÕ`Pî+j±m´$iZ9Réâ*J)^HS5?0e³ÙÐÛóÆì�ï6Ö¦«îšQÚ©}p±l?(>¿ˆ«}âľL¼R!ÇL„%à¯OâýŠ4Noü÷9~wzÉm ûkÜ êÎë’!V 'a<(ñ‹û7®nš\âNŠ-e?n÷³ýW÷W©‡:/ÐTËqlÿ„+øÀùIVO�†W^˜?œCA�í@ôx îŸo úï*ؾ·Ghí�`›o ÖMA0´ï3*{È7öŸ;³]ävQŠ9¸ÅS¹f¾°QÀŠlÅè üo]L“€ºËëaH'ú-„[nëÉ|ÈŽ®PãZ~íá_i/` –¶`[ä¾ë7c¦ìmæÐ¦D±ÅytáÖ¦6æ–õÂß]þZ¨ ¶¿ñ·ätܱëh"¿çÓpP¬/Û¦!v`rú/Î2�}«©ôÒÞ¸ýsM莩5Uî{ŒÕ¹W™}6éU(.ä­„‹˜w°#=<òƒÞv~#gµûÈÓ‚Ÿ"Í•§¯· àÚ4+*9êÇf ¾|?–¶/Þ�íkiõÞ(àªvB̉M䤉e³Tðßj]h_^ ÒSà%ÿ‰½‰[ yZàKx5;šZŠç¦Œ¡%‹4hÙ»0<;<§½¢Ÿ Ñ5ž\Ô(ØÄžý–‚K;§Ct¢?‹Œ°b÷d„a‰e.͹™Æ.RËS|²ùНe³`¡m'Ø��EÓÕéWQ>~Yù�%­:‹c–¬¡ èer;ÆßwÍ{– ®ð›w鮿bîùBê©A»Jˆ6É€ˆŒKLaƒ!ŒßŠ[6�£eýaÐ&3‚ެ�±\ÛÓÏ®šK’ø¸Å�.®‚7¼äx·5ú$}V›ÔŽy‚MK«é6%™¿çðùê~å·rfd»ŠýP�ƒm·WPdâ"Úë“C.}eðáM8�_“É<ù~´½ê qâ9Ý?€ ¾&Öýã rŠ�ñ `µ‰%´ÁêãÚL ÔÌŠ~,DÕ;]ìåS]vÈ(K·Œ"“�P LO†H_ê¹ZÝRö´6 ÝD«ž-ä|~Ó9ÜLónjAÑœ ðaó4ô M2‘§™EG» M$lÝÈñ-ûgÐôû"`"ÞÙÎõ´²Q%i0¨ß)?2iÿq'v!*— îÎç$JæÀÕ+,åöhNküXxýæ v^3CÕ©«A>ó5Íq*c²šgÐV$�Ò B¹!dŸ&�×ßT6Eì=w,g"›¬S“7­à¥×»Q�±=üû>ÀÌþ{Ç·‚M?9ÙòÆ;cî{žôïR¥^Ô¢4DúʹQ1²0O˜‘Ï/E8zý£ç~‚UÍ›Ét«ʬߦ¶|D�»õ¼}In¶wj.Zæ°Ä¯‘”õ}›º0„®Íf³® ŽÈ‰…ÄÎla' ÿÑV°/ð§ï#`ìvn«¥&ioèä^7­fgB Qä§�ZcBqò¥ zÁªZ î•!�qâP³êÿwË?æ#¿“Æ8ž¥=åKñ¢¿!ÝSXËÔž¥bøËfxÉ‚íšTÃÜöpr( BuÎÔ,lLª;¿±äl.¾³ëÞ³ïŸÏqŸÆ|ÄMi“ A#&½¬¢Ö�WÈÿwÛû+’Bw«Ð‚SsàwÛN6zM�²×Z2©3Ñû“Æ]ÈcŠ¥u¬|J"ß÷ßxòçØÿ¹¢á�<áÕˆw†òËþøx˜‰­Eì A¨"·SÇáÉ–2Yº0±î'nùQƒúoïá×ŧ!pÜzêÒ� zaưzû°y¸„~¯G>% {j?3n3Ç¥Û‘¶všÎY?S_ÎRëy8=xÒË¥¤{BÚÞzLîpi4*aùˆ�l­TÝ<¯?—кãá{ãåíªÀ*ó8¾Q$*üÛ@¯¼tçi¸}Ì,v¿dâ·ñ™h´€c©�ÙÒ4½7^o×­söxÏšj‚ƒh1¨k¿é WpÏœP½³C��¡×š³©ìÀ%ÈøÅf Ô×Åá$S”Y”ÊQfîÙDI©P’H3RIã?!óLÆHTÆJ¥A†»·¢Ð, )%¥¢YiRy½ßχ{öÞë·Ÿç®uô–ÓžÙï9QuìlyÁ,Œ:™ëâ(2Š4 Ioú¡ìfEÉÏæ¥ÎÃÀWªÓ+¾ð�›÷@¯öZN�é‘ov8Ø—…õdÀÊ P2æñÒ$o|ø-4.éC˶Zn»�©ý) ‚ÓÀëú5f`¸¾=žf5ü7—ÞrcYnƸ“PA‰¥¶œå¤£¨>¼„½¬nƒî#ª•³BÓ¸OV�Ђ2:sÕ²º<‰!ëÒåµ›®N ëƒ’d²'œš†ŸAõ‡k\a—>ì¹ sägCãú38øtœUÎçmôlÂzªšÜËèÕrÜ¥D×½â°ìæuòu�"˜¥Q»Záö¤ ÚÙÕñ´tq´]ëáŒMlèðN9p›N™“$0éª1”Ø$ƒçØ1`<{5¸(t2,L&•/JpÔ®�ùŸÀÀ~k8zHœÏ~¡î/j´N £VÃ#SŠ/®n™ümÇÅ�ö[úª{òÍëA,ê Äþcÿb—ÃÜÍuìÝÉt’Îôåמ§Æ_C q«–ÕJâÖ¸&þfÞ‡Ÿønúœß � ­÷ƒ�ÀlÚè]E»V;±+Û gš“96“F÷Äcñ{)ðÙa Ï$Ó+5³š®â9ÀVÅÉ2±l¡À:RŽE±ì ò? ZÅØkbZô[–3¯Ö¡N ¦”Y$ùò ¥©^Á32!ñé;Ô,ô¢Ÿbß |Ó]6©5Ñ·ŠÝ{ÎqÓ€ÁwV>ûý»'];Äg/VDÀoílúºÃ’¦m¶œ¦ÞDWÚ ¹Àæµbÿvž4âBÕ/°x£4Ú¼d+)-áA5¾�ÞëÉÖZéöà…«2ôõÈ+,ºiC6Y¸øm54L+Fƒ·‡à1)™sð½l!©øv€ú ŽæM\Àeïk¦Þn–*§ÎІÀl4H§Mjû`îãó°Á´�ÿ/x|ú S „霕#»·s.¸ëð/4pçÔæçe‚ŸÂ5vÐé;m?6ˆ½-5„aãÙΗ¶ÈücWw„±ž²ApZŸ ïSŠÛe–•ýüJ #‘ÈNxõ^µVzTžÛ×…ûÚì˜dB4œZSÉŽO=ÇÒS[ ¦JŸ^;˜YÞÝ6‰ú®ÆSþæP(­‰mq/�ULå‚«ú Hûw�’å0·Õõ7(*�§)iñ,uÝø5à†“vbbe?ƒ<{ôÙÛËÂÏñÓG¾ÜT´V›†€¾Ml;‚rBJ¸+ú/>” ESZ˜*e‚A¢šÕì/ÚT±åë~= 4Ö¶3?í.˜¿æ0mš'ÎðUÓñYÎ~Ç…Òë™—-òL®0룊¬{à•i¶¡Š°Nmö*eÖ/’DSeUaå ®ãÑg:¹ßD‰pJAó©¿xiP�½ÿY gƒ_1¿Ó?ñxk\+Ÿ„fÆâmÐዪì[MÊ?E¬DGúû$7£æí@ Gx½¶þÍ#ùé�³¬˜ùK=ƒ¸ Û¬™®ª®§¢µõ¨~j3®´×†á.ž1±�lRM ôÜÎå€>ñ‰Ÿx‹qc­»í±G_™|WÓ:Å)Í�¦÷¥”‹òÌl�yíÃý™XÐ*›¶Q~F=ùtÉ@Í’³ÜØd_ Uª®Š*¾EFÍNà{"³÷��‡N2÷9ýtÎò"u~:D?wPCÿ˜®¦Èò7ø±ô*Z¨QS*fÀß½3ªŽ$í‡÷3€¿³Æ2ôÏÖä;��Âi–��'+÷awK.P‰4Ìl·ú{f|í¿Ðq°y¼7ȧnDEU¸à×ÊÞœ8OG"l)lÌhX¡ Ÿ-ÕH¦ –´}fa݉U9Èv¼ `£�¢àZ¡#µÏ[HåR«`¿‘þˆƒ´Ñ—eï)0á>åþ:Èn¼S±’º4eÓ£«ZWSûŽtòñOgÂZ¡æsýî"´zq>ŵFÀ ea«Ÿ«¿ÑèæªWR_ûP²;™@®#¬ê¨/µÊ›q­}3½½÷‡'¼aEîBVáÉÛÁ8£Š¾‹/~|¥%EÁ”1pŽF›&“Éߺ?YÀÊWßþì*d�k¼éãkšo¤Dõû| eËâCÙõKÌo_iþ;Iµ³MÁ~Q9;e.I�THóï"è¯X‡–“ý÷] ³4‘V¹ŠQç“‹´9¼„º-©WÇ„rg øþQ$9v&ÛãÚU=GAp`Œyü†$"–ãpÖþ¶Ò,ø½ü4KÈ·cÏ?ùÃâju“â+ÿZ~öjgËÕk÷�x°Ž¸3„%Œf_Kéë§IìÌ%#«¥ã()Û~ÜAfÒìÌ SJ�ÒUõYµÛ³áÁ†qìÏý#¨úÁ"͢nj©J)wK%R�"ã³ÿØÑ�B rðžå ñ NЬŸ=+;„½ÇjÉ篴ï’`eg< |¿þgÁxü!ªÿ˜ÇnÍÕàwhØÀ¦†0žº˜ÍÓcu<ï6wÅ<™"‚:kÒæÅ39ÑÅxðFÿèù+J$µÚ‚;‡P3—§W_g0+•lö"éW¦ ·XÕŽ²�­ý¢<½ò³@>¬¶Î¦qMgIhN„Œ8ýÙú¿œJÌ,Òm¡Üäd¼"Gþ–]pL æ:%Påµm`2(;^l‡ uY`�'Ξö”õÝDïŸnà;{*›óM„ÊÒH³³Æl—Çž¹›p“â%ˆÖþ Á·=h`î7<òÌ‘Ò�¦²wå!ìÚZøO|lÍýInEþÐ8Âû{Ñð®óLBµn{ =+¬ÖM+&ƒ_#žòkŸeœÞM¦ì—æ›'¿ /Â3=èÓvÞQø§6ˆ”~°ÔÛJ½ é¶o,]O9�ÉÏ6ã³,ÙÓKÅ ÄÑ/§jxülúz~ƒ‚s½©°eµO~ã…Fx!ç…c¤h�þjêЀ�GRÙÕË3kÏŠ‰Ó²Š20ýReBÙ¼ÒIºrè ýäÉfê 8cÙÜðº/ÓÕ§¸rß>Üéö‡ ¹E‚ôeK’„$íõðT"77'ÑÖh*?àŠO‹í™úŒì §I—…@H /s])L>•nX+™Ï<ì“æ�§ðÁ;æEµâü Ö0Ý¥�<úÇ,F\­Së&.í)�ÂÀN›ô’“/nU´NÙÊYBÌü®ñù=u8cÆGþ‹ì„ÚcÅÍðoðKT¶ê3’¯Y�Ô>v¹„NMõé°û½—ú5 öÍÙAº·tà¾|9�!3ú5÷8¿Z¥õ âŠö”ž“Á¤írGÔo±P—+TõºÊbÏ LÀT(ð‰Å*V)ÒVAª£iu‡Ýˆ«”sušVN­óà‹}+][>ÊÎÛÐw‰)lå7UT:ö–9Ê…lµä{Éš÷ÛOî¿WÛíŒõÞÉà¸é<̉(€ÈtÍZ‘Š ~¹þ9:¸‚%ß±¥X—|šþ¬Ž¤^’iFnÊêãúg)Ôh›D%ò{¨»=—y,»ŽÒ¦-ÌX­¯Ÿ,€àÈìºIf«–Bížl·N€Ì½_ñG;-ÉlÚ \-ú)§…³"ÐP$ ¶¯qk÷{ôWñ%“H˜B­®`òí“¥e.B¬|Ѐl<ðÍ!ÒôÑQ´GÉA�F6Ê:xƒ­²8à±~R½nt§þ�ßYfîh«NnXurˆ‘˜2;9|“™ˆê€fë#üi\Gç-±"ß³¼ìÁTJ[ÀìcÕ QUŠ=w$�U?¸=;.ÑéÌ甕j×>dg/có¶à¡QÜÌèlæ½Ü–Ö£#¬Ò a štøb>§&Q‚²Lñ¶?�¿oÃî uÐÝ5…²�wÑëZ÷r!èv� ¦µ‹!&v ¼•e—ÔK05]tgA•ÏމÒâô8 ŠÍ «¶–Ùk.ò.E~,{8‹Ý_Y‹;VïÆþ÷†°°E ¦¼)ÙdÆíÅgï“©¢c3ûèJ•ÂïÙͰ‰lç‰èЃlïõØ8ânì}[›Û º?¶’ïøj­°Â…VÑTЇØ/ú5�B:8\ñ™µF €²þhêõÈeűGÙçý€Tb±Úc,-ò|hñ)êxËnN¤dYȾr˜ .Ï¢ö ) n׊·µ6&¡Û™ÙLeSۼŠÛU&°Î¶›ÌöÛ*8¶ñšÎ¨e“\&3ÿò|½Ò…Oö[ þÇ˸ [·øîÈ ”Ž]M%ª®5]WÜIJz6ËŸ`½¿0“³øäv<õJíA~ÒÈ™/gÁÑAš^Š.«Ù¨@Pçì€ßm¶aÁ’É(úS˜Î¿ÍÅbëØýœ ä(^©¬äçÀ£·£ÉyQ$´ýJb¯>}á§çΡp/_˜ºêë}8îŽäwÞY*¾„C'œXžm^•‹SdRáQí%Ì8©w¦¦Ã(‡ä‘½°†F¸Óéµ<Ï7©kPõlm—¸Â�ßžŠ> :ì¼l½˜í¯çq�Ò%™9×™0åÙÚ—éŒuõcéÐÇçØÿÿwÈRo`ªµ9|ÜÉœ ¾âfA/º$­ÀÚf†À†ý–d}’ÇÑ’müZò`A‘Ú$;±£l/²¸�3Á;¤’ ¬kåýk%½­q¿ÛÉ/n×�¢^?«›qç”­ Ù®±¢Vs=FSλ dûé2Ó>åÏ7*WðT\螯,QšÃíÌVÃso.Ñõ<5Ši£={_š;å*�€h+ëIÜÆ:Lz8‘}¸{x&mO: {ÝÐîí!lçfS~Øw*9ÅÜdÛÞâ­lÄ%k�ð²ª3|4NcÓþÆÓ‹Ê±Ô¶Ó…=7O£×š_yÇoÁíÍ9œÙ“J_6¸PÕ­G`úx>(‰;Ô¤IN�î¯ 4éý–áØ…�J…!­:¢�ÍÇ7§iêµ$šRR‹ú J–†nÉLÿ;Ú½™!‹â9˾ϖ¡—½À'è7(hæ_ul#‘K1 ¸B¢ÿ•á_õ7xt÷o4Üg ’…± p(C:½ñëz%¸ûí+÷Tn ¥ jЧ�e0(rš6³lº=ßꚌù ÜÙ=ã¹´ŽïÄU%œüS4íýÉ”~&ƒqs÷gÝ#V6í8ÿÒi.Ôܨb„Jx±�]¨Ó‡ ¯L#£iË¡¶ røN#÷:�Owî^Á�çÉ :Á†væèúΗ°<ÀŸåfà5-’ø�³3qèÓ_ 58ÅÆ>u¡É!ãj— ^Ä@UI˜°r ùÝ/§)¡†°Rv+Y³uLöû&zvá:¶å.ÃÇù¯‚vñ»}ÐC‡àÜz+oÓ¸ âìQÒ6œ¹{€òŸ©�QÊ®$ô’î®X�c4nýÜ,~7vÝÃá�|ö¼7s¡6ôù¸Ž¿Ö€NÚ# ñ+•ÁEù ¤±gÖœœÃ²í6r%µ­$ÿ¨6v‚�ìúðqEX,ûG�û;dK%òÙƒ�(ž Vûiƒ ßxôÙ/Ô£=^J ³È/¿½5NyÔã9‘ÿ 㣠žl[ÉX˜úH•t�2xúj6äváÌWÉ¥ÏX­è ‹Âa<]a“"RAWÁ‹¯ Mfן$1Ç#Ýü¿JK^öj Zßÿ�?^(Á‡Á/|„ˆ!†<ôbr•Ö¨Û^Îå/²} iÙ§)#l�·>Wrk]PñP>íþR5?FŒf�†Ö)¥PµièïÝÂ4’[¸�¯\Qs…ÝÓjcóʧáåç)ð@oÅÌÞhEøÓÁÒr8YysîzP@QU¸ Ñ¥ÑjP¡öËÆ�„»o)z©ÌÎF•í. #]Ë;¸å¯6å6­‡ì¢Eø.fÛ¯‘‹³ú™¿b &r#)9›xh@�À=¦ãó™or=9Âq0EW†J_àê5[Ù‰†jXå¶”)­˜ÄÝ‹þŠË‹çÑ·ìyÕÚg²9ñ)–O–ó?v|à.ê°—ÍÿØÖ^ú™!Ý…aMÌ{vF¹šç§�°ìÚAÔOZqjüt9Ä5ï‚ ´£lÉpxü-’œ½Ì Åû=\i'—]`Fz«|Ñ ÖKÇA‡¹<¾m„úånøpíiv? \Üzg©HQp×dÚ ‰¯oóç�±Þ# ÙàÒî°"ËRg>ô¨2ÙK¥�¶¼ùÖjQHÁNq0›ÚÇ0µÿöBq±øÇr´%q% ÛÊ‘û¸h˜°”Ndf±[mä%lJ {fѪsaø(™±; Ê–žwÁ„ÉžØ5w/Ø}R%MŸó`ž×B² ÈŽkÇ�•Á(év�_=ÅjVI*Ú×e`VøGþÕ>Oxw.4ÌnÐ/�-°R¥‘É=VcÊ[ËX|c o½w ûwQ 'ÖkÂSÃe8ßú9˜µÖ|ŸÇ­l!Ö=~¼Ìw Ëýï¿Ïl,5oq‡²1ä"»ƒ¤×4`�³2™µ½dM ùìÅÓÛ¸3}#®Íý�ðö&tj:ˆë/rMcíèm`*õÒ¤7‡ý@øè*¸¯Ú‚Ê8štžï-±÷‹ ®Jg žÛ™EÃ!Z— N¹&"ptu&ý\8 —4²÷M’ÜëÕÏмþΣ£"Éhph'E`.±ÙÙ®ÆNж1y|Æç¾Î Š6#ªÿ[ý•áб¦ŠÅ¾S$ãôwµY$À<Ëåu-Œ ÊÊð†ÈEø#™mîìdK 5`tò:84ù'÷2ü™îò¤ú ‘(è.ÃïdzpÚ¢ [Ý”Áù°3v ‡Õ¢”Û.S»ÏÃÚ{nqn£ìÑyÆ V¾S'„Œƒ¢Éñ`7xŽVªøÔÈ­{À¬¬/ÐcÝ‘ 8êGçÎᆆãäú9…õÎÍaÕQŽè-DRây­Õ6üiçùt¹#ˆägÆ�ënG3Ãp hó ÇËKƒih�•…õ²¾OÃxkÁ^vóÇJ�(‡ácVtÁ¡‹Ó~òƒ­ý“—«ôÀU|HMB½-dתCßëBr»}.ˆ¬¥¤kýd°ò%Ûþi% ð[~a<9�?…3 ¯Â>ôBΉŠþ²MìQ÷dü芼òGqxúÌŽëá¸ßWèÄ¡wÌÈSUÿ†ïn žÉHÖoˆ¤ã×&Ф¿20[õï’�@-ß®BùëíÐSfÍÑÆ´•åbf·kWylù}€âŽÖØÓ yqo�™4z!‰\–»÷x�€«œ÷|�jïýáAË(úß(0·R¤îWûA|1ÓÒ:Ê{ëŒ7§dPÈk ž­™ø�¦Ó�uøee,$“¢É“›¹ôöئ.bÕýÒ†žLc© Ö¬Íû5·&, ¢u¤­.‡lÁ;³Ja`ç'Þ¯f€Õhxƒtž5 õ¯¤êúè]ö�Iï:bQ/½• Ë"ÀÝ8ªzëÚ+xdF ¦ÖÍáÇëxP–”2D®‰aÕÕ/QD6d¶Þ"ËW0¬�H«ö´ðﺔjdÅ7 ä–c¸a¿oÛþ€ÜC~°K±á¤ð«½jðGovå8œÔM êþΊ­ãÈ¿7Œføl£¥ qp¤ã h/5‡�f…š¢MÁÐ1ÓF-•£ážX�]öÜbƒÛdAöÜ"¤üø6¡±•ô|B' XžÈÔƒN`\H:9 ¥³'‹ôaÃf%HÑò­¤©ÿeÀƒ3àV†=ìÿV@¯ƒÉe{0½Ú?‹�²²‚÷ü¯ô8z6qÓ Ë%�£¶°? >îÖb ’àú«R¸ù\‹.5ê’á×w|ðijs,„ @¯Ëœtexkv`ÅÜëxÕ<Œ’j6±}1ª¤è~N¬ YŽÂ·)Áïq4­?„5„uã"][”hd»Z¦RxJ"3Ê> ª¢1�[TÁz6*cÈ�úÓ¥o¯R厛¬`ôRا*"òX©Ú2ÎU¥c²°üj{¸a" jË7¡ÜýÆ\¦„ÄÚ¶jp“Õy¾Ò¤Ž;Q$�ü“,z½Sƒš×g�eÊm WIa[bfF™ßñ…RÇ nµTƒ+`ÜDZpf¾6,½<”blXgØZíæolè×µ v즸r.Ï%�œ£Ôí%€·�ðæ÷;:ŒÙ~´`w=K¸1\d¼â¨Ò"çû^ þze>ãCÚw[Öä† ÑÔ¹hÝô Øí•Â�vî&™å5_˜™lÌbÇcê·8h‚<æÀ Çn–&w‰Ò�ì†7Ïä!º+ 5‹w°9ï‚ø3룙‹÷/<\øåWx³ð‡³7EÊÍùÃbðÅá"BÌGV[ì‹þ£"Ðx‘›hýp6m˜Èʯ�…Ë{îã�ëeàR-’‹OáÇ®Pøã°ž¬¥‘õÁ‡üŽâtØùúl?/§v+Z ®&j+‚ؾ9µ+ÝN“Rà0;¨îÉô¶Ð¾CÖ, W¹¨@µý7¬Êsã ã…„mÌhv›oó‹­É”e3;Žâ©a]œ›s›) {a‡ò2pÎôeíåªèýFÞOäÄOgrÏ2­Ó§àæ =èH˜FÎÖE8Cm Í[z„ýœñO+܆¸y,èo1Jøj±›’b”tžùˆ‚‚Ï:3�Æ›Òagø*”�FIÓáuÿN¦Ûi o[dÉêM=³QÊäF%þ„=gUIêp&èÞž�÷"÷á:}Ì3‘�[žMô»z¸K:QôŠ8^øå|zŸUËâ{—‚]‹uo l0�Y;š>ö9SëˤCs³èVÇN|릖Íóƒ Üžóµì÷¨)  A¢g—BpÎsJù€×–~çç>±'û7»@[l3Ìú7bäÀåà_üÒ­GG³ž±c5ÎNÅs3±U'¯ &,Ý$•¾ØÃž;…`ôÕ“µ6ì�—‘Ù²ü3=ìôÇnUáT8Æõ°åQS±^ƒá®äOl«Ìq¦æö�¹LÔ¨¹âÏê 'SOGï­Åm&ð°7ˆÖÿò‚SçüáÖør nø‹�9|j}Õ6N£Žª3‘¢mÝ™à}O)ẳd~LZ9;ñ•÷ÕÅAn®ê2d[Ç­ªâg—EÖ<_%A‘*?1$7� ªu¹–5hªå ýw6¢¤H#/ZåKé¯b(gþJÉÜáâPôä [�K҆Ǹ衣Ôò˘û2ÒÃ'Kœ�››^Nnü‰Çµø^Á�—ì AåU”¼GÆ|‘dn-éà Üþôàæ£’(³~+�H,¤þýÊQx—}ºWÇ„…ø·÷øgVÚé®ÀÞ’ô8½¿««Áï&ÎQ`"<,þÅLmùŸ3è×–0Njå™Á4Ü^KöãŸy µM¨vaÉ}æøX/9Jru6ªøHèKÁ—ÌchUÅУÄý´ßf ?&Bw«ñÚ¢Wð.¦ÍÞŸB�3°oI§Æ_.ðÓ=š} ©ßºÀËÓâÍ ä6ß4ÃUÐÂn>Vÿñ„·t»¿. µug0HŒ×ó`�9áxêL3ÊCs–¤âÃ÷/¸,çÜc�áwxÖr™$4uüþ& ¯�ÙxÇ»¤jÈAõ»R<>?�d3y±ã…´m¬Tí™ ¡¸StµåÏW3˜ÚÎh^x²;d¿}Ã,´ÑЋ˸ôÐ(Vªd–ç¯Yr?¬Qûo)º 9AnÔköºA޼ïŠPkÆ8Ù/ÅŠy!R}«N�"Æm#÷ ¡ÿ3Å&}èlXÎæG/×D,Ó_ Æb‹V*çwÀw·{ÃøÕé¼@n%¶ ë![\Äþ}jæ^¿–Á¶;˜vd"îJÇ®Dtâ 9)Œv†½Âÿÿ÷3ˆsØe–{âß8Ηj+@ÖóD ³ibf&6œß„ÍœLÅrÞ-ü ë.cÇÍ7QG÷i¶x»)žÌ=ŒïwDû[’¤f½�,Ÿ”± r£®bMöhîqpþº>IÈóî7›0çw)çÊPîÖ¡ ò¡¸ö”"|¿0TNt°iµ ²ì õUð7ƒÇíñôܲ˜zK²W"Øéú(:ü¬Ÿ’”™ÒÂçd½e¾JFI»kàÔ&L[ÍŽÃ,³HnoÖU\s™çÒ§ÕY¦³HyÜ¡‡ãéåI'èñ<‚÷+’É )ºµ'ŠIx™Òû²8>oJ­î�@W5“(¿ß ú{ÔÐpþÔÉ‚~âd›ð‘o¶ŸÊBŠQ×q<µŽ.åFE~ÅáÃgÈþÙK”“/�׿R™Ftœz Ïç'b§ùC¶û³)&d@ú{¼²Ü<È*¦¶ð”oik–°©ùKñÍ9CV˜SÁ‘–;©ùãmíñÍ›_8/4›=v£½7/²HÎö_.bƒ_ j|?#“E×™éúr¶ks ³ß_Àï©¼Ëæ:Ø@Ï’i°"Ä7rE5¼!ÏhÆê《«àÂiá¹õôy|2ë¨çp¹{8}h)d-‡ók”Æ×&äk±�ÎââaŽ}¦ûØíû:ôÜO Ò ŠŽ–si‰óh™âÆçu|“ô(Ø›z—û6RåÕ¾Viél|Ýi¼pÄ›úħ@ì:Iž{œêÎu‚c~+žXÄÎ ‰Ó¿#™xj@ÔÎxõh,Ï�§ÃQŒu_놢º2v|þ^.±Ë&šÛᨬ#lçf]vá|[vÁ›?QáËi=td;¯J¦:khÄ/^˜vo'Ãþ® w{Êíúo!Ø®‡+Ï"4ÞžHžãÙÆ²¹8JE†â³êÙâ¼à, XöA•~‰o­ëÕd;ºf–¸).¼Ïì[m™eÐ2*œâI~è¡]µ!-çrÀ»é1»rU™ì"ΡÁ¬dNÏu¾eêoÎÁl mÇš¼l™ûy'S1Ê'^G!™9üQí1Ì|­8¤åKÃé»7 :W�?_ò„•–ýef?Mùc¡¼ËØËø:ÊW •£ÐÇ(.ø•9¬±À1�/xç,.l°C$Š ð•4Ó±»†³c©âñ¿sΰè¥iÌÍàß–W3“® ŠlðeÏ[qß#Cf½?€Þr *RPå±>Ký²�ýp2`\ó z­Ò!òÜœ�²4ýà1>ÑÍ÷ÌÐLJ™Å� )6ª’öžæÝÞkY¿ > xØÂ¦®$ëñR´4Ö”5ìªÄ'k唂ñðÓDú7K „÷èÃ1¿PîcÙ6˜pì)ú\-ÝË#|õf!ë“Ó™p4šz:ìi¾}»ù:—Bs\AþâÈ ó‡ûkê¸Í%êx—Â�l ÍxÊŽ†<Å_C'Ù‘¨R<".ƒ6zR´(ø>ÈfÖá}—ïÌfØ—š¬dÕ¿Ýà¢qù¸�¨ìø1&½q³Té‰c6Zv�¢ íëЦÃá¿À×lñÄc OáÃKsØýëŽ: &3®òÑO¬øÏÃ3è¨Ä3ê,�ù/½Hûr9ù¬5ÂÆâu¨l @] !ý¸ËËùÈ¿ÿ©JJûqòGôXV€6¢AøO2‡šî{²Ñ'(¦ã“ΚN ’Ös*åMlÅï.Vì£G)’{HÎÀêÕæÂ×%xâ šÖxÕý5ÓJc53ù#C¦ô¦Cn”ä�¯÷¶ëï¸Ú‘|¥Þ]ÛHkF#ïðR†V8/dG’˜´÷¼š÷OrplÅ42 X†BWÝ-#]\@ä¸3>ÜAÎóÊ)vÿ)LÞŽ�o<)ÚÎŒr:Á?f&ýeËbTVqÏfoÂàín$T»€ÌŒLÙ»LÉ{Y _?Ç%W€[ƒí¯Œ�•ýø¸¢‰=eO9Éúgliÿe&§>нÞ�ŽYŸÅ ÎnF¿2ìŠZj�p¡<=�3‡n�5¤Ñ*.l�ðEvîå\òzìO>ó„`~öyˆŒ¾L  à?í ´òK/EP>³¦æ–qKŸO€ó/õ)áà k’OÆ ïUtâÙþÚ·cÌ<Ð�‹8'Íë€PÁÎGÃ-#¸€kð�¤'üλ@EIæ–Yoþ"|]OÙì;ÿÅ&Ž —>gz­[@ûH µ¿äS;+pï7&®{ ýôʃõ×FîÅÓ±¼ÙŸTž=›õ]*ÃÓQ+YzfL1t§»?ð}8� '°Âs­¨¼-™ûœªG­5 Ç�Ô)ðz¯R€ø‡W!-`)-Ò6�í�l æC´È8œÜkÊžN ƒ_]kÀûC8ɤYÑÂ5‹¹Ú§F�*•Ëýœ‚ Sgâ,]c8ZiÎÙáz' .šÎ_XÓŠŸUÊ,Žx@ži»Ü�ÂfÚvUÕ M¥A‡n¾ãV?î” vm©ùó°ýðvÚ/ÏÌÂÔIÿµ&Æß6¡öá1ðå«ëw�¥ÇKI¹:‚o“„û\Ø4kIV�ÊF¯0�l™…è#-[o7’Æ9ðß÷ú3qäƒ×éLZ2×gî7g�îˆ3þŒ¼�ÝÌ, (uÓÈs¡�f]�j`Á^>½ÌÕ�õðEuõnÃÀzxÎ]æÖyWÂõæ9,ÃݫʔÉ+%• ï$½?ÃÆ®?ŽÇ *q«~=ƒ& ö÷™¶-´{ý5þOEÕì&õ®™P–£JWGGÂDAÐ=ùf¤ÎŽ ,Ìm3¹aéµ]ìß�†°Dß:6K@;dÀ/¨ fN�Ù™1*”yÂöظӖW©xýµ­Š^ùõì¹Înë²Avr·0®ã^àÚxaÈù2›DO ÕF×N¡ÊE%®-¥{5c(yAÎ�uÇ9å1ôd/?嵴܇( ¬1ŽÊÂ÷Bè¾4tŒ‘iW%˜³U’<œàžR+zÝÎͼ÷ÏÍ*ĪòC¤r!…©‰ÃŸñ]Xª6 ³ëÖchá,¸™ƒa›Ï³Ïb¹ü�ÈË௟K-‡_qUâX㜹4JÜ�[hQ…£žŒãW�ÞlžB�ÇrÈÞsËu4©/Ä‘ ‰&1}¯“ìèòû˜wj õ¤ð#Ü]‡wŸ¾Àx‘ ¶ò¸ÙÌßÈôÜ}P]ëZÍÔ<5±Š`n.˜½û.sôV† S¬ ›PêÎ\B8·Ra«_Å(¦TæE2ÉÛªÐkf^gg’]�YwˆQƒî,È3ùÎ|"ŸÀÆùó ôäEEv¯v„SÇéz�Þ³À¢¯·Y݆˜dÃBx½Ó�OkÁ‡Ÿ §tß\ö¢i68Ý=b/ëÑ®·„íNéä×F„—c"°Jk˜¦ÇÓ‚ E ”•DCg'qÓÖ�¦3‚Aœ²½¬ÝLh¾¯Œ H•p ôØ®ëž}E™À4ç}¿SK^ü�bËçüàžÙï#è÷™œG˜3'†Õ>glýœyÙmâZQ%u*\íó‚©ßRØœƒgq¨ÜŸº“ž3yKc{¢Q`º-T¿ÚN®1QÃD o];Ïé|¬‚™+2YUl[¾Ý®(O¤%†ìRQÛ¥  ­¡nlº_l)¹Åëúë“‚‘ mû# …Ò ÕÎ…N Í)pW }‘Ì¥ù‚F\n8ù«QÊ^Y¨Y± –ùl¦6u1€¹cAj�¾;`gLN0¶)“²\Ú`ÜáGøÍ?&~bZOîr­¢ilý¿&–üë1ÞëT†2xÅÞkœ€v5 Èù>„[F�"«@ïçõ¢oûXÌý @# ”|÷�„S4¸õEуS–x¿^•’^p$‘›ŒË3ÔYÃÕ"šü®‡­)(¤µvþ|K‡Ù§ÎBçëbÐf“A›¦�àü`º³6Ò¾òÖÿeÂ7¥§ì@”'Ó“ñ`%�Ø'��hÑÆ~Ö"—U:à>¥=»Ïrc2ƒ½ý8cœMêžÌ\•ÃûÇÉ"~2´ÌLbîâ¹ìàñlžÆ?cÑ'Ïà¾ëC|·´Åm<ŽÅÙÉäw€X†Â7è�‘þ/Sh¿¨5þz€ø(æ>K�}ÆWzV°]–¿^ç1«é³øñ‰ž4F$…Ìüw-*ÆÒÆp7°‡ÓÉSB£ÕÕ,2X�Â>OÉÖqÔyEjƒä˜Û‰š54&e¥À;%è)<Â)M›— dܵ�ví£NÍ|È�ÁÌ1fÔE+¨ô€:†O†Ùéy¤~®‹»±‚Øá’sì‚ôO¸k¨<ò4K¾mO5m¡S"�F¯€m�ñ¨¤Öˆ‹´»ø¶¿cèRË'šðÂbBÐ8ª—ÕZþ‡é¯µ ¯Ä‘=’SD–狳¾±Ì÷‚üâ/ƒ_�Šþ6Wñ˜I hJ]bŸÇí¥à–\yà O¤ŠÀ.{AjXó–Ûûf:NÜe‰['‘¶Ô:Ü\e²¢d”�ûuK2™³š œiúÁ„^'RXÉ5t4UØËúâ+¨\ÕîµwG¼:;`ˆ^Aó°'ð"¾]TÅNö•QŸ°í?5šl¾3\ò`#n{½i\E»A–9O�Jµ`T (¥˜Ìu›‘ú}þÒ¶ lû,‚5Ïâ#*Ä]í˜pÙŽf?‘†ÙRµLHX ¦;Ðâ•‹Xî•J¦9ÞžëcåÉÑt ¤�)\ÆrÞ´á_<Ë{äÉ”Š~³¯Ùã:~ýƶ8—4K«ûæÃÃ㟹§»ù|Þ ¶Þá?÷>¥ÞÙÁ¤»1Ô‹RÈ¢ž?§eñ~z!{Ëà§¿),1'�•ObÈ»›�#ü�˜8ŽÔÕá÷ŒuèfÃÑ®›ì×î…à42�¿ÜÃÍ£Ñ/ý&_ñ`˜OnØHïCû1íY­Ùì×.1{Q9Z¬VŨOÿ0N—˜avã&¥û#2zqæLiG7·XËõ5V…±JLþ‰I.Ow,ç&mÒgÇŽ’‚ÙfX¯û ;ëY]úª×É@Ÿõtø§iu˲ɔ.8–rG[‚ßÍKø°-^uõÂïw›ÑÜ_ ä) Y‰¶šÁvm¹‘ °@:û…\3—ñ?_*ÃþE§yõõÑx®¥÷Ï Î?Æ!êIó�íûÙ¶ÙŸXÍÆ§ìÙ¶«üôoÙÖy‹IÂÓ‚¿½Âò€D®²7$iúc–Ìן!®Ì ?äõáEÛ«ìøiIÈKn_ <ù8…¶ç áð€$õg¯ÇÑVK(.u˜}]0Ì‚aqXž+ƒÜsNÆK’ª±àÒfˆßZEK~Ü„†³ûqOË86;ìi¤ìÅ« : 'шCÙ;áγY?¿—MŸØ % ¡C;›}=; î<<‡2Øëëµ(õP ]7xÂ:ã/f¡æw™ClݺÀnoŒ‡�úwÿMÞ3•f^nç>{'ãýƒ~й$—/Cñ)Æ©ú�KVÕÙAOj¹Í°¡- ÃEÇÂ!Ñ…Töî óÓ+ÅbûÛÌ?ãËL,@ær€›‘HÊ%~Âî,¸¿ãª?Ò¢Ÿ/¶‘ÞÝŸ­Ä�_®œHg3ºHi±ù¨m?U“½@¨)œÚ­ѪO«ÀØ1Š5Œ³rÍŒƒÌ#a¨nt‚²€Tæ%eˆû&»`{c&•ÖŽ¡»JfìGœ ªm»ÎÔ¶~gŽi(~ï<QÐ…�®L{ËZjí-‡Ú»’,G2Æöö ógk’G|^ágÈ�ÚP~ n瞺ó£ƒiýì“ ûà^îŒ�ß}ì9nâĬÞ^2„0ãjv{ÔJP±¹†Í î53ê�Núu\nvŠÙ(w2ó–x¼¶…m³— Mïr7 òqÈC€î]5&_á!RØ8�œGIr5ùbPÍï�€Û½,Xæ0Ä­®@kÑaX·ê ¤‹M€õµo`�˾³`�9lžEzËráÇBcRp[š¥ïÑpº„˜ûáu×}xR~.ÜaFFÌ?Í›Ï;«M˜E†c“1Äi[Þ5¦ª*QÌ ÖüÉEûÆ@ŠÉ8®4&ŽâF�ºÕo6ëb"CQÍWM¤’ÇÈyÚRÞyå ÈØ Æn­d1ÏëApÒvjùYdK°Rƒ‹¬ªûmÚZˆêùÄM–³² Чá.c¢îPöYë_ø2™™ÞyÎM—ß^“¨xÍ„‹Qô[$]×› _„÷Q”HŠTQÛ×ÑEû{w |�ûQó—yt¹æ ÓZ°Ü;�@iÅF6/ÅI¨°ùênL´ß‘ìµ}HÂ?7” ¹º!5+—|äëšc…ç:K®`^+EhL»ÅÖdö}`5ÕÍœÒ2OŒu˜‡ro7ò-Nðóx3.¹RßµÈä‚(¥&Ú?±¾÷¯Ù¸©\Àåùhú§ƒ62�Ñ@¦¼¨A¥‘ýéq`1ûþç mþ¯�„ùo Øô>Sسt lwªª9¶ãXì4š®/æ¯êÆ)«ò¹™Ï1Lχ5’¸3‹PÏROêÚÓù•ÏHÂ.­ÆÆ,ƒí„ÆÅSᆆmÒëÀ„ª`ZmtåeÁ¬qš|+“3ø\ÈLåE0`â r\XIŠâV­Wi‚‘à.ÈÕ\=:†bƒ¡÷´ûm1ž®?ÉGNšA™–Pkÿú¢- WY©ò7fmùˆýî/¢Ï“¯Cïy(°»Î6öÎ�žÒv:T‹lf‰³k‹Ô@]i2õ¦ˆB¼ñY¨Z¿Œ¶y‘ªðtT–¤+~;`ßî0,t ­Ê• w¾«åV{þ�ß~fÍ\Â7a®�-(.èÆtÑ$ж¢â¥{°ÈËž· ˜M푈/^ñ°¤u2ÜSœÌV+€ˆ`¾Ÿ>;’T[“ jM™IkÞŠ×㟤¿¬1΄ÉÝ­æŽ/ˆÅ>}RL`¥�ßX.¼f·,Â9Jkñ›•L?ËšªY�³3Ƭ\E›.02¡Ã_^ãƒÑËp`â~6ϲ�™¡´¤vD!9¾ÉôïÒÇÁA6Ñ{Ö.ö€iGgAñ÷@8›˜Ë™t ÆŸÑ8]á#›°i�Ê}Ïv­½Á¼Š…!yô‰Dû¶|Ì0Gíþ5øoØš¤Ä6a›º-¸IÇçó‚íü¼†Œd’A»*•ò’`V¯üʽ„{ÓäÁiŸ&xpG2ê0M~1^O6§Ã†’@™c¡J­œ¥^Ok>Æ3‹x#~ZKZnI5sgã<¤G7ÂÈ-‡õ(MÒ� /›A·Žk³ÎèETv1Ù­®d!9¹°;{+è 2�¤ø+Øe}øÚƒWsñÞòD:>£•©îŠ¢ËSC¨.yˆßÉDã+¾Ü÷§ûéÞÊl~rvæÚBÖ ]n£í–%—ÆZŸ%“”̘ڿçqíŠù4¥º ge}Á±§¢Hfg>$Ç»ÒY³Z–ø<?Z¦±wÅAÄD�Üt“`ùªš£‡.ަQÍ� ‘{:gêÁÃÏì„SËOŽ„Hç>ÆÅ&ÇW’ ^b1æ[.ž<éëäªáóùàš«Züú‰2|ÿ–ÖT§ òJ;Ø•}oðyy,½îk1*\Þª|�5ü=ÝÈS°'×z RæD7}}YyÎÚßrÿ¸Á¦jé’TÈ}ŒÊdOŒN�ëå�¸zu Ÿl¨F~‹op[l„N,eP‡?4þûl¹¬¶Q€ìG®,@¤nlƒ{®‘üá2’ø'ËÝð a6[äiVÃú÷o(ÛAQ:€ é ê˜ôÅ¢¨Êêžµ Žõ=V”„Ö¿µª¿¯&ÕâxóPK1QvðÔX¸r}±�XHòtdï$B@ö¤_–; ,f»€ÔŽÍèà®Ç,ÓS!s…ýîÖO !¯ h÷h7~,ám#·q%GR�ÖjóM ¾"ØÆ©váÊ9nK~.ž©dótàÒÎMl¦Þ¸ò-”G?a®"tåú>[0œl{@·p<üÇç\¶†=]XªZeivçÝ4A[¯.nÑÍÛ5ï-£šIp°U¼Û*¸Ÿ\,RþÖÑðŠG8Õç®ÏÊQu�TU§Â¿Sîlqr$>œôŽ/¿ÙÅ…¼bv±¿ð´œ½�Ø ¶þdï¶Âz—OléÚNvmB SÓÒ#ß?Øß¦4¯Ò�VÙ€b¶)*u¥‡ãiÂÄý4©` åm×`»f6áfãÔ½ ™ý�Bópäúëâ¸Uv*«Ae«4ŒŸ{¾ˆ_KTEQR¡¡¥R‰ì‘™™MÙ"›Ï=_#BRI)IK{ Tz<Â=÷œ÷}½î½Î)ytó8‡XþÿÛ%�~­¨§ºüêðÚ«”µª€›êw::çüY`OþÛiÊv¤µÑª�§hR§Ú¿�4ô}‡Uîû!PåËwŸ$\Ž rZ‡ñÞnO\;#ŽMÊv‡v °~s˜|±/e>'}%+‚p™è2rzp!êë™e»á}&—¬Pê¡·~�µ;·àÖà|<2ÅÑËO\¥“ÊÏ çÏm*¸8ˆpዟ '2¼¨ò AÛÎ!›Ò 17{7%…Cd•Û ôlű <*«ŒzÏw kH¸¡‹I &ÌM#Ç…›èU=,o +³ô0d©(÷ÜnﬠBæ�l°ÉUKÚŠU¥(ÀãæÉû${üôë‡àþ–d*¿ð'�«ÃYý#ýbj(,“ÃZÞ#]\qjù<†X~äÇ�ùàö` ¤ìa*ó�ñr¢{�àx�+Óû”ƒ›ò5ðŸq¾æN#sî2JÇnP'þœ«WK¼Þ5ãäÖ‡ä½Ç0©;}ŒtnϬ›ó:�Vç‚Ø[_ÖZ¾eÊù_Ђ†Wtµ�2™ÿÙ?mh¥ÃyÆŒäï!¶[Ô‰>¸{WµÃ<þþ£AI{àà)–m¿FŸÊiã_Š—ßkRiÙJ«ºpc»-4Ï“†ÖÏÕ$\b%9Û*J½>!;$îàSŸ�mè®[óìae‡<þÖcɹñµ¸Mb;Qr¶ —f¹Ñ_Ãhy¬XB³—›ÁáÑC´ÞðÅ—$ùF öÿLýy-ˆCØšTžG¶ß 51ñHµþŽmkL øŽ4Ôfnd¿õ¶À®n$u�ônM{¼g3N\^´%€u „„Õ—Ø�¯‚´ñ×Z¯ý£ôϽtݶéøëº *’bÊ7bƒÊRupüùZœ;r�]Þ?‡ü½ã†¡Ž®¬zùvJvyÃÚ6)|8�… .þ8Zw¦NîJ#˜ß8@:₱ᤠìÊ™�›+cáG^fµÁcï¨ç‚e`֕϶$ÃZÛkÌŽYr3ú23Pü‘tHž Ç)6‹ó­xºÒó 1k¶0Ü=¨Œéϵ m”|1s*Gïîs§·›±2ãÉÒXLŸ¯4€�Ö½ÔöÞapÕ K†ýü•TëèIê$x�î|²‚|.#¥¼�`¶ß†f8ÆcÙx(õ½ýŒ.çªáòÆLô?M¹oà‹7üè­H'T†ê‚•œ€Ïˆ’•ÕB°=8˜õ_EG.„Áœ”×í:�±ó+ùVµ…¯ý‚ëSÜ=pœEƒ“ í_Å�]ßBÖ_:„®œÊßo¯Èâžt2!„ün.`¼�#¨èà\ª©¾¶ŠÎnÒ'Ž—™óÿàÏG ”âƒÁ²5 ;ÀÂ|Ù§dñ²d¨@‰q´– Ãlb}nØú­¥îÓZÉ•™ÏHþÓK¥o‚n¬mÛ,§WÙÁñeÏÉ‚£z°Ü͉ÈÙq€ý$�üqäî’/$ðµ=ð;'AY\Îð½Æ(F+Ð{C3ÉÈêڼȕ·?"ÅZjtEÁUèpÅ}ÑÏèŒí±ä¾WÃ?éŒÖŸ«)�h`ßXê“û/NAÀ 3�hdÿs*#vö3(ŽP�ºY¬r \)��õ¯p¥™l]{˜®Sí˜Ê£*¢IšØ§Usˆéß;ô´ôr.1ï1[Èú5.ðcËq¬ìd²/`åÌ ÖúžðT-"6â*èÕ§ O.(@´†�1û6éxl† £»êrß&CqCJ¶]‚¯“ÍOù~Gjº§š;¦Ö­¢-ó«iEÑ*x÷;·'«ÃÈ¡½ ¯bJëôiÎ{3Œiï ·~óÀ½^Œm‰"ë%7Ù÷Gà|òHU£¥ûÞÒ?gýˆÚ.m¶d¥â­FÏn3ùQ- f. ô.šM¢þ<5”Í›K%\ß3k;ײ6ŠkðÍÀUøuÊë~Õ2#;_å“â°Ç´�nŽØM?� §£Ëâ¡Ú"Œ¬îùK2R‰q°"><(�ßCaª jý¾ËïO"k¨‰S0³Sh·¡Dºþl!ú;A˽þ¾ £‚žýgAOÞ;N·g‰¢ƒ“jHC"§>§T!ø”J› Üˆ0ÛÒ$ç¯%Ê< 0½™Ô„6cI¼4WãõrN‰’†’ü`ÔE’ÇäêÌWè³™g~b r=ô•†à)Ñ=xª¯7?Q†î–Xôh:ÍÊÙÏ¡áotèškÝä‹ó°Ý@�Ø—¿¤®ºµD¿ÎÂW_ÄÀ½Ž`ºÍ—×;SÌ}ÈÞùíŽo©�¶übí{M‹âòȼcödKüTEe’ŒØü!¯þÌ…ç§/×íû�÷—ËáÎ:ôø©e§ø˜ÝAJ ÌÛ x¦zìIÊɶ[�¼‹)Ë·W BL¬ A] u#³Àâôú¡&l2-ð˜Dí¶5«Áolj}NÝ¿´»äªøvúÙ¡ '•š@Á¼Ž‹ÐóJ‚uÉv�¨ó�*Ãçz¯ÛxQNÉðÓa†V$bä¼ú÷ÓšÇ܇UF«`O¼ˆxä¡pM 947†)\ž‰Û¸tƒÔ>Òm]ŠWu¡Ó¢WìÃÏÏHv¼ žé—ƒ³ßæÃ–97éº.?ð>•B-T2�UÕÓÇà¿�"dö§zyRƪ�u¶m¯èÐu¡þ–tý{e¼®”÷ $U¥éÍiÕ0jv›,P½Mvç Ã;»óµÄ¥· Ú0tÊß3­Î¶ e#††÷¨ñ/„µpæü(³3H Ôa—í+ösøsÆéùUˆšî }×)ïæpÖŠ×^›`üxÛð“½�³èã˜i¸¡æúšºÄà@Z¤\MRBmˆKŽ;¼M•„l˜¹¿§cnd=Iõ;L“bV¡ŽMOÍQ¸ÈSºâ±ó¿ƾCŸøƒGÜj4zv… èZÖÍè–‚sb›È¶Åo¨êý0°�ŸŠ[ÖøÃ¼}�tݾhöiB-î}�n¯F²t†|ÐÄ[©‡ÀôÝ”šó¡FÊÀ�Ã7PE¶º$uË ôûsÐøš1ŤÕÌå-:pÛ}!œ˜ó’ì�9<·ºâ5:uÆs e—VDÿ#7N^‡9yè*¬!í ¨çÃÙÄ.øõ<m�÷B»Vzâ U~•A‹\pï¨èðÏ忨¡ˆf/�¬­'öî^ðcI Q· �‰; ÓÇò–yØb{ ×É�Ÿ²(²à  ›S,h¾Œúÿ; vx¡ÄØ3:B”èéJk,7ÿÀØô�dm—¥þ+#yœ m® b9w°“µ³¤Æ¢iĶ¿ÌÒ™�5]¬“™F'byB"íZø¶ž$£ilÝô%þ°§á7{çˆ+u°¼ŒÖéè³Pg.dðÿÏ×sGÉ„„'6sJðcš84'f¡`± gî÷!2†J PiÖæ®¼#‹Ùø8›cPäÊt• ¤s†Ç‰§g2,:¯ExÓRÑÈÕÔ®ƒöÊÛ¤çÅ:n›�®¡Q$Aé9>0âÀü¬+¨ÈÔ‚ŽávÌÜþ›9d µY‡0>;Õ .ÐKpÔAë^Þ¢E3–Dãº5Ëà�°Ÿ¡Ð— øOó;Y*‘O£çÇãåQ¼Ö]GØ(xL8 EÌ •ú_·Å�¾yÈQ¯'¼Ýð¹¥”ð9þ$÷^ÒÕâ–h”ö‡.­ IŠ Tú‘/ ௡®=ñŠ"œXP‹b* Õü65“3‰Ý¬\".œõkȶJìw$ ú{�o–>敇²ì<`ÎøAÿ­ÔYNwßKD£=ÔÒi¢«x³ öE mz§ú×óšTÒ£ê„iOýëTÌÜÉޟנ1<…üÕCÉNIúFŽt�†RCÁÌÞÓ!d‘º;Éš…,S-R‘¸J×Ñ›ô*YÒÔVóÞa ´\]I·¿vÆuj=L¦œ-N—"Gogë´Ù™J©œîYr­ö*¨o‚˱×áÅÃ÷¶þ˜õÅû!ùΧBÀú&†g¶ xT°¾º£d“‡'<_Šç_eÒû6feè!<)º›:ÆÁë]‰]w&YàíOï±óàTp.\˜r9»K8òæ8®û|ß.äg­]â:Ek>U�½ÿbÁ,E‰ò¹ZQíЕD¶k5ì/õE÷ ý½ —)3¼�+î pgnL$ÁGizÄ_fÑ¿ŒµØ&È™Á@7–éaAÏ�B÷ÕZ=í>¹Ï�‡†hóó êW“N>*phÎHÝÀý+Ôvõ&µ22WßCp‚I4a@*%ˆ,Û¢`ðåI=;  ŸÁ,gØñ» »ê„!È–C{™ò3žè4Cgú—Aõˆ)DnEÃgKÁÒ! Gï!ÏFKˆi—ÁLc4ÙA߯“ÄSh²— �¿~ª$�2ïµÈº[ÍààL¡ˆÇ”*~ËDÛÝë±E3bBA]ÓŸÕ×–á^zÕKA~+è3z;>°*�øàà] 2wíY4lÂ3û/€wœV߉LY¬Î‘mß·ÄÖZusxhó :3¥Ú§�ÑPBºK† ~†#y&*‰#!Öp®)w[§ÑF5ضd÷dm3±ù›ŒLÞLPß°®Žß'¹�Ó‘ù™A nN£kû|ÀÛ¤žFÛ(áM‡’³(ÕŽMÃ>Ú�Êß²·f rÔ<¾Cþ#ìÏ›çqÐz.>eàñæ|ºúÆ8ܬ6Žâ{$Öè•#q³ÆþåÃì°¹‰Qm"×N¶@ŠÓ-òÛ>‘ššI•…ýLÖF–f_¬ƒÔ¦ÍTìIÞ6‘¢•7ùiv¥6 »9uf”ü¦êyrܲ ›!ü¡É„RÉë<¸è´ÝÐl‹•. Qu1hrüI„ëAäLÈAzu9Ë!rCÑ8”eG¶:¥P¯;S.pìö´…°}ÅèçK `q—’#lP}ÞnMò3ÃbŒI´›ý õ´®ò9}ß¹a*ߥQª^ÞÎþÎüük…šøqöKX ‡àæƒQíqÒR�jžËcïðêÃþpb-ÿ�TN¢_�¼yò™•Z¢ ó³ðbª>áÝp +ctQ[É™.{,KןTÀ˜z˜ïÖMÛ$¤!À»‘Í­ÊÀ”]…ðƒs�ª×)#õ‘BÛ‹—¨ëé²s<3W†aoßK2¼gí¡'0÷Æ &~×Nšu¬¹û×a݆BüÝdŠW­I_N9)®Õ&W¶þ&ÓyáÃæyØTÒ ˜&‡RRïðù¸3Bd;¾¸¢KžšMÃ4Îrj lL¤ÖC²Ùc²î‰ViøDÏÙh6l[BàëýÝh|ÔŸ+ß";„8ÃÖóË ?o€g÷ƒQ K�éÏyEx¹‚§&‚Ó¥`žl<îx# qóòˆde?[êfhú^ 2²tqré-x}л{fÕ¹×ÑÔBC´w‚ÅZ Fw÷}†g�9:¾åâ—ÚºæµÝP*H‚t ¶d–øX’ñù>dÅæÚhUŒâópúåf”c숧@ìÖÕÁQ üñÕ>ñs•"R`¸CŒîíõR7Pª÷3œïŒæ}ŸQh>ty¯µÛäªûgFçÌv ±¯µ£1«ä–á2;oæÌû|4L«>i1ÏÝÉÜ,k¨¼w�®- oí}qbr-èþ5"k¾ß‚£*¶‘?C‹aægP)u�Äë–Qs_7êÐìÂ^Óœ ê·bà«ÇSz¬a&`%Ü~°>Ͼ�^ZõÔ�ÇͤÓhªK§mÁ•ÂS9umI]2óÒˆ�­¨úÎO‰`¢i¦µ«bñçðVKd´æ½«L(�ß É"ah}Ð‰Q ø6¢E„>“Q·ÈÀj`o‡Ì?è®Ò{dV¸&i'†ç×AÅ×a|Õf¹Çóàò=üŠé†º4Û0ŠýLÿœH“¿¾T¨`ʉ·€Â’nÐH¬€½QcDôP*l\Ù.�ñÖŸ­ômu/Ê¿jÃmgÑÛ‹ÑébÓàÁSZ�aì}3=)˜Mëe�¥_k¨ö–­@ZEp×W9üšÔ‡qMø ¥#cÜa¼‘ën¸Zþ jA‹IÇ¿9x $l†[ÉÅÔ "Ö³ªOGÿY+Z=Ôu~!ù‘„¯^·˜�~ŠjÈ™Ààž:v ž‘Xá·loŒ ®¹¤LªB9Ä8ÝTž%/RÓðÇÀ]øQSÊrxž#>_ùW¹ÖŤoéè»ÄZ ±»øV’ í¯©ëN½Ü¯B ÎTl‚øÃ‘ÌZ�M¸¤Q oü�£ÕƒtÓêpj§éJmISK0ÜœL0ôе@žk ámdðͶwkv©'0üÍVÒ�f.°o‡*³½, ü~ìƒŸÜ œðpãßK …ìÂPN!4HÞ"%+q>}ч þ ¸z7†¬t!’×iíä’躗,Z&ÇÆ”Kq“lsp0õ6ãøÉKfó ûÙ)N»ó�nPh“αu ½Qäö'EpÞë#“@ÄS=WÞ!’O±9¹°å?s¨kHwù "ômB°¤Ã¯å@°é*ÍÎSÄw+–@ƒ¾?4[ˆÂÉ»ò(alæ}m¸;Ƈj7Äc„Ó bÔã÷Þ‹bóž~jŸ3 ïÍ"m hb¤îÑ?…Á_{hŸH(¢ïÔ�0³ØÒ½ÆâF�Hnv Q¸?8«?�·z¨è›zbµ¥—LÆ€ÌV|šµŒ?ÖÒ¡ëD=æ*^{ÕJ<9ÊžüB%b…@ úàcêò½-•:Œÿ¶—±ì… n·ƒUÅ?±ÝC }µÃåtIXm®‹´ÜqÔ+ ,„cÕAxoâY=…Oëô�ÍâÞJ)Û™…€)OéH¦ í•‘#¾é³àçö™X��ŒGÕ  Ï§˜×Hù­½ÁUâùàíFøÎÿAPˆž‡î ÁSì0 ^û£R¼~L*k…NÙÃx2ð5¼Ž;ŠÇ6’ä…‚õ] ½íÄ”þÓ¸åT2³0¥ê¼›è¢€*Û¢E¾v>¡ço‚ªs™¨j𽕍vR­®î0�7­ø½(˜,üKÝ,%oG'Èý0lmÌ ò³èÃ3ÌÙÖi¨`?•t5Ê8½²ù½Tˆ7šìH+ÆœÈzØWò#wt’&~5¸÷CžÜ_ú…9î« Æ ÎðϨÑp!TÐn%qº¡2 >¹†A¼ó*<%z•v쿊“jíDr>úÑÙè¸ý�ii{F2*®Ð”<1t/ŸÆ•‰Ô£1J‹ðåù(œaš@pž åi!ñÕÿhU©0w,e;¨®‡œÄ[_j¸¼DmDg¦'¾?Åuiä�ëC¬VSB3åxP?W_SË=H½‚à°K&ü͈gŽL"];à¡ð8ùÕ5�v¿M„ 1 À¶oÊÒ‚ðy1Û|(¢*º0ýò0sòÒa\RNi�‘;y¶`ªJS<»²‚n $× p�‰± ¤Н—×þ5äô‰ÄCkãy*à7ˆ_u�À¬­‹|ÍÚAC³’IÁ³�ŒéÝã�ÛŸJ”{‘„´l2Má+Ðí… ï°¡Æ@íÒ vþûæ�Œ1£YðcQ^ö-]®iŒ½QKi©q ̯§¡òèÛ‘ÂÎv ùAx$Îx´2 Ç&¾ŽÄ‚nŽw�éz5ì:FŠ:‚I† Ä�Ì„ ò™Db,»®ì�õßô™ÔbŒí’Å—�ˆ‡|' RD· Ì�<¾ÛBUöàé¹á¤kL7kÀ/õµäç÷»ä­#w‚²HÊ­tL±�í*KqVn>(n«¢Q/âÉ—–½ÚC›®riF« ^_-Š.8ŠªácÇS&`…:\-ºF¾W Ó¼ñ„½ø�^4„g.“Ôùâ Ú—}Œ®‰`‚(Ñ—þ¼3º-ÄSñT4)ûDbŸÏ…É£¸ãG0�ˆ¼‚s‡CÎG–ß”ŒÉ�y¹³NµCËFWj ¦ T™h�²£¡Ò²è]ÙKòŠ`Îñ�X%>Õ7ËαeŸ´égù" O*ÈoÃt:ºmVZl¥ñoN0‚NítGÎL¢AÌ‚Ò1߯¬î¿ûCÌþáÖë]A­ °}÷^Z½Ôàví8¶ñìþ²ÖðÊ5OÒ"c€Ž¶AŒÕ9Üôò„Ì׋.ÿä‰ÖÝå´çë>Ülôœ„kÿ|Ð{Ã-Rd—óãU@Uf’Ê êÏý‰�s4y'NÿŒvÞ#¦0‘µ+¡OÃûo•áÌimø�¹Ž¥\Ÿ¡Çx¸{^;Ù stoQG èÈ>�&ýjh£*Ž2E…hÊ÷›Æk÷JÑd… h?âB!Õœx�ÙFWÑ Ë8gîsZ·1’©_FøÞ_fÉ0‘¾r•êÌ»iÍV+©‚)…ª3ˆRìœÿB‹}™$‰ÙÙWpeÈNzøŸ ~ùr ?¿ã'Y„ã4ƒó 5 %Fʈۯ Œ„Ãc&ÆÌì5~£ãh>/4Ç9e—@íü)°÷Ú†~¿˜ë«ÐKê h/ ­‚ÁøÝ¤”<ï§e"š�Õð“nX/Çq*µçÛ‹ÙÝË/cÂ_¶šˆ«uõ_ †�loÀŒmà'·"}`ýi´`¸âÍ|œVCø»÷9Üg­ÔyH‡}<®ÊBÉ>¢¿9�î¸døÈíáÆHšMÄ—oG�ª}Pbð �E©èøì #tWÂP�jòrÕU°‹ó¢pñ·Ë¸×�BÊŽ$Ll—Å¿’iiyÉIt¢BV±Ìgç5t¼d6¶£4ž×„·¿PigM¼ƒÞ1&¯4ð­±?ù6óÑm µÅWé•kWpï~1l˜¦¶ZÙX% @’ŒîAÀÎxüóp«·k“1îª68×V¶•$1W$Ðè�Œ mÄ£V°¹å‘°Bü2×�›[0ßMùËCyœÀë´z#‡üAuºÌyªÀüú‘ çnë@iÎ%*™PÏóg³-<Þ88�"p–íq,©�ÆA¥k$ô­8WûRYºó#Ù×ùË®®Åí¡Ï¨‚S51œáÄÌ¥‡¿¨á¿ídºóNø’­MFLÄX» öÞæétHþ ‘¯B»¹|¤2>®GžÇ÷ñ*„ÙúšÞ“žQùäÍ‘0)gsßâ¬Fi½±Ù¼Ü¼g§aZT9£OB¬¶Bå¶äó™}x¤7„1ñ9m¸ú ?g©É8FÏÞH…'d8 GæãîyMD¯ú�;¯É½¨|ÖÖõ°qÑêð1Ò Ÿ=ÀnÜíÎØŠ¥’ Ýøº8íŸZ`Ô¹|ü¶)ã–IqÒO ó]|ç`0ƒ—»ú‹|×î!9˜º‹o �y0íoºê�Êä*š¡GÖKæØÓ[D«Bv?± Â숤-'ÇHæ4KôQŸ†Ë„>BvÞcÃ]‰›;�w�/=RîQ7qüm|øÑMäBÒžçbÈá,D±{g!P´,¹ x;½•Þ ^Ö›ÇI•V9ju}¥y&¶du+«¨8ˆ ¦wÇÂñEª<õ¾‹§4tؼáÒÿþ**¯ˆÅ†rñG½ZWMÙD`Ž¢Mêk¢î¦Mè[ŒKóűz¸ˆlŽ ‹I—ù~`Ý¢Õ³0T�âHô3éu™WD&ixîoIþï¤áì\c!I¢¤�qÌø*ûô€%_©®û´³®]H‡£ ô™åÅ—èÞ§\¼7=•f¼,Ã4ùåØªt“UXó¢&KÅJ{åÑZ½‚ôl"›ǘKŸR@ûÖIÔì¢ç"@ºv¨½H¡ãHYŽlrΠg.�†*©í$¶‚¶Ÿ�þ-™dŸ¨cf†î@å¢tù‹Ã(0Á2_16! ~í~Jû˜f XÁÞ•eän€hÝ+ˆ³L`Ãì+ô 8³GõÒ‰’k´äE(*ëÁÁåΤ2|ˆˆ�  Àê!´|ßIOGÈânÍ<³+Æ’º\Ìn÷€JˆÛ²Ò&Ûß(àfžIbfå�Þ)äÖëפæd zÿž1ݵNgÃÉÌ`êVíEœfáWy;HÜÒKÜ×ÓÎÎ øXZ™ ç ¥Â¦qR½yÏ•X5Ç^\õ�4/RåL^R‡E:Ðó!Ž{E5éÌ×bXù²™T;bâôN4�é77ÁÅu/©ží;´>ü¥s›eÉgýdšäGÉI8óõ7r4°˜èHG⯾fàx6zý³Æ%:ÿQi0…¦gT×Ò۵·$U¨va+œe¸žºí˜X9q­é|ð.„I©D<å\ŽB^pÈg„x½7ÅýaØ/‹à²Bgn^E?KŠMÕUˆS‘5 ¯¯ƒ—oGØ[wgWZ½–ÅwÎ�;ÏŒˆ½’¯“,‰§yÏß¡õ§^¶&¥½‚ÏÀ’ÿ‚qÍÕ9Xù`1ÎûK#f�Á-èVr Dž×áU'Ü–ç@öw¿ ã—pø×/zæß ®ÓýpÔQ{oÌncV¦7ô?/Ãk;ÕÀñì�á›äš½ws¹A3"Chí⛌P¨•\-Ž—­wa„º$zÝ^F4ó¨io=pý›qÈ*â+ï®´±Ÿ·ßFWÂË¢ãpØÁެlFŽ\úJ­­êà¬f \¹“~>ì Ϫà}�}$3JçNTP)ÅkäïœÜ‚Tâøúi�0òގñ‚«4XÜ�ð¯ Bå)§tì¨�‚Ü9ì1ÏR(_ÝGü¡ pç·Q!s–Ì>â Y²pùt,\Öÿ…ƒ ðM±w„áÌ8sXg¶¶ïõÄL«2àUK‚Ä�Gi²üFüàÖG,dÄÑ·ïInJ…ÕŸ$õÉRCo÷µ(Ÿý”ªÄvÑ�7Û°Óð~þRšã3ÅG°$פ·¯Á[»,AäK8¨Å_—Æd<´Î§ý\g¥Á ^À½û@Žx©BßD y)y—ŒÝ«�SWÏ^HÈ"Ù}¡às.›6Ü×­s9*CP³�n]Ü%Þ²Äâœæóß!ß÷ûâW¦…U68ˆÏ¥ÿ¿ïg¡º+„¬ß9¿ž†á¤»ÄùpPýÝÏlƒ=çãhýîþÚö¯­0÷ê%ØuàÃ,YŽ–O”ÉË�døÿ_ñ#Fð(à"¼îˤŒ`ÎÛ¸EK_׈áïî¼?LyÜ_ › ŒËÌBýCðØ5ÞÎoflêL‘½&O…×bøúy¸÷‰fü‘…ï<úxÎ?o”<âcõ�Á½FVC6þyOp'?‹V¯ ±G\öDé“3ý¿˜þ¾Œà"4Ál2‘¦ªBj¤1À{�³Éx_&ð^Ü QßMqÓi^àfÒN {\jþÇ:JéØÂ|Ü´»ŸœŸ_FÆwZãy«JvÇ¿òx§#¨î÷ ®þøc³(W¥èü ¨ÂºGÆ,8d¼ �|—Ò×5Ánãxy?y³¦Ý?UP­° §Ý`¶_÷íY«À¾o9jo< ûSF(ϱxC'«72Hª�Ð¥‚eX|æ&=´z?棖Ìw¼iê?¤¨Ãëv8ýÔ’~ߣMúÛÁ¯¤–ºöyᆃnøtŽÖ—ôAXy)9ý¦ž­®£T»�äŃgþ<%(…»Ô—‘ºrs:}È‚ïýB¶Í}ˆ7ºÓh‡ätu*£¶ïkÐFhêeÚ¢†n"Æ_$Â1K`gä%,|$K•�@²‡(›"” ì®Ohz�þÙñ‚ZçM´bŸw¶xná&ôÔ(&?–•§ÇæpÈò{??ÌðDý #u 6}bzÞîÇM!Y¤Ì¥}M²ijäòìT öæ“G3d©X« Øyâ¥`2.å‹uY%s’p° }‹ p—ø¥üf'ľÛùM$wέ ÊÇ/Ÿ¼qöôÝd ¶ß©%GÏtR•Ï.¶Éœ§ÇbâèZØù—ï褖BOë^¿À¿í™pòñºùé&¸Õ¼ $Ÿ7‚RW!*çñs÷•OÕÿƒ3¬Ÿ™…æ½6d�.‹« v“å9ZÄMQ™ãÃŶ¥+pÿ&Q° årÂÜÆ5á (ÖF“T¹‰ž…{-NûþG/®8Nš…Dg{$(%ŸÁ å”î­“æ\µÂ6tƒ´ÿÕ+=D[C®ùóitíe°[½�ýqàðeü¶þ í-…Õ�:éíJNgW<‹âpZ5¾ãk¥J‚œbûMXØV Å uÀéâXÕ¸NÙ4×]–ÖF ŸµøJ^G§üñëî-[îZÁ_DR0ˆDÛ–`P—Ȭá|æIÀó7›éÎX+¼;< ~×d'~¨pw ß$/\O£Ïœ:¼/=Jô4%9m‘PçøÆ5\ªmí ‡|×�ÛÃàýsьی{Î6“Uazœ«z÷g;£Ä“úÊßm ›ˆüʽDjfµØ+ùã'ɇ—!ðPTRùÒ±ûS ]wÖ�ë;Ã-êµñæKŠ“¿0â¥L¿±¿b»Œ7à­–gëáÆË»`•`9]7¯ÖíXk%ôpí˜VßžCmù!ZÒ÷]Ù4µF^kÈt‹s³5ÞãÁQÁ©YÿHï`ûûü*\¢B¿š­Æ Ae:Ív= óÍ“&éäéêûG ¾ ƒ¸}}àÙN$ì·âI¥ë0.ñ�:l’ÂÉZ¨ÿD…¢'èÝ3è¤ Áý¸�û¡¡,\7aû³.lõØB¥5öáæ]¿È/¿T\´ŠsáDxw\¤£y¡PB #ÉN@FàLHíE„„%ðsDÐðÜXCýëÆÐÌL€«çú…÷G`×õq":ps·Y‚O|¬—­î°»WqYWyC¼S%Œä/àª3S|=ƒY"=/ns‚dÎUÈZÒGº·\ÅÏ©«//1ήïúœÿf¹qßžª¤w>q1Þè4í�+JôìŸS��¤›×ª´ÐŠª`o¿ŒÜ6Òóã(�±™rÊíû1@}7Óù@€zÅoÁäü¤RÚ&åäÂ~¨šÆým; EAwãKàUJ~õæÃßI7Æe—")Ð]Œ¯¬7ÃÃךޭϵÓyŽÞÝ<ä­L'Xå†�˸h¤w y¶'17\g¢hqHº¤ÎÕù`…£è§þmœ³²#ÌöIŽ™#giƒ�ÚJ¼?«#ªh³÷'’:þ Ï:YbfäWºZ�EÎ{ÄiWþ‘¯Õغ ü š¬Å9 �BB`�Ûxãw+ÎiÀá�×0Ús õ.€sÜ+¤Í9—¾Ÿ˜‡Ãü >­›½?W3ŸpÚVí…'^á_£ö~ï;XÐ4�;{À ƒ@Fn=6ÓÄ¥[™›*g@µ+sƒÙl²ú,¢AÁ!¬ïì )Eü\™9Ümðn8óã©)‡õ¢ÑOrDú®Â¢ÙJœ¨.Y¸~)ŠfsØðëcàKN�.m^�Nž äëÉš%L«‹+ëb—‹iVŠ@ x9 žhpþ(zb™u0OÕTßÀ™»FK’³TO‰ã—}…ÌyùÄäæA¯qʽ¯$C, 'õZ©vàl|Õð Vt€ãå¹Ðòk<ºÀO§9Uî´�Gƒ8O'�£�ªÆcÑ!.­éÊÀÓ•pÄï¹™±ƒéÓx@Æ,"ˆ@A"ÎÊE”2QçÏó§ÁŠB\—1*°}„<¹¥@\S I€E)uiYoŽÃ¿Ðk$ÌyŸ½ƒ-ÿö’›Í™´?#”\¾“ˆjç—A?Ó?ÓoBŒ¯Û4G‰»9¹Œéá  Ù‹“¡dÕ¼µU†[?ºÚ‚jífÌ¥Ñtb©sŠ^ ü~ÓyàQâ]qð`Kþ�R 1,O�Īà!¡lVMY¬=Šè½o€ÆõNÌž³"œ�öQ¤°à)»ü‹7¾ñâçžæh@�b$QR�nzóÁÔW�#[¨Šl˜§tÿ¨Þ°�œÈÜÈí].ë3'ñà™¯`!}�F%¢êº4² W˜Ëí̕Αàœí*ÆÑ —QÔléß"�§­Å8 –¼$²Žq¤Å.�~TôfÆVDa—‘ ëƒBòmRò$î8]Å_kW£ ÚLrÝû4'vx1DÔ¶ã_µMÀgu›�©µ 戓MÀD쇠GÃpÅe6§Ò¸ G÷òsÜÜg0þswpÄÏ,£Û®®àè¹]¡¯]Ùes­ ·ª¼ Î>ûaÎOq®‡ê%œ#~ /Þ4æô|˜�›6ư­�®¡ <9 ÈûßWÂã%[Æ5`wW$Û¾{JÒ0÷´&ÝßÂnI ¢òþ±&x±¿�­äáÄ,ïdÌ‘rëCÇ5ǰèÚ 4 •Ä‚á¯(.ô‡–7Ý$nÃÆ\é 0˜Ø€ÃW£ìDñÎk%,OgÂ7E�Te-åSÆï:3áWhŠ cTíšyó04_ŽÁè«…Ÿóž�D’÷j>hÛòrÊ·ùAJíFsÙ�ôƒ»Z �†…Ÿˆ¿çJNYíthø€ß?¢­îeºó× YÄ9Tp™,?*ÁM¨ '‹ú”PQc IÍ!ç_ÆEæ§QÞì8–t�¦Ï†ŽCÔ*Qx¬× z-‘ão>mJ0[-x~ð ¤õ q:âüȯn?”Û�ƒ/“sÈ6ë`¢¾…—¸=½Žùß?À‰Ù’œ«%Óñx”'Û”E>˜ïÃß_ãDÃEêÃ)cO£õ[=Þ�tKÊ%¶váwü<Ìjš±A´ ßnÁ®³x\¯Ž\Ýò‡*´9ï÷ r.d­ ÷g?†•]Æ€lðÉnAn]¬$=µŸú1DÜ]ŸRh�D)žÐ§÷¯€Aþ*Ÿå ™QË Ìì]ßxºpà†%a›å0Xè8‘¨¥‚e>`f Ž3n!aKˆYçÎ�𥜪õ3¸]'ï‘+ÏD¸£ÿñawgíù$¸ðltjÁ ZŽCÁôIƒ§¦í+:nëÃ)hóNˆ Êð\ϸ•j{¯žiŽT{Â*»öíüˆÕ©°1ó)Ög·â{Sg™b¢`û:’U´ÿ« ïWqÄÏá±0òôo œå„ý³êéa}oœÐXÇ�©›µn jW:æxdÁ¹ÐøÔ-¥ûÞ“Ê­ÖPr5„lžÏ}úI‹»°ª%÷«rÆ6'àÁKKÑ®«ŠŽvíCu‡œÕ/Ïe�V�- —hÂäÞUøî¤éO{ÂòEåÑfµÜÂÀ4x÷|jŽVµ�ÈÒYØRs†Þ7,Ä‚reNù‹‘!³%œû‚>�™#Òøh™%ðl£ÐûÒë”’·sPØ]FÚ.PòyOÎîô&â»@ìÏY’ÌåÁŠ�spÊvÅ: H!Ú¢û9¢dΉ˜ÿK”¯Ç¡“Éä.¸�®?Å‘nî#OÚo³k_ ñ¢0±€ûâk¸Xp-JŰ5A }ZĸÂ�«{>'òs"G|Éßö[ÐòŒbéx*-ù‹×SÒñØÑǨ—÷�¹l?ãÿpˆ^•S¼µþÜ^ƒ‡âyðÙ|Îeûhz¾tö4̇ŒA�ÒmIJâÚºâ?ÞØ";Iß·¦ë¯j^È1Š!dF.ò½i$V[¿‚_l Ùëå�Ç2Õ5ŠôЖf¿Üºp[-l´ô…Ñ…C†>w;ñÙþD°_É¡î†çqû[ 0qÞC6ÞÊe­bSðhJ)ðgÁ¥L%î€ØzÎmoòÁc!Ç4Ò“múY‡©¥ë©ðå*f¨/'7ПþôçÌ{ŒÌ�@²§ÑœñÙE1v÷ Ø eŽRÇ÷â¥ÑøÙåæV…ƒ‚ˆD Ha”‘Ü^‚z"\ùE @‹M¾Ø”ìlð¥]KÎ0jT²r/>r°€7²¯‰hµסf BjÞÀô¿Þ¨™ˆø¼ÐZ™${âŒÑOóIÐvÜM·Ò‹Ь0Gš–'4’wÞSW5 ®È¨·:+Ë$¬°©Ô¯ÎOg7m%àæÐ�æöý•wñ^Åcv±ËmHŸžEMzÒÈ�®Kx±©›ü{’¼øM´òFÈk‡%EÞôq"#"q”‹çqG~d“$ÿu(\¬Ó5Ò¼öŸD?êu,/#Ç\Ö¿ãÙì…øåÄH`. Ѳ愸kãÌùŸXÛá¥Ü¥Åx~Œê÷䃢¡ zü‡V‹=ÈÆ–º jhLKbO$ÞÂ6ü~»a`›çŠG uˆÃþïd†òl˜¹I˜ë:ÞC KÀu=R�|¿LqZÿ#ö~Ÿ!~y&„:ÿÎa¶>²–+ 5'“–ßOÅü5{°»] |äÔ±Saœ¤K6Ðì´hxXØG2Ã\ ן(ƒïùé–B~Î÷Ù ¼c ŒN‰ŸèöÒ•$ q‚Ï^„ÉÙáøwàÙr)�ØÒ¢ª>ÃŽ6Y¬¸|—õC�c‰09ˆË®°ÄhjF9ùVæ{ûcâKýdØ t…Ù‘¾”óûQîh€‹Ë �6:⨃:.Zî€Ë�„Q£GªÄ¼®öíI%ÓäûAÆ:˜#ÿ£è¼Ã¹zß8negd“�¤]F"ç¹?QH•HÚCI!•´ìÉ–QD"â<÷‘E}%E’¢!TDóç÷ïs�ç:×õ\ïûý~¿þº“”5ÏIé¿óPV9Æi£°úÓ|.³žÌ‹„�wlAÉ„¯…ã¶Ä³è0òCDob_á.t‘Š¡Q©…°Ís wCx Ö?z¯ž“T¼…•ï Päç ºÎf>»hcúY¿�/�ÉÙ©¡õêßÑU]…ªœé¢ Kèàh x[�åuV8ɼ›ê»Mƒ›÷ AéÊ'âyþ!œjÖ¢/{"©‚yV'ö’BÛR¤•Ž—–_Âåi³Ç ¦ s;äŽ`Ámg<6ç4^º6}û°Ì¢—ÞÅÝøÉQ÷»fã^ ¦qå2ä O ߦHÀ~/Sö§ïºAyVÅ´¡Ø@8¤•æQ%F BË,P'8wX2*Ñ38ƒÎØœê@=BƒVD‘â'P{�†©–°^/0.þ �K|`ÔЄ§,ŒO>™¡…Göx€—Þ}4í[Œ–±Ì™Oó@o³0¯ åXzzA¦ÕA0[_Ž ×ð¸×:¼kT¶´MÔˆ¨l½ÉJDÅ£†€ωæAÙXìÙØB¶§í¡+w]5=ì:D¢cÎÏ…Xé6”< pú²íUJ3¯Ðà I�Ù2ޤ'ñÄ\= oý\pß)@:ØZäߥ{ÊnCX‹;»17—>;�5ëŸAԾŢÓw]äU!îØoBíô8ë[/(Q‘à�QOöo\9xf4‰_¦ïÊjèÛ¹%x$Ê•Y¥\J›"Óñß…_äKÆuRtc/•¸Æ8¼LÅ¿«÷ám[™êÍî³áRÁ,«ˆ…‡wòÀQÒ�d½ŸÌ{¥0KŽ þ9Hµ·JAÔâirÚËE¸ô¢ää÷q:5$ ;œÂ0Ns-6Ö¡QÚ<ºà�N ž€íVGRle„*ñâðÚ7™œ1½ �¦|èìò&%¸cÛ È£[N~‚•­­¤·Sÿ2~ð0j^ûYÅäÜ ¥EÁa¸Ÿ�2…ë©ôÉ?hØ2L&Kñ„<îÁqá30Òxžœ‹Àw©Û—mxÍr1'i“…õê(?íøŽÀã³Wb‡úJ¸s®�6¹.d;· cØâkð~vüÙª@ãØ22¸/6ù?¢åë›aKã°Ô˜ðO�$Hâ?bB50ðs5ç-%’‹gcÕÒ¹°Â§‹¼qYŽ2Â}`Ôû‹â¤8ÿ$¯§{t6§Ã'!Øje êþmh§gAꋈDGc3€Z?„Àô0{6’òKÁod;”˜Årÿoä�Í!œ•é %6‰˜x- ¢gƃ¶‡6T XCñ’ËØ¢UµÌÃ<Œ`ûO9³Æ%x©'Ð0#‘IéwÅßù,}ú31ÑXS?“J�Ðö jzw¡ÁØgòçÍRØ}QŽ ºJÿùÐZš(Ö.y‰IÄ�'¯éXqnÉŽÖE‡Ë÷hÛüP&¿¼× înÂ}p�[Ëê{‡1“ž¾…ž«³¸uƒL¸š6]—»…4Ý:D®Y^ƒ3âü`,.ŠÏÞ¡s®Ô{"·OÁ­™W±ç¾/Œ®|ƒbö™�KU0IYÙ{MUÞ†_ Ø|fWebV�Ü�o…•Oø ûýF ÏdŸöLe3g%¢\úcr^­½ZÛä9|tô]YHò7 òž·Æ‘Î94«©˜ÄlŸŒ;…]¹0qöc«Ö„«ñºäSq O¢zŽ.Å+æ’”D-ÆK_]˜Ìßu 6/�‰M–qU¹ÙÃÌÔ…'»ã k§ÙR‡{ð^Ñrôz¤@3>—™F$Wü ‰OZàIokñRR(NM `8|ì®_¥ã qØœ5•<=ö+ޏ£tísª5 483‡ônâ«ÜkXŸµnìºGî})$»gvAìå$2éÈP8°ÛŸ¤ÂÈ’i!+ffQ»Êfšòç5=^žŒ�ö/DÝÜ—tÑ‚wŒ’BÞnßÍ{¬Ù�j|àuäf6¦Fv+«›ÄnÁ�o,DÍÃìBÈaíi¥U>dLÖBã©Â8ÎëÃx##ا1Ž]O¥èž $N8¡ÇOw¯š‹“¼OQ)›«DkËØ”BIï—°ÑJ† Y¯Èó*Y0;½”ã®abM0¡§VÒ;_`Gjæd Ñÿï± ])B–ì^�_»¨§ÎUb©³€ÄŽg%ħƒõ€$ïâ™ÿèÙë²\œérÓL– ‹¼B%�ðþÛ‚‡\ÜðLói|ï¦nóZá–Á„ž#/ÀLÏrØ"v¶ïׄˆ�]xðMò[¼@ɉ.¸©ýðžê‹ÌÛÅ—È—€Ròª�~hymSÓ‰4“ç¯ ‰oh|Õ`©CI,¸(‹ðBŠpÊAhГÆÝß e—/l¸ñ ÅNËóæ‰$MðF $ —`um,\΃¶ý×:UÓÔ@Ú•�=ÌRÎsÓ„&¢ŸcÚºî¥>…¤:~:úÈ'A_ƒ!î¸"jàLT&ÑOXÍL‘ì€MW怪ãkâµd%Z<XæÑ�ú!Êœ‚6�¦ß!¸4æ> È9E× `gƒ¶M4ç�4ì¼�?×A¨?7X¤ gõ†é¢÷©xŧœ ¸o^2О3Ù[”…+ôþ±Í•X—š ¸ð çûƒCH�é¨]˜iøÅ×´ò¼ªß?ˆ‘®Ó`G®GñcV€_z¨À‹2Òк DGN’{9KAíy©Ï„Ó|é¨79ïÆiã?EÌ­øòµ/ธ¼³¦C»Áó¥(v%ÄŠÞ A’Qùá5võ ˜5Pdà׿¢gN¤ÊrÉs�B2ì¡§®ùáaõØüg~ª» —Çâ±S° ëênã`Å;F%Yã¶?$s§ûb°hZ‹‡�O/éŸL—‰ÎókV¦1›ŽEb¡z–¯_N¢iÒ|Döÿ–â•5NG»UÏ€þv 6><8·ú8•úây!IxkÖ�©ãÊôÁöbÉAÞ�Ê!äEÙ©Ý[,û«Çv¸Ð¤sòoþ8©Ùÿƒ¤ËlDi Úz †Ùh˜C;oK!-XH®Å¿a]º£ðÂKlѪF"¸È6œ�Ç}ìy@j{èYÍ3°<½�¨Á«�Ó¹½êïáôù`J̦«ã+À·ì7“¢ ’3` N…÷E¥�/!Û&ÃÞ{�ŒÓrH‰Ís«wlÕ´`0[wJ­Ú ‚a˪dh¾­BÜÆÈ›®óà¨*È5òziö«,ºv®X»¸ƒìËtÖŒ_tæ_%ð2«©¤|ð~ …ó®Ñ·ËXQa"`™ý4ê«1—KŽÎ¡×-¼aaš5,.n§ò[öÃËžr¯] /g{3dÄÅŽ\&ý"* N>PéÂQ8¤·5\AE+ ÷½ëAƒý©Á¢p4@é„lZc–˜F:T×îÄ{èö½r©ö4I¸?Õ·2$ÆÝ‰¤Èû¡"ŸrµˆŒ)îTæàx»7Ì;œŠ‚ÉQ0C°¸EíÔUßù£cÀeêü]5qÞ¿›Ü‡©—Y²¤èa&¯�¡ÂLüqS‰}°=s*ä8ë>V¥j2—h_k=• ßûqºlæ;rKû»{– Nö0§Åß�Ý€n£°7á%9öƒ¬³šÄ[qÈœ ´iqÛû’à’ÏL”º[Ž>•+x¦ƒJ˜8, R¶pLô"©—/¢¹usà““?(ö�â’У( ¥Í^™ãŠ^‚ñï~oØ[CË—ÐÁ¯yp@´ý¢Ža�oÝ4ú‹#ö¢G© uz�AÍê“ÐKiŸþ›C'iÈbiØzhqã™·©Bšþ®®¥7Æ Ô­èi/ÀGÍâUjÁ]ÔM©:4_Ò‘ØB)vaÔj5±fW?õzå@Dk±Z8„„‹‰Á”„:+ÃË ñ�ÓFZ”ï wç´2�ó¼Á¼ã5&-#½N‘6ÕµÐÑy‘¶ü™3nîÂç8Ô&ˆ¤?#v/›cF8¾ï"®iÝ­/)- ZK�§úྠ×àÖ$!^µj(ì´îÇ‘%ÕÐóòv‹æÑÕÂÓA÷k?‰·—fsì4°~J5ÙœàM2&xfࣈþ ¼o0ºÛ‹<Ý.Ï;íÙ„ûìß`{»×ÿ>†l–<gt‰›Q6‰jÒASà zäyøœî Ò÷o3¹ŽR¼±O«¸š.ε'Â4T–’ÎáÒWóè†�а¯»~…bfl"¾JM ù6!T{<¼‚dá½~"žä'‘¿Ž`oNQ½°…®–0ý�‹h›“‡CSƒQ±¹ˆõüZ€RýIô²QôÛ€Ù´6ó;Mútò3êhaB›MÑGd/8Ý%…'CƒIŠ{oFù�ß ­þì_EÏûÙ²O¥’¨�ö+Zþ>„XÉŸ…ž, �˜y¼Tƒˆó§ŸDò÷R˜Ý'Ols�Ép•;Æw’¬éç‰Î¬•øá­8ŸÝo�€ßa\Ø'%Cg™ç+È�{2xÉ)Áþï$¡c<~+‰6ùýd÷ì 9ÁhÓˉZêWZ3ó4è]ßš­ ¨æL0dÊ72ý¸ÀwŒ>[ÖÁ×bzi|2½³@€èUÜ'm2€�õ('äŒIOèXý 4™S@¦¾9ƒªZ З�“Z×à=ÁföÌ3;ÈRœŒQþ{è‰/ÑhåÒÌ.6«�5Çñæ±a�ØŸCB7^€EÁ pj´N{Õ9M(T‘š…+CA¥´¶‚¨ÒN2•ƒ1ýËø0JŸˆfm lV&ÍÎG¢+~‡®yù£P¤Òy?K˜ ûeœ··I>À‡›OXa€h+Ý8†£SqãL5°˜aI×d>Ç6ëœä° ªvÈ⺜XŸ�[:àÙÿï‰x~‰Ê[µaÙK+ºîe5 ¾H:�0ÝÍ>o–+øæ—¿…ÁØêó¤‡ðï�¡iŠ�ô«Q uv>A Yy,œ"¿>æÁŠgd¥žùn^D9q)î“‹=^z¹ûö2í&ºø{ ¾{ó"g+¢FÃkÚ/ÛFäD“aƱ(ö§¡:¸è?£†'´pç‰ì1²ž\:*z`§«®„�—[a©Ý0{²¾��ÅMÕ‰Aï}ÆöÆ*²<^œ,!bY¾UŸÛ÷à*ëdü»�…±ìÄ;Ãùµ˜Øy0N:‰®fМË+! }7º&s½ùáz¼×Àæ)Ž0]u!ŽŸ*eEl«™…Y”㿈ËC�ôþfryR&yscø».‚¦úGìþ‰w:æDÓÝÔpC—:õÓ4G}Q>ÆcÈ—¬”ÇZïrܺµß+L|—v ŸóA«ÀÜ[×á•îøóÛ…¸-øAâr$`S (/€ƒ¾ÛHÖ½Žå- ~ý½–óô1H@¿=’‡Š‘kìT©gÄdº(Ü“š„®å7Ñl»*éPVĘ×@l×A³Ák¸3ü’¤&>½aUlYÜg&t“´|�‚ ²þ¬!¨u¨ã“IéÐóL : ~¢¥ë7¶gÞ/ê>Ë�œ¨®‰€ƒ4;Òêî~e%^pD|® \¿REÖY§™_ÀùjIàªrC#ññ@'V*¾�}Gá�œz†'ÍÓá ª ¯¾'6ßÐÄÇ£çá|�Ș̃®ëA#+NÐùƒ›ÁN2™�´áM»äë[Òä<™ª¸þG4´òqEbÃ|¸Ò—¸ˆ+bµd!(Gô`[µæÛÕ�òÁ0¶äJX¥XÒi"7HÏ�‰Œ¸4þl­$§R?RéÕ‚Pù.Š-\™Ìw��¾Y‚ “Á)Ñ ]­ 9_$ðœðW'“P­²ÕzÇ鎀•µÒ`yì4N+X€�ÏB ûŽ0ýä÷¯ÜnÆ�̪àG½-ã!¬?‚ä£ýÞ6z}"3ßfE¾`&l‚MäÅ˰ðý:Vë– º·”“̺mÄàCsç4*`:˜~Ž«.YÊ^xô¤)ªqñdŽî8‹OËa°TŒ³HX…�ó/Á_-¸•yÒ Ó-ˆ Œ¯�*A¥Î�è¾ G ¿Y¬Ûçh¢óŽd¬í!MæS½äjþ#‚™é€Æ—ÅàJ¦ô>³`#â�Àêñ`9Ê2«bø‘y\ ™®/ðDÐbŸ• u?CΊûD!)›¬ãË"‡–§"1ø—•ìYKv…{ƒ¤AܵN ¢SîÃ+rt—Ç`ÆR1ÈZö©Zë@/¦�}!ßë¿PÇÈ'tæØdèmùLM"V`[Î|ê;SŒ¹ï®ˆ�ï+ÁNÜ®4ø3iÿÅáýkqLß§j²»å=¬á¯GVC¸¥»ÃKÃnÝRÔÂÓÃí`R3B©ækú ¹ï k $½¦C7ÞÂüPg=·…¤M9]ä.*¢«²è´%·Éâ3Røpš�Üz±Ê¥QŒ7¬”�x<æ-È¡¢£q±Ž,ût“D)S1¾žœu\'¡Êªë¸|¨¡zéSAÞ–Òsäaí S÷ïe .•ƒ‘nýäžK±©oîdØ*áÛvÉaì!%]º‰–­±gÄü–±¥/®’yJKÑñÔZ|³kþër=9EÞ�öDÆ­pâŽðVŇÍß6ã�¢Ù®K­"’X;™ƒÐ}ê5¤ÌâMÖÌ'2K’!Ç;Btãé—“‡ÐÛ#’8lá �ùBŸ€<¶l¶c¶ {s»É¯öy ÛAr�ñã¡Çþ´â°$WóO‡}øüYÐ?–GÈ ×”To%>Í~x_zê¹=b®¼¶Ç®Á`<1Dß%Ã’3hû ±'ZáÀÎÅøãkµi F0J6ڃ뫋¸Þ³ÚôßßyÜ‹íÿᾺóø›Aü>ã2í;¯-–7pP`6†´)r3VÚ@•D0œº |/ËË¡Ä;níû¦8HÓ¼B'Á- éC^žxÞÄ'r|°+Àñûd^¹o 3im-&ÛEaPW+3ÆJ�çeaÌ»œBà‚½ÚO_†ÍJåcá\=¡õk“öâ<¾ÿ s…,§ü„îÞ»lmG––º'L°Ü9Vüù.SOA#<ŸÐˆŸ%30½·€ž{ÞFŽ.ÈSŸ,ª2ñ†±a¦ØlJœ—%�»A¯èÅ»;á^§.Ï%R åÚgá�à(ües7‰Jð?Ó&±¶ð&½ªá¥Ñ4òì}6Ýôl*̲©^š2+„5l(y½‚¹*\ºF™h‚œœ3ãXÄú/Í$ʳ’Œ·éƒ‚D&Lo Äv3œü3�$sl«úŒ¸vö>L¦“ua4l!¸ ÜE‘?àUìg{0�¼Äì«è6²7Õí�q[;Ðüœg?s€ŽDáõÈ4r¡0Ÿ<˜�.¿ôq8p'Õ^X-¯>VuEÃæ¦XÜLC*›«÷H_Á.!i*ºç3Ñ6S€uß—à’÷È+É |™|f<ñ¢Û-põ3_°vÞ-ýü\àíl:v¾:Ì2i³�6—òÛ”“ž`랃8�+±¥}ä¾_)ž2 ên|œ±nœ>¾ ÒKÞÀðº4Ú�Sˆ'ÍþÒú{>P®�Ûl~³¶Q"–‡†Bñtdþ+W‚ÃëCaß‰ëøµA‘h—F0N–ïh»¤ Óá¢ÿ.Aƒg–PòÍÏHªòšs4yT`ð]ãá"& ®ä僌–ïZc#1¼“…kv’—ë5qèuiܹ�JÜž µ,ãjg€&⪰TYïÎMÃoþü ªžMï÷Ô¿Ëx�dPï9*Èg¿š&æ Óõ ³M`ï¶l§âJ!Ìy']¨(™F EÛ 4ô�šE�ǯ_´&Àøf§Ó%ß–òtîfÔXG�ºy£FLg¢8×"[‚�ݹ�uTõgé’ÍEg`TÆ–ñÈϦIi h0ò‹½±û8迌ÅÞ È^ˆv„á1PþcÚ°~øþf"ëó{œ†îÜŠOp/�O0«W.ÛE‘£w€þ$A.êk(>¶åƒu†)ß›í�íÔF«—²ÀÎâYÕï…¬­Nèï£LÜåÓšUºhdÕ…¥i š/�D¿ÍFƒ;{ÀúSÙTÜ€áWBàÔ­zœQv•ŽMöľE¨¶K$ �ñ7HÚÛ‹ñîRU Y»z*á¶²(:8™›.X’ R'pÚ?Ìðƒ@ j=ö•Œ\Lå† p‘ôØû,®l ]?£±=§Œ|¶»C�Îì‡)ÏEh‚ "-�å{ØIjÌ/�ˆú¸ÜÓDžÁ»nü¥–�ïåßQjz?8Ó…µ�0§t.Xh`þòédƒçjx;_O» us–cʼn)ä?!.¾\¬ËBÈÔÅðØ|c\œB.öÄ27y§á!;áC·q¶Ár8;Ø@÷I†á´àäWI2F§@Ä,žÔB5(Úž�ïĖ«M™4£½†�ÆŽ­†ö'ØpR‚‘¼cI¢ªbP}:챆'r—pv²1J\±¥¨(ñ[ÂÿìA+�ïô¦Ësü}. ;§rA¼¸óI‡²·‚fÈJ±|gØ—Óí1²I ÷ÚKRYûŒž¤NyQ pI(BÈá ¨OÛOË} M§½ ÁëÁýD}5Ý7A—>#TØ= ÚBì@EÁ‘(EáÙX:N;Ü´qó[iö’�L_˜DtÉxz\µ,?�Çï=áPÇv¢Þ·aÂ/ºé<åFS>”ô(%�¤_Òä>wÜßt�¤Nßæ{~¥~~OÙc�úà~çºúÉ�É\/”¯šÎM‘ªÄm³øÉe¯Jri—8š?ÎÆ;Ge9»‹öÖã½yÓp6é b¢ÿá• ì&;ª‡™h;ŒÞô‹~eÇáPðlßÍ8oz»ÐßmÖÀ§£b<ó6yÎ *—¬ø€8¿ì™ÙkÏ΀&bS*Ž. ´pY?ÉRÙÃÞ¿^›†ùyžv¹ì‚.UÔ/Ú‡³bžÑ´/eâQ‰a½ƒàöA�1µ¦Îò[¡lÉ4–©ê�“D~Æ1/c¢éHôjó½Æìõú†Zà^µ¢lLå:ïbYD7U¼�&©çé'û²µ}(Îi|E ¬n' ž?Á�!™8¤Ç�ù"*Á…Ýœ¯®ÚCÔÚÇxvj0\Œª¢þ>h©.ÆjXB½^´Ž¢ã+WÇêVŒëÄOï"qÇ“l¨™‰?#Tw} ‡xÂè²/�˜9Íòß�§au`·$�ް°»f�z-ÚIlÞl¢þ+6Rß yx·ö ~Oz�+ÖbÂŽIŒYp"™Â—ˆ ½›áþµð1Lù~3tý”ÙÄúAðÏ= Gºï@³‚Lº'Ç»PW5ñMØýænÚÛò[™óq±˜¾oηd™_÷þÐk†7˜ë+~S±Óežú‘Hæu’#­:�øÝJjm Êñv›<gLü£�ár“rF`Ãl”ß Û7!Œ]Ãîж “©bê•O¤ôT ûß1¤ýZ ]+œç$t˜-^Mà£p‹Ô´¹ãl—;dò3;|sNíýÛéM1I\ž³“Áf EHo„»mµQâõª¹yÝ,¾§f!íš F®PÜLÌù¶À@i¾�$ÊS¿ÂŽ9q˜òä=†\®&œÐô¼Lšv­Àá¹ï±ÎAšÚ˜üc5[çÃ\'LrqƒŸQÛpQùm̃KÄß¹–^ü„?‡¿“Áó®x7>×;oÀÛü3 cXŸô¾½I¶˜šC©[6y?½Žä_K#Ó–Gà:ëvr|ExÎP†éÙPs© ±h¹NŒÃѺ¬ ¼Øã¨üÖ�þýû‚�ìûOdA¥äÓØ z’ؽd.yVT‹�NMh¥²œç7y:·ÓãI øFÿþч”‘.�á5í÷$�•³áÈ�ó¤éþŠê»{v£»•>/�£†9”o–Ã.™J2µn?cïÍx•ÁïC³ñˆô}<âQÅT´w²^£ZŒËüR¸Ó’º<ž;èÜÙÑ Ú’côɰ:‘çû ËõöC‘S ½z¾riIà’p½ŸÙ5ÚA·ºz¢®º?Ý]s bÙl:µë)U?O:<Š0õê�*ý b<ÕT9 ½ –¥Ö¸â¢„Ú pK’¯°©Ëponų*h™_MïMô·°ò‡DøÔQºk¯Y–¸ GƒâqÎkQ|¿œ‚ýV<¾CˆŽ3]÷:´X-„ –f© ÁÂ{« úiÓ^¼D.š\@ë´ÃP7XdÚk�Ñ«×`X¦^à�ƒ]òÔPé Ö$k“‘ë&á‡ö,SgI3Ü)Vó—2—%xÜâ±W°@x;6ÞI‡›¹s¹…rhX¤ÄUÕÒ×:}ÄÃAjú¬°ÔnéXòŒÜÏ_„9�ç�§+‘Ù^G^?E\ÇAý%le ÑåŠ5œIÖ÷&n­ Qtðz3Æ]ÑÁããO©Ft2-Îð‚¸cª ¶mX‰E£qç||¤!E'ù(ûç°û†hÅÔ@è“ ¥Ï´µ :á:~刘E¾ÿWGÒvï4ý',»Rühùà-¨ zDέœàï7)TÑÍ¥€Ah£­KäZ[ᨡ>•ëc’x™ôú’J´¬x�C/3à‡ÂR΋Æî‡íT3¯×±9ð÷ñD·5ÿD“ƒ…àÅv¸ó~X%ï!nþý ¾ÖôºW^ %ûÖøcYjò~oF[áP¬¿z/�ƒüg{ñ°vÝBèŸõ„Ygs š÷%û1‘ªŒñÓˆÛWÉjý+¬Žrë—{�Ô‘,v \¥ú“ÿc~¿HÂC³Ü­ÇìwjŽºÕkÈPÒ ¶OÅê‘›xÕ UÌŽ£ü¬Ûðõ”�ª„«A–Õ?ÄÃI†<^GЧŠB|Ü1Rõ�bW„îW¿ 7³,ð «"Î�Æ÷NVr|þjœZ§�|å¡´³íÚçIñ6O°âF+ylÞì€{~�¦×«Îèá&·V¸uç,¬“·ÆÂÊ ô�êTpÚAuË&aÿ«&ú»Ê“ˆeœ E&Èìž[YŸ…?ûèÂoRàöS¯Hpç¯ÏáºV+sO-å »µ‚®ŠeòÐ yhjþ�Ý¿ö ™'}ƒœÜ~\~ü%c.ý´Öú?|+0ŸäN  �5¡Ø[QNå,‰ªƒs"öп¦h=§“¤ke`)›IR¿’UÁ­°7( ¿úsª-ª\WÍ`úºèä7ÄÀ›Å/hSÈ\ž‡Ã%œÿ0*¶.‚àx;’}ú ØÊñrJ&2›y[+|`ŽI;ysp#nLÀ×â0rï+uîÕ„Ð #<ɦãè˶b¶6>2šLþÄ~bϺÌåªêlÁAp®þþŸÌôƒ…ûýpé”\Æ™b2eÛ"’ò²‘,;ZPíï*Áþ>’Ivˆ­Ã·n’žWF^:,åY$.â½üéÂŒj¾Ãwæè¤Œ/ëÝ`Užæ¦UBË™›ôŠÌudŽ8°�&’P s°Ï�!›ËñÐîl<+ý ³Ã5i\�ÏëÑ$�Ÿ^V2ã)šŒ†Í}TÈj§–!†n_ï’(wkzÇWƒêé�“ë>c}€¢—ø‘v60ÅŽå¸*ö$ž[èC“úÃñxY=17ýFß0ÏqnB>;u¯®ûCvZî`sv‚yT+ÞËãxÜ#ˆ³„Ÿ'r\?õZ‚Ìå5\ä¼X’u>"ódAÂ=îºQ‚³�]hDò^ääBèÝ Íe}ã `,íV,€¡|Ob£v“ì#±P ÏÀéöeTÙ¾ˆTëºâÀ• ‘Kyo_Óyë¹þÖ$ÌZ�Ûtõ<=}ž¨z0?÷Í€è¾_¬Ò¥8‹(‚ƒÎ9¬ö²zHþB'-ÖD�Q~ÂÉ(ÓZ>mÜôm6w¯Í|Ö q"zÅPk[б»—RÙÂd¸ž3—Ø]Ñ�oư`¥| ©§ÅJžx×] \×Ï ÎD²gçÐŒñ0èÚ»æ�ÔÀ³Gê\ð 9Þnu7æ€Ö?ö¹‹&BËZºú­:/‡•ÅËÓB ææ Þâ< ´×ϧ3s+¨I@0bTÞ›Áp»„æ…) »Ý˜7�øÁ¢°ó`á[ ß²c!Ø"˜X¡=YZ"�¥ßƒà‚E,[’'I ¼P+<™mW’æÌ¿Mž…8¾Ò‰ÆE¡¹ õ$OZhrßgòfî–ã‚­  óÏi2dýÝÔz×UL›™A½{}©ßìíĬŸppK3½WJÖEè»aÐ !3׫àýˆd²¯M“”?O€Ðß3 S.˜&¦ø“ÊדQA-‡ oç#'LËÝö£Ï‹ß”«¬eŒ§g€òÁCܾ‘Ï9¯Çy&ÊÇ0ÆT M[ʨb³§uC ´þ¬€C«Í¡(q:JñÖæ"Øóé27—�±Ôy÷71uòZàþ'Ž­Zþ„ÚÄMC…9ÂÕ¢»¼i]©7(Ü—…«M cø>Ø®ƒ6«#èÃÒ8ß�!'+±âçMP,^ÏrH…©—„9{>‡´Óð†€4w6h þ—GCíXÜÔÝ>F—á«Û)H;·˜,UQㆻçSïÝ·ð6Ñ¢åî¦TîH,M^cI â­@t�!ð®ãÝ~Æp‰ÿ¢_q)9¤LŠ2wÕê5ÝÒ¡ ógÿ€ðä ü¹áÈ‚ÅPDI³DùøÄ–%y³œÍ8ñßö«^¥»£Ï‘;Çò íàgvmE*´;V±ßZñ‘§ôQjík¡³N2÷žõ`;ÏãÍxclAŒìWÒ�ªçIæÞ eiÃÉ|g±V1˓ɢtq\ü±„¹ånÏäw àvK*Z¾L¼|ñUÿÞ2ÓÌê%)_àÏÏY(n~�45IðNµïÑx²qïVã<8–ýGLñ̇r4�jĽ‹ŒxºæAí‡RŒŽÐÇ”[hµŠß$©£^EK²�¾°ý­ßp ÿiSQàMÒ¹ŠÃ™±4ãU9ø‰`ÕÀ¯N›ûÁ]�/tìŸ$ÌùP×>35ím4[Qlçì†Ãý« ßÊ;4õ­Ü«?N·:n‰™¥¤åÚ|¤Ž÷žcý¢œ²ÓOz"ÔæÔž¤Â[OlÜ|…[mññø!¢|˜®lˆƒmC³±Kµ…w(žŠ{æf�ì9X|vw,€Ò&r— bÌÝ53Kæ\mÃÏ«‹ñòH4þ Ý ¡§ÔÁIš%Î'cXßTrãÍ}ªO �Ù.⩞v†ýÍgÐxÇ\¶³\†˜¤jceç„—ž[ˆ¿[³HßÑ1Öäe0#z? výN‚{ŽE êulÒµÉé™mDíí$îÕ×L( ²}¿ÛdÝÜey ·nÉ‚îÝüøÐ, Õ<¿BÂÌ|’/öC„¹€ŸFtûý.\,nŠg“Á]B�ûùJ€wïF -{Íc>ïéƒsû§�ѹMX´>Ç.-Cýç©ì]öø‚´Øâ3}ÇjòÖt¶±c÷u!1r;¥^˜ù"Uíð»•&Ê>ƒ€ÂõÜÁ %Ðù®Þ_…!mãq¼¹:LJ‘§,É›*ú–w«á§ÓÝt××(ˈƒY>;ðA®"xT�1­sUYG^[«È<~ä‰ 8<-´Ö™ÇÁ£Óh—Žþmâ üEœ4é5PÆü1¼ˆî„O“°©é$–ASF"ÐsåÔ D Sk…8ëX��Ÿ÷þ ë‡m« [3¯›ÞáaU\æÑA®íº‚{_a¸çZ¦ïÁ„?ëÄ™ë°ÖŸ´éœ¥»¤~-�ÿ¦›.Ná½”9Æ�0¹¹aé:ù×Ôo3à`è%³ó®>:i+÷¸6×?µ†ýð�ÞykÆSW¯o•x¨¾ÿlÞ·€Á+X;² ¾MóÁ5Aò¼û (^À€Ž RÕðLÒ.¶“ci›¿)ôO™2¸¦G�¬xçÝOÐck’Ù(‚µf $à I�UâÚ®,ὌR�rÏ Rv*�n“¬b/ ÊãÐ%îÃÜuL©l9Í7ÈÄíS yîÚê¼g®Õ¤ç&?œt¨¥º·0ÒPþFâ½\C.Ðl7sqAj G0Q7¿b„»Eu$7R_ðÜwÀÑLKZYÍÄÈ4b,O ë—/‡§ñíÌz��L�\y5%´~¡§NÜcŠ~Lçu—dÀæ4%ØøA€c%!–uPÝ'IßW=ZáçæàÌøÒegI!ÿì_¢z¡ ;øÃb¹nún¡?Þ™¶ŒÉofx?|D¹o+äiÀàTÌÆ…V°Û ƒ7* lèIúÇl$‹&€¥C‘©¦�;Z=ÀPÑR²ùæ&À<Ôô…×ivgóFtCžÌãS`¯'w\ÆqüáviIØ]<¶Ü Z�¥Ðú4 ø)b ]¯™¹ò 0ÈÉâE59È“õC©/J8ëi/îZáDÖ7ÐÞåÙ¸Ò«�,aª½s5ì)£8vz#:vKÀÒž‡Pý¬û7X£ -Å)e‚$Ü7‘ðň§ÄÑ{ÒÛð‹ôgˆøå :ƒŸÎ÷ÅJ¼É»УW?Ó?P ß|@9¶¹¹k±ëE3fºýWq{ø|8óRÿB¹¿.÷Ç›ŸèU< â¥àÇc}ôÕ¸ ‡ÓQ¥$ÍDJè�·!æìI´Ö?†k[pïí¼C“Ø )£ÔU0ÖzÝ¡�¿f`úT~.wQ“qØÞC¬ÑÚn0Ý÷�þÛë‡"1Øj²Ę`¨þ]^hÁå6Ú�©¿×ƒ³[(öYæ@Ú¯â÷y³Ïg+¬Ÿ˜¥)¡°.F Éî‰6oºÛúQ9‡f?�Cs%e8ìoŒÃF6ìÆ°Gdhp˜1^R�¯B艋ù¸ÖX‰ûqb6¯~}9‰0ƒ“tj¾hƒÖÛIÔÜÕ¼úsGRakOÙhªŽò£©¹sX‹Äâì92ÌôÔ^&¢Å—¹£w�Ès tk Þø�–Ò£öß1[}19gT�ÓU$¹CÁoÁ0=Š7­g~Ë™óªƒÎ2÷ë1ÁY#çñ®üó¡CÙWñçYð’ýÍ� áéQyÈÐÍ ýi¸Á¯S„£‹(t>ÿø{Þ7ÆxT|1ÏIßzgHóîáôÐaréíl/|EF�áfSøn?P}æ›.ædIÐÇ– (®–�—ÎÀ–ËÉÔrv>Ùw,›�kv W–ÄÐI»·CQþ1ø§¡Dëï¿Á_ûuxËüÔx[ex·oÅRá-k©C¼.Á®ßѰhá ü¹G�­B¯©‚¨¹GãÝÌ!-k}pdƒgÏçyžMĵ8çÉ$^ð1y{¹„˜EZÀ%^&x‡¢ì¥e¼±æÏ(»|)§¨)‚BŽ×È%±|0LŠŒx€Çîêórõá�ëC(YÃË~ú…1¬“…’O�±¸x"+_U’KMË!6Úså¹ 8'ÈãÞÓÍégIÓË€FFáv½s2†ìX|�ö}€uwv�¦îjü”zÕr$ Èü™™ÙmCläºt(=MW8G2A§·€9/ âÏå^�¾ =ß”9Ѷï´Çâ#ñåÅøÜ^²E%ˆl5Á�¨ÖöÍŽˆ£­#‚÷�•¨½v”“@2^kGUÿžÀÃJëQMî.�¥û&øD¾;d–á§ɨæ³�úž’ ‘pâ.·�}�¾'ïSÝ-vp­þ39²QŒð÷,ÐýƽO'[ð3X¹d¡[ÂT”æÉpçÞ¹3Ê� ´5€ ŸÊm¾ü™ ú55¯,d6|Á·Ç¦â_C3¬ñ[ÂÜ7ù‰ÝýZ\Тærõ[¼Ó×ITwòó¤ÅñLO%v¨‰s ‡ŽÒÂþtèñãͳ¿ î车$ZàáƒËëu1ÿß[¶¤{m´LGŸõã$=$ {¬ æã&ä†pâ”j ;%ÅýôL%&ï9pŒZÀ³¼u¾{_cø²T# $vk‚ÏæÇfÑÏäQJ6¥Ž’×ýÀÑï&� 1VçoAMg}w°šl=°6®œÌ _ÑOi¾xÌ"Ý"hø+‡†$ZQpÖË\¿îÓ^Ÿh|0øŽY§XE šÖ?ƒÚœ¼õe †„ï‚Ä¡$¢ß‘y¾s>6Vó„-®±Q)qkËF²àCëþô5­ßð�,Rçiþ çµ³‰”Áy ÓìÐlsô¨qtåˆ4¾Î9D‡.ã&¹ÿoj8Fþ|u&¤�kX/‰cg…1g¿''¸?.«©¢M@&ŽŸâç�~XOÎÌF—ïa ¯¢&z»¬à9ÍMÀ§ŸSËdS6åÕÿ(:ï.ÿ/ŒÉ,Ù«Ì„( ”ܯó¦" íEC)*}’•&Q¶È¦P4ŒÈHܯsGR6Q”"D**¥Ä·ïpçq®çu]?�7øÛN›m‹8Ș}û‰ë§­F‘G)dyb6n1¦µ¾„Äž½ G~ýe‚fi@‡Õ9zø�ÔË-cRO»ùÑ1yTÞ_Ç>ŒÙwâõØ`t½=…hÿÛ/òq“d×cØ©bŠÉfeBéštuºÑõÕ£’\ä‚rÚ¢hˆG›Eè*Áp.Xoúö'~P;YRñq5~s—ÃÍuçØÍdÉÀüV¢©s•�,W†"�Ì‚QæLK§o NÐS®êÔ¯â)(�q`½JºiãÏë˜a�…yoÓKµ“wÃ� óaEb0Ê…Ëp¹ Éš¡�”<ü…ïïtƒ›f>5XÓEo8…û·7BNZ(Øž¹L§O~�¹"$1$˜½ E/}»5/pþäõÀÝ‘5 ô4SÉóž-ØíNZe&0É]÷ˆrAöªøýÆ*ÌøBÎ6瘹VÃU¥¶xÿYh‰“fĞǓÅçýH±×önM)Œ(´¡þÕdÒÙÇ0¯z/Ã!ÛwE å.áîú©쀅櫑­²â"w…S˰¨ ßHÎ9½" j×™5ÕøÐ9 ÂßÉÐUEW1åõ&6^�æÎæZš6ýÍîÈwß�¹½x;nw ´wßÁåå'ðÝÕALµ«Á)â{½o“™ïL`ÞÏvf(°–|dži*ó*C¥Q £ƒ°–W™ž‚Ü`h‚ÄfÜ™TŒ¹ƒá$JïíXs„¶ß³@aˆÄs0Ë?�$Üýe¶_ó5œ‘aÉ:·òâÊ|hxIŸžA ÏêÂj‰>6hÉ{ïWÁÿÊï�E"Ó A]‡K�šNóÁ�z‡¤“¬GXe郺þ� €ü©äÞí³Ä»÷<™T0NVMWçB—Üaߦl/}Wv… §{êƒÍô|†É-~g⤴‡~Ú¼‚Qó}q¶Ò»fbÔÕr²x¡ûx~]�#3›è)‹~LèÝLNX×�ê¢ë(гw¹Is[Tÿ¢¿ÐX^ú�D!pOøç9–èC·ºT˜~–�ã²Ì„“¨zdSÁw˜›#‚زÚCÜâIꙫ 2Ôƒ³˜?ìºÖHr¶îu÷Qå½�î‘WSJÇÈÑ-äËh�¹«Ùì¼lòm§¼6Œ‚…R?è™)œòi0ŠJ!ý>,Lþr‘Ú,ºO¯NâPzƒ%ñ?{›æZi [?G²Ø‚Ì.QØ6)„ªíÉk…æÜÓ…Œ^£&廪 úAYX�‘°áxê¼ JÕп]©¤0°§ó&µ˜4ƒwµf9¦Š¼§¶Y»aÆœÓpüY5U¼µŒŒÊÁøç=ø²ò.þòÉÁÐsë ?¤“èG‘;êh²)Šê,{G´v 7Ÿ8Ðü?(/��‹Îfá‹Ü=× ræ5?t×mã�ùÁ£àâÒþ? ð@«8Fû™âꇒÜË-)ÙƒÄë®Ãø†m?C˜éõ0{€žôªÄÚ°/85eº-ˆÄäÉ!{ùVüip fð­Á.—NZ“*ÏË]Y„o¾õÀ¤ÄRXz7æÇÏÅ/Þ©À¼ŒÅÁ¹BL„C™é•òžX¼ñd'ûQgq_FJE”~MÅ=�¼]ï*à†·ÏÛZ6y¯£û†»u;á,÷˜Œ<äã„E÷áÖó¬o?éMˤî«þÐ=޶ÔÍkêo¾N�zr¯ÄUpd{=,¶н¢ü) lÙKâ (I$•zæŠàZ·ŸÄ`q=9<¡…æ£eY.ðâÚñ¥‰8âM°h¹ )纑.·¡Õå­dùæ×ì®o™ø³üS³¸¯š«r1?¨ºo8-:„›kÿÝçÏnòóûòóÍ)¼¶d5Nâÿÿ¿ÙS)<'‘€ Í È%\ÒYÅš>?EÎ_î¥_Æã–•7Ø÷™.È[Ĩž?_i¼ï RÁ4¯Qœ7¬û¯Ç´¡/ß²ª3Ì|Ï@£=?ïF‚:7ê1;èÁû”{DqÆ%º¡Q Kìü¡uúɸ‡ö;#`" xQ.TÌ/…};»�Üõ…ÒßéªSIÌ>ó~ªñàìÚ¼o›£½å{ìZ¬‹Å”áØp1w�…­µè’šʼná`µ_W ב˜æ*Ú¡ ïO¬ÁWÉf'SÄ8áÞäæ^ûGRÐ`ö!Pi‡N�("ó„”+3Ûg‚¯”CÈZÝHºÅô �g5S6bݧ "f!�ö§ƒñSx Ë¿C‘N?×êµKA v¹ÂðÇàÜ)é$Ã֚✟;•W5£…~“̯YÅwKñ¾ÏÙ¬‡~+Mã—³»gÉò6ßßD]£æ#h]O†<“à÷u¤"Áø®lÛ: ç¿™Šö¶ ¯ó‡µ×aðù’ ×¥€÷ºŽâÝ'Uxs�6t½/´mÎè·/Õ#Q‹0Á»sâ`ßÂH¬ÂFÀ;¡Sa!­¸0Žwn͇·‡oõ=š_w¼ê9·:�Ràc’^'ë.¦àáB:œ?�ž5'#ûj!(ó-¸]?À¼k[Èã5ákû&øx3ÞÁ}‚³ØT b¢®Gæ…ÃJSQžaü36·³„]5Díþ±iZ)ûeÅvÔ‰¤ÊZæð*0> -B)}/ò }ŠxRõ¢ÒwçM÷ AÁœhø¾R•,+ù 1¹SÔCOX‹qÏw…ãåÉË4à‚al=¿ÛîB‰  ,˜2Nâ8™Á`Ÿ',ˆßÝ�IJoüõázWKÓ½\v^\œt¿UÏÁã{7˜1:O`ä ènTÄ“17HÈŸNúôE%¼»êI´âÕ²J¢¸E™—~Rò6ñ£ù«°R¥¯v ɬ•Ø;%C½‡6ßa¨ý^ºêÆ ÒÒ8È\óò†‡‡±ðQ%Üry˰ò¢œÛº:«\¬ØhXs“ÚÃ3 õéALpÜŽ¯îÁã(+žÃ†¯ôê¼T(4¬Â³ÿrª©’Ùî~ðã«2^”,ÅšÕœM¾ 5õ]aÛ$ÐhuÛS8F¤ãæS¹×qð›o;o¹ š©m€/B!ýÛ}LÞQ ÷–B±pV¬çÑ8Þ<Üv"‡jnT6-KMc’GÏ£üúרu™ºfÉé“3¡lÛzè è!®ÓZi΋¬Ë«¦kmïÁȹpzÁ9WÛ$3Ïf‡ ðÐ9HŒÐ¤þÜXÕìC;–Ru ܬpŒ<˜³R—bÃBqòbÖOjy¶”¬R^Œ™»îà~—ÝÄhGdõ~�½ ªvV¥ÿéj¯T<è®”ƒôß0<[�ØçI R»1ªÙ¤ƒPaMTÈ'áÝì¹¹ÿà —:¢ñcõrâwY ÚÚB ë³ Ý/nÀ�G€oóØÓ;Nf�ùƾ÷Ì€�S£´MÝ�äœwÁ¤äFIOÀ‘µð±µ$ï‡c!ŒpÓÿuµy`»$LOF¿€»-ñìË«úf Ÿ>±«ô9Ùwrœ…Ñ5lÙs þ:¯BñNJŠ«O°ÎGCÿ`%n¶™À™žßèИ<·Ï7¤Å?§V…Ó¦Ós—·âè¾pYʓ٨L­dÎABš.[6†f&ñŠ’<|ÖH‡9·´!#ê:�ºÅnÿ�F/ìI€Â£rôù¤v¼¹#—®|AÅû¯‚v œ:βûoBǼkpjëÈð›œ�qéÙé�²ïÇ*\¢�Ö⸠Â0íº1-´ 2$pšógòòÕjTÍ�UéÙØtP˜w­»–\c{¤V£FfÔY´‚䵤öL2ð?=O‰8ÆO'6hÁ´°Râ5°§Ò£©˜Œ›¿t’k—cáÈ$ì;°”èO$2«—ÑéŠÎ`õ%LæÕ“}’Aàë üUi ý•~ˆàÃë¡wM{_"¥Šz4=#œ~™{�¼Ÿ‰-ï‚ðéÆ\²äùVºý‹ L<¼K| ‚’Œ;6¾€ubÐÔÃtIÞ`Æåeðó¼E¸ÀI Lc%èoõéÜãØ0»¸~Z?¢­*h»ý*µïQ‡™ž«Y�ú2Xô•® WÁó’ÏA›þ~àhZŽÝÇ�qÍŒ|hóš¹¼º�ZyHÑ̯ShÇ3·¾�H¹9AÇ1œúËŠ{?ÊâÛÐ#x±í 5ÌOcsüÐÇp_[g€If=3^£Û6 ]í17€Á¥Ù…/’=ñ_°bf¤ÛáÃñ›èüå�™’ð-8}VpT…Ú‹‘¬o ðhM;ûQN˜çuÌÓKªPk.ß½épB ¦œü‚™Ç?2›W¥`£S<ürÿü„‡×cõä¤7Ì“èÏÉÇû¶¦´o®fúL}À·ÖÈK4¹òxò³Ëeƒ±DE�çùj6­[cMÒ¢æÒçc!¸Â@Ò^ÒËÍ(W_Aß'•±íNªm½"øjý´3L½^×BUœ Y¢C0eÆg\´9�îc‚v.Ï"‹¯m'æMáÐÞ$2 6ŠZõn(-šˆ%?31"g:†Å.ÃÍûø0á^8ÕÊœ !UêÜxÆBxXw ËŽ~&f;Ÿbk¿ýútÑþMÎÄó�Øuy,’2� D\Ä�ø:®Ï“®tgt Ù¶g&ÌO”¢ºj70òx%æìä$Ýna þféâ+Ð{F¯í¶§²Ó§Â’Yòp-6r®§Â%+>ž>Ù…F5°yx{G“u­Y¸âÖvÍï@LO°þ¬…¨SeŒ›W~Á£Š¡(ºâ7m ½‰a·¥8©•¹hø#Àòè8MƒQ�Y6ÔÈôúèá8ÉdjÁðý8¶ºÁˆ$+ÏÆûäññjàiOwaºŽP�Us9óÝgÈÀÁ5ì²ÍÛÉ)åp$5ˆ ¼BOWÖ^ŒßXÁö¡ ªao�š]HÃn9RÇõá§3ÉqE�‹ŸÄzy›`gþ~¨:2Dg¾5@m­9K:îÀ¨ãJ2ÑÀãmZ§ “}ŽƒùÉ©¨~ª�±k÷ƒ†/ux¦#¡´üãG²w‡-=…[:óQGñ36heÁ1ÅWðtq$ý¦1‹Ä1ãüç<“®°�öeSrzÂW5½—@¬L™c-Z ÊËÊYË\)xü±ƒží4Áªä¿äÇã �ö| }’70ù‡+sÙ[ž;>ü L«}1_<~µô1ÉFaxXí=Pö r}£4û¼$/r§|¯ŸCÊ—ePyÑNhÚ›ˆOKéÓž`}:&pš:4±¨k1{öî‘¢tÃÂ0|H‘W6”p½H<»ùNíÈGÑ (˜âø� ÛËž<6Õ,n~¼²®¸÷ÝQRÝF›âÊp…ó*:Z+ ¯GÞ‘¯âÑô¿'⨕$ Û™×sÿ’™×ÀPÉ–3¼ªU˜Su„Þ¿™ËÆzÞ¥Îżo�shî…{8÷T(YŸþ–½ž ¿I…Ù¸@ 10´¡v+j­LÉØ*d6¼„ì�XØŸ§Ã‰ÔÃèuÝxï¦*n–#Ë*Ü0.ÉËyø·'R T%À¬ïßí™—'˜±GúØ|È;ÄóÉd¡)XóEjî3¦*þ°×` J?£î*0D� ÊÖMtø›º%³ÅªòÚy‹±œ£‰'¯�Â{mZ¤þ$«âÐû–-í¯óÇ*>^ˆ�3°ßw¼¦Û8Ï:¼WPáËܬ5lÑÇ}Àÿ+C�ô~:ª »–í%Ž ûɶéòpuU8‹š$Íá:Ž¿}ʉgð++ÊV®†“¦9d¥ÜZ›/Ì=ˆƒP9�ÿ;É·Mÿ¥Uø³j/t§Iá{‡ ¥ÖõÚ ¶Ý¡ »,ráä¿]½•ùK¢¯Ý‚¹œ F Úà—¼@�9.Ë ±Ì)­¨˜ïóÉÇU,FF< Ò¡o1|EjLnƒÑøý™™á›Šy³ƒ«øf,Ù–�¦ 3©wQkKR-QGÜ™“Aµ0ÔK6È_!Îë/`í�I¦�¤BS HÏŸ‘܈i¾…ôƱé¼gøàåý©¨WÔFû"QêÇL8¦’fvyÏ (ë±å•ð¦ãÔ}ê\þ­ŸìS‘hæ/†’Ž—1ýŠ<·Dàížq½Ý sg7‘�O“áà=+ˆO­„÷G: gp6UyˆzAÚÜÛ9°àûrèÿ.Ç\ø»tÇÂéü¦Òg‘D{WbNð_*·e&å ‚�“V‰ý&'v6µ‰¡˜W ë¾ÅåOJ[ý±l“,W¿à-ÝÔ¢…>óbQYV}�a¸(qžý9aO‡‘ˆ¥h©¿™H6§Òwûs±6‡½â&H¤ô–€c<Å{MVèÿþI>/ �wfйÆÒ^‘Žƒz³©ùýu ôO��„Ø{–õ¨:/Ÿ¨oÁ}•hï*Â%™1j9›H¨˜)á·pÂkR'`e_!®Û•Âprt#ÿ˜žS ¹z)”çhDª�kà»"qˆõ‹ڇ§Ê$©»§¤øE€ž±;X_)eãŽÛcá'ܼûŽ>ý€9ËŽÑ囨À9Zþ[š;p`I«è/=æ| >­(#7 Ûr6V9^Ý"CzÑg6¦ûF‘´6jàz…Œ½ °(‰8=;¦§B”ñBNÉ8 ýƒÚn/ðT cZS =êönéÀ!ë—°³Qæ<ЂTÕRrtÇΆb»¨2²r‰ëúCäEø9Ïê”�•ǃs·ÂÚ›bئ²üHü×ÂÝ ×w„î,C³æ4¢y@Ç58î8;-V®ÿNdc 6cÈa”uåG„Ò�GËH+Ê‚ÝÔt¬=‚Ñ}{1#N‰T†û‚ìàj²Kk 8ÎÀƒ!wá¨Ü 8vK…Êy?Ãõa3¸êmX:ñì�gŸ¼8�gÎÁM;‘_n tߎ™6÷!°v1Œ«?… K± ÖQ× £ìçlö#‘›“i�A�gC¡‘”àg›íHÿË+~‡cÒè¯$îbk^ú«N[=uhΧ7äø�Bxµ]”ºÄÌä=N×AµEá0”Ît0MÔGíúËüI¥0X¿g&yZ€Ð,{h¯i!Öûñ÷ÀE0 C•nJ¶FíÀ´Í8po„�hnÄ�ooRû;Ô¸M|VŸ†€yPJß ý?…Ò«óî⻚\ ê�†:›Z|0[ƒðÆHºÇGšZ"fêGaé�½ø§Ö�,µ±äÙxÀ»}Np¨?ÞD¿¥’xøÜgŸÜƒ�¶Oƒõí»ñà´é\íb?º§òLþÝA;ëŽBι¥xíˆ4'Ÿ£€7×:£J½)<%â¸îôB°JÍ!{lÅ‹þŸ˜­Y1˜]©�“Ž”Q‹Ú$¶éy„aŒ±×{ŒlÂÕ¯Âp×1_z�@�©ŸMU5|Á¸Èíüi�‹÷!rŒ:—WQò3 §Ü:¾® ·#N^n†²K“¸_Ï/`Û½@4ìúÿŸì˜gI¦e„£HÐ毿 /ÐÑ�Lq[W2¥ipgz8üGW<áF¥¼ OàŒ, ÁéC–è`ò‚e“Â`ìÍj$ñ °8ñ })¡M·ÿ-¥ÆÉžÄ%æIÒ C MàÚ ,¨EeŠín$¶ ºý÷ˆGäe2ºÂH…/N.ŠNÔ OÛ¼ƒZ¡qÒÔ#Èuè �ŸÏúi”q'æïÎD*²ª°Úy öò^¢}rõì|ÉŸÓð¶äSÂW�&§!A+Ì̈È«È�ÉeeØìàã²*Œ²s,Üvˆ�&¸‚ë¾�÷´#8y§0§·B¼­ Ù;½”e®’r‹"ðˆè„üíah RAû‹ŒÅ¯9 ÿkŽ]�Y=>®F\ >+ò.}J,øHeõÀS?›qÿ¹rÔ%¸Äç}8£O�&ìùA�ÎÊ㽨5äå^eTPé÷I•¥å'̰äämµG%ÖßGýÀyI‘å=hü�YÛ÷V׬Y�ÑÒ(9& .íòh~·†&‹Êâ{Ãjê¾%…¨WÝ#K‚ÂȲ”7`›«ŽÃAnPûº—ŽIÍ¡‘_3×ýu@N`˜¸î?Kòô”¨Ýst¨ý—K'×3jš%tøñ0yœJŽTîƒÙz³¸È¹ôÉ’b,¶Zˆ¿WÓ¥ZE¤ª§‰NlöCþ‘:b–±ôîó¨^ì:îª\ 9p<L^!«$@Có£Æ k\3(Gέé#þcŸè@çTª¤0�_Žn-'þîoɪYBx¶×�6ù�Ò`¼u/\±÷�A,ÇÝ�(åóD~…ZMsPQôÆÖØÝ± RÑ›èB{X(‰šž�Љ`�Êa€ÿ At_0;ÏÆ m”s¨ORª1âpDn„xÅèâµìÆÒËe‚¼ý+w@Ãéý؉¸r*øµ±é.'¡\1š. ùDgM'–ûa×Ú7ôÍÆh(Ÿ:N„•ºØ…üS‰aಊ/)ŸìKö›CŸêJ¼óK�†[€ÍßÙÈoÇGxƒÄ&| ¦M?M¦l¸Ž='cÉÛ3¸÷ã*¨¨qä*Éžì�RÛÅ÷qmìsæÃ`l�ò{Þñs]û"ñ²c)±þ�·/%¼„bzoP‰ßå‰v÷L@]4·.XÈÛ7û+1Ò¦ ZÒNß&,ƒ™¡ toåçK]‡´Qƒ·r]2xT½'#SQèE?ÿÇÍ^å)Üíü”ZºôcäÒ©˜½8‰tÔ àñ]n½®©µ_G[Ù'Xýv Ì}øßDÛï;K.F[Bï�ëÄÜ~\]s‹üÉÉB Œ»+�g–'C÷Í£ },�ò9Úóöb¯¿óJ΋)ð(ÕßlÅïûäõ¬V:Cµ ãÞ³‘‰á¨~\ùE%ðë·åÔàoÞ�‚CÎawÒi¶ã9<ií4T�="›¨Õ¢fx×�/¨Ï15jóë|_²�óœQG/”ÐÿˆÙQÌøVF4fà¥_Í4ÑEŠèMêfB�‡™Mr¡HU‡º&^§Ó/„¶iNfü«ž@¨©%qïÞKŸTF`³Šž @t\þ}L•QÑÕUÿÍ='ä(©ïÍ„®€µàëq ¸.È ,n•4m�W8ÉBÞ1á¢4¨‚Q‡Æ‰­–Îq—ä U*aÍãn²Ö¥Ø1Ö;¾¯'¼Â­aŠ�#¥¥*0kZ äü«õŽ–ê¼‘+%´Ÿu†‹¶‘XŸ Ÿ×º²¿ÃVÀ™|D¬Ña²£Ñâ§Þî]‰wßRüî‚}§øé©,GöoåZì´_+… /×B�Ÿ>1* ÞÆD¤lÝ.}:§íǃêœõJsž°e6”–OA½Äû8+´� 3yLœíê1üÈXžÔÆæ…¬¢›þ,Ä?-�/Zˆc®åÈßoW·¸�Uo çÇ=3SðÍ—>0°žÀã™ðöFl÷ÌÅÍÛ§€ÑܽÐ:h�“?¾fÖk_ÃöÔ-ø³&î]t"æÂ]TiçIfóô­ì¡¢s°ïr|£&xúòt®O!�8 rgï³Õ¯o å™ý»¹gx�TúnY!ÜØ’Șž—çõ¶=¡é'ªam»<3çÙz]t-ò¾’i5ÿú‚äôì¡Yí÷ Ørˆê@ê�½ðRN�YµK‘wL™WÜËÁœžXÖùÂzÕé që|/Žñ V]+¦G-¿Õ¬Âi3`šÐ?íÙðÈ’“¾èæMŸV¬¥¶SÒ˜­Úy�ÐO–i‚£•8·SqþœŽ%/#C!³+¯¯rdšÝ¦òæM� o·pÏvëË2xøµ î}^ËfeÞ´‘oÄô¨ÈÁ&ìN’å†h¨&ö"ÿÃx<ø6‹”k�ĶðÉÐ<ׄ<ä‚Ï•7BUØ"Þw%@…åçA1v¹¯7†Fã_™Ž¼—äÂdwꦭ…ÓÙ�ÛÓ ¦Ñ†¨ÔŽœÝõZ‚o€�«ŽT=Å?¾´ß⸌oa<Šˆ¡ù¨¾>× ¢�Ÿ!¼Þ/‹+¨¾Þ®dQ7ùdµ&¾¾&{ßÓ _ nZC%±hºˆ;žÒuã�TçX)ÖÍÃØU†ð­ð¬ü½â´ïçΣ¼8¹h°QŠä½8L¬*éÃîó0°=›]®Ü‹Êœ׺´˜´µ·•C–<—L%¨ÏžAfù®ÀÃÉÿ2BsøÌ¾ˆSs᩸2<[»Š=Û¿‹ Öã$m�·m¾˜?†¥[б§|ù»y&u•= j4 ›Ý¿"/Ú ÍçS��¯Åk}ÿO\ΆÊ@÷“ïd‹�"ø¹óaf±)¨õÿ‡áÒµô÷°!/U/$eÇÉܼ<"óâ"‰»TÏÎ/øCÄUCéºq³ŠÛ�`tfHêú‚):•Hž�À,W]^å÷{$VN—›d Ž2óyç$%af�,'¯™IOøáü÷A¸¨”Zð6øs›..Eë¶šú|6˯º#]€wfð­}EdCGÚÂ|gÃ=(½ò´‰+¢f¤D?_‹²·”ñ0ßtþŠ`¡ •ã_ÀËñšOM 1MLë-E™RqBßi ]ˆÓøhß“wÈnN%*&¡¸ß1…´Åjpß¼$08[ M”Ø�3fl¯ –Ô˜‘ßn>˜Ð´ ¿”Áܵa8:+½ŒÙÜ~£™OjZ„0‚½ë¹wÓ;(n2Î.c8P¬s„²òt®e>1Iá=þã�ÃÖIdÙ­P°»—‚› öÐp HßZŠ¢BF8–ñˆäžö  Üù6_pcÇ$Úgþ.ÜÞÂ] °¥2+ƒÌÔâ{àåL)öYØ&uB”Ûõxrs–RŸi“x¹ëÑÖsiQÛ iÛkÁê\ »éœùº¼”�ÂÁêÐ}fnÒm }LýŒëº‰Ü—<‹¥Ûæ›âóEZÆGQï7YÄà¸"·XJ;ë `á‡düôã6:)™¥uˆ �ÞC—ï Ã9üp²ÅJ,~u�‰9«ÎØpŸq¿YÏESpÇпìHM‹fÒ㟭‰·èRfÙÊ´Öè$ë]DK‡•¼‡éA íî ùy ïÖ‘ãÁÖdái3ÞΉl’³¥v‘ ¿e¶óÇ}Þ_ÍræýÁÛWçÁ¨„#ÌÎÍ#¯F²Éü.~œ™ù†fœNa›Õ'‘¨I.'ª—´½j¦’÷9 »õS¡ÇÈ¿®õ…ÉŽã¡pæD r—Nå‰nyJ¿G'£¤Ãð©HAa {øz„%�B‰@¯ÌùŽó<ŸâÑE«ñ¤û¢sÑcÊFz7Jpè5MÑÞM½E¸­žSx.ú":ù6”gÀÚu’¦è‚Ë�ÁØà6ùŽEL×£&œÈj ‚Ù9øÃÃGÔáåä T-ó n t#ïï”"Ù)‚-{=ÿå†zè\0tiÜf›ë`ƒã~ÕÓ&“�¡o¦S(-Ê1å$oR�ä&\¿ë PÞ�‰ÔñÌ$G*ý¼ÿÈÁ£›Pgûm:‚aÙÍÝ´½6‚,_} õÄþ‚)¸x­.íÞ¹N¬ÙŽ?(rKë·ÂóϺ<· yžÜ?ÿN)Ìcv܈3EâñèÂûâ1yúê ª?Š^¾a(µÃ¨¾œˆ¡øÅØc«Äx§ ñëÆTØxò?„ƒº’ΪÅðéÞ4¬+¥(ã*Î+ c'öªpšMyô¡®.›xóWèpã‚“‡ ™½�:ûúA¹A”·ô„>�ó¡l\ÂÛÉ[`ïÙK0¹Õ‚ØÞºˆ1‚šœjü)4 Æq¡0PNÝ�5¯Äðâ¾Yøµ¤€Õ]ôüŸ+à�‹IxÏäÜ4ÕÅ}989È’+x;�÷J÷?ô{å�ê^q(áCPÇnQ¹Ý@®l÷Ã=;rð«Â6ül=“ܦ�”ZÎ×¶¨µ§ n_‹!Y‘0ç϶§ùìÝVKL*|€›ÂÇEåÜÁ¢Ü9¸. ßh—2Õ«ìàÚõÛø½äÑü¦Í™ð·Ò3½_ðåFK¼ô„�[¼¦žùUƒóÄ„ÐaíuôuUÆøé×Óh’ЄK£0¡/ÃÆ¡ÊRGÌÈîŸ9T=‡Z¿ÑÝ>Ò¤a_ 9 !ÁÓ9}1kñÁÐý´K­ pÞUœåÝB¿°t¸çi}"ʵO,&žßùټي8¯·ê4¹S§A·ìwš{I�'é˜Ë»¢-ßc_@¼7¶Ñ½¥…ð HED“™‰É¡�߯Ìkq;&ƒMtYÁ qû£ �ßÕ¨Òžep‡ï»7*–h? Š}¨ãù†=¦²ö~$îǢɜ¤E¼“™øÉR’›Qr—Ú~6džl%°íO¥^¯Kˆ}LuÛø�†ßðaLË@ðž l?z�ì¯/©f%,-0ø›j{5�ÖGõ;‡�URÀ—„ó:ÇÍô¥“ã*v4_ß�§Ñ 34Zè¸\\ù�‹Uìɨ+/KUœ7’ÔDiMá’ÚHÇ̬3û„'5–’šVI…Ö�ïÓƒdô(oŒš!J7sÌ9iKqLj�©SbázcixÏ‚ÖG”vj$š¡�ÁóÕEøÖŒüzÓP<ÿ!^œE¡í›%×±®Œ »9±V¿?ƒß 6,:F‰È}’$½Ä-nâëÜB6øÉìEm”^査«©k°-�äCÞ¾¿O8ÕqÜxb ³NY_5�CýU)zª×„Äú¼ÆÞfd­V½6‚íƒ#ŒÓ‡w”3nfoÞ�€ä†420ã‚4Óòþ/{Çw†Ëõ²ûó“h^öúW/w:¿†Vél|Ú¾&Sq.AäÖîh¦r¦gáwüfvËC8¦ kîŒ�Ι'AV‰Ù‚™•¤ü^ T{Ž‘Xeü«¯‹ó‚ÖbÅz{:¢zözaåØjãpW:¨3ešÃÄuÜžM s£Ñ¼—Ä.¯˜�Ôòƒ}÷°nª®#·kÂ!­*zÿdLº«‰¯¢Î°Ž×? s)V%Ë’úŒ²µ“ÈnÍgô]neC§Á]cä]@½M~Ì¥K <þ"FªÌBA ü)â#Ø–*BûÎIñÈÆ3Å�ä¿C_éùå§™-x·ãw@ôŽqXPu‹ÆøD“À5ù(žÄ1]Å’=×k’T…¨—¶@ñÆd‚ìd^Ó´-pGæ¶öÒ¯¾¿èì²¼[ ²¼}žKáUõWÆJJ…:�‰‹LÞ-úâ’\�{OÝ3 ·üóì|© ?Å7’í IÓçfPÌJ…ÙOJá©õ.pz¢@¢7-…3“Ðø»,:û=ïIv³WŽÊp§x¶h5-œöGÒÅÆ}°ÀÍÚ]mh¾Šnp‹'[—šÐàÙLãì5ÜhI &ªâ�m^Äon «Á•2ݦqR•Â`!y€œ�ø�¯×»à•ê@:_ÿQY‡áŸêõº~ÔÑu€}Éßò�ű$¢£˜Iª9KuAe6ÅÈ^O*!¦Ë-M×�ìIYÄ.Ó_ÍøJ=¯ÌãñGŠóf†ûCÐ]ú±Ê ÷{ûR›Ñ*ÈUa&"·òèñ:LHÂk:QÐZö¥Âΰ «Ád¬�l]ýë•”PpŽ-v(µ.ÌN­Ã íôÛÐiöÀ¤Kø^ÞŠœ˜¿‹®ÝJV¤ù“'MzÜ›}°aÏ¥Rß¿7ˆÿ�‹0¶�B•SnáCø3ÃöÈ óÝf‘®žPmœÃ¦4÷Ð[Âèãy¦ì7Áµ±6{ø&ü©­"ûð¥ü}ü'NÓm)Ëð¬Ž2hÞ‰“2ÍÄ�âáï«G¨�ušt½3bJÖÀ‘ìM¤ïhÓá”r®àƒ^qž†~1y%ìBó§�„¹½ DQåIUÝAÕžÿåz¸óu%þ˜x‚® Âý�G‚ˆ(Ïü‘¯¶B@ˆGk§§àìÉ~èùߊÍTµ¾ õlãàtèI<â/]Z}ó_M™˜Ž»c�÷ ¸² ½ç13›®Ð’£>lîÒVh¼ÄÃùJø{…3yã`æaùÏ×–ÃÙ«®pk¨ŠÐ«1¤Þ¨é “‰�98p:Òc4Ú¶¾=]K;n¬¡:R›ã Ñw©på <1�'·ý;³¹#�•ƒÙ±ÐÝ`ËO}¢gÂ×haÌ^šÉhíÍ n߬aÔB‘·É •‡µ _ô3«vQÝ5Hw¥ÚCõ¹r›tþ*£ÒÝüXÚ-‚˜=O­Wê×-tÚW2Ù¾ùë£Zh*ðþ›ƒAXq*غUÁâ¬�fË\PçZ.®[]Eß§ãºè °j*‹ì�âbñ(ãbM]œX{ôt#!æ¥?iô5_zÙå-í]v™)q7Çýù5ôk´~¬¡Odçá pàrœÜFT†3Ñ^Öš­#›1ºìÝÙâ$?yâÿz5�¡÷ÄVÓ,;~”8ÝUÀó…NäÚùÛDº¬$äw€ÁÒk4[ß?=×&³_Õ’ªÐTºvçGfáw\ñœähVâÍÌZìt|kð„ek¥S j³¦ƒàŽYlÿ5b§½€²F»Á´QžŠµÄâ²ö9°ur:ŽÍX‹ ±KIA nõÏ£‹uUqÄNŽW?` V0裿þ“û„C-ãÈ®¹ êkÚÙ¿Ç=áB° É VàÄÎÆÉnŨê6£]8ô¦µD-Êö œc¥2o°DGéû€R»+9h½F€7þ÷(x^~ø_+·ÉÄ«g€Ìtw¢N“rˆfU-R¯¦ù×®bÔ~ dj~Ó]-aзšêWÌýi—à�ÎR!€dçBixm‡ç6úâ�‰cÀ+† Ë£0óEI7y �ÛñßИþ�õú`O6ñqÝ3©‘è“Û!–Ã}˜²ØL:‹¨Wq$xY\ƒ¢Ô>°ñÂ2=S^úžRàö§[õ‹ŠY³ã±äÆ·Y¸L꘿Ü޼iòçäiì…ƒèw& zõß2K6`Ç�9Æ éÐÁ’m°ë²5,a=xÏà�Ñ0]ad‡‡Î©§¹¥�ÃûÈð¹ËÔ.,„^(q¶�+©å) Þ~Õ|zèž(õšN»Å¦‘È]ÁxÏOÏËÈÁ³�ÉP2¸†¹6¶žÄéåP½_1ò¦ö΃•]¶ Ø'�C‹ÔðÕN;:gÒ$Ô_'K P=¼ än~$¹¿a‘Ó*±_©êž÷� úę̈\²•D�ž ÇsaÉÃí%�t–ÑÕŽîÕŠŽjpen(îQùD²”e`šê%HOOM/,�?u™Ä{º'ûµö˜¡âGCÖß:‰&Î�ÆÂn¼š¸žf]t£1%ÄìAÇÕe4Ùí ©ZvÚµ[‰ûÒG´MÀ ·äâX4?쵈2+,×Äÿ2æ@uê²{›.×áWCîzÍ…ÅûO2BñG™˜ÛžôÅêxvEÀ´ß@+ß<ÃÖ…Špòš‡;×_Çmef¤ÈŒ¡TŸsiQi*¥ˆi§�J2Ê^eD¶„¬DÖçÜ_) á’ !IC”z<ÿÁ9çzßïûõº®£ÂÅ/é ´D׃îªâá~²²DøIMÛtߘ¦Ü¡~¯ø1¡�K>|¢C%Ì÷K¾l]VNëK&ÝåÙuI5Ø0ªÈÙM«ˆÐȉ ºdñ56¾YVÅíÄʃ üê%w_…7#ŽAÀž™Ü�öwäÏr?ÜJè¾’›ä þ„éí÷ÉX4å ±k¹ó?U2êž ²ÔrW‘#vû�#Þ…ýÏ—P©e¦í‚0^ø¶”pŽ&oGaùõHXð¯œ+¬ñyØ <â¶Žô9û±¼¾IdEáwø‘~›ýT`E~?ä¤i @qEIH?QêH-Ì04‡áˆe©â,Å@Fh'ëD¸UJ!xù–6½c•L>¾×-;Ä‹ð× �ûC*Þœ‚»Bxño¹òI›îwú@t7¬£ßâváŽÎ,âT{M<§°dô:6¦Ý"ÞÓÞc W‰õ™F4_çÃC�ÝDpýN´,²†=jÚp¡Y�1 ò#¢òoaWÉ *q\ªÉ2…{bÍgN‰ø`ÁHÉVgoŠÛ�˜–�øäC&ý"H7çÊ0NÝw`ᮩ=œ­� —”…Ü!‹å‘¸Éðмô»8>>&fˆâ§g'©Ëˆ -Ø‹Ÿ}Ä»¥þøZÙ�ž8ˆ×~µâƒSïqOƒ¤Ì[„Üw‚pñÜ1T•tg®Ü :¿Ž,‡¿C¡ô¼ûUºÞXÏ߯bóÛÕ8Ñ¿§œuÔ…ÎòtÄL“½lú‹ä‚U·iÇœ–gލ9¨AÅÕÙ�3ù–Šû‰“Ǭ+wUäª È:É£À�N2ñ»Ùmªu¡ XÍa“µKS0%_‘•H¤ûoúÓ˜OhÓ›Jrzà Yf¿þrcˆÄƒ º)ƒJ¬%´ ÿ �ÅœöÀ~ b3�”÷t$F¶Zcú†\X0M„3$8�».Ò 5äïâúè4ræó!:»ð<]b³r•˜óuJÐãîƒýù×L™£yŒ´°2¾î; Kßè’Ôóö¸6a”î<<‰Gàí”?.S §n{Õ¹›uÓ¡Bø~ÖOƒ [!¼Á1±žso ¾¨"ÞÚ#ȱѽJæ6–½5*Ø.Ñ3'÷ããÚvÒ<-ܧÉröæL§……÷é•‘+X©^�n¶,ûãôsúcíXÐS Z¶µå)0Åá'0ñW2®2*†¦y)dëÂåe –z°ëÍ®€Ü~ŽP÷f´ Ê¥ZO’þÊŒ¸âG�lלò??r£ú/ŒKÅ¥oHÛà~š¶ô³5ìÝðdÒç=¶ß€öU"4l÷1ñ«¶›ÚàaÛV\úaª“›àiy54$󒳩RtÖ[’ 0ä!5#ü$íïVøYÑ¢†Éx:ó8ºVå33§U@¸]•À«8Ë@‘–ܾË.œ‘ 礣ªb%�Øë†zû®Á%�v8ò׌¹)À]#0Я Ò_g£UEöÖ‚gÞ´m €l^/¬?ˆ•ÆC°’n&«ŽE¡O`(MŸÍý™- ïÛitw°¢ó8˵_³ÂÓΡXT<ñßËÜÛÞC}SÂM‹Üû±ï‹ mX\ˆŽG"¡zz*ód˜Ÿ¸eù‘Mviàû³‰Ä Ý/wíùËn[6BE %`·Þ-Ø–¤A¾¿³Â�ñBÈ0OÍÚBÊK‘_¿‘Ô¯~X#·†<ª°s–²é-£H´}À2ñåÄK87Û¿#¡øs­iBd#N<}@nExá¥õ6ÀÕ7]æò3¯~ïF"|_’-tº@Îä,˜“ŽÎöp¥ �>ùvœ˜8?§½ãu°Šã‰Ÿx1Ïó8”hJо–w¤û?9LÚ9‹ûÄwdÀ(í¢ ”ÈšÚ8ÿÇJ÷«õÔÁp×;Rt!4û>Ð/u¥tb:?¬¼ÅÏšžÙ ?qé²p’+už¥ÿþ¯u=°£È‚ò¾‚Eƒ’D}Wnp DË*è“?®è@ß�`ä¯OF=IŒw|=õ6B\Z¶ ÂUB‰ye/‰+œÆI+SBöÛê,¿ñË{²«Ì _Þv¢ mW ÃK�»\l½]^Ò7•¥ETâd2ìçúÈå'å`ëŠÙx\ë�ÿŠŸ+Ù¢F×OÊBШÛ0cTÚ çз·ÓÁŠû€ô9ýa’E«ÈQýXÐÊ»Šöª¢3åó«’±õÊXƒ~,±¥ { iÌ¿(êªW 3�À!G7^©�ûәºŒÕP¯-À­ÄnTy}½}\p|Š·†ÅQMqn¿ çÔ]qƒe¿4Ä-}x¢½”*%âíˆpâ&¼˜š~[M?Lk¢Ûl8h¾UÛTHÓÇjòÎî?rÀ$ ®Ásõ‹°ÜëFšä’޲»pþ@ñ?ž…Îù|äæÚôüöMFîÄnl�æ‡U’K‰Év}L{ÉA%_u !êÜ(‘"±ë/ùu_SG¾ÂñššØ\ ! qÖyQœOžÒøâ�*H‰ñx8�D…ì¨rû-YŒ¸Z4ÚZc•€-~,ă‚¡Tèõ'ª«ÑG6¥ù2ü’\í]HI’0§z¨™Ù+űâûC%NËÒš¡¤ôà” ·Ê‚G| ¾uy‰�O<Ø™+©Dj 4Ïxœµ«¹‹ EðÎ4 ¸tŶÅÍ$ /†Ãêeå¸?¤ùêôàMMî>òŒ¸­È  ›]�y6;þD¡v]4[Ý÷•‰ÂþÁ!’y$Õ×z‘÷ÊPÞ*ß‹¨°ƒ5;ãßj¼î'9&#Á¹º ŠnfÀ’cò` ÔÎ䮼Ή(³%ù-À]Þ{�n¿}—(0ÍdÙܧ˜ãòƒ]_±…UÿåI.Œ¯ƒöu‹MbÐ Ê·R_½Åä„ ššvYIÔ"2iD\(í†ÔÄ%1é¡=~*Á•–B Ó“IÍÖ¿$�©89/-¡ñÄqÏ“ÃÁpÔß”&½zAü.¨áC¥�Sì]�+Óñ¶–rÿÂe*ÔOQ§¼çP-YøU Ž;ȰçæË럮rVðm/É)9‚î ÄŒ£CT û ß%ä·Ì¦�£Z ÖmœÕ~´ðÔ IÕ¸ª|;pr8•„ý{@ãovQ³�eèøl€�VI¥›R¡Ì¡´²F^ áÁ”0:ùã)\ðßs*F‘?•BKÆ'ôõ ‹�ZBÖwÈ’0"¶±³Ø…Ù ¬Æ’Rd”ÃËYõôÂä4t<.@ÃÛ3›[×Áôqî[5gvÉê/ V½ßÿØ òQ#S3eOyé#ŠM ðÃüMȪo£ÿ¾—€ñßtüâÃ,MÖÃ’Ô§Ä‘/-b/Ú·¿èлtؼ¾� ùS>¿ zt½1ý‘~ “ô™®ÏÄK±¡LÀð6nÜ4gMßžDýw ðûyâ(—�uR é»Mè%à èrcõ]È4$²ÿcž'1¿n�`1pû$5š7(kÀ Ô¤d %9‡ë1O\íèÁîÕs8U›Ôà†š2‘:Æ�¼‹2ñó/\í`§Ý"á—«)Û³¿›0d.Ó^må»cNÇ—‚qšœ›VPFÏU0ªßY*^¡Ì£(|˜Gñhþ|òr×,8s+×·`aqM-{=J¨e;ž‹¥�–ªÃ(ç>å5¤@Ó�MõôÂÔíêàu[Zvߦtw›þr¸ýê‡Ý±˜³áé31Ú[oD.–"v\Ç$![xØÕCüüË´-²ôY]êODoâÜ™êøáž48l ¡ªÏÎb£Y Ù8>íSx ^êIðÑVœT@¨èNP>?ØrX�Vq é˵“Tºø.¶ópÚy›ˆVÒuÌ<á…ç-аdx”=Z™€ôL)Ýÿˆ<]qf× #nYÂ|ûîiä½”"w˜-f~×Ë““7£„³ì.fíªEÁIfìÔ½-ºýDso$í°‰ÇÆ]òô±N8¨YfÃØ,X¤—…«æN²§nÂ3£ äÕà(};j´�håŸÂü¥'É�‹«àáÒSôô¬{ðó©w$ÒŸ_†‹²g±áo].!€‘IäËÑp\˜rÕÌ“AU*UiŽfFwÀá¾]Kâ™QÓUhçí {ÎÞ Ý/‰™Óy¢i`MyçˆHD œšÜÍh}C¨]™I•?­#q“T4Á¯ü5ï'tÏïZêýˆbæÃÇÌ)»[À® 3¼V_Jõ<@ìó"ÖUF†Ë¸è IÒÌÜo…�M³‰¸9�„64tNÆ×dì�¸Š5ú?h÷7½uä&ðœÇx!}ô�ìÇoç’Éþ ¹típ-ñ`Î$ÂÇ#KàR„®›Eú‘µQs§ó¤ŽÒŠ÷‹ˆF·Ó7lQÁV�æº^ŸKÌ–“ÝûÉ_—“xÌÒô¥ïà�Có¨ÒHc<±>ç[!…¸ÖžKÍä�áò¬9MWsN�Û]‘¨iaƒ¯,„9…œ úqTˆóâ» ªª0fµ°PÈ�~òÎ¥)´ñaÀP�:˜m†¼¿Šô_¦?4¢Íúªsf]­|�®£Òðܨ”8Ž%Ò d3è|fo=v‡ge¯IV½½_7—ã4©Ì]™§…×Jy9î«¢U�:I¸UEŽóº1xq&:«¼£“.«àðñÂT7ÓˆâTÀ3K`Ë¥+ ™„’Ôñš—Xe ÑÆte8Ó: ç»^å±5#м×J�þaݪ¤Ö.³é¹�’day0È*:€î–�ôiy(Nrz+~QþZolãK'{&ZðhÀ/öòd'#fÌaÓ›kˆµm 챋Ã×¾:˜z^žã/Œ;¶´QE;58œUI-Þ.g¶-I�ªíéé l[éRø³À„ä'˜€Óuì_®7×´‹ræ–L¿”O-÷AëǦ�“ñ›¾žƒÛ¤ ýºN=V§à ±,º¤˜•ªí8ht‰Î�.o˜ïßb¾ÁÊd'à9FåycÀjR:DX8ÿë'I©TÁG¼�xzÍ&ä{aDåÍHT‡*¾´é#6t$E˜6«FO=¶V�‡ë¹À³Ö ’_¡Äs@ "übM¶6àö o©ÃKWø-ò€ŒÔÌ„Ÿ¢Ñd½/˜—ê íñ|rB[ŒJ×Å•¯ËéÊï Ü×¹“ì™=WÉ�Gó`Ä9–[bB�ÿsy¯µäðÂNÓ륪Úè—Ã0º‰ApêÖlT÷ÐÂæû¡/E>Eß"Ã;¸¸íLÙ1)3õ&uøÊ[ ê»ýÈ««IdŸ·¼Ü<Â%�Bì€7T­ œÿÎÅÎY�ûRG7s†È™¦è¸D½õWƒ‘øe <šH¶¤ÅÁÙ÷Ç�jÊü&ßc6�Öïà—ÁA�†o8gã 6§}¦éÎêFöÏggzçù#Hj¸ û^ݤ‘BDU{'¹;͉™àƒ c Ϲ9xÿÆsXuÅÏÃÞ Gh¦�ÐyL€“±ä Ñ3äÇÙ§[!ëQ53=I h&=þñ½ÔŸ€[ÞM¹Û%Yð7ê&•ÀÁYXAèQüû¸� kZáòÙ®`8M“˜­²�ä�!ÄÙÚ‚žrà'ùÞ¢•,æ¢ýR_B7O¾Ç9ºËá0w’5jÐ…K3½h‹¼Ý6=ïl¬€ÿ¢�q±„'vü¸þ^^P÷^Ù?þ˜}<‘~Ûž‚WûÿsÆ8ÿ8Â"¯$Æcq ¾¾KCN½gïK⯵‰ '�Ÿ¯ƒ]¤;Ë|þTv"`Ù¿aö‡ü8�RäçlþÕB?xÇ—ƒnø°Ýšnw]Mnµäáì´IV†Ï§¯|[*±]…ŒB}/ÚÃ< î�˜…¹¼þhý­z-æüZؤ° Úô;¨Ÿ”öS‹ïöpzz;ÁÒ/ùЦ“�Þ®OˆMæ;¶¿9/÷hÁGõ9¬FÉ´sƒl˜¬¥[å׋Ë÷ÉÂ)§|^a ÓÖ•³V‹*qŽem–[Bó§™ìŠyµTÌ”1^®-ŽéA1˜â)g%2Úö àjªNŠç/æ.EzìzäîNÅ';ØÊù¡ðv™>—_ö©6…°2°jU&$¨bøŽWè¡”Õ§§“?"!лî4L÷¨ ^Ó¥¦Üä6Qý£�ß5VAI-ýྠ”×»Ñ÷ΛðU‘2l9NÏd P›íؾ© Rau¾2$ª‡Â‡/ÈѬÈÄ´<¾jm‹@̶VÛTÀo)kðzž‰“ëÑÿÇlËmÇ»q«aš(/Û«p•jiÖì�0ë1/ÇâÒaœ�h¤«¿P€CqTæ�ºÌè¥9œQ\q;‰zô¡iÖBðC(dŠ]Án�Ñ4Ñ™# ºÛ‹„þCûž0QP¦‹Ê’ ëÃJ¨væ>ÑõF[/ªg¿™ü8’úŸÞ÷TSºP¢�è$ô˜FòÂÝÎo$³g=ëv[’—ú†~Z>äôsmØâ[Flƒß5~´’‘Æ9(öô |)<F·µ0Ø¥Ÿ~Ì#‹5µ¸ì–˜á3ʾ;IßÝ Ç—�&tÏZ~òµ*-²« ßÏŸÆ ñšþœp¾b((•%B'ËÁn6›rfN/Ya�ÆÇ~‚�­/Öíº��öÂû÷Xî:1´7fð¾å[¢ÿî&;+©™F‰m„Œ_>„¨¦ ³¿0(–¬…U)ÈSSBø«w’“˘E]ß1TÌΆ»˯ÉÃîÂÞ‡må™­EŒÁ[Ø€â˜!º‰,»i†²‡¦Ó¦ì{ðq܈üͽ…ûßúуÏ2a•ˆŽ¦F뇱ŸÖOÇ2Eüï.í¿4Ž­&½°ÝÚ’œ +¢ÿ-­Då�»ð”«/Ž�51”²¼_þµ¼‰-7�Ä^8G@ ^Z—ûØèj;Ïüªž‡6ÛAÜå3�ø¨2uÛkº^ÓÈ™ŸQôz,éíÌ„ ª÷Ðæ½(z¸»cĕŬ‰8ñˆß‰Ï6�ÐäEÙØU‹­'ëÈxµ7ìsTššñe�^JÞ¥|fæÿÈúÍñ§F ÝluëGšU'„3d%áfWª~ºJ3·YrØØ§Ð«}•v›Nï(,€t÷Ãh¶ò<Ž©oÃ;0{ß*ütû;r4…´² ºzƪK`Ì?_P{¡ŠÓ׬¡µïài`.ihüB¼>ä�_LJ N㈓%VxD9‰Ö8<ãåÃjj¤û ÌÅXb¡~J¥Uñ¼·†lj6%ÁÆp�G‹êdå‚÷ nÍl3jѤ�æ7’—¿íÑìº>K^�ÿç@t¦(§èÒ,÷�ƒÁÏ#ÈRí"RrКšo¤‰K•éϯ!°âñZðúÛ ¼Ÿë£?^5H©É!ä›äu\ÀçýŽà˜cˆÓ­#1OΣjk°G¥™èiì!˜4�óyu+3ËqŒºð«�® =´.ÒŽ~xÍòWÛ‘U"30LíŽï‡Áœ…&|5pyA9\‹tÄŸ9žd—‚Ùnv˜\?ç�.ƒ=”Ó™…_·QAùÓteà?2ô˜v¼:Ïü�æŒþ^@Û¸'äªôBÒN¯Á‘J‹¿D¢=Oùïv~ bÀçOz}ׂ+KÙ‘“ÚÔBù?æ`´ß”Ó=Ä‚iÉ}ŸZÄùOí™K(¬ur„d ?ú,ĽýB.<,§ºˆËGÅñ[f©èö …´qN4˜û?À¤�ó˜Mþ}S÷ßH–¯Áµ·]ÑL{&×dG.Ͷ�Uxºç8¼_|“V/ Z{èå~l‹?3ÄQûK�Î×`gW~#³å¤°øk9ãüG€Šæœïâ2Êø)Õž¼ŠŠ™Òpbƒ U[|žªýTC‹[äݱ!º%\�¶¨ÎÃî¼"ût8™­C•sž°ù|®Ì�ƒ“ §ê Îó{;zÓiMƒ î´z +Ÿß$Û»bé!¨!Kçµ­þ0þ‰o|î@öNh2igg„›³z×Ò¬ZIÈ©¨ÉŽ˜0¿Èôñ\N׆'Ä4y!¾óo«ÁéøßSt{cÄh£¼»(–I‚Xq&û·Mž^/‘ƒ­=w0¦÷'9Tá»Èî­Ð=—·&·¿ìrl¸trþ~ºf–…R5=”ÂW'mÀàÜ6öò싸Qÿ*yÄ*Á¦'`¡»qÊé¶ Gäw—ÂÌš�Ä4¡�½dÈn(ZFW(œ¢¶%^ϳ$ÅPÞ°jeÁ�ÂÍßÍÄ~¿9sƒ0¡�ž�µæâ˜"î¬ß†¢ð¼.ßd]p/yêÆ‡ë·¶ÒÔͶ¸`>Ïå4±úGÄ9_„)I‰.‰yM´c³±)Þ½§RAFø2ê¨xãÅ¿ehëe‹•ŠûÉ»Ÿöås�wá.á À[E°×~®(ÍcŒÞ•üc;HxA;�ùÄCÃVùÂãÿ–rŠÏFÃÛV{ø}ßÚ ¡|¹ ç§µ�ê<•Å ¥�.-5§VoOÁa‡bò51”nMÄʸ$ü÷K°›'ëá°Œ0ñKmg„fUR^Ç7ô¥$Üܰœwü Õ!(èì�¥-˜øÀ‘y™6 {Fé!ÙZ1û’ë�â¦kŽþ†È| nïQ|³¨“:ÌIÃÛ=çȺÙ(會ÁCUð#Œ2O&bI¨ÛyŒóX…šsá«3Ç–ÀJwYz4¼ŠM®Ú„g-üH§a,òÄ‹'xá÷Boæó‡™¨<_‰›»ÜØÛk°ÒóIÚÛOþòsÜkZ =H�åsÌ’g$¿é IZ`–ŽÙü"œÝw(nn CÉ-âÀ#\‚¯o&‚ò åôµþ5ò'tœì*9³‰Cð#|Ø¥‚WÝðró�²�'Ç_`ÚÒÌå5åÖL|4f™ þ�ÈÇ“*İ^†Šº;ÂØò¤n˜@{|>|é|Íäï‚é)ä�ëaöý™§Œ—e�f~ ‚tÖ!¹=Á(îUå‡Ì2åqÚÓ,M'µø©¼`_™ÊÒƬ‹VZ“s‚°Ëjj&xã`Ôòz�K&¶~¾D ƒ�€sË0pÿ\Œs&Doª‹òSÃHèŸzÔ/"‹­y¨ƒŸ.ÊÍ:K—N–Óóóp¼è#¹vù4Ä*JAši6i¼bvÝ3âz¥ýe�T³>S»íåÈ8õݳm¥î0zb3ÊÖ=`º—Þ&¿õ’ oØY¢ëK8µˆêa(}ÑúÌ$±²£¯‰‚à2?ˆ-.$Ác‡ Ý‚ÎÒÙ‡lÐRV ëMïAoÜy¸âúwAW|P. ܃ÂöÏQd^)µØÖBÞ¬ß�bÚt|ˈö©Q1{J+~Å£CÕ´žâc›Ôuh7ƒœË즊-ýL¦ÚM’&RÍZ<‚7’%$*�böÇæ]ê qžÙIÍ“åL'"îB>_«U^hV¦içÿ`×[CH;N"îäó-ÿÈÏWAõŒVº2û?ú,S�jÜÁù±€ò§ *ÜãN0šŠ¼y©çnCL“ˆòÝ!sGáµ£löÈ0Íno¦âŸ>âæÆÝРï‚ZâÒ°ôç(¬ö¸O“eŽ‘¬0ip½¨ÅÍ:Iרda°™!Ý·¥–V\9 7Ÿ,@‹³.ð[º‰ª‹I£„Û>x å4©»ø&pÎÜ�gl²Àd™�ÿÓŽ?ŽBÅéÓ(×4ÓϯÒÝi‹@t�;eõñë:pR\:�8<æANJÝÄôõ‘ô…H뺉J¢‹©Õ·5ôŠúy�A3çÞ‚›Ì1¡Y /kÆÓ¬ŸX³¥Çqa„:Îüô‘^‹sþ›Âp/`’¾$µñÀyòئœ‚Ïyüð]] i¾|Ÿ�¾wíá ¼ §¦|�鸳($®Ú ÷…Ü“u„SßÝQ´vC0Îн öæ,£m€ƒ²è5-»Œk,ÆdQ~ú&'ˆ®�®#ÿŽCàŠctéï‹Lì£böÚÛ¯¿&£> èY&CÖc¸öxôw™ŠŠóƒî`ª½=LŸ•R÷룴mʯåÜaãË´vôƒ ÙW§8f-,<"HN¼J€µŸõÉÙOUå%�ràöö>Ñ•›Îùw=‡l²ÿMêV^Ã]#CÄÅF ¿-YÀqôQA·1}øî AsoÀµñ'DB†ÀÒ‹ËȄ׼?* ®’¿^‘ÒL™ÙÀ˜\j¥ãþs`3o0n7V`9é”xý„*¤O�-A®YÊÀãu54d8[O›Ã;¹5œ�mØ>××{Ûâ˱EhŸš³ÙõTÁ#C—PŰ0°uœ vÝ<䨵)•º9­Äc»39øûʹ’Â?Y8š•M¼½rhÞ s2i&dÒ–î8ïNo@"Ûq7••ö°Ãþ ðïùF«¥Ò’…ƒ Ï[+%OƒÕ{Qpƒ$×ð�ãÞ7à`ÂOÖ{ï% Ò°£,hy8¾j×Ä® ð‡ÒI<ºé)´¼)fmÝH…L^ÐZŒÇ¥ó(;ÛÀœ­dìŸ 6 �Ôñ#x (”tZ%Mñk ]y¥½\[ZNÆ“ö»a¬á*�Q9* kѯj6ó`»!=aåìÀ2ü¡êM#ŠwÑ,�l˜S�ã|RÔCuç&³š«ø ¡ã-z‰SºòI!�<=‚š¯þƒßBûÑú¨*V¶^¡¾žöôÒY¿û�}»È #E­qIÉiޱŵ›ÑK’‡:«ÉMÐV†±Òzl{,MÚQGÄ6†ú]'fíø²s1¨³_Ùõ(xÞ c\%8”Þ UwÓñLäVX=ÔAÒyÀb\’;"¸r˜€�“uQ Àý™éPX`m5-x‚÷ÜV}ˆ!‡ÍÐÑ¢ ¦}þ:gøàÛ‘Ä£-˜µœ“…^ÒSP ½‹]ðiö2|cšB¤?Ô‘ÙºB°µÕ‹þ.În¼³Ur^�—*p[f:ÝÝqœFnŠ·“á´l­4ÙÛ">}. ) `ÿXŒø‰½„›{¼iµe"8fð¡ãÎä÷å�”±7¬Ï’PÐt¶AióIºªYeªã@¤Vƒ~¨zî=fqÂ`¬"\ŠTð×ü ¨j¹Š&‚wé"½VU!î} ¨;‹lvþS~*ÅŸ¸Ð ¢X~�‡Zº APBfîJzsAªVΤæ ´¦þA®3d› +7 �œénøÖ*ÇÞöÕnþe¶…ŠpôWˆâã[L/2"×OÐØÓÛ8µò_¨mÞS��0�g�N¥Ö÷ýàÕ¾£„ð®g÷œXÆ Jµ¬ÂŸË¯–7³ åú¡°Å—ªÄꢥáϬý^‹Ã-h£š9$ÿùRþÜ};Yþ›tyáÔÀ mÊ"·“ Ry¬²ÁJà)¥Ë¶HÒ½&ûPdíutºåEÇ_ùT?pØ.À}od2zR¤÷¢®ÛÕÄdKß#E©šØ“mFgªqμï¥K{cÉbN¶i»êZøö¬‹Þ«37Yõ~Ñy¥ÃùGѵò»Ð´±™ÞÉÔK¢Òĉ*.»r>ûÁß#¯d)aËʬ~BÌþN'�æÔÂÎ{üp¬ë(\+[µN•б‚0ŒÜFcuìp®#*ÞÑäÛÇr\ï }›/Ëú÷ˆN÷$”®7K]×úç�6,]L/Ç9Ágñ:Æÿv* âð×ëeYžW1EðÌ.Ë U>N01_‚ëoR¢�‰65Tõëb<øâÝAιÏI¶ÀfØdð ·r‹0pÚlœŸÀ%*ãü�è=Š'K0½ÍƒN‰v òð'ÑŽL‚ÌW‹°ÑÓ€ñ¸øœÖúyÃÙ>îÑÒTd‹DÉwÙÿ@|•oÙ‰W�pb˜î˼ê’±Tû‚-\qöÅýsm‘/8M”.ÃÄ1:ºKgÝ’ç’"ÄÄ|QŒÊÂ6•�äë£(�{nÊí^T —¿T²¾eM ´¿ÆLBiHá Ïá:jЀç:=AYø/Ö}¶À·éd+ÿO��=‹$µÒ’ý‹1äf6ýú¹ >ôñâB»Rî4ƒÓšâ›§:ÞæRÍ2m£–j¼\ûNm\䈼ëæpÉ>¨û,ÄÜüÂÔm¿-9w0F«„Hì ¾¬œduó Yß )Nåðn²å¡ÜOÃnéH¥HÞñ5äÚ—òôb9T¸‡‚Æ6º×%Sçæ£|‰#nLTÂÅêZÈQÀ-1èš@­f(€ß1›r$8ÇŒÇ “ö‰ˆ†~ÃM}g–bpª ñ+;øî4XÖ#µ ‚«ìÝ¡¿g¸\¬¢‹Îl²%;ÆXØ=·ŸÈä\BÝGQàZ4ï€r† ´k!y¥” ÿ›À,þ9¬ì�ë·C˜æ½ÐÞ!ÄiŒêd„þ6 -¢ô+ˆö¸Çì’ÃF‘³9V �¨–aù6zªÁMOYÃë‹ �|�ß�;UƒôKÞUêòt˜š�ÚtFë;(°^N^§›œïa-“Dù^ÅзiîH€'cÚhzû ý¿ «:Þaì“ÍðõŒ êPÿDÂÌ©” ÷M.–7”_¡=tïÇâØ‡ô¬Õ �†¿ßˆpÿ-ï#Ùˆõ/–ƒ]î6Ë“ÏT)i²�uÓ§±;1îú#3œ $/‚�#æ–�gîÉ‚ÚÝ"(Ü-… 7>甿{‰wMKñ¯x{p“à(Ó1å5+[”1àÃAÜ^³ý'ÍUðZ{²ŠH|Ü\œ9ű[BéžyJ«CÕ?¼°è‘çÊ^/xÖžH n<¡^„•?.ùE\ØÃ£ÀTÈíåáÄn#Ð]3‡&å­¡V‚}%ž©rfF=…ÕD–›·f<¹ÿ•9×ðd”ì7Nçmüíùp÷iÊ?G�˜nºú©÷”Nªå«ãÚ=A4<¬¾�nÁ·—ø øº2ÌŸ �>“c¹+Hß ?x'Ä’¿_¿Á Ž"Ugß1ƒ9¨ÿh.¾fN––ÁëòõtD÷ ¨IJAD»áé�<eN,v?‹ÅÏ¢1„üš ­ÐÁÅìád3*BNn¿ã&ÿrºñ;_•¹~w»KÀ¡ja¸ì’Kn~û\;A,Ù• Äc‰—�åîÿÏU�­aÛáF6Ú«~ûA¤î~h®Ê&wÞg[0£vDÀS�(Hêì$Ïj{ÉÁ[.(nßËÎñ¾!.‹0O[‚“²Ãœ˜Ê#ë¯SG.]_hjz!+ õÉqhâprŠéÖÑpÒp¤×e=µFë -I&ëP±bÓcÆ“L�.�”_§Pଣ-ÔÉã)==á�KvNÐ;MqÐØ• ÷Âd±^Íü¿ÄS÷¹Ÿq9ûÚ˜yx¢{¨O”‹MËÓO`Nvœ\�½=ß@¹_ËZÎÃ^¹MDö%XûÀ¶²Eà y©b¿þ{œø×…K¥^cÑ<#<1a€Â‹’˜E_H„O7»xxwɲI´½(U�ýQ88Õ™B«¼é g¶`ïmFä–¨|ñÃ0S~”ó+¢ëjVCÇ6ˆâàöâkô… *[Ÿˆ .?袓�芇‡éø�õ¸ÕãÈf}%§ÝRAÿûr¢®*Èj=%»„ö€ft#»©|„†‰’ [Ã1×qÑ„�³[‰Ÿº\6…ÑÿÿMj.�vðÀmêRž‚˲ qÄ/«ƒž`æ#®Ó d)¬Ã…g0®'…Én³')u!4·[˜Ž)Cåg_X«ÑRÛó¨“ !OpNÅ3Öù©¨9�yó·¡~@=9µvŸiëæ:o*ˆwŒ ©ŸOqyÆVW´–´^�™ ¿=žþu½�užì°é$Í’‘›rÀ³´[‘—“å¾ÛÖü##çØæŠ8\ð_#©KÜ{÷yš>œŸÍH5¾¾}H®)ÃÜiù¸óW?.I§/4öâ¶ÁôFÛ8·¸� {«ÐOEHÄ÷Æc±‡$ý™/¬šñ´/©à’Íxå®Y¼ï�}@F¦ãͧúXp²™ë/äð�†ã¸ö1Fhü`9·R™Õ¸ŸgŠ‘�誻 ¹SŽò­Ó¬¥¯›èX¥¡O‰?œþ¾¶ÏPÞ…R”ý �oÊïÑüŸ¯iõø’]•F¿’ô¯y,¾J³£Óügs¬?–2e3lPu(˜x¶ºC§ð(=¿nò0*°ñ²?™o…\‡—hø9˜¶8ËÃ7á ˆ<*Äѹ3\Vð! |'’Øl>ÜÃQ�÷N5äÐãyв[ ¯Š¤›· —ý¹èµ˜û]? TÍ’PûÆtú'X®gåÀÜæV\qö+ zQЇn–“°¦r²óÈÙ‘áÄl?”L©Šà[Òý"3Ze¹»T¥`VôK“ÚYrtÿ!8¬²NóÔ2aÞîÄêäNzVÜ—”ÞÈ„C=å$ëi<öb ›÷§�ôwi£Ä¦²÷ŸÜá͇Yy„õ3ÜÏüÓù ýM´Ëá ¾òÿ5±Öph4„ {I#íÍa‡ûoro÷6Âî¸Emb:è%=|p®ƒ<¸þš9W¿�pˆÜ¯ñ‰™ôa«(nÚµ Ï߆‰>²0t´˜Å:#Ò|x'YãýœÖ¸ãŸ¡Ïlý”¯)_-%3,FË;�Tá[�ë0­ùV,Ó@Q•ÇìZ…›¤âã1HÞàÏìö^È®r­DAOMÍ ¤«Î…Ó¨yàÛÆ½Y·ü½»Ðâ¯1>¯u€ÈíÍ°ç‚ ŽÅÈQ§ùéð÷· 1º¬Ë]VMé¶köôñ®ØÐý”hXM’<{OÚªç@ÜÏ}¥ÎÍ`äKÈ�3}vÅ^Û÷ROŸ^:ñßž¸”@ŠFMö=ùYv´`Tñ¹^uxÍ ¤ Åª³xEê»lfñÒfîT‘ø› êéJ¼CtÚ²ýùRäé̤ãî:0˜ïC®Íö 6b3Á²‹1(þÊHx—ᑟ$ÿ?j+áu“ X0T�éGRáÑ ‰¿ Å®Zuïm,ÆE³¼púázе†ç?†(™nE÷]ñ¥fÆŠÐë>@�¶Lžj+T84i'àHù`”bh²ð*ÉCé±­`uL̽<ÁLk&n_óógâ½q5ÈÑ}AÅE$Á´" P¶–ž�ïÆG½*0æ~ çÚõ çNƒP=øN �‡%哳“óNs°yh c°õ;Y¤H³÷oýk©×ý<Ôñh„s&’¸QÙ�î8:•“§7±O4™�nôÅ”-XØ} VüžbË­¸VÏR’À(H m Mõ>è±›Ön"“§3°sv*4»g\°>èÔÐ ¼@]´ ¬>*&5—j(X£lG Fý'H÷Ì»b4)R š#" Gr9T™Iž4 §ø²VeŠIÝpëss´Yž@²Ÿ%ï|iy½Õ±Ö¢j’7М¿€¬¶ñGë¦é\™Ù”œ{³‹:HÖ�+¾R®¥WÎÝOMƒ'ô$(ô¥-­¤ŠÆ² ]»ð _¹SW8½"­Ïí®¢÷Ò‡Hõ¾èþ¯q\–$*bÄ È[úÓªð k¾•^|¦‰ýŒ&Ôö&¦3ñvšÑÇrƒŒKŠG°ÿ  s?[OÂ" Mz2ÃÓ–b†zlXò L§q ëRi¥à��3àÛvO´!'føÀu—sðGè(e¯ËÀ˜Èb¸/.‹.jP»âqfÅQü|~”¤” ‚tÓ<ºþk)ò¡|¤6ôG0ÝçÎbHkvòÅ�»¤5RŠ£óMV"ç@]YH—¿÷�¬¥iùú  eu;`†üC"ÙZnª£íGʲ�Aà�q¶¢=ÙÎ4‚³ †A®ä$ë61ìkðèGí#‹ñêù"¦ÒOž”úâ`F>nªög£7¶’ú‚3Щµgõ Ø$“[^NÙðYÂÎ,Å€­|ü¡�†ÎüMîÒ%®í¡ðóæ'ú-ú ®¿aH–2ZÄöÒ ˜øM,ØŽë>l§‡³ïçPÇæeäªESÜØE p1ªtÖ@‰W2íêsżU…°eÊA˜¨ÿQtÞÿTÿ_—d�Ì e¦-qïë\#2“R‰¦H{Òò©ìYöÉ(›Œ”r߯s�”JR”¢EFRHJß¾ÿÂyœ×y>Ÿ?½°ç¡4d´ÊS¿É@º^µ½õ„y×û!VQ‹Oþ·O‹@º£u§=BÛEÌ­Í­xäýv² j!, û@ ‡Y¤.ïø�ÝÆq 4a4aãé\Ɇ ŠñÙ÷r5õyЮZh2¨‚ÝÇtÞ¡ä¼¥:˜®SÁ-»Hþ"¸ß´}:3È:¹YDmZDŽÉÑ‘â”~ô•D{ŽùiÔMÍåη¼�Œ„ÈQ¦ñ�vþ@üñkˆ8{wÂo:Cí UÝd �;ƸޛD8?çÿ¤Åýä|ã3[ö�x8¯‚çëOû±‡db`;®•�'¸Q�(€O-rpÖd6ì]x �®ÅÒQmJ.ŒÐn¹xŸ‚=á1˜}‚Ò\jŸï|¸ýúì`«nMÀ™š†€¦c0╹ú¿Á¨7>Æ]Ä=ù¨ûfs41 ¤2… B|ˆðÈa¡¡=û£nî¾nîóuQ-«À%4Úp#� |d&>²%Ì­¦gôçIkÖ�wÚŒ`yˆ5 €ç\[�ÿü *| ± &õÏpJ¼™¬a_¢g¹ò¨Uw‡1í¹L<£ÃÉöé h|Tú5.‚…JÐõ±…(<À„®»´Ø“E½K‚¡e¨ŒQ4§‹Et˜ B"dCþ]j÷}  G’M7×aÝÒK8°ZÓøì‰fÚÖÞöz�U°9‹(�ö/Á_ס%:K>†ý‹;Y±í'Ççÿ0É�ÜElÑDé¹±9ã LOÑ=.  Ò¥BÂeSÀk»#¼:DÉÛ5¼çÎ7îq̲RÁ=‡¯ƒ«êê>”Á›©—œDØa`û•EäuÓ¡}aÔFè Ý2¡K�c²‰Éjm´xØ�if�ˆl`ØÈ$ã–K·é "Æ=ðä qf)pò#_±·.¢Ümÿ-äÄå“[~~äôÕ2bü9œv�»ŠpȾåDa},¨¯P¦þFøw®$ìMMBgýkÈýáÆî¹Œ¬FȪ¡nÜèg×9(tM2|ÅI­ 7üQ‰Â€}§ñÚ‡/$çÖذÅ�:Å7ãÎIè?h„1©Pé|†XdÏàY<燒èRzÇU%j–ÃÂlêÙkÁi�ù¸šý�*Ëÿ`皇¡àÌPú,zˆY³Z�nþÛO£‹ž Ö›£ðÚ ƒ–~au*?'{Š Øùêö(2›©nž¢>—ß°¾Ç“Í#æ`׳Ü>u«eN`•ü—Þ•zJuÎ¥ÓóËT0ÏH�Vÿâ‘ýñKaƒÎ3²zá$šy ŸtÊ€×oÄþ¢ÝS>tòm7KíA1FùÈÀ…øy<>3¨’Œ¦N½&0+6²ÝËaP` ¸í9AfÁB^ÖÖnÒ[”€ÍŠ¡8»{ÞzM®n{BóùvŽKÙfM�x~£¡ºpÓç#Ë2 úÀÐó’!n‰Kq¤MvëÞýèIªj'Æ­YˆÀ¨B¼ÅšÙHêNFàî]³8w�LÇÁoËñl†2Ì{zЬ±ïÄ[o§ÀõH=8ìb¿?¼ç, cæÖ7’Ý30Ö¾ò×Î$OæÂ‡šu(›=HV¥w³ 4·‚u[%„ø;Q±­¯!ÿó8õÜ4Êè­˜O’¸´99 XÈøÏDpã®I‘�˜ëÒø)¼»×sI¥ç¶àó~ê`t‹ø\{DŽ\´Áh«h°ºö%e±ï.Å6ÁØûô8†Ÿª�Tåß„O–45=ª†-öíuǰê¶>úÌ~ê‚(‚Í�°éÍB¢øê®EÂ1›�¯Š‡Iå^9\ Bú tõƒ+4p›­´<S'ù�¿r/:i}¤�ËÕ1§÷°¬4áR§5oØ�ùBÑØË7Éš-½ƒItyŒ §É+€Ôv§‘P9;²t{ñÌ3£1Eôúm•¾„Íߟ“„ ¹[º4©úŠiøW:£ídè`J-+¬H+ÜŸ‘«½5A»×‘ž €½aÊ<3“ jž;ÜãÙÜwmdÁÈv¸1~S,1µ%ìÚè±roÜp"†Y´ “„SÉÀ_5T¼f…wz.°ÓOø‘t š­Cæo=�_ÿÛJøÈCãâ­lÝÃpî­!´í‚‚y ´aà[ªÿ/Ýœz?ï"¶ÏÂàäµ’™ ·SoSÿ´xz{øÎçåÑ!�ïhâþ�>8ÑQJ�·òH’„#–�'áðUQl²K!Û_®‘¢;ðZƒ›þNG± ÒÕ'G¢$¡ð‡F¬|Kn•—ã]©L]—¼+Eÿö"–äÛ}¦âN‘x»,‹ë>ÿ n‹àǾ®Rj´[µÏ´�-¿.ÜJ}…_¥WCýu p[Ð ·Ø îôEX<ü€áJ. Ó y¬­â�Öðø6�ÌXŒÀ?h‚�·2˜ñ�Röº³§`×þ¯D.ä / ¦7£ù8gžâêÄï¤.È]½ @ø»0{_A$Ö[bÿ@Û]Ç”}¢Ñý] +om&ÏŸìg¹-6fªýÃqÙ§hj(Žd¥y6TN”‘•¢¤áQ ¾i3Õ½“0øIe£áÄÒ1Øk¶ ‡b•,úE* ¢úÙcÞ±írð^u5—0eOМý™ØÒWÖÕ¶¸st:GÞ9&&ãúnzú‰à½�þp|ï:°Ûœˆ/E«0gý|¬×Ì¡?dèØ²Úa’Æ+C�|&ÁUâ#uº=»£<™ðç*PÑð‘ÖwÌÂÅå¶Äï“=šzEz"¡Ã{ ü\ã ú½ƒà﯉NËëpèØ¸V¶–¼Ž®ßoö¦u°ßE“¼HlAWEª°æ{“Î/ª·÷#»£º“†v™–Ø4à¦Ná¸O ŽŠw£ÖçƒhµÙ 3~¤SÉC[°Ò ±ª$õb‹pÚá6�¸Ájé ÄG—Ò¯™~ 0NjŸIÀ³Æ@®1o}êb{äž ÷»¯KS�üäÃÙ¬§t~¦Sê™Jî]í!k[v²/Ðá%è?ÄFþCÐu/s~Þg¿–|ôoVËñQs~�hb [Ë›¼X‚Âü•P§yîH�Ä6™HèûœH_­N ®ù;,á ˰ßþ—@Ң嘶Ë"lkiSèŽî’\úÄé\>$õÍÔ!á$?wÆ;sDZªy l:EãÚSÀÌè6^”³AŸÛÔeâJãe w…Ç5Î,oÁa:³0ô»ðHÎë.²ojx¬X93×1 ¶úpnÉH?PÁ j%Cå#3ܬFNЦ7�NŒÂnÍD"§�áeÙÅ]J0vcW¢>úšÛ’‘BˆØ/Ïqþ6Œæ JرõŸcÚfa‘½&¯H$„ÆÍ_É´vESOGÈèB˧ Àâõ³WŒ?„9OfþkEÀêa¥¯5„ª,@Væè²_>z+ñí)†¼h½mâÁ7J�ÖÆÒŠ Ñ(}@Ž\‰×Ç�ˆ,:y‡cßÇ-¦ª¼µ£ÿ|#\š7Úxš}t^;iÖTÀ#¡æ0øq3(ëÅ€‡™àÐY,t•á%.Œ¢ .IxÑ$‡Äò¢@wè(5¯;Lž�k�ïôPøB—¢×:AfZ-‡ó‹O„¼åóá3ùì„C¿è¢�=ÐgqöÿØŠ—~Ç8É6ªù» ô�^Ñ4F�éÞîIE ãÙ ‹«ˆG¸ Lüö‚Ú)^K½k�Klû•O6Ì*¦ Ëk1ó¿B ©ã@ü e¼u6“&†˜ ç¼³OèUÿ}$èAÎ3YéË`‘bL¬G8‘2g?£y7ƒ'Ná&»½¤b×c¨[¾%ÿ“…W¸ÐÎڬ̣KÞSÁY;ñGþ4žAÅ+:üø*s@oŠ ©Ê¢ü–I|(šÏ˜Ý¾@Œ âP¤c9^mj4±î)#š ±hxoD' ùC®‰p?òÃgÜZ’ŽÌ©Ó9ÉXÌÙéEyó7ŽQÜŒöQéP¯8Ÿ(…Ž�´Ý“¤só±_—Èî² %Žù§ *µˆ¶�TD¹úÕ$0lˆª*À¹&"çàŽ;" ©“Ç'r/È™®ùï'õ[Eį©’úŸ�)ý�IŒU±U¶‡˜úeš‡1Oß ¤S.aÌó"ÒWDÝ=C–»ø=ûÍx±† üç»!ñö[xc›èf^\Nï`™õ1�48†âÙhò¦²ŽüNxš÷â»Í�9‹�óg&Ñ,µ€Y?<‘säîZ Åëoáß´6úRç8›z“…tå º½Õ «ª‘ÞGóÇ‚ÐNå@Ÿ úm¿ˆo{ÿæb HþB½Ípr ƒ2I:ÿøÜâë`ñª�hýΞ=|?&„üqã'©JAú‰•8=Û�~X¼Õ»f@ô¡n×ÝW¯ ÏëCýô øÔo„µÛfƒÍãÚý  ´åaº„öîÉ r?Và« „Oê?C«î]tyÞö„Q&wxóò•§"c8f’Pk »vþ V±ƒLØ W`Å›'бqS YzØTÆEÐ|?uÔ^ÅaîîÝ�ômû|9¶ŸúPD�,.j=qÁ¨Ÿ-t_à0Ù(�ì�OüÌÙc¡p2Mƒw�ßf‹�Á²onõ. æ‘~Y<ç(Lãöq•#ÛÙ½;Exo¤Äÿµf ©M·Ý\ µîµ„õû,Ø$–F“äÎ?Þ·j Å“ãðÅÚ2,óòFĈ$Ž\¶GåÏTzæ=r¡t7XÄ|åî8¾=T“ñÓýfÚÑ#ØO¾­À‚r—ïí�º_Uì K«ÈW%5H>ä�ÇL–áÎÓ�Lð/O Û±ú–…ác÷A"³ã24|:LD/åÐo;‘…Öɸa$ 8Ò‹éBûU¸¥1lboÁ·ûs1b•-„® €‹.›pÿȘ~u&½�s9c‹nAxÈ7֭—šÏ`ö¹µtßÜiPÞ6�^4-‚ñ'öŒ~="ßÚhg¬„ÏÄãþÐÓp½D¤¸ òÌzÚøÚŽj pff͇åÿ8wëôY ¿]ÿqÃ=îƒÑ~ÜeŽž%�ì¦>²~˜ëÃêßöpR< n|ô"æª`·gt¹€Q‡9hë®ÅïUìD™=ôjÛÓ.ËÎOŽc¿`a9CÆJ !ÿG ^]¾­.; ‘f,õŠ}LTk5’öµ+¡Õê ~[Gï6[ÃÀõxØö;?Wƒé5¤H8�,¤1´§P�l<s4D¨“¿3Š)âšcê°÷¿@˜«›Èuÿ ŠIàá˜zç™s=†ž\³à`ÝMfxé°<_’C¥-xN£ Ÿ\à^]½¢ÏÂß)Wúæb<8\<Äþ¢³By�ìmì.FÉ s¼]àTOéQ�Áõ:<2œ{·æ íö7xÑKº|Õáýˆ[âo cù)�úÍ 7³A|°ÐG>ØÀ ‹ü�( ²ùg�Õw š0JÆ´$HgʲÕê*¶åÃúœ=$öÌ fë¡o4³ö ¼˜{™f8¿k¾ b�»ìFŒ w� è'Ò·îûÉèy¼ÑÒ„~kÅx�ßðÎ…I�q™#ÛÉÜþ[ Im¢ ×à’–G‰×PeÉñ΋ǹL$ì“æ²ëÖ¸âüuSÔÕô6ò͘�‚\@aäº&¢n…ì—‚¦ð®*“Ô¹F÷[©´}g3®’i`çò÷“¼ù ¡ßÄÈ?^© tϸFwˆÆ�uÇDØIN[�+]A¾Î ãÑ�nHÔý›‰¶k4ž;VÆ={´‚¸ ¦� ´ñ‘€Ý‚«±âR!´xþ"^Gž“ãs½ñ±ê[ª=ÑEÌŠkáçƒ1vY— 7 â«§fDéU½~_.^��ƒ)¢˜f˜† �røKW‚þ} +›¸�îðWœhΞM}u éø‡ÌZ5Ež4fÒò±ù‡O<"W–X�ÿ"ÊÚtöd¹ üo “2/Ó�”ïÔ#f6ÆfP™Ñ-$ï³"øg´CÛ(v’Ø/ráù2ž½ž}Ô&ù™­(œ[J+ ¨®þjÜ«z›®~¿7ý.Bûþ4™õüìz¬žŠ +lß2—j–ãcoiØûw!.®X€œHÛ3�¼œÍÁê÷·Y?ïåàÜõ© ””{:'ÈÍ™R¼ð©¾)"‘ÅÜtºÏô¯‚ô¥ahuV úì]ð;W[ý2ÑôÁ ¬:eF:NJ�ÂMw‘y‰æóóIÝ„)æïi@ 7zãZ8]ê‘ c?ß12sØRC^p¥ò-ô�"g¶?cßÚ¿ë'ÿ‚÷ô‹»Î¾’‘Hó\ÊPÏ!Ò5ŽâKþë$·5‰¾—ž�K%E0#`M›±ˆ7™ù™9Þ¿ ò‡•RÌõòG_ñzÚ!“ŒÖ¯ñ_¯I; Çb¸.ýmÐËïŒóV9U€Í•¤÷öœÞéønˆd. ÃõVLÎB ë…«àÊP庬f�å“bz‚IÚ›u°I„�7h×JºNÎâÍÛ‰!ÎXá!‹¢ãÉ€]'M¯œÅÙ½�R•/ÓIîÛ1t5ÞîÿnÏXÁÎÒ¾ÅØ�ý'{éM‰ ¶ÉÊ*TM¬!S[óȱäqà¯s…ž“(4¹-Öý`R¿Ê£“¬ ¶µ�"{[.Ì}4Éž{J‰â:È/{§÷Tuv0– %�Z–ùøë4Çs5 š à “0ÐÆ´å`�Ç5"¦¸­óùtu>ç°L,ºN±Ô_ö×a7ŽœŽÇ\Ñvºu7‹®ÍÞBä8 àÓ­ 7Aš·^[ ×”3xÍ.žÿšÁY¬[B/ùÑ”¦P—^F/Xg“w#ñk�šžd*¶£bDÈ ÍĈ00ö�×w¥Qh¹>ÚžžGê…ïÃ�ÿ⑬~v›ñØ›hPw‘Í]G:âWÓÒ׿±IÚë]åqjÓ=Ì>;… îïéÑ�8ät E”ÁóGX~¤tÿ+ý”õƒž¬óÅHÚÀ]qò%ºÎ¦k¢Òp–l6~u†ˆ*kÎçÝtY–Mr)ƒ•ï!ôÏel׌„G´ÈÑݳéôSNø-&6'a1Lj\|ºÝ| púþ'doòSö˜Š.uørϯZŒ[üÉûid¶¨?m œ¢ÿ¹êñætcRv-Ó£# ‰�Ǩu^Ìhž ˜ÿ}‰ŸW›cÍgeÖ·Ué˜?œÍD‹DR…2»³”#?лÚêøÚú(¶½:W¬ñ 9‡*=Z�ËÛ{è�U1¤ ¾Ÿ�éE—÷=¢y†Ú¼“É0g“þØgR¦ÇËg Óq+üv*ajœ+χCÍÿn½*Å©„{¸¿î.¨¬>–ö…4öx íñzH†¿- Ž'ã9M2!GPŽýëS:|þ}WlR¦�U%ñÀýXúTXš³dc˜œÓ¦•7)ßÓ2ö*ÁŸ`j¬ÈÙ}Aƒ¤·ÐmË_‘áp1Œÿˆë‚ 2tô}†Nò4¥"›ˆã…9Ãì÷u€k ®ž5èzà*$8q0»u)#yðŠLSäIÛ»ƒîßwŠI&ÝGÐ~×Ú¬Ã�2 1Ó!VÅ—³?)Ò|SvT“6|¶ž…?,t¡5Ø 7™Â{a3¬Ù䆟ªãO3š �ÐÑû Y}«x¹W2¡þÍì%ˆßƒÈé™Û3g=° âŽá¸õt¶n£ãéçè—� íáŽFœ¹ÅT7™ äªHò·k:çÊH9Ép™Æ½�†ÖÈ>:›~¸u’|¨ǽmïh`à&·'ž•$›eP KG,{ÂZ=ú˜¶õlçX:t0ÞùÆôHQ>.ª€òŠ$P›(¥ž/;çg$F-àgŸ^w“Þ:{‡JŽ˜¢¿Ï/ùv9jä½!³.!Z_ƒ{ODq¨U˜³ZDtôõx\l²QG+¯Q’´Æ‹™­"MÒŸÿe‡dÔÑ[›®'Å..¡ØÄGË©Íä»àe¸ù´�=§n[ôçkª9yZ¹4C§Žì'ƒ_íQÕÕ_3aУ¦OZ7îBiÒ†¢1ʼè,+˜³n%}¸Ò!üsh¿%x;y‚K{!SÒ©ÊéÛÚ W·Í¦µš%ä[l¹~å(ÏŒ× VÑW% ;ÉiJ ðÄÂ_¾¼€¿ª–ðÚÆ�‘ôæÓ„=¦MNÉmdimáã¤={ß¿'‚dw^oêcÿþ"ˆ +"ÈüU|üˆ´ —Ò9£¢à™IO*w‚¤� h)rÙ½6LGŒsƒË†¶'¾…Ú¼›i}ÌØ¶üqX+ñ¯±°z59,E’CÁså,ðÙ£Ëß|eH#/c‡|9KqV쉡Z�L°¡w”œ=”†x(jgX»Ž4ðÁS;Ižü»jHš}ŠL†aߣàÝÍ«n’å® ðGÍç·A!K™ÓW.Ëû«³3Þr•N…±~mwÅõF¼¶¢ ´�Í0K¨ÆLpi~‰e2vhnð†ìªZÀ‰Ð[ô�É7 ÿ½$UÊ2†ž®)v!×{¿Æ‚c¯¬µÌÂÑä>R¥ˆé~qèé‰X5ñމ¶ªA%‡'äøª:ºý.΂SWA{z&V®íE ^ÿ©�¢¡AÖKÊ×ËÒŸþ'ˆV“!ÖթЈÍR›¥ÀÐSË;éÜwšPû]�ç¾èu=Bð¾Ó`7]ßy½¡Úµ›®®ç�c7�£Ò¼7úÉ⛑®r™w.tù¦¬y‡Å»[Ù³.lAµå±hœö‰n:ŒPÿL ô¼T8§¬ ¼¸�ŽQ7(|¯‡m^)l;ob«\_V·�©ýÕÜÇbóPê¤:ô*áz霬&Φ³È÷£•V Å0JÍŽ¼ž#u�01ŸóRÓŒu¡$•Ÿžà­Âó*Õ¤ïY‰Èú¯ñ’™äÕ%àÐ�»ƒÕ�IzéµñÍêGÞYUÜwp>´püÀÇ» l婪C!³wÞl4}J.i¥Ãv sôƒ>=Áß’ûZúøâ¸ '�Ö«“¢¼Àé5(§¸gHã²"s”_y5ˆ�ñ¸­ú™~k¾BÔà Ñz›Ä’>žƒ6ì@ AR¸1Sƒx Xãh Þû©´l2 �.çžÞÇOY' ,]ÕˆÚý¸Íõyx[ˆ,Z ˆ6]D­´„Ù`™Òÿ5’÷ª?ñî¡Ù´�¯Ø„døC„áj}7Ç/Í!¥:§ˆS�¸õJƒæ½Nz´¸ÖHŽÓCy&¸Ä] ãê¿ã±4Kbî£�F±°Sè1yýx Çܼ•ÖŽAÔÿú®¼‚Íåõ˜„@Òô,,éÝ}´ék ÍÇØØmÈr°äÙJ˜p>›fãí±X•Á>g -Í8——�m‚UÎxC¼™ÄgÝÆí+¥¨Ö¬�x¸ôÖÈA×Èu+½Ï|=Ÿ/ëqÎ/›;Ûîãg±>2­ñ:ͳ¾ ²3£ª4.‡f‹(çt[.ˆvHÀÎäe˜åÅßQÿ'`Ù¸Ž X¼ý^5PÏwƒ¯ZŸ˜«¥1È•ô‚9®­øÞâSúÅä8]²\êL㪦2$ª%ré›*öwåúÈÓæù†S/››T£R˜§Ü/‹=s±¯(âÏ8ƒg•}5g-fFò�Ü;YtùÚCJÎæ“jïv*°§–íÃóyJXØŸB´JÈÔÌvl‰³¢ß"Pñz ªb?�2 @á®Kاl/¶àŸp>L>�EGeñà õÞWJÑô<“¶â<—» ³øzÀ^@bö'ùŒè  §¡ýs&˜—lÅàù³¸üŨ}Û2Ã$Й'ÇYùb&»eƒ oæµúƃé3ð†Œ‹ñP¤• UGPèß;à(VâèlU6gÞ;îõ»�¨Ÿ Á·v×ÑïŒ&N”0 ¸Y€Zy°'csñ'(“÷Ò7¸vÖO`?qB;?x�: ZÃg`öËl4—£5O’njÄMDˆØŸ¨6y‘•®Zœ��þ&.Š’¾út°{).ôÃa'è8!0®Üw 0d±F~Q#Ïî¼Á‹×í fP™wЊA�>+ž€Oú` ]SWY;ÿçìÿp‡˜ } 6�[ÀâÔ\Ìdý¤ {ÓpEãS%Ž[2?QîÞ´9°‹mwIœ-ÓÍ2¸ç;‡¾ÐÏ„¢óW £b&6L,Áòh }ÍGÒsè×_XŠb‘l÷>òdrÍÿš@�ß)�-ÇŸ’5/•8Žãê<[ƒÇdéìJÄâPt(懃²ë˜Ð§—`û™&ZÆŸ‚%¸¨Lšs(O…ÔB¡Ó>ùlbë�Ôä£ÄËm'iQT€bâ‹qÖ�p-Dv—bº‘2¶ëýfrEð¥R"žúwǽïÆ›Ûø¨h¼*ˆ¬�†4éÏ´U°‚„‹á–ÞKIb£ÝïRÔ3áýç=„»â2†’Óðôß q>Ž;„-Ø9 Vé0ejê¡ÈÛÛ¯Ìk?íàÜÞ¼Û”f¡ƒ�mvÇcw‡o? ïnƒ4ÇÒç8½¦×ò„áVÞõ›kŸ<Ñͦ &ž\Æ O=�×=@ Õ=à�žoöÊ»Þ$�‹ÞDC¾[øEéâb�ëdëP0öoäÁÁì zÜÏÒW6Ð-ϨÅá�(cù úæo5ÐU›ÁilHc¾èëANÐ<¦(tÍZ{%ŠÁ_ƨ\ÁY’]TMÕ—‹ó¬¢�éßáHXñé3ýïk1ßµ¢õºáô«Ð.¶_¡$ÏrT�3w´«ÛS™Á,LVøH‡å#HoÆ\Ð�w…”®ÁjtAÃ8õÙ�*Õ¯ A»ˆÂk<ë» nÜ?_›ªiJ.‡u7´ƒËz”Š‹J—›Åâ”nkeß×½‹âöPX^Ž ·B�V#»1?ôUò§Òâ‡Áý£ ©}õ€™gu+¤ÌüÕåÃòAÄ3«D ØÿU¨Â<�ÌuV¦‡ü¢À¿–ë�X æ®ïôXÞEª®zjÄôaË…#PtšGc~Ê£´È6ÜÇ· oåOG…[÷ˆäÐb“r ÄŒûé1ó`¦kŽ~êÏ&[c®ÓR¼«ómqciÈî>¬Ë $yS9 ‰äm“Ÿ ¿øEñù/œßC/ÅIӹϣð¤[:u¿úWܱF¡ �h~p)'yé7\iîŽó–YÒçÐ OŸ*ñ®Ì"–¹¨tª Æ=„ð­Ä_B>…£¼qXÛø�ç"œgõf¨ñW˜§}ÕöûÖÑŽÅ€:7ÛIz¹-4^ ÅÐùñqöŒn)ÂW�N–÷?c‘ÿ� "tI£-IœÔ¯{s8w^�‘ í‘°+èŒ7€W3£é²%wÐ?Ñêw,‚ôvwx|ü£yø1û²ìc.+t‚ùÞÍŒ­hsí5zø}#?ðûž«4âÔ#2±?ƒY$&ÏqÝ:L4!£xà —_óB‹ž4r¢§�T¸ÚÀÚÔ/ ´n ×4k‚+ß )À·.O<ól¯ÓÅò�kè¯"+8.È{äkáã˽tTü6¥Škñ¹C*ü2B•T%ò4ù-mèX“ïGÍ·†@^‡8ïÙ#Tðþ óC.®f÷ì¶rÈ¿ôܬëØÉ®I],–üLwÖÁ/±’œàçbì ÀÙ<ÑÄ�ôfÛk8–ØM47ñhþ´ÅŒÊ�›ô­¾ G‚i¢—7@øýŸl©%áa‚¾ž.0lc�»û�0!›KfÀ.§íì§z^‹îBßt?U:Š·}…È%4šî ÷s"¸×ç¥c S ­~ćfù‰(=_r/rÅÔ¯ÐÇ&V�«=êòç¢KÂ8yК�Ûö> ¦‹6ã÷^©v 1»IÉiÍXòSS•Þ–¢i™>OâëUžqdèàí=šT~â]›g þÍþÐ)s’ÚRKÜ+}оCÆr aqÅU\ŸJ{ÛKáè�uTW[”6¿úMOïJ€´ “hìÆÂ­ CÔ"ä¹ú‹ðÌ�ÑÐ-›Æ�}EýÏ=T²´ ßw—á±£sÁ×ë Ùôù*¾pN a©Æøtž º\˜ ·LoS§q'è°:çmë9Øqà>NXûS—�A¦h9Mf•Àª÷ÂH·‘M.*81û<¼Ý™�#ÂULA®§@†‡æ ŒAïÚ”‘´Å˨½ê!ôegÒÖ¶"Ëè'z† èëÍ‘°Þg/XŠ„¡Kä5|Mg/„n�b8Ä‘‚‡¿fpŽ®Í`O>�Ævµ;ÔˆgDß6&›eÇЀ÷vLÂYm­NûÞÆÙÏjP?;�Í}+ìŒ2²H.™. à!l(¦KL«ñé,SvŸ¬NqÎáª"ø ×LŸ•ƒšø LÏØ‹’&Z°Éܾ­»ÈÚ>¯ çüùKt{ã)ßó`èË™‰½òÂ`^\L86r4NçÈÍxJK‡ÂÈ Óh Ü S[œ1÷B´Zàíwàźˆ»l9„§¾…ñ~ø—NÏ�àì|ºÅo�*c†Ç¤žc¸ÓîO4ú;È.ÌÍäF˜W®Žáóõ€W’â&\%=]è‰^ÝWšá€Î2 ™Õ›™bãó¥�z†p7$Î\,À¿ÛÔ‘?ñ?¼Óo�êÖ)´XëI÷=ÕÜ_(c%ÆVãAÓ€$þ Eƒü¸Oõ)Y6ð÷e3Ω¢¦¾,ϯ¥“¾\�W™ùdò°\½J–5'/#È7šö¸„–n#�ŸÙñ— Y@�yá&Ebÿ¤_mõpÏÒû`2: .¥`éñ„¯!Ñkøˆ«³´y/¶FÇõ_Qþâ8�-um‹¶ár¹÷ôö‰&Zÿ;™ÔÒüú÷ócÅ›â¯O×I’¬(ÛÌ,œNüÑãhyLã­Ò¾Í~„ÚýÑÚ½h“|—\Åó ùHvÏÃægëàË~ú}f(D.P¾†IÒÁŒÛÞvL:šŒ……ni—³ …‰Kª<ü:Þ‹e¥­ ?÷;M j@õV†‘ÎÑ5À €ãÂ9LÒá>Zv9¤Ó‡Lü£lpæL{¢@Â1OÈ‹®ò¼H—™K¤$xÚ.÷ÁàdIÉmƒç‘á`®_‚o{gwS1hƒq²~ú^¬ ÒCX)Àº:’Šp“™!mçžÒï÷æó®×i�çe*œv�ȼ‹ýdå:{ˆtc9Lø�V¼:·k`è4Sø�—�§UŠ  °—˜-ÏVú}…NœõAÑü*âóA“ê”8Þ'øu=XSAtFWìÿ¯úô?B…ã viî3ÒŸE ÑoaR¼äy9xóà0ùá€e^˜}ì<ª)Ýgæo GïÏ�t@5ç�ŸÎ z5Û_h¡ÂFî„è êÝÒŠ«”Óà´˜ ¿ê UÍ«`Î.6N&³upûÇÙô¢ÈXr„ŸF_¢¹•ް�Iì�C^f:âÂ6uˆ•ŽÀÇæcpw_ôÉM�—ç$KèP9º·”¡_ÿfxý#¢ÛZ¸ý‡],´“üÍ<ÁTš¤à,G'P“\�Mõ¨¶&Í^ǃG²0W„QÈ÷ûÏé\¨Y,‚‹Ò"¡hÉ%²Üvquì•ûäí�·$§3O¤_$²ö[ˆøÇ3¸ñ2…ŸŽÙ‘‹îÒ-Ïå/§ˆ�úKlžÑš*äúcETªÛE¤;¾cÍý¦uS*Ž´íFá×|œHØ%^•çÂÈE«5 ¹ê+1Ð ÆÃ¶g©ìc%¬»®Ü‹(\µ± Ò«:Þ¬†ïaStÒ͆ü÷"ΙHÂÏûüœÉ‘zqÎsxa†ëV@ìŘžä€ñpµÙô“ÜùÅEà¾øbD9ë¾cŸÁ تöÌ®þ¤þlCîÑ^ºÚÿun7£>1ñ»ª'=š«Œ�ÖQp¢Óóo8¡ÅÉv®~~*Z_æ}¶ O^1ùÈ/JccG!x±:¯:6×<UÑ\&ÞvŒŒ¥³ômOÀË<\‘·ë]fôµ#Ȧš»tnM7<‹¡“9SغAŠÜý&…|,°¾6žã0n‡þÿ ¢òÍ`­¿ ,Þì‚.‰°Â¦kg¨Ñ‹EáØÚšM.î* VrÐ$Æ9s÷"=ì%Êy¢xŒd,±¼çx¹ŸÆmÓ–ódÿ¹ù—ãi¨ëÙ•·0¢î°y·QKó¹b�!:½Ô·ü ¹õ¸¯»ø³ 'Ï�ÔÉ0Ðj±‡òliè0$ð!¸§N„â¢K‘qö\•l'Òn¡‡™¼k%/7šcý´~2¶ ­Ìq°dº=|„‰á]`ùØëúz¨‰v £þ”ð‚%›®bö³ûxãÍ+¶ñ69eË&÷rl`Ê~'¸E7C››=ʾ}ÊvÞkó½àþKçî��e[-Áa]þ9G??¦ÿ™Ž‘ÉAÔ“Ë$|‘è4¿—tGv“SÇ?ÑŽbqì±Ð€J“°ÉvJ5Í�xÇé¸Ó[&VºƒŒï¼ùo'çE“™ÇïâûÏ-l¹.°pS¸\ž‡êFL`õ <ôþõeNÝÕ)PLÌ‚oŸ‚Àøñ7â-:Nz ˜Ô,yžù±jj0Ãü;¨õ)žÀó S¬-Kˆ~O c¯¥ A¯Ôñ¸G"1zöŠô¦µÃ®à%À™”�†»¥ø7( ^ù׈tëøi™ãƒŽ�Cߨ«X g2½o`ZZ8üíXK*þñx¼w~•½~S|áí‡EÛ°eìQ\_ ïDŠ0þœ8ym¶—6KF²’›óI˜e ÜÝ»cÿïj§pšæGšö¢—®ëP…å+ÀäÞ™�ÂjUÎ× G²þè ‹ !í1瑳^·oMÁ†ä dÉÄÁ•`$ÙÈfϺÄ6lÅ4a}êÑÁ8+0“îÛû‹žhád Cw÷˜;ëÛÒ¬?Ñ8KjÚÂÁDš¯Ie=d¾iBåº@R˜Nöô 7ceÄiÌ×Ã;×þƒœ5”ì.©&ܚʹÀI}p5FfÅx é�Ú7sq÷ípÒ¾× ¦n¾Å‚|஀_qÿák€¨·‰¥)²æ&ÂÆ÷Vøšqªj¦¡“ö0,»ÇÏ›™7§Z!ÏgÊÚnÆ—îk ÒOåõæðtv€öÊ,úñëQ®ß�37î Ó+þu63ƒ³~Ý~Ôê‡ÍC`X›C”÷òÃÉØuœXwø¹Ø ö}#´åæNò´ƒ‹çòú®½!Ü!qʵ¸K¯ì]AØAê�7z‡Ý!ýçWã”AæÞMí«�1Ti,�Ÿv§¸þ F O‡iMή:WÈŠ±ùN%ž‘ ŒÝ¨Z(ÉyòÞc^�À g$^‘†¬ò£…Dôõ£ü½ãtcÍ1Ý MI²ð>’Eú—‘a“OÔÛ̸O�àI¶9“¯jù3x ljq`ž>–1¡˜`›ãgoÇ>„ÄÓó%�pÀç˜�ýÅÜ[0Jä0©ò/]ñrØÆXÑ6I!œd©‘y÷ñ–Œ �ó��9/¼©ñª…øhÙ!jy¢ž†dòcü‘0¬Ú�„ßâ¶â1{„ŠÔ5©öž™{©ß×gؽk·‰Ã[êwëbö“%/ŠáÂ-ãç½:&DæÝ Å_¼Ì9•Æ!äa�1ã˜^-bOÙþç*àæ‚|Zšk€ ¯M°“ ö±M8páĤúv”U¿ ­ÿn£+@†{xyùVr¦NIS¯º ¬nr¡,™ü9•£;Éâö!ú9f%¾ö}K/7®DçÈéÄÓxˆ„æQ‡[w2üÎV“¾öHX¦cÎã¨]D�ô z~G2[¢I tòB‰4¬ÀªáJ¨Ú±�GÑøÉ5xõ¹§ß=|QÉðÄëH–.À�˜Dž}¼‚ó�±ôÖ‰2Œ‚? —Q¦[•#9‹Eu݇ã1]8<FÖ«#�Î4ãÔø°¯aÅ"ºR£ŸxÃc²è�&ZçãÇ8U¢{ú0Ø�$ë¯Å�M‚\wúItGB!uñCª±#æŠÃû¤ăO. ´ŽuQíÉjØšw�¯Ý…û„ë)—w åÞ¦2ã]QDhN:#ü–/•Á''­éö›Óyq£GpQœÜ?ï_KBÓâÐS"Œj§�Ž‹ç£ùÐ4±À3 î³�>£«Öó°™ âÊêJƒŠX ÎÐZCƒ·-Ç„ýÄŬD¢cpŸÜ&«jÈí'Oˆl~4h�@î£hjW2ŽG›>ck°3ŠòÅá'ÙbÈèçÿ×±«÷œÌÛk„÷¿úåM ÌÃM6!‘�+½kñÁÌäÍ•30êaÉ™6 £gñúG§Ã�¹ö´öæÜ\7•)Wé9)Ò€¬×…tÿ»5º‡ˆÏÝ ãªéëï´vö7ú`úb,ÚŒ÷îµÒ§ÒP½ô ;FÈ î‹ñDbšú�±:,�¤¦Ê{Ø Ñ«‘´‘ø®ü�çìdñi)?~Ýþ�×§úȾO3‰¬Ø$ÔL£sË”pÍ%%ÎݠèÒ6Ÿýå%RÓõv0÷Ïz¦¦^9fãÔÕrúú ¹ó苉ý8Þiò6·‹¶žûÀ�8ú†M¢Ûl�ÁJç2Å]«þ¥"ÒÓFqú¸-¦= d÷KO’eÈ,ë�£bÆAøÏSàLÜðó�D·céÄ•ä zq'Êì öRwy?pùU�bZG¡·ÀÊÂ� J7¿¸±>V¢ü .·¯(„Þå‘jù(ÿô=½ðNÞ)ùÀ�ºû(uQVçH‘Ÿv.è«›�‡?¯�!_?”O¼�kfÏã1yx,kè¼5"ŽC¤µ!v~ñÂÇ+�á$3D¿¿Î…OÙÃ0[j1žé�ÆpÇ`Hœ‹é�ðU¢,´ûòCâñz¼‘Ûˆ1÷mq¦Î~WöÄ“iPúñm®ìCþušxy{ &l×Tiòb[”Ò"—ÄíîcÕÇr#à*&­…¯óÚqÍš…¸t®=Ùn¦Kïíé„á�<î;esŒQ~GÅR°váR0?{µÓ@'�‡¶£_èNþiœà=¥ô×½aÆvæ7¶ðs#ö43S:ýl29<¯k‡É`Í ¸” GN á—!=Zy"™XÝ)†?[äÑ[ñlŒ°·G…4Sº�øßC ?Øp©(¸e‚`­°ßJ©@ê”Ü0Ž›‚m°8ïÄÏÁP�.öÉ䀒9ô«s ‰êH×ÂÈ¥�¢¨á?÷QÑ©(|{6–¸ëWÐìwAØ“`ƒç;ÐÎ %8Ú;8E)äÜý?dn¼*-?� ¿=þÉü�[tG˜½I7®—�TÇwèÛ©�öëÅh×lW8¥<ÊVÿRK�Ìáq["ðžjyL_ÈN@ýXÊœÔ#yþ)ôÜÃ(lÕ“ƒ�—Ûð„12Û²É2 5®ëÉE�`³mUÔÁöƒ>,a¾Ü:JWv}c—[ ½‘UØ›ü//ÞßÇdv‹½6(Í3ë®'~:FtÖ­-x˜›OçÅaÕ ÌÊÜ×Ú_Ð÷»Ýp3ë.nTý ·²¯aÑ#)êvÄ‘°FŒzéf.ZìzN*é�Òœ%Ç `Q$6g|§^Óÿ1]æ; _±œþ9`¼qðõø�Fá}ì®÷l¯ÀäýµbrÄÂfÖ)�{áCòÄéžyRDF•xB‘ÈÚ\\¹Òßx¿§—BŽÃÑ}£ÔøùHóçÓ¹#Êð©÷ l\ŠrÛ8ôô–o »×‰n!±LÏ! ¨¸ÉÁT‡¿¬¯+W³Dšë™÷¤ŸÈî›Åy5·�ž˜[”o“…—‹ˆ¾Ã,zO?ž=ØxŠVñ5#÷`&ªÙ5¢¾Ô®ê9ýÆÔaîþ¬”–™c¾Tþ™uŸþ‘λL@rÔšv†e�Î2kº9íDý�¢ó~ëùýâx%-¤$-‰%ERïû¼Q$ ¤2 )ú !JTÚ;-MšÒÒ­×}^hK*Rd•È&[Hß¾ÿÀ}]çºÎyžÇ㾸º×å!ñ:úŠûJšk¡ßÀòÌB‹~[7•«b”œ}|xÍå!Ç­�DI>§b³‚I¥ý£FÝooIlß{ìOR†aÿfúeKü”ta ¿(”›)�˜Å©ØP®‹é%£u û9¯9‡h¯Rdê'ãзR[`®Õ%Ää_U¨=‹Û,pÞžx&±˜À ©3t׳!NXð]ðO©¤.b`�Šlý´‘^‘·'%¶¢`UnŠÑ³ ñæÀ|xÐñ�æ*?%ñ•ÇŒÇc>VBó<ž² €i›⧉ËhîßM}f·ÁKÁLÎdÆ^(Z#Š»Î�¶f7üsPÁå½°°m:ºÿG½ãýè͹¨ÉE/²þ`8&mÆ9á‘°ôû±?ညv=¸o%<Ût mƒEGf²ï¿Íöè9Ú…ž?Óð¶¸1üŒ.•g¹Dœÿ8¤ªdÁ¾¤9Êž—U¡^€Üí:ËCž�åsñqå&ƒ¬£(0;%oÀ¡33ÁT~#ÍçK†Jyty§‚µ£/ æ?5 =,Ykzðˆ÷A\\烧¢_w×óLˆÝSÆâM9ÄDZd$í'ÅË~íüé�zH:Bµñ¥T}zÌžþۚ˥/1‘zyp^éÕ^ø‚ÙÚÁù7g9×EbéhÃm{ZßgFÓãt•R:òô; h«ɈVÇbW-ÑŠ¡ª­)d�;Â…-8±ˆ‹º"%xÁU^úBTþ»Bv?ôÆ=:(-‡WsäáÅýÕôJk4” %N~9EcÞqÄ *è[ÁÐÙÀˆCg!vönØ¥tÒ4† *V|kŒìzC…I Ø4qÀbFN °œHþM}] 6Ï_šƒ^¥@M‹Cé*)GÊûF ô†LiÅó„Fÿ[=ämÜ^ˆŽ1$ò[ûñ‡›¼�G¾rp&õ ÔVÖÁŸß²à¾m.¬še‡Oóú@êÞ1êÜÈÇ<­!»ýòÁzÍzåý^ÂÛßÃÞ–Ømç{Ó“ï³_à–…gÁÞºŒZí󯳳VÀ£ÈÎæ:Xuæ&ið ;ÌDý3: +÷€œsråh=ß…Z§uAÒñ+9y¬<¥â`Göµ“aû¬õ¡¤ë]Ý MR•0Øq†+›ÐÚ|Nø�Æü´0üòÝ ?¿ ÛÞÚ¢öŠ1ޏÍ$>Tƒê~sj`¬ƒ†q¦P`GNoyÊ1X�Oøµ¢à°Q,ºÊXÃ#Å4¼Â9Œ)é½–†¢sñÌØIÈOK"A$ûíFñ`ñ?ºyß4îkƒZ"vM݆x¹ÞÆ#˜¤ãOeu™�ß?“›WaI¹,ýnÁ|çh¬’8Iv;-§•·¥À¥>$n£ÃÉ^²äÂJ[ò®ëç ·œ<Ó*õ˜d™©`áÁé¤ñ¥ ‹¹ë2¦±4adâ%ˆW]Ï=�M6\L…†¿gàÛ�i`Ÿvãêmé·™<\¾�ï`áñ?ôÒcy�m™Î޸ƴ;6a‰J?iS9@šõåp˜{k�ü ­kÜ@wÞ ÐÑ‚ž»íØþ°ÈÈ~´óZ†Ü“6pQù F~PÃáëwˆéÚ@ΛiWIÔ+G˜a–€ú|;áßÜ à|î$å±]‰3ßÞ"ON ‚½E±å�ÃÖ¼trñRÆ7É�³ì6/÷³Ø6²ñ] nm£¿ÿÅçt6ÊËo"“k‚¨ç:E”ñý†ûÄ�‘Z*LôÕHøa:E|.à6ÅdêâK™2s!Ö¹L•Ý"e†n;OCÎÐ ¢½! s„–r;†káœf>Ú™Ô¢q†/š SÙ <`ɳ#8Ë/›¼? sõr™~Í»èóèÔ�Nù|8ºªºÁg¥XW¾ ß]$yf3ØŽøÐÞ}NÞ‘ƒ/ ±xÆ%¯›=¦™�›Aú–Ч…jmºx©1EõáDËΧÚ�4À(¦³bó˜kCgð—½4¾r3@‘£{qÖ¿44&dqœæ-SàN~§Ô_�³F$¦ÜŒ$å휀+Ÿ‰ÓÕp,þ[Nã$g‘žÓGèÏe™Yý§ÑñF ¹íÑ‹”ðÜùz:-²QüùU¬Á~æ¹X4®½×O0W“�´ž�`d£æ¢dG6¦N1ʶ„ÊhjÁ¯™S{É!nuÀõ4Gú¹¬g �£Qdúƽ¤ê…´Éõ7¾z Ä5²dÂm Wr9šIe’Û¼d¼�—Uü7Ÿë»ÙÃ_ž¦Kc#ÀuE^£ì@v•…áöI>:ÍEfj†§ãÑ;©�BkȆ·v 0#—H4~ÁöÞ­0do†xD¼ñ†Ù(´ä2>Á2*ç>Lƒ]¼qe�8ê8'‘›‰å´jcGÇ£ƒŽšË]ž+Æ¥N»áçŒztÚ6_�GËe”÷zŒy}dÏx˜Ê¥Á²¤nÈ›hâŒ_z�yXž…÷¿ªÐË<¾Û„ý>zœ­|ìò·óà€x(ÙøþÄü*Sˆ|vȃ„›aüVÈ~Œ¥b[L@f7RÅÜvFëí_ÎyEe,ÔAÒ‡ïLßë;ÏÁµCÑ"±â—ÅÓ‰EW@©÷:Ö« ÂÓ‚81?v;܇�‹âürÿY˜P®£ŸJŽãÕÈ»ôšêr"÷`'ÿ\Zœ½Áµÿ4Ѯ̄Z¢@îX-Aí‚*Ø$qŠ8¬ E»²“à·¥¾ª(Á´›ut¡Á*¼cs€ÑŸ{ ™K> =f‰ÞÓi˪Vò¢ÄŽ'pw Ư g™ ¦-8yŸxŸ¢žŸü-¢Z‹:ñÜ5(g-n°¶ìõ$ÒÌ»ÓP«÷Ìü< ƒÖERÛCë°mO*‰A˜î)‡ögÀCï!Ú§>Ý+•H×8‚î`ö?{E¹ësé“pÝ&p8xÌà¡R1Ýžþ�ñ•÷%ÿ^¨‚hjM{±Œª¹ž¡–Ö!`~uxJœÓÿÞtÓæI�Ši[à¸^::¨‡ ;=6_ò#!UÚø±Ñ ×›È¢ß”Ï ®…Ã2mþ‚\ƒyUòȸz"çO‚ªÃ<¹1úïÉ^P>žBxeÑl®*gûð*zãŸ8Ù( ï �ó¨4ˆäÏt…›/ÂÅ\^.ÿê](r5U‚yØZC%ª“ÀöOG8£†öÔô õ¶\·c9è '¦Î8`©�g¶¨³eýEÔ)Ä”|Ñoð*ìÆ`‘ ¢¬µ ºbµ1ªwœò[ÇcNq_±¥ m’øÞ8ŽW'áPÿ|˜gp“²{fÀö/GÀ4¥nóC² Íâ»KžCÛ�0êä%²ûg;�‘OnóöЋÛC¨Km*ìímœL} ÚÎÛ¶”-è$†ñIÏ´.¶¿�ãLj,T·ô!¢Ër™ÍFaôó e©ñ4)ê ñï]ÏJªç‘ Ñ8¢; kus1s0Λþ…–»?À—òɸ{ä<íN/Ä_~´qÞîé8±<ÎËÞbæß- …7´à”�'ÖF›àçÓƒ`ÔÉO–(O±„B¯úgÔTÝ�?%à%“ßdñ+fí\~î¨íKÚ_ÛMÒÒv�ÉÞ§Pðd —®àšóio.Ææ’+¦³Xìàœ‡äÑ|üç=ÔȪÀê?s òê ÉPž’…æÄ/#•ª­&ö€Ç³åøÐX¯×PAM¶ ;�.¨¥oŽPôQZŽJi˜}tèZ´Ð¥ög`uÂUˆLÖ•¬¥¥AQ豦KúÈ»çËŸæ%æûAUðqΟWä½™üy&À…ézœ7Ÿêíë\”¾w‰º%`©žñhªÅóW$9ÉiD*“éÂ�ñÙð(Ù4úpëbúKÇæ|«!oä‹©üŒýP9|†žWä‚^†_oªÁï`>ÓñzÍ‘ÐÆû\‚ºÍ�äÏÜj>tcÚ;8){�*¢ûèGxkô�óDà2Û4—¹#£ÆíkzE_nj;Á¹x~ÐÙ<Š;+ÂI“Aæ' pÝÌæ£œêƒ ºaÑCZö.—dÔ3~:·˜LqüÁ “„qyèž½{f2áÉ¥�òdûßÿ#ÊúoHÚª?8RâE µ°þ¸0~Ú!ÁÕÙ‹?Ž:‘¦É|:/r.DÙj¢~N7ñøÜAË®ñ·yøõÎ|îAÕZ¸Ò/…»¼•‰°Ò=ê~‡ŸüøTKÝKúp'™qÙZL=ýïÀÓú+ØÂÌf÷+.Ç•çBP ¬‘8­ÂÉ·Áä}Q=¬Q ñnà±ñ†óÌÁ†жEïßùÿ?›,Q2�AÞ?ªôeÖüy:ˆÝå¤M&Œ.ÀãO{iÖæ?úü”—ÆÁìG™äÖ~PÞÝ íʬä“(|4ö»,;ñ”… TQNÍ2k¼t%�ês$9�\Ÿ2ŸêAÈîom¤½OÉðçb�•¼Ž×EÙý`o¿®‚ FOùæ e:«)6ÔmDšÜ ó¼ø¹ùù«PÈk9:>€­“HvÓ –ˆžíåo6bûÇÂÀ¬*†²o‰êÒaúr™>¶^1mFÄä-Ý`y•Þ©z@ßjŒ’ômF ©SÌYéîEù¹™p?ã�T|K÷©.ƒíW"‰ñÞò§r€¶»_„…,î¹ÉC>äà¼ÈxHOš´Ð= ïé‚qqné—û(kOÅ߃˜Åo†Ï ™y2´–tú9s„{ø°»A/ßKÁç1 ­W˜Ã5‚Ç�óY_ÂqúR]� ¸­Ovˆ¨Ã‰EÉ"Ñbx$ሩ¥²´n?î¶6Å�yäùÁRÜ츋:8Jý¡ùÊmôí÷ÂB×ÐX„%vß1JÏ û_í²›8»VR, “�Á}í’El$BH½…Ç™*¸q›+jÏ^…ÛÚ"qŸÆsú0ߤñáèk Ôå}Mjß<öäz¬0a˜±W‹àý)nß'K2Y{§QdI(þ¡ßˆ–Ø xfƾœæGe£±ðî~àìÊÆ$¥½à÷%¯g璘õ®5ÞqþI¸ÃwéúEú8=W•¨iŠã™#LW2‹×Üã¼qƒ�!p\v½ì˜˜;åO�iÓ’C´Þ#’¤îP†Ón¦8.¨Î6¿ ÅÊôòÓ3Í{.Âuþ:2zVäòà‰„•¹å‹âKÉå]à—Fw¾Ûò;-±;=¸“=Df³66Ƥ`ª³õIzŒBzr°J*™ž[Z ÞjÆ›©ëíõ(·�n<.‹îÆ‘?5»PyC"¬ðÁæÏ ‹Î7á×¹E¾©~Ž{ÓëÖ¶@íΡmÍÚiñ‹j �¡œ·ô&§.}I»_VÓÁs�˜ÌË>ÚdDVÝ?ÚÿfãС¾†¤í´²:“¼»Ñÿ%.ã>wð áNü òb&>æ+§æ v°#1ÕÀÒ|;†nº‚ä³6ö6¼„xºóÓ8izågiàl=]tÝ€I÷M yA$ˆUÀÕ† D¸*›|û5Hê„ôçD§F6FÐÐö…$¹)áÓ] @@Ë rý‚iüaLØÞJÒjAÛïú¯¬ãä}îÂ/ 80Ô�‚§†I²ïú QîÛt®í>Xs4ªhÐþ¨Î’QVcënÚÆq0 _Bw,>r‰ðB£f>î’ÐOÄNv1nwÇ-r&daÇ,8*VŠ7{‚AÑ8f\¸KÀö}b·ˆ8<Õ¦ZÒ&6ë.[ô• nÝN›g¨ÒƒZÿÈJ•�ôæ=.¶\U%¿|uñE!pv¾£u/×áíŧòª÷œ=KÏNo ÝDøm�{fÉÁµl^6Fª�D}Ð%–|3�×±ÖæÀ•nx &�x�DÈÅa»ü h¸jMezžQÓ*!*»7 C®KÁâš8PY±+àÞé'põM (•»£ïd?‘u'[®ór›xëÐäß ôzù™³`ä§�ášvÎeerjl˜F)¼Ãéñ&ŒKy8œw ŠöÅÀÑ c ]ù @Èyòa„Z¨‹Áûéç`g­<]ª¢ÿƒÜ0™ŽºáZ�RlShyÕ×éªÁÏ̤‡Wúßpl;§§Wž°)ßüŒ“®`´@ :TØâÍ%-^‰>¥×È6Ï«˜Ãªc¥÷3¦¬c3¨d4Á/ãÒWö’¼¥UþÄw‰WÂlØ`Dv¼N€Ì¦¸~�¥_ÛÂ8·6˜1aÆ �}¥ŠUh9vÏ4ªZaåŒM�k9aœ¹¨;åZÍ~Md¿½ >ŽÇømËQí84Ì¢ãQ+À=½ ÎWG³­ßÉ^©,�±Ç  ÑxIO“«‹�îÎCsC°FÕœG¨zðjVl© Ûä"…Lu+LĤ3ƒO¨É·Ÿø«¶„º H±Ô?3ö­¤ge úð ¡FÀ~(oIb¬2á~eÜ[¦ƒ<↠¢á‘ß¾âDR ù4;Æÿœ…o›Ž‚ìÅôÛoX—pŸ.[ÆmðkÄ�mÑ´÷¯k›ÞbŽÙ8Ô™‹§¿¨MùÅ$ Õñ€Ë—êéómÈðÙ«”yíƒW‚|á{BÈ”,boGÎ`w4_Æææ›t§M§;$ÇçUì ô‹?¸ÜÑ v¢ò|€pSÏÁê³7a¾W 漌¥~—u8ê'æc»ØfòÏÃ�¬ÝÊËíØ_K[Þ{Âà^=âݺ ’_�½õiy ?&ñî£?äÜóü¸Q Œ¼Yâ[¹‚ -™€²9gH­ï0ð‡}Ä ]I^:{ÿKþ}uÃχíÉQ�- &ÒK"c³©óÍ–ÐÜèô{1ÙºúÔßT ’YIÑôèÆ&‘#X¼®¸±u£#†ú£ìíÏŒÃÛ0ì«bæ�L bèçFÝã1~÷ ÝïŸBçŠ�€¸‡ï¨ò29ä]Œ‰›Ñͨš–¤s˜N*]ËW%•3_ €¶Ž¸àvž°hUâ6—ï"Ÿ–ð°¥Í^07™Å" ±Ë�žš+cjÃ\¸žÇÃ5õ?FbIÈ;‘AËö_„ø•u�üó˜Hž§¿-­hàm9¼çz–&¤ÔO¹…0ædþ‡Ó¿à‰kÙ¨('AvkÑ�±á°øx”Î3Ž WÉæ=m™u æg/€äBSؼ ÷*Iëe¡°ovüRË“[Ú4§d:½Œk¸¾92„ zŸßÆ‹ÝJèèh‡¦+†iÆ„!�¹] �wÐA°b­O¤û¢ÑìsæGN�@�“âc f#±{œàÂ’¼1^E–oÝ1“v°ZÁ›�&‰ö2q0:½ˆ›ãÛÏÚtQ{&/;±&½ø}i•ÖŸ˜†#:Áek=±?ôKÓŒöMФ§ è· Òd¸¬ï�YDãp2^J‹£k߃SM ‚ñò­èªJFAIm �‰od÷c×´zê8¼ˆªyp±ßÄOx5áÇr3rkÆ]ìé/ålÈ:�éÇÈ£J#XÞœ‰»' þë=´‹Äse|¸â\½ã¼æ¨cpŒ²è²H5vÏd Jäè°|? î‰0›•ú€´.”`Óys àp$”�H‘ Ûp{ƒûgÄáÌ…ó˜[ß,¹W5ÃàSN(ªór� J¡É‚™Ðp2 _Œ˃æÜîj®bh:ß„ O×3ZÚñ™4ü!'‚ªpΦ-¬kè>Z¢ÉÏžá4€ä68!s™L[“÷�x¸MDÙb‡tØý ðêþQh�7‚�;;PØå¨° õ‘ýJÝÄ:zœPXnûŸS$ÿ¶eÎ~^ÂÔˇôÕgqécEfúÕZ`Žx’|�{Œ¹l<&œ‹jŒ7ešhÎØˆ÷{*!;õ1­ËDØ/¥¶\?Aeø’á‡Õêº,¯¨�º1�›¥µ:•�[i5„¿©ÂK×$Ñ÷É|üøü]¦ú‡ìŠiu)ô «¥­}ó¸ª ˆµi/„Þçn ÿIÔ/æÌy-{'Òè\½È=u‰.Ý_³àܬN’~>ÍTeÁd¥ýQ«‰–÷§v̇y´ÐoÇÅVs·7{a®H/Èq§cLQ.D·§ã¾¢òðÎbà8�tËYœ]_‹Þ­T·¡G_n•.Gf“]µó©�ïf¾5È£”m]$mF~HžeÉV*:ÕVáÁ˜_YIØ€•Ô4äç_@k•~‘ž)jkU“ûX»=*Pc#Ê.¼Afˆëãæ‡ò8_±“>Xï�kï‚&rN®î#î»qëÙôË©R+NâL²O ¬¦¼-ðô½èÕ�_æB°rå<Æu€kÙ¸i¦Zå݆”޹�l¹wj.çÂ�ô üи÷~,$žõô«"ËïhKõVrÍx.ÀݳS»¨ü-mX²ˆ#´ñ2�_}Çï ºa¤üñ pÅÁ·*�rõ±"k5”áݨ Ê^§'œ$À�9>t^J†�íSœ×cÆøïšNXÓ“óRÎwðŸæŒæ¢¯˜¹‘ä˜4?×õo;6äyBë1h`j8YÎûaâzº~â£ÛÐú¶�lîx‚‹!…òÊ €É¯k­¸"©22ÉŽ=ÉXÝbÔ¶¯7Z`ˆØVö׬ãp9_˜›Ùþ F«ëÈŽËQû•4¼ý^ ûZW²^ǧ³Ù2~4ñGÙÞgGÏH È@ç«Fž´Î n”€BI+ºþ| ~Uôþl^n‘aýÛªH”ñ謯/7’a�gñq]üÉ*O'{þŠî«�£\áLð¶áî´…Û Y8�Ô¡àI/¼]òˆ¶Ï¹„)w•°Wq =`™D7í÷@ái®x¢î$Ed£àú³Ô¿÷&¹Öô�¤þM„U+{‰©¶ É£l§*Fœ)ƒ?ïf°ì¦u)’ð'Röß0&Ç7#ÿ–>²'GŒ�w±LäM{Òc:�kmhržÉv°Eµ¿Ø&d /òÅX×[·hÁ®ŒuÛŽa¶÷ñÚå ´o߆ÚÏɆü4T „ jOP­3›~Ç�±@‘Åìš\'\š·hÓª±aPà&›K‚lŒÃ ìl¦8£ __³Ù25Þp}ÿÀIjKFõ^mTm™…{(s ´�ßJ¾(3?›Ê¾\7–GÝÛÞsR3M±RÒ 5΂e3Áê‡Ù¯Çìü%\Óv90åÆ.ú †‹üÈ‚G­ÈZiBÎÂÝprÀñÃ6?u)(ñ€?–pسpž¯ *‡oPÙž:樀æ=¹‚ªä8È\ç|a°-`¯K»ƒþë@r²G–{Ùj5®=Hþ®]Î*«À š‰(ì`�<.ˆ ‡¡Å=ÄìÐÔ­ËM1·†ÓŽ"Xoó¹ÊìÊ Â\ßÒÔÜÿYí4ÖÁ½E�8h3é´Þwg’ås¢‰Xµ0I�ßsöÙASóWzgú54Ù_gðj+-ÈàAÞP¹ð“Þ�iO�ãèŠm³P£ü<0‹ RÇc9wTþQyKŽºWBJH%š®6Àz¡D~úa2j^Ë©t)…çEPlÙI¢74` êC²¡%cq<ö^f¯â®íáe6dáÛ-óÑÖk#¹ä’ÏY}EOê:Á|™P·$žXÍwmü}y”þ•ñÆP¾t‹…!ýáÐöO(o;�{MGŒì‚b—>Z,ɵ 0�Oë糎ƒ¸…Íd䆜@àð$±oÞˆÙm-Kåâj¶Þ�*AÝ*3|/扡}ôþ-Ô©œÊáŒí 0’NçÜ·å®U›Ïݾ˂]pá=ýswš¬¸ÝUªèy\ õÔ"é–ûWÉaûãx©Á öU®£ÆÛç`Ù<ÕÆÏ½½$tÒëÐK#˜¸y­ä¬¡°å™Ýó¥‡ Æi°’{ÑYùé”Ã=Fã-°¯Ç¢Û*ˆR®÷ëýt<ûN”¨ö”�Ào¸”=‚Óì«@{×RަQfTgz{«`ÒPWÿ¦sW�àb‘�2Ç�ëñê±X9ås-Ö31âÑl}«‚¶ö©˜¯›ê•6 w¿•<:œŠê£+Ñ5<�YGËAýHz6¢¬»j†¡ï¢1fÁü‹dÖƒί9Côï³hhŸÆm²÷£©ªËá�ÑbîK€}Ý2„~Íņqe²äûNœ¾¹‡£µ;—ĺ‚½k)ºó$Ð×ßbñ€ç º¿Ã·Á«ê ¹ö$wpN n´ï$÷fmç–º4à�áTÔ@�8¨åáÂO8K�‡N¹jt]SYJè­ó•Ü»A,ŽÜ…7Ç/�wõ ¬½øÕÓ•dO,»I>vša£eÑü^O>ýÝ “dÛøR®0ôã‹/¥xß( „n„€Ìö`ޱ|#>aH&+ û¦M1ØÂïþ“ÆÍT"¿þ¼Äö?½x'õVäÅcìÆ4ÏxY×@NØrPB�ƒ"õA¨¸;æLOÀü§°i»2µ÷Sá¾+LãÑ�üÕÍŒ¡� Ĉ@ÆÉÏ$w¸'2Ëñ§Ž+ïnAk3£p²•�šMˆáIûgpÿð_r²$-ªÃìÓšD÷´«–ù�LÛŠAî ¸/ Ž\©uÏQañTÆ…EÑû˶0Ï.9cw¼/xEîÁ/W9­y'èß Çð@ÞÔù6Oi–gZe$sÞ;ƒ·Vû¡ wòt€.΃§‘þô¥ã µÛÌýiö¬ ¸g‚Äq³n º×Ûâú¥­8÷p î o :ú—HÝ*Á”´Ux8°ŽV™„c¹e'Fcu®Šp»£ÊpÚQ%¶iÆN ˜/F]_�ùÛèŽÍ%ÔâÍe´³æ¾¼R�ÄÊ–Ý£¦Š?zC!Rh÷�œ.·øù[¬i„²òËxìö-¸�mÂ�Zy—ö­Dí�^tqÞë?Â=WS8·wŒZL9ºÅLnÛhÍ›êû²5´0-™6•ü¤‹òf£B¥;9w\‘ Ô+Á )îù4;òØ¿ nûDa§‡ÌýyÖß7Ó9» uÃ$M¹o„Y©wàl®=ó[i[î3¿o3  ˜’¿58¢Æùyý}A¢S+ÒBÛgðh@’¬])�[Öx㧸 æ”P¨�]¢ú¥ÔVz\­èäÜ-"¿ K'|ز u[ �<ÂòGÃÈù$GB�Ô‰‚ªâú•Gq4c eÖ<Æ[¥£¸aõ5ðü%†í ÷×yNƒ­:jUã®P»¢ì€÷vc”FqÂÆãk…Yiÿ|îF%bF@ãF4ož�1·R ZH•æˆ&BdÒIRÉ ¶Ïz!÷E±½’†Þr�ƸU|/ µ½Á­Ð_3,'ç—bñ:´MSÂßsP¦a {)} º§ ¾e!ôt^Áë?Ÿ¡zF}œÎªx ‰··àûü•ø<ð¢Û L½.ŠÇ‰@�ï-Øóõ1¬T¬¡×.ì%“[ïÐ ' qR‘’œË¢�v“+7AÝ& —ž-'-[eÐþ~uYÉÃîøtý‡ IJ'ŸvEnÔØø¼‡;® »0 %OÁÜ¿¥LAW:nwlb.vì Î5E ô² p–G±�íˆÞ°–Lþ6gÓw ŸôÝ×n{šs”Ø e£ÓŸxp°Ì… IîhM®šìÂnª„á禜L´›ªîÊ#ÈýÐBL È‚÷åœc>rp&bòkBµfÌ–JEŸ6]ö÷ÞMu+%HÞÜè �µ�˜MãE/ãÇäh$?÷¦2:ð ÓÃk=ࣥ#ŠÛX€ª�>ÄŸ¼J¨ÓqòQv9êߌ%å�ÛiËŒ6Å « aáË/Ø35×7i!N»'�¥¶›è¬œa^ ÖÖ͸èØ!dHÄÈÅ��«™´ð3¤ò�8·6Ä¿„ˆ³Û#20c[Ý$îE�I¿�ÀƯp.u'-Ì8‡sV‡À>ŸÝØ�[ a^‚x\þ)5¨(`V;ãJÅC¤òÓoR±Y“xž™Ç>û J 7ÔQ¿Ê]ì×¢TØÔÈdÌ�Å\ïB2�­s°ÿw ³�‚^_ 4/ÃŒ‹²ø^Ó�«OqLþæ`èÓ’Æê€v¢¾å&í—‚ÌXF2o˜>/ŠÂ£3똱¡2Øž½œlmm%v·iö¦í�i1D¬œ 1q§U;‚“.F &<�VãšÊe˜4g1wyJ1’Ú×Xüè6=F#±kFê,Äï¹Ù”ÿÉ•K½….çÇIvï7,²–Åmƒ€ùFh›ZN½ÿ(ÿR]rÎΞSm‡Fª¹$Šhó_…cè–þnèøs7F qçÿ>‹åAª¤Ï8¶Qíè!8k2D¯²¢-Ù»Ñc­½^Âáö5M>üw$ “~g §è;ÎëêŰßÍ‚Fw}‡Y?rÈóÚp0Pß‹oj+àC¯¸¸ŒPÅürÔ?™Ž“ETó˜9ñ«ýkî\»œDI…â@�§Áž–éÝbÅWß’Î7Rì7c8¼#=í—Òw%³0_ ®/ÂWëGÈdo5Kñ‰#"ŒübLYP ¾¢ ÏÃÝ®”‡] à DSšDí܉¶7PǦ…ÔU,Å=éûaVâsÎòó½Tòü6³Z|Ê«ázÇZ˜¼´ ¥©%‡•Ë=àÚ߯çã$ª*Û@Ÿôfd,'Qð‰<=gËP‡�9ôeS6GoZ?¼•xˆáwñ�ˆ;.©Ä— r,ï w°�—K¶é¹“yB‚0`zˆZ�Bf¢�žÌ 3{—@�Ám|‘èKé§0’°¬§ëÛ�‚§µ”¹GN¿½ŠÙkð´Q$>¿Gô逸–_pôÛsZ¸~ ô%CïæÃX1hC~Y€Îö=xÀ×þ¤ià }= $¤Pt!K^4Ìq�Ñï‡È@¬F›ìÁEOvƒ¿†8†ló£¯MÅ7ñs3ß,À·—ÜAO= ´Ó¥Ðõå"¸ô@�Ù¶}*«|$gßIƒð�(×)�«'ÌШ¢ù†ûðžé صù)góã½Ø £@÷›ºÂÐúYkø%Ù�‹èik'ô­o"›S¤èHÔuº´¸·mÌGý«¿É!½9ìÛ™ðZ\fÈÕÃ÷–7è2Q Nã±4(â ÈöbÉ_ºæ{4™Ñ×L'~\bÚÏ�¢¯ Îì� 9ñäÍ!HØ«~dÃéUõø·w�š;¾ ûç‰p¹ï i�Q..ó"1C{ñâ¾Ó0˜²œŸìÕOθàâ#T¸&Šgç¢Ù9bòt‘ôU°¨Hd>ìåΚ–…RkñðQî×pi¢x¬­œî`ÉŠ.¨ Þ‰G QëH¹°› ”± ui#êÀÌ“dªV¼¥f÷SÑ4À»3è�š<ù:=¦æýØUòy�4··;�ªŒÌÄn§|ÜàL u�8ØíÊÀ–ߥ4£#/d‹Ã�Ÿèûwgh«È5Fáh75¸þ�<Ï\�ÓWbÀr*ú}X}«¢ûH6õŸæÑß衳>5ò•(1Õ«~¬k­YDòæVX¯èH>aç Í€˜°bÔ"ÌAæjÔhð’�ñ7áW`¬Zƒã@úI:ìá豫žv�¡ŠÚµ?€þò,UL~W]<£º– òâ0ûÿ;û1f¼j»V¼ RáÛyYï³–¦yü€˜#;á¥åLX{­ϾØÊ$j,¡ï= y¼ÞÁ\ O$>ôipÝéU„é©4EÚžJØ#ÿÎsR£¾B½µ›2#—$î¢:KÁGTš~ʵÃ=Á»À¿˜=jíéŽqônµ-„ê“ç?Û‰ÿù ¨¾ŽÎRßa$`ôïJÆž# Xó¿§²d‚4\rÇAr e30Íç®:Œdߊ‰F‘’~òÏ3ÚTŠ8xàÞÐ #§öÂBû=äD–„û:£K ‡™Ì†ŸÙ‚Øzò6 «•@e7)6ûL:SÜ’ÏñÜ,lÿ;"tïC•£7†ˆÁ*K’b½¼÷m¢>_ÉËåäÔJ }bñ<,cŸÌ'{¾¯†l‹7pQ ‚¾–¶Á/àë†Æk*|xpY/ñTo!¤âp®…¾Mõ˜N©�‘ÜŸé)·2‰_°JÂüñ4α ýµÕ0;ì?̹¼ jä‹™á›Û°{f9Ž {émß?¤´â8T¼Çt·€¤„‹ðgM¼”+Áý* _ÈRùt¢–‘Gq¶"6¯Ù�ïóZá¦K?.åO$:*w1ðxF\ròð!’˜ÆbdÝ]ŽRè]F_l„�AÞñÅðâ2àN/j,ð‰.û�‡¼ÙB+΂Úê¹P7Bby³èë[m(²ï whIþÞÖ(s£þr¿—>­’c99\Lu“AÅeWÉ»”—úBçd:“g�~Ðå:*åÛÅñf^�J˜>ñ¸Dþ5`�­·`/ ü¾ä÷ס´ ’ŽÜAI{yhù%B¯íö"÷±£qLhàÁ–¥¬¤R»$ŽåO¬s{͹,�G†Ú˨¬Ãwju¢�ä6üÄÎmíDK¬ž) ¹‚Ǻ3Éåñyx!B‹ÐWëÈñ©lúWJ6º¬ÀÆXøÀím…àØ=¤„+Æ�ÛŸû/‚›ËWÌ;Ÿ‡Žë0©´‰³z®5¬íµ)WÑ`ç�Í[ëÈ—•¥(¤â 7–&Ñß[¸ä“ð;òrÿ ̆m…¡ã»z+¹ãUþ3Pis48EùYôªž3Äui€É‹éø³{:Î=]�ásÑÏ[Þ[½£ÑïdP2ø$’ß¹�4ã(Lö¤£vM•ñºÈ‘ÞwŽGà`›ÑX:‹�ü­…ú•p;ö$g»â(uj‡ìÂhïPMVSóËÊ ´&Š®©›…óü&H¾�6|ñª¥eöä¦÷B쎙†kÈÉYF6|4…7<À×¹û¬ËHÁ³TRŠ¥¿–rö¨xb™âFèÕWâ-ö UatY²6œœ3Œ? ¯@nL9½‰6)‘D•N�wá%e÷SHóÞ+tËúD³µŽ°SÁ =R‚Ák(üxèÅÖ�œ]§ÔHÓ®ŸPp¿Žˆ¤¦‘µåc¸ÈÑ­K. ãÇH¤§—ÂÅwzíà Àï»nÀ¤ƒ øÖ ”x;Q0¹^UžKç<ätvàú­épªK-%µFYyr2i#wáϽàü%Œò\bä–‹m“ED¶´�: ÆcVܸu ¾i|æ¬k"‹´;˜ _A´÷úWÁê^Î�T~¶¼n„ª·Wøz2h05-(ü�¾‡¢–åtAr#ì\)Ç�1•eÏÖfÁÙ—Yø{ó,02�ƒBë>�0§Åœqæâo[Ê;½~½8Ž65�ŒÖgH>OWæ¨gK|eÒˆúXD²Jÿÿ¾�'F+¡ß«ž4^5Ä»òàЕT:ôg�­ øXú,IH,Â÷³røpÎ6�00€Ã±y ãJ¦›WѾuƒø}’¥r)] £‰ø/`“`…Á†Ø"Ä_|𮫌þiyZí¢°_Ý†Šø•SÖÊ–xÌßñ«hC£ËnZ³.•ÚÇéa½Hü¯ý* ?-�f’}’þ¤…–@Fû%Œûh7ôbÀé’NãÛ@åö-¤2UhT¦ ªÃ´»àô_/¦ë™F¼½ÂίD¿#·h†ËgÒ�SÌøÎ�ƒ;j,ÈCOXÅ=K[‡$à!ïwñ¤8§‹nŸÕŠúŒæ�nÑý[ÅȃGúìö�³ÌªÃÑœ7>N� Ë]€ýÀ@“´.þwg)}Ü¿ì¸O~ß–��³¸ÿ]yB‰t¦Ðê�»�}ËÏÍ–zOÃwæÃ¬ã,•&…ã ô®ãÇnâŒ�`:Ý‚aqa(.æ•$ë›CHwD+.P¹Á1ˆ\�½²Z˜³ÐRª7W²‘hxË_‚çœ%jÑÅ�‹ë} ɶ›Õ(3ú€þõÙ ‡ß¤ræ{:ㆌÜ©QC¿)j’WcÇ`w¯Ù÷X~”²8bW\ãPxl¶Å‘ˆð@Œrc× zsŠ"“ÈŸ¼ì–GÓ¸³3ÛÈü!+ôvˆÁŽ~b \ø´5—y­O „'�~ýY‚§ž6Oùœ$]t»óÓ°0¸•Öóá®û.�øe¬}\Ad—’€ê"�Õ;ò�,u––bm¦Å¢6§�v¬|e0y"”Ö<ö ¯‹QøÊ+K¥f‹¢àhû,ÜÚ3̈ %3ŸÂÊMùpHíîÂÜXØTì��¢’·áWüAL}3ÁØœée²BOCHugšý æG€s)x1ièÊá”ÛÍÅþ³pÀ¯ÿ³n¡áùÐÛ} ·g§,®³/A»¶#dø‚èðÜdÞm¾ŽGW‰áகøPù ÔQ©T üñ½›ìöJåpÖ_Â)+Ñ´a1÷;·ÏàôCÉ©ˆ‘Á#eÑËrfú¸Rçç—F­žMÕý1 G‡Ö`“÷QXï´Â÷1µ¿Fh\Mž½UD×èraºâ€Áß.TÜ[À5ú¹€Äší@{¹0ô—b›«ãÀ5Zû+ßQ7Qr¨ÍäOV…pWë*4fyNÕ:‡dó©Ó²�Ói�?® UƒCY–èßSJšˆ&÷`V80µCdFI€ò0:ù�Æ_<N­‚Uw×cÿf~vúÙ<|=>†¢›xØëeœ#¿˜b÷lbu“EmHS“jþ�âòðËñýâxJCII…Ri�‘õÜ×y$’ %)„)DD{ïI»4(ʨõÜ×¹KIJ”�™YRFÉJ_üüþ�ëuÎy]Ÿñ¾¾ {Þ”£àôÊÿZDšìqá­úcÜ ˜o¤ÁIµ‡Û*qt­A$ñÒÛE÷>šuW4�œh�ý$/`!.lÍ�ùNÔð».~:—ò¥ õgμᄂÛêbPÑq¬bçqmGLÎd¤ÐF"p ׊Y{z˜ÄWcÙÆ:˜ïȳ‘æ‹eàz–%£é$sýòs—<ŠÀ¿<Ù›Lí·Ù�ú± ´ r<–ïöà­ùûpGÜI¼Ý]�Ê*qö�b.ÿ@vÙŒ~eë0uŸ8¸öFaÒæVFºã¨«Çcéòø¹H£Ž´"rüušÙhë†Ë–÷c‚uV±rŸ±0û€óQl”V¼Æ»Ëñ}A#lVN„â¦Ðíµ¦á§ÀDZ”KL‘¹n‘6Ӊŭ¤Þ9štÿÛ«àóq”Ýr›ü|'ŠŸ//‡÷m¥¼¹>w`AÎqX&ãƒòe—ÉÛ� A¬x:>7·¢Ãû‹×a…÷"¿ÚvóÎ4jòr´¦@ÿ¤�ÿ¸W“Ô†§äÙŠ"¿JqÜ, ÓY‘Nxûõ¿½^¸á¡vt88JšýŒqΖHð8(JÛ[Åa½…ôhã-K°pY^Ï«H­P%œ¹kÈ-7Âm-J¼»N19Vi?ÁÎÞdÐŒ»‚z}©Ì­ãilæ¥@RnN¦ý …ýsðÐ�nú2k|[Ì"Ñ…œ�.2lé£:i9û”Hب⶜.4Î)ÆÝ¶Ñ“Åúâ\¬=×ÞLÇ5A-ð|Ê È6ÌÃ!1\¡€·ç›ÒØ¥k@Â"4}~‘C%"œÌ[9X%«‹R{çsÉG-qù§@Ôˆ|GFîâBÑl85ׄ§{‘}V*0·Ý Òm ™÷Ñd›Á5ÔÛ7·»aÆØsúûûW’<²̯‡Ð—×Qmp-{iG#�¼“øYWˆû+ªIôÛñ$ûe}ìŽ#zc(Ï43÷ÓO@ý~EFSý˜kVÓÓŽÚÌ*§d²èÉ}À ‡²ñ{þ+œt¾*�jÈ#³¬ßäWøFFÛnøÃ”�[‰CŸ8ý¹~âjÍÒZ§RzLå'ßâH­6?b`îTI¢5Ò�ŸßÚ›_“ØRË$^@7eOT.‚ÉÅé¸�¹Âæ~úC‡¾‰q�E•9�…>œÕJŠäÂhq�!\M½„d@‡ÌÈY€AÓ‹‰×Zqø´*vOïbEžæ­§† =Èê‘«ðãp<¸ÿVÐUî{Iç»ó´¡ ‹¼�8Iýîm$ô`?öÈÏ@ï–UTu†¿Zàˆ5þêèd2g÷LÅ nd‹÷3êùWºƒOjΑŽÀvÐ9¢J6öÞ [­nc…Ì+ºªi!ÚJ�CSÓ$jwUÊa-ì^ŸEôã™r n¯õï ±Sƒ?Òâ–T8àk�G²ß³%+Tðýç’ŸG~öeü´“ÁàÂfŒ5Ïiò¯À^á"¸{JŒ»¶Õ› ¬ùDø[tXÁ_þô‹àæ'´ü@%JÝšÆOØiË<š÷ÎÛ«cç>±©wÃqó’¼;wÆC¢Âiº¶ç+u—1†+�WhùR>S]¶[3öc›æ½º—ë© }ƒ7�ÛÇ^ÓDßEü�ÓöÛpxÚB 7[Å íÚI[këá’õ9ð¸_Æ‹~æ†n燨†KÌÏÍDƒ!/L’ #ƒÏ~›N2ýƒ— ˆxw îñN‚Þñdh0Ÿú«­Àyeãqÿ¥T:ƒu¤Ç¢vâ g=<ïÇ…2€ÜTÇÙnFp¹Ö^ Q0¬¿Œu�táñsOÜÓ³”;hE§õšâ6ù­ábˆ¯Ëðýûspîy3õ®ÚO$¯( »¦'ó 1fóa¼lÉÑÐJ zPÐÉ*µJÒµâôö—«tÖ¬¢5S”¹aW@6JÞ£ÂDÛ?6óÂ]�µ'¨çƒ6ÜÐ'JÚ߇áæôµè°Ðg~ÛÉ2ãv°’Òz4Tç >YYUk±]U•�T`šœLøÚ “ÏÒ¨k�$ÙN#wު󿆹Œç\"H²ÛUXg8™û¥‘ؤMÛ³4è,¿Ï´Á*Ø´áú&èûD‹l¿2ƒyµUŽ›¬” óÍq¿J#_!]j¿ˆæ¢—dÓš;Ø£Á Â4š·¾’üy°Â$!©@ WW­ÂólsÚNØ~u+çë¬Á%®ŠƒmeÑHè/»Ïó<óωM’æ^Ì(�‡òJð²t HÏ£2õÞøíÚY|¯5‚f±z´ÿ¿"«öeWˆáv¿YxnI:˜·jÐo/®Ðimxöœ^Ví§¬ù°¨áí)"†[¢à½¾34Îß Þq¡¨¼ÿ ús7Æ‘‰ÜµS©4`À…|¶àß…øåK-ÝY)À½sÜéÄ °ÄÊ�ˆ}N+ÎЯq7 D̪O­Ç)F“8٠©Œ+§IÇ d¿ ó¨ëZ˜ßÅOn‡Ð}£!:üŽ#VÞaÐÑ<‡ �‰½<žòŽºR…¸œa׈oØ^Ö|a5¦aÉp´{Ž; =�€nN ò·x/Cô 8ê �:ô¢Mx$~vxL„e¤±(â$è>æšË1Pý5Ê*z©¡Ô"< ™+<÷Ó±ŽX´ô\„QßZÉ�‚9¨tj&©OMÇê×;ÈoßidøÏbÎø½&þŠÿFÍËè2“. uk\£“EmlÿÂ�õÐì"Ï}üÀƒý/q÷Ü•”ÿŸ?Üÿþ�¤Õx¡öç’ó`;*}ø�‡ù| �•$Þ6Íù¢$àŽ*§ÏeãébØTw�)yñ{îÎæWÈó ÆÇ†«þÌ‚”ê4â3iŽ+Óǧ~¦Ø±½gE«ÁžL-ܰín: Jo> ‚®Ö}ðîÆð�Äúš¥!’Xø±œÆ¿Í$¿Ì-àï) âp£;TŸQµƒ,ŠN�ÅÖrE²�éco SÒµ{֓ø.ËvÑ�Êd|ËMj"v‹X]:Lüæ‡á¡“ÚðŸöÅ.Þ�Jf9Ó ³ïÒ}ÅûP?¾¹ÊjS�™EXõu®ãC5LÂóeáà}Dz~¥Óæ@)hÿ»‘ÏL¤’³Ãà›8œmßÈìI£1ï¾’ÕÕ‘ø05¤+S˜öàùÜX’#îŒÿÊäû¾D�‹×¡7A�ë*Ü‚>¬•×ýC£È"*«ŠN%}d³ÿSêD0V^@F®øîi úêÐ*›kL…Â]zH7•vM)@í¨wÔÂê ªŽÌ¡‹Ö)ceñ|2ÏQŽ/s|=5ÞÖE6Ëšr¯6óYhØeã€ÙmJÿÜý)&ð—–㛓¹„ÞÖä^›×¨‘‚y¢àº¡‹ ñ¯‘ÝC…`}d³GÒõtñôöɜƆ§ìt�A8ÿQ“sB¡EF‘o;o.+ºÉ‹ ªÇõ޳¡ª/.¿dàðá3tËQ)YäC¡!‰•|e o³Ÿáé#îlîš�‘Š•Ï2˜?éÝñV ðšÑKN:¶ÁâEçPƒÙã×ùbkëY(Šø7wÚoÜùmÜ8îƒ�/4 ‹â8ºÑÐ(èÂæSP»gþÎŒ,ÝÝ’Gq‰º(,j}!¸0Í›±ˆ�ÌÜ,‹Äƒ>1 ö=�aŠDGÉeÒºM‚A|¢z ÇngÞü‚³Š™î8–ðâÉß}ðæ®¸†»¦ÉÞ–`œó$ëtŸÐ^ªð¦ÿ/ý²¶�ÝãóCù'èžÆqü]™¡°ÿåyÒ �ƒ(¯~:|KØ9«pœJz÷ÉÂ…ëìy3†L›[N6f£®»å¹#jT)ï, 6ØM]›ã�¤Ïl”†6ç:gòç{qƒR¡¡±Êâ[˜¥Ó"�zéA’ï4š~`Ô>.ÄOÿ�ð.Ð5ïg�úF“I»ÒàÏ.eüýóØTü»§� spË>%ЀÙ×ññ>W×Á˜¯(&£²ÀÄ:™ìȘÀ¿³�À¦]&p¹°Ž)¾Ïªhž!/CÆãÃ[Nt\‹ÄNÖ¡{L`”󰢪—„þ,ƒÙÇÑÙó"™n›Bôg+ƒäBTkÑ[È¿æp·¤-µÈßÚ@Òš’M•Vª23™.úß¼ï ¶^‚ɬA‘À,ÌÿJd/ý†}au¸=}!ñV˜ Žaïh³¤¹0!›M4�(÷W¸±cÒ,u§™Ý6Äz¦8÷ùð:XwA¦­âÞ>Væäb¯Üb[³UFÞQæby2HF*©{ñ X�ãâõù½ždäì/cîiþ\£hÚwó ÔŒ¥a{¢—6‘¯ESAeÀ ŸkµÒý¼Å¨êèÀïPW {¶“Â}"œW“JM}JÏ-߇ê¯Òp-§í:eìACJ­·m7íßz Ê_ǯÑ:ð¬'�<·+%NçÓáA)âÛ:ytؤ�+5ñQ] 8{º‚Íúd™zE®¸ ïf�Æê!Y©0�Lú¯�ŽÅg²eM౺”¶+I‚ef½VÒŒVæ€Go*5Q1�Þ̬I$r‰áXð&ƒù|x5.\ÐKœSüiÜÔ ð£k/v]>Œ#〿4 rý¡Çüé賟ULáÛÚ¦bŠi-IIÎÝw£Â~îtö¨4lžKúû3 Ï3“5.X¡³Ÿ·æh-x+7‘·©~”> Ãqçı<·Ž¶_QçL�ìD›Æã8çe'FÊâºÞ°ÓÛ>ÝðëIy 4pç )ƒæã¼0�Ç—ï�Œó»;0lq|“ž‚ÞíÏà‡ìz4¸Œö\„wÚçy’ã(-ÿó×_�GßT]F¹uiÈÖ‹“¯ƒ[ eýD~Ͼ,aTø™�Âÿ<<˜Ð¸kY yó=\~ÌÞ½t_LpÅÊÅ.˜s.ŽxÑÅF\УȜ«˜�JÇràä~#ì.l€Yw(Ýð|&lަOr:hzv=±ž Cæ q)ûõù-¹Y0ôR÷èúã‡Õ èÜ&’Ž­˜ ÛAüÏ0[Ò8jš:óØD¸•ü %FQ¹ø©0çÆ&(`r¨,�™§RQ(¥•Ù½[ †ßŒ‡�KÖƒSC N^¹_î'i‰¤²æ¼ö‰Â5;SØc[ðüÉ0ì�5¹xT<˜aæÐ’; Bé瘆µÃ8y�>ˆšƒúú¸lóUôžß ™Îcõ�Ül¡ó�k)�˜9ÌAïÏö�6êM|¡ÑÍ#ç¥óªÏ,…0‹Ët[†6æ�çäi#›«/ÖU//+m¼ºÚìÌR`tª ÖYaÝ�£èeIC¤…øtÖibñÚ�}“�?]è�Û9¤õÁnHIk}âÇæPI4Ê3GÓ-쟶p’a¾ Z[@”!…3 ^!ûS ~JÄÃlÙe`û®•m^áº8i~îõ^°Z•{´ø8;6¾‡^¿ò–4¹gºo�ÿq$–±' Üâ>µ½ Áœ“�â_pv\–uŸ'ƒÍ¹øq �ˆ\>•IˆRsᨠ¼«GÑrzé¿üŽ¥ý³ÑmG<ÖL ƒ´’}´}×*`ßÇJÁWÙí¢Ï‰¯Cœ¼óBÏeabÜ'”ª ÃÝsXèsEÁ2|èé9°ŽæçOäþÖœb�h@ó1´QnÄ»ZeÄoÀ½Î@|ÞåÅÞêG‡~__YÇîè~L\”eËE8…ß�l–�4۸ñna>Ÿ_�BKF€ÜV€‹+¶ðw¬Ïƒf5+,2A3C ɰSy¬ bà!ŽæÞdN)ïcÙUÁv—b°VÒ÷;Ðg¼Ú»á<¶Ù,$ÙýåÔîÉBÔ‹›Ïm¥ö�¼1’Þ(7á×»+‘y®S`vÉBütX@f¿=ïdI¢jÛ£g‹ÓíÉ×1Çr#ž}4‘â_ !{_#tP¤¯‡ÏQSߥ }MŠ

ž ë]Ïãç cè¤ý¼©¤áÔ<ìa›ÔRþléz¢‘ÛŠ÷#“iLf5ëÒó…¹ú]“FM†.ææ8Õc¨P…“ºCæŽxÈþ(” ªð'Vß�ev7`Bå\²¶ç6°I5Þ.ÏÏ1܉‹]àêÅ}˜í˜ÈÜ6ÄÀMÂü‹}|¸2· V?¢®òü‡+Âá•…§óf6jI¦PïèGìÒ§lÕc·$:Ñß“~Tl€öˆIÜ ÷ñÔV&„œðk ÷’5Ñiµ+íüiK”f¢ãñY Yë ½ÊÜ�h+rÅQŸ¸jâêÞd"/{‰�Ôý‹+M�`Öº>¼5Ê#â÷ÇA‹ª ÖÂÜWè OäDøJ÷w¡Æ`ÉÒÈDïâ,^q¸ÑíøÌ^ú…^‡ ðZÿðˆœÈ[vá(LÉ:�‹ò�‘ýZƒ (ÉQdV÷ˆCC^¼Omg]¯zÚÊrL—áþ›6“*å>þÇHN¨ò-‡˜=ËxPXá�­YÚtë§çÐ8YŠ¿þ�=õÃÄÏä‚v1áo¼�_¤ôRd`éµÅü­�عÞ�øUþªó|\]6JÉøÂ­þ[Šï™ÈZÞ�Y'�áiüz2[¸xCe¤CÃß ãÉ®‰Ôy¾éY¥Ì9æKÂæà ýU„ßµ, ÂNMåK1˜R´­¬;(ÑË„»ê%àÆ×­?�é§&Á—7Â\Än⮕×v£A¢$麂âíhVÚOC{âÍqsQí¬:ÔÕ&žP甋Ìܲ7˜™ ;N¤£^Ï0½+sÎÂpHzU€5'ÙKÉb`j¸ËÔ§ gÿ3jþ#ÝWã¦Ö*zê6jéößUUˆÅ$©~ úJYcýmR±»žìz–ˆi›5!Ëô¿ºIY® Vã [p¼ËbNý¬4ŽÏÀ­èc‘D¼0î)m)F«–|²ÇÖôtCÑkq.uä ãOÅÉ2Ç/ôÐOXëųãY‘5+ÑÛæ¾×‡bü°m3øJá tk´5†LèÇÕ�%˜VÈç Í6�Id8ò¿…oËpAºp÷Ù½çU¹žïwßdÅù¿+p îüŽB²hx¸…Õ�Pk5šYB½íD¸ YùþƒsÖ<5®z•5�qׇ™•½P÷-¤p“þõät[•æ§5Ÿ‚o›'Pm h³ݧ*R¦Lú&’Äe¬(—çüc¾Ñžm-ôÌea~�š5þ™lŒr³¬p^ RAÄ%hHcÑ1¯‡w óÃKÚ˜A÷ñØ­¥Ï�œžÂg¹1{3õˆn»#.ÊzIs*"÷˜OîÕ»àÆ€‰\w¬6v^ƒ�¹!ŒÏciþí»Ò´6ä$ ;Cè¼{Ô"&ž0†°Ý/ðô ;<­o„3ÊŽB¢í!º×- 3oÔÂ[óÛÔóÀ¦ØÇïVTÁíD{.¡xäÞŠ½7?qÄÓí¼¯³ïŽLÅ]ÏüȇºbrU��Cæ°vŸ§šd…›7»¢ÅnJ¸Œ�ÝÉÂe©Ø²Å«w>Á?®Ù¦j—ÐnQ){S–ÅW¹Â\À²›XqG€û¿)⚘\Ðh9ˆ–&ùx1&–\r›†ì§0¢0ôLË�@¢l>&ºš£øö_̱”ËØ3L§4ê£ÿ£L&bu%d[^DWì¥A'ü¼D›Ùû9¨ògìV;ÇŒ¸›¢ø+s¾©{„)ºãõÐZ æeÕ\tÑr‚h,ýE�E4À[÷i°Êìb1ÄÿÐb¬�¦òg�)„ÜŠ‹”§Ûr‡NÐJ47ƒÈ[þžZ†§-)žîŠŒwß…]Ò;ð íz´Ü BËøgç­„Jq húÒ aAi˜ÊsâîŒÎ£Ò, ¤Ãx«Ãaú—7à: ��'èø±8²ËÊ×Ë’P' úrúmäɃé¬*ggÝÆÎO!Ÿ®‰ò³¿i£ÆDðÜËJ¯‡3ïà´po³˜{ý°mµ<�¿…ZÅ-‚rò�õlùó ×ÏZO.,bÅ:%ùÄ/Ÿ�$¦ÕáÚ“j`r0‚,9hå9“ÿ®ÑÕZyÄ.ï&è~ŒÄûkWpæjÐÝ„ÃkïÑ!Zµ1›L—A?0©˜µá5$fTa»ÔY½¨ «-ž`ñqÙï2(nVÃGÙÇA\æ,}g4 j˜lx$s‰”” “ å# IŒ!%®Ðtqß8œbd@o:êðls’ ^43Ë…ðwÉ0=åÙB”<üÈAÃíô÷4{”Ã�>w)ªÁ§uáà½8�ý>–OîxÇÃÆÝÉ(´B:Ç`Ï·ó |±ƒvµ·R1S5bÞ¦ÉW™®ÈﮋbŠ»æCrßLš’tª\mQÄ݈8e8ÐÁî Xæ+ÉUz†`ßÁUĪZû=v3l; jÞØ18LV~Î%ÿ‰ à¯Ý/*sY_%VOµÝ 7<êƒÓÍÛgq»¤¢ÑôãvöÃÏ‹ìÒj)þªËEìƒ]À›�‰6V9dX<ƒª4óÙºð‰Ü–Šœik‡Ë,¤!ÁL ¿Uð„FÑ"l·R÷alß_ŽO té»GßÉ›ÂnAˆ�9"%�Ðë¤ë?ÑéžùôgÃVëä6p>³:þ\ÆŠ¼ùøÁY�«íW…ç>B°ñ`“ÆG~«VªŽBÜ@ ôð/gWlRùH¦0Õ ´,†ÌZ¸„¿$:Š�ö�­‡ÆU;ð”ôº�áþùÃëk¸\ �k�{ûœÈí:��^”c›>G_ë€Ãm%îMù~"MÁk"‹ðÑcw& á…�>Ъ�§z ‹yW=šaþ»Ó0e4�žI‡lSŽÜ-¯‡Ùo¥`¢c1¼îˆ/w`ò5!îüîSäìü«˜2©•¬äàuÜ 0½ÊRœÔ�¸c|+7D¥ù~ÐÕÓ¹ã”qÊî|X¾.­Oße%)Ó¿ÙùÄó¯ضøÊfÂ�3£¨Ùù‚›öâgÓæÚš[ÆÜžÑ|𺑆ë79£å 1—½{—|=�¼·©…’’ýäÕ�v"râ%ù:¨AÚýô¸ ‹MO>�MŸ¨÷M]HpšŠ-SEØ %¤ `9öìu�Õœ ìó�Ç/ž!ÙD¬¬Y¼zƒô�`¢T4íúEÄ—~&QJ`th)ñ‰£ÁA)H\‚�Ǧ୆.\Þy‰Ý/Ÿ‚æFûý¿“Ÿf÷¨oLnržÁMíh¤©ŽÚtºÖ�x󘙓[‹ná­c&¤´ï.9iÜN„+]�×�Í2á}PNi¡‡ `(Â*O‚Ø2#vSç$�}“ŽW箂ƈPY-ÏU3FDº-àôò?Ð3ñ¤™1ÜþóÎÔLrt²�ÉØ�h¼y]Pvõª`B1R{ѺI é”·n ƒË“qûŒ¹„1ÆZzáÆ"!¾ä–Ò�ÓÈò"?Lºvu�ðô„XXzW;U€ày^–zþ|Ó=zñïzuÃòÔ{W”húyŠ4¢¦Ý?&¼@&ª…ƒ�úêxÌ�Zµ^"Ó½ÅQuÓqàm¹¶uðçÃ2˜;M¬òFõsªdå³X ‘ÒaŸþËYëÿˆ¹Îc25¹ŠÜ°‡Ã'Úï7 S7�¸™ ‘Þ;vÄóA4žš×ˆæ—t q&îÚ²’L^ªÃ]o÷¥Rø;U¹ÀúÝ2CkT4¨éÉ5Èþ÷E¢WáÅAIúy{—à­ñVògøßøú™ÄöBÑ`-t×ïx† †¸I{ÖÍÏ?ù öÊk‚°Ã#œÏ@‘œ'n½¦ {å§Å¹¬úUQü±-Žÿõa �ªpr¿üéÍG¶(4º”îiòN9|£ïîGÒ¹çk©Ôñä÷™ \}—¨ÜË¡Ÿæ‹ó]Ûrxч©Å~a~üšâ¹ªôol� ³pÒÊç0YÁOß™êã’! Õ^ÇöbÚ£Õð|r$žöÇ­VÇñéº<Ôˆã«0#øÞ«JlŸ�f‹rN‘í{vâÄÛçã.K:óÁ72?§w� �…ªÿòŸ—Œ{¯åA—ŸÜV}�{JaøzÕ2¯M��çVÁ…ÓLðþs¼"ÝlÂäÛô•v¯X3�öïpÀ@Ýu0*¼–XÉZ‚àÙz”Û[Š{fmÚ_Ú™¢h÷†ÁáqˆƒÞ²˜³û¼f–CdçTþMŸZp�έ“@°+VKE ÚÒ¯´¶Ñµ&‚eÂÌÕ ¡þ Äöù|ùaåÍQÆ|Évy$ ƒôÀçRJœZ@7ÖÄ»*µàTŒ�Ç-ÄmäÖP;ÌKhe�a¿lÌb̽¤Ñ»Y,fñëè«Æ)üâè6ú§£¶Óz0œ_Œ.Û¥ñDE<¬¾‡›ä*ÙsÁÕÐYg†ûc©úd=º¥YŒDä<‘oí1µkî¤gŠîQ…EÏx‡ŸàÝ7º�¹²eæ ‹u(.š뚉¯«?.Ðá^/7 –RÀuKþ•ì¤+ŸI�ÿh0q»˜ƒ.¥KáÐ’-­ˆÚãm 8Ñ¿¯ Ãý1kÐùꜼó.�TQ†åJy0�¾÷Ý�ª`a.òÈ5Új²—K„Lü¹é8mžÇOol'ó£!¿ úò~@tj!ír˜Žk¿·ayíl,ñÎÄœ¶`þ©—>þsœXË™¦ßI€ǃqVí­w 'ñ.™Ø|f'š:܆ÙZÖ\±Y¬ø4 ë 0oº7ØÐE”ùÐ5_0¦1ÄÏÆâ¢5àß@Nn^Šõ^ÿáï ¦mŸ†Zgu¡¿X�êG¦1WÿùÑ*gqlœùŽîè(‡”'ËуM„qMoØ¡:�í¾š‰˜<½”xç¤ íˆ ÚÛŸc—DùÛbd‰¹¥0\‰” 7ÍBaU²4°ÒÜǰ2—–®$Cêµõ Ô‰†ü�i�ÖÆãqˆ}>DªÍæ"i‘çß2¹Êʘ'Û©ñùFèxýŠ?w“T £~® Ö6vâ¸~žûBLžF#6‘¼QèÀ•ÜT”�šë$Í |šD¸âýþPª§$ÄM”hƒ¥rã°¶J@÷ .á/š†¥éã±ÀN“3:›Œ£â�0i±<ß)TÅÜ�á=ï h¨Î Æñ>ô˜ºãÔ¤P�Kä'À#ÛxüÚÑ�ó|½qðŰ�ãá–p2þ+è¶k¤Ï®.AñítùžiðÕ£�êåia—‰<Þz�vQídÇù¥T¾l'ûf ¾�Ÿ¹žtœ+‚÷Ôr.8o�Àý³àºÌ8`ˆý&ñtÖÖã´6#’.úàûöžÍ±Pbš£᳊@Ùu UŠŵŠXðדƽ²…˜‹áµT#¬¦.¯RŸÔW¡þþ[DKô$ Ü}wU7’ê.~ä3zu¹ýdÄÔfÛcÆÄˆÌŸB½CÏà'ÿW�úG}êòð³n$©S9D§öìOž`ò�÷`5ÿìløÅªGÈM2zÎ{†aÖ›AÐþ…ž�8*'Üq´ÓÒÏ ùÊ>ܦ¨‹ôÝ <ñ�MXÁˆî|BEä°ýË,ˆcŽ6¾žv/­l…òIS¡¶­®ÍÐBIš}¨šè—V²¦� Ä÷O¿~Ÿ©gâÅ®Qvfn(օ̇ /âÏ3Ê‘¿ü§šª¿2‰É§pö^©?­Á½¶;aqÓAð/¿êÎ×ÀÅ`_�ÌxOꀤ5'؈ìžÊ9V¤ÝÕ‹á´Œ”¿ê†mnÂýÒglà=“φ™n·Á•ˆb¼>ÿ§Ä2ÁP¥8'c® Rc ] ûžÅáþ€s  �®ŸÇèC,;[�‘zŽ]%ßgàdÑ¼Ö ޳ûýØ{Õ”�l¿G æ¼Ûµ�¬Ä§¹UDòVˆ}ÃW–ãÏtÛEÑ}O�¸˜ßá´ Å�2¨³v71;}Oí%ŽS.·ÓšçÚ ç¸F³ú˜ ŒÓÔÐ;C§>BÕ‹°Ó(8=Ð c|]æ�-­Øú¨…øHؼ$ò0‰‚eoã0U© ÷Éa¤ ‘ΪDhlòbÔW¼xŸøK,VTª) ŒT“Hè�bPŠ>×2ð {˜¾3k¤;Î…Þ}T+ñ)¾¡†Õe!‰·H`u Õ…[°ýrݘ¾‰¬I gGY—ý3P©E‘ÎГć«òˆ�R:k£ºœM¿)ƒ<‡¸s9ö”já­w'¡Îý~)‹€ï.9tú™FfNvÕüÙI–ÆLäþx3Þ÷^�Á‡Ùü”‡‚“§\xieoèÕ›ÞÔmCyäP‚š‹–‘Û—êhÃu SqOöã�|4ì/Á‚*à�6™©ï©wïZ8H…œÞÓ;ŽAZr1(HœG÷ökä[`22ëð�½ôó4hú)ÂÞéÀްÇd«ø¬ß‹û?Nà§™¾¢›½âI@iûH\ 3”åa–ï5xz#T ×?›þ6>NÅÞ qC‡aíMNZ¿�¯®e9¬Ì]‡ $ò˜HanÞ¨µ–…æ{ æÀùb ¾¿ñwþ¦ _ÔoÀ¢ù”nUÆ %=D6æ;ókk‚@§eÿcÛÑ|“lq¨�§ï w�(Nýù böJ’ª’Sè±i_¢è2Íû£GŒksñí‚o¸)ø –*î£BêË臇TÍy´šZà„‚4�øiƒ’×vàíŒR&[¦ŠLßvB ÈìÛŘåPD.kyâ§}˜¼HÏ’pµ*|)G°i«{ôü×ø€�âƒoÅOÀŽ ×‰Ý@$�ùhöWéóµ?–âheÉ_£¶ßgá­nä�Øsšø Bóö»3ý\蛡©äoÛo<£y¾ÜžO%¼Š!H|ûƒ_J&‡ê�súãà’V •sËFµÐLÈ�ÿBóü¢x¼ÙytCs ~u¾�êcŠHS„ÐáÄ"êe™€•-°¶Ù ¯ poÑmÊþJÆ ¦³áTc'±¨j"G?øoóZüµ` Úܘ‹Á=b¤øF�÷˜?,iÑe1¼íoÆûuºŸô9¼aòV[Ñž½� Û¥ _*ƒØàsØ÷oîLráùQ D’m ,,wÛIlê�èã\9~œ(Íz€ó3ÖàV-g<ìèŒì%Æ^pŠŒ·;Ã[dé�îb’õ*>=�ƒ¬“›àAëMz<Ë£Fƒ`Õù—$øšÔ„T¤ZÕ²œúöX¸VsµÉÜ“9â\væyL?qŠ$ÿyJÎêÓ—ô"#XL¦_b§„wED`qˆ‚™¤éò fðBÞ™ÆFØã™ÎàrL5Ï�ýªÃ¸Tê.õ�áNˆ]„� ÆÜ¿Er«ma^­¿Ýaäø2œ¾÷)]2v–„ ÎS£†{`>ÐLM¸GpÓö"žµ‹ A ç`ÎÏ^àE» {HÀÍU€)ÿIq“�g�¾ñ+pß%8ëoÄÿ�ÛhU“&,XúC±D8®‹]"MÛVáº'^dÝ�ì÷Bpc‰Šå©×X_’…çŠ#i¯ØDöÇCu¼2yNÌsF³j- <ô…5Õ¸F{׺¡åV˜{à=¹ºÿ;Ö@·"us;Í‘¤ŒÁ± 6ô)ìÄϲîC B¸n)adÅ>ò£–/Ë!3�¿¥g¤C‘Ê\¸œïZ7sH‚ú&fªÒF”ìpÑOö¸®Dž RrgÜlîxQL”ÇÜ‹åàž>†rƒ‘ø–É¡çjGè˜ÄA28OŠÿÊu*oxè dÏRCM£ˆcÊo07ç4Îè‡*—3à;+K¿ªà¼ÁÌ@ïy¼D³S ê5�{ö²ÌÞÑÛîCÔæ0û¢5ѱyHîK®€¹z¡p_¶L`2óÛ§8‰Û¡>�HîHG~¡)Q�ÚGx SÐ×~³ï×Ð{ÞOtÂ/!õúHV˜hÎb‘ô¿&~�Q8×­‰ä¿ã¡ü>o¦¥È†lx =«ÍQÕJ >?{�/­×aöÔtˆºGÍ�ª|½ 7Ÿ€Wg\é„¶f¬ù Í#âØì5•oìb|µíÈZ¼ágM_Û?¥³{'ÂãÑ"xaüuÃaQÇ!ºU·Š‰ûÇ~Aο` Çâ‹ý™’+©$) É  p¸�j¶(sëÃ�nÉ^èÔ;M¿W/…]:¨~ï'+-yŸdÀŠAKl�³û_/Å�Zø*õ2I}�vK2 is1Æög¥V¦"g&OìO¾�Á­�Øm:bßdÐÄ·ò(l>“‹(=�—Î@Ó˃¤©,§ùÕPÞ%7ò,ý7>Ô›ÃÝ™Ég”º—€Ö+¦Ï3\:/Ò/šHá¯Eèý}&*Cö•2"9µè.ÂYxŽ Eòwòëåb(š;Ÿ˜=9 ÎE«Ù:R xæâýÝ_IÓ�‰ø'é�¡ô ^\÷ê,ÏMtSÂ!®š +“A_Y –ýÄ¢í-?«ÃLÙ9ÆlT7ÂÃÅ. av‹hj¯ZKÚ†Ù%á)dæü/ää§_äLÉ[ÐÛ”B{^Ç‘­Š¢\wS!¢zþžDeûNÞ †Wï‡W£²Eu�޽‰Ç®Sz±C ¯HÒxË™Œ‚ÈE’+¨ ¹ïlˆÊM=8<}-½¹!9æhl8GKüÆaô’PT<ÑG'‰ÃuçDÎM§?Ì.ÂMÇtèJ\Á•7p©E66¹|güVJqŠ·…Ð÷Âyª|��¶Í†¼õ5ü(—îßÅþ})uWûØýB‡©ÿ¶uôòÖ·ô—\$ý4>%Ž àÀëŸÄé¸ä»icu¨7Ì{¸êdW“¹:´Y¶k–^ š{åøÓÕÓä²|b¿›é,Æì $ ÚÕŒ°þÑ~ì<¯ŠUpþ�ï`ÿ<cÏ¥cnü5˜1Þ®ãߘ1H4ªÔ#î•ö…±¶Vº®c:viΦ²L4+dã‹EÜ*jôX�Û~*…nÚä5úÈ!Ÿ ¢ÿt j�öÓérxA#î ^ ÇîŒ�{Ï^ÒóW·¡Ö¡Ä©[ýKi´Ë¿VÇfyÆ<4”˜äÍ¡ý�ýÊHq›°ú+JñМÜäÎÌU«¨"ˆ»ûƒüà…âپèÙ{§G“À&Iþª÷ÏÉhÙ#ÖÉ;ãMhk¸ÔÍ®S§L/Á`èSv‡ ›îh�À3³?òÞ» SÝx…¨EWS·­ÌÛ r%êü—r»|9ÊÓE•‚S0!<—Eú�Ù‘oÔ¤2†([oÆÉvYT6Ø–Ô§brå7"í°šÖœ¶Ú„޾å@+ô=|5”�€¾{/=à¯C?¿„ž\¥»N£LGúQ¯ž”'¶þÕZò³ó1V/§Kì…¸O¡OAqŽ#¾²¾Bûv~$¶l«>WŸoY)8‹‘cƒ)x4à ŸšBÅG¬ò8Î&¬ª&–ÝF9ã4Ô •3u þÒõOÃ#¨(ÌÌÔ=‚QÚ°MÝ„¹`? ºÉ¿Y © &òÏ ò÷v1:²³¿ !VMdŠTåqó”Å�6Ž˜%¦Â£whgB¿u~ÞM�/^@«¯;ñ6Â�¯O ³ª‚FcµS|<Öˆ=2c¤q;ÿŸ¦LñjžTðŸ3’—´ÐÞï5„ßg–òð€ÃØ“ƒë—…b\èMp x€]]שÝ&Jt¥UHëÔfR^ˆy|%ëX«; Þž¾<ç¹à2ƒÿhï¥,œ³ª–, ¾J�èÐyIò$éÁBÀ âdÒé P®i'“œŸ€tMÞ›¾‚ü–þIOœ‘Ä=Gº@bÚ ¶– ²•iÑÈD\Ñ÷ZB¾�å=³›…'«OÃA›`l‰ìC�£©lâ­;tó›³øû½¬h¡O禠ð¾i¨â'˵¾�Âß·òÎ,ÿÁJ¸ö²56àÍÒX�߃‡ÞÈ‘÷çkIwy ÜM F÷û!�Þ¹6øž¡¾Ñ°½k�½59 åä�¶úCÓ_{ 8dþïmtòá¾F'ÓWÏѰz;pyžŠ2›zÈ-]Eô®‹ [W“or»H€ú[Y\�>~ã W ÀÐD˜SrV“£id«ä ÞV„¢Q×Áôögú.É”bw “®ãC8,¸š„‡kW³��AX6“´­ñ!ë6wÓ;6 =% ·ÿ€sP’´ßŒ¦-íId]‚3Þ¼ÕIj¯ÈŸP8·å“÷f*¤þ)¤åž‹1¼l2ÈàæÐAíœ1X>w'^±QÄÍ»s`ÓßÖþe ˜k¯£y6¿É*ÏL±†lU�ÞIÆ¢ô€7v€&m=Iæms�_T˜Ø•w‰Õ Yø±õ"œsòƒ»^,„å@qS6Ý=é ù{—ä7|&W¼&Ãö¾s 9ÎJkäàg§Alò;‚GFfaÎórVÅ« SýóY¡µ Ñsþ5˜¶^@Ʀ…—M%¨š±‰úêKñSfù"÷w"ºIó!Èb˜É–úF·?„¡ÏhœJ(™ ÏkõIоá9(1�8ؼƴuþÇÑyÿsý½<Ù¡Œ”¢PVC!Y¯ç¹^´•RHRi©´T²·D¡Ì¬ìl!^Ïs½HQ„4¨¬¶RoQúú|ÿ�s;·s=®Ç㺟Îa¿´¬Âá8#|�x7v»�Á¹�8h~ 'IÕP=ÓBŽÂ÷LtÝõ�ùðÄ\¢ PÆ;ƒüvÝEìkÞBÝ7¹ÿý ßËbQv+üµ·‘ô¬¸Nì/×i×4šŠÍ3ƒÈ±·2ÐrJ‹zÉÀoITza@�󇨮Ñô�rÎLÁ½=l¼Á×oÎ~ºKžŽ`®ÝKžûÏU�Ö_LW톱5ºÄt­3¾™mT$puHè¥Ü–Hê1�Ï¿mÉüžôžFdx‚õÓHr´·Š½ïŽVy´ÿïA\šÎ£å_wñ”îš“ñam˜ÒuœWô�‹#ºOϸ¤gØ‘¶7\¼>#u6tÁ¾¯qÈYü�DzRO®Í“\ægÖl·¡S1óû38÷f¾ë­ÑTRàñ)ÁGïÓn¾+g-ƒï-^sœ—‚9K;1rXž/¬ïCþpÓi—Þ Ö=[KAÆþÛôLÄW¬øëGlI1š±=®¥qŽÌ|;årÈô¹±l»˜|Q¾BÄßÍ'v™ß¨Qk=YóV½ n‚¾î*,ÿãLLÔ&ôY ßÝ‹À‡wVU¶Òš³}d,\Û ý ðmçKÁc:¢Ò‡qCnô×ô³ðVý;+¶`G†<·Ès%_äÿ�‡Ý¡è¾éTmâ*Ð ¤‡éâHºáºUËQ±Ö>+[Á¾ë¨¤nÏlƒÜ÷Úàß¼ �ƒê‰¬�Çîùj¨ÌQeo‰õ rX;Õ÷Ê$7mŠ!úJ7©º�Azð5õ4yŒ)·–Cøßù¨œo€²–«M¤’Íq’¦%†+v·7…ôa¨ÖøÌÿø…P5S3|äQWB ßñ'´ûEr#ç#‘Œ`ç]Èa“Jæâ¾´¿ÔÀâ ÑŠ§çrJá€U']*éÂ[ð˜õ ìÖBZ¥’ŒÅGз^‰»áÞn*î$ÀoêMÇŽý;p圽ŒN© ª ¯Íj1¬7±ƒWãÎ( ´Ó?6ÀŽšü0ÿ:º(amòTî.ÁRrÉþ4Õ]…åœ#pØ0Ïoß#ªdÆ�å ²ùHN>G~R!¢¤0‚Ö·x̦Ë0q±8ÿÏw#xá ‰³ÏÞgW[Ÿ‚¯I²¸Bj�èk%“¶.è9³ö(Zà�§¨Ș4~%+„iáö3¸cßO2’9‡6{mâDôÈà<½XÜÒj²5.?ûoå¶–‘ùË&˜î”ÖD¥¥9ë�<à ÞpH†Hªåö{pëk/÷Ý[ÔèÓ�’eùåÓ/L�éR½ìÔýJørVø[íÄ´èË@Möá̈Ø> ž/¢¬G¢šÜËÆxËê“eFçe/£ì{còqV:¼r³‚¤›|ð;f‰á3 ÊdŽ¿$ =ÁqÖ1འ#½VƒÓNnEŸG8vP–¿ÿØ>èÔ8M.¹}«‹…0ꂬ\ÛƒŠ“qéz5òC–’ ‰xj«¾�œÉ7J’ 1Y§9-oØ×~�'?’+ØÇÇkÉò‚.°54‡Åó~ãÈ–/ì±ìlæÆh°m˜wöa]Þ,R8ã!íßcÊÆÝ/¾k$xa=ÛlK2GvÒvwqŒ~ÛHÂ]L|F6)ò3öLÅQªe¶J¢ËÁ÷†;œ^³�åï3Á§3‡ @Ó‘Ø%¨BõCu\|“éz¢‚^õúÜ÷#éä·•´vsêÄ|¦Ïš~ÜF Å]ÀôÕ;ªñL ›×‘õÞ-¤æÄ\nHÈ=PóÑÀ&Žnè¶§û–~¤“/ï�_WÖ`¶ß+ÃhÕ\­J³˜3&yå¥t6ÝŠ¶W§pÖòÁ�s½(çÃ$T­î£ÞO±×lQPtK1mþ>S²Xï=ï y·çñ;â?Ãáz¦º9 |tÕð­²2T¦€Ö¹\b´ÃôáÈë�8ÜCÓg”GÝïäÉ"_\:|‚ÊÚQˆUé$R¹w ÷i-kû²€§S=†Žô T,å;Ÿ ñß½ðÜÌ0H�‚­JÐKÒ‡½Ö‹±ß�Ç8Ü,…É÷´0y¶<ßb¥:ò|k™Á_G1vÆí¸"�'Å— F·-VeªÓ=ßÄðn�.KÄ/Ÿ¦ùx“$.½@ËŠ@œ�)éeŸPÏUOaß[s6âôê2�€î3ùÑ&”:lУ;“qóp õþœ„v§_pÒ·eãJtP[è‰X}wÄ'Kc«Y9iœ¶WÉÛ€â}X²–’y_g ±ù{öÆÇÛ @^’éÁig”%­óýFZ?›B¦•ÎWƒ±ñCø2ð”Wg{ í%ˆ±†¾P…Éëò)´+R§1üUw“¾Ç¢È‰õள«ÏßamBgÃÙµz`¤íŠMF8j÷‡Øwá²ì0¸âtÄ%‹éØ‚¢L­@ëî‡�BæØ’â�5{k¸ß]Ÿ×‚´e6»U"Û?ÊC;×7;iÂÉMLù’bHf°j<€\ýMÐ{h3ñZWŠ*f”±TvÕ=rk†<ðFuˆ™ä{œ=ZASöØ¤Ý ™#» ¤Â†¨ìo"jéê0-9̺Ú1ö©ÈçÔ³£WÍñ‘ñê§Î7Ì ‚lÇùX³'–Lsm&®r÷èÙôõõf�D§b ˜6¼òh%"ɱð£[Ž[QpžfCg¼$Z+‡zvÿðŒõL�ð0£¢rÔŽ,Ąǖ8/8ûž`϶9$ìÝLÚW�—~)b^“ú´Àx¿æLbÏ.ÇjXyLJ¦óÜ‘v0§^¯À�_9ÿ{«ítN Þ—ËÙÛ5pãðMž½¡'™œ@™�KËÉþÒ-0¥p~?¼æÜ–§m² ñɧ+tÛ,WÐÊ€ƒâat_W µ�y…O bø¿:¦Aö/ParاåøýæëÑîX ‘æ7v4a²ØA­œ ÌPñ˜È…ìÝŽ<§beøòÚîÕ o¶¶?׳çÊdHá >ÌD6ë|£¯½a‹¤Ñ}t�h-ÁïOS( (‚½;Èo™ÜÄóáxùÝ }ž‚ÆY1°Ý×sퟲ5&ñO•�²_v˜21g0÷µh_ާöû´Ñ't�‘§Èw{›†‹K–àó:M 蔢 Ì¢"ý�ȢŅ“d÷ä>¸í+Ο;ßïÆÞUvæ9pϘDfÜð¥U�Û:ÂÁ¸Uœqüs—8d¢ÂJ[¿Ÿ(þ¾?ÁÚŸˆßœ`ä‹¶ƒÆ‰SÀ»Ü†÷ûâÇö"ºäƒæÄ˜Â.Ý ²¬u5ÉÐ"Ò׫ág�Ȧ Ã/9軲‡|[y„}ûǼŽ/„%KD!ô« ÷´ŽÖ~W ×*àMOs¤ÿqÊ+o]òÿœÁ»±7iYg?¹d´ÔÖm!çå üŸ);Œ™3eÐñ}Îð½DÞÌ÷¢Þà¢Ë§[—s»n7áiAfá”fXø"�TUˆP…âzª4;Žx»}'ßVãZ?H‹¤3ñýó›^’jÅÈoK!åE®7ÃJ‡`Óà Sw-‘$íÉ£N£@�w›Ý{š– Ê’Ç" ÔALD|¢á’K*{)ã핳Æõ‹Oâ15*=² Ï ôýó»¼*â£�ФôÓrü�’¥·Žâêî ¢¿,üæš“§œ0xtnJÎ…y!/�YOhüÜh :H{¢Ýi´ë7º�ÿšÎ˜öˆøVŽÓD�騻P™uÐÍï\ƒi¶TÄ[;Sò¡h[$Œ Å÷û4¸­xXM˜?åÍIx5«Y–<þÞ±Úè›Ť¯F¡Ö�4VëQ‘@ª-œÉâ"Ä5'š¦ÃÆiÞLþ>‹²¥ð%it�½{žrZ¯j@Û˜¶^›Ã=ræ!8R}–ghÁñêCP$š ×vNã§¿õ‚ ÃÑ&þÎ 0ðE!êÏÚŒ_¾Ñ~o2­?+£œØ‹4±{ªŸ£™Fݦ-fßìè`ï®e/·+ó;®'Ó›M«ˆbR.n¼7ˆæ#OÈEA82ö�)ðM—åÎ0´†¦ÎžÇk…¼à¹äÃSÎ7ýxdéû&j­7…{Êd&„µ§àË…Ñt¥š?™&¹*O9B÷?QüìW ¢£ —ö�—³é #4á£-ªèôþ î1*£z—ßÑØ/É6…>R;W”;Ù2„�óÉÛ_;Q'®0é9qà ÌHbš1Ït ×<çñ~µ$o™xël]Qï9 �&ζ½8‘Êf¸—ƒâÂψçàr¸ÛÊ@õõ9¨&RI&ç:@WÍqï'~¸µr9i¾@~jJsù5[á÷<'˜¤×CUög€Ã.8{„sÃúHõ¯?4½q%xï)¨]í‰{GøU]Ö°vÊt<ô¦‘¦Ú^Gÿ¨9Dpù(}Ñæ�/V.ÁÃ1h>~žnIÀ ‘xî CHH÷÷bw¡$ÔK¶R ³_ÄİjTç@íãOP±R*+Òüdš[z‚†ðŽ@V^³øùy²,�¡~üôïâ1v2vÏ…8ImNh¡.¢ãÁ·pÜG j,æA©K$)·�ìœ&jÀz‚ý^cÌ[…Ž™RÄiÂS§ºYÑ£š§pÏ£5ôôÉ«(‘ °D—ø(lBõ³î•tÞz­ï¸ø>Õ˜žüÍÏœ"a o.P•Æõôy°\,$-œúȤŸ9aØÕ͘Î_ &êÌBÍ­°hÀ££€±ˆ†£;Ыë YeÛû˜& Á�,¹>«—Ü~=H7Þg9o=Ò0=?íWböý ˜‘ÿˆn �ƒyL}ìqˆIŽæzý+…b×TÜo’HÓõ#P=é>=ø¾œŒ¯ ¥/Ï^ÅŸ.N°oŠ=t�…Ðd5i’x$.]c`öF¦f_ÚQ;ô¹ªŽ�àtÓ{ñé;ݳ È„Æp ߌ˧ð þ:àÙ /¤ñÃE˜:s+ô�Èž:7ï0¤×Èr¯õ‘Ç­åäð“x<û·ªg„I’3aÿ5¨ÓüÉœ«º†ú£Ô�‚³#�!"Ü]Ü@4æ(‘ùÏÕùK®,‚¥·×Ѫyõpû¦$¿´1ŸNÿo þr:‹Q'ãhÞ“e˜·b ~;ÆÎñdšŠ)¯½Š7ƒ\Qú´´ÜfA§W»�ŒXù#t¯º Í48ˆ¯7ÀŠœ%Xÿ}6ûwr9e´Ž£Qøo<àeO|?°­¦)P¥¹ŒêÌÐ�Ò£¿áy¢$y4£™VLš gšÉ±Ò6Üwä&Ìy›CR°F¼‰—fyÞ›2wààkpÏùMgЈ418p£žìfBP/Óž|ÜF0}†H¨ãݧ3ó¡jFk±÷Ç-4ˆ(#­7* v3w’“ƒåi‰²5ÌÜIt.Α䇱ð!�^·\[¬‰ñÜ»˜óq}ï�#c�LòÝ:¼Õ`Nn.}FºšDAua­ú6ãÓ'CÛ³\¤3FzÎøCAƒ4[FIÜ·e�?J=h+9“©U{HŠ,!è˜ùoIމgÀi³«LqãTôV×å+ǧ‚e\<1ûLV¾ @�uñ4ô£Ì·Î&‹$ÌÈ£ÁO¤Få(2õgˆxš5ÿ¢ÐejZ±?‹D×EEä°D"UyZKdŸß�ŽŸæ½R†K©ŠÍ6|ÕϹ® ÈÚ=Áî!úüÄã.° *‰†]ôDU8¬[ A] ðêBv&§߼΅Mâïè…P|Øs�^ØYg@G® øéµ¯/ô�¿ÜXþí3F96Rù Â0Ð]LÚoöÒæÿĸÆê¨kp�É>Û/ôl‰×aóZÝCç뮤þ*áxôÑ"VKs.Ô]>ƒÜRYîà© rãòe´³`·8ª2RßYëÆLºN³lD‚)cõšºÃ¡.E‹î­ãàúå0ÿòyS£ NÁ¬¶MpG¿ˆ6NqÄ�ÕçPzL–&EÅàoÂîlx*2™˜HÌ… F®À�&GÊÒåÀ¹(cŽ“ò~RãÛ®8f‡áeÐç�MºÁ§V‰û~<Ÿ’œë$7†t;Jð¿JœÄM7üq�ÖUŸ/JÖ =¡G¼° ü$x…¹Põk§±¯›’¾R'Кq…´_É;£ù¸°Ð<ŒÕ(ÿÓNÌŠ¬œ]AWŽÎ¡î+B™ÞB`6# !ƒ‡¢b¥D·!“”®YNoçxÊcLv3ºÿ]K’ÞA×eöð®×Ÿ[GÒ× ®PÈÝ Á‰«pDZ‹;JÖB­®æaÄË*|ÛcF-×G Ý¦=–¥�îe’y‹¨]W÷ƒÞƒ¯ê%Ö¿IÆ”Êð¹Ò=Œþt ªŸßçÏdQ²ÜÕf·Ú[R‹îUPßwƒ®][NšÊ´°­z)·%2ž a9ËÇeMópî…@f•í}ÚvÈ N+c|O5ûïÄ¿E}p.䚌öÜšMtÉþ"ʽû�5íÛOSóI×Ú¿dñ½UĦæ>Tê(Cè }hN€’1øõ°;Ô3q“ƒ¿úŽCƒ/RåbZßßq+Ž@íØAüÞ!IÆ'²ÕìÃ<ù> Î~¹HZõ¨ á)=]r·ö9èMÒšã ^ÍŽ]`,M×vÜÄóªÉÌ¿mêðB.”­µ¥ö_C鮀\l@MâX;y}¸·.�ªo¼ :î QãØv·Üc'U^¦Ëä¸2–u0Ûè$ïÄõZm$O3áÀLî¼’àÚkNÜ S_ÂÌïΠåTï¶—‘@ïLv>)ÿ™À¾ÏŒxùDÿeðl¸Ñø·!Öt^¤µ6Íôää;lu\/Ù²u&ºÛ#ÏÉ„¬®cÄ[ñ‰c4¾ׂCjÜÇ2\¬n„ñÛ>ÐáÒ,ì{÷ ³IóœhÚhó…‚ø¤D ‰nX„Úî€`É Ð);—N]`ŽG­·‹¥ý˜“£ �ó°Mÿ¼Wå“•Ì||5ÁÍ>C[HÿøZÞ­‰¾;-)Ojû‰Õ±QrÈ.š|µŸÍµ·‡å'üµf*~n!-×)‚'Ob”› lÿó”Äß? ÑÓp=×M£ük“¬žâµ_�áÑñrÖ1{Y¤-Œ\ƒ\l (g]¬²qÞ ms³튥èÚ™yX—8Ÿš ¡’y;æ’F"R’ëèØ€¡ÏLá—â7ˆ€ÜðÃÔ@ï Ÿ ‚¯ÞÐËÕQÄä<½½Ùå× ÂáVUäio" •‚¨^bG«‡Sζ lð­ÆK\vÑF¾Óœø|(eÆ`Ë&5<}ÍòGW1‘7–ãÓ\œÓ÷…|Îý¨Â“ÒÆó¹Ohöô%ü Il×2Þvó*Ý¿<‚Š$TÀ‚CžYˆëU}Á(T�>ÿÔL&É®£¶r‚ܾ�ŸÈ—2\ørL‡Nƒ©ŒØõõü¿ÝÊÜl�föå½[ô˧zt~i $›iôÿ‰R |àS{*®I§UsâAç[8|ù%“Ü»È(W÷KdÐÇr0_ª,;òè¹Ý~8mHº ³A$|+\Ü/ƒâjkiöÒ@,»ñ† ûïúònéóÄ�Cr±’R.ÿ?²È¬\ÂWÃ^ã•Pù €‰)C0ÓÅŒƒ�@‚ØayÉkü—ZHîú âÚ_�ÄîûI<ñ# �ªG3ßógpÇw˜Íã‹ÑëkÌÒä¢Éƒ\‰n¬ ª7±ö¬WÕFŽQΛÌ© ÀÊô8\Q¥"Kš éûºZ;“r–¥“’)wi�¸5ñ�Ç¿8~õÞ€tŸkضÞvjÔá¦xI¸p¨›Ü ƒ~ƒaÔnœ`áwWØÛƒ‰t«~2ܼøPγ˦×]Y ƒÊ$æ•R}1a‡;©òv†úÒët|3kÔvÓŒ�û¨üð!=6Œ2öÕ8UE /ˆI “·Ž Æ+ñ)4ààÚ|§Õ×Ê`{e-˜ÔÕCºÊŽù–v2õGÉl_ |™Å ³ldî{N †îàŒÊ(¢¦ ô´$q,M cR{ çö¾ˆn M_÷Œô4$ÃꉌLùù§,Í¢Ó¿ÙâÁ‹�Lã®Ré=pêà Ökg#7T’ÿ¯ƒ0ÃEâpZñ‡É&3ô“™öa¡ô¤Ò8t³³¹BôöŠ�ý4¿-(%miÂÜ©<øOÏöÞõ§Þy§È÷Ÿ·i§c€V:r~ƒZÈÆ2<,u*¶¬¤ƒÉRppc8Yj^B=\A­'ÕĨ$¾^XBct�ù™¥ØœœƒŽ»Ø¥1?a�Òq<øþ+ÊÍr¥/ÝOðvF;p/.ÛÉŽUBöÒÇpL%Œ‘#©PÕ1xdºŒUÛ* ÏF'sµ¦ž@�<ë1¡¥]ê4�i†ÎW&jü€ýñ{ §èQ¾Nà¿>îƒÙÇ@n‰cI½ƒQß#Žì¯®Fé%Ì)ÅÍà%“H|>s˜�ž¡TlÏwVïÕn¸»*¿:�÷_Bàü;`Z1…¿}¥tîµF!¿–û)ˆØ«‘ÊÂÉÄt²Ýtþ›¹Œ>弫՛Kâ.y�,×núùJ9ÕÐS¤Gh£•ë-R¹ˆnüXvo¢Ë­8çIœŠûaì̺©Ü»Ž¸aáÛ•¨¬ÍFô 1ûÛu`Ùp:\¶„Y›€m/'‹ŒªHçšAÒòYK�çS‘^»¡¼Ce~_&ÑûV‚ó¦l÷[Œ³|dAk³¬˜JÚ¼Lñc9À´õ… ·Hkœ+`ó‹lRñý á…|§¹c5ZQɪ®ÚœÞ ØéYɶ �íFµì35x¶EE^@��^4œ²Uès²C‹R¯Y²äñ¶ï¤¾¤7y¨A‹ü,–¿ î=²plÍ.˜^® ¼ÅédÆö ì+^!T‹Oå÷'W×Þ‰ñ"«]ÁÙ)Ô"g�·3q€rÕ Y¤—~zù˜œë Æ!ÉZ¼^ªŒ®Wd@äóÞ¡�úŒõ9†ïêæ‹‹öÊÒ9;1vË]ò!? 6½¥øŸÍô§ .NàÞªëé]õœcœ˜uÓǽêð·Ë[ØODðœqŸ,êðšÁFOõ\¡Ùø Ú<ÜÜŽWð£S¿n™ÝÖܳÍÈò(wx—”ClÌ$sÜ;�Û-�½b‡ñO�Ii¿:Œ7¡E�|š�--ãdÕ¯`z)bljQ‚�ƒÇ4fáXÑmT:Šùé‘8àê)RÓñaø6TÏÈ¡ö-* 0œÁZ‹rõE™3‹vAýñ<ä;ÆÂÉ=ûP;NB%tÉ«ðø&x‘}R+ˆå©Ú(P8Jy»¹ÿ}áK÷lÃö ‹ô˜ýB–Ö”Stþ†'r7àœ…¯HBBy{k sâ—Éýø|{H«ú3føô¦¶rvÑsÿ|˜æ¶»Pã$GÜ�VÑŽ¬'àã¸?:Û’Ê'òl9ãœÒ…_ ˆí4ü©�áÓæ�¼ T+®¾çiyÔ3 .Bq�,’™q›,É+`ÖäLuÅü'šè–«‡ÖúÁôÐ�K$ïIøüK ©NÁÄëØnÎæïkp�í8õÈ“!GßÅ£#?š·ïÄ.ÿ®Vœ¹‡³]À væD½a‘›BF‘zÃgøJ4~‚g*ˆâr[*¦z{ºO`´âܨÙÉùQKŸÊ"+zì½ÚzR¡Ò}àòå<èFÍ#¾c£´¢) òzIdt&J†”ƒ {4vnZŽ¡j6˜gáR³t°*ÔŠŸýÔ[mþÆøw .* i½3ßN6cjÀ$Üž7JsìůڞÔ2ÿ:´[³^­mtž“(ÄÀy^ ÞÉÁáØ t9zLnÑóv r±†y &Íu÷¼ ½N'áaë3àiܤþ{£I'Œ@hàN¸øPdlgC©”*Ë©PIQKj2u·¿ÍsµýÉ‹´gdßáÑ2I˜úþ,™oT†³>ÎåZ}çâqÏ#èÛ4D¯Ì *œg°îq'$>ïÀÖŠ«äÒ>q”*¾Z*štïµÙ´QM>Ûžæ¬;y•.>ç�gúâý²oÚtSºAdïÒð…3éá´xìÞ“ˆM6àØ‘!´Â~ì=bŸ ÔQ¥Ô\²«éK#LŽz5¼2½j¸ì} 4ÒÜ`ûùyœ£gÄ1ø#]¦fÂx~IŠ?åhøŸ°ÄQ¥&x<’O&)õÀšÐ8R#/Ã==¸^ß9ÈìiÞ€gvhñ³"̱5I–Z.ÐÄëa¯Àè™;ºFœ�¶ù¿ØHCˆ®Q‡«— IËÄžHù|êrªL /ÒÉî?Hè?YÜ�{ ïù‹Ð¼îF°Yo ïN.ÙOÒà|l-¾¶ D7ó] £õ eÅ LC&cÂ�òùE`8é9n::§BÕ!i8B_>½€«rãšuát耔\–ÕÃ3¹ç—Ìä/¶Ç-…YàYÛCþ;¡È?¡¿�ö{Áœ¬©ˆ ÔÉs!k{æ:�¢!~(œh¤º Ø±ðmçQP‰V�–­@äG8õHã1óýr¡L¿„Lf‘DZlä=%pw]Oº¿Ü£z+"Q»"£…•`ëÙ(pۈͽw˜3¦<wšÍ±Ö°… æIƒÂÀ¯Ð)÷(ùa5¡Ué6ªÑ¿Šµø•FNml¢‹_ÄcœÝa”œÙRRÛáæ§(¬ I«|Î@R3ÎûU/Þê“;˜�¸‘l¿Þ„{ÚñîDäNzAÊþÁ€�&ZŒíà�‡®F›¶*"'ÐFnµ;“ jFÔ¤ÿ ©wVÇÛËÞ¢5Qá¯8)Œ6ÛQðO�ÉïkAp@üýW€1eOðÊ×Õ¼™@c|Õºm4n²å»²i½h“ú^rm¾Ó$ñnâ”�rïGHàêÍ ”DU$@aÖ"È8¾ ;®rqÌh)†šKà�X?üÚ$M-•ÈèI?°ýz�nw°¤ Dxä„Ð ,æBÑݯôQ] }<é*š÷ï…á�Rj ‚w§XÀÚÞdH:?¡�5í0Ũ”²wFÙ¸3әޱ0<éx�¦å•ÑÇI|Ý'_è¾¹3qÊÏø$¿€¶‰å°ECq¿k½x/ †´qÉ.yŽòþ(R˜ ò—náNŸýäÈ¢"j4QS±¼}pûC8üw0‡Ýò ™È·2•2ô%¯˜Þ)Ã}E©ðZ- µÆ×w'ñ×–>d­ÖE hv4,t¹äsü0¸Ž]k–°•K»é–«©ŒjËtÝ3žo:‡‰ºS¡u¼ä'¸æÎ3pX�ˆëv?Å„E)(¡ÓC�Ê"w'Ø¢YÕ ÜÌèý‡Ä”IÇ0"’³w—ˆÏ0âl…kª§ðÿ»·Š7{—šºƒl“Ê>pƒ“~·Èác³¸áàŽÎKÿcžj§ÑI*¿93dæ@RŠ7˜˜‹ÉÐZ:WbUéH„Ø,_Æ=0öQ1“® œ�wˆí—66m‰ ¼Y‰k$­ñƒñR"•l�{häÃ\7�Ò5#ú\±çIÈÙûX®rœìŠo¤‘2¦ô³òj”±»Eõ÷8x‚ùù¸Ÿ>/Á% ŠðaÙB.B\“®p¦#»�?!+?±™›EɆõfÐ^ßKµ´ ð^Dݻӌ¢¨Á&þ›ùRÜýzµøåvå‡ÇS»’+Pê3Œ{“ޱ;Oðë‘r:üf7G¢þUé£WÉsåòâPµ^—XT\G³‰³šôذ\IøuÛ—yYuƒô¶¬�´­'Ñ«<‰0w]i<ºwáuÐöÕ%6åwhؘ*¤+FÂËgµ–3ƒaF¹|;¿ï›ôÈuÅl� Äk9*ü6knòÒ0æ–ÏÞÏvUôœåGfVÅb›©91|ÉÆ&2Xhð‰ª–Ë’ªô�tѳh`ÛMþYÇuÂúï·°ThNkXBÛc É«ò,VDú Ø|(f§-X†;8”¾ïšÏE•ë3àˆŸݓՀ{œ\`ŧ 6wuÃ/Èà…ƒä�Æ&ˆªà‘½˜Dùá(É#*‡ÿP¯€Âc§ s»$ [-ýBümº^{A&Íå^ØÔH¿�øG’’Åè·ñB”døª6¢¸bkÍ’¸Šozƒ`·ß*ø²S�VªIâüÝ£¤ûk'œ¤K@jÊ)ž¹jè3�$‹§ôêݩةõô€À‹A’ÑÞM‡–¿a–­2ƈ ‚lUÔ:ûKþÃí+šÈ¿ï;cùCÄ~š(kª{fd–ÐÐÚpRÔH..Å5‘…ô²C=ÛR æZQ©~8µÜMCÅ`o¯+.qüM%/âm¹XœRç‹x&ëo/…0·k$ëPÔ›g¢o%‹ò/ñžÝäJOøý¹ôæÖ/µÆ ]äá­{/ µóØôÜÙax¹ÚŽ×¸ï]çØôP�صžÓ¾ù¹9·æ�΃ô ñº©=:2“Æ·ˆÂ¯.ö›„@Ðuo¼×CØE5hõïãÈã§ãòé/Œ?ƒÕº2ÌWùwä“dì.¶Å…JŒí†˜ÍBj*¸Þ,ÇÊæÞõFXêuˆ*Ÿ~Ȧg]›Ð8*²ï;�X,u|�wÜD¸¾­ÆNOH£×F(ÞÏW×�ÉÛ‰Â×PúìLbðOi Ì'ÛÑÄS œ!›ë2áèÞ ú=ûòÝê2ºõÄã쩬¼EøÈä��¹Æ ¿ñÌq: f’øx>ßçá팡];~ön‘€XÜõ‚÷Ùf”²3óYÍ{Âä¸��—Qé˜"Lú;›¯wjöJ ŸƒÔlÀâÅSùÜ7‹`ô¢i�X m•°–êÓûžãLµÏ^` shoã5hRÒåŸqX‚Ç?ÔA¬ìO€fQ®¸Å<(ÖD/§/�€ÖÃXç4ÎZl�C�N,—¿'Wšfa¹¯%Ä^!’Ä�ܵï'Û²ô™VÕª>" æQò¾C€dϸ‚á·š‰ü®Ÿµ“¯Wᜊ“t»J¥¾Â!zàv'ͼÀÜÙ“CggÜ·—HFõ˜ªw é·¿°%¼…¾^:BFí À9ŠB�ƒBP ýµu+¬©ðFµ×Ê\ÖPÇ6’îó·p–žßoÐC‡>Ó?q�¤Am€ Å sêÆöO6d:/«lÚož�oƒ�N]nK† QÞ™�¯»b‰þ“yØ3Bx7ZùŽ(rjÊ;7(ˆ§m¢[>‘†`a2€ŸO[ÓÝeØSò³FhŸ21µ*¥ÞÒJ°zœËâSSü·ë(¬1Ë&ÒíëØàB.èñ?€ú�0Ü»`3¬2¸Ë«*–Çx½™|ŸäAÜe¦Ì‘äMωu¯y“o¶âü\‹^ÜÌQ†néטvÎäjýaŸåoê"£åâ‚\רû¼ß-ðÑî[¤z|!ÎnKÄ¥­ýÄ=×…�¾$ßýálöUØÎ–�°ÀZ"‚š�|ˆí_¸5jB–w‹Âvq)Èö±˜`™,’hjLRZš!\_7�аé�XþåJ\üÏIlLJim°ÃÜ8�uý°úH¬x̃ßùgÙAi>ý<ó “üGŽwÌæVçÊ ò§í%á‰CA“À㱨^à‘Öé¯H{Ñ]æC¥<ÔIÌ‚ö¼\tà¾Çª" &¿£áÎl||gÆFyQ—¥—p†Ÿj„†a²Y;î½HxÖùøâß1 uú‚žç)Ǹ‚&K×@¸ª)Æ}3wÞGÒ;Š!xs…­â$@Õ1²70 n‹&‹”çR;¥ <˜¶<ç¸cKÇü�R„ç7^ÆÌŸÁÍK k¬œ1ëÃ)jÞÆ¾ãf#^6¬¶P€©àR»çn"¥ê£Âl]ric!d-ˆ†VEu:õŒ J&¿áÝØ‘ÇLÍñ#Ñ"QŒÃ“nOžÈeâg¡ÆX~Æ›[piw œq‡ìËìá˜÷ý£ùºƒ¼Nóƒ0½ÀŸþö î�J¨Ð¸G“Сa„þ÷@�5õŸarLû lJ¶a›X8­3@Üï}„úŠ�(}(–ÄYýÇhè"†/ÐévçáÙщZçm¥ ÞBðEw(ßÂÅêRüѲ\L€�†«áæÑ|ð•0G=7tÜ^†ž'\àeÀk8œˆ…Å.œÝ\½j ¿¬: 8�„�º á­WÀj¿¾úÿ»´’,Þ…2w[YÓ—1æÐû6"scÁÞ®¾Uú#ŸƒðÝ·˜z4�ÙF…40RC˜ŸŸk€’–;Ñv›HÄk¡”ßq²ýÔ3°Ü<Œ 2‘S—¾‘]ãY÷Es¹—JÉÜ2X¢÷€3ëj=ê\Äô˜TPÒr§Gÿá4œ0ÇùÞÏà€í"ÌOÉÀ1WòqÒtR-Ì¡òw§Ö¼(?­€·%.ø~è4/òt0i�Yг†zñ·22ö+á0nÁ£ëî`ïº9¬þºêðS›Êí…æšx](ÎÔ' E¦>T &�j½øëM·ATæK2¼Á&Kž€—§Ò–Ó3¹C扺ÜG¬7»ã/[¨�º0Ê�ê Öì ÛÔ5áWêLܼìØ®Fþ¾'ŒDph‰#ï„ f”´ÑŸ“ªèÎq+²êž7ì‘ËðÛl»É9˜gÕK»½‚`öú æÉÀþMw�`’IÐË‘å;BfG&¸`ŸŸÕÿ G®ü÷ƒý¬ù—íZx»‚`L+ PÛÑÅ(Üþ›9tt;ñê´Þ´úŽM‚¥Â“á…®ÌrŸ~g=É=ò]JŠ3 ØC‰¿áÄOœæ1tióß] œ˜1“1u� ›Ž9#ÁdFô=Œ—{ïŒVCd+³jÝ lX9�Uþ/ œ®ÞßË2¸ó�%W<óù_ÑþÆN:éå_Òþ·æÍÞIý¦åãËOý̉ƒŠäHÇCH¿û‹8(ÜÃÆ–\ÚŸ‡o73k®Þƒá¨yü‹¦i8,4 ^ÿ:J¯?GL 9üµ›ôác}�ÌÊÃɧà5Û·‹ãçÅêñ‘ÐK¢š4‘'ô×4Æ>) |ý�–.†+šC8wõ%X­¼ÛvM…ãNüaèŒãúîðzøõâÄ€CÆO¢ws$IŒ0—- ᥣ¼-[…&npPB’?©à(Üñ ÷Þ¥u½€Ûw�Ⱥ)‚Uörº­K…ǧQ¹Ù˜JÅ+lkÅß ù¤sA̺ùš.WV¢Ý'è2�ù|Uˆ;­ó#^·Ÿý"gÌuÒ¢AUÐð‡*˜ã-­ÍÐ>w >| `ô¾¤²AC\è¶k-ÖAÈžA¸[éUÌÁRãJØ(äE-íÎÒùBÁÄÄ~D=¤Ú<{ØÖ쀞wa¡ùSrQœÌ™ŠStâпö ½É{E]ƒ™ö18i+Ê÷ÿ­Dýߦ…¢h´<\.aAÎNô¸J�˜mð®pîh/Ä-ÕB˜ûÓš\we�#bñþDžV‰ì%£7ñÈÇ(ZZ½�´M¹Ç¤lx„œ1O¬=@;%Ò�gæOoÆSãÐI°fATꇃYôoú­ô)_&„»ÇØßS¶ÃߪPºø÷šÍZ?œEu/I…ÊYŒ.‡¢²<ÖmW3+[ÚKs;wS‹éýøßÊ4x¿M†ßV¨Û¬vàök´(â&39y-|ôÓ‡Öýá¸bÇsòÖ‚üÞ§ÌÉÞ‹¸r›;5ÄX™™ »Tó1B–ë¨QK‘ß;4iÀnˆYx‹tS ÙšëÁêQ( ï´ÁÖS�D_3ÂìÔñ˜æbxµé}rd1¬½lrzÊ^ö_/ºñ”W"-ŸöÉå¢È�9Ÿ}‚>[˜ˆWî‚úö.ˆ™§ˆ™¾q(«2NYÖ“ MhsP“ë0Í�Ù¢OfŸÂÑ{ŽàqH•î8ô‰HC(o[C–¯¨„Ë¥÷y)¿§á!—õ5}Ò'A¶bŒ øËcSL'‹ñ!þ׃�£¨†µÁmx¼y>I-¤³¥Í0›®{oöóSþÔäDø*· C§=cR»0aV løùÇyûáþžXjs–¿ ­kï“[îÒñ)�xI’�>Gk{+œ¾ 6Û}eóQŠýG+ጅuÐpD’ëïlYyspG¡jìätê s[ž½£d»æé\ÇC׿²g¥`ÍWIhüL ¾D¢ …=ê\ÃÞM™Ðó˜ÜZ¤Èµ§|’iiObË#ÉOóRt5‘X쉂ð†:/z€&½/'¸÷ «qHëøð’9„£ûlqYÌ}â™w�1¸E.¶Ó‰qÈ(×3žèy8`ÝßX²|U%L�<¨íO§ ÏÌ‚+?ù}¶÷P_´Îm ß|U¨Ó<+x3ŠXâ9 ?\†÷o˜£ÝyxÜø=r9/†`×¶5 ~/ä­¸0Ê.˜·‰.?¡F.µ±h$¶ÇÒ{É»r²»�ì�»Næÿ’ãêD,!§oD�j�#ømÙpå²LH»11\g»=Eáë4 ?Oÿˆ¤bÌÏaZ»ü >}Ÿy³UðS©=x®‘Õ«ºO{ªòðãµ$ºòù)ª»^‹ý^Y%ç¥1m‹ >¶Ñâ®åóèÎ�)àÓáŒ.‚á{pšXîÂ;ÒÏàž¡*cÅ(¢¯�o3¨êT]ÚïX�©wLˆÁ™tÚ±"†±»#ÅÝåïUî8;NUÒ™?`~~ÜNÀ)¢óÐ1ä;­RØÀo»&­]ŸÂq›{N|KÓ¶=3¦‚N§Cè†êS/�øû0?bŒ^»ÆBêƒz\̾#ÛNät¹� T æ-@™eCÔólßÍÉ ß£�MD›«˜¹-øå÷%žÑ:gâ(¼ _$bBØ(m ¼¢jql°Cªoç¢ü*9è]™É*¾Ñ¤¿Ês‹iâêÌKà´{,lÆû¦?©¯— Åo¯°ìÁfž¼û5Ê©™Å½ý™†]J‡½²æ~³5|[î]©èøÅý�Ç©n‘ �ÃpÂ&3Fcð¢þvœ{Kƒ�16=C.Ò[JR<ÿ‘rÚµ; Të©ÍÿAJú2ì´”sÒ¨Œ”%ÞŸáOË+*ñ¡â) üMçf/€OõÞW-ÍÝ{Êg§à?Ól8nsòI[ðjáøžðjsØk7áàhý½ ãðƇO›å`È :à)ý»uèœE¾ëé;èöï ®Þ�·¦ea‚Õ0Õ¼O rûÅ‹0a³Vü¨ƒç{¤¨ÚYmç³þ†’>þbi,Ož\ˆ`nÜ›F}¹-än:Kjwž‚|ÛFÒ¸ü=lÛÈLß÷�¾Ø¼ Öƒ‚RÍXw Eú}±×Ç>mÊDù”ÙàqÁ‘5ã=,éÅNGBGž/´è:¾2Ù iËíáQ˜�€�ž^2²— é ûÂU G¯>¥9:9�¢ðÓ&ç…ÆÀ~¢`aK-|ƒëq‘pNB“£iY /ÌÌQxÁ<üïGµÝ#SgQ¸îV�].i`}ã ³Zü2Ê7 ¶�Ó˜Ô­Aà`|¯}W"uBá0a9Ù2PM¸r1µ�ya´hTºE8PÑÝÆ ˧ð¨ú1³ä§hI”ÀŸÊ~jxnöÙl þR1È­šœ 1 "4ø–«„°sãcfJŠ4üçJš‹ð]òMqäÌ%’™�‹©^ ??ûzôÖÓ`·¹D&'ŒsÅ6Y­JP 5# Þ!pÆ6†ÌQÔÅ¿ñ¡l_ 6‰$àÂ[j€E}X/ÝDRã›Èq•»ôöî:lžÜD÷FŽÑXy]�ˆzDw]Jçt¬J#™’ZÔ-©\‡¨�DY¢¸gs x·„¾‘KÂÀ¹ZüäÄe¸AI†ÿ÷ó,œÒ¿f•_§ ¹ &³¾¯ÉÁeo‰žóúns >¡‚'ñ³¬|™3•×H‡MUøm‰BžŠð¨n7(ŸààÚ7/ÈÀmîf9e|¥5&GL†¹ë¹0'¹‹u�©‡RÔüvÙ€*"iÝ‚#Íì–æ¯ì A�ñO"Š•yäléeúÚ-Þ”õ££g\\ ×TÒIs¶°½SBqF»¶ï1‡Eglì6#¹½–¨³uwmT-kØIð·#ª¯¢gœZqÁ߸º¸Šlûë�MççôDàÉ3SÑ7T˜SB ¾¢›9|‡…Ç�aåÞ¢žý Í~ÈО—òØÜ$ËÏkí£í×Ðèì8=0XÎ^YÀ—û%G×^œKW5·Ò¡ù‚r™i[ ï‹âØÆ¤n0ŸŠ— Б¤Ï2"ÈïÙ¸§tb%Ú¢¬t ä©^£R_bÁêÇVöÅÑ×ÌÑPl}Ϙn—%ÓÇ `_f­¼/Ó‘UXþ†#Ho´1FðJ K­�ì;šݯ6@é3�'áX´#š6ñ¶@“ç%öXcë¼ôQ¬£b÷ì@º/¾Ù�%vûȽÃýToU<ú¶X¢sÄ{¢órv±k ›˜ŽUƒ´møL+ðgÿx‹?îNâÑÜYjÿ°…NÚÈÅ�¢8”rßß’Jà؃&u- è{­ûؾãad~õnúÄ¡Ÿ¦4m…?¶“¡I½pdùtÉ!B²C�äÐDjféA¦M$y!�ŽžEn•›�èò/�û×’ÕÓ&|}z¾1Á‹Kºh�{ n2Þˆ‚.Â8\Ÿ�'''ÀO¯P,TÝŠs¾J�GI%»_†©A[oáT#!2l<�ëT` "‡mpèTÙ™b4ñÿ8:¬¿÷�[™¡�Mˆ"! á~Ÿëii¡!IQÒ'•†ö²É!„Ì2³B¼Ïu—‘Ò@Q*#))%…JJ¿¾¿ÿà\çœë¼žÏÇy<Îé¢Z²èý…-äçSÜô}#/óF¿S¯ˆóªäYþL™: ¬À¥k \ ÷¦G¨9ìMyÃ6-Ø Í»Å Ñ(ûO•Qµ6o²#Æ_®Àl›­(º¯’íL�YsÁÅŠ©lâa¯l ^UŸÃùæÞ Jònà›³�NÙSKö¼¯Eg©ç¨øFž….ÿbE|uav•7“"mKðtNcU¢ûèÊÕ�ÑäñÜ+á‹!‹i —".;$J4ªñèš^Žít òÖØnÿøµê 5(�Tø @VÑvVƒëI‹Àô¼/}¾îîùJçI\ çU“ÙÊ«70F¶”þŒŠƒÔ¢éPí>J””•áÞÏNä\A¡ a|9J 96'Ó4Q»WŸìÞú•uæÂZésæò‹Ür>÷ëcÅÜ-&É=·f)ìêŸCÝ b‰‡ª —Od;*�'GëÒÁ)s XÕ¬Æaí“æ ·O‚k‡9´4ÊÓéù;p®a+I ODß3OɃÈ@rõr(8n*€'f[ñkßH¶~ŠcVn07Ô:¤¡é©³4ßümŒ™…¯yPð�i§%Ëá¾[Y±�ÕÈ»iHøMãQxÿ[Nô†P*`�mëf”U™TíËü‘[ïRd©›ˆŸå0®z;pKC8fÎÀÞ¹Ò0ûÖ-r}y1õÞI—VÐW§ÑaŠ+ä>œ õúðÀ‚¹ tºöõ&Óý^Ý øk Ý0ÅÝ_àkA¹f|ŸD[Ò›û±7Ü€{ªð'gñ¢oD2ΖœÚ×ÂêöYÀ`’$ïÃ-º ¼ûª.¢¤zqÐSÀ7ÏÜQ±¤Œ·ÊÔè„áÛuX®xö³üͱðË|%þ˜P"7û|qÁ¢5pC=‚øK•ÐïmB\‹ü‹h×1‹)­ Óíó9þ­àعšî:÷¤fg÷[~ÕK6óãƒâ¼SžSf�¼w1 ÙS9õ©ø¡g&yô·òlMñm�ùjñ,¯“d\¦Œ‘±°C°Èf܉½ÇºÍ”E)éXº¡ß­D—Òçæ«�o�@�ĵf\ñßEæµ/‡Ûƒyplþj8¿Zx¿å%‰ÔFìÖUlúo ×|û fµÙCÐ;ßBŸ´ïSI˜é Î4ÜJœ6ORuç!:§s>¼ÙTSäÒÀû@�Z+i2ÄÉžnJÖm‘Ƨ÷ÈïWÁÏ×›ÒÏîL§€ˆ·BFtŽ›#ÓŽ^ÆÐýØY;ž1…5·ÜÆt�çIƒEèq<^•,‚ú@-p3�F�Ù?èXÃcšq XœõòB`,ß¡®àyèö¢¬{{9ÌÊ|�Ò˜qÄ ¨:cjû‰ù¾n'œñ+¦9éh3ï$(†®{±cK:–µ\$_²�²ù-jjº�õ 2b™{`:¼:®ëÌ}È’ o陳ñfc55lD's}ö“x9!¸Ì2ŠIpé?¶ ãÕle:yv(mS#g¸óée=Ä¡¼ƒ5qr˜—0e<£kbt/ãñ†L¬÷{NnDðèÔäjVÿJ$“óbYô]ÿª}%aK{¨¶ýV2Åê6œœ³vÙyãpe2û1Úu/Ž×¤œÈ† e7¨ŸÑz¬ºÚjöâJå—_E”¦£êžò~¨ w�ï$I©¹uV�õ8l„Ïë_¡xèaf¶¯®ó¯@^˜í§+WU⇂Wú‚ˆ¨«¢À¬ãP�°¾:ì¡ñ9à1l‡?vÿa$žî¢U;&‘W ©ÉZ�S–Kø÷%S§å•˜é t–"š<3„ú¿­ÔÖRÁ±�_ÞH¢~Êñ&ºÂÍ[WÜăiÛ˜yßãð²@2 -áÇ7óÕЃ чG‹‰Ë‘먜¦ [Žƒ¾Î;`'aÁýYÈ¼È Ûli¥˜æ>[ɦfOÃU{ãhÞà:&xÿ"Ø:ô\?¼#Yà i“¡žß©åuxÑÀ€x¨òþ8ý˲9)x ÄúW¼§Û6oF¿N)®½Ñ4jž¨G4o¾A§ÛvPs©OÏÈÄU›‚©B¦;ë ·�6Çâ.AÅ߉NÛt^P†Ž®õ†ã¿ã·*I8r`d…m€MÓÐpu<ú\ðÀ¬“5LÓl á9Ç}œ(Xw·©ÚÚÂse_’sͧÁó¥Ç­�`Iƒ5â…„óßtÀ›wjq|ú bæ_c~¿û0üì¦8ù/Ãj­Äh�� ·èûNìÞeLê%²!$ć±\‘A²WÒ¹‡”iýW~´ü”õ»½áÙ¹«Ñm„ãy»�BÊv).{ •Þþ“JCwøAè+Ýl¿WhâþŒ�.d"k5ñRÖ>ðiOÄøK’`Îý—`Znž…$Ÿ9Ý7çâ•vÈ‘Jâ„•a>µªéìxh~¾¨‘6hÇ¢ÍÓ‹¨–Œ–ækaÀjY^Ìé•x.[œÓqPè(Ý …‡_áDËNÔhåMº¯B„ÇÔç3\é:ÆýMðù|ø¡éÔA<Ç ýi¶]ÌÖJg7í-$°D”aòMkÖÛ…�+å÷É¥yÙkAä:ñÕè FGåaúÚõ˜¥ƒ /p$Ú€7ª»˜žxÙÊœì¾Ížó›ŽQþEbp³æŸû¸8á3iEÞÖ �nFÑÅN°«½—}�RêSáÖ ó°&*š¤[Ëq9)º¤¾¡v©Äsœ]7�DÎrìlSâÔîåὈ…¸¿]>w„®À—ä@¢šTÆÂp�'ÜÕ§ž»ù¹¥z:°ÕË›9~ KšZañèz˜��fÎö�š\y,w·€9A«èæÆ@:qlþ¾ý¶7ÅùS£ˆ�Ü쪷¦å"î´Zú>ÜôF ú¡FÌ#ùÜÍ<úLÂ’7Ð}¦“ôžÿ&H^1ƒîWõfŸNКÍå§QY°‡Üº®Ë]£ bÕ=Zó×#²ßÒ×'úA@Á ßý^ÕÒÑ5*…´}ÝATw†rñ[ä„¡=ÿ•yŨ¿:žÄ–ÎE™´!äùAäö¥CÇœIÎèë}g¥Êu˜U†æ5 »óIÂ?ª²P"6¼€ÛuÛáÌiÀ¯ucœƒF | Ù¿‚0C”÷×}38¾µbøûEÁûcYT:<¿0¨ÍùN®}íÇöÒ8Åk6^àD,eð•N¹á Ç@åÜyF›Á´§’†M¾`Ü•kÈîÚß$xÖR�z¯Á½µÿ#æ8§e³C(ª´ß2YtÄáã¶ÎžÂ\¿WÌ–Ù.ÆÚ€³�¹ÁŽ>è*Ä”…ƒÈgÀí<]NM¸hÝ~ŽøèåÎcNRä™èÓû³]áÓ×z\ìV 6f¹ä‹òUèß:o¼�ÏŠðtŒ’C+°¦E&_O㪟úŠŸ” q1ç8mØÝC¦iá´û¢¼;š–Úïe.bá†~œ 2Ëý.b oÁ¬rú¹T³Þ2¶¯[áIJ\úâÌb,µ¶…+ã5ôÐ]°º·fw?Gýò>r‘9bÙ…2ÇÂñâË>Êß^ˆïåô¹™‹w@Ρ )€û™¯(0¿o*h¢™š>_Ò#܇°’χ^wÈ#êLP:u7³¾%�ìØ¹²O7Ó¥T\Õ- þ7‡±}—nÙe9†ÿœiÙ(ÉnÞ³3a¨TuÚ§ð^G!¦ñ¬“-ÙÖ-÷0YnJ�¨�ÄÓz¸ÍQíl)žˆ=�¾™ °˜ýBO%_�ûïˆÌÖ~8ª| ®:D‚²ÿ%¸+ÔÓ50tC5I“É�‡¢ÍdMëR<¸¨zÐAüÍ\¡%ÄŠóù¹nÅYød~2Êé~#3ÞÆÊLHõ•áþ‚½Ù_IÚ®%rdÅ’+`vb)[¢�YãiÂöŒº‚öï>X\°ìSÏA`ì Þm Tßë„Èž¿>p{iÿò[DlûÜûV›óá`Ðo”0KÉÈ!ÐIvF]~€eá�¤iý}¬ÒŸ‹WV?&fÃBòð«¨ûß½düŒ,f…ѻ҉ÎÒU‡euš�vÇ]ÅɾÅišè\Ø?TN�>é`ÊU¶Þºr,k�$g/&ÔÌ‹"�\E4¾�ñ_ˆžßnj˜M—)©Ã�|ñZ×^Jšr!^ÔÑF:µ•Ç~õƒb—ÝÈ?ð‡^Mp× qò½ˆÓÓû´n9?s#Å VÊNCÉ>º¬i¨ÖÌÙÉŒ¼.¥nÛÊaƒðI`®Czƒ?»Z_�˸ä>‚ò‡ <"1'ðráEгž¤Qüxá5ðÁ1¹u¼½’½Ðtk5òù¥bí™ÂOæÒ„Çöp:�CÉ“Ø@Îú‚ÿ òÞt^ÒØ œ)iL¿<ÌÂÿŽlc–Þ…˲GAóW,TæúACtöbàç˜û_ÛZ Ã-¸˜K÷3pæÉà±Í öÈåѰÙ÷q[¨24Ö(¢¥ñUxçòš–†<�"±2›ºß«È“™{pöZ{¸þ}¶ÍÀ|ÇìQNîÛño¸+­z'�QŒî„ùñs•$kèFß�Û¹øjU4¶k—`·[;möœ�oä“`ßábªï…ôÐ9x‘(Ç„¼‰Ä�פ…Á×\þ“/Gÿxcœòã=îÔÎ$^.btÕûPÜì_‚5~�Ø­++pW Có•Äxi¨P�å³iù0KuMžbŒs2[§ýÏÅFE S+ú}”¹+d«€}^b¾¨hô$‘RLÇ |`D4–øüÙ ñ‘�ÔpTŽºŸ¼„^çœàä}k”H/„¯ÞützÆTÞµOÅ´ïÃ/Ú�a;9™`p1ú¶ ý+Ã}Ó2—$W”3äál,’ÝÆa„‡Ø]CTU KbŸÃ™o‡éa¾ÔgS"N&EÓ•¦ Ä^$ÖŸ$vz@¯–4WçÆ©ÒÃ{ÐÊoÒ V—ŽpŽ®}/jõ¡åœëÓ5� %#ˆ…Õ8ZΰíîÕØ¥å‡q•¹TN!ŠhfíÁGÎEÿÖCW|j#Ž+%°ü×ÒÚ�‹êîù¸íÛ7œì”ÂC xc¸„[]¸©|X3�„¿2 ¸¿é!úŽþ\Z‚¯ž_gÂP[W<:s f„®b¿¤�¬“?žš%?=W‘»T (6¢w'ËõdУ¤ž¨]€™—ÐE;ˆu•ZAÿG8µ3È“ø]øŸ×FRxHõŸ:ˆã/ ýño»‰±o£ÅIX‘•ÉX¾™ëKè±¹�±e[-D©¿¿ÊØÁuC%ðOÄÃ],FÍzFzT'h0ï"¶ ΀+Â…¸Ù]šæ_øJ;wCSL'µÞëOfÜ�f—ò�·™h$üË<ëp¯¼ é´‘FNÚGìçûŽÇòšÈÏǽôÚ…\ ºŽÚ{µA9º~S£O–¼¢}©M Å1þ6r¤a>¨,Τ…"=(|fØ{daN}/äðE�U¶øãÜYôŽë&Ö7æÃ©í-„ðŽ°‹z2ñüßB\#ÈÏã¼¶ Ä~²4“ºÃÜM«C©m¾*l}G­.½¥!Wß� :\�¦(fäéZ`Ÿ„pg#Š„Z£ÑSt õÔõw5Qò!‰G(t9”¼y?W¬öÆþí$ÜXÖ{FPÉ+…°®^–›²ò)Õº5¯Ðý®â’…W`ê_ðÛh‰]‹ðç°ž,×€7øÀsÚ,¸ÕáƒÖ†Æ¨&å�fZYc3+¦-Z7D‰ÁÙ‡4?0–#[1�]¯–‚?üè²Ò³hçÕŽ¶G 1µÏv4_ËV#X1ŸÈŽ´á´óaÌ{Œ š�ãN�iôb‘NFDà�{IÿÀÀ=î¸áuìÃcª»¹Vë2�äsðúWu¼°æ ˜méÃ~ÇJâ¢ü}FjÈÃ`y©?-L³Æ=žáÄÙsÕïWÀ¾°]hÓP‚¿¢�áö¶ƒdš‘ †U�"Y±ph×e<-ÈûH3ÎsN…a$ôoN&®³)ž¾œŒl^s¬¼!J£»2Iíp§vZ§øÁ|¾m�ö³±&íÅZ4•ÂÝßbteë3’ø`íl+aß)Þ£ÉmÊTæ�2hϸˆõ(¦ ðC}‚ÏïI «Þõ’ü¢¤OX—ÛèËÏcci·Å­Íãn¸cK©Êp†ÃÅä@ÎjFfå+Tó&O�þ�)aê`ýºÛîwb¾î)²þ—4Î ˜Ç èÁÛê˜è™A™š´=y-M=™‚ªS—àê, Y» —]i Å?'hr¸1\Jø†bVßé§ù\E½*ÒèÕ@›™k°o¹”Ï›O _-%÷–¡º�;è³U"¼uŒ 7äÃB²]¬O¼ùI‡^CÞχ¬Ô¯�tuÖª}¤�^)Rã†ïyCo^Άe®OÌÁãòØ)_Klç$âȲÛhâÞKŸ�©â·@%:óE>ûËÏý-¶›þ¨oÇGuͰôi qo,ÛKkÉ·#øÛS»Â¹ä‰ë#Œ¾GUBÀõìMú£@‰®·zH#›3qíizó¦«za1Ç{J¦ñ¼"UðOP8MyCûMÐøG×°c¹/-¨æSsxîu�öœ¬ ›šÍ0ùí ú!ûøuÉóž»$Aÿ N© ‡sÒ‹ ‹§�î°hx½L 5n¨A�ý>¦Ã÷19ûä>¬‰6˜Aøéc¬ƒµEg0a<�ÌÚÆÃYEëpû@&N«Æ½…MÌkayÔ`øð[f¥ꈎÊ:LÍ÷$nUÍ4þ[®/?„òAÇàoÎf¸)é s)C{ÖT­œ "…ÌÚåÐqçÞ-úŠ÷»‡Id’ZõFÞVÒö">É'™Ù~Pþá&Ó#m Ÿ Ðp‹ØnŽZr^†ÐZ¡jLÜò Ï~ˆ£Š?èû‡1Ô@÷ªÙÕèݯ„XL�O”žMáð¨Ú‡�ÀñŠD8^6AŽ„õÂÈBÀÉ&ãíÄGb"Tf5¡ó×˰" ÷’sãnÐS`‰ÒÁÕXv}ë*­0)å?’wK—¬¼Œ•{ŠÐX«„þ8žƒ R ÏgDŸª4½idSÄ6\m®¹éD¢Ã7¬æƒS9ÎTfÿz¸æX†»ô‚Jl.NO€Þ‘~Ærõ‚¢N?¨”j"~ºÏðkuNÉv˜wÒÿ¨+�…õäȪaxn)E—>ÂÃ¾ë ’|Æ`[_ÎH¤ å»| «ö_‚±�vÜys5S; >ŠV…l¤q1õYŽw+ 0M\ f'Ò“1`2. ¬M8c}—’àÍ·9vš´Ó¿Þ©Ô)D@c\¸ø—ZcýÞý°ÑYŒ'£d�ë}âñ¦Ç¨ød€&y3©OïÕHÍJÂ÷Zu´«Ù,?icÐ~8‘’8mÊ"§ìù¸÷å=P*gä&›â¡Ȩ5gU/73¡4šñ �žxF_˜ì…ñ�Ø‚™ú¾ ‡ÙÿÜã•`Ï?÷]¥h‘D–�;Énš™Ätžt³Åø(”�+,Êc†r8xvâ 6¡�é0Öns^}¢ÉFr€‚ÁÔ6Dˆ.ÍF›°’ïu—xÓΟíô…“&Ÿ�=-Ó`G^ ŸF6椡æ¶zªÂ�çúŒìø)ÍõÈä‘ùÒ 5rR§ŸÅ°ãeTáŸÛÏ…ßÄÍàþ’ûHâÄïÀ©Œð¯P‡UoYß?™Ò µä¦ïZÂù®É=ôý#ÍÙÞÂ�6ØÖà-Û½1þ˜!�¶V%ã{”è†�E°uÖuŽÈ�aðÒã=ò¶&U­°B99& Ø't•9ós„ò÷Õ’ˆØ·É·õ=g¶úï…¢;|æ;ÏJnÀÀ6~|øåìv†Ïa;ÉøŠSøù·úÔ®tº‡ëfDaoÒ¡ð–ÄÇOå™/‹Ákaé°z éMÉ@¹&kȱ-¥…§•!AC†æm­‚8Õ RÎ'OÓZ©Ùý7ðó\›y×¼ :è$O÷ébŸV(—o¤7ÄÈwÂ`dt tA(3 hýEáà÷�ΜŒD}ùBÆÈøªò®@Ð&„Õ¹ÊøXÛ 8&“,7`=}¬–fî„-N¸#_ZwXâÂÐ;¨ñ#†pêé×�ƒDG¼ÊöÖ’ŸŽ¾0W¢‚ÎÄóç—‘žØËtlp ò iïy�sÒ>�Wç0TÞ '‹*…¹sÚWCçjޝq¨(ÓHƒ²»ï^hW ¾ckÑ@á[Öo‚ûÎÛ⑾vHnÜócçñÔ7ÎdÄŠÿÃYÉtÙq`Lœ`Ýo;äI f}:ã`Dgg?ª¹»™wkl¢ŒÔo¦ÀË M[Ù�ëýé‡ÍR´³”‡*¦ýÕš1 H?â xÀu3è™L-7j“G;œq‹W4ìŽ&:eôï×NpÒgïX<‚Eû[±ÏVš^ëp%ùÔ0mõ5¼‘»¦_ÓûÇÀÿzáâ qßú—µÏ ¥:HŸÑXìñt¿qqÀï2Óv§tRé÷Â@ºñó7˜-¨ r. ¦õ{ÁŽ¢‡lGŸ¾æ�8F·§/¦Qalƒœþ S£}qY‘,Üñ“ž�ÞŠ~z0K@þ -M3¶ëå)Œ¡ÉäCcˆµhÀæçi Ñ=ŠÎÐzÛŠÖ‰æƒïg9\ÒøŽ{&‘ÅÒ“ô 5Ç�Æ+�mæGÙÐd<'ò‹™¹3…–¾xÌN—ò…7ïjIÂ×=(jô+#œì¿”Þß ²[rqì[,:«\Æ{.ö(ñÓýYF²>`úq�¾ÚÝ×Â_À¡�8"rP VÊn¢ÊbS¨¨cú 6 ˆ§C+Ùý¦û°7f*z¹ 'g~e'!ú\™Ë¹çušz–ü gWgáñ�ñ˜—‹­çÕ�'¸‹0CÀG_†§sÿ?ø<2gצÂdB#é!,eì"­½°NÚ‹zNN¢ÀÈ6êÞQ„G5£©ùãÐ=½ˆè[ÑÄ]~0¤^ÅDn} ϶Èbnä]V1A G—�€v¿Y„9òouãŒXž~Ÿršž¾mƒ1Ewa|•wrY±Ó«#ò^+ùýý aèÏ&¸8D 6KaTnAµØÛä1 +‰(�£AÏ 1çA4=!ä&ù~B…Wõö$^ï:É>PîbŠÓo’‰‹@aÉOºô�÷ÎyuËPÇy5Tí @[õ—t4$ ‚ê–Aãé 8V8“x¨øâç2ôl‰e"½À&N “ÂAӅ圎'BÜìå¸-ßU%¥éž¸4:œV ÷¥x�âk¨Ôò/´‘Ô˜_^îIR¾�Á§5Tò Ìå°•�py%ˆFu‘5«ìÉÀ¼d,ºY Íc‹I¤O V‰¢ò¾�zK æ5”ÒÊsÏ!‰G†ž¼¢™ÆÞ8õÏ\.föl"™·¡WNõ Ð×õrèò ­z^0òÞtsäæãÜ\T>ý” Q¥!üܦ®ç ú­ŠZ'Î#zU‡qÍše¨.\Ζ¼V†—¥‘ñ z¾ê#Ùàö‘ò¦B‘º'®ºÈß7s^à‹WnN‡ýÖû Õ^’«}e6ÞåâyÉχáˆcøñÕr¼�ާÚÈðóÅdÖYr»8§-'ËÍž“©Â>Pt&�Î8+ÀòÛÀ¦Åœ«Ëµy±‡VàÇZ{²[ï}ß´ŽèÌÁ?ì‘Î¥�F7ð¿ r}™ ãCèäéXÛYÉÛô@y%Uõ“�f»WÄóÎ4²Ú!e³Slþ`;4öFáã1>zzw=þj t{I5.^…ˆŠHLúPGŠ×`¬R+{“/e6žÀWw±ÿwê4¿§Ü‰P\ y ¶zƒÙµ—ÕßOä‘ã+Œ±J@�W¦!÷aõ´YؤÖB¦Vú¢„Ò?nµ.�äŒïhâBVŒ&áŽÄ!|¸÷íqÇÚ ¨[‹KGÌ c­ >M jÐ_r�ù_1Ž×e?=Ì€Ô³X-­jt¹„œkž¤ü�ãdÙ¢|?Bɬ^W²(>+Ÿ„àÁï…`²xn~¶�º óú§œÇ=W\“…¬ kdû�ùŒN–m³‡„ÖHäY?…‡'úA½B› ñ _5 LZKÊ>?@ù‡ñÌ£Ai\¿Î¾Å“™@¥¶àξR|<å4\ÈúHݧäâ ;rJf˜í™<¦éG8v¾3`®}-9+Fû³.âòÚQ²Ë- oä·�Ö~ž³ÂÚ-B|Úîp;»˜˜È&òótóXËœÎ÷¸ «Ê‚ÉœÞ<z%J>OóÆ@7šu÷P�Þëh°˜·ö�Í÷Žª³vú˃šh&ax°Ç#…¦NÌ�¢ç¡"#�L*Ë€½FZÍ?D�Òðžé{ö#]‹µùŠ˜~î'¤€¦é7‰ˆk)ùoT�(í‹Çç ¯qB1Ï6l'�� ðJdCµ®ã"~QŒ÷W�¼ZRòz%»J<„�kó •*t±ÿ¿zHΩ _]E¸hô»›·Âêt5X]b‚Ö²èû$ûF®ÑŠË605l”î²k%»¶`ñ#a˜ÑãÁø°3‰å_ú8h„¹|;ÏØÌ¾Ô'¼¦ Þp|ä%÷È妶âÜæö­e¤fÃZŒ$i`±H÷þ>Œ{Ff“§õ¾$Êû ã¹,ÿŒðs�²;БÕÂUNý4'.t¬ƒ•îUô ß|,™ÒL§‰tÁSgoÛù‰êýH`]Þø¯öZºy_çî�;Œæ^ǿڭ¤e°‚|îÂÒ?¥øÇÐ î›Î§Z&×ðüôp<­cŠÙ»ÑC ²™³ã¡àÈ$ÏA,a�áS:¨S>Œït'o“ÚØ�§_’Í¢ËÁEÌ´_]„ÅÒ7™îc`­ï£#NpõH8kQy�zs9ˆq×°Wx„ls¦oýJjn ›sýÚÉŸ[(G3ð�LÜ”²ÄÅ7ò°^G—pûÁ`{?U}‘ ©6…xF9joòqÃ&J™³=`ij&Yñ½Y-4æ?Eï~ûMË]êÀòÒ ñ ƒöáµàª 8ú/«´ô`ÿ%üïg„Ï{!vÁ0êê�ÍŸx‡Ò¤x2yú?Pº t:éÊëA·×‹ ÒÈñNš3ûrŽŠ³"ErØê]I ÅÂ/ªyv6ôJ@Yïb"èáÆU¹ÓÎéÏHžáÞ+f#½ãMvó&j�³xu«`‰h(W7“èÕqåb!Œ–ÞƒzŸ’q�e>eß‘gµ–ðÉÍ…p2�a¥ÀE•}Ç\SáMûK %Fî™ ´´“|P�§åsÉÞ>žEX•«4aÿ¼ Å—‘#‚­øhD˲Áa³(:°¢Ð}:ïe7¦RÃÝ�0Ì3%kdv’üä'�7ùœù[æ`?ý3£>°��GK‹à÷u$á|3‰´5ÀìO�äË»ÇtÁW ¨˜± æ-ÿË\ÞØMå«]ØSõ‘xËy 5ÙàŽc/fà‚l Nâ’ˆëJÔ^5 wýaó_µ“Ûï÷t&Õ�ÐMKÏáú¿îìÛ)’° K˜ }<LJ�ýQ®¸A|#œúñ=ŠÈ °¼ÚåX.hDO®ó£;§.Y*y‡--¡§ü44(!*’”_{„hÛÔÐŒ*eˆû Q{êð¸ªÕW¨Õ4|—K¥Î– æÐ šsb”z ¦ÕV#µZCÎ⫺̤¶ôzn÷lµß‘!ž˜úw ¼dÊàì%{òLc#<)4Ǫµo÷ƒƒ]¬Ž{DOÁµ›¹dÕ<jçfƒ-³€DâBP+Ex#10¶"›3E;Ÿ| €’=óè±�f„ûà4Ø|¤·î† Ýù,à[’[3ÿØÛQÃ^»×º”ô·ÇC@X)ô9š’\Ë-¨¸Ûâ…êÙ[ªÅP³$®¥BÙ»bè�DÕ2ÜÛÐ…ÇŠ¶á™ÿÊÁÙ¼�FëÇÐå®ï@FYº_cõÚÖ°6¿¶Î$Nã!xbýezõ»5°¯}ðÀðâ1ü/½5�Égߨ‘’�4Ùç.ö6–ƒÎKÜ!{7M³B3z•J.è‚7Ÿ&IÒ°v Kr¯»˜àžÊK4Q½•&¥�½] à­ Àyâö_³Ã‡6ËQ1ø8ë#²‰lë­ÆÍ‚ê¼g§L 0p1Ì·ùEJ/Qô7Ðì%j�88ùBÏ>ÙP´ð,$kð9ùãìÍÒö0ì(È]ûv#Üà›Ï›�9ÃÖ°nôÖ?4�‡ÁãÆ x?õÕ3ùE¦ ½Å'†‘į¶ëM—àŽ/æÑ¢pšuåûóØCúCÄûm¬‡­Ý)Thù(<º £‚0¦DäîPî»fz}lûÊdJlg$'ꙵ‚ànê„kÚÖRg[c".+�ñm °þ—cz¨´ÞÅ’í³¶SÕ8GF{½9•³ŸN·$µC�Î‚š–™—°Ú_„Ñ}ô[Uïá~³`ø&¹ÙŠtßæ”kԦǺ¸xR.™ÿz”Ì«´zŸ6TùR#ý©˜wЄgQršüíŸ »û£'•‹7ï-âÎ�¶¿Îàv^(þ!ctÆqnZnc2JòT¶âÂ-Iî?ÎHx °¿&áOw/ÖVŸgk<ïÃÖ`. gG/�ÜÞ5�d«ˆŽA³a‹z–Œœ#]gýк´�º_$÷µpÛøvf-‰%çäÂpÓ¾<¹.œÈp½aÉyuÞ9É3 Ú^„²Öd``>ÕÑÝŒ¥Ë“µ ªäµ %üø¹] 'è¼;9Õ§‚´x–ûó±Eñ2l›:UDÈâ©›qÙ–mœYW¢ðK[~ œé[ÈS&îô lÅUFcÝLž±è~êÔs�&™ÞaÕÀ ;]ÊICº<^Ï.¦y’î`›«ósÎâŽØ—Xæôš2·ì5¦n½ÖD$8¶ìr¡¹3¨MÈ |œ9Ê8VRÿ47Üí vmA°Ûí-­þo&_„×–ÓèèâlÈ4“Þ›Äö¿7ä¨ ƒ©�.¸…€Í±ôš€  <Å55ë°ÄËßì[Çbƒáôí=-„>J'3\ëÉŸòr:P0—;ÜBÞ�gSŽYÂȉ£Ø1×?< •™äœw*š[Bß”N¦27Ùí› ¡ËàËTÉØák…Æ­t5ÎÖâɧþ©ÉEFèq»~„K>ýs¶N5_è¶ûXs@J„çÐw|?< #oãrÎXز>.°Ç)W$Áyç¸VT@Þòr3éå Ñ9¶ˆÛ½qåv¼huBD+!öb=è§@ïåÇ[BÙxÙa ½;= îOåÂ’hEÒþFí"Êcç©ÄçyÔúœ =­ˆ/vŵæÎüÙÃXñ)‚,wàI94ãùõ} é¨kr¢Áè9<ç¦S­ßkÈÖ³Yô}�-üh§Ÿ²Ôà�ñ(]]-̼úTE��à)J*¡J�<¦üÞ€¦“OHð;u´ä %xû*(¨?§£ÍΨe™ËÈ¿%ò°$¥ÒYx$x=в‘£%ßM÷}Nƒ¯R;�£–©!N•ñGvO1»tÆM²´¨›¹¾< %g`qÙ$ “¦eå Ø#*Ƭ.¤ÿµÕQo4cÈñ0WÎY¥Q·Ð@›;¨ÔÉŽþËöK­`žE67¿Y·Qül˜©í�'KßãïˆópÄΟd4zãÅ«W¨° )(Ð/:P û8\SßðÏ#ÿÒ›w²I€Ä ÐØ_„«È»©f<ÝÌõTŠì…¿’~ÕŸEV ö¢kÔÉl�ÒÇ«!ÒÅÃŒÞÁ¤u Ý‹ÇQÀKϜَ¼²o4Æeù¥´Ó_]ÿ [T~qr'ÂV}:~oùIÏÚiC÷ª[ŒýÊ—P|ô $-dží¸ã�& 1€æneZþh_œR‡Ì¯ê8ùQ‹¦¬ �Gy§jèÅ© ñ‰—$¦$-Äü grÒ´ »2Šh}³ Gâo?j1¡1i»AËü:ò&ù±~í\\ó¢­wK’—¥rP¤,ÅT+‰añ–uÐÚ%[�øßt…ß{«ØA 1hÍ~ÎlnyCÝšN€ðÞ2"±Y¦ä§ÐõÏìêøÕ å£ÀSã>ýQ„q#’˜žC¾$uÒÆá8SOgŒ»Ð÷à »·.&—Ó>“¼|>\!œCwöÖãvþ0°Ÿó�†/µ³ã¨¦¦=ÕÌô@GN7e–*à¶´&\hdŠa«#k´ïfÓ½ÓiVç{ª¶^€›KŠ›^BN­(íü’^—Ž`J´!ô>ÂÒ¦ Ö¾v;à&Xd!Ìý{ǘ½šÝ…kg\‚áµh¥»oªú`ü§1üìµ�šÅÇâ6•µÌ5¥ÃøÂº‚ò7Ñ�«7ªv½6!ç“þ° ]ÃÐÌD—LÜ€âzÙKT·ã/þ.Dów5ýç>±¸ó•òž»Që :lôæ(æj>UŲë6¸X3ФMQNYÍ…Ik¤o­ÉÄß�àµûszÍ£Óì¦â !º³•ASÉhâP¿¯˜NN31e½8z«S’\ ÓO�AÎ�ëtÅn jëÕδl4du^6аÉ ¢| íyãw™Ä~f¾^H5§yãÁ—“p«c-Öl,!gSWƒˆ¡*Ú¬g¾Õ¯¥C]»YÝg Ș©Ÿ¹¶ß+T^�rÌ8Q;�‰_ÄMxâìÏ®.ãã ê‹V½“ƒÃò¿¨öÄ#øqè2zgʆɱæ5S|àåˆø�³›ÿ@ã¾Ë¤}¶F5EcÏ·TH=НPÝæ�8C!Ü4ðÆNãåÄ´ª ,wÁ/ŸGÄð6@gþ9àm¸‹Æb™´Û²ãÜ!�MY£ã �dñéÃÆªµá)�Ö!ÆqùÆðÝg2Ç+ >L‹cÞþ˜D^¨`]Löà�9t§E0•¶ÜÏ•=ª€·Râ¨Ç|7˜V»g?fÈî·Ç0л’^};N"Å×ûÙ7½RÜÅ‘lWÖ öø^KöhYn¡�t絸ª‰‡@+óóZ‰ÛÌ(Håçæ{ÊЗo6À¥Þ:˜~.šÊLç^¹W„oòè’;˜gW%‡ÚØ8WA8¡á GwUJ¯=‰×ç«1õkbé¿ÐãÄ`ž5É!Ö÷H~Â}j<“mBjª2Ã;ñáÊݰô¡*ås.‚£Ê1ÛÅn¸.M¿Õ'Õ»nØwè%¹’’Tõsóu8·'¾ÊY¯šÌ=ø�þí;ߢ«½˜i¯#ž-¯‰ÍGœoñœžªñ‚¥»ë!cŸ$½¥‹Ê‡NÁ×½•�{ýðÜ|[ˆ½ý�æË�†<ž;ðE¥¯LE0Þ¥7ÐÎÄè³\�·GÔÑñ=CÜ®› Ð¥@ê»-�¼Ð?K:Ž£Yý¶¸êþJ8âÙI;‚áÏÞDòkò.]5WÜínRË3[iþÆý |×EW-Â!àÈúü´žYáMææáÃìû`˜ç !c7Y£ZI|uÒ›–Ëâ¯iŸ‰îz?Z”ÀÅUq‘xšWžÊgŽ&S£ˆ>?H„g<õŽÉBát[V¡ôpç–@o²'òWì$+Î1}Çr¨²íiÒé…¿‡‘[3SHƱiœGÊO©d‹>~XéHºœœé£VG¸“c|�Ópç‡J|:Eæî}LÜÏ} ·=ºi}µ!^ï9‚ÞvûñÏûéØS÷“›ÄÊ�K ñ_3çÉZb´ö-{[&�î¬æ£ça{D l ÂÊ/Iâ«'ÌÂI¬†íÈäÎ"ú/|aòR>ˆI!) xÖJ0p†íý!$ô—îÙ�Hsf<�"¡ý ®—‹òsz©!SM~=Ã�!2œïa¶ötTÕs€eBR¨Zð‚>Ž*ƒEöRp÷ç_”5'v±9¬@M8I°8ð/SÊȈBÜ:/KìþŒRËdx*‡Úô®IÇ>ˆ<ò ‹ñÁزýpIÜ&€ÆaRØ’|Ÿ–ZØ¡~ójÙÿowŽ= ¾ëÄ�·¥ŽîËòDïc# sû<ÐϧvÒöÔSçâûavwà2ø¢Äë�€þ­ÔpÑ)x(æ¶6­Dy¼G pæ/ꤧ¿(bPTl‚?>IÃêÆš±kÔ<(5$G×c¯J+œxÔ[D…¹Ö è¢8)ˆ²_î^ž¯„š8‰÷M¨F}J4òs3{´wŒC䯃ló^>ôÌÊCγ&ÒrR†ûvt‚m[¹¼y‡Q]ãñ®ò€:�¢ª–»Œ®’ˆX)òXK€Ýõ­‡\�„Ãßšˆÿá� 5MÞ¾ºãôîu®ä€}Õ.¥~¿é‚«/ÆRäç œ¿óvßø°Í»0œ¡÷õ˜s¹>äë*°Ÿò«ºUiÂꈼÀ:¾U�]ÇðZäî Ã1|y)_JËÒÓBv„ÿßÌí�Õ±:qܯlÍ™œ^ïƒÉúo› jý\n›K·MæÐõrøì9Jgó€EdÔìãÎÐ)Öw¿¸=�[ CHûïtVåáN˜' T.ø;N�ÕÌ£�\´+‹¿1lz>¼•š†ó–wc¾–Úz¢òJ+ôÎàe%ÅÕà§ñ6D?s®ÇSWÜËìG ù1  %¬ÝéÜÕ¬ÂýbVA"øÿM,�­ÿKÒS#q›çl8ÜPÉt«ópžØ\…[f;häêßx?µ—ï –ÿvíPÒc(Ö ¦«¨’ýüA©Î�pó]ÙuhÖÊI#e®[íjŠO’Pó4L€Bà—(ÀgGøÉ—,qå΃‘ãÑðF;UÛtg‰™£Ôæwæÿ��A͘\4@yŽö‘Ç]G±áÍ#ì�&>ÕŒŸP(”óžÁ×xrI)—Äi§M1õI'õ4"Àyì åO 8‡+WQ¿³6\Å7õè[QŽ7ZÄ8�Cx f&jl‡7ëÔ`ƨ”œ½Áž¼§ÌÝ ü»ú9n£™LYú×~-Ô¬A‹YœWܸS\¼—7¡^U(?jƱ<“º�v¨,ÄÊnôd~On!™¯?3ã³›Qžß�ÛR‹Nß~¡õ…q2p|5i¤ Ë?Àö/ȃ¯OóÐ]>žpýÙ~E RØI†6§ãá#A5ÿU¶“Ã9GfãÎjIâŸü�øt2•ïg€G‚.yµ»É<Á˜5…dܽ~�K³á[ÈÈÁ@ü¹p= ³%>Šç€g§$ñPº‰+[«~¶ÆÃ,Þ»X "ÌÉ~³�ݧƒã±Ãx·{y~qŒ´(×h~Ø·�hÎñkÄv$‹nXÔ‰y«µé²@ 1sÖ²aNØq_„£µÖ {W–€É4 Î/“¸œµŒýÅFá7È—ÎŽÖè¶j!¸¸•Û”éÈ?H9¥GþòÄU©Ü>ƒgntCÊXu»)É=¬$Àyä €w\…8±"ïiê¯\hƒLä÷‰"±À„Mgf£EKÚ�8áxkSq @Õgºlu“Öì‹­eûñIˆ5óÀ8…T­»ŸÃï»Z^tµÆ”fw¶g†#­‘*AÙôÝdmÚ+R¸Å„´ùų¸³{Táw$wýqrÖÆœDy\À}Ó;éáUýôdö"8ÿõ³§´Œ®�¾D_¾ÿD¥>á~2—OÞUÎä^Á£˜òzqTMNçýówh#Ó/_ÃF+M|ßðvE,&1•bTQbÙŸAÕ›dH’º%üÍN‡ãv?Ð&(�ìm7æøT@Y>׿u)DƦ“”ÚN·Å²—çHÆ©%¬G2Gƒx¸¦ ÎÞ<ˆú3Ï’cR‰xÝ«Ç<és,�è ç¿­á‹Û`¤o!ð,ZÊq=Šš]gˆ�›.9L�Þþ2ÁrÏŽ“=}·P,[©7}‰s^bÕÓŸ6ðCå;[ ÎÊÄ[¦Š>gÌÝ¢à¤~$Äõ\ÁêõÝ íc�ŽjQ°a—5|Q6Â/¡Û«:pÑè&]7,ÎÙ8Ùœ·÷IÎç¥aß«§Ã æÚ>Äþˆd¬XE\}ôáÇ=u´%Ø8Y�rîOÍ Û¹ðsÚ|ù½NÜqÇxΘ«>‰÷V| $„FKI½ýe4PKï—ëhÜŸY8±·ŸŽN·¤�ñ84S…Só�±»†DQ£õ-y/Æ�S¼(;˜†�ãÁ/9’ldø±¿Ø‹Ñ[—Œ6;E8µb·Ðê¼6¹É³ L>¦²J–—`k’ÌÒ %¦z¸$¯ƒ+uÃ=mZ5-z�EÜ"M!V�q´-OÖ“†‡ÖprÓqˆ·ßEu ÁI)h\±™ˆ5Ã’ã ˜hÔF §s÷D[ °Z8JǵâV-ÌSä–nÅ4ñ88Öú/#UNÂ|�fŠX‡í1³a";†¯à+Ý Ê·/EóTXi/ÇV(… ÷µ£ý S¿¥¡`r {ž¶PCä7sg”Ö—]Æ—Õø Ñû§`$ßà�ò‹1G+W@áß*P¦�Þ'ÕÐ’÷)‹j¤{‹‡(³h6§¹5vN…‚Èú ð4üÅ(ë ÐÆ›rXuT‹ÌéÃàPÌË_3m¢™DvÄ}чÆÉï(®Èú=èqç?²¦iíüÛ©ÉSq ´8Ž^/ˆÏh7 V4ƒ­œ4 §ˆq:ç{ÀÇ‘0wf>Î�F—™[ÙvÏtTMcrâ¶ßã»B{¼ÞŸãØÖÔOscùa{‡^î˜�“:¬�œ0ül@—½ªÐೆ?¬¦N¥\ì^ æûì0§­ø_Átg~îìq ŒM‡þîPP±Eó†R|uê�yä±2:¬9‡½kUÏv| À›–…xë})˜ÃË)ÕÞGœôjénbK]UãØ¨_ötåj N~x9¹[¾Ÿ®Pá´)©1&Aï¡…‰c#.¥ÒzÑ_Ô[l5 ÌCˆ *Åéi/ˆwà;â.º�¶¦Ô¢ŠÅ qõ¸‹ƒOÿq@ _¤ nׂ@®ê2Ù1H™�/Ô!FO”»â]úkÞÍй(,¸¸ÊQÊ nBn�[]—FÛCÈ6©4̬=ÃP·�œÄŒCf%,|¸®„x<“¼§WÌÏ·Ibñ©XxÆ“Œ-©Ðyîù¤ÈºË¹�¦·¶påO ýú$„ª[$BÑ#.˜å¢¯x6ûã¸ìÄbÉÃÀšn-üûé'Yp¢»RHqn̹ÙÝðÊ¥ƒ"òP%x ¦ý±›ixòý+ô=±Ú RE$}·M�sB+€îò­##f#÷á8٦ׇ:bŠU÷ÎÞ—‚\QÅö͆D й‡F|øQý=Õ%) ¾ü‘¯¾�·%BÒ–í’/ÆÁ•¼ÜðÞÈk7…“¹ðAé#5srK?Ðo�ÿ“6dÉ›VÚŒ“mò܉ãÌüúp»A×Ô¯!¿?ç�=ÙO`Í:D�+-æ»Çô03ç,¾ÝâŽ|ÿÑ}“9ui ¨ÙÉ^ã~@#ák`fÞLûâºÜTæÈ¿ª´[ôÐ�ïg¡ô?-òöü&RŠÀ„}`žÙE–¼®‚“ý†°wîKvKI*ªÓµìþ­#tp;·Iá<Ì^¹NK¬¦œm•ðñãø³ßŽÞ’µ‡ÂÛÁ”^�Æä\‚à«ôIù0>i©ÇÅó†‰wÖL”üU AçN³nçOé‰^¼åâAäÙOÄü°÷£ÀôgF ¡Û¯’2ºÀߘ3k· ´Û2Ó˰_93ùîÁí--8ÂÓ¶žŠxY÷-rD£„².ìùóBöo#QƒHïÔ�ªšµäè¨x¯zE½ p#m¦EW xœÜõ^ùÕFØÌ¦¬¡>¢&8qZ™s?á8‘qøÇcuA8ps-™÷«&'Þã{™!ºê 5ô?²«ŒÍp°ä9­WÃnQ‰1ä^+™ÅYD=«<‘ª�Vnµµç¤WœDÞ•¸Z“�{‡Ú¢ÓÞqj�,Ë„ßÑÂcû}ÁÕ:Ìæ5ÓÆØ”=Á¥Ör¤Kñ71Y}�nÙó€ÞK#�–Jq%�2`ØûŸ´Þf/óÍ¥£Ó8ª™0»lå‡3±ø§1±Ü) Kç)B)GƒÝÚ¡K…yg!µ ‚ÝÁGpS› 8ú�5Üe@ñ¦"ÊÇécÛ‡säïë/´OZ†si�6çw¿×Jò<½X[J®‡GÃþKDå™ ÌIB“ 1Qà$Oü`kû @ËF»7ò ß$Ç‹Î0%¨ÊH5¥F|„ôÒä¬þû“ÞL' <£¸­ùÎ3ùJ·kŒãaÍ3Ð4¡O—ú3W—ÿ„]Ñëpá�eŒ«Ék¨5Û ¦#aøjG÷½0½/Æ­¾UÏ^³9 .:àò JÈ[ô¿~g¼¾›ÛtTcÌØØÝ¿‡Vï(¥5È»ª¤ažt-QË‹„¨1HÖ”æ*ü×HÍ7dSkózð°LÇm…±˜aô‹„™öÒÕ÷IåN°üò˜Z�PÅ—ç}Ò8/‚c™Çí¢°ñ�çd^î9]löJæ<ÞŸ î[£ðm²:Ô:Ê’~ {0MñÇß ëhüf t=1ŒŸ.2œˆ®µà(¾º�åÔ T¡¼Ë[’œ½Œãu«íž÷QçùäáQ�F¢ÎŸ“y¸lË18~ô8í0úH¦%å��’T8¦œSòW� �a‚ߢfm,ë¬AþÿÝÅ—?1 ÌÛÊ:R0uè'ˆþs’y£Ü-Eçá\Å~è9BŸ[Æb™µ ðd>$³šëÁ󛉗-t¿�túôÖ¬Æ)§L|σ¿^!FY»Áá àùÐrºG—�{·ì¾|…½øç4NY÷Ò• ª©ëñ[ýI’#ãErÇf•KOɤ®<ÄOÅC/ÑÝæþ:F×Jåà†üé½-ŒêÈ=F;ݼRAÇ­œif’(¸ßäçFF2«Ö<Æ‚I`§cÏjÔ`‘r!Úo¹/*’¡Fn ÇR·dPRÞ€³¦¶‘EB¹æ¶æËP i"®BÞÃÁht0ßì�¼5)Pq;[Ò­‡Ýe`2q/5à&«Þï[ž>39R½ÔÔK‹ßLgý½Žë`e —¬ö�ÿî­£ñ¢eô�Ž*®þ�|âܾ»ðÕ8 M}u¸ç)ºÿÝ�# ä̢őÚÀ3g÷{›(çÅkl6á*Ýâcb÷½$ïf÷BÃà Ø™Ý†'�ÿ²F“{P¤ >ôÙpîŽd²%Bθ®7�T'©áרvÊÈ}MŒ5¬Â‡âb3¥ÿL’é9[ñïVYœ±Ñ?ô aÓK–ÑõAó¨4Ü:Cˆ³áˆ#½w#Ú„â 5ºä bŸ–ü×ΰöÍ.ª5ùµ�ÝS‹6²ÈG�;öù'M9ëA•Æ[?¢ªB/QWI ÝLP £™n| ÑÍù¤¾Ë�Jéâ×\–Û²†Sñ�&ŠÓ®EÌšoêÄÐO‰“¡²^jqßU\†ógžãÓh*í@~+3Ûµ…ˆÅ™Ab,´ ³ÍJiUá%š+ÃÏUÜ× _s¬Qªz9,,çÁ:�ÕxÕ¤Ÿù/ý%øù<í,˜ÀO.÷0íu=væ\ñë¦Xrê:$'Â2RÞ{v¼¡ês~‘Ó³oÓ-au¤43Â:Ö™•"¶…Pþö6/éë}È^Çýå·à¤—I8ô‡Ý|Hª‹Õ–Ãî†\¹äîƒÔp‚¾'¤Ç¥¹Mtˆöe®ÅÒ;$ô“ L®ÅÎ+WpW~0Fÿ-¡$ä ûÛ�ü– ëûÑY–³aT¡œœOúE3c«Èš¢æT‹ u™x�žxøõ¶ãä�§>NU.Kr£ßha0[Õu�[Àåèq¾þêï7PÞ&øqØ�•Ü„ãéjäIã<½ßY·Ñˆëªp6WÊB»�Õd¥Fü¿;ÂeÌäêÁ¢¹ˆ†m‹„r¥>¸öi”¾raƒ–D¡ºX0|Ú}NœY™Qpò¹èÊž¤üë;Pæ]8yàR…k+lA@l>M8¡NÈH`œN5ù²þ/¬·ö&ö¿³aE8`eÄzSÂþZ¶GtaCð7Ø–yŽæ9¤ÑÑBðêÇW‘¸F‚²hoÄJuvÓÿj í:ØÕØÂ JÀ ¥÷ìõ³ÃUù6�è»A˜{â$jκoŒ[qÚ Þ”ÎÅs¡w髞b²SÏŠ¶”W“†›õØÜ;Fu¹Âœ–îARé}‘]êš Äi¬ÔEϯ™¸ùR&1ùO—¦ä¦âLÉFºÉd .-ÝH—IyaÈÆSЕ7†I/CÑ*Êšd~2¿\ý•QY+�IÊ™$à`&è™c“ûvî.)Aü´ÅwIZqãd`ìò!Vœ§ž¬…iÒÿú¼Â$³á‚Ü}xÍ®% ×WïÞŠÒ%X-¯@íÎ$¡õ‰2vq­px¹ ?„ !¤‰½Þ¶„õŠöÆr�Kl—˜èÍ"¬‚DY»ÝÅH<� ’JX¿—�æâ‹E”Ø.ýaþ<½œnYƒ¦&úœ Z…ØRRŠF7R‹©{Äù�ý"�m/½Kûk~Ð%Ò)X ÌÌRG‡U§hÝ‚(¸×ç‡fWŠaiÇu>¥ñÿp¡¯7}ÿUCJ›é>qP÷šÅ|µZ½öá�àwð²Ão[¤äú̿˂ú²xª½;’ øcÃ?¼%kº¸T¯‘˾“>€’ß{è÷ør<òŽt›�–‡4[ÄùçI¤åÁ=ó+^ çç0>0Š}N¾Æ`èÕ!"1‘E’/*ÁÖS"œ¾çg›ƒª`ºãe¸ ®cH¼á áš’‰©ÙÜ“åÚà` ‚ú™§èáf†ê¯€¶>cjÒ£f¢Ô�ã¾%3ÐÕ<ó÷ÖÅãf4$ ÖybÀür�YDŽÝÞzGœñŠå-?1/dƒàb~Œ•'™’<Ü£üרdûǰµTÞÿ€ {`{ÍZl½±‡z›]!~|U(Ô¦N’ƒU‘U‘ᆼœ†m|�ø‡fc¾JtÑï mUŽ&…çЯ!]šnã¯n¹÷ X¢÷ˆ^ú2‡úYˆÃ²Üèµà*(ZÛ1·ÏÒÿˆæ²Ç¡~o-Ý÷›—ûE¥m5À­»�Œ,ùÅæ•H³E^uðçT>#lxŒŸ …ß²*°ÒÂl<ë`¹r®ö5Ä}9!Ìhh>”NŠáÓîILß÷�èrô0Cø4ÌoVçF· À“èt„Íc(P†§ƒ Ñ}jcÕR¶Œl9ÞB'v“&QðxíZ4u[ƒŠü²œãÞ9Ì’¹‰ø{¤ ¿\:‰¤HÏg¤ˆÙT'MOTIƒqöÄðdšµÏ…ü§ˆëž×"Ïû0¶:7�w\Ç›Á{ñÖ×N’Û�;÷îÂK³Ù¹)/ ·­‰Õ‹)ì”l`˧úi†Ù"Xãá‹ E0!–‡ú'ݦsÆ› _\4„Ä"ómÂmï´u�EÄWa%U,NN�°¹CR•n ×“<øô�¶‰_ Ï/¦�Șo¯Æ=‡�`asc<'ú¼Ì xs(¤Æ`rIF’ñó}EHÕ‡WO½¸­F¥°ác³Ø¥â#¶a³�¼z4A'¼CánÚvÌæ㻓†w/æZùºÁzï*'ô ÆSÿÈFˆÔòåàhøíèƒßžçu›‰éò1ØÚwL]Ó`­B Ú/TÆ¡71««s¯³={æÃ–¥‘DëúBöþò“2›+ÞË”}”f¦ïS…‘ÖoÔO°h(À–I!ºëôjÖm†�¹( : )U¶z9ôÂT*Ç¢Æí» Z#‡K )ºŒ"¿�àˆfÙ¹/µzÅqù•x \l†ÏC8`"�—Ò‡È+×8áÿœ½i€‡½M˜°ÜhÚÄv2YžJð[[ �¨†Œ]'«¤){#xy¶§IðsmüwWòUŸ#Ö+¢Èr�$ø¬ø®<‰ s}[ɺ­sèÝkR½Ý•L¤>%³Ö΢£ •Ðu+í­;põ÷Avæ[â¶ä¨Í̧!öÃôÃTܲ‹õþvcOG’‹hb[a¦ßR~ žÞ"MŸOÁÆ¥éP¥¼JÕe9ªg£Q,^Éü_!¾üË�:-´íog­(d¢5®£¯o"øÆc_I&‡G1¬»8ìŸ4¢Ý³màü‘ vðð¼j¿+¤©»Ä«~~IbƽÖ㺋³R0vîªDâÒâmTüh"þsy â¸Ó}¢Üð—OIÛ:y²C@‚Ó¯,‹ö~4“÷[ ­Í窖g‘Åg5¹�õ/ÒñµÇ˜gS+QóÐMZîe ]Ÿ‹à¿ ‡i›Hì´�@¥#¦hpñQ”Ñ¿$Ͼ=åÏŒ×�£§ñ—U;Œ`^åMerKΠMÙdùÒ˜_/åñJà*°]z™‘Nɇò‘å ºI]Á%Zàþ�?ù�Ìôˆ/Ü Ç�Œág3jtÐ€íø³µ2bY§0!x$f„qmÂÜ�ýw±jI:Y,xõxoÇY0Í¡†�]ÔaÇ:êW<ŠåÔAu—Ty¹à0?C†²ªiUë}•Zc>3Їúù9’oGJéŽ.ÍÒ�$)Ë®=žÍÙã� ì�`ôK;œŸÂû3ië…“äÚÕi ¹¥•HÏa ï P¹zŸŒÉ¤c_ÿ¨�xae+û³äù ã�!kC «zLx8S~¹Fªçtƒ|œsÒŽ¥‘O×Ãh×Ñ0Kê$¸ÈÓìç¡T70�ÖbÆØ‰Ò[LçôÌű£ÑXú¯¥Óó ÷õeÚ^�LCÄÝàì�A&W0 Œ[Ãø+E®ë¶8´Œ©ƒéïΞá÷ göš,¼ýˆÝ¦ÔG–»�‘ÛkÊɲ”›+BÅeL mÃ'’3ÅO­¬ÿÐÙù‘ö„0Ïl…ç‡))ì# wî9:=ïì)b룱_ŽZ=]餾"£e´Ê¦ pν¯f‡³¬‰ èļšØé=uø½®˜°"áÌÕ=\˜«†$àT‰ù‹–)zþ?ùJ¾æ ˆ¸™Å¾¾a’)à0ï;ß&ž:¥½$¿|9×uÉâœZ*}Œ�[#W†›ïÚâ˜[(®LÔ#&Ö8ÃìY¸õ?vǵhôrÂßžVSƒÎlòôË%ˆíñÀ9û±Ø"t·í¡²BæTcLbΑâ!Rña'cy7˜T^�…B¶žtï½/tË…)b·zÞ÷b¯ê’ßMrœÉ¶O¸ê×L"eŠá:\œò¤ÓàÜ Ú±5…;`žûjs×ËÄæ± ©âŸ‡¼µ©Þ_]¼ù%–ÆU¨ÁÎàM°G�½ ýà]š/4¤=üšè%ö׬1. ‡sàŽÈ4Êfû“ÇW6ÐyùÅ89$ÊØõ‰,pºFÍëp(ØÛ¾´£NPÞ+Ožßq^®°¯!8Z¬b„£Fi3ǚƈ‘¦oùøK%‡Äã{4i­…B•Û4^"�ޤZâ³­àt·€ÜŒ Âí;uÁ4ÏßÜË„¡ìP¾O mÿ&Ô]§Éy«¯ç¬^±ù¢çI‰¼;ºŠœ¤‡¢6áògëP|²nK*ƒ¥éÐQè!Dú4áã >äþ·)ñÔ’¨ñzTDz˜#°oË ¹‘²³‚žÀŒ[°áb(VÀƸy;ËFZ;UKl¬:0J+ž<Åð_³œšjYÓêB< ‡GÒ{i|¯ä½AoI,ˆ\¿Oô³múV$}A ™V�¿oÛý`ÿën¬ýþ >²ít^B4òúú‘3rªøn–"û¢7ÍX’g°“—ˆqsTÓ_ÇW€·~)£°ÔZ—3ƒÑO¨õÇ·x}S'Uú›vYc¼ÛlŒ[p…j>»Œ¾ÂiÌð_̽Qv¹™Ti|‚‚Š-nH$jjÚÀ댻C-™¨já›AïÉ׳¶-¾úщÞøÝ^ ƒýP²ü.\ïnÆò¬ h�ZùOÃ0½tjè.cùÆn¡Sí ¢—�FË€â왘+‹¸Ò¡€ù�–�g:†*%ïÝ;ÿ`Ò&:Û›EiVR'Qü°ŽplSè´�üpÎåøûggͺE{‚ÂQ§+Ë|æb²yxئä p¾mU£ .æäù•qºü>­~njôÙ»(F»n6Þó‰|Ÿ«q«[._šÇ¤à—LFfd”®ÔÑ¥~OªQDÑ l§šn\}9¸o¹Òƒ…at�d�óÒ8© àoæ� “V4ôSl›1ÆlÕnA©ñ üÑs’¨ì:Šs}Íö½ù—EÖ®xç CWjËrì tÉÙªÿPoP‘+¹¥†ùq´š&^1ÅÖMo›ŠÀÏ/Ž0CýÙÊRΑ8f/Ìá]Ö%‘ÇòXù?쥷ˆ}u-¬¯Š£oÎfPÁÀ8<å” ­€¯Ïúàê°Ð;Ã8-­gsÍf‘ÚóBœf95š¬™]khJ0Çô­±7î {Ü jÙÝôN•*÷´ÓN­nÒ;Ã:»Ò1A¶†øŽÖ’’›Æ¸/0�ÙU¾ d�]¡È\ˆñäb¿Ó$µ©‘²ÝÑ%Ç4x¸÷§‘¾� ù[Žêß”@ÙäkX•�;“cHˆ’œ*«"?êUá³ê%Lµ}U¹�°ÜS’. s*úÞEÛ³ˆÈ«JrÛIœÛôx ø³Œ ÒÊ�$ý±!|u[Yÿ_R8+$‹úyÚÀ‰U[‰ßÁpÜ÷õLÌ)Ç“ ˜§5 ‡Y94Îe/�o‡´ø8òAÔÈoöº9´zÅ.Ðò›�Ñ+¦°rVf¦ P�Å#Ô×™-ÎÃ,_Ãhßq–>Vý/°R¨À5g�wï@žgPýÜ5æÄ×R˜NŠÉ¥æ@¼0 £Yå©ßC˜§6µXÜroìX ›¬Ð€_g¾Y̼x@¥¬§dµ&tÆÇA†—*Û‘dACqL—ºHZ—ÐUׯÃÔ�8sgwü¬Ç)ßdU3–�®K>G}b‹5>ÒÒ×�P¹Î Œ–û¢Ø’Räºï§iÿ]©¦:d-]Xû&"xl7‰ùfƒ¶£N(·Ù_EÁçÊÒèö²�á)¶c/Û(àÊ¥…DÁ_ƒ:ÎêÇì9™P<ß‘òo¶†+¡¶U ³"éÑÅæð4ô„ý"¦+uɯò+ð¹Y�sŹ¡l´á/z·¾…G³ª.£°úAœ/)‚×�i[ì!óçsvEÕ¼\§³= zvŒÌê �ßiÄqŠ› |Àݵƒ4}ÙGT¬¶cHš:W·b·kˆ¿»6,s[�¾/hôku.ÿ÷¹ÌÎ6%ôݺ }ÄúA«ËÈÐ%øp¦‡V‰bä¡ÏTÀuÌd=—Ò‰œCLFÝ~˜«œÏì)攽 Ëc÷R~ó1|­­Îy™ˆÿíù]ÅÞo# ;ž3kß^†Fƒ;tÓ;oºïC2ht¸S¾ Pý@;w%ÁãáØ”3‡¶¶Á%�åìÚŸï@áâ2¦ä¢;äMŒâÎBôº- úµý0 ðŠ,Xw‚U !µ£qævÝE¨Ù~‘ü–zŒºMÃdôAÒÜq ­œIÀ-=<¶}6=êâ@:®…ážè<¢i0�ªýAGç|:­ø ›!r“üà‡\lÌË$z!±`Wð�(ëPT“�Å”Ÿ^Ugšœð*¿,çt¡>^Z|„ÆÖàl£fP5œAι]…‹iÏÉî½G±«Dú¿ºÃø¢P2‘‘ ÞW–p³«L©ë§@”�ŠE�–[Œ}l Øp.ÁeüY~�Ì_Qb‚´g‰$É’m£Í§/Мž(=PO„%w¢Ð¦¿äš¿Ì?•F†S†éãÝ[ÁeýSº5S�ûÝn;%¯Æ=ôÔ ÅçHAŒ~6ˆ&×Óåé p[FºZ¡s⥹:ß1HU'õñ'`í®X’]JgC6k?Aû&ç×åêiµÓlÓtA’Q]‡ßó¤A)Ç”æÕUY>·‡o‡7B¾ýSÖ3ë }x& oÄÀ’4gŒ+àA{ï"ðVüF§£æ´ƒ˜óù:S¤�‹§q·ùïá^‰>D_=âç,û®‹gzÌ1õû)"µDؼcº¿pª¼ã(«ÿ›T(—€z± [;b4¿¬YÁö’Ô¼&˜Œ €qÓOHÔ¼ÓX¬àêØêÝHV6vÓÁ¡ËPÝ™D Íùà•�"¨«7²Zã^¨+6‹>Ø™Jó%3 írú.µÀ§V�ä´³†RE½CЮÇ®u<Ü /æÓ+¥bL¾N+,‰ø��© qúÊÓÔ?ÞÈÐ5/ Q , £Ê³rðOén¢cß ®Õ‹ˆLƒ–®ü�ª-,g�¬ùI¼W6ÎF5]QP–LB“™ÉoÝ/TþB^Q”劤Ì!_Ÿ0D¸P�i­…Í™è6éDç]ÒÅÓ}÷‰¿’%æƒìÀ‚c°åþ~ŒªïG‡Ã›¡×dnÿäb±Ä;zê#-’ÄÛ¯‡ R#"Cî£ÕÄWöÖž>˜™XÆLrëpf\ ›ÔRGÔxÖ ò¥+¤��œZÔlê5{y€Ø•J’þÛ�êæQǵÑçÙñ‚_æA–2(³A†~26ÇÒ–^_p•½µ0 Ÿ­çã–·Z£õ’Ø"$À‰½ô…¹VQˆdÛBú«Kš¼�ÛKeyÛØ>ã|FIpˆ4±¾»oÑ÷Ž�H£f§·C¥ñGÚ5_‚Š�ü;ûç~ÁÎQ¼k,«ic§ }}õ1ñÏK‡ò%4þzr¥æ�Ð…çÐø2ô@Gî^š»–›“^Dç\M—ž@y>/”z½íDÞ@÷:^8™¤E¾ϧ2¯xæê Úú³…ªpxQÓÀ çm+d#,çbùÚ¢sïô)ÀCXô3ƒl^z…æXicæ¹æ“Bt©:¢ª|&Fɡւ$ Þ„'­ÆÔÔB¢á¸‰ŽOí'[„ZQkï"Ø­Q„AšÛ‰gþUÌìì·x„‘îç4Ń=Bi �>›Ùú�íª/0 Ã`�¡‰~Øþ$�ZÇ>§açiºèE8xÎ:­!›?ÎdF·�mtÉîÔÎAøOèîÚ_Lte1g87'I"_¾Y®€3® âÆtO¦;�ÉåSåÐ ú�?ï²E¸ìþV4ŽJ†eƒ´y¹:Épñ€!Ã)š4³ŠOW…�w·Ó-£7Æù³»–öÀ«åÈβÝbiáÞ¶6µH·(~°6‚W!iøPb.wF¨™Ñ^^þ›ézçhFý¥$gù=ܬ®…’Kòñp“2œ…@p:øÍ<�šày¹$r\ZŸÙyó&ݧy“¬gËñÌo}®ài]ô[–‡)§¿Pÿ“Ï XÃM}V!&ô:L0+3öL £Ssê wÅéJnÄËçd¨»Ë#zS²¿¨FœúCŒ–äâÒÅYdÞú6šR¬BupyLžûWö¸ pÀkW6H”,¯¡@È�1ØûžÌÃUÙ² p)®êGçf’6Ã…,+�FcuOhhê@Î�k€Y~�Óú‹Dà ˆÞ Eºø92’ó âˆ-/ýL.ç)óæ¦n®`—.¹ƒ£:W‰gEÄÆ¾¤wgOƒe‡ E¢�9ç: ÎÖmĽÝÙXd…üñØ8°+.—šoìÙ�£÷_á ó#¸#ÿ5í™aŠA8B×å짆}s¸*²í yÓŒ[±>œÇÂ÷P^:‹¹EóÈÊX©__ÈÛjœUÐÇx “ÍÊ 3¾¦“­R\0wÅBÆ RÕ»èWìcû©±Ç=¸(òáõ¿bt•}+Í» 9˜“5'»èPÂ>š{Ož¾x£Î­å½êõ‘$™âmRÂú™¢[Ë_’äU>ÇßB¥6s¶¡Š÷[¸ÀÉâl-r_軫.8û/þí•Å¢YïÉiÙ� ³&g^¯e—Æ€yÍød÷з]èaÍpRûIˆö¸“ 9é°JÀ Â[J@sA6z‡‘Fá�³þ*ön+#îvªÄ]·<÷^Þgè¦öp+å!”QÛòl2P¿’l>ÒÀèÝøE…õmñ}»%¸ U’Cs®àJë×Ô¦@äÄ9tg&^5‡M´”.ÎÕf|„¢‰Òsl” ‡àßÅ(ã�¿ï‘Û�ÓÁØO–¤9HâÌ$$¥�ð&Û£²„÷Ö¬µZ Åó ÇatiùFÖl¼ï»}¾mÞ¢óxÂy>Fyæ ˆ2òÁMV# Ë­Ý@7?”ºpnÆ´ò¬ÏÒ+Pœ¯�2ìpôŒ §Œmd¯üc/%ýa¼r<™Áb¶ôŸÇ°©±ôZÂM¸#ãKolÉcRVK’ñ?á³p:˜HBsW™süËñ �Ø9Xêb‡} ÐÂå7[qdL¸>…øŒHvÇÎå°³1�8]xÆl•»\)Ðòs…¿é÷ÍdÊyÑûàèŸÊ •—÷ár­\:<7u??%|>P®,›RG]#I¼ÿ? îû­çï�xSC%´„ŒRF”T¯s¿“Z*Š iñAÈJ{H¥EQ´$Í×¹ß)I) Q*É($EH¾¾Á¹Î¹îëy?¿1!\N9t£ª¦ê¸�ן™dõÄEÐvàSŽøSYNIŸåljÈÌÖ¥ ›iÄèG𺹉œ.*#Ö ÿÒ}L&íûeL\\<ð@ƒ ý³{Ìt3a�ͤÑiý2bNÕ¯ïÝžr0œ¼y/ƒÉ¿¿QC—nF³k…Göà|ã.z/ÏÜ¢›£‡Áuà8³‘÷�t€Þ|Ô>ÐAxc?WŠc²/ÛÍâ:×Á5¦š~ñzU+Ñ+sdøÁ¸VÕ@½Ç|ÜÁ£EÌ™=t|ÛF䎌M¹#ì�kK9Æ/úÜþ߸�¸úA ó„ÓÑ¥B ý=›Y¦>E…æ�Auæ[½�Šƒï¾qôÁtL-=eüÅGÃÙ8¶­.O|¦óZLA—çqR]ƒek Á^¸Šµ2ëDÏ眂-{`Zg Ú+\Ä®Ûòà¨ù„ä.ŸÇ}+ÙH?õgÝd§aÄ—T¿õ,‘�ǤU!˜öY äS®B­é‹*Á?¼¸Ô. ½3èžk—²8`»ô _½K¯äÂÜôP,h%Òg¦Ñûwñƒ^1ÉÖL%é?@fÜã5ðÝ�‡DpíFâS¨Hî®ëg*\Ó‘P”Ȩ§a¯Îã½t$¿ÛáÍ™P´Ð¶Ïþ`"xaJý÷ÌíÃQ“�¿Ð8ò¯s�§ñfO˜Û‡4Àqm5yuõ Éï‹�óâ± "þ›Œú}&)MÊŒºyäË»«ò}£¥ú{ðÔh)–¬††.5èÊÁº�§Pr÷8;)±D¸ÖøSŸsX*º�ÚÛ:áÒòs¤Ò<”¿hd<–Á¦­gAìM¾œØ UWÏ‹jt/MBEk?º+ï+ø®v•2wèÛl˜b‚Š E3ßMçty|$g$¾Ñ€Ðu�Kæ~Åð)?òÉt)wX%k�Èš•vøy1/ˆÈ-‡ç`ä?<¿…�ZP‹þºÃãÌhäeÜmô‡Þ¸’÷ž,"fŽÚô˜OI®ÿ÷¦\KrgB ˆ¢˜ÎiK·èñG�¿Áë×Lì>~gx$IçBì/<¦Ç÷4áªò¹ôy¥ä¶¶°ø/»f? ¤Ù^Òðì‰ýÌÏè,£xe< "Ûc‹°CGÞv s%v©ÒW½Õ0Ò “𠨇£š|ÉŠdòå¾GΑ²+¢ñANV¾'>þ„ó-¹ ×³ ûDÅIco ù±…êÕ�„›Á¤5ñ,™?õ“1¸E?ºôâ”íg²y ”ž+ªÇI�û(·!‹¬ëeÿêˆqJÇ\‰XíÒ~(¥ÊêO é©ýÌØ-TÖ�¢µ³.àŽk<¼„»´{5çÈßx’þmŒYìž…ÅZâ´kæJúƒô° ÇÒ ^®jŒ:ê=S͇Ëà×ß<Ü|Ëgç_KÅÏÓ~5¹Yõéè ðœ’çÓ9lÝk½÷­+›bò´\˜“ ëQ?ð Ùw9öš…YA¥s�'Ç i­fݖ咜ˉ L†®‡¸ q*&œ¢«�i–ñ|®š˜NÆÊ`ü£&=AÓ•¤|R—Óg?Ÿ{dy#v9Ð[‰Gè䜴ãzƒúœ—`yë:Tˆ†QÕPâ·t ¯¥áÆŸ÷`½÷-fUQ>øÔ£Ó„<ÞÍσ¿­  Ï­šÉþô†¤m¿›äŸö[*š—¢ôîpý„1)ÔÒôÑõ˯Á/Ï2Ùilh¶a·QÚ²›ÉX~‚úFÉ�_spï»´ÚM7=Ä·ß2µã)é¼Y„5;á·gt5y㿾Æ~¨Å–_ ™eu XÿM[MjA�‘…žš~fB-O·ü„\ÛQv»ó;µm†o‹ç¢“LNÕõ±¨ØJA"€þN[åÁkQÄð†ÞzYšüÂÜ•©Ý$CFÒâ/Âá>~¬ÃÞ?°HFŒ;±Ê�n?3 ÑëðÒÃJ˽ôîêl0‹´fy+x1›Oœ³ž†Á®ƒ�Dé€,fͳdå¯ÿ@µû{À«fÄ–W²›“ƒñŠº)5| «w�Ðbíd´ö'Ÿ¹Q¸B:ÚÏŒ’+�&x²ÂM>8±V¢½Lí>I,~'ˤŸ_Äñ³ìÆ!™WT·v V_�¥™FøÇi\×’€»ï’_©”©L]>ˆêQ«qÀÚ€CêK ð¶'é«“äœ{L¯ d×ÒY�°D,Ñ9K›M:¡kE§þ©¬›4ª4äaQºØ[Ç€¦jd.,%¾¹fhÝxyv]Âñ²J2a÷ç »}ô8ðÆ¾…+÷?À:ý2X“¶¿]ÿK>è�ª~&®]~’)ì6—Ç-Q‰8§"¾áU|iãj“ !rBõÙ–Œ† ²žÿ@žf)qwÞ2Å£:s°-C¿ò™3^å?‰ÉéNTú´Nšt Ip}â§‚/×DPãÓ3¸º§J øQ*–tÒ{*çqÃÛkTäX¾ü�Ë�Â+r\§µ¬…x?M·[^E—`ü{½I}0IŸÓKåŸòBqQ;(zT—©çxü¡íº€¬4V äÑùŒHz‡Káï‰p¸§…×Å+Ék;š¼„5JNpža¹›î*qÀÞ%œŽåîp¢¯+O_Åûdø;dƒz]î`¤PŽ7ªWT•yN1Á¹wAZR¤¶ÙÓÏ«‹¨Qj4i;³š¬Í̓©ÀÙMR�¬nž.æ6ÇaΓ-DÐ<åß>t„‘žJÐy¬`ÉKz·j/Ìqܦú÷èàÖ,g=r¬Ïpûåp“áJäQÿ‰ò^‚`¼í;]rÜ÷þ5…»YÚœÅ> 5�ãìÌ“;‰Û¯QÕšµ¨ ÷‰É½5‡tf4çÏÄsÙ¹T1{ y;ë`ëƒ÷U%«ŸæMÿ㬑ç6†' Ÿþ'¶µ“‘G'¡ûÏm˜LrC‰ÜLáš(r_¢œ®U£7M&QÒ%§2\áXµ#9þ …fÎ&-m.Ð4p§êûˆ-3øNµŒ¾Óë¼Jxç“?‰V=Imç½§‹#|pm�:Ÿ¹CfŒÍÁŸ^ÛaÛÃ\[ÚK£Õ_Òd|E;�ÜÅ—£éÞpE¢ïGOJÖÐs#"ºfÙñz›åñ 2Ž ÀôÌ€//çhý4€WÂÃ7Ó<8©î÷™‡S/ðþÇïD⟠rb^øU/�)Uz ®EÖLh’8Dÿ8ƒâßÇhKU<´.Pu!¢WEtD·�Ž1X#7©·´Å”{Õ„;=ðs`Îr@òN‰ˆ¾ö 1ûßá�§# ·0gÕφ³ß›ñBÕ ÊýÊÅ�±�`ê„�]�àðqˆÜã‘'_ˆ j$A^dìÑYxXü’Ó°:H›ÎóàÒ¯÷©ÕÕ8X‚Èób/¶ ¦ꎽ&�•�ÉÖQüo-’¨ËfìBo!ˆ|³ûvñ€õP,K¶�-¡ç†•Q[þûë¦,4eªÀßld3yV"›ü„ýx)�&ìÍÔ?y\§¯Lýê^ê¦6�*›ÇC¦¯5*7ÍÅ­žÈ´¾ܦ–b+ÑãÕbny—\{¾å¾üÏ2³V@ïñ>24ÕDþ~~þFÓáb~>š3J >žÓ¸jhKNÁ[Á˹ÎL)ªÜåBBâMòùä6*,«�ݵè^�þí9ØîX–)Ì•­d[•+Û­�Ö\[NÈH¤©½ƒéâ¹û:™ðÀoÉ2àÿ‘”)D“½î[A_-F;P?›å ±…�Óú°’m¦›å*X�nòbš>gM¹"'pb®ÏPƒ¸ŽD'7JSbQPG�ZîUÃâû€B ¹3¸žå˜GÕM‡>U5hß” k…Þåа´ùBLf¹Ámƒ[äpß_–ý°Ú?·2Vîý�¡÷,—sïj SµÏ‹ñ~z�;* ¥�/ˆíð’ÌÂò“DZY¤P?û�U^Ê•©º…ƒ¬15,›I?§?¢ONoGŒ¯Gþ˜$éa.^È 3VÆsõÑ䬸âåoŒcß'‰i¬ uÿ1sŸ‘·ÊW˜Ê;_˜B¥p²üDtœ6ÄéF²Ô¹²í”&Ž 'k>U?öˆõÏ}ðuv8_S©½°[n.ê™ÌÀBý(pP'BWrž{î $žài›txû<÷¸¡r¬ž’ ƒzW¯3Gƒ( PÏÐ…Ù‹çá;…F´º^IíÜ€A¶ ÷-³… »rÒñh^FÕ�­iè˜õϑ۫–Æfé4Ü´¨‡ŠV�ƒvp);ž<ˆ�†°Þ ¸±ß�}nàñéç@bçQé��w—ýiaºÖAÇŸ›ô~™<ѹ ³+NÐËövÔ².…ñ™Í0ªAðçr V�}`é̳xëéKZéògwÅØÞjrçÒ r`Ÿ?Ýï{�ÛÝËJ,#îõ±¬“è}Òuâ!�–XáÊËñ²¼ˆÇO+ÐÊ¥¹�¾Ù ʦ $÷)�f6Àf{S”º1“n9[<Ú ó§ \Ù í놡ȼÊŽKpŸ¾ÞC åBhÐeöÔºxZ ) ywºm´‡2%fÑX4Û°›Æ=y„_rǰ:5†,þ8Ÿ¶އ/ß‚g%tùEšXt^F‡ qâÆëŒ£‚»1&[„÷Ô¢BÇU²æä,ÎVû%TÊ.¸*|ó&0›™‡s[iûÛb|ýá]“x�äTPf¸|/ÖmôÁÆ}ì†æËôXr yúÏz—̬ÁîþlÆøS:h–Ê¡šG?vÙ^ŒÉЂ’‹A0¡÷–ZE¤3V÷þõÜZºuÄoŸÍ‘š?H{ é›×'Ïs¥±Ï£ŸÆ%&Éû&Ùö¦Jê@).ØêO§{jàÓžaÂí‹Cõâa:¯�rUWñÊôïxwö³*'7)�]u/é§;ɽwzXºR„”Èè�rÿJ3R†¹¾|Îá²\¸…=÷üLÊqTÛ­ÁÅ&„V¦§2ÑOâÐZ!N¿öY&ÑuLEmÇÐòe;ÇcÕe¢øþnÌvDË»Uïã•@{X�Ü.Á++éN1,ãÑ@!W¯aœ_/ýªòœú*ôTôo:µ¥–«¥�3AËü%ù°°•FÚ†]|4ÛÉ� ¯Ï…5Wd8ÓÝðÜUä+¨àÃwExøÎŒ½ƒ[éNŒöàeU._'ñ‡g@^q ‘¸y¡êíX»O ³uAõ×åèÝ× Z{¢HùN.œú+Y�9‘Aw|†ù¾ P÷˜78‘_@C§�Ø…M`­ÄK‹$üè‚YÇÐK~ˆM)Þ°Û ÓOï…™~z$¼®ÿšC§üP%4²jÿ’Ãý9lÎý•8/1+ó¢ñ•v5¼7 ì'aŽé8æ/œ{ƤB$J»’ðcÁ œ ÄYc!³-)m$›Ù³ñˆÁIìç]E"<£ð‹‰<çeIÇí]0µ¾ÙMËñ·*Ê~œ•¹K_½ˆ$ýºHQãaPï§Gw…û�È™m äÞçZ°áÀ¦ÌU8*2ŸóBm\l…àÇú?¤wxÇÙ¸ ¿”Ž`v}h~äÂFÓóxÕIEZ­a­±‡¾¯!Óç­Çêº8¢¬„^‘úÄpm;ö,žÎ>™;�Û‘¸zrkíÇÌkƒbÊ|LÃGŸ‡hžàwÚZpª*?Óé{¹tí…yÄèïKÛ€[9ià”}‡yû"�ôëžûÇòÄf×)ôt·@óíâÊǯÃhæ¬ HÊzF%.¶·ª\Åá[øDy>×ù\,z†%`ðd?¸Ž2—Â�àƒ^*HU7�zÍŒ3�À;r­˜¢é‚?Ô#ðFô^ªÃÆÐªYBDþ³­fU�DÓ¸i©�“9ʦXcÅÍ�h¸©ºu¶pG hÕUR¬œ‹ÆI¢ÜS!,Sÿ˜‰…‹(à=¶¨T9.C°±>Qi=èNÞâ~߈7'Â躗¼U—üoÒÚ�¤‹cÆ/óc/N�“: 'í‰H~fÖ58ôâ „Š$A�@:ž˜w¾Ü„yVš4/ß"bj (g3ªò?aN_oÒ·ö:2gó˜'wžâU^{Z㌚ž�T½Òd/QÒgû l>¶‘Å ¿É¹„˜p½�¿õ9µý è�Q |6û59,§ NÉÚ�ñUʧ×c‡ð"'² mº£ú äpàÙeª%<‚u“Âkú‘ôìseO˜÷’Å^‡éÒù­¿Î$ƒL$†ûúà=õ‘*¹œ1ö§¿3~ G|ö,—Væ@¯´4gÛÏ»è>¯D aETÍõ· Çì•ðÚ4Sf�î,îý£A�ÍS¹³ÜEáÒèÜ¢/I!ù;ß ÞÎ|]9ÔG·Ë„£ø¶W4ÿÌtð;ù‰е �ÛŽá¹{Ñ¢-‘Ø'¬ ›r  Zõ¸;’Ë»~¢Z}*ûáÚâvç/=˜, ô°XÐ=ÄRÁVù®£Ö…ã€Í$|Ɇú{™tCL÷¿Þ–Gnoƒàÿ¼È}ÅxÜ|r9Šh¤‘œiv¨òZã~«�´¿*T÷E&úKc›ðjpXœ€a {èéûÃP·D Òõ{É´�’pÅÚ sâ…È ;Òz}+¼i~BïùaòË“Ø]·“±zµ u; çCí¦s8ÛgÝ‚5Ë´ª>½é&Óv�S/¾àW«|Põ¿Åj] ƒ�Ï,ñÓé{X †s’gp…>R¸êF•–’GcIwÛl]�C•¿Ÿ¦íæ‘Wn684å ú6&Ä3© Œx£å4EC8ÛáÖÅ�ä±ñZR9s%Õñ½¥ïl˜L'þXað!º¾k7Š–ÉCMuœù~÷í�WÅKЕ²‡)Ý iGr¯*/¢ÙB{á¼×2¸4‘‹"{UÈ]ÉjPM°"«‡+AÞ;—-±*¤5�ÑÈzyéÁÑÉf¸·úùº‹��úQ0«­j¬äP§f.ç¡Ífü‘œ„Ïäå‰nÍ´¬3¿ôC´ïåu8W�Žëû¨Ë)+<j…Ò<üœ7Ô¼„b¤Y,þwX™,j1‚nÔ…šO«pϪ>(Ì1ÀÞîóú³-ú¯ÔJ¨ï…œæh´Ä–Æ<¿‰g F‰òÑýšk fQÝ©˜¶(‰ åðãˆé%<õõ �¥+¢íàÆmD‡ÔpòÐ×½”>¡àÊk ¤<*zèXUÍÏêÄUjÈ’õÁ°“ß”Mª°Ä.ë#ì¦".&, „½P†ª* ¡^m%¸ä@Ts¡3´p$ü3..À×¢L|lW£õÛ¹6¬ ‹ÜÙ!àœXëUfCÆë#pTq¼×æ3Aƒ¯àÖ§÷ ï:û²qOl"o�íqubfã¬Sü¹Oš*ïŒfC‹?¯ŸªtF«*Ñãäá�ÅX¸l ^[;+ÝáÉÒ™�$·œZ}€â‰ÇÔysêh!ÏÞ·Ò!,!Î7ð’•v´XÑ#Nš ¥µŒ{5iÁ¯TaâÞMî�½q.�h€PálL‰4!î…óÑÂŽÒ½ ˜�‚¼\‹¶ rô¸Š~÷ïrrü;Í� ¤†—qÁÛdç”NJiÀDó:˜³~%M²¹¥¿˜§‚IY,ŠY¤¹™C×aöþB,.n®â>ÞG§ÒP\q yOhaêŸUìЦ…ä÷p8MÑz†ZG÷Aã½ LõJßÙ5U�X”J§}9 FÕ~h’ÇÏY}ª†~3·ƒ þšæ†p4¤œ*ÊPV F’h}yŽËÊg€”Ñ>ìWI göì‚9ß7ãÆc¹d�þ~:ª€…õ§AUJÕšŸ²µãêÜØÂíÙO–T˜w‘ÞêÇÜ+~€MO»Èdô[*Ûú�–¤ã”ÃUœ�‘¡?'â‰Ôå\¼óÍM/€þÜBâ©Ì]‚Ï© �õl’Ãk£pRµ˜~i¾†ÛþÍû¬°KÐ"Àá3?ÍJî¹{]`ÕéäyMFo�‹›ômv@ÎnL,ŒÑ÷Ü�6µµø»< ¬ÏfÏëé<ûÒý»›](ÎéçY�í±“ÔÖ·…,ÌKd4ÏÜÇÉÆ ÖÚ~:Üõ…ioÓ°PñÝ{ôµ;âÏãÖâ anJÛY�žz‚µ½ ˜\8‹™câ¡ÑK™åƒBpºÂÌ×.€ 4¥_j*3ˆÕÝh™í�F…©$ƒÓ@~§äÔÓ]6Ëí=Ù ¿Æ8c:�¤ôéuð¾ƒÚ,ɹ�Ý„Çc.¼pƒ-Ó”C0Ý‚U"q ²6‚Æ›¦ÂÇ”"ˆ i@wµ¯¨pà4@íl�|NŸÇÁÁw;±æâo|}ä"i®ÀËòÿÌÊ–ª-ž÷]|$µº·ÎºGëØ1Žs¹ÖÃSd�O*Ë/Cf[?{l_5Q £Í=GЬ÷¾8RžË9w*åa½npì+Ào÷\˜q¥ž®ñÆOMêô^Ÿ×üG(õç×ÿ84M½K¶FoÊ9_%ÆûW`¤’.DÛþ&Ï7™�ôH¦-]–¾¨ †ò÷3Ùú‹áhÓ¼ëT[¡Òçæ×ïÃæ8�Ãû$ w®aB0¯°‹˜¸Ä’kGR¨ÆC!ª§0@.wéþsô0æÓ'ê3B˜ÀA޹µ¶.à®6@¶¥fãÚèº`„%lÄÊ:Gâ•î@C�Ü‚+§4p¯&ºE‚R^!væNÐC±ÖìþŠò=s#^ïl£Ãýï‰Øõ%´7c»~?q˜s–|Ü–½PcP…QÕ<É–lFñ‘Uð”߉ºv¶ÂÝ¥–tåÁ$ nÿì�ù+2ŸCì©88Ãs}fç’ ÷ñb M`lÁtÿ=Ò¼‚x¦i€æ-íD?»„§1�¿äà‚ qܘצ4”·1z.˜Á¡Ýã÷ɵüÌ@Tt!.K¬*J°bvHøb_4f»vÑôoéø_\¨0$^+ { nÐÕaɇ›�à´ócÛ´�¿w°�{EO„ïFIá|c¶…Ù<ù}GѹóŸS—‚þMKª¤w7ÌÂ…¾.8;åS`½ gº2­¢¸®XÕžlCO›zȈ˜`z÷þ!*ëo‚�ÿuX4 ô/÷îC�ek¾ï(XÂþçw 8â%ÐwÁ ¿ç·ó<ŒZ}pÇ.éRœAzø¿ŸZά!ê]t»x˜—¨’YËŸª'ÔPÅ—¢›Ö{”v´Àq_3½=©æ8€.ú6‹¸/ž+¢÷<ë´#K;&ȈS6oc´w„£ÿayÂrAX ”Lþ›%ßæ1_Ù#ÚD*d’0—5Ø\˜@¶ºS%ÝTÈäñ'�Œð‚~3±½€æFÆú›“§È_%Yx)YFºæGŠS#zŽfùž.JÉb¾õn�ê–pVñuÑ‘„—ŽuxMè%Z‘ôh×4.ï1M¬‚„+¼8þt.gªßy~kÑ„‰�ôáÌL:Vy”æŽ@‡s=cª«ÕQÿ‰7Däa÷@ .û¢ŽÚža¬pœ‘Þe@›:‚æaýùŽÖäਠ«˜¢…ìˆ ÝÛ?Jï¦Ks6} C›†GU#ǧ ÀÖž”Øñ�Š}$Ùy,–Þ¶†ææ5¸aO.Y°)‡Èõ¼¡ÀÙ^\1Öÿ„(J�¥¯\^²Sùžü‚¬×§ªEªx¯r?щâç<Û=̺),`^ôÁŽaxW½�<Ï@�»LL±3 ™…þ¿àìwS9ÒÏæ¹¢{ß à΃èÐŨ¿¹‹è´PV¼«–¬CW&Ý Kß(±‚Ïõýç±bÚ4HRUÐÏB¾é 6‹JIÌJ ÝáXüm„_Y÷�2qEn´oXOdfüÅÇs/£r…Õ×FׯL¡5o‡‰�ó&Œu2Grá#b'p8OŽÛà / áÿÂÚçÀ¾p8V}‰ù­|„1 ¼|EþÍÛ'È=É%'̾’¸`´`hŽ\díöi¡m�uÙç†wFzÐìPt|k£cv:Pkã€ïŒèùQiÊÌ#ÕŽýÄõ‚8¬ò®ÆV¡èÛ9ÔJ–Ÿ„�…0ý¦pªy>qY‰k¢(We’4£#LÉW`�æs交ãd@39"jß:é³CÈ÷äðµnüëTK\vÇa¤û,оÿˆp¶�Ó ŸŒ4n ÞbÈ9÷€\ý± *£„`�Åq|àåWeëËöžçáQm"2MtÓ‰cß¾bçx3{ßÍ‚›BZxú'‰(Dƒøøè( —V%‚”º?ô>£öBú`9Í‘Z“"ÍW¯œ&â!ÓEÔŽ©Aï¢"t°På·`+¾9š€F›å�ÿ¶;QêiÀ*McT0¤ ´†O/Þ¦á5iDgo4ÈDû2=a"�]WFšÿAÖޝçã.8°ÖM¤AIöaºxl=þéf‡ãƒqâõ;lT–ÃE�‹Éû;ô¥¶Z×÷¡v�!¼ 1g-l5II¼¬ˆS§É*É`1‹Ò%’ÉJî8V_ŸWn¬"[3ˆéÆ(LNÇ¢}9ìõïPÿó19û‚z.{KŠæç2é {6¦—ô¼¶À?ÂA¸zïè,¸††s׃ñx�KÐ7ºŒq2A¸HÖ ï'hÁÇÍ»0g¯5Ù”%ÏËŽQ£U1L;gÆ?·…áYqœVïŽ Â… “¤·ÕŽ[©²Ø~�ØŒ÷Ðì:eˆÛ³ ]L7‚„A ,á;"ªí$,s3ÖúÂ.î ²\5‹Üwé'fKhŬÛxù™œ¾N¯òŸœ OŸ<¢zqü ÇSÖ‚Ñ�¬‰ˆ£¯44134•ÝwäFÿë0�RêðÒæHŒtY†‡è…±¨µøiÛŽõx(_Í .r�G¨Ã¹nÜqAµº®3ãîç°Ûx˜y>c5^êÖD-‡ 4Ýs—æhºÓ¨Š2¼ñÐ�¼2 ¡iòŒSÑKÆ£"�\|k×#ž’¨ïHšl¯£QL:�É¿©|ºdzßd“r"ð¤éš—´·„1´{Yílù¢÷9AÖ´­„g²CØøý:6eo0·cr þþ±�íJ:HõæÊ¢Ù-3t=œÀ¬ê=ŽEsD¸²g�a0×N4nÀ:3"e–A/®KÕßzíNš•Rª©Þc $:Ð=³Ò`Ò\möW²Ëçjsæü²‚lG9L™ÞMŽŸ|DJÕ/¢eM&¾Ìt¥;|pýƒFfš¨4žwZe¢¶ØãË-²dy-åÕ¾M×/s…¶=›áùü/¤Âz?ïþL‚ ›ðTÕläÄúÓN—A¶Lð'“›˜LWæü€áozÄÐCºÆ—ç™q´k äÍä…~ã¥�p{ŠèÌ“ä2†êdÚ=–Z�ËdÍvŠ�^ÛTàÐ&ŒÜÂǃ  tÝ+&« ù[ûh³­:œj|AUeÏïá1êý¶xûñ‰mñú9�{-6„C:Ð$ eÃ%³çõ\}ë?Í…%Ýú~*b\…Q\äˆdèñ6Ú#;�ãüˆÊxý¦mr¡hœö–Úü°Ì]jÂ’„O@HÜgr3œaᤠíÖuƒ;ì"ýɃf;«)Ïc¹¨Žq/Ñ{C$«ä¯ŒÿIk‚‘¼ôêàà‚@j~¹ƒ=ÁJ½W´bÈÙDˆÔY�Ëân2"ó©+ç}ÿ5•|W¯€#ƒx°Î¶jÞaÛ8m¤UL ?ì�ÃÙýéh#¾ÿÌ0†5�8‘œÔš ¼ÞרK�žWmO‡÷©átå•$Üû o»Ü%—µÓà�Û),3ƒÕg·aTï6Aà¶+/ƒºÏÜ÷¸d•£(7ùïBЖZvQìüïë-ŠíQ—èÄ}tÚ|ÿ¼9ƒ?d5QJe+™ ŒvNئiWê´Ñ ’c¹-áå>˜›O›¯¹£‘ç6D¯®eû�ä 0ùoÏ2 9WMœÊã2>9<Ô#Œ;†¦è¢¡ ôqˆ‚#ÎhÆàS‡`Ö7OHÚÙŒ®Û_³ WÊÙ7èòÕ~pû|½íwßa+Jr¾–0›m‰å&J§*‡Hg¤<Ù§êGŸ®Ö@Ãö=XÔÑ7>_¥ÇÛƒiÚû)àñÿ—æ˜í�¹ï1ùh<9mv�¶/7$²bY`9õ†<{kŠ=%ìéÍìþKoèYuRx|ô}¸y+4ÖµWqFþã¬=m‹~‚sL¾01¹ú�8¦F?LÏ›Š™¤àÀmô$B[[©¹–8>`£é|µ•�4Âùvm;)+ù†ÓBÙÖ '4ÁÓï´'øžÖNÃ&¹(Ü\îKºMÎäâSàû²ìU¿3 ´àxÓ=fšÝZÆLª”ø^9EÇ}H JÈš¼Vx´é4<¾¿ ÍÞ—¡_þL V1€öcåD^¤Ds¯O•(~Þµˆn¯àÒNßT¸¼?�Ì;a†g„’±UeÆMº2J'1½ð#Û1�»UŒÒìòAb¬ÐI»bOãÃ"_èytÈáB¤Ù„œh�÷èp³.>ÆzìR‡%ƒÂ·PÜë~¶*õB¾Oš�c{ËéÔ ]ö­c´;1ðûº},pòæ6¡öÜ|=–¯N†AÈÔ°€?G3IêÌVR�Am“eᲂóJ;™Ú°áPv<•¤m‹Â¬ä«DBtË4  Y{0ÞóÌ,aôêyP•>;=ÏÖÑÈõÈ/¥ü~é/Ýx:v“HúÓ·ƒÈÏÐánî¢3½;˜ÍUØsC€û°þmðæÕÙtÛ-C[UC¾N‡ÿê•híËPœ¿>IgRq߯'ù@6Wzk„8ç~ƒ�ÛV¶Hs/ÆžGÎÛï„ú�9¬yЏf�Wà1O¦>E|DÑ4„<·SCå 3¹‚ÇV¢åV+VsE)ˆyN¼ýªÎ<0ïYµ|)C�Ë«„““ð¥ã T´{Mgþ^HÏˉp÷/9�W>Â9Ù~xù¢‹ÌœžÎtieæÙΆý› �c;СÌx¦© ¡¦n¸EV Ê¡w«~~û‡¨Žjã˜ðRòýùEpðÿEøq´ô^#Zþi$Ó£ˆäðõ“ô–@®ZMEw€I« $™"CáJÜ*dˆ?µê=±²ù.­ÖƇ¿ª?cØQŒQ°EÓó�ÞGu@!ù·¨mìG æ:âæb0  oÖ¡]F'Üí´¡ 3Ëá#§Ž5�6ƒÉS"$!Y£O%³æŽo©ÓßC°0»šŒ^XB='ˆ‚mT¥Ý _«– [غ{\®n¹…eïíªê.9Ãß ðZ² 6¸»Ò¿•å`ä9ƒZ8`¨½zj’I¡66`É6â¡6YŸ¿tÛÝl2ѱø8Wñ‚ÒnÒp:dóÓ�oñZªg)Á�9õ_æ�ùÞd»ýun ϸ¡0Ÿ#Ч$ÑÅŠ‰Ð%á��.¤ õ8°BžX‡ïÏÈdÿOú°ÛŽ,žL%'�ÃéвLxO€¯ièü�áòŽÇ² ð�„2eïDI<÷õ"”&!IJIIQIËž 3EÊ(;IzŸûzUJ%!ú-팢¢$|ýÿü~÷s�ë<ŽsË">*È»ôå%e”Áasüà†c¢Å*óœøn”Û†7À¢–ÿ75 .Á0­<¸±æx ¨¡Èš'lͳ°Óc5Œ{ë€ýzy²÷×cRój'6Єe±ån=$çÀW¶ÔOp`Zö^¦»:w_OÃŒoH­l¡cx;X ˆÀh°d;͇ »ŽëWRqà>¡ …É”äÏ^IÈNCna׊”áû£‰DH0 ”b»œóq;i8ßA¶:ŠÑ-V�+Gúñå«t+b›Å95³xB=»°o“ Û+y3ÒâÉÚ±ll8ƒÖoO•»mäÖì,ôµ Àm¶EtÞŒRý¶��j$CÛ)7Ä•^¶ÐÐ]­d–ˆ¾i¾šøwæéºL»åza�Ö6(±¡ü¾©�³FWm5‚ßï„ÔrÒí åUœ"oÔM¨’Ìfb*š†còœ®:MºYº7ï†fŸÔVÙHãE„p§… 8W^¡Æ"[qøÝ4PXöšœ(ß��×3¬…W$Î�=Eäv¦qE˜fyÍ ,ñ£géMX  Š)çÈ~%c¢ð/;O܃/3V©ø× ÿ` Z?%aîd!IHcކtc.Ÿ ìUཬ&öJÞ8%ÿ)ŒóìHãÏ*y;�Ë—ëakÜK¦rF5Uì#gÍæ�ò¶ xw©$éU„n÷ Y$[UèM=?Úl}ŽpÿÍ�ñ±F61n¼{¹ cÙKhr>½£Â hK>-ã'Sª.0ï«0 Grjæ‘‹À�´™p1Kžgð³†N·þƒº#-ô—yþ¬»„o¿’¤–Rý` rñë�ÈÄcV÷m(èè&ËÇö�HuDB`I_ ýèÜ‚3«º‰[Ðâ°1?D©�”¸;„^ã_K„Ö[¡AÏ~2oIRû/6O8›5þåF"ËÏ[\� ‡Ðú…-¤í.COiOúÀÜŸ¯w€—S�O1 Œ n�ånÚ7g1ørˆ†Eƒ’ø¸÷ÆÄ7o‚Zk/|¯yÕ¢2è44œ%çK+àãÍÍðf{%ûç™î{ä‰Û…4QcZ=­*©' TA):O‘˜ HhKÄeV2ÀrNSë§wèHå¿î“f qoÂàjÀ0¹~æ1Þ-‘g•2:ÔØ�Ó¤¦ƒÆ–^› þŸÊißjtöã²w:Ÿ°Æ;ÖzÜõþîhj¿‡îé9˜9抧Lø¤¾¦·‰ÃÉÄ<kÔ�Í[ØÑe¹˜;8Ÿîò Ù ¢ º Ê—âcÛ`¼±u?I•ąꟈðLZBéI7-ÒõÌŒ3{©‰î"Ü™>T§x`a%?ƹ~f··9CÅ ¼¾¹›µ3á@Q>7ßC ú–oæ>T>Ž;¬Šè®„éxTXD;€¢T#ÝYGÉ•3Üõ9 ¾#oÍÖ;s&nþ¬CA´?È“ó³^ÐËA ±ËQ øoá¦÷ÛH¸õ:˜õbvz‚ÅÏL6çòaX’ÆÞµÓE·9úÌ>N©³5‘ùF9=�¸ý�:uÕSÕÉ4˜9ÿ$ÖT† å ¸'�±½e€Ÿ-ñ¶Óy:ç…u¨=]Jød6Cè𜩗Gf¯ ¡ºÃš¨uŠÁ –’Ú SxÞCqX�Í£ƒâ ¢ôkÍ—r)Qxuô<j-'£=ƒäÏœ.¸6@ä“}ÈâÀr>—v�íB TäH¦? g½�^œ SûœXãŽA2Êf÷>§Êtyí¼þÏ0ÆÏçˈƒé!˜ú=ž{Þ©†î#étÃËïTÊE²’üpä¿+ô��%í•–!cGÕ&Jñâwk É6NèÎø1ÜK-dá›Ïgéq‘©Ð߸î=Ìe�‹Â±Æ4 göôº ~ê6â2fJè´Þ6ùÇnM4 {Aß®?B‡+É©Ÿ"°P64Û@é×Û¤¦Kjý�Q¾ gé‰ùxÌ÷.nÍMs×ý˜ûÚ�î,ÒB£Û,¤m8‰ÎNëˆ6âÎ17¨\¥'Î7ã„ÓbäññÄ`Õä¸QÏ…€Å« õÐyy}-}I§Žî¥]zàÁbWº#Æ݇“{Ÿî�HßßÖ˜î£�13Aëø*¼r?®]"­ê,Ÿ6Ðn¥ëدa a‡þ�´^u0µ«‡^Æ� (·Ãó‚Nº2�–8­¤Å­3x}[£çJê~Ò޶‡ÀœeB~s Ó{^Œ3.TN/ÑȤs$ìøùå$Ý `‰ÖYytûh XèppÉ(‘ŽÁÇZþxâŽò‹6cÞøáoOM·wPñz7ü/ó·q†èz-p¿¥œ�%tMÎ<Ê�ž„Ïw�°u¡™\­|ÿ�„ ý£¨£-Ǿý=Ï{F‘²Y9Ð)‡ûü�ÀË/ž]ˤöÓ¿›?÷úIWgY@Öù8ühžÏJmC]Ã|¼ÒUa¾mH�÷ßUC,Sî¡ÕÅDÖ’bü&A¼ ›IɱY8Ô›€Å[èùÆ,\u3S�±-k*ÇòƸð@çøAΤ»3úD‘>²p^?Ž›ÄG΄Dǎbsá[zµUÿ»²¥V [ç*aPR•÷›ÉÚfðóö†/f�láûž@Ь+&E`ïÆE¸åÄtžÜ­üqì%¾9]ÍþMi­F¼z�›wC–÷ ÂK(€Yþ�x*r>.»ºn˜à„’Ïʆ¨˜›pl“™z6%>7‘>g¸t[ÎìçŸ^¸Âm3œ8PÆÍ¥óÁÎW�‰k¢ÜB˜>×G¹ ØPÓ¯/K@ë© (ßë…âå†<ƒã¸aO"„> Ьñ¸ö%¾'Ñ{÷‘ sQÎŒ¢Ìüž›°W°ªŸ¾ oŠÅ¡éöqbÔè Ž '©Ù.çÌâ­¨"õ^¸  Â¢÷Á$ì¯âPÛ¬·sþz¾ÕµŸáÃ× ¼#3š‰Ä~C:9_”Ô9 º—yÀ·ÖSÀWÈdñþR 'ÊŒM‡4~*ru&•vej®z°Š;•v{¢ŒE"\ɉÀ+W°±óŠÁ.#’’o8ª¤ÇÎK¡¾�Îcÿ1Sx7;×EùS¿ˆfÍ¥ä«ë"ÚfsœðâFèx–DXñàîÇ)TZ7ÎUs-hú´V2óï%Ã&ù™œÕó<ÉRÓ(ºèÄV�B¨ÏŒF4z±�ìß— Ý5õp¸]˜“9lB|7§ÃÍÐRHÏ¿²�!Ö\ö×/IJú©hì_ºm‚GSа§Õ VîÆKާhUœ‚¼>ÔG5@à¥ø&ö=To(‚‚Ä)Ô+|Ý+ ¥~Ñðx™ j럂•bá¨ôynãߌmµÛé…ÓÍÔop5˜šEÁËÛŸÈêÄ“(ñq^ަÆ]up<ÿ¤jF¶MøïÆzã‰:¾Ê#š»ø@pæÌY”K¯¼7$üWc0Ü ÅNˆÓb-\­DiÛßDøâûƒF¯©tY|rµŠ™UÆM‹viv±41êwžùbù ”ý³É4ßà[ÒBcwš�ô©VÜ3xË— â­·O‰ÿhRçÜÓÓ…•oá§B“¹¿&Œ¬Â lÄÌWäÏ—_Õ‹ÂÑUÆÇ›ÑÕ[O>D~¶Ÿ„_ygIrÕ¬Sí£ÜŽÝØì\€Nœ§OråñÇRGÒé–Únèå]D�þ¸|,žÕÞ[Ïpn!ŸÀèÅZX³Iw\ª“þmxý~)»In¿˜Ýë×€­Õ|ºh† }s¨ì™ÆÉrUà™ žÄÕqš˜f¦‹‡ÿ®a£³ôx²N¿pËo+sÕ$—xKÑ{s ˆÂBa�y øô17Htì¥%î¤2—Â9©y ãpÊù8^®ÍL¢{"Ƽ·G8_ˆîxòX?ëåNWK(ã4i7ˆ«*�¥÷WcÆ•¥À«—Âéîv(ßwÕŽ\"õ…H–—ö’óóä×X �B´ðìŸCÀ7Å„Œ|YKvÿM1?Ÿs &ê,‘,…E©Ÿ¨£x(|ck‘w‚·å,ˆ„‡ÓM^X;dÈx c÷hÊv�^†ú3eyšËC!_R£ä¶ãc&šµG±Á4 ·%‘�ô”G7Õûú�Ù�­L3ï$Dµ¾%Ãg’ÁV±¹’ìa¯ÂñÏ5d‹ë+Ú:~ oÜ wÉ@�œî‹_ ;Î| ª Ù×W˜ÚkÁkn�â<íß�ÕÁãï›a¸­å'«qJ�]®?£êmPOl#TY¹ïÞÄj½¹|6ì^Æ’*MüfG_ý:Ûf}ƒ”ÍðÎ<…U¦‚ðdî.ø¬ž ¾NCˆK%ù¶¬–ÖoW…Øú ¸AP�Y§ü2ߎ³õ|ƒÌ„I 5óùI|ÌCð£÷I²'WþЧ‡îÂzÕŰ£© ÇvŠRWý[t¦•ÊÞfÅÞÞÃ.…õàf72Ëp€<»aЫ֬Åíóž3©uØ.RKŸÝ@ ¦`±)Ê4uÒݵ…4AÖ?|z!‚¯o‡2t oÃ÷ƒÏpꞯdNÈtž`¬ÞÚø�ŽÊ•ÓÖE�ÌX±Ìz8NW‡¯!‘^;ȶ™^äÂøüå¡‚•‡saQ ‹ oaû?�o1jžjCúUÐ1hGßíty�oä‹õQ©%òŽZ�/—iÆ¢:ÆÕê)t’\’’ø�;Mýä“­:îPyoîþ®˜ê¦–‘ëãš«'̳Úü�nš—�ƒÇgƒEZ h;ƒ[§ p¶ožÂ—ÍÇk�ÔðCÑvQó(ú3\Ïh≴ª 1iwAÐöGP´ç2Ù8¿DB@GxHÊ p”>|ÄKûD€Ÿ£‡«<’@W×S.ˆq|¾­Àk‡'±ÿˆÒÃDjS<Žgb|ì *±ç4ñÈ݃­Ú«±îv&\û5…À¢?"¼µÚi„k§†)¼Å0]¿Ôã‘�Mè¸C”÷Mß›œòÉ�MfhðßJú’”Œ4J‘Ÿ-Ù¸ÅIV›öáÛ“Oi”¤#Þ�WMôŸEÿ†óLŠÒ7Rq™�3$hßÛ§\©½Fè»/äÜ·¡éÀtXÚÏ}NʈóÄF;aö~S¤&›´á?³|”u؉MŸÁ?»~Wí£¯Ñƒ â6ú<¼¾¸æ€Î„ÇnŸž˜�.yÔµP›Ó W†½^W‰¾õ},ÙÀGÞ5ŸÃ„OÓ8ùßnø½…cŸ¢ÕßvÐòz!&NRœÃ¿v|¹qŠÈô¸áÛÒÝøˆ (ôaÞˆ!(ó»±xü)1�XÆ^ý›nžàަOÇ®rkr>& u3rÐ^»džâÜg@ß}•ëŽO ·;�Í|‘ôÏ�’ (8 §ÚzB{…>�Úþœís5Ç áå8ôÔ…ìÙšŒ®ÏrÑ'ìΕa·ö¦‚v� ¤ìe[Ïï%Íãsàwô_8÷õ*˜1Á†¿ØKNÕnÄ|í|°n:G®´›aÂÏ¿tµÒ{þú‡--ŠÖÔ1;?¶¡í—XÒYÍÁs)˜ŽÇ�Hþ ÊVd�´Á¡ÿ¤Ÿãé�Þ�Æ,½7±Šk_•ƒÇÜt!@w)4 ÇÓ·×FY—ô`ü˜ð�YØ‚_~­¿µRÀßáFïí’Çøÿ|Qµq+¦³³ah¼t•‰{ÈŸè�ïOÅeoz#±^¾|€ÛÁ75“°ôößG}õ³Øo}Õ*LP ô0ç�Ú·¯¬sX4:¥ùàs;O¼È-±xzÄ^ ûdFi½Œ4v»ü ^íß™}E’ùÐ&χ¤,Ñ"¹�BŒW_2 Ûš)wÔà~|*Ûò'”&wÄâV…øŸá�ˆ¤£[Ýáù¼›Ôíµª´`íD+Ùôz6ñÿlí0çtÉþî ÔÇaJÅnÛ3F+5Ú 0¿ ^s2ÈÃBð�Ç=‚åX¹ûv˜NÅö ŠøË—à Ïu<áÈ$\u°ˆrïm„¶¥4l\�„㋜[Ä{Y?Ñ™MÝ–æ‚÷û#xøƒ|Œ»M„¿ì»©¾ž°«ÿØ€3Šƒ’k¤F¤�‰­ICá§ç`šŠe\F©Ô|dìöp³ý/Ó7^¥"i‡E‹ÜPyž0ª$�„ÒqWÒ²èqM^†'O*ÂrÝ�Ø�ç‚:sí™ÄÐHNRÇÿÒ¥µжÔÒ“$¬Žb–sµ:œMžQ¨z*Õ­¤qÎv-ô¹3FtwÖŸ¿×/ž °ëP"èÎ˜Ž’Çº nÙ I[րΠºp'y‚´Ë¾gnÒ®sQ Cn*¼M’¦Ð³$�Ýë¹qQ$ƒÞ½‚oÊâ1«j>‰tŸÃ{>/v¬>„1/ãàjd;3q0ÕñPöÐ�”XôPþ†õ°vè=ûŸ×bÐú)ÉZ«æÀ@sò›$CÿA{¼D·ÉžÀsûÌa࣠üÞ9ÄO¦˜žÓÇJÏ øDLèàªÌÃhäǹyº0,/Ë9WxšXïydfÄê^KFù™nà!o �Ö¥Ô?0ƒggÐ6™z,!âÇy]íàùµ-mö±ŸV?Â9_W€Xy'ÎÞêA¦�›@ŸÁ|­áÐZÀ%M­°àzÙ¸Ô”9Ø/Ћ37W~*¡fKpÈ,‚.²Q…®ÌdÈ>zãaªÎTÒ¯” M‡+ñÚNg< `È ŠZ€¦u›H Ÿê”®%%·2¨gqÙ_W�yáqæ¢jŒå(ës¢öüÝï?D޵zÁI•Cê-€Ê¯daÍülô0jaç Àþh{óãÌÙ2ƒîèûŒ…·Œ!ãOζJ€i}túòr ÝRƺI$à›˜oPÄyLjgžÙç‚Ëxl¦ KkcÛÃøýú$«é÷Ùd6]b„qŸ�W*[pÎå[·O=¢#û`Í�p²)z?¼6L#Jîëб2…þÑÎeÛ$ð°‹ô]™EuGáSwIâ>ÐåKY╵Sã¶ COÁ¸Ò"j3ûÉž†³y‰Ø›•ƒb÷…‘�Œ†r­r˜Ê'GÀ…w”®Þµ¡g9&K_ŽÆ—KF±¿‘´5`)B´¯ €Ž¬,ˆ¤&ÃÞ˜=TÀk! ‹ @o…ž�Œ¸ò÷êÙÅs‘>Žö%¡‹ÚGªœ=A—Š—Àñ8COÅY¿;i_/3ªæÍÿxO }Ráí‚B‰@žU 8DÓiïÛÙ.+Ð(âBô¬-ôÛøj‹Í–^ÌAkK@ãt²´f£=«œ>±-�á¦pÜ>3OlŽ$½Âç¸Ö¾ä㎭è7%�hYìf!¨�†[—¢¾j1Ý0G~OËUÕUôZÿct0¡…óŒñ43¶{¶[ù5Ÿ2×3`éÍ(T쟀pŸpÆ_i6Êü%rUYtEÞèpyGŒ¨Ï4$IænÔ`óš<Î�Û"}4ã€8'ï± òj®3¯Fè%¿;04´ ŸÜÛÇέ0ežö~'•&g0Jµ�­w~¦g×aö×àõ¬‡¾?²‹Èùí‚ ±å$§Y„g®NS¨`œœ)MÃôÝ�|ú  ¬ÇÍmS�°9K¢Ý¬íÄÚ¡ Їm‰çp<ûñr3+¾F�Á.¦ðü�Îõ†¯çý!B~˜Ùôªœµ]‡¯’#¹bpß!†^%Ó’2d¼ß 25ÈÀ±=¸lC|×.&çŽRé¾8æ”ÄB(Ø$[7‰I-ˆ)/ÃÚ�Vbj¡É¬Œ�"{ƒÁ¬Àýúbô”&5‰;€}ô€ë€çë®�–x"d|[‰«çg°WP?Án0�+ËÅájÎ>µc!O+‘ø%»â¹Ó[I³Ö9&,ñ"¨IÊŸÚO„ÝÿŠÙ­5›êøÚÀé²x7< �fa�ä üÜ‚îü³ï­Täý® ^�ÌÈͤ ×WS¿)‘ðÌ,Ë+ãAqánÒÕÛA¦LꂆØ&øíBž»�‰Ðq*²]–³w…µÒZ[©ûb)X_Ž?ÄÓÁà„0æ¾Þ€±ïø‰Çø9ÐÿÍÂY úHÛÅã—§e¡L´ è]a®ÆlHV5èüÊ6&¨ÿ5d{Òɾ¿dL£†ÑªÃèÙ–x³æônwD—ñÇÔò‰û08Ö­ý·ð÷àé7ÑH5‚ü×ÖAÖªo2Mƒ¼�ÈBóÜSLyÊ,< ~šÆy�¹°‚´?Q$J´`Ép Ú5àîHAN�Ê%Ú=°ŒÖD]&¡Yÿ¬î7‘é�Á5�ЏéL/}¶{:šn™Fv>ÙI%ªÎÁÍ‘ø4*Ë+‘ûŽ—`Ç•Ç4ûL3Óêð—–Û™ܳŒ¶Í0Ùä´ûãQ³mÜè¾�T4ÌÆb§À}úW+wÊ€ƒq½¸¿·‡�ƒµ|XçúŽu~Ù‰åóKéÄ@ N3€wÕ@{ÛZŽ€©f9¸ûþ=TnAky#໑nqñ¸0¾VЃ»WE᪮#­õ´‡Iè¶í8¶A‘ÆÄѲíᩤ*yRÚ�=^—àä—åæn¬Ç´`Ò}¬ˆˆÙ%3ÓLúåW'Ú_/ƒËv"ô•ÙYˆOµÝýû°ÝáC7飖B8èþQ¶V,ÄâÝ%ÚR_‰…ŽJœýY(8K޳TÙ™ÙxMµ®,!� p`c0•zpÅæ”no#º+áÕ~a¦pË)²9¢€TùF-k±».WS¿²Y0,™ÌHçB]–(p+‘üzK=»­QXï"è6^`M ?RÙ{Ç©JŽ?�¹¾È­°£v©7©m-?ì¤ÔX* † î�„¯.„<–!wësàÞÉ|fŽ·)ZÈeÂ¥+Ðk›^kò®ÎVFó•æjçQóóÈM?Š1ö°ï÷ë~ø�ä¼ÉÀâ77Ñ¾Ä Ó¬�b�× •|~³ýhùŽž�µ J­—ßÇ-¶¹à¸:B/HCgÑnêí"Mf…Í…d­¬¿¤&çéX Õû|}ÈÒЇ&·J˜Å„cÚ�UÎz]ÂDRäphPse ±0'@á5�`/÷ÍàšU“ðÚ»U'A (X¼”ƒ·k�ñ•¹½¸{ ©­Ù†%}õT­ÝL§p©iø˜_8Lo¤¼§eÒ«©Tõ:Ì2ÓÁ« \ÔJ™ÇÄÙ÷2ºëѹ°UL%ßL1äÜvÆR. Ü‹K©Åívüþ–Gg¹Æ‚[Üøc[#(Þ›s�/bÚ� ª‘7•=t±ƒ6moþòÜw‹šcZÈóÚÇ®p“…Úp+Ö � <œŸ Ó ŠI®J=p�žÄåùgÝà�dƇvb+ꈊ­Éhê ô�\OÖôòvõè¶ÿÎlšøF…)×Þ€±Ÿs@þñc ®úàÉvà„¹, 3)¤ë²&Š–ÆÒ�3÷¢¾Þø½{!^ùöŒ<¬� M§:ˆÈÅ%¸[p#&{EA›Y j¸žbÖÜ×çÛé +•àð‹(ø}1‡ ã™+¿v1¦>ÝäkS ‰Þ¤Ë¯OãŽW²kv¡ƒËzú3Z?¿‘`»‹Qà§ .dÐwÉ"Ü|6�Yl­ IÒ¢D&x¾‘G/=7Ã,õ�˜çY‡ãTÀ#É.W€ž.°¾ �ÄÄcˆH¶N&“ñô&h9äEÒ¾¦SmùIr)Ì€ç�#‚D):íQéO2ÌózNëL/Â1NsX-.'íÄo3µèÄ  h¹ä™[¾XKõÖ¿"]ñ›©q[ =®�ßê�µÞ ‘–èÜ:Í 1IZWªN§pnïJD‰ÒçlÒ�4p—º�!—·Ð''²°På1sÿF+d¬d³�Rɵë^ðÙBc�oãvv¬$ðÐ�-±Bß³ï;é± FKñ΢eøÝ|!\“ˆ¡JÏQôFœÛ(;Ú´©ç{~|ø¬‰\žHåc>�#Ãä¹àXë�CÝ /2޽þx(ŽԳ䱙½ þwÞ“#GÈÞ2+8èeDžf â§õÔG^|ïÎÏŸÚp#cß]eªòpØZs~ƒé¿¢ ™%ƒNµ®xf—öœx¶7Iÿ›ŸÔÜ †œ='�ë¼�‘›µÜN®@›é²Lì3+â¹£–¶Oºbÿx5:ù$A\ã¨x˜Šby�Güɦ¦Õp·q+ýû#]NS‡u×aå}ÐZfH]Ë%8-ëž±7+Ž¢†}!5^¥I;~QJ×£ÕÖtí¯GÔäÑ3fï¿�޷ІÝñqðØ7ൠiµ"=Nƒt~÷rZòŸ¬Ð¢‹v¢t÷]ª-¼lWkâéBZµV½Ê»ë|’/ƒ{A™…{V#™hU#Ì kÜýÒÌœÖ�pŒ.ÔÀÕ Â¬»ò>ÊѦv´°j1IzJ~•¼#bêùXÿD‹…:ð£äRˆý–3:ÆÉ/°„¤[ïPþ©%[ßy›î!Û~-!9SøØ¢¹aìïN[‹Îé.DÊáÞu)¡Ý«¾YLI¯†#kg�%~!¦¨<;Þ/þH«š3ÀúD.dj[Â�öÃdó¯tôã'Ô|ZÂ<·{Ë4°¿¸æˆzSÎ�‰G©à ÷›’OZ�òÌ[NcÂ×PfTϦìsÄ,KTÖÒÈy¶tVÉJìqÓµ¸%[Î.Q—E/î0ÏÆñãT#QŒø'ë‰÷¸$U—8}XE#ûšÉ©æ:Ùæ‹ {àØiá¦öç÷�m'̾]I–¶&ÃXÂFŒ+“„.;%X Ã#ûe€æ5Ÿ‚sÆ2 C_¸ò¡¶†T…†á€â#öõ‘DfÑ8éÜIàŽñ¿Î’?jÞú¡Ê"yÓœro:\Ÿ¤Kn¾aSß.@e^ÍÕQ£�Ë"ð^O4ÜÍuÁûjj ùJûs®�i“9h -E¿qT0øq9”ž52�!�ó­ÀG)²îKÁõ«lOÐi¨æ»ˆ>º÷Hu•-º”Ï¥Sn?$O§pÚÅŠ¡M?GÍuáoe3U,š{éæS&rÝGòPìu\íÏL¼  mnæ‘�žà&�Ÿ”åVÐì阚»nxà¾,x4¨C[µ/Þ�­1'‡�ea6Vˆ ÑÝRàãZJÒf6 ÎVCгVcÍïäAòüÄxÑ3òv‘;rŽ æ‰’ÿ†sØÓû¿ÐŠé óÉ�®Ùºº»\a� ¼ôE¶|Ì‚ ÙZRÕD¼eÄy=WIN÷Ç\†-+j`“´¿@„ >ïòËÌHÛ?ã­ÂIîîpzÙÓŸ­øHTeäðït#²øL&4þVƒ¡[~¡ƒÆê„àÈtLÞe |»¡çÙN,ûõ˜ª%§Ó.» ò-0 …öг�pÃÉQꢰ?š…Úåè,¥kØÌÉÚZúþxvé^¦þM+|Þ±‚¹S𯯠¶“µ¶f´÷�/|Ÿi j�ÖdcyF…Ú`ôÅzF"ì¼\ÈO†ブë4çjì~íBµª'Ù¢UèÛM¯6¥³7àÆçÝ”×9L-ý‡VÐÿÆÝþGUL=Ø–‹ÒP¡Až„fÃÄ€³ý�D냥4ô2bg ëAÖ|Ù*R$-IæÏ]@×O‹$ ¼yÕF!/T§Îê§1ö8 Ó4CžAH "U…8×4B(šØ”uÐ…ã—pÛ,Eîì¡5¡üpÔ�-©gh±Z ³ÊÞR‹§6dì÷Qò:Y«ÿKƉ_n„‡q´«>€ÌäÆ1ùŒ&¸öÿA³ðûÄ@˜�NÁºÇÏFR¦Y6½Çö‡Q%x9°yÿ Ð�¼KŸ=¯!ùñ¨U6Ú^IÂö^Á�k´á¾Ð}zP?nņB—½ ^¹w�Œú™i›ixÀù ºo3ƒ¾ec¬„Ð0½ÌùÍ\ÖÂäÀ\ò÷lÑzx�­i»NÞõ¶‘(5/öi7� �Ša�Ž!¢;¾Ó8˜Ž�ó8Äb(.IÑ…Jø!³•<äu@—¢Ì/mħãR&PM—MŸ$I&5Drï ÞÛü-Èi™vÜ_vJ5Rí†ïdãIi*1ãºÅ�»ð÷®ï̶€;èÔýŒv¸Ü_.3ê2à]‘;˜ýTÂ~;è3¿ v¤�Ž’ó„Q"9¦ÿÑâàXä½L`»ÍJ±­ú$½§_ B!LRš>Ûg†'nßttÑe\ÏŸbuã­È”{a`ºµ—èÍ~HÃ>YÑ—ï“i"o.ìØØŠu4¯Õüd—°aIŽ3dFOgO Ð+g#0@/�.ÎIã–j–Ñ´Sð®[$ž«`Ž6’KêDü­-Ú]œ�Dø}›Å�¨£O‰ñÄ:Ò½ó­E^viæä!YqŠ Ë…dÿÏ$h^ �оŜ›LïiC¬ÙœxðNèÉߦFÎ;0W$�LÌÒŸÍtiü5Rÿcä_œ¤¢·lHœòA<ª )µäÃô-¤Ñ;ŸV䞀¥¹‰p`Ñ�´=GCXi;ÿ—ŸzGP'î1›²?‘>_M%’|ÉK�RÌÐWø÷½ �éžG÷*¹Âé‚íøBØKÅ qçx |³•{žÀ¥² uí?¼è¸#‹Îbè·­°#|%õK æYv¢”ïGZ³ô*ž Žíã¥Píg ÖÓKpaÞTHQ� M·Å¡*Ò�Ľ$«fg²Q {áüaâ¶‘¬ ? €Ü¢boîaýÏD‹�GkÉax<‹wboBv!×b¬íl¼ô�y¦gè„ól²ô™ gH=b2i¹K0ΓÛLJ‹â‡¼TlèÓ¢Q +aåQ¸Ó¡�Ü uˆÝgƒ:çÂp¶V%sæš3­Út‡(>ÐBzé+1Çh�Š¥ciûþq‰ãÅu`÷Ï™O9|£}v›‰¹O%{wýWUYJï÷¨áælCX×5BWíúIjwhdÓÉ3ù³¼¯aƒ·'ãðö"µ¶ÀÛ ÉÄ[XýÔWrý½d`Þ’Ëøß¯pX»Ñ€ÕØŒUoC`Ò¯ +Oÿ1¯´l$I/›Ée`,0…—ŸÝýf¢æ§bÅG‹WûW¢Œæ*²ÅƒT-æã\2ùKeg?£›§&�‡z7™æ¦k5Ó@éØatÌ‹ÁÌë¯PcËFzkýØç Nb:ù‘3ýÝ1êƒÓnÒíkâñè©*<‹’;¥ZìèÌv¬;�ýJ–xE߯ó3Á—zcOØÓ¾�Ÿô hByæe�Ò¼Xê|ÓdŽÌk»·äA÷lΗ"q9¿Vdd‘׫ŒÑb²šDNÞA“¸'àñM‡•©Ü 6ßÊ"pv&}¦˜“;Bê }ÖËËšq [÷Šã×'Ø×;�º·/æ²0º±#MlÑÕRÆW—˜™„lуÁïk�¸)@Î� HÚ é?÷ƒü‹V’#ñ‘�%ÁEw-œjHhüÞ<6õš!\,™CÌNÇÀ¡²z²êT9yýð¶êvXôYAø{I̾ =cÑã^Æ™´Yä„–²;.ÕГ;Nƒ~š6r.Ðî�¿èžäãäL·>^OB�'K0nñ&jÍz³¿cd¡(:€Z~½†s†õ`Øä©Î¿ xÝž™7¼’ººô€è@ÙÜŒ"ÅϾÿ–ã;Ãø �ðjÚ5²~ù ¼,†f‰ò"³d¹>õ›a‰a=À”xúâŒ>Ö�Ý)hÝù’NnØ‹?� såy֑ìù&µIàP›C–éMƒ®'ÀÖxÏ +Ôýè)•&º%hYbr$N·‘Hæ=÷9''ÙÛ6�ÐÁ÷_>;JE_�À¢f5ªÜ� wã‘Ä&°µ€U‹¯‚â"C=?IZ}waýÙ¼Wcæ`¿ë�K)¤´8™ˆlP�™Þòøö'ºqûƒ³‰ÿ\SR&í‰kîDz÷gK�#·ãIò ^?Od‡ºÙw†Íÿ°?œ mq ÉÖ®Èzaÿ’õùjµÁÂÌX÷¯÷ôPÉ噤äq ®7$"·)<š~*‹þ»‚å'ü›Ì»@ADÓ´þZBÆÀ z)ð9]`²†vÆÿ"Kß(a![x/_J®Ÿ3¢#k>Qµ•<Øí£÷ïíÆ·[‹Ø©E¯àêuO S9)‹Í1Dê ¼ÌCÿfsºEô1) ˆÆ¥³è˜Xþ½ÞN�ôöCx–ä8ܦó‚RIƒ ý,÷ Fu?’¥¦ÂT9*Ú¦d#-²efL| ËÈ“Î1ÆéÚò!ð$®ù×XA÷q¿±ögEhVa$*¾Šíïíé–œH´ú“7)£ZË~òD] tÔv�5ÒSѦªÏ"d§/á^¾�^žyè{4™läËCS™XªA6¢÷Ÿ—ddOåm G§Õ¶Ð}$±)šhI–PfŒÈl�ï5QØY©ƒÕ¦nD°Ó„«’Aw½È(%Êè–} cêAWVeúGè⸠®Æ &;€RQŽÐ�4Ø”r‡òæÀÒÅ’èü8ÆÞm gìÁèO‘à£tɦ=س_ú®¤¢Š¯0•\ÑÇÞVsÀ°·aÄ®†¤Í €øâ@"_“ œÞI2H“àK¼nãMÅ3-*8ŽXåžÔ²Ⱦ»ßKÎsæ¡|ͦÔ>ÕØŒòÛM™¿ïÒ:gIŠôjhþæÂúnˆ�ûÙ–xÅÒ6:ŠÒø!c({WM‹U¹D­qõç`­Êtîœ6{Öÿßlw»ÊCÌ =”oè!I·ÿq7¦“þâüc@ïÔH“Äσÿ< )ï_ªa2ìm±‰w…Û^ Û¤Ò›¿®•—é.Å£ŸÌQ.">(|ÃzS¼Ù$6Fd’ê©t Qíó_öÓ-Ï9R %ôØ"lù8ç9ãÕ‹bDMÊ~4‡")•êïÄ»­1½ ‡š¿2aÀR ]¹ll–Ëášiè1[�U-¼é¯…ãeϬơÎ#SÄ%%TRÅêÖ `mY5ýÿ-¸Ù?Ï��Á³ µÉ'ÅXèrˆJ’KÔzæ%å'¾fŸ�C<Éÿ«3â²0ç¢ +¬Â÷NSøšËN²ÏÑÆ:]gŠøi.fn2b�%¡à‘Ž0þCª Lµãê«ÆØçà@[3þ„¡s=�QoÒ0�ýÔ&ñÈÆ‹‘j‚4WÎA#‹pÚ•QîŽN¶›ÈaÂï†O ì³D&|í‰çQ§8ÇUƒKM×Bîz3úxÖm|Às]~$×ílØc‡ÙoEÜ7íç¶)¡ó}ñ®¥zÍë/ØDn!ÏL‡ßf’¨¨Ta²Ç‡¼'ÿŒ{ ,Øîä|¶_�.Y|OîcÀÒbuLØüO\X;…û#5ej5hÛ�ö/YÂðá:ÖäðÒÆ?yª¯Gî0Åo—¡éõõhW^ ¡!šl\ç‹#`’V4[Íè†[WÃ’Žï¸½kDÔm§ ¡Ú¨÷áê_-Åž…ÿâ̸Ø;ã¶g“¯µ¬èå�1›�pÛ˼•u¢Å`Bpo°'I[â1¢Ê•cŠxטV«ÓÄ~í<Ác«UåÞÑù´¬ôìO–°ÙGNNXȆJúô—‡5Fîsçtñ;˜ã¯Ï¼i´ã)§æ~‚ôËI¬øÆŒ½W¾ Ïû½âSùž–h‡úÕ¶4fy&LÜÈúÛš¡Äs«N¼‚¥�édzZ²Ü–Õ(=)åž’bávÓvO Æüm»11íï�vãmj©ÍÉßÇÄrbÁVñF¼›àY A¯ÍÔD=à qÊ‹y ›­$�ÜÚ*�ÅUçí¹O¡›{–cð»|á~V%U?V�Í?WÉ=¯Ðì§·¤!ÉÇ|­ ÂØ¬ÇòÅ”—G¬æÐehe¬ÏÐ![/c›ò{˜¿ùn²Ç3Ý>¸ûT)8T‰fÛvPRƒï¨Ö�÷5RVzâ*zÈAÿq¹Ö„†rË\ ô×g—€/ÐdŽç,‚0-ÏŽéX«˜šwšPÝ“¿Jð›z3¾ <›Fï µjd]„ϣǡ䲌ëjþÁm½?Sð#þÁß?XK0x°�ç$)²ÝŲ¯‚°kŠ|Ûj¢ìÖJÈÓZÌ—Û‚yù¬J<à]:êL1Ú¼¯Kß8ÿ@ÙeYæîEšµïÈmMµX¿ð?¸¤[�‹|©å^!š/Í£Ã�¸«ã$ºyqÖÈj>@F[,šp“á12¼Ô M[øoPK-!É`tÿÿÿÿÿÿÿÿ arr_2.npy€�Nœ™÷?Ðï×ÇCVF¥™%¥�÷9ZJHHE‘�JJ…––�]F! -Äû*­Oƒv‘ÒÖD)…êîû/Ü×o×ùå:�ë:ç¼^ÏÇ•é2{†«—D¯µ½6/ 5¶Ñ5[›ê/^êâ»2tQàÿâSý–‡þ‹‡-õ[øo?lÌ8S]K‹QVÃMu7ëþ¿VŸêwöŸù+ü=AA?�ââï!è±]§ú“¹¯Ø½‹ GèñÏkøµ¯Z>{O¢ðFÙñ’o÷ÜßGû¦Êá&lÁoûå™›Þ0ÌÁÏJáÓ�NTg�cö²Ü«™ÂêÆGbXÙkš),¬§ñ*ßý”ûYw5 cm_= [äCÕÓŠIIû5v›fD[·¥øÐï==>¹Û:àvO%:k© g]¤!r,šÜnÐ(ì¼ZÅ…þ�ì¬q™WuR{ÙYºµs úܱÁG�üF_ƒû,Nã)2ÓXïûQî2”¹Umí…WãŠ1â]‰xùb_îìÝ Gô8€³Ã²ì¿òê@ãµP§BìI€¡¹’<úhþT÷á´o‹q¾°‡LF:ä€�|ø q€®*JÇ·Tœ´a¢]¥Å^´ƒJvâ‘Ø“´ËÏ¥,Û†Ûzb›u Ž~¬@ëšUªãS—áëí%u“É,S•õ{ï`?“hR¹êŒOsåiä¤uØ>£’V,ŸKWaK ,ûlM±.µ—eš‹ÍÓ{ñpïT:¾H‡©eГöpxß?ýý¿ÀO·$úy³�Œ£§I�ØòуT�æ-«úñ‘”1âª�Z0¶è�æ{p2pÉüü móEó& ]™Ã×µ‚ñšì0^¤3_HÍãö°DŠ\¼†KîeöHñš^ø« ûq xŒU¶{þ~5Ú\º&Tÿ¥1•sñ¡÷2rý]Tµ{ÂGÒßvŒO-.^ r¡7Õªbâ”%|!äíì×(FžRào/ÿ’Ãäþp²¾�íÛSàu¾/v’ìÎc8/ßLŒ•ÿ½ß<ÄʬòÒTP,Ìçû½q¶ÙÖ¯h«d2MìV¿ø,|o3ލ›¢ƒ·#}«Áçý[ «Ú=îÊaÀ±bÐ>z o†;ƒÊB –¥ óÐŽl¼krŸoÌSA†µ¸Ãï9fZ?•Ü¥T}æÄyÄÅóƱC])¦¤"8ìdýþEèÙ鸴£/¤8 åÌñRÊqø%ô¢±«©ð¸è% É; W6�#Åuk°Ð;–kºòè¾¢EÜ*™x˜VÝy@³ç+óÑ9{H£¹–ïÞÔ©ÖY£ šÖù¹ì&ž-3è™2¤DãÐ ›±OV]qã îÒû3}ªÕ|àQíþU²Ù3`jv6ßh2㪄Ÿdn»—ªŒÀÙô�OÓ ²e Kf:Ò�®¸jcº˜<³’C•üà꨻¶OÖÙ“�v5î±®Æù:¨Ó–†¢{‹9.| ç^Œa¹©ÊÜ/ÈŸŸ)ìä%¢½bÁ©3‚–þ>ÊË[FâáCgéÙ”X¼ÔqÕöXYx lqn›$]öUìäÒeÁ˜’)�Á“kq�ûc:ùþ2»6\™?ΊGž¦Þ™o„ #KðuÓ-°Ý·³ß\ ©îVºy ƒÆ�\›ò)¦ÕUÚ«Qf¬'ÍøcÈú´Ð…©“1ëGŒ›ðV{"ŠµÎ¶Ø¬ZiËkܦòCIaÓIœVýš—Ž³Z=ðøÀå°ÕD�ÅŒá îoµÊ»Ôð:޽J xUO»5U=4áÙLnì“�ê=Ø=ʆ?œÛ‚ç×-çŸÎ®´àåGÙ•Šhn΃Ÿ<�C£›Å{Ö�ÜubœÐ·8'¬àæ ,¾HI7Ç¢Y€ ßt¿Og¨aûF34¿Uor áˆúwÜ•}¼ ÿÂ�ñ¬°­Ö5ÅAÝÙœmXN}/ü‹Êx±½™Ç)Ñ­áJ¼âN¹‡a×€axÒ$—'m¬£àQ¥Ð­êÀ[û?¿ ÉÍ×ÁY3Ú6þý§§@ü;Ïî‹ç:gIö¶ÝÀ˾Êbý€eœ§Þ ëp—ÅB8µÖˆN¯._ÌG漂ÓqM�Ðû£­ÚËtèÿ#„¯ë�Á¤¿{Iûû@¬J.¼[–3RÓ Ô|=Wì+ÞX ü¨ªCÿT9Hì$³ÍÔ¹ùÝÖ^�‹°áù¼;`>ê®R…àÏi´¨SJ|”í‡!ÊgxÅ‘.«·‚ô¡Qm*êH�¦·48fûwš¦³�³%—ã½è×`ä2�KÒ|X·ù+Lè�©%©àódv¾ú*œŸ A¯díRº¥Hí9 ºõ(1¯–#9•†]ñiÉx|=÷ hÎ%ç&Czmã g*‹à«âþÊóÏæÐc�ùرiîvJcýbY»�mñ÷ºî©|@mSnâÈÌraË»›‚ÆÓ3ä?, ¨Ï=¨[ò <] JB§Ê~Á»Æ1øÞl=KŒ¶å³#°Út]¬š]" þ¯/÷‹:Npg­Ø‚®,õ‹ö|[„‹÷ñíí;ù½ù>›¬ûÓÙc³k.²ÇêÄch£~Zx´È‘}½¯ã~›ï l–$“k*T¯žƒÇ^ÇŠ…*IÂÔÇÿáïÊ Ž{*âÕªÕ¨gæŠÊ·ô`æO~4qÆ”&²¢Çœå«Í«Sëñê¨1ÞÛ§FWbQ»<×L‹„ ŸÆŠ}e}ѧiçúÍáCo¸.°Œª^g‘þôFñø SU~‰®P;b¿oy^ñ›Ño›"=UÜÏŸúFà�Q}9Jþ=äG5Á�q[¨Kí†ø2“ÿ{Ñ�ËNųÓöq{q%KÚî¤3ó!}¨•oRâô[Å4ËH’w‹åCU¦Øç´6,ßEûë¾BÐðB|hq�Œ4VáÜçÊØ/n£�2cäm�ÁòëX{ÐN^ß›eÀú›IèêŒtIß5cÉgâdœã7‘—çèáò«ÑÚSÇËžÅØª'ü{Æ4qŠ\9ý,ˆåaúRÐ|$Ç–J’ÃÞTT4öÀ)™›øâ 4#v6EyÅ šãSüýû0ëÄSùô`4 ÷Ý'Új"‹»Êüyoš >”äÔG…w '¢×Ù1|ÿîQúûì6tç·2¤ ‚Ñ6®(ÚŠ›;ý!µÑÍÆTp•l—8Ò=›û 0åoý/ò²Ãn”ü¶œ^Ùõ`KRþxV†�s<ðõŒ»tp¥vdpÛæHœ|L×¾"lñ÷ä[_O±cQçUû`Р$šo3£�àÓ«½q—£‹è>÷ŽøI;‘ÔóªQyG=ú]„ W_QÂUüß­Àåâptž½ 6Hó½mÙ(:oƒQòrØv®·œq ‹Ò�Ux_•‹gyRßDS¸vQ4¾¼Æ€æ\”šDQã#DÓ~³Ñ'.€ådbð¿U~Ñp�|d§Ò?‚1æÎ@»�Oì/(û"YœõÊ“u­EÛ¢k¼-¾’|cEÇÇ—pÔ‚¸0h ‡Owí½»aé‹ñB¬i*´UîÀùÑÖ�þ¹ 6Ïœ�¯Ìÿ‚´´>[™B9×öñìågé‚Ã} «LÅ¿_¥ØO—xw»5=ŽXÈ9GÀh‡|öïì…Òqü6þm/Óæ=‡ð¸ô1Êß�Ïÿ7�m÷ËcZ‡·�uÀ3.ågð \{ñçw xï€&ÿgýÖ÷v�÷;ùm+“ö’XÀwÞxÓxïzG“3Öc̆iü$²Óò.’õ¿~št‘>Y€VÛY¦Ð÷®?(Šj14\6�Õ+cy°¾4-—j±-ß>i¡~\9oO¶eÉä+*¢ql&Ëδ%™ ð‘+†(íÛØÙ±í®‚[®'(bK=�sÑ£ÀLvÊŸÄû• HNr–·×ó £‚¾›„eœ½žBo6ú¬+U­É›͉—ðºK Ìú>’+O8qÃ×F�WÎe÷¢"˜$³–µïŸ…?›ÿ£J?67ïÍ&—Æa�†wNÙf»ð©žp{ç*÷Î~_Æ·fxuýi\c·GL™@Ûž9£B�:Êl2àyî½q’Ã_Z ˜ v2©üÎ,�ߊÉâb�™�ÚrJ˜ç¦mût\0¿í¯É¶Áýðr[N#¾¤¢ˆÛ'JñÌ–8.Õ•Àð©:h�#ÁÚÊÑy”8ì•&–?z&ÎNŽûDêB¶ù*Î>£ÁCâ°´oý³�C´Ò m7T;ùöÍ‚}Aθî¥�Îû =Æ�¢³”æ]°çŸ²Ä¢�÷øÛ©Ýž±íÂÛô(ù¦7Û†ÐÅýùD½=IØ®cÍZ0;×�•ñÂ1â ßú£¡ç òtYØzhJýª‚„ç¸_½ ¦mFõ*âAsw³X}˜ßXä¢Ù»à/&çëÌ×PÚ‹!œsÈ‚'v½ÁS›»¨­OgyÆB Ï3ŠþÔ ÛêiÒñY|úU#Oš~“¾øÉís 0aì ¡–gX¿#‹¿=›Ïž’µ�Ξ4’sl¼0Ûm"¤nÆÿ¦§‘t¿ý6 ¡‚Õû�ìÑoÊD±¾m ¼rxØÈ\°Þº*uàÀÒJÒ±sÀΈ©=g=ºÇ?£.«–)ª�ÄÞ1æë9ª´€ªb,Qî¬ß8$‹'Ìä¶š|´¼0쎌%ƒ�¯©F^�5‹^Ót¿8HÛ”^=¤K†/È4_NÿD]c°k•/L¿?ËÍ@yæ¼öû:4ö`‰0=t0“üdZPý�hÎ ÿW™´¨-LXÛ‡_¬³å£ê7Aóz(¿;Híå>¸Ôp8ùò–IÅX}Ñ€Þ+ià$k Ú�³†ïŸŸ‹æÃ&�ii9[öóÀÉ |¯õy¥8ЀMôá’5u$â•wWArÇ2Øp� #Ì„ÂR¾Qvæ•\&Žyd;½3ƒüîõÆ•íð¤ARn'­^ôYøxq8¿ß >y®ˆ³ç*ò&Í °2e²¸¾`0uí‹c›Â¼cèZ±«h›pL"‡G‚Å—(Ûo>I´F_ž»oï CUžòkui„ñ°=5¸vó^î¨_C6ý¸*+˜WXqu�ºÐ2};-ÒuÁ¦w–øºFÂnqÙž®ô‰ÎUÃÍÜðF©U5žÏåŽ. Ößmmì ¡Í‹g°ÂbS°ôK€G¿‹úuS jn6ØHN¨\–¡O÷‚'ƒüýWÂí¿¦;©š,~¢7ŸÔÙK¥„_~þKWªÏsįû•+�#ÐçÁ8Úy"˜ f£Z‡3 šXÉÅ“Îá˜!<Þa,M¬]ÀfÏnðéá¿éç¦zÁsÃã­ ä:GüùÁÝh˜•"ƒ_§ÇÇûbÍîN8~7/‹ÇÏCâMµm QV¹+ÿ µl>…Ï�?Øöµ7¥sE�8C³îä–BÙ‹‰¼Dç'Êl4b‹gîxæ‡^ítÖÞy¸/A�rL£¡ÁÞ z%à?sòE³ŽÂ…ñ�ðéD4‡y}%øÖ—‡LÀ‘ãÖòBÛ;Œ¡{Èú^"�\=„ûõŽnLDÅÿúbãÇô)E‹´#­Åˆ„ÛûåƒøÔ²\–Ò-½ø|£â«]ùHÞ:šº&êí£BN+]]U‰ý�íÀdÍl>“‹9%#pAa¾ðøËWÊiY�«Šº¹‡�UÅ®½…Ó…3¢—B:í60‡¹/øUèNöt3d•A-|×s…· ÿ—G¸¨!ͳìg¢–iLÜòîW§õôßÅ�\mp džØSÙEY8û ]¼˜x.ËJ±÷¬.Ñä…‘xÆà HµÀ鱃IâÔ#HR<Í�¿ Ù»Þ8bGĘºÝ‡%çëñNj‚ò7ÊBzf0d΄~s{cÂô1¨/{Šû¡ò«¼ª)`Yp0IÞ{Bîúc¹nÍ^Š ½N[.�‘í$®»c�RŒqÿ +r’‹ûŒæ²3!`]*œX�›-•*ãu·£ÂÔjHΞ„Ÿ—�€^šVüéÐiøæ›Ï‰Ÿ9<°–†VŸf-ùyà>*›ò3Œ8úñežz³º—\°Vi9 7nÐovIòé·3¡—q ×8çÐe§í¼ ~"]¿ e?ŒGÙŠ˜ÜeŽùF³3­LnRÙIîYÓ¨$·ôÙ³t¯¹àòÕ¬xšZ�Ž)¼ªzÜsœÌVäSiÍ4ºµÒ€Ï6%ÒEq4Þ™ž�¥º Èåâ’Ί>c$qì}cn¿ïßTy}�Å‚»F”ÖO.%½ Ãºl:ûÚ6o‰c•?&¼wÉ8½î‡ì‰¥œ­õ4]ÿ9LKœÍ½ÐTXjÎ# d«·ßý�´î uïšwh�}6‰\ßOä?ëúÛMœ<ޏ [ö.ܽ«'v¬äËRÔ”ù˜Þ:tì�ŒÊsgáÚÑ“èÄŸë°X÷0î9pTÌöÖ³““ôƦâtlMÕfÕ�iðh¶(ù!‹ëVÁæo©ŒM/yÀØü"-ÍÏ@mµ ­Pmþ¾\Ê º£ ~òJê½ÆOºÌ—íò :a!I›BÖ‘­Ç )fÿû>€ïÓÄúý—ië|7¬t›Ï—7¿€ìúÞ¬r]³GM§ð~þC §é¹¢¿®';èªÓ…[ãÐàÙúºg ¬t܆®»T¥*.æÇŸuIîdNʃ!Çⱚä4b1o¼�ÅlôVXs? z.KV÷Ÿ2Ÿ2“wÒ�|M¾³îû´bÕ£Xþ4NžÂ–ys�a>Ì\DÛ–› þ�³hÝ©«ø¢Î Õà5ñÄíï´Ú#4G¼…#oWм¥9B؃]tµeg-3†'y[YݸZÝ;€û6ÞÃç%Ð7v öm]ȹ+ocØE™<‹³³t¥ÞÒ¢�S›…®¹ hô5”ezÝ1 ]¼#Æàî�cpÑ�Ïpa·¾tþF[ÂòÄ÷7ü7�HlJ)&Ó€ ü*å…7S$Qúh*VšEŽQpWm ·¹ÔÀ”]4�ûÉk«cëŸ2öÐÁâ8E¼û¾˜¼V�?}—ÄâOP8|ªŽx?w¦£Kñººë¯8wû(¬¾“û/ï)äöX„ÌeÛŽÏ0×<�Òqrr*––­±µOôf­Í.hï¦ÎËtð‚U_󯥌Ecà“[¹ ?±‚��&�£[é¥ÜJrójtÌCãìz{|+9Ü ÷9ghö�ðyØë>”Á*…äúö5ÉôÖä)ãdPމÙkˆ ÏæA_­§pxIlHÌwã©à×OvÓÔxûã 8Ö8ŽZ:Áñ-+0«´æ/?oz¾ƒœe9d.[ˆdoWu¯yLWºƒ£ãÛ§D4˜~…LÞ °6žOÉÙ‘“{1ízoBãlÔ�ì&•ÔË�ss;}÷MOÝ�Ìyüü)Ž'× åçoNâ*'g¼qe/—M¬z{éÿúîCíáIBEÇ&”<÷Œàj¸g�Õ¡ÞìX— )ë¨fcÞEi¾ðS­új<)½�ÜÛ~“tž2{GJT»d:¢šI t|Ñ‚Á3OÃ²Š Ž”ô%ù©¨?L�,œŽGδФ+Uìòñ8*Ù×ï<z2ÍÑêˆ7v?ˆe;Å›�Ñ+]Ƶî§;ý¾€»ƒ<ùnYIM~æe„Kž­à9›í8Tœ›ÇKÓ—ðÙ¨Öí®‡õ.¸x¡šêw‰ ÒyYb4¨øC\O=¾ÉÊOŒ"Eù‰ì´8/ÛÂ…ŸSø|í;82Ûup›lF½ümСºšãF „¥qŸúH2çÃÔñ¢¾O@jnŽð¤|PõýÖ¡¶¡‘|ÌÈß-Íp`ãpIÜŸ²C6âô î¸><�–7�ç}ãÖ�ܵaB£RžëŽ3G§C~§Ц `RñÌ6þHª°üˆ)ëìÂn÷\ Þsl^%ÑçM´1¨¯íD·PQ^«‚“F]ÿÂþ`›‹ªý¼Ù¶w1ȼ6�®~!P~ V$A»ÚOÒ8¾&�*Ò$‡Ùue|‚'MñxÉ{¼­¼ �J_�Á\W8+ŸLÏO¼†œøûpþ'ý$§ÎZ1�¿´ v;áá&ýˆjƒ¹Ç’!{BON¦WÁ3Ù%ï(vݦÆ�#txù7-üóN…CôÁ�qSñðÍiTxM?ÄÚSÎzC>0u®�{g +uZ²ë©5¬éCûg$aܘm¸gÝ(˜³ mœ¢©kÏ“ÎÀ¥¸uäljöÚI±-²â¡Õä§;ž‡Zì$[é0 ŽðÄK+å(Á)†OŒ £YÔ;¸¸ªjâDܳ1/\’Baj.æ¿À1'OAñ™8ËaU®®Hý§s­«ôñõüLÛSæ‘UÍ@Ù2·nÄa¥Gáxr¶ØÿK9(ÌŒEÇÌf0wÂð“}Ùw‡3æ·ëãÅ ¿!ü“6?¯Ý�{"8*ïq¼#^¬¯I£7<û¤zµUÉcÐy{ž†å�z½8'ÏËr.о¦fxê±V\¦ÁÍî,åu›ÿo…{QøÔg¨øW6ŽC¶Åra¯0:ï0�FNM€âMÑlÕ+†Çü‚}Ñ<±ß%huÚ->6�åo™ò²Yòð —Èw#‚ÀÔ?ÏV(rWv¦˜P^hk7.еJŽØÚnŽƒªòÏÔÓø´êÑäºð2]¬âføêä€yÏ:©ïè“l~Ô ã‡|¬·î#ýRZÃ_ŽÌÁçâYØòà¾hrw2Ï0–&ÓÂ^ÿüP�:¨P ½öâZ ?´y®^)ª�§à%,krÀÕ›ªÅ ïèQ{�|õT¡yW-ª”œWy5«™BºŽãÀ蕸a°=߸‡¸åqÖ¼±µ*ó?¥Š{œÿÍ„Úéh­-ÁSêQÉ�Â*µÈû°}Bî]ð‚þq”b¡*™Ò€ò‚›g+? nkä±þš–ƒ,P‘†«{Q„òT¸Ó3ŠÝu®r~z_î@›ß�QÙÖËÉÀŸ* áb„™»û‚ŧýÝ ­»UpÕKÜç"ÁvíÏà÷ºÞü4s<úõy@Zû¼Á×~2ÔüóŽ!ûœ¾?äÉžKÒÉeF ^} /¬zsiš± †ý 1´è�1•¥ß‚ìM!°9Ñ¥F$ ÷4�o »Œêï¯�÷Òálu̇/¯H“ œžrF°²Ù„Û¾ÆS˜|<“Ͱé6ÖDŽæG—#ü»¾ê�AgöÕœ‹u®VODuVuâF\˜‚ŽÞCÐEk^S&!\Bü#/ò¦­¢ ¼ztÎdšÿ3DÐÒIÍ·Ž0!' ' ]ϹR:T4e;~ÿ±ƒ ­’qݽkÜZÔ%(Æ‹‚Ô[(œoɆªWqéŸxhß(¨«†aAŒ …jîÀ†§ 4¾át‡Œæ¹£Ïó§ \ºîY�wiM]Õ‡ŠÿÜÃÅÙoÅ}1(윓U{ñÆW†Bpž/N¼æÏó|Ýðss¨ä¯å¦Àñ¼æÈð¥µRé\†œ©¦õCaîy}”¾£@ëOŽ@Ÿß^\v=š·¡Yz'¯®XË¿ çÙM\Cq‡¬ñÚ|².ÈK)Eìx,ÍwãûòÝ6*ÙâÍ›f×€]}_À³ü[>•×íº«jpŇ âŸs»xæ[Uá·ÿl¸aÛ¦9:+¥1j¸9í×– Ù‡ÜÐjøVˆ>Ð׎O Òž×a\7<ðûþ”!=œ–H`™9ñ¬¦8œÅ aûëz¶·V-]��"´˜®=�Šî!°/å%¾{<€O§Äò‘8ÁÆažœ Àâ7¢ñymô-.ã‡ú.X—cŒZœÀúãwpóðTx¨*ëüP˜µR ¿iÇ __-á15…ç+ŠyPª�/;Í?¦óÓÜ¿B͆Þxì‹&«t»ÑÄ­é‘e ´x^¥ãI´ðïmÚª˜_⎓�c=ÞnúC » oú+zb±‡ïî¢ô”c¨ï<—žÜÇ'îüä™!Þü¤"ícvµ8ÅÖpjHo|#ëÀÅ•FXuø&ÙDá©"=Vz:V]i#›Y¼ÔºÆŒü‡WܤeŽß¡aî ²Ðûx̼ž¼ê¾€Ãm´ït£ ei8»yä•dÓf_îuäê%ËÂŒ%Î<²ÎO\i…!7çòKM >î»&œè-fܳ-I®yÿˆÚ“qHD§w‡Ñç�E0ƽ�L¦�ƒüóYX²] »�ß"ÝkRøÀåGÙÕc‰0õ/QéCEÌ}Û­mNнóÅ 5ø$o*êKwŽVˆšj9tÀ,P´yŸï)sY‰Î Ë7Ù¢®}.J�žIý§™aÿÇ[ÐÉ©•Ö/Já“c¹GË‹Ö-m¥ÅƉ ³¦oî‚*@£k�ðåïsúz(ŠuºßÚõ£8'l¸^+Ž\þž<]®ˆ¾Èb\aÜÕWÄcÿf{Úúœ¸|0Ú•¤Ó»&%Öú+ÁKϦCÞ¦‡¶Þoèµ²þ~׋m¾ëÓE<øžž:3”/–¬†Òwî\ÐóJÙ:ª©¹˜<³î&�Àû>`ºíŒðÛC³·ŽÄ^‹ÌxrF u®€Œ3šÿ™d#D½¥Dÿ§â•®V˜ê—+îºV€ŸÝxY¸ Ÿ Œ€Kë&áØCÞä4÷p³¹ \÷4”¿”ø SjGãoÅ,Ô*SÃ�;Ïá¬\æ&%W,IÒ¢—žãñM‚*ÛM³F'ÉjØäˆ½Cwâ�fM¬¸õKT‹¯‚®¹ýøpX8®_ôŠ’º6ÀùàQºš{\¥’k‹Í!)ê!iÊ÷'sçƒ$•%‡övÁ’ šx—ÎÔüã[Ñ8xA ¯›ÞËÖã™ÉÞÓG“ñâá¾¼Òî+<ñj|–UpŠhŒ£ÜçÛU% 6³X×ùäÀ·ž\Âj2 –Ì¢MÝg¹<ê¥í ›y6•—³þ͸°(CHð¸ mÔ©ªw" ¾ ç›°×о|®(yŽ›xÊl®\”�ôïÌSCqÄ| ”u>�jƒ&à�ÏŽ˜|§„çì â'ûM±0Á�]Ço¦®Œkص¬šç&æâ9Õ^¸beŒ’ÅdY]<»1žS•NÁW1‰í•ƒ­Á]r žLµ[+¸æ`¶À#"óâ\Xi¥óf<´yo·°bäR!\ê&øi+rHÄZã¹·Êx¸77ýÝñ–U•jU¶m«ÏcÎÅZÿ‡xB–j³JN ~ÿ,3ïS �_>G-¦»Ó«8×û.^:’íÎh¿ä3 �`ÂÚ|h�öRjµÊÆ4g;jkœÌ3ì±ûA9䜀[‹c¸ey:ÎuägŠýì~•& Î ghYN>ýÚ»÷ìý7Þî:qÜ…!Øþ±˜ƒ†ÿáŸwÞ±¾ï-ºdhUûvâ¬÷œžµ Ÿ:ãØêyt凊lØ(*�.W­Ã�þ½!DCšÂ(h­Ôåî—×(îò9X[»n¤U-7 VôqÚù:.{æía9hqÙ ÷RC ²þÞå‚Áž+d:¦�êc y|âˆ{+Ñj¾ K*âš¡¾<ôíOT2ÙÄ?žàœEW)ýµ:Lðå*Ýyèü¡¦ÎÁW|—‹ ÚÀŸ˜&qæf#d¹abÿŽª’€éÕ8æE>þõþMaû¶°TÁ 4šVLþyøèØú¨fÌÓí–Òù'­$3Õ3n­‚ŽÇpAL0O°8‚§Ï�àêßÄÁjNlõ×Aœã2—œÂÄm†ÜcüŠæ[{aFÜ.Ú¡S¥2u‰0ÍJÔÉìÃ:v¾t$Ì…4Šg�¯ªŒ¨ÌÝ;׳ÉM�ÉÎ<Ô»ÛVkê >:ßœoi‰Ý{Œq޲%ö‹ˆ{|?Rbs èÕŸ¦‚µÎvÊ�‘<$U…2‚~Àz¾ßg|!É­cH=ö�Qo„ ÓŸ!õàÙ/ŽÔ:#xé°µ«>.ÙØ Ó.è’dr=¸æ¹c¯_¿)„FÒ ·q”î> Ö†�oêcÓÛlyÿŠnT‹Ãvšó€ðºx#£ZÂÓn;œžÀ%uóèëñIüÅ �­rÃHžð`.�>·mób!Kæ(LW2Åæsi´Ãô ï(t†^¶OXÒ˘/ºÍ¦}mtî÷%ö3’wéH@ôCNÙºž &ñ É(x�4 ªÈ¨î,�·ÀѶâwË·ø|Ñ…·ŽLãw0°°ÇÌ5àS_4ÖƒGÿ¦id4HŠ·$ºáœó)'zÞïIìŽG‚älC~JcˆÒè¿ú7ULÏ…^ŸõQûÐŒZ¯Ä}OÆaiQ1·*~§]%UøÎô< ÙLü#©ƒW**Àx9sžùQ-WAê­Udåû‡¶�ɽ}£X²´™v7Ïgórž’"ª&IÚ…l.Æk²ßÄÃu¦¼=sE–ý² Náǽ̃V'ì¾ù¢QøazóxŽ{;òˆö;œ^‘É.™²ÞÁh¶»œÃ§Ÿ0Y[ž§kÒç¸ôC®k”¡Ü_—)wñj ª¡µáŸþî J#ãü_ÿ4#ÈŠg:Þa >ÿÎ@Õàuð|H·Éû ¡ï ÐÏ%,= v_=X÷ˆ::w÷öû©Xø,•O¯~$ ü¶—Û Ê“ÓÈãº*¯hõÀOv;!Ö#ƒšCpÕÌ4ÜY-ÃOeÝD+¿­‚¼oºÐsp�ÐÉ—¤ÂÓIª4eÞ\¦o†/OmÂÖ²tíIúÊŠ<­J™7ÕsÉ0àC_FáþŽRÛ…;�PR±ƒT3·¡†„ � zEÁÙ’Õ³4ÕxôS~±Q ¿•Fp§ì’rÞD—®'@Fd ݱ¼´|&¾Ûú“ýFã÷ÿž��—v›¾¡Ç·Ò�‡ëm¯6àÀ1sXyÁY”jQã„ÇÉàÈ&3©+°Ž)ãýë:)9ò„UŽàºŠ�Ü7÷�p²ý$ÌÖ5À ‰ÃðàÄ Òn, e¥mèi”�N¬µsÙl–AóY50üM9þÒ®´Ý>Û“&ýB_Å\º&{ÿ�æ_gLm Û7PSÉ»ÍyáĽtõt>ÑŒg\¶e"/[rG<0ã …ÅVyצ´°ODÝɸúa ]7¾Þh�êoàq{½Pá}EtjÌ Qc6QKà s�ÂgÁ‘ôq…3^››Jf¾˜¼ïš±¿5*н]ñœ¯—œ’çÉÿ�`Y§0žª[‚UïöRõsìoÜ,LwŠ®´äÿ|ZPkiæo$z©A�':XçÓC°}=T’¨V½ŠÎ«9 Öƒkt½�7(Vüö}Ê‹\Ð~4ϵôbÍéYb¤± ž¾ã€7šˆ?~ŸfõžÁh��§oL#1þÖ?fûC!Š8ðä ˜êÔÖJ[øxO†G\¨ wކÛ�Äþ…¦¼JÏ ¿­iW 8¡LI¨Y¾§Û± ÐY"s¬=Îóžƒx8ÿ¤´Ïg ßHnù°CÜ ¥ÍúKŸÀÜþ¦´t¡¯Š¾ÂvRÒÜ“ µe-•jcÅ{5ô©Ü’>¸ aë'#Øúž©XµBÚçi¨×� ÍÖÇi¶Îr>÷Ù¸JÝ3‘ÔþÌÆmç )åU[UÄ/|uØ;9†%´âLÕMØvë¯xìÇKwìŒLB­~³Yé‘_~“ +³ `M«‡a›Ícˆ]óL08ëŠó&dR´…¯nº"¶ÿPäÓF*â[y\òi vÞŽÂO勉<©4•Ì ¾›Ò°nÃ5ÝæOW¿äá—ŽñTb.…#R-y£ý;èz¹�þlͤå ëøÒÕ3}4ƒÂmÔðÜún¡Ù_‹Jnj‚FD?®MùÇû­š¸!y0¿t â7{ªê{”X®0'ÿ®!ù·²àXØŸ�䨲b§'k¢§ ÑÔm™E;M¤ùBá(Oª„/¾öÌ�•,îõ&…ýó`—b.)Ùw‹/¹³Ž§#ý”~�oÎBƒÎ [âh:æ¶%<Ĩ´Gäàø‰»–Ûâ B+Ô•ñE÷Ó]P9³LÈL‘Åöý§„­s¥;¥ �PuÐCƒ–àk#�X‘·PIf + ˜Æ�véxá‡*(Š¡á+Ànì~T6âÝûQÜ¾ç §ÝsE…qˆ¯Õ0n÷(ü‘9‰kÙF&Òö:‘È| Z^¤ö¢aüiÀl:ÑÇ�†:O„ÀUO Äó*ÿŽ¸Ž rbõ#ñÁàþw¥·ßã¤Ç5´¬OX.Ä¿Ž÷„‡ëŒ;l‰îÎ6œv(Kô º‰ M°4½�ÒvÙÓ—ñì¤Íùn°ÿÙ*”íû–¶6éÑìû»0/n5ªuÛTź=£ðqgªD¿3t?NS˜ðfêdü«ýßñÐlÞ%ªßƒçN†QhÕ3.Õ0G—–3¤9¸ŒVËqU¥&Æ>,ÅËßzø‹à¯Y�øÎë/ÿíÿVjâÀÿr/QÈ:·ñ ÂÐ ØuNš·ŸÙ =þЮ— aÝ4wŸÌr—‚ßÇ|X$zQÛý4œcÚ(6„¦‚XQJ=ÒRÐïÞ6poµÁOž•‡tõøÁøwÔèÕ¿N>dÛ+¤†ÕÒËé»ðÎðt7i¶Q?Æé&žüuÓÞwŸPÍÄóÿ�D¿ÕbûÉ‹¤4)Üš¿BW?m›Ñ,žîoÇö•þ¤/_FæKõÅÀ‰ptV&®z½›Ãæ¬dŸÔœ+Æýóþyxô}ì·�.ÝúI執â’k~<8«ouÔàİá<Ð<OäH ÆY=XÜu™™Ôsäí›èu¤œŽÓÆØ&Ü8”õûIcÖÈ ò»è{‡öÂ5³¦sMÊR¥M‰N­Xù� ²F¬  ×_�ŰhޱÞËǾüËãé!áÚ�F´Éü"ø÷íßFìƒO+>RÏ!E~ežMýz�ÁœXJóžNûkcAíqls~ e¦áúq±TrñIT_tl°ÁEw’øvk:ÍÐL�äñnͱÞijíϤ¦ãCá`k­pxÇlšž’HÖ«íðKø-Êx°7_ÝŽ¢ÎXŒOµ‡ÚüÍVcíΟ0f„Жp~VSåb8àƒµ½ÿ�áòëñ ø–BC‘”¨¤%*™õ}Ï“¨ÈH¡�„B…PˆJ´—hªT¢%¥�ê}žBC¤””üH™™‘Ù¯ÿßë:ï9ç9ŸûþÌD¸~÷辊ä¯/Ô‡�Éϰ0"¬l|äú“Ÿ÷^£ÔÛkáછ|~N‹`�YHD7³™tŽ%.›Î–UažÜ0¿áM7s_⊰åPÛ�K·ûÂÁÀ'Ld®ðVã7r’Ð_Å4ø¶Ȩ̂ѹméðjæ;|8r&…TÒ‘Gâ`Þ0 ýuÌ�²w༃Ÿ™ô®\´wGÓYM{)Vù·b-Y�¼Â Æh£†þ¾XÐÏLr|éÝ÷¿øOy˜êÁñ«â8d*WùgݨèüÂÒó=‘äÜIíú!6nÑ1*J�E­ˆ&8ç5‹4H*cõqV­*iœÌå㎛»‰,ü'gC¯nÃ×kÏÐuew]³�ò¶&ÃŒseSù[®€Âc‰¬ðsxy¡D(¹Í>Í=9®RqQ5úEG²Ð�²ðR;W»„¿V–b}Ñt›[†.·š ,JƒËY‘ϧX¥²íï#èýF!êlѽY³  5гŸäÊF'¾ÄÇs�hTºl�a-{àŠ�hn³0嘑qå[<êQ‡U ñLJ PbÑÌ{LÚ‚O›Ò™‹ÿ:Ñœ M¡øXà 8vñ‡œ_a¤Z;?ëÚròés€'«ZùÕñÉ ;â#/°ˆ€¸ÄxþÝIP;,Íæ˜)�cöBØ5c!ë“ ӽř‚n¤œ@ºªùÅׇ}) )S9¿qzåLq�: F³r¹óëYÎaÈê{GF+oñï71‚²�8CŸ;ø1–®§_C×õ¥=ìƒt Q �LLdçϱO?×Òä5Mœ–Ö0礢iÌE}˜•Â�[ØW!©Å‘B³%ü�àAâì¨ráØ&»‹”b(${9Îì:‡¤eJîuJ0gí*^¢7KÏ˰¾·"´ån3-àbÙ®î‡t$¶‚xHBú†Vö¢Ê F_!íT(ú–Õ?R„ã¾"&ד'¡ÔÅÿØþ¸‹°[9•žyÄ/¶/`©…ãyyëAÝõT]›ÆLÙ…ÒZ“ñuíXò;ÁEž‰A=jj2¦Ü-\)ÉœSbÀ+ªÞFÁ—AâÓhþ­!–²ˆ®Þg¥»pù'1Ôûø‚ûÔýžlî(ã”%Zà¬gNå§Rí›áù{<ìÑŸÿ¹‹Al«¤.‹#W^…Eâ‡]þ!ÿ*Iƒ÷Σ+†ú4ßä&¼Mmbµy­LC߀Þñ )e�0ú'Ö½‘ }÷5cƒ™ùf€ÓZéý¬12¥‰32êdÆ› XF÷mO;Î zßâ¾öŸhóíú-’Âý6šT.s›=šx™vh…Qîç…´3·o�¾ÀóëÔ¹§¥ÉxcîZ¦Þ6Âı>n]hå×èŸBÇm(ÔäËþ^šHš1³ IÃ.Ovfîf«ÜŸó˳)+±Ÿ˜óˆÚe�¤6.À¿¬˜qÍjðêüÀµ ßBÙM§™Êʱ`‘ÛYQúw/Ë�#€Ž.qñuøè§*9^�·ŽD0RùÆbØ z� ‰¾¤¾€Iï+Å_–tMË�.Ø.Ä3ö’Û…1xæÑhPwO9ÉôÎf'Å&©@Δ5(º˜*>ee*7Œ’›]iîâ©”fÆ¡ßù©vœÆ]5� ßp¦íýL(k"�×ÏB‘ÚW*ÖõL H]NれèNé]Xú.úÎêЋhÕÊ“W]QçrèˆôP–õAÚÚ0êëc©©:UkÀížmàá3‹•™8Á(Ó0LO®¦ÄœFÜ´ë:H™Ñý¬N˜*~Of/—ú=l^A-™|øÀb'g¿}B7“… ít¶B½t<ú˜1Ñë ˜ífJßÃØùJ[Ð(†­^¼É8Þµr€Ž`ƒ$`DæÞ{ÛMö×g){X1�B|ï0墨ߧ†g#ièq6Þÿ³˜7;­ u‹ž ãí"Êý1Ÿf÷̦À·ùø$æ'ùúRYz +{3ìSÚ;˜®hM…U–Dåª7רG…—lè÷Fжçnˆb3,*ÿÆ lÔ1Úg'[n|’etH‚×cI˜ÿà~Ô@#4à­e^õ €%ò¸K_a§fÕWü3·…š9“þâÛt=8'í«m·XKù²±ˆÆ®„ŽYî”¶�’ãŽÂšüiÐ_]ÌÅ}|Ê:5p�j,øL›…29g¨gÇ$ìë2codŠÀ·o,x7ÚÀ¸ª³L"9�õ´GPdʬ`gòo££¢2[ü̈äâ<0õë |WjL¿ÚNss“*T¼…að‘…¸Œ™¿jV‘ŽgV„ìc¢}®�©òVþd.§Í¹ÎSIôù`tQfÙ eèÖô ÎÆuq–Ÿï sþWj@;8HÍQ„gšÕ8fŠžŠ~Æ$25Øëóà]æºÓ…—“/á˜öß(Ú퀦i†Ô:U‘¹Ýp�»Ïå˜ïoKºÜ- Õ�fPã Iþ»FÓ*zŽ�­B&‘CA4u�8=·ÿJ«a_;—Á.ï‘lÁ³d¾7e;lXœ‚ûŸT1™O«™ó±4š°•~>g§|n^B!òQLäÖqð6÷ÇR‹+þH� „?:ðfb&)º›SCŒwFQ| ¹í#ËYÕZ'¸ï§Oú§û™«åÚóÉŠk æàî�™4ö�Zœ¹‡1ÃN`m<Àî•+³ï×Ci“Éxx¤�Ô€§“µ/åð×Omæea?{ó‡óÅ ì\6hì¥Ò N§�·o—p²t!Éçh91‡ù3|„L¶­G!ÙiðŸ«"•½UåÍul·–ØmÝI��³’[Êñ¥I'}¹¥ :í$¡Ëæx¤›zBì7ü}ãjxz°Âõh.ÝSˆºW0öÛhvKo=x•¾b›6ïÃMNw0çg¼ö,gcþŒ¤K'[+BlêaÇRqØ!P¯œ/ Ï|Ñmz$­8ÕË[ÿ›9Ì\E¾C}5MŠ|Ž;3TñGÀø1ê1‘~ÈÊõB)RÂ[ºÕÐÆpbe@Î&<¨yU¿M��­˜9î1×oƒåù¡xo¹+™�ÄÄ*ï²³Y©ÌÒç[RâM×jΣü™ìèÑöd· [r ŒÚŸOc¼GÁ¼yé0v»7=–îe‰Ÿràö�5ôbï n—Ò úàEkÆCÕoò°‹¡¶£Ëàû¬< ˜Ä.ÊXÒ4)d“’Cð]-ôSϦš>­õý�Ó�ý³àÅæ´{¨ &NyÈ|ßèRǺãl� šÁUMêtýÅ]¬t‡¯d°.dõðÑ…[HùX%4ؼ‡Í>+ÈþÒ#¼¬�í¥ùxF Huû񨀮k(q©`rݲ΢¹�7Ú• cùè! kÕ‹³ßžÚ8ÎtÏ$½÷Æ ãdŠÏ]~¡ßºSdõ)�_yØDw²mÑöX¸˜Õ�^@·Écv´t?¬‹ªT®iÅÇ‚ËìTÍz°¸2ÄÜT´iŸA5.�… k›¸ÆÒÉ4hµ’-­M‚ß¡úÕX0S½Ï’¥‹ˆÙÐü€2Xðf=÷xV$n}Ñ —¹ÐK�4]ø—¶UcÁaKNê�*ü;ü`Á@g´¿úʭȯáOÑÁæ :¼$ð>Ð]G¸oÁ ×"p˜(8¤_‰ŸgÚòb¦8ÁO 3¢ñ93¢ÇómiDÆ5”=‹7Ôr(PÀcgçzý°KkSÕSiš`?ÈPT®Z šz`ú†­´ÿÜMPi‹¤%“ƒL&f:‚ÕúJ�Í«eáUìæ°×1ÄŠ¬Š‰šô,Mƒ½ÉEøôt†ì,†[�™ôsv�ÓÃx¯ëྃ<€Öä’{“ÊV_Á.ûyLN"­"�cµ»?«©ùÉ21›i'oÆŒF1ìy²‚[6ç4¿wÉ‚·«(¢T÷¾ö¤žý¾´½ ƒ×S< ÁÏ‹Ï|Ä »³p>[Žâ|šÈAn#[c#MýŠ’h"eCgúæÓè†JúYϧh^àô:<ØuïF²ô‹¥"$òò –&=FiJf݇ž”§f.‚¥W>±…’ë8fÒÊ™šeÐõ¦]¢ÔÉö¬¹€Bç’à^õTV£²› "«°ûim=î‡RE £ä.øúO§ƒ•UÜÜoÓ¡OvÍïêßÎD p̓<'EÐ[²Š®Ùï¡òu0r†D¥÷‚^œfïÚgÂ)bGhº@�B®\aîËQÒ ”Ô°SU*(cF~ž~\ÎÑäÜ~+Õ ù¡=*jùÊ^õ�ŽÅt0´¾BÂ.V¤~ä(z¥©“Uòö£¨ŠÎÌ‹a·|#hSB,½l[AÒ‹ �T4pÎÃjv3ç TèÍeéÏÜéu´ÑÁTŒ–•åé±iCJ”<ŸÙ×¾ädtÞBB^,SIqßVcYìÅ®ŽDÿƒ1ødA{Ù˜D!ý;Éí§ ™=YNÅó\Qî§:,�§{CŸ1›KJºžŠƒa‘Ð(�wžÂâ §*—„/¹Ñ�;l�O8 »oXá"Øây�[_}‡‰Ø¹a`�Ô_f¯öWqA Á½—ÊYAôìIü_óhú¹a!›fu“âý AªDÞ-ëì2’€)]þ¤)L"¡f^z…Ñ»cÄÏ›^yJ¤�mºš„ÝŸ�ºÚ椅 ÜÓ‡_žgð7a ímãZ²ª9+»%$”ËßÌd?VÖ‘ß­H˜÷ê34ÄåÒ‹7B,¼xÕÚKPÉ¿AæyJ¼æÊS�ÿuþî—6 WL?¯Æ¡^E¥"R)qúÎ è@%Iw¶¾f;˜JÐtµ}Pe—=·ÁÀ¨Q`=TÂýÉþÀzäO²'TÆü˜Nyßc˜9@G¯Ü\w… ×ñ­q#Iûiž°˜�6çØÌs/èWM3“Ø¡ OǽÀ;+“H®'Ûå§BÖâçår»Hy9Lhs�°Iðcj <Ú~ŒVÝÜ7o*à §J$GSÀNÈq¾ƒ´3hb¢÷ñÙ ö|™@`»s7¥œ¸ õLxÕ2˜¹ïVµj°7só@¯Mb�2)¬iK©ðe¯.;Á�¶ šòf4øœLŸ±°3ÔƒÉhQ’¾Š­D¨[BŒÆx @fÈD:3m&ª͆䘮âÊ|±Ç7RÞ£M—lH­€Fú6büé¯äô*˜þ“l§„û(ôÁf/¤c�ÂÖÅæ,PƒgÏžöÓ2™‰t¸x–ñÍ”4F|ø}4ñaoâyÅ)Ê=Üé Yî2Iíß 'L§(¨WÞÉÒx¼-�«-)òY·àòÆ2¶ßÁâÂ+\¿ˆ8ïžakäàîíÑ&K¼&�ë“B|:¸™_ÿB“Ìp6ì¾´”,“®hø]Ï9K É&-P¡\þákø°>þ \ÀfiÔq_W0«ÕM.¶tC5{Ø™-HN2•²Ú¥¨-éb…‘IûfïEóÕãð`–|m¤w1AÀäŠyÝ©œÀ81Çt_ >Ð’ª[Q ŸzJòÿ-Í�×CŸéµ±(y«–‘ˆé]:þw6³²õ§KÞÅ4ÎHÌc6^˜"dbºZ¥rò×ST&ßÒOçЄ’vÜ®sê�±Ù·•I¾‹™Ü�áŠþMbx­eæÞŨ­AÔÒ¦ ‘ 6‚Fdt)7.0Â'�ƒÉ«d!¸o´É½ŸòÀÝ'i¤_ïŸ@VÈE~öî9”bãþ›ÎÑæ9Ë©Ó&¶ÂÔ©í-@ãÇ­èàËþFxÀ˜®Ü´¿‰^íëçm>…¶%ðJ)Š9ˆ¯$›Uç1Ð÷¬ÝHïï<#ÉíbƇ£“ÉÐû=÷ó^îT£©Ülp?û)oÇÍžã…�Œ,j°­Õ¯ø¶7U4E&Ž)vš0þM KØp”TS'·R(V]‡þ—³Ùü)]Я¹ Žyñ>iÌ1kd�Wµ¡aŸvå˜^/Pmß�éÕè®,Í>.ƒužÍÌåÆ)ü*t–;¿ö^?óŸ ±Øõ³@us33?XŒz9ƒ�ð°�ÛßáÅÿ; GÆÌ‚Ïÿ.ÑXµ}ôT‹gç—ƒúN5;·oòðüÑÊã.-L{Œ-MùoJ5ã¤;.ÂüݵÔë%d²é©/yakÇðm›} ç2£.kº3/Ÿ™�ÎÖ,?ŠÁŸ@œÿYnËj-èýX�ã"ȳDOü–…‡ß)!ç]]·ˆö*‰²æW°mN&‹9œÆ2.TA6éáϰӜòfÌÈÙgV Û´Ý= üTM2¬?²íC:tîø4€¾n¦Ö)C:G9ì©M߇ÄQn8#î˼z/Dï³2@[x2½Ê ¡­ÚŠì’Ä C [~«/†™¢Û §¿»éb(1NÇ$Ø6 ŽTí`žN�X÷ŠûìÐö- Tk‹ÇºR•‹$«wª€Æ};ÉJчk|~ '÷ç¿EvâJg Ü9jÓ7N Šáž!tˆÎ�Ö47)ŠD‡„ÉbòHWD³ ï“ÎWûe ‰×܃\}cP�&£¯-‡ÍEüëÉRì릣4gMŽ«‚cBùO–ÏP©@¶Õ‚!L"�ø8&ÞìÄ{/Š„Æ—º}�‚ĵÈsÏ}¶;l Œ ÌeÉ>]à¾!…¬Ø_Ìî¶b ©Ïhz9;CºŒ=::· ­*áÅåŸðÚpøM&3­™ÿ ³¡‡WH3Æü�§�Vÿ`K·fòá+ïò !ߨ«èOÌV#̾û�ÚVÁ©•{({qì“·„À”Ù4JÑ ]v˜Cã-oxuURâ S?˜d®�$G+}pp¸ gÀË’tÐo2µe‰9y‚æŸ ìèÒé4Îr=yT€-DAEQ•WS‘„³odLBv·QYƒ }ÞIk7õÝxîI“Ú�‡ä›"ß¿róß6�]R¼ñ]ûCàt˜µ±¡—+|g%ì•�2èüŒˆyΦܿa`{ù:�k>N e{¸ú??`ÍôEpÙ{U&žàB í¹$Ë/{V‘ýá*v~ˆe˜- ;ôaNäÜ_`O>•óª)íl…âRÚâߊQ¿Àï™8J6걯+Nâ‹Î‘\�Øl6óÎh1¸Ë¤û䡸ÞœS’ ½ƒ¶lâüã0V7}øü›èîk+j}íʾK—c#¨Ñø6kFiUŠˆ—Þ»Ì+ánú%&±÷H$ìŸ{ï#sî%÷ø—ƒN$rý ÇÏÉÜ¢¼'éìÞlqxTq‚›1ö$w²Ñ?¾ „ ?W“FÌLöŸL`Å¢k:L©ëþI`Êá#hÍá[¬+m2ߤ£›mYK] óó"‰)9àuÁ˜–UñÌ«N‚~,‰�™'Hþ^ W··„|¿— W-ƒU¢L÷ž¼j� 6¨€ÕŠ› '¦Dá²ÙXݿڋ(Ïe€_ødª ±ã^kö‡ÏvÆÜ#÷\ë²…aš\h�ãqKzFÐù´z{U?ŠÀ6k 6¡R„buáâ-cœ£ô+?U3»é1Ô›ªBŽÞí˜b�ÍÂô“0Uá Ž¨jå�âõð£k$³öšFQV´"£ŒÒ 4Ø‚ñð’]ôj]£{»ú¹³:è6Ö‚o�«ðwì ãŒo5pj‹þâòh%Avnm š–rÔ¢3Ç$L¸�5]¿Ç×ýûÆ9ÏjÄ÷¢®äzm >+ð€°öl{Àã¥;@ƒ²÷Øö–E˜ú®Š)g‰ LýS.yv3S®�Ã�•ïØá­;0L«–¶Ý�»Õky fåm°rîâ??a?’`Œ‡&lJ”ƒð•/X�ñdPq aö¯/°£qëcCÁôµtÎ “]¹Olö7:<å#ï›¶…þ‹o¥3£©ÒÝžÏÕXƒ£ò pLþ%��Z�;áÒÒ6ÔP‹aá?ÊXQx úŸ[FéOà*W)öZñ<þÔŒ£üÃk`žYÛ;©üÃKK«P)ø+êÚJ+RÈzz7 ›]‹Éè³äËÆQœ¿$ØïYDï¹À f\áêk�’i–^Ó«ÜGa‹hnK�ÒëçC>ƒÍŸK`.M5Ó0oرÇí¼Ë¦5†À/›ß¸<½Š;g&_ëˆþ�ôé¯kÛb4¿Ý¨fÊÆ©L{T)žXü�›²6‰cF{ñî‰K¼ðRü‹®ä‚³…,\T˜I‹*–Óºßâ´FøÜö]˪t•èDÊL¶"£„YÛxÒËž ôán5¨6˜ÿ{À÷Ñh’0£=^‰t,*˜vˆUã–ï Å] ¼Sî°›Ÿ2ନ¥›ã¦Þ`–tíÄðŠi˱º&0`�K¹ên%*~Ç1‰§Ñ oí‡>� Øž‡ª°º˜¾xœaâsº¨¨ÛaÇ(ºn“CeI+˜�¼¼x»®åi3¡“<}x‰/æ6CìéÍ,B¦‰ßc¹ Q¸åÈqZ%[Ç”ª*ÑG0‚«|™J=; 3^æ¹Ê±Ã›S8�WRÌ|L ³{° 6Š~äönaã\¨úó+êKleRI¦ì‹^)úGÔSMÝx“ÁˆåÙ�†épŸ�N¡¦ "`^Ïr&»ði!J=Úǵµç«k%(îC)e÷dš4ªˆ©\צû>w`ƒü*ôûƒÍí¬æ™|O)�OÓÆî.ûz)§Ó)·/+±ð”nÛÃü'ÜÂÁÃîTXï‹C(Mn øÍÃ%ï\!í•»ÔhÄ–î³§Ö«]|’�5.žÈ^»BnÂ"”ë° *Ëzhò«Kìz´.lT¼À¦‘&í苤%G Yˆh)eMTÝ ’ƒ›Ô,Þ�FU»Éû™4éÀÏáhf¦®]”ÌN+ëRÛž`ìý„½ÜKÂéé´îÖK6ãܲ—ªdî»d)`ƒ>4òûa¯ðÊK û'Ã+÷%�%ü“ã"•É�6ð>æ)›¢µ–Ϫc[—>dջÙ�áDè© š­ 4ëüœ3u18ìY¯Ÿ¸°âuR˜ö¾þ°†àð2ëE�¨½Ét?Ê�Dà&Úu{&Ûzu -ïû�©ŸäiUâXÎïO7·�Û÷SËÁªX…;Úq|š EÿÒö70^OlóWœWÇaLÉeæ™Ç�1µ¢…7çAì´dÒÚäGbÏb¨ÈB ¶Å˜ÒÅ&~ñ)�y†o8oË4 âàë¬Ük>“õ°�ö‚bèŸú犉ã•è$¶-è,-úVÌ„� E$à‘¿œi²‡¯“‚ÙÔî½\—ìktûþ÷Žô×ï%¨&CåÅ0ãª={ò„>ŠŠbÝÊ,~ÇB8³þ¡àæ1%¨v{ŒG®…ƒìjeXV]�’�uɾó) .0„«BÄ Ò÷ÁÙµ—øó3› bÅrÞ“o~Ùâ´ºY¨}!”uËãàþ[4ÿß6ŠÚpC{ÐZ{%Ürw*µˆ^diëáÒË5X¯ �–'›Ù'wQ¸—zœüD' VH0ÙŸšÐäž/ˆpڳŬ õw»ý܈ߣ?Žy&p1>éLìóx­#i¢e¤�…! pò9øÕ§ÓÑCø¨Xë‚&ñ67d¡¬ÿ9Û®·ŠÏ‹@½lsÜ”z– “™Ê{}&žÖC½—I*…;,…ßmê ¶rÙ¤|�4/žÏñÛLºp§a;œ+ä6Xgs—"½˜êõÏlªK-¬›kSЇ¹<�–µw³¦gŒ˜÷ƒÝ’@!;£ˆ¢{Usñ‡%µ'±ïA0yÛ |ìòYOH n¿Êž�<,S üEUY°ål‚?æÑ9�Y‹4jès�³rp7œPî�ÍÔ¬×౑'YÎë�Ó}�¯÷"íwÑR¦‡Öß@ïžw(ñ$ˆ¤„5x}‘rŒ�*O ñ+º½w3èhÑd']–­ýMm fv‡åŸ¼ÌòÌÔ©?׆;ñ§øâEÔùI Î=plxÄšâ\๰)sùœ@ž+xä.¦%÷Ï“m¶;}1�=Xk«vò1šë)Rè X©<`ñJ5u¶¬�ö°~·À –z±)?¯³>× ì°ôñkçŸÄ�‹„Àòñz:½|4¬ìšÉP0‰þ­çð¥ÐyÔ;z™˱ԦýMIçw-PIû_Ñiål*Š¡÷ÏD@µ`"{ÜkLYßÃPÌF£ÂÈÂAš½3ÉÆîZ (-B‰/,NË$©WÖJ°¼Ü–'ŠÕ%–RßÊÕèiçb¥Að4üî•üE-b9ذä ì}tƒ®DèPáü.|óº”T~Í!ËKÓÀaÞYÜÓ|W ÑnŠQÕö(©�$Ñ ÄŽ1›hîƒðñ�3ÎiußQº°ÃB—fœ ªG°#½¦´ßü »¼°Œ_1ï^>íÊJuiéâVËyÀSÙcà»]‚~Iqñ ÏÆÄðùëÔá¡£�ùž†µ±IøS;ж)ÊÑ�¸¥ÌÅTŽjÄOãÉ� §~ÜsB¥• oý¯ñ… W(}†ñ—°/ß”G‡Ñ꣛`W¢3·3SÀÔf˜ “]%-Ï�†þþ}ìó‹¹0()É~œøƒÏ¤GÀ6ûB8µíÍÑüÃI—£®€y’"?¦õýp?ANºüiz�³çÆ‚Ãù}ì�oÄÜ=ÚÅ•©¡à"î�ŽÉ]Üâ53تë!_Q†T?ÄåaâP2 )½x.ŒHš NZ†$ñØ�$ÖkŸÃS�1´bjúÌ߃ەM9NU‡àÅIßX£×d›3 bÿËÂŽusá‹ã^òÚÂAšGê«m§7÷Ñ8«$Ðm;AŠ­,$Ü. KÓ�(MÆötrçDLé�”E…Ï£¿ø+%Xp¾)f+ï†Þû÷¡¾B"õÌpyYv0-f•\À´fóXÄì÷®¤cë炟çD¸Q4�<CYáóSÐí¥I£cüYFÈzˆò’Æ[Ý–ìàÝ3 k¬Öޤ­NÂ¥àWw!ž6ØHŽÚùóï=^âÂf]~úºjøžÒéÇS|{™þÁt¼ê?ÅþŒÞ_�×[Ciå2iøïZò³ß’ƒŽ¡-¸ú•ü»]ΞA6ÞTŸfüþ5Àå½_¹b˸¶ªR°vÜVrÑŸK[$ä¡Uóžo�Â%2ùükM°,XÍÊ<£šø¿û›éiM¼Íéí? ðd¹Ak¨ôIåç%QAšnV†££)=f-žµ;eÓ"XªÎ �ýÎZ´ÿ²†ˆ$¼à=…])Ñ¥ÔY«Øß…˜ÐµüVÀ#­eì÷ÀEþ�Äö«=RÍ ¡V:žøœ>o{´Ne÷8?x`3^.þ&8=aùbâôM] î.ÍUP¦oÆCâ_qÙ<}T<æAn/¢T 5ZeñÅW¾4ÄPüOê¨×Á5'b¯Òµ‡ç˜êåópʧ­ò¦°?¶s@¡c2,ŸÞD63cA­°�Šï¥@…ìNc�jÌÑãO·ÝF5ƒ~–¾òãâ.³_ÐWùÝÑŠpýŸ2mÕƒk«óX€ÍW¼¿a“H¾�3ÌʹsH7ì�â®R?�K 'Ý‘­d¿“Õp‰x#+° |У{Kñ¾…¢tRh5¸¼U 7öql—Z3*¼óƒÜ²§ì©–-y'jakÔo¨= ÎXž`õ kÈûsùeGOÏrÌŒNãoÓ0Ò¸î7,d.Û”‡™ÿŽN+Àí%Sð¤º4Íœ�¿äiDZ:væ¯yòo±üʰa—ðgGBuYÅåpP?é^©ÓÙÒf!“øƒeøÅê$ÚmKõʰÍa-È'>ã¬ÿÊà¯iz°¼ô =QŸÊ„oâË:W˜Å9 ì"_'|ts =V‡zõqdðí-o¹¬MÔãáF¶ÉB4O³oûæð�_'“§8ÍͰ„A9´¾Ð溼SaCTdv»�÷ëHz`q²UN³âc’ô5^“æ_l¯p›4Šm²¤9©ˆ'J+Ú÷Ö`Šé!¦9aL®Ð£}ëQC:�â쇽`ÊA>ÁÞˆ KX@Ô)Ü)²Ÿ*7o`Ó\-‹_ÃÃîq\J•'˜W,í#–˜|n5¯íÄÏ%×Ùé¦4ر(«âùÕñ�] 9$Õ•$Y±6.év8æ=öB›ósPv{,·4ú:[f,Á>® �¥�×¹‰ë8zcHGÍ€øÂK$ߊñk—1½ Ž˜¤’­åVºôp¤�9Ï2®QPe4¼tP"§ SÔ¾|ëM‰y¥òÓ$éÝ% Jû[K9]ys~ËÌp.ú‘ i­IÖ)+Iß]›šº6Q¹=ⲆÁ۶6êÓ×_Wi¼æolüiIƒË:ðÚ‹ñ°¢®¶-¦ÿÍ¥/Úä`Å+¯$W›ËtÌ<•æ=Íb _ÀF±XfVÉ̯͂—{äIçÂlª‹h£}O4`þyø–f[{ÑÒ VpfÂl˜V Þ,‹=’ϧø1 ¨ªµB7ÙÂWa虼‹ þeÆ÷XgÛ2V(TÂN¯VÂωwaݸft8Q ^ã97š‚>›Š¸û0nÃ_îr¾94ÊÒÏéØåþ�Ö·j Ê ¨Oï´Ëƒíârm¨=R! šÈò¸7�WJÄžÁ›,\~Õ—I2nórÐx²�ükÊH9æ•òËØß£']†~Û&І×'á.µãÈÐNz›¿�j~å1$·‹Åî_w ð± õ aÉòRš*Êöïõ¥ )Ȥêÿ²U‰µ`5q�­¹ÙÆé�•A>³˜6œ?kV��â ”Þq . s¾*c:s¾‘[± ½4ÝsØi«l¬»›²_×Ö“¶Ãmþü¤‰0ÿâ\È,¸H>-gP*ùÓÊøŽ™(1e'TÖW³cÏlAhêIÿe=}ÚŒõÜnü.gófå2Y¿Šse‚IÆ÷YéÊ'ô¾@x1+È´î.ãºù» öõùCÁœµl¢÷,7�…GIVpsï Xß¼ ^ –Eœâåûƒñ›i•o+GÑÔ>¿Š¸ø –»Ý•%œŠ6jo˜ÄêæÆÑöEˆ¯3jØŽ¢ÚÝÊlïŽFCóh¬Úy^ ðý:]2¢ðË]870ž5GTAåà?H.÷€œü¥ "" s§'s/¾eð/hg´’å¦dÒ&§T1¼D\Mǽ]BxÌÖŽ¶»RpölÌñ‘pÊoWŲ-{Xü­gú÷>´ç­Ó÷HÝfOø K!O7?¯§ú”,–ÕåÏn¢\™L´a¤õÌ�[:šdôR�L^åçndÀ`fÐEæñ­ÆÐGYoê­MçÞÞd¾Ç##£"›Ԫеç&ç[tzÜkÞ��`‡ï†ãy Ž }taŠåÒ”DSWeµ>›ß|¬xz—^ZD×»y–ðÒ÷7,&µ�“Mì=EMú.°¸1r•L¦ ï¦äƒ·þqr 9‡°-LÆ3Š2ŒOs×v�£ÒT“?Ç$%Ç™<-› yrõü•äy¨¼qÝY˜¶ÍG¡¾1�³°Š‡S^?pB� ÅEç-»ú×=òÅ­—.2 Qf\¥AFƒéÌo^#œ‰Õ&µ‹K ý‹-é¶âÍÅ…ènvžßkì‹¢‰¿è_Úî³ê�äþ(Êé<μâã•™¿|Ë‹‹¤ù7©<¬‡¿:•`Û$Ç+ð4L‡ÔÊ�i_EõN1¦Åöêü…Ý 4R}7ž)ŠGÇøAtð—ÉF–êÝx¨x6¤=0§§öÙœ‚‚œ]¦Lckœ+úT6Óê·€ ’Qþñitù¼&Y J 7®Sï¶± ›9†^æÁoXI‡O!XÔ-ƒ{ëš™¤ ¤—Î}•ý¨3Ã�2’þ�MùTAÚº…ô0Ú®ç§ðA#ü÷ø?V­9ÒDKª›�vÔÂnÅ)ðKO‘{ë¨G>µ!0BÔa¾áo^Q-=viз¬U ò°ƒÏÜTC·biûuyêýqœ¸}²ô·b1• \àÊ�¬×cx‡Âþ‡é¼˜½=«HoŠué¸�HåeGkÞ*½…Ü2ønqix«n±¿Êàñ”º1~Éð[Ê‚DåáN8sÅn΀î‡Ê4Ÿ…±´Q/)Du Þ»XÀ¯R_Œ²ÑǙÒ«Œ½G’jK8a·Å|‡ýqúO‰º}×€^×X¤ÓÈ&̶ãN>º]¥7<Ž?; ›Ë"¤ÞÒ…ÖÿÐ{K6û¶5úÍ‚áùXXx¡ëÇ’Ëàv¸V7�ÓH±¢…£#a“l(¤4Ñj« 5(E _3³ºi0x}53ûx„E+�ƒ÷“% 0½ŒÍýZWñfm9”Øçó™ë:øýÉA`a­OZ’‰|ìµT Õ«ÄgWÛèƒÏ¾øÁnm¦£KG±yKŸÃ×S°qá+<«ÿ͵Ũìéj¾ †O¢¹ýB,ÿÛeˆ|{?wn¤{s‚AÙ'–;~)»¶$ªT\i@7§X¦ÃŽ@wæbAoæ^Á¤‹Æ)SÝHq½'„|‘‚1Úχ{Ï!ˆ©‡sæM¥y¢ZCßÙ&c¢nt‰yLÏúH˜údÜçÓ/‰Ð»B¨¬xÌ‹¿÷‚ú¯9äzy9<±†jW/„½ª‘äh9’>”Ž�î¢oh>�E³ó–SKÖ[ðí¿AÉOïÒ«fPl4žö޹I¯¦0­º4ôµôƒƒJ`²\ÐLÚ„Óqäáã`Z ÀW«1k¶À±‚-~]cÑ|Œ2¬˜äÃÍZRƒ‰¶"‚õçÙáʰþüŠZfO[β¯ÂSàÂïw|ÅÑ~0ÓAÇï“ÂJ~íÔ"ÁçX¯á,#õÝË…[(ÁýñnŇ‚µz­ÀÆÈ„夾cW«ÿ2w’ ÇÌýx}¯7ëÖÌb7Z+ò'͇žÃžlw̺)™M!|ÓüJn�—AúÄ.–�®M^C±T%õ�½úÌ|ï@(jÁжDâk¶£ëïðRk†¤Ohöi‡­ÿ>ÃA.æ,jò»í +=*N›CH¶ ?™†áË¡P4‚�ÙÞ Ê×¼è�F)wBÝ6D̄Έd²¼ e›OP«k |ÌÃû¦Íá\ %Þ¢uZ¦7·±­.ŠðUa9ôœå¿×cä êS6�®ðG/_¡Ž?¡ìoêK�SU†�Ètb®ö‚(í&úk¾õ¨CÛ•#¡Pÿ;f?›ÌÄêp«ë|n*Nœ9’�7� öž�ÅGpNf«i _¬5™þþnÅš}ŠlpYX ÷;æM²ï’Xäë]ð¤86ʰؤ–ͪ¥œ—“áxåG®È4¼=ìÉÙÅc/“îØP2É͂ۅ¥8¥¤¹—îðlè:M­“ƒˆíØš[Š•�QLû“¥X¯v· ʱÔ5~• <À–�®Ð ÄýÒÃ>ã—lRÁm×FÜ8µœ^Ý0¡7Wì鳓#›µŠøÎǡԺ•0ó?-¦8¨ ^kÀÚLs°ÐWf½Æ‹`½9£oi£±�Fãí×3@éöZmÀä–ß1ú~?�Ž'@Žß[´¿ÔÁÉ(Ý`û¼ÎвwUàv# �Öâ—u1pDX‰"”»xë„&öýµ(Îè¼ÁþçèL£zü¾>,š4j”F‰RIR}ï½KФd ¡ÌcIŠÌ4¡‰JŠ” BI"Õ½w %džÉL$’¡Ÿ)þ=Ïë³Ö½ÖÙg�ÏçºÞÜç`h>éß<�VÃp¬… ÿìž§üÁïô8~ ÞÜŬ Õ Zrãù\·ŸÇ.ÁÂC�ôïÚ8:Nܹð8jÈ:ÇÜ-©±)Ô‘d͵ñgèÔ_Ø4ù™H¸÷O;~:(FòohÞì�Œªç°}çHþTj�Õ1Êüåm些Р‹¹#-œÿÕôD•‘QøäR8í½®á|ÍÒ�ÛDà`†ÅÑ3ðpËQº¡q§ ¹Ë|·$ã�¥kY²uîw‰Ô×ñÂÉrg<}Ý‹å“f¹Ð.s¼;eÙëµÞ’ãÌòßÂá†eBL¯p¨{Ohá»ÐB�r“7Ų—º&ÛXWU}HÔå?ÛûŠÍu=¸tZ�0º*s°ð}JKÓÆúHô*ßKk}÷ãôNmþoz3]ï,„ËnmÂíO„«´xÌ›jší)Ï/_ÎÇZ•V,¨µdnØÉÅ#C(´,›/¼Ú}ô1¾Í2Îj¢k› ktgÿ…a¦Q¯G ®êÉçÂ&rùóh˜âõ�lœpÀ©£øïø08ubjo‡é·›¸"P -_ßç ü&xµÊr…Ü9þQh�A³LС×}‰ùüo0Íé9MÕÝ'Vw±1À›&²H­ÇñÈ;ØnÔtêaÃJFp7Ë‹”â%è¹�÷ªÏ2 ܳ9‹<——QŒâL­ŠE÷š7´Xù=UŽ}*ôÍË$|4V?ÈZqõ KBxoþ#YL³gšò™®?l´d^›Ç[·¿‡´† ¢ªÝ8bÔGŒ-1…•Ö•q-Þv¯]™òSÐ|ûÞZÁ-QS"µ/uNC«�дr74=µåé­OAÜž £ÞŸàø#ÐMŘ/ͫ؇‡ Þ>J ÿ@Â,‰piæl~þ­'­:ô¥³•Í/ ùê‰6ë_Ò§ ódŽn<Û_/Á�Ò›ÁîæJ’9ñÖÎʦƒ‰½ÅyÓG¡ýò<¾Ym)8Ý3ƒôøsm,Xé~¢E!11‰ï'¡ã4kÚi冣”q…E9M8ù†þ*¬ã/[Ó ôAû ÿ"Y¼�—…f&'á·æJʯºe.ÿ@‚Àp— ºí¬‚�eYX³¤ß´½/,7µZµ«?¨ŸÁR¯“ps®ê»³ ¤ÒkÇDHš†3×qÎY¡ˆJÙSA½· Þ·J廡{èzêUÁÖY­Êéz9LNìïŽ|ýØ7Ú<ô»èuqü<ÊWï€ F«X§ˆy>åVߨÝ?Z¤°Â±OW†£þLãªÊlVp)#©:–˹q[óÀ~üì`€Ž-¼÷ºßêŠÁî4.‚ã ùR9Þt)>œŸµI³¬ÅÞ?š?Së~nKí šJàVi-už?„ÁŸeàê[€?,Í×g9@Ï«¥hvõ¦­§ƒ“KÅxõ÷Ð7#w“q͹û«ñÑÉ/´î± FUÞ„ù–í4J÷ Õ Rä!Æ7èR/Uò{¤‰iQAò®K˜�<•Ü>߀ï� äú0‹/êÉóõÀÌ%Ëèòƒ§�}£mÃÍ‘$滦“ú€µ¨;7‡~ŸÃÎ{¯ÑÊQæxÉМmÿv3:¶¸ëC_?w,�ëäEð¿KS�_p%•¥Ü§—Û�8UÆ‹žº(e²õð*ušðÛ9™Ç]=T½¯¹¸úÛn™šŸ½t)*{ †Ô [fŽâºWi_GÌI†ø Ëàól{z{B�©–Ñn³˜3‹”¼¹}V/î9¹닜pÙ×Ý�¹Ê¬æ??º¾ª=z¦³õ•ýC‹Ñq^R -ùUaŠ–“ÛÁù¯3(ÇÞÆýÏXl2ÙÄFˆ{\4ù¿-Ψ4G�ËiÁÁ˜t¬SÑä 'k9¹¥?¾èH½W›s|²z%—ŠëÖ'ðüÌÝV߆wwÊåì�|N<4]8j™KWH’êaÁÄ'bsñ@ÔxGØSh€ïëfÐþ¼–ÓúF±}Æ’Ñäõ¨Üuô¬- óyöÝ4·Ë ˶&Où3ÂבҬк†ç¼=7Ž�æ—R.dÜ =Í…bY3Ô30äÔ�4£¨Z´87ï9½T=gaÄ1‘ÖôÞ�Á›'ð‘‰&øÌé’5 ñk›#íZÄk3Æ¡ö‰Ðøtò–K,W_„yjKñ÷…³BÁø}öÞI+{aÖÇD šÔEŸò‰=�¹ç¤DýoPÕy1R¹�ZÿDcàöTŽÒXta ž¾�Çigà«Ê\²QíË/\ÒÑp�ŠÏpïýT¼‘é€[/ÿù]béaE|1=�—ûc^×H~¶ÉŽ4Â8BÓÇ4š±òã›âr­8 u9;x 潺�8s—2Ëfª–IÚFIr>Âþ©²ø"ÌB.:�±É`ù5.|½¿wøºˆ¥ºÖÐñú6¸Üˆ¦+÷DVhi'žZˆ'MÍIáì;ÚßxÖšêðPMGV­µE�mú¨·É”eÃ:ë@Cl…¨c›�îW†³áñÏ|¬»šËG(¬ªNÃm_˜¶ML¼4•+§h’SA9üðò$Ïðµd*oŧf÷¥m— „GŸ7±¦Îc®®Q¡–ÈJ±âüVž^½�‡žh€«þ±æÑ9Y>’U^’ÆØ»p6ÕÝ7ºr‘q"e<ªC}×Jj ï$§*˜vøÜ+–ç7RéNÚ6PÓéƒQk#1Ït5Õ”Éó¹=|q^Ž_¶¶Æë–aéä,¬ê³öèÁóÓ#AY&§UÆã�¸£ø!ßW–�]•c†MÃf뉰xØWníc�?Þ“¬Û\À>B®ÿ"ißJqJŸÝ¼wêE8o´ ÆÞ¨âï÷žp`]§0kz¾¨YÉ+Zäpãø±H¢æóݼKe,Ö`Í-¢Õü¥@ûR@wÍTè”XqÓ”uؼ:äÖ%Íqà«àÔõÞÝ­eÚ¸¬Á V{‰ïÖzÀ¢êPªò`Ïf[¶õ8ÍQtQUY�ž‘À­ÆX°W�¾iÊ…V»$ÁÒãi…–œ’.Ù’� [ʺ`ÿŠ:ê9b † x*y�US¦ð]_AÁi7”+-›ý¶ãñö•¼%´?N¯ù¯z}„×Ä`½V*8\¹ÁÖƒ^Âæ€<&í.ÚødƒŒÆÉnç>Êήڧò;· ’¨úh ž¯%–I¹ð’#ƒðÆÀOUÔBUù˜Ó¶ 8-ÆýÁϱ`u VZ âõ¥$ ðÁq“ïÃU¼•-¸Ìù�g؃§X@MjùeõÁ¥�¾<þÇ®ê)ýKx_öašÚòVØßÄ¿ßøãÂâ[tÀõ'�M»�¿‚N¾%Þ ¡'y™ÕÕWRxrO%g]»FÑ­=›ÇN³†ÅnÁé3~¸núŽj.¼3š,«ÐǦAü¬0Y,Žô§¿³…[n_Iãæw¨/EO>Ù³œ‘¶�!ÒŽÛ%Ø. ¦WùçùÕSE*7ëÏ9ê-Â¥˜áÏGnÄ`\ì4¾0ª×,b»Î‡Öûméh¦¬Ïªf3ñÊ„B¸ðÓï*­¤-ËoK¬p&¥âßK‰ÝÓyaU2Õ(•ЄuÖ<1B£.ÝôoÛBå™ùøÀ-›vEÍôø „ËlÃ%r!·voõ=C®ç¸¢ÇÞT;[2ç´#×;“¾}.Üìsukö‰y‹¯’Mß�ÝC‹•zX’Ò$ %g˜áVÛÕ8Ó·;zwóþ&š³uª3WŽ“å¿‡F!ŸÏçÞCøÌâ2±£Iÿ˜ï&õ˜�`–5#.Þç«wiLÙ±*æ+¼qxAJÁµÝ‚½n<†W ¡Uí‡ñãÈw’éj¯„Ô$Ìx*U³Êa4n´<)ýfÀÙš–^»“$¡20ííh<¬=ÓÅ©š¼·Ù�Ë�Sin î)OõX;µ�2]ŠÐ̾RtiÔ„WÀAe�…†wýÙ¨ü’8xpm]yŠJž–€ëR]4—Ï„·3~ ÷^´Añê[Pô¦] ‹çŒÀ•6wi[þXü=:†¾¨….óQ�jÅö»jãñä>ÌKÍÇüg <°ŽNo¦‚½ó^0y9ºŠØ´ó‰äµÉ*~»�%’ÊÞ]Ié#êY¿ÊŸWz�@ÙöPh{—Çgö£îxÄ<�Áaü M‹zVø£äµ:­J“¿ £K®ˆS6UñgóP”ÆÓƒº=pª/×(¦Ø�©×Ãr\± aF\µè7I}#¾œŠ pJë0Iµåcƒ*hÈ’˜¿_Úú[×�Ùõv<«ª7jžy ªª0!ißž©ÈÅûº0°õ æœOå°¡ªìë0‹UJð÷‚0{ð&~©ôý%.”Pœ)îÈ»AsÖ^åíѱ?Nê¡ÄZ“Ä�ÔqÉ��˜˜pBÎV–R; õöc0ôk» ½â:®“½K¿õÅ?^÷iªïOl¹;À³ ¬}ç¿„Áccámä(Tä½1Ñ0q…=\ýƒwÞÊðµð,ýlqS„Ñ3³ÑôÚ{xõ’Ž)´àò!Ýó^qMܽ0¼sÊ é´ø@½]3ãú̯¯^7éì²]/<ïÑ—ú<5D¹9ç üV Ûw-ÃÓ�¸Êc¹ðľ…»Þ«³Õc¼ºå š^Há&›�˜9V]P—¤snܼ¨A›ÏhÑx™>=σÖ�!‹èz!KÍ Ã{öåy§MÀ93 –‡—Qÿ‰“)´÷°º“ÇÚ;¬1þuÌy*‹Š²†¬ì!˜ådP…¥Ødþ€^é“©zŒ6—�¢ÌÊ,º`ÎÔꤟsÆð뿇Ù%ä ½J÷þ ¦ÒÓV4ãÛLaŒÇl:1ÛŸóÎIaöí¬ C/SÜpÜÁÌù¶è«¾ƒ.ÿ†/Çß!ùÙûøô®HpÍŠâh»‰<ëž™îN…¡ÃíxUþÎ]¸‰tËs[Æ]‘6>c£æ(Zº^™ËÓÇJ†æ$#—zØ÷í/|ø¼«ZW&˜I¢ùÛ÷ÁømèVÔ¿ЇwÞå÷\ÑõÎ>ôó5®–ï00Ï€Šd¿Kn�Cm«÷p©ÁGιHa¯2à‡Ê{ªlú'tþ¾/–yyã|ïDl;Y½Èôzè]†á—Bÿ®„­”Äœx·Gï1ãW7ã Ûµ/±Â¬€"|àáLÆÁkŸ‹ëد:3 SÈþææ)f<®ÿ'ØÜ§™ªROÒŽ¡êÝ*PéÇžBÄ.¿)ܺΠ״¦£Ú£jÌéÉwEISX9kï¾Æ:�ûàñÆ[BÇ©y¦ïªt$“rUéôýë�ûv/1@Q#¨q½,J½ äØþ™ø«D «f�îléfuëãâ€Ø8±w´û@ãÌÑfø² ‰cM‹/2ÔÉ�R ëgÍË©‚“sÌ)F+Fì»‘Öæ÷Á—5aÖˆzÖ¡"xšÞº^-Š·¿§ü“·!§ý4¤;U�Åä&QÕäè»'½>':DÁ9ÙšžH9ý"X.á=üW”B¦?BÍ�…X8$Œ—7;ÒœíkÐûy ìŽRÄ"�Gp¶. Ÿ-ç¬Î(Ntòá=Þi‚û«Û ôã»%¬&x>kJªx üN4Ï�e�Ý¿¤” x!*}×QãæTJšo„áµ Q:ÏçHá€�7é�«?$þ-³'öĈòB:óxnN0 ÿ¹z5«B^бFEÌv�§«bXFª?ú¾8B©Z¹Í¢A4é¼CV•3Asa7Oö"¶̺¿ˆÿeï’טÔoGí{ +«'r�w 8., ¶eB_õ™Â”sôuΘtÕš ì*A¢éCÑ-ë@}ìqû�@ªuSÏÙÀÇþ–à(WŒõC_éølT™ »¯×¥á8Ö¥·×¥jb²FÂÕŒl8S1D)Õ J†Óêë?3—Ïâ€6vl˜Å�Š.¸a\"G.=Ó®ý£!ÿ"xÈ„žè\œGMÿå‘‘u�˜¦ØíEÝÌðŽ ­¢±x�Pý=ù§¼hìÚu øÍh.ûG’|°ê“!]ùôªŽ gª«‚"×m|SñµÕ,Àë�Ö‚yÂR²ÕÝN[Z1j—7¦Ý’ÂÇ瘵±ˆVÙý‚K9;pPú{Òš„ áÖ$×Còëëñ×6=n8„Øz(�ó¾sÙV¼0=�§ÿéÇj;R`»ºŒ8�_�dÕ7‘œ¯Ð – OÐøš³¤QØŸ�PçƒUuUjþ§»¿sŸ§TPº—2fOzD?²AAÍÝ®½s|sC¼_/K?�áµ¿Ý òÁ 2ûz rMžÀÿýkõíð*ñ@×)Œ‘º�2Ÿ¾‚íì‘5ÇÏO ׳˱ jóØÎ†¦:hRnͲ¥Öx¼|Þ¿G˜ Ç�ýò0Øí>™ÎI'�ÄÞ˜©ÊWO)àŸn|=6[¬y‡å¡Þâ²»ßÉT±'ÓPmÖP2á ×â‡ÅPøæ#íÉÿH'Ü–âeS¶7ˆÄúAðÞùͰZù0ý½yÆ R]z�ã½Ó£)wˆ�®d•$ÀuïkXŽŒÅ¤³Rh±qgžï^qò<àVöÔwZzÃýyÞ»2›úy¶ÒŒ]ŬÎäqsöŠ­kͱ¨¯ŸäÊÖxPV%?„£lGðå½…Ô¶ý5ÄKª½�{à~›‘´æ‚&îâøkÛª¿võçÀn¦\Tb„ÊÊ-ðòèDeôða0j?í�¯®Üâ€ïGñH\Þÿ ÕÊöh©,E=)Üۺì�pû jƒÆó€›§ákšGuòz�Ã�?1/œÁËÉ»Éèòp°k„še+ø­bùìŽÄ;WÕ$CFŽ£žÂ_I Ço£1èæCñwm 3gó0äɧ¡ð”�OÍà‰Ý.�U¥J¡hÂúÿ%‚øk­ÄtB ëx¬¦ÈV^ïÈwCö‹×o›Àé«[`óævawŸ¾øØow}ë }—�@Ês”a�!œïS�Ÿ†‘d5[’m§w‰Û8ãåHÕd3QJ¼¬¬ˆž??Ó·¢Aô蔃påój§Û_ü€¹Ã3Å9}ÈB'‡žLpÄù›�U”#?¿æe‘ƒy!ë·÷ ®àe¸®CÖW÷C½Êd˜f‡¬è¼Š=V¯×ã»»÷f‡ßŽGARaNIÀ'ƒ ÈS\c¥œB–{Ò»50`š�TƼ õ 0ý!8øèaXú0ÁçCeI—ÂÆ O¾rc¬°,f ^þw‡[myÛO¨üú þ“æ³ç«E•£û±õ½3¶Íµâžwô¹t¬ëôŠA·®›°ƒ¼9år”Ûø¢÷?YÁïx— =qfÖq8¦¦ˆ¿£ø“†¼Z>¾] Šãtàå«Ù˜}ì©fx’ÿŸm¨4Î_lr=Š'Ž¢ë�ap>Ôn¦ïÄN{mŠ©=ŠÆudþ¯eº?ÃÒ†»prÜbl7¨€…ÿzÔ„•ñ_‹¡õÛj:ýÆ'&¨SLÂ|¬v¹C‰Uïhš®ìi,OX¬cë÷60Öd?úÖ-äº1Ô\1 g)Ú c'GòýähT#�Ë/¨ã‚ÉÆ8>CeV å÷Çþ šàüê£ß/V'ÅÑÅ•ïÀ¬`˜¸ë~ͺ³:_}+û‡tg¼¼­FpÃÞ¨4™“¼=xè±2§ÏžX3Fƒ Ò^¡J¼ FÆ�¢ÙIiã‚õ”ßЫöj’ìsž�>½b¥øó\egÇeùBýWM.êÕ?»`W¹Y:óý;›D¥êÂFS[B+Ý/ôËô¥SGÔOÊÔŠg”„ÖEMôäýr /ÝOÿm“å‰+êØç·¢ ø'±ÚrW,þõÑÆxUÚ.÷™ö¥7Áo©2ü³V‘ÂŽÄãÏIŸ±ñ’Èì;�.õ/¡uc;͕Ӏ\ÅWUæ•)Ð+ 6œ¿Þo£�r#õ[qO\WZ@÷ãÕqFÐ >š¯‰u1Ì&÷ÄÊɵbl\· E]K¡÷ê¸Õy¥VõK{ JgŠ(sÝ)Z®éKV*vf`ƽÿ$ÁŒ Éä¿-�¼§ŸŽm‡ãSQܯÇÇI�×F£ÉF¸?^˜ σ׶ ³wíáþ±¥äù¡AŒþDx®È’ç ¯ÅC3}ðçuCN_³[¢¯e ƒúͤ—§±íßjñäž³ä>{:ü¶B7… ë-yJn¿:—ã´¿×9"ö3”ÚN9_GaÁ�xÎVTbµ¡e‚ë(4�þ:ÅghþdŽó³åÍ£CÑâÍ ´x˜ fŸA׿éÄýÃXS©Û5Ęâ>Za³#òè‹÷=áÓ„ãpÞm/µ„‡UøI A©Q‡]˜ˆ¿{\‚Tý)hò¡»«Gþÿ{Ô3¼O`öÝÁì"B`©#ê­96½S. �•»ý=Ê ks² Yç¡øS©Üµ9[Æ�}Nž€ “q�¾ú‡pò¿©Tû"š­j'�ÏÝxÒy•Ë{‹1»<‘Ã> Æ}Agš'™Vªá̯;ð[�ÌÓ�oo¼F b§�oëkê“éA•ßGᎃ�ªCF*qÓY´P½BƒK¶áÙ¤j¸}æõx9ŒÒ å †ž»t39Fýš�þ; b»ÀÍË“ëæÔ Þ¼Þl–l*f>,6ÕÔÀµ¢$ª×óÃÇŽ¬4,wÇ© *oÂ#+>¿LŽ�Ê{àÈqfhnšAÚ#~ÂpGAÁ¼›½dp�rO³6?GËñà@��° ÌÑ×iØðd§¾½çÛ�?ˆÂLhzX E{WÐý0.ã÷¤¸H�at6ìÿ¬ÅKÏ$`?›¹ëŽ]¾�ž¤ßÂe{ËÅÅÕmT9¼N2²>B¬@ñ9s~AºÁóPšbœI eFSØ [¸µo éLÄóM8/9�*ÿ9ÓSj�~b#Ú¾ µÆ�í° ì7ÉŒcóžÑ�†fJ¼ü¸ºu¬6ë蔣Œ]0Ÿ]<¡ûì�PÍ"�4O„�yY#>•’çæ@pa?zrׄž¯#ºþç@£åå%úñm‚}ôpì_•E•GËÈUÖ­:ü|v_#èÙÓj ±Ð>…k”Nrhd¼¤ý(ºí…°ÂhÇÿ.‡Y‘„6Òœæ© ûúÐmÒ¯Ž\ïC_ï]¡�#ë1Ò{êÎÏ»–ä‰1ó‚±Ö`xF£àe§HÇgš%£å¸úC-ïlƒ;~�ùàŒBf‚)�‘¦ƒºKè}¹ F/‚r�¼ÂJŽ ‹°·Çªˆ9Їê(â H}.ë²dÍbàä\;òØ œ­†Z)ßDW�BQ„�ðdÇiÑjü, ƒxñÐz2Þ´·¯_CRO«è��êîÀŒÜ¥ôbŠ'ßLiÛMÒ<¥3™[³OQãý4vÒæ¾äÇûžPXW)Tµ)Áí—¯ã5ްX=´�”9©Ò<Í�‹[U¸lã\ö¼2�$]É8çÆ1±Ø[ Z‡òŽÏæxÐâ&¼^Z%~-þóߣü­� Ðq/~VŸ}~“Éà"º�#ESït ú"Oîíßè¨åœqNÈ®£�/b â+áœ^>ùϸ%T¸Ï¡½¿&¡ß•"PŸõ™,üt R^‚Ã�O‚¢ûFLÏÿBš/уk9l¿¢öop£^÷¢¹cÃ*^mp¦dÃð—óYZu ÝßÖ.r«YçYvõü]Aܰz0¬—-Ï6 §'& ‹Pš#ä4xTÎEâVü!k)7@OG–[Nî� x²§TØ®•8ß¹7÷Ç'1hêpüòó=÷ RB mÇFIýh�QÊO¾È4zóª[!¤.Ó6-ã�õ©ÂÂÃQ¦f1Œéu›¬x;^5퇺S�1Ë@¾ú©Ažˆ4ÄKa ,Õ�cãî\‘(Îo£u‹âÁ¥ïA<¾g(ŽÍ9,~“�ÿ’%xcÕHùr0h^^]�£Ò‹ý´¬ðæÑ–�©<&Y™ïø·ÀjÝ(¼ ½ŸÖzàÔ�ÍŽ­u÷…õ‡TñÊ''<_ŠAÇ×r¸¢RÍE÷‡Â�£ØØ› h8÷ ­Ÿ›‹ë¯kÒA‡éØ5¸'8¬áüË»]¨•*ƒÅ VÜÒ>ˆî¤L¥BÇáóÖ |§GÜ[«Œº=vuA¹~O¤“ݲ”%ËüñE]ì굌%‡ÕYÛd¤ŸßJ·ÔxH„.¿ø“~ôLä“ÍAvc/ŸÍT¦#`ÑÛq¸Ú£V²®¦ÈYy°.¥ÇãP.Þ0Ò¤VÑ–QÛYzÃq˜�éˆ|«¸ÿG§°@§QHÍžBý§öÂÕ¸úÔ3HÒW§³ç|qü”4ø2S ?‹ãÛc0Ln<*؉֋Ù|ÂuÑ/r>½ã¤Õj:âõñû{c¸öñe9”€Áàå´ˆ•x“þRqòô‡tÿr®T™d˜›×]ƒ‡–…ð´-Î<ísXÁ(ŠŽZ5R¸½‡Áñ8ŹëV�¡jæ°Ñá'-2ÔÆ:mÑÿüTxôd WÞž · ñů(ˆMUƒ³ßFò—ö…˜ªÉMÏò83;ô×ý,ÔL¹ &Z_©ãÔCˆV€Ks¡ýçvNw,¤Šò§4Ë8eöŒçêòC˜ùú”è6ØÓZzq/e'Žn·„UÍmtû¤,Ö¿òÀ°±Ø=ªˆ­•ñ™ùhÊï=ˆJS¶á×­§ùœÓt*š2„‹s©~w#/šQÀ±WÍùÀE/6ö[Í_KwçÓa\¡ÝFY!×ÄÎ/*¸åÀ �VÇï[—À�ħ$_f�c6]GéŠÞ^ ÏOä¿îú|Ô=�Y¬ÃÆyøµa7,³ÄM;Çã�´ù|l¶9Íz¢�v5?ÅàûHå´)î\œ‡–+/ÁÏZ(_¿’¢§èó�w¬O”çìˉ˜sSšU> À®mû°n©TÜh¢ÿæÊQ±®Eõ’6s¾=|.¶öNC«óã±øMm2닽�ýÙ^Eåÿ�à9Ч±éäãÓƒz,~ͪ‹Ù¥6ˆãÖì�½}2»û÷ü{4°ÛÇ’Ä$ÝdHØýž”'÷FåÚ ¿p7¦¼Ú Kwcð€þôàürÎMÉ XeÙf�'O€¯Z¥ 2R‡…#–ÕO»�àýªÉüIÌ0é'XZ ÁÞÎ~ø±m8š\„Щ'qù;ní÷,ßÌàÌcù‚™“Ëäˆ|´ØmŸ6,OÅà�ëð¤Î$–—;Ñ©¸Â趘u"϶ÿ­7ÏO”¬ѵ˜Û <¹1˜74L�ó Mø¾×NA5ã©à“…þÏD؈Ÿ`è =zÇbC‚:¥ÅýO�x^Ú+Zz%é–QV]LWî<ä_Úɳ^P>ü(ÈÆÌ£†o™ÚH1üá�nQƒã�­`Ñy>y¹Aø|1¦J54 êæž{ˆièu*ƒt]šÄ•W~F uk>4:îú'r_íMü÷Ã8>¸i2WÞ-=:“é©Í8Õ>wþSÅ~ºOyOé<œe«G?læù%}ñ�ëqr\6\Ø&o¢a÷Ž 8÷m'Ô%Æ@™ÿu1½?X™EÇf{³ñu<«±Å�IPbJF=Þ�‚û}±:m» £áÿ±jyÙb|_=>úp,Ä¿»NYkFþÝÛøB>ñìY¯•Ê /½Hº_› Þcg`gRޏа—Ön8hÞ“g�.\õœ{ 9Häôñ@Ô.x*sgÁGë»0ÈÐ¥<rÅ3}ñç¯Þìlª#|=‹Ü cå¹0HUŸ¦¯ý�„‰Ôµ¿\�~ËX7ò‡ø|GRw÷¢µeI¬{ôLÝZ/ÆÐ¥×Ëðë7x÷¼/äž?Ç®Š�`ánÍ–^M°³ñ­»ÙFÊ ·«m]NƒjÜpü`—CEý´xÎÆAllẊœxç–øî®þõ-¡WUçýƪü`g’äá´^ürHDŽ­¥›�Û@¹ç ê:“H­×ÑÀð/%^ìökó'yÔ|û•lz0üûÁÏŸ-ÄâDCÁl¹¥àñØ™?9:`û9ij³ÏÚ2Í ueô_Q‰Fa™n®¹þ†šd¤ñЫ<åB*dY­Ñ«ÆÎ5ÎRü5ɉåDÎRåŸÁ“Øõí0Ⱥ(¤EÇP¾ÝUо?œL}©c_ ßàøu?ÀÁi •üY…Ï:?œ½Õ2‡lÝriÌÎzÞ—³‡.¼ÕùAçe¢ðÊÜñØ€£âÓŒ¤âŽî‡ ëÞÚßñ…ÂV â/½Ã !d¿x!W¿¼}MöM€“òE¥1éô%þ794u�LèY±Õh!Ô^‡×ÇöÒp÷FC'ŠÑNÀÁ;v`î¾y¸ƒÆ*†áig |ŒíÏÓË�F˜^ôQÈù¸“T=NЈо0ð¥»pkM!¤[Y‹ßCýÄ™ëŠèÆåÝôã¼<÷ÎÌ7’Çö;U[;å©Ãi H÷ÙÛjÏs}8¼›9 =£ÙÒ:Ÿ?P&-)Žÿ¦ 6²ü÷úVq“Q4*í…v˜‡gåÊŸ.âìîü5qþR1´/¥àÑåñô"|?„HO«¦Ä~¸QŠX°qêŸl½öÍå=mÓàÜhåêž-NüݸPpU\ŽwAýÃúñÚ²³ðOß™�O¢ðÚmüýAÍf7ô· ³ÜamÏ�¨¾�¯ Å; �ÃÁ‚þÂ�УPðCŽߌFùËò¬û,›��h£–è>‚å°t°œ×ƒýZw‰3Ýf´‹Õ4fÎ_E©féX’4˜7ôÆÏÙÌG�°Ïu÷‘ãæ¸(,ŒÀ=_ú³^¡‚¾’ÅrF¤Æ‹ÂìáÑ»a Ð"�'½½¹Pý ,Ò Æ�·}xÒÌ͵׻¬+`À‚G0úb¨è¸ÛŠ?ìOÝc•xwŸžT�%Þw-‚~�µàÍç~œp|2ÊX&â§“È]ë'ÍIs×£ñB«Ln)WÇÚ›_éÈÓôÐ̓:ЗÿIfkëxÑ©ë¢xåÙWZÔc÷¬ºÝñX©K§N¤q—�;ŸrŒ†¿²‹à{©a7ß©Uú?t”@¡8·W)›–�ýž‰7\_ ÊcŒØü¶¦­7å¯ ùóµÁ˜/Käý>¿ö)ÅC‹n sâ/�UÕ˜ñ胸¬-zþž\×)(¿*„­7sQùþIñ,ý†z¡ô$„­ûÉjÑZ¿{LN³¶çRéµ^˜'^%‡EÆp*j‚÷ŠÙ�²ãÒáÜ%ßûoJ„Un=kTTêÉÌn1ÞmŒ§‘4oö-Ç-?ïuE]TΛG‚QF­¤ Oo|8ï…[$ðí KàÖE¶‘ñe¡¡Î]rZ[â6ý6{ÜQ�ã$Óó‹¼6Ð�ÊF+²]ø9¼Öó#5»¨@†J%ü;l+ ½çÉ [.Ð�3;à‹G†�1QŸGoÛ€Ž.#hœídÖ•”ˆ–© pnÆì “Á\'YèðH¥²g“që…»ÐØo'<¥)­…ò8fôU(1ÑÄâóhòã”7…�ÕžC0ú§”ÐÛ¢Vø�úÅÉ®p´˜wÓÖ¼QæÐðñðkõd®X …ú×SÉÅä4h.˜„�)q,uË�ÿü·'ÎcódÑVN ‚çIÐPê5 ëkÁ ïo¦³ÇöJ‡¦«7cÞ×rÐXpFn(§/þ¦´wz"[ÞÃ9¶½†d/íñ‘}2¿ps d Lò½”ЫòÆ_ž9ÔaLÇÎäõ!¸ü|{%jS’ÈMoë­ïS}áÙb89„`C‘={í KNü»EwYÉÓ·zÇ É$ýÏF([Ñ¥E—çü} LêÕŸ³Ê–Š«ËrÀ¤ùIµó‚±dêïÆ“îRÀÜK`¶ai‡NŸy‘ï;Mpzª(,™˜îz…0Y]/ ÐçÛ¥õ¨³ê�êP‚ÊD>² åÅŒ¡8|K­ðcÝ4ZpêüI–à•=\³m& )Ð�cF¨ˆWî6’Ê‘ÇPÑ•Fù…Jz]Žõ¦ý£g‹ÖóüY6ðÌ]‡~‡4Š»�xÂãÔ¹´5 פN4ççcý¡oV$n}5/[d›áÂåÕsÅóú¢¾þFŽ2Öf‡âa ÖÞ!tÝ1Rì…†§W³×œ! v®xT¯¦­½þ6‰²›^J"þDÓ´‚™lXz/:/Æ)as¹!^•OÍØ FnÇoŸ3ªß�|ð- ž÷.…´ž ’ýYûåfUå_œË«'ÐÊÞΨX´—“N›°é¾!l^x‹­"2éôBVÙêÌ}®,¡áGÞˆßäNˆª¦¨ù€+õrIõ›#áÕâYÐ ´#µd?&ÐÏâ¥TÐ|\t‹vÅñªÂËß)ܼ+F¬©‹¡^ö·©(Ó²ì²_S/Þá¶R÷l�¾iýp⸥8`—mÍÂÙq’lé�sñbç\‘æ™DÐ·Ž¹¼f¡Ûζė'z#\s­~çð\·çSü"z\uCÒZq ž›£Â¶iOÀùwèßÛ‚ïT‡²½ÎkÁêºH½V늆Ÿäq�‡¼JÍ3]œ6߆§r†ñ€2ó…^¾Î8¬‘³ÖvÀ’û}Ѩy �.9M}×­¿2k>¢°Ÿ<ßÈ.ÉÃø” ¡Á•3€^ß#`¹|š]ˆ… É)6t›Ð¬–-ÄÇÕ Ñþuä´}??ãÄÿv¬F_ÏÿhIÀVqÙG{žêñŠž„Ȉ6# ×爊œ!.•ð·nW'îÁøvü³õ(\]“zmo@Å^GÈÞ\¿vÐ³×Æ"¥„Ñ‘”†dT¼—ÄnÇ�³.¸"0 oú½‡¾kv‰þr»¨½e Z¿ÚM‰ùÎÔ{f4�ÙúœìFp¤`€ãçwBŠõ ñÏ=5 �þ�Î=X‰ 55ôZK…ZëHÇ0 X�“+²©BƒÛ®\…÷½¤qw²õ‘"žVÕ6§ŸÃÅ×;øÂn ^j »Gh¢L‚Sõ—>%0­u;ÚÖÍx_ 0ÛMŠË>È€î—:´õ”h×G2_Ê¢ÒØV覀¦VL…Èi­‘ºè=s6¾‚gûê}èô¬\Ú„Û…{·SÙÚ&>Ö›³ýi¡àÛ,Ú9„w®˜P™¡bB>êM°`¤›Øüã(<=,ôÜÔ=/�Q<©¹B\–åòË)¾e~¬Þ[•ð(�o¥8é¹OÄ‚«WĽƒ~�»S I;Y@×®ƒ’{†Û$ÁÿUSËnO¶¨ÍĘìnË’¢§™J¤ôM‰?5æˆç‚S¡õv‰8ðB™˜1O?ÔøbÙ´Ó˜ãnŽ !Ë—ã—Ih¬'£Û=!(^–?+t»©þAjå8 »›ö™îÀÎiŸÉ:~ ŸÜ× á•åP:¬ _ˆ¡‡†Ð“qtÙ*M"µó5fºsÕ|1ïýDL6ö£ù!¹Ðμõd𮥤)¾%®YΫO´ÀÅß.Ø©7Wxµƒ‘±{nSåY‘Ið²Ib�ÌÇé¾A¢Õ ð#;4"í—Kð‹ùQ¸{ôâ�Ij�„¿n›�Aù‰Õ�þž¨xòøºþG«VD‰î"©GÜ(¯ðÀÌ»Ó~¾¤Ç–7¨öòú#kÌß—ªó�OG¹~çpï€4:ÄoæÓ÷Ï‘WøDºëÖ N.�Ü´J4_Ó±ø…�öµæLÒDÇä÷ËgÇh–†FµåÁC×!èaåD×¶(¡ßÆq7Hí/Xb¥‹4W¦®xmô<8 2âGcåàC¼ñÅ1qçË/DC±ö©ß‚±eþœ6?~Òäøª½|o¢+Y[çWYÄ&CXÌ$î£ú–ÂY³]ü%ôä€>wîQÆ÷¾œó°{že3臥[œ¶Á{Ž“¸îG2ôŸ¿], ê‹Õ“ k÷ÔêeòÛÄPÕ 8ax%�˜kŽMÿEð³å¦ô}µß»4†xñ…ÎN¡óÍÁÕ½?æÍÙÅG–š³�üVð)­'WÍž¸(PšÂl'¡ú?…nHÅúô·äâìOMgÎJ²7,¯^ÇÄ1÷­`GØ*¼ñ°TOo3nä­�‡à粪٠¥+CyrA Ûô·'Ltá^Zaý¯ ÚዾJAè¤| Ê']§±úÆèoS)¼¨É'}Ç;óÈMΔÈÍá§J×áIL®ÎÓãœ:DNt€½óT9¶Þ®Ùo…šNŽ LdÃç~¤¸ä ˜”>¡ ×~‰›!Ž÷~ÿ+ÚLùGÞþŠX{o$÷Ù³Gø1t>¥–σ×ãè‡áJÌò‚Æoàå×fz~ˆÂå¦ÁÔH_üàõ‰¦ìÃ@ÇEØ\!K}Û#ññÕžµu Ì�][ˆ/{a€é½ê§«[h°¦5nTC�aìÚ7K´ÉàO)ÝWlÓñðOá0lýwŒÄ._þä¢�î÷Ãaà×Ù˜±x �mí¤GÅóušìòe~uì†èJÚÃ7®DpÛ!îŒnkë\”IÔG£�+Å�½|ðWT!-ïñŸ¸Yw?tœo�üŠáÅÏóº?•Õ÷_g‡«ÿ($>‹Ž¼�sý&rŤ=07CM<|žõðÌõÏ…�ðYÜÏN…çÌÝ$^."Ð]± Ï„.`­àS¢‘‰:ÚõÀÿÍ‹FGöxÛdŒù>§y{÷‹±M/1cK ‘õA|ô¦^ï•c/¿  Šûà‘¿>_zÃ3^ðsÍìãÂPpè ­š‚ºï‡‰~Ø,þ»´ ϾûÅæáÎåÿÅaÉE’QJˆ¨(Yù<çH%-MÚB%-¥$¤"" %% - ñyÎ!%Ò0"MIôM*Úã×ï?x_×yŸû¼îë:ç:wïÑb×ê`õÚRIüçÕÜÖ7…bΆþöBí÷=ð®mY$óÃoåt¹% –Œ›=6¾"!b öp̢˫· ~LœP˜Z—°ãú]B;‰=÷÷µg0Õá9-ËDù‡®¬¦4�j5ŒÑ¬ùÚûdÀÀòó¸Îõ#9ÌÛ†ÿü»~ŒŠzN²ó†dîŽ[ðfÄf:ùj’0˜ú²O5<§!‡óû†`—'Cx¤W­û"ŽŒÌçÉ1hÌþx?Ε•3(ÓyÛGºQdÞgøõ` kL>ÑÇðå·¿ÔþÙV¼[NaQK 3RËð¨B£8¡³/=ÍSÆšÛÃàR×W¡ b3Z¨­— e’d÷mxmÑ^z2r ̳q†ëD¾¼æ½ÿe‚Ia‹ñµS{fƒ8}CÌêÖ +fîä Ë“Ð0ºŠÊÞ;ÐÂŒ“Ô/Z…ÿzͦÔçŸ`§vÔé{a×ÝfAf$Ic'ð‡mtéPvwŽ û?¢k×çÁã‘ÝêÉh‰†¸náÃs´ñè�Wsa_ÁÊZíÄóѬÂËPÔ‹Ú¶ô€ÿo$”Ö› í/SØåy´xÓÅ‘~�ƒi‡“Hv¡²Q#-Ì E—¼Ób}Y^½Ü,î>Ó 9MW¯„B�Õùða×_šêû„ÚffÀ9Ÿ½¸S,ÅkNïÈs^«(�ô�rB/þpw9Å«W=¸Ð#AXrCSŒûd)Ì5ò¥�ö^ÐÕQ@çq}�¿c„–&-þ5Þ)ºâÝèÙøøÇ/ÉX™ R�®ϺÛ0%®AÃ5øèš/ý¶l£í‰Á¼sk>ý6ŽcmDÊ~…šmy¢Ž’XZ{z,›ÌßÕëÄ€,î{É t" iä¸'Žvy¯Ä CWÖo§©Z¦fÖV�ñÐ\XþªVûºð­M¯a‡g.¹X 5M¿ÄÀ¼ÉèpÐ�ø$³u¸ O¹#n(Èÿüò'ËÑ‚Rz:qd»ê ¡O ÷b-ôqÙO‚cwh™Œ޳1%©Oµz=¿‹ccÍI5ý9uîê­Çૃ‡ ¾»÷•ïI¹ãƒië›Z^»ï/}ê™Ú?G@Uþ8Ü©hÝ!¾�ž@‹œØ÷ûA˜ø¼¶wF@`Ö(<,ù"¬¿~Eè¯ÈŠ#&ñ›xv,G1çfð3£¡Gîuqõ®.ø0ã(Ø•¥À•Ëqá ®û*òòºøÌ[v?PâßAWiu¤9†™K=v=“¾4õ…‡»œ9øÁkzØš@La�¶«ÝTcÓŠƒtäƒ_yw’ØSFƒ] ŠñµÕ´¾ANDI¯ÿRÅÉßä)o}0'Ywø•;0\v%m•» ÖSß“’½,®ë=ùájŠÉû w«ó%®f&\/;ïÆ¢ßA劕´ÌGqpa¹ä×ož{b”ÐÞû L´ð¡Ù}Q»« zÇP†f—àþ3J”è]€;ÃÖw~¿=\|¿K›½_‚ÑÎHmfÀ‰ý·Qç¢üÚ¥$ñôN#•{'LýÇã ZwB/§]$¥½+Eõ áJÔcÚv¹˜F¬îÏ‘åq_Ñ+x“ÚÓÝðDilbl1¿E+Þ¦Ša«:„×ß‹)a^4Vþü¾7+}†ôH{ˆ0eë,°õÇ)|?ÅPØjÐ(Øú�ê.QÐÛü8Ñ—ä¥ ¼¡é˜ß÷Á¥ß ÈnǼ°.‰’Rè™Û~˜4¸“ò^Žaµ¹{ÿÓç†my°)6U¸g}™V—ý„gÁö\þ,Ž~~r�AßAËù(ÖôÀ]?<è¡÷r½¬®ÿ>Bsý·óQƒ:üoÖg\ËþDã«}pØVüU›‹&MC× ´ýl,·,MÃŒ "±³i7zk}”D˜œ€/Ò#è¶z€xzPïQÖgŸ[±p3oêV'rWýQ{Ì�,Í<±xèFz'/ǪÅc ûB (¿9=©…§+w�ý…Z¹D^ÞYÌ ¤d\Ÿ=Ftãe#œ¡ñÌA~#jq^¦?öÊäŠ-oȧn_Ütƒm‚^ÒbÇ"¯Ñ‡ßÏ}H½nE�sÄSÁçp2lÈ´U‹$ŽôöÀ›ï‹†záì:9-Mä/:ýDƒ?gs}à× Kœú0ƒ? ˆ ÝËbÀKÕ��Ÿ{H¿LÐ9ZIÜ{µ«-4CùxÌBtÍ'AÔ„r!ðZ‡|Ç~¥Ù$®�Ç�!2|¯ù ,èwMµ¤ô~òJü±ˆ:_åÑ€~vs'ëöà�+ŒÛô‘>]ùkª'sVÇ`Ôú¸†Îm•’Jyõ¿!^ÈYƒCy†®x}ƒ§ðà[]ºÛç|W‚È‹?avu3ôê?˜n]Óï9î ±òü9¬Wh¾ÃEY™ÀÙQ[øAÍPÞÚÓœ{ýg¯¾©ãÁ7ßÅÚkÃÙ°ó y'yC�²Ž`‘ÿ¹�$m;g¡ršZ7;ãÔÝÛá÷Æ�õ&[¸-7–Êó_éà×}ÔxUG!\KûLôqÑ!tß슯§¤—vO`ÊcEì”ñäÙ8¼‡¨mì’\¢}”» ÍôvCX�<ãÇWé-‹ïÔyå;yOˆT3ñY±^ajŸÏp4Ã’ìÓV£’¯•zòÖi'ñëb}>‰8¾ëŒäpq¶ø"Õ¿XÛÀ%›#ë}“ínöã§ÿ%Ã�õ§Ù ûY~t§†ôÙàŸ_¿¦±—uáØ'] Û8Ž{®( «+·á¢öGQÛHŸm=Kßì…Jÿ\q¼^ 2˜Ê~ÃËÄ“�³i¢Ì.ô¬‹Úü¾%�>ü;×<£í­±Ü燌ï×[âôù…ìjÞ¾¶Cßw‘JÀ|ñjC¡¤¯oé¼ò£kpU=²©ð]}~VC‹ ¡xt„>Uü=wôÑ>r:½›©ÁÇc×QŠ^%ìÏØ %Ãͱäo¾›zò•j…I³%Ò²)bÄ»|Š·5GӮѠ2Q—o‹ ÙÀɆ[ž·õZ…^u•´½_OÌžhÅ™ÿúÉv®:¦7�ÿ—‰è¾W tô>!5îÞáxÁT�?<χ»ÁYTÿH4s›K™)�Ðþä­ òó"ù7!ê�%§E¡÷ª¥œ»<Ž^ŽÒ剹þâ._]¼³,-ߥÓÂ)øiùJ¼í%å^› Pù†"žuê‚·AY´¦w?© HvÒÅÓïž\–çÿôbÈZÕooŽKoX‚oS(Ká›ðÇÄŸZ^‡†ë×vZ¾Ç’¬r²Ûú§ÆKÜ “E·Ì•rò&zfá[¹m‚—tû,‡äpåµt*i->V�}z9 ÓPAì^›MeqíëÁ\ž^C×á¤äí°áz1Õ$Õ‚Ë¥MØz¬7FìåîƒÉSƒÆæpÔñš�çë0Š3áËÅFjÒ‹…9½pØ_e!vA ØöôeÉg2‹ô5ã›âÓ¸'‚ŠS²ï$^¥ª�!çõ9Im=‚yïëñYr3ô¿5’Gx¨cxb�d€gÝŽ¹Ì.&×Ŭó«À1¬–&=lÕÖ÷Ť֞Ü-¥ÍBõñ‡Ó4Ábè#ñ¶žOËîþçÈ!GÀ¤v±ã¹ …ÛõGaïm_îÌ�‚•3yeƒÛ�Ç Ê”ÔM}�ŽRíï—tÓ"šKÖCijMÔc‚Žp¯CTýÅ�r^œ½@…_äAŒÁû©0'A_Í~-ä0nY‡æÈ0\׆}­§`§$ôª2aÓ™yØþ, ý<>Óÿ÷^ÚÄBŒïXlŸÉßî4À‚•Šä»Ò‡2OÅBáå[üýG´Ðp›ŒúðÂóÚð&<&ÍêÁC«þ«÷Hý•K)½îÂrÕtÔõÏà+ –dï½P!r™7«^‹Gã‹qp*&ÎÌqà¼Ç‹hÓ{e�µ["ÜÓy �ýrhÓ¨Óp+i&[Üö#u£"¶nˆ,‹“TÆÅ wü2rÌZ„Z¡©ôeÀYhÜj‚›FTPê:5~�µˆžþ�¥S¶Ïá{d;¹µ›“Æpkö_òrp �qxóüP`ÿ©ÒâÎÃÜk¸GÖô ¹Ëy·q(¬7U§‹íÓ¥&¹½�®œUG½„í<K8¾O´ÆG™«yÌúáøëB6��ñÀÂøÇdœ{Fð¼%‹%Fº˜±¬ úK¬éŒU*_3-å¶`ƒ6z/§N´Á�å1G÷ è°Â‡Ê)uù)âõÏ]7ázíx¾yÚPØøï¦j¼# [pͱ›ÛÍXÏ)#=‹Rš(ÝN±›åà¿ö�h½‰2Ðû=%Ï0G¾æ› ‹{>çF�å¼~Ü,Xøn ÎP±BÅxwaÓu”üšŽê“-8w[D”*³ñ¯ó…ã¶±³\¶XõQ�›®͸±zš"žˆÒEÏá8é˜>ô=Ï=Õ’IG?„GLïÛËñïêB�ÃÚ¤çëÀAtø�Úè¢úug4Бg ü¿Ëüp}‹ûïÊ ì¶­¹ä>IëdœŽÜ]B“ï¿¡©ëšIÑà=)8»ò�šdø2¨'nbo·å*Jlw²ÑVÊPÌ&�T+œÖ}½têK0�ÕC½°òŽ„nFm W•ô»o ŒO¾ ÇÇœ~n÷ö<±êŽœù‚•wâp…²:6£#�xtJœöäF�fÔG�u·çf´S}U û'p¾j+Uû„å{îÓŸ*<÷&ž¶~�N6ÍçÞàÁÝyØx©Uªåû™f¸"Mš«@êSB íÓìYóØi®1¾!¬_O�ç°M|Lò<,&¬8,˜«"<ž< ]É.TŸgÀÏð�ÚC½bÎAåÇî\6};ޝzJƒÛ¢ihoò¥A˜tã+yvÌEÏÑKHw¨ŒXó`8矺ª¶ðå4Úôl�Õ­î_Hv÷vZ€‡îšcèç9¥ÕQðO†&ô‡ÛÿHÇ^Чi߯ƒØp �¸0zùDŸ#aËB°×Óâî�d9 &…JôFK¯½) /\œü·„t‘Íq ™|˜Å»²¦â®~9Òy×ó·4òèA¡v®oV  Â¯±ŽÙ»&ˆ.^‚Lc¡ïühžvÒ€kmt9î¡<çJ|ÓSÚ⿞ rdÿ‰çqа?ŽcÕþVyëaãädx`²_,®—Œ6ÇCøÀ’ÂÛàúÑ 3îÌEaµ&¿«3ã‡OÌU—¡`;vU\k£2õ_�ð©/9mÔã¥7¥7Cûò0å%Tðäªôú’íbšÆrtYžÇ«�™Gзޔ—|¼ ZÜõ¾ J^Ÿ¡¿�ë'!½=ͳ-¸;æÐÉÌõ0ÂyXÙ‰ÿí1¢Ìv8R}Y<°£�Ì·5‰¦`�OG4‰y9ÛQñdéš ûÙxáÞÐÞ´êK1Í\Ó,ºÎÑbëÂ*xº³ Ι/‚9©�„�·AOc]r§—Îá çÔYÅÁ=ü{³ÖdeÞ8ò 7*åI:f>nK§)ÉidÚ8“ð³E¶h´7»_Æ�ÚɆï+ §b2í‰�»õkÅC¾Š¨ãÌþ´ïŸ¸éóòà9hû¦´Ú_;†dûÓþåö¬;ã3$nîÎß‹ô„ßÊ!…¿ øý�‚:7î‚Ú°vú>‚ Ìãx~L"4 †öô§\6‹Žù)àK[¶ö„WÎÛ‰=rU [|Y×zÿg;? —Œ“àóÜ®¶æ“›áÁ©� ¦�ê’þYj‚ß›†bh½¿>±Ée`pÙŒäw]qüÜò—{NºI­…ýí¡Óš´óe%Á@ŒÑ �ä7³¿ËT7F÷Ý(%Ó�ªÜ–‹g®¤Ð·6lãwMð±ê�sempú¬"°x0 žÕn¯ß„[ü_ˆ_7DÁÀšbñòyUaÍÌeøÄ¾¾•›AXÞ4˜sîèIÞ�Ûð˜¿,¹O=.ÔxŽâs ¥9KE½:;j2¬r^›½Î:CçŠÓ†’þ:€;z– »:„²¹› ù¶:§Ì‹³•ø[ÒY´hʶÇ`Kè9zóô&¤Î*›Üz0âhœ„'9%ï\‹ã�oäö%à@‚/ü*0à% ¾“I['ëëÓIj"dž¾ìá"Ç] ±Â€ [xíƒùРiF>kwÂzç=`g~‡*V|‚”íæÔô6�=Ví¥3/Æ`ìtmœ˜lͶý^ÃÄ¡�?¯;Öº¼ÿî?K– ^p3e¿Pn” ÅU{Á£e W5µÂm…~ìuq/í¶ÕÂñßç�× ‚'¡ ik�G-χ’7ð^C஫î\7s§°\)÷\ž.´æ*¡Ã�.˜òîø©ä’꾿dkLo7xñÊÄù”¹ÅJlY³–ÚüâøêS›¾ƒŸé7HrgIÎÚàμ�°¡p4 y,ÇWbfð¦Çeµ\ìýÔ¼-Sí B½ë'ˆŠ3¥vëÅTb,ËóÒŽPÅ6aEóÏ�«€o¥ Š~O¨Z¥Lg%K |9°ì‹ÔÓo>þ}J�¿KÀ³›Š–F¸ÂþÛ?HÞp<‡H~ qRÉVÝcâ%“\�c‰¯S”ñÞÜ>ôÑíè%Òã[£¹¦P‡¯W µ¯Â`KW0³4�´?Rñ[gœ0íÃzáôÝ­¤•¦MÊMa¨U}aYÄrtU’áÓ/ûÄy&’ôï'ɼ‡9n2ÖŠÅ7<)Ú-žM5ÙîQ— ¬l‡.b�‰+YqíBþéZ,$x‘n·¬:Lç«*¨›åHñÓíÁ8óÑ(ÿRp-²}u›¶Ú�-{žˆW÷Ï’|ÿ­òæÍ�°û4Ošjý&óÄBSÔ,2€ÛV’®Š;ø9¶û£r\?¼°ï.A;á(È÷\Áƒ}öâ¬oåÐ=ÂŒüX±ŒÎazpþÛÊ…-0#Nú ¯iz{\¦NgpâZŸã!èjŠ·l®‚ìÏùÜøª+Ž‹%ÊûÐøÉwÁ �n8áÃÏZ›¡¥Ò–D÷âóZÇ[�›ÂÁ½�‘]%˜¯3Æ\•‘¼«‡ïÐ�„j@,}œ ¹Gd%–Fð¬jŸð˸ Î<ÔÁqÊo…ðapmZ�ñÚBÊ%SpøL¿ôIðÌm·å~rÄÇ1U’×–ïÁs¡!/>\Pö¿Ì;D.ó†p—æ~Q+‹ÞzÛ`ì§þ0kéUÁ/O�srjá½Þñä?• uÁ¬ ¾TþÉ�uu6‘ƒºnRò¡Â‹ ¸5§Üì? oeÏÑÑ™úü @–è\OÉPy_ô¸íÛb ûâ/±£Ež?ë¢Z×2í1,nö“>¿³'®Ë>ˆ�åO`cù:X7ü-Y½û_ÖqL �¦åkþY�£ü¼ 3\—^t�ÁÝ/[hÚ«ütÐL®ØOþ~¡àM6EÞ^@«ü7AÝ'Eûb0Vßq �=T¹`ŠUÇ¥#�²MSøöUD¿øã�2'YhýRVMÙ’Ñ ÍošÄƒNjó|Ç*QauiÁ\4=è‰�€k£z¡ÇÓ»¤?·^ßl…‰×Oá²W@]f<UÑÃ,]0³º.l;äIW{¤Q{§©ÙJh…Ñ5š6}$ú¬ „åSJ¶9[=*~·½H·†LçgÇrxÔÛµøý~$<ðO㎫ Hî¾ Ì?³Oµ¦rïûãQ©t8ïQÛ�׃¬ðÄŠÉø¢ã�бb7·Ÿ‡à5µ‚gæ/°T*XWV ¡¿„kš�hìvfŽë„ÙµIâÐ×¾pt˜üì(‘4$Éi9­"… R² Òä_Ÿ‘&ËÎÂÉ×zÐãç¤j‡yC‹3ÝEÿq $g¨Å#Ä�·m¥�ÙË'/ƒ0SÉçe1k¤ˆ+<ÖÀímµ0ÂhNz2ší†ÏÁáoÊ…y|1ý9ŒŠÜ®÷iÜEÆÎO•�èûÌÖ¾Ìß–¤PfÃ"Idb�´3(‡,Îþ¤ý% èÚÔJè=*‹gå^1®ƒ^~3Ånf9·#TxÒH¯Œð ¢f=àï“4xÁ·aÜx :䲿/…�7¥ãÔÏ ­sÏŠ+ÊL`¬¢ÈZÉ›ññûlY9�Çš;ós�ÅlsX„ÛÚYd8Ç«»Ö�µ»)œ¾}�®O�ÁáqFÐÿÒea¸s&þ™ð‹Bó6²cÒWЏxÆkDaöWV_vJÓÌðwÛGji;Áóí¤›Tɼ_-™ô­¡cÈñ¸.z˜÷”éFbCy‡ØáÏ}z ¯Jm\P-ùbÝNoü@ðäß”S*‡½¦†ä) „ýÿXQêô”v>܎ÁâðÞ¨bØ�SÝæà \ƒ[V<"ùšH”èÏß9ð(³RAã‘>”MÂ#õ…ˆ“ŸéäJ ìå¡�Uï×ñýÕi¨¹4UºxcŽh3[–+¡D- êFvã´ ‚¦¥%Î1M°ïØ÷×ÃìÎôé£9×õ/¢XCÁ1ºxÒ[“Ï)£kJýùžeªh¸aÚ,ÏòÁhÁ+Ì<ëÅÓ.•À‘´C¥ÈÖaU'žZq¯`S‚‚8ù×I„ÁÀ«þþ¡�¯:i}\ø­5ÂÕþ?É-F‡G©ã²Egy½ß¾ghÀ??í¾^ÅãCŽ»9£ {á�ä!ÜâdÍQ… ¼ËøºPñr>+½ –uG‡]^ ©4„Û4u±Ì$^o¿ O'‘á¤Á`çÌ—“ñ(_-ب®ŠrŽ:~¹õ:ƒÆÁ§Hw^ÒtEX.ïË_î”ÂÚ}çáxH?¸»K³^Eá†wIPá·—´–™ƒ×Я3à¹p%ê¯ØëMÌG@˜œ _|?†—?~«OžÀÝéîøËÀ ±à忯cR>},F2úà"Œ±/¦Žé“ú߇²‰Õ;<B\îƒåÌo¬ÄG�*²\FÛ·oþ»• ¬¯¼Ϻú�õ©ô7M Þ‰KÚ]Èäºå×ÂQmAdü\|`~‡Ý\o ÒG±hõéŠð¤Æ]G•ST³!¯Û§ˆs{Ýá”…5äßcÕÍ�}õ ø®‡)›>o„ØØ3Tn…«ß^‡ö$jÿñ|'¹ÃßÃÉ0jx>4ÿ¨†SoCM^ê7Ñš9qØÀßä;y˜Ø88R®óRüïù´›6�kN„Ia £?3ωÃÊ)xÝ1X¼¿2¥µàøò+�ŽÙÍ”ƒ#¶%C”Ó|ȸ¹ úžú#x÷�Áñ娻zí®ª×8ê˜/r”÷¼4³,€î87IõV† ãšC‡Ÿp¼º»L\ŸŃ ]Ø÷ïZ~v�/ÿ@ÙÓ�òßßBÝQ7žq Äìíü%j%�I 峫Âé¼Ù;ñ…Ó0¶P<„>¿ Í‘¹l�ÿ|: ÝýÐ#=J.-ä>Š qø´ á¶ÑºrÁŸ¿¥Ÿ·Ràeô6lé{ÌþŽ`çAÊ!ÝA¯ö)þë½›e8èòT-´—Æžz û–¦ã åT¯í†©gΊ»\úp|×;¨ Ùj÷©èg¥7(c¯T l>> UÂI½=ù“«¶¼£ù…ÿr|ÛU>Ö+™ÓÞvÁV“O0×-Íä*¨sõ#1ò€¸ s$g<”eCî‹OÎŽÁkõj`�²”L?m—^;5€ÆØ à ÕY°lÉcø�Q(x”ÅAì�T¬ñž Æ+aaá)ö:ØFïÊñâ+œô�¢×îú¨áµäÑ#]�ïÿºE¶ æaÿÀ´é„<çÝY�k-k©%9ˆ«þZÃѧ÷ ÿ—opØ8Í—^mã„Âý7và‰‘ês¨MPØ Ñ FhÆb¨îaìs)e¬Ýƒ‘ÙMðf~{v>G}R¦ÿZ“�Åêad ákvríñ©ì7©?Ÿ¨Mˆ.;/ਢ›9h:Œ»ÄYEÇáݽ“0@ÃÝ+á)‡í0ëÒr<;+Ï~§ZÛÀ8}2ß[÷”·¢ó�çbHd¶˜dõ¹Jtû¯ÇOµœF>Ë'�¹°<1@œ¬¿‘å]K¨mÅIV•´ž ^ïvL°´ì%JžP†ÚªNª…ño"9òøq:}¬�œ"cx™àÄ/ŒqX€zßêͳÆ¢I¦*wGpõœtõÊä°Tœšç†õûPI‡ý³¦û%ZZº˜u§œ! ñù�«°îù'ÊÕ:#\_6Žñúym&t”í®ÅGÁ5ØJu;@_Æ…^ç[°cª,^HТéßöüãøoø­`D5ן‹ÅýŸ‚Yd8œwŠ {›`]Ý9a�ön\` Mr®¤2&�WdËÂ…Ô‡6ʲûk‰�ì ã‡ÇÒ¡.?<ôa#·N1Ã] GÄåæ lÑ 6³ÃiœGw<˜¯‚{Lú ÃvÿÅŽÇq£ûHˆ} ÆïÍŽŠ‹÷ÐÊÊ7ðõÆ<þœö�ãn âH“™X–ÝÆ5ZxsàOñòª\P8£+óëÙ"ZíYH‰=K!ClMö®ã%õF8â¹öSí ŸúóJ›V(׈ڗ‚iælg̺m�ó6-„kqô¢ñEÌ‹rÜ6$Yâw<]¨È{"Äk ç€Z5¶WšBÍ8ݱ>lÙÇ«.äÙýZÅtµ¬9Fõ-bhNÌ®Ÿ¨ÁJ?½èõ¡Ël|ý‘¸lÌ2hÌ) ,ýK°¶Ú ƒß¨C›Ïð;yJì�t“f[7KƒÍâ¾ßŽ@¡ÑBÜüØ\q»0ûI>ΰKÒ¥jP~�Xá¹™påEبN�öôhdÍxjïwN×Ûð›SVø}ÐK°ÚhˆóŸa~¯y$ä�¤ÈŸ}qëûɰó}Å^ާE=SÇ+Ðvôf÷-{9x‡ ¼Ç/×öÁ6WoØ|å <ÐÔÆ˜‘¸ëõeqbù/z}X‚êÞýñðU¾™mÉý]œ!§3 6==(Üø-t;Ó$.RL£'1»Ie�w4_ÇçÝgK{Ž8¨JDëÿî ó˰`ª ¸“@m.ÝrDp©*#õ™tºÙ�ÿŒ¯%[ú6ó¥xöÊHÚ³&ŠçŒžÇ�Y{PñÈ5J,üÞ,ñ°£—6¨±á E<`wJ:)n?ZBÑ5°áÄD4•³ƒ# ¯)ô¬<~’î�¶·HS3f^éOU©³0&c)N{ê�r©?ÁÂ<æ�Å—ó΢Fûbún'ÃÚms¡ÇÞÑä~-ƒëlÛD�‚ƒ¡]MË"±ùêyÒ †Ö÷?¥dˆ%^9èy‹`ö'!V5D@žçBÕÃJ^ЊòM°}̱ßÁ]p6+•è´,å_˜ £iVÿRâ—¶vx®%ŠL&sXBe«å€Ü¾|ʘ_9uâÜ ÊÙ´À¨‘CàÕÞzÚm çmö¦Ú¢+Bæ¸É¸îò$:ü*‚6nL¢1ÖrÑÊvêžb�Ç Üà‰Tš‡Ç �Ãk±÷ê^ì%>Ïë‡�³M°âŸOyÿ·K,‚~™Âïæ÷$QöÁïð¤Ÿ%'<°€±2º´i°#+•'ÂÞ]²(󢺽R ‰^)Äõž…Ë^BƒÛV0ü¨Âww8P÷ÙÐ]«VP-VÐÆ['³ïs(±VÀå¹pè”^=<–ç<š�ÿ)¡~ÓlÐY!/¶ê9РRº›ìÉ.ºþB{c9hçºã×K–¸UËRº¾9~hêcLå}j4bøêëGuÇ@ÂŒq,YêÆ²‹¢¹Àç Ö‰Aùì�’+oï cý°ruoBÛˬeñ¼ù¯?çBÛ¬0ÚV¼‡±Ë’,~�å;cÔ±À£µ'Å%C·qóiÞ÷Ë(ÊÎÅK £±hM4ìw�3E´ÉÜÛ-u¹+å.]gˆ+:Fó•áŽ(ý¡€6¯LPk¸#.:Ä÷NÊaHÛIJòÆ]ȃc™{HåÄdÌ}ýŒž7ú‚߃8WhÈËϳWy:v‹Áie»É4p‰ôÂ3,9¥…¯¯ g鯜¥­Œ¢ãuÜÜÐ 'Œx‹lÅ¿Û)jÀ¸y®¢bt¡}Ü2ºðw»õ[%,—Ù„�ÚÓ1ì· 4õûFéz ”qg~P'8êLåÒ>Ò"‘hYw?ð‘</ÉÜ©õ}ñL«žñ`Ë~sÚɃð× V‰}}/~†ßÛ—ì\ìñÒY{8zdõ��Ä{u»£•¹$e|¥Ãa'ÀÑÞ�+ºeÂÂÞpÿé_.»b\¢>GŒ� æºÑ¨¼µv÷úS>„Ñ«ÞïèT�#Ïy0—‡ÝQG³¢6i�¯6hì‚5Ù|c·(œRl¥I»ÌX½íìyµG{¢Ã=ìiq=¼ã…‘%•Üý�šbŠGÝ‹�£aÄߥ *Î÷‹Ã"Ùkt:OškvqÿÎ%T¼f·89Ç�ï·î’Lz—ƶ¨“wæ9úí;­ú g¯]½áèÒtvˆ>Û�¯Ÿ5ùÄø~äT9‹ªÚÈê‹=®êÞ/èŒÃj«%üž ÚhGÔõãÚÓ†¤``$LÊ{Ý nÒG¿䩪D³m ñB`Ï›.â¸MÄ?Í· «â?Óø×qÂ�/at³R ÕK×á**ÕNn’vúNíØHðñ_*ÙxR…?{Ü•8Úwcÿœý¸Ýsë;â¾×v¢šx›íÞÁs3Yܲ'„£ZA¹y6óÊåˆõ0÷|€ì¤HÓN<Åoá=°Ÿñ1°ñ/Ì Ñ±jÚà}lžÜâ.XhµüóÖ i~ 3çô¢’ÂRìZ)y=^.ºñ½Œ¸ûYKý¼Ý“[" p¹íx1!p"Eÿ¢‰vµÔÓ,�ÞáE˜n%ƒkkŠù÷ÍVhLƒœxWù1=ªƒ¹#*Åd/À´o[áYs.ÍÜUG½®kÓì_gY”œÅ0[.™²LšRs¾³åOƒV ŸS ÌúðÏÙfHéнbÁ¿ñóƒî,�TÏÞ˜é¥ú©¯¤£“ùÞ®V¸¹j*¯éXÀ–IËyiT*­ûŽ}ÓWÒ^·Ç¤—¥Ès—f‰›¿§A·.˜5*‹$ãÇà몲Am/wöYú[Ò}¿ÀB¾k¸—P þ¤;æPŸÃ_dÁíüÕ\`n�ã>�eìkˆE æcʰ>ôŸq>s$‚í³¾ã$¡/ŽVh–Ø\{/¶7¨áÚQñ\ã®À¹Ý²aµßp6=¾�å[½yKª"©ÏNg–šâ�Q·…gi¡´®ûy:~ÕŽ_-½Låo«È@fßx!ƒ™×r‚AýC‘kªC¾½'­Ó¨=hü¨^ rªçÍã Y»x:Uì”çÓä±ÜÿÜ{ Âói¸ü¼«!ÇÞ�•ðùÖ^t2N§mY½PèžÄ_&NaõÑñð3p h59q‰ÑJRžB¦Œ“<§e:ƒx°÷WHt-†ùìA™ÉÓðoþ^Qƒcðží©¼"p/•ë8£à5Wì”H–Sd¹)f:Ψ�—Á}xk°-ZhGñ ï?…úTy2Œ¯‡ÚÍdžþ�Âuíp¢ÂEá†É Rœ'ÃávnøN’€ª_Š(.`4~-ïÝ¡?¤¢]ÀWŠK?SXéšÙߟPÝ£tÐ>wŠ�êRê¥á¼íæQ¦r“F+ôö¢®éCù–â >Ò#”nÚ²þørè,“‹c¥J3\YÊÞ×hÌbon{óI<·t->ËÖã¡GvÒÞÌ«ÈYBË¿üS¾\*6ø“khh,ÔÃаy¸[Ý¥ðÖyÞ_ýž¬Ž¼�‹Ñ‘üR³‡Ó“Ù^ìóE¿»ÇhË _87cgÏ*#£®Q¨¬|O:a‘;MuÁeÛâª}éÜèf¥œ]óJÐÔ÷æBÎzùŸó Ã;Wb×#5,SȤºøzX׌c—ƒÉÉxÿX Ö6½…´¸ tas2&9m¦3+$fûgñÔ¿ Â…²T>ß•D§¢ßŠ�ýu¸±&š¯WÅÑÞdž,=¡ÞGãM_Éààwáúìe´&VûT.Á¨Ñ¨ÚvŒNt“ÇC a4T%Í*j¥4qf«ŽÅ3•e¸$d…?‰$«ì ˆ�ⱉÓy¤óôÞlÄZ~húÐ^¬°v§ôc“¿U? Û¾?†—IVŠÇÏ©åK0}Ÿ �w»ê?­¸ ç»nà‹Ÿ©,¿ âÏ%`ÂåŸÒsáVøEA޵oD²ƒ¦ÛMåï<ׇ¶wÁôÅf‰'=ùâ’“$W™ˆÏé°o³&bêÚ[z˜­ïÏŸ¬q Ù{-1GrŸ¼§–ÒŠ+Ab!ø€’ç0MOû6Hñ@qö[yƒ–�×”^hQ×Mδu^�Kð§=‹àßs|ñW�[.qõ¹`>´S’T?Cð§ È�苽fò´xgJ/4ÄÛŸÃ-mÎ)<!ZÖ2{2$lºF½Í% Ý´C”ËN§úªþ †*PgYIlhLqš&ÚûZ²_Ä_Òy5€‹Ýf “ûéî”RH«|A;: xÝÆv8Vf�³?ôÂ@3 žv_lŸžŠy›ßÁ¬ñ-Ô?L%™C0÷‰œ_µ—~×¢êE-X-×ñϽO e$õoi�©ïIC—¢Ï¾�¤›®+•Ñó×6r,ü—ó��“çÀLL½1 =uÝ¡o“ªxeä:ÄzR¬ùä²ñÙþ�‘'p¶g7–ö·… ££A«$Ÿw†šnqL{/ •éðòÝ1åó*^Òr,ž‹ñ†‡ø}Óìýz¥�á÷w¾S“Z»8óU/ž[ú½öp…Šˆ½ÐãCŽxañèó;�.‡êð´åÍp7±Šþœ‰½µ1>ú ®üW³¨àDöLùL³4­©x�M?ßÁîåPæ¨áô1ý9}¦CÇ^ò¶Ñù0(h™(û«/»&Y‘,UÞ3”/~ÖÀ/GdðõN;ÖP®¤gCdI²Á�×Ï §‡W>‚on *$ý…õßöK,¦d ¶�îÓ‡ŽhÿáAÎ+ýè”\“x t¤XkçA‰�J8翥ا<"ú|R.�IÄ¥}+¡Ï †[1ï»ùìÿB{ìÜnv6¼E´Ä)Ëò UÍ$£Ã°Ò;~549¥cq¼Q7œ>ì%vÝ…‡Ý¤»aƒòŽëÁ˜8k ·é»°®âZÜæ2‘[_�;‘70n¡>‡Û�c»/_!c¾ Æâ0:ÒîdžÙòòa¯EÙ°`¼»”rÖšàÇã`½ë|þü΄ ‚Ê™óàr?û}8…= wkÈßÞ‰yùQ¾äZŒÿ½†VÌ –yRA~M+tL{+4½›ÎʯSxëAkÒ ½,˜ëı ¿@Á$)Ý.­Rššµß1³¿‡Lb߆óœÙ?w—žå ¡Ü§³¦‰Ç×�@Ù€p6]³ îØàý- Ñâr*¯øç(ríB±f1�8xWüöz4=)Þ"L–géÛí,3ç ìeÕðSn*¹Ü+$•×°ìMìqŽ�â¥aã¹½g …ENâ×› ¡)Z±Ô†­£¨þîüÑ*Yˆl”CýDU¬£ù##ñ¼ËQÞww34}ƒí¦Ï`†� mí+‡gàH«- âÊœ®hL_Ö`ûŒpH¶ßÃÚ&¬qŸL;?áAú÷ðSH$Vé{¢ÛÛYÜüà =ÛñŒú?w˜ö&�o-YÏËþ±ºu!žV¹ëÐîÂ%éëÔüÿ�ÍûÚ1ÿd|ƒêSx­Ž¿:&¾zþÂde0ßÄ ½{¬¢°o½)mðgÐZNðºG,í_D­_ ¸êq/±4zÚ˜ž‡Ã—“EµŽ�bÿnMðaIÖÅAíL-ìÿõ NZ{�NHÚ…³ã»ñÊÀ}0+Ëi‰¢‚ßMpó ÁÜëÐØðŠÜgȰV¤ê–qÖ„ÏÂÞõ‡(½B�C×F`íÊ(þ¼(�ç„À7âpW™$ì~ZMW_Âß‹£7™ò½¤$3¢;?:>/hä¥íFø©§Ƽ Ç_nÚ�Qö5NƒuËñšÒ'ÒìßÌ1Yyì-d5êLéÏ׃‚1cM¹Ô(í£XѾ‘·Ê⯒‘Øtñwî�Ö»Y¹·Ug¸qÛV„™ºÙp¤Ê¯8=±ç7ðÑ‘ïµq¦Ü¾~:F¤¦QqÍPx3 ¾ÍRç5.½�v¼’aÏ{Ûi°qÿ�¢óþæòã¸MʨŒPdYQQ¸¯ Ò¤¡A%”B{I‹�Q„ÑRY)T*¼ïëRThÒV‘Æ'©4”Ô·ïðúåuž÷óùxœó:ç.™4”Ó— ¦þëá¯njoûJs¿æ9s˜ÅxοXG÷ LÑ\g<ÒpÛÆ…üéb¥ðõ[%=ÿ¤‰»º�(°á+ürJƒª‡§Eµ|Z¾'‘W¥ï{Ÿ º·jhš³ÃÄv�—´Çe$·÷$¡ÿÖ5hø\Öí§Èá9W˜ÎÃ ÚøYã6ù5§÷ÑÂô²%0î” ?9ÝùÏÛnwuÄ�úYø{….[O^Ì·5öá°?'¨t…%/ý¯†T¯„ó +[êµÆ³Û,X*ÁÅ#Û¨ª#•œuŠàõˆÛp¦ÍZ|�׋!i=O– ½ãÏãæ«í”ˆz-Åô7+—ì°å™¾Nÿ֮ Æ]ÏΑeM&z0Ãå��¡£÷Xl5¸CÆ£4Á3^ï�DŠ}ž ÷-và›5ÑlÖn�©)ü¾rX~ÖcíN¨Û;…;¾; ‘Vz¬ìÃ-úÁ•\¾y°B!þ-(¿)šgõç‹ã>‹Ü“(nÉ¿ìn¯é–×dl>A2kª¥`è|ŸE°³8†ŽÅðI³ëؽð²a=¬.„µ‡G�ò^ ¬R9ΛeNBw Qz¡2·µ[âö´&aGöm¨à-hPkÍ7Ï胖f9½›ÄÞË.Âó€~ž“G>Ê °|yŒ}i*„vLá+?c¨­çPI³ä·‰M4X+|u"1ìa%½{Eº:{¡u[¥°éìHˆZ6*K¶ Âø Ø–d+ÜÒö¤¥&·aÈ¥Í8sOÕ¿í0ÀóÂYøÐpžUãÓùdv!µ†pÓÄË$ÔU�[ˆ+𛩰TégŠk\�C¶‚u`&¬�Î9�žèR>šÌœiÏo-vá=ø2¢µ.¤—‘v¬>ª¾Ë(àQ±’Š_ÉðÕµ#pû�ùà÷{—JçÂÃËÛW’W‹+}_"tGXŠ^wzsVW"¿Í6àk)A(åbŽw*ÂéóïTñÜM%Ü6Ý‹®*q•a9Ìó§Ù½*IfI½°þÕ\ð8*aÛùÒü¨Hšƒn>´€-Óx…©)ë\†=ÆsMM8©Û½‡ùëúH†?_/œoö!Åúbz³6‚—÷WÄ[83&Š¥œçÃX¥Aô_m3×þàÔ–"žÕFn_žS°—.�rN¡ŠÇËYnÎhTº‘Â%ÇÚXjz£À3Šp´EYþë£-²¼%É�hïÂÞÛñb¥¾™ý“vÌÊ„’Õñ0bÿb;�ÇÜ�ãÚ¬e`*k#„°2v©šsß?Uè?_…OàeŽ{Ðvs<>å�(9q²k‡sŸ^ãÐqÚ Iþbþú|,ZþØ:ÌŠ{UîOþ¹#�ÓÙÊ*ZÜ÷®’Wú¥Ý\—6Å£_EûQgáJÀhz#½�z«ã¼æd~`’É¿5·3vÏÆâa±èõ¤D"wíYÕÄôÞ féÉõ{¦ãµç2”è+m©’ãÃKÕ0ð�:��÷øß öç çà ÙòuVÂE7d¹ìf¸Mm…‡¯Réw}OFÿ;´è-è=$ƒƒ¾(ò'KK­Å¹okN‚ïËpä¡>ò™�!‹¤ñ|ð+¸tÎ;šr�‡ºCî¶�‚Žê4Ì|{Ußþk}AU}>ÕH!‡©K8±D·ÆŒ¡ÒóŠ —šÆ×&sšó-“mþqÁ¾_¥ôWYî—-~™ìä7×OÁ@]'a@É^:ùy ºýl�ïÕ>8*V 5¾€©y"^úÛW¨rÚ*ìxÑMT+ &ï–™|Dû¨ÜrJÈ·ì7¼e° z©ë:ŸÝÃô{˜'²�Íi½ s]—w Íuz¤¹þšÄ&ë�бY�—‡iÃBá-)e~/ë‘löÁ×ÎàðÄr.±È'¯=É8VæºÜyCÊw`]Nœ™ŸÉ «éQß4ýâ dZ…6JWQô¥pp¾z™·«Yrâ(%úV2œ— ‹až8ϱMò¨N‹~ é… þ;©iÞ!úæñ^<Ú~SL³4¡u#wÒÓåE\2¤‰\»GÐæ‹28ÐÆ—s+t×L‚WV÷…TcZX~ÔeÊÉnf ^ª”B÷¿Ù4®‡ Þ'w|3e‚à×ÓŒë¯iÑ09Y _dAëûÈQgÔ$±GQ;M9œÅæ¡ñ¸æ÷~aú•DñÝŒ"¥áÇ~Ú#ÄÇcO’Ê<ÎŽŽ‡A«Kðem>Œ^lÄ©IïÉDå%iŽI'c¯bîð9GoE‹ZVÁŽ#GÅ©ïÝPÞ$œ®\ž·læÐ-çè̇UûIWnÕÈ…îòÜ1Y¤™;�ÉãLÖìM¾´’Ùóo û}>_Ð'(ÞbvGB~v¾x�ªÊ¿Ð±-Çi‘ÛÂ<`<éûw‹÷ŠZIIa›ø˜ïPæüN°AÉ�ƒ¾‘Ë�ýœ¤àQ’›‚å·yÜ$,‚Ôm.´4/ƒW�=BóFáÍÈ)({…ü³dð˶V:b,à‡s\ræ,…½ê�ªó츬¹ŠVùKáÅÔ} ò–‰(×…•†2¸äöµZ'Ò ¯›.»¥>ˆ—Åx(ú¥Ïãf�lÏ0ÃÝJÝÂãg›ÁwPnÙR#»¾ÑÝä~¸ÓîCÅ�Eƒñ©ÁŠr-qzåO²£3Ù{è~6žq‹ŠÝò8¯×°Çx'þê”Qc(9”Esß ÓB˜hÅûà¢a*úï€ÂuÈ»¶Bª¥;šŽâµïƒõXK‰Ê§s¢úí5°i¶3'À¹;½0|z š1Â�ñ·°çÁß�Ÿ3[0Ê †µî<©î�oö჻¾ÓŸl}ìH’�àîbpn”…6﹜±#^R�ñf'D‚¶ÐGbe[nÒ*¬Z톳~ʼn‹Ú~ƒAñnÐÛÓ“Žÿ­ÅWßÇò)M+Þ±à6ô~ñ ƒ ¹¨l¨£õîºö2Í>Êcè ^(XyKrÒ�¹UÇ‘Š}§ B½DLh›Ëž‰äôýå?ôàM‘³Ñ¢´̾š ‹.¡¬·:e¼ušŒ©6<…çŽ�w:º_þö½€ªsýh´8‡xÄcöÄnÉžìÑzŸöðÚ¥ú´(ú“Óô’ÏTš¸–m÷�ì?ÓpÛj¢Ìðá†uEÅ%ÙN¸~±|ö.dÃÕÑT æxóÂE°—�m)¿¯E¤’qÞ~z?mKŽRf€9Ú¥žàù£‡bá²bò^õ‚¤ÖûÓ-éÉx-ZuNfó •bÁÕ¨ •¾Ñôˆ,Ñ6²�¬ý–â�¿� .Zšg)„“ +xµçu1ut°Ð6Z k dyÏ 5|‘)ˆ‘y7ùËÓ9¼¸Ã€šQvÛ½&•4L# ~‚éç~tÁÇ Zâ�þ½ñÐXpð܈¹¿Ã©m|2«[2«&^Hëé"†ýcÿ­3Á·PÓù<Ù[»>†°šo¥“Úârº7ð)}ú¤ k²4èhôU¸;¹ 'ö•áÑ™)°Ôâ:ØúÅPÎÓ_pyí~ê9ÅM;ØÛ[ÃÑ_i“йu¹iÄ[ËÒ(ÖõYÏÕpÎÕ»@sŠŠ�‡%…Ñ%Ü]ɾq£ÙáAOÜ|n%ô Ø!:mx夑Yç7YAÒûZJ¹�ÍkK ãº*&<8 C©ù}·ðbøyt<:ŠW}@µ;á¤7f¼Û†~ÿÿߤ~šäË 7†sšóQ¨ùq‚ž<‚rÆCS™¿•ï�‹´˜4ªkiÿÄf˜8m7—ú)W–Þ_‚í7GAöþLI“~"�ø!X.MxxŠS³£P飵Úa]¾,þÿ­Þ Ùx®—/Øwܤ‘W“i³]ª­ŠâÇùêœÞÜB >AªžÆž+¡[ßZ)Wg)þ–…Éæ(n¤#MÌØckÈÌY HŠÁ|ªì’è‘Þ]qýøSTÐtgï�$hù~¥€¤Õ¢Nf4Þ�#{û½dÇ�=°oÆ|ñBÅnNÍ•Ã)�á<­õ%„]9„«†NbÓévh3¾Å}�5åà]9§O}Hëb³0qäjüDg<˜ÌŸƒ~Ð$ïNQ‘ÍâÐã¶¼XMŠ÷þ‚­ƒG;õ®æ+•ð¼Ÿÿ;Ž_{UàŸwpmW/çI­ßàýMW|_ù[0ñÕÂ$¿|h|3œƒÓqí@ZóåœÐkãFf«eà{9�”zcÙl©C|,M–ç©§Ì©ÎbsÛ¼¿}½rRp˯ KcÒ:J åS u‹%;zi–Aýþ@zv§¬?Inê8üýo˜ºë’ðòÇGP{RÃicžâÂê8Ç\‡ÕW¨ñ´¼p¡ÿ_öìAke(fv¨àŸË›°æsGküØ�ÄWg †à÷£ù —³ûT?Þµñv›HñWl�¦Ý"ïÇ èxsk—D€fÌ@ÖÉò(Ô ½†ÏFÓ>ñ¬žlʺµq¨wºVÙÓ7}¬Ž‹b™2 |¿{Y±û¦ xÊh†Z™áfŠäåF=ÑFgŸ ‡uýÅV…fNÝQŠ·K=ÄŒuâ)=þ`«ÁöSÆãÙãsyÐm9˜Vœ {L'ˆ�"YõŸãzyŸ¥ë0Þa&y¼´CÅÅäSMâë. ò倷Hé_àÃø:š}"šþSøç‚3 ÄËC®Ó�ƒó9Ü?Ph èM¯òÂHñM÷ql”‘Ð÷ÑÍFo¯�† µ·Ä�!G9C¬ç"W[Ê_�ï6Gcÿ¥’£ûfჽzØéfÎÁEéðÐ\™Úž!� ¿xP•6FM_…»–L¤…µÔ¤€/_�‡Ò©9°h‹ βðáÃk¼…È]–|¸l+:¬ß±8Ñx,J�Oã‚�W ©Š'žžÄ±y*•k,ÏKfÈð›eH1:š5=&‰¯›þ9ƒì6Ü“p>÷k¦LÜÃsî7ò¬MˆpéÃÉ&Et&S{<8E#ÆþÂÒl�®;ò{v ÅS#ÝùÁÚåP±è³¸¹¡ˆ^ÛÔÓÛˆšé²š å¢ù§g*ä,ä~KÜñeE*¥¶¸búæTjqŠŽ99°Šçxwë/=ÿÐ*ÉÕœGƒÍyÊ«ðßK?Ôïû©ÐöŸžÖÒƒ'�úBŸŸžt·êczX(¼k I®PyÆÒÙ`ήFßÿåL 3GÒeƒ£°¢>ÖqÐüð7ÿ,õ�{ '&yaÚ”å=�Xo`4šÌõ„Ç:FüsÊ\Þ¸é¿ ¯¯_‚Ñ·Sñ¡§>Ê>HùÇsøÐ„[Bõ»k4`åf¤7‰ßo‘V]/œZí~8"ö�xíÙmzdæÁ'áù¾Ó±ûE©°ìÉ^šºy^³ÈFóqÙbÅx]ŠïȶÒý1|¬,š"ÇÆ» œõ0ÇS~e”³2‰ïïð ©uΠõƒŒ(‚vMSáâyß„«äxâ«ÿÄSq 𨭈N?Îý�œ¡¸Þ)ˆŸôc›ý{ùWž?ŒLw‚Ja�‹1Ê^Å9&‘=<‰s_�þ´¼u(‡ì Öó’w~¸Îv1½ë÷œî�Ã&/U©Z9ÌiÜß=’Ô{®s6`‹¬ÞY© _“ãØòÑ3òò~,©ýçdÕ·Ñð~8·*Ž «ÿ ƒ®ýÉÅæ¤0aÃR¾òw1žV½!:^›Áýi¨ƒÊ­0ü»z¯pÒº ŽœþLᓃçþw”TpI8-`à?7¾y-ürïé ¥¼ånlxê©cüÚ54ØH ú‹ ôû†�ÀlÃt,ž ƒ«1rb2~ÙÿGpX÷^,[¬Ë‡FÆ _f~€ó™í¢FßN˜r¥XH97�¦Í2Çè>°jÈ7ê9` Ï�] §Û =ü—ºg‹—fÞ�gÇsäð·ð¶J‰á0"¹í§ç�2üÔ7›cÒ·8ŴɈý�äG—gò‹êzX¸#VTðÒÆª;2ØsÑÑÎë(ýø*�š†ßÂìØÊzi…sGq‡¯¬èªûö¼�»óXŸUEKéø#î,\û¡ÊŠè’ø R¶‹t´³otÖ9.%ð a]Û×BʵŸÔ{*~Ü SµGcôÙXˆ09‚Ý’—ÿÅ;Wý;óy"ËŒõB=™6¨ÚùºïèÂjUÀǧs·×eÉûɲpZϚijŒ|½dQÇ=6X­M‡^½¥š×¡ÿÜÒ�&P…Â[H?!Wj‹º¾0b¦ÎWó�äbU|i{ž®nÆE¸m^«S‚�={ñW¸ºãD[ŸÅ�¹l~êV\N‚~ƒÀ ˘´ç#ÎÊ“f}ƒÞØKe$¸>)¢Ê–›ÿÜZ„ e?hçC[Çõ‹’A-Ê&g ‡.%,ó5Æ oípþ‡›´ü´ Ô-¢9Ïécâ?v»1õTú�Ôºhš.�Hþ׫oHÆ™?]ôOP—Å[¼ÖŒÏøH£ìÎ$ÞXà }¯F嫪l¬:W]qáoE—º¯‘dΔÝð[”oÓcß«ç¨ào.lmè…~¨FÛ•9ÁÏ…ãLõ)ßI íØRЭu¢®²Ó¤ºTCœZŸ(äßÓ„SBc¹z xAÇZ¦ð0»xººÃ˳ÕX}ƒ6?|öCüœÉz±ð75ŽNoM!ÿ0 µT¥_2ýÑ7Йë÷6Ÿe©ë£4·Lx ºJ#áùžçBmåa ÇK±q^±àë;žw�¸.ù32 ·OÄ·ºžtù«kÚ a�Ã:A"nH['ÔŸ¨…•å®ìhíÏ\qW¬y1Ïå8B�ùjḡ=¼�,Þœš>ªã ¦–ìêØtGï@»7ÅÚßSÐ&“apGLÚr˜îž9H›ÒåYKce¼q2+ûzµf|ÿ½+ë­éˆ] ·¾�&Vݠ政t0½Pg$LÿÏ„�¼`¡¸uuOΆ™©&¼`öd6º•Kéºwàä`eqtL·xçÐF| Mꋟ�C¹qf¬7˜�ó ÷QyÔ>ˆ¹‡Õ&ñNÞ§ªHq뇊­r— oÅdt|ÛÌwg„à|¯‹ÔÜ[TÎd Jná¾…SŽð);s¶\ÿLxÚÖ@k–öäåfM0ÿÙô–ë�²ù ðõ{�|1ᩯLðyð Pžb€Íz‹ÅÜ7þ¢ÃÐxŒ²é•¶>­Ž•î€QxW³‹$6x�‹,_^‚?wÆ®C°ãwÚì F·HñHƒ]6Ћÿ~¦u‡r„‹R™Ž3yA¦%k¯‚Mʈ_Ssqë¥YðæÅ02V¸ç`˧ªÉ€e·Ýyî¦ñ\e™$äGÿÀI»Óhwj·ÿ¼7çN&ÑÌ9*¶ô¯’<µÁFs÷á“Ú.a² },u0õU0\ŽUd·D%ø:w±hógŸ¸¥xµÐ&wn÷ÝHm=CÿÍ�½ ÃùAØT“f¹òúÄUnÍ7ÁÁàiujI"j.Ê8 ú�ŸDãMÝFysÚ™}°ªz"T{ÄÀ`m;l<{*äqkÇ}w黓Ýì«Ô•%ϧ= ¨©æ%ôÿ/L_�:]çÀ"1ïm,¢·&¸ñü.úÀâ×ñ‘’CÑV?„·>±¬\Û!:4ZÃäƒcXj¾zù¹KL¼D_±U²ý…ÎÿdÑ]÷l®‘Ʋ”;peä¾rùmꌃgçæÂŠ1^ô m)fG*âÁ…«˜÷„Þ+Öà“Õ=P¸pE¨‘nƒú¡Ç¹ zïÙl”/úþX‚d¿@ÃÆA¬¯öÞzd‚Aª2¬OïK�®ê0§Ý½Y‹8Wü¾!YP\™E‰OOÒÝ)nΈ£—¦®,&$Ò;½.Ößö.ªŠŸê#%·®¥m; ÄòEذQ‰wõ-éMôµÓDÙ%œ­“Y›Îƒï—~å—З§49Ðñ1>è ]M+Ž/çø–|2h�q¥÷!éÏ¡$é)ÿÌ…�}å�¦8'Á��‰|C!ù©Ô°ä“ˆy �Ý÷BéÉXXéëFwcæð¦åƒ°"»â6ÅâzŠÔéÚESøõU\u®’B“�Óܼ)ìꢄmPÄ$Oqoú9h™ÁRÑIp18F�¤Þù³)r§�0$eïsªÀV5ü¶µ ´âmÛ$¸¬Ì‰[fÓ’9Aù³„lºŠ¨ÿÏQ|þóWúߦ²ø\é#™• ç§æ‹Q}ï-ˆðYMÎ è´Ær5ÿG x—Ì=ÁWZ‰-Vχüãj4ti7T4.ƒ í*hµCƒ’/Uá7ű°Ù4—·i¡ÔÞ�àòä¥P6Çóç«ðܼ�Øç×Ê1�EÅC÷ᕱ¿`ðšb¨N¿Eƒ=qØ�(¼âÂ^k áI“ÏûÉȧ¿¡¸}#ÿšyž|×ÎÄAÛ†bÄ‚’®Îl²KWÀéïÆ Ú3w°i®,ÈÓ¢=l;lÍR‡•©µ÷8ú™Ò� Ã~Óî…–Üûñ:²�©.)ÌãÙçψ¬æ)Ìõ]� L]iÉÞ]0eùv˃O”«äwѱ5[q­k?X1¤b‡�÷ï´çP•ŽÐÂM_exâ×3¢Iq.•Imá0M-1mà6´{Bdð;ŒCp;XõnÆÚžÂÇͲ|oZî5Ó¾M8§3àXŸœÓæ�ƒ¤CR”3h«VÒ†§ÉÑ%™Ÿ˜ºPH¦•Dáìwø&ðǾç@«©ãïÇÂøúsN‰ç“¡09å[r¹óašö7ŒâUÙݺ/›nWå%_Úà q}ñOÅ~˜Ño&.ºšM?=cÁaW"LjËòò(á9<øYt�x‘C#øÂ¢·BŒu ~›ÝNÞ'ãh¢C9Œ<à�kf�§¤DÍÃ2¨òÓ’çôáËÙýÁVwF-]í´ß~@Å�­þ.ÕéÃß&T¸‡& ÇU¶åÐäìD�gqõŸ—â¹ ËøûôÕ¼­·.+Ú¨CÏ•÷`Ù‚&2S'|öòŒðã÷ò.: |Õ”Ã×F¸ê‹6gjj¡Ü§\Øb.å|È-nø/ áЦâ…)øwÙ :üAŠ{hp³ §—'róPwž»›”&í­ŒFáƒa ÍèñžZÀIó\:çkHúUÖxÇÓKš÷PÍ~#®4JÂÁ*â Ùž¬ä¶�wŒO¡ÎG³¹ü²¥:¼]Po‹á�kððÆþds™´³­1À<†Æíd}’ͯ#—\gN}íÍ»ÏL¡+¤�?Ã%éŸt(~ {}¿iö&ØR;�µ^´ˆ§÷sãŸq™ž’˜¿jÏ/:C.³ÕÙi”%ß°Œf$°•I ~ÿo0îÝÁVšîÚ�X>5Z(­qà�_ô»ú)œi›Ç*ß·“Ö‚�X0ÿ ½©Œ¥«BQrä>Ì8?^¡Ó—ŽAOŸh*Ÿ÷~5§Ï_ᤸ~ðãìOÊœ}#4üÐ;È�ìÆmÂË’;t¶ë¥01c ŒšiÆØl€5ï‚¡Zö-�ŠqäŽOŸépm¦x1è?Ò�y-l ›€ÁOÓY51 _Uà•�"Y;L™í½<9ûg,ÿï´dà^z!™Ṵap j6NæâlíoŽ[Å ¡^LWæ ‡à`]žtä6µ„]¤Ó 7 ™ìp,[yå 9-s* ¸@Ï#í±p·,›Ë£[³!¾9•%~}dAÒ·¯Ðá“ùÃì(ÞÐþï;øëˆ—¶øàp]}6ë]#¼ *Œ—ÌÀ7V_9¹<}H䌯Áóúl·'§=aßì¤é‡Óaøº:X´ÓˆGW‚B²{�Ø�£"*¸oà ßpºªÕ=3Å ñ#ñ˜¯ü ÖÆÅ{„ôYy 8¨îºÛ’ ‡Â—MשeÛÉ}»S(ÿ¾Z¸�Fbýa[z8òœÃfT2+Ë8ÉþX�[ò0õ¾¬Ö‘,”¥’[ÚFºÿ,Ì�âiU4¼ ]Uº¤êi@)Þ‹'ª˜7ú@ì@LÖÿ% ¶Í’üŒNÐÈP翵ø¤z7­ÝRK•g—ã‰3jÂéËicà2ú\Œ†­=+A-{Çü�¹úÇ7)iµ�”V�‚:™]tIN5ê“»Ûc1Õ{3½øò�—®´Z}&À¹§ô á2ÛsB¬5J¦oˤYgÝ0°HùA¿L/‰bC_ž)Ðý^Û`Çy.—™g£Þ’L¿»Ô^¼LLœ¿~�õ4«£ Ñ2hvv#¥>™†=ö§gz×@ù²ž°íÖyÒÜ|øž ®KÞ ­ƒñâ´h1séöX ……R¨ñÏ q#DkŽÇïRÓ%ub+6žˆU�{Èk£5ôÞOS¿“ÐÜD¿2?Pë|ùé)(W:Š9·…‰’‹`h™KÓµ×ðð—�‚´Õ.˜:XrËá‰hã2 *V\ÁžÓçdGÉ”—S8qD( ñ°¤ôi‰ÿÊRîž�Ïä÷áŠâˆÝônp•øÔÿIòbc]�ØLÿ\ÁÖ‰ÊF`Ï™LŸ×<Ÿ*‰.t ²aµl+#ËÅ£{€ï¼a˜�~Rø*$àñˆNR¾�Cò Ò¼nŽ-&[õƒ¦PÑÏ/õ5?â@›�<ô¢Ù{¤ñ‡/Ö°éq9¬ÕëÚRù‹CÙêáTΫ0Âë·³AZÕW˜qhÛâL7] 8C#Šƒå¾À-ŸÛ ™Å#e¦AÅ ¬Î`œÞÚA!3ØbF ¤G{VèØ‚Ë1íaœp¼³…Üö\€Ç±í’–¡Ýd!~�Œžu’šÖÑ45†ÛCpÚkà‰›öá’‡LFË× ñ›ý^‰?Öχ¬#Ö°9% Ù£¦œ9i¿ÎoM’„;‘ëñ‡lÕ¸XñÝZ¨1á�xÁ7‹~îT©YTóœ¥.&c÷xQ`Åë«`àä3NåŸÇ£°údÂ=>é8]Ñç„ÊcænèÙk6Þ‘šÊ£½iÏ’eTu«D ˜“B£¯�áØØsTÂ[à£(*³¦R×þ,·+l‹p2÷£ö =Ù|úbžwnEë åoJ=±V} 6¿?ù^‚¸áO_4‘® Z<Õ]|s�ø³+¦,8òQt9£ã¢”èeËþ{”0¬I“9ÿ?8-™ƒ®ðÍi.0+6Ü�âin]\n¬‚¹¯¥œ’Fšàb³6!¨"/ìÓd±o>üTƒFªÏç'ƒOƒõƒ°aZfî—¼všÎ4 cÍ.MŽÛø€šëÎÀö §„_ZOÐd¦¾õ„},|x¥ýAxªtö½{ á)§Pož ~oƒåF°Üù•}¸©=El‹üyíbaÀ¤éü¥ø Å1œ­{ÎF}.‹{t˜¾ `ÿ@m{v@äþ`ìZt^½º—ï€äÙ Ì]© ß»‘�/û [fkPËà�x6f.¯U¸ =óP:Ø€gŒíAî“óÄY=-Ñôk|‰} ê]�N}ÍþÀ÷oÈoÖ(ÐÞœÀ�›@�Ê<>?n²PÜÇ®]SÙcc"->–LÆ:œ°e¤pðªêo‚b]ž3W¤}‚öN Á’‘')0ž¸0%ã�ðåä·pwm�ޑίŠúà“5©Xf|”U¥B óÓWÚÇ…4W”‰&“z¡ÜëA<²O.öî¾Ù™Xó®6.WÐÇW…‘ÐO©Æh¹‚´DW~.ÇõD¥§xôÚšú&�_^£ôа¯)A­ !ÂËo@ãyDYàJkoøžÒÊ‹RWÒúóMp(B‘NÄFÐècößÍ˽øsûmžv<ß))ô8ÍÊã_eríME “UîÉÄŠê¡Be† kЊÜ~8ÖÔ†\Opmi*Nn�³öyp]û‡ÎÀå˜ÚdÅyÂ|¢¨ÈNCàKî~^Hþxt� λö ÎÞÛ ’ú≩þè9t7æþÑ‚è¾7hcÈ)§‘1Y7þ„IJxª2÷™ÌÂû‹ùº’ÀƆ¨�z }ìËØÞ}=l.à”»Káí§mNWÅ”ÅðXw"Fõ²Â¥!| äyå—pþä_'Æ–ý ËcPXöäÈöRâۃߡGŸúïU-Ü1ž¦çh‚YßC,:õ€äœlŒ'³dd™Õï=�鹕‡ôïù�Ù ²v½¨sì1Žkô£ZÝ¥ðáö^¾œšH­½½yYi ÄM"�–½P–ÚÝÆ\É÷ááæ.èx)Ë6ÿ˃^ø’Äß;xðÀt²â5~é¥Ì7 éfúRZàö•vd¹ðïíý¸-,6h㦲n(5¬g}Ucítûí`4··À™ýÔùÖøÑicÝðzã#Ð?1ÆÚ!þÔ-¢%3ÖQ·¬6¼œš@1ŽÅPëT#6èÉáÍzmxÝ>½=•ép½Oü=Ž�ÿv€°S �A™Ô¯ÇJ 8|Š´†4QÍöPê'º65Pªã?×úAf}±°èö;°(ÿòá.°Ji°Óéæ˜vM‡¶ÇŒf=)waËóNHZ¨ˆ�:ÉÕ¸fKÜqt@8m:O?¯‚ÇnºbÓ¨ ¡OÖz=^›üŒ€#ŽÒy�5¼!>•g:L¦ø•üÔp?­�!>¯Ž2ß £;‹Ö‘BàLªË�»O«„€jòz×XpûŒZÒóZÎåsï Woí÷=¸FËV×Pû[u~¸mY¬,\ß8�?Ÿ+Dõsw¹*9þ“æÈúkö¢¤· RG¼ñ…îää‘¥ÖWº­�@ó�R9~ãŽyÔ!ûˆ‚ VRÈ‚D¨ Õbïwìç’ 3[#ð’ðîEƒèãwmêéMr3¨*Œ6+¯à¤úxInÖ1hš•ÏusO’Ûèß Ý¿ŽÝ²:ļÁìØ¯XXÙáBGÇõDÿ_‘4$ç÷ÿuë¼'sQÂv.{¢!l- D¸*Å`)&˜Œæ>³·€ÏÖH˜ Ïn#&Œ«—€q¢r#€ÎŒ™÷¯ûÝøÏpi>†<ÂYº$ß¼"s8î¿Þ(ÿ(GTòñæ9mþh½×w%€Å²Ïð4{EL„Ö‘4sc»81Ðû,Ì·ÁËG-pš3;P Ù\Móv›²’Ͳآƒ ÷·óÚßöx,ß[�™[Á_'[â—7»Å€ŸŒ3ýRœÂ}®Ãø+î~38pΙTDsLmØ/ÄïÎHƒ)‰-Üað–y(ñÚ\'>q;—–OL©#›EÕw¨S2“«rœŽj�JÅk�vº·/îÛàŠ¾]Ÿ„[—=Å Ík´!g,:¶™ŸŽèÁqf/ÄÅ<$�|òô<§#sL`Û}cÜ‘ nš¡í° J~7¿ÊXÃTuìqNó?õÙ™ŸÃIËeÔ1·‚ªm~’ãŽn±€G+�¶GÏ ïÁá,±Ï„‰ç–qÔÄFrSý�,Æ¥“Bf)Ÿ %¥²‡pgìZJUòÃç`F^ TWŠjx×e!\ÍÊÂ7ÂñÆÚ%Ôcg µ?}Fµ¡,À¥‡Fq¡1�̆z¡QI]öŸDY£pÔJHƒò_ý°ï»Yà}¦Ml›þ„5ï,Áœë±’�ž7 óþs!;êºð_p!Ôô^Ž^7`ç›[¢ÞG˜ú´DÜ8¤‚®ùaÔZ|³JWš¤PU¬%ÈìÙ-N` Ë}nPQP¸Øu!¬Š‚:­iœ¥WÂsBÆóÿ½“Ði›¬ Ù‚ö®û8ˆ3ó¡c‘[Dï˜ Úpĉ�æ,ä~3�…�E:pË®\§Ÿ¥JÒüwÞ,=D/&¥£‚ô› Üc÷~'¥wO…«ýOˆŽÉe´º·/¦u^ÀT_Z³nFáÔ»£àžÃ¿ý¿qFØ� À¦‡’’ìÛbÑé©”[Ï’ðq¬ìö-Îû$Gîym/ù•&³ÁÌ—B(‹Ã¿‡î;±¼÷ƒ7?6M†Ê¼¢N룬ÌÇ»ËñÚæíüuætáoòQáþv2ï³k:o,n#'¢ù=:˼¦ç¢ÁÉp8¶Ü ŸÜ ö}%à9d)6ôžª¼Tþ>¼™ûür}!¯ßr6l+¦A7×â�½:Øò"–¢×/…Yõýe50ǰm‡b{u™¬ú!<§Åÿ0QP\iʆ=p/ï°êó1¸Uj»îƈm1jØÙ'�‡\{ Ó*¨óc…ö ¬ý0L´¾áÄ ø§R^þtˆ�~¦$åÿ ûF“àQÉ=UŽã´GC(aÁlÁÿÙ{˜¸v0ÛžöàþgÏÀ…Ð÷”ûy OŸ.’TÒ\r™EÙñ!4ìU/AzèE8úF“ ìv`êãZX{Ü—äÅ´‘Ç4?zïÅ÷¦¿“ö¨¡©¢%¸•ˆZþ ÑØÔÐ9{†/4Gó2hcîØ6£ lƒžÀìê�0!Ѓ§�Cn­åuôevRé?Ϻ®�LaW~²¬§ çËÿ��ãÓaáÊ,þ$½º·žÂ}ºÍ’5;CÑ"á8¿ñDùŠ=ðì“6ooÂV„Šù7ñ ØÕBÕã> ð�À¯ßÂÝHqµ»€v;®‰J…À>> <©c´w¸XêŠ%»o‹SgÙÓù‘^ðlÄb¼²ì_6F guÒÅ=I2ÐK·NMT þŸ9çd(¿Ù¯�m= …¢ß/év‚–›LFÙÑ9ÿöUÇy›cI™íÆEÇÌñ§{7,Z°˜m¦ß�³(5l8$þg wR:%F%ÞüÃVöÔõäœ-�´mñ¨ù› Õ Ùðõ޼㎩*„·ÚZ¸àðdú°xjžßˆÂþBáð¸s'8d¢)ÛT]EŸ&š@QþUºwîßm[OÓ‡1ÓðŒÃTÎYÛcR†óƒ G(»ð8KGæ‹6õEåc¯áë#\õâl¨ ¤þ Óyqy ¾ývm´KÁTYŸ=X õO—á‘E54q—:/+œ‹¥.C(îe;»ñG\fˆ/Å20=ÿ¦íSã[Ÿ@óÆUXÿ*tn\§ýCÙyÄFZ;¤Tp1Ó „W½pÅ”û”‘@!�uÙ:af�Ìãj¸fýA’vqmÖ~}¦�žç”rªM‡äõÒ`e$�ŠËÈúr(U-ÌÆ×Ûø¨Õqx°¡JúÚóñ©h§²{9îà›‡}0¾v4KËà›;ö|{V߆êËAüÛ¿˜”¢†Ò[åkÂç^=Éû|»î®§œ]ͤåyŒý?À�o&øªõ5Ö/¤�}›iQ’ OŸ´^DNÄnkOr6Ù‰öŠ:w¥„Þ…“Àyøñ��&µU,î+²Dº/ÇJj©­C–KìÔ‘'Ÿc°Ìœ_ÒÏ{Ñ”gy[¡wF�öÇ÷)Žèm«†a7lË�À”Œ³NŸöo`í1…D‹(ø{ó k(¼�,ÆÛíuð>¢uŽè¤›Ë“ÄùG×À}óþàþ7geY`êçuxöY쪅 ›–TðšË‘0pó8NÏσOÑ}ÙQ~#\E?*�´›ÂØ­Ú•Ÿ/có÷hpÕ�çë�¡êtwRPŠ+òŸÁ^Ï0¢�[ \©Øx". œLuódøð†X¾¶é/<^§\[‰\ׯ Ùÿü£¥S,Ù¥‚‡LåéNU8Kýr'ƒisÇdL~4G¯4Ò»RÁuÒ'±rë^’œ„ž_¢Ð¬þõ�U¯ 䉯ô±0â�`ä*‹£cµÐ#Ú >ôCã¨<©LgîVæž©æÂØ™ÈÞ)ÚU[Ĉ¦jêc _Ï:áÈêa«ÿ;p³Æ�i†ôðŸïøõi„Ÿ µQþ·]<ôµ”rsNðÕ‡[ùéßxÒîMn…åüdy!¬›U뇣T÷7¡ÅAFPáö†_ó•±3?‚‹U—ó·¢ñIôQù´ ¬q²a½{ï`à°8Ú> Οõˆ¬:Å÷þ*|²I�½Oäó ÙFØ+&rˆO«<ÞZÏ/ÒÁa»IÕk© P°Ñéèˆ)¬¨–‹+§Ñºýñ–t‰ØTú–ÔìÜèPÂ8â –>Óà�QøvŒ>Ð0†«áô²ÿQpžá\¿_·÷**!I2RBù~Ρ$-’ö ÒF;~Z""DFɨ$•¶H>ç%І¦ÑÞhÐÔ¿ÿãûÁ}Ý×uÎûýz=¹ÓÑ»Võ$�ÐÆg[šhžåqõ˜ÍØXV FEjÄn›ÈµŸ&Ì^>„õZ­¨ò×eÌ�4ct—Кˆ`¶Ô’×êŽ|Gç0ͽ”Šoú ­�<öD(Ô¼ ãµ{��ÜÍvêjyHµ— Ûe%4vÿI–»ÂàMüa2Û.Åê¥!8§¬&½Ö¤ CùŒ®)ÿ°|4ænï×âùÁ')z¡šÏ:H/>}§2ñ5­ÿò\üð&š‚}õ©YØáJr<¨¨AX÷ �ö¯¤æ†ðàˆšØçø~¸£nśЕ¸TÇS˜ôî3Œè\�Áe~ÜQú´ÖSóÞþ˜3Õ\üɾŸ~[Ü8cŸPØ4Í$ Ô*ì'åÈ`p˜ïB&RÍ;5^|ælÀ*)ö`�~mÎìãÇv£ûÓº§‘â-µ¿4û’÷ÐZÄY�C°^­EÐìÿo'ÛK}qÂ/Þõ¯_}ÙÀÏ+÷A¾k%Åÿ�G ãÉaËOAOF‹Î§Ý¥º:,»*‰öma _#þúßYXzµ„n¯ú�¶ د´I¢º÷å`¸7˜Vê\¡o÷–Áà�Ãè‘j?œú¤‰¬Ó´h›ÁxH{ýKøï›1¥�]²%h+'ÐV7]º¼t¼h= ¦ÊXòè}ÿØ®?¦lPâßóµíó<ò«Â§4ö¦ú¨ÌEÕyº¢áÂS°Vû 윱›ï½�§7¾ÿãªD.-›C's”9Y·Œ~~ù÷̇v©\Ø9¸BâlaIú½•pšª šéî ‚iý©ÁÀoo©Àçv#xjLü¼5š7.9�æöÀŠÉÒüħjöðªmEpkX(çŽszJà“êJ¾y:’ŒÍ8d•Ú9H[ R„svÆ8tÏoñà(–›‚¸ñÎüÔrŒeäxàÏîý+…ª" ·C0Engéò¡¡²ÅÝaÓ鹜Hi“¤éümUþÏF‘Ÿ¼Dùþé½1šÆ»Ù÷°úFá†'…YÏU9;œi¹ön^Œ—ËÕ{‹—*þ Ý‘ ¾…Áô‘3øÔý,‰t¤5ˇ‡‘~¦¬·/æêëÓ[ØÈU{�ã´ÈñÌî‘t–í&öë,ÌÞÑLOU>Ò‡Ç7 ¯Z†G©‘žÌH<4£÷œ†ÆÕ¥Øí¸™Ç?ó£xó:Q(¶¶]§è¤ Vzû.&(ã#ÅÝô42 f«bF©,<¬­•Þ‘ôàÚGA¼ÕLþ+\xSŒ&’çò^¨Òþ4×|f§É³‹`EÝYi|,åÄØ«ò£ WÅ•s@j/G^#»³œõ±éK-†ì‚ê…ÓiàO3>4¸ (.æþ9Bf§9©Í¯‚Ù³w“ïŒaì²þ3HŸô¢Õ“º(~øadÕ}úa:�sþÀ»sÒ¹X#T°Ý©Ì›}/¡b…‹_˳m†¢Ó�½xÿï"j8#Íѯ¨pÜvñÏ~ÿ¤Rp}xšš}žˆÛl½)Gï8ì<è–õzN¸{»ÚÅ$I–z×Ã…#³aõ›ñîšhNÏÈ% ˜È²zy‡¨+áqÞ |í—­phì!ñujnؘ*ùx½Fp~—Ç&ÚAôMI‹+ ®‹Ç2û�´Q2«l�Ÿy(Þ1VØ´l8O“‡åC½é¥�~ûn׋R`¦E?œ²Üï(Ò[Ÿ˜³AðóðE�>Üëp8NŸå,q=jÀìÆ£Ï¬"°ˆvç«Wô)ù³)ŽÊ‘æÌÊul.f¢êì™Ô¶Ç“?fÁá‰%´ö¿ P’5Ý6iTŒ+¥IEw…]'-ÐÏE‡=Ô.ÛïªÐÆ™ûàðÄ/pÎ;‡š]–aû¢x˜wŽUÚqWÖkÚh0KóñMò�ã¸àâ¿wƒ9Jí ÔH `ØÖ°g±„×ßì„áayT#�IåÞ°åú: ð˧’ÆHPØŒþ¿ÎCߦt8'–m뛋oÏUÆ/_ 3zÜ£ó•¢jSÊFošùÉw®û$4� ‡|« ¾rÜòì~ÅS”%³ÕÞ’õ²WFÖô�VêJ¾ääÑa…Þ”8z%—Í·¡ÐP3PÕŸÈV‚!æ¬+¨›ñ=Õb1Ìå9py0œeÅñ}q§yZ[·›6ÊÌb\»~?<„µ?OH†åï!Ó"]ÑàZ"YvXò´±.Âi]SZúy�P*#wsg~|"óŽ_�gV=P[M g§e °0dL¬õän­ j�2ý×#™d·w¨(%ÂíŽJé Ë—C÷øû¢¢› ”œ‹±áƒ�õ#¢§ÉÀ«ÇYʸ™–ï, Ùmz¨¹gdn³€9cnÁ-CGê;݉³þú`Oï‘à±,Ì__½!e4­»X̘g¿÷2›’!V£?¹E¸àé øçÚ^z'ú«ÆÂÖm¥´UÁ€Ýrûã/¥e4¼JŠ$Ó�Ý/A}O)ý83ŽŸ–ÄÁ‘Ãÿœþ”£ï”AÖîì­ý¶¸æªOt…yYÓ1vS9TÌîGÙÕ=Ä·"(iÝHXQ{J2�ï¾*òœ#á1OoÐÀêT^Ÿ�C;T/ÐÍíÁ�»ÝFàÔ|ܸtuìh!3~+6寓á¼O´`vlÜäÀÆGR…÷…¯…žE¢Ìé<_/ÊÖû‚OS/!ýfw´SÉW>õj´p¹4žLRä °z0ÏÊþ(š÷üE>$ÃsÖÝ¢‰qtdž&;ÎûI9·±ãfUvüP—B¸‡B#üǯ^—CMÕrüÔ1å Ó¨Üx^^©Ã?{e †Þ^è€ "ZWÇ•†½ÐÓt¶{Ìfµî-d0OÍ'EÃôZ}¾åÉJg¯S°—°è—6î›s˜¬ßÇ}¿>½„33#ƒzÝë—ÁÇ-UBA¯<¸2ö8»�‘Â1áÝÒ#°ª2\8Q>�vD�Æ–‘é"´_&Ó/Zè÷agrlN~¬´zGÀòKkèÈ�´ìC0K=ÿ×™½å°ãÁp´@‰Ç Çþz–˜?èè_¶ÀW�C…·U—aëœAÂûú©(q³â;+(¿®ŠòŒGrÙ¢þXW¹·xX‡&7ýš ¹—¡Pe;=H¶Ç×ÇF¡mH�U{˜VíÐæ6ïéµ�óäRʰ�N¶äÁF�I¨.¥�}ޤµ£‰úøãM�EQ§?Vÿ‰� N *c¹An0¨ïÌ厳¹5ÈF˜X§ŠÑž…\¥ß‹«–+Á´¨xL9’󆙢Ý+;ìlZ…W;‹E˱ÅN…>)¾û혋%OÞ‹û-ØÚg4Ûû��àéò"ŠâmW¢×ä~´ü2ðSt€®†1Ôd²–B¶Èóß9üŸ[?|¯¸€ýº#–-¹N~ƒñsÏݢ̧XÜúøë¿™Æ[j?À®¼$¥×Vl·â>u‹þðcO<ÑËìwCÉ ¦õÂÑó‹À<¹œgôåÉ±ÆøíÈ_eŒW_$Šk´àà•JHÖܯØr�Ä�Øöm:ö×>'žÎÖCÕÑýxºÇ˜YZWaŠÏDÌ÷–büdÂË åÁþZ,ε.€Gotø�ìXRmO6].ÎØ3Ž6ý- ñ8y�ž,ä2´DSö«~8÷�üqóäL¿‰hÛy‹^®ÌÝ‘F%a%}Q{aˆ�yZ îµ·€çõJ;÷ÿå€wGûfcò”Uøqû]x½][\“~˜6‹yö9Vžôqw_8+ú,XIF—ùJ_šsq?¼ø4T–äÀÇ“�$e$PwÂFº~@— !Ž_|m �ßÒÅÏÓ³‹Õ^ )¯åyQp#Ýx›ÌO��ÑÚÞ”ïÝ·¢oŠû…e­ˆGÆnštK•šz|&•º½ÜY¡„÷õ¸Ýáô}O\–°†_è�‹7Hሟڨ;W[„�Zx®ûµ0g]:öR‹ƒäS½Ðj²/Õm §ôOýðü»~|ê[0+û‹bí½8ÙõV¾Ò`›x&•el¹´�J[Çá±ý#iïÌô:ô¾xÒÂËâ”MÇéíŪbƒ×ãÀ&Ó vÌ�¦$£�"ñ¿~øTµYHkö`÷ð„Nmœç”(lýçºÏCøàç½’õ#úòG 6ü–K¦®˜\4«>ËðÂ+ç!ÐLÆÔ½c*xƒg‘öòz"@F$¯š:žc‚�CÉà0̬“æ>ÝŽ8Æá†pÓYŸ‡f.á –Gaipvè`‚öXɾ@_±ÿ—Áèöª©,ô§Žôe�‘2cþJ ^>uøqmûŽ“åª‡ÁdÔ˜#yj2™Íºnƒ�’�Fàr6¸¬ ¥É{ÐS:N°~ß-Ìõn¡¼Ôù¨(e#Vu݇ä—LÊÛ®PóÂVÊü� ¯Û±ÎÓ,*¹7•nÌ@UG š§�¿"¥PëH"¶möµ·ŸÁ¥3¾ÐUÕRhIúߦkЪbÌ WçƒQ{áÃE,ÖŸ «�å1ÐטôÜOÓ OXò@ n'� Ÿú”â™N“Ðòæ-º+£ÄF�(º«—ñù@<·V“¾]\E§xÅÊÎÇ·ýpÃþ nEÕê›Ñà] —Çêcw^½øeû ¬~ú ÎÊ—Ò·M¾µ,“6lÀ /äØäŸÃ÷Z¶ ~iϡǯ_@1(súmU2Üü¶ÛšðÉ V4§@�ïþº„#Ï@O—ÕЕÖg£›ÉúñAou– /Ÿ@¯¬ðéŠyß½JòÐöõþ[ é7 ùõ$¨^ôŒc¯X¡x5šdó‰š ¢@þò\aå‡a4W�ïÿsÔ¿ºxüöEüЮFÊ7'ó†%ɨE'r¹÷ÝzØÕ È²ƒ(~ÑdaÆš›èlg CÍPÞëů╹àq2èaħ/$‚|í²)בſÿÞ?˜5—f†žæ <<¨]Œ÷z/´ÔÆü{×nÁxB6÷¿+GçV*ñøÁ¯á�äY~Ú4°'Õ�o!ý¦Qx5h�•Æ·¶qX»¦ Ÿñ^´¯H‚Çɧ)¶)[ ¯øk�+]äHã¦,¾UÅ-_÷6ôåî’Lúy kš$o­?Ó-Ìç­Î¥»ëdAHU†–«±¿D“teµ`è?në›=‡W4CRÈuýá9Å{ˆøðÔ=úvó(f'<ÙECŽFŠ3VÞÆšQ©ÂžºÜsþïþƒÏ€9göÀ·ì ¤¡ÏW=¬x¸…ßU>#.�‘6íK¤¥!>à0IŠg?{Eçý�Ó§ýÛPc~5TT{]±Z+š\Œ¸bùð_Ö®ÞÀ¡7£�¯ˆa¦à½v lrLÃÙ9Ö¸Lgž�x'„¹Âîw¹Ìo*'¨_!ß”õ86Û¦MÍû_Œä¡A´c¹'ž[KFåiP·õ=ôظžôÒwÑ¥aÖøöÖWš¤o…G,Q¦×f˜³â©pe\>%[(ˆ –ÚsF›¦†¶Šv¶»([i&šˆ¯ Ã)›ŽÞ£!ná¼Ùr/ ºÃQÓx.Ûuž'½7f_ICa(�Â`xïoGó–…S»ôPv°}(¾£… ”}…Ž)âqšˆS_·Š÷jú²©‘HÓ¶?£Ê; ^’°+n.ckKZô\à…4üæ3Eø9Nÿrc÷öØàŽÒÒZ2µAXÝ�Òhkç'mu±s§%®´j"ýìÝ:_põJ„;gpµÎ1ŽÍ˜ÍEk±Ú¯?’¦_˨Ùì–xõ«%JW.Æ0¯ IþØh~u¿…Aíþ�”ÜÈ`/3ï-“`Љe*wÒtÔaéÖ&h¬ÌR OòÛút8Ò� :Ü5 „ú÷w$Úk� Oaýñ¦¯Å~-‡puÙ_wŽ~ Õâ9,8ë¶›ÐÚ[—cÓüȸnúZö€ÀŒÝBØñd®š0=ýGQŒõܶÙF €ø´…•%ÑrKÐbWç{mi@ãßÄPÿê(rj^¨@mjfðÜ÷{±j~--þ1DF ýø”ÁÖÇU¡GÂ.8yñ›0·jŽ}Žt2Ž2•ÿ¦(¨À&­Oôgáu:À¡§”qAlš8¹- ÷:tâÉ‘Ûxòäã4Cñ ¹˜Ë󣪯väç©AX7I*~†R³Sz/m 0³s´¨ZŠï¿Y!M¸Úy0)fEaeïéøàìPv›;F¸Ú>›Ürq­±"ó; GÖ˜ˆÿÕjïXÀ µ…tßroiT£+‚5m~s ë_†±ËÅlP�êéSøö ROÎ-kŠçw¤ÎíÍCv`÷­¾¸Ô»Y@/Ë�½ek½ Æ÷�‡)Øò­øcôÙâ›�ó9´Q�wÄ\")Ûì�g µM2¸nÕX.L·�YGÂéë¨OÂX9cìºjñ¢4¯HPåèÕu€ãë qio>=~/j ÈÇI›¥Ù@ó¶m2�eÞÑàõ^—*ž´à­ÂXè½|½xß,𾇤Òߨ(®’õÀûÙ\,ñ‡gñ8çÙtkfLÖÀÆR'_Dk_à›þ°ô;òÞíT^oçB~Ò°F3~²½„üz—€þ†A¨¢Ìöí³©i‘>š¤ÇÂ8O2WvPmt¨ -¡U‡-Ä«†çyü¹£â©ØrȜРûÊâíßn*—ô¦~Ö[xN~$¦Õ‚üZ"1bJ7¼åÓø}y-<|9ŒÞÊ:ನ@š8¾ nÉrŠÚ.ðÈ]-/…sKÑÐÏapÀõ›ÛäâóÂâã5ðñe¼aðŒ–—|'Ô¤ µ?U©É<e&QÒ8E¶µÚÌ63ûó"ÃC‚§×ažP·†Œ"ŽwMÄ»³è Mp:4·ý¾€—L�Yé„ö�4„è�ÆÐöÈÜŸ6‹�sMP凳 uH¼3º7Z¹– ݸ»8ï= ò•1,½8†TŠöRû†½T~` P™bGÕ2Ÿ…€ôxO#òõÖŸ•æíyoàÿÿ”‡l“) ˜êO:rèC`¬äÏ‚NóGêTRf¥*[Nèi€·¦]ê`ºì,.8—+Z¯m£%Æ÷aÈ)01O¡£�ùÝ�,8—)ô«°æüm÷pÀe-¼¼lˆp½4�Ò‡ÿ¦³ßUÑÓ<�w�„mç=·/RÎO†„GºBÀå:z§RŸÚ¸9fɽ4ÞL­f…žˆÉ5pâ� Æ(µ ŸMU¡ÒF…mn¢P–[$P.¹äúPxVb?X!™,»Œ8UÓ—NxŒ¦>…ðVÞ!U[<¹Ý>ÍLŹÊðý`*�JŠÆÊñ½Ø=h‘h·à.¥È‡q¦®þ9ª�êšwŰºÝhV¸lƒ+WG‰áNR»k=.ÊÛƒ+<ü§Åä”fL+âð†\W¾ÒQ¸ñ~æXô…6§Œ¼˜,*'× —º�1ÜóäÙ¤òSƼ$ã<Ú¾n$ɘ!Tè}“nÉKÀvÜ  ÉàdâÇñæî¤á¹k²àä”u¤Ø’_2Gcò°Õ<ýýŽM<±úâj 5žm%.&8¯5ªHó„<ð ºï>‚©2#hJ\T–f_r»-xYþ¡‹‹‚Á席ïwDÔß5”¤Â%tàðc2tÙuåŸø}…õ¶$Ó µû4·{,iÖÇ €Ë¸×¶ž|üG˳càGÎLÞ™ë$¦à::uâ ôóÒE¿wud?Ø “ÏÒù±•tÔê9½hTtøaAQëZ‹™¬–âˆw¦~‡=Þæ|¢·"Ym|On‚ª….:æ íywþe`>,:'œNÒ„Š5pÿZÍøÙ-¶µ¡þ» Ô¸í¡ðùÚ’æHßËÜq{þp¤‰'è=ûC¾}H¢4\Ž•ðóÙBz)jÐäœúQÔ¤'õ>Éîg“AÅ2ƒ��aU¥XÈ쬦̴ul~Ñ Vå¾ûkeÙP¾~»LtèÜÏõc±pf5,ÂJëBñPú1oz5x]è‰ÊÍÀI)”&^°®;„›ì¦Á©í#Ao¡7&> :G)ñLX5΃ÛÎxrÂäQ0ñy+Ê@Þ”¯ÐðkYŽž'ŽëÃÇ ˜Œbea¤I4v.J¡g“Îòmó6º´Zš_ÞDÎ7íÈÿ£;kÿ°¿Ê¢íßü¡�þ¦ ¨è‹i÷;Ï¥‹¿Ñ„lk(n�åIç™NwÞ"ÃtYþñì(ÕL¿E¤Äk ¾SµÂOpöÊÀ‘ÿÜuûõnØðPF§ÖÃâsSÙ«æ;DV,¢¦‘=ispÞÿm�¥ã-Xýã ÞWmÏ“§_~Ü/ù]qdòÝxдpú¯4‰ân×Ò·¨ëôõEÙµ¥‚×”[Tüü(;|ÇesuÏÁ˜þ¡/<Ë÷ï¥Â„��8kïD¾=h$Ìu=M|»3ç¦ÇÑ¢+ÿH`áPìU°‡ò{¥¢°á+ù)žÃI=¸à×.¾6S�ÿ Žåáƒh�ýÿÿHª€9-¬‹=O—®d¡³g/LÚSÀ[»VеÉÑ<â^šPg«…¿Š=¸~®–äñÈþã ÌcޤÖÔ]Ø»ÿEˆ}ÜE³†êÓvÇeÚvŸNõ”ů®àmï"Äj='ƒA•<½p2?}5 ¯Vä—nAäË–»ª²…ãR3!ü@¹:ÙRÇk.þ×¢¸Ö?–õž�ª=§P˜á–»›K?ZÊ "aí]´ ·J™ñæ¿}X²Ý²ï)Ë Pñ1^Œî‡C/Ãð7<þ»4ú/“瘨sâƒÏ2z:™Ììú aÓ£ìÉqàt$«hPÒVO¬=ó„¾]ÑÆ½ÕûÄ£5 8óÍ%ør»•úWS[¤ŽNØÄÇ‚GҺ˪´/â,Åï¹ìY¨ó¹ŠnŸŒ›5÷ã»ï[aôŠzJÕ°Á“+‚D¯žGE»/ZÔ9ë²øÉæ<œUL¿ËùÎÀÙ¬·0ƒæ,1Ãß§Frú÷«bÁ®rÊÐj¡Þ­ýx¨~ôi-¬‚;téÑÎk;ÊoLaˆ¹7ù¤¶‘~ÙgX=ì/�n>Œ¶vÉ"Ïꮌ.ÿô%™f0#Z›¦à¡�[àgà"ü�±<¾éÒË»£qe�6Æo]…ŸSÖáN ,÷ŒNJSCÝ2ôzx�šj“˜úLïÜ ÃEgQøw~0KžwŠ24—qY·'ÍÌZˇÜ"å”ðÀeEvsPã“èdñ‡ ïès»údX2ÍœŽÜRà™yA¨ÑÏœöv>€‘¾Ýä?w¿°èåbŽ×:ˆR7žÐ�¯¯(W1„ŸÙSO7)qU‡Ýjõ)î¥ë褌 µ¢qC»ý W2ŸÄ‘«ß#Pp(«ø!5;vΟ!!¦¨¶3œÆÍ>&l°>ÍÇä¶Ò©aÏ`ëÇpqRQ¶°àP&¹Ÿ(§ÓS ¦›KðçÛt·ý[ÜηAþát¬¼Ÿ¯•±ß£100G�ßöœÇ¹§ƒ¹8{‘°-´ Ž&=¤¯êebEÎYêe4Ð>wÔ8HkŒäãOèêÓB;·.ÜÖÄ–j{¡@ú- \°4ÒNQƒéWº¼¨W˜‰”TM¾‰²’6£·’Ìó«Ùðv=›kÎghEÇ`çAÓÑÀ,g× `וi…®4ɆsÝÔ—ü­Ÿïò”¢•ï²¹^ÇÃ?öÁüÝc1Y p÷ð]ün鬜x@(Z-ü·~Wõ8SFÕ�/G–u‹A›¢ØiÈÒµ–ê÷-¢Ð�Çñ~ÚHRNtådõ^(³ù4:å*²®Î3Ú8õ|vùA¢Ü †‘}Ø(Å“DŒÁ¹æ2¼9Ûå pûí>ürÄ"ìxòŠºŽýÚÎþ¢¢¦[h–íÆU>zÜj0×®•q¸XØŸ Ôœïi©C}ün:Tg‰°ÃTØñÔ”Ûôºà{…3ïO>m¹¦ôk‡X´Xº^•âð¼°~™åIÿ‚ëÆU“«Ç?>/Ç£—ˆæf2ÜÇ/œGÍ|Ë×H0¬ßJ~u»�‚êDÁtŠÝß`£q.jüZCÓÞŸ<¦>•Øœ‹ Ê ÃÑ~Ó¨â‰>y0#~0�Ÿâ“)xD3Ÿ?ì9OΩcðñYV�Í¢åvlåPÈn'›¤ë ö¥&è»N‡'ÏÒ¦Ïg*y„b¢ ÔÍE'zrrÁ9¸w’�Šå©áTÇ[Iø2_ŠÙ?ù™9Þ_޼­ñð?]Q<Ü4滼¢?ÎÑÏmÒ�ÎS�Ma§S% wõ+ÙMÁs2ñsµ._[dJÃ=mðaª­L•GïoVlæãÀ«ÝCY¹ >mªçV•|qþòïâØ`n½_&þñîƒ#3,í¶ÁŸÃ Èðyu²¶E7ö6Àµb8·‰ÂÞ¾"•)CF‰3I–*íÁ6Qß6¼¡sgH%á(+PÍÉ\ÉäŸ Ðdž‚?(½¤Û¾¿$– ]ÐüNöß™Ï17Ú×Ö|<µ„íŸÈaÖÌ…¤ÒÁ6Éü¡Æžt¾„‚‰ºÅÿÙQß�ÿr¦s0�í8H5/7¢vß5Ðgb"TíÔD¿ôq°#X£­ß‹2lpMh˜¸:à§ Æ#Œ’PÍoõÈ·€š¤N¶�¥ %¨k/¡ÏEtØ&ŠíÌ `uÒyúë•›‡(cbætP–ɦ§#â?O=T<Ô,äžW‚“»÷à핽ÐúÕWòúŒöèÍŽűìîêFÛÉ¢fOS êmÁÕ¿³aTì*Œï\À»*UC°…Ì.Ö¬º,ô¨—æ@ƒ›¤w'„×Î×á5é~ä:…iÈa%Þÿµ¥ºhÚØ8ˆtÓ¦†aZlÙŒÃÇ÷›ìüu.�v�ÏM>¬±ͧÏÁ9ŽS©C#„Ó’îðøM9¾1„þÜÔGÏØ pÜÿ |§É¸íîeŒÊ™w¾ ÂŇ­°ÿ£Et-ÁK¬šÔ îì'™èóâã@Aec_ø¸›Oÿ2Ñ~‚n™Þ“�à»í tGÎR�=‚à÷ë$n�p‰O(<ÉÍ‚®Ä¿´Â£B¢Ké¹Êø¤¼šW-ÝŒ!ŸGóDy_0vÚÃO úÚsHþ» O¾¢�î�}(/¦¼*]x¥õËA ·ŠÂįvØÖl†úë6B¸êIú3»‹tо Á&�#ävñLß­†WÕßó£¥�UFå…rÂ=«xêàE~çÁ­›�‘”ÒH-i!?µPx&Áe7èüß�¢îÁEöMÁ�Ê)5¤¿úœNxUR¹Äõî–ÃÖûfÜ^º Î4eƒDõF]T‚À3÷Án^_¬H8…µÿãv75&“&’’?ŠcB…K% ø§0’î°àõä]t÷'ƒÜwT¡o#¶'û‡¡˜êÝ‹ deDù%Vœ›27 *ám£\~¶t �8Ðè?~ИNugû¢ÂÐlú(„�~í.«0â‹J²ôLÑ�ï‡è²Sã0Ú#šîØñ ŸÁh¢�^„ðkÓwî೟‘æ¬ót´D‡{Nû%Xë=ò¼†ÂÐ÷Âñ›»X.& L.d’³‡!Îì?�B¯-¢69bÃsMš™?¦ujBâžsPëÓ Õ‡ß’âŸñüMþ 8�ßÏÖ½Ûés¡§œ¦ ÏBñ’ìTÞø._l_ªHc#ŸÃÐÊ´yùLÞÖUXü#F——§ÑMw¨ÿ ý;{â.w¡Ëe5­Z©ƒcãðºÚ"œ¦RÚ~LÒúÑ–•etöh"|÷–B¿FGÉØùñ ¼R㶸��RñT8™^ÈoÆkÛfð¬ølÐqÊ]LFáäO…õÃ80~6_þ%®5ù*ÔçhsÚ×:÷q'»Oå5%C°P¯î]¹G|_É_t;ĸ¬«lv�|ôgãβ ñfÚ{:TL© Ã?—Ò&¥D¼£†ã5øO–,ÌYŸÈÃue8ðrT›‚¢Ç~X[¯Ý�+�ÄEI-ôö…2µûsû‹ÿøòÄ/tìª,Û=RÃ/ޱèÑ:Ž/˜Œ¹rÃõ2Øí_ õú hòÙþT´ ê‡Ú Öx³bÏ~A‰A7@Ãê Ž(+Â}YK@¼ÄFs%Μ¨ÈßW_*6RHË}vºŽ:qóßmÔï�ŸºV“ÝÍ ãkKíÆE:Âætu\ì©ÅžºDsÿö¶ùŽ£Íf ê‘`ŠÚÀÅê—„>i“y·O%H%ŒæµS•s‹ZZÏý·}=üy¡ }¶^ä¬äyéy.˜ø.»ó=óþ¼ºx'mmó.>"× kžk¢i]/|%õ®×/D½�¸Î_«Úéqma‰ìešÔ»œ<=>�kÿXzéIýç=†%»´A¶ƒnNNÄíKûÑ¢U_�J§ÀÚ7ÉrͪžÑKüâ¡B‹ã'×d5Tº6w¤¦�Êžubuëø}' ¼½´èÝA Ž—ÌÁ;í·áò¶wtËSF|t¾ LlõøG—/,~-Ì|?„+õ{ãø«Ó«´0sË%i»Ö~_—¶�཈>ÏÆÑjpûüiÔ³Œ¤;oPé¼^ÔZ©ç°ÐžÉí]‰ø Î“> Cmpn×A±üÈ~ü&»Rg8 '¾§ÎZ#<¨Ð‡]ÅùðóJ4úWl¡aQÂâ»Ûx¹~h»�êòaˆûX3UC¸ü{æjO“=œHaÓ;’»ø[¼h¼…_ËÀöM# ß³BPék�–¦‰µþ&ܨ�GïޮǪ¹ìûym쥎ö/Í }…MIÀ¬�$Y`¶ ö¤ˆAGiÔݽNBÐø. çW.RÂØÔ¯ gGxáF:c´R©mTÅÈÑžàßâÀ‡ãîÑØ£ò¸Üî1=Ùxõ›ócXCç0/ÿ#üQK:kó�W¾l™¨�N³Eã~†èn¿�ÖÔÆÐü%Ö¬xbP0„�z ÓC•¨>¼Ú¶(æ¼�•íÒ0°mGÚœ%Ɉ |¢s-?ÿfÏ{Zs­Íár„D>‰äÊ�7ý|#]´“‡yÓ�‘’�J«ìÄ 9´·¶b7…­œ±biqíÀ/ä.šcô¡mtwí¡BãµÄäÐ=èÌCžïç+^–”t¶í›Žº«:„ÙýyÁÅ1ôê²9‚™ ´ÔèJ&ÔçO† =.ˆN:�Ž óĨ+_I¡ì>ûdÃUßòå±e`稈Ú˶£û©­°;×Ì{µ‚–êET±:ˆGWÆ—½VãÚܾ֞}\,uÀ¸±“„ôCz¨¿sçêÄòí×ý8mðÞÜkîÞq$}{bœ×Qnú“^×ù 'a—»5Ïþ’N%aUêE'æ,§`+–^¿š_<óœÞœcýZ~´ÑâÂ�Øû¹²0jŽ=”�jgß×ð÷È,êåN~{ÓðøÈG¢¼]>lh#²Y¿;/¾}ŒårCS<<:ÌmW»HÅñÖÇ2?Çu´ ê5Î=ÄoTn‚nv¶n^‡âÞO4õdÔx­b“ÿüñÄÖ\ òˆ£c¬µ*Y£�!ǶÑ÷üÅ7” 3ÕùR[<º� Nƒ÷À:¯›°y_6 ê1¦ÏôF{3;¾pÃSˆ2C¬1(Cõ/Í4]¼FÓ�á¢uÙð—b2¸áxÛº!èÞú­rصÇ�IÁ•“Š�ýõp€_;¾†Û¯MÀI£Øéš#fEn¥Ö•DÍ Aœïh‰‰­>x)" R&`â®Hl¹¾»+—óÎ7sHXø–Ÿy‚‘_IsvÜ9🇌-¢Ån¦ðh¤:çøë”´tÖ“Ùö(èW>…ŸÏO¡�­×¡ïüx1^tÂК8Ð_¬ÀËò¤ñ÷Ú{¼eÕ:º=­’ò³RR®²P›q–ŒžBË…“TvcœÍ…+ÊeÂå%X4Ö 3!I{oÐQ,Γ$ð»�}¸\£”îi$ñÏ’¾ì½†í¯k¡é=iÔØü@tµ?À®Ë]¡ÅA“e¦óÕHê>Ã+W•Õ£šú}VTO·†ôÇ÷ËhÇŸµxý£3{ö~ ³:.§À[ܨXÝh$žï€ëÏšã颞l¢gÈoÝ ÅÑ×A 9<Ršc oòúÈqÜbñ�lTÄ>�›p[ÅN²Ú> µŽ8òFG?Þ2°…@rŽ<2YLÏ?7'_À¶eðö¾gžhý÷+èŒÓjÞâ&ÍÓÔ/R}¢Ú}ûD).NO&›áß>aI§±¸ÞwGþÝE/6F�Gã"ü´¼¦ï>$ŠÙJ®­ÁqÓÃáÜÁwx¸é¯Ø¼M„·b Þ÷ 2<×püè,(·�€AϦ`•Q_ÉúÇ7h†ügš:üH}Éâ%9‘°*£¿iŒzâ nšuŒ÷ç#�¡Rl9©JÕ:÷ #èVçF³Å·=úCš<¨ê(¨vÄ%‡Ãy£G\úüiu ÁPA÷Y�¥º^zÐ�7Jˆb6P¾f*õÆLžÝ×§šWÑ¥Ö¥·LàÆ49´¾y&Æ{À)­ZÒñƒÔáæÓ¾”5ç± Û¢ÍUvð^EN«9€Ë|{R¼—_Hý7o&ìŸQ�G�Ú‰k±ãÜ64<ÐWÚ¯à…_Á‘$u<÷­6߸* ®-O9ÿ¡˜3Öh¼MO%¬$ÇW†èuù0:+7pîˆ.¸¿`Òh€OS½ ¨nñ5‰oOÚ­"û­ûĉð\Ø1±Ž&~Û$¹ßã6˜ÛOÃ5þí™b}øÐ5ü:B¹>Ôxõ/í(� ³¿0ìU/FÌ|o £VVÐÜ€ž ý×–”æÅ~+Àþv7ÞßùY”L—âQ¥ÿ²Ä‘SÝvÂóÄžü=TåkfŸc… œi€ÝÞ¾¢c_íâ£r´Œ¯âD«½ˆû”Œq²U*• ça)0f÷l=5 cÃ^çûð\ÿ?�®ûì7NßCý­�±Òûïâ«ô0pTÿ+F߆˜cWÀwŒ{±öX#¼át,/æ¢LV¼øÁ¦;gÂ´Ž…X¼[ãOШ]�…ê}VyÅñ�ßס¨ß \«ˆ?¼­0S±ˆ~™6Qî3T‰¸.JþZ‹é·#ÑzîOè¾þ††)<¥¿¶7%6ÔØ}Ö.ö:•Q¿æýrÿë—D†’¸ÑÇÛo_�#]ô2pÞ]{ýHOZ‡àŒ@ÅXþþz<ïhÅ÷Í.�ûðø¼BBY'k¹ïëy|ù§,7]£’C–ØÐçŽ(Ç‘¸øË?—j: "HËý%bà <ø£“„ÝŸ©ÍT‚¯¾d£š¯bŸŸ¼ã±*ïlÛÌþ‰Êöî& |à®*|>q†L.>ÃçM›ÄuV†¼½û´ÐSj4ŸZšÀÛýЏÚN…¾¦+òÛ[”áö+}5Š›¼ws™ž�oÞÏgLŠ1óÍ \Q~‘JR«'npcÜvtYæÆÿ �ÆÏffÀ]©T–ë*ä> y…Ãhញ´Zì¯ýîý�áòIJ�Âx„¨„ˆ ‘•JEzŸsT¤…$B[‰¢EK¥²ÉL„‘Ý¢ìÞ畦TÒî+•¶J{K_Þÿžû:çúýœRà'L‚ik#¹>â æTõÁ½K`s,ŠN¦óÊÜAøQ>Z2øÞ™ïü$Ãnæ½÷¸RðÒ‹ã‹P'ï<²-8[¯AørÄ•ŸÝóÙʃ¤UŸJ¡ét*Øz_Ó?¸cK »{wDÕѶØYÜ­·Ž\–- hÿ7Ë?7Ø®O$ïÑù_¾&€CKv{3�7šÇÏM£`üâ'pfNšz/†Œ­ÛÑÐL�ì¦Âo "ÕOu ¿p'[õ£ÿ–ð‚Mtsœ+—Í¥Æþ´Æ G½ý²Û L³>›©–æÓ|K´Y¦&¸¬Ž†Hë+07«M¨y^Fï—ð˜õ1è|6 ‚ž^†Ó}• "Mæy.Fe%Îâ¦ÄÑlpàúÈÅð™ÈOPóB#ÆYá¾þ»YW߀‡žýIó–¾àþ>¹`S¨Àå—h”Q—ôòZ¼òßTìœ!ä^iv4cŽ\+ŒÚ©Éa:YiöÄ%?ûq*Îf×´MhÒܫ޿L@G1>L‹Ô[«aTÒQv_¬‰ó�#­}ñÍ—•¢�¾‘ïœÉ¿��Ñþ·Føtªï Ãd…�àøþ®ð,Oƒ›×yãõOÇ)¿åI üiÔ½Fð2±ÇÎI±8³¾Œ [ V €Ó>Žxµl$mOÂÑæãÖgÔiŸÂreP3>ÌM]PÊA²ýP^»„¿õÅ,¹Ñ<ùï` ÷�ºutG³»é÷�Tt—¿6áâ9Þ~½A&“SœÑF>T¶ ʼn•pż;&(Lä-“+päK-\“5”eÃ÷â—÷.lù{4dihS0–Ò“a–Òcé¬�ñöQyNêaÙÑO1òn;½›°_`õå¸ôa,X^ÍÏçbî*{X ‰6K½èVÌ x6µº•tA Ü/J�aËšžöøâ”…ÿ8@Õvì’w°ðÅ`ªy†:‡×QÛ (Ÿ×3†šaÃN?,9��'¨ Ý‹;Òô„éì=Д×-�åƒË5éåà˜qfmýaÂAÞui9F'ùàþŸiT�Ÿ�¾ÆÒÊ¥byâ“Q“áRàm¸¥èˆÓ]ÏÃèÈÈ®[�w¦]……·Ã&…²Ùù/ÂülgŒ´e­ð<ò+½ËQcZ`ÃÃ}0ý�Ž œˆëâ¹ëì ÔëoI ×?Ü£o“#¹¨}½h=�-KNÐÊqè½{ϱ5�ž�²™ô£|Ñß*—dUªÄ6mQ(ÿð“Žd>¢ª˜Ë({^‡¯|ȱù²U�²NKÅÇïÑóÚ&*³¬âç;OSÕPVSfÓÁÈH)óËÎÓeíoârË/ÂíÓ¶¸uu_Ôº|bÓE|l/›N-aƒÕ«!õÚÚ$=ÃùÃû¢Jþv^Øé‡ÖÇ«Qѱ„×ñ™ö ´ct%° "V\/­÷š�?=I®9\p/ðô§ƒLµcéZc/—7çË/4‹ƒ@þß½Ÿ76ušlødÐiȶÿ\,„þ�ƒøŠƒVÍïÅå7GbâçÕðd»¦}ÉæOÒ~¼æÝvv›¦b{cÖ7–Y0Cû7 Þyî€qŸ ù¥£Ž]󜾸 §­5ü÷Cz¾^‹¬á+üÇàÓA‘d·¡™&t9á±'³Áæë_6�˜�Û MÞvl}ãt>R¦—9Æ�áÍæö8bEGé¡åãy†ñ)º²«��“U8éeöê*£Ãº�R�ï€�[àûÝw„¥!op^Y&^˜áM¯RíèT8 vüëÖ�JÂq!¸UäÕOuø§Z²Ô:Ü•¯Z§`›ÒA˜ýÁŠ�d·PWÒ7PKÓ‚fÃò°ÉV™Ýðž’v}¶ƒØÌ%|ÝbvÛ6•m¢Úé�õFÊi4GÃm»w+®$Àãg<ÑI;;@€u¸Øù°ŠãwHdM@Í�Qsõ`nI‹� u¼ï»'¯�˜Éµu[ÉËÇ/ z+ö¶ûNÎåE¨l]®ÇKØ»(nç�dzËÙ~¹w€ýì£9[º€.nÓ'Ã>jø¸žu8¨¨ß°ª%›S¦W@ƒ—9¯Ù=›=ξ’xèÊ 'rÁ/x(ŸY4ƒ#œ•øå…S’Çï[Ä'ßþˆkûvA™³³ýM1Ýi[ÎúŒwSd8m{ Ø`w[ì=¥nÿ.}ý‚Ü‹ð¤ns}`Ó–3Ô×ä½;³W6±Öe�–>ýNÛÏáà K8¾¬7Ô×­aÙí5°8–äÝLpƳûôèßïç#ÒÁ uã… ëÆáåâjºmùI"Õq“VÿØ$i,…+f¬á¬%›pÕt_6 (ƒiaޏÏÑ£—ÿc¸eÐTí ¶ ¥Ë>Øf_ÉÍM…˜ %Soî¢ÓnZòO›Û¤±ä�踴·8yZ7øÑh‹gÝcÀû¸.¯¯Í —îÂÏ+}¡À~æœ*¤—ÜÅ‹yGàÚ i|"i.„ï9GéÖº¸³úÑÔ®ZRò­T!À- ç?ï‹CöÆÃ£–lP¨Þ„[K{pF¿qðÀLÂñ[qÓÉ|ÜÒÞ>=£è�ÞÊñµ/ˆZýæ²ÏÁMäàš‚3�waèËB¸PµžOÅ%ÃŒ1Vã&;`¿�u<x—øyg&H[¶Ñ�¦7°BÑug/#ãÑ¥�­µr�†â}~B/zÅr¹÷ú4Ó‡÷„Ü¢x�Ý\¢¶•mžuãààž<@_žd¢8¤k: xy�š»X2^EÉÕ¦ó·‰Ḁ̂ܢ5gœŽB]¤:=é‚tLêaâÏ`h�+à‡�RŒ~å€-sžÀN-~òd7«†–JÍÆWRÊÂRñG’}ÙÌ绪…¼’Åøâ¿¬ã0‹¯CC[º�Ü—;ÕÃi–뼄*„7ïÇ`äßi¬z±/ÌøÚ�åcJD9ß,¼uÞ Úµjióòx>Ü•�m¦Šo¾â$»6²¾qÆf­©:>2Jâß«¡é¸¸/W™#Ư†Îõ†œ¶C–ŸéŽÇKf6ðþ[$M]@‡ `rF ¯,= VŽwàVá ^iõŽ<*ǧ®½ØÆMUm“,ðÛ‹ôë ºä:þ5áÍs—QÇì,¬+놚Ễa.«Èc_&'Ér»Ó\‘Gõ•xz÷§P¦tžKåJ!|îr<*D é2Oæ^áôwT'…¼¤¤Äxlº?XP5|Ɔºñgÿ41PCCÓÝ8áÞJr»´Ÿ§“Ç®°ád£?[4¥bÿÚíd=®Þýëãs~&ãGrLÚ<˜tMzix-Ÿ»�G=§›á†°8±ã =ú’öY>ÃßžÃÏ~/Åsù–pYï/íí"í™#ÚÇsBD=ÞŒ¿EJ§ªù`| °v›}�PõìF¡¡y<êPâÛšE3F‡³üÆÂ”Ñ*h^Š—3Ü„”`3¸;aà§f ~ü”ß…ÈÁX©ö¼­\ïrs.®úõ©©(EêÒ½àÁgáÒ•¤wþ¼Zh+è4Z#_¥¢i}q‹T‡õg'ãÒ`->Wß¿þš‰)JòóYý«3 û%¦žêÅWþù¿¬y6VͺÈþ Ÿ@Ó�óüyÃvJûÀ·nÛ‰;÷ÄÄ?3Øï¸²>0‚Ž¿y* •Øð´)?A¹ÀSzÛf;ÏèÞÆŽæuµ)èËj˜ð* WÕòŒõÏ(99“òô»q^á#j;™Cåñ¯EE77¾òk4ç,v‡Ç&Ð6Û=Tã=.öñåé‡dað#4�'׈ÓëLx“åzÑï\dqÃq¡Oaݲ�äÒ§@¢�= *…®xâ‚Cœ?Q’K.ÌÔÐeçæ œöúm•�ŒY…ÿXß} U)aË ._#‹ÁσùÂ¥dé”`uˆrÌàEO¥d»®7î=¶ ý÷ñ·°±´¨ñ.»× �­™5ä´dîøšÃŸ" yî÷“0ä´—+põÂ%�»ùúY�áô; ‡îà æ7)&dË�Êá qnÌAqî†YTc˜Ë©Lå¿Í8°ÿL’¾®þ¾éE’Ño•ySD/LzY mqî¾PØYÜ9ºÿÁ�4w±cù‡8×H£>\D®RzBtÖ€Î\‘E݈A}Q ™³n¢œú0 –}LÕv`´{ +óåeS§ð‹†$¡ùë–$ûÐmß³ˆÙ]0ëH7¨ý°ÙÌ;wÔRªÉ"ùïmqÞ›gÞ{�SF�ÔrhÝhÁ/ ­¹+[ÆWNì·¿3Ä#õm{�EÇï¹Â 㑵c ã9mÿ,\t(æÏuãU]²¬·ow­ ÛrĤ5ÇO^ ~ƺÍA\møÌÏœcí*8Dï¢t@ßfÖ ’å§›÷‚°Y Nãja»©-ÈNnâ�Á‹Ð¬#�$ǣǗ ˜=}%~Û_L›ã©yÐ~víýòN€–Þ_©ÁyJzÿ¼º>AÀÕ;Ü$m<Å—x1´¹ŽFße�©n@\|ånÙmŽI’µðTÑ78ãy‡}<íÑ^ºÚ÷3'?ÕÃwïP²>Ÿ¬û#[‘zž—Uá jK8Víºx©¦KX=¢š¾Ñ„Ÿ"ØMµ™é÷¡óD(•] äáþ¿)þôrÔ;gÍÖ~)°z›YOÇnq^’²`mj‹Ê ™ßqåÅy¼¨¹ÞS<� bÿˆW¯¾ª[ÜÑ�“6EqMëO>¡‘ŹZr\‘+öõ&‹Ë›1T2RbWÀ׺¼Û£²† ]ºÜƒ¬“ë�äì°tR¯õ>Aû¢+ÄqÇúÔ«hLD1 Œ‚ú®¡ç pôÄ]ÜlßNj“’8ä“1uÎô¹zþ ZKË)e»|ëLÎ Ž6Zóš á¼²Ç1ÑCÇŸÖÍá4™CÒë-ר—¼Vnm'é©c(ié‹S.:R\¯©Z}NA‡“#}…ް;T¬ð’üÒùÙdŽÏÚ‰k�_�¶ç Õ%©)ùê)Ï—­áNýÚ5Ë ß×,Á“!˜T—t\)tD (ÁD»nlù8”]íE\VïßhãŒüË4ýð$ô±>‡Ù�çÐa�$žíÍÉ#V¾è :¼,�à¥<+¬L+¿dìø~‡,eŽÑØO ÓäÃʬ´ËçÈ¡ÏÊË\ñâ9Ü+Â7OÊc³óhNÜ7�ò ?ßÁåµ ¸bá«l��û²ÉjP42ù_4£ð�L}êz#8t36• F$Õƒ»S»-{—Œ>%ÊìÄÂL ôü Iï°¦Y(Ç$íb§Å²øöº¿xêo ˺­áG‚!öæEé öÒ±-i8Ó#.õÆýi¡4Îq1 ïžÍEé=èlënݹ‚f<è†)?TPšúˆ1V ;gÜÄÐÍ®hôljFðOéCã•fýÏóLƒÕ‰û429‹fnËÇ'¦A'©"Õ‚NO¿Ìù¯MÙ¢µ’—'ˆÉÎ „~¡š$=ŒÿGS­"±��ú�ñ ?Wøã GWº8(ž®ûA‹bNh …Ó‹’ùo}›paÔjÒï©Ä÷ïÏ…ï“>ƒ×åžüŸæ_ѸçÖØrÔΟD‰ÂZ<´á7|ò�U¯“GW7<:´ Ê×< èÊo¬¶Õƒôux¹ª�Y`ÈCÆPæ‰z`bÇ-ïœQó‘žô�“æÂ>™¸vk9ÛšyàË)dÛó®0Íà—˜ÒXVõ/vÛÝ�Ëßw²õ4/– º+ô68TÉµí« G�*ݤÅóvZ𱉃ñà:¦îhÆj¶¨ÐÙUUýë¨E€Eˆ+Ë[^/;Ë…½Ô±Z}õ¸2�ŸÌóÄöžj¦?…‹ýr èq"�—¡ü¾Ù.yN_]#èî×\ õ/¡È_ë87¢öŒ»Î?Òä9{ç˜YøúÐo„§qÞÂ0΃n¸ÜÁW§†BüKu¾^÷ÏO*Î ·ª*HE+ÚÓµm#Ÿëð—Åìi´3&Í�Žò×ÔX “Þ«ó›€4FýJŽŸ´–Ç.ã…¦�Æ{ê‹9úä-Áio4ny1 :®ÆÓc4xÀj˜±Û…—¬È¦ÕGèã'+nÅ(èæÁ“C“IJ!ÆbÓC¼µ!]|Wþ×/½($8&ã|ê‡ó&Ÿ”yq„s()<´Ã‚ÑwDóv|1½/¼yÓÌa·ŸÃÙAõú+ÞAÙ Åò·TÞŸÆÅÀ?m ŸhF÷ròÉÊ»W)îàœ…Ú4gÝx4pX‚Û£^ˆ6íbqêÎ\nŒ ?tÒë!¨cµ]Lnãôͽ°p•y÷kv¬‘r¸©*oÖ�†7>އ=Ñ$ÓÚ8Ô{¿7�LVKöRáÇÚq �†õÅ]�ñÅöËv>³â�†÷)Õ±‚-_ö„›Ý’pÇå¾8ðÐ\!÷ÈJ\~ñÛ?wìÅYgƒ�»,®ŸL¤7ƒ0`œlX�E]�ã%�–©°…büjÄÍrŠ˜¼+‡UØ–ö Mæºçiqº?¾œ;V\|ü� Áû£Dí[„wËà~uø¡>C=ÊX©‚ÎGï€Ö™4v��ϾâT�"²|®Žº'rÙfé^Z›vˆg'Zcû¯•x¼c$¬nƒrU|£XúïÞfÀà á|Ñð(ì—^“iÆ?÷]Ðd°¿x¸ˆ|uçâ‹ê#ð&±–?/‹§ÕÅÊØ{nµ—ž¤';L¡þ®ÈN©�—›)ÌoÌõÏ÷‰JçàW•ãà¼C…¿?…†)7=  ¦Q¼/½“6xäÒÚA«¸%™ì³øQMLê”`tw_>;3�A Z2c¥š7Y/h5~“æg8îï;åcœãQº×„’q39oÇ z4 ‘ÕHÐÊb(½üÎ.é¡MËJ\x/©ùñýýP «ãû.C¶ìXY5‰g‹CÓ’åü|`ØÞWW$»�à [ »S­3C¹wô?¶ëš‰ïûó­+'(+ÆŒ3£'cÈúv É1³¡¥`·d§…2Ø›ŠO¯Ûá�ªÜX¼”m>j£pe�nÜÇPS^9ûË”Ó} _€ô8¶’þí5ù¢zª,Œ¾FJe7¨2iÛlîE«<Öá–}/`í«@vTöÄèÄG°ætڿΖ¸ŒP欨ð;²ƒ‘§¹î½�JÕʨR_#þ~–Äg柃“»^ŠMÛåiÝÓváºGµ@Þáüµ|Ÿ¨x=LX¸³’ö81¬óðÁøÞ7ÙøšʽœúF-ÜâúæG¢«C”UÅöêIìýü {zÎ\ ‚¿6²¶Êå ñÛo+R[GéÚoÉ7e#$®Î¡¹Ž†è²£”L÷Gò³u³p®ü1Þ°T?Äüãµq'¯§ùó¨ïåÜY²†/Ý<£7F©’>�+ü@ûF‰,ûÃ/æ°ÂTÈ÷%L¸À©eÜçRfÂ$êå÷›ún},t³µã�ËWñ‘¶�pú&QŽK&p÷ïTÿ¢�¦[í—æ¹ÀÙÖëⳚ·à/+‹NCvQÙ'9ê×ë„нÓ_Òy§”ÿܵƒc™¿ Á¯oÊôà¿Zù`rb<|¯F£y*`§–�RøFq¶ˆÚ†ÕÇFÔ_·V¼×MAúáµ!9å&ñ‹ÍÇÏÀñ‘6–íPaóûÎ`“¦‡o»)³Ç‚aüáE3M©ïÉy% zXúX(Á�ø8õ8þ\dþÝ{ÛWž>Ór^ýëÃJ½ÒWT"iãõg/RN†—Š�tÂißõ$Zm»Ew-'Áç³—a½ñðZzOìÞýÝqn‘«“¸¢ÒÃ&ÇÀ’ö <ßÖŒ¸…û§ß‚Ìž4³=$«‘›5ëø—ƒK]0ïòlØ×§ö´À«·¬±yì\6cô/IþÃqð5wn׋Åõ÷Ñ*Tqª1|´Š¶�‘Å™™oÀ>„ûû̹Âh"Ìì_JQqzØãønê¾&šÔ–Oå¹/õ9 §?‰Àëóz£ï¨"a�ï$~s`0öõÏ„»GoŠ#t´h€“t+Uz M•;ñ¶Ç]ðsFt½>ˆ ç§œ|tX îLT¬ºªÕÈï¥_qîôy{$¬›ýŸè}ËALqˆ†¨è—bå"EœN™lí™ÄJëÊxÄ÷V¡ÏG70‚}ûŒ$Ãôìß¼®üºÅ˜}ÿ¼¢MˬØnúô’�z/ýðúÝêšmAÊÏö£jÑ~\s]cåVðÕnô´t ç˜\ùyõOµnË…á�­<*¼S:Bñ½|•*¬ÈÒbýzüyD7^8fýZ<ì÷»pqÍP˜?×ûôý—CÇÛ(«?ˆ¾Ζeë{‹ëD§f%S‚íÝæÃý�¤§‘§²Áeþ-;BG%‘­�U ¢o®{žÇ³26òË»Ê(ŽßÄßôq@¼=:Íy®—>€l…ıª #àÊø˜¾ü_ðÚT¼•§%¡[ëw >,dáEÁ!Ò�—Ã[·ßðV’×B%[OMDßc²œ)¹‰Ú/¾ÂÕÚÞÜQp^"ø�Fÿh„(l6š oÎ\%ÓÄ-ì^ë nµ } ÂáëßBÌl¿÷w;cïŸÎ¼*é'i}}=,oBYû <¦d‡ÇÏÙñàÃ-$×­žþöæ;[uШ3þ‰Üα¼.¬×lD³ˆžxóÜ�Š=ùΚÐ4N3i0Å´d{É¿ýóJÉ¢Gg8kDsÓ§Œ�¯‡1w�R£ñpGbëÄÛíʰæãz#-¦ËÒL\õ|ºlƧ‡ÆbôóQx²G v½V§“‘©¨þ5ž;ÖîOŽëÁ&G¬Èhÿšáü�,ZçpEë,Ü­�O*Ǜǡå=Im‰ˆ[Õ·ñ ¾G°¥6”'k6гI‰ä´DØûö(¯›ÛŸëŠŒxSµŸÊŸ‰Çœ‰6ríúã�½É””¿¤A‡Üp|gÊÿ¥5°ëÊ4,ÿÞˆ=]ŽAgáZ�<eUw‰kì" To(ï]_M™‡dÄßΪ<䟗ÅÂ� âç£Ôݦ?�ך…[òbQµæ‹ôšõðÊ­ ä+øæÕå¸å¥+¦yéñíÂr¦ƒšØ¤<œ›‚?Ÿ™˜2b§d>ƒ—«OÐ㻞¬küÈ.…¥3=ØéO¯Vbç÷â•uŠ4}9¶Fóý?ÅœüÒη}×@æ?6Ú“.°[ŒûØÓWMDzº¯Pa‰ iÇ Â`äZEt)ú~þeد.’#²Æóœa9X×Ü̺õG$>Þ“ñíjYH¨èÅ''¤�|Žx=z*µs¹hÌ!Üîž�‚DáJJ6Z¸Ü;$º4²×-ÉÊk1´%$™÷«ú örûÐuj8gí¼#h:H‘2üzÌA8¹-†=—±rÚ@è¾¼|Uçs™^7ámñúê­Èû˜1xÇqb·�ôaÇ zº›pšŽ'í{ß˶ߥ3hãfˆ6LƒÞ™·`ZIâŒtú‘—ƾ‘¢•ïfššŒ/>G‘±» õtÇõÓNRmU.h®å•¹xM+lç+òÞüŸ¼æ¿o0pÆo² ‡ÓáÛà ^¬KERWXufý ÕÁª[^ø¾ÿJ¬/’CÎ ÜuÓBhŸ®(i—+áF—váÁª;ðnÉf8ûm³L#ç~¿Åîož‘üêjØ«3?Þk‡_P¦ªœœçe¢qÎŽœyNFŽG»«=!å™#Ö Ÿ¯5ÀOc<ý “5j•q�ï9õÒ‡ã}OqRW²6Ô å—$BéFgq«ŽŒùdŽŽÌ`Èo `ïȉ¯NBÓ¬7�ñ]†ç6B†b:Ì\æAæóò¸¦)lsÅÖ¿DÏö�ñéç`xºˆ|ÊÒxòçáêj"çJ é;±Ýq;=½”ÀU÷_‚×0©ØWI†'›[Š%ž7Ѷç/”Ö�{Oä­÷ÈX}1þ·árŸËžá~hf}‘¢”ŠÕ×4ñãþo4î}?ñ»•,ô\¤ÄŽÕÀ·Ùràˆ?¬¼-2O‡k*âù�ºtpj+õ8FÏBwaIÓn˜ïÈ'«ã­7·ÿÝæüæQþˆÓâþuø•NO]¨}2â~(nw‘ç!Åà¹ò ^3‚°¶õœT¶L\ûÑÕäŒyðÌÇüÌh 8ÕŸÉ:níöL�·ñ­P°z7 ÷O3�¡^» Ý%†Ç˜”fà–°U<$5{�;JþóüyÚ«qÜ}(oúà‡³­”òÓÇœ¿s-7H�$oäÁjÉXxå¼d]Rìý¾‹Þ†”ÎL  z•Cär¼F7äÃûxÔ°(�ëÿµ JíÎìSïÇC\ Ààó^˜ÛÓAȹ&Ñ~ο§�êfÑÕ ~ÕêÉ4 ˆ_è¢#…¿áqÐr°ì‹mmÐÕi�˜}„h™NÔŠ W·¼±öáCáuM®ø«ßAÐÊd·Þ�xî¼/îú5…»D/eåXÃg/gÿÔç5?€¬wŸ-DÏÙQÀ—îQöay[�½YxÊ{¾e¢º´P˜n`+ÀUo6›¿ô–vǧ±¯ÿZ S&ÄÑO¡¿o«¶#óO‹>aªxaŒ.Ü5¶Â=­ûxŽ$™ÔÞÀ¨~g¤UËwˆ�Ÿ5»Ö.ªX\�Ö?�Áp}*JswCñ±R!a÷ðã5¥Vµ`�ÿzeKÛ£�X·×[𚤎7Bƒqœ½›^î…¯OZcYwc–{Ò3^ÊÚú¹_¦Ý»£åó!bõ¯Õ¼_i Ïã †oœÉÖå¤0Ö|¨´ ’…ù³ŽÒÎÏq,´Ùà÷ šœõDUÐëiŠÉ‡ºhÔÆótE[‹U^χ+…“xAVÉxþÛ•³„‰W!ö}3˜é^x€BG[GÞ�Qý/rÄa{âA^8{Èiê?`2/è™ÆãÊ20ãy Äù벡Ê9^莗¨aÕL|¡´kCÞ£’vO°|4 |d¸\ñ¼øÍktL•�àõtð:•Q8ÿàvŠS:"ñû4„Kçìiåuû�á?úÚ’‡gN‹÷Ü¥u}wÀùšëb|Wìu1î…À——²ô|:(¯[ò4E™�;Ñ¡-U(­>"ھ؇Ÿßj£åhMnúíʲK6ˆ&Nœ›ðÊažñQ^²Ü_M=Q_RÓ^+ÔŸä·,rYm´7%ÂFOM ß´ë½FðQ …$³'$s©å*ãxÒ†Aœwz5.Œé[ߺw;¾¨IBs›WpICBc—0,XÀÅ¡Ž;Ø%M¡KöÆ\}ú (U~‚áç6Ã÷K›ùkU¸:ÃÇ0D* m‰CÑ7`¿èãLÝŸ/ƒ·‡qLƒ*OŽN«±¡×wè�æ÷í§I¶÷f\xK:XqÕícùÕ½ñHuè´õ�"Ý_ü¬û4œI{oõ@ƒtº×Ç—Ò½n ;‹�øbÛ)ÎVÐeŸe‡iíÚŸd0䩵.ÀÒÅZhõû½Þ´‡±n<êëÔbñçp¹IÿTŒBº÷^˜¿sþ J£Õ÷áÂþ¥BÜ»?´Æ8Κ<ƒUúûáñÁùE×°Ëb!­êcûÂÄýÿ;€ª¡#ðøÆ_/Üíqˆc7îÛ ¦q×â,Vó §k7{À_Ü­61â:å/0h¯ffuÐþ“ÏhØãÙh½gÊÕÁ¤­.ü`e-¼ÿ!'XMã§µšô)T›#¾óå�W©~ýEûö¨ ã½~I?Z?燫¼°ÛD Ô•+ÂâÂþpÿI1+.[Ëo•A*!Ýa»˜ëÿùº×¹(pµ¸Mó$˜Ò›³6é&›båÌ”u�ôZ{â“áØ"û‹ÔEðÍ^¿@zXNÌšP�Ý–FÑÝöìw¥¿/Råá "w7: «ìøPؘ½oï±LÁÑseØ &¢ü‘Ñhž|ØLRdWž’ëαCy”ŒWתãü©r|ÄЕCBRéAÇTÌ{õ›*½íxõabźQ´¶!™'+.ÅÏEîü7£žc~…a´÷^lQïÍÃæÀßvá'Ó‡Bk{¥˜ibø…ábŸ77ááðËôñÚ~ª� žvnP’åË›ì™jš¨àoõ½f�ë‡ è\±†¥Ãµ7ªì0ÚßÝpc«´||¼f½¡‡9Õ\“3•”K8´¨ƒ-æõ¯ßØ8Æü1 G�.Ák]+ˆ Ü º_ˆ:îbâTŽ–H5kÿBlØ%nþ€õ<áS«>Š×ÚZ(óX!m½?g�…£ymv:ýMòâ`}UŒZ?Ǽ‹|ï×Jʳ ¶Ï¿¬~ «zÛpþþ©(IŽbƒuM|Sÿt7=ª�ÌSþšáò,hŠsáA�/Í›ˆ“cLq�y7tÕ_%5åð‹n©ðÝÈ»/ò[µô²-â¿�Ã’»µ\¼okgw¯W[˜1û\Ù{ïêˆÕÀ¯È^Å“5–†B¼¾%ž® §¥ggq�{ûøþâgÐ�ÛÏëÇ3<˜´Øa@КêáÁ?¯¼!³o¹X¸]à›®ØÖ«Ç¥eà¨õ4æéH~k–ÃÏ~ã _~S¤íf23œµ$‚Nޕǃ†³xvmI¾Ö³ýªÁؼg J»Ý¦¤�/’ïcO›/Xë½)§Ïª¤¦×g}Ú$-6N¡ç¦<¹ó? 8VËQRò� ã[Uýóàý9íü,ÅÎ.4æ×Žwÿõ_º$—‰�{DÐ×»=økm/.Ykƒ»­ÎСµ!gÁAj—Q´]ùØ„“VWbú¬çô{¶(º½4åõý¦J Ü61µ&ûe‘ృ±ÊŸ•Æq¯.'îp×Fz~€É^†Ý•UÙz°„ë£$Üõ1¬ ¾S߉«Ð·x+Jk†¢ÃátÛÜ¥‘ ØÝk®Z<Œw?Ô¢ÛÝö�ûÇ*z�ï#üpk¢¹K’p¨jÜ82cfPCs¼nÝ%m:›ÈË䑟ùC­¿]¸vñ¿ÿ7�S÷æûÿ2£sˆt®ÿ¦Î° pœêÁ'µgsÜš¾ˆóŽJ5vÊ¡ž‰Û¿lMÇõÝ'sXÙaÕù9(Ù•>AÒÜ¿$:�—„úà‰†wz«Å YeBZ”~”›€¾�£¶ž<óë~šïÎ?�áȰߔk\@Ó—1kpã’!ÔkÀ¼ªîGwä,Øuú#ûõA¥~ø•p—“/OÃîl]o)^ýö]X,y.¬—À#é1¸¦»Ð>¯«Ô�†ó '§á(�;P®öÿ7E¯3¿DŸ˜"úd*+<.²ÃÔ Cpvl9©™Œç¬dp…[åÍûõ‹zÒ‡Ôê—·›¶Zcî¤L*~5ßhgÒôê°zDÎ4 æ*›±ðì¯=¼ˆjï»=æ²{>ÐoéLþüw:]2„è,îJü ãæ-æv³4¡wµ&{ëT�‡Åv¨ cÏ‘ÜæLþðó34ç�²Õ¸¬Œ‘[ÄLÛÕ쥭�o<µ1}½�ôððºvx#»—7ÂÚçÚüªÅ ϾÿAdž•ðóÿ¼itì¾k­�OÚ;Áùà Ú6à ßïƒ.Ç~Ðéá!TTºÂfÙ„± ~ïê?Ÿ›Œy½å šþu'ÌUã³'|(Sz„ë+æqÓ²<*®‘LÀR^Y«Ë9ƒ|ðÆÍËX½ù,zWlsïz(•g_‚;?±ÒÃÃtüÑ@lî®ÏFs²Ø@ìÁ¯v•ò]cn­_F£ °kZˆ€e ©s^zpšñq0žj†ÑU¹ä9äU�ÃæÏKñ‡¯ çÎé ¶wÀq�ŸŸœ�ê«(@9�w÷OæUÞæœuI‡WÏh`ÙUÙp¢Ñœ‚ŒuPÔ°—Œ(�çüq�¾� »:$2›ÓÑñêÜ©!…—9§$·v$‘aítª�ÍbîŽ"š04WTÙjÏ ×R®Å)6µØ…¶ÓG`ór-ܬù•†Œ.‡´hQTS™Ëû‹§qñÆÑ�§"Ësâàî-ÖŠ ÃZ´ì‘?›�Oc«…µýÏÁž6½Æ‰µ€²G wöØ€r� ^ÔŽÇØ(ñ¾užé²”&üþ¯}£ØèÈ!:bò…ÊS›iµ`Љ'²HÜšQ€a†ø´Ì�{«¿ƒ?¿FðÍYaPïgó4Á •ØBï[ á¼ât”éŽkÏâ<|=òx¨K£ä¦qh×<xª;Ïêƒã– c®­„ø3•ÔøÊX’ré#ðjœ0IŽ�û}’Lœ#KðyÀ4£¼ ÷؇B/Õƒ ¢~YÜäë'¦Ù­ä�.÷ëßHú[>$¿E"�ý�Âyê³1üôè !ÿîDqæ„^ö"Žòg-çö�:økgÙÿëè¬9œ*SšîPuwÚ£Li„0*Ži^ÇR–&›ÑŒqª¶so/WV® SO¾€ú.kìs;žï|™L 'ŠàYÐï¿YxÖ8GHÍÚ»´G°J’*Á1ê§½n-.¥vQŽÃFùÂâ·�PSŸ)ø×Ùá�qÏI­ú8Íz>U6÷ãnåß M»Rp“ûC›Æ·CçÈ� ]ãwc‚F‹~KçÖ6ð½ý9¬d9.ªd¾}UYTê1Ž×l»‡Míšhqó ÷,OK-.~âÏz-»p‹Âo~°5S0ÿbÎ{++±Åõ•øc¤.çÿé�%Ó§¡^È,0òýÂ�²ëyƒÙ³×=ÒÿáÂÙ§ŽÁœÜOdZ'ÞO5eÝ·?E“éó Æ3?úaæ]ê¸Ý3à/4ªÛ@~¬ Ýtœ·¤=æÎd"ÉÞõؕɋ/¿qX�xu(rßÝF\â2šý.ëÑ®á½9óÉ ú1NÙÙ`ëf‘þôKB»Ñx{è%ªvõÄì—¨¹ì~¤D¯Æ²óÖžlv2‘¢®€ÂL-4ˆ«óGØsÏý`_J8-¼tLذÙñ]E�òÓ”û~=ïÉ˃#N 'gŠ*{Óɾl*½ñZ'”í>Ï�Ã8Àrµ0ûä1ŒÓýOü5= '9n§;ïã±m_?¸­p€4ÛÄ.™gðàe¸¨�iËÖ-4ÿØÉ'.ƽCn°É¯,ôóŸ/šdþf·“qÎ…ßx)rÛ›ñôiyÜp;�6ÍÃ# úIVfî§Qñ™hiÒ‹k?×I,ße°´ã$¹,-�CÃ95"Sì˜6†Cªï‚JòD‰gé?¦l¼+2 ñ¢ÌU>øÞŒ‹gaaª�T€ÕŒ‹fM׸á9hJ-æ¼±÷¿î¨àš‚ZqoÈUaÒöó¸o³;è]ÎÅ�TÍK2w Nn+…úþ°3‡ø‘i%>Í–±}©üšNýè€Û6tÙŽ?ò¡åö;0X2’' \MÖAƒËM¶Î¹J:�‚ ®¡eÜ6' •nd='†V6ndëŽ|F?ÖaìúÖßtœ4ò¥ób_‰r÷g°ô°&÷ ·æ¡zhÌóR‚ÁN‰tch ·ÿzX²‡m¤¥Ðui·¸£ÆÍÝ�rzË1ò6­Fïa¼4¾kŽFá�ó+ÙàCoše¨NÓïPÄÄ ¸÷w_v–�ƒíiqÁâ~¼qö!šÛ¹ß÷ã=½TÐÊÇs#xöÂÙÿ¼"ÕÖ«ðü�@ºd<NPc/^Ê*qû…1sx„y%YM¹�Ÿ·ñëeß`âšnBÌ«áüýSš0ãG ˜¾éºØjaŠáã”{L=öBáñ$½ü‡3Ýd0ÄõÈÔd“'²8Þï%<îÆzó7à%e~¼Õ‡Ç{}ívÔhuäˆyþôNÎ6vÎgQuðr|¡^ÊåAk„ÂćbF6âòEÁpPÏöçÓàÓòU|¶´ïÝn£À©îPͯ‡uÐòÝñ"¿ŸÌíkµ `¨­sËb;·bøðô:ìÒÛ®VŸ8`¦!Û÷ZH;|'°þ�vh�� ÞœR-–ŽJµ©_™û±Ü3ª|°N`ÿÿÃâN'¤ÔLÙ·ShSc9 øyUØ9¨†Ž~J 1º¸`ùOW~ tÉV­¥2Tm) ß«¢Þ³‰8 &{;†ñîÏkøLù8^[5™¦n jž´ÂÝ;ú “jyQ�„Ò6ºó«žÚ0lw1$=œ‹�ÿÕ@�‚éð|}–,£ÃnÚü8*ƒÕÃ¥O†/§ä'òhqZÞvÞÀýT�Ý ['&àBŸé8ìd„ØoM6¾ Âg®Æ=cûð¸ÕÃð‡áV⧇1YU–žW«7¶ñCùÇÿu§,ÿ¹³Ž"ËfpŸ…Џ×c+ÚmHbë §ùÜ7n Ie{Å]ôb‹³DÑðL÷³eÃ�ºdê7B4²80‹Ëub„ž2ø˜ñ‚зž’òÞéŠÒÍVsFóhTø\)ÚÛ¥qQn-Ÿ©óg%çB,yºIÈnê¤+¯<é¥Úg±**:†i áÖPŠ0;€ÕßJøÐ c¨ó…X7)Æ´`½]á<Ãq'·l»KÖ“ŽàÌ*Eq€©Ó‹�h¨ê.¬x€» æœ83EøþïƒûpžóÎsftg“7o¡bâaʉTâî’6Žp8,¤•W@[¡ ïvuç&•õ�Ÿ—Ègþ4ÀÝcÅè¾à5]¨Í ;bqgí>þ­ÿ@8lîÌtËHâT1¾×=¤6Q¸»'‹1Ê�¨4OZ�MÇ&&8z¯‰8ž´ð—f §îâ1_Vò»žÉ0në¾6r:ÐíŪ¡óyêªw4NN–'7´ƒÃi!ÿæxq�²3õùצIaÈø!Ñê×ânö†� ãhsâpœ¨pˆ3ObïÁ1Üû¼  "ð\åÅS¾™¢Šé5Aðkʘ´�²ôRyìs[ž�wWNáxç;ì‚K¹ûñ•8¸w1™iäƒ�ƒˆêšYbDqxüé!¼`ØYQwœ*Þõµý±óÝêM²]É4x~ÚÜ,3µí?ð¨�u6;¨ñ ÕRÜu9 ¼¬ÊÑab ­îï½ChæsnN¶Æ¡³ßK+Ý HâÄþÚ&ÜÙkå†þ'ìK«¤ŸþS°=ø1VRàO}ì¹Î(@bû?GçýÏõûýq»�½šJ(‰D™¯çuH¢’$ÒÒBÒP¨´TfVQ![…Ò�Y¯ç9¢B¥-EˆJi)-õy¿ÿÁu»=®sî÷Ç×íš…Ëçh³Cº´n×34<¦?�÷²Àw!àt8Ÿõ¿ Åë3Üàž0Ùê®Lð»#øíÓ@6ƒºð`A)Ë-©ÄÏ�üSM¨2±œ¥ÎíæÏ¥/‚˱¢à?v'Yž?Dù�q–Þ5=x2çÛ5ÒŸ?ñô#†;; ãuWs×K2àrÐ=’Ë-`éÙ¶¼©t9%ªU{©w°5ŸÇð#lÂpÁÀ}6zM.š4ÝÄ™‡“áÑjøØaŒ#oû³×]epéù+¶K|)»l±Æ}”ÁßZŠôòç6„l‚Ô\,Y0Äš·ëÀ·Q+ $ú  h]?WP´‰·=E¥ø±x#8ŠÐFÕ0Ò«~j¥r6ß<<¦¿ÞMë—‡Òä9éñµ$0À³Â*ÎóOSU×í!æ×#Ï_®c ]“Ié„nõ±£É§jW>&ƒ¾í[Ím3ÚF3géà¯ùu8Ø1š2«}Aí• u)ÙÓæù1X[ZÃìFM¦¿Õ»áFŠ#[®ð_&­ü¸NNŒG;&(/gdZÓzM½ìGüex²,€ùäÌÃ¥Ä ¢(Ö….„þ§ dš6Y‡•2X8•o�„ÈBcĵ¶„¿Ò÷‹uÛq« OãòIN”¼ò Š^À÷³s19p=ò’“¡óï2Vè&‰Qá_¹²EX¡ô¥¦_âö¸ÍÞ³åY‡È^ÁU›Ñ|Ï•T¾–Ví\ëT;˜÷>Y2¸T…ã ò1õn wzP�~t_… I´óôrÚ¤™_¢±§#�¶øîÂòutÇ‚£R£S°'0ƒ__gÔ×àšÃSAæz:ßTà†k~ÖÃ}S �Ð÷¦ªPe�²I5e^DÅ™BÐ6E^ÓvÖ½Œ»Í68Ñ÷lù²¤[Qzþx,¾Úì 9“™£°ŠÛFÛ_ñÑ'Oa¥Óa ï[�¿¬€íž·™®N«^Az«ò(¶^³ßNA»#ߨ©„‹1vçšKïlRp óF.Én/àKÓ`©åúQdLÛ\«ák¢¢À/ä!»­–Žæ ‡�öæåØqç ;ù4t ¯RÙîÔSR™®¼›½ICë€ht™ÀpmþYÊ} ßkû@ùçlìþêN�ÿ8‚bÓRR”1‚mOW�H�#œ© å6N} Zs`õîŸÐnþë>IX´£‰%Ù�ºù¤þ>�{·Ù½nàvÍ=‹ö.�|ÙB®ñå2jž Uó‘ßNƒgéºük ˆ¼U§€¼qPø<»ºk1hwjîAÇb3�nÅ ‡f‘F@–ð=Q=6A ()Œz¥ú˜¶è˜0Ì™ìn¬¥õü8Òxzæz:h‘›‡(¯67ž=XœÄ bbéÁU1šeãŒEO§áóQ_бà“xp“×8_‚»ågÁãCþ踂`—ž?»±f$ŒP�MnØQ( �òp!î3YZúR�þ8P6ÛB[ßJÒÍgxÉûGéíl[¼rØœö¿Š‚–ª"\üü,Wz!ž.�ާzËkÂYÐÍ]ÝôÛÛð3+™öÍ+§À\à›ȃá#EvZÝ×ê/b]ã7CñËsøÇÔ"…ƒL²tÁv·Ù¤ÊK´N|I]ÍÒbƒ±ý‰9׫¾„^7[Ðó‚+h±N ϧå±ÒO�xsúçz¹šUL�§kÙÁ°$³�~çíDלQP¬³*Î`ƒ»\fÃ@&8D–¼Ÿ³?Ó˵¨Î„}SQ¹æZŠK3aÊŠé0ùÕfÜ"ÂbûmØ�lCpuØÀ^)Õ³y«§ÒK™Q¬¹þ<,ØfL3-'Â'Ÿxzkã£ï�¯N˜‚¥ô8º²P‰™𢯠5�zS•Ï Ùò;üøö¦Ð¾‹¢¿Ï‚'Þì ï{¼P#‰ÿf’ÿ­&öè`—°D-›�9:-FÑ?›Ù>§G¸Û±R~¯ë°Çhàaª»Ÿã¼5‹XlýKvìf£ààítö”­¥šÚ½¼á¨ÿºöŽÅTê‡y¾‰dØ‹àSËæUvRšv5`Úà�:£L_ÖESjüá›.H·cät Ü8’N^ EÙk§È¿ügÚÆ³[}á$þÍ &ŸÉ…Y‚Oœq¿Ý)ÝäËu£À<‘nuä°ÏÃuQ3ë9ö°ª6u5”Ζ¨}c�ÞKIó^»°w®Œ’Þj¢Ôý!šíÉ­¥k+àëùyT 9•TD®PQO.‹xÆ–¢ä$yúÚ•Âw¿r?cK(~U¬ÒxξÞÝÍ~%¡Z…Üñ„)ÉYøÄÍ}¦Ò³Þ�¦¬»æn#¹G&¼¯ç>ZµJég$SÖüÌæÈ pãûŒÑ»}.lYŠó‚>Ñž_•¬;S†þ»Ð)z™U4N$³ÁOl�#{2E 7l±ý¿«"ŠR|tüÞ.A3¯3«¾áÔR¼„Úz€Ö�3¬îI³QýÄýù˜N[÷Þç?þT'­ªA<®kƒ_B¦Ã™Ú0ʃ*|Vw˜>¡MQéÌõX«ðÇQ»<ž¾~ØÇ”sfÑ÷R°P6ÎD«ÂÛά¨d+«p3ªŒùŽ=€F¤B¸Až–v�æ;3qh÷+l‘{ÌËœm`bwq 7˜‰Ò!êû}‡uÀð¥ËÙ¤¸>Ntã) sŸMOtÿÓe·ëtÁOï ü²° ï™y4Ïà �*ÃÆÐ+¸moØ®5"ùÎýB ](ÜuÊ~^ w­ëÁ®BÈvúˆS_¿dyüÐ ÊaElõ£TΩ+œŸî8›ì×Áë2s0[;’¯ßfåçϲÊÛÍ8”§C}¥çYAÙò±â±B6_ Ýi¢M©Ú½3ˆÕE¾¡{¹£ÉBɆòëh£‚‹ê:ι�¸é=¼fõˆŸT8Àìw[ÁE�,hÕ‚Þu ðN®ˆþÄó‘A£Xpÿ)¡¨B?uN +×' £­ óZ„VÅ©±ö96zãIAÜ41êF]r tþ¿-� Åç5W£ÕÔnëÆ¾1öü«n`Nà�ß&:´Í‹ú“Xê€ñ %ìqb'¯ºp� ð¾!Ð?t”¦äØ�}1tpÊmìVˆ@5µÏ�zH„øþ£¸»&""OÐÙnP¶‘“›¿C§HÀˆGçhÜÄu,3ü—P— ±ïdØå1ýôÛ3Ú·æÓÊ•)ºg­å èìØf.+i,Ÿ5‘V¾î6#ß>®û´Äú Å-‰&‹yœÏµPî›C=“ФŸKóвÝ�n½EO/âÿ1Õ…uÿå£~žÏ? uƒ¤÷ã$ !µ$?d?‹%I¡ZFx>G±ÔYôyÅd:·˜t?KáÓb†ÏlÍ1RNvŠŒMÐA¯šÛÌüÃRð¾)Ü-&úÚ€=—’¦—uOc EØ� ìBF!·zç1œWó_·Žó/{.A¡e8Ä ƒ�ê[Ðk!GIÎë þÔ%hž¯ƒÿ;ŸËArY ¦7'Ñîù.à‡WPøv15Iä2c«}ðý°8õ(¯¥TËgìË)ØsÄVØðÞÏ øR˜—<_ƒé³ˆFNËᢴ6pCö7Èiu?2ã!SgDgWbk˜)%-ãôî´3û½"Lüù1Ò™{öÒ÷þç.IøûIžB?GÒ/_;°, ¥ç:¡ô`ú¾ ;L ~KŒz/“Ø~Ÿ—dPò‘T\¦]mM=–ÂN;9À›ºÙðÏJHÎd(xV4M™—*ã)wÞyšªÝg5éþcÝ[ƒ>žûÆ®/R¢ÂÊ&˜ügW�%¶£�«ŸÖÇ®ÊÎ…î²ï§Âa š¯jGïs™Q‚Õg¼&ݦíØ8ß—qmrpxÄ ?7Ÿ}AFškð¶l?¶—G²ë£ô¹™JÆÜüÀ$´�“Àm’¿Æ~DÑìeïXªà»¾ykµõJŽnæ=ú—îÐ)“Hœ­Øz/Ó“6”:Îyø$‹g?òD˜&á…pMêÚÔÌÁŽödé“_C=ÇV>æt!š³3`š¹RuîÉ dƒ“©*MÌcàRñ*uØB—ú&�˜™€>Zñr°jB_rdqBp-<ýÕ�4„ôhQ ®.㮽œH"ÓQ�œÖÔâÄž7ñ§ŽÝ"‘6xsíÝù³=»2a†q37Ýv-ÈÅ!v¤°\²mþav…4 -l¤qBq]|>»?§'µjpB-ÀJn° oÜ—…á…üº/?ùéÝtGÕ þLïö÷ß ºïñ wx{÷Åã1¯ä'üûó•i]FçRºÙ‰æDÁ”kw¨J²»ÊÿD!”K[ �½”¤�â¤yŠÉ�¢õ°xcð7 cçR|¬“íG¸:7µ²íKÖÓ1ºÆiw/‚@ÕXôމìÐ�ï+™ã*Öïe3—ñ®ÊGHñ’ í˜×±¸ù3†ïL6Á<Ö� V×4´ýk9jÏ|ëú]Ô/¥ƒóî­‡¢á<œj`º§íÀ$k fŽ¼Ê¨´<Ú./C²ÝOÁ—¶•¤ðØ“J)�iòØô{'%žù�u—déÉ�ë`füLVEr·œ'ÀJ.o§~¦÷ï-˜Ê» N6¢AGÊŒ~ɵpÓÙƒÀaÕ‹cÐ;h"™Taeõ’-à[(Ž/¤¢â—xÜ>š §^ì=!n›ðŠQ^nÝìÒ)ÈÔ;@ÁÉB<é•Ä®V¬'Å3¡R)WÌ÷¥+‡‡ƒWÓ²¸¬R?šø`ÜÊݯîEÇdnuµ ç·ÇþöÉ̃·âÁ‰Já°–â »Æ��£Å.ä´TƬv¡«Ï«(i›6œµ?é?‚Èu%ô¡enxü;d¹ôiöÒH¾áK\où☱ #§wëY�Ý>:Q§`=Rú$Ìob›'gÂo>—©—½àsÍcÉøªÿñW¤8È¿€Žwêàei»ý¶�eçKU_¼C "%¤Òþ˜Fh4°73Í. Å{GhWíTàÕŸB«Âb’˜¨þR°¥¹ì`þ#4hÙôåô×Þg®Â˜�7 zŸ:‰ûp\ãî'X:™OÜ|£o¦b¼^üVä@ÆI'æT°ŽñÕг^Œ•ÚÇÀÄ4–{\²CÓém¯$W¬dœåþÓø±pæÛifnÎ6˜ì¥ñ§@g\8œ5o¡`%c^oö|6J‹,ÁIŦhý¢’¾6«ÖÍ‹‹²,Psp!¯¥—P[¼ —¦Žò�”ºŽ…›ö[ÈXy‰®SÅ©Ôgv†�j®lƒ¶[þ|ˆ�ô½Í X7.lòfZµ¾˜�~µœ[XÆòÒ2è‘ѪÕ=‹ÁÇÑ-9 ç_=ÀÄx9šmÞŒrê=\Ï)KöèÃ�³ nÙe2i+GÚ—¿’$ž¡ù«Y°èÅtxâëBÜKc¨jÁÉi]ܽUë˜üá2˜÷$Œn�mÝ«`—±-hx¿`û´ŒYý•'Ô¶Ó£”âA½àyæ¥aü“xyO±QÚzúqþ¡F6^ÜšjwHñö&2¹%‡E=»È%*ž„²ªtöåWÔN~Öé?ÆÛÒŠ´à�|õ¼®P>ž–³™llnÔžÄNçÐ0ëæO©x|»êÜÆÿ^ yû8f`¿æI“’l$.y3ÉJ%+eØkR�ç]?ð_çäaätK6eíZºqŸyÞ¼ÂÊó%éÕàQØ+9Ò:÷] T[¦3ØæO­¾{ùËï^c�ëVÌÉ~1¥¡.yë5ÖGQÔè><«p ÍÉðBW„V­)§ôðƒdŸjE…Æ�P?7š†ÜöÒ} ôÞÄ‘XÞXE­Ú9Pwj‹÷ûBë×´ò�Ü^ò±½§Ù·5û¹m%óàíc5ò9²|-fâý×d`ù–©ýÄsGk0yUªùO'Ÿ+ZØèl+Ì7þÄÆt1‡ædö·[”‰¬u'Ãè™Û,t‹>L;™--’´8îJ"U!h”5ž´ë”»B[rB£Q:0?ÖŒ?æ5�ìæð\Ò»í¼]ÕF¨‘•µÎr/ao¥MÙéCŒ Ì%æ5˜j2‡QK'š½ï c©«OAlÃS˜ü…ƒÐíðñÏ4nÃ0þ-!Õ=n°ÖÁÂ7\d7 ®ã¤Žôk�+¬œ±ó7ó{à�íѱöWXJEz�$?E –ùBÇ{QÈ7–‚§BÆY<Â�: ™ïƒb׃hÚnŒn…sÓ }ÓNÖ®ZL²Á!WRƒ–´ºƒù´ç,rÊ'˜ÁjKº“s œ ZȬ•P³1–N” ¯õÆðg×ÞÆœ¹ŽÝ»âÑî—m¸‰Úf�¼HÉ]Øø6”Ö©>B‘f©w§s«÷qƒê§iÍ1ü#¼ƒ»½(u>›jTð‚œÝæa«i‰6Ô°9º­¨7wõL‹¡/«¢…ú)ÜQФ¨â!ÁÆX1:®=JÏú�­ý>2½œ¢D?ó3vÆ7¯]hœûw¶Ay&ŒýM¾6?«DÕ§R€‡*ŒÏhÇçŸ1½Iïèúžu8n3F'Ÿ€ý0íf)f¼K‚;“èíŒãd÷Ò™[%f=Ua|}b ;—ñ.‡è½Å*°»�KVç^6ê£ìò^ÞîaÊÔáIÅ ¬šîC‚áõ°œ MÛ¯ÀþÊ1ð"},T€V_1n[³n&‡?d�*Á¢[Exx!5N '«ãJÕ+r$©öl&)Õ8Àªæ|R�²y×}Tm°…ML“$ ƒx–­I1šFhö­‘ê?� y‹e¨$y!]ÙLÿ‡¦Þ ;iŽ»$̸P Úùá/ßd½K@Â%ÜWËõ¨má��GÊxWÏ÷8c{%—7)Và½ÿ&mR1ÅeOÃi®ö˜¼ÂAhÑcHdÿƳ„w„"ëïB–ä~¸*:–þøÀ~˜“HÉ6Ló+–Ž¥W³’(<5]PñùÛÙó ‚ÉMÄú?/}EŸ6$à ÍPÔSæ5‡âùEn�ì®ìGòLöEå�Zp[Ëëƒ/Bãn z[^|ØšÞ³�[àÅÝ±Þ Ey”âäG9/bù?I°êªÚ»°êÏp}ö:øØ<²&ðZ¿¯é¤H^wß1«ÄîãMò]ïqu_QqóD¾iÄ5œqPV3øYìüU  Ý·êp‘›ð!L ¾Äl‚�²‘ræ,eƒGj›˜Ýî2ت2ŠÖˆP:á§ ²7[J;þ­ƒRßÑt.uWz^FŠz²“ß¿‚xÑYîl¾ÛStOiÛ€èÃÜ“hÂôÃÒ)nÜ)îð©ûÜÚƒxqz)t>KÂ¥®ÃY˜ñª97àã—qtó¨ ž2Н‡#îÌ7FŒ)qÎp+¤øÛ²Õê—=°edÞùÖIÁó&ÀÞ¯/„³ÅÎáõ­öðgq{ãÏ.]›ˆ ð€»]/µ—ŽÓÑŠê\5‰ÞaáA) �z š,ÙÎ0Ämnu¸|ÍVhK¯@¿Ÿš°½ô?öåÎAý<è+«â–¬7fÆ� ’y�7ðŸL=÷Ïò~]óèÒåaœœ»ÝT›v�ÞÒ¸þß ©¯V\eNSwu Ží…qÓF‘ɧIè˜û�ª„û’�¸tCL"VäãÈf[©ÃÌ!È{± �7z DVÜ`9K¦³wÜi>·Ã¡/ ý¬hÔNM(Þ¼~^¸À2*“ÞÜ$2yÊ,w$÷¾[¬g×�÷A)ÅÉT[¤J·†…`ýJ¼ÄLY5èJ›ÄwÚâ¥fä5ø‰é òånKy‰üG˜m8âöËZ'üëÀÝkÈ7æ>ŽªÁ‚Ê(àcN‚fc”Üq`†ëB`»Â*øRÉŽßÓà“l2™¾ç3ÌÉL·èáÜ�?-,Ír9‡î£y1Puz«º]„3†�Ëé=ìÛâ[\±»5Û½ZHEéÕÍ[˜º@÷õl“Y -{Î/>, ñû ¹¶EÌæ„}Y íÕrÕa1V[Ähÿá*¹=“Ky䯋€Ý‡t¸¼=˜1·5à“‘ýYÛ‘2ß6œµ'*ÓœÎVòvÝš~¾ð›dFÓPOvMú Óü}páÑÿ6×Í#°fn&ýzQÅUlNÆ�» wûIà¯1Ú´_΄nêÕrO{x8o‰›î>�J/Xç=»6ë5{m©A«EŒÀO=?$PÃ9Ð;#Z½¶Øºd¿gs óô»ŠªjRð#2ŸvÈyÂE¡½ê} ¿²÷@‹c^¿ ñÄ·páÜ=&Työ%ƺà%N&©Ï§ä•ê”qW›y0œ’Èö~éŽۊѿ¢žK5A‰’$Xæ …µ¸Åkˆ½ÃZuAoøl/s‡-ÞôÀç<Ï)Ã}+—�ü«ìص=쇹8&ë`LªýÔե̽ÑÜèZäÝ_ޝ=ªÙÏÄ�ªË͸#éwã‚�ެxMC�Ã/RÐ_ ªÚê@"Å�tQ8D’–S oÛ$V'o߯FR‘Ÿ§¿áÉvC Œ\^VVœç/ØE»øæÿ{§mt–æþçÔCK�Pï\«=´è·6)ÚÀ¢•giñÚQ´Ü¯œû¼"·‡W±•wi¦�lõ‹¢/øíäHö×'“Ä�øô S`NŸ§Ã ÝzggçmŸXÕèÙCî0-úp@V˜…¹Ekhþ|€…jæÂOVÄJujy}çl¨Úv„³›=�>§œa/c&ÓCÅm4«ù"æ�\MYz,05‘ÿ…63üj8Kpl´+ê&!Ìn°ä»qT¸™¶í8–1ŽO¯c2c`L€2dê„�úùQìNïI*MŒ€¨‹âôjã0(ÝhÏ÷n…¹¿nÃë,=6òr?ód9»¬i¾Îcu›Ëþ’Bcš*a¾ÛC’ô]õ.Ïá®°)äõ$ ”›!Ø]Ȓͤ9#ïö n.Þ€KóCÿ˜Wß}ôž�G?fKÁTÕ(f&rÃnEðßm:±b«|·èÇ-WKà¨kΩ3¢ŸÊ�àwùî_H -µH*¶ØöѬÆoZ(ôãgëTØï¸ˆ¢Ûc™Æ�Ë‚»÷Ç�×!9AÊÄÏ,ÁK–‰¼‘°ÿö7¾ˆmã}æRýw–àl@½U‘ ’¤G­–·aN~!ÓwÂÓºïÙÒùßÙðû“ó'ßd›;s`ø�¬¤Ö›ªüØÆqï%º51~ì–§™NÙ¥þ�ÄùZÆ/˜€V1etúß)’ˆ� hA³GE3ë¥GضGeT¿p<¯Ò¶Â^ }*Ïpâü)êèg¶J2޾÷Ýà‡…X�ƒóö¯x5×"sĸ±Ü8GEÔ2ØÌ,kýè¼\¯Ú¯Á?ÔÈaŠºÈûãs2sñ�_>4àêŒ�07Ê”žó®ëœÀÖc•V~Ìœ:žæœIú_‚g|@I)¶øc@È"¶:BÖhWÝ4ƒ�æA,VǽtµàZþ 6J±¼UÄ@²ÿÖX'�ï£D4ë^N!ü!rxø€Ý¾ÐÃOÊéÅ·£ŒÁÂz9§j³GòHáóuÖmXª"ðxšÔ�7×N¤?›"QëJ•7 ¿1;hêÇ0Zã|J…xNçÙçUø·Gžz&ûc_û x© Ùì'ò¯–ñ¿Ü˜t¤&,鸋æÃB™Ø†óÖŹæ‘Ö_ƒ¿G\�ŸuIZe8¿–€†�°îˆ5i­f+NHPëšíô÷ÆJºuf*w+!;W�Ö~§7R<Ÿ©_¤ø§^LR*®ºÏ¢-�kê!rt—¥¡ φë×=(7�h†SÞ Æ~ÏùIá—°­áÆË/¡êÚZ~øV'TI%Z¿ªO-’‡AR§'‚ñ¨0Û ¼ö·°‘÷�X–|,¹ÿãÃ¥žs—=-ar£>ä™ÚRÒjMø±t¤¢ˆ´%®p3z€ná)næ)]âÝ£…a "¤zªš_Ùw?~ûp�õ ÆQÄÓƒ460Ÿ³™lx¤¾çþbÃSÄi‚Ež:sŽ­8PäM£Q[î.ðŒ¢Icºñ¦ðëØx‡óô�Ä"všÀŸ¼ &q²ŒôÂg0 µJ0-Ëg»šu@gÈŒ�I÷8Wx^l‡KHñ³BîbÞ±@Ü^<x‘”4îÇ“�ÑèeEÜŽ™i‚9:Œnn“…Ø,ûÿx(� ëžÂ‡�ìÖΔnÉ Ïó#Ùþ¢ôþÞQ¼ðò:ÙÝê�“Ùð½õ:«u‚õîãliÝgòÒèa£Ì(>Ukgÿe{—4Óˆ¾^ÊK[I…¯“˜—Yýn¤¹å‰è'»Ç~æ÷•è�×̱6�'•Äk¬Ü­ø–qm)‹QFÅQ0ù|x}¯roM?c ÿùof'ç``Œ�KÎñr«`RâCÖš�KŠÊÐTUÅÊ&œÝÄŸ|²ÏϪÉsë1ø×'Þs×+îåºË‚Ž j¬î×3VœãÄ"F½f"×FA¹Äw–¿¢…IÚ^�}ëó�Ê1ûËpô1Õ„ý�g€ñmþÇoú®/E%*Nà¿yTŠ+Á?‹~x–õŠ-¸jÏ»�´¡Kžæ0�}eî-¡ãÞ|h}ϳæí'…2g1Ûj4‹ÚŸÄž_”bã~JaŒÁ0.ZÈ‚~tóGZœ9Ó N`¦åÍÖO:D—ÞÅчQY®œ6ÚÎ:åÃA+ú.ýY¶™âÔeª)Í`˲ޣ٠Qèq©b>\)V¨\\½;ŒÒ<áÛݹPv´€æïgÊ…M(Óu™kn»l'ÃÕÏÙœÊtä”%¥~ŠG—ßéõ²$ºÓ£ qÆ™`|<Ž�P ©‚¯|ÓÏn㛄û+H^~>«¡¶¼¦–à`Ø}z¶Ã�î.å¤$‡[/W’‡Ø+C|Ö=Søn:Üúþí8p<�ço­¡Ù×(Àöv‹aÿ~OÂVÐ5?NÓ �â:lϳ$“ƒ©|æì%d°J"sp‚R1v/ú‰ú²Åï7béá{ltO:?vøH0Ò£-)YÛòY«HAo¯�×®e÷~\E‹Õ-Ù‹/Y [7'�b«ÚP£Ã„¤Ï�d»¾™Áv�™LS‡¨Öã-=9µ‘þÝg¡)°uz àÝooô£¾ñ±ðg|Ú´ºd±óQ˜rn,úûŽ'Ù›ç!9%nHB±I“#²-?_á c6_Ùù—›É­i*‹©mÎ7ø¥t�MΟA_M]Q ‘I­†²$Nmx&.†7ŽEy·84}ˆõç:¨|Ñ"ŒÌ4$½×éµÚO¼vÙ]7Üou=Ùeïï¿ÖJr}»°äXX ¬ŒN¦Y¾é Š26N ‘r UŠNóKí]ÀË® žû!Û$°åB¬w²t;G’=µcçm�u/±‡®6 íò»ž¹‘hù;<üC„Í\£I& Íìm¦}ÔÞ`õÐè2U©>¡#hÒ…|†¯�ñ:}`ѳx^R´�w˜è û÷=Â(Q^òÁFR;› r£¨Eõ 5ÔÙÂeØŠª̽ì«éè`ªÒæ˜ÞTA Y0²_‹®þ)a* ’ÿÿ_€áüû8©È™êo¤“¸½8s:>ÀÞ}:OÇæëNkàT»Zfà€õ›N¢öÑXø¨˜Âfi!-¹>&öÆLV-ÿ€\ô«ìa!?Ž�sÀ ñ€vÓn\U˜OŠßUÁÅÚž”î;Q×� º¶õ �k+^ˆ1žÜ“cì󯱼 Õìêö‡8Ób2µô~ØâQTjüŠ¿›~þõ‚jÅŸüWùê gˆíõûË�W¶£Šã5¬r] ´›`±j¶G w>-{ÿëÀ’˜úã�P踚,C3éÝ{z:|�ÀBøc[ƒÑÌi+-UÇçóÒp‚ô|XÐïçæ~dO‹Ãðîè¹ð¨£�-úÍ<Ö,ƒŸÔpÙ¢ü‘�ݬ¿{GSâ—“¸«•Ç÷"­äãÛÁ›v$³.Š´¸ô<žÿÝŽ¡_ظ®µöX’ìú¿ý¬Ù.Ö:]¤Ë�ʤµa%Há7~ïÝ(ØÖu•=Ø{—ÆV…ÃBn ˆ·Ç±�è.ýïWV8+�&dÆ¿—ŸD…Gs¡QF†®+R»ß{^çÆ&X�$>Áä<¶q»;§0þo&†Á&³ ("y3MCÀæx”þˆÂ¥Òî|š¯ÞË,¦ˆ(Ï0…ÿìL{öÎhÙv6©= âuSè§t îN‡©{¸û«`Q™ ?îÄ—G�ƒÎÙ ú•ÇG|gN·ºXëÒ;üÊâ,î‚v5“{«OW#riǤ6V/@þÌZ¶°ô ˆ7ÜfÃ:Ìùmd2³KÛqéŒU$·Í Ò6ep_̬ AK•ü*>q—Î׃èC¸§âÆ®më{²|C ’ö}Œ÷&§p{ú¯ð"±wñ'†�^û16ËB—PCøº�8LþJè^£§‹ àèö¸¾Ýô¶¢h¹ .ÿ ½Üx�Kg+î7±_›«hý‹ùÌFI‰W^.Ëþî›� Ýèpõbh”.¤ce)�=B Ê�åòî\¢UÎyü­ß t5Ò‡YMÏ ¯•g9í¸1ìnc[¯æËb^XÑŒÇûaxÆTØY&ƒ=Kþâ”mYÌ:€³Ù<|»ðFû[�‘È>Ö¬¤Í¾tÁ–¼@þ[¾Ì~©¿ÝãQfõ+,‰í#W•6v«e NÒú·fhÃO¢ê@‹ã¾áÞ@QèÈÏB¥7I4Ó'‘3°J Û¡Lól-¸aɬ3õ8»9ã$Èê÷1~™¾ÁwÏÛ˜»Ël*+µ&#WãÃq¬j5/ç鈽ʵìXÈ2~üByvsN?ZÖÅá¤Q[hÎÜDæpÓö6»Söœ ¬v¦\ÁéÖmÌe…3½ù“�›;�¶þ;GUž²dŸwId‘Uþu.jÊKnñýA>pN8/Ý9…Nê™PÙßL$)^°Iý5Fg&BÏ´a´ìÒ8ôpÒrhœÁàSË m²ßäÂø6pž•ÃߪzyËÃØï;RÓ�‚/./˜pC3·Ò¨é�ÅlùÜGOæ³÷8Á³èxºÚ'½×þb�R(nÞ‰ÛN/¡Æy@ûRL3œfºä`–T?Ÿï‚Õßð2ëésY+÷îAho¹� ‘8ZõÓ´�C¯ƒ)óV&ã¯À‹ÚãèÙ•[3àó¿æñú)¾[Î%Ö¸Á9îÚ6�tA½8öŽ­8¿ î^šÁÊ—½b'/±�»C(Ö[ÊJ 0Rêkp’ ˜~WPÊþÂ^ýÆ4-‹ðÈÁ‹èWá&LU7d ‡¡æ–@¸“–AJ:ªpÏ£'J»Ò—b3ªL™L¯¦´ðí~7 �¥Á¶5W0(i:¹ÏÆ­™ìê-YšáÁ<á$7æJ8k,<@—ê=i W² ìݱH6îkÓö™‚‰Û Ù6›E°ªì8iéèÓ°ÆR¿ˆŠ¦öè%Pƒ ëé¢ûHˆPbm¶b9[»¯’W5¼À-ZxÂÒGR„êz:y챕‚Ÿ¾ÄÍÖLfV–ü%Cüñn6Íù»ÄôEáAŒ{ݹí‚Fr'Ša9õ[¬b4Œc‰,çzOÃ3sìéÐ2Ö3÷1=Ñ+L7Y™Ï–äBË\¨}ÛYÞFí *5J5ºÐ~³Zé¤qK y[<öÉùÀöa±ô¦ç"+´æùú©R(¨�æçoœÀýÔ¹3²3©d(œ ´i³`-˱E—� 6eØÅª­"ö§XêÛx’Íj"EÉqùÊš¢õ¶ƒdm ‰ç°Í_B@p2–íT<ðó8;Op‘!G¯Ã�Õ©.'[ÏcìöÂîÍèÿæDä$›¥œ�f鹨pD(ö7&^ ¦ûߪñÇ�í~}Žª¬§Õ”É)@ç¾!tÿ"„Ó›ãxÙ þ]˜øoÒcþîÉ»P‚VžMU®›p츳L4£‹Yþ cÒ;.Â¥>€Ð°~f¦P u­ê°~^û>Å60‡/�g`íL HúsŒŽýz„žºg]ÁóÓ0à¬7N] o+pçºÆ¢Ý²,8°wün“¤"W7˜c°Žž¶ ðLë)ŒÊ…ç"F°òùÚöÆŸt¢@8-ĤG¡%e¢«âp�û_Ô æö~ ƒ@á�Ñ(ºóbå÷OÁ›ï¥aZt6¥Ý8Áû7ÁתµTܬE[CÐõì”Z,Zú�‡Ê›¢ä“;œµ›ª1�~ nɳ.ÌÈßÏLÿVÒr‡ÑT~S„Ù»Aƒ])æô*‘Ÿ¾'õ� ?—Œ GãæâÂ�9ðÊè)“iž …�¼N[D†Œ¥nÝ«ø· oš Ýõ¡ÕˆdhYŒ¸é� üVÈ@I©DÚ0ßGþÇwüú�+]¡O…Ãæ‚ýÊ3ïÇðQÉ+¶µºŒ=/Ž÷�É‘÷•há÷�Ãìý{;èœçA½¼ñh\8Í«/€0mSá qm0W,ÀÐ<9ýî%µ”·˜ïUÁ™?¹_u¾0.,X‰w3LiS¤ uþ o>™©,{ÅOiÎ"¦ZÒéAgPàdhµÞQ¼øj=™I{3ݸ œ¹¨¸ÕÆMêI��æxˆÚ{î4¤gý!´,å ê…ì€ í’Ø\VÉè‚–íAÜùX¶:óÁu~É&W’ˆß‰³Žó¼j!æ…$·lg&Vçð›|#·{¼ õ_�Kqyj)³†cS…lPYmê¨â± %)žå Ï<|›·�Y_cáNÃB(|±Œîõé’ö_d_]ü)¥½.„ªBÀ¾"6YÌ ?Øï÷ù¿•–ÔÕýŸ—Gñ ã6ûï˜(¼ùMJ`y<“>4ŠPlþZ»·…µÿdëÎ'‚µÈH‚ì«å&6 5|âÕØö­–re4.§+¿­áG^»¿\ú�r4½•罦Ï _‡Èü¦<¨¥iQåè%(ž3�Z<Î3íáøMOl—‡³½öðãÉiðfZ ^Z^‡cö·²ÃŸÒÞ}Ž4çÐXÚûRè¸ûÅæÔÿÅq‰PÊ*³TVH¢pÏÑ@Ë•i)¥!úµS¢l‘J²B%Â=‡RZ4E{hKQ4ÿþ�î³ïë¼î÷ÜÏûó~p—|«eí8X])–é>…¯V&ørˆ+®\©ŒmßG‚mܕРÃn÷ð^‹ŽÞ¯…{Þ¹,ùØ� bÏZi6çgÝãØ_^ ®½ÍKÒ�rú¨IÕR�àÐ9gKbݾ™â…1Ûie¸³øa o6¡µOoþÛ2�C*dhñÉ£¢å�üàÜ%æ´[PL�d=óH9­-ʤ^w—RlA&$…d€û¶�8nØì×mÚaê™C4\ß��¢é£`»þKÒ¹f)¼Œ«b±À£�Ʀìbu%ipÌ[‡Û*âÅËsª­hu’Œä4œk´�7VZò{“ $?ëM)*¢ºÚÖ¼�3ýÌY½Š}ŸIóÑó‹ØD.Š?Ý; 3«ãX÷v ͳ–�¨àù›>ÒžÂçHE 3¿ ð1”$¾÷¸ö2}>Ùã·g¦ËrnmÝözìÅí/uxtÙ&¼®Ùã=ƒâi~ËU²™¿UŒ÷æKËÏq—Ü8 Ô­ç||ß Ò…cmn0pþaXí­G§\½¶:RsË¥ýÓ¬qú3\TTygg2µô á¥=,÷˜Tî¿‚¯§Š¿ƒ�î¾xvÊA!Wã$ZŽÐ¢°¡Áâ�?jxéA7´ŸÓæ¶¢ßq×EJãnƒ ËgÒ5ð_q_µ³ä¯Ž¯I93CHqx‘Ö.š­ÜŸ?¨ŸÀkÊ,?SšK~Õ³×ò§o˜…Çt�“§ '� gåœúTŠÌóÇ]Sl„Ï—.‹^íǸ$à«®šÈþW3áDZð�Lù?Ã@N¯TðÏÔcE�¯ÂqÀ­ÇÅa&©´ÁÖ“t·Oà&ÑŽž|TæŒÃ«¬»Ü˨+PýUªºö:MÜàŽú¬Ç^3ÀØG/!¿) ­h…(çZåWæ÷fÛw{ÙW:†MÿhbÒê«ð\KÖsNsO‡ò„V¶jRÕÑ@MX©¼–\ wçf‘½×%êU¹•gÿƒ§+® A�õôºé6KNGÕ‹ãsÃ)öÆ%¨¿c�Ÿl“HgóF4JÁ×flSLöl‡C øŽÃføgÛ‹ƒQ§d<ÇN�àÄ-}Ée#ã�½}ªórÛ![3Ìõ¦ùîÉü!ÿ-.we—kFVv¿&ÓØ›)h=~\ÛÄ—Ÿ�Æ;�²xï3Z�Ð�rÃA”?Ò-¸»ÚàZñ›°ía*·ß½{vOvLüN^ n‡Ëi›�=ô¾€C—ó•&Cr¯ø�Ý·OäïÐí"+\™}¼Mç1k$«ÝãÁ P‰ÛuœñêÌXôy.û•3œ*x‹Y(M+8JG:ºhÒTU^ãxMØ~p;ä^@~!øhCy9¤’æÃÜn,”K5 ·¤�ñˆ‘5böý…ût»`ÇÙr2´ŽL•F·šþt{ÍsH U¥6ëÙ¬<wŸ0¥E;4±*e0Õ'V�{Mß.êÅ¿o­ ÒµûøšC˜4U‡£*Ké×ò½ÜÔÿ!ô? õG»Eׄût&3œžl=Ia’c8ã[;Ôþ˲‚±œßh6¹TŠ�‰“iºc;½ñ�Ä®Bõ·ãƒR¼_V¥•ï�ŸS`í™gü*~xOÖÇ@éœBH‘ŸÏÊòd¼?ˆËÓ+c !Ñ­•’)cM(NöoÍäö­ ˜g1“äïÄÒÂÉ• ø9�f9æSüàwÐR8CoìáÝaíõnO¹‹sƒÇ¬EìVS¯Öec‹f‡ó�…!éb½ nê´>ªÜø£ˆÝëßBŤ´éX2w4ê`{ˆ6Oµ0!¿¿øÙ¸¥è²Rƒ7N £#ç³§á04®1çYßÖÀýÏñ )xˆÆ!êX’oÃьݽÉ]ô„w-¸ŸÛ.Ú¾ª»x œö¤‘rÕrðY¯…öÙP2Óý½ÇAìÉ$AñÑòP|Mæ7ž‹g7U�â/4Z«IÒCÑYŸ°òI{·{ÓØƒ±à7bwï™&÷é`÷äc0Ïç(iwh£Ï¬f7˜oz[7—$‡ì»$í,Ï®}µÁh½Œ{5#Úzáü?#`¾l$;.ÖãÍ‘°??έ¾»£1xŸ"\½àÁác®Ueín“�‡bã�ç±5={¦~•¼¯ž‡Mïná)ã~8ýçH”ý³žzùÝäý÷ßÃþaÃùwÀ|,êÉ«“•ض󯙵QÜ}rh¢b(Õg"¦l­¤‡‚ŒÌTªï ^[v“æ·Aè=á”|-Ã2á§¥œ?ù|<£¾‚×ï*Òî �›0°=Kп ‹EÝ e’?lÇÒ¢ã¦=NI™ÕÃ8ñünþÕÛ&÷{ÔãúéSiø×<®ÿbñŽN,ªü‡<è‰?/Z£NF}ÙŠ¥ «ÂFpû«Šö:¬4ë „/™ DÏh mÿNUMñu®R±a¸Tâ-ùöSæôõ…°hëq­ôINS³â™Ú�ìý@4XGÖiSú4%Ìàk«&}^¶ß�%xñ^%iÌÎÇÝ[#hâš ü=#¦ýZÀ‹#µ©cèrн>Ž—.•`“�«Ùä³~<×ã{)üðKÚ~¾W™¡SŠŸ÷ÙYÅc2©Ÿd4j åCE.BðÎ ß�‡ÖðH§xìõÛ “ÊìáÑ®U`|*_wÜ%+gÈtÉF'K'z¼¸&¾ŸÉ?c–`Ûð’š|¹%6ôG­£áÌ4?ç³Y£SîárR0o�ÂÑþ{x’‚+Ù fZ8[š¯F$±“‡% ƒëãexäùnî£m̳ U8ûôD’©Ãî¤�Â÷‡p{ô\¾ékF£ÏLÍn©ðÒdæå¥ÁÙñ—HråS¾ýW—M9yÝ\Þîv™¹~&5Å%�ð6-ЙO½Q€3<¿ø¯ï—C»–N­úe·ƒç,€¨‡5T¬Ëna;ØI«/{Å·‰–Cr�ÜÕ™/Ãc‹N�—¢›L˜Îš¤â|¤ÌGï»!|m†±¸oÍX\çô’î¬è‡FkÄ»›ÖˆkU³y‹>&n„ÁsƒáæÍfÑÜh›z¬â”¼ç8·ކnbÝŠÞhzÄ‹Þ×KX_±€Õ“6rT„:M|ý –KèÀò?¦›¿æÌ Ù Öuë'Øup”™±Øy•… AÉôu³ ¥÷÷7†ªx–öz- Š¡#å§XQûüI¼,œ)�ƒX�µÌ&+aLâ , LåF5ââ?+…�Ê2¸{dœNš¯ß�Fs�‰xÞ³ÔÅ®‡ Œ**�_��ПÝï…û“ÏàÝÜ5x§àýýk/Í …u¬·dh¬Kcï?™\}Ç‹ŒÇãÓ©h³ê¼ð¥Ö�?d•ìÁõ_¥u²Ù#pÜbKCu9b…×ÛÎ{¶Ð³ëÅ œªDããßÉöh%ož`Œ©:{°ñ…]û†WÖ£æ;�Î^>ã±xÕzVŸ$lìŸÅ™�Rг±ìáôPtý7U»U@úÇgñ/k²¿P±›�BZ› û¨ä‹Qû�jÙ¼ Ìõ‘|½^G,0A�^yÂÇþ —Ùcž&òÛ¹q”úN5»@{Ö4˜Ü5wKªðx#=¾r±Ì7uÓÃ>Xðå(WG]$V¸(JoUåO¥rôÅ¥…¾ÉÏBM!nÞë‡ÃUzzÖ;O�és.FÕ‘m¼´ÉçqvÏ<7Ñõ£ükÆTnªéÉìÇvôn¾>_Œü‡ÂÞí0Xj+ œ7ÙfЭý¸ös|Õú–#U߈?ÝW±m�‰¨öi#Œ¿‰ëÿÿÿƒºMy^6VÙ\c³ÎżVk>J+§ÞÔ„í9¥„Ë~“ÚÌ8� |CN?‚­·-X�³wu^,ç’šýüùèuHço<é�€±ñr|µ˜…`�||·è·¯í¢í~èñËú?Éåï ÷á«ûcìÌ; &}žÑ�ƒ­Õ¼j°üH ǺÊÙDßE‘‡«1Ä:»r×µBA¯op&ª òžÔˆ+ /ñÈÉ�âÃGá4çJŸ~|Ÿµ;6sÂð¯ô]¦Oµü«ž­k¯cÇÛ1Ó¢T ’Ÿ‡1–Èß[¸mD� 9;‡ÝQ´Y¾UÍfш#<À'˜ Þ‡Y.µ^J.�]PÞâÆ÷ŠžcÔb)žúE ¿¤Íâ5‹ná�ñ­šhè+V±æ¦>=¹ú–b­T«ÏÁw:S¯Ì©cÐlÕI²ÒÌþ™Ùà§+ìªD9 #|>Q'/‡ â8Äî /ºÂ;uY´é·XŸ Œ+>/Ã[.ît®È�î(ÃÊ-Žt'd/4 p¦ŸéœNÕyñ0¬o™pã?_,¼œLÚGˆ ÿø¡òYgÖ×¹/6ÔBnžY„?…´Øþ8k„~—˜X½§¡÷ñ^gö rD£™‘´úÄ#X`Y ËÞVC˜œ>~¹ûšü‹P÷i·Pþûø.ÍÁD søFšï›ùŒ½|õe÷Aìóy�Ÿ¤b³ñîNáÓ�óhíù¦.䳉¬tymzÞ‡¿½°ñëY�j‡^‘è:9�uk{¡ãªkÉâÀ’N—ô%ÂDqÙÊ7ÜÔÉÍ¡/,:u†7Ep—Þ˜˜¾Žj›kikY§•|¬¤xÏjÖú¹Š 2¯‘Ñ -E ‘:È ¶£AqU‹W’Ή-ïàÝ„¸+Zà·ßkpÆ �ܽSäk·=8Ì]w}>Ë’Ë-°îëT|�}¿)u€få^ÌŸx™ÞY)±æpzá°:æ S&�á%íêÚwõÔ¼2­/n`c…ñرb .ÜèO#›k„� CØèoW~–âÚqùï«T0½“Œþ:ã®t}á�•?H¬H-7eX�7+ãÞ‡ùVÛ3ˆŸ’ÖU…\<Ý�[Y“sj(3}Ê϶~AêvéyÞ‚åJßXˆò)»ùÀ,\r[T.`ç:Îÿqƒw<ø qS®Áw�,P,Ë@Õ =´õ¸Š/¾]Áà1GáÓ¸Ÿ4q >÷«ì ±fÄ=7NrbóbœT€æ/žÁënV™I\Á�ûyÕßµœ´¿ï<%\^v¦ç¾†‹O’Ã÷�<ûÆOpÊÍ£Úçוּ/û‰37‡Ñ¡‡¡1JƒÌËÀJ»‹ðh]Š�u±�|nÏç�ž¿álJ0ÍþYÉ–aô†¦ñÉþt=?�•ÿ‚LÞ=êTKo©3âÙe—`F´!tùYUp¡šÖgjPì¬}´À ‘º7?†ªæh}À¹zÙ€eü%å¾y¡§É/¦?*�Ç †±ñƒÉPóA,lˆíêµÇ½¦ÚÃYʑڅùJ98ã¸=J uƒäAjÜà_"?z Onïå +®áH¥ØåvŒÿ¼gŽ5yÑ-K¢ƒ’üùSÜÜ) ÿ)Fc§½Ë·S†½Ç?o§À¿²0|o”ÍÊS¾ þNNb¾ØyìO“„͉rèþÇXü½ >Nc~ð³FU¨ú3ÔLQöÓs*Óµ~—R½µ=¹ÖØÃVÕ0޾¼–³K%ñ“×^ôI“²Y�ü„ö¸­1 6Ç^çð¼ Ø/Ü�&T…r¯üÛT™¸ýËMi_\S›6û¿…Ïë…†¼“ô}‚.êOÔ¢“ºmÂø”|Þârïpï}f :õàɇD¬?ïÌÚKªN_¶ç¬µé¸Ã¯FþßzÞú¤^û@VmCðì· \sÄESÒ̯òúvüóKà„AM´áÄ\Þ“÷Ov F}¾Ñ\ý*Ž›¿Oa…,SÔ+;€¾qŠè«È�³·Àè;:Ø•¶_4ûØ æ�mŇ²0uÒNŠM‰Ú€Y3¤lþÉ?Âð[jükd!Ýêÿƒ_-��óåïaP{<´-äñ$­Wš·%‚î*mÜᔉK. 3K>xx;ì€rP³—›.òÂûQµÇy&5&ò­Údtnœ[õ,æ÷ª¼Ms÷Ý—JØ8Dç‡ó—p ´ï·Ï�™Œ~cæcÝÄm® ܰgùªl¯¢¹­Æ86F Tã¶ã„Ôd^Ø¥×2_á¡.CÞz¹Šn¹xqw×7Øxxû‹]°sÛnn•UáóWôÅÔž»‘·ÀÝÃÑe©; ®s‡w�"hr£îa÷áè_�›VަáÂn»x®ö.½2® {KÿíæÕÚ𱱿 9>‰ÇûIò›ñ†8|É:kÇ¡ë9J³ŽÔ¤lfn8NÏöoa·+ÄoõñTc*αæßnìþïe§/¢kµz6úŽÂÍÚÏ¡Xf�`å5–eBú’ªf9gv)bÆmknyV4ì­Î<¡¿š) ö¿GѰ�÷xBâvxtˆ„Hsœ~§pÁz;gì¸ÄwVn6·¡Q¾ z„³�ýLºO÷Ê”lŒAÙ¶`þ›¾†óº}y÷‡ï¤¢?À濳�|ìÌ5¡Ë\‰_¼ L“s©Ló{.•´ñf ¦e¸¡Rþn˜Pòó÷�¤½ÿlN�½…»GÌDkmC¾æ{.ˆCðÒÑ‚NÓ6®º�†C†…má¸àz î?‡M›�òÔÜ¥ôáýF¿Ÿ„XÝF¡´L=êßPãÆ»l3sº$_Á•SMË»g±áß9’¾1#\:¨P©?~x�+¤@JG&ÆwŽõš \·¡œÿ$Bß±‚ùŽá�z`-• M£YûíÙýr$¤ �÷Ú‚&f© ?>ò¨—°P-¦¬ú þŸaþ²‚ÕÝRP«�ˆz,Yµs–ü‡ã‹/ ¡ƒ�ðK!–ƒ³àñ]Äuë@úK?¸üw½…AÉ&PºÒdÓï N:P„IžÁ¨Õ5ÛïÁï;» Öh¿ï§GVçbp\Ý N]Ç-Q1¬|k+ßg“ÿ¬g÷={²ë[9®v»Ê‘·VpɬFÐï=‰WËïgóð:üº˜+ÐBÐÛxÊg}àOmXvz—‘!ñJ/›»>ÀM×k˜¤¾ †» `'½Ñ\ýú<Ü0�õЧ £vÒd¨Uq¥ŸCðtV ¯P_Ám½åp´t oKXÑöÑèåWÐ3ßkŽØ/ËWÔ“éM�4åÿ� Ã2£à¥b ÛùFòÍÐà]>í‘üÜ{sëisÜíÇ[Šo¿�A>ßÖãœÛGhý,|ÝaËËέä‘ó,ÉÅ´@¼xHK?:r«Zo]~[8>%„r°šGý‹åôãñ8Àv<)ƒ!�t€ßR+źUç¡è�¹eñÍ`2hËå2½•�;“²×¯ãŸÜ±ÍJ#k¯’áƒiì’7�5öÚÒUý~4àä$l>?µ-±oCý1·¥öððr¢4Ì“ÁöùãpI˜¼Í³°?œ¥b‹Ê ÏBi×e0ï?‘2ªQ�S"d¸÷Ç7»,9­*�^/§£*ÑxpË;TX›BC9ÄXεli¬î9« `ÂÇŸ4Íòè�ÿ.®{ÍrâÙÎw ·sþ- €¦«¯xö¨,ÉõÃÊì&!xÈ,þ„—xšŸ4(ZÏ@iᣅ9ÿ¹ŒsÎnäEâk¶7MÇ®¿&t°»7ž¾û‘tB‡¢{ê$î}õ6n^ÃWó÷ðlã‚\È6öyAd쟪}f—øíϯ¨Æi§W¢ƒÔFühs¾üÖÁ=·oˆã´Úqº\‘˜ñR—>æjA§’"׿Äç¯q÷ƒºª2cSñ]Ï› =Ä5 …Ø1åp1j)üTJÛµ‚1ºb÷Ê›†éý»ŠK2³pÒƒ·¨a— ?& å!Ç7Bè€TºØVŒ[&ï"�t+8¯;†oÏŠ!¹1V±#|8¾æ'} ÏGÎ<¤É}Ã1ÔvΞÕ�”¿ÌæúÕX´f3ÛH‚y�{x^©Àw2B�*F‘ìÕ*þ/ßœO»7ˆk—;àoÿݬU5W ñgCkñ»j:»6lÆë³IÉÄ�—¹Fu樂;Õš•ßzó„×…°Éu Û»kò†vK¨[Ù f=$çg�`#ðß "·üùê9apv9¬¬ ‡ëœðÅÚv*p4å‘×ëÈò§;þïÜÁ‡OÅ2‡„¢ã½Ðç“æÕvxõZ ^=âÇïçÊa©ÁH”ßK»§8‹Þ4oê¼—F ã+øSÀ( ÿ/ñùúUïŲБ(#Ñ‹ÚäÒX99üm5…Âã�ólžCÎ=Û(`o½§¨=Õ%ïJcUÉ@±¿åaäF5ü$xáß áΡQü9¨wµñËÏdoôZxf,~�Éûë’¨È/ŸÕX ½mÍ«&O:RúZóV†cCÝc�”é‚WEÒ8Öq/öŸ–Ì.ùI ÒôˆC^ëSL›*—µ†¢Ÿc1Ng‰î½Ü=L †‡N箉&f+ÝÅŽš¬ú ̰ ÌwUÀÓ@K¨øs€¼?$¡„½):GÓ… ùž^(ˆU‚É­RØ\žJ~;ãá”F»eÖSÿ � cb;m zÙûæÐŠ`ßHY�ù2G(‡ülg'tÈèaÞƒØa7‰ï~ÓÁÀ¥£XgýbÖÔpB‹æ�X•‡—n£uÙ{x¢¢ˆ²¯Yçj½iû�`ý*OðqÒ£´¥xÝŸ÷¥’›³bIj‹.V2åã"„=3ô±2'‡Þ’ª�sAfùx쓆:ËA¯0ˆã ñgóÓ*W—P|ýݘçüd®ÙÛÂŽëÒhæ9<s‰öË8 sÍcÞ»“MÎòðÂá¸Éq Ä·-Á«Û³¬ØW¯fß7KáåŸ R÷ÃÏ™}8ÑhO²zAÙIý8B¢˜þíÊ¢>Ä]wÅs->ãölKÁÞ3žûü3ƒ˜ùì¨�À_¤%ábú?1ëõdèêÍub´×RÞnõ$‡�$¬|ynBW®=Œ“ŸÈ‹wd'¢F¾*7WËâ¾zcQ±Ö”××"³¦Ø3bŸÐÙÊE©âý¾Õ4ÁlþôRÃ#£>U©Þ÷áíCºPQuo½ó�çg‰§Öõ¸QÉz¾µ¼€ªÖ6pð¶Kè_üšä=#Юo]û] WäüYâã t‘*G]y³¡W½Ê²¶œRuÒr•xw]Ž­í$«ÏÒ|0ジF³?Ôùms!ú¦š²5]€ÂãëÐ{]¯�ãžÞÍiÓŽ¢Rt-Å®®C¯9ñØ1#’åeÁñ–_BѬy¸üÝ$VYÚ Vs‹èðËùfVX¹Ê$žâ�Œá�¡Ñ Q:‰Øg7G jdûYɰ¼VSXpSíšûóyÉý|jáÐq)À4‡,ô(®†Q£ÆÐÌ Tsùkmhxdõ¼éÊH)–èåÌÊw߃ï½b”¿8ˆGìké…jÅ{éXÏ9I—và3ûu<ôk Îx¥f`-kæå€lë†óQç3Øe¶—7á�,WŠ[p=óç°x!Õ&}ÆùŸÓû¯µðàÈhJ\(MüË‚¿õ ëñŸ+ ¾bç8‰—Ž�ÅñÛÄëÿ9 ¯TIø!Ác÷9‘¡©sïàñJ±ÚìÁ¡9~6uÙ™ƒÛËà㻓Ää`8³"^¨Ë°@÷¡kPÉé]•´‚„Í–9JX"à©Ã¥â¿aBŸ®.’ ueµ;ÆÖå'�`ê¡óâyƒtX¸š:4žˆ‹ €Dö?ˆ”°�*­8œ¢ZJ±ÿïI²¬¤ES¤Ðòã2íß›oì¬Æžœ^H'Ÿµ~¼(‘e¸ç†�³š�ÔÜ{.ŸÜ€�IƒHãU2š\·åßcGáËåž$Å:èaÀäe†%ýjEhË&ãý0Áÿ*Í,‹-é—yñdoH˜Ö›suOó©«Î¤zÌ�g‚ø°d6^°š½'èàçOÖl÷æ %M´@�V=w=Œ�.ø êûípâiXë5‘=n}áôñÔé§Š³ð¶R�x§÷H´è?/l ¦Íw�U�\ÐA«‹–a]ž#­Ù7”[)¨õ& ìc-Þ)Ä�ŸÏ‚‚»O9>Y˜òDŠCÄBñSë{èU£P}Ru(æì>‡°á}ÞR}‘®»§K+¼Ý ¦d?ÍQv¤Q—²…™›/R‹é"ˆ(”ÆÅjæ´Eê‹Û ¡î$©¥>ƒå=�M&½‘Îû•rUÐ$–»Ôȣ͵�eœ¹u~ÎYäòDí�JBVØf¦× £×ŽC9MWövƒžÅ3Nj¡Ü™|áD_V¾8’ë:ö›¢8}0^¾Lç~FòŽÿñ†î6¶¹ý|]{s\/v]Iƒížì>DÖæv�e¾›‡G ÕÑ®¨ï!ܬ€_#Tar¿(JrÊÇܬ‰´¥‡~Ç‘„ÿ{«ÅÒ68«Íˆ=fùã3·oø«¿:TÔ$YïYz¦WÍ;¼’�ãu˜Ÿk��gOAOÔôÊ¡•§¿[;zŸÄ¡SäYw• ]˜êL*ö^Ø®'‡ý7OAÉ÷!øtö>ü¾=“ÇŽÅ ƒ”@óf3ýAc¼u-»;í´áp�~l.NÆ3mÀu׳ìÏ¥øû‹"º�½ ê¬Ì�w‚aR� Õg¿Ð­»Ÿmãex°óuòÒˇÊåS¨ÀkÏ *FŒµ ›Ìqmï\¡ñ´À'`&Ë#8÷~¨O¿Â—V¨“ÍyÑÔ.Œ¯M”@Ÿ�¤ww!�05¡ìOz/}Sèx!ƒg^öÁ”\:òHÞŠË-+¸jinÝ0œÒ[àÅ´­‚ÙôQÔíÔn=›ŠSþÄréStüˆz¤9õxõZn8µÓÇâçÉ•ô䣖Xe×LÎUçÀwÖ ñÛe¼o\oÁOé<îUWÖrŠÌJ~-‰ÅuMP|gê=ªïû4S@LßRõfÉiýùïž(ÖV½€�¥¬Òÿ,u†IcŽÇÙ’nÜî1*ÆõæÕZƒñÁ†�<($‡z'®¡@×á0nu2D›OÁiÊÅôìY¶Ú¤�Åôê8•¿8÷e�ÀwbΖ8k�žø;Cš'ä'†îÌd·¡™¼–¬ ¦îQ:(émƒ�s1aBL;q\Èr†;‚÷rI G·¨áæYsñaN4æç#Õ­QQ?œ#F.ß›_ÁúB ,“.‡êEKù˜ÿ4}Ý)*�Žù¯Gãù’v”�¤—sG@w„§å(ò0ÉÑøåAïÉxð‘sý3±KWõäƒyã,Q°�WÆo­¯àÍóI –ïKŽ©GAIPæù«8€³¬Õ̇àî—±¤ú6Êö«þ~v"òÓç@W&#«ƒà¿#‡ŸÎHï¼<àËï-l÷#Læý¦m†á°üA.[˜«±“íwÞeš VeJÙ¬óMå³}xQ¿“Œß„Áø^‡h…ñPúc:‡4¤šÎ¡˜Lg1ܧQÔºâŒÞ®êÌ[&ÃÀŽ#¬?@‰/ø;Rû|}fËIØ�$Écâ+`óû4ý(IIë8qÒmÞ¡r†Vf+°ìÕ-xS1¤s}U²q§Ašg¾¨ª±A,NTA¿½«÷ïX#êŽyjùwýa<§£F6M9t§&y(¼*ve¹î˜üïú< ýªZ¨yçcx7b ‡IØãD§dʬäžïç-†2¼ãv(ŒíÍìØö�NÈœæÊÝ'aüaGÈ ÉËÕœ¸&æ'ŒÚ3¯”ðå­zøÄ{VÞÍÇ“ÞÏ`_’ŠÐ¡v‡uT"èüŸ}\óã¾pµw6˜)‡Wcš¬Cuåhu‹�#Ð{A¿4ÛÃ;M�Ã# Ùmóq°�u]_@x}8?êÉÅûóö …þΔò^™ÔÏ„�ÑÚÞlûª—Ð䟳ƚ`fu,ìå}ÿ÷ Ü[½SY™LF ­°óìkÒ°id�ïÇ¡ óži� Þ =qpŠÊ)¬’Ó …+>«¸eS�`32\8i�Vì‰/>×Ã5‹s‚åœË`¦Ô@ózq�üZzýì9\9´ =gksßÂ8ªµWãï§sÅóf317æ(�(QÄýæ_ Ãæ:Çúlçó÷Ô…7úÒ<ã‚'oÕGí�«„â°3°²r´•Ó…yõðâyÏ5{L½g Ä´ú0Ô¬qeÃ�yCŸ]h´yƒµBcùß·«÷(!Z¬‡#~) “¯Bç? £«mÑ'(šîÇ„°áÀf>'þ¬V!Áóh˜[ðƒ‡ü×ø>ÛœhÛŽ®�ŸÁ:Ù)ð)^šµßõâíÒËðìÆ[´pßKqøv™êù¾«1;ñ¥8à×h~§5�>-�tñÏy©Ù Ãëp‡ÑñoŒ,þw,¶óþ…/!VI–ŸmWa«€µ˜åðQLmÜ“$Í(«E7DÆŒ�%ؽȀ+‰�+¢`¼j!žýÔ)æÇJñ+okþsú ê?ÏÝwK©Às({xO2¾ßÝ?˜2&„•gÃ^*ô;h0OæéXùþ,šô4þ¡VçzØžy�L\ ÄÖiOiÚÊ'0=³‰îí­…EÇg’j––¤=y9ß÷ ¤ I‘$-�{Íä06C‘ÿ½É&ýùÕô´4½×7‰Ó”ñ\‰naìß,øVC!Ýñöà*Ú~2†}×W°ÒüÙ°‹6ÿ탧û©‘ÁÙsV¶Ýt-Îe'~Ä£šÂxôx>~žQCëÑaxpóPøô—jÎpkùGøèxˆô¸³ÑÚ8”𮣛Á—awx¤X®!ðëƒSp@?ÌIO;¾êñq!�=šã¿Ó ÛS� ºAå}.Ô~ õ/AïX,(Ø+³Ï�¯ô`æiú°]*Ôàá }Àš4cÇ?´øÑÇÆ°€`€L:N ç®o«ö¿�§þûA§å„GšáøäO&DþÝ åaÿáÉ�ã0&u17›ûˆ“…ƒxnŒ'Nlž�Ÿs–ó}W9¶¸ØBŠþSqü> NuLо›“KΑžìAÞÙ#8ñè!ZtW%ýŸ�‚«Ê3¸pD…ø&n(ú0އoÌCŸ.WðÚÚ?ß_ã+»Œ9ùÇW´0=Dý~…€~C¬¸jÄ_±0<Ä:N| ß²u0 bžØ› ‹ûãæ¾ë„¨2 Þ='›Ýâ'w=Å_ÞïÁaÔ4kŒ!8]…Üy@¯ ÈèŽ \+9k?hàëû}9`uNÒ–JML°öÜ~+«‚O_ep™ö7²ŽÑÀeEÑìl-< ‹`mßÁ´Øõ �2­-ä~B߉z<¬.‡•u“qÕát÷a”ÿJRU¢ÿµ�,_T$ÈaÿÂÞØæPCyË ÑÄÁ[1Zbš-+‡v™Ñ\0ÓD¬×PÂXFùO`à âöõ`Sv/n3á½Þi¢Lé+ð¶ åT•`Í=}LÏû-ºÏUǾ •ÂJЯö#üzfÄ_/Ý„æÒ“tbú|ø¹õþsŸÒÌ”ÝH)|qrªþµæg¿bÉ94¬&‹ð&½_¥Wƒž‚E­-°ÙGKK¤ÙäO/Ž¡€Óó)_Á’F‹›*!n]ÖÏçáǯ¢ceÕ9×c¥baÒîtÚì2 RNÐêYT:”-¶'×Q÷¹2™Ô §yþ­sñìlÙH/%` ÇÐb—šf,¾š×Ÿü¢{o�ÅŽïmÖ÷ ·ã�å‡Aqq3>cƒcRÄ/£Qùw2¯`ê› Î*çbÙ³T\c½‡wÉ ØÚu.GE°Î~ÿÛ’û”½ 'ûbðÃèáü®ÕS„E_ÈúN$¶æ‡o4ó›<Í7Hå)•FDJŽ�ô±€M²à¾ý;z=hlòñ*‹öò⌋ôsœ<ÖTkñžŽh”ŸŽiCYv·R¨ ûªC�V­½=LµbŽZ»?,hD·�AÜ7en9*Eÿ†þ�àØ¹Ö&Ã9´-ìU-ÉyçL!(g$UäØàðä0¸iÏK6NÅ&®c¹Z ®¿iI{ظ™Ljü!ê5*Í›�+[Và/c\’?é¿BØydªØ°ö¬¡8¤.Ÿg\†'5Mø�ï\81õ%í›�÷×ùV®)žÀ³;Òè’áhL”ýK¯Û”Øç©¶µ‰Ñ!rÛ׋>ýqä…ÒþPsKÒ·@öéÁ´H£‰>ù=‚p€¾½q`Ë^ Úó6¿€€ù}…æ+›øöTSNS±À—¿ž ¿ÿ“}÷(”ÐYÀ+ûúræ¸oô‡þÃy.| â$¶NÌé+îÁÐéò6ZÆ{Ðï¿H|ñ5K$�·w!ÔUr‹Ì÷áÛS üJ륵öW¹ªÚ�yâ*Ùs”'7½*ì¢u½¸AÇŽ. ßäŒ�QGðè¡Ñ|?ÚŒöà¤ÐÝ98g”ž>Jõr=w_äÄ�>ÉpxÈ$´~îǯÇ.Åä`Y¾Wgýð‘5^™ý�ÚK–¢�£¯@í3!x·õ˜?YÃ%wãQÓC<ûë?Ðr8#’{#¯{< Íiíë{ã�Uʨ:}ުwŽdÇÔbTùדéçhäÞû¼wj9çÜ$ØûF'ZHðõ.’ƒã¨Öü�LÌ6 ÃÎ~ü.n©àù©—|:‹ÁkŸÐ¯Å øAãi¼íúrô¾Ôg6wø›à�ÙÅ}Åœׇ ƒ•,÷Ó?F[r’yOÄmú’ðòcî1C¬w— î‘Å0Þ&…§ž¨Ä›Éš|®önÏ÷ eúÍô]âŒí_Îr'H^¶M�Ų °�NåÞ¦˜Soi_¯8c—3ï¹\Rõ¶òíèé=}¼Nxû Òª>òV{‘v6÷®Î²ÖÄ7±æÔKî—�îÏK>8ò¡†�l\ …U�¦áóÅiðÖÀ�¿È:`rÉ ºñ�<ZbžÍhø±)Ûœ¯Pëð–½eWµ§¾�´.Æð£G7È #�Û—^¦×ïkqVDG­ aŸˆ}³ézö.Vsoƒ#k´)ð ““–œ)˹÷â\x溒vœŒ/Κ‡…¿ŸRÀ÷ˆ{f‰ ÃÙX°aµÃ31½ÀÂ_lâ‚{6ÏäG_WÓƒh^'¬'s£7^ׇW¸ðŒßÍÐ:40q ¥¥éñÜŽí Ò¯DTñME� „A}βœŠ$ºè_…õ6®|G|7M¢öV;ë˜ïƒ‘Ž f¿s1l8{|ÐÁ Ã)¼æF›h»ë'eÇ×€ÞƒâªÁk”Ajœ;:ÌÍË2Áv·Jõ �§BœÙtB/ÎU íƒ‹q‘î'°3º ¡Ÿ†ðeƒhjQ¸ÉëìÅè^¿©³©N´êÞÇéÃÓa$†s“¼5­ó©ªð™ÎK¶Á^ÿ¯âÈ-ý`bõ.Öû�]Ù5~&jMHÆ«³—>j!ÿ'¨iÃ;¸µ=–y„²¾ì¸ª—JÍxÕ� 0çªðkòUÂ2KÜpïlú—„¹ßÐXöåR‹søoJR•sŸ[Þ§ŽY›ùÜ»§4h�¾õì…÷÷ƒ'—QFÇoºP…©ý³ðn�€'Rª /x»qét&Ñüo{)øÄAø¼à é^7å¯ôI, –´yþi ¾]m ’Š®ð9ü…xû—;›ýø +ò%p\Ã[Aer>ßž­ƒSó/±›‚”�CœO·ûÌ«m‡�Ñ¿`ðÙ® åžIäÛò�NÞ•A‹ÅÊ8Ô$V(¹‹-oØÔwy¨¸óËÑð»[ƒ7Z±A|mxƒBk#Ý·¢!†¸@AÁ¯“ì^I`ñ…Vr¿9Nš_·JAMLaCQëã8.“Y…5ãæñãÛ pOýè5½¦_‘SøóÂ0:ÚÛCô‰¨¢]ÆÁ¸»ã¶P™â  !~O!gÊßo ËÞ02Z& zC,¬NÚ4bÄ eÔ\œ†m¶ÖG,œØá§ôþ :»ƒÅ¥Mx¼öèŠ/‡ÿRÑ‚ Ôã¥U½£)ºû>Üëy_Ë?ê磻LÇ·W´àl‡¬˜ÈÛ—î`¿-Aèm¶ã<©3%<;úÏìűnQkÇ5Çv‹•ªá˜þÂ_P¹wEêlÓãOÑ|Zx.Ðã¢Íb¦�*׎‰ÂI[ËIvÌcJv¹À�õó)àa"�ßÃé¸$zéR‡ æü çØˆõ<úTºå׼ŘûymO¸/и,4$п KX}Óm(ŸžÊÅŠk¨à¥$[Åzâêq˜» D…hp®l¥™úGxåbI×; º<œs£×ÂÈ0æ®c±6wŒÂüïõøÀ ÿœé ºÆØý\$K³• ‘]€õ�å` ö¦WhÁˆ|ºñÜŒ ª�y”Çá÷£ƒ|l3Àã k¸û²”l;ó«œ1aý0è“O{΢`wK»âÜÅÛµ øeŸ]ùÇ®‹7;™'‚–Þt1‰ zž¡»!ßèuŸN¸¹QÜwO ¯ýŠÇ¥·€•|T1CwŽüò“²¿5PÌ2yp9>…Ï\Œ÷gæP¬­¢UìÖÓ¤çÓtר�®­’ðzZ+Ûèc¿¡K©ÏÀ½Ôا�¿>‚«J Ôâ =¾Û»¾A&…?Ì9Á^ëjêw÷�æðÅ—y˜ûÑY1L ­pÀ2Ím’µÓwAÅ’;ÂR•}8qå<ÙàÃUÿöÌòu¼‘ÚήÇ÷Šu=þ³÷§$™iJxvá , nåë£÷C18š¿œÊgÈZM»dŠ*ßmÑ`Ûy±ç€§pSC†&þ­ÄŽ=9“6òûßdÝÿ6 Q¥©]ôÑþ=M«üNVª¿@O%�K�\×HX'Õ ¦íßImœvqÇì)D*Œk-;xiµ꺸 Ç—Dˆ|­· c“· ê­éñÉà’Xfž7@ùígØg²‹ž˜OuûÓl~Q�OHÀ½�;¡Þ£¥ b…´F¾uè³ü,�»wš¡Õ¶V|·3 n½´„eÎv¸­ïVüï‚.ÕN¸Žé# ¦0~�Û“�ªaégúæ?A{Ô±Éo5Tä‚NbºÌÁõ«Ñ{tiø÷‡ ½M¥Zžt XŽä¦Ý„ ™×Hé×vŠ’à¦•šœ8eH¯š�·gâ¾)kDÛùÕ,îê#LÒ:HcîŒìŒ,H”[ÇSåçñÁ/Þ¨°‡IëΞ¨:Sdk1hi KÂ÷±´b*…üw žÿZÂÒNB­KK]†žer¬Ùi„¯.Fð|ŸD>m°…oôòçý-‚Í{ªÑ�¸§� /«<[ã6ŠÇH*èéƒrôS/¦ùÑ·¨&Øh¢íû)(\¢ˆ çh×ê>x•ŽÀ› ºß– /Ë]1f¹»†Ìe�œ¤?§�)þTôæ3gõa‚çH1ìà-Rí8må|˜:omöƒYácÙ.%¾îJìqøÚ‚èŸJ·-¬yÞý!6¾?k‰ñ‹¿Â´Æ‰˜»å'¥oІ>ÙÁÙ•Þûw¿s·¸¨c·{qu'fu«ã.…«l޽è—Ô2|Z{¼ÿ4“¥¦<�R,"ï7·!ýš6Nßõ‘S÷WÓ‚9²èö{.[™fqÊGuνšMŸæû �¦ºêƒåM,ã{:ÏŸ¨‹*'�ž ¢ËêOâï^3x·×!´ƒ!G¶+ÜÙÉGV»“”B6'Ç]…ù–lù9ßz*ÐÛî�PT¤„ÅYzl²n;†[ê’ö5Gœ1= 9&áÁ` Ì�Pë;�Ýü«ÈðV¥(ûJ‡=¹ª_Vˆ;‹îЪ ÔÞ$KÕ¯‡á—x3ˆYÇÇ‚+ _s%Ø¿› ‹za�{"vY-âήJÎó*#©¬|pOLIç¨?Ü>o9›ìÈŶ}ðËÊ·àaŒÅMS(ÚÈûØ4sÄÒ£XÒo¸G«ñ©bmÁÙ× fÈð§jìPyNèš4ƒ¬cŸF™�r!®¿ƒ`º1 +Z‹=ï?^ZäéƒãëàïηãGOIîÅ4»êûøk| UíiåÌñ~0!~¦�ã]AæËæsNÄ}qÚàR²™ÈÞŸn‚GÎV©<|­'Z uæ£Á^ak½J×aê|] ¼ÛÞ>ùVµ¡÷eà쯛 ±mƒð¢¨.Ü!¯¯SýþËT3=TVørì-n/v`ù‰žø²)‡ßI’HVoh¸«¢dÍX>2ê)$¼†úOl÷Š/¼#ù¨Ò|´­çÞÅÊ;²ñ°ÚîˆJgE5;<—x4ó{Q“ÙfvýpŽÖ™ÍE—*<š÷Hœ ŠG3h—a*´Äicy[ùø\áÂpëÝù >-(ÁéùbíºfnÙrN-é¦Ó-Sê3LL8qÇpß¶îôë‰�nöü©0€>*–PLHë Ãø–]4³úƒdö�znǞƙbSÖA<°ä¨1§�üEÓóg ðoDdIEÃ×û%(õs þñ9&Þ9›ÿÆœm¿ Õ†£hªÇ:4º^Že½ðîixûÝר…º' 3Ó º ¹®ñ=Ü6œvÜ\�Wo=ƒ´¢È+íퟡ‹ß„қ݇¸Ó?Ú‹ÝõÍ–žtm#‹ÏÍ)8;�£öÒóÍ©U>–‡Í:Á_K7x׮œ„iT•TÅ ¾¿§_�øÙ?öšÐ_Æj©A".^ŒQ—ö áW°¸BÓÀý�®™&Üy4+ñ³Îe’ôL`³Åê[^ cýg‘äôXŠýü�S�Þîñ%þ=©ÁËûDã!ƒ^=û#™Ÿ·æ[›¾ÒŒºsôââ),Ò俇÷°ÃKmLt8 ¬ó æú\ê�#ású\q}ŽìÉ9…_ŒÙ¯÷ÈAÖ¿þùRTGšÑƒØåü¶°�d¥Éã±j@Iw’.—…¼ØÎz�@iÔ,ºBƒWmÄÜ3æ¼<4�ç|9‹*'ä�æÃûj'ÿ°†W¯}'ºÑbý>�”=;ÇDCè«Ãœ‘T/®:Uþ]–W#<˜¹—w[í»™Q I9H½Ç›ÃS‰ ¯Î9ˆž�Ê¡Á©•ƒ "±s?FŽæ‡IÝQùt*z¢m°"܈¯ ˜ôtŒÝ–Ëoÿ¦=ë“yˆŽž }ÝQ¨xA•‹×ò¼÷qpÿçeJ¾4¥þîs_Íñ kƒ«VÑ̰ӂuc#¸–דú¿Ü–SBy�N|;ð%]íT¤Q~©\Û¶˜‡Z]‚ò¤ðôŒ1Wã}á˜ÇBè}¨€|zhXÚîb�¨7“nÛ^‡löÀ¨Ù5ÐQzšÓüH%ã-Ê{ –CT­– “Æ“Ï_Áߘ&HO¬`ËOz<ïÃ<ö´9An6Cy¹|:¾UÿMâŸz-Úå¾”›øµ(á݃-QÁ-…mãkqN¥ ÚþTãï,Ñ)`6F�ž �™$¦µ�òÍœÓÎ…á'•Éq°^µŠà󭹇¼/NXºWX;Й=;^õ=ÂÕyÌól:<{%ýVY/_¸®6œgíâdçë}çqÎKÞ¶V¶¡ë© ]ùHk_^¡Í.ÁÈ}v�%=÷¾.‘`Ï¡x~v)wž/ÄæðXÁ«tžO]­#1UîknYˆ[£w0$š‹ú~?�Æ+‡zÔïŽ×áó èôÉxX—Ý‹÷fÓH5¨5žÃÿ æ«�E´'ì0+}‰e=Ÿbxð@ÃÊ çh¼£´fY¢¼‘{ÿÜ-~X2Œ $BišžøëT1­=0 Täyï¸i�5#Ì”ÇàÆôBvi»Hb§)›lhó³†3~Þ‰khéÒ<1²œr¿¯ä\CŠéy°SÈÅÖ:¼¿âš03p>?º©!DöO`CÙÕb‹†oRÐèà4§ªÉßN´ ÌïCÊõÏ!ª{îé§�ö]Að oÓ…4Mò^³×ÕÒæù^˜è,÷ï½{~¥ik¢hXÂ|ç>ÏGnã·®·êvÌÙ@?–Ä ÞýD–~˜L}ö´ÒÑýÁ�õi‰xYã…x5æBý1Ãñ<¶i%v©ÊcF�3ë�ñ ¸‡YÜô5âÅq–¸æ¬¾�­;óX¯ï9ŽÛÂÉ�/ÂTi]®åÆÊÛÄï÷wSöÊr–¾ ³ŒÅ£›fr×Þ ö RÁ>¦ 8wq1µkD@Ý[¬\iƒ|f±Qm6îÒ§&?¿I”ŽAOG|2G(Ù¾‘®•¦QäC}ºç%'ZÎkäœ>' þK2�t]ˆª=Ã0íï ,ÑVçhsxÞ8ûâ2Ô=`„I§²kÔ\Ü7§œÍµx³ã@¼‘I³mëxè0ú›õA<ðof7��¥ùQÆ3(Rx …F5œX½[¢ùÐømØ{—ÕDŠ£+Ók¯8òéòáŠLî7©�<®†à‰‡VèªgˆËŸ’�òCÜß ?gÆ Cìt<á: }c¦ƒsòl]“# Ô>õ³½\U®Ÿ7Šd1?±[Ðû6Ÿû~¯ä�´ÏuŽ€»:8á}"W©¯àG¡_éØò0ryw€Gª¶A•ej¶ ¥¦âDÐU†;¼-h�áMÊß5v|9À cwCÈyÈÚwýœ¬Iþä”_¬ƒ··¤›¢Ycµ:íÐ"·[×R»èDÝC˜Öã�¿”)ì?žˆfÎÀ£§»ñ�'ahù4´ù¸4o'q'rŽïa|¹]¥B§@«L-�?„Í_ •Z'rYM>+ü½Rßqä£äÓ¦4ñ`ï;hS¶>'`±fo«— ¥X6Ù÷ëT £ã‘ZF=Uma%÷>C¥GàÔïùÜößÖ/ÎNÈc‹bON)&<î6 d“7RÝšl�rSH¥F¤ˆ5rä�ZŠûdü»ÓÞèzÔ†Gÿ•GòÓ’U,sî,ŒX‘‹“”ó -‘¤™/kõýÓ ìZõ¯k? ®‹GcÌ_i”uW£Ã²ã@Ò �Ófe)’\˜—¯Ê¡z…·l?±…Ì5kpz«­wp¥ªg#(äó-žýl2V¼Nå=áθRÿ:j޲À<åH6~˜‡ óßBð,gÜ©jŽ~|‚â[báˆü$Ü^Õ“rWÍå¢ÅzX¨ÏÞ¯4¡Ü)•‚kSHµ –O˜^Áo÷õ¨ÏM/\ZÀ Ö{àM©Ÿø5u†_¢Ø[xÿCK^ª¯Å÷¾YЭGЪµ…lªÕ(¬y3¿¸7äo�<Žˆê ÎXévS6—{íuÄ¥ŸópïÇrÈm l‡ã”\eô{¤ÉEÊL'?‹¯Ôñe¦"¦„Ï秧ΊF×ÜéÍéòz骡J¸7n2Ð)"“ßÕðYk^6:Â�£6£±ä¥M ÃϮІošØ®“Ï®cMyy~&g~âþÜAkTøèë|ÊÐ8Ç_R¾IºJàΨéBI¸#ô6våú¼gç^ƒõïðä�“ùÝ ÑbŠÉ$Ô \ßíú¡b–1ÔY ©¬Œù"%Jò•Ar5�×Èò¦qð&M¾®C§WÉàðP±¡ëbœ¤Á*ïËõ`‹TpIÚ½âÔ€§ÂúühvÝ6B\j6ÏΗg§sÚV«úcñóÕâ9‡>˜ûè�¸ñ÷<ÈÜ0_ÏÛÀßLê…_ Ú<µYÙJSÙ—eŽ\ ÙãùÃð]U?]|%Ñ¿êH3þ>èË8Þ×Jì~欲·¿©�äÂ, ~鼃4�y}s+LÝåiž¢|a‚è>_0Û«a`¶|8/2œŽ›Ší[dØÒÙUi+×}�CÜŽÀÀ¡Y°Jð|ßÇ”§½Çhãš.(§ÛNûŒFòïøf¸¿? ûôÞ$æŽôý4ÕZ#÷œ�´ÀÞܼýºÀíX(þº.À‘ÊNÑõTø—àÁ׸3É“k£Jù\Úsz&w �›¯%MólÔ­Í?O¾.Åâ‰!§è¯C´–ö`õt­zûÊZž;ØË$üßAeŽyß´ù—ÔWj7£:ÙÏ»!kG*:.9DZ Fu:‰?;5Jür,Ñ2ì‹ðqå~Z4y/}’µz½M• ×}&ç‚CÔpÖV˜¦Ÿ÷‡³ëUųÞst&F¸Ç“áº^Vóž¼'éÁ«ùsg8nUîªëHÐÀá¿Gàã._ÚôÏ;5#îpYçÝzÕWíhñÃ…)9QüÚ¸¯Í-Æë–¹xí‰[ý/yC,\fG_NvÃt­¸¼³g&¢Ã®EÌ[>Ղƈz•aøæé!ü;e0{íù Þ î,ÕZ‚vÕ/Qˤžü÷ý;_çŠöð+ÓûÐ%eH£xq¬J ¾¶žq¼N›¼"ùUõl÷�×§Fóµ¹Ãq«µ•¡ÙŽëîeòÇ)Q<èÞ>|±F œìÉaë7ÞQ¾.MÍ=\}p襖h>…-;‚Q�×äôÖjÔ‘HÑ $=ž´m./5—h]ÃCO/G#=ì¡öÚ‚5ùÂ3zºP‘÷ÝÔC­gGéŒmw+ LB�\·”Ký ÄŠÄ$¼zµ'( ›Œë? [˜ «Ä0ÞéWŽ7S®ˆ¾%wðD²4êÄuÑäw�Ðþäš<ÿ-äE£C¿ ×µŸ´Yú MØË•¿ó©¦rö¸€æîðú‡²ÐS(¤ˆXwe67åDÀ¨_*¤m»A<òâßZþ›ÄZêÀ}×>'ë7ãx z W ³çêàŠEæ8lJ49½Q#Q) ¿Ôm¡jW9\±c3ÊøˆÍ¦T$ƒhyü‡èü¾mš~6;¨nD|Ó�§ä×�ñxGŽˆýM±?nÁ›×”þšËegᱦV{Íýç6Ów[7~8¯¾HûÐ’(:TVC�ЍQ~ûžóÇ�ƒl¸eÞIyj%zù'‰á)Š´Ö1…Žÿ›Ë¿œá%Òÿ²D?’Н‡Bõ×g8{k �žV }¢cHõÕsh´ˆ§­�šî� ó*»þÄt5^¥t†—|…^Sû`þ¥gá˜Ú´ çî³ôz5œöÆ 4Η ªÓpʇ;8æ!q¦ž Z/©äžoMÒ} IïZ×ã O¦Yshõâh\û½ŽÿY<†It0ým,,œšeéýí8ù~‹§u§ ©í®°Ñ0—Æ—¦óǸaxXË_·"-zcÎ?.¿‚Í÷¯ÓÇTYnœñ¦Ü,åF¸wÕD85<öopá‰óéö¿½ÿ}2l¿gc×½úmv”NÎ÷äÑEÁÒ"˜N„,äÌð}8ù*A—ïc0ÞyD@/ úìu„¹^œ;Æ•ÞÎôåð'í¨’jƒr˜gñ9ËÔêÇX¶“ÆÏl‚ç¸OÔjA»[<ù{‡»ò<˜2#ç ‹@«ƒ±±¹‹ }C°P!LrNBsû̘\Ë;Mì¸U3 ì’Š¡#¥ïŸû_/IÐó»ËÍÿsÿ1KÉ|Cò�/o*U°•í\ì¬OæE¨i`©Ë+bÙõS-›¶„å¿;±‡ßtœe¯‚Ó–õÄÑ-_Àýo"N žDSBœéÜß�¨—¢Å ëš�× C¥49`¤$x© ÖUð¼Fú”Çe hÖ9˜×uDݺdŽèµ£Ü´É§LŠWJ“Æö?<±zE®Šàçö°$C�NeèáŠM0{JÏžbˆòZO¨¹+–Ɯ߉ î�eÇ^¹4Y© >ÛÊ�ÄÝ‚“&ñG]oŽYVOÖGlöÆ8{]H5 ª1›ø×Ãxsy~ùóT»c0óÃqñîÄéøè²®m~Pò¢/W\[οÝÃX2v,èbirŠj«ÖakÛ^PTDæ§ÏÔ/¼C^¾�çÖI|xÝ]Z!ûˆânÇÁ¡umô­� ‹×òÆ5º¼`· =ñnS<§qCêØÎTƒ+"qêRÎÃ;Bý];|ó\‡†¦òB| 2a튋ëg2\ÔêÈ—®²ëª•‚ÿ¿<½±%EXy¤M�iΤ£õ¢®G$î¹ÉëMá«�Íø”»lCV¾)õ´û,I-¾Ì¯bï‹§Fß�åÞ8ýæñÉØ<\k舓ü�Ñî±l[¸‚÷j§ñåÖ,2Xj‡'Ýam«XÿbzûƒÞýQç�£o�{ÓH¬S#žeYY;!x7O¼ñCŸïâ‚6cºeÝ�“—ÃÐUýØÛ*S,GÖM¶i£Lõ™èàåÆ#²ËÑJy&_~x‰xA(DyFrÆÜõ‚v~|µyPý²—á÷õ½´¢¶ýöšÇRK-é^ï=Ü•)Áæƒ{yÚ„Q4¦ß+Ü;ÀÇɌÓãÜ0e¿UµäÀjœøk·øf°�ew™ãd刉O§êðÏ ©Q!D¨^×aöà²GƒfQ*¦ÆÚ š‰�½>šgý˜ÏÙÚ륡g/=�‰¼VKƒã>n½öï"!ó¼–‹ä»ô·«pÞì*üÛÚ‡‹¬{`WÞvœu3CXñ+€•=b`õonеC£xev�ËF�)d|=‰ÕŽ Çm׎Ânƒ�ÕŠIã14�°¥·>Ά7‘�Ô ú×õáùü4š œ…çï‡cåÎÚ펛¦¤Ñ»³YÔêSN©¾V}&�£Ô±_�ؾ¬/ï7³\ ¿QJŽƒèSÃié:(3d!�ÎzR}#@÷Z ®NŒâ0û¤LýK· */§rÒ¾qhÒ°…;ÚAºÙlNÝå…ç—EÃìÔNaI�¨_ŸÏ‹>ŽÅñ'Ç`Ùo’çÕ&(÷x3­]p‹üªÑ8L“{ïFd'£Í‡uâÔ{+ðXÝ`¼"Ä‹—[âèjù)H„ÜÃMœ±|7œoûNц,»Þ7¸Ù É#<庌¶µyasy|Ðq†Òg½Ù 4 ¾<�Çv1b±WöÜ'̈‘‡ Úõ”×\‚ëU§Ý†£Û²Q©õ g/™A×,‡aKþo˜¡|—ÚcpöN7xµ’G]LᬕQ|{­µX»é-ì¹²Š6�ÒäAvƒØò¸÷�¾ü¢½EÛ¨Ñèû¨´®ýŠ Z¯Þ_uŒ:Çòyï5]Üá¯Î^Gѓ޶øÂ1u¾¸„Ûön`Ù;ax¨¶E´‘ÞÌ:«ü8õòhžéÿ‹Žcœ·ÌOø?Ÿ;ôi¨qè¡cb<zD æ0tø¿>iƒãƒüqü¨#øëÏjý‘ íq*xkLý-3b©¦’׿mz†Ào¸ù‘i°¼×<‚ß¾��™¬×Ô%ô•ߌ}5Â[{M¼S$Ýà/DÄï¡{I{Í'BS¢ðeþþ½-ÖxVŠÏo<"«eƒ²>ÔÀ Z…Ó/d³ò gþôw+:ïó—8n2´œkšBÍr¸øÑ¬lÐip´î„ìØ{\“–CYÅ2d52²ÕÈáÆZÚ›4�ý2Íøpå ø£Y,<‰àÊ'M^Óz…cFg`¢ñzžTm]:ŠüpP+)ÝÔ´z­…ÃÀMãádÅ |Ú_º!²ÄítgqE^n\þŠÞé„ò×&<¯µ /ƒýyò‚ýк~ƒ¤ý¢4ýP�|JŸ‡!Û¯�¦Ãˆqýx@ø4íÔÖvƒTázþÔ2›.´›rùŃ–ËGé²�§Ó/ÿX +,óAZîÏÌÆÓn Ððã{¶;õìO©â�¼^ܳc:*uö¦†˜H d‹ÑÓcpÿÜ7¤(¤rŸCÛ$‹¥RàÅîoëH'z¼k¬Ñnz.z4d±¿rytH¦u&qÿÒx\é˜ÉÕ×álq,þ”â÷S\ð†ä)LœÎš½Š9ƽ-?áÉ¿¼XSvŠSoàæŒll4‘†ÐzaM£9¯['¬-RÀëa9¤Q�L§lÅ Oð>"�-À½_o¯�ŸHLÏ¡!ýy¡‡7®yÄëSx€”Øw¤²f…1;†mà9†»a¸ùiØÔO‹¿©Q¦õ}èØ,ÃeÌÀÿ\"ÑŸõ‚JÛÚÔ#’z(U%ìø¯¯_B}çɨ;ö"Œ»ñNt_¡]ɽqÔ£%x]f"þlËéÚ|JìÇœ�)Ïè1T¯Ç î ævüŵ–îÎÚ"™uÄ—õ?+|´páù2~psÞø"ßN[+ÉÄÎø¦-Êκ²Õñ¿ötäö÷Yè¢Yp—Í6�ü‘Á­‡kp…Îv(ø83B‡Cmw(šÆÜÚ’˜Fï/ÀÙôëC8ݘõÖ¨W@Ióã- ´Èfnæ%7eP)!¹¾F¥Ž�ºÛÉ´<žK'ñ±�ÕË„.VòŠ„øŠÂ+ÿ~uoUØ~ÀsaL†nqSâ‹svbKóX>ùò:]`ˆÇ ÒD“¬èZb#ɬ…–>w¡õ|îá�N[½Q3-“KŒ¼� RéC­Èûôâ®Õ ðËEšÃ½bèXÅnTñ]Í«å{óbÝá<çõPÚuP(̇û=-¢“¦û¨N¨€S.Y0í\ ¬H—3OA¯-Mô!y9Y®„×§åÕüܽZ|¥úŽPù-˜ÉF³€Cüøír¾ã«À=–C¢�Ÿh\ö mv@™( 4H®ÿTùTâÓ´‘„1·à¿Ë…¹ñìç"Ü¿¥Xø>È>Ï“±ý©•küi Ÿ[ ÆOƒQ¼q š®F£éŽAâ©)éàꙌŸí$x÷Cé4[¢-‡/'ñÏcip[¿‚v¼Wn¸rú 5çì‡An3ÄË€µûUQþzYŒ;ýLì¹~:çÔš³}¤6*ïS#+�Ô÷¬4žW|,êWmÀÐ ;l�¦€ÙIµ_&Ó%•1B¨i6Û—ibUa5­¿©Ä@ý‰'‰?<ñXöFž»t¸™§òÈ€Ý`:®µgÉ5è(Ýë‹m$9yH°rŸÇ âR¯Ï4¦T‰') (¿Üûû>…‹cɺò+7ØÏ.¬"ÇG9õ©å}þçÓN1¨=ð'©÷ž†^—˜fdúñõw¥Ô𫚶ë­ã&ÛÙbø@T´[$´}.§ËW¶c/7%<àŒR‹ `{B<ŸõˤøªÂξ;Xrª¢NVq+Ö?õC‹Õ²V_ÆIñBS¶|l1µž¬´qï´ ÅZ39f…òñ)u«�Ï$l´å#ƒK¸¯x”Zvëòú¾š<Õ}Ÿ8ù&Œîš±ì÷c¨ë?ÌÿÇ;Þ�y OzãaÙ™àNü$ù›¤oö^]è/ÖÜëâ⣞°)eÆ?®Ä”£ÏÁZ¼"¾9ÑÀs­4È›ë¹lµ?{=™â¦TÖ߯ì¢àÁ=lª¸;•µ ?ÓÛ&4s[Øã’J+—Õ°µŽ)Ï<­‰«Ó°­w%öx;„3ɈUvFxs¸&Ê­W \õ«°lž'?¿0wù-Ç—O‚iŠ'.½¶’W¸ßãÕZÆì1$G'ÿ„1fïñ¡ÊOð°8ƒSÓ!¦n �±0äê…’e“¹mj–‡=¢wöú8éú,?©/\{Obã9âDõ‰º¥Y¹õÚMXºgþÞZ,¾÷w5k~`Öܬ­5¦0‹õ¸=)“L�¡S?/�¹” ^íLæ³CûÑX…�è¢4�̳Càj/e6êË*ÇÞ­\Y!8‘,N�ÈR/J¨¸q:\Ú RäÌ;Š+iô„¸ù¨ˆÉeð<1‚lâʹ¶>‹§À¬—ùêITï¡ÈÅShùéíüîÞ#°ü¨'I:SEÉUV¢ ®Á€®Ïd½ò¯Ï·Â?>Uð^ÿ ¯uA5ù&¬~ߟ4\õ7e >Œæ“~'��ò²`eS)Û¼Uã³’¹ñJ@½ú‰FZR öÎbú°³dj»R0;IÔÒ{ó©*ÀŒ—úC.Ë»påàgäÖN^ƒ²ikÊq̾Ù*~�”¡“e¢•_GÈOâõ´¬ßNØ{›¤å�‰¥­¥Ô~w!½¾Ïi#åàr“9«JêiXôÖ1U†ŽŽì|Cj÷þCº”Ø[“·5záÏ�'}ÓOç[MiÐûéœlêqŸªÂõ¹#8’¥2{Õ¿½]IpnÆXí#¢†Ç|´ê/pÍdÌ–j…°ö¹d¬<‚Æ—ÎEMÉ –n.à¢aöè/ߊŽ˜Ã #/ö ͼÅ\8›e� [‹†»)ÉZ‘.8åP/Í\áì�Ñ+u ™¬Á ÜðÁê~V~ ªû]z‡ßøÄ¢~ØÚ¿ÄóR(Z•úÔ‚Ûõ†«#và·«Qbcw!>^´ÜöHѰÁ}…)qƪðKÈa‰ž[_­¡™ÿõÓ�%Z µ°ÛøŽï�ÃL~‹ ÖPwÁN¼4g—ÐÙ>�uHqtQ ¶º¿‚‹]¸{g8k ¦bئ$š©„z”;`º£)Øöx á‹,áþO †…}†OI&˜Z·^¸c‚ÜsŽæO’id5„�R 32FòΛy|û-^`=oœ¯âé£ÐÙ"Ž¥\aƒ*^l‘ ¸ÿµ'oã'€=zpÙ†¸¼f,*lˆ¤#ôI>¡E°µ§›³rAw^7­ßç…;æ‡á”km"w¦A«a:8ÄÎàDåbfÙw¨�‹ÀÀ¾vxêB8‹š�;YG…~Wº(áÓdU`ƒ¦±×ñ‘·®¯Ò¢Â[m ¾Ím»z[ÅZŒ…s‡öSVôp ÞÕ‡G¥ö¢Â˜\x¶8�'ûìàcšè­|_«0×HÖ0–å Ѧ‚Aï¼Ù\§eÛd+>×ùì�Ì„_÷³ë´³¢Ïëå¸fÂ%ZZr ûËÎӈͧ¨ð“‚µ á@�ž¼öî/Èj{Žö‰?„3Á£Äò£g` û J¿Jº>C¹~ö^›sT\2öÌO¿ O½ Q1Â×öZÃå{ŸÓŒ ½¬¦Ö”ÁÍýXâ8Œ¼äBYsdÿ2åÕG±ô‹ˆÎè§ãVvÉÙ!ɺ�òž¼@Í_ù0ÎSO�ß Ë Öá©í‚âRo–ÝT3kò‰¦œj®Á—Ä?ôòè|Š÷L†¾?ÜʪéÉ�BqVïD²–LæÓô\¶t.î½£Ñòó†[%òºçóXæ²n0¾ƒŠ¿’°ã�%j¥N‚žbÇ“õB�#îwO"Ù²UŽOýÞ!ÙyÉOU�¥w2¨­Ú,–Ý…Ï×îÀߎp~1,»5KPò}6\y×�ZASz âÖT,™³”7�D7a6o¾~–¼,ƒÖ}ûÚvqsa½¹?w sá¯ÏZÑxh$†ï €q‰™¸8v6Q¸¾·“à®Ö*²³v¦�ÿ‘f–dLý¿ûãÐ’4T•³Å‡ôìwÐ�à<Évµ�xÒɘºw¿Їձ³ò<sR×öeÿ9¾Ø§£ox×E–}‚ñÏ!56œ—†ïvñž¬N0ôy±Ã† ¥/œøÙ•›0|� Ê•ó¡.CܾÒJònC,I {4D:ærñ­ßukŽŸµo å—Ó²iå’D°hžÇŸ·–QÅGšž;c,°£O:îš³‚ ¼Š¸»­?nr†ì�ÊiA\/üò Ô=[Å3Iü§¬šò÷?£—ý øö‹àÒ+;û 3ZBP〗Þó‡þÏ1Þ~©Ž‰©×xÆôõð©H‹cBþ�kù5xþ¦·^ì-Òt'<}YTyd‚«åjh�ô=òi.[s�÷-«¡ð€.:îœ�Uí’Z“ôµ\ë¤�„¸Ú3Ðïázz´bIá²�/aŸÏ~IÅù`–rK‘Ô~}IF_fb§O?¶þL€_n\Îõ÷^aõ¾­pt@ OMçÌ!p¸Æyøm²|Š·¡÷ÁÛ|Þá t)GŠ/ßùp°þwJhjƒ-µÎ(•zŸþú^¯ `½Æ{bG^�†D»|–{û†6ÍN"× 3Øs<ß5Ûº»¾‰ é3!®¼ƒ6ûç°ßÅ2Ô;s¼;BZõ)øÉG‰Üw…ã´43RX»€uZ0~^f*øðêpÔºë ‰¯ç úöëø×ÒZÉ=#c<ÿWˆ´­Ää©Ü[ü+^亦ý÷຺ ^kš�zå„Íñ|þÕCØjT‚e«‡ jM“°+¨ñÛqAíV[õì—¬{`ÀæôuDtɇû׉ÎÇ7sÏ™qõŸ�Æ5|½¹’œ‚ü`ñ‡ÏBW°zÃDšÈ�}ì„ÛO�Ò‡W·I²aöŠmÀG’°eÖn*t�IÛŠ#âë`|Tv�ªþqª2¬§ôç/¾ìfùW�ùçf�’Þd:/\R–6 UÞuÀ I!N5Œ�GÑ�kw…³9pýàhž§cÄþþYtNµ?¼ìÑfù>*ts£ibbþÙ` ?²8Ôùe]YÈaüjAC{âÀ¹¾80W �ël¡"íh|+UOVK4yù©,°™w\´¹{”.&ne™­_Éôõw¨ú¯?w¢œÿ´ñ·ù?&S˜Œ!¶ïÀ|[)ï¹JŸŸ¢ÿ¸�üù›2Nç°ûFîN,âÉÏ~ˆ ’)\ÑÕÂuzaèß] 6@™½Ý„ÜUSp¿T _ÿ”Ž1�sFÑJèµWòm©.¹Ã2£°=@­Œ÷³JÏ,ü¸uÛ¦„ÑäñRœ¾µ£~¸Îw°×‘ÂóäXòì:�Uu�÷9lŸ{E2Ôl*zÜ`•7Q8E•}Û¥hÑ$´ýo"Ok™DJë' §*>A`z¿†p6ç/èD–´ÕâÜ>¨òô�_jÈ«Ý ýÛ¶rK·:Á›œDìúݵgÊ`Ìe^Z4“N¬FÅ…‰QÙ›”¢©R-Øûñ€Ï•è=BÌ”‰ç•¾Giú^”4_#Ç9TUôDH93Î/CÍ^þ8tÀ"4ØÝ !êiد¬Ðæ]z-Ü6K§ Ìqq c1¯hçbØÔï’ÜêØ<\ÄYOàÕ"<ŠEpiÉur_ª z(]ä¤Á yo¬øøãë¨=™L{5@áQsù:EÍ„³,ÝÄì¿› u¿ ~N¾ŠI[mPMg¢±Ì ¿<¿OöÚCÅß øæùäc†°¾{#ÚéDÙ†Ó²úTj.^“V°j}x\xæž~¦Á ïqÅ‘Üù¼t=ÞÒ(ûÓ´ÉêßýwùbFÌ–úÌkã„ÜA !°¤–öJñå…0ÌXgÝ[Y¿{N­¤ä9SæŽlXø©7èz©â/‡aœ_ Â…SX¹9=[ß%úlœ ä]Vƒ``ïÚt½L²Ï'M‡›ãç3OêûÔ�f¯1(Ñ•â#ªY°TÇœfÎ!zS|¢3Éö¦ îHw§×¡6\9¶þøeΧ5úräuìþ‡xô‡g?U1(Ö‹ýZ‹XíÄ>l�ÌSÉw×Ƀ?w=… ªVóËÊ(®ÉŒCö£ÖÌ$Õè zkâx“± œt!¼¹³ÖYÎ¦ì¼ý‚|Ò|i£Ã5'²Rß«°ýd., ”c½Xm¾i¹‰÷8à"Ñ—«¦eÃE·¥¸û½ü•ŸÊñÚyÝú8.\['R½–Šk³õñÆÄ7œ¬}¿6$ý7I=€¦JftÃã8þ.f5×Ýpq.ØÞ†A×�Ãd.Š|7¢ý��t¼aw®| ò XèPÂÉý‹éá²WäÅÙÔ÷R OÌ/½ùºËcˆÈŽD”–ÇO›gò¥rcšpä¾V@qì?¾Êˆ�yñ¬­z˜×¾-¼7'´ÿÁK“ÓáÅXO0™ZÊwõ}ùö™›âM/Ú6÷&5¹j‰Û¢óD‡’ñëÙʾ•L}:D­å2üU?[ÔX›%Góxfì1ìTðD‡ž±`¶XkàvM‰à–õ³¾ÇŸÝ£VlN kŒcEY9ÑÈþxº'ˆ!ÿ逷ß<îõ?†ëÃË> ¸Q²ÉÊjØBVyîß‘-%D%´´í¡YÙÊÊ•‘ ¡pŸóHJ •h§]4¥=ÔÛßp>纮oÌ~6¿Ð¼¥¤!yD,} ~Á7‡¾C÷Ùé|ë+;²,ïO»Iß´7ƒ¿ÜvþÛTµ—ÈÑé§—([O6¾1dœA�N‘ƒ—Cºb•ÅOßJ*†ðÍŠ~èY}ŽÂ‹K¹ÀHgÌ/<ÊZ4®óZ?¿r“ߌƒÃ+|Xì�—0é7 ¯U‰Û _º‰Úçì€(ýdmz“Múx™¯1ÜÍ4¬žãÊjEpý¾žïì%å�“«IG3Œ`Æñ"Ûco–O¤{žzøf®+é*àËX4¶fòŽ×R×’¯¨¹Ð‡_vT„]{?™ö”ãèóUºs)d¯?±EŠ|¢ëm>ê^8éܵÁ9^wùlëdüøc>Œ¨\C­©ÐoãN�ÅÔÙéžsTRb×ÏòZ×bûÍ—¸SZbgZ°ay¾´à˜<]|x‡UŠý&nŒN˜û^?4@ãTáuu=Þ™­Cb«×ã¾CP3Š£þ¸l8h¿–”ùÓ¢Â(væ{?Ff4L¼Ê†ÍP¢·¯ï£Ó¨aàèÂÃâéPôÂK,Ý?¦½PÏ+¡p¢=¼Ã8Èð À«ñú�ǃó¡fçiì ¨Ç…{&ÓË»ÿ‚{WÍ-Õ Reª‹[‡îÕŒ<=Ÿ Êrîâíå •’�¡7chT–h=†‰~F°eìXš‘ÞÅ’Z%qäªK$nåNwF¾ào†aξ›|SA&{}:”Ê�ÒÑ$.ÁæÎøâÅܳO1çGã¹ZM¬/Í…NGIýÛ\›}ƒ�¶œìÂoÁèŒn2<:—Oñ†§YÒúö±g8ùÍ­ãm¶ž` �ýÙ+×ÓøÅÌ4ÿ‚æ7ö$n-‰DÝàVؽDñ¨Œÿ±ˆæ&>ÀzaIìÜGƒ"2¤k"ç­—�àµ&Nœ›Hï£$áÃ…g8ËÐ 2µÑ(Í›¤ßcñ[èÚÃé$xj âCÏ×´r!wûè•úb|ÿþ"î/:�]ÕNE ºÅ 7s‹4hmEr7®°ô�v¶f®Ûë‹&›þc-†½T%èàÃ~µcJW÷sä4š|x8ˆŸâÄ^¯aþc»@㕉I¬…¼`uÇÉÍ1`p®��.úçÓ ¬?8�:/Í£úâçT¿r ´—.¥¦n_º²óÓÑl‘±Ýi@›æÆ°®©P³Úœ©ª€È¸XrÞïÏ–TŒ…»{0 k€KÈ)ÁúßSàöÇض­†õ?�ƒäüq "êNÊ apâ\s½�·ß—á5#8ü¶ £ùDV,=ž­Š~ƺmý˜³�¨°-Ú— #æåJäÉ}cæ[!¾c�yûwpK[ïà·T“ÖÑxÄ~°QÃì!¬Vèh¬¢*ÎÕ'ºh�Äbý>BŠŠ,œð³`Oƒ<ÁdOüHÞF޹÷Xñ‡]äqô%«Ð †êþ ì¨Ñ=XÙ³ænGgæŒ`_ÿu¨ÅÅ<6~Õ!ò>å gŠò Ä3�fuëÑë‹ ðiª/l¸ÉöêíƒÐ3 2È4$iéƒ(Î]SI°fñ^’í3£Ù"ô¬,«Ï¤ ÂÏ£lÚ�l2¶͵›éö¥•¨¸,Ä.4²LíRêè¯À¯AQàh´cŽÒËŠB6aG©cØÊ�ÜY© �âßbô‰P|;1«ŒÔɺiˆîmb3gé£ÙT|ï£ÇDÓò 1ðÜ6 Ëc™´R&-?i Ñ£³Ø‘švn4„–³Ès:?ÙJŠ¿c3 ´%ߊ©àήÊ\ô&ŒÔ }§—ó¡ëaWãÝ[—YºäR.ä6G½W¯Ã6Éïh|¿œÒ§†3%-g\�Ó c9߯ƒa˜.5Ž9ÞYÎ5ýëÚ�¹ab+húÜ26o¢¾ßmCï®ß×{Ö”²Ÿ.ðXzr3¼=›Juå—ðПðnuI•СCSÈäÞ!vãÍMvý‡ôÝUd:‘Å,ë¤Öµ›ƒè]Ðüj Ù�m܇Zðè�¬ðDó,àíæÂÔõÍ$·ò0û>é"Š®õ§õ¦ älˆ6'Ùʺèâ¹™øV 0Å#Ó`´t+n£H½íq�ÅŠ>o„•ofѯ¯°oº43­ð"§×üÙ~?Z.jËn˜já9ëtÐì+„I)£`ë!)¨HÊ€éâS@Ç?-4H¹ÞÜä>µ0S×¼ÆãêEÌ%r*pòv$�ËæHQíÚP<�ÑǬä‘AƒRLˆ _ÈBÚñqà,oÆ[OÒuƒ““Óc*™H§8Û|ÆO� ÷] J¿„¡ڱ0ó*ñuj*4KvnYºŠÏÙ¼“?ÞFw£XÞý‹;×½…æ¯ÆåEòh¿ùçu†ÿúݤöYÒÑìF¶\B–»öPG4¨�âSҧ׺yÜvÅ*2j¯ÆYWO�ý-8·¸ Gn½ƒ³7ÝÂÆûîlël!*Õt0}¯q4l�Ek¦€%á.¶±fù~ö¥,›;•!tŠ4yOã¥¦ÙØË  ðKUeЦY…ù{òIaz4Ï× VV4FäȯX‡ŽõbG¥#-6©§¦³ÉðRu…ruLnº+}z®ÉýÛ;Ú4tò<'_: Ÿ¼d2o‹Éáû ö³!Ä’m¯¸�Ùm‰‚'ª˜‰=Ÿ’8Åùç™öæõÔùr<ÔÉ¿dš¶G(~ÙSþÊõSpÙj.®“ cs¢Ø^ÛÚrÁN˜#¹®&]C§…0-ÏÔT½XË‚ÎjbÛ”ÉåÆ[ú«žÃûäûÏ0S�à~Y>Rü…»×SM ®?LZ7¾A¥ =VE$WÔq?ž…ûÁ=‚ÚÕŠäñ\�]ž`7M,éyô$hëåÙôyû@7G‘ŽUÛ"½™Bû?‡@�§.=Ñf-?âÆ=‡ØGßwÌSì7Ö}_#u®à÷í:pSz.-¸ö�eM;…_­ò¡7;‰»\Uü³2Ù³ikÙŠ�*~qô~J€=ð:XÃQ¼kU©/�Ë'ûñÌVò´ãaˬw EKv�ù–Ó4�"Š«ou£o_"‘¾ÉŸOº""ìØSGO?kÎG¦’û}J”4btïÎF{ó#(Vz–yA콂z¶�`ov|Æw­ùAõtzzª+ öz<À_m wÅŒæŽ-%têú‹Çe®�ÝŒ)4)gKf”à©_#ÙÈŸIl˱*nÝúÕôND“ vJq‡œdÕÊšpZ¥–¦ïøw�Ah-ŽÀ=Êδîçfæ¿Ô÷ÄÂca¹@¥Ö”µ®æš¶%±_õ³ ÃÅ W†3Ø~ÕÿÞÒãt—N §n,Cð Ï,OªÇžR|É9Ø*z™æ>ZÕò�µ:1çÌvìN‰ÿù;“�ÒAîy Çê/ìAÉËSÉw…¨¿Œd”¸…ªá‰óntú�6[>΂½\/I¦2þÜqó$Ü{JŠ==aÄÏ¿ª Gލ³n/è~‚ ›;ú.:Ëÿ,¢|Í.�XTH^÷¦„¹®ÜÁÅÌå¦ÓöÌãg¨�gù¼0¯Ž½�.f;�Ò5µÔ¹}›ps¯å¨E‰‡„l[ú_äNºÒ9«5Ló‘®{–�‡Ne’úÏ4ˆíÎ#w%Ö39–î½Ï2®ƒÎílvî§~wÿås`µ#Üòņ°`ó;Öwë}êIc»á`ƒcÝ,2>�Çž}sÓ"’œ¹ˆNl‚u�:Ág¡S*^ZW{AyÌ-V£«Ž‚¬Ýov4/žýâ �RÂO¤ÄKH41“VoX¸q"œ_èÂŒ?ƒ´tHŸ`þ5v(zzlW~ÀÙ¸Áª yŠÿ+ß¼­˜”­"D*eQ[<‹á‹`“ÛÌ×Ë¡À¸9°&J ž‰ç0í��T§’ŽÎÝ·Øé¹£écî ®÷�1]XˤQÅËzœ>¦ìèACÍá˜õ'‘¶ÿ÷žå¾œ±Úð:á"çm1ÌÔº‡Š. Ûö`¸ï>–’EÞ‘»¬=¬}]‚qï i×óAnþDW¦z"�¬ÆvÃñþ%òK*�[�Ÿ‡'uÏr€ÔŠjé­ÆZš±}#Ñ’|e‡ÉÔži÷ÉŽÿUFÚõ±T_iAe&G˜™ÏV×2oñªÎ_¬‹âgÚ±÷E/ ûðtö÷bÔÕGdö„f|9—~Ê §~�`ƒj”a-FáwÊ`gÆWÚÒ‘ ›õ†;ª¹"¿Z²†b<|`vC‘™µ6ÃÆ«Ø4݃,hzôæ¦Bè$ú»ÝžU*Ò¾ß'ð�ðXìßÏ/û€º[ǃěhöÊôn˜/Ûxˤ�]ó†5uúîŽQãl�î&µòÙàµì 4‹HÂ-‹�(š-hü<Üq¦Z ½›R@éŠ4I!…íz}”1û^: !#¯æA‹5èÁ�°é”§ÖÍã½Ú’AjîsòÞJÏQ×›ÒÆ´ç  {šëQ+�zË,î÷[qÁ¼Wºð|„ðx¹[½`š0ïÆ–2³�dTæ“ÌP¸ û‚àNçàKÀpx¶v7¥e %]6�€|¬¿H5…£¨»[~íö„�ŽìÙO^ªã¡LYðÖò‚iz’è;ýç~« šzv¥C•Œ¹°þ€€î+³1)ÇMT„u“¿³�»™uY=ÂÑþ Üéò�©L …¬ÆA0œ9Ž,íªÈ´8º�žŒÖyê&/žºÃe„‚€=ïÀ÷&}߃c^ |ã&ðJÐ=ùL àµ2# lÏ.XÜ�Öý·ƒ³ì~µšJ-~û)(~)–\ÔÃeU…léäW`î6Êž„�Õ‰&rüçù#ó¤ÀåjT&È¿õ3/å•ESn2~•®ðí¸“Üµ•ôlèèvtðë^Ùs}Jiôàœ·°ãÏ5¾i µ ¢$hÑá[‚Ç ¤^¢œD2Ɔ>B —Pzº&·—�ÒŒfæ¢+ {—s)= xÖ- cgPÕäáŽY±ïIá«2E_Áªãžpw|Kpâ÷+;îßÕ€aÎ>.Z•*ûrèSo¸4g’]lK¾u[³ãè�úRЪ;‹•]⎖ù“¨àò,(%¨8åC;sFâ‹f,}÷Dð¨ëÉMàüM™)¯#Ê»»™7 ÞKýϺ¸ÉÈ­™âI7ço‚¤ƒˆ“×t2ùu…`8}=¾Z±„’oޤìÃfp{q&¹Ìît¸÷©Ç•Â֤Ŝ�ê(G“Ü~œ×ùß¿L¡G:º¸%è}!ˆv4ÀóøyÔ5cŒ\qãOÛa£¸O!FìOÖÿÙ ËZªèþcRlr iЙÿ’1{7þœGÍc<\u1�êüœçÒ†m)pâ´ð�7öìgz-•A{"ÀûèŠâ‚Ø„tx¿aÅä÷áOýf0Ü uÊY�ù0ry¢LšÒ"ÔPÊØ˜ y:ÈÉ€ÕÒ ~X™.›'9zre¥7}he´\–m±Õ…w>_|+½�ÓêPÕ÷‰ºEγ3¾$þ¹´ÕIdqÉ‚V­!…Ã9lU}:ú\S¡ÉµbìÔꉠ¥UŽÍÊѸ`áiAõ!G ™bÃkÆÃC5á¡”æ5ãÆý‰‚“$ÐÖeäzͦp³.ÎàA;âÙÏv¿Kád ÊÙªa(ïd‡nÏîÀöˆ(Šó­Ày½–°©`{^Å_1n‡ªñÅôç«&ä7 F\p…ðf;XR'Fem™ïÜ(‹ÝŽyK¹ ÚlÊØ) Çm/Pí…ù0ƹº-Îs9¹eðÍ2‘þ¾îætV”,WœÆÑƒ~°èònø1±’¾Z„Ó%ÛDæeâþ�&lz, ÚÓÆÃç=~°>U�’“-@ÅBÓO¯‡\;1lS~Hcî3å‡õxáÒJ\IV¢q�OÎlŸçÃèYk0¸Xw±ÿöeÒ¨uÑØÚ£M™cíö‰ �²œl[Îip]þ´®S^Zò�röV´µ{ ~˸nv€÷¶ó§SŸ³¶}ŠÂ±‘à¤Öðîc&˜aE¿ö­¥‘ÆT›GÚºd:;¤fÁ©ú|êg è–ß ß.qÑ?Ȳú¾ûA·Ùƃ[ uâ(‘^€#OV£™J=MZ¸ÿb3.¼ðÏhÕáìö=Ž–ö…:G+ò�e¾RÔs7ÃÂ@}¬˜¥¿†·±|—5›¡¨Ážì;Æb 4„6—Ì)#D�jµÇAr§Šã…Ó‘�識ƕÉà©pލºT±»~Ã'‹¦±žªøsÚtîÓuð*¹ n'¡û¸}³œÉL7\§fe ú“ éåwÁÞa55[„âúSr Ñ$^5,%EÈ{ŠÓ�SGÙ~-oXVwsÓó©ÚÝŸšo€?ûS$…r©c±c) ?H'ùÅaœÝ kÇü2]rÈûç=ÉB°¾Ûßò¡æn:|è’¦«ua�üuŒú�œþÒCtCøV¼zLÇóig†+ZÎá›±]T·,™Ú³N j†–É~†%QߨúÒ!6Fû4�¤Ty–«Dަ‚ÎOeúWǦ^c•¢&\de:9<²N ¿ÁÙ{Í¡æ-ca«ÇM^-è)Œz³ºü•úFåQzÆ3Z{¥œòM^ÒŠ…3¡câLºh/%œPÂÿ°>‰óVÇ‚Œ†úv]½�Ôj1Á±jM 3Ë5¢²ЬïíEÁ†Àrcê¸æú2Z{/ž$Ь±®Ü!5+J?0ŽŒ+¡ûÒp¶Âë;‹«18PÃã2i¬Øg¦¨à¸ÊwßæhF­³ü¸RweGéþdôð‹ Ñ÷ö�§Þæºq¬Ÿ#¦ëÀ¾.™æ¿IÅ[âút2ú2[01ŸÙŲqùñ°Îà�ºÈÁ®óïá–¯-gΟ!X4`\ˆ:öÀa‡Ÿ’s…+?/í¸ó¨&2º_ÏÒôÄVv�wèßήX Œ7­ž©X5u {?è?ƒ¦·ò$>˜¦IWd‚1»å=Þ?R yIã`åÛE0fƒ)n[þ_ÿ·–]Ì… �¸ž¤VW-OâÕF»í0ÛfÜ‹t@*„Zû­+^Ä`Ÿ�ÛϘâïÏdã›_³?O¢` óÅk¿ë˜êõר¹E´¶ñ;‰TFñ;÷êSrÞ¶µ`hŸ�qüXHGÉRᘧ]a– ÌÔE"fûÃÀ˜©$i_�ò½AðrÒW²&â«î 줇C·ë_=zÁ&è.æõªdiþ×ï$·ctÿŒî/s'ùƒ3A×§|V¾:~ñ639ãßЦÖË‚co°¡�ø�5WÙ]¯7(uúû¬s™-öÊå†DÌèžü W«p’[ç= ¯ë‹cæW5Çî ;¬�lÊÝIfGPx=�OÒJ„WŸ:Ù«ªrvs|ª5§%JÃRépôFpÃ9ƒ¾¾ô9s|œɦF±q$PiÆ-Ýî´è¨eÙFæý9ŒͯÑÊ&Üúz#‹Þâ¥Á{x7£�½û´Çç¤áo¥7ê©¥9ÿ 2*ÚÄá›{µà§Ø0G1¥³QЋ.g’y‰+ûåã˱¬öº�Ö’ëÞ%À•NæŠlŒñ|@” ‚ø?q¨R6憋:¶î¤ƒöມŒ¥o݉“&±á“fЭS¹l[Q =>Žž*SÔâ&ìr·‡ØõRޱúYôïHÏÎaµ«o2Å©^`Ò!ëXé!Kóæ+AØ�p«·sÛ˜w›¥iü�É#®6N{ÚEÁ+³«›$áàïièæTF¿Ÿé ãÜV‚wÚu–äv”ñr õÏVr¼&öœ\5Æ ç-d¥ zŒ�xÅ:R§ã¶ ãi×¶ rþo˜cáÚTº8¢�–„ ™ÊËÞ¼X fÉRÆšLJ5q4ݰ +NWà ùƒ,BÍ –F‚’K¦¿;ö¡Á0`±ƒ ÎNfV>îôYô2=J&ûu0©ÿóoƒ.`*Ywd?Ÿ-‘µG«(ϵ‚Ý›Ø{ƒ�ÁµÃQðþ™ ‹ÊÄ®/n¹)h©|{l5wî¶FçÊ60ëÖa"%ÏpÝ +qeg ¤ï+.zQm¿y7;mZ9ÓE)fŸ¼¾²ÆD\$ÿåûH2½˜êÌÚažÏ,:3V’û^÷Û¡¤EÜw�¥ßGãÊ�˜ÓAIP�Le“·jQeÀSš³-FÌÍ»ñØ;%—¾­Ú?ÎQÓÐ-zó÷³�¨fý/$ jw×bÃï8`D Æ™à·ùUCØ“¿m#EW¯"óÜìtk½ÿàðÀ§ü†œ_ÐÎ×ÃHWENê�?ÏFN#Ô¡ýÁqšT{oEØÂìÀ–<¨ Ó>Í¡´±céõè04LÙHmÃ@>Ç�L^-˜cÖM§fŸæO\ §-ÍéÐ=ß‹u„9[IÓ#]È{õb(Ï K ‡x×k3ik©4ÜP8 ÷µg± {:³4¥13}% M-‡?—$ÁÄMtzW±¢¢¹×VÏÞ6_#C\‡³f¥0�ŒPwà6%;_ÅŽÇè^E9w§éªÇßÊFž,£Ú˜ÆëM‚õq¨ázÿOŠ»4Rew\å“§I�Áäê¬F¾[aû‰4kW/TgeRN0;|$9VéqW¾šáÐ[,y”½jþÀjy&2¿·…xíŠ!ä5 ¡wæz;]”h ½¼cYíš0öW. x¿ ¬§»AVü~¨ÿ¶2^{±�f�Ðúò$îÊ™€Ç—†CááppŽ€¢k=•+CÕ5#)?u%|Ž0¤%2&`ª¤Œ¡¥2„%óøYõ…œÕùGØ—¢ ݹÿ1Ù—�Ø«£ëæò,l» ü7-­ÑïV[éd=6fíÓóýfR©ZDˆm¢aH~ò¢¾ rd”ê@ß6Žä6T²yi�!²:Wΰ'‡T;º¥ÍMÀ©ô­µçP*Ò‹ 'Òms <:£›T)Ò¢•Ž­^€7çñqÛÿ ¦ZÕ`ÅÍQ‚¥}ö�}ñ,äwÞÃüôjèAoÕR÷ÅL`ýüT’Œ©BMµδã"õ­ÊdûG*Ѽûü¹Äõ´L®üßÞÇck’ÆÇ 8CÐIçfÆC™ƒæ…:ÁB“0f¨ à´v¹�Ûô'¨uù(S9 ªÇ:PhüE5©‰�?¸ƒ6oýÁÆÛ�ƒã’X‰}4 ½ÁÙÕ…±5u¶[c?âH-\~¯oO œÍGÁüú7vôa+æŠB€x{WˆÕ¡ÀÀ^µgÁçCp2à!šõžay É ; —NMâ|M¡¬¦½¾áû°½ »¨ˆikg¶ö‹iÓ]´’±Çð²± Õ¥O}Ité±)TÏþ”á†s-úuFÐ÷ñ‹àöð (øn ã¯_bšCqðä~$i^‰†³`Ûpcú3­–iúlÅ�­ñPé& Ÿ kø�c”À§þ;“qŽ"½ÂìºS}ÞÉZå�±2{< ®\ åOØÅ|¬;-Çl‡t߇iU‹A±ª�å¿‹`Cþ©bò!.>É€•(*Ó„¦å”wTØ·¥0íf8EäJ:þ9cL›ä­ üýa&=0 ´VŠÐ[ý4P 6¢Še¿Øº+ÃAki ˆ·O†?úq°¾íÛ˜©u àj~6§e�IB9ö`Ò[pÍ®anÞfRî1“wº¤Äóü½Þ��¿,�ò•maìä\”}Ÿ®nºˆ"3§Â~>ˆ¦ùXЂs.tW0€nŸm𜶠~ºÁ«¯ºLÞ$w+„9Ó®qOm"!%«…‹VÃ9³}ÜC»‰,Êy:4uã¼¢0<ðÂ�¼/äÒ€Ö[›I;V³/}Ul<>déA‰ôî÷!Á·ü9ðßßUlyþdÒ~§œ•e ŸC8¥ýýì)ÁÚ¯YŸú{n«H;ûÚŽÜ’-IèÚ ÏÒ9úU2Ä–ô'QºI4ùbMþTÿ’½|çO#þ rû½å™ÕÂEä3E\ß5SÈ. úoŠ1T„‚MM/ö¿/#ñê0¥#œŽl]Lï6í£nam[aÅõÿià —†ÒÀýI /7›ùïØMƒÏ8*ŒÑÇQ›Q¤>»êçCÎ�8>\3ö~ˆû¦ëÁM÷�ìY®dœ€6³ ìóÈdxõí"û2q"ÍŠqotËÙKS�6ÍaóŒñaóTñˆ‰'××ÔÊ{WvžnÃþôQìô3m�¿…œå8ÐÏ™GK«ÕÙµW°¡A‡u¶’å­x°­Í…oW+Àq—,êAx<¥–~¹>ÆYy�ºaÁ ü/¿îj¨e´ræ³;øL…íL'9nïÛÅZÓ{è‚ûHXP°ö=³¦ÑÙ’Xêî÷oƒŠ£Ü„“èç3 �ö€A¸ßç–ÊILÞÛóõñÊ:uðîÆ/cæ°û¤ó½ŽÓl³ZlžX@·v´3ƒúýè=¾“ácê·N¡ç);’´Úɹ%Èà¹8X­ô™åJ”@÷ö+p³K_—…ôÉ-LX0œÎTÍ„_jæPêÛž�’ïç°ðEæè¡”ëv¬$ ECY K*ö"´ÿ]2»t`,mdæP:pÌTÐíEtÍ+‰ýÉFO?¥ñ=b1P`4޽ú½ œæO畇�¼±+¶™‚òÞ‰xKn ú,ô û‰·8:þ/cv%CI•;H- � ;.këV÷§Kæ&‘Ö€®\í8jÃLFÎãê:]ááýÛlÓД9¦ Æöôò“N«ö'À¼8)jI•@�ßYŒoæQ¦Ò€þ-¶L‹¬ò%¡/Å…f­Ë§ÌSi¡w¦LzÄ®KÏ õŽÛÌEg ì+™BµÁéå_¶ÝÆgFU¼ÿñAä?+QÞÁD(9pŒ�{ÊÁðW�ƒGîã’F¾Bu쎑#Åe'¸Š1CÅŸ Ö�…à—{zuxþjÝúO#ð.Ô¯>Á2ëÆ£ý‘¯Lì\4ÿ¨" .|ÚÇß=÷Ipõ眠¯ÖkÂ+UaÉ™z¨°×þâWU—³G�5Tö,‰·UÀM£ýaÎ�kdà›Bñ¹© *²ƒbÜ�áˆæ\ZgdM9rò¤ùú8YxmƒòÄ=üõ‡ô°}¦ÿhf==X¼í^ýÇ,|ÑÄAë�*l3t¢Ã¦‘õ62‘°:Ú$¬„�½S 760kI85û/k\…†Mz|m3ÔN!©ï{©\òSÙ¨üÉtv¿ô4g¬[�3jà†�W)Mt=(çþû¸/ ø¹ShÔ pImÂ…êSѵkùE¬B1;[ ÈÑÁE}ŸP…�õL=Ü�‡ÏÝfóUn¦tñf:,3f3l1ô„i_°X»Æ=Pv¥ï»“¡lé!jíà(Câë}6•}½ÒL{“rȽz*¹—çBáê“lhßz¿àºÊªðדlðÁºLL ½)ȦÁ}/šßG²ðl§ò0|»ñí]y³C‚ißw÷è(&·'– S~qË'ECÆ‚;´äOóùº—ô”2ãîô©oø»íó+¢à‰¶ý [M2g/±BtXð«:Dß?7aKV×P~+±²&=Ý«©wy�8ªê˜ûi l¯ÌÂ&Žú–ÄÀʶ|­[^Ÿ¡*�Çlüòv>¼Ûú_‚‰�5,øz  ÑG~,ÎÈŽg�מ°y—}aħ‹´¿Ó•v:r‰ê©�|´2¥r(V)^ލeuÿmgU}§PqwxºŒdÿyt3·�ÅðÓЕ ËÕâm,“Ajaÿn-’é<ÃúïUs\n x¼Œ„šoÈÇŠ»�ËöªþV‚g½np/‚Ç0±+]è¹i+é}7Í\GÛ7å±R'K†rñVV%z†Ãóià ¿ýh܉@¿\3ZÛ5†—ÏšE¸à8[¸@(øºw�g–ÂÎ=šl…a=ÍH8‡fŽ…8UûÛ}û!×e¿ŸVް�5ãhÍa ö_Áf¦?³še7ýe"BÒ %'ãU¤š÷ƒÝ‰\Mέþä$š‡ES³ð˜ç5,¨n\¬ó˜{–÷*<Ð…W—Y©õ9féþŒÉ>ú·kQ»~*“t$‡—Öë�ÎbWX–úo?—÷bõ¡Í8ò±±Ÿ¯±Ä4†×Þu ¥ä&�ÉÄ}lŠÒAg}Ì_“ ˆ×XLÞÐÞp Úñý$Ô ¥µ_GÂly8•ËÝw[‹õs žË\ÆÍï62#*€¹¥‹)Öé/*�J`¯õDÁ*$’=)Åm×M{ŽXSˆ*±?³¦áÍñàrlyì#¼�ŒSœvPàEˆà ééŒbÞ‚{E/ÚÂiìÝp”¬m¤ç%ñ³} iŸ7gwWÀšªÎ  •ýwf—@¤ðÓÚA‹…™ØÝªÌ¿Ú” bu7™Ç}zô$ƒÏï�Óý±´"b"ÚiÓñ!(¥—cùéïÒŒïS(RË•n~ˆ ÿZ'á“]äÞfGîëJ˜_Y7>ò˜C#_–³�ŠzHý½�©µã¼KeõwÜ©[¶-¹ÇOÈ�;#‹ãŽ�ÆÇq4êÝDXÒŸÒ(î¤I';Ta|ö êÓ8ôÏ”ßpëÃPZjO~šž0ðGŸf~(†Ï¯Õ™—M·è›&âÝklÈx7Âc:Ýt»Ç<®šQÚ“P:Óÿ‘Iôkз`s˜™<Úr”Pí…€I>©Ç�[£ÐðB3‹«ÀJÝ:°d{? |J-²oPá¤/øim�!{M¨J=Ë”¾f�…ý�û£#\ +@rê ·»BÉ?£€ç=qᣫ|E¦$-êO&GéLÈï_ˆk_Ir÷ÍÌ@Ô#; Ÿ¶›@Æõ1œlØQ4Üu˜¦%ÒóžrÜS<šVêÌ¢§A¤c'O›ïàèŸs¨¶¸„,çU௽TSjÁªÊípëˆRL +¡O«ÜayØa0ŸÒÆ%tôsjÓŒŽ¬zk eç³Q0AÖé8±©B+:>Üs^]À-�ϱÂelÇ*s8ØSŒ}[QâÙH2Ò•'¾Í„ne¤Ó¹…”Ô'rKŽé€§æn¸ì¦N«õ�À½�_«`ÓÃçâ#›·l¿÷$öºs¬ñadÐð‡Ù«­äîúÐIl<›ÅwE¿Äî}ÅT;Ç Düª™új64Øä�ü6 ïÊÓO¶�™Õ`[.ÏR¦ÿ‡1‘§ØïæÖ>‘…,–úgúÛ켊,)8u‚�G9F_Í +é.ÞǼ,šàúò,<÷,Œ_$B k$üàl„Ñwø‰A^â•.Xì–ƒ¯Íè#z»ö[ O]ªa> Ú8>à=3|]Šú�¦³ï&º H0þ":5K“ôŽú`{|�ésÁ°¾¼�=��ÂŽ•£)nª8ƒpàÆÈá�qC�äC•8“yOXÄ©4ZéWη¶û@IJ_ð-—Š[ÆQlìc¶üþƒÆ†�:°½úôÈ"Z¾]GŸrÃPÉJ“rgõ®ØAß×xÈ™yr4œ8}álPøéˆý+Š(8&öÕƒÞ”|7ÿ^ô\Ö) Ö‘·ä™ŽH>´gÜ�æUŽèxè<�{nþŽì“'½¶dW^,â§ÿd£ê˜…o9óxuˆ ~êÁÊîBt¾¼Œ‡¶Ãú0FK¼æÓÚ]ìRn výõ€ÉÑMðèoÌ¡G0G‹RëÂhÆ#rÏ1Ĺá¿8UÕUܵÃQt\â ™èsÜ÷B ¤—t3nçÜóF¦É>`"�c ¢”ƒ¤kã¨R'œ²”]@]K"Ú’˜Öå|·ë†ôA2VšrÌË ´³ž~n!ó/žLF/C׃åùZÐ{’ÊdªSð¾x¨W‡³&�%0¢rdF0#í(Ú´í-Ëú¡ ­R¨ÿp k×VG å�4?ïiq W¾)‚M- 4Fœ,–üûåÛ^d_›É·œ,ŲM–Ðvã¾Ç]Æ)º èPc@u ºx_J€ç¾½¥°�uüî »(Òº†~ð™MÌ¥ó'Ÿá¨# p@7F¾È�n+(÷ŽM_úKƒS¨Õ<‹ä/jbvÉt¶åŽíôÚJ·‡�Ö…|,ˆ/8u(†u/“¡–™Ÿ˜z©*$$-ûñpVu�œ]:Š#�2É_,‡¿]  G¶,¤ü94åùqþìš\z÷M†î$ާ⑆Ѽ–4R3¹€ÇëÈä¾¥>îbqœ‰Úþ©ƒ+Ü<»™_šêÎoÿ’HV'0Þ‘ðëàúˆ‘pî©<¨9¯ÇÓ9°|áuÖyþsê9E›| ¹ 35Y﮿l[Ðqx8'›ž+]hhÓZkSb¨Ð;ÇGERÒ‰#pÓÅ’3¢ƒàaõ�{è5¶Φi½Ѽi�~y¦Ü%Øš|’ÚoSŸzëGƒUü?Gݲ*X„±ÊñaP´ƒ¾)wÓ++Ìô?Ž»M_á¦ÒrôIÜë{¬iÕîÍÔ*QomÌi5ÀG'gHxÓŒ'­¶2ãóñ±ú{¬ñeBY1Ü%&�t‘9i­^�Úg_ñ&w@të00¥ÁåÌîÖæ¾^€G~Œ`/dX_¶ Xn@”“;M®Peéñ÷Xç¢R¸¢¾—6ù¥°2‘ì·Ðò¿>f²á%lq_ _¶Ð®ÎuÃŒáéìö.R �ç¯ �pœßüÏÌ�F–}Ùx™ÍÙ?Š;;Ø‚Õÿåa ë¢M{+)¨÷<Í<8 T4DZa>y0;-î­ü¸OŽ#XÆæB˜/ùˆµ}IaïêÝÁÖ¬ÿLqt‰á[,²/îN£Yé†pGáë¨ § YtÉVïD(’àòA.Σ•K�´‹Ó•€ìW.¼.¸9*ÂÔThŒûUÁÊַ쬌3>û ×ÅŠ:zIqà´lçT.Êê_¸Pò—dÎÿÎ76ù– Ýk9ɽ Ìò»s XNƒíuZIVaæ0gò]”|mÖ¸T`IáM3àIúm(nú‰’wsY•¢t9:‰ÿ¡ŸDËó¤`Ò…¸â·7ªŽŠ¤ëé`%û �Û˜Yßgï§gÁõªñÌ:Q‹,”s»3åÉD´�›#¢Í¯[%%¼¢|¥ŽºÑâEElmÇ=f?ë Ï¿fýí“(ñ—9ÞQÑ€½ëWÐæ÷Eü3é<ªö¯ºtÙÔ&6ßû>½Ìr£Ï6îW´QFÒÿ:x°~Žðä#Q¦´ö,ÞžXER³ñF·l¶¶o”ØÚJ9?ù¿c¡Þ7‹}”ÙFŸ*à6ÕÃÔ?q,í~–€Î<Ä篮q–«ÅÓSÍåã�Å$Ô¢YhäpÁ— i�÷8‚ Ó«`ëƒæÙJ» OÓ‡ÖÅPš��ö¾˜q3§’jíNL-ÊB–;±´š6¬½Mß%…f¦ `ê?Ò´U‚ŸéëY�·“ò.gžå² w³ˆmÈO; §cvNàss6㇤HÂñ9}H•`¥G·‘c›6 (¥#Å °d™Ä›4ò&ÙV,jÙ"¼ü6�8 �m qI€7Í‹qAaÖ”Ecg\ %M`~ÈÒZÓåÀ­t‚_¿Y±Âr‰@xÞ¢ÍB:“YJò}Nph"æ²ÍÉIœòN0ÎÆ˜›Sù4YµäA…Ï8¸~�P¾³K`Ÿ¿µc@EÚ„%Ýf«s ØÒuè5ÇÕÔá݃$–ÞºO¼h„èÜòZƒ�6š[&¾akFŸe-kO�äôqÔ:­×:Í�§fhÞÄGÛ�&«µœõ‚*¾R-V¸Èò¶uôe ┨EÜû4?jÒˆ#¯0}Œ->q¨|í0)..§#– |‹ú#”ŒÔ%ÙU°ï-Cã�`Ô­wDZÆ7øœ‚R´è ‹|!ºŸ1kÈüP‰ûöñ#ÖÁ¹/b$þ…¡D¤¤eïfÕ+�Å‚´ƒEÔJPe¤2ý6…žÙ§?vCžù_ög—·JMÌq¾êd[mü—/ÅøGq…y­Áí¹5¸Ò„š¦cÌm[Ø`YÉ‹Ã`ÒÇÿøFøÃwo“eJi¬³X�¢Öv¡qŽñ?*¸øO¢d!q•7>¬Ö³Ùí¤7¬ÖÚ›l…¹G_‹¯�Ç3Ÿ ¦|ë9îÙXÇfYÜåÔ’Õá[´$øÞö‚7ê(ðƒ/í_N]oØW/†Ý¤{ GÿÓëÙì½§ð¢¦>·mC1ȼùÆoâH+x)ë2‰#Ø ¿¤£¬Ô<â@‚Ö–�âÎK™Ò~ˆ§:ÿ+˜deJuV’šM\]íÏ?àÞ²ÞÏpz|?—VQGCzpîF9¯Û‚[õÁšg &f¼ åŒA¼»?�ŇÔßN +ø×7—³³¾ú´así –À‹Éñœµì|:´ù0þ8•EmÁÛЧ3�Fÿódâc;ú£³‹“À|ÈnvªP¸ì<Ö.V‡>UElÔ®×8¯ÿ.[ø1�?IÞ¬e®5Œ¹î�ÇnÆòÏ|¾±]¶² n;Bi\ª¬*%Ý!¬^[�".ÏðíÞ›löç9PÔ—M‘«6AÏ6º€³È«Ež¦í¤<;�º¢O­KWÒlÓÌŽ­f²÷ƒÕ¨~ÌàZJî…áW�`{íaîïãù"Öf´óç¼$�$n`»ÈÖöðS«‹¯w›8d þÁSë&ð5¾e ìrz«[ÙI&d'•nчÍ3±Vô>v(X «™Jfá^´)ux/ÃOKsØÖÀ>�TW6Ølž�º±Ð2ÞîÌãR_ÚBöÑÊH¼ˆA¯É(Ëž¼OGó‹�;“úæ‘HîšÔ¥G­‚»äÅ`¨z §�y%Ky =ßß5ɇ(vC‡iü³–æ°H&×ÞyÐ=u)NÚ„�5;øÂ¡üJ§'Xý¦Ÿ­ׄÃÙÒ`P¼²œ'pã®D’ò¢>±ªŸI¹Óqëü8¥Nú£6œñÔ¥¯Ê9¥| 6nkKúñƒkµ€m’ž�ÑVT´#‹WZUÎò÷·’Ì/ºy¨šBªzqØüá¤<½�ïïBïúŸáúðª�ÂŽP!dFJ(•"…û;F´%%¡EJ¥�JÑ4KH-²"2 Ù÷IFŠ’Ê)½I)¥]Òë/¸Ÿ{?ç>Ï÷1-h`×^›TtÎÁáb�=‚ß%”Q"ÇžEß%.ðp´…Lð$Õ™k F蚸Ž~¼_Ç:¯À¹Ì=Lq=£M™Ñä,h«•höçá3Áèš^¼~5¬¼F7>îÌ ÷v>ðOîãÝÃê|ÎúÅ܇kiëý»¸V?�U>;L‡¬ýXð.2Œ/+ŠšHÕFó I]«ÿéAìÌA–Þ Cw꙲ñLØxYrmÀ¼íÒÏÿ�á~shþ˜À‰mõ…6¥[¼ïЇ\Û£lnœ« pPç›Ù¥ «(j—ŽßöŒµO%P!@ñnàã„÷˜¥@ «â=MyœSö™u†9‘€¶3{pë¨8÷rŸFu‘ßf5X0ìnåV™R�¶¤Ê=Æ�‹édAÜZÇŽÜ¿aâ‘DÌuÉ)&Ÿ/ öwb­ÁtìªØ@§•÷ötp^3¹3 [ÑP&ƒ¾µ9�ïf Ó꣤½{˯~`bzç)8kG°Ï1EèW×Íöœ½)â+ùîqk(d•ÛädÎÜD ˜½È<Ó·ƒÞn>ASòçÑ}OØ?ó*~�Z „ÏÒšÿ¡kðdâ[’Á÷ö¾ì›>x5\D“¸Éà%VJáGÚññÆåìd@¤u|C-#Šš·™Û•$JGw¬Å±P‹Çrék‘:Ê+EÓÄ•mÌú£"¼èšAg¿,…Ÿ°®€(º¦Ãtj„@s‚ÛàsƒBìñÊü"¿„³(I¤�'Ý!>*—/V$óÅÛ)ì�Ô½»‡åß1ϸ{(³z»qv7�ùa<¸!”;Prš%ç½ÇöÐÍ´»ò,+p|†ÎobÖ2 Е;�Ú>ÇÒ«øùlì‚<¢*Oƒ¾ËPÌLŽ1MÊ_+ŒYùªTö4¾r—˜÷¸\TŒS£.�uô2±(a §=ùtž]—¹Šý;TÙ�§j�&_Ãjä˜þŠ%ü?<[dñš n–Àºöãü*#'v_—='ÑÔÌ„ Ï;à±¹û@ƒjxÁ3¬Êr¢ÄápîÑÁñ˜“šª_çSÓ§E˜tžú.`;,Øß,¼fó*IUà#$Žü×m‹8±e-l‡§" (¹ ¯t¿£Ððüº…öŠàÕ(gS^?Z”:„dA³ê ù,Ù‡‡o¼¤Û�5ท+;(ºÎ e”�É_ÍšÚæ5ýlx± ­H<ƒÜýßܦgÓÀP»…O~óš 8Ç×¹*Ð5Owfþ¥f½û þëyûn�>ø{²šI¸*?Ù²“�©žNÀ#ד€‚ý¸éN:_bõ£lTI¤ Â÷ÛÈí?صÝ Œ"˜”÷E²­øÀ* —ÀΆµYÔŒ^ãøx±py�MçGW¾dI �Ô̧õq‰{ LžæF°�ÍÓI-O «öÛ°*q:"ðØ¤¤J°¢¾2ˆ�(±Çu+Œa[�3d¢ºú8–ösy¼Ç�JW8&©ÆÍ¦� q¥Ž {:áõµÑq–7É厢íÑYLVã0‹ÝëHiÉ7y}â4fâÇgY¥ˆ÷ Âk£ŒœÊŽU…•ç�W£6aP›p— œkg.ÿîRîõ?lfý20Þ±òLÆÑT‰:|r „úÝ2`›Òpº‚�VYÜ›¶hø~˜Œ{šB!nÇ.Üd>® QÆ%)ÌJ¹DÿjWAo²;F,8ŽïžŒ…\·]V'Ho2üiEç)–4Ö’Éá½”¹`ðöûv9›ã¥*v½eǽ$A`ž u³I¨'㠟㕸çJÿá]SŽ…Êjp‡w±³Ç¨®$ß¸Š¿Ä}2+eÓEÔ`§“–¼[2âÖjÖxìß¾á"[ë¶µ^Û¢LìXÒÿ& —âÿ·Üè¿ ÙÜ3‘ôúg<»¹Û=•Þò¹³(f]./¶Ò’ž¼_ÉF›FgCUìˆ'•Íй'†)­�cŸóRpá;rT6f+ ºÿmT+_úYc["†ê>„�ì�ëlá{èàÑTfšOŸùÀa‘Õ8ó¢+ˆ¥sd/“uA+®uª84#Vô¼ãíÖnÁEº{Ñu°œƒ'™v*×BŸ}6ËIY@%³àŒTëÝ» î]T…®¬aqæ©ÒƒˆÛlp¶ 톱L… ÇN] z¾òÒt ÁW±Ì("ÑäRˆk»ý Yx=Yô==¡mØVŽbœÙ Õ>r$nÂÜO§èªÃ9¦öOˆjÛ¤`Xªœ7?Ù Åe�°ÂOv„Á¶°…`þÚž“wšFBR_Ù^�ÔášÄ"«'ÁþýQÜLž‰p3v¤£8Àü‘=¾àrZN΢�O£a—™-{aì�Záô&¨ Ý»ÙfžeŒXUäH }°½ÏÂÏ$›¼9í ÇV¡æ²ob×L°=(–øšh(éÁÖ³™Ã¾̺;Žþke¡kòØ]K¾âI8¬ —�ˆÛ†ô[ÜWßo s«k`hbG:¦ÄÆ�6§ÝZ†x5õºIµË Èò5ă^5åcÒ#AÿÝg4µfÀ�…ºtJ¤†™~;Gö‚ú`^[ξ¥Qrø0Úˆ4R%xµ°ÍÌJæ*\õ¹CRrKø$ÖXð«þ[I‹[�q�ëY/š¦¢<¨°ú2ÅOv…½ó0%b"îî—u&cW0P“¼…úŸ[Ù�[Øñ®üdé­JpéÕ=:äÈAwr¹ m„ÊÊy0µÀŽ-õ4‡òØ[dxX‰.^1„åUŸ°{jë-»Ê1ÁµôZü*>7‡m޵E÷­…ìå±!°:Ú�êžýÌqËþy`)4ÚùSàžFœ~æ`Y´Î3îƒÄ:\z¹ ØÔm�l™EŠ¢&”Ÿ¢�ßýªéÝ�³Ô1ãŽ3Pé…LkEŽ5ŒÞÅú²nÑ t´hLEÕuGRÍû�] «$ý¨¨ð7ëß_Ão•šJ3_òä.Ágý#ð»6›ë) ©GHW]Œoj¡XŒ^W€]Ìd„Ñ÷~ÛÓµ‚šÿiAû$o6žu²G-!¼Ïë::sÔ�%ÎP%‡ûé´âÑ,’þt¿LŶ�íO?E§¤Þ`ýW2Õ¬Gg˹`±ÌÆ4ÅCÐ\]M:Æš$Ji†õÈÉçл1R5½YÚ·aÞvT [Üã_ `µÎWvàé{Lò'»�‹áv«²Ñ´)y¤·�eÍ�I�³ÏÐ*‡“8æôfª}·-_÷Ñùü䚯C¾jáô;ê-œÚö�ç‚�Ò- 9øJuë$Ahòv�ÉJfãÏl¦" k:P÷�™½$¶{5ÕX°ÚÕ‹èÑ——4ú¡ �c+YÍ­WÐ%¶•“�Ê(�ÍQ¡n“ãøùå ‰—_a{FËPe^v®/†§j¸•ú‹@Õ{ÉêÛ�Bn=Y¥YaÙË»,Ã.’×Ý$H�þ3Àæ'údî3Ù¯Õ�»$lìÅ'U#ÛÛ~˜²þ{Æ$ˆ—éIk@Æ[T1£ÍõÌ/ß‘ž1!Úë2¶˜&ÃRùë¤ùôvÞôÄð-ç¹ÐÚvjìÚHÎËû¸ë÷R°ß(†¢¸Eæt<ÎÙCV òË'™‚P1¢·Ç,ú×¢J»f¤ñ}*ëéáÒ´Òt§î§¾d`,ưõ¼jpÆ�ñ�Ü‘ý2c"õ§eó%Û>³Eû ÙH�ôƒ`s�?<Õo ׋Ц ÊB�žcÔÁ”:ü ÃÝÈ ï<ŠßÏc©jŠ0ë†:(´Ï!I'ÈŒLÅec5Qù¼Ù6ˆÓºQÈ[¦áMnà4Ä,£rÂ'žâö?ÙÙ}Ëàíkøyø,;=b²M—j˜Kzl¶{GU÷Gáà©õÐz|}ì^²I3UY­ÆrR˜€>:@aòtX{0ž“½oJ©Gd;ñÞê¸É÷ è[;³²{hð�NÅóÀìÁÝRëV=˜²Igƒ¬MS1MÁ 4¹¥–¨ÎoÐxÛ½Å`°ÍZD·±¡/6L'E¦ äb¦áDV&²‚¢§î„YÿšÊõDèúIÑ ŸÐ62J„ÛºQähöžŽ;„ÿ½›LÓ>ýÀ=á”,~ˆ?êRØÚò:vuk$6´0‰4'–w¥ƒ�zè…eÕQx9~X pó’—Òùœf&±>ˆ_®ÌOõ݇‹?Æ;G/¡Þ÷­Ð~J�¬›hž€YÑa`SV…þC&‘Ö Õ" g•¸?S‘â´àùñL.Aëw d>Û9Ý�Í™‚å+”fâÄo]&“�ìvh€²Ç§q�m=©í”¢ÏÁ_ØÓÜDèƒ$H oc–•²ÃÕüçæÛlÊövdC Þ´çwôAÑlX±*ôÎÞc…‡i_\,½�Š„4Áã8Mr!{î$H&‹%©2X¹"¿:Ž%—;ÐBï8¦`RÔï”ÏbªJH÷° ˆ¨Ta¯Y $½…ƉÛéÐý{”–]Â�>·ÜW…²•¹\ÐîëLò»1û?®,þÉ^i|Á±¼)u¬ÜGÂV°F²‘YßÖd�[÷S•ú%ÒØ› µêgØͦrÙ{s©i_",ú#ƒ ³âéZ³>¬ Ÿ+08U‡^˜‡BÁ�ûü[ã:s»KÿãÆßyÎg±É¸Ú5ŽHPhªx=ŒàZ÷FÓ[;gR®®ÆÊ Ùä–=X™´ŒºS÷ÀÉc:�§+±eÕ f¥4²-�ÓñħÅ4qí:x}_œÌÖ:`÷—*ÈÔ2%“ÎÖ©ž†2F3›'¢\N\@yxA>{µê.-z-£má®ÆØð2•Y (Ó†þ�ÌåÁŠX5€_ì’Æ÷óìÃD-p½iFM¯qË…¬ßé¾Ë™ ;ÞšÁÜâSlH¹ÚD×1MýÎbÜ•`ºL ~ä³Ñ-2�IB†¥é(+‚¼^ŠZGçê/`cì Lz~œú¦Ò7':|ö ª…eà¨{›`Sa9ý÷ö*n31Ñ‘}õe‡7pö,]R &‹WªtZù‹w»Çþ¨.ƒ'ûUø�×C Yg DXXCÜŸmP :b®»¼¨þ]Zp¯òú�ÕWkÖ±?ƒÐÍ—E¥u³µ-òœŒG<Ó=3†õÚ‡²NË‹8þþq¸½Yž„İT½)l››0¸<�f½wÞ¢ý? c¡½9Ë*˜I…�‡ÁÂm:­Òû”(�ú ¯Éÿá$ pj² ¦ÁícŽlEʰqÚžŠ6ÈÓçðh<¤êÅ:n¹sBýyœÐIÖy¹ÕqËÁ»d>�w| o¿k�ô qx^4 õmèêÉT¶\=Ô–ZáúW—xãݯðªÄrú£þ�ñ†!¬^΋Źù°™sâàù) èà”¡¼R mªLèŸh"o±ÀgÞ§0[xaâù§¯³y·Ãâuâ¸(,Ž÷ÆQ¸Q+³L 0éøÆ Æ7¡ÀOkŠÿð‰ÝvQ Y7%qšÑ=Ú³S‘8+u¦òõlÛ’Sž�iÌøëi8_&ÙšÒάQƒ__=¸ö¬dª}“Eマ°åÇùV·øPsöé€% ?½Ã‡¦Le×A’„Âϳ™&〛9:2\A~e—ÉžÖ™Xö*3œ¢ -'`Ûì'ìE›‰~Ã¥‰§ÙΊ^ìõ3ük¾�IŽ3 5ÛP º×Ë=Ÿé§ïÇBÕ±°í�ÌÇ×ï²Ù¿º1Ò»"­$ÀåÛüŠ“_Lq铃´äi„߇ö£¬È¼d%5H”±Þ¾>öàOÓÝÖ‹zç@ÆÁv1Ù‚ñ[ZÉ,g¾s‡ 驜ÿî‰Xª‡IY‚Ô«ü“…6oBÅl¥Àový{6 öñç2#Íi¯b-Ý’¿Àÿð™¢"¯¹à¬.&fk5‡ž“vóM°EšvÅ¡o›·‚®,¼É¶¶û³þÊul^ë*Vj2�“õÔ‡ö eÙ‹[a¦ö_ü¹}~^q‰þzH°ÍŸ¿ñû­ÐJ> šnDZ�ë�èDZ0ÙŠ“ÿuÊ ]ܧ¯ÅèPcE;—ÖPà´—°ÚM˜Ž©Âg´ee‘‘Pú¬˜|ìv²ÝÅ—Éï£ ~™Có7E¢tÆ]t:[Œžïs«Ù¶Ë'OE$V{€ÕÇ£bÊX¸++O£Ä¨In˜ljlpt®)N~f4xk½Ó×0?8uæ)©7®eÏRšq¬FM˜º¢…Ðýøzø­®IV©´ú‰;»Š˜.;ØŽ~e,ìG<$(-á'”c-†“ê×Dغ,ç™Êá¡H1›Ëq!n«–6=®n2,†*•¥™Ü�P8!· µRǘv >º…¨¦lŒèòa¾ÃV¶yÍ,&H·˜Ä’þ¹È%ìz‚]ÖL!¨‡¹ÜhäßKúÁÔàãZ�&~òêlæ¾®³–fÑæÏ·(SyM™»Û½Àð¿ßXÚuÖä�Ë}˜NâIÒžSÁ'5•Òë°hÂö·¸}h2£•ü©9N¸lxˆÞæò³ hX…]YZÅ+deñ³ŒúØEcü¼û"oX=î7ŸgÛU \x5ÿÊq:)߬".H�Âå‘w¢ 8ƼÅ9µóh�tVy„L={˜ôª|·–$-û¤G³ïF‘»Èth çx�è(¦•…Ÿ~”sŸr‘S>ÉW¨‡Ãe“oìÇ„ß8{[2ç©­ ]Vþ”¼´‰VÌ®f] ŽPlÈ¡å®DXõ»’»*7 ¤«³¸ñ…션˜$3ãHþËVˆP£[µ‚�×»�w9¤!¹SéÌs›5‹ÞšÈSÞ¦av&ÿSÎêÇXáv/f,I®Q£!ñÕìXê|´VðÃî°0Eæ&Þ×cËìÆR�Ý þÚÍy°\H�ýW<V…l!£”ïÈ-Œ�äå.43P†ö…CØ®<Ø.»Ç�Ï•aþ—¾?u1˜ü|ª˜ÝÀ?Z£¥ü+vÊ(” ð&ý=Š÷ ƒÉK«í¬à=ª§Q±õ3^[4Äİt�%àîÖõ‹,¹Ñ¿í¼Íï\?v\\€ßï¥cS‚‰`{—ÿûer¶Z<÷¬b—²¯Fê°õr;>Î Ê‚áê‡væP„v9…`4�Š? ÁŸÈÔÒ '“Ëß4ýâÕ•µ`מµ4¼´gÇ]¡'ƒÿеêªÉ­ ÖðEk;Ü0»ÆÂ'Ø0³"'ìàV±´éGiܹJøò° õ‹[iþ/_ÐK•1ÕQó„ÔógñÙVMèü{™ qzÔ±Õk,aN¥:|×ßÖ¢hXþbæ/<<%„)ÏE§²Tržf¢UªDcdSðQ�5y–á„Ï"0i¨‡º•ñ�éÓø‹·%Ñìé\:ÒßÄþU®e¯Œ#àüï=¬/ì6¬׿߀1oO# 6”oѶ-{?ÉœìÊåÙÜ›3 N_‡VM ±BK¨:”Çúì4ËÞxˑ͚[üðKžŒçl ½³“Êc¬SÑÓò5ª9¬‡ÞfQ0��!·U ·]„¼m¤èî9ø/~«¹–Dû¯í'�ÄüòVwynTÿ®òe·ëAêW5�Ÿ˜ue:¡u…Þ­¹ÏV).¥ìÄzŒX¡NN±Õ¿[�.nÝÌ g71=s5:ûæl|tŠ^xÛðovÑ¢ù‚è.ÐÊþ J�÷~ú¨‚ëG\W•0hâáÝŽ…Ïk(hx>];:™V'¨C“›ɺÛÒ¬1oàÞC g3ƒ&îªÅ[�aq¸6Yv+²üø<1Y²B>mð�ªËm³¤£tFû~<& y#öý*K ��ÅÌ29¶0` ÈÕo…‹É"kRÁö ¥qìs3<½¡È9«éBq7…í‡Si£_Íç¬\¥©ß³� IÖáíõðÚD Vj^/ß~ë(]û« ïİ>é ÷:Z¨¬,[…Út%ÈgÔ+ê2¤·Æ4jÿ Ìð‚Mò“iãÄ…´cr,z*O£Ÿ‡”YÜÀHÇš¶CÀÈ–_1ßï¬Õa¢žCu<@ò•)pÄñ Zƒ½Rø‡G�EØ‘ÌbÐ ÓÁçǺZhRÿï�0ºÝ4ÒŠÙÙªb–W½œÉLg¤ó_&†êCºX1Ï¢æ’E� 'ËÓ{ÿfÖô“Ii'S¡ÛSPÿ°’Œ×ˆqêQ+ac§þ‡.× ¡¼%Š~•DÏó�8pÍ‚/žGÌã³(µ†Âç_õd+½“Z÷ž€Ô Cä|Á þÓG8½û9JÇ)qq/š©§ó*/Á®ÍÜݼ:8û¶yˆ³CU:Ðà> ;·Àç÷ÁåÂAטó>iša+Q.–G¸vP¿8ͬ8¼ó+Óœ#îdÓâÍ?ñ®óHoj)`rE.®UÅm®™üæƒMìØ½1¨“°lÔ¹w9²æÅpÙ:Ž?²‚õ󦃉c ÛÚõmµ×ã°ðTu(+®ï H6�€§�Yo±]’Ûׯœ¤_ºá´»‹ÑÕšA6p4‘}q>Ê7è™á�I ²é‰Ésé©t„%°ÍmçYƆ‡d"`ÓýR7ì£õê}8Ým�ÿêK[fü ÁÑ[°Z{%–-Bë¨ÓPôc: ðĵ¯à�…~øÈ‡ÈM8.Ž]E'4ž�– ßófBï¿ôÛCŠ6;F«vûvÚ‘~^vÆÑ¿¶ÐÉ>wÖ¹u<ë)‡ü}{YBý lë£ç†Âü­ÏùðR6=v¦�R´h´LYŽû—…Sú©,sÚ�þÂ^ÂxO} jº�'¯Gq°÷ÉÎ]�ó3 xÍ“ÏKôàMº%i\�/·ƒõ€_Qˆö§°€¬©M´#çÙ±iQßYéÊPjnK„¸òïl‰7éÒÝIGŽZ°Ùå3s¹Y¢¥d?g6õòqSÑWô]4 œÙÿ�D\SØjËÅT'Ã,²'ÁÌ' @¨>jžÞãî7똦dt8ê„ÞךqMò9?�®®{È4±Æž.æ±t>ˆ$ï§ÌØÕ+cú¦Uÿ¸¬+ßrò*ûòµ×oŸ„—®ê€Æ†tˆÉ6€ã�û)rÇ|ZÔ‘Ä4ïZ�ôÉ45F‡µùçc¸ÓÒ ôÆ…ýü�!;’Úч;k1I¹`˜5¬ ¶–ëèÕããt¯Ñ‚ÔL~‘U ŽKzõ réÚÆ4Ú+˜Š—aFX“'ˆ�IÐd�€>jb i¹Øx8k« ýùK/±ª–IdXœdìݧ@ýõ+Q~ªšé‘=˜7]�¼Ê_±Gy‹™ÙÐxX- *B Ì?ÁrÄ­à뉛èv¼—]RÍ\…`œƒ5¿¬·šIü�'Õ¬³#ï&�Çd“ÿ£‘Ý6Ý ä–+Òܽ%Æí?Rð;}š³/NkÑÝk€úêÄEï¦{n*˜|æKݘ†Áᤗo„Ãurda&Ç{í`ÃcU(ýÀñ:›ŸÒ®Ÿ?¸îÖu0Vëh¹ÏfÔ4²'cDàno´IÛå0èªD?‰Éìãb{°ß` –‡ôIÔC™ŽÉž¦c7~²—|ðœ T³P�ýûш›„¥áÉ#ø.xZ"ÊõÒY…ЍÄhÂÅ\håNû׫Á²õ­Ÿ£I�;¡Ùè9…x’§V8MîO"�=MÔ4! M�¿òžƒÎTvá N(Âäµpcîxlýýš+ü�w>Cm¡ùTSóîüÀCÊÑ�‚ÝOÈí‚)9¤¯�}­x@ä's:ßÀž^œÈfÄ?CÕc÷Q}|8†žŽƒ'ÂS`Ÿm1u|��¯v5²A­CÉ3H°ì×yJDŽc³ô��J&�cšô™ßÒ;”6¸—UæzAÛTQ\–“ f—�F2gSŸ¡„¡7 8 Sj½t?F}ÑGŒJòWÃ.É â¾—º?gª2‹˜Qy§y­�I¬Í¥K}ÓIËňқ¤ÁRYIÒnô˜oÇdá®këhÛ8u8º|¹‰‹·¿ù÷ °Yê _.‹ÀÅ4]{ˆvÊŸásSîãèwØÜ¿“ùÌ|yÄß1x¡Ožß·e½OØÐ‰BrX|KN΂…ST¶ ;ý_q.f®å}QÑlèÁuÒ}>¡\Îs> «&ð¶Éi¬!k"ÿÖª�–|†âÈiðõþ]¾È¦ŸÏ@\7q7;°±€.›Xó1‘4^Õ²>L§#F¿øSJ°ï{ypŒaNTü…‰ot‡Ëª‰ÔþÕ�Ö;ê‚vÄe|Õ½„E©ÿ`g�ïdö>¥ôAfùwI€¤ô%°dó`ÔוµÀj¦Ð­¨¬qF½Ú›Ãë…‚{Z%TùKwG“c£(äXžb5R°(7€IH8â»Ãøú` D˜ðŒ½óƒ«US±^Q>$—±×¿¥*Æ.Ûþ+žƒ1k¸‹ÞÔ�µb§á¹Íà¼ðÄþv&í¢8ø°ï„¤î=Ë{>¥êh-ˆüâÏBÎt£¹W4Ùx½Å'Kàp°ª?}ÁŒ[ºØ¨æù$ý]6<©åÏí‡9 “Ñ耹‰Üšë<¬Åb§‰€]CŸÓSoôh¥º‹®…e'“àÖFIrlOÓ ¹ØhÿBþÁu™ %®šG©‘ö½kÐêPÂuU£ôÓ)à~ã 3ÛÒÌÅžºÈ%Î A)Ø•mýØ1M‚e- K=XrÖ ôÒ&Q[~(2›ÿ5,G;cŘdv zÌäYáµxzêø ›^Ú`Bòï7ÃT‘¹”¼¨ÏGîA�½0_Dƒi·\¦Åñb0CÌ™W桾C><:r*%9œPL¯–€øñóøoµÊSÁÞÝç)°D°Â?þ \HÝé�aþsö,V Ï¡]´ÝÉÕ¤r…?„™Ërß{'0#Ó;ø(Eœ467 e„8W|s%E|CÙ½FLÙ£©|Õ@÷ou&ů ‚¿LΙÞgù‹'AÒ„6¾Xƾ´î! G“;H*e¾äÔ5 ÷î,áDºÔ(ܶ•øäÉÌæ£cm"Ô†·E³Øã’¸+¡>~¬e îe ±±�ì•$ñË2Tã/MFySÐuwÔ^hj˺¹1ŸRøþß]ü2ßS6'àqFÛõ^’Hl�À«~ä‘SaÔ/t’=øóÕ„é°˜Û76Š[`H}ÉüWó”ã#ËâSW—ÿ´�¿·—åk1‘¯a3 Å3ãð”Þ]ò‰“ƒ¢�ùh‘3cÄC R;ÙTI@Ý»Ó�Ã+IAáåy«³¼±çX»ù,4øYË�Io�zaÚÒã¿ÄëhïwuÓéߌÙ×?a�È4X°é «ó3ùYrÓá™��‚#éÞðVB“Ô}µà"‘Gî)zîk�AKù)ýÇÁèGÎ V¬X6˜~m>…&Íoñ5ÅÐåCêÐÉÄA�r®¥á¯iî8_Z�õø?c/®ÆÐggër§˜ø>˟ΞOǰŠX8¨ƒò�‘Ø—ûÂxþË«è5OHºŽ76¹‰ÑG¨Á§� >\H9û/™¼�ҤѾ® rmü7Oã�ãXÓwJŸUËߺ&b�,¡ah"xÖ-‚['Té¸~?EB2çÂãâB6©VÀTÇw%~M*óÈ–39Ów„´O!Å*Uñ—BWƒÚÑjܽÆÊóuÕàUWÊ_¬cš¶£€ z£Nï¶cp“ ëØ?òb3H/5 díÕ)èoýôÍ'ƒ3  [' õ %Ç•3Ë�¿vv4î ]yž�k—ÁÂí£È8K“®;…s÷«Ùƒl¦e�e2+gDÛÖ¡ìÄGO 1=MJ;XÊ×Ëì¿kÎô.fvãxËÝnà[¹� ˆ]¦{ëáØÀ*œçMnžÑ¬j›:�Ê<Áb¼¿âÉ\3˜·Ð�>è±(•œbAëc«`ñÒBédOÇ߸¯ô~ÐúȶjJñ¥N•lãQXÑÖÄ HÙP_ål:â³]�˜S^ 3©¯ÒçÒ´üŽ=ò¢�RÞPE Ì2îaØç2Ê>ð’ÎoŽÀ+aTtþŠMN€?'éþÑ4î°AŸIßÀVïÞSº7¨@µ›ÆØ¯ çoèk\&úÝ#çG«À‘Šy‡c£±·«ýGÍá[ÛÐÅê-_Y0“ÿ~c?ý÷û#›pG�”>]æw-þƒçJO£Î*û²5Í.$ð@„v µ:¿bÏÎ4°C>[ ¾†þhd{»õ˜ó¦™ô‘b¡º(œ/k{ 1.ÉËÓMƒéXÝ\z>­‰æ|Žcr3£Ã?Wì¯:ƒ*¦K˜Ï¤4šöçÐÈmM#—ÙbT;»™ñåXÑ’3•s¹7�rämµœª–ñµ÷³ª¡•4'�á] éÑä?¬}•#øÓ—_óˆ{^…’í\ŽBOók^er æÏŸsä^Òåh:·¼[l…M£«v‚ú¹ç˜!¡Æ÷û­¡¡¥µ¤Ór‚RÌHºI‰¼‚%¸GC³`žW Ä,ÿŠß ÑÝæï¤qÅ‹ÊmÆúåöüow¬ÜœÆZÒ¢(,õ0ï°w7ÜÞöÄäÛ‘ôÇ”ƒëQ~é®LDå7ïÆ<èët‚ã¨Ü,üóq?íéÚ@êKfBä¼)�Ôs�àçÔ­ŸÈEŸö`ý±ÅÔ}¨£g¡¾}:1=Xí-ÂX…Ûï.@n¬"te§qÇBô T»Ž +–àãóYÔè?b5Ù L/2 [âåL¢Þ…N�ºDsªGUvä´á%÷>ÿû¼#V8Ò½óø?7˜U¯ h‰Î¦Íߦƒn‡¤½ÜI& w‚ҳ·Ñ¿íÕì¢Ì.6¹Ôœ4õ§ X›D™Eçs~¶ˆ(ç�%ÙãA ­–Š·ûÆ¡»»=,^éBßSìáÉ$3´HõáŒkùÿ®y‚FÊÜ*¢‚çâœØâ§V°+ý,Y|�}>½Ÿ-Ÿ �,+.�C�g akèmâÖÌ"çÈ |ÖšH‡Úç€zp8N(8¼¬Ý(ÎB‹rÛ™·}9 O¦ÄöÓ,Ù§lÄ91\ºêu8ä"Å\Š¿ðúº|{‰6Ô”þ…­ÅÖpåÏm4\‘U1·Xû®Çlò—h¦'ñšÙ?ý‡±KgÁžÞ°Iï#öÖ®¦øßË(/ã/ûT>^ž%û—ƒä{Y±¢þÔ¶ðùj:‡ÿAìzÜ=*�ÿŽGÇ„À�Ÿ’Ô®k �îűÞkñÙè?ì™›l©ÙÊ>@ öRîj2ÐGwFïÂÈ¥‡ðÀì f¾9þ>á)¦î‹ß<›’«öÀ¡¼(>27‹‡‹LŒb%@zŽ$ÉÍ%�¼TflWÃyÊÕþ”ÅD<øm2 Zš2�¿­¸{ý:Ò{êÁ­odš÷–Óû Gðˆ}g/Mœr…ç Ò>×±Px¹—­±úÁŽZ I™o™b ³úï¿c²�Át¥6ù<\Çú–»ÁÊ-wàgá+<8’¡{gJу}Ôqc5\_6ƒÖîT…¡B\ûG�\*©rÝYì̱¡ŽŒƒt÷Ûl(HŽ€e†ìßìü+'-¶ëÂúv²gªã8-'8ó�|ÎÃÑõ½Lí üºî[r´�;Î3qùé|È×·8¥Ø7þ=Båõ¿)ëŒ%Õ:�‡eOÂLd^¥�‡N ­ñ¹ÿ�d–ké²B«àmv%h)\« V”‘þ‹;m @.Ç a‹¸'—u „›ÆR«½4½Ú=÷cÃ[­¡ÛéÆž:Ç ª_ÀYê`\_2ƒÞ&Œ¢!±ÒŸ‘„în:Àݳͽ—hC¢2¿>¤’rކàcáñ vIî}-ÃQy¿ÑóYÇÏGyIw¸Lkˆ¯Ý��öÈ ]#¥r®¦UÑDWY”öûH±¿c‘ÚÿÍ…‰ ¸hâUÞÁr�õª�¢õsÓYls0:þÉ¡ þ™V[ƒÀßS®Åa §Fɱ_˜J™!ƺ‰ÁW8þ¦‰ié†Ã`×k¸Øp‹9úHÃ÷ËX\P�‚"cé?õg8xù4=›:ÜßÇ‘Wy m‰Ã'IÄ&ˆß¶ÑˆÞGyÒ·ƒ®8)(á¡í¹�(=†6uëBQÆVì�gëw¿£™eûh…­%)�º›Ï„æ§öеh'éÏ ƒçÛ…àjÃH’®„þ–ÈškGb=×Xй/�©#äÇõ°§•)ôfÊ[Nz²,x–¢”GWæ��oDˆtÂI=, ªÎÈRö!nyÔ8r{ã!ò‘¿H|iÚDbVÃèÞ«0J2–xÓ¿cKaÚÂSÜ÷ˆx|¤šÈÒÒþcO•D¨—χ ¶,möJ8{ß’ÊÚMi´—:™‰Þæ>‹�£…¿>àåÈ“ S3JåÏ“•Ô:obWU¤è¨x ·H)6>Ô¢µK¢Xoàz»&�îˆIsße H\]í~Ä|‡2±Öì2¹$½f9#9fÍÌ~ÆprM#V4¿Y¾uÿHvDùaÁ„‹ ®à Ι‘üeÛœl_0ìzç†F¡Ê¸Ìù<´ ÃÑiuøï“ûv6ß�å& ÄÂCqúœDÇdëÈov=þ yÅkØ&2ºgI™“ä©2êŠþÞÆ¼>̃eö~”w` ¿ ]š,¶ÿã Òã•eì|X2)o†"‰D¼ãôV.¬B©8àtKD/°Êu Ák¸ äõ“PA)€U©ÈrC�‘tWaåW5²Š 36fW3ßÙ¦©‹Âã Ó¬ñ}ÎK»ÀÛO]�àw%°žuVï±Ct.a sX=Åq‹wêÁ|ÙÇt;ÌÜŒ¯ñºÎc*ÊÌ y¯ ×hýj' �ÿe-}í÷çªý™ï +Jímf.qiÜÜ¢yðyÈ…Âwá�›c+.ÝSO¦œù;bϲÊ7‡(·q?í({Œnî°cÖu(ÿV ô‡ÒPÉr4ÿwæE6§zíHìâ"wzCŠd,'ðäþúÎ ëÙM,’®bNíìûãÿðCZ {¡½‘’§s–›¼À|®1½8YãàSaÞïfÀï Aþým6t2š’^ó÷ªÀǨep²O“Þ®zyšXûT; î¾É’Þ£Ù›XÔrŽæC. Wtµó¸BÑ�m½@Q]ŠJåà¦P:Ó¹žÎûQ¹Ó 6\^E¡úxéþ\Â’•ðºGý‡¾â‹èDœtZ,òÇàê˜÷”m ËÖ]4cÒÃö@�æÑ:�mT^¶‡>¿^Jß�Éd¯5sµR¢ÎºýLèVF–R³ÚJf44·�‘©Ð}9„³¤Óèý–uPf¸˜t_ŽÂé׈O?Ê̻‡çWµ¸Hðg ìcº;¨åó»;ÀÌ×·‘mÉ·9˜Dª"Ù±F€5×ÄMÛZÊÊ뮽EÝ`�#›3ëÞH.èk:ìÛ£M׆õ °­‚Ž÷a�Îoª†³¸i ·|‘ tªàИ"? ÞN´¡jaM·íŒmyÃÞÞØÍVž†³nW½ DkÐï7¾$�WØF—$ºQ8ÌŸn°Ã¾h°i™K˜‚t È·?æ53Ô¡Ku,Þ�_Cž#}w>´Ž{ÜCÝÍ”4E(Ë®�F¯˜TÜ~jû“'gÓÐ'“ÏK®±ŠçÓ¨¸MÖI!8ÏU¤¯—¶Ò;q[ HU¦2ÝìŠ^ ¬éу!jÐól=s„Íû0{Õ¦*6�•ΞÂ^„XRìÒr¾YÐT¤þ!“SÒ¤½¿X±š>ûøS�ô–¶³-7®š”Ô«Ã|ï¹t­r˜%† ðId䯻UAâ½:­Ü”ÆVl°äFóÌÿ_Ú8[…÷Nç6ŒW@}Ûw,%hDöJáå3[Än w>©$WÜ(uK J1ø¾É`ÕëKëûsYΦ[TýÑœz{x™ñOñÕÚ)$y&ž¾×Ÿ¦ÍyzfiÒýè"ÖO=‰ï¤>RnÞ–2·-áP ³Ù÷¸q\i],Å�X!Àñ-‹;òM¼7Ãk¿z¦è£ÏbÉQ±W)nl§]vfÔ¢û�0.äšënc_Èä_7óJúÆÔöð^P5&+_IÒR‹¤Ä^sÚï¡Ï>-@Oá¯Lè·X$õãE7 ­ŸÊþ¿b§,k(aù-�ÿ¾˜]ñ©¥¾ƒ)Ô®ý’’›ùúi P¨´†ÍùÑÃ-Í\Ïjj>0?áòEGƓފe4Mi+x'vðÍç¹ìוøàº ó’ýA>\akWcÓ�–€w‹_0MúTÌub‹—±�«�ç#™»U ´–eÝRàöÖ,ºê@w2B©´Íl£o2g½w쇢}r^F~Ï@ÎЀl‡£àIŽÜÝ S~Á7_äÌýÒ|(rÍA™µÓiKÉ;öRêEÏZfb´ê¾Øù'¿ó¦í^h,v…4ö…âVUo€šT¢ìÜrWñøkd¼6$Ø6ã:°¯pãžÈáÉÇûId dö¸Ðés�Ò£…L¦HùàF�@v}^ [ ÂïäR9�£àÏhdBë¹Ì>'úùCz5M¨¨£ÛD3êŸ{¢‡ “8íî÷øên INÊ¡yë6Ãùíª “{žW×Úr&fŸÆ®zއoïmñ™y«ïøÌ~?_>I­xéq2 ¾ÙÆÛºN2}=A« Ðбc�ù”MœQ†…Õ Véû9xg_,žÊß»‰á’MìÆ¹fœw°‡F›�U£^öÓó2I‰©Ð‡Âp|¥#˜Ê‹Ð^³|”Ý_Ç hÒ•LN_¦t§žtÉß1>wB—ÆGt3:fNzüT ~öï€K)ñ$ó'ÚÖ“ñ[e hœŠ1ÅkpšK½ãh_WÓV�¾Ñµ'™Þ;°s7dàëÝzµ|Š©ZÏö¾¼Í÷¾8lúüÓ¨îþ;¦GÐD·Ã´lÀ²eøFëû0-³Ÿ…[͆¶ÝQPý3 LÇ�­¨½w‘Ö'˜’]ék¶k| ¾’“ P›gx†>ߪE§oal#Z€ô,I–¢®ÁÞv�©¸ âWn©lPq˨�¾ì$·nO8¹ñ1ô]ÙO?ïèÀháVöxý3œ±¤"·¾ˆÒããÀ&¾Í'ºaŠÇ S=Þ šê‘Ü©ß`µs==,‚G}èŸÀ–¾ã/f*“îú% xE—Æ4v‘°‰ ½ü ˆ)�KàÚÝf W™@‹'Vܾ0Æ]±©©ùð3`Œé«šAüÒwíæBu¤N¶”€»†Ž©ÿâ•ðyF~‹5«èTËÜåe+V¼€oNžôåÀ4Ó«? ÌCÜtF½hEšA1,›ȶi¦ÂÌàø4¦Œ–$èP™æÌ ‡S+n Öãêþf&–;‰ü„ŸÑÉ&銳+xÏýdûJ\ó~@ýõ9à©\MŸ‚h({t�óƒßÏÀéÂ|¶öŠ%tÙ €ƒåvNÆW‡ýQÛÉìEÒ³ëˆÊ’úX5hãàL°#•~»Î«ïf‹Ÿ�®Lö!ñc)ðe|(;ó¥™o¹kTž¿ñ ©<¶fºÇ{MÞÌ^N©rî�·M£"QÛ‹§j›îÓÈ…üÏ¢=Ï8…¾ `½x+´vOäÖM»ÂµéHW\±[ ²`{p7]}”öµ>g ZÓpy|6­®P/‹¥¹ß’IîýiH°½aRF¢¦ßóÄÁÝ\‰vxC.¶whJë”ëU‡¯Vl0{=ôüyÉ~zðk)ÒË9Ý´D/ÆS`Å€†9wܶ—ïýDÓ=¢Ø#¹8d¡¤YÞ�“ø—lô¾«\‰Š?z&˜�ѶÕ7tž¾N¢ŽÎ4XóáÇ—éÌ÷’ é˜=CíÁ05ï2‹VYF*&'Iwìøfä‡ê;-QºNÀôJ¸9×µÒŒƒí¸wlpç*f\݃1‚Ù�Çáƒg,SnÓ†wSâ�µ7+Q¥\™øl‚RÇF¶k½9)¯½Ì¢6kB¢ÿ¬3ÿ…ûž 3Eûå=ø²K…²ÝÂ_%JòYLß]ö‹ºãxuIôQU$åqªøç¶2iŒ¸=rc2{_iÉ‚ûá¡z…Š;šv”›FÙ9!\KÏÍWû±Ö”¹ø´?�ÿù& v¼R ¢S±`sÚ6ùýOÁyGõôÿq\¥½TJSJ¢RZhÜ÷ëÓ™Ñ�¢4m‘•Õ”¦–JCE´$äs߯OE)ò¥”d$ZfYÅÏïÿ{î½çžç}>Ïsî¹Ôl¼?÷˜1’™ tiðŠÇ‚8ÎÞý8 ûé¿�hÀO!^¢�6m»Žê~çp2Mó¯âÖw�èþUÜ}z¶@óÁD²Õj3Íï,™j´d�$#*©Òƒ]-­·$†ýüýú¬NfC cYÃSd´Ý¼JÊHÀÚ\øô»ôFçÐé[¾2G7hðŽÔï@K}~^zútú&‡×hƒçê½pä„$V~M¥«åsñ‰½0šjeƒå,+–- #‡�™IçtT –`×l8Es¾Ag`>5ÃŽ� àûzJåψ�ù°"�Hì%!|Œ5£h‹½°NjXW䀦CžhÒý�Ýç_⥒ÔyB†ôóA‹¯¾ì,€(µ�hf�4ÒoÎÜ!�9˜�þUß�£›JÝf5Kni„*8hw\=ÄmGßp_w§£ðæp^µ¦ì~‰«oúÒ�·ß€[s$üæ8²ŸNWÓgìÁû`}ô!¯ç`„V7Û×vt�¿ÄŽ .ÑVf9½ÍäsnþµâÄ­�F˜æ •Ü�¬dõ¨ÝÛv(Ý` NÞð`?*6=Àð7‘Tâ×r(V4w­ûÄóƒ#àÁ$8á�@ÖõOÃë½—ð+ÉûëìK/¬ÄˆC=8k‰ç®ÌþCÍ´³}�º>©�ãË↗çð©TÔ9€üÍtrû²üðØE­l¿ÑŽé6 ¢gF“»®’´µ!¬X`**é0ª§³¹sï¶““¤©þ4l-ʀ̿¼„S89Mh”ütÞ·Û[ÁêcÆ´³xv §¨'ºMBtÙÍ4&t—#Ñ º†‹OÞHK{[ûŸr-n&Ñh“mÓpúÍrÐXe¿¶xcˆTÖ­7I�™/ ‘?ò_ÐnM.,¬ÅëGŽÐ¯OÒ_~f˜xñ/#Ê¥¾$€Þù>)BÁdº˺˜[òô§��‹ àf«ïyñaÍäÐ~…�vΦ'°Ly*µ°I†Ài–TÛCòþ…´õ^ô®Q0ù|î Ñ:Ú ›]É£Ûüà¶m†~ž‹·¦ú’?—µ1qý~”«ä3Þºmg‘+tìë9p)aóÅM«Bïã…�ÁûÄ„GÁ|ê1 †Ã'‘ï@)Ms³B“ø)0çíTÍÁîCS!Ò!Ò—aöÙA艿FT¹,ÖmAÛg{qEîP^ÎvuhبSþíã«›ºè Q9Þ¢¶ H\³a¿‡ð�äåµ$u|^ªé‚Â`k­É».pƒ}é¢Bn^F�‰tN#lß´ of<Á{eÔû…,G5ܾfпƋéAK}j!||å�2ëfÉ5ÜrzdléÀ ðµ1yЧƒŸí¿’wZ'A×& "Öà—3× ñ�qß?H U7á•:sêQ\=ëm`Àó:;o®šlގ뿘‚ìòÅ#šlòË…ÍÏ�î›Û³‡I®D=ýöB¶ R§cˆP´‘…ѽ¦ëèñYYXþŒ´èîu¼g{…ü–Û ¯t=9³ À`µò Ðå_XÜ÷¥™„ÿ–!¯?–€Aé†ÿî¤F‹Éy5kàFÿ¥p�ú—ß—fhµ-Eÿ�§ÙÁýõ4FAÖ™î‚&× 8¾Fš³1щ 1Õà­ï_ÀÆ«*›Á�Ðp�¾ºìJ¨œgq?u^ WW ÓÇZ¢–±«¤¡³ùüíâLÍÄ€H1 ‹æð^è…3fO¢É3é0ª¼m ïè|c8õEƒÍ?0…C¥COÒu4Œ9MÓ¡_c'zÞÆÜìpô^iIÝ!áÇÐ2Bk‰1œ ›‚îþ£äòÚrK«¸Nü(›‡/cvbºüýVN« ±Á ¿ÉÑÎ&ZÓÈ¥IrD�ÍAÉO0¸Õ ó–œg2n}¦òƒ ï´˜ì‰ˆ!û¼ÈG£!j}é"ÓvyNw-Eííì#ÛZÐÞ)Kä¤À7i‚È]Õöj£ì#£3”8×Oåí˜QŠV ò†ü·�Õô ˜›5‚ N÷‰œÃ88TMTÝ@ϧãD¹ÃFÎ"—b†§*JuÒ• •ibÀsMÄ€˜õÄùü$ÎÖàTõ¦ÃÑ¢;dH;EÅ‘mÏ`D¾ï¬\6>J/agZ$¡Ú¾1d#SÀ]A‹f3˜ø¹#Oð¸®.w¸ƒ�7phÖc¼ª ¯`¢ð²Üî„‹oBî±íPØ(�*ýà¿}’†ÔÍ&»ƒO�ÖsÒök!Ý9ÁÇ1“0"õ^8¶0Œ ñÍ€þòhº'!ï5-Í?* ðdg§É]æZÛ~âfÿ“îø²N_: £e¢ðüJ^úb‚®QW€>Eö¶�Cá8P6n£…Î1tée9º{å"Î4ãU •09¯ð�ÇnRâa›—�“k®bid5õñƒ!ÇËÐÙÆ>hûIfÏ ¦¡£‘0çëRí~K_ù�Ú¢rX‘pÊâ ŸÙTê«^„êUGéC¿ŸLn÷Z|oYNƒ�ax¢Žü𵄂ö^˜o®@Î,ÊÃäŠO§ˆÓº²²‹ó’šºÅ“VïߤÚ}*6¯E] Wº€³î—#LÝõ‰½T`Å,N`4вá÷ðEài8Aö _¬XÔ I­”¦:k£Çô¯P?ùœùdcI'“òÀßëxOšã‹zÆ5§e¶­dTV†ZÊùvx Ù²Î!½`;¤Í»¸ã1vm Í¡@Âèf4[/³ÔÕyƒöʼ7<’îïí±ôÓ9 Y¤D7ß’ãȽ´‚ƒÿ<½óñJ¨9F1)…™)Ì3Òí#Oþ¼Àô¸‹ ³M•>=½Îf@tÜE<࣠­²,ìžû/ÓÑ|�ìiD%óÓèü#‹‹ ä®¬íMº_ëTº}'ñ�^¹w6gvËY E®©3ö±_˜ö›V>]άñŽ„_¶¦¥ÛB¬œ ñlÖ8”þ�Õš(¸2 ŽeOňðxE��š¶sìäîGШ‚zöZô,�*`·A;é[ö‰5š¸ŠóóÄY—R„¤[è»wˆŽG˜ûˆŸút^Aö�9ä‹Á× ØÿüÓåŽ|2;FûÒ8÷˜%T7w-KÂþ/Šœw;f0"~›©4ÿ_8u)¯×4�†õB6 sŽéù3ET²p)áoiÆÉ÷NÔ?ì.uÒÆ�“\zVP�ç_…ϧa®O!šsÞüW¯™ygi…ÇeÓBce]öé› Ì�ƒÂDËð3‘Ñ?‹VóÂaŽxÆK¬Â¸¦D˜u%›lú~•J}yÃ_æ2+÷~ùíBn|1‡‹¼ÀTT"?fÒ¦s™¸w`�öÍ\‡ýð¦Ë V}†eÿ‰ñ|�ÊÀìñÌ¢C>tÝ@9õ|%J„y+!³g,[5D+>ÅGGÿ�±Ø*ˆ²Š‚zž d¥KsÖî8Ig¿e|6ŽïËÊ÷4==:ûâ º³ »A�?¼Äj¿ûHO *¡fz É1T€­‡²áÖïp|°œ½ŸM¾¸} ÉV÷aþê Ú´£|ü§Á™öÔPJ jös%óqòWìxš�2Iþ¸|ÛlÖÝà¹`ú€Nv Â]AÚ L7òJHýu<úÄu&3QÍÉþX�Qÿí„ãùψN†!èÊü88�ŒöÍ–†vàZ?&ó£àg÷z7¬šu¨„¨=Ø"Q·‡„ã¨qR&Ñ9�JÜÏ%U”·Jµ|KÈ÷& /Þ†aUlyQØÏðåÕÀÜÊZ¢ÐÝK_Eá'ÑëL™”$óê w]¯@£}÷QnØ—H‹Ë“e«-QñΘö1™vüä9—ó™Cæ7YÃgôÎýDŽ|GÁU癇BƒŒI¾+hìò·*c|з”&l}G#�Ó[Æÿ®qìy ¿ÿ[Þ �¿Gè.²“ºá]ó¸An»[ãž·%ì¿ ˜o÷ˆ<ø 8lÐÄÄwµÐ¢—P¦»�Ñ=8…Ýõw>jŒÂЭcÄpË,FwE+ºÞ€¥/Ò0*Ú+ob„ºD}^Ž’|c´9�ͬdq¢<˜j–ç2YžÆÿPCz.s°ˆŸj‡mѧ­ušöÃC>´‰ð#_®NÝ ÆÔµ‰Í»¡AûÛw“î®Ð»D $šëÏ„Õpð¥eí É잘Z_7sªPz›¨É˜`çœÕä]éZ¬¯ÓFáé1xUù,¼€ç½.1ûƒÿÒ§Œ°Ê¼f�Iº{VL“;‹&ïè¦U2çþI VႪl÷ÃSx·;þ¦“òÝtñ‘s˜§±‹¨�Ëá’c‰lÈ\†däVçåaä¨B5¶É\£AÑpgÃä…öCõ@,¶ ”À_u>¬øKê3Y²öi!))�B«±óTþÆ4¸êTCZ$k©]{8ÕL²Á AÆ ² o7½…P§ø7•Ùs�–QÿÙˆžòð`Éf´ÿ~û·X1R§â¹gnôðfT5m�Còú䓽Ñ -ÀÌ[ó e|3Ù\”I�íN‚·ð2Òùz*“&Jï-Á–Y~P¦·çÛ_eDû@±&ùG°ÉIå’G,´»*é»›'àÄO¬+¸MŽð‰àéÅæ˜@p”ÓFSÌ7“Ñ#ÚXC\5“|‹€{ã³An?R¤áâØÝàÒ*¦xÊØôÃÀþ°=É/²%�¥¢äGªþËÿ¾FܬF˜¿1YÏ}(èFߪRË‹g虚¤¤« ë5ObÈmT>u¾\c/­Ë¦u°cIñž·¶*¢›X: M;Á]›]Ê®x"™¼¹&Æ­oZÌúj6y�6J¥‰Ò¼{ T²ý*£(ÛŠ…iÁôk«¦� ÷| \`t—DàõóË0ªYÕüÙ9Þ*Pöئÿé¦]IRøk¹óVU}®î`þ®Æ­5Í#¹—¨ÑÿøË%Õ"-–WDBåKÿx4?•õþþŒúu ÁîÈVöØ®M´ÆÖ‘ Écq~Ro|£l’ƒÓ¡zâ ûWL Å‹ù!ؾ„v¾ˆ$²»íñUËtLV¬ƒÞMuÄ[ch¬!6Eê)ŒëÎÁƲÇ,߇@"š+ –O·c£¥(oÝ´bÂñêÀÉ׳ÀåÆv2Sî »Ÿ?—†«(²ÏkÊè„ñ>’S’ŽáΠÛ]XݯKž‘—Hv°ù5ûú˜xz¾c.ð™Â e„˜Ã‡bhެ i3Ä®8–sEqéÊB˜Q¿ˆæ†k‚g‰'¬ î¢?Ã\Éå÷[ɃW=4Qã*þ0+ «æ–’± ’$ÌÉÌïNrµ_ÿ!!�ÐÔ>F¬Ô¡ô^ Ž­ sŽ[c9n†ñ¥çÅÂ×î~úµIÖ;¬Á²ÉŒcIÝfx–:-£Ñ›“!ž$Áºà5Ï”]8bÁ–äâ»ÇKð°â0.¢…ùÌB`ÓÏ›Ôy(Èw„t›†ýÛ¿‡hâÚ’û©ZóÄÐ;´‚|1†W*âÑºßˆè ©àmëõ¨¢A-Ò PôõÔlÔO 4ˇô8Há^–8²wUïÃÒ[±dY´&ô®-%¿Ž’�m1äPÏ X3ã ½c¸—^2´FGÃ8�ì#tqO8á{’C=Ùp�¸b 3óó,l�æÒÔw£4Ø3�|4ˆ%®£æTý´ϬÁ@œ‹RÅÄÑXÞ~åû×{ßYµ_gþZ/¬„|~LJ[-ÕLÞÕc�tjØh�À`=]¢7í¥œ%1~b°Ê$™|îHb[íW“̓Z8·° §_WCÝ…©ôB§ Ã[›gõÿ#/Ÿ±:Ó‡IƒŒ w™xñûõ‰œW�çòÇÞ!^®DC}_r=N�”ÏU¦nµ"ÐÖx�´¬C©cb¸I5€\Þp [6ˆÀ@{Æþ~Nô| 1y"å%šÈ³µ=ôí{eøêû±]¢ÊnˆÑƒãöè¢LÕç¡��†c'®Píûƒ¤eé.Tæ­$G„[q®ì2ûN Ùª©!»á â —Ó"謲ì�øU–F�ÓéÒóhŠ»91«…¨2²öö>p{k…øP~p1™~÷$æ?¾Œw^…Þ�–(‘h §Cq Ä 6þ9K¶éß&?-õÆïSY•éðK"õöƒõï øäw]M„W7GY~‘|V©HTæág%FGvþ'°‘òÛÙ¡ Û W6¤YŽ—Îþm·Ìo®}@þ,ÜAf<Í'ú#×éÄÊ|zó¹¾ aá ð±´�¨é¥ÚÜJtTïBþz5ˆÌ\KW«LGÞÃrî¾$c,NuCMMÛÞ“š�ûèŽÈÕxBéÒ?}€Æ»ûƒŠ&rþòuZXÏœ¹³ ÔBq¿OÓUˆŒÀî{앚&Ò;Åh'k€çÀhyi…iOå@õÚÆÊÔ†}ìr'"iÙ2,Êò`ÿKJs¹M˜?ç+q�SÂïRÛ xË6Ÿ)¤�%°hú)ð)’†Q£ÝX6I”,ÌÀ C�ê+>¤Ïœ¸8C5ûÞ�Ä-7CIø«½h´g Ö´i²žBáXkšF?Icf¿˜>•'ѺÆÿœ†äsŠè—o„#!e¸îüœ¯#Í%5¤pd± VÄfÓ1ª>ð€nüŽcß•Ðÿ£œÙãͽ‡³¯tt7…ÿ~^ <… 7ÿ»eµ•ºwlÁÚÛ[0î…69st É-þÀdVé‘wÑ[Ðèuæ”#ûq`E¥]½†)+h~ÐF{OõÓz>.-ݘÁ]uý>±ý¼»6%²JQOÉÑ™Ë0fžÔf™“@÷½X6ð‰vqˆóuKø•A·çS³¿Iß ~Þ-ç[d½�¶,ŠG™Ç|#Ù0>‚©mî8£ü�üm�±Õ¨m@Š…AÓ|rN] N,~›¯W#Jü ncºìß{ª4â'’H× á< +¿µ ç½*2·¥�Yó#V=«`—iF�¨_ÓQ;ù*1Z‘Ç,+9…ŸÏ\ …ܵPë‚Onˆƒ ¦;�9¹‘bë%*\ïH§°Ÿñký tš¹ŽŸ{�¯;îÁP�]¥aCÿ%`âž vxãÝŸEØ$ÙD¶m>†K“Šéû¨.º¨â,L=-ÀÓ/»Oƒ‹’q›JٺņîyþŠ,ûœ ǹö QæA¥¦Sn�<:H áF¥dÓø,hF~9ça}‡]l5@ºÞí¤ò“Ë(w5ðWëÁ¥¯êdSU½‚�Rà¢ëgÙq®vÌè!ECšTƶ€ÄµžDÎÏ¿øëÀúÒ ÒVÃÆ)~d`c+ä=ëÛ�³(36‡™|1f&sè¢Dèz±šh0•=ÖGöÖ‚‡1å(1ß�ÖN¬åŠ�ˆãÇÞ‹øðÕ1zíÅTð�ô‡·e#¬ÙÂkèÿ“øß:‰q)î`4ÀÖ Û€ŽÜók#vÉs16{”Û¹aUÌ\Ê’ã ÁÁ³ãä‰Ê¿l˜ àå2_h>[ÆŒìÎ�$çLRð<‹>&�¯ÏâÎÜdzô�"Û¯YÞÁ…xQº¶xÀ¯ä}lGŠ.ç•ÖŽwK8,¦öH¥Dx¿þ¦ÐüZé[¬ÆM.“/¯¬™Âijœ�÷ëáe  o¯¦>;C÷Ü5ga0 ë¡.„QГ¥íÌ3jÚª•»nÀM‚(¾4|oÁï¯È’U^à¦'ôµ“"ÞQë#?.€¶}ëæu�H\.&Åfû‰¯;/äÑ=b³û=ל¤VA+Éóì#ôÖ•v( ¸�«4zÀeÏrVš©Â8v9Ú29è>7óç8áåiÂB½3h3ïºÏ…ßÖéÕF01þ… ïû©È35Þ¶±Nföë p81 TçÂ7½`\ËUŒðÀi?×Áîµ|p·Y›cèÿ|oÜ·x¨¢Í›fðŠõKõÃ…[ð¸¥Uû.Bì*8í?…Úðiïh�.‡)�FHçŠR˜�`�?bŠÙ™Ša�ÞŠÇÝtñ�ë{:³ï=ùÞ]€¢wïàåÙÞ¸Õ] •Â-Aëñâ&{¾FÒM~ûñÖi ÞýïÓ ñ¼3T˜�Í[Xå= CóòD/šÿ¹žq3ç'\°¯¥K k™ü¾spýG Ê&»2Ó>J“E;Ìßé‹¿¥(Œœ:Âj'¿g_­X�ÿ©aU¶ˆ\4&ÓÔœá]Dƒ¹¾ø9ü\œÁÞ#Fœøk1Ðó ›0­ÛC¾u`›&¯V¸Ò-ÝÍD?wÅçÙÂ�ô'ÆRÜÍŽîÀEœñXØ qòíÁ…ò<6Öûûré”à°Û~/-럺Gäue 6ÅÎq8óö¦+!&S£ñ`ÐpùéÈž·¯ÀÉóˆÏðn‰Õ å]X¡† H–Bã àë¯LéúHŸ}ú Ù“7ÈŒÌ9ÔˆßÎ5Ãvî/RÔ"Æ{o1CÃ,a] 4¿üJ2ñÃÏk+‘—}ÚÒŽDÓn6ô’ƒ«§qÆþS„hÁ¥×V  ñÁ%`ðÔS¯XƒnG Þ®Íö¡(�Q³É�˜æô—÷þ$Çúšñà‹U(鸹OCáeCtyÉZqì{by9ÜF”späÕnú`¢Jùãi|nº¥ÅØK|ñ~*CÔ8 ¸Tÿˆ «U¢hŸÖ"uC…Ö‡T¡ÅcsXäwÜׯÒ?ß(®Ç2ÞÊ:‡éQ ´/î8=uƒðÙú êûÌ"ô»ç¹e&^}D¢7_…y4éšØE–¥×úèË%ÓP¼² rÏ­„ä¡IÖSD’¾šRIÖK¡U—$Ö×›BÝ¯ÅØ":@¬+¦ç‡ÿ9鎋ð¶õ ›Ô‘‰…ÍáT \Ÿi·jÅ7žT0—·cªaw›(X[¶Â‡cÓðEp Ʀr°nÕk G´ß Óe¶Ñé_W�®cFû¦YJÚºA™Œ$¼©.ÁÄ«ÝTÞe1=óÉŽ÷ð×TüT_‹‡Ö» øÁÛ`VY¾½dî¹í‡Ç¢Iì–öYôcÀQxvåtžYB^%-~ôã÷0YOhæQE0Ț›rK�#dµõ³?€ÔÉArÀ…ŸcùS¼É X»"ŸC¨»+X�uE¦´õ"¨Å÷Óq×d"h8ÄÚÆùô’õ\z�Îø;�už^lÙŸp–½¥¿¦k0ü“†´¦¤õO4Áس*#¿€÷gé|xQ4W˜Ÿ$­éhù0†ú]¢Aájô­�<^<Mod®6v�ÂOYjT$LÇ�¹×ÁÃóB`CÀ,øy“¢Äõdn±„PK'èRPAæÇe8?K—‡yq­àKlcXúq‹”‡-Äß;“¡ðp:Ìl%Ë�íaZÆc�©S± ]•Á òœ/Åß-ËöÃ3•ñZó½!›Ã’€ôTÃÖ}&X–ÏJnýO|­Ps¤Æ·18îx†{;*U!(þ ]´}#ž“¼ ÁU¸ào S¾±‘«Üº“˽NBOai�8\ü–KDl!`þ óÅSà€¾.Ķܯ™ÕøØø0®H›Î !¥Òka¬M£]+1qv›²Æ¶ie0*‘™+»1.¨_W}ð•=ãÆÎYâ ëÇÉœê½Ü¾Z|×ü—Õûêû¢pJ¶1Ê9‡6wá ®2üð�Dž”!<—A¥båå ñVc´åyýÈ^ FÎé°L{%1׆ù'láØ5o8»FÛ!Ü«¥î›¢¬v*n+e¼¯¡‰ª6Êv?"Kg÷Ã¥£¥ôøh;Î&èÄî"j±ß,”¢sè¼u³Û ðõsRUÑ‹é{£±)¦›\Ô”EÛ$P0¼K¥ƒÿ½;§°òã3vap$ú5ðñvÀ /Õ¢oü©”oñ8 rû·UóáØŽ&츯ÀãîLdÚëÑü¡üî}I&J°ñ‰4‡—€™ºŸ_t{A–ýÝ£G7« kHšE…ÂãðK =I9?Ò?ãÍYE�±çÈùÝ›GÖ—Ð,'YU#ew8fƒ;, \×€£ûm ÿnã0çú&Òñ ߸«âÎI)Îs—P:Ó†K+ûóaHç!q[ò‰Hyñ“!EyŽ.W�÷zE&“ÉDÅj5xé—E–Œß#Ú#5¸Eë?”S…O~ã�êZ|ƒ_é4ÅT½"¬·Òò†M¿�»Ö…¢tÈW¸¥g A|a°°û-•ÛæF\ß©CÒqY&ygN¯"zûøéo_yP9¢E#Vyqïz&9J ;@\¿5iK£]zË¡*ÌÞ¼åzŠß`?-n$‰o @ôØrX×þ’z½xJ$S·£r»¹th˜lØöÖÚà�ËùÔêA#£¾ï8^ºš'•µÈîJ+j¦,œÑm0ö­�Þü�X&ÇáÀÝ^’=÷&)Þaþ�™ƒlØó â´ÎÏ΋´ì½oÌùµ$¿/á#9Õ\Yù�ó‚QZNV­7'êA)TWr=†Îâ� Uãù¨Ô“Ä®1ª¿ØÙ ój«æãÚ�ÛV?Iº �`aî-²cßy®’O2ïçãŸÓ]–›àñ<Ò n›î0†B”,·^Ù�°øø/W©µ!|¼+ŸlÀI{)Œ;‰ñ o\G�ç·±;Ùk(=NæþЄgEþõAµO~ÇO? }ÂüTuGRKçƒ'ˆÿ�(æ]æv�yt=�yÒ�k³±¯U :_�s: û¹,¸Õ-ÆCå<üð"äÓ8ì÷æ&°®NþçN‚pa¾|¨ÛD:~¦…*I°Åú ˜ÄZÀ¶ÉdXÌI‹õž�B›@º@ò"�åv•;'Hùf ïl+YY›lš#á BeŽ�—9‹Ó[ó/~¤ÓùÂ0ÃL”âϱ¹-a8³õÌ’ÈÅžÜB¨uy�_åCêYh¼%Ͷ[xÃ�›¦L€t;!*íX·! õÑk¸ ÅåR§+Sz·b©ú& e‡<†ˆÁj‹XÜßG›•²€ÿ˜"t_Óƒ¼o.ØèäJk£Ð0TˆwqAhœÅam. Q¦ Si#ï6Å*à�X–ÑmâÀ„Œ'ˆïq¡mSÉÖ5)�ðÒÌŠ“iú%8ò¸l�Z±þZ¹4ì1‰þT¡Ý�}¸w)ÊuÁÎîh0úCñky=îzs„º pêY@æ…¯ä¨æ#ˆíi¤‹uœ 9R tÈ8‘q˜FÇÖÕ3™IY _…çáZ º?íÛ¿m 'šÑÀ󂼜3Ïaìqc°DE~%Q —j´Ï!mI �`aGxbßñ·^ 1¼)Âsý.ÃS›1½¸¡xîáÒ´h·a!ŠÛOã�­60–ÅÛ"ûɪ•=d–~¸eP¾+´-^ßrÕ±~â|±+D�'Ï ;Ë–Jœ‚�"�pÚ¶†µ&û¡ç�3‘"6|âó>ã ÕéQ£Ïß¼au„ãTÞgzïOûßæµ«|þÆ�ÏRJg¼½È~Û³#/oƒêø,Z|]ß¹½"Ïs�JÃFµ�LVp5ûÌo<9n‚ƒÅ<¦áÝÑF*Ñ J¦0¬zý5ªÄO?Ñ&ʯ¦bRP4\¼UK&ôjÙ¼�yè&ðšþ–v„y¯i_V æÊ=fê-Â…ŠqVçæ?«>æþó›õ²1�wŠÂ! ʤKó%ô˜L¡ŠÇöâ–Õ½ðÓù;íøeO Í}‰Sm6øk8ÑœY2¸£âýÙ½?–”PãMÉÐ$÷&b‰ì”$p-•"wùߘ�ßMeÍmÐqò ùâ?"àâ{\J˜E¾�Í&-ÿŽŸß¹†Ü—SI.ÙgyŽ&„ó“çìEÐG³)^FM {d^$ùÏ@ ^•MÐ3áÒ`Ñìˆ!r'˜ø}®Ôi„ÝOçA÷ÉÏ4SìRÍr¶oy![›Š“W4qƒØ\pHN‚q {üþèüÇ�Œ™’°(E ~ÖòAï¸#(¯\N O¨£jÑ/bc0JÓÿídß}ZôNýO”’{Fš²ñÀ•M‹OÒP ¤å¬fÏÉ'5ÿ˜÷¸¸Âm“ɆåkÐnëNò\Rõu¤¡R]ˆ†�Ã0…(œ«“‰~Ï¡ÁÛS¢�QÕº AŸ~mKçꜰƒ•âÿ±Ny«è�2ò|×EœråÙôô3ü÷8èËÉá*ŸcÈlûÿ¿>¶Ñr+YÜ8²ÇúÃáˆøE¶sI<îH¤»ÍnÐmšgÑÝÅO(èà§òDbäé æ‡sÉÄ6Iºªi€xìï#¡óÿ#1ãiÜŸÖ™TÖs.þr½Oï9=¼¡*Š•£€�!�÷lÁÿ¢ñpZðŸÁ]AShçQ€)Kؼûoiðý¥øø5âÑ-—X¯K™˜ßœ€;¶ á9i;:[ °"Ð.ÞTC›PZ¥KŠM}I™Ý)R¬TLs#v’޼xvòlvbÙœÖ0~©…T´�B~\öq& �Cg›$H.»‚ÏŸÕS‡ kѹ?ǼãÈqº&˜Žö±Ü°ã­¤ct1n¸«C¾gYàè»zº°�nÝÉ’oIï©ÛäRfÓN3”ÍXÜ[·aHæôÍÁ*Q}˜Ç;€{õ] àÞ!ðpƒ�vÀí³ëI惛ð4w1eýlá÷í8¬9JþÔt0î:&Tì^ùúÂËÜCñù‹P$%ÄŒÔùQÑã•À¿ï­e3ARD Sì³áÍ~ Ð’{Bõ#÷ÓÖpü]Æ>]lH_¹ÞÁÖÞL—º¨.x@C{o1‹ù@›CÁÊ¢Í^¥ÿ¯�¨"ßDDoKQÝñ ìë� ÜXÿú#÷^2þkµèñ a°Jï,úàŽ}ÃlŸÂ)x•�ŠÖ]‘°vÚZê'aG•Ýlé=·„_ÄIÞ�¤® ÐS:Fù–”1¯_6P•ò8ndÊ’Q;Î�xÃß�ÕÐbës�`Ïùu/÷�ecÚ×@V©å4°ê«ÁGXš>[�K‹ö`‘DJ�°-ò˜5Í c²1"_5œ"1ÈhÉ”Î�…ÿ‘ŒôóP;ฟ œ©Ì~MÅÓÞ’œ}1tb� =ÿ·ŽØ‡adíÍ(~Ì.žZcÉC;9*ñ¦SN)™et×V¼½¤Žµ[»ŠZ3Ýìì¹n4ÖÊ“…ÅŽ8a{?ä²li:�xrƒœP Ä€SiòêÒ�Cãl&÷x±¸b•…é.aTÖ9œVú‹‚�ßTÖAýÛ´z¶k£¥"ð­·�ê~½F´;ßÒÁ!:g•=:ã3ÝuoÛKt@Í´ˆu_ÙÈx©£�˜ä…ó@ÖΖ$S• õ8&QÏœ™"…ÎÍgÈ…‹atT©�KÄ�ŒÔ“´Ùï•IaOš{s+þøƒ�õlñb=d/óƒÊˆ&TKà¬#SqïHs^} 1(zDå_òóöÑ\ðØ_Ë£é`—›( ÷²4$r&™¯¼̓¾“û'M Rb>¤ÿÚ Ú»§�Á%ujعŒªæ…aÕp>]`‹ „g@£h ª&.?V’‡ ÎNð)Ã’ÌÍćöH-ï"˜RøÓ>œ“‡—ÏmX¡�kɼ¤LRæ§�¹^óáë“l0ØgŒÛ˲0¸¹‚8|˜‚7ä0mÝ�1ø K+,SC´ð¦h¶¥šÒ:X”d�§ý(ÜT€©×ÂÀãÑ>üÕЀ…W/‡¯›þu‰%u<Â�××h`X—YYkÙýd„H„¿³®^ ·_&BïQ R”J¥�­À#Û©eˆ.ö¿E2sQ"så•–F•’KVïè²MÇè‹�tKD ¹¿ï;QÙ‹ëï$€ÚÒf¨T „áÕh}Áò‡sp©‚,ÍrÂS|ï©×t—%&V%Ñ«"ô¶H/·õêS2æžÎRûPx¦à¿¾®�g¾ƒŒàYZ¿À;±�]sè"ô'õ¥B�íÄ�)ûc™e)tÑì“̦]^$å{íŽ&A9ðF#’žßø€})ØI´’=°Pÿ2ÂUF_Y¯TT¼²«³7RP‹Ahn£ôÙŒ¿¿NÉ‚{â[±hŒ²³ò鯡´3N“Ò"†ïD ÝEÔj3èÞƒ‘¸Aí9­šv‘LÕ©ÀÉœ8ÈÙ, e‚j¬ –¹Þ�mqf[<Îö/¢o–ŽpC…×à†3zøî]Ù4¥–û:ŠvVðÃÂ6!}à#6òžŽ*-bஈH—ÓtʼÐ�9IÄoLu0£·îP]Qw*é¿ -F³Õ=td~$+6Kd;˜‡—8¡Ììã47f3QàÿJ¤ÿíì¿)#sA†$Ãð±²Ètsió¹ëèýJΘПJRÞN‡ë®‚8~u1MmI §Ü÷1™š_Èö+”\ …Þ ›ôzƒ9f:£¢åàˆÉ)"ów:Øi¤â¼{±çw$zå¡`y5\Ïbµ¼¤ËCsPÈI²çD£ÑûÓøü`8ŽDž¡'JçÑæÛ‹�uÞIôÂ2ŸtÃM;‚N—pÿê…Xþ+ޝ9Ã�úÀÜrCiäíH|Ú)ȵ+CÅú4Àx.N±Ñ�+’=tÇá*(ÜJBí (ï7ÎsÐ‚ÚØVo{ wî‹%ðRA‹\©ð Ës’˜usOÀâ�_d¹�’Ð`sbPÿó<·ä'qœ‘|.jtµÎEZôfLX ‚Õùq*íŸa}LõÂP*w§‡ýrW5ê3˜7çCö|- 4J¥ç?&¿%Êà�šm¹NÍ„`ZðN(™÷…JwJ£KÓf¼¼Êè @Íe²?«žÕÑi&J)e¸«@"c_QÅ­k0S(€˜ýs�¾³B`)ÔO‚“`”ê^K>u=(Г�×[œFg3`\Âû~r¸™ƒÙ‹Úé—RqX½ÿ} ÖŒ3 ä8•¼ÌÏQˆ±ÁÃ�Ÿ‰žë òfþ$�cîG£C_iŠÏåNá:‘qayΕ]|àµP‚ O\†å´g¥'ZÞ'·h�×]ºpµ&nÝ/E”íø1büìÒ4…Œµ‰h¸g†—\$ÖÞÅŒÇ{Q^ÄËϬº¬$³4Èü£tAÞ˜*Ò‹D�1õ‡=ã—ðʦ³pãž'4|³À¯ç˜º�\Ù¯`‹Ö]º}æm"‡^_àŠá)†¹¦Œk"iÏã”à\£/ÕS©¿�:�_åù3‚ˆÃqu·xŽÚ_‘šY7c¹¨®}c@6ëé�_šDm¤™Ó„ÈŠÇwéØ-'¨^¿ ó�/‡á÷8ác,š_PµC‘袷‚Ý"µ™Ü+�U ¥Α0G;ߟ#šßæá‡Uxzþ+K­aØ=í ä¾g©r>]”‹á{-ÁÁ*^ú*XZ¿*`íÒáu#ÒÕPMÉEI,k0d>�ÎÕ±ÏÖ µwðÀ®T Kyƒ‡Ûz²¯Q�.úšôYKAЙMбè6®Ð�Æ£Öv´í~ ‚"ô¨‡1Wžš±'¾i£€ïÔ­_“ äAÚµsôãájk{…L]pF^ø¬±$¿ÓȚĄ+8Þ¹ðQß=Š`8’Íü”­¤ñ& ˜®X€¯5½ÁA?‘†Ü|J.Í(±œrm;:¯RÃ|ßkDÄ<ï9Ë{mo˜íx}q�WélQˬϑ˜•|UFæanÝ)ºi$ž§qÉ«R^.†c¯n@”ÄFì°ñ'ÍáJ˜ÒÏÅWiù¸«4Ÿ~ê‘þ¬èµ.,n¯Âës³Ñä¶ÆÏ‚(¯ç¬‘J3ì3žOÎi©P…#ú˜vé2™Çå0}S¯ �N+=ëw ’žÏ¯¦§Ì½¦´}é4´Ïç|¹ô‚iéöšÏ%ëFrñ°˜=®¢SàŽn6¹ã�@‚Ã_Ó×ïþ£Ã£­tCR Ž^1�’!_r:³ê*m™GíHu‚«Ì葟ÓÁøšh?g’oö’£öÆ0pœì}ÚOÓöÄDæWS ÞÙàÂOÐ]ï§SݦzöíGè²'7Uº)×JC¥oª1ÛTè�íJÿüó*ÙѰU+`îe1ô X†5ÑQTöh\T¶õÃ;a®~=Õ ¾ÌDœ^.Üᯛ{}DïB4ËßK ÂA#DkH~•1m‹§;¼g�-{�ÄO¤Ð$ùA´ ÷¢Ï_ïdëP’Ÿ_ˆË­6Bþ‰_4Wn]bê�ç¦zY®Í�U-éì;/-0ŽâLýÅæÐó÷Åq¢B*%I*$²Jªïçœ�”¢II¤"#2*¢=´HQšJC%£úœ“„²WöÈÊÏÈJòïÿô>»÷žû~¿^n$í�¾+–¦³Å†%xk\ ¶ë�ºq nÞ½+�õÄŸ“§Ðm�côíO¼x~É”æµÔ¥æŠ‡2:(ñëjü™¦ÌýÆ�àúÚÞf?nÈ⼉YØxü,j_‹^¦Ãa{i*–úhS ú#lŸÿÆwà¶S¦·õÿg¬ÎO"O€©×T,-‹'hb¤ö �†Ïç�á ç ZòWÔŽ5ûüÝŸÏ�€Y/tÌÒBkpþšå”yF¸Ú£UPµ�gÙÛ¿4à?’ÕüJV ªseX¾¦ƒ^ ]Âö:=Ù¨Ô \·5‰�¡è=ä �Ys6¶ÔðÛž¾BÁq ² ȦÌ䩜¤Ä«,¿7È mãÆÕ˜vÁ÷�ðuª6­uÇŽ!GQzx;VêpìØe|©Ã„n]ðá‡�ÿ ye2KXI÷d›„~Gþ­Q[`•Lº�ÏŸ_‡?F nAnM@Ü ¸çÿE|”{·¨)¢$¦EÐ/�ŠöÚâ¡Á…®Ü襊½L¥kƒ.>&I@õqSd×~‰´¥FŠåtAí¼5nñ€0Utfõ}'öFϘ!à–EL[«¼ð"/NpãP‰N‹›„¶ó.ŠŸ7dVÛºb²û]ìq*R$.~�÷Í\?+ Oü´ÂIo�DùÄWÑÍpï/ ÷^óØ—�|¹%”"Ÿ.äšœïÐx#œ£ ”`|u¬Îí¤´™Ï±Kû„â‰|Ý3–‹ìã¶ Á`~ hë¿ýèër,g�ç9Zó8§fªÙ~\5B‹»½íkK¶ÎéÃç~ŒBÿŽ]ì·é<ÌЩf· ئ‰æÁÒ<¢|7ó+Bà²1\%Vl”? {md›þù´ø{";òÙé�¨°~ù™÷G»ºHÜ4cJb«_/³�n>ˆ9éʹ)_)àù1¸¥¼¿h°dn¢°ÌüÔªþ¡¯¡‘¨×6+Ü…)•ã±®ò¶P�A�Q¾üóž9Nˆ�Çþò© µ¦.o‡Í•[EãŒÓôÃQ”¸h¬Â.AUeœ��ÀÏBÉËŸÐ>`î"Ú¼™"йp×ü‚AmŽÜ°´æ… «ûšòžÐµà7æ üCŸ·­æ²�¡<³:™mVFcq¿T\;8H´ï1«ÒöÖÄ×)Rë$-|�ÕÝSòôiº7·y…Þƒ§â‘ïÑä:ô dÝýa"uà0]}[…o¾p†žXCË&²Ü×( žžHŽ GŸ›Õ0ñ¼³ÐO8[3H=WPl8æÖGŠL©gýg½Õ¹ëa›�ʱE²èâeFW~P‰†ŸlÌCjLQ÷Ì%qzqµxe2 œ´+œPûÈNCØËÆÿK*_ý¨cÎ"îÌâW¥÷áèÕb2>»—WuƒjïnW£“kl9M]šdBûò 3¾S:YËrú€ù¸LÎF ²�Æ[›CyÕ¸Þ˜þ)ÖϼßíÐg„*�¹<ëï*Ù{KÐ<^ º»Í}ø–õD¿R n· t—÷3B)o-Q¾Ð“ºõãÓ–tÕ-å\`w‘ç×¼•\ËÍ£ÚÌéaÏ—¢¦ÒR¤þmÚ^-:L…ýæ(àu ++åòð•ÕG¸”dÆû—¡Åv1ïÈ%,‰1¹^Û1J±Œæ-ldIc?µ›Ž§\Ô…¨DM.—ÑEcû"x#Ë3Œ°2;œÊGM@¯·ê­_‚Vg‰mf÷0õH«ë_¡�›�qhÙ|Ô^}Sì3(‰¦ÜK“Ÿ(PèwS’%Ζœ¼i ×—TbѶl2ý»Ÿ‚æôÀKzÇ©ñ’ƒð=ä;…�wá–gr´Eu*EŽ©Ý½ï&_™;œrÞ‹–SÚ©£Ä„ÓÒàaN5×F�*ÖQ`fí&œ:¦ˆÑþ:ܵô—iÈÙzœïë�™…ft¢îì¸VY `ï‹ë=ãÀ¤"Õ•Û„/wÒaëY¼šø üg=šÿ¶ýGMãìqÆÌp~¯ ;à1]øÓ½~Gï QA—¾7áë¼-h¿.J|ûãÔÞvF<¦Å¡Ç@úØW*9nº’åF]tQ��%ÞüN~?79i~ë¼k ý3•ý¦ÿÊž•mãèåØJ’3¯ðƒið̱~8eûNnÏþƒ[j¾»ÌáÄ—›ÈÒ¯7öŽîîNjg‘áØÈ虜­<õášÉê¼^Ö•Ü£OòÑu§Á·ÞˆÎÀ¾zæôÍx¤¸tw=ú5ÊÕÚ¥õÛúLŽVù>Ÿ¾×Sz ÉCÕùÙÝE<úôAvù|ŒÏ<ŒÁňŠÿhÓ¶‹|¥ ô­û`EØ@ ßÞJŸ3ž �I8Pº_òÉ¢½Æpîð Ë=@&¹-´!ÎWUÂàŒc4}ò`•h¸·+…·§)×e™ û�mØ>ù"HTz°¶· .¾µÍíŽP?×y¬î�ÆM΢õ>sœî»˜+2bPC«VÒ´í±èQØ— =ÍÆ�’¢àŸ)üïcvzµËv¬Çt[3<à ða–1N×H?y æŽ/‚r�pÀZƒó^Ÿ¬™úŸÀµGMP¾òé>ÌßåÕá²�ø’úIÿó¸d`(Ùt•&|ô祩ïé^A9¹Çõ5Ûôk:�¸ÕÉÓÆÿ/oêÉ®k8�k(Àú¼É艺Vûèæ|se?³­ úŸRuƒ}&âß/Ç…~†3¸pâa¤Ýaè ˜Ú7ñÖ)»8tf”P0˜£>9r­}¯xš‡ÿFŒÅÀs ‚LU;Úg ¼øð€><ŽN9M8ìa·Í8ÜL·WLä\Å×BÇälLÜTX£0x0«—¼¤9§`çµ6Áñ˜9^ c›Ü =á¤ØYГœë`5÷Rá15$ âÇÄòáã$Y#ûÍUwàÄÚ¯tè£6_û9›rkzð‰Ÿ�`7õÅM¯HùËZžw¶ÿ ÝW®¬.,ÁÍ\0ÑU¢üZ›xE’m³5%Â#c–€zÿ-0E+�tvMǃ%Šèü.—{it{ÊJE6˽†7.ŠI7ìá÷å#ÔëQ8~i.£ýå/E%³*šàTÊï �ÃË <2á%�JÌÄgõQXvð§þ� Ýt�âÔ<¸3·›[l=ÐÓY+ÌH}s·ì¾udâŒÊb?—ÍtP’}ÌÛU,•dVxÿ¶î–üW‚M²“ø´Ù[Pö9F÷ßỽ㸭0L ñ‰Ì9¾­Mýneÿé;yshÏá¼±vËNrªÎ�;…£ä;}p(éÊòˆ^ád•SDýÕžŠënËÑEƒ":xS“ݧ +V÷¥!í9(åŸKÓÖ”‘uŽžëXË>svá‹#8&ö߼їãksÅú½ðHR ÎR;ÿJHòR@µ]f¼ûLªE>ãi:[?Ög?“Ïô­P±Èƒ=S ìÎðÄ7—µ—�—|JΆ‘Û5ùG·/¨Í/ä“ÏPa7I½¬æ=žô³Ñ€-d+4`Ö×Px2ÑŸ¶ÿ�¦4œsx nè¾÷¹-t»a;}šçÄ5qtÒ} ]>ï+~Ý �ùó÷À·³oi×:nœp‚BÆ a .š©ñ3y÷Ÿ)lüëÇu-€í#VrSÕþe1 O\ý„¶w>Ðç'PécÏãõ6ãççßaSõGÒ¹w@2è‰#ùù¸Ð´þq`dæÒ¢ +'L¢ Kö¬>�‡NËæ®Âí¬5v1­v ÄÉ/ŒAæ|Ý쪡j�ÔêQÎ ôeön ¸b‰kº*àöç  1æ+6Ä#×=ìÃS3�qHJ*Ÿ¹ÚI÷>d¶ìãé·‡‘c›´ÞÜO®�9ò<íæR£|e>¾“‰/dðWÃ@x¹9÷îV–Ò0çÃ5ÁÏg'E/4À1Œ†¦§pD©À=\®ðåoáWûïlÊÂ_sbIªc1úÌŒúeaÀ–wtùúVØS?Ÿ¥†A¡ÿø3¥‚oẫ¹¬{( , :MGTlbåî<šzý*ªu’ÊZ¬óôÃ’Lœr-!Ça^‘„67úqfûn.Ü–KngRqµ�*ž¹¼ï<.ž á{»-Ømé:Ú1>k ÇàÀkŸÙeÂ5ˆzz–­Ty(%ó—cݳ퓔bàêÌÇ�ï¹Ç;÷õ{—yÁ‘iÐ'-ˆæ¾ùçzô ^”!Ô©>ሊlö{Û ÃÇ{ðͯ¶àÛì¡æ}Ð)Ü /‘Çe£Gà ¼½ö™êsj¬: h%é�;ÐÌÂXxtÏ­/N¤IkösÙ¯X˜®Âáåsð™f‡œlã'ìƒ ;q„y¹Ök.þ,5Á€ º³uÓ×bê/WqOÃd4ßþ”†õ~Fí¡øîž:Ÿ¹ B‘ç»hp×<,¬è;…×Ð{º�ŸŒœY\½MÈ’vÀwÕ¡UÑšþõ3ß¡�|vδèìÊuûJöÁPÞç ¿¾¦Âú¯7BÓØ1´ïópv~Óͳg#©³<vNXÁwOoÆŠ š�göýͱ�ðdÝ�<ÌN#ÃïIb´Wwg ¶ÈàÖux {ß^éݳ/]�Â.v+ñUT<–tºó‘Æ¥$Cö|í¾šÑèÊ ±ÿ×&¶/-®å ¨tš‹÷ãÕÒ¨æi‡%’D\ž§ÃNAÂÌU˜§ËË”êÅË¿.Cô4;¼yœ­º¥Ï!}g†ðwJ6ùå®Ã”çh‘š®ÄW~Ü kCÉí\~¦g%ìóŽö¾[ŒkÍS¹tW L𢸔dÖ¢IÙKaÔ�N)}JfÍúðzsFMËåìÑó ¨p¼ŠL¤_}²¡Ôï4($­âèG Å1§ö ^füp�5]ÿÏQ‹�xŸÅ@ŒßÇNNœåg ‹f˜¹8N×ïÅ:½xk¿³¤1t'ȯÚÑ»‚É1ÎYx¯¼‚{._ÎQº½ªmýR°³à�8#Å7hIÁýÇ9®[+›}–�øFýKkk£ùJV¼èa±GˆÖ-¤²ï1X2~^ Žg½iðŽÒí —ãd±çöîuíE�\ú}ÛiÀ¸4eîÓ]>ò…¡`}i2ZyÍ£ý ípUü!L¬J„Z ”[œËVnÃÑ룸(ä?±§yœ¾/öñ\G·<�a—÷j|Ý¥Á²`&®–¼b¥/¼ö ÚmôqØ»6ƒ#ö’ÂSpßÝŸ³v[ Yʹ<îÀ—êSa£áÑË¥òyŒä‚o&é`üÆdaãíØ¶–¥ã÷S²¢%žK?N^‡Á”—gáÂ3[Þ4Ò€ŽÝ^Æ3ÙD²^3�VËïÄ]ÉËÙϪžuv+ðíåRX�LÖZ¯IÁ eü=1ât4¯O^*|Ü™G­c±üÞ16ÕTaµ÷qü{¼¢P,›²¯‰:*æøÎèûNB#Ó›ü·<�E7oÔ”j‡ ”#�$¬®ø'Y�ä�tb¹¼¸8æ‹äüƒ#4Ia‡?gÕŽl<ò·—вl›;<†’•=kgô5€SN±Ãó×5V;)èÂtyKKŽeâþ ­‚’û¸˜L�OmA¿}C¹àg ;ó€Â¼‘þšüóßë–X7å½ä÷µ0Ñç”ÎÞ·�~ÕÕœ»òN}*Â�S“ð°A =ÕvcéèѸ˕U—D“˜’ ÿ ÂÇN…áN!®Oqƒ‹GÞBÛÆÇ`¬Ÿ@M‘ÑÖ@f�/F]JÔµÒεtû¯8ô ç%óøÎÛå8bn…è;l]ûzІ¹RÏ�f8oz„:çÎæ¤Í:Ø1‡‹Xˆ ¯üy…ø\˜uuo¼—Eÿd#…omËÐgT-+e£Ûxwô~q| 9ýpáΙÙx¡q8Ø”Áçd:omë�J5qù²C8\×D¿ÃÄU´o]„ÚStmn-øG§ksDS(‰b:gÃ�þ¾�–- X7÷µ‡Èàÿà¶§½ŠZŽÆÃn‚Z~)£hÎÏ)ã9c¢0NÍþ¢G¿ßô€ÛÝ,�žcÆ Hî~<î¬Èƹ6ps—Ó<ìá9o¬ÐƒÚ MÂåÈ¡lüb ØnHƉfRhè¸^¥0/Èß…s.RéþHø€ŽXsb—74Èa༑u§“ã\.“Rô(Úø°ïÄB–òÌçúøò ©&ñÞÏèÁZ%²Þ(Ás“k%›�úRöÚ2¨R©¢r•V±Ðå5D^Ÿ5n¡†E[i²Ü»š\ß¾¾Ú Ëô\¸�ƒ/þøü„®ö^%|Ø<€�^ƒg»óCé °­ïo˜;¾7Jfе3†âÜOeØsa*§G¼… CS,g ƒ^ï¡F·kâÇ£áò; CrŸ“|/E¶xÐ×ìøñE0€[ƒ½8�å}3ØJ׃z¹¥d•\9Ñ¿Éátš_9mœE¶z)d1àš�0'r«ú›Uºþ …¿üä ú ÞŒP,”ÞÁãµ—¸Ìe:ÜÞR³-n�Q�‚ôÀDXðÎIHÓ½W£|1nï?¹�° .˜�æy7dj�_PdËVGVœ£ÏSå@âÍ\ÎʃY¹V¼ÎA<¬kÁ{Ê2ØæÁÜq?�îìM{Öv{ÂÃ?°©ÎÈxƒÒP¼�¨ÍÉ¼Ò kOÿ¦ˆ—í0eH!=rFTi¶ÄLŸrtWqä;6ƒY.EGHTír¡|«,¿¼Ž`]ÏD<ú¹ jÝ °4^ø]oqœa,¿üJ,©òò܉†`ÚÑ þç°Û}—`Ï p®ØÎ·"ž ›_‹ÑöÇàú’HhÎ�®«K¤‹ñëŒ×ðw¥2Ї�à8Nz8@èl˜Im2É<'"Ç5ïãö°P\0G6áøz[¬0YÅ·š�Yo¦—\'¹¤žü#^ vÆv‘|¦ÚTÃçÞŸ…�/¼é¼J>–÷]‹>—4ñ÷úŸ0Z¦?{öñäfgö÷@©Y0ü±,l=]€Myç9x×Kú/7‹cO£S�†š¾ÿöàÕNá̉Rø>ã&~ßÑ ïL!Þ±X�̨˜uªðÉ£:\Ô!Ã]_ûà¨ùJØ•ìHå[Ö°ðc7M¹v‘[ óÅS‹e°Z" �ýŠ@¶Å[p©_‚í ë±¢)”ã�çÓà�r4¾ô€ý[¡ä¿5|]6 74YcLž $V*à‡ÿ¬øâLuÌ�°`ÿcc¹Õ~߉ÍésšiâÇ%†ÞÞbÑÝtH륌¿÷ß-£xÒ@šðº�dú+ÁhA…Ïü[Ñ·v`égsR2? ¦yç`£e¸à˜­„K>­à /»ïî—Ï~ªÁß²¾“ãJ#n®_€G›¤y‚f?q] Œ™bƹ/“¸˜ã¡Ly¨�5Å¥E´a~νø�¤6hKö‹ýqqÒ3<,NŒÝ®‰òyμÍÖSõ™fG.âxÍ4pQ_p29�kö‚�#3$šF;À°÷#¨¾tŽ—¦ëV:­ñ–Ŭ\PˆÕ~ÔÁ%<Œ’OCùãôó”¶•†>,¤ø+Ûø¿{�ìñú5IÑFѺ¬ ž4•Á»À2Û®Ãqê7–AÙ@[amr Ô}:‰ôâ2¸<rT×cüØM¬R0“UÝ×ñ³Kšdd4­U˜¬V¡¿¡mñzv•!B›[�°ÁÖ˜4G«ñ]ƒØÛR+Ö�ÃAýFà•˜$žÕ•‡Êh¼_=œn£a^-$ÝUDM«ÿ½¹i¼4?�¦¶fÐ…+40½˜Ÿ cS6ù›(Dº-®éa".±Ú)¼¸õˆªzÌÂkÏ­9çÌnL­ˇíxò™<ÚrIÌØ.ìNn§ÌG0øÑSÓβ`ž/7‘»KcŽJw¶l2E¹e±â&÷ÒT»CâO5þ,ýšB÷ðð¥Gcà'c^,†É'»„ØÇUðh£>šõ¡­J4ÞúCè¿|,}q_GoV÷Çy*¡Ø£Zž¿_Ìv0€}o´vûO!SÍ@•Öm=·Í‰ãUþ¶$æõ=eV½eP|MºÚAIþÊT!*ïŒðú¥2úoÉÂ÷#ŽÒ$åTòÕ\„£_ޤü+9v¡½2¸BYù”ѧiÁS!×ç<‹:ÊøÝÈkÔ�ý†NÛM‚Üq«PÙ>—Ë·î##ý@øoâÞ™_$¬툓æïÇýq`yb­{{�’‚ñѹ ’s+2p¢“µ]*D?Ã…Â…×§°z¿#Õ§†ÐõêdêS2@2d×HÔYñ¤ÚÈ©ôÛcÈ[_^ÓÎI²Ø±¤� ³1Õú7} Œ’̶–¦ç_¥‰6ÊËïBùÞÚ²qiįpúthžHwmùJqo(‚ ”ÒùûÜ´»6‹î¶oƒ³�|Ùf´L áâ3[%sÒåüp|´K×î ÁïÉOè@G*Y]Å®²a…¹§ÈîC\þ9_g›�–––éOc½¿'„‚”ïðêR3æyo†O� °r�~² âÏrm4}à0‰k�öîñÞ”ŸD«aÔç(®v=B› �`Ùµf¸‘Z�f§h¾°‹ôãó°ÇèÝØr)d'õ&ÞÚÀ›îÀ›§^¨àØLiöy0{ªÀ ðHa/DL¾ºßÎÄuÁØ'ú¢(•0{ÄÉðjÔàœ+ö¼\S†Jëþò’ôÓyƒûàÆÉýxæÐ«|Û­/©¬�¿&Ü�å!ʨ8æCMº RÅëÓ$jï M:ckžçWðÚéç$³^yc&(wól!Ù›SõÆãàðO¾Ù â#=}ðÃM¸^–Žðu+¿’JÄÖˆ6;Žá"ß-¬´"¢–†â½•ضFjØÏ'}„OÕÙ”¦°.í>Ošu¯Å¶3çEÛÄ-$¸„5›l©k˜9Ø3½G•Ò‹«ÛÑeá1~Y=†’�à—´qù¯T𲏅~Zß„ãu*<{‰/p¶5ºÜ¡‡_\×UŠq=цâ©ä»”ï-P׊­B…Ÿˆ�WaÄæ�¼äÓgñâÕfñóþT^ã‚χïáYîE„Y‘¨ûï›ð3È™îN(‚^�4tî9Ñ$^7¿"¾;yœNªì­Y¶´6¸>WNâß ©Â„c�hq�äêbY6N •K¤øõ¹±üð†n¶;Iß>Ò5m¼¹¤æð¾éèñ†Þ4Àí¿ –®ä“õY{²ßëîÞ3‹ådk YÇ_Ï ë5̰yþg(ŸÝCðÕ“Ãw úØ\%Àʤ8|{Ç K7–‰ï,¥Àôþð9-´ÏJᛜ¹¼@Çã ^Áä_cèÏÔ´{¦%YZ—ãóq±5~9:tP<(œž¢*LqìžO´gË7QmŽ£˜8l ÃBeÜ<ÂŽ;Ús™¾…¯7‡PÛê·Ò‹¥ôåiíù|X¹Å^]¡�¹_`SÏA<¬%AhNº&Ù­2ŽG»•ÂïM95`9/ýÏ•6½(†¦ìª›“G¯ü ðȸ´õã>ørý� ›`O_Ÿ£=GèÜ1)^27ÉôÄH®º=›ïõ�~>µ¢Éï{�JÏ<òE> {*®˜)�[*oàé£xtð9!õîI~¨nÃ+fÆ�©Xª„¨/8Ѫ³Ñ\w‡T‡Þ‘$Q/Ù\(ž�j�/öêqŒÕK…K¯ D\SW7«GsŽN'Y†‡Ó†è"”©±ã >‰Þ³ÎR}� x«(<Ž5C ºgÈóÖ鱯ݾúÀûÞAeoÁFJßê�’=oéóuY бDzr(k9o ÃÁFÃkÞ�5ÅoBtýBòšq€WŒ ÄÖÎ{ÝÙ½Z w ÒK *ô�è•WŠ#„¦˜‹¢Eûa½­ ®ßif¾¨‡S{^£ÊS(eír?ÛTšp澆[œúâ#‰5ËìøKh¶Y4Ç s´BÚÉ×ÔëlññE'ò+a7 3[•ÀÇÕûµ¥Võ4¾·ÏìÛ 3Ê^‚ƒ©)nÈ�ŠšnÞTo—²Ëç‡Tµ]Ž›C21¬ Q0¬~Ê‹/ £Gt¿÷Åþ¸F<ržrÜ ^+Y¼7(ðËÅ‘`æ-�Ñ÷ßÓåÆ˜¯ó»:_E�euç°±ð‡ýƒøoL8UÁ‡ŒC”^r•¼äÖ£LÏs éTçãß’Ú·`˜*µœÇ�kYęþí÷ ïøÛ⸾ˡ`—/†>»Í~ aXékÞ¹ ^¥Ì{üb‡åP0_dî¿ÅÞG{ò„Áiä÷ï&DÍžÄRùNðºr(©ôû^Cc]—I¾ßúNw4µùñ»Z€Š¸úCDŸ)ü3;ŸJOÏæâJW~=Ë“´÷‡™Î¯ˆ€Q«,ñïñƒtÁ¡†Wð‡G»–Ò¨ú%�zg„f=ä(Ã(Ô(ñãsùâSÛaÜ’ÃÁ‡à›ÑP¼ñî>šN�°ïûÑýÑ Þç)ƒJ œÒµ¼Ê“ÖXGº�º‹�ÞºE3ê^ +=¥Ä]&\;UÇu�iI³¸£]‰û—Á�²›áúÍiü{`6ÞâÇ‘‡ 9ÞY“mæypø³·bÖBm–÷L€‡kÄœ€… à& OHƇ1W`¢êL¼¿= ÂgÍæ'Ã5ñOH–ü@†—ÄÇÑß­ÏÔ“qßY¨^q›Ï¡�_E¾:~1ߺ¤ˆÍÍ0tºƒh´+zŸšÄK\(7ð²²ê¬àê^EF«$üdñLüÛ¡Á£ 6`û¸ñôóa)=Ñ/¯Ï�Àº^”XÞBcrgÓm“‘¢¬e8”$É󑔯ÄJ¸8e'UÇÜ‚¶ÓЬ;ü 3|'”þµÆ‡&§M³Ë³à^EÕ Ðã_¥Ðr-#™W´$,Ÿº•*^8ëÆ ó†±î©9T5u,˜ßZ�c§¿‘Ø�Eµ'Ä1†;i•ý*¬•ߎc[jÅý­‡°§† f|'åÎo°ÅTW�x•ªuâb~LÞé¦ê‹‡ÃšÉcØyo ìÇ­.7ñZ°~9?•à�©çA%ž¾·N’õÀ‹ZrÉ÷çQ8·ñÇ´måP-ÙêÀñùtÉÐŒÖ 9 {ëÇ`iœ³� • �w+‡ˆïÚ„üQÍ(Ö<‚Rû‰¸7oÑ£ëÅ�䣘¸n0z&׃\c<9y6@•]‡p`MhÍ®sÝùr¶’<^ŠeF�hgÿ·Ôø~ Ÿœû F…†‰ê·ί³x‰¿-¼âɃ|.‘ýݽxóÀ2ø¼Ñœ–Þ…e·Cz‘�ÉÖýùãQðÐðňëô 7“»`'$M1‚ �w ò“`ÖõÁ0Þfx7ƒÆ=ŠW`Òß©´¦HŠç/ëž� ÀÿóD®ú&…[ü•0()ŸÏýÈc™eOàúè|ºÖq’ê^Jðs‡1&f¥Ì1x{HUÍ$eAïâ&®”öÀ˜¤�5Šm5NpCû/ÁjÿˆÙîÆÁµ"Œw»ßçÀ§68­»*‡ßVH½×kñðŒ9ܰIžÿëÿÜÍÂâüCâÀ}¡<çƒ.v n ¹û׳ocͨÚÁö#óPqãaRIOÇÒÀ@5\UåNÑáC©îÞ6<ö#�„üc4GÛ€W¬žIõŸ�sÄà«<äl‚8´b6&Ý}#Œž¢A¦‰ð78;l98¢VL3ãCÂÑ:²ÜìcX¹È §õ;$Xï)‘<é u8H‡O'cKÈañÍP0ù¨r»G‚AÖJ°²Ó‚ 'r ê_ÐjöÁË®AÙ¯r(ì2¦³Y?H£W8½Ðí�Póžfÿ²å€—!`Ñq†;10K³tÿ…áçkzü[Oò_ÞDîÊ0áu¥ûA^o8k÷>ÁÕY­Â™šÕ|÷H*»÷í~ØKáÔGò¸\vÍH…Ý\¥› +&?ti)ßkƒÃöK«$ ë•+肌ƒiÐþ…¢«ûuÚ´>†�-Цýa'/wêÕ1�?õˆZ\¬èwÌ!RéÂ?;�WØ�Gïµ9dx5÷HÚËYöП٠ÓKNßn¶„ÿ»&®ag{GÞÓxʤ½¾­‚]Ã@öÚØH]±&èóÅ”Î' òÖ#PEY†ò£O _ ÓøðE¨<î�6ûÂIû\1ý4…ófá«§�4^&‰²Z¼aƲ�yHÖ ã'jx¾o„ð/,�;§cø‚±Üš˜ÀrçéÕ¼™8f{šàû-¡¦÷FEžu¯‰ÒŒôyÀï;´ÿ‚9jm£µ~ýÌæµWÑá5=àê=.®ž‡Ë¿7zî8ò—RþÉÕ^[×c•fqœÛ}2yþFÜÀߦÒ¬õT¸'޾yäñàó‡øie$8«GàGé¹`éë(n.Ò ùSÕm§éÂÙ>ä;B�NÍžHãç\ ÔzK.¿ÅíËy‡m_=vZ¿ÒõÃùšç š0J�=¿‘Ôõ¸õ�FíþÃipÕJ¶rU ¿‘¿`+-ã­Kj²·Èð¥ÐUXa¦ /ä‰ue’qàÀjqFº*É9_Ù˜°I‰„› µ‹øÆõhLÚíK:Ï‹±clèU ©�õàÈVL¢3NÀÀà1ÿÿÇÉ'¼ºác²ÐÖ¾ü'?Ä’‡k@µð4Œ?S&Øúùsî«$T9;–ßNf÷f3Žþ¬Ãùo"Që¯�¼P%i–¡±³àµ¥· ùw8¬zdÈ ·Ã”tiü·2›Öü ãÏÏ’QN݃îzò­¸Dxáxƒãœ”èë‘Võ+2Ýî1(Y\£gë0;I‡ÎNâKÒ1¤_øH’“žE±–ä­ÓÍÅeBÉÝW ¿æ –%DÓÕ#Πód^}ç=nFQe¢;dæ?§?áÍ¢·ooš"@°M>ÍÉ;òò-gø¤Z¨¤IfjJ9¡QŸY`P«ÂYç“aöN®*‰jÆÒ‘‰üEû4ì[àwµxøSX±Ð‡×)á¡ÃA°Ël û¨]“ÜkꎞÔ>‚öÀû`\w_WîèU6û?øI‘Ævl°á&V© ï¥~c[ _½ ¹^+JÖp¤mÌ ’Ã� Q9í0‡rçT�ª3¸^U•Ç i¥´;ópDèdx+ãÄŠVÓöWüÚ¸QR÷v8Ê °ßÖƒï§ËÓ‚¨d—®¾’»8å�¸½ÕÆM@.²ª|X¥’ìÜ÷Šð¯F,Œ·lêÐ`¼!–'ùR‡‡-�êùÅd˜kÔÒ*Ôr$0pŽ€,�8x¼Õ.ålw=.9²ˆÖ¯ŠÅÔâ#¤fmÆqæ=Åâ€ò¶1«ȻӖûð0¶2¿Qeq³TA!=–aî5ïé¡ýÁ‹â”ÆV˜^tX�¢ÀÙº9Wþ£0cW—Xg=ªÖ®Ó §Τ`›mBß”21âW ¨ÚTˆ�Y¥ÐV8�æT( ÆÿZé¨müýßpŒ9þ‡¢R{a¿ãáôδF,îÚ…“d'à�G'ɦp VS+½—ªå‘ûTIÜ^‰žaÆB­îC¨hÐ�#w‡RÎtäG˯�wÉ4<½Þ‡ Á‹fÙðå¿xöL韔Ǟuΰ¤·*ÆÎ8'ÑÒëÃFYwhøÁ̽3ŸJú˜°¾j5ÏY…)K|pÁ’¸ªµ#}xÊúZr×Óâ^¯W�KÌsÊܼ­/þkoTË‘‚�›Kø°ýaqï_žö0®ª›q�y ìü¼ó´ïÐÛbx#=Œÿ5öÁ‘9ž’µZATö׉ÎÍBÝÖ¨I>Ë'øÁ»;ß«‡Fï³ëpPï›ÜÀ�ë©9eºß•ÁÕŠ^5Ë?nÆû¯áË•µh3l {ªçbO½#¢å™‘8»Ü’_� 'éµwiø¾û¹§ë†Ñ¸¸{B _à‰h¯ÿAè«¶?5�Ç’¾+y†Ã º••cûaæ“{³ó$ßa!(¦ð{U2)[ i Z‚\ni=ßÇzê`Ê(Už™VÒÊ|û½>‡Å¶IÚô#xéõ*2™ð ½—qbU¸pÞpŠòŠ|.gh¨ý 7vU|ó�„ ûrÜs{¾aüb�qÊXSQ2Ëw³ÕÌ[ÔúyŒÓ%jÙ“(ø¥Rˆó3h¬úEïÜðd·KÔzìµò)?YªÖ;J =µ‹Ï¥8`w-¯ž�ßfK.ɽ…–ÿ:ÀS[Sä<ÀÅ㼜*b¦r'õÿ›Œz0ÎL_m·xöè 8¦“Há-QØoÁ!®p[€¸õ¼ð¥ Å…E5B…ÅrlóÚ.Üšb¡ómA»ÍœäO`ƒŽCÔóã?z5I…Æü΂âÄrò§À…Ž ~wÑ;·jÓªÿÆÒå;Ü�q‹Ÿ˜ÎàɉZfGb_ÑœðQ´1¶Xl>_Éå­gk 0q=ä¸OÅv™Ç½t5Ý¿Ïr/vÃuý5°oÿIl 2†ÂÏöÕ³÷¢-—ð†sÛÈôÖhGÙ÷/ÀHªNôŒ‚ c×aÎè}Á\¯ß!ßL¹]…Þý ƒž\Ä|µ‡äQ%æ&è°Kè)ºÌ—†eÓÁK1<µ÷”û&Ë6ûV ÎÚr|L_ dU¶�¿÷ñ MŸáH-&ú Ε8Ъ|½’è¡â œž3ƒ âVò‚R7!fÉOÚù}-Þî<ÌvRG0FV‰JÝÅiåÎ\+8cÃtøWzŒÏŽ*á?“߈K§öÅ‹ç Ð;~XHm€[GNÂÔ¤¸¨r€Þù‡ˆ$mz¯g¾#çÁùå ¥�ÖÕjqٶôF¾‚OLØ‹”Š·_Æ“ÜòDÒÚèÈõKÜÑÀ!„?ÉÎG¾yœ=׿b¤r!Xž¢£‰WØ7z96–™c�®:ëF»¢î/œ;v1HÂGm{Ùfn œØI“¦Æp¬CƒÐ\zTìãé/Ú÷Tã”Iòø³ú9´çe‘d¸½qRPxýüªªxZ¿dª3öZ®Æœô1dôm?÷ß_#îxÙǼÍ"Ë,TŸ9”ŠÜ'÷ÞŠt·`"öOàc�sÕð^^°'½›ÏÎ ˜=©AHÍ«¤Ž•oÙï™ ?¾÷•9èrò²½è³1�cbXûåVR|+¤Tµ û>¢êm‘ÐUl�oŽïÁÇ•Ñu‘>~Ko£Ot°�Å\XHÛäîÀðY>¼t ·æéÐÚùýYiÕ4<³©gY†p¥p“TÊJðâ Æ9èñ×YIÔ‘²IT¸*ͯO?�%¼G5Š×¯œÅ²ñUð¾hì’këÓ¸­zIÕ›ÓÌÊ“B�q·j:§@Ì‘ÙüF&Gû �÷¶ó_G®~|Z¨(Ï@w�A8M*\’±e,æïw¥+q7–Î%« ôºúžÏZZ£ö¶C¸}«,Ÿ ê?¬»‰ú«[H§�+ý—É%}¸ëB¹œ_….¡‹ ÓÃ@h‰—¦¹oë©nÎhž7t¾ûP�‡ÂžStŒ�øxj³ëÅ^}Ëys¨:ÜÛ&¼¿•~—A�ƒ•);bGú²lÑ-xõs6ì‹N¦·> P½ÚˆãòvÁÀ«Màc[„:KÓ bC>òÜ‹ßã(¿Ó\wþ¬SÂM›ZŬš~ 2%�þ•¤ÎË=¸Õä [¤'T.©ߦ¤¢þu#¼ûý øäœä‘ÇP7w9·ÎãÎ�L¿e—°ò¾ä=6³»»ùÑ ŒçÏĵ†’‹[åEÃí?¯íäwr¯Œ}Â‹Žºan}<¦ŸÌN¥ÆÂiK}½…ž�?@f/-Yõbw¯~Ò£kFé(œ˜Á³ÎTßÉýçÚœjzXŸæiÖzÐ¥¶ž(à�gÓ{޵ ~�0`Ï7ƒž 5–ÑW`ÿc ÞeþâÌ©úû&Ô œÅ¿>\ƒŠ³êPû» rÐÑ‚p>Ò•|¤y×õhHŒ~/&—dsÛ X½«ŽVžo€rõxzãÒ(<±²�ùZ›`óÅYl%6R¾[x)§°FåŒÛqY<Ó¾”w/F÷½Ø'M‡çÿLçi*öøÍP”´êhGM5N¾’'ˆ)Û©²â0ÿOBs¯…Aäöû�‘1�›Šë¸·‡ªÑi²^ZEǼYöߺçÞ_-Á¤Ê2ˆŸa)(ì8Hš¯SÙ8Ç‚œW6C�_oü¥£ƒúèr½÷`Ì7ï‹S½Ly¯…:Ýã žœ#�‹ÃïÑᬡ¼9 ŠK†6 áÒìÝZ€k ö {[ ß�ÜÄŽÞs0±×uÒ1[ÏJÃnÒ×50ùz_Œ®÷޵Üß� žÃQ� ¥2ŸÝg;Ó×JÍšâÏñšß€#–n¾Ï€_EqœN:xØ„€g§ ß�½e4¦ñœ{ðšŸ÷ëgÌ_¤îŠ]RåÕËt1ÿ?»%éКŽ×b6ðf¿¥|ýÚ<šÛñîCuÎÙæÚUð"r 9”¢ö¯Ã`8ò°Øé’É%’|.²š•Ýfâl»IصX…SçÜ »ï#ØdÛà~“O7Þ¿ä:â izíΉm(W$ºZè`²”»>XïûÞçÝô^,y€Üñz)‡[�Æm:¿™tÌÙùQ9õ­òãqÞ Vîœú v<ÝÉÿíЇ ÍÇ –lnt9“„yê°¿Ý1ê#žƤIãÍC Ð.å4*§ÕìhŠ0ÍmWÂ�ÉǨǥ5`y³–Žh™¢ÜHkjí`ñzwü„2XûèFçØó›&g\<é5ìKm#Ÿ)a¯VÜÞï,I¼GòÄ¿ íÁW!*þù¼®…gÞ€9Ȱà4´2è^^ß]¤‚Ï¿ôÁm†`gz.ä”Êá¨cæ|r¶)iü �ͬe…ß,Ý!qdÕ…\ ??±ý«��{Ûˆ�zT +úž¤õ×ráÂJxü†ŽÜÕ‡g{â¬�ûá¦(|£9æ¿ÚK_ÿ½@g‡ß4ÅáÙd†bGÑîa•€'²0ã×v¼_2‡ƒ*U8À7‡•íUèΞÝBÇŽ2T¿#l8àÈ®‹î ·LBÉü™7)Åò„R3~4{ jÕ=Uõq¼ãôüX7žÛ” Ç�ÿAs@1Î}ïAn_¥Õ3;áÝ»Sà8¤ i*ÛÊÇr|] ˆyó¹ññdÎÎ8@SÏíå‡]û%F‹Ï±Vónò ÎgâŠÉg÷uj‹(Þß§Žÿ¢wSè,àWz>ø³�o:㋚ú\tð9½Ò{Oã}†Pºu ]�+*ªT ¦Õ H/ØŸ{;’óÈpV½ý‡­5E“?aBÁ]Üó …‡¬†!ï´0¯h£x+ø#L„ojÐt• þ¿‹utœxÞŸÙ`7<´f ÖaÔ»ø2cßÃN×XH°ªGÛF0ûrˆpNc!ÌX~ ãuó!yònNò^E«%®¼Í?ÊDZèî;DŽvÏÕÇÒï¯É9ì¶IuPÛTLt•À¡±°>nûôl„NÍhŠùêMaΫ¹¯x¦fàd'Þ>áËÄ͇~È“¬¨ï£�4ѳ3eäØ'å øØMõR²fæ ÒSžWÏ2Ö’å«�÷iÈw5°;nÍ¿A­¾¦&p\è`¼¯ü¿†ëÄ‘Êu À¸’HÈ<$Q¸BT’ÒþÖÚJ"¡‘J™"®’�¥2•" *aï ±ë �s*)I‡"Ò �K©Û_ñ{¡ ÞÉÉñ ïà^ˆ0—>ËüÅ—ô…âG&f ¿m”MâÄmbH«^‡•qš3ÊÑâØcœ­DÛàiú Ø<Ñ¿×ÄñÅEBÖjr¢‡_@©y4ÕE ¸ewس'лçRUW~&ÿ¬¥ ¤ƒéXŸÝëLI�f>ÀûÜh)`7#“ Èu+L­7 ÝC-Ü®�T�O×*vñt;¯°b5žMÂ)Þk0{Ÿ9÷äù+PP`Þ¢Æ÷´€Ñ5 ×ÎÆƒÍxLb ¹¯Ï§®¢]‚ì^-ê,Îs«ûÌtÿ3êœ'`·oÃIMÉ¢†ºðçÓ7pS£½g¹bçªX¤ŒYd½’• oMívû ¦ôœõNÇêÍÔkÙÏzØ*Ë*¹bƒ·ê�b¦´ÏŒ‹#O)²¾êL¥c¦aåH~³5j3hšþwðŽ Ç 5qåžã<ËãÈæZÖ[›À)DöñU¦rtpç=¦Ê7sGŽç`CÛ�H§hŽ ªG 3RÒéИv¶ù×\º�1TÛ|½~ú5�>Ô=åò¦ùCÆ;ÊõÉÅâ æTÈ®qN»ª¡êâ2êx¬@n¯Sè%Gv!f!§#³ò*/:U~‰’^�ð\H+ÔWÍ…²ÊÅTÕ�bu­ÁlæöT´/ßSÇsí*°ql"YyI Ëö~�0˜ÄÆX=`Ñm6˜)Ôo:)ÉkRäõ:ø<�·Û i§2ð8‚,¸Žßªãaz6«Pc³ =8¼ëV_$E¦±ÔùSI*AŠ—Î4=ÌN#™ðãÔ,1÷¡T˜m+â"¼UÎ…›]ÛE†¦’œNÈtL”�AWcZ¡ÒÌ*.DàÏÆ÷ ]ƒ•]„ùÂ`Vm³~?uü¼Å-1ècª ±©t¦ÀÐg,f *ÞI‘T£Ño/~;�NaW™è~:¾Vš‹ÉŸ„,-fvêÂ/X”´»÷CŽ™h%A´¬9ùœÎ—î<ÖQn’uÐhòy*°¬•Y�Þdße‡™_I&½4ÕÄB³ l«Õxjy’�ïaX7{Ö?ÔFL„#ªJ8ðG2öÕ¾Âw³j(�›-Z Hå:b¦ž;‘俤¢gç1VWµ€9X¹@ó¢6Nª©‚iývAõòCÁåteNB7Ü´pµH_Ý”Ih™²ÀUþnü~Ê·ëéü%Iö†–PÉrø¦Ü.VÝú�ýxÚÏ::�±Ò�Qk‹#ÚÈz£«G§¹ÿ8uÊécbÇuô¾UMë麟̒aÞaç{¼ žÃý¯t˜%Å¡vü|4œž:"AÆQSèènxºÊ?\«#ïÈ+Ü’•ÇiÞêHÖ]Ô )sÒiê[/¾4³ Ö?†ŒçÝ<žèc¾3Z¸øa[¼R÷žm)˜J ½¤wr3œ4–ÎDÄÐ'ŸLº÷pú›w�8¼#Tþ…õ—)/³”çÊÔhÚ‡Xh9‹dFÁ³»€+·“Õ3hoÙ�ê�b¸Ó• Ñ% ø@ý0*,Ê�Æ µAšBKt4‡¡7p6=p�„!o%ڨʞ{)Ó‹Q5V¥×ÆdÖã+TÏS€o?¿ÓZ†&.�cvÇECü%´øæÀûKÿÉÉÇZ²ÊÉsñ±Æœþ"¥âHt©•Ùd¯DßH¾c0¼uP½Ðž8‹B¾¥Õ½ Ym!YÒXÑåEï<“ØÛ«^lô5cC-؆ïiCc9&¾Íò>û1ë¥}‚_ãl8s§ÝxõÈEäuÎLÞHÖ!Y"Eå\lÌù/ÃÙóébþxŒŽWÁ¶S©ÐŸ¤Ëy[meE>®li×r —ôÅ·Ö%°:DÝÃu…ÖE|H�'t-,áf&‡QKp]žd‰§²Ïã¹ÝÛšŽQ7Ø”9]¬Ço=¾˜ÇoÒrÿ_îåóæe€µÔß\õÖ X;CòNî“nBä \´§”iâås‚aØöË‘Æôgœk` ±˜\™ ·W®V¤¦…Ÿq~|$šßå½î– ó‰…$²¨…ç‡.2ÇØqØXÆ|Ûÿæ× Øâ¸zX¢1�ºÎqIù§ ëuëqÕ%Ñ�;Ž�gª§à´érŒ×+d?ç%ÑØU�oþ¢‡Ò`ŠÌCnÛ¦ÇdW¼ì5¡;á3øò€è‘¤¤‘þè.E’ˆ–5s}úf) ¡ÅI4> Ž¥Z?‡�w/ØÆUµ,]=ƒ»®­Ï?³Óëtð¿1ÇàÓ9\¹e9™ª–óMÛ–°ë[÷àЖÅühp=Ô’")v¿àŽ<¢<µFÞm² û×i¬—®„­q¢¿´“I.n¼èÁðIܺ–±¢à Ÿš€v÷™o31w³ˆµ{˜K­1îúqüÅR¨öK�Å‘Œ¯®U£ØA�òvëQN�9wŲŒ²º5ÀË$ ~ö¦³lh‹,ÝQþQ’¯Û‚õkrAuåÁ5kMôcÎ&®$LMf•¶²øEXñKàvæD]6ÀÖG¡Ô¨ÕÊÕÌ4ÇʱëpBñ{ÎÓ.оÜ0€H“,Í\MÿœX.×¼éDÇîrM;9=TšÿPK-!0daÿÿÿÿÿÿÿÿ arr_3.npy€Põ7œW÷_Ïï÷n¢=HѤŒ¢H½žç¤!Y ZVe�JJˆH{/MY‘YÉH½žç”‘•ˆ¬Ì¬ì=ßYßá{ÿvŸÇã¾ïó¸Ï¹®s]ùî>S<§Ëʬ’‰4ÁŠyƒìM mYš Z1gY`XÄüÿw�²bÁ¿øŠÅs–/ø·÷JÓ×;¬Ý¢O‚û*ž7¶MTØþØQîÛ åºg¯„ÏX¾N æZSiñJ,|®Æ³ê¤ŸL¿Ãê;6ÜvF�¯_I‚Wû ë’ tÏÓ€JÊÐ)–Œ9ÌB�ˆ_†dÃÙÖä;³C¯7á½" .ÌÈ‘Êu¹SxÜ—Ùœ™õ:âóaÝûm|FR…ïÚ¹ÐÃ�Îÿê1¯ ²n4�ËîÝxiòP>½d6mÜŸOÏ�ÔcÓCÜ{h�î\ƺ؟¶ÎŸÁ߯Á›SnÓTå�q÷„£¼–®ßÃÞUµâ.¼)Ö.‡ ª,œ™ÿƒ¦ù?‡Œ‡WÐ1CKW©ŠÏlýðOŸÛä”t æ„ò–Ï1mU3©ý€ƒJúäyO°�0Ëì½ô€áúy4¥-ÃWCÓqäÌ�âɧp·Ù'沪ž;Ÿé–ʱ‹ª©¯³?.QùI?¯è¹ž·‡Ò�µIdÖs5Ȧh5œÌ�ªÛzzŽÙ;»QJ¿èq*Ý>.ञC8ð÷{è×¢‡%¡#9¤4m2ªø@©Mv¢AªQðèáÖ( Àî÷‹QïU?ÌL¥¶¿ÀdV2U/ÜÂû®³“ìAzÛ<#Bú°êZOÌáÁ2%G3*Ðfÿú;õ<µ7cy§?Ÿ“ƒá7bùâè¯t"¡ÞÁ}•gã£dNaC»²_âãCÓ HÁ—ï þ&àšD7ò{Ý�:¶r›s8Æ�sÄÛWû⥣›qØ­i0Hö¶�ÛÁÆÞ |‘¸jT2ßZïÄmû:Q· ¨ûE7–ñÝJ£æÃ€ VH?kÍs£ŸáÙºf¡¾µRÔé«�Zê¶pÕ<:�‡ê+ê#ìô°Ç½ÁܽK�ÿÆL¤ùÏ\uP`Ù•{èçé$4 M�¨©‘líJKÖ‹‰ÝWãÓî�g ï~Öwöàg«�ƒ¡·>Ú Î,Á¸£¹,Ÿ->ød×b+39X>á>¹Ì÷ãy‰ÝNkr²§ ÏXÿ‡&¶~¤„/9cäK8´Zsµ¸látÊM:+Êl{ ¹f¬£ w5ΉG£bÙyÚ.ž(É–Ê=ŽßǬäƒui¬Öǃ͂Akk>·FLC_Ã\¶ìŒ0^c1¼ïý›§�ê%VºÛûxXi0Ÿ,À—kléý�ý¨kÛ“õSªx×Ì�¨Zùö$L}Ç©¢ƒ{. ~ gžçòèשpαOƒŠuyÉÅïÁS·€ÕÛÞóªmÓñއ3(û]‚‹ßýp‚Noñ÷¯÷Ôß©”ƒBzðœI§¸m––fGÁº¡31дƒî(+ƒK�𣦈ÖO©ëšï€ÁŠeèáwIš�Ü*Ý5k¹-HÃ�ê-ÂØÙgHq°=^³{ôk‡c.ãÒÿÞ’áÚ0Xå�Jç׋� ™ÔC;€ëg %Õë¤Rù†#Ÿë°)çR—ÿ ®6­Âê)Mhñ¬��èù€íŒ ¾Fñ ÓÍO(Ú�ãis�°ñ´ –ͨ¦§¼zƒþ ’ei8›¸ ‚çŸÇ?�k° x.Œ»!&ßB»Öf{¿œ6Ԧ㈓uìíy�òÊ& ÒI inŠÄ'? {o¶LÁçæÝXÑÈŒEPLlOMÛ$ø¼~.èüù!©¸¦qÛ¶vš˜œ‰ówgMåDV³…\ËŽr¹¢“øÖhV=¡{d×ý½�KRçób»jðnxâ]]œèH=ôèÝ™ µñú=)fKSjЭfµvÀ!¬1dN(]\Ù çT> ÙN>yF"´‹pböw©ÍÔcÛx L­„ã¿““ïŽZ­oLP½YG\úBÙH4nÊÑÃÓP6¸FôÉ’¨È²ù4#¾U@»¼M…ßï0TÎÅ3$ç¹}Æ€$,á˜ø5ÊgO^ŠËœ¯ã‡2YþÞX-Îpè cß�ë9 n§Ä±"}ת§Ç�wØùíD,u�†Ú^û½AX9=²Ây¡Ðí:ÿñî‚ UXä†&%{ÈÚ=˜uÿqNÂÆçâýÖWÐæÏvEðÛE¯ANû „FÚ u=*àî¾Ã¸Ô«/'õЧˆØõÜòvl®¤–ŠÁð !î‡\ÿ-§Á¨3ˆóö…¢í”ñÜëã4jtï ²�j\ö¸ð;Ù µîWó�k/Égdw7rÊËbî6¡›‚ŒÃh³>´Ú–0I{}8ùGè·¨;Æ.êÎæ K¹²`7�s•ã/Ž ¡ù)œjŽ29nèÜ9C4λKîè>¿µ/lÃoþ�Û/æ¹¹$߸†õu'‡4|?½Ÿ0²o"Åé°ÂâðQÇ«›²¨« ƒæ•à-KmqüÞq¬´üxï"²3 Ïä—Á  ç¨ 1Tó>È)n Û,ϓֳ'|êµ/ÿ›I‘G¢Ha\ú¹Q§ÛCº~ËØAmi_./̧¬ uxôÄiÜÔ­G\ö­îYR £‚Wj¸ÄnÆwΦK9ñO‘䙩®è[�i¡kçÞ‚À9gÉm½ž8¤À϶ڡ¢Q/ìꌙ*<¾t‡Lÿ«æ‚Çy0Vë�0?%g¿=†eg^ ÝÊ ÷_kÚ¼|­M°fc!ÝLê¦/qô™wÂØh;w]…Í/Nb³q‘œyB�E[qóõŽzù.x2±�;ÔqnY›×ç༰ít»È‰­´§áË`OÔ|uZ¼T3Üø$93£;;ª0¼R©ƒ½MaÍ��±?‰%“²øà²Ë¼aº-„_,Ó‰ÅT¼-‘ö®ñ«ß½ÐR§‰*Ü@Ÿ·#àú›»+,ä´¹¥`ÓvºÏWâ‰sUà­uj $øßôùøÈï0d8nçÃßXª’Ƚ,�ÃKÃÇ —^!¬ª8ÏBS5ë<–á%gЕÜX©´•{÷¤½Þã„ ^ÐRåÍsÜ*hËK{>dý“~ìh û˜¹8ðl:÷΋%þªh’š€?¬šAfÿi®Ñx‰å�mT·¼nº¨�ÆqÉøxü|wã®´²ÁíGNQ�ÈÿøWÜz^˜õìô‡zg ÎàT‡¸Pǘ)îÆé�½¥Cw²tÖAœú*›ÅS0 q>¯Êü�ýÊ¥9Ò� ©[pô5w±sÃA~œwCŒóY†µvaQàA ™½�ã�dŠ?§bï ´±©…ŸËÜifûPÐüPC;:úâÅ«rø~õ4ÊmTâ¹WúK®n‚éerpj¡ æ VëâÜe»iÀÐþº•�lÄÌJ˜ßòRxÓh€ç`GŠ6Þ+Ù…Âý9ônòëÁùt,¨îU¤âôÅ\Ý—gìQlpþÓ$†oÝÀGª”é~~5�²H`É}4žužæ^YŠ»aûÏ/Pð<œ{Mû#SÓ`+Óþ²ÎQ¸{”yÈSmÔƒ%h3š_ âï#5%Æ/Îððä~X|¥{ôēÀ¢ >´ -4?ˆsêÌaÎ` qì˜zÞ¤Û`½RWÌëg"ä–OÇíû’»Ÿúø)ð ;yïÁ«Æ›8Qæ†Ùdñó�* Ø�n˜FºùÏñÐÜãd"‰†Ñ;ÁÚ#ƒ%²oIwE!ºYÏä)ùôÝ¥„R‚sh˜ùR>T4›þN Å9-®I¹A…CÒÐ)âÏ5†ÍJj ¿&”L’(ã7ß©‰å–ßãxòo»Ú�þ›U»¿¶ÑÞ3ÈÔ:ý®±ÙÕ�¤B^¼NÏìÆ¶âÆ0žQ¬‹Ü&á&/Þ»!/ôL£ºOx” ™ÿ08yÑwñኽ€©´tã^ûSúG0ûÎ#8ÛW­áï½�<ŸÎJõÏÔ‰µµÉ8´x'Þo1¦qûÊyY…›pçÌuÐÂ!i—; çÖ)4x»– C<�ø}m/ Ÿ6_T„S/g°uqº´§·>ŸŽ^Æ8¹A[zÏg5«§uÐíÄ üÃyÿ¸uÓ�K88v&N ¬\8�-–e¹ÎX ‰-Ã%¶®(#�xzd*<;µXìê|Å Wé;XZš±Ó›³Tip…«^¹“冘6’à܆w½T„ãŽ(q<³Îô³à…Ÿ¾ KmBÈèñ˜Öþ RÂob‹A2&–Q�_‰Ðµ¥Ö,ÁgìĘ’úX&åwŠóÉ‚5xÈý‹ÂÁëøæªCðp�޼.®l=scÑÊÀ‡+¦p°Ú$8µ²@ˆÐKMVïÁwã{RÜÙ(\¾¶¢¾Ò¼\]öµ~jïÿ�Pï±÷p7~*šnÇùº±"¥þRæH�ðM�âïÞø}±>^®NnÎ 084“]i¡ªbž^­… ³2¡>ø¿õÖÁ}'¾ÚÛ¯u�~zÜöð7Ÿ¬•ôj[ÍAÑGñ¬½,&‚¿Ò^mÍG¤>‡ãÁ§uŽÛüôpªS]³FÞ.a§©êhñËž«WÓH³&1w¾oÓDëâ­ô³¯ ôÛy·WñuO\¢ÔDý–ÂÂûR1½1–&$¼î¶Ð�¬…°Ì;Ÿ,ºB+oMåî�ŠügyÙœ=Ì��Q˜`]&^vwe•9ß ÊC–õâ²EÝcÁ]ˆ�î–Þ‹³nߥn}e¸þþ%ˆ7ª.>iƒ—Èbgë5akövÞW? |wÉCí«r(ë»×¾ŠÃ[b|¶¾ŽuÏ@Þó¡tOf¥ô¨±íÜ$οü‘ojàå­r¨n?H˜ØÏ«"½xÉOs.O•EŸî­tîe-ë¹Ù4ÜÙ8‡ŽO³åóæÉ(5ÝŒ¯š†Rà£Ãl3¥Ž‹âÆá¬÷dvþØ$YªÇ)ç4Ålmw¬õ,³F‹ºîΰ®ÐŽ>È•ŠâN?TÔ¨×íë ÿÊ1Šî¶�_|‘^ÿ»ƒuGÝ]'_¸jî!º7Œ(Œÿç32¸dL0O[º i½Àù§!M? Œ¯©óùúû4øCU…¡¨¯¯Ïêéw$UÉ?�S3ø²eo4™à‰—/ØÂM×Ó’Êî¥éû†*Nÿ�]™:`èC& c°ïÕBêt=ˆr ßaPú9¸ìûE¨rBZÞñ rûUÀ©¢û°Qã³tYã-Hðùôï_“ÙoO©8Ã%•'xŠ8ýµÓ·�:¶ 7�R`ƒ‰.’ź½ñsÅ ÎÿO4 þKò‘m�ß®À�³¿Šæ1¾ø|£ ~7å±EO¡ãÏSÉ1wÎÜ~GÀS¦žS�ë÷GrømgU�×Í·°¿ZÝrÓG‹“q49n'›5—ãÜ!ýbªiÓåÜÝ·‚®>Ây‰ÊP›'pœû&ØLaËí\a G 0yÐ !ø€ýõ(×åæ(\„­!û³šÈCÉ&’ ˜ÅÊ­2мgÜ*·ƒÒc�pª›6Þ9¦É�Ÿ•—yõh%”ÎTDzß�¸¦â2÷K˜ñª%`ÓrˆôÞuG‡7©´u‡kãp�e´Pz�è•Øv˜š[—óöK¢(íæ*8¨æ‰gfôçý%†h¸°7Ö§.eù•Èég3ùƒ“Žèeò¥môiï3m“uhúÑŸu:zÐ|ë ¤Ñ/�w|¤/ËóÄûãdiãÂ%â¯8ØÌŠJçÓ~–ní|#ŒÒ„UÉIk�*Î+©ýo+0Ù¢3œ-¹›Ë°†¡µ³!ïôWÁÃYÆŒƒn+xðÊEøPý*îÑÆ APpÎ[«rî«9pUÚƒ+»}¡I«äø¿eY�~Ø�ý”“ÅÁë‰mžÙâøþf°ôó št*¦oŠÆ3V½Q\æ·¢‚P«ø.%V0oÊÙ*öû#`Líu1s[9`ÿïô·U]lL@ÿÛÝy²l ÜO1b¥Äj(7òb8qUìç:½t´ÇÐ ©°ú¶onWÃÊSQk]’xëçŽ+5ž€ÑZÕ¸ÊcÍ}“Ĺ/¨¡z(…îRÄ‹KüQò« l›1ç‡;� •öC“ɶ]Þ".Õoæm«Saý�/4¦O¾T"¾O„ÅZÂ;?Gîqþ¤ÎŒÁWk‡bϺëp¶y¿\`‰…%ÁeÆ 6¿¡�§'ÇbØê…¢éù™yî1È×|&çõNtk–<.ŸÙPß�ð‡Ò<Êá´� þ˜9‹7—˜âû0[V8°áG¥œT²ÃçûÿÀù, üþÃflt§^Š.tqözN•?–!—(ô� ¤|Òç{—^ˆ “¸©ûnš¸³Îù»Bîf yöo„�‰#„ø¨<×0¼®´ÐaÏC¨¢}ŒN-ÀÓ ¢è|õ�¾> Ï�‘á“I¶0ñ`´°ò¨;'ß#¬˜{TpqÉæ¿ó ÷O,•,Ü+8mx ߬,Dáœj‹âï§Ö$tº *”êjS\ÁwÁôÊoÑã˜Q·Ò¨x˜'ÍŠáoÀ&:ba{Λb@r”¾þF‘“6‹á;½ùB†<*EwÃ-òýpòÝE¨>C�^ÆsL¿0ÎîqÆYÍ–O †‡™T¾Å�ŽÏ¼O7úOÃ;—PØ«éøBý{n^u#t0a›!†•þ"Ôì€w·‹y³iìº(ƒO–¬ÀË:±ÐóQ ¸iÉ=þ[r€®ÏÆçIšdÙ±‡vêŒgé�El�§�“§¦ˆãoíÆ‡‡ðò€AØyRJ'‹¢ènè"ôP n©ÆñXÍòc¡ŸM&–{M€—£¹js õTZHÜX…}†o£‚±ãø™·>¾c�ñ=íÅ›»qL“#�ÿÊÃZCÄò±m2ÛÅ`M|™îí‘?èËËFЬý ‡]Z¤�÷Öqhß2z:µCtÛ°�êkCÐme Å §éIë0n_~ÿžüIyí{(º4ò�¯P×·CâØà�´ÛÉÿ/�oüvV8§Ö)ฎÛän€?] ÿé¨@Býoj˜ô W`õÀkPð£瞋Ž›úàÓˆrÚ)¬Å͇ߓš‚-l±â 盄NóÞܶgɼ×ü7ûFò�e¬YTZ+Áà@8oYž‹{¯ÎDW'°'cZ5 �ÇYÐ�©SøŠž;½Þ<‰�L[ ¥ÆRR››Dï<3Ø%½£dr’Ê%Ø4³¨N.ß)' žÒaÛŸ}„ó¹6ìPã‚xo–7 ÆIªñä=Ñü.f°÷ž#â«&U6Ñ[G×Çûð©1û¨Þª‰6FΡ= ± �£Ð,cÇzksòÇ ¼H®†Ï]™Œ©Í|ØõÞ¹÷äIr·`øÀ_Y½Å +#ŽùE|me+ÏYˆWʺh Åw��=�S•5øÌÛ0,Z,L�ìmMŸýÞÃ.Æy<°y=�÷$gåp��{!-ï@ÑÃW»EÀÔ^u¤·{h@_ΩÃKc¶PHÛMZûf½xsæ&¬q=I·kP[G�ù#ñæÊC‚]­Ë>9W!ûRlj‰ã¸çÝ8w|x¿ÑÁwûóæõ½póš‹Â{çƒ|ì„”¯4+â€CºQ'…¨°zøyòÔ�™Q`Û÷×tnE'%Hú‹‡ßìÃ!ö t�¿ä´÷ ¼þd£ HOÂ�ÞèËÖyë–AUs8Þ•�få#ûÅ¢£˜)±Æ’?:¢ù`wtsž†—’ö@€Âvþ\¿¿~®:Ý Ô¨äŸ$ÃOm œÖ¢Ážß‰Îá^šwã"7ÊÅ} ï„£UØËKŽ]Öî"½Æ~Ô¨û�Ò�¤ƒê¾G¬Ì¯`y±Ï¿éJÙCWÁ”©Uô»ë ,^·ªSñ2Ø@e|![÷ÆÈØ‘ü|¼…»Fñµµý¨ÍãЖü:÷[Œ¾´�'¾Ý'<ûMíÄÇ…rpìk:˜¸“ý§JÜÕYC6ÍqÐnÿTÂ^RÃõ‘ðñ¯«t £’¤kôp‚ÖT™±©l7Ø #úiSì�%Üz' Öyœ¡‰•IöüsDçû°?³n&Úp£Ÿ'§/¸GþyG�)qüÚ�¶”uâIO9– Í…Êg ñÉAXç 9ãIµNH®ÿ)´E d«¼F”ý|_´(3`Ii7^6{*–uE¿æ1Ô­ð#¼µÏ·»r©2P åï-xÞóö„ÐáîÏá«A:˜6P"—ôA8vßF¼š„”Æaò.mŒ_â꣛hëÕ`6¯:-$ž…Áñû„ûf.g'Qán±Y+]: GèîÛô¼ªËlÕØ`ì3x?Q�äL¡.-¥ö¥»¤cŒ5qwŒ%i›Ÿ€�¿æ¡Ñ�<鹦> öÏTÎS†È�$¼—ë %·baRËsaßÿ^iÆŽqýðÁÉ=Òô¶|Jk*ÆN!5©òS�Fê1£œ,tÖÑ0ýþBTrwþñ¥‰~5 ǹSWóìóIÂòÑž¤»_Cóï‚Vø1~ï}ój"ùǾìðs4™ í[Ci€§'Ηå1VS}«FCeD&e—æ‰úèÒÔ>™p®1Ž'¨³OU>¶t]îž]iw„q… YÒ¶Š:×rrY9Έ準Õ(µ‹AoÇ °+qã/ףЕ‡íh�G:•äÖ'õ½uI’¾ý™G× V—ü,�Þ¼]ÇœÓS—€Ú¼ìZ—H©{âBÿP~¼V_´q äbÅ PáÏñ¥)d统–×õàc[g ËnïáÉÅÐ[Î Àx l›µ‚¤ö ù³pbŽNŸú’¸í#‡Þ'x�âôþ”I(négÀb¾6¬¯ïƒ4ô¡~ð Õ»åò9xy¢:»Ù©Œù#™:rýš�—j;%ñX«§<…šWò™Í‹9úü\,8.ƒ·\R¥Ÿ¾Úp3Æóón¥<5ö†p.w'[Ž‚ù®þ€acà°Ê|ž1‰¾ùç™sž»)GÍNñæo¨i¾ÀoÕÿé/×.IRähN°Œ†{ŸóP}õòª0¥ò_#1ó–ê!e¦Øcƒìp˜{6«fÁ�ü:ÊOðŧ­ùSAè{);lêSæÑ2‰ÐHbC§ç”j|åÆÌÆGª–,È4’Óžö_Ò$5p8w×Pè]ïz¯Fõ‚�¼Ø«.çNàF^@¿ò•F¸Ø9È%LÅÖoV¬ö3Â÷dМìBî¼ÙBr;¡~b2^xº^š1-¬óý§éº£ü¢7´Ñ¼÷ |ൠïk/™»'IJõ^P°î4)—‘IÙw±vk M^RŽ¥~7¡£®^; ÈSdÕ1Õ4~mNÇ‘Öx&ã·ôéùBª«øHÉ9}yJƉÃ�½â3ÉDZ÷¶kžï#å²+Ô?ú24:Ëb²¹)2 F‹ Why*@߯IXᬾÊBØþ&ÿ8=¥_¿4ñœÁfáªd/éÏPyœ]æRTg0¿ÿ¶ ¿xçKÔ_Åë@cÜjW Gï¤ðÎ9èÝÙœþ©D8 ‘¼4?{ ?¥mC¹ìº þ¹Zñ&½;Ÿ yŸ7RiÄN4(‰¢Ð›nx�M¹ÊÚl“3‰¹šÄ/¥swÁ“µ8ô’?-\yOâÝw•Ž¡»GC¦ájXihF�W�dÓ33!ñj–SR£2¥Õõ+ó%dAgˆltBá²XP0 þTnàhóñ$ÓmŸ¸>e:§É xd� OêºG…G`JY4Ìs¸(n‹‘Ã¥†%r[‡ÇteÐôûÅëˆa ßlù3×ü€B' :õ]Y¤úßøÞX 7î›Äç^láÖ{£ßð�‚Ž�ȳgfAÑ’><ÔÛ…Ë &iGésöx6:bLKsaìãšm_,±ø¼nIïòÁ¨dLýP(¶oó!—òfzåŸÍ6÷ÁůáP®¹O~Ò–éiâUE3¶}ð‰,µ·à±5½áØ‘ßÐǨ#X¿�ßÉÚA;Äß%ÏÄç·¢Æó \Ûdîà³5„Rÿ¼€3ŸØ‡Æ,â‰Ú y¸§™ôƨ\æÚJ¹öÚ\³ç-´TZðaLÁYMþ8Ù€‹O‰î¹èøþ¾8¬sªz§€8MƒM>H$#�T@‘Y9%çÖÂÁ„­(þóŽr~ÂÂó9ö¸9êe˜cÏG!Ü!ðØ0GhþÞ í8ªBç£èñ‰TK“øÝÍ�$5Ê{GpˆK9^Ö_k¨ñŠ˜o´=P‹�¤ì�ÞuæoÝúð©Ò3ÂÄ©†ÐmÐ!±J›W�ÀcŽ]€OÝ-ySámº®¿E²¨î•è³W‡Ä›’FS4~{⌇ëØ£:F ±ná 

ÊM«ŽÑÑø\>|)ŸÑ`¹ #z0‹6ì"�Œ@>>²YÐ.ûM?^理Ê(5õXîÑCXºÄƒ|mMÈqTY<ŽJ}ÅuƒpòÄá\žyŒ4â”0ú—v“â]³0xðx±ÍGY\£/ù9Á¯ø{‘‹v¬8˜¹7oÃõEõBÔ 3qçYÙm',RÆAìù©é{üÖ9�Æwä€ýùÃâ¤HKñè±áÜf�S²’¨|®.·»WÐUvï7™.žDŸ»£­ç r]Ê‘ïúáÛYí4Y¿l;L=w«S·¸oðá½2æíVÁíŠÓ*�ðËTsز7†Ün¼ß_ÓÇm¶1¼÷ÈGÒqÆ·~~¢Ù#yùH)únRF¯ˆ41NsWJ=ÿ 41ìÛ>P¿y”&^RâKãZ¡ûvM|·È”o u�œ`üñ^¸¯fzôaûû[éB¶2%ÜTâ5jâ/•Þ(³'�†µ®Àµ. È?Fàôïñ´§SC0kôž¡Ì}m*0ÓH“[ eø»¾&®ß½%ZÍpù·ù ‰„Æ__ÙqÒ5Ä.¸Ü?H·êÜvœ –��c&§aGÿK°Ý×€šF`û®ëôvÝ=\Y¶™eæ¢Ã¬�p¥è,\ º,ÍœOò!Ÿë^]‰‡Ïj¤AW”pv×(Y±@"SªŒ:O2ðùs5¶-¬¢k¹—é²É_1Éx‹ŽÂçãå�\ã@™IßáQt¾wö ÝËJçðYNy¡…±~køŽÚxhë1 UªðÍå7„øIЏh�·€ÿî5 n”ô�»�ÇèóÁÌqìóÏwÞV-.òwAÓõ›9o¥/«˜�E³¬èÃþðŸÆP¶ÊšKãºfQªú&ÚÛ²�LŸ¾›ËŸE_GCnp [̇¢NÑ4Ü•p�¼6òÒr˜!Û‹>ï/§üÃþ¨¢½Æhªp”� ¿grÜïÞØày 7धÞ�Ù¼‚‚š5øÇË\lõ‹ƒ‡´Ò˜ßh‹M ¾T–’utÉ_ê!”ÿÃÓû3¹4Àqª¿WB'ë‹ð¹P…R {òå]6vm”t¦DúÛk§¿2‚†H÷:ñâ�Ã?„£¯{!{�hœ/@�Î!!mu^=kÌ%Cª ®Ü‡TJqÝÆçYñxÍß_µ@å3":~X�§%ÄZxùe�´~éwèû\ w�âG׆RéKw®°ùI_Œzᮓðý¶Qüg•?OT:7¼TÐÜ¡,í…Ï�â¾™1ð’O‰»Îp›‚À_–(‚)MÔñO(Þ¾+ìû‘NÛÈ<›K=4/ÐYéCLžw€£eÖ€Û÷|’É–b¬ÜPÞm^r¶o铟+ø¸¤à}�ß4ã½kô4—Ægoã-Åg¨òüfºr5^‹8mJ6Ýp¶Ãº?Í£[Á‰�©º'8ÀPõîÚÞϾN%ÒqÈ'CJRH �ž¸kõJŒ´º }ÝÕñÉ ä·�ÿ£¤w]g8Ör©^N*ø ×ü±@ÿ(\ýf Z¿E¼üÙ’_4ãÛ‰M¢jì%Ò�þA/‚”y³·oŠ[/VµïÂÿ^¿¦ë›âøe¯˜ó¼�n€; /…ÉêGxÑ©H®;†�¾ Ü\�Vû€GTë=,–-ÒäÅ“?5;�p�ùd�tI]N½0ýÉ2ªý&zyžç”£«x�y5,îZÆ×Ž> ½7ÖØ{mˆ�ÐAWV/'�UEØe›":ÎìGOö‰©3 …¼ñrp­�ÎÒ¢ý—H<îlë¿ÞóǦí•ð5R‰Ô9"lòpÔöñ¤îgŽ£©²'¡!m»çÉâGË3´zˆ9ºÎVúêqQ<óñ"#l;„Z×bq°„‡��ýÇ»C¹`u©ßµäËþƒÑ­U'jÞ�náî\)-óÅ!þµtõÈBšì8�ìûTÓÃÁù0rïwGÂ(³8>µüßëÿ¯æÙÑüF°÷FE\³~%êYÕ�Fv_8¿,–S“ÿP|7e¬²é‹>ÉqÔne\ÒfŒñ3½)öñ3zög£pAØ/¬ëVÙ±Ø8,F”CCî ¨×݉ÚC{ Í¹¸Ým,(¿ sçÛ´84‡º4ñên›áÈO*œ˜-½ðÝ }Ì[HÚ3�¬ÞSGO?pŸ€þ=ÇóÇ%˜ý•ö­.‡qéS¹ÓÂÆ=¾O›¶¤Ûr…¸CdÈ~}ކDÜ �9¼Wñ(8}ZÕu±°qnQ—¿dÅ‹_dü¯ïš6¨‚ŸAuúÇÃl¯cxG�v@»§äsÞj^—fÉQÆñä°þÔ8‘§ÜlÞÙ³4j*¹\×N�¤%aJ\¦z„Þh‚ä{v$;ä6\»­ÆÛìæóÕ!}pűtžkPÀòÃKÄ êótØP™Â^ß!Ù5��;` ×Ü®åSã©î…5Ÿ3‘&�څǺ¯Ä-¡cy›é-êÐRgÎÀ•É¡ù ôy‘B+ÛöCs«Kê}…ßûÂàÈ,%݃Õ{>BÜëŠèu„~�Fß_ÿœd_’өݨóìé[ty§£1¡¿-:[­äÃÓ4$Ñ &z‡sÛøžì®:†[º~mì´b“«µÕÿ pÈ‚WßÎ�¯§ ?Ó…ÃÎ&â´Üš��u�¡RÜL>uX\:ÍÐæÒH ¹œ;=Ö£Ú Cr‡¼tì*Ìù;�k¥›@¦v5¾PÌågrâ›Zxºû5JÚüSø[”Á+ô#«½Í4\´ü‡;!ÖΙ32ö²Ãò¡$þ-}“N9'+aÏžJIº.ºßÉÆ�“yËÈ;g‚¹ >ƒÓ¹0^]¥Œ‘íc1tŸœÛQ .ÞVÒ©1CñŠoèŸ Ââ-£`뤣8¬ÇHZñ$›ö©ÚâàÐ1üìF§ä¦“ººéñ|÷4VûJßµ‹zÖRñŠh;×í_/ÁxEW>0f8yN á1‰[vÛSìÝFˆ{†‡<—é*À¹™_M-ã€hGju ŰˆüG“ìê®3G?¡�ûûÑŠÈtäOw„£’Û;zøü2çç›à‹ëäSO•$W·v ;�aPû<å²ϙ܃¢yßA/<€>¹`˜õUNîd!¢W<£A.¯šqš{IBaJCÖÖ/§ó2cxlÁxì§hGqSÓê ^˜¢åï­°²þ>¸�sF,U‚ Þ/ÁQg(€2sUp†÷+ü}ð=ðüAäûACæÞ¶�*,£ígÇ£öuž5°žß¥èã†N]N:+‡KÆ��§Z+ þ¿þÔ+7÷——åù1j‚â¹:¨qƒ¤¯œy ÑЖQ8+û>ý,7Æ×T¹v÷H8tü¡èù$:½*97!e«05û$¦´�etº?‚øùÜgáŇóVQ˜°CpÊSc÷Ìþ\›¤àÐïEÌ’À¾ú´ÕÀÕ*í™N‰ý¤%â¶;ipdDûŒ¢s*+èYÿ^bʞѧ‹’|ÝYQ_ 7Œ×F�tWÐ?œ�M“§Ò[ý™xvW71ª)�/Ÿg»—ãÉ{A?š.ËW#rDãþýÄÉÌ<øwJ½ëþLþ¨ÖÊ.|ŒBöÛ nÁl¾ü©A²Ôe?Ü"¡ñÏ©?~&WŸz:âcÃs,‡ˆ�Êg6�ïìù!�¬Õ&n›T½nã*u4Þg8m«²à¦Ûáþj\=Æ?îU•×x´0J\þ²/n{>�Ôù©C,Ž,ë�¼-©=8 ̓ÃÅÜG÷(æ„÷Уœ<²n4.]ŠrS&‘¬Ì1˜84CØÞ>‰MÛÀ"S?è©ÄK%½p{Á4|ˆmFÃÛ�Üµá°øò|5›i¢²ïQ_¥ÁöœfŸ¤“_•>çÚÈãïv|»"›Žyt‘²Wpûê&<6²†öiþ¡%™Â½§È}îND­ß•p\¬ ¥t!ßAÁ1|Í£Ø3QOfXá€äzxyÒˆÃ×óí³k¿üZŽ÷œÅAª®üÈê”m<Ä›Õp± À½ïìsËmÐÇ?«äg¬¡? $ª,�›qé�åœòˆZ‹/×íJ¯e›ùÃyrr¤`—ß›{Ÿ€MY_)tC²0½z’d–ë–ÜOÁ²ÍR¸ðÏæ÷õo…Áje¬m4Ÿ®,4¡s]ðžÄÒÏâ<ùÜôVM(�|)±™ºŽ_ï%Ÿç—$wm¢•]ÊØs±¯¾Ð§œfñr÷åè§{„dCe©~„>Ïï;*"f¡åßIPU³ƒ¯ÏQ'U“;»qê¸4ˆœ·ŠK‡ÚÒ•ŠXÚ;¼�E­Å!Ùsqæ÷Þ$ž¿jùûøjÚ“z|³„—^J¨òûÔüO¼,#¥ðÐi WìÄþƒ‡²^ñy2ó‹ï æ02q“]•ΆîžPh†µ6G`LÆpZw¢]¾ˆG‡ÿ•~~i"v?Cí:S„–ÏïaïØ£¤*_#Uß] b¥4?ú‰+þ“Cvc\„ߩϠœ…`Žõ1<÷‹.ý×È�®p÷’¡p7E‘W:·ÀâÑ·Áfv¬˜ëѼú)ðë{�“êXYþ¯ïýNH''ºàdgu<¥»I´ê9 kÚY¢2e´ØÃg'ÞZ4ûF…³í¡pTï1l“›ÁÎŽkøhpõöåpÕñ7™]<�E±Ú·ŽB|~RKéAÉþÕÞðfûEòÝ8ƒJoŠß·â ½`MõRªû° ̘�Z±íÚyd˜ã‰&ëKiØ”Ü1î5u˜hƒ?\ý¥MßG¦âÅÖÑè+-ƒßCaƒ*aŸÜ(.Þ<ŸO �cû[{©fð} „£ß•å¸iMí|Ñ ×†Wñøø-Òq/ Ï›á|è¥5ÏvÝC^†ê|ëi§ýz½\ŽYVI®9äq .ÙdÂà°kBÔ¹\©¨ÊžñSÉ0´�&9ÆÁ·Ç°Q_LìÚC7§ü"ó4ñ°MÝóMåìØ|ò8¬ÁgŠyŒÊNT�Rà7&€¤ÛŒ™ñZ¬rÖâÓ‡}hû•K´ç<Œ¾Ü~ß�øý¯8ñFïsÈçò…}=ÆrE×v8µ(O¬Ìί�Ã_§n`‹Gáä]}þ©X©iËaôJœ î«ÐÑÖãïš±ÜO5œ^'‘\è¶P8(\¤“§1îÐ8U¿Û¿ oŽ«óÍç¾_›m»­”l°Ÿ€ùÁd:zعý¢µ¯·‚÷ïuXç+8y`êô™8kà\¬~ˆú<¿^û&„´Ó>ÑîcÚ¸·§&Œ“Þ&OéóÏwÞçr3¶­±ÀcžûÁ÷r<+T„ °8úOf"Žèæ€[i-†Žš"¤<lî8qämGÚ?b�¸Ål�èK7óBÑáU¢÷±³ôw˜¶ßm"sˆZé^8,6�º;ÉqÎikìóâÜ!cô3 „Q×!S±ò ¾­a(R@u�‹÷ç‚ü•´À#ÉâUq\”9ý:¯Â·FHš”Jfg£þŽ*vù�ô“åGò+ìÃã‹™­{òÞø‘¹|/~A[Z•Þ!þÎmæ“�'’æ£Y’�rá¢RþÚÒ[Näˆ ±‚¥�, W¢À¥}TêŽF§¥x»ÎN26Ðæ³‡*%kJb×qUš8%¦ ôÓJcׯƙ'F ÕE©‹ ÝüX+]öEò6CU¢¶á&é”ÁÉ_�9™Ã¨a˜5Ø–D”Ñ€'×AÞp1º NÒg1ZèâHŸ…بáA~MÇÉig>ßÛäN•Yá˜tvç�O]2 ØàHž‚J.ÐÅ ØfJB´a"�:D.GwàRÙ8\íc�Š?]éN¡ܽ#ø_Ê!‹J’úæh=˳ž`éÜäk$ö(.ÁØqËU©ñ ¶p–ãøEî‚]R«$eâdu2œ~ĈØÿpêkb×äXº¨‡ßú¼¥«‰'!ëò.Üõd7Ú_Õk'>³£�Þi®àýäqÎÏ<¨5S"ûà¡pWgÖ�ßN§ÿÍöùÓyÎZ?ÌZåNå‘&ÿ4B,ŸÏ{FEqIqUåÞÉ �öSèˆí1qöWîˆFªaY »î$ ½&XÉä°ÖU¼²³„|{ÏÅä‡ïaôövQòRÎþEíFÉÏÚ¢ñ’�˜žÝ6pÝ.EüÙ’#µ{%¢[­/:Ú?¢§¿?ÑýѺt©&XÜŸdÇ+GP^Ë$Ô)¾ÜªK$µzêpªO¼¨æ’B‡[Pmp&/sXLÁôÑnm$„®4Ä©ûí_ÿ©6u'}sàÉ—VÓÐ iPœ3¹E�M“:iË\�/å¸#GqÚΣR©þüX<‚õTBhÙþå4º–ŒBOõ©¹Ý‚îé/Æù'Ö¢Uâ P6S�S�»ón‹ïÌå,óÏdcp‡òŒ³¸Ù¿66ˆ®óS[—.(…ûRSŠ^žÛÓ¶Gâ½Ø5XUš$^òÑcÇ=5‚Þ[réQvGÄO6k¹‡¥<ï[“Êš™�¡>Ë‹vê‹J)±Ô>s)öŠƒZš«8Œvl¿¨¨Î{²îP¯5j8)ÊÍ4�ar² *œŠÇ²ëÏ`@d5®ð›‰ú1­ÔÞÓ’­Gf F-o%ÝšV’Rµ.XikÒæˆtM8Ì ?‡`³X±êÐcH¶6á/íÝp´©Zÿ9N ¿À¾ÇÎXúPƒ7úÙÑ��Ò=}^}¿š =ypîë(ê5Lô~@EdƒðsÞX8i¤Xý-ZÏŠOÖ{°´OÄê“ý°.ùv6m§Ë5ͽX+7““3áÃÓóÔôë çü9!|ú£ÂCxÕ¼³ôÞÎz½÷„ËÞ‰cwFà ††ÃªÜíÚWáF ã�Qî…Ô±Ö7ö۽̻a«�ôdX§´ Gh ŽÃyoçó‡*ÜÕźnhÜÁk3Fƒõ+àüƒÉœš¦Iq׿q±Æq¨ï7jº-Ãk´I¶QÝÁÕmÖ¼ŒgíµäÂq%üòÁA>d¼€=®”Àò£íP1²ˆ,[·ÃèQ&xóì~nTî%»T ¹v@à˜ßbIÔDˆ˜²O›] × ^sB„6Åbqíì§Tžƒ¼°Ââ úófxÖû àò£&zhs¥m ½™F»³ûó‚ôTTè?þô¡ºô½tÕ¡˜#nd’göñz°¯’B·Ë9‚M«;ž¸gÛz:¶c#Ü“ÀWü«§ß/J;s»IÐVV‡%b%üLRç¤ '¶h¾@¡ÿuÑçæ¡|4:÷}¡7câÉOÙøë¾»¯s€Ó&³«×#U¸•ö…#×ȃgøCv´»F‹)å½Y§eÒÛL‰^†è4I›wÛº¢í¡Z|ÞÔ ìI �¿ùQõÀ÷Ï¿“ªxMØÕð§ôRp>Û“:¾/¡Ý9íô¡Û'˜—vgËi Î¸ÛbJÎì5]Ð,)‘j¦¸¡–ÅI¨o$VÿÀ=a°30R�þ$}%5¶Y?–^¿?«lÂgξsÞ¸O€äµF\kwEœ©r¢Lð —w\Ž}Æ+í�mR$#IÏ}N"R ¯Ñ"[²²·h TB¥©ŒEV¡zîs*ŠDF6‰lʦôúó÷çïú\çœïwv„>3宸b8YršÇ·ƒEâAع½ˆ |•hXò%áÐÉ:Þî|Sl­úMkôðâ ª+î‰…Ú ˜í5�çͦí:o!é^*m˜„ ®ÂÚÏãXuÇS8ñú,mU� L솳ÒØ$9ÕE[Û€ßÄ@7-Þ°¥FÑÁÕ­¹NâŠ+²üÓØw¦Iè¶Ü8œ¦;Ý9™wÓ¯�«YO¾Sš5¾„oÀW™‹ØÛ÷©°`æáÚèíÐ'´ü=úýßN�ÏÍM@ßáº} W-PÃL?7|](˜Þ�¥ª§"6ž¨�¨�£©êŒk¬÷¤ÖA»9-¶/?hSq•“wcÛí¹R‰© õ ?áðURxµå $r-ÞÂêAÊø¬ï:Ô:6•Òƒã4f@âòFÈþëÉâê©ØýW<Þ6R•¨LÙ�×Jgáï×òplz?Éçå¬á×*.(į¤:\û¤77Uݵ‡æƒÉXü¾m=v_a�÷º®Ó¹éÓ¨Üb)çÝ9 ×ù0H\ì)73—ß'€Éª[pòMÕL\LµÖ™t]í)©®Ì§3¹Z`dº1ÉÓdrÉi^o©Ûбô§ßSpìS Ì]°ÇùEc~€DŽû.¦ ãgùéBgJ(n®sç™ïF‚X¥'ùÚO6r¬í¹ ¬Œ/‚‡›+/ðÝG[^æµ!ØwŽhôÆêkàov[(o5?ÀÊ©–¼¿+FºÙY÷—íæ…«y�Y_¯PáU�£k³ {Ïm%½ÍCñ�‚ˆ5ª4;í0.›0«R3„ew-ØiÑTŒé!BÙÁxØ®Ù�}låÐÄqSa=„z÷åñ2»ð¬ÇR|K‹­Úæcܯ7Ô-ヨ¬¶çë ¤«¿ÿ€Ÿó°UÊ/žKw‹Sxx¹'nY¡„«-³èéWOh«$¢Ra_µŸjb˪÷­èÌ9Q2†FûË/×Akk#÷,rÝ1¨?P“ï©7{ö0Dãÿ2xhæ^ê3I–ž_qàÒá�Ô%#v¬ÜMj{Ó6€x£�8ª �¦ü:IKcaÑgKt‘Âçê·ñ“èÞ¼=ñl1�]g¬}ÍŸŠÇ7=-Ôf³šgtª×+6êÞ$&ÈÌ`5Ýåü£w5ÙŸäË žJþNù"­¾`.yÔöo^–äO×-Ø„#S¦`†’�9 #u� ~$Ç ‰urØ·³�?¤'cýš]eo¦ÆRý—>ìeÜL¿²lÉ,¼Uéâ ÕK0Ó]–Û_?§®Ù‰‰gç³åtkÚi'Ë“7Çpñ„á\í¨É¡…E4>ý¬³¨ãÐb—«ÝðSûãϧqÿÈ¥´Æ–þÛÛƒ%ûz3�ìËÚÉî4~ð5|¬[Ggf�…'hú -þ:–—-sç?OÛéxÎ2¶�¼g/åíËNHú:4rÔ¿[793�v}�›sîý»C{(Î`O¿˜ß^Fâ«Õx6ÖŽÝ"ÖÑø iâŒ_£QÅÏ…»ž�åõ#5 vÈ1iü_Ö�/ E·‘ßVMÁ»ã¢ãø›rŒ¶\‰E…9GAù•�h« åS8Ûõ,�ý×�ÊM°ŠÒpYµɤ”èë{Ñä¾cY®¬ì®ŒÔ‰w5üyÿèhõ‘/™+ଚðÖé <û²¼ÌÔha�'ªwna'·A˜hvR¬Sió¢2žzl4_Š z=±í‹×jc͸£Bš¹šP¯‹/*œa°K¼Tév�8µÙ†»_ÌçþÑ”¬ø Ò•k Ø2S�”C¯sbا<¥æ÷ÿ¼[Ç.tîsò8Óg"ËO¢É_¿Á›‡}ø�B¦xDC]8²"ç­ÙÆiWáüI!¬X]ÀJ>}Ñg×eh›wŽÍ¬b™&[.“æá Ó$_ÀBD�©Ö@ûsö³ì´gJ>mýÕ%¶(Nw|1`�“uÐëM4Þ[¼25ŸH.(çp„…)TOïÁör·=k°vÅlÎ9À¥'‚U R©]ìT!l·羓r×R ö¼“=`5ÆÚžɵÝÜ·ì¥l­¢¡¶ü§aìÈî…raÛ`~R:–ķ¨5‡Qsò'˜zpCœŒ’»Nye”®!òÔTu”-5ái²ÄC·cÙÝYžÛе8­•¸¬è½H“A_­dŠ㈮²È¹0§�j+áÚ”<ü=jF6Ÿ‚OÃM0ýÏ@ì ž‡.W" oH?® “ú5ß±hí ijgØHÕˆ«GÌæ5»‰Rò)}x ~ÝUÉ�¡rü°×iièYc¼TïÇ×÷÷£¸Çþ”•Œ¾š³ðóÛžÒdÓ©â3[Sr¹l@�Ž—Uµ©âgŸ¯bªâCøÖQcegr꥘µÖ˜­6»òr…�üÐ[ír·ñd±K4OëY8¤}óö ÿù1ö¼"O^µT8·f-�jŒ„ÈrOèº0Ç]°[ô³® ìë�\Q¢Š{\†ýŸ~ÎX§�S&Ã%×…¨Ú¹ô×¥ŒÕÞ›?x ãwÕKÊ«²ÑŒ˜œkŠ]§µ(£ð ˜î{Áûö=<Ï­Ü5šHãâ|øèÿš´ö7áɺ½d¶°ŠK3¹irÏõPàö‹båµ’ü–)T®¿�£”Í…°÷?éFU48Ø ïéR¸üìÍ­>/HÎ:ñ©¨žèç€�Û©éLç^gÏáŸûò©‚› ¬6å ø™Z(þh}ëâ¯QEo†ä’m¸ ¯¹µoö®#]© ;ÓHZKˆ›77Ñ ûñüÊGO�Œ&æ£H®l�È;Ó»ñ©g3qˆ¡TøÔ§ f}‹‡/Ò]bÃ)C´)ðF§ ‚þ«]BG’&·^Å9f˜®Ú ó,-P;]ÌW6Š^{ÈUï´8Ò¤.L2‹ףȴd5÷»óú',ß|·DÇ7¥|ÂT‚/µ.Shd®ºOšzâˆ^j®áÖW¥M¯ÚïQX\o‡cg¹Š½� ¦œ9¡ÜÙ´�ä$»qª§>ÿ ›€égÌØ37™«#Ã'ålÑÎÍ>t&Þ8SW›âã­xþà/�Ï®–FNéI…/KÅÍ °ÏAc¸Ðߎ/lããŠÑl¶¶µ¥ã |úò ž_É� <ðѪå¢å?÷îL�«7`˜Ž:žtøy&1аLEÈN×àm±”:N ßö샇/“GVؽú.Ù­øçŸ}ÅæÑQžu_šÄ†�WiÒÕë´êïnQ¯Gw6È/‡­ŸC±MÁ'ª“C™'/Q�äác€^�=‡É÷CwÍ¢Ž/’Åó¹Ük�-7 -|ݰUö¿o-ÉÂõMõÔÖøœ>•½¤ ÷錞7_±‹¢+$X¯±‘j/|cóÍôSÆëŸWê±³Ã_ˆnÝÉ÷FyˆóJzãnEÚf$ày]uÎd�¹�Žx U‡ÿ~¾M£úÁ”©Áà/3�f__ÃmÆùÂMù:aä¨Dì3ú‚ØyÌ€;ß©/è‹çÛk ý~±d§²"®ªE=†¦AqA&íùæ…—Ãã)òj*z$×qÀçj1þ8ÍǼ,?í¡˜x-•‚v†ó»�/R� t­Ný8‹ÙOçò†£�âÙ–rœ4Ô�eÿD³áá °öç5P"xÙìvqàs´Ñ½>'ìùv�\reT¤¨4Ö¦/Óvm’‰©V•ªýÒZï‰+-¾BÌC^{Úª<Ð\þ8y™(Â¥Ö¿PTáF Þp5ë%¨‡“vY5¬¹àQö|Ùb2…íÅÓcW`i¯ |o« Ý9x—ÖÚ_§Q÷´ø×ÚvR¿<Û7؉¥+Ý©Éz..rñ¡#}‡ÁÑËiÈ>~r5<�‡ß<‡ ûᘬx®$h³êâéBã´gÐõP ¹f‰\dÑ×ãjk %‡vTtXÇ_ã1j樷 ë“­%uá™9RÊ—éF“*xÆ•Z·¦F\9qö˜×Dwž/å†87~¹V–’ß s3¶’^òBqÁŸ4°yÑ@ù‰½yý�ï¤8æ¸ðz¤%Έ1áË×Ó8ÕN3—ÎÁ�:�Îõ¯réþ3cÎ¥‰¾xdæTqÇ´Ì3êÇ«loÀ“ëfŒšÊEw'ÁÔþ¯ë¿>Å3ÇtC¥—:ø°®Eüü®W¾L¶Àˆ–xš2a¦ë;ÁÜVÿœ÷|_�¹¯o£Ðp¾º­ÀÍGy‡Ü9¡Øüsìï6Qœ»úŒ™YG9šbx9\åTÿß·6ŒêöPôâ_b`‰,:hy²ç‘Tv™{Æ]¬‡÷Kº`„çb‰Ïû…د­S¸4wyç`[õ&Î÷6F§W‡iËäf –ÝÉòd�^¤WxhJ“¬’ÉÛ)„ç,: ìbÈ+³T8¢ôô;ŒÑ\­™G÷aÊ⡸ÞÍ–ç<é‰ÓjÎ�i·lN:P€á=lj)2)Ø]Á‚ΟŽF·^•ö¿žMqŠ]%7–ÛdÑÔÅyÝ6Y(v´�׺; BCF’q$Iƒÿˆæ†úu£1²-MZ#W $Ðn[+ìgV ¿³î�^�ÍÒôàVÚ 7'Ît7†¹ËNÁEÉg²Ü5X½¦à²Fm´òzE{õp«~œPÙí+Y—ׂá¬Ý’ ¼AbÇ YLÿ×Ѳ˜—Ð<ûˆx¯ý>ýäv*,^ÏY³pè°™¸øŽTèaŒŽ\ï‡U?a宑4^�J’9U·Á%_g0Nx”Dð:Z¼¡;~fåo£ä©Üú/éù[2esµ�›Ý�/¸+aÁµqàïx§Mê3§[’áâatv›?™c‚M:Ëé£îpv¤ÇÇ'¸pƒÒ.òg0{΀‰' ¢›‡ºÿkmž}(_OÞöï?�ÞÆÐ}ôƒâï<#ÇwBšþ]Ð9M}�%°ëHEn¹ÃîËâKÓ{ô`^ TT¢–�d¶hÔÇù�þôZ¥]Ò'kMÏû^+Ñ ugª]nËKáˆ/½pbD•,+ý`@• �XbÍ_»¥Òù»3X3¶Œ{³Üí^¨2�]ºÍƒÿn gMÍz¨W¼Gf�³pqF?Þ_9]òE§ T!¸¡ùEËŠæ‰FBõû tÿ‘Ÿ ÞK¦B‹C8dçi‡ã«5[„O“:…¿¹ �ú™ªgecò«bÜyCйRFêÓåH£Z¦"¹mÅ‹±Xv:7÷åÛÕ7`¡ëÚ2ºgáç—6¯e»�Ó`SÍPTžŒû¾N§[îv  "ÝÊ@uŽ1?ŸM~)ücÂaÎ[¿šÉQ–wÛ-½ûi¹’F+O —å€û>–‹Ù†“3cè}?øô2O—A¨åèñ½Kœ¬°‚Uƒ.Šï3òyÉͱ¬¤§G›T¶²ÉÆÕ¸2\ž¿]È<lp”¡¼Äᜢdû«hPþÜw—¦ æ/\�Î}„9NÆ|Ô$€~læSón o·¿…È(S N!þc Fl/ľ9=àŒñ(:áÌçžÎ„‘ñ x²Yýó5xõᾸøçyª{¼ e§ ÊÕ`é¢LV¡3àè:†6XZp¦_46-Þ…ÅΖ€o�)ì«5¯ÒÂò7÷ñ×®~>¢ÈÙõÔ¢ã~k÷àà vÜV/˜mž�K¬¢Û“âÙ`é é¹»¹±>‡M—kò¢V|øa-xJbø�’×kº=Q•­<…SJ¾¼ÈN…FTÑ©ÁAaY!L¿´ú>Õ ÒŸ7hÌü:ê]r——ŒìC/î ¥ýòûz=b!Þ Ù†I‘1Rï¶ iÖÌh®FG/G¢4£‰’ÌW’f‘ûË»q{mØëÍ`Ÿð£4é¹o¶= ›-@�ˆp>Ý;[üiU¼"lvš‚OÜ´øý×HÚ;l&ϪÎnI„«ï[‚¹¿Ú] bçwoiòÕž(g5ò£NÁÃ�¦\*×@fƇHOl£C4)2äõó_ħ/X£sÇlV ��-×Ôøbž&[+qýî­=Ýý|,XµôÃŽ1�l2y%šÿZDy?²©4,ž¾ï6à©Ö!4âEøõÊàê˜oà1Í�vDȲíß4Q6¤ æäý€ËMôyï«Ïº/ƒ }r)|w7äõ$äҸ˛"q‚ÕAú Ú�½t }|a?nÁÚ—°éån\Ò ÍAG–»ÿãC×âQí‡6Ž]~Bì¿|Û*'±q¯Z¸ öž TÀ�/ºxÌXÕµ¬È0³n.mƒ‡=§?-æÒ¢-Ž×yÒnŠ<â¥'îÊæ¹XbÊza çc=Î`/¥ØÍä6dD_‚Êê%¶p+÷Ù†-»h]~�øî¯÷@ôÄZH5—.²îûJ_þ”Æ:tiå°õêpÁ[j KîâÞÛî�Z÷ùhëhÀ¯\¸íÁ!:>Î ”»o,{÷Ùé÷胤R0o´d§ÜýAoh=·‹7„Î啎W$r´�o ‡&e=„G_zboÍœzý$¤\¹#:EËCÁ½bèé爷I`Ù)¶kÄU·vÑåOs�¼b„ýö�ÆšqŸ)J\°éݘúŠæí»wîà{â.l1ÌÆÈs³…·'àÖ] YøVØRöœÌ"¹Ea ´ðņ6Pa ¬MËÎmáƒW´)¤u�´ÇZCî÷t8ÛÈ=‡Ó÷žÃ_WCÔfkH±ê�Ýú^Çcæè©ü ìgHaHp�Ô^c#š�«€ÎkzQ·ú)c`Q¶ßÉ@õC”³°X(º™× aÒû*:¤ü¨üºµ¶©{“Ó¥ha¦.^´*¦ÏSåÙ6kœ4ß‹µÇux”XH3?劻w82‰—h§ì+aý�s˜8¾žÎ÷?Šýwóù¿ë(lÂ[tZdŒ™ ¶P0y!´ÜI‚?›‡²~Ö<� À‘!Ô¸j6\oWᘗÑ=ÆŒ÷èèq·½žœ{& dì|iˆÂ~Б:`?�þ0Àú­¸)¸¨à»EÑ«þÖd$ ý›¼*n(Õ¥¦MÓ_R’W6m>êAW7Цó ÙùÛâ�xNIÌ-XŒêçß@ðI=2䯇7uc×Õ¶4µDŸžö: —½E]–û]ÚŽdÒ•«é£µƒYÜ=·—Ô�Ö˰|x%ù¾«ãµÙÒC›«È»k&-·§-nF<â»-«iÕR¿™ó肘#Æ.>H�;5YõQ =’ý‰ùºº ³D™ôû‹ñÿuRÖ¾¯5oíù{¯~ÐV¨Åò¯Ð¬íšà{|±T>n½0ûk"êKÌùÚ¡“°W/‹zž�“žÙâÚ”ýì9̓ý/žä<—ø£”)vÍ(MZ+éP�ª˜¬²Ÿ¾5bÇã8dýTwß‘gh%ˆ}ý: ïòpß�Žºà†x¨Y%vó²ÝÙqäú §¤h—þKÂò�v'lêØBóV­å'–çÑ´&ŠKÔCÜ ill‰®æFdµ÷¦¼ÕvDУvø6MÜEN¶hŒI³xÊæ„Ø÷Ê É†˜AÂÛâ»%ŸZòF£êÜ�ÂZ¾ðöR<úoÉ„ÂÕA~P+�üî$„¹¶ñÅ cUe¡ã’OŽj Ê_ƒiJ²;_|ÓÎM!S»H�+P}Lo4J¶F‹ÏÑp|VŒ¸öL—.ÂoQ‘꫱äíppx“#^­ƒf:ë@{ÛO±èãì8·ÛûÊÒÒ±+9üu01ü-®y&Z ÅÀ´5 vxÅá0¼Wü×�ÿóÍO­§‘ưý¸=¹�Ôã±cå=òÒtÇe)’ÚšÕpÁñ¹ôÍmª_ÄSR/ALa8¯}\Aý/“ñÙp½˜PÜÿ=ŽM¦=¤çº4SÏ‚2îàc­¹8À•Ά%²ôb"_ß©À{e0O¹†ÏÚ®‚}!c™Oè`‰ªVÚÌ…‡‹º$–öÀ¡I×(Né1M’Ž@=¯ >L-E5xVPµwÖ¿ Ç3×R¡|–HßÇ/ÃÃΠíçËÎ6rœ~a»8K߇uôÀ�ß]¨ÔÎRˆl6‡ôô9T2e!tÜ”æ\”uõy�-qÎÜXaÑÂh¸(<~ªãǬ|q(‰ÝÇxó‰À3ÎËâJ‚ÄÁþ¢³ ~ΉÀYµ¥ôó¯"_5Ö�¨æíB€û**Ÿî€%' xËû8¶HÌæôO2xÈQ ·ëºãÍÃÅE32^›¶+èùÊ2.Úzb7 ä‰>=ùRtOìž{–_vÃí¾¼P­Ih’ÇñBYµRm�Ãð­O$.•:ì$¯Z±â¬,«Mï?“gâ¹€M¼³*ž|¢u¨B{¶j‡ÃßíסVV KûoA»´:ñ| º~´æW‡‡PØ>â£c$Ñ^À�þ£¡©[Ɇ.›~É0ÌÒ–>Ö˜âß~ÚâÑ=¡â¯^˜«ý¤IûeE»´Ÿ07Õë ²x¶×Ò­ˆÔj—Ã)GkΘ‚611—Öÿç…'½ŸóX#6·û)AÍá �´ 4eæÑ‰ŠXÞ®_Qz#Ž$tQc^ MH6cï{èÛ³Þì¦2oÅÞÀƒzñøL!Ö\Raï)úª¨…ÿÞ–á‹PÈ\R5 â1tI9£‚)a&Öœ¶æù5²ÔÏb=8·€#;J׬*¢qÞ…ðu+}ËòÊåôÉ{SOž¼º¬Çýãªê6´ ÚdC°°Oo¾òԚͻdqÔÆ&P <É„½°* LUs×?¡®ÝpÚ|4¯ëÁA%të{CŒÒkÚ::~­q¤µ!8îYL¸AÞF«°g¿"HŒ_NÉGt`çÝ!0Úr8ûTk¡cêm ñqæÉ–2¸ë×pþ=‹|÷ÌÆ<#n~úGXÒ~†^ë|Ú¼¿Áôœ5ä ­!…ߌÙNÉOó-úÜrV›U7ná'#&ò˜s\±¹[i­‚ÿ©V~b•z©eüûÈÞ¿ d>¹+¤•J–8ìúè„ÂÏ ¹pì¾ ÞÆ{ÊFÃ%+?° øoæfŠc3ºSY¤×+Ü¡‡W×b@v‚ð󩦴Í,¶‰dýaCø!Ý¡{@«> CwÐÎþ!˜<³J+ÃØ¼j)„¹NÜD¸î¤„ƒêíHqÛ»¬€Þ:I{4Í…�Å“ùã©‹¶ã«Üø¾GÍRÁs–»é—²,o™xŽ7ÙÞºæé OÔÎK<OÑ|›AÎ|x>“à“ê¹è&í—ÖýË£$.zn à\zKP~ÿÔe¤¼ .]T-FºÉb÷á‰t T&ÏRKî÷†“JŒ"NÉ�¦ÕÇâyÄzü©�[—€GÏy‚D£t²— {¯ÔÇÞ‹Æá]#(»y£cÁ0º§´‚®‚›ýëè]‡ÛH¼ÁDú@x`j‰Ÿþþ‚gŠÓ!äáªVsÃUWܰ{?¸}û#.zÀiôÐãÝÉîžêÜ?IóìÓ¸½ûlnéΚÞC¾B³¸Iñ6¨züÅnë÷“ÎÕÅTsk2½ë>Z ¸ÒڀɖSkl8ºv—Š¦ÇŸÿs€9ð*®‰i[cfg2ÿú¾Ý"õ±Rçßã/òêòl½g..*º‰´K5C츛¦ÿ¬ÞKkß$ñ¯¹±à4g*kÉŒå]Ó qvÆsÞRÂæZQðü׊øö�”|«…iYÆ®N ‰Üúò \1]�ª2ûiçŸ 6Þ¬èSZÏVo#(%÷¸y+ñóo…¥æ8o\Mh˜Í{- ñ›þvti }ÄŽ~‚wG½yä Svz?Œ¾$[àÂ×�t% –®-ÝŽê 6’H«ý4Bc6¦©˜â]‡Cáv*"ÏXü‰*Ë—óÈ)½øŠý3˜?êý©ºŒÛ,œñBÕ^&ÛÎS;Þá¼óGaô~ì ‹ ÇìZä{Ò¢xú'˜#µ*ééòžüªÍW4Ð Äœ•/àµz2móSä=&ÑØ\ý�”d­¹fƒX__Îwcú1éAú-‰}ÒAŠ+8(èä½~mX/Öh;Ãp‹p{N�8± ý3fâÏÚ>ìÙÖ­ÃC3¿Âû½AgÑ1ºsç©.MF-�ý”9v% _=/]SmÅÊoËÎo•ÇûÕqfÖ[žq)FjTÉøîàpòŸã…}#£ðþPCÌTI½cQ}Pý¹ rêl_ ³°æ4ŠŸ_’Žw¬„ÈM;„mŠA �w�ß9ÊÁ?ƲZÅqTs��X3}W›îCQ½4‚ß�[‚,úÚgÒ�>št¯f¾Øc +4‚€¿ïÁ7ç,”a笈˘†Enà{3øÚŠ»ôùïb«Áþf»ÙûÖI( 3Eü—á„!ûéî‡å쟭Œ6í%°³ü»èa9Q<ë=…Ô ä¶ä4« õÂÊÇ¢ZÇÐv÷™Íš¿€AèäxdÀaøm Í¥ë'П�Ûû6öœ¨$¹tÇš—•mÞ6-Þ�>Ÿ®ìÅCÄ=Câ0âeökª€Ëñ�<ëéiH�Uåyãåðò´Xt|ë%n¸ˆ¨»x+ßOµ�¡qÅtîuízlw_ìä^ 9³C¿¼}ÛÃ8hÕ8ès 7ÿ*÷D€åçIì¡þX„H»Š™…V8˜’Áô¡Ø›‹ºzëI%Ð UߟåSžÒ+.§=öù¸YøÀÁÌÒÃ8U~5ËUäž´BùñJÜe¬"ÊÞ܆}ëÅ_ÝÕ!l³ [EÝ€ š¸ñåzžrÛ’ÏÆ6ñçA*¬<Ë�õÙ‰1µ í\9ßí+IzA@B‹ømv2”Þ餀ùYô¼)‘C¿·@•éNR­TG;sic{w~¦5”^%݆ªeÊbx{ ¾ûÛ�®6GqYE§øêîxÞ’Ñ»âZ–�èRv ¶: îêû.;'íÆ�†M´¯¿Ÿ·�@‚¢ôTù ‡\ê ïÃ^Sg@‡ÎÂn+cq“yw¼¤(ÈûN#ÍÕpèõßp¹>†-Ìwqýs7œup&¾ž¸ZúÔèØœ•ÔjŒä»/÷AGNëŸLfOŽÞ�ŠÆ Û›—²_áÑ÷¶7o²rÍ ÛãBq£²¸§/·›ˆñ»6 ë‰bNÌX†EÅ#à¦kÆ&«ñ½ŒRÔ·/\VEƒÔ²àżÃx"+œ÷½À9Gƒ¹½Î}“qŽg•Åébºl©0§ã&IÿD²:÷AÕÖZðÝ6Xð'‡ÛÂû>> ­1Gý§?àH]´pr½&Hu8ô™>çÍ)Åãj3yŽy5tSmS=÷�´IäjŽÀ˜Ž‘è´¤H(;¨€Öjó9+t™° m\ñÞºdV§zÑ-n8��¼á¼ýIOñ�ö.ìŠ GåF%^‘¢÷8Vž Ä%æ›i“\/ûáÅwû˜ã¬U¬2:µ˜bQ£ÔŸÍ¿ß¼ ùùaù€~Ô4þ/´YÚñê^m䛎 zÏàó‰{’G…†Üž 'EÃnØŽ© —…—ñz0z¹1žØÔ rCñÑN5|‘¦ÎR¯C8\î"w—ο”у#Û¸Ý{f¬ Šv¢`ï…1Ÿ^Sø€Stʪ�¬^‡nÛˆ«Ã%¼ýž.úhVáHõ]عEB5Á“@ÁÝãäÌPjv�6–\{­�áÝFq˜æ2ºÒK-|áS NÙÛ2|q¿„¡eÖ{8·î3lRºÍ ÒAýV›hZ³˜9e²®µ�0pl„p$Èa­µ;ÉpîGEaKíÂ=÷(~ÉOÜÚ0“‹“Žã£7;%­£‡³MÉbnxôœ;v¬äÿè»dÅÛJŒºƒ!ëxô‚™8êîjºð#’oÚœÁ#»‡ÀÈö¼H?ƒ»¶‡£ÌQE¾ðç"‡ª~ƒ³¨pvŸ´Ä[¾Q”²u ÔÈ|‡ qÕÐ\4‹�fZrÊ�c8àï ˜RÔ}ð³îrù~]‘óöÀüI®¨ºÑˆó›pÀïþ|Pu–ˆKøp°=~1* ²DÉå÷bÏ)ÿñ„€l‘ŽE×½~|$¹=øíˆ¡©Ë8aûvþY<Í.SÏ4W«†qâåߓٶã~^ò˜Ì¶Ùáö½`ÀËÞ®ÔWºÙóöœ#40Ljmû=Áÿøü„ ož—γëð‰7ŠÜ»rvÍl¢Ï)ßà¦í ÈWö…®WÉ©à:Œv�Ç÷RºåŽ}–Ãò9½ø†z—-å’ài‰²_ì°Ííó/ÄóIá7¨õ1Åã ÿã�j:øè¤ß*–|º™!:Vp]›°K…4¹ÿYØc‚v}2ñ°Ó7á饞xªÅ¯ËâþïÙÞtÎÉæøïÜëÎÀKã!üäfw×OÖiÐi�ç_¤1Ÿ:aó@[Ú‰ÜÍËÇ.ˆ€�[ty]¿³p`°2tT&ó©›½9ýéj¼êgˆ?õ‚AÙÜû>)åÑómiyRÒÉBÒyOâ×—`®ì¸óy„Æ*ñïŸ6ʰ‚·Eb'ìǂ˺¬¥–Jû†¾“¸¶œFwõÓ4°r¼ø:0 ”Ì,Ðóã1éô¿}imÿ1t[ë4\üXÏ[ç?€zË,­·Ã©çGÓÍ#=ù´n/:ªp“ '.Ås-ðÃK8Üyž¯ÑA“÷‰°Íï"ÓœÅ÷Ú[1P)œoÖ]£©}XË /†ßJƒ}Í49/‰·]#ås‡ÙmŠ/ðøÑh}-ŒÓDÆÚÏá4ùS‹R—��†gfÅóI™Xݹ˜ Õ#P}ë¼su+´¥ìáãfæ|>t8Ɇ%²Â-ìuà WzË“Ããè´â\eš ¿÷$‘¾Få¼€+Õðؘ$Xø¡“޹kàŸßí,f>bË¢Px¸†©ìŒv�Gq› ðFö°]Í›î2&ìy Q©5uý´E¤áfµôéÍCl]ý[<�ü�µnݧDåLNžä‹Ûàæòd~ªuHäÁu¾gÜ]» 'êïGßÁò¦�ÇéîÁjZñà 8{æt~Ûê‹YC’¤Áq2¼åEw�ê®ÀìF�÷fìmCbp›ïp°z%)¿Ú,~Ý—Â� GÐÙMÕ¸f亳Λ†'B협å�º£VŸ~¸Zïžøö“2Úž‡š×ùôb,gÔ×’Ýâã0]Ë�»N.û”رÛÁ‡Þ‰àïÁž3Ïò™ð·¬•”ƒIšðºä1»9žŒýoƒcO_Ô¼[EK+â‹}ïAY±Ïn™Îk­ éÃ|Q�ù²äòÕ›c¥·¼×ÐJÙsë‹ZÂ;3À¡w$t$ýây;s1QáÎ�¸îƒ¹+4#TdÙu­��ï¨)ô¨Ôç'²ù¸ÖoDm�ÏiU”’ VEC÷¡WË-e&£‰A|ö¹Á¯~÷§Õ¡¸Ã¡’¢]«H5P‘5»á¾ëެ»#žug*Ó­%³ùù-3¸ÔÇ�<âãÁ—°þã\!º&‹_MzÁ…e`{É�=߆~ýû£ôÛ\¼uãH$~Üç¤*e_O_³G<)`Ec9çågÀ¾ Aéd™_ñ‚žÍ¥™ŸŠ@èö/×+¾âÆe_aÿÔÏ•þ—)$¾?äÍ꺹¸Þô'|N:wOôàP[/r�?�?FsñX=´×\É;ï.'ïþšìl|‹ÖUT¼3Å“WŒá�ãiIwl�Z°®[Ïù‹'’a”™=‰â�`‚£Wg¢P»ýg£Ê‰xþ`ˆ¿A¾ö(\ûø¦NYÊË]–mèGÏésÏK;ñüÞ½p¦&—¢�–°ý¨Rt�´„f >€¤Š8wÑ©Ûy«­X¸=÷j†@ù…ã$…øó-�{TïO9Âvoäqq›ü~f�OL¾Ók>F¢ƒ;˜””ŠûæDQLìQrÛ„[?^³#³ ñÙ^ºg”ȇßùáÅoñäaœg•béú«q޽w)€Ç­bm|Îë§¡ ×Íkq7`¬“1æ”|y<ìnÆžŒå1rx†.‘ªAÕL,çqó÷âù'Syð–,>6Êm·/CÙ§jø.¾„fê¥�û®9”q-Ѳ]Y±´Ë¤ üßÞòð5—0ß5Ìêì]qspZŒ¢Ð¯ÿ´šø�üÔeùNÕ5©‹U7þ8±®:íAËÇ©%ȇí.{ ºàÒi8íyæÄV“ÕÀÐ}eÔ°ç�l¶þûèB{Ž…î²±H5è<7Œ{…³ñ?A{f>”g�ãçíØdV �Ùì#4ö�Ç‹oPäK¶ªÞÂO²P“i1_èk…AåÙbÉz¶o-‚>”y½ç9¼YùŒ¬‹¬…N¹¿ |ï›ËíC˜óâ¬P%?Rº®ä+ž¿I6ÇÕÙî?nê©N£> .‘1ðtì|žÚeÊ.O~‚Šý8¼ veÅPŠFؼ̹_ÃËæY°i@¬ßÛ*\ëe€_§¦CŒÄ‡Ü»ÉÓxäÙ“Bß;¾¬¾ú"9ÉÊó÷ve¼ºÇ˜½ê֢݌¾Pê³Cüþ’¢øF¶œ(ßêìçü“0f­«ðؾ”3Ëæ ¥¿6^nTÁ‡ºwhˆ‰™à~z¯ÑÑ�\?MÎ.y}ýµ0^§,׳ͻñ o&ývš¼/Сü4Î}Å_z2ž¨¤ýrø×¦9°¬Ë¾°eiïÏð[ÕÕ*OÓ³÷£Ê-‚?HG_Rä'Wº a¢cy<-{�}ÙÇ#¦:ãæïâ�9ŸèjJ)5ßj€ŒC>,ÏÇÜÔQ2{Ǽ2Ä­_¶ÐÁ¤bX»Ü ‡¼ çä(�Yº�Ç  ÃÕûáò%^¢S 3¬4„iãŸÂBåc ¥R ɇt°yáê³&Qœ¸g ¬ò1¬x4Ò=ZÀpo’ždÁßÞaÍ3_^.š‚½†T_k‡M†J«@|彎››!cH Œ�}Ÿ¯ûFsõó©ìãdÃÖë¶Á&²Àó­0ëG,ÖYhÂøýÕ0ñÑ7P¸6ÿ$óï)öøµª8ã8)=1Å+3±ÇÅ}ÒAÖ>�hœþûüw,¿ŒÆæ¥Ö4&½UôÚÅ ³×Z(ù+[á.èÑ»r èþÕÓf¾àÅn+ʧ•›ÃÒ:[¬¿lÀ× %4Úc›e†ëp=ÕiÉC¡j_¼ÙxXcîÅÂq3K|¯—KÉËoI¬/æ†ðÓTQjDAMi¤A®x£W<î®JÀ´?±·¸B,ÜR†ƒ#žî)àÝQâñ¾#Ѭó;¹Ÿòâש­ä“¶‰L,±P·ĸ›�`Ú ºx ùÙü‡û"søUP¿<ŸYsùZN¶Ð|L…'¿VåÀî‰åmEÐøal=�‹÷Ìä¬nÛQë×\´‘èâªx{~~á6ÏHý Ý?‡âÍü‘üèÝ6ÉÍÙ¬;d(^°Û'æ|.c6á°¨qµÌŒWÊÊ“àŒ‹<»y7 fÇûÑý^žø)ÿ$7JØ^í²8Oý(=ÁV+2y�{š�q{¡èíjËÆš`^P$îÜç›=¶ó’Y'ù]ï_ä¿<´=¡G¹‘8Pú‰²îŠh¸©€æÏÇ„ÁêØm¡- �¹�«'<‡ößg1ª¿dxú�é¯hùoç{ýÙˆ{|Æ™ ·„ûépQ·ɽéû ò]+Ç�{'˜TÝ;™oo‡,ôóˆané§æA�­þº ËŒ4aå17áþáçâüp}>p¸Lx8¿ BÎYrÇEchµ)§�˜Â5{³Q[»„–û¤�Ò.gaŸ“þ<ä.öô|AKdòècÞg¨äQÔþ]ü×Õ¡¤mÉ`½·IE=Œ2¬D˜°c0Ü>æMc”ò±Ð,Å6A›ÞHœ¶d&´ß7¥^Át-È[À³ ­¢}UñÈ…ì7Rº°zÒ?–{KbÁX6°ˆ¦fm'^™ªÉn® h”kÂ3no§¢B-Ì~'š-›êónBÃá±$í,�~pH˜YðM¨Ž’Ç ÖÇ©Ÿß=èõê% æÈН¿ ‡•U!áíHðP¤^æQ|¬y•t]È\ä«Í‡…ã°XÅKh|¤ƒ§þyÄ�ÏÚ<êêJÜ8gè8 ç„ÂÈU°Ü¥Rìc¯¿ÝÐÖz)wqÕ}h÷ú"ÊjwcÖº@[í´±0Ý?u8Á`Y—/ÆsYé³!¹¤:ò×…ûi‘©e×Ðcø#Ä5ïC ïê¢ÔíðõÏ7Òé4ƨèq�Ù1†¶�vÇâéíµôÜÝ‹nÙ ¹l8½>8–õùI[Šþ~¿Ñ`ae<×k u«Æ?ו¸n˜OkC/Q܆¸R/¼û°ù'ØXò”¶ÕŒC¿8Z0"xù|’}u™ŒÖ�ð?F®}ƒ¿}õ˜á¸Qùeµßü ¦�}̃Ž`Ã_¶X/ðN�18oT!ßjM†ò§û§äñøî|%D%Ãsµø­ÆˆÖEK¶ö+—¸ÛF²ŠÌ>Ös=}="+(îù� ]ðõ“Ý’�þÚü«’Ê�ßga´ƒ#zOé�çFÛJe+މ•�—xµ\*HšE·t7 Ú oØiŒa³L)D) Η&Iþ,Ë…³+ §ÇB ë~Z6ž‚ù¾+Pá~-½z�T»ýûw×@}åj÷Z K‡ÄaØÌ¾ñ‘ôåC)èåh4YÝHn·³iN66Ùë²ÅšÎ9îÏ·–þÖ•©�›$â-ißݰ¿R|1e>-ÿïü4w"å‘2Ýΰ[‚9×_½*œ^cÍ«z9ò›õÌ™zÎ(»€Þ¼…[ÏD±Âe\ôõ òœ9Kñ¹ÂÉÈæÖpÃ\§Ép±ÍW_²2pºü ¦ê%Z®oâéþ)ubŠuCHoê9 †ü)*~êÀw�§á°ûðHÞ™wg�ó3 ]nªÎùVK†©öóQF]ÁuÔyÜ–lê\. Vï×Ñ´H-^¸£Öûöæ\Ë—“ hÿ±åü¾X÷+F«öÉÜ`m ]ŽG„­‡ûqðq/Ö˜”.y;aÏýxŒq˜O‚äØ$x?y²ž}À�ξ1£¨^Á|»Y�ü³Ò«Þ;Q­J�Á¤ltGáäÆÿØãPÌÛ/´†aÖ?4�X~¬Õ [4õ¹Qû_÷C\I;>î$ñ¡<çÀ�ÔLÞó¨–N^8EÙ.Rh·Iç¾7ÆüãL4Ÿû‡,gÊ�r»3öÈ¡âo7 v`<FEÉÍ_ÅÚÛÙÿ_>”³A2Ào=k‡BvÒ<Þ¸Ù�}+§ãU5h�“3Ng³+?iÔÆ‡Ô²Ê™W®½HJß‚–ÌPl»œÃÆSkI'Ù<¡VyÅsÛì#thÂ4ÿ–.éé}‡fz~§>*ì¸×—OŽ}ˆé¿ìpxÈCúUÌJWê*:Éu�P°ˆ{úÈá’ßëaåÂwbÛ®�ôôj+m´O†•æ÷©ÐjŽ î ñ1d>=ž�'=Áë¶…ISƒ1dR¬^àÆî£Óå§Ùø]Ã{çhCÃ_\´’ÆÝÎ6š=±fÝEX&ó�În,�Waüææ@Éãíohvèœw÷ ܘ¤Â+Whò„Ð5Xê^E½Ÿ/ÃY}x‰g!Oǿ_ ]c¶SÇãÓåæ³:ySÞHÎæ�ͦ'𮙦Ëäâª^ÿ<1Þ“=|�:ÿïtÅ·™õÖZ¢ãDuÎ-7áóÞß¡Hõ1DÎÒà%¡þøê®àÂYÝ¥£ƒ,q³}…úŸ£ÐÔ”`’ˆt0:íƒ0N:Œ'h¼¦ö'Ëùyl7ïç§.©“íAÊlÍ$|ýNØjW�_/æñ½Ú9ÔUñ•Æßõ�´¹©×6HtKÅ1åZ6‡“æ~¤%½”ð‡÷ø:;ŽÕœ'âšW"'ÕŒGëK!¸Åà'¼ÿv•Wž¢îAXÛ\ |½ ¨yA ¯Õã³�Ôïg5ßýþÒügñCum>t?¾ Ñĸwaô 1[>GâÕIŽ|µx…ð2ÎwŒðgÓ¤@ôV:Œ†-vxDé6\VHbgãO´+ê•á@pïš° m3F�yÍAÉ87!áŸUŸ§cª“HYõ!_»unÆ<‡–‰_©ëHаÖz(,y~˜O{?Çò¦%ð¶àgù&É–J ÎÙM6[Mxzs¥C§Ø3®?ꕯ#ùAÑpýÑK±Ý‡L½zâÒ¸5bí"+vEÉ€ÚƒQâjý©Ø|A w¿>P6D2œ4¾êQ‚v¸¨%ù+>º©„½ÔåÐÐV&g…sGvñŽÔ"ΰˆæ –<àøbœ8æ"�ÍŽäMÃÇroÙxn5JÇ /¾ã膩²MtwëTÜæ2Iè¬�>Ó:àAý{Z0Eõ\ù@°ÿ­Ôâ�ç� jO£Ä++»•]¶Oâ}K`sâJîßS›Ÿ)}#õýÿ).w®þ& £ì{E!’$ŠHÉò=3"Q!¿)QÚ%E*R)¥,EB¢D»Š3CZ´¨´(TÚh/´h“^ï?p>×¹fæyî›O§òiU°fÝüZ ±ÍæwaIÁj¶—Çû߄Ѫ*dW>�ùË \^£Ê£ä†¡´Ùâ«ÇéxöDîµ} E‹Ò t^‘¾Û.\ÔþG…o‰zÚóÎ]Vl±o:޹‰&¯hùëJñõs}qŠnø»Ÿ¤ ’£ÍbšJ7ëN%ñš÷u‰n×zvîê�)¯!ó£,¼÷×…•_ÊÐÜ«\¬> |ûÆ V€3”½Âž´¶›Ò‰ ¦p;¥hõ ¿Ø#é‡y¡2Ü*®¤( �§�E÷!¾üÍ�BZ½yXlž(9Ù&¨–ÀÉ¿>Q‹g”Î:¥£øñïpúµ±€æ»ãÞæ•´ä¹À&~Aá‚Iì|ò²Pf�Ľïkó� 14â}GdvÀB™Á|ïÐ Ÿ4ëzNÃ�èä¢Ðyh>ÿ7>…v^ŽåAGèßü«°Ø-›ä S\ÛnúÐÛ¶'5ÐFW€Ã/3¸ò�-)yàš*ÜT¼•R;Ô^ÆŸWnþ�‹ m+I'ppœfŒÙÙçW|§Ìާo‡ð¢ ÉtêrЉÅÂ&»|ˆ,Ú‡ÞÞf¨ûK�ìµnÙŸÄÇ…Zl³.XÔvW�Sròاr>o_‹�9jÜ/8Mô°¹�VV‘°«&€o„~Dýh‡aÒÑø$ªŠïÿ¥…Š©|X¡XÓXÄ‹G˜ Ùº»@pÎ�Ὗ‰BÍ^!ùñ8œÓyïüo›—ôîJ8ÜØ“Ê.×}ðË3-Ž˜D7/Â�„"øÑ1‘“£‚(}ÏlkΞ'ÅÊ~S™²³Xïmš›Å 6ñ/ÝFñ�Ó�¼v0^%RáÎbaÍxVóÊÓáÛX£Z¿Ü·aç]¥…ØÜvZÑr�d¿Îà=HvÕF\ÓpMX•; =Ç_ ‰®…»#Ðùí\’*6oÇW …F°æf „܈�ý]„žßÜÑÌWWÕg“£qÙ­¢i»–¬ À“�ÖxÃÜmz°È¢Ú²¥üì p׌@~Zÿ-Ü­ÅE+ÎÀ×yQe]|�èÉ–¨Uv ¤¥¨¾Byq ß|^G&&ÄÑ_¼à?³µBƒ® N3ÞÏ�çîŠqÂien>}(¼EûÕêQÿ¬nò†­±R\7Ë\òûs/‘½JcñgËérÍþƒñ¹I¾Ð¼Æž-*âˆøõ”N!\˜¸mö´¯¯®æ³“'ò&WEîª_�]‹Ëÿ[Ô9.‰¬öºŒs/.!-åÏ`¥%±[H2:ž/Ÿp€-7‡B?#_,>�=‡ŒãeÝ ®WÕd¦‡—¿–/‘™Û ZZ7Ó–!�a@t< À{��ƒÊg–e.˜­Ì¦Á~OiŒÏ>;ƒz�Å�Ö0NÐÖãš7ûñ²÷HJò)……Ö°µb¥©6¡œq_þØIÃ"­9¶ÌHˆ­QÆ®�+Ôj¸‰¿É§ ©u&ÆYÕŠë]�„?÷]xlêxZùm›R�sìpvƒ%ÜÛå+†ä\ãÇ;`T’9ök/~þ�n2ƒðü´:Н=Ø M�ýxÃød°YQ¬{˦icPé{:Ô% iÄa¶:èõŸ z¼‡ÜËçá³l Hw߯† f|ê)‰ëîYbÛßí¢BÇ~Ð{[4(ö{”OŽ©ÝÙÕ2‘JWÞ£ù7ÑÏÉÇ蹜Ï—1DŸcñ‚÷KZe¬FGçt{ž– –¤ÉcÌÐTT÷ˆÂ/�3x½g÷›1&Ôð`›0þº«\"Ò0È€«'ûâØÓ¹ºm³ ¡±üzÅqX¶é€vú‡à4Ò‹šÂIY­›}�Âw:r%3:hÇ SðY½ ÂO^H»§ÄŠq{á[_s§dÈž§Ÿ’ûn¸z׿x/úœV¥{í`J¬Û¿Z† WWÁ½m¯iDÚ.|bÌQS3YÝvì›ï'éü©©KzsÝ…�z݆¾Ù¬V\Užpj)ØÉpÀ.Kˆð&¹a*89#›WêNÓŽþ ÕÆ1œT¥J6«äèûùóP0ÀˆAu¶wÒK¹s‚ÓüÁâƒÊ2zx­†H´ðè -þ*�š¾íBÎæð»{®k\Xp›ðAr`•Ü3·…æ o!—û ôÒöÂŒÏÐ`ébÖyw”ÎŒ: 'ÔbžÝfœ£�»ÏúbŒÊYþ;¸¡>Lì\¾R¼þà((ůe·F0b^•ÙJ=ŠðÆÎ½tüs´°�Öb|Óˆº9wÒÇø—p°\Nô˜úT§YòæƒYðya4¼vRáW ¦�9ëuøHƒõs;ì}M�ý—^§àw:x§ï?¨Ê6ÂÆÏiÌP=açÜu2l Ÿ-†áv�øKq;F-¼D½û�âOÏäàõáiüù"9*ØÓCÿ2=>ôë/ ?¡f �MaÊ ´y”�Pá"(í«bËë9˜ä/ÏcTObÈã™âƒ´(ꉠZÚŽä¿‚a™ý Ï&þ5{XÏr ¢Ï�ìÇx\CŽ«‡¬Ç»qháÌ’E)øfçøwí8xz�«>'ë¥ŸàŒ‘%wÎ÷WÊö‚™TÅYKBð‰­,îS؃[<ó©}ÝL^ ÷Ä×½Þ S–¦Â¬ÔÜš6‰SþmæÝk¼`ìÝ9ðÏì¹:âÅkµb?÷àê‡n'ÒŒ‚(œµ·ˆõãä1¼2ý†ØãʹñÂו]ÖÍ)þ?Ðß—.‚úÔN0yçÇsmRÅž»¦ó›Ÿ1(Sh… ¡¶8üänÜ3M�Ãî­׃xÖJS²¾Ã‹§iÂ¥„;ÂÂ#¸Ï˜zw7€ ´Ê…­MeõͯÐßð?Ôqσ5³œÙ3ÅíJô)š&C¨Ñ[Xqç2Z›Æ¡º›É¤ú(Ub"ùÝk„×³ï —ÆÎåÙ¯§Š>GóõºL¾ÑÝñÊcé­ëOè}Ü�®l˜Ím¯…‘ýúsس\:±¦�,ƒ¥E§}Øœ¤NÐûäÿQÁA­øÜ’3øp’!]½ÓW°îåIwZáå”å8Õ{l]…¥7¦Š/GgЫj3¼=ÂË~ˆ´~¾*?½f‹®ãR¹§¬jÍ:+ù}b:Oþ>‹F’ÀÉTº}¯»è„Ÿ" qCöB>úB™u*ãòÀñe% ȯ®Ž¯;ÀŽôtr2œ� k‹Ë½ÆqÞûrAs‰ÕÞy/ø»ªÐéö�­d‡«KF Û vß Ü°4�jíÎQñÍò8š„šg;ĸ…ÂóüOמ¿¸W‘ö Øú¾?ìÉÊ�â%²üút<ÎÛ³…ï m�|ZÈkòLðí±aQÚi*ž„®ÃùxÙ`ªíµ�1ï¸ä`õñ•½)Çç*ãÍüc4çâl[´;ªàg§îyºò´9KáÞc=2ïˉ'°Å=‚ª ³ÉW½^X”'ÒÒ‡àÊ+y �6…P}{úx|¿(1‘Ç´g#H%Æ~l3áEYå`ýh<6•×ü£Ý‰2å÷ŠŒàùK<×+Ôå¯íŠXwj>†»ìçú^•�œ ®rÂ,´^>ƒgy�Æx‘×NÚÏÓÖ¨ ÷ìñÉv?(L¸L§ç¬ã—ï+@ê^ ·Oë�±ÿÃdŽå¹9S¸X#š{�׃•ö _‡ïrï¶¹Ô7†�¢çu×Ò×rÖõæ6‡7ågu×ð®«ÆôÏ“¡|PÅjÅ‚°¾<}t!�Û©%Ôê¢bµ[$û_¦/{Öl?¸QÁ²ØCÞ–ÏÛÇŠ3]¸£›­öå̦êŠß¢î÷zštqn<<”V€Ê­Iøel‹°!g ;š ë©J¼y~,Xï'ì±–ƒÿVÃý4¾1W…h‘ÓÙZRDA3 ÐIo�Ú§ŒäE››„¡Fæ4àl,ÿÊg�n–ˆVÔÀ¹'ñûšwd¶î™ô°ãÅÃçó©-佸'Ê=H¥�:<òìKú{GƒgfiQf_[:KfïKâÂ~ÙT¡Úá‡Ø™•°>/�O-ÌåWûá†ä8jhƒåÆ�bä‘vZjÆ}×5�ákc±±-ȪÁ™‰ ‰m+&Ý_q4gÒSRÍT¯#½:Øbq�Ö�é�múÊÐSAó'§²¹ž;kö¾�ÀWeòEôÄ3ÿP0vSNjÝ2¶À¡Åžg J`‹údÜî«„Zön0Üó»^�çªI<)Õ›ë*»Ho�/—,®æ ñ/èÙµx¶}ô‰Ö.-ÅÃg7ã°®IVVFVw¢`ÌyÎX^Á—ƒ:¡æÕ(ÎðXÎvW»ó$³…ª¿QÑ”VÒ˜ Žš ‚Ÿ ~ 1ú#xÅï/‚YÝ'0ú®-mÏŸJAÛ-ù¸EO°$‡¡štÛP‘Oﮓxï/Bú�‚oìT¿— ±½Ò° ­¼ïní÷€ü­>Ü7$†z ðáÇ5Å;Ux�Ãiçn îóßPˆ‡Éÿ"Óý›\e?Âm«ûT0ýÏ·Zé�)(4•^„+ãÝ€øWږ¢o�¿0ó�2+`W?,ÖKy³Ál ·,/ÖU�®½›ÀK3�–�§]G½Èßç»hÿzŽXÛ…ë)³ô¼n.¶Ž�ÄzBµæ,»5”‚âÃYEM Ξ�ÇgŽ–TÛ>‡dyóI ´µÝ®cXÿ–åä·Á¯ŽbCàwQ&HÎqIB"�¸—´ÿ0Èp‡v¯›°ù… †fÏÛæ!p%"†eï^cé>i ÿT�v(eÝt…&¼"éß²ÜK²‚|¡“(e_/èˆDƒ Ñär½Èõëê^ì²a•$‡M»ð�÷(”ëÑHމ‹ø�KYÄž÷<0¯ñž¬¹¹\T­íÅmâ9þjï�A´Ÿ;njð"U].�Å>�4XùÜßúˆT|®€‡òvÔ|êβMmåÔò vûm�ô¡¯—ÎkƒçƧáñµ¿9n%ïÚØƒ ÚÃþ'°Âð.ô7•¥Ö°‘¸k£<¦G†ðéùrœt.CksZôN°Ìîƒ9Õm4Öôܦ=÷šsþ,5´Þˆþ�×:Hq£³œcåíJ¨¬‰ä™«ØíÎ œld�Í2—°²æþ[xGWkbJ®Ø374&è)‚å�BÉøÙJT¯U Ë3áNx?¶x¨Š‚n'¸˜WÓÊçHŽp�ÎEGÚ„ÿêMÐáüfè}4¼¤ ø•gôŽ\Cï·oE¿ 2Ü¿ºþ$ŒOIÆ^�^�›ñ6r{öúWNA­Æ\¨Zº›>-µÃð nNù“ƒ£=,±gÙd”Ü} 7?Æpô °~ýTv¬J…/—N &¥¨âä&¸¸ulíyJ0§‚ÎgVq¿Üßâ°ÚxûW°}c�ZÔK-ïSŒ¡û%ïóKP!ˆ K–`‰ÕÚ\D£æÜ‡yÎüãGž 3U·\ª®¾?=ÜGQݽ‘ú©‘¼’Ý9™ì–ñTÿŽƒÆK{¨©„‹;— ŽG3Ø!W W;N7Œ}Cv�6¢KCìø(JL/5�Òøå¨WAÏl(¡ÁŒd=õ¸ø“ ­w+$¯ó#ñț粺PœC®¶•P¿~±8®·Nx¡„Žw…‚ý;èNþ%:Vzœ ÂŶ’ÖE‹Y¯2–»¾¬ƒ~GðÐÉÉxìÅE:–ù‘>�ì/<:œs;¿ÁÇÎD÷Ç×¾ø{É1®nÆ28T[¶áœ5[Ag—,ª ¾€&+” §[ãÑ3ðëë‹w;VÃK2 ~ÆSqÖ�"jº1ý±E¬3ŒSÅûëàÉyeöß”H§¶ BÝ 9l}"MóÇCUÒg‡c˜ÓVÕ>&´_M£�¹å�KêùQ²¶>ÀÎçqüÔP.d0»jÀ¹Ý>›JbÞ-¡aÝ Nõ Fn;Éþá“Piæ´Ýn&h”Ü¢S÷ ¡�û&þ"“…¾¿dÿŒ|‚}Þ7‹NÇìñ«Ã&¶jn‡áRWD�M<YNr}Q’Ç´ë+9ÿy„�ÇæáºýÐEó/l(È‚IÝìaÄCP­v+ÜÞ& ‰rR’ykÏŠj�InÄ=Èý'àý[TfŸØ½ÿ>ü^nw¹]“-ÄÿDúp5н]¦Iï�"ªxëpÿŸ)lß.ñT×Eú]²dKÓ°§Þyqã‹ø­Ÿ‚ QkK2ú ¸±‚̧¢ã�ÓàŸ6·™Bòeƒ`÷·*z”ªÊƒÛŒÐad%k�ãk¾ƒKK ôª™ #Fi’¢GÄ»I¸—ÐGÍ&§Æ±�1Æ�—íŸÎ;¶·‚ÔyYÇ•´½}¾q’|fÈqmŸX–î«!ѹ¢‡n‡¤0Ìñr„#�Ú^iB¤ž+~û�ùã·ÇEÔ91cÜü)0\±,QúiOƒÈæÙPâ-Ì˜Ü ÓoçÁšÓgxÔÖL?+#Ì-Üe¯7‰ÁY[¨bô2ÖQ'۱ª»ð¡e ?l<ÔÍdkP!«HôÛ²I(K‰&¤Ëâˆò"H¿6ÛwÕ�ÃØèû;RëÃ? ÝpYÀx|æ³ÔllHÎB]VBÐó�ô|ô :ЬßV†^™ž°´¥~J/á¾Úi4(d%œ¸B;6Œ•Ìé½IÌÓ×Â3ç>CéþeåKÓ ñóá>‚N®,̹€zÆýPÒ±_¬�ÏC>~„B… Lü<Mv�â{‹ácû&4÷6ê½ÃT»Üò»k©}í–îm‰§úp\x}Íý÷�š6V�á°ˆpW¶o>¸þª#.0X •_¼!ºÞ׊Ψ-ûC˜=ŒÁh-¼ê5¦F<¡¼ªï$?G‹G:x‚’r,Û¥�ßÌk¡¡ò2ÜÕÂm»O ššE ™Á¤;žWdöá=*YÂ�Ú¤s•.ÔÍ 6\é\&þ®ðÅ{7[†mÛ³d0hp®ØiÐWnì¡-ZP2dÙJÓ�¹F¢Ó�Kt¾æl*/„½é}éxˆ xR>Ó²—Zf&sñC't¼ŒúÝÁA}R n·› èÏÏ;B¹ÅWÀßÏ€qÑFZå¬ÊSr¬”-yü ‡²t÷àT‘;œáeW8=‹Ã¢®õ4aj,ß0©vi·Qg€íÅÚ¿;a¦ùujrØ z«\¸OïY<äÁzR™`�gB•ðPÏxÝ-Z¯,–WÑÙØxñv�›”¿4M\ZÞíç&zøhœ&ÿ|¿kô¶ ÒVº»Á�õÖnÀ–²~âù Ä—kuȽa0f4Îf‡I$>îÞ³£U\Ÿ'¾¸6�K°ŽöTuÑóp4iÏãºÅ8·]†__Îf£^&”}r+¿˜yZµÏSïccéáñt˜ý›§táÑÀÕ4 I–?_Ú€¹W�œüŽB›Ç85÷6­i_W¾#(œí÷>�ÞÅ’W¼hc‘�JmÉ”&ÚZ×WpÝ|MPã#?$â­!½1Aù—pC¢Äúå9¡¶ö§�«ö f{¦‚õ—bèØ% îž«V>¢åÉå´ZNµ»¢ÈÊy/Ot%VŒ‰¡4/b›Ë!Ýx7øMlÆ�h˜pjêƒö%bð®�”EñQÆUØwå£Xü“&ý´ÀS‡6Ñà ~�T Az ¬w“ìGŒ¤�áa”Z‘C³ïdaiRÄ9ªK:äzó­j?¶ éü É ‰#AÑTÛ§Ë ×›záÇî�´`»<~®XNnšÎœ¶¿Œæ.>'®UÒ¥«e¥iî°ñÝEZ`3Î=… Ý“mT"Y±ä¿²wNïxKÍmQ|Ý="púÜåkß&_8};OE9‰Þ`ªùüQjN!¾êxªÏM:dý�|òbQÊ+™]rœùÄ=QÖ­¦¼ï¸}0l•=Ô¬¿Æ}5ðÕsnÞÓÓ½`–ìxFuQÊÝM$:7ªgIzTÙ�}à3xÑž"ªGÚ‘f/)ú1¸¿sŒ¡Ø“e0qËfÉšÕãxÒönt¯£lõsb—n?ýO†o‘Ìö'±ï rÓŒRÕÓ $'ˆMU_‘ÜÅXèo%ƒ%^+…’šVÈ>v„eþyÑÒOÕtN¾ éfÍ ì•²[�Œ>Mÿd`òf%Qw@^«]€ÞþãIæ²:v$èã#ÛWÔ¿&�â[ñ ‹4’‘‡ïF31l±¶ð}ÃuAÇ©ëL)'Y( ¯U% |ŸRÁµíðß[9|çªÂ&ƒ_’^Ù}‡4 'î!Ìä€ô‡4­j›ÐÚg?¤*‡3¾rÜ4í,Ï‘”YéB}°/8l.Íëù}ˆ¦Ü,¤iæÓaÒÍ3Bb@½RaÙi“¹)c ˜òœ¿‡ <^[ò¬'Ø>£/{/ÎdÏç=Ñ0q w©ëA–*RoÃXÁ{"¬ ËÍ’„¨g ðñÿþú­úlœÅªá‹øöð7 }àLmÎ Ÿ,㟚fÒ†m•dÜ÷x‹¶}<Ð:ʲdX<Æ^²1¨ü}!oÍ#‰ÕZV�×À¶óÙv,\iŽ{×Ü4"S�1Â_pZéI º½Î¡¨²\çŠ5�í0ÄËiT›í|Þ÷ î–é=¹zo)Ü›xI˜Øe�¶:q¢î1?úòß)’»YÌl‘²7Ò€‰ñ8¹ú!mÌKãÚÇ×!}Ã1üñg�8yôQ°0“ÆQ‡M`NãT|¢$[Þžúz»|)/ù®ÇfßçCWòÒ�ì¹·µè¯Ý)áZZOìj˜Ão]�ðó›GtÝÖTè×|îýOª6عçi\7ãîJÒ†[6€�·N¹»¡–ÞYÅóµÊÅgÿ*ÐSsްÃÿ…y£ÆÉm4é°%öÊÚ ÍqÊÂÒžhÇ;h¢ò—'å._×¢žŒ.Ÿ1„Óþó!~ò Ï;Fß§ô™;P»¿‰}3=Þä…éN%¬"lÐÃaŸïÑÂþ‰‚‡ÆI˜úR…TܘþÄC£9dD.Î5dñqÄyºÒ_'膰ìà�í»�Íçq�_ÅD;¦Ó6‹¥àð~ÿÈ5CR!43wÃyì©¥—;åik™/•z³dÄ3q—½¹xmád>hˆVug¸DÝn7eÂÐl#%c�âŽ~»¼£·îŒæPÅíÕ÷íîÓ ”â½2!+0Šwvœ¦‹MCñÚšž´Ue¹0å\#(­¬"�‰}9"ìøªžá#éØ/­»GÊÒÔ»Š|êêC .”¡Èq‹xà¤=‘�r°¸¥'­Ò:K ë%¿- ™ƒ¹gU„˜‘Ø«OÉóæeŠ©½­HÇxe¾ŠÇš}ÈN§Þ–ÿ¡Ã“ÍYâ8÷ÄK‰C•†APïÑ´SE—ýÝ�•'î*³®8x_û%–GŸŽCèß!¼ÒmH¹ããMع6tj%œ{?¡$8‡^®Ÿ!x-Xµõ�p»hE^ÑDëEkÄ'ö})öîk1n€"Ê·-Ï¿wa «1¼®-�' ø šj¾üÐwUGã–%KxÓÞhá|ÎqØç#O×ðïcže5LO®üóŽ"ÝôiÁÛüiï1�n‚Sšç°W¡ïfÛ>—§pðüÝÈöp«‡ hµéaŸòé­Ìò¶R]a®°ZÇB\{¸œóÜ„R«½\TSB�ó–ÂÌ“9´¡f'|l¤¿6bÙóqM�Ô³‘¬½ËyHF˜ð¸MšßVwÁâPeþé[ˆ ƒë@¾cÝ…~ŠÀfYt}º„ÕöEó}Ï 'j²Mà–òƒR2ÖXŒŸ.µ ·´v“õ¡÷”;桨¸í£øàUªj%“zÔv1Á™ž‘xôèJìóÏš³îÁ‡žP¬÷ n÷�ÎÏÃl8é«*ïý¹OÈT~O Y(QÓÍ}{sdÓ$ÚŸ²ÌŒÔèPùHÎÑμ NùJ_Nf¿Èõ‹d>t�wŽò¸Ó"�º&z‰#ŠtñÚ±%Bå¾:ˆÑÖàˆ¨ô_Ìq1rçtÎҶ°¦pÜãyÎ-H#;}Ú¼_© «|&u|K�Ááoúb­S üÚÐ 7 ¿NQ/õ…#RÚü|Ñ1´ˆµa?<‰†ƒ²ñes3ð�ÍøÕ7 †­Óäi¿6‰cÞÑ¢Øø¶NÆ1(à²$²ó8FEŽÆä„iôVç5õèÅ…†»„„øÃ$½d1ËÜiÒè0ÊOì¯9eí"5•N¸´ž)ôs‚Pò¢–¾ØÅÇ=WÃhÃÕ|¾ê¬»ªËÁÉ£…è»%�³;•æ?ô`™Y Ñ\•†Â‘°�øû‚‡ÞQÄvVÇ3¿Ž�{AiÙ}¡}-0ÈÁ£�Vc±BO!hÒE¼øþ8Ø›I—¿~}œ½ÕzÑÕqöœËóä�Eó'ºô.ÇNrîKJ¿>-ÊrœüB¼å{–Ï»÷!÷$V|”a5ÄEÌÇ5qÕ°ËTŸÓ¾¾…¤»} ?L“ñó:Ñ-í„ø¾ß5ÜgOfÝìò ý"Æ?õæÆ-‡å×ÊÉræCñhñ:<½À cÇËóÏŸ¥bá“ÿ¨òÓ ¿>Ÿ@%ÕH f˜qšö"ŠŠSaûQøºæ�´H{Ù�à_ <±å™ƒ¥‚)ûÇeó” }<[ßíå7ÌÄOSªé_Â!·!�ªƒôçæ:þ´à} j�›ì@…ʽ0¸q,é¯[ŠU�ÓHEp^9kNvwoÓ}Šù– FM ²ŽÇtC=«êÃÄ{6pXÙ¼#eø•Õ.^rORœÁ÷ý6ãû‡ïÊ�W=§6¥´a»çÉ8^ÓVË>…¹ºE0·ë-i¬If÷<=±Ãé0÷9BÙEf`$× ´ÔÿŒsÈ€ âcŠÞ±6ϵ`Wã†2›Í8b«+_˜4GZü 9)!¨q ®ÕÅå]LBû¶�èàä©–ðîì'*�PĹ™%⌒#àѾ”%7ò|†~™NU•rV_£Íí××°Ñ 'ÜþÐŒ¼Ô­øö—ßâ—V?�� Ò)F¼jáaÊ<¿€ �:¢XcÉœaŒJFOai€§f= ¼dStÜ}onë‰cx\^ÐÜu€ÚÒÓDÉûhÎô sâàð´QBæ×bz±–±eg¼µ¥ÇŸŸ^£êŽ ø-ºòO…Âýtkè¿Â’ÚR±+Zãí+#8,|¯˜jÈJÊ[É@{?Ù~õÃÚ‚ þ·Æ–íœß“Ïå�ô9&'Ý®…“Ö!¹BgŽðÉ£Ÿ){¡)%ÅžÁÃÊ—qwŽçõúŸÆ+bÝùa¬ –å÷ç�ç–¥«Ùê˜w­\’QlÏîkÌ^ÕA¾�£…±ÙÇØêg¡ð!%…n:°ñÕHÜ?k—ß@#I oÕ¿NW^Ÿób°Þ3ªÞ7ˆûÔ/ÀÎŒ’†¥3 ·Õ#p�fZ±S€ ·S@�Ôö†÷›FÏF³ÍÜüñ¶è÷jþŒŽeUýì2%¥áðïÊ_Jÿ– ÞûBD~.§Î³¢“%¿`Õò øVzæNñæØ W0¶-–L? åsÏ΂�ú¼{œ"žï³"Êñàº7¤wî;÷û ƒGúšp†¾ .út�úöççR�´³Ý‚ås³Ÿ>~k ‡»=ŸÁ0¨K-øÎÇ@âU*UÍÅE“ò �+�Z®Ê©ð\m(ú^‘'™†i0¦OïÐqÂEË@ÿ×'xë•Åg¥/áèœý|f~yÖ(Ovs6Aa@"¶ÚÞ¥Ó™7 å³þÚ„7‡4‚góQ KLÛÝ“ 2Æ›>4ˆ�÷M¹%t�ÿ|̃—7äyÔñn¯YåÃJæ¾ØÿËpò-ü²ˆV|ˆãG‹=pÁÝépú¿m�ÞCŸ~’§ÛŽÓ¨lÔ¨ûþ‡¢•bqíÅùrÇ!©(«À–¦€é�-´°ßTY>Çì¸ Rñqìœ;™ãõOªÎëá†ãVˆ¬ña§ú¿âÅïèé zñö$jX[ *]}ñÁ§�¬ýO‘Ðú#VvØÐ³KÁkô`Îh¯u+@ÿ‰×qD¹€#:œY£pT¬_H+W ( _Þ(ñŽštÐM•”éÖ)“Y˜¾ØãgW�ç?þÚtãrUبF�çšÜ¤Å©úâ’â` »4Œ[·‹<¥Ep9{†?î‚Á£³¸ßäA8R&…•ó¢) yÿyR€ ÉñÅ#ÑiÚ@š9T…¿åE¡ÍÐE<}·7+_¥Ü�Ý»se8zM}B©#�Ä~Ò=v…u¡å‰Ïbè¦ê%HKS†Xqw]m…¥_¦aLá^[u›ŠÿÕ�Ön%á�ö$’ý¶µ-Ÿò½”£zr�à¸Ëj£ðÓsojª^Bap›Ÿ_˜�ZºË¸Âp vŒÌÅ� ¦qÞxC~(µ:I±YóõÑÜþ]ß6T‚q�½pëÖUɼÊCœ·Ñ„ ²†‚ÃÃabÄEU>’°Ði,ÐŒ6žŸ‹×§òpûáð{3®�ŽäAOvâÂLª©n…ˆg9¼þó øuœÿ ÄR5:˜\‚òÝl#÷ø H}Eî‘˹,g ÿÕƒiá]ñ8sû0Ü|+ž3ÌŽ@�CÔ*؈§–ìæd&Ë¡ÞxmÏZtÁ”O;Âæœ˜|_?ß�’sw0猛x}‡½`ùŸ×‡‘Âæöޏ€ÞÝû±I»‰¿¯ÿ©ý)îâx ÿñ^ln4à%Ç\Á¬CAˆöËBÿÂlA¾~±`·~ ü¾³ûA@¿zqêÓ8©ú,u¹5ðÑyG…C ¶ Ï«þ¸`4Âê“t¦S�wÜT¥+ïšndÅP¼®#ûûr}ø> ^;Šºj"9ccO𿨓_åý¦³Š·±u„7êŒ RÕçiÚ)áÊËö1ÅäÒQ|âr›b4ä+·;>ˆ�ÔïdÃs¾4dY;ÌšoAJ±l…{@)uM8Ì7´ñ¤V!®¼^©n{áà <%Ÿ"nÚÝT~�ÆqÁòxóË{ÁgÊœ2JÚRTŒA¶.ëZ *­¼*d73�@OÂÛpcK‘P¼¨ˆ<ëëÈj^鉓%NƒÍá÷·Ã²Ô’Ûƒ�±¯ÓS2 +øNY&ú½•Æ£§¿QÔšuh6à8\ìÎuµOû9t¾ ^(Ÿ€AFÛpykÏÊ'›ËÒ˜«]Pë4�[eõñ²•ºJŽ5ì¾|,ÞÜ$‡}‚×òÓ»†è,sP�;/Ûíó�p¹ê.8ýZ@–Í}AÎÀ†þ{n ŒR–•œY¿˜Ûk Èeìqx¹oR ôï‡ßbåÅFEc2ýワšêÀeÆi8kšÈUÇhªº46-]O?�áÖwÎ?7�"&Å‹Aékà¾o–ø¡×h|×<ØQ'²‡ÎÊ¢}£Eÿ´�|o{#E® Åö§™âå�–¸Ck=†+ŽúÔFrjÊ$žT'Ë2ÓÊyšýŒZw—<Ód›Eg¸\F�?ŸM£¿Ë„ð§3P÷V¸dYGwªPPb_èA¯F±yTW~؆ÃŒÁ|kÉÜqÃÝYy¤ò)îœ÷#—o†í!I©$•THÆs]¢A%ʈÒ@’¶”Ò¶G!+³„ŠB4>Ïu¡oiH{'í]ÚÚz{ÿ„ç¾Ïç<�ã—›ÏÖG¢gÍûßOì©lÚ|ü=|8þ ò!ÉòGäsï VØä³�“’8­î­~!Z~�@½Uäö}HïÍåè–Ù°nûNAkE6íÉ•gÙí±u`÷v5VÏJ“\xþ¤Öü¢…¼pâ•( óŽR£Fóæ�I`? /תÙO?‡=�ÄØÈÝ¥�txΉY]¹Øwp$&c’Yøý\͉oDÞ¶ç=î¹÷¿¨NÅR&8êáiÒÝoÊ9r;Ù§Ÿ)kLéÁM×/S­»ï­Â½üI’Qµ}$Ÿö¨ò‚‹šøxê6úuuÿ©3¥ð;žb^L ¥ù?§„/áXÇ8ú°O:nçÁ÷0O¦UÞ>e·®ÁÿŽN/·Në‹áCø<Þ©*ùô!]ÈNèÛfKÆ™¢ó›]8wá)¼qÁš—õj_¨«ÙÎÜ'Ö +ÅQã¯�Xâ€��ÇyÖÏ<¨ÐDÃ/¯ç#Ú (P/4^SIkì…„´bŠXœ ÆnÏ%v«ä ó¾ÒŽ�õ¬ýb(nV:³#/K%ÀÛ¹ Ù_ðçóîKÁy‘[›m€®RxņÏéØÝÉû ÇÕkù�cwÊÚ¡ü£Ëü\ó,ìõÏæ²±™\¼ü":¶7°½m0'�ñ@…Íßà¸âÒýýRØ85™/k€>*Ž,>·»:\ïn>N>qrøI­Z2¿ä,%Õ˜â,·H.�÷§%'CY]&™[ÿSõ܇ @ùéM|óç ¾Ö›v+íBÿ'*üýØ >77žŽE§ ÞÇ^ ¬V‰½oléæ¹MÆy.†hówß ‰Áóumtu²ºôh¥™É'x|ú ´Øý“*Ó­1rá3²Ü¹�ì�Î`œ4’+öl�8êFà��§`fÂ#ê´ÊÃÒÍ�âç—hèøhqž5uÁå¦1�‡ÆËBÇU!öÉ`8Ö�¬Vö¦6³¥ LùÆ_5u…©¡3(áøXìßó)Ž^X {*D¾´ú î5{ĵͮè~I÷~hkß¿uÝæáÇ_0çZ‡š£úƒå< ·œ/Kôyð×Y¢ßfevY–Âg;Ú)Èá úWvÓâ]uÔr\fXG¥ßTáˆòõYµüúË6Z˜EÓgý¦/Á7éB`(þšHæ}dqçu¶6Ÿ{íA#ÀöêsÙÔq`ÞynY£LÒ¯��¾õ¤]¬ôÆ?�³+-œ·y”æ–˲„¢7‘tž#`Zµ›Çô > =Ðú»¥ðçr6YÌÜÍ›S>ÒüB>Ô\]+·yìxÒ¾ëè¡é,o®×ÒBíŠØ–[É ž‹°âÔa.Ù�;g4BÂHKñËŸ ”¯ƒÅõM8þž%ý³a‡Â/6?Ÿ¦ÀèÃùâÔ›P3‰§Œ[NÕƒ_bQ�:4øñŽNZ·/ñž`†×¾cϸíÜ?l(_è %ã@ШºKŠÿyê�r(¯[B½FD€ûÙ^2§/?]½•�w«aày”©ÒäÚ¹Ciq£ûÕ-�©_&ðѤ2¬¨�䪶ôf­?{T‡õƒð[õ$̼3 î9ŠJu ÂmùS`å˜Àqm:ü¨ã—èj¾ æ=¡(0 Ÿ…¹Ðæ²m°ö¡.¼üÐ�Cé¼qx-lýO�Ž×Ð䣲ø$*´>·%*Òºó¡(õ0€~/ÿ ¦AnøQõjý¸Ý>â�ä1ì-Û›¿zïÉÈ´×#£�ÏŠ ãí*âg¢ã­|›»Ÿ¢±b_ol:¿‡ßˆKïžÓøºÅ¨Rtd´Ryp¥…]Pº*Ü”öä‚86ÒöF7Í`ú<¤‚·UÓmmàì µW•›¦Ýƒ¸;{Èa‡6ÛkÀáKPý¸^0‰jr£ø�û^1ðî8ñ¡›Ž�–Åw;apgõ<˜†l³Á»é:½ÝaO¾—í/.�šŠxžÿ:þæÐ°a·ÅØ s¬Ÿ¨O^‡õ‘âýËó¬ÉÿÌÆ¢xlÜ2ÝD’ya¸øf±®b�ZëP¥9 Ï„¼¡œ=½ÑÕà vÛUÛN žËr¶ýð²yZùP¯=£èçÆZ1ÌuÌ3v” ¦üxi->ü¹.^Š)àâFxUêDå~íÀ. ÙoÁ°™ƒ¥ ±ø§ð=š­ÄM_ZiŸûT‰�ª ×\Êãã_+±)~FŸ‰aËç¶píÏî%¯ÃS³z�ë i6}÷_mìÙxgåTY‡§…H¾fÐ,¨Öš³cÆÞñ‹q´ŸÞû2 Ü—Šv;°WÖ3ˆð±f­uÉðª�*Ô›«°›ú.*NÁÏn ÖÞ{Ùˆˆ«¦0*‡l"9Ùs ûë(›= î-‹…ÎfX¹A ×�à^ßËÑ|È<†rS||U 4µ„CEµt9<+ºÝbù]¿V5J™dp4nlŒ„ù‘¶b\i´ þsÜdy I„br’®þ‚qãžAH qøáÃ�–{’•7^àçÌð.÷Äìõ-¸2:,ƒüÅi™¶8F{%Gm±k»èLL ÖÚk ÓîèðZ݉¼¾J‰IAÏ>µY-&ÀÛoˆ7�–óðgá΂ˆZvTPÒ{/Êm&›¬\º²Õe‡à«™½iý·LÈ©9õ�<ùºÃhZà[ÝpÉ?Ñ6s\ÌX}€¦4‚ò ~·³߉ü!¾nGýâà\µ[LÜør|ž[ÿ\Õ{ã kÎmÊ…•­ýqø¾¸ø’+w—×ÂÊ’ñôñå9ž‘µ—îtâiÁ–+„€e¹°¾IF¼÷©‹.Ÿ5ä^JiPÓ¾îþþJnÚÑÏ '™ÓdÙq\v, ¶å¥ /sôAÛk²¸v³„÷VÅÑÛ3Ç@\zJî^äß<©Bæ [tû0€“£ŠEw¥L¬Q»£®öÅ ÏÇBÏÝév�§sì¥Fâò_v¤’Eó÷•`M÷8ˆIë‚úÞ¾0_K¼m»)8Æ�׫:¡XÙ„y�¡£{­h)›��´Äá&¿¼©‡áãÛÊCðÐð\vŸŠ�+' Zî'iÞ:ìúo;k÷'A…i•�eS’¾©„Å“BÁÿÝ?�ÿ-³ûrß“½h]ìC\ᚄ˷ì'Ï›ž(/nãš»kÉ^I¦„Aïw"ôØ·š¾È‰³e<±·#bàþpÀ%�²y]½;·ÿèGʹK±àB ?”“i\ U§ÊÅ8§á… {AŠGßúa«Þ+¼"Ñø[ÌÙ“H­ËúÒ‹%übíCn[玮Yîø½×>PûcÄ»¾NEõºƒâ½ƒ ä÷r?f\ö'å3nöqóó$6RΘº–6]Ü‹É~ÆÔûŠ5Õ(_öǘÅcSí˜'XðBß\ê=3ds_IBKV�åU ìíÿ‘Ý-@0Û%¶Z¼‚–£«hè¼øhu÷Ž¿ü.°­‹Åô-jÚw¾êVûG£Óo=´PO†•år۾ðÍû/nØi†Á˜ÞªA¹†økUËÿßãÃ+UŽ|iÁ" _Ô‡Ôõ ƒ $tL>J]wYíê~5w«ü{Â�¦çv?öÈ‚�Ž1žmy ¾—OÓèµã°Ûy;œáíMâ3_»‚þåZ88Sš7îäÝÜ4â&{½h�ýº]ÂûÆè?#^,Y³]4^S‚—¼«`–väh¾Ÿ(öR<«X×þ›8~²%µi°’K|¿�;Oô´;XM*¿NóAÓX ¸˜íÚ1Üe¹-žî–|1­W{€ã=‚š Šp½Ä#LJYRKé.V›Túÿ%áéÔŸh××Ï�ˆÃ?jm?—'CϤ}Xy§®|Ißîèñæå=ùݹ\>=ù<éO£Î­£Fî0EÿU­ÒÀ½©çÊ6V6u"›Ok¹tÑNðôµå²Æ!8á~ ®_Éó;qþã¬Äq!ßÀ»<•ÜäÒ$Ò–�ô9Èœû]sDõ¯uâ¯Òƒ¢Žr pEŃ÷=Ö˜­¡££…Ýxux=ÙÖ‚Ä‹·a±R�ð¤ÿ%8ù}7Þy® ó³¦ +Vóò—Äù‘Þ¸iÔ3²›µœí ëR;Aªã>˜ïæ3ÆÑfõžpÎRäJ§º–€Ï§Bús׋gÉ?BÝ¢f´óœÃvy¢Þˆ¡aÍOÚ\¿�–”§âK?õÆP[GLòœÃ=‚^‰UÙuÔõT�"ù©ìC1!û‹ û¹NP”o »]ò(tBØ&{”\=¢®iVœ<Þ Ä:1-®ÝZÝ=Ø* âÛãS³spRi%éh¥MÆhÐo6Û÷[Ééþ�Øòh,äåWÒ€vWÖK<Æ–ó²ù;pò„:ñÚxgq`s"¤U:áùÒ+’^3ÃE­]–ì÷þ ĶÀ½šÐËÿ§pEÍ ‡�–gŸÝÝ‚"jÊGBæPg|3 5>"#ß‹µh#,ž0Œ:–Éà˲.!×Ò™–.2áØS— sQO›èÁ–õßaä|ˆ}ëC'²_ÛU€å9”UìÉN§æs󇺫ӓtã„�±U°vc`©PâúVŸX ¹o£8Uf s7„嫆àà›½¡ùû0îÔh„™ËÓÉtßHöê žù:‚ëÌ©Zc*ß-ãÒÚ±t?ÎÞô�¥9·ÛÀ¢(‹lÞüG³.÷å «ðìÊìùá®0üÞ[zû¯÷ÄãÓî$ðaÍß·RwÕW¾ÒÔ:ðwW u?¢Ÿ6¦˜|ëßX.�k¹èصƒ»C“»f4¿UġƯ0Î(MØ�Š#:ZÅ ½áùçj‰§D¡±õ÷º?»_^�óu¿¡ó¡¼uË^�Ùï‹êC×rá—�¦|ºGÑ-yŽv5áAÏa.âÈ—¬›­È&×ú“d¶Àgu,@;G>;„6Ø�|Ç×ýú-»I‹Ü5±ú†îî�²/ï@”mMÿd²¤YjÇœ5b¤=Õkœÿd-?žƒ»f㺡÷(6W£—$@Šy4¶äUЦ“gÒØâ(ŠXu‡V­ˆ�‰ìf9šekmXS¥:Ó ”ûa-/¿#ƒ­£g1+æ7¨m*!ÅÁ�ì›M÷�øË²©¼*qï?z‡w•MäºÕ'èòÓ,ÈžlŒwûbÒä<®µ–/†BŸ\}Üü5Žg¥ÅÂÇi×È¢ä¤;¯øw÷¶œk˜Æ î½ñè‘£´~ž7fŸ§*‹s80÷õ{/`ÊŠ�5n'¹´n¥¨y¾T×öZðØ¥@õoîÓÖ¢çÐÔ0—^)”°òŸVꯧÂÐ<â0ÉÌ9cWõKŸvº�Aé–E¸x¸–Éü¥÷ò‘œ4÷‹Dß!DbäàŒUÞ.l2@ŸþÇ¥`ë® ÁŽys0¦QÖ 7(~ö!¼6c9VæñçŠa¸®ÞžOäîßäb^™¾‹n¾�Ï{×û`}ÕtS¼FÚOëÉs»!?4JrI†\x"$¦§£ù”ZÈnùN)ayeß!ijb²§‡®sÂ환\8›#ÞÎÂZõïк×ÔŸöAO(£â½ \Ó’Æf_ª@o¢< r^‡Ã¯[óx¥YâêŒßàá:Ÿ��˜÷Bµv!ñ¶Ièvo¦lœ�²‘üðߙ굛¡“ÿE®ð�†,ÓÅÏ%jlÇWùµs4êÎäWÚ \µÂ ßêâVÏÉè!\¡�#þØuçöÅOG À¶û =Ë9I5%<­ïq=#�lPÃ?€Šg¥ uõéT)á¤Æ4áùzÐú•úÇÅñR%1o*çëµ “¼Uñ‡n�‹hãÛ{u©- DZ"ÎÈMËCë¨*¤'ý7Æ-÷٠ל¾ÑѨ]ÌîkÙÂN$Û¹ÍÂÓgò” ò¤ìj€½¶Êã¥ù)�1ö�2ü8jíÚÄ®ïmàÀj?|¢rµ! ~$ë)¼�wŒáY| þ.-álE…�gî"Ï·†swGr�gɶ§­Th‘óSx3â-ìI-@ÿÌ/BßÛjèôàäœÒä—+3qé kö†×¿„ñ¦ _NxznìÍŠ¿¤áγïtfí^Ž˜bÊ^Y]äŸ&ÏÙ½m±uh¡d¥ÛdŠí›‡ØS»C!�ŒIã!q…0üõHq„”b�X~±7¬’Àÿê=ô4µzbÙÖMhò¶/ÎþžÍZ?mPÖ+^\³&[œ{.TŸ†bû¾~w8Ôú¿¢Øøœs‰2–½¥Þí¸ðf.ô¹ÖL“WüSàÎ�Øfµ”o•ÃJ‘XùÉæ¯'Báç|þü<Ö3µàè-¦ùâìÖlX¢—‡V™�Tºœ½/Å¢íóÜ:d´÷¢ßÆÅ¼P(‚¯»¢iòPÎæý´ •¾".,/ƒó«wó“óì°Ø–Õ�¾„;�-h?z¿x_G¬úãi÷ÑܼmüÙ�}K¸#n¤¬ºå±lÈ?æ;{|ßûïÅÑuóÁì°f(ø©Œ# ׳’»¿Nѧ.ìñô-´¼Ç�-Eà´Ý“Æ™´ÓW#àôìþ^å9nà-omzø´^°^ƒ!Ò^¸É.�o¾ÞBûku1ä§ý*º,i¸ôÝî,¢C¾÷`‘³#-qý@OsŽb¨gí¾n%*ídÒêÆkgÌÆ’Ô•Xó–²~p©·/gŽ;#±y«‚ñÕ¯i¬‘Ç´8ã©•�yéðÚãw¸ÒØåÅøãÈqªþ^ÆšI6øé,„Û …µ‚Ñ:Üg"÷ú”@Úç øêí|Á¬-—.h°]`–8óâ܆kïKÙåëiz{{4÷*ùQ13Ðñë …É8GN“WÝ>Á ÆîØ=¿^yì†ÇV|=áùœ: ÃB¯Aþ:M6îKx’”*n®Å~obÎ×ÏbLEÅ/ÎÂð�óì–*ZóŠt9è#¹šù³‹yÌŸ»|Æ.A{¿<¼�±�W\Ûç5Óá¶\þu¿P1­Ÿo-�ç»¶Šz1?…;›RñÓY+ü›!þþëƒk-Ñ�âÀ‡„ó´ûòØ÷ø0ž� –Y•|ÿI—øzl0>Ú­Ê×»{âBÍQ=†'kHᇖ9p÷ù\¹à8æ¾ô®,B}ã4 Ðã_q¸6&2{˜³×ß2áFÜŒî[)*åEñ˜Sßè�ä l˜@‚þ‹ è[_ j6üm(Ke…H¦®m/ÚŽÂÛ751íù>ðziœ‘ Fb‘°ýé!±£lJ�­& Í—Ðïˆ8ìÐMá�­ÊäjðÊý»mç\̃¶9³Ÿáirî¥ :‹—ðÇÓ%`gG>àÉë_ѱÏCqnc+Y7®÷ÉÄ3W.Á¨�ûì˜0÷²ºµBx�¶Øå9žC‹dð‹ê¬IÏ ûk®üßÎ;ðzL_©„™Û>ÕËOýႠƮۈ럕³ýõmþR9Ԝݓ¯BCª9MŽ?%†_^Ìa•Í0`— g¿p?‡$£‡ÆtèVIi& ðTÞ8'’mÐs{6üwßîÚD}um„ýw×ÃW�¾{û=<ûý¹åñÒ¡sH’uZÌ«êgì àå‘·!©q'º[Nåìli<ѰsÎfQ¿cUÂÒ“|`@6N™'e'y» }YâfÞʺ m:zd‘fõ†[ í9¬Øš=þ‹ 6+±}X tù®ÆÎ½«ÐòÏ-¡r½Ý™‰w¢éúŸñ 6Á…�ØÎeC承v×Ó;Gn{ÕŠSFþ¤W}`õÀã4ÇØÞ}_Æ2™`n³„6‹ÿÏŸ gyÌ„û¹·;ß±¬®‚ö—‚¹ó]¯9SG×�€k—äQñA´8öæ^ 9ºÊ"ƒé­â=ðxª á¿éCF®ÛLYÝ8µ|! |„#›þF¯H+Êú fbÇ)âÈÇ9"3 7Ú„ŠON^ïëáú=y®Z/�!™J|=ÿÈ/âšÊ8/ëJ¯ËcQ·ºN×ÅAÞ&´ô£ŒøG¯?-*ðh#WT²‰§­ô‚{!KØÂm=)¾i'ßð6ð\|Šn�îúÞ0ï_V¬í�/?uÒ�(^h£ž^#xªofÊïCÝ® p‹—çM?ú³é¤¾œlH]×®Ã�cÃиG ü;Ü?�~ÞÞ)*kñ ûmBŸè)°pêrVÿçnuÑví’Ø4r/òd8xø*Eù ã•z˜«¹°é“¡�Ø·’É£fúèÔ ‹:. •›wBn¸�Ða³O9²]óöûBôíO`ãõ†\ª†ªY>¼´UŠä”¾Àû.5Ør9XP—K�ù‰Â‰â>ød"6›®áÛòû·R),õަs¼U o¾C:÷Ӝ+^d“¯!™išÅóË6FžÚê/ÖâõoçÅ’C¿IÒõšL.Õñ‚Â,rß2Çü�HÓ74ÂÈŸ;°öjEî*Cþа±¿1¢ÏW±ïÑhp·˜Á= IúƒöW¹B™J)Uõ9ÌúÇ�?ú)ò8¿tø{õ4XzÓäÇé¬?x/íVqàªÍÖ[™"ꨤ™õJ´ªrß÷IT݋¾Ž�®³ýçÄÞ[³ŒÛX3¬“Ì÷}"dzàóô!#ƒ”ã¬%BùðU–ÒOÉqaR‰`¸ê1©øè³µ´ ë•Á1¡GøR&Ó¶©ûÑ­É—í†n቞u�s1PX«9W‡OÀÔöÏ Ûkã±cöî®)Ú‚‘Øvõ1,HW2¯®VõĤOaxf$�Lj ÕË#XjzÝdÞZ‰2úÙÔ³"ê¶¶‘Ô‹HÈy6 Ÿi<�«[èSïÙç» ê>ºá™ÇÍ`ôDoHÒÊ£Ð}¢ªŒÖç_3ÕÄŒiÓq­¤f®OãwVBŽÿ^0¨ }}RqJ‡Ëšl§÷‡vðY-ü.—úb.>b§ò’¨vÐOšJ‹!k%M+�NCùëÇßà·¾ ¾ÿôâØ€»yœŸæí«û~�ÿ|nÄj%²´Ç~‰søÏ//ê߬ͮ'ki¤¹ŸË/ÁŒW=ðHC­±)¢ìs.l´Ë™²jõ9ïœ ½Ÿ] &­H� ƒì1Që;ÉÌCö®qØý²�×´K~Œ Ÿ­ý„áÁ±’azÞ´ÅL ¤Ýd±H*«”*yŒw1/Iåû“j(ÖJŸ„ØðÉ›½QãëªòŠ¡þ}ÔàijBÑ #…^úµÂ…†=t¶B[p3ØÉâ_[š9«�zšñQÙ2TíNf;Íhmçux?hNÈ#]eé—b¿½ÈÚkFâ&Ïf«Ó—·Ž½/~UÔä¾UQ(?l;5¿XÏÂNùлº/Nê—ÆƒžÇ€”\!¯{ÑÀ??ÃÉmøw•'ðùæ{hÅYüøš÷h¬5üƒî�KI%ø#XŸ7Àöœ7`³û›ûÓðe¯iÝ�U¨ª! cÌ“è‘>øîSIu 0™ D»€¯S9¥¯Ú7Ÿ ŒþRÒË?ÔVxŠ•óù“Ëñ0úˆYKã׿ïTô6\8”Mûod€Õ¸\±ÐNƒe®¬Eu­N|¢ÓÂæ 0¦½�_ÌïbJØNú ßËÅ3ÛŸÂþd þ²Z þ†�âû‡´�ªÅªüÒ?‡ 5W±‰ßV®“Ì]+¸ïÀPœ¼r*Ï+í ÷³[áÓF3~9ɈEá—Ê…lS£ÎʺƒèÓXwµABo\TÐV_‡eŸö 倢zúùÚü�x‰åÞ½·It6 äxNggùÏ”ûå´`öBW¼éÕL¨‘$Èȳm‰ïü8¦ àþVÖ.¡ ÕŠ'B»àñuôX¨H Ü­ƒ×R”mˆtu]º$¦¶×A�yþ�ëTÙ&AÇ�à”Z®Þ8”¯æ¤=ò…ÐÒb€†«LaÌn‘2TsHûvÊ]ê ³ÍÎèh>ŒCüF »w+âc×qØçG:”ge`X•ê¥ã“й|u}/Lš?œO ï7�•8†ÆÂÔ‡sÙôÓÛäGkD/(�Fé¡t—øÀCœ¶;ƒoÔýçD/PýÐGØñª�Þ†<¶Ù<–È8ë_?I’å0o…ÖŸÝŽ"»„%©=±p徤¬ÈÉÇ÷ФU9økØ7ª¾ñ„רêÙÏi8wµ*èRy/,~þvïú[ó—b»×þO±ÊÈþWûˆs×Å¡ïÉ~ïáǼùh¾¡VŒÜ¿—¢jýÄ™5yè˜[Fï•’hÕEš0²†mkÁÈ·=º†�3HöUŠøÔf{…öã•m})üw&­ï*�‹M•¼ÊRSo4x-\Ň|³Å5²ºÜ–jeÓ­xÍÇÁ\P£sdåÑõhôTX�W"½(sÐ1.Ê çQKp­á˜5¶ ���ÉÃÏ"ž<…£ÕÓD›‹BàŠ3õžQ¹2ó£¸HÅÝ÷ÝÇÏ''ÒÅ‚Aü¶ã �È=)~.ü� gD éIöWf;í½47)�­ ¢[#Øåú`�¿’!Vlž‘1Ø80„¯üÌ…´“’Ê#ñx·Z>Z›óÁ‘Ƙ3ã=Þ<MšrÈ«a>®�ú�n ìËï5üðå­Õ¬y;eú´K »ùš4iËâ³�ëÉ[¶‚^G¡Ï—�˜:˃V �3ód Ònëí•aÛ;Bµó�ëõvÂYVQQä žg!Ò9Oàª÷vÉÙ²œç߬Âo�a¿Ilñ³2CèÏš'tÑ*Ÿ;EÒÖ’…4kõsÉ�#e¨/ÝFjofÙØ‘–D²£„Ÿ6‰í]ÓaCf7^¹"œ«@”.œG~Ée8÷H¶Tªa�ACÙ¤{4—Mẘö羦äŸ-x$s5¼­Êw~ÖÄŸSNÃó°øuêoLæ™·oCÂíd ydÇ-Z6ÂÏc3©a€ix}"�‰[(Þ9M,ÔÞÄGýò±;!œSÖX †­<§nøtc4Ü_¡ÀI-i8ÜÝ’g­ÍÄÙý°óÄ1ZemHcÅ8xón+|ö&Ì­áÑצðº©ßEñ|ÀHh d9OˆÚs¾ér÷¤Ÿ0T®”®1ãg—nÐNµNÑÅþ9˜•£ëÁq¸þBOö{�Aý~4Ñ—2M.ª+.6ž­üaà’aô¯Å¹]m.†XOÎÄ;bFÞ]X‘¼Œ_yøãÇä‘bÝzG,Ùè ž-MW7ÁTÿx<|H cõxeÑÖ ;ßãâÀIa<¾<ðÐL®0Š—¬Åð«F|Õ¡E,Ê0ÁÅg€Ïàž˜žÂßÝs¹yR<§IæÖ'¯i“Ÿêd[ã«—³X{Î]zrÄ�‚.ܡ۞‘kP0¿u!…�¸Dö7(¿ƒ :ܲKî÷¦+u(X{‹T.dƒ•ú¿œ¿.¥�áx·JÄ‹XôsÛ aØ\Œ’‹/¨Ök µ…Ü$?Ã4Lª—ÇN©jzð îé`G½"ŒJiFmé4x‘ÉÏ÷O€+÷€ü\u.û¥ËáûíºPùνÏû²e]=¶_û#þW±–ú=Ý&hlt$�gTT¥Î;©Ð©-%`¦\Ïú]¡…wñhÀ4î±p<üx\„QG-yI·Ž>#ÍšKºh‹Ã|³�œ[¼‘‚Ë"¸ï£ULÆ-Ë“`ù‰]·¥o³šÈvƒòÊ£Ûùâ¥g$Z€ë Ü%�ì�<ä4�- ¬à‹©_:=wë«ó¹Â RÞ+˜ÊX‰eA&¨~ìßJ- ¬ÇáÐa5“ÏLa“-‹éYër¿ÅšËtÇãä�3hÕ0='×Òâ¬#ôgý üðÞ0aï»ÜPÓV&škï*Œµhû=cA¡ÏGœù­ùËM!þèj:fÈ ò?�”‰Þ÷�+ßœüï …‹çÐúrkü$¥Âs:ïÑULº¿,ç{Gf ›Ýlæg\•/2üÜ{ NÙr¤ëœAI>ý\>AÓ÷Û'Qæa¿5ñè?­š8`(nk:„›²Û©ÍpÞ˪µ2çã¯LpI†¼ý—§Ä‚ýòeçe`N?mÔkÐGÿ5žœ•År]ËÀº×(z'•„«Ê_C÷Õ"0I‡I#ga|ˆ¢ÉÃfÞtæáÐ)¢LT,úÛ:Ðd<ÙWšªFñ‹ßÄ@çcÀ2Én4ó-XÆZÁ¤¢äÍíwñ ¯ñYY5¼þo FSãš•ùÆ­#âCé!¨¤�Ë ^ŠËßÐ×=SÿqÏ8¶ög¸:l:{Ÿ]w.ä¡Ð£Óå‚©ðÐ}É1Ù<œõf+nn7Fɲpö˜ÆÕQZ�©ND£þo Óð8éÞí‹W•ôÈn›!éSÑìÊ2 Þ6�¶Ÿò!Õ£úø«æ-¼×KÁÌëñ†»׿»A«Òvñ›¶¿Ôh]„Ö>ÛAx6–”FÜûI åÛ¿¢¾s½øë¡ÏeSjR2Ìö]Žq- 0%`6y¤8²_§2*è©öæÐd†‡­/u7-!/÷.�7ïÇŽÍà²Ë¹\#}€¯f*âÔG¡852 ënÀ�}¡8«)€ãéL·x77š£ÆÇRnôØEòòX:'Hœ|aÿx7†åî‡SÅázú.4˜°Ž¶Ø@°æ2<¤™IÇ&6òíЧ¤“µ“VU5sU<òïƒÂ¦@ÙÆC–OéΕ³v³� „ Šwàg×TÑó•5Þ3›œo›ãã¹óh(ÞX: J>ýÞ­ß cxΩQmô\8Døûý¹àüÒ–w$<¦å¡ü,u<š=Úˆÿ] ` ñ5–ù6 ýz]€·óóÕÒë}X�‘5ãw�I�†¸©ê²x>y/Çneý•ž¸ç¬?—µ}¥= f’~u „îËoFƒìß}’Waßq£ïl¨ñrÄ)V_ áKZŽÊeé¯.Ü'ñ¼ðä\ó0J^𢻸ÕïbL[ÒÆ_i×Ã0z¬a)^Î/ÚoŒ‡T´pbÇg¡sû…†­s¢…�nò ó9[4P?T"hóÁÕÜ5ÞÃî™à†žù˜èôžVÖûáÒjùÆj©àyÓ7½Eù›c!æ~,iž•æª-c`ùÉã(5WÑáŸîSðâç×dã¸În:%s>ÉGЪÆ¬ ð¯³óxaAá‰Þ0­¿œxü†:J¯0ÀȲ¼ºT–Cú YwÓÈp×gQú­Ù¦ˆ–5QÊ:1P Û_ØòÇÐh�VðÂdŸÉ¼d±/+ZxÛén�w�Qªg5•”æáN!ÏÑå¼â)ܾq¸Ýˆñsèv¾üíô£IõG¹íE‘pá‹fïNÁy�[áÙ–9ðGô¦Ø©+9E7J–ý ž1™t¯\ƒ¢÷ªáÈŽœ6R—:d@oç�ôeÊ6º¿â·pÀÔM,éaEº¸û¢4ÿ™qP¸¨¸—¬¿%âæÃÁÑ ‰Vï!±x¿;¸šÚV}ˆæáþbPÓ0ò ¬ }JÍŇ¡fk&¦»Gó•½± ãš²¹öË|§‡Š?ŽÁÛ•Y÷ç`4ÔÏ…>B(?6>ž9öm\ε߶S‡sWO†~3|Å©\Ñée‰P»>ÎF~eµÃ##wÉŠY“ØCÉ¡14Ì Í¦³¼¿~Î�Áöè1œc�qVÜv2Œ&Kà«aÑÚû8Tå?YGYÇ}GÇc—æDaÿ¾•vŸvŸ¿�°@�ë¿õ!Ì—ÒÃe.÷©_Š"“õC4.› Âã¿0 ¯6LÖËÃ_í¡¬58¥”KÈ~¦ôq9ŸvÒ}õXx_‰Ÿí|à¯ÕR2öëFù°å…�PÙU�þçanÉj<¹@ ÷µ;ðgµ]¸C+†rtOÁ_­chùè"|�Þ“êG–Cú¼%ŽzÚ½Yz÷kJ—ÄÓ‡€ŠâXjÿ[L%“¶ÓõüóV±çè O.ÅêpW>ÝHW§^¢µ�Îñ‚§=Å^Ï×°¡ZþÕK«‡W°�õx>á·øJç diùÃЈ?ô`Ð-’75‚–pßq,ó"Q =*¸ôÙ!ÚåÚñw›ü¥œ#¤Ÿ4¢�÷Ç‹³+اʕ£ôã(är!u³G\3Uú«s”ï/Ø&‹+Š;¡·\µÝH§_dúﮫ:‡±êU‘Ç~ˆ¦¨žy\kõTT6ǸÞz�ö Ç\×ç†A›9´=L#Cù摊+×kABû.,íÃR¿ËÁ;àxæß%³ïeB@b)ÆŸ§èdd›CNe[h¬¥›ƒvñd�HnöRç1c.&óâéKNýq5¦9qq¸jËEá²vè—f7Vf<\âÉ}e;éͳ3â£cz˜þk w-“Ð`“"ÈñϧKËnÀδ4¬þy·|—dž‹)3ÑÏ׌[�+aÏÅ¿éªþfap³Ÿ‹È�J^|>¾„;ÝŒD_§´¾?�çGA_ý øµ¼Œgl‹]†ùQ¹Zyåùó´Á¤)rì–;ß8í¡ûî„êuMÜ}÷¿u~A¹úcA ¦×ð•›ûñû”}d:[–•.—BlH•$�}¹e“5÷C.º|ð.êæ'ÁÜíi¨B-O<¾‘ý faó¸Éd:Q…Ñ.ˆ÷LRÀ+‰J¤�®ÌèøÉöÉåÆôd5ÜÐMú†Wavð Ø¶$H§åšÖ\0ÒÝ!+˜pD»G{¯¹Q+q4�:¯²q¬± ް€Äîhþ~ëߎ¬N¡Û“«Àpì&ÜÓ`�ÔÁøl--›VY¯¾»F8ye7?üeEåûë¨ya¸´çPè¾ýi;Ðå�¸’J1Ú9‹×ÒùsÁâï+èÞ¼Wlì�M£щã&¢ÚÇmÜ}¼êZ·Ómç0””ƒq6-°Žfáƒ^ÕôsM.ù,™‰®Þ¥”z;R˜5^øy׉ÇŤRkÔ˜àÌɱßHjÖrzª|ÎxáŽ=j|¤¸ê&šŠ‡�/¢zÐ JÉ~(^™�2ÉøêøBAì^M—½’ù©Ânì,ýg÷ER›c/~ xò{mjü�ÀUYmÞwaû'®¤92_„Ãw�‰’üÏ»š ¹D<SPû{9Ký™G#KŸ‘l£$µm •¹n±~/e¼üBÍ4ÐzÛ TýDzÝçz™úzSYÏ~‡ÎÒ¶�™à9; «`J¬=Î:ŒnÇ pÿ)®pI­×“yu¶«{OdÇE‚vRE½vÀ Ö¿(êñ¾=±\ÒÄÿ¾gj‡ªp^i{5/DË‘À¡ø=Iü\850L=íŒ 3œ Èx9=Öv㯾é$7M–¾":EÆ5~ò<àà¨îs‚Ö³¾©Lc?}-,=ü…fè.ã=¶ãß}¥¬ef€bQ"'êÇ '†sÿ[E¹GÃ1÷þ~!?O‡ÂѰ§_n¨„´\gÂ�´Sà`^»0Åÿ=ÅÞ—eó†ÜÔ ÀWãkh¥›,ýÒ¼a3b:Üš‘Bl d²6Í[H7„ai•¿©vÞóTô®NT1L1]±�ù.U¦ç�ëìæµ”ñ…ïê¸öõ)Ð}$ÍuË ñì°7ä§>W«äâí^ïàTÙ/0zÁ å›”²%�Õg7ˆ—K‘�Ë$Sð]\âŸI‡[2`†j‘°Æ²@œ²;‡”m.rñje6 ÏàmxT”ž³÷{O£ =…ÉF4[e0¨,3÷.[ÊÒmÒö¥·ÏŠÖsÆÒíÕ¢äÊœö,çhtŠá+ptÂAðË“†õGgùúX›ƒ·F¢ÆÏo`Úø’ _œ'?™»,ýP =—GÐçønÖôáÇCÐMî…Ú~ã„Á¶Ãañ]RQÉâ•*¸ù¤!š�ÆG4ŠèeÖ(ÌØÃ7c·°NÖ,AjhùŒmâ­6É=NóË&pÅkÄû�$ä¦ó—ü¦ËŽ¥âçÓŠü.5C56àìS ètÌ÷éñÏуñªW´ µk‚c¦*_3‰½7¤£å´h›Š_ÔØBr¹c`ÜIM´ÿ¹wgîà§Úiüë›”÷[þqÅ„µx¸P�ßš †_ú-ä§�MíùùË‚œ Ý¡w� ”�Ÿ¼“qq½“=%œXÙ‡/.×Är×)Ü&½ÌÃCC„ õ9Dð&u[�@ÜÁKŒ øû²½0iÿ`>·G¿ü>P4•GÊ‘ƒV\zOš�Zá|s<®=Ó$® OÁW¼xý��0"£ž®üû§n?V„GóÆóux�<˜g6ÛAÎ%o ^ä†ÇΠ–D-q^ª-fÿtæ)Æô1ê-d´§Ãý(=T·è„äŃxȬw0ßE —Uš“ÔÀY|j„®8¿×IºèaŽÓ‡ãëóå´W‡pŠTÝù¯)$ò[S,楬pô¯8-ÍÍŽe`Èòx,7Íþ1Þ»Hú)Œi+&‰à[|ôYEx¡´”'kÕ³ÂÝl;JÛˆ§î|òæåÒ€Hò�d{Œê¿ŽÊõM%COË¢ïøâ€Mitén,.8.t”|Fi(Жùæxb÷)�þrßÕï]…ðì­5•]q¢öR/¼8±˜²ÜªPâ?¥ÚÖàì�»qÔÆÿ ²¶–69¤=^Â�|êÝV)}m‚¨?óùÆÀÕ¤ü¥–ºËò‘ÞÆø%s‹°Cç„øöˆ2^\Ñ%ë2[8zWŸÞÏN¦ˆ&w¨Q¶ÂäDIçª%týí”ä¬âoc£('êƒä‰ÕD0·Á°¾}°WB&5­$صk!.’Uà;†×)(})xj¬ç„`íàqwíQq«Û&XsïwÿzYé'×Ká%}nÐáÞÿøP¼‡öxºe(ÎpõÄôMIèÛ5×d\"�ʸßm&¶å§s›‰¾ÝÅÕ ÙëU¦ÝÖó)øÚ°Ž|–+“ÇÁ휶é- YeåƒðëYKˆpÛGN/B)q—!§UÇQØÞÑð§<‰�²‡}ºéé£x.²¨@…'/@æÔñAq9D/iãuú‡íúÀWk�C¤ê$ôQT@�¨A¼~×ú�ú^+ßE-ƒDóK“WTÛ‰’wIÒ–íK±ËI…ïI™cfìKZutê­tL Ê„‚’|6í.@…fC¶ŽH‚¹QPx2‹Qxïé³Å#1â›ÿü¦Œ8möh¸!Üì5—5�«ílm·óú!P``Žw%~ X�>—Ѧ® âDcYÞR¼�U?Ùャ*\rú›­WÇZþ]Þ—tO(£ß&i4¸R&Ö½!Áªà"AþiŽš{œÔŒí¹àÜHIù´#;ë[¿BÀíX*¿šŒ WgcÞ�O`öå&™=GUCê¡Ó"š�\ȿڌÅ&º'.:q™›~Ì’ÜSO¶»’éM6o‡ñ‹®D˜òf¯¨:ê Èý�@ò©„î®=4·o6çkÇñÌØ3Øbt”ïp@Ÿ»ÂAƒDv©ÞB‹z7ƒo^³°3üׯ˜%ÔÛ§¥œg�蚺^™ªˆ�òìI=ú0ø|÷㛟]ñøêstÿbôÙ?Uœªwž‚Õ4Ñ'0Ž$÷¡pw}–é¥)ίöÃÓ“<ÀoÄ�sm«Ö•ýË]� ‚¿9Ьj¯ŠUƒŒÄxu¬nuåËm‘TØ ö»qŒ]8×]º$¾nS¼lvcÓQ¼²s.ÜUòá¾k&sÁ®VÒë�Á;ø=ô×êAšÄM�–‚iç|Ù4Ÿ/þ¢žkǰþâ‹h6½XÒÔ�/ü‰,&«wOØKVçŒÔ¡¤%±³8Uhm߀>5»9eŒ„Zü³iõæ´´ØPYCpé=š7Þ=Ãq°àÓ$¤¹�ÄØ¾¤»0�ƒïÚ:ì®k–‰™^Oì¾[¹°jN“øªc=篟H‘Ÿ8ÍBžÇ‹æ¹MÓÐNo.T»‚î ­›„×ÿNä®êþÜK¶ÍöÍø¿ðiÓ!˜8ÛûíÖzžÛ!F/”i8ÑÓ˽Ëþ1“'¿’´a¡A-ßê­Âµo¤Ðdx;n •‡“ bÅLQÿ¼:ž~o2ý$v÷�ö€b«/ÎmP46I’=ÒMTã>šIX±wõ?±ÎW½…]�Ì9J%â|¥$PÌQ,` xl²áa½ŸSàæ(sg'wÿVãEÃc ¥w-þ9³‚ÖÍ '·òCÔ!ãƒöxº"URù~ 4�qega¸y½ }DÌŸY ÌÝ=_®I¦ý]9uÐNNxX'Jn û³ÙÔ}½RÒ{aøG3Hq-NÍd2=t€ÏûÂ�©^8θE¸²â"´Ü«{…çáœMMpàöKI«Q4o6ºÃcgër�¸Ùüñ‰ –¨�`_‰#žx)�ßò‰�J¨£ƒÎ8jå'Ðÿ4�t'�Q(CÓ1²|~Ë©cŸäDŒèYúźY¹Ÿì ‹Û$¶ÊRTâuœß¡�±z=Æl˜Î¶á+ù¸N"šîÙÀWVÿ¥€¥£yœK,–S’ÌËJ%ÍM§áhÒ~½u$/›VO ´ ßR¦åh�¿ôP&÷CâLI*·ºÏÀ»Vžtß/º�ÿÂô;âf5s¸~‹îoÞÍó,‚c6Þð2­Ž^«õåZR|HS•ÏxXãÍ8ŽÐ�߬ñ„y“�ýϵJrÿô2n~6–�¾Óþ¤£a´êz?…sÿ¶Á ì�óú–>� 7 É¹©œÜ:œTNÆ·ÝêF—™×Ï`ÝŽß/;2?¾¦¨”­âáÞå´-Ô—”¬íèi`Hõ™ÏVaÉøs´2g»ìe—úN:R¹ûh.ÁÿqtÞq!ßWQiii)DHÒ~ŸSV¢$’HÙ„’iO %)-‰¦DˆÆûž(ÊÈŠŒ(%‘Q”>(ÊÏ÷÷ÿýã>ÎãÞ×y>÷ñ¸gÝCrs}ÆÌîŠ�Ç÷OƒÎ§ÏØ1�O2�¹^�õÛirÈK> `�ìEk“Yd­¡ ¿òÂp $ ZEãP`¡ñG˜´í¿Wh’ê®^TÍP¥9^·™)¹/ÒE´¡€$áÜ嵘¼n]ÜÎE/GÑvd¯�FªÓÐóª2�¼°¥7Åj¬w»=Ô5 ©êX½&®ù–²— ™KÇf=æ4¿H¡nª à öõãÖ$¦OÜó!H?î= -.]ôJr-§yŠ›"…äñ†ÍY‰åuOù=o°w/ãè-LÚî Þ­GêÀ'ôï~@ŒžîƒËiæ„@ÔXp¯)?†{úqøî’w¦�ÑÔ ‘TžÔ ¸áœ—g™ˆ@úu�ÏÑüT­:SëÿN ±¥Æ\ê±Î^]’Í*‹`ÏïË`RI!§ßU¾m°¸ê¦ˆ,&Ð!»Žì$ã¹"4+ÃU]¸ÊöKHÒ÷Ì•(•ÙʺçcsR,¶úZQ¡�—afëŽÜâr ¼&ìÂÎ"eÖR©J³RÛóz(÷—Gce%‹v�‡ñ€k,‹P<„ÅáüÖSpäI4sÕ*�¬DKs]ÿQ4Oe/¶�Ã’>u¬�z×Ò`hÆLþZž o[t� ÇÏf>AðtQ.s÷%ƒÇ ¼f‘&^þ.ʬ¡´º$‹pw#¦èt[_D`„ýaH_w(QÍ"Y®„Ešùñ+KÞ3ŽRSâÙØþ“¼«N{â ÍŒ+—Òu«±W‘†=3œ™Á[m:bœ,døZPIóz4ºË‚?±õnóñÌG}t7ÖÏÂÆEóèLH Ýœ:��8нmL¹Ý·ý¼ƒ×…Áš0B�­bø¤Ü…î¹ô2ËmNP\êN?w¦W?Üâ�çãP��ë¾?ÄÆm �‡‚TÓR�º5bDMz”}&²{çÐZÁ«°ú¹*ʳèkvh¸‡/�ðÖ¯™ ¨�ôˆ+›p� ¸-&q¬]Î]”°lÒNXázœmüü&Y SñÎRZYø­Ú(ó$uÞZDf–ÐÜ:�6Û7²›K±cù!&zj¥Î�¹ë³YÝ…ndL?«Ü‚q®HÑYoH!çô–D“yQ\žèβO¸³_y—9ÓœV®zÁˆ°Hƹþ0þ¿ñ|�öQîhÝ(P¿•Ênþ™Àµ�“Ć]ü¿|’P‰Â!©h›v…íðüÈVÝÚ ?å0| ‡ï�”‚Ä{/¹ÛHÁîù޼NØ’h SÌTàaf;^^·Ÿ´Ï§æç!Tkû—…ÿ~ 6šÒü�È´Û¦E{dY\îtXÝë‡Úíwaƒ °†=©û¶�úþ˜’×Þd'sÌ�DÇS»A;ü¸ñ˜Ÿè2…7ܟǶ/çN�+ƒ d%³‘5§�‡ €Ó”-!h)ãs‘ƒ·ӊ̃|ûDì{‡>9‹¹ù¡s0d°E'E1ƒ[NìNÍ"êô¢ÉüÛ©GmÚÉ4¤¿ M>¤[tÇÆÂ×úʨJãÄ–:ÒX-OsÆ›:�¥0XÄ.¡9ỡ1%—M¹�ÁšWù²ïÎc(qÌ-è}�Ï¢ÅîU—{ofW{•jêËïÀ@ª~ø½+þ¬ÇðIwy·yʸÖൻœ@ý͵\ð›kÌPó5g§Ü »´‘ö†Vf¢!‚+T°þû „²It7,ú3«ØŒœ®xrûO£—�½ÞƒÎ�ÙÌBG¯žÑÄ›ÇQbÿhJ´9ÌŒ>öƒhM%JŽÅêZO25�š/SøÞÑä;-‘wë¾D›n ÒŠ�»à.WAgëHãŸCY›õÂÀèm(¾ú¥EÚ›LŠxªM�š«˜BË9ˆÙ±‰v_šW½Q~ŽE=bwªÐÕ?Ù[/ƒ�ï[®ChÞœ•¦ef«1;; Xr©Z*ìl±@õ×C1Ü£Õ4Û{5w9“¨Y&©–¥� ñQ¶UëN­z¸\®�ednûÄ"Í_ÈòÛ ¥ê7š¶Õí½“Ù§Ç€rãRiÃ+!˜ ïJ#j¿8å½hi6‰®ÆŠ°R£ÉìpÿCŠVËÆ¦o¹ì�À(R³Ib;ž�¢Ï�%ñ�@&Nž…ïRaÖ£D~¹ÈG^!_ÍÂo£,1|­—/>år»&bzˆ3º,‰…ÔrÓÈ'U«Ñܵw6ä`O¢›£XíÉh–¶:õG;`¡_"I¼á5e‹ùk*Ù¬M³:?ø±uU új‹½kÎà(GZÜRȤ3À|å0ô^KNYý¬ú¥<íûÑÅ÷°ÅúOZ:ë·H.oüÕ ÉZjÔ ¯ŠÖ?vqãWÞ%m»\v$xš—g'ú©xö1®Øö9̓óƒãpØí+ž®a#½1Äê/q7'e/wãÏ•n¨w>’»ç¾�½Ù6ßÕ…ð’aÛ0êÚ$«§ÀÅH#R|3—³_C?“ýŸ =‘ǧŠZ´Úû98ÿýÆ×mv…T�§0èåFïѱyÖŒ-Æž„.4d;ØÀ§.8�¹˜*¯ïÂiô©ÒÈÒËXö`)—EâÍŸdÒ÷�–EkòcKGQÎ:!ŒßžgJ’зc³Ãt1þ‡ÙúÀyø¶KëgMýwâláú] õS‚-¼^ ³MÃàéV6F BouÁò+ž¨Ÿ²ûþ1†åÆÛ\ßoV‘ 2Š¿™ NÆÅ’6Ô¿“õnœ–¸€>G1kér–qþ+l^I k/²³ž“0þ¿HêñÝŸ„aSö-ÎG;•¬î©à½ïrØ~C"Õïñ‡Î‰Ù*¦tØs3råUX ”ˆ¹7êAb]*™ˆ„±­7húP:�N3ô—çá Å݈Wa\<Ú¾äQÿ?8¤ iy[P�îóúd£ÐÌ ù�Ùá�0X{wáêÐM¦Õã²Y­LäiPlŒÕÙ¿…_Aà�g2©9ër�-&tÒÒ…²´^ñßÔ±tÃg6Þ"ˆ¾æ&£Cù::4N{zl(`h=ÎV3eî™wŒD8c¥-{Ä6qÛÈGÈ›ùù°ãúT~YkŽÙ£„†©¢É L®Òè%:ðªy2kV5Ë…³˜õcEºpl-´vW²%wq|Äræ.| ƒlðCÒË¿®ÿÉ”Ú×1ùã*tõÖôâ÷³EÉ‹(oôv~ûˆÿaÅÓÁ}Ëð�–ΫxÖÞO û0c.Ñ ð’Ô*Xñù ^�³ÃÝ­ñüC-ro½Â÷L„Ž�ÆlJº ª- £Içé]Â_o± w;fÀ²~ܰƒ*^�¥eçK¸Sx¾÷— ‹˜[ʶ.üŠ�Ö”0�à0Ü«°�$†N¢Œ«=3‘ÌÏ„BñkÑšOZª¨$ãAö=»Ù—ÂNXµÄï*zÓhË^¶IsmjŸG±¿æCöìEl϶3ÜÒ»Ÿø´"Etkÿד–@±hâçÿ2²œ^†}†_Ç›pÿ¾0øóWzJ•´•EHìŠ +hO¢.ï…h³ƒW}iH9æé¬ÖÅ ÛQ¾Id³·[ŒYüý&6'õH sòš§©ãq:kê›]W0M‹Ù$ß,|¢S�UN°+�¢qùX'h“®¶POÁ(�Ÿ°£' VÊÿ€®Í#4U4?4™á³P6.­”mt0fI³˜! "þœµ¶ É*(²öò…$é~B¬u@¼l÷³l}u ß>‘`yáû±¦Ó†‰ËðýÙd¬”µÅŒñZX¿L�ö+F¯yɬ٠�¶gÜ£’¦(4Öµêa®-X€’Ø’,A-ծب¢‹î~ ”Ó»3…X™c§z«œŸ6j2¼.1À¬@Rœ`OÒ¶"T¥yæ—ä£Y„#Óvß×ÄÁãt¼fK¼V6îiw§ÉKhœˆ:¼ô~OŽOåÙƒØ ÷õ¸§æ+thõyoš·6TæêЊiŠ{ú“iCÌüÅ…ˆ…‚ˆG©õž¤!|ð ¡úÁ÷�Õ ®�’-§Ù”|Qˆ2$®n?yñJ4 Ö �Ýçxs;9šµé<=j•!_B/§¼¹¨Ο*×ÌålŒô¤D$å±"5ß ¶sz»þ°}7Ò0Ðp2ž¯�Û¬Sœ§STmÓÁlùyx7äœÅo'ÙšµoÃËuv,-( Ïpaî±á‹g¨nÅTx¤(Ž7C/³wå:�=Õ…Ü®9³Ëëká¨øGhŽàͬ”Ðòz2™­´ânîxβþ{îi‰}+�ÙDÙÒÂGÁøùí1þÌÍzX}C‹¹àýÿâ©?q-z®?Æ>UpS&1ý³ pQÏJ\µr;5¨+ã¹okؽŸZ>C¢#Þ™kŒMûç¡lß`‰+ `c}§(õ…éÿÌ£È.þÌE'!MoCÓs=l­a —ÿff®õ%E‡¿\úÅbXÜQÕ ™NX¢ëB/Ú"œÉ|ꪸ® LÝX‹Ê4úiCÙxšSmIV×cðäÙP6a¶ÚØ’èÅ™ÔÔòV5§£r¼`M¾òfÐÐ8Ã2ÝN°…'BPû‰&ðeeÌÍî,™ÌÖè× Mò з¹œ{ö)èo<ˤU„ؼ×êl}AZdQûÆfìÑÁ䫨(zKÍg Fí �°/`Ú+ôiÓò<½’nZ‘„Dè¯ ÓªXªnȇw‡B ÁBRñ’%õï%,¥p,^«€3ÞAû;ŒqÏÙÓ8R¯Y ÑÏù{Óþ›Ï¸ÍË#èM×ïð�Wâ‹øéÙa8µ÷>w+dnvTG·*ÂCÙ((»vÓÅ¥QÀb&ïQ‘ûºÛáŽd NHãþyøyÇ"ÜØ ÊÍÝLjÔ!œ:M—~MÏG7Øò)³qöÿؾo=YM=‰'Æpf¾Èüg<å«î¾a�®D�ø 4ÍýÆ µØ`¾Ù¿»]��ÏîñÆñl@ß—Ay¿ùÖΔøUçEŽçæ÷£ê1®~×nÖPèÎ{˜òÄ¿ž‰µ[ ͤº˜~Þ$êQiby›"á»Áwö«³€Ñ -Þ™ ó*ûq‘D M‹:Ebz·(aíiö;´€Õ,½'3"¦‰Ñ®s‘˜;E­Óµq½¤:þÊ0%çÏŒ]tä#êS@âBÑDì¨Æ\‰É0!5Ž›p&£5Žð¯¼´é’})?§¼¯f�€²ÉàP|‰zA§¶ë“ßáä ïØžßÚ˜ûF‚.ËÒ¥ôœª]±pES‚Ü˜Æ i ³ ´Ù8gÛOØöQ�_nÃ$çwÓ]Çš´:ͦAÝã-Õ">Øtk tº°úqt~¸ÄÎoP£È“Q«V˜¢sâØ½Š0zZÂÒN|°(éJ€ª>CR_�É’Þµðšgcª› ]9æ�‘�bxyÑ&4›×ÅǾƒqë´HhúîÂ"y ¾¯EâÏÛ¡´&üÄ ˜ëbv?/³<< ¦�F/q0:¦Á]…˜g}�.gÊ êt­M1?E!§Â‰J7ð‡^ø£ð'£êQ�œé¦Þ¦ •Ï_ж@IÜØñCEbÐ:ǽ25Aäc1üÒ ¡¾Ìß°Iü-ÿ¹µR¯î†ÅBGáÔ{¤¬q–¿eýˆK7Ÿ¬Pä_V�ÚÄE(¶x)çë�UÃTi<ÉÎZLðœÊFv¿àæ}b\²Zï»äÚÖÓÜ%!ÌÐÿ¨T½d–“½Ð»ë ËšŠ*~†,&i~.êÄ”ÎZîžàŒ‰MÆŸÉg˜ Û;[?cB_;ýîÐÄŽãáLvt,µIur‰ ÍÐìrŠâ<�A)ù[èú“g_`Çœ(gò[PmMïIwH¼W l ·2½Nú`¶‹r¤i¤ê=|ò\ƒ›•µª­”®óñ.9ltY3LvyÄ OÄÕR Ð%ÄZãÄñ\ù4Ð ÝŽ¾/w1¿;mœª‰ì>÷Ðâáê±øèЮb{jô\�R^ä5™$~—@ïæ`¶+”8ç–MpCg1íº#hù¿wKÁÝ|u"7æu3©ÙôÍõVÙ/§sƒžd-‹;ŸO  ™;éSì 깜À6Ê-§ ¦ðç÷&2°~ÏÔ�¦âx)´ž”Ä�Q�£O0¾[éµpÇÔ½ˆ§?ò›ÉEZ‘YšL ËÇùïÒ¨´2†½ÀÝC-ì–‡MŸýúšë`á`.*Èø°UA»ùe§ás¶€öw}¯²ldN�£hÛ¼K´b×bf&ü BšÄ±ôê!ЉeüºùŸËshMÀj”º5Ár ·›f÷ÇÚÁ Ðå†×õ¾3íëãÀk¹%>•΃ܧâ˜èåIG澄…ï2¡âÌyz™/ ªŠ3Yþ�h̸*Ǧû±gUÂlµe¸KæÂˤF¸c|‡{qSŒ•Ï¿n'¥Aýo;§~Xô_†|ã èQªL Þ"¬Yñ2ÛýåIŒŽ•î-ô}yeXL"·Lú:WŒ¹edÁb+y“¶œ·ÇíÕßy³º™l⿞¡ì}Å'¹øKIxw~0Ë}5ÕÔV³q«ƒø²ã™t8¬½*Ó¾:Ì7ZúÀ².5Ú!y­îȲ¢ ´ÐTÏÁóÃ'Øù±Îh¯´›Ô]hD¾Ž›õrížÕ%:Ø;íb¼¡ï y�¡´µ`7VH,¢šsãqî»W0 §ÆnÜɪkVã #!®bQos#—ýZÏ&9ÔBÝ,ί@ŒìÖŽEÕH#–¢gHí–Àúl v�ˆ>‡^�Ì�(°,à&dGM1]îÜUG^Zà,§qu%MÈ&¸ØÏu.´á ×f±1�Èíã7¶/2žŽø[B¢ïaÔ5D•'á¸ï¶ÆŒ£OMéòÍñ(x:‡5œÀÏ4ºîÅö]WišŒœndÎ1il¥í2;lÄì&õZLfE¯j!':� Ì7áœ{K9µ�ò$Ú{�R5š-ÎmúÀ"!�—¼í2ïJà”ÐFr}oÉnlD%?¼i+Ï´ò–àïž•)vBMX2¼ðÁ)?Fà\¡.üÊ&/§$˜¶…lÂ2ØåäVö|Sè|ÇÎ;$ñ›CÆakáWˆ–xÈNË¿§7«Ô)¯Ñªâ§¨3,Â/X&�oÇ‘úž`~UŠÜ^ ¬èL2WUL_n¸+C]ib@$ØÏFù_þ¡ÃLºë]ÀÌVÔ1‘v»j‰& |¹ä*µ—²x¥Ã¤Õ°ŒLN·0�1¯@õq&MöSÆ£ÊáÌé_Ö ~E_v­A“· iE¢ Ï ¯þ'ÞÐØ� îäsk»ãUBöþ èÓú“å¨Y¢ÚËgÜç­tqÏü35 tU®ã@׿{?_ ²~m y�4¸ô¹¿2B?I0Üý€&oYQ{\ñº¼ yþÑ/ÇÀÿb3ØòfÍsÃ%˦Så]ƺc?3»ÞÈ2—ÿy†&ž?ÀÚTgàâ1†L*1Šûõ® &‚cB,Z¹Þç·r+j„ðøÃ¿t ?„%gLÃÍÛ—SðŠ™4VíÓ)MÅ+U¸'b=½/M&¡Göœ¥èªGÕõ�)LüÞoŒÅS{¾ðyªÇP\i4‹øç3qg󹿒Ö/JffÒ‚xýÍr²k7Añ5ôUš…³_Ëò—ª<Étf:nÈ £U>KùS˪ªï‘*Î_G>ÖX×ÙvöjÂ4|-»&¹NB S]:77�j|3Qï­?¹ùâ~µ �Ñ·� ʲÄIéO.ˆ‹Ç�¿+ c}3Ž®¥œÈðŠÄÏÙÍÜ‚ÎÈ-Ž"ë!/44®»Ñ™CÓ@vš»þËõo=ä®é¿`®hxRGuóìAfé5š÷j¶¤;«ÿc^[¤(²QÌ,HGaø+l>?œLéÁ3éªaešBëQÕ�Å*fâ¥, ã-x´ñ›•Û q�ÃL­H•Ô�ó ÔÂvN_æÑnØnýÙ¶¡„ýi­C™?7¨#õý•ƒ+BÊ1MÄ‹Î̓=ññ˜jX£ÜnNò¨á‡’­‹YµìlÓ• 4ÝLüÇê ÍÓÐù’&MºPÚÞškµž#Ÿ‰v,Æí7 Ì®aoñå�îOS‰ 4{K1+2£�™o`øìdÎÌ¡Vh0še‚ö{XèÙþ[¿"s ÇQÆÓ:–œ®ARŸäHóÈ î�{;ì‘�ÿµ§�ÿXaŠ»ïÊ45¥H7,– B07>ƒm˜áG?·XŒö&jy»�G˜¢÷)�_n…'ö R·‘g¼îüC5|”ÂcVËù§jzðîX 'f|ÕBçt.<Ùí@Òbùd}Îu²µ_þ�v§‘E[[§rãÓQòs$3¨È }ŒBaµ×œ|A)8ùÏ…Á3õðsûj˜ ëÄšK„Q½òûäT‚ª¾<ŸºŒáú=Z<¾z ƒØª¹o¹óçn‚þÞ>È›-�5KÎÉ}5éee^�îêT*Ò�ö°´î>ÚJSñò-IL:<Šiwz¡’F¼ðyÆU¦¡Ý€Åå¶ðŸæïâÚJP]U� çæmª¡«Ê´u û$7ü¸<Œ ÍíPti.|Z#Å7ðp&n*ž+‚½ µñ’Ÿö˜ícµnò´òz½úé�ê²6hÿ\�ý^5“æ÷ñçì²Ì[g�û­jYÐ(…å»™¬Q8ûä“R]Ô§Aòq›8s;#¨´‚•wR±od!ÊNŠ¥ŽÚL)ÁœöÊéUï^*Ç]çØ”k‚4×qí.%í_ ð]?–Ûµ|OÖa×&'[4~÷¥Û¢i$"’žf’êÛ&z'튺“©å®+é§3FÑó5&�[„ârûñ[»$U§<€ä1j•%¶íÖf¡Gp¯S7ÍïL¥âõ]\wÎöY[‡r×¥Ã,Ck³ó“ņÏZŒ· EóÌôÛǘ õ„1ÛÅ“éö‚Ù4ü÷*)ËÀw›ôÚó|’±ÚR4—O¡¬ýÿÁaŸ0|6æ)ÞÙô²ÍÂé§œõ‰é±‹W»á¥Ý.…è?Kÿ7«'Ý�Æø*‘Q{?nžއN´1¥¹ èì�BgåI_Ô�âÆþ¤;o¾0ÝG3¸Ö¿xÝë‹`FK³0çF�ØüäOhäãä¨)t$a­ß=•s'­;°ÿà Úó‡ =ˆuwBñך>î4¨mg¥ŸxrÑÒÆ¯ºFÀ�(€þXkÙ‘ýþxœ$øš=ÌùM{3�IlÙ.ÊLzG..ƒi cñCè*Lÿš@Ó[O@樫l][:çuS z?6BÅæ`òýð¯/"ÌlƧSï•èʧ7Üoéë´õpÄ×+Ñ�ÉþÌh|¾˜LråZ'ó õÆ~‰ç@­—çQ˜u! Zþæ£Rü¨ëÁ¾!d|ë—fÛV¼…·~²ô9ïhµ,ï‰ÛÊØƒË�F]â]®Ó[©œ c¡rw!0k ý˜p‹®ÊE0¡èkp!¬™¬#)ZÐŽ\ªÇZ |O€¨éF8aT ›»BSјVýH…Q7™ùmyË/A!ÌnNN ܆ãhѰA$ž/Ôç’ŒD˜ç�ÖãÇØ‹}«ÙÆý'èJC1dw¦Â�…›ÉlÎhô Z‹ñóèíããÔ­ÂÛŸbøÛ�mqøF�âw7¬Çûš/nEBåËXΦȬ9”VµD±¯><ëŽÉÁU#±h3Ý·nùÄ{éþÀS;E)§"%µTÈ{” u;âšì=0îº4þ¨÷¡Y…2h¨VªSI =hŠ)ü|,NMYsÉ·ÿ Ä}Xª@%ûÏÒÔÑBÔø­Mæ-†sýGÀkX¤&jôX|u¹‰%h)± YX»K� „.ÃèÁ£èX=4["i^Æ[øäÜÇ_w§÷ŠŸ€–’¿g+;ó�gr3R¹ù‡-°>UIJÒà%UÇéΔ4¶�mu‡²ÇÏhgÞ6p(Ë|óž�è½Ð³—ÒÐjˆÊr�ŽßŠðE]žÚ. ðcöâËYaªÍy:¶©<†÷kU-÷Þ‚Q>]ì’˜=Ëè<ÆÝ9êBû�üÇÖücþ›¥[1`ž+¼ˆK•ªÙ«€\fÏÇÁ…N�?e5ùÍ�Їš¢™à®Tþ¸Í%<¹r, �ÀmÑŠü–eƒ4Ñ$ ¹�ÁxK!—²§„ókãyá85*¾‘@âY‹±jëÖŠw´œi œæëïšQ¦ÂbZS¬Y3J°îW0Ÿ7P3ó’¯àW&.å*‡OqS'½Ä÷Ï×SŽºý,˜‹¢®Qhëe@ã`&Ê‚)óöã¿Åà.‘�Ïw£¿Êú0ë”,z[â×–5Lc‰¢e²IÔÊÊÁ˜o}Õ! ìO©}¤'á#Ë|ú5ù±E¥Ï5®ÿO«1ÒdO¸tü1¿™[q¥‚Ÿpt*>P´Á+uÐæ7§ž0×Þ¨J�ç'áÃ_aÌ_|¶éo·¸¶d”�™ŠóÚ (Àë(éaÂag<™ƒJtž¦ÜKÇ©†šlø‹i¬…�þr^ñlæÚX¬O7Á?7æ�HË9s‰&vðê,âÄíHxÙXZ-%+~ê�Ìü9¸'~ûÖˆYJu�¨ÄY¶é~ Ù>²Æ/ÞGP/£²ZvÖp8Kï•ø_ÄC‡qeÁ�ö1f$µ„b�âÇh(×ÈN{Œ¦‰eqZ�Aë&BWÆx Øy‘"ëD©jË_º”ttG<_lNu:è»­›ëP‘Ä“ÙÞ\’ÔEø3`ÏnIâ|ìp“¹<9ïÝE;›áÉð0ükyÓB¤®ƒ¹dldb[8í–.>3['žÆŠh/Ú)dÌո܇ú¯Q€Ï!‰™+YK ¸^ê­r¹µ’”/¥m±6ضË·ÛiÒgöØ7œÍ¹Üfq¥,ö˜$Ѿ|¼•|�Ž»eE-{ÙÞžæ¦>gíòÙ³ D¾–c6àKµ+ìHÉŠÈþc�rá›§1]l‰%Ï”‡0ô(”W,#Ѽì{<Š:Œ/Ò\³ °ë×ZXs~–Gk ÎÖ±xÁë68µ~¬ÚT1Ž›~±ðÒQ!�r€vÓ604yв§«oõ¢Ä©{PHÔ�¥6õp• štB~!»u4›Û||%«^€YÒXp-šõn?ƒã]–ÓR‰X8rö F õáµÅl¨Þ‚æ��KçÉäW·ñ\~Pù(ºV†•ÆÍ¡?ƒßqû2I\ðé{TÞLþúFÈù­Àé/OQ÷ñ±ôñÂ� ~l9ª†Yëõ©ãi==S Ó·Ç©`—=Øè•rCvXÔ4ÔµÜùìêâ$°Uw|ÿcÍ?³qêjVý¦.‹dN—Ã_ïÓàí.Kë—Œ¥i|2Õ¯>ÇlRä`á÷‹ü;Ñj:é׆m¼ü¯PÛUÄ\*yüò`ý,ûƒ׿�¡&9´}ÿƒîÞåÍÚÃGµ¹ÁŒÌjz:U÷f1ç®3üøG7 Ò~Éè‡�°G- ê•„(þƒ(Þ‘|§<âØÑï‰YMG¹)#Ð’t:f§¡ÞŒ Vq{ ôN#^T™æÎÄú=B8±e4ó™H²ÃÛ(/ ™J�)Á‹ÀГxUúKÍçºë£Þ«QP©®Š²Ëöã§mÔÃðgp¹óNŒÍ 9Ÿ4¼Ã‰’m]*»üH ¯8xàézu´ ¹ÎTÜ põÓól�Íš¡­ŒÎAú †kÿ³¡°&c2î‘£ 1ÔrQÀÍËŠÙÕ÷§«µ·¯@ƒ:œÔDZI™áÔ¹‰>o×Å�È�tv{÷üÌpÏúÃ6—…sÊÑä6åÛsH˜ÖD»“î²ôêa%°s}&‹Ÿ‚+WÍðkëmZöõÙŸŠ¢Ô/-TÐÒ«”Mþ¨ŠíïWÂ}u \?&Ÿ¤ïäÒ•K×�%ò$ý�£—}'Hz¤˜œ…|Ùé&ìÎí'Wázùã=Mƒþ[ãkëcéUïœ.ñ¬:m¥ê�½Ê\'L¢²ò8ªº?R}a`«I!:W†bîãhZ:þ)lôø…¿àðÙ<2]oáêk1e”åjsÕe׿âïœZ¬¶-dÏC�,Ÿ,NÅÍ~¯`ñò-܆šAÈÛ°”$„ÄùÎÎ8c¯vMtì4®åÜöY²öèb‹^¨3¥'[¨ÿò :xð6o/ãDo’ä°bÒo¶F7õ¯Å²i®B (G£Â𸈜¥lmˆ5ZÒÝv¢~92dèÃë`ÑãÌ߯…wÐÌ‚ZÅ *l¨§€k<#<-ÄJÙ3‡›©g¾&¿ÿtÀZ-‘ZïÕ]Q… ºïª/ÿ¥½[¶¢±c<}}âÀ Ôãå!ÀïN²°êŽ ZiÏÅ! \Wû„»3‡Ò¸e”×t‡¶Ó9ûf ·ŸÅyk>³é¿Øôï.4tg4twÞ +)š¨y‹µ냆ä de™Âf~�SE•1ë¿äêiÇ®cßáeLâv9m–îe–V¼¦óYx•}g¶òÂãù­Ñyì‚Å8–#§[#÷ ÎKŸ"ÇM´vâMrСN•´K©WH“ªRùßCÑ7@L§ÑŒ�67Ž]l”±Ì™6ÿ+‘©™³[ÝÝŽPæ¢ç›¨Ð¥É¥éBM}:òóSÜ¢ Aþóa§�$±ƒÛx©«pо‹ìa³ÅóŸ£j‚|'C“GèÿÿÑÛqÄ�¾]áÖ‡¥°ïÖÛi]¹ ¶ÌqFå�‰V…+Óvc•M-­É^ÇÒ­ä¢7¦À.#7|X6Š®~BܽçôÂè.$‰;åã·Ã'Xs��iN S5 ÿ3›j,÷AΕø´\ŸÙ�N^ø'o�¹ü�ªqi¸ÁäM>�XÄ ·á[<¿^’Ãàz¢'´¨&ü2³‘A~ù{ëÌË/õƒrÕyX°ó(="M×k,›/‡´²óüôãßàøM{;ýŠFÓ¦)b(ÓFe:Wqëãû0¦ù®Å”×@+bUÁõùO¦Õû�+(sO/;v}_û3F¼ @Ë¡ã`ûÇm÷GWÁ6vÆîË3L)zÍ ú’`ª@–‹²†®tÉ@v¿ó'µÍ$(I£*"¨rËmj˜ÔÌ:vˆÐzabK.ÇQx®-\Ž?²#Ø ³Óª¦-�g×p—ø´8­–Ò–W¢•¸:=ž‰ÛÍ 'ÔeÓâò@êL3¢{ áÔØ?­ÄŠ˜P` ÝBy ×iÅÇ¿]“Ú²—ÑÊÖ×ü“ÅKo‘O3N–�ÿæa8wð 4.~>¼#þñ�4›[^Icô 0—ICÑÏ ¤¹¡"/oçKKºÑóQ8ášf¯7w}–Ç€¼Ý ¸�ÙO¿«îeâÍYhç"‚Y÷ÇÖh>ÏÄ©¢PåågþÆ !.Ü´‚=ŽÃk{ ®×œm5ž�‡"ƱÝã<Ù³¼ûü©åÂÿ<-˜R�—ãç@ãd]‹¡•×Ùã/‘Èå$Qúü³ Qt—µ·Ç°û[”(°ÿ®íS�1­ÁHžÕT™Ô ÊÞŽ(<³€6?‚�Ç£Y‹t-+å¡yèXôzÿŠ­ú!E�Ò?Øôê µüçüúgÁTh-WËÃmõŸàý6ŠwªeÓG‚¥Çwæ-ÖŒ†þ­\OÈE&g^…‰3΀ÝĹ|ä¤éÑÙ4míþ�Çe*OÜÁvnHZ*�Ô¥zET÷QÏ]+ÈÊ¢³Îeô§[„Î¥¾°˜òXƒ½NbþÔºèì„BoC08{Y½(EéÁ<8ɽbVÌI#ÌŠ¬¦¶ACq9ßPäM/¾Ì¦U®7è°ý\3’Ž\ÇL¾|�3Y-ˆ`ïžÜ`§$.òÑF×øñRÁ|û›N¾>°f q§j¼ðˆP(§Vч”|ò�Ú�3¯Bgº;Ê=‡w5ÄH-h2/GÎ*ClBn( jƒˆW0Þ+섌–'”ßàB¶&â$ß ÉvÊi¢ãã¦rƒÕÆÒÍðH¸,„Íã>ñ±®ùT­¢O—ë$é‘Ùdtž6e{…饸`Íu) ”yÏì~"~x1 _tËÑ8‡ ¬ØÞˆ*î*!3¼BïfœåW·�dÛ.6qëæ€ú£0²ž¼†K¿°MgÇ’êÛÍðÌä{[Çá� [°æ_¦Î·_†�Ö ôFZš­�Jeßw©ãÔµ¡q<¿k²¿s¶s¹ŠôSéÞâÈ&ø­D›�wñ÷µXþžÏqjš�3ƒ)aknüQ‚KÜÇsõ•t÷»3XõåS^¬¢�G˜n´!ÚÈ&r"ï ¡mÙ)ÖbIΟ[ÀFe;;¡¢CŸÏ .ð—g®é–±ì½¹�$†A„Ö¿6’‚NÎÅÛ3÷Q‹ÖMX"Ÿ× ÍÓ¤¢-¤æðt~C$¯; õWèóO�î±I£¹ØçŠü²O[©ÿö:„ÏA8›�eÉXÍe•‰0»Ý«yË›µÜ]£ñìvÎ&�3 çõàág±èà ¦ïõÏÕ®„áp‰%Ý‘%³² p¢j:jY,¢ €,r,zÇž.q¤›¥ øÆ ›W©QüîkuçæÀ¶)ö*ç*­ÊŒÆ+㩨;Šëëþ-3›Yl€Ù©ñ‘E§&î¡äß}¬âäX6A%—Íö¨<ýS¯ìßK_g_ û!,>ŽùÂqàód î}DíëR©è€ß³�G÷Ÿ!ðözû¯˜¬ÔŒ{:û9œE \ÑÏ.Ù�Çáe?°¤4ZNžeW-g ÁLsül�›³ŽÑs1<8ÀHòÐó*�«~·mwíïMÉxt7Ëà·žÙ|UÀ†éW©Œ¿×=½˜ßª|êYrŠL“ûø”‡gÁik9xõ%€‘�,ýO­Ü öÎòX5oy "<‡« †8ë1.€q'!³/�VIm%ÿžslño‹ºe¡Ææ°{š1ž·e©†ùxT¥™­øçÙùï ðù?~(óîˆKÑuµPš19Â\РÑDêsœ™�öÄ7Å�i—Œ‹z¹·©sñò{UÐÍrÁ‰p%0gà·0î#ÿeø*¾‹šfKUAdžhÍÓ{1t®-ƒžÏÆÈ.w }ÉöY]æUoW²Îþ ˜ûh;Ÿ'dù§Y™nÃ*è®…ÕßRɼT‰¼íͱxÿ¿½Œüâ"Njƒ[�:v­§Ì™‰œyÛ ÖÙ®„ï>Ü`ë??ÀYGP`Çu¸®Û@·ª¤¹H…-˜tó#ˆÕ _í1Ôíˆ'ÿñµ¼ìJeÌÝ3�ž?áAè´µ\™BÇ÷ûâOßs�#½‹^d²¨™_˜CÆa¸b›ËÞgµ>!ì§£&…¥FÒëh=Êþ5 Ö&W`ÁN92XlBi�ì éE˜²§Œ~Œœ ©ûˆ‰—ÕñóÖÏ,G&œ>Kh‘ÞÛ_pK…Ø#«�\¯C?µÐÓÎ�9kåž?bžpï17÷ÚlĸJôÝÛÀf/ …åš–raÇéEÏKЬ�FÛ¡jö k.ß²¤Úe¹ÛߙӶÇlúû_°±ÿ.TV¼ÄÚ}›éj¥�…î¦ßy‚oi ¥8ÇVFÀéCT¯¥Ã¢Ï.æhþ9¶}ÆG 7Šù-`SU¨óº•.]ƒÙý á“*R…)Ú÷6±MFãPñ‡$ú̙ɦ,m�Ó®~̘¿ÆÏTÙŒ Ù[Q*) ×[‚Ë”F\Q4–ôžDÇìJpr£·E÷¡öÊF꟬A~¹3_™(ü5ÜÞÖ3Ñ^#—â‹îG…7Ø}å§°ûÐVlV GŸª°fŽ"ùk¶U�Oè¢Â˜¦ŸÏÎù|#8º‚lÔ¢XNÊúô~5µºý朜ŠÈÝ.že—·òuUR5 âÃåÍ'ÿgAÕ?„�ZC0m‰?>”ðeÞ± UIÇǽÅo¢�dâ J¯÷SŸž.Ú-D³³Åd:W“®‘CÛ€ì…R,–?}ÍÔËžàñì92>5Á‹)k¹ðŒlp{?ê�<[ÐÏ燃W»íã²põѵ¨ëéÂ�|</§Oby1Et6þŠBCËÓØ4]™^¥¹pIŸÉé†.~§ÕcIQ3¯pÜÕ¢ë1±fn„뫚ò¯û“DK=²îãcø'¬‡w†…£?qjòKÐH³–ÏøMµŸOCü� –þX‡÷¼‚écxÝoêT�O{¥žÁüùæLà~:}ÐE©™Öô{ÊBÌ!­Í™¸¡Õ³÷ŸÆ[›Ú¸ÛS�ߤ3tò°#‰ž-g:sôp[©#•–&3¡ìKÌ4r!Í›2‚æã÷°+’°wRWÏÑ®—L´d&ó<¯F_—�rË?ö?—ƒ2Ÿ'Òè®ñ[/Ó+0f±%åh©ÕÏ=ß“„ÑMÇàà¿3—«u sÓVcñÔ…t8¿n­Û�Û<ëÙ¾9ØHùG.$è*X9–³ëjV.…§Lا7lRˆ 6¹f@ÖÛç(-ƒê_Gpx‚&\›`żÿ‚�²`Kf¼Àçv&5È �¢Pº6ôƒâM´Ù•Á«4O…íséa�<Ûü¢�½ðL%Ë®`øïµܸ3Ê̬߱Içɬ4›‚*WR\ñBUL,ÞÁ¾ö¨Ð*yi ùG—Lo#h_@ÜÕ‚þ'=ÁÑå#OPã]›99«jÜ%Òæôýy!˜ßVÇG/(¯oèÅe⦀SŒ+í1›DΓÁ×#w9sì{LŽn~”·n1õ̲Ùiøåc –j�«ÙFô/ØN~wXýé(H_ZOÂÜ,(x[É[=IÜþ<;t@#¡† Žñ¸è£+.Õ\Ro§Ãû?ib’oúµ€Ü›j«­&˜Ù:™Ðúsƒ¨ð´tg>£ÖÕEõÉ€�r6(œäÔ:;ØÖÆNv.´ZwãÔÁnºö˜èQÌ6K�‚Úš�N§ÁUì<Ý«ad;!ýÍ’ ™Óß?w6v°M–Éõ·d×óècñ…ý2‘J¾u1«ÆÓ„£õ,¸ritʰ¬ˆp\gÁÉÈ-¤Kuš0ôHˆ–•…p29šßiËÍéŸY×5!Šs×1ÆîMÅ\€G·¤¥ƒ¦lw"÷¡ö*¤ã—+sgßÅà�3�?<6Á˜«5{»áe3ï‹U$§PˆÏOÎb;oK€BâëyË!û1ƒÊÏ=�<‡ô³¥7¿Ÿ«½Û;�«öÒE)}–>y³© N ¼± %ÉÓIÖbc‹¯ˆЫéÅÚÕ-!ÚXû§×Šaé¡e jò˜U7!»½á úï�Á~×,áŒϦ¸³¡è{tœyŠoƒg7$àlo^£Äuç¨eò8*ç«×ÕÊfÓŠü%,Ek*(W^a²?¢ù$w{”ö’£·Ù”yÜ‘œN‡à¾'”ï�ªîRPTâD³çܪqË6aÝgw¢¶s¼N#¯úø«bÞ8÷éz»l/wA`À9<á™´e=ØÕl�ðé)k{X©¯c‡k› íÌ*hKeéSÏжÑK�Ò2–’¼Ø;lI£�`÷�½Œ›m…Qg³áNÆóÃz0ÑÖ v¦™�òløÚgÔ�A •I }ê<šcÁ%õÆÑ—Ðt^ãÖËN,bª¾ ôý{? šô¦ÉIÀ¤è•”¾N…RsÎcù›&¼¨y#k &�»ßÏÏúª±èg‡ú˧ðïýêb÷Ç?w?ï ö§§Žwïõb§d §°g.Í>Ù i¥©\Ï´rÒ�5Ä–-ïáßì•$å­2uv©êXÐé]«4¯‰Y»Lâû(ªV�ÔË.2 ŠdÛu¨]M…ªYqs–Ôò£þž"pW[ ®EÚÚ>*›P¾r”)Ÿ´…Íߨ“et¨Úƒ§…/0x�3&¸Tá¯uÔÎî­ø€ògüh“ý<žDûlÀùV¼ªL‡ÕôùÊ+¡tÄ;™=ôÂÊ|IJI…„þ¥¼¨èm~Sl(· 27Ûñ¼A–!‰ŽE²™|¦z}rÖ‘¯Ušn�&G°TŸKÜÃÇÜwk¹ 9ðÆÈ~«· §3WÁ·Ëδ¼¯X � !ùul– ¬?aƒ~n7ÙüÝ[XVÙßX? KW÷Š€Š@6¼/âA|%íÂxvÇïÆJÐà rg�m†tz<oêÏc9Ž,ým0‰ˆ•Á÷õ�aÕÏ›( 0‡:}¼œdL>û. Í¶`’-ê ˆþ,úÜtŠ¬Ô¤áìØ%¼×U‰õëJábzkØ×/P7q ˆµ2fww׊ŹC.èãûEòœùÃFjÓxÇ8áIü$%å¶.Lñé¿&7’5)6àÁ² &Cö™gÈZ�ƒÜ•Š?›\�›!§ jŽ1½,y&['if$"C¿¿„¶ª0H¤Ònm˜(ªD¾{³h(EšZÕ\Ámï6*;ÚŽöÚ�p<*¢Ímy·@S‘9À²=,àÕÍ…`ì‡�tU7Ö UX»iâƒTØT_Ã�Zfð'tk Æd1dZöqÊJ)dßæ�!"wØ!¥÷08ªÃòI`Ö†¤´�žu‘¹±- ŸSm뾆>ž,ÜW€åï»°x‘öÆ·‚�ú.”w¢y„‘ºqטs!…þ^ˆ¥Æ>�µÏ‡(9†bMÃð²à Nù‹ë²¶dŽ#2ìpr ­`º|ÀaÖó1�<$*!èËUΠC“}=ÕUë;x [Âc‹q(?/ðð³!ÏÁ ÿð̜݇ F£Ÿ¯YÒi3Yof 3bG¸bï$:ê2 ê�Ÿàëå\AÅÿîÝZ&XºV^-`Uém°¾Ï’Ù ƒ^o ð-Òa:"Ho•̳xÆŽ%¥¼"kJ9¶Öþá[KÍAÈ$ù¾ßÀ39Êšûù�_�»þ;y®lgÒ ¶°=o&Öí*yÅ” ïQ\}6/œâït¹`¢drlä${:qøÝg4hîÀâ÷Cµï#³¡2=ú/W4”ÒÆ¼X¦­´…¤ïW°õ^d!½|Sª:“½TÎÆGþåÞæ�±e4 ý0¡„éixw¡d( åJr®¤.›6ªÜm•"cyLˆ½Á•MŸ�æ+a팙Øqt6ºU远Dv¿°º5s×ÛQÕ®jL:¬C²wJáÈÅa‰Ýþª¡4¿p7ö¦ë#[_Ħ˜¿ge#Lr, ë·\¦±uÛQyÛTnS¦íлbÚE3ŒÁE©™sÿôŸ*;€œÚ\œ~ËÃæ³s®¶¤2! ¾œ¦ïà·²4ñÉ-ؘpˆâ®&�rqn¡ô`;Ô˽…¡‡’kŸ¹8A…¤?Ù,�4Ó› Î{imƒ•žáUûÃY×ç%Œ$Ã"�ÍÔð² Úì÷3�©AÔÕf�E~å”9âÈ?MÃÜïÞ$¾ù2EtfÂ]Š¿‰¯Ú®à<¡>Spo8¯õ†Œùãd¹é ªêì ‡)÷áåû$º5¾œû~¶Œý2ÐÄ–´•‚T†È^ƒÉ%Jàv±XðP+6n_ÏfŠ ¹×Ý­Ì~³.Üä´!ÛM›ìN±Ñ°|n·°„RsÝ àåZí,€Œ–X*{Ž�2öƒè‰Í8½9•.LÛ†ÏDøïG\éº^2ý°œOšn…Ì&è_¶< / Ý´xŸÉ:Ƥ ç©xκFŸ^œ„Œã,û~> <)‡õñ 9÷2~›±'É�{b—§$d _cij[h^Ë,áÍ|81ͬ‘0 ,?�º#¸|ø·¶O2ŸWÚ¹†Œ*dA Ü a³þ‚(¡€v¾« òÆ úŲ™—ÿΧYÕ°òíxá¥.±�n6®Ý­�ä[üƒ³Ó¥{Jסô–>8äï7ÝpJ›¥o A³žS¨øY¾ÎªBéspoêµx•�ϱ«›%Pò)VÎ0¡(swp_H_ä?¢œô¬Áa;m¨·¯»44LñάÉ(BY“­ÜÇì…�8Zm"i¶3n&© íàUݯP²³K õG!ê*¥‘‡s tš 6‰`XE.}4°¢“f0ßJ~Ïë4ý³®žZŸLdÒ¥ªÌè•5Z—dâðó0J¼É…M§ì™°;ø ab©m˯aµÆÙ<#/¬yž�u2ìß-Êð¨ZêVYPëÎ Tÿvüá]A.ׄŒ%”£ÇÒèhìcVbøߤõ’i»�A�·>ËË‘§È >`ey‹Î¦†ü‘�g<½`…Oßtø.ŠW ñf— lÕ=¼´Ö‹Ë{ …çÕïÐŽ_—“Ó¦võµ‘à|üuÜâ}rv'c¤c#Úem¡ ñºj¥–ŸýùQ91NRÕ—_þy2 7PåÙ‚E×jßí|̨ùçÛZAqO ×ÔKÑ7’™AÍ * ü‡¥šO¬«³3¡0wK�UÁ¼KWðPK-!^Óÿÿÿÿÿÿÿÿ arr_4.npy€p0œ—÷_ÏßûÇ[¢a6iH¨ˆ’Qôz^WɈl Ù³h�ìˆÒžJƒ4TZ$¤z=¯«²Š ‘‘�•ý¶WŸ¾ÿÂ÷üvÎçvÎí\çzÜïq³�fÍu–•Ù!³ÇxÝú­k½�­ Œ—±Æ# Œ]6{oó^½iåfïuëÿo}êj�­ë»Ö·nXíµ¾kn2nÜ‹Q£Çaàkðÿʽýðäëk¼Ôq> è�Ï©âšA?xöÀ±ìx±�×¹&’ºJJ>MÇâÉ—AßÞ Ëÿ{.^Ù<“¿½.#¥h9<­q*çƒEi4´KpèÖó�s¦”¦,™…ÇîeðZ]ÔZžDE�ÉTW¾jÃBøç´1ä¸1n5c»}(›äJoÿÇ “ØçtšMG/Å 8F®‰B�v íÂTZÛ ^v4RÁ„ÞEâÉb)Ô*´Ñ`ãµüH³“«Vžci’Ý4×ãÎ Qmì ¼|“çLã£3¸äôþüÜ�?® ¥Ãïƒú�ctdO!ž˜B QÚüX5»}ЭþÜrj(ë(Äì¿ËXÿ˜¶Mûx-î�Æ J+’o8ö·lˆg±ì1xé³~g<”4æng^²ÃÚ…˜½¹Ë5–Pñ‹ \0æ$v,÷‚�žÓÈRK�‚§ßFÄášRxªWÃS[z¯ˆÆccd¤2˜Ë>jÎpÃj‡¸ðjŠ4�ñ±¢÷°vÑjï#‹yÃ.Zè]±“dwñèfYÎrXÅOÀ�zfÕËÿ0x×Bèé<„›Õ] Û›µüyÁI,7Íÿ"­0pþXîuð¯0fk»àŸ=��Œ9 ™£rAgf4Æ÷Ó· ô ¯~,Ì»{ÆRTÖOøyzì¶ê�zµ‰èä¥Ì-n°Oûn,T>Cëw[ðcOú÷j»=7 Ïƒ’ѾÀ—²/„¡a@$tÿm�ãfwC K®• ¯ñ˰cÒPiK¡üi!4z¬èÃ¥vý¯Nþf$ jw¦YÊ¡Æäѯº�³¹[\*¥Má÷þáâØÍ¾pöqëíÁ¸%üµÏè�S÷6ˆ;vH26Äðç™QX§CÓ†ìÀ9>Ñ'ãê+ÃúÜ"ÛºöpÎSw©ò“œtÙNÑf ]Ì×Õ:/ð炸ΚÉè”;i±'Û›×9ÜeL¿O¢¯q¸Þ݃Sd•Xu•å�r�·1¥vä*´^¯¦?:Å÷ÝqQ“"—:ÌAÿX?©tÏ`!SÎwÅ=aŸ#[ ªÇ ^82¯-Ý çlLÈ­&˜³6 ·Ñ^^í½oÓ¡u"\­y,�rëÃíÍý1&é0ž¸¢�Ë”×SXpÞø=FÔ½WB稢³¨Ê‹WØ`åuO®%E,i÷ÁŸ‹¢ÐMF ¿ýk�|l‡?ïO¡_W}äï Å¿~›±j@=–ÃQvo`P¯œ›œ þíK(é†_Ù[ o.Ÿ®œsÀÀqßÉ:áKYØå`hX5ƒ|r¬ñªå©‚¾%_¸æ)¾v¾N&Å'IöR#m¹¬ÁF™ƒÈ#èç›Wî~Ѓô·pÑŠ³ph¥>«»oªžBñºÔŽéRÃFT—T“SA÷ÊAÿˆ¿„Œ ×½‹±ll÷Ó7gŸý}8¼ÿ,,Éœ�Ò3=* _®¦¯i+ØçT¡ØPè�Ö·¾Š_ò²8ÞØîd�Â7ýúWT¦¦à�!„†O¡¶ó*¬MìÁ·Sø¥c Û• ã¡1‹xÙîûd oœZ'Q¬& [öõh†?¾˜—šc|²¶Dc® %B'\~™O½M—õ�Àï«Ö£Ì»RjÛr-›Ëè�K)çk�G³‹Jx'-�”ì „l³&4¿õ ˆ'T 6 �¹yH-ÔªÕ;Rhð�Mpú×üyÜæÏ;MKÍÄ[Fá‘'A9}!ä½\Å^«Â’5Çyݬ‘|öªþTòf£›qBË\|üi2º˜¡eÓ‚91J—G†œ¢·ŽIBù�Ü(ÞŸ}Û£S 1Ïœc Ïò£ç!<ûˆ 56ÏC¥ŒåÜ×!•úT©,÷�‹n.iX´§žO¼ÇÈñÕ Â.�ƒ8>f'—þ[‰G‚æÑ³ðP\¥u€˜Žá’0L}/ƒ™ ö>°ömOÃ9¶ ø3¾Ò÷óm“Ë›«‰Ýx OÌ;KWÆK+bûNå‘vßè¶f‰ô“ïHëUÝÿ�Ú ]”‰öŠóÊ”Ã<ÆÞ¨pîvE¯xvÝí‰7Ç|€YFãIú7³b½Õù\½Øñ 5ÕPý£7�uP¸pW–ûÃû—‘taX¤ô½z!ÿx,‚B¼†We�ÊÊ‘'Éï>ùbï½=ùÜ*=×÷ø|•›�Öt‚R>=¢ ÓÒêQ{éè��’­ëoƒÄ`ž°yGÕ¢/®.èn•�çïjàEßÎò·ƒ^Yë ,¦ëa¯E§Ë0?:�ß�ë kÿùAi¬6M?ýŒÆÑÐå¦êil=®·—â¯iCÑrÐJ :öUr_ñ›xóq+~_ý.ÈvŠš§Ò«Ä;à^çEw¼;ùû¨Éhëj 2£ôq“r%í�ð…œè `ò ªÄˑڎ-˜ÕóúYéó—š^6¡±å šÊisQ@_G,ÿUFùÁ"i³8w‚˵Aø¼?0-ƾÑ%(r®Â°:4èžÂËÚÓiÝÞ‹´ÚY Ÿ¯÷‡É…ÿQ{�›X�ÔCÔì eOsÎÙ; �_äóØ‹áøîù9s·/Þîd‚/»®¨:Â2háCY›Ç†µ0ðÛIp”Èñ]ÍexÂ;ˆÎH®B³ºˆï|׳(ÑÜ�‡[ãÃË¿I×a5o?¿fj°¶ÂBT_ZLöÏQ%ä ÛöúrAÝŠÂÎn˜öÉ•þíqDž(RP JÖŸ5£?‡ËùSÅRšòó^iÐvYq¼Å?8^8�ŸÝ4c•rLÜq“z+Ÿà� ³°ðúáÆ¢žètK 7 KÏžeÓ׎0ÍC�§ê»c~ÂP.X“Æ× �v‡é5‰ÙÃNÚÛâ&„žå-r÷õý±mx,Ž^Áþ­—Ä¡ ñx±ú�o:%é­a‰Þ–ypFõD÷ÿgÞ ç•jÙ»ñMó(@‹ÆÝ˜íU±è†6Œp›É&‘ö(`“Ÿî¹�‡'M�‹}¥·<‡kÎ…ÒGWþfÂsö{Ã7‹HÜy"TLxI} ªzpÈF;^VUIîÇ»ø«™´qõz©…§ >Ü5!ø—$SÌ„c³ûbö×U­ŠÉr(rN>™»ö© k£7Gš‰&›ûâ‰FåOVÄmK–Âg 9°lDŽ.;‘�ÓÈA˜Èsz} ¹ŠWØgt-<ìþ…^«Û¸WÛ` Þ^ìÑa?¶Þ'ƒ¶Vе=ËSç�Æ¡÷º£ÌÄ6!øk»ø$òù¹¯X]v&ŒÏÐà^ãœÐ¡PĶÃñ°ëí,ªŠ]ûlmxz¿&Ü\s—؃¬ûj^£Ñõ^·Àdn&L/¬ÇÃEäÛ‹/V,fåÁZ™Õ¸åÕÑ£»ô†�îÕµi., ¤Sár6 gLÊ ß¼ð_ãhTÜ¿’§(4ýiø¶¾÷X|±ñ§–Mç—7˜¼'XºA²‚$ût[Œ¿Ú£ùÍÌcP»CŸ›–nÁnÉZph³*7û(ÎØ×U®{…sK‚D9 ;ÃjË/àú;-ìpùópŸO÷ Óù@ÞWñOÕy,ÛŽŸ6Í#+¡†­Wkq¿°C¼¿á*¤¯a>¥†æÖ{x¨÷QºÑ^Êãš5yß@E°ðwæ±…45ö#äÿgËw¶mÀc„¶/N°ó¼8™ú¢Ö%M~Ëá’�Ÿè™ÕÄ{TœùgHº›˜ oeí î´èãA|þ\™5ð%>ÖBMBýd1;KGn⣱p¨Š=¼±Öþóà‚ÀíUùA¼áz@¼jh‰sßåƒËœM,®®£‰Ÿ¬hÙ�R´4öçm~ŠÛ�ú�éÅLÁ^çq7¾ž£1Ðý¶†<¡ñ¤¬šÅÛÅU¹¤3x ¾è–Ä*SORcõDñf}~^q�–äÆƒsÿ¹8ô…•¤aÅI »+‚éÚgT;1—ß%K!P©š'ËÄÀ”ŽÃìso¾}´ 7¹Žáª²ôà‰6nÕ˜Ï÷FºKzîÿ+�c¥Èq×ݨla޵ïQyraÒ5&�^4üEÞÖ쎸¢œN‡nÇ’òylè>™Bçs}%üwW5}y+œ?¼˜> £1ŽË¸ÎôìÝo /†ªbð?NÛØ Ñæ£¨¾9�M$ÚÃmÄ1´Hõ Þ©GÖlÇâ1Ê”3q6Á“\$çÅOïÆ‚Gå!üuã--ˆÞÀ›"·1ÜwÄésmÑk¹hþž‡E«—rÒöÉâ‡S_1²ú¦ ÌŒ¦¿3 ¥cGVsïKcðy†"ÃVÝ5ûü¡Ž“¸æçRx3¬š´Œà'ZáçÕwpØì³ìª ë=6Jt›$-cm±ãC¼îVV}ÞH*Ê×(Ë(•ï´^গÜ²Õ 7™ÊÚ”5…‹ý’h|ÕDŽ5²å�ïŽâq×Þ\o™À’pa´t©ò¸©hº¹ŠZš-ØcßE^²(ˆO/PÆ¿Íýá‚ÛQ¬÷½‡.™áéÂÝ\=3˜ã‹t¸çß50â}>gXQYD=ìß‹mÚy·VÐÛmŠi&@òàÛ´b•"~8v¤bq-¥+ûÌq¶Ó)~šnË’Ùz¸Óë1Éû´C¦œ)Ÿš°û…­wŸ¼Ê£‡Î=atذ´ÏcÓ‚žL¯þÁÐ}]ü¤gÓo�/†ªa¹R:Ë8M׺eaZÆA²=lórëyÀõrj5‚CcFÓ¦ï±T¡Ü FíÔäè˜B¡5«ƒ´¿ã§G�G¡'Ý-� ¡ó“Äßásð¡¼|*Ϥ‰á`QÔ�'~€�­3þ¬€Ê£Ž ‰^×�,Dù¤2a‘N(ö9ôNòlã 6oUe£w� %ŒxkÆž’Žõ‡¶ÓoÇÁtem%´Éƒåš ü»ì6üúvTŸ¢š¥÷ùš¹.ùób}¥Â.“h~Ÿr‹lËÔÙ4ü™¦�‡Îή56@v7ŒÝ4Eëù˜Ø_ø…“xtyž¶7{M�Œé+uùé|.ûu„ÇŒlC}yÖM˜�·®ÈÁÍWTtÉ[¥¼­Ë±ç}~MΉJ`.#�ÖI%4É1c#ãyêñò‡ö\'3˜×îð—eé¸jªIÿÒ`Â-þÕËŽ*N¹¡ÓTcöOKõ}[¨íüv˜æp„w^¥‚Om˜]z çÅ™p™£®‹‹&§Þy�gòÇúý›¾7ÄKÌËeg‹Sî|£“ÙÝqÔñiÔâp^fšH6T™¢Ml(m¬çš¼¡t\&TTÛûOæ¡>‹;zŸ™�˜jÀÿuåæâ§Äë羟PpÀ€ó.†Šg-VóZAµ2Œ•øÚrw>f¦i£Wô›6+çPE%Z;s+öüÑ�C9‰ u+‚éžb?kŸ.í˜Û›ÝŽÖÑ.ë/Ь)ò± ëïD_–àsxl®JÝíÆrÇ^GÁùµâÑ'î‹—z+s–Bϵ³äô9% 2щœü�²oé®^ˆN Á=¡;~ÕUAÏ?DÕó!|z):ö±ƒrYä$Êh¥ûâÐjÚ1°�þÞ|ϹK°÷²øñö¼˜µP‚t°˜WϰGÛñxÊóÖ…›á;Œ£Ë!üùÉwˆž<ƒRLQßÇYèѸ´ÇÆ�–«8ëãzún°Æ—‘"ïqè_¹³y6/±hj”ŽÓ-U_”Iø%þñë‰ñ·D™Å´¸X¶©y ¡ ð=ðù,6‚o:u¥÷f¨náL»@²È‰€ŸÍI¦s-g ^à Ê|¾Ÿ¦ÇúÌT™­³g¤¸[ý0˱žƒ¯kac¼�?÷'3öJ&ðΓ©¬ Ñ£jûp8e™Æ—/­‘Œ+qÁ~¡y¥#�Ÿ× _Ü‚%UƒxjŠjùÖÑšûå윢„î�è⸑’9Í ”|ý([?&ÿãÁ;Vg�jàuo½Ðj¥îL¶ÄÅùá�s Ž)-Çsên¸Ò6^ œÿO›¯¯VÃ*ÛpLœòðïãf,ª=¶µ¹´}öübtãK�F+°ÿ” ²5?ÌQÍ–üöz°d†ü~Ø0¤RÈþ•†JêóéõÑ&ÁuO)§ÉÙÛ’zѰ­g ÷OË¡îÿ*ÑørG¥‰rG.Ò›ï¾dõà4àå>w½‰F·ã�¸Ÿµ-³|•ˆz©»­¿U¶Ä:/ÄmݧÀä?ÓPy`3:+¹`ó¤«0yÝÞÿ÷�™k�O}g .J‘:õ›@qe7À@=‚v4ž†Úµmä<å­p]�WV Ù:zi¡�eY9åçsŸ‹Å:·á�ïôù9¥ÁãØ¨9[úêûgœ­ðRÔ’\¥½Vâ΄ÝxKñ)V¬¬ÂQ=� Ñ+¦â`1›å¨I/F­üœš2ܺu³/¦ò­ö¼ñÞKHЏÁþnw¨,ß‘e8Ò¾tÀh§kžÔyë нÏ⹯h5º'v;¡‰o ïÀâ$yu®6ÉÖ`¨Ú\H=<“¶ÿÖÃèMr¢v =..=ùóš!’µÀkO&®bG—<:¡PC �­%ðàÉ3E’›†-?Kú•ú²ï[Lk?Ó塬»ÌŸ¦›K—ßî&M)ë�%CøæÑ…<Ù¾'o‹žÁsj!Qç!4—NÆ“[0I» dNj±Ù7Úq$€ÿ~F;ÎÛòžnUtàÊ4qJ¤ý n0ë÷dl~Ú‡6.�ãï= ¡yÀpV²XJrK^‚ü«óhwéô ^αMÑpî± Xÿœ4®-ƒÚ37„Ž ÎEŠ|‚ÏÊÃ@ö–‹àò$œÂÆó›úüpÓF‰÷5`ÒÆ�•‘ÔzO =–©€y§Ö¤fò±ô4þ=ÿ›�Uñ»[�Ðzl?îÁ�­5¸ Ñ—4¤†âU9ÌÞ;ÿ¦%³ùs;¾ºé‚àtwš•]�SÝ1c¾ n̓×Yqø ê¯D¼ß‚7jBà£|,z4’t cÅrUx.×]0ë6‰œîð û¾•·bâ×Ç�èõ ¤†õñfÖY×Ù3»qN�ò«ËÆÖšŸðy�}»f�õëÉæÊ\ ðBêc´”swœGSûÁÙ.üo¢É™:°ýP07yy£ôgŸ:ÿ[EAóç>ð Ñ°qˆ/¼rm¢£[ú±ÃK¬ý«Ã³tÐã�>ö¢÷dÐØjxÔ‰h&7 5î'Ã9VûÚ‹ö%~+V‚Ÿ}",ˆ·Ãì´>üß„’ºáV5áÃ;yøòó'ùMó‘„FžÇ]»{Öàx´rýJ)«Òû¼ËPÿdŽn,a û0tIö¢¶ò¼ÜÑÊJvѽ¡OQ÷Øt|;n?íp3ƒÐ©éüyÓaœÅ[ð)}ãoºùô"ò+ô+žËUKÒÁvµ ®Ïi‘p¢x4™.O»Ì$¼HE}W®Ô sËßâïBm>¡÷Ür—°ÑØ,Ð�8{�À¸u¡!ŸNs…ÎÆ®;5ç…=‚½‰Í/݇Í­É¡¼ËXæ?&%x¢Ûx<Ú|¶êØ K·n¸´WN’FÓ ï0]ýÌ,ösei<…So,ážÛV‹CfÊò…¯ÕX{¬+# _êIž¨tQ„�' zš÷ßA¿ö ¨H?Gêý)!e ó�2<¦ŽÞeJÜë‚3vÄ±y_Þ@šþ#•RKˆŠÂ÷GJxíø21r‰çHÁ}.s¹úñ~ʸz¥M½Iq·&ÿü0�÷Ï$Ÿ‡‰ðqÈ+Zøõ�Xüç.ly§‚W Î`Ý:;�›3Ç×-/X»’ÕÑ[´M0å,ÕOºñ†‘ пʓ%gs¸´±@T˜ã‚ÓkÒ hδìâ@•WÜùû2º´Y¡ÆÇ0>#»‘7ü)¥æˆ~XÖͶ™'`õØOdyÀj·GѨ)rx[ÿ£tð3ç5›LÓªQj1?˜ G�öù ½l7w»>�'¼†…Aðôª3Owí´ãœÒ¤|'�•ì·Bþ—¹¸mW!ŽH»I/› ÷{äò½×Ð÷°õ´!¼lèLn Ø¿¥çhÿ� üRk&JozpyêÊôÁÙYaÖ—L1iFz·L‡Ì’áü}òd’¼.§U0å”)g°Æà§;0`�'½QÃQý�“RÁ ²»èF¯çoìr«åý©¼�ìÚ^Ì)j¤»t"ÜÜó’îvŸ ñéC˜¡¨«6 ïMDñŽÙJìÃÚ”ßk¹½:$®jòF³ÝÍ4['*kàõ•¾x°ò¬ò €Ï:ùâêk6¶t7cÍì_L)•áøñl^zû'Ì {(ðãœHX¹Ôâúÿ¢$Áz£e� [ëï‰{ǶЧéeä�ëN6ÖAŠæ ÕÜ‚ko‰úGÈÙ¾«zŽB«}硳+ƒÜ\¤ü¹ãaæ'¬G|Ý[¯�ÜAB« jþ¤¢*ÙûOÕ£µpmìhιH–?ÀØÁ<–ÝF56Èø,IÝímÖÏH}éIR~”&Þ^^(Ô]ºO­;¯pþó’¼^¶×¦âÓq8=bÊl¹†žÿ½ÂÕûzðúÍèÞ¸œ74#“û·ñöûbˆ;4�ûRÇÑ5yy²>ÌIvEU¿¬žA™¦:צK)[©¢×y™ÕF’Ý'Ñ«Ÿ"~*œØøïæáAϾÑ×ê$QáX78÷B­ª¼î£=ÑOoT™§Í<ãàßž‘xÌa?O!ë]À륅XXéË)ñXÙ2‚ÏÜëk㘴v/,Ú/¢Ý»²°¿Ù&ÚØÅŸzeËáûA?*1¨à'Ë[Ä«,ÀÈiŠà'ocßü’¾®ÉCëûÄž.†âš¶ÔÛ;\£�’ûÏch¢Æ7→âdCî®Âò‹ÿÁå“©Prþ&}wmƒ ƒèòÍ^ˆ»B8þî¸<Ĉ#,µñýSs6“Cú"s^ç0¯ñÚÆ+§ÔqƒÑiPPÑe÷5Ëaºq"Ôªç²Ö¤JðX–*Œ™ºm'îáZ+}Ž÷¶ ËÒ!þêÞ~Â�»ˆ!Ÿ0S<>ĘcÜ·c/4Hïr£•GÅY–>RÅ1—±Ùµ½|ØlÀÇ\l}©R9òmµ¤ÕȘ¤W@÷¨DÚ¥ÉuÝPíö`ü7ḜÒÂ$#%0v;=ò߯ 鞤4Z–¶©Â*Hªb‚޹)¨ÿá8žVË…Õ~Q¼êA?t2·ã› zœ“¾]t}vWØ27¢Y[úØ6‚Õ‚ºaü:RÙl‡Ò¨¡|û�šèô9 ߺ/CŸ'•òb0™Ç´Ð?ìÉ“ºòHþ¡¡Í´Waµ¬:ªšÜ‡ÅRG¢<–?Åžûš/¤³F$ñz„µ}îaÄ©Bzæ?Œûÿ6^mý Çô‹ $dåns ç8k ¬¤W…®ÜÓîI3OI�ÚÏñ´ ÃT\Í>YbhÚ`^š8†b>ióBE¯Px¬õHHxÄãÜ\h³{÷³ez #ÇmßÎJnMø †É¸µr&è(q¸W_ç÷¡»Š1¨¿fÇô{#þy.ƒgfT ·V]åMÛÕøñOð<– ÃåЃ’=ü¦²+-Rá¹²håÓìÊY ±t-üê•„On>ƒœnŸ`tÓ9º4z7èÆú€�Õ·y Çuùìä÷Ú›�ñ3Ä/iiíxqxËW!#ÈT¸®¿k 2 }\0ü¶HL-8_\…˜y•%»Ÿòí¦Òà±h&{–ö~'sy\?Û}nq²é˜ÊÀélY¼tªT b´.îX)ýZP.ŽŠVÇ~$Emâ‡Éý7C¹ð› G*OÁR!<Ø€‹Õ¿p�Q" »3Žùì�êô·b»ë× ðât<ÑŘ.^øyþ!ØK�÷}òç1'WBBHOT †þ#và¤Nuþeó@°ò×#™}¦¼ïpé] €±z¼_~4 M“ÁÌ�ÇĿӯœ@e(»Šn_+äðH ÔܦE_š yŸsOŽT€O—Áá 4$ð/[7™–Ÿ<ƒ�G>”'þã²gpt—ÛŸ;1�>'AÙéRQ¦l8ûc}-Üõ¼†Ôôû`‡Omë×uÆà¸Šr˜9¿)íÁy¥óÄá+öaãç´¹öQx(»P˜‘*ÛöãŸÍ±éF$,¨‰ §ùI0»Â elGà©ã�ðxn.;vì#{H£º®Ælù ‚g} £+ƒŽbCJ5ÜÍÚÆñ9꼨çp©µë|xö�"ú5±Åˆi0ßYmޏ�­Ñxž]l‹F²ãðŠ×h,v ‚Ó ºCrílLé�Ï_¿‡j[eñî0¬Í<Í鹞èðCQ¬?Œg.LÚe¦XÐv"Ò) Í�ŸøI©Éf-^;#�?¬ÿR–ROt <¸.OºžGN#?Áë—oaÿƒEØ£ª”’ÓÊ餃¼Íso¥Š ÅC„k›çów‹9P`Ú€Ñ c±eß)ñ]½ oqëº2ÞöþF<±.T }j¨ßHu%§(5Ñßüš‰×§²îÇóüP»—h\o'M¼<ÛOn~y¦ò©`e´=üÖûaí«ž8»Ý˜šOl×·U(EÜ„î3烫I}Ð ¼ÿŠZŒà‡0wi*.¯Mãð?×qh˜ç&ŽýWHüoQœïo1°f ¬™?‡‡O7‚CQ+è@êDü*´Ã•I¬Ñ8ܶàÜ'ÇHÖFû¶Q·ž½“ þc0^žçÅQËêÑým~ý�ÜLu֔Ç ¬v›$ŒÉ¿'½‹…ïtžúùÐŧh»•žŸšGÚŽOñGßdq˜û18žõAt¼XMO'B§ÆQ¬‰�ÌFéq`²P�×õÍâT%7öp^€WB5ÁãëvÜo¾Ný7ï½H§;‹ ye–^§Íõdmx°!Xì¾Ã�®Ú|zG2uTÜ:?ÙãŸÚ°ê#©]9ó»újú7UÞ,c- T 4˨î#WéP×ÎcÌRøËÛ‚åÐrœäIº’X–©^…¡Oã�Ixéçq¸aI°üøHH9§Œ {PÏé.œy¹®ÁmqšÎˆ¥ê°6.ÔõãIÉ™|Þ¾/:ø .¼y×å{ñ!‡5¢càöük€Ï^˜ãÒæ~Rá*œÓK¥ 5µèsr<÷é;ƒ‹m^ÁÇ_màv!Zè¹å1ÅLØ »›R¹ÏÄ¡ už{“Á^ËŽðm‹1âüÓª¨8u&G�¿-ÚWï¶þµ›3 `ÈÉ|~H5¹ rá¦S¶ëWþFwéÖªf*;ZFÑWÛ+”ƒ£Îcs¾‘üžÜÔìùŸf-ÜݼNÑ⊫. `Åú/´âY ÙLb~ö¤ŒÎ·7 jA/x²÷,â‡óíhÝÛ |˜:‰çžYÍçzzqxT%T¿pá#•CñäÂÉš ¡yÎei6×ÓÄàá -�é·šÏXœ…K¢q“ñz®ÿ“‡�–ɤëžÞ厚¨Òò’Úþ\Ò÷Á†jMp>þÚþÖBVÕ0št3ˆŸ\Æ›ö}‚ý§ðΤq¬pè´ ~f=m² öè(᪜9lÒ&íS`ËÝýɧà™`²~*¨‘/ÏÑ_Í3#ðÛüBx÷ÑPtÜuL´­ùRh²([Ñ^?Ú#Þ_{]÷æXwYÑZ{Œê‚3¼r8'ú'4]€ «ÏáÖAñh^6ÖîœÍ_­­¸¹Õ/¬ýÊ2—r–¿¸L�ú1Vübôήî1# /½¥è7„Gî™Ã.ðÆù‡;$õ²áÒ¨,ÿœž�=n‚Ã…Þ‚³ö ªÝyš:�Ÿ‰®×<ÌÞæQì^g+q`ñË3P¨Ž³¿`êÙI}7½à_Æ~(‘ÎC.õÛ!Øë—û ÙG“~Læ kWñ°CðbI+•~r<îÑNA?D�oµ*w1ÃpÖ:‰^’%àïaˆ eÆÔªªÄ;7÷ãÛÛ¶ AOb)Àxl‘»#ˆa*8ï°®zbG•ï‚ÞTk´˜°_ξ»&±Â¦9 !gøIÚ=ZÚÑÓåMpõ^~\ºÿ¬¥áz¹Åë§ šwI¨›ÕÍ&~âhuŸÊwÞ‹�>g${}Å I(t°–¯V† qJ%pñl6Ûù$á¸âw1¡Ï`¼ÛaÄcšOÂìMÅâ¯�¢bÿÃXþ.N”ï�…þ½Dk»_ðiÛC˜“c†v»wò$è‡Å¦ŠW6v‹w)릗x_¥lw5¼l%Œ;Ä|©ÔdÝ€††üùû œh2 r" Êúðs·9X?¸®H+×6†Øz"ćlüµwEÐþξxuádŽ>3—Mƒo Và÷5ÂÆ6C<¤•@­Ýƒ£�½L–`úþyXÖž*,÷�‹6�kK¦Ò²ùGøKð5ÁàÒ%ÒiÑä«[ÁÉù”ÒÕÕ)t5î$Ëz Æ‚ºhÚ~ø\V_E£®`ÀóB(_º™‡ßßÈ£45Ùã� �­Ôæ%kñÄ»9ì¹ÙßwÚ µÖdaðŽCPß+Í랊 ?6³Rr.*ìì.@ôoøè-ÂÐ?T|“ƽ•çNË\œe³ž&ô¾E™ÓF°Æ©A}»?š_ÚL™S7á´‹k9¿¯œÍ̓ÉDq,œ½kÂRpKùºç¥Åkßhc·úrú/ø{�ÎçÙð‹Öß…kv½ÄÚ;êã…6Ì`Y¿ltœJ}^°0ŸüOe¢Áóú済zº)༖ú0M�žwjâël5RMšŒ ýåÉáM*¸­Œæž?Á³e6X=«DlXOí·ÑT¥ÿHsâJ–ר ÓË ¸×Rü—<ÇO¼ íF–‚Œaînùëvͥ˺71hŸ„ÃìƒìÀ,))¥?± â•ÿTYeŽ5¿{4¿:½¢iC0;8„Ͼ—a·˜@¸‘îÄU#ÕñKÿSüjkË…ÄÐiýEçç¼üÍUüÕiÀýd‚0çx U…ó: =ƹâGå¶<ê…砱݌kÇr�ÿ~¡Hñ {xk¶LäYÙ§Áid>µ™*Ú¨BvÁkñ÷Ø‘ÂÁC,¶æö«†ByIº0ìH Tg £�|¥Ê÷G?¦³!´©ßRŽæÿœžÁôêéèkÍñ±Nÿ¥ÉáÃØz`¾4ßÔæ·þY~§¸Õ\_aÜ­9E “»˜Ä©C,R}#µ/iDׂìB`ã‹yˆ~FsRŸ>ŸõPôÜáDQýó@aõoA.\÷êWÀÁƒa82ö$ÜÏ4„ÿ¤q¬`ÝÖ&âs’gíõø5ÝŸ†4™ñتQS´žŠRé"ýÄKï·`Ÿ}utz×|鋯gl`·›3¥†Ÿ~Šå‡ûá?7y:jPDZi}pćTÞm|2›7âùª¸ì¸&?I¿AzeSÙòÑ{Øãö€g{âΡ©-s5„*ô¢}ñkøÓ–0<ÏŸÇ[¤%Oä* ÞÕBUóO’þìb‰PžÍÝîƒjõu8f2—ov¯ÙÑ2x¼µ@èÑ+ þÓº¿,ü°cö86w*Á²�[%;UÔ`ÌsˆZo‰oí‚Cr­T6[]@§þëƒ1Z1|2æ}» ¸�ÉÁlù?£ðøS õï·=~ÔÀ`)…n+|5º‰›wF⯠Oz^‰ÃülÐ]vî\‡k*�Є?—©�Y?›\C.õÅ1»zóåÖZXŸªAa]ZùP,š¦ÌýË¢¹4®�·§²ll8 ÜØ�O¬�-Ý/RÎ? ZÚùÓ{=Ü]Ú•ª_Ajåh|,35?ô'·ÿž‰ºg#áã»§ÂÚ»‰¸‹Ê…‘#×À-CMô3�€µ¿zâl;kɶå?àÇäi„ËÍá�~©éÁC´ Èóe çö=‰ŠFHkÊø!éNé™r¼Ãuœ¨üù•dí•ÁíåRÚøü!ÛXŽ„��¤›™{fðOlÚaˆ�ªëy…� J&½µÎÄŸvÍäX?_h�¤‚WÒ3N~¾�>œQµ±5È¥…éURÇ[)ÐêÝL2e&H9ÉøAÁ–Í=�€çUT3Ì£‰5]Z~)»žüÌ #øåoS Ùm…fi¡á¸! ‹ÏÚAŒDŠŽNм^êômì1 .$joøç´°ñl4;¯™�ÿ–�Â(åVšo¶[:=ö ä–Þ¤}¯? -Í@'ŠÄå¯fàS˜eµÇræ,CÞeØ$Lß‘Ĉ£‘ìwá [b¯=g±(L™ïy¶(9âúÖtH¾Ø*̉ÅÕi©¸îs,™í ¯\5ù„ËzòZ©Bjz_`IÅ>Tª;)^]e…ÏÌsiÁ� ºü\�ïó§ÌÀX¾øšx-G"ÕÖƒ¨¤·0úF‡¤3O«®‡ñݲÏp©] ÊëÊáQƒ6/°C^V„™~=xå×Ïp·.ŠžŒÊn™ÿ^·¤­†ñûP@¥³'!qúQ¬žÚ,Þ*+Ôl܆ëÉ6§àØcE•Ûþ°Ì\/'ƒ·�/Ïž«Û´‘]c?øPÈæ£nà¬v#³k2.Z™ˆ“r¶BÍ”&˜{ïwÛÂÎcªáÈ,E\TÞmÊgóŸ+ªpüT$§ÍËeJy—Ö%xnC…³³k¢.þ5Ü·ï¥å+¤¢ßÝ8^9´Œ¦NÛC÷Ë/“˹o æ³²Õѹèðéu!½µÈáH“Õøs¼¯Ò”«T4ZÈVëtaø‡×ȲgÄÞËÃ0ø(}Ëk»øáôуpwZ—·Úb�ÚiéØ1ô¡,¯Í¼MJºcࣵS¢C»n.A¶¢ä!ÉðøâÁ7¬’¾èoÀû“ªÀ¤æ!Lds aIÃRÆÃ‡mèþ#v4ôæaýåØücj�¶!y€CZWÀÙÍÿëëÂNs]¡·z.�uµ§dÏ“P1÷�ñåâTìÿe7•Μ#Îð°�ã�`ñ»J•òÞß%•~±£ìf°Cw4Z`b�bÓžmµ¤Ø`¬«ŽÚ/‡€' nIbÇ`‰F«¤X§›ÍämáEñ_RYt}“Zà¨åTT¿ ‹ç>ç†ëIøØ§R¼üéR–ñËjMá@òoáoò?ñöÔ|ŒæÈö%å¬OOh»¤�œ}¿Á¾|U‰‰º¼¿Œ5b3¹iÔ,}\@õ¦ã¡m¥>¼±ýO²¿·ÖÔ\†¶…ØS�¢£g¸�(†o¬!µúJèYÒ¿ø8Àƒ²‘âêþkÙ‡örÇ­7ͱb»" Q$ƒ5…¬Ó13Þ iDàÜÊdê5 R’W7„°#ðÒåÝ;I°wF8}ˆ�ÅCcä¨'lÆ{kðªñØo¯è`Î7øÓmù„à+κÖ NÎcþ=€[•?Ð ¹îØïÖ=\¶{:Z³fµ@MIÚ̈ìüŽW^_½Üþ\›f4 V#H¼¤�ÝWƒÇM%ŽŠgù{�³%ŒÊûŸD® ÂWr¸NîçÁ¬�¯!á^<™zÉr°I FŒ¸=·çàØEìvß³uF av÷ÁºßZ–; 9À„�¯Ÿj?^ÐYKò_MñýüßÜ¡«H .SË¡—0¥Ï3á�j5ÙÎfL7Rδ§¶šPí>“rØ´f–¸nð]±àïT,J™oõ�ò»òžW!>�ÿìµÆPYEQÖØnw6°óרg¡K/*²±F„PÒ´“^Äpï�…™ínú•>Þ&lyu€ß¢çb©à_Õõ–ÏÄ/Ýfaü’£B–i3D· <àÌY¸¸4š„éç ñ|*,¹<ß^Ÿ)‰\nÃ2™òÜê} ö¿«Ä–?¿ii†;†ïså#ôxJÍšùLz ¥¶afP§�Ì+Û“ø�~ΖsÉêR±höL8w' t†Nä§_óĹۦ`øIù±’¥Ñ¢ÇÞ([ÐŒŸ#—;ÿmAó·¥ ŽÂÖoÉ(³ìGHiÏ¥Sô=?_=)Ì>sm› ,sÛgµãIÍt¾ *le6 ã/Î㕾;Qg�*¶ô—“6oû Ö-íÏ��+𮼶dšpÍÇ]x}Ô'25˜È—eðô�`Ñ\QÌO2Ãççð:ÍJ°xúITó›ÊK5pÛß¹ªDŽÖ˜a�ïoQ–—‹ƒ(aþŽÜûFlúÕ�·Õšà«ë³hK`·Úwß]ðÜ~Ü`�Ckû™±k䨨ñƒ8gMÎû‰Cúkq¯m÷AK݃Û5�ùîhKZuLàÆÚXx¦7ž7�9‚{^¡Ý…�…O‰Õç�Š¡Ø0y¾xl'ŒÒ3ÄV_én^Ÿ,û%�ü´þ+ŽÂrÒÆzŽx0æM\mi22¼ÌÌ]Zг],w¿�3wj‚�­ dÖž‚=çfsÕÙ©¼jŒ¶7<‡ßF‡³Ò¡~á5j©èέ-[pZO˜°¡š,ܹüY/VËÌš.ÊÜð]��éåá(¤#…³cÔØüš<Ø' ã‰=÷â!Ÿ&ñÝÇ~øáÓÎ͉&ýPàÑÿœóF嚸š×¿q¤Áßmñõ×,~ �xoÃI¡aáA±nò<Ú—«ÞƒÅ3Âø…“ ËmÔC…Cáx0þ:eÚçᓦ¡¼";{FÐi)äxý¾IïÀìÕé´ê×@pËœI®±©Ü/º'4ï!0‰1@Ïõg0çµ ãÈqؽÏ?ö±ë¢„‹­€ëµP+§šÞŸ�(Y¶å¹xà‹3]¹£KrK& ì7z8 ˜¦¾…åî´O.Ž’µ�øÑêÛä›#V6ÁèÖ¹�¶%CÎûvñí̽’ú²fZd>رkÞizp4knTẖBø›µÂ¡ÄÉG²lêwaØ]±±ú }<ÿ~húÂKŸ Øwú·ÿáS£þ±ÔìxYýŒ&(Éò²«j°ÿ²(ŠEôÕïoí¢?÷”ùló4R^‘�¦ÙÓXkßVê òfLñåc:¸Ó�„svF¼ûÎy±þ¿“¤õÈ—O}p¯k`žr#}tÛK ‘›@gS»pY&ߥ\…M»æRÑÎD¾îçÉ•?̰`®=Ï?k…§‡®¾šú‚f.4§Ê±þÜôy1¾¹®Ÿ,pý̓àXá�=ÇRð­|x7W_péÔÅw#Tá^ÀGáºÄ·ÎþK¬ðêÁ+üªâ;MîÝc�Lˆ~ýÇ“žÔN{ÖÇZòªYO v«-Êë(â¦)¿\‡ßã'¡øL/ׂ4¥¬Ýß-•(E7Á|ÙP>a’Oã÷ Ù½ J:úâŸ_¯§Õ#SÑà÷´?šï*.Ɖj~_Î ã'óÊ[‘¤; Ih•Qæ!iUø^ø£6„:V˜ ß¥|¸d7½4=OIÓYCI]”¸öÇWZyµùl&ÁŠr?Do‘Vú‹”V1 Æ'0;ICÄóúëµ(±–c»×SÐ3+�Ï÷7â~ýã†è£¢Ùˆïpsù3ò){Z;Ú‚£(}�2¶ ƒö·ïhfG"&Æï�o÷åùêdo\üý1蘌ׯ‹e Ýù@Ù'zsü2üº;˜ Ϋ0mN«5‹%¶ŽG©âF‰(—xSô¹Z ¿zåãýòî¸öõXq‚F'Ô>IGë¯zœ‘dÏ·~0ø¸§áEY9,=Ú�K§»2Ìš¼‘g~^Š·G4“«ÂB|ñk=ÄÙhóÂuJ¢÷ŽvÑ1Ö�g>T滵ÿõMT_ûÓó�ÁçÞ8ЗLC¿Ûå´°÷.aÌküÿS÷¹¡÷§…ìí�‚ç ¢éÒÂIèmþl‰…-ã±úEOïÙƒŸT@ø�;к¢¼3gÙn?á}ã•–u\§ÿ¤Ë&C‡V˜Ð'ØAÄ-saÉE 5i=¥-UÒƒuŠv Xùåý`L“ÅmŠáŽ�îâqoi#”Ç_�Ýš†'[�[žõ©y ¢ '"rÅÛbéöû“PeT)¨;É!_Ú÷ õ€òƒ ^_Ø«üýD§^ ŸyÑÙ™Ýyfç9úÛMÂokÖi'Õ_’x«Ã˜¤`ºT¨Îu}vàˆù)`2¿‘ž)—ÂÇ£àÕ Æ):‰”]dÅá›�ñC›/ú¯| ¦¯zsh?Y\ê¢Ä“”ìÁ¸Ä•~•NåcÑyüWf¬h¬·��Ûþ–œ¼r ¼S[èv¾ �9º�Ûšî�vf(©v=¡‡äÐ s$ƬÛË={.=pMcå¼OÂбÆ|êö"~݈­‰¡††ž} ¡ßcÞ9f5Ýó>m†©$™ùÞ5ñ�ö�d_ñfƒ±h<ƒŸdšcúrO÷ùá¥yÛ]oIÝ®xÁÄö©`ÞˆµU:äÖ~>† ™�eÜ*?ñ”üR_uq®¼Co=�šW]ï¹Íæå sAÀçõÅbÚ™zôò\ÜvŒâÔXôî( *÷ʯŽD€âeá†ÍjöžŸ#¨õß„‹/…QéÂ!¸ù(e�Z�VGuXÝΊ³Ý¥´ß^(ÿ£T Úüÿo>Yá¬AsØSu8õhü ÃúD³×ݱ‚õC|�cÅn2š€™ßé²_<Ž» Å^ ptâJ®4Dùl>„¿ðÅìa4ì‰ýˆ0%ë²½hïq„ýölC'ãñØ!ׇ°Úë}pÔj‹âqVÛuÜÄo`÷ÅP^ÜŠýã_Ñ¿{ã¬eÖÜ×L Õv]‚û[§à¨Œ`xèŠ_—îæÙ©'„3oñŒ%ðÛ 0KÌW]î—y ¶œ—Céa¹ÚÑ ï${õEÊk—äsåá�·¢øô—Æ)çBVÌlZ_óKÈ×*ÇŠ†5²ªõtaü~¼ö"Þ›l‰·U ko4Uâ�ˆ3ä°b"/¢É–#útm„ e¬ÃöcR)Ny€ Þ!ƒYKÏÒÊ\4ïÇ<Ñ‚J7n§ì9ZµÝúÉ“ùÇ·ÔWßPW0 Om\ ©ƒÅÀÈMx!¥XX;¬'|»òÿ÷fpêâ ºéõ�ò|Bë€ep:Z­ÞÍm�=¼ÐyFt¦bIâRÖ8‘ Ÿk6ã�Ê•Ôséñy€,n Žã‡qÝ‘•b¸VÂ;¬|°R6…§ÜŽï[*³åŸ¯p¾o0Ê �çñ~ñðµ-…l0‚6& ã]DZïï'(3uÊ”lyD†ëþÿù�éü*Çô{+ašK7Z¶5U’ºSã÷A¼Ùý6¾~£ÚO5Nwõåiî_H-p#·$Ïæѯ$›çX€…‡ž0¦]ÊýC¬Ø“&™eKacÜi´ÎHº'©^ÍMƒãmʤkeŒ¾Fáä<,ó_À71=ùÕŽg´gDíuÿJ®¼¡µ!ò‡¬ˆþ a3¾Ñ­Á".ò=Œ}¯Û°É‘bª~-ã æbœ¾?ýº\ƒû뾂rH#üH>ŽõçˆâŸÏâö¡³y[X_û¾Ø‹ïM’gÿöKh®6•+Ô WÊSÁêÍDÐq=@mÊÐÑ}?Ÿº{™ êeÃ\ÍØ@)Ÿ%¯<øÊ^'á÷Æ�˜k�9I[iñ§ÉxÿÕPö� f*Ðùôp¬m&|î<ƒ˜9ŽÓc¤¼ glÚÂii¥|^N¿äyáõ΃qÿ¸äØê½X¶ÿKG¨°jd8.)XÃÆéŽ\îµ�5ׄBfé!2aü“Í|l³uÑû¾"´Þë)þú<-¯k8Ú�õÃqÝ÷âø_ØÏºLê‰:=ð]Ã>¿<2UfcWþœ#+5r3eÌ-,—¯¥Ÿ&ÙXá)º)5p«æ‹Rä×®I¸èñ)áóÑÛ¤êÛ…ŸÒ7r‘í˜xõ/Ü_¼ˆʆ .Šã çgSÈU+GÁΆ>|€¾‹È8¬�JÕâtݼýµ܆žÄ«ÊÁ˜^�ó?§Ï–´Pƒölhuõ ßèJ²ýñX´¸ãÊßÎ ±šÙì”™~+ó›+þ\<ÐŽiØd ´5ÂäË&0[s!ÇIÕ ¼Òú¾ ÕäuÓç9®z\úo;’.àŽ�Ò–Ü�Xvz¶÷Và™Ò¦‰W±Éª»à]N^Î¥£c1aÇ nm¨Ç„çndòþ æUBÑ$þ|ñ0«-WòJÆQ·ÈäjÊ/½ÕYá¼"ªÅZ £²¶OùáðFsÍmÍnöW"´zÂ�kûó�’…¢_¿éšû1ήœv/6cqÑoÁ[vGÆÝFÕƒW5½d×¹}„U·éêíÛ¢Õï8Ž›¿žƒiÏü:ŒT~m!�S*øÀäŸþ½ˆƒ4bxÇס”x§”Lß,…Ю �úÞ—ž‹#¦-…sÁªí>wîÔáÝK‚ê‹4¾W ¶´� �éV¬útüjÜÏç¼ðtÂÐëpÛL–²ÓµQ0ýÓ`\:ä7Mï÷Säóà t÷{Ò·rÜäÒ—ïv• Þ‹nµ#º?§Qê!ÐSÉœ/Ü9Îߟߘªˆ…�¶üþðLöøû’:Ñ¥©×ycÜNêÀ‹Y‹]Eæ¼îÃ>þ~ö'-’CŠÓÆŒk¡ìi2ŒN8K¥GÙ[Ý âç4rDñ^AAy7û¯Õ_×rEN!ΜcM‘ CÄqkõ°jöCávwO¶ðMƤYã9¦ãÅ=F®øbP»ý³+6×û»s´Ì4¾÷*šÿÆý¢M¿‹ 6W�ïïãcß÷r†fœ°l‚ŽØo½|zÞí‹V`Àžx>Ü@^uyºÕ¸¯$‚’ãbˆ(Kãcj[pøøT;ç2Þ™b�%«9âpOÑÊ=wæ}êkJ\æõyêBFv -åpú!­$ëÐâþˆ98¤F™Ôgk9ʇޡÉ{D³–¨aòy¾Ý™ˆEÃÊøòÎ�¢î£{´9f9n–OÁ3øÖ8;‡Ûêi¬ö²L¸~o,Ê%UóœœyiÇ�'¿“Sz¼GgöMPsÔUŠæô§¡°PŸåþx‰fçJùÉêdZ¥ÇЧ'BTIï|`û7¸²ý•„Ëó=wM|è…Ë•¢…%•‘‚ò¦M”¸2o<Â×·ÁÚ•‰˜Wvƒu}qû7=<÷`›Ÿ ß»á[�mlÐÿÙüÑAÇtö~ÆS Õ@n~4^rSÆ�%“¸kF8|,¾}œÆ¾Yw`†IH—΄Ó݉?•� »ŽI¶9D Ó'‰´ht'º.\‹÷íÒÑ|ßV ;³^ûBÅüSôZæ)Ôº—±±MG©Mçí ûX7tŽØï¬;¶.ÐÁ‘ôqÿÜÏäà‰×V-Á²ä^hV»KsÑN&•Íär·)3šzä í©tä=c±b�6ÙîJëÙ¬��Þó\·~I§Jç�Ѻþ ¯(ÁW‹k¥ž.Uì"”NÔ–òĺ¨vÎ[;Ê@ýæüËr�är6"êæ&JN~\Í6FCjWÏQ¥Á GññujÙË ,;p{7}^¨¸\¼ˆiÍuxkêNæ3Ï‚VÍ ™ÚÎ1Én¸;ò)þÔKç·ºùâùÆ9¼°Î–&Þºý®Ö€ݧÎû™¤4N2:byôk9°¶°'ÕwýjGŸ8CT È"L+f tÖ`>âãƒõ�Kqà¹ù8¶¿OÿJ—.QA“ͱì—Zíl‹ž¼÷kid™aÌÃa¸ ò9ŸJ/õ;O�=N’ö)-;"MOzÂÿÐ÷U§ÀÞ©_H«w ¥ó�Ë0hÎ4-ÈÅû ^¡+�VêH½‡K¨A/�KÿV@ÛÞ#�)Ó$ÔNÜÃâkqpÕ4 5\ �o*Îúpwx]…gÊU<ÛÒö©=†ä[£ëúÜ"Ý Õêñ¦Îi0Y3›?*ú°£ö+è1ÑZ°éOãW¿GÅìPN›Omçá�ii4�Á�>ÖT°Ã•?j ÙkáRÙw[Øi²YôMþÊcó•-߸wk³è¾¬ /kˆÙBÖÃ0t8Èÿ©^”ƽÿ@i‹ÝÙîC»P¾ý9»@€¹ËoòƒÏcSxiÑ9ìmY†1½ŽAï¾Jµ�f¼qe*ÞÊ~ÃIÍ1àZjƒ §ðºoÉíp_LÈ�A™€*0Ù𗜼Ͼާ¢ß3 èÙ:~Þ1[lÁ§ã•yHK ö6n#ƒü nü¬ êUÔ1&ÿ4݃;ƒˆoŽF·ýÐÛm5Þ}`Ë÷¯ã«MÅ|Ì«’‡?õ¤K‡QPõ@Ñpœ+ÛŽèÉË4¶CéT•jaÌDt‰ÌêÎ�©zÂ^:!Ž�/½&‡tMn·|‹®Ú¯Å}O1£é {8ž'�÷eXú€ L/ƒ·Ïîz¿›YæUô)‘¦�wt€ïœùv?oÖ+Fý8Ù‘‚ŠN ìûH¹–N¸j]ow> úyÑÁðnGw¶š¸�b—Çñ( lÚ u£k°_ÛM’ssGß›'°#ï%|^^‹u²w¡àþ òÍÎä­›2P}ÀŠzgÊÁ»Õpoøö꿜ål¡8�£?s�WÂëzkqúaÚxù9ÿ>¼¯úf¢½ÜÌ(Ë…¾½'²Ã£jqryõ­ã�7kXÞc=¤­ßÃÍêp¹ŽáJöP:´Þ Çl~Éwwaïä¾ÜÖÃ��Ž[Õ÷òD×Ç;Y¼l�þUµpBá8îÿ�p¯×:ÌM¼Hoô£%}ë°*Ì|«eé«e¨²ô'xÕl‚í<¨6ÁÑïIlß̧x§L!âé,Xßÿλ ni|L2;.P»¤ŠÞŒVÄ˃ú¡ÿѯ’K͸´å ¶ÆL%­Ï¯è`÷ñø<Ó µŽç³ü¢|}¬"Îû‡kN.Çs ´ª žìúÄ�kÃA~ZV2­•>Óû —íuñƒôë¼ÅÆds^¾+'¥À`ã ½h=ݧK‹ÌapÁ;‰rE=™r%·ö‚]óSð*?„sËcy™±më®�è6ƒÃÞÕó’ˆq\x»K*<ø×W;sàyºÈ-º‹ e¦|`é|±ÓN ÖïmFÓýq]¸7ŒÁÂv-ÇûW߉>êG%6sîÀuñ)\ÄJÚ_%jÍCyö,K~²¹KþôÌ*èNoŒ­ å>²v<¥^À+Óí`JúYœ«³Ÿ3Áç‡÷rôEÇÊ‹qäûÉÈqÊé­x¹ûØ Ñmmã`ÖÒGÐ<ÿiŸJâUÉñ0`|*Ç�bÅ�“ð1á ‰KóÛ4¤K….)Þ…‡¦{Y&c?ï‰Éàê}Îü¢®Üq<øïk _ƒ.¿âçJ;$ªn“Ø£%�ô�1û] ²#,z/|Ø,/l)Óg“ϵ´­ë‚°Dï“ðP ¹DG7]-Äá'äxÍýl!4³ÖšnÁwÖÑdaÎIæ¼Eô…�ªÁ^,„ç&o°]-„¬zA³rT`V–û¼žOº}CÑôz!_Ó_†úúàa�â6]yÇ71‹y‹{)tí 0äU�å°ŸF¼(5&÷žÅ2Îtoó_ýE˜®µxÅÊ:ãñéæ \Mº3�%<ÉxïRØ/¾‰öÂ5�Zaä.9|ñ{/·+åÑÑwþ�û.~1IĶ厸ÃìŠa¡løk8ö ŸŠ§3–6Žæ5õx¸¼U˜ìkE_ÞöGy3Ǽï¸{©ÆW»c_S¬';5L¾4Ô|_{WÈL…õ“^òðÆ9iM4Ì£»õo’^KÔÀ€Â°3o†s W çD5~tmN8x�—™Æð7°ƒÇ­÷ð`o´üÅgó³É»# _僮ŸTüi9�´sŸÀAÜ&~ö’¢ÛÃn]‚«¶T\ÏÀãýJ@Õõ~ûÞ†0J¦v]Ï¥ôíÀ0‡”§ñhÐ냑HëþKålšÈxÙÒ‡æÈñů³` k=ÿ÷oÖWüÍÝkãOùÓñ„HæùÎÔÜÞ óû¥ñÏéð£Íe÷ª¡~gù�ña©b®U\Æ7&«@ÖçZ1;ÉXRûÖ†|…+Sh¬O#¼|õŸ qä_Þ\Ð@õÇñBÚ¥=Œ pÓüq|3² "V÷æ´¸Ó¸Åk �š5ˆ»¨@ñ”™Ôù'm²8úµ>š€ÔMWôê¨Æ/jl¯™Ò7DâêØc<7.M2£`�žC 0üVO|Ö–�šÙÖ¨ÛnÈõ�3ÙvñOªmSæ�iÀrJ»Øô¯ w•uŠÍ‰=8hf~t4æ{3,øØ'=:k;÷ôÎ'ƒççhA/þN«'§cz°*ÎLê=áÒ93ÎêÍbŠ,ã³£»„ç&Ó%ÍJRLª©æÕu½q÷ÍhÁSÙJÇC}(ß) ƒz³ÓÐ)¬îî`2i#^Ð g×ÿ!¥å¸vFºÔ(H‹”nÊ £ï¸P’¼#›.Œ";gºlžÑ�+N<¯yÿ¹ZKÎ^—<÷�õ©>Ô3eøW„ö®¾ï¡xŽ©`½{ô=‚6C‡€GrÊÔubæØuœ8ü>¤WF®¿% YŸŒÆ¯’¡W˜5Z]ЧyS³AufpÜÜ#�^ ªã!`Ÿ{Z„©<àŸÃ<¿Ì~6oñÆeN—O¢,ã aôÑŸ˜!EìÈGË”Á\d™ÅàPFKvív’f» ây7Vr‚úMŠÝ—­‹¦³æbyt¹q 6óIè€Tá¶÷lRö—Âï†\9$Š•4BĤ€_Ʊ$)^ÿ×—Kž.––¤jðÈî‰âê&Ca×euÔ>¾‹?Ÿ¨€s§£ùuæHžçŸÅæ} ¡µ3—JCð{c¿î¹‚"W à¾'TØáÙCãø…Žeœ|HÃfçÑ�n›ÄÛ[´1åeñ·§VzE’^âر¨?¨+?‘X]Ù›×x�áQg ”„›óK1ëC7òÕ äC{ŽI+Çÿ›r× 9mù[8_¹<Ï­ââ>¦<`‹2·üsÁ5NG1;ï0êæisCÛ.î± ¸¡›=¹¹…Ã×Ý=°×Öî�0ø¾ñ�¢èš{4FCü:·àßW²µG—’aZ%´MÊ«Cvœ³òi•Þþ#x,ä©YH…-'c|íþXÔƒzÊïçÄ욪ÏQRúbŇ/λ-c1ýýw²ú™Äõý^º5´'¿Ûü�ÍrÍÙýÍnzyõ!E¨B·óy”<|û¿TÅæ'¹ÔG«/W~î`·ò帲á4ô=j³²åÿC•[ª°,m'ö7)VØú�ò V˜ͪvGà˜~¬[ Îîr¤œþÒèÅÏ�â¹§*¡(^Ÿe-Wˆ¦j¸¬*ƒ€Õ\ޑɘtšY»€õ¥Ï_W“ê3…Ú.”r)cwó ‹ßô[}¿¹a ~ýçɃ«+yi¢2™ç«€f–3¾i¨€iºcÀD·œŒÃÁ–Lc/›·Bù{üÌïMJË”0d’/j(�m¾Çx“Ìxº©«È+ä3! ·÷™»„ŠÚwƒ´ïMžõS7´-Àû¾ÃýY¡œî†\Üãªôbr·��?MFqdûQ6>äŦ¤ðÄ)½YkWœdUãp¿ÅŒ¦©ÆÂ]#^Y3”úËåýý#yÒô}¬fí)œû¶ƒý¦ÛÖM‹¨8î D¥¥A¯½/éäëXi~-Çâ£Í³@©´„sÆÌBl €µ«Ë`rkoÔ÷`p¼%fô†-ƒ:aø:�ìׄ!ÏÞB�Ñ3ðÄâ�ÐaX'<œSŠ�ã ¦)ÇðË27\un©(ÎÁ3j’¥_÷6WåÃ-†bk­d~y!y펛Ÿºa÷k ²D�>µå×gî‰rM~è±�•ëä¸àðxïTåK—³[ÇTWÂŽYgÙŽ>‘ÉÎYü»—.ÖïâÑ+ž“ͺR>×"P· °Ùp %¤uà ª„מ½ñªþä5žì·{+]}‡¼ïòÌà?VTÄ ÕsÁØ3H2}év¶ØZ‡I uèšÕaÑ 3�nT½ƒQ®"N<žOÇZa€LÊ}›§+G ­ûŽÐaÉ&x·©�ÇV}€®'1PÖ·?»Çjÿ8MmÁãyU!õîµ’›ôWòéXn›6&Õÿcø÷y¤òP™¯4Â¥Š6¨&ÙÊ.›©àíré�¢Éú…s!ôI­xµ›)ï>…lœVÃÖÕoéú¡N 8fHW/ä@ŠÃBI ¿]ªE·ÊsÁ[9åÝŸR´ìVp°^ Ô€">“Õ‹t)ò„ü4^}Ë—_5Áî½—’Á-:š‡Î&l^¾�ãÌ „úkê<`¨5IœP¿dÅHb0øâWðÏÚÃ-(gÔX*¿¹‚äÏýêê%rÝ��áÙÅl¡G®!¯ú&|÷5GÁw\2å­qA`ëÒAËL@N;5d'òä©'DK]{6z’õzId¿è&¨ úCÑS¿PçDÔù{Ö×B—�z§Óf!·×WÈ`2}ç‰� Sù]C8ìóqu#\ä·”oHëy¾…Þß¾ Vô¯Â ¬Jxl§ÍOZ«!°¬ —Ä”p·ga¿ÿ ø¾ïØôzl$l[=PìÝË!σ-×&â˜kgÄ®¥!8�‚ Ö¡ÿмâ±yh>¼\9®ø F-#80µˆþ^{^…òÃ5/i} ô^⊹ƒ*É Û_Qó”^k~Š&��Øtÿ1rºú <}àæšzˆië”Ü{ �S­»á¸e£0·³€ �Ç¡lHk-ÉÇGŠk(tè'‚•ò|Ã1 }_%óù³÷Ds×P|z-�æ­©¡ôï.Bx´5÷ŸI»Œ«É0oƒp{« Õ@§˜,Ln%ìºù’ú�QÁ3-“ñEô|>~ˇöÍæó¶º4Ü0‚ŸTMÄñé ˜(ðÀ÷ÛÈK/ã8S}g'<Ûfƒ{Á:r„£×SPûïÊQ²9Î<)¿�×…Ä t‹…ÊU±Ó‚¸r8’–¤¿¦ù�†‚†J2®MÌ@ù—}°_û|ú`M÷´ S;/ŽïOç”òO�”³�êïäút;d%ΊpÆYšSpkÓI~/ˆ_Ÿ gF|vX8àº{1Ð5.•[¾>#%e|Ó­‰¤_%â£kZ´ù™+~Ììc,²o·ËàÝá…æÊcùTÏkÔÑç ”&mÃ+Aº|rQ)»î›Ï¶!Uèa÷>:â;:"�n>Š©áWúÞ¡Ÿã‡^!w<’Nác¶*ò\5eZ½"ŸNú—€O™úXõÅñcS…ícOÁðŸê¨ÝM £ûMÇìUë©Ç‘i¤6@Àþ=by|®šãHGE¬®Àc<ü9YR`1žÂúóж!}emªi=…ò§óÀ–Z0)œM|¢„¼à`Œ“¥÷…F‚ãµ§°ê¼ýÚâ`ÆÏ8üX=#†¥�ÂËœû7”æ'Ñ`9¾ü±þ~ÆŽÕ‚Í3_‘�Œ5ÎY_ÈßÖ•‰oŸ¶Qå�y´Ò—gš±Ü†‰$WèÁ¶#/AöhYŽ4Mˆž^Fou•i‡� ®Êv„“œ!|è;22þ@¿žË°wõ.Lœp†>S¡ ¾x«Ög4+böõ^2,3<7C\V$4ÆqˤR1L]Ì~[°åhñáå 4,j5§u¬¡)zrØëzYßÈýµ†³2t—xæ^¦…–½ÙjÇ0þ¾l$ü™ÖHñm>pÊÂ…ÌC‹1ë\‚Ыú'ü�Œ‚[?Ú°p‡ï˜OŸôMaÞûïfÏÉ] bÚ½tÁ$o74å= ŒU%YÑÿAÛUSn=Þ /¤/Ùƒp/ÃCOb$¾þÑ8îV?XÙõ…CæZ ¯ù¢¨4’ÀêÉ-Üh´–vfšÒÔA1¨³à‹¤ë…)ïjX�é�W±Îâ[׳¨µ–¿ÌÌàs�iÂkc`žŒ|ö¸A{ÙkïtŒIp¦³2•¸ç¨¨®zS‚“…U®?á‚S1œ‹>zƒ¸á—ÛNôÇ6»>ü5n+wý“‚ô®Ðµqм¶~n:pRHrO…þ)¾}Ésî%£²·«FèsÚ Z�2h¢bÁÂíìWW�ß‹�>,„ k)ê9n†®yªx22IÜŸÁ!xáönŒ}n+¸eän±âô6¼{QMãkqÁMÉéuNlÛô›Îz6Ó›~�ÔëI‹d†vo¬¿ÕIK2ÓpmúTœž³oý»§§ì�ODqº…1==ˆ—â[éíÂd6ìBßþ¨¢ØÚÍÌŽà‚t+\czÜ"Ý!küÄïî<è»nÉZ^ã¹®AøµM…ËÍ£„Gy!Yc ÆæÙð«ê#ºv)þ™é cÜÚ©ÐpÅ“x\èCxèìO÷jŽÁ²¬‡ALS]@±Ù䦾‹‹þ¡{Uø8¸¾M›ÂÖÿ!ã]û0­.•BwaŸÝx.è%{�øFK"^úV]ð³è΢Z Þ<��†‡Ac‚çä)cJd'¨ó§:¸õ\�êÀWÿµ¨¼ûO±ޱpkÖ*ìòHÀ»Ù“XÉÒ‡&ÚR—W4H߯agJ6u=o­ Øôn¤ÀÙ˜z˜Ý»„ƒV›Q[«šãÜ{¹h¹î‹ ÓE%PÀS•…ÿ¿½º¬_‡4≠^’ûDfÝs(y�¾pÍ|/iÃ' ŽÀ¡ârV 5Á½Ãƒi{¥3ÿ<¡ÃIzò‘Šxòk*‰wfcôÌOè5û±x×ÔòŒçS~…‹ã®^¡ 3-MœPæÜ8úù ‰Ý"Öè–ˆß$Àµë�ÍÌ|œ>´ˆ´ûk‘øy§ _ì·Çïša6E �XŠË2¿R d7?9Ò!�˜!ξ´�].¤‘òìS‚£^$D¿ ‘޲:†ûÛ‘üî”BnÞJ|à“áJø½lOP¨Šgb‹h«XÍ‘/ÛéP×ÿÿ•á… ‰<Éà .VDÖ‰|è«/½cÃËÄ·g]øÓSy>T¤Â³õ»á^i ¬97Ó »ÄeÝäÙ6X‰Gõ ¦r¯Ñœ¨(â” š´¥oŠ“Gð‰î£=»™Ü¿Z“† }o¾òðCc0;³Šd\€½Î8@KyG}ÓÅÈ»wA3û¾ê(&¿³­’>yAøÁâ,¼Ž—ý{A]¢5NîÞZ¥+¸ÁmïÀZ4:Ïr)_h¹¾5å:¯–ZTÍâv¹Þš£-xÙ$²âø4ᬎϓB³Ñ>¾ýKÜ{æ"\.O‚]½ïÒÄñGaö·�2=Ç$Êq¸­„‡w\`ÛÔ*½u »dõëÌiì|N‹�õM#‰úŽ;ÜMÂÀÒÂÍÂt¹³• æ£en0Ÿó]Š8pÝûÇ!óKÕù oÿu'ju5„1Iw{Ýâ‡2#YX?Z¸w/…ÿFíd/q•Ü€‚Äó7�”£!¨6 £OQÕ¯nìhVÌÍ~K&®oÙqƒqíŸhíñ¯ã\üñE÷@Ü®÷ ä× æ–¾£DŸ‰Ó`LáD”½&—ÀÔ_vh:ê¹O£ó£ŽB½_0õЊÄ=£åø‰ÍKÌ®Ø ­ëŽÃòÖu¢ðÑCkNŠÛü>À'½¥Ü–¢%«c=|n¶¹ÂA<¦}ZŒÒ-a÷ËÉplØ:œþƒ'isƨ¿âÂÌTšÝc4'žYAmF·aòB+`6¬oàá)psƒ2ËŸPÿ&{Íu�à¢Ã|¨R�Vdhð„¤‡¹ŠAxeìi|“ Ç³µ.˜S¶ƒÍä<4‚/܈‡ »Ó4£¦.”†Š¦§Aºy¨tÊž¾ÝË»B^RçhwT¸³˜�÷N•.¸k&<±mÁ=>§ ÖÞ•ŽkÀUiÒæÝ œyöp•\a8Þ¼â€óp»ñER©l„�öð÷äI5óðü§é«òíx3»ŠÆÄà¡ó®Â¹~´æôÚš?ýÆó÷¡š±-œ¬¨¢_Ë{sÅ0;ü‘b$Œvy –û*à„ø…JáMx¸>Ÿ|“Ç•ûÞð‡¿DhÅv£>€â¦ó‚Ï ž;¿�o¬´fÿ¦vj Û†Óv?º}”ÞgEK¦>èÁ´ÇŠÚ¾ŸÁa.{:UÑ¢YûE·[ÇÅ5¡Pg£ÎrÉ.…tǎϱ<ôÓ>°S7GífRZU&$ðÝ“ü,a0ªf­ž%„ëÞãÄCÎË ¹We |Sú×;es¸:܉¶O_ƒ53†@Ät|5NUrÝåðéþ`°£Œ¤�©éÖrH+5ʼn½ºÕ*� %ƒ�oBw�‡ðŸÓZ˜_K†ç2àGúyJ2ëÎò:|fÊI*{Á5}Ëa�D�oÏ_ÀÎϤp®¤;/\Žü9J•�­çŸÄuû”-Ç ×Ù(ˆ~×JWß%�ÚWÒX¢Š;óNrÊ3v;ÚèÐÛËŠ¼ghâÇ5ެµDÒzÊžWΊ¥›[!µûF´úû„zŒ^…_¦/å_ÛËQѯ½[*xÆ]WñÇ§Åødj nÿ}ƒÇdÙªU�áÍÆÔyâ‡-4eß“‡pÇŠ4ê_«Á{×ìÁX,àÃJÞÜcw9Œ{i̯™ÓéCV¬Q'Ë7`Ì;nÃ*ÙZl}p2çú1/Þ¼6-0à Ù££ÆñgÂâÍ¡”¬ÕA›þË… ÏDÍwÅ«% ¢UÄÙoH<7˜”UìySÀriU�-ÇZép‹ŽªãŸ O0d@8|É‘«�9\‡wÆcB×Q~Øã‚Ð÷x�ø__VÚ.kî�æéÎøR}™Ð§í!ê7ݛݿ$ÎPÖ?GªV¢÷…åØ9¦,Zóðñk^¾Ó‹³4£Åõ$’yR/ _ݦ­¾•ƒ¢i£c?Œ¿qû ¾9!¿LÊÍMYtÊÑ–«'�ðÏ£ÿÌÈfÍ‘ÂI£´÷²�y05dxxÍ~˜iùXÐVÀùw·ó*�9dt¯ŒûAÞåo±×ú0®¯°äÕ‹€…Zœoo�‡,ÙçIŠðnS’p£c$ù?‚˜1� ;?‘æ>”3´ã¶ É(i?8”d½NVÙ´Œ£²ÅgÁvü8µŽ„ûj|½ø>Í\t�ÏÌŽ Ô0Uwæ;òÄ¥[ðÔ´…¸]ÆRN`OûA Î WGñVó˜1Ù mü·°ùñåX~e'›ìÖ§ÀÉ °Þç">,1E» ÃHû°=¦ÝÌ+�ïJõnàþwrqùÖ!X|ï.-Šñ�vEu„'ûì!£eÙœö·€k<¢åÛ=Xåæ'{ˆIzºJè}æœF›õ ÑáG9Év6RÈeM~ Â}sDî#õ¦Á†Qõˆ�’Ï’øûå(Ì;<oºÍO“ÖAôÝ:ü|V‚u�¸lAö\ü�‚#ÅØiïø yà ጪ‘še©Š÷Uÿƒ_žf|iOÌ˘Î�ý3¸!=Šk&Øâ#m)Hý$wþÔÓ—½I˜ÚßTæ¾¥Ÿ�‹ðzëÚ4\Ê©¿\¹¼C;ÃÇá�!Ðæ Æõì$;�·â®Š$¼Úk.Ùh§ç¢;ž(NĈ€?\Ôº-õÛ)wäØ*9Œ� êÆ‡€—Ú.ŒÏ뎢ÁCañ³)c*bÊ©öþÅ�†‚ò 7jng¾ Á+=…ŸžÛë äú×KT:çðä+ûèur).ݶGe,å1c¬xÅ(9JöÖ@•¡¶¸ñP �ØiJä¡íKN—ÊcÛcŽþWð\EWF`YÍJÖŠÕåGÏ¿à®_Gjîhîfü�ÏSµ9!Úˆ·Çâxï70åÝäù? ²HÔÔò€.G9G—ùj�c§â¨2u 8) A¥d\´H×9ušï©ÀkPmÆú©´Ùo$öW‰àÛû7áü%ê<7k^ØÁk»åÑÔÓçá}‚#¥–ìgRÎf›AW±0·ˆÿ ŽáµËF`²“;_ˆã¥ï6ãã›jd3—wõǾcÕÑ1+ ¤kãy¬Uê7«ñûÌûðÈo$Ö'Ã�Ý…4ÉÜ�¬ufàõ5�ð¢K—•†«a/ÕéÔÿ®Á�ÆçÕƒæŒe›ºTꞬ²9=xÍþ+Ø–’(æœ#÷.+þ®Ð%ŒùùZZX�÷&e›lÜÒ˜M ¼_àçó°Ù)L<£+ú\ì^ì{Ïîeè߃ß„5¯÷Rƒñ É ¿—¯ÿKÒ«A .¼<Ë×OW§ýt^÷i‡“ú-^ëÏáfxG1 2<àrcCÜñ-ŒgŒË=¢ÑCÿ6Rk&ÆÍ^�—Å;x̺…d4åõÌ,q´O¬ušLçèÂ…´P°ÐÜ…OŒÂ!×óî¿ÿ…NÕέ ƒ·¶.�¨äàé;ÇpáH%œ’¦ï³Ù åzª< ŸýÂéõ¿Ü,—�—†\Õ‚›Ðlp‹üËF±»ÁwøS\Aü³�ó&(óú<Ç\ÿT˜8ù{=žK&æ®Ðýš-Ǫ¡Š‹�4-ÿ±¤2)+¶ÓÕýÂiG{~q£k3&…áWX¨3ÛÏ Aq‹öz4âØxúvF‡¾?Îì'ðU�áÒ‡¡lµ‘áˆS FwÄaëªn³8mÝ xÊÔSðŸgo‡¾~¨pi0Oÿ^/tí¹Ï×�§±�sŽÜq�¢ÿJ%–^ ¸~ÖwþQ‹«šä°¥D¶ös@ªø£ßcúºzgeÆP¥â$Ž–-–ŸÚ0AZ¶•ƒeómP×�…Ñ1Z¬4÷4ûåjq?_Cž4Ö gš¾¡ýM\éOwNÇ@ßO:8áUN…6®Ãð~ļÜí(5<˜AEÃjéÛýE�ßÌ;^…µÙ©¨1œ}0Ý�N‹F‰³°¦W6�Þ×Â{„Cxôm5=Ȭ¡Ê‘ØXNáa=éöÙI8ãq¾Xš(¬uó„ôÿQt~=_ohj!¥¤¤$4QIïs2ªo%+%I$IBHF ¥’Ñ ¥¥”™R‰>ïs ¡�QFY!!;›ŒŸßpï}œ×ëõ|=îã>îô\<2ãåñ¸MÉ´¼ö¥Å`ù�R6]ó ê¦+ñ÷¼B�\I=#Á .QhKYÂ[4sœ]óˆ:šªM«ß„cïåŒC”hÿ+Qöïiˆž¨‚ÓÜQ2Œ“ÕUkæYØ1¡�´ÛcÀÇ`Û�«£Ã¶iΊDx{ò*fÜÄ~¥ÊâéA¼²[-?>�ïu5´íM0.í«Å·~aï´ (>a@Ñ{+èÆ�ÈЊdݾ¿ª;V%€ô)iÌHqâI}糨¦Ž ÇôǃG‚ÇïtpTŒ……vŸ=$�jJ>®Á—EÃyÁš"4Ö7Ã>‹Œ¨vÏ l¼qH8w“„+ý±ÖÖ“œ�ÚªWÒñSƒùQÃ4¼¹k­ðãÒV4º¡H¢³)Ç?ÕåX…Þ4Ç9™û¿ðå‘Ý&ÂýÜi(ó°Úáò½hQS©7xhªc¥ÄÈ1b?á—v 2µqà)Ú“iÝèE�ÍóøýƒYhót%L/ÐÇÅïè•Ê+ᵕ».?M-Ãåàeç}úx9Dp]<µ,~£ú¾s˜ö¤€'O=3T>AæËB‡1]x=É�fÜX·ÌFñÊ ËAµx,¾êˆ)ûÃÑ¢Ðqh-Ÿî½Ÿ®ÊºBåÆï4/ñ*uþ›}ïQš°=÷;¼�Ù‹r阶Û\Ô?í€o¾]¤´»�èÝO‡Ï(Žf÷°½-^Z|¡lá7©d/¢ééQü»yö6;Ž2–õ¤ýb<_pDpw1a£@|»eÚðïöا֘­^$²µï}RtºƒG¼ï‚ÔÊ2Ì©£s¯.Ãàî<Ä-wûÜF©cc%;§®ÀªÔ£8Þ±‚KÇ÷G�ž#i°äÔ/;M¡e¼üt">¤€.ç�Iwì鯩ð‰&§Lë@Õ•Êìè3ž´"w±G™—ZYò³Š*ê.x†»¶Â°G´ù\Ì ñÓ/‡µx:¨´F¨o{ Îù·áŽÛ#¡Åý éŽ�"Ù'{“»ófsž�2 װ娎^w¸VåѰÂ=´4ò;Û­AÕgc¹×UHqŠ�¶Y«!p¢R²ÏºÄì�¯^OàëÎkÔ¯Mo%½†Ù/3@¥¥'¼ÖM5½�Ãã¿2¾æ¯?gÌë7\ ½mã¹æ¤7^ÐíOka–™À›f'²ó·~¼õÇ Ìþ”Êg>eãöVÀ�M0¸y µ$¼…ü UôõçÚry§˜T@‹íè{ÙQžŠÞs[ÈÍZ¹cAåGˆ–¨³ôÓbÇâ|0*FÞ`$瘱‚¥N°¿D†Bß<‘@'ýÀ°%!ôÑПû¯ºLÖ³97m¥«¶ Õ ܼ¸'kf ä­[À°N¶›ÉÀ–QÛàÊ 5vT_Í�Ÿœ�Ìäm8iµ1D�å’b8árÎ~vÛ¹`ÈÛ�X|¸?/t‘Âo£6‹Üÿ º&�f[L?‡ªƒWÈ1Úž+-ÈÌn£ùŠpž_Zäí ¯ 6ì0/�2‡ŸÂ¹ÕŸ„VÇd»ñŒî”c(¿Gúß²q’½›L©™WyXº3XL/žÄ½×¬ä¥¨Ç^I°ùà ~Ð9×\nu˜øÒ»ºrèCúlÞuw>¾É3-×д}Ǹ³É{IÝ$Ÿ =pÏÉà4} žØ '‚Û6t,@é @{÷LPý½Œö?qä=u?¡»UUC£y©Ùzab±Ë5Åñÿå Ó* Jg¾kÞDoFñ÷ÇIt¿þè-=ÅV5]ô:²/Î�£Í¿ÿ¡çƃ‰rOÁÝ’ ØsŸT™ †u+œiŒõYzò±/(í[�[J\ywÜU0»ï@*yeÐ�5 ²¿ž e™†P“êæ0äÉ>ü22” ðIô&ôÔ(£o¢Yï¿ 1h^'†ˆ]Y»øÛûOÐë¶%:YµÐ°£ýàµ�­p \ eO(¡�«!dìÍİž,�h(¹pÚ†¯ØÃÔ×¹øãý �Æa±lW§Î¾ÑÀù¡ë01¶§}­€K±û†k-C«gVüÀ÷ Y«û8—�Í�µÂý„ð_øK2ß‹_ĹQz€!L ;Ès�ÅÊ Œ§ýùd¾JL ³õXø&‘ÂZ`\Û`ñÑ™&®–²d·È1¬âþše³`ÞiôÓSÆQ†ÍŒÏ£9Õ³?†\Lâ)OœàenÓ¤+.«±µÛŽëÅÒ"ÏV¨Ùk„¦S>Òå’§äj.þ:¨@Ûæôåý[Ðæ¼6GÁ…%7h™™®È9ŠÛíGÿ·§‚2l¹êÃD îÜ�º›Ô'ïÂû!FÜhˆ®…£`~k7Y|´åc_Q¹K-½1� ÇÊé[¹êø7(˜gF{²ŒàìúFI‚Ô^¶ ª£ÛÇ/Š]'—ÑóêkU‰g~ŸÁ[(Õ|/)U[b·®.zÝua§¾ÏÅði:ØïÏ^—d�/>”Cåækâžu&ÿèâg—î ò,'Zí9úª=¦’¨Úµm› ˜t e½v4mãŠ/u”»U  »§§Æô}<�ÔîÅâXóDœ´ƒïϸYHÍõû(sÐ\:UÁ[yÍÂq|@J/�ã®êl:ÝÛƒ×ÜœÁ/Æå[óóHwû=8]š&Þ›Â6¡ñ8í¯ißkek¥›¢ôÀ0œ—Ø)¸?Â=œ£‹éA¬ÿä¬>¤?sp²ëÇ-})G¶ü'Úa›l8�Ú*ÃÇâ6¡|÷ ¹LÀTÏ5+=R²çI´ï³œ—ž†Ý�… ±Ün[$œ:cŒß7j îê%4pÏLÿ£‡"ìY*¦Pq!€‡¾ŠÁ)ÙŠè:a°Ð¿)çfÉrRú–9> …AÕb÷Êí4v›/¾[–$±;ö÷ôW”Úb‚™Ü9M:}ï;ˆÖ“ÚÈòZ&™f,qÎxü¡*øl™Œ¼iN�Ì1𢎜j¾�Òó¥èoþ`ä{Úx5›Â†nÂé ¿ÁÊÛ�Ô Óq/„€=�i\�ý¬<ÿ´¨ßèÄ­Z¾˜ï�ÞÓÅÿ{c¦ê:ÞÿZ‘¥úÈÁ’wŠø¾)Œâ&£¬ñ4Š·àªW‡è™…1:Ù´<è$$Ì|/Ý_I^×ê˜Ý0r•=Êʇc£c-ä¶N…¡ÇòñBà ˜3}7V» âÉ²ÇøÍ§ŸBjœ2¶Åß»¦÷æ†Å]0µÖ…�ŽIâc_Ò1rß}ô±Nglà±çH*Æ™M¾Ø³È’õMõpóŠ9ÂîÉè°8–¾ÊWœuýj°ÐPŽGíuaýn|°ËŒ?Ï;HµuÏ`ÑŸ¯cD~ß‚@>¤[à¢Ìaìµç¯ð«ÜÉ¡*þ6ýV�ÅÕ³ªà±”þêJù5æØ¿Á…Ú}ÃØýU(¾}³/,à Èz}B©I;‘UÇ�¦Ï•g÷@1TS{¹)�‰ÕsRŒ]†õ%¥‚EÐSè/1ç!¹wÈúŸw_ýhïVÑíćtÄ_ƒÇG¿ÓC†‹Í/u$#“å0Þõ ·¸»f«PX:¿÷ˆ‡Æ{ɦå<¸‹V¾p¦IÇ+Al~„·tÐçÖ{\!Ÿð-$›†[mxTeþ˜ˆ³í%Ó”<¸e÷zl†±o†@…g,ë¹ö¡žóñà›5¢©Sñ˜£ ºu7G|§Sæì’IæÛ¸ìëL1êÚnªú]F&÷+¹s‘=rÓX‡Ò‘%ü{)p¯z#)Ú £^DýÉ_[9‘{JNü¢JÑïG «jÃé¯À1²üߦnšVÈÿE â’!ñ?˵8Y¾–оß#�©³Ñx‡:kÉì„ùr»Qã¹>}¾¶•ÄæÖSpéPŽËžˆ óËðî$L|•Eã¯LG�tÃ1~:å8ë„!œùs‹�]Wc°A±°¥ôÏŒð€º›ÆÜëÝ{Ar¨œ,O›KáFIk�ÿÉ2‡A{íz´Æz¡ð ®]¯ƒ°šd=8œ^—�öµMÜÛæ…CáÖ|°öI…ËÆ‹1Â׋�ãðð¢GÂ� ¿âÈ‹åÂ=+%<çä�IʲQá‰�?&»oÝ’AfpÐ�6DXaÔ›÷´&â‹©Ò8cþ)1SIGXä7+^ÚSL_^e™Í „è#gYÖõ8íÛdEÚîK1:¢I¼”s<~Æa©Ô6^¸p-¸Ý é» ÍÜ}o²’°Ì{»s/\6hƒ8dØ'ðú–ƒéßgC¦ƒ„'jªAß u!ôjÐÄöüôbJ2§È\¦¬ Çxç©P* 6@c©VدÊ`q•àÑ÷&ú]^ˆ¡SöÀ”ûˆw"«p™™<Æ-n ÊË7é†Iú×CµØ½¸ýÝG‡¾/º°yÛj6+Jÿë <¤V½Ü´yG¸I H`ß½[Äûex{ÙUަ^_ Še‰Ú´qg‡&ú—&�ñêOâ΋½`Üœ%ì5°§ã‰A_iPVï 4ú;ƒAmmŽØ{˜…™Å »â3å,så¾ ^|Ï÷½ÄìùFQ³Í�úNÌ ¨:cÉ «‡¹7sF^0îýÒNs›ŒìGzÑš¡Göˆ”§ø�ÆÿLWõ¥ÐcóZ›ˆ«î²õÖÇ}~¨4ƒ±ókè°·E�—=ØÇÌ�c¬¡]o æVÑÅÅiÌ€c4¢²ŒCç`Õúdþò§@Ü¥�…^~<ÑhŽðâ´�ª)ÊéºÉ·9²ã§„Á1o(þo?ª¨ÐbM£: 3 z“ï… ”Žr⺉Ê0ñ×løUͧhç¿~âGÅé|pï zïDÁ›inà‹×3ÈÿŸ¶¼æÄ¡–ø�¢gõ&Ó6pU ‘/ÎâC'f�[×oJÿp�Oã³·Fb”žIŠvÁ¶€Ã”«yµZóà]H8¶ÇÒÏO•bQo-¡T£„. ú,,x †æú*ìd°ã+cé K¾®«DÇÿ*r^ê × !,»_à¤^gÈw`:ÜË~'ú,ÖÀËã‡bÞÂUüé?%þôÊF޹ Æú}ùSšž�vàe&±°ò›9Ý).†–â:qcûMŠ}2á¯ùÄÊ�86 &þp†Ñ ž\.>¥ùÇäpÏâA¶õZvÌ z�ÁÝF…oškóhElù\#ÎT]�‘I…ôËî2 —áñJéÎw7>öx4œ›æÁÍ‚9}�Pcånüê„>.=¾N\}ÕúÄü…#á�8P_ÈðtùOèª�EuIªèm°aY¼ÛjîøI¾Žöaé{£±ÀÞ�.{ÎÀ_ñ¸=W ¿Ÿ•&_›Á¸t}*…>g¯X &ØSñ—ÂíWd12€hrÎg=ΩxÆû —°éå½Bèø|av–=øîÂë”\1ê„î6/F�Uº\äö�FVõ›§àhé�j×Ò¥‚Í++Ê2~ËûÇ=…¶ iì"­…³-¿Ð¹º…t`€‡Ã˶¨U6šŽ¹úóànñ¢µż�„/Š·©Ûl7Ê­3féàz ½$Z”NèE²²=ñØÃ[tÛu!t…ÅÃójt}V,'u;Qɾ}hÔqçÑNÖúñŠî-¡œ5A(?†¡cÛG /òÅI_ýxÿ€V¼èœ gt˜Óú ySò… ó–q�ŠZX­´ƒoZÀ–äóëí8%¶^xþ€ì?É[? =^@öSÔѺʟ'Û‹Ÿš�X±Óæ_p†yZ`ê•DpþÇ·bÙX^y/Ž”ŠBß¡ÿôÖ=—jÊá÷âzxu{œ9xw^{CNO£e/aè(ÏyÁÅgÖ¼ïø‘»|þÿµÏ|,—Mƒ -(×+…Zí,x`6›¶Ïäp%¬ˆ, ç²Ì|:É W�üKíw.ðÚ~å4צºmlDÛÅS9ðã\¡–',ù=š?¼:Œ#Ü£�¿ˆ«Õr˜×`ÎT–†W; AFkÊ/ʇG—ö�¢Œ¡¨:ë¹Dœƒ§g…m‹9,ùôYwUØ­ñ.Fž£øà˳e!7›êÇ/¤;ç�øÄ‹¶’§T1„We­È…<ïõ&¬ ™ŠõªØm¶MtꌧɰðÈgh[^‡Æ*À³y¾xOáºØÒy•fZk9œÞ�rbo]&Çy›*)¶£šVTÄqx¨=/[+ØCGoH±oÿv° úÓ#辕*§ Dg»|Ü¿a ÿ×[Øža…Xn€Á”!Ù0q476fð»ë3aY=ׯÌ~“Ùaë[Ò›m@{~™pg}t“™‹WœîѸ«‡@?Evõ,SZhŒ¾;Jë¤Ó¼Í͔Х€§ÓOò¢¯ïÉãÂ^º+J“•áuºü;’‡†}§©òæp˜¹ò*']›K¡U%ÔõᆃwÞŸ$ª…•S\ÀîS.(8Ïçèyy´D¶ ª»¢ñùý0Ìøk&ŒÆU³RÑÅ· vjÙá�úã=ýÜЦÿlÐ|–*×z îß~ i“ÆÒ¼ÚF*+ºH+žBâÜaدµ/=Ã8ewµ…hxH<2Wòã‚.L¾Ü 6QõÐ9œìúl�¢î[âÁUxÕ\ƒ>LAú-,d禧 ±b•`³$šÓl,øéì›ðÞz)¯Ý(ÇòeÒ°nw\Ö“Ox|[¾ ú�ù㶈‰«Æ�ò•>ünÀf¦?�¿¨]aÿº<Üü¯O½û™I_>ü÷õýqËREQwm*W�e•m6Õ<.Z¥ ‘+9$/Û"²Pf¥D\£1>”½x J †r0½§�geÐùÔL.iˆ›§»Ä^:C¡eÝÈ 9Gï§OƒŸÛ•yîYáùÉk46e3\<ÅäVýyIŒü5úÅÉg {ð‚cƒQóZ_˜:² t•. Mßá˜8 ]é)Ìxh‰½��ø7¿r’!9ÜZ;�ÊüÒ#%5¼§u „Ë‘Ëhy|Ó>‹ÛOˆšzª(qû-\pÑEÿ¡�,}Þƒ—'ñöu\c/ clÖL{K-I‘,èçq�R žx[/ÞJiŬœ lsO rK+ñǪí4X³z'@Á‡Þ÷Êᬳš4÷ã4 sëÃ7Z~ZÏ*z’ÆKCÜg‘. m'kµ% ‡–F YG¦ß¢?'õpen©xd ñ÷åwþÖ}½µ& IÙïÁmÿmaQé)Xm¹›ú¨£¦Q,žŽÑçófr¸MO‰}IH«PÌê/P|,Ü»Ú_œxÖTÕoÒóY…}í—®-¤|6žÎÔ~†{}°þe <Ê-¢†=>8ò¼,äwAÆD=¶¸^.jÚÃŒ;Ãáìà*Îý´ÕÂ×Ê5!›!}z95†*²çÝbò”f’;ž§U á †¼íéOp‰ßHÆ3YþÊ.¸-Ç37{òÓ-QPú;.ü°DóÇ4ðê�ß\mпo<-™ñ<ÿ±déÄh{>�·õ1¡x—ðVÙE¶î'„?×ô8Í[wôĪ~ <бU0h\Ž¿ïµ+æZBLò=qEø6l Uõ¿5¬©½ƒ²t—A�ÚüQ=òŸW4@ï�›`úɽâ|Õ»báÆ±üuŠîÚ«ÈKí3Èy·% o?“ñm ޵>Í;Aþ×wQZË‘�¥¢Ùõà0Ø`‰0|@­|›C�ÿ26òßùé~Ð瘼\^¢þ‘\îõÃgšm$õ�á³¾Èߎ€òj}‡O~éÁ{^²³YÌÎÁ+�Ú…{�`hâŠß¯GFOvà¹ð×8²ôÜê6­‰X�KI­Ð{d.Ç�ê$én)Lí÷�¾ñ�üÝ3‡©ãŸÞ{ BÁ :­§Õó¾QnÏ]`ê©Ã}Za� €×}À¤{Ö\¹E#¤dYn­s�ñbBúSʺ¸ã îÂá™ 4óáZòŸŠÄ¬ wA¡0Þ½iëÂBuY´ê¼ <Ùè„›7oÅ nË8Ïr6 úÉb䌱ïBê©3 ¶]Í„êšP1 ЛÏÖK n¡ç³Wñ iRÊ?É�…"(ƒm…9ý­ª>2ŒpuÃS½Ú¡±i/ÊL3‹ö°M¤.ÿÚ‡­dB”_¢(k;Õ9#z-6uÝ…þ½Ž¢Ókopj¼ʸ’wN`�—sp§n87ýÓÖÅ›Çà­É!rz35KÔpý b.ÕŸ‚ÙKèØ0iV<‡øèDwôG…_ޱ�â`_)¼p¡|½‚p^«¯©›Ë–?sàfn”¸çûø%ª¢ª£¯ÙìÅ=i nˆ~ÒOà™û\ôÛK0ûúr¸W˜M³þÖÐüäŒ1*¿ÔØÖi,…Z?'¯{ê|ÿY?ë�Ê¡±°íµŒÄNã¥ød·›DoL®øhöžÀ¥ä¸ä5Žsã‡-chöµxX#-�•ï�Éýõ‡A[Ï�I‘)¿mö{‡Êó§¡ýÀoT8_h·æw‰õº@ÌíÁ>F‘¸uHÔk’ÿ‰3tÿ‚&6›EÒÆ£}yÃÐј³ç-¹C ©LsBÕû~g*J��¹Y#P·æ9ó‡,û¼—ðé�>•’ãÃþ¨8 æÿ1Bým¸K�ÍX:aîÜ1ŒûìêÅþ¨‹¼Ï“Z‚ìiò^Uoîáú«‘Ø¥´P %[úUðþ°óä§‹kNÛ¡ûcsª‘ÎáO¤€‹l(™ÛA(–ç¤`vi"g´áýÛ ¸g¶øÜx4×�ýåð-¯P8¶ã“(ÛÓN­/%µ%Ùœ°”âÞÇй~6ÔlL§Ö–`þÕWâ/¿O¸¤à¹hÁ_ñ�©Ÿ8hc혆¦à³8–þ¨§ÿÆxñŽWš|îO)„¶&cWÉr£§AaŸŸ 7š†OÝ�[‡ 7Sî“]8êö)±oø3jSKµŽ|êÉ6ëŒxâÔá¢Uì_˜°ôÑÕ¾øõýœ¦°PXò®�Ò+bE­šþjìïàºï JžÄÕ>ýùR\íh4À3†ú(¬žÅk^¿GkwiÎöσ#Q–è“Îttïxx¸x4ž8ACGvÀ±Á]BÈ KQ{éa~Do~f¶…NÈ  Ö�'Ë;ú/…Æ­ýp³“).™ÎBê¨ý4:Zå¶lc�§‘yê¨è4ªRTV¿óC=é—Â'R|Jòm† kj�Ä59½ÉÓo-RH£z­£?*�¢Õp~ñUêÚyDøüŸ2¦˜$ÄëIs´ûpXí…³ªïÑ»+²ü:õ²Ð:Õ^ïéà³5™¬÷ßlHøâ#ô´Ú VÎð¾µÎoÊeƒVóÜÖSbEš)ê‡Nàw«6ãÆy¯éU¸v)Xñ¨‰xÁß’WŸI 'ÓÙ,×sN(éI.*òyÛ§4Îwš:ýì]�¶§÷:,>Žó¥´)æ½._0h—\üOw“ìEáp*ïŸ÷ öUóš›ÿñ×0]λe†Â05^çÿ„fžØM®Ä:P)È¥„ýmÌ!'૎*J—Ã�ú0¯^-Nñ˜Â76¹ó’qS)v�Æ*àiµÛ¢Uˆ sÑôäæÞþ"ÏÆÉ”`Ú÷§BtxüÏO÷ôÙϾ¹ŸÅã°àP\ª!ÃÏ RyÂb€s~-vø½w:k�ªñrø}Øün´ ×�÷DɲQøBsË}°æÊŽ ¨s6‡+2­ì_§ƒ…{ŽÀµk‹`ÝÅ—Prï¤8Ò¾“ôÃÄÀy)Ó;‚ËET³rÏ0‚Eg,“–Ç”E..\Á�}òç©CIní ê{ê”hÆ`ú)Šq.Ã;ùGrzØVÂÁ¬¾è}>ŽÏ™Ô‰×«�mÞ ˜ðUŸý‡_¡Ôס¨1I�§xäpáY áfÄiîzîdd|Ê€?Rµ˜Wn+™¯›Æ}~ @]ÚÔe…az|Êdöª çÑò�‘Üe°˜¸ÀÝ z|WæD×nÁËu�dÊ›¹Ê¸^ûás…dÁsÕ]™ãüí­È<½,f߸!ï4o–¿Ets©Ðb¹–§¯8ÃóOÏ”ô.Z�;è ™æ¬¢GCFáÀ^2ì¨þ =ì 3tÓã’ÊÍ$?i.ï’��ÕrxÎK}^0ã$–öØ‚gVvÃF™ª< ›&ÌÅ2KsVÉ4æã»,Qaw/H] ½– GwÕ›ÐþD E‚ 25^ö;‘>¿-l ¶g¿�áXÞ¿÷;©ŽÒîÛð¤ÊI’×n¦À·ËÈTÓ–ú-xOôÆ‚”Ê xV€Áµ-“›sKS,+´;s‹¿Î7 Å5×—áï‘Öp\#[ôóñÙS)ˆq:Ì× †bDoŒ¥€Áó¤ùíÇ$¾¶pl([�Ê“_Q’|ÇŒL¥íÂY2÷�xŒ¡m_-|ÔŸ‰%^ÛÑýæ²ñVãjœð®S?ì�»×Ñ—€ ÂÔû±ÿ«PñÖˆÅØ¦uâ‹Aúu<�F6à¦;sP'0‚2|ká峃übdßhÅK:£9õçv¾Öš'/¶‚ÏPgvzu†ì‡Ó‹ráäNSžú« "òL(õý3xßó;ÇãÈuU€còø˜S’`ûD³ž<§æãr¨X ÂïA“÷Ý¡=‹ª 2Æ ¾+q�ÇVˆØsjç·;TnÒf-™g\v¯›ýƒKû�õéY8B9S¼­EÓr¶qšÞš4—žE¤Ú´µì!Áj—_$랎Û"ÃàÕàIâ–è:úÓ ‡£¶  ÞœÚc –.KîÑzüݯFXìÓ(þ÷˟ɱÊÇD~è=*g´ �³ŠàúÈEâ©¡ÝÔ4pkk»ƒÚÜ´óì:ó΄þ ½#JIîœi»ã… gŸ…gí+„nûDÚq)ÔbÏP¼ÅSø~\ ]zܧuºc6bHièànÇhpŽ`P4ÙŒ3–ÀÃq3ñÙÞ‘Â+½&±R­”ÿ<û—¯9wi£[,×ï.£›¿*øW@0æú7“,”CËÉx ÇþJè¨÷XÜÞ¼[|–fÄáS*Ä÷Z�é”ÕfÞasþ>«€?¯ 劽ùÀüvx¤á'¬yv îjøñÛâ&Ѱô,¥K2踥žWlcYê÷S¼’´Á Ý›3ŸÒ†�%3y¶ÿ0œxÉ_8|ý�pþÒ@vÞçÉŠû!óf¨ÎßÀ››G£IØ1?º‚ /-�®A�”É4²ä8÷ìžÊJÊ»Ä?EÜ==‹“‡ò¡Ü‹´e݉8«Xì±Ùé�:/�‰ä³ãÊÈ*¸†—¦ÙrÔ—p8 lúIplª-¶?²Á[;¼ñ^ü ~º7Šã§Êò¡/M$5Þ�Ü ¶MªüʽÂ7¨°ËEü¥7�MÖ™£\A•ž[‡p¾b Íñé€~Iz-­:SYG9–…¿‡TùE˜¼a4.¿Â! Á˜yDv_,Â/ËãùÅ©2ñxv7¼ÜGðn÷!Lü]$lp|.\¬Mé7“á™Tøf¸òW[ÔVÔå-½ÞaAúTî]ÑFâßvõQ =Ü-Iø«ß-6Q²Ã0vì?ŽB‚.rýз¤�ýžJ–¾î¿DuÊqïa‡ÎA›à÷ ``õœc ŽO/záþ…? 2g*�Ž|ÉãUxvâQ쯷 ‡ëi°á¹>ÿð\;°œW¶)ãé¸Ñxwç>Ì“6‚dõóBq¤*\èÓi?ù…6ôt>ÆÛ�Óœ¢>¸ú`4�Û­ËRZ2Xâ<‡_~™‰ÃÊcñ] 6ëí{DN÷ÿÂts_}à û#QÂÐGŠd¥úVÒõÌÌ̸>ŽZ«à‰Ÿón… (´¬€ye‰,褢¹Ô~áãí¼ö¦?&IBÙ}m-4ìtÆ« Wßµ^Ǧjò°àê6z¤©—£š`åõ7´2m4¶~«’|[Š{\1æ¡/nOLÀ’%m¢³¢)_Þ!�S¬·J>Ù�†ò’‹07¢ÀA#£ Ôûˆ´ËÙ'�<Ìч_P…ÿAvŠ;ž©¹ÎÍNËxý’�¸Êw"Y†÷•¢îÁ¦÷rØ©·’É£9�r êà�O>4Z9R¬DŸ7¬è 9ûh³m?º§‹Ã—Æáº—G`êÝ-Bê•íPÜ»l_N…¶M¹|‰)¦“££nœâÌprz™†“åk$£ÎèñÅ *Üh{uÐ[þ`”Žr“]Øÿúbèç,¾>4ƒ¦ø¡÷ETé¾*Z¯Ï&—SSñü�ǰ½& eÇÝ£@¯%S±š-pû�é8ü-ÄMJÂMé!ܳ5… K îÍ1ªß~n¥çÇÖR�c#ùM¼I K…&ÿ^bÝîNê™V[6i·Ã¼ö�9 Ê]�¯†´Ã�Šøzë (QóÓÔðÅÏ3¤P0Q¼my€Þœ¬€„»×p[¢œÕÒh°r,&‡Ó†¬Gé»5X¬�MÉá'hÿÚ8L±˜ÄY¸ô4Sx”×ròx ¦Ì‘u±…³wÓèix/vª‚FûHJ÷Ãà½YÜÝñŒl—å]É'`[|«pb¶"{„á—ý,¬yÐÅ6olXÉTãF^ƒ¹#^ Ÿ–xsÅ‚\AÚ°gMR£ÅãŠAEú�xþW‰ðçv  Ê–ÈË…áÁÔ+wªøÜ\]»aTp;m¾\OùU²¼àïx ÿmÊoþ³CÓ�“ÈU’MõU�7Ü §-�¡ ú ÕÜû¦aÊš][Ñûå ø£ÉÏç¼„Š Î¶ÕdÞžx}ƒ"ß.\Eë®TSÖ7j‘n§ÁõSpô5=všTB­Gë„6-|=וìú#¨•‡À†ª¼Ûx':Ÿ^�/g*ã*{Ëœ¾ƒ^«O�Óÿí‡'*>è½EøTy&tHã]¿@ Z4 6�2çi—Š!0y¦°Þ³Dø;`&&Õ�÷Å<ÛøAÔŸ°�+:ê–íÀ¯Mz¼«œ(\ï¥�ÒöOw du“tŒæ=h¿ Ž/îC›,9ßý�¸*<†¦h©V×Zg`â£8^ZÂüHî‘à9ºŽÜê{ Ù¹µle™Ïiþù¢¶ýhÚ”Ö«}:Hyï' ½» æHc\º'O ¥hÿë`Å“hz×d<÷s(zþwC�’1¤—ŸÆ@ÑX pÑåë'¶ó‡uéàu²V¾|Mõ•?àÐÃ1¸ôÕ`ŒWÞ žwMkÖ7«€[Û ¸“:Ÿ—ßÉ�`ÑçÙÜÑ^G¾�ð¿F&¾s\'”lÕCç`wqÐÒ Ü¡kŒòFßíOŸ¢v½xÒŸ¯Œcä‹Ú]›iN¤„ïºm£"X·8]¿®¿û† :cM±ÝÎ�¤l?šÈ3$;ö3HRÕ1;!‘ÙÍšñ?a‘ÇøQ ~º; §�x/´æ¸òLZ9<„o~\ŠâÝÝ$³l)ߚ뇎Gê„—òxq¦¥G¸Ò`çyÐÐ"Žh< ®]T.|ø,Å“+²iûû—BÛ¨M¢FÇtèÓšÅ/á¤û²Þùž&é8¡¤DEbö<�ŸŒçü˜|ø —ÚÇT7¤+³×*Å1Ê !$Éç˜'󖍨«ç$!êw;íXóî9ÒÏ¥�¯Z Øo>ðCÿS[¡%r'žûŒ3� å[I0mÁ$¼~‘R·sA½ 7[…'ÛïAÌMY‹´¥%ù_•È9d_³ðî°ÉXÌøOóˆ‚Ö2 x½òZ¾ÀøX>#—ƒý‹¿�óâ=8XC™3%ŸèEø)‡Ý§>Ãô‚2WùåZS û€8ÌZH+¾�àŒ‰b£[-´ÎwÓ¶áW‡ž˜q0¿Cæ}Z){Ž;åiÉ€ûæ9hn³Qô¶õdÉ/uÞqt?÷WâáÆï,é£{ó)¥F!9i×ßÜ ‘qK¡59 Ú‹�ƒú8{ތ⮃¾WÿiWë|{߃vlà}Ž+Ñ¢vïý4‰ïe�/|Ì£›$aŒœ±îm<3•R#’Àû ª¸ûo­ˆŠãËóädˆ“|!SWÔîcÁµË2ásóá{ö:�m­»Ú­t6ÏnöEÉÝ.Ⱦ[C“ÔëÄ�OÃ0¥Á\¶j ù­ì‰:6VX=•<¢ÃÅè—ý1Ü9–LÖ¦A‘«2¶4ÊB�ÆU¸¦éËcMtøvÅ}¥^ñð qS’"”È©ÀاJxôP¦½©Å3îÓÝG<)|…¿e^0o¹·°pô~³Âƒ®ÍØ‚~ëÀ³ïp|¶Æ‰8ó*W�2õnk¢ðxJ§ŽGµ§k!Çd,˜†Áëÿÿ7_ÿ"OàÄš¹©‰NÈ¢íO‹Y °ài¹hºù+tþëëOHju>¥ÆöÇÇ©E°¤íd�òá-(ä6ÀökÑ~¬‚í-‡BçÞz'¤röË]Â~|¸m›�8v§ª»à¸g $U{_}^o:ÎÃÕw|X¹“›ŽîÀY໢ØÓM:ÙâJ¥Ûð#Ò{õ@ Á Em q>q‚‚5ޱXƒ�{¬¢ëµü¾ï4\# ··Èñˆv)¬ô²Ç*§�¤0ˆýîǯîÐÁâm÷XNØìU¿¸Gº–ÎÊF$ks…Ò8¾Ú"‹Óë³É½w:ÿW#Šª]¡lX�e3.‰ž}—rا lzHNÄÚwäyqXH¯@ƒ??élçò¨­á°M®Ùk� þé‰f1üʾ&(Ò(~<.Z43h£;¿Ö‘»¼3Þ5Ø œÉ©"ÙOþ(`9*i«±a„2l¯O÷þ{±È»ƒÖD$‹á6ø1Î’u�=°9a /x`C·½_RlS¡ <‡5½Nq|— 'þ#ÕËqÈ’ÓtòÅP”ï<.-¡ßU¶‰´ø¤phú<žéŸ‚3ø8&®�~<yƒþk'¼mëOÔ÷p vΟ‹/eÿаJ6üe@ÆiΡ]¼@Õœz¸(ÃÍ×°Ow9G˜Ûˆj·*ùáâ½’#§B(ÃD•?xqK|4޳ ÒzâÅ{|[*EMÿæóùáØhÿXlZñ¦ÄYpóï<üG[\ë<‡†˜©c×ÃP´ �~‚%ö¾0�ß„ù ×óäpª‚¿ÐÉÁCù ñÅN°TqíN7²Ñ\‚Õ†±Ý·18"ÐCS}È6­jc„ÍS÷ÁÜswaÉ¿¾�ûØ’Yû~ÎÿÓ?Ïç0--ìHS¢´ÙÏ8À?‘#o�Qˆ'ê¼6Á ¿­ðKÁHL®WÂQ—Š`ö>¼4ÃŒ†¹¡C+59JÿŸï¬¾GgFTñ‡®Q¸èBºô¬>•ýG!^ú´ž6>–¯-ƒxŽTž°ñ€#ßmÜÄý .Wë>²Â‰§qK“ ¹]½žªã´,Ö«ƒ¶«”XsÃ!Äc‡œHš?Î «2Ãp­î(Þ¤P…·õTñëð=ýáÙÔa.ÂìF0ZýOêp¢KVò¥{1¼sg“�¼s5~ñL�–Ãÿ£è¼ÿz|¿ÜÞ‘¦ %- ©ÞÏ9‘J‰”¥¬"T|„PVE©ˆ„$¥(eTFBïçœÈ–MVE²EÊÌÊ×÷x^¯ç纮Ÿn=áj|4¨�×6…À«ƒ}D©Fž¨ZjÌ£ÓÅÏb„ÛTpþ£y–%Òô®ylÓ†M¥pë|_0}‰úú_A‡×G¨²¶?J_î§¹*šoÏ>êÕà»Êœš}}%T¢aÐè}¬ÚvÏÔ溜¥0¥l 4æáçÖ4ü.Æ nŠ2DqÄkú*œ7¾öðº8(Ö=l‚òºÔº7…†úsËëø­€ +•QwDÅ6G‡ 2ÑË<œ§Ÿ;Bµ]VÕ>&{Ý€ýͲ,7ä!ÎêŸßßä ­,‰›ª1N=GåÄcÝV@ì`{8»ã&ü8懫¢Œiê©3dqt:j%©¡õ³BV 2Κ)‘ð¸ù¼Ò.¥O%°åÈUåWcךòÕ^_DÍóÚ8J)L¨š2Y4Ý]+8f' gO-Üj¦óÅÆq¸*å$MÿðRÌy. 2á§i扻dì5=“e8|Ä& 3X)Ö�ÑÄ [Ñì÷b­�ŒÝ“0ÿØ@ú12‘Ÿ:L”Ȥ¹RƒQx°×*hqD¿«tºÖ¯_oíÌ‚ÙðÖAÊ^õf^ÔÇOäíEI·Ò¨Ý#“x2>%†'B©çk2ñ½ŽÉǾJ”öÁÞï¿ÑiE—?4XgÎ8Ò¿×�ÿÝ0éá…5Ò‘½ÞÐú�¶”= Rœ×¢å­‡¸ ô3Å’¶øß¼�‚õ’õðtô \\b ¯Ê¼Ùât;T"ÜN·Ç¿–û.‡ #Âx\£#;Ø][/™@Còj8Ý ÖÚÞÿ›RR¥7�VvæC²�3KÒÒàÈ»-dèvžNÊáå)ë¹%õ­ ”m‡ãœ¶Ó­új´ÕzF–�ÿÖ%=»5î¥w;ÜEm¹ Θ~BúÒA Fevƒñn`¥Õ|l™CÇwµHR ;iheðÛ“BÏ/(¯Í�L±ÂEN=…³CþÒ&Õ!¸Ön;9–ò;ýÙä·ÔOXÿñL·5åfÅÞ”þk,íÚ2žW%l•ã0`éjðÝÛL—LE3g”†õµýøw£!Ì»[…iB�dÿý¡Üü|>HÎóf:((ñ§.Xõ£x6òË�3xÕ@E¾þÂP˜é¯‡Õê ð¦þ8쪊"é^#þ¢¼I¼êxÿÈvIóÍG0ë¥w ‹ ¢’î|9ü3}¨Râ&•0RžÔN¶=zàá69T{„âˆOÇȸ%Z'c~Æ^t»?¢åP°½ Û+½ho¤�0Òò´ožFŸhAÝølÌJ!”pà;Ó?+‡Ý§cººe�ðnž}·ßG»BxBÝ2~¾ª¿ëÂgû0`Î<м3ŸÅùñV­Åœœ™&‹ªúPx÷é=èc¥¯ýЭvÞœîöÆÆxàøŠÝb‡:Ùóašº)n,Wç¬âÑ0é×828 ÊiÞЃ³¸jk.lYµ�iÎ`ž&¶x[íÆá™v.Ýò�ÞY¨bÓàÇ�qÆDj»I™‚JÞÓ–üR–ØIŒäÖ{º_äÛ…f¬v:�R&ÊPÝ=OžSq…â7_%­!Ä?‹5ø�Ö4üÜÐÿ%´Ë›ðÄñ‚\â{áfX#µ$¬`èe†�Ô1rA(¬§i¯Ö£Øo/¼|žñŸ¯yÖú…°"z®è½R¿�–ãýý̱ñ‚šê„Ð*_9.Þ­ø7óê(¤ZžoyEà�Ä¡¼ÿÊMrò_ ݾöR.™Ã×[jÒµU<ùS �O+¡iƒ9 5ø«#Nfµ�û�{‚²L%èäЗ+,Œî‰Ýæ&Cɉ|x™ºlrlñåͧ¹ ·ÔZô·�]ëWÁØk„ì.Y.™·ŠÇ:ôDOçH¨KsEÝœ‡p�ºãôuî쥋´Óp�ÿ*ô0ßÄsÚ-xà 7rv¾ F“î6ù�6ígE¥@êI#¶ì›�?|�_XˆÑšº,Ú3Ô(z’·g6˜§ÀääÓ0ëáiº&÷Üùî 4˜M¥…s¶nkTéªM+Ô©-dC�=ÙrPœÅñÔÁå 3O }~¾#õ…-ÒåýÕøväNVø¹VÍH‡Öúß`d=kë(ìñH¸{ï²ôØ9â�ãö‚šùP´ƒ�"C±NS•ÝŽ%a—÷jü²@Oò]q…s§=â⢊œ³§ÌåOy<®£’,ë É×ùEÿŒÖãÃ¥—=²ÿwYnt’׿7‰ª…ðvíN|u£Cú:¢Kˆ +ƒ¼Ýæ¬ñ5�½Ž�àe\ ËTúâ¾áZ°oEì¼xIúQi2g—ng·¹Ä£ó›!Ö�S;–›òpr²—ÞyBeH'u5šea�×áUX}žgÂþ§‰Wb•Q}ÕØÿòŒ®L›Ž9V.<ÊG—'§"5µ?– ¯Ï[Ž­×ê¹�à­³6¸ïCC”OÃå$E6éTÃ*I:šSXÃ&‘ªÃZè£oŠønK%¨í± ÷ýzØÓÕTâ+?ßT½«Åë(gAØ~ÍÐV–z¸£éÎ ©�0úâeyå¥$!ô4ý¦†;‘±k3|B«zA„‚,ÔXkrÀëd x1�uw­ÂÐVœt1ýöÂ#%{ì\a‹óÍösïˆ^øÕTÓÓ"Å¢¢Éܺª˜G�‹�^§’ñ}�Ob¬úš$+Ãk¢b9ä¨[囡ö¢�âK‚…Åê¨�d~zÓÈ®®?(†R¹Ò+Œ›³–Cë‚…'y˜çÓC}í€ÕC‰2&ðµ,Œ2�Ö«ñ5•�¸¿ë.˜õ��ÖÓyÞ× T×ç˦ð ÅU\ÙÓƒ‚�ªCIs„Èh�‹Føqc$û©=ƒ×ËVÀø¦WÐÿÝ(W{aèMªÍ#JTé烃0eïfÒO—Eé!3îÿ‰œ¢ÁŽJø8Õ6&Y™ÞlóN ²«;áÁõSâ�¯[9ðã!*¦‰Ë–Ê€Ýôp~¸/¼zŽ^éÄ3þZÛG‡Â‰q·hwÄZøú¯Ï­uzpCa'nÞ €¡!w$ã�ß–vŽRA¿¯´ßw /hØA[ü«…�î k]È+œÄ¿o\­n;hsÑDÎ6IÅù~ßÄå_qëë|)^‰çΚÏåýl„3÷)ïçWÑEÞ”Æ/; 'ΫqºkµÐ¢ñ‚LByÍ<ð�¹ úOTQb¶ìÖ$¢jF…EΦÜÞWàû‡s=w3pxÙCþ™T®‹ê�¡FyPï{tä7³¼ò˜´`˜¸©¯=WŒ<ši›øá TÌ9OªSï@FB¾—¦à¦ÊŒ‡bOi­Ð9²UœýK–~u—C‡Ÿ3ø|ûL�Ú7-¤c‘Ä—cúã÷¡20î� .ùçG5Ï’]—•jkàÙıt©3WüõLôœÂýJOÑèØž·c4%�Χ#ûÞCÂj� uñâaìºqØ´Ü*ãBÓÅÜI½é¦ñ#Pº{ Äïep¨l®èÁ焱ð0R Õ;ѱ¢;_²9.Ìûïš¼Œw_÷¡«a¡4.É c®çPòËpиŽiëzà›‹´ëÊhÓÄ1=dàÓdY\ê&Çå· ñÐøç4wM< yçˆÍÛºÁ¤ O! r�•M—ujé„Úb>¶à¼²ÔÅþÃïB�mE·—Ÿ]Q<T é_9 =µ¼ÁàÝn¾ÿooÚu‘ÊðÛâç[ãù‘QMœöC´Ø’ ï"•X·"Ut�Çð§ÉOþ;;SõÃõSìx§ÎCÒ“}&¼Ñ¿Æ•qg¸ùe¥€†ƒ0©"Müß Ö °/Þ#�[±}š«°ÿ…'¨i²Áí]ì¨vŽ\þŒ…ÕOĤM'apê3(˜ºÊH3–Á…Ë{+ŽÜZÆg;�ʰ>*6ÓŽ¸CB­ýd·¹@¿çù�œN:¹¼Ùu�E™ÐQuœ³´VlKÝDË{†ßN¯„’Ùë1êX„øny/îײÆ¿?„/>Ž“´{p™¹7ZŸ¢ÆOwppîÚ05€­<¹áM T^OÆÙá.¨x`$—Õ”áA·ÅÜWóû">�Ón‘ÃÜûÒš£–¼6ʧ[’pU 9å=ó£·Àâ¦FáûO©Óáç­ÎIì•8 �O,ÅÆPŸ;EÇÆÊ³ù†ãBáa j>Õ/ó3¼ùšÆüNÈΗ(é©AÏ€ž4{¯fü¨�/;Äê?U¢ýUèš»€UÏ_ãšUnŠ9Ç“˜»e:›ä'àcÅô:¼wh|�‡#uQP�Ø»g1t,Z´€Éé2‰ç¦tѬDOìÜýV,îT�“‹T9âëUr ìMó`åŠ*ÈÇW×nëŽ/ÈG+ÌyáÁý÷†à<ÛÍ’}¹=øçõë‚· Éczp¤ï6ŠÌO&ñcœÛ“N/UnKúî(眡[¡ê¾ ßë™G÷�7�YÞq(¾k)þ tç�j#]çbtÐ�góŸ  oç_–Ôè«ñ(�gÂøoÈÐÚL32ÏÒ]'&÷{*ìQºU¿Ì™&¼Ò€aw®ó�ûòe•-äâÊÉ­“°p7t/¥51*'�§›+…Ä Ixð°?­S4G¤ó±ÅŽ“ÛP§Òr>7Û'*3~Z²ºÏ�Šç‹aAÄ:p»ú˜ÔËÀ=ã¸r¥Çzôö¨_ ^�ìq–ñQ‚GÑ<;p³�úRƒR¾ˆé5Éié>8þóž¤scƒd Èò™k¸è  _/¿Aš�Ryý;øùM•¶úöá£átrY;ìºz�ŠßDI†¨)ò•Õcñíºð2T™¿ ÷Áq{_ÑÓ?Ü+x1MßdÂ;<^ýé�Pyc(h™³`¸3"C(¼ð?”vÚc¯‘oéÓæ�èû[�ßLØCeiÃa©ãOZzê=+É Òs9!ì<]‚1tÈ¢ð9]^}z.w 3 1«I‰G(M£EÛ¨X1ïµ6wŒ{^}ê×A:PSLŽ?Hô•v²WT{ä4S†gƒ°üÈ0²œîLÙõ¤4Î\¼oYó¯{ó� þù3¬+{Š%·8ì¶.¹½·ƒ1[©îåwZí}B²ut%V>ÝEÑCã-ÓÏ’än8cµ ¯¸ ÔÍuõª).g;ô<�…}*"àÕ¯žœvÔRšYGû¾Yã_[Sq§\7öx’Ýb=pfìO ,6F3; Ôõ—ã+KªE¿< žuï�cüswZu`Ÿ¸éõZˆjê^—íP6Ç6+܆oÏsxBè6~q×,ñKêïó ›=ôu\¡°Ðe"¬8H;õ­û£Óáf˜&wÌ>Äʪ„©˜PûK2idg$„qlè,;) —÷¥7±�^›�ñ?•ñÛŠïÐ1utÅܧ<ý/ß}æÛ��hö–ÃÔÑ茇æEÒË7–P;pÎ_oÒðyu­�Þ„m“®Û§”lUyCà&\õf�2\kþϩޟÃêCNtpìN麜xñcf-•*À˜=•´°û*l½~–Š#�ÄÓnAœ<º úݬ€fãoðé“ Çfƒ¶bgE—hVyL^ÅÀÖ˾‚÷Ç£´âO!îEQœÉ7|âxg‚#åÄc@IÄ>5§_g4¥g‡® ÅGÜ%ùF7µÄûSO‰‰ýîÒØàÓ .m€· è¬m'å+íðì|"ëwn„µCgÀƒ>›8î¸-»YzñXÚOžÌ£òÜùÂC³¡|²sÿh~"V& _Öædbí‰WLg�±K>8¬…wšSßÁ6<ìèERÿh-nÜ› ’¶Aþ eÎN³F'ïB€�Û2PËê2­Y» ¯4¥R“vo\PåÀsîÁ 09\ö;ׄtã?]óiR½9úè\ãá‹J?ï ²ß½Yë²Ö¿ŽiÁ-ÿîTÜáLþ]aÖÂ\ú¯iM2@éÈÁyçae~ K�Æ“l/¦Þí‚Mrí�­\Hƒþ<�Û ïêO‡µTw ™FÕëñÊS0&1úÿŽŸvÏÎE�ôy¥"l:PC-5¶8øŽ ¨Ä_'§ï1¹ß~ZmúB(üû•^PÀ _ Ç�[Páá..ß×çÌeê±í<÷ ÇÐìU#PÞU¤ �uè.Ò&z8ðΈkÀƒx5e¬Ü-Y÷¡ïãÃi©óy²Ä�<Òí6Üx™ø×†2¼vRï'OédÛiÚÔnˆCó2œu”ÂÁm¬ÏèÝ ³ã¿ƒT0ÃGÁÏ©eæV!µ÷oR¾c,Qº•E_¤�ON :N|'�ÙM¨’„y£bØ#x"OT{Dn¥Bw‡©àÜü–”î�ÌTÄ&Ÿðrll¿U)´Îñ†æÉUpö²)v̜ɉ³‚ûpe¬_>�6råJY^yl0^Ïï‡bæ~*-�©Cž‘ßZm~ÈNèÑç6ŒÕ‡K«ŽÓêŽ<(¿+åéÎä8Z0a:ÅÚa{�7Æi°Íý¸ãÕ:ñóKèLÚ,G:nËjö΃&­JšqWµ’—Á͂Ņ¿ty¿/gr•ÐÙ`Ë'ynm2H”@ý‰ ÿ8®ŒŽµqpèѲ߯$ëà²Ñ=R™=ãì†c¾î\ttJ½·aÙ#‹à�ø²kº¤ú—Lávš È—Xàó™]ÐWi ,ÛO�C/R·¿×à­r/Û¥‹ ‰²¼0Ú‡Ï%yI˜*ð)¹üûtAò3t=¿¤ý;¨»‰ <_ØD¾’`(Ÿ—K7–ï… OvµK‡ÄSáÉølxè7ŽC“Uð^ñi¥êGˆ|v€’lÝÙv­†×“žoŽý¾íµÇÓLq ±_†#;úPðÙ=éÍS2£I=y¾°;F—ÙôàÑc8jq‚øÐ@†¬z²­ëvqÁJ¦M­P8|/_ß�z‡yþOÅ—÷¶ãR§~„ï+œ„Ñ…Ñ,o¿€k£g`ï–xTÙÀú+6ò¡E%øî_{nN Ç7èRäJœùð7M”Y©·>ÑãžõBî—›p7Zž’–v«¾pí±Z�#Çâô{Y{y.ì‹Û¿ú}›…W`�\*¹s–†/ÁŽ ñýœEðhÀ^pÞ·ú°Od½Û.ÇG}‡¡T¹ëÓÚTà¡ÁàB|;{¯Ð§f�xÙîJu�íÚèºl»xôŠ:)Ôºð‚… x-([×o…dÃc0pÂMqN¼„γoßûÉëÂJèM©9¯ç`P^8‹› –³ø"âmÀ–7“—gžÂÛõEµ2üx`.Ö=ÙF&ý>³k‹!¿¶üE‹îÙò†çê4çökÐöQ¥X/%’›sWŒ=u<‡xbÄ·"/�Œšö@[¥ˆ÷ã^2lqÄŽ{ ØBÎúõ°Æi?ôœ:’‹÷f³ìwH}U f?c¾ïtLý²–ÓJOÂŽ�¶ä³à#Ý )‡õÊÉ8ûÇVÒïþ�›q[Ae ·( b%Å}â6èñj›{%Åãš$þóÑ‹�°CHäÀèD®™ð�òr¯ÂÎ2uÉ; iœÒ>ÌX?C¸âžÌJïVqôZs44Ý‹ �}ê–…Ã5^ ÏϺrï÷ð�[9�¹)ÏÁe~xçP7|4Ö™ŸW„Y_ÓKîKò8ÝBÌM¬…âùxËc?žÌÝŠÃï÷ÄÂg¡ïv~×{9”ßtF·ºd‚ÒIpB^‡@„—´�Á‘ϰ"®’u—e­‹È-1E,møÃ³v e�àDÔZí-ÂŽÕ³èW‚">ù�ÃÃþÍ—Á½øé[=aå¯l.zGÅó®�¯ÞXôî0¸M dÿO£ÐÈ8{„%c®€aæ(zн³FøÙÿ!�ÊêÍã áõʘâ!Ë1m3±Êܤ—PŽ®<;¬Và÷SíqÄó‘¼å_S¹œ›�=·.ষռBE|ÏÜÙÐ~89Ñ {õC¶uv0'ÒçÙcóŒl´®ÃjvPÿl=´›…¯L¥4©¿€ó2z ]²©¼Ût·äÁºxIŽ«_ÎÐä†þ9‚Çk>¶>žåÇXñ—VÜÇà ™ ŸÄFá¯`ÉáðþÃ\N6¶Æó7³„¥z�àôYe¼ÎCžE"N\´?©GS鿨òŸ%¦î‚‡<\¬q_ê­êE«{ËaÌíÞ8Qu<ž™Ÿ…�v{KU†¼�øæB×r¾Ó´Ìzªý@a^@CJ6K&oK”÷Œ�ÙñÝÄ£“)+Í‹H�ÿ˜)@Õ*{;v‹fn»Gúòqxäœn†ðÒÂ3h:Ñ@ðÄ{rr渗pèÜhèLÇ+ž�üÄ«/zfôe¥nFT£4Ÿê‰âÌÛJxàƒ.ÂØ3¤äŸ'¦Ýþ]Ã;$×ö�÷úð.Ýâ�%æyM‹IT˜æÂ!]›Ñ4öÅ|‚ô�68¾çzˆÙðŽR,¿@RK|3<š–×úcÕ‰}âá”=|túXÒ¶Ÿ -sþÖzø0€©âàN¸öã4(vúÑ.ÅÝb^¾2—)r¿IµÐ›IŽ^÷ÿ¹¡6 H§I®Å°Î.Yw’ºëV€ç˵h<öÜ‘‰ä}ã»óœß[ɳËÛï!¿©[ �‰3ôñÜê�Ð/u3”væù¶ÉⱇkÙ;W‰×ÍÇ‚uwéÆ�^tyÀE­;•7ßß‹™“ÒÐ\#ƒœÐánûöÀ�™OQf�WGvÀéÈ`Üìòr¾Øòo“A<àäEQüº$F+§àˆ Cº°f%[Õ(Q½C6¨¥¤ =Æg±}Î1“Ï•Îk�å¬Ü@üïI6>²‹?8L™Ëˆãn�ç‚KA+öä[Ý+쯃rbä;/àÑ”D«§)Ânýã¢á÷µ<¸±*–úâtåK¥±¢ÇîZÔ©;×çÉaGõšÐ²2hVNÂß[õ8UÁ�¦ÆÊ�»‚–XÝ÷7Éß²A瘓�"t”.Ƽu!tB+†¦¯Ý…ƒF‹S ÅJÿkÕ*›v‰ÅŸîÁ ß¹üÇû/º1ˆG®»Åº®¶°+' *J°aǬKëÎŽ•'¡m^/óÎD%½C°o¬+�ýÒ›·§ßƒÈÛFØô䪟2ŽVÆ‹3¾öåUï ÉÊ+­|X�—�…} šl;"1RëÆáÌ_Dÿ,†Ù±=8ð‡,6(v§sqÄIÒ<á§ÄîÊEË1&dî; .6ã«ï©¡SªépußXtÌÑÄNq�.3äøOÁØuê=ùý½+Y>C› µ·‘~¢Êƒ;ÂyÁoy xõ^Xþª;:å¸9{g\Ûæ`NEž¨éy¦íÀ3‰Ö˜ ‚eKGáûE•¯£á–´ ¢’ hÍŽcìñ[•¾íZ�g»GK: #1&Y‰ë¾^BÎ)Š•²øÓü`Ü'Þ�ØŸ‘ØZâ�±Š)ûÒM,œ?�–]΋ @z°ô˜?šÌóF=Óà*�w2S/’ûÊqÒï2xwm$½‘Æì~ê¬8ÿ’;SÈ>ˆºëýSñþ…vX½Å ¼»g �Ÿw±8ö©Óˬídù¦ãqi6¾é™Šm°âÛCˆuîÉ×[Lp¤Ò:þ^õ GªÜÓÖ·4j*¶¿Ì‡þ::¸Rqu‰üHÝ ‹ƒºsÍmMZÞžrÏnˆãƒqºàÌMÊÀNÕ ×`•žZ5j‹WᯕE¸»Ð„ï�Úîçá«gúôÇ‹oÛ®ÇâA&°¨·œË;9m\Ðõ úŒÎÁ Êlb•õ�Õ £zTzªi¸\7aGûT:m5׬¸ß ÆÜÙM»ÃÄÆŸÉÂöô^¨)¬½eòŸÇzì™w†Õ?Ïd—l�· ̲[„ÙzòÄ Ûp~|8EÜüG,â›ÿx¾¸³D×|ª.ȇeîs©¥"žg/SÄóË�Ç4¾RÓAêÑ;xBe ˜/Õ‚©±WI×T‚½/-¢ÀB#R”ÑD¯êóÒŠ�Ùørzw*�©Ï›æø±im_~µÔ·Yðd­½P3úUŸÉçB\ÛåÅÊ @5/BðdÂO¸pÿU¨ C9ãDtú¼žNž˜$=+�N/ª=Ñ.d ®\ô�||ô‘Þ#¸_­Aññvß§'ÍoŠD­3Àmsó¡òl ÷Îv `ߪË0[´â»ÓÃðÔá)9ôzõÇÁc±ÌR >‰G`@W»8º·%ØŽ=½Í]›»öžCÕ�Õñ ;ÿ½¬ŒWœ �bºalñzh‘éÇ*‡×Io�€Ö'œ¸×Þ#¸rc()ÆâÁ¬ »¥ŠÁWŒ…p›áxùX–8­6-9?–µ Û—å@Äè�¢‹ÚF0 ëz߇ì-wÀÚþ­—çÁ{÷\ï]/á÷¿Ã#×]@×§s–d»ôÍã"²+ÒBË&-4w„ŠŠ0çâB”=Ô“'™ÄéAÞà”D‡¦ï'÷”í’¬^Ò5–Éü¡È‡=úd°V´ Œ(J‚_NþܲÔ�½N‰.£Ù°`#h—²ÖòÎÖ.¯†g/.FäYW‰i‹zãˆýÙqà%’Ès·]Ñà|ý 7Äœ¢õbø˜;°[Á‚ö®Yê÷L!êþHt²ë¢cöj<0s—­^ÀûÛBÅóqsøíîC`˜é$†Æ7�‰Ãvª÷ú z£Î¡w¬œY–]š²Yñ³ ¥»CÛ‡¼‡ó‡_€õ¦Fˆñ=LñíÓÄ«zº¥=Ïí°³V¢Þ�B”o´`{™÷X°MŽ þN¢å‡ËÙÍɱÚ̧\õfÌõÓ™fAtum_Tœq†×N ãðû:°)û)ŒªÝOzâÜÁý¸<±ÓsúpïþC°Ð5[BCÐÁv¹°ì�.ÄörÀb¿tÞ5˯Fgá˜�°ðY>ÝÚVnƒuõ–ž÷@óC»0îÃGaDY¶´!q·($�áCÛ\øhÿá¬Ö”HúEDÞ> ÇÇî¢ew-Hk· Gí߆omþ“¾®&¨5Xñ Ç:pà‡ _•‹£g#.{ÓÂ@uôKµrC‰Ê;†aäœ5¥žf¾€ ÿñcX~—Wó›.Ÿ�â»þE�á–*§�P‰�ªK�b/:_“‰“¥CyçÆž�¥¯Èšaº˜¹'�,]ñÂ\ԦÅ©øÆ<¶ÛàÁþYh`mͧBX¨_€�§rk€7š�Äw6Ë‚šô¨x"'¶+³_N•0¤£?޹¾’$Z_ ýod¿!„ެ®„ÌÒd\—CÚÁè¼kš�˜…:Ïîâðsé4ÅÙ”WïÏ¥ïT\Âc±Ð÷!…ýÒçŒrm8–Ö@ÒIRqUûŠX² ¶Ì*ÂQ7л4Ž?‡Üäòï–ØËÓÞ¯óÃ~ùðÆ¿„½�– 'ŽœXIsä—ÚAΈ�äý£’ûúr/}<ÖšÀ…»æ‘çO'ÜlÛŦ<à‹!xfôîðÙ- Q¥tJ:_*Ø/ à52Æh4‡¬;&êúØ¡V¹_ê6 ×.ÅÔà¡ü~my-Ä?ÚMé·|ö=}FZ¢©�çÿ±gC~{´œ>M�àÇsаb %ŒÔ…ì}Á¢÷{sìy³öiÇàCu|²îç%ss¥¯/âr¹“�é Ó¸Á“±‡ÈiÐ^éFÏ xŸüo†«Ž…=G³JÝvÃæpMZP—K+\-¡Ûô^xˆÜÓùâÕÝø1ý<ü‘ö É©Êì�†+7½…~‘ùç’ Ž©ë+6·ñ'.†¹y[EùÝ–$Ö2ª[±ä{o1ñS O´�ÑV%â‰úpvø�‚jó§Áê™[hÄJó±¥´|'É-ÇåØ0\—VæÑ¥ ³¡ Æ°ãˆeÁXÓõï ©»ó¢›Ó ÉÖ‡eÕ/Ò±N#´™£È�Ίxxó"a÷«x.x{ššÚ¦ö¢ãX½]^|õ¸Üü2t"ɨ|®7�-)*”ã>�[È£S†sü¦è^Û '¢’~Ná)³<Ä®£ðYx"mpŸŠuɳxnØ \aŒãçŽÀ8¯/p£6‰Ï}&WŽÀß7KaÖ‡l¯V””��pÿª>–V‰!“Ë«o|©jývÚ"Â(AQćhSd‚ëŽ*¢Ù×oTÐ0KãÍ@ýïdž±"ª;á—·›þnÜÛ ¾…jœ;]–ˆ‡›b™ê'nÑÄÔ#KhÞñ8õŸ)�í¿ˆ«|Çá,EG>·C›åŸá†)I¸úQé¿ÆmµþŒ¦¶ïß×wx{ÿoqw€ ønÔG·?'Aa‚„úù^€‘kÄÉg@1ë:[Æé¡Þ¤ìaÕu÷*�Ö•RçèÓ Ýf&|Ñ�÷,ù@z‰jÂö‚¯”S¦ÌSÁ�V­åp÷-Ôª¾^==á‡aÖ?6õL/¡CïÓ áÜU\j7ûm]‚‘" W‰{Wk╳f _·�¦.š‰ïzG [jH+0¦oìM}fBÈÇ~i¿V°b>':|¤Ì’|ñσú¼+‘o,èÇEvr¨=LOñ‡¡¨pWX‹wçöø×Ûg@U. íð×byþGo t°[ÏPT ¯@•‘#„‡š+qj×QQæÚx⯇å+_ã˜çY”zÝ œ6 õ}4fû¨0œ7K·ÒèI&èf8ýxA}ŒèGêRNöȇƒ‘:<ß¼X]êïíL¸ðí²2,™¬ÃÕ*{¡sÄ ¨ý³‚ÏfñhëÅ0äO’ÐE5Ò|•°à´6W;þ‡ß:ò£ý2üøÉ^œX-„û£ÁÖ ¢Lb.yùœº¿ù¿ŽY[» ?->‡T® ß<¥ß«=a²n&gÇ)ðÆÆÕõ4 .ß|o_ÃÙ+%™ÆnÔ·GØœÝIsŸ¥cJ?aaó(‰ìâÉë×à_Çtq\þqÊ ðÉ=G¿Âµpt`8ù5m¡ûòã©*Ç’nVä±?.5QƒX0J÷’Á1Œ ÿëÃÚiÒ ­÷¬pèY±û¼Äo1«xíÍ£”6¤ ªw §‹¦ÑÖ…¦â i ð~FÅêîx}W~>#F×ño ©ØØ{Šoç {Žªò K2|Î$ª®Ï§C{{cµù 2¯Pàmצ€\¡’K²Ðå©»ÉüÄSqÓN4ºªÄÁ¡<›î“˜|š_œ?J¿tÆ‚áÕS0 ûNyœB/ÛBžîº®ZD¶ÿqÃdÄZ­ç–ÜÐÍ6„7l1âCUºÌ³¡Ìi7×ÇÕÓ–!±8çã[il]«‡µ Ïi2mí눹§¯PA7~xĪ7ò’ûÈus*ì±´ä_Ó#¡oÖS,oÉÂãŒaME� ÷ÄÄÆRŒQ< f^Ø&\ºý ¥sǰì½iï0 ì/w Ÿro:UpÁq¹`rÌ—÷-¯ƒµ£¢ÄÎ�{ðÑ„ʘéŠÛ�‚džETÑc/ŸŽ6à�¹©ü÷ÖcXZP�çJ Ë^k'*ó•6 ðø–Æò*ÙÕ[?jâ(�ž`1�wg+ãã¾êÚ#‡ü>v@†ý¡þc$EqiÃsÚï„ 7ï—. »F5a÷ ýNļY�“æ!ݳç!²å&m¡ÆAäÆQú‰t_‰èœd?(Ÿ…ÊyÁàÙöS$.Ë“å0›“4|s5\�¨ª‡ES¡qË0v{f‚3lò´’Û�Xº±’Ò El�ðLPo¿EË>ü…C¯ð»…–ð_á1˜ør6?I^‡7‹Pe½'uí‚ßÝN‹õùµövô?<ˆ„ü…¼¹ÿ6JœM—fs¯)°µ|üÚ œãpt|Eï…ëg�vÛRž÷KA†NbÚ?s ù(…3ߡʙ³°,¹€6;dpj€!# É­™�õßwñdB4lœ9 ç ¯£Mª8~¯ d¿J¡Zl£�W§PpgϰT¤g®1XcÖsמéðîd!¿–û.8Cû_§•ëGâÏyRŠÙ¥�µr)pcƒ;¯ý¥Ê?d5(X!ƒ>»óý [·Ý“·³ÄR…þ$7}t^þtÞ½'…ǵB„Á<~B™?Ø ÜãØÛVĤ�u–-äµÊ‹ †8ðÝ__Ä'ôR´Ü¸Þ¬?$¶¡QÜ8°²™H 'daÆ£LÁ>b=š½.z·[á“` „:gVðÔ¶žhÛºGt�؃>ó¨ù»9îþ•º†Ki°¶3tÊÕ¿_Kœ4]r/k ¨VOCíBgðøD\3í9týëñ³êŽpý?%!io–$«1£Ì×ò¥o§ÁRc?ù�`ÁçÞEô‹? _Žh *Ve8äôWr=‚�?±À=«åpð®kÎ� £øä" N}ñTÔM0ÀÇm &ç&ùæ$ö›jƒ]ZI£#l.™¢½« N®}.ÜÿÏwW�§\þp´&½Çì‰ëœý:¸´-_ß= ¯–*¢ê-šc‚Ó¤p«W›ànoE·Ï´AxˆÌΕ”Älc¯3ƒ¡éfLÙÎEº657CĹu$÷b(›í‰�e1èïV¨\ñƒZkÐêŸgé_öFw_\Uüä© “z £Y£Ä_j뽆$§}˜Î‡ŒesKþƒ1Ç?|dk¥áp…çL„œæœ»yÄߦÆ` þáèÀ¡&ŠRÍȃÒÏòƒPM-›'�·/,$×YÝ1Ö±ž¢Ç;szL>¿cv­ØÄ³ä€åÛÞ€Òzš=Ç–­®)áÙ/iµòjyvÛä²Y[{ $U)ÂÎa­ôìÖpÔÿõ :³yCªÖŸ§µ+`ö⻊·iõ ((váÿÊ¿ˆ‘yæVœ÷¾UÔ™ÖÆ …PéÜÃõ|`ðpaÖ?Ô16“èl$¼œä‡²E^˜]:š= þã¨qþ¸©õ­6Œ¢f�­ 8>Ã\KÜ­7F~ìÝŸ_È™õv0FÆ“¯ÉŽ„}v‹šAZ5¿-RqÉãä'šá{ª¡’:fÞú=‡È¿zP:èUå:À>£¿TpU‡å/~‚Ë.10Y)Ìä½ýî£Ê�\�wŒ´ôÒÄ«yòt*¦'Uûƈûr”Á½à-»wôj,¹Ï˜!ØmÉrv¨Ÿ¥ÿið«¦bv³öáw>ñ`þH†½[Z é�*‡{�.ÔÑ‚üt˜–XE¿½Œ°]Õ­{-ÅÅWSéÍñ7ô8§ú-›†Ž–iä�ËàõïY9€tÝŸ0ç¢Ò6º3v öz9@Ô;þEê{­~WCÿWÄ�‡ßÃ"Û¥âKç�|j¬ÆÔNÊ¡õÄDš2¿ž 0„YÁ㱪›7ÎnÓ*ž³âÕ�¤ýÉ–ñéc8=. Ÿ.¬¦[—§RæÆÊ“É~–d�ñ+³�æ~©ÿ:gTÓ˜Êw¾ž§�IùÜùá.È{ï¦8+s>»â“p\xJÑ®¨zû -ŸhÀ 4…æøSòÄUªiTÃPž&£ ÝË9¥:�[ÞÆB€åPù\„Jf´gbùC#ÜJ&løe-¥DÈpņ rJýÍo\6Ñ©â‰8qÔNÌpðe�UÛÄýwùd¤ãòøäñ[~j l¡U+Y¡% ]ÏÓ(`ŒmR.#BÍÈÄù!•¬Ví�ƒ Ôj&Í-ç9?§¿Zq‰GËdªcîêÑøÀcðÐtTn}Cuš¿%§®¸²Lóf¸eÕ�/þÞl4Ï ’ð=cuŸÏtâÑjúØ�3ÂþGqy¸åü¶a,ÓYvY�ÃOo‡r¼s?Ú¾COÐíz.nÛ_$¼ó䀰âêC©8ïDw–ùcÇûk{.Ðèp5`鿞¬fÓÖü×A™· R#+ÓJˆÞ .fÍæn™�ûvŽÇÉËïRØ“S $w”Š­¢öÒ³¸;c1¯¾sýˆ£‘^g))d2« R¾§¾¢Ãã&àê¨Q|Zü$èÔ,äFÇYôeÖ3Që+î�¡U£P×Q›T·l×h¦ãé-1pùlòæ¼íåLd5}Ž{ð³’rz=ù4<Ÿ Õ{`IJ%æGq½ëúÒ? ÖnŒ£ìBC?ÒMr68Kz¸9»–a.¤rcî(N³YÆvÖµ¨sFWõÞ��ÏÙͲKû½‰‡iol:YÕz€þ¹•8je>¾Õ)Âî= Ø5ð4½_èÏÏ ô�]~¢†y˜°`“•Ðòb0¶lœÌ>¦ÇààØÊÚ³vI`vbür ÜÇlâÊú?0ªuµÄ_a-¯™�˧>‡_5Ñ$Oß ¯ ºÁõdp¦-xC!;ÀþÌ òŠÑ£Y3Qÿg(¨¨Ž�kgSééÊH=öv]nãZ£ ¿nG—–âOi#Í�U§ßê£Ù¯j"*—ëp­�C‹@?ÂÒ »  ¢Šî:ysÒþÇâÄY«ñÁ1Eø8]‚yÁ¼h½.'øXrØÀn<ùÎzd^N ïYJê_ÆQËð´Í¹¾ÎNУæC„iJ—©1< ä÷Àtþ0/ƒ'ØojO¾™]ÁQxš‡¦wãŽ#pÉ=[–æ!+÷’Ú¨O’ÎQ–ì;×”¯)=zÿÔÇ3Yé˜<Ά=ºã«M7À8ñ�¸>‘»ä’¶Ê?GœÑúsºãÊÎ<^2§?ëŽkGÜ= w £qòžsÔk`0› ·aFí4>ÙÔÿß]ëhÐQ8µK—=�¦JöÊàæès<«./°Guu/>Õဋ­ ¿3–<›²@{B«Nø�—ôM«Ý ¿ø,ݽYO޹cPúvÑ=¨šfäð8cEß;·ê)ãK›+1,/íZ�½>N†é4lx9”º·Ï¦ìQ9¸[綨ï¡Ë¼]Á5Ù»�°ÇQ‡�fQòoe”SôÇçigœ¿|¼…g 2ððÍ%X½Íªçé±ý´*‘ß©£ö‡|N–Ì[�B- tWTçÍ#óétá\µ\‹›"/ÀËyG Áà¿ô†¿~%|°R£Äs½ø_pÊfTO(ä×µ³û�Rpvžd«ÍèîɘÞk+ ͈‡ÄÄ_âÕûA˜ªõ†ßvG Òà[�“ÙÞ6Š¿nÂq�G¢øñ8Y^04ê†èyw,èÇ@æ³µâÆqa°çûd.êÞLmÆVø{·>n9ˆ÷{·Û¯ar¯n #F „sW¢Å[e×é†a ŽÏÕ‡°Îßu\sv;¶l°­p/ìØýog%æÁ²0(ÁK¸y;N¼z"QQ÷¥UÇKx¸² ¾rúF§Lk$×Â>K__QǘCp):M´TÞD ötCߥ‹°û‡¼©:žØ,aÕÇ31w¹®í×(.q*…&�n(÷_#õ9€Aºƒé¤ò-Z–{>û(ñŸœÄÛJwŠW^^‡;eoaøæRpŠ® ',Å wЪ#ØDcÜ»nƒÝâ ‘¶¬K‡ý2oñùÕ¢òûFaÕÃwV‘_7Q³SzˆdZñ<õ*<ëåp¯© Ûö�A[g€úƒ@êºv–žt®”¶¼”n³� <,øwŽê!ªR ¯�êAósºÓªÜL:·¿^»k»& ÅwóßP¦×z¼™ŸŸ#ßqòšþóo$³‡7‚ïÈ»ÜåVN¿ÂðÐB:bú„îœÙKA1èv¥ÉbÉÐ h9Ç™£Ô¸ýO$º®Xƒæ{îQÆf :²HyÜn\oеß~ÃÚM ¸*©­îùªå✼n¸.T·nåä{”~°¶%¿¥EÃ`�BNË`úíRJÇîlæËçæ“ª¢&>üa�“RðÀBä'�FØk^‹pº<R–ér‘m…8ÏN›¶+òÈuypùã(ý4Wɽ盓Xgn®¨Xb Ç_ÖÒ]��˜ë¶N0 í‡s·ó|�TÒó•¥Ô�ªx§`V¾9yá.xaóSôÙþ€Êó6@/×l8%þ†^�C¤5扼þ¤+·Yö¥§E¡âÅ5ÑhÞgp]Þ�nˆ›ú»ñ…«iÒžYò\Ñ­nì\‡>ÿ22~ÚHñÛªE˜ór6-¸Ø�o¾ôÁ¨qv<Óyލ]Ù­TQ³­” dÅ�º@‹ž“åãDá×ûX3 ž>XŒd’Ï‹i0| ;¢]z5Öiä�ç‘4Ø«öžB<0uŠÇz�Æ”#éuíPR*­£—dq§ƒ%w&o&½ölÌYœÅ�)Å�ü5B�)\ÈïÆKBún„µß.ÑìeøËÉTØ¢} ×HåÏ›u9ây•�uñÕ¬*§ ÞÓÁ׫1~´„g{|䨷]Pá‘Ã/�Ìù°ÊLñú¨Ê±u›ªü§�Ù¼Šûœ “«ùbᬹø'þ ¶wóMe\¹ÊŒÁBï,;– 3Äk·¥tHÏ„JϪ +dw‹“q¤…±Õ­Lù]F¯e+„õa³àüL,7Å|ãÙ``|ú« eÇÉ)èñϽŒÞ®åK)pfûqHm�Â�¡<ðáOtœ¼ ûûñ ï_Ñ8…Ádwl<•aïÊû¤‘Ö%ÞNÛÅÃøÀÕi<æçcAFë3~ Vë"V-˜Ë!­3„KíM°?n+9w8âËL¿:1ñ™.è°k¥µU•c€X!™<ûqu™j9ÃÑ]2àñNS¢ª¹Ñ6Íyè: ôY8žO™ãÄÄatW/”žZèò•Òž¨¥Ò@q�©¸T%\hŠÍC½`Äfm°÷®„QÚýaä¢N¸’¨‰‰!þŒxÉQVèÔ½#LZnD®qyteæU˜%;·½7Ñb–äƒ_DÝÅóÓH-b.{7ŠïÌË�·ýe±ÆØˆ>.ÜGûìû²¢œ�SàØÂñ¢oÙPq?œ£Š®íÒçnG”Èû€íµ|Cu;Ê z»'8q•¡2Ì;v�]C.òµî£iP¤D~íÀÒ»›(Ic7®qÄ¥~l¸@•o5þ  Z3˜T]Í“«Cÿyã\ôï9ÕxÑ´F3ù'bD@,no= ‹Ôäê7¯&nqΦ§)ÿ².§Ìæ9}qì#_h�°Áu;qkÃLL( §"Ýú�¥^\0Ú„ãœb­ëqN��‚+N�Áµ?ßÄÂoh=½Ïz÷[¸¡Ìi“û¸c•´(;ÌŽjá ù\·QÛEž¬h‡c�ô¡Ï\^VßNKº%Áîç»@Ïfî±ZÅýí¼X~d­yÏ»¢MX!yºn×[Ç´à€¤ð·-�Öm3"‹u6(~Þ+¼é(ÂIËî“Gµ�ÄÏe6ÌXý“=ˆ�Vÿ�u:_…V nën�E—G �hóì‰;ë¢l§¢G„/ö,ZÔ¹Ò¶w=`¼ÙM.Ž�ãäÁ¥ÔVPa«Ö5NšÈùÊ÷¤÷ì¾Ð-[5æ)&UfsÒ©5îþ�æ ÇNÖÐÅ�Oi½«¿˜!KSòÜ%å[ŽHM+ãýÝ4µ~ \¼ƒè´Deâ~K`Ñ88«w½£Ì~AÆFÎåÍ™þ|îOÖ­ÚCw-[…”ÇÏ(´w¨%£ —ãð©ì{Úyä,*¨o¿B|µY�ì[ÌS®Ì’3à? (¯<à4P/W­? OܳХƋ«VÁÒÄpžpíŽT”HÙW°Ôó¾äô¥OÐÜqC¬LþA½Û÷H‚â21[e˜³þø ^òÔïå>‚ ¿Ï‚¾¹ ‘É|¸÷(~ßRKJöW±u·%CŸZV,ɇß�2‚÷PkÎ(A+ê0®ëþÒóß㪫Ý]d×öâüö2ž�¬ºa¹øû‘†|?-n:6‘¼ÿ¡àïÁgÖÃß'rD©·!î¹Ï}UEƒ<ÊY¨—‚ìƒUÜ­øtÝ’Æ,«—ù'z èj`‡£O·ÓÚsÇ¡G¯§àûÛ“ŸÎÈ•†`:m[À5ÞñFŸðxÑ:ÕÂJ\C·¢ýÝ£<*¤ŠnÚ´@ó£r<Ÿ×‡‡`¨{J„¤¾Ïa½™)n»' Nž*8¯i�ƒY%ÔU·’g‰f´e™„ÎÝ„!ErX£k޵# y·�ϬÊ·>–Wž Õ™,yðæÆˆ�)üFa,–ù©ÃŸg×¾o¥m3Ö¡ÞUy,ϹA>ÓÍùámðÙ*Ÿ(ÏǽgÓÙÛw9ت«á`‡l:½í]Xì /Wù•ú"®,zÍ2¹TÒæ�ç§ðÚc÷¥Ç£f‘Í×w ªàÔÁƒØ?l=Ž�0Äàþ`}ò>ù\?·p’´fñe;¾øv7Õ ‚/ßw‚mi7j:ÓŠ“vðÜí†lrú|hÞŒq)§iRøZc+j÷´á‘Ýôyï cJ«Ü!•û¡GÉb°b.—Ébµ‰—°uÑP,×�ÁvjÉðÅþ�°æ×bön�³"¯ó'Û�Ü,m'ÍÜ,Ú*Ò =/ö—�‹»fpÞïáõɦºõn–¨4c4Î:¾B–`ϯ¨7h>~~”—›û¢‡RN>ÿ™ZΡßèj(õ�ÎÇþ8‘˜«Kc&¢†£;~N·Cö /˜«¯�KoíÇ;3&@ó×6áúï«ëï�•òÛÁ{ùzŒÜN`ÕO“¯�žI�ÀÍ8廇Ù,{†²²‰ûÜ¥N‡!,Ù¢ÀÇÞÏc·_§ÅÚzUTžw î¶h‘ÓOˆ–­¦C›a³‘é<\²¦†Í�$Цê(2ßí�ÑÏ7Ád+qHM ¨FÑÛaÑ«E0Ôm">QÇ�òjYwX#ëö;†\wá¹€­ì×OGè¦v”Õò°=FpÅ|&E`Lœ&tV¤ÐØíêØwh3·ª�À¥†‹q÷/k&=wlºn Ë:†�^/ ¿· §•tpYaM¨>'^*L�L~q{éY] ¿ÞcþoÕ9Gm,Œ2B'W#”¯9 jsk…üŠP7ù=Í‘ãq³`Dt]˜˜@w[åP)÷4~ž'‘“ž‘D¶{Š%�à„e‘8Zæ˜äù•Õ´LÍ��ŒŒ§'Áؾö n—^ú�z²]}Bn#ݨöà_§`Û×3ølUÍÜš —û®æCVõÂÜuݰÿ,GΪü 6jkY€¯§}õ¥Ð±ë¹\šÌŠûøÔ{kºõˆÐÉß�ÞËúBÁŠI'nzGóâçrÒã§Óð�K1mÛð•6š˜ávPpùå¡„_¬5pB¡&jÛ˜aw•o1| ÿZëÅ;Êž±Œi.”ïžEß¿^%ã¯I<äßZ›ƒÒûŽìÍOªRmm+ôX™Å_û†Q¸}NzÚ æ{:ƒë« †‹Ö˜7áVD Ö/·‘K{ºÈÃÏõ}XqµzM܈G#„Q n`‡®º´{Ï4º¥[Œ²³“„ªÍ�ÀrÈ¡¿êITìkHý/››lYñrk[Vñƒ;Á#çL;›û žŠ‹×¤sjÉB±Ô:‹ôüþÀ¸ Ï[´]´´8Ì<ì� |Wã*÷³ŒÍdð|7‚/μB+ФðE•-þy�#ÆÿÞÁ!o�߈ó¸Å0~ƒÖã`u:ÆÉ&SB’2G×Þ¦kŸÌøÆô8.>n�n2Ví9«1ù©/×~¸J��áXæCpÝó/·‚�ú\Ú %Ñùc›âiÜ®‘ ž¦Ío›ÅCIYèÛCêó´Øß­Ž©¬†˜ÝK€ 7òeöùh…wm ÔùJ*¶á‘›)˜b»<&ø¡AF�¤³k)_”Ï¥i�–Òåúl³Ò¶%|Ÿß0A™¥xu¯º}ÜŒº3R$žNÊl¼âtWüJ“âÇ>¯¤ã—ïeú„©i|`8Œh§ÈøxòÿÔ‡&oæ|� ¬µ×ÀÇ{açÄSxQ‰{¼Ã’"@yû5ªÏÞ‹Ó#Ä¿’;Ü^s†kÞŠðñn2©‚¿:&t“¦–ØÍ?¡áf DîîC‹ÕðO“:å®ÿ"8/’åó[yëÕçpt¥,f6ä‰{÷Äã´ÃßidM+mù&h¼š-¦C)ßë’Û©ðJó…z�2VJ÷,k‚+ÍЖ7žý35Ábß©NÒ@®qî‚‚»`ïõéøñ`9Ï.4a³ÁÛxÄ–t8y?KÎõA»+;„_àƒª™4ü¿atr•7ÚnúiΪ»Ê¸um§nOºÙœ«IG¤7jÍaNa=ì±L £ÃI<ô”%Jöî¡;AZ¸¸oÎÛ óÕψS‚$Ø‘›Ìý7|Á+­ ÐÊ[Ÿßº}‚¯;“Aé™®-¹J£¶TÐ𺋰u­À×ß‹ð{Ñ_¨ïÉ&íáèðÌ“ÓzÍë6]~ïeë¹zŸ-è~^Zœûî(æÁ�Þxôü q‚$‘Û jpé·ãxúÔ9´WUÁÏO2á†Þp ž¸ˆ“çúó´ÑFtdDY;Zpt¥ûm÷æÅ~(§ˆÒý–0Hf§NÝ„£‹�`ê§V±á̺v)™µ�›pÿ-ABŸ§±x®6ŒÎ�5à¼'Ð×|"¾ilÆæ§Vu} Ôðañ|c6,JàAçÅ)&Ã8h�®p©*™›’»à¡^2o«™Ï2S¡=7ŸaŒÿ(½¶ÓšD¶�–Tgr\\ºí:NËsb•9hrÊ‘§|ÐåªOëiÉ”0V=ñæ¿h½Ç=¼»b§ }ÈCv™£Þˆ�ô§C‰¯½)Àîu/_�yÆýp\�HÝ.¦æ°ɶµa´¾ †Í”sÉœ¨Æ¯Ê2Aþtÿ~<·O Ɇ~t·ñLžãÏ!EÂôØr(�þeCbñ`&êʕѤ=?é0Ý€}™j8gY"¦ÕÂôÜyðÞÇœw/ÏÁÔ•0~þz®u¯ÆŠ4 ¸’| "½vñ�ߪ.j=RÐÕ=Œ<{Œç—]­”×Íž3Tdpêô-¸tú^¥ˆ…¿Žs¯í×ÄÇŸ®òšPp°>ÄšaJ 2áwÛC¡ù'¡ë'4÷?OòymÒÉ—WŠ5Ó^Á?3¶Ê<ç¥øS\‡./6ñ ‡'Ô–7=-6£ÿûÅ‚º[4Þ;‘ÀFæ5b�¯*}ÈÂ�¯0>’étÆ4ð}òšF;ôÀðA·éÆh#ü¾×›uVqZÖ yXI¥? é}ª¤?,Ü ösoXQ—ÿ ê?]…Gæý°ªW±ôNJZæoƒ'�›ñÖüAtô¿‰8aÿY6[Ü·m6ÌÏrW’H©­HxۤƛÒ�Ó�“Lw¬‹…ÒY—ÅÌ ¼Ç_NP{ôŒì¯š°ðý1홣€]Zö$'ãdž‹ŽþÛê�Ip~GòIc E5šõ&²É 9¸VœOÀhÅ‘du:×9÷F%4a™?!p}¶?™'9ÚçüMÀ`ÿ©¸óO*ár}gŒ«ã³kl×Ý _~íâМàW¤Àu½bièÌþÉç=Z…=÷máù+c‰ÁAˆ¹˜‡mŸø¼­ ý×M›GÚ´�錑ìßôRLZûÊŒÃ+4áåŸî0îa¾æv„µ>þ×¾TÓ¶n‡àèÛ-0÷ƒ??×�ƒË_R»‰-Ï–Â-ƒzó¬ 쿉AÎÄ¥É÷¨à˜<7ÅNäo;ò=Ãý|÷u^ßëÂ’î›pÈÊ!,÷öÄhÊ@JÔ¿�ÇÎÜ' ðÝŒ(1mÄ`¾?ÊOû+³íè¬[ ‚ßÛã×ÊGdºFõžÉ™cÿЊØ#r6]×HN[FÃÌë"×{Lcšxܬƒ¤˜T)¾÷àÑÂÕhÝ+ ìþ¨b�ÿk2ëýIr¢a+^uKË›øGÎB¶ÔZ²Öè6eÇ—°Ò×eÜÙÒF•ƒ¢Ó€)T/7 |—NÒÅÿÁ@}§£ùC\›½�V(qð™Ÿõt~×3âšæJ44zˆ“oØ#Lü ^pñä¡à98‡Îª„‡—£pʳ4Ö¤A¨±ò´ú+c‡ÇôvÎNl7s vóüêp–ž5e½éMâ÷ {%—л󯉆ûºU¢½µ7?Û•Š21aŸ‡*Oç7ã›Iýe-öñx@}ÍæSV±Ág Ð{¤J…ÇhÔ{oœÖu¤FuÔ³uýE÷¦M°ôT&[ÏûBeSàÕƒOBt÷�¢id,ÌùN*m?A§K \çÄÂå'içó¼7ó´ï�ðĸQp„`–VäZ—Lø3||žöäFvÂîS.p>ÖëjƉ+?‚vyˆt]öW r{~®î¼DÓƒ_´Ó¬éÇȶé/dš¤ÂGsSaÊØ¥tq'žÛx’>K%×¾Í0&(¿¸ÊàÕ>cPÆâ!Äv™Àúë_)µÇIÖo‘Ju³M1ö�%Zo!xˆ Æ7sC ”}–o—~ýçiOBÔ¹'(rÀ¾Kà™²C¼Ü®BÅ+ŸÃ1ý,Q¨šNÕ D“ýQYÇbÏQJ¶7“v>Ž{w«z¬‚È[OIèv—Òv�A¹àtšõ‡4nFƒ]H6ÙoðOøåðäöWt¼G3 H¼£‹üèËu†{)Bÿ~nœ\QB‡Û¡yÒ^¸±G¥ŸØa˜~V,t5tÑ´§§ØqD:)¿þät štB9úÍêJÝEti![׈IÊ~¸Ѝ÷È],Ÿ�E¦»¥Ö5jì7Ü—¿<9*z|û"*,O$˜Ïc–%òáöÇÐÃYÍ–îeSƒŸ’w�×¥þËo°ÜñI0}’/‡%Yq6@¿Ç+ÅÓ e0"Û–�/Çqo~’dñ^®ô«%¹á†ÍVêÝ¥ŽŸÏ÷¡þ]úètF—·|«{ª`ݨ't¦Â‡õ‹/bWMŠKòäßÞ+éTàJqLϽ4òt ÐOsÒê‹'—`Óm'ñž·ˆvϱöe¾¸õÁQ8³>‡bþ+„ÖïI¾ø!}XåŽmCÂiuØFѪ\¦õ4G…¶dñÔô@¼]'ŽÂu;p¸z ·Ë¤Nù­ls=r- ărBßñc8ä«û£ »…„×%|qÄÛÏÌøØ¤Ù|²—**õúJÒñÏê½ÐQÐ%ZØj‘¦–3^ Ê„�ûoÒ¸ð`T�ú‘ÛBñ¹/‚kóZŒ*ØA^¦+Q�TàòéÇ¢üAS6&ËÓ[CÉkª_ÔèÉÒ©š817Œäñ¡ëuBJ^ &Lœ„yÛ<%9ÏïôÄ›î`åÎ6hùV‹Ý'ž¤ëcøçû‹ð×ä0?´Æó×`ÿ™,xR¶”ÿ{ƒ¿6턇ӕ±Û·kŽϾe­çÛÉÀ¹;_ÛtÖ{ó�˜øõµ/>o_ŒÏVŒ'6½ñߪÀ÷‘2ÚÜTÁ8+=z�¼7x§ öOhÇUÖýçgk/®“|<ÿK�Ù>´ 7~/ƒ#. U+Î :ȸ¬ùðSxºHW¸ÿ'-ž[!¹¨ÚÄÝŽõ€-ú2<~E&<|w 4ô­éî Oð¿SÜÓµV�Æ~cí!þ»ŽÐûàHΘÍås"q¾k,úw‰Á®»a“£>/œwH¬ÜcÄúK2ÀÜô>5ÕÁ�ê<ö‰\�Æ£.d 1Gp�í^ó£_:ó¼o›Á{Bon=ܯ]H„Çfñߟ54×á0\Vø*94y·äÞ?ŸŸ*Žà°ë«!If¡(±¹³*Ç�ÍCÁôy'„uI�DZ+hj¬£ à ±Õ„`êÔ@~`»Jøèí�ïþ‹¥°]"©]+�gõ‚Ñtm6J½ÏÆÐxmöˆ›Ï~…gý’xGt­2?\5‘Ì×8í?*ìùvTŒ7Æ¡�cñÛ�}´Õ5†‹Þ 7~ÖÀ‹ÿt!±M“f+ØpçóHømdŽ:�RñÖÜT³m£9Ï%¢¿�ŸÒqÖþB<þâ-�þ†ÖׇZ·«tõÒ;j?ˆ³ˆë�¿RdÃÈÄïø#¸H|ßí;Ìî,ëW8fþ(þ¼4�ävkòðâhÖÔê9ô•ÏîÃ^Ó{òƒ�ë4mÝ$¢›Åã6ˆvÇ”YÎè§ ãŸC é0h ”²âÎ’мÔ�{ž¢ÄÞ£$¦ƒñT˜?,¾M¢rj<\ßo:2î’bžÅ ãQxLKÜyò®E þ¼/î­Î_îz(äÕXâ뎭¸"°Û†jÖ/K_�ò+Á¨ùƒPâ* ·þ5È¡¶ð°¡S“£úÎExT;Šbôî`Q—œ‘=sÌ•3{ų¥/„¢‹%8ͧ–dW<Vø¶Àdã›±2ÁMÈ•{*4+–ðÔöõð;ËÖìýEB]1uN‹Ò!XhDzC²_ ºY¸bКNˆÖ}$Øß©àUÒt6¬NØü\O÷^$ž|¤ƒVoê@?Û�Ÿ©%Q¿±n¾ ž{+؈ZF–�ŒK0y1Ç^2'áB×^ÔzÕ•aåÜnwI˜¯®vtt,¸>˜’,‡âÝ{fl{BJr9Ç„[½ý¹ínjk6-.-Wõg•çßh�ûžýÝŸ§-‚h•|jµÑ”–<éJÃjèÍÚA4v­!\±;À#[dqÓ¨éY©‰¾ÒöLN‚Ò+<õe/xòn#»ùÝ£Û—frÃìa’ÀJ`ÔYWavަî!Êd5§­32sáwƒ€C:Ö€û%mn{a�_æî«ë+�‡Û‹S-˸rV:«_@RmÎ6ëö ß*eù…Z™˜hóµ"ìõ¯“ÜœJP1깠ݧ�‡÷BóPԻ⟦Æa™«Õ=ð”^!Ì0v!óŠ Üq[×…fйº"áïg3œŸ€\-yw“ÎðÙS—Vî®#–ж«ö±¦µf]•íGøÐ=Õ¬¶a©èÔ-r§ƒôhO~z=_Äg¶T¬¤K«Þæ® lr(…$:ðçr'ž3þ'ÉÄD�vÜ$‰ò±pnÞƒL¨"|ßýäêèb»;tL¾ ]O~Ã*K –^—ççí=ùг0¸·@®¾dÈbì3ŸþÜ\—«aMîøâÖàÓ {4®?¶¢ÕÚ9l’0,.õÆŒRä2›haÿý\¡Ûðî8,Û�eõÆ '=»£ìkE­¶BVj¶å1Žõ|ú‘´ß¥�/Ê ð?O4ø¤�¯ûƒ^Ê9aZW½pl§�ì[‚ºòÆBˆÈ逭ªF<-¯ Cl&M“|ºx9ƒßÉ]ãÆ­“Á{eÛ�ýêÜsÓ.úXÞ_ðxg,9z‰´"Û¡qïSágölܰ=NÏNAݲqügí~¸º{'Ån‘Ç�6k…Xw²\ñðÿ¿m ©¿uÐ9~~Ó“ÇÒÅÏk[„X³5tÑ$[(•”â˜MEïÓiP:qMºlgž–Ý¿]oG¢Ie!Ô=?A‘jàÅ®¼®ý&©b*­µÙŽÓˆ¨ú—3µZ†“öıϫ*R©I#ªvˆKß«qô­8 –½� ÉÀ�#Åç:"|w—Ò%7%üïmO›·”ûp¨BèlÒÅ8�yâëXÖÙL3¦>W„²Ò�rülB³'tÂ�lY:`ÿ—÷„Ú¨NÁh~ ½ÙÛ·% ¿ 2¸pË\._µœƒÁÌ8˜ëlû �U-ÙCf1f�UÃêѼ.´/ÝîhÁ‡mM´ƒÑÐøöÀÆž¼mä ž¢Q/ui©ÍD¡§¼oÜÌÁó/‰�+�ðòüeú³Ø�|4û ÆÙ*5tWø%.»ò�ª$"åö å{{ èÞÕ6éÌ¢nÜø.ߟc·^8Èï'¹eÚˆ£«Œ°Um«³SòkŠ)2#Ó£oÅùêñTøî»;_´¯Ý{—HHùÓoñIã{É'“ÉøLèUþ¦Ò_•ZPR™ Å¥‚ñÝ<á“Ö.¼,×B‹<¯±©¬MëçüD¿FE„n½Ð"ï ŒÓ8CoÓZÄé8\zÁÝ‚ÆÏ‰ãÒ„áÛ³‰¸òÛ-0O}L‡lE[Û�ôpÊ"Ž4ÒDwSÌ5HÄ„ßî 2{.¬ð¿ #bOb\�Rدú™ú¼¾.´jÇà/ŒÄ“Æ=xÃÙxvü¯VxµÊ�—¨òè’ñT©$ÁÞ^'…5ŸN‘ôi ì-ÑY‘'=· aZº9^•ÙOºIv3úÄGÁØÅM�%|qÉ)úÙ¸�Ã*]yLÁ Áü°�ú«‚Û¾ ãC?Ìéô„=`PèÂ&�ÏRw­—”?¿�Æ “pqW>M^.ôÞÔ‹Ÿ¹'ÆÏO Õôiü)¢6ÝRÅܵ3X‘Î_/-£Éë÷óV³ ¢™o!+_¶æ~%À~kN‰††ñ8³>�ß_ÏÀºn�©"`3�Y–JFÁY ©ïÞWÿŠ�)1lþØwo�λvš‚xVc7m¡Š‚B©ìI „ÒUB/ cÌé’ç›Z}Äå;‡ñÔý-03lï>ñ [ŽWŠ:¹*$uhDóâpTöh¢FŽÁó»Þ²?x Ór-XgÑHl9Arvn“xy}»Í?!lsò�YK;©öKmŒ’£ôïÌåF¡Iy¶QMbóÁ~<@6‚ž{K炚iÉîhvöÑæ?ëeÑE]ÁÅyósú«É#–ûcG%Àá–Tš"¼ªKV ♥¤ªØD²§±òãX_Ñ‚Æ RÞÝ×�zµZóÅ�®è4Ì‘†Þ†µöuøNA–õNL¡“›ÞÒÕ¸g´aÈQîL—c:®�1sñcäušt3Crd‘!9- Æ“éï rƒö 0Ã’ö tàÝo� 6pô+x^®&oµY‰fêjKàþ‹`~o·]Ì)€8bk¡Ïšnœq,Kè­ÝÀZ‡ ‡¶Wmâl¾ÐÁ¦\ɳCðƒ©7¹}@\Ÿ¡Ê+»_$ùî¼u¤:~p½X÷;ßÑÂÅ’L�ß ù=/‘rúqL^rg&o‡+Ã&Ë!ô6"عxyéöLÁ)êÎ0ÄÒ Bߘ`öÝŸâÂ�)ü6º^?סð©?…C;nÁíû=vŽïy�~O= ¾/:$�²Å««†ƒŒÆn(YÞÉIMñœÆPìÖ¬Ìÿ8ñkt3�óS”X#Ú¿äõžtÅ6‚Z7€yVn\PÓIž§òhÕÚ4dæU´}&a‡ é�n(¥î쇫u¼á~É(›%ÏccS rì|þ=Ú “^TÒ�±ÉbQ˜¤Gìñ€íTÚ8T ?ǽ•–²Fû�:{Äaíá ÐöÑ ÜÝâ ïâÑÃò<Ë> o# Ï¬F©ã15±ª3'ǸÒ#­láÞ¶X1â´OZ#<‰~®‘/){ÅqqÜ¢¹tvÃꗠʆî¬ùÒ‘²VŒ!�’]ø+6R˜•Û!ùÖz‚‚ j„֑øx‘Àé^Š7â\Qg²&u¾L’îW"cAýÕFó_žwäÙÖF«Å3`Û—hN•SçSJØ ¼~n›�õ/�µ¿o�ÔØïƒÕmÓ°±R“Öûü|Ó¢èâŸÿ°hÝ48›e,Ù0u)¬ U«ï±ö DNò…¨45ñšÞYHšê 6íÇ5mØnéLÜUÝGзz/6’ðÛ½#idêfë7qPæOÚs<ìNc×ч$9cËá�ê'Ñ™†aõV×Ã~Þ›p‹²*ý¾VÒׯ`ô‡Þ¶Iç/³ÄÞ¿½¡y½Á?�Í.:7Q­|$6¬Ò­_b–Eýoáúàz[šÍå-tçófŽLU'ýAس»öQÏòó讳N\;ø8±â4Ô¹§*¾T³,ºÃ—¸ \uÈ ‡+Èó†%Ì5ÕãøÙ y> û›æ'ìG½º}V•¾ŸRåÇÁOL²x…ÅÈò~N*<Ñý6÷××ùMBù•øXn=Ý�Ô,0x,Zä/Ãò±ýáªc$_m¢~ñù°ý«;Üêù\>Á­šG`VŠ¿ðcB¯¾× ݳ‹²Ô‰Žs9©Ì‡�Væàƒæhê3)ᘠn¤Ig�Zaöš»tóBmðªU~K`|eëÖƒ¡ß°xãƒ7úï§Þ*‰Xe8õx.\,Qýçr� óÏÜ´% åL¹Í};ßOÄÜ)ž˜Ü¶R–^†-\)9ç_‚m’J`++^Û¿T¼ŸH[+üœ?=z!F·eÓì¹²¸ûî3�íe k,n‹ék"Ð|6Dó‚ù Ж¶hÝþa(¾d;ê¶ý$13ãˆãû`B³«Õ/Añ�h¼ñ¬ð¶÷uÆ®d,ÖuDåì§‚>ÔBŠ‘2«>²ç½Þ‹pjžÓ;È•+miVc"ö’Óæw *(õ}<}‹¹IÔ‘ÌÕvºm²žj ½ßø9þ"Ìï3‹fHØçß9mäƒÅ5Ž8"ªŠ†fžÂ+–�(YÍ…Gv‘¦4”uÈa�~>ÜMªUÿ¨À8¾Jk?“Á»xè¶98ª¡×ŒhÈ“ÀsmŽð®A;¹¾ü8> vÚil,zŠñ+°ŸM*ÙÑ֊נãX,»’#þƒ9GaSÚ:j.7æÖ=õpì½&öNp¢"CçÚ%ÀŽ3Öèe�‡W,ÂY4êÁîZã¡iÞx!nLÚV2µ<É¡þb8Ø´¡‰ê†?¤5lW¢tyuE¬ÏuäJ#&.Òç¡WõÑ÷~›8ý‹³P�}_Êãµo2î5š~É¢¾j.Ø}x?LëÕQCFÓE�we¤WªúÏ%ú K}Ãí<õ¤Š°ÿÆeèáKs¾‰_q|Ýë~=^vˆ‘fò8åæ ’ƒùXð;6ˆsðS9¢‰• 9¨Ð,FÞG4óqÃ1µ0u°÷ÚY(Æ/kÄ]å?žúWh|f"lX±šuÁH{¡bMƒå‰‡?!ÙØ¡Fsí3ø«Ægp˜iö^¤ážÅ|ÏdÌôRÃ’ePë‚:î·H¦ÍÁø+n%ÏúkÌ’I’Ùߎ“³÷{éÞ•îì¬ð†tµÿ1 Ÿi”¾,5™Æ*º»ðJ‡Œ‹ÉÀ™pë�<¯KúçþJ}9,r Wvÿ·W_…Å�ÐþFÒ»{·†LÕÏE×±´hØN;ûåÇð탺tØÀ‹ƒ‘`5I�Ïýè‰é_»ÈÈñä =Ü:*�‹Î¢Ð³k k÷qú9Ï ¾×$áœÑÎ0¨¯Â.  ï·žÎåvž¼Æ¬V,úäÀ¿RšàÚïͰ¤¿;Vüý,ºÙŠß{+²™ÑÁãùCÊ{烡¿å¹-ô#®¸�Œ �°Ó6œÿjâ‘eÖhpU]ê*ÑëÈs¡ù÷`<»©ˆ7õÚ‚nokœu{Ò·Ëì5ài½JäÙ‰SyQ?C4ˆÒd·ó)’ÐÚJZn>–'“à¹�?¥ïföÂËFüÛËšx6u?$ic.>¥ï@¾j:“þS–^RvCs‹d^b×)éÊJÄNÂbí§$X—:†Àp%oP¹êŠe½.AØ– Â+…L6–ù+V÷‹áÏžuÂåµ…<ܵ‚$W}yüŒg±ù8 6ê�Ì;ïÈoL3àK¿ j÷}.¹¯ÍŠaÓÉsb/¸ë‡»\ThíÆZá™Ñ0ôùôM2øüüò¶7E‹\¯(�cG'cãé8Sv†ØƒÕ�>4+s hÉ©âÎk@£?{aðuL)¬äÛ ëa1©LŸYÊxr@.½;y tê­Á$©Ö¨÷Ä/#÷Kb�ÎR‹‘¡89'ž†Õ×¢¼ÊhðXA4°èœnÕ¥©sša6>dñý áfÜhN �¤†ÑqQ�Ó�€‘RéŠ_›yNZÝ´šÌÃŒ’ùd³Ë~k³¤�|£š¨Çì.ÁþI0Õþ$êQ2VÌ0�Þ/™ÈÝ:îb‹–Tll±òÚŒ’"Ü»Ó6èp@ü¼çÔƒ_¶É¡Yk#_nÙŽB?Àº›z n�ƒ€B›R=~üY‚ÕãºafÏ4^]*qIMÇQq¥d¾o¤›7`zW*†.°fË yÞžl†C:JÑ%ù:÷›rÌiÌn‘'éX’ÑcO–¿S$®2(@�ƒoAì¾›­g³§_viÞDþf€yd+±‚!6†÷@õP/nñps¹26Œ»)ü•¤xY²É[hBY*mmðÅ l˜ Ìo»(ÿEïúkÍ~Ëc…u³òÀÁqŽ�QsÑ­#YZ;U4|ÙÀV±Û„/¿’ùyÃÁT¹'E^ŸÄ67þö•ŽämŸ J¾–˜?*YøçÈå÷ÅqDFV‰ˆ(M%V}žs̤¡¨Œ¢¬JCJ{'’e4ìŒ�‘Äs ê[Ò&í½´ÓüõûûþsïóÜó~¿^ÿܳ‡²E›M2X¯x†? ŽãóX*l´õ–Úlæâ¼–·Ôû'qÓ #<Âb—ha’ ê)¸â£ÂÓpÐ"‰*â̸u`=õ1̦ñ‰ÿrÚLàijP+D‹Œ‰h^'Îþ;L¬ÙxÝ@ü1!¼*”ï}5À ;yÜš ¡9fn]äí@¼á]3¿Ž¤l•¶9tt¥Äo¨Çf®Žh°u,á‡d:í)Ìü¬Œ—Ãê.®½{Š”9={,�W„¯TŠgB› ×Ÿ?d>ó2\ú$À‘{òÜØιÃTPÑ"A”®~ ª#Žsï¾°ø© ÊÌ¿F ,hqŽ#:T•’Õƒ#‚‘‚#æ½ Zk�øû,{Öù‚Nx(³Ñ+ŽÒóç$¸%üœ†o¿yñÇ!OÁ¬õ'„”‡àÌ)µ¤Ð <9nÀ{!Ž< á±8§,÷Š­EyØ»p¼ÑAÛM©&6”äV*q—¹n_?m¶,;„½Ì|¨GÏÁxlÙþ™Ên8â{3Y_?Å›Àz9ÿ¢Ñ]yçLBÛ‹qP²«­7áÁ!öø^n.ˆsBטaÜêÔƒ�«a^¶„_ŒÆYv_ëΉªxÖíO«…�®øùŒ'wOl"#Ä-—ö㞬$ºknó²cð³ôœà,>Z¤†}spcw|üï9%yñI•nrùÇŒ—-ä!qÊD¼óºwŒà'É¥4OÞ�š÷šñQŸ"v=9— šÄ×L’ o!pYóT¼´â¡‘·í­ Éð†ÏÙôŸb_~1c±Ë”öõÈçž›�º½ù™ÎšnGŸþ„ü—[(©$¿/“CçŽC¢Ã¹}t-i>�×?J³Š#ÁP²“¢bpºm ÷½õvšã¨íÑðrE(dŽš/I;Z€mz xðo�Ò¡£¥Àð¼øeMàc }¸­üxß„ì»k¸u�<]e0j°§vW…3ÊäÙo�)fb}¬áBˆÒ7‚•3ŠyÃï[`ãkÈ!–;qKŠ”½(º�® m‹ëHÓÊ;Êóm¾0;¢½ÜØ;%•+sü9õ` wï=K{ ÝÙäá2t°Pá郥¬‹“¶p[uy,Åg«ò0Ôy1Úuî^ëÑúÒ_˜uåýÄ{1åz{p^D•x`‘uômFù‹ÚèóW/†Ž—:uª *À}/�¸Ýu–ÀË­Êœë{ïO§Ûå7iН:ŒsâœO¶¼ûºTÈaë :sg:'�ˆ€7Ÿrï¿A\ü_%Y­pŸ.ôdU eH/�#îÖÁÀuZµ.’—IÝͯk/nVÂ7Óù¬Ã˜Š:hÖëMMgÔú‘~™":ÿ· Ôùµq%ú»$Â(k5,9d�×>¾ÁÑÁ£PîìQ\b07V�·Žx>:E¯‰¨H¬s›,™ òÓ/J΄­¡ËÝJ¸Þ¿…æ4È 4RnÈ*nýò�?ë_Æ€ Ëq“ó+êοF.‹ûÚ¥p°¥{–¼„Μ溿«5ù‹ý žêÉk¬ØtÂMÈ›³å W ¦Ï’±ºU �ßÙG³f?£'­oÉ`º1ÝÉ=IÞCô /~Ô’·…h7æ « H¦I>u÷.©»Ò éXÅ»Øþgþ€q´´=æ_—çÒÙª;賦Õä^Sì·�⌙ñ¨´k>³y’Õ3DÕÂjâË1°lf†5s,<ÜdMúO´xý9+t‘C]iæÜsÜPñMÆn¶Hƒ÷¯{Á³Koávl«ÄÂò5HßùC“=¾î)Ь創ֳX5ª…ûëC˜}(ólivi¢Û4àÆ%c¶>$”ÙôÒjr0|[·;d1ÿgޝÂn?yèSf/öºkÎÒï¯ WkµÓ ÒÞ_Ž\*ýºÖÜAÿ%É”:ÙžT?­ÀiK‹¸ÿèNq³þvh”Ç·VSÁy šÌÒ®uÔ¯>TÌÚ£~ŠŠ=zz˜íÎÒFûP¸dy‹'ÜÜÏöC¦ðÉ{Å‚Á^s)ÛÿëIbìÉe°%Üp‹#|" Î)åH§¶O•Ì¡Ë)t2ÅÈfZ<2‡«—åQd8ê4tÁ“žÚõ±ƒFà¸(Kü^Ißu“àS�=ôĽD¶Û�Ë{ÌXp¦+ï£ÁÎДÔqÃíz=å2 ªÐ |~…».”¸q"oø¤ŒK>™“ÉŸe¿Ví‹øü«ñâÈKñéH•{ÛBno£Ø¦< š×ìa­[ò_?ïÍUâ^358ÐÙ ­’³>Zv��F¨òýAqÈ•Âñ¶ñœ©£‡ž“�Ðuó)ÉøÝ̽ýû㑟òèü§J| "©F.˜Ìg¯ïg­V?jú××ÞײGD<v>Åg27Ï„ÓQ¾’ïiÓ¨j¹ÞÜ“�oŒ‡ /LüÑ5}$.¸šBλáŽzÜ¿|‡»B_Óeð½µ¾¹; ¯Ä= =•*è‘rmë�R¬Y¸ˆ+2gácÅF8{Q~š7Áü› mÚp¼çœŒi�ßA;9�³À ¾� ºJ;(0L†û׫°B–=†}ÒÆÐðxò�rÁóCÄÒ‹|»r^Úm€;%Ki¢ã¿3¾Ì�BmëÐà÷|ï��¨ýÄ%îq¼ùi e¹Äñ›fÞ¾¡/÷v ®Õš”Ôh‹oi¨(F¬á·ÛÃI�D“’yU•W¦\Áõ7ŒØ"¸Œ\�ÒidU³Ønd(6oCã}EpbØox:l>ö>§Â·ö¢?kù¢îvzݲÿ @“ ÏEµ í�,­'‘¿T/€Í'¥AúÈ}Øá`ŒoüÎѸ€/Tùp-Oqr§pšÈg&,‚R¹©¬qå2ܱO G¸fòIãÿM¬ LƳ$>7mæxýÆ mAð{æP|ûÑ Ž›ÖA~N!x‰Q`t¸ úî`•ÿ’ø§Ïqªpé�á-‰”³[#¯|¤mçÌ0K7G¸lbMO÷‹â®¾Ý¡Ì_n'¢_ÊkúD2�{h™Þ,Üóößõƒ·M|g’'Û/ñÁ½'cï.;t ÿÆÒ¶1Ø=çi,äŸ+›AéØüúNظÜÐÚkBD. ÃìQÎø+é Ôýõâ¬_ª,¥ü�P8JΙÿµ‚š¥#Ùrì: „v LãO�ý!þpµ˜¾î/\«QÓ9‡É�£; ñ܃4§ë>Úê&ƒì˜“dx« Ô›�oçÁû.Øqê³xײ4Ù¯”º:ã‰ûÝfò�ÎqéÉ£‡úcÙÑmìâß�_„æg “ë†^�…Ë2œQ¶¡onFTxPñðl«JQ_+e6Ÿ€'ú·!íÛf±.¡�í˜ÊýÜù f4h6Vàž‹ÊTÝÎ\`×Mbñsö`|>à �'°ç6/|×û º¾PCµhØ%¿”ZD²ÝÍáÛYS|ÔºûõaÖxëW×¢©Ä3Û/ YiS¹GòPÞäZ.\Œþ‚){�ù¢£1WIñÂ?óÅŽTO¡[ºþ6�–-õƒ[OÏ þ›dþc,Kš�°õ ÿ6›€Y�(½ò‡}=�þÞÿmÞ†ó_…ðæUŽüâk¬Ð_ÿ8o Ž“\15j%¦c!ÖB~?r;o¿¹š½½Ê~å‰8b¬>¦_U´^>$B6ÔHþI¸ÞèŽ0÷ˆ^ðÏ¡†•™Øš™ƒC¬µP½5�ãä]ñ(FàÊŸQá+Wÿ{ƒ%ï¶çÎu^°eî>\ܯ“›nNÇð/Åô 7ž>οG,`â?ÆÜnÒÞ‹JavÑaøÜ4ÌÒ;.„>ÊAÞÒ¸%ZŽOÄ¥Ög¡df:O@rî®äí¸Œ‰nßóé†Õ1ùk5®ï±Æå7aÀÉ"~’›GÃÉyÖI•AŸ#¿Ÿxšëqg{ÇoZH%Û¾ÑÌTdÓ¨s�ï›ÂÝÏÜ¡kJ>õzÞD«[7³Ýì=h¥à¯qû��0nx<‡<žß®@�i°KgwËã¥á_¸_°Ïs_Îá qmÇD6oï‰M§Üi@q[V/‡‹¿'üË+c.ÒúÑ–§È`ïn8ÖŠ;›ù˨}¸·»‹oL¥'=Bmž'5 /œ9†›Þ/äÈiÇ`“ÆN¸y@›§O[Ì*Sþ›N ¯¿?ËàwMù–W°U·!öq*&oËdá´y~ÏcÓwÑìS±^ëjòÉU/¡±:†mœI±NC°Ýãmê4Cƒ¡>L­ÿî’Ë;aDe�€÷\ÚvÊ¢�ΘkÊ2ûvââ1ʬ óEXðX‘ß,kïÿÑ%�²Ñ¢ì* Ð0§¹þ¦ã'û¡ŒB·“ÉïP·ø+€d.=#…‰× †±·k:žOö{(j÷ƒ1›Ç‹ý}˜ý®URå±›|Xo8.?e‹uŸn‹öƒÂxëP;©sÎI�åõï yr£-ß«]C¥ÅÞ$5g %kg ŠÕŸè›W¥à4>šO[ŽÀÂ3!´iÓX¾ÚÛ“GŒW‰#–qž¾ÿyðúlêÉãúps¡ }|Ež^‡¹qâ-qÇ«Bºïº»t‡âŒW£y¿ýFŠ›Ñ)Œu !å©¶¸ú}rÑœ'Øn@³ž‚­Ò9¼Ršã\ÔQvÚ^Þwð­xcÂfZáU í}PNµX<}û¯Ð´6œËÆðų„†ìlq9K£[G‘éuC¶=Þ-©7Ì/6šóà¶í ûøü²üI½lèI~ç/N+úçþƒÍÈmt4ºx0 O9Cížh9ö5V àa»ñXu<øEõ§( ™·¯æ…ùµ‚FØñB@„°§¹Û>!/ùE4ÚØŸüWŸ…Mb ¥MM÷?+9ߣ…š&|’¼`RÏÓtØm$=ntç^›ƒ ¹®€¥ kæáGZ$Þ`�û•æóKëC° ]ƒ½rïAï·½ÐÊq)L¨«„£dI+Pµ×‡Ñ¥§‹„ˆ Q wƇÀ|/ËÉ<¤:³Ñ”vi O±7År—HþÞºu_›õ|d¹áûd 7†åòœ~ÃðØÖ5ô6S¥ …Ï9ËðŒT$Ù5¼šç�æ�NùBšÆaòžž~èVI4Û#ÐmÂZúë?n §ÊqsñÔF ¾õ{6¾*ØÇcÅÅÝZÔt¯ŠdÞÆò\3-~Òߎ� ìëO÷£�ºé|(uoªúìJ£ÚÆEØúõã°‡ú¸áR²>÷cÝŠ7•Ðc޾~ÞÂ1Ãázr%ŽùîÈËC¼QŒ0Å�á_Èù›oïzÁ£ã¸M î¶Õ�Eëäqá¼×pØz³¸øT ™ç›Šcäô9çáT>ö-Nþ¨[¼F•ž.H;Æ?Ä¥»Õ¡om=­e±µG4œˆð½$enYxœÎmÆ ‰…87Î�K÷õÀ$‡ƒ|ûFܰ¬~H÷ä}^Sà‚Þ!þ,¿‹æ³í¶pûýJ â¯;ey¦»ÏVÚkJ߃—VU Û1¸ÂM6ÝUÊ=ðÀzuܸHgœ%èÛÍçüã¿÷{èAÏp”LL€íµL×ÇϤϙ�~k Kœo‘Ã:)žæÄûÃ^ñFS†Fóƒö2qrY;Q<Õn*ì|%‡vÉjp¼œ"^¿¿êò娰{¶¤ìS4 Ÿ?�WûLÃeiF©XC6û °ð+t× ÁÚ¬½öx•Jq§ÒÎüP r߮њ«ËĭߌDÝ!ÿIöx•ƒæ�jò0ìmõ¬v^»Uæ»içü±¨Ð·–÷}^ öÿ_Æ#’²Ší¹ íÙ}˜‡[VAÊ‚$*Òɨûéë çozÁü«8JòÓIíYo¾ ³†ýó#ñpîLôY,Ïa_n€{Õ`<\ÑD§Œw‹ê×þÐÒd9~¶s ÝLÀkÂåø¦—ôeÍâu >ÒpÄÓçCã'Mÿ�/\~aC[ vI”÷dS§Ïlqè5aêŒ V¿Î?I%éÎÊóú#¼ÞSÌçï8 NÖÄᎺ|fx"dL?ÁÖÊçÄs­}¹§|&Öò ;U·Ù­$ãI¡ÇÑÝ´Û¬¯êH[í’Å천=^ Nm ¿Uå¤ð{5…M.£„áÎøCÞ ÔGawP!ܸgtNÀæå0¨Ô‡ë÷à¤ùÊ�˜X±™Ëo ¬êõŠTÝŠç7àùðá`p¿b ôë¼nf¿YÃÖëãBÃMXÖÿ�Þå95?¡$ý´àêøÏé%ÐÓ]åuç½Sábß^¸éàUñZü,^ý¾Œ-/¶£ý?•ðZÔXfì‡Ê%­\l„»›zó@·Á jÐbôê°­* R�ƒ?ú+Óf�•’ÞSz⼿¡âÑ?ƒZRÀ¾$Wþ9R·hÇJx÷K“âÒàì…ƒ’ø Å¢êküèAHmìl)Iò�>>¶Fµ~žÂ“º¿pp´)/·ë »ùp¶ÛŽëŠü (t&¼Òöãý¿œQáM*|ÜSf^Ö¼yÿF ΖZ/O‹kÃrÃ|î·ê �[(%# «F㜋5xÙ~7÷ÌÝ‹+ÛL1cv?XÍ÷hìóf0MØÉ�-ôï>Átð—¾=?¸W]¹É�áð%Û÷çȱ–pµÃNÀlo¸èÛ&†¯¯–T™¦ˆI®w¨]ù¨¸Ø6‚ÍŸœ‘<*þKš«v‰Ž^}à™_ mêw—ŠÇOa·bg(—«‘X [ÊãnÙòÌ›­ô!S{h}†ÒvÑóA(Õ )¦ØcÿT©C#¥0ÊHŽ›3(ËÏŠ‹'vâÑ«ípü[¼ž2 ur³™­|^Ý«‡±ÖU R, „yç÷Ò•®P!rw:¬qO¤Gã†ÓÂsãðËÛUôW]‰÷6ž¦ÕwܱV:”vád8ÿ÷Wi­·=²o3ÃÐk¼#~>-~ûAÌÍ�E&!œÔeˆ'æW@ï"@¼•Œ´³´gµ`5^Žªö Mð'$~jĽë¢ñ€üh¶Rß—ME Úi¤f±8XœŽ :µ· ðýÄl‰¢‹GÙÐwñøÁPŠê7—“ó†ð„Þò(9Ä#ÜFЄ©ŠlRbŠéÚv¼FAVlϺ­<…Ïš¿%•‹ï—ÃáÅ«(øb•Dó$ö»Ø›{+ß"¶ñäYÞrð³¯)Wž°C½9»¨Ty¾^ÙE-ƒ—Ñ•uý Â¼?§o×àeÞ_¡ü÷P~ÖùN~¿&ô׬õ¬‚sÖ|¼þЊY>¢œ,ž¡� ø’ÕQ0¬I—ü¼jÁG/àqW÷ÓJ�WÔ>šÞާu&Zš_ :Ìyj¨)KåðÜ-t–â¥}§ÁJ‰ ë&¡Ý´húnê�.¡éTD�!}ELhÞR›<~<ëï„^?B1¤|-–ˆ…Ï�·ãƒÁ¬ø@È`â¼þä?"™î Ü̉sgóÍÞÝ ?Î'›™ÓøÃ'ÑáL-„×�¢²QO`ï»sÂ+S4Ûe*ú»!¹÷`^W$᪭+È.ûÜhS Ä§óEçêp[=Z°© ¥—jS!ÝP^%òÈR_öþ6…>ÈÇêµÍ°º[†4Zúðí¯§Ä§yBQæJóÓáé—Þâ»÷š¸ÝºÆõøC…ê%P³±U6r nÙKoH˜¾]�dóÄG«¨ÈDçï¶ n¨›iT�e¥‡A¿)©S ç­‡“ɇÀåã~ré•J/­½x²­*íªÂQ Fp®$G÷ìÇvzì÷àˆpÂÙDب8ùßÚÉbw¸<±EZ?JÆ,¤yÏòE»�NÚP›ÝAydÜ?œn›òúG@¥2|åÿf]_ÍQÅK±z¥-‡Šo’  ó¨xÒ­ ›Ypå‚ÖE7@?)’}Þþ ­?Tx©Ð.Òø|7¬v€9J©�¹ù7´ž-‡×[ÝIÓü-ù)ókç]¨Ô)6O‰ Ó–Ú8éÈ­m+ƒ½x\5�Ï®Ï;÷í„Aó¤á‚¶DkW þ¶òhfÖ�æ,Ê¡ª %â%ÌÑŒ¦%5f«8ê ÅŠå½ÐAò„¶¯ sR‹¯�š“²Ö௩×á<ê­?öQ´Æ”®'âgØ� ƒWñó%>p)!WË€Dã2üÞp�J^&Ô=~mÏŠñÚàI8{9eGæS(Lš�œêÀ~ÿæ[ÿ'¢¾2êß %ò:ðíæ pY³œj¶î"=k^^,[W°KšŸåRH·výß"n~½ä«7QÿBuœóK¢‰!]¯è�ÂNÎ 0ÂU0%âÜÔ?»ü•xåêð,•nJŸ°^Ìòp€Q£I÷ˆ”hМ*Èô܇㷠íóì ašŸ˜7šdý�œ¦�‡ìyíTù!„;Ö¯¥«Ó9Èz&,U�O­èkÍ(xQ¸‹ç �i]¢½ë™Iw§—Âܰ0Ü·#K\±ê7¶a-¹¢~dûmTÄ�?j¼±$rOLøÕħËöƒméipW[ƒÎîaØTkxÅýŽ(à¸[2¼Jc'Nï´À»’»¤º,„Võb—1!üɾ|t…’ˆŒ A=°�j9Åð‹I¸YumpA?&ÊbŸÊd*VSo¹TAv¬%yœž‰ÞR>h>ø78Æ €Ýi¹´p�/ÏÿS0úfÁÞNЬÁž|åU4…_Ñ”&MæÓyshÎm9 î,žhÓ�Gy¯§£‹ºî¼å©OÃûßäËÆÂÕ?ŸÁkѸç£õsÞ‘Z¼�ö*¤½³­ðþ ]Þ}«l=eEuù嬮ò_­�ZªÄðX Ú}›Kù§wÒ½óEô¨1–çÄ‹Îáï@f[�.ßxDš¯MÀ…/yüº“T7ê™-ð¢Û2k+VõÁ›·0yÇ(qŒÊbnŸ”)û§¢¥vTº¦ãšq�Trü7Ô¾ÏÏ¿dÁ©ó›i½cU¾Ê›zmÅÖ©ìõp0ÉNºæ®A#Óráå]ÔnŒQa6:�¸Ó‰ÏMÖàÈ‹Š4ý˜¡øàôdT‡CkîtJÕ7´ ?²6 »š5ð‡ð€^Xù� ê}… ¾†²ç™¡Ð'S÷9ËbÅÏfê›&ò“7oèÎÒvœlÉË\õpvçPºÿ£öº!…ÙÙå\ÓåL™‚"%ýP—€ËÙÛIÍõ�Òû˜X�.sb7—{PýÒQ<28CtüRFsc˜Ü�‡Óõû{AEÆæÖ/ã>¿•¬K.]ƒ±Ʊ×.ÉSdóKÆèÛg$¨4 WÚJüÜ?u-Ç”öÙè7Rboå⻿™äëΓ-Çóª} è÷á&œQþN1/]áæÍAX•»ž¿ÜêGêï‚§Þß±IËŠ§›ëÒ>·b¡—Ö5a°|xˆL)mƒ8Ðq&ÚÏ©§–qÉ”·O²ÔM�+RÃèŽÛl®ù ËÚ­Ú,Q©¤Æ¤Vœ¼÷‘P¾a½äM“ °nÈ:Þ­h‰›<èñ€3´ºf-\™¬Ç/ZhȹLÈìZ-.ë_1Z8‡éã¶a]ïáœ4í%¨�Û+4k„cŒ¡¾å“¨í•_·ì�…â#J²È¤YYH>çÇý=#5™,óß\öñ $AÑÇ}»H‡ÖM¢ myÞ¾÷ü÷_(=Ü:ƒ›gìüG��[…`Ü‹³ ·²†öß�A£­ Ñ57 êož½ãïS*¾†Zëº{A{Øhñå™þè�C§¢j!xÂPv> „]Ni¬S$6L*kmqÛ´~¼5}6«¶ÒìÆá¿ü>X¤jÁ–oà‚æR9�¶ÌxEÉÚZ�yX8Zz´"›hé²Á8àÈ,ô mƒáÏâŸÐqü¹»ú:„T?u¡Éè%8G]—\é+‹eiÐZÇQ~«°\Ê.÷áòûS 4ÑÇîÙ-^ ä-í…o†kpƒëx¹mÙF«�ªÕÊàeÆzvŒ¯6OòÅÇNδ²G¯­µà²^ƒpÜÖXP‹qÇ·AZŒ^¶Ë"Úâx÷ÉX�6§•¾7Ž©Ä9I©û¹1 É“ñÌ¢}�{Ñ>Œý7Ÿcªéâ“\ò-êÉ·žîÄÒ¶ƒl“hŒbË!lÑ3¦‹¡ýyŽn1þË·G4Ò܉­TöÔ=åÚ¨@^C·ØÂÀó­b×¼!øpZ6…/ŠÄ©|Áoƒ*oþ©.‚ Q¿î$Æüså%1kÑÆáqV6Í}ÞB‰s·â»Y0üÞظg4³*‡ |ðjçOˆ©€2 ýÐ:ºÂjYœãzeV ܈qÁAøçÙêÛ¹Ü7bNsO>~àuUç�/D2ßÈz¸bË4_.µû]÷Ðv ùøVâF—úx]Âïì'“ÂwC´o5Äãß‚ñÁ2MV1Mç‹ç`¨þ¨k9÷¿ïá·�ðíÀp¹›,ÁS½:èšÊi÷ª’ŸTÇ„ëqtQå1)4÷¾D°ËÙC4vËT^ÝáË‹K;ƒY×Áõv8¨•qÑö™xåÂV^Ñל-m}qÒ P4ñ/&Ù™ûy½Y%õ¿qNùÖ‡54.1Ä3 üîl^¯TN+ò—�ô¯ ܦw�c7¾Ÿøõñ£º{..8on*O-XŠzïBg ”Þ—Ãúا°üÊrÈúl‹2:W%þ%‚Íï�äsu´°¢3Yú¡Öv{0õ_; …Z<«Â}×mã­ù7Á~úbÞ½Hãv¿«nÔì`Ê’Ü®;ß8´H*+åhwø1‰¥ýAìS£g ]p÷Ž�BqßYø}èq¡Eù1R½ +®N¥ãIؼ1†¶íRÇWã�/ÏóÇZ½Çüêf0Q´|¡‹·”Kiï!9ÔYµíOÔJ»¥ÓÇUÉ7÷5-~z€ms¥øºÅHÚ–‚·“@˜ÖqAâ~PèÕs5ŽYc ùÍúØtm’dæ± £gÈκōШDÎQ_ñˆð¶fuñ$Zï¤FûJññ J’<Ÿž¸õ˜4•¸?‘˜|š}Zçs—¬8qߨ|±,Σ$𔾭ÂÀžCñ?ûNÑ3½÷öaáü,KÖwüçü'°Á¯� QsÞr0IÂ:Žƒ xæ@´™šM�vâÞ…gùyƒ-ÚK'@žÌ ÑÇ*OOÛ…o|'‘ö‡IXÊ=`ˆª4êü5ᥓã0_xEñÁ�ŒSãÀ pfÑüÛåD ÊpßðP]ðŸ É“9šü$:ž{ûäð…w=qi–'¶ÝRBÓþfâAc7ÌÒ}N]K‚ØÛà ]½ÄæG¾€d³éD�Ú ]²„ôO~ÎÆo.W„£^‰P8Ñ‹Ro̓æuíbͬ±Xj0¾NJÑ�¿¬�e·™nƒ]SðÀÓ«à8«DpUÄŇ�ÀNYÏ�ûA—?]¦3«Ü¹JÉ�~ÑâO‚ꆻ‚û¤óÄ!q˜fš 6Ö?�ÝÅ~xèÑ^œøg#ä†4H”~׃Ê×ÒºS{FHŒ·”‘Æýp‘f>‘l€f1,="˜àÌRô9ÐIÒMÚØÙ©‹AzÒ¢Ìx7þr3®¥¥p·™bQø ^ú%\fòì@+Ê A¨7ɤéïàÁa5ºpK[�>:RS—4×ÌíÁÎj¶BL~?¶RÒcdwq5Ü”½DjÃÒ…7«óg·Åôz}~Mh—øó òÌ›Þ-qBwœ„ÛYÇhÙéxz¥ ÂŒ23Þ�õ‚†ÀØ}vöÙµ&~Çh�ìèQðßî�вü]³üDÃeÛ%s¿ ¤6²NÌ*™ÕšÆ�°ç¹åñ½m½pÄ’;pçÅHñ¿)¬h.®óUæ Êüاh(6‰ïüWñ£‘;éÆüùµgØ?—:ÁÁ³h×-VÞÝN¿Ê§r¦›¡0&ßd;¾n> Y’EðæêWЊɧë\#tüËR¡ZR&_ïúIЕÒû«ÉaÞØp:šKo{>óM;ð1¥�Ú„,®ŠƒŽäPj`_aNC<ïœ{VÐÁée©p6¤Ö››ãzÓ$aŽÁ-ºr# ÖjáâBYöû5†¿¥§ƒÎÞå´âg ãP]xVýïv‘纻äýzúv¨Rë½2. ‹Ç›¿ˆÇMZaòÈ¢ª”ÇÒp¨£:/VߎC?FqȹaÂçƒÞ¤á?bì38v€Œõ¹ëSðù— ²½WÛ ôùI¬+™~èA9 )Æè6»B%}Sÿª¤kIáòer‰YS÷sù>¾3ö‡^°Å@›Zú¶ºúÆËc€S ¨º­ŽQʵMâ9çé`¼8öO­ès}1¸vÏÁ›ÁŠ,aÈS=òÌØþž-íRZPz`_:KŸœ¦ñkNÖHÁŒ™UøVÚµ_Ñ–Ð�Øæý;H¹f‡ª÷Mp–­UÝŠ[71ûÉRV_ý…,3•H-v Nšô¥ä³µ“é@eí͸—™&Aó¶2F*Í¥Ýö'AY±O) Ÿ¡ #žâ;“L}uy&ÅÁË;½Èt«ü¿ÜÿJcë{`f×#�MÇéÍò¤>¼ž‡(W‹Ê#˜¾î£ßA]0õ} É8B V5hÿð/4o|)´ÏÆ$É0]Ú d Íùø©R0º²BÔ;çM³OOÄmËoÓ¶}[ó‡Ö7tˆ¦á³q°êsš › Î®÷@� ¾o܇šzá«Iô¼5Úœ̤ê)p—<uµŽ—¤pÈ£ðÚ,Éò®g,U«ÐÚ»V´úoªðë‘üÝú)ÑôìÃ_°Ú½Œ]ôc„QWUyÔ²ÝP¿Ë azc 7ÖÊ¡¦ç®r-ƒ?“üñCR<º|�‚‡jšhÅ äo[*¬Ó»lzb·ó^œkÞß|.<³ìÍ:å±th¨tYÈBúºu)ÑIpú¥VV܃ Y–t^笨¶?…÷†öä¸è}Ð3~ì?^žŒ#œW°çÁïâÒS†\2Y–_Žίãõ©q¤h:~81†÷LZÎ×=†r¯^>ôüÜQÜ顈ª;3XwÊTþþ=µ_^4+Ö =…*Øï7™3¬z³ÜÁ¥¸Éã:ßÝâNûÐ<>T¦ÉòÅ?ZøzB6Ï_÷,´¥„¸q&øþ|ÌŽÕ€¹÷“ÿú:Ñûô[¶rL¤[åF´¾1w¬‹.ÌZÁa‡hÔû‡˜p²:|<-®‘G›Êh4·‰Äˆ2#0m/ÑA‰‡RÚèŠc£�¼°S„ÕõïiPŸC�¥ãÈò²!L»”LS5ðíã3pU»„WÉà§þ(÷¯‹2&¼€·cåqGÓ2xÊü‡ýÐ2,•ûå܃Õó)â|4ìÞþ”c‡qbMnnY7äò0®5RágÑýQíG þ¶<‚æOóå•·Ä÷#DªøY OˆÃWÿË*yš·à.UU&ã9×—uÎ}$ìzn/>@í7?‰û=¤Ñ-N�×2™�hÖ`Aà-ßû�¸îŠîû=—‹Ã­póâPjI/ñû5ˆ w¢AªY|¦ùÕô Á…É0$Pž®¿PÃì2B™Âwœz úlHb�÷Ò¸Ys3÷9r¦öמFªÞ6˜/<Ü.�™†±U£hþä2èß܈s6Ÿ‡=˜!=¦ áCòà¡ô1Wc_êÞ ½Ú8ds*ÿÊ3æÍUNè ü†–¾xNNZ+ÅO‚8¿}ÆmCx'–SÏ �áú ¼ûw »Ÿ,þš‡Ñ´ÓOéçÜwôgÓ ÎîÅoƒ³©“ÃXÉW]l¨inþPùJƒö~…aQ Ü[3Š}¢€÷{î¥w�„y*¢]ãW*]NN×§¢êòs‚paVy¼í7?‡ý tïÔg°]È¢BŸíhÜû–pjÿ_±÷ %^f ;ïG1�)9= §¿‘oâYš¢w&Å#�Ï5à ö ¡kŽp@õ3¹X¾ƒÇÓ„EÒ4ɽULpRâ3B¼Ö b�¶w<"È‚]¦Yw‡â­CøÚÅêø©À[a1»°õE|P ÙÕL…ì—QÎ[UN‘ÊŽì™7‹ã‹ìqGÚc±zZ86Í*!Z¬�/Föű›†QÓ½lÊÑ¡aý À½ÛWmY!zZþÛcÑ0Ñ*R¬Ê‹«®ÚbÄ3'ÖO5ÆÙ½âÑ:¿Tøj"§H�¿ì@§Úþ¿…¥-䨿e&.¸�ÛhÞâi¼­d1¼9ÊS 3hêð'¤9WÔNù`R¶jes¿‰£PöóO‰kÁ:öí5‘WŒËo8Œ`E‹£¨¶é5ݘ0NY§»¨3X—Ïl©Ä†5R¼u¯3«™ðŠ1Cx:)ŠÊ3ˆª7ræÅ¥œ­:›…/ã`æÀ8Èé;J¼7A†>4À<8 ò;«)÷˜§°ñµþ÷(v¿2#çÂ0Z¢˜ÄŠovÓ÷—·¡TzÝ<÷.f8luC|~«ÚYïC™ Jxh©/ÈØ@ʼ´ñ?-éy%Ãnš€mòXîi<�¯dÝ£ûé™ÂØÉy”·¸–«Æ 2ëžÒ×þCïrV¬âD×…ì°æ>äuï„üÑ�‚j¢,%8Mǧ5¨—Îvzé_+Ž×ËÁîM¯Ý_$¶w¸)eƒéƒxz:g _|7ˆ§K7⾆ìcºÿœˆCûÛŠ,Ïs’äÙCËœÝ� Ù°ßv}¶�Ä<7vh»\{ಆaøkPOl¸ŸÇí£2qÙÆ»BÀ¿ ÑWk jzàke ;¯IÁ±’¹Þ¶Ü¸¿šž“JWí:¿ Tãêxfðóáú˜Q×ëýßQå€hn�ų þÌoWð…1SH;d'�ÈÈÅÈÿ¹{‡FÅãâ^oHÊ9�–z±t�Ÿ(3õí+gý¾~6?m>OK¿ ¨üYÎ:`ƒ)í)©ç?‹†ÕêÏé»óÒÑyïqØ]´�û#×áÁ0ßY%hÏ4ãw×~�M˜ xG×âÐû¿é]K:\^r¬üŒqâÈÑšÓ5�½A�Žžj#CYV1Enl ‡»�A‹KoÞ´%v� ê—}ñü�ºk‡ÇàÔÃ)BO]R,ÿAáYmÔdu"�h£ûì)p­:–ÒkjéSÁT-ºNMY¶¼³B".^ÑDC}å¹ñÍTTW,ƒ~Ïí0îØ8Ò¾ß%hpÚ¼ÖSÔ$†9‹J¹4=±V}®-o™ìA‡‹�|¤’+Ûê—\>ú%ŽjÙ¿ß-Å#î}qÿÓQ|Üa­ž>7Ù�Äà‹ùTq4RÌY—‹� ø£Š,Ÿ™>å…=œÒµ¹Ðé€?gXÚ±´�¦è® t‹\%&Ü5å'A�\}ß��/qÊ C~°Ê]T-è 7F<çiLƼrÜV(�G>Þ¢ˆsàulDÂTÚ†+å¢ùiàqן"döÀûS@3Þ‹�¿æu»ˆm~l¹ ‚5Üú c@9o:ˆ³qVž…/+�6þë®™“²Å¸/R0 W¡¼6²�æÝ‡okšáçL \­3oèÄ⨴v°\h†zšø¸E‹^lT†D n*¤k åiÊmÇÚg6¾\•ÿ�>´ˆŠ…u?.ëá÷};ÙÁ&ƒ~lLt· Ó/ƒw‚Þ÷W|g"š'Z±ý³±œ(SG<à‹Ðxv8Ÿ·öÀÄ]Šl];KRy_‡ã2_MÜØ©H ¿¬æ¯18Ñy5L{Ü «òK¡¼°C¦í2Åÿ®¦AÄíÍ’µ�Q4`q MF Ë{ü3½E<ñ=¶î�æH¼t·‰o�<½—õg“çâÝqêœØJ6NãáA‰ˆ{êF‹ßG ›gÆb@ª¦EŸ£A®'(ù«Žѧ÷%µt¨þê¤ÀŠ=Ùä“:ª_ÚC§hqSÓXuptfV£Õõ%pê¿áon ’ýaœW³ŠUyÿ›G²£Áù@<êU�'¹å¸gr=9¯HÞ÷ ·wÁG×,z:Ì žhÚóЦ 4 xB‡BµxØQiö1 ­§<`�³×¡öÃÊ]cXu¿,¯ú›Jý£ú ÖÆ/”ùø0�[;Ÿ?-Èçéó:©d|$‘ª]¼!çù žÊ‰ì7w/jÔ�ä®ö̳0’úéKxŸ·“Q øo'åëëÔmþýß�çokäàH÷¾vn%<™1”b^xà”ìÑ ¶ÚŽ×áßß3¢†PWU|š_&>8ó> çÙG”ºN/’âê�s©z÷rXd$ù9U½-íyˆÝЍ(Ì«D´ï9ŽÓlÛiÛœ�ô×nª¤¾w?Ê�ǯ‹ o;£pWE$¤íP¦Ž›/¡¬-§Í; >On�ƒl W) ;'žSO¯ÑоxÝÖ^�âš• 0P*‰ ´pb¿`ÌTÏ�”L E]ó|f=`Jb<,Û×äN€Y æsÿž åàJ%›,pÌ…&þ6`5eZîážy­”pNØá=ôé÷’Ã]7–Ó“VìØ{œñ{ív1°çJî‘D®òº8}�öxŒÏ¯)aZñáËm;1ª(œ¯~õ‚È-3!´G ø]Ê1+K`SÖsñÙòqPØuRÜ£I½eÇòéØÏ$ì;V;£j#8>€Üç+Ѥö6õ³i&#¯OuŸRÕÐò]8åýΡó ÈÍ# ƒëÏ –ÅW:áØI6�êзá(j\*Åß/NÀ$ù來žN£f ®*QTèMµpø›0JÔ|-Îéó„6«®�˜gnƒ‹¢®’uMì¿~ 5±ï¡—F'Åotãµ £LÚ-ôhZ‚²›¾Ð#÷NùUN{NUŠ+:¢@®x0‡�릅×#AûÄ4–9ß7…š ä”B´}à8V·ô¦ÔÙ«Xª~ mm( –Õ`ʆc 5ê |»¶î¬dž]¥ óÔÑG£±öGÒÉ:FéËÂùÂ÷Å0fÉ\4ê_Daãñ«L�¸¡3³o®D =Sî£Ó‹ïµ$‰:ý‚xwŒŒkŠ‹þ†A¡]”$¹þ,è="ýñÚ©å‰ëW¦ñ`{:ýÑïL+u ýú¦)Ó¹§û(î76 n)ãÄ]–4÷‡ šqJRÞiÃ�Jüiù˜ß ¶ï™ä‹¥[)ïB¥‘Þ¸¿Ðð`«°ú¢XÕÎfuVg MŽå4Ùö& 3èÇü#¼¹c=îðMÉè‘Ü*c>©dÇo«¢R™-¿ÿÚìWÒ£¼¾â%-¾jû†J6_ßÓ ¶b Lø² Ó]ë(ìÀ"0?qÖæZS\È Ršt›f—Õ2$í`éÌ•Z}ƒÄ/ BfÙDôýi ´Þû×WVó�†<­Æ�óW5’Æ ÿÛá8l†ªÈÅ¡fsY»÷,QvÅbÞU¹�³õ¿Š²ß /: çå‰T°“%?‚ñU¤kh 〲$<•Æ®¿‰$}ë¯vf÷ì2‰‹ÜHæùYtl…8à°'…�Bã>u ôðLeG‹ÃŒ'ñ0»&¡ý²‰�•Žüóãrª¿.�'‚eð§V&?Yž ·}¢`×}G!¿N•®l¿,éÚ#|2/×¾ÊÞ»bqX­2¸åÖæžöâÇaëp YÕݾfÊ ³†¡¯… ·Õ÷D£ú60w×a£K>â Ï@Ò8Ò)HE}‡èÀõ(V˜‘Þ1cZ¾LŸÙMµÏ¶¢¶ýŠ™š#ÈÊhÒŽïVØñ<‚¶yP{Èuø°È„ ÏÉ$òlJãÛGðõ O¸ös(©.÷&Í—æxS!„£U49pJ(khgÂÐÕ Bƒ¾(&ü<ÂyÍF|QóÅÜÈ ¡r–Ô{úa6 Ëöÿ˜DMKzUfÂò}x>øXãš�‹¨d¿&üTúNs¿%S�ô0©¯Xb¼Hð1=þ…î‚Y“©àškÎu‡¯™ãRýÉ’€t¦±ÓÚ!}ãQžõB ŽÑ±—ÀªÜX¹1Ÿ_‡y‚ã†Q´¢`Ü �”–Ì+— Â/ÙÃ1`f‡˜äžO5e³ ¢]?ÍÒá´94üþ?ŠÎ3®ç÷ ãiiÑ ¡-¡EE}?ç”­”"e�²·ÈˆÐ.m¥a”вŠBZŸsBVH™™YýPHeÿýÜOî'÷y½Î9×u½Ýu 6?‹,åX-î�µ˜ËÆ™øiÙ2úÛ"*¯†3g5 ;=JÓ¥=Ù¨ç]Ò9)Kù®ÓÅi5[9æâ*P©Ï¦N™Ëõú±Ã±òë3þ:$ÓˆýI¼´!‡ÞuW²(¯ßC͔Ճ§‹×?õBØ9ŒçÕôüÜN(ñÀÆ’\r�­`Ö²äµqvl¸µ£òóÅóð1ý_Ÿ¿Šq??ÂCóõpúK;¸Œ’У(EL�PÅm·cPÍyÔü9B¶ÿ…Ð¥äñ‚¿ùB26 åÒ«'$~cï��Yäq2í±Lù_þ)÷+I6^–ëÍ�Þ~²Ã[@Y¶`}E~o)«Z¹9ŽôÂp%T}„Bâ ?9í ðÙO<WC�ùY�ØÖ@IŸ -ì!P{ ¶ýºLoVyâ‰îÅÂû†tj�:Ï}Î Ò~ˆzÇ: wú<~ª&Åd'£Œ” �™;TþìMÚS2±ó‰!Gº„‘ú3YÀc±ÂËóæÐ¶ÙU8“¿?WaóQaBá¯mU0{›�7¡—08u(>)ëÇCáÍ_XØÜ“sµ÷Á*'Á32’/9÷d®Ñä¹A”<\Þöþ@C£-ø“ìx¿,‚¾|9@}¢æ“LJ¡ìÙhÈ «ÇâD¥u|Ð@�Ô7œ¾ÑŸ^{ ¥r=Yafå/P¤É}°Qj³XSæÁÓš„æý>øßw©Þ~—ï«éò�~uÐC2ä;¥8ª«‘üoù³EåmÚÌpÊ.Ú>þ¶ºËÐÎɺb ¯šc#¾_v¿ªµÿDû\ug­Ã«õøñÔ~Þ2ú£Ø9a_�zM;û¸³š~-™¢ˆN‹…¼J7jÚx…Ý‹åy�IHáböÐÒõWW 5ÏÀ@=6 ¾¾‰4Ì[Êùi´ŠØž^Oõ}vPÊl/X)ÇñsJù��7|ì¼MŽº2˜zµÅA4ù®�Ò£ÃÿöBº$�FžÜ‹Š‹U)þÐ:^µ&OÈÎ�ÁƒÚ—yçë‡èyʽòû`ò–?T>dDì:ktêá£gñ|ßU~eKÅÛbËé›áæC?hH‰ÜëÞ×RDõ�÷YïH:5ž>o¬Ú@Ý{*LýI·+Öà�7®8®¹P’¹~XþxEÃŒ"à£Ó\:'‰„¬õ#P·Ÿ|‹TÁà„JÚ9BàÛ¯. A?Ýx6Q £ ûÒÐùOÿ2=ãáö�íÉëòÓ…cÚ–<áÝp¶þìEöw¢wÎp°òTÄã¶ WôF¡ÂÝ<µó?ýpo-½Äö!i�6ã›0=1ƒNG›à±ÒJ–øÁѽñxm"–ÛöÇ‚ðË�c€Sgl¡—mpVóÝþtŽ£¶cJ‹"?qP$Yïd?¯†jsq—Ú^0s0ö/¾/Æ}Yƒ:æað¨¾]p{ÐAÝ*=ñ^ØM,T ^�;UÁEó2M7€Ž¦:¬‘°ˆ«­Î £R”Ñàj7ß[(.ï·M˜¨eÆ*·>ÖDŠG~„¡¶÷wºÐ J+ÞÂïŒ\I¨ƒo/@ùñª´|ªÀ{®© £Á!˜6§ ìÕ®CEéTx`ÈŸ? cÝ ÉuÚ\Ö­Ã÷‚6‰Oä£yù€cøý�D5]ƒÂ7š7ª“ú7ip?Ÿ‰°e¥6Ï-ÁKÜ* K d·Y‡$Ú'-°æ¥Vùz`yr·0ëe)M˜¤Ë�–k`õ:wÙˆ «ç(ÕúËðhãpžÿG»<ò8ªÏ*±�o Q9¡øbùV.³ŒâÆôÝ8<*™æ‰v 1ñ?èwðÙw�ì¾Qp[PsJåG®QøôJ¼¨÷z%ïÕUS[¦ÂŽ9}ùe¯,qK߯4~é3.ôø*Yjü‚~NJ¥c¯96å¾à¾Š¨qy2Ùäh4¿¢ŽF FOÃçzÓË·)Øny8Š ý† ÓÞ„µ4‰[Fïû ƒ¬�ø¢óÕ¡Ûà‰”4XùwkEëYg¶ÚÒ„¢G’Uãž‹w½ vuex5i*Çh?Õ‹hQçZ¨¯°¤G‹ÔxÁ&=\gaÉåÉ`ýc:쬗w ä�Šmd¤›/›TU03‰µ�êð…¬�0o| †©Éá½ÜiÔµÜ�'e-…�ÚX3OžïY% zweLøç^tpŠiW«¶õ  ¯ !½Ç ÈÚ}e¾Â�3qÎÍ Ø¼Ù짵ŠŽbáÑ�Jêôš‚~¢æl/~룃jòlÒ�ÆM>Üd¬Ì7?ýG›nÄÀ�z+±Ã_.¬| êÀj[ ܜׇèDð± ×Um ® ·öXpPÞqúœ-T¶_K·¸@b÷Cd=‚Þñ ™øTrfZ ÝF Æ1¤Òû(Æ<ùU9ùx-º‹ÖØ™wŠS4Báõþh¼sˆ ç”Cë¨}„³çÃÂyý b¤�Pw`7>_Ù 4iÕÂ6ÑÿG/þ¼9Bl ]ÅkåÕx£N"îËk!Ñ—á^8Þ~�D³½ØóE ¤ö7«ï@[¿��ÕG¤xh¤6__¤Å¹GWAͺßT½ñLÚyQiûb^b5*î³á¼P8¸W¿LK¥y½#IúìÒª×> ¤áÚEot´Hë¸2?xþšÒ“ãaÜölE¶ŸŽWŽÃFOÆÎós¡íB8O=Ó(ôZ_Fó6‡Ð¦y[Áúå:XVNø;Z‰Ç—]¢Ð{“0/§®_´Â¾Á2x4áèì­’ÇZ—É_Ú WŸ2€mÑ·ÄIgoÓó™ÞxgH?n‘�ÄÝRåÐómÖÚØ`ÏmíðÓÖ ê‚¤ÐIëd¹hÒ⯻sƒÛ´ÑyÎ=(Ï�£“y¿äõ3„Uò3Ѻç3±U‰ê†¡ÐQ ¿~7³ñÌ—P¿Ã€m7…3UŠÔ÷ÞÁÅ׌»sýxn“*>Ü®Ïcˆá·ÉHa™Ùjú/å"¶N|ßøœÖ÷Ä×&³þ†ù°½×. ?IQùG)]Æ–ÛÂÃ!ö¨šøøb 0xÛ;¸q’}O õÃ’K�,�¨‡&Q èIÿ˯÷à‘Ø<>-¯eT½ó4æ SÁA÷xœ¨Œ½Lý颵„oØ•sˆûD°0¯‡ãaj] k—+¡�ü>ï\“¥ã…>ýzáíCFüñéDÜàqNTËŒÃ{} „P+ ~hã%L�£ˆ|À©ßJùê†w7ÅñÏJ*S ×Üpåç:jX»%ÖÄk€âéá4üYªpnèhr˜Y.T_ gÛì·–S¡Æ²”¶JéAÊ©ø&•�]î«q²™.©Žê‡èbÔ‚X°¾u€>î­‡ò'N&VÕt\#ž§6eB±ÞXžY„5ÛGà·®(ô:ý…Äî\t÷ô.ŽBi·8š¬„;�¦³ÕNG˜ûf°ðLFÎmVb£šv±ìÚ]h©(¬y:ÇælÃMW , îÓ¡ÖÑøîœÎ^…rmÐõn*fZM—™Ÿ„_ßÒ šÆò’Þ4òJ-ÄäðÅ�Ø_&�í‰àÍóÏCs�»èU¯Ž’ñóÑóÆSØ{Ç ×Ÿ3G?*<:ïÎîca¸½®Ø UÍ^3)ñÑñHÍ>qì�Ÿ åV,rµ;üŠc ŒƒÕ^†X£A6õÐ�9 Sœ'@jÓ4>Ù,Cj�o�ÆòÜPÏ)[¼µj4Ÿlk¦=òþðP˜O½ÚhàI[œ¾e<ŸÕü¦VJ-LQ{jÿüB XÜË8QablØ| &Ñ�ùúèôÕáŸÆúÓ[ŸÎTŸ@ú-•B‰0€ßß‹yÇ@žSu¶@ÄÃ:]èÇA%}øÑŠÅpõ¼‡ø80•6YÏăEÅpÝo7í5çØšg”uë5]»›)ÎR_�òûóšœõË—GÝnS#zÒ»‘øHÐ?ýXþ䙡ûÑêUÎ>¡M—_eCËâlðpæY/‹é^V;¾·ÆÍ׿Û~¸Ê­†‚ ‰ëņ–­Â�•íÂÒˆ7B—z0ÏZㆧ–߆ÕKω+ H5TûxŽES~@Çî¶Šã¯FñC©uso—~ ¹Ú×Äåƒ÷ÀÓž!|>l]t�Šî” âô Šùó�Æi¹ÓÅ ú�\Æê6רÎÀKp~¶�üLžÇ7- |¾ÀŸ�˺³ÉÌ dT��³}Ѧuzž™ íñò¼BLšÈÞÎóįše`òÙ‚EËTêõDh•D�MO±�t"HŽŒ ?‹ïBU‡ЦHÞP| {æŽÀ©÷FPD¸ ïqÃ'K†ã³e=q¼åÖ™Â3Vû@øŽµÝIÊ?7sß¡A*3‘GoüNÝÑ  éôšcïlGÈL·Ük(aŒÖBX¦ô@ˆœqâÍ(¼iqèjQ´ÂÀ…¶4ò½,ÞoxÄÏÚnñ·3zðÛ?~,L Ï!œ]H/½d°qY ,LPÁ¿Ïãã®ùØd�nv£P¥¨•æ<Š~Æ E,SãUÂ2ö›seż&::À‹ß\æ»Rù¬pÔ›\+yЃßp%º^ ¥™âÕ;f‚¸Aš¶5—�ÅNcèWº_ÔY/ /ÇgŸûð�?´ò\*HL9kSŽ¿úš¦Pv”ë+ê`²‰žûá-�~¤¢3”}ÿLæ¼ÅáüuþL”L³àž§:EƒVMa¸Ý"\ºÓ§Ë–€•ò úô9 癄æ1a<èN¼¸9�M•8im � ‰ß³dªVCÛõ¡0Úó1m~*¼Ø¨Ãñ+ûrõ9Ç»«ŸÁ¯Ò ±Ä/�´MñGó`|ÿu"íó䥟îÃ,›OPgàÉ=µ’xÔ7œ‘ó²¿z åùþ²ø¢kÕ/­Å¡¬ï� ÍÖ¹Ð{Xt�ì ýédËwȶpçÆ¡@í¤&¯spå��öŽzIãÙÅPòO7Wr®ð^œØKŠ/Ï ù]Ôý¾&uÙÐ>‡l,�‡mㇱ‰¢\¶ž?ÏþAæ^3xà•¬èŠãŸNÅÀÏ“¹9~;úŒ¦ðN4¸?m–FrÖŽÛÂ9£§äÜÞLÎɲ­?>U_ƒ!n„W'qË®´°z! œ>I+QFoèÎc¾q^/Ú,«ø/vÆÅ ë Fàè’ý´ã¨7þì£Ýsm8ë§®;YG{szãæNØR6—ºñ™Ph(îÏ'#žÞ„Á÷#q×’),×§o� Çèöþh6Vth8L½ŒÌxÊ»â›õ)(YñB’“ß7ÇQb¦5>|WÀ'ňÝÝŠü´È�Ÿu̺&õÄûU¼aú!Ž¿½ž~žÁ§†HãðÙMdÖ?ž×åýïGñNrÎòF50Ó#°J¦Õ�Z@—ÝÓ.cFŒ<:ÁãYiðu{0Íl-¿ÑK@u£<´:³zìnúÐû½ä×àhÑüÍQ ÿ™6df Y| º?h#Í!Ý g�ާ¢Óà@¯rŽ®ËOÕøÍ©$Û1êœmq©Æ<”ÛcÆN¿”ñ‰úöýÇÙÆc'â‡�,ÙÑ€Íÿrn%\?.­÷ŒÅï­­ ó¬Ž/�_‚'·‚ZŸ~hqó55FÒ…–5L››{í…©ŽaˆªW)öd†äìLMöÎpG•W£E«¬¼€¿4gUÝ�5ä·%ý±DÝ ¼3ÐëíNßþÆ5÷Å-à°¯ãey�¥["ê• MÛl°%:õßìý è„CÔo](LYôoÿ OòŽ—mtyÄaèÔ¶ÇÓa<ÈÁ�_êÇÅêyÆ“µŠÇãëô˜ªAñš˜2dº|ò£w#í¬šˆ•Ú'(jNUÜø7Í׃ޑ4~¤A£�<±}¾*”—ÙŠ¹ðÜT'ðà'+*^,ãĉ%4«ñ»{D§¦I㊋ÁØ2UZÈ7¢1^ Ž}JÃM£×¡ï.ö¼­LÇ*ÒF· ð("…"ä– ¯f.d<[G<Ã]\µ¸Œ­$á¸q¸ë¤Ëߺ2èNÞ¼°ŠE2¹áÍÅÒ£qÕÁ†: lî5–³Ú.8ÚOã©wMyIÂ,Ž-ƒ –ÒgÞrJÇòáUœf†{ô˜‚ÊjÀW}?­$)Øï%d«Å¿ƒ&Pð>;VŸ7…ó=bi‰£©uÎf­Ka`´)hŒU§a¦ÐÅBS<ÛfÈ…çõp¯ífüåP¾ßÏ‹¿V…Ÿ5Al˜X Û×Ù‹–%à¡~r`4rŽUžÅK|�T¦¶·pÙ€pœ©¢ Þÿí@W­è´c.>¹vQ0õ;ÃŒd±<é/=d-Ü¿6óÖ„áÁó‹p…›'N%¸¼Ñˆnl¬ƒáê`ýŽr¸mƒïu2ø€¸�_Îåv7ü¸þ2KŒê¹nÖPêó¹MˆËñfÇzcáõqmV™bŽ÷‚öðѵ>âˆ>ÃXÖ½#UùÕ–‡ó7‚yçŒÈ;ì6«k6²Ù/_蚉EŸGál£½x ¡7ÿwï_‹yãQïÝøzT$\€RŽÂöªÝüV’ÈO•[„rÇܵ2‹Þ1ôò„#—¼F9'Õøóv{œŽ,jÅ¥B¥´÷?R‚AžÁ ›«Bz…)ïꚟ¤I†ï£ µ+8ïj$¤íÖ¢ Ó{äù±ŒoÏ’¦¬³»„·~Q{Ö~2 ­â¯Ç¯âOuç&)9¼·î¶0Ü+µæ:°åüH2UIâô½¸àý€¾\S…UQï!ypÿYü‚nß«ÂW@)¬{à%œMpÄWÖpAß>Üô,Žâ¯DŠg¦Ëa@ó:jt –â|\©£„þ÷C“`?ž¤P —6Dˆ½5¼ÈY3 j•Òq¾”ù¬kX˜<•GàP^Ú¯  DY6R»ãg¡–Ò-ÆÓ³aãŸ6®þŠóSÅ�²Oo¥^h\d…O]BèÃ8YÔˆðÅ£·»èêëTq‚ú!“’„ò!‡éùsÎȺI©‹…¿‡Rxòúp¾sÚ&^�øç›JŠ,¤´•Éh¶‰…�¿ó“/ÇaOÚ>ŒîJƒó:{@i‰"j9fŠ ”¸úS IqÆ›^?%_÷p�£9Ec­Ð%¤d?7¦&cÿxÄ�Ñö°ñÜ$¬v$Yz‘0h_W÷Ü�—Î%sÎÏb¨­Â#^Òšñϧ¯ P` £ïÅâžcsȪwne†wƒà¾ò¬²;�~B\ýHúª*>pP¦ •ê¤ûý 5JmçÚ=S1-ñ³à·wÅ9õäø�`å�z?ý³Ëédg}=Ô€i*ÊÐ_ë….åƒþ‰X¹è8flÆ\ë{tÜýˆàª:—ÖžíÏè^/ÔëàCoüô½l¶Y²â¿EŸ’ͬ²0«Ÿœát˜�]ßÒ˜TWñNÍ'¸ú$õâªÙpäHð].‹ªU[P§®J|Û2™Õ†.¥#Ê_èÛÎp Ìæ¹/ÕéžiëæÐÚ© U±i1¶¯ '¸³å–jÚèóPœc³[lJ*Þw¨\C–ï¡"ÿþo7¢ûFjÒ_‰¨°ž`ç!šxo;ɆYqÃâ@Ü1`-Î[Rè_J).³ýk_1žFŸ$1È,g®“«þë“$~?‡•ß.pºS&Ž©ë„”óÕ`5¼JìóçéKr¹$°«�F�ŒåN—zÚè´“c;€ÙÒh ˆ5·V] EãDa‡ý*nY9–û]«jH\1"¸“®{§`GeØç‰ó§h`h’"ß Œ�ƒÏ¾Ñ…­{à@ßµðüV…xâcþr’“MþöÊêÕϵgÒ›Àq ófï›(‡†žCa¾’»³䘔ÓEãžxp~èEã�Éñ퓘óF߼݄ƒœ¡-1ÍÖ†Ìx ~ú¤fËér…Ay¬ºU5¸>ƒ{ ²FeÛ¨7Þ J�hVÛíø—úÿ\&Êrê£tôžÖBF3:x½]>ÝR¿"•ЧÉ�ÅÈ‘lôe[ìsçIqf\Õÿ,ÇÅÓ�7éé¼{ª˜+Þš‹û¿Žæo´ÑëÐL§=–—ùØõZR£‰}Çú“¶ü{Èqò Ú ÖqÝP\V¹ž©’•ú0"¹Ž¦»gãêùà²Ö†>C?Ó¹`azƒÅáKx¦‡UÍDl’î^i0jyI>KøºÛXºî(nþ§7nø"?¸*Ž.œB‘º×à½Å, ÍÉ`ñʰýøªÎ.ã§Ý¾¨6IÎyìŠd§òYý)(Ü^)ŸÉM'î10 GùôAÓÛÖ8ÒM™¦(+�ô´ÍüÇêl œÄ)_U«÷ÍÛƒÓM/sV�ž{¼Lg͇Ã÷TPaé9tò«¡¾“áCë)Þ§ö‘¦5…3¦¼â"LÑ:;J¤:%¾}窠¯•@QcùOÖ/X²ý í±ÝÈCZ:`cµ3_»¨ÂG*Rsßpü¢ð‹ÚV¤÷ʗ设ÚÅ›~¬ …Ú}…ž93XVÙ�¼ÏODûg£YýÐ rÚ²�ôÍ`¡p&Èöü!«Ì1~—1 ¿L²ISÈìÉøQ™^÷ûc’f.ý�@кl8D ¶æór]‚ªK·XùS¤»ðÝŠ”ò’ãŠ`-tØx ×^þMž·ü8Zù+¥˜¸¡s~" qÚ�:�à¤M.S”ð×/÷…„'ƒ!8{8[µFÀŒM\°À�3ç•q’^;,™Ë¹ý¤ø×À"\»]Ÿd_¥’[Öd<¡¥í|/S–{®áä'1i²“·¿^Óã.òÝŸ£Dçwò˜ØìC &!<*f+ȧҋò‘ ÿ´¼®·>9L7 ¦–Å\5ð/-v×Ää¨,å–€‹uÐ1¬7ž®¿ž+5PÝ#–W¤°�ë[¦¦<ª q€¢k !ó€0yI±xl›„Bö÷„жk´¹´Ö–;„°šhÀM£Þ Ù›kÄ­ë-¹Ð+×÷ $ùļ+Àœ»òä9xáZ+?ÃÒ,1-²Î9 …ˆuƒ…`ë>•&¤U ÅÂMëé³m-÷kèÇáóñ#Ê�+ –Àó´ûä=0[qÛ´h]ézÔ­è‹w‡_y›¶E¦‘þÁ 8"kÆi¾ÛYº¢ŒOúPz­üó¡dÍN¶nDˆ°ÝÅmoŸ‘Šëh°¹µŠw‚ßùÃð Ê—©›¢Wò Š\6>n6Âûyg@ò/¯E¦¦ÐÄ�F<N $÷¥·µc8åó%8¦ „”)Ó˜A‹xh“…²ÓŒ—Ø'ë…¶{°ôlwÌtÍÀF¢°à%ô®>%dœŽ3==Xn¢%\–Í2“þé_ðwqÊ$J ùÊ(!Ö�Η�ùÓ³V ‰“ã?€‡çqê§´Þ8¾$õÄ˨}0Ðgi-ËÒÎój3(ÏÀU¬rîÁs2&`²’À'>~ËzÈpÌû¾ÎƒCSù×°>èï%å|e»&'ë÷Ͻ5b^|™§ÙñY\ËZr5â•QI°{g;Ô[܇Óý 1ÎÌc5àc¡#ŽÎ=EÛÜÖQìSÈ•€Jy÷È¿|Í3„ÙçüEÆ Æ,¤âq%ôvÖ>˜$D±nÚNŽ—Îáä•pyÍ9šcGs-GbÊ}Z^Ö!L9OφÒÎì¿TìÀæuVÔÖ<ç×kòñ/†ðË©Œ¢ÒÀüÅMz¥õðEÅóú¤Z¦É Ä^ê�`Žt½©)‰{gLeIhÓµ•ƒÛ4¸äË.âyŒjÇÅVöY´©Qa鿪EQÛhR‚¦lˇšO®¨>z Μ¡ÁQk^€©ÓÔ¸ÿŠdœ“¸ºc+ÌûëŠÓìOàìJ¤ÇA8sY¾Î‹Æ+ƒò`ÒW*p8 òS xüÖó´¢�6÷­µ¥ÿ®¿€¡M>âýÌKt:³?ÎWÖæÎ“Xb¡îÓ£PG¥ˆË��B–âfr¤„µW2)3ä=´½�(,\¿ÖõÕóÄ4>=ºùfýÐòÂ[°w‚`µÁœO¼WÛCyÙTxd†eŠ=ñí«=¤|ˆl— Þ—h¢¶NÆÏà€ê¼r÷%1P2÷h =¹Ãl&=J²Å#M;…ègFâçÐ xµ|…›�KÓÖ*Y©Û0Ëø8çu6�fäf¶Ï aǧSàÛ�¿Ð–[Ê+¾¸ÀùiøhŸ;^&Ô¼2#ÛONøQÚŸú ÂÇãd ûÙþa® 0í½0¶þ$]_›LÕ¯²øluõ™¢ˆC— …÷[Í‘KÁ±ÛWl Áw·399Ão]ƒ@ù°*ëY¤*÷™œžXÓœÆiøcõ)\¯‡cnÆñJÝ4°Ò›~œeû8 ìõ9ºû°�b#ù¬[űæX4< 7¿´Æc·×àËÎǼ1à½ðdk˜°Ö`<Ê}Os"x¨åpÜãfȦeö°_z·¹jóÚó=iøãf^<É sÅahú0˜vª¸–±{JÞRl³ †,ˆõöå%JZpûÂØ¿ïÐMÊ~ŸÇúGg¦Âí/§ÈŸ“XiÆUê<ëN4¼7ÿ¼zŽv2ÀpŸßBýÓ5¸¹Ç¤\ ˆÍ+¤ª­ãƒÁÖï0}}8 þc÷üÕ½0Èþ&©ú’ùüØj²ú9Ê�[ï"X:=�ý—‡ƒùκ¹ýÿÿ˜¦[ `×Ùxè/ŒŠ©�Ÿþoèlågjßõ˜¬Ú|1ί�äWaä·Ó;Û%×>C`ß±­:¬Ì�Ðc±œ®CÇ´tøú³‡óI¸0ÈjÏÔ^*,]�ƒ‡46ó„ƒKq´ß$<<¤„ZW+ó´¬ròW±§wWc8ZZÓ)ó´*Æ/qaŸom°íuxypúÉ×ÐÈü  Ú–êÉE½1¨Þ�Wîác�*´¸#íÂþ¶ÉhtzoŸ×�7z®çus(Þk5?¹K݆rEz‡¿> ‰¹‘ü‡�V½ À––wBŽßYtH<^‹Œi…|¼°ÓE•DbQ‘*™Ú äû>�°{a‡{¯„·GúV�w¶�„hd¡r×<ñå«�dPw¶Ë?çý7Ÿ·&Ñ”[`LÇ)Л-ìYx\,i½+³±ç›ðxý]Þ4O­êV\€KåaªuÇ~ý³ÜyÚ%[r³IâçXò7ìŽ&äB«õZH¸Éý_¬çã;E‹ÒÇUª>¿Åã�ª±w�RÚßèFѶO¨=Ì‹ÃîR­ œÄUp4†÷äøŠ ¦¾ã+úðî¨4/�Wpçêé9fÁOMEt“M·UÅ! ¶qËË3Xìå�+vìŠ?¡k’èâ·E” C[’†âÈ.[òv½JI†]ô{—ÎÓ³ÁÒ!ê˜o?„vËÜí¯ÎcPÄSoìùu[8jw�fŸÙ88ɃŒ(ÅÑ*}xDK5·›hà¨+GPß%^LÛùW=ËF¸Þ:7Hà[AîàPκ£ Í©³Y\’�;¢àf»5 ‘éË}´+¸{`è�s×MÄÒƒš¸ý@^ù9ˆÏ¾ºAýÆAÂìˆ,NKú^E=—ç`P oÊJèC˜8wŸÐ~³¶Eô¦Ò…<¸í M9“%6mÓÇ5ãq´~Œ®ä/ÏÎ ÖF–hC&¼ù™3Ìu´ ï!Ù+�3œu8¾û²`ón7\7%«wYG˜Ä ß�ïæé¦C äc¸0ó…ô¢&Ì݆ÇZ£põ­eøcÌXªÕ‰ÁWÏWP³þwº™÷>,táí©:Øc�„ßzÓ1ë^üEj(-H£|…»bQÒÖ.²ÇïÓCɰ¦�{x€Îâ‰-FX¢)�åK’ábr4ú=üFM±Õ8‚®:æ¸þò–±Îw Ï–z «7áê¥ ÐïÐ!á[« –ÜËGLÞAï ÖÃìì@®H˜„šß¸ØØ ýU÷Ví_Óʯ~í‹UüvÅV9¬ˆ†[‡âYŸzRø<„³—w¿GñcstPS`k‹8xi_m†ÁÛ°ª15�ü °×å~|È÷Ìü�⦋Å7ñANäö ãÍG¯E;"pêòëä–„ÞÍT`;ƒ~7~†¥#4±«q1*é¢ýèñè¬+îh†äçáÀìhº¶¬M�êáŽÛG*‘îF 9Ú|ûW“ O|eû »«vHWPâÙ•BÝÔ[$ß�ö¹fUE½P�ƒ{©yx /ØNÞÖ™8Ùn œh�cNJ*?<åDeGìÐ�74|€Á5ÇPz·βÝWUÿ(˜»[°hù"^µâ¶D÷ÍCŠŽ}ÈU‰EUížQëÀ þÞn…gr>‚jÏ&غ±^°qÐàM‡ù؈\~Õ~6æ­„ÅêAì×ÿ6z:NáÌã\5aý=Ø3{3¼‹ZÅϵŸ û߯ÇÖ¿J¨ÿ‡”%ûĨI¶0÷l/ø�’åuØ/EÌ—ã–Óp«ø¤Ø§õ_>ܬP=é °‚Ë!ºkÜm8 ,«çÓKõXkáF1W1F*î¥ÈøXúí/5&°Ç¶¶j¸ â¶Þ­#oèãÕùä\;�>ÊFñÛag%Oç\&É:áµ+·óÙÒ4{Ÿ“ 2X[ô‚®NÖÄŽ¦{‚tçvèûˆaÏMHCu4ãÏvþó¼A¬h 6x‡ÍÄ–WyüÀ/Œ}t#+Ù!`lìwuÍ8~Ø ^ú}ï¶=M/dzÑO)<�{-BNƒzÇ:yà8Îù`鞬+]÷êg�r¨Û¯ÒÇ�1q¨” ÷.C‡§ãÂß‘xèÚ¸}*ví6Ã;þÔ~î_Þ?+Œ–`ÝÊ“1ÿ2ƒI³øÛ('þûâliþÛm”1ײ?ÈZì‡1d×[•;îÛÛ±vPH�x.TËû°_i—¹cMV:Éú>§Ð…ÎpÊú)\^øîo¼HJ9<ì[-í(ÐÇþ5bü–powaQ+»ò>¨ð T¦º’ãâÁ¿8�æo ƒk›pŒŠ!5Ýk¢ôçÿéÅb”WÖ`Ï ·)/"˜®h²ê|w^u£'ï [E#ÄÕøú¦¥Ð™¦Ë]­X­"ž¾Lž c>½¢Íñ¢ëÅaÇ“�krG˜’.Ç~ƒ² gX:j¢2~y˜&‘8Ãé�á°ô?Ü+U3¿ iïU)f¬3žŒèËß[+?Ÿº žwï�×þ&pÅŽ�ì|(ŸåV´Ve®zWuÁ4Ÿ SMA¸‹Þ3þ#í°�h½&¬ÝN%o©tÙ( ŸÆÃßÙÁâç.ü| +Éh�åûÀô¼.öHÞ�K£2­Sà¶B�¥Ö½ÿÂr#šû —f,m¢VQr…»xC´ ›Òg˜›j‰=ÆæsÂÉÀ‘E.Î/]ײ¿Xö¦Q|ßÁ †Ìî�߇´ ú‰&\8eîþÕE»�ðï"Sìr‚4Y:ú&i´{rê‚>¤aQÙŲÝ.³ÏC“‘£±;=‡ÖuÎÇÃ�ú$láågFÒ�Œ ÎÉC�+ð´üùôóá5˜úDoÙý ˆGßéÑ,Y¶ßâŒsÃj)ë{¾˜c­ÉÒ‡9»QO(\>Šó 9>#yÿGî—¶°sU8¤öÂ[EÇ`V§7÷–) ݇£ÔÑõÔnØéî+ZøQ÷žU8ó@4I��ƒÏn …ƒtâüð›ùÌæ�àl_ —¬Šça™IÐgÀ-ØøWÓ;÷Sy}±Ðfñƒ&Œ:�¶Ö‡¡³ÄìfçÒÍÛÅU gøç¢_Ð2N†CŽæ�jk°hâ7˜f€FÕ!´¨Ÿ®Rø+Ä-UôÞ.Íý ¸oo)aóÊjZµù_†NÕÃÓ_K)»øùÅüîT$z­ØYu} ^öG‚Ë—-ÁÒ q||Q:幄˜ñ�žÉBQG=¸_hú[zC’÷~ Íרö¸]²ø¿L²¶˜F{–Ãúä'Tt¥SÌhî‹ÖÃREüCè­‚~>ð'«ˆ¼ÛÐ{ë\V>�ÊÏäII®¢õ�"xï0Ÿ—LÃoß -/,àÛ»oBÏ—ÿÁdY9èQ»ŠÞT†’�óøšYÍ~¥�''Ué ]Âïßeàï7V\“+žÑŸÌ¦ÛðÙ†¬eU*žÜ23ô'áu›Jq§…ÊØÛÃ’cj˜Ô0êejH"s‚Q³†ÒÍô±¯5‹ão'“T;³¿•†uÁ§v*<ûçex3“„“G¢íž?°.hµ,Ç;}—bmÿXV8�ÝÃE» iLV´oª ë ºÅ©¬Å{£qÁ%îÚÜQ {ðÁ¹xìÖš6ê ÝMÝNI;/à7¥çâð é(-Ʊɋýè}y�Ÿê¥z:ljp‘æÔ:r¼eoŠ)&óŠ·¤Ú]›Ê‰3´qñ2šfl‰vÓËxE¥#’™iÞy¯¶)¹Â¿5ñÂnyJëB×ýÏsô˺Û÷ºáŒwArn…++‡ý7£_Í:ô¤CT©ýƒwÈCýèâ,[5ôÎ÷õÂñý˜ãüÈ8ŸIWŸ/Ùñù ‹©N'§éFSýGÔ\êÃz)¿Hå±,ª o€‰ö`xŽ1oûœ©ð`Gšù¯Å‰1Ö^÷Á”Òxhi„z‰ü~è)º7õø'|�mM·¡d’"·_zÒ²òô#»œúõzç&_â.­¦waëøúËr(Tw¢Í¶zôùœ ¬Ý“ !Ï 8( •:ôI¯öÌú¸Ÿ^m/»4ùž4K=�Ãõø”»¦¤´ÂÕu$ö‡#âJD¯�1t IžF‹qΡzž4Ñ$3uQÁ\äc÷Ó…f©ò“Û',Ážh§>>î 7]Áç€1�–x?°€öï 嬡·$O]ÊÅ3Eã…,s5<æíÀ Bt±¡8 dTÄå3×Â…ØdZüû;œ»ñ„nÎåÅû¾Šô¦xŒpi¤òÏãHsŸ;Ư½ˆ-áýŒlVȯ·éÑb¢‘³¨§™‰$ó˜nÈåö‰¾6ÑeϼíT†£ŽÉ~Ú¬†*ÁÒ¸¢ä1-Ö~G¶Ø¢GZõï#‡zç>9ñŒ4Zwу½U æLuíÖãE.:ù?Ë‚¨¥ÊØ´Qš¶U np†f·4“û�HPÍ?¦8Á47ìú¡@)£¾RÙ‹+â…Gx˜û5X´u%¬ ¯†UgKñzõBÚöw(Ï›.…‰ãÕY~«*¯ü—y—jVùgø±gÀ¿¹¸ã‚rcñ¿ê©ìv‚d2¯‰uµìR€Ϥáï„ßèâòdüY2sYýúø¾ËÓ,íXîÁ�P8¹€WXóž%êÕ¹ª2Õ@e`¦èûööP¢9 ƒxö²½øtfõö#ý¹iNê?S8¥ý—Ÿ àÚ5»Hª¿,Ҟ̪*�ð׿VÈ1u`Í^ßÄôd]þ©t´ Çæڹè!*P½õ2ø0}Ö¥YÂn©él¨ù ”¾-åUÇzV÷ØYE¯Sñy&Î.Ã"þ±mî¡rZÌŒÜ íqÊl3áØ�°F#ÚBoªÒ¢}žÜ&ÜœÚ×£ç…o4¥Öî_65æ¹K3C9º#©¡xùÕØ¶™ÏÿüEg�å×…q³’H$JŠ"IQ¡xTš¤AIšI¡Hš %ô7Tf "4˜šϽ·TŠT’æ�¢™”Jsz{¿�Og�sÖÞ×uýÖ:g�ô¡4^ú(ã³?'°Ûj/¸rTPzÙ l·nçŸ7óÌÿ–K?>Ú‡ŽB«°]f,n{¹J�ušÂÔWãâGmÂA~ v!C±OÄ2Lìì ËiÖ0×R–77kᄟ{á¿K¾ìn7‰,û À[óu±&t!rJ!ãøløyÎBp„Z¨íÀB"Psx¯¶Ó&…üqó®S•©bÜ jþ^¥Õ§y˲/ §-Ëv³XeX(ìú{ gUääÌR1A6ŠvØîÇ~Çâyü,*βÀûJôøãÀ4®r¾BîïŠ^ͳ0~À±ëA5ÛsTê3êg¤Ê⢞¨c‰ñŸâ9<µ™ºÚßJ7\âWÒ¤ž�M}­*tæÏ$Þ,Kç Ò›àL ز›ã»±oý]º!%�œ¿â‹I‹xÙ¿Œå÷Ίƒ¼dĬI)¤ÿÙÒûêQå¥jaNò@n¯î� Ã)ðÀ7�`²0(Ä¡1~Ütb'Vmc£­ßE» cyÐqc\"UàƒÇ^I·Mþ)äLPâÚ®)¸0<•¥rÓyué6L›ó‰× nݹKfë\ÙéŠ"—å¥ ¡f?¨\w–ØA­ó¸ò~Ü?ì¾®†–Ï:i°{¹+=¸²L²ò‰>víº(:?ý�âuó±¶ÖÂr²Ám¾- XP%�"¡ñK2°ØKWå¸6Ì�ÿ�&ýY°Œ´Æ³õï4ŽÓã·&raTŽðìûSÒîÞ@Çö¾„²ª‹ôxªz¨V‰Ÿ(÷[Ž�ó®ÂÌõ†xÊù—°Ô{ØKÔùiÞKqÓö½Øï²'¼IOÅ¡øwz+Üôé‡]m¡ðýu  >?ŒÞ(I8é¥<õ» ÌÖˆzຽ¹åo8Yor@��64hOú?}óWÔÃwë2¾´©‚7ÛbŽ÷<¨w�^ÛIv$ÃÇ}ýZµvrWy#�¾p¢|«FÏùTÕ=è“z ϺôÅí �llÓ'×.�6g†œZ'¼3úmî 3&ø`ãˆDº{R_´$Óú^ž¼5f+ו ƒ^gÂÉÁ¿†æ§Á¢I#ðz¿ XÛîα‹GàS“­âF57 \’ȃ×z‹þº²]²BC•ív¾‹�•ðqÈ#>²­>lѠܦ¿’Ûºsˆ78KÐî±&ä(£oî%ê=üŸÆâe¨aËVø,Û”\çQ¢îx\bœ‰�AÿѺ�†ôcl øcB¿B¸I\ÅÇln‘Nå[²1)⥡;i†ëj�Ù±‘��g×–W´aêsJÝÃc½†‰¿‡ùaúÉ­8>ç,º^I†Ÿ[¡hç{©D)Zg&‚˜]Ieïö±ªD½7ˆìçTKM:30bÇ ^ø¶YÜ^`CS®Åòu¹  pw+Ý]µ�Õnêài›åüŸÇi:£ý…®Ç®Åÿ¿³Ö]4Ÿsu•xOäuXðf<”å ¨Ñ�+u�ÞXáHÕùÒ}u›@e«,:EŠÏãyÌy˜2ó ¶ì ­ï¡ÎÎ2³Ð/"�ÿ¯Ã+ñªq9O�Äß“ÎÑô§!œ.›FÞì‡ ë ¨_Ÿ*[›É ðQòJΚ#ï«àÈ'‰dÇ$Cq«“!��â¤ýy�t2^Ҙϥé è×q� 2‹ù¶ºg 3xÞÒM<,!›?^5Ä@¯]´.! 67_R5m¸ºJ!8×UŃ©{)ŠOáͯ~°zþ>ümSdŽÐÐ4�õžK%Æ `ÿlZ!5öÏåäÛøÀÚ ÅÏãÐ*>‘–? ƒ<ý‹�¿ß’•T�¹à¿±”öj_}W÷�pÑŠéØÜÖ�"þ±öÉiœŽws.ÒܸF =9ÏÓƒe+Ãc:ý@v:(²âã+4(ìvùýUݰp½�9'Ç=föå�e²Tœ“‚/Îj ò…[q±“Nñßm3p@UÝ7 gÚ¼§4Møõ[�æáÈ�hz»$Vjܹ„d�Çãö£Gàº×d4¿hŽ½ã»¡Í˜»Ðöô,/ëY@ƒŠ´Qáè$´þ•#Xþ‰Ö9‘«¦„> ËÒ{¢wnmÝáA>f#qmýZÜ~${×zâ‰-Ópp£;,>“ý¯FÐéi»øaÃGPÒÔ§‹ÃúqÃr}ŽÚØËº‹ÚúuQÆÕ‰mº4*óÁ˜Ö¼íÅʃ�ð¾å ʸRI :Se‚´ß�"�•�(‹Fã×õ�’OÞüZÎ…OéfŠ‘žgPåÚBž#ÓO¼øø#üôVǘQvœßbÒE}%�\ɧb:ŽkžAGçDSBñ@VÚ¥ɺHÖ­Þ÷[K=nÐóqß…˜ÊjPŠ©>Š;ÑÅð?ñCÛQÚ0O7&èóäEZ¸ºÃWèeÁäÒ¯êZÞÒ'«0mí*œx`!{¼|E;škøu\çÍêŽ]»7ñååÏňiÇÙÕüæ&­‡cÞõü*õéô9FÅJ"ž7ÃÊ߸ìôy8嬯µ_ÏâÊyUÔ}ÒQÐ*éÊÛ#Ц~,óìS±3d/¥Ž\χj¦³ì˜¼öü,´0Þ0ÊMô8ür¯Ø°ÁÖz‡º·±µåÉ›šã!‹£¸#³œÎ¶M¥»Ïf²ƒÌxŽ?ö‘"·Äó‰â÷T5QœÑá¤ËÎb~ž5ÜX_QŽçÔuójÆê*;Èî§…CeR…í7T±­)o^úZÞçäa|~r0TçŠXì°‘Væw‘`@ ›§ÑC+˜pw†Åo¦ÜK~•@‚a¾´²ý£xã §||bQOI¿LybÙhp¯‚M³‹ï~ÁR¯¹¤¢M‰_ÿã¬w2\ ;=vœF�&QFu.¹;ˆ¯“:ä4/Ðe—¨þâœ~u°À—@aÉ5ÅÔ½np‡  ï½cÙBq;zÙÞ£¯¦éÜ™wíº‡ÐÚ 5–Vþ ›4œà~�:tVpÖ¬7bhîuš“7×`U¶½Ê®ïåkã' *›#0¸>‡³2k…ë;ä9À6Ž«EŠ­À»mÛA;ÞÚzÖrY}Ö\\„ªC«!hZ)}ߘÄÁÒ)¸þ‡Š]ͯpÜi0ïY +„LûAi{ÇÓš·¡hD *kj¡¥›,~®8É“”ó„ÑÆQÒóÊy¸r„17_<†÷¶§`–TQ”*|�ãGñÙwkrXgÃeðaþ¿ÞQ3“ìò 6~Ú'ÊWŒ¢ÜºÕ°¶Ðþh pŸY°ZoŸxÜey¼¢’"¦Àƒ_ ,úŸ9³K23h5¾_@k4ûðÄÛì{d M3[òVbæ|ùé ßc¸ðK,]'ðÕ›bиÿ¿‰SáÈß0ÖZv‚fóü ïÎNV§±qÿ&:à×Î( ï;U°Hf —£Ù£¾N›Üüãè`Ág±òîI2a2±;jD‡#«YgH:n,“pë¶Å°}[Hû¶ƒíq H:ºâºÃ+_]–WÀÅj ïØê íx•&ùÄáþ÷S ÿ‘e<¹¥…Îè�ᆇÙèðjþ*¥ÿ:þqãÑ[”™õäNÀÍA�\dÈâÃJ¾Òó*pv¼,šÍ<Ê6F�©²ÇAjùÚ�Ã4’Áªá�:ü€Î*¼¦³ðè åì[ïÄ9ÛµY±ò)´'ÛãˆÌ&z�K¹³…Üg1bãû0–KÉ#?h #óðáã3pQ¾Ž^_§Ä×P½qù½6…’ñah;- ·+>§ +¬xlÚ4.“]N1!ª”©ŽÇr¾‹ q¡üjŠL�uà”ˆrÞ±»ý)ÀJ�t¸X7"¬)­o³eIûUd‹ë‹¶�úIG�mV·k­È§|eü¨´ ïáp4x¦®C‹s‹Q! ðOž.7õ�}LF±–ã1|/ÒÅfŽª®—Ú<óäì;ÝXi‹#̱§t·8¸“pì+c¾¹a.׎ŸÃ&×XùA_^qÜ®ø ¨ósŸÐŸ‡Y[àæ¿sy_w{¶–ÝÓvœœ§˜ Aµ/Üš¿�mlµD½�õôtø?–q›I»Ü™k"/³wkoJ9„r…<žÀÔêȈ=ñæ´ù0¡v)ÜOØLжò¸Q¡œÏû)mV¸º¥wptP#í,ÛÀsžU“£F¥Våá•T�NŸÁÎ7Þ@ýéôÒå›Fñ”_¡ >%< 6ç9Š�aÿWŽx#r4_m ¨¦ñùÌóRðŽ=âêé}Z�x!.Tß�¡ÉÓ?HÕaç�8RÒ{Cº† ðEó˜´ä8!‹7i�ô[?ˆÙG0Jkž§CæÚükZšhúCLÝÿeú¼Ê?ðß n‹”pJè'²Ÿ´&œÜÁŠ h…F ŽS£U½{sdÑj¼(ƒ�/ŽC’¶Y.Wâ/NºR¿:e\¶k šo›,xžÝ‚3ÜïAˆêr^uJg=XÊ5·&á ã5|úå<Œ 2[ÜxÔ 3ÔzŸtÙpÙó‰¤dYÀþ«nÐ�Kfè·d§«¦³[²ïo±B²ƒê½ñÉ|Gü` ˜yÍ6\J㯲�”fôYÜ7m O Õµ»ÿíÀIO¨î,:6›£wÙ躦Ç-YÁpõ.}kÉÔw€f}»D£;ÂXÅ¥ôæe ©6¯À¦Ÿƒ‰‹pƒjµPš‰d?2Vh£QÊ–Xs%M¬ô=BW¦q¼�'×¾ÿFó’Â¥sãºI;6ÎÃû†u<|­›¨¥±«ïIÊkÂÍ-„À}Éÿòür®» ‚ä6ǬAdz°½¨'oŸþ"µOÃék•xñÙrôzÎ=,–§@ÛÞO´0ý6]´{JqÞ =ûí“ö‡óͰYŬ«¦Œ½ Â5ùlðØw]ŒW¿ ÿž¢ÁnÚÂͦR©Iý(ôhûÄyÃô`”Ïlp‰ÝÆc;FVTÚÍ×Y„ç]E«»å Û?ŒTZ˜¼µ€ž‡«½vÁ±Áàeh‡bÂðÍ­j( ¼†š¿vBñMsÞáÓ|Yf¼K¦—R@»ßЍe¾Ÿ›«Ñ¤Wì6šÏ4L¤Á'48h…�R?I³öðâò/‿�äñuv.]ÉÕw“Ù:f//|œ‹ù[6‹õåÀmíWéýÐt!{®.©¦›K&ÌÍ CÍŠ;~Íâït¡„°Ò¹»¢Ìþ¿¥B¤{„=Ñóx€¾%ö´ªÛqŠt¾Ÿ@;ìÜ‹wsti6H¥„Ë’‰`Ï'û®ÂqJ—`…G 6t'Ò?;vQqx𝠣ÔíÏÉéÔn�§o0îI>.¾ÂK�5ùúp3®ÎwÅîý‹«»³bÂ@¬íUÏò³÷‚õ…ñå*GV‹íê¶–=”Ï(|£œ±špæõ*¶xyWh ’£šÔ#âðŒ ´}y]Ô©¤ÈÞôÇAöì6£[ÁªpfÞ^¸sc¿ð×*•ö¸f“ëcO¸ÙÔSïdÑý¡Î{í$ùÌH!©ö‰°oñVØž€ 2×(ܲ›[8“ûüDáy“ª–ç‚f¤Müd +^£¯�«å)aÓåýØÀŸûPWé |:õ>ÔutÀ"”M!楫³_«)Ÿw�£Sòþ¨ÛV £·ÃŸéLó»ñ—Ôvq­«'»9¢›E<~°W·:žã[±Ž¸ì�2)X„sö¬½âß\áÍÁd¾"s•L%;q”³S/áë¢.ÉÈ¥ïƒÖÙt«Ç˜»!íòƳ•V±Pc»T{Vƒ{›"ÿñ~OÍfÏéâŽÖös§ïê_ "þ9U�ïÉþ³á¶DŽçºƒ9E xþÜ[Ü)º‡¿E�'O„w®gñâÀs$Ù¡jWñ#š}MÛàk¬yê‘á Lwd)>|CµÙpwêÜŸÎaËC±ÛúÞdk‡k�øU¹¦ëĈý87ÜL’DE2[‹|†+r¤åC!Ãf>u�õà ûJÔþæÌ^CÐÏk*ÛH�Xd‡“š‡ðå—ÿ²aî)ꎣáí¿ý7~îÇo­C©Ð!Ƶ«Hõ>Ö𯭆(�7ç¢�ÂZáÕ!XF+—Wx»Ðír%,Ê/€[Öñø'¨^ìžÁ�úàv¯záç„Õ<—&âÁw%œ�6‹÷ÈêâòqOèääõÒÛåñaM6¿Õ�!OWc8ì¶ ŸüìŽÖs{pFI2÷ÞÊé164Óß z›Éð¥�Å ¿•{·üÇkRÕ¹Zï¬H¨†u¯3¥³Å…s&`ðÜÏ¢ñaK ؽ?i¦Ãš¦ƒb¡B9LùeåÝV‹Ïf—ªÀ!ü@¡X œ¼‡eò³iѨ#6 ùØeÚLò�o`ĶÝôdÙtLä�ë�à­=¸ïL×­–Å#Fò“?‘�0RoD8Šòkû³“™+^tTÔcyËí%Üúi$& Öãy¿aLã~ÊQFñ#•ñ÷Ëþì™tšï¨Ý%/µD.m:Â%4$R÷ Ì9Ø@½£ÂïÞÄIyÀ×^êbf׿qÜVàlñÚ¿¬yOÇ€"“µH¶Ô�fwK€ûZ·¹Óâ$yMÝÀgFêþcØ?PÛå k½òÈ¡\•u'Ébcf$Õ�Vá�¯ôðvj$ <;3ö\à%—Š äõ>x`R"é{AÂVKË0Öc.+š­Å¢oj¼òÎ,t·É……>3Ø=A…òÅ4É»›'¹×÷g°Ü{8®ú˜JWêNQ…ÞT¾úKrÕØ•Rm…óAmT¢¼•ž}l¥„sóøÑÃ<­wƒÔ7¯Ç‰SÄ1¢Úd8ˆ>|˜¦T '_Á~¦ãðΓװnö 3ݰèNw4,,eɸ{ÿèôk+Ë{ô„y#}¸UœÊ#璘nEIÛ.бù ¶LÃñEÑjÒþ™‘�-�Q<Ü+‚O´ƒÚ0eØ(ܦçÓÇ¢åó7°ô^‹ò£\üµÄ@ZÓ�"ï Ë�}ùÊ"Yx`íŠ?͵éüã.èw' M…y÷“vk3<¾4›Ëöþ'™©2§ÜRã?Ýðfk8gàœ9O¾âVðM0t}B¿ôä±}ϪùG.5âsá<Ñ]è“ j>¼ôëiå|)õŽ&ÿ�ÕaQ½”þV€çÍ^äu„-rÌø¦Z+É”=—Y¿…\Çç¬�nÛ~Òòéà,1aUÅ.qd°ý (O2Å¡¿bù|¨@æïÀ)m-û0}ÖŸÓ*N’Ôjµ°y7ø� �¬nüáú#ØXàMžk•¸-ã?º¾Z�ÞnèÉsxq0�e‡ÑïƒÙª5Z|eþY�õ¿^îu-îØ%à÷Š;ån%èiÀe˜?ò/¬ÿeÀÄÍl1ÀK¤ ¶r(ä?ÇÓ Cu.T›Î‘¼­òZvá�›gáA›V‰Å�FSØ)Ö ”eù©àµýü\øO]¤vŠ×t‰o®³²Æ.ÝÞ$~ÊÖGcôàÆž^XUo‹›­OÃÓîv¼åf4„ÆÞ)^ùo(´]åÈaãîÃdñm/Œ¿Ï2m8ëë Xé²�îr®NdÝE>é4>oµ¿#«ËwÄ÷ºýyöòCà:ÐëJ5½³}Šï>¦¿ ã„��\ÕS™?”Høí÷vú0"\¢¡mÌI½u8EɈçåÅ ®•ÿü×gߦ`�ù(ýƱ/ŠuY.bE¯päZ¸°àÔjXü~17ouÆnÑR·Ô©4®¨Æ™w�cíhu6ãsI¥R9ø\þ(ÉùG‘ì´i(<ñÏß\!Ã]k,ÐvÜ3Ú™zŸ.}ö#ûa½…‹TÿÍ3@ï_[áýq¯¡Ç=uKÎ:·J(uØQºoX‚ŠáÑd¾cŠ"¯‰ëôâ9ªÑGr±`ÿ`§XÞö;v²«Ê7ЈØ.„Ç'ã÷÷ Â1ß�Ïûøˆ÷¶ïÁùWE݉!|Ål<_Êræì¯r(ÔKKIµ¼?(&�×Lœ§—ίÖf²¬ùiZ~¢ vAþéhž¿üOŽâƒÃ8°bïšø�ûïÚôØÅ{ñö›=ÜozÈù°ýÏgPämÆŠ[t±9Á–MnQ]Ëb.4–—fÿG*jú¢ÑØC4oÿ%Ñï½,7òBû»ÃàGe6&Táª8¸R½Ÿ¥þøç‡”מ>ùõFûí4ÏÓ§ë`÷dî~e‡»�C`ñÞ,tÖpòG׃òñøpCü¬×MµN’ú›±¨Í‚?ž^ üj ÍyÔBå}ÎÓ´äyèxau|Ì'³ÿ ¥iÊÝñsaoÌ^ìBY\Dù?åpD³3e»qà r“=aVå|ùJ$­½¬…ý>Zð¤­})qš<Ÿ•ëÇ—gß…^wLÐIòçìß„OÜøE�™¨¥>áýo’¹ã¾Ã&…²4‹=âs(­+S¨¸˜H.¾M¸ô€6)Ó\á‡ÇRܪ󄦊9!£ž¾\Oå-wŒØB©ž†¨�°ÔÍ Ç ïf÷dž’]Öž².½ ò±xþŠ.–—qœ¾1YþAdƒÊë/äYøÒ¶=w+F¥»ñaC…Š_¯±äv_ôªºÆ£»ábÅ–¤Ü&oÇK¸Â5�³sõéÉ÷Q|fš¿ï^æ­³°&Ñ ã¡nq?žQøHì}î5öÇŸÖuâïCòÜ8!¯ôQ úyáÝ…‰¸¼¬“Í»ñÑ5ù¼²vϪ|sl#8c·v…Ù¤v—o§‰Uûy‚Q$U¸ÌS¿Z¡\Ð|X6 ÍÌރɼ…œ>SËŽtÇÆ‡cí®ÙoÄÏÞªÔóÌ^>2÷€ðýÏnQ§Ç;8q´’{ÿÆ©îèlS u»h™Å_´*lÄ�}u°yÄ`±¸E‰ßÙNâ%–“yeQϧ½eùòß}˜)ù+þœ[Ä?zÖñœÀ,zuyêŸ;(Y»h%zÎx€×F—ÒûÖü¦«�½÷ÿÿ#SʲNh¹:ÍÝÚEñQ"}õ`WœwVtû©†éãv×ãaxyénR<ñ Þúè—;l‰£ÖyžY|„•’ú£s’§xÿÐWâ§sylÌ@ñ˜¦&”×Käó㡟g4¨oÒ© {Ïé{û1üë]ˆr¶÷ ¼ÀTx¾Hkg]‚©º‡y¦÷}qp€£äì–¬�ÍNùâà”7bäüSا¥õ£�_�!×)åš"o�OE¯)I¸ìvÄÅý7fã£;Q�ÇÀÈÿ&8u_Žª«æ OÕÓì[ñnû.¨ó§ï!),Ö�@¿Ï ò{­x×[ØÌÜ�§x–óùO/èMìA~è» –F§“m’]÷’¡HÆ;]Üqu© Ê_G½ÚõÀBüŽÛOGa¿«~Üw÷XTM×çîõ½x•弫Ã;&=Ƶ] |öì\Z5¹»Ýø'•<¢±•´³Ê©¸u(×)¦.‡!hIJ҈y^k±mTžÊ-¦Ï*¸h¦=i’?ú¿6Ý”PX¿—£ãmpæYøär›Ž-,ÞŸîWqqç~ÔÝrDìqõ>=ò•Ò'n›Õ�?v’»–5·Í×àé⺯ëÞçÓ¿žô`¹SYÃÆxɳúÞyCTyœzo Z‹CäxÚóüP_"$šFðÂ�qrØ©�/>θ Ñ+œ¸2l#ÿ Uç>*õf ·¶Gò»'>ññÉ=Y»I•-d±N´1è�»ìmøž›¦håüРо“ü5Þ ¸„Š<Ô<…ef3¸s³thõ ÎAÛ¹O~ Í趪';±êFìY’Ä¢�ºÏm‡'ñ¨3§»ÿ¢oâ±ÇLE®±( i&�¦üÏ B¬9"ÿ?N��å…ïÔź^œl‹¿`-Ô]ÈÆºÚ<8+ŽÃ+÷Á²J|äî%qü7mñjA/»ÈHEb-÷+\ ÀÇ9ß í¾ºÝ�þƒ*ÍNáÍ�qØZ–‰ÍO�Aý��pÔËI˜�£Í)ƒ41ä«„µ>Æ!OÅíhþÄ"ø»ð>({à7çxˆñˆÅÞO”Øfùr_£*múÍÊg“ØR¡§ä�ÆCüöæÝâûŠ86¦7ÿùpƒÍ´?ô”™ì”¾–ñƒ>!ý8ø¢*Ü Ý#4 äÞ‹ ð�*Þè=·âìÉ™\6€?*žÃWo¼9i|_ §âTµq|]%•g‹$s쇰&ã78m¿Oí…½9Jã.V™µŠ3ªqŠÑhÓÝõ¹Q-tvÿÒ³böÅûTh¿‚5ÆÍöîX\¨B!±Ãq½³'œ‘@{{졳��pjE‰˜|§k¾ù=ÆbKá�CrI©<“4¶CQI<{à…N¿Œ²£�$…,¬T¬h¹.r‚¹5/yùIô¼>ˆöˆT)ó�§eÉb±,9¬ÑC…üVØ3MûŒ;Êï‚ê tç>Õ’GOÇõ¼÷ã$Üã%;Oµ@jþ:4�ëD�wß±BÐ{˜­:š¼JkðʼnVz_ÀaGÕ )¼x¦#œ~ÞÁÆ ‡¹HOu‡MÂû«·aÇ·©\öf4–Ü­ÙÃé\÷³?–4f‹æ±ÎlD?£ïrmJØÕÀë3†Óˆ_¹ °¼w·©"{6Е=pÆò"y® à]©áx-‚yS/'j>ó—ÀŠÀÕÝàŒ÷}>ýcSëÿße%ïñÄ;5_J‚š"qâºõ¢ÊÔ²¥¼ó”‰Ö­‡�£“6xFs³a<�€Ãln¿›·^Á©ã­„cñ‘sñŒtwÀÛA8ÊB%ŸÝñ¨¿>nRÄÀ(¨‹? ³¦ïá÷aéÄêpœ¾Ì…+»>Ò¦ìdœp#zûY³¥²#ëYEËê‡Øå¨œa§ˆªŒŒ¢n¢Þòihqe ­k·1»¡ƒÖêó­Ã0e÷nt÷…»p›œ¿…bZçlNêv€•3ùÅ›·­mÞ^ŇK”q}ýdÜ:Q•+ *yÁ�PÑÞ@»¾,å§7ÒDÕæè=ØY´ÏzÉÏî›AX¼þ¶°•„Êõƒþ}š94ú \¿šœ÷ €0ÅÁÍø(>Ð'¹Qu”Rû#½�èÖš¹œâuRølš­§×²½——€Ÿ}…Õ["Y9¹?fñ¡þ©R²Í2æeõ þp“Ø7ôŸ?Ì“á{M˜j<œÆÞOF—o³ñ¢ï5ñ݃.Q~²?'´Ãφ¬÷ø"7+ÐØðïj©$ám4¯:�7\)Åžç áý3/^ý�6º IÅ ¬Ø)‡ S§‘Zévp˜èËÿ%õ² 8õcZ Õá9þÜØ:²©tsAo:«YH”žÒ%‡…€océVÃmô+ÔA‡áÚũ볹³Ù€·Ë¿â>3ýàèc{>Ù=Šužæ%_5Q·«‡L焸³ [V„a;ê¡ÜÒ•d+qWr—dÏÎDÊp'ôþ;‡�æ�áz^©Ec:gÑÌæ^œ‘ƒµ÷×⺖�0¹* zý½ŒCªÔ`šÿµ –Mî…ÿE±ñú󠩇ún­pª} L‘îª-½¥¥fûðù·GhdîŒÑ µ,‰�H UMb¸®¯0âNe¬ÝH¶Ç2jW»…Ï�âÃ/C9Y"™ªuÒ ¯{âÚïIôâ4,YÃîæïécC"þ±>LÇ_mŲÔ\~úkšž±áòÓ±¦í(.h–ŒŽYÅÕIQ/ lÛaZ`4×§ÍaŸùOŪƒ¥”)9K‘GèÃ*o’‘o¥y�‚­¯Ú˺ãÄžÁ˜¬•kRXåz½Øÿ™*9bNêt´>£ÏÞ¾‡ÞzH“§TI[¶íÂÔ�¨äÆmõ/pØ„£øþ|7œ›û’78S]Û-Ö|à@í+qÄë<ú`�ïŒ'Ÿ?£)㜦ÝÉùƒ áùOúãâƒ[fåïQÛÙê´³Øc@$oØÇ2URü9Ôš·ÿ öQÉú­Û̾E¾kV Ô£ð¾Õ8¦ñ ÎSÀµcÑýL9;6í“3"øÔw¼3HÀ^WíÑ8h¿0ë_M?ˆ²Âô­¥¬xC…WL�¸üïT’‡‡ÇWb†éqþ +0tmaÕ^[„Ó9&0öê5¨WëÇ Ïæ±S~:çdëÙݪÜɦj’ ÃÝI:Â÷íÍ„“F¬[²wä¦2EaˆO/”3)â¼²å({r4?mŃʵq‰ïy½x2Úå쇪 ;{÷bÏÙ+VjDÁé¬:!uúÊ©ó/‡{äê4ÄϨ+ü”Æ.@•«k©ç©Obq��óð•ËC|Ž3tkìFßÜ1þ\w;ÓÎóX´1�zû9s•G\´WàŠõaঃ{?má|Yy»Ñ?ºhSÓÛ¨ �4º@<<‘À¢í$üctU¿tÈÌ(ÙÕƒ±åW/;Cɸ\uÄ7àÏÃp¾`2*>ÙZöV!&숃á×¼p—^†õÀ-Ù»pœK t>½# ëÂ6“V#å›ãêæ¸t[JݤïøïGMüxÉo0"{Ó6VL—·SÕŽb¯«—Ù>DôÜ�3Æ(ažt>�{þ_ýé]^Žéµ …>l–6…ôœgá»ø:að LɹGxPH&º¯Í:¶q˜âþ¯ÏÛwÒëüÝàÚÁqê—°›aK�”­yIz1Kù�¦˨T–5?uàÑjòhpjÜùhÆëÞ�q.áâPïÕ8Õ_Â\zá£9×9#Ú‹ÍÆ¾%ÕÒ$ š?…i¢¿](.‰ç'¥‘,ù§¿ë¾w·3ìe„jì1nÍ©úú½|sµ:~S-æ`Çð² —LÔêO¯ª–°«ˆw3—ß6-ç+k9~Â_êÍ{8ååfœ+F³¦4ö$§óÁí¥ÐíH U¹ç6!ŠŠöÀ»Ðó¼ëí&Ö-ìy níâ¨În¬·í7õz[ u5¾¸fU4šöôâ§|D—>½x`Ûì«ËV-À�� ¹ïùÑègUù V`><ÖäTAXý$IÿÖ"qÁ¥žâ›ñï(«Ëj&¹p�ÌZ<.Á“Ö0…¼Q笯¯X~°/ªá§ÅÑò²7¼Ûºèà¬Ë¸­3‡vÛ¦â3Ó/P´ÆD7Xèºãþ„¹´ ýº8\å2ô~µî̶>Éÿ4R¨k¬v's�})ÍÜB !Îøã³%€�:žp̨Žó⇠*…¯�ç¦ïÆñÕM �Á_þŒ×Óÿì„�Ð'Tüº…ûèÎ@³ C„i³Úmm}¬°uL5ŒÝ� äµ9ÙUPW7äWßÛé”ÒN¬‰ „äµ€ÇXà —�¨’k†ë÷ÙñÝ7Q.ø;Üœ7ŒçËÖs°l88¬2àð EŒ)Q!­°HòWU…M�&|(ZáL,Æ ¦ie ¨WÆ.‡†ðÏßúœØ¾ ËgÄ`«íhz=h7DÖdqËFû¶w0½c-œoûF¯Õ‡àqEt}Œ!lÔ�÷F±¨æÙF¹C_‹ù§–sçmuX²7þ–ú“ÞF+¬|’Ê]BHsX> :`È­6NØûã|X6C•ÓæìçKS8Þµ�×|Ñ€G¤Ì1£¨£›)ךl …tòQ ¥V¤�‘ò]ô)ØÓ~úÀûsiT¼è(¤³.Úâô�™T°!m÷ ¾@§R´ÐoBú¯û$:Õ�ÑŸ"x›ñu²9çúFþ¤˜.T÷¹(6»ãô;ºlúö9«!¼¦À¼á¨çésöLÜBõNâ!³rxq›11–ÚÚ"¯Þ�ü0ñÃ#i\éRå^GsÚ”ÿ�Å>ìûT÷kjÓ‰R Þ?[½¼°ùÀ"ÎÛH‘åç1È¢™î+xsL”%¦Í8EÁ~Äk1&ó2îê|NÍ©œþ¬Ôû7ƒuÜ)(릅eü8i{$9ÃsqôÏ]BÞ¶þt-æ_—¬Ï]„‡ÊOâÓüÏÞ¦†Û§ÙñÍ—Ñ ½mY…÷‚ £NáÆ|G–8e¡¸e&|ù¼ž“Nœ¢ˆ¦Ÿ¨ÑX#œÿ};uìqr÷HîZ§~ Fô$¡ó”ÕbjŸ¯$”érÓ®Áõ|-:5ÄÒðüÛx`ç<¼é[ 7c;¡%á ½´«‡[�ŽRBËN¶5·Ç®*˜ÑšI·wËñ„¾Mîþ�TÖ†›OrYnÝTÞz‹ªc?àÑ>)ø¡Ø�tzÇÁ38 ·ZÌœy†Üø@E]�Th·WYèp\œGHê(ò] ´VMÕ„Û4Õü}¾züÖ¥1£w²gä>Œ‰O¢¾Ôzð,ÅÔ_…�Gƒ!8ô +™Ë7`Üî ®_ÿ<Æq÷åĵ JÖá<Õ³‚ñtšdýgµÆpË¥Z ŽÍÃ’ÝÑ0Ù,’µ“ÀéIŒ0Š ‰ë>p×êˆÒŽåÖø6004‹ka㎾t,½?úDßG»&ä6»”*¸£ë€ïÔa°�ŽOpàm‡óq¦J ïÎxȆ¯Ýá¥t!¼2qƒÖôVjºí‡7Šó8jõMQÚã Ojî‰ùãÌ8!®œ_Aï“/Òž/§ÀoH1L|³ üãU=t)ˤP4‡ã뎃*¿„[+VâÈ«I˜zûÕ¿|;‹'WÇÊñøpý#Q~‘z}»ƒâÞaXð0ˆ –ž�Ä‹)?�¡Ç®˜Õ¸Û3N€±©„�ŠâáÖÉÔœ=-—êñºž¹pÔ`¬dÿ éØ3ú<–ý(„v«kBÞ€Óÿ±ç"*~ÒE‚I9× ÅÙûŠXx¸b¢&Á¢�%äº9g´ì�/V/`ŸÃW€Û·¤,¢AÉDüýnJjÞ… ?sèÌÈ nµ�nÞù´ ï ]oA’I¬#8–„E}z’VÄ64î¯ÀÝNµÐP¡}Ý´xâ›S<ý¨%Ï;#kWÁ’“ÿúZb:Jü${G¼˜"(kÃÝ)ýáÛƒ«0ãà�[ã7ñœß `WÓ›öç¡öMôÊÖ愯âÛ}ôñû²)üþÉ\Ú¾ nGg‘ÁÓýSMòÒ+áQÓY”õ ¿sãÄ!%0»ë ]Ä^lž€÷jd¸¡¯&^ì;•÷ou£WT¸Õó$Ë@÷ËŒåÑcÇp‰«7ï�1ÓöpÞV®úTÏ‘=àlÒr|¬á*ŽÌïäçAXï…úØ“jz³åû&hVïƒs1ø¼)Ü,Ì¥—5æXø§’\cbhì°=8ïX ×+í Ïún$Õ’r«ÿ|\nΦ+½èn�Á|X3�OúZHI©~o0€¬_sài¬±X2,žº­„1#vÃõÚ)bTa2[¿éÕÖ3xóÈþÒ £\%1æã¶{Ý„Áj2^ŒôSs$:æºpjïh8w\-º  Æ‡ýªZèSxÔ\´¡ŸJCq“ò7°OȤÄî¥\^¼ªßì味åqèâp´J?À™˜BóUdÙùh9m-ʇQ— ¿!m�ç4&ãáóëxèð'àZK[|+Á'1…Nùß�®XjÊï_cÀË<вàEü°Ù·”>ªºIM—„cãætºÔ¯Auý å¹�Ä/‹^Sè£Á8}üfºÕÝîNuï�jÛÃ8¬�6)LüK¹âGø8וï¯&?%\;Ö�—«ÐP ^¬qV�€V™£é�j.yi¸Q÷"E´Q,�=¯g’¥ÉÛ­MH4¹ ­+‹Ùƒ®À½¸y¤-Dã|‡É ÷ß1FÄüx9Îy¿Š£$v|f“Œ TF¥®Ý8,G÷¬â>%™uuËG©`á™ÜÜ! z–¾ëw&. ¤a+‰«S¹sÞEÚ¦2�? \ÏÖ‡ÝA­Î/öŒ3yboë5é¼Bx›.ƒ³¦ùb^p.¸—†AÏio…†ÝQé]_v-[“"?QÅ¥ûÔá?çØ3­9€Ç[Ý÷ƒÆ%<ù”ð«V3MŸ§îsyEŽ=·ì{HÔÜIãót°‹#—OéØõ_°:¢†v^&�qe°¢ »ö娉èý=�Ç·Ú²ü }TÑ�Œ»N…“÷ÅZQKfÛÌîèPz›†„”Ó"ûÔÛð%~8-n+XÀÝ6}åÂy:QÏŽÃVLø¶ÊL»W ·{”ÃÇÂ\öžüWȺ¢ß¾-§#u°rù8~WöVô÷cš[ÀHÖt«jF ‡¤Å²ƒùÞ‰¢˜.ǶÍ Ô+œÌž|Ö, «k#¹P~ož/•š %à!ž˜n‰K½Ó%¯câù#îè0á8l ¯£JQä¸7†e¯í"‹Iæ8ó¬ôv’Á^Š“ðqÖHÞ�ÎøˆÖ“΢e[lꃒôŸ`.qæ·§ãÉ7È>h›Ý¢"_)¹8]…Q•m”]Ò‹¿²3Í•«Æ§Žc Èl,mvå*¥m¨¦e�Q~Q”Ör­ N'èÖÌDÞØOßü.æ�¾ÔoS÷5y�× —à¬ù�Év]-ÎVß?÷¬xæ„ë†Îãà12¬ÕÜ ÛT*øYÙCv9fË{?ÝÞ»��ÓB^{’n¶Ãì¾ú|V×�篣‰6ñ]¿ ضè_þ¼¯OWÍ´©)õ“r# ý;„¼û.ð÷«-£‰( ~`-†B¸týù*|5õ5¼RxEçmÊÛ?_,ÊÚ&õ¦À­éâ©’µ4HO×+ ßì¢]EÝÅA6;¡ó‰Í_õÞ ¡’‹ÕîÂôKªhºñ8âºÏoÖ�÷.yÒ8;³6ØÑÒâJØ¿NŠË{} ß#Ù$}QÛ:uخЖ¯éGR¥d9Ôýðâá½iÅžé\¼QÇî~ MGI½³‰ íZ¹ä×6~.%�Ñ�7Aý¨ kµÿ +²¿Áfý:ÿÐÆdÞõÐ:»Ùʯ¢œd]ζj˜€Lë—§Ì97DºGFÂ�–ƒ”Ø­m +ðOã‡â>ÐÌ ÷™¥â7ý`в’fKÏ´&<•}�‹©iH?6xÀù‡…�fm¢sQÉù6¾½"|»i�Ù.zú—者8mv2~�Þ.Ö�ë�Y‹Ö+`èã›x]©?=�Ê3Ë#8°6Tôž«�ùå÷Ä3 /èø?tÎF÷ÑPöÝv¶ºÃ4ù~¼vÞ5úk»§—WÁð šxçùM2¼îÌ3Wÿ"ù�jBøJ3ŽÏTÁÔ5öüžŠÒ« Ù±ïYö¸¶žã,ƒ×fn°á\?L ©ã –‘Ó‚ãØª>�Á¯H8èÍ>½ ±÷ü3|S¹b÷P\“ØêZêž!®p8^™v;ì³p[tÝ=Ö ]$‡�SÐTÌØ¡ÎbÒ^7°Ž÷IÃë×½1Û­¿l "~ûUÜäû4Š‹éÍ!i^rî êϯ�µ'ùnÛY¸z"+J×áÃ!îôçK”u®å ¿õY{ÐPìÎTâã»óYßJ³¦ì啪cyub*¯¼qˆw/Ó´Ñ÷A ¥¢¹žoÚRŒ™ûvÀßWw¾ÐŽ“môûæ^ÊÐëÃ9WʿԆE¥.Øq-Sô,�¨2 ú U/:agÔeÚøz�;€.ÉJ¼·„7ë·°Í\™.?ÝciA¡€Îs¯b�ÕW*¾šo­YÞÔ­�2©![-+ìܯⲩû`Ól߇ðsmyv4èæØ;è?ìÅçöã1ëcqÒ?;£r„TÝeñõÓr°ãèÒaeq“kÄÊÎæØIYý‘ÖÖ6NÒ‡üÎx`Ì è#è §?äq¤ÆS2×A™Ž+y¦Ó"Ô‰ïÊ[ uÃîÙx]X|ó/Î’˜�%~6 ¿FÀ¨öàSÚ‡Oê¶Ñìà¸Ö'ž)yAOÜç¶. �e;Xª6 ô¦×QjÏLV¬LãòÖ&Œ;Ÿ‹;½-Ðuí\ÚŽÖ‰ßfá¯÷'�?ÿËã­±× %i虯ÂEuItC"ˆòÃI#" 47_§^?ƒ×›údœÇà»úH´ùÇ?š€§¥�ÀÃÚNØ®0S|©ñÏA½nÀ©8þÖ1š‚6¤èþÈM$¸8–}í—Ñë�¬vÉ5ZV°dåxp©»ae¶o±hˆ«qf÷±ß+cÔ¯Lãyᢡ�$»¾wCïš ¸«µŠ"^?yÚÂwGÀ2’`��p®l=>mß @ÎÒîxdî|¨ìŒÃm±Û¸~Û5ö6w"�3K±…+1ë¸Ô*ºsÞU'®óœ‰-ƒ®ÀØEÆ|V,[ì¾Y©ò¡ û7ü:ŸZ°´¿ŽÐ:ÖöÐvj»²‰¾ÉÞ¥xó�\ºè†ð 'b¯›»iS‘’Õ÷Q­ ñ'�]þ±Ø‚!wú¼©F¨2Êæàª‘¸he:ãÁhÜûªˆ)ܾ<‹”'°ßÃTÚK Æy|aÃHYQÍ3Û`P¿`6®Î;åÿÀrûch06ƒK³·°Š¯ ¼�ßëèømx ZxefF£qXHUfV€Ë'Á²»ÎKŸ!9•=V¨6kB:Mî7�50ÉÕÑïe¦¬0,ŠÕ,lÅ c6qÐÏÜOó)]Š‘ÆzÉÁ4K=™/­NsiýüOQ™n”0AFÕ&Š'ÂQjº*³ê¿Ýï«N?/u€t¤ÿô™Ï¦;×ÁÞiûÈga/½'^ôž9 · Ñô§a9Ƚ P¹"ZÜdͶÀËopÇA9vݯú h,Û�Ô«ò!ú¾OËl€�ÁJ<¼ šõ›üEe¥£è:)‹?ô5(?·kL¥ËôAt*ÞUÌ|ÖLÿNa¯�9à5¶¦RBW$= , [ÂzÚmh£jηz4QÿÓF´K¾Æ {ýð±×AkÎ]|g»ÄÔàç÷*0m¦Àrî“¡b@2ØÊÞ…øÃ᜵z1[‚¤\îß[âRI?þâ’ Ù=„†»0bˆ n~·Õ ^ Ÿ î® ¢·;“EyK´zë?€–ÞÞÇ}̆ÐÙNTÒ,¤ ]ÏéÕÖûм-L°¨8Æ÷ïÀé]ÔY˜omh…«�oÃÛ»àÚ­Jœ„ç·ÉN•ÍOÑ2'˜S_ù7ÓpÇ»xÁg_çÆ‚´êdÊ|f‰äÄõ}¯Bç©Ñü,­7F¿ú ‹ä£`Ѓ£t,ê,-}ןM¶Mœ#NS¡ª޽Ær¶˜,UAß6Íd׋“ù±ÇfžUÜ$DÄaáµ2¼µ4X¸¹o0Å\$ÏëV0á›;§ýð‚Ì­Ý`ñRç ¼ì�!gÏ­�±ù°dm*Üõý,<{ÒL?Cn‘5}±Üè*ÿé%C�™ ìZA²±ÒìâTÏæÇóhãéVdÅ©™k©ØXL~`C¦'oCÍ…C8Ði<ªÊðM!û�N†C¯—R¬£&l0ˆ€ jÕÔ®öK²ÀÀ-å`ñ+Ú­F³]U:Í4BÕ]îütË-Ør:®�$G¥«âÄÆÖ^°„£§û aú Ø>ìÈtÎ}²ë/!Èœ;?MæÒ;Ý4œ­=µÔÛÀ#½7ÎX‹Ã[àQÀ4üzf/æët‰yà¦Ñ"ÞòŽêkÇP¦8 5mæbüT!o²6dià†˜š†ŸOoCñÙe Ö„žgóä–ÅbËO~8ò NZl‰ ¡\â9“3^*ง±·‰X<£¬9òèqDÚÆí¯:žo™ÂËÌ}ü¤øÕ2)vSu$™×Ú¸Õê4_d%Þ“�ùïm¸)Èœý]’°]ñ® ’½Œ‡DmËTª´í+[O±µXɺ5á=T›mý1ð0{õ¯\üDç^‘Øö]žÚQKë>>±¬7.[4’Ük¥žÇGq£;Âà‰}ðýõW”•µköáÿvÜ¡ÿÖ|Õ;–’ιA8nûvÜ'ó‚ÎLE­¢cbÛØ$wéÏ7#¼êmm?j${¥-Ç >"錾KöÓÈ…¯’•ôfáò ¼J7–|×x|¡=÷Çc¶TO˜ÙH×þ9зÂ,\ù¢ÚzUˆ:šöç·µ)¼nß9~^uœ4Ìbi]›|›�ç?4‘ljӤ“æÊ­_àöö|ø^Jµ÷—Á�1;¹Lå|Zñ€É]¢ô[ë¹Öसh�ç+˜‰Ooáu‰ãØR&“ƒÅɯ øÐé`Ö~pZ‹sË÷ӞˎXê)7à`ŒÈÍ/ίMæ%Îû±5}IDëÁXY$‡Ierô|Í^!úÂjþ�[¦ž¥Eç›ÀuÿxUŸ^‘¿jï�šÀ3–Âì5q n“Æu­óPñI(ú­qÇþbùÆu^Ÿd€q®,ùíöì¿ ­§lÅA~”~²îæ@ÊÖ‰¬¡\ · (a€#ç%…°±M/Åh#è¬Oáq')Vb9~=õ Òª•pÆÒ!8ª+ NîK•KÑÜùC±Mbt¥ÁÀÕìѦÁÒy®Vô([ƒ¾Ê8}úl ³„M4îàRN<ö~Ø\£¹;ż‡³Ø÷â)ˆ{ù‚>½9 /#nYË^+ Qƒ¥p©îxZÑx¸r@¬ ~Ðõá_Ó¦ðƒa³XÁ¹ ~líWg8[g˜¸V™hpà¿}Ñð¢dì¥m {‡éW̹ùôõ¡a^³ØÛ²¶?hãYv¬²GMløXG÷ãKáæèQü+;�cKô«¦5*‚ztˆÝV¬Úì%6òñÒµŸb¸itùµcsÈsj:°‚Ÿ:¾+²Hèk�Î)ŽëðHç&xÙöV÷¾Jµ§RlÊz'‹­.a�Î:I~A÷4\¹¶Œ´“òÁWÊŠ%Ã%qæ�XŒRJÀÄIvtgû îi©¢fcD]6ÕmXO*}åù¾§ 4gåÇa¼`\ cø¬÷všÖð^�|7‹c†÷Å!–<¤Qƒs-’8hÒ–±X{.ígÛ£³xæü*’•lÿÚm‚ƈØ&·?L/«¨qHvìMÁ¨¤›ø~¹ï9��“ßQÀÌxŒ²ŒâŒx#¾:‘›´¶`?§Dz©x€Ë3¿‹�{×ÓÂÿf …‹ˆEBâz­¨ÉwJ;iØŠ�p,IQÌ)ó¢…³ja�ré¶&ÐÌ~' ³Hkd•а—?íºãˆõÿàA¾½[}ŒÒ*6sýî ²Ó褢•^‰c“=øP—=ØF{Ãñºð51‘%šBIóu0y…rNÆ<±üì4rðG-Ywn]¥ŒÍÏ@cE9?ÿsSÐjj"—9øk…Nÿ—�ðpîsŸM{3fàæo¾Âã{±èó­ë-ýhMD8̳‰¦Ø-Ë)ë¥xæŸä³{²hÚe¼½VÁF²s7u3ã(³¸!4Šhlú»âòƒë°"¹˜*Îòp9e�µ¬m§Ñ¹ë)´$|'ûæEþÁ´ZB“ûÅXò½�+xBõ.h�ÌcÎ�®Æ$úµv18Œ§ôäùUr�hÕéÊÑ·?Ç^â„Æ –[=ó…ÊÜ0Ëë½ø¥¢·8íâH›®BÆ'Š`ÍÏ*2÷Ñ€ƒENø¸?u/ ·¯ž‹7JÎpÄíõU?vÌü ëÔ‚h>´SŸqA¨©pD<á{wM 5ÿØhCG=˜eÌ F€îoÖ#.+ ‘³'þ÷iš}šAµS¢@Ñ?‘ë£vr†ÆêcAËÄüuãzÂ.‘èàŠÞ›7ñ u³¤–…g¯ p—*-·=}ëI}Ž £o”˜6¾7?¼ÞŸÂ†Gq§'= ôEŸ0ÎÙøÞ}ÛË«}{/�qùy*õ\ƒû# ¼ÉëÚ":ç5Ç+®‡}0g.µhÍçüÿ’à¶s‹ Tö›–n»D6�‡ð§•™Ï(o¿'ÆyÀŠ{T }Ë·@þŠß`3)ŽTZOÐg^RØÈMÕ¼›K3à0eEH<¦Ç{;Ħôx~:c2�Ôæ ;'òó?Ö¾�¢ÁÐþp±Bü ¢²ä÷`T?~l:JÛMœ`TÅpuË&?çé°2ZiìqœcxŽÖHÆååÅÐaë×gšÃ¶E�ÁýŠ5¥�ЄÿœÈÌô¼âÀ*#3Ù)emÖ¿ˆÎUö �Ð2t8.ˆm¦‡ëç°Çºo¤wÕˆóã#aÝÕB*‰ÊDÃX7hØ~Œ«çíÃÃó#XæSÏ.›çnþ”’<Æ9¨¢ô²¾(gλմ+ Uxí•§uB�ûÔ“aš >9x ÷Îöã [&ÜÜF/žTM°ý<ã÷10N~„Öa¹Ü÷ì/Öªÿ Þ9´=+]]êñ·Bž8ÙX4|,òv¼-:½^M“ŽvÑÍä0z¡IïöéXl¿ GéE«Ó“a–ÑuÖé[(®oi…é}ΑdŒƒq˜¬BÙBÓ…Ržs~®YÙ×ÊÊó¾¨Í‚é£ Ñò¨6/žâ‚£WWj}ïƒÙñ»aúÍOð,±žK|¯ÒäÑU¢Î»hšòCX�óïÏŽõ㈣«ùxg xÿËÜÀÅ~¤vÛ„Ò¿ÃåÙ¯¨©è}˜0…W¬ëÖîeÇ}ÌÎá8ˆiñ¾zÓƒ.·¢Ðø‰=¾hùHÙó"Á>à0æ9[㵡m¼æî6aïÂj˜ú|nº¤Å^ûƒèÛ�œµà„ Ä4 û‡J¡Û’¯ââW¦Øodx«É°‰á(ìöMîK^Òº «pªw´x7$‹ÎL¸Ý6Q¶u0ßû6î>Êæ/£NbéoMê|ÈOzK`¼bzõöç?d`ÇŽ±d¡>MžµpO„G¶Wx¼îEK+ó›‰ì*�ŸÚ\ye�!]µÜÃWû ÁÍcuißÕ Ïªqüñ‰-Õ/âÄêŸ÷ì½H¬-’àÝãiaÓ_0óº*슌+[e�"F?•¦´Ÿk8ÒË’-UöpŒŒî[0BÕ0 °iø1ÚÒa„í+WÒpí'4»Ê–g(òÒD§>?�ޱ_.’Fõš~j»˜{­{!8"ÉŽ5ð`§t•Á¼a4AO  Ó0ùÍr,/n†Ëü ÍÝîp*Ö,â@go2Ÿw.WâÀ|þJÜÿ³®¾$žß´Œ%ïtÑÓ÷Ç,ipiHƒææÉ¸¤`;Õç-çðîµdû4 Bâ½!ÌäøÍJEÅqªœV}:uâÐdj/Ô[©…{£‰¦5u¼öw0´õ婎X¤x™�?êóÊç!\RÔ‹”®O%ã‹»]$)gx4T)¸Ñ Ú°ó~Ö¯–|¡Ú ãPbÝj˜^{ï ÞªE1â¯ø“0s°|[GÅ’áí1(“ºD<¢ô ÚüÀH«Hèþ:˜ó’àC¿{táêwê-µ„gÉÿÆSC3¹¿ç^<:n;Z‹ÃãñCüDÁÿÖ$´ü¼í4�RrJ8éÿæÊçãêX9öýìNMã­„3NÒOµ4H¨=K¾Wƒb¥ /þÇYN‰ ; ‡JôÒH±»kOî-ìaÔjEúP©Â®¿^A®¡!m|ÿ’Oi¶Vj ºdV•Dj „ý·ÖÓ€h\èx þ˜ÇVÿÍáɉɬY¡‡Ù·"ñvT(é&ëñ»:ÑçæVW9@Ñ3ÝhhÇNV#CzÅÿ±AÆ^üûè:F.MA’çûß‚Vo Ìš>— FfÛÞéÁµ­¨½9’M¬Êè×çÅ0Ú/�†öã�&;P2çÎû¿Û–T.ÜÊ3a‰œˆ_]ƒÄÉK¾Áà}£IãÐG¨—•‡|/ ¬éž&Äž_…ž¡íâ´Ò,uϽ‚¢Ê“Ôü$€‚b<ùIjg/ØÇ{ܲëöpzQ�Äi5ûù×}{L¶—åÑÝ]œ~O—;o”ÒºíÈ¢åžÕ 5™àò'ϨkÜ;Ê} BŸåüj´½u¼ûJ´ô†?~£•kxÞ[0� ææñ(Ùµ£òHà²9uºŸ¬ÂÜSiìy5 v܈à‰nŽ$¤~¢õáâè_ÝÔñ¡2£1‹æŒXÈYóEé;ôvÿshÛlkŸ`Í�7ô;JÝÊÖóÚÔ1lÞS^arà^×A´úbC^Gq)pNS’+·›|5Xu©7hèZð]ÃÝØáŸ+L§C_satä8öz�Í+Ë$oZAŒo2/M–ÆæK²4Hªàßn¼${ã@6�XYþð$\s¬ÿ瑾%ò(Ö&Àò^±<ðú�ÊŒ Éœrf[¥[…[åÐC›òÊï;­âµ, žÒÒzÕðqNË\²€§�Rô«µ&}õãÆËóî+à©tˆkcÓ©Øþ •W˜ “~ !ý'ѹûÛ1F{"´èá )Üý6‹~.*ÞE\»e�ø,<µK!aÙ¾šq:Q¦yãòù’FûÙ�eµ†ècWŽíu:¼'Ò ý³Ÿˆ¶]–Øù5«²î³.jŽBõ3¸¢N *æ«ð؇R¬úÅ4oâéGÈuˆTUŸnGÔS¶DÍyIPõ#?Ý Æf·q@‹CD·Ë‘ iòGô=)Ê=Õàg>ºüZç�Òz)¬ÒÚ‹ûþ9ÿÄâë°J]M¬ {_<öV:Ö}¶6™�¦oÞ¦ßÍFü&—çYf³ ž²7´¦pùáÅÞsĉŽXŒ ¬æP*Ì/—EÛŒ'0©C‘lí¿Â4 N•6à¤þ[‹çY4ÐOuWøsÖs v¨õ¥_J\û•Œþ&Öœš†‹Ž»£LB¬Ö–Fµ²±¨°cž°¼óuô[„Ò‹óùǸÞÓ›Äýy·•ŸUJÙ²†Bdû=ZQU†ººà7ß…ô‡Ú\ŒÇû æxMº�_µÇ }tÌé€E$- ~Å\w.*ú ±Éª¿�çÞ'°Ñn³)1Ý•wzÞ@ÿKo(ÿ°‹å÷ ;¬“ŽËú‚mAª»+щ°Î켄ëæ=6“g‰k_•¢G¡!Þ(OæßM5,™K´Hê 9‰NˆHƒæJCIÂVTÞ1„wm‹‡9fÙ(ê ¤Öt²éØTÈ*‘³ùòR%¡ÏI9òö­äg׉ëMs äÓqDõ6:º V(Ã�3ͤ8b.¶Ì"'÷9øõð]Ôr9ÊSä7AW‹*ÖŸ• ÇŽá㪶ø…VXÊ“?¿¢ô6•Þ�Y¼v îÛJЩ87Ô™s‰·gëa@œ&ëÝ5°™jнöþ{Ÿ¥Ã¹;ô Hž��¯Ë°9³¾mœÈÆÅ²ãð\èµ=`t šxê{ª"~c™³…„ì¤÷ߎ@Hš>ר èÏ%ÔžÐ-Þú7·VÏTüû~(‹£? �³º+ÛÔÇr‚¶'õ ¬êÒY)« zRÜ­ ˆ×’Ž„^'•ýÝtÓÁs]ý`ݸ�P¸S¿ôÊ©lHÆ£ÒGòò ©ª1ç¢ÐåY7 œÞ˦*pJj§ÈÆ|ÞÈT¯ ó¾oá¤_ÍT1à—È?Zùšú Ê�á7e&X0¼çŽ)ÀžYרBë!ø»(ñ¤ ¾SäJ¤Ç‹¯¦Uð¬ ÄeUÒU?®ãÈ^3…ÿT«…7·Šðþ×x^¿æ>(fâÛ®z»ÑPÌžcÆŸÕI¹Dž{,㦯ça[ë ~Ré€F§Ââ�Y8Gï6©Îbõ-k!ô �_¥)êڱ׎VÜ&{?«œíå£)7¿Œ�þjÍö—°Qv°¨%eŸzò¸`Ä�³¶À«ßÞÓ…‘É8íz0O=ÉÏã2¸f©~o á<•óâ _w œ�‚óAÁ„eXðî-ÝòŸÏ¡21ywŸ¾ÅQ/I¿Ø¨ê­ËN*žw·ÚÛrk¸ôÒÀ[o7Ñ·>¯„…û:„+�ñž˜.ª°*äkIGÄ`ÚŽ»~xbÇ¡É#ú¯û*~?RO¾1‘<ÒÍ“ÿÊ‹ð.à¨%ò2?CÜgú‹n~3âCZ¯Xv¥’Mn±gŒÒÄa™UT÷ò n‘íÃ~*ÿ¡î†«¨–R‰�F}¤’÷GyAÝ7êø�y¿Dõîù¨8G.�ÄãÅ™ÝsB4­+¥wì¹uß=êû%—Ò;.ð ‹©|qY"VŸK«|“øE°>|k*VòøW¾8,Qþ)¦ž«„˜¿ ðŽ�nTãß›ŸÁ©©´sÐU!@¥N¸¹-ú´½[ÕTjpu�—€ö°n±ØÏŠ#^81:9ÃãÊ@z·i9ïê¥B§uy†I#ž aéwfø±Ï~šçü`n´õÔ[ ë·)döW@éZOºô²�â¢üIÊv5G\ƒ®Kœ<Û¼jPe»Ý.æ~xÞÝ™â¾+ヴ¸4ß’ƒ�ìp}hÍæ.®Øòd�ú°Å¬"ñi“”MWì@¾{R‚¿ÃPÀ”)ø$ÄÔÊõ‰-øÝ/ãÇ+ó@ÜÇñ ëp®†=ïi_ª–¦ÿ€+Çg[_�7%¯~O`É ëʽShõœ=˜¾]²¢á?ßþxmZ/Þu)’ÿ(àfåÉü²_2¶ÿãýS_Kx¼l+ÉDqR½iPçU5|Ñ)ü˜¾ç¸K°ÜKp¯­ÀSãçC€G.ìóŒ}ø.|�/ª\¤?•jøp`3¨åMÂzÉíP!í�—ôµ–Z·Œ‡onŸ}ŽÌ¿a€ÔEÎÑ‘DWïxš£É)…çA7ø0OšÀÝ'A×ÅK~IÙŒ®'®5WÇéOÞ@Žý®/wÇ!vY¢´«?Ûm›Íw¼áàĽô¤1�—hÛ‘òš ì½ê&.צ•ÓQåYõ.T… É~l¤ž�–‹òŒÈR•— ±Ã\0µ^ŸÛ2e°ië8ú­Š3‚c„QàÅÎåZÔO²ï¼;«Ž¡¨Ï²¼üÙ*·Ÿ�÷ËAÂL†cÓëDóÒÝì—¯� ÑÅB©x‹tjܸ;.“?î=DƒÓ²*­·ÖaLŽŠ£9’acé(Üqø0I*Éò†ª(mP#Êê!ÍxL3Ré³£ªÍœgwp‡Ërvè–f¶/gý¥×áÐ’F”ò×ÀËÊ1uò$äþ ^óS`ˆÑH<÷c'&l(t_7açÁÊÔþ¤"ûXñÖzv¶$!î‘Ç;þ³Ä¼¿ÄÔ€bvÕ ¢ ý6ÁX»t|$•Åv¶î‘<ÇÍòÂÂó»1M~0*ÿ®†ÑQ:x8±P¸7ä0ì¯â’Äó(ûµ‡g=Fÿ�õ þ>Å|âF5_Ð8Ç÷¯§`»Á6ëbü0Ôs8L{î€Ï8ɺîÉJî»k<9?¶áW–y¤­:�ý�ÊáÛÀ1�=é_vgö§Ÿ·ý›ÍÛÚ^GRk³ß´{ü9£”*—ÍÁM5Ã*37aiÃ!~1b† ·!ÅÑì°Â€<~n¤:í±xAç ÕÉOÛ}&pmbM¶é¡óÅœîµÿØþ‡›¼Ì)~å¨y[†«OWÀ¯à:¸ðë8Ì @G¡6:”£kã4óUœ“Am†¬{¡Фz‘‡—%G´ži¢»tj®ÌSωÔÜû1ºÿ7–#{eó�óî´d¿+F%D¢‘Â6þV«ÆKK‘GÆ$ší¨f³fæ"œ¡½óÞAc=ò-v8bÍívUàU8�Ç>�¨”üFR+zл çº/¦/Žåü¦ó-ë*NæÒóy±õ(JžÄW²#¸�Xs{¦cß’6‘2é|0Q £nõ§>ÉÒ6×_„€êþcóµ’.Úý!× U޾ñ ·þÈå§×Àþœ}¥ÍC}1¬Ý‰ÂûLå<ÕçètnG¡Ñ÷E [܈ó-ÎÐÜ·z6c Úñî©ñèo¹šÎï�ƒ«­Ø}/FJ˜ó¾é^xåê&8>/wÊ@5¥-˜b~‰í#Jh�äfª僱vÆ�+¡€Š“ygX'ìIÆ çï¢BMìØ–ƒÃç’Vv ¸wHp«ŽÏý{›ï·„Cz÷aœ{\oOÈÁÕf™¼`¥Æ-¢‚egÀmäë±++³„�téBÖdmÑ$J &Urè÷Ãl®vÔ¾úƒçÙà´)›­ƒ±?íHN'61´š'mû+f®×ƵMMœ|ؘg_åYÖ~à´ï#êìM„©f™ÿø<«±g‡aôdÞ^»î;/³áûû-(36fü:O§T`»a ÊKZc`c|ü+l•3À·fwYV±†£—ëðÈzôÕî?qßf XŽJâÃе\²<–ÇF—aûÄ4êÙ3ߺgûQÑù¾1öß7Œ§ ™À]bqÒ� Vz0ëj>Ó±±Šœµ{>i�ßnÒ‰;Ägå9ì�É— aÒú�6Q2Ûÿž»ã&c‘æ|P¿»j4gàŒšû–¯FVî·—ÅÌE:0ðá;ˆöéÍúÿÜÓ¿$ƒ.뚉–"èuíA¸ûç9XJ|"—ñÄýÛúÙx™ïÁ„Šãb£yíV@íÝä cɪ�àç$vL¬Ç¶ìÝô”QxïNN›·BT]ǹU°úìl+ÿq–Ðw÷oTPe?§Eì˜uØWÁÓú£¬�<”;-6b¤Lié)oã>òátÔS[+o�áš,Òú]ñãÜT¬nïesÍï5\í­‹7º›!ö~$Û5 úŽÇ`š®ÇoTÇ$gcÈ™sÇØ›ãÜeX)»�®K<ËþðIÏHüOc?6+›T®ïTå—£ÿòŸ3�=l>:=W±Ö^°“G,BÛkɬ3¬�£ò-ÐÃû”É¢åÎiäm˜ ‹Ÿj³”É4”ü�ÓþtÓñèkBGÖb|´¿BhaHJ'R9÷Þ%T•´aí^Ñx·b RÅg2@_ï-ÙMîÁ°Ù ÐŶЬv”f·™ó�â;¼gJ1§}œmízÝ•ÌÆßæ‰ÂÅi”÷f:{Y >z 'ºŠ1ýØ6 ï?zŽÂC•sÑA;‡?–ÆPËlŽ<JôÍ÷#ó ëPÃ!œ{ê¢ùQÓî- ™ÍøRÞjºœk)|»¿‘jƒ%AýŒ xϓ栾�ù¯Z¥ ½G­™21õ©_'åSpÉð}¸kS>J^GA&$[�’ÑA?}|pb-�ÇFÚ¬Æù‚ò-56nl®w�çõF:x«;†”Û¡­úk؜܋Rßô5 òñµ÷, Ìaž`Ñ%’lš¸Ìè5¯ÜaË{\dÙ¦D>T(ER¹/C¶%ãË1ýv«˜Ë)ãµ3‡–VY/ݳŒµÎêóŸ¤×–wPçè(»ú£ð£å%N‰Z2ô©ãñR¶:½Ã6Ça®ôN\Ê%»¦Sʶb¼kÞÚ�ÈbPÍ8>ŸKï&Ñ͇\ÞÇs×\#Ðàͤ§ ÇÿƒÑ¿Ãxá¼É¼oçQ^?)€ú¼» /hb£‚Íz²•u‘s×M žf¥M@ÿþ昦q›$¿÷¢InžâÛzë�ul[êQFØQ&Om³�y„à ??–Sì‹¡9^Öpû"m*Vçä]sqñàå´öŸCŒbO—�³VS>IÄJñ‘=�ò†² «üc"·Àå¨=\¢JÜ™Îïýñ€)ýqàå…4ºJûišáI!UcrqÑ… ^ÓÔɦ»Lxͤ]íêØVf¶áâèî+h&iÍYÙzxµõüM"<1‰†gþv,I»Ð&ê4_ôçå]cY9ø-Ìsñ.­—G “*šÜû˜0|M7)\£æóù°Ç¯‚L¥Áò¶>Yxf*Œª|&wÍá}/ƒ°}—Þô«†–Ò2VœjÎ[×;£Ž×t\®u…$R–Ú0¶Ñ�¯N¡ç:8!.BH}0‘Jv™U|3¦ÚŒ0ŠËMbÈÊ¡]Ÿ¶cÐES~tÛ«¾ ÀÝ-wqãÚ�8­QäG‡cä|oÜÔ#�›õØäZ¤î«"£ ~è©1’/¥ïàÅÚUKÝVpÍþ¹8.o(÷;ýKðšĬõ¼yøeNÐí†áE†"_Ûƒfíâ¸Ë/ o¾;ì0üANØÝ²öæ-äÓ×+é³¥Gä–WLþ Í+ujx]ÔA±Üc {h`Œl<¯7äE}ƒ}_=.ûîÁïãŽ9ÎI'QºÇàž§}‰ƒÀ½†üü›× Ô΄*ÛC,±Íž/=ÍC5Ò^ö ´“¨Kæ-úsYÜñü9h¥QHg\HNdC·þ™•Bw†\¦M‹Êä~ør¢¿˜¿y7ÏihÄ{ž÷IÛ.“jí¼It½EçÔÍøÄA)ëªð\~¼47éä¤HO,|.Ï-ãtóþ<Å6�jáÇ@/Lhˆ£ßΡW4B€ÖO!*ø)| w¦¡3vSöù°ËºúÆ~¥ cã°eÚlêùA;>Âi‡Þ8zårî¯ Å•õj8S)€¼³ç‘} Q/Z—_7œ¶LšŠÜO¡ÇÃ,ß¹œßÙÄaŽu©øgò!,Ê<‰³�ðÛ7±âŠŠ`~m'†;ñ$�Ùp%$ÞÚíx<ÖHÂãг´ûõ¾ñ�£+Æè˜pí¼;|qßp¶¯¤úYIÖÓYY0ýz˜×M°‡ÿ<Ì‘ë„=æ�(½ö%\¼]KóËžÁ¶ Pýt0z¤°hÍ’Ïz&¾.€ ÛùIøñâ6ŒT³±>‹:oTôä�À˜#Xß3’×ôuAÕÔNÊêÿD´ŽµæZ=ÝÞTÉ'Í0åa1Ë{fâ0ÏzksùH,g°5¯8•¢é¶›¤ºÀ%•'¯W‰wNÕR^}Þ?¹L0˜â s‡‡¨ª.(R³¥G=ñBÜd[O�6›Å·Ò³xDü4õó=¿t.éïI4 _[ýG¢¹K2½q¬ 7Ja©ì?°ª= C·œ +�«‘\ðGßáxúÀUzY-Çׇÿ¢À')hŠð®Í f覬Ñâ{¿@j˜õH|5¤ý~ /½Í„A‹}0,vƒPu-Í–Îæ�ºíT`: Ö¨®"ǶøDòqÅf�pWi$]Åe4E5™/ûõÃßjˆQYÆ/gõçñ§dÐ@KF4žíŽ5Ë$xñ˜!XÃæ-Úxík]5héªP4?ƒ.¾‡�SÇðª–8Xy\d•ÏÈ,¶Dèû;„+Z%ÁcîüY¸–,IeW z\1û”é°Ñ‚̧Ѩ±¯ lޝÇþËBPúAn€×tq€ž&ìKœÃg§pß͑ܖõüñº˜RíÐÅxô🟚\©–�íA÷…²ƒÿüÃGŽÿ¬Ó¾¯àÑdKös-Ÿ81Ž$·¤’óËPq ƒªù\ñ®¾É£ µÓ©+ud…Åì�œ?h?_¡Èo-Gñyß <–K—ÊÃ59Ë\Gøá¬ Î?£‘´â:ÑD|*Öµ‡žÍäxÿCÜே?’ŠuÏæÃIËs´Üì‹`Ü6Îj±¨ŠW·N"�!Kp›¡.Ê>Àý+Þ�ê’4ô(VÀC?ÎÂY“~Ö?;ÖZ;F�G©Û+übXÕæUøÂÏ}Cùñ�½�îůƾ'ÚùV{£/|ùüžÝ½vpÁIöZØËNXÒu¾òXš·OºË*GRÈeäÕ#ÛÂÑì½¶p&É…Ý:¶àê5àmóŽ’OdÀ›m9¸åU"«jejdaEÐ Ø ‰ÿøðMö Ï7íkðmðR>mŒ1Õz¬1Þ†�Í\ÂyÍ• ?@‡V�¤Ëí(ßþCXS4œ><˜Å\ù’²[`kßn¡Èl4}Ì3ÀÛö¨±ëí-{B!ö:8$u%´�YB7@Š/¶ÇPíÔ<áPø¿.ÓAÉ#µâ}¹™<Í!¿X/l÷ï�…ÕQ&8©ö ß8Þ—löÌ$ËÏÅìÖÐ -ßùAÁ³l1ùs‹°è?=ÖÛ9•Ú¦5Aó‹qP}e)¿×ÑÀ­[¶àç‹ ¼èF¾îîÃûŠýaº÷)a�²„_þr–¸~„Ëvß"‰„@œýº€^gðô½Zdž< sn{Òëóôªú9:íºuBÕƒÐÉu€øÒûÂ7uþKWh`é8¾Û•ÎòÑùB{Âð{7/è�¬|1Œ`Êš¹œ·æ5�Õâ¨úe<乌MâÃ;üìR ½)�s�Mq­G,«HJs�|_õæ4/Óàa¦�trf M{š.8 H‡âfy\ñ½Q,ñø�á³Å‰O?�ºR­Þ>š+æ„̤ỗط÷?nzðDØýÔŒŒjÑÿÅ\Ü(Ž‚AwŒqÎ|LZ¶7\(‡‚kcéÏ7ܵpY^%KÓ÷°pÈs>˺>ˆ£^[¡gx(Ëõ íÇ_£"sìS— ŠjüæãT²*¯ŽNÆ®Felæ@ž/O³»¬Ç¶eÍk÷¨aðPÔ×R@…¹÷QñÌwúû]�KO/EX%ɳ màê‹�hç9Ÿ/ò�3,jL2s†²Î‰7ÁöšZb]K)o—¡Ë3õ*wëسé5ø¶¨â—~ïàΰ\¶�M§Ô-¾ ãR¥cp£ÿzw@žÎ<ħtÙ7û ˆ1âíe˜ãYÊÕçýq™�ÛïÙ]’f\¶æ%iÇ/g7ïôC™~¸Ã8ö�Œ%Aõ¤_F—óã) T¤és¯ Ðn Í ÓAïI…³N¯IêÜO¢Ý±…�ªTΥξ8ýÜHt¾ß�…ƒÑ`sAJú]‰86Ï‘+¬ 5Ó꘻]ì?v2îN¾ åÿüéE±ÿØ¿ä }­ùžwéàÕ¨t�>¿FQ÷4l²?‰ixP,ww§ôŽ;!O¡�Lö볩Ý8=‹‘©Uí– “ö?oúC:þãpÆÕZêsxÞ¸0Ž9ÖšçT8Òÿ0ä=.¤EÙRøóô7mkZˆa•ùTU{5žƒÁ9'xýa t.Ù†_}›…OÎѵó“øë›MhÝþKºGž×T_B÷•à~s<›{æÖmä}&%È -q›{(yÔE±›Š ÍÂD%½ëæ¹½þ@ù”&*ßЗ¿LžŠsçž«‹eôzB¹øéE=¹Ûßåâ±û‹áñ�‘ÂÀ/¬7Úv·¾ðÃ6l�ÈGÿqá×?�ð"·Ö­z(º_°à5ÒPìê.ì*Ù¡2p—òvÌZ­Åñ›zS¬Y>ú: ï†×@Ä�îÜu~*/z¤ÃÛÖ9àŽC#øÕ»½áö€Þº(ó´½ùœ0ó–„ñ–eKhGrΓó…þëç±öƒPZºt2^?·�Uo& /–~r8*~¹w¥Ï�P.èµWGü-|>Á9“Ó4±Ñ]4U¼@Ù§wÀç_<Û8ǽu8ëvH‚¦ºˆê¿åùÒƒžò)�iL. ñ õW£[OÞT¬�Ûà4:FØìÄäÐj|X'\]jÇËêžIÆ/wŸÇ-„ÿ~µCé¯6x9d)îiíÅc÷Á:›uœåÞ']©£Í³ýxä¿3x×߉Wç#¾nœ‹÷FHÐiãh\¸‡�J¯Âv™®=³¼–FOÇËúy`ÃõAìû³”Ìwáð¾"«ï+*§5³óy ê˺ê&¾áTõl}¬QZ¿6sƇÃnë`ºxÛƒ’'õâ ¯m¯ü›ö)&óøuëi«Þb’¶íä{ëûÒ|S<½m z"µõQÁˆØÏ°©œÄaRP;U.º˜%˜ð”pe ŽWUÃ1Ê~ü7}¶ Îïç’LU8N|z�‡.m§BV¿4†µÕbx@ßaœ¢k�GG)òÑÅ©ü­zZNà“KÂñÀ¡‘ücìF8Ùó5L¾ÿ�Ø€žv0¥«„Lµ—£ýÞdìˆßŠ.KfaÕ¬ÓЫp6§D‰B¯3Õ°Öì .ž‹N Ý*}Ûs`^�œ¹‹ïÔÈR²Á%h7ñ£ŸÂdǸ°>\tzÒaqúäeÚ=>Õ�D�çsX7 š´ åŒÆø£mÊ× ¯ï§ ó¾‚d˜=>ë‹üðNMoËÄî��$WÇâÞEÝx({BùZ7pYð–{5’gÌTÞ¼ÅëHއ©!G¯;ÒˆG>뱚¯ßìc­6PIJttiº�¹xd¤+וR¡û`Ò-ú2†‡¶]`-Ü}Y٠μC+-ÈE�˜9´ûi?áHx¬¸*W ™Ì8aÅÙ›â¡i¥Þhüᤅ{\æ__ÀØÝ¹ä8À U?ð¾Ìxžé˜!îÙ‡sÆâ­žÉœ4©Þø5BãÏ"ÎqzFUo¾Ó¡ÉŠÜ†ÙíuôúÃ…s?sÓã·þÐy4�f.ëÅvûžˆxEÊ—Ü¢HÓ<‰’ž6þÌ-«£×Ü@!îŒ"†~)g¯° )ÅkoÓ°ì«:>ÊŽGµûæwpGñqHU|#,¸çÏûß„àO×þèý9 Ê–þ]ùÁpS2—ÏÇ<…«:(;Q›d,À¢Û[0zö4vÛßG¿žMî�Ú`ʃÕÀöó¡û�ãVô…Ž‘/AˆˆäãÆ…¬›4ŒS££ïD9gïçCŸQñ1†[k­¡Z÷Äê7ý†âŸiýù^ÜYª5- ÜDhá· uCÕyQ_êÖ¬Ëí纄¹³zsôŒ"¾¢Œà¸{kô …S5pßÒ<ä5•õÞ æ¾þBM}å9mÅõ yX;o}U%J:WJÍ_&àÞMŸáÐÕÚ¢JOFÚbï¡ã1u…Œuö¿\¨!ÌúeD#Ÿ¸có¦bâ§å´Äô¨ž#r1ö5—¨jX`y¥>xŸÜÍSSõp¤ÚIÞÿª‘¼eVƒÖÒcœ¡z‹ŠŸ'ó©ð_ø~³)ŽÞ^‰‡³Fá·¿Gp`®'ÄTÇÍÅüíœ3°�YîÁ�#4¹´ò!L±nëêúâÜ›GihD6Mw`X:D[yaá‹`ìl‘Á×ýô…uÑ_(rd§GÏç˜Sñpm-o.•ì¼®†>¿HáÎ0.î¾…çŸJÅùk•øC�¸Ân/ÅY­ÅéOñâ+ÔŠ=ŒÊ{?³�âUÁyV«ÄbjŽ¡²â�¸Ñ/ß äz—%ô¦×uº;£Hp›rL´¾Ð‡gÿN¢öÐÜØ‡ÿéndðÕƒœŽõ°�îÞÊÄuEx}‡:ךÿ¥ÊwU<ů;uû7ט"àè[\ºÌ’W)‘�ç,Ìß3�Í 7âgËÕhÒ”€kÏFá©´xÁKûG®CÃå?U c·¦Aÿ“\)³?£(ŸTa‰ü$4ä‡S ¡ëñln2)ÄÎíf8@k«`vÿo‰â•ñD©*öh­¦Ëƒé–L:ÚÆé±8¥7Ú¸7“Aù,Ši™�y ×ñ¥êMºz͉íÜ‹0á§îŸ:Œ�~‹97K¤ +ë#.ÚÀ"Óãе¹”6}[Îöã‚Dó­u°Òz.?‘ùÙè‡Þ¤óéqMdêÏ·ƒv+\5a»iëAェ\™g�Ž�9`î8·ð|ÜÄwvéaHÂN”Û±‚G]j¦á­ó%:V bSŒ�œ¸�Ku¹ª×Á1>“Š÷VÓW³^¨vv2Xú¾¤-«-0y­† TäÊ®ƒôà�?…Ÿ}N³â0}‘…x”Žò·ªî¨}·Ý™Îý½ô`Û»º©8�?¨·˜ï™ ¥T/í…«�›Áþ—)n´Ð …òf£ÑhFˆ”ê–ãÓz{±•ÆïfªÈô¡§‰ ‚ÁwΙ-Ã9¿èomOš›*1±ÓÐÚL™Û\­übÜmž@)z©¢åh#lj¯¦òÌcÐvD�O}½�…ußHîøt|GFù—Ó'íbÞ–¸Œ7ÙÓ×/4§-„ÏM¸§lò Ã¸�¹úA?@‹ë;�rú„�ÂL­,jŒºÌ¹–¾‚IõÞðH …ÉKi‹i M¹Û ¶f¼ü¹ õÇó&ç‡â&…npìÁB~ñ¢J>›õxÙ–þ´Ø(Œ^™Ò–—àrûC:1ˆß^žÅ›&qÁ•BØ,SeçÚŸn|=o\ÌØ€�Cáà¨|ɇ�Bø^?Ú¿,¦ß{ñû…c„ë—ñÑŽ¸r· «z•á…_+¨ïãżú×ka–µÆ…V²Š\o<˜iÃÏâ<ÑýD•Ž˜Ë·íÂx‰Ã1˜“Û×dá3¤l�¹»û¶YäÆ{ °òïb¬<ð”ôÚ"¨bLTmUA?÷Ñl>ý<õ÷ʽïCÓ*müýÉ^t赃ʓGƒÕG†tÞþ(†“ÜôЪR YµrÚo2ç,3c{÷Ël»ç:í¶ÁÒ²B(±PE|<�k}§C³làb‡Þz·�´ÏXóñ÷ÉpÞdÖó>Cy›îŠaçÖá”Ë%¤®+ƒQë 8ÈÌž&-ŸKá°˜RVù·‹—¨Òìv”Ç!Gnðà§%aû6 y¼v+q£QÍÛ¸ÿ0¨ìn‚7Û<1dØ_6œW(¬éŽÎ/¾6ÿ*¾%•Ýü‚ºZcÑe*‹yÆQt_3Ÿ_97‚_”,ìêcÇT%p#û8=×·ã×ÑãvŽÀÖä::!³��7ú /ë²X�k ŒîY7t²Œ:n½õL̓Ïŧ�â-ºžh`’MKªœÑ®«ÊÌNb¹ûm¬± 2vvça e¸tÊEZµ¿\ôtRFoy°vè&6쬉ÈfþêŽw[þçcX6>~|n>LJëªàÏãqh<ï Ô*ã�²ïT¥Á¿¹¤Õ:ƒGMQC¹‚ë)z¬Ðt~d~–f�}NM¦áý,ñõ¬vî�~ÁNS.|,]4k-&ÌyE[ízPIú_ú3?öWÌE½hÃpmŒ½g.ê® Åªüz麆¡Ð/rÚsn-í�kG†‡Ï¾Ðì¨~kù•^unÌZ.=%†rµß..) tY2J~<vDì¬ZN±›p01w7}ÚÓƒzÉLã­Y24­i«ôXÏCœÂÈ.¾’í”ûÐ\¿PzâÓL%¯BB‹!ý+š•ÖUA_ëDî0 ÂÌL9Þ¶æ:.8ÊÜôÇ Ö)ÈâÄ ›Áµw'l—Ÿ�ŠoøÆš �Uq�…~ð͇WÀçÅ!bøD”6†)òÐ}ZBÿ°�d³#�ï$lÃfú¼³æ5lWR–Ž9ˆL©Ãö]çH3A†y#ø�º,/|¨ÈW…\�¨ûBz[—dvfµàïé›þvî6kœp¤X†“VÖÓ¼ žüy!Ö}-â­Þ×¥ód�.Ê¢óªN*›eŽŸÍ&cÃü³cæJà®#´Ý| MÚ-b÷7#QÿÝSqøÕc§öI�†ù wÈñx…ÝTi“Ã<(]½ š>¸Ð¯ÀPôŠß(ÝwR*±ÿï¹ôúvW}5œŽÿ»ÁÏ®ïÁ%ŒÉâT­tñ9®:Jÿ%)ð㛽¹Mx.¸–Os€×œ¾Å»Ö­ÃІ�" »Å_ egUnúJ ?Q~´¿˜&LÇ«–ƒ’µÊ«…K¥¯èç–/TsJ¢O§ã½¯ô2+‘o.X„¡Îœœ1ˆÍæióô{šì¾�–Tþ‚Äj•œæžV˜>Z€�K{ýëÇ%†}œùöe¾æ„–öÝxÆéƒ¢ü1’ÿa —]V¢úrEÞÿ*˜®]Ë«•·°øÝüç~nQâf¼ë–Wçù‘£w$R7í�›à¸)˜>îi`­Ã÷PiÚzj6‰­Õe±cÀ+0{B¿÷�EýÚ3”|ää{ãõHM©Aè ¾sn¼Š°‡‚Òqlºk>®ØÔ�ŸÖ¸¢Q—¾•²Y'ÄÚî¤Îÿò-·äÛÖòÐÒÍ�½ú%üˆ‹çÆ)1[nË¿»~gy—÷a”ã*Œ;ÐOúTóŒT¥4NX¸,\d¯ÀŽË¯a±V =¾ÝUoß§þ™ ß?�¿Ø¶ Yáߤåú'h¯ç4xoš„OÌ.±\E9–ÇrªI"Ù˜ÆòkåðˆS¥—&¤I+§^–§ÄÂOkìÓnÃEI›Ñ|R:v[�º�ôÉ5 ¬þÃÕ¦�<Íè…P&›O#íáæ ¿BóÓ“äª öZ<™äÎÆÌ¤Å4}Ì(Ž®¨ÀÞ"pã›ëàß¶ÜjæñS 0…¶§§‘‡Æt SÞÆ‘“#¸Ç³!ØÞãÖîÆ'½oBi@ e}’ƒ«šG… j½xÒ–b¸²w ü{—&é>v¬üKv÷½pŒ‹î´�ãŸ]i ýdI�¦•�ŠÒêú•Û†öFw]qPîr^õu.Î=œçpôñƒ|íkºðó…2YH‹Äú3Å|Áîü˜@óg좽 ŒÙU«ƒ<~ÅÂË,*ò+Þxá¶3Ñ4š¦ŠJ Ž¢){ñ’3Š|ûëZ=§ƒ‚î½Ç7߿ٟ£Ê +Ù÷‹=~>çÉûNˆ=*¯à××Ayê#Jz'ŽB!þ,ìé¼ÀÛÝ5øö¯ªø¦�–ÿ¢Ü|K°Þ_$XÇ]‚͇C˜Æéòóô È(ª¢³&z¼ûS,ZÆwç?.Ø2a)¥§°½d<Ÿ_¹‡×ØX`‡ÑdÕPŠ�]Kðè•’”ÃN¸(t3Ú*ã2‰­Ô7êœÜ›¯µe’¡‘OÞå�K|füãï>ïŽÓ'ýîψ'µ Çi¿}æ.âÈÎÇDaÓ¨ªÛ.2U¶G{C?.TJ£Ÿ%¦|¶Íˆ7'/ã)ï^ó£Mÿ|½ª†®=ÆçÁ:ršžå®.!®¢7j:ñÂ/-ðgD¹¸xì`P2×ãöt8·©˜=¬ŠñÄ]ä›fàt| ¨ Îþð ŇdqÇ’S.Ç‘~f: alfwÊêðjV9¿‘G[Ó÷®D®ôO …ß®èûWÖÚQù=¤{ á^UC¨¯®3{oô'ô f(� Ûþq4¥h!¿µ\ ]-ÚB¬|"ôÛ•ÁÿæÛc™Ì7z>§9uK86úŽ»ö„¢›^Ãò}zÜ~( ór˜KÊÀ z—/ Ý(S•(̘ºr%€n/ǰié>Ø·N+ÇñÊÞjPX•É�­¸x}¢p*dd÷øÇzí V�ùCñXN¯ü²wø¡æ¶}<º·95�)â—�yß·nò˜N¦ï¿qCú3´¼�Ezþûùâë]üÿ®¢Ño�“+޳‹¢ø�±ä~æ>]>ï�.8À8‹`á^›./QÑÂM›q¿B­˜òF …)€òÃM´×©ZÀ›£1èT³07Å?¿JÀCÃpmÙ?M5þóÒ´fªs�x9—ÑʨÿÿÏrÞÒrkÕvb�ª¸tÙ JrvqßáÉôr2ü·~ί¾²W¦²õˆëâÛÃÁ!í¬˜³> §iÓÒ¹²µ †hœ•âäød˜”ªvGÒCûËÐ×¹ÒÒX˜yrö 燷~ÂÄí/)`m/é£gFd>þÈn8O¿ÿ½g™Üjv=¿79ì/ÁI ÑiS VѵÅÑû§áBó]˜P?ï2'-ÃÏC0_jPy²Ö‰º‡q…NP³ …Œëîäü¸…f®>Ï™_†¡ñqmIéoM,<=—ß�ñâÒ]?Éû¤(œQa‰ë^‰ƒS1~Ôø!jNœzVq0þç@Rj‘ã=)ùbýå),Ô›âí!\VX‰ƒr€÷ÍÆ‰/tññq{.“!z}o¹ßV´CrÂ} Èæ@ x¸XÂݾÀÎu«ñ«éBP¯NëÏA®œ3³½Q×°^lŠœJÞ)h3ÇXâ7é¾^¤È¿´åñ‚J .ôM¢ÕQÄ&Â\Ë•£Pÿ×:ˆЄæyc±>h®~u+6ÛqåÍp¤òh¿/ˆ±<`KÔü`?4f�Ái¿nÑ,—Õüb–"ÿ¸úæµ çÌ“ùøØò4žÈŒ œ1+ifÓZ²Þ�ån`ŸŽìV㋟M­`î»bÞVWÎÛð¼ÏõRYi(. <Žq§¹èê(1z¼¶u¸rz\²‚šô�pùþIxò¾Ä…IØOšgÀ±E!˜;¡œ°÷¡Ü#u´!§‚Ûzmz»Ãï6O©s÷Bø–!LŠKãno6¡_™G?0GÚ¬„ÝõÑb¼÷Á%�jÑ“;Æv�w´.lß2‚&Kב�u!¾Lò§'þ•¡‰ÿ›ÀE¶+„3)'±M”Ñ’m¦ä-�nkaIÜBî!IÇÛ‹¸çÑlNúSB/|£øè ñµÑSê·ßDü8MÝűõN?2º¬óÔpœÂx?kºßüF›Û»½�4:2t�ÆååÎx7k7ø¨rö&ŽË�ÎuQÐw»r%Ü Žj Søƒ²³gÓÏySØ.6MªÌáy¢Yµ/¦€}ñúK5®0V¶~©}{ÝÍÁƒâ×Y´ü�;u¿†�ž»†ƒ­ƒxÝðCd[ÿ/Ï·â>ió¨÷SÏMVp9I�czQÈú·´ì›6ôxmÇOoqÀ®C¢²ìwô]$G³l^Ñœˆ·ÂÖW¸nU,Ob€‰=GÒ;Š÷F;|±¡¯p¢=:ÍnÑ ûU4§ŸØ:ÙˆÕ"ªis†Ï=¨€~^Qâ³k¡8H"…šaYR×džbJ7w¬VÙƒÓTßPüŠ´¼� \3…³�RTÛth»9Oñ@t™£„ÇVLä¬qóhChü,�ÇË«î@Û·RÚŸçƒkÿ±ùàIvÜ4p§=Óeß=Æœ[ƒQר©{“7†·‰g*ÃëaþøÉÞ‡##ì`×ãTrV ›ŒÊX÷k4êÞïUòwñ³[†ëJ8°ëYÄÌ€Å^f¨ñü,š¸ïŠlŒÑÆ!®vÐÄ’ÚÛ¨t¼‡Ô'Êœï›cþ©îÖ‘>³h{N«ížÎõxÂêñèIð_`ÔZ†£�ó*hkôÆ6�+TÑó=n¾Ä[ªMÙýKj½>Cs‹ía»¯º¾/¤›µìñ»Ž?tÃôÀgð{{6Nø~‘>¾o$ƒgÓq“[1~ªˆ;žT€AÉ3y|ô¨’8)Û Åþv¨ø�ùRÂõG¼áˆ:l{îȦ»5Ñpe }pz Á·2(§$Q¼Õƒ~)Œå•Ò‰k¦Sh?sÞ#èÀÝxÙn:û<Ðçƒ~ OíGq’Û¨®Ü=ߟáʹS!åÉO˜Þ»Ú¾®À®¾{1|ÆZ(lÑA¹bkÚŸlÏKÌL1á©.Ûi_tcõ¨ëõ3¶½á7n‡²G3‰=Ãcy!§SÛ¡,áÚϳ ;×ĸ³Åø9Ôe¹P¸W0Çûa»‰‚JÉw^|Ó�c}ñåp€‰ì–1 Í;uiUŸ×Ôͧ+»\Å=¡Úô©_ŸÚŸk~Âþ65¶xþ›ÕØãF¨ž/!מ&\¤ ¦5géyò|<Óò�¯5LàÈšxè-k‚Wf7DZU4~ïeΑ|X=™û¿Í—xš÷áƒ!1ì›/«åòÿ´ê>‹ïŒ&!%ç;yÚÉ')F)†|tI-î ï·ƒ+ŒÐµ²–ÙZ°×„Dœ_º O£©g3蓯o›�„gvªI R-àyÉrQ×&PÐ;¨Á^NZl˜gM£Zü!RÆ•ZF’j‘%h­©±ÊpRt¼”¦ÑÐçL&êÔÆ!O‡sÚ<Æcƒ1Åôf˜¹xzß –]`‹¹Õ—±ðÈu¸úa‹è”×A¦Ûñãà�Âá{¢£€®|> Üý7½xØ_‡‡Qü­ò(\¼¾œ_;M =Ñí‡><ÚUL`¾[V Ùóú4¹É Ç­C ñ£7ÅõDݼ,ÐÚ‘CeЧ$úù-¨-ã� ?l�Õ6#…€]¿©ZAŸ3HƒmñùH';~Œ*¤1œÚ)»þyÇÿÄ\!åž±ððûD¶þQM.†6AãXñ¢>UÏ0À‘ãûòµø÷ÔC6•~MÕ‡R¡?ÕÊhó'ó´iÎðsŸÜ·üi† ­'àϬn°,åžè¨4\/Š.JR‰Ý–`f­/2˜>¥Vx VÎ8«/N:Z.~^Tµj/aóÕ8Xo¿–_üi…aOc0Öè0«^Ÿ‚KUnq¼Æ2éµ'EݳI�ôu75Ûs£v êäeg ,î·7ØÞiNÝS6Ó†£N<âv¬s} E[úð¡c¥â&…ùX?§Ñ=úqf÷©}Nº4†¯ônâ÷Ã%m{Z®SŽ \R`È£p˜?Ó–¯Yèó¬÷j¼Ì¦†�¹‰­×µÙkcÝ�Ÿ {ôeIáÇZêu°„«B1ýuì~SoêqséLÔÍCÍv¸¡—5¯+l¤ì}AxNÕŽÚ�åÑn�ÑKj¹·W¼¸ô0ÔŽ�}o.Ð+™Ï´WìAæUÙnÛqZÙ¬ºd†§ÿŽâq®Sñt¨öŽªäë÷£ÚÖ4Nù‘Ìé¥KñÈm4ùu\3Æg�õt»`;xÈ áÁ%tºs* TAÕÁK9Ào;œ›ø¶)EcDK²°o¬ &øgqÂÎLì9,�µü%ãww‰ýŽ�æ|;[ö²’pÿýùãÜBÁEØ]õH˜œZ·ÅÃâÿöpV¨*Í ™ƒ¦Ö¬{½7š9ß«çƒ�ž×GNãiμ`nÕ§îÃ! »ñAC,Ôpsì¬` £5/[ïÊŒýÁdRyjò8ˆ-îr\"ô� ƒTyoV"_°HçhÐàÊ[ìþ ˆ=VTÃÂHeܬI­_„¨e;Á3hê¤kâý Áîå NÕý�ªlåæk}q͇Ýðb‚¿Ú]‹r©òØûíh8ð½??ø9û�çwŸÓª�v1l»– ‡Ï÷!é¬#´%"œNŸÂ*ÝxA¾*w9þ Ä7e¼}Ý-xkˆƒlàµ[Dïçup2¿Êž!=­Åð÷ç}(° ‚ìØÅ´åa_®V³e·¡ÅpwÅ:ä•J•ÝÍð�‰�Ð1~™¥¯å)’¯­ãÒüñœ»ù ?{ÉŽÇ|É;y0hîNäS¯ŽÑ:®¸¼ê 5E BµÊ2üñ7—zgˆÓ>QîYÞp,…ï�ÿ.ßvŸ©‹8ÿÏOqìHN±ìÃg¿ÜrÛ´E;íÔȃ'c¥Ñ!|Mù;VIãë·Â_'þ/$§^*#%›ÅØíÂö{n3çÀ–ß'hl?¼ñ3ŒMýúÒ.+ÀZÉP>z/¶e_Ï3f¢ÓŠõBÌ�´GUNç9š¿t3€ ÷)š1œ C¸§évŠŸŒCW‹4FâºÛQ>i6û;M³0?áqÅI ËaÃ3ÖWXŠ�~[xݱrøKVÐp?—Î6†àŸÌ'Ðï–1>22×ß.®x÷‚=YâÝݺ⓼kf$%EÅ“4ãàR6ȘÅ;L£ØA=?ø'SÐsWN™’Èe;H¶=PfÊ7Eu«é•©ðæ± {xUÑë"yªú|+ŠqÝÿF;áÍu*xñÎv(nž‰{gÞ€>%É].;…þ^Cpz™¦®4Àc²ŽtUÝVf4�Ö?J¿àľsOòºí—¨÷ä³08÷,ôh ¯n¡Ëdh˜ÔCaóBê� Æ{[¯H׬ø�JZW´O‘ù6Ô:î]WM#e¾³çCa¾V±˜6Ôš¼Œè„×`!YU‡ÌþRõéåüØ%×Û±E¼õt1•RÁýûý±ÏÊz?!‹èOœ~Ò�_ÍY…ï#d¸´ ¡üáØDþ�ú‚ïe[²ìmô¸<÷%ÍÆ™yøV[–ãFU¾¬"}°Â—}“ÐÔä» ,ü¯Çý‹®¥Ê�¹½Á*Ƀnè;á�W¹=Їcl~Ðýß÷k×7PbÏJf›ñõ¢'0D[�“î݃[c¢iRÄ2Šuü&}ÓÇ­.ÀNŒe �D™3aÕ•Iøª|+º^®¨}VLá'WP—~ éþ™ƒ3ê+¡ß㉼AR-¾?!R{/líÌ ;bKsÒ9Cocñ‹AåMrŒÎÎGm#Êú4‚œ]Ëi°ãw¡mGúîéízrü•»£ó|<ðÄðLzv¯piB8äçãÛ™¡ËE/¸-Â/R?p_¿� L¥@VÑèX¾_H£‡í²¬³x-ÍðÝ)ÝJ¿&`›ûY\õðµj�æ±?‹ÏoG“~yè®ü;†øáèm?EãËùî˜:¨ÒÇš7xü+Àü•ë±Û�2>å�AïÿLÃ^‡ÝðÂÔ4¸y¬„^æ$�ª÷lÌ èzz•âõù•8bö °pY€ÏkOÃç¯~Ò9Ò ¼,½;ì+AÓwrd༠?ßRç5e[ùÒ@Kô_�ʲ¦ã»Qãaoü¯ÔžecÑ0²7[�~¦õ0Y[ ÷&|¡å†¿!©k?ÿ“œB'á¥Y¶<¿¯_ÝÀÅ"Jüz%òí~h|Ý„ïïŒÁuîW(FëìZô ¬þÚãµÞ©ÑL�V5%AåEž_ðAèíôB´j(„�¯¥~ùQlo«‚Êæ, Í"‹Œ1h”ªZùpíZØÞ² b}ÊÑÒfŽº­Ãå­&´õL#�ú<…g_àà‚+®³�š½&ó<ä ½pÒ‹D’ów•«$tä•GÞ ]ÇÝ¡Wë 9GGØâ,©!?ðBs_R§tèã«�¾†1œ­~�‡ÕAÿäh–Ñ žoñÇ#`n!å°ª S ì52Š£Þ– ^Yêhìè"˜g/üm8@»'Go•çù »Ð`ÛZRiª¢ƒMÑx{¶†_‡ki nKdiR¤7ÊUDòáQ�¤}~!^Û¡‡³~ƃJ¹Àë3ü<ÿšÇå‘Ý'csì}ès»¼ÑáŒ6�ÄÝJ@éq ›¬b=Ýk:ží\ÎjœÑÄ~ ‡ßŠOï܆�‹Æ.xt¯bæ4o¾çØ�SF'I]¤Ú¬?ž�$¹BÝJSéûÞ}¹æÁ^â ycj"¹´ù‰åU¦Ü÷¨ÿJXŸô_BÚ>‘rn¡Ã÷ZÁ¾ë£°Ù)[OÚð¡ÿB@²»Ubªr“"· ׺óšŒï ý"‘—}ÿJïD5š<ý?œón3¶gàmC8cv z.h‡Ê@GºR ÛUVuŠÓqDK: &ó° ,o‹‹®Çá�ÓüôIŽó¹%œ?…Çãiæw q½¦,®¿\F·v}Þ3³2úêÁ‡¢ÒbÛmˆ‹µ¸ßÐOà–ÿZlëáÉôNqPôtv³XÃ�F[P¬ßNÊÏT®ì=&Ïüã¶Ùiž8"1Ó?¶Ó¤#9Âs8¾Šx!]?àŸÖ·Æ«:Y¢3«R �Á!#âΩ ôç°ÀÉÿ²²«Å SûÏ µEÜ^®6“ç‹&ƒž ~`ÔýU>¹„“_{þòÍûþf~qâËó™F|'�4ŸyåÐ�=PwXÜ3šÁÝuþR׈æ·+‚UöÊy™i ‹iD Ffv0(^†g[šàéŸQçÔvÖBÀ’MÜËD?j…â²)œÇš»ñNïš­×ÀŽ…ºlùÁYV‹UÓØwV†ì¤yýGsLÁGÚ±h#×è(ñ"“n�U£ËŸöóùŽœ&]¼¨ŽýëLíø‰Ì&š>é¢`ï2�öù—9osñÀæo´µ-˜ú Ú‹SVqÍKSÞô�-‹Ü5xTÈIÐìØÎ†�Õ”œwj®4“â7èÓ(¥‡‘nÒ²ù+pá/ø~d>ä\ÿÀ§nchrOžbžJ²X¯#Oçcøñe=LÒÝÂ7lz¡~Á¨Êk¡nÿfº¸±“r«öÃ{Ë 8yw­8×F™FÁË[¬Ô^ŒÇÚ¹ïÌs0Ãé'jÌž²k¸k±ƒX÷4”~Üö#ï÷±üjWi¿Ë7cYœ›Pñu)dtˆ-dÁûQa¼´Dh­f¿(œ;Ȇ4!ÿq¶áý ã„Þ•¿àÆç�ll…7Ÿôã÷Ûp‹÷ºóf¨WŶ„%Ø9ÂP¸¨ü•ƒ Þ&Ǧȉö-ú}%ËfOiãÆiÂŒ†‡UhÌ#V*ò£ñ�$.Í8=BQ:°�žºªáψ`xúl„ËåÒqa€f h®½�™µ×ñüÏ×°°°žÃ Î= €àmðŠO:F_þBU[>ai͈¶ Â^êÆ (ɽÊÒ$ï}èYjwþø¹NОWƶX}­€Ê †üôæcOâ›÷‡xºü;°MÜË×Jè]b Þ·é·0]Šg`½gTñˬH±þÕZ¡ýÄ!0x³YšØz@a‰»�œ”ðó#¨u6œFû]Ì�äÑéÉC¨„‘ü±¯ƒtצ(Ìψ€—iš<ýU ™â�ÞãP¯×hL™’�½-áˆG$Cêҡ纕|¡|æ}ùA—v|„UF‚ÐkÉ)qÙ¯IÜÓ¥Þrü×{çáI§�X·¨‘tn½‚¬‰9˜¶ÈÖnG…0YÚƒM/“õ¬-°yH3½»UŒÌ·Âpûö¯U \;‹æyÉ“g÷ƒ\ïùWüðÇ›½ïd@ÖTÍʤQÊÿôà“q*¸«Ä³óãùdéXPêÛ ¼úM·}/€™á”ÐPÎüª„wäN‘ŸN„8f‰ õÛøQ(× ëÎu'‰*Zþ�‰+Tù‚_‰ôÛÁ^¼Os"L?2g•MÁÒòýhx¼7ï°Î㕾’’ç%Áµqj…õcãÃãùÞƒX~Ÿ™êG¿‚(燙/ý…Ò9ûùÜþÓ*ïaô´±|ß²?xÊùÁ"áì¼àŠšï²qÀ©q0qg�äï¸b8“¤•nB_ùzÐM9ê“r覂.þv*ÞÓÄKr¨ÚÑO’¶¢W^{FZÖñç@þÌx/ÁÒO[øCÚ¸ôS_è�[Ì*Ž…pUiz•Þç�’ç[{êov“Ê“W`ŒÆ ЪŽÖ†—ø]·y¢Ø”3Õ¾ =Z‹èáó£°pâsp?‘έ£Í¹þÒºöñ-m/—¬9¸ TÍÂÞ{GHÒ‡ñë×I¢÷yqãJ´y²,y O?9¢Çz]¡ú›!̺ڃ:7AU(gj,âafc1æÛb<Qƒw»B¡®4—Í0å'Å’�?­‡¬ª>gc%€ý‡‚çï(ROç)…2x²|�$§!‰7Ș³ï¯4!]?WŠ/B‡Bdýt@³g줃¹�çñ×@º.Iã ¥�Amu-ô}æ�¿Ož`ûõùÐÐûÙ.<  ’Y�÷󆀡d±GXú¾Z*ÇNtûÀ=Ioï÷àþ"žK±ǯ_ä½§U°Uˆƒ›*9Î\‘óÝçB@�1ܱ�æ™·‡òðª›ämÚDÏ^Eb²³7ºé�Ó•âï+lü~×ßK¢U˜ÌžÞd¡nÄóL+!ýQ7>psÉ? ï$ÛQ.|e¥ ëŽãàmGx\ûa.|_"yqfº·‡ ûêV‹ÍÐQOÎka_³9hô9� Ƭåךù�o éI·®J?¾ÍF¾Rƒ_Â÷ñª|6y]ðíaÉÿM­£é|�J#ù·…†ºYÕ»Q”¿y·¸ÿÓÒSz>Ù•“º�`¥«¬ÒÒ‹ôzI î±ž;†’=gˆÍÇÔQþ‘®xnoÆÚ…c¨;Q®i8ï®7 U7ä*‡7D÷„7ÅÍ÷2øjTÖT÷¢šúa{#•Mæ?MÖ$³KRo]± Õ·²é„c¬¬›Á;“gÐ}�8º0èÌÙuqØ dH]˜F9ÚwøÜ×"С.ʹŒÝN{bÁ2f¤­$ÂÆµbóË7àvÖõ»,¸½ú°hÖk ΊéÁ;k3ñçî4pŽ»ÇîÄñÓŽbüa2?ÍIÆÙ—o[Aá|Ö½†Z3½XÅPQø=º°ñm%¯X\Œ·± [Á‘,[±_Õ}®yÕó˘ävQdšü¸ó¶ßf|ùþúcøž“:ÿ±‹=­„wÙîäòÏ«Î4BOÍ@1èè|�hO#YRáèây£6”w¸¢�BwTʃã¯ÎÃEu=¶•‰¤ƒªŽøE 2Ãä­ÎÓÂöåO£É=xe|8Y{�vÈ{óét?<¶ë�ôýâ88͆ ®ô„ÌG^çÕÀ¶Ç¤Ø÷�hky„C«(>£KdÞJ4²rÁ^3l/tBó‹/ŵ5⢨TÜýA ‹n§@·²IÍËþ#=E¥ë|qàVY|üâ8ýw2’GòSõGâÕF IîÅ_Ü-;è™÷[Ïÿ‡ÓÐ4(ÊhhHC½ž'Rˆ†- ‘ŠB"”ÐÞ *šD¥”Ñx¿Î©„”Qd–"ÊÈŠÌïçúþç—Çu羯#ðþ4‚ô£7²G7ŒØíi�|Ù‘K8{È #Íì)Ú¶N=W¥ë²3i0¸ø^‚4^O�Q§®6Úüã&½Uu'ÙbaK×½K(òC%/«J¶ a8ùÛ-nãUmZæhÁRº)í²<å^+¤¹“$ Îã„`,¶ó-7/bOÆ+�ûŠ-¤¼Ó¦z–°w³~ÁZ»AÌšcê sAö£5ó÷[ ®þú`\OœiÔ1vªI&I]§—jI~ìrxÕ ÚÃDZóT8 ßÊ )"Y”fO[§´Yè¬Á)Bcèá37zùõ+FUýÅÕõì^ñU“e™CÝ]Ùû‚3 œÇ:à‚c·ð‘•8wm£ýÓ;ˆïâSÉ×Av~ù@y_}`Ö÷ÛlÏ– vîB Úe·Ayzÿ£³ZK¨5Iœîˆœ'·»¿ñ’l7;$¦ûÅÌé\P d6O§»ÛŸa…B?>^]†ÓqÚo8‰ßÌ{Ž]}`vÞö0ûôdê7œHS�˜¡ª¶õ? ·*¡iþw\q1ÄŒ àìM5Ô ™Ë®,ùÂænЀ'©“馳”1øøâ?ô©–´ NâK~[™*Âe“ˆÛ²¾íúÆmÊQ¦Û ;±ÎÌ|@ï�vVÒUñŸ×ß…-ŽàQbý±¯d§Ûdákµ™}º�üHi¸\K?UPÒÔK`ô9¢LM˜ÇØ-T6n&;ã—ÆÌ¥³ößñÅ5Q¸6uãkãPv]*[ør,STkA�u¬^r”jY‘øÒ~Ö\÷é?Ž‹ ³a{`·¬/eK½ãžþG#||¢Ÿþ¬ßš‡Å¨>'rîÇW‹ñ¢n6þÍç£'î`ÂÆeä´U†ÒÓºñIÙxÚN7·ê±o‹op»MÒ€)úÀ¯îr&©p�º'AóÓkìy¹üÌNB»â*ÓÙ ò–â)¶}Š×’­L*M²–ÀŒÚu®q§˜õ6]*;2€‰¯¢aTm&ç GØßá@Z, KuCØÛíf4¾"‚Õ®KÞy“œw)²‘k28ç`Êö ¦5�yì¢ÃW|1xnvJëUvt ƒZ�YÊPì¯üï¶Ë€XÏA[~6«3K¡ž�pЬ«¥•ŠÐT.SçuÖƒ�EHo\<9­ß?§ü ïkÂÞø�| @…Ù%JtR W÷¼x‡ØÔúLôÌ€gu Üêñ:ìå´­8.óóÞ'orYÍåÏÜ÷æ­ðU¥�ã£Í9¶Âý†rп;ˆªõ†Ù )FûÕA§S†ö? =ãd˜X|/sGŒ¢#¯²ÓÊ™øtm&ã–m¶3}WÒô 8«oEíïŸsý¨•t$´°Ä¤PµÊÿ(Ê#ü<ÂY.Ó¡í»³)X¨½¦ÊóohØ£+¸¬‚4}ÎÌÜ^�›4—3çX¤¡^2¿Oι™‚-'ç°c“V? Ï®þ-G�­ Á#aíò9 ´K*­ökó-¼pr¢ ,3UðY@a*YÐÅ™afcÖi®õ‚/5+’ØÇf~qé=üðÃ3ÓóiÁ¬1œKÚ^¾,¨›¯âMµùYœ­·(+Oþ‡¿Ðåâ¡,ÌÿÀ�ûþsg7¹¿˜UÈË�î›Ý´¡T’ž,­Ã+ÂÌæfÝyxvª]bEÞWP^SÔ^Õ0—ħl\š6¶ÀË^ž ^î³hëçYô¯zޏ¦ù¤Ã‰Ûå|Á�,õ&˜:³Õ¸q?Ä9?µ,Ü(ü� —O¦Õ�BÐ�D8p�WxhÈK�´”ŽIÀè/‘4rŒ==5âöo”b™®Çˆ¯ÜDýžW™nÞ ö#$œa™ÉÊ$[Aÿæ8½Ö6¾Õ [ye4Zc#xýR£ÊžÙ`Ãÿf/²ŠÀot"µ/NÂ�ïƒhàóyÚ+RÀuÉàc{”öÜû‹�£2™Ãµ#PöâxljZ©[�Ò[':9ΔRÕÓhbÙ 8s3<ú^r!fxC=‚t·šÀ*)ŽìjÃ!µ@˜]1ÀÝ[ýx×ú,mÒ»N§/øâ ÿh +õCX±�Ü«k;›¾?y€½ÎâuÒ¥Þl½`2YÕàœÓV†E^$*8J]¤ë?¢Qd8ˆ.Ü=nù¥Ó(Eƒ³8½c7Ð@Äø>�¹�ÖðuéI¸ñxj�6(ƒ1›žoG·ñ€Áf2iÍÉÔ'nŠ#IGå‚�o<‹ÔeU¥Òl¬�3{½,�zV*XéûXÞv/gFBªtg½2ìSº›ƒì™SF:­zåI�7y\yföÍW?,{SOP�ôEhŠÓ©;éwŠOþ¢ K¤t@f­+ëNeêöO£…MË`„�3‘ˆìü›hþê «©ûÈßó€�Ÿ«ÿz�aÿÆg´âPãÊ™Oö´y{YÁ4z­í¿ÂÖ³’0¿3‰ý˜TÉÿL4!ÿ•{ òÓ 6cåE|òÜ‚�ûÓàÉF õV$…Õ¯xñq4rœ7ƒ§ÍxÏå% 4Q›ðì–%�‘4Þwž`Ùeê{$E›–…@ÚÞëÜ÷Ä¿ü´ë™¸7Â-!j;¯O¾§ãX[Ü#|^æ Q÷œàì¹pÚùRröƼ¦uÜŸ›Ñ¡§¿)“£Y*¾¶."£YF¸C¶Œ=òP£Í¯’AaŒ$-hY ß®^c–î™`œ¤I_ºMÙûÊXV1¼Î]ŠdÃàýmz$}Jµè\|5müoßÛ“±C! ßf ¡§i›êzèI¤7U£±'±Ä ‰V~¨„KWÎѽÃ~xUL7ß²AýµlßÚ~šâÜùO%áþm WËRáb¢œU¹ÀœÞxYÂ…ñ°�)ÁnWeöd0‰“(8‡Ã]E¬Í+fZ'ö¥³ª³IfûwV�S ÖïcHàs‹îž§‚%>ô3Ο_›ºv{‹�‚F ¤Cgw„Ð}šä²ÇöúH”Aí»²à"gÉbÆ 3Y›G(óÏ�lkÓ¦?©ìÃÙe$«â NQôÊ>¦Ï3£OQ(òßø@é¨úšWPÑèß‚¥±/w˜Ÿ2ýt™D›Ç…·f.½x• êò¨·™Ö/+âÞ÷R_‚� 4Àü¡7ìóÝÉTŸµ¿  üj0ƒorÿ³–R?hs2¥¥lŸ¾>\”•ä_fMå?™@ÝŽà¤x™M™%¢'³ñ&£ ul!h^…wŸ‚(½hmî?HÏÃÕާÀRRƒ¾L:ÀžÅÓâ«KËÙúM" zzš6�;§ª`©þ2¢¹±à\¹Þz¨ÐL }aŸ†|ƒx)àñ$nõí9d/¤Õ6èÒ´¹˜$ü ½SŸ³ƒ[VÒÈŸQ´äÜmg?Þr>ÙÂ×G²M­b~ ?èÄè~†½?ëX` kj°Ù%™~vv²ƒ;ÆÓŒÐÿùÕnˆq÷$åû‘ìIdµäX6µÄÒ7Å üÊÌÚú1Xf7ë®9Â8œfJ¬Å(ûÊ_,ɦòþ)ìöãppüµ ¤¶d)zR/‚íJ€Fr.¸øÒhºo”o2´ü%± t+ßÁˆ¼(øðº›eT‰ÁÐa+ìÏ[EZú²hq0„êUá÷è²ÿGoîO�@Õ4z­pÛ}²©,®• �Q>r@�±d˜É7ž¡‹í5Ø·d<ðkåÍŠ `ÆÅŸt9Ó íÖãÕi°ÃDRêvý× êôpå1Ÿaº·³pG'æ¶F¾'Ñͦ—ð|Õ[V½l5‘[—´E¢n¬‡^e�•lÅå[tu™>Ùj­„›%ïð»ØqÞK¹”©hÑ© Þœ’Ùy.òá‡Q‡YlÚðš�‡õ[VÂÄç3 V=z¾Ïc b ‡w_ ¯É$”–E{°__ÎrRSÙÀ7QnHÿˆ�ðe; ÏSÿÖ ±?”ô&)Pqóhzÿǃ„ºœÑn¿'YïLƒÔs³1øqDß’„E%§`xy)_3*_/Ì¥b? Zu4–OO8 o£_âÈ-ÅÔd�…£-wÀÂ#£pN�)�0·„m“ž²›§gÐ5ûXLìÜ�Á¢8<û/-ušD›:š0êêU\ôѵÁ�Œÿ˜²¡’I…­¡Sfh2•î'T×QÌÕ߯“ìLÆá1iHÐbñ×7Ï`NÏUaê¹7xoÙvÍÿ}]½š]øXÛ†¾˜ÇRCx-&çM!—?lyŽ;gvõ7ñ« �Z� ­W–»Ø#€Ãùôà— «°]‡‹ôèŒ^>åL~Çj[ã÷{ÂÔÑNº^#­–¤Š�`v;Îk ayÊO@4Ú¾»ÍgB›½¡ðÚ 6ø~îÞømN r�öðšîHR³ `¼M.›[§Grn¹Ì²FŸú&„ƒ�ÕU>íú{¢-kµüÉ>s"m_ùÔç¬'ÕŽ^–1ù¥`D‡Eõ¯‚ ïä˜ëÌ6ñ)ÔŽf`nž#^•L„5“ÙÖÅ+èŸY+¸Dá¢�EػȾ%¶rCQ²þ0tüT'VÂ#{zÐs�: g>ÇþåÒP}>�”÷®áv)¾„œuâðCa$Õý2ÀÃ0œ¿õ’Ñ-°Ÿz•ßãåSžâ¨_�³Ò†=,^ òüS¾Ûr–žNŸÉ“grý’½œýûý8_¢Å„¡&„ø]½O™nØQ4ú?&—‰¶žÏ˜å'àá|:±Í™êgQœ•yš–AÙ62µóc޾ÖôH_ÀmiE]Ú~ìoY �o ®g—hë@&·eð¦Òú*Ne£éßV�i¸šaÄÔ@öÅ`%ˆ»hÃk«RúÙs†^Ø@{�&UÖ«àN•jvWs"kàz-{$Ÿ×¼uÉH4§Œ©vq%7m™KU%Ë-¥—ç ‹ÿ ²Ì`-Þí”m«‹¥vá—ÔýìÜpsÆâæ|,ýÈö§ˆCPd2?öuû±®ÍŽ'QIÙx.ld,*µßD~îQ<[qþdþ2˜¤RÒËÍsYÄòu§¢-‡ì4(¢n-JK‡t÷Ÿ\r­ (…ßg5‡—’h×8e,Ä{Ì[…Šž[®ñÎdÒja`ó=‡†ºMñÆ ë7�ò>´·v9Ší¾N%M¸¹Ú„KÊiî�~ÿ® ì‰H[jv”ÆKö³üÇåØ76 …š±�›ÃHèÜ1ÌU¼Èšâ¦Ñ£êäÖ`ÐøÓXýÁ‹žJ†ÝúêtAôÜ ýÍ¢K[@½è43_O å¢0ç’ 5É-ff²ö¼�ß>TjÑbÖvbèñÄÞli¡F�[pgcL–Èøçû³úAA²�½ÓÊát4R¹É7GÒÚMœbYÈ—ÛМƒÝ¼§.L(Yµ¼p‡H¾€Ù�©€Æ»: ;pg�r1Ñ9oëÏoøË­½yñ„—ìÕ±Ó0ÅÚ•N÷ÖÑÜ¢r€[ Îc!Üñ|LÅY"|ö¸_ìíþ£P^°ƒ—pØHV{sðîMYš'õSÌì,׈Þf[¡›Ænº2Ì6ºëÃì >xÍoË©pX]q„6¦Àà•g("”KîKc´B ŠêOÛžlÞ{„Jß½ãßû6ó;¿ó# ò™u™5j—ÅÐcñ«à2â6óZd�R?[¡º¸ äÖg2OG ®B™Ö\Æ=Û¢éyç$((b9ù§àfêZ«¬OæðrͬÿöÁš¤6lå§úoÀ±Óë@aóc\#L§Ïä¹ïÑðz(“8äºÚyüÃg¿¨ì›ÅÖË£¼VZµ´[ùU”z¢RP­ÝFË?PN¹Ø^ꀟÎýx”K¢×­÷ñä^gã¢áúÂ\ÊU 5Â'Ãjš§W UßHª4Oaò]û1cNEIΪY¨^êñ“·ñ/Gl&ùÎDzг‚^oS„NAh.‡²5{Y3¾ã”_è™Ä~üøZ¾øªàøMÍP°Ä2'’}Âh&q'Ì?“µ+A§,3sÙÄ>=…¥�!æöWþò¢Bvë¼-þV££Sºá­“EY(¡§ ¦¬Æi›hö‚µ°¸(™éŽÑ‚9SµëÂÜÖãén5«ôή·�å ‹PI¯€É\ØFö¿æ3q•2N#²Š\ö>íËá5Ü!6Ï;üF2õ€|TwøEóWZNO‘©»ÛéË}îV¯ó<ÝŒ&«î�ô—¸nƒ†u¼¨îu:}[“²ÉÉl}´tÈÑå� ¨HŒçÌ?´cÿ“õ´#¼Å;œ!槯Q¸¬&פÂÚ­Î%¼ŸJžÖÕøªÿ8À÷zD‚{漺#©ÍøÖÿ2F”À�Z\!ªqqN5âõ±l‚×[Ø1`B—ƒWAåÊZN;¨êÆŠ³ó`NúODI©Õf=ãúš2é•y $¯’«ssµŠíj°Ì3u&ñL.è…1[ŸÙ�Û¶$Âkûx|{Xš{ý[ ÐR•ylJdi›.c”X1-û-CK}è÷ÏaK©ÛQÂèËðº–Å[@GÉM£²þsðPviL9 ŒzyW/0ãO§Xú¸HZë´ 6ޝ§‰fA}ç^º:­®ßùÅ"þ®ƒõ¦º$^ø�~«ൗãHì]º}ªgã5åê$~}Àðü>,¸0–¬ïß u˜b³ƒÔT–ñ3þ|`žÖcíškü©îxL·:K«}• }\ 6t>`ƒ¯_°[_Ò`Ûu}Ú\§ñ�>0ôú©4òÄ(ZÿÕ�ÚÖ’ZŸTx¢•>*” ÁÔ–Ø¢ŠvÜ7– ¢»ÆdãoÁ~N.´<Ÿ$ŠWEÚØ³™Qðï€d˼gêç‹qlÔò~(N;.£ô£ náÊ�xˆ—'ãD$;yõ5š]g¡ÑÚ†ý³‰Æ·…ÏX:=eO3¢húœBÖ+Z‰q«À/9>Þ2µZ/;–Zz~ñ’§‘Ò÷£xcòF¼zA‚ ö¹KÄüü4˜/šD›¸n’"à�¬&/^J_ãau °=K¢ §èËÙùp»ÍŸ´šðñý:h!lÕé5¤Œ"Ùƒõ:ô(,ÍRØEšä+^qÜ€z]׿**ûÔÇÝ;ù 5Ö¼áô_­…qšÚôV1�¶*<‡U —@C2—½} Š9ûGPg��[ÿˆõ}jÅÁŒrÜþ–KŒgg¯FÏZð8 nyÁYÏÏC¯;‹`ãŽå‚rUj¹¦çF àÁ†u=G]á@×s¶ˆ±Qo¨Èx,衲¬xïÎ?‹ñÁ«yŸ/,@gSª.¸}ÚŠÛÍÞqárÎ`õÐ,´¥ë»oð�Z¤£`å¢`%ï$ಙ4ê��FÏ¿íì e“l‹‡æùCe¡]{<�;ù°~�Ÿ�c_ÞÀ/#ÛY×”Hpµưk àèžHAYó×g¡ÙuÑp¨; ®?ÀK&O†TÍ# “|ù ËÙŽü(–7¦‚»{¾Ÿ>éÅ€½Ø h \ onƒÖUñdb<"ïŠáj먿ê>|àóáxüqÊ¿~šªæ¬T,Å m ‘|‚ðÖî;Ð2 š'¦¡—ÆÆÜ!¿k"›ö[—íYú‘Üdâx±R<ß{ŠÒ;C©6>Râ²ÍLj—±…I‹�°Y]ðË�(•dø`^ÌFø¢4¢î;‹F¿ ØÌ½ãPÃZ™�RaÑ¡òPx¬•Ë…ôáVü *7D©1rl$Q'yºŽí1c‰bä¶J‹öޝ‡øÍ;pI�H]¦}^ó�3cÝá�j6µE‚Ýé|ÉÖœ 'ÕÓ ô , Ò¬û>–Eˆ9CÇe}¸ÑÂcªð¼)Œ–6ÄYîeãªß¡´¨ LèÏ¡õ?_ÁË¥Iï^ÍNÊÚa^o\ÿu’�ûµûǰðFä.¥YZWؼ?Oy@óº§N¦ts%'ú9Œ?»í5DRû¯OêP¾ð'6–ÈX}ªYÃ>�u¤îsðl¾'ú§±;©F4›§~‚µZwYÔ¾BZ<#” ;Æ�‚×z*vÍýÁ‹ _¸‰™ÉБP¸lz…½¯ßÁÞ=ÀÜ,'±<©Ý FÙìŽÍkt“'“É£~€íÿ¼Þ…Pû«‘ÍÈmÚH n1a1¬Û¿@‚¢}LÍ?ÐÜ—ƒaeTlW´‡õ¹6d�0 ‚ŸZêÄ Œ•¯�Qè3ø×ZG¾=é,û€!ÎPìäÆœûN§'—Óã‚©(;ç>ì’¨†sßÜX»Û ¤°®þžP·¼áµÔ­§ªÉj¨NrÍ`Ù¯=ìá;�º˜§?±xÕø;°ˆ=¨þË,69’ň�Ô)¬ƒf;ÂÞ±ŠP{&ö®>ÉìûKPD¾†Œb(¶"‡N&¾!Á$9(œw+K/3¹>3’N®á´Nîf}æÛ˜O¶$Ý[ zÍÃÌ®×�½MV�?®‹iÉÌ0>fº0 ¿�b#^üeæ®… ô( ††Ô8ÝÌb�� Þ ™K3pþK¤½iX· š¹^uš©b÷Zr0¼ =_¶£äÑVN�ã‰f~ý9}‚ÇÊèÔÉÛ˜÷é >ÎÍàcÿÀ�–øZs‘ótî€?!RàU[‹ŸîvÓÀÜa69žÇ‰¡r0@ƒèüUÔª}áOËe °¤1‚.¶>¦ÓIV4ñŒZ]õët5£¿¸B9âðØÕG–w�ÇBëV]*R2gU/¼½}”‡  xk+–ü>_‘–yoi‰`¤Õâ º´Ûõ›¬üÆü`ÜñD ±xD:+CÁcêY&s²O~机ŽÂñ×RT0ùìùªnõÞ}!Šß@Óú&'3 �+Iôñ0v<®bÛ¢¯³È‘�`²!4{yX~û8^îã�&HS•”œýbË�÷ÔÑ åÐHå¡‹ Íå/ìy¾ìñ`¿4�Ã!"2ŠeÕ8P†évröiB·UJV[¿(Á¡ùS`FöZŠ~zÖmØhYøb {¹ï'} ›&èÄUŒœËä,`éW&q Of¢Zƒ>ý¸ZÉmnèÂ+o< ï^»¹t-¼Y=ŸWðmĹ—$¬Î¹Î‚¿7nÂ~Í_Œ5…Ƶølj *œ¶�ùáoÙŒl"+Ã0úi¸.|Ä{Jp¹u•ípÁð’|ÎÝlX\ûÌ^�meú«‚IÖ<'6ÍÀ)MnÐ÷h-±Ì³¨þ* ÒWÐH!«ï’c€ÞÄQ®¹zœÛÉÃô#½j‹„»·âˆÄHÊÒÿ‡ç¯cë¢.Z±ý)Û¢zš´M)6éžçxpù¬fåp¨‹ë2v€ë^þPÔõ„‹oÂÛœ;½°i€N½!‘=É[A`úŽÝí#ñ··)sG>ÿ^<œíÿö�m­Êý•†KT«ËVä|w1m>¸�ÝË»Ë4{€ØÍµµ\l%…é_†Ž%ú*q¢*˜ýô3læGÈœ,A¥�À¨Ïï¹¾c…ÌòõHÖûë0EøçÓ®´ƒ¬qœ$Û8„zŸ8±?Ãðqg *o”GåuôRLÅq E�8*ŸßR¾—«l f«Æoi2¥êÒïœEaA>wB‚cŸzŭ̧„PÞR+>ÒefºN„òÜ^ܚР?â#q™¿6ù7¹ÑvQ’bÆÏ:„¨µ6£õ)jú°¥fß´XöÒkÜHÕf+R�0é‡�œà£Vß9Ì–uƒØ]Ê`xɧo¡/C>ðÑÝÖÙŽ‡´Ôn‹Ø“3h¶Y>Ûàp�­ ¿NÏÏ%Òß´+r*�$¿²x~áVr û ï/Ð/q:»í³ô8Ö.âÙ!ÇfHoG£S#©0Â(QŠÂ2lþý Æ'1£ÍÙ|ú8ÚGX´±;UJÈ“ÑÐ~æÉH/[G^�g »I‡Ua'müXD–û²1+0¬4—ž--Ç„²¿\ž}ÿNê½8<. Åáó]³étÞ5þÚÝ0òÐeWÔ+™c’&èĨÃöùÉÐÒÏR$éP¨d]þô}`Ï�†®éWÉîp1 ?øÈ$ýîQôE 1ì`†ySþ“ßãdœ|ž¾í߸ÿºÊû†á&øêêÊÿMºÌäÏ÷³5ÿ1�“I�¥Ä@“È]áKì X²ˆ”範; GÃ%EXßXÁ–-RaöË¢iº €ÙºìÄ¡C+˜Æ{ž­Øw“ŽrƒÕg'C“O)JŠÒôúd $~çp›4¾aïJß´ãð"ý5ôªZp¯~Øòªb¶Prò)æ¬áZ¶1GÙnAÀŸNt>ÜÌ\¬6@FèDz¸z%wÙ2u_„–ÃëÒ%|ñ»|Ð]VÃfŸ¡§sêf+Šâ‰A1ø�tg &âì.'Ø1óµ}¼@ŸTMت¾XvB_,V}³Ç÷˜­ïûÝ�MÙ#uøáÑì¤÷Úì( U^ŒÕôǦѶ1-`©&nåä" iá‡1Úw?ÈTIÐú3�8KV€ÿÒ\ÉNYˆû•oBs£Ôºñ ×"¯æBÊQ³¨œ{ã)nˆÊ†¿ýoÇ90åCz .†3óØy]EtÏ…_"É+¬ ´O%%ëJZ´|nÍÔ‡ùÃùìÊêD {zŸ—½ŽC}ÐdfyÏÑ…žQR0¦È6fIÀÎkÎìÉå –d¿ öô�°2¹›/°Ï`"hùÌ‚óçÔàõo~TŒ!Ý[l#Ð÷®óÒ”t6� ��F>gëqÑκá(ŸÜcÈ(§™Ê'p…aÄWq𢢠Á+ók{gpnã�3ÓµïØí«a4Z+�=u^\¾zžgÚ«’Hsj!.†]©q´kZ³åO3  o.@öC’±½‡áú`Vò˜“Þ�ƒ‡_§Rò¹Åðî×xðwx‚câ²=ù‘µV,ü¢éÃmiÐÝÈþM2A%­LœðRŒ¶ïgÓj¤àšQ¹¶I�³˜9ÞjœÇMÏdijYOT°³´;Ê-¸a_þBA'œo9O¸âGÀÀbºÛ'�5é–MÛbÙo ?÷l™d¨´ŒhdõÄâ“+Wð¡Õql÷I€�}3Ø5ãí47·†Å dñ;¿V`júX(ÛE6µÂ°:)ˆÂº�rï]'ÑE¡í`È5¶fcÍÃ,năfòú/“”¡å”ß{�IæMFxž)H3‡Ä ɤ :Ѫ{¯ÉËf²Ï…#XéŽ+ÌÙ0‡sX­Lï³F�ett¦;àñã~,ÁÑ3xìz Eè ð¢-—²|sl<6œ^¿nÓ®)é¬<ø7›µxˆ{ož �[…­Ükòà@t5{l«@‡uX’Ô"®dy$mÚ?ÙÜLA‹JÞu³Ò«UlÃÀC$†W.¬„º… Ýð�›pxUt E‹˜Uå·) ,×Äþ>{̯¸Œº�F0e[»së'Þ$±%—Bá�Äcî�ûJ©Š„65cpú®M?S§y?¦½ØÌ”6~aÇbk0ÓØí"9ð®õÄ“�þ°DO†œ?`Á“ °æÊRú£_B3=™˜†=Z”ëó74Ã1â‹!“Sêç©@ó}"ùÒ©˜p^!Xkê¢ÓÀº#—?¤&Bf®³Hâ]<¾=§ 3uÎà‘Nüð) Ç,s®]`øš9ôð,¶ÄWPZò‘m pg©‡gCl&c…O¸._QºácSŠ7�žúøæêÿÉô�ÊPáÂçØ””KÁdiÜ#1X�ñÐ께VE´ ä9Qv1â¦nÈÅ¡ÉúTB‡-*¶Äç_]ƒH4{±˜Ϙ…Ó{\È(þœÖ(ŸgV“ñÃOìPS!n¿¥LM›Úø·f¯ØŠw'¹«EÜ—Õ™ÕÒ{8ªQ„}ÖN³¿£áñ.&îìÆžÊPšw}m¼6 žŠüeïÝûpW¿¬¾p“Nu03…&œ¬Äm:Eœ„asÂI.àôõ'8Jÿ?eXÛæƒâº4öÁ!’Éj?dkç¿f 3&�ZPÅŽ*äf\ Ç©)»é^yëüj�ª7ŽÓ]åÍ$´Un *à6ïÿî†öXÒÑÑ…Ö{ÿ˜YÕnNòH$õ|IJ±ËÐXelíÌ÷ûX¸o‰.8O#âV³J}36mq ¹‰)cû¹�(£& �zt؃ä N÷~#öYçs£öhÞd%º Ÿ#ûå0+]OÌ”fa±ÇÙ�éë(øÑ6¼è—ÍŽK.)QÆ_é›Íóñ³ÿkNð7–,M�Ð6e}z2,˜àõeÏ…âÐp$ôµŸd>?„PP­ÅŸˆjeeÿyö7 ¬$«x—ë¼ê›\49ºÂUL™÷íE4ÿ³ç¹ÿ!7/ Œ%xÃI9-ª uƒƒÓ!Ð_—9áù–Bæ©›uV}攄c˜ÔÙ”TÐVÉ›ÝËásV/§à1dl^ ß^di�‘h•³FÞ΀Î�kY§ûêY“t>óÔþÇÝ5yÁî\Ì"ÏÛG¹óbOYÖÈwh°;&¨ýeŸJ´ãاÅ\ä®§èß�§S^ók^µËùŠÍÿ (lË?¦Û§1÷ñûǧL¤NœÑ/¸"«LU¡½üBI(sô[8Úžü �éÆëU½¼xs7{Òׯ6]P¦Ó,û•$'ÁåÁ¥q©kû:Œs÷ƒ™ÎúJ©@ ¹Š…tpÔ;žíŸí‹ulXŽ…,Ä®zñÿߺÖÐc®ŽqPå§/œLêªáxù§=ÅÆ=åî ð3–¬ç§\¿ F|ëÈÐ'ƒŸœ¹ >W3B>¼a¿z‘VDA¸ÌK¨3ªƒËpýÀr H2£•ûõh½æS\=$O—* ©oÒTèè&¿c¥(½ÜëïÿÂó÷Dêxƒ*ž¾‡©l®§¸¡w,=J ݃½òÑiL\[ÀÝ;|’ â`Í;z…it%V˜æ èAýÞ 6#n˜Ô¶2/\G´0•�¼ÿ›\�à�=Ì*c Å·bàm¬§ `ûâjÑxþ{u;pKž$µ’Hí±$3ñ Ÿ«¨Á2IøçfÀüb-XîEÒÈ6ưÐÜ÷d3ô`Z× SáÔ”©hó[ö©S vŸûÏ£=A¿RRÊ‘�U1Û{ÖbgWPÖ$ 7ø2<‘ü÷/B­"±ÃÇiqÞusÅ~ù»;™»s¥åÝ•´#v7îjdøy>š¼ aüOѧÐÏx fÓ(¹‰¼r—-õžŽ�gEâ#w”Ú·¯%ÏŸÝ5ŸºÔã™KÕ1Ü’›‰Ú£«©«1¯©„i•Þl»ïKTU9 ãgCéèP.ɪ ÙÑ<Ö£·™Å¬ŠBßÔx~Ìù\,V3„S.I\êÔàxˆMZq�õx…ÑÔ�³(uaM>zž(¾I—ûà ‡Ïÿd ÜÜàöWÚ+È]Þ¢Bù®¦0ö~2&nZͶD�Ãcv¦ðsž?½êËfÿ£è¼£¹~ß0ŽPDVH2‹ŒŒ(áó¾o M¡‰v¤¢¥´”!{d¡ŒŒ$ãýÜDí­•&Zß”4~~ÿ?<ç\÷uÝ×ëœçœG2ö~äðxzVÏaÂvUV6C4æR]‡qÇ•àẳ°Îíµ ¼x­O†Ìñ¨9Ì.MB÷Êàà‘0°ká7™ïÌ1–eZÁôÍ�Ê3„–ˆÙäø�eâ}OHETŽÛ4Ù wËÇùbœ@$ÇûâZ~ŠöZ6¾ÖÊછXòÃT´[³Œõfy¹×™–˜yã©Ñ0IA“Θ^€·£òØÛ¸I qô;›,*I6f.´ßìÓuÑÁK àÁIb3¦c•¤3÷%ê³»XAßýÁãNUn𽔪9@Xš¥+œå„ûáÎäQ·ÖGÔ�Ç6޶®¢“„)(b,û ¥JìÓ‚@l¯\)³-éi|1òwfUqÂìôn\«‡ÉæMèßð‘K¿Á¡‰[?‹�õóÑ’6Ÿ‡Ùy|U9¨„Á-1œêŠ£ÿýÀ·vj°ª|)~´8†µW3V—Ná›â`¼¤ö„Éì˜M9ÃÚôöƒû@8n?ÎÌ `íÌõÞy¡ØU¼Ÿ‰%`â;ÌpW§‰Ÿ²Iy—3\“øÀJª§ò†ž"6ÍGÙmvYP¼§$ì^ÁöHrÉÉNØ· ßñ?XËdQ2=# 9§EHê€+ª¾„õEXñûÒv°òKAôTo/ô¥¦²WBæ8} ‘äUPÁ¯6vf�Ž”ÊAq½|å%Gf»’!LQ— -™¨ŠP£Ï'Yömßœú|u�-FéÂÕ—ìÙ„xîë¯Xl­å_G˜Ã¼ªR¨õ¿Ëþ)ã®:Gô<}³�œäèà k26Ì‚–…2hv&Š„ª HZ¤]çÈÿñX:ËžÓÂ’ƒxø¯Õ^Òλx ¿jA}MëpiŸ¶›L&Ó}=0 ÕÄ;š¾·rµ×¡—o/ NücÇפ°s�˜b‡™Õ†= ‹?o,Ä�¡ö0å�9-wÀßm’¸ï˜4ÿ—…ÁÓÓiÄ;S¼›‰7á)õè?ãg¤ëSAñVl�”F3%,0 O¹/¹XkŽŸÓ<ÂFxÑ)œ?(F¿Gçà%ûá»3 ó}o³ÏÂò´±<�ö•ƒD¦ ¦Gn!I§6‹>VO9Lz2§Á£é 4^ã/Y>á¾~�!½‘Š�GwóþŒóx–ÉT/š’Úî3¨WÃÑMeÚ¹ø>)Êc'7ƒÓÜzH�>®)‡Á ÙLp0—�íjâZ…‡{”†î^]Íšôÿ²ëj˜òOq¦Ù0O/ߌ}©dy'{ wŸýŽ»ÉÇn mø;m„¥vÁ³³ð]!œ¤zeÐýŒJì}оÞnd¥‹Ÿ°å¹�èóæ|K×Äé«áp� †©‰ÓUe¼Õä5d>…øwøpü5Á~“Ûì±ý Þk\èx,"·ä"Z4t†- ý…«Û‚0#Ú6ÚRäX vo“'ЖCˆÆÕ5zXíÃiì A]ã0ìùéÉ©yfÐèó9p t€î›õ4;I .§(S¢¡Ó¼ÙÊ:ü_’ûÒ­ìït;úg~Dð!×%CShÍwÐÕ—'ßÇe¬®ý/HNJ¥WŽÓØ¡ú6KÞÆ¯®ƒµ?¹ £“ ÙŘnùJSº&@{v˜ÂG.@çà �Yk¶‚§™ƒ_$y–•ìVÆ3KƲjjlÂÍñ,íH'š‹ ã[…=g:,/È A¼q–¡lîdvcš(Åm¯c‹�/­ƒè¢e0P†2[_°ëA7‰åÞ¢/­m¨ý¼„ŸjÁºå XЃYìXü(¦7é&5úÉcŠP8Ëœ„ !3©ìÃ&zõ1 6Ç æŽÐ1¤Š°\Xïw�ý'‘ò�£È¹BwI¢ÃñV&t²¼ä—Q¬ù9’R·äŸ¿žGö‡sY»œ"¼ÆUÐ+…Sœì¹1#ÆÓiù¶l�6ÙZ¢ö¥›˜ùs$›v¹žìÅ0}ÊJÜ¿ŽØîúwÜÀ§1œ°‘!þÑ0gZ/j°CÃÓ½½@Iø%ÓÇ;N‹ðr÷B¬ËÑ#ç.q”êëÔÜÍD_˜@—£ÖÂÖß X;§²•ÎçD³ìÂöks9¼Ž„ò…�`xÿGª� ’®lÞšŒG£‹¸kq‹1õã5xužm69Ã^háÛ»¬µñšýK–ú³(aE*ˆß›Š‚µ––oÊžþeók~0 ·ƒVn�ÁÉë*Ù²·¼ØV)¿ 5ÚEìï‡eéÀâòòhõ©JÖ¹r· [“Þü3¡Ò‰§@éÇtÞñ‚íüNî!>,ZŽ›�(5q&û“­†uÙÝU+áCc&hüX€÷ïe³ý/„(}~ ­Yü–u”åU2¢¸Úî!^œ"pù& þ¯ŒöÉ»‘k åìÛÉtÑUV゚,tóXùEÆ j$IÓ#œjWA!i1þ3ÞOuî`²Ö=‚³2óØ o0­S˜Ã�Ï“ûæ1¬æ‚[¹/ËÙ\ßè‹]E߸c&¼í±‡¼é]3(tý�)]¿ÅRçèSJ‰5JÙþe¢‹˜œ†ï™³ @ç?Ùy1Åo�ç²QÔû¦Ä§ÂÚroæ½u"~Lßã'šãaó tROx´ÐìÜ|ZÜA2»­P5iuL/!ñ4Q›xáXaw‚ÅiÔØ³MX\õ„¥¤FÓj[WØ«ãN”ÝQBe+M-%3÷Ý´ý©ÖŸ)ù)OOºÙ¿¢4iÆ.Úߎ?üï3&Ý3\šàÍÉ[\_ö)fòÆuõ§Òõ;Šüþ§qù Yöй—fuÔ²6©Nî™÷%<¹s+¥=ËÍ0uã‹m|˜~¡wó¢!òôþ@ê+æ´ë?®É*’žÿ�@,•QÍ iòŠ`_lKØöÙY(3-NM Ù+?pæRWX§ÌS8Ú<ÈH6€e_-o¥=ë�qêš(t†n?åÔ7-çC£ÙË!2Ñ¥wËjqáŽp6 áÂ<ÍfKŸE�î“d"¯€—6t2�öþ ž�÷!jVŸˆŸfn„«/Òi¾’=íR7ÇØ9&pæ’8ór¡°E–\}òhÚ¹d2ì[ÃT"vѨ]¶d³U'�÷¥™9°SD�½}Å'9��ƨ•|äᚆw\¼¼VÙ®f‚©p{a0mÓÚÍŽüt£tY)x1"”Ž´¦·åa¸!N‘µ\-lhÝ®H¿Å¢£f öû¡ì‘…(vÅ�iúìÄó:iä.ÂRÓÄY¬GU–®ÙBØ£R*mo§O™%ôlX»G ™¤zæ-»™„ì~ÊG¶@õ7Û{:ÍÂ�gíHl<ÂçV{Ñ+c³E„èTùtý1™¤-¦²—©]Ü„¹®nŽd ñÐòe––ˆà¦I¯àÏž.®l‚:íz©!ÞA„ê‚×Ñt2#-–$—�gÛ´(àò-(ÞÿÜ =‡Ûub¨˜— †*Œ©o½8®O�yâ�¯n[RwI5ÿ›GJqE¬¢wk@¢baô{•.×?Ê¿pQ¤›y{ËûóTÒæµƒÌ@)ë´:‡7]\`Ïù¬ßÀäª7ìºÏ|œzÞ=:ÓL»Iô²¡˜ÿeT‰Ö"Ô¾~ÍKÑá �­!Ëu´óÑ:?x�"MÆãüYìË+{É…jòã0w´$»í8Çth�Ð>yú%æ…Ém.˜÷öTð†X+}�µŽí¿"Ct|–F‚¾$ÞS‰s÷΂Ó: ¸KûaÚÄѨ}ѝˆ3F7ŽûÞB¡~±€%Ž”Äen‘ø24 }ŽÖa˜_>y+ƒ ·–áÈýJ´MÝ…+^µVáálܪa‰â 2w@�úN¼‡a.³¥HO¼ ðïZ7zå7žôþ`òï^°Myýà½Ì—äTÃ_”:ý†›ò’f<ñÆtW ôÊße)NË#êPÛ—'½ Š6y…ÿMŒ�uá†Ð«ø\®¸¢¸÷ (¼¤ÏNÏ9Â|k¯ò¯!¬¾#ƒçQˆŸ$1¬Wï¥�½FÔÛ8ˆ®ÄÑžÓ2xn}/7Wí#þ› m?²ßGPZNÈFúGSC…vïù¹Nçø�-�¸1§åÉ"&Ž™÷‡gR@5{BqëÂR¦û#]µlÄd’ðÅö…´7¡–ÉJ™Ãá–0öh/[½M3ö¡Ÿ�àÝ|Bð`Å7ˆ{þš³›”ÖÍ3æWê²7cò7v–ÍÛà ),§ŸÙ˜qm%Î ^¶‚wltË, µ�Á^Ï^f¹&ïnˆ¢;•Q ÷ü0ʺÄ»aƒÔlŠ[‹-^ÉäSÜŽwÄ-Ñ4ùKÉXÇVmýÇß;à©=¬½p.`Æv%Ì4ýl]*È«¹Ä&ªÕÁÖ5;È köèͯõ˜|, t{ò°a•;Û4MˆfågÑúKüT¨‹±·Ï0G9YVîí ·G£é½B™ñä~ýÌçÈKP@åi¼¹u#&¨Dëœ!æêðo°]8ùÖXŸö„Å�ƒ57ÂH:Vïùˆ³%0À„¿cûG7øyÕ]Ü€ŽFqÔrE Šm)ÎL<®MbWoûbÁM¼QÉ'ΈAáßÏØ^çݼçó3äµ@ö�)ƒ—EVø[Y�Rwnã=•›_/>‚ñÿc7’Ym®™ß1aã÷PŠ–b£˜êX[—7ØLóŸæ4zM%×þr9¿½¨ð¨-nÈ Æ7o³Ø,§"´ý*?Ì$%ÌÕÈ5ÒdéºÊvÏ÷žõ¹`—(L×ߌ¦Â;صFæb[ É­KÁ™_�ïÎê2‡c!�6F�ø6¿üþÇFò7@t·"ç GrŠÇ¡D¹Ÿº.۵v´bé&›J9ïã§œ™ho¸—V}Š�í²xd¡.ÎÆàªfVöo þÆHúv<ƒÝš½�\÷ªãØ¥wA}Ó vO]FÇÐèh8�•HEﮀæ2]öXÓ�´B[ã‰Ãž­e…­d°(>ŸÜŽ’î«© Fš—uNÀ‘�ͬ7C„tÖï†Ø§ÛÁVǤҴ¨úB‘y‰K¥PÈi�Û¹¶ž‘ìNDõ2�ÎÍß¼”FÉSY²Ëp¤J?¶Þ—$µCØyG\Mª�ÊèÅêgíä¼³ËÁù×rÁîåŽäf%ÑX™úk³[pÃtÞm›3»Ë©r‹EŠ¡Sc ÌŽ €ký0î�+ Xäfâ!$´Î˜9=ìƒÇÇ4ÑOè3?£s¹0�}wÊA‰âGìÐÇ­¬ùþ3ìjä[®‚Y½jÕ”�Æ�æ`z%�;3¸™m/ £WEß¹�‡¼[Ö½ç!l ^ ‰¤ØÆ“è~‚œŒï“SÜE*~TŒßfx7,ž%‰^Â˹«úQt±Z„|ä&76IŽC‹‡Ýì¹t"yÍo&hؼ5:�>~ðGLŒ–ÖÆàRKUœcW ê‚ ¬Ö槸Cÿ-\%8âÆîW¥ñÁñÖ"N†Ìù›,�Úá6Ç=±wuÓ~7Î>ÞËsÁUlÊoŠ}ô@à¶PŠ��ÑůzâdMÉkÐ!=ÝŒûØõ©'x陑¤£`ƒ…)“Ø„â/¸&z>M̃ ]>Ø|ºÜ‚ô_"tßwú¿4‘*+ùƒ…è!=C‹äØ’Á<Š{ŸÈŠóÝÐê,BÇZcZq²ŽRÝíàn¯3 +Í£}!õ¤xæÛö]œ+~p$Ë⩾3…ÆûNÇî°� 2e˜+ï¾`> ^4j® N�ÂO›8“ ½3W°qýBxªõ +ºÕh-Ö5¿|óÀ×]Õ,°+'} l‡/~@‘Ë®¦¡²MèTúнÞу®dübTÛkÁ¿) Š™èŸdÔn‘Åg éߌ.:UÊ_üeˆÊïW±ÍÿMh˜9Ú„Ç<Æ%±å³á}¯¾{&¹òWy‹í’ö| Ú}4¤ßûrù®žõªö³È[O(M»’ý3”ilXa“|Ù¶Ž~6h=Ä*®4ÓèÐ̤S¶U+¢¤¸n�t¼û–±ñSðÞŒ~̱ jÊg"¦âßÎ|êTÿÌ-½©M âAæ“25=„Åj8¹¼x–÷K×f­ÙV¥‰�£ïAŽ” ‰ÿÜC½KñòX½D”û¦+„J·N¦®+é�X'}»Í_eñï G’ì¡9󮚦VÆ2Ï?¦ø´‰ûê:N¶nC‰ø�‚óó®7H+Ÿ¢w©¾¨l_d‹ÅSœÍKÜ}á#“ý°C¯Ža‡X$ü]ñ‘††3QwÂF*Í¾Ï / £¯jÎ(Š¢°jY\Ú,KêžÁF••�qssý#`9±ØØ¶µ:x<ñâ«‚Ó¥$ þùžëî4ÀÂ×¹�[1Ü6$üCèËäƒo°9§ÝY¨¸†c8oäí…2r:ô&x½ðž¯$ÃüÁ8´êˆŒQ”L�¥èÔPÚ+îE«>ÑÖ1>8ÈuB¾†n¶c›‹?€!?’Ôÿ{ ÒC[h­ô)ºß¡`ÓúÏ™7g±iC±jÃX:à–F"]ói×ähª—‰¤÷2gý�ü©[wcÃqÆ=]nÏÅÓàDÂdÔ‰ïMñþÍ ›7ŸaòÏë(éí(Pÿ8™ÿgy¦'ÌbÚ“pk³?7@Ó’!˜S˜…&¿ ÝE&þ¾ÁU©l‚J'øålÚP@¦-§YÏÈõøDï;Ȥã(Çs¬­û)¼ë/¢ùûFAèÄ÷p·{5už¬­{(oC]«'à¼Èh>·^Ò¦þòL<Õ0©±HS‚\5ßñW¿-¤-óÍéä“Í‚ù!ø7òÞæÐ0¨¥(Å´•ëø˜pwšx/‹O¿Ûk8uò5óðOÍž{\ÜÐ {e¡,(>¼ §üúÇôw7ÀÎäëtý½2è5Àé}wÀÂ/êx§�/Yœ¹|>hmÌ'îE26À�ðê6àÈ0ì6´�6…¸¼l\'g3òª'qg2ñ´%ð íÚìiJ�&‰ÖéÂÜÔ°ÁÒÖõ¾ÆÌ�>¸Çu5 Écýkf“âÀ)’Öø×ö§¬ÈZ�dŠìØç #èû¢¶â‰"Ó¼ÃöÖNh|ë®@'rôpæ´F“)dãÜ4žµøÌ¤Ê®^¶.]‹W(×Ú58õj#´ì–mLº\Eþ7gÑý?ÇpãàOöÙú0»Ô]ˆváKYÖ¤Ãð8+‹Åo)Ç�& Ûy*W[©"}ýŒFgÀò�+éVÔZ\Í®ø¯dÆŽÛØy�HjëQ&2N"�­ü˜s-8Ué¸õ’šxâº瘷seÃü,²:S£û5tÜõ F\EÞÊ„QÁÂÝ´É4�D‡^A»ò\ªŒ8ÊÎn˜Ž‡i³Œ tß"™»˜hD:V�Y‡4mø³˜$¢‹h‰5¶<;E‹Bœéíã$¾¶ �¾}ÁTö<§JGE Þ¾‰­À?óÅÑÕ:®x¸’‘äXºŠ&FÀÿ.gAþs9ã²>UW­±[xíÐÁÅNzŽs^3‹‘-›ÇÑG©4H3zC˳pm²è¾&.kúüÎã|n¯Ásy¤!îC+Ü%(Çk€dé`쨻ü†½ÒtqËs@UOú/í+ŸÔ|o ·ð¦Þe‚‡�QQ|€îÜ!�_ŸË|ŸL¦_aGP¼HŸ†23莿6Œy“ y‹â0ÀÕ›Ìw{�šG$Ý)ƒ'²öÐy;gÊÌT-Õ¸Áöi`ýymý¬Dáí×ÍWì°mÑ$´Þ>šd¯KãÊ-Éü8o_Úϱìó^¬! ‰ª‚DiÙõ8 *ˆ¤ýK¢ù*©±œBõ N§0 U5lH^Ÿv|w¤)'£ñ`üev”ŸJ×®¦rÝûñ‹ÇZ‘‚¡m—ø$œÍ²×�ÇwÛ”m@Eá¿Ùñ;}°ËÀdîß‚+_Û™Û?ž›)¢F¢=ì¥j o÷¡ªGûñivm}üE›T£å¨™VUé‚þ ¸D&þÿ_0X­TÐp¤m%ÛŒâ8¿¹{O}%í7¡ô)z9Úþ8"j¸?^…é¢{0Ï«ܾ."{|>Ï«~L²Mkø½‹±¼ÿ±£¾ x)Ø›åÊa Ï'òÝÄ$ï_c{žéÒÉ©‹èmý=RÛ>ƒ N�cƒwÒÆœa~:éLóâåè›ÈFüh—E²¡xMã ]ï]CR¢iÌN ,n[ŽÂ3ñkhy–‚ÆVl}ÙL¬TÜ‚ÓþhcKÓb:›ÜÈôCDmæzÎÆž IP<îU½Ÿ‚ùIG ÂÏ––g±&ÓxÈ쟀ªÒߘÅó|4ó‰amSª }¿³ûj{›ê¸?ï‚áºù¬ˆ éÄYh~o;Û²Õˆ?:)æ¨*Úö8à irój€€Ùs˜¿ˆ‹�‰·>KÀ¡CßÉé{8;}â3s@yÜi+†b��\x¡ż`O¬î¥ aÝŸlÄÉÜ ¡*¸¼û5„\€µó‡ Pb{îÆ™¯¹Î ÙØ:åÛp÷Ûw «Öƒt¨$n°JŸ÷aoôlÜQö©áîˆ7ì‡;cË6¦qå†ï1�…£Þ· <fK1&8ãø Z¡†³¿6Ó—Ž"TLL�?¤é“WÜ(ÿÄvC±ËÏYkÀ\Ør(„üf›Vösù'¶!Mµd:¢�ØÜ¢9,ðÍkÈùŠ�~�Mò=Y`q[›VY«Rpx1¹ý’ÂWæIÌþˆìëi‹B4Ù(G_œ–âÒ3RTñ+ÊNH£\©®W„wCæ˜R|‹=hÛÉݘ›BÞ=Øw¦ŠËZaírr!e*Å`ªe9¯bv†©DŸƒQ1�Øi÷—lwJ2+>5Wp“qÞqöpè§æwŽ/è·Â¿¯Üˆ†»�r…<µ’nls8FC±rdø!�õ3˜ÏýclÉ™C̰B;³záWpTÝyÍ:Õ ñ™¾4={PÁö =£é#uðËœ“(%r—½¹–½›(JWõÿÿ–pOÝÛ¶5´'ô ÌÞâ�㺔ø«'ûÀ_¥�­ð§3ÿùŸ-ñØŽÁ^˃ $k a¯ßÓ| ?Ö|ª›|‰å>lƒ*K] q’=î–»{ýìÕ�¹ Ûa¶û­°xûX�ߋҢ4í®E H³=ŽéUÎ…×Q$1½gåâÇÑSè¦÷&l¸ÔD"Mº´V¯‚¯þ% /FÿXòQƒÆŠ3Õ¨­ušòÏ…ù « _!Åwº��d=ô?:C¥K¹ ¶¡´þ– ¦|ËýH‰ Ö‘ÿ©­u lØ¿òo(rŸEj¸0óIR8‡C·˜1iTµÒêÒéž³–’^W°[‰zd'|L«'cù•?äxó·oÞLQÞƒîà6FÑgÍ%¸q­ {+Ò� œ4®s6Žî6¶"ž³Û‚=±Tª%€õ¿^SmjJ>ÚËÚ¦‡³j·MôÁs6éwퟯð­ª*æýµ G^�¾èB|¿`Ûexï¤iÃYï9e%öL$jÝòœn?w�åõá4[d�ý©AKͶbœ½"¼ŸþšŸ$7(˜cPÛX’\² ÿ]†²`±é={,�DüðN<—´ ãÔ;èËó8Žæ’ÌÛûÀÊtpTWÊ¥üÄ”îÏlhÔrT ñèAnÌÒM$é:ñÚ]Rææà»KJMn«êȹ AÚ­±øö«€Àz;‰ßKÕ¦AõŠÀ£™¨)ÆÖ줢cÇ)ª¡²¦¾à¢ÿÅèØ ±™$qûæÕ0�¹£m6/0¢ð�Óàé¹TnÃUÝ*®sãWü…qåÂ6µÒŽ8ä&G‰¯KàÚz)ꇿƒ`± W‰OAq ÷[‰›• |˜­� }BÁF6p¦�­÷ÐÂ^kÚƒ3N6!êÏeûõoò ,¾²�õDGÛwà±hŒî�Dò-­Žù\™é:ÆäÁz­Ý”*tgzûQ©ó;#XæØŠÆO,ðîO67÷¬;W F”LÚöÉ8o¹+1»%€*8Ud*�[4MñÕ@¹ÇÓ†sì;Íô¹ÂûmXDÎ�傸«ÓXØ´(æÒ?o¨b]Â-àŸ;‘mtMÏ6¦¹?/±+ÅÛA…%ޱÍ5+H8Œ™rC%γð=‘0k „ÉE…’{�tΠãÓÔIÒÆ–�ÔÞ_ð¯ÄŽæè+�n÷f6Câ:ÑÊ•$·w ì;wˆe(�¤Ù£<ñħt®¤!€�ÜÅ£ÓÙì꺂ƹsо¢‚Ý Ï ƒÙZd©õâþ„..fªÚq|h"uKÀàðü±‘­4Ñ]LÙZûó=;¾j"Ù¥©Ð¥ò)j„Z¨ƒkawù²#a§íQ2¿<�ÝNi Ž5>PfÜÀÖO›JÿzfÓ›*Cø3é(*Ÿ¿Â-š<À÷]$�”¥$”ò”­q5á/nâHsÑD .MA«ÕJ˜Vñ˜éI ÔC™:ieTÊ“^Ç4Z½¹ƒö;âêù¢tëê:ëw„¬Ã¥aã½첦‹—Ç“²V=íß? ¦'éâÞ?Õ°X²Z–<åÞ8Áxsq¬uHD³�y¸²è7ø¸Ðã™ÁXa:²ñmÆXv­t,Í3ÖĬžù'·áÕü)ø÷¸)7}t,ýt-DÁQYÊZö ÛøxEi œÜüâ«Hÿ•9Y±Êw‹¨:Mmæ½dò =lÚ˜Qlòu;2-ø[•h_ßcìÛCI;VXkhäðñiëqŸY ¦}}WÜÐáœFÇâ7RÈ‹8®Ï¦—¿dûöÿàs²R™SoŽRÁÛÓ]@Kx)sõ‡`ca0�nõÁé+èEa&­8ý–Oœ¿ž´ŸžÅÖñ¸ãDú“žˆ>¥Ê$�°‡äâ ü¾2#\!|‘AŸ&Þ\ÕǶ�Ï!ÓxA~·WÂâºø«WÛóó©ì‹"éËÅcûñ¯#æ]‰ÁÆóš´Ê£~íTjô›Û¢Ú«Yüx�õÁ©8±]˜ÈÙ’ýNùu²ÞhÜ–‰ãâ9ÖÃÿånoÏ*ºÒÙ®™ÏÙ¤3¹�”4±±lþqpyQÞ¼úGi›®³�ö]¬6>HP¨lÇ?],ÔRË­—Ƨ4ÔÏ*d¢iò˜˜ÆÑR¶–IúcÒ¥|1j¸=BÛl'èq‰fJÏe)!¬„:ãîr†ñ³)ó¢ [X´—¯¨e—¶ƒªË\¶oûi~apm]¦o*#7cíj0SÑþ¡ô¶?ãÔÑi['SÝ)L•¿EØ–…ã°ʘʨpTªǘŸéêfIzç@œs#­ I¥s²mì}§%\Tg=iR,“ƒÆ�Ó¸{]éì€Å«‘Ó�i(ÿÎ�\Z“1°å4®òNÑéþ´î– ¹gFÒç |ß<‘-ÿƸðøt¹a*ó±¹gmÞ†å•z86+†×8w†½ž�ÄŸ¥jlªœ‰ieóé}½¹4Vaé-Mº²kçfЃ1þ$²ü_br˜ÍQØ N ílï×÷`68Äj½ù/³J1kÖ'îú%Ï•jSÐŒ(ˆ¸_‡æ,b¦%ßXïäØO/¬ÀΔ4üõH]•wp�5[á?‘±ä³å §ë»�Û÷hÉTV3‡÷Џ5s½Ž•f©’Ó™“T í›;€µP]ÕšöV–ƒn‹5[T ô†AvÙÜ 0×”Ðò†�2‡¯êë`nèg� nå#GàD {ÊH½OvGÂÑãÔTÒÏÊ´m;·1+Ë^æiÓÉnÜ·'å](P dJ º:˜´»Ð›]#ÐoÛ ¨hb5oÅhÅÎ=ÜYqúª!�¿»!½ „‡5¬EºIóäOè,X€B k¨§×Ÿ\…§GJaBõHz‘˜‚¦UrÃZÖóËÇfv¬6�j/ö’±F=·nƒ€Ž|&´Û‹¼ü½!â™™=ýz‘&|’”Ý´ÒbÆî�8÷õSPÕY/ˆ ZÝ+TTÄŸO5)ÿy,m<¤Œ ÄÞ»Ókç6–w8’ê‚SiŸ™•œùÈÿö¡s3ér]éOâ~µüe»4O <»¥iâ…N¼0a;Õ—eÐä/ù¹’ÊtêwšL2eG ¤I3Ècÿcr­—à ¡?D‰=‚1G7�rÙEp—-€­�—Ѳê2|gwéä»gÜÝåu0ÖØ”^vL¢Ãé3Yg�-þ’º×á½\`*-×˜×æR¸²Œ?õlÖŸÕau!X™ê@RQ9éÑì~•4þ9@%OíÙa£rô·“£S±óðä¡Áú ‡¬éxÚYp.È�W+ËvL¢È9 iÂd;ê™”ÏoïB`¾¬ÿº ݯ߄¾6 úóÞ‘ à޵þ VÇrùέÙ(¤XŠÛ÷•�h† ­¼èKµ¶AüÀäç,mÇLðt?Ýó“øƒ"*7-Y‰‡oí†æÜ~ª2˜Èo^ç�ß ³ÈÜ%Œ7*æ«Ãò¹�Ÿ6lÖ1{ÚûÒ“Ë\3Ýß+PÌà*[1‹®Ýá„_޲Q2ÚÆì÷.fîB¡ FÀè?j4p.†øG°¯n÷ؽÛÑëxOÉ„4;ð}|î]C|õh/…$W`¤dÌùÚÉzÂ’èò¨ñX²-ŠóÏÛŽ3£§ao½9\ý’GF7“©øüM(\]„«tû¹c ‡wt`Ú¹¬¥æ“2|ë¦ñ´¯û?ðÓ;"ÊXÀjêˆ?J�cK°ëÍø±.ìéH†ÈÝÙä·Í:‚gú�»¥ŒßUK!ò´ô+”Þ�DÆ™Ø1ª§ Õñ>iD~ŸØû9ìGâ�ì,¬ßxŽ�ôNF‡"0¶,;æ‡ñç…'±3æú¨¬¯ŽõD騷KÔ¦VÉÉÿ®Àt)м¾¶û�€�óû™ïº™u+*®ò§ú>a­o9§o8†;=­ˆ³Øa‚._uðÏž5\‚fÓÏWg3'i`Àáóhrq5;Êg@à–Ðp—süðŒârFSkš�t‹©b±õnuØÉwãÐçã38 •D .X—±7Ü:|7y |šúúFÉ‘A霯ƒc�ªè`fÚ1>ïÅ Ú�GéjÚø¾ÐŒ²“)xJÓ–=$P·Hg Ér³ú{pбí¿Uõ9›ùp ¹��Ó¯NB5/G�œD ·Í Ǥ…°†É¢Ä–Æá5“ñø½{¶~Ò„ÕÓ^‚ܽ2:v¿„³·Ó#Ùç�Y‹îlZPq›ÿþ·–ßý]—‹þñÕ¯@î�ÖØ«G—ÏΤ%…GQ,ñ'›5ì‘ûÃeÍ:Œü\K ÎN‡¦ðÙ¤¥'Šu8&*~÷¯ÏcF‡RáSÎ Ú¨žÈVî\„ê�¨à}$^TK§©¯õ1úƒ³�$¯_s¡¾(�Æß�æj_!êþIÔ:_CßÂèJL ì{ò›�YÕG6ç­È_+žÝž-CÏ丽A!¤¯œÈÎe Ã7 ˜þ/_.ífZ+2I[5ö¯,?R*¥û¸ñ{_vá™Í � Ù‚ˆH&?Iž–š¢³l$)|å†Tºù@~÷EB¥¿Ý€þ]9(9Z´ÇÌÆbíó4W/žw«Uæµ%¡Ëƒq¤4+›} Ï”±) _ ±ï[¦…"|«ïC5^»± pά0oçprŠxÀZ6T㿞$0u�`îñrØ�4ÛrzŸ¿ NUö0«ªSà5í.�Y¥Bž¼Ñ”"¨|$C¢aí4ð¾Ÿû룆çŒ8ܽn2ÔoÔ!…«ÑÄÎ@SX"]ô+duÛEØè•½üKoj*ϯO˜k’8Üáãñ�«,ŽXUÊZ_%pñ†×Q®â ×±4ÕZréæ9:·€rdñÁ†ádyô%„�Ø«&®éÒ:5˜è§E}n±8u(™…þ«o0ÿ�®WÑï±×ü­²`þãºá\8CPêÞµtÅs%å© d±ýpñ~4Þv‚¦! }åáua)ºv¾†¡{ÑÌë£Xãõ“ðÄ"�}š>®AGC�ú…ólØ”€'@7cI.¡“ *ƒ¡ž³'yÜÚ&eó@.…¤7HâæŸãýþ\ÃS„Àî¾1ÚŎé•�ìo¸3Ê(]c‡ßè þþ\÷Íÿ.lÙ®ŒsDŽP·K;ð:~t²Ù…�$¦†ÂTí� Uÿ±´([ši:‹Ì36QÓǧ¬>ç!ýÚã…oCÝHsÁ;&±Ëƒý´ÊfP»•õo[ Ñu¤çð ö}ÅùlI×gB×"àÑŽ‹ðúÕù ÚØ2øh%ŠÙýŒwYÀü6×4¤ú©bçA-2¾H z9‹ŒûûÑBw-ä–“Ù;_¼ó)Žô¤¢Øù‰bh"â„ßÞ¡ÖíhÔlN¦JÓ£ðãØN ¾—�1²*xíiÞ¾®Èë�+º_s¡5èÀŽ"жw L³TèÁäËåÑg¡. vLÇu­‘ðtBÆôDÁ�É$|ö1“ŽÏç„L£¡ïñq²§||y ‡‰oÓo\jE$—™ÅÎx‹sBg³¯l¸',Ž:œ12³Œìl èUÃì<4ƒ](Kkta»u7çâù™ãþ d/Ïe?F-ÇàÁÔ±èÉ×¥‡‡±”e*¾sž^ì˧ÅXÈm½Gb÷ÄèJ¤Єø~|_ãÛH?wÑ·ëC¬ÿɺwneOBçš*I^Íë�C�˜Ô‚:+»¸Wáûp_÷ujÖãIwu½f�gkóÙrI´�ã`e4��ò•³�Å1�¡ûX™cùÇ~1…V _xÑÉ�\þ–•¤±4�„ÌÅÙÎ(?þñÖgl•ðW6¸Á€ž†ÐÌ­Êh»s%æD¼|ú5×–Ëáâks@V­™ß£x …Û&SV“‚Me“„~c�k¯‘’¦8M?y“4ÃïÁ2½mô®:´Ás´»¢Ì»žIb.™8go=ïýc;õëM�ÐÁ‰ìv“?yhߢ“*Öûf,}þèOØ¡@ÙÉÊLf¸£%ÎãRƒÉ¯©æ­yžŸ±‰O§•îa,s\*šm/�]ì\ëÑJI8d�n|â¶€––$�DbŠUIAÁÄ^Xÿ%Š‹LÙÎDgF‘X>Ú¡1Ý·_Eµ›Â Ôi"˜œ?‹CvQ”¾æ'1 ©ÆéÆåôß«rVë©Êe¯°`6汨溟v1urb…=깈Ӥ 4Ï­ üÄ/pßX«|xH�÷ÅÞÎßÐbbGY¤^:‘î˜#ŽP{»™´J¥Šé\¦Õ’z°E=¶dàs„]S~ ¢}Mø§%ŸW;Îö­Po�.Ü~*³y�«ˆÍ—ž2¹�6òËo‡¥†×ùS¥sIÈáD˜õ0'ÇÊ{9D ̹Ù!&¤xÀˆß¶Ê’¹È“ôÊçŒFY¢b`›:0ž’ícþë?à;}ùL÷‚ú¤p˜¶c�~m„Æ·àu†$Øõ q¶'ÓØgû ¬YLGÏ›IÚ­÷ñJr1ÕÝ›ghaÃþƒô¤# �³;¨öNKer1D§s+¹BCßÉ•©»�+ ‹ —iá`=Ù>HÇf³ Þt—¾àD@±ögÒC¥gêCõo)àÚ‡á‘êhX„_ŒtðÀ¤6êª*’-»E™Þú؞ܑš,*½ç�•KW£×Û|YoByMåáü+t{5@ô'azÚ»‰É'æXht×ó \ýf2þÜ’Î<ÌOEÓ‰‰ó+ºoTFÜ"âËñη8¯J�ª+× G¥ƒˆ–_!eíê¸hg3¡¤ Š˜zÀ»g£dѹäM¬éç8Ñö�‹@4û!�ßí n¾�pôñ 06MÂü{­˜ypŒæè ª‹¯ÃŽV#À ‚-Õ8Mc¢^aÚ¦{¬]¨%b8?¾¾DɇçA›qó2mQƒgéñTõ»šÆOÊ÷‚UçO A~õRjõÂ0#1’X¨³ó9ÍäÄ|gZæíIï<£zcn˜b|ŽOÐ\¿R¡JÜàZøÝÄ¡)_mI¹H„�6™= îx "S¹`>¨LFª­È[Õ0°+§ ¯màiöfé3ÃòŒŸó,ô5–6Íuú_Ó°/´ðZ]¯¼Ź+±íû<µGô^YÀ ›àOqÇ—‡Eéú®TùNÞû®„âÚ*²¹6žÎјKƒUµ ÄYoz÷û™[a|_?]ôˆ—l¸²9w´üÆÄÏÝBKîÏ +òJ±Ô·’ñèü�þÒÐ&{¦¯†Á‰@¬´n"J‚k±ødõº/Éí»ý™]·˜�Û@ =bXñ<2tÀšªÿ·vq Ûÿ‚|ÈÚÕ|À9ü$ùû÷áÙÒA‚‹ïÑÝ¥ žOÏ¡ÆgÓð³› $l¿�æ;ሩc“ª�#er}d=öi×ÒØïšŒâ�Mè¿í:ã°â˜Ác³­Øù{$‹aÉ¢gäáÀGÔû„ƒÅq‰R?þÃP¶$\ü´èÀb?¸.L {T!ÿp=dv‡äóÒmg=ÀæY$Ô§þ$œt¡èûE¼¿쵆#˲p{ˆîòó]¯2ú:Èï8ôAã›yøvùº™Èæ—Æ@êí» ?2„§–ƒïgäh‡`2äåDÂþ�Mit¦‰,ÒþÈJgvP›7•DÌVLµ.ÑY=>�¯™IBý&‰b’¾ºö�}ØŽÏ%ÉYM#¦m¨�¾Þb ZÁOýÍ5C�³phñ_úììzïZ ­óp£˜+é}»‰*¾ ÀB ‘çc94s_V=øC.Ô2ž/°Yr|½P > ‡áDÜbòœ—Ú•�"›çYàýõxy7e3=¡ôà0&§ÉÓUk B%‡.HÑÀM]Ó¸NÆf gáBCƃ/¶þu¥k�Yð�ó‘ÎnÒC¾ 7,2lf³Ñl÷µÀ¯Ç ëƒ†'îÐfbJFö®ŠCŽEDD0ˆ%¡·R.â³uX+L7¹v“tûÞÐ9­‰Ú-½G>{›AYAŒžld†æÂƒ~ÂJÞ_@Ü4¢ž¶w0ç€?Zc“×ÓÍ,Úh©ŠÜ±çÌ„ïgæ�äÚ�z’Ì»vG~ÿGZƤ`«Ôб:N„ÏIÀ¼“R`õ­�¹qh˜®-Âði¦P´ð%xé'>®Zˆ=’™˜½Çâ½Áq]%µ·W¤®÷û¿ßhÁØ(q{žÌ¨MS‡�;0ÙG‹. æã&}:ÏŒ×Ãü­‚è>M’œút ¦öÖð�}–¹„i�ž†/nñ ™Ð#׫"ö–Ÿ;xPc~ ‚i«|¨Ìê³Äö%€_Ù ,:,™§ÖG¨‰¦Î"G{”ØU'œ‰îVgÞŸA6l-tÊý£?Ví‹æ‹0d^|ÔŒÞVNBÕÉ6FÔ+�ü&'¡ë¶^*ä¤ nA©�±�är_Ôú´ Íâ.¬¨ê¤ŸF°/$¶I¢Ø“px¡ÁvPøÅZcª¼04/âvqÌií`nU±°äü CÇ`-<´×-öHB\Ù6z #0h¸Ç°tÙ0KÖfIb²»ýú·‡Î�÷:4Ð�ƒD´b;>øÐO¹iư-µ_Ú�'ò§ciXYVÊ^AÅ“ø÷l¼ñÅÞù}ô?As“±†Î}4J0;ÊAN%�&?Í�{÷ö¡ñt€Ë6-wº˜ý¦N—/*ÎŽ�Ãa—AõÅw晇îpÉ¡�r;IpD;Ÿ¯ ¾×Õ1vç ²RUžsœOm/ÿF‡Ãæ¤uíZF·æ ý-K_µ pÞÜ'£Þ1¨³„‡4ÙÆÂ®ÞD~8íJ(„Æ•ö4\v^MžÌj|ṡݣâ@š/\Ç�¾ìªi›‰¹æ ¦±h iÿOŠHÖæÁ‘<.q6—†—…;‰ìîTü´^—­tÙ»ià­ypbõ=µQ�|×áÆß5{ÚºçÐà>ì�YOÆ>4äúÂUù 8tä&ß飖 a¿ƒ^EâÀ³s3y4@,·@Ĭ­¸9U„2Giê†&òHÀŽºnîaÿ)øã§ÊbüT‘s¿æ,;> ©‰€¤H‰ïBÆc uOJ#µOƒ÷ïçtÑ­òUßlÛ~Á�ƒDjS6Óxa+–æKƒz…4Ç CÇþCxÐG²Þ³.�|ØÎó‘ô Îdܳ³!åüýoSýž|ãèÌZ�g·É"k8SŽÝ¦�SPÜ—‚ÑM%ôª¿7hq&mù)‹ª'D0­Ó÷ŠGâåþ,ªþ…/¿`Þå&јõ³ñ¿Š~tÐ#/·–@ÞÙdæËç82)¦ˆw‡_3ÿÍÌ"ã¦,Ó­ Îð€zV9WKTÑhÛ%ìs\„¯¯ª@·ÍZ&ƒÏÍOÜ5|ß�Hlüà@Õ/Ê׃o½æà¾¹G0Ê@;¿Ñw©IÔ³¨”<ÑBžnvÅkÿM1éuÈ÷"Óþ¶a�uäÍ•†’eyH/8ãÈÓ™�Ï,³× ,ÿ²`(ÚðœHsâ½,i,äZ‰s:D n…R×ÂðÔ\NðÔ“=�å†w' wÙŠr9*&ðô$=eÐFÑó71U­ mŠï™µÊ¾lgÇ$}�¾™h+:³‘¨©ðRÏࢿÙ20‹OCŠ#Q,ܚ놙aѹðþ¡-ùn�c§z ý©αç1�ÃÖ·«ç8¼7Ü©0@ªZ£A:û4Jê+`æ‡E`)îˆBô9©BíÖ`vƒ] ®eEv—âý* dÃÃ7X%*|ï}™ ¾°L8Mø))m£)výì�’?ó%+¯Y'ÒÛ{-É¥¿Úp)ÄQFg*.DÉ‹Q¤_Á¢F@À–ä.w…½™_˜'þë,;¼j‰³5AbçR<~[{ç%×,Ø>�>hC<—ga݇[´üÐVÜ´'”ÿ3¯ÁC³hø“&­)ü°¯#™qÖ�FŸ4å‘urü¤\Alõ£„àN ßš}ûfsàù=r¿)‘¦ÊdÀÇj hSÂ.£+Œ–r?Ñ�ï`{ç^ƒŠFqšY:DÏ1z i(‚{x§s£ŸNÀ�xûÒGU·áÞ‚o4ù<-º4µÇÎädÅSjZ®€ªùÍÝdhzMÃ/¨ µéj¸øˆ0Öm¦¸�LtÎÀóã}$Å!ªì#‘{· DEwc‚ÊËUðZ3›^‰…äeÇpì‰'õç‰Æç•ÿa[± zút“3{ŠØm·à;:�óÆ“G¯òaóGuçþºiœÄ¨84m báCÜXKSì× Á›•œäCƒä�CTõöç&ðS(6^”åÞouÅï³’pIØ)š'í†9fÓð½ÏêJæ¿�éÆÄQ–.s1^-HízK>ß(ÆášïŒè"U®\Ô*Ü$�ß\«õ �ÍtP×^pÍ ‡ù#3ðîäRn�V6þ|Ìˑ謹3'Šhe¡„fŠÏ@{ÑWOfq/«Æ�þŸ™øîÚrQ¦ž ®Á?•¾ Ú.‹i7ðÄE<5”KnîQ‡AË”ˆØõ ¸¯Ä@P>? †’Ý_abß"ww+cùí,ùûû¸w‹p2¢Or¾ ÚÂ9Ã%tµÊ2.L†3ܶOøë´§wÓ[j²Eœsºè.ð¶‘â…ÜõªAöŽô?áƒug2`÷â�¨o-�G=Ây�ѽG„xÙ'Ò‰¤2 ´ªB'_An­Ê'L HÄ·z:ÄW†B«Ý(©<üã®� [Ÿ£¹KÔ® ‚ór#ĉ,!G•SÀIC�:|™°Ÿ4w¥c—d3yž¹™ªÌÛL®„<ƒÍs)•Vg¥š*ØtÁ,dÖùRÍ+jà:oΛ¥[ŠÉ¹†L¸ù¼:u¿ ãöĘŒ-È…ÛËqíYöަ"çžð+ð^ …¥&dÖÍ48~½:T³Hñåû$pŠïL}ËÈùý X¬ßߊÆSÖA̧¿äÖÿ{#f5—Î(Á¯ó‚qÃñ)º•,å4ÖÕ¿øAeìIÆaî[óô!·Þ´8ø2q€OI _£3ÐØ>íB£á�(7U@Žš‹­!Ûö:¢w€øAêµc½�7ìÏÿKÆ_¬¥#gÐMÇf²Ãé¬MWðŒjžûÙIGÀ¹Y „v‘ñíYTªH8Ç÷’ulnŸ�gëZ˜%^\š?�†EwCdÁj<ðA7‘lšüÁZ,äÖ­dßä«ÆÙ®åÜž_ó_÷vˆx/9)–8ú�EÙ5‰ðôò]èuŠ"%zØ3¹“äâ,=´8†_�n‰)·ÍÍwЇ‡è$«Êþ1ZN;þî|ýu[éÁPQRV­áM;ɾnø¨8šÎÎ(¤:ü4ûH ]›`Î ªEîðlªÓ¯IÞ}04<ÿàÙoû—>Ýæ‚<ÅÁRWeLŸCè”þÎ"¼ºG‘?p¼ZW~*bW†:Î}?�óõê-üyñ*ù½*Žª¸=ÅW‹S³î�xM&wñŠÐ¢B9t}E»¢}±(éô¸œ鹯‰Ü¶¯”oG"+ºá|¨YH5liMÅ4î±�WÑ&2—¹y@ÛtÛÙƒQ׉cîò)Æ–…òØGäàÛ*Hn…ЭGéþz.9`µ�ûѯ ‡ÜRÐÈú6]ø�ÛÿIAüúMÀk'�ïÔ’EZö˜À�¥ôAöoä¨%ÿ‡M4O3óT ØÀ…Z§l‰3ítag6Ûµ…µ¨Uo']£îŽþÍ„µ&.Ìì­×雈ÃÔóÛ­=âŽ%çu§z*’t¨ä£áGx{v!”ïÉ„\áL˜ûR„óøV^ú½Š�¹h‹!®Ò(ä:ˆzÿ p©ÍM|¤5�}—u�ôÍXûñ0ì ™ë gÊ'ïfˆ¡µà]·£oeâžÑzè¢:ôæ‡mw4Éøõ‘š < ±t~¾ø…Öî DÿÆfÚnZ ¥Â¹È—{�º:Ʋ^cþà¡ÊÅ~îrNlâ9,ÛpÄN‚yGl_‰VÔ|†¦ƒaS³{þÍ.Äíðg$»ŸÓÇ<ð1{O v9½Y‘�åùjĦSïZ%Z®æˆ­Üè¾A×ïÐÆKmݸ”ç»ðÁ5"ÏâúÕ”gÒ®wùcʃDlùâ)Ú í‘D;È-ËxrÆé/õó†;Ýœë]ð¬S ¶. ˜RŸfÀ=‘B<¡�h¿bÈÀø²ï(Ľ‘ç¾²³ƒ­‡Âè×ëjܾ‘ÙÐñq6êÛµalõMÜÂýJ]¶¤1#kCØ!ë röi4^\¿…Õë| K~“¡_ÍT¬â³X3ŸV7xƒî˜*tlÊ¥úÌH‡w¤Ý½þÉÌ}G4?µ `Â&T,¶C·ðôŠP;c†äLÃ4pÛžL9¹§Éî×!(-NAaµ†À;ÃÔ¡Sxv¢vúÌçf…6¢ðÜwxƒÃâ»C™ôÛ»ýØ}GŽ•eÀ%GqÒ¿VÊ7ô@ÍÛR²©‡t¾ #<Ók vé|’m:¡(‘.B»EfÎ,”ŠŠÄωŠ0© Ïí;à‡Ì·qx³!b³½™bT&×Í›[@èÂC”˜‘Júz @ðq ü»r+£xqGWFdTÑ5m&XÒ†m»¯÷É2ØŸ$À-û‘ÜUät– ^¸pÁó½ü'ÜÈpg~í 7yÂAÓ0ÆT)ÝW·£Š‹!ÆM±ÿw½…Ìð×VòŸæ5œ¾è:ŒÄ·�O]:\㗲̶˜@CÇ—ë°î¨ûã^*4zÆS—‚oXFÐÐÒœ#ýÿ�+÷²¡þœLzäŸ2XéJ§z ÎXcH<¶T¢OBÄUâ‰úB°®zÅH^¯D#[Æ]¤^IB%o7½jz jÆß�ÛMÄ%£–¶×ý¤±*Óa«å(©Åõœ°¬JÍø“ᨑ\ Ñ!‚A§©ÿà,nl©-á}p“ø àWÕ-à¼p7™¦*Dªë˜§§³Ñm1”w�-¾ùh·F�(¹’BGtþ‰Á‡w3ÈÍÀOdÛ?câlu&žéÀö±5�ûó¨é’"¨”VáÈ{ÿÀoý?©ÀË/Xt¶‰ð;k ÈÀ¶^súèn |ô£>*ñ²D)~°ˆ<™r2Ó Ñøa×Y\ð'œìdWahÕ î¢×zXnçJ=—¾ÂUaN¶` ¥¹²¡*ºSŽ;VêU#;2‡Kþ¢YÀqúC¬¹^¸ö°6pœ²@;èæÙMx¨D‰+ðáIM®9ÅÊrWªû#Åp7^6ŒW:’»NÙ°G&—É’Îc&ºqvÑ)8Tç�'â‡H­×ub�-m¨rÿ/Ñ»‚|ïcÉþwi0±K�{w¦. ûï#5/îá³EÝô½›´¾R]çÓ¬Ðùåä‹§Ì*W5{Z=�o0·ægä 2—ÃÁlKȸ@÷½¿H¢²nNu™!-•”G�ñ <~*Å/í£úMp–ì!åC"8çÎ Üì/Õ6�'�í^ÏžÍÎ!µÝM  YÐÒLÎÏ�¥=ëNc¶Ø3šõn?ôóÞg4ÕŸ“üÁb¨^}>Þ•áê-Ńëÿ`àZ<3’WðÃÙBšÛw†cöè'É:0ņ(þ÷x:gÉ�6öï‚8zÛ«ÚT1}h>d{­!ï߃°ù›É¾Júu™=f釭cöaS.ÙDC9|èçz­c2p—ßk¶eq2ÎWâî_ÂXΡçr_࢛yt¶q#]�e{ª¥è¾ ;Ò:ûú°ùч¥l¼Rûx }Yýøbþ6‚W72àí€såg�~ÈTW]r[µ“$¹;—äßÓÂripí¯.ÕtV%{ÝÿƒgºÃÐþéVD.¥¿‚èVûDbÔšF…Ÿ¤æ3N“|¥pìÄÔŽLïC�ÑpHýÞ ³²Baôälà:<‡÷œ`ºTð;«1�ŠÉÝBû~œVTªÚŽÐw³}CéÞ}jðý‰GV!«|Ã�Þ1B¸yì<5‰ÔEÛGuæ?:“QÀ†J+øÔ~ƒi+Ô=ËE(ÆÜÆKîó`÷Ì1ÆÃ?Ÿ<¸‘Çæ7¿'«W¹‘¦k2äkÆvøÿCë�†ïJ¹D=e äu§#·õ&]Bã±8:ÖEkSÙýÌKÙKTCȺÄp<;s”ø¸.@ ç�ìŠ+ÄÅd=ûÙ? æ>Áo�àü6˜ù^É/¥älT茯 {—¿'1çÒ'»ÞƒÒ… Úüé´…‘Qé8jo#A{Fô!çx]–ªŽ{ïÕ�OÙg2ѵìŠg\Á^úðx÷º“nÔÞÀ<ñ?ËSa³Qû´x:Úû� ͪð'ðòíÁŽÀ/Ø;x•6büÈF¦�Ê’"ËÈPGú¾5ü羓š{­8˜îSuƶ;T±�à‘ÿèPîjîø‚BR¤¿ übÉók+ B„2ä£QÏ~�¸B»òÙÄx~òÂÿ ]¹ZwiÕÓÑ3°ÕÁœ$™‹q_fŸa*L¿0ÆvØ¥‘…gö=¤Eñ†yqÚyŠÆ•_¥}†’è'ïD=÷ùЋn àˆÚ8én�CÑx^x�Ü;K}™0R)/ ç´2¹>|ð™o9 ¿ô† 9 °m‡èd샻7N’][è׈$póà§[òÇI’ä ü¬.¢yÅôxù$¯ÝƵqhL÷3$×|> µ–€eF&˜¡# ŽB»6 S.*�ß�ÏðÑù1­©NeJb•Ï HÊL%¥ÛkˆôÛ<œöªŽª†¥Á¼•1ø›Ç…ÏMÐ.í•$[0½â {öí€à-1YH 7›KA²õ 뜨à^Ž/&Þ»•rUxaZ©¡kj óOwœ�zœL_d4“º[É�küSx,­óÙ#út)!^ÿÄààên:ª´ u’±tçZx5c9Ž^ƒžåë@ ô­°ž2Úä-Øb÷Þp·i}Û �³;§xžÛ.îRÄÖË›™hå./XÄJg½§ƒ�Ýoiäàìe¸¹ ªwâL°T•䚺ς‘.Töþ9òF´ˆ~ t7GG*á«…ÿeð²F³ `­Ò|¼ÐG‹›ÒÊ'³ï„ÍyZ¸Ö¬‡Îž3ÈêŠ×ŠÁmÊ_Á~ƒ:,qÚMž®k'‚¶áÔþÁbÚ|6ÐÀ«iºhëƒæàPö—Ï[ç~\BºÆî«, ë¤1æÊ‘ 1=NWᚇ¹4òd¤M+¥óTÜ@~m0†-˜‡b3pú;q<‡O,'£Cµ”ï�®SÞ‡—G‘X;_²Ãø'å÷ó¬©YË’KeÎ5�Ö9xíñjˆëMÂ5:Oð¢Qf�ÓÞöüò""öx/5úi¨X\Ɔ ÑõÏœñ«S*)èPµçz(',ALÇÖQá°#$ÒI‚#ÖG޼’…Y%Ápíb=S­rŒJØ9@x˜ÊØÏ…¯ÔŽ^Ÿg' äØ¿é$s±H¾C-\îçÌ™ 9¾ŠKif¿§•c’œûß·bhø [|—U_ã ÜÙå°Mô ºû “‡“+áÙ¢TáôÔ½åàE—|éÏÇ>uLïU£6Ûíi*Ÿ2¹Ÿ¬Â!èYÂ’m‘dÕšyÄ~x!þÇÉXƒ7sÿ±?\Ú´VÉE鯳ÈäEY�ôÈa"%ðšçMz<¿‹ªÊK“ÏÕátÛ•bòã@è”-ļ_©XýÄ�6óÇc;,áßï;¤¥´‰Ø+¤r²‚è¹W]»ÁZ~tí‚aª~º…nm¿ŠÝ¦yÐóæ̾®M6¯}Jy͉ï�XÜ*1ŠQÅikº4÷¯¯nÓªÄß;e VÔÊ“ªÍ> ´á•ª_ÚêÓaþ­ì_>q¿3Hþx4²=¥bpgùi µÔéî"`#�Û“3àP„ YÐ@mã6Býƒk°XæýÍúá­ŠPU.AÅ·´®»—„ÎóÂWç>S¹Sš¤ôj:“’¿ßøùbè '\Õ[�“7­ª¸Š9Ûfãe³L<wâéبc�oO\ t•9žóCÛþ‚üKœ ÿ`'ôkô$¤ð†„Šÿĺn104Ó Å™ÞŸÈ‘gb�½í3�3¬�ëƒéáCÓpË¥7ôãíìq‘Âøô4éL]¾½�¾G2aeúuÚœN?F{Ör/Ó¦†­†o›ÝÐï¤$Iý³¦£òÜIóR„žp¾Føõƒ`['>8LPBK WèjáÇÅÞÐñ)ƒ=nÓG;Žc˜þ²çT5»Ô1œŠ¼ÅU÷Ȥ£·ªõ‰z±�u.¹…Ö‰¼PàE ½§:ýý~T±F¿CÒêB-¬ÌØß3 ¨ªŽ<8 îûQ ÿ#mß´ ›dó 5bYeT‡Ã°¼‡� ¿ºf÷ÅŠ´,¨LP"Y.©XËcŽ{Íj‰ÔT¦( ½Âá ÔÔN*ÇÐcK²ê‰.ÔLÿNçör0ü¶4u:ÝD7ÎÄô3Öpººù^‡B„ª<™©@Nvë uyCJO>bï³—QcªCg÷>À .SÞ¸Z”¹ÙLø£DÌ uÍA~([œLTÜ‹è=×lÈ]yx}Þ1æ�¤Ö›‚n¿®&­.´¯7›˜»‹¶j`ü†f¦z™T‡Çከ“X.œ&'É&¾8Ø|Ž”‚Ú2^ÒªŽa‰q˜ß{çW .Ý� ÔÈ0µEÞÄE<Ú>ŠAZœ9l6Iæ~¶€ �çè¸íyÐú ’2†.Õ‰D주çžCá•3 îH,õæÈá ¯ \\&Èì|Å /ï-€‡{Ño×çáþ*!:ñ\G…™ä¥ä­¯/áõ?CSÒ”Ñ�"ÿÑCæPz}ÃVVT¯"½Áëîb¶»FìçØ x�lO¼KO«À‹?i¿\9÷+é�=ó°T¦õºÞ2.›- ½\¹=iûÖJò~Ñûõk8ã÷¤83NÚƒíÁL”y§ÈMÅ뉘þè9ˆß®#ËÇŽ_“œos›Áê@3ú&gP]=Æ?Ùº¦ÿ {ð)­ì§GeRЀ¿‡jË„ÕÎb»ÄºªæV4…¢ÅäCºTM†«\®… }0pVyô\’cå¿÷¬†.¡¹Ð’%¯Qù²9´ÞþY�¾¨•¤×ú 9iÔå…˹²õ9óCâ°²: Tž½£ý™ÇÑæg>�»n�& RË”áJoqäYâS“Vf„vRlóhÆÝUÁégæsÏ¿I™L„-ÝkáßPõÌc²]Pâ÷1ããÁüÕ¯ïáà­ûLwåv�jÑB‘kt {šíq sœà±ü,²Jü#~KàHkw_ÛéŒ+¾«Ëð£ŒQ#¬ËUm.;Õï] ÏX¹# ¡9yjþºˆ6ÔÝw.š?úp`­ð4¨–†ã2,j´ü@™¨9 S {ËeàT×0yqŸZùÐòæ>’¦åܦø²F„.jCNiùY-ÌY^-�×–e3+B鱺�¸˜¯û‹ßƒSáGúrc/]e\Hæ&)O½?8Óš}ñíÄ$•ƒ×– ÜPr—yý×€£`ë–s¦Ó@[Ñ¥M� §Í—’�kÒeðÙW‹adû!zµù}ç/„]#¬Õôpò|†G/.æmOÆÄ n¸ðÆ[rEÕW†Þ†'K—‚eT<6Ä/C­ïgéæ‚ºšcú”˜yùѦu�ÚÉGwÄgkpçåTüm ?vçªÌ>EòVGcßžäuóc�}ràÝDŽ^X%yŸÞNWÔÞ@KÉ�¸qä%¸ERè²�êÆ@ƒïI� #¾Ç-°«ñ, øGRdœÈ馨«5‹Fõð §¾æŽÄ+˜ëïƒâ×·RU5}ºÈ%žÆòr?ÈϧÔ{T·ø3hXÀD™4ž:… .¾£²çç“!�bøäC{Ö"ÿ6LйB·ˆ°¶IhðHJçrŽ�%¥[-Ø=åÌ‘åIÄøwÜtz>•A h±~Œ8IÞè:Ã5JâØqK\k¾˜×Ó¸ T°5D‹o“áoO ka@MÉY1<ÖŽÊ® ¼2=ÇTyˆqÎØó‚úC%ÈõºŒF ®k‹J`·ëZtÅAw·{^ó Ä-£ñâ³¹O¬^�»ß«PAé¨ӧšÄyg/9”ÃægR‹�AkÁx½(…²oyØÚ[G/žo7l‰XÄ­/eïzn‚½)6Øøç%¹-/‰ºÕÖp®by�§ƒœ—…D£³&ìS©ÝRTô/ÎÿHJxÅ‘7{-^é\÷n€þèD°0ç§sÛ‚Qº/·IÀ•¾•0²&’¾ßt�:Ÿ§ýMXÀ»–È[ȘòêÆ ~¾™<ÑØDK6 ² :íäÏ3@¥s3á[ìuV¹4nW@xã.l«Ï©¥h¯JÂl/ãRíDªþ¢“ÕuƒÜµFÐkgæîúmóuVçC6Ýt#�zÉ…â] Ýí„«]g`aÊI°°­¦g]`ÕmYp+©Åõ\ªtx^¶nD�´Aò"•„qß`ñ<| V› ÓÚtòSi H§­Äve/¼/|{ “WŸG .ÿ±2ƒZ­7ô±ôeñ`6÷Ù/-ÎÒÝÚ˜è<sÞÖ@¡�Ç“X†ÊkÄ_#ø"ù8?óö·[ 8o¤’úÀXÈ[^óXÊÞ™T’í©­·½-BNÖøéË!¿ozõj£~N�çhÉ >Hééë<$tiv}3Æ÷K{¡1ö0ÎØš�‹V˜Cèß0Øås�L»1vÚÊלüIùŽÄç±-{to0xf[“ð,MØï{“=õ[ÀpËù·0î¯JDÝ>~“Äü±jC÷P^_]Ý#ü•r IN[0F/¹JN¾Æn^k–·^'Ö‰A“Ìènª¹ýäã{в«<ß²|Z¯þ™ý+°Ï÷m‡U- 4/@_¼C—¹ÌCiöÛÓ¬_ÐɳÉÄ‘»{pW¨=;¸ ý�’újPº©–>ûÂ5ø%¢ KL0çtè+Τ�£¤°& EŽ'@¨áØê!ÌuœßDO¿GŒÒò¦z?E‚ÇžœJ"i6c°Ô“’]îR(»ô&¸xIqJgû£ÎÃ|8ežBÃ'�™Á�Õä°þjþ[ÈÎô®‚Ñ€+XGÍ!2ø;a7Z¢ßüdl6SC÷u/á\„·ÔÏ›<õIšbÒoôÔ¡[¸zˆŸ»»8;¹âÓ‰«dR3hIrß¼4�ë&š°p›÷‘gÝäð‹Y·Æ ïlÞ€JÛ£aQÉV|;<†_êë)}Naäh Ü×aY»[êÌ©íp£…¥Å­Ðè™ø†à›‰Ï4Óîüuž,þÕH•,î£PX4µª¹Dܪ/1¿=�°ü}ÄK(Á¤U ì7СT?…¾{ìƒ(Ü#k†¹_¹Äľ Ëe÷Ã÷¢&VúÓÐ2J4ìàJZ;’bi¼®ï�ÇŽæA±ú6æ5C›o~µˆ%èùp1 LçÁŒc<°åI& Þ†U–ƒdŽˆ5Ž-æÜ8Râw•0Ã@yW>Àç/+pBe˜� Óéœ\q˜| 3 é§DðÃÕYp.f#}*]Á.qj„‡§ Iù¾"”,g3Ö‹£z¢$ˆD^…? ±Sp&gl™'mr˜šãÜË´Ð*d�·‚\”^ÍÊŽIš5 Ìñ0”ÅoÏ5àêV^w#¼Ðž +ÌÒÀoÚJJgý¢áó¯ƒ\xFjÕ1M>¶¿ö2¾ÜA=’k�çÍr&dì>\½�là» G½`ô}‰IÙ/pýÀU¢yf%x$Æù¨3ÅbqIh-ãEbj"``ƒ¸Ýb÷*õÒ9ó.#Ï ÉãÒ–ÝÓiQJXƒ? 9Ò8µ¸Tp ù%ÉF� 8Q:š4–à‚G?`±@6 ˜žAœæÀ+ùÝøHÎ�ôÚ6“Œ£±zæúT—Ï‚4úÀOezrD8ÆÃƒDv±+¹w9žÌ ‡T“*Š×AáF–œ(•!ü#úø¬ìZ¶Õ‘Å‘0hLJªÎ)Xöj3¶|» »Hc�ªEòÂS¡¥ èÁÐÇNˆ#û>ÑÏ÷ÈÞq‚Y2pbÇJò̃Ë<æG4f›‘¯%¸ýµ×_`œ=v‘Åâ¯_š¬Â¿[ƒÎò~òêh�ÞX‰6¯á«tˆµÉÅô¿»ÑRµ•ú:–bf‘Œ|XÊöizC®Õj\Ö@üŒÉó¼ྌ—Q�OZÚ´@˳íþT�†EZ»A+q?]uzœ 8£1œçÔmÃ6rÓþ$œŽ[Èn¹/Í m `*onm‘¼£2 *§ø¨L�긪âÕ]Ϩw'/‡×P‹äðöãXn«ØKŠŽ0mr¬YC;ŒLb–I£‘€²ÙfpwÁf²Õõ ÚK1Û)Ã÷‰’­«ðïVø·'–é¢Äm`Ø:tžKk$š%¹K½N`Öýåœ_Z>àué ”)ú`wã.Î\L'–k“Ì)twN(LToE‡Žµtë: :pe-‘]²˜hHÒ#ۮ¶w êŠ[`ý!gPúÎÓWl’½1¬KºÊÖÖL�ò)³yB–…’/z1x¸ÝÌu‚ÙÙðú\~™G©âÂ}dzÓj´#„ ÏKÕìîÚPxãÿ¶@•ÌûDï£2®I+bo©±ÎõdEòö¿žÒW*�ÃÛEp×WmN:ë‚<®ÑX÷ölúrÑ3ß„@ó·N2·c}‚QþQôØiÄ5\REÔ’¬l­Pøý4V}HÓÇfqFçËÒ�ý9¬eý9h*_„ø=‰ø¥L—"�)WO4º.BÐN_¦oà(y²õä>y‚QÿÀÙ+vþ„©ÓûIS>?øš|ÁW>£Ì˜8 +áŸô”Ízr^b9¨ŽÐËçͱD­ÔVø�ŸÓ÷�Á?�©À—/dÝ®šðŠ–•‚�d1 °�òò\iëKçrÎ�ѧ[ðîÞnˆpVEƒyó¹[ï¨Î"‚ýïaÕ5 æ–dcqR€µ±ÛíÕ¡·µÖÌÖ‡KïoÁ’SЯ_Ο‘ ¼:Ö¶§�üî¤41$�u\Gƒö”ÐkgMð¦J ®{D4´vpRzêÉ*•nâ›Ò�2VÊpëQ��Åô‘v1x†:£IÏ1^ÿÏ”„CK/�õ¦Ð±}œæÅ¹"rÐñ_ž“¬7»“…5;ϳúÙBTó�¬¸‹Ëù ß» dG†â 5T6…_?�ÁéoE2¼?=OHâK?8z¶wG s£û@qéMÜbR¢ºï^9„6Úž¸ñóv8š²~XÀŒ×GÈø¬ƒ 5qœLB¨â’pôH„µÓë0l� »jÝNØå¼ŽöüüÅ´¬º‚ï{™*[(]c� GvâšøMÐ1Ò Mu1ðïW69ë”_2lféR8Ü#Jÿ;¿f” ãæìN2ÿƒ­È*‡¦ ôqÅ8Sò[˜#i´‹¶ÞRçV­ø Uœ ò±Š¥:U�ÄC§ ‡fé0«O„ÂÙûçˆF’&w$ÄžJïêB�a^®O¦?Þ·]AîüLþV²ŒûÃä뇌ZyN¿ŽÁSûØê“FJD ¨z}è–*ƒéÆ#ôå~ÎÎrŒíy“Ÿd«‰ th[ÀÐó¼A÷[a÷|mx=ï5óéö[RÚƒ×Ï)àlQQz¬•¿3¦nžB/»ˆüŒÖ¡¾VI0sb%Y°Å‚T\é‚Þ$az'­ß*Œ×4èÕ0tùc *æ%låL)HJÝ UZ0õVåz= ¿ñSI¢Y ²F ýe±ßæ•Óü˜¾°‡Òµ�Ú}—ÚǸã¡'»qwdéò9Owë\ÃQ›_$lÅK:ô͉ïbÉà‚é K y•lapÒ‡nŽX n›3‰g[f¸«á»cÝAçÒi¼k¹þLì ŸïIrìöŽªÚ¤±þô-Õo¥³½|‰�`dh�þ¹�|ò¶Ç.=o%7Ô~’&Ïå¸~Ëœ;;¯ÛÙÃô›#äi’ªÓ@÷Ñn¢áùF¢ÜHAª0×wrœ¾–ä@»Ž4”–îÆ¤—³!*ö%U<| n±C¢Ê ¡gè¸Y>ük?ŽËìºÉ.É8Ú�€Âª›±ÃJÿÛ£�éwÑÍ5ÖH§ºÚÈ@bç-„GæRìC—lÊt9ÀëŽBÚzÄPX ~ͧ’ÂA8ðßaâ5ô€n?æO? !VýÁ4ýí?Š9Æ» ôß œËäl؈GüïáçÅŽèÖWmÿײ¶­!z£Å$Ed)ä<€² wÔ¾…_O†éäDÚ²â5!*Ø8¸÷ÎC+[I¸¹2Òöwq3îbã²üW'\Ñœ ŠÅ� Óm´æýè#àÛÑCr\,éÞƒ¾˜Ceûÿ*..ß/ŒÉee•Q2Ñ <÷ùDT„TÊ(*EE‹” ™EɈTÈ(dUH<çH4Q¨¯¶’¦J[Eñóû îñ:çz_ïøy¾=?cI2mZ”�o(ÒHãåtýM[®|gžã£óéÎ'W¸gP�Ó+ ¾Sçwö@õ2¢~ÓI·Ç”4D¾²Ék}á�ˆ+µçNÅ/3 LvEÇpülj;É÷Òr86k$ó­:Ç]GÐS£$°>Z ûì;¹¶öhò›½cëdÉö�>hzhAªM*tª�€´¤ˆÚõ÷~3ñÀáù±ªBë J´µ<� DVBS¨ý÷ˆdvo +•ÿ¨/xåØÊÆ%N";q{ Ø : AÖShú¦5h“SÖŸ€¾`(�YPã')MSt,)ûötLå0ñ¢±€ëzÈ Þ´þîÆ«äMK®ÅSÁ?p öWQVle-f#ŒV£ËÉct·>„½ÖUÂhé+øWë(†OôÆ–Æsdº8žNªO…çÞûIÿ‚l�'1컺Ð?àR–ø1³çÀ‹-]�ðˆú ¨gMîг ?.±Ñ¦ðÖÿ*¨ú³¢�‡¨}±$‰®@�¹�`œHyòÑ,D‡í¶¿?” ŠÀ»[úœÚ¥;¸ç× rì`4D •8h; áÐ |óËÎøÈÓ8µ *8Ͻý³ ×% ³ r8ò¯">±ZÄ�øÁ�Y¡ñl/[³U6¢°ãîÆ˜1h§oÓü¶ðÑfK©���8ç:šß:�îfÈ€ÐõÇø&–ðwõ%Vð3 ÛÏ:b«Ž<¹<üÎþ»r—Ý´ˆg~œÝYñ•-|x›nIå™[)Ú,‹b«WƒƒëhñÙ›åÔ&¡›’TÔp _·N‚ÿ.|a~î±%#•éäîŸøÁ°Œ‰-<ÉŠúÇÖor`fç�ȯv3'>¾–—Ÿ\J-"ÛèKq Ùv±~=ý(6d >^^¼a'Þî… ­kÁJØ�n¹¬¬…CI¬ìö(æž© ýª `nF=ZyTðŸ?�¦¤ÙÄdw/ IwwXâuÒà­×ia ÓÏÂwV -3HMjÑCËŽ‡ÐÝ#§–n~Ï]òói©Úx†ÕòÉ¿ñöŠnþBq+çc§ö\Ë*zÉ´ ëñüs:(|“÷QÛ�Ç�SñŽw *oræo´KùWúU(§{åná',KÅ[B–·6•â »v6¡‡s^ä‡oMÓxQ³5T|u#�TŠ…¹k@ùƒ ~o€ —GÐëCðëü]æÕ´­O¬´Z¹MÞ¾:I—ösÓ““±1RŒú"£á¤² žŒºJ«uXë h§oß?°{ŸˆóãÑúÜ–åPÖq0»ì!oR«Á_ñ c6É'ù¥®û™²ê# ~ò÷öã¦5©¬uªóÿÓAýS?1çk£qæ§$!ÚNëC +ë„eg?Ë3Ð:3 guú¡CâÜÚ�ä ¦ø¤’³OÇw³ 84C mE¡#)y—'™OW¢Á®CìZ»=ݼQ‡»œ%(Õþš¥ÿÇûœÚšœÔÒÄLÎ�§Åq»PåñXŸóÚj�ÍY¾ÑÔ˜ íÿ¾>¬]2¡“ýsÉÇåÏ$àÔµà°/‘–V,£ÛώѦãÏY“¹4ͬN¤1Ã}Ffýh‘LòJ³kW¨˜’ç?]ø0s]*mÂÎEB ìÈ,3ÎÁäºø�7‡µûõÉhÔCø}¡ŸÒo‡ÓÐ8UH·s€ÅÔuá†åí/çXT^3Kž!OwöpÙ£ò'ªô"ý,䯔¬szWÕl9û^ZûãÌH{OýZkiî#z¬ú'ÅkSa{• kTáQgç°a&l9xÛv8R�™—¸G@èÿ¬ùÙü„·]³aL@üÝÈöíÔfÏfr·¬jø¢{WirÒ) Qž„‡S2àû÷Q|×ÐIäG±¯Ãý�xÑ@|n�áÆ·®¥^ööÛ 7NaMÎöôOH‹î8¡lÆ  ‘"è¸0¯$¦P‘ž:mœ\Âv2�P±©$ZlÇ6xiPö ž|Õ%›6U qMÀœŽÿb¨Þ+σ»>9nN¢sêAP>ºîz]=>ýŒ2OËAvúVØéÅ/W»ÇÍP–…ûk¸·êà[æˆ µ©Ù zÌÈæÖ$šf™.NÿÀ:|´,Ñ£-~†—×Ή°|?•ÞIGãì£MP*•ÊI9â©˜Ž“7ÌóÂB²h¨²j½ÿ�×HУԙ µ>®‚ÞJرç+Žq§ð2Qð¨Ð¥] 1ôÝÇ ¶¯"̘~˜M½ZEcéëËFsûIÌõ44rƸ¿þ̲º#ö7`•ˆ?¬ì`á¶Ï±´¿…«'cé!:vZ_“þUÔ ®Ä7>ý‹ø1ÐüÄÈZgn4Ã'›÷šsH§E‹ðÛ<¦3ó§ò‚s¢¡(<ì“j›B±Ó¦…ˆ)Ð_ýÇtïu¨ª¢hmžóÁãÿ±Û…¥¤��ÀÍ™&Cž*†p&�ç4ßn f×AÖ^Ê […§È¬ü,¡ƒxY³¬6%0á”Ttÿö…�ž¯N¥Žyœ‚®t×`K"“¸GËþð“D6¸ ìk�¡èt'rW4\VÂ@ïVˆ2�epjFj0ˆ ƒÒàyáÖw=™ËM¾ÅÙ;ñ°Aú5MN‰ WÅcáÇŠ½°­‡áS½b¨_¾Ñ¬OU\ðê¶tÿ;JâŸ<¡ 2ž¼NYà^H ­Q˜¸A¢yx~pjKWR<÷§ gCuãYöÖPœJ¾²à¦kÐ{> «_Š1¯[ª0ø_ɔų̻uù·’¸ù¾ðçžÞ¿ôf:Þ–pÀwhÇXC÷ñµ´ùŒÈ(g iŽ,U—QLSíÓ¦¶å—AqÞLöïà}n2[§ÆSð’|–† „7°Aû ^2ÞJ£j&ª·ðâÿPøHœ|- Q‡ÐÞe±òm”"­?ÌŸe0´A›žnÒ¥“«F²›;þá³-ÂP¥˜Ké$þºò7D®y–Æî–Ü ¢±ùfpRÑÍ>>ä Ö�厫Ícebdy7’™•\ ¹ {`yørÈ,ü̼…³ë)ݼW·¸`dþwüVh‚ÎK¯ÁÙËylVm0úË¡¹œ åjŸ¦A™Z°çFæÅçØ®"gX*ŸÈrõ?!p±/Ú�làïË Õ¹ÎžÁ.Î6�ºA`pnÚr�]7ðäë!vt[1/Ñ´Hçjfo¾[SÕ·�Äe‘˜òhÚ¼ý6Kûî̵ÞYC’Aaœ}$·Ýi¦õZN²k%EÊ.#9ÃÓôØ#y¸Ó]‚}µ\ITªr…ÐrIZŸ-©5Hj£r‰ Õñš‰ŸGµÜ\öØ}*ß÷çîgW”€"@äÜTp7‹„_«,°-dTÝì×U°»F G®4…‹Ý‡Ès„�Ó¨ �)j ©y07þYãÊ:™OírP�›HŸWç²nñA+³z³øœ•ø¡:³îütBµÓó¨Òoù.Gßc3™ÿ�.Øk=f¯ý°ÑšWOFg³wø+@d±›�uyÌvH캜¿o>uôOÏønn¢\¿ù³#(oä‡ÿoË›HµFâÒIÞª?¹¬–hÔ:(�Ñܰ۸—½œË™ö42å *=BŽB Ó1qçšõ4­d‘’Ts™qc8¬È g[—`¡«Ï°#çæPE[Im: Dg°»—OÁí Î,ÿ÷/Ôë�¡=ãNÒ¡þ0JݯÊ&�î|Èqs„FÂö<…onžÄLý@Á }s» 1¢¹/ï(ÉOÒÒõ ¤U²Ö#ÄéʬRxøì¼åâŸáÈÑ}feûM†}rÖ³Ó˜07¿jxÐÇÇ2û·¸ãg-J¬Ž¡Å‹æòÙ²Ê *ßÄ^¯—`=#‡sFY›îüÂFýÙ´Q�QYõG6Áª‚å-ŒƒY.“`Å�b¶_R«îÒ|;VvDf§÷�#åçÄ<„·öñ°ë†¬@m©nÈ'm¿'X½äPm ê5ŒÂE$úÛƒºkPºQ=ªË Þ:§ sëcXôݸäþ ;óö ùÐ)ì’îf<]áïBCÖ—©EŸzXá*ÙZ³’‰$g0¥î’Å?ÆšÊ9«œ¤‡Qõà¸Æ€ç ±Ø{s™îÏzöM3€Ü¢µ˜oŸ ŽÑݦ+?PæZ5 |¾nd‹Ð+‡;lä%@ÇütcÊAxwßþ^u~{"D”¥³¶§S8!É¥VßLa®^ìE´4W0ãÖû¸2ó=ÝJ-'×_E¼�çXy&VWÉPÈ•x³�»>ßÿ˜_a£mÙ�×ðy’+eι}ÂÖlÍ&F¶¦C¸Ó(7`éÇËü^rð?Hñ5cÑåF=Lú†ÁΞ�¬Ú'›…-v{@TâØf©’Oâ|o€ÁpÿÍD/¯ÓtúìJR¬Ž†§g=èÀݽÔ&�A¯’VAgú.(Ð|Åne:ã…nIRù} Â~«‘ÀþÛ¾ïŠ_ü�]LbFC�üב’в™B^ÊÀ3©çøàà]ˆ˜÷˜u„%ƒ×þb¨0ù޲W&AØ.1¸>/lßEÄÀo�7o\?^ðÜ+vÝÙ�Kl]`±Á(\©³…9húÑÕð HRãר•�ŠÂ–ÐpV'ŒNŒ¡÷ ¨ñïj…R—œ�}‚õ!9¬+8 ã~L&-©m°UTŽbNDpÁ�Ù§L ÒÚ6Ž=¨1Á�&µãYÄ5ém5¬ø¡/ígòUába 8ø˜Ò� ‹éë°³´—ïgý ؉-n”ä“ÏÅ_+d«oÂ8YB‡9œÚÅ:\–Ý€òò[`ü•™ôüË|’$ Ð@eui”ñJvº4…Â/£‚Zq оK\E–Öå‡��O!ív³Øüµ z£@™Ã":� £} Öi,…å.ˆ¬/±*ßy‰ÏÙ}3Õvp-1Ÿ˜\ö?pû5žW¨†[+_VoÕ9M%…BuæNžX{û1³›õšú²™þ?9ZQóÏy÷±jm]nN©,Œüzœ.ìH¦0æ�o¬´èÕñ^Ì�ˆ%çEò Õ¶¬j†>é}±'ý#ܯ)LŸíÄpè–,˜•]¡c…Ç!òéq>`Ñ|rqÙNÛo'ýš,LóŠ!½ W(e£¸Ü·ZË�’­ ½Ž¢Ó#³¹±{§Ð‡,q°~t–:CBèíw¶¶]ž>Åh‘Ý&e«ç›f@Á¼`w¾öhôK¶âžÄXs©¿v�¨vî‡ÑÝOðãØZš^ …ûY~R ½W© ½L�Ú6Qõ禳b{æ•L§±v-Ü·nÜX¿�…Η¨O/ÂCMö¢ñ$ZíI¥wgO±§âõô­h2m®µ‡K=ýìílO2ÙQK ˜8ûÏî)þ5-&É1-´þç|ø«ü‹ùšÖóÑ[ŽZ˜FÃÅÐzÚ!$Mu‰­  ”qêÕà³í5(Ÿþ@riðï¸:¿En'[^gˆ[ÚN�üôqü-‹xœ¼Ý”\:p]·+ŠÛŽàLºÌùqDZdƒ-ïðA ²4�fg(néAåB+H?Ç6˜¡æ˜ˉŠe0¤w·öòÎï´â�¼U÷ðr=üÑ ónpüé—�t\ªˆUÿd¹±fPq™‚79ưH#ŸüúJpZhu^™£æ4ÃXÏhöÃH�qIöXcØÛßÖPà0;vì˜ âÞœ§ Û íàÛ i舙Äk ³`_ß7¶ "Ñÿ,lÐ;�)ë¶hÍ-Åêògðä :DZQó˜$<6Þ›œ7±['hç­3pí•2p–wðø°ã¼™-K b`Õ¥qtå©%=J“ç’[h¾ñïüÁú¿jÁíØxدz½¶Íb+sivxÃD¢½q྅vnDˆûáÄÄjm!Ú@„öÙ®¦d¿·,@4™Þ3!W¥1¸Ã…Ú¾²›s ¨yN2Í)e;ÞúþÝcèðŠ>^þ¢#H$šÂô½×™¿« M4W£É‹Ñ¹(*.1$Ûõ#Hóþ „ðO\tM¾¤]8Kn6K‘2ÄI�¹•ªKàE P]GÓþbF=ž™s–LV¢é¼ÝT|ÍÏÜø­‡ÿØüÅýÖ…dÃÒþRȾÌ(Eó­ê‚­3L™Å÷‰4°<‘üE¯³¥-;n=*ºüÅqó÷€¸û:ØùÐì2£Ò�;lmÒ;ÜØ§A'Ì\ÙƒÔÌ¬Âø@729‘ÆKøWðî:™¬ÏSÂÊ>p~ßÖJã“qñÙdЛF܉iàךÁ«ÌÖ­‹[ôÛÒ`Š” ë’ð§lø å�7?¼FÁµ NäÆmÖ¢Ec®˜“Àý8µª­d*bÒ08ø'À,ð”lÂßÇõÈOÁ º]©®(†Í¨ÆLO”¸JNk¢À>û6Û)Æðž»ëÍ» ç¾ö  Ë†Æ®*f*½u¼]mì4l¬Ýùç&¾³¸†žS8ÚSŸÇ>lkÈ„ôšQUk™õ0÷vÉÒÀYIîÞãË`Õ§ f*‡P`~‹½º û\søÊ¹qøŸA(Î+}ŠŠ®OðJëè~ Lzžqpu¤5Øš[q¢É'àg§l¾› ãï<öd4r› ‡kã 7T�œ·½d¿uW€MS«x9–Æõç mª×(ޝRkÀf˜{‰ŠGY»ýAVé5•?ö6‚Kª˜õ;º®H J¶p^öʉ�ÖãÓ´.ù¦y®Á‡ÿ†»U¾¾5{Å–T„S×@5Í“Üû˜Öp‚¿>)7êÁ4·zäΠ°ød°Ùº“m¯'œ¶s3Xµ]€Xÿ»\‚™6)F¬qòr�¥î‘L¨°,>‚LËøxIO’:ðçíѧ†wàÔÄ;œß�ßÞŒg¸ì)ùù¶[5ü@îÅä Ì-x (ÞåEµh#“}šŸYÂùP ðØÀßÚaÅV݃k&´²5nêP³p'½Ì[F5’5,f¿|9Ì#‹e<Ý‹š¸i�1¾”ƒUîPt™ö+ŒŸb g±¤÷�…ѶoÌã\ KõÌ ÓýôÔO{ÓúisÎL\àæ�íë+ÑèÂ!¬¾$~б°.°_§$Sà¢A¶»ËŒŸD¾¶tròN8¼­ÌöTÒ©Öö߇h2ILíÖëpyá.0àÙ®÷y,B]š~~O¦k’˜B¹° ùëfãÐÀ‚}‡�öw>&Ð?ô•ˆÂJma×7µ‚fß"úQ B?~ã›�•­NA¥øâgX–§pAÝ…ø>ß²¡ ¥GUR­ñ$úÚuZŸúCv.ñ îÙø.$š­VgÙ™yï ñïü΃Þj ’“7$5'8sÁ�ªζ*­;‰¯¿«Qѱt&9<ŸY^ÌçÌYàƒ�pݵ63wS�»ÐêØ9û|Æ´5�ÐÀµ¨*ŠÀ€ý½è–¤‹›vƃÙÅû8J)šÆU$Bú«{ÌÚ}-´^5‚%Oº¹?éÿaöD—ów¸ÀÎ圹 DÓ%éâ’wôõû÷T©j÷" mLªÍnë h¿u3SqWþ)vu}$ŸëñÌÓ>¦Ý¨Ÿ¬Ây‘Y©}f³þ2œ§ ²hV¤9’õ”Âaëë˜ú8�©! Û1`yú®4üÔyøÓ:—mê^Šüki(лɢ&˜ó•Æ]èÄ8æÓþ„KTÊ€›¿ÕÀ´û·Øó3=¿›eD»ƒž ’г´øU_噯  5ídٔǔ_6QšÐ:ˆUç #dŒÀ5GÆÑÝW{±qDÛŸfGc'O£GalÞ/|f>‹«°òÉ,X­šÍ+eÒ"ƒ£øïeO¤œyÇ`D÷bz2í!-R&�  ¢¬ëòÒ¹š×OIf˜í§ò�¨?ð?úPÕ¹‚}H0”éî¡ìÌ<æ¤2‚í¸ÒÄGȈ�}ù2Œ–Må?V‡ÓdûffS“‰w}0¦t´`¬�0MÈ‘€+—ªÙ�7°ÚÛ¨Néó ,H§»k�áQÏ®G\ãåÎbŠ‚ùâ)T(÷ˆvî�gYý›Ù7Û¸çñl:c»–Š?Ÿàj:TÙ6aø¦“ÅòƒÄH£b4u\ÚL-%AtÍ4ÔÛ:i(à;–˜lµštr ÌÙö±$ñX™5¥M€Ù(N=Ob¿ß3U-ð�>I|âk‡sñw¼ °rüØ´ƒ_1dŠ�§ùBWÀDðÖÑa=°óæ)È�¯"·&qæ÷;�KÒÀlÓU´9S ívõPíP*ɨ—82×xÀç-£Yåøëðå‚5ù^“§b…y\Ò¸=()ÖÂÚTéÿ<l[Kr³h‚`Û¤_+ï‘ÈÊ—Lêí)vè§í½kCIO>rãݚɳ;‹V+Þc™VÍ|Àyþƒ{»»zíMm°±ù8É›�¨ÕsŸH=6�ê‘N¤s`ÕþéÄ–u±P“»øæÞyð‰ƒûq‚Ñ]Ltm/w–÷M¦«ÕIëµØÞS§¹›ƒ@n„>üN)gúöþd[¶ ‡Õê´¦.¤O‰5°=ºLÎásæQãB’�E»}a¿¬i¦têñ‰Aò>Ï6]6¦ò`I4κ�B·Ä`—œ€úß›€A²×5}MX » L!vF(\xQLyÿŽR̹Cµ[ߌàZÿZ“`{Ý ¡Ò8Û–ƒ4Eºu; W›ÐÙŸïØøìdŒ5~´$�§Þ”ã&&(Ê’={ZgjÏÕ‘.Ói "›ŒVy¬vܶ÷9ÏJn?įVK©Ñ[�u8Ç3~Á ó˜$ž½Åù§àzZ ‚¸Èt¦óF†:¿–àßÌ-L3!¶zA¯¼ -ÖT¬ûlêC|¡)»êôŒÍþÚÂr8áì«)ðJ·ÆM=��üÖpо7­Üݮ¬ô«Ðõª±vÄÂZÌà›qä‹]¬GŽ#G0‹ß’¬ê£°àøÂר<­‡]1båõ �52³Uô!äm,'ÙóžùÞ;‚•[µ˜ün¹:áó‡Q'X‘¿U8¦®˜%�ë»Ù$úî:O!Ó° ðXî0}Öoå~©nÄi>§Á®9™¦æ¶ñ]R 5+.¹ÓåÝ÷Hëc#6ÏéÃõ~8»Ån—¦¿Þ`¤u7ï '¯'9¥“G`Å7š\±¾¯Úçõïsëµ6R€ã\ ܦAíGαÁ™)°sÒØù&.—ï!ÿ½]\Dš=ç$̹ýÈÂáÓèôJ†e”­Ñ:N^µ?ñhýsÌ“„Ž›5 |C•f›[‘Æä—$7Ί¢r,hûÚ@ú´¾ "ÃUAh¸Ø1AÐc4ŠÊTd(©g �µÕ†´+º¤ uÌVÿfSÖ?Çù¡eè_2,§Ú SÓ ~Ù±}Øï3žW´�Ê3ܨöÁEºfÞ†ûâÒßë“ÙÕþ)ÜŸ·+¨uð:»Wú­V`ã1 êJ¾¡fz07Ö¨ö¸HÐê·,Ù7RofBÄùÌͰÚNåô&ÕƒÖYm?U‰)¶Öð¬n7 )Eƒ÷u^ûE/Ê�œí³|i¥ËHÜ-¹ŠÌYbÜ6wC ÝÛ·ÎLOÁ�­ŽìÏÒÑtbË8šŒÓÔ¾báÓÉ5ßD)oB[ç ëeqÊ1?.è¶M÷~ˆê'æñùÛË1ì™ wT®�‚®Í Ï©°n@„|T*IíF5k–íÇ—Á7ˆµêÀ’˜~L‡¹’i`wîúŠÆSb´4Í açTfü_è;¹PÆös¤d=“3}ÓÈäãYo�+i,ú�bwÒ¸½Ýi÷²sÌ®[bÂ*Xºm¥k&C K`*Þ¸ZÇ€¬—å@Ýv=ÚÑ®D)鹜Ký%ägÍ$_ß³äãõ-¼ãi0ç½\”FÛ­O‘ãš,èYüÆuyFK˜Qk<hE]Ë\Hþùž¥å7³9a©°;e/|šX ës5ê&.æ˜RžÚØ2íÇI)ó ý¾»´G)c~[.s6³÷ðKä–Uˆ 7Ç¿òÓÿNëqþ7hq�šiœû§‹ÌvL0-�œÂj^©]ËþŽ~‚>GQaøRk©YS<<4¬\ÒaôôÕ0íq6ZŒyAM7£�R$ݰöÀŒóañ&íSÀÙJËh³åMnχDöX5’êDH°Ôš9#‰OÖ|¦‚¸öÏ÷YE޹õšR’h<ZM€…åºðcwlõˆqÃ,_¼Žk·ÊĹÿ”€�€~í.|³ü 'höõ@ˆx>ÄÖKéÑþt#Òœ~™ŒGåÒ“PW¨ˆ{ÄzüáÍ›SQÛ»§§K]·mˆ)ÕÀ±OùtÉ2Ž—ÝF¿�Ú¤6ê/\¸,mÎÒÃGGðæ¶Pf·¬mD¿Óó>¦ª. �¡Y4òs¹ŽY(t•ßQ®�+BgÁ–çW­Z~¤°×æQ4öþ(�†¼*“�Þ Ùn»á‚±7csƒH=òy{×ĪÑÊó*ÿ­´ó^ .¡ƒ ¢ H¡•S e+ÏÙ1ù¥&s«’íÕ“%ɀɴ·iõëa—¯ªX¾Ë”ãgÁI,³ UÊßà…t0ƪy:&ÐÖÀeµŠü|Aè½¶ÕåÞ3Çq2d•¬ÿ„BL¼ØbÛÇÜÂF0̱Ƌ^(âWJ1Û-Ñ©4žA¤*LeŠ®†TSþÖOs ¯a8ÏÏ‹~yC‰ÿEf ÒB—X¯€‡±‘«1­, KüF³¯—|‘oT‡Q’íL�w \å“ÙFÝ™ðRÊŒM߈6Õl¯÷YNäÅŠ[G�1Pãµ¢:�`B±$ø•ûÁ )ì.P!½oOù}»lX6Œ¦YW¿q_“õ˜ñ•c$QãÎm/f¯ÿãŽ]Ó…¦º¤_r ¢”§Ãƒ±Þ6ÿ)sš8æSêw[ü0º—=ëY—ì™COŸE1‡ÖŸ ’+šCê9»‘íʹÀ|üŸY¾zÿÛã㙳ƒ‚M³y¿m‡ÈÒîûï«55Ì�ƒû`VîJPº‘7hâíˆÙÆv¹ Ÿ3¹’=™î .?ù5¿Uè÷ã+ô¥AŒs�HßFŒ.«œ¤û™ìo²*]?ËÛÏáÅÏjU² å?’•«ãŒJuh_À%xäü»ö%RÓ‹ÍTßÙˆ³«¸òý+X`Þ9øòè;{7ð‘%å'³Ý)×Ù»9¾¸s�8ûçÓMïÞ0Ð�6h¸Ñ²dmú£®—qU®�î#Ç#·­Z²ZX¯É†åÔâZã$º �ʺ“ðÖÛXsS Zú xc,ÛU7tÆ,D‰huÒéRÅÃÏëÙ½SxÙé-.2¿�Á)­¨äó‘?™NÏÂ_À?õMdöž­ïT¡’�½P–ÚejIÍŸ§*ùÊFGüÕ¾Ž9ÿ>H/«Ù-¦F+ñæ¨>cúR¸;)ŽŽÿ ç?w/boÊDÑ :œuÆâæGê2ÅA­Õ4Rî†uœ`+-xíg ï@½ü âž>4FŸ�uU#“܃ÌûÆWjºö_Î]L“Ë¥a�Ï1úUņBς΂?Л| ›áõØf¦”øVl•‡ '8Ò•÷ï>çŸi ½JØÞèb¼ŸØƒ¡Ç’a÷¢x8{׉ÅJjr‹ã‘­õˆ†ie<ùŠÇ$¡sð¤W�MQ\Á6W‰‚‘Äa ÌBã[±Ð<œ‰�óðiE(½žʇÜXeI<9ëM¡DÏßÌhÒQ–,žmÕiCŠRòTs>Óö2ýø<¼¢Ã*ÉTX|–IíAvÔæ-æùPi›6†¸à­H56ÒÖ×ï+�åöºðz¦L�Ç.²=À”‡»•e騺7e{)÷É[=z ;Ö§¿ïÇç�`³ ›ãîòÓ³*¹íÖÿ]ÉARpеófö+ø95¡tÿÑdŠí}C'˜¬§Ž«þ̤óÅbô?PK-!Ï×ë&ÿÿÿÿÿÿÿÿ arr_5.npy€0+œ—÷CÏßûÆ‹4••6ZF¡¤ñû�Ã÷ß�Íkñîh -�OãGÓ·™÷Éë°¶ä:�ÖÒ¶>f-~—Â8þ%.’ò§ï“Û¸è09�@�Õ3pþ¯ÑÐ{e÷uT9Ü5fÆãõÉËp™x:ÒhocÖj`% êlÛt:+·‚ºRçÐq‰tjwpA«•÷àçˆ4<œ�É¥«fð9z÷ðj†m–Ý‹Mi¹£}Ï*7à{|ËØºÇ,kÙ}˜·Ð“c‡}"‹Y:ço§Ã#Í¡µÇj½³èÛ‚ÿØ�2H;fDëãšÉ…©ÁæŸki¯N&Ö‰ã?ÂR5˜b”LgF�ʇp&úì ܽÖÀuvÁð×�$áwŸý çaFõ=ºèz�×éáóÁT ÛSKzj0þý®¨~#Èk9,y¾ þ.{ëܹ’°¬Ež¤·U ê ÞÚÑ�÷pÚDüŽ5tèŠ"‹¦8 TÈF»ð54ñQ:íY2ŒGR²´£QÈ]R"+¹Èφ¸v–6ÍŠNfÆΡX¦Lö;ÆöþÆÌe¿°�ß(ŸË4¦ß3Ëø Æ¾»®e›Æ³Œ›ãKàó‰áÝ('zòå"Ó�yŒ¢¯õ(dîS6¿]žLã Ùa&ƒs¯Òí^9RW=‹þÁ»á½ã<£F‘ÊIXŸ¾äŠÓÂ�õ”6ÛòŸÕПÚQ�¤2„stmÀ×ìW0rnvÅ^† cÍAÔÀÐåº ”¤ÍÌ^G@aè¥YLC[ŽÚ#õKGÉmÙ°*°€Cî¾tØÍrìàU, iý§I¼N‘,×»l,TcR½Ò´ïðHx©(�¹‹ØÄ †Ð56ÕìC�KpñàD™œ�3$MõƒµÅ~T¢cˆ‡?D3ã/9_ã;¯¢¥©´Ý: Ç^ÊÃ*Å5t�ßÅî«)@ì‡dÞÿ^àž|޲–¬ùÀçìÏ¡`6ÚëTæ¦pO¢_Á®//H?½ŒÞuhÑÔ‡�H²ù(½s”17ê>Ç.Ö6ÐŽ„`îVXïœw•u¿^Âä,ÔÌêÆ ¿ úžŽwo#ï÷¶UHá'ñ“øÎd'ŒqÞ�‡W;ÁÄ-Þ´ÚÚ�ÔJIÞ_Œtr\À>! $Ucբ缹w.;“g�|ëRZq½€ÆjM…Š/;¹‰]+*`>±UuÖ®×ßg%ò؉é«XEQ*^ïÍæ–7ÆRV~Y÷û“ßC?vúQ:z,òeÓ.¶ãä§ÉäôÎ�ßy`&Ù›EºR0fT)»|J„­»ü×—ýÓÛÚy`óóO§ÜèÁÙM ,r½2Iùâòy¥ewî즬îg\®Êmܼí2NþÎUŠ?¦Zgà~g}ûW�Ì méx!œÏª­/0}uoºXá�Ý^û`TFký¸?U–°×yfðë‚×o’IÉEHè¤DMÔKÚ_½ %wÖ±µÅßÉëQ(ý ÍÛI¼èµPˆæŽ d^Î�)*öf޵´TQ…4½÷ÐW!%PuÏÄŠ¬ÛìàÒv´¼þ�û~M›ÍJ¢Œ)ýؽmÄØ¤ð!'=Ù¾ªP8TÚËfˆè3sâ¢öV’Lñu²L3�ØZ¶:, º�pÔ#¸~i›&òo¥Õq½�SpIè¦÷áÔ *îÿÀ;ÙGÑ�­ã¨,ô)ŒV€¯ƒ"tî‰1³”ÙBU_r1çÔ[üá?šÂeß%`¾àz»o Ó?tiÃÓ#¤¼ÓÂÓ´ÀÀ;–ÝÛæË–i)ÔÄÞøÍÎÔ´rüÊ a’&ó5®î�'¥<8%¿jâvó¨øK�þê qøh®ô©+ÿ.;‘:_bœÙaÈâå¡Obîý8Ž™4–p¥+αUm“P¿ä ?lþÙl5:q eãÃNzj@#¼X¾ª¨%Œe²½E´×p˜Ý}�]j’†ôˆ÷|”úÌ،Πê43p %JŸ!õ£dä'(ý=+~ŸÀúÙ¹œ®›!…��3›¿ó·†~3Y%M|ºõSšSÆ.,óË-õÌTë(ýóó+›ÊEÏÃz+ _1¸3/iMýP<�–Y"°û–+§�¥ú: 0oE•ò­d×2Z-oÐã›�SOoö[Л¿Ø­-ì®D/·² ¯�}gÂãÁ?Ð ì|’a×µi •h +g˜s);m°×> Oh ×|šq—9ßgŽ}WÙ·{IT2Y‹\ÒWAåžL3í¹˜׺�ÁïÙev5¯‹yzϤk:¡ìÌù¯à"N|§öÒéìÆÅפ”1\4M.O‡z£A&f>;2“ê>êQjd ̼ÎcòÍ�¨ú4‹î™«@ù¶ƒ8{ÓX*Ìuf¡OÓùAѬÍÿ&½�”…Æ«¨üÌ^xøU–F}°€³Rõ¨f‘EK_½gÙûb`±d¸KÚ³7)\d¥: ÉF`�ånTI�$ËÏó©hx1ß75 ­ŽÛá®Ô—(6~Ù™SgŽ9{œ¥FÍÏã!ñr0[4î"$úÉ@f„¬Q̇¾‰ÙH›wP¤Z3¨V^D£‰t~s(vn^ÅÂ;CñþcðlŠÆŸ*HºßÙù%çùÍ×âh‘\5æÄ‚óB º 3–Í9PͲ¹”m7ž8ù€ÍHÊÆ7 6ïK ‹rÈÂYùh´%³ÏÃöät,ͺ ý7Ôéhö26µV¦w`Š�#×Õh¿ÿ1îÂcA͹ÀÙÓàK¹¥M~ÿáªùaxHþké’ŧ‹9XU¬O/�Üíû¸åÆIÐ{?‚<ÂÞ ­R�º»1`¢%޾áÒæƒZÓ©ç¨;š_¨Á�]ÆPõçÛ'àºõð৬ù±£ÿÆáƒ}qt®ŒGí)Ö 7+„¸ÂTÐR¿ÌBèÉ©ÈRÀ“<:ûj¸G“ÓÙ­ÆõÝ)䂾AŠ\œêj/XlUˆ^"ñ(ÿó%tŽ%ß½×yõÝ,tç£ìñØ�e´¾!æt.e‹…áÕòT:¶U£ÆÑi-$ ÓxÜ�v´²Íæ.¬¬ê·ú¿å4a¾.9¬Ó¡ÒH Ö\Î¥.Ý”9ÃuÍ0`ó+q¯+;âGW.N'ùö4Œñ�ŸgÌaÉþ£t*ø*Å?Á37ìqóm]èžiHË|ð’ü\H¥îqEÔï�„R ¨o°�ew$±/ ¶àðp$h�yÁ´¥–€ÝŸMLqÊ6yŒ5%€äÏ×tÞ{1ô·/…-JÛ™cí{x•õ–OuøÆD“D`“­ÍŸC³2ÊMVw@îz ²>¶Ž:¯§˜¹šh“æ=WžÛ3•õü‹K×ëÀ º ³Â�D«QêÓR³dï¡ø®FX6Z†Ì—ћ欲ߧk$ø_!S(?ØŠ>Ç<ä½N{‚ÛëQ0eE4ç�¦ŠØtMžKnÃxÏÄz¶M"þ¾GJŸpš„«1ÐgñÛ-a²k!“ï-ä†ÝÇÐÁ™môâö^Xvôüió†·�Ñéã~CØcVó}ˆu4pðè¡*�òQ"íyê |4o´½ÆÌÚ0ú(_ÇÅÙFS–ü.<|µŒ„Ç©BG»3˜-ÇÿÚÄHvÃ.ô_õ�O½QË>­ûäÄ öó_nhΪ²K6̓ÔÚE´z··[š™«òrzñe/õ9Ïe/àl÷'líãËp·3„>ä…Ãú3w¨ô�,0v'½Â2C1möª$ˆÆª™µ}9 RS-Àì@7;xI>Â;ÒÛ/€#r©ÞyèÞKÃ⥧Ù׎#tI4’ŸEÁv‹ÑLXᆔÿeŸä…ÈÇz+ÕÎ_ ¥sY†F*[?;Š O¨áŸq:”ã…]?ã>¦á`šm1ãÿ0ñÃÒäÝЋ º}˜¬LøèN.×rö¢ÙiÐ =σ\U¬s½·€¬cǰÎÈÝ´j”³J‰…â²{xáä4¸|<�ònîçÇûMÇ÷†änØÌ¾Øfš�(8<‚é]O¤»Ý£h¨îóð„¼ªbØ!`Ç¿ÿøž fGø‚�ãNê–&©ƒVt?Á¯9Ÿ¤ãG‚`|Ìq.Æ72ÛA™OñÉüÉäfò 5Þ¼21–Í"A)àÀ¦ÿ0Ñ4¯lm§üïñà}o*Ûrq¾9²ž;Ø`™O(½Ö§3O¦1ËÎ~îŽ_;oSz_vÒõ±î,r?Cͦü�õ/™—“E_ŸE�Òà¯o$\»+Láõw@ç¦'MU�šÚð|?”ÊՌZ�'(òo9“t¸r$ÙŠA76çX L‹€1È–§e® �Ú:®í^JÏmGà,§4`#²áHéi¶½*Xð\À*B*1yKöMâ7{‘cyªÙê·ëhÙÝùHmcaó‚>ôv]}*©¸åýìx7df+‡+?Äâ¡Û»èõ3Wø4ð‹ÉŠm'¹Ùö0ôª‰…L<‚EWã8—ù'YÀ1F›n£c@ ¬[š‚mQ÷Äjöñw<¾I/é…{ͪ6Ø€Pž5´ Réç’,�áG53à -,ëê–x3„,­æÓÓ%­Ü?¨}ó,=ùüšmïjD¾È–DVuó¾w+±‚ÙrËîßG‘•)^öö¥1¥î,ætã� ÄRší5¯áM<ÖÀØZÁ?ÆÔ%åZu>Ât6É÷aã‚ï‚3“ýÙlÕ:YËvÉõpg¯ü¥ñGv“šÆZ¨Î¥Œ}a ýù«@êÀFlù¤JKOÜå¥Òq¹qòÄ^�!åEû¡æÕYþYÒVºQoÚ¤dNæ±8ó1 ŒüÍeªQŠêL¨-ÆU6ËùK¬»þñ§î‰66i¢tËëR˜¸¹¾NFû]9\šç]zf=ìU’Íä�—cn¯)]¿UÅBF-e©'CYJRëR,‡qËÓΩÑÌK~GO…]ß§‘éèo*‡í»ÓqÜ|7Ì8+F R^0G[“:ª×£òêå¤$Ö†½Í4?’Çʹy48s/….Šg›í+¸ç;èÚ�0ö‹ÍÚPB׈ô³¤aÁˆ�ôÕZ#f¤C÷³[X™w$ŽÆç[C!ÖPõF7òï‹K bÒn˜M)4NqM¯s C÷“ñØ1´åF0^Åÿ7g� où *4?6—<×9¢�Òp¼|ÞH¨Àî'–Ìm÷�`j¸=Z²¯•3ÿ#îüÓI*LV²Œ‚§äàà.°¸hZ»VÒúªÉ°úB1οR&§@YéXsµ¼A&q)ªÔPÐg#œ� Æ7Ì 5w Œ;EÇŸew“ylûó�ù³V‚sv<¬käÌ?š¡ï''Ú»Yʼ¯ v]ìcÖÇ!äÓ´:3²fìÄ?�¼ï ÊMébuÎÿ¸ç‚»;1„L¼)¿¯”¿íª¾†wñ”­½8‘ƒ9ylÆ”.œéûšëúj í,×Zk�”Q—zS fÂu¼¬} µÿDbrÿM¶NÔ�<|ìº@åa31ï%·l;- ±¤Ùyϱ 'ÝWðÖ¦MømåCö]h^¶ ão» /$‚ZjchKr«ô®D'«+ìDÉ8’ŒØ'}¾ qËA|§>‰šGÀ°~!út áï¬ÕqdÍÓŒL,¶ëß'YgÐt*™ÒIJýÃ,áŒI gn¾_pßÌ�,›k4[§ªK«Õ.Ò¶PeºÛÙÁn.YH¶ÊñܱQvìíË�´Íê “5 ¡”ç0?D36céYsHZo ºõ“N�s@3Ù¾ùŽe‘¬×½ ŽÉÂ%*ô3Ó"Ú±ÞŽcFÁ�ÿCÜ{ù*9Ó�ö³X”‚"µç ¶�æu‚ÔÈ:]‘vÆ9ìóQèܼš²+M`�Þjy þï?¡Gmœ¼°äô\áÛÊž¼xÏçÖ–‘HˆÛç—È?SˆƒÕ™§pço‰ªi)Çøû©©ôéJ M•ËãÎ…3gÏw8B|ˆ¬üƒAigð�ÖŒR] J,Èéúva~ê8jâ£uö¤݇—Û,aÇ7;)¡Êt Él_ù#vâÈÚñÜ�õ~q!ûè-�ö:Ÿb¤Zù7ûïá@ Ñ méïøqÔ»1™ÿ5#�öGZ"I%l‰¹iž3Æ:æbüÏ8X¤‹_ŽÀ£- ¡öñ&:n©BËêdèyLLÍÌ€qïªIıi�$%m‡‰O–CñIˆ׃þàãàèw‚¶Ê:ÀÉíÁ4¤ôo÷’¾ä“Ÿ�;ÌÐñøG¬hÄ*jÑ’�ù#ŸsE³5¹[°ZUÂ|©›œå—ÇØ(Z±5ÎŒcÇ–¯#ý}§à©u 3š±샲a8O–„ÛÎÓîÏÉÝGnꕳëù©tõ§ tkqðwT=Þþ¬�=¬<|�©ú-¢Áíq¸_i:LXžÎzk ™Ú�2Þho ó”»Joì§ý¾çh‹¥-lÕU¦ß+R,ΤÊcЏx ¦¸^ãÿÞ/a'jŽÓó@Iº•‰v+™ÙšÿÐiè6«Š-ŠÓ‡ƒ1ÇX`³8ÚÖY�Úx‰šÚÓÇp P4ƒG˜«éÁ¤Ø-ðæC›Ñ)Ji_Ó¡Ê™p`Xˆ©%Þç¾Ç‡Ó¼ú“du®D‚¦ BþùÓæ¬|Ö6q!W&FÑ+&pGÅ ™‚ƒ6 ´¹ñÂëtQÚH"Ç¿eÓTÌ"ƒ]‹nÑ`û›¯±…’)¤ê+ÖÌÇ9*S)n¤&0–ùÏ_CÑ·ZìuµhíG¦P&IÆ×pm•™x¨ÔŽXé+ú¨ûF0©AÊüíi"s7¾f‚4'\ÆYÅlX5 _G–à¸Þùt#m ŒØiK«ÏhÓhë½´w9Ã+1þ÷Qe¢ªupoÑH–R8ŠýXÀ>\a|Ë—rœz…ýX§B¿O0ƒÛ‘ôó³$­÷È�~�’œÉJã§C‘ïI¿Î']ä 0ý:~~dÍ,î´a°ËsVþ7¬Ú¬Ù�û8¦ŸB¯ÿåÝŸÈ€ÍÉ~¾©*‹U àíš2�-•5+î0aŸ[ãÉTw:„ Åà†äs;�UFMba‡ÂÀúÛDÚ?í3ªŒ&ã<ö¼€ž÷ ŽWd34Œc Þ>°TÃ•Ž­/Áœšqxvy.v†Ÿ€ÅíEhڛ˦IŰº´_ÌÁ)z×£ûþ§\¸p6Ÿ’#EnRåL(±BÖ�õݾǾibÒÞ�ü擸<>› ‘¾÷ƹ‚˽)p»Ò�ëðOá«óØ»SàI°+%ìm IÕ08¸\¼æ�$~éd|•Éÿ£%¢`\÷™7ŒMeÎ;»Ù«áPœî=§¦ÛÓi�•èyú÷í­…qÇaYE0<Ô{…�“ÁY�Ñ��6´{Ô~Ì—«…â½{ØZ_ “F±¡Õúr%ûSÕàÃfk&¹Y�6§�ǹ¢ÖàwêL¨EN´ Ûu~™Y¥¢_&v4ß=žuÊ•’¬ñH¼±`ǽº†�×›© 7£ÃèÌßÈŸv¾ž„¯ô2ñÜy³çÙªéci®†'¬I•¤ŒL9Ø=p“}]Ñ�+{JÚ«èÛ¨ØSÎvVŸe'.¨Òœ3`Eƒýn¨Å~1xÂ6Žÿ!aɯ6š e ðÁ†ùtiìhÒ_·\‹CÀN-ß)î`uuØÆ³#ÌL’Ó½"Z.ÿÛtE@OR¹æÉ©BrL‰f—gŒ€­µ`«ˆEÓcÈ7ÛÒêjqÅÚAÒ?o ›$Ù8¯ÕLÏã%,lÏÄõ.áÙ¸4v˜Äâòj&ÜûžnÍyL&ç-™éÌ7è>mn˜’Å„â8Ũ;àñ¯‡5õErâƒ&p-¦•­�|ÓkØ~'¢¾›Sá²%à1{™[‡ƒÜ’HzêÖLñÇÛP¶ªU [(n²4Üu§UAö0—‰Â~$",¢ce¨65¦/¡Ýëº-�–<.ÍÀ=?NÒ�ÇÉÜ»^/vsc+·ãL0ÛzÖÂ�‡YóöS¬n½X8_¯îTŠ•u>°ªgÌÚùŠ“œµˆi¯‘1¿>*ŸÛ1k7µ±Ï8EqÍ?.8¥ä@m¢°ñûG,ØëŠr{²LÛ¯|Ä»SG#·î:qr0íÛGVÝ“ÍiØÎ5ý½’Zn��¢§=œíÆS»d÷|k=9žøFo¿0ü|ýwÁ,x©Ç4öÝf›­ƒ°År€ýý»Ìe¾r¯Ïðx×IžúÍÃqÓ�Vu(Ò–¡SØþ¯‹÷U½ÍÊnf)ëÏl·g‘_ ¢Ë„±ì×{>`w Ê|W¤éC{ â\ÓÞø§¨9ÂåÂûlÔ!3Nìˆ[Ï…m‹‚aö6þãšJ«�æWíK`oL¦BÄqvïv.ר�€s˧Cïñw05,œüGÔ@Í·ÐOª e;ÄN¼÷§Aägªº!FÓvðmúü–¯ù¼}H&|ûG¯]ÞãÈÐ 5O:7RŘ›ü–ÈLØúÚ7·œAQ§pk4$×<–Ó‘»C¤™¾‘&´âœÉµtîÊ-(Ë¡�ën°Çpï×\¨x'KŽJ“ày§•/^ÎîÜ:B÷�ä@FL8V)X‚ÁÃ,Ø"íF÷5­Ù³ 0þÔ]¾ïÆ-n•O*“ÈŠ¦�xZmÇÒéV'§Ne3{x™Åw)}¥›°‹î˜R°ÑJ´NÉÝí|ußx2¡Ì;ÇžcK fr�÷˜\žº¹Ç¹$_=·�§-¯§1ñ§ž°¼Î™�BN΃2�¤Cžê¦j[«…¨úýoýKÖä¸ÐÁ"MögûwTü1†þ³îÆñ/7î¿È,–bÞׯ›K(œ!Çà ðòN4;{5›“cÊ×�üd“/ôdŽ>û*}†uxÜ£¯q“aÓ$Oô\ã ó¿, Ÿ�R ¶·€«³ˆ¤ñ³fÀœÉº4EqýJÏeE"Á±F�E±w¬¥¦g•‚ƒm0<Ù·$Ï[Q«‘?¬lÓŒãÎ?Æö l‡èøéÇ<äXKªº?±Í9Î.µí§Èn°âÙ@/VSòƒ€îXØ­œMŠÂ¥˜ã(CòI?ðÖðcH±ä`Ò�l°«˜Ãæ±§ldëy¬©SG×®åLÝ#‹VaOŸî„ ×/QÍà:–DSCü=üô;_'Œ$±vW6h�ÿ8?ùÈ›êBëÑÔòi3tè(�¼Œ0‰—t±?×|™¦Í1âÍ\aÄ?ï<åó¥?láþä²÷/bH"Ñ€‚&½á¶é4²‡�¢ð3w m{#8ï­G´ÞCtÄ)f=©̇¢°cø" ø®‚óy'@d0Hf�Ãõw,­=x;i�”ðí›Å¡±¼žó}LVU¡`Ò äU%‹ZɬHŸ…Ц™Ý½ôšy9j4CÌbÊIÚ ù‰®³l�TZaZ€…-3áïœLˆ«Ù‹mæÀÉKh}º5=[O¶Ã;¨yG Í�3û‡Y{ÑÌo "˯*,¯èM7߆iiÿáÚ˜IÐ_ÒF³E.A߬˜ª³Ú"5"2T)¾� Ï£žÛk6¦ã$wî½2ùÍ4DÕ§°‡m6\¤S_RÙ Ê#s˜ÀL™ÒÒ§Ð西ñòØû”[û•¿¾{;¾]�œd”;¹0†�?åÂ-ÞŸ‹-7;Øðˆ.ÁôñáìrT… Lf5Œ©]JER0bòwþÄÒMtÊõ†Ä¼äǺ¹²I·‚Aƒ4=Ùèçe~<ŠJª?ÏcoeœÛlHNã­qɉ“Àìc¿…×ÀÜy³èc¥7S3 ‡{Ãk„uð‰ÿ4 Š6`y´ êÞè±7Ó%è˳Q ö^+âÉùô øPX bž�‘ï^æñu@°[ÌŽ)̆¯_’ËÛ0&¤ ãGœYá£èxÈ› „£OÑ_•PúF #¸t•«|GÕ&l«�¨J©@‰M¼Õ¦§[¸¬IËi�{�Y¢ÿ®Gø*ç¦L^�éWæ=Hzöž][sŒÞ©÷‘ó²°õD)“3¢ã#pºD}Ó]•rÃnV©ÒõD–"•�VÃqê§Ì4ª–÷9RΆ¹w,ðž8Ì9ö•äg®¥ùÎ1T¸ã ôã‘g³á”èG”üµ †ŸœbEf+˜âaЬ«�’ýÕøs;�ÉOâi+'#êðšuœÌN…¦<PªCÖ4 ü·îÁ[ó¨ŽhV²x|ýf�üÒAfÒ*H}…Æç@ç×òy¨‹Þ_A.D®½Þ&�èµ0¨ËÆ™+³í§€Å¯)„Øî&=Ò ì%&À†©Ö|Ú¦Jöýíq8çt’Ùß—Ã÷cȤy�Žî‘dÖŸçÒ ²2<\oMV6»AÖɶŒ§¥?‹ù7NLÉÁ¼o›°µ@Ãü·ÿ¿|=}íšA,&’ïžçÒ‡�!4²Iö¥+âÓÐL¸§œHíåØß3qFg?k{îK!÷@Ï0ˆ7ŽØÉýh°¥4_{ÀÏÐìÞƒ ì|ž5™x&’´J9œŽi`nfmxIA.¯8Iã:öÁă“aKî´yù§iÝ$ùß�ñ íà76Î¥c©»à¿»õÔU™Hw§¥ Z_ˆS¦|&¼Ûò ÷~ëG—ºQÀ½²ÇŽDí}‹×z…Ê¢˜Õ^éÓáXàeÞ2?ƒŸô¹%ǪI²²¤|¾¹Ñ–Ü{ ™Óí`è ƒ;r(:V@9ç„iж5ã´ßs·–@Ï'x:² ‡ZËéƒó’íÑ$¯6ó—wÁ£„^Ìs;Í~üþ‰6e.pw'òGcÌa]‚'=šHÃ;Æ�Zh3‹ù¢L±UØ3–yïwÓÏù´ḛ̂Xÿ^ìYB9?”赺0®»a�nê“…º'³¡.çétíy›¿/‰²c>š¶—¶âÎyµ˜üèfw�bIuÅ܇Û1i´ ‹µÓ¢S#ö£Ùï:ÖSñ ›Ê?æ#"�Õ¡¸´e!ˆoêÁõçT)¬É›r pŸóS>½!ƒÞi–±RI„©Ÿ1Ýhœ�š‹Š‡^šyvË¢XD d÷‡ ^™þâáôB,jßMQ+[q(‡ðÝ¡aî@óönÀF§0�žO¬tçHfbçÎXç’Ý9ýµ_ uuü¯2w°ªØMËß„²ÛYöPÖÌÛr혮ŠOçw°S’ÓÉw†7¾k:ÏIŠ)ÕL/Ûݵ¿Ùö­—@áîHÐhc.'Lžˆ½ÏžH:¢»H62”þã�ôÕaBâÿ x]cã37òƒ“òèKæÌ»pö'zÒÊ»â|¿{Mnr)×Béô1 Úþàqi$<Ë3Þ0;‘Qü³¯Þ´÷›0Eþ5¦µ–M y/žÚî¥Ñ¹_]�õj2´ŸécâWÓé¦Q9³sôwã�¤…xMô¬mLæö˜kÒ‚³‡ØÂ™Âæ&÷ @ûø3\µ§‘y ƒê‡ydô!€Æñóáðª7œž› [9Š+›LŠFâl5¶æóŒlUjÍÏmÑ#qÑ!|$2 ÷G€ÑûÅtqQ ËþÛÜ,zx 'J`–þr:ù¨/vW°¡ëa®Áufcצ.´ÁŸ³Ï­)üÓxÞk§¼ú-J�òÌõIuÿÁ—lÀþE ¯ãvŸÎ×0ý#š´ÌT¥ösö¦òFù¥�Ò]¾·3ØCEö½i!΋Q…šñ1 ’ ²+½¸[Ñ1ÜH ß¶ƒÝ¸Àt³„0ÊsÔ¯� ó?ʼBñ$pÉÍb•i›øì¹¸S>ZÇ[°’® þ†L8Ÿ¹¬‹õ]—2‘牛r !yÄrt8É‘tuó¿¿$…ËÞFÀM9xT|™mÞNHzpÉÉû‡BUdD5,R¢¾;Áá§)µ!ÉY°ÔS 5‹ÁÐæ]$â}Þó;aùÄpt÷ª3³lT…€ë;·8VíÝ‚O‚²ÐóÒröâéLr59AZÿ²À+lxœÓk™PÈoñEË*' OgsþÓdþÿ­ öIð_Ê$2™5 7�|D„£y09ÉöÎ�£ 1ðZà+wTñ¦Pöuí~þÅ÷zؘcGBriè­×iO»¯úÑ%9}~Ä�sä3±“MØH{;óQÆß�¿ºÞ€”ÍàÒž QOëöm$ýÓYT;–þ[2–ÍÍ8M%ÃV°ëÎrOôÀ¿êÿ1ýGZ¾ŸÿëY-b”ö5œuuÍ…gš�ù¤Iv0Ún2�s÷¡�nÉìÚ©Uàë, î`Ä¿ÿÏcáíáÝ0ŠEeš‡ÙNáJU¥¼ÃÔk. 6W¹ÍxDV‰½rŸ‡Š–6èSPÇŠ” @©`)t��!§Õæ``OÌnþ+×¾Ôwßã´kã誾L°æACn�‹-®Öh Ûî°_ØŒ¦Í}¬›»EUÛ—ÂniX�k—)Ÿ ;¦56±O“ÎsË6¹³7;l8ç)~X°.Ž)ï[Ê~Øzs×;ÔIûÂX:¸+‚ó'“åàcÑ¥ïȯuÌ·‘ mYö¥f�ëe”XÁ³Ã…MLTVŒ5ÝMÏ„ÊÂÓÀZ–úŸ2=o òR@ÃÌ�™Ô5Á¥›•ffåLg�7­ •5¿Y‚½U¿‰¾/¸ÙB?ªoá˜{>z,ÙÊš“:M}î�ÐóY˜`ﮇÑÈõãQ§Ø”œ±+õX)±€E÷ 3¡M÷192–\×�öDSøÕØÏÄz��¥ºÍÊ=‚™ËÙ†¸+Ìó["üº¢h^y"~Ù&ƒÍ†•t>¬ 6{Ü%S)Šñ>Bb­ÏQpÆŽ÷³€esétB\÷—$Ÿ+ìÊ+!Â? á”N >+ÑÄü < ^²…ªS¦w.™8ôQª®Z€Oê˜&û�“¶b²I³¯±A�Àxœ²¥Ž3 ?Ç\´²ð^¤$œþÊ–LFƒ½9d©u=5IïÜaÚ™çÎü§F9)‘Hj Ö9/¢éyò\ZçVH ¤ ¾%­ìÐý­h8F¦¦Ü=€Ä˜;%C‡y4”:¹ïÑg…ákŸãµ/ µ6‘pz| ã¯]“)ðô*ÁiE=pؼˆ:º�IÞÈ•éSiuÛzFéã(©'žýÑÛIkç¡[@09mËÆ1Ñgiî›v¸=ºHñªjýœÕßkøÇc9ë§§�£éÛ“dõk<ð¢º6¬ ºÍä.ÁêI¥Lo “M¤.RÒ!ã*qØl§ ¦ �qX™½¼ÖCþ[^àô}25Õcl053™�\x/$Þ¦&ÝÓ|ý¾F³�S`8ó °£´ùªq^ôÇ�£ÒV/�ý›Z,9F�^É‘Äq[¼9ç8µ/‰ÝN¬çDüÊ[/ß^Å õ¾0"s%:¸?e}G+Ø(‡ëì~Ï(rœ¦]3b¥=ÜĶ>‚ºìL¶æ +]®ÃBÅã,¨QœWK^Û{˜‰îd¼ñËFª­Ý1à?}\R–@wã4:ñóÜBpQÜMíeÚpàâ»U/*í±µìr,4lýÅ5¾Ð„Vg+ >kÅËøêâóXž�ü xÌ”—´Ãy=q8i’�~®p¼ÿ.Ôï˜hn|�ßçW’NJ8ä`/-ƒq]mËMÁD�\´¼ f¥—XÊžŸbbHXì# çÁzٓث||ŠŽR@ÉxîÑxoèq à¿è‡b®€Ö‰¶|ðo¬/< B!ªÑ2v…Iíp1ÇÎ&$±ÿÆŒƒÈÚ‡ð¹�l‹SÚ1—o>š.Ÿ ükñ‰KüÂwôêï36ûã8Üö²Yðmñö-gRþv–ý�«<¯²‡b…ÌâžÔFy£=Ù–Ì$0_/Ž6kG’µê<’jœ‡úÿ5p)gBé£a9~wWªy³Èä_æª0c‹­$kÀã­3iôÔ¤°„ê+ZHgd™/ Ùé/Ñ36‰íù �Áߟ“¡É,ú|a�eð¶¤~ª€ šà ɑÐZß +Öìaß~þå °R¯ àž�ÇĆÞÁÅ·½�ê§ÆFˇP›É3³y.J 53Dÿ1$–ÓöYÓH,«’(IÇù¦Ô4©—í5¡™á§éÜ­öéà õ§šÀ‡ì΄V–ð–‹«q�ú“ã(D=ŒgŒ§{Â-¸{îªx�L‹~‡ã›©[y“bå^‰¥°2ÜQÊÒÚ6ƒSC=„¾r#å÷Òd¡K7vØ3Ë»r5ûÏÛÁ¶ mȼ~w”|Ç÷EAxÛJªyõˆ»´z14.PÁ û çH5¬í0Àþcè“’ù¯\2�Lu£.Ýè$ãøƒd°hž™hS'×7›tªÆ±Ž³sØ{+îbI#Š\ó‡�#úñãêãcã·445 —»ÐùØÓ¬(p˜E¯‚yJõ,4(†:WjaÛšNôÒ’w M‡cIóv4%æÄÁ²µƒ,÷Ž&q:@d\¬-Ž¥I¶!8N+™M¹?Àf¯¾‡á{œè]å2æ¶bLÓÎ`Q*ÚV3Ëž7ì ¸?ĸ£þ}3Ûûiʈ2ëÜ %åñü’¬pnêúE6|’ßïQω¿À�‚PêÝðT“òHØî4([mâ�[e�f�Z�}ä8xW…"NÐZ½ƒf"ì?L:ë‹ë”ÇЂ•2|Ðö{PpǾmÞ�½%WÉÁ3Ž~œnD%›A3�ß §òYÈ\+ð3ûÅòL€_>W0Awån‚9‡KÙŠ@/6ªQ çzù0ûÈSxñ¹0m.Ma¾—4!hÊ4x3?�<΄>t²�§»°+Ì òOåÂ;ÿû8(i^óúv,�kÞ÷Ä„úæÑ}™©Œ™¿€Ï;×âŽRpñ¶,̘O¢‡Diê’ $ï?šÊ&ŠÐÛElJsÜ~¾ERg±ópÚ>þ‹ãÙÖiV¶Z ¤ìN1½]~Ð/ÙMâeCl˂⽔á\°5-+, “²jöôØø3ÉnDŠQWXäÙþ³Qs}ÿ‚ÿØ>ó¯O‡ŸF¯Ø`z�kögv{²· õWø¸Ã|ö²K�>`–o)ú°Ê!}>³ÿZšØæqv°_'‡ÅFå^^[ ñû7Óš&Gø8Ì]¾ÀØõ‘Þ üΧ…‘†÷HZëÉ.`Ë(ä¶*gë:õi¸G̼aÅ,Û¨!X–·‚ŠâöiU~^ ~ZÂéx;¶fâv0©¦§ã”è“› )Ï‹¥½”*{g�]MòGU¡"zÌ‘#gñ‡("ήc¾^sùG–Þ‚³й÷cðá£ð$(–é¨ÚR‚„�¾—5žJì€Xl8ÚǪÍW÷öïb “tèÁ³.ÞýfÒr¨CÎ�*”ÒØÄVXtð,Í?&…€àl9ë)tÀ³æð×"†r…Ÿ kïr<1€ÇüÓémç,”«q´º�gR¹Ë ›)Í*‹x�œ­”0ã3øŸûN®ì`rD8]|ô¯W¥ýÇXgàm®)¿›MÚnÍ)ý±¢mƒ�¬þT<\;ó™…蜇•SÊøë‚çìäï™Ô·ì7Œ[¿ †ïM4ÿÛα8ƒ(,éŠËßr¼Ëá1ôTã"»¤®¿:Ymm+;ñm;[”¼�´&o†ªŒx\ú„·˜ý‹É¤jƒL�-sº¾‘µÇ>`gWÅÀ´uuønŠ5ËÈ|ñÒ‚ži‡áÇi+0Ú|Ó²®g©&ÁàP¼•ú<äxé’èÇÅ` û‘—tø€fO6‚ÚKEôÓùm'¸E¡ù´áÁ�àûoŠ0>›Gó‹¥ÌxÍ!~Œq .whç¥]�f+ß@!]O²Ž«ÃÖv_ªÖ>N=£Sál«4”Œ—¥ëf�XYí]³þ𡼇לÜEõü;UØ}^¼æñ3Kú~ŸÜî�§“m¸‘a;aýî�h“…vfu¨©,í!0ìš·j/ÃÍYÄGS‹†âI¿ù�%-PîP(è¾³ jç ²ðÉäÏ?c§BfYø.î›áî0i¸ê5Ž’Ì›É ;6€ý^&gn3×Ê�Ù‘èíiÔ–&Nëm"øšõg¹sI98­àÓŸD8)>B\X¯ËâüâIkã6h¨½Ã9õ8ÀŠc¦*·^›ö¹ÄüLgÑ„ÎôzÞ'î½·-I®î ôâ§ã›�MïL?l0‡o�_AãÖUpy gúÇ�ÜÃ¥ìC¯* LXÄBÛG•æOç|ü×éäÉËÉ î8taà†‰p½)À²Mp.a52_\L‚½ý}L*KÂüƳiøháVrîpÀ§—¼Y�Ì?«µgo¿¹2¿Ëú0$½„¿3§š2æÔ€ÕvI0þ|’²¶ÖàúïµLç¯;+™YÌÄÄejħã¾»%¸áÇ(š%NŸÛ¯$ÑôùNØg%dÞ²ø{ѧ¿nÊÃ)³1`ðN¬æêƒzØ9a€¯5´‡ÅãÚx˜‡ôÎÁ’Ô½9Õs:ƒ-Lp¤ŠI ä ³æ1+èRãëyЖ¼†vÙÞäîÞKНS@+ký¨:Ç5¾ód=•Cl­CÎü†8©x-ò}Ê[¹DLñª~ì²–MѾnjóÙ×°R~Þ”K¤œëb• û=áÞüfTºÖ†F¥Åô0tÄÙíƒSÚ÷¯YÖø£øhôX:>ôH`dÕ@û…—ÂÕ<v8÷ é*Wã´¸^fºs.Vü�–õaø(. ÄyòZÎ WEàéø ì‹ÆlT*| –ƒ)¦?:R^â>Õƒà÷[šÞfÍ�\<>Ê.Œ@•ÕÁ´ÛçÎ’â�Êo1I›“ôIü Ó’:ÎÎ.ŸÎ…MŒg‡lŽ2©Ǩ»Æ—„f%ƒ¦ê« J5éÒpfœŸwä#/ƒø¶Q0pð*ßæ®ÆÎ¼ø—QÙF„ááˆ"ÌÛêñ0õùFür»£S~`ôß ý<Œ4M 1ÛùkêÿÆ® "™ªÔØw,‹¦• Ý¾Mp§k ä}«�nû»ìÕÖ‰T&A¦úx7hEg[�K…[äÂ.¥Ó/#`b^Ÿ¼ïô|чó-¿pÁ“ß‚Ëfgˆ[ý•ÜFÂáµÿq‹,›®l|û<µJÙ€�Ô·a>ASPûÍ–ý .ª€9G2ÉîÝìrn9í»Ê –ƒÇÊC0òœôö·ƒEW$›xfï{E)©dJ¥EÃ&¡l‘Qf4hP>ïsŒ-íQÑ7 %¥ýúý÷�sÏ=¯çó�ûJ7T0 8ÛWLæ#5ÁâV3†>ò`й@·ÕÎ2émÈ5Å¿£ÿò󢦠h0‡þ­ ñõ?i{ÿw½9ø•ØÂè %pGó:o×|œšc(jo.vucŽc,He ªù\dBØO¦KØâÿ†Ñ}/R¹` Ï®±ï]L6oµj¿}�¶‰ö�vwH8gðŽòËBïT»~èi/·@µ�YÌVº@èÜÁo1�u¿æãïg�ÿ2< ïíù�=­ÃU¹»Rö‰{¬gq N¢ß¸`¤n|[H‰êÈ Ýžàäí¶ô.dž Íe'j’ DÌ�Î#ÖÙ?AðμÚ/:‘j^(+•[†?Ãà³Âo–Þ4>v¿gºósiçcRþéÉvóe¾í/ù¥¡q˜5bˆê.†¡Ò�¡ v�ÅÌÀ+ú¹@;Kë¶s‚óqp³ºuUt³»}•Úvß Ñ›fÝãî6K|ï :É,<‘]¿ÍþpùM>øÞu#T«õsÙ—�À<ì+»j7šZ%gCĆ8:`&F‡’,IÓÞŒM™<£ÜW“üìD2˜³?Dÿ²åÕlëpIÜ:þ*éÂæ<¡m|&¸¦WH"�J :¿Õ0ŸoŒV<þƒN£-ª½3E.�d',!çíƒl·^·”A~óulw\‚Ÿ¢+™_a¡`eÄFz¨¹ƒï•À2—_¨ešÍÛ•§LïVü»0–¶ï*ÃÕŽÇq~é:Ry,~ŸÆÑõ-oŠhù y‡AäÑm–uû*“¿uŠö‡œ§Ö› )2»fÞï#Ì\ç^Êz�ûäϰ¥Wì ¹pû´UƒÆgQm©=ͺŽ›lÞ²úÜ`:`0 ö¸žgú -›XÆ7/ Y=îë­E¹È>,×ñ�áÝiZúsºvó*7_e7FŠƒµÈK6a¿2;m¯I“th㸉 ×�LciÂâ—Q/MŸïS‡þyWqÿ€.°_K ¥Á5D‘V#[pVsŸ(B¼y�ÎLæüm&Óþy tYÛ ÅœÖó2úSáá@6�`GfÏÿ͇óy�Óñoìˆk-ivmÅiGkèj²+3‰Í¢/éÚM&áçÅ]ЦPŽë…7hÝ=fΖ’ÄÐ5&í¤FîFUÂ�+S`ÊÞ³,A|9凹‘ÒŽ•¬ì‚+]|T›æ‘úÈáÙuK)Êó2­¦…$×*ΞøI1×¹Ô¹)‚‚”`vŠ'¶¶æ¡þ¢rÎÅ¢�õ�½ËO¼áŬñÀ¢ r:ü�;ìõéÄþ6zúø³BzRî`�j%ýöa¹—¥è›©:†.Ü÷ó?×,çœ{fRÓÇ{ìåKmÚ:r%œh¹ËJFìÀYÚçØ8‘N¶û—×oè�Ä=Fô0q/;º/M¢ã°\e¤´f‘cçv|òç û®±’u«Øð­ÕÌ/2޲k¦³Šiö¦BZÞ" ¥ =¼m[ †#¯÷£¨ æ�³g:yO�É7¾±e_?°ê`È“ìÃ"ñ.«QNÅà¨×�»–€\«Ï쯋D,½†zæé¶N vÝ–‡úõž²íeOaåHq�)íÄõÓ ñ—ÍÜ|dgÕšBgÇóÿfÒFí‹TvæÏ÷íýƒ;ÆÐ�Ää (¯s<º*CuUÇhÊël^SÁöˆ¦ó±-£Á+c6�_« U 9Ôy1µG¦�cÁÇAª§YΚïª:];�£Îæé´æ½jmë2ؽ¼ûG?Áð€çà–%ÆmÑ�M‰ÓÀß;™ÿþv\k5‚Å~°‰*yòC‚|÷?¥ß™(¼ÎrçGûCPÿ} …ªVãîf[œ?q¦Ðóƒ&6u[ñ"6¦0væ .{(ôI ›âàbØTõ{2H[¹Ñ’(c“ Ä�ûå!þå}A؇ºšiÃ*aù# Zë9‚ì£=éÒŒb?ô‰9/‰$}Ç÷,lR–.PýuEÔ,Q�óÒ×jïã‡v ¶{<3¡é 3=ðÛü�bÙ·…,On:úÙšRÕ71þ�è8™Çh£¤;ýW·?ô:�Ò1KÁËiF`mjJ0C’^ýóÝs®]ðTUFNùŠEaÚÚ8}p~ÉBãO³„ÆaaÈ/:ÉÔ×v‘jŸ þºš´Û¢YõÙ«¨†ý©Œ@Ô Y”ÓæU^Ì †½FÍù ¸U‹©�ƒÈB£ž)Þs ´™q¬çóÎuj?+q² =ŒÒ?ûBéÙ6naÃSȳ²!­Ï…øGÕ�u vb‡Ê'úïA7Û\zž¤Œ–€Ja(ÿ©z4uc!C6�Ŧ6 ×v¿0n‰2>P*‚3ê1phè„+�g¶[bŠx‘É+á›B,É*‰Á÷µIX'ršÍ6˜Ynð¸Ê’N•L¥;è c²“Á<ÃVéÝeïWwÑ~åFÚ´[‘|ãäá¡Ù/»xÍ0 „F™4×g, 7>¿táã£tW/§ˆè|r¸PÈÄH ?�ZM©]âdµb&›¾à9Ÿ¬Ê ]7Ѝ•‡ŸmÕTBt3Ò�)ŒHf.v?¸¶>:*§Åj&­†¿šQp.îgpûÞÚ8sŽ÷â†-îd"é"“Ø1_Vl£'¼v¢°J FfžÅÒØoàý¾‰ÞIöBÒ@k¾ZŸ,…ÐãýW~‡�ѺT°2‹…ìH`_Œ3™Ï—MÀŽ¢ý»ˆ76IƒágiÌ#?ʺjLÃGѾ’jØ Ëøãî‡l—X!/'6–ìKdŠºQ¸Æî9 :7�ôý/ò†£äÁþ[!Ex>eû}ïà¢bÆr\Áä+ÊüPs ;¨X�V_Ðæ6'�õßNM뢙ú6 k‡špžy¤QÙÃB\û]™L=ö° †Þ ™õ©çãɦ*r²³�•7î@s‚?~óËǤ½eeâI¼î×BºUÎ㊨åR —;a6µ9Å@z¥ûuSòWÒ6?Ê—?ƒ½§4áÊ»|(M½Ævo—b CÓØõ·½|K~×+/ 7o¡aå°/W ´açøèìl÷;”ë­zÆ«ÈPo Ë'ïƒ÷ÛÑ&ñóK0 ÔŽ&vô•¥�±¡)Uãƒ_ÓŠi2˜ku>kiÓ�µ4u™2ItK Vp(±â ;sVÌ¿Åþ¾wÁ[y³PJ¨‰òù�mïø5?u¨wÏm¦qB‚J–hb¢k3úÜ"2t¢ÖŒ|‘–…}ƒ÷± >‹\¿šáTevµä UNÏü±oÇé¦2`ªÍUíÉÄYfËáBº)ÔÝG··ЯGr— Ç$âð±ÊcvK ´–‡ÑƒÎ¦>½—>;B•Ù£ ïô-Òz­Ã©׳�"°pœO2Üe–æì�¯Ú|èƒylHA�CAô~ÒÊßPKæ'GSs¨ Ýìž#—(QþË�¹ –¯þͺUÏÀÆè[ë[Ï¢Aƒ0vOk3Ûö<�ê+–‘¾ü~xó—‡p˜vL Ö¢ˆXW/ôe¶ÅÀÆš¦ãÉ8uˆ^È"›mÇÈZ>—àÛqÌü/‡*‡á‰ûNò%±Úb‘(²ÆzvóÛ,ئ;§ Õá€õî“ìZ™Ò >fž05ÔŽ|5ý=8¨ï(ˆöãÆ•�ðÞûrt4 dÃ$Ëéì¬ p=kË~_ï©Sîìä7uînU§@öÙE"?5ŠÝÙÈ*e ŸüÄïf¾ÜÍ£,È&‰»øK 6™J5r,4oW€¸ê2°*Áyï[G;²S") ëË^�“¯ýÞ°ôØpìÐÇ£† RaÅr¸ÑrƒlæÄÖŒ0<1ˆÕ¥êpãÿÄ–gî:hÇ ŠêléϵŸ¼jkM<ýÕ¾Z ”Ѧøc&qÓ–!9Õ¬‚,÷OX‘³6ë°á¿?B!=`ÕïâÙb¿.2¯¶!ÏØäCqÜVÙ,Ò˜PÈ®JZ‘•l>}øœHr?ÆQÀ•é´Ö. ÇÏE7L6»JÃ%aŠôtš‘e€/œ¬gÚ×ÍÁ%Kü‡CY}ü|–•}KdŸf¥‘óåÈðô œéLæëcéþœ¾šOêï1ø�³sͦéfõ`æ{�BÇÚ–ƒ^臲Híî9{±E|l­‹`&Œf¦äÒO6+Îc¶£ÿm² ¼ ùËnU3�}ƒ³¾Ý@¿!X•Êù„üGÏ»¾³fÙ"r©SÓ89j?Æj·®af,›µUÌÃ=˜ÙÏP§ž±o(Ükˆ"•©~ê1l/œF÷U1“ªfØ;’.Œ½ÀzF^@í$5Öx>R8¹îе)ÕžÜèMZRw¡m˜´õî¾w´—Nã;­“üæ]sðˆî¶´u6U ³¶nk>Å®¸l¡«r£˜ª™;Ä\hã·4Û®Žç»¯is,½ žË,É€u³ŒÙqŠW¶kc?·k[‹®GÉeÙÿæ1¸¦*ŠpðÞv-êÛW¢¿&BAÏHXø¸Š½/u$ý"ÄÕQzå f¬Z÷‰€Î� ®Çð �4…¾;¿1¦û&{þxXz¸± ZÀbÞxR”¡úgá÷‰ è;ÎíÿýE÷àWb8ÿTV–-º"‹é/õ€»™FÕ�pDL4Ä씃 •Éž‡‡ËàÄq˜Dkáüð㔽j'MÍÜòDhBÛ2u¾"Z’øŒð,¾!a%Õê| ïit`ÒhHÀñpùvôØœ€þÆ�Ü«�­œùˆB¨:,¼fC3‡ƒÑÁ³lž’Y-ˆne{¶Uàί"0­i§µd¾µ‡¢g'}ŒTç]#µÅ2”tp?µkSýSÍ wÄQrëXؼV‹â·L£˜[’4þP+.û8˜Ž#eYšÐKk9îLG nºÐ¡=­3äÖ’Žx GL³¾rêWîö˜�hŸB—4'‚mp//@ÖëÃø‹]£`Ù}#raº¤xnî00#Ë�" ˜¾œ­±„ñyëùV—VF'‹)¯á9[·ikp¨„¢s°;<öÕ²ï? ©}Ì|ÞuºBm¼G5i‚•¦sh0!‘N~y†3ή£c±<,ô÷¦ “ j9s¶wbGf<=M;FÒ•Õ0×ý6÷`E1¥ïP%é·“ -eXÉTÃÚ…�ñÝŠ¦ãEGVVâÊ££@™¿„—Ü‚á¢_8•ØÔ ¡ß5©Zÿ‘¶ð…[‡¹Þýh-:¡6eØ9x¾¸“éºÓMÛ¤ÓM”S±†\Ÿ ±çwÆàFùgXm(Ãä3ëñèÓÁ¼ÌÂz,kõ-U Ñ¨ ¡ÝØS¨•ß.õô¡ê›Ið¬,ŽòS_ÂÑt]hý®(ÈŽ´`9Û€rîä ·f5=K¾‰“ mQc–3t ïàš€ûÜ÷7òµT©9%ü¸ÙuBuÇMìÁl!û4<�ɧŸ$ÏKN”i‘ÄJΈ’tC<++ ‡Saqt4h3åï7á^fWPÈýJ¼{Ø…˜ìÎHþ޼!µ´fcàukíZQØ© )[ÆRè“¿++Õa~ù_Z¿³œSÝ*i=ÌRB¼S™io.CáQ¼¬°Wó³éÃ?¼æwŠÖ%Àlÿ‘µÇÍ¡nê5è߯Ãí�?¬²qûã+wtNÁÜ—/…œÄ&ø“[ 'm€{Þf >F‹—¯:Ìü‡à]‡Ô¡åCI�¨ ïÑÒtô’Fí îÞ¡qH]¼G9/ò³¥³é“|�Þ;†¨C¹öPJ-‰Îo禑ó6¸-QI)fªÖU:[`Vd*d, Åé¿O¡ÉŸ¶uµØc~WD­c?=ãËšýðÌù‹ÜƒÙÀ=«äµÇ³i?™ù�2îªèR¼ÿµ�&÷bbW�}Ù6fðÓš9ÂUeo’¹?Òz¬$ å8vù·–”&aF (©îñ…îEÙìÎŽ",Ü/T×H¢•2Ì⑽_=’ÖlË€x›]lá›sÜî½»¡®÷!»ø:“ªŽäAHBá‡åüÎÇc!ç„L p‚Ų³ivÀQ²ÙîO½?¥aýFÞùì9ú†’‘N;sÐÜG•zó�ï4ƒ@…än5�¬u«è�ÏB8 m}ÖN’>•±‹¢×ä¯{”å‹ßG�³×ÉRQ‚ï3煰ЮË'n¤—eïa­}-ÜI:[ÜaY/òà÷®Ø9nû®^W¶™ÑŒyrìëÞÃÐo« nOf,(eñ7C‡ÃÒ7º˜û Væ¦/Nf0cû£1¶fû,»�"+#ØÂÜH€WÛÁÖý§oÃcÊ|_ªJ|‹hd“l0ž 5W–�ŠK–p®¬$¸Í�‡ž Ep®(¶†kQBz-s°íà‹×ÊÖ¾·¯ „>Kš±Rü«!õ˜ý9; £?GB�|È>ŠÇ4Oi&›r— nŒ$÷,z�$é½ËMš}ÏïV¬½øk#^òéƒ/Ç[ÙbßX©w…é—Ya�ö~ˆø«Ï •¡# œ�³‘&+÷*ôrR E©�îÿ 4.EÐϪ!öTÿtðoÙ†àM47m ÈyÀÆÐvÖþß;œv9¶/I[z ÇÚŸŽŽ| gÄq»ëÜP]%¢k„•*èÐ�4ÊrÛ%APèËö”V±Çg»ÙÙÈ@öd—MOùçîUâ4Sm4Mw*@ýÄ{P˜¿·o¥?#Ú¸ J{A:ã>pŽÏÙ¤ˆ1¤¼Rç‹Àê=9ÌÊÜ„¾ÿ€1q#¨HµrkÄiNÖRû¤d½çÜgtXhBâ¹yœÅûQ4aà&F™ÝewM,pÞ«3,k˜2©ö.‡Öš5 wΠķRXR* f{j@}u(¤Ç7ów÷Òq3kÔÆÓ¤pð¡XíÉØ›°J)‡ó;^�?·'PÔÄ^©¨•íR ‡¸ttFûB�y”.šÏw½5Bö{¥è]7 ó  a�ËÀ¬®6æ0·IUXp*eúf±Z©çVr×IíÛXõS ’•­sv?ƒK‘Bæ4l êTË.–Ÿ�êS4Áe�({­“Æêï[ÂYÑÚá*häæïüQÍ5hjÖ,¼:Q@Rkd)zs-»8E�eÛ–BÐßbVßU ÓêOƒÉ1º¤“†òëV±ÕÒ>Œ×J„€u,aGÓÿŽq?ýÁÇèúÌ” Z]èCõê ¿Ç†ý6=…ßï7£kp26>NZæopñðµÀ;G‚æ6IúëÂÔS�É»ì·èz”ø‡¤0C|½w!nY¤ 'Œ¯ó÷y¶¡w->(o=;û Y2 6gâf}ZV#åU²TeØIÓ̦Y; ùªa²Öî�ꨓ­NÛmëYÚ {xý]žžY¤²º¾l³2‚«yÀ<6‰|VÀªù!v9‘Æ÷g�´Œ»72ˆ†¥¸_£o&VìÄôŸø#Í‚ª jX·�ì9LÒ»mà]à.Ég<þ~‡w{!Àœ¿²pBé&–.¦ûºWa¡õ;nöü"ˆ/�Êåä©ÀÊßÒàt;�©ÌñƒD§LxcØÏ*{f¦zþe›nˆÑÝU÷¸Ðah÷ô(�9àÆÚC¢q‰H+wfî^¨ írR6tBÁƮɇ·U^pQ5 V�ü@�#|¨`u#g¿-�¹Å/¤3®Àz§Ü`*ú~ä)·öHšÐ¹�ºMŒ:~pTÔ³´³¾�fb<�Éxƒ›÷›‚yÒ/&uK…Õìëg‘ÇóÙWÃÐdË{c`²¤:,?JRÿ=*Œ3©±¢��‚´„&^ëÝúŽ¥ 15œ†¡!„_æ ¨Éî wÃ`äî%�•(ÆíL{ ×íôÀòK+Ù‰¼`¡Ž zRÌ�“4v{5ÝËj&_Lew,˜á¢¬­9Ô-~rʇueÈ{o~ÀjFÝc×G‡“{¦SÌ�%Í´ó�Ÿr4l½4ݰÈ�Ò¢«8xd´¼9 ç\ãic‡x?çu�iÙÛl’E_{È—ÎÉG€ÊŠø»«Š¯�ç’®:Ðã×oø�FYåc@o^)Bø§dÖý=sçÄÁ�y¿Èò®éŽ>ÌeŒæsûɹ̛mz°ªt\±ºc#îÚú?ù©—´ˆÞ¾Åmï”!3z~m@vìÜÃFg–AÛ&QÖ�žÉ ¼÷C݃�`u¦ iA%¶æ�Éc J”šÆN½ÕÁÅK!è^[¾úþð·Ò­õ4Œe–ÊÅluouÜ´¦‚ŽÚÄÖ‚Y‰å|:„‹cG@Ë×d¸×3�Üæ/ ô‰oùqxúº6t†Œ G(E.§7�¦Ü}Áó¹(q׿}—�‰Q`c¡ÇÔÅaÛÏ=”rp�8¼ºÒ�—'qEÓG‚½Çc8øgœµ“ßTZóp6¬½ Fîæ0ÏçKø@�OLÀÜê_�Up l}ru ×U¢´óUí½Á.Û¼ß? †iyÞî£ÖâtVôà=“oQ ¿å'Q»<“ n¸±�ñoÈù†L­b§!“Ÿ™™×lácŒ®”¶b3Äó Läÿ~é^ôg/³é5æ{¦±8•‹ .Ȧ¯jPyvá¯áÅ0ÝKš�R±í5˜z®Y¼(ý ÃuzÄ ¡MÎŒúó^„A±'Xý®löàRè+âe‹)p×SÅszp˜ì~JúèOÚÀ¼ºÀà½Võ æÆ‚ìÂË�nà mãÿ°PÏùlÑd=(1ÞM>dbxÑh ’lf e à · R×¶³)Ïxæßc vé…,ýä$°yÙyo?³è}NÞ8߸ÎΕt³/À—ªRØU®Žé!Õüf�¿¸iž[_èþœà?x—Aöâ[XX9È7l7€‘ßÙö;‡ æSïNv°l4yv¬<˜Ï(#üz)ƒ‰/¬åvÞä©ô{Æx°€m²ÿx.MËs`�B¡4A”^+%±ÉÚ½8õš.¦^w§ò½³À® ™äÚ ´gŒfíסWÒÁÄâùLÝ_Œx‡‚»Æ<š F’v¤éïκËùá7C©îÖ1دï ÞÓÓáÜ�”·Ù„¹À™D‡ÒyUO(–P„=�©¨êú�ÔN41þÃÌMUk=ÿôà+ƒµBahøo!®e�Ùj¥xK•ØÒ�DÚVp�u¿ñ Ó”`p§ �8�.pdïv Ë}¨*cY6ªt"h!ξØÈ=?û›åŠÉvCýèi°wB+©ƒ�‚øø�¨-ºÊvúã°SŠøòešp|k �p„›™¦`qþž@kG%ÜàL­m衆6¼—¤éÇZÑÏR‰NŸþCrí©ù£.ë‰o³Jmª—“%½Wf°Væ7v\³@×Çî,·{ˆ5÷*Ѳ˜ráa½Çxy�%4?oF½q{Ñùëgæš”�¡ÿv¸µ¸nÝ)Í–•VÒ¤êSx|îpútX�býC—_÷ V“}.çP¢ª„Þ¦ÈaÚþAÒŸ&�¯ËY×�Ý4wª&æLu„.a?E)ÿåç%¯£Uv†P«�L·âç’ñŽ,¶î° |lV„+Ù‹PüQݵRd’»ãÉø¡ tìÿ‚ÜoRüµìwœ+¬>Jç½ÁùéC¾&Ó‹¢’”É%î1çq| RÅjÑç,¼?ƒ®èš Oƒ &” q3ôù�…¯0 Õ“““Ô¤ù ç¡Y"‹êg‰YZ,ŠÉ+­¸“áH9]øMéÓÈVçÞÊ€÷ÜØu[êOï¥ÈGvÔ¹†ñtw¾o¶c®+|Ù÷ šúI‰%eÐu[Uð^p ‚ß|fùg»QÅwˆ™yQÞÝW|´Òuœï=›tW°O¡ÛèF¥1†=E£ ëÙ·ìDŒñ‰Æ¼êP¦÷Žwøt’ßcÆ©—¬Ì…pw¨{ýמñ£l÷‹TÞž ÙO"¹lG×âcWÃhz¢@›”BÉ¢"�õƒXE:iVÇV®ÛÅIµfÀɺpÁª_�´Òßµ,ÂôÈ”™ûGÒLÙû�æ+c½åÅ’K¯@5ƒJÜÅ|x“!gZ ¢Ðúã';sY@¨7G)Š{¶²WÉRäd^M7Ø}ê8[ß”Œ¡¬W'.¹€ß!Czöûj|»§}GÒVs=ܳU‹ŠgÙÒ1Óæ³ù ý{� õáë˜zÐíÊç%zÇâ„ _)3)u$àþÍòÏÔÇçžÂÐ�Ç´æ’/ŠM/…ú6Š.ˆÂ'�ñLtK#½sõ?ç·G—«a(b,¼N¿ ÔZ[óS¤›­Y*1T`Ù/Wø3+ÌÞÒ¦f7�ŸHœFI“÷¢ÍÓ èÔû�»o܇©<箘ÅIJN©,„¤ušui{>>�~¾5Çö€¯l”‘ìL["nì¯K»ôa™°��Ýr ¢þõºf¶ô—±U¦k±çž öjÑ«�ö0§Æ�;íSÏb{âˆ7ˆ&ïÿÃn‹0ö·þfÓ֘Ŭ_Ê�·�©¿«ë¤Ht¤¼7&³Û=“¨°z4€šüœ±’ýÚ(ÀgSFÃE8NÁ�Kqä”R~®c±êúxy´p„$†~ò¶#Mi}çÞéÎ9Ö²H†?‡úCó©³·–>¯gÓtW@¯_4–¥Üƒ1�CLÊJL‚ߣ@QÔºa§.äò·1mºÚUËBç…Løk¸�' `ÛÛTŸXÁ†{ËÕó„¢�¥rwئÑ:¨hiƒç=pVí¡çaY6]Á‚¾DÇáEÛñL¶T@bÛ÷ÓÆÏ¡òu Þ.igËï•PŽG £UðÛNŒ¯\‚ÉŸ”j¿Vüb~Í^Ôõì5{=xR@4KœÒïèP“x+t+{G�õÁH¾H%”e€-_7¢æ‘„¨ðÐÄyVq�}!žhæS&o ZZCL»Ó7K>å4%¼Iõ÷.ØqèvÌðƃ"ìsË¿~kxnp…Ðí}èwQ“ŒŽ^€²e%lRë$¸'îÏ"Îì‚[ÒC,jA>H˜¥Pb© ›>-£ªçÂÌyqû=¿˜¾ËžcÝ9¬ïãFض1•5ÝoŷʯHÌÑ€Aiš³sëþPÇ6Lb×O”S'Ô°µJ°Ag.LK9�ïv¬‡îµ/μ¡¬4œ�þ£cî™Cëo‚ÁrQP8J/ŸÀU‡p8�3�µÚ- ¸*wØÙ„ç�µs9�°rD!®Ï­§YýùÐØžŒZÏ{hëñ ÖŸüu'NÆaS–Rõn ì™ïêuià‚> �¹wõøAÞ‡‡$þ³Þ¸‹£áòï<‹í1 Läê5Üú*}�ÆÃˆUý8Ôo϶ÊEÑôÅU,Ñz'ÜÉ<Ž~ç;Ysþ¼Äm£õ ç¡'܉µ-Ðd ò?p}AÿØTw8+¾ÒB™Vßp²´šˆÿEÁô$ˆjlf zVÀ°ôqܵÛeðÚN•ôµ.³¦G`Ø‹Xx;÷6~ª� iû˨qT SëûçÖ!sé`y1-œ/J“ÇÁÅ8?øª<—b4·“×éQÐ`ð™$Îe³ß[ÀplkxA»µ=™�…n�±¬Q›Ö·'‚ä]òœ§FuÕçaŒC ¤˜‹ ºŽsê’﹓•°²i Ö&�à‚*V‘ÊŽ:â»Ù±÷R[lÊp÷ 6"¢Ù¦óÀšê•Uœ–`Bû5ööH=Åœ¸|ò¼*DsY4a\«(áYÓæ"÷Ŭe¸ƒôøûv¸Ûü §´¨À¯„·˜q<ÑêØº�Ï9ÑÄ�êµ� M| ¤E\P'Ø‘Å6 ƒ�öNÔjˆäšvºÁš�#aÔƒ~¶YhMG¸CTÒu”·²¹Ït¯òW RapõT=ÕŽb˜lí ÙóÄÛ�v\¾H§Ì­Hä  œ°€,¥«ìLÃ$:uv)œ·­ÀŸ=;ˆ0×÷j ½²6½ÚkOÙì)`Æ„š‰îèÙ‹&ëó¸ùÔM²"–4-̈‰´ÈÃ󮑤ôáܰÛÁä†$`[î7æ¶2 Ù¿bu/S¸·M¥´UQ�®ÌÀ�ã ÈH@G¦ñÔ;;O… ã *áÐÛÉ4áW ɫ혼G-spÞìC±Ú¥¨{Áäoäñç…'hé¯yìI¨ -~ö…y�ZC;ïKáÔ’°E˜Cê"Ô6[“άDÇwžT9hõQçÃÿ±£_|j‹¡Ü4º¼á{çõeÏ_aÞíÓ`ã_iz˜‚YKþ°—W³šC¾d=º¦á” L�R¢*3Ø”€)tOwÙ˜OdFãÏ�¹ª-µü�j½xüMzmÛÀ/[‡Ï RgÆ+Ûî oöÀ’!,þ¸…Ò|cøùJxdS ýñ¤ò­š{!j ÖyCÌ)u=ÕT Ù‹÷0XÕƒÇöb´Æ3œK™ìÐw ëí©”°ë¿3î,}-ì9Ã$ úqÔ#˜g¿ˆÿoqXTe0·¹‘䑉Mæ_Ùä¥ÅüÍÔ|Y‹ö}*a¹�eÂAúÐìDž‚4ö}.¿S¥¿Æ�aÉ(Xÿ�—ll±aË®ÐÜáǸCÖÛIçI$&W]ÃQ› zò(Rž O÷áÚµ3÷©ç@«N*c¹ˆ. ‡hϼFT¶L@/cUZ/½ŒVÝËâeê” :°’mÃÇû_b€½3¥?97Ô­¸”yò¤¯´½#Jhi‰ðö�˜ØÉw�kg³kSp>eA�§ÝÕ=F¦;î²é“JatåE¼¤› MAÄËÔd˜ty‰`’Ýsá÷¶hœ~ú%ëè0Çõ‘›Ñ¿k8¬œ2³°ª®È ÅÔ$,øç=â:0¨6†uo0ƒËÊj”²ÊE=ósÅøjÄ ÎõO þ�êN·÷Œ�=îr°²p—s»‚-6ˆmlIeÝ%<—Ííúe‹'òü—Ö½ôwŠ2ܘyN –_då®Êôñ�$´Xô"—2_wúCHš©Ý9�çtMH¼T’ºÝ×Ò1~ KzúO&cù)ðö³bËžnµbæ]¤)}xvÁ~î#aÇf“ßòa„�3]¸#¤€·Ñtõ¶LK·Å¾ï7Ù²��8«d6ùg=g»U ñÌ_’ð·#·sA¸JI@{ÿ /]àœ�=lë÷©´¿;Ž+œäÁžÅwF«ÐˆÈhlzëFKßÕòŸ��¥0Õãlgã/ƈÆ5>S¡ÅhÂÌ=›¡e+Ï)È­ ÿ¹;è‘éy¦õ£‚;)T¢Z?š¸y =š‡hàAŒY– �ƾüíJŒ'†Ó½ñÆøèú(¼ú �Iw¬Ç=!2”3×n:>e}²ÑtTä0gѤÇV½ó›iþÈ�¤ôVнMÄm,eÇo_B‘aû [o8ÜÿÖ…óŽÇ…Q:S÷“�Oi²`¢pß °á'»áÇý"0õpäÛ¦™SÃYž-•-¸¿³Ò„^.·¿\àô�Z°ú›Ú>z˜3½•[¦ÿ†úÖ}bÏFs?#íðÐâ_üÁµ¬kl=wÁR�FŽv!S ‚ß™¤¡ëFS@œßkŠÎ–@;EŠæk|ÁŒ®~®É¯‡-sòwt¢¸I4Ü}5œò©mF[A6IËÁºÆháÒË©N`sž¼çÆÚ� HÁŠÆÃœó‘?¬K+ GªÀ¾ —uHSâ,¨jURM¢ÎEh¸)Û ‹+Éøáÿ²îM†:7mêžIw’©Hì0*Œ¦¾wK@¿myQ�}m9ù“¥¼Ã°¹xd¹Ìž-O«�)2}1- >ÌT.HÂ×íô~‹S�1yÿê^¦âÑ¥«ÀM¡ v˜AãÄqÜbµdlÔ”£ê-qL!LÖ±ÉöPk?~ì^M/Ö‡s Nú0×­¯;Rò÷¥øñM�àÑ¢þ»Ï)œAü¶^Þ8òn _Ky2Gñ«¦¶ŒÊÇ Ñàø¶”íõuÆ�)¸®ÜŽ��¤ûJòÔ»ºoX¯Ä¡ôÃìÛôpŒœ8À†�‹¶ìU÷… wù¦9ÚBƒ£Ytî¨ýøo-•ŸÕ„ �§@;SWìê`¶ZR›[1�~¥~9Ï&þ5"¿­ŽÞæ\´Dj·ª0›Ê:î¤C;=;�©œ¥ý^²k#Â@k¡!'UKè*o 5£&ÒÓñF´'ô[±Éž>uL£øÖÃ(\µŒŠÔ÷0¿Ðüƒm!á‚'Œ˜2�Þ #ƽ³„ÏÓ’¸­1n”~®“KVo`#ùÝ>ú�.±–†oÐݲ–6„î&u#W>v,™œ³£÷þClpõnš×fÉ�½¸�.ïA^Ó±Ÿ�½ø�¹.Œd1Tûeðê?™ÃVY�òI  =S@ìצSçEòcº…;<ãq¶ÌÁ~š`óv¢§ÇìÙIQ`¿2†}+a¨t9v9‰³€üxþr_3_c´‚¸ÔGL}Î0¥ >]ãpÑ÷Ýð*Þlï¨CERÛ,k¾ÂMœŽVï…ƒ6œU£ n-ÀšèP°ÔÏ 5œX÷âvš>8†0¥=G¹ _”EÆ™,¾å$ÛÕœ/Œ�LàÎ�C*FЃ/�üǽ{`Ô¤ÎÙs -3:�YØJÍÿáîð¢Æ/IƒðŠéí«äzߺ0É´UXu0 Sc jN&t¤”3ÃI1ä$¦ÉtZEáI›Ãì*^¬L#ÌèWé:>¦m-uË£ò ~Œ·šÍrSæÃ¯×G…R¯~᜜ zêyŸ5�Êc+Ý$ðÚ˜0ºûî<Ën,Îû:�¦ü ]Zb$kƒ‘º%Löü x:¤1#hsÐHî£î+6ªÅcv˜‚î; vÕ�ìNlm°\M²­cÙõJ)ü¼ywñÝðù37¤zð�‹EHªGŠêòÇi�tŸ i˜Dq…ÁL¤+••{H =ÜŸþµ¤`³¦N>†^ Íéú&ðøÇHïK/±›Ž�Øs(5eÎóO‚PµK®}Ð+�8ã˾ªh°Uɲ`a>��(™¡{cp¯0kÞžaóŸLÀÔçgØ÷'BælNCî‡ñÞ‘ÚÝ—k¹j³ÿýöV|X « ©!k)I‚�_Ç SÄk¿m÷‚²»¦ »>&“bÿ$ÈžŽ›ò _¨Ë“†£�W¤T) Ÿšñ*^‘ ©³/z¥ã�¯b4 ²‘�i§‡esÀ¶ ODí Ä¬Ô±‰­£;‡i�‚ÁU˜µéIÖ’Kšp.U{°uL«æ± ö {ÔÇù<@ÐNiÆ)Û±{™y¿UÌ�B"ë‘ë‡onùÐê[ã ¦]‹¶ÝÊf•oæŠQ”ñE¸Ûë‹ë“½áëv%2Ûê�•F2¸|ñE¶ßf'ÚúDÑBioa]£$îèLb»|ÍéO”#ÌÝ’„göÖÓä]vÔ:m VqK¹#Eá}› U˜!ŽóÚLUz^x¡[“Ÿ3w8™<[Oi ;øè³÷QÍÿ4ÎÊÏ%²pÄÐq–*‹ÃÇw¢šßAŒ ‰ “¥ïÐ9$žœ5âqF¦ ›¼Áæ‡Ò�ñh<þ|¨È⦙QRIL=¯KCY+à’ÓqÚ5¿— ŸÓŠi³†pªd}?Úù�{¥ ÊC[ûáÛcÆ3¹Ÿ—˜^¢‚µù£ЦÓÊêL lf#g®�»:¿ñ)½A¹8ˆÂíÂÙ¥…/ì0ÕÎ�f'È€QäL2P_Å©Æ×± Øë¯z´©ÞŽošÕÀ]ú$Š+ÎQf&ƒréðSJ]X#lÓ¾F/çJ Pï);ó8ˆ{-ª#?†²/O(_AÀŸX{‡qR×0o™,L�¿¹™jè25ÏèQ÷üg‚ë r|fBO—ªSô”SD-)h—"AùAÝØþ} ÜÞ&J  n„%<.W�F‘ð’ü©BY ÄÏž¤÷Q3é¬~;óQ‹#�î^þ‚h …ŽÕàôz¦’ñózßïÀV»’—¤ó¿y[A+Ùfn³r”Õ?äŒNÿ`Êo'½ Î(u³ ç|œ¿°ùÒ.Rü4¾{ê±;rŒ~­ùÅOì ÕŽEd¤*ƒ3å�Å OE5áx¬4ˆÖ7ïà›„78)eÛ§þ™)Ü; ûŒ'“² êËÙ/EX´Õ Žh3¦ÐŽË‹3pëNC˜>>Œ¢v‹Á² Ù…žjœnêwî…Rþfeº~ã×ùHƒ²I,sª/ÎßßÁÆôçà9ýÙä1W—«s;GJ·€CU>+®ƒOæöòìm6xyÓ¹EXñ�z–é{ìòL&ºŒŠFÿcY�;žyT„­;ï᫼A4J’¦î9Ù`c,OyEª¤£ü…_<Ü¿ÿp¤Õ—�¹§œ_\}�+{ß|°`'õàªk7LrØ–L[Ó#¤gîL' � î¡? סŽ?/0\ú±§*ôxÓ&«6‡r-HÂ*šiZÒ)“–eU=óàðöq4ÁÀÄì\Óè||»žYD¶—Kð¯R(гwX�¹”Q¬U^òË^ñçKNÀ”�R;N“E­XÉÞ«z²Íïf@Aö4vÚ?œVÞžÅ>.P‡Áˆ –gŸJ97§a¶ÃnZÛÀúõ7ÓÀÉÜu"ƒ:3ItWÿ.KÊî5TlÚÅÊæ�„àâx¶ÃŒf„ËãÞ¡ÏlUªXöç¢ÁgÐý|>¨Ž@¬š;_ÆDÌ6�eÿkNñÉKVÕù’SóJc—ó"Ù½t5Jz3�V/7boÝ˹ä·8óúM¢R‹ÐÙ©�SÍþæ&à5é‘4z@ŽÆÅå°£ò‹Yá݉LÕó ¦úV×ñtR:&ŸKa§Œ£_ÇŠYÿmiêvÀkˇƒhÓyî M¦þUט¥¦$i¬!™×6pin¹éö³ô KlÓj}Ò¹xž�c7h>{°[/ÏTq¯#•á̶5Ðk¡¯›KÈ6W’¹ýWL×Rãȱ{#ߤãGšXÇíÕ$¶ ÇŒS$z¬Â"Öãñگ­ ]\~þ^Þ¯Ñíùô¾Ã£œ9±q½ï%Œ¿-A!–Aàn#G[ªïëy¬bßHÔ¾iKmS3Ås&Lò[2ç~¸�µæ×1E÷ä»±·åªÍ‰ç?�Ëe/OxмÓAëº<Ø,¿Ç5fòjÖfO«*âa¾Ò-Ú�_�É&45½œÝÙsV_ ÇÛ™Àåºò‚B–$ÔÇåk»¹u'ÙÑÂbš•lO—}W‚i8Ðû'Áø¼Awì…½�g¡y¬œ: úª¯S+£‰�c)]¼­íÃôŸÒ”ªØÄ°ù4âîȺ´.p5µž~œûÉMûØ…OÎ(S¡O7ŒÏ¸B|Ìrø�ÒòK(ìW=;¥¡N’y1üV»¬®Øƒul—À,±…x¾o=úÄÈàr?gJ=‰t}•;=XÜʦ?Ë£›è wÍF ]�ÅYbä²Dš¬&d‚ù¥3tdá𘋫ÊN‚�—=w$ä+“X¿ý—µ° ·~°Õ�31òà –4Ó¿Ì^ôÏIïñ#X4[cw¬lõi»šuêË‚õ¨ù¬Sù ?Zõ*ŸãœH·+>sþ7®¡Àq’0¥)ŽmÖMÄE]ÕìGÕ fVÜŠÓ«ØÜa£(U4e‹]H¶Ì“’dspéþlZÑ'„gƒnyéÌç/¶×�ˆ’®ê¨ƒáAML¬*•U„É1÷ó `î��ßjÙÑý“Y†þŒóÏ$¥Kpèþ=V?ç;Ó¬ð¡äõÏ¡º©äØ&:ѾC7ÛRÚ¯ ú0Ò’,óûÙîÉ´¿ÀÕ çÒò?áü¬"¤ñ3Wàáöó�¬º�ÞŽV§þ_zìXx MIEœ5{¥Õ°÷³!~º™—ýN±€’^X(0ï£ê³M´½3è¾ØÖß9î¢�LÓfÝZ›Ø—M@­">´�ÌUÜuåO°Ô½‹f‡¯ª7YgÌ6z–7•‘G[´Ñù[´0öðª¬×bûg½æ®ß\H÷ÂGS@©ñ£ÎÀTÇy4ëo½9䊱Z‹ ‡Ï%i‰-p'òŠ sQ “æ… ã1bô<šiÚÍú¾ïGïàñd”a�¯vÄá*ç(ü uŸÍp6�‡SÉì `»Pj£DXFánšÃÐçJWÆ Úf £öäY8_e)~ùÜD¥R9¬g~ êK«ë,Ï¥ó›Öb¶¹¸õîüᔳTv}eG3ïBqÛ(ôõÖ‡>Æ”¬WJ£²¦ó3ôñÿ�¿{_+k1›Në =9«}ƒìƒ´ §ÿ OìJaÇé nž8ƒózlGY+‹xç§ßà¶G9K�뀦Kw ç\ÌcFuç ì‘?¥’£„ ¹ÿø2¼Vb´«xx¢ã§ýìóÉÏL¾* {²¦²«&¶¬pb:8>âÏÚ•€ î-yøz“°á1ZZÃI+fÁæ }j61¤ Ý43f}ñö$Vþ±ˆô¦ÐÎ]“éÊZoVßS�;�Îa­}>«:=‹Ý2ÞL¶Ÿ¥éӢǢ¿_°ìÀ-”<…ï-;!øb/Ó˜‰k³Ž‘vF ›õݪn¡Î\5v`M+ô^&´ˆ½Æ².­E?åÉpåA &äSóèBX0YÈBÖ½ac¾W²ÉçÜqº�gẑƎoç�’cÛ«¢ÛeMÒ´|À}7býéOÙ—B-;zÛSFAµ¾¸le9éX1­k?À¬c÷²¶À ["e-³Ö/<¡òÓáóŸtlIZÊ+�s[4.²M�°ðãYxûb+]ùd{j–ѹž8Ò2‘e\ÀVd�M3°ôn!´ÂD*í"ˤ¯ïàFŒŠLÿ½3þµÅ�€ÿË2ïж�GìøÃ)äX²]Xx/›-Ý}U�ú0�}XjÍFLlIyEÌHšíb#Iñy :ûq[óºÙ £t.bV~adwÆMPó37§Œ‚ë[MÑâ�.„‡¾áŒëH2¢’¼�ËÑÅwœå¶V¾·|I§j²ISËØ×íš>÷)„ÔóW& ´ïzü»ƒS¯vD¿Ô? åCjå.°d±©½Ì #§GlâõdnÓO_œ7¼•�ÿ+䆆’ì�8(:¨C¡ñÌÛ(ž�xò"ΤÁ°—cqüÓÉŸFbqv9Úôä’™p-xnbØsSRßKQ˜Y÷ôø>Á–™‡XlÄ=úù`unœN%#žšßÅñç™ӟ«Ë%#ñã*yfyKš6ýö€ÒžItÆ¢’4¢µùC½ƒ`±õK)*GñɇYÎÚ‹P–5 éÃüê„�ǸªÕ“pžÙ~~ÖQy,)Kµ©%\Kèz(·[Ë¿…²ÙÿåœËLÊ8ý—£_r¬»x¹�Ý‹†“áb^!vgye6ÎÞò,/¦³¶¾hy§£*Oü¢ã|�ž,Wy‰~®",–)ÛëÃa�pö¢Ì]¸Êe݃g=Ê©9KW¨2/•jÚ:DØiË5Þ‡hì°zœrA�†9ñ†^åB?ïó þ~3Ú}jâ†�§™8[G®ÇG’’—­ÆƒÖSØ•ÑÚ[SFR’QT ûž¿TQÎož{”¦G÷W™lùª|VÚ¾JàÒϸ€Ø<…+Œ0Žz¯˜Ò pÚR!ô·œBg^sAnßaޱ-ðẫdI$¦�&yåãË·Eè•|„=×€ÞˆŸÇýäw¹�.#·°°·mH ¿y僡lÃVÔ™ý•­ÿ¾3mòyë 85¡©ËG³epby§>l,¯«a_«æR¬ÓLþÆKnkä%ËçðCQ´îñ1|5C‘.ê(c㯠˜`üÏÃã¨xË1þ¥Ñzîwvo¡÷Œ‡BçQš]4ÜZÞ¿Ÿ¥Y£É�lú(tq%%}UÄ{l¶ý7�¾¬}ÅéåçóâDZýà °¿nF<Mˆ§‰�Ëaë>)ŒLò£ó²¡)ƒg9Õ/˜„Ì>þ¿÷G‰þeË�:˜åt�O­ý¶/µc;�DÇ­Ö¨Yô�3K0Ç—z÷aÁ¿™uö›44Œ¿³u<u®ÄævEbßðÏeà¹ò6š½7¥%UÀ(A™|Ë­1¸Ó—,í·áOO¶ù�™nwƲ]5ìï“ÓÌèÂYÖpò/tÊ™#Ô(Chb%ÛÕvœY¯úÆjï¦'m9´ì›)³ 7Æâ‰ÅX#ï òϲ((M‡¹äùSH™&µJºąXFÊ^Ì;Iz*á8b¤1Í2»‡üFÓ¤§9L9ä|/Ô$ÑOƒì©Õ$*ÛœÇ׆)ì_,¢†¢q°U[_º,€ÜÔy8ß)œün1´«t¾Œ³þ¶AÇ0 J6<„�.²«  5í E~O£JŸB’³¸È¸À¡àvfÓ8¿êÕ£ƒßDn¡Öp.òéS¡Z©<VêðæqÞxñ‹7îM™‰®V(wÅž>ºLc'®æãâéeì`&Ï?ꎥ‚™R‚O\)Ú—nçª�%=:%r�)ë±×ó„lYf$û0 †3�pÕÚ"È]Á¦™ãªEËÐ>4�|>=åŒÂnÀú] 2Å—÷^Ajép ª›I^K>r©'VsÖ³ì¸úïçÙ–º|XË]öÝá\º=›ºÒ~ƒ·Šji\ çKV³ÿT´|ÒRؘb ýÓéCõNš÷H”ޚϧ§Õ×ÁXfÙí¼Cò¯ŽPö=~Î�*zmÑ/¼]�Ë&pÑôûÈf CJ¯Ñk¤µûÈRèÕ£Üs³?,nÖœbUkW^å¦[J³ùaUdøÝóvO†š×«é\ïZýþ.۳Ήö?˦¼2‚T3 Ô ÞJ¿Ov‚ç¨zøîò™u‡Ÿ�¸«ïà‚X̤p7|£Ø²½B²›]0¿ùü]Î/¬3ÂóÉc0åÖqˆLtÞ<çÌ ¯­f1ºsœšô)ðå~¾¸õN¾5�j&)“k×u¡˜´|ÓöÆN/QtxhŽ_¦š2Ëq:t?T@ Ì×ñªþùô©î3îöÑſá•X9qgÚ¥“ÃEø®`[º½Ã‰b¿-ÅS2Ûáp{,¼žç‚â³áJP6ÿ«×6°‡¥ò´þ°*æ•¡]j£P.² Í'c¼§&½”|Ç\?KÀ¤Öp{ì¯ùeÈìÖeÒ•uÊ+J#‡ÖY$³ë4~ÿ²vù°_Aëp¼C~È7ò#±?Rl5qT±®Ú—I[û W«„ÓU—ËP`ZÏØ@Xú~öâñ8Ò <ËdvÊÐCé�à¹?©ÿ`»ÅsØç^ª*ŽZ&¦4ðí:匿È&­< šæï؈Íí°Ñ[VóŠ™2 q˜p»Nß)ŒDÓ_Ihwo*:Ç®‡¥_FSù‰Q—šþ‹‡ÌA{”_ÉŸ�ÒÄPÓ è:t`Ãî–‘;ŠÉåòÝ9êt@û*‡iÓÕ÷6ÌÙÜ•{øs‰î[ÆDëÌPÎ@ŸbûSP3PJ¾'°‹}Ï y»1Û›�Ì-,§ºÕb˜ê¸ŸÔ 1ÿ’øTF¡.øžâÏYQ}½+|½¶x¾âÖhG17-´šb…ê•Ø oÚ¢mN™V?µ-Ï'Ó [½Ú)�ŸçùÕcާ•J§Uãé™�¬ès%W9 ¶f�©…/¥ÛkxÏÈMønñœøM�î¿3¥Rï(˜^øùË~׺c­gŒp|ŽýÕסœ›bL›Ã¼x]748ºáˆõxôdÛl5…:O'BL²"i�Èï‡Ø–fH³rÇ¢¿† Ö£¼¥h‡Æl¼4ÚM8µ4…ÎøÁ 抓¦ƒÎÝÃñoU‹É¿^×Ï&Q)Š ò'ÉC™‹I4VM:Ë|¾{¢Õ%1ªPë…K{øT[wXÙDc†y³Ó#U¬oåcØX”ýö¬ÒIð#„6—¦�•�;+yX¼¶ˆ5êYskgãêçPåéN�¹±™•&xþÖ‹\å7AÖî$:a;‰F¥Uòú¦Ÿ #Fëúwbt­ø‹ÃÊÖËXI¢]<¥·/¢ºÙâ�d) OÚšÉQÿÔ«à˜Zy�TA5ÕÍøýç  O"£7—a¼E"iz—²·{2Y€A õûV³;¸ŸvoC–î놣æ"IìqY)ìÍ8ƒý'êÂÈÄŸ�œLõeÚ|áÊuøóÒz:[ÙJo¶}¢ý]›Ñs‡zÔÁôÈõÌWTü#íÉ:è”Ëäñë¯áPU4ÔUkã´/ÙÌ^Lš"Ë.â]“µxÿûÞ�w ŽBo†G­0rER­«W6•­h`M²üÍk#`þ´"ê[1€«‹ÀFF×þÖêÜÏ|õÖ…ýÖ¯MŸÂ¦Ý�€ qKõbÎÐKÚzLW»ïnÉÂÖÒíå#hö Cºzu{~í4r•Ô-ÌÃã‘Rýbwïb?ï�çÞì>M´ò /ì$»´¸ŠWÌ�‚æª!°]P̽½ŸÄÉdDa‰Å Öê?‡¥ÎU`²û([{ß·¯¡®P;vZÎ;é¢Ö.3Rj*ÂÂŒ]döN”nÆêãsiwøùJïʰñD+t>H§ú.†õËð¿ö*ÚnWÇÇ‹�¥gÝÑ¿j é®jå_GË ”ºý$†Ùó“ìu¼³°Ö½‡o‰~Ã2ç´ÃýÍ9$þó $ Rqýq-üq¢ÖLŸAgœ>A¡Ž+]Ýn¾JgÙæ§É”_¦Ï"gÆòé%ð3Ü…¶mkìO‰xw'-#[wêϤ‡O¥ÐÒÃ` ®ÉÆÛãèϵÑ`;ò³Ý¼�v·… ·ÞúSÙÊ~ZX“Š¡(û¸�¦Uàá1‘�ÿ ¦Îÿ€!‹ØñEg˜ûÙ@|úá ¿Et€Å†,¤ïU6س-ù5øwâIz¾õŸƒx ”Îuàzq+×àV> ®þ¼Š©iuä^½ §Bê{™(¿›Jsä˜�Æ"¦¹$¾¿,gŠ�°Á»ó À$ý¬nóÂì¼ï„™{ÀÞÆRú*ÎaÐÆ~êìKäç^õÀc­%(x%…NŠ‹éÉPÍ»ƒ’E§‚”õN¬˜åÄîÄä³öùìá£iX%M¯üäÚ¨~zá‹ý¬ç7’]XÇ\†Î€ø÷7¬QQ„ÞB>ŒµÜGŸ•îÃþI twŒí;dMÛ§Ç©)$®�D¯]ØŠSúØz ÆG€íí¹œ¿_2é\MÅá‘ý¨ê+Ї1ê;ð’MKzÇ{lmfÅç‘eu*yæí‡àüÕ”{!AðpçlòLäöTŽÁ) ¶ÂHv Ž,,çÒ>ÇRŠ� ¼6H`“½%ÐDPÂf§WZÌUÁÁ Züå4Ã)¾»½�޼?À-V—¤žƒ×Xn¦ïlÆÂÜ� Å�õ´ûOyÎOÅ4Û2þ¾›$›.Â�n™BÿË™ì�ú4¦ª†£ïkÒ×—àɨ;P�8†¢´µ­7z1ÿDÜV…÷¦ÿ†®è³l¦r$u/Ò‚Å‹'áÐÇTtf+ ¾f2»±ò»°Ešz¤ðÚݯ ÷…ñš1ߨ±iÔXRF;ÆPÖÌ[X¡"ÅL&÷Á6¶ÃC�Þ µ ‹ÿ}xâ˜E¯¼s™ŽD4n–”îjdÛ&�†éŽÇ`(è |)¨LÞ·­ï¢k^¼]û†«Êáý`£¦(ÿÛJ—yzÇóéZÀ>†îŸÏÍØ&¨$ÇžjÞ¤ ­3¨xõiH“ Äqf—8|Qóê‚€ÿ[IV›áåÓã¬e ß²-ZŠXkì†ý²Q´ öÍP ¦ Ñ v»zÔ•ÀÁ�û)˂B *-W* Ëö5¬«Q„N[9A`ÑìÚYLwk6ÐÒ‘p1ÐÚJFe‰4ÇÓQâ|èÃ.J+²@Ëól‰¹8>9n„3 …Ñoû)–æ8°#ŠS܃–€Ùx¯’0l39OÚÄÿ"¯žø'&–­m<Å}Ú¡€ñ—b™�<M6Á8üZ’ÉOlBß’:X^Æ[_®B³É‘8Úl/ž<\Â-ûQ!Tœh‹š rù@ÿ|^¹£šJv„a°{>ôµ5£{ˆ(“ËkƒÔ…Ô4dÊvúÛSèÐÊÛÀ¼æõBt×pçeÇ%Ê{cZn"<·.…sªÇÐ`�$v�Ö„kóµ¸êÄÑ8ù¥+'±0ÇŸ°£.ƒÅôBu.ž²¬gûdMiÔíW¤›ã!üVÜË^4³¦çMØ=ê/ºÕ ÷?`%Ó¦ãÛŽ-$¢ÑÄÌwýb5q§X—d—•£u9FºË±Æ€PÖªÃêÆüvcR·"1Ûõ-Öë U –㨸[¸ÿ‚'<ì�Š>'&c˜ ‡Î $jµ OÑ×ù¹PñÍ#= 83‹,V`ªBÞ‹Ý1çìÌÙ™ÏYOò¤›GøcÌobÇGc²wÄ`1 švW�.§#COX·GŽ&ž8NÁò˜0‡#ÛG»1ãx ­]ˆ1ïHe‘?^¿é‡ò)ãhÁé>Üu£Ö<~Ͼë’O‰îß’ù»—³¢-Ë uÆxnåí‡ÄÅ[ø©™$Æ4°»ë–r¢7qË5E¬sôþðÛ¿5‚ÔòHú+¯…wnó?¦$ÒÑÁù|­ÂuX} %×±TCGÒŸÉsAŠðúíl²Œ™H¯&Ÿ¢+eÃðèX=.òó% ©$–Ÿp”¦é¾ä¯ÍŸ‚åKU8К�«‹@ê­þý’;µr*›Ó‚%”ñß$V°Í韌%aƒ&êYÀ'flhƒ›ïáÀ”D0]Íü†¢k‰[ã6š&lÖ€˜_� g¹ƒÈ`5Ÿ�†Ï²›Y÷[¸iÕ‰—ç¥ãñ”nP�qǧ>‹YæÞ4\³…@üþès0…az lØ‚ÛÒÿ g_¸þçÉIiêcfH#l,) š; UšÁ„v0ùÝGpÌ?‹KO,#¯ _JL˜jç×áz'W²::—Û'ñ†·\r‘¤ 6�Ë"Óý²à 6ß=V}&ÐgË3Ç+ª8÷¦lݲšNpoÆþYƒ­x ¿âÙk~ÄÙKÔ)è(žR£‘çÁBø&´|-Ž©~BÍØ+BÁötÑÃ]à°Úý—·cû �©È;8 ­Ps7‰I��@6™á²³°�«ùû¡vâçY¸®vÈFo£ ÿ©xB^ŒrC ñ±Ê92s[GßB'Ð Kbûðf¶'qÙ´6v­ò k™6(|>ØÍ4õF±C;æãg½ûP•çCãk£¹-ÆÉ,5ŠrÎ&Àˆ ç¹Ìæb6òLM1LÅì<\¤)SkiTƒ±ÍäëPÂ9¥zñ1æ5�:64|dz÷Awà¥Û%Âô¯Á¤~µdÔÖC__„-'hH¿ ôûØo�:ïà\Ló>çPâ�(º±á&,GJ�•°Ž¿7Ÿ ´ZÙˆ¥)ø¡à ùDù Ä=´¿q�${+È4÷>6˜‹³¦×)(:ŒFjýF%•9è6u ¾:`AAÃ-Ù}uGÜX¨H�×&€@$E~ÕÐë›Òuj{n3®¢O¬aÆëc rõû±¯a\g­™,É—ÍvÇ(mIÊÔ9Å´t@qÌj:é…Ò>ùìà¸HŒ^ØÏ}& ƒÉõF¤G�…¿bGñìMñ ŽjR ÷�¯pœ÷5¸ø#›ÝÚ™ËÆÚplEâ4§›¨98‚}ꔄ¿o‘veFâêe:ØcLÐsŸ‡Æqlµ©TÝY'=Ê—ó§ksưٽʤì¼� ϤïD¦°;ëyÑC|ø"O-Î(áüž¤ì†§%ÏáÓ]QÜ&y‰Ôj—€ôE kãÔ!]ñíUœŒ½3$.úîÜ—  œ—Æø§ÃÑä¤2ûù1¿Š:ãî)ðäq"þž oæÆ3k¯~ظƚh6bi¥øMs W sÊï̀巯²�RÛI𯔚€xZ Ž-d Ñ“�ÃÝͱ½ßƒþ¨Žd?_Œ‚} ôʹ‘™%Íd÷J=ˆZsë#ìhÄä2Ì–Ã?—D°}lF9Ÿ§¸ÜQ~"ÎTQÎÎòNóÅãjFìÞ+iôùç—sæÔBÛƒƒätù6³Úz:•�)4â“e3 ûó8z·)ˆ¾JI�Rú"Ð ÚI'á*Þhͧծ´îÕXú¤û›=Ÿ�ƒu }¡xÎL a¼…óTºvk#®9+À~†�ò,z˜qÒWù©è‰ÿPTù©ÍL>N{¦%ÀrÅõT²ß N v?…ó¡gØ—–_Ø�x£BþÆ·`pŽ>éÛœfiæ)ðbâ\Ú4Q‡-ŒEçKñøôx-~²š‚;ðÅ#vpÄ/°IA[Ïù / huñ.ôº=ŽØéÂû«UÈu„}û¯//T´>¯�س ×Vá5'ב²~(.m’À•ï:øuþƒ‚ÚÊÚÒR¥.Ò•ý Q•OØ«[7x±Gñ[Y ¥(50—duR�[Àdú§ÒMQĽ:\ã»ñô4š#ï×A,> b#ô�}ôÉöN\A‹>ÕD7ðý÷7@¹â8 |XûŒ¡× ÖÒ9ã>7ÁÉ<€]z´ëX©x›QFëh¶èw&òÞWÈÛ¸}–ÙÀ�Œrü~ñ¯`ïÄ ±JÅÆ•°se;äÉBÞ]'aÕUV–u'�5*ûaT‚S=˜‹Vg½áÑpSÎyÆMŒ>âK;f¼³Z½Õ�|åÛXÚˆz=·ÉžÇŸ‡î±-?}('͈tN…2ŸùG±e­7óŸý·ß[‘1ø0i8iÃØšD8;>†Ûüð>üÖHg-vjPªÉpŽ {ä}‚÷t Æs >ÐA�Pz³à8üÚ­A†v¥÷Fw»Ÿ‚‹+·QøJàµëg`ì¤$œœÃ‹…æ±ÕGNr£ êÈÈsÎH©bÞƒÉXª‚ÇŒ*èa�"IïOâJŒ ˜ÉVs<ÙôÂ/‹cîÓ� Þû .G Ý�i”Dw4Ö’\«"м°Ã(ܱî+<í¾Ç÷5¥’[V!^Ì™‰%§„4L¯lÌÓ™óbmœ÷Ä…µªµ±Þ-Õ¼ÙÏTzr3Œwð4ù¨-4¥O‡�¶£¾kÿ±ÇÆS!üe2“~ºW ÐT† õX×è"Šg"ˆ%s¨ûÝ*j»~þrxð™8¹Ýœ‚é»7ã§[{è®J²ðÃB)zúY'u�Å']QØë³¬$?‚‰•>³–?µœ"ÞÍ;A2Bœ>PaM9lÛ[[ú¼ö̯ë/ÉÆ^£«ÜÏæÔqm1ø®«@—žaôññnöIQÜN:ø:ï/¯mXÁl&|dv› Üõ‘ì÷ Jý®„‹×wP!3� #u(Äs¾Ð]Êüõ‡3>]ÂïhiÎÔ3wX b~1ƒ»{«3‹#cIcV5D©¶±Jt!~Ý6b¾~‘ËLön&égrôyë'Ö�ù/#t@sRK �¥«Îx*$ö=ØÇ"zÁûólçÚ�S6%’œuðO†—²ÉÎö;'¡8(Ôx_Žã|ØŽa‹)3B”üþŠÒô*wTŒ A•Ÿº¨ÒQje>÷{ù3ddH"·jŸ~c«,#Á¬$˜ u]1+¡˜îÇ�¢M'1qM|“úbzE˜²„ Ã=Ù?¦VUÅ|¿r%;«Y»f hų õ�LW‰ Z3ÜP[ÅžnŒÄÝ0þô#p¸§cgâÁ?Î|ÇÍ…ôÌטîÆ90-— rᓸô1g@ty,Rˆ¥w�„°»Y ¥X ˆ>«°)ĉã6±/;£YÌ·*š÷üœžåŽÝ;œ©x¨’ n”¥n 7úúß¼³å½Ò¤¾ ÿ ÎØwóc݇<µ™X”äDÖ#÷£”ã$ÚŸ=þØbMÕr&³Bs€”÷S6{ÖW²¹{µzôÐj6$²Ó8cÐ Ë ØÐ•@*Z×¹œ*—VùˆÓì–Æ}ÃÒñ½¢†>¨G/ïéXo;Ø™$ߪ¡¢©ÌRZÝq�Ñ2ËB^ržÝkiè}$½Õœ�5[�†¯ 㥢|‹]*SXxŽ[8k'Õ˜˜ã¶ßŸ`ôäÿpLÁÜÕ¢À–{UÓ6ûj4›þ~ð´Ý¸¥öÝè¥è•ÌH§¡†”ßÔ`Þz *zÛW^¢ÄmÏ¡ªá(»5]SÏnÇÓä�³ç6à»U ´ý�/ªøÄ’ L¦ §*С8Ò û>üØ›µðzµ€ßõðßê'ùçöâÈ;~ôù¨›pe&N~¤F‹·¯Á‘S³šß³é×Ëdû•öeàÆ9K…çÝ‘ùý{ZJ�óqÜ^äÝ0è{-f낟þ ö¡¸šMëe&—ær®›šªÃ‰G»à/;²›cÀXz–‹®d»¦´ð‡ß2ÙÇ¢¤ôºGJP`l»55;ήÃéÚ±¸sÙ’tXBmß—RêjGz2m%¹LÄœÅWø¿ÏRàìDN£ý>§ŸXËœ}ª¹¬¤<ýÀ‚Ì5 ç²Áv ˆ8æB#l>AfDn>Å-´WÇÀ€ƒx¶m »œ„û㚸ôŸÒ\—»>�d­0YF·•‡±'©ÿÑ­y� EŸS[ÈRym�¨…2£P|·7‘ Ïèâ¬]BÁ–Q°¶û% 1Ɖ‡…ì�èÎëÄ ^g† ¾jg+‡tg“臻¬æX$Ängn)#ñˆ\w<=¾µÚÀå7ï üØeôN‰ ù�\ÙÐ-Ñã)Ä"�ýsm£~¸Sþ<þ]dO]ýA¶ô/T©T€”‘yå7ÓÐ’‘xÁå7D,Y†]û¡ùÑþ½®ÉŸ„ 2F¨Û5‹"UÛ¹·Éñ$v³_ ¯`�ú“ÍhÜü)PR³Þ[àÄØQ+Bb­'øK)ã™ùÅóKNab€;>½’–Gâ¹Ï8–]§ºÆ™V\i#^ÇÎÐÅË:èiÕ+ø.}—-8í€G›.ASõ2\ûP ãã¥p�íö=<“?´K‰~KÆrâ�"°‰ ýlì[j©µ¡�7él|²¾•*Á]ËJرD#ìX°…¼÷â·2Øl£Î‚FÙàóR_öÙ~8FyIÒ²AIº_kÃÝ-cs]¢„W‡OàVå+²ÞG¹Tt»D;ÏášU«YªXª=KÚêû¹€fEÊß¡Ë]ØÌ‹�Úˆ_C×°Ù“¨8ÇôÔ-Iá‹UÇ&¢ø×xhlO¡Ï®D]Å,®Ï’æLÕ¡C�Œ¨{ Árñ‡_,5P Çü¡Ÿ©-eþޤ‹Û?²î7çði¸;îÖ2ÿÓ y#Ákî—«=?oÍÌÏ}gC½Å¬ç£;nUK«+Tieª–íØF36ÃwGœHuš:W%2ŸIÝɾÍ`Ï-æ°3[1~´~¼Š9·�F©Ý]ÜûÑ],Ôi*ßjM¦sÔx+ñlõ‚×b²Ýö‹fY+ð ”*¹Í/Õ9 ëÝÝÙ¿MÒ\¥Ç(ßPICóÉvx2Í­�@C­ûðôíÙàm0H ¿òh}ÑV©¾E°ºÉ E§៙Qì¯�%ôô¯a�Û¼ÑÊ`)Eù«‘Æâd,’ÜA�G:µ�ýç(:�›É²fɳøóøÉ©´ä­?ª„¿%¥Ü„·�ôÐf� Ô@=7}þ)2ýMñôQ¡Šù- ³^Öì`Úzغ´vÖ”nKÑ:«œäJLy’Lù:íÂÚy¾ çTEN¯Óø­v¦´ÄÞ{¾ÚSÉ]Ü—×§a…·©�#‹ÎŸB%“CdžÑÁrõš°yk3«¿™ �€ °êµ%^÷hÁˆÞff:�¸]4艔6Å׊°c ±$ë§{¸îI™�çèNºçCÒ ¤Í nœ…m[¿±I¦éévŒ ¿�.�šÆZÝFaêãlgcìteä©ëY*ÍŽjàÌÜöaí sœûØ� /²…­&3 1EŒS9�°·.Q´D0ä•�¦ºŒÉ‹„œ'¢xrŠùh‹áÊ r®Ã{mí]Íy4^ç-U« àßÚA% Zšúl�N± * s¬ý©›K?”�qöӇܱx[†éàÑIµlÎÉøhx'$&ÁùkðÑsEpu§C]@,{Ü÷P('œEW�‡÷ã�܇qh^™ÚÆáH9-nc›Lº3�]m¿ÄÂÿÄSê4Yš>ï!~qšK7>æÞlþ 1 ˜QÀÆúecÎQ^dùJò-†ÌFœ¥Ôú8EVLçÕåZðiN'îHÒ¢M‚ ÜPZÎß5èãt6— Wµ>3Ý3ÌòŠ2F dÚ.Œ-÷—ÏÊüF×êyt ¼ÑÅ¢dо�½0Ö„åçú˜ûê]t]»€¶¦³*r(‘µ�­×Úßž‚ªçKø=ÝR,g÷>|µd¾5úÊ­:®D’K+ñhÍtZR•�Fþ…YªÏÚW¦²Ç½Ix@UÈñÓ+éËdqôÿú€ÿµù>ïüR‡3:äy­ÈéYW·=úNÀüë‰ÜÁßo°åXîw?KÛ+¬~ˆìb¦'ÆÑ½/7xÇînÖo}ªrqú­B¹æ>šž÷ÆØîîôø3ì¿ëâ¬lV0Lm?.œìlK—‡ë0§9BaV§(–XííK+ùÄÓy°¶,VÂÜÇ5ñ¯ E1vr;ûØò€¨øøÄÐ~cs©8ŒÆöÏäÌe0-ù$Ír¥)�Ï‚âÊfì¸7›Ô?‡ÒþKŠ(è<€ñÕ1`tá ?I,”Tì÷ãé×Z¹®œOyfŠ+Õ/cCì#´MmÆ‹-�Ô•^Ïç~^†�|�ðlÆAªz½Ó >qSªXHSFÎÑÀ–WàOf5»ÿ0*tüh�n[ oŠß{ÃãÔŠÐ=K»‚¼9“{/©àîIî��šú]Äf×R¦ºa3jß_‚Ëç§R�Zõ;:¢Žük}n}y�<¼Ž£s‘øÁr.ïuè�³,&­—‡E·´I>Õ†_z\Š~:-¥�ÁZíÜ�Ip3×FiˆcìÇ9ìωlÞ&‚£¾sçˆÛõH°¯ã2›¦à¢G½¼»©4{q(TPf“"[)ç?‚·°:#N[Q —.Áþ/¼ãê¾§%cV�4žElû �¹úÞ¬Í;zxaöl²•ÃÝ~]$ˆ¾¾”½{ˆ]žEÊÃbÁÁó5/ò=—¾ÙNW Maxäal ›ÆúÑ™•Ø)yN .y“‚Š1üÑVìÿ”M“¦NÃüUêx]Î'¬†à óß÷QæŠWì°ïBôX—/{¡yS*)Ý•Á%G80?Šø~8%'W¿«Àô1q¸jó%Xt$ŸÝm¿‹CréΗJ¶ãsŸõm ¬’[B…sJ©a²%íÞÅ|×$°žD/¶i™3$M,¢ …"Ö=ן´NÚ�¢çMvR¿�i„…RŸ§[Ë6ú%Ó£NпÎËÞæ> üñÖÆƒlïs ú"/ w{Ÿ‚Û.ÌíΆqêßÀnÉy<µ!ƒr'½ƒ%ú[øÎ@?’ùožÙ´‘ºÛ³Po¾*žXÞ†j¹pHÿ§ž€d6°%K0·D‡)»]àþøLåùàréµÅž~,ÞÆ^—a/¤hÜT{xluƒËé½¹Æ;ÐBd"7cוH¬y÷Ó’p{q*ÉÝÞ:Ù·9oÉ,J¾Ôó† É´’ÌÊ×ó4jsÌ7¤Ø•×áîÇ[ÌåÚzúµ$;ÞêÀš{³Ø™q£hÆ­D2¶Ï€¥ÓþùÂ5gÚÐ}�Ú|ÓamɺýwPx’dúÀ×c=ü³ƒ‹™ý…Ó~ˆ|N*еØa`ï:aòÖåŸÄm) N)EÓü ì6�y×/¦ø�\�}¢ÿ3ƒuÉ$ü•iŸ3À‹³K U/›‚6¦³UJ)L¤|8í5`{&¬'µ´Sð ñM ŽúU61‘…Iì̪ØPmEþ'‹I026ª—ѶG pè8Û™Ióß\gãðU–ëØ/…J]=\Oè8¾KÖ‚¦mõÅ ½gX¹kDª/¡à¥¥\VbÙ$^æ?õ"ëÊ3@/?'X}Ü•ÏÅ·ð4‡§ïë̽m.ö-»YDzñ}êbŒ¯X•ã?_±ûnÊ ~¿ v[DëŠÒùõiLMm or¨5nΣ 21Ô´y)îŒ)ÆÌ»Ø³K‡9.c(t YFÍAºø*&,ÿ�6b) ö¥�\D*Þ%Ü–óE´nqKZ®23Õ\J°U ctèòÆõ¸*åÒÌÀ×>`1ü:6¾†Ý �/ô.ÂhgÆ£'âË�!ìñ¦sP!ÛÄZç<áu,Ö±^ޏö·‡QGeKš�ãmuX{¸'Þý„3cØ�Šª,�¥�†ùøàïšw ‰iñ�ÜBëëÌ<;oZcø5]i8½´ÄqUòeæ?ü ·»©2ï6³iúÙtdÿV¾©ó \Š?I•wWÂïuilô¡ à/¶*_Éáâýû@Dù,Ù·¾‚� Îød+š÷Ï@ÉñÀ^-Y0%>Žd�qÞòiä8ß�þ.€{ú'‹òFnóËêSZH¿Cå·®9™ÚŸ2ï ôšÝ`î=Ïž¾p=/7–wÀú\1Ò•p¤4©tàó2ñl±gŒ.öÖCé)|d• ‚µ:ì£-ùïñÄ�çÌuô¼º ~n n“–Ó¶3&äk2“¿ž>Œž�†{W·Óá•§Ø„ª¹‚—Ù8uáJç˜ñ¼XÍ îÏç&aŒL[T¿…I½HÃ/½ZY¹í³/`ã1§ë,|ÊfÿA Þ%=g…ÙÖd-§€b�?¨aÔY~‹L%w¿`_\Äéð†xš¸c˜°oX&KµþÅô>ºñ{µ“ñîÉåx;ô.Ü0;Bý_ p`Ó[¶B“£‹WlpïÚ-¤^0�~Ø„WÎu°ã¹$~•RÛÈéx|þfŠ·¾Åã¶Ñ GQFˆÖÉÌ�§Îä‹P-¾sVˆbÛì(ÒM~Ä?úà†ËŒ9Õ£ŒÙ-vÿÔOnïìR|à’ÌmpO¬v#|ýC žyo#Ý5yœ”²6ß?Ì\6eÒ1¡Þ›¿ ¹ƒ.ÇÉÏO2t£A¬i9×RO{vÂ[ãwQîKKÞ÷!†…cÕ!3æWtzt)oô"´QA”è“£†3Pw¼†ËtPf®�ö¤4N 5N¦ò‹þžÄAñólEd$ågW }ܶO“æ¥rh2©¾ÆÓÃ!&“ý”/…ãMhéá¤SÆO\„ 7ºÓx)G’Y1‹!VÉ ½² Î8á‹ /¯�U@ ­ ?ÆÞ|@¾¡�ÇŸçܰe¦=I•=€ÑÛO‘ü­XH•Y/ôŒña§üm QÇ�¾ÂF ”ÜàßOV§e»d1Õ;›ÎGLau"}ðý^C ™¾žM¹ØbEìcœ?ÓñR³'I‚hW!ËÑE]Bª9�HºiíBÈN‡‘Wž3|[ÏêÚ¢pêëxÚx) ¢fr¹ËÍq›yµYÆpŽN9˜ÝU«,aÈ@oüÇ+.1ìÏ9|�µŸõDÝ×-RøÙd*þ…†~ÊÂäÛ±üœ©3(鋺›ô±UªM°;m$×ÒòÎÅO§Å¥}àß<¦«Ðy¥&¶ì¹Ã-lÆõ ù JÍL§.šßþîëqöâ>®Cû7&#ž¨eæÎߘ¤‡=^Ö~Ãú¼‹qm§,‚ÚI>ýÚ&«\4 O‚Õ�dˆ¨ÓdSÌCðIÄÁ)Ÿ$¾D¦¶¢�A�¢rš�0 ž”%SøôxbìAÝ* PfË58a’ÂÎÍÌE5ÙL tO6é²&<ÌÄ×dðbk¶Ü®}å!¦–1ŠbÝÕI¸¬ Š=zXÙÞ윩*¾v{kgw²×Ç¢°R˜NqŽ Â·’SáúØf§õ2 Y”ì]”‰IaovEÓž90àåH÷©±ÿŒLA.Ñ—î­†Ãõv8¶Ë+4#8¬Jc^ëw�Ñ 'x>~Š>ž‚—_ŸÅéRd#:aþðrÖÔ¿›4§s,l¾9ñ^Xc°š?rñä]]Ú³i )=,Åßj§1tÊ&ºTs{j“òxs:µôý?¾<€��Š ÷Jƒ.š§°½+ðòOªûm€0TÑMY˜ì'¸d›yú‰ÅþéðõDVÕ zê53ÉÔ¥–¥(ùñ*»fèD)íBÛ Q< .N”À#{�^ÖË£ËéWܱ°ûLÜù æ¸çàê�Þ®j%¼]ëó;`ÞͲjVIJ¸~©S¸ÏÄ®~Nck/m§µk~ÂòÚ\HkÂ[OÞby·8M»6 ¥\¶s%²ÙXP<†²O�¦«O£ñ÷hw”ÔZÏ‚zF ÁµÅ,eÎYzt²Ϋú@Ž×f;CWD³ëEÅlÛìWøë×:ìMÑeni·yÏ1îLAx:W-‡["YG©ùIòG(²j$¹WÍ„î?<Ê)‹àrç"ÁUZ9¿‹~ú8±¯ŽUÜ´7—`‹ö¸YNûÅâèCÕ\Rãȯû‰}ïÇÒ/«§œk¶ÉîËÆ‡C„SÞŠÒ¥ždV6L�ÊÒ®£{ýCâ'NÓMЏlQ.G‰˜Ü‘EP$²‹ÌäŠ Ã.…<¤²Ÿ6iØz/[±ÞžïÆ[?�Ö­–ø'óuMo ñ¯Mô0�Ý*»ÙÏ@àäUâqåéAô–çhAd àLí ?¯&‹k6h£1½ÌøL�BA)µÜ÷Èé´âŸ³¿_D—ùZæ1î:…Œ‹ òT"…°¯ä‰‘̲ð‚Q8;`¶>ïñ…æ©HõWйÉ¿©Av,þ’ÿD[‡M‚ŽGmìÓm*¥z'–Î.馜:1 +ýÁ6.’b6–¨)ýœoŸÙ‹ÀkçóÇüÒͧ[1×f!YŠØ‘Ì@'ÐÕAºr³öˤ‚ˆÔ'Ðy¬H»œ§¡ÿìñï0}ŒpMfg2�Ÿ_¤E#êãá°ÄfüÏ[ò #aá6  [q]˜â4q´›­ÈmòÎ+HcôÑ�ìï11våë,8÷½„u}£€Â¥Ø!^ź|ËiaÑO�Ñ�↕S°Qû=Ï‘¶…/a“ìÂ!ã¡+Œš„�â� ÜÀJ®Põû`œßËŸS�¡áuâP¯[Ïîç«™ÇËå?3µ1E jÜÂæÜæ¬|ÇéL1á“îíÁÚqu8ñÇz³ß‚õ/Ç'ôQU£‹Å¼O�ÓãÊiEé܈Æ}¨ì¬€íû=ðm°Hb=‚ÓÜ�÷0`�ø»=….[¦`û½Ó¬îWë%�—Ë£©ÈÆ�æ—>ä¶�‰…áÕç¡1a ZÙA§lpÏ�ÅL't5=ËÍ3me�ë¤)¬¦žˆ�…æw‰8¦ò.$šÈãk?Oló‡)Û:ѳ' —µ®¤•‹µØÌ‚AhÔ½ O€„ÉxÛ5›™Ã]ê_õ†QÖN¼vZȆô¢q�m8Û÷‘®?ÉÃ[rº¸iE>Énp=?`­"Ù+‰¯=ÅK ��à]F{Uï2¾$�í¹ÍŸàÓ¦ÿ)¸Î@.¿/®d+ …ŒÌ̆–ñœ£$IÚ¡DH( -•ê'#[fd' +•$ò}î1¢ECEE»Œ†”Rþþ¯ï›{ÏùÌ7÷­?¿{£qshÜEQ ÚÝ�»GGwŠ h_ ðÇ:„ÿn¢ÈõãYÏ5FÙÄiÄ�mgQ©Øù½Ž­yéA¯î~�DaìÛx€¾Ê¡™Û9LH€_«³˜™‹žNjaϳ¾’tÂ<ì´zbîûpL¥[óVÓ(¼ÂŽyþaN®£¸'µUlÉ‹àaµ”^lÈåÛÇbÝŒFªå\ÉýÝ1¬=Æß� ÉªN÷3Ù5ϸ�;9èê]ç6Ùã¹8sÁ”ѧɵ¸€5[϶¼·…õÞ¬doä^âúÈd2ö�¥ƒ{ö`òóx¶v�4h¬úÀB;Rÿlc´ÈÏÐUêÔu ™É4ª?ší��a�û³(£T Už¶³ �vcÌÔÖÚ¼û¢ú`šÝÛ�Kø`ï'æPÿˆþêä¯ÙˆUè#+\ÆŠG±/ÄÞNÁÄl\ûX‰üÔÓ‡ý¾M»–“ü—ÑøEø6íi$?¥G°pÁê<�uIl�ˆ­˜PYTØüy š¿Ž²šŸT…¥Gìª$Æû£ûäX(r W^­ã-Æú0Ãà±â¯K9¸éø,\%“Ëù¸0ïæZ¼^‹KÂd;M2+O‘ûX�©�¾^‡Ùhõp®ñËAâ—ïÀÅ{â1ülX%‡ zX½P›[j5ç÷ â> @¹ œ¦ÃdæõY ƒÅPùt3Ûk(N Ué~æäL&ñ©ß­éÇ´‡Ôù2—UÙî§J¥K,,4·*‘d¬ †Mv Ômó€ŠáþÖFqqöôìç4\¹k.}­·eò›gã?ŠÄË¿^C͹û ÃEó×Î- a:ˆÙËLÑVù#:ïnDõø2 #Qø":�ޝ‰ñdzqŠÍD�¢zÓ‰}Pöï…‡}¶èñŽF¯¤^¨á¿1ä+öi[ã¦S£«W¼Œ§Ì�Aìµ@þ¶#;°X”^ðÂhñ8:rã®=z–%©&ÁdÇ+ Ûã‹9¤‰+î’bV%¿'b© •Ã…Ç%à$ý»|ùv ÕX·ñGniæehœCÓü¥,ßËœ£À¢–rY§øwoÏᇲ`Zýà à eÀ~I �öÖ!©ï×@aA&U0k÷}b5Ârðﻪ?_ª˜YøVRŠ-Gô­‹–Ÿ°úèuÖTpŠíÙ'Mc~…“b¥uýÚŽ[r.bKÄùp®:Ã|¹|è©=L#æ6§$¬‚ÜÝx$.•VnPÀ@{}Úðì{›„×÷\Z–Ãóiz¨;EíF·C­c«Z»öôˆ±…oƒQ+Žý &ì�Ö8T3  ÍkñCn7X6e�së Lnâ¦8ƒäí‚á÷.†Á÷0uì0½?o˜<»-b©Ÿ9“¶¿…—sh}õ f^aý¨�‡Z@Jz;8 cå˜ ò>|�/(w¥Y*@AµITjy”µõc#®ÈQ*^bñIm°æÒÖÀ5˜‘ăpÈD\pKŸ˜pÄ'úòveÕë—θlÂ&¶;Ð¦Õæ¸Ø÷)̺Š})^ðóx"(K–²pѦm5ž,o¯ÀqµïékÓG|±Å¿IlÆæÈ_tçú ÖòXM¥Ï&*´È'‚å¬�„ï•'ù¥ÅxlZ;õ–g'á¨+6x?ÓsÞ;²}¯–Óü©!¼X‹ÄG©a‘Î\´õûÐ{ š¡‹âO0œ™ˆ35Yݦhù÷4ʧ5ãÛœó(-”Áœ¿Gàªä+Lv„/sWݧ[áû¬d~…«;k°é“ëTøA s-f㣙Á|_ì¶ýZ΀r‹>à T¢ÛhéÝ íËs,.(¶±¥Å—ùuž‰Ì/w™uþà<�êØC›z Ñ|ËwäL¦›ÊÙ±3ñ,$Oš}=)T-÷ò Ÿýz «ú„*ßæÒ»�x–¹9|8t€û5‚û´ðß²@Áï8×èK ÔMõè£ñ6ï—/»§g6c,,¦#u¼Ô¥…u°g�Ú¾<GM/°ö›~qv-6=:ÆÔG™cÅ#v­s-Mà’¨08Šž)Þ$IɽtõÑ8èþŽÒfð'Dê½²¤©Zo1ýo ¬³WËä„·¡ÍàJƒDøö†!X¢â‚ ë,Ñp›¢@iùKÜíó™ö›ùð�z }™G‘^Oz\#w^ÃZÍÅ»Rv>0¢þJ¯\ÀLp7zø¥?J2œhYUè³³FyŸú�,¥ð/ ÓpÄéw,W|=W/Žš6SÙ•¾6O ïÇ^ÈO8Í?ž¡ËðÝdÒÞ׋ÖߥÍ??²ñC~0[ùì9² žÜ¥øÉuìÐBI¶±¥“o dŸ1ÿ^wÀ½ãø›6ã(÷Öh Ða9/50c�,^º¹ž´öéÒ®ã7éÏŒ8X%+Umgå͹;Èà¦ihçÐZJÓ ¦ÊOXÿà$ºæÎÀž& Áó›J¸Ô> 77çÂÌÀ;5‘¸õKÒLeR�bFì\�{©@¸b< ë4à¤Öx¬ºà{5ÿ‘?î;´Ž¨è° Fwéæ)%^M½<x\鯻 ôBA]Mý´…µ�’ ë�É8%ôîöÈB_(ËݲÎý+0º)E=â!ög c–[šž3‡ÉÎtIr=úw’ª™rÉ)0p·g�ÁBÈ›ÕÈéãÖn9Ü»�^à ü; LΕ{ØþR±%~S2ȯH‰Bôo3n�úþ kúâeèdyŸ︃Ùç}¦”SQ”Wóì«V¢u ,³-‹b7fe�O ·Žûwí…ðìÆ!V½}n(P€cå£éÀ›˜ûk&ýMÈÃÏûµÑ¡2Ëב·¢:O¿ÃÏèÒÀÓ–³w·— iÓt¸Š“„†»øJbNíœUê}¦8? ßr˜Oãðý" Þz §\Pd^ÄWßß²îñø(â!É'“O°”\l<*äYÁRX5§Ö_,Dómtt-f›+ëøŽ)À{°u—âaá#I¼ïâfQÄç°†@qR¨WB½Òfö¯K ´v„qÇ Š ¦c>„îÏ5!¶yQ5ÕèFa“z ·¶f°1ׄ‹ «ì³°œ`ox )–\bmRÓqÙèkÌ_OI*’YÎ>L¹Îel®® …ާ‘ Rù+¡+(àÁeê-TA½Yä-¡‚ÍÞR¤»ñJ»åãúÆhš9î'pSù¨”2Ô*ŒD]±Ój–¢Úý~‹•·ò!­k3?¯xŽ4œÆäÇ'ÀS•³h,çF!ƘÕ�K÷öTbíÝb:3À1Fý‹“èÔD#2[ßÇtRob£c:JvQBp(€u,|Ž]ëmaÌ�í4²ÿ=þWÌü�»cÇ–Ÿ¬Vg=柚½Ï؉Õß Ä“£NCB× ¼õk"zÊ.$…ã^ød×a6R:Î�ɦ ƒ0Þ`ßÊáž3Ä\MK8?û}äÕ NJuIþQzß(ÜoðÔ7šYßåÈqÄz±Ô­ ˜EèX’mÀ‚–<6^¯˜ÄeUh¬ýIJ™¨ÏÊõ"±ÊÁ~'i“ÁÒÜn*Izê¯àå!&ÞÂüVSLy7·í<¸UŸÎ®Þ„wϙ҆ Ú1®–q|µïžŒÁ_ÐFîÔ¬Ú@#�|èÙ!MºÜÏô±R`“.¦ƒÚù2Ž/>À½ ©‚gëà¬Ëõ¬©6•îdó[ÔBaÒàa<|z~ãÿ™’ô—�lVùpQ âjöï¦3I‰8Åw:y,zŠ ¤LXÍ";-S MÁMÊ”Ùø8‘jT.íÒ[Bñfš)Ì9Bªœ•ͺضñIx\¦®ß[ñûs83žÆX.€Íqãhñ«°óÙBñ§‚¸GsA¬¥‹Í=ü&мg‡úBqµØE|º>‰B§½æZ}�`£¥=¹õÇÎËÀôâ{¶[d E=ZÊZÿÎÁzäX$Gv-­°áúïÜ M‰‰âd¢–C„S…ƒ w8¿š×“¥wúV[ò“šÅiüR}¼-u‹™_;Åõ­xʬzçÁßû£Iâþ|îB�ù›1XЇç½ÛxærÎÜ–‚úçÛÉ¡`‹ëûËž:Ï‚m*˜˜o VIÑÃü‹ÊPjð¯æ<4ÔpÆ—:öõ™&IOEnK]±ý¡)YÎhçäú—‚pJ(ö ËÒ2ÉsÔÖ´…F\DÛøqüB÷Œ«Z…©¹- ïË9�ej>–Ç΢ÍÊx)ayœêÉ™Xû¸’-ÈZNñ'ýGðKO¢V¡"}uœÏ¹›ÒœEQ!o"�}ÐÊ7…¥¶dßvGà³z7e,6$™ëÎX¿8’�œ¢ ”úo'e_ý÷Š"ðçUQÜ)q™µ{ØbÆÔLæ²u­ì °HÅ«÷/Ñü[¾^ስÀ×O') u°ýê1Ì´wåß]xƒv¾el�¬8«ÓCñºtô¸ä‚‡ŸƒÑ�ñ4eu 0³#“"(k3–Þ_h±<ä/øÞ‹…‡òaU�¤@;1“+&â*ÙnX¦Eò'¦²3GnÂÄ5±Ü· º³aµžœL-IüÂp¬–ϧwK‹ÙµOv�Z¤ËMÄ<ûL|p¸:>¬bÛ†çi÷ì- édÓü•Öxu¡ŒÿÞH¼^=½š„§c94ò›DE¯„ða�¼pˆàÖ Ô‘×8ˆ§•±D­JÓ`‡õ tZ|Ý"ÿçÞ(TˆFxÏÎÑÂ/n0«OŸŒ³ÿ ¹¿ŠÀjë’kMO„Ša›¹2U$¬Hôµ²Yµ ifý ?(ù‹›sè X7ìÆã&¢Ïè¹P³ÍOý]�O³òÁa[/ þxCx;à×¢BÖ±Aó¶õàÒ­!xV ö.<†µãÒèÉÆwt÷`'ŒÓ!÷Æ��½w \·“Õ¥Kºj)lß8&Þ?¿†»ös©0jª!}m\ÓtÍRzÀ�¾RéŸ1Ô”<–ýÛ“A%¦€'I£å†O¥Á)ØÚZx¸¦ÙÈÄ®³�§/0!4ƒ-œ�ëd³P¤\�©XÑÁ¾\\PÄÁ~˜SU ¢¯fãù$|Zq\ÄG�òó7L-å±…Gq�c�À�Æÿ~÷Åõù›Æöx§D‘+f‚ðùzøâ7‹4:ÛÀ\lúùÏc^C%î\Aæ#üïŽ;i¾‘DÏ’ ÷“b8û¶ Œ7ÌqÉp*©znñþ€19§$BÐi36Á_‡Øç~¶bt/�7W@µå3ÙB¡öXWƒzÛ”˜HB£Å» ¯˜¬õ Xðe)®¹8m.ijËóßáú?œNû®º`)ê¥Úáâ¦�;~÷º@‚$'à ‡ ”¶x(Çm;§@™: iâa°•“à\ý>RØ�]Xõ=ˆî¢F¼ÌB,ThÞñ$:ës½—}‡Ç'Ù]+ôšç)¨{|V°F.Ç¥­d¡g[yñf%Щ�g;vðܘ8T§HÁm2”H ™É\FR¸ ×áÔéA^¦�ï½|-ª ¶cûî`áâ…kïûàë—¸Ž)!lÕܳ`åÈì½LH:‰£¯Ã>–U l«**U|„U×uiÚù¥TÒ» è!ûUÏ®u§ÒÅÜûlÞ’HêÉøVÍEÉ»0¡—Á¥¿q$0;E¦I—ñðŒ~®búXz˜x†–ï;D†ê?¡xñ:¼4.‚Rªöq�âNcÍÝYX^² 'E«Ñ8�à!‡c²gÐÈK°%ºT¢€&V-Síy4}�µ¸Ý¤þ}ê¸xKȰvªpCc{`¤¶×¼ó ¸/þ6Ö<¯¬;àpY=NFbÅ_|c§îFú ®:>ÝG‹ÂÐoŠ-…̰�£ùåu‘tå¬ �Po…Þ´�TÿHŠ$ïü‡­*Ïøh³ Òû¸ƒVë&°qBÕLÍ ’N‰NI×L�ž[Ìdæ�ö-9Nväpޮǂ²4,wî,Ûz]Ä�çÆ÷š‘töˆê÷«0ð¹K ß§Pïïï‚ÿ’kØzé0˜w ³þ«e•J±ø‹sÁÌ ‰¨¾ó>iÏàÒ§ËaøüÐ_ŒŽw£¹›« )·LŽºîKÓ<ÛXv"bÖËmö Cª÷ .”Ôr?½­hŽüHöoU2y8ÜbÛΟ€ŸÂ+ÐJÉ›â,W€ÁòLåN"׳9UçbÎÁc|ÑÍ56v?Ê5iàèêðdêÞôV¼59Åöi�&%çšd!FK�ØÍdiˆ:²Œ/–V§ùYºTÓ­xÔÕã¶àLsÚÔp¶.ƒ“ªµôÙªð÷¦ùa0ßüß�¡Cf¼1eÈÊrKŽ”3¡‹7™Qœ(ª<“@ñ‚ +¨îí}\9Æ„œâDÙ‘y¹Å7·Rè¦$îw’KnÞ‰W7UÑx©�ôpþ;ð½3¿-Žev¦ù´²v ;¿U™êtkàc”Ü8¿?´@ù�e°ôã8|ê¥IŸŽ ÑdüŽ˜Ô²�M Þ‰6›5´ 7_G‰’"Ø¢o@7FöZ öë`h�*EÞÎ`ó£–‘Óä­¸îM:f.<5¾A£î¢_‚y¾;ï&‹‘¼Y¯@hò«½«Øî¶~ø7GÌRªòì’™BóÕ—âßÝiý3GvjãOجÙÏä‹Oãé×Îh©ªÁ\nÜà¤ò¹*9ü²â6t-6ÅÍÜðpѨO\*Q£mAH±Ìß*h€˜ß~Ùzp³9‚ßõyÓIã°´æ/h/eëïÉ�¶a<½½$ù²C‹pÉÛØ0Ü5縉â·{vôþÏL¿H‚zcßÓ©4/*õ-)/æ'-µ´‹}kP|¶+†_6EÅÂ$zxà8þ7ͽú?Ó¸‰Î,µ:�ν™J{Ø 846@,AÑç+áWÐ,ZÝõ‡%u‡€\w(�ø¬†¥¡ñè°=‚Yš•@�²}*,…·—Ѝ]q\kŠÅ×呤¶ô<ÍíYÎþŒ‰‚éƒ lcÀ$ “>Ê\¬Éê[6›~I'MúÎ]ýÞ¿蹆³ßiag¤#¾Ý‰\ýûh4Ö ×¾}Eœ×jP‡»)¡„—êƒài?±÷#HÜ/‡VW¾„16øëB8t.Фƒ…RœbØxÚžMš ËIxíJˆ³;N_ÈJe,Î)T6PÄ€ò±¤‘OZ’³PîèDš´õ?¾ãQo”ßÌèlBEË=X¯ØA3R>Aàlu*Ø› ý}™Ðá!�žG¶Ð�ÆNÊuW œÜ`#’�QÒ¦ÌÿÈiÒõÔÆ`‘{�¯7‘P¾ mN�ˆ* úÁ©#˜œJß‚¾’Quêñ÷,2KÖÒê³rø&(ËR²ÁÀn6)ÚÝ�œ +M�uí”S<ÕòX”'^²0£yp³$‘õwŒ§Ê9¬jè-—uiU­5bBB{î>Vß²€¶Gè¥Û üv|#©®Õ`š¡”“˜Ie'™žÿqò{6Ÿ6Ÿ¡Ë›&£Úº8nà¥ln(¤´¹ö´ùy#|ÈÈÆ%Ù_xßÅÞäÖt ®¬0ߘ϶‰�„ƒuS-OÌ\BÆIýò›­¼ûÚ�@xœ/*ƧSŠ�ÅÅ1Vé¾aU0y;RßË\®vö\`eápùÄ{œ'ª"Hw|È)TÄö®+yú—é§í|(aY%šÆ.e50µeYtùM4.¸nHkÔŽ3¡Žÿ5C>_Ò Í€Q¤1r'™ÏœÄ$þÊ‘´Å5fû»ˆî%Þd‘Càrr9Óû³Š&ÒþÅ£(Ó¸ 5ß¿gúNYÝo‰ªþÖ´32 Ç]mÄÝNuÌ@ü__z�÷¼„Í>Áñ|Ûòg>ôüsÅ�?> óSïU¡¼Î€ùf�¾mk‚ƒ› iÑ—3Ã:rßÙ­�¾ïÔâI:I½¬¦g¹/ûËÆvYžÐœë°’ÖNMÃIc~R“ª˜å'ß1Û nØ¿wâ°®Þä‚nŠ�Âí™8=\³⸪%¼gë Øú! „òØaui²¹;›D¼ÍÁ\ô,KÒv¦õóð¡­Ú÷™qqÛqåéSiböeÖ¥ÜC%ùS˜Š�<¼<òÊb]æ.[¹áÂÙsȰ«—–õ& 3 ʳ8l“ŽIŽ2…¿S©Or€›í.S}9à<º�õG‰›ñ€œ™•…Ïdéù½%¼6xý{Æ.‰fAYÌf¦«(ÏÕÉ'ãÒQ&X¥ÌM|û ¿‡fza´Êî Å´Ë ¬ÓT욯d¾ýŽó•ÃN.ü›å1ÿ»,?vÿk®eáIÚßhFžgDX‹¬>·¿ï.ü:I�Ó”ð¶“0½Nû*P6 FïG­äaªÎP;Å~+ƒm•HúZ¡è…Ø:æ ±ß+iö܉mÀ¸¶² ˜Tµiý ˜h?’õ˜(bZD?c A~ÛkXâÙKZegQu �‚ô'¢º¼.‹<†sfFÐmsÖáþîv«âÖ¿…¨94Î1ßé$þ½”ôVý†%/W³¬;–L©ù|‘ÛFÙ¤˜'\ýýÁiÇ0Î�S¡'‹»¡uD;9ýg�©¡r¸"¶–•|� —K^«�ò\§g ¼˜Q„•ž¯ùðÊLâsî3C ïû¨ã=�~ó¥åáï·ÍèðèøðÎÕhÅuyxã+T=õjZÞO PC#4™¬†�γiÁ†çÜà“jèÜdf©ÓúœóSÏ\·�¦ì+n`yQÙ2¹Ø–G†Áœ×9 öΚ¶l*¡J™‘øµeÙökãÜ‚~¦óü0ÝP*äÊågÒÂÕžd•Åø:›R†-•r` Á#˜=¼ÕÌ]¬e”•¨Á´›÷iéúE$׿”}�ˆ¤¹]k¹; w`òéܲõ—-ªù;0· xÜ«Ci�0°©=ñ1´ïÕ°^–” ÿŠà´×Èêéu-Ø<°Ý|If¤ v»žgøíˆd¨Á«±ÉìzF «²ôÁÑ2Û)_ó¹{�V^éγ=neØ[íû� §ã[¿µ,Es7›ù«¶¯´dA¦<®z°rŽ… m¶ó;ÏôAJ#’œn¶lYFër;`�qŽ}¿fEB¡Î&@sš§jL·ÆÄ}Æ�X•âTòÚ6gíÃKO;Ø¿£7)v–^yìâEìîqÁûDñ@¡MÔ° y®lNÎFƘzÔ\¸úñËBCª\ÚÌ‚çV3•�æXó¹�Í»ÎJ›èà vhs4V(a�ªáµ¹h.XŽ'åÈBe5ýø 2ߣÙÕsp;bÿ:ï3{…ZñåOËöÔð9#tñݦbVçΑïùâ'•à_8ã&?Á„Ä–ˆO ŸÝ.è^ŸŠ9ù‹pG´5{¹C¼ê¼{!�6"›¾‡,gú>Îøª$óÉ~Ž®qÿ‘DÇnð–j¡æÈ~ö-P’Ê¿ü`e¡ ÍûcùÒÈaŒ³ì3Aÿ½(Ûö ¢ƒÿpò7ƒèÍªÝØ²é<=ÖÅTOzêÞÃöËz±í[ñ؃`|92„^''ÃàóŒH˜€i‰ÕÜiWüæjŒ‹[ÔÈM *> †’Ü ´°çÛéÿÖvµ³E4ªiw&Ì8�GW†ìq�ÝMŠÜa ί^±˜«‹,²¦ÁÈ›{‡ß¸ª*÷u*vºPžð2½¢‹éîÚ`§jË&GÎÁI¹Vßh!:;ƒÄN²"µ"{À�}Q«dü5K.õzŸ°ß‹o5Ie3òÙØ�:ìr_Ïú«>Cú±‰è,Ùï—&Ñ FspvCÒy6}Ce*Q«Û6¨v7•Á»l]’IZ�\„Bµyñ)n­¨?›v`<´�þL^Qœ@î)T ý‚»úŸ¶»ˆöò$µÁ°{¤2îy'‹nQŠX“CÏ÷ê±¶»éÇÂJšuá4ÆôgíN£ØýEìAÂ*ßÃI¡5v:3¡Úí¸(Ñ%{Íi…²2ù&ç™Ú Å3­µJdœÄÎ7u²äþhnBcN¿Ìç[Ž©~þ+–kAòçcøZy>ðKâ«®E‡>kúö`5-½âKäªëºCñÓõDšÖö„&œ(åÞö¥ >Õ]çÛDšø³ß0÷ß˨l_*Éê%áÏñ‹ÙgÝêIÔ)MyYßqµ?[óð&‰÷v°@ÿAÌ•!³¸Ÿbiƒð ®®ßµl51óìq°ºdʽ4,Âû7„ð¯Ó¢Ê´]¿YÌ_e’سYìkø›ŸByãÛ8%ûá¬)i9ö³&õœ�Ç÷êìù¿B6Ëùfé%°iå)ðÖ)ÀÚQg¨sõ-8¢æN¶)Hûów0©òñk.Ø~š<_5 4ú›Pl}ûüÀ ü5éŽaÙÌnÿórt6ÿ6–½ÇÒ ôP-PƒU¦LÀ'î�F±iÜ ýx•v 2ÒÔÁ±+�Ë’”§&'hYºfOÌc½âqqEü} OÝEÀÚFž*ž•Óý?’pW­•\–UÁWÕh¥ÁC¼r_¢CMB´uú1¼-³ o^?įĵ�¸‚(�u=¬oF(LƸÜ*öÏ»*ëTà)C'|Ìø®[ÅdⳋíÞü %þS`.u'Ù³mAì,ÌCÕÚGøe¸{½}*iéoïÌæÿ~³Ud«ç®’B»è©‚‰Á�`j‘%�^æBÇÊN “¤¶ì×C9Ïf‹ŽµBÜÓñÁtáMk[Dwî å±ÕÜ˪"�ðWC—°`k¾«˜ÍyA¬’§=™KÉvýMTN¢…J÷˜œ|;[ì“ï¶w’Ç×Ih°J“|O&âa—,»§œ ^7¿²®Ð!²Ç��ÒÚÿÔéßô§‡K”ÇB€ž1Î;™Î ùŸÆË»³Yð·h8yXžmh߇Òñ± Wióƒ‹Ì#úܪ£fólJij¡YpúhôøÞß fë᪳.€™tûÕh<ù:$,Î3·ùQÌßl¾ Azo�й³†ö]Ŷì›ÜޱÉÔ'ôbŸî¥ð۪丅›ºÖ ?°  à:è�£óâàp¼9M0A |£Y-qøþo&–ï‚9ënÀ›zC¶;Ëc}Å1íàm6*Ó”�ÍbpÙ·…RuÁ»Q#0Ú&—¹Úz’Ë’Id-«ÏÔë ¿äwÏÉ⬀Ã0×qtþ·6WÂ¥€DŒ5^ý=‘[Sob¹uy?¿t§jõçÉ1xõó ÿzÒøê‹)et±:�œ#^cFÑ]òf;Ù!9\üíg–]�ó?rÚµitÖ{j+•P™¢:×ö=×6Ä`ŽÍXhÐ]„�8޸ų@ì¢3Îßo…cisMÚ·þ€ëY0?о-L ê˹ž #pQ€PuÜ&„ÜmwÑwÒUÊHxÁõËHGj Ié-À[�BøaJ,U/> ï눓ùÉ�FÝg&|¢ë‹ï�B…/'òôš¨Î¤÷dÀ�ž5´¡«”ŠÛäÐÏæ1îó½H+$q†m$èí,£´³§!쌥¼sÍ¥iœ»%h8ÑŽø¸aþ'PúÉQ´ô0l„-H¨$�xÀQ–“|í·RÖªw¦ºÇÑtú]0}šO’ïž�1©áÇß1eÛî„¿q½LsG©Ü�»ªÈuȉ¢nSú‹°xª®òf÷lìñìM1Q�E‡ggigG2áôwìPà[xš"ZÝêºkØß›Ù±ïy¸s§楧Yì+ÔÀ¨—3ñDì829—iî£�›ðgŸ8=;ÇcüÞXA€k•ÀP§Ï�»Å$s¢P»ü\û­Ë ®=ã_Ÿ³Æ'ùØ\+†—GÅ@Û<qVÄ ³ŠH¿ãË{ø˜?kgM×Êšp‹ˆ(“8×Ç'*Íö€úÇÙtsŒ›ùîHd’ñŸã¸LH‹Â�À‰mLûìÄj»žã °KbŽVÎ,û¸«ïŽÃ¯r ðú¹ÍÒV§6©HúÞÒÇŒ¿‘èÊgø¾4š<\ÒQjð¾ò�eí×3¹åA¿!ðS$…n:Ëí];ÈöRÇ4ikvt¸Kˆ‘‰÷øŽÍó�À-çTh¥þ&š|º€vfíÄSªõ}åYÕÛQYð⟩ŀߓkè};ã�%XÒ‡4üVœÃ9†`é°÷æ�odò+Íø;Ûj™£þ$>Õv2µV~b)L#þú°Eóh�ËinŒX?óÓ&ŒX÷•ïø™OŽJ&ü¶ø±üñÕ!8ɪ <�3ÁuÝ}ØÝwœbÖËàà•lè´î¤ÿþ½dº×S(þu2u%ðæÊ–Þ§bñou7ê4œ`�ÚUøkÓbä监 3^ ÚñÅÊ÷ð”úQq¦�dT�¬ÖáuðÛÜ"~ò' ŽFá?Ÿ!~ÿv0®àÂ-^f÷r2M¡¯G4èy÷ËC"aðl(1%žÄ죉e{éòž=`¶�atÅKå#Í֚Ǥן¡ß�7±£~…\[Ê7v~K˰�1L�OÇC­™’’6Ø&Î"3�m¸X7Ïÿ › {!ûFîùz†…>Æ…,à·x¯aQ㻿­�ÝÞ¢-°¨z¦ÿFá¢�•Ì*×’ß±0z®.&ý¿ß˜Uz7ßèÑópÍåý×ó� ×Sæ6®ïdK]�XíÅNÔ‰�‰½¦°Ýÿ1˽ÑEuŽ̨æ:tÌ`eŽo‰Ó‹ðvF§`êJ]twÔǦ¸Ñ4æq>4í0ÎBU0�é‹�Þ=à×§Š=“Xn`”Zä£�Ñ1ü-~ ¦Ñ–? 9u¹T®~ç5]�W‘}ØYæŸÿŽøêdZá>NÞŒÅquS¸†º.<3•et¤­>¿gÑ'¿ÀúØ¥à—´‰,øû ôq$}4i£««Wòó$ét :�oGªöÜA½ÊïðeÞ!Ò¼ÍJ·ê \�ÛÒ³KLlV=<¿ñ€�T#üç~ÑÂv­jÜý-cb± ÔjæÏìMeªjÑUýÚ=°{ÔFºcs�FöÍaò¯|øî× Œ‹@½Éó©j¹;þÐ9KÁ]šè7œcåúôúF†´^À=±h(wŒ%楰ÿÿûfmw•}Ã+ivhYx�=Zx*~'?üTuTJ/Âëh¤�½‹PJG•Å5±ýKâ4‡, B ZmI<|>Ž?4,g÷ìÙ §Zœ%Ë$¥-Û�¥!ó¼Áô,@Aü/¶¯üJõHà Á1Xÿ&Rð:ÁžîH¿"f¶œÄ•Îvì¬Ë°OÊa¶R ÉØå[Žò�ÞQ‘ú è”>C—# èá•Ådõæ$5”ºá˜Â·ÃsøÃĪO°=ç‘¢)ÿmÚ>½â#+T4 -V”d½ŠÎ÷Áê¹4Cj%¤ÏI§�š6¼Ø"ÈÞžFŸ3î ÷Ûœ›MÚ•õ`¡xOý÷ŒiO–Àw+ýY§Ë| ¸ª‹±ÿ4hÍ‘yPìí„S6ãõöõèÿÔ˜Œ3&TÇfN#U‰låçehÿ˜›=K’>w¿†k…?é÷@�¶üÅîXí¤î_ÛÀ¾,�¹%Æ£L™9]/Ö§Â13à?§¤NaK•‹Z¤^5¾Œ‡óÎýhè’ˆó:®Ómã'lö›c´Ú?» ;ÙãÙÇØå\ŠØò.WNECû�´–!©1Q4ëzõ-ÇÍÆô]a,üW ÓÍSð^ÝÞâÖ:¼X /Eâh¥}ÅæF�x['³«J ¨Ç6P¿…roõñë6Χw_.“®ª6.ó“§�Õ `pD‹ ›³ÏßÝXã*wØ›9 _5/Ã[#qG°²¥÷`›¶:€ITšSÐ.KTÒ³‡Cìëž“ ÝëÄh-WÍÖ¸oÀ%×»Xî©pt­�ï.éV/øø¿eu�ÃkÁ!µ& ‡1ûI× œŒêX^Äö¨]œ¾KÒhë3¨X>ƒÿîblízðô/ûé`ÂÎ}™‰¿ñR�^ìÞDj�ŸúoeQ‘íg® åPiX÷NG¨âñ–s¨»Î‘âµQêÄ$Kͽß1ñe,Íé�ÌßB']n±ëŸÒ©ôÕmø^y‘¿½b íq„„ò7£qòKzû`<–IRáÅÓ8FT3®~¡Y'蛥’åÊÑo™wööj±,Ú�éa½›=Ù¢½bôwMÿ1ë K4<—°ü¯K‹¼Q†T²–RVl<>–¶t÷­��¼9o¯!k¼Ìž}®äxÏSt뇫ž á»Rzá×ÄêçF`ÿ§ß¼hôh*ûI-å,Û1”O@ˆÛ8KÙn]zÑ©Eñõcéð‹�$ðû„²…žè:r'͈ˆ„ÜY-�pw:-|Æ|\èBž�×ù~™6m8Í<RïdW<`r™uÝŸMwÒ‘¯b’u�Å#Vl †U óÔÆC‹SàÂ` îèeãí‹È±uE47â‰ù§áÂQÄGè³/|e*Äl‡ð�+È:w˜ ©´q�,¹~¿—…ãèâ/ðÜç] ´Þr ï%pP±­,ãu´bÀK:ŒÌK#¿² ho"R~2LÍ÷ ;u0VˆOcFEjjSFÝ›ŠØªIË9Íê÷$_r›%[(£Ì³xþo•JµãÚ|V*WˆêvÓ1i¿D¼ÛŽCÕB¸k°–µm×§�³ó8GáÖdvÝ«©ùH”–†ÐìŽ.è¯jbóB7BÿI/Bµó\èÄ`ì :Ϥ_$Òµq"´^µˆé)†Òâ®tÞ²”º•»-uìñð]uºóò H¤iâÖ€¼·ôTÊÛ¯Fî=\táutjê`›­%Á÷°üò4ÄyëšñØ$]ª¹ÝŒ{ö™³}ï³9›'DŽ]qeÈdúá§sÈgz:]¿sžÍš° G´J£m˜==q=€?ÆdR‹A+¦Ÿí‚Ê"¸ãus›*…î~N씸!�î‡qëgðÛÎ㇃µ¸º¬“ÍŠ�äícu-¯4*Q•�lñìI‚lm[Øy¯— ÜÂì%SP{»4—Ûþ‹u.ÔÆEsBH$¡…º»äqÜ¿"4‰¢:¿‹ÌÜt[ov”ûè¦d‘ÔÀ�ìâФm.åš4²H�É4a¼0”JÁ ‘2Hl-Øü-´’ Žw¥Ü”`Ûï|`/~ôñÚrþ¤p£˜¾%bÒv OENÇËBhÌ¥N^&W‘U,;Îû/¯ä/&ær§ãŽÓ/+*Þ厳ì5ðý‹#4ï‡ \0ÄÈe{aÒÕ Aè¶j>¶¢ÐB®5…:>¥³=‘'!¿¥“}`åB¨ð\#¾ù9ÄäÕ~r¿Vm‚‹³–ÑïÊ4üWZ„w6Ž#ç}hY]G.5Ò°VÊ™´¼�BžNÅí2' ô©.e_¸Ã Êcq‘§èÝj9L-;†A¥ ãïV’W©®ZT�ãU­ªÏ oÅ÷y�Œ—-D…ŠVòuHŸ¨‘X¸8•έËÇ7ì?f7w‚àÏ@$NŠgºæëI£i^븃ÓÓŒ,÷¥hâP˜5|3Ô'þ#Š8ÉbÄíaüÝzŽïhÂL¨Ý7 ÷ŸwÄÛѸ­üÙ÷ sÍT�|«GЮZ}Z'Èâw ű•�51ñàÚi)J3ÖÉÒ8‰SXЬMa�žäŸ�É=9a‡�çÇSŽ[#_t?|GQË'aë[[T5—¦ٳª�­ cõÅ>4÷ýÌÚO÷ôÂYÀ:IêüªQí°òÛ§~€3›EJ1�¸æz%¾9'•ù™ê¯Yòè&5Ê¿b«0 ç.2f»>gZ¯\h³o¾ùÏ-õ¤ßWˆ¿g¸€zW¼ŸF ì< =N}9^t+V“žô=döÿ«èÌß©üº8l*2fŽÌ ¡Hqž½N¦¨4ÑL •F!*%!‘Œ’2D†D2>{�*RJQTøª¤i ÞÞ`_ëÚk]ësß?-YS‚ êÜsÀcÎ0o>¶³õòùp`ÏFä�M/ƒúŸ‘ïýÔ69Ý–1¨×Uo×ï#;Ò-QZ£•θ’šOp¥„\9¸+TsÀEçÝøäÉ>>…ÝÛ¿K^§Å›^ÃÅZ¼[�¯éLN<øïyC;¶ U�€e½ÓyùCµ¬ÿT¸p—ŒÔ„Òª6‚g"Zé2ŸqºyW#^j_/ÏÓ¾X}Vs¡#Ƒǭú�I©·ªÖU‚¢À”·º„Ì&iŒÛJ+6æÑñ&:wó.ü­�¨ñ-aEFOR•é™;Ï)«´ l¼Î¡Ç‚x<÷æ*Ö¦®'…åä´oôÖñÒº�Óì™w [P–ogÝÏ9ŠœÐÁaâllF:âepßs=ð_±<ãÍ |µ/<­G”çb¸s,}jR¾$ù·Å¨`\h@»Ë=rk¾ìï½g_éSçÒs´nc /ØMëT°påfÒúòŸûÔ_¦ÏxÜ—ó#ÈBKüW"<9röÇ™Ãˉ‰:—<(Šu‡ê°ÊWü“p‚É»O@m[öš+‘“´ÎzÇ<¬Î“Ư;:ø�T£•p�môFŸÄ:;mø â ²IZø¡Å † kÉÑK­µŸy¢x¼º�Š¡ïUM¹§KrÜD¹+w§#–NVH±_³âAv«GíØûD+d#íêîÁø'|\;‘G侪(܈’§¡ÝÑ5®ÒÇǬPÛ�E—Ûϰe^ y¢È5ˆ¥}qÇ”ºéËÚ»Ðí†Ô¬ldÚåö±AŽº£+Õ)OÁ® )[äÑ ìÏ#Ï0¿fXãÙo~8¨¯�ÓŽ;PËÈP•ã)LÛ†;§“@�Õø-à ³ÏÜ”s"®5å©V�?Ù°³�Ha¨ Y( #§>À³SÅì6ŸPLÛ¾ÛÄ IÄÉ� w»6«ÙqW,m�Q©BPœ£¿–@„v5Îv;ž ËÜÒ雡Mø×±Žh‰›sdSÈ_™ç¤jõf°?Q@þž ÒùñçÉVÂ�|þ _ ç£b¸µ~6@fº­£«^ëWËÿÛ3Ýö!䎵2šØû£³çp­ñâ}D| ƒ4^MÇíoSIÄÚvÚbfHKcÖ²Q¯)ÐÀXÚöÈ•½ù‹šíªcµ2é— '2õ«*ïÍßl¹!=KŽÁ)ذk.wj!ܶšz|¢7#Óa›5KÜúCðëÏR*g°ŒÜú‘…A˜ȚÉÕMÄiv tû€%Y‰Ìoch¾;ÏÏ;Nz‹Á¦7ÁpÍõ1�RÔ͹k 35gcO¹49£4O‚»Å=€joŸÁmî~Aõu#`®]Ã?Î1Áëu  Þ·�&……±êè~}ýÏ™s ȇ‡ÿAûô:õu=ó-¹ ÛjJQ¶� ä`† ·Ó_ÜD8Ò Júо«žõ¬;®,ˆZz¢4V²™¼5n&Ï",袷(¯æ2-–ãG~Ýs„û+´û* ÞF�é©zÉÄÏ{MrŽä“ÍÖ›`׿^Oºcè¥Ð\†3¦Îá6µ27bpN@1?ð*ó8Œ~ÂN”õÝÄü÷`€n�Ò@‡–)¸£G÷˜£oî|01®þj rrä,¹zmœùëõ‡HFþ&®AáÆ°v8ZÁÝ·§ÐÓóI FL©ùH¯Mò²ôÔУø=}£ þŠ,åõ3`ë5¶B¨OE)L-”C}«“èïoA¿·Ã½Kª¼ª–!êQ&MŒ�Ò㚇A{–7”$RFa´œ¸ïI›¿Â„w8G~avÕ…ÒIXOƒ²a—ËiÚIîƒýÑü–ôœ¬ž‘‡î‹:˜«÷k7í¤KžŒá|5OX³Ž Çù�àtW:|ÑzK|ܵqéã·°“ó33 ™ æÈP÷vThÀÀ~(llbou,¿³³ñ#÷VïùJ¿[.ÖîJt½‡êÉLÚ>T9uŸ'»PC+Ð_ÕN+‹„P@B6:TAŸ„ÕÝU‰1«ŒèéùÞÐ7$w|À5B¸½¯  ¢^íé}îa2b]“ƒILP¸)ÁK¯à½:…£¸d|Úðó…ÃÌþ>mX>1ÈÌXîÄ8²UT2c.RCâG_9¾ã¸4ž¦«º,PñØ&”º}�Ý)&M+AŠn6ž-Þ ç,Vã]3†ÛwO�ç²µ�دí¤yiÊäLsýÌûF½ß½çd_²¬‘Ç‘Ñfbñè8¸~‚îsaìÇOìæÑ$¨Ê{AíM£ .ïUšyŒ)þï0†…_„ôb!ÐY¢©9 è!P.WÓQisø2T‰lò=Ê‹‹#]Û-6 xâ2 ¤d‰}Çq»ð]Üñê3Œ&/C•A†òªÛÈúgµxìæò±é'Ý&µÖ.ÏÀº÷üR¨O_Õ„c©v)[×ÂÛc´½$›¶>—ž)�áõžž€™œ“°+æ#g½Õ™lŸ…}_ÆÉÄ僠_’³>�€œOôÛ.ÕyŸB'ΣqåútiÞHïÓDeé¢ÄÎ'ˆðÎkJë‚»L0 bªïn6Ï: O•5áÌ|/Ø#¥€¯Ž\—šiTµý)|ÐP*�º°Œz9�‚ªOÜ-ÜpJלC!ùDR#)Ám-ä—é”�t�þ: –ÿòûr³)é=ÖŽ•O›¡tsZ²~ÞäƒuÒ¨2ÿI¿±ÚÎFBg¨#dJþ\œÉ;–3¡7Á¯‰2ød›‹­P¥æDùí[@ej}é~ ý¬�\r†9z@g¶ >—†wÙ\•tú>!KÐ…�Ãuì`m$¤Ùeáв|.Q=€1êZÞaªôa!ÝjeFäõ3ϪzÈþ�R:œÏT½$~Wn²|Ëö ô”ßPRQŽnT;œì[3Áþž‰²×·‘¡Î_l^ª :H Ä€0~°XǾ”ÖÄöCs@%˜$ÄëéÞ+õ°†Ÿ ¢« ïU�†L¦c©ëÍ7Îg4Ç“©S.ãeµmµ¿Üæý««“ÉÜ–C›¹ ¨•öµÎÉv ;�‘oY»±”àÖ«!(¾\‡ø¬mf§ÌV%[£hv`�:»"[ˆC‘&zÔ®‚ ãR¸T ÒdJȹÝkP¬®‘4û9bÃþ•8PéL6:ÃÀ }Fy¼0åß,½¬›ùúíWK¢ƒßâɼ@?t“©¢îÑvï„HÊÓH¤SÂ9ÒÝÖ“GÓ×AÙ›(|lTK¦�W“XÓcèY“D̥Űüc ær‘pË,‡o¯îÔhjù«®ýÈ¡ïãfâ´ÄFøfm€‰_\ϵ0¡- ¡Æ;-_ ÖZz¡4*¤_°í”0`²‘ªHÆÿR�°èpNdóÁâÇ,—„�º¶ñs%|‹éfïù:�Ú�ól]�Úõ PáÙ qÓ–އÒ`�(|t//–”‘q ƒÜÑo¢ ¶Xá‚æÕuF–àS9•žŽÀ¤6 l0E�cÒénÝ<°½®†VïS‰ê=}èÓŸ ž/‡H‘ó§Ú‹)mÖŽ õàãò„­HŒDû¥›1òv81š!Š/èâ�³8¤ ޲0ï¬|oqÄ5>(¼˜ÌV Á©}Ÿ˜·½Ñ¨&ÊfL…—V‰´_â³nøûí6}è«�ÎVø4 š ¿Å´žs&wÞ\üëý£ÍàoOP8¿Õ¯†âר8hêxȨJu�‰ðâ·ù)ûW[ôÛ…0ÿr `Ñ81x›�aÖ¯‰Ù*MPíÓ�ãzßI÷¿÷×]ü�¼KûEË[€¼ÝSB¶|Ç*ÕéÜlLÛ*8 l“ˆ)Ï7RÉGr(å¸aÃ'Nw¡2>Ÿ:ŒÂlöùg¤"Dž ~J…�Ö¥ð�¯µžß¡É¾ÓQ“Hؽó#y=] =Nèá—\5”N…ÎÀ«Ô%3“imj;5Œ”Œ'w›™Ð¸á:¹Õw+w{ÕÍ÷j"UpcçyèñÕDædý¼ö'¾kš©OGÙÇœTK>NŒø§‘9K^AºZ>Ü»�Š­*CŒ(çûnc8,*–Á¬÷Á(Þ±—«fÓ¼ S²¼5–nç#¨ŸCæÚ}¡+‡)ù°t=]£&ƒÏÍvc´˜«ÞìN>I„‘¸®l2Wz :ûZðºâNÑŒæhkXH¯Ë àÇâé¼?= n ÔGƒ(üV­‚.«¬ay� U-¸RlÂÄ?ðÀpN)™ç}ƒ«Âñù] øñ-›f.8£¯VPŸ}ôÞÞ\�’xL0ÄÝ«•˜ÑwÛaóQk0®Ñ#²C¤àýã$g O‚óWc�¸·„3£A8wâ ?}’dÿ‘†ð‚d¥µZeæbyU&ŽŸ�Á³"Ûip»&ög{`´u7Ýws6]¼<òåñº˜ Kr÷É;�üò,(KL„ßÕáÄ lý½Poz FO ÁŒ�Ò¾§à‡!X㩄Bò4= �ÌדØ[çqû -rdø'{Zûû¿ò¡X’g&¤“S›3iØ¡}äKG9Ù™åG*’®ïw)ž=ïLìø ÎÎ3« °`ÆL_½—„7Z Â/u”÷I$.]û1"ì#™â\FÃVgÑ Q_ìŽP„0¦�ni ‚Ò Yäke.®IhÆÞYÒŒ�r,HŽeÀ‚·©´´Xˆ¬Y[ Ž«™#S3Hg{"ùnd(ö qØJV騳››É�4/œføñŽPÃu&+h%NìÄÖ˜Z;X ê7v€Îªu4ç`ÌjQüñæ�n2Þ‰_éRc9…ÖÃá°qý}‹Éw)Ÿn^ù—ßQ&sÈfé}8mÇ•ó¦;Ùr)>JEÖ籩CS¹&̼“#…‡³,ñ‰Ì%zSý qóØû:Ëèü/Š0'_9/OSÍóuÞšÎpwÕQê½ ê'¢˜îÇ#d.“‹ªéÊøÌLžÞ¯ˆ­ùî•r½ÿ†àåµaøP÷>™¿þñ3„�kpýýŽQÚVð÷3†mÝ’מfj´ó$)t�¡ùG»iCÛ"tŸ{—H´bK™Æ\×�ÿXæÛ´Ó »n.:.CCß Ã¶8ºî^2Sq«CtÉ�lÚõM•¦KwRùï—hÂþz•’×÷AñjOŒVúD¢¾ýdœOà9æVž7‡eZŸéö»¯©d´îlQ”‡ºôR¼—¿>­€Ã”Ÿ»|©Y¶o¹¡fH”—çéÉ„äU³PÑåªüÔ”¤!ªÜ+ º{o1o9”ö·/¢)Ú…˜7AJe“þÞHôŒòÅbÍ)(UʜР¥ëØ4t"2¨ìX^ËæÀÕ´é<þ9DîI:µ�¼ÞÍbdï ;¬¼ÎŽý7Ì)ÕoFçkòÝP@ž­0„½/*©øÛdr×Fš\4=G[wÏË‹kà”yµµ§¿U{@êN8éìÑ'{rî°+¶’Èy‰„ÿ”Œ‰$v?!_#( ¶“ñ’›´ßL ÕåáaJ%æJÌÙŽnF]DBΩãówPئ‡óÒçߟ?H¾ðMz>'“Í=�Á좊ÜüóLýŸj²ø“1D©„@òуŒXd=µÀìw�ü³Ê/t÷.p÷À÷†î¤8Ø“ìcÑÔUS6Ÿa}ÍäñçT'´ÿCæy£ _‰öÜ„çÿìäØ0ôìÆP�p›ŽlE™úÔ C¾Pãõf`:¿•X)‹Ã%á{t^ÙM¶¥¹…ò 7ÀÙL,ø(À½¾Æ\ñ>‹Éóu1ÂTšôùzC׆iôÈÛƒÀ3QaÙÞ:ûˆWlÉ ú¬c5!�â«ëuÿvÈ'Êå»M>F¯Éœã î³�3…8“³Õ™çu8¦íD™yîЧÞI™Ýxvpñ°×‚ò-ÇpPY�\XYÉ)ŸbLÿþͤ7~„SïSjðëmj‰DÕwQ{g ¹v<›_˜È¬#ÅÉx†ã·õÌ{Hrp;Ž_� YÒ«á²ë0=âq�î—Æ3š+0S?’Ø•î"Û›ó™É+4mŠ®ÿ*ˆë…ž@ÀŸµÐµí»vŽ3>Øo�63 ðQß)Ø“ügŒÐK|'1ýø%ÈÚ´”¶ß.&îê³`tO ˆWÏÁU6æp-56·§Áž×G¡Þ6—ÞÌË Ý?ÞP¾ƒ£äð™÷tëô²ƒ#ЧOÓ49�”âÇÅÀpÝ XGòÙzI9h±îgrnCÖÞGtÚ¡½Øl>Ÿ@¶0J{¢F¥¯vÝFš¾(–,û F¿§&3½?ЍjðZ¸¤CS$ø‰‹v8d[‹¡~ +Ùè°•Ü*Ч|[ò`ÛʵlxÕ~öŒÅì�Ó@�»�dÐb>±KųÃ÷™íïð}® q©Ô¦Ny+é�‚æÈxõiÆñÜiÌÂIWúEYûÿ·Éâêl@Iöøn4‡~Tá“fe|Ï­`·º®Á/$Aøýî㼨v$ û­ÙêV¢xaD›<­Ó˜a$×kÁýÙWÉ+_�’üàg8Ëö��¶/*ÎÀ@“µ¬·ÅqH¾P»×ï7>È ‡è‡Â¨>m19ª÷ƒìîS�éÍtÖÎXzn—:ܽˆO¼ ˜Ð0cRZËÑý§)®¿ ~ç ‰¡@ñT«B“¨àuO­†‹šœÈ`Õ÷ÊáDÞtgÑð˜qž/†Y~†�vâSRÕŠj³ˆ—ï=Úí’Ř/O ªÃ5Ìkå‡äÎ118Q> ¯ð'âI]ižv(nF×}?É;ÿP´š¬™-úr"ŒÜžh¡ƒÉøth¯ÝØMWÆáŸ|*¨“FIËf¢D¼ž5£Äë«øŒ3k´{IÉÝ FDV&¿—AHÛ;z7ì‘w‡Ï4LçŸ#lXII…2Ì8áþÎSч bþs¨¢Á-E¸l¯2$›Æƒ…P Õê Ä¥LTÑoÓ"襅D±Æ ƒéòÚ. ¯ØáŽ*4`�©È—FâuØï½ ÇÛöÓ GÒ Ò1•ž«v‡Ì¾12ÿI)åSQ'�ôÉ»w`уì¡`°à®�r×IS|ÚMÔm¼Á?S€çs÷<)2…ÆX3¦ãDtÌ'Ç#† k©Ì �#*Âæè¹ùyåRLÄ£øÑxV,þ÷"hï6Ü‘µmeV¢-O~ͽÉô‰HÒ×ÁµÔ¡¬ ·+ÀÕ;í t§|x)A¶�wO ê}y—m±Ë—ÇŽë=¯M^®O¶}Ræ-•›ƒ#ŠöX¾,Øf?X9ú_zLÇ¢€X¼|2úÞ\%£øê\ås°É\ˆxýU¤gÕÆÐÐ*^7™bXér$Šž –º/©âíB¬1yNùNmÅã/wb¬åj"ùØ�”‹¼`õª ÏX ºëÛàÞ¬Yd΂ ­Š'Öm{¨Ë¹ 8ók5:¼³…·ÇQõ® (ê>�9X¾ÛVM‰–$(®¼�âê@öbÎk(ÆG¶ÕÝÑ·m"'p †ydªO+->•»Ýß�V¯Ë]’³÷IàéÕÕ([pGæˆS½vZô2–øÊCSƒ d‰.¤Q/ç£ìe¼P‹;f³Ÿcÿ±Uð‘ouE¤|så?ŽÖF§N£é“qèm®ŒÉ Mx>DòBÊàáÑxЬk£þ‡·B¼s ôN‚Ç(8=N¬ßU‘ðR_¦íuXÚ¸: !|U.úëÌ�RWK¯ÖÕ*ò 1@á #S½ìsžYã ž' �/cP²¤ÑRêX8˜ï;C¼±Ä�wº¸aÑö«k ŒÜðÀceü\Ñ7 ½0óG'<5n¡ÓßÏ!é™/éÙ† ¢ÒqNW‚O¶?Ñ=�×3tW¿¹"#¨›Ù…„šijÂgÐÚq‡�mA<¿WÃÉ ²d¯zò¢™‘o ÈÁèwôÙ·4Ä1“àkž xCDe—cJ›�|~�ê&ÈŸkN# k@û]/ýu!Œ­U‘ Ws#árU³Rá œ´¹@n¶¯ƒa³H˜6t‚–˜k0W «p³T ŒÇµ2‰öøß‰÷øAÏ¥w÷Ñ�2ž8�/‚'¾Ù‘ûÚWŒ;MT 4ÛÓ´´…DëM ª¯1¤7„fãçÒ½ˆF`yùd-ÌHÊž#ØÊ,ĸ7p±Ä�¡Tæ¿ÝÓௗ/ÑR 6µ©±°ó£0Oè‹êÖX’•ÝâøþÀy“NDåƒsy^šKè0߬:åVº¢8÷ŒÜÁpAamãyÏ8 Ž%‡Qã¦W@5Û£6ࣈ5°a„�'JS�sC޳BÙuBßõq䈣->S¼A¤än /ï-¦ 9ÁÐñ"¬ßhÌó“w$‹Ww¡ÒLUâA³":Øš£µš¤ cˆâ“å¸"ø:=! ÄS2½‚¼ ^pò О­C­n͇¬öµÄTC…kÀ1ÃðËi¬^ƒ ‘±Ý 8vh䂞F¨‘ëG­TF.àê,ºˆ+#áµíÂÜ€íÔº÷"y¾0Rã⊠ÿ�õ�&éw1î«#4míb”¾·„wL/%–s¤5zÉÉ‹Ÿé«DUr=‹�³Ôlgѽ^˛͖p)e “&KË�x„h[õ#çجA]Çw�êã p #žÆ¼L†ñ`Tpc*â ïP8j�Lå]Ê�D‹%å´þ?9̼¸š.½�Ë•|ñèá|ò9ð8­ŒÚŒ6ŠhÑ;îÍׇAðÀ|tý¡»oQ¯;|Ü9ßlHùò>Ž” ?iúÍô¹Šµvrðwç0Yó‹áJAnPØ"ø`ÓGïéM§Í[Zñ±Q7µL€—pR&%y°£‰¤m«�âDS\;­OgXƒ õÇfkyx綪>Óž5õ€·ŸÁÄ2úž¦"GÓ -FÅ)£ýŠùûÉŽip#—²›q²ro€[ŽTv&Îl|‰sÌl±/c'N³|@�έ�¯´ ôG,Þ:½’{ÒüÓ²í!„]k¦ÇKÕÀÛ¢ˆ}°ìçõÃ\ø¹- îx‰ã’¶¸D¸�>y·¦Z3T¥ ÷Ÿ�oAÇ­é8žu‹f'å°Å ‡`ãƒ×t áØØ^<ãa‡µü"ä¾÷KôÎðÇ•ïá¸Ñ8n¹ÔK%ò` Cˆ�És&$l’†€0nµ“€Èþb¨œ=‡ûG¯†~þ“ŒÙCðêÌÔ( h—Ê�_¯aéM¢Â:Àßêõä»S6Ú¾ï!ñû9E"ŸÈ³³a ,Ä3÷f5¶³n®~„&Èeb~�Úga°9g \ê9…& 7ÐA×­LŠò{°Ë9 DZíá'´tWä.ú; WÖ¥’©£ Wâ{5JC¯ƒ7 ¯û ÷IÖ 5TMd꓎6eôíΡ‡œÒðOúŒáD„Lå¦wÏ`4WDÀâüdã­�)HÛ Š1|©j{ü%EƒX ê¯Ü¨nÉ>’ï,Íý×Mð‚Ú¹ÙÂ作¹<õ·^ÅCNJ¬yš"©¿ äÜ^ò9e {Êp…±�>3Vé¯çÄ?‡žÐu`ªCö‡ë£•…ðu£ú±0š Ë~Œ�Ÿ99ðî‡ »7ʼթÆ-¶žT.ö9œ1 �ÜÀ?Dw,ª ¬Â’Ì](âÌMjñD^_:kç:BØ@Caê_ùÈþÜv€UZ¾ìØ,?놼{aõ‡­xsf*j]Ë¢JWnŸª¼UýzðFG—ž¿,•ó3ÉÑ ;ërkVƒÃau44壖gncÄ쬮õZRôû=Òd—ƒÑ>®ö—³TÞT”—›œ€+¤º ?ÿ\]Õâ8\ÕG ¯R±K¯P4íz<|‡ö vcõõKøjÖ.T[ OêÎAÜ–§Ð|>‘®ß'‚“ðÔØð¿A'›å¡—wf,YgÀÕÇBáe×TÞ[§÷ôC¸7í=;�êûM,4Éî¡vB^P_쌪¬®±Ñdúú㘒Wà¢iËÃæëuä°Ä^Tî{Áö]<-2Úb|ˆ€J04Æ”Q;°ˆŠ(„Az¢*ê45àÒû—ᦌ>vzóÁ3Anô|8ølk]Æ× fY÷C2WEÚüúÈñ®9�˜Ï^Œ›ÂþÝ`Àãÿ> gzñ~ík¸þpk×úåq‰×vð�Þ€Y[5ðÃ]]ªdW€eR¡á 9*DÉæÛ=¸Ë-ÚÂںݱTÜy�¶ðHÝùÙtöØGX_õ óȱÏÔé«8÷›�ZI£Øcú=—ˆõ]ÁZ°T÷a>\ÕyI&Wì@ ûßäÐýdÜ*ÑFV¼Ÿê Ë©J’ Y¶¨?Ï�¦D¯Bøß1üì«…±yíô�&ïS‚2< Kƒ?O ཎ« "�'¿^Ü®„>©v²õ½5&ïãì(–à�9¨—\¿“ÙëÄÏÂÞî `jóŇT¸Iÿ¼¶I–./« Kg°h_#+�Œ_¸Câ|iÞ«0qtà]BµtPœï ¯ÚuáÂÍ(ø¶[2*¯“ó©éÄøáa¦§y?þÕWä^Žõ„/ ÓàÅ6I¼5Ƹ=†#Qá� Ut¹H¤“w£ÒÊ—°9× âãê±j\zyÁ\w¨»þ�—øÇÙ¡•<´_�ô®L5Úô¶1®®³ÑŸƒàÕþ›„)î":K%è;ýÐhÓ#=�•´ðŸ+žÑ¥Ò÷.3ççÐ?Š (´‹Òó3.ÁÀ©ö}E Ùs;žòÞ \ùnˆ›ºŸ>.ß„aí—ñc Eã¾ ZÕÇOÑ"à#2­0×g¼g#@îéT,ôQw0A©?Àwg1¨äîÇUG_‘ •íZ—aÆ£f–óP6 ª’~Ó“ðX»—êÆ´ã¾¿~x÷S5FΉÆÄÜMxR÷U‡�˜T–�‰²H6[|!3üYz­$�lµª'W�¾Àš_edÇ«7ô�Å‘CEÿ\£ˆÌ+”†1sÞ^ù20~vûe¹¶;Ñ­eùûvÙ äØXÓÿPK-!£¼ÿÿÿÿÿÿÿÿ arr_6.npy€Ð¶vœ—÷?×ßûÇÍŒ²wedoed¼žçRF¤’DH4„TFËÞ;¡"ÉHJ¼žçÒFiêÝFJC‘´héÓ÷_øžßιÝÎíÜ®s»×ãþÈ_î¾l¥'/OÏ^�€M;7†ëبé0�æ:†j:�¡á»ÂýB6„†lú¿óE~Á;7ý;ß¹Ù/lÓ¿½®¥¥¡Ú¼¹¦æz†jûÕþ_KT7C–ê~íÂˬ6_>űéÀ* ¢ÿŸF\ß[9±›Ã3î|ºÒÎÆ¿Á@‹±™É‹÷C|ÛOi¡“¢¹pk¶(ûÈ5ŸÑð¹?›Ž’¯ Læ3êIÆk?ø sN%óó�,æöNd36% ÏßDaÍ,ôçË¢bîô?õmðñ]"áÿhA žëÂÍQàð§9ZÛ ‡Ÿ¡©ÅŒ_¶5‰ L‚Hq%¨¿Ô VÍ«!)~%>�hÇÝûrÐFN¾£4|ˆ¼cYÞQ¬J6¤•²Ø{Àù”“16æ&½·l¦œãAµX%(‰GŽÿ)<&¹0?›‰š JÇšé½Ò.øÚa‡•i Óñ‹|lóÂÜ!0t™îOµqþ‹ÈÃcHÜ}£êÜj=£¯¬âÅ]±÷@hþX.z�ýËžË÷ ÎêÓ�#‰Jl õºWF¤ï)CÀA˜‘^…5kkp~Y<‹Ø ]§RqâÜòhõà9*@Õ,ÉI,v·€+»2Øâ7B0÷‹)^hŽ€Ô^q2Ô+�ë°‘c€ËÔËá�Þ2É“0_jP?ÊÄD³°ka>µÜñ¨µ6P«…óÐ%"Vén£#‹){û#aS¥à¦tmE�3lh+ž[Jb Pjš1ñv%Êãdµ­ ¸l'F&yÄåE<æþ~„ÿ‘U ò—z½¤¯Íh2®-sÇÏ‘píÙZ«˜Ç–ÖûR­IsH.�'wüd‰PŽ;]³ç+'ràò—;°&0ƒpyA¶í/úŸìiªµ"¼Ó·ÁõÜsŒw‚ D¹a�QñÝqœÜVÇ‹½=8ªí6]'ÈQ;|X)J„ÃPËÊfè‚aÎaÆ¥ž—ÚH. ×Ó¬ðTö=Ù!dÏØéÞ¥GòûHÕa ”20Äw#wéºÎT|å~Þ*•€C]#Ã÷LÿJÁãÓµl¿èt^" ·?a@Ä%¸¡VɽŸWC^ùᘷ k–…¿_êâ«%�Ú>Dftªa™Å)¬X ýí¡èV] #]s©»x 3‚åÖê—¾ãÑãIÐpÀÕ"),J—a²33ÜÞí¨°ÖÒ6ÈðwÖ×IZÒ4þ*Ôƒ¸žö}žµ§¯²ß½øÀ8bº¬§;wÐdË4,}ðŽü�~²õÄØZ»åߘAR?­Þ'»Cð5Z<Ìø´4%axD7Xõß$l‚sàëCT¹ðŽ,Y}:‡YÎá (gúÞ/+ܶ<]‘Íýb„"’ïÈýÝ øÈY¢iDÒPü|j'D½ÐÀÂçMtûËÛtLUV¥ §Ð6tÉ…Ž §…0Z—Ž~«²q¹ðnX¹'̾öjy4м[’¶rÊ˰ò­/ªòc“Êz¼ÒRG´–_Ä„òj´Œî¡ƒZ!რ˜f¶aVÉj�t‹¾Ðí¢¹YU üá Qú“Œ³2!³Í‘´�ÃG®û ñ–¥­¢±ðL $_µïÒzù�ø’s­Bî²äÛIì¯&X+“„ >¸“7á3ñâ½B¬�f4Ûn ƒµMáTa¼ ¿ñ0f/‘5w*¤áW.ÐÌØµÄó@Q˜ú [#y:=x‰-/ÏA×CâÖà„~Éñ$;¡l_+Âó¬s$ô©†ª&Ûó,I^å{ªuÛ�Ú-\W´mcåø`´°‰.¨9E ¾D²{ÞÊ’; c¤�S†¿¶17ªŠ1`Â?ô³ìŸ]c¸{Án„Ühþ1<ÂïR­íeØsÒí*íZ|Àß‹—NïE×óÇaëèk*U™‹oCa$ÏŒ>¹÷,Î¥ñ¢mX²ü mpLǸdm°É}†sËO‘Jµ&úèl;•g>Ó­-t m§\iˆY¢u‹ìéeHÖp&áþuÁŸ®É ‡ƒ°*ÒŒžb†‰Óåýü‰èKÒÿ3¸6ù,y¢­N�¨¡^2]2x“z¼‹ÄßÒúÈö*Ðë_;è‚}yP½KÛÖ±õ‰ù�£»lüþ—µ|{…ˆž¨‘IËP^ôŽ®3P‚c£íäƒÈ,<rœ¶�»àZ ì×¹M=¤×°/l!zSJïz÷cæ52°óÑHì(€k‡§Á½§âäÒW”Û°ãÝrÀʾ�Uá<[]’÷1•t ÈÀŽP%È\ÝÉ8ÜT¢šûv£�«/¦¿��;©Ø'<[‰³ro>Ä›*PÁW‹ ¤>�tN æd6í5GãË–xA, î5“ºYÁäf‡uÇþˆ°äÞYÚf÷”x= B_'Ot½OŒ�ÁÍ\�sìd+&1AÞI1uÙœ*4O·­lŸI*–IàT îyø¤ÞKãÛ{•ì‚ÉL:4CZ—V‚dãOæË¦>r # ̵ŒmÅgõ¬õh{#<Faó­µðèÑôrB<ÜHè§{1º’£s®_¦Ú/¢TÒºÛɉ{ãŽüq44ý»W®æí· ÃËpìŠ xw³ð%À†~jàÅÍñ\ ô¦T=QxÕgZŸ#¬Z ʽëádm~ñ—¡'~·¯É ;.ÞCçX�OVa:³OBì¬r2¹k·Ö&,*Žcò yôUÝÅh�.‚VEI ?·ƒQÜê¸ñ6jñÒž‹°Ûè$Qù$ƒáìX³ý"JŒÑò‡½ ·ŠaÇNãœù`ií@?w¹�’Ý:ºðuž(òÈ\ ‹\ÌèÂñµð|£À4\·Z’kôÓ˜ òaGÞQ £ëÕ$ñGHíV5„›´žëF⼤Bˆ'§úéãq+|Uê '¦£¼Yj¤Ÿç™�év+ô,h‚Ñøpr.H’N²LÓ–ì;ð…dÁYÜ]æO›àªrEØa¶ú·3‡ Oé"ÕŽGS˜}ëJ‘3–� �ÿæçËâ<ËîN¬€€z{ðI±ÄÎ=8í¦ÎÉ!m» µå.ÍH,EƒlØ‘Q IBŸÉgãp’Ÿ9Æ,œû�¼âë ³EãéÇÜA˜ÿw3=-ʯE¯`ü�…P»«‡šÝ¹ƒÍ kþ½3BvܦÄõ,CD´2a~oÆŠ?j�ôB:î�q ;Ÿß`�nÀ«ú0MçñËÛ=*óAd0–ðÏð�ƒU†hñ»„Õ²¨cs6Ä‘M¶‰xÆ,W4¾ /÷|"Wu<ÐBÿ }-`«Ÿñ‹îL¡açÖ@>�ë~ý<ôÍÒ…ûôñkeù²3AXLˆÈúµAÌë—°mƒ=~*Ø#Õr´äÞ2¸0,.3¬!ô›î¹Ž«ÂcÆó,ª½t1XÚÖ]6ƒ[ëãÛ\ùdAʸ�HË-'�~¬€÷»�PC�·ïOÆw?µ‰Wˆ©mKØyÔˆ¢cqLè#\rø, SgÞ†+C°#2ZÛXX;GfÏê@µ'*�C÷|©aŽEfAÚÓG$©³œNX£Y”,ô;¨Á¬1øy…îèhŽ“#“/܉oÐpÏÜŒuL‘ÏZŸÌÇ*<Ÿa3Xu,OÕ…inæxòîÔr?�ëfFàê¿7iÿ?}dÅ W/>–zõÀZcp�Lƒ…0·Ð‚|ü��O‹<ÉÜ·3©ãü‚¥×Qõ}–kü«µ>½VE™ BœççLzä¾�™ YH{x„^3$ËÆPMÓôÿÝáûy Þ êÁW_‘5Ä‚©8¬ã-${ô}ÀoAs؉Ôï¼F%*hHK,MA;H˜à¢RÎqj)åŽö´A¬®ãÒ“³ô E7ªWã‰Qè,+nW–\cg�káóÕBä{TF�„’±»ã'ÙÎôS³6g\ÂÝ„µ‹þõˆ0 ^É”ðqfj#u±ûL£qÌ?­¸F–ÿg�þ×ÊÁšë*Ó:èW[¦je?ÛÜìˆÐ,AB±“eéJme4²/ƒC+1Œ§–Ï!wöí¡}v«¡úÍ-“‡ñ›Lð׉&êý €Z¿|ˆ,Ö3w�nànŸp�–Ö)ϱ#¿ÊùpÁžƒô¸ÌDñi>È¥YÒå¾�Чنþ”á sˆþ*FWTòÓÎm‡À·E„ȪÆÀ~•·6‚¸MG”ôLE�in »ÇîFÌ&r#oi·Ÿ >ŸJ„¸rS’ø6˜#}ÄV.;ƒ!¦;![ „Œ,"÷‚™rW5øi|B\Y—ÊPt4ƒ©ß®4¹e c+æÍÐdÉêß}ÔTCÆ>_#ÓŸŒÁ–g x;ëáP#{ØBÓ W’Â’zÿxþ·>Îå=ÆÊ˜7â®”ìHnBo°Í3†Pô`„ Í5�íO�Óõ£:X°ƒ �¢Ÿ‘«’ûpwílŒ ¤·à4Ùúº€$¤ŸD×ǸÃYžÛ7OIƒðœJ¸}·Ž‹”0î?®PµÃŽøn@—oɺPÂm5iøhVoàéî1Îð+Ö2_žU˜ ØÚ :½åì-[Ï&kX�žŸ#œ¤Í+ 5•3o_EåEs@1ð9�g·z Aé—$¨8'¿YïŽß½téäÕdrxC,*ø¹£¼íJäbù¯‹DX¥›NµÛÀÏSïàÍh"�{m9©;~€º(_"�î!¸g´“Ú1À¼†-¸÷­"¼øó‹.«ì`ʃØëPeŒ»‚YµöÔnÓr0õöÇ ÐbÙTÉ2KxpQ 8sݺ…±,xC’¾Ô2£ïµ�ë�šÛë°âIð\µ!.…k@ip;Ãém§^3Wѹb{ÉT�cʽJÈ;_Ö~Ž^ÌàÑoÜ5ÿþà.IXÝM[UÑýô=tú—5¾]í&]Ú1°Øt VhÇ"'Xu·ì$[çv±zêþT%>–yðìùì3L¤×#œ…øRgÖõ\Æ45 Û#¸†ƒ±;!“6þë“9Ì^RšèaÍUì1¿2ÂÏg6}ãÌZOÓ ï²nßàHG!9ÿÆÃUÓi�"°¶§†ˆ8RÁ¿2uãO1Da ]~-‡Ž7EbË:q"°Õ­–-$:Ÿláý“™xÚþ5éè¡GzW¢ÇÝ}è�§ÛX?ÔŒ’1Eþ$æ1Øår�”ɯ¡:·”qÓRy8éÑË&Öº‚Ãým´û‹íšZĸ_ý@/¶ž$wU�aô”MÒµ‚yMçáÿ/úµ,ú$�°Ö¥žj]OF4¬Ðñg"œ »mÓwù(£Þ§FS9áh¼~%-=æ‡ Œ¯Ûí;°\µä/î'%«}±æœlœH̯'ë¾44 Z7u³±Ø.Ÿ\A“•Íh®Œ7}�…C*üàR­ ißKØ„¡Lâ«”‚í/f¢{œ4Ù³ÚNMHƒEP&éñCLÒ2‹+†³õ ’›2 Vå.ø�ö‰]a<ã_ÓÀ_š4G5€$œ ){æâ±btõô×ß*˜um.l[,Dâ;0ˆ3�ܸüg`ô„þ~˨‹}`_Ž‹ÂÄx/Ù¥ÿ�CŸµÑƒóž’Øõ ¨wå m)I ¿§ê0f — jŒ3Ï»ÓÉ/•$xë�‚ç‰4òý΃k-pö^úkG™z± YsÔÐJb6x»A¸Àl¬¿D‰ xžzL¾HEòÑX²„€½Ì÷†Ypß E£ü°ÓS�NieÃRY:·² ¼Êl™âÚ5wQS¶š¸zrèaKI`óFèxKÿ ‰Ù6ÈWÓ¶ºÅŒâÑ%ôcz?™“? óÒ=³*Ñàa �!ûTÞ3ÄÔDš<ù1«CdYÜ×÷¡N=LÊ|:©@úŽ8ÁÊ1Aäý-Šó¿Ôâ‘ °¬§ŸRèö‡âÌæ ÝÐò|)í+Ï��§óh -"‡ÄwAò1Uä.¦7'–±· ñ|I/YÊiÆ‹QF.Ï®Uµxž ŸW¿c³|-¡eÔ›Þì ÃÿL�Ðs@ŸÕZaŽê TpJ!«£Ëh®³"ú�û¢Èï]xñ«íÓäüxúžúFm¡½&=¬�© í[ò»÷§¯Ö8• ´òÉ®ÜgtëÍ^f…n‰1.�MwÈig4Ÿ}›m gÎGÅ»§>¨Qøšµd¦ãTˆ>1;@÷ ý¦w–G£a+Щ˹`%t n‘T‰uÐ,H9ã,éÃEeÕé §d+o?g­jLpóÞsŒÌZ)N£n#q­´Å x~¦3í#�º’É:°I°ã»’Ô5²­]ÆÔ¬;ˆs=rÐeõq²D¸™x^ªdÛ4 ÕÆFh]¸_FĶß]8LTêSèÊÍp>;œ'o0¶†d*ÕDÌÅ�3”Ù5œ4:¯ø#¾ÿNÆn«ab”ó>KœwγùÈî˜KTg`„®g¯”E¢hG=Ø›Å2Êw„!°”—h¾ Ý)ið´-ÅZqhÖ%"U÷¨™¡)FµLÐ'5dGè)ÀÛƒ�Neïé CmkiD}" ͸�h(�Y+½H„—$Ì"èÿ‰M±ÜFÙï+¶±%|…ð™W‘]ü±…ÜT.#JÉôþ§wdÁÇ%˜ÿ›“ôbòø{@¡åth ®�÷âaÏPð tÇQ·¹K@+X '•»èÉ}±ìAþT »”y,¼ˆ }nLôV<¾ Ø%„ð~:£0�l2ˆÕÙcÝ–y踨‰Dãu(hÞÇJýÉŽ¶)�*œsÎ<£¥×; «XƒÝê_Èöì4%gN5Yƒdˆ6ÀÅ”¥d«ò3Êyõ/¿mŸ"' j�-�ƒûs„`«Ui}0ÄÜ”�†)ÞøhÑ ·hR¹¼gì«÷Dmámß:JHˆ2,~¥…}åNpdl€Yó«šm;~Jl„·õå�f®Š[^¥n^pÕ²!RtÃ[®„ôMÂr'Ì‹#x²ž{vŸî�NcùôðÊiItòºÂ=ž¹‰Î^øŠßž‹Ì½*6ùÇwjm™DÏ-Y¢¢ÿÒå‘DèŸâ%—S �Ï7 þ|ß@æßxÏÞ´z�cu+ÑÂKsÞQüاœ ²…yôï$m][E=�ã�¡[äìH¤ž>„J÷# áLŠËÆâ·:K\äå NÝÛiœÉjž>¾Ú�œs =dÙHö5ƒ2átÖæ5%ºÕ›a^ÉQªØê -Ec¨ÿa×-Q á±™DIñ)Ûÿ™®ñ'Å�E”'°‡ü'¡Œù&+ð*G‚ ¤®§gE–Ñó3ÃaŸ~ ]cÏÅ/’hµ·®t£ß_Yâ×q¬ãás3z ^ZÚÍ1ÉøÒa1<ð†™³Ôjýæ•Ç Ð4Ã?†Æ¸g�?]ußFº‰Þr"øµK¨¦¡±t߬@²Óè2õH–„ÑYlåú,ÐX„’E´‘{ƒµhædÖËQÇ¢úÖa0N0uïRrVÁ{); �{…•²K`<Ùž=rm¨£~�ÓŠÏš´ñ�ÕÛ¹žð'¬Dyø]…˜ݚç`…U7ü÷å½÷†K—èdƒxÔì$Ñäú©w4QÍkãÉk•-`ÇÛH§ 7пz™Ò¡5¸-íýРjð�ò|Y„WÚvL �&-àúóA2ka']¦ÜDÒ�ÿ#Á<<8øZŽß$_[K™�§ëÕ—W±^Û‰¯p‡±õB|ãZD}/¹âUˆÑ/… s1ÌXjÃôëG3«^ld˜£G_Á+Zº»‹ŽéŒ‘ê  ×¤C'}]1sÁ :Ýe üˆòÆ+×ꨅ7—Ü5ÿȄޟšFcT§0•,„µè&o€%¥��2³ƒyð<…_ÐÑEØT0ÈýÐXDBÖš�Æ1z}o†+}f½ƒ ð`Œø×þ"fÚ ,ÐÄë[l˜e+á€û}¬·Âcf& Sï@® ]¢–…�x‘óŠ|ûR Ño¶âDŒ0lŸuLšC΄#Jš³ªw$qéÛ<¸GŒµ><ÛøO3‹è’U¬á”mËœç"&X=…9àb &òéÑY'!ÿM1áIVÃû!Ù(ØÆƒÚ/‹H@“‰¾yÈÁ£dcXT¼›FÞ‘@¹[ä}g½ø÷ k-¦‚¡Žû¡2ÝŸþ×) Ñ3À‚ŽÉ-rD§éi¸¡‰MN6häomH¯ /«`õgi \#�Ï.O� ‘��U 'þ™ªf$ÓO“ÈñE˜“t‘Ü�^Q~ï™[nÓqâ¶[¹WÝ/§C|×<º¬l”ž�’Á™ê ØV¦€ö­È!v.Ù<®È èx@wIMZμLŸv1y6y܃3�Ù) ΢ (÷�&�æ0ÃvõÐWl åò…píûLÔ3|Á>X~‰Ù¬å€k¹J¤d;KÍ–�…›ÌiS¾7Þ“C·}Ê\õDIRgÔLÊʵQ¿«‰öT˜ÃÚ‘lŠO Y3»ý§Íj,ßnMê¦[Òf…ÅÔ’O ®•Õ3ï3ÚlI3`uŠ:àÏØ#ûÛ¦}ß…ÿ-ïcß ‰J²sl:Jhâ…‚z' ´»›$íÞÂFÙÐR=þöuÐÔ qÊ[i�‡›À²`kV\! –:p=£ëé®'ØÜ²Äúç…coˆï€Þ¯|Ên>gŒF èžÂ�±>r\l!ÝPw‚�5Aé³¾Ì2¤;o!Û»y:4,¸G%pÐúiúNGø¦‘¨µñ$èzU¿²ƒME ÙS–\|lCMe¾0>ËDÐþlPï°)E|(ˆ¿ÜsP¥¼�ø$?%¹JÙ\ý+—Hê§Ê}¿Ù&øÄe:5ç Dž£."Ñô­W4#î}›¾Ò'ŽÕ ɵ¨gœw™bîü’T±ÔsÐ�¼?­ãa—#ðö¢±FtÏ{IýÚ.Rëþ ¢;+ØЉ�¢q­Õžþ‚i\¨êo!�a·èþóÝìWÇ.:óu„^¶GÇè£ð4EŸ/R‚eŸf¢‹ýq`äÅðÁñ™PX³¹sêa–dž»ßM×ë™àõ›Õ„ס=%7Œ÷QIž5H„Á~Ås9ä‘8vƒKkÉM…W¤¢´™VÆg�†Õ'èÓw'8ó¬ ‰¨b&Ѷ5Ä_ÚøÒŽ‡Û¿²75 ÑnÛ!:,¸ó¿hÐÏõ÷Yž°xrÌg1q —‡`3Ø]¢ö�±äQ%} }= ž'«0ýñ^ð¼~~ǃړ(›¸MDÀšš”7Ñß3Ùw7ÒÀÊ>M ÎTICÑeúŒ}s™ù·Ó þËÜéË^ÌýâD?ÔhÿŠédúôMàoº•xÌmeœÚo�²®>d}¦!S‚�>l?4L’Ê‹ñGc'u]}ÌÓó‰Á¯Õðifu½û�U4HÄPä^íQGou]:š? Ö|;Åü]‘B?/5�ÝY’<>Hßž¶eTî‹Ð¶x ®bˆ%J˜ý cˆˆúKZ­ÄO¥3Èæ"?/.Õ‘Žlcô)œCoôÙAKïJÎÿÖdîHÇ€�¶Ù¥ëVÒÅ�&Ð7¹ž›ò¢[Õ;bÉ|"û‚ÇiKÇ-’½@‘½?PÈ�½iŠJ^çpìb~°ˆŽ|åÁ«g i¨Ø²ýÁ´7­œUUͧ»Œý©’él¼¥gLaKÒSæNŸ8æÎ<ˆšƒq褦`+=ßž¦ŸØˆ¬a �W†ýUB 0âvu½dã mryÑ98ø²»ý€Œ'sÈ¢ &uüPj÷{*¹ô#-SNa» :Hè`¾‰Ð‰ôVôܽ� : ªäVâh™Cÿ¸Í‚åÉ1DùÖyZοÚ›äÐçNJôÞ£ÂBÙ˜?&†Ç�¬éj}qˆ5/êï�æºqpæÎ$Ý|Q Ç_ÓÈ=-¤LJ‰­Xx�X�s½ÿ DSõ- ¹B&³*IÎÖ°œçǦÑý+6cÊ‹v(äMd7R`V=ˆÅ72Ò´RZŸ j(`}Ÿ€íФ²å[ÕË7èãªVµÞ¯¨¸Sµõ‰Ãp|Þ}öXiÒÏ.Ö=IZêjÉ‘/|È¿׃%Df—£_Ôþ*z�ßÕ-è_g-ðeXH±Ñãy™$ÏÑ .z¸ã—àÔy,B5/�ÒÞØ2xR£A÷,öÅ�^¯‰‘c$^wª%�-ÄðÊæóôóÔ ª0èDm_UÑwê%R°Ï´枺ÂîçÓÆ9—£ÏåN:ëÛB2pQ�ñï’Ä”P3Úvm†­›¾áõ3… �c‘7ë$tÞi`¥å»@~În,X“ g­ëéŸ@p°9‚9ÉÚtãRôZgÏ�hŽ�$„þÔ I[ `mð:¶[ñû¦Åbó›Çô@xIvË >7“hR„"ÚÉ ³Nh)3˜¿t:F¶Kv/=HöPsb|åŧypT(‰•ÜâMî¾ ‹|¡q $¯ÜC³˜ösPt»ŒÌðÁ¶‰0²’22W©�£ÜësÅïž~¸xÖyü2ÏíœÖ‘}–|XH¬P>½Õ¤r§©ÖwƒÆÞx˜÷î< ECd£V ›×FÖ­ƒŠ [ü>ò”t¾ú—­\N�Ï6�™·½ça±Ÿ4t8DáÒÈm}uR¼‡á¯9ûC ¨¾Ñ­Y3g]±9É_Nží2fRß±Mî^¸ìc&¤½Ø– ™!P™½ˆL¸V¡Xà(µIûERÒYõ¿¬š°A‡÷©‹Dé�Šÿfðð=!èß½—ìpõcæm÷eTKc1*稩UÓ‡¿P¯Èæ í…‚ÍM°áÔ •‰ËÁ»±½ANpÎ>ÄTi˽ø‡L3¼E•7Ä?Áç´Tö£¯ÿ›Äto…¥ ¦á'–-ˆ*‚;G/P�E¾øµx)¹ôP¡#W¤‡F÷¦d»�¥ ⪜ü—ô—Ý%FAj £v!Fö€‚ŒTy—pš[ÃŽ fþþôkŒÓøÜ t/tÇóƒû‰£ør'ywäÁ¬ ÿ� aþe„íÁTÚ4–Î+æôzÂŒñ[@§Ý0L„¾ßÈÂDc<®à‡ýå€΀¨W|Tv'Eû©ìSãŽZu|¿vVaª*²mŒ´~°¦MÏHÙ»›$±­økv\ö~ Äâ…d¡½ê-Èfí«à«V>Ûl@'øí.j¦J2i`ôR™þx'ÎhÈÍ…%Rv°HÆNÜЇÉ6o�…’µ=Ø“o„q·Þ“À!ümÞÃ̳�$sÞP¹Ëc$ï®4®èl‚I'SòrQ¾êç ±3égÑ‹­ k# gâgix°!®/Äy_�£Õx2QÈ£·^a–·Ž“È-¾œÎMê�ªÕM ±·S®á<þ8¬Žê¥žÄÃÕM³C¡ôãaÒùû2�PëFѦ<Š·yíEË`ì°#*œڷr4t æ×œB{›p#Êjæ¬áõ ø>fO.lHÿL|¸�­Q.ߨ|o×�ŠgSþágT/°6žÖQªû[WÃ�3 pÇ¢RX1»}âñÓxçé¼ÀwK Ž?csZëé5Ú~w#/@^�ŸœUÛâ°£å™Õ\�g]’(×v£¨ÞhsúÆtëbiŒ—?Æ*Ç´ùØÏ@¥5‹ðôó&t>ù&Jnâ>qy̬o5£··n…¼o54¶”y=¥ ’Š« 9v:,Ô�Á壸8ã1N®KÅ÷zBtÇ ×í¶d�æ Ø¾™Ú î· °+{’^Xb�ÓÍ iÉ«4ZVùžNN%Ó‘›I‡—:ï~ «VcØÖ·D²éûnÕòx9Í8{ˆê…èÂEÅ@bõl¬6•ÀÖ!]2î–„ìÝu´t¹'ßü89L ÑËd½q PùDQéÝ ”6–�¥g›Ðåµ÷Ì[s²h¾1êŸ ¡­©äœ@ýÉû�è$ÈáûªfÌ»TÁ¾«áƒ§b§I¾’ݯÆ�Ô¶€Ô/n„8~ ô¬¨å$ÆjA¬˜=Lú Ó€qO”|�ŒÆ<;�SÝÛ&7ç:ÙT°�HÞ`Úo^a|©8lž“ 5§èì·¹pèô Øà̇á?gAårqÆ\ê,h<�^.­lå½�pCz&ˆŸ>ù­Ôæ0?LüMøöo½à|5Ïo†D“1bÿê Ñ#Y0Ä' §K„@Ö#B.Ç⹫Î4p?<ª¶¥Ñë‰U—+>[� fƒ�J úݸE½âÄ€Wñ=ûË=$íÂ@¿3�ý¶Óƒ.ª»BxäcàÈô®l$? ¦Ær>ŒxÒüƒ)ì�LAä;y>zŒã ª1÷2܇*½Q;¸˜HyGnÝÓ‘ó¨ÑBdx0d×aFõª°;µ!¤¡;X8æžè}¨”Ä&YC—‡sa2D«>ÑÓ̉;ŸïæbOš(HmÏG™Yedóc+ºçÚ xÍf]†�zÿ‘óñ"0Ü„×0îÝ~ôÕ•¯T·§‘¨¤,eÅû~££ú<Œ– …à ˜ºìZÇø1Ô ›ð°Ö¸óð :_µ”æ3ˆ˜ä&Ô7!“6ôªx EMpjïg¢òZQr¦¸ŒTÎL o{|@'{5:6PîIñè`+¥ðà‡!æýª¶�÷™*ô€˜)/*e+M�z^К¯nŒoô9RïK9%«0`/ØQ7ÞGäë“ð[ŸAnè=�éÉÓpí!*x÷gO¬{}–ŒžÎÂSÛ\Q¬¡‚Ý#'eâ¦òT ïα–‡=°íy;ɳ{Æ´~Í$·«QŒ§¿6°¿W’¤®«ÂMÎ×aŽ©e‘¬šÖ ç·’SQñx¸|mI F·/ê? -ó‚™›MȱL%»wÈ —ª&e$�ª˜ üd @kW+²`gLˆ2ßöðvŒŽhÁûaä�²—ÛŒ1•rTv¤‚]õ_Œ#rÚ¡�ST‡�@¸W7L§W·WQÕ²îSóXuz÷ÓY8p§šj O@êò0�øÜOòûÓÑ;ë?�¿&‰«žùÁ—+¿É…ý¶°l>ÉölçÁå¢ ¨¹é1öï¶¼0¢v�Ti?`ô6Ú€é½í$ù�0þ�þEtf‹�‡3ÀÓìߤŠiI´«š'Нª² ÎƇ]…Ÿ}^0‹/›ÌíŸe“\ësKé‡�CÔ^$ÖÙAâ9ÖèP­$ 6KÑ’ÆåpJp'æÍ~F]dßЭŠÀë{%y—'È ?ßÌî˜y•ÜÜ"Aïì›�§fØ:ë=s#q?«Ñ2A„¬ö�ƒJ ñ\ÊâÝ-Ðu{?¨ƒýtôÆ—PïYœÜ–eèþ�ûýWI“¦ºPЛô…&¼ðµ#QáÈ«ë]ÌšÃH$˜Zi6�¸Gü$oUþ°‹«Saÿü³TSúseÂ–Ø D�å.Û©ý}iŒTpËt>=LLòjI§ah¨õ1k/¥ÑàGáëÛ'ÌŠ•eÐóy#| ™¿óç"t‹3 P0FìÆœ82ôé�‰1'÷]ÌOñ@láoÆ…š"8 ,ÝÌqÀ*o]"/¢r±‘¸î6/N ¯§¥ ¶n nÄáa,ªlq€XD\"‹½Qr¶6�Âàɘ&8þðÇþûȱ&Ù�ª@Ï ”UÊȺõÊðä¦'^zBé�¤cà­o Š&î$zçgܱIvÉ®"JÂ3Ðk2–Îxþ‚u]I'å(�k rãžõóAk¼Ÿžú5Lfûl†ž>\wÝkæ_¦‘“ ÄäåLü€tûŒ»8Dzž†,Æo#Ùñ óÀœc‰«:qÑõ¿äÉ~E¶�ç3lŽS€3�D:ÝN‡€Hy¦¾© üŒ"¶W30g#8;1í:—(�å*Øš*„UŠ;qË?î2ÿ} ã[æOøJ¾™Ø§v•úWõÃn«!Ü1^µºÏ0°IfI›£ÉðgR-àŽnɸû”>íþIdãq»Øœ¯ÓIbê>¢é’¥øYª µPé£nÿ8¶ ö,Mà„ôwBÛ™‡ìe'ô´çíØr>D?•�gŒ4çá0}Z¤‹»ŒÝéâ»Ó˜ÃR±0_. on�ƒ]5�\Š[µÓçBZèr<óÖç-Ã%^ñ„¿]‚Ì;m‡>•‡È>‰›0¿§ Ì ¾“åÁB8ãøeæLö_R�� ¡šá�~áýþQ_­úÉ®k žç'at™ hÌ!Û\�ð›èܼ“•{,ˆÏ7àS­rs*‚*Z/Ás¹èw¤‚D>÷ý÷_)ôà`ŽŽf‚¿QžZŠyµ"t¿ƒˆ¿�é'MŒŸi7_²›HTTÓ3£¬�ªÙ?3—4:/ ?´ÉØá+8Ãk÷䂊¢”÷zô t†Éôv—å¥"©h&÷‡ìÉ߯Xox‡{´Q´¼›¬LŠÅW /ˆ­ÿedüìðƳrV4d’.Љƒ{¦¿ÈÄOYØ~á4úKnןL@¶‰mýa0�• ¥&æpø‘#‘NO‚2—‘’5Åÿ4¡Ìñ¼B›½ %E WÿýEšÂ6À¤^ú¼h#\âÇ쿼¶sR‚é<žFjÏœÆ]]žìæ©Wìº[‹ýP(4ºÞ+‘ñ390\ÞM÷Ì£w>ß%]c{!iû)¼àøfoVçpêðdý9ZÑZqý=ôtj$êmS¡‰_& Î-m'î£x]2��Ož)ìIDå€Jì¾EÓ­•Ø/ïÛJ·Ñ˜gàà`* Òr§ÞF!tº1õ�öÂý{Óáĵ½�“{Âo­ÅwÑÊTmósúèc)ý#ÛÁ­ÎqV�×6 àYÇO ŸÇÂ9’Dw¼¬`¼®Ì†tz6w3,T9ó)£,%`A?¦þ«s�ì]› s»·¢ÿêûÜ‹ˆ òt¨k¼£Õ88òî!9䬌ù˯#7¾ŸÝ£:ÆáD×cˆÛ%òÛÓÄ/©uq¤ øNþa�ABe:®áÇ;{Ð<¨°ïQ8)yæ)w|)ÿźîr£c™g`lˆbñ2^o�M�öX›¿ŸæLm‚o]×±}v6óHÙþÕ~ˆvÖG˜òTAÛŠJ9œüž9&%dïŽ|öMŠ,Þ)HZooÁà×{éî´2â©�ï..ÆK¿]Q~x+™üò‹^“jÛ㚘‰2’H òuå-â¨ô%VÌ›ª'ð市í2·Í�ý«§–fƒ€A}´ø «ýÙšŸ+¢úê§Ì#¶–ü8'FþþÉ£ºî¸fš$ú&ñ 9²hp É�Ò´} $vöhZ}„šªÁO®b‡¯|#µ¾ßÉŽÈs Ü$ª5±&õ-9lI„J²×¯ÈÚÆ;Aì�4ÒŽçè6:„é+EIÜj#Ø ˜»k-¨ú¿9wuS-ìVµÆ³•b°¦©É‡dúTû,õ«ø„rÚ¼A#ÿü·&Ÿ¿)ÞDÃŒªÕ�øn)ÿóï¶}°ò—4ðG®�¥KÊ`èn6TÄùâŽ"#�<¼~õNað!?Ê=±‹ô)žcº‡g±÷Ôr1lö)ú4;‰u•=ˆÇ·–ÀU®4~2—ì|-�ó” š‘Dég—v‡‚âK–›v ˜©ÒÖ¢KÅ`çÉsPX~—x«FШ1/|³ÔÞW#º�EeÏ7Ñ•Ï}ñGQ-l{Ÿ1ayèÔ:ì=Î�ì%÷0:׈Œé¦æž¿Ù;{©îíb2ªr¢ç�’øî²Ç~œ¬ÐžüiËpÌ!ÙE†-*¤Ûõ×a¦…ÊgŽTf²‡YÕF"~:‘¿¬ç:’�]s¨õ%üh2NÎÿ÷›:[ÈBß§ûpôI)\²ñ†U¥£$7Ý›t�(€É´pòÍ]žã—ršì’1ðåbÈ�w¿Ç§‚ŠëKr÷\+íÑ»@'?̆Ë3‡©ùÆM°màµU§?¢F GËmh9yZ›1ó¨SñUÂÂ6²ÐIi‹çÿsd® ¼”ùþ^¶°úh™4œ"v•ømÉõ“‰ha~ž}­l�—¶_á¼Øû•®{cUZÃô‘ß¼÷Æ�ïûqp›6ø§“y«ê1©¥ü¹M°^ÒNë a’½¢�[bïàD[lÛª]‡ j� 0+ÿi[/†‡'1Ỏf®÷#aþ>,›¾–ÊœxF/¾X†éeӡȯ–HN´2{ÍòéÂU|¶ûª•!Þm?±.ïøb°–I|½”žYèk\’™dï»p@#Û|­ÉóágT¹º‹lúæ‚cjŽðýž½!ROiž¢ Î’ŸMgX,i"ûÍÕlÿÛ±ïëÇщ—¨uß™x4-Ƈ§þ³)‹¾Gbw�b§Õ=¥÷dáâۛļÌ~ØÅ¢Rß!HMš"ʦ¡´îE˜=¯†TIñ³b'Kÿù{Ö¿^I&k¤µ±nƒ‘ÚuœìKéïk‘Oý:¾¾O¦ª¿Ré¿Ngö%ñxœ‡�§p•ÍŒRbíÍùÐܪ ãW“Dì_)�3.éÀï‰8U܃ŠUàÐXyx̽LÁ±á#7þï<ºÏÈfãì±%kŸª�Í‚!4[i€Ì08̽×z•]=\Û‡Í�UÏg¤760ÅI`;ÿ0îs… �ÔÔ!œ­þÒŸ7º‰óVeäù4&+TQ¢:�§®b¦Š5œÕâ³ýpç0ÙôÒ ÙÜ3´J`!š©‡#äBî•9²¡ådÁ߃øzn-LÿðˆñÀYr¡½¸‚̾yŠëz&ÏìYD»Û('a@ÅoæÁ Óa|M{÷W<#�BØÙÒFÆfpÞ)Ï‚4¢'<‡a͵¼wŽíT?ˆ¢S5ø? ÍÃë÷ ÀöJf‘!”HT*ïç¥%-)Ò�ŠŒñmGÈ̲“BFdEÞÏsP •JEh(Mi§R¿~ÃsÎ}îûºžº{åèð+�]˜8�Þžÿ ƚƤ�' O�oœ‚�Ðl9ÄäÃ¥, 5g°‹Çƒ]ª=X�ž‰Õ5Ô(}ˆ½Ç´žÇã5£Ï¬ÿÎNZ!­Z·rÿy"qš%=?ε†Ñ¹ñ¨«Ú5 6,[‹¶~ª´j´'_xÄVÆï¡'ÖâœéLqå"2´2 Óå|@F) ¬‹¡=ãïã¸1{)[3ˆf/‚ÇÆb¸8«Ì7Ö±—ò>ljnlíñû«Ùê¯ÛÛ;V¢‘Å%þó2QZnò�eþ¬FÝœ(ÐÿêM£~ªÐOß}8éo,PªBQox=-ùbì)]T8�OÃSmØ­±r´)µ_M™KÓûîáÜÆtˆÆ6¸2w+{DÉL#ùÓZ’É4SñqŠ|]”‰®/`3ÒšÕþShun�P¿§/ÎMå‡í]O‹¾tïúpN=I;) /¯èágÎt€§=ux¸Ô�úVϧOnè�Y0®l5À1g·3ñõó@ÏÍ“ ïp™¡Ô¤cÇW�Ò¦Yuãù!Uüaw;r6È® �¬dQ*uñã½—IÁüÐùØ+\‚wÇ nÆ®ƒ€? …û³°ýz!—!ÞÄgmÝE§Ç^†¶¼õð×¢Œ|Œ �n¥þo"°I$…ú&×É)ìãÊ:rÙ›ÖØ¶z/lø6Ï�NùÆxœÔb·²`³É ò^-I‚_}ðU*}ãÜ0ýË2úÖ‡¿u•ðø¹JªÜ³ÌÞk÷œˆºÚYÅ£"þ°¡+<Üõ•ìÆuáÆ›¿˜M„1ù>�Âõ—&bY¯;¥½:‡n:ÉtKã;Ó2Ì…Û2ò–W4Õé]vÉXdâ/E;ö³I«#ùM®ù ]}…M>õ‘ízxŠm •�äíìÚcjU}ÂFú&â«z—§ü{%!±[¯8å _Ö4îZ½L¤"éL^Nšt3¹¨.G¶ªv 8ýðàGÞŒ-W�1'<…™�ŠaîCïy]SÆ¿l¤Ýé|‰�bݘyéÌõÕT´q²a¯ç±c:Œ ÿƒ¬4þ8´´ðM�ê,üGe׿F[ûÔú1 ^ü€ù{e¨@mJ ’ÁP3©¨Å¢ž:¨’: 1r‘d£W„�ÚÿÑh•!¨=Vþ"ÉuòS‘ž„/÷[ÀO«R{¼ÿvW^À[cõiéwtÎäš6÷AéÕRÒ{?§<0äâÏ×P·ÂdöZ"”ýç» —%DPŠër¦3Ú¼Ö|S/wÆ/ÊÞŠGç¿�¹}9Ù4÷R:¿W Ç:…âÐ1êk0%Ó ùpã¢(¡¸é€ãý+˜}V'©xyÓ¹½tбšòžðGþŒÅç°�„±ùï~ÔýzþÈ,G…s x‘Æ �|AvüYÑ:Vºs$jxײ[× Æpr5…òU§pÃ^K´‰…Û¹4ìýûž^•lb%"ÁøÐ§‚"l^³™’Apo¤…�lDeöñs<±ðÚ”Œ�‹mýg˜ÊŽP®d»¢e‚x<]ù–÷Ž�Å67”±Ž�f,ï÷ákÒM0½Z‘ ]ô-»4#ÙB�%,ô UµPð@ŠV>�£3G_ŠèT»z¤m(çd„òÔòú§@¨{ZŒ‹q«þ]&srÄ>þºÕb6ìÓŒ²Œƒ-GgáîI½ìÇ͵¤ûs€ýŽÔ£W]÷ø–+pØ““(°ÑÂ_3!õ©:U¡ÀLE½ƒøë›ÑÕgÜMk¤)Ii˜ùîÜì¤ç÷7’h\w¬Ånw/Öè¡E/=ù©7‚P;hm´ŸM"»ªÈåüz6Ód�I ¿Ààk:8þŽ~c¶oeš›eÁxþUîǦT^ú„$þgy �P)¼„¾O#nW6ÚH$“GF7¹„ç]·Nc99IÌàE!ùž Õc`Óþ½hÏO¥®ÏQðR¿‚M”6¤w.fQ:Eô�ÝYsÐ{.Š�Vgᨛ›Á}K+´—=bƒ¦RÕü‰½�F®æ/í¨+Äÿ<©ÁÇ‹úÊW°Ì>Ij_Þ%˜WP ÓÛ’YôãûðÅ®”íÉ|RZÿîLõkæö& w­Ñ¦^H„T=Ž-˳gÙcɧ©ž‰þ†'»ñÒ¼é48f"]êò€dïölH gË<¦ê�qø 'ƒ¿j�Å^çAîm09´{až³6\Zó€%¶u“ 4Ó0DøÈÚŸ©7î§îÕoÀ¬ùl}:”ÖDzޭYß¡I¤"B/o“Åigö:xø&ö³ÔØ`М…AÎ8üTöl†,hd׬éQÖúê(OÂö·|CÄO&~'û¾‹#÷9�¯?°•M'²%øë"ÆÜ�yÙ˜:¹Ž™êë² ~gXÆòŨWx‚¤¦œÆÑËRjï©æCKu1‹N|~¦S†B æ—N£5/h`F›Ö1‹;�haÕZJOñÇÞã pÂÃây»¾^hÌ=ŒîÇ^eQµÛ9ª(Ô é¿GÂÜcaƒe*hv2%v ã«`Š~(¤hÛ¯àse-ÒÃy¬Ts%.ÿ£�ï©ãÔ+�•SñBI,½µd9“rYïš4¯s=œðäØû=XqĆÆ}ׄ§{ éóëTaʪÁž•~P(óÂ(¢ÝÕôË›Ãû{¢¹ðYãpñ±ÙøV6†OÒ$©hZt-O†ÔsjꎴúL4=û¼i¶Ó¸e$ºÙçñ¯ ‡QZóUPˆ{M‡bÉ9yaD{LÏÇGïƒÙ†_|VËwÎûޝ†— Òè ܱ©‚-è‘Æ= Ætëz%ÔøÎEûITóñ<ó¿¯3rUáo^(_šÅX07î7#%qE*³/€ êñ‚‡)¶’G×q­ aÔÍÊíÆáüÞ÷ìüжÛëS]´OÐù`&×Ï÷ðâº`ÜÍ"(lJvׇ‘Ïàäs¶˜Iœ˜�ò&Ç©Ç “¶Tö³Ÿƒ·a¢ùW £¡x d+ZM’ÃUûêáð–t65£…+´Nƒán`Šq%4Åñ¬øé Þ—Ç~nÃËX ùZûÄ‘]¯b¹Ëç�–¡ßZ¿jÇ}ùνP72˜)o„ðØ±¬Fä7îeJèE㟠 —xžeœ‡ÌH8Ó.ŸÚå�?˜Ä‰®[FgãÍQﶬõIÇYM­Üw‘Ѝº ½R®è?g,Eíí`·jmé«2µp ¼U¤M·Jãÿ8ŠÍÂòö…Á¼§è™”AËPþY�ëtNf›ç·`wÌQêËù×v7¹¶×PõtŠpeZ ;˜Œùa'„w7�ÆEYØ�›‹x½—£)}ÉW¬° Dù’3ýó[â¾m#²Â£2L¼¹Œ–fzÀ”Ueì®AúŠ;àÞ—º˜? A=ú((I±!É8ýÇ>�פlñ¯ÌqQ4¯¦Hí뻡yÛ]Á4A(ÉEP@Ï#¡<޼ֻÑÖ6à¿U“Ú4ËXÁ4•—â¶šv·¡‡ß¢ÙÌÄõÌIüV>ÎÔÆ'þRgê*Q¬Ï&•ò¦u†F¾Â‚#Úä ituË)Áy¿ ¤šCI[‡Ó%W $Ö³‹ˆXe«:¼?Þ:O»´fÒ½?{¨^ÎŽ¦h.¦Ñ…®Læçu¶¢í?¼{ï?¦»d—µïÊ¿“'ÉYǵ ô…Ó˜¢Î=,1¡s6±Ki ”v'ƒó øT3�nMćów�Ú¤PöóÐ8M�ÄTÛLá}­pl†€� »8û,OƒÔ¬cè²™(¥›Vû@Ï9 ·ß�gWû“†�+”]"nÕÛ4fœÔˆÏŒÄñ“é¶Ðþ¼˜G}³ŒP_y&S™$J©Ì•¶{Tpç�Sh®l7Sµö¢…+;™å°LR´¯bS7·²1ŠH [Í®äPSöTìÖ΀K?KðöŽqtªÇ´òQ|Ü7¶e™íï…g¯ÉB½Ì~èÏÊcu× ÈØÿ*wmv=�3àëÂÂ+Ý„U½�µ¾ Á#Ö�©‰~äöç%Ó‡s±ðÂg0ÏfGæ:°Š, ú|ñÊ.Ù,e©J‘òªê x;õ/Ë»e†g_”²YË}ñõáiµg�õ!Þ)„NÏ\�ÖPAd"~vIÚBEŠÙòšö‰âñS;Ð?p1­ ‰£7˜Ñ¡�vطƒsË`Äyu¬ Å–ƒH™º²-›÷g'ÿ¹<‚ÂWÝdÏÛì¨?[ž5]˃çàâN÷—à©S$>e-:kL&0—gçp„ÍqtºK§×·Q˜sº7Óê,uÔÄj¼<-•ç(á´¶Ö86t†àó™xJu{¯›óøg›áêi#šâ{³Þ×ÓÞ1°á’{Ù¡‡{K�âüV0™Î|3Q> ÚY~�‰?ùë¬O¹Ï«ãl%ä(7ΟÆ?,áßÚ;s¼uô]‡:1G ìN¯–�ÈÞîf{Fdaþ�{,ÅDÃr¥ø\nHŽ1¦¤9×wlnç6Ÿ� ÑƒP{·jNù\ »Ý-¹Ý‰'±¹$�­¶—Ì8ÇÚvÐnu.ó­2þ�šÎ|5äøŒ}¹´<5.ÁÑa*´Où,®íŠ s÷eH¿û*þ{ò˜x†>øÎ¦»CvDÎSIæÂXZßÎñ>$úŒ®°Õj*8a�86µ¾aAë 86�/x|>¼Uüj…sç…ƒBÿIÁ%óRv<}á¿ý›Ì}Þ쌇"‚H^F�ú¢ážÉ?>­ÐÅWgÊøÊˆMÜþÛV|¥­»Pdª$5ê+1®,ÐÂÅÊš6‡ŠA÷ÝÔ´ÇÛ ·Á%úÄ«§RÊŒ�¬8ó2nh½ˆåbo©ai>) îÃ%ñvvkê Ì�Ãq¾cQÌO„´n´ptc-�;;•¯ ÿytÛzÆZD �vzíÝ€fS˜£›×Ôp~ǺCí“Ôð,T—ÊἕbôsN.¯ÌŸU£él¨=.{?�¼Pe×dþ}ÈQÔ«œ%¼²R‚VO ` ¶™tÒq4/=¦?g� Áž?G(ò¹3N°T·: |ÅêFÏâcGŸçÍMÒñRu “H¢„U%¼¢åHˆÒ¸…‹žÓÙbz˜kV>¡�Žê8g�‘U>²Õ�\k¯�}¥ƒ3ïdÑëeØï�!×nY¸=I¦¥!ttÖJÒµ>ÇÖ<¶¶³u¸byl®ßH 1Ü[·>Г|¤)´æa#wNæ8È÷à¡j©:îigU› úçÍñT×5.úq0ë_œ‚_6eØ�Ú…¿pòE1ýéüΦS&nœƒÊÒ÷ Yá§3S6í¨„HÕŸtL!ŒìïÖp{´×BuÅ8<`9ž>�á¹jî!—&V 93cñÞëjO_Åúvv!“�ƒžVé³UŒt(\¬�Œ›C™jˆá¿û6‡^L˜ÓðÙ¿ÊŠK…=n›¨Â?Ò†þ)>,Ðä:ÛªÚŽ–û¨¢òÝi<(8®­‡+ãÎô§'Q,©Ÿ5æ‡á§ÁyÈßËÛNÒP‹ [œÁ‰¼“¶TOŸ�yEä7a œùô}R�QÚ¶³°´®�ù�O�Šl}�í•"|¬C•g¼¨áw,ë3ÎaJWyð'%|„5³EñM|½Ûj‹¿CÇÆ:¶Ë_º7ó-aâój ïé1óø§ ¶r5íù§üC3è·ƒ8Öý ¥}ªé`{é ªågàe›–kúàv~¬L?>Œ¥³‰[QâC.6ô– í�çfßr`Vë�0ó|;å>ŒË ˜ J�­,j¤™ýXDマ³EÏÆÃåÃ]à"ìâr5’©eúXt<£ÊŸOU(¦I ,r–0“½çÐÝ]NX—r‘FÒu>Þ7ùÉWcpÀFzþw˜°q?á˜õ)AËyäk†SMõTVþ%/Ïa½Z$#·ˆŒ.»s¢ý h„Ýj|±PgÊIÒ`©»s!eÍ'0¿-¹�ÄR°gâZ<3{~-Èü°_u) ¿tfR³ýiÒ݇í�–4ÇA–^=ÇÔD¤¨ËG ÷Y¤ÃÃã›°²;~ÄŽÁ[½…üÔ_ópMß «ß‚£ &°M» úsP&: ùj;Ò’ £�LŠDÅw0A‡¥ehÐÛ+óÑ® s>Á¦$]”úãÈ=ÛH‹Ï-#OœZJC?a¾qœ[¥ÝÃ%ÙÌ^]ötÁI~¥I,Ñ|Âæ}÷dÓ|ð·­¬e¾F ¿î�KœõQ®ÏœùuØ_YLkv€•)³àóˆ}0R³&Î߯MQ/¢†ïÁuËn rY„#¨’¾þ¬†Ç7B(|— [WôÆ ] [ÖПQ·¹Ú Ü« Oè³ËSÎ(e»v´€½Ù¥Jý&?X°dŸ@sï'îæd¬}ëJÜÅ.ZÄÕp§+-þ³Lâ{ š¨qñ3¶øcfÎ¥/…zÄ/Ñ¡x'2O?ˆ“å àø3ƒl{Âo÷+Çßöjt¿Z»„<úÍÎeøQì2 LxG6”â½ß~ Þu¬õD„-#s»~áôœìáW?Ø3™U £TÉ.Óàžn†;5Æ·š±Õï�F‰²|uRjL"ÁÂnzÕz6×è`ŽM&¯ìÖ oulYÞ“�ÜßçÁ,#}ÅÎÁ™ž§àqõ~]ãT µ™D³Ó‡ ºžfá¡­ãÙ’'Õì{úUšñ*˜þz‚õ.›IÊY3èÜ·Ü÷=•úe"ø2Ífz”F¶ºÑµa­?ÁäðáÆLð{PDêéù0àv ê× �™Ü2ôîÖ‡m1W9Í67f�Êø{v":¸Üc†fÊlë¡Í!aŒç� w–ïÄEA½à7Ý:ûD-·mƒ�$Ð1ç8Üûƒë´ Ä÷"et"¨•bVŸ…uOV`‹¾m�c­oü°Jáº`Ç(-òã$ëbÞ:áÈ”˜Ð‡+[£ñKA)Ô/ˆÆR{Ml{�]ò„�o¾0þà&zž:�½ºxÕòˆ»’AowDÒâš=`�ÆïSUb-ÚÊÌ0`ˆu% §k+Ωg.%úo³uÑÒžuCk¯ Ë™YJiš•P«»D(Ÿ“�å‹ÁÂì"yKÄsuYäoN>G1¡Z §jÅ3I5ü3T�æ2þ$Y¡ ]ÓáHë _«€�7ŒÁ­%ØA‰;|üJe#°ÍµÇëŸ Ç'ßXŸn5*{RXÐ^¬WšMêÌÍu;éü�ï^+@<jJsYLG—0÷o•UÄ1­�'pÒžZöÅü¨}ò€CÉç(öÛp´�d4)Šf®©m,6@ 2«]°çž;­˜Êœ=-¹\ç58߯Ÿø²lOÐþOì4˜SÊDªVÁ^ IVv, E°H0¯:ã‚/ÿqr Òlup'eþxCÿ3„©g{ Ð)…ï,“� …¹ìêœælDhµwúZçbEÄD0ý`E3!Ü(üg[UØ_¥N^+twø‚”í,yRJ̹�Au+Pez,åܳÅûÖ¬9_/<×Y �c†ðÖ?|4¢€I³�p:²D`*扑E–ÔÚ‘CÞfŽ»Á´j[(Ë÷ ~Ô[H7èÃÚaV£DËj¡Å?Œ.ßg&-ø*VÜòïiy¶éôQ6½@× gÀ^56ëc^›rR0"BÞR¾y�¡;Kà`àH Z�ÿ5Í`no_‚ÍK{¬U…¢ƒcÙ‡C ëŽ>dc¿šÓ$®�Õ^J#u¼¦LÛæÍNy†àȦ¢OåS¨/c™µª�É<_Å{>¤_ÅÏqË�"C·Ïc��«ã=Ånvø±'î–ZI­;ð²v¯ì€¶iÅB£�²ôqF<{^ÚH-Ê& —¡Gók½htv2Ñ·DI—þt¿`Wœ·pbÏÂ0­¨�¥·1æðX´î\¦¢7£±zV,Ì—ŒdIù�üùåÑôwŒÎ}7Šr»‰íðvEãx]Ümç(<5¼E»2£R?L¬Ë§a×ö¢i€*F¯Š¥‡4OÎ@á¾ñªôrÛ7÷j,É_æÐµÌ &�Je¿ÿ �•[N07¥ X‚ëeFÔݳŸ¤WvY4½ß‰Ý71/ñªl ©í†øCX‚Y7#nGbáWînw,»¢�·�dëÒËþÂÚ¤FPÔoi!&Fúâ§èHÅH^ûÂcx×¹θ-¥7É-lYÕsœâÿ—ýœº=Ó'R·v$Îù¦/?‚ ›AøY4žS9´ ã=…ü�ò4Ñÿ-h\Ã_ÿƒqZÖ´Óá- ªbÐŽe˜ýñ6[³ÁNV¯Ûy)4¾2S4úá뀀~Ã]fU ¸] 3BÛ9sA#¿pC+“ç;¸›5pq‚/](Q¦íã™]Ûš¶I–R�5¹ñmü_«µ¸DY#¼Ó˜AgÊVN·¯W¢Ô3Ëä^5Ô PÄøi °wúZAm� �T"·¹øãä/0Þ õFQ…ñ)Ú§>÷íŠÇ¬†×ìÇšnŠò~£¶ecÏ—6ºöAÈn®Žûy ä~¾fzÏR´x2LëK4]ÏÀAŸ<6à?¶\€¹ŽÃaA`8 o§«NTSñfßxÒwÈ¥H¶›æ«èãæ„Iø¾k'3„ÐW®MÇ“‘�ˆ{Ýò †4[Èg3½ü{i½ÇCÝÓáÝ“`ÌêŸ�‘ÉÓ)Ú¼’Ëö ¡Zk¸·óB©*r·/Í„ä…vX¥í‰Çº«©’Í¢S;;@ÁTšr¾HÒ…ùÐuê1Ý3X@ƯY¨8)ÒY¿7|uÆÿÿ¡àd–�Câ1°·­„žŽ¹†¥o`BôO޳�LE9õì@¿–0²àM÷›ÍöÛ�KSS¹q¥q-zFjaXÅ ó½v“µ*fR<è£~Ê Á}Ícè@[n ðyŽDÝÄçjtemßtïK†ˆéñä5â;b•ȯùÒ…9O¹Î3³):P d5ûþÅÙ�hdúqÌ­:@ïÃâýF=T•“¥{å`~QˆÌŠû*¹ÏdŸF‹[zLX‡eʉÜPÒ(,<¸,¦HÒÓOÑ̾<�¶É™RìÖp\å »‡‚ÈY”ZÂOÌØ‚íÍþP?à…É]æà±YÔ2À>˜�‰4N=fF¹“ ]‡å‚J 4ÎÖ6¢wÊ_ù©R`!÷ t®Ì'“9j¼šÏfvžÇû¡²ô2¨ˆÅ=ŸHýGb(r¶X¶Ó¸)gyͦïPóÓL'Qùh[a¢E7¤>€žÙ�j¯£Ô�Fô1ò�Há}†�Åké†*{÷©€¾ªò‘žÑìdy�lM5Je8aúiÒ9sïÜ=�aµ°E})o>Í Ïê…³åÆÚüÁ£ù좤7�§�ID#€»Uy `ØÚ¢ªÉš,´©|òu\0æ$%' 4ÛAîòlÖ’ÎBÂa°l,É·ÂßË~’eÍqºûpzÃMÊÿ‹AÒ:rQ §Æú¶G.˜$Þía Ú¬©gJ&ζ G•kàjåëtf…]¢� µx;ì|h@5ýÆTwn {ÝI |;üœ# =�ÒÝ8 x¿£�îç•/Y0÷¼:Öi5Z¨ûCŠ’/h€øŸ ¼ÝµŸÍ7­ÃoncÐt@Ý#â)kÄ�i•§¼§•t)2�KîÛ@¦«ï2ÑéXáT ^fòPpò»ZôNð­i$IÌŸ„‰‚¤I‘ÞŽ²v¬ûÅT:Ñ5‡i·4ê秱Àç$,Wɧf]l©c=Üïwb©=|Ê÷#h9C‘×ëlÅoÖfØÿ��w¸*T{´ šÊÙõ?‡©Ä²‰SÞiD“NÛ@JB)Äó!LÚbG §¦b»}m/»ˆ*ÿ™PÅÎô%ä'«Ù¨Œ—¾ò­V+qÉÆ@R Ç\K!|±è‚Jã|´~ÕȾÜÉä^|¦Ç'¢ÕÚÕ¸õÛWÒ|àLæïüYTd[¿UΘ©¡™¡ðë¶,«A©.Qw�Ð$à;zø^siñZÚ7&»mÅðcÏeðØr•ýöÎÄ#hwÂ+”'…5]œ³Øq²½k@­Ë�r*mÜÙæ;LkÊjÁóõ”U–¿ü$ÎÐá»[8 ¦^äL—%2GÆ:M²Ñ¹×œ.¶\�7Ç„‡—MÅË^ ì‚LŠðRS0vJº‚‰× Xn"û›LSW < ?K²©¡H ÕK;’ÙÒêQè<;š¯ N8ŠZ|RG³GÜƒá…æÿZðøLT¢G#ƒqõ‘ll¹½~È(㣷zØ:b^À¾8k±7]l\J0tþÞÏ–X;óÇ:äÈáÏEöÕ߈öì×øGÇ!0߉5O(Bwkžx„1qÊ£‹æUþtz-í›J“zýÀëä]¦ÒÉ2£•$IúwÃYÞ¤ËlÏžóܪ®ÃzƒóLIû8Nwz¶1Ò8Kf+=ŸãJëk»˜¿Þ|jÏA¾—OAÉ@ÎRGJ¸%Øêñ|7Ô’]òzüÓœE_c°~N¾Xº„FY=À%Ãþc‹‡×¹W-e™NÑ4êb8çhcÝòí|îŠ7à…Ÿ·�C—’³l÷»¸y˜ÆP°Õl.·ä‰}«g‹>O¢çTIÔØ†i­,¢¾äTˆ�N¡=Gö²­Bcf5I—†&"}ñ®àSªy‘%ìºXÜ?�6D¿ßsh…íX>÷g¤‘ª{ÒéŠb*>•¿¼7ðq¦I ^Ð�è£BõJô2Kæ¿(7Á¾†o`jÊô{»¸ƒëµ1Ã%›å=>„‡\'Q[\.TYA:îoïÎ%­Ôe¦…îTä±vd Ð_€�ó-hÿjs\k¯CËŽ¢Yh5‚ä;þÎþrT_ÃV›ùbß׌þá�šyë¹Êcg©:®†”Z&ã Òµ\Vñ’SìÓÅHC3Òù¶”ïu£c«Ÿ²$SôXá�!¼s}{€=¹aN^¯äéÈ/üÓH)Ò‘´~½Fkµe”¨ÉÂ�EoP Èá™ôrÒjd#çÒMn)®º$doÅäûxF×™2<ÿÔ~í �*ùü¤3Rاv VÞeÂW¢˜qk>jZÃäÿæcµç2ö¨£ž‡ÞlU°°¹…™+C—ûñtr�4¹}–ìš_ïÌ<hK_9G�fF.ª÷™¤«˜¥‡AÊ,UCåYK°Ïz7ͱ Õvåâ¾…Í�1é1ÜSJ °WŠÔóÅŠû@†Ž¿�>K°ã¦4Äo*%½–Qtæ³ë¯ñÖY-é_¶ebd{¼�^ Ó¦O�°�2Y²¶µ ïÆ*Á÷Ó1ÌgÏ�í—#Ü‘+ØåõFÝ dc¶zRÕ˜Eüíà½d'� ’4¸}|ôRÏ Á|W=Ë ŽKPÍW}ŒªáÎâ>ۇžÇL�-\méLÌ´g} PgY[i|Tx6á<Ê–Á q+ˆú Ïù“ÈúלâÔ(–7Pż¬3@F¥D3O‚dÈx\î1 çw-Á=9­øä•3ç»­šKs/àšÍo3õãspØ1,1S °dY,Û©�Jáû0¸)ný}ϼwIÔÍæyúã¬ÇjNûQµ¿*¶•õqU;ÊAìn#‰•‡³F]Ì3ºÉD>«Suy0xŸ~ƒüÔ¢ÅÏù¬%gá˜Øm~Ëkkº°µWϽÇn—ÃÄñ#ðÂy?Œv[Wª9.fTMÙ ¶WBX]¯Íñ ¶zâº-¾,·K�FþRd¥Œñ}ež¬7†Ÿ*·ØƒÒUÔë³í”ÞB_m8=ûxš=ˆgÏÌÖ³K%˜ôJ}:>ë Š*²•ú’–3=ó)õå `ÆÒøK|².ÖžýÂLšûYê#FŽ¡�ÿä¿¡êÏ)ÌGÁãk/‹Ge¬±×Œ>Åø²ÓUÉ8ð´o‡³‡Ï á�Ûpµp¤¥ßf+vñR1ûSòÍâå < 4ê¾yÝ@®j9m[ÃVþ×ÇŠ·ÿeFÕ"ìúÅP¦’zŸF}b•‡<ÐqDmu¼ Â�"ÔµF<5'ÓIjÒ –>ó¾‡7À—ç™4oz=)O‹¦Š¦8æ�å/ZGµ‰)`ù9‰-Ú#Oþ¡Ê|¯ÌdœW²�‘\+�žAsý†m;߂Ӝ,v³$�]µR>÷á„¥ EÆýÇ"Nÿb¥ÞÛÉs©yð›éS çÆ1�×™×.j-ÝBU­ÛiíÖéðÛ+³«yªÙ}²ßÇ�߬6‹ØpïtìÔ>˜’ò�¼bèçi('qì~Zà{ 3¶¯ðüÜ£‡b’é¬ÓºoÉŸƒÿÞjÙØ®ÿQ,ó“ÆÒ RP&i�­)»¥}³§+j™àôÔž˜Æ)XV¡ ¦§¥Áhq:ï—¦'ïÃX`éC6[ô [¾÷é_Wgñm7P7+T~-ÆùIÛ1bB4m·«b¯o‡ãåÇ£©cÚœ|_ƒ4žždj-{IqÍc~Ìïm\Åœ‘gŒïRÇ »×Yºž/¤ú&Y¶ã³«Ù’įv¸O‡ÆÚá”ü$ü’õü'|�‚´“LÔžc5WF�ô×åœ~R9çì Å‘?q¶újQÁ ÞÂ÷„TJá•(N³t5'’¥ìI>÷�ÛìƒéÀ \õÏÝ;á { ëo*Xjþ™Bb—s…O6ÍÁ±†Ê°{‡®³}‚¥•(›9]§=g£›®Ò¹»rlÔvùºÒæX”T¾/'Ëâuýuðñ`5ŽŠGã¥`µM‚ÙLQ ŒZËʱ¥§pâ<ûw3õ·Í¦[ê©�Õ®B÷rİWB"UÚ˜sk+]aðô’Sèo!Ã.úE`».qE©¹¸FÁwsÀÖêç¨!òšu6Yã‚kϘ¿c–¦íG‘ÇØ¾›3ñGX3Ûqë8þ~¯OwþÔ°Ð ~µ§•˜Ћ½"–’_Ò¨yÍ$f AÏ J™k”!|wR³lÑù Çvä£Ãâ]ôeÃ�T«¡#²á0é›�ŠjÆ}1´!éî¿€½ èéQбåéœÖYü|®ŠN f�Q²gsø3ÛÙW‚¾E„•.Íà.-Ç*µæÐÁÄsôúe"Öu,"Iÿ|6`Ž‡Â†‘¹–nk˜O+«f’õ“c¼f²Ž:•Æî�o‹8ß~ÏmX^T·§¬ ®OYÁ_n?‡m+alØlv©õÿ`žÌÌn„ïßÏRlÀiðl ”œ‘‰r»·ðâÇž�sIûýGI¾O�©§÷–î¤'É8sŠbO?�ƒ¦¾éd4î'•:’îÈ;£îg ’\lÍöW¤/?Í(èzÏmQ¬;_˜‹ý zÈ’Z„¥ö•ðda v,:D2=WpFèDúQ—I%¾` ¬õ¯¿ËXÿåU$ïSOâÍ»hfùn¬t„—s@‡ÑYÖ)e:Å ¿Êàòcú´Ò˜âÒ·ø«M�ìAO…ûȱ¶"#Ìy¢‡tCØÜ%8ÿÜtö6 ƒüÖ¸ÒO˜A‡ÖK[.p]‡sÓza¿¾=eˆUW,ÈÌh¤y~€Û+_af¸y>Ž!ÞÚ– µALºá3{¸&‹[ò~öì™Ï]ËNÃj¤ØÝW� te'�üá‡)³jXàÛý(ª¹™f­°Â’&øº7œÛ÷æ(õÙ�§�:·)j.–-�bE’d¿¹‘sô9�t'ФóËØ´¥ü0ß1ìeÊgþ~Q7Ûî\H½m"P­‰¯O¾ÅG ¯éæøLffN¼–Å)vfH–ò]ÍÁbFY6¹‘�¡Fê¥Ñ¸ü06¯a*ÚÄ:�M¶ Ü~1�är9ýY7¸Èa tÑ ÛìHgŠCØÅyš`½‡�Áa-Ãhø–KØ!¸……ò5è»§˜=òÉ A°m˜Ò®Ž=Ô úsšËU Æl¬âî™WSÄÚ£()™®~Y¼tM?W˜ýêÉàGg-k)ti .¸˜F3"ÑáxQRëLlŽ™ŠÓg¼æ$מb×”ð Çr3]µ§…"%ÐÂëÿñ!'ºà¹‡£9í;(­›H¥Cš_Лƒ ¡Œ�!z·æ ] Ž#µý$õÎ�W�…V_Rèlï&ö9æ.úîó¦ÒÄ”^Ötü*&-¦—R ä]¾ëçÄ[ÜõÓÆu½Ë(i© Îj ©­¾žÎ²7Ê ›Žoc,$’ÍtÌvš&²ü†v.Êr%qØñ¬ßlöÇÌO_‰ |3¥kþÌ­†–* 칫OÏ{>RœG~ËuÆ…c,™íŧ0²V‘G&Ð^uf_LM^7”)ç¸4�Z4¯N¥ò3…øÍ}.=Ò� Õ‹Hãå ðœó˜Vê¤àÊËÑð‡&Úöß �C¦øâÆ~1%HVÅ’�Ï0!ö.óŸ‚OêtÙÚ§²uÇëî¢ZÁ7ÖØÂ6mÄî’¦±:APs/‰åþU£÷qÑ(P�£ª¶Y”ïî‡?ÎM”tlG%BV‰*í¿5�4'-ÀÁ†*rwÎ=U)ö«ú]` ¹Ñua=®+–£�ŸVá²ÿ‚)üæ6>CÙ?ýÁµÞņ±?°Cà cM¸ý>B,�·ÂÄ�áhýýu(”ñ~òµ˜ô& R ½ pÕvÜÌ~�ˆ«ì,ká<ãÕqC�4»MGÉqü9d@¹Uh=4œª~)“Ó»2¡ƒˆM} ŠótQÚ¼€FvÛ’�8‰¥ç³[²ÿñ!’E}JF� ·,°è•¬5Ãi ¹×Æm0òR(ßœÆaj/XñV[˜Þ@ß>>cvg ªÆœe ¤T¡dX¦‚§¸i ]7ú•vâã!4¿çJ;Œ¢.^0¿°‚ÿ{f9 h¨Â€ùI4z{‘† UÚPï?Çq³%ÉÎd\+G×�p˜Ô8S|»èÅäSlÛ®Tä†/DÚÙ¥ÙÊL²Ýâ|/@€Úfô?èAZy¯ZG8pl ÞyXDgöNljûæ•q?Æ·0¹W3ùÕb¢ìûk̾ü«�BØN™ãü Óv¦l-5^Ò§ånרø¶$’ }Êkö­Ã@ÿ Ìïœ-w¬{)•J.d±Ve|hI&¾qJâ^{À}ç¦ãÚ1Ðk@¨Užf$“¯Ö]Ö¿' í’qø&GÚ¿ý>ý–úe«8}_i|æyæ–Y£Ÿ×ž÷þ'ï9â/1'橹�‹úº‘ž]G1˯À»üG£¿äaåË ìhŸ}Ý`»kÞo›Â$'‚ì”qí ¥|Cþ%M|éM=š6sf¶0ÑWÄÎsíµ¯Ú¢ì…r~ì{YؤKOlÏpÓºŽâ¦KÐ/ù˜&bR‡…�¯ãcÞ5³Ûœ;nn9B÷ªC0á¢2·êª$¼•Ítâ˜BÌJZæ—ËþÞN˜Ÿ‡çÇý�áòçªø$DJEFEE*¢"*Îó�´�Jf%M¢To4¬¤lBÈ)2+¿ó<h)iï(íhÒÎÛ_ç¯ïu�ëœï}ߟ�?» *&áôorÙ�HÒþ*¼¶k(øõ¢Iµ›pÕ}y^èä(DæEàÃMÞ6þ¦øX½…îÜq@£ûá´ræ¤.@õg‚€[; ëÝ4T�?Ci•Z�Ú4â·)Ü ¡§.½8Î¥Kàò…¼ø×RÐÌ0¡À|+Hú\£5-1»ú6÷{wŠ%“ïXô4kE§ʬ›â/œ.H†þF½ñíí&Áb¤7ö_¨G=çΪ±¨6— ®’SZ@<µå¶,ƒª°qœûèŒßx˜ Ôœ-[‡p£÷@‘JV“ÍØuhqZ\»¡‚W~(ç蛹>QgÉ«âß^�¨}bm;Ï=›Á;F…cW�4—��„Á�óÑs¦.ÚA6l=—^ÀД ¤`‹yW¬Ñûá|>¦kE[ÿ—]Qè¨6 ¶†�³¸a.¶¥¦ažãi:êjƒŠc®óD£ß ¶$¿“‰ºßçБ¾ØÔ×Pl^µŽ£ÎLj9ã~ÀÎ]Óèg¯u3ài›šÄð�¦<ìäFšV8€Ôîd~¸Æ“SWb÷uuV ø 3î‡1|³£?µºlƒ¤)õ0Ôx)ÿñ‚v¶Â*Û5àù`0�Ù)¡ãøˆ‹ö«O§æÙŸÉÖZdîD‰_ڿ‹ö‹¨»x1-ª~L�ñ¼ó¹1/>ãe1sèMünÞ�V™pwv%Ú sâveV< lU9|PX ´­˜ˆ‹DáM™'=yRbðtJ‹~TP~Ô÷Áñ:ÓñëG/Zªů÷…À„ø ðhÎW!ÎAÀƒÎƒ`¡¡/oÜ~Òb¶¼¡e�¢�äó¿Þ÷ß�(Fë…¦ߚ4DW…Ý>Kãë¿sh�ÿzܶz+ªf æM*»ÙãûtT~eñ§l[Ü�sTPÈÛ(eùü{Í=à ÏÁ�{ †X\ Ë¥÷’§òª+ˆK‚Í`ôZ/Šœœ$±UUÇlEÑDÑWéFóðÙëÅ^V=ðA·Žš2,4e“þaÐÌP\,m î�¨p”–dÑž³Cjœº­Å#7|Øø-ÒÀ9;9­1‰ÒkÄƴ øí†&~{½^Ôj€uàÏ(-ü0ëÝní�ë½ÿÀ¬5>m’�Ù^�ì½Ût°r?ÝÍÏWÐúù:üZ ÁÇÝâCU H®rª>SGê Ò_W)î[@_9…–ümUþ ŽŽÁ0ãh ÐTñ~%\[ŒË&Ú ›rÎSaOì2 å‡døAÎ|¥æ�% òµ'ÆçiZÊÂäe&|Íö͘ö*¦*áד}±£Þ�&Mã_NÀ¦#÷A†k8êÆÒ”KÇ�«²ñ—±,[�±æÂ‘„�½¦[LΑ…+´°ÔBmy%Ê/`éý…õFÿY$N¸AUg?¢Þ}rvKdÿ|N;gŽQ‘ÓI¡s( ÔpxôAžd³¥�K1Àp87ËȳqÚ^êûΟ×^œÂÒãÓ(¶t‡ë;[8Iâ̺,ûÏ=î®`µ’ž­lÈÿê§ü�ºâQm]ƒ n¾Áõ ”QSs4-5ÃKUÏ…˜ùç`�—-Êo®S“Q8+o-š�aoªx÷“xÄ­¨ñŸS¿;Ã^w€Î£hTºs]F¼¤-})rÛPq†{u¸OåšÀ¦EšïÞ ¢ù3s$ -ýxqwø+ÜÇ—ó—ªVz}ò–]3Å [µñQê"8ödn¤"L?ãF¯¿ørñøFº?}3|Îá…xÚÔ�b‡¼º¼>ItÍzðøæaâ…êZuO<„ÍG^’bÔ]r‰—G¿Ó‰(ß³™%^±xwf?|ÝÅ(%œÝ_ ®>Á¯ Qòú=¿t†Ÿø´Àñ¾)ôïûAü’¡xK®‚äFVCŸI`{/ô‰+ÃÔÌd±Ïwžº}"6‘„ú„¬nŽ ÷âT‰*Ÿµ(£®1'ÄŸñoabHÕ¨F‚äñXîó¡Þ©v¢õV|Þt 4턞Εðv�ÿŽ Ãq^S9Ðs={Õ¯ÅÅxY­4o–7F'…|!jN�D–ÍÝÀ¡³Ñôt$\uŽÁ‡GTØÌI�†ÿ@O¢Nã‹6#þc`"¦¯GËäØa2†N9gB¡ý>6­ÜÈ·'Öã‘줩6†®î0G•Sµèÿñ‹¨«¤‹cÏFQl§,>¼\ˆÅ³>‘ +Ö.Ùœ…ᇏþéèßò„Ï_žÔ\Ú1—›æ]7)Šm“¸Éó9Ùùä|*‚G~+iã¤FV°šïI•ÓÑXšŠã0@ãe®=AŸŸ.Ͽ޷HlÜÎRëbJšŸa1bY_þ6y©På(?ö¬$9Óaë™.Џ¨ÈrÿÍÀ· dðƒêQh]?¯?Ûƒ/ÍóÈWi¸p¼M–µ¦ó~¯ê¹Vá;&‘Ç«Ð<ëƒk–\‚TŠ)åñ¿÷�ZŠáE¤n¾ˆª”bq§Iðî½ô«Ç^X`Àn7âiý-'µƒüufrÍÄ6î¨ d|‰Âza�±s™E‚ýiÚ½‚¿(žâTë•tïÓn(Ëy ]>¡dXý4y"9WH¡QwÌ�f‰½šÉäh<—'ù º­Y¢gÄÖ¬ó£—}”PIÛëì7 ѯÞзïš|Ú"‚¿?XDumIèZzüý¯ŠÛŸ¾€¼—Ê–é ¯?Id·ŽÄ37ñ~û‰ÆN´Çï슉Àʶt:%J0TE†®Ê�‡z9~�> ܃×cÞ¹Zˆ9~˜^MλÕr±]å$U &!Ô�N­ç‚º"^qý,ÌÛ†î�Š@Dk|æ7Sg‡Ãä§o(w±óÌàahÂö…Gpó×Q˜òl™�v2¯ííI¥V°[ÉXž*ÕMŠÖâÜI7!óŽ^•J·×¾…ðãöž*Šgn÷†ÔôíøP[‘#/„¯S�øZÞá&�â>ÛË$ÝÎú¸j¥,ëüó¤%f, Ï;yúÙ|¼ì£B¦­k ¬D“íö’«ÇB²Ó0¦õ!аOÂÛ–H�]‚;&«²Ã$%´/m'Õ±¬à0>ä!k^”Gß¿‡0Ìr>°UÁß§tÑñ†È{ÚÞ‰/­¥@ú›;¿é߃MÅÝÔç–?Þ¿D]:Æœ±à°EèõzèÔÜ…?�¿RZâÛb—ŒÀïZ,.™ÎA»ÖË`õZ�íüÕ`ì»":3Õ J»|qÿ‰•´z² nõ‡Ž³¹æþ¾»èÒˆ4ÿ…*6Ų˙$Ѩs)½ý½„f+èç+�^ïí¸zõ{‘ ÆcB�.¼ ñ¾{¸mºЫ^<®ÏNqÑÛ)0Ùõ-�ìH•ñKñYB_ªŸNorñùÍnH;Z%Êö²æwÕñÜÚs«ÐnŠ£VØ‹''t‰OÊpá÷áX7-ýJE·¦ì%ýE¬¼¥Êƒn‚•ÒH” gZë…�SwaVÔª~Ý‹_N˜€nKžÃ¢O ø¥y� ØÊ�wX(|ÔÁñ÷ÝÉí€O5R'ÏÔkð¡ú1ôêyVl·<޾êE|6ãMqÌÅ4ý1°nJ/öë� ?=²DÕ‡³È}ûd‹à}ûð ávÓwGÛe3%ÒŸá±Ví Ç;ÎhòÌ­2|æûLÑq�4Ïö3ëºÚ[Ý µ ëþõd&tLä«oòÐnE7ýÕŠ„çÞëIýÓHÊ×ÂsCG£÷¾íq7dŸŸ…W‡ã“ŠhÿØÅ¸½Ö€ïZï¯yÄ×ÙÇ?„âV;j/u„ñ«Ëiù‡×àY1�>Ôìç§ŽÔ%ºóÅÅÃyh÷iʹ=ˆk[¢°qV¹,½“’�A68þLÎÀ/"Aïê'qâêoœ¹ä ]‘ôc­=„%£¡¦ÝrÛvóüž¤†J6ÙB庙üé·´(í¥Š÷¢~á9ËfpÚŸ‘ãzÓÛ1¥‚–ò ôSQ�6ø`}0Iß�CˉÜNîæ@͵(¿½„3{?çÒxêh4T5V,”ªµ�F›Éh™µ4nÈ‹$£ÿ*ac¥襧?þm_ÕL5¾90G\”ÆïÅC…Ÿàôë°2j#¯Jô#y³}ñÒ�šw·AºãBV‰F ¯)·Bµw6ñ¬®K³ï·…ðó½1º®ËNâë·Âá®ÝQrûÉAƒ‡ò©}–Q©€ÓÃÄ÷“ÂÚ¡½xëN5¡Ëù)üþ¶�´ ‡ ×¿|v/›E?,^Óœ¹xïótaÿ+\R~æÕîê–önü˜�«è!y'5âÅY J|òŒ'õì�»ÖæœâqØ&=ˆ×? ✾ÊÜ—Izk$Ôcá$á]õG2|Ö(xºC¬¶�…ØLmÔ±â¢�'¡NSm” Évî|øò½ÎéΜ^¬Ü,ÞM+@ݤT¡;Ê�ÿ&¿Â¸¾]´Qé'ùYÅ�̃µ`¿Ø�/¿Iõý㩱zçRm=$ ýk¨}‹Ý/žÁ÷^¢uz.=mXÈ.ûÂØ5pMºèÈq�.“Í–j™ý Îõ‰&åObéÃS±î�ç+[²Ê„7´è£ý Î7Ö`Sö{œý‡åóâ°y]1ílнž²ü{ÀÄ÷  6–lÛGsºU­8¬é!,N�ÏMgà+Ùqèylvlhâ÷ÓêX·ª/}ì‰râ jÐIçWe­À¦½Š0Û1gÕÚãø»ýùĉ;r÷¨ý�)M›·½Œ†ŠAÃyfÕ!\6Â�,¬ã}c14éI~û�íâ{âØ#¹TœyŽß§(ðßðñÞðtú|îÔÛdáÞÝïÍáÜ8 iŠÃõºcÁ1)„5”ÂðòÎ ’ËÞ#°—³–‰_?{a쿬Iò'€ïs[L,Äbs+õ^ †i½kt-5àZ� 4wäMÔ±cÕªtÒcqÁLüÓ5:Ú\Y»ŸŽ¸äÉòW‹.…5ƒïµÁðÝIT¶¥Î)pÛÖPè92”7 ¸Lá‹&RÇäU˜¾X•g>l±É»ÄÞf‹‹¯¼Ž°šòÈn4÷ïÇ\}­®ÿçÓñ„ÜvÐÉ(”´“ë€ý¸àÉyòYžŽƒeV°ÓûXòþ0¸I …cfÔÕwμ%�üÖrôŒ|JÑ §áÄ÷óŽL)Ο§Ž-'aYÀ:êà̪ýÀ²b}Á~¤>Ö ãÞo$в⠽Ym‰ï:&ÒÃ3c0S½ OlÇ¡e¹BøQg4z]ø}u',Õ�ãÕ­Õà¿+�Uå:é/øX¨8†àШi‚wôKêUhÆö«å,š›ñ÷ ²|ßt—¨”ì ã¼'ò¢¤�¤W|‡�úK•[~˜)ãô‹û@ã©)k®¬„üž6ðíç~hæ2¬ËL‚É–&hÙªÀ Mû'¿Ý¤ºl>î~£BŠÁÞäïïHëžyã°Sa”R¬ÃóÅy|9$e�ì&‹÷Áⶉc¹ge?\(÷ÞnNF£ZJº qQë0îã@|³ºRŽW_}2És¼ NuŒÇšÙaÜ f§É¥‚ê‰y¼,ïµg^»e쨪¥Nx|é0oÒ5ç]oëÑQÝVþ¦Õe©X¶ï!Éþ®¢²É›QÙt oOq�7�×H5·–HòZT ®¦bƒ?°Bw¬hy +›«`ƒÛ¾Ê—(⥄+¶Ýûõá ·:æ ¼EkèÜiòG…Q b …*|óy³ªåyLkO^«fŠ>ùçy“lwÊïç늫~¯c§JæåöcQn×*?qÉãÄOZý)¬ú,r}.òéÓ¤:é± ôŠ;{òÄwzBŦPª4ü(ÙâÎ1s³éî‹Õ8ÿÁ7ëÓ)¼8�GãâŸÑÄ43P»n]މ¤5ƒÿ(zãèß�ÈvºÈ“æµ ÐoŸ¸; ¯/‹DP¯8„í=ÑN¯ÂÜ/óÅOÖ@#RÌùâV3–³èßÿ!fxÕôü@í ñʃvq‚Ù)Zí9�o4.Æ–À<ØžäëgŸ¦f— ¸ /•�ªôæ{ÔlÙÈ3¥‚ôòtaN{0ܹûƒæ]\ŠíMßDzµL¸ñÆI‚kN3`ÝÓSâ±×lu±�Î~†ÉáMÔßù0]©©¥œ·áhÍ.¸¼ƒnºD -}GÀÔŒIh¢T& ¿´.oµ¢Yš­¼Õ&G¦�C«�eb…Î>¬¹ṮŠÇÜÜŸtñødÜ?Î’Mªï@¹­4�´9L+–¼q­ÏÞ2ü„ã© -<âë"ZÝ =Ÿ­Ä×Ûlyz.´içÀ­‰ ”z©ö–qÂ%U'ñŒs“…ig=§È á-é·)âdý—D¿œã-tLñ‘”>I¿¦½Çb\“êÞÏ­ö0¢+ÜíY¢Ó[·¶X\{›Èôxs©-¾{žEsímaqR½øìÅc82ÌBüð¤V+߯Ù>õÿ&qâkøZ~�ÎY?‡8)ã5½ÝÐ �ÄÏå”@ÁpsáA×áÊÞ>|°•ìÊewýÕ,¼¯•=¦½7Þ�ôE}¶èÃŧ_SÃ]-Ôð„žî¹gcÌ•ºéñ‚ ¹B�µÁ\g›Æw¢ð�§&ëWÓ¶ÍÓ¹¿Œ¶ÐcÛ7ñ¯8­ׂNÞ`Ì냯Ûã!5ð4/l!ò / ™Oìx,KHÊmOµlÄ‹¿�’Õíên÷Ę9ÎoðU òí'L;ž.lzÎF,¥ºQÆ5¿ ÓܵØîøo²“=(¼èº‰‚ª!>éÜÍ­5аåùz”ý6÷Í hÊæ#³'âÏïÓM9wŒêH³¸”´�·N*`%!†Õ,ŽB†æeHjš ÝN�ûÉ_”÷©³Ph:)1X`M*_gý»#x�ÁdŒ9™ƒ™o’x›ÏH¬¨¬£eáÝðßF]nûrD4×Ï�¨Œ�Âûƒ03Ák=Wóòýlc}—ŠŒwr¥Z¤˜©B\Z#Å»E�úž^´ßÂ?<ÃÃßÿ¡†)¿ÌS;ªDëPô1Õ§õéóq̹¥ä–3¨ÖJ±ÅB�ŒÇ†eã¸lª,:,ÅIêÅBçkUvÜÑ&ômqßøù �/Ò(ôOQ³Õq_^IcÿRÓ<àú=ãáý‰`|ü1 f¥Ç‹¥Çd´+”÷]Rã”Mrl—‹;ƒ®ÁmÇÑœë›B*õðʧ4ôñ@˜å]Hñ›� Þ^êðhm:m9±“÷â©è¡Ø©Ý1q»ØÛHg('à(©CD¿ ñÞ¢�hz96K¥gaÏeÏázètØ�e�¿]§ñƒ)ܶ?tve ·ò_˜wì ÿ«…ë¿{Úir¹åKÚº¯‚Òb,tKjɈ °ï6]8t-K7 Çüyd?¿It¶~!<õYŒº—ö@þÛ“0ët=}èHƒ Ö˜k¼�Vjaí½HLM å!K§b„¾ [íðE]¡A(R:NÛ¾gJ6ÿóÌÝFÏ ®n9Ű…kŠ ®b°«oEoõæ•<±}¦›`n"Ùêáˆ^±–¼WCOŒ½w‹²‡žÄðµbºJ8um�pÚx¯’Ek‚&áô×Ò¨ùk$|ÙŒç�´c¿í.¤»4�/L„ûÿO%/ …–:ƒ,ßÊß;ŽÂ¶ÈU�+<ƒÙÃ*Á¤ù£äíaJ”qfWCn]±ŸÛne«ŒT4xpvn#uI—ƒ±°Œ»Vü€‡u~úŸ0Ä¿RUÑÓy¾�®§~5ÀåöQ’XߢÞ_åð¥Ñ ^s‚näl¢U=k$R“Æ¡™¤´ºÎcý M¨xP m$†ÜgÈ_Ðê�PÒí /{‘F/H´À#=*8,ØDtÿëŠ*ùR(ØNÛB8Úõ1Ø÷›ÎØØ ÿ'%�ìl€ç/²yi .N’~~õ†£ÿ]Á¸Oàcûœ?o¡¡\Þ˜ãW»Ÿ0Í%we ˆ¢�T÷( m{êàÏ[Êðä�6(Ê�cåˆrpß³ß^>N�ã'¡oHÕž8^kÒ¨;¦X]¾^–xi"¡“ 2ùíßkp§÷bXX{I¸5{Ù^š‚ß®¶Ò��…ô<2ª�•Zôkzæƒ+Å”ï>ì œ´ßk’upºîr0�ŒänŸ¸]7 Ós÷À†t�zÜþE뤇ðÜS5xgÀî}`4®}>•¤‚`þ4/:÷À59÷Ù³ðè]u'õñÆ‚î÷ñ~ÿ´Äfù9²Vzq¯oŠ¡µ ÀùA?±8‹Ç+ˆÛÿëÁGÇ¥óÐÓþ¼Ù(ÕÂÃQÜû‘ ¯’ᡉtáå+Øœã‹V®Ãc®Ã§1/1p蔤-~öíFiÏçFÐûW£8w÷2H8¯6�2�ê`c€ 7×Úà±kÒÐÚ _ý¬€›/îSæ˜,h؆�™S@ïfhòèEºÑ¸ÁÏ�å6A×ï¬uÈתf üˆ<7ØaÏI]ö7ää÷€0ê·h½è¾`Õ Õ½¹ó�†®�äÈýƒ)¯ÄŠ#ßü6´˜Üo‹0Ñâ(]XšE�²_Z¬—G“qÓ8k[‡9ø±}Èh`ŽÎõqœû&˜ovèÁ‡G(êç=ØbÓŠ+NYRäëº¹ë ©|ð`Ãmj¨Ýñ4L¾ÐƒÆ`^:æjèkã‚�VJ3™’< •Î1|0½ZL¹>.³ã±í±4sF2dü$-±Ç}�—|`�FœòÍS̾£ú'-þ<åd‰qè´­_iØÁ®S² Q�ûäÕþ¹2gD:£ü�lpÓ—O뉰nž#êÜÓ$³âQP¿£¾ä©ã¶†_´jÜaêµ}kZºNé·Í…÷N:A ê¼²ê8Í2Æ €'Bîçñ¼eÑ#œõ[zzùSÎ?f «ÝÔüzÎh‰©¦hs’ŠÄú�t­Ô Äa®ÿaQײY•DSb�ôv¿½†Ðû�ß_3‰C{~¡ôs¡|°-�ÊËah–7«+BÎï…zôäïÚè¥Æ.áŸà—F#eóQLl™„A ¶ ´e_>6HÁrdzZzÓ• ÍÐGßðÙc=×íè°8œù‰ì>ù�Yº:¸_ Es -`ïJŸ�ÛwŒÄwÖ-ô¶�²e�%2x¨m*ª/ÉæA9†$¼aѸpæY¸V:˜£õÂá»�<¦©X²fw'\ŸK}ž¥¢ëG3´éØ)½¥ÊßÛØ�ÏA׫ñø"$KHô;‹þǃ…† }UA|6stëçe�áÛ)nè}¬œ µýx„D‰ÝVo�¿ I2l5½0±ÚV'RiM ¿½´„S†Âê…`’a€«ÝçýcÛþ¼¼öu^ާ‘K¼«”E©‹_òͧ‰¼Êr< ή\tm³p]Ë –-Û ñÏ+iô—3¬ñ)žÝkp¦�y�áB­ZèíªËîìÁÅ£à@¯t*ÈSÄÜåà—µ<ÞW*v/ù‡·ÑêܿԽâ|(S@•o÷¨ïÊ·|gÆ|¾òoV(Ý&‡9ëÁ´kˆ`jú’ªkÑèÕú¼yÃF([ÜåÇ}ï-Û<ë8%1%?£9ïo…T ³+Gñ¦Ã½pØÎ½W²5ºíÑ|t/Z¤‚R®»#´ÛŠðbódÒ1Åï/\#§÷ÃP¼ÿ€ÂGT±â 7ZF¢Ü�=øÕ°w=�¡mÓQWs3.?ëÅw?· ‡¾+’MNó¿-¸òÊ(yÒAõ�KX~îüXñƒl‡çCxG¾+éX]œ<‹e†<ã—pØT1›�_úTpð‰ˆʇ,* ý}Ͻ)�ûGAÒ�Lj=»ß{”qºö%ø½t�x¡Užû§„¸$|8u ×¾ìYû"øõ“q_]y ¹aý çì#‹ç+�7·8¬ï%ªò¿Z/â�¯ã1zõgáÕédž ŠÃšûáç��X’`ÍecŽò¨gø)2Œ]¶“vØê½zD=§ã7Çr›Z¥Ä¢ßm²ß=™ƒ¼dPÿÃrÜ¿ÿ�.Ÿ«ù�‘Flp��YìŠ;2 ä5C¹Ô/^"´ï�ÙW� Avž4ÚÀ+Õƒp×ß½Âû·Rð±6¯õ-†‚�Šh9¯'íìF«Î]„i·£vª ú_ û sxac&¥ÏY$hõöD©£°ÄT–½ë—²cTjÆO`æÀÚàjàÅaé8mÁLŒ>IbP@"Ü?ÿ›CŽ'Úyo³1婢öŸ[Ì••Òç=SiÚÜMîg êlcZ»Nƒªçœ§wg.SЩõèÔ0ÿüËn—JkÖ�ÛÎ)šZ°ý £�=ðOÆ;Ê68(Nf`ä™~ä(m„æuÂ`:==¢å?m°G¹€eÿØ÷©©=ŽîÔ®e‹i\� ¾œ¡Î’ÁAÌ¥ ‚ûÆßpÄö……‘WÛzÕðH±Ÿþ_?Ëè]ÕâùRS~Þ[�e*‚PV£/ê�þ ýP‰tèÁÕJð�ºM·]¥íº—pÄ$Cœã² ÿ³úJ·ï6‘·TÎ}}v4¦àFK³”±¬µ”ö(+`Êe ¾z»Bü|xØ… âÖÒ|}Ç2ì0­¢5]›øð–ZJGãµsöŒ¿É «Ï)âõ»q0Ó÷mÝTïÆær£e.:™]ƒ�;z£Ý‚:Ì××á)s³èÞD³îã4ÕO�ÇŸ†�=–óà=8taÆ|Êê¿m¡¨—­ð`‹Ðø‡�]µFLR¶…‚Å8Ò¹Úë‚ ¿ÖÏlÕÃçòSÓ@š#¯Â^ﯰLý²o'(”÷Zª¡úüÖ_üzÏ2ä­NWHï_?IÍu qçq噸þÝQÁõ’"^J´A{9%|9v=J�ÝÍíçÁ¼ü<�تÈN&òðÙqh–{Ví'âÑÎb¾´-ÿoLöÒâÎÊž8àk}_äÎC•¨we*8{¡_ ¡D¶9õQNg½EÃñ ùrv¾¸€oÙÏáÒ2tŸ¦Ï‘Y¿$ šÊ– ¦ß_AyYÜÒZJÇ%&ØÒ'‚šö•�‹ÖZ¨@�߯rØ`=~¹À�ç—5[LZàËyþ¼:y[¨¦CÕ{+ÊÒdp13åˆe+÷ÿæ“Þµ,\ÖøLÜ~,ÊSûÒšñéøGÆ„^9ìºB7¹‡„¨{Êœà?�M×~%ù_û0Eg�˜­–Œ0>Orqÿ^jôý¾ÁÕéž\·[†žÄ×»W0­×$Ãi¶Ó–p˜[¸†�?rÅÚ"1õI?¾Îãxí´R"éú‡sdù=ø·Q‹º2ºÉÝ£Ž3[¡|ŸVí±mëpôôãìŸÈ3Çö]»d¼p[…ƒÉ?áöð$<¼ ™·.?ˆuû›¡®4Ï_ÚÍÃÿ>¢«o'à{ŸV6;k.ώ̨æçmëq󿞸ð"ÚnŽÅAÇ Z–°rÆÊP´fÓŽk0Cù=<»ÖL51¢ï�pjûŒ:.(b¬¬ û´ÎàG—g³kZ$l|5ÿzÌÃ'Ï×2]N<¼Då?–Á¸ª;x8}0«o·âià† dÔè|7�¾²/ĸooèv‡2~=”�w5Jé±R¾tËã=&“Ѻ T+[®Š A;¹Ø2œça»}8oóùKå£ãñy±2”6zÒƒúñ­î|4«�Ù>þøé “ò*}Ž¿MLªIÀX#¾‰Œr^H”­$4£µ[LY{’n)¬€�nhw¨‹R³M,o‡ãÁrlö%ƒ¯ÈƯyÓpÔ¨"ó9aå|½ëÂC™ZãqÏiUçu8¹a*~÷áDØ_3ô{ˆØ³V_r¦v’寏^ã@^ï¢â‰ŸäÚGä1—íñÖî—¬Xó‹|]JÙ~®=º”xñ½¨•taørôSÇ–³/òÓl=t©ŠßlCÎ ½ã–ƃNÏ)¸ãû¸wׂ³½òE�cü¬6 SfHÕ$EvÈ8+ªJ&ß'Iu„/wO£/YJ¼±Ç0^Y©^›’ð¼á¶�?ç÷°´ºLÒ79 Þ«pÙ¦Rê�>ïïrDß@®8!`Ɉ•ܯÙ¯z ÷3 á©h“w€ïÌ–ãA[ò/çÕÐ÷H o/ÿÂNjà‡»1a ƒþØ�òìœý!'0Î_² s8aMPºÌø [>âÆƒ±¸âQéùxsä×ZûeVÅòE“bè£ú”þXÌGŒÊ–D,z„ ³þÀûY2º�Ä1—à醅\[(š¬ïÃ9;dÀmò}Þ¿ü~žäÏ'ºán°'æo>+\ÒtÇýónS-TÐÁƒ7ø~D)æÿ-�ÔÌE$Ž-f]¿Lz¼ô<ߘÊ=»êi_z�¶î w&ý…òßå‘€÷Gzc\ÿ'ÜÿH ¯Q(‡ÙëH\¯“Ö׿á ïvY[Â�¹ó©1k6oä!0}ÔR±TJšã—`jÈq‰ÿ¢|{h¬X¹É�¦»˜ð¡°Y(À§·Mf¼Ð°Õ5g@÷ºn¸ŸbB¾±ÃHF½/& ª'ËŒqzŸa¬~çœ7ж”ÎñÅ=úŠ|ÿ©äJÙCзhLõJÀ·r™\öà$æ ™Œ‡jëhÍ«©Õø+M1[ÈÕ$kŸ'Ñd ÿ˜�Ý6\>!ëß™nÚzç5yœ ô^•ÃI©j¼7i û,ÃÃI½ùì¨jL䆵Yλχee¿A¯Á΢íÞl<ªùK"i_È}µûÔ®K(€Gç}áË,zþ$½›˜e'Eð莔�6�ßL�û÷ð3ßµ©~z±œäb2ñÕ€2ÊÔ®×üÇsŒÁÁ©€k Õ1yð8¾\ó�ÝC�9›ÈQ±N ;�•q»…\èɳ”—ó£Øpôõoõã�3ë¼<Ê•—Á±¦‘åš»éÏÞWâÉK‡éˆï>uUèéîJ˜ Âï9±¬ug*¯d9K+\{4—jê‘Fo ˆ§G ãÇõr¼#²NJ…b²Öyñ—‚&[/ŽÕ·9IM³¶6Ó’Úû< Qµh¸•ï”DòˆQÑpoey�vCiÃt’þ˜„©›žBI¦4¬ºã…z«Àñ$3¬—>2éØáÿXíá4\·k W;,£Âh:ý?«ã€ý²|×¼^r•µ¨ÇŘÞY^«=éÕ¡Û໪”gTbDy¹ÐìTÎw[‘ÊôÏrì‚rüø�’BUqCU ½¾½ÍhJP¸ÅE¡Iì*9Õ‡œÜ­pËð)ì©Õ‡#~ÑWK;‹ò„ƒü-1šÞ†]áٺŢ_›1×\nCÓ>’|ò%ª°Î¥Oý{–ãÿ§°ÓÕV¬ê£Î?ód¸y^V<(á-[¡žgpBU û&�»æK¿‘^MŽÁÞK¥-Õ×'â›>«%Úé8ìt=ÿµR[ ñ–,s …¬ÝrðK»”›×åòÅçËñFûgÈše‰öàÃ*y>Ý*‰îá W\EukÔL¶#§º"ç°–/^�g|å…ÉONàX5cj–ŒÄé�)’`‡)Ø‘cÍá(ò’eà÷ÙLáíï¤8:‰œ–²ã¨AøÓ¾ú^3àž%¢¨]ûof*—ð«äxÒØ¤†�«´±ÎK ï¼.¢ÄtKŽ©ðæSGc j=<°šHÆ÷ù¿h ¶mÑ�ö×í(Æ ›Ã~vÁ�ñz —Ìyõ2w²9V�Ÿã1f,�‚A 0Ýì/m¢ü¦ÿô_Ãý2ìá³ÖÇsßú@ñ¨ç�‡ãñø ü³q-;¦^$,e¹êÞSÒ^BÁÏâX²µóø1ºÔGÔäU mñ©k%¾©ËæÙƒß‰£’ûYN¿ëÇWФ{&o¡-b ™5LyôÞ÷ÊCé)Ù~þZî°Mãö”Y8uÑk¨d³c5m€§àfŽ¢oç9Õø…�Ëk¥ñ@SªÉ™‰¯Ü+ù¥üx0-:ˆ†ñš¢u²\U‰WzgÐ�ghà±Î%bÂ+ ´©vb×u'ØÿÓ.޼²²2™ÊÕ쟼…'¡[gö¿Ñ‡÷¿r…íëçà_ kÂ+ÄÞþªüß.?¾ì^ a— pa…,-=¸šM¾âßáðÀï ÷N8S�W‹‘œh}PØ9LŸÔÀó¢F¡ü¥Ð_·?Ù!:½U·øiÆUvŸ0“Ïç�îÄCl| -Í­¤/s6BþwUy™Jíu)-7‹4\Ï¡_?àÖ# zlÑÈo笣ØÛvàŸ3 g7¤¡Õø)Ø·‹×Ûyà¡”Ü4Ò‚ó¢Mñ–c4ü½ßBä`ó蕸ô°35Ä[2ÐöÔ<õä†íºã6ç]ésøíüWÂÅ€~tó¼OK&Ó¯ŸÈ(­Y¸;ßýðä]“ÚáÖØaþ˜.NÃñ2:§3êeæâÐ=9£K?ßÅî�!ÿBÎÌ8N5HÅGEËp²Îev^YM—×MÂýÊ%O¢ëézÁz~šùMðhÐBåh:ÓÖß´9±Éã�hÝrSøP�NW’÷±õqQôÑ]Åûç�Ä�8vÑüÝÑ Èê5�ü&¦;Óš Ãÿ?¾+»5f™òã×ö<ÍÚ m܉ •¾ô:l04®6ÂËâ%Ìžåȇ ÿãÁÕ�iÙªx~[]Ä�æ�š~1‚=àÆ+vüça*>>�íÎ |:7Žl yÞ‰$xšÄÇÏÓ–¦XJ :ÊZ…18"q!»šþÛèñ?EQuÏœP„ZÇòøËá¶ö´e‡LKÌ–¹ 'oÔ Áç„I«À-giKO-pê~GŽ/¾DVMò@åÖA¸¿5ç/åÒù±éôü¶(”ñm¦ WذG’äðù`7žª™ŠgμÀ× ¢�ª+=0pƒT^šƒ.“GÉ�þb ½géÏ$? =wn.Ë¢ ?šáÍjMªªÂVè8ÂÑeV”s" î+rBöžÁßRŸ©LÔ;òRr±¿��ê.‘ÞK‘�£”Ñriœ†ôOdŸž&²šºäÁû¢~±’.ù¾ƒÊ´Q üG¬–ïýÄòç(mÈÍ„þv4ä­%f»Õñòa`ìÕÉbÿ:rÚQ‘`Pf޶Xѧ¢H`â&4Ô§gmöÂíoëÈ ][x�ËÌ2QÅóSÄbäÇ»ZÜ_Â…h�žÿYáŸ$Gôü1ÀÖÙ@ÎZ9,5¨†.çsl®¶iÚ�7®rØÅ©PeéNíT 9?,†ØßY® »O‘ ¦ö«ægCíÀ Övs)ܯ¿EcŒéxâuÎNåD«K.¬—3Í-Œàf–·pË5jX5BªmU æXåœ &Ó¬¼!Mh-û×Ìù¸U¹9DϤ£˜­5±ê5'9í[é® ¹LIå�IþèÇ» ëB¶g¬Ã”=ýd<&û£W“k?m˜ÀÕ ¤¦AÎ[y�Ï{Ü1'�fŸ‡¤C‹`ëýëøâC*&DhbŸÙvX¶¥žl<�N¾£ûòž&¼ <ï*)~,‹ÚÈ£�9ફMVÕÝ$3kwâÙû$3JÜ–O"U_Ĉõ½!jÃ’+’+¡ìæ0=ößÌl–"ÒÃ2øùý#Úh¿ �¯3ü»ÀéŒ •úèƒ3?U±ÛèóŽ:L»Câ ,È<›ZÊs ›Y”5Î!9».`ï¿:ºîN(¶æÁ'eihHHEw&=dƧi¡÷ì}ôoÕvæÔ�qV¦ò=É_š©“O3JçÜ!Ó�ƒc�1X‘¾ƒ_ùPî†bÖ«XšD¼ž ˜óžðþÐðõšpäòn¾bˆÖ®\,˜ ·áµ×J¸ál=3£t!ó@C”¾rI¡�£ƒhÏ��चNs”ÔÑ>ø0•XÁ,˜-Ã�|þ�r æá�}xß–x¡ÅýHPp�ÃBÏèsIÈ\:Hc—Á¿2 ˜ùæ0Š�Þá‰lS$2rŸáù/1e\—l SR¦cXþVX#8Ž·³P¤ÍôÚõ´³ý «ßBu®ø²+›oÓÿàáTËWPæ#“ÓwuWL¢Ý ™0Ò’„/ŽÜ¢ÒbEØ¡.ENYܽ°·ÄXÑ™¾}Ô‡ÍÖR·²ÚôŒ ÌÕÿ°)A‹fN�ßa)ô÷Þ�¸Eo2äLåÐ9:øÓ)iŠøDÝp†¼D'?ßjÈÅ¢½$SQU;'ã±Þ^ÚÞä ³§¢€¬¶q�Ð�”¡¹æìÕýA“C¡Ô&‚®™Þ„ëg5œ m3Ð|wmšQAÄßÀÙN}²ÿ”ö.˜„>x‡t;XBí:è6Ãÿú„áA]%€;*‰{p±z~Œf´ RGº‘ð¼`¯ˆ6éÐ8¿9÷×ö¦¡"Ø‹äÀ–GíT=¡Š^¼y™}ñRÙÇ °ð_ {3Ëž*ç`Arb°P/îV2{ 8û4Ëá@™Ós#ƒ„º¢ß´‹ôL›e^}"‹3Ò/âp^ô+Ó¤ éb -ýÁ|œ Yw½éÚÞýŒÍOK�ß.ÂÙ;„DãV5I¨Ÿu¡¬å…Åwµ…÷šrî=FyÌ¡ mÄ0Yÿ8}hª¡åè¾Ýv›†@¶»>„›ÌÁCb�~*»+ITÁ}S,úGyÓ¶£~±: uûÁì“ò�ÏœàhÓz"Ð]@ ¼ _¬'®&içÊëT-�‡RÇ,è¥tò/0ž˜ð ÐH×wK~$sâÁhãYÞ�ƒV�:Á¥óšt[¥)ê}ÑÇÆ�U„üE�nà^ïpX¬WßšP®ü&Õµ¶%_kGH”˜=~Ûkƒ!émÚÿ�‰¨¬³¤pÆù«þ™ó�&,Âk5.T)(šü+ƒÊ³ +t€aMçðÞnÈeÿV~á[r¸|™×~£˜'ÍÄò]싌<ÆÌ#‹5ÿº‹c6¢… $I+!nkwcŸÕ˜¢<@g„Û€©Y=:_vÿ�L.=JÀëç¯Ñ‘O@¿© ^*óImf3¼œ6ÂÌÙ«@Ü7+u´üìЧd*÷Ô¡ œ§ÄHØ&™õbŽz6‘Ï2À¸ùkarÚ[ê?b�¶Z0¿Ú¦�eCëÏkdéòyÔæÀU˜¿Í�ÎöVÇ™.œÈŽ}ô”=Ìþ£¸[—Ü›ÛD¢Ë‘îù„?b-Û;žs/ÑG?}aÎÊ»Tòd#Iv'G·ÕÒ—Éx"¦½aú�L\91¾Añ0}Ûys‘€u®[ÑûñE²¿(—úXõSŸþëäÕ.e8Sæ{\±ìív²M,^#‹nög1«ü)µx~›ò»°Yñùä¯J*þHÃSáBúãB&ù¾â&Õøuž¥¢w¦ø`þe+ìHÍd×­YG½�4ìh}Cz³ÈF ¬Ì?ÇÊÅÝ% ï–�»w�cõıŸ&üÒõ5 9œ…¶³Ð]ç+IK'›,GÀü¾,IÞ'BïËs±\÷öÇ�!!Ž7`¹¾ó¦c7&0rÜŽ÷“ÐÄH‚á×]fÜNÓÉ—^ѰåÓ‰uâi\5—�÷=´Ø?fƒìÕ!#”�3æù÷lÅ‚ƒhT°V1<ñˆÝx0}M£ïÎeb4ŠÁ|¶–uÇ(±0pÛnƒß‡š@[(›6\¶@gyôi™¯é8Ù´9¾\˜FŒW¿„ä<ȺoNë×–Ò£’àÕ¢�;/íÂ1ûïÔwzÛ|×T�&£æÚÓdKü6ò§"ˆÔÔjc°ëx_r†j/p$WœtÐ|®ôÌX†Ì5<¹®Ÿhg°{[…˜¦;,]ó‚ §4R çÆ^ìôÜÚL>ÿ©`UÇ–Ñ•�Ôøõnè §ŸÔôÍÐyñ+*—»�žý“†²fÌŽ9õ³Ó�.½Ÿù�'hד N%?ŒÅñ�â,ˆ]a ÷æáSOqœmyˆünR…уdÚºøkƒ.Ô„ø•™°J¶‚.ò >W–_û—Ϋ�Ç‹fIDõ�ü¾?D3EÑôA7ñšaHýÑ@Û÷ôÓ‘0¸Ë¹ˆw_¢·òbÙlÅðéü44—Ç/I+ w¦*±¼¢ˆoç £û\;�42 ›'';v^ßëP#r z)�aÝW."Ž4-âLÊÙÄ>P ƒMË1ûÑmšî cWs¡rõ|o)H�+íÄ(ŸePªö�-:튷ý¦sZÂ<-[øá/oYàI6sßA¬^<‰,PÅ¥×oÒ×…(at�z.]y·WP…†‹ði� ¤zÂßC‘0?&W»c×Ï•DfÖNjÒþ„~6*'O�ž„L»o¤Ór!=µ¥ÿêКÇ0ä©‚q]L°ú$\®ÔLWn§æ$¤=Žþ�‰mk0ÉÆ¯\\µ�Æñ=kE‰Ão™ÏÄÐc€>·^Kv ÛQÏ7™™F�X®¦�¶€¦]:Û Òo‘>�Ôs´šœ‰he—L ÇÆ�K /ù"ÍóÂÇû†Hü+0{*‚ †åèixî\§9¥hþÛï1µî…Ìù«+ñï)'º3-B] ¨£ÝòVÔ Æ¸ „Äo5…í»P_™ylÕ»æ�‘0ÖkÃWŸ t±é~ŽåOw�|N£bâÀºöÜ´- 3µO¢Õ5g»û“Þô´F¡—ˆó„פ_Ç5’~Pô ©%r®XKÓ¢á$t8k\îоÙ!Œ¨ö&úlz>�Ú<ûVþg}‰ã]«ÿ°Ú®RWk¶í.†Ó fá:&�9wX�×^#õl5¹ÖŠëÖàäZ>˜(^@÷Émdûþ­P?°›æQÞ§TS:@e¦aPk$§¿V‚¬It½ÑK�Ä[¤ oËl⯕È0jJÜLÅxøö'“TöS¿…•´-/’ åæ2»•NcÂÂB:jáEö+Á¢Ü,¼6k:FS=áZ4£/Wî‚„»òè¡äO%ŽœÄã.âØÔ��_ͨÑý*²zŽ4Þ½Z‹{«RQòl ,Q¬ƒVª�#—‰TÌCܬ@ÝüH'•ç­˜@X˜½•x<#ݶ¿¨ø½¥ì�ǸN:{ÛYÆ[3‘†í“oXõa„cém ûNHS.É!ýËí±1Ø”ª};HD„àö¾§ôÃÜÀoÞ†Î#ëFÕhTÉ"¸zh�Lš:$Û¾RËíCDÈþ=p<â &ò‘Y?�çq'Æâ…¹WîgóÊ7N˲/¼ŽèË·Ñ¢TwJg®BeÎ bZ7ˆZ…yô™r:öá>ö|Îm†áÞ"^?ŸÑ»í‰¨V¥ \«(ÐÿE‡giÈ–œ¼“BÔKÅ�ŸÖBlœ(Ì?7î’8üÙãÃ^,Ý…]»æ÷Ll¤² fMê'ËTÏ“KOc ÿõWð™}¶èè@Xðeb�ÿ™hÄ¥³Œœéë#©Ðväåô�¥…·M ák>N4(œÿE§Þ*Ä×›NÓÁùŽhuù4uäÂ�bC"²>žÌÎ(!·²Ó`ni•ÎZ‰">¿é®Am(Y¸�]kØH²å(nœ,‹®^Á 15¹Œs¤­Á¢î$-ÑÇSe)pzò'²èÍ$�jñÅkk†é±ð¯4òh<²…Sáá?Q`÷ê#¶ÞÀ¢C³Qpÿ¼ž2FWÑ.l]÷ÜøÛŃ1äK|ßÓHÝq?.â`f{*ëyd¬�‘ç)^“äeÙ%68dtâÝ8ÛÀj¬]©ÙS%t(ZI·7 ‚ç54èºG¾s¤Š-" ଺Ù'Øu¡4]Ò–¬Ã“� ñi÷6:ºaìÕ�e­'ÃõËÌ,/Ut×Õ„ýj/˜³~3ˆÓØ ø�ëŽNÛËi_¨ØÝK¦›ÅäQ¥ô*¤r>·œ€îÞ�˜Ö\H9ÿ^1]N8Ì�åüs·„šö,:¥ÎŽ~ZòǪVg#z]÷¡Ã3CY[¿íDs,Cç4`�Fy7˜·fšcÒÓ"84 ­Í°ñfúDްc¡CÌ÷ve0ºó�î ‰†¦i˜ô°‡dÿÒ�yê„ÕjåØŸpAïë1hœs˜^¶Äª PU§fäHÒ¡ÅhÅc'\fÙ@ÖÏË¢µ[ÕàTá.¨§Ä¬WùM¼B³™ž¥¥4Ø=‹^é9ƒázøæ|-;;‹ÔžOæU½r§Æö‡¡ÿÓ\²ÅÙ³Öbïû¢T…ÐÏž ^  sÝ�“¡¥žDïW*)Xå ù‹ €òi©©wÕE­|w‘/b ØLÈšnÔP=yx‚°ñ˜:¯m>B§¿ '몮Ó{5"ñ9VK¿£iÓé剻º#;³öÏêå¢P°d Ž^?C�ÿë"óÎÏ# !N8¦5ƒ¤×ÁŒÎi|Ó7ôÁEO(÷­åAP쳌" 2ˆéÛm˜mñ•ìT½F­>Èd;ËÀ0ðX(jQAo°é+¦J4å…g�†štàc ‰”âÏ¿¹• k®G6oi¬šð‹Ë4Yâ*é�ÝÃ;×äCöxzQ¹Šè»´�XEAÕgréC©ÊŒ$o¦£øð<à A Ò &wöP¦t„]§®Â_¸< eŠÉ™à…�X;—­žµ™}VÌÔå‡([¦ÔgˆÉü¥%yDZÄî>i{¹§¬Îï¿LÀ2/¢#x�ªkw�-ž0à<©a§P :¦aVœ~LZDƒ`—]!+¡’@pp ¹m�C9Ä~46ž ¾#äóýç¬÷­N)À ¯Hg«3é‹ÂÈåÓà‚U$\ÊCá«1T·Ù:çþ yËKØgE&øÆ8×MÑeß ž„ݽ†`pù0¶�4SãQkД~Çj¿8É› áÔ_-øª¥‡ÖåŒVÖÐÚÏŸ©Ã¬Þs°æ»0‰?ì‰b—Á õ�$ÔÜGžÑ­x˜3�^MÕ,SÚ˜âA3 ~ߢ‹“Yî ¸S{“Êçx#�7¤&ïu wÑûvŒ�ù“ ßË�´ZB[]äO Ãæó»¡Ë¸…üô…�oÃa‰¬-º–ý ¯÷¹ccÈØ`gŒó NÓãßJpóv8¨wÌåÑô�1vôa<ˆÝ3„7ÙITía0ÝÿÅd¾Ê wÐ žu�8nv…íûžÑeÓ5I³¯$®šVK²Œn°5.ÿAmÿês´‹$gf Äê\²u�'ݺ ‚v-<ƒ>÷ß“ÛS¸¶âÆV�‘Ó¼5(( Š ƒm´9ë.ÕÉ뀚Ø}äŸP/íz'Ç\“?ˆæÚ€Ý/9”NþΚ•§áçµ]¨×XEJë ™ÞªÉ0;;ÆÊé¡�$BÉd0;—nã¨**„�±ô¥ê²Ò÷ çlÙBê ekrr@Ùa ŒO G‡Ñõä× SÇÓU«U'kSõ$pùö`·C&]®ÆÅaËaqçºz¤„ÍÝ1vÞa@dI%_b`[‹-y¼©½Â*Øw%…4°f:ºM´•㟠’ºy”ô5ÏG¿šãðBt„o�ÿ7,{jÞfúku+ɹ/ƒö'°f“3ÞrÈ÷*’¸¿ƒ™}Ufm»qb-­‹½þCtɈ-nŸ"�景‰Qû,úeŸØ8ª’ž"!È�#ŽBi§Æ p ¤Šù?Ùhñ#w8«ž¿MA™…}dPz'ýø9‡~ÜäÜe,žªSÞ­0°x�I› aiÉ_RP²‰IoŠ'‚2Xýº�¶|¤nö±xÂÛ�Ø×´n¯/™äWŽ[õÔa8\—+ûF“?G’”7™Xûê:Lì²ÕBì8.Jäé¯�hçÓ×ÀÄßÃØ_xXè„Μ‚³F¤ðÚe/¸·*æÔ[á·¢DÐç)¦0•/ÿû:’LF�ĤùMÖzÊMÔ/ú @èMf.­‚Ŧrœ±}ã4ÄQ þ 0�Ñ9výixn؃[§³ÞËœ¦çºvÀ-ß#t­_-èvÕáE§H•O5¥Ô)î ]ý¹V]ÝHtõî�œ+#t°v<±˜5ˆ7�ßüF,ð¶Þ‹É8ze™škOŠE÷CîÈ!XÇSæ‡ÉN¡G¾% ­Ð-PYví6mƒÞD”Í‘�]ƸVZ£6yBX•Tìé®R ™Z˜ »ï>'ÑÙÇqÑCenÛp^™<ÚfÕö]ôàë4¸TsÒÚSÿãfŸŒ�fŸàñ¿ úûGQƒ4†’áÕÐ"…£±å°éª+xwo†Ž%¹ú]›—2H‹Ì¡dÓmºS\‹ï.*Ím¿7…âG+¯G Ž?ç¥\åmºçÃ.M¾ì w¸¶<ÿ»M¯ˆá>iŠßJ¢Ü*>³K™ÿÎó1mœÄm|• •K~ óÇ4ô³ÄYSXü`iÊMÒíÂÍþ9˜^r¶*712\|»ò,QkVÇ“ñSq_zCõ°Õè9ÌHÇÆ)ÈhEÔÁ½â_ð¶y9vô=¥Ýê“øGC;©¥d6„œI$ÞX¾«Ð Zn¬{Æ<þTFNdÜ¡‘³ áÍ3Ô7®$V"; £ß‚”óâ:zÙ^&Üh[‰+Ž\Å"�'6í™m>o­ ëÎz1?¹[¶ °/×®ÀÔëŌɃN˜í` kf]€Öêtj×unt50s»3`fFQ(/Äõ-øŽÃDõ@ d€E›:6Úž!s8ëad{+Ìý±gu„àïÉóðø@)ŽÏ" ÒjÐ8"Ì ø+Æ�;ÑÓžÀôçg±37þd)âY›M8zò24–GA˜» –“x²•c€i {à/E¾¾!GN p—Ô/ã'LOä?Yh†ÿ$}éÃŽ9˜/ôj·V�ÙµûÄaŸ,÷zþMÂ�÷�ÙÞsæ‡àŒôuØ–¿—ÆOáK,Š�uk֢ʮ~LÍñÇÐô`xF¢`ß�)üý5×ñîs–Wœ ¢¡GÑÊ¡ Äö¼aeŽ~aƒb«I˜‰6öæ§9µp+–åØöÜÁöߟHx9Ô‹aîbW=ØÂžò}�zõϘú*$Q#�ÑzDE…éC¿I¤»K:g¢–ï\P�^®rfÜØ#)ì²-'àákèsÊÂæݨ°Jój`÷‹°ø5N/ �Ôy^н.5÷7Q2%˜xœŸÉdªì@¹Cè0' ôÔÓEú ±�û¸•ôhãkzm÷d<:4™Ê¶Ô³;é#öãh/–�¾¡oÃÂÀË:cŸÚâ†7©�¥w›q«œÍŸcÒÀ5|dó nãqFÔ„øJå!øÐÒ�kBYø8Ñ”Rå>Α€�ýÁøãÀjfö³“,J6aèÒ`)} kí¹üí¿#pÁ¤1òü�*Žù-Á^M 0lÆž™Ë™øÝb8ê{Ö–nfœb!"þv¹ø0•T�»åKÞ¯Îç«8§¼p²lpT+˜£¹j8š-.�ÁÏKa4)Ú &Ãf'1j²q�@ò·šÖ+ÛœjüØ~•<)þGwLŠ'n;hïn€±ùªÜœæ(X5v^™Ê~(œ&½§ûØ#«ì@ôU­™yŒkëö»òmøsj*¿èíft�3Æ3ƒs`ëòf¼Qø NݾNA3ùëçÈc\`ñö">O¤±lU6¶ rí‹Wð�iÛròôÜP?`,—oÍn\‘- ÓfqCí»q{j¶ð©æÇ…¸)c˜“xLÎZ=‚MÓ‡Ù¾5uðé¿=øgk6«òŸ·D¥†š][ÙÒi‰Ù[éÒåäÎrgF/B æ7Ÿ€ò­yºâ ÒHƒUÙ[ñʼnk 4¦H/p2`}Ÿ‰®|¯¿*ÀŽýס¬LŸËñæàíÄJ þH–•š@7_ŽúfÊŒý&rÿöÀúÑ F·® ÙŸ[Oàë‡Ï˜_áã2Ú"¥È—ŽôàÔíÛ�×t¯3ì‰X<pSk Í4óBê©Cà#ò$­¸9“¸[Î^&2 H÷ñ\ت! ¦[ÒaÞcrþ·Y9c'êvÏæ63®8VAž@ÿ±cðï‚$—sT–û§q)hœ¯ Œ“`^‚®À,ñ³dȲo¥üûâ%@…(Šx¤Óàјš. 9¯“Ѷú"¼äYâÃB;þÒ‡8½K’;­ö4û(„«ÿûHæ–ù ùp +"|ѽ¼„èyl!Y2�pë5“º ÝX‚Ÿ×—BÎy°¨lÆcbýôö¹Óäòƒ+X8r¥«Â–_"Ôòh^¾Í£×Ý3‰E…)¶ž‰I¿ÍÐ"÷Û’Fø³.,#¯¼i[î[8ùî>mù>�«+Õ þ¨âà‹8ës—Û Ç4‚:¦~Ä9k¶€ïSi÷à„k†§Â‰Ô1ØÎè…âƒr-Z{¸�D¶Æ ì»(òŒ~&O<üè¢m§h¯Zx3êx»é];�¿Ã±´+û@÷ÀUÈX“Oƒ,$À<é<ýb„’Óà—6‘Ã�¿yÛo@÷ãÚ;¢e‚5h8DêN Ö²I|æcÿ§P|þ&·'É�íÇÇ™pCsLÿqŽÍŒÂÑkåè<é0H¯'ñ—Œ¹Ç¿£ 뺓™ª#ö8çÅEN”à¼C–óm3ŸûðÍpÏÿ ]Vÿw]yDT€ŸKo5jà¹×º|ùÛþôÃ6‚WÌChŒe }~q#ÿ§{*Λu£ý„ù[7n…l·{˜ûõ)ïýŒ�¬¹ÃY/È´ç#ä¹m6›\ó3>ðÛ1ÿ…¢Ë˜iÀÌy@¢÷�cÌBEÖ ¨6çNAß Öíq!2Vº úˆé7Eð~›L«ãÎâÃ-•„o~‰„|Ù@;Ôk`¹Yv›Öp<\ݘ†:Zµ:KhhÒD‡ “^íD<»÷6¼K@Ñ/ËñïØ!4)îÏî+„Y¾.ý×EƒFSè-Ñœzí%^ˆ…ÎÜBºÝB™/$ —¶Ûr+ac’¯�—}ÉiÓ5˜´K’oN…ò¥¿@¥YwfÇ¢¢d´æáþú\£µÇá¢órÐúé� þ¿°o@üÕGNv&ÆÆS›úŸ`žNU/1*ƒ‡¨Ro½Tç…o�ï@ àûã]-pšsw(§ÓE!à ¥ÍíxØŠ�ÛQqÉzˆ°ß ¶©ö(îÅRJðJ0›=cAñÂÍ2pÊÅ›þ&øî]?FàËöDª{@Š+ù+¶Ui’cßž`àç&œZè†û„Àfž»[ö5Š€Ë5²°Z ;ü®ÓÅWI ™ÅWu>íGËxÑ.7ºê#͵ͦ.«Œ¹×·  Ç 8vçõ±O¡÷š»yŽ¥™7­2|¡KÒpÔò©zW‚d–šŸX‚NÎ7±³ÌVWÚàþ#`¶é ŸºöÚcuº«i¿â ¹ÿ �N½#Ì�O“†¼QÐÿ=ô<¢Òš å6‰þè ŽHc?ܱƒÕg^ƒêu%þáY¡|E�myý4*Q�ýK(÷Ã@‹ò-ñè\A¾Kåü<Ù‰îSrÄBSQ Íúžr9¼|®FK—îä׊Ïç5ŒÇíBÜ/¦Fxh§ _u–,Qk…Å ÌÌÖSèzI„ÏlqFFöÝh”ý�a®_(´Ø@î33pµ;¥ 1ðÞŸï–á¬ðX€šSE m�Z6\µ•ÐRÒœ§dâSÁd¬5§bAë‹å˜1l|»NºýÒTpˆ{D󂥸ÞEð×k‚•/ü�³Mÿ„UÒ˜7Ëàé¼Ch²[‘kaz˜v4U>Ü„?eà±õ ™.õ�X_ï@U¥4´TË£r%·@þ•&r©ò]¶³bº~ø·øUñNø1ó •%“i˜{8‰=Y±6ÇÁó£6·ð¥Š'Kr§¬n@K{¢ex’oW’Ó>ŸÈœÙ›Qçm2zÄpaeuéZ}‹Î5ŒŸÝq‘Θža@¯ÑËÇnM8¶?ák}ªÒ ÖK�Á[ex©Ïp‹ý½`h¤‹MÓ¸†~q{¹�M`è§övñNKDÂÚ²D"Õ›DÛº»‰ø[ClXø ´¶†Ðn�b;n‹Obµ ê£#Kéó[_N¼Ï08¿_[35gñç…°X1/u»y&ÂÀ×=–öß ÓŒºyÏ-P¹F-"ë²ð²ƒ„à'ÈJEùƒ»ñÆíLc€ yzÜ™�$T«s>Cün=²˜CèIà†3˜›¸†¯Ü9‡›a ®&¬æðN;P‡û¦�õÓyðàœÞ÷7çiy¢´>j~½ƒs„+ñZ‹Îà3:m4'­¶éòþ×Be„dß°çÂÂP¨õ�Ďׂ¨ëþæŸ&'O:ÂãË  µ›+XJ‹Æãq×ìØ8' ­/L 9Ìöä=#*ä˜:Q pÆûtøë»%¸¶ò÷é¦,»£¢²Ü²ý«¹£ßoccçFºufeòÀÄä6õ1æ;& ã4…=tÖZ:àg§ÏD¬¯6¥.ä(„gð,�‰à‡§©“é$îÜ€tp¯ÖËWPÛ(Ο/MÙþf»~r÷·ÒâïÂ¥uñ¨ù¼›Š&ÁÔ›"ücÕ÷ÐèÈ„³dÃNûDãH)™\_«œàΟ(`73á¶`[Ò4â›#Ô�YQD`çF,9Ú�^ùxNÓŽÐ…Þ“øRŸ’hÔõ‹äÙÃ'ì�fè .cöN�ÅÙ} ø}öAñúd•>3~ ‡RvCêÿä[×8$V~'?‹|°„ãù](·Â˜ÈÕöCsMŠÊáU²�¹�…a#RàìKfÚeá¾äµXk¶�ëï¡S[;é¬=+€w´…œÒ©g~§Am8ªz Œ“EÌAZ™£‹îÏ 1µæ|ýE¿oìM% TÿÔOƒ¬¢È§†&ZiïŽF6„•ªÁèvæó S8”ëM§¢{ßF< ÞK;ð&± ú‚!;½.~±Ë°¦s”Ýv›QÝCº]ƒ‰¾› =òªœx‡™ Fs È(bR€ º,«D“·÷ɳ\X4jÇ´„E�ŒÂ}°måK® §k®Þ *¿§ è¹~ÜöóÛùœÆ_ZB@$’ûî› ÚR´’Ýq|õøïfÃç—´¹§�ˆÛû¢G‰9·ðò"â,YG¦NüÓ#Ùí¼»òuœ¦‘ͬF mU�À¡qW¸!+‹š=/éñ7mÔz<zÂr¨HÁâ�(�§Öç�ÌAK�äjÅ ²Ÿ·�¸¬BMC(ÀÀ™&\¦hˆ.ó@ñéRR×B¾Kâݧ�!vÑ{rõÊ �vÖA[‡pYRæ¿�ƒ‰Ä—M¼Á×¥Q8ç¬ wnIÕÛv‰¨ÿË«Ã*ö O 7Þ> 52g0ø@q�Ì ŠRÍ`â/A�^˜aÊp6i•ƒAá!ö¨t6ëÓNfÿxOnp«˜wË�@ÇX$Ú_#&gÈ“:iÞ�YHþP !Nô°~ =ocè–1K Út�J]yÛ”Q ¹“—zø Ž_hgœ+˜¼Ç…ôµÛ ¤4_zh&¦Þ{EQ+׫lFø 8Óð×–�jï8 íXÎyÜÒÆ+Ô ä©Û+æ†@(-.ˆ‚É1­Ìæ{mû†Á)MfX­•^;MS�RhPhQl’cîn^�.Î Z_�"YûdñÁ%oât<ŸD?u—|ªUZÎþ¾s’2sýÈÐp.ŠSe’ª‚±Àc::›XLüÓox»+Vf­÷ 3Œ�÷ꢪ ù#ÉÉZ[|Ë|cÊ2´0·j59Î"!»�ã‹O<ÕP3-‘ÍÙ/‡6£iÓ_5¸˜;á}¹dŽ�Ï•ñ±¡ˆl\cÅÞäÊYFõ×°S¥‡ÃŒ±).�ʧV÷]JÐsTÞYuÑÍÉîP¬cH^�ׯg÷øÝY: £ŽíqÀå�7}|M“‹K1Sò!ѧT`Û_¢µaîÙOì§Î¤ó�åpÇ‘»pÓq¨j£ ÞdyN5]wÃ<Á•Zøtæ5�í ŠSÜ8mN?ÈÀ°�.ª�—u¡ES\s‰ª­zŠ\� “Œ;~šð¡D•‰¶i±C½­_ˆÏ¤Óx~³$}Y° oÛÿž‚ÐÈXÞTMw]ˆ¬VGi¾y_®ÌxýœBDäP�àRfÑdðÊ“Ç=îñD2*�>³-»>>l_¶b<‘¸;¼‡²WÊ´LXá‰vj½°¶ÞÛÈꯑ6â7]}r1|ÖÝ€Ÿ†#ÈŽ‹S‰#ýó„‰Ô…R˜jð‚¬²Ó‡…}�;I*Ñ‘T~ #Ñø‡�Ën7y²¾*• ”8€¤©(vx­Æ”û è±­ú½›¤œ ¡M¥ç)ÿj¼UBý¾5еµ¼·³¼ðÊÌ›¢ ·zl!p044àâ+u¸\¾ˆ@ðwrA쩸 ¢Æá Òˆ¿=åÙóùN¨³? ú¦s­¶�ãåXU<{ëµ}´ Þ2Ü;‹Å¸3m289*•°þ÷ñº0™ü³¯Äýo¿‘èQ/ìදl÷4!ý{—Ü|¤ ¨*tJœ'Ûo�I¿W Ì5Ü~}”踙€sÏwä8ÚNXÌtšQ„§[v¢Ê1gèþ.Ìœ„»jrãM¨AÖä$´Ž‡__ZÙP i.ÇÎÏôÒȪø«7ÑLj�.“Æõ.l×s†¾ˆ;õš†ppÀ }*4± Û?+ב¸„J€©d´?ž–†¸P]\Åqò¹È)‹ò‡G'ã!¦OÝšðis4‰Uk''žåál§‡Œ_«&ýÚ6ѬiÆ !8—FÊÐÜßçQ<+tmÁêY7gÕ�(tyñ“S}Ë‘\Y~¢ô¦bw„l2L„Þ=ðoh9gƒþOºÓä=½¿8-æ/ ¾9�30¿ò¯’õ+éL»lê‘§ì¥xŒéô&{mÜèw? ª|S—È'IJÁ•š4¸=“V}×f> AÁÁ;ðqq B¼/Ê[\¡¢  ø(^Ó˜Ž,o èêÍ?;Ô—#†v¿éFŽ_daÇ”ÄmÃOÒi©F5Γ®b}ÆžCUr ÿ÷™š¦§ãê{ÑØq½…þãۇ1êØÛ˜ì/@Íy³HÏ^!þVîk"Ð|†rEÐÉ-oˆ˜�yÒ‘ÔìÖ,¨�¿�SÊJhÚ0ÕL¤«EŸ1Þ�'`±b(áõé‘fR ؤ:&‡AãŸ0¿S‹ùp?:®ÜÀ;ÿzY⹃4vçp—¢}‚,tÍ�G+C(êNayu\&¤O7¤BêŽÕT.ï6µ¾ð�Ž÷裈”~í<�>&£ùL]\Ú£M_d×ábµ ¨þ~‚ö—W‘Mó¾Ñç dðaí„“ŽòÞd*“o�?pKM3 X-ƒEÂ`Ú³ƒªÖ·ÓRõÝô‡À8±Cå CX¨ö 4æÙӧ瓨bŒ8ÜwðçÜpZÀ�[~¾¤Äίn5D ±Éä“ ¶z,B^öú¹m1ätü$†;<ñT‰ý‘UF•’Y6f­8=àz+¿Ó­§˜Y•ŠÌºá1k¹ÂpÂg;¨4˜£ßœvdÅ8¹± ³„èM•�ð¨á%}~³•™qñ Nm?ÀR²�ïeÈÈý\òvÏe´m‘`ª—ÏF ÷*p=~Ÿö7/Á/`a†<Ê[>Á^ųðï¥ñ´e¯Oõ)¦ÇQ{êyÒK·ö&¡ƒP±ýø—žhŒ ßúeq�ä{Ú/  Ö¥¬ÔÊfÒöÀdbgkéߣ øÌTóƒ‹P>Çžz×€ÒÑšÖg€OÓüQ}œâµÔ0[¡Œ mz@›èÿm d�íN=ôÀ²/¤K2ÎU ÒŠÿ¶Â¶8îI� ï:ÎûÒ˜Ì+פx]n _v;² •–¤Ã#ß먡lˆRÝû@R¹#ü½ÈóKf fN僴.ã.îXíÀ§« ¦íEtÐÔwÁEdêÛÏÄ~u?Ø"½ÃÏÃ)XBWDŒã{Ó òàòÓRѪ!EO�›~i©ÎÜŠõQ¸x©µ•Æ{/üèéBö(¦Ñ·=õ”ï뇋·Î‰e©tÆdÒçwœºÕm!ûå)ö­&LR-ùRÂîp8G°ÎÞ±BÐí%Ê‚ ¯ÒGóŠP3Ðþû·=9b(=7.·®†Em§È¶Ø 2.RÇ8ýeÚ-îЈ%¿ÈW“0,._E¶Ý×åŽ:žd´OÍž«>ÙôßO’ayš~[Û°¼"õ&ßgf}ê�¡•kyS3_Ñ25ÂIX؉¼ôŸÖž­pÜl66º=¡-QVLô{M<Øql)5‰Ò¦Ï‡ÓðÚ·5TA0*‹O’7MzÎNœŠï^�ÓóÙæçsÙ›m±àü ‘[p|y+á·oÇ=g2ÈžÝ ðð»Mø@£¥þ€Øíý#‹ö á¤iÝŸ wÝóh±Z ¼k˜yy„$ÏmûÉp~»ŽRïÅW‰˜`3ÓSzà¿jµBŒŸÒ‰¾»AŸ¿Þe ’?å«ðÇÝq¨ÉQ‚)—AÕæ465zcßI+È›&†ÏUÅIäzCÎF»ç¼GEI‘«6ß4þ˜ï›‰üK?˜NQÐö«‡´ \E�=¯Ø-Æï¨×Z ì:z X©÷d¶™þH Æz;%â°L �ÍHD%Áktïœ|z=LœÛya/{O¤€þÓI‡¶RNf8Ø´[áɱ#Ô0ð>çíát¼¥àÓ£@šµ^~?)ªà’­wÀHp –ìÁ‹;âiØ4 iî «½—ÜxåûuþC:5îó`Õªvµ'¬óµÈçbg”œÁTç­Dmã¹hLß0Ó oq|Ô¬qÉõÛ設ËúÙms$ùGõÖ�±Ù+ªs�OÌS•`äŽ"ˆ%d€uOÄÙ[ΕI`—ŒdCÄS‰Ú�_/�{iè¯3åãþCKÿBˆlÍ‚WWÉ�e%ªøC§š`Ú˜;òÔ€^±B ö(ÊnÀ±Q ºtJVžÜÃÑ0"d­æ||,€ÁM…SíÔ="ÖÑôøÆçôô.cb¾­ÐƘg\\¿I‚üâá¨G Ó3�ß®f ë_ÅÂ$9A¦yÃF²ÓIÛ¦…¨ñÕòu»é»y’8où+R gÎN�èSßÉÆº™tŽa2(L'‡‹# âsy(*@oøs0Ú˜@I�.ã)÷þ BñÐ4ö±�'ùÖ;L›’½÷k©Å‰ÉÌIYi®ÛâŸMå é-ǘ¤9ðv³¬æÿ¦å.'Ñ8§Œ$¬ÖÇÏ/Çh>E6ßw;9Öó‹<§ÌÕhI»ŽÏ­›ˆ™Ù6v¡ì"’Ç뤓þ|¦oÄ—L9·¢†oP±A˜½Š¦/Å¿ÐIOœT@B ¨Æ¼º”æ¢\ÂNz—YP›©- ©):|²�É·ˆ1£HŒPT¢ZÙ5àuo¡qNïNòŸóÖœÁ]ÃË çî¿n éÿ+ü7£Qg¥hGd ¼4a¶ÏÚpýˆHv\â;FÔi³œ�½Hº‰Ë»÷–ÝÍ0=¿UÔ¿Ö‘7øÅøÃMxõs»´(�šÓ_¯ýtÊ_‘i<<¿™³[R·¦ b½]2®üûÇÈzÖ h]—¿f²)ÜñòÔZÿºc§@–qøZ�{…y{Îñ9vûh-‡Ú´0~›ÓQ:>G›Êþ,ƒÉëÓùó~(|§F•r›†–±!Myœ›ù ¶>Ë‘&ïÓgõ[<(ËÀ7NÆà¹Wàš©‰+ºó¯MÃaw»ü´E¶cà"fÌŠ¡?Ë,¤a¿mäÚÈ‚Ïo'™£³qœa yœ ƒ²‹ಯ %ÖEž×ÂÕ•î¬!+ŠoÖdª7°�[2”ʆÁ6 šÑ¥É¶úŸÁ¹¯iÊCpC—_·»=&âýìGœ¦c OšCVª´=7‘ÍšÃìrþòÙV¿YÙ¹M îë £w—¡yD#,N3§»‚èZD±�~²­UYèr+>·õ’š™?Ø[Óïɨžž‰;ÖXÀøë¯¯Ì«rÏô<%Ó€¹ûÊé½»6åX°¥Âƒ0$ýÃx^èhÕ$�Õ…44û3æÍ¡ËÙGë lühÜØ¶ÕÀº j³±2Ï®ªã¾î)Té«H1�±àÕ�ƯõT„­o•éû­BîN‚žiÁ N™£Àx\8q=r¤˜}Τº×GÖ�ýêNHHÔ…úmçpͨX&Ö“AÊygÐä]{šÑ«ú�ð¨Òƒ,•JÎ.ñ~Ð�y’p¯½‰E\Þˆ?$¥(^° OþDckÕ90ü<­ƒ5ÈÞÿ{·Tvï~…©Ìµ…ÊѬ(O$¶A‰Û<Î-» —f8‚™…4X© ã»9o@¦2’„ÏßÅ‚˜Ff÷å'3mrrÎÆ-B.dôÀ «8P¸ŒŒ, ‚» ú$yIŸhÖF¾2÷+ƒšš"V§¦y…ïû{�ÛÆr—÷ûÓÀÁ—ð³�^{;xÄl‡Ò·ÊÐ;<Œc}Õ +é:M°.•dœs5=[¨M,ß«5µâ†nÐ5¥œ¥DÍ&aI/:j^É<›óX__-m’†[/>qm£4ñRôcNFx îYSÈ*ò1äÈn�t©¥ªÃ’¯oÙÄÓ/Èâ“8ý}Ûñ;�³þ§Àgîž31 [öxaùÖçûÎLJÄEzWÙËÌO´2&æ·‹ ¡úÛ3Æ‘7}áÏÜ*>ëo MU¢¿Ý³™�ù-TùçM ~B´éf»óÙ J”.qý©ÆœŸ¯&iý‰fNæ¹pìf¥q�á\È\/6‡ŸƒC·È®�cc?ßA�/,á�{�SÑl²µˆÀÅ¿rÈzÛúP-Æt·SÒ�‰¨=õ6K«âíÇ~¤CW$øÇ’ÉLUfÛ…Z$ýò1¶»¨Áýàã4`ù›¥T•27]¹ Àk¯eÅ<3Ÿpf¦¥Á>žív©^”zŠ­ZÑçŠ×-Ð)ßo³èkÜ œ›|Ä7¦€‚G0üÜqý¬vÑ:nµ&‹’°{¼LÏâ2¼Ú8� tÜ…¦:L�ß#u,f¨Š»." óžæ°ˆkN»ƒw\¡og:ØÆešp£á4¯X9žÒf.§UŽþ¸Èv+))Gp×GSCÚÛ;Xý1«G£öáöyìèü؆=±Ç`žcmƒ¿Žrí›fAÆQ{Ü’O�æÐÕT£ àÎî3°ýi·'Q”0ž´2n²" Oº*z€ÍxêDë[íhgÕ5v@,˜õf<âÃc¸±£LöùbV·ÖL ¹‹1Ë2�ÚÌiÆž C’|!û<•�o·O÷ê(A†k0Èüå“çQxx"ûÓw�%­E‰F0fSîìI`ïã3 Úc/JTÍ€0÷ ü•qúd½^�Äò«9cåÌó�6{Ûꥣ.àIÅ\Ðö$áh 4µkâT‡KjC3eÈçõ(X{m,”�¢˜çqÝ™ ÎOç‚@ÑYòs÷§­¿R¨'ý1*ti’TËB*=ñ�å__‹KñôîÅxWe=¹ 5ÐÚ{šð{«µÄH`qy�ŠZDzæ6 PâÃ0:Ë,×Î!1õ‹X9I¹vêä‰X™lB:ù�jÆ Ã‰´TØ““пÎz³JÙ‰ëØU€îz¹Ü�nslZÔÏl½Æà홥’l¯×¤;ÞÓ)Þî7³½/ÂûEؼC@{ƒÂiãø›°íz,e·˜ˆQ üí=RñlåœxíI¨%s‰3¨VEÙ�!JN«§>Ÿ»ÙWÏÎÆÑ[1;še„2+uéÄ_'h›•s’Át®=±±êàYïÍê÷X¦úkÿVÅ¿×ÍÄPë ´õ‘,�7>IcOéá°Ý\ñÚ‰ËÊM…Ÿ\X°5yÛN‚+þŽ�¢=æ¶ý`êƒXC—)ÿýàYö™°ð£-õî~ÉFÊRá✰Æ6êŽ?`#ޣةtö-RžÈhP³C¬V]JÒaôbªÝ×Î*ž+�ë+šèu�ÕÏüžÚF1]²¡É#¤Há »P²¯‚~tüå½È3][“E­ð?î�K8=îCKÔ ”ì`Ÿq›ñ±ýg¹–1§Yà£U$Øx~ÍYÈj¦JAQæV èYŒ:ûÕiáèYdÞL¿c$Àª8n&Õ±ÛUóÈ(â %ßU¤”-àØúlRý»”Ýô– £-ÊPqM—fŸ|f|Ìá³Ï«d2£gcèVe’M¨�±Ù{ᑪÄv†ÁøÂ2RÎŽ¡›Y‚ÜŽyÊ´cS›2a'ÅÎx½N© ˜YKÍÿVJî+þœyÖ@;Uƒö ¦3¯' t×}KèÖþw&`œsž9HÂF©×µ>¹‚øÚÛ‰Þ^k§‚¤$òÝ8¿Þ¤’§á¤­²\�+Sˆ©›=—ÿàgФq G)Ñûó_©Ä-ßp ;îg1³™ ¬îj:ÝÝ¡ õ¿YŠŠ:ó8bËÞê­Í\)A.�Nó†'Aà øµYŠ´�ùâkv¦�‡gMñƒT0ÛÿÂ�ä,CùýÅŠp8ÂØøô _ºX6ÄÄ}ÆÀÞ:úÓ’¥zx`Ú·w&Тg^')çƒ!Kñ Í“áµôÖ"ˆÏ·îÄmqmLrd%øw‚§I ´Ëô;·]à?–L’¸ua3û­¦.J¦›ªgpbúl˜�wŽ¿Ô¶Î:‰1›8¶wÛRx*3�„ŠêØk_&wZ¤%/óÉ­wØÞú¾ü?-` ž›�¼2qÅšé4}ž ÷0£€OwÈ­U”þå°ÎÅxXtD�™¹ÝÀê. °>\W_ɳeíXýÛF[…@WçäîÌ„åG,@[]ÀDMƒ‘îë±p#~;ï’ =6‘ä¢ÚEÞ¯Ðù�'tL�…Ÿ3ë'½ø®GâärÁDp$Í?M¾­Çøk‚IçÀ>²Œýƶ:=‘v!ö±Ë-ʼnj_W³¬éjß…ºâ¯C%Páw¦„‘†úgæøë6 Ö�­«‡9UÃAæ ªdoC%ý1�ìëAεŸ8(º—Ǫ́«Ð|žíÿoc>Ó/Óžò PÙœÖ�OGßû‡À¯2i­žÂ¾ÍP€BßšBK ä‡3]—~K9µ”/SP“¼_ RMàŸMð²^üëýlòÐŒóô€!»d6Õ¥Üx߃9åó9¿eÊôÅ$�tãX›áúýH3ƒIPâ&kÔ”g“zz$eUcQó¯{|ì¸ Ül3Ž69mƒ/í@pýov«HÛø‹à?ï֯ᇭ=ɶî”.–¸20Û¤[‚Å4K¶fi6”zË‚üúô³.¡ËUþ¨˜TAn lË‹"Vþbˆóåì'»`lø+>½g�n6ŠõTèor û.6Œ‹Æ•r‡R<8ŸìthË ‚ا†p,*nœ�ܹ8ÞÊ~!,tCèð¤#]ÏÙr£Føv°¦•p•Ý’Ü}ÓhñÞJ%öù)�½‰:Q½bTŸ0ä7d0Éœ|D aA#['Aü¯£Lhg9,¥'¯'QXì3îBè+<üCžFŸzÅ�s ë«ôȽ¯„1Y@kf‹RÙ%S^}ãn¶ÙEœ4·ðu‘hþAƒ ξˆññ†à jÇç~ã—JÀ5�ñ´Xù1›õU Ä[âÁ:k{rOŒæ©Ë“}pìyÌw¾™É>ìf‹WÜecÛd©ef7¡H«V´°Û3 ?àüX‚>"¹X4ØÉ¦TX�êYU<ü<ܸWp¥7¿Äýϱu�#{Y¥ 3ÒØðД龂_¼?°wXñØ›F3�Sú 1Ašú–Ò�› ¼aåác ýj#» `Ú³PªØÏmŸaÌ+=þ÷ÒìÛšÉï’ÄUªòØÔ¡ßo¯ – ÎÆq«óY”m¿ý„=û+BÖüÌ«'˜¯ÅbT‰Ï…­Û ¤¡~‰âª+ç@úú!6rÆÔÁ¼Iôcvß%MÓ)Yd„›·#»ÕCÐÓk‰v+`²a\[-C8í¿~Ê(fúׄ‰ùÑJd0E¬…ýÉzŒoçf�·ÙV¦¼®…½;M)�äYõ`ÔÍ-Åú+ºãº™¿þ.—´F,Ù›ÁY>™ôoÎeØÉ°GL¥§‘çgg0ά�=Ð åS©êjôT¬ ÿt3ÙÆîb,´=ö­Î8´'�©!›'O9A¥1$ôw\Ó®0>t�ÕJÍÆ¿E]l‘•'jÊ'ÖºŸ>Ozǵh»jp#Ø|£Û¨¦'g+1KÌíOâÕè�¯(‡â"©wÜa==œqà$d‰ìƒÛmh²iø*ø‘eK>hLyáÀΔYí{¬iwþLü¾ÄLÖ/bÁ[¯¢­Œ—þø³Ÿ]Ïym{Bó½"á蔣ð#¹ƒ…]­ÇW!6¦ç8Ž÷aÐ+v‚›knŒzBg ÇÁ‚ò,ÒÔ çƒ¯øâ½ã­hÝ?ö¹È“•ðæ}2ûføÀÊ.xÿç ¸±r›—½dš=øš���_†{2Á¤2°�‰W»ÄIu)¾7�Ù<K•)«©hƒ��6fS£™dМ¯w™5§1 Œ{º.£¦õR6ß ³~ÍÆù:vÜZÉSøU4övIð“$P„�"g_:Rmy�¶oÙr¿ iP3$XÒ¿OüÝa7µÊ¹¦42LóÃ×mÌÍ^‘"ýgãÑ3Ú¨"]Ç–ÝÖ³&sÜ®™g$3?§Öo’®ÿÌÝšJB¤¸Õ.´Â&ŸÝÐHÇ‘ÇæpÎÒŠ'²®•º ý¶ ©n;æ9’i¥"£¾J¼ðo?.~äù͛F¶Þ×°hK$Žz†Ž­âp*÷ ©˜ÄºfД—ZT3)7º<ÄÂöÏè°õ<»Û¨ïIÞàó©Óþ4¼œ´ž=�ÿ‰Ó™u* ”°õŸ3{³éþÊÕÍžF’`Ô2ºnKCooñ÷þÈB×�`<ã·’Â~ŠþãrWšûç :ˆÉ1Q¾™Ô32Øë�«˜êy]Êjècží'¹û_Â0$ü.¾Ì(f‚6wðÄŠ‡0_E NÅeÛw’êSóAÿ°,¿ôä|½)N|û~:%róò5)'ýŠqûÕ$^ü�7(|J¥Ìkz¸2z& Þf–o£ÑHü­íØFÉG“¾š ¿HT‹Æ¯ŠCïÃXâÜÍ•×hAí¬l[ý[~¹| >YžÊ·ëÁþðh’Ûôó�Æ2ßQá›b"÷òŠ>ÊØ/îHƒú«vbÚKœ¡nKNUW©èé:ú}ÈÕøÛ¤D’X ØZ¿,q 3¿{•Ø×?LîÐ.h�£GÝÛùˆ»ö¬1è?FYV4gÁTzÅ‚{?àÃ7¡Ô“9^üÍ…¿e@Ýò#¯eKê•Àrp1=qSd2ÿ¸:lµH]a`,f¾ÂÛ/RÑÐq4(ýc³5© j;u“yW 4®ì¦ñ“¶Öj?E"£Cà•¹.&ìN„»òBtõÏ3´è‹ã_Z¡ÅÕ ZîøŒ¹4š±³~Ý(#t?Züâ§™ rBÓ—1åQêÔr®˜¿ÿ\¼®ÃÀžÍÓ+‡*Kv%í?½¨3‡cú´¦¤À­Þ9øàÑ*4A'èwõdŸ?ú¡à§×ܱšq /’„¢ÏSi«l jŸ‰¦¯g_±v¥lÖëŮܗ‡¶kb`’Šë™>Ï͵7ï{wnÜR›Ü�²[úQÀ~ ;GNa™ÜÏûl$ª V]¿Î_ê™QÚ[ìÿ�+FƒÂ�”VRÓLuQ¶E�œïíæªwH±´ÜÉPïkDw;Xdù²¯ÓÆ¡ùÑô­&ÉMÿ�b*W³Ú=j4;%€&u²Â™³ÀïýBºº¥—i�“£§~óqTýûá*/V#µ•Z˜ú%_;tžõ¥ÆÃµ·‡ðëë^î¹~<]÷«åFî%sí3¢ˆD-u?ÛÀ$ôAÀëp�žC»h/Šg îBç!Á:g¿ÕìÍGw* ³F-Mq¶ÞÑÇ �cœ� '0{ÄÄžÁÑûJà•çVH\{ŠYªÅÂbÏÙtÚô1z–'€¢øýÚiêØíU²ìö‰+¶$FëàþxÆþCMBQ�âþ¦öK½»xË�¾]³ýßü£€l.ÚJ_> þ!þ|¼ð/\üh7U±“ôuêE&l/�×oî¡\³¿èU—‹}OóYÇ»8X•µ”¹müµÆû,Hc+VßÛ—æ®Æwõc¹ýK›ÙÁÍ:|{­6�þú�]ÜŽ>ެõœ>p??¡cÚj’iÃgNzðó‰ø}2¡ÝIïQ79‚ù]ó„A[{\5¢¸atbZð†ï┓8îûŒXR Ì…ä¾�Ü"CÞ+ ,ÉúKÎ0·Y�l×®�/žË·í †5FÊ”4wl) §Ñºàgáš�]!+»™·°¼ Û®7±¯n³¿j�â€{\BpC³-Ô8Ž"~ö~çÅŸÜKÃ5Ô/ºjÖ‘ö£ ì¢s!Ü–YK/äFó¿Be!ãD){Z¦Næo, ú€9™¤Áh¥ #N>/£q$æy¤ÈƒÁ:9v 5Œ>MkçÌ^Ó�c)3èŒf=eèÃøFx)bÉ^ÉÅ_¹ú"˜þ.Pƒ½¦OaͲ{WÆŒLÛÁNîʸr+¿¿Úýÿ÷ÆkSÚ®AJËVÒÜJþ�ÔI'>ºÿ`½³ÚŒÄtIìÖ³Z‹: ¸»S‹_ú }vTÀ�™Òtvw:]ûÞl´èÃøÜ‰�2·�’_•Ðö¨}üËižÔ¥}�T>³Í³WCfd%FL;ŠG>^!ïçÿúC ‡ˆ€u7‡'uÝf¦wÖŒÎtû°çò³j¢eì©/á4¾š�ÊYüß»x²Ì‹–ï²`Í š(7(³Ìaú-L‡ƒÌÒmt䮀ŽÂ±`pu,ûã H]?¯S›­#Íþ¡ýÏcSýto°ÉqF‰n+ʹÊnLöáJ0ƒ%Ie×3b@Q^Òú3qˆ×c—M}kƵ&qŽ�q(mdJÇŸLÄU§Í¨ß4%Ïhósÿ{ŒêÙ£PS£�ûW·Æ—üž+z;Þ }2'BpW=ÛUâ…ÙílªB+›_‚Þª³œCØgÛ4HO‚¿ÕeÆÖY0GI×oÃ5ÍÓXÅäîVÁa¦0JsOÎáÓv�˜/O®ùšìLJXzÿ/ÆÉ. ~…-Wþ‚aÖS)=%WoVãä?ZŽÁÎ_ýÎ\צðCzY˜WßÌ“b9* ¶îŸíÿ‹ ‡å>ïQeM-,3ßĬ?³]c\ØtG˜i°�Þ}7eÍË0ñb%»`šÉN÷‰� šÛáÃÚã-ù;ç’Þ­*r—Ìe›§†Ðó§f°+t$�¨BÅ”h?) ”Ì¥§ófûâC~u5èýz/æ—²ÖdmšßçÇíµmå“{Êøi=h›ÀLxT{´j˜ôë»ä¯öŽå§½ÀcqËÉßbå¥�¥.))L­Ç.Ãbü²”Ö?àÊEB±JG�Ìûo’öD³ºËZº«ŠükN¢}±,Ùõ•->* Uƒ�Øå÷çá²Q9ÛXl§ÍdêYiŸ¾¢Œ×C<ßy�¥‰¶×<*݇¹Wÿ1pI¸F?CåÁ¸-y#T—wâÇY5Îu-|¨{8Z>n¥ƒÉܱC9ØäºöOGÉyy;,> £‡x›Ø|g¬Ig'ÀȅǬáãg®{Þz2r޹îÆö ipØ?•~T Üª`š®—H?]É[%oÄÐ÷Šé`ÕÀ›Eðaö½xGw.Ìð^Eëû„)·äËÜfHBèá¹jÞ�O+¯‚mŒÆ -�æ�2Nþ_ž´Œ¸’Œ]G탬Y$?O‡>½È LçQÂÅk|êŠSì]ˆ­Øu”.϶"ávS1#�¸;WjF‡aðÉ¬ÛØu§ CØþNfƒìseëÛ�Î.žïÀ‡&�`p<8œ>Ì[¸À/“S,uþd’ë‚ÖÈj¦ëcC³…ÂæQj˜^Z W¬­àà²zc¥U\( J†þ|ò�Tò qé¶R4Èœ /Ÿœd-R¹Ð´ú| ‰ƒÃü ã{¯²¡¥ù3ê:ω7*=ÔÂlæÍ§—ŸÌIøX1®Z튃Sä©{ê~ó«PfæO‚’±TÁ“l?bQÝtªiJ 1Î0@·f4ô³ê˜¨!¯BâkL´^o€Ñïg×íÝ©�ïÝ&ÔÉÙÃì€Lcƒ°IðÐü<ŽmPÑ þ©íÞ¿�®üœ‰VÝéðAa&½7á„jpV^B›4iÀ¬ŒŸèf‹ zü§Û)Ûù;1ë9Óî=G³æ‚ÂóOáÓû—ü"Q6´È‹¦­p§Žnw²nlàuæ9Ðá9Ë!Wò%ɾ€Ò¥)éüg¾t«XÝX› R-¶!1ÛÉÜÁÔñé)'‘¶B²aÁ 5¸û&‰fŒ¨ÐçÓíØpDŠø«‰lƒÌŒå’à¬ù0ÛÑEß7Çx€cÓ\Ä"ØQYS<�8 |kàÕóM¼ÚÂ帩ՆL ©ÔT€îg~gŸ´�¨Rý-Èh¯çtÜÞq×z÷;æ–ó! ©há2òø2Œ;5ø‹™–¼ì÷2¸õñ|Íñ¶~ôVó†í»k0ç”.¦�Íe5~´Xý�°2¤­­“qå³zœv;”Óú=‡ìd¦1QUx³é¬y‰6=ô\É&nÒݧ^$¶/² �{5ƒx½Õš¤$ ™‹%áy’³{º$Î,¡ÇvÇÀáF>œBih|ü .ó*u³fýb~Ì’íj»À–ÙARätÈ>7‚§.ü¢áa,RYEiÏ¥¡¹ tb`íØµ¤¥<~|Þ ó*¼ ÷IDö$c·r“±Â½#|Q(‡�ëdÙ ¯ ¨<ÂÂÍèÓL­lÅÕ÷ÊpçÆj0 ß­ætÈðÃ’)0xl~Ýæ#ÙÀýpr±´ƒœE:°K¤�‡F¸Pÿ;lK—:Ï+Ä^Ïnº¸D¼“j¨«ì>^‹p¥©á»ð}}»]Õ³ÿ¢÷“2S¹�õŸs_[•Mö»¡J_H?Á[Ýaê PsK†VhiÒ"á <¿]ŠG·Â9ó<¦uÐfNêÁŽ i²Ò*fú“D1'^—ÿÝÍ.gÝFU:ûý¤ UM°øßý ~ÓGE×Nìð|Ͼ¨dãÏ<:·4ç8õ±åyW!©ï,=R-áb�ˆI.Hcã›Ø�?–Ö»’ôÊÑðK?‹:gL7®¥Á×�ÕPlŸÈIìNÄŽ—žL±÷:Ylrešñ&º)ý8&Á†F &Ó²œµôc–>¼Ìaðß]KÊošË&¨ ÓÖ‚lˆð��Ðù‰µ�[ã1Áï××æÏ¶{ÊÀ²O¬\.Ÿ´Yž’)s­˜{/$À—4t–¤52×I‰ç'š„)ƒYìɺ™øbl;ÄËÖ–]VÇ«ª÷Ðßì6˜{±»Õ¦(0aðï~à²Ù–˜]qžoF�äz)’¢r8öÍž" "6³öˆê_lŒs ] ˜v.3rûÑj¾9ÝØu™ŽQ……Ccèä´@öà)ÂߥÁíéVŠó‚µÿ8þÀÓ…TÊDM>8ÈÓqc76x>šÍúóЉú:Ò–¼cl¬Z?É;Îc>7w€yÓtü¶¼ŒèЭ‹9'Ã9 ¦H¯ÄCîÈ'{*�û;Êf¯[�啰·€}p<ŽáZiɽ :•ÏBÖé€û½z{w"x¿dõÿ¹�’ò2ó÷eaIx2eÞMU†�=OàØÖ�VUÁ­M\DìÞLÊŒ¨Ñs‹Ai«-Þ[`짦Ã5?Wãã)pä÷Ð �{ƒ¦ü*a+¶ü°,ýuw¬u£WA%ðÖev?*"Ygt}6ߪ͋ž1“DÁ`GÏë=!nNm­åï1àÊbš·Ð{…#°¸èÙ¬hs“A¼ª@,¹4˜<£Gƒ^ÿBšt{6çf%J&&_IÈ`-¥5ŒƒêE‡`û$&~¨„–šIb9A4ðw|Û†ú3ì ô £)Ýr˜Ô<Ì,„ÓÁ7û³ñŠÙ‘Tv;…&¾+¿ÜXâÓ.Ñý—˜ïPÏ%•Áîg$>ð�¤Ìâ¹xªìˆêÒ9ݣؔSA7'‘ü"Ðxø™Õï˜Âô K’™^û10Ä5((Á©�2¼0\‡¯V¸�Š]-Jåß„êÀ¾:·�øüÄz–âöÞýË«ûyô~y'7qtÈ—-¤âÊPö8«™¦”êB¤ëSþñL5H)Ü�ß�;Q…ô%lü]AÓœüá³¾w��I )d.æ¹á1’nüËþ¾Ë&ò<·3½œ5ÅòŠ3¦@öÜ3ô§íûµ÷<Ú�§Õ™6p O›ÙìzM?{Jù5c†8僧î¢� QLãŠç©[n%Íl—ç.š_9Škš´ƃ‹t%܈–£Ka-à¼ë·ÔE6õÄu<_XÈæ˜Í"U«£#v��:«>ÊKAfc"˜íËe ÚÞC‡Ï18\ g¼™my=ºˆlÆ&“t<þÛ^l‹¢ï37Ã˹öÐçu–� ž_<žpïÇ60ÝÞ-h]íÍú¾ºÂõóg ÑH—µ>èc©ü"´[lˆ2‰rðëP'®Ê±¦kgÁ¡¯÷pé‚Hf.’bòX¾2£«úŒ{ÿÔж[ŸÙ±?òQßÃ6,�V~±ÕÆ8‘mg‚ûñTöZHX�F åµL”¾?@Y¾‡©=fÆ"Áýå¤\/€¶V[àÎÖñ£/¸àЉuÔ7û¥‘å'#l‘‡mER¤¯)U÷Ùå_ùa>NÖc ¿KP‘Hû°È‘¬†wA<çHÞ=w)wE(Œ][JŸ#HÉNˆÔ,ç¥u.Ó‰ÌW,„%ÖCÞ†-ƣƌfƒ÷’a’€.öJw eÔ?ÓDfaì”Æ<ôûÆÜÇuak ²Ÿ;Ù‡Ý#ü|óxbû­˜[ñr�4û/!P€ã¡?û,-JNÿ8Åh*QS•-~ÃÞOÿƒÛ’à¢ÍrpÎÏ¡Bh-ÖˆC¹K ,W‡<æÞåÏ›5òê‹`kš—ó©'›<¢x^‡fz�¡ËÉb&ãƒh­ÞVú±5ó,ÿbÒë1täñXÊ}1ÆdI¢,û½ #wÍÙ¥d’ Ó�‹³qïV&Ò„{VÐÑM»I¢û#׳ˆ ðk’  �gXöÍ9¸Cþö½ "“Ùôúñ8|AŒdj:¹Joa’œ/PwxójÐ�ÚÉ…i’‰ÁtØ}übmÁø›x÷Ò{ƺ iЈ¾[Òµ1T"ÖÌêÎ’ý©Oì�ßDÚÙ©£â¨$Yö\¸R¯„\Ó%xÜtœ–¨?Йâ„zo¥`Ôh=zœt?­�;!˜emsž³'BõYF·C¦1¹Ž|òz½XPÅî9-‚%2/YÍAx¶@†S.ÚÂéq“iÇSU(ßsŒN®ºÏt¤íhÕÍjÖê¬NÑ•'`OÓ3Þ ì¦ª’Nš ›0I´Î$ ›FËÙ²E§gpŸ2Ÿ°§×Åàâ¹ ¼°Q¾,D�£™dÝ�‘k²(^µ’¾‘® 1¨Ò�P§Û{™yéÒ6¹ñ`ezŸm‰y…SõÒïý¡T½_/Õ÷óhžKM5B(;΀\ŽIS�Ôih[vª­ŠXÿwèÌúKöîúðMã!îä?±¢ŸÒ/VÂ’cÐò÷RÚ&»þŽGjÜT"J)Üý0uMÆIMÚ"WìX®ÿÉH<¯ƒŸj·béÚ&ü:Ë^}-¦ûÏòÑÞ,£È‚6MYÕ‘S¯]HÕ2³éû\ w ðww ¯q·Ÿ¬O• æ °î.û¾–¢tÇÖ•”Èg;›~­l7ø5�´0¢+Çâ¹$­e,øŽ]S^�Þ'®aPë5ÊÚ$‹o-–à‚e§ ´þíµ›t™ÅS¿ø5HŸw‚·Û�ÏŽØmÄÓY¨2œ A BhaÈ?×cŽØé‹á00©�¶%IЧº�ô`îqFçÆ€‡p:­¶§ù;‡Ù´óúÔÔ´úî7à—úô`›FdÏÇÈuGq{€iþLNÜDy�˜IþùLœ/!�);hŸÅè[°þÊŒ¦!Q8'â„—M4¹—0†ÈŸ§Sõz”³4ÖØ¾„Wý ÷¹/¡£ê.š¦ÃMZê•xä\ l㊑¬bsþ¹¼oÅèÙD=¢–Ô»:ŸìæSÑ•N4ˆ¼ Z¹îý}>=n1†ú&™‹1He_ZgC_]:ØÓ}dt„’ì÷Ó¾#ªÐ+jÒ;\Á­L(€Û‚“¨Ö$™Õ_YÂ?¬€Kcs!ÿÂxòÚ¤N"›®¡ÑEa“M7Ød9zÞ'o_Ƴ¹ZPò�G«˜“øcÃ1¶NZ�&?ègµíhzM-î1®BÉ9í¤}ü [›”„ß[KÁæÝFvyF–XY�¾”%ß3†ö)7à\C)ƒžO2µïo|e>tÝÐubCU¢`~L?Æ©“Ð)p¼Ä š€Ã éÆ¸Õ ö󋇥+!ûÑxîŸN³rÙŠá9˜û¾³·?d~K™õÂwxüÍJ\Ù†qîá´´gË[.Ygù[ b<ó˜{¶ ÄÄsöåtCB z¼¨øDc­.„>aQŠ>ó�¦Î2Ñ8{M‚ £ŒÖÓ½(6ÖSšžn”eAxÙËo3.Çé ÆLÄ=˜´/7r»`NòB4°úm¬>JÕòæÅÔwà|[]V¬]F"oTiÆè.äÕ'Ö• æâH‡´O\G·]?�´É;´%u6Æ!~!lË)Gü]u‹›wú?v÷Ò Ô¼ü†GGÐg×Vã=S£AÄ®ß0äy^Š>ÛoëÓv¹d QŠB=‰(3r…žV¨S÷ZÍܹ ðçÏq6Íÿ_í§ˆ‚·jž »³ð³'Šiºèp�¿óû^WAç7W¶Àå"­Ð#éÉ”6´B™Â�;si©ö ZVÓj¡:ô¼À º ¢a£ÇAÖ± e'…ðRÜ)V­–­Ë‚ˆ¬çØxb,ýÔ;ÃÊŽŽ¦Ë‰Ñtû@¯ˆL6Ó%1cþ�m>»û÷)þV aN“æ0ûCpB? ëu¹{k8|´�ç �–^:$›Œ§±nNä;µÇ8YÔ—ž¯Ó¢ ¢+Y”·¸ÉË�ª¬ãqë«D§}MÈrôh0fâ‹)áæqN-@•l]÷ ëÙ™ÄïI§ŠÕ’°Âð ŽVk[H|%L-EÎüÉsg¸¢ 8Éùün¼£Ð@±ïR0æá²tŽB-Ç=œøƒ vÜæ!­Z“FwÌþÿÊtàÉZsö8^ü N ¸>ì6}è €#Õ–—saOÎñÓmh@%�}ÚÄØxæ®c “ªÀg´ œ4iC·òùÅV-ÄÐöµ7ê%çu÷³{dA}ÃFÓœ&Ö}ÛIê¿î×zå„“}ÈM:5í© ¦øœh:aˆm¹s�­m< ¡±=8!@ã_ï¤c¹øû¤ÃöìK€¬YߘxÛ h0QBµÜ«$ü–ö´,ƒ?   V;®^� »:8�<6‡ybÃ~,ºÉ¾ÖÃb¿SÐ0¡�âòfÖ)ÛÌÙEñxt‚ÿÝE ®+H™8íÚ…µ~s¯jؘ%S Ù¿’*8¸ïv�ÒÿtÁŠ…Ó�{8¿ýÍiŠÃÒwë W¡…º-áÒËqTÆ_¥±> ôM)nóÙ¬õ'âÛ‚LöA@¶îÛ@',Y‹ ß�h¾P�ìöuäq8µŸÜ§ŽßÙ4Ϭ�†Ë~áÉ+Ð# lŸ áâ (ºTÅåÉ-ÇëÙ©×ÀžFÕ…‚Nã#ÔÉeTc­î1t{:Ž|Ôôh|j9e û£Vä9£o³ÈŒO%…K’¤?ÄíŽMå>ØM„å‹–Q¡Étr›ð ìO<€ áÏ4Oj¾nÌ”é/ïôÞ‚ÅÚ›q"y(r(C$¹éOX›|;ZM�„–ý'¨é#BõæéƧ׸Rlï'ÖY–Æúdž’’ç{Œð�„;grà¢Æf–Ý“*�_0ƒ?íxzB>|é—¢LSM2NÈ¡çï@ãöIlú~–4ÙÀ„ÝG)Þ7¯ÆöÊ]|­(ǽg²Uì|Q<íˆ=ɉMˆŠÛ~Çæb·º4X^œPwoÏRHšqš�±Î‡á¼8XðÉëÊ_±W)jÞÛÌ¢ ÇR|ø,²Ù’‚ÒuŸ-fÔL··… G¶e³¬Ûöº–ßcÚ;¥ØÒqå(‘¹‹üD´ÐÞÿ*“[_q&;Ÿ£”ç‹qõ¨$¸)÷z“E{Ly­ÀÛ,/…ukÜÙ„W²4}¼8gi,M‡ƒèǶl~•N&ë÷¼F¡Êpúó2f®)ÅÌ;�IÎñù×Í…k]ŠÐ°h¬»/±·ÇvÐçÏc ž ’eÉ ÛZ–Že¿qcª³ë  ›Ÿ“é”Â`Í2·Ý(!èûÚ*¸Îݕب8Ƥ%U´d% ‡¤qÃOl¡Ês tçÌ£M�‘´úµ»–ïNÖÔak›-u¡;i:¼d˜Óuyz°Nš^š¨Ñ7ŸÓ4ûJ-ëôÒ‚‘%™$º \V[â#œ%ÖS(ÔpéP†ÕBÚ™,®iü Ї­aw˜âŠ/(ò)˜äŠ‚È«­=¡ƒ ºØ”߉4tð0•u8cÕ{-øØò�m¸ ÓµÙ·†‰˜~ëŸßÊT“ž¸4Wv³Ñ9`¡™zMËD?K}(òKÂò#c©²F~¾{„ÿIß5Nl¨àÌK# gz1Mú¼”žpÉ+�¬ôÍM”У=³âÐÒõ˜ þcÃ'OÑôt¦Íõ��^2&viôH7Œ¬š‹˜ÀT9NE´7×lþWï 5fW�ESöÀ¶#– sTܬœ¹n¿ºð­Ï;žG•ôçÆ*Zô=N*‡ÅàÅοlzÝQ�˜ýZ4æÕLZOÊtrßYˆûD£'€ZA«úuO­› «“Žà%!I8X7‰›l~�K·râËD eûrh�Ãሽlø�óX¹ñïØK5 Zú€ÒFGr�|6‰-ùn+ˆ¦MìÈsIØ^(T÷Fâ2ùý€‚4•{>FZëB1ÖùXìT‡Í‡Ä©É#›>Þ�ƒOÌ`¯Ïÿa{^ãçw[™n¦#Vrl"Eî{¶�_QiR8Ÿb)“'cÕ„~Vi#JÇ�.b‡�‚ >Ïn‚y±Ûùöu�©58<‡3i‚H%6…bÅ=ùY#¬hoˆñ¥JâDª üAocéf5ð£ðmœÐˆEë¯@Íø^–®þcbRàb‡/yu¥C$kÆ:Ÿj¦qâ \Óÿu‹‘ʘùµþ‡ ruÇÿT2maC’8“ j*‰4ÿüÚíDz”XÜMöX~&™z×¶7H³BÅAfÔ_ô?ŠÎ;¬Çï�ã- í­”&-!Jë9÷iEÙEf"[(¢´S)iª4ÐTŸçÜŸ’HE4�"¢ìeçûóûÿ\ç:×s½Ïû~½þyùóöºgˆðŒT|PÉO—¬x˜š‡™_B&6îß·”ëŒcX˜±݆(.8~ÌUEȳ1¢¨i…-*¸‚ŸuÐäv(VßÇÎQ.óÈÍ’ëbœµoÕ6%ˆßÐÕI—ás!Â�Ž*JךÁéî@2—ï}>ñ“¶â/ó+d}þ-êt$2t:ñöˆžôÂY¾iøÜr-œHȧWÝ€×ÙòxäÕ8÷§6,��Å5Øø“-äqùÃÇlÂÜ(¶‡$âýpg²z{<Úi<Àu&·ñ¢7ÁÊWUĈ™<¡ÛîR¿9ü8ôå*ì¿P|Û}Ùg2CÔ&¶˜Jߣ•±—iÀÞe0Tú‚‰]øRçÊpJÆ<áÔP|_XÚ?J³2ž±ñꯡºe±É´/Øå n¯¯¦äõc~Zµ>¥GÍôr€ñ&f‡ÏF(çA�µ䮚´žoæˆ=¡vTt¦)®ï%jM�鯖f‚­Ê'æÛ•éÔùm:,Ýa÷d òG��!žêE1Z$ó¿EXwIŽmS…âÂ@L-öÅÿžCÜ£ýLØ’klåAitXûŒ�¿k1Vw;ä¸.Á?£`rLžWúw!ÝzÏÕ^í�íµµ�ãÝÍn³dVdtb�ðö‘Ó±8=Á>"KÐêõJ¨7³Ää¾BpÛEöÇ¢@’*r#èþâ.Ó $ËŠÁéÝŒø} ¼%†ÔÅ`§¬l[,Š] ÉÉ›&°{ùhˆcЦè ÂÎP²Mhد÷bʯ,•îtº#»d©Ï°"‰O¡sÏü ªª\8è9ü7H—-GÙÌTðþ0�3íö\äQG'ÈÒy=< Óð´ÕlüöN‹§Ò!‹ 8Ô¯®ã*Ä%Û‡Qš÷Ðú;ݶ&/k„ÀðMl0;„·‰Âƒ¹HÞÄ8y‡GƒZƒñÝÅíÐÈÖ”/G_W%~™ÇwЛ�sà!Ÿ�aþø;7Dâ˜bÙ,Ïîñ;„žÃ×ð|A ¾µ¨B%Ñ:ŒJp;C‰•;¦Ä¹ÒÛE÷”(ƒBT9}bµ ' �Dn˜‹—ÚjXߨv²ê”L7"Ùé3s;¥­õp?@žø'’=?8¤ÞûŠ�!zp�=¢:lJc-x)¹ÂnžGÆÃÇ_�ŶÁ°n©FM—C�üó´vÚ<ØÜ¹ú¾ÎG±c°á½'TÚD¢kü'ºZ¨€PQxkE¥®ëq|¶™°âÉSq‹@5nجdzÜô‡ªŽt±7;Áå[ž´¥¶øL¡bˆ_Ë!³§.¯;ÓOæi¿b4RaÓ’q*#r�vè´¿âLFËßov„ⱚ©¼é6=ôÓ“õtÞ1Œè¼JÃkŠáPËiÈíP7¹yÀײ–œb "{…AÛì<‰^$šÃ ´>ç 9m(À¨ê¦Ãsshˆ ÎX„Ñwpr«?VÄæPÓË�(±5®½²DÏgÇ`~–Üî*£Ï}˜Èçþu« ç`L�Õ9L�-˧Sä}Imª^¾4B3|ÈÎCÊhª†ÇÿˆÑ/ïO ß™K4£{5á–’‚øz«5­"!Y�Ø0*]Wž+L{?GÀÐïƒdéX:ĦIòD_Â#à%}œ¿l‘9‹ñÄ–üõßC®›\úñ`vQ”õ‰@¦¹¬2g¿oô‚OúèÑ_Z´Âæ¬nJ"_«_Ñæ(yàí>ÃHÅÙ7Ô©�w%7Lr¼ •³€*6_ÿ;(Cº�S3õ¾:Õ�rr|„Ì*òƒ5õ´Ú²•øvÐìCÿCG•š³ a¢B¬×ã>½0ò·ðó‹[ •!ÉÙô\<ÚÌ0ؽ {ø� z|<8'ƒ-;‘MÙZMw”ý$ŽoâûÕÝDqDYYʆ†„â�(¥ªÆ¸Gj‘œ÷}VS¢ }‹ L~xÒ/Ò‰v¡$¤ËU@Nâtúé§ê®Äö‹�ô¿R1ÌuÃçVmtû“AâýQ‰>é—ƒŽG®¨ý¶ ‡Ò˜$YwpTtc5p͂ҲEâïA{ŽÝ÷ü*½¦ª§ Ê(ÿöJ²û�,§«g*Vs͚׳Æ_ó)ÝžÄTŸô¢_ìq,-v¼yŠÌ3e¸»=C´ŒÑ‰¿Gœñiã<|•eg c| ´TÆñ´t’ûNçjµ²§î W~JÏ. ßéôœ}Žž8F’Í·à­{S鞥oˆòæMøzq  xâ·•™ø+f.Yw OJ;`EÈb¸ò×4UMÀ¥ ÐD_¿ùÉ- À.»‹š^¼M.<ÜI£þ�ßÜUt”$Awp3;äsß5ºzFÑU•�þëF‘¤¹Dü™1Ç&÷Ã1[BÞîÞDÂõoÐ:s–~ì™Ã«>l…“™ÕôáK.>ž ƒ¼�…ðBy%´“AÚu×”Œ¸�î¤4ln/'O;ÆInKYßÙ°jl-¶/ÿ‚öÞ¡7Ò¹0£ä=uµ#4”ÅâU é,þ,´Kn¥5e)øüÄ-(JWÃ_þâžÒê‡ øë�8h,  %¾'aá+1¼BWÏÓ‚Vƒh8liMeoåÒôÜ·ì7^*rm$­N% _¹ßÏ—b~|  §¬4=»…BÝŒ]@ý¿yêKþÎ#'?û3/–ãqMU¼U|�ö=ËbEî ÐÔU0vzÄ�®s‚,{Nv,_�æ©É!™v÷ë"VnC=ZêÑýŒ"¯@o íH¢½;q›ìØZWÏ*Ç¥‚aÑJ²^: Æ ‡Ù¢Òã´²q!ÞŸ:�sWïU;zŒÎ‘}ͧñåjñJ›¬šVAæÌÇy|a±Í>иý‘|ñ;FËn:ѓűḣŠ†Ð˜‚HÚÞµ—F*¯b3ÀçùXPö’nÔ=KÒ˜8<5ªMöMq ™ªd™q{‚°nƒ9$+nÀöÁËôÉ<ðÐMþ­ÝZ]K–l’…7å©pÚ>ƒµ‹�ÂB”jõž$‘—SÑqèÔIßµ¶iD?$�3s©„›.þÑö‡Qé&KP4¥ËÆ:hã—Ëäì_°º ƒ-µf°úìZ�áõîMÆ-õÉ¡5…ù–°ÅÄ•”XáŽGwaú®c°À/ÉþAxËÄ18ž3‰œk¸LuQ)$¢ßSÈêû¾°}Ú4ˆ÷à‡þ¨z£ÍT‰Â�{•("qÂeã�¼j"¸F‹äzᣠ¶Sæ,ð"zñ"M2aÇg}ôi6£±çz–ï…jáê:•íçIy—tà\\¥¼[Ô4pöAH6f¶Ì4\|¼�î“`#û.ºÈtoHyïÔrÀ9�ÇàµÀoFÙ·�êYK£ùžhÂfm›µ3ÁL)ÕêÚú�2õ,‹¢¬DÏü‘iI.ðA|F ¶Ê¬‚^ûpòQbÌomcn?B Ûd2MÓˆ¨ü$%Øò…œ™ö�äüã³Kz•`ðÒ2‚„xéÙѬâ´(¸l {9¬Ý¹`xQ)�ظ�nçk@©EAˆ¿ü­ÝÞ›3[Æ–@ǽs8DñõM1„Ù=Ö“zÚøRCõ_wS¬¨'1[‚áUX#²)Uf”À¼–- XJýIÔùù>2Å^g¨¥AÁ¬Hºw�>η?ŠRHRd}:O�v<^Çß)‘dÙZvÄ‘Ÿç¶bÙæy ®Jmw©!nªì"nEÇIVéY*ôøÀ׳ñÌ&uúréè[sŒ(`î¬Á¼“¡$ÕRÜú®ðTœŒzBn-J§sÿË£|‚ÑÖ{}Œ!ó[/fyeãÖ‰GTð»e&ÐìYê´³’ Y“Éä)¡É“mÐð¼›|­ŠŸH—ÜyJùFÃþ9¤ Ø Ê"³®’®{À’£�Þ‘‘ï% S˜@D.î&çÚ±ç?ϧT†J×íÅá¬Ùpï*!¯ƒVã·îË„ßV—4ëãúª8Úê‚÷Òæ�åt]L¬ë±~蘊yq4)X�†äkçlüæÿèÒI7œÇ̓{Ïùx÷ׯîG@}^©w,ǸB 4°gîV'i‰uPäìJA° £øyžG6£ÎÎEhJ\Ñ/X mæ¦QY¯ëØ»~€û[è>ÉÙg‰¥á㫇¤�ÙŒ*é÷I´ƒú(Ëc¢ñ'ZduŽ©.ýסwY›ò•0bž}îQS}ÉØ@&e*ɽ£i�Ðg*‹î’0uQp.»l@ìÈp¢!¼M85±š†¸¬Gµ. 0�sÂýsà�âónVz­×Áïm`lhvýáxÓYÖ|ÇŽŽ4Z)ÿ…&™K€Aãrj·Ú÷g° é:ì<«Ž‹—Û0þfÄú Á½w=¨iÈ µõåT!ÓAŸôi]&Öa"<ûÏŸÔL’\0U e¬ï…áL•]$H¤ öšÿ¦[â*@¡�CVÿ‘€Þ§§ë÷�".¾Tb“$~{Á%·üty×lâ˜öCˆÊñIJÅ]䃠$tÉÂxT «ÙÁuá½ ÍÍ�´ë€ †'º’žË÷éóxrcCðI¾ ›×vc;ažTÌ öäÅÍdp:¡V­f–or—À’Æ&x< Éº¼TÄ—vݤëž4ãûÏAÚØ‰wIð(£oêãг"úâ“?N3ÚHídŒÈŒ[u—(vƒ°~Grä¤:eLÝ‚P,~)� æ¾e›Æ‘‚ý/ˆp^2½(¿ÌbSÀûóetãzá’Ý QõÖ¬©Î¶f‡Ä`¿x")‰õa.'Ù±o8�d�óàA?ýž—@> Ù²³Þž!÷­×õ&)�šö–\ëk¥6ÏÜ ("“5s�†Ÿû“hѸŒ÷’Ù’h¿ý5k5uq<û¥›ˆ<›‡+µUÑâ½(*6LÒëMÌ›ù¿è¯cVÜO« óK"¹—! 6ÿ=G•- ¡ˆW?(Â.ÿ‹huý&=ºˆOƒÉ‹o§™vñ2âöã»ÇdðÀw-<<%Îsv3§fT(öÄ•þx•,`Rÿ»Êfh‚Ç Y”q}„Æ[דì’xï³€(aƒŽoø§žop¢6ªI›˜?î�EžJ…9Þ]ܹ›(mš@•Z3@çÈ_Z¥æ ö‡ �‘¼Mù¶×�Qùi.ó<œ9ëDÙÆ4A²ŒYƒ|“ùtÙ*=R<Áü-¥a%æ®Lõ÷Í�(cUìÑÞ‰Ï ªÉ£TwúÎÐ�YxA:ß% „Ãt¥÷tø0m;øÌ±‡!«Lb¹r1m€³S´@J;ùr}1©‘{%×óþgdécº»÷úù�׫1zÞ[ÅÖî0‚·7IL¿èµ»‹¹ì!¨ˆ%¶�õ,qìÅ´„,Õ8JœIHÓ7òGÃÕÒ£âD¿î-¡—\ЪW ¼*·°ÊãÁ´éÛ\¶lßBrò‡½ž® ÷zw²¢—q“p9ùå)‹Ú×�Ъß(ìß„ë÷Æ’èûd{Ä�=:ô®ß~lh®`K…娎 ÁOc%ô×»CðûHýŽ¿aèÑ¿<7Âóay�DŠC±ÉW�V+dºMËHÈ÷ûdÙ�¥ÔhB�<ï0ñ8†]òã(Í}% ïDž;©^ºÔû:¾þ2´ÕòY½¯fìÓÒQÐØ îñŽÌÏ'£ÜóüB°ùÔKzjh„a6Öî¿1ÏšÁ«·7NÁJ×ɪHUŒÎÕÕ—ÛAýÙ]è‘O³¦‡ÐKÑ-ô–ë2<.³“:¢ ùT¢÷<7B§–2lΦ†Š³p¨®™ÍSè$Ï^Iñ䲄8Z¶áÔ¿$¢#“„gùÒù‹¹OD H—%éÚgh�P9i3ðG—m|ìÆZ0ºÌ2§ÀFI‰t Ù×&„ƒgIWHÞMyAžVãî�°Y#žN²Þúø&wákI¯zø#=ŠuaçÀñ¦ »í›T½t£!¦?ÈW‡%xc´“Fð¢hŸ@äÞŒ!Õ²pãß]+oª§ ·ÇiG”ˆ×ް#5-”9´�x‡3# É­Á�¤LNºW˜awè²4ïý!ð…²–«©}zcò5Šx[½àÝQC¼!ðž;q5Ž>;Jë+-±$ð)Ùeö '#ÎæÃ¬¹{÷v&Í"‹1'HÑWÿ¸§N›óà±õ2˜ 4˾¾*¯ƒZÜÉá´±È4M'蹋`ly—ÞëdÊç½ ¢‹fÓþªaR3ðšFCT_ œ=´˜|É–‡ß»»i‹”ÏÖDórMÈùç—ÆšpÝ�ËÖÚÓãñJöEÈ©m‚mŽ—é«Éxf Á tWI£øØnúŽi£{ËÃB…øÞrŒ8�V‡ÙoKYw…#˜_ôÜê@i‰’¿�-k>ÀðÇ÷°Qu4¥ØC³N)rÓùxË“ðàùHô[æóÎi2moÈēà’ÿ�ñ8|ƒ…of¸Nh˜ð=ËC£DkÊ;ÓL>¸©‘˜ò‡ˆ?Å@é Å·uÐeï'ü½ØF­êéžxi¸c6'Þ“Û²FôÁõ¢së%ý²«LW@õ“°#®‰ ¸ ÃÜÁ�ðÂXsJ¾²bñ�°SÏvM|¢ëš °¾Iÿèꑃ_{ÈÑ ËˆŠZ)å­ÄùªÓqÎ×ó¤ÔV ¦}s´ò"§}•aV¥/�ú²—¬ c Ú¶ nª|¡.g,ÀhüÚêéãÚ\uòP:vÛª@¹¢<¦$œdµÄÀ1«hzëBõ56A7“þ¾©‹úñ†¨R¾ u÷Ÿ ³v~Àá/c$�¬£�&KqWA;óøƒ'7Ç·!›�‰7»¶¿|$µ¹TìÃi¨Û"¹ ‡•¹  Åi";Ö­{ASR!÷K %µˆk…!˜« d~"¦máÇîÙ^èt5ôƒNÐ]sÝq·ÆaZ´óà�#`ø÷ ¸®êf\ü2SÄÉm;wvC|ŽõÅŸ‘èÒJ�,«0Jì(o=çnº¡‚›ôÏ¿O¥ÎuƒW]:ÕÙ8BŽeðƒcI�Åì`B¡˜|=~ƒ¤ŠÕAë=_`ÝÝA{ñ´•4„s}»ÉÁŒP¨ýÇ;æ‡èÒ±ù˜¹*™n½ªg6&`fÎTÜ*C_•Ñ*[a0®XFD¥Ö1šë—c™{ ˜È¢û‡åào fÄúà�«O¨¢®õÃ}‰Ü½›‚}ó:*ñ¬ž¾R;ÏÍ:k…�4l?E_ÊooÍxä$×àßÕ+à[B.m�v [„èä�Lïož¸*ôÏ ó©èc8ÛþŠQ4—…#/ÇÉê¬PÌÓÞ‚“k Ô-•¾lr§Á‰ää&1ØÒs'e®¢‘q/Øs¨L¬-1~™‹O”*‰ënIæÎd=î' }C&X±^%�V�Í¢í8ßo(NÂ+/utš Æg»?àç¾@R¬˜Ž‚.à¬wÚF6âF©[¬ãúr¬1·þo�  ¹K¥^ÕÁ¢Ê8˜Ü}~"�é!ôPM;Vr ¨9¯;£ÿf1Æ!Aиâ5ëÙ-„–ÂÜE€ãkñz~#ñõ$^:K Òó¿NÒ¾f¤pA(1¨~Mc.-Aë Ð87JN1Ø™¼ È‘šžï§£‰Q ‚q1 –€°¤2êÜ]G^+ñ2†5É–ÐÏtò¼8íóí¡¹$Hìm2ÄùŠ?7|¢ŽïN±Jçw1? "qÙÞhߺ¯ëŸÃ‘dOëÖ“ »k|ô- 99tQïlœüy÷=€Ø%¥k�ð„ƒ'åÓœIŽ;‹CÔÒ `³S Î×üžLîþÊ`Yÿ ÷®!¶Øàª†.pýx1ýl ÞB˰îB:¤ŸÉGáÛž˜÷-�~|‰¨ó��Ê�óÙÂ�[På{)¹1@/¤ã3iU¸M¦°DZ,ˆ.õ¿�æóÊhŽäšRG{âØ¾Sü0À¬†U%_HÙÎ(ÚuÚ Â[zð¸ˆÓOBÍHXc÷‹Ìt)ÄžeËÿƒ]Ô»Ò‹Âþ£Sï„¡Žû,^¾q$¡l’¯ŠÄ}ë,ü˜ÜÈÞ/üž<óµ¾E+ÓOäfæNz¿9”¬ ‡¤çK±QžRVEá>´Ï>€íÓ¶AEÉrp7�†â…°¨/»�éÀ�—¬‹Ó¬—ã³íö�>Ê2o¦CùU3\¿V›_õ9¥äÚD>©(VÅûC¤Lí »·&ûž0�ßnR'“[䉩"„mÁÊ >úݰ„Šk^Áo90Z#È»ï/IŠû/€Ñ  <3¿:‡·�C;/n­ÂÎ+d™†4ü®ÀÖ«AÌÔ'çØ×µÕŒÈM‚‡ ýáágºÂº ÷=ž ¢ÜavdÝ£^IkθQß̽äï¼fbdžõ%¤.«Õ ÷ùz“Ù  ðU­>µ_nLvÝú�VÿÂÍZ<"wfƒ»�»Ÿ`#ÉÛž¶’Ý»5I¦ ä¯�½Q'�w#‚\4#ùϽàUc(‘ó÷Ç»7‰Ö�\êd?Š�[[ɤo Jîb¢í‚ñå1I˜{ï…)ÅlžÇê6{z ù@Ù/]rS¿–Q:ça5بôÁ kX¿S†smØï_wŒ"Ë�Ã;jÉiÝ×d µÕƒèí’K`¥ø�:ÉË¡/&u�¶‘¸¾i;i¶Øë i‰¶xni¢«þº‘’'{ páxéæ‹ú�4ð˜ç6ØøP Î~$ÈÌ¿G­µñ€ÇšuÛª%•ÿ“uÄjÊl<`9cñƒÐZ²ù…ZñµÁ\<âSA´D£pøv$œ›i†7 R>ë•„óu!x]–†­atø[Z×¾@y©Ã¸k¥Ä»v‘3º= ×*.»Ö2�we€“fa‹¥ ¬ÃzÓù±ùõjhqe3‘ÿÛ�С¬…ø<}H|ªJ‰ooÙÐ4nÕÍ£xÀ¨.·��Ê-çè#þwDO›G®x÷Ñ1™zò3I"îÆoÙ0U®¡æ�ÆÖ¦Ž=oIùuÜ«|„NÎÁÏó4À[½�ÞPX+ü{Èw»ÒS±Êñùyah<Š#ˆæKaPN-ÄàÙx²/‘ôè3à�Ÿº÷I�À5ð øLf÷±‡½PÍTˆW·¥4b‰ã9"md/B�ùîDѧirh&¬Ž-7ÖÂÔàP¬¼s•3Ê™í3OàP„ªrU™9{\ Ê[²\Áɱ6Œ8?�Ê{¨qBß®ƒ8—©hÐ4FŽOqµ¡*\àŠ«’|Àu}*š–ÊѵWti¹(�eÏlˆ¬çø£9•t²fðEdz\ØNþÊ%ß}ìÀs–"|yxþ´zBç¬F¼^þƒšþ#Çtg| ‡AVÅyÉ×!õ®*F. �—£CÔÁC‡~‹ù‰“Ç Ȣ†®ØÃLÜyÂÝå÷�WÅ¢j¾7H¿Ü�ãSçPÃÉzlùpŒgüøÂùȣȒý Wß ­7�½~{à†q2ýØT@ïÚ¯…ª†8s wº±x4=—”P%ÉÉj0;ªŒèt„ÐçþÅt׬X(Ù›Kú‹6 H�-–¼è„í1¹ìémº öTÃu–’¤�ÛÉ»e"˜š_RģݖLvÛ-üÕþ‰ÞW"dkJdCÿFu¬h‘„3‡†ñÁæ´Þ7Uϯ çÖÚ�³7a07~>ÎVÝU�uu¨äü”8]E8�¾ŒWÂëúü1RÁí£½¯ù —Ï�-î‡KÛ´!äà”çÁ¿IoIºó8X8Ê·’Èa(2U彸²ÄM‚ó GâÖg �ñ~<&דïÃÑx>pL}E“–™ÃoQ7œ~Ê“KeÌ~ÓYÒAJœQ?…y;÷4Cë¶^F,æN3»O¿.f.I%“wxWF”>Ыa·f�’è„àÌ«#AK•©9“Ms¶lC—-n¤ë¿É­�…ïû>ã'u´ÛÇJÇÞ FÙßS1O!Ùµ”.ä­fž±Â娛½ c*!¢õ9ø¬šk§‡44!T/fîØ�ǃe�¹ñ€-ÞÝBVWRס0Õ5\±ÙšÔ.ùÁNdRÛÁÆ -�jÔ{¡÷�œÞünᑨ6ÆÏEÔÍ�ÞÅ,¢µ#…?�iˆ/‹{b6�º¡¾È߆�÷daÅÏ\|cm U.¾hv]¯%ÍÄУgAúQ7“a-ÎÚàzk èšßEºÉÖ¿¡`kŸ�©? ±½7˜aœ¸>>܇0í¬ /fG?¸ošËŽídÿÑÅ2í»ôìR 8Fô2$µà îÐô†À°a®ÞûxÖÈ¡ž�puÀtùW°ú/ð&ïÊÁë�\ç”ÍÍì~Ø¡?Bœ#%µôxVö$‡4Â䣣Ô~Zöz‹àˆõs8q} ­_Â�%«•ñA¸™×ÃA™Ãÿ8-!Ïô&™ªšþ7‹ƒky²E»<áæSÌÉ 'JßÃÞ±ªtªw]ó"ËÝTÀfÆ>´Y¡Iž›â£_5dmˆ"N!¡øê¡5 Ýå è} ­Ê�IJì 6ƒ4äÂFLúY !¼éÔ"™�ÇçÕŠe-ÁøaG}8ÑBG#Ep<²ˆÜ´}A*Äá¾¹+ÔÃ5Œ{CŒóRÁU> �¸ñ°‘žb“[þÒwý¤x™ çˆÌ•æÇM•°8�ŽÚsÿD[¸îý‰ý»þn¼áÊ\5�†vÚa’—/UiüÝnƒ¹ͤº¸×ÐY)Î|ØØÏ TìGåÒzµ»‡^ݓ͎.Ø *Àk§;RóÁ0b€yiqŒ´õy¡‘à bwÙ uÌ+ÉÆºÙ¬å‚®¢C:xݹ`K¬ñ¶ÄØ¥sðöÛ`¼å8ít>ãwþr§ÿ¨£Ò#3àZª<,!+²ÁC×å¾ÉAmòVË=6ÝÆèÞ)ø­Þî@>ºêæãªUÊ Ï;3øÒˆa–=¨/ú7iÚ§q­4£·å±7Þ Ñm®ðÆ+�¹ý[ÚM²á HO@ã�pÚQá |vAÍÝ©8E¬ó# o¼²nÜ> Ûž¶�}DWtÚá³iDãž>øÞi†±*ÐÈ™ _ÆWbÝê[©l‚¯Åc!b¹ \ºI¹Q ÿæ 4Ln°Âìü¯Jš´¦l§š7ô‚› -½£fÑÊŠ§äu«Z8äÒ�);Áô~†uÑOúC&šÎnwÆ[C☺j æ™Å³4Õ�µ»Öä?Ç,œàn•|=ìBÒã¨Û­màRþ³åBé”%w å] ½SÁÏ›_3ÅÙÖt“I*WU8lO¦èàD¶Ù£={•xájßQùæu*wU|ú/°Ÿm›aÖ&>|æ�)—þp+›}ÀÓÎ6˜k¢´‘ –I¯¤bÕHWš“ýËý¹SwL!î áÐëü/�ŸãâóêämpFÊLä.¸L./ÿM oHãºÉ²êrå«Év™€zp«ªª¬^ÁØÎøo•0ÊÌÖ‚ÐÚ÷ðN2—¸kI"QtF­éæä5 ƒƒÁ-pÊsœhUÙÐ\÷¯Ø¥/‚{Âþ}Ëôé )l;¸‹溠Ɔ+´Û˦îÁÛLXíÑ‚1²Ç1ìWiQÛNG:…H¿Ôg당¿+J1ýiiÊ:H;Ÿì"šNñ°5²€ì,W㙦o¢[ÿ¾#;�f¢ÑtWvÜ'ŒÝÖ”Ef«.Â9#æ0!wë�’½_#h±• Ä^˜‡Ô¶;¦þczk7Ø»%Ú¾V¶^ :W«¢D±~vá‡Á àÓs"WÎëÒûοÿ0Û§…¦‹_s½œ@‘™i¸&-×ñ„+óõQÆ{dÙå¢ß”r�aÉü\Ñ…ž ŸÉù;oÑjRš'§pœx $cÒÀö§W±\² tÚ÷Àå_Ø?y ÕÝG¾E“ÙõÚÀ�ñµÙÜBf„[—]!Ý Û°â‰1Þ³ï'•~vVëwE¡›Mðm5‚ÿ,wAó¾éàûç!†X%××G€\žxò%˜É7Ò¦Äá—A–DøÄ”û©Rû–7ÄË!†|ÒS§Ú©Ù³Oauœ+x@Þ:IÃÝóþ4l‡6׫Fœ¼"I¤ZšOÒ§ÕÑ${Å4L”‰É¯Ä¡^Ðz°i}ø2 ɵ5˜g¤N6—÷SΔ•xaÆVОûÇLÎcÒ…(t/ÇNï@ª¬ÞgUÀµeý§ĶŽWr{í‰!Ìʶ„ì\5zæ´çþK!žŸ‡>1ôLON‰¦)+6cŠÿ_æÎ³à· ælr†æàܺhŒüç^¹FŽð<-˜%—PžáОî*[¦‚®sžÂÆsOÈ÷Y5k’åBÖë{Íñ¢Êyh›U '¥8�Q–¬p©{)¥ŽþMÞˆA¦UÔ¸*“=:M�—×ø€ÜÎRÅ,ËV=ÝB«Ÿæ`ÊÃ{t×k’í4€M‰ïÉ´M½äOŠw¬Õ3šÈµe+Pè•V·Dá�iâ¬g;j�Œ0 ¥ë‰ŠR-¨È‚ô3)žê›KôI­ PÑ=ä²Ì~Xé*Áz­ �kÎàüW[qu·¤èXS9^.žÜw–J/UÄ=¼™¬O=?éÏÉòÈVÒþè¨' òž¾„;,…K= Éßú{¨ýô"øV»C`v8êÚ[a„ql0§…“�P2ç¯�„ÂéöTy㠛ƙ Ïù8Ûl.Cô€9ÇêñÔ¶í d–1ã‚#ôùü³bUNFϨB“�¹Ñ§€sZEéú]™xà¨+Î-� 17Ÿ`÷›ö ÎËi‚Q±6Žæ1¡½sð½u9¤¶ÜÁà €ïå%÷ñ¿FâÍ¿–¶£Ú¼÷�ý-½­†*6=üfCÇ*%޳Z ùrC~/™OMÓŸ�Í ytï”ËÓé :u„toeGXŒ:›‰üKDxJ÷§!Ÿä%?APå¢é¯D½egBè©$‹1Ec=_"*%ÆÛ3û+XÆüó´5rð-C ¸.saÅ“°/X˜752†…}dN�,Œüï¼³Àf�fE°¤e–ïkD9Vë‰1žk÷B¬�ÊÛ—áwÿ�8ýË�:’ƒIÕ£¤¹»ŽD(+q:BÒñû3=xsµç®xÇüú~uùpá*ó¥vò¾ÅD�#³æÁ¢R)ÐRw¦¯äîb¯Ê'øT¼�~(> ƽC] ? Â[åö�ätª£ÚÀ{5Ñ—sé³þéO†Mwhy€Œ~cê5ÖÒ…ë¤`Ïy˜³ÿ%F»óñ>œHn†Šðrm—ãõ€RX;qÖZuà Uu�EäûÐ�#òrå„Vð»hŸ5à½z3 ¯0Kær îâïàRÒÖóÏÑîÓ3ÛʰáfukºF妌B· Ãçß'I™ê$À¯{¤`ý�ž¸—L|÷Ër¤ g£¥fíy ‡? ZKãI\ŸƒxÈj3y¹'�X¾˜‡Š9œÿé¼*¿E¸´ù­zC*ˆóɤÛ¦+áfg6jq4<�9ijÔ\a5) rY wûPœöè"Z¶Wb y;ºúNå]žþ�Æ&q£++iR„ Lß{upšÉ zŽÛI¬u¤Ñjß´ÚÀ�VZÑ|ó.sôû×bñúë º&SÛ§àê‘Lð–ÍÃï2s!lÓ :m?KÙ�ƒ] w­¿î1¤qµ¸Ê(°ÎúM2”þÑâíS™Ë)|W@4šZ!ä�O`¦ /+ƒbÑôHð¼×K·Û†bóZ>Nwiþ<±.¯ö ‘Üɇ7LÄ`¼#^�¦‰[>ÐoëÏÁ¾Cź%‡Ä­¿‹n@©ú*öˆÐ7êi¸A+m¨HA»Es–ûÓÒ¹›p�ÁIœ¶™ÝšdWñ%ôV³€7[`æƒ ¢ÀƬxÚ— I’yéê‡c ص ò‰¾­x5Å‘ùçªÙô`{giX³\ÿbÎfÐë }…仯4´oC¢VD/Þ ×Wþ‡âíð1õ )åSy"g|àÙ×1tºC±F®€œNm-BOÿR,=Z‚Q#•P/³ßoÍ„|(MÎ%÷Ù Ø•ÝL­è¡�K¯“g]¡À[;�Ó^Cë/`äS-ŽDØeÂ'ëÿÝ6�‹ºJœ½TVº Niáßíæ¸%FœSöÞU˜r$Dþ£ý_,xY'ré¯ GH“Ïð0—…5³aÝH+­zN?»Y猞§mvbíYй©·Z×|%‚îcÏÄÜù�>Å´ã|гlÞÚ>‡î}®Dü¶¯ÑÇÇÉ®—`¦y#!ê·0»ª”Ø{¯˜‹aSe¨u`MˆW· ˆÍlhþ@-ŸÄ©«Å؇�'�ûÜ„ò12b*/.l%ˆ®$žB°é�¶©—Ó Û/BôºylávsæêÑ,bMufxâºÚã´)ç/;_y*5ÌDõüÐ7ôz?\f×l‹ÁÔáýDht’ëú_�exYí9H~èr*ÿÁVÛå»°6v1{²–Ñ ¯©¹Éä=õå –æ=˜g½ðÈLÎ6Ý{d¾ž>~÷m¿Ñd�?à]ÈÝ_]H3©³§½¯E¹ÕÈÎV$éR¶�Եݞœ‹àPØM Çî@ô]}ŽÛLc¢{¡“&õ¡�›�ão畸Z³‡ÖÑâT:H J~,õÙ¦cU¦ë ï‰'‹ÛN äÙEåó1 @�Öè.‚tm=f‹»#Ñù;°WW ­ÆBÉçÄ`ô�Kù­æ�÷&��z¾µw­ƒÝñÿé1 {ÿAû‰lOì„“a�IМíð†„;·ÑÑ­Pö¡º�–“ƒjÑå(q[�c-O¯Ìô„§Ñ|ðCl)| Ë#_7Þ�Ê;&08ÁÃùÿϹ7g™ÁãÕ{ë^yÇS;]ú`“É^ÿ…~4YOMßþ{B�š¶”ÞL«Ûx0VOù^†…GÚp;¿îo’!&Žô{«炾L(œ"Ó¼N‚Šw%ž ðA! ¢—v*‡±#s.n}ªFrºg᤟/Ü©oFu+ÖÝüŒÃ7=ðêŽ*ªún1šâü…¾8š0ˆÏ¥s¸Nµv'Û=á½Ìú�x£ ‰=(iá.næXå19Wóè1øA×èêòνÖ�L #x}Aï¨À°Î#4çd ¿:DcÆ=ðÄÂpÈ3˜jÀ$/:Xdm}àØS²Þ}i1ž¯�ž’%9–œ“U\ßò`LÒ¢_4ªð„èJ¨µž®3ÃàoMÝs™H(˜Å‘cáâ¹y¼c=±8땹>®t,BUÐÄâ2ÐõY ¦ÝîDÚDò½+áÛòèöúHãþ¤àv�ô®¤óUα+Y3ø;£¦óžàìfA¼¿® ®–ÐÇ1[¹…�a áœv‹sàgŠ]•¨ ï¦ãOUAT¯µÀ�«´±öŒ"ÏÆY™—Þ%BNÊmA�ý"�ý;ßë+‚Mø-8Ÿ/’Ü¡Æ" ¥µeé!ßë—¼`‰a:D= ¡¾]ØÆC%SÓè[Ñ5¤¨´‰áœ!m/Áõ‰&¸§íF©ù…ôâ¯pÌJ;�:¼’ðÎÿ°ú:˜‹o¤sL¢KàÏk ª6ôJ]m0ó—5¤mÌÂÓ—I€©,á\Û’¿è£éã8q! $_½£æj±öQÙ/ÔK£<•©Ë¢Ûd<ù;òË ”�WãKgø8ÓÖ‡«ð2 }ä2‡³àW¶#�uºß»„ÓäÞJØ®„¾]¡ ~;i=xöLòÓÒàY¼‚·ÉO7#f -í?¨‘ž‹‘¸sÈ¢E`è@)FŒd’KÞ3áƒË µ3á§FU"03™iW B5ƒÆËh€²_/1°úÝ«µáæ¦bè�>�ƒ}ŽøÆ‚ +ޤÐ#FD³çZòݧë?†c›íYPù­Ž\ŒÄ6þ5äê¢�•غ…ðF_‘'TèD�r–1 yê¼ÿ¶æ Èý¹Ì³‡æ$ÑÆ†�~$NI¾$y´OÏ@£¦ó(`šŒ�‹MÈ—Â("t,'º·/à…-ðÖö*ž\ŽŠ C'¿£TḢ9ƒŽ;z dÕø0vô–vâ2™hb¶q:oÞ™8º&ÛOJñ~ÄÍÃŒmëÒï?Ùc»Ñ'n'ÉÜ$Œ_mÖᆽtÁoµ³xäü½HL½`]²&ÚzÀ{„ ˜Y—xGè¾}‹ \zNû-Îñv‰"kæÎƽ<* a¥ºÎ` öû¢C§ \8K8kÀr[?íí Ž|頻�\ÌÕƒè›_Ùáq|~Q~Ž;ÓÎô}˜ûæÎoÊ¢Ù¾¡(ºo�3S�d+.á‘Æùpo—Æï>Šþ:«p,R æx à�»ÑKO ¾íÁWF71`ô åÍq‘•™$Ûo¼+çG)NÛ^–-2¬ÁwEg8Sl�PD~.o�Ú!Øú¤ˆxeŒ“×óˉ¤ <§§v¯Ã'cÚu-nc×:…xý�†¨>é‹Âž*À¿6ž¬û>›s±SÄÙB—©¨ÒZtZð›ñöqÆÄS?™˜†Hèxò ÎL”Я*väej!¹µ[ ’?gaƒ{'ÌjŠ¢K_$°ûL4àSôLΰâ¹úD0Útý”mw›Xýýi .’Öý±4}4mCÝYþÆìÜ AÏØ:  Ú#s_‚FÜŠE‘_ÇX»ñ8ð°ªN×0–šT¡òÆ:.ƒ•ÂA�$¬ÎS‘=mŸ L{w”�Š`~º ëg¯Í]>•÷_áIì0«'¯¦ýã?»µ¤ûÃ~¯°¡Û§ÌÇg'Ó€ùtã�{èV§70e!>ºUŠ;óè¹jP)]Ë-¿ý‘n[x>”’\Hžq˜˜¿Ù`è†vÅ<¸•k‚Qµ­äø«šÌc8"ƒµtæœ÷�ZVK ‹Î¡ÝïvÂsÞÑ�_©ˆQ7èÆhýrs€Ê&f“$K75 Ãu§½ z·.=ÍÀ{G…àéZWøæªÂ1Ú'Œ~)0½lâå`M®$mÙé{O1oÎé㾘¸ï´:솱‰Têî’`w—nZ‰÷xÏéÐÍOäî1�u,%Z;âð§¸/ñËÑ€J�EÐ68 ¤¾(ÀÕ”Øèÿ¤üMá±GŒkÛñ>iˆãHW5u7ä´ÌöFá ðôÂ2t¿ä§žBDP¾ÊG/EŽƒ¤Z}W'œmax{‘%LWn¡?jBqþè[¢°ëÛéÕD #.ÓKëžRÍWÙ0˜Õ°¦«—ø(i±Å 4Tü>= \DOÒG=Õð»}ì²›‚vSÓ©ZH11ÐÂ…±¨§¢€W6*’ŸW¦¡b¾Œº} R%!pÓyèÒEó½vh} /¾Sç|Œ{ËDÍ6¡k_§â¶rŠ3aÉÎu'6Ÿ½Ø×IÒØ¼ŠGýû4h”þný÷Í4ÿX¼ÿÿúwfÀµ9޵�4Ú¯óDd‹qf¬_‘@ L Á8·‘2Ê ·ßV“á¯ÉX–ð ôo‡ƒ•¬¼í�§£Â:X±@G†1—Š9Pþò$ž™[O£?ðq—Ï!l�B¬d9Mnh¥œù?†ËÃ!ç. Ãm‰öPI) ‘(4ÞßyJ($¢¬’IJT|45DJ{Shiˆ´~çy(%‘TFi)QV}þƒçœóÜç¾.\)å…iª ô@ÿ=à`ËJ#Ÿ´?¤z^05{Mß}Èdžß>‡Š[—àÄyhøŽ‡¯�<�úýX ˆ¸Ï"{]̰ÓÄë/†‚NQ* ò  –© Ð#¯‰®ðôõL%1oÓ»?6 ÿó<¶òï)â3ý&ýŃ—ìUXÀ‡KçíÆ¯íöØ•¸ }¿LGƒÙeÔãFÜû+…+¥CéŸmÖ¸jØi(@áp&N¦èCÃCyŒü( ¦ÙŽÄP¶”*Gù�ÑK©È�…(“=?È…Œ«¨ýŸñ¬ÙƒN7‡Èêû±  8 G‹2ÀÉj&L¦^½‚2|G.Ð$³óø}÷²§4Z¥fPùùWñêxq혆5±¤8åQ:ç‚®·Ý`åð ŸÚHǦ �©ãâ'óïy¼FŸÊÒ�y‹ûìo3ZÙ—¡äŠÑ,Œ|9?IÐá›Ì‰IWÃz^-bµù3;t>Šþȇ'J®¤ú’6d¹¡ÓºnòêÙ=Öá€>&œ¸Ænþ4@#²O¢õÃjˆë„çÅ÷h±Ë2œšñ‘˜ë÷±�ð$ U„àðÓ9°ïˆ-–úðƒ›Ñ$gáõ# ¹äLCI¹w3Ý£AÉ‹Ï/ɦ­ï«"Œ×ãç�±XtR  Ê¡Góh-)¥?Ò{éýñÐn‘O[¤Óéœ÷¶pŽô“ÿº*hpÁ7Êc•EdÇØ$G1àßœÅàUekî‰BÑZK8{ÝS¤$Ðï†'ô_Ëàti!®YÕN6òT�{Z…åNZèiCõ'ài�ÚóAø�6\2ƒÇû+XŸ‹?°ÌMg|üF…‰Ñ‘Ý…U-üK9¡J¢tŸÚ¼HM„UñÏ º&í$fgUAôÖ™F;L Ém“’Ξ‘ZËÇ�a–àv2•}oÛnb¦ý½@özì…Zñ |7ÍäŽ)V ×€ä;GÓXySº–�É/kðLîN<Õs´Ý`n»¾ƒgÁØ’ö–8 ˢ抈ðOÉãç‰÷¥*³ôVµ5�¢Üåv¯ùà£Tz—ç&û¶¼ßÄ©ƒWJ?Y(9Ö~D)—dø¤¥d �ßâ–|#—8B0XPŠý‡ *ô u\öŒD•æë„ºí?)ä‰Òbªçè�’�‘ÊI„a½ êüþYÒ.�þzÎXrÞžh-QÅ¥Ùöpt]9šj cAv¼ÓaÉûup(ÖïÇÖñpr./ ŠþK×ãžôô¬£ä¨�È,x@v+¦ãRÙtÿXñ8�ˆ˜¬F»ÜÊ®ÁySåt×Ü 2|æ,”Ïʃ�ŸÇà`B+È~ÑaYg5Zšø/C÷…‰mU.Y»nŠñP ¦«ó’ÉÓgÐwÔ“+F9ƒ]ÛñEðy�7xm2Áÿî…À~ƒ-t°ýòNÀ›«Cô»Øl¸œœFùÇ2Ñ[.Óå÷æ¢ÅŽ:µ´•ø¦\G¡¼Ù*KÛÕ!Þ›E·º˜£ždä›ÚÑ:õÝÈûK½^¥1 —÷U=YŶiTÒ¿!ȯžš¨xr%{ì�T¬… þÍ„ùQŠÞï9@j‚Éýþa•MðÜP€·Ç¢õ¢™/gfü»§õ´~ýSd’×À�kàòp�º„OÑ™iKq¶ %ww:£›ÞÌe‰ã$KDþDÀv¦ž4d,‰ž7ØcO³¯P›¨àÛÖK•ö½"©šß“8Yä_g„íù‘¤æ�"HÊ.‚…ÒR¸lõfÌÛ*‹óVäÑi™æD)a6¾r»N�­?D+¾7Ñu*¶Ôár)¿Äo£ÂØ1jMÄÃóÛÈgëLð•8D>¬ï O­]Èî-?™�'ýì»ÁÊËB%Doå% N¸…Î3ÛÙ‡o„©YÀ3±�Žœ¼B^��À ÷O±©Ysá•ö}T]˜€ß†–£¬%ªc¼qNû’¶ê[ÕWƒçôÓÓs¨PÓ@ji {?7œÜÓ1BƒÖaüýIãÃpë¼/XûÃ.M+ôØ…gh£ÙE¶•‹�‚�0Ý!›B8ºélÝÓfz×s ¸^2€gŠÂ¨­ ÔÕ ¤f e޾kïh°ræƒî,T=¾Ìh Bñn� ~,Ï‚’œzꑇµ[QkñÄôç`µr'Õð’02‰9 Ô[p–"5ºk�Ç�ï¼ë³Ä­køà÷Rì|$É]‡OÖ„¡¨Jé~w¾Ê Çç¯Ì#˹°æ°'ÙºH|EÂÉŸC#ıI ¶ T‚C|#Z{Æã©g…Tk,·é…ÓØùiìÇ#1 ÒYBsfTÀ;M~´mÐF…B ì †'V̉¼¯4¾(>w¹âÄß(ᦙG»IäqòÂ2ˆŽ„×ÂoS¸y`%Õ_‰++r½Wiâ"smT)ަ]R¢TØj.˜÷™^N}O=ÓÄ©Ætˆ»-ˆEªÄ4;šÌ_¶oŹoÅP]­š:»íBrˆ(¾� ¿­Æ'I»q›L=,s˜�íšÛÀ´,N¦é[}‡>šáê¼§¸‰®’܃jbéÑqîäÛ�í#�\hdº54á¹Ósf¤;—Fª–’¥r)ô�ò;Öʳ‘ƾ#µUêøv¥ vfÃð*U̵ÙB?£ØÀß)0Å«‹ÖUÁCx´Ï=„öÂjPpZÒh¬X”¸$£ºxÖÆÄqeQL < êâ ÞéÓ•¶ÀT·+|þ7›Á˜•z“@S˜ÃTèº TìNÆ›Üð(¼’ÔWQÆð·9“½âM:Jgÿó7œ¡Óß®D—åÄÕàÑ59 W§îV1ýá(´" �Õ?2CóÈT³$ðë'±¹“"†ÛÚC ¯s.OJÉ î˜ï›�Κ¨¶8üãËâ¦Í¹•Š×ÇÀ]6™Hˆd³½µ/Hk[¨¶¿%_£Ï£I±6#Wõ��_m ©3¨ý|ÙÞH‹¯)À“'³¤×½ÕFï–0ÂݶŠ=ûTßßÿIÞÏk…�‚Ý´t¨š8_! mQ>o´ o Gû÷ÀœWŤ«}9?— SÊÃ¥¶¸æQQüú—¾½v¬fóÂä¬ùH*lð¼â>¼â¸’ß9£ÛLmle×ý˜�–ÝVÌ‹=Öxò¹Š-M`_têR�¤@ˆ’Hdæõð㻎W´×]^ìУۥ^Qž° >GÇ+t`Pæß9 ƒqtÛ•=9“8-±‡lÁ0F*Pš»Uä)©…òà–!U©ÿIx=«IÂqèºS‹6ű̇Ñ*&ÁL++ )϶G¬Ûá™D¸F DO-G;³E¸U-3 O�é*YŠCßI?÷:rUKh”@òÐ�|­G'ãj‰èÓ|š•†bBHãRuî¡,8h_ϹrYuc]›?<¿PO䎽'ÁÊ¥�Ô_÷_Ž®Þ#sÓÃðx‰‰9ÛCOŒ.á.Oý†%èá}·!Z=„£Q$¬U huŒž»¢„J×#QsÉ~ÞM�ÏzC�™yós:‹ÛˆÐônÔ¹ þ"ÍÌäNs¸·^ÚÜTaõõð`ÝG’8Y ÂqY8CèNhPxU¨’�¦h›ú‘>9t›{Gqxϳ܊ٛo³ M#Ù¯ƒ°¹- «��ÙóÛ±ÿF·¡fö!ßJߊ.$Eò÷è©<32fÆ¡u¸t•Ã0½h ‡sa`¦¾ÚJ49s^Šr«¾Ý¹†'8à7~�Åcël 8³/·[@Ó‚`ß© ¢æ£/4í·£‹uÿ#þ¸±À‡ÔÕVZ%ÃÑÚl¦ý³¸Ý[GµN¢U¦ œ^–·ûɾÑKè‘/„ï�{a€T=-íFW6„z¹D¾_Ž9Dø-Kˆ™™?GXeˆø- ‡îšXR:nе<û™Ð]öXl¤,n`~ªé-ÐÁiuÅTSJ†xŒìÅciIÔ£ÉûÈkD¾Å�xJ,G­O7q­§F }¡Ê†Ú00{ Жc¤›Óü´¿tÞ‰Xò=é:-u#wçv’À_Wˆ÷Û3¸O€Or úâGšhXn`\•êw‘üóUøßy%|;vŸXȃ÷.}°OÞ OŸ•á¶B|ë’C*7æÀg«-ðµkˆYšå„7gð£’J»A¦�˜¢3ŽËG�ÇhÞõ8’p7Ö_¤ôº?¸AÝó×gõU´†³…õÛXë[ö5:›Yýçíï$Å‚Á¤þ¨*o¹ˆ çeÀNíòL½©Š[€�÷J¨ñœؾÏ7mIDO°È˜I¾ ‚#8î„ ÏÎ$õ�Öƒ._Y¼•5¦‰ä­Ž7q°èeí 6ƒ þW)eXPéÎ3r‹H¡S)f ð=„†Ë©â4Û+`z>…Ù²ŠŽì‚T§<*r±’÷öuŽOÎÁܘʚbcÐÉ_GôžúBbÄ]ð}ü�‚ì'ÜDIj\V×¹cóáø©dq?²'wí‡Ü.ÿñlÛ]MÞ“Û0Õü%K†ïÐ_<º$ÿ¿IRèþœHÎï§>^qÌM3Eìk+ÂÈ“ 2™‘äÒkSÇÄ}pv“vV|CÙ Ôšì 5d6,«&šDpWìôyjŽé÷®2³õ¶áÉüwìŸ3©‘G uùœŒq‡i½záZ»àU¥OH/$ uÂDó@NU_'ýòíN³ ä^ò+Â+m Ÿ�¿a; ©é:Yx}j)ºZ»aÂð48-•€½!Ø1Ç�½Ò —˜`E¿/ÍBøšV%0¥Œ:)³q¦v Q»»˜= AÿÙpNwˆÁ¯øÛø"ÿ ½ðk+=d×A¾ñ°V>­Ý3l®QÝ­rF¥ÏÙÃ_µ`ë^),±¬æ˜•¨ÌòˆƒÒ¹ØØ=Fmf˜±RËÕÁx½&ì¶$?&דÂݶ!ú‡×/TônÑË¿Sˆo¹9sã+çdž8™^ò¯ÛÞÛ+Ï Ncm,î+‰Fö[s4i=œH£Û;ˆý│ðô{åñr¤wüáy³Ç¾&`LW5;­A=}`_í¶ÇÇuÛ¡ñÏò}­v—)P¹!úb¶Ý3s;˜lŽcµò°þb!'²Mû[âhØ�Ũ,­ˆo?ÐOý¯hÃþ{XA��‰ã#Ë"÷v&®C‘ó©n/Ù&~“e^Ý„ÐòBl;b'Àñ§?¬ 2�…"ÅÐ'hJJ“Bé·^kø´Š¥µF#ô¥òT=Ïdêh·§HqóécëV'óF¸ß�ºÂ}µÜÿ¶‚”�È_rý&‹1WvâÏ£æ4¬D‹OÉã�Õ  ó« Jõ ]Â(MêØÄ²ÂG�ç ;g?ŽÃÆÐ(Ò9g;-#ý$¥7‰6«iR “ `øk¬ð¹§4‘ijô‰¦ –&£nµ[!4—ë?ªÃÒÜ!G!tØv�¹9ü•)k*$9¡Êر†Þðaîþ\v·àÛÎ\ª5;›Î�XLל¶{Àùeß96¥³�x‘ïX5;Þ¸à)zN;áˆÉcÃF•xfO2[®w@_A^C€°ÓâØÒ�}éæ| â;êŽzWß“�¦ä“ÜKì•ÁË­dÃ?œgFWþ¤ïÿ³ ï ãÙ!Ù dµå^xó�m2 êÈ¢4U¦ÞRŽ¥ä0gýé�ÆÒ»BŸ0nÆÏúD°~™H”ÚÑÏ2šðõÇnx¿ó4~Ð\Ft ¿“Í´Nò6ɟˆÁô½\ Å%OéÅ{è«g©È®’}ëµTee Ò BF¡ïÀ#%ؽÈ Îg’[{ÍÈò�Ûd[¦ì?ý�.íІZ‘‡(WöŠîŒ˜ Fküiéè;r!Èí3gÕýS`»õ„Ì–‚Éýh¦Ò~ÎuÿT{Ï!¢făϖ‰r%” 蘌 ÆsCÁ¢±nÉF°{ƒÓñÄÆTPÙt‰¦“\RÖRO§¯‰�Ñ·Û¡\d‚½'¼2+H¤�Î’¬aÛ£:‰i¥~�Jé 8p8›Ö ò­<Ü÷¢‹/ôЧ/Öá�Žý`·ø"ù°¥‰λ5+nÀÇä0¾_†ŽJy‘Ø¿},ŸôzcËÈŒqktí{Šú�®³{/Ä ”áKR•Š[rCÁEA�Þ¹r –¹ÿ…ÿz„¡$ –tσ ǪéÆûþ L ƒÞç–£”{Ö¾µiŸRfÃËz‰é%¥Î!lÎíP\’·רï¡f #Ìš‚Øxs’&z$�ÑFßZaVú Ó°cÖÿ´†)Ñ䪵Ø=x‰¹á³ÁB*µrÑ£Æ<æHn§GÆ“Iy�ê^ÀÕ?%LÄV À‡Ø{œzˆRÇ"²)AØèÑ�IxëÎñ*ŸCf膠؉qFµþ –¾Jýïþ0¾ƒˆÙ—FHíÑ8/s|â@^=Œ�‘¤ô�|LµßÇÃÒÔù g9“a…Bˆo Ë#°DwÆD‚ó´mxîÒM2XÁÃ1‹P�°:¢í¸ç‰MÒ}FŸI—‡þÖÏ«Üór˜~Û´ª�ù2žqqŶ䔲 <…ÜZ[šæ¾gFúpŠÞ‘LÅùÓIüÒD|â7N6ù Ùµä£dB óÖ?ÍL"àªQ%iRA†¹KÈÙª\Ðâñ òÕŒ…ì/<¸ ö7³]"3áÅj;\›iŒi7Áj<œ®õ Á®U Xçz5RË¿á #îœò PrCEeWài™åàìµ –»1ÒÉ8”84Ÿ˜@Øþ|œ˜¿›Ý1Û‚�€žøR|X;Bõªi‹Çy°½VA�/5ŲԹ\ñQsÔ?JO¥±7»é·DSXèC[ã¯eq´…§ŸžaRIAÛy¬ÍoÆ …XÚ~ þ[NK4ù�¤nÁÛ"eú ûÖ¬Jbw,l®”ߊO.™¢ïŸ ”ž×#³‰–ßLÚzÝ^îQƒÜcõð†å’s¼«`á‰j¬ ÷$jJ�qµ¥ÝœXÓw› ¿NœbÒ襾!�¯Z‹ƒÍWI™ï*Ö¦° ůÂÎ+ tºzæ—5pØÂú£ñ=FŽ5�y+\hŽ¢Ù¢J…W$“Þ¾ã¸bLƒOqa‘†.¥s~c ~8 HDFÜqnM1ù³W ?üò—®-øÁs>´xø¸j‰uõä—8ƒ ìñ÷`(V o Sgs“ –çÓ٩Ɇÿyƒ³v+׫CëJˆDíNÿ#Í”6à ãƒTô¿c4_°†¬í Ç^/Œ02&“=žø³I‹]¡Úºƒh- Š¿ @oàÐvcLÚt€ñÕæÁ[�º8|©‚$†áÉ;ò ou‰3å�~ÉG°vC¡¬èØlQ‚ò¶A:sE:Ü»6TµWÏœ\Ô·e×Ì�÷g  ÷û‹ôJòn˜cžöÁÕÄR÷!š9DO\eé4“épÔü uäI$Ê…ŸèOóíX:5öŽë®Nò¢ З¸�ò­ðéÛaúE½,W+WÕsh™ #ð×n¶ÇSáæ4–G݃Ö/‚óÓÞ±Y·si\Ál^Üîá��)¢xöE9Ý"îD.ˆª‚\Ò3²ß ›RÐ1ôd¨>#—�E¹/Ö·¢DËÓ¾ãF ÎÄd¾rZVƒš.ÌgàC�Zˆ|÷ƒžT<Š…‹äÁé¹m·G¯—«¡o²ÃfÀx” Ù! òõ*”ì½KÄ~Ïäžç›…F±øçÁRYžŽÚ+~±XˆoþÝQã^ø_@Bz² áA …ò0”ϵÅMÚÔõ¾,TµñÐä<ÜÑ·�´ª$­Í7Tõâ6Ç0ý¹ìÁ8ë=}PÒÕ—ñÐÄ48wt˜,>_A­¹M î#-‹ðÔç;Øò²—-Q.Uôšæ#×ÑÈ:€ZÛš¤+â¸A�´;�Þ�ià5ŸÏ¨[u5þìÿBíG½PþŒ"ðZ¯D½°ièª­Š •SL„«u�ÅlÚT<�XÒ홌q·v§þ¶®~­ ¶ûQÛ»çèÏy˜µòuÆX²WÛ·¿†…‹•¡ög&嵦sJÈxíZ"wÞ�Lݦ^yÇÀ$N n&ìÄ´¹ÊøÄ»µùzhvÔ2bߤDŠF¶�‰ÅåìõûLÍ[Žõ©PL1__Μcï †ÑcךÁüOM{/ˆ\!(4Í„ÃM‘8M[ 2¾s mÑ95¨R?³�>yv…)…Ò‰vN‡ÕÚ¿w™“âî!Ãá¹t…Át1C”In&/ÂüI¶«˜Ôþ`*Ä£¡ü¶\×Éc$òšˆD¡6~J8 O¿äáWiPQ±™¯´ª0“~çá\l¤º¹úÌHo¼$47 -‚p~µ¥{³6Ñ´æ$|9p�8¨Ý½œüþ¡ƒQ‹®2¹ÝlGh)J @)w#ðÍ:Œ[FžÃéWf8~¶ŠÜ×x‹£¾ÌLÇlf»Þkª I<„‰ýàòt¡5/N¡  þeòé ÂYg®Ây±3ŠÚ8>&Ø¿ôôçàß«Œ†ÊÄÔÀ˜”ÿµƒ%Kl°Ïu,ù¹7äÑ7çqO^kÁAâ·f3Ù»«…„–FД{{iÏ÷oÌTq{|V.š?’Çí=/I †7,JX�e,‰¡˜îQ�‚p V#P”=Ûr‡5-´ER³ä{ªb¶Jám+òÿ´‡a³@Ô”€êUPç�FÞªEž¡Ã8çy5ýýö>æ¨:þë‰÷„w~4F7oa¯}_‡²§½°NJÕ¯Ù¢_I%Ί$±ºùx_Ã<$ÎáŠ�Ï�‡½†övØ–ˆ§’édR&DeìfÒÒúÉ7ÃbÂÎ×"{›®À»Ï×QM¬€îqžÇF+‚ˆØ'¨b'É<üåÝ€û¼­ah{œ°&¤ç—4 ›ã°&ÉÊâÔqÏ+HSš†œlOvûÖ)ÒíçOœoAÊ�B$S† �òÀÅüå^“ƒaË‹¨ÿay¶fy°íÀN/8Qw—œ É!N •Ìï1R¯¸'KÏ¡çËmDoíZ {×ÀÒŒö�3-„¯ŸàƒsJ¤¯@ u ‰{”+ûX¡ š; ‘¯0¾-æÈ¿æl} y/’ñ‡Ë@LщnÀ~s^th`6µ¤²%4è û4â9 �²¿SáAúaåDh8‘u¶M´³$ŸÜAõ¦s¸ïúl¸¸4æßeŠâ¡l `ì-´›œ›ŒU8e nD3�j¾¸öôݪ†íÁT¾'’îo:û’Ľb>³X¢ŸD_^ÖŸ·ÛÐÉÔ$z’±Ia&ˆÄˆÁåG-D©-€¸FO0»«â`T=Ý@g ûªm�áú’~Ö˲ c®`qÄ꿆%�Í‘p®ý1­u¨C¥ii™Hø�%Âõiì"ñžØç@L| 6;M tHŽv~¥Ó—pÜì7Ãø2tO¢‚Òñ¬A¥Ùø99î8ŸÀÐÌt¸¿ë/ç}ßÑšWŽ9Ñò¬nåE¼ÄØaKˆ®ÿ"?5/b…Ä%êFWÑGÓ_Á¦mAù][—ÊÅÍçf¡PÎrŒWÐG9ï$ú¥²ƒPÛ(|¡ݶë©ÖíômÁ�*UY)¦· ŽîwÁý¼”’9(à"O�ËƬø‹T$}ÖþT†ž¹ÃÔn¦¿²”½xŸŸÉÒÅrׯL¢Ç~1Ë | àžO\ªî16ßL¤‹dÌAàâà»ïL¯>Š`9#дê'þT<Aîpýô9è¹£‚g©7ì9�_Íg¢ÿÒ¨?FÔ9vœðyÇRAšz׿½zDÌ^_'ûįïw€Éã(ìåÃè÷®ÄhÜŸî’S„m¦s�þ¶Šq#=I¨Y6Ù8Ý 2ÿpàR†+žˆ¢7œ\ÀýO5hоBåTQº{8ž¬�1Ç a9 {u%NýU„Æ5ލ³¡Þ3&¯#%YÅÈ*x°9Œ Ë®Fï ^øéN.d;0p?œ3;Ñ»Ì]pqm­ç-àð[Üf‡Ôª0G6e¼?ÑOõzUj‚s`þH8TO䀱VÕÜv¥Ji¬Ï nGÊal „÷¹Ïæ.…ÊÝEX`� Ì%@Øø ½Îtǹ=pLz/¬;×”£jì;}›KµV¹ÓÑ5‚ôÏííØá³ ~9IÊ3âé’á|fuxÖXX ¤çU0úõ›þÌé¢ffWñ¶Š"ªË†ï�‹`w1�0�ìÉå ï¦vÑP^î P1*O‚Æ.d �ßHQ­™NŸžƒg Œ”­ÅðW`0–™+€ìíÇ0wk+Q¾\B‰fI¼ržé²é ëV�%߬w1“r3Q-y9>}¼·_õ×€{Ð.õ�,lÖ»× Ur™˜™YR˜’―‚ö„˧vŸ< ¯*„níÙGÅ ’èù§ÓàåÒ[¤;QÀhân7½ø"úߎ†Cן ìTîC©œ*ç)Ÿ$‡Ù±üÜ~Óà�Ù�÷’ ÷þ Ä¿’ƒ¹½ªFó�’Û²¿É45T“×äDèdâ»õ×Ñ`ÁOzMö þ=³‹<Ü: \K/ÂóS*øôãMè ôÇ×5/árñÒæ/�¤LË ðþÆéDvÙk2í¥(Æz&“;¥ ì´ ÏJÇAKÙA¸â…K—°¾1’¸v· ÍÓËa©{ï¯H_[‹šüH“ C¡ÙÔR¤ÅÁÿe"þZ>‹I{ºr/BÝ3„ �O40t w¦9OÉ@ùRvÃé5Pûf%Dæ¡lríÖýÙ+Éã´¥xÌ@ºE·ÁüŸ‚ð.£/- †À!uPŠd�ÛÀŠ…˜íy—V_»Šœ‚øÕPJãÚëÉýætôo&;Íÿ$î}XÉð�Þ@â �ÂÍ?I�ïzåz~Ó7&{ÐW=U;$Ðñö üThJþ§’¬(y¬7j¦.Dz‘[M½Ú¥¡Òëjf—ƒÑe,Z…t:_üUÞǽåHX‘óçxpÍ =§Ï¡ÔâT’¤| ñ¬4jÍÆŸuáIJ=އÔÀÜe/8m“y¬¡@1UY~•–]|HžÆ�‹U­´3ðä?&û!jc%aXbÌîrÈw6*»@±£`úNŸ=×Åv™­xmD�½Æë�ʇË`oÁ”:+�û�®ÌMm…O›¦¡þ‘j²È_ªûÓ±£ó&ÏüD_/�K:òxŒb¥^2ÓRN£vy1Ùš5I§Â ¨î÷ÛÐìÒE¯êgÐ5#ùÄÍÒ…D Sß¹Ïé—€uÄXj%zŸÞ‡ƒ‡À:fG¤/VÕž8ŠS1„k<ƒ¤§>#?.éeÞ öã�:rúêA¨–ÿBD7ä1šóÀCÉó°F6 Z“YMY�IøðLó³ŠÒA~˜/ÔÒqñ¿òŸoݧýß}Á[²‰U½¬�âA—ªft âî=ðKHÇÄc(}ã-Îó†=q!€ìÖ¬£º%`ÓÄ8Q¿û’ ŽŦ8º8�KÿÚ#Æk—qg Ÿª*$Ye¡k£t,“‡þ–�9ÑL¼dC±Ã*‡ã¢Ž¡s–ÁÙPCì}ìCwðfí¶þãðCWÍ+úË5šŠ6[C»L5sj÷*faŒÞ=Ì6« 2ÅÆQû{—áy°ÌH¬Ñ¦zŽŸª3‘›Ç”5!.=ž- DàÝ\1´Æípë–ÖTR¥?,ê?ôþç6>ðR¶‡:Ûá–v9\^þ/Ά3jBÚ&1È~J/„®‰ñ§ìàº[´÷ÂeêÀw˜Ì8D)hrÕuà^{¹ö¸°.’ÆÇ<¥aé¢Pýk�l°Áõsâé–ªPxe–ìi„ÑÂ-øŸ±ܪûJF.ëâ®”Fª—SCžO /«ÍîЪA)§.ªŸk £é`¹×œ>¦þwM�X}I§{xÝðP�ôè·ñäËìfa^¸ºÅwÐíu$¼Î–¾¾LFS¬Ð¶@ê”âà§??ºØô“ùû&9�k¥˜ƒ•ãLmO¶ò3Àwœ$e+£bÊ©ª«ï×`ÊÕ  ZN×Õ,F…í^(–é‹KhÙì�”SüæÅeââÿ®Ó7ï@E�}³ÚÈhð¾ –dÙÃìþõ w¥™Mì‡üøF¬Áaæ;]³×V/)áà_45Å‹Ñ]ñ‹d¸ïe‡õ†á@›쟾&‰(�˜v8Þ©TÑ šÜ]¹Ú®?B~Ó(0¹ WKëH]| ìš~‚”pް-<8{ù"<£�Z¨É�å¥kɬſ(]ÖN §íÁ모ÍËUá®Â¶ëAôd‹<ŽÄKÀ—¤\zcy#ýu}ª[ˆÀNýk8ñÙ�œÒe"‡‹ ‡o6®�7ò¼B n¤´gk õ“ÇdÈjžÑ{÷XˆW[Hñ÷sòB¼—Îû(c®O±v­s @”&쉆F!Ї³®Jø<¸^¾¼Fîd�‚¨il`’Á f.=¾Õ ÉT:Ž âNµ3äQœ7²sãÀýÔÔY¢ˆª‚ô]ÓL’â'|iûA—?lúoÕç•`ôí,:fÊác©íìW�N(¯ ÂÅg¡óÝ]¸&vŽ­×…âzܬ¹yðå.î:…]ò¯Ð/9w.ée²ÿ˜b¥›Ä†5CÜÎÌß�O˜C—hQ»—ÇàÝÊÇTdâ'9ÿTŽaÈ•&º2&Ê�ƒp×ù{(åﯳÜaÖ  ^ nT³«vº…Ru»aò3ùn7Ãg¢Ñ "<%W !-–€ƒo” €.${L_0?LûQééC^TCLÓ%ÁäÌgøýÛ�vèt_‘zG×Þ%€FûIÒÀ\”xT%[UŠkº:àbã§½%™ÛkØdχX|ü=Øo@CGk|Uó_Y]Å6x)|n¼â%jßšØEþ™²a’ª•¾£µÉ@Dî>s{P¦”Áy4¬r/ÑB�Ø4ݘÎ*'¿¥ãÑiK)½ñÏõ#h»¦ uÜ ÜÇwQº=_:홓�*ÓÍ@Ò7ˆÙ¸èSðB [_ã3ó°+½ÎoV½�é°Vi9¨=½À\ì£sâ÷A³ÔS:Ö�T#Útšd!!a!>Ï]Æ]Éõd£:ÄM”ã³|?dÄÃò"#àWŒÃ{¿eÿy—Ì‘}M‡¢¦/!³¸�XÕ�gßÅ�Íw¿qâI)Â7¶òùY’±ø9~´ƒLur¾Ì¸¯[Ï~¤yɳˆàþ"|¦ê R‰Ê¶a’éÖ„ÎRßiçHÜYt CüI¦P8$(Ÿr‘Åž´&N—¸PÕ.7ß�¸=¾I[=Áë ]ûÁ ½ün1l¿Ð�]Ôüörô<Î…ú‹73}p ô¦/wšÐ¶’;Œ¼» ö^õÀÓqùdÿ°¼4I‡üd?�Ì&î|¦dhà$u)¶a÷EÙcÕh)%é‰ÌyÃN"ÄùTõGØ[ºC˜b�e�ZÔJœ~Ñ£¿ï²Úõð^j?(å Çø0¦$XRZR¯ÛDÁÇhéËR‚ª�”nUÈÖϳáÅÉуðìX&}x'†ÞŠà~ŽÊ„ѵ°¾¯Ê6%à¦cÿ×��±ù1tráC²UD S £È›p²~ô6QßSJì¤ 1½æ(™®`L/¶Ù£×£Ü[AÂgYÙA±Ë%—mÑúJ¤wËÀpï^O Ë{W��^Ä»A™ü0UÅÝÒèù4”Ùu 4>ï¤õ“†²ù ¾º¨ˆörG@\aν¼�<»'Ä�è[ç•q°`&DH³= æ"Ü”ðäçó€{`.,TAGö/‚PÑ>¶éô;ª§Ž¾1=Ú(ÕÐJ¾Þš�JÇü‰`2þ—*/6ä¢v£$7¦û:ip²7²i'¡–~Œä.-OÎÃÑcØó6�µ]¡ •ÔÌJ O{¶ÒŠƒÞàË¡;ýE‰êò@Ò*tÿt/%ÿµa|r$!8f’¶¥¯ <÷:‰Í�LÐm¦’ÿ-‡yîßéÀ° Þÿ+‚ÍŸF©æ‘P楕4fåã9o1 ;#ÂÜ™YHNWŽÍ¤Þ2OÈ‘”o~à?–ÿN‡õÃ@*qÝ�Ä×#÷ŸÎR8”ÞIÃüdá‚j%•‰ßžþaì¿ÓÜÿžPýç .ú0vÞê"�—Ò ß ˜¹C7 ¢hX<»I,�•jB¶¯+b›ÝmÈàÇhl¡ØrXƒ­µá‰X$l9Lßg'@M —Š:$B–ÿy’£Öˆ7fM�]gÑ?Ê“~ûË’Æ€k°¶0 ¿u¸Àï5 w¬wùÙ.„ÜÄ kGèƒJ©�ý"÷hºì3ê9Ù�<Ü}ü7È+×N曋 ñ<Ò ³^>¥ïrùѲ¾�:e¨°¢ÿyÇKQóÇN˜l€éæ7PEË6Õ*"O×/²õ†|VZŒÅÚ=è´Õ„††Iƒº,Ñ“à…þåT×èyÕ.­[HÆw¢héíqYÈ,vL�XïÕtÛØ²dZ4+ÇÃrå÷ôVÌ"TØqeʾà糉–Å&� æ4\?�›­’™bët�Ôk˜§Ê0 �ºû2q6½HN…äž!u <gU S[1ë°ÄNjÀ®*AÐØ.ɨåžd¾ŽÉñS´:´�Ø ð£ÒþÀ(ßBÇKsÈÝW©pì5/Ü¿{C¾1œ·ÓÚ˜]xµF´J¢'J JA¨ÜŒ*¿îÅ VüÜû!ÁpnëoFäâ\<>ç8Þ‘1a“¯…SÓ`YX•Ÿ‡m9Ÿïã™ÝÚ¸X+–xs�‘ÁÅX­Îùé�üP ý#Ý»Ðpá~µå Ø•%øÃ)§Š3lDìîBŽ‹.˜ôÇFÑZ¿æ¸ÈxãçTazKè_¾3þqƒæyø bÖOéðe!¦ã×\\PRJmWŸÅóñÀÏjTÙ™ÂvvÊ€PÓ"H³Xˆû‹‰Ìá„ù—{“ŽŒÊàÅÑsˆuPcןµÂÇ/¹œgq÷ÙíRvØå8Dgnl‡jΰãÐ&Ξ’/d£6 |òšx l¯î!›»/QËc(»,ƒöu§Â¼ò(Q—Ct–\�}¶ºFESk!ýaü)Ié’ë?)|:¼âSÄð¦Åð*½“sÈÎC¹•ôUòHõ“pÍÜÖä‚É»¾R¡`wdŒNôÙ•·È_E,¸RÅõ¸ê‰ `]/µr ¦ �òH¯G,n”í@Ó1¢äù0¶?p�¶?Ùਯ#®xÂo;íÞµ‚ˆ¹þ¢zfš8çìgvù ªí2V…Z‚¶ãb8Ù§^yoÉCzOu–ä�žôMIáêýøË!ŠhÝÔÃÌ yøœ‡²?ýÎUùë´Ó7‹CÈȯ2ÚÈ[L–(.ŤŽdðK[J¦‹5$�vÿ9ïZy�xíÈ_ó1VÞ$ gûÜÀ¶Š·˜˜= :+ªáÔÈ:tžÈH ©Blj~ñ\¿Ý=ÎaÇù¸2Ì œ$uÎy4”ÿ/˜�d¶‡%ΜWÇV{äÐGš!p~^ÎùfE…|aÙ‹HL[QÏ@ë½®Ôõ²>PׂýŽ%tßáo¬¯Â?Ö N§«N.¢ë¾D+ä‡�»Tѧ,‚!qrxàí5²í™ �]Æ EôŸÍïí4§v',·ôG¥ŠxœtP‡˜™ñÔái<ùµ`>Y»†²¨c 7q¿«}Ӄϲºê˜hù�J.Y…M£ŸÈ[Ù~Æ;§ŽôæÂi¥£ +£â»©K¦#‰õ5™¶¬4�£Ã¼°ÿi9±µ»+ù뀳’‹u*/Y…϶ä]“ÞøNgt–ãË=ÔB@†ïܦWì4qÃh{¼+以Á2­Õ�§Á×2[œÕGl™Ö1ä—…0i\ø‘4‰¬ÂM;Èú&)ˆYŠS]pËLÊïø’LÎß eôε)Üó�!b?¬ÀœOIÿªãؘ—Hz·_w÷içvmuy¹Z[È™ùÂDá¢,§ˆÀùè–ÞFóÇh›‘aÖÏ>“ÛèuË �ý¾ÌnïñFŽ‹"�oQM²¬µàI—5oפuºª’êyp^æb`¬…&ZкdéÕÂoi£[GIÁc�K€…y©Û€‚[éöeÝUÏcPo÷ juæ2NÒ!èàõ¢g}„éMï <=° ï”®ÄÞªEPy}5^ê»H÷?ë&O/™‘Ë?£QM¹•Šs@6Zÿ .Â͉Á+x‹úöà×%ì«Ô4ÌoQ%Îì�4$ÔÿVÏ­&Òg¡†fyœùþ¡0óõUQ ç-uéåÛŒë–J¢É¼†¿Ã>Ì60î!³AëÕ1ب\ǮƎé?×ÎÈ ±À²;’Å{K|ÜêÇ.Ž_FýËñà¨*§ ’s²•Œ?ŽƒãìA�,ž&[�­ÃR72S3‘^V×€µbø†,"ǯCþ©ZÜ»å$uMË¡W:tq•Aß1 5ŠÂÁcÚ=ôÀ;ô™Þ~4yHç¯â‚ó÷ãCÖFïÇëû“I­ïí~s½_$àO==š¦?ùÞçØãSúô�Ž9Qô•aÏ_tÂÑ9Ex³ç+Û@È_C^Lxs�Tv½ �[àaÖvÊxF¡€}N,½‹]Ë~BÄÈ}&ÿÅ:´•nBÛCwqNB ÆÉ—R©²½è¨Ÿˆ]<ÿ¡‹¸úC®¨ú÷(ç¡®’C³›Àë#¼FÚÏÂñÃê…Üà‰«xy¨Nþ,‚éÍPÞ¤ SwèÍÓ§pž«úìR¼ÓvÆã¼C‘sÙžš¨`ù™\Ü×E×½#à 3AçƒÊÎ2ƾÿ´�¤Ÿõ¢‹Û ¡�û8¾·H‰eB]Å¡»ïIH‡ú‚Ý, ÖþŠøc¼–^{r�Ô[Š‘/ìÀºê{êV*•Ë݆Ǽq·ÏIt‡–^o:>­Œ~û­œ•Œj¢¦¨P}*¡Wð¢v å´â‚%Œ¿¤|ã½NœB»éi½h|ž¬‚qneìÌ´PÊ?SŸý,Œ¡ýŒúÛ1š¨%iT²×2×áÿ ×w<–_p+”([H’M(;Ϲ_ Ò^*£¬´…4ü¢¢Œ’�ˆÈ.¤¨¼Ï¹_ DEEDTVŠ’Æ¯Ï_çs>çºïïõòàlœ–~2«â¡ü•%&ÜÊÕ]¶0.SC?:ûáë�›1ïän\žõE?:BM·î9¸(×¶xßfSåu\z}bøêT«hžUØŽE¼0�”ôžŽÚcÿ*J<ø;`ßÀæÛü!«}+v?‰7lñ‘Èàœ¦`oˆ®´q)¬nÌBûl×¼ ¿{ñéö:Ó&ÓÌHÇúmÌà³ �y½6ìr¢º÷œ0Ûð&Æú9BýŠGø‡3‡ç¢æÈªz?Å÷Ñ©øÂ#œÔóm! ƒŽâŸÖ d‚UÃ{D3ö7ztù�V�‚åDêÝ :¿§Í4ÛÁ,W’7·é1šjÏ�Ø»‰ õÓ^„ö™WA]Xç_?°žígPt¬›úŀƗ%d¶í_Âon‰º>†ìÕÁÊ3¤c\=ùß�nÙit«âsÛQ §t¨‚ÏVžÇÞ°åðËÀŸêyzÓƒ:™®s ýw9î‹ kÏ(Ü¢u–~#žO7B^ã1”<ü–ìÑõa�¥jSm»¼ÚãÁȧ‡îÇöà½äv(.> |ë1Â$—*¾Þ[4"á¡Ù^ˆi}B¾I¯%ï£Î²ÆÕgÉs_>T6gÆÂè­ùŽVZ2Õà¯\Î3_ëC¸'Ft˜)Z³!?¡¥.Ó•ñ¾âovñ{ÞžÉ\ÚžKŠ6áÄÅhöëEyNnN(Sí¦Ý½÷‰ep ŠÕ âÄ‘zê”aLÍœôpõèÖ$ 3Ô݈�ˆ1³t±®yf‚mñ‹Ù·‰s9ê•S9–tîÙ÷ˆäëçB\ß:(¬~ N.ŸØ˜¼/4qC#ŸæMØYzì¨o�x-æÛH“ކóÔýÆ HЕÅôy 0ʵ‡L],ŠaópÁ"y°áK#“ �á•ïªz: ַὊÿ`ÙÁ3ìa©÷¬mîiÐvJ$½rÓ‰~_?³Ã9~On…5ϨØX¾JëÇ­–£Äå• ÇÀFÖ](EM•3àäÔ‹=íÀÎ~KãÎ@È9q=j‡‘7Dá™›¯ñ¶îVÓ'Þƒ¡ìy\œÉÁóÃ%d©� ìî5å¾[r?ü gÝs£iáuA´=u "V>¦ž=i0k¡ ¦úˆ!gíi�VP!^_HfØ9̘ьy¾¡�@`ÁA¸¹tJjmƒ…³ Á@NþêÇPïÙ‹ÀK`€r]cHSËY–|WFºg¤Ž£Íô@×A(µ› û¬…9ùEo YP Ì’±¸ìø>ûçצpHg)í ÌoAEèÞ;ûkb׿½øI@Î:üB×G³Q½e5]©ÈM`8jÙFdaÅRœñ8 j”�},VB•;i­¯4ûêÞQœæK~ÓgÄ@b¸+×öÒÍK]Øž¦+hõù1óœ³Õ÷ß�+üÀGûDzñxz�øç¸Ò“¶ÔÔÜÅL5xüÅÒ¤Åx!6©Ìt‰?dÁ!HuÛJtCÌðÂã06bá†ûõ³!՞ܯ‘…7Ë`ñ÷ÝA…">ÝæºNfÇ7M%bÃöÒmÛ¶ ê# �“Â8i%ÍÙÅžžþªhñä{p]ñ$¼AÉ™0�ì#xulÛ¹roàq2üâÔnÒ‚2‡éGåÖ—ä(<{‹ƒ;@6ûh2çˆRô2HпDâî³û˜ÙJÓe±éË4P´i½ëTï·]f‹;¾§cra$ŠÛ}'ZÅAøÒí0 “Dzì/ôBëržß5ZŸ£Ëäþ¹Ž“{2é�®[ðXì'±êf–ë—ÑíÚvÜØÓ‡ØRqỗ5�üñtu(ù38NæP7ëUdðS }~GŠ×¨³ d¬Î�ÎŒ[4àRF›ž`oЀײy(^Š¥Ç àµÂiˆŽZ�ÃÖôyyqEk–«ÍˆAÔfe΋{ºïº.ØýüÁ8÷Ý�•sOÓ£í[¸£Ÿ¥ñAlž¤’ ÆoíŸ�'ÖžÄ*u5¢ð+ªxûQŸóï¼KtÒ™ô�½´.ë ™^¨È;S Ê–̸�ÌwòôÄ9ØrF‰üc-ù$Vc'ÉÄA7ߦ”�”ž5I“¤w×ÕÃy§`*~)>'-ƒ')^À%ÐøiBVß7ßbGw?¯a3xgBȈ,e�d:S‘+ù3{1%±åʼS[B{*Ñ¡wÕÌ=f§>Iež+RSS‰›ÅAкŠhFwQáu3yïA¦­'›×΄ÝëcHý_i’œngê¤`ÛÉÐ-5Aý\‰qS˜…¦bé�J¯G¨3…÷ øþy3C&7DeÒ�št}w>ä¼ Åòuoh‘ƒ<ñ\ƒŸb -¦ ¤V‡�UI  ¼tž 6DðÙæv7å;°¬Ú´$#è‰ßÈ»$Œ•—±ýÛCZ;v–�yÝè帅ö®%ŸoŠÁ6qcb¹ºÝŒ…¸þ³n»~XvIoÛò^zX¢zôšyô:ÕÒ¼Þ‰¯È¡uùh±ç¹¸’|›Hd�ÆŽ¢wJø-ª¢7çaÙª}Ñðý~Îä½éavô�–M)Ç^OªÝï<�ã­‡]=–ÄXü*7ÀW1÷Ô° ;ÄÞýx´ÄïÒ’°›DÁÅœäI›âøÜLrãÁknÈ€.qË?A‚ª<ÓK°Æ[‰”�’ç”×äÓ‚/lDF<Û¶}�Z8ûCZF>îOÙ s>¸o ¯-ÕðúäQÌ6“‚s‡ЪAÞúè~’ #æÁÑÔt—çY½Øü˜&ºoΖ´—¡oq;ëw"q»ó‹ÜØH’Üg‘Ý6¹8úy#áÓ€©Ýæ •öÞ•¤Ãª½‰Øwk.×KÀ¸=*ÿÐC!·)œŸ»ò`¹èwt~™„Ú_W“¬L!|ØÎ¡ÐR½è$ü𣶅&ä׳XÜ|ÀU­æC(½BVöl@q�hدgItÞë³QQHNI'д9M0_N„g´¤ƒ™gVˆñáËØéáÀof^ÿz̪vTî|>ª~U¥G¶ì…Ž_p+¤–�åhMú% ±Ø—¦ºÍÅ�º3 '8Ý]QÍw�éíò½#ñŒsÈ�zV½^p¿]X„i±$©yLý Šƒ ®Ü“ŒºAðß§µ |uJ„_'o�é ~rmAsÿÚNbþ½½x[èžSö8oŽî­xK•9³Ì k‡8ÊfŠmÃPÉ1Ì :h‰‹:Ѻ�qÊã¬g:ù±ºš|j§š)ëñÈ2i"ëÈUSŠèóÈÌ*ÁtÇE(degoØâLç~:%̉l�å©~肯¡”>µ��¢/6�ã÷6rV�ó;ã±ýñ´¼™Ok ÊáGÇ¿YØÂb*ÜÇÀ!tå Ž„69^þ”Ñó+Æîó/¡«çúÖ±»Ào ‹kø˜[Ò½Üãϵp·íþЍu]Ä�­ë�ih¸d%ÊÏ6…û¨kç%*ñw‚)ZcSҨב ü¼lüð÷C×÷ùôÊ3/<#³‹æyGQ‘¨uøìNixö™[~ /ìÔÄQ©LدuˆmMUÅ™+k!õ•?¬à3‚Ò¢L¸÷I³FgÀÙµé8˜-KˤoÁ¥¥¡ì¸P+޽T çÙ`rsíÚsâÝ�ãÛyÒ°óš>¶¾«©®:£5¾=?CnnʤA'’ˆjùMlÔ²§Ç][éǪ 8º&®¤™BÇë-ôõÂ…XíAi¥Ï X ibæð;Ô…|x«�{¿‹ƒQ¸7Ú®Ï'’ ®à×iÇqçÏÅÀÑ2)ËýäPíœEƒñCÍonÄþ5Tîç|ô5œN®½]µé?Ù€�\ºió¶õo2nŒ£�j–TtØ‹¾0šÊä;â ‹8›PÑ:Þ‰«ªê|„ò�/"Ç;Ęª/qM@,[>‹7R·€<8|–í�ÓC„ͯ¢Ðs.ls6"7~î`{›4±ùŽùaxŽjÇH¡¡™(\5ñ Ý£ÊtõšZ8àTH©ùÚæ—f⿟"Í/’èÝ£ôíýpì�gŒÓ¾|�Û0çüZrôÒi8±„ª´+âåÍ3ˆ[bù;~�~p×$v‡�ßZkœp@ú™0}Ñoü’¶í;Åîáë 7k…qÅúbè±x‚ S[‰×T:Ûè®ÝÈœ�•âU®g±¨ðÍv6Ï¥qñ7ȲÍ)ÙÛÑO‰<Âc®‘5‚Ó™�Sð¢Â4¦\€àWÞ1œã¯¢‘9¸Ûr˜Zn¬b–O{Àö»C ï4ÊRÆVMT¹™¬­i&Ý‹˜§{žªe^¥OäÿÒÕåAÀh&�jŸ¿ÓTEEÖéÜ”L\Htì±äÛ¼¼ú"ñê#ç:râG-6ÏÜ‚6 îi»A–ìHg7¼;øÏ¶ñëÇäÔ±PÒ•xÂtÃÑH!¼“°/È·Ñp *ðp Øî‹ÂI%̳Ø(°Aq¼wk’~ÎÙC|Σî¦'iWyÙ}½ÍÊS` ù¡¸òL£XÇÄQj]L%֜ծBâ™?m%2ñ“Öeò6§ ¨kâü¼TVYYõK� ;;Õ?l@›Ïâðbjì¶ÉÆÖ%L¨® ºoH†‰ÔÄñîVr|³ØïÿÒIÓBgnOÁâä4Ü‘¨†‡£dó;H¿i€ÛVÅÑÕM*LäÈfvê1°×0g�ÛF@OŠ”¦ Óc|³ÁJ{¡ª†§õ�ˆ¹Êâݪn°”{AÖýŽ·#F�U:N¶Um Ü7Q ¥ctò~:þP9GýÆ{ÈÙ†�ÝsœEÀn©g�°üSTkq'¢ðMo>љޗа±ür°çÄ"¢¥!OŸT¼²Ò»Å_�¹o\pñÉ5V?2·¿ÃŽ"y ÑE­Ø—¨·`>û ‡)M ê… ºö[â;‰HL"/ØãÞ,V¨ 1SÕ-èò}g‰˜ä)´±|Gï8FVæ¸ãÕß/°nº<{~Ì—šŸ'&knãpo5Š|ÈA÷XXgO/zÍ„ËO7�Æ/®°05Ž$ÛÅ£››^Å­m¯qwR, Ì*†oÿ:Ï“ÒÂgŒÛgü²Š�ÿÃíMöÄíås¡k$„ÌL%ýªºWÖYÚ!Ÿ`zî?†et’xc‡`ßwŠÑ’–¶!ÇJf�©?–à»yÁ°TæU]wÆó�ñˆéYîV-J7L Óì\©îÆŠvèu±9áË­–$¦Csž8Éé�Éš\ú;çÓ}H€È³!çä¸øÃœ}žr™ óyEÎ>§‹£­ŽÍ€(*}µÍ­w�ÃP­”®%NWÉì‚<;· ªñ!ˆ¶]]NÎŽ¼gäOÅÂ÷Ò[¶ãêŸÑÿlñP£0ÞåkKøÏ¡zJzåî8Rk)ý2­¢f¢ûFW|7²•ÞVg:¾^¡G<¸¸0à-Yps!~/kA¿ð¤]К’Gß~?A7ÞF‡üQ"Žw˜%Ÿ@#ÿb²ç×Zxü*Œxî›MÎr‡3–�ÌÀ¡ âðG £cÐýI+HâShaoÆ€>!Ì}2Å¿¥Èíqi¨v\©¾—`Îó Dž\ÁˆgEØRþ�+ÒÝD’Š h¬r%L–ü„â•3èš¿;%“.é=É?ÓÙ·™1 T«Æ8%¾$×;ÿíw8üHµ?ž&³$-aÂ6´'a�1�ëzuÕ'ZŸð­æFƒMg¦¿˜‰]iÕ¨¿e>šxù“KU$VQ”œô� ÏC…Ø›-Ñ9�™»�Ší²²Õ^ �2'ˆü^8¶¹­™råu95ò^ øë)Z.>RiqÏõ`Q–`OÛχþ²:½¡�Ù”©ÀáL%ØéTC½2­Hô§T�Úæ5³.‘:Ph;ªeA•÷< Ïà÷ ‡Œbw<ù®ó”~[¦ »/6[}Íû·›,n¥Æ̃)Ì—²¢¿kfC_ÎË'“ÃXÜYá*¥àm#NN=*‚µ–>DZWçèlw£R*à–†Õ;ï�sÓwÅý ©�T‡#|_SŒ'–>†ÿ¶ ¢ZJ8ÆÝ‘þ% ÈI§?ö¼b¿¿ wã[ÉÌ‚½\Åülš‚?N{€£»È®{ v²£TÞ?žoKÂà%hg墚¦�u=ÌyïTjygŒXå­ä~Éxn> »­! ÒA„”Äé·_™h™8‹×ì!ƒ‡? âó€`}ǃÙU´‹x¡üù•�{ÿ*Ý?´ŸnÓk  *³áù”vês•ݻߓÎ^ýžy4óŸw„±ýÕc²u… ¾ú›QÿEC7Y+Ì %[„ʶҸ±ý4S‰øîÓ^(ÕÚIâõçá-·8hU> úQ£Ä²éA·C4K¯ŸìUð·©60…&ËFíûIº\ OðëB©÷sêrì \혆C‹öÁ®â//�ˆ.Ù �Ü$÷rêÈ<…2´åìœ~�4Î…,m[Xö>Ÿˆ˜$_/D]IY–‹êÖó±oý.üi»‹Þ×µÁK¼JìÍ\Á,—š¤'w¡û[jûª—Žß±€ s;’àq•Q‹\‹S]æ€sœ0~ßbµ,Ç�èê=£n@I¤+óÌxyŸ±û"RÀuÎLXí7Bz Á%‘¿äð B‡ˆ¬E—•A@NÝÇ/ña ÇYæ[�輊Ô܃(üçˆ£Íæà›ËƒŒC½p])¿VЉ`g�Ÿ±îóŸ„]"0Ë0�¶”Úƒ«>‡NyŸ }Ff(®DJá5Uì!©ó_3ߊâð;»ç¨W�ãîà"Øê�Ëó�ƒMîZãòê.k :JŠ$ß¾ƒÔhW€BÖ\f[L‡3LQÁy”fäï#Ì-7Œ:…üƒ†˜¹Š :?I…\{”BïV„áJ…³°=æë:­‹L󟄃i(bÍ=×î1 {Õ·Èr¶§&Á \º ‚.ÚdsüÎ2?¦�‘‡ºéD2ÎåcéÅŽO$·ž®Øt-$¸dÔ:€|ïcWK�¿Ãïéú_ÆHP=1xw¨�Hèãs}iß»Bî‘ùÁø‡3@“Í��×Ô(Z5޳ RY 1$BIdìÐyJMr¨GµN¯�‹o¬¥8s7•Óõ �0Çh Ì* &Ý—©ë�EŒUç¾6žÇVýˬZ»!®úñ™¸<ÌÄ9jnø`Ï1�éìI‰¸8 NðW�Ú?!8(q�þõ Ã�!keJ•óÌ÷è1‹Y!V ¸þ*Ý�RNŽft°%ÂÒxc÷ hŸ#‚O¿­À_“ÝäåF?ʸù[)VØFuû�QçÝ9pmGsîyªoÿƒ¾Í^Š+ÕBÁ|Þ¹«{ÆJü T=ƒÜ�§ÈæŸ{ÐÏè7ª_ç#ÇS q®“<ø¸ 9eµ´f×Q,M#Çl¨æ‚Í;‡VÜæÿw;Àîï5²^é y;¼ŦãÍ£‡H‚äL8ºÊ•ÄšîÂ<}[�ÿAÖˆÞÂMÔ“†zZ’)né€9åt�ÖJú[(ŒI'�<’N'ëT ˆ]Ät�

¥ÓåqLJ&z·. Ï-ü á·P›`ýT¬CšæÇâ‰^,YÊÓ®¢Ëº’ñ7)ôšë,¼2øŒ<–ð!eˈ̉JÜfÞϾ޾Œ™äÃYÏÙ èMì¹%~°Ã;ýŸªqýÕ5È0ÊÊR½��»Å&†S¹ÿ”9±¾vè(°Óß*ñf1¡»L-¡eì1î¯R¤Ã!’8¹—/YN’âðg8ØŸÀÌ9¾ Ž� ǹ±é`Ô¼‡|èo©ÿ† ½=‰ÖõþáZée oM)®ŸZƒW¼Oá ‘&tÚùΑ=òþlòY˜?�^  ›ØBp2Âýƒ¹Úzß>ÝLV%{MX &Å„]þ 'gº�‘O©2‡’W®n ìTˆ[V*‚Íݪ1EJ›3±ôCæ§—ãì+o‰ÛެÁhþ1^Á;ô:� XUy«Ê‰ÇX&ÛÊâŠV œü¼S0%”žù—áѾ�ôió'Òew 6¯ÊÇŒ›3¡9ËžÜüJËSž�Ž÷”–rø8k”Ÿ�üÔhØÖI™¬ôœ[Ïc™��äZ³¾öˆÚX_&âE ÀÛÿ‹87>Á�¶P<=¼•>;}ÚʲI‘5*™ ”T1ã�<ÿ`È““ £Þ¢¶¨õ«‰µæý›“9–X·ýrFBØtò„­³¿B ’“Ia|'ö‡_ÆÇLˆaQ±�ÇlyyÚöz-¶uf‚yQ1™ÄÏk²µ#K¥mƒ¶ÌùSDµEx«Å_áöUo¬Xq‘E÷BþжK/È­T-bÑîùM.Üé*sq $WÝáÌ»Ù΂üæž6åÈÙUZM]q ›®‹².÷!¯û&­kÿ âûËÈçó%ìÅÏÇŸð¨ûe¥|®œ|Xd‰Â9íhéq‡¾á‹£'ß{Óý!Yd—üT*5^Bù ¢é‡ù_Ÿ¿,I~%Ò“øi$Œˆf+R�{—ˆŸf±ª¡ ž�øÀä=úë¹e¯ˆÄÕ $: QºÂC›qÈü9tLT@Ǽý°<&øÇ²‹:©Ë5(؉˨scI7ÆûÛaήWLvý‰R¨§=·Ö¡Ò0Á_k¶ÓR/s°“2 ñf;àäÙ0tù–Säñï ÊwÊðüiÍ›Knÿ'…Ò�¸ã‡.hm¬ ¿Lx+ªïÓ»+q�I>YzüÞ c—¨9ö™ì게«™þTÝNxšÞ?…Dæ2þÕ¸D tL°•É$?<Î@aótÂËFo½}õ5Df‘$ˆ bÍD,N �vS i‡ÐÆÉóÿÇÏ™áBXlf µåQX4fÉÛ*Æ;�ÉŒGÖáàU”¹ÿ˜ö,ZÌ4TŠà1ëX­ãM“”­øúÃ`©ÎLžóÀl’¿„³ìqãÃbL_ÎÖæÌþNµ÷o�Y‚â<ó‘rÚ\•áÔÝŸ°ºml‘E½%¶îxÁ µ1év›aš~ ?‡ ›¬q_ÃÜ]C@Z¥êçÁ•tÎ�üy¬Å¢]Ñ«¶‹×³¡î�OèÜõË1u©¾ù,Æ»´w&/¦¡§)ïÀ…ò+A¦ö+vž™}§äP^> žgS)äíq�‹gL…á§�Îÿ(Îyš.��îïf>ÞtÇúBAÉùdúŽzq™Ì­Ä™\§`Ž·NNPÏyù\ë¹_1/ÇŸ´tMуôZ{‚í<ÞЙý¸go 1—“á5‡ˆcîèNòÁŸ~ö¦0_ó1ÍH”‘øÏ b¬²è‡Ð2Òÿ‡Ý£½ UQûÇýæ·”Áß¡`ùÆæ¦G@¥ß2Ü$ZüÇÝywî(Ó6}œ­önT‹‚ÛŠ*óÔ¢žžçG ¹1ÎE¸yý"jÎ�©ÁõDÿó>40HÀÁ£ Íx¹wÅ9³�󹆜 æ~$ÆìŠ"/³ùa@Õ Mi[õIlFwvöMœ[°*uRŸÕ–:3~ù_À·-:DxÉ&!y89;ñ‘‘'4=ª„J‹˜–2L”½”ØÒ¾p¢é’†˜$ �¯OAŸœ¨½ÄŸ×�Ä–°™2xÏk Ù^{†.ú«E7•]¦C5õ4'û5ÔUDáL¯gŒ¯´35:íBôm§¯\ÉÁNj5Xžï²É)þu\GZã>iàì>‹>YbÄùÛÃ…ìäq"ã©Â®3CÁ¸xü jµèóYùOq™ž£`$I=­ñì.y™Jñ–W éëÞ ÎG¾ï´u0&“ͼÙîÈøŠv`ͨ&”6& ÚûæÉçb²z‹f剣wD¨ÕÀk>*œÆejCÓÈܸhx\¨Ä¹0=¥½¼Áa‹U»s€2|}VËCõ°Ør!#gïÝ �eötà?=ÚÞ{rºÑ«Ñ{ÓTÉÁý&¨•¬…©=%��‡§�Kfpš¬2€eÏè¤ÙMà»p•Xr%¡ Ð¬•Œá¹Ä\²Cá(,}¯@o«oç¹ù\€?cüœÒq[täçd©Í�ÎùÌÄ)a‚ö,U¾qŽØ1tÍ1 °Ò¼ÂdŒ•3N2Wp}–Ýÿ!…ž?Û YžàäêƒÇ;½¹¶Êaøp�xÊËâðC'²u[2�º�OŒ¤�÷q ZŽfÐY‡@aÅè’<‹¡ÿz…Œl Yµ$�H¢eóŒ˜ú=îÈ¿V�»TK�Gv¾,i3«dœ[¼�_¶`árF[ð"©•5NÜÍØDžÑÆÊ¥¢ø_Ï2®‡ž5 ±©N%ÞÙ£ËiJÊGïþ‹ÐÕbs…g“§¼qö^!´¿qG÷ˆðêçd€UäÉŽVǹ�Åð^E�˜•ÁyÓa\£ªG¥q¹Ù¬Q|¿/Ó…Êh¿+?º%¿ žß ¡âw>½ØÜ#jè¯#j«l°±ç˜Àdä>X×C×z~¢»>ÇCV­FÝ %^Áª ÒvGon� ëc’™Ð·j ÷;=~äàhD¾^+ 3¥¥`Ž~%i³ç™ÑÇTêö�G�àûëO‰PM4­}°ó –OÁ?rëáo�0/RÇåU¸8ö-ùtôŸ   º?�£ñhÉ0Ö=ƒh4kÜB†*{ªvµX- O§k�¤àªî°+Ž% 2¿Ãå~Q”®¦ £©³p óû´øŽ•ÃÄp$¶*âõÃ3àåêsVQšÌ~7ÁnH–€ËÀ¤Ék’¼Î–oó¥†b1`-ÙmÙ£+ªŸÐ�¡¢ø³® 4eÏ#ßÔFj_¡ˆ‡Vâ)a^ÕÇ}¦ØÚäË5ÿìÅ0‡�` ¯Š�Â1ÍDòŒÓme­ZÍúú¼2í³`Ø�A¾*ï£ör±í˺¸J‚–ú`M .#Ÿ”<‰šh|¯ÖKÊൻõdi¿”*t�¯k$[ ‰jT>@Õ u0¨c€ª—íé¦J®”‰4(eârÉpxw}ˆñúô�GÐ/sT8û[FÈÎKñ­·Ð…Í$·)£ËPwù“‡dž}!| ÊÃ;Ã÷iCè4Øÿâu?ÐHj´Jèv¸�²O¥ òÖ,Ì>ÜfÕõñ r®ð¡ÌšÛ$®9£tj°[‰ †=ý1ø«D¬Ô”Ñ»ç[ý2,Î� îB¼žKZ$hו;r‡­8ïî…á`Ô”�¸Dö;…c¿8˜”¹âα,?ã$–·‚±SØ¿7m¥åÊ2PÑ¿îÒ¶f1N9>ƒäeY4¼ÞyþˆšàGÍ= –K!O¢½8Ka©a)ù²¡•õp\ ÒÏšHÃK.×ìV 56w€ï‚MTï@»¦n/ì0J@S‹fZz|6Š˜à#oy^ëû@ü5}ݺ~-^_¡¡– ÅÛ-Œ£H6ød€õ6GzJDŽþ8pVÍå´‰„âÏImÎR™»ào^é÷á%$ó�'u8N–lcÚ:mÁ»Þ¿ßkbzTâl~YxÖÒÊØdÁm·±´u>™2²õ }ŸîžÆÙï7#}Ò�óS—<ß‘ ÚªpsÙ²k¼‚ߺ²Ï¹@ăh|T¹æzÀÁY÷‰ •%\ÖŽö};RˆÂœÕ°W÷*jˆYa}n·Õôm pòÞRôú\DÐÓ{?oÂMëCÝäN¬üdÍ‘YàYmB¶ÑIþB´º]‹5'5`ÞÇ�´$Zôs[ D½Âê °GLçÚ�“ezÄÏ9 ¯æh¯°Á ŽàÖþt(ÿŠÑü�Qnj:LžøA/T/ÄŽª �ôQæ8,RbŽ7ÑÂ�ñX[ƒ&ª;É«% ô‡Ðl‚. 0|\`ÚŸ×tÐ/»ÿäÒ¿p4¢ç ¿ Çu�™–) ÷ŸÍ¾ªxæäY¸š3D Mº¡¼Ð­…~‘ ÷Ò¡qèoE =%ž’èO¼éËG†JRó#-d|™ çíH&ýýJ×ÝõDy…7hçœ'Ï¢Ìò)Øï{oÍÅnÝD™qfó=6† úôaÜÔ ß<¢ jr’ßÓ"uîQèw¡Òã3вh1j<I¾$¿"†ß#±øò(T”àqÞä€àú ²R†„_^ˆOG×â`³<åû¹‚Þ|Â1©�YëÎÁÕÿ¨�l>oЀæi5´¡4{áKéy’¹)�Þž…˜è�®×| sbšO J¾äá~ï[D«RðªÁSãŒYeªÏæè¸Ò«£EÈ"ËË}©Cz¸ û©/̤’&©ÚsK’œÒF^~9 3lg1ÎBò0-i5>Né¤'ßÃÞga>�~»ú�h¦Ecyè ~ÿVúï?†@YL>)+¨çsácƒÚPB×%NCƒq)4¹fÁÛuä;\a%¹§Áön QZ™�‡zMX}s)¼»SFùøÉ�ù`ñR–ò sx „:÷7Ðï T(2k¼×¡“»®‘†õ‚ê°òËt”tA&� ¡ûà]¦Gý,å¬ÇÎl]\ò>›UúFÄü`³#‡ÿ™4Ä�-I�‹üÖìÁÿì…1Á¶æ�Ø�œ¡/J‰ý ¸À‘¹ÓÛ¢u%dWRXIÖ‚öeL;E¼µ]q( ŠâŒðVÑ0Ýœ‘ƒù¿/‚àÞ02m’Ÿ#¥.ˆŸý=pÙî!8;/ HBR¼1Þ´�BIýD’§£ Œi:£"ÿ 7~³²ÓX "¿¢Ã·LF*ï¼ñÖ†�ïLxò÷?0 ÓbˆÔ©«ð.ÄÊã±#J;¿‚&Ÿ˜é–÷°@5}­´a­g2 Þ.'køP}£$Í<@‹�’UÖýtý5'hÛ¦ÇËt»õ E¸Y²‚œ“¸’/^`¥è'°é8ÿ¹c䵇Äðk(ä:Çá“ xÖNJd›­Ò5bà€»\Ü¢…®­P'�Z¿�vj ‘=î}¸)N”̨YÇœ/—Ü1Øm"> w-£ö�¥ÿ]öCÙ×ëP7l”©ºÊIÉmÌ%eO,âŽR±'óÁü”!ÙÒH¦Ý]EÖdµ`ÙÁ¯äÕÎDÊy‘Õs�óg™Õ< øäd±úæ �^`}&;ñ¾~'ý«´÷þ|Kþ:ïEÅë[¨õ ;\�r+Ï“è0}ÿ˜IZBÔ.~Ð\¹¦‹áz+Á5nbôØãSàX±2²ÅñDB5©â�†ù�Åéw{a0ýhôÏX¢<û4?p|œNL™4ª+. ¯Ä§`oG)7Ð�ÿ¼EXÎ?4»ãPræ2œmKÇ+HòƒßtyÖ#:m8Õï¯ËWÚ<1r/�ã.Xó„‘”·‡�£Ë0Ñ�TRé;‡g§…’í¸œ+�+‡´` %lÍ®ãïùwˆìyAÞ½³NPiŒ|/9ó“<Ñpø%•Y‚�aË©Ñ5)¬\+À9¸’Ÿ§=XȺü»ÿ„ÊET¿;y²hròçJÓ–gOɧc5Ýuøý°ö„QÿRìš±Ÿ„PþË>¸Ùwƒ¾n߀›ûÏ ÜŸ•$`c(ÓÑÔN¢*RÁ¯•ƒÚÑ}U.^6ÂÎ£ŽØùö³åò{.TêÈb®Ħi {'(:ô‰*üÂ*¹»¡¯ ÷YÀó¦<ò¡Å VͶcϵõ�ªÝ¢øh>�ÜHýJ$–¦âß¡L쎜†ÞéudìÜ ÌeþÍ„›!40_  +5—üw"âßz‚Aí[v×<+N^ô¬–ÕÁÃM\Z1-k‘ä÷Ë8Ö�JïWý…µå¯©ðªq”ô�4ÿgñòаÚý&”¸dÀ›Ïk‘]<•·�˜ðôß¾$G_ ±Û'F铉ŒØ¹7]ê¤E‘)ÔpÉ$m�S_Z1�ï+QYYŪ.h"ŸûÀ´{¡d|àô鳡t±cÔçb Ínr{¼�®`ThOëWš¨�DÌ^=íµX2ó ¯°¿Ütðæ‹¦^YzôÑ }(ØŸï1sa�Y7ñ3‡,)˜…­f4\ZV™†à—1T<ºÑRUû ðÿXƒÜ»¢ðÃþy·ù=9ý ~4`é…Ið²]�°Ÿ_ÐÇoÏïf%¢FþPÉ,}2ƒcúÕRµy4µ@õÍ  xÖ z2ˆ‡Û â k¿ {~À?~°Ã¨ rïÀ,ÔÝqŠ,nŠ mKNêÂø÷·©½'…¡‰è‘¯Ò°K¸šl<_B�§´=ÒM7šH²/»Â кˆ uÿ!óÇIsM2s¶”Œßk§Ï·nFý“R¨»ÆÜ&Ç�\¼äJÞA×l *´à·Ç® 8ì<ÜŠ¯&™¶ühªÜ†Mí³yúþu”öFb†5}VoWm¥É‘‚< Qª¼ú‹,ƒd':^)Ð4~ ~¥ù³«Eû©u› Ì¿Y…ë(ÛS•\Æá£ š>;×›”À~é„Õ�>β··°wäfG÷ÓiAÏá†Göb)}}ó>nXp giðl™ÕZF~~‡Ç õÐpŸ&²ye8ûàFlÞ\xœzƒ›ëHVb3øÍÀò×wQ(~½!×­ ¢RRépM%¶ÖnÁòuðLëxÅçá¶óQ´#S_ïý…ÖZRdñÎ7´î¤ },ŸMû>AýMÉz«�tÃ:Ciæ’{|¥TñÜ|øõÅ�<ÜÔFÕÉ#˜rë:[ïÃæ€ÆQºÐþIô•.V½Zy ]†G Óñ…Á[¬öŠ‚@}'p¹QH:.ãœx:“‹Ê¦Y iÁr¯>l‡×4h-åTÎ7Ň ©åKI&Á3Ó.Íâ¼UGìë#ï=ŒY¹;BÜS®Ùh°3 tÉQÜ¿Z3¢"¹NIV”�Ëd>ße&§{^Š\GÒuó±ìÇsØ‹7Ë -Œ¯�³¢4a¤æÈûÐW_óé»[�ÈS}€'s x3˜T8-űø5æ· Ñ»·‚›ÙiX ³‰~ÝÀõ}e†’ëÊñy¯9ô*T�¤úR”‰ˆíôÄŠe[hß—�”{F˜iß8� ûbÉ•ëê Û)‰Éé§à¢îsš*£‚B°ü;?\^DV2ÛÈêíÕx4ï4Û;í_¶¶[Ÿx;Hê•ű-�Iãh8"mJøÏ‚ˆƒ:Ôœ a}^p@oò"Fg¯€®–t9¼_­È'ÉÁŸ.Kð¹bD]íÔaéYÌi”ç½0�Žªõø{.ý°ß�7Ç9c4&Íþ;ðžÆ^øB}.šQð‰íÉ…x0õ(í:u“Èná²lÜRò±€Cü,wà!áIˆ�L€¯æMаΟê!=ni8CNÅ÷ÒOþüÈö‘‹¾Ž=›S±ŒYA–Vå\x0‡  ã©4]ŽLø×%£±@v¦ìøK ­¯ §Š…ëñ+ÐîD#9ËɇϿ'qÈ>í>·°rIË '¸|^—ö÷ÏáýnûFÝß&—ϨÂÞi´%åɈ‡/—¶‚gäßîÞŒ¼5ŸÉHC õ1=N<ÏdÃŽ�«À4Bk™ 'H¯Å!æ�Âxàžþ ç@ãe3:v|#†òíçÖbœô‡ðŠÝÑJ_™Ü¶QÃißßõÞB� r„>Š�–é*(hræ|ÿ¨J Ó�ˆ#E0O‰}`÷!mŒ¶ÿeôûà¨+_C«s&Àe ˆª$ÿâ¾›|…Yûööì×ÈáÜÜ0_cçP™†0�êëB=µ[ô?ënñíS¸©$Œ.W&& ñ`¦‡µ õ½Tæò¬b^Ÿ\&¼¸Eô¦èc @¨ê~„»*�pþkQÐ~3FOFØá‡.2?H÷+OZt�»SžŸWwP‡¯Û~‡Â×”6="–xr<Éd`/ÍÙº_¿„­Ï+q¶h(®°Ã�œÉÒ£sIå×S¸êÂã¡‹n¥�« Ñùë~Ü*_�j‚…øÛ¤üìæ¢v¢Úzú€žéY²a£5m\ÇÅ«Jmì,6Z6"±ýŸbóËùkx%MMí’RZ’ŠB}ÏýPJDˆ”Ì„2’´‡&í½¤hÐVé9÷Ó0*Š„D4”EÊöãíýïüu®ëÜ×=>Ÿs�Ú¾±GÔ9 WTÄX‹ö½&š‡x]}Éä�õô‰ö,>“GzÖ¦uüÇÓ‹ C1Ýy‹`Û‡VØYŠS Öâ^¯ì˜- ’o¾Ó.¾É†�ŸÜ©ŸP,žºúm>ä›®oÆËþ gWž2ÔýA.©«¸á1?ê¾d�óÃôàxj²µŠ=Û¾ßôتJ”?ØNr2µÑ'ÒŸ9. 8:Þ„®lø¼fÇB’¢Ý€%G+‰XHñ{•Á>1·^*ß]'¬O × áà˜ jÚ [lôÙ™²À÷²“´l±Ä·Z©Ì•ù<4?³ÒX5ì B‰ç¦pl+†{xñÓ1U´âb¶6ô€ÏM;Ìz]5ò›è˜Ñò¢"ê=Ÿ£Ð2�–ò ÿ)CWç_z¤aˆœc_4)[k4Â�óÃv F�JÓ¼/cS/Ë9âÄ:b…�+Žq_ƒ6•<Ð:`óäÀÝi¬Ý€©Ï2ˆò¤G´IÌã—ø>�…Çà‚E)ÄYé<Ž*þÉI4z$ y«¬¨q�×'3ˆágA¬ä`/Þ}“œ™j6U·id‹>ž‡›>©À„S-D;íc½-£-–»à÷7B¥f©rÄíÒ˜ú¹ø†ß�’*XÅ/D‚³8礸Y:žx¿c3Ü:ßJ;$éîÕd�ð4$õvA„ý¨ñÆ�‹ñ‹j)ÕLB¿Ó^hœ`oüè‚oȱŽi“XåNøYCûiÜ~U }öît¯›ìêj|·óŸ/îxj»Ë�Ž K‚[sn�’eµ—°Š^÷ã(�êÚ¨`Ôt_*¡§¡¯­Q¢ ½5`IÙ¤tD–ÕÂ%ÁIëè¡ÊxYN¹lœŠzBô•„ ê•úòTj-±ðKrãó¶ÔÏzðt?ÝY‡é&.M´,­ %¥€ ‡'oÞâ¢ÞD$ Fd‰N"Ì– 5OÔQ¤‘‹ã[•…ûV¦á¬·cl{5wø¡)B¼k Í] †f²È7ÌÅR ÎÄ ÷!pØrWLå�€vVtÐyœçÒq!ô_ÏuÈïœé¤%e!7ꦪ2ù8t¢î²äÔz¨©B"ûíÅ'¤Äº™~îÈ A§×PÞ渫3„pë¾d–˜bɵr·±RÔf7"�Äî¡´ÏœK·½ÄÍæµäñŠ1òú_ü`œHa­9ù-±L4§IþäqpqzNׄ²7È­†�†-X·î?â0#ÏM o«&6‡Ílúº¤ñŸS"Ú­âÇÜÚäšÛÌÚtŒµ>¾¼�ÆÛ9̺¼Hз¯§Í’/Él¡r|ô[�$Ìä‚toŽÄºî\ذ°�,°­Å“½�÷ÄöÑ€â ö)-{êÒ�%eë¨êu>²WÔÂ÷ó@ЊÇ(÷D’ŠgèåV#~Ç'às¯*çÝ®¿ÔzA¹ü‚êJ�Àr Irjg:‹$@ÕâäF¹ 7ȺͽxéMXÏr \¯ùÑÙÕMj‘ï1§bg«)kq+9ñýQm»ˆ)͹èË}×µÀêÔ¹`ÂJÂ~>qÌsøK›ò”XZçfC_©<œù³™ñ~Gzñ 9kš†Ëï» F´„os¥{?Ü#–Ëo [4uŸ:�‹l] »éÄ€l±,¥Ö‹pGC0U¹'Å™½z7$žl%?» HÞ«ˆFùÕwˆïÆ» ZóGrfs:�üb¤l?� õ`#ê‰hÇ=´ú ΜóÿBQ¦XÕëÓèÖœ#K¤ë±ií#r¾õ {Ñíäù¬,¸™ìåËŸRË, òñ‚>ù䃨²/0ÒTÖ6Çþ¢rÐe”³ùgZ›r›´ÏWÅ®ßèÏ^mÖ‹ÖûX¶N”•{4ŸÚgŒšV%uÂá:GÓå©‚ ý» �0ïlëiþ·$Êýõa>;,MWŸ©Åe\ç¨M‰~¯‘@ö†ÓTYŒC+õõ1øÚzlÔ†ÙÉZX“–N"Çð˜Íqvæ«:æî«ïPi®Å1ÒÛÆ¬ðVeü¿Ø�D9?jþW†Ç>TÃ;׈¼\Yò…®},Ã)No‡–§[ñiÕ-º·! z_Òvèà “d¬y)ÚˆÁ¶$¶ç<19‘e¦��<›Isk!¹ý@†uÝ/ë÷awO”nØ+¢cñÆ–§ôÍ)kFöþa˜—Y g¸‘¨§”ëZ)û¦¤0þüK½ÅÏ€oðR"ܲ<3®Ð}ÛáÒõ¥¸²ÐÝE~`×ëWì ypÚx=]ÿn?œ2 exé±Çm¼�Œ?ŠšáØ! Z“�!l 2m(ó–$Á¡½¶8cõù!�ç¤êAî kúºÞ?Ç~‚zïF+xƒfƒ,¶ÄiC„\7Üýœ†®™ì‘e{�Ç;³2T ?sœí„CE³9óê»A­°†æª0˜;¯ŽÜyÑq�Éç?À'4ŸÓ«\núöñ3ZsöËãÀÀº›7‡|hÿŽQõÖ0/�MV¾ÐïÜUt7—7º^ía"—0õr;0yIݼd åDÓUB$'ê‰ÿZ„×tÅpzÞ:|¿œb7ºH»¡´Èn8©ûš6� §<ó¬WŸDcû!8¶åßz‘þ ºG‡Tä ͨÞ½�ÔãœbG®šÙ%1�irŠä�\"‹ù„iŒ–ê×üÄêkuô�-/•Û'ŒŸ'ÂaNÊ;úwZšu•Äß[Å,uŸ‰×Ž×ôLJ-°ýJÍK�öÿBp­„ðÍGïæÓw(�GMÉ“Öâ‰I+nPx»›¹àƒM2^X3òžþû/ÍÚ€!ž¸•kŠ ˆ±*|¯‚ó’jP«–I‹¨PcN‘ÓŠÖ;EˆÕßnæÊŠ zÃq…lÊ;‰àäêyœ^7¬¾ˆw ô‡bˆôÖØlÛv¾:Aø‰¥ ¾<îšW3 Eõ ÅíìÜs]¦¨KW$yŸ“ßX³IúĨí·�Ä^0�ΙÆ.dôÖÔž?ÿýFz',þªÃ›C¨Á»Y_…è#aXt:‡4³�€» UË+ÉD~ :¬«—ÀL�ÚW�:7,ñJÄ*´2kb§ßŠÇ»4†J-�ùl—QCp N!ѪTc]0 Í(Äzû(�á] �›âQýºûo[¸<»‚{ëby÷ ì.(À*5î4´ÇŽ`+ä›Ó€�QQÐíú™†¿?Ble85]F÷λÝS³00|1Ëj(”¦¿iÅÊ¿5DÖјüø[U”� Áðé}pÀübã†Ýéd½£5 ªEÅ—±p÷žmK®€!Ýô€Ñ[|*ªÆæÖ« �×ÄI±Ï{RWMA¹…äÖ)`·Ÿ¾W ÄÄEŠàö§'¯¾FϽD(£�>tÐÀöGÝ´lÍLï³µ‚[‘y8;# +íZè£kŸ±& î¦fp*µù¯„hüÞO§FƒpãÈ7bXÏÃYlä� ÏÙ@xÕi”K™ÍîjPïç@­è ®šûú2]38Ý]ªéç†8¢P—C˜9˜óÛŠmxX¸7y­˜ô¸´ãó9˜ã鎧k±Ó‚ÔÙïÏvÑ YNÈ{hìˆ*˜‹|"'«ÈðKÔy|m.�„Ø/KÐ0ß�I–чnÛrp©kg¿41�y�÷ã¡kŠÄS¾_½›Gîž?�Vd‘Q)!o5K Ñà"ݰ]•ÔÅ»@¡·3 ›[c�¸7#ñ&�ªVÄáŸÁ«¤sà04æk‘¼`I²?ÆÆW„#©ED�Á¨ñ1ªbö€ ø³L’£¡$£ó\óØu�ëiôýTdÖþ„_á¸Ï4aÛ`Ü=À9]ïh[|?m9©Nz£ ðùÈlÜx·�úH Ïö"[lIî‹éâ›^}:;Š‹#ÏÎEî Xt¯’Ö½,†S_¯‚ÑÑgtoŠ3u<® ·¼¤ÎŠ5P¾aІ}X œì%ôúÊ$"è© ‘"ŸpW½.e)㩼�ОK4WܞЀ©¼·èñ…ލÿ$«­$ô%Žî«A÷u6ù§âê#ÇÈÂØÕàÀÍJJ'±Š˜ò‡»Qyé�yÄõ ¢óJC_å0¶>§È!ž\¼ÑÊ´^�ÂÊ'Tõñ%Ì.›fîúŒû›¸Y�:²ñ¦UÚüûI&,Œa_T1v¬ÅÄ� *lŸ@þ³vÁC“X1h‰ú×ÁKü1(��¯ôÌÁà”9$»{Š_¦šŠx]Ó¬~•b§{<Þï‚ï«üÙyñ1䦮*>œ™ù¿„>ÒÞK"ÓéËh.(ЀŽ(.ÆäBut”¡Ë¯|ǘ�5È‘þB¼?UÂuAnð<¼&½Ž³÷Š£a{,ùdLá–ÇK�ªlÜ/kFžíTdÊgÂO'q0H÷!½íŒ)—HeÏrAÉÜ +ß�>{.ÁpŠÇOã"Uö¦d¬â/½ZÃÃ’Ð×¥gvíC—’§´ÿ*â/ÿ ï*¨0‘©ó˜ùukI³ööÄãO«ÙÍrË€>¯¤ÚÖ+˜¶€4¾óÔÔöØJ =g³þǤëf‚ÃT7>�= ·•.Ñ;‚ºdÙ UôwxŒ«¾þ Ñs÷£fn –¬¶ÆQá '9€g¾Þ¤÷k”ÇC‰Ùà^M… úè‡ÿ¿ÇÊ©¥Ÿ,1‡÷4¦Yì–Jó e•ÑæIŠ¹Ý›±«U–G¿`ÊîBçKšðû‘ÊIÙÀ†#Üãð™T½ÖB‘½ÞyÚtÏ>C˜]>D7Eÿ2ÕÚ–�.#02{%Z.hê]§0z¦†ë«AoW&D¯»NÝxCˆ¶›8JÜ&ÛO:À§.U’{Y ®ç€I&k=*"btÀEˆ^žË|¨¦Ï¥X扷©RO =d_vià¥�}�žóű6׃ċP`ÜUñåy'Ö>ÃHTSÊÅFÜàÆÍ©„ý"F\@½Ìš”ð…R­ÏïˆxH-~X:�þlïcœ‡aúi’âú„vÞæ0r†jôœõZløQ…�/hâcû…è¤øˆRQT÷?hr‹ó¯wÚ‚�i1Û�޲!M$Á<ÄçXÐWó2Én+ôîZ‰rËÓÀp,X°.dK¢¹`ÃÞC‘o[†b )ÓJ§¡WÑünê|we\×zõ»4±Üù=ì9Br͘=Û‘ tŸ€šó7@îÕ"”àßA{BÎ׺ *úkîeÌÛ½ÁŸa\y¤ûE±×MÏÅ€—R$×+lþþ èÕCr‹tpÐ{9¶š§b[ê]¸¤¿6mëD韋Ñç°7T5™™JýöMÓ�líQÈûÇ÷Œ]Æs޲ÄÓkëú­>öq»²¼Ê…Üùö7É·³Ã&?ø”àNJ$]rr Ü©ª�g({i9»¯S‡J’!%ùnß#ʸ'YBµüñËŠeoË£T¼�›•áü¿=ŠK½†‰më<úeÍ jq·†Ä¥}b^ç«@ÁùpæÂqÚY-Åtÿÿ_.· Ê�Í"§}®3÷ÖKÁƒý=ø ̓¾â†uU ˆFD½�gN}¿/�ÞsÇðèÎ5P½ –nP3#»{�êÙÕ¨¾Ø�p±< aÌä"|-¬„z�«ðwbQ¯? .ÂÜŠ·\÷3›3ÝaCÌ9rð|6lëAÛ7ɰ%ê5ni’ÁÍ@Ü;”aù tZ^3îËAŸŠ‡£>ãêÚŠÄÕÍ4yó‚›Õ!6÷+˜øíÈ0â=äïÔVò­b6õÚ&Eœ}À^Ñ“DFX”¸åO¡�EäÊGÑb°|çnÀ~3X¶Êéâ®u;ÀÁø'©D~¦**«#`xIî8) =CQ ÿx»ëŘH67ÈÆ¦™p[¸+�i�“dj2#6¢@ãÏäâ¦júsû2œkÔKel‰�Tü¬ôÝgpù_.Ù2�?êe=´–ƒn䚸HŒ$7ãÍ_UX¸AþÜüÈt¤†à™“©–·5Zw,eøÝªÙ'Gá°ÐQPXßjêöyvZ.C·Ü*u´ 4‚þÑêÅñ8¿šÙåœ/«u@t©åK~L‰ÍWUm_¼Òœ†ë…£è3±P úF燹bÖàŒwyL³ãD<è/÷ �äö¤e{n“—3Îz¸k ” FùÕñ ÷Z\±‘Jeósœ“¾À&}0þóÙh³™î_ZJFÿ‹"}KµÉc£7ðÔûñ9ò’¨Ö ��è\ÐJ�ð½m¼#iѨùshk±ÀwÆ{·Ö´“7Úl¥?üà;ZU=:°ôY)¾-×!M=ÖÀ_]ÿ2„Y÷Ö6Ró\c î"<Ø­.�äWo"lÑGæãNªt#ŸˆØÐ 7ŒÏúA�™[ô{Î.œÚ> Ž�“aýÑõƒ;_?‘ë/¤ñ¢�ÈïaR{ÉÒ¤×øvE"µyÝU&Òh3ã ¿¢`*}>ŽŽYbÅÂâ»'œö{¡Ï¹De³Îú–��U¡TÎç>é¼r“„$ëã7—.ªÔBuù"Ðî@Â;¦à;‡l˜å sÔ»èòý Á³ãð*æšSïçƒgµ/u¾µ�¢Ò!/Ì,”Þd„O+ca‘qã»Í %x°l­=H¶`/_3sûø4c»a'Ãj@Oú™î—k&ÊêSØýÖ“9÷ã2vN(@·Ñjþܸ `É· °^pé.�wjèºG:à~°„r½ßŒý#{ðåzY¢Yøˆ(:y”‹¹`cº)u;ªM§ÉQÅÃù8è—$ßÓ—ïIó�~¸Øu„)í›Å™pNÂ1ódèO: ¹ÝNu­áÔ?¨€˜IòIé0ý^I¨tÚwZÝô€ 45‚‚ýké‰ï§ñŽê?¦Ý÷&˜ ²õê�#ÿn(xl¢Êµ“®=ÔD�,³ðœpf7þ‡÷„ŽÁ“Kcdùô;æÄäÒ–FZ üw×\Äþ1vö²@5”ƵâÔÌ&‰¦? %©ÊYÌ“½-ì¤ãÞtÈf€^=2FªåD ëÊQ\uv†It.0ý昲}TÑ0‚"¢.Ð? Zt(†—˜›Êãt‹t7¦3ýqjôwØ<ìOþM–îrÆ a‚AbYXYñ¿¤wS/Óªùð€ ¢÷æm´tD�±¹µ »�‡AIæ'Ⱥ�Î&oµ²¹;Áä/Ôº»Ïnƃ�÷’›“Qd|ŒWù��æuóÉaG.Näem+LB¹Ý‘`‘Ý ð@h·i·¤ Çô“‘=ö™æ¾gäÔSP¬g>/ñ ) HK3Ò‰Oùx%ä‚YïȪ©TèþbF‹ü"^egM' è_ËRÚú_·iÉ�]dgÐ<”¼ ýh0]L S®ƒ^8þ™ÚeUÀ«ƒèƲûÌ–’ç8h“AE cüü�àa6 OS³Ê0PÙ_�F¯¢²óCIH mÏõˆ]ë#j1ø�pF‘^Õÿ:[îô°SÿKbœø—°rþ&¨“Œg¦S½@ÏV~f¾Šâ ÇÛ„ëß¶–;’_âX�¿‡.ÞúæŸL„ùûN±y¹Sè“;ZØ´µœ4ìǪm•ÐsŸ ¬ø0|øûˆaZôãœKz¬ôâÒÓf ³&´q·þBÜTâB�„Àûï«fb&˃‡6‘�âIÄë¶>§wÒŒs�©’^\¼ÙŠÃ^ÍTþß´©Ô?mT s£{î÷�o9“ð’ÝŒ¥ÅÈâRæL~�Æ¡Ëë€wO¶ø©ñ01´PÝIlÈ$xÉŸÂ×;üÙÑ'…`þüYø§¢¦Î˜ÐMrÏ@òF ü²0ƒŽã“äÕ� LWîGi‡‡&}«VS{ËaÑ’Õ�Ø_46á®�Ñä|ý'vêÎcø8hŒŸÂÚL^LÜËÆ‘% |ÁÐØCûHÉ*Â,4þ –öðß{/ª£T |â4Õ¢.À—´ "–jZK*ðFõ,]§Íé‚è*]põþFsü_OÓD~„±Í–`oi€7×/Ãê·Åx¸÷-e� YW?\WŽ‘l<ö´tF ·d&ñ^†O†}¤P5�’Ãjf°ÖRŽ•éôJ¥ áož!>Xj�ò„h;Éf–ã¦%´Þ±•dîd×…{�±Ž4ü5]O¿/•' O0AïŒá‚ñxž[@+ÆÄXǺprãé‰ödô²U NUŽYî·¬@¥êfrÔˆŠôDAå׈@rê»þDC½ °Ú'ŠxA‘#z®�Í=ã[Ȱ4Ë?0ÿ~âùZ~Ú-{š]›ÇÆ•i×ñÈúå{å]˜=êB<>"}·ÎPÃÍQ$ïn5{ïÁ�Û«F•ÇÐe¼ÓÞìb½Ê�¢GK¢°í§&kcp$£ºZˆsÔÆ‰Šòq´ŽzОÆo’AC�AvèÜ“`æŸ ›µv€Wô$#¸,óªQºÊï-V¢En`ÛhÉs@Ëõ ÷ÿJ-÷hˆ–• x«×†J3\pLª–äþ^G”âè.sgöÙkT3D¿Ÿs`‹–¦_jŸ_s8Û2Ó°²Q€s†;¾: :ãÄßSj¡›L]LKЯ@bšðÛüNÆßêúyÏ0BðU¢—æ_v+a®ÇÌÇ ØS½2í¹ $ìY¬º p£° ý[ÁVú2ò�Wh¥Å…÷[èy¼Õ ¦·Îíe»yØÂÃa�6à¬;k²¢„/y²0çt%)[PÞ˜ýC–5.ÑBÇFï�Dëœ�N&å…løSš‡Nv�xI†°¢æE«1}b{¬,�ïXþ~8!^EvpVãuF›hœ<ÇüÿúqN|–oyÃt««Á_¿TN˃¯Gô`ŸÉó™¼¾Ž>¦o\êËüÅù«9­NœHÑ0�u�Í—ÅaXO†„< 9J³YZuAðqd?öwÕ’œÓG`iäBðR®ÇÇÑ„G4ÄäI’²Ö*â§Ûjp'w°gaœ”++Á÷.ò&8âËIŽn7ëýÖ   ËÃ960N|®TAÙÕ_äož |rO ìÈ"“s£ÿöƒ±�&Óø#…®ø/ÍÚ àÓ£q”yúc3oà›zô'+€¸ÜÚ \W¦P~qg¬1_JÏ=ª§&EâÐ�?Á¬áY˹/'�)SKÉÖ´})|QLÞn?„ÇrØÁ� ë~GdâŽõ­$H‡’Ì £`q¹²¦Á‡¦×8°l!§ôp2˜^Xc=‘ô‹—&¨\É~w'ʰBéå °áðú›*öÇØEÖBÀT†¥Ú[CÚ•ËÑ4æ,&š €ºŒçÎ561x)HOÝ(¤{‡~“7>“½y\œÉ rLßX„®­·Ñoä"È¥}Å·2P2H“ µldBãÞÑ5 QÆ;D†.Á ƒ3`SÝCG’ðQ] =ûú>Qé:ˆ}ï>ÿË+d´² v«�’�‘íÔJú3ÛLü#ݶ~/MÓ[ *_Æ©ŒaƵ•œ•.‚œ5^=( ›„óáHA/&¶ç€í]næÏé „ë?}N‘”çØD%âIàué+óùà8½ò—þ(NbþÞ@·¤y¬te1ìª @Ý.n–EL?êÿäÃbÙ XñO9jÂô²s%îü\Züà9ÔÎ~”‡Vzœóa•¸Á8Š,o�Íy4ÒŽÆÃHËØ\ÖÑ_¿iÉ‹šx| ȉ¼¡Ü;Õ!êF œí˧öóÏãÞS!¤þ–ò&ŠãåÇ€ŠS›Q¼[r÷½ÀÝ˧À+ŽÖ·íÁ•%ˆýáÇÁ¹?Z±ø[( -þDÚ6FSéæ4¨´Ò…P–Á“צ1‡®Aá‡+xÂDs~àú2ýÉó‡NÕ¢gÒRLÆ $£„ì?VÂÙ¸̹§‰ne®ZQŽ?û]@I‚ŸN� ƒì¯‚˜ï¸íxFÑÒø!>Šø¬0~3D¶gøÃRa_jµfHöNfÓmÞœé^¸Qu>Lt½ƒ?aeŒÚiЪӦç"wÐÕ�\xª NõN‚Íðwàû§Š!BúŒÇL²-�VÑ¿®Ãœ¾Sôú… 2£LDäÜw¶Ðà27tfg `ªôñ6þ@Nòw‘ª»kg|4ˆð¬EcPvi�1Þ¹¬­‡©V— K=}§íˆù¦µ·vÃÒ@ÜëùºXóâ:¼B4±áÓ¸i ($ß oÃö'%xV+ úG–—òX ]�Ærhâ*‰%e?�cßjºÇï3Ù0Bo±øÒõ°¥ªöu%ŠËÅ”û‰U¨; w Óðô¶f†¯^ßðÇ‚‘´,?3Œ "›AÁ0Ÿ”ý�iÁjl’=ôÛvÈ›º†§wu€Õ¢.b¬›G¤vÌåm %Ž¡‚ a& Û>¬@U¥`l“$û ópÂûÛ} Z¸(™*U\&�—dé°�«Ž}ó¶¨ãn?ÂïÁ�S�¶IN{Pà© f™}×…*�×ðm‡1¼½úΫ‰á÷‡>¬‡z‹X>!MäQ7°T‚,1Ü3u¯æG^-•Ç�ŸE`pJ’5xì1ñ¾†›ê-‰ionµP„�v7 ð‚k£Vd»Hî>9»Àœ=v¤×üjᮨ¡p‘ñé #ï P;3eêý 4dÓ½‡BÈÙ  šp›�M<¬�ÔNô?ê —nºvNmøºïWsˆŒ¥½‘˜A<ëw’õs^п_•c±]çqî|òD¹ôû¦¼ÓNo$-ƒ$Çì°kTÔÞÍ~¸ÌB½ãB,é°™zÿ½<¬ž5nT¥u+˜·å<rJSö�åˆÏ�ejƒ>CVQè¯i†áèËdè`H9¦áðNC=¾Ï�ÞízDºú½áÄVSX‘†ó=-ðˆD76.{Vréà·6úÏEµ³NÔwßkÆT«ÇÓ¶Á^yJÆï€áÉHæéìï´~–*Š­ ·‹O‚ëËdCylÙö˜ò+Ò7’ˆÛc|lkGóßzôÆ@,¼±áç”/vdê¹Z|®FuÛ!ž*Q;Û#TëÊ8Y±Øšµr°úûÊñÅçK¨¯÷_4o€þ'B¸Þ$]ÃT蓺ODvWF7@Cá;r¦èh¾¿‰�ºMâŒ�w«Çp-…=ï‡IdËz_ÉŽ�KãÚ1{XͧÇžÏä¯? mo@Ͼ`à4>·Ê ÍÏËÈ­ÕùL¸«ȵsã.{iVŸàü“} uï 9Žo`´6œdÎÏ…y‘r¨Ô·’#ª.¹ÿ÷úÒÌG÷‰WÛn8³ŸôeÑiÃ%h$ Šåñ‚u6p èâ©ÄM²‰„"O7 ®™Yã¹#$E¦Om?ŒG(¾?�ÞÑæ$pÍ3Zµr Tà•ãk©�»ôÌDuö86Í;‹ö];áî†<æÎÇÔ„Y‰sÿeÃî S�M~Dr;‹i÷‡…˜©¨‚ÛÞ<3u�Ü×™™/gø)ßêܶ4�Ì1d;­Ûˆ:Ùøem)Š~¡òêa`si6™|µIN!ÔGÍ…ùÂ2¤ÉVöÕ�õÍa`´}†M%Qóæ,”u…“:P ÚA¶[£ÛŽ_ÄøºD7ð²�°pò¡j£à°ƒxã0ÆØ–=õ3�:>”¢)�MÔçr1´e]Ñw(;9—¥\]‹]ÆÎø3¥ãŸÏÍ»5d]ÖzíŒ!úßBWPi(Ø Å‘®#Á{ã‰HøF0ÖœÅz«— þAP¸ÞŽí¿ªLEÍáàú4ØŸp–¹ßèßÎA|Õy\þ®Šf˜N°}�×buZrþäþ%RX³ô.½üD¿- A[+xˆY”3÷5)õKf¤O]‡�ÝÏÐ#ÖˆæÒô�öUGiŽªæsz]k7^½nƒ©¶¡è.§ïƒ ÙGlO�ؘ$ku}n‰µªí “g g®‘xÍx Ìöĉ9V�­�çt…LÒ5(_ízbè?�ß]¦ˆžÇÑÆ5˹9_I‹óO(®Ú@ äXkêE8M¢4¼ñÉ€YÔ¼«“ÉwÎ…+Ö`Ý_e\jqªø§Ipv y¯3ÏÍ‘ÄÄO áLÐr"7‡%\ó8r4¸1ê' üžÊr.?|…û'oÑ|ãR0/ÁÜó‹À×Î×í–Ãk¼ŽK¹é›%b½OÊ8~&NqûÓŒ‘Kò»ð‚?ïÝd& ;ƒJ¨`ä ¸h¨6•/{²Äx¬Qð„¿+ÑÀw�ÉY w@‘’‹ÉɲLœ4égÞeÓêaó8mé‰~¥á@ëùL=TdpTÍÏçü¢mŸ0¯™KTHæ!îÒÁáŒÜõU {7˜ê^LDweªðö*~ÿÈÍÙX=�»Ö€Ñ`(ÍBXô�êˆÒ€</Gø�|‘ªœ jËÞK·tpQ\�·ó3àAØ (7Y ov¢ÇÿÌ�ŽFyæg"SeJä>ÿ#r—2Ñ\ãá«vÇ‹ð©ÕbˆÙ%˜tÇ?k£ÙzÓ¦Èû&žêïË#B ²\‘¡{åQ}k:ÕØ� Ü9M¤�Ù åàxȳb6¯ƒC~Z8o¹~�¾LªHxà=:õ÷(¾îÊeÁ0´ ÓEQ.ô©Œ£'ƒ¸8ß|7¿ò zõk hÛMQ1>”e©C™pñ‹ã^ëp¹lM~}TFÝ’Æîy#¦Ì¦ Í±CÖd§«%‹|O£¹ÁO¡¤x­YiFÄÅ1Qï|qcW8ÜÕ`íé¼Lï? s»yˆáàlNum.YªLÎÛJqg¢ÃßxS=‡Uóž…NÕÕ ¦�óŽ9¢ŠéFø¸= “4ž“ãïQ¿Ï’}MØÙ3®aÝ·�#üF�[ɱ¤7¹€ÕwÖ‡p³T甲3W¨ÓɆz¸!̆wZŠ˜ñ¨“ÜŒ—�ÍÎé$¹°‡yòä ¾ýR„mÛ"°æe YäC>Ô@æë}ôòäbFÂð'ÝnÑ€ÌTÏ{�ÛßçàèßF\r•ÊÞ8F¿»ÙÃ5Ù'˜5ãÆ­·Ô8&E º&”&»Šá¹u+È–S« Ó:‘0÷DQ£�ÒºJ8µ½�¼µ“"ÝÇéÆ#Rð}á5ÜŸ2ˆÆËjáJŠ9𠆼m�£FÑ» Ùí23:g¼ #‘?MXÁÄøpúTÇÃÓ&L‰°='¬üyã§Ü¥pìþ|ÖÅ?áô×Êxp™ÿ÷­þ:©·pÛ7œÓÝ ‰ù–¤YAžOÁ�"¶Xþ) Z§*­Þ삤î˜'ž‚ÖGO£õ;kH-“üXæ_7:ŸW»ñVœû÷ QôUB�íûp“Ý{��"…a]dxÍy|$P™m %°.ª¥™ô´À�Ëb«§558Cõ¼M)«¢‡V®‡Ws^�ø·(ân”Q2Cta®ÝÍ»—-6&ÆIúöÍ’Ž°÷ÌÙŒ“NÿQõ•õìE{‹‘«b6çvåjLŸ>MÕøCÏe^H)¡Í�zøÇšcª­Iïˆ'26œšÝM„�cièõ#ع&†Yô¥¿á�z ¨ÌY²¿Ïƒ‚†>[­ÈRˆAóm½Ô^=‘ sÛ`[ÔF|ÜJº9’Õ˜ ¯ÇðŸ |�ƒÐ€Þdáê’~®‰óøÐ½î1¨D¶ ÞÊ<Œ}·;×[ÇÓ�Ïá°H éè»Hƒ7åAô„)loKÄoÏ`Ù7]èé92Å‹Ù}£±Ph¿BJýqÓ`UŽŒ@ñŒÕì€ pºò›z›Q³Y‡ÉŠœí32Zaøúï<ŽºççK/]½ð9•ƒ‹JH_89¥œ´çØÅ߉oøasŽ8K7ZƒCÞvМuyà"׎láT–ÖA…uù.†CªFµÏ�0¯î¤ DÐwˉ†’0'<Ú“µm†7‚A虎ßîÃ7ë� •ÆÏêhzCçç’Zf-G6µGýi“Ö8±HAí ¸³¾êRcàåœÜÝH`AÐ&¸ó5sþÕ@EŽ&²/À»•— %{)js¿‚gcg Ýè šþÞ�hÝÃмmå˜as¾Ç‘ÄÆÐÿT†e?t¬DbãD.Ày�Ôî�)¨èðQ¡¾y°Êž ›Ÿ;L’½Å9·6{’A ²Yƒ¤ï�v@�lWp½¶-Ü—p|R`y÷²yW5^ûZLeö&³úåDôó'¹95w ì³8ºÆ‚®Oí¢Jº†¦Š­4òÉüu|1èÏæ'ºKSÙ.îÐX)…}¿¹�”Gàª1È‹—@®¡ßd‘‡N¸Ôbë>òÔf\(˜¤©/´°yÙnÜ¥u—¬ÊƒŸÇÄ᛾ ûDÈatšŸŽÆ®çPàŽ*1öq¤áç¤`}Š?Nñ°Je€Ï ¸Â”SFI�´Ï] ;–cå‰{$yT”ó¢ÈÆ{YÔ·e ž$ÿ0s*�²,•ñÊ­ ØH]·¤`”'8Õ“‰g³XVä²¾5³wäÎt×°A8ÓÀÅ9¶ê'\ªâˆ×_ceT çÞ ¶¡+ÏVç^9f1ÙVêÛdØŠ¿æcI æ,üFôVáƒü)’²õ)Ý®¦À*ùã€+© ÞÛ`�¸¸™­#>x÷G�CŸëaä¿�ô¨ÕKötÍWÓ¹T¶Ç»eÔç·(¤4‰¡!±Àæ\ðöá,øOı�=çÂË<Ð\7Žž›|>ÔNô»8±>_Ødõ�h¬ Æ Xf{ÝþœAÍ&=\2¥CÇBÀV6�ç´¼…@¯ül�ªUÃ`¶ä-T{+À¬ÿjK_]di~ä‚=QÉØQió¡oí˜iàÓ\f&Ä Kb¦µ÷£ºÙB¸ÚŸ�*áÎ4zëŒÇ]ƒ¬æEpkѳÎFŒó{í ó�`_Üò¹±D65f©»°‚þÔÿƒY¸”û `ã•ÙT¯¾OÿÍ€†µ 4Oã4x{ÁæãFdÔL‹¾\´Œ6^=š'ßb_’~8*†®&Tl.¡ÓÂ*²}œ ¦ÊÑúÅ”oøÑö|OqÓAX¼Ñý ÏkË)«9\o•’ùÕ¡ãìy\VŽüÚÑÔ .ªŠrqÙ¤0òŸºB î­&O?÷S¹‹Êt®i-ÙóßZã´Ëˆ‡˜€ksG(}Ά"\Äth>pÍç¡5Š_aëØlVI\ZžÙއuï[">J—â¶ azUo6+uà'=Í? ŒLZn*§�óÇl!Ç£ˆÉ�dÍ.„½J‚œ€‡ûð^H?=#° ez2˜v .šƒkZ‚‰¦¡Ö]‰‡y¨×}.8‘h šJKˆ~ïFˆ{š*èYâ”T8vD²"/2"LÏäð'Ç冥}ØO†ã`ü ‹µÓ°š.µƒ¶š$üë&€¹N`þ(/g÷‡ˆ«Ì…Êųá‚~28½š�‰¿ê‘¿°˜8v*@§k$lúB<ý}Á¯>�T”Ïk~z“Ž29×H¥â"œG|Ô#ØSýj°=V$^j’�—}ÐécÄ¡â[9ÅD›* ž…‰ùó1bÇf¶gn fß.¥n}]p´¸�ùæ´ÌVdÍp‡U,Ælg,ïKBÁÛäã—»¸½àùuU›Õ>)OîJâ“Ëq®Ê/bÖ|.t‚›Ýlá�¹œ¸§ÆÐ8ë.øG¤àéœRL±î¦U"…xvˆÐ<^KHÜþŽñ¿R•LޝºE„ýfÜ*³ n—°éð™( ɃÇ׿b\×7ZvÙ�è´ÅÑò°vÌq±W¥šô7ŸðasÅOl„šO¡|ƒ ð®ùB�_}D³,J ‹‰†Á •$ÕjÞiÌü;—8–˜Bh¥1~x6ÖÁÕÀê_ÛÄ-ðx{2ª�)ê;ÇßÎ0OÿãÛäÕã#(1¸˜.ØjJþ5?Ť”oä�¿,Ú«‘e΂¯.uc'ÒÈÙ·!ûà,âeØ“s&°8~ ”WN[>Gî¹·ñ—0FŸKGÅ9–¸$晬Á„÷ÐÑ^ÇF¶âØWq\å¯Ä$ž» óä5àý˼/\Š�^h³k6�–�'žwþQÓ3÷hšá5Rû5VGÌâ|“„éþ'Ôöég*êl@Šú3ž®ê/£K¾|D ¶\†bKˆ ÕcQg '"àotšn�ãžï”NúJî/2ÂÈžcÔÁ/üøÈ¹44SË�Í´Uˆ´÷ôÑ€­¿L7Ù |j*ðû±©¢�fzî‡Üp½©—]ô\%%�Ãæófðæàiø^ú3¤ò¨züwj´ÐÆŸKA`Ô{vê}g“¤/+Ù;��Ò-ü¤@0Ç6x6j�ÁÊêOŒLý]4©4†„WÿÑ?±åX¸|ÿÛÓMnµ¾#Oø5É�M;±jþ–ò2ut´A2ß’µæË!€¹nÀ7[…õðÃ9”ÿ.‰[Ãj¨¹o;öó†¡mܬ?’K¨§ÙWðw馎ÖA7k6§�(•8X]v�æªg’›_Ñkß ìuw…ùn:¬gÿÍåHKÿG”²îÌÄâ8J«oFá õN&ÈúÍ zÝc;µçÑÁòŒT<µJ Œc×€h[}LDé�ð£Ì †rôà°x4p-˜0]›âOlL.Á™V)–•>‡–Zü0íïžÞÏÄúU-3¨^Šx5S¹XZåE»ºv‚¶ÃöùCO‰g#q[ðö™Tã¦,mTºw7V=ù�4}~8qçÕâkß‚ÆTÓl¸èŠÏ@ Å"α"\>¬€�ž/Ä‘?IØ÷<�½7hƹe�ÞÞ(s¿Ô‚âG‹#û`ÓÓ0�hª…¹ÇÃéº'BðSgõ!+&µ ¶!‚»x�ª7­…WÞùÄQs ó“øWo(ÌæƒÉÊ,Íf¤ú¦n.™ˆavü¬ aûa×ÀtáS:ϧÞ4NSK™¶å«Wdt·kݦrnÈ};�ý'ö„ù¾¦Yƒõ·•aÏ�ÃPñ¨‰úE `σPvKÃrt0Á3mA@×.®Ã£3}é›ÏUˆûJæGÇ?à�l/TÈã\™x4&Ó5~ôÞ;¬Û¦LçH�@± r¬�YÇ:~S»Î`$=ŸÉеbPðƒ‹—œ@Sw!¨óÍ…²Cdä¬H{í4=Ãô2Ë7oÀðŸø²ö5Šèÿ{7Ù8¨‚x¶“ÖùŸO=nö_ŽÙ'´ ÿ¹OÙ/Ò˜éF¥B_ƒ­F1õ\CkÝ_¢ù¸ æík¦sëØQGÀIó+.Ö Ü†Û›ÃÙ†ÃíÄCBÿžøÊ~;P€+h;)~o¡ÒBôXÊ8ûL¥ ü>:f˜N±¦Û¬Ø�ñó ,ÔZþ%'<–âš&/ؾB†Ìß´?�ú$jAÙ¹~ºþqÈêòr/|yI�>¥6åwÑͱ^Hò�\¨sÅi%>ŠMƒÌMñ uÿªÔüa|Ö*‚õvê{O Ò<·}'¾®SŒ”êl¶évEκÅ>4Cß F—¸cÿ¿Lœ.þÅ$ŒëÑ99ó¸ÿ­›%Фס6àëVI±ÀÑÂPw8 ǶîÄO2ó°ÏÔ Y§„ñàN%¿½Ó"ɽ|sòK}N| !›Þ_F“þ$Ô[¥‚ƒF± ¹f ”FåÁÕœ $ÛødÏþFȺ9à·;Ö¼…{u È‹Þ}`[YD¤û#H�Fæí߇!W;Ê—ºIbºJÈÛž+ =vÙ¿�]¦ˆÚgî¢ëàrÚårŸøæ¤ƒ[…ò÷‘™ܤ—ÍW6 úÉ#̬Õ`y>„¤Ö73ùz-TÒE•®�ZÏ÷ŠÀ�¡PZkWˆ§w#Â<�A=H‹h­±Ã:×Çd¶^2•Þ‚õÓ1t‰ócì?r�ØÒR*5Ë�¨<ö¦RVþ¸eÑ,¶pD>­¶ãà½îdJ ²2E8A›VbÔ‚(¼½ÔÝJ ùó <ëþœmz6…‚ÜÁb"k:nÐ?|aóNw:ïj%Yð$=OòrMn�€+G„aë ”çæaûv{®m“¥Lü[ŒpòDG7U,ÍöÆÛ}ôÿ<8ëxúçßF_æU0qÿHÊÿT€áQŽó¤0*.¡ƒák//§°Ù/JÐ¥sÊ`×ÛP~ûse,†Ò�tc‡ ý9¯uøØ§N«Ó1|CÕ>í¼;ä±Uf/•ÄT® t÷&àÑžNrmtÑúO :Ì1Í„ïß^YöáT®ÉÄ 2çwúoi$Ù\œÝêëÇ’=_n’v[îF¨'ª ðk‚¹¸Û_ßjÄñ‘Ç%�‡»¨Fi ؊ݳò�cß§N†+r€�² _÷ÿG¦fcë{L¹ ¹÷ŽE8ãH§<Ù-N=Hïá‹À¶7·ŽùЭբðtñ4ý‘ò#ÕàÄœF:çB™Ë¤ãÂô½’¨l„GǹPñ` çøÊ¿ÔãÅiܪ&ÇÝX™¯µgp+eãÍãEt«F!0gã™ÃûCáäI Œ�£ǯ†‚ÒÀÜû5 –�g°̴—�/ <®p4¢�~ŒxÉ8Ëz�qÖ+T•¾ÛyhÏ ð¯ÙKFÛãk“«ô{¬ÌrRfާ߄_¶ÅxàT1�ÁIw ƒ.{ íK•¬U†>‰b—ÍÛ>ÿ}-yÈ„Z°¾}dÇßIÀ¢M¯IÑõytºNSD{‰)�,þ¨å"[ÈfÍ$ Ì0"gSûéR9¸w4- ìaàþÐÖ‰7jT�µÆ<%üÈ–ŸFdqó"2¿Ü‘uþK�QG^Ã(Êm¥ç‚ì|.Îý,�'S6ûl"u[ãQJs&Ér½GÆ,r�´À³&>øJ3‰ÄÒ¤jå•Û0‰Kø±3…‚ø‚ÏôèÜ •£¦¡‹ñUeT�íñÅ™ìS;\Éš÷Ve} ¼ªŽâ¶Ù‹aåÒùÌ–7,rîÍ6°ž1ÄÔE…Òêm3Ñb¿(D€1ÿwôLÿI§µùqYI U�ñž­½ê5MNËÀÑ*al;6…÷þHÀ�ÿV°Üq‘e˜t�¾³õ]ñ0²oÃÆW­„ÿG1ÈfûáöøÓ`œ ©jç0}S:y¹‘K–üÈ€—Jë±à˜0´`÷*àû»gi®p¹–­ÂÙrÆ&.„ èuÿ@;Dn²º|EÉ…+Þl;…4ø¥³ yâåQnÓeØ"v_¥žG"ȢǢx¯U|4ýðÖ.y}ˆ^\‰2úš÷:†hy�^Y�=Ƀ|zQôÇÔ ÿ/ƦÒ0Íø.TçL�@Óç´F¤ *yW3Z[WÑE»?•vvñ½bÜ dÃŽ¾åTþbS/¦¿? ÁaG‚$u5]KTFñi‚í½õÓÌÎ’¬Çwp\Q.ºJãý%#øæ†,Þ{˜êhÐΜ*â4Ë+¯0i§KÉáC œ=mAä�qþ±9C…Ä&Éæ]Yì>®%;[‹Æ¯þÒñ÷˜oŸ4p|»Z×OÑ"M5TfÃQâC-Åó¨Ë�l´˜N€¯7ïà.ùËÔGµˆ,ù»—<û€oåléám¤S*ŠxÏÅÇÖâð`�2°®4‚_5ñß³ŸzãâÕ^$Oh+HyO’—{IDüªo“NÒ<óY9GŸl¦ôìYL·Þ�¾¢vÉ0¹^ÜÈè¬Î… ¡ëÉóFWRË ‹Ðè^(H¼–çnÚú€>hš$·õ�s#û#”®Þ– ©·Sé‡||5’N,ç� �¸"?7„þÚµˆLž^O½q‰-®ŒñÄÞâP½2ŸN/gfGS‡ZT?{¾œ3G»�¥DU¿οd×äšã‡ ždZó ìâÈbëw¼}/X š´v¦4×íE;[­Iƒ0ÉAàwY7qùa‡Å"2/z æ ߣS7ôqÕûôóûùÄ7„§÷»Sö‚Hâ×å Ÿg£Õ¢Í¤M[Ä3¯Áùê» Û&j5™¸du&5û>Èü9þ 7ׂ]ò4ãÔ)Ëž�ÉF‰žö|�ª1+ ÎfÐlF=L·C5n„ì(CRÇ_NõÚ¡¨ƒ¦å§bêJ{¢¤ÊÁSûú1·¶DnÀùÛæ°ÿe «ýh Ý?'?ZoÞºYhzÿ!]ä“†Ñ ^pòM9n×XB÷^ÿFÄÅ×@¢Ð/ÚÙv_prHè,uîÉo¹ønD„ M‹Ñë¢Ax¢„¸·[“ÖƒèH�,¼Þ”UípvŠ>ÑÍ¿ÍÞ#ë‹æ^?è°Cp9&ðËsnÕSG7+„«yføÓ*€~ÏK§É âéßY‰ ³sœL®)8þŒÞ˜q™IáÂÕ—bœ[jU´íËgÚ$ÑÆÎX„V Ù/Û·#Ç\žN¯e[¿Úi÷ýpå¡–¡ôa�w¡�(ÿb7Ú¨Cƒ›ØsS[Èâ¬`èU�âî[éK¿ªß£±k hãÖň¹¸x‡${2§•=$syWëÃgýf<ó‹ìÛÓLC´ !¾Ð%‘]BÇaK®*\_EìâŠHåž“¤/]-ž5AнØùbãoÈÇ-þõ�"ˆêÖí�L,±FõiWò‡âÇöðüÏ,÷ò#žé3A‚ïùöH2–¯äŠÅZ€d«t.+$™jUïÞ`ÙìÕ0¤ÙJ2–bAP©nl“9[k¯?‰ÌW�U÷bàÁ&_茈@ßµé8RzVÕÑ·PDE¾â™KçÀ#n&Î{úž¶„ ‘®Ü<ºË!ÛtPû y{€Ë^YJÜÿ“�Jp癟¨ �O¡{¼;*¨ˆs^¹Í†ä_€Ï ŸÐH×fz%"’¼Ÿw>¼[Ì~£Ož^¤á{ö‚pÍ$ýñtDØ_©A:¡þ!^t¹Ym_–Dwï¸OErx¸C}×qRô<´ÿ 6à =y<’:§ø§øntÞ˜�—.AØgØ]vnõ“Ÿ†¿á¿Ûž �MÝlׂFK=ɱW›÷ðI/–îK¸O6}ê!�ôpðl&x�<Š_%= ¦÷$,DZý²Ê®�£ÉÚXì°r¥µú”D�ë¨{ žø‚²y,õ} 8TGAàR |Õé!ÃÛk@›ïw¬"qmgP¸ª‚îrL¥â-—+"kù1p²›Ï}!qQÄt…{Ö.)Úü3[œZX–¬È&ÿaãt|õ\Š#GMAý ¸¦QT;{ãöásîM¼¾s�®‹yÇ–ÈX‚sÂBȃÕè»Ù€‰®÷ÅVõ8üÙm¢6K±ÿñL¼T—ŒQf«Aa*teüášÂj2º‘2êÍäôŽ.¸áø„¯#óïo¦¢¯»éDвö£,¾fXwþRÉà[ÌÇŠ�ô÷¡¿°Ìö(d�#(4Ø…h³3õ7ñÞ…K†nÁ}·zsŸ9-ɳÀÂÂùpüž/þ5Ø¿RšóKd5ÊÅ¿¦‘ʉ‰Š7Âä:ú¾r [CvaV+í›aDDÛ„À k=ìqá…D¹_ì“E–¸ºC,\‚ÑqM0=¢˜ê ¨âŸíh’ˆÔ]Sc1Êœ@ÃÛ|êùÓåýç£×q{0š™ 9œŸ3ø¾T Ýc#[zË膉¼?š…)ñ‰Äe,�~|ƒ´èP Ùê7žøM� åBpìÅfnY‹ÃÊ7à®­Œ½JÀì’¥Ðër‹21—¡fsh¤à˜óM|öLõßJÃØÝCÈûq-> ó2`›µ0µÔÙBSy: ©ßC¹5Op^é1ªVçƒ'õpÉáòû@:´V‚/üèÆƒ‰±v10i±ñxØ{æ=§>rz�﵈ÎwÆ­rT{Ç]ôáÛƒ‘i@ðTvŒ™b<©D»Ïç±p}­Í»LÍjùpÖòH²ò¯:k­ ”öaS½�Wúïm ‹Ñæ¯2ªú`UL.¾0¿Mo|OÁµp•/$'YÔM=ˆ —ÂýÑN`Ëç¢fá6ö=�aš/ÑF—œb´þàRs” {Êþ]3…&ÙÄòt» ïê‹ØðõÞx�øS%fØÂÓy^ð~.?\‚Zнr I× Õ7À{µ Æ¥á4¨.˜‹êÑ´WÙ�ðïr¡çnZIþLì'WX†¨}c;(½jœR™ …0ô‰×„ý“71+»¤vùâ7ÇܬqŒ-Ï· T9ÞÄòQ<?4@2ßä2ö¡­›ÕÖ>À𵜇¿½Èw³yXZå…Á¿UÈ|ˆ&U«|˜×ÿ¸Š#‚êçËØ=jÜ÷ò pïq;õi§Bú;H²Ïª§4Jÿ›Îžkƒôø÷—Л²žZÌ =ÐFt†è9×å=ß’Ì÷mÃØß ¨ùù=½1dtK�ûæ§M {‹ÏÞב»Ñž°ÝrôŠç‘·áóˆ×�^6N%·L{Æ \'×Uœ–Àçåbøð® š¹DUŒŸÀs§ïØ{Ö”F¹è€£C5Õšn¥�Mö8áô’¦hÆVôh”¡‰Âu¢pß�ðÁÉõžh".ƒaÃ#ìì´lè’cƾú�bîÌ5~Ê4è\F…þLÐþMØ;¸ÿê´Å¬N5Xb°+VHµüÃ4u¢)¤Ò –ëÇÅ«p›Õ tåÓ%×TÜ‘ªM£Õ–±Ã¤»˜ÇxböHOtß!u-õ`ï$Q9Ì \'ò¬qý�¥¸¥]->£yžáìm&â Ð3Êp·ÛáĆ�7ÝOà‹çë`©í+ú¬Ñž ½¿ŠšŽ§ƒRñL Òƒ‹·uUëÈ�ã4ꟗ¼øªƒ¥…ýøKõÝ·¤�ªù„Ô9' 蔘ÝNÞWu°ŽõÅ3C‘#åÕÏÂy·°Ýð�6^Œ¯åI±¨$úŸ>IÊãð¶&P{'†¡¼«`úòFâÑ3êRùœá?”F·›æ²·-ß Ü·ñÔ ÎÞÛ PG¿W/Ìbûí]Ï<ì2‚Ä m¨n_,á!:ãw$YõLôìÒ~»ÈŒ©&ãa�R)WH7|?ÊZõìæ[„�ÎQ¸Xì?ÜÒ玫mžÐ›� úe²·¨5´Vü¨IØùgFYàÝ­ICÄq•^ys1•tØ‚7kEQ]3SŸ“’z<,9JF +éåKðÓ !Â?UÀÄßËÇV?9Z~8ŒØÈ¡ÍÙÿð÷í(Lt!Õµ‹àò*2eAØi'‰ÖW0 yŒóÌ×’¦ñÇìfå7ŒíŒƒ°˜:á&’ mIüð÷—.¹½�åÜÏÐ>Wp’â@é ÚgçGECFh nÇž­q°1Û8ü!è±¥fz­½X"& ÍãÔ¢§㥣ÐLÙEÆ‘ž¡X¨¸nMïÛ¼a­žCSêÕ¡X»‡D®’Iæ0Ü…‚aÔ-²ïSeîG²Só^þ~–^U¥¤dKhñˆxµ>Ñ ÚY´3à%ðç¾ÇebÑh~F4 ÑtW-O­]³ Ñè8¼½‘JÞl�ÍX;œ„àO8ÍNÊ â§çËáJÑ>²á� ÎÒè¤+ùg€L—º:ø°2Oû`¸ &LõzââP(£L^á,²²04$‚1E±?F%ÀÊ{`͆7—¾ÃJ«ÐåT�>Tý%/î�y½Ú¢HYŸ<¢ΗƒO¸|:£ ‚¯Dá²¾÷¤Óºàq":Ä\�ª§³Ðóü&ä·Š‚ð£¯PW“ÔWó2®‡¿²¯ES½€%Hý?�ä—ŸÉŽä&8Ó‘Ä^)BÈžÈ úkK ûbM'5Uª _vuáó’Ûtrq8¨Æ^ÀÊÉcðöï]äôCõÜÝTãx1±ðãÁ„UmŒúÜÍàЄĺXU³ �Ù…Íμt_. Μ¾@.LjsJ£¡zÏAö�O‹À®ñt…æOvi¥„Ý &];k)ž]FNëÛ“Gr+k+dÏâ0×ÞýGà¯ï7b0û4«âO-jœ&ç $�wc5º»^�fÍ~€ž. Ýž·åߤ2� bö—]¦ª ^Ý¡ÄÈ’ÂÒäýмvíiw±ÕÄ1c#žýžÃN,üH6"Yãäbr°*÷#ʈ£ùŠ~hr…æd]LJ^*�%}?éîgúÄÿQÝ .Q ´»Û“<¾6‹sË‚, C‘+pðš$ì Æi¡W8çËBÐõa¢v.Ä�W…ðJq6ÍJ_U¯£i�W(¹ñø¼=îMÎ ¾ �yþºÇ”13Š[Ó¯I b^’ÂUUà]æ†ÂÙû¨V¼08ï�¤�!bÓ)àØâu£ â£ãë, �› t„Ò!�&ç— Œ-¬p¨}Aý3ÇÈ­Ô[u•rEJÉ­å•ìeæŸhº7üÑœÅD™¶Òeë¨>ë4iþ!åcIìoWK­ûÖðÝæ&•ƒ3h­uC¾-".6âÓJ·©›ÈRÔ|SÀ|^€Y›aÛV}lpó…îcsˆŽ×üv` Ž­Î…è †N&éÃä.XävBO£"�KúçÁMÁNT“LÁWÃ0!ËÐ#A›©ë ökK8¶³•±›úCT³H¶KÍd ˆÔ¡TüÓñŒªh˜Ð÷�$¼i�¨„¸Ó„î-¨�Š&¹?ÊKiúß{ÔtwY¨!Zw6�Øú0`T6à¥+û°æa1¶Œ‚bE?2£‘ –Èà}E>._}8ݽ. �†­!xë :1O>^£g%ã�ïå9Œú—ÑòúIôSW˜]L–uÊ3OÆ×¢pýSäx�JX°E5Åñåó R»,‰yðMŠÓ~§ƒFàß={^™àö)Q<:K�ö;íÃì\Øz�&Êœ$Ûl;èÑ»ˆœÞZXs= 7*Î�½n]¦û�eµ0ø³ðó~¼”ú™È+­$OZ‰ÄÂwÄ“õ�dì„O•ñzw¾þ­Æ¤V�!÷qö§�5Ü€ŠÄÊÂ�1øFÒ‚ñDð:�LŠG6B“œ:~ç«¡YWÓéI^(õõCÍp+8>s&l[fOçÙz¡£�=ê[$`jhÕ?§áå&õð€¿¸+ìÜDi_N]¼o6°OœFíô³´ a˜: ÇQ…w¼EI/ðÓÛÏ@^xœ J³[¨ÓÑyäˆôJ²ZÖ~ŽÚ€dº0æF·Ñ�… W@— 6á ©4ðúý…ÜZ$…&óܨíà,ªÕ5ƒÌ88AÏÛ&ó�ÑéaÛ¾©†Ž\ä�Ꜭ;|~kàC™.ª’v‘œ;tŸ.ÌJ¡¹7\A¹È«7çÁdÚ'8¹G F �ØNja˜˜ÿ˜§}¤ÕZÈ1˜‰®×Èš]ï¨tÚj¬a¯i}ȃ%—&iOh.Îîl"^ç�ûêòÇ„CôºÄ¹%ž®tÔñ ÍÓ› ³ÅJð€rÞWÍ„“´k"›8?M…Ó®WØ&“ÄgÀîþ¦ áÞ¦—ÌÚ´5deœŠyªb³�ZÅ…,*ï| ]ö'áÆê�ÿúmt"Îjc]|ü>c V¿vÀ œ'–»çÓ£ÝK‰YÇm¨X´…°UJ¨ï!ðüF­Í‡©ËEŽä¦¹Pž#ƒ+ÖÕÓ×Ý; ÃJçÄÝÅâNÓ³eé�©õÜ Õ8ZÕ*ðJ9Œ$Ô–åÞ$íN›ÐðG1I=_ñé�o.iÌN›$úëo7œ{ë].”÷¢×ÞŸÁ[¢q+ý°�בz­&‘�r±ÌN‹|2ćþQè¡Àâø.|\ÑøR„¥²ÙŸôܸƒ‡¿<¦^ZѰéüŽz”;ŸÂÙ;Taþ!qÚ£‰fálÖž¶;¨Àò‡8ùôydL3;fà„ø ª¬6…J�®Œ8p2ËA« Þ(áº�«Pùކþè!Ém8æ8~åÎÄÐV(T“âèÄ/DÙùôäŠMàéIÉ® -!‚]•‚œY}¯ÄX•Þà°Í‹«‚ñh\+«ž�E¨,‡P]pÛ´�ãØå§;HO“lÇkáÑ’-Ø0º9×ç£É™l\<5‡N+’ÃnÁß±ïð±µüU[ÊevT ì‡ÍS(èi:…´hÞ/ð<ÅEõ´ün÷?*C†¼x '“+£O1m§*Øë�”q襉â£åÎ8½(ãœâp)ç5Iz‚�/Ö!ëO%¦Ër:+ýI…—,…¦Á>Mø"¸†Óê_"aÄêº7ÎX׈h@èúS02QÍŠEôp‹ °šÏ’] Òpœ„º|¥æNKÑHvèvÜÓ¡bp{&‡û²¬9‰;¸r"‡ Ä~ ¥~®ÃÍ[ĸNVO�#ý3÷–·ïXSB_ ^ ŸÝÔþ7º•a¹AüÙº³6sÕÎZ�í^/)JrþFæP!þ@4vÞM?nñ†C-eXï°Ÿpµ¹zz…tèG¤î‘¨¹cϵÿF£fà–P^NY—fÚÔcö˜Û^õ çmÎl¢¬—�ßõpüËÝÆ˜&¼¤ƒÊÞ*ÜÕÎô›{9¨AµÐ%L~ó| Q†N¡µ°8I“ùv±–öMÞCáß…tb¾üök†‹enÐ<çp/Øà¡´– –ün¸Ï1'§ `‹T ¾ˆYÓm d*ZB눙C4ý³NžvçWÒƒ“C¤áÓR\«Ùƒ;Vq;¬»ñ€•$÷Âë Ê»Áœˆv:BÕh'}/‡¬’&Ì;¥DERãNæ¾)ªG¸Ê ·ï4)Ö”…„þݨŽÿ¡ÿÒvjy¡ˆÙ;Ç xöŠpZ¦·2Î/øé³uÏ`�‚†×Ö1Ž¿úñ/zæF`„v¬6â2ƒÅ@bÀJîëú8LL¯ÃÁK¦ä˜ícø]ô�âoÈì÷EÉõ)˜Ü{ƒ©øfÃH‡ò¢B·jï Ã�s¶“‡ÉϘW6£ÃeÎÚíÙ�¤ðžÈç_�ÿ²AŒ€†–I´®Ê§g³wbÍâÙÀ=&Ìé0¡_ZBà¤òsàsþ áF¢œ+–�Ç;¸ 92Üâ´ô¼¢(wQ�:÷è�óxtTWÍûD¡zn8s¹Gqk ôè qsºtÀ8§”ÒÂG¸=ü#-Û V'_ƒkåìŽL„Ñ�ÂÜÇýÉl*ìG>]r¹œƒ8µ‡ã°Î’ž¬?ÊÔ~£Z:ÅÀóY…TȪcäêg¬;'e°‡ 2yÕìÓGŠAju1fn+ÐÔ7&²7¸€¬i:þx胖1ö¤ç¦ý}¶ï-âæìÏæúÍ,…ÀÝçÿõó3µ`Z7Ë ?JqB‚÷‚’ƒOÖ¹ÑÖ=áZ’<Ü�åM�TÌ7“ιRˆ™ö±-x6njE!ÁRú2ÀŠÃ3¯Ÿ(åaÿØ2n—ò$$É„ð¥ÒÜŸÉ2è´ç ü·q¤ WÓò´ÙÐóæ)tÞƒ}ƒóán_¹(ÕÎî¸p_™­†ÅN}¸tä1.½\‰]ƒ»`íwu2»a ج»¦êQ v'ö?0£ÚõÉ Sø¤Æý,nÀׯÔ`IóYZˆsüRð³�?׃pqž'M‹‚A²œ”ÚHš ²ƒ}×CâÚ…9b«| †´�y� ·°¸•çòÁMå7™q¶H×Oc6”ü‡Ê‹`•È7š¬Ø<†ž 0;èÌg~ØÄÏá»bÈ.…<êŸMÏœã…=«¹ùï�ÎP?Ò{ú=�Œ/€ÖÌO$�3“{Wø!�ÍÇÅg®8ü‡ÀCuY®fBÊx‚ˆÕ["ã£HÚœÜi ¯üWìÃo�ÜÑñD4œ¶rŠâ¥Ø¿„÷H:iÿד³Ö’­Ö$lRau ý*|‡|ãy ×Ò;¨�t**W¡†t2^/ãŠÊxa™þ¯X�ê¯&!r¦äoU¤ÞŠê\hÕâò [Pš8æÚ- SÜ8ÆIú]ÕQ©ú%Þe‹rô †YO.Ó¯ œñEQøcR¯V»¢Ÿ¦´pˆ±Ç"T´žoï$$ ÈbÇeøbà VÛ†O „ès}YôžÀ¥{C´ý2ΈpÕ—ó£Î%™ÐV¸zo1›ÝÐ c[³ØGjÑJa'(p'-pÔWëüÄñ¹¹+Vø3¾©Wæ,kýZžíÈç\GO>zI ÊQ¨#Å7ßÈ0'Æú1ÁØÖz8y" V©΋¦E^*ȉò|‡f%<�oÉÅ„-©tì`N�(wÀܺmÿ¾§â�?ú†Hœýá =ƒÇðÜòԔφ NEðÍ÷$ƒÉ>Ìy‹y˜)Ñ‚:%áøÑ¿ ²®´Ño-v ëöt?áåÔXšžßu°2z?÷ÓÚ»T›»‹œ�…Ù室Ӟ YSsH:-ýe©C*B·ƒÍ§f þ �OçsæÎ}G»y9jѯ˜®¥ á—ß „ÎY…ŠÕnDf®"\ÖF÷™}'¯dJ@»ê:V—v’�>èU:‚E~rOlwz¤øA­H~¯x ´Ï�ókªrVsM­ IÑ;yœX$ÀÉÊh@ÛÖ5ÜáÝîdyu™Ålƒ3çLÁ7é+ûÛ “jñp=À¢Â b>”�¹oø©¥yµWµÇÌû?ÑÙð8Ö]ûM7]+�™&Ày1»™•e².ì; *¨Mx)Uš{z¥oãCê£zƒíM‰�€8¼—Ožï©ðã{Pï'clYnöj?Ø2SÞÙ}¥'Ù¿a`B‹¬ø�GCÔ¸§·ÏbÞ|xÇêÙñŽh ™Ñ9òQ˜Qa ‘7Ñ�¸a¬.R£€ X‘È’q|ÈLŒHq,RGÑ!I §â3©‰rùUç….;mèü3p¼,�㬠�m£àû�‹65Ã1ëÔ\Ó•óÖg#§U¼ˆpRe9[ãò‹õ(+™E—¬Á}ùKpE]6ìë“䜊Òó-ÇqOi%Y]¡‡[V„ÀgÓ=ж¤(°˜žÞàâ�âq¾Ž(öŠpFŒöàÂ�Ù-•«àÜE°L²d6 ?gÅä¢ó˜ÕQûBc„xa¹r$|øV�«´$�ïNá†Ê‘J3@¢¾îóµ�étªuå [>ù †î‡–Ñ¥ÖlAî‹ÁH|¹´€ÑœÏ*/áÇä60–KEß\Ê €*_R@PY“3L—k’K70|©êýgÀÂcy²³¡"Þ0�uâ� ·KŠEŸuÃÖ@UPÝîOt,:»[; Ïpog¢Ùcjé~›ÈE¥ßü=@Ú—’éºû÷2€�gDZI_ˆÔh{%k™sRËév‘ x¹é&ev ð×|˜îÈ/�}ˆ¤Zá+Hª‰&#ÀGÝ6�À…¯Ah!—Ou‰àÊéÝx»˜»�U‰ˆÝuTHò¦ÕKÆÈîàjT÷_„9ãÙ ï¼HhàÉ!]QœŠ+¢oÅî‘�nVœ §Àöm]çt×›W¡ïÒ+ÛLR+ŠP|ÄÞÜ€F=+üpè3ï€ÓéêpõôjîÉ'ÕôÒí›´ÆI{V¬“ØWdŽŽ5Z„ø@]–ûÛ�Çj¨qEòÛƒbÇ™´u.½À!Á`¾ø5{w'(L­'~¶¼Ø©þtŽáÁ/x))“fð®ƒÏbˆo•¤I–Sõvîò)®åY ŽÚ¸ŠlÉÁñØãL£"«é¥%¤*¹œ&_ãÞBoxÚW@>. Ð'úôn»`¸ Ù÷ßCÌ;Cè¼^9A’¹A£bA Ö¯„ ¸lF(3šäý¢&w2h¬�„=x‡¡;d¹mÿÕàÂt-8”QLï( &‘gÍWÀݵž»Â vQ[ÕdQ®p?ý»Ï�îÙ:Œo¬ 1U pª$›ê&`{& àdøm¼ðI_oø"�M\æÙÂb3E´‡yê .: ·t>†)ùbâ³5L¼a�8CGO¶P¹Ïa 0ü—Tßu&?í&h¤@>k´Œ©qî^¯Bìî'bvIË£`R�mÌv²:BÞ”Æî5òhk yŸõ�i„`ïøÈü6 !Ûø¸K{©EÕV0¢†ôÈíAès~&N²S•jØ“ËÓaT|”ô¼¾…fo/�y°$ åÀÉ)ÿ+ ¾Ö? y皇““�çY°ýx11V D‘ø<š�ŒIݨ4ÉÅeRœýËš0ÚW3æ¥Q÷É\àýn[)û”1d¦(¼ú0‡k±Ò€cåNžO‘/šÜ쀅Hǃ©çúÜ±Ü ?‰€|Á,:Cü¸+5ÃL½HÈI&}MÔé§ÈÔ»Ó¥á+¹�MÁô‚G&]¯0?É߇yK¡jȘœxÛ�p¦#ë4ÌʾJü.¥ÀM«£äYB=(7s¸–ËSpg¸± 3h‡X"5Žå8§ôÑo‚ê¸ïm)TN3á®™äЊ$A;BèSÿ "�2îäeÓîÌ¿|´„·dvCwLÇ[)‘¨vGâ *©Ná‘^‘H£VÞBÍw©4ïž¾qäåÞÖ­ÐYŸs-�`ŸÄ'ºÿÁ$žßö–mº»žf¶ªQÏÀlÚÕ¤›·¯X‚‡ßwÓÚyhçNñè¶/Ôíh93»†u?Ü <…Âééek*æ7‚µõ6º\yLfÝ�®oþXØušˆ#Òñ…z$�æzdàó�ÍMj¥�,Q¦¬ƒ6¤g+Üì'…YŸÈÜ×9zC¤yßh�ÈÃÿŽ]ÆGo2©¸‡eÕJ(]I£ŸËS‡páÝ™ ;ÍÇʨIÓ"{bè݇SkœÁjõ8îìaJ ŽPUÝßôK¦>'°[ ”‹p|b5áTœÆ|ÞEä¿O©¸¾aH|Ôg?~dB_Í,¤ÙGFisèvüâ]GÉé7ìq©xô�)/Í$Û@ælG0û¦ ÇJÓa�ð+¨Ò›I:W—ÐmבλBU´ôñœO\­ ÞZÒÿnÛG¦u%QzÍ]*Â=O’³³ðN”(*ïøM¶¾Hd^’"í.v=› A–8ç\‚¦Z�Ó?Q^ðëø|2e€DxÒ�ÊëdàÁO-äu�¾uð{G˜êó&ë&ÅÁù¾R;7R´ñ=ùên…?—=e·Î? \wb­Ç (=ëF¦¾ñq‡âÉGk1¨�ŠÁ™o’Tóµ (?—cxøÚ–ç&‰±ôg”a¦ëCšÜ¥H´~û tŠê˜Ç‚AÜZ˜ÃAm{±‹¾{*}�IXÓ8 :=,¸9Ä~°Ã¤[#YC7%áŠÅBˆ2›&#ô1án ¹ôy U+@ö‚`ÜÊ>‰º©ê8¢.‰§B•ÀášþŽ‚�<—Álă¸Ýì§^õº(wˆÙœ«¨SFÏÄÛâãN@ÅT:Õ 5ÝzX}±÷¯hÃ;¹ƒdýÁ(æ¥ÿwâÖî‰ù”Ñù:�«»ËÈfÛ¹t» ²ÓéI³ó´ëw'-yùøNw¡šé,;ņ6Eè“€xÓÔw­°žŒ�À·haù[ê¶Ý“Ì_–ºGð·@>Yªˆá¿œ¸r!`â&zyä%ÙËS—CÐµÏ £9¬‰rzóþ˜qH9}WÙy¯,`¸;+íâx™äJÜW›@Äæ~‚^³Röû>HpþÛUhƒe=ùÒ;‹ãÞC#æÃÒkçè9¦ _rå°GéúX ³?–í'‰«ôÐ~^Iú8›xè˜@왽äÒô,NÆR5=x‹V§ºáhÄìÏo%-seÃÍ-´Q9û¥Ú&Ú·ƒó%…|~=ÁðIÝuF4dô *i7<–ˆ@ž©X õ—°y­h¹ä,Û·tåÜÉŠ-|ƒI¼ú#GŸN’Ñv;ôÚŒûn»£Ù„ŠžGñâOQToN¦±·@<¢ˆô.}ŽñFãÄ’ÿ/¬›~@VXÁá÷‡èÛM�‰Zj+–§ bq‰ ™º Š~_"qÖ3£ò¹/\àî^Âü^À­‹È£�Q`pu ú¶ÌăӋtÓÊnÒƒW”`­Ûð¹ØÈþóK…óä•/M¾ˆ¤ôU’*ˆèåA±f6æ|1^„±µdæŽK¬<úëÚ(„`CÎf&§»ÏfŰo¿rÂßi[ üã½{ú!ñö|3æQû4‘ò†ÐÂm¸Ô=‹þMÁ½Õp^jÄìK$íG´`ÝrMüø¬˜$œ�B²OW{¡n)/÷MO urúW+ÿ;iñ†LNy 5Éc_³,!»¶^Æï3>Rå`^Z¥Û"×›Ni›=IšYÐkh�¿¾^@’ô™(ÌóØÄ|\6ÑOu�làØÜRžEº¿ÎyYqªd¡’ëa­É[Z,°W$¬‡g#ø1(™¤'ùÀËÊÀר‹ãªÐã°f­'ÙiŸÃr(~C&Ò hÊ竤'ñ5Ý-VKޝÁ±úo4Zêè>SàôI$ñwGÑiY úÊeâÚ]öädÄ|è’–!ÿyJàÍuàSÚÎÞIïP>ç>Ü™1M³m^R“ ð8¥¬<­¹Ïe¸=dmšßaÐ[˜TÑcß•ja^ï^LŠßÝaÔfv‘¨µ¼Á톓¶kñŒm*½ó|-ðšëa¡êf,�’¤{‹51Tì ­Ù“Æn¿nÊyÜ™†¬Õs™+KûáPï|r&‹8zU�<ŒºãN\÷ �I" Pî"A&8]ÔÌ(�bá¹ R×YõWB¾T*åK¼€¯lü™¹FVp×V‘ãŸó‚ZóROorôžܹoîÚÌuG[[Àä,Qä0ÊK8나k§žÓDËä¡ö(íxHÿtYâ“�«lï_ï‰ïþ‹$Ï(%BÀË; ­"£ñlI5nJ|ö_;VñÐäÓѶœœÍ¹ºà¹9ü‹˜Oÿ…Yy¥àÙŒ0¤ËË u £Z6QøhOM³ò™ë7M([§S™GàVëªf жŒôšÅyeНæÕU(|)ÁbkAª¼ë%�[!ÆiŒeÐèÒY�k¦ûÏ£„~•9·‹4KŒ`ãî…¨|S™›.[Ë\ÿÇ'±_ôa6ú‹¯úºbl€-«‰ní#¸"O zª�!pÚ–Èðl\Ån?C¯%±äÓ~ÐÚ„a|E`£øÒk¸ bÊ_QóYœ;>RJBF(ù6ª‚/'pñ;Cf[`t´ùÓæû¾ `÷ˆäÎÖ¤¤ª†œY·×{ã„—±ÁÁ�çàVçŒÁM ,·¢nò-Èè]Pœ´Æ¦ – žî ‰m•8wáYx·9 ôÎŽã®<õÓ z:šÈÏõpÆñ‰;ŠÓÉþxìíg¼»½ŸVfÔÖÐ;Åí¬Í¦kqÄZ¬WdÐd Güþ¶‘¦mŒÇç¢Â0Ô‹Ãu�tWÉ·‹ Ì·7P:ó~d?�YkÎcì‚¢õy‚–w¢¾º.÷�<·ƒ6{lpœ†oõ€yiƒ´ª&L{Sè³Ó ëÁ6anˆ™`…»ù6rº¥ŽÚ~ŒÇ‚·×ÈÃ&UR¹ÁyVÝd6kÄ¡ö3a”ú‘ ×þÌÀ>,9ZJ¢ ݉üÎó(ÝnM¥ž<‚=ùiXñ,;ƒå@g—g‡�T L�Òpü_®}êEw‹†!NÀ³w‰äïva®êå0ôá±€’M;‘ñ‘Àà]é4ð˜4Gí¡®9\A¯¬Ð�º÷^Pçÿ›°sg€I}´‹Ý€^ékÄmAø@}9pp}ñ :ðµ–ˆ^Ÿ �K]È�+;ðÑ#ap‹ î·¼ˆ¸N!»xM $Hýþlÿ7.Ç–k°^ø3 ¹§ƒ1&‘àXwÓGßIo41öEÞ/AYl&†›Bs:§“o.^öAÅÝ3Ñ9®®£ U7½J¿ºÈcJÚ´¾b…ëÎ|%®ïëé–÷BÜá‰z¼Q5 â�6`Õ›S'šŒ+†¦ÍAôi:†xcè{IØË.Â_ŽÙxìÀ0ÝSä�U=-øÉG«t‘Åë<Ȧ@yš0C“¾ZÌ�K—E¹²Ç93ëÄépŸ †UÌ…&ËV"³;$ÏÀ.ñe .ôœ´ê¼',; \x0ެ^ƒòò†6D�ט‚‹e�W�/iË ÷9~NœpÚù«| ˜4š�–¹^dUÐ=<\Q£R¦_c Ž,–Å“n4à�$WèkÞL»‚JÇáãCuòäÙ=¼Å}JƒF[@b ‘ÚÌË%DßÒò»{qþØýø$Šý¢òŠî;®§ïàxCi©4¨ÐTVQÝóþT´e¤B‘ÙQBE´K{IÓ¨´´—Æ=ïO(²ú*I¡($™ñóûÿ>ÎýãÜó>Ï×_W:ÜDÃOÐ�£Jô�±¸@6 {‰qím˜>•@*,‡é•ÆG¸HêÍ #¦A^DfJ ºzŒ7n؇Oùa¢ Œ<¦A ÍxAÅ”r^�ÁÜ²Ñæî‰épëÎ$iÀËÔ:ß [OjA¸„+.ÉP…CíZølY!.A0ÏY㬂P¬ÚJA£á-VøÓ>pÑÎò|{ôÕþŒ�ÝɘÝÇî¹nÈõHØr_ƒÛ‹†fnb-îàûý-[aÆGWU{€Ôµ�aô°lïysym`–‚â78]°n>†‹½ždÇôà2Íg{¨ÃT;åßmaO©©r%ß;BUŸ ‘Ì”EÁò"<ꉕ«ScÑxL”|Aþ ¥·}‚è­)o|ï•�ŠÐÁNšhÁ™bÇ�¯k8‘?µSh·O˜¸¾OÅÊF%ì‘o¤/$6åž(¤5Š3é�'¹èµ1‹m异kJ%xÒ!_ìÖ ¦å)"ÁÇ=ty=Î…Û; •_›kgùš|ØMt½1¢{~_ÇÇ#VX7Í’Ù÷¬Ëø|K<¤^Cýù§Áa™(Œj… Ã‘dÔ Ç÷¸6qT™þfîm©‡›r >îÒigèRãfØbö”øèÀ31ަçRTêßCµê sæ[0™†²2“LLg:±|‰óçn‡Ž ö´!”‡QÝÝ‚ÜÕûIàÝ6šó4œ(2àÓÉÜ&ÿ Z-éO”U&È¢aúß“Qrî¾ ß–G–kãj�AÚ·x™&V7&Y¦Àêâ?�«-lO&÷ŸAQÛHØûP’lðù¬ Ì”"ƒwpÏ7UБ'ÑѸöo6~Š%iæc´>È,Ã.Q¶°OX5~¯»€=ž@NV° ­$Á³D˜`^ÎayÎï &z¯-¼]·‰j”ÂeW–0*q€^õ‹À)w:˜G§Ã!3ѧJ€ÓÑø‘ödgÀÇ€,쬠#¬�ÎpÔÅÙ‚[ÙÙh&Æ2Ï׿ŅÑÏ 6©‹²X¬ÕR§§´áÚšcdí¥½ðÛ$ZÂö±´Ìå'³eþ òœç$\z¥ ûkBÀ|”èk®÷!H<>Ÿè¿ÄzÕ§þ[¯­…zYØvíÍsG7E íê6öÛkP>ù˜žøø Š6>¡+kÚéäÍ`uï=-8ð˜t±j`fCTÎñâLmeh;ðÚð•—"”ª.¥_·¡–Ë4¸]óˆo=ÏüꈇC¾jxuPÕ#ùÖàµóÔÊJÊ/ÃîÀù(µ5Vœ‡î9¸fƒ äÈjÃ’¼rãs„ I²›ÆØZ3ÉY�h|4ºª¿bšò÷£h£Œ�0ÅvÃuŒÍ�2òaÆk:9| ˶D3¥o IrD Îî<�Éç+ñ€Î*aD¿o :Ef„çz‚Q²ûA(L=ƒ.Z›àO†Dp{èÊ60Ùùïì$~!ù…«aÀÜ™ÄÛæÀ+!L’WÆÛ¼¡TØÍ›ñ ,&7e½àbкÄY£ÊÀA „g®[q™¬:nÒÂ/í7¨žÁb±î ¾r©EÅÝ[ɧÂW8˺�¼=w´b¸t»· �æ¶0[M„áxhä%2sc5áÅì§ôRÖàmíöp”Ø.ÓGçà‰yU�Ù¡…ÆÖ¼Tã`â©"�4~T‡Â™Œ¯0kÏrdrFHô¤#|Êib BdɆ _¶d‚öxÝ­€*4ºõ•ëê%z«"Á…fÒ°Mf˜Ò¿ŽŽS€�W·b±_9üjÌ…¾¾â.!‡NŠÉ”¶)0 ¤æ]#µÿ³»‹Õàì\+Ý{ŽîZÃiµ·†c†V(4 Qôé;ÕÁ'LÇ]Oé³;5(j'B„g0W&Y½W�pÒð©÷N |¯;‰ÈŸ+ÿüIÿíÂùtÆJR ãwC¥{�T Ùç÷ÙBrT5ûHÓ¯Üe©I?µÛO×÷Õ1O缂åGMp¹r0†Âà'¹¤Äc6ëj�ÙX>:ʯ`]6UÐ/‰Ù˜Rú ~XÆP±r3t?wŸy²Â�Ù1‚ä…&×8‚ÞðžC‘¿£Ôºµ€Úý©lîÛòoïR´àšûyò¸Ã VûL#BƒéV¡a²ÇƬ®Å§§$ã§ ª�¿£–­Ï ÆÆ â&ájz »XéVƒ­MÕd-®Æ¸Åx¾ï³)H îÙåc�°1u—\yª¸æÈ«gIä$¢�‘n ?Ç6jÍärÅõà®ÁX³»�08hý"å<ï‰e‰ ÇñìP¸ÏÁ;£©áÙjö‚ÏRH<Ç’úšãøÅÛ„TšomnÔ<¬œüA×·¾¤wVþ¤—âèAžTVþ¹ö^ƒ-ß:1€ÿ>±0ž€Oò¢t`oÅÃdï÷¥ôE•µ]‘�¢-= 2Oæ8®åΙ�‰ìƒ2C@ÎßJBéSb`þ-ªne0 ‘Õ(~)¿—_¢q'ñÖHfŽ4Kí3…Ú¶3¤Øµž®Ðøf,îä‹MŽ0FÇÞAvÖõ½�;þ[I>²Paw%¬añ?OÝfGßîl¤;EÙÃ&7Èœ™pâ×mj&-ODBlHbŠý¶ó³¬Û—¸™¼&…i«ðÂÃô«ó,ŽÜÞLPkl"Ð2 ãå/±§âÍðûüÇh.Rˆß—¿gx7‹q³$ær_¼¿IÞݹDÞé—Òõ»L™ûòpû¿Ú-‰á†éÍTæ!JnÊ‚ÊÛ‚šö”ÜÈüNì�®Ã7óe'§Œvå·ˆ`‚¾^u›~}%ë]¤éVE#osdÖÿÖD_kCªte4üZÚ¡ÁÄ:­‹(HÐQæ6ðèbÛ]5"ýŸèýë÷#šp$56F‘÷N�£ô�)=½“|ylÚéaÕ}À“”†>áÐÁ§ l Åé`´À+ª÷�ÊâÞ_áX»9J²¯¡#[É<5g?M‘K†™ô+ÿE£wUY¸"JwÇôÒË\HyŸ$}ÐÃé3m _è!.ò]�+>ÌÀbå"xs&ÎöoÂu­[Œ¾òúÓ\9*k#J5…ìð��>=dÀ¡UóHõÍ�4le6óhãs"³r¢YOÿRxT‘EÚ"úhѪ>Z¢�/~³dƒ¹3òÝ~�¿•ˆâ®8&t©=˜µõ‘êHhûâM¶Èðq/üZ�ËÔ¡öSY™ø87ø¹eœ˜àS… XñüûW/ €Ý'‰ØÏSdæ–k¬hž'34OZ·þ ¢ûøø|yÉÿ°¡¨_,ŒÄ×ÛÇÉ�óÿZ%·ßlÝú*0r}ú—­¡Âÿ­Á‚Ñë8¦¹¯6Èáñ�|Òã,CÞŸßL&öŸ„p÷¹ð·?�´^Í ÁÐï) –ó9¥‹\AÖÙŠxÔÒ¡—ÈÑØ#÷*¨Ëq(®2�…·K¨*³ú[äÛv UG£ÏÒ²o?‘ �ïÑc¬é…·yèðd”ݽ96o8‰ò+§7±ÊÔ�O³òËiŠÎ ºE¦¦Åy`UÀ+ˆÛ"NÎdßE¾ùPw.Uun`ÌÄ&z—WU«¥9ïä½ÈÚ]®@Z£ ®VÀÆU°ûJ½{¿‘¯î‚)�ý´nnuX¹€“2–SCŽ-À�"ì]úWÃxôÉâÁc욃õd3•ƒb‡^rH¤ ÖëÍáÚéÜböšm€õ_®’ŠôyÆ#­ôˆ�.LsþBŸ•‘Ô’ºøÖ+Ò»sŒg÷`NK!¹ÿ¥±"!¶|y1!🠓Ky`¦`IÍ‹¹ËVáé¿kHEt2Lÿ[@†�Ä/a¼#L ´r6æÂßzü`öÉ´êö@mXnû÷Ž“`œ/žU cØÍdJ± £D)™êgg$ß#éÓùpyòej¾0÷?;NÃ$ hxðSêþDšu;ÚM-f<§IGÁçS4N¬ÿ…'N#úÿ¼8W¸…øý—úhéd2.÷ï¦:=¡tæ o<¶5Ò?ôÀ¹ÐëøŸ¾ SÃs¾=–á½C*�ÒÀòëP'öš<ëòÄ<û\zâp=µd+ß2E?_¦¶{'ÆóÚâÆühgÎFTg`ìöæ!„À£Gøu0^Øæe�kÒP´g€F%Â{¿Ò€/tÄ6¹}Òœ˜¿yð¤&Z„YøšßŽ=ê qT89‡Þ1n)º$qÉK’ûÌ”¶ǶРv�A,$v¬Â’¾ �{’ rÑvöµdb Ëf·Ç¸iûi¤T9c‰áX ùo¡ñ8‚‹¤ ®•ÏÅíë5 2)•¸6¾…sYdC¹ÎÉÍA级T^6æ³Eåv Ü®**#A‡å#™©´&LMºÎÆîõÅ·½’¸Q˶Ï.A§×”†¯È£É£aWâX[îŒ-�Þ°Fÿ†7›cPíl$~“Ö_Ö":¢âȸûO:µsü–…æ?|pi¢¿©8þ•²€5ÍvtèE,5üSNmBË!/~)MÿeM=Ê/c¸ò(4"«…R‰Cd$+Òss‡«ÁF¦‰êµLR6£Í °à×j Rl'³õ¯3˜1â²\ Byp=³ƒ.LÚC#ëÑÉþ#T«[àžŠ*ÆR|§¦#­aÐ@î�ÀÏB‰àZê ½rTmÑl(~…å*…¸Î-ÍWå¡ÉÍW$k´ ²®ÒÐÜÃt¸«�XÝò¡‹WSí}géÔ£~à‚K•z�‹ V£À¢9°VlÄ8ke61O¢± |ØSúØ�6úä£)Ùž+ë}i\Éfòe4.¹íl’Q@ý|Þtë7דô¿ó±]ç,^ßø 2WÄX“ÛÔÉÁ;¾ÌÀw¶ΖB£í¡èr$�Ü5ªÇ õ3ìåôaj®so[Ð ‚o ûÄŠ•šÉìÀ.Ôÿ€—µþB�I eE�Ú{�¶K.E�Û‚Tƶ•¼vÂõmÆ\ïñ<šÕs”" Ð~>x- Çi§þ5C¡?¾mºO×ôcœ[û¼óHåd©etNïNx7? 7׎‚½/Ì<4“õp> Šbv]”Ê-¦§w¨Â¢§�˜fbd´<µ‚ÌÛ¥Î8ÝE}Íó@Ht€œQ•DSe'ÆI?_¾!‡=lAÞ6“±öÍaöÝä!6êè'%®ýøš©C‰6¦¶2"ª[‰‚5Á_öÜ`]9‡wLyˆ‰×jÒf4N_úÆ€¦X&F—�á€&—_¹€øú8ÒAÉF’øšzÉKaÜ‚Ç úc)\¯_‚]< ³]WŽæ2±S‰0u> ß.�ÉnêÜFš$ëðäé[?3‹]}ù9äN‰p,,¶âäŸjì÷x‚Ê‚>4;à4µÐÖEžá«DoÓyZÞ™0p V~9H쬦ț۷ÉûÈzR6|+Ïü3kZvß Â™ú\¡ãô÷E=-gÖ•X‚6¼ }›J—¼–ÅC)¶ôDßÑ`óWJ‘uû�/¡ægâ¦7g©ÌÍ› <]ò.�ÞK£¨Äû‰úñÒð]G!ûÛrºÈ6ÑX-*’ºÿs¸Wd7›|Þ¨ˆ=}»æº©c™@0½gPJ–/¡Ö‡ªáãé5ä·†�Ôèúw6¿°�%ÜÉÝLì�i`¾/Uã(ÉÖÁ »²¦ïs…`§¶-u@o9nRÑuÜY²êŠ@SÊrLJÃ5Šrfz-~òröiðqM¶öÑ foIÜž*èØOú2‰Ü3â0qÜg\Æ}Zõðyöz“ëŽ< þÆ5›�ÿ9¯t,�Á}§_´eN9ñQK¥N)�Ì" îS>¢»ø8×5\ðŽeŠ}œjžE¦È¹ TW "þ[À`Þ|¬^æsGèæ>À¦„ÕôŒ¹öé9§é×7½tî踆Òu¡xú¸öOþGc,®³¹’Ó8w.ŒŸ„íKÈ")йzµxi®c³É‡¹èµä7ó¸=ÕøQŸ$5puÃyüÝ$Þñ2iVíDAßÇÔmÓ:¼adŽV.EXtb;OŸ‡ë¼H—œXP †a¸mò $µ’¥*Ìè}I¾zo&o† É):˜ì„ó»DU pcéYP¸LO ¾óœÌ“Õ€5÷»ñö×ZzTÈs ÿ¹¦—»›·7g< ¦zp¸7^ïhb&f_%¦·máCÌ ü½öuQ-¥I|³@lÖ=rmÂê6îyÅHÐo7…8pxüÓL_£­é|ˆ;�J¤NM‚yü5zW-’>4¨ÇmªÊ(|J€S[JâŸáÇÌlfìÉOj}U�,q=‹æ%‘xÃ:œl{’:kŽÓÊ„2{‹V/ß³75ŸÐÏÛadK'±”pÁ²X%xŸRÃ>>~ ÂSÖçüv›Ë¬–Š¢=dªƒsOÈll/•V3H¯`‡Û €OÅ ‚6íAã¸Ëäµ`<+š�M÷g`¤³n<–*§%`§U:sìúüÃO~¤àö<hîÝCžœ÷†Î;¥ô�E;þ½Ò­ð‹TÄÍ +¿î³Š´fmÒO†*xù�&V[BŒ´\BÖû4çLâ$¯&f\¿FZͳŒÝœ¢ðk\3Dÿµ•ðn}QGuÓ IÀˆ?¾['OŸŸcFD·�ý–Q¡ìÙþs�5.DnäÚq½å·°»•bhg£<}7�Ê—B÷ïj°Í ! í^¹ 7’-y õ<ÄÑsž]! ?$áÀ,/~>ŒZßAÖü%/—¥LM)þ:ÈB‘SµxÃCêš–²ó– ‰Løþ%�±Q À›ÓÔýÁ�fKÁO ¹ø ÉX|zù(™«Bq.Á£i*_uÎjÂ}çÄn« G]3ÆÔìèCgg²oö}ÒZ‡¡ù•°Ï¡Ž½!dŒ¢°Ü»Ž1:ZÉQåÿÖ4ℸFy3%À‹ðdæ|¼�÷†¾µ¸N–t¯Å¿¯ºP*~ŒDï¤ ªñ¿‰ï$Hà>Þ¼-OÃJä‘«„¹[�cf!VhxÁÑÿÁ�mOŽkã­cöE)¡­©ÿZ¾n˜ê>š‰¸] ïñˆ y³£ž«sg‡æÐõëgâËú fÇ 'äj[bÞ¶ExßÙ†1Û¦�Šì~Ú ™Hü]ŸADâi Ýiôâ�L²#"’®­öFßÞÝÜ%�|„¾Ú ™Y8Zö�®�‹!so¹Â/¿]F�T~˜¿¢ égʼ…cà—Ù õ• åK†Y“´(ÔOÆs5�üTYi›mÆ–�.2÷R{ÐR÷Ä?c>¦%~öh 9F�Õ 9®†»V•arÏ&èÕ~œÜ&Ë\È®Çðµ IµÄ4xºø LÙx‘�>9°ß°4MõP×È>:C�k3|>A\{йº·h[P>æÛÚà._G‘|øfü6~i‹gĆÉ#N6|¡ küÝ�1 Ýé¾T»c [å`Ƕ¸&Ngz~!Áš»IÀee´¯Ø uY’͆¢Â–YÐwJ¿(>\8O¾í-c>ùøáûû磊_ÊPN§Ž{žr6d&´éã7ú´?ö~KÇÖC)$!›ŸÈ5§¯e'©“ž]?ÄÈÛ¬Á0Í ¼å‚m/Î�A�y¦â ÏB0¼-I"W#S S7X³æ±ÚËz†ð��,‡ç\ê\¿Âðj‹s¯osÆoµYpwÿ£8fŠ›êR×ev¨oºdw˜±ö¼óHr¾2ÁõA©h“O§Z ¼J έáˆ4>&geÀ4©û$~šUÐO†cGV0iKÎáá¢sXþtÿ<ÖUÿºðÄtX”}™|½G¿dLàƒ1uN­·´þxÎþl÷WžðxÖ%ì÷šÕô-l˜ô ïÞ®ÚéN„½æBàKÊt<Ò¤ òêè‚›’¸=¾–v D9}Y(3�s�pl?~ƒÌ[q ÓR©x� '£*4žË‘Èî<Ûˆ©³¢™5Ñ��ù‚á TØö‹¬ðú�~_§JO~"KÞ³9×E9ùÎg‰ÃÀ&rº6Žþü w](nºð”‘�UIÛw6ãeãp,,AüÝû˜ºÝ"æž•Dv¬êP �K¯0±bœ$¡ÍtÎu-!,ùýòè¶¼$•%™øÞPÔ­¾Áº¶`i? ~¿e¹•Lï/:Ö"‹¯ ÎÂ2¢¼õ·È´{ô»³›ŒŒ~*À\zšÜôåÇ^ùzÜbéJûío`í7î¬Åª Ê{˜Ô; q5¿o˜ ;EoC{ÈwvÔj1þ¸›WßÅîBœl4©÷ÀÚþ$zéÛFÃ{�éY$×w¹× ôš‰,…ýoÉšëÕ¸ÖÅœ¸¸ï@Ð/Ç ‡xâ0Õ†[Ú–ÁÞl>Ù ÃqðW´ŸógòÊTüÞ5Û”àNû,—h‹à(X\u¶ýWJüùÖ”¹Ï‹¾¹Ü@þŒöѱä‹Ää|0lè7Dg�„fžƒ2¸xyŒ¨.Ãrî Ô˜8ÓüÞ‚�smßfTO˜‚´–+¸hU8 u|ÂŽaØÙÿ‘gHs£]íQcŸ7W’/«+àõɲf—Àô´Òá:v¾„µµ¡ wð^‘�£Zkq÷›û ®dŠs"R@5LšÝÂi�Å ù(ÆõÇyær¯ÿýLŒÌ%ûK)LMÙ 2mu8î=eB¯M›Á٫扭ÏSðg+3ƒ8q6aìÿÿI©ü�Ö…ÃÙïH&ÒÒ1çŠ(÷•ýqj*¹Š#♿:¤œÓkü yŠM7‘¯ö~DA¹ ³Ÿµ£é’LªV¶˜“{åT�¸ÓׯfqvÎU`Së¾°cÆ aPÓ®òÿË?T{aõÑNk^7”$&hžª fü¹ +æ÷Ð2/]� dUS☇I#X!P�v\ÃO¥DãÈ.ò2m é%Æ+šCÆ_Òzþ)ê7º¥ø‡iû²˜•#ÂÍ,§Ü›z¬�å4’4†Æet^„ ôk »ø|Ù»¶Îcßë”AHÚ{¼¥‡Åóa“C4­Ì䌴€\˜þê« �Í‘`ì"À»ˆÙ×Ò0q…,±˜s.¾£¥‡œÁG_›?¹àsó0%˜Ã ¯¦¯ÅËð“H½}ÀÇ{C}I:Þo¹ ýªØqö.­ž‚ú8wÛgÏĪSŒoÁM�õøFŽºúK€ÏwŠ+šCßÉXŸwFX(þÂ>>…5 ¹-¦‘4De¯”¾Ç½{pú|`+†«Å“¨ÑA9ò,ë9,»®‚B\qãÙô‡µ/~|wˆ¥ÑØ äÖ%8“û“ üJƒ—™Q·¡˜TÍó@ŽÝYŒG–Ü„M/-@#8Eß4{OÅÃŹæt¯Š9I{(ŒoÚÜñ‘—+Þþ‹†¼»NÒ·áÀ- K¨†ÅO&Ø»2qÐe)�j’…¨àÙÃÔÉû2¼Ž©`1À‡1:—1ÿ˜·wûLŽÓiP–R’u ¥‡ �›,ɹZ ¼Wbayu¢Ù�×�Þ'›�MQýb1Õ«àaLT뫎¢•z%•ùá�v§‹ 3ñ!:ª]FŸ߬ÍbÜ”%Ù_qëAt ½Ioòn²�¼í[º2ÿ‘ƒƒìÊV�îàPÐ Gÿ°]hb$ν�²oO‹Âà¸$¢ù`ŠøÊˆÀœµÉÄlßcªP¢«ƒ¢#ØS_Xy?žíÛÀǽÙú¯wžm$‰aÅÆ6˜Û@.4¶1ÛÄ×`ÇÚ­0‘³®…Í%¿›Û�CÍ µHM›€Ó�×lOÝïâ‚\ßYéôÞMü�Èa#èkë7Îõ*�ÀgjðùkÔFÐÏw�3šó%`ìa‰Z Ù~\ºæ†(„·PÒªê‰iÛý¡Æ2‰‰�ù‚µ"ŒÙÛ(Úds 7ìä_!ææ¹äÂ�ç `ÒÙ|¤Ö §ng8òçñËÒX>µ?4¬‚Ä~;ºûÆ æHÙöÆ%ypÙÊŒÿåÅÉœq¶s_RóÈH£¾¸D/S-/%£U‡¿’ôST¸[ >òèr>0©ô®Yï8sØc?>�ÇYçæàÇg§¨Ú¶ vÆÐ3-e |Û©Fi`qùävçQø¶Îé§xëÁj0I—Äö®°çf+Äyðq.\±ÞoŽ�°wŠz?þ@ú‡‰~£‚.)Øñ¼³¶—A‹K4}¹œ9yÌÐ8'̱³§ X©Vü› ¿Ÿ¡©{¡ûúr":.ˆªtb*ú=�‹Œ‹CÞ�º�»`ü¿DÔ4湑Fj«Lwáþc[°æ…pŒJÀÂQÛŒ1~¼OYñß¹xõ¢'tk·R½¬:ü<ÄlÞÁ¶ðg ñp&gÛ±%¨Þª <×ê!Æàkz&é°XŠƒ�úÈ¡Êå°që3èk–B¯cõtÏd€üÓét�D¹„+÷“ÿv°3pƒR~#øROA*ä;²»òHrA$½¥$Ç1=ÓNÖe,DK�b÷óñ_5@W ‹ÂŠ}»HR­,1áAÛ/Ñ€?�ĉ~@—²7LhQ .ÏXÌ^êÑA&é#ëóðp¦yü�€QŒÞr¶j ¡õ4v|Ú ò9tØ/€Z”è£Ë‘2ª¬$ÀùÕ¼†Šä?ÆSAˉ�]ý]i ÛVÓGI øqð›m„ê•N`{j˜ùÔ,ÌJ8Mçž4``æŒN¯B±~És¼ø´žD_."{öÆÒsb—±I‹ ’ Ö:“:¶ÕÁÔBOòDvÎzkx'i Þu�é§•Ê8÷=«5äÙß]f&$Ý:³ÌÞÁ§Å¾ŒÎKŽ¿ç$È»å�ð‡›A_#Žˆ½ÿÊÌL¦ÇþÎCÁ#éXUPÞOë˜U ÉFýXöˆ¤ÇXü³Ì[*2Ó&¼G™™‹÷Ó�W~Ï®¦c.çë†g£½ä÷Á<\æ¦ «M0³5_Q �S°ð>E�̇ìÂéh¤[7Ñ‘ø^<õ~Š”ßö»ÀϬôÜtµº€éôZZoÉòÆ.ªr¢ µnÔ›yù`2/ˆ r“¾óqŸoÖÀxÉ ”NžK·G¥£‹é9ºå{4¸µ¾N…cÎÚðÄ­Ÿù\:Ú§º©oi4XÙß#ñ&&ÌÉão胅6\ß_©°hŽ ¼=û W‘ÝÓ‡ˆüû;Ðc÷�–ÄàÂ×™D�o%Ýáâ‚ÚôÉ*E_°Â{$Ô­�Øn[…³bWržÍÊuÝLòé¥>yÑñv¿´¢ ëËáe~Ä�ÂÞ…<8ྠxã¢@¥zˆˆÎÁ{`¡F . ¢zÔÐ|Jœk"“Fêž%п'ìÛäÃ(<¨òÜhtºfn$~{ aâ€ÂfCølM§R†Ífq–1ndÆx(#‘¨‡úÂIøên1{E´ª<ñÉ¢›ô±Æh•~N"õnQ€slIÈY¼–Ëœù½…æöX€IE Sþß;¢úc^ºégü¨j+Z×n…´¶épw÷²Øé.y®ïŠ+‡N3fqßðÑËÅd}ÜÒùèwá$¶õ‘ÙKíð)›e,8áN+{^Þêi�Î^!k¥ðê}1nk=ƒ%²39ùP«ð‡h³*‚8^ø�DpŒPD#ê¬OÁ•u2èв ®f…Àòʸgz¹«qü[#݃'†!>χ‘R€ÉÏÚXéž ·\ ÁµÞ€ê/bk_î'òŠcpl•îøÒŒCû°Võ®æ #k›*éMÕ0Z¹ß�JJUáìS´uƒ,x<Ó— ã¡…¨ß@ïäf¡¥£#ÅÒ�Z‘¿É²Ç HØŠs°HËÖ°wÖOºãÂ4(j[ ���ÁúµÓXã{:l÷ì7u÷øû�7ó¹ähTdWèEû9ÕME£õ˜Vgl-'ËŽ×?ÓÌ¿ÆYÏRÈöUοtšuì=öªÆ“-ÛÖáy1UÐÙ"ŠâZ©“¤+c˜†ç-…`Ãä(¿œb¼È³“ãåI ÿœ÷É•šŸÌAuÇZüxä8‰j(¡NK_ ¢æIÆÛv?Ü|S3R›!nmÃEèWjÃe^¼Ü:Íeéàâ’sÚšžw»ÇÿÃÅFØÉ×AWjo#.ñ2ÜÛÍ ¬ '�ïÄÿuQ61œ?‰jòs`z´287nBéòUP^óޤÏñ€�ó˜e¥µ¨´t!JÍ’Á¹‹ªðJ÷f8:ш›‹ qìSsT;”³b�Ûm2µr…Nûá=qGиIŸLk@Ûš“´~•.}y4 vO®á>{y#eo �¥ µŠ(À%L2Jz©ÀŒŽNð=RÅEðóu+{ _äÊ¡î(9/À©ób\ü¦ÂÕ/æGñGÊTVôu12ÇÛmóø"5sÂÿ :ñ÷·dÌø[îséaÉ0mõjÜð¦ù¾fó·Fèzj/Út `_Àh³ß‘T*êØ ‘ǧpºЧü»iù¥Oä�’4×Ъ˜Öf_5þ3 Fʦȟ¥ŽÄ×£‘X�ºCßÛW¸I= |Ën Àp-˜‹2™¯¡#•†>ß`;–ôÒi3|ñþÓ@•÷!ÉJ¶#Õ—Þ°>*ÃЗR£t” l5Æ^©B:FÅGê1aZ(#³žJxï½s¤§�qa(ÍxxÈõÓ”Ÿgd¯ÄKñî€Û¬áø )¼òÜ €Ž#ÍÇ4ž(<=r9à'£ þ-»ñ%ß7úùåŒë¿’�§è�2ÒÍ;Æì|•ÊöyK“®ØkðQÁU„³XµÊ��À7›è&Æáø‘xò^I áU«Tð|´ü–ïÀUÇÜ0Ä%€4¿¥]q%8ÊçDs×]‚•Iß%À|Ð%ÿ-�——4‚æôÑ•…ꊤ¶ÓÆ“{ yƒh„e�ÔuW»LLÔkHGâ* /2`UŒ†Y7³ÖÕ¡\ðrMœnîìc»^VÏ:fí¸6zY3QóvãÐ!5¯¶{®Ì¢ ÖÅÑQ×TׄR>jàzK> €d—Q>ù5>/cGô4�½kAx%/Ò¶Ç2\: CTáºb8ð,§{%”9‹Î²Dô„ <‘‹ENæ2zw ó*ùÑÚl=æ×S£D;øé½ ž8¶³‡¾Ÿgn¦ˆíM°�ÆÇ©ÍgGSÉHJñØ›i‹A}à*d¼Í3ÑiœKO °Ã3¸›ñMºÊ Ñ5ÕÓ©Ú´ûìóå~(å¬O—+^­�ƒ^&à'TOßöÄ“KªÑôÒd+*–uÒU§N’ ·bF}è-såP% tmw-‡'wÉ�.ÎÛ�çpþmc¢—! ×ùQ(‚ ÝÏ4ÕŸ¾‚Ù6Z�˜¯Œí8¸U¹�¬•¾Ž++÷þ=[ÀÕ¾®'™ �òïÁªEi˜§‹óPôFp#û0hw Þ³FágÕK‡Ð$W·Iðy#4Dw›g¨VN§Á|ÛØÈ q´(}M#NÓ×M½Í‹âÉ2Ç™¤å¿9°ðÐKÜg #Ÿ 1Êc€Nw>ˆ³–‹°ÏN…Aïq”ž5A⌥8âpbvèqüBÀþÏw+<gŽÛ‚Ëí`,;|‡þü>‚ßþÃõb�Ù “~`+º•Ši¡«8V”ÂçúIpµ¶EÅ Rà={qó­�âð.æ'ºzl„âGÕØdcHöçJÁ­Jšÿ:Ÿ\½ºä›¶á]w‚»Ê¢àº{$²ÿ]a¦:J+™¡ñLÒ³;¨í%´Ù£ˆì×éÎÆ1âïæ½ZÉñ—qïÀ Ðí4À#â÷`ï£äÁpN.h†îUºÞxÕ{Ü¢`<­ðnæYCiM¨Tž¡&á¹�ì¾ó/¼Â/±G€‘µ‚Ù·‰£¹æ?ˆ?®e6GÜ^…!ÝðeG)¾ħ5ùä×¼cUÄKž‘‚eÌ ­Zx[öˆŠüìÃMßÏ#[¬îIÀ›ªœóÀšiö öÓø8‰F–IsçÕW¡�t™Û )ø1Ýȇ·†kíNàò—#"³ññ×DX_™„çŽIƒKTÍH×Á(/":¸´nÉaÚ¨% !Õ3Š™×gÍÖøGá¿oD¡Ó×ä�c6, ¦µš³qÿ AØQ1IÕyëè0¯V5E¡~¶ Wcê!YU"‰æô4ÜAªe•Áp ÷8GÂÀó r'»j@q×i¸2*�Fý éúÎÙ�´%9ŽÓþh‚¦Ä¸x´ŠN‰ÛÍåpϪŸe„ÀΦ¤R9Šx+g±ó—úà M2³+~=íÄ­é‚\µ5®$õ@9å÷ž…ó‰1.á&XÎäø™´ß�¢’ Ž´Lb-,ù`M-…SÑ7ZŒÌ×$r,[–îJ¦GæÕ1 oG™Óœ5èf Eˆ],99pŠ1-T…îV°tc)c{ÒˆëqA�k¡9NžJ"Eóûe0,–Žç÷÷óüXžÄ�ÅÎ z ;CÒaãÁ�TËõ 2Ãa0V³ ÏÎ΄¿³ÙÝó-0ÿÀ”µ¡Ö¢Uè�O¨åxgâ,¶ xóèæo�ˆ»äkÂõ8HÛ ·àòÆR©³y–©à‹�Ó@,!Œlèöeª¶Š¢¾¹0G(§w^Gìûçv9¥t6xñü"´‘h{ÐùP9“ì¾Ì.ÚhÓsXÖñ´ÜÞ€¢?¿-ÿVÁRýôêùbjcŠg¯™àá q0¨|—妢b[ ùŽAôog&;óìþYŒÊ>óþ9ç&íõ=I÷þ3ÊõÕÞ¸z‡ 8ØDadM lrì ©ƒ p`d!�¼+‡Ý©ìúÖ—øó‹=¥|ˆ>/‘�ÔŠ �“²E!K}à6çS»�Íø£¼›¶ ŸÄí¾÷Øx(¤‹Î;ÃÍ‘¹(}t •‚)UO*\=5â�`‘B)*\cþGÁy¸sý½a\dfËJ˨P’ø¼ÏóimTJKEƒâ«Hdï™ÈŠ™Ù¼Ïó‰”hˆ’²C E%©~ýþ‚sžó<ç¾ï×u�똪¼Ùsê¼@þêzzË7’VrÂÿ¶Ñ�C‹I܃nºK[�ú¾yI$.‡eö ¤�q@®š|4‹‡#Êð[ã ߃ç±èâÙ2ƒöîÁK{÷!U©f¬­r�¨©�p¢)^œ^L9ѳ!ãÅüÚA¼‚�Óý/æÁ¼â«$ðÍ"¿ Þ«¥p6ÉšBlAð= í9[±¡¯ž¤Æ¹àÖ‹‘h0„l¿ŽWoMé·ó¡/¥˜Æw9’®sUtkÄ;²xkh•Byõº½ >|>?.=`flföÈáPPíù¯Œž{ÁÒ—tvŸ!?Î7J%uNFh)¸“AŸÓMðx¢I¶Áø½¼žÉ¹·JÂ4p‘Xñ=·Gª…¸/•›ðKµ%ѾÉnÕÕÁcé$YI[7c¨2º%§a?ÉŸ©»É Ç r@Þé¹£î‡ÝTÛEšW{�2UïpÖ†ô‰šY¯Ž`3{×½=ÏÎØ”#wÃó* ¶ù*üYç@ó{3¯Î¹’Œ²ðÊ`¡Fj•ã^EÛ§Ã Ymœžü‚V’¢†Øœ{[8y(È™�Î)žÀ“‹’B^ÄäúMy%�{ŽXÑ�ÎGYIÂKÞC>íV#ð5˜,Ú7VyØóUêYŽw¸ZèÙIPbÖkÎÄ žxÏrºÇJeÃOùp*ýÊŽ®<€?ohA|à\¸oÁ€jOI?AîÞþAï+òá yÁª oG˜ÿ<©ê¿'ܲ]œ(1�s?�¼ $}ÑÔ†]�î9ZUk¡ˆ©‰û^¸€ÀÀÆ|²ò™õ8®fNKq�B Dí�‡s›QÒv!5{xsŒ“8H-ç‡Óõћɡs+ˆÝ™:FUډΠñ-ô"s¾Ó¼u¢¼+JÀ´>wÎ܈�G�ïÛ±VÆ’KMyG9Œqä‡î´K5¦ê'’ÈØ¸!ø]‘¥+ʵ ÜË–9Ha]ÜF¨ä¢›ÒÕcøG¢ŸJLJ¢V»e‡.ÎDt uÖÚ ?'îÑXtÎ$íÃqönŸé-êÂ⼄9DeÞ `YÈš/YC Ó8è6žJ¿^hƒ#Ý/Ñ«l!¼áeÃóðs¸Ñòy{à ãGÞ‚�Ò ˜ýî)Mù’ANlÆàÙæàpt3µv~O7gB„À>\OçÁÖï±°9á’%}ìô=¦$EéŒ:N^ÈhÀäOm¸×ýоúj€YêgÙk_¿Pã]-l†¢ÚeêÁöP;L¼7f»"Dß$µ.�4Äã&®ø6L%†+0Q©±jÚ�»°û$’ ž×`£«9É„�Y•yðŸ :ˆ$ÛÝN´å9>Û“àÆÝ(ùb$‰dл›Ž0§JñœMN‘ ±3Þ4æûMêXz€Üy¬È*®…}* ‘ã‘o�Šxóú\|ßv;»ÓhÝ•"Ò3k‚qÿÇÎ’Ÿ" Ì©™�^*2˜Ïä¹Ý¢ ŽÍû3rù@<ñ�ÐÃFµ$²Ê>šMwäã „ [ž»�à%vhþa‚jnm¦³ßz�Y¶S±WJ´êÛ\Õ“ñbRuȲ~­Ú‰ÆãÖ$`t¬÷/'æ}‰Pý”¦Ë¹Vn:²„®­Åh¾mìì%û1Y6–|§²rL1ëŒ�¡ÑäWj )—ØEß[ʃT» òXs5³Èu$9ùvpK:ÍŒ!Y±_À{¸rÔ…ï‘̧ÕDÏ÷© òA¯\O*—ûtO ™qx;v5¡ì²çh}l´}¾Ì�Grí¦/(ïP‚ÿV¢:Šßw•àÑàä¿ÿTɬdV+ݘuj!Iú÷±¹H ‹óÖê«’µß¶á;‘)ø>(€dËàö69hû€‰:½Ç|s gm>[‘&Æ�ôªÞð£ãÝ!ú7ÖMØâ�¦MŠ{·Cø£1Úul>þþüoìN†»ÊêÈpÜ`Eƒ'Žk œe%õ—+&ûÅ( ½ rg“˜ão9¨RáIM×G‚ßê^Îa.^cö—k’å:Vh±À™³,Dmâ^Pw=MT�\Œï3¯ýÓÌdÕ¾+ðHNãúÕ¨x_.¹ëY'ƒ4éQKoL›? vï !ÑØë9e8ã+ÅTT¸Ó³ª"p7 }®\&Ÿ{ÂiÁ³ÓŒ+nD¹€Ê´ØCÌ…ÿ`í›Ý¸1BËŒŸ‘Ff -Æ·+¦ÃZ·… ––�RM¿8»“Pòø7Zèh�¥ÿPÓ5wÈ©k·¨ÙÃV=ü"šMI#ÏS�Ñ,s *{äá¦øò×&ð�‡¦ˆà×3n„ÝUH¸»¼˜‘,âbEê,­!ëH$ý¼´ƒ$‰(#‡�ÂÚF9²Ï¯Î§ÕÔjHƦö°&®n¤½à k�ø²ÊÈ}-N·×¥Êƒ ´ N¡ñV]Fll)˜pËñhñr+6þ®<ñ¯u@ÊWÃÚâé‘cwpdÍ%ºRyœ½p™ŠË×±AçC âµ”=œE¿ ©\]’Lûo¯†WÒ{`ÿLOìS&)oñ+fr7 ôèŒÐ5>œQ‡ÂfðÛ-…Ü=_�§V5£S—.ÛþA6D)Áé€1*þÌmÚ5ËÑrE/1©+`Œü�Xõ^¹ ÔÄþ cz)°¯1”>:§K¢dtÀͨ+¤GÕ°õTT=‘\i"éŸ6ÒA£X:"≚<Z²“ò°¤×‘*V¡ÍΩؓš‡)öà4š@ò¯;âõ\® f&oÇ·Íì“m%¬žÌ|R›ê–�ÒøcIŒWÑÇF dд˜¬3~ Ÿu7�mK‰Ñ²T° eQö¥ ¸p³Ø?É¡PÁîUÜ sƒŒF� Q’u#Úýúh6ÚMGšÂ•3÷�“®Ã¦Í üí�x`ËZ‘ G›ª%€òAƒ›s°ì•={r“$&ét°—�Ű’~Ã7^θ�×CøÆæ3Á¢ÖäЄ X›±Ãv±ì ŸFælùEpõU'å/¨F† dÞãÃMÊñp½Ù7®_ȳR™YeÁ�ªXœ…ê˜÷ä€^(´ÅÀüœ ÌŸ¦48�øÔ©Â¹A3ÚÿI{¬$aRV—ŠÝ]Cln÷ÓöO±Xú'µ¥`°äqM´OÝóìÅɹ�¹yœóƒ¨ÀÚaL9¼—J¸ý¤Âx?hœfrׄ¡ç A¨}O\&s‰¬U]ÿRvÓÄGŠXjnuR—°9! 5ã©PSø|W‚X© {ËÆ%;£éýÙ…Œe«7,¿‚ôÜ™Iîu³ô»ê 8�'Ó8Œí‘;a¼ü)o]‚YÎ3×\«qµé|8ÖOÑNl˜¼¸ç�|Ó¸K=GH¯F9αáç�Ùý¡f­%l`ï'ë6Ž*.†¬¤fî^S»r´éþYÇ0z|ó’eþpyäùu^ãÆ÷ìÐáöíøKÎïç9äU}.^üþâ*xlÊ=,kÑ%Éé�ïÃ7”ý/¸.%DdÝVœíßMÞ¬bgÍÒÄgþsÐý;ÅŸrñxév.g(N l7ÕÂ'ª7ê�¿^,«íWɰÂünºì«ž›‡1eà0§›ÞxíN_^˜�ŸœhFäU$rŸ‰]{ÄÍ#·20º²“]™Ët &|¿¤àtèl ÷6TlÎew¬Ý å׋™ž·îÐy«"¯ãêà�(±ý Ë^�ÝÆÇ˜dÕp8÷'GíóèáÙ†cã!w³^R^€ÅO!ñÀ¢UªÎ ]¤öáè²ÝoÌÑãNU  RÊ‹x�­Ø•Œý›c ay*þ4L¢L¨3†?í£i>ðå0ÃuÕý…‘ɯ¨³ÛGjâpß(jðRÚV¡õ›Vºj¾ØßBOË죷?§oçè¡Ú¾w¬a�œØœ)�)“kp×�'ÑUýÄHv?/+$ú[fðZ>Ëa{².ÊXžCþú(ëÝKÇtÀš/�³Wæ…æg0àv¡‰S4?†ÙvÖ>jÊòÈ�«pÖóüžRB-Ie,š±°÷­þ æ�+Lá­^³�ÎzgÀò~æàø§[ìì-JXzU�u,­FæÁznÞJtæ}'›ÇâËþ(¬�/Bí º,îu’䥋5ÑÙãÇ0ë^7)y�ƒ?‹ƒ}§ž¯¤©×Èèº{¸2ñ"*·U¹¸‚¦ÚGâ·æ!-8†!« |T¸w¯ô�t¾( ÖÛ3[ž0Ck!ù”$3>ß ;ß7Ãê…¢À+úÄúŸø‚çßoLJŠ™ýÒèõQö�Wç=`iZï;6)øTIFŠK^©áFÏ6rrd3éœù„lq=Bþ®ý ŸþôBö…hÈ>a¿Š¾Ò´èåPêÄî}߇zç�¼óßè³Â–cô "«ñXÈhX*bohw¬&ò•@9yˆå Aèä%Ú ÈWóCdËàaä›ÃÁUò’}À‡†Üçç~™�ç%3Áâ˜ta”vX)S×MšÜUõ[ÿy°;�ÓÉøÏã°­>Z”*É��Ñ~€ç®D£ \(<ìÏqN.&ÑÚ‰`'ydý‘ó ßIQs'[ãåÏÝýpó»zÜ�´�˜çOÑ¢5`¶t,)SÑe3¸Y“€j¾A,{#�NMúF®EHr¶Û\£çű0{ 1—Uã^Ú|۪ˆOp?6ÅòÑ)¨ôx ;Uø%¶¦aø�køÞ§:¤¨…ä¤UþprõmŒùm?ßíÀ&XåØQµùùlàvc^n; sF‰K•wƒ[4ç¨Ð=ôßU„A¤ß™ÇS(݃r8Íò3^îâƒâoah�ü˜ˆ›,%K‹}€ÿé”ͲÛ³p�Ñ,îÂ^ý®Åk¸y}}kªÚõ>`è‰;È\°còà¯ò(k6躾Wþ̓\žFlóSØÀ¹rÄ™Vq$j¡Ìê'ýÚ·_xrPbâV´Ý‚`f”]Úú S ¬©Ý­)¼Xë xõ%ž4ÊðJ¬üÿùÊud#ä¹»&Ì9êžÊ8Ä…dî3Vüï^\mE>T]ñeŸ@ŠÛMòyÿ *¸g\—~¤³ÖfàÆ™Oéðô¼_ü†6˜ãd¦-Ì‘9ÃêY ¨u�mx›I\SÁIóh<áe…’¯³1/|&wâSŽXÇ‚Lè¢`~¾™¤“i€í´Õx%£_tÀÍ.ê$f‰|R“œ°¢+ôÉYbº}'ؾäp³Êq›Q+ªŸ�wr�!Ïi€u\AýuVb™è™o‚êÇ顃K¹•„5ï€EJšìŸƒƒ�Øpl!çbÖ·ð�¢¸å¿U—Zªh„(Ýê|.¦¨ÒU™ÇéyÞ4l«ó¥ùÖ`¹T„ÿ/\Å@åþ.Τv=÷w)®´X i6ù[ŠêFÈ‘¿I¸ l ~.âüËxñhí-Á 7®\«G¦@üËCXhKpÎêNm…"e€/rÌýe‹-—ÃP}Æ;”zö‡½áŒ*ã~°·] [–=&ÿ™x¢±þJü-qNzô‘IÑuà«´ÐDk2žNÿ0@2Õwá�‰@pµ!Ê Ñ0vÙfÍ–äŽZÛÂöZ9¦ðÇ¿µú·ÁŠîŒn^óFôáÕZ�à°ðQe;x.ËC 9y<·û&ÖÞíbMwö�m§J™9Ò¡$,4”ÞJ˜ÆÛºnüH±Í*ö‘lN_ ‰QÈoÅűœ�—Ãlÿ(VÉ^©JÐ[Ó“qG 8°¢@|X¦_¿{]|é.åIòIp.ÈÕ r½ .Cô÷õŒCŠ|Ý3È~½e‹/� ðÜk_Óéßóg݇”Ïq+Fëùk4úM"~’º…'î(ðrO/äÖ¾v&ùÿ‡Õ*Ç)qÞ}§zºùÊ8a8U‘Ú~Ì­¯7HXù/(õ@Û½e Ÿ—€ óoÙÄÒð( bc‰nQÍ)XH•öÆbxrË,Χû_ÂÆõË@vÏKjácƒ§ÈAUqسbÞLÁ9ƒÒ¼ÑJYÞï–ã°$dyõDõZ&Æ¥-Å‚¦˜¹˜÷a½ä¯Ñà }¿Lă¡ÎÏ×' p¹S^Yëõ¤ù’ïBä,žkD$4ò…‘ÖDÖhsQk¬¢aÍÓ4û©éÐy|}´öhäÓßÕ ¨“Z«5&P÷Ë6|øˆTÄ+ñ’grÏn×û¥ãÚ0—Z˜%ÁáR/4_1\ÐϨ¡Êß÷’ýëCh¸*O”ÑÚqxü± ñ*¡½³Õ@¾cÂ…#àøã28tRÃö\”K²DÁmÍ&S ï`ª  )S͇wP_Ê, åðzÑ}`¥Å6›…€ÒŸJvÍÄS¼8Ç;‡ŒW¶DWhϺkã‘KíôF¢fž°¿5�Xªs“ Ë,ÈþwN°/$�x¶ ®â4�úª.rÄåy%W$:d$Aba9"½^êMÇ4nK*tcyø<7dè_ý�”¯y ×¶erìv pö\¿f…4mB‹ç™Ì½ŒŒÞUø. ¦Òèü9žAS>ð…K gê3¨é ®vPû8GQ8vÃ>îÝÑ9€n$d¾ÖjŸ‹îHZ·Ë&Nƒ{C–èþ:nd?¡õ7dqñÉøSµ“¹«%„*Ñö˜–æÃsŽ�mõTôF:1ö7 j§çâžUÑŒK‡u«“¨¶®49ÒP¸–GT«x¸ùÆOz½zxG”ÓÑNèl„÷ÏD²3âm@2Õšü¥ñi]þôÙ‰»Šý Z9‚0Û, Þ9‡mZ‚D§ã¼þw8w×\Œ»v‚”ÜWA—:¨TSƒÜZa®«ë¸¤å·±ÛÏÛá·§Qq»,Ï8Äæm^Â�Tç÷nh<´Ÿk¦#:uÂäbýäû¹�Äo< Š i­A%êÊ=$Îþ ˜½Ä…,Ýû•:׳�ýÁ±(AÜä_Œg—SË-ÖxæGPÝ <\ “βK#ŸÐ»cú0üD®ÛNaDü ³eèü·¯È Æ£aªvü*þæ<Ö)…\ŸjKí¾…Ð}U:¸òP-™xT�-w,På‡:4Ät·#‹àm{ž<´-ìËèîvòß¿µŽßK»wch�Y˜´�Ø™���Ý›PŽzÿ|ãÙ¦!Ðû€9:´}Ù)òðÊ0ì¼w›“P­ÅTÓL‘¬,œl�ŠÇ³§«Ö@ò� Ü÷œ�7ËO–�ãÖÿ gŸ0È,¥yò‘”o« ¦–JrW»]%Z^ƒø]¹ n„ž"•ÙÍðº(Ó7™zM »ï `ùªJ>—ж½ËñÑ…Û4™Äã½l·rECE4ÀfùtüϹ™s3ðˆóe¸¶Ìã vÁYƒÕp¤û"»ž{Ÿµ*‚'©3HÅ“Jd�“=’ÜsÛ�©Ãâ<ʃ]•8_*ˆé¼¼•Vëhpü�a}dš‰SåL°nø‰/ç¹ROílÞåMJ /“šÍWˆzâ&n`ï!H»ŒW,.SÙuÂ%ð“qµUAãC°n½Þy`K·zìÉeïüÅ»ù ¼<ïÍwA�ª 0ÅN�É©–„FEqôm”…}×)È~ˆ$ò�¯ˆB…l»ΓœQʽÊ%;/¯ƒ˜ ',¿ý‘ÜžÃó‚ù`¿{†Ïàüÿ¿ »ƒªÏ_¾ ÃfÊâ„@®¨(Kæœ^ù ;bªñ³\QÉè$Å·�ùn\ݵš�kIt;'…’бÈr¾Ø‚€Š"&U_ÂøÏsyœ °‘Pç =òÇQx/S†cÓFAéçž°™w•SèrÞòŒr¶Â&—XçЗ‹káÀccà=„„Õ~´ R\P‘7[ª+ý\À5ió_È-p¨ @é¸Ùu’$§èƒµb"ÌH„•‡ÐJ·\˜™<Ëôy´¥"“NYÕ‚­|<î~gºj„Í$ s\‘ž�ƒb»6iò†÷Ý_ѱkgÆÃUó¹ÌÅ'‹IÀœ)?ñAÝl¼»F‰žjƒ÷ËTA6æ$ xl‚àu¶°c™)”f+bQÕ_â ¶ÏÓ`é—Ôœtž ©â¾uŸ‡–™ÉP;KyJé(Nد\30Úì[¶¬dªOb­Kn¿Lwv߆ª³xù.Zx mDÖá©Êhê•#ˆf¼»\%<¹`xt‚™A=®2ƒ—“° üu¹Ê“5pv™)~Á%­Óyßþ â�k˜Œ ™BðÛóh•{Û"p8º.×<63›®ûþ‡6,æ´ÃØsßÀ0ŽŒÖ•Sß%\Ðj€331o´c•›Ù ‡qWJý„‰W©˜tÕ ãOûÒ_‡ŸQ÷5*Ð!š ~½ÝhÜÚŽRaoè«Ñ|ÔzÐ…C'�c¼­*šN Hk.J˜ã뙎têÍÙÜ_gÒÉ5ÍwðÐq¾ü²Šê~ã±V qRc�äx»aªúXUP„†'ú€SÏ máU:쀫Ō ®ßD ®XùˆF%Ó«ë¬Ùò�™’ÜżzªŽ½]8– ‚Aãp¬: ŠòçâéSMl€$!²ú™{ž,´D<Ãè¯ÚdxëJvé»0ãG4‰¨J£ÙžS�¯7‚iý8ÌŒM®ä¶æwïiïØ!éTlòä'‹ è9Malüûµ£ù@ê”^ÏÊ£±+ëXí¯kh9ç�j+!·�E€mJú¨oœDšú2‘«•pÕ“K”ö”1£WQzíLî­è¨—¡Wèoz8¶“º77Àw÷ÝÀþ¾GæŒg�l}ºþÜ�?n™àÉ™ÏÐÃê5™gƒÏÅ0¢²€žéŒ$㥧�µÐ€OÃõPP•ˆ Jr»#Ý!ðèh”ÜÆµð ”�ø =zJv ü^–ÌÚ8E—Èž£r^ljÓV1¤¯ÏÂ:‰5ð­^+o=Ã;Úlu‰#lÙ) ±Ò×X©o·QnÆ ´Îì§Ó²i�— ÷†¶*�öµ‚TÔà=‰‹Å‘CSÿya.X,Åí©y ‡šN’ŽW;ðÐ^}B?=ÑÕdÏ•/ôã#cöáŽËô±KŒ<^ q{§€õ†Px^c‡—JÿC‘9~pÞ^Œ\×ðÁ.ß, ýAÿðpWÇÿ¦·Ó_ùt²ßAaî=9INz+#|Ÿ�f«~þ†ãò� ñ&&¸!b温¹“´þ~€>:5ä¯Ô*üØ• ˧dAäþÊ_²œÇz+ñJÔ‡ñˆì”,aòŠå!á— O©/[]a_ô¿»;ÙB'¼BÙÓ–:˜ùºŽ¼ºÓâ&p»V–Š–Â «fX¢VšŸþÐÌIàvn�„>Ï^T|ŸÐG¥�Mtß'A"9\Åñý£Æ£[ï’YÆS¸šŸøazOÌ”ç0�É-øÉ‹Ÿû÷¬ާÏá¦[8¡[¼/p|ˆp‚ù�ó1•Z³þEäÛ±e$ý Ì5‚O‚axë— ×:PD ô‰�ÝTé~öôú*м% ûÚOবhLž,g[ìó˜þK ¥�€Ûš…x£×>WÍS´!ªãÀÿõ,Ùí Â;o`Úu¼SR·ìa LV�šó!znˆÀQä˜ßT…Éõ ?ˆ€õ†[ êN2. Iß!?R±À¯7vàʉf÷î»8ÞK†ˆÃ€P'x¥(�ÎÀ¼Í ]±u ÈŠçÑo#ÑÄãî üè1G·h‚ÔG>ØRö±òé×¥Üůnƒïäz™87=®™S% %vÎÛKÍÐbû¬¨Ò�ªýµ€Ô\Û7ÇÈyçí ?£Kù1xs,h„Üc¾Ï,£;lvò‘|ÞZ�Ù %ð�·�ÆH­ÃM…˜»ñÚ|4#/S*`Ý6 `ÞKгÍ@íIýâ²�Þnc46¶Ñaé`º9”¾Q™MG# ÞOhÁ _7j½ú�ÕðåWtÙ 1'æ0¬{bèÉ“êS‡Y[>îÆ¦1ÜR`Hîšw"ÿï¹dlo¬ªgDcÖB�ÓEr£Ô›xš¾f?yL¬Có1æ¯41‡½ô˜�4Îv”„‡Å<ÓÚódÿ s<Ùó—MÑN#ûþ±ßÔ_ëÀmí 6KçÑ +%®²E=t]�r'|qOÓÀx'¼¾úmL{ŒÍV™`¹‰†=Wæ.šGAL^ˆ”™ÉóT.ç‘-ê|<ÿžy0·ml«‘á}e­‰ó‚çdåÅ8ŽY8P*C–O݉ŸÂd`Ë­HÜQZCŽauësÌË›�úO ‰O^|I[ÇÂ/nJ»5tsŸb¢Wct1 Û§âË#p·Ón|~C7·�¦Ó %!ö`4Í‹t@&§³mÂQТ6:„ vœÍàÞÞÿˆ‘&¡·�XÞ§‰Ÿ¾£¾‹7˜îñfWþœÂÕ¯½‰ì{5´H¿Ø�xþt"ÜjÌÓ:Ý ÛÝž‘›üóɺ‹~�çߊ‰j‚øùúS±ÿ:q³ãƒg—xŒÛx%+¢ï / ó€ç“L]ojcÝ^\q ~|¼€X¸4ж„v"W¶“!²bx;L?}©ƒ2y)äN�ʆe½'!’áTa�2*ráîDM,‰‘åÅ-?Å–Ù² =x·7ã¼\Â3ð\Kr}áÐöllÚnD>3¸ÁÙ†ü¾ÔVwšÉå•��ð(•ÌÓ�‡9QÞx®>Ri€»O£ˆ‡ûR¼¼ý}lžN]Fá«Ø2¬™>„ÓoBÔrS�•ã=¸ {Ý”yµ¸ÿ$1"�Hb�rH©ÌÁŸ‰8f•M«[7��` ~¨žÊÍéV‡%«/cGë=ÌÐ�$µÑiDõÍ>p»‹yk2Hò—�°x‡"Ž} ¤ÕáË¡äü"è¿f‡~*xŠžÀ'ÛCëKÒè7ãh·„÷Ï Qìá*hZ ©OkèÑ›ôë*QniâNz{ŸΘӃî˜Bn|DŽ_]ƒCµóÐç…67¾¡¹–#øn �Ü3QÅ£‰£ìú kØ}Dß¹\¥¯¸Óx‹h² –œÝgE·.ºÛø'9„SÍœš`%^QÔ¼¾‡IÎÊ€îÁ)¼E™õøÔÓ‰Hç¶Â¯Ú ˜ôü�Û:CÐe•÷R³Þ %Byù$èƒ2wÕ†óàëS8žU÷¡û¡dxs%Üÿ>B,^­ÆJê”% *÷á�‚-ñD¾½¹t�î˳ý°D¥~9ÒìæjX˜¡Mkæ9BÌÆjÈÞ—E:›)™öü2·¯À%£ÛDW} ¦V¥ã¶£Ç¡H4;ùc“¬d24�#6ø™ï½x°·ôhà‚4iêhÙºÒ¸w•~¥]Â-Ly‡­4ÝyÔ>–æÉÄ­´Úâ¡’ñéÜ`\ùs'ì>ø ~ØõÒä>C Œâî¼ß!OlaÄH†'}u5î,4ç^Yº½òàyAÙ.HoNƒ†¦||¾)ƒiÍÅ»‚¦ðD¥ŸUˆüBTŸÅ‘ÑY´Ó¿Ï&åyÝÚ�`š†ÿ¸R-&Š>?¡9t > ƒôge¨&_J7Ì—†Ž/�·ç(�þÀÏ»íàNOfÆâØÕ+�:ð—Œ[e3e­¨ß±ËDbú+üzš |¤™ê‹áaÆT‰ŠÁÁiì%Ï#pE,;ºˆ»wzš]²•&ŒR?w˜ñ†¶Òtr<�ýM¨štø!½�†'–ycú1K,™~ÎõŠ€9g*÷˜^/éœ:Íû�¨Êú©Õ(È›<üoNõ³à•Í3°¦*—LÐ…wæÐS‰4A{ÈL(º²œ„„k‚€[jÕ·*¸;²knCg‹jðί©À9*|ܳu !¤é_4}Î&]YM¼?TÂú‰ÿˆïɧ€Q@Æ5¯‘)¡a´m’Ô¤7Ñ{®©ìnñisj±Íg5 &a¼áfÌ|4—u‰M *"¬õîż—y,þüu›¬{{¿Ù顟0ÚÜâÁ¦'~0~æ$¦‰ÔàrC5P›Ç‡V„Âûr¼T&ÈK=PßH欄¹s¸¯/\¦ƒ¢sxwû„ñäÒ&ãX)9=ÐA¬Áûý›‰×©¤±5^b·å„pÖö‹CRbY&¹–ýqp&þ.¼�™¨`f<‰›ú„MÏX]%w묞}­—ªðl\ �bаÒwq•w¬%á9*0Öí‚¶®?»Õ—ÇÓ‘jO¢4ïëê.Œ:'ú™)ýïiMâeúdúCÜ:"ÁŒä´Iõ×$éØ#J�£ºw$ÑÔXLÇ|+è^‹ ²ùÓuh(µÁACt•ÏÇ�E¼ä[½ô½Ë-R¬9 KŠ`ûÄfP¿ÿ˜Š-Æ‘‹»1{aÝn»&ß…à0)²òô-"ùì9œýc@Ež§â�,Kø¸Ä‰¾s†YNßé}ÉèùGŽ^˜ÿ€U÷™Z'ËÑæ¢8î=+I®”‚ã¾#üs~ê^ÅůþÂÍipóÁgá¤cE2ò9,b ­D‘ÝÒ'¾CdêUmûHز&ìΰ�—vRjA!æ"ª©üÊÉàY€°ùur'c+ øiÃãã‘(´tФ`>ÿÄø Â®/øÅYÛUèR–@N§�Æ_RÀ¥¼‡vj-gÌïPU}–4_®º³iŽà Ì­O'ó�m!xµ9”ÇØÃˆ—0ØvàÚÙgà{oxÓGÖ×¢�ÊA 7Ú ZFö¨ìKûÏm$†¯™�±-(³'�ÙâšøãL�q�Êêîã|NØöÏ»Pð¾.}[JLÖ¦£ÂbîÙ´,ˆÄ‹ÒI”Ï,—Z««q×ý À�ûô†[½Ø:�÷ñ[3©0óÅåÞ�*‚ÕZy|¶X¶à_ŽŸ”ø9.¬Ò�êDµ‚vT}ö–ÉW€ªÆöóÜ]Xªà ǶìAÓJмM#?]äË3qÅoG"ìÖKŒ£v‘óƒ«ArN†¹óàí†L¤"—Ù=¹åñ}¯Š�_î“…F:TÍIõ¡>i@k ¹µ•¤¸¥�FßocoW rZ>“lÂ�/.°^S‹Ü�qV|¡Î‡RhNæ; Ï3ª–Á�ƒW«*{g€ÃóvŽ_ÚqèÝUÜc<ÎÙû[àN¼­—RÂ;zS© ÿú)Ü—ÓÖƒñ�ëÞô‚½(ã�ž_è³²×ì»ÇÄS(ˆþ=ä]%—÷/£E'¥fÓÜr¼*’ ¥tKó^rêÌ8ê®É�Pé´«ø)ëР m7z™…¢…”³ï½7ý5.³×B‘/Ëà#-!! /AÉ^ rw€æ¶pÆl&L\0@íöx¢í Hè—O«zš¦’ÈJ.²�ß��Ì_Ö�XHçaOo,šï@Oo²FûˆE”¤>ÆEÕ¦p·J|yÚ{>Fƒ¹þLŸÐ<`òW —€>ÜR@³æ-§å�T\%�¸ŠOÐ)Ó™S»¼ˆFj' p©ƒ¥{¾’»ç§qKçî±&¯ÏJƒþëŒbñ ÂL ݆/S?ЬEixNî;Þv§øÖþ\J�BO«­¡ßÃÀörù"ì iãDfù&,ت‹³ˆãoKà¨Â2òD&úNsàB[)v? Aï†x°¬ž;€² >ø‡¹È~™ý�øCÙó7ÆÉ�X°:%ÂÛb€jß ÷P‘Ië¾½ì/ùñp¯Û_ETùy¡«1%1\øaÕã1 ÿõ0eÎR‡ÛO(m/·FðyC?ÎæÁ(FbÕÅHrîIÓ6@Œ ‚ξT²½`>|»lïÅø°81Ÿ Ƀ¯öEÖvR?=»Jô†æ�ï_ã·?r`Ùx m+ÕVäz“ï6Â<ÛT>àÿןe½›qÉñ©ð6}+F½(€Œøpr敌eÔ“NãÖ<þÙ5t£G�ÈøH$#Ùµgÿ¹wCïã= 8kaÛeSRÓxk3Žàå#«¨É¶ì­Y@ .lÇ:0D°—�êb2»ÓŠct)®0Ñ?«ª¾n¬%{nå¶Ñë¢S‘ÿ[%ľP¥Ñ¢„ü®ž‹T\›ªäu§£ôܽW$n�)ªØ*âË‚çäÃÜ=Ž˜Í5Tt¥”G2üž Î d‚9}ŒžÌr�áìÑÍR(ï%í¸ µWÆh|?¦©Ì„†sxÏ[û(ËI�3ñ•PÚ ºNZاÌODÖ r÷eøí¿ :¥ÀÀÜ™™wâ1½Þ›BE„Áž7âÜÓ9‘è3”†"ò9ø~^åë5€Ï¶S `t=†¸ãœ/òñ×)x|¯‹¶iõ1·–™0íüpªŠIL\ V’Žp¡LŠ‡Â‰ƒÍ¤¹oýQ#Žù&Æ ðÜ’îúöŒ:éVp’U…:ú“QïÛd£R~ÕçUïñ•ü\Lœ•O"7<¤]æ� 9#<ÎàUó�ÜÍ3ˆÚOÎÕ0>œ¡jŽ;íì¡áÙzâëƒú0·L=Jw06·àìì˜KÂ}ò;ˆ¶î(._Ö ¿gÊ€n­2<úXOÚªD1çŠ Çä³ ¢ûq(ÕÜeÁãþ3zvQ+ìŽ,ÅM®Pè¤ 'þûGÕ‡ùaZ÷MÚ›©�b+šÈŒ%ñ·á^gH•ß:ÓU›3rˆ£�ˆd® 7;_ÁÉ㌯¹ò]…E¥>äbà4¾…ä‹P }®Ÿ€Sl«a‡ÃVؼø.ΰ'’Áæ {¹ t§JátÓl´|ÝB††üÉyéKh¿_‚«-õ„ð·;@Ç|_PWØ�û÷“ŒÐ.ì•6‚�Ii°>/ ‡>'Q;uqø¯Z^ªÄ[J�P鯨KŠ�K%rÌ£Î@¹Ù;òÇð4‘y©Œ;ë5 JR’ç}ê5;'Ñ&*1¤t?9»¶©ríÄGL9y$–Ng¾MûJ6f�Qa‘ìL¶9»è±<•V޵Ã÷ÑÙ¯^yC‹ËÈ»XwªokFgÉJòž§êá§~ÐÎsñ‡jXeó—LúFÁªÇoƒ‰ "zk=ýS+Œ»´ÅAE6w9�Pûí/ɤÁS”´q#ÖÎ*½3ÃoÉÑÀ‰{DtI:\Ü£…KÌÅÝ[PWIJŠÉÞêÇt¬F˜N>}DtÂ]ñÖó*âkD�ÊäS)‹ ¼×ïD+l6¢ ³X”%“ %IÒ}Aæ›ítøM§ÑÀÂ%PóEš76¨��é§vI�÷ÊAÒ×ùµRÿÇ¿ýÅaßi¦Í›Žƒ™ž)�MÇùüœjÇÒš>bñà<=·d Óþ5š”'¼·áazâ¸<–\‘€ïL>¾YEøn±usào% ÐEÊt}‰–i2ÉÕÛŽÍkæÃÑI~Fè�ˆi@¶%E35i–FM´[…ªÒ¸òúEâäþž¾šúžvÌ(ûŽ&ÖN0^_[0o%Ööár¯l¸o)Eœ|P¤0�]âv ¦´\ÇœÂPrÅÍØW9I.z�; ¨z-ÙpwØñ|}:Û†>ý¥as"ðöÃ)(ÖÜMäO bëltW/5ñÁ8Þi…{$¿‘>·&ô–K&‘g H3ËÃÅC–ŒaÕ³Ù×½·9`÷2Ý/Î�ݹ-T6êþ’cãtô@úÃ\K[ ÷¢ªèŒóWˆÕµa¶Xê-™Ñ^ŒíòóÀË0 ¯zc¸H‰¾¹:H>¨ÑÄZ!x=]dÞüÔú¯•~"- ¥©Ç� p{s¶3á~H,ÄÙáWÐíí²Êša!îbò—sýÙ6”Íh¦Á®pô[d¬ö�&Yªÿ¾ïæÖ`ÅZClóþH]®§W×Ð⎠(œ>J³*âðÀéÙ<±ü5Ä(i9Ùyç1ËyQŒ??^"º´˜ô´@üÚaR|U€³­Ô”ˆÜ.gtMBQ—É‚ž6t›ÿ ’&dŠ~þÛ±±ó1”?–Æ¢TgòL¼Ÿ”\yÉîúL4eLµx,ÿ­Lâô$ƒ„üÝ m¡°ï×[rô}g¯ø*è–[†æòèÆ#sa�¢&ØŸÛÃjÕršï“£"í°±|°ê‘ÆjöMûMºèn9~ô±ÁÝvµ¨™ªOÍ8ˆ’Ú×h{å^ps‰ƒç§gÒ“�Ã9®êøÇºW|!ŽËº[M üÑh„v7Ôpµô{¸sÍ‚<ªr‚_Á‰ÌÙcÚ¤ºÕ7!¡.logmâSh˜\.õ¨¡Å‹¶±MºØ£¼H~’LñÞ(}ÚGå~ÛÂiHÏÌ�£1·ÐGÈ<JAãû[èöh¨í¯Æ½�‚ÜÌ·„DñìRx¯Ã Q /ä¶„°ðÃ4aš.ÛÜDžN_L/ýYâì<ʽ²¥–^Ǧ©nôçî ¤ÕQƒÖM"¿„Þ�¥; ¡‚/Š–O½ ™ ÒÐu*†™”°�TŸlØ(8I_õeàQÙõx°ë_¶Z‹î �™i©+齡 ¸Ç›Â/¢Du?î¹rŸš¨¶I}ö[‹7I•ï)x–jãôרwì-<© ¯*¨`¨©}±¶Fhœ·”òĤÙÿøîF`h�j£~Äx_BçA¿¼?&žŽ€ùÚh»Ð{&y µ¨SsÎF´³u±^xàÌG•¿‚nÐr&ÏÇr±P= c.{ÌS!m1”=šFÍîÌ]šamd"pêf¦‘^8 {‡Á¿MxR·Žìõ¹ˆ×aÞ%?Zãç ;ïЙ*¯�Hí$~ÒÏ,`$i!ÎÑýPyßà"u,‰ �ÍéÉé›Ðr‘/*ûî��3¨üë$iS*8˜v“D›WÄ;¿ ļ³ðÍÛ%¸ÔH®xµR‡{•4徦܅䨢Öm8éÊ!©¥šäAÆ?¾`–_' ^’¸Ã‰˜Î2�È™ž{¸<ø >ïSµ½Ìšö «#“[@"Ÿ¨Š 1!U<%||j/¹ÇÜ ‹×ÿËâÊ}¬šÒyæ»ßvj×sÙÃÏK¹LNñOÂ��Λ­ºÅ[¿ýÙp¦á2V-�ËÚvÄNG~/”û X#| >½Âþœ 2,ö�Sî–ÓÖó÷hú|¼3þ�Ñ�úFæ‹mÁcÕŠÈ�ÈC%C5صæ4ŽM3¤²�”L‚çâ"¨ÃŸ)p~w>i±¥÷Å4q‰z$ô‰NÒÜ ¤¶n7Ö~áÀÌ7ÔRø!z“÷½ÃSÿôh|r:vE:ÑásQBâIÅ;Ü&Ÿ¶ž�;»ÅèƒåÐ@{pè¬XŽòÈMË9ô„Ë9ö²T%ŽÔ¨ m‰2h¤Ï…y*³8-öŽD—›Âv½è$…»Â±÷¦9rÞ-qSuö*‰Ï«Ÿ0µØ«ôAGZ‡}wì#[²yÝï¿ë¤bÅýòªÚ7¯JÄúœ$“Nþ¤Fœ·Ã“ìš’N"æùŽÝ¨^N[Tp�ˆ(LJÀÊ¢y`0¤ÏÈÐÕÈyšT}X�'tÓ'A4ºêƒ]7—Ÿîu¤ðw>É ¸`¶'½r­´ì“LòNí"ç·à…Ÿ¡xQÂ�XqâHõ¡r’©`½'äA].ñØœFRËêèÊÂvvâ¹+±xk w¹�xüIQý…ÆRn�·Ež(3œ†ß§£Í’ÆOû婇V•áu�[Ïû±Òµ ½J¶ÁëígQ¡×�î�šQ'ŸˆÄŠK HÁèq°Bwq xhˆ�Ÿ†mÊi_(� ü“BŽ{Ä’•Ó`©ìe8ܵ¦,(»­Îø&jÈ*C?ÆÖé}g­}Ósñ±äaè\yÞØ%ƒô±#øRª_®WÆO‡€ýb… ¥‰ã¾XÌ:y•Úw�K](­MXL~�‡ŒîŸÆýâNT\Ó/myNU­Ç´À(¼ƒþå“e²oµ¢‹I›Ú>3EV‘gžjPÓ—DfìÄŠ×ëщû6-aÓu“Iœ‚ i+’Á¥i†Äjs ‘1m¤ë‚^UWžRc³[—Óªw‚à"ò~¥¾ù4› Ð�Z^+a'[ # R�ÿ½2:·>`¦Ž:xNiá—ÈF²?AÂR )Ÿ�*uï†lÓõ4ŽyBœÄpß± H_Ü��…Rh^‹W7¼ {^’SY¤æþEìÕ/€LÿTÜÓ�BíGî‘_  žÐWïŸPM2çÉt’ª”öíÃPH~$'-S©ŒëshÖM€=;{II” ÇwÀÜ@AÌÚ§‰KoíAfÀ¦Hp¶õnœ$¦Sؼ¾ JrÃØá 8¼ÌL*æÂÔÎêíŠ;¬ú!ÆS Ÿo¡=fšDÆù1©8â�š·ÙK-`ÖÕˆBÜ©á °1Qy)PÛLr�¿“/g`õ`µØi’_ƒÐNî.€ütôˆ9ü/ç`¸èx —/J‡»™ðìêÜÑïFŒÕ¤Øˆ›f ‰'õ浌¦Lèg&u /Ä-ápì—MJä¾gqtBR‘®•S!ÿ½‘ÝÁ�¸ý´Þäу{-*êÀ1æ}…‹OÍë„Dêæú}a€psjL*-‡8aÄ{QìúæÍ¤­©ÊX=¨�º-áTš³>I²<%]V NÿM%goÇ%»ƒ ûË"rá� †výdâvv‹ kãûm¶hµœ|rhSÔj˜ús‹^½ò‹µÙ–K2«Tá¾O ©¼ð—Èݹ†?þ˜cò®×Dr" ¿pƒ¶Õ²D®|ŠÚ{¤Qçä°ø #5 û×)ÆpáMë|_ŽÝ/¦Hû +Øé —ÉáÊ�4-e#}´Â/ÃFŸu`/A^­ð„=³£‹×"xµ7Ä»7O²~Ú&´o“cÒV°<âS¼%Œ]ä~í£—ƒIàV|]ò†ò÷î‡!­ÛÌøD;Ýò)•ê¢ œ¸ÌvþÜ¥ínÈÿX.µ0lBcÞ™¨ÚŸ‚1>0ñü2^Tpþær»Cz&V£Îç P5}Oý³öaÌß„G> gU�¡îîT¡Ü…f)Á;©;$}D :—æ“y³`nòM´ù@Ïzf2I«ŠéyõÃìúš2vÙ”>þ|ž�$ƒ1í¨Ý8nŠgÂÉÝ37ñãÜmp0Ë„uùy ÃͬŒ‘3í!ÕǬ«éÇÂ8X³«îécôÓ]Ø1(ƒyš–Xé•k¢ˆ‡Uiyäô§N¾EtÍòØ1Úy´ÕØ ®cØ\_œŒÕ„i‡ÉãGZàù†Yµ2•ùðÏK®JmD‡¿ù8‹û½úumMw{AoràŽñªvåXõ-3—Œ�Î-™Å*ÀwóxZÝ…Ö½’'#ÿ SÏwûÁlY 5~2J'þNA×n:¤ƒàþÌL0¨C!³94Äö4¦«~`M, ÈñáOá@ÙÇSÄ>ÿ*”ckˆUëlÒrD]7C‘¸(v}ºëeíà¿»…ô4&ÒÚ…fÐji„víθm.Ž�zÂÉâ»´�£Ž“Ïõq£»/6Vâ‰èËhc�Ñ×ÉX}<÷p. Iï<@^~¶,‚Ç[þç‡ÈNuÊ@­Gq¿y•Ôldô;2éÁ;¢�BóÄÈÓŠV*t=ŠüÓ ú$à,ˆçŸÃØ=GèöÓðäËW´éu®ÎE·åÒŒ¸kój´‘Ô?o¤¥/nÁÖ·õ”RyÜÜhìV¨©{¶>�£ gæM'·%�ºU![îµ™‰]5�zøï§ÿýâÀ‰CïHêý3 öúÉo�‡=çÁŸ•1¸Aü NûN&6;Ðd×ømö&<þIdnzÐW~2£C¦LràŒ{Çeg¬ bÝokÂñ@#É�»p½L k´Ñ¼ì÷ô[{.²f›±ëɽbOß[ŠRñáeTй‰&4+ÒÜæ¬ë ÂÉ{Dê»þ#¢Ó$@úQ+¼¨^„Y¾×HéÊ^ZÖcË.¼°—„¸.£§oÀýü�dÙ0ؼ|jô2+™Ño?×ßç£ÚºXÒUù“¤•&âYkmp9± †¾ôÓqª´;‡¾ø×KfO¯mæìú‚P=ûŒIjJ�´ÌëôÞJz$x.=MÂè×{±ÿ (ÈJ’ÃÕ~(ƒmô̓ìÄ`’ü× “Ó�Að�lúxjyäbýJ3Ô¶¥î;aŒB,6Üòƒ;Eöðà~lûŒª3Ñz‡ö>›Á±í=ŒÇ´]Ü==.1?»R6«Ÿd¾ëbJŠ2iNY+ ¶„âÔ› Äqݜخ_q$÷´Õ‘É� 51�k0w„e@­ôA’õ‰^ͼA•s#à03ܮΥʳ/�é·o_žëPFêÈü¯UŒØ~1ä¯W‡ðæÚÞ?NœýuÉQ4 8Qð�µ² ®N®g´§éc“ 7YTN…hÔd/$ í §ÕÊiâÈI|zÒ¤3XìédlÆ„¨Ž_ÖåRùw9Äñˆ.nÛ˜�gŽüf?¿''3Ôáԛ˸çˆ(Ö¬^�­x`»§$µà9O Þ§ÐÔ�˜)ë‡+Ëàþ&mô•l%I½§ñÖÍv²>û-)y“Ksuƒ‘÷b1<¹_„Zú÷`�µ2œØ‚¶_Ù„ºv—zn}�itó+)ôV¿Î^<î�"*¦(ø»#tæqB*”`]¾<•ëûãJœ3Ð)!°J}- 7ÖÀ‰xþš;Dúh¡çéí Zå÷ÏíÃq©M!½’ä”zk°¾‰tÚ[+|~­”®®¶Æâ¸ƒ´ Rwm]ÁýΗŠz{sZGÐh— §Î¬ „±Þ—yŒº]Di�{Þ ÿIçHÄAÒ´/h´§ÙƒÃDI ^xî†QYRÜH:-ÏÑ'ϳɅ^öX³õœWAÄò~± bôµ{ä|»_=;—Ç8~çM Òæî.©Æµ!¼¶²ÖíÒÁåÚtÿ`xØ)‘_÷ qÔ´†*î"ƒÀ§?ŽüüBTõ|Ááú.8Óø»¦zQoE� y,¥–®£Yg.�¹î-*%©NfðÞ§G¦��ŠÜåOüh»–8·m©& ?Ù…J¢ÝäwcÝ�¯„æ‘18hO›—Ê‘˜[!äÜ_qè�ÄM®–ðHé:Y,áð/¬&“Ax1Yî�óþ㼯°¡”¶â.Íl~¤H×·Ž�â5ÉUÞ›s0k0N„ÊáÂÓ~¤aYÉ×%žGl¹S¦Ò�;¢�é·4¹7üçpVíµÃüÐë‹+; ×lá¸H|‚+}âˆ[á³ìÜÔ¾—L#«uƒè>¹T^* ¶ÞhõÙ0¼úí}ðZ€¶«žq×òÓo.g­éì¿°ÏÆÍà\,ÐáÊzóà²_=(ÃK±Äpà$Ã% ¸{È)nŸÖÌlŽñŸH¸�0ã8‹¹{9kihž,¬ýÌáò'$yz4ÈMгt�qì�fQInζ`°ØÌ¾Ž(T7“á®Õ¿CÄü˜¦d kòú¢7Õÿׯ~[ÿBŠp88 KãÃ!Œå»÷ƒ�ÐàÆO¬x¹ „Òp0ó1íNhÆâWcøp�>êÍ-ǵuóa¼…�ð©û³vmØ!S¦.ºe�yp\û&¾œ’F½1ìF—zˆÎ惿wâ•:AÜwAò–ÖÑH‡â�dÌóÿD×(:Ã/ï˜õ6¬ú† ¦ï±‚3Í<¸I€U©S�§àÆ£ÚqÏ5·ëpc]·"çµ$-|ž£GˆÁ««t¶Š4VE'�P¯T)ÙiÖVhþç;Ø5›]Q±ó,í¥ˆó0&óéÀZM ŠúM»�3ÃÝq{¦ç’ùW*y¤ø[ÚÐ@ÿjŸ¾Œ*ñw�ç°WxÔ ¸�ê�­Ë5¨ÑCÅšq4¨“26-,b^Ìï§Gùâa‰L)hÎææ8jÐÈ~ ÊsêñÓÖ"g6ßÄ_…ÓðÂ4^®Æc.|¯€þƒÃpâ[”qü÷UŒï‰e�²¦†Æ«úQ�WûÐz�bœ¿ ¬:©‡Y'ú«›šVc ¸#)lA�™àe±„ëõ˜ë·¡´c--Ê{‰Dµcö§â‘�>¤c—)-ó–ëÅ}¬¿bäÛ-¡ c‹²‰Öži°âµ Bói|–ÜKÔv%ý}a§K(ÛýUóŠçpNçN’*ùtÛÒí¸žÛn̤µš«0ª|õO\îÿ|9ðs¼fåóæP´LõÇ`Y%9ó„¶Nçz *ž÷ËÐcÕzÜ!Ÿ OšZèémó¹�3Ípgãj¨,µûkÐÇWÞ` w×áAÛÙóé>Ýjæõýݰm‹+§ÜI‰#'pŸvEâ�ya@¯ºÒ— VpW¿Y�×?‘¦×±, :Žªcÿúz$Y †fBÁ‡PîÎF~Ñ5\þØPJ½×MP/Aðù<¬=‡ikanù$d”lƒÉàÁþ |O“ ¸ËÖ}�‡ü˜Yv}¸r¼Ÿ?Âá è²P–z&qImÌF8öH™«êЊR?­¡Ö]ê¼$à�û{¶KS—ûàâ;òÏ�Ü’æL—ÐCŠ‘Äbç5zÀ`-óûL‚Ž8A”‚î—¹�Ÿšu9ºcAG%ˆž”perJXœ˜û¾U„Îñ0_¤”.uƒö´Ù0¡}\·ŒÒ¨«ü0§Öky¤¡Z=†ù’%ßç]BE¡u`»æ¤‰š‚gÆìíãÈyüµìïòƒùOÿ7{!nü7äG¬á3ÚÉ÷Í ÷?âˆS1:,â'v}ÕÝAc¤¬×€þý`ˆåVyÆ�g¿ƒùÚ$âw÷8=eâc´Q)¯ìþ ÍêµÌ:‹zp¼Ì É2œñ„  ¨ÁÂ=]ÔDy#„Åë àâÝÚÌÂpN´–Ý Ê™tVo9s#¯vˆ0×|9%ÄÑóVÆÈÌàn;øÞ^ÿm,{ßÌÝ2“ëPÉ¥�¯ïaGÖ½¥‰Im‚Ü7Õ 3ú”¸ýp¡%&ÇppíÚ«ÙNûãÑ0`$ê=)މ!³ì$1ÁïðYÉê™—N=SÛÐû™=¤mbw=˜m$)&)•ÛHÞè<ø¼è4µ öÄ:žП¸�ÛQ³C÷D²«Ü�É%I;6T®�ª%Ò·¥ èÖ¿1‰vX!.IÏEL _‰Üo~†ßô+Ð:-…•'çIBÎ7ºcùüä grÂs"`ëbup2¢[£±}Z¼‰öĸ¼‡áÊ—rì\±^µ±äƼüˆ9ˆ“•ž¥¨V¿­ý/CCb*8?”Ų¼`çy”MªÀkÚ–ÜÕ÷ê�Ï)‹iç›xéb�SûühÁɨ2œ¹U'¿±óŸß¤gIôG6£ì.™{7›ÃéÍ£T©ì'9sh%XÞ¼NZl+@0í!.é£Çñdg´,æw€­Ó‘ôéËé_¸ oÝ"‰Ã:g0�Ò‚Wvíèxa’l;2kÖ#�áÝŒ/Ÿ‰‘X ibliÁ•œ�á~°ÒŒeªjçsRŸØpŸÕ¸CØUmV¸’‡£(Á N사Æh”ÑÕ6=ßæ\îÑœDä_‰27 @ä‰\µ™ç Æ~’b?óš ‰x jq3æÀë¶€g û ÿÅ\ŽëoEt¸&לAÐ^Mž¢­�1™ø�ƒ³Naˆ(S¡½š•�#f,Ú$+rþ®^ÈÆé§³þß*«V~Ù }|ØÂøˆ,†ò§‘ðòâ‘Ñ¿(:A7ôN‡¡!0°•j¹»Ö¨„q¿°l߆‘«¥é‹ÒL²¥é7Ù¹z9|v rW�âƒLpþ} �¿3¯]$³{”å¾Ll›çqf”q@ÁYÎv­¤ãâ¡S9²¯ç(l¬wdžWg�í¯­hyá íÃÄ^{¬qŒ χg¡þ¬½´è2Lßû ¬ZÏÐå\aW{ÌQûÖƒ§ª¦/9 Ÿ;¼èñH¨jÉ…-Ù‘´èÀ!šØ¨Ê´¾Î…Ú}Vàìì™b=haPeòmøeósýaa¹ÜåÝBƆíþ&ðZëIû&È™u»”̸ñ¤4ÎAÝòk(7¬…çîõƒ¤K/ ÏàZ•xq_ƒiù Øœþ”{úé•2C\XšB5s±Ä=�Ìè§/†)Ò£/#$°Bò,ýåJòþ¹£aã{Œ ãp³;îÁ~mˆhÆ|EmâkeާTÛÈ�¥ƒ8Pyý#yÈŽá¨}b^¬Ë„㇆¨ÕIo¼”sJÔcØ}ήã>Dz)Wƒ¯…%Üf® qàžÔe«Ð¤��FLÚÇœ’ò˜¸8 "#�¯" ñî-:ÌÛIÒÔö0zWø¸áŒ™cû@b£½[8O.QÂåìÉ)Ä�Ú�àSŽ“dä&âÌa™E`–=I×Ït¥Ÿ£ß€WÎgØ»o×A¼'Òÿ`ÂÓ"ÒSPÀxüáz¦à¬å*¤hš$äEËÊM#ÕE—!ÁÑ©zÛÁ|`ú ÌïUaѱabûx˜ˆå/Æ«–b›’�Dù‘'1ÝöÏ{׃ï'?Œ•ùÇÒ‚CÄ™é@òj;Šz¨(yí’ÞÛÁöPAέ+¼8i�ü‡Ò‹‘—aƒ˜.Œ›Zp˜¨c¸˜k6aˆÅ›rž~”Â=¦�hð²’®Yk L¡){Æ —™W½Š–ªcì{^R4§†\3© �» ÉÏBs"[¾<¿Í†6Qõ½IÆûö¬ÅÆÈzÊiN}Edˆ2ÎÏÕcÿÜFVžš‹Ñom0êc1™û%­ yqµUÌôy�VÒÚ¸Sd ¬ÛÝ{5šÖW fðÏÀÝkΠ@Y2¦¤ñ�ÐÕW¤¨õ?Ük¨…Íf#ßæ’ê‘z}¢%ŒŸ†[qÏá F?y’蜇חÌáC¯ |®� oMZxÂù-ò_Y©»ýâ~ÝãRŒ®í*úö�*$h&�\a3ª'þ â.=` ‡ `Óœ¦ÓãJÉúSÁÏùpf¥ $š.ÇeÞ°`Æi|ô¥’'$«WÖ´¸¦úEŠD½´xŒÛÐñácø à‰Mõ~ä½Xl•K§“. 8Úu'QÏ;2dî’3˜ùNw̤?Ä+ ìØèR²ž‘`ÈýÌÏ)ÐoB¿—™ ïM1®©¥tsMAè[;y±åÍj©A›Î\œžûþþNcncì¾aÊwí.X/í%›ü“Ø9óoà™C9ä¨Ý*ò%ìÉ¿)ÈMטÃD~VâðÿËà¾Öe,úv�ÊjœÆ©ÅCx þ (ºasn-(Z€78•þ�r~ê5·Vœ¢öŸ×QëY¨×pt·Ç ù;>îÛÑà=g¦yp‰¡e'DȹeÈèÝÎGî‚™´ÇU€sË&‡.I.‡—fcØe+ÎÍ6ŒCUS¨zò„>�ãøëPÓ#ÅøôüBº¯ý"»·’å¿7âë_oHi½ åÓ‚xùP` Æ=ÔXNOÅk‘m©¸Š°ødÛ'—!FÍ ÑjÁFh± £QO3ȱµ*t•ÿ|ö¦q$VÍÍ­âÂæâE8w£Œ94£�n&HüHWwœý)ó[œp•£7ÆŽK"8”“Ãcµ¨(ø•´Ÿ6ÂÍí°Õ;ž\.Mbþpn@áZ%è1«£]‰ŽÌ|½1*¾ aG4Õv-Å3_ëØùMmìTŒ/hõ/�çëªß¶ÒÖ†8bÝ@÷²là¡›pîÐfÒù¼s®ä²*Ëpóqîî'Ðäº(Ç!5Duÿ�S6Ùð”þ!2'“ÐÊè3ÓѺóþ»}±$]HŽsÎٟ탰ûÜØm©)ûE0?î4ˆî�„q…$òÂÃsWo"6ñò–}à2u†˜¹6Óy˜%­׋ ÈT÷*°)\1—sàprüøb‡®ºEðîËu:®4ITš+‰� 6t)û¯ä&þW‹‰ ùô¥�lÇôR×<Âdº¨ãÂÌxÐj›ÞOÐR‹Ìñ £,w¢Î fHăÙðŽ/$ö"!0:`0ÿý£Sã)/�"o<äi¯� }¡ C.ãÕŒ™ài.ÂùúŸÕ®Š%n³×²î˜@¸Y9¿É¿ˆ‡Áú¸®±�çÃ÷ÁÅlÀ¼{´@Q …m‚Ëùëpx‰=|U(®V½Uï Ùˆô%ÜuAޤ‡·_¾š³]ˆçNÂdU9ð* §êÈ/ýó°�áÉ_©ìÕî“dgÀ,FZù}eg ’Éô€Å oŽÆÁ±CpK*眷€u™iPðKúó:‰¬§$œÕÅ5Cý¾Wo¹êƒb^to{òóå’³Nc$u‹1Œ}Ë‚Ì x£¨‡¼ iFÏ×ÔV§“,Ô`ºŸð‚Æd)Œ‘¸Ý;†„ݼIÇ]œAÖ¿‹.J»æç/ãm¡Môì—Æéûa÷ÀK\s°¯:³‘1—í>ä™è[xšH›âènÁBãœìtT° Ì¼ÐÍ0&’LÖ%“³>¸›�% ÝM±ÖÞ‘<Ô›�M É Ú!”¨äãJŲÒ]Ûþå AžÇ/$»§qÌ�ûã‘wÁdË/ÚÉó¤‡�IÒœ70òË^ÅmúxVE´{ ÊLÄdÔp¨.WyR‰Y�pü»4,ê(!û“ÑS×5^Ñþ9!Ô!‡—{ˆ/‡—“»žZ�#õ9hrõ4¼N†iqÚÄ;›ï8à £d¬HáÒÚ]ÍôxJ3Þð-Éäi 1š·“ãÌåÙP- ƃ}ô�±7¬ß²Œ†l�¶«¶÷ŽP;õ÷À9¶ xøS±M#™¾òpÃ�—!þ~ÒÿR¾~Ù‹ü—ËññÇ_´ìU/¹“UD|˸G¢X·Ù›ˆe÷uºzŽ86]Ì¥;ÄÿÐMšMäuê]össõ¼É€ó$w›Rg‰4Ø'g…wN)ƒÐÆн– ôf¼e¢Ð_n”FÖãì -ðÙLœZ‹W(‰âíe�®™Ë½µ%Ïþ»¿É�ì'}ˆ ;…Ž={aiéZïVD�XÅïõÛ��Œ¢5¯iýó`à?D�&é©G387+ ˜žÅÊà¥&Œn¯Š!±,즫Óz¯ZpéÕWU$7§ò='IyEéš�‡´,ŽF˜'¿e¼(ÿý{è¼Xæ^§¿+.Á¹[ºt;¢Âã�‡¾o_�k*f¢ÇÐ1X5 ˆóíÒqkTžzÿ’Šü”ÂôßÜìè¨tÐö¿ D>Ž(õ> xGv Lw¾œ7‘Ãs`(NˆË™Ë¢„Ètxç¿3lHže+–Jŀˮ4á”Ys+�:iéÀ›G¿!®²�Þ4÷…Ðñõ�ß= ¯°ͦÌ•«Ahb%¸´¬d%zJA> iŽžæìq!?tac ¶}IøÌy>”ô)rÿ4/�ùV¶˜X°7‘ pͼDå|VADWÓ,qmÿ1†Šº«UÄ 5þ¼Ü׎âײOToIÝ·„³ü¡¨› AJÐ ý2š¦h ÑÙék¡ÅÔæ¸úáê�>’—…ß?‹r—Lw¥gB}pƒæÜ"¨Dðùm—¤˜S�$œéDí4T{¦ã£XUT¹PB[Ly¹ gNa¾æ¤h@E‡7HhùBãZò”�óiCY´&tÖ_&)[Þ“tÃ[žqší¨i¥AÇå9ßviZ Ç¡éUeî])#LK½§¬Ô˜úŠ`OÉKÒ¼ß�qŽÿnÌ/ÜKþTÇãî͈£×Pôœ8\ùçÞïˆå²pà.փɣô‰O,Ín¿Né!Ì-½Œ÷œÝpá¢U¨^rž��d­c­@ ÀòWNã$ží§:?¥ªÍæ¥@Ä�mäøÒ…Ü;Öáü1gº{@‘Ó7¦Åõ9>J/É݃>!?H²ãá¨ßÕÅ–pmβû¯ÈÑØÏDH>ƒVº¨aþ¦�éŽêËaÑÞÝWSEOupâV†âëÜ)v³ß?)½§�¯n¤‚Y»lõí¢\n\+ã+Ø kj�ážGétüL#•×_Ïé¿Z…ë_[¢öH6Y¥ˆ†UD]›ÒчD/ìdjý[Ä£•¤ôµ?¾qSã¼�‹@åziøl}ÿz˜’šÔXœûC/¸¶bÌxìSÅz ðWóå�à’h¶Æçùž�ñ²:*pE œæÁ‡ªÝàõœ�#a³�*Mµ�£Þçñ”û½gÈ…eËgƒqÍmP–‰ü§%_QÉL�´Tª“/}âäͼ`ðv¡‹£qîJ7<³‹ÌšVKçKJÀãù™Txè&šKóÁÕÞÔ£œ�ûŸ}p–µù‡™ð:õWöãìò7˜ƒ�ói<Ïê`-í&«ª+¨´æ#ü�+ƒÊþ8ÏU‡1ƒF.ÞCó§ó0š–'PêÊ<äéV‚ýí%pØA€#5TƒŠ?3H¬š\¹?“uY3hèBNº„ ÌÛRì0I*›Ô'­£Û•xàYëUÌåé¥ï5ö‚ô«@"ûÕõNw’‹/HŽª(Ýòc�š8,`nîyJ�¦ ãØSÐ:Læ¯ü…æËû@Ëè#(\\ õzO±œU‰µiðÑДDØÌÀ9ö9t¸!™„÷íÇF_Qú~™7ußêÊ»~É�)XÖ:Iqþàd¿“ÀMëݼSÞE”/K-Ãüæã˜�v ù^ýGEÞ+qdìC�Ý`þ¥�>޾E¿ty€¹¦õŸiŸÉ2s†/kË@]¹ÞpkA-Iª]C\± �lJy9¶~E¥`635×DBûÔ4V±-¿G©áõõ½8Ëb„v6Àk ä¿Bõ�]€ƒj™àK"Ïao cjÀŠ+I5’ �ltz…œµ“4ºÀäz8˜Œ ³×âN]höæL_Ì|ÒèÅ#ÏâÐéœ/[¿]‹Kê)æ\ó`ì´®@ÛÄZLêzB3Ö:¡H¸$Ì’ÏÆ<ù68¤`Ô> ãã@/Z� ~­À©ø,lÊX‰dj½âîÈ´1Fš;×E[¬¥aýÍ|è|Ç¿ÔÐ1ÿ«äs&›„¹3àê/Eà3p€O«^Ðý+€7ø¼·ÓCç…ÞxàN8Éõw®H%ʽ  >´Sê"J'�áì¼ ú ˆ€ÅÆyÜ]GZ êáQîñC­íª¹1º*ef �¿>‘Éîð¯K&¿B~RþšCå�‚iS{P-3€Ò±ÇÔHaö‘“ض[Ù5?ª]}¬ /³…˜ììÁ—3® » ° ²­ |¢`Û­Œ�V‰àÝy›wv�_;üáÔ.CLšÛ T³ò/ÆÃ¨EVh„clõ,jôË»z÷dþÍŠ¶ÆÇâþ1Åæ¦-DZ!ylJg·Y@­·¦cýÈÎÄø°±Æ_kx¸m‚äl �®…O@3p¼ªô93¾bšåãZÏž‰¯4gö]¼.yf(lDýRIŽFs,p×n€GË@ûò�¾ïµ·q«cä;Šqä¥6÷ÂiðÝu™ì“t2–«�僘=«�pÔ9\�ô(°ßæFûÈaÇôo•EîþØ¿; „Ž?€Ód Ò ëb»QgîRX/±WÁIæÿ> M/XÏMùPñÉ�<AËlôŒ·@�šó¸‡o ºE‚ÀÖy;ÉÒ«‡Œ£üÕÜJÜ^W@}ƶâ¡.O¸<í}íÞÁ‹÷)ÚD¯®4™MJ¤ y>ÎŽ™Á±iÊÂù™póÄ!òó÷z­TÅVßÉlqN€÷w¦ü´}.²2Þ¦aÝO9,<‰ý3šÉΉ*˜)ù—=s¹Þïj#fj×À‚'Ç<ïâ¼îÌ(&¥ìB0–ÑE“Ÿ¼ Ñ㎑Ï7±–vï‰Ìã%Üw†‘Ìà A¤[>µ9÷Â` iL¡·ÛL™iëtQ=E«JZòûõèºéÄÂ-Dµ;“äð­ ”7£½zö;ò*¦\øŒˆ»OIhq¡jj4µa .�J…okòp{`õ�ŽÀ‰yÈ %�3µ€œwgv‰þUÁ ýö.Ì´\ŒÛÎ÷«ÿ ©un=µ# >5[„Ñ�&Si/5\ê9“#Œsˆ†°3¼Œ¬–4:‹*ûæÙú,bR°V³�l9å2zwŽ<Äy)ajvCu÷®¤¬âé…íÇ,±»1œÚ6Xâ¬f0©›lç»G–”>÷u¿©�²®·î§ó2„{Ó ·—Ð Ê©™ì ¨?M"ʼnæó<”¶ÒdžÞ‡2'U¨?r;eøðËônvA†7sA· �¤CQ­<Û+[gÊ 5ºS�äØቕš\òÞç<ìë+§aÍ7±f§ Ô©Ýwõ`zÑûÎÖ™Cg>ùà Ú0½V…¥û1~¦1™H­Áò¸E7 È¥wxÍþ?¼^hŽZ»èîy¨Ó[Ž!wSpÑÙÇTøìoœ¿“�#Äçd#pµ­ ÝtÿMóÆÑZIüTz/ÚÈBïsî�»ÍäñIã²w�ìâªJ0zÀE“þ—ô1åUi­vV= ×>8áÚS·i®ïVÜ:kJ~ö ?Ò ÉˆÞfJ‚fc“}%ùŽöO$Á¼.eluž‡;+M±ãÃ"òsõ MÛ·‘¸ÎÇåá-¨Þ_z›¶•ÊÁâ?V ©wN¸ýã9#rnÁùêÂãO±!ç:˜lÝÒ‰Ãì—7~$ñ�HM$ãíô{$iÌ#n^ýÉðª8‚¨m£ó­Ë1ê,?èx@û‡�Pqx:ùZµµæ’H[#>²g55Óð–;$§a/yÐ~�X^3ƒ¢ù;A!Æ þ¤#k¶r€Ð$£oÓÁqe[úBBnàÖýoÉå”öÅømjý}>Ðní˜'Cs†X2$N Ššÿݧ0¸ž×HÀz-¬ïr£sSZÈÞGüœ£æ{˜OW!5?˜„D¢UjŠ…ˆÒ²t<›ŒAÑñz¨êºˆê­!芕¼^K–7½ƒyâ °j³æàĩ۸n0…ñ ›�_ÆâpÎß0à?‹äÔ¹Ï+©Ç;æûGSº°°šloL¢�{4 ö2)Ã:qðNûE^V%âï𔜡…3„ßÒ9•£lêwªõ¥:v¶Ói2èöó¹�[†ÂؘxÊÝšFÛÿÀ<ç6TH CéØpªxF:ß¶’ªoØ£û ðºzqì™lÁ¯»Cðóö¨æ8Œ…{bˆ–I ¨IÁa÷`öAÆ)Øøñ¤½ÌÅÌ8@݃.D(+�F-ŽÁ‹~3¨bÈò#)~#‹z|UdüÂcý3ªÄf¡_%ñßci¡C8Õ½X­*QZÊäù|@¥öUxj�?ß½ˆõX:´t ŽÃ-ºY]Žœ“xI”þþ‡w#þ½³Åap—8Ú—ÿdõNU‘Ò²Xb´„~>b ïóÑãn¶¶e‘–ÞãdúÕoDAô ØÔ>£†w¥áŽà6ñÇ-²f×Jb5§†Ô¨š ]\§8°º•JkNÝažÿHĉîÙàn"Q—aÕñ|ﻜ(ÊÿÇ�!Ôö²*sk�y^/‰ié2ÔH¼€fíœz¶�Q€Æ'jà~Érì·ùCäµåàoQ1=yˆØˆ}‚.‡r¬g˜=‹˜–Ë‘€á´®Z «‚ÁÒºOyh’›™xÅïÙm8BϽø…ÙVÂØp+�<)ºŽiG¼QÇkëãð�nú@Œ4=U™ïlY0L°€&Ål%š2/ˆjÀ\0«°†Ó6žØ• ›J{Èðú}ðë« �‰„æ(>ø¨sß|8�×n…³båÉØËzàþN¸\þœÈMlEÇx3ˆþý�(gOc,<÷´:òÉX´>Ðb œ:·�»€[UóõáiW"i;eHŠÞ Ñ7Î%ÄS©î‰5x"ȈßÒ ómÕñÁöX õÎÿç †ä�øj¶a�7»%]Ù}‹¨q„© 9Ü¢Æ2úK¦‚>v�ÞÚDgOÝ'g�ÄQáÔnìkT1î´I!Bb6øãšFUÆA`ãhœX‰ß¶ÎÿÇÏê0§â5^üN¹%ëñwl¤”0w-U±D[ —ìÂyG3 wr)»Ï9œúþÒÂÇï6‘uA»É¹K©ý�$P8bG©OÃÖЙ¨ÛóÌ2ÈÞöDìh³ÆÑ¤CäÉk&o‚‡Rÿ°)»rÁý…9˜L=�K^¦ -ìHX}–¦Õ“u\#4Œì§�÷ÐÁ¥cTeîzйr�ÊüÃÕ2Ñepüñò�·Ð”7³që°µ‚sdêì:,K~ŒWÁ�ØwÈÙ�t–rk·›yÔ©CcTŸàká1ºÞWËý1ÅéYTùb;#ò Ow£�¥aˆá’u{ÈWÕaª¾J5¿Êaè¸&‡ì�©mÈŒ‚Ÿ·0^IZKÆS·‚§g ±™ÕÊdÌž ª™ôUÅR?Vk<Ób�ñ”èu8~ñîR‘ä<˜Ù ­ùÈh À¿i€ŽßhYŠ/ÉÑlb“üà¬ÇLèJºBB»Ð 7ò{×4xh eZöøÅ=ƒ=Q¶¿|� J*öôOx ÜœAÎ$/ƒ¡SgP_ ò ¾��ƒ]ì^ÏéD¥ŠžÝŒÀŒêy f\HÃ$¿ý9Žȯò@`O¬bxd…¨�¨*Œv/£û¾{·È×B0¿*}™”ͬo½ÂT5µã¯pˆ‹Â›‡h—²14%Ç€ƒ¸ŒŸ—³`\N2­žôˆÆm­€ÓdŠaFèN8ÂêT«âö&¤Å¯g…VЋ� ø(›“´AC|ðâ 9R=><`,¬œ 3<Œ±Ó÷¡úµÁé[/Í(™…É|£¬Úf \´3¶üä­î³OŸI¬L Ê>zK½�þЩ—1¬ÈÍÐÁ�Ôîé%ÈMzÍÊŠ¼¢“'V³(Ên#É=ã¨7w‡Ðî¿ R)ÕIµ¥Y}c>Ôùs•NØîÅ(Ý›èdû‘ U×Ñ}©]X´Â"]½ÈY­ 8U’…p'£™=�ܘNcWàmöˆ�ÄÃXB7{íÏz꿺†dü7Θ¯œ¤ÜÆ¥°SE¾\ÌÃy½NÌ̉&²•#ÆíÂL¾¬$<›óŽn<»�ÔŠßG11fü‰t�;~v¨e¯ &Á�”jÞÎRWɬ³�èSq´w‘4®ñIÄú÷9üˆªmø "ï!~ФÙ)?X¿à+$ûØÖêÊ!|Ø#�Çh—Œ®�þâù/P©eÐÐ${­ɽo™ªÓJb·Ú€ä–ûSú…œH¾Ol^Þ½û0&™‡æbž¸;^þ²²�Ût]7-A£�Ÿè·1rá³+˜u>gæfH‚Ë%c:×O ¼jk±<,ƒ¼Ö*�€˕´±tA±^¦ƒ%ÒQB‰>›"÷ŸÍÀcs#hX‚îïi¥:IÙ}Ó�´»�ã*UX¤6 ÆnB37£óUè<¾`ùwx�MüšyAª«‘hÈ@ºm­*wF‹/Ç¡ÏGOŒØ#7b+ºÝäþHÀ•{‰™ÙWtIe½þ[º3+`le1áI¸KT�rèüþÿ˜‡—Ï#<¬ g¶D âž>¶ü¨!sð M¢ÿX³ûIß퀩»"q"=œ¾|tKÞ(£œq0H»!f�d"'»Éò­`hÍÏ2ž±-·�þãáÅò >è(¸>®›ë‰Øî6¡•{“Ðm@¾Çûâm«ß„•sƺ®\¦úç({´BîÞ•4”Æ•ëpÆÊEx¦{ “‘.ȹŸ•‰�Áøgs>F¦B¦ul¼;v§’¿:ÑÜc1áhr%;%aÃ'aØådFÞ‰Ô“Ü/ñìx ®µX º×ÀÆÆ ¤Ãš¨€�é‹U¥ê;¨²\6ûºvnt/¢�ebðßæsXXs„½urdƽ¥�mq•×\z%å+íµ:A7ø—ÛÏúVŒW'‰\pµX) rèýTÏÄ_„€ÍYäë’åq–¼ßïË(1芕�éíH‡jÅKSôÍs!öÚhæ�TP�àŠY “ø+ò¨<ÕF•+5‘› ™FâxoËç;Ö.%П}ž$ÄB‚Ú•ª/éWñ¬×Vúj Äç=œä]MŽ^ŸE;GÛ«„>¯Bh=ŒùݺÄZ(>ýÈužClp@tÊ�ª¥±‹G¹¤kX—v�uO1,Í¡{ëÁ{Û9%QK‚û>Wë=N·…wâƒA†¿gŽL`ܤ×-õ+ï€Lt>¸2�+"p�ŸXF•â>‘�ª|)ô˜~qn„%«ìp¶Ø(³zèù¢ÔMâŠìIÄ:Kêú±œ�[ËÑãí2®åÊß숢/ÜÕ:ŠV?¢µã+ÊóUÆß÷3“¿mAëé^Zô†¥;yu˜Ž67üki‡–b{íMµDºìÌ’AáU{©èRL©É'�Êêøî¦–ïL„­éçá¶›9‘±�…¾²YÚpÇrˆ¬W¥±Ù¾û•´À¦�î¸d=øÊØyð ;Ó«_ž»‰$5€ä‹&u¡1tøš>ò=2Ãg×Ñú–'äóñHP ‡M�<Ü_¯+éÆüg{ü-íg1KîîÁ…sñó<ØT¢ŠÂ÷Ù Y¬,? 5öž˜|Qˆ²§*hù›ËÆ/›z!ÁÕ­þ{G;íà¯G:¹·@‹Êç)�*_s×ÌߚᾘýøöÈo:¯]Ž®çšCMË á{°"##È–ÜNZt˜fÍF~÷JâèË�M(M BQÿ5•¾Ž[ ÌØN•n”q½Î®,5fË:æB¢)Ì:ç‹<}�`»Q§+']\„ËrcÑH&�žeZÉîÃA[‰w±¡Á”¸÷˜îø¾�yH†…ß3†é(å«BUøíI^Ô=Ü^¨Bǃ5±óÄqпäsæ€ÈÚ“Ä]ICÅŠÐê†çFÂ]ˆ®,£…Õ�ìø¬}4ÔU�$�I€¯ç8QÚ”Ç~þR —fŒà©Q5P¯ÌÂ;·ŸÁQÄù-KqÖAæÑ¤(wབ�%0«ÖÖÁÁrÖŽï9¹{”�t 1§_ôSŸª³"#@cµ%uSÛ·¦È™âkàÞIv�×À'Cóá‡Ø2B÷j�©À~°èòÅ£ÛýŒ|öèS]!ºÈzi°NCåG7Ø¶Ä }Nð]ÄÓÇ#ðÂÉ@|wã<«K͉UŒŽÞøn ÎâÕ ¬+Hª»Ó!¾‡Ø¯º~O>'çÞ-iÕ<�è Ç««—>ÛBׯ˜‰×ׯvQ7:« ‚ÅùÈíZLcháµYP8}�]ÀÓY ËqÿS5Ü”,Ή^!�MŸÚÁhQ0†�òà!±Ôñ½ƒŽ_UWl2A·—©ï]QåÃZݹ‡/¯eỵ¼Øs$޼éi |)=Õ|š�£"uY»áLe4S,¼šÆìP†±SÍp`  $Óp2é+ó_qêÇj³íjçQSSˆó$ç ½'‰F…Žhqþ-]Ã:@×”ò/ê rr�™Ký„ÆÖóAÂsTw Á¥�'ȱ(gé!ŒÇ�›Â!¦·:T«ü“~�k©×©œ¥ áåÄ|�*»~$6qøòß>'fw¶ŸäÓÀ^à†EÅÃô¬‡ÕÆ?Lj­Óâµ~y|)Ö]ð�ԆϘ)!c‡³í|dÐÓ“�iü10]y�h¬³D½ÑtR!Äè—x�)ù  ñàÇ×1rÉÚ“$…+»ä[ô©ù/ºÿNáì<‚˜ÛŠr°i°‘n;ôž=æX€ §课ÄvüœL; ×ÅÛ§›gX5©B¢ÚmDVM�ay´Ð÷^Æð-À–î¶ÌÂj­X"?m_¢Ó™<üùUÎG6°KdkIñ»£ÌWÎ~2µ-Åì#ÀÐì ^ê[ˆ'³` ÉÏ­ÙGDo?$!�kPà+üìý/ð›"Kåq\µw„IV[)T“¯o=éýzPŒ¬Å�Îj\:êŽEÊ7 žÿ/õʲ “ ³™}/=¡K8š–÷o1üY9Qèuç,l_.—%D¸ÿ=ôÃdÆ�ö8žÅk�R°Aæ ݤˮˆÂZ›eèÕ5Âj?ýJz$ü@çp'Œ—ÏÆ““ß_üĬOjX›¬Žf­džÀ2´ÿaÀ \û³±‚›Š“kâp¹“¹àŠ·½‘ÊÚ€gÕ®É Ê×5×¾5†Š×ÍôOZ4× ÀÊÄS�3º�^�]½ŸÚ�ã«DðÎhL$l�bù\¢Øç¶öˆEŸÇlmûaèŠd÷2¡ä–Í&�ºÄ,wIÁR[ ã&“ñ¼ ¹Ž%-Ç—£Kx9m+m€ŽŸîpȧ íÆoÑñ¨½×f(OÒwóâHq�Lt>¢*/Ÿ\];â¤0us<ëaç BʨÏÁl0¾p‘i“�ÂgŠátÓ¬>pŠ-C™)ïhðtoü™6»%6ât Ì®¸‰™nC`¬r’`‡#Øìnú×ÍEÐ8v¹WnT›×Ý%ñVÒ¿ÍWHj´ }|\R\ƒŽ]9°|aÄ™âÿœg@ŽßÆ›’$$Ú©ü¢PÝçû$£E²’”Ñ’l" ´‡öNK¡DŠöxîó}(!%R‰Œ!E$£¿ÿ«ûý¹¯ë:ŸÏ›ƒY:°k³1!Ž—Â2WI˜ï~åWÆãD»2£Øöˆ”ޤ•ÎÅÇIÿ˜ÕÉfq¶S´\¬qà\8J táà»)X^¦C~&†cy¦6-Ó%ßž ýw-ü3�°À·ˆèo[†þ±Gðèpék"ÆR`{HŸ-¼ÃÝsg#¦®l¦•·BèÂ#Ùt±†åïʉR…7U]Ë�pù4I½Áü› IöÔÂÆÇdöÐŽ^Bµ–Üa‚\ÇÂ#/™*©ÿˆèÚepóõ4?ÒM‚ì/’ƒ6% üe9½#ÒCæü¡1„¶õÒB™\ú¤G€÷=o)npÕóçqè·Ü{�?}ï’P–«ÍæàÅŒåô³Á-¸13D£ÞòÔŽ3KændK‚vÇ'ùôco5s5ñ ;wcêœÐÀÂ1†$Úš`ЙÔ¨L£{jÄ9 |°KU‡ž%�öQÌ6úH:/Y£¼¤8GìˆÎK¡ý* ~®>ŒŸGÞ“èV)9ŠV±V¶bXÛ{™<>§A|,#ýVå%pù 2ihe¸'þÖìi¥~/‰íuÈÂwIçÙ„ð·X¤ƒ¥·«P]Z¶?H„%�“ Lì#ÃÇy’´b˜ehºYŠŒ_ÉAe#n{F3ø:ëT{ÝA�eÄ�¼Á›‚‰Ò¿ÿèoGÿVþ…¬Éø1¹O ‹Bêó øy¿%þ5¸HV*þa�Ø;’‘`Ü~¨�†KÌÇÚʸ2^±Óæ�±n�I§·&Š>ŠÀ´¯K¡£ž�c¹5™%ꪒ (ÇÒ]_#p�íÝêC‘îDš” çùÑȃÿ¡ñpI”úʪZ‰vÜ›…Õ‹7R›ž…øË\ \YÜÿî=,š»˜c¹}€ ‰J Ôv Šã’ öÞ÷ÿV€Xv3MðJ¦ÚÍqïœH»•Šû=§çeîOI˜ÓjFù¦`½Æl0àú`ÂñÙÀ‰+Ï�9 HâäâÉxú\Ý­ /gûa nü×Yj?z$<íI¼Z*\—C¢×5ã_Q¸:«””QD$�¶µÑŸ‹ñð�1bï¼�Ê9ä@„e›>¾Ã"àäNY¨þ|œt}’ãñ ¾æºŸû³J®±ž@²êj=·Î_ ƒîƒ÷Å‹P;ØŒ¹;hŒù>IÈmš‚uW:À»Å®¹¸Á¡³-$íÇb\’E³º¯Â×ÈõTÒO@:‹­u‡†ì"ÒÁìH7do.¬GÝ×�ðì”5©ßzƒ$q(á®V‚_^kñÇ'¼}ºún=c† 7Ò)Ãóq2Ë—Mò‹ö:ÿOy±q9>z?Ù_Y3Qئü„.ž¸Fî÷VâÆo9ò*Óñ�´/ö^p‡ñ4¨ÂZ¯;8‡›12 ~ÓûG&Iœ²¤»HSÍ—p[¬’ˆHÓ裼§Ä$³Q)_èÔ´$ršï=“)E÷Ï»ŽY#Á`'h 5ïb‰þ½A:s›öÿ‘†<²½�v‚êòWÛ“ÇÖâ‘y¨;0–öòÃü¥ë@È8…ªŒå’Y§c`Õƒàn·åm¡`–,ØšJŽMÿCÌ­‰id4{Ùó8Ì~ÓB4ÏÆPõ«Øä7TÑG‚çìn‹}š2pZ1 ¿‹­�I£7Ø= ¤7Xߺ|²¦oZž5„ÌêC°|·:ã¶JüÞ½ENp4Wñµ&®‘/¡nžI(umºGXbé´[HÏqõë×MgÇ3ggL�Ó)·hæÁF"â¹—÷ ¤òIÂNÄ`–‚29¿ò.Ž…!9=ý?Ð^•‚6éI4föKÿJ7$nÀ´YÊDmÉA¼è³×õDùÅYÄ-3Ÿ¼å? leçΪcøNv‘¢ì*�<Ó$^§/1Å-Sýi²ñi[^+EÁÚOŽ÷ÁÜ”>>Ìg±AªÙÍÆ³éo‹tˆê®¤ª7W2‡º(U9Ý€—ø1Ù¿›7¬�i{ ñòÂ9š+šíéù;Ú¦Íhj=‡º.}ZÖù�8Éû£ÁXùz*ïQk6ãU>�—ôî:Šèbõá§ìÜS§èò¼£†b­@èº>š)“†a?rÃê¾�-_€Ôohþr‘¤¿å#ŠmÊh?8ƒz¬#.ÞÿöÚ5 �ñÖe> ²•Däô‰à—¦µÐ—eK®é}ÀȼÅà“-Ê|?M¾Y›SQÍQÒ”·»FºÈÍoh³5Äó2Y!å z}v(HŠ1cÛXȈ:‡Ëú;ªu§%À»—µ4�ñ§'ÇvÃXJ(m¸ZOß?N5EGØûådî¥ù@z¯0+ôiý*¼Cõ�â1fª/ª %Ò¶%W™�–ì�¶4¸·Vˆ=õã¹Ü½þòí 7õ„σÿ²c &눃Z à-äý¿‚ž·%ȹ¡AØ -@o_[K 2hó9r "ÐŒ‰"+ìCA{ —kì-=àÙáMVΪ&E™ tçÂLìv{Oc¶ˆâˆŠø[| «ûfC‘íI„Óö8Ò»›˜ ‹Z3²�k m†—p¦ˆ9 [CÚf(ƒs~ŽáóŸØ©²!¤“£ ”Gè 7ª*=¼Eî‘§1ÝÚK#§`¿ðêžùƒÞ´‹ÝÇð Ç¿-+ÍE±~CZVrŽvlÁ’Û»1jí"ȲLFÇ¥ãÔë“�mJ×¹ÝVO‰öÀišuèœØBÁ�WD%è&ìÆâ°FŒSñäL¬î wdòiæé+$È—¿3\½y`Þ²‘¬kr¥!Ù [t“è¹±ÿ�ßÅ=éÐì|¿†l$Êé+ð�‹ ÏS\’C¶Ò‡çîW÷l¦?l:hƵJ"WÛö�ŠñBH¨Ð Ö“3Hâ@8,(*a®š ?OäP“â:œq¨ŽáÎþFí„ûȉÌAPxÉì:¼­=ȹ\ŽúNÉ õ¾áŽjÃÙ�'~†=¯¬‰M+~bAH)MøZE#\ŸÒ”ñ%°4r ÞÏÎÅC?OAé¶ äÝͽ(ûž~'ŸHa˜"§ªè0jþÒdÖžwƜܲ.áè…þ‡o¶_ ÌÆGذò™¿�ŸóÐÜo øNZ|Z¨ Uj'pƒŒ.Š~ %ÃZ�ºÃ3ß6Àîñ¸�ç‚ß®Ã)»•xÚ¢˜ò3✠_¶ãõ<œ<¾Š$=VE‡Âkl—m~ÞÌá|{7"†¢¸Wõ¦óJ¶\�Þ>à)^‚ñoë‰añB°È>Œ¡ß¼‰Â…h ÒrÃnýÔ|÷ƒêüPåÞRâX©iÓFùXÚ›�óWÐ¥‡Õ�HÊýÆjšôà1ª„8ãÞ_ éЭ*ì Pâ|J8@žy“A³aë´fzñž7.ÑÜLÿf¶BùÙj´ò~‹Ig™-ÅiÐä4B"r«X�Ø(¤³œ¡î\7UÝ–K7t¯Å�¢bª©¦…Æ ˜¸ K@»ïkUBÛ�¬å‰ðáŠ=ÎHì~Ñ<Ë£DÔYÏm¹C=FJ âØ fCBÑ3„N[xò¹Ž´NÜǽçÙq×LÒú=Œzâ��¡È?ºÕM|¡ªm_Âî�å"Sp!DåS#Ñö—Á Sæó~Yþ0”ë�CCëXKݰÙ=Õ0bÄÏ:¢°š ܵø ýœDâ.vœüÚ… B Õñ"¦øª°&E­¸oãPäÅÑh˜ÞͶGhCƒð{øk; LfÎä‰ÜE3~R*2¤Ë%Ñêò^|ùbÆ)é¢ûÅêñÓžZHá÷Nyž¸Ä}2|‡¥oÖáÌcШ�ŠOLñül'Üv¨~|ØÄIÛû ¾4r�ÿéckØi¼¦Ó7+ÇO˜AËg[Ð˘Gî ¼";¦Nc57¦·¦Ÿ…©þU‹-/ÑÀý#4=c,@Ó¥ŒF BÕ,ž�BÍJöGQi\cHÃK¶ò>hªò×­rÿYN>€¥…‡á�]¾â.å)ŠûÒÕ׿€{þ*žlÒKf“ÖzŒÍ �MX÷ ö·"ÿ«©Pý_0vƹâ£â üc û ÀŸê›\öÙ¢#lMµ Á©H;Ž3œ‚v> 4rƒº�ð=»¿•>ÀÉÃÝ@�­Æd|I“KãM�Y¼©òxØ-ލ‹¾#‡÷´Ö%œ†GeïÁ·4UM$ ¦_P5tf§å Þ4’6¿’òN�®Å°¾©‰j¿RéÌþùÄ/¯ƒFÉ«À¼%~¸š<¦ ¬áçåBÑõ£qv (àJUBöã¦Gæ>¹Dd[Å9þ6Ù¸º÷7åHüÛmSìkª_¥Б“"ÿõ¼e¿D]Ä¢íËAîÇ<}0šÜz©ŠwÖÅA…¾Q=T¾V «ZHëún<—w”ø?PµÎ«z‹n°+œ—â!ÛO0šJ¬^ ƒë¿¡¶’!Û÷9‘ζËÙ‡3yzBâ6Í‚2åeÀòd0z¶ïeü<Ìy<ä^{’;I¹Ð2d€·³ á§ë ø’û ÞG0YgÛÑzÿJÞ™EÂthâ ß]ÄlŸªŽª¥Æx¯OŽ&h Ñ»||p@µâo»bžÙ%Ü$+íšs`ÎŒtîµ€k4Qê"¬»ËÇw?Ȭ‘³�Œ3�¸úÓ6rÎ2E”᪠~8Ö¡Í ¹|žæ¯Á6©‹4Þâ> +§ýQj¨(¸ŒFÇ-Åk·àœÇ‚Ø¡; WîÏä�½=FwÊx ˜á5<û© ÌMcX>Í Üº°ù{`‘L dfêàÞ¼Ç=§x%õíðÈk±ÊI [TEh%ŸGÂðçcq3Ìy‘F-œïÒ²‰uPj@sŒx¯ü|èÍU_Ijÿ tþïÔå‰ã+›qhØžQöN€Áñz¼\rЭ¼ý Òœuý• ©Ãâ”Gˆ\f€’½s©Õ£_ê3!Ày’È•=‚âI1tî)l3€µ~Sxóv�$B�cõýRôy{ãÇב'ge˜ê}fdÐC†W4âô#͸%ý:á~H"%gæ�†ÑJœz~5ï�šêEäãz[iŽ�÷ È�%í_0q³ÒˆŠXÍøÀwKm ]&GudÀXÒwH-þHý¼éž|a^‹Õ]Œ®‚ñaðx™*µN,…ÝÉ÷A QžóßV–Þ¶gá¾R!Íîb­ e te)¬ž¨Ç“ä7ÝyÐŽÄÏÓÅ}"¼Üǯs³‘WÖ`‘|ìáÿLž7Íçå´‘½JSyÝ’~tµ<ÀÉL3Þñˆ÷èUQJ¿ÐßÔz׿»‚O�˜'×2¯�\Ût´Knhƒì¡,:ëîwCÑ4QÞ”ï »í”ý~Ê/Å…Æ;°vu"¸œÍý•­ÿai1ˆ—'c~_;çžB^A:8•áþ�ÅøkW*­7'E—ý™‡�Ì áãÐt÷7Ž<E§ /Œ¹<�3Eæ+m=.m:Ý(±´�ŽYîC‰Ùó8ƒ:±d`â:ʤ‹rêžøW/1Zˆc!M¨j{�jÖáÕÍ4@m.(8̆Ì}aä»J))Üó;T%‰¢ÿ™\z o ¨¡ùx>¹X-ìaWtnÓ‰ÕÚ4-†äpE+@–ïÂ?ãÝNå9Î$ÍUëîfÐ4ë V£©Š>{¬åÓâñs§ ðÌ“ÀA6•l¾ÚŒÒ:ó€Ü˜Ë+»º¯ële~¹¦ÁD8?žô¹ëD‚øz5ÎnûµÖ© £iGÑ$Pïî\Áã7©ÁYO%xW&h£g.�ß7V7‘IyfŸb7Ùü3�ÛbPˆïš ^‚óŽËÀ´õ#Õ»ÞN®~OçÚèÎäíÎ]Í‹ÍçÔåo&–×Ãȶj®.ÜŽ»4K>�ÿbÁÿ’5¯´W‘îœ"‹m]kɬ¤dOL XǺá‡×P:~˜:–3tÆòõàÙǼz(ÀÚ¾¿¸ sªÃæ³£&˜ðÛuPù•I1)cm£"ÁÎBwm?F†Í„82³ _ƒ4ØÝÑÅ´¡Ÿì”;Âøò½"fžH4„à€o&Ìš­Ê1™¥ŠÝvK8Ï´LxÃa:� =›Njqg4Q²z&¯à£ÆÅÞ"©YÓ9=î`ôc*T©ˆÃcãÓØ�V™›D‡ŸL¡œØ7hy0—ìbÙ#½sy{D{0×KˆH>†çãc nzàßY*€áéà|`5N(;Ð{êëÀ`{:®y*‹fñU”ësœ¨qVÀøÒr¬¹Ð 5‘Èì±k¢ü豉DEd“5A,´¹~�¤¢Ã/œb­Å»]xwV„03âþÉèÊÈ©Ãð|sø¾ã ™Òè¶°‰VovÂE©;`Ç‹fær•§¯ŸŸWa®€£wÙu’oIи#ùÖò‹É=~™^_³Œ7ëà›ÃøöSV;GÀº” ¢7ÊÉ-ì†é¡ûÙ}Õ ñ“#†nz†>·Cñ-ï2Uxkç<*¨| Þ?™�-ÛyžITdÕS Ø¿óbUAnN9SºæXŸ „‰+!ÜW8ã9CFØ|¥ˆªEOÕ v„·~‹àÖßF|iQÅÄÄÑô­|¼é7 a·Í_ê{K’”›ªÏ†Î£¿ò´¼ö)X²Öó kšÁ®‹íG·ñÿº²Šc}A�÷ëÍ#¤©SxRÿœèóri^å¤<§³ –îõQFË:_ÐÓôƒ€BÃÌUó yEcXBâ#jhƒÏ °i²$[ìËIõ†LœœëÄ‹?BÃS9-?ÃñÞÊ|øŒ‹Ñc¤…tέÀ^õ&üîÂO£E2ñªA·45øOµ¦ëò7\æ[¢§'ÕhÞòÍD™·¦ÂOýBƒ¨äÞ>´ _Â>ÿö”Û¥ »gó¢K¡ÓžÐH'Ôè"–óR&^h¨§œƒk†îQ�_ˆÙH1~—Š÷·ÿ¤ïBV�´ê<žUL59Ù.ÉQ}÷¤’ ¦QrªÔ‘Ú÷ûÓ7êù0>eg¡ÝlžW‹&ÏþŒ%ò±¤¨aìš}§:>"+æ�ö§Gø¹«Âð±ê9bg"�«ì°iÓ,ÞFÜF}1¹y:<Õ{Eºw\À ËU9g¿zÓbŸl2í”çë׃àǤ£æn%Ü~E¤;Pï‹2ûÙ3”z,e©Oû I2j$o·,çLåWÁ¨ð*,‹ÀÛàò­§$†Qátv�¦Ï7ó4-¯¢æ[eN�f U•šÆãy€ÉÅ{àܘ94ìu¦­Ðù­ņãqܦøW‰^ëa&2ÅiÇÄØì‹+6$p/‹´Ò-C»@j̼ܽpë6W¬›+Šæ~™läŸÜ??®¿?NÏ5^£Nšuhf¨‹Ù¯b¡Æ¤£íÀDi®eçm²;JЧ¼›¢gßnÃa¬U[ W‚•u"ý‘¸ç™ø³L4�¼ãaر, ×g›â˜þ2ºuê Ü]çG…C!ñh9YwªÖf-A�âù˜ðf¬Ë+#3ŽMB�l\Ö5¡“}6ìÚÏ“$âØq’ñFl· �¿|TÔQ ¦l§‹·qo�0ºØô‚yå²óc:Iœÿ÷µà‡�øSN{t[éúÖ5t@ý¤ÊŠrܶ%cŠl<ôÞÙ†»×hÓ›óIiåkâÎeD‹Á,ýÍ$æD4®dDá\ÛkðõE-<Åg¤[è÷MZ œ n„Q«<¨š ­v£˜w{/Ý^çn¸sñ\4ÿPNM-Ò0Èõ+VÏQå}Ø• #z²¼¼3‹pÉtÈÛ¶ ªtëéÑc|¨)ÇA�üVÜ4¤Ïä]Ûxfœ‚%¡ïÈÇ!L½ìË^ø*•Ü ,8/M¢OífÝø<`·x>”•ãÜbm¸Ö«‡IÆ.eÂ딂äÒprh• /éà'âøk%f¯A�Œ}�e�i÷W@´�ÏV« êÌÞÝÌËø06O{ðs2jš©ÍjEŽÈÀž¯U:Z…SCUàX™¹,Ðm)ÁߊN˜ê74lbéÞ²ñÚa’:Bi¬ †ëLƒÖ¾·¤Ê@„çýÕŸ…�Jë(ÆmZÈ PáGîôz¶—«Ž#“àæßt2[ Ÿ ‰€ó´†Çzkq¿®Qº{%/�\�˜ìPŠ\é} éä§Ùbpx0ž_ô—Lyq�º ߯£BÚ ´=ï¬ò‡2aÔ²}KvLóu#u’xå%ùq1›ž_®Aö_Wã: µ³Ý;O»âþ±ÐÅ•ð�\«6ˆ ^²÷>Ó©C¯¸U�(i܉¯ß<¤b|AôÆ¢HXº©üÅLŠ"ZèleFb:•yGͦð^?¹@{²É�—â`Ò€kŽÉpr´ÅxéAô \�ns~´Ýc/äTÁ)·r²÷x+dHšÂéwä¿&Šß;bøÂe øåï�ë­ÈyûˆÌuþƒ1aÿ,°Éƒ^uU…²‡ça2·‚¬>êGüÆ.!³ê8Š�²Áý‹!±©<ç“™ïS¡¡Z ^‰ƒÂ“D¶ÿ? Ÿð¦¶â«àâÁ{ ¦‰ÚÅ[qñ³_Ħr!y½™K§l±ƒ4ݽúCL =²`9}h/vÅü ¦øH&Ìœ–°«X7KzøÒ|¸bîÅlú¼'z‰ªy8Ø�5‘˜«bØ2‰�¶+ÉÍ-R]èÅ>¬+Ç4Yrs¡/Ü“K%²žú�~±‡ŒÖß$2;}Áÿ»:ëÕw‡ªŽ¾ 6a�ƒ4囜Žó#Ù�µÒ(i7BÖÈŽÒ=¾G¡ ÝéŸgËñ–¢¬4ÃkéÌú!JŸÚð/ÿФçüE*ºú)Šß}í |ö¦†Õ«qå®iÜøÏT/CËKHá´ÑDg"që+–Á±uḖÖpÓs¯†Ê2M¢épg¡éÚ%‚º”Ñ@HŽôË!-È?K«\fñVçÙ@�ÍS}=’|ONþ7¼ÂyD=÷<­Êpð•=Ù°Þ‰¤ÏŽ1˜>õ%ü¹5ˆ'�ý&…_¡ö¥c¸Îºšûrø”ÜÁþß°iÔµ& `dú5t:ãO>| ±û‘Kß„È#Ów`ëÁåÇý$ÿ¥5[øõŸá®†c¿¸0ó`y;RãŽ(rÙî]•/J6†:�Ùîj¥–„»Œúηñì EV»,„o�ÍO4ýî ¿<1©0æß]êD¦>ê‚ÓÇÖà´ÁKÓèÇjÚá×\b<¾…LjZ€xHWìœ,¾È £]¶£_Ý\°•q«ýµÜKW’1;¢�éwK!“ëŠí ôhU:¨h~›#A,þHBó«ü� 'Xp;¤Šî2Ç™‚Æhlk ÄrëÙåç¡‚ôz4üì ¦ ]ÓE4^�À΢áËa�ŽÊ°Ü#œØ„ …R=½ë²̦ÊЂ­F`•ds®¾Bý·‰øEáFls†Žâz8<@ê/áqé:t�œŠ[�2éä/?Ôzû+Jõà×¥L@Rqæ †vˆR¹sSIÏ�;l¹æL7s„[/ù æR$xíÃ×… eæO/ØÆÒÝÙÏ1îu4Èšo†äg©¤ýè/züR +uÜ•í4±a†Ýµáû\‡ëO$A¾U3Ù”ôŒÄÀÞ˜èÚò�þÊ�€îè¿ä©R =7Ôç“1 ¶�Ü‚Úô Ú)xÕ$gÊ¡JWü¬‡¥� %±„zç‡ÃÂò"2ÒÉ%¦sl�DTR°^ÿ<�ýún*Þ%œ‡}8žÁ#K,ñÙv)*~ñÝiWxâ>@­uŒ™•’b”¼ðF¥T~Ã6�(âÍVÑ>éX¢£è ‡òæàK^3Ëa0Êr#®Ÿåާû:°lÃ=6zÞ?.ýö޾Tªæª×®�m¡DÄc¤êÍ�ÓYÝÏ<§¿GéÉ0-jm õµOid¡0îëÎ%çmúâ7‚m —í¿«Â­ÌÑk! ãÓN†’gs‚ÿ~ >ïöý‚ à-ÍmOî“”[�}²ˆfÿ–2ü:¼�6YÝCî�©œ<õíxc)}½¸_½‡t �"BkŸÑœ£ÒœßJèqQ}øl&ƒ ‘¸Ý%$éžË P¼ÁBDÞ•~:¬Fs&¤8o*:¡Òo äZÅÈ–ß4Öt’uÙÛ ²åèzëgô[~–á½¹!è½k&ï•C�³ñtÿ¶s¬õ¿îmßÚÃ,Y[…Û¦*Á¯D34ÉØÂð÷ÈÂ÷Üìé;±ÿÆvT\kH›r_âç܈¢ x×ÃŒêBB›=íçÔC‘…'4\·ë×à°Cö�¯Ç©‡ý 7v%Òpy²lN •ßÃÇkx eØ<$]ÛèÊõI¸h×:¥O©èï,d‰S€6õ{>Fþø¨¢ëˆN<Ï ž½µ¾{0¦î ê~]AŽë—BOi yÔN ~_$ã±ô‹W ‘7@4� õC K|ÍHWã«ávàf82¢ÏÎ?7›#‹ÈóIYüÐMÄ'F0`¡§|0‹âC-Ÿ/¦µ�lß°>°¦P¸¿*<㳊7�èáÚ!Ôî” úÍ:‚e›áÙàjÕÉšýH„EžU w¥‡~|JMû‹Ù·ü˜÷='èAð�VO~¦íÀå¥üø>h8½Ä– 3ðćRÖ(A…Ž¿^mG¥qH>‘G_Å@_r: XÂÒwK¼™Ñ'-Ìç§Ë¹ï»ìh»Œs7¯—ºùÂõô L¼1J¢fb·n -t¬Ã¼f]ÌT?ê÷Ï—¤ßî/"'~ à™yÿ|£dÜUü@ºdêhé 1�öœÅ9W™ÂeÈó¬Xè¢R´iùs\óâ¸{¯‡Û×÷ã?Éx8?﮽A‡¿Ý$}ó¨ów[PPj£Œ¡Ëß¡Xo16Ogí.Ý"wø2ægP1ª�q6ò¤6›[Pz²‹Øl¯«Ö9¨�ÂÕ’“Y�æ‘Ñdwþp¼8{/L%�?\�ñs… FŸä #»*ï#u(�Óöl2Ö[ÍúÔ͂ћP´Sóü¶0^©v$´ìݬŒžhåƒö7µpƒŠ»rè@ˆéNÙÎ*\uË>Í©ì ÜŽG­ÄxWçvQm¥éœSCpÊš××KZ¸¾ pf)Wjeì/€eõ 8|ïlV0ô98SŸý&­Öœe^•ðjF>ʵÈ�š[&4lÌ¡÷:;‰÷�˜ÌI$î÷©Ð©¥4{ƒ mmýAv/ý¶]ÑàSýÎW†÷'è"jkxÃ¥³çqq$wu„ìê»äŸ2,úo ‘ž¤îq>^ƒs½ÛÉ™mŸi.‡]ÍR¡ù�13&Ñc˜–«Ä¹Ïƒ¾×paù šÝ\F<ϧá¼ë‚øå©ê§Ëböëÿ Úuº<Ï"ƒ›KHãÇ>Ú¬À2�ÜÉÖíÓq,O Óß:Ò³êƒgýq]쌱Lgüž]d=ÃÑüz,žç$£í“̃"¼‰·¾˜zæY²ô'é¸=axA;æ�¡>;™<ù"ÔÆž’IÇz=“§áO—VT¨Ò�ïé+`~<¤?¼Œ–ŽŠ\“ j£—Èpù\ÐЯ‡ÎîåôªZþ÷½‹îéVDlF³+é8aÿ‰v»>Çœð|2ñ ذ ªxO¥R÷03ÝF!vB^ÜÖDÕ?ÿ6ÿÁuXn2„�÷AÿÎ4ò4Ú‡”®x�Ÿ �@eI%Löî�ó¼®RG2CvA�÷+ÚÓrÕNÖ ’ê&P,Žv�X£ËS'X%™ƒ^‘í µˆ4Èw“ìâBÈL_‰ò‚ÇѧU–±ÜCÕÝhÄ'>t¶�!‘iè‹ U…”ÿAé?o#'SŸÑ¡”|Úq£3Τ |>2§¶×‚PË ¬0a?×—�b˜ãdAΞ ‚ÑÜ jw„|ªÂ…©+áÍÙ!bà £OÕˆÍ×_4ô©´C̈́۬ÚÊe8Ù8 õø8Í�P/LjÎa§új»¥–®ÙBN/b8‡�¶+b„|™O›pŸN'µ=AU[Õq(¯žùv ƒ:å]?»<\½úîÎGÁ5ðH ÚÈvÃ4Ñ?$ö‡µšâ‡?ÿ«§Oážø—vl˜„EbÃ3kØg î]Ð:YMüoÇc“Ä"¼ºe9c Æ<7CÁË"Ôí¿:¾V›m88¼œÔqê˜f0H}særBÓüY¸0,‹Ny½ôÁtcT‰ãÓ{Ð}ÀÉÚçx-b;À—ý�›{Œ²ª`¯Èu6쪸^�séÆ8vÍÿNÔSëÏ�¸±€�¼9ÑÜ÷Ò |�ŸH>Ÿd¤–ÐëÊVSV†Ï•~pw…FÕühI«/ßzFk\B!£n YeSÅ�ùÓ͘/¼ ¯Ù½ÿØ`¯ÎÑÃïÍAÕg3ÎܤsÄ(.t‘&Éà•¢KV@N« |jÄ_—ƒpbÊ(ýå' {­ü¡Åé?¶µóL×ûHõÖ?¡]Mªð´º*CÑÂìKîTá–ÅÄ êf* eOÎ¥à<<­ÝÁüžüÎÆ¼‘A5‡û„0#8÷… hÿªdk–ÑÚ¸FôPSãçôð´nfGôzøeÐÉöûN²¼9bDMŠK¶eΆcç¿�Ôi$¸¿‡t<Äêô‹�¾q,Ù÷bxÜ5#cU»/?ÂÕ¼~røk;Ý,ñ�4Þ½‰ó4}ѧe ®‹ŸÉ›¿É: Oˆ×§ÒÔŠ†c«À4TÚ>—à .¡o»%!¨K ßF52º ¯cLÂoºMe Õ�5 à1ŠœE€Ù §²N ⨢Ð÷®ÉIc¿þËæº7ÁÊh˜œ˜SVhó±oYì×ç `Ÿ²šœÀRóéò¹oH$s‘ú ’½Z%»5ŒŽ™àêôRßDÓ¶·ÑØï³¡­4†îORƒk}ɶÏ_P¤½ÒP$e7¶|)Àiu}†‡’иÈ£Î;`ÿ¦xºrõZ°˜(…6Ù9TÆç'|ÿè ‘_/`ô8Úý,eÏÒûTÞ{-&ÛÿæJ,š£Q+qXZœªªKÑשÖtëþðÇ,˜h¾ÒG�ÄÅøcQ$Èn„+:Ì÷ÖtØ#Pn˜N5°kÒ’®ôªg-úHgGÒµSváFã{³u#¾ È#gÅÅ@ÞAŒ×À‡C}08� » !a®¶áƒM™Ù¿Òᲃ-Úß’Å0ûázÿdÿx A°ÕJüS!„ž¥ÖäRË�L_l u*²ºCÑpؘÝ1ô�ˆU­�oÇžÓ!Ÿ:ÿÖÿ߉ ÅsiLyc—kpsÂfzéØ4wX :ß#i›{$¤ÌŸß-ÃY±›Vß/ ÒUØzg=´œ.’�^hrœoÞ�ŒÓ¤³ æ<³¤‹­蜣z`~Î =5®CÜ!QðnN _r…1ÙÇ�̽|—œL …‡¿; ý3ÀóQÛöÞšèºI£ˆ-p�s‰˜?<‡ª÷|Q/û-qùp€z…y-ìð]¤¤ºr­æF�óÆ@ñùiÜd|…Ø 3pjÆ;RÚå �÷à ƒ¾Ö“®Ý©ôúýcö/‹=&¨ïÉ\NÂ�ìsV4Oãêýxƒþ~v—¶Ê¥ÂÙëbàó{�šüsÚ;'saÏ- ô,ǺcH¼ÄfrŒ%oÀ»ç[ðwÂMúÜmšUž5“lz1eî´’5³vP)þ@:'ÿ_®@’Œ$|¤åÛ ˆ¨³³¥O• zEŽl’À¯¿øÕEš]7ÌÐì]Œ»‚¡#LÀ*MfíåO´mÇš1ËD¬…Pøõ,Uó§×¤tÁ[JŸMŠ—ÇÏýÄ(Õ æMÕ")÷fB·ö~Ì�ÓË6'÷’P¿òBï,;�Ó çM5åSÀ0ýÀ/åI2VfÁbwU24ÒI~[ãOsUr›¯‹ÄM-což»�‹ºøˆÄ¾ècþí‘ÊY ¬@‰žlnc9)ö_Eøž¨±!Þ�èñš0µD}–_]_9h²zÄM�Þkx©  ·¾Öa¾}�™û¬êß2*6ø’ñp‹ÇŠÁi˜à~Šö.Ê‚*7¼0lˆ"¦é ýô(*š¼¥ÑÅ®0sø'Wsºšr…±¶*ŠvôǤý”\ÀdÚ²IŽ[ÌüËýq¨‰n-¿‹¼?¶Äèx)&Íq_õ'´!õÚ¥‹P�Ð ìŸ:F¢¿“‹o_cqËQ²ÿL<‰.5§ÆËS@×p*>ý8Ÿkú’G?ÅmgÛúŒáƒÿN]ÞÊ„HE�•ßm²ûê^ö™«4�5žO®²@ “õè8Eï^D¾yWˆ‹þÝ5Sš‘»c5ð!¢*ÆÂßü‹´§ÎÛ­ÍIá«tØÐ2 šâŠ©›¹5îªõÄî›Æ8åNî/± fÒšXqL«¶©ñ>™n—˜ið‰Ö’ ¢.˜òX”9‘¥ˆWšAã„(ohåúÐáž_¿´Â�†F*Ð G rÐlü2Ä]ŸÍ+ùL&"|aKK¼jOg\naþî+ ŽO`oŽ"<©á§&Ô¡tœ¹&†i!¸µ÷?â47_*ý¢«KTá¹Eþ=lC•fÝ%5{4Ðd­$ÖÈ*amÃOÚþ»�ž}Aµå‘c$ŒcÎ'Ñ#P_?}H\|céâ’JfD&¤¬A¢WM_é`Sí56Ve‘ál�e4¤k‚4¾øEGx¸(!>Î=ŠÖçºPÝS LJæcÏÒ b²è&ÍŸk̤‘ÿ,ì-ÞKAê€7$Dn§{>s°ää n/¿1\ÙüŽ<±ý¬ZìL"úQËé€p2{hé¼^r–iã;ËŠçÁ¹XuÆ"³†»î˜9üì;…_:Ó™«VoéKýbòG$™™µ%–±WÅ·­eìƒîç.„J+�àѯ \\‹-øxï«ÓÚYZd¦�^[;x tš»�¼gä¼rõÙr ?Kpá•Þ=l·°&ÉÞïIº_:øÄm…Äs¡Õ[¢é¿�´)éÚ”}¢‹T.2}}£¬Ø>1œ<_€—Ò4ɉÄõ웣°Ôï>7¶Ó^ú­À-{§1�Mò�)¹H–)1e–AdùígÔà‘5Z=i!Y»¯@mùt £ Ž�˜WH½ºgAz_*ÍØgK§ÌåQÏÖdÐ]äOö¨}#&�â¤'Užý3ozê¯Ò€ã>ÕWoD2}²'h›ñ³Ú_„쟠Â[]PðQ#Ó6,…U9A]AAüþ~2Ã.†ºL§Ç&b1Pø%1z‚«f󟓆°À.¼ÝBU¶“»Â‚ÔCXê4e°©º�ÂÓ 06a1ÏáØ� vb¦¸¬3ĺ>¦/ÇSõ¥4žÏ—kí$ßwê²�YG¡›“€nG„ÉÓSs@ G€†ìÀO½Ñ˜²ÂoÊ¿açˆõÃSP;œ�ªO»Mêˆù…@¥s97÷d½d_�/Ê51*ä8)óqF+ÃHœâ¹?\�HÎú4ê3G‹ˆÔÌ‚}‚5„6æÁ›tW4“ƒkbù,CK}Çp̳€Î€"/¡L‡úÏ‘“wì@F¿�ù (Šg‹ ð¾rjõz[HËxÊ®´1‚5¯¯Áèx,ù”Z Ÿ3aÅÞ*–I 2�öAל#઼ˆÓr¥Š²#@9\¦ØMAQ½@†pÍA]] Ïj¾¦×gÐõg¦âÁPÔÚ5åݰÖZ øí̘òU›8‰W�Dþd˜y4”šçì‚­á—éÒÙƒDýd<´kÃþt/ìPë¢E^T\1¦Ý¢÷óí%‰FÔ{ÜE9®,8Ø_ÄåÏ(˪5‘óŸ‚JL 8=ƽ!/J'T^ÂþEZ”ÞE)ä¿¿Ÿ°rv1-Ý™†Þ>[Ùeqe4ìx&*§QãSŒÜ± ï¯÷§ Z³ÐoÏzÈ 2B‰Z†Ž«æ�¸þôÁ•hØP«KÞì‹Ã{NŸÙY"¾ ùâ;n ×t�35n2X6t•|ÿ{-DeÉßóHÑRc·ÂÁ¿¨EÃoؽ� ]¥‹[5QWÁå×Î ±GÑý“0¦2rdÖ“? 'ÆÌQØ07µ“]Y––z¿ Rt1&y/¥Ž"ˈ¿Fkr÷,WÒht©ô­J#¹fìPq)s»h)Q�Ö&ÛŒèhãUö¦« ösV@²‘ ùÙ1Ûš1Ó¿gœB¥)Îh1 „þ§cêW?*Ÿ?Öë_À/¿’)fçÉKÂl¬Ì3\áUNÚDtÈUÁKnÎþ²®^Û†þó2hÁ•ÚÕ%ÂmÿTCÎAp¥¢˜n­6·§„]2QAŠ f‚§SSë �ã¦ô¨Ú ¶ðÆ1PÚ¡¶OƒÔ°<šù_�ö5…*Ĭᮬýa4”[�ì¥÷4±\ r—µÿ#‘T;ÒÛ_Åd�˜èñÃ�]“t›ïø]sOÎûw6‹¡ûm¿NÐHU_ÌÞW -BAî¿ÖM/‡¦ð–BOˆ>V�'?Z™þ—'°JÔ•‚1A÷0û&¬�’)ógáÚQ%Œ¢�4‡{z‹Œß÷Csk]ß|“̾9ˆµ ö£sÚej�šGÎßçþe×_$£/u OXž¬Ðä³ ê}DQ@„^18kîªC­ÎFÞŵu¸11•èìã’]†› Vl yÍÕ¦ë8£{+>v�D¿e�X^T„Ûº‹ð«ÖÝ?‘„ÃÊsP½þ>.¶<�TÌzBðÙ�3ÈÎ{ûËö¡•p%ëmx�jÁjvïÇfÛ=?ˆ>>Î4ŒzPŸïψ�  úO¯§‘÷–Ð�í©Õ|Øé¸*·¡æ:è¤l�Ö*1”­6…'‹š‰³ Ý7‚®ÿ|°¸ ½uhÏÓUx»3˜èe-C›Ù(|Iroù¨j„.�ð&kl˜L£bpeDL,� ;†Ô�ÏC”×”ý„òY-¡ŠÁ—ÀC}n9p†˜gEâÓÐäü‡ô‰©Ó‚éxüÇ–¶«ÃI‡ Øš¯o b‘7xâô"Ñ$ø&]Ñp<ßiÒ¶êU°Biœ™út:ë¬êâåöpÛá¹*&¶ªä¥¯"Õp¦¯5ò ÄÙ’vø‘»�±Íõ"SÐÛÂT™”C‰´+9õr#½Õ$Ž9…å¨÷ì4õ{&ò�Õ¥��,FMÍ:Á7_¯Ä@µÿQlf�Xv]™E™2$„ Q(‰÷Ùë iRII©¨$)•"C¢ÌC†Ì„ˆˆŠd(áÙëM…J _ƒ�Ѝ�¢”æ¿ÿxîµîûºV0*ä­Á7›«Ø¥+èt¡m´-€Ów&Ñy;·Ó¢?uôÔžplßÓ Ø[ÔðîÓ?„EMÜïþ�êl8JùòÞÒšÌ�ñMx¯ôàf_ñUJ¥’ó³qôC‘X˜@C wbÕ–xˆÏ¡!ÇcæüAºæ«"­�Õ#bVYðíðT˜³ûg†ù=\ñã,“ÝÉÜÛöŒþ÷BŸY¯Š[ú“Ix{»0Bš¹Þ²† X&ASÒi$²CLºÈ'r{ç3zE6×\½@¦¥;BÄI·ú½±ÚøÊ$KgæÓ •ÀòùŸ‰{E,uºó„DÆì„'£™XuªÄÔ�迎إ�L>艂Ɋ@j¸·œ¸&�õ_ÈäÍ FcuiZªELæ©Qïa!2æÜVú$Ïç›4[ rÀÝOUý¤�ÖCÌS¾X2¦&ÕÓ¸�Ó.sž†Ñß�”Qn×7øT×Gª£§àRýçD¯n -éÝVg8¸jŒÍHN!¢l ŒND¡€U,³÷)Ù^MÅ„K™j:`˜‡t¢=Š-ô¼CÕL¼|,�¬?QËy÷s9|~ ;ßQq¹½hQ�.;s8Œù9<°¡Ž$š†c£î]r+²œ(Ì ©kÚ¯r3æû¤KµÝýŸ3‹qú“9(·=šæºxÃ^ÒÙÚBÂn—°ígï�É/‚°©Ò†ðËz¢"¯Žìýë�s'=á?å:6zÞ\p~%80©önδ�ЧOQÑÃôÍ¥aþ&>ÄÝsðÏw}{LfÙW ÞG½(\ÜD\¦29VqÊ5Tu¬€ ÞáÍÝ4¦yÄaAN]0…¦—דÏf‘t—®:9¸`ï6QmûÌÚÄÇÀ‰ä]ÐxH FÂ.ïÝP´æ–Y^!vŽ¡ #Å ³X[O9ƒiðº¢ûøY�ИÏíðH$ ¢Ém±‹4S; E9=>„Há,™zJ}DbÅq4ÐôÎÈblÚc"«|�éÏîa[%-™]‘(}õÜ3Q�¿GOàØSUT)®"KTºáœ` ,÷6A¿H-Ô«L§¯>z’ ÀXVÄ+=¦�òîøØÉc²6ÃÎåоã,ÙäCD÷ÊaÔeyØ{ñ UþxÚ]¦}öÆøMI„ô”ÛÓmß-Q²ì<Êõù³nãÄî�7]Ø€žðrÁ÷³;š,{ÉŽ ËÃ:ÃãðŸ�lÙ¡²ªØ9V¸Yê"Ñ^¦€›^‡bÞCpQj‡#êYäz¸Ü”È §C„!kkê—›Qý¬fb�«…û¥bð}B?“=íç´Y >Ê&&Íð_¶}ÿÝüÖ=$ïïö’Vµ•dÎì$â=K…tÍ V$†\ìøC�›sÚùB11õ¹¼~eý{ã8«Éƒ•þA|2ƒô$®¶B—rrELO OßÑ÷äÉÃ!6Õ1 ái-gƦ½èd:FÝüÁ+C™¼qÎÑÁ™¨PõŒð8«¨þÓ4|ºb:ó½h:ð6{‚¹w0($²‹ ZÈçÀõp©/3×lgå«.£mŽ]½Ž»,�e0ƒ9®¸N‚Èr4u\ Ý×ÙÉ@¼Û9䋞ᮆÒKë 6w*~‰_OË×İV·ùé�ÿÌqï6;Ì� ¾'s!áM¹bø¯t]bë¶]ÅoÁeôñËedB ï4R:GbwOöƒƒyÉl«‘“¡ä7æÆ€í—ûp7ñ®ÔÔÇåÇ‚‘7® 1 Lkörö¼»'i™ W‰Ó€‡¯PnNDXl„ñôÏÄ8 œ³Hu;¾�Ê%¹Ò¢às"øXbÚ·Uä¨gcð'Ùät ýJÅEcû 3zï’¸­�ÆÎ%õ0àûfÜyw o"‰kYÇ©šLÏ)Q�ž.Mºãát‡'qÛ/…÷ΘãÚÊwtâÚB:ß<f 䳂Ñêô¤c2õ~:“¬=!ù³è¾C³àà|fƒQVfŠiÒY³J±¦‰ÐϯF˜P©fá-B…l7�÷ =ªOÄ3ú‡Šaò°Ìyâ ®…30<Ë•ûȦ»çH“Gc®€2ý‰PaKˆÄq2]¶€å,G �Wµ3õ�`¹‰ñ‰j#µÜ\6pç6Å4Ò~‘ŠyGH¼ßK(¾°V··s]LÅè8�Æ7Œ\a%Ô~lŠe�*ä¡OÙ>Z€“£èáG–tÑSÝ�ÙÈYi´uf>™Aáç« ¼‘½›lx°�5')˜ÿƒ˜w]|OGößb¾÷ŽE·hÐ=mH&ãðñòI²z_�è�N6Î)†ÕÓ-q|ãY¦ÿÅ ¸½Ü“³sL’?Ü¡ÿ™YuYظʯê&ÃLe¤Y§ÈíG8\pKžG“�[ôPÏLïC±˜¢NþpŠÉŒëÕÈ­L¦É]KÉâ~!Ì‹:K³b0îÂcô3J£s‹Fëˆ�'}Ðyöd~dx6ÞX wn†ë]Irà1\èñ‹îÖt†Û’'áléyò„ܤ®ñGñd¦=éküLç^‹¤EÝÂ0g¯7)ú×÷2åQètú"ÛhÙþ&ËÌJ0�Å©-á¢þ}lz=AÓLê©L§�°o¤{¼ÔáÀã‹øñË1¶ÅðÔ8:ÑwsAʪ…L }» �¸8–‘åÓ[ÉýÆÙè÷=‘œHÊnpó&"é{á«»]nßÀ¨¶KR�k±h.?ÁHEXâð”]æÃY¹$ùJ?ó¤ÞŸNsFÕSˆÜӭ̬犰ÿÒpË÷lϤY·rýòE·½Ú§ãÒ¿¾Ä~èž Ã»P*y]‹U\ö€Ì�;Læÿ¬ Æüô¡ü0­R”Æ�W!ôœ+:ZD$†æáe»’žB—œšE¯(q‘)pgX[ÊàÖA+ZêÀ�ÂrÜÞoIÿ yœu¸fº=·(ñÍ€yT…êfCÃpŽrqer 4;!=p_œ'ÒU •Oã!ß9�ì°e­Ò¯9'Ð’'FŒN«`¥Pk°¡�ü:Ï£3#¦qEkU¹i²‰TÛ.ƒNÉvÂ7eÔ�9®J,!8”†ù¿u1ùv\Ì¥OŽ|ÇÔ6CîÄ…íP·˜D³"KvìÂNé¨çƒÇn‚V£ ß^Žã¼Zñs8ë>%>ä+As£b�½d�Ò6¸zÐ í% nV4Úü�bœG�^ƒ[_¸ ^áÞ–©Âl’ÿtzeÚ}Ìó¯ ßMå±°#šŠ¶ò@9÷³|\ cÄ`êi‹&“ W^áóº«W�:nŠ�Lÿë4×sœ½²HWB"ò‘­ë»=•õQ̆RÏQ2gÚ+j=TD꾆 “¿"¯‘û”=¼ˆ¦8o¢Kò×áð‹XÜêø3g`¬¥&TÖœ�¦© 9™SáÉUaX¸kˆÌÃí;;éÏ� ,*Ê™’_¸‘W�çžkÒ™£ Û¡ΦÃgYA޽܌´Ð¢b¯NCü¾$ÚS€Š&i“ör,|²·¯\ š£êô–¿<ï©$�ˆ¬ýK{ 2q©çÊ@£³å¸ù»6´J‚æùû¸Gs!6ûYp´„|a5yøÓž.K€Âƒ¯Iñ Z…­$Áô ®4‡¿J"îZ€wŒ¦á¸ÞiúæO&„�ž†Q�  ¹£[ÄyÒªŸhP÷eÔö²À¹¬ �[£Èû!¡À¼ZO‹ýCÈ|éøœ=…˜»Rœ¾P/îfo0ãÝzAã �Mîu û,¦ÀÄù¹¼eæmø;£‰ÌzŒ#—b�k-Ž*7`Õ¨™:ðŽö)‘àµ@`’•â7ã–.~Nü¶ÇR™~ ™ü^�£úí"¬ÉÞÎ=±U?æGÓ¸á¥Èh‰ó,…ëœ8S é’@ýÖ%ÏX¯ « Ýÿü*Pbì·«@Èðì<ž†š5±}à| Í##àŒW‚©Ò^üm´Ü KañEaŒ�,‡^f †Aq¼_m”Àw­™|u›Ôû°êGÓñISÙm6 È,æn¹i�ÿ-ÁV,ǵ_“a/ˆ·«ƒ¯aD¼Ý ã³Pw�܈ ¤cKFÉ»tlñXCòÔg“7ÜmäWüfÜõé²ã¥lŽ$ÖX@Û†{ }S0m;2D÷,˜Â5õ(!GME@çÉÞíš'ì&¡&NÅž èV@_'´-�‚^à jºAÿÎ:Oš±X«ÔL÷.¤.cñìV«éÜþ0L| W‡‘¡£ØÞ%°}eFï,¾@–ß“åšÙ“Áƒ9 )!Ì«6"<·€ü•.yÓ…%‘ÞÜútÞvä;}›9©0ïîm"M š¨ÿ3Ž~ˆßŠÎeÉØ1ñ‰ë€lf;Ö˜c »~l8Ž·>Áñ“?˜MózÑ~û8N_/à Ÿ²L}í08vÏãq—¦BŒB%Û¶«…íÛTÆhtqÝuá¾1ú 1ÙxàÊΧ©t¦Ç%,ù©ÌÛbFùÄÁC>”^yÃqr\hþ_¤8&$j£Ç´t¸ñ7Bn<°†×+3•{í\,¬’ü—©#‹‘£pœQÐT†bÓVº½+¬á¸Z(Jm LŒ+ìZâ öýÀòY½ä†ý“\‰/Ír0V7—¬:œA>Ô+øU;ªqô}8J.=kæ,ƒ n|¡‹—4xòÿ‰`ˆw2†ËrÍãŽ#Í#s×¾¬ã¯¸N –Jpoï(‡if÷˜É¬�ôWƒ˜­¾ K$?‘²smD}l-÷}ÇßáÙðp·xNö—þðóìpu3™ j–t ÞL{ÄVh¯ÀG±A°œSlV u-:X�£E êPøU™§,%Ö¢pót ŽÝ�æc$u·"¯ãi#'qÛBÞ¶øû¶iÀž\[ž]å-LHúÅlIš  v Óx¸ÅþNÑ©÷ dI¬žt¯¹Ã–µÖ’¤‚Žè$N<*o`HE´9‡`î“,xð¥ŠDŠ-­20èy�Îf¬VJL}ÂP)þý\…RŽÁX'•Œdþ}üÎÌÀáŽç×ü—ܳË#7žH0.–�ÏÕÇ8°lÏ-#ûEëàÎø*¨r»A89×0€7•�NÂiZÜó;ã©Öz “äÆz&ÐkN›q‘G7* b÷ÙT2{2‹ž»™÷$Ý$üÁ׉s‘Œ‡õãÓ¬8ªlîCç…%âßä<9½y ÿ­F/„Ö›ÐÅ`^--žý ç¥Õº}¸®{²°¬¡“†Îm² ›?ž¡{â%¨P¼(†n©"úN8Ã^._‡&Q]¶v3bÊj¾aÍÔÎIg­–gÀúQ Ëk‚mƒo@xŸw±†<ß^@dënbrœ(|LuáýÊŸW¦ðä—Åà:+|àùKUáêB9r/³v‹à× …xµ×{í�€ G€LÌ2Ã?!½$f¿ gˉü6møàÇtnªv02zQõ³ 5ÀœßBV3Ê�Ë]ÎOþ¼^Ë{åô�Ù}£œä�§3ž›@îÎk S4ßé» „Ý7º[éV:ñ fÔ Z>Ïà>rR ÷¬tCm¹8âplŽùÝ%¶ÚXå >»ð¶`:9û‰Ÿ»ÙFŽ7ÇkˆîècÓÎlcªŽ¤áø²|Ž–Ñÿ—ÆSÆÉOF�›<ÿ<ºuVÀµÚ¼é[À¿µ“ο“Ÿš8úñ'6KŒ±¡ó*ɳ°÷ÀÜÕ‚´ç«`VÄFn¥‰o$¹A)Yô8�‹ÏJ¢Ð1rÙ«~“îiœÇ-y„óͧÿ†X8œžCÖáôEpœ€[y}´$YͦÃß)}ö&g:”�Dðn|o”üõÆóóiÃ'¬|ÿ'ígѽ7”·žs6úÔÃãáaz|Sd²ÂP zT·åâ Qz²ä¿t~ߊoîèõî%xmLj)ÉÀk -âZ'õP»¡2LÜ´gªW’éuêèá<ˆÛõSX_[ÆßBmBƱìp'‘u”e¦úeRwÛM°>,’i†¤õæTÊ&gVæCÝ�!IÚ(–O¿´ï#2Éõx[S6HWÃÕ$Dm�Ä# œ)7ôi û—�¦2·×‚ÄìPXW†¾sêP­0‰1¹²‚tkIâžOúPu â¤×\(Vu¡.–¥õ§ KñS]Îx«@·{Jñh+€~e7‰öÔÅU& Üe:\ ·¸É�ІÏ�a×£\üqõ,ÚëD€ÅÚcرœ¯€…U3á˼ ຠ^m�ÃÝ<˜…†ÊÉÈkΠKrèÆ1€+ Åýð8ŽþÜíÈk½X‡Ãï§pÕ›?°S~ýÆÙXk[D–NTë37@¥® &6¡H„–fÔÁƒgZ`a.HnYªÒ± ðùÚR¼Z÷¶>F$Œ}þcÌ—�ÁóqÖZeýFX™B̦ HÉ t5ÞDVÖöÔë�ä ÿ×0œýß9Ø%£†IWBÐjÁ"öÔÂh˜²þ +æŸ{ãìûrtÛ5FWQeâš. ¥ÇóЫƜ®õ‹§†'—2O¿Ï§óa/v›ž¢•e\ä `Q\=¹š7 BÆBè¤×Oi ÄýTšýЀ§*È„½Ž�½âZ80¾Š.í7�}}‘DOb'DëÑÖgšd´rY-îûí4îœZMíÍ�� &÷­’A¸)µ9Â-7]ÜåÜbÞºùñëÎî:qPu2ÅÇnNðÀ¾”æ‡×ÞäO##çÈ��yÝÕµVàa¹•\+ѯ0ò³õ<ŠI“„÷šg ““Â’CêB0e%Hs 9|¼ª<ÐÙKdzCðj´&�]£ËÄR0㼯W›Ÿg*ÑKà$ž£¶©âpäºÜ}Ä�»w¬3{�]ÖF,Š—@°÷,^ºÅT䯀£ìTˆÝp½²¾Ð™Ï9Péz�%SèùÌ)T.Eà‹9J$Íஉ$U.µ·ÉþhhýÁçlÍx}í¨°0ŒC~âîÿ¿oÕ¥#·Eà‡óšFÈr›ù:ˆÎ’R¬Ô_�ºµÀ~ð!Õ{6—{W`/å¤/Þ%0™?Düþ÷S¹27f`�æQ\æ•ÇäÉ‹ÐÌâzò·À8³‰‡Ä}\ÛÍ+ÿ0ð!`:o[å‹Ö† 9-ø`Œ�§âå‹§™ÑýtÈ@‡ô¶Å¢}�X?>›DK#KÎÈð\–õ�UµIplÁ^ˆ9 gjmÃa¹Øã¡ bwÑÎ}jØn¯Ö…Ämj?�±o?˜ïÇ;9O¡ÔÏ# AvÛ]²¾ñ:¹Ø‘gfá'‚‰½~›I×ÄœÁ£0¤E牰_'vÐ)jÃõ%�8Q.o@s—~¤ƒãÎDþRµð7'› 8ôY‡vjöмć¸ö�2n¢²<‡vo|�ûšš@ì{¦^[ü:¾ËãÖÍC5¡f¸ó,¼´š…ßù”‘[7ém÷‰]Z=TÏŽÍ7dª¿ÿuƒ–¤V�‡Sb@àÐNœmô–lf¦ðNŸï"3î�ǺÂtø[» *—²Û³+8âßÕ0`¥væ¡©ûjˆÞп·n%Y“ëàGš5ùµf&ùÆd­Ò…°g†8÷ãSø²ºfDÇ“å­u§`BL/™ã¹4ãØ¢êÓ¡8J @ó¬#<ç|,ðƒ1¬5™Í–´y­;ŽêŠ#ŸäÛ™SC>VÄáZhm<Æ&j�ëY78P¿™ÞÖØ‰nn�lÓeNöäÒâ+d^N?]6«šÜ?O÷Áˆìíú1‡æsëQòŒoˆ\×?‹RJ£D·ò vÞÚG®”ÒÕnI�§$î½;INåõS«iû@á{ Æ<Ý�*±ñ •’Šq%>¸Y\‡º6âûÝ$R>žæ(î†ÿÏ¿Çi µdD}ÃÙárWn3(a.f­XxMNÉøQe�T’߀f�´_ö9í:Îæ¾ ¹»+Éå‹¿ª†/ñ#‘ûeFjZ/¡zÜ$OíðKþmöóéM$Øà7£q •”R¹Ûb¸aA.²»Í Õ#[£?S®äuØ´ø:–—òÑéûÃp–±n�VJB¢nƒFòogd¸'íN‘¡éoÉ�&+l^¶‹íÑ�IL~2…HŽ˜_…'i äáǪ$�Vü¸1ñlY´¼ï·à”ÛwÈÿúgÆ]ú^¶“ø“n‹8^j»J~nÖÅyi¨³ø.³#ÏŽ?¦¤T[ϱ’�ù÷1~ºYåCô|—.ñpE*wÙ"ÅSáèâHjËK!.ÊŒrÉ=p·�¼ytÈ=”ÍWrÃ=_ °söš9÷$‘ª9�½Se 1M¦Ói2ùÑ!�¿CS0?çå.]A,‚-É‘è„!pÊì"(óS¦=ÜŠ-8Ù%O·Þ £é�vsÙŒÓb`Õ« ²†Ã âü1ˆ«>a=åÄßè/;o£0êÞØ‰ß/ÀóYËÙvkYܨ†Vâ(ÛVŽ KupË2;0� …iÑté¢$�+�bö…G`õêK òL %tO�¾ã\ÞšWmôê´&2cŠ Þݹ>q«ÑÂX�ÛŸXJzUÔqæs;TSöÃÚ´iD^DŠsíÂu,‹}E ^'0Ãÿvéãr8îºßœÅKû©ÚCêfÕÉ|ÌX��ç—`Hq=akPj"�žtÜI/‹-„!»&³%JÓáËcܲә¼Rާ'‚ìpuMÕ¸x­Þ6öæâÄÉ�ðb¤ ë¿)ý›ãb :·”UvF~‡&#|„Ë�Œÿ9�] B1§? §¤±Òž HLÿ2ŸÏ£V@4®îm5íZ«ö|å�ÀÓi ÖÃöi�Œ–p:fÅ“Ã[öƒ‚b; öÀ—ŸîÁ5Ü8µŒLl{H’¾OƒK> PºH„§·J€—²j1XôéàÍÃ=Dp”\àL%’¹yD:f.;ûo-òw¤‚ØñÕL…½N?,‚A‡©ã”—„Ý8›(ÍÅyzÏ(÷ôzlÑÕän]P�±ŽÐ›"‚—ÕáŠâKò#¤«Þ}<•Ù…cU¼Ì\`yEÃ4ö =_õƒ™!dþ sÅxk1dN*ùÙpÞ•bÕûs1òMµ¹•Fmbs47 ¹�_tXô¿ÏÁkKiÁƒ9ÄýÙG²oúN8™L×§J�Èu�ð±Â ·T[ÍÀi¸]f.|惯A~ˆ w·íY¸9vßÉÅÎH 9Ó×Fç�5c�raÐë»29S®„=ÚB¶ ‰@Q½hÿe·=J€Áû-�^šÊN^Oª†KÐÇ«ŽYyl˜šH× éTô-�£îßûèê sxšj/©ñ^ˆí²Æ¨Çɦ°ÄÅ€¸ídã†yôÞgL’)€Vƒxj}4úÛÕ'DšdgO?)5SµQRЩɽ¹u ›à”)#t®ñ)œÜ÷O¸vQ—%ГÂ$¼8 ŠFq¤d“(özƒ[ÖóàÓNÔ¸‡rvÕvЯ¥sõvs"ÀØÒÊÊìô Å«/ûÿqÝ>xçnÌxý•ÅE̾ªÓ¦Æ�„Ü ÝSx1=7Ø�÷]ðåÎrvtã ”@KŒV±À®aAœ(�änÝyŽ6ë,Çö�?è‡qß3Üð0œ‰Ô‚œk®p“-ûçùÝt¤ù%œ·0“ÿˆcì*`×§áÝ ×È4/o Ì™�ïÞÄã^I,_†+Uò°U±åMåç90!Ù¶Ôµ™�´ä#J­‚g_R©¤o™&ƃ&¹ ä›p¥””l¼Æ¼íÁ¿Ú�ë—®‡Æí%DÐ~?– Mprƒ¤�q¶£‘m…x½tF΀h‘Nš2ð�¶&‰C�^!žyÏ' !Kz´d®€#ÎøhU-ZÇËxi�jºÂY»x= <'äÍý <Ø„œ�—œ§Þ&˜zA \´†Ùß�D‘†'.ÒùÛV�&a)®w`È£0Nç&9(8ÝM[K‹Ùzãh(íÝBŽÞŽ�0ì6ˆ„ÝÎì;ÿ|ò|z*]¹þ ÜŸ‰žÂ;Qw•,ƾ?ÍÞUçµMŠñeãé\eUà§ê(¶)­ß¡—«wßø›8eãTÝ8¼¤½Êï »�­ ñÇÙç]K6¬4g,tøÑç×(ýµYûŸÞÇ=2uò)¨¼Gµ�m‰f¿Õé…)ü¯ ñâãjŸŠ C!¦ÊXT†¿U°ÃG“¾~–KÎé`5¦j¯3AGœ¡è­>]!ó—%΄o|+xȜǚsY+q3òç—vP$“ÄJeî£]ñÓÑëÃ"¨‹ºJ‚ô/Ó Ï0Òô”½0�î¬;£ÃoF×eÄaßtKlœÅÜÎ&ÿ%‰Ð3]¿‰ó—u¸Íö4\Oå'ÕÐ2ëØötÓë]ÛàS˜6ŒäûR.O¥7ÕÒ¡eÂÜ‘KÄñ¸*ºm•G�¶Tb{$ÙçÿŽ|IX†nÆä×òpÒÒ7Y/›Á¾Ñõ¥'SZØÌPI¸õî >¿§ 5U.Òå*Ò°å« 47?¨ GžåÞTHŠ ös¤¹½…ÀsÖãT Ì%³ïÖ;œŠÃýóo‘××ïÁ 5]”\Œ¾âVô�;r­~(1>åŽÑµy£„¹©w¸‘m³Šñò¡S˜o|Œ“xά•äÈø©Ó¶[Ÿ8–iÖ‡�(P¡ÃOÈ’Èg´On/�§ȇ®�´¿<³ç©m8OãWÀ»îÌ’§k<”±­RhÑGº<¨§‡ýb]O(Ðû–o°d<�|s˜ß]$x:rs`–Ò£_Çw{²¡Ã÷m¾4 o�?ÒŸqG!aª ·‚­ÀQ[6…+]p‡ð»^ÀqãDØ£ó™.>›CþÃÌ»|˜(�™,ΔššÕ\mÁ0á`¼�aC*çFÃýw¡øè—–ÛˆÂY÷ó4Œ;ÉQðÔ‚ì1YæÄÈ]*V¦€L"ØuŽÓÛ:™7å—Pîç.¼v£’üðŸO3¾’9=Ú$‡�Kˆ—þ[àÚ¦“€ IøÂd+\¿ÂÀI{#æÏ:=ZonŒãgda`Hüöÿ%m¯,pÏïdvc—¹üP ½û¤¹äÈÚÙ`~2´pÓ©"…a5Âܲ„ŒúMÑ×èGõÿ1Šf =§ŸqÜÌ $¢•$?µ>´V¿-¥jåÈŠ0Iä÷(f¬KFÉÃëBPy{%öfwCÅlY˜¹)ì¶`¸.À‰YÒ¸é—"5;–…ɳ¢@n !$àÆIº!z.Ôª+p¥Þ—‘\Ù×̼E{Éã×"Ä®�x}ôÅÕ]äÞ$&œËñÎ;ú*¨ž¨ì _›0ϧCþªÁ~^s†?j+,‡yU¶¸«‰}b½¢‹ ‹CèÛ,²aÆ;zãD {—µÅ·›‚p$É�öýXEý¾hṦ{´O3Nè�­Þ+""%ЇŸÞ‡ŸÕ,#s‚M¦£¾užË��wû1o讹DÖ—{8�ßwböZó e¸Yg ˜\´&Ùêwq·Ôw踞BÍ VS¾+VÐjD‰õ‡\ï‚9úQ0UR„1 XG¢³ù¡ã­Zœ×&6ç|á^Øwì1¿ˆÚZ& 8p÷ä&¼´¢�Úõ~Dü¼t\¶¢ÏAi ^^_Y¦G¬Excy‚\ç[ÉØyà5ÊŸä'½¯ƒ¡wÁ&8|ÉÃõåáUá x7Mµ8ð"ë ÍžX„e>ÔϦO®Þ!)�ìæ¡,rÇÒ–D?!BJq¸1.š8­l¦‡Øj¨VÛ�}ÆãìÙcR8bØ?½Ï¨†µYw�ÌØ�;[ǰ :»ê¨ø³®,•\ÕÊÊî£É66¸Õi-±-—ã>OžúJCäÑþR²äÛtÞÓÂ8pz M3¿D&æ•àQm˜uà_†Ÿì“{¯Òã:ÏØ7®ŒS7ˆÿ2ä%‡„`ê' Ü:.Œ;>ÉqÝ6ד's„™ ¥"LOÿK¹× È«%q¸§*R~63‚:%$OtóÛHz—]!;VÊÑ­‹7`÷Tyx á½!lÈ£túÞ_·¬ô'"[[hËëÈ„3!7!­#¡‹ÿr,¤öàÇ[µðr4c¢áŒÂ;FøA$n™ú…eYW¸½Zš^3¦|ZÞøúÂ1¶'?ܸq�Ɉ7¥Q«EyÖ`}G�Yeù”<µ¡7�PàÍ9 Ü ÖËZèÚªËA�%ZpQ#šC‘r�³LëóͰÅýgëÀ,tÐ¥¯« i» !«=ÙÔçԨϷÛÜ"òËÐÎ&3pÜKÞ…&aßé£N(õ.‚Nˆø€Û+Âwý#)2ª…°†{f$Î΄È).ô˜�$Œeе tÜ«/ÍKÀ›S`³j$9‘çÇ6󹣆^–(b¶(+Akø<ðÍR#›®¯¼"Z»3 ëÛ5Ñçó,jt–Ù¿W�ægkP«3Éô�Ô(å¬À¦¿!V«Ÿü‘:LZUóñ²ý{öÎø12iQ‚&÷õñ¾Ù$(s.ËÕk1\­…ž¼BZÞv¡Èb14™@|×4FÔU·Ó;ApÌ8Nòœ^™Ý£ôª4�{1Ki¦??öI…R¥stlžÆµž"Äý'Ô&Pî»g`‹Rv}ãåF »ÕKWX‚èíßdcq2­�í¢gþGeÝ àP’ätVA€„ñ›_€A|¥œ‡+‰Nß Î'/FhûLxp:ÿ̵�îY2�4Ý‹¨›Æ)eÏé•�ð,íÖ—†s§kqÕîU�ö#^ πϡj�ùM…¦öÒ�¹=dŽv§ï‚ Èÿ$Þ½µ`™w<)bŒ43hK\y÷j*¼ÿÿ-ãò›´JiÞq3`ë.^êj:+ù:éN�&ÔQ„,”x…léNðÛØK»£2é=õ$NÑNcŽ\e7}kð�ˆÖˆ7"T¥ñ€·>y�ËùÏü&«[ô‡ö(7P—D-Æ÷ü30¬ ÂøòE¼çsç¢HM|;JvfÖÁÉ !¼÷Ö<+µ�l“8 ‡ (ãäVW·îwÍ빃o‡CÔJMŒÙ¨›�ÚÁ{ 1ÙóëÈ¥žd˜zPUÌ;©F®-X�ÍÀªSÊDqŸJ¥îcïúl$³óW¢ZM*¨�lƒ[ñ›aóá|r?™Ü¸\ øb_ôgî"=G3¢†OHÛŒl¶‚c/„áw¦±×Ú÷Ãbàøk–ù/¨ƒÛG’o¹Eèž Êm̳ÂCaŠØ{ð1®þ¬JW-‘! ›gÃå7ƒäÆÚ¹´´¨.­û3lVCáJrí¡¤¨¶0¯ ßÐöW³©Ã#ªÅo€;q�`=©8šH–NtÐç“.Dßy è-rà¶ õR½ƒw‡é®¢N8t¸¼„:‰M¹1NSê !—´H÷~xöw&Ä¿çÃçbª°eüð>:Ñ]ÿ©ášŒO䬴œJCÔÈ[EE™à�Š1F8ï‚_îò° ¿‚èGÎ' ,ÛÈiÿ»`u5 ž¬SE_³¯TÛ#H»–²*›¯S‹tö ³d dü¾H­ç›0Ë�Ià¯;ÿ±+E;HBþ*r�V‡;ã;JdíŒ0SeU:Ça‡ Ày;¨ùÓŽÞ)¡�éœJù{ö’•-0·b¬4”‚­U×êÝM×Ãw¢�òSiÅßxÒ•‹.{¡v2ã}¼Tý™X¿äã»Ã‚üÙ2 ûéC[:/ð–Î $7å]iö@&¨ØÔ'ù¡é«Sß|â˺Q§�ü½;03üÏ4Åã$:S�®Õƒ„Faœ½N—¼xÌ£ÛÂÊqLʰã#ñïÅ�¯7ɤŸ< +0oh䉧>ÃK‘åôœ˜9õDz²Oâ0æKœ}’I$KeÁ&v=¬]Ç¥d’‡|Çê@&æ-zAƒ%°ú­;$t�‡$ÿ(+TA…f´_±¢Cêþñhéx "£«¡ÿ´¤×_ÃÙ±pÕä2Ytë¤]œ¡Z‹°Æq v®æ´à(�¬ˆA§ß?qûYq̨ �›Ò¾¸ö¦Ö¿Œ9l®aó�½Æ˜Hê“'¥’p`â zm#gvïÀ]«Æh©gp½ÿH½üˆòÕ¬Ãï{šqÊ;7TÀLÖ y-»È±š¶ ÷Ò¬Ý_®G ö‘ˆP2òé(ÀŒuÄL@‰Zw”×�þ€QKÞÒÊó{QÅÔ’æ¶™Â�}G`¯Åúöd3“6²�üÎꃾDo(þ퉯VÞ'câ) rî?`Ü’ˆŒ 9È}�ÂÆÏêØ (Cç“zšx‰Xm=ùº÷,F÷ŒÓÃGÆ©äQ:Ú'ÄKÚŒm²I‰Âî'/ÈÆ›b<·e‡áleóÙò2jz<ÂE3L´ß3T æu#¯ÚaÞãl"÷¦*dJ‰œp2�v¿ÀÖ> Àj›b2öû*Þç  QîKêìöŒv/D§Þ§ Q󊚨6RÖ; ÝÙO™©¨ò'ÖÐç9²÷-#ß2E‚éν›èË+·™Íϼ î„6«>¢LŽj¯BŸgzàÁ}�®ýsIuî\æMs2¬¾ùŒ”®M>¬Mê§'íÇ%µq¬ �š×‹ól£ßB…ç;Ò${†Îò¾ ~Ï$ý|‚p##—š»W3 ÍÐà ÂO"mb¶× ñV�àçÓªØj5“4P# ÿf½ÓþX®†T¿PäÝ@¯;ÑÓz…ñ¶Å#Ù[GÎpÓ™’xrÛ\q�iK~ÍöZ*�±ý]Ú2 Äo̦}9'a©²:¾µbÅE’qÜ9 œ´É±´f�oåÇ6íý@�p`È �Ÿu¸,œ�*[/Ð�½ÝÊ6Bã¯_4ê« ¯ñ…Ù/²È�ßê�Óyß�ñÃøV½=üB©ðúÒàÝFU^ŸèQºÒ'ŒjkæA’¯+k}°ž¾k Å—Ç1H%SzHŸÃZ,Y)ÊÈk‚ã‹gÞ¡v’ðLˆ ª ‰Zåà ·®¼ûAçŽ ‚ªo&–}¿B嬈ɋ‹ôÉj 0UιþXùó I8VBë_-À©¥9�x/Ü*f�ÔÀ<¨ÿûæž½ÆT68àŽÀKõQÅâäÛõ“t«áeúüß?õvéq[Fã›Ä.ªÑm�7;�G£v—„úî¤Ë̯Á«wHýbLì>§À•9ßåð‘óa(³;� žx�•¯¾�îþ$œñì"u(=�:þÍ8)!„·Æ%˜jÏixR¢9_•P5í!ì½å‹ SwBí!Ô\˜�‚YdPZ“rgøB¦_™©JÚ“¥©�ú: +ÍS…(¾j#•ÖÒÍ;²¨œáñ¤³x>ð¹‰7�´`ï”trfý¨ÌôÀÕÚŽìnQ&ürç–e4ç}N!À\möÍáHúx�ÞõZ‡Ÿp=>›qÛŽ…€�i&•é¹ÂFˆecW™�¥*•¸ò¦œ˜%„oéEôÛµ��X¦ÈJæÆ�E‚]̺Ö\µ¼�Õ¾~¸ºx>Ø ºPæª&i•ìÄ÷îîô@„3ë«ÒBÚ—…²çD·ƒåÙ#8%Ìë‚é.ÓoäÀ¯f½9L¦–³*†ÑèûõÍà�1v+>œuƒ”)‘köØchažE®Ès¯A8óZ GK¶«‰8 ’ƒÝõ1DÜf=u|NæF.'YÿXckN1°*º¼Á ×p¨Ú}Љ{ÉCŽ/çœÈ)¤Ùl.­:ÅÒh»VVum°[†/[Êð`m2ùÒö€®Úˆ!/^±ccEàÞ½…9eÒõ¢ÏÉë»bP_½Ž ¾ÀXía‡Æãé�÷W¦‚ã“:èȲÇ$Ãq¦Ö:†Ì]UÊÈŸ”>×X;*�©´îW³@9Šê¾ÿMϲ†ônÐÀi”£7Owâ$|€½þÇÀ,NÎÚ¦E��Lòª~L�£ËëH¾�!ÆØK`êÌ¿Ìw¯³0å« M–r#a­v(>W~ÎÔ%oî£Åñª^iYô—®!H^ÖÃ*éÝ#ê{OãÔ <¸Ö!€Ë–'ᇠµXÙâ†+u¦AŠt]H Rjàw¤yÕ½Žü\£ÆüØÔG-öaRï0¸Èˆv¿H�龊¤ü]:ådÏW?ë…yE ±™º6‡•|º5[ x¹QH³Dp¶¯³ã‰9”9*£õÀ9Ì.ºŽÝñ»Ù‡ eäïôpˆ€·’ iޏ0<³ÏÄþ ¨²]èœg<ÖïÇ­ì¢H’2"$âþ^G*”$„(¥¡A¨´T’™•-Y¡ÈŽÅý½Î]H𸕤�´h+ECþýŸžGç¼Îë:Ÿ÷ûÉŸøBéè²j²ä6Q�åC‹ÍOXÁÌŒ Âe!°îáƒ{{——µìHˆ%™—, ñM÷a´ðŒÑ£^÷~‘ÁYÉ\•›QŒÍäúb§ÖXe’ÔS¥àýÙ}6|´ÏšUÿ+c™¿É�9º�.9̾þ$€dµ ð¢ÃIc38Ö(�Œy÷É ´r“W�QX°f&¸o½A~Dž☳#Î|D?]´eROÇÀ½AO²+gJä†é#['`¾¾C—¨ðýŸtƒÒgÊY9@†EÛéV wV-ϘÎ{ÍÌõ{E?æ8¢žÚøb!„“Ó×ÀÁ„²lm7ÞtççÖi�“+ôØÏZËàẴRv�,ðñF�hCˆ~"…š|ùh*Š›,äñžÄoN›ÕMØ“}…ûÏÓJ |oU0ÃáhV(&MI#Ä©åê8´œ E¸}([slš÷âjomÔO¾µ$ó.Ýb«–BÔÓhÒÕšCçÍÿ@Mׇ‚Ç*�›f€ó¢Ù4L¹ ذ8ˆNífŒ˜ 6äìsÂ÷K•¬óÛÊUN¶`öåœ"ƒ?ÿe€’,|b÷£äûpú;õ‡yy‹,Øz�”µàT°*&7k“Ïx3Øå¨¿:‘ –¤à®õ�øõLMÒ¸GKbÛÈcù¸!à‚¨—O�Ìpvƒ+n½[@BØõÌ –ôl£>AÝ$¶ïÙ°¯…Ø�æâ¯a8›Ï­ ™Hã’êϼ_Œ\­,hl‹"ªÉÝTÝñ0d['�WÃ!ÑÌŸí¸ÖÍ>ñÂ;Å_¨QÎuâìÌì‰@ßRW0¯ …ç¿¶ÂŒ8°H<ƒ:BUÔÜÅ…F–¥¡RÝ Q ©`´ŠvBt¬$š¿: ›e+µÅ¹¹Íô�Y½òE„@½µ›~4ÔÀ²bc[ÐÈn¹I¾ÌZŒí•À¾÷ƒeF‚t\¬-B1Þ/†]uó H)Ì…·œNºÌºž††åѶ+øæsúYãˤýçGh;n�¦k_Ñ˱ù¨Ü“L„TÛ‰P´<ú’r�½kÍ|š“‚ií÷è„Ö]ú¡¢ ³ºŽ‘œ,wRØ¥‰?:yd0y-Ùû«¬V.†ƒ;×clîcÞ‘GÚ¼µÉ/‡)žL‡a_n÷ZV`¹*ÌüÇ‚o[ÉaV�úµÓÙC¹<ü�*§Ý%¯{?°®êó€å_ŒQËÈ-™Lê͈°çåšÈÜí'‰¾Öÿ�Ëj>.@7£�ôýðZôÉèA©'Èy¥4ï„hË ¼m(4_Íb,{6AX^u²¾yûá¢=¿ˆ÷äÚ´[–^Ää�üà{× „;»‰·ñø6¢ˆžÕÊx>m:j­ ‡ÏræÅ QK¾]ÈáT+¨0Ž ó”ƒ‚^2Ù'i§næá¡Ó�dãÝúyÄ󣙢òpÌŽ½Â¬î±Á–öu¸Ù¿€º?s ‰ó§aQÂ,\æ»3¢UqÛå7Lù®z³Ø�Ë8Â%) b²¸ O™ÉáÆ­ópWÞ4^xP4L'iÕØCóìÈÕ[Úô/ŸVoP#â_§á¸Ýêó[{TùñÉ•3T¥ Ãr¢!¹Ñ ¥ÐD(†î{G$-Ÿã†‰r2ÞÓ ËËo’þñDÂ1Uã˜Zß5ÏÚC#~¾¤�ûÒÀQ bÕ‚Ð\1êMÙ^-Z¶ý!ððO%ܯs€~¿N´ŽZ°í½BÀ¿î!•;5 ®íâƒ}AË��5é"µ—ûÈxwUëSÞ9oîE‡£Øûx?)\ÎÆ5´DÌë"fb_[*»pPÿ‹Éƈºed¼:…Mç“ÅB»9oß÷%�v¸µëîO$þ?a’añ…uªÛŒÙrQL|ïB!¼û¼V%*³™N´W_“,·XÈ”­çƒÊÄjv‹§ͽhRë0»Ï‘LÏŽÁÐW†ÝœAÒž½dbÌtñŠ|5ÆÅFRÏ;É)3É9&§CNßЄ92¿éä«9äuŠž×¶ÁÃJb:< ýgU3O-V@ìÖDzÿ`"H úÒ[ù’èùŽéßqjØ[d£ÛG2ÈÛFB—¼`ã¼"p¿Ó ”Š&ó6+Àá…زOl~)ñ¦-ùHRô\¡PK æ<"A; éLÙãP1«‰áZsñ§X=]·l5~qÍ¥½‡f@ßy.8­áàžëh)Å‘òÄ­™Ï-D*=`âÉX”GKj`�zþi5ÃK¾f8uj(µ7O¤‘Ó‚±ymÄoýLx+=ˆößEhbõ“0½Bn(ÎÂ-I�Ó0èÅ4œ6n?ÄÕð(3ÌYå&Høê³À¾Ý ôoA�˜ ô b4×ûƒWlòûèÿqi¤»]Àí]­¶Š£ógò1ƒ÷¢IOõj\{Ͻ'áå³±^ó ›4tŸî°•%ûÖ÷ÑŠµŸèšcIl]÷zÒR–3<ÇdÞ»Ám�Ð-+GòÓi÷Hh¯WVñ(ü˜}yܤ šÄàáªÜ#j‹5éÂ�д.ÏÝL6…)�w3V§1fS¬Pû¸ 6 Gâæf]xwçûî¶oáÛ=äw§8ÞSÃJY”Ô¨'ñq»Pdýâgq�Ÿ�Á¾ tæ–“°ò¸(Øë·“©sEáLØÒë#Ÿä±—4;àLò]8íž³êKQF5^úd�ÙIŽÈ5ØBt/ KnÐs=éôbþCúö˜&¦ IÇÃhÑ—2α­ __5é;Iæu–`ÄÁ›0Ø3= 6BÃ%,8ÂwL¾ƒçú…Ø5S�þöO¡R…40{”¤š^`S¾Ç�·°nEñ·ÇhñNdIÓöŒX46Ó=ÿƒØŠìí7FÌ#I9p‘%AÏ–@תyð±<X°´ 6Fú/ÌÙæÛ$>ü3~FnÀ{¾è!Èê—ПL,½Tž’³‘1tîú5ÿøøð™;Áºv^”/fVóƒÖ˜*õü¢Î¯&Ibäò¾H©ÏSZ^H,o(L¡† ”ŽÏÃ�+·éæ´0*,¡@Õ>=¢®ÎU¾0 ÜpÝÄVðøu¤‰£Qv(35š˜‚Æ·1’�ªýÛu)oü6ÙvRÄÒý¿&²µÛÇ›[På›3¾²i¢¾ ¯)ޝ‡“A`o€|kžuþHšú„bо™º%ƒZ4ÛÀßWkÉdÎiŒþš„ó®îBwß�ôáçÏð³2¬·~‡lÜH檓½ îãcù«äÄxÝkVNP~ÛTþi!NOHöh \¸˜å�•öàµ+Ú Ã]9v‡mýÿ4–ÌýWͬޟ`bøp ¥± Œ‰[/i—Ý ôï¹…µæ`Ðë^{™‹§?Ê™…·@賕å2ÝŒ‚ð£)ÄøxòAËÉý÷«iå�/´^ÁŽDÜùF •Õq²p.³æÀzî´7Λ•ÁÆúâ}Á#à®@&. Ü=æSdxéÿn‘ØÌ#8�¤†FW¾ÑH[9^½¶ï”áÝúI8y³áKV(Qœƒý·|i³|†;ì ÏUOc蟧ÔG+.¨‘uèÐZÎ;nqë?}帘^Å¢ZoÜ".Oæ™WâuÑ0º-²‚«ÍS&NÿÙÓåFx_Nß²VÐn ÂÜß‚äˆðy0ß Iž^=Žå¯u,w;P›±Ù(æk…ŸËžaèôƒÄwÞŽž†v¾wÉUuØx¸ †Uæ¢ê?§-Æ›šZ(ó%ŠÆþ¡žäPlëú}-yb ™þÁ Vqö n¥Õj•pXÀµëÁŽ�G¨Ç3I¦aµ!ºtì£éÕ’X'^‡Yǧ’½~Kpz–´å“¯¹WùâaU~ðù³0æzUßé/$к•½bŒ;ÌJ�¿¸€ÙÞY§´†pý<8‚ïw8[ΛXÃ4~ÿÎæ‘²¦ÏšÉàŸ{šèËo¶$aj2n´°ÄÏRÿMga§3jôQÁ€qµÇÐðNtê9­©EøÍù':š8+¢¬º{—v!Ÿè­‡:¹hø|’»mk6£é3ÕR¡QÖ23@ÄÒ|ñMîŸÇ¹l¨­-¸÷Bûޏ×eˆÉÎ\ýSõ©]y)1=³Þ±ê[±R¥ƒø¸¦â¡æó>ÔŠã±çatM4œ|�ƒ 1xæ”yúÂÔ–±Q�¶u}!ÛÌ×À¯Ü|ZÐuŸdßÜB²Å?ãð˲۪ç¥hâ¥z<¿b =YAçœÝo¯ýó1ÝlZcgŒ í†ã ™ð„5;ë;ôMæ#d"øÐ7 n[cá×gÊòÈeûr÷¸ í»– gX¦9&S³ºäQi!(ìM'ómÐ纣ä]3¢´S/ºâ SǦ“Ù-™äŒàòߦRH.ø×碡òg`¥Ä|ôËâÙý85žç`ÕØ敪)FîäÇ¡MØÎ­FûP€>ß|ãû›¦kry�Vô¶ÞG­ZÔym}›ð‡¦ ämÑà=þ×÷õ]§Éï«‘ølȉføŒé,Sžá§S`Eì1¦ùœ*<˜"ÆӻäU Òs–S,‡ÆøEV¤ëÂ#²yu1¸¬xK„åð¾˜Ù,y�­ ÏA‹D}䯻†WG÷àÎý~ à{ü *E/È&ñL|Ÿ�õ‹e¡øF!®˜�à�»^ˆšá"–ŠïÈã'þ4Ú�'Â>‘{ÆÑè¢S ùS%ðÏ•Üg d9¾Õ^ìBg¾{ø°HS?°Ìò ŘZ&в_S [?—1îÚ�‘�sñ³ßBôZR�OJ;Ñâ°/„\Ý .mâ8~¶‚~ŒñaŸi<¦nèÇúó0W17Ðbl3Ǥ³Tv± ÞšÛ‚Qæ˜6þŽapVän¢¥-Flj”h~Ä©§°¦ù+ŠäÚãàû7ôDB6l[‰·¥,Wš�§Ø½Ý3a—æ \ÕTLÂdy=¦Zd~º/r;ÆÙÖã³`w]$ì÷;QìK†¹Qj]t¹Â^LT)e^V4�ÏãT¨šM?äÈ ¬ˆ9·íÞ5ºxÛ«XÒ«wi–rZj\$~Jx°ß‰º¥V‚ìƒéìz žÁT¾³4‚qªÜmà+„UNf¤9�gÇ~$±Zˆûÿ¹©»À0qÏi‚·S› ð®&¼9«Ž½ß/Qã'0°í0�Ë0bûfë�ôªYÔmñIX¸]ʲzÆý¸ÂîÔ­!S|aâW•`ÂäÒt1Êm2`³¯'¹Ôù2+µðù‰Ø[‚{^.„ÃÚoð[Z)ë­'†÷–`H®œ8ÕLf%ý—RÆé/O}Øzè%L 4G{l]�ÏîªãÑ—ÝŸqÓ"yx{\‹ŽÜF#]ѸÌ&Î †ùçÖAø»×ÌX�<�(?ÇÖ¦ÎÐ ºËo%I/ئ�|‹ºïÍ/Œ ¸O¢7þ$c\zóˆ ¥áš{øÂ$‡¬Øs d‡Äh‘S·Ï­€ÞŽ»ŒÜ8 K›K/è»fW8{Ñ•z)ùC€ÎTÌNÙd)Ñ�ÎÚVô‡¸Q ¾€ÓK/¡ó­4,ߨBâÂéÁs¾Po·�«I…yƇԘ‡Aãô÷á+ø•½†;û¾W>%Ø®¡ÌËúk�þýdϺds*É«€ýÖÅTÄÃ—ÈæÃÇM`6¶”ÈüuÅ=O¥±ÈA÷~¼DFj`·×B˜jÊüŠõ¡¾—Y³N!1 &êÓÉHtˆ°Ù(Ç×EÞ/W@«’©–^§^ ³{+M®û�“5E(4_”·Ç/ ~:ªà¤h]öYžK:€ï£s õm I�‡Â|5ÌïZKäWVrõV1¦º¹¸ÙLž§ö€ÀžŒ}pëL#åEX@Qó4L3³F�€5xÙ/ÍÅ{\|z§‡#1©ŒÏl�Ñ/!3 ûÓ8Ò®íWoÁ¬6wL2ÌB©‹ñÇS Âw, 6nÀó ;©®äfl9â‰u�EÈwÛËäüÈ:]nÝ‚“¬Á×8z×¹ƒ½o@�)™ëŽ�¥°ks8&ØSß "` ¬ŒrI4Þ%–DyAçÏZxþ¬‡N˜_ ±ë—#œ²\c?�ZøÄmIQØ:ÜŒyË h êCb$Lúçbjä¶Kr®ÓÉ#7¯f0²e ô@±>Ô¯Æï¡â qô,Š®³ä»ü‘,O?Fk®]�öƒÖx½0–üŒ‡NÃpæˆH9~ (Ä‹A/@Lo7ûdmY®p.§GÂŽÝ?`ÚiMx=OÈòvést¹~ ¿oX‰ &Vô’Éخ苵o–�9–ñ´�Ë®+gc˺è{½šò a# åþØ)îI¥÷B¿ölxøC‚ç`˜Ž÷lOCb UyÆÈqo[¸s—€Xð,ЕþNB—9À3ç Ö-Ñgi‹@ðAä·Ítª#‹&ºø.P»«Â™ó~) Pñ‡r=ž£Mœ(mýC]_1+ÿú2AVIp²0¾F^Æ[¼ йÕFœc>®þb’qµ�=¸ê+ýö®/ÞGÆG:ˆùÆå(»Ð ÿ LÞ�Y+XõPY,Q¸ •Ã!BɇLy¦ yörøuíyø‡šJÉ�§çON¼P²LÏgS2p° 9rPôäYvçÌ$ª{ô'7 ÂúUSIî%AÐj½Kµ<IE3à¾é7Ɇz~K«;¦äòlMUâN{œûgJa}á1èÞk ÉÅ›p–• …Eùø8ü25Ù´c /â÷ä:|üßp�£ø½ì1½»�Ô OЛï‡hryŒ8ü¦:‚¸çïlð°ý†J.�TøjX"ÛMBŽsúRW·¹ðQô&^ \ÄæñÁ¼Õ{ڒ蓌÷঵ŽÞëbxò…ôÛ”ëäP¼œ ·â¥Vœ"¼·^�ó2�VÎ( G½°%8ü¼›pjÅU²ÂOH«oO– .~V72§à»°OpNÓ�—¦<̘&õ!™5€�,Xß‚ÒA:Ë´k²éÍ•ŸÉ÷··É·ÊH¸(’�~¥?ñsÎ"zõh=‰+~…“:–¥‘À¹¹ˆø£ðÉ£:œýN�žuÒÀ I`ø) µ‰gM°þ¿“‰ì\=��_j`[B{—ÞÅ•á8�›AºÞW3ÚÛ÷ãCÚDž²œ´`Ú¡ÀùÜÝ]boèËg�À˜WcúZSzÝ;8_cåh/=t- ý9R8u®5þéãâÙ`îÐE®]„’7“D,¿5ÆsÓéOŽðûVvl¯(>ž$ƒ[úéö£Š ôÅfÌ3ÅçÖkñÇŒ»¨UukæÌæ]Ýl„î§¥™uÞ20ŸI„Ú«c4gr6‘_ÊÖIî =K-À'6Ž0áÀGAx:  |‹J˜³ö?@På(#7r $â¬Pïfô”®"vŸNl¼OʬExãDÂÒ#:�ïï&|+Á©ÈdT~žÎÝ%ÖÅé6uÁ”Û Xêùr�ªÃܤl=«î/}À8(ö‘}n–‚Þá(ùЮ«ÅÂ-ÍL¢�ôç>¢Œaü0�pgKµn0éÞÖ°t_<#nˆ`Âÿ™˜ØÃá¶+0çØezì¼°µ‘p"øýFt!Zßž1s_Ša�PœØ óÏç@‚ÙÆvõGª¤šŽƒþ d¹­7æ8ýb¤/W“u÷ý¨ÃáËtÔVç#y«VÐLr˜]=Hüu‚Ö]ˆf+ÁíË9L ‡1«IÚËb nb¬²/{G÷»‚]w62žN8÷”±9± ïㆭqÔÆÂ–†U„AÞÂÌí¹N$—ä³Öš›PÀòwô• |MÛ‚”¯�ü/„/è&}æÃÝ-úà;g3„~ö#Ý×½Áû±: ߆ôø¢‡ðëøMRjÚLŽ˜oÁ›�”‚{þ3ÆÖ‰ ²å– öç¬VvôO'2OžƒWí[Ük¡ÊÆîì„_ (ø�È¥Døœ™‚í7žÑº¤©ØŸ\ Aͺð×á#xµÍKDY%+Eø›¬ú�{æÁÛK:°IRüülq¾îI’Ò±Šùsa„Zj`›4·ŽÅïcÕxë´lŸt‚‡£ÓàÒžZj¿°ÔÓ'¯Fñ^M"(š+2¸ýuëá@þ*üèµÚZu¡t²ìë$`Þãph™¾³šÄ@zù£GóEiÌ%7˜x¡zõéêK¦WE�ت'CâÒ;$tb|8áBwúcYz%-HÞANWžÄᘔÎ?DÎ�‡5áu`üDÂmg¢[¥ \Õ÷lɦÝWT,O™9’žôZ4žƒâJG(lV`N¹ëÜýÌ:“@ªšÞ*ÊêðÆÈ7˜ß£™¼ÙUFóÉ�j~F&<}^+ÐIOÔ�½ÂIZÜ…7&…0Nat1ůé¤À÷=.åfÀkMzü¸4^q @—È0Tîÿˉé΀;£¸Ý¦†ü,S'SŽ ã™GY3[,Ð)C>[ØàGìômIþÀCz˜_ Ç’4x[g´±]ÛÏ—psìsüçK&úXéeh!UQ AœNjz1”þú/›*]KŇ;+¹·é‡ò(<¨ãޝóÊa$¤ EL¡.Ô‹¨Ì(#ñãÿ1•›§àÝvc¼!ò�Ì—‘‡Ýqïñ…ü\ÚI`ñ³·Ìå=àû¤’æ«­ƒC�^�»R*Óya5­}3ÛÔ6p½¸3éô}QdóººúíMéƒÝ*»¡,Û�JvuÒ(¿s(¹QŒ‰Ø‹7ÆÀ•æpò|íQôs­ÂÕ/ŠézþSôñµå�Èšá³àC¤_*lÊ®aRÆnÓ¯ŸÃñD —¤-3¡ÄKtOäfèÐÐ…%ÝFÿÔ �\)† ³ÄX¤Êã÷`Ó:?â"F'Ý5k«©ø.Ý®«Ä¾ÞQŒU·Ý¡ºQ}¢Azñºððmn ñ&W²¥Á±D–ÎÏ¡¢ÌÕRCX°ö]ë¦O™ÕìÇÍpøàê¿—ÅÓ1W±êõܯ=}°ºÇ˜¶hkW@4Çï2ý·þ2?'$‘_ÔéËVbÓ©ˆo3Ué̪fØçïªL‚¡Sg°vI1 Ÿò‰Î>}Œú¬ðÉê« Û$„;åXMÁ"‹¯Gü@}ä$Zç̓éñmÔx×`1‰¼ž©Î�à(7l¸ðeáÝß6 g~[¼HÙ®Ó¸ÕÒ”iïÀ—ðŸÃsVÈó,&÷Ùàü¨¿øCwõ0|‹.ŠÐIFÖÅ”@¹×5Z÷„ƒæG׳މÁtä¢~8‰1úçaGš-:žý¼AÆŠ[há�2OÜl:öËCÜj%ü[.B÷:îG¸q›9ôPŽœ@|P‚G¯WÑÎwWñüÐxú[?<_‡™Üñâä;öEJ-86çöD‚m W‹öÒ‚-^œ£1 5$�vOWØ5˜‰ù£«ÊÜúšÊŇ|dåggªÝòƒä­í €oÌ^P%Ç<ºñ¾+8éÙÿq¨T�7%sÔB6Á‚sêCgµmÂ÷*3à£L-½—NhÚTETCëø-vÃ�Dú­æ ý½fؾ÷¡øH—tå°ozã9MB4âœ$�b/ØmÉ�™Öª "18 LjSkAZZ¿o…|C¾U$¾ÛŽþã{=1ä5mÄð­m´ãªnýQHÞßFyÙð¼A~ÿîBÍc Ñ*�Dûé²ôŽŸ9.9 .[?¡¢C?þÝx²¾¤Òù:¨dA_ê˜`ÃCu,е€)2bÐ}o NÉ�a9Õ»F,Â�ÍcÄ=×%l’¨ƒá ÔÑ«c¤%sp¯Û{ŒU¼E·–æ(¬ó†7§�ÀÁ÷ H˜œ‚ìChùrJÅ8¤N±„±L_BãÕ¨qJ·‘Àñ~<ÄWùÈä}c2¿k~d S¼–ÓmY79-o†aè{=R€å³°ü§$¼0v ÷ÛOÃ>!g¸Ó7ì~‹òþn¦M9¤Ü2¢í×â2 %hþpž¹½ØÜh Ùh ÷ƒ#pñ¯½tuÃæØ¤=¼›NÒ_9‚N“0ïr¸zÚ~ :ºÔÒ 7©ŸêjÎ>“500ÝÈo!ù'7Bq¼’ާ×äÎS¹¦)øÉt'òÕÅ¢wñã«Næ¼µ®¥ W^u@È… ¾¡ }_jáü‹Iøy®ž8±ãç\À×hº:ú9‘«šŽ·{jÒÑß1‡¼â+`OK´‡;t²gí2å°ÿ\:}[b‡Á'ˆ©÷C*`IÀ¥9¶ˆ[báJCbð-–ÌÚÛ ×ãåa`ùN8æaÈ^¶¸I¥›ÀtîFr+(–¾ià¿Éx:ÅN7LUBé“5쪓úôÊg³4©8³*. 8ÒK¢€v§&•ýª4¤î~³¡? ÿñk×Híõá¦/ƒ§°Çù:eùRÿ­ªÈ‹H¯Í�"ßu`‘ÑVr~¼ yê`mǼÏh'b«h°Ç,Ì3õÆæöhøx™%¢¹q˜Ö³Ô}rÉ6¾b¼Ar‹§B×~Atùóˆûü÷î´ýHÕ&xŒ¶Âþ™Ödwò*Y÷ ÖL�½*Ÿh­¼Ï?.¿AÊ„™ˆÝˆË�#OŸ„'ÕÎxü±4Y<¥î©�-üAôòæØÓ)‡¶¾ˆ¶q… ÓZâ?¦CÞWÀŽKwh±¸éù0LÿóÂÔò# »1þÜè&QS-c÷ì¢%D„çí¶Ó¬r .[�y=,Í‹F}Ó$2{ú<¼¡’M7ÍÑÄ M$¤BŠç}K tåóÙj“^ áßMrÉÏlmÎ}+A(`*`{×]ôr&L}€ jb1xYDgÈoDɨƒ$úÐwºMeéQ\H7ÏÅÛÒŠ ¸by$¾âÊ�ÆÜ÷µ‚Å›b¾E7Z RÅ’•PØ Ý(îQ uÛÿ£üx…-a‡}8¸˜ÚQg¾ÙøQì:l[ć+ƒáTP×1�Çq�FÎÇ…OÈÛ¨ìûA^�Ò�«:°ðçW’£İC™x�n�­×ˆÿqyÊlådŸIeŒùjÁE4ˆU�å…Ko«YŽì¾KÍ41Ò5ˆâÍÈâÏ‚¾mðxG!…kû1ök:gÑŸb”¬X í“¶œÎ?o±YúVg©S)a´ î¦w22˜°TX×&H.¹Mƒ“{ò`â3ó·ë'm2L…²€ê·/ƒ»mäÞ;LZ€wM#Ù¼-fdçAu¢öE ¾V�’ üàSé@n¬>Móò®0ÊÞƒsÄvêRÏA…Q¡ªØ…ÀÐH »ô²aíªðöÂYw]AçÏsGYÎrlC¯Ž¸ÍÆŸÄ|MfÐ(™\tŸEµïJ’#…è˜þs²!ª™r7ÅÐϵ’¸\ƒËùtu„ʬyF^_ G}#OÔÛÅ`„ó9ø±½Š^Kð„½JóÑ_èÙw¸ £ÒüÉzýRû� àâ6<4UŽø$x“É pædŒ>Š¢:Õ쉎™äIÐæê¿}DdžÆmËn–7�½Â¸m“xÁm…‘¸fõ8ph?L\!¡Æÿü&"*ŠJqÝæ!êä… ½Ä;ŒŸîþ0„ŒßsÜ{˜Ǜة'k˜Æþ³ìÊ >Üœ€$¬qNÆÙ»S*SÉQ6–Ù¯¢P2æ5ûçz>>;ý‚Z¯ÎÀ$EàÛ0Ðì�gµéÏh¢¡FV�˜˜^V|¯j‘K»†Éè°þüíDV¡>Óß�¿v‹èôñBâ_²œ¾»‘@ö½©¦›®м_gሣ43\dA[uìpS’>Y\iˆ–Ê{A(ÄŽÐÆpØÑDõøÂ˜¦vwÙ}Š/ C¹%1äFÖÒ^½\'Hk§æ¸Ý!õÊ‘èä° ¤§Ÿ£8rš§„¢ðOË¿ÆqÙ7[R©%/?¼$M‘‘$Õ®Õ¿J�h<‹Ò’dØ+��'+àüå/lÕ­Õ„÷]%B3éùŹ8ú½”¹ùm¶ÏÐÇg=úÔ»�ÈÈÑl—`¢¸7‘›9BÃß©Aä•1rzÊ4,ÎudgY8£šR2ÙÙA_.R$QÛ ©eœP?8ßÙŒ£q¹p“5Àö8iÌÐÙƒçŒFȘÙVÜÓ•JžU¨Ë*?¡ $,OöÜ‚Ãí'È7v&´•ÿÅ*ÉDX™}öó­Æuþǘ_¹hØå@Z¦·‘Üi{éÓý_HOX'9õ2–¼¨D\pÄÒÙëìÀ% <à剧ûk‰®&2B¯{ˆÌ®¶8€?3Aíâ4hòp£"s\a8ÇŒüîýIä�À¨™*x1仂Oži-Ü�®Fàñ�±…Ö6Rsá4Ì•A‡ªbë�¶U&€»RqQmV¦‚à+â^k »«ƒA#è U»F'ž.ÑMQðtI ø.j‡{ƒ|T/TƒMÛIúoÁreW-ÓóÂw§s¾žZ‹wnÍ 6áÔc\2oܦ[Ç®‚µS?è=‹Á-F0Ïä¤>!é ¯~éßÔÛ8.üëiCžby÷ ëÝ:.ˆNl+Í»v‡îK„þŽLj?aO¸ö`}³4N[˜I;~sérí“TëÍ4NwÜþ‚ê3ÞS©%bXùb Ór&�̱*"AúÿÞÃúã]©_aM&®‹“Ò:RÔª ²çøáýD<¨ÆãnÝùdY¾ŠE�À ֻ鱯dØ0st¦NÇsRˆ®z8ø6Ó˜Os©_"–$–§¼„Ê“Aò’(:KMƒGq›aɱRÆøò‰÷MÄø Mb]Î+HPù˜9GhIUY{ƒSŸPÕw=ìZŸxÌZ±ˆ.x®‡Ò;!uî7u}5õ yOC*»¡­GO+¶à¹}\úa8² œDÀÝú;8¬DF%�ÿÖ|øò n¸s ç±*\ÿJÄú·3SïÌ�í·ÁÃá%•ÎØCo÷§ÀRÉŸìTÕxâPÓEÏó–A~m/Û!¾Œí×঒˹�Gò•‘=ž›ñul¶…TèMxglŽ6ð“3éJÈ.PEÅ«p7�Ýöé <ÍáÇ'…*0¿«„(l-Æ¡sˆÜ½û„t*ã_!?,�÷8õéÛ½o!ì ÞÂõ͹ƒ?,ÌQõÕæ|Ò‚1þëpÊðº÷¶±_8ƒëoò½ã,Œ:B†�*yyæ­IÄ+Rçè3*|z&ûî{/N¾ `G¬–bß•nòSnˆ¦F?#›Š˜û®bÔ`Œ¦33èÈô­¾‡{G®°Oe>ÂâF+Æ©ö‰�5HGï °sU�`Ú¿y&1��JÁZ× ÄóÅéú`1òH-“ÖþËeÿK%ô�P1¿�Âèèì/ $Šu·¨^Ë)’�í„ãq[ØdÇ;Téçl¨Z�—­ï­‡Ó¡wu=W¯,„ÎíÉÆ‹ëÄÀ~Þ"°WŽGø hµer’a0Ã?‚üث҃;H”R(t„¤ÚËôç�zË'B)ó‡í]g†YN¥Lf’" _áçívÏ!kF ,¥§ÍÜ@@èÛ·;„æã™&.;ù}1¦˜ØBÚ*)²~ÚA×/"‰&¸¹1”È4 A«“î�2þ…ŠÐ»³¸ššà¥ó…Ir¨�¥§(„» r\>,Â.GÝ ð8w N zL.Yß#ÃU –_t„UEÙ4z“.Z§ô̆ãXyIžVPŸ'?Éi£'däü\œ[±¯]?‹ÝCi§%?vjáçï´éÀ²ÖY®Î¶As§jÎàÉr§§w�ô„L]>š¶Ï�y ƒ˜9ÿiFÊ�×&·©¬Ö "¶Œ„Ãbiúél¸ÑS�Üê(|}5U_O™eZÌšœIº`• ˜ÍŽÄ=Ÿƒ@·ÒßÕ…e÷öÉm‡©Ø¯êï¦Èu-çÒý¥-ä¶,7ƒåFÈÜiç²Ãúµ8ùs¦/úF´õW“U›IHÍe˜oý‡t&,ÇozKè©zU�hˆ‚íß…-…TÁ†æp‚KÓ¨¹ÖKê–1—(åIáçé¯`ŽŠ3ˆdTñÄbP+þÅJ«„ÒâI)ŽìîZ©š½w±>µð[*>¹GÞß#NgD±å`6Þ÷W ã«Ípk—ñßîÏL£À‹M!|Õt„ßAµ §ÿ×NFÅSM´ðî0g†G¥e·aûa*½ý>ù³eœ¬ý›«? ÀùŸÜ‰=œ!Ÿ:|–öw‡¿QÞlD{(Mb¢L?’ƒ•‡X³ƒS1ä•8(š9âêÐj�S×êcÌŒ> Ý8@_õΆRýzjpJµ¹q¨uk&};ɵ»“Dðc?±Ý� MY%Ä#"OaÈ.~º÷´ ý>G̨צ…¤Þõ#Ê©µÓ´6a¨_ØK4¬;hñEMH™WJšcAÉmhµÒ¤?ï/¢B‡¹qïXŸˆõìàCA ʬÝH¼…†9îƒ è«'ËU± ·ŒèwÒí'°nÿnÆÄ彿ÅÿpCñ[Î3’\Ú‰Þ‚è_’OÎýÙ‚I Y�“Õ°äÛ]Èmÿ®=Îù£¡(PÊnQE3¥5X»ü=öÅ �+è�Ä?$Hë:´ ìG×ûÞ(Ñ�Nd§¤³á-÷Ëòhø!'Á‹SµæVÍL£i¯’ñÜ¿ý=T@|Æ’wÿrãÀ]jäiÆä �õ®„… ©¤È|dëV�æõ¿X«�Vr'õ]#°‚8éà‚’¿TäâtÚgÓ‰ŸÔ\èoÄ�í  uçpɽ#x|Õ[fi|$¬håhóÕ‘E>'ÉñýÆð®Yâfž!róg ’ÑFê̲ÌiœŒøJAØ*JÃ}Üa·íâ&ÏNòæIë¸ e÷J^ÃòÕ“�g}[†ç²ãÛ`ÀCoæ¿#=–BUvÒ•±(öí8Ióº:×,…ãÂM">z¥ôì[$+o¯Äh³6fh+üe"ÁÌ3ü5B8ºQ©0\³.wß!ëÍCÙØ­0 %§ÒÀ>E#½ƒ©Òá\³ßF�ï±.‹(ƒG“c‹æ£ÁÁGÔÀz%ÊÉíÁè�9ÿ²Æ”ÄU‚õ­ì±Ÿ9gc–AæÅOTkŠÎ>+LÛ¾ñAk¸º¥Ô>1œvÃ[|­ n_„Ó£Äa¾þ²ÿ@9�Ö·»Ü‡YCÅHp]iŽw¯ç&-�¡ÅÛ$AÐÇ }WP‰EBì¬PO(×ΤFPÖtf>+D�ÀeÈ1'¢¯Ÿ³¡‰sȼ6*|åŸ>Æ>Ÿpà7ùpƒw5èŸ;å?"ã­ˆ£ß|˜§-]Ÿ>`SçMøJ® å‡iç`ÛGrG«Ø{§¨ENÝ6ÄIn«¤¿¦R©e’8ÄÑ!Ñû¿Ð‡†ÛÙæ8ñê-Õè·¡÷O.Àà‚âd††¢à÷è3ІZPûÿŽ`ú¹VnÑþ z©Òƒµ‹¨«ƒ Nö°Ñ®ŒÖšœ$qcäÅ /¢·ï5êÔ9l‡³–¼$í§ðmì^Xæ-�/’è×£¹t–X0Êi¨³e+“�çìñ?ÃΛg‚¤¹‘¨±6˜:„©v“¶¥â,HhÑwëªÉ¬=ºDþ»½Å¢®Õ¸gt1dÜöÇß-¿ÀlÏ<ÏÕFÝc7póØ³™ÃžÛ,F¯žŒáJôœÿ�z¹›ac�8n^uþPh�óŠh«š#ˆþòE»‘˜n/‹Ís—ãÂ'‰›AÝü$É{­O{¤|i'㈮)æSsþñ¥øZø5õù&ò‰–<]©I•ì¶3ÕpâÔRV³™Ÿú:f HÄ¢ê_€ƒFsc“m>Ì0À¢§Ç Ÿ‡±8±‚Y·Ä5än²Yž0;B›èýצp¨ü=†ÜCWÎf°8b¢Ï’ª¾à¾w~“Íaù´fðªíe¶Œ êÆË(ihǸöd+ù…K¹ŽÔp ?o{ŽlŠŸ ¯ö^£3·+öù‹Órv$õ–oà´=DêEà‡[*è²m‚œž¶˜·ÖçŠÊ›àn/3R·©ƒô^#ƒ *å^‡Jù‡0;o#:žN¬~äc¥þ mß݈©ix³ÈƒÖ&'¢»®? Äõ%2X¨ôëRYN myÔ¿fpgæ&qÝ5pÓÖpØ¢®ˆß?­¤ú3ÉwÁÓÐo¿Ï‹4aiÆ=Ü`,Ø‚hiD••P>¢—™¼Å¾-‡Mé±S1(¸κFRzäcóV£4Ëqí#ÌÚñ˜-ô‡Ésò0±/ kJÉΛ’«Tá[ÉÄ$Ì—Aipõ¸Eù.ˆÒ†±§TxñqüÓ”†5¿©Ì”¥X°ðÔ ì÷|1lçÌ‚¸Ji,ÜF¯Ëcï5¤ÐnñQ¢.öQ½rœÝ»öí2 êëç@ˆ“xdÊòœ¼¢J¯Ù¥e+@`Îgèp|Æøå¡ÈŠAöv“0-ƒ‚��»ÄvtÔ°»û ¼wÕ—ÀûæÄ”O†\û¾žòJô�Á³â)„ÝRY‹v1jNnèQ¥Äl¯&úkåðuî¿<”ŒÀY�*`¿Í:,H;FÎÿ¡ZÇ£ˆÿ–DrPI�UòÁîa!XßWNìNþ!Zƒ³°Aü:ôe¶’ÇwŒ@úã5NÇÃùdÞ¬gäýEv{«ÁmÞo|õ²\�8ÃÏÿ‘e­”öÜåÇþh#ŠÌñÎ3Æe\ |¡ UÆòMÒIpõÍÿ(:ϸž¿6Ž·*¢¢) Eªï¹ŠD¢lRHHFY!„¶¤�–¤¤B[´û^×�J²Z4ü)QF$#{äv?:OÏë\ç3ÞOÎavºc1ñd<©˜\†Úû·™þ‹¥¤\sÊ´âŠ$‹Ô?ʶoð-ßs`A¯^)vÄç_biÑú£–%áà HŸ¦Ô’¢~Ì1ëÄ$ï¯xö[SržÊûL¿ �Á¦US1ÄÑ�„˜3=´OW"úéåÜû˜eÛÊGw0ÿÆ6ì=Êê[eu+ aðþ/X:°˜+�ÏÛSº½ “ÉÎ%èÏï£ñ$0ë½É{ëõ°ó!W!ºN~þT…[2ß¡|ê ”{ÌÁ•féõqÍìÛ)‚;3`Ùª+tyþZb¯Ë8ön»¶Ï¥ ÿr^@³=ÉvÜXœ“ïÄÛ;,…<ËùtMdÓ3i€�?¹¦CÏ™Cª4–îV‚ŽIʰsçKüÛÐB\…;Ù¬K†cþRßnèañ¸Îo:íýÈî-É��£(¾&˜Î;ž…·iÅÂ,þ…n*×°È„f'Ì&Ñ\q:3J‡”2Ê`ez:œ•kaõGËI$&Û*{°#¢ B®9Yðì=6:èÏꆙ[* 6Q¬g½ÅÉuiÚ}Yjž÷–>_kaGÞÏ ÉØ;,0ô .HSeÖàþ=¿°ÄW^P·$²ÏåÁºÿ4ió îC%?ðÑ ú*šØ¹Ü–½¿Ÿ� g ÷á)’‚SàK»ïàøÃ&4k_‰NzÅצÓoü‹A$÷¬Ÿ['smÒÙ”€É–Ìâ¸=oJs…xœ—�?„ü©ß-ˆEžü~°ýùکʪ~^c=#K`IQ|ŸÔ`¡çXŽ�^*ÓE{oúÓÄNì‰eic3èý¬tNýÝ#˜˜nÊä£ã �(Ö›QïUºphŠÀRÃ`*E”<·yðõ¹ºÕÚü—4¥1ÜQß “õ6Ð7¾’sÓéçÜÛ a‹õmÜÑÕŽ–/qþ)Öñ‘°iq�xîB  çºQèÚqöD9æ·�ÓvP¢šÇŠß²“»2A[:¼lÖà}gb¾ïï¢�ý)Ô3þÆÔ—3=—OX½J’IúʺÜ-¡äF&�I�Ùwþ0¶Ê�Ît†K�íÁÇ%…­Ý¾™ôMðݶ¹´àž<S’�«ç臮8]ß-ÂGüᘿ;]Ý[�µǀϵl8Ì|sñô˜”¸ç)K�v€…×ÜNÏðgë›ê#«÷îæü?ëBfó88ô6œ6¦f“�Oq/æ®�샷¸Õ™š¾¯É{ÏÑ+F…¼¥dÙÇb9AÈÆB ¤wdìñ—mRó$gíd¸Xò‘»ªrš›Ëj¸o'Ýñ³m ÙÑBiˆTžd)ѹ†å—0ýèpöl~= éŠYͰ-$áEÞð²ñ ŽmÍç ^'[¾/p†Q*©pCB�lÌØc…—èïp÷ÅüFó¤¤ê󂈺‘‚Û§ƒº_ ,ÏÚ@þÕ Á<)›ÉNÅÚœòbп6š�Rœ6j£½ÎÐ$â r“3Öe�†!¾M‡?W?ðo­•`„y?ó¼s†¶õ/ü×·½ óR^Q(ck�§Ì):z+’Ä$ ñüžp´í°Mžf¤õÑžt”¬hÜÊùT²ý,Ï[‹û^)À�ÂqT6{2<ŠgC/«ñ"ó|¥ààyúcÄY\Œc‡–ÂZçÍ´�5Z®Ï9M¯Ï>GaqIËÐ�¡¸Ýôꈣ�ÿ-ötp†ãëgc…aëU4‚ò)÷ákÓÀlˆ½ëøÏã™[ë ,²¢àÐê8.¢SNp¥³ŸeÕ£¿¶šhÙz›ÝSMc Z6v�d-[^à{#¨¶Û÷§6ă¬¢'ûúUŠú 4ÐäÔ êô— L=ºÙÅJεãÓy“ ©8�fÔá¡Bní>µj¹sóa߯´àE6í°‘hS­Oó›Ü‡}¯NÀ&ÉRf•6nÝJ„¼gPÞq:íº9®çÕ£�d†¥ê�z°o¥÷,’;®ñŒ•uèÑèÛbP4a;½Å#öçQÁf Û¸6“ujôã£DfàteŸË jR4๠…Ó+ø]Îe¸{õ˜Õ”H%j1X{¡×½¾íAXñô\ÖÕ²Ž�?N¯ó­qý2Wú)Dö�Côêm™ g"e¬®Æ‡áõiØzí;²{9d¯~Tup©»¬œI:5qÜœ�mø*ÔŸ¿tæ+½FÃ>CxJ;…|´ƒh÷³xX¾k6ôü¶e ²à×øžå›8CÓÓ»Þ•ƒ#Z3�{dL—]ñŲ*h)+�‹’doþÚҢɻ)bÕ öq×]ø÷$’A®y ©^�3*‚Iý×_ oÔ "�HNâÑ4š þ“m“GUã?¡ÿcs8µË„-·ÃÜÇV¤XpÆÏyâ¾cï“,nÓp¾U­Fséht׉�·Ý”k3s^ó 0È�û`�s³ïAŸª«Øð!>grÑžÓÈÔk3WŒG#%¸v/š2–è�Cêöyóe;Lšù9$’žG–¹<+SžÄ’š�ÉëtÐõ“n Ôð7î‡5{†,.dŸ§dNÄÊij0L¸u¨N¡?+zYËw_¨pª`YQ®0yH™olH·2žXt‚.X¡Œj �òË9Ì^DÇ#îñól.‘µËxz£B7�ijïKNïônRµß«ë/‹PÐó(ª6Ã3ñpwÄE<«ÍÁ’?+!Sf€åêÁÑ>¥\GÝEœî׃]‰³) ¶R¦ñIvó‘þ9ÊežßĹå$²�7°õÒ ¨æÐ{Q Öyõ°Œ“áhðyô]ß�÷ÿ³þ³«Ù7Ó—8ý‰ Î?IIçîqáÓ”Ù¬ÃÚ¤âü�C_2ÙùIÌEÄš¹Tm¡áQ…pºó!ß}TŠâ–s�‚Õ`îøp±ýEÏÍ&B›ê—jQî>uì_½Jùg‘U‰~ûµ@#] ð*Þ³ˆ«š»ì%æ…?¹¼–qÉúR_£À$½�=ØT�ô£Ô™]ÿ~˜ÿnü“áäts£ãÏ3qf¡$¥$òß5–�Ó5èZs„�P<�¢}I\¨ÛH·3FÏ�g-E-²(^Ù�Mî¹ÏÖ”ö‘×ßÔÞ¹ôŸxA›¦Xô¥±Òó²‚Èö¼{L®Ô¶“§­Ëò6yÉ"¾âñ¼Q" “ÎÁ� Zôyg8[N€òâœý±@˜ ;‚fÐP’®àSÜ-Œ;œëÅÈ퇔@qr"ûÕR†¯|6ÐFåûpHl+ïIi¨üú6*ôqKöâ¹è4<¼¹ÆÏЦ›õÆ ¹²’¦²¡™õ¤4S£ ŒhùtK´*Ó¢WÓmamÚwôçô¦táZƒ޵Ɯ–Y÷â…úlêó"l|¶�•5ÉÀÉDÈ–•à«L#ØsïL|÷Çn¯‘¤¬ãÑpûUL·KKPec3Å—•BÔèã,ÿƒ ¸Ÿ| •‡–�ù�!¼õ:´·x1¡»b4mU ü*µ†Éyñü’²ðÜ¥€{dEÒÝIpÓi¬•ÖÁ«–õÕ’‚;Âáì¶Öö<í&‹¼5©\¦Çü6òßߌ7½öàŒeÖl½Ž;gœlM‹�OX6äCrj*õnåã=réKU"¹okeHEÐã{ì­a«÷¶$cyû®…M]é�>­qdkãÆ-òTµôÊKÇ#«B!õè"hS»Êλ E„½?,TŸ(èÜ|„•Êf“Ÿù|fpI†7Î.�œ@�•ѤÞÀ£ô„¯xÊ|)Ót” 2­ŠÙ°‚Þ.I§8[ö+¦zstù%ú0.M·¬²Ã-…Âø(sû³l”=K¦–âô×x*€·šÀzp'¤]?@¡7tpìýÅpéUÉçÿ©z¸$š^˜V—/Æö³à×e+ì. ý5N,A1þh)ÒU—‹PÝþж”&’¦Ö-:ì'O–à°`%ÙéŽc–瞢¥û<ØçÿG4©À�öÑl¶Ì88ãÑ�"ä¼îªÿ{‚“¸¼þt8µpœ@üñ ÎûÅÏ•8ƶM¨2K9ϧm9JúŸB õù^T£«#áKßl~.ÔУf¼« U6$Ñ AYí¨ª¢›lWW¼}9Ÿf_ôÇinàšõˆ¨K’fGÕ›ÈdÊÑãuV4:¹�nümåØ1�DPÆAeŠ4”ƒøŸ¼WW¦N ƒjÍV«Ü‚›„>àÏ #<øs�=™‹Àog+{n£sûúoÎ2øòHTüÙ…»Š™–s,âÎqYe΀›`¡–L8= •ÓÍ`¿©�Õòƒ{ÙŠUÏàïµ*✂Aû@"?Ýg39îI ›7á’Â<\Í}¼#76M…Vß��àN»�aóð JP!9^ˆD7|‡ M 2¥Ûi°4: 5 T­6š\™'ר‡ÇÊdýú{þà3ñogŸ/ô±ü‚ëè•û�]é= ®ªah§ú‚»ù Œ3à„š$øUôCÎÁ³ìF� |*� •;7˜äMdÑ[ŽÁ*Ý"^ÛNж8Ÿ†£O¸?wSàé"ÜûêMí<Œþ»GAGóv0úå�ß¿|ÅI>5øGz9¥o¸DV.št8þÙ låm÷+Cáð\þ¯Ç¸nÕ†YçL»¼)Ä÷.}�ñ³æù±›å?1<ò/³ FÝæ­l·P^³6‚\mZ9~ ´Õ·2ëo:6þ$©<}„/4vÓ½†8˜UU»ÖÆpių)sпÚíƒ#[<'~n�ÊeŠŽ‡á~'öbÛi8›x~åÍ¢ÝGŽÓ—K¥x3D‹½ ¢W­%»óHO%][×÷}æ·ÜY2©£hò’SäfóÔ;OÀc�¥O;¹G Gýã©9à™ó‰Ÿ,¡*¦¡´ñV ’5£ÃÊ#AÛK‡|îö ÜŽ ‚ÃJªóü³Wè”_¤Ú½¥-×JïzÎAá”çà:ï9Sk\ç•¥àÕÅ �;Ò CÞgXÝBî�ÙÖ3–à~`/dÑTê-D6Û> ^%©Àظfpkƒ§bèȸHÔ>UJ V äûxòŠ6&‡¯}ìô€½Uù’gàSGϧy�ü`K)lê6ƒ¡6¼]zöýËþÿž@�o>§\6ÆÊzZª´¾gVî 3Ìɬ³žýœ›×^ìÕY�ó+š0Üú1S³M#5ÿ%„Û3ÅÃ׸µVG¨L÷¾;kMïY-*é<âæ„%�«µ"¼Š—ãæp!µ/Át%@‡·ì4¥Èöxš·ÉÖ›ÓÞjúñù0lLtÎë Oc·p˃⩱¯�mR¸ÌÎ?ªfщá$iW�ï6nÄ «>`K#eþóû€†6Ë…ŸÛð¢p0*V5×ö§Z¥úAèÐ?½žªL€UÁ�~Ý‚¼B³7ç‘IÓûsxR.ì ö@åõL~ý=Qj�†z§_Õ)íþ�'}ãs­)nÉiæ8&˜Vv^Ä“g²`v€«»|ÜÔO²¨Z ÁÉ*ˆÖ£oÏÙ§ |¯Hsäé÷ávŒ°8¨G“Íׯè133&Ì+[)X \Ãzþ& ›õ0}OIMLØ™A¸å<æ¼BÃ/Rð·^(ˆ 2— /øÆ^€ ý+èZe:¶„‚õöôU¸„o¿ù‚µ;߆,s ȤˢA–ik]¡'ñKã?ð»¶-†ë㞃¿ãQtû½Æ8„PÌÅ ]ŠG¦0‡ «¬¿Cì‚âlèvw¥u_\Iâz#Ä~”‚Û‹C`¿«ŽxQÊ× úÝšËò.Á�‡ü‡•¿�›‹òÒ©LbÕ fÝçöÔß¡ u–;æ"¿;°…gSü…C5äƒiAq¢´ )�‹áôBñ“l"û¾ð3ÎY ¥ËÏâµOQ°}žØå<ßIz¼ÆáùðuûcÎ:ó,uÙjj%2Añª\h’¿µ!Ó2–¬¹Ç]|2úÔ&RØ’S𣣠Üd1�„i¤yÎ8øCòÕd�T\Ë~V¸Ð¹•Ž'MñÂ?¸n»n¼r!öÅ£ä‹?p;Ì�¾$H�õe+xfpW*³ Y6Íž…–@ÊÄ÷}ÅN¹ÝöOÞ¥ÐÛ™z£½YâNÍçÉÌ $l˜Mú�ž�ÈÇu7IË£”µÀ'Ñçüð�Pj2šNºUQø¤é Tª•X_Ò ‹…Á´zSIþ1œ‚&³Hì¨�aæÒ8&Ç +DÞÃåŽôªg:høIZUjê“%Ž…†¾ÐQ# ‘þÿ;ÌêhÒiŸ/'»�®]4¥Ží“YÌŸK¼ãÜ=lEÑ,Èv!hþYËú®®c# Š™�ÑGxvýM³šfþ쨕)HÓÞšµl­c-p¯úqks( ŽkQGè|S=„Ë]°áå^¦ó7‡ tßcßõ‰Ô1üŽI¦&Ðè-vëÝ*ú°}“~Ržt)¾#ƒö#´5ø=|í“mÙÕõ”|íægPç´:¼¨Aš—añH�†‹m«Pá#ÿeÞû!v'Ö�¾ßdMr×ø„ ;é¹ÛoÌZPÈäFi’Žç$ öý�%ÜïÜþê‘Qúð¤¼C÷BÊj <¶e4Ü8õ˜Ÿ¾ê( Ä'Ð�¨ wö[푦‘¸pþ z‚W¸0ó)àÇŸ‡‹e¨jìnÔ/b~÷ÔžÔƒKçÛùç5Ýib=—é§ÆKþ`€÷@& t[B©mN n;ÏþkS‹]ôNͤúÝ¡P9·´~Õ±oÑöL©þ%9šÃ½- ö®™*ÓFÃ�ä‚K»˜Å›:ú +ʦ¥ÀÂÌ^þÈ… ¬fß=¦Ó\Ñeìú #Ð[NÚ[y6¨L›'7@ÁíÖiÖBŽ•ËH[)„ucCŠ }jc·Êf‘Ó4Ž•&´±—S²X¥édz˜ú�þRFÐi‘§hWg|JÁnQ)ä~§oâÃü›!)ˆ9ÄæÝ’­¶ù@gÛ­Àvà4|͸/W�„ª‘AÕ\µXå<%ˆÈҧƦÑ4wn"�¸Çßg‚Y¯Ÿ²öIôîg!ŸS±Ø\ág÷/ŃJh· vMª�¥¬„V/Q§äÂ6vËd+«=qÔJëÈøú(»gì�?ÈoG�½-KàÁ¥�èwLƒ|•àÏý ˜p&J^ì¢0ƒË5n¥ÑÅZ׿ å·±jÊ4Hz˨³'Aæfhy7Õ Ï0G•@ûñK0 �Vç 6.&ÍÚ Šâ,ÆÒ÷1úL¥g唿Â�Oatñ_Þû6>§ÃýŬù�8(¥s%¦3XìãnÜë,JŠÅ!Ðd]ÇäkámöCHê.‡Ûýq8F]“öz²u��íÝxñÌœÁœÇÌ@&ƒýÒL¦àÿ¿¥RÇhÞÍT6!­—÷‰Ðà W:óКVôÿÓYMù‘ ›j3پȽørH�, Õ!sGÙ¬<ý< ‡;Ø‹Ú] ó_ã-Î>ˆ.'­OqËÕbú1ò{á�iµ�ä,Ä‚›� sÀ�:Öçb™²3ìúÛKçDµYÛ±C=×Rs³hùv]ê{eLJ¯Xƒ“4Üwî†[b^Ï03î\[ýþÒHAËŒst°eÝÅýHfÕ_(~À©{Á�#aÌØ7Ÿ}éi¶œ4æ5nþÌBö{Ó–;ÇifT78ã, ¶ %©[:P;ð¦úïõ%–龜ñïXE<õq<ûtºú©ˆý8%JòBÙÔü_h~¬„WO�ݶõè°ó7›vÁŸo¼ô‡S¿9‘¹-»„&¥,ú»%E¤Žç,Ú¬à‰°6¯ÿðál?–¼^‘ôÇÞ'×6°îõ~›is·ûÌ÷-HD±‘’ÜŠ#ëáMY6 {2KÈâàOÛIøÒ•Ôªè°Û¿x|B޵©ì³/kq/ƒ…ÅblÿtE¨È~È4j²!ìÊSæµDƒi È*.æøM}RäÜé¥Ö¡šR¶¯úÙ߉P ˜MVùä{™�¸@.¶R©^ ³u�§»?±¿\7,ÝKÇÆ•ðv�e@Hµ�½ªîDõ¹Ø­÷”ÕDùá&ÓðJô =» K$UhR¦&oíyœFzFQ•¦!ùÅÒ—íàŽt4°W²ê�§§Ä†ÖÑáÀô³—XV£µ©¾à5ú“y ËïónVlqÌYXÓzÙÇu %™�©Ïzèј¿V #“LpÐj3Dø%²ž¾4 E-{7p÷Ej0Or2Öì†Î_% eª Š¿R êG&Ý|WCfÆè™™+$EL¤7ü _2WÎS†ÀõdjÖH©Éß1bz8ù›]@#¡£tÔü?ø—ëëßdQ«d*êýÙFûc³HÍz.-®‡›QñLÃü›|ÂÏ_ÂñËÁÃdµW B˜?Ìr¦a›\Zõl»v%ÚbÏ�ºa ÉÆ�‡ñºøíË»¥u�ôÕMaÊ�‰—sY³n3Ž,e'&1ß‹£1à‘L³¾LRVsIíM�Úü¾‰Ü�6EÓÚ�“èc•*Œl�ø >ÇïÅ®5‘èRó�I;“?DAþäW”33‡½�—¾÷Ÿ¨Œ¸cHB¥mö»&Aošó °GV;�Lì¶`ð‚ÍÀz;Ø«]¾ì‡ËY\2÷5»ü�-휡þs.,�šDÌæ8ûµ³ž�S©?Žg)aci÷Æøø{XàL.*œÕ¼Œd¤SK¸ ·‘³V;Ü.|´½Á®ÞÍwfž 9ómòTø2‘¤6{QíïHT9¦ZN/øô¯±¬¹~ ]O’¢¸sa’o/-ƒ8÷TÔº±YP‡Ù)_Y0¿Úç-²¼ë³6®7bNU�zª.ã_=c3 ³»&ëøa½3´qè߬J·öÂýØ[ìÑo#º¬,*0Ó97[þÝ#/o¼\Ìw ¡êxŽ¡‡)þƒdW½vÛŠmÉC/g¨‹OAÝQøïÈ(2iP´Ú{´ŒµHDñXNÛÿTâ‡Æ,V,föi�øz‘.ßúyˆ1?sQUC.ŠÌd{š.rò‰1)][Ýæ�‰v†àëâÏb´âøÒ �ì­Ë{nœM3_ÿb+=ʬÁgLpÛå“´Óð"Iãȯ¶�)7Ÿ²|£Jèš�lé×3¼Mý :ŸGøŽêO9gI$,ž§_#íw˜du„Kâ«®þÅìƒÿm0m6Õ¯‘¢US/°ñõǰ8Ú�b² ñ&äcâ¶xénØÕX„_߇‘W_ÈIÚa©|8öìÃþÌsÌ/ÆXw1œ?_ÂÌZó!5ÅÎêîªC4}öü>ßMÕcøå½ÓQÚ6ÕòNSØi�KK7KLÜ/ò&ùÿ0Ì“h•«<“W}`éUÏý54`"ç¿¢–ÐjË'"4¾Ü‹Y´ö`„“%ëL æƒg†1�äöú.Fx½¯îßæNÆ®É,Q‹?ùÓ�ö¾æO­ʼní3˜ý ]l?vâmÌN%õ‰¬¡f5¤Hš“×€n ÒtÖœüž‚>Ó�_Ÿ+›m=Œi'­H(" FŒ÷â¿Jfr}pe…2è+¥@QF"lÄÕaÛàDH5^w0#ßx{}³�Ù¸_­ö- {š¾cAy¥Ä{T¦˜/åÝëŠY`©}ºt�yåêÐÆe¼þõ¯xMܦ‰S[^ [¶½�^/{ÏŽ=á¥ç=#óyÅÕe+;ÙÁŠ¿lŨ…x†FY ³$§!îÇT;¨L¼µË�Càr+Z23Š„ ÆÂñžX��Ÿ U¶ãqÇÄç8xu,žçɾŒVÇÏÕ™`ö!nÝ]B[ϱë)ªaÜ»tîÙ|Áñçg“¡óK6hy‘µ©Å“Õa�«7þΞÄÕõí_ÞÄ�{ß�@‘¢$•`IÑ4À¢‹´þ¼œï[ÈÿÜ:=…íéñëu iIg téTa@U½ÛI¾ö·<}´ÈÅåe�¤$¼·št£Ei¢v. ©œ!<‡ÓBýapWBu·B- üöf»6JRpt)w€�1-è¿Æ”Îß�[åè·êyËU}¸¡xOZ¾\€Nb:°_baé~¶ÏS›ýi"w3%øí1ŽDì÷Á¾LO`uˆ1ƒºðáÂ&¼(ÒƒK]ΣÎ/1 'áôë¿5B“÷(ÐrPdýaË貉9ˆ¡d|�Ê!“šÑ�ÁvýD§¼F¶£Ô ï�Œæ^:6ƒRÕ^ŽM¸Ã¢Ïø¡‡ËjrO>GÌ-×íoÆ ^3ÝÔþªæUä’u•…–�¡�ÂpjÙÛÊ#'S«Eü.¨d»¤¢Èêfk\³œ¦�ð¾`˜G¯wÞ ‡LÕM¤Ñ[ᨑaõ×}Èsí»{…µø‚Ú®™�Ý“ú�™31î¬à}8b?—¬Bßó5 [PKt˜ï‚Ð¥‡Øµq­´-m[ 2€¿3Ìø®ñÈJ iKJ4-ûª@zÓØéœÌHÅ–…,£ë7²ÁPXVÔ¤ÇYTŠ9褶žÛ’Còû iëtIšµ$2¼TYÎU¾jäö"v?\™ÒM¶á¯m·ù¯}é8ñbµ�û†>"Bôq§5%]©¡ù…÷Ø£JY²0ýÍ?uX�¯l€í÷“ÿÍét¨+ŸB†RÀæÞ*¸Q<6äaò¾Et&° ½¦Í¦ÑéÇÉåY1ìûkŒwjÇ�aäIXl2Œ'Û{Ù·ös,Q¿Õn®¥… WàDþL¸üp4í£±`;m)ûYfŽ7~»�¤®9œxÉû߈‡ç9oIêc$îðØËzïýdW’u¨îòôxºŠÞš×sG7Í->@=¾rÈGÛ½Œ:#•¹dµuà™TË̶q ×’èu ›_ O& hå$IXèwœIN„Í]‡È¿m Û¡DÕ1'YÁ`¿8ý ¬}rŒ’·��≧°Ñ;Ÿä ¦’G\Iܬ—P!OQ#ðç~aã3ChHSÇKEi´ÝøE+†‘CÁdp]êE�„`D¯9.q¤i šrø57˜D3¦8ÁÍÓiÕ»ÇRˆs0^-:HϼŸ£GÄþ�­%‰?i†ÔNˆÚß‚+¿*ð[gi@ì™×–9fwOÒÌÓY4kÃ2’ê âú“bPôP:íë9A»¶Ÿ�Óî¾”žï½“‡øà³óY†BÍzÇŸUë��ËMÉÿa­σMÝýœÕ÷~´Ðšº»›ZÈ�ÎZqNc‘”`àÅ#6"Ñ |5•`ç»Åh™ìD£^"›nèÂ:ô6°C;a½ýWZØ•í½Íÿ› ŸçãÍà+Ó[ çLöáÒ¡$jÿ„³æùAÆø $Yž�ÁOݘën3Zj¨ÌÄV�&¥ía,mk� ,aRÜæ™§A¿¬Ÿ·l´Ç©DdyƒÍLõÏhèþ×÷Χ$³ˆ¹’qµ‡ÝØWÈJíD¡°`ò¾³�ŽO7gn�¤DÜjŒk›¥ûÌmœÁuúcTÈìNåBíÍÏxþü¶$& ßzÔƒ…f$^^'L®tXBt0)YÉr3/�$SQaÁW§2r?¯ 峪™GñoçºYü”Ͱì�4} güð‚^¶ÿü,6í¦2Ú×®Ot§÷nq‹t€­¾™À„Õ¡·“ Øn4ƒ­ßC KMÕL½!pDÜ *Ǻ�khæaJž?’a¹t R¹Ë¶.o%Áê£l¦Ïsîu\1®Ðö§ÕÙe¯FzZ×Iõ.’ÝÌý8Ý®·Fø�`Š+T¥G²­Û3¡²<›†1ÌÁm¯1™•®Écq÷·ÂºÂAˆùÙŽƒÂ:¬7ÿ¨O@+¬Œ#.ª°æUýLRqšÖ7vÈUXÐü®�6΃‹YDóBÍØøÔãœÉ|†÷Yc÷Ø2öå=zÚÕ…²Õ®ø;è7öß.F³íýüÖd×ß@“Â%i±x†¦ž„Ú+œŽüBÖäаè+¿Â �blhÃö“ì™\*.»ì­·B›L'l¸·Ïm€ùýrhdf EËæBd\Xˆ²ŠÐ4:ñæM|&S·'‘ª¾�Ò>�YÇÏáÏo}l³V%ŽÙÅ&Ô†Qo¥ kŠ×$ÿöø¾ûKÓÄù×í(Q,’è#çÝÞDkvßá,ßÊ- Ú ±ñP~Q–¶H1VƒÙ\ó_�Ï+Àß#O±rê¶vò÷ûsá’íHз�#ñß¾¨•ù ßÉaÇøI¼†Ýi�þS-Ö¾„öˆ—b…Ú rn…pÎŒÆw§°m/ÇÒ»=ùþ tC9ÑIŠÀ9îcö›ãèÀ*\‘.Bn|sW9ÌÕæÚÁDÖÏÖÌ%xé.°TSÎ JÞ2ÁWp£…±¾¿±(üÏçsv C«e3ÿå¿L¼ùb’àT·-̸¡÷WΠ·5ûÉÁ~õ¯Ï`Y«fÂÂÖ×üíè±´s8�Yz•:ö+B×Á 8{U4‹Tµ@û´:œ^´ˆº.œâe~]#ÑŠÓìÕ»] Ì¿G!³fTÔPË91Ü\öCº¯rs¿.‰žX .–Æ?éñdwפ|O³£mš4/¯ ßI#嵘ö^þkò€ŠQ ̤IãÍ4²ööu§=œ_w›êŽ8eC)ÊZ™Aöê½$ò³�eŽhF¯•>ôúP (ïH@y‹`L»šïþSe¿Ö+óÒÂ;ô)Î;y ¢Ÿ›r3Üû`0rïÔ½ ”®è°”�-TÁGð]ª’¿.Ž ¢Øm{¶#ïwµ½„{¥ê¿Ã¯±èEøŸ{Qfž.,[W�™;C• Ÿ¦®Æ‘>©Ü4Ómø;{2¾ÏÏ‚”­s gVZÎFîä»j­ 'ñ¿‚]$+íBÖ)¢¤kdžÕuÌöÒÉûr0øJ¢%�]½Û�'¨w‡Ëd·®Uó~#%)g³ìvs€šœ—èZÍŒE¾CŸg é*fÅi2×éËq¹Â P»â ¢×™ÜÒx§Bz¦ú‚þ4Z·G“�¬zÄ7Ø ƒ›ÖryÑC¤ÔÙÇÆ$rá£Ùn;ʽ3™ ?TàùÎ Jmm„ãß¶QÃ�v+ñ1coÉO­eëÓfs‰!Ï ð·?„žGk|†XÜÔh®õÔüøü Ç_kG‘ûÜã¬Õ¬A_–Ì=jØüËi4RÆ—•|Ç0Çyô'{"=Õ‡y^‹áØ3mX׌¦�ªañ•­t¨OÜBž°ÞÍxMø¹ÅÁFõ9s˜™È,Õ;q™Å˜ð�§õIXàXE®ë„°[uk?ãÛÞÉSŠÌuÌò{ÆôßýÁ5'Æ}[­F1 ¬Dáz±t9BŒ�­ˆgÕ¶§Èªâ9|}4 <¾ß§CùÄ� „a£¡Æ]Ç„¡ �ågj‘ì‰ø7Ñ•S \�-±Út áß:Ê‹¬Ìèúòë´ÃsÐb¢ÕW¶~gkM�ãLþÛB­œ6É–D1þ’ yü벟%ñ#öíx9K¨ˆ¡ìôó4ùéoR©Õû Ä^ ¥çP všK·ËGÈMÆ]µ™l¹O'ú¯” ~±$àQ«ûÞ`âÜÞ#¶­úÓÅÕ²\vf- uÍž˜;â K ɦ÷¥ËèàÐQ¼|·ï•ÅÑO™Tê¸�Lj&³–õɰWÅ‚d;6²Ñ o˜Ô5#¶ã£'SZ7ÌBbƒà‰’*è7ZVûŒ>ƒÏRƒ(N~Å¿œöovsQ3aWHs²—§Cúãï8R'�M7ŽE»Ì“ìè ìLi£¯_I²¥€ î¤ñ3ü¥@D҂³š�¯¬Ã›§$¥YÉCKXå…“®Åb­É$Ì<#Õþý¨ã(Bcs†ÐpN8¸æ…1ýh5òn¦RÑ¿œ:Â:§Ià{û!ÿèÜ2øÛg[çæã Ö”S­£®§HxPŽTê.óÝü.ü~t aç†�È~©>ñ{d`OÙš”0�ÔzaϸK´ôM5jØð‚¬óF “/@…x2{p3•9TV±´qåw!‹‰>E4¨Œ«^Vt3×ýd_,3xc›¦êØ€C¸{š¶Àz´œ˜@û341}@4¶ PòëR,­ôÁ*ŸråΠšB:ˆùžE˧F¼ˆ›Åù΀G®lâœ1P9œÆÝ_!‰RÀµk1Õ6“½ÀRQ©diÉauR¨ 5{�똵ΦS#ÓÙЕ×èTôm?-E³À/˜©¹ƒÜguãéÙ °Íò Kwa3à«x=yýÌ ‰šEà9ë§é"EÂk¬ }t?sJS†€]îìÜd&™óxŠðnbÁ4óÂ/öõñ¶Yè Ô$Oņ§è‰ÙOnë•”j»LÓ?͆¹‰ž§žnùYœÈàͪƒo”Àð¶�ò”EQå ämq«B…éÉ7 Ñ»ÇlçßÇŒ³Bt³ê4‰ähb˹Ôú˜ß~d¾þ%Í©Ls¤„|?&òI~iÜç®\ýÂÎ-ŠåÇ÷­ ÕÉÔëÝA&°Ëx Ä¿Ÿ>3*X«Eš%Ѩ¼@À>oµlZ1“Õ¤ “\úÖ¶’¦MÅê¶H:;w›­fL÷:bÐÞ0Œv‹M ÑSwÑýÂiÖñô|õ«€ø3ËF® é^i´JLYå\çCÚžÕzâ6¦!_6tÑsI{Z·½´ÚîûMVÕ©ÁÞf§cþ¶&x^úŽ·S\‚ lÝŸ lÅÙçefÅ-#Áÿ9£ùËïà@ìXÖr÷8Ml˜D†Ñ/YjÜ2æ4sˆ‰ÌKƒöMU˜µ6ž,¤�)ó¬ö½¿¶d˜êòŒ¬M‡ÿb9Tç&Á·>9me.öÔM$™a;·CŸŠ)g^"'èYNwWÏM­ ÜÇÿÿ—˜*Oku¿rs5¬)õÒKô=ê›É aÚ®³h|ÝZBY-°‘ÿNÅ’¡à6ñ0ͰñÀ·ó¹-ŸL (mWÚIê—~ÃÇ]»ðÕÊöld!.º‘öonkh£ÕöõU:ge–„Ü~=Võî(¿©$—¿µo,;Ô‡â1‚¾œàvØ–p œhÙHmÐùÙƒaõÃÈeœäö·çш›­ì{× T8"ÁÞÀHp£:½ö70�füÓŒÆöŸZ1ÊÂÛaW00›G i¯Û£P4x�?®D¾^³èÙ-ºw¯”F>Ä×Õ)0½žÖµ^b½†òd÷÷(Ì0®ÂBtb•é–tHËɲÛVÀ];^ݵc¬ù—MmDùm«A“W= ð¿ŠF]I”÷–¨kæVX\×Üd­–v®¦c9~ û_~ øÆ ]íeQæ½Øhê+¦B½o“²5 ò›èWÄ_“aQ[™kÝiÅ{QÁD·:ê7È&õÄ¢uQn=6Ž"?ßfÂŲT´—£:SsêJÛQu–-Äô[“y˜*‡iáÔ¯!!o:8Ø€—¤ýQ¨/w/³$©©E¸á¬T¢¤M²ôÝ …Nº @Ìá ['×ÃÄ)Ê8TGN"•e èá&÷¡˜v ÙÓBºu«›¥ýŽÇ½S„!To)-]w…e-êå¢g-$¥ÀNÈõN-•ù¼«¹ ÕEÓ¨Gy‹YU,¥•(83Š“–�ò:™rˆá›¼i&G3‹¦�ÅÏÛ|Õ;ÙÁ¡:ªZ.ÂüÖ¾ÃÆ‘ÿQt§ñX>]Àí‘lI!k¢H¨P¹¯9wÚK"’D”’´h¡òÏš­D’�Je�ášsK’¨h%!"Š$¤ôô¼šwó™™ÏÌ9¿ï«ÁñO!DâêâæFsO�¡e…Jxtùê¤#ÇŒìH¬!··ô1 }ŽtíÖ¥´Qñ&\4�Éfi×R‘ŵøa,‰˜îŒdü÷]Â*› Æ£TÄ®þe5ÖÓ?“rpÊ#µ=ÉÙ¨_°mý Øðµ�vüÖÅÕ ÔÐwîæZÀ;’1îÚãÓ‹ßQF"šý±Á3í+“êt›ð½ñ„[äæw˜ ¸ž€áU' ‹o3u=eDŒÖ…Bgázl2¢Z_x¤^J°ä%ýµÙ“JÍ]H³ë¢xÐkò¬gn©ž`~|, ÒK=T}Ù¸�d(' ùîd`gÚ_ÆSË“ðÝ¿IoHþ*w–¹G·E-Ç4ái8zµ‚Z÷'@ò” ÿŒ"H4þeöÃ¥ÊÌ_OMšú²6«Sõ´ÛLüT ý×àÖÐe°ð*%óµ`6ùL%ºéÜBw|æ*OjSÚ‰0†DÃÐFü*5Ô; :!š˜1y «ùˆç·$;%�DÌ$nsQÝ0üó¥UQì°ì!Rõþ¶¢Q‡ âž!ÊS’õñmw Ã]ÑóÑÓSÍ?:áÓñ Ì0¤sµ±Áû&±ùOrzIOæPyÑ¿¼ë9:—ÜÍÄoŸ|úÀŠTuä�o‘yØT@Ut>°1K–ÂÜÃ¥åy[d¹�ê�ñÕ¢L€p.øVF‘Q&�ÖÞ Çxþ~šZ»‘ö½KÍ7�oî‹pÔþè ¹»æ4®œ' /Ü7b‘ÀIk©E=×8Ú0›ŠT\ÀDigHº“°\_lìÑ_sÞÖƒ¢bäH³ ¡Ñ¯7L˜g¼ôaØÌN�£5Ù$°{7þÞ6òkÀ-âÖYÒØë{ O< ¸}„Ïk¦'—.ÃwNclXþ-"št{˧ãT$Óû“0}Žê¿µ~¦wí×c¤T-³XùNÞÙ†7uÄ!îd4®UÁ}Ѥ б�3ñÃÅóLÓ“×´,�‹ ¶‰aÆ%=óô€¦§Qhxo?IYÚI”øR³9çé‚… º?´;1>•¸ÐÎ7>Œ§H-_þ•¬ …ê}ëñÛ±jú¸8ƒmäƒÆ !úgÅiôÿZNíT£iÀ24o–�±�ý°P,”Èy¬=ÝŠŸ;‘U!ýĺ"žÚzúC‚&¥›�Ž3ó›B0£2 'öâü6Ax߯<ÇÊyÝëÀRêH²&W½@‹½÷ȪɈòîÃÉÀˆ}¢bTÿœ?áÌ‹†Ý[¼X�ŒŸŒHÓJ!Ö¸@“.ÄâŠü0è`‚ÓRgSÕßžðº6‡<¹Ÿ�ÛŽÅÁž=ŸH°¤!vÁyï>‘‘R=Å�VY(£¶ÒÔHÛM G˜ëê~dó£Óà­? x—b™Cý;ÑsJÖ.t‡˜�RH~™Bç�ZVд� WÐ=C_È�Ø�¬Ç'?`N¹BäÄUbóŠìÒZŨE�­VÞôeOîðã4$«Ñ½/oÃ;‹"æh\:éŸá ì51ˆ¯ëg¿ÞHÂ|!($[‚^+ï—u|Œe?}7Bþñ“ %ªÏ·Â&‹½|Ìg�&Lßñ�Xœ›ÇoΡ¦ƒg¬“Lb5±ƒ|¶j&Ë%±,æåwÊÀèß4ÓX‘¼/�ЇB×°>çXâú"‚j=JÒv‰ÑmI¸èw.Ù–‡Û$kþQ÷)AÀå£x®q=l1x0y€ª;ʼõÛ o'œQ ­Ÿ´4Ó¹ÙÔæR1ô©–R§ëX<ë)9ýü*ÕÿúnÜÆýäY†4xT~ ÿõOã­ù¡�g§‹òÊcXæV[8z�•‘‚ºqWhVP ©Ñ"œTEül÷ S=à”sAyöë²û³júÄ€œg+h}[מô‘Û�¤iahÙ¯s�ZwsÊøÍÁëàûòàIôÔ€ÌËÁ³?ÑŽ8¬v¥sÞQ±Ãëhv�4Qê¡ÐNÈ­Ägy{HéÞ~"u3¢�q™Þ~¤rÚ qã.yë3Ìy{ ¤Z"H剩¼ßsìIÞö”9®?œS¡�.Yd׋p4ýi‹¾+ÿ’Õ;dP]ò!ýo^0H|Í£nµÏñ»£×m {�|>ÜCz2ŒéÛEŸ8;Ãq±s Î ?Ȧ …àùJÐmüûÏÀ‚Àã§eehô`.Yð˜ ÜWE¶¾“EµÌ¿$\F†6ëX—·E9ÿ¼Õx@üX¥E¢Õ©i´sèüÑš>z©¤Òü*}Zç…ͽ&þaŸ!ß4~œY�¯þûFÍ.æÓO}È’ ƆÜoT·ý ™I�×>MØpé.NÞØŒ�F ÄKw È.º þ+—.æÔZKúÖæ6Þ÷ùNËœhØŠâ7âÈ‹mäPã?G…–‚OÑ4ôÙaL%Y³†·ž²‹šY”ÃŒ¥(¿¡”Ö:”1ǯ•³ÊõdÍ‹ü=O#~ Ò�Á§˜{ø µ¾?®U¯ƒ¢¥ÿÖ`˜@~ùðÜ> !°™m„Â…²p¿²�zfœÿÙ9軯�Œ )ÿüò�´‘¯ÓòHâµ+€r¡åsi€Â'ªR2/glAãÏÂpþ¶2Ù~[�8 ߤ×c˜ãMØÒ¾¿4²qÊaoÆn\ì €OÚ„ ÿØ7zî±pE·“îÁ^òÑn.,?s޿ܷ!Q6¾ès§†þ°ËG��åbú9p\|;ökÜ óÙÍpæÚMP¹ÝL?æ;£Ùú@\r¸.IÀ[ŒárÑ(ñž­2�SÉ{­øpJpùñ4`”gr.L›I¦†Ðï»a¹p,,‰¯`ž­áÇ}ÒX©t‚ðýË�bO hßWp ÎÄÿüýàÈÎÕúÓ R} È»Q§ü(@K;¼þ>ˆN¦R­ –ôÉm=òb7>:žEŒh5Y¬ ƒY§wÓk7nA­Í ¢(VM×GJ�CF)N ü€KéÆäM(™V7r<(‘éÿ@¼„GhmÃ ÎØGÐ/‰zù±›æ «™Š½¿‘“ŠftýÓ%°Êq'ñÌ)F3Ò[,ßÑÄ�¿¬êáJÒZa‡Î‡gÑ#éÁdnpý¨]ÅYâjí1:+^ê|ÕѲî#�tšÕ40(×b¥î@G–}™CLÒn’Ÿ�b;–@ æ]:lVOçhÁævgzsFê}g`‡¥) È<ÆmÂé�÷ô3RdÍ.‡àuh4ö7ý¢[ÎÙзçQUê Iç" ¨í(^tA“ôMìe�™ ª–Nªsù ¤Ìö‡ý%º_Tàžº¬›¾Û“4ÁÁ¹•|﹂Bç<¨wÑwZgr–&ƱѦ¸ÉôÙcÁ‡küQPÏêN4“–bȸ«bÄIš] ë?¦‘å §àò›µ¼ží/@m×uRqYg ^“ûF�¿ëÀŽÎï% Öw÷A&Z˜`¡‡ ª/8YÑë‰TP(~7 EçWtq¿=9>Ð�¼·“GÁªË•‰Ü”D2–„àUèL߇ÜX%_š±*†Z <¢·ùûpƒÒWa{J ¦‡>£¯ïái!S<åý÷ÅñcæA²yël®Nn³c¹ ¸…ÉQ5¡|t�Qc�&EÙƒóá™ÙðºhÐð3�G³RP_>¾tž¾ �dM“$Œµb“e}[‰QãÖ˜ŸRƤ÷76Ö‘,Öic3îm“ç~rŒûçŸ}äÌF\«½¾ÎÆúŽI싈ҡb\ËÞ¦õï.jÑ7 †+ljq=Ãk[Z[ ¦Â¸‘ì¡›Ðôì VÏÝ8^|\^Âi¦uU&¬Zî@OHKý«mUŒæ��PݶÂ.ÙCf �L 3æVnÿCg^³€OAðM$ ›þÌ‚¡ C¤Uy&&oäByÄœò«Bìñ—1àe�Sö‹píg*1ÍéPtþÉ;¼…¯d¦óuÀ‰*¼Ò–66«ª¾ëqx‡ý%1vƒNé¡«ó¼áœ!bò®G8ðù�µ6ÅŽøÃâ_lá�  ú>„T~Û%öÒ¿«°�£Ì=|ÆÎ<‹Í.ØZx Õf8aǶíäì§�J}Ϻ= ć,K“/­c?-†ážmðÐt;[kU„6ä.lΫà +Ó×QêxTîL}ï|vÃp¼¯…¶bø´çÇÄ�w€¬–%6—ý¡xQ*›_&e™rt¢Üø½vÁY�olÔ9^•}äj×WúYV€÷èáô“^Ä•ö¼‰1Kf¡>'ï ÆXáÏÔh‘ Ïoé'P7•¥¼k¨íß9¨8Õ—ÿíÃ;Ùÿzäë ¨¬¥’�—ïßÙª@ ×Þ„ª:I0~"H&æÒÅCl“,vT÷‘*Ðcñ�l�³¥�-ö�¢î¨»ë) Ù À;…U¸èúx3Ö\ÄîtU̬ð�Ü÷˜8K‡u˜(帆â@Š;ÿŠ¡µñ0{f"¤‹…ÃBeü±ÐGåŸàì1QÞvVw°Ý™™.bVy*[zî èÐà^\Œ³nÑx±Zμ0$kžÑœOšÌ·›BV­L6êÇe;7!×í.tý×B’mšÙt/_š»A–æ: 1Ài½ßèŸñ˜û‹m½ŠÄñ_ïïù2¢a5hà»…aÖXaÞè.8²ÏÿLŠ€±KNáõˆµ%Å&”8²Æþ†ytFÝ0MX/E=‚¾Ò(Q®¨Wp1IS�%ÿ÷&Ûòã�ÄÁrØôþC·ésñ?X+’X¾Ô' ñÌ#ˆß'»‹¾£ïø>ôUýÈG·�¿·ÒÁÅ0”61àlÔKÇ[®žpÌH”»èÒ\Ü1]ŽR$Ð+Ε^Ú‡õÇ[°ZçùaŒ8Y²ÃWˆá—ûϘÖWÙš_Èͺ r·°o´² ŠMÿ솿¬ nÚ XµWužG—¨vèŸ>%cwÃñª8>=Žòdêˆ›Þ ÚšE}‹ß“{«—ïØ…Ð8¶ìÃLi¢$I{¦õP{�qšÛXZ Wa¨ËOãÚ·ž„õ#ÈF³ÒСlD�ަÅÁ›Ä|²7€YõKf«"Õð²9œZFkƒ\ÒR\u#’üº;At4õÀïq<:]‰_C7£}ð1į Øç¾Ÿ}õþ›~á}ï=FN-ÛBJ#ïâç8=Ôšó‹ȾUæáTrW&Ø>J€Š©Èß‘GºW} â- T—u¥¡�1ô¨ög&NmYw< e¼`À£«Ü%ÃΈ| g¶÷’ϳ×bC�;£1=›F�¼Xn±d¦œÂg†jÜßQrÔg¢ M}´¡êEá_ ·“\Á2w�59ŸA+Ú¨gVrJ‚bû$2Ÿ�óþJࢫ&�Ôl ÊS§â·_…Ô!X›8é®Åý«„¸úàk~ Í\ßË>)X/ù0°5î W�À¦|µ÷´ìØIdýŸ¾6×µZw¤e1‘œ@Ò×™zäð„¤~?í8¢Ä/GÂP'Oï0j¼¹I¡yÔdGî£ÔŽùÿê™!ïQð|Üu#ÆÞé�³ð œ¬â¡{ éåôý ž!K:퇗ï&qãêj*׬‰åürĶý4-äÑk“Áð̬ö­+ˆ‡MسðÊyUÃá-¡Xdö/¯­Å·Dq`8ƒ�úrž�nÝÿ¿¸»ÓÁ7)°þ˜­‘XIžèZâ‰Ê:Ù¿î®r‡®,–4êëóÞ¸]ÄÞÚ(ý½ _®ƒ¹ßõ™›â©ðdq\ÉW§˜UäEO»I÷gͤê*pÉ °Ð‚Ê~hfDëBáÀð3\þÙ¬¼,oo{l(kÿa˜¾H•æüù¾ŠÜn0£¡Ç§ò~íÿMïŒUÁ¯­—Ðg¢ŠÂÆA©¯F£WÛP°h_qæ‘1iC|ÛgBWšáÄ?«Ö�ºDè,í!R�¼•l}E–,åoÑã¦N¼¤Àåa¦të¿·éQê=k®@À³Jp{¹‰:l–Ä"ó•D³;)9e��aäÃtŒjˆdª®å ôÍã–Y ñêøeáôŠ<’¼ NŠS8 ÛŠ)¶,íЯ£ebóñË‘ŸdNB/öΆý{,èóÈKØ—�"æ}È•[ŽÙ½�Pfø kô¤é‡À0zè[%x&Éð~N£¥bÑVéV« غ± Ê+éÞ>ãòÏwÙ±ƒdŽkÇêE?9”-Î^öeI&?�uÊÄØS% ÷#ëÖѺ+!bè"tíô§ïõÃa–X2T*ØB¬èg²a ‡äýÒÀ#Æ øôx@º€ÇÏtˆüÙ?…µÌÿFÖåzE.�ZJÃ{ësÈ Þ…“ÿeÃõá!ø xOÈ� ¿ŽO%×™Õ¬°x‹Ihýð ]á¢Ä‹»µZ½fÂÊ|=ò2®�Ì^w;“7ÀÙKMḚ̀ ‡’Ò‚MõÄìGŽ� ÂàbøÂ} áÒ%È}¦ƒO´ Y¹ÍlÅí­Ðë*1v꼋`¶¥Ì¿ô”ï^„U>¨ðäß™^ˆ&Ωª Y5LgéˆÂã�ÐݶånGÃåZwV·Èƒt¶²AÖõt¹µ,~LÉ¡&¹¡ Õf€™<Φ�^F0o‚¹%Y$Î� øÝK祯Àywù!Ú®—´…‘x¥ùåF~Ò\Ý#ÎÈI©‹}Çè`›%žÊ­¡ò:'0'П:Çh¢söy˜‘ʇ¿ëæ²7l7³^ç/ °¢®Q–Ã&ínø9O�ú¬ Aþ×—oYIFòýHçžÇäGï]ê¿$ކ—±gqó©Ð�Ìcš&FˆÃq+ZwÜ^Á‡;ÃØ‘ô›V'”ûJƒúÅRz§Kßg6ÒäÊKtGJ<éQµE®¦wãõ/´ýN³ã;C_Tàáëc´uÛw’Ø]Vg”D‹®G@zh=ñ=7 Çß Ðw³2Éj=/Γúod8Z�Ì+™ Ìœ�ôížúÒt û2¾�ý‘i AVbÒ¶ÃÅáŒÏh1îU¦ã_]¡}J vl6M�g8£ ãh£~<Î[ò \ÚÖ{ñ�ô¾I¹1å=”è«a»x8æO߇…¦š$ÛêîÞQN”–AŸ�™8´�ÑMRfêmŠÈ¡Ù±Dlµ;uØ;î `AŒkóå/›™JR´Íà‡·,®¼ƒãÿìSüÕÌÿx‚Ï…{„[éFü…mp÷·éðsõÈ›�o?3Ë]ÈÝGn×±j>*‡nJ"Ôá 7ë„}Qîú©†•ˆ­¢1•†`é½�ØpÕ°âK2öù_‡ÝÖ_¡Àáú¬Ž§Ëì[XÿÚCPuD‚ª ó¨í±püÛœGÔD q±ƒ£Úc‚¥°^èÑ»N@™MdwªªR± Ƙo9 ­ñ¦Ýbú"` ~[pˆæI%b%QÃU�WÓùr’(?œJ«ž¾À R1 �—áíN/5lëóÃø©ŒX¹›Ké±ïñôé{¬>K„ƒàè MûÙÇzøˆµ÷ýò¹cˈ¶~ FÌ2ƒ·»$aŸŸœ> 05^•hŠÙ�É™~øÞû‹áÛæˆm¾ÈovÅ“šÉšDsLóÀ#½ÝÄY*Œîã™JཀH–Ùõ� DêÖ5Áš]»ÈØ\�“GÆÈjÓ_¬7•ÄÛDâÍÔ‹àïöŒŠZv³« ·Qy™/$ùM.óJü-º{ø—ÐÕE¨ëÄ¿qnÌò´ž¦Gu®¥‡?ܤO“S�ÇÀ¡ü*“qàµy>•ŽÝ°€Ùÿ¼§A ¸�£l^ÝZ»�|ئOÎw(‚îá>ÚnP erÔ™| Ÿf¼Åóæÿjöõ0®%Š‘£YôLôCê± “è}FÅüMð<ŸÕû¾ ý|F®—æ1‹~Jà‹õ™tG£;J¤¤0= Oá¦m›Hrˆj8>Ó·y>Lïb)t©šF–»Wƒ@éR“í¢‹WlÂe‘U4Cù*]]§K>ê\Aó›ïARýÉêPvÓ3|³AÞú¤b§“!�ql¥Kº>³·TÌP�¨ußnF«1ŠüŽRB‹WØÜÔW¦â.Ó›pL9QõŒ©h'Tå3éÃ�hÚÀ€-""äp®äîN‡æèH¼æ8JöÞÉÅŽ“Õ°X: æñ?$¹k~`qÂi¨ŸcN%¯\眞ã�ÊÃ3¡åuQ©ã ÿ€'=ê[G/®ƒÛ[>Ñ·&•hÌM£=i6ÄÆá¯öA²§?J$›IÀ7iòÎ_7ôÂŽ{×KUY<7e'¼”ŒÇëœ%Ø#óœLjü)/œö‡œ¼>›„ÌÁ׆·ñ­’|Ò1†gŸÃ‰Háh?ù t|g»Þ¥±!ŠAðjt€ŠÜ´Ãû;ñ¬}ÓØ�Ë…—’–çéŽvQ.×·�}ÚK"æp×�Æ“½hpó¨lÎ;>´TñÄþõ�X‡—ÂÌâ„G$«~#¶{|¡Ùf]ôÞÈ)¼—w~fÍÄíÌ•iú­s¤Ñ­}~:AHÓqf�©&*/˜Bë/˜²S–¯â7–TïRÃÓVÀŠrIÑ–ÅâÐC�LÇé½ ü¤U/�ÎϼM]¶®dz6®fvÉù“œ°d2'(‹ôŒL%bŠÛp| ’œh7F«ý…düq)y´! †}©G×TžÕyUÔbRâÅÁ<=v^8NN[�×l§ñsÛp…B¾õ¼ü²\17âBUóåi©d:º:Ø@_§HÜ0A‡’�Œ±§ÈwÉÓc�þˆjˆVÁiš,8Dè¦:bà²:.­%çJ�›Uçé ó²SX³üÔ„X­‚}šU ß“a’úë-?d‚¦€ã�‡8q1ÅÞ¥Á…·0W»“•KøHŠþû™�Ù˜°Ón¯%Ú/�BìîódíV ÜR~oÔ%®˜”íF™I?\&ÿ–J�øR· ·°žÇtQ�< ¶Mš 3î†^VdÿŒµ°ýûÖò©.KhÙ½ljÑ¢Kv¸3t4ÿ…Éˉ"r¡x +³0–ñµ^OO®¨&QEúäyülÈú‘J»\‚sÞ-Æ&ð®Mß„÷Q<µä3©w¾€NŽbÔpålš*6 «T蓜­7Á3çÏ’¸‹§0vC±Î6¢wbúè3ŸùP:‰4nl%g�tÑ£Ý+pÕ�ZŽ–Ìfxê³™®öÃÝF $È8ˆÆYüsØGuæò ‚Ÿ}Ѫó= 8SƬ÷Ô$^³ÇË ¯%�æIO<÷W–å³ÂpþChÕSJ^¨œ¥ûKË�F3VíGF#’8Œq-‘8l¸Aûøf£mæ(�›ÖŒš"1å‹ç„°!;ÇIKê>x>ÂNäBËŠ[¨¢z¤:òª0¢“ JBë¸ÕoûCÎù$“âñùêTD“Au_\¿„m›«izS7Þ‹Ž¥¯ßû29û:ÐÀ5 ‚Û%y¯'„Ù¢5âÜx”Ò„�´ô^,½//È�ôžOmRü™;ö\ ›L諘Y<ƒòÙôÄì)xnÝ9:¿Û,Î:çóx§Ýœ¹µ&”ÄÐR*Ž&½¨Ã?+ËP Ý7�Ä×s�“†¨é›‘Es!xUåͬ`ìz¨ù4˜H‚ÛLQâ£ÎRó¶[d{U.Sº]XÙÅ8/V9ýd7û›|{�–^ö¤gú:èvÝ£ºÙÝ%YŒâø¿½°ëÑ×à4~Ë‘�j»ÁŸÙ&S¼\Ga Í?ªí)þ8¦?ã\àGè$É“†cW]HU©;y2-"—kÃá•ëðÎcF"ã5…»²°é¿Ÿ´©ã;ÙõZÿ MáWC¿Ù²¯„´»žAûÍ6´e/�ëwc5óiNs=›ù¥’äN¢üÄu\&Jksúé[õ¼÷µ™mÿÑ@F»E Ë6,ƒ�£s“ìîª!{š²ÐíàL˜sC�3§ÍŽžs¥¾"f¸:D~{É—'6)Ã¥Áæiµ×LÖÍsþõ‘E´&Þ¹1èµ)•lt…Ü‹ÁXö±„tyï^¦˜J$¶\&ÖÎ!·›ÉÃͬ¥® º C™C"¥='óAúÚDyðM%UÑÅ™Åt¥¤Ú{ÿžå4z8Ê-g ÄçQ¸*ÚFK®Ì¢7Þ�éÝ4º£ô›x`*šüsTÿÖqÚRs ÷�¯ø�øEàņ5¸ÚDž£ªXFû¶�‚˜Q:/TÇYr¶øANŸx½ãLô› ÐØ×‚9ǃˆè+T3Æó»>‘`;-ôÛö ºï¸”×ÜhCÍ)¤ÅüN—u€B»W4]@?¶´’úG\›{ f·ÔÒ(ó¥P½µšÖ/ųÿ©¢Ú§rzL΂ʚ Dz‡ŒI£(H'»bÁ—a2Oò Þ´Œí�ƒÊ¡l<öÌÖßã¿Kø£x¾‰�O¯ûSë R÷Ô ÎœµÃÕ8v^òßë“À˜BMàÐ8ò`ï\BÇk–Ш‘ ÔŒ{@Þ±jTiód´êá@à¤-¸P^îø—HÉÌéîPVjO ŽÔŽÒò*9î›9´Ì0½m¯àÆáP0¨BÎPÜê…°X˜÷…Ï–)=xÚdëÞûl¾¬iæwBÕÝTìÕnœÿâ2Tó–BÓ³VfîŒ'´$:}²ÃèáÄG$Ö0é)Þ·ÚÏe‰ÁµWdF‡¤ÌŽ%^d˜¾¶ŸŠÞJD##°AÅx¿OvdÎ… ±F¤{\—�./‡a­ÑpG‹ŸxÍÈ!¿ä2hjÀZròé}|°d&iÏÇþCé°1'‹~nA‰¼J(xŠƒÿ)â þ“´U¸ÖÄC “@Š d˜’ K-Ñp¼•Y3jþßoÒâç‘8=ÜžmŸ9@±œèž‰Ÿ KÒ•©”k1|TЇ+Éelh˜u§šF·‚òÂ¥œ%ÂÒìRÇ Î¦ÎVÒ¹*”.œ¨Çç#𶸻òþ˜¿m‚í^ãC“¦‰Ó‰?uÛ:‰�ÌCò]êÙô_åV¹àÉ¿@òŸÝŒ6QçõÓ±Ï}¬øVF/ððÉmB�3Ÿô¨ܯîB·8Ôob ¦�aê¶Å£ÜL†s« ‡÷ÆÑÏ›Vâ™´ lMÈÆÖµeô¼‰ ^S:…Òóq™¹->_�š°­÷ÙáŸ�>ÝôtÝ?ã>è fc½ævb› [`›Ùiˆ¼>^žøá8zïéA»©wï®ô§‚ð99›Î晃‚ÉÛXÌ£izè±ã"3èí=ëÉé¹�ÖîÀiQ­ãÓW 1C Aj¯3“Zœj¡Ï”Xÿ•'¨øˆ”m¢Ý 3jœH¦‰æ =y>V5âb›ê"s·ÍWG ?aøüò1­xÁúnpc×*x· _Pþækt~˜/*6«Ò r: ®ø™‰òaƒäAi…8V¥’y†§áÄMe˜øÆ®±¼^ÎðÅÕzÝäç™qf¾j+nËRE®ôu¢ÚUˆRý4¾Hˆ1�²•ŸÿóÄÍ,u}¿ÜË0$8ÉðÛzä)%3â®}”ÛÞK�ó-·X¾ÅÎn†úÔU87é%=™ÒÉ~±zN$C†µX¾W·£YmªZ\!�†/ÉÁ€0˜ŽòÐrà&kWL¿-“�ÏJÓ�»�¶¼m`mJ4ðdñJ o$‹^Í‚-1'Ð\™²êj¹œiÖÞ¸Z×�)zM�¹8¹eŒá4˜r8Ÿ2NG!¤Ý~Û@À>Gœ<Õˆ«?I‚þUØ"²˜øÕ�Ñ’küx¹ÔK®ñ\ºmÉö01æœß|¬&Y^ýTÈ,œv>i�H_á�ö/„ð–Œ[§øOÏÚ½„?b[è7�rÐÿ“HÏJÇ›³.@ü€>1êÜŽeÍäóÆKôÒîd²Òõ1Y\—Çn†ý*LcÏZ<üÔ›êV«1Ÿ·½bžkMÅ÷Èvx’�ˆÖÄ1wÞ…òFU õj-¹h¶‡8T¹2? ùaþGjzUžwjÈÓ=ƪ‡!pÿõ&Êùæ�úúRpcŸ(Tós—Ii1Tï ûŽdƒïÑÛÐ|&lnðÊw‰X³*‹–Š›<¥¾4bXª¡³¿ÐÉÁê#u™³³¦’¶7:Aê£?¤'È2vße“¿$æO¡Æ$ /{OÁY‰üS_�QˆcÎÖs:Öå�Í›¨œÛ ,÷½Hóø÷Ø/²ë?;lôñ#1)ôJêLtN.e=çÉ�¾¦gä�³9±iLöŸ‡˜dqÌ[ºRbIä\%’"ÈD5ˆÂäÊj’]õ–ˆÖ÷’鉡àþ6Žòm}N'œ{éÉ©tÔ¡™és?F:ö'Ãþô?„ªêÿÔCà`x Ót!Yz¨deÓ›Òy ç<›Ì IG³˜PPWY†ÃçdÑüÍ+Xl-FÊ{„y¦F‚ì¯="èôå"ñNRAÿ|A^ËÉTk¦&¯*}L¸ùã™Ôµø†Sž›'MbœCqgÕëò×f`Ú¬Ô}�-Tß¾†Ý*\ú÷Ä-’ Q ½Zp¾c+{>á2ÎØY ûä“Ù¡Ë’÷NßÒn�ߤÄw�J–�ÓçÛÀÈL˜«÷\O»nDΗ|´¨…¾ø~�h-ÆÙÓr™÷c¨ê­9P’, ºÜÐ�¿˜*›Ì$ íÎÁ^·Xÿ³%fŠÃ”Õ›ànÛKzæuïR€[ÒBà²H‹WÛRMØEÏ)±rÇ{"°à{l!ý§8¯¶yo+…Æa¯™[²ê°Û­� ©jÏn ý?¢ÿõ‡P"-I¯<c„ÛLÑ~ä+yÞÛõ@kí.|fv�Úÿ­†³�Џì¯6¬ë¦/²rX¾ËmÌ�2*æ�Ê,{í³nAmTõuj§Ø2ÄLJl`%õJ©Ákªºì,¶«ƒ8~€stÝ_ ‹ÞÓüûàÇ‹I*ðë!^ŽýJ»ŽÇQ§#’È)½ˆ­ÁÏÉ+Mt ÊÆÐò¶zóˆ9q�˜Ïm£3Þ¤39ÂÂðÉ$ˆúç»'IkégNBÓòßõ⨭ö6ºÅ(‹,¨ @EÉ|\ñ$È’µQ‚ wÑgÎ…AÛ1º5n©q9gê%°®õ*yî\‚\yÈø‘ÇœÖÖFˈÕÔkü-––àÆ/AãFÒØÎ‡ ¡�táa4lÓ ¢ïggoÝÞ «¿AââI’,� ü�¯1E ÉHq(ì9@ý�þ2b§Bfìy¨=’BÓŽiÓ®Â=¨Ù?D—Z­#U—i¬×7ú²?Nûâ˜÷¬½�A†… 9&cL³v½$�Ö˨ÚaXœ`ÏT\ƒ¯¨¾S£e!úÄþ‰4¹Ð)nçíQ,¬–ˆÖGõÑ tê­F¹²ôÿÿ2’/GÓiÊû¹˜½n*1uá«·ß–y´¶q-„|Tæ4:ýfßnáƒû%áPî%â/¾›ŸêÒEõÓ1§áÍÙÐÂÌ]ì‹á§o€g^<õί€®'–¸fâ7§Kí±žD<‡£Úfy°¾+�3„wB©h%«ø\�X½øELLÍ`sVÕÔŒ"þÏß•ñ Lqj 9ì–GRÒiå2w\,Mc+‰W¦d@ÙGÌ΂þà ¬“ßFˆ3ræËm2è%ba„ß2’ mýζõ^…jõqš/:ewéCÇ(6ëŽ!6TÓ÷&@·r1NÛGûöÒU_ZÉ}þø!¯ »×CÚ_PvŠç+‹ÑïÄSª8ÅB ™Æì#«ÿœ²ëžfÚ+6~Ñ&+òíÜTFÕë/�^ûx,SÑx{ý O b>¬OÄâ�ˆ×·üÅZCrÏæ º®áƒU6™]Õ¸BÞ’¶7–+Ëâø‡zŽO†'½å=Þ Pœ1‹7²¿:ô0 >Óaø¼ .7n§Õ¡Ê�+³;VØ@CÖùUõï.K„ÒâOÌ|\ a’Š(ûÒ�¼JíÀ—A”3h «·³Í›Ø«‹× ~ì&4*{FjïøVs?±ZFE–ߣ›Þ*à+Ó,vñÇ@0S’$gvµ®�ê Ã?º³A›m¡}÷fc‘j|xôÏóŽö úHŒXN¢+D/²)Úá}¦¥™0ÉÁªÐà0E¶aöÈ<æÊÒ÷ŒÙŒ™;Pp‰ ´åAdRô_&sƽ!¦v+| \vxØŸ*ü§†ãÓ݈ç|ô UÞl|sglÅ¿Nó°õêd©p0!µ?͉à3lɽJ žœÇ' Ťt@ M´3“¢«H Ú5ü1tc1F–àÏh Æ×¤ juÂ1ªs¬|åwM2Û$›Ù ý’Šü7 µ\Îá£]GPâÅF}ÆK¾«„ãóÃé�4f¦P�o†ÈãiE}|PEÛ?–3$‘‚'RèÖ¶Úp‘vÊšRÕ�nÀ»mh—Q1Ǩw!lþo”:¾ÒÂî#YÔêi,Í–8 Z�ˆüê0âç�aŠËÀí«#U}¦…*§ŠðË–L:�3Â&Mÿ„ú®ÑQÃ40pÁkºÜ»yÙà.ÑC÷é­ƒ±©R077ˆ•¾‹ÄÝõ í"Ä-º´2݇X¾´$¦Òk‚v5Ê¡ô�'PS•IìßÛcœñaâþ$n‚9ý’tš»<Ž–1Xî9BlONçä™)á¯þ/äìsa:ªWï3¸ôý$œ•—rkñot*y=S÷&F€]ƒýèæ#Kpžbí—ÞEÄ|µ‰œ7ÀжFæcp&¬¼ÕÞ€(—8¼{{˜äh¡ç$r´®Ç`fÇFç¤'Ýø&¤„èÛ½  ¡y ö,릩&ÏáwV –Ù%“C.lùûûŽ0öÇ–N³•„YíS©oÀ9š£ŸìÓŸ£CT'\E­ì@åô#¬Ø7@¶™AïNQL™±ã…ÐÌl„ñ™PÝYoX¾¢'d{œOyEJÇãO&“„¡D ¬•ÄÿºqvXâmƒIæä¹F<Ÿwþn¯D©¯ `-‡!šJð•7Pþ÷ÛN*á-ƒ.?¯Øë�år£„_ÞÍïÜ`“sð¦�/m? k�IÁØ\_¢eýœ^ý[€?¾®AóÓJö¸›Ó—KÎSfÃm°û²Oñ(ï¹}ë¹î§ÝG-Ù³¨u#…sˆôü2¢5Û€j‡TPÅÁa²0à-+Tw€¾Úººì£™/¼Bf¾™A^=GËcedóbÃë&gC¥8Í=ÁÔ¥ûuI%zSèéOëØè/ èÿ›À‰k�”±…ÖÍiä²Li\NPò£:]’ÁÄü­9°$$¸˜å›Hçòi€aøØªÊ¢öÒfzæpÝm·Œ®á%ÓœÆu ×{RQ éè+2Çì.N¥ÛF+KyÿÝd7–óhvò?·6ÐdUðû{=È\¨õ@ë®Xôýü€ãx‘‹ ‡ oNDo�):/Àû/�œ(½Aœgx’=u¾Ø´5 ÎtóÁøÓtbÊþ3”kMÆÀn-\¯O²Ä‚H¤"ú{�j~^‚Ü® ÌÏ¥tƒF<5Hµc+7Þ;áú^x²\ÿ!¡wÚØƒúpûüFS4 ç‚‰ÕKG�“ÿCvÝHd÷`ÃÔ'LþÁW”“ !²qdÄ6ßyÙÓyˆ^�€%%è>ÓŽ4ß8Žï"w’Íþ ôîg=¨­ð€QËÕ´l~410Yp©´˜ÝúÆä%Iñ÷G–ZA|ÄhÔØ4‘®TÞg†Õž¬î½0wRB�¦KÇ­ì�ÛaŽÖ¬�AËkŽPõžéôêb:û%ºš ì/±?úÓ@íª;¾+ŸL½Žê^€jçßãü  Œ · µÛ%á`ÆÊ0ü�ÎLÀ«Â¤Ø8ÖÕéº]PÔÛ;ÕD kLö¶ãº7K!:?„3nÀÉåUš}¶Ü}ñi(«2Œå–›£6…T¾ˆ@}ìDz±Žl:òèó¢­4%À�´*蘤…ŸÐ@™ª]t9f´ªŸaRyÓàþÊs4é� ñã+¨ü…¤eN¤ßT@c›/sïà¿|†r®¹§Ét…8T/ "�ñX2HZÀ–ÖÇX•G®{§�ä[ÙÏÞd͇�ãÞ±8óy 0•#*Ìa—>L¦Kc¤éÇýÐyl"<ø»½g$1÷Înö06šm¹ÖaÅìðŒÍèlHoÞŠ‘+“Ç–=Tós2õˆÊ‘ÁhYÞìf†4m£Ü¦ýé¯J-óC©bf%>^ˆ )Žà{NL6§‚¾·ŒàyØf&,ïF–½¾B×qãó‰ðVO�¦«r”§ù 7–—Ò¬À> äÀ7 5º§³�‚•FÀî¶vö°³†™8ìgñÍ�ø a:�£ËÊnß¶º'¼•éÜfÛ&ÈQ¦žüT0çËòP;^ƒŽõŽ¡ÉìVü{,ÏW�Ì®rîϤ zuÏ€Ý�'KeÖ:Lßãü=°óï�@ÍGˆ<�ÀlŠÙ¼ç“IMx Uïºâ÷dàÜÉLʸr\pWAŒÌ;®%ï<ÛÔmsGo³„Úo[ÂÑ‹útw‹x˜Z“‘S!n>°…>-a‚=â¼£ì%JÜ�…ý�悪³Ug±ÜåGy�-®”ú%žl¢›Ð®f:•)‘±I#l-†Uûqá×XXñ6 ŽÿyË=¬¨`s×o�H=kBWfº˜.J ÑØíNd9)îÛ€sòP°r/�H/ÿùäHêécÝ\\÷1Åã>Ê(‘îKn¯E !¾¤"KÑ(8Œ}Š�¥CÕÙè•týátnÛá*Ԓׇ¿‡0ƒ ’ðÍu*® gålÔÏ*'yÕeÔÞ ÙIâ4¸cn™Y‰=^÷°±´ƒS ($ñý+èϱð|´Ü{!1g¾ *OÖ…]ÛWÂïŸÖà²XþªMGµæ/|pÌQþŒþ htMÆ\Û"Ö!™ƒK9iÚp8Žd—‡Aó"¢ú ê4_8 Å^à<ï©A°ônlÞ^2–:¡ FÜé¦~¢bU:HöÜ;ÎC"N°?xÙ-1§—ÐéÛ†½±÷MÃû“ºìâå•0||+´}_¡¹=ÜMe–j”S²")dšÆ?n—:L([¡ :Ü¡o”&œòYŽÅÊ?áÆ´¯Ìο•¹LoäÔ Üiß]O²Û±�J‰SxòTNçiv`¾û¢Þ/D“är“pgŽSÇQ†�Óã’YcÏY¦\q äzƒÉ]©C0-¡ l´€ÙÌi"Éy9øqc8Õ)Ò¶¢8°dGiA�4¬)*¢Æ»1¸éº&Å•TÓà‰ñttÿbË>'Š«-¥o½é¤¿å1:'Þ`CÅéÀhú~ÒüÖn¡J{øG®&$Ñ=~} Ëþ1ã>G8Õ¦€KÒ>²®9ïáÜÑ,üëªA½Õ–ÐãÍÿÚõ‚%›±Þk®lÉËSô6l¯3�Dutakd$<5ƒá­ñ0¦n•¯8�íÞLçt¢ÞØd> ÓLôHSì<^iC¥…ºÐ*4 þfëÃs…2#„رF›|~œ¦ã ¦4³ŸÏz�Œ.³Ç¡¬}/eÝÊ›™»BÁ¥±(T¿2åÞá„ séüâHÖ«ÙÛ‰ÎpXS�,"ÈôãuÎFv _¢žH_^¶²­·î‘BdþNÚJEûï²% .[Ù¿ëÆšD¼%ù›Ž»“WÈ@•ýÍ;N¶µÝ ßÕÆcJóvÚ¹a7„y­¢™«Ø¢?çàƒN )�aûŠªØÁ§õXè:Žn}¯cS?ï'‡#þü]9]ª1O³Ï[Òª¦«`ìû�Wy$EV_£¿u,{|”ýœÓÄœv&ó¥+ÆÐr3{(›yŽñƒ]qƒ×;惛˜-ÕX΋MúÆåä&À|C–§MÇ_¥ƒ¦ìQö;EŒîå-eÛŒU¡Qi­ºóŒÝ•Š„in¸JÑh†¶üÃTj­iGúsÖ¨ã×Òöó€,=ÓêdRâ'ðõ#wfu§�ù§ ’¯Ì)ø#G¿-�aQìV•È¿º­À’Ÿ_fï6’Ýi6‘w¢yi›!|‡Ý›ëÁVúî`­1ìyõ<7'–Öz‰ÐºÍ iý™×|äÛxØ5% ”5ë±M«“Oº{S››éÒ›ñ˜¥£3 Œ`±S øó {˜w îŸaG¿¤ò{2ÝàéŽ:öûâ;.xe%œ½¾¯rãës«Àéõ•p}ÇÆ°y�-U}ׯqc,¨»¶‰e[¼–‹Å¬‹sig½öyýfÓ2M¨‰=_òÃÏj¨P÷¤ :ð·™GJk…È>é´©¯§ËݺPgKw¯—áo• ^OLÊz¼¯¹ªh�Ü­6¼¶FÚþFáå}x¦¸ ƈÂÑñÓèå­¡ÊÔ§:ðvQ-›‚±pÊ4ž4¯¦Û' ¨Él|0¡ÇžQ,ñS )ä_•e×çx�ÏúQŠ&­Xøô"N¶©b…Or’IpÞu4�-œ‹•*í$³M““¼lÛ×7ƒb­ ¸ˆw°)',¹+rØ›×j`íãHû ֢ޙ6Y,¬ÇÛe#¨IN÷�æ<^Ћp?6ãí næØhÖ•³Ž”2(w§à}ù'~G7ÈPW€Ž)L}k6„¶%�Bñ}öKA–ò´©ÿŒ€&åªaÝ%yë°²0’û© ¯~£ö>'H$U¥Œ–¦·‘ñ33nV�(q„&ÖbPz͈…¾¯`Ï4ÃH+û Õ¿�£W'²}ÇCèCœ'·ûç8´¯T’F§éÛÂtîAúw6ßÑ—~®< m§|áòÇ ØPÆ NøLa-â0RÔ�WÖÂc!·ªo) $q© ½TaqÈhnkº,í[L 1Ä!æ¯ˆÌ bÍGà„i ,¨Ú”¾®R"‡89Á õõ û›/éoևłB(©ëŪwwèçÇ‘pÚãoûû!,èG¼âCm'„èóÈ r_¹Lï�€¨˜Ö|ÄÖº%@Ô¬­¬jÖAæ³å¾hk…]#BÙûhŸ~™ëHJäWm»äU¹ Ï£T� 0zœ€}.*âÚ¤ÛiVRù‡F¡â-I|—›ã†çRhS5Λ1’¼ÎjÑF›óUÛ–�B½ˆ_¬Ô¸c«-9é?lìZK=�&ưwB {„6§ |"}iÑû»´Vá T?Ëà ÷b°�õ¢Áð åŠ}ûpBñö0c?Z}Hgk°C‹C˜oìNœnpœÇK�üÀ#þu´'·´ØˆÈX¤:B`@¯Æ�õ§9pz�5õÌXN‰wÙ'�Xô<…½©U µ;Ÿò¯ƒ±*º ÃLÒ™ÌÚxJ •¥ôª;LLt¥mV�þ¦ÕL�^ ­¤èΓTv4ò#-YîÀíy; ¾‰,€i׊èá•—|‹S;¿+ÐPT–‚÷FpGSÇ‚ÌÏmðôáe+ßFÒèL„½ Ú�6â¦ÙÿÁeK,@fÈŠÍœ;Ÿ¹oM¥JËBöÎ"åzÃ�ÀHHÓûŒzV#hÄï[–ñçaÉ­À)Âæ±d¦¡ W6o%éþVX”7�*ŒÕH; ¿] ××RNÏXPÊ�à>×�Üç1Ö®“rX°ø*2i}AÙ ¤œ¨Òòñ|·2ŒªË"Tߣö‹QAñ Vb¯RåéºÙ›0‹ëÇ2þ–©#bþe Df¸Ñ—=›(i ‡îÌ"iK¨“}Èt?9‚b³ +¼Á×»\ {âU¡ü‹š{™òÜiÐ|RˆÛi÷š…½öá’T-ŠpuQ:„_Ñ¢šMº.Õ:~[˜mÜ1x'[ÈŠ‚E㲄YðýÖ]€ÅxúM>^ï¸\5s@šþþÝNrQ6ä3p‚ìßdçh3’Éõ~1ÄÐÛáìõì\½a 7¸°K¹Wø#C™´t3gÑiMS?�¯Š Bïchß‹jºï8JóÕ¨ÖHú¿'`n¯ýØàwª3p×@:«™3‚%üajµžXeÄ?š¾Ÿ,?3A™6Ì2-…‚©f´ý¨½º2Vx1í›;(húqH´î†åw8r5 g~~”²ç+Ûðï�êóãXˆf*ž<™ÉM;¦Kqs‹ÙB­2�óy‰íß;ñùªŠ«[ ÷Ä…á�ƒ¼‚¥”¸0¬†� þó»*¿@ ¨™CŠ&ÕêÁdó@I¦³;!3Â;™Ñê[éIAßöCú”©¬0à_æVwp—p#«”°o'㟹ÛÛIÇHÍ2ô="�  1õ„àÏ e8u¸µJX�G#³ùuóت§Þ”*—Ië¦ÑÇÓçXºøfð6 ~³á&–ó5”/’rp44䤒mr÷“RXÙ5º4¥Kà>p~Ú¥²�Ï�åÎ5l¡‰¾ÔìAy¶”š\¹0ÛÙ$þɉÙ7vò•e4Tèöê`&Dï‹Pe ú�Œ‹ç¤Â—'�X9µ±ƒÆÓe_Xˆ�Ôt>ÌÖÓü,`©S²®=ËøµïIöG$«pÐeǺ×�KºžæŽîš¦üÀoÇgPPP3‹©dKœGƒâé‡Ì~@’ÔÊNÀSïæð^@"š‹ah—˦Ó,¥3¨ Ù…7f…áäÈ8 Î|öBdœ˜mA¼ÅT¸¼ÂÞUþ¯p�J€ŠÏÖP·à4¾:- ÚÏuA'D¢zéÅì™ühâºìaøT÷¿Œ§7(h[=½ Ã43>°ÖŒ:ql/¥€ÖB[ztj3õk΀ˆ§ZÄ:b˜TVΆqn�¦š'mz¦C9¢p×U ¼¶9”¬�¢ý«ŒiG¹7Ýóz˜¡K“2ã™tüzô[ý½66ú,äªÍC£û+¹ˆ ŸGÑÈ輞Çõyõ²¦æ Š É ¿{¬g‰¯ ‘Ž“aVk%¬­ã†bªÁƒßIb‡cé^NsÕy‰GܼU²jóÙ�{‚†ä4´¬üÂô¦ªAŸWOeå†:\l3�;°r> I¤»ÆbÁƯXÓÕÄ‚g}À‹S:¹ªªq°èG»··$…Cïäo|~{»oŸ Kúò.Z AèÄ0Øv¢ÊI÷“* e-¼hÂ-\ »›;þÀxñ.Le%ÐÜ0ȹ^3��"Ù»#Ü(CEøôÚb FÐÒ¥î0è°gdðq”�9A$n•E¶ÞÔ3YÏ×%çÝRpeËIŒ_ZÃÞœçîŒô‚A‘]ÐЫÉGG©‘ý„8|qc\ú‹=fLÝ%­šäá˃6y÷dúžJ¼Ú\vó0ˆ Å7Ï?ðË¥¬wn!­ùr°×qý˜‹œßŽÈÚïΞO•çkb§âé…éP 8€5«âñü§|ì÷�˜¥—™ßŽ8ìr‹Öª2“€LP[±’.múÊ;6�Í›éü–Š*¼æ‡R!ä“ÉÎ]³&ÓmWÙÓg3aíûjîIž�Ù>ÀnW\ÀüžÈÛmáZ;2˜CÆ~FS8„vãøÕ±äQ¨Býb¨Æ`ç~@š}�áDà*Ò^K¬Ù{…§ÔTqæƒø$r$Š«R¥âí¿Pi–Çï¥åžðÿäÜ�¾²ý·íÙåƒ`¿À€µMšZ|6;£¾2^L…ÐW ‚¿QFôx¡ÍvMËÛÂÐÓö˜û=o›kZC��бâ-¦´èB"1Ñ“™ S´‰úȆ"�6�D¸<Înf·²M Åá‘èÅtÛØÖùc¨J2™¤íu()|{¹ë>Ÿ ›ð²XÊØ 2eËHôKa&^ºÜYá'쥂8|xV‡†þͳø3kþ5›�÷ަ}½20íÔwšw³ÿïàŠY¸é]Ýk�¡w~�´O¥úw’ü¤M´)w“;�Lr¡#Hyà ·ír2˜Ÿ² ¾ ïðéÇtòºÃÚÝÀ½n p5¦üc‘|JËMü—X|”=Y¦ÉÀÎË'™cÂ&’ÈÌÅøBÌÎ,lí0ËIWÝñyüÝU‰E2¢|Ûßå8¾`zo¢ŒKK˜wr»‘ïZC�ܦ�‹XÖõwg—c£D.6ºÖ‘zÂjÖ8f„tÜâ ųhÿ‹›À^Æ€}r¿Ä·Y�rk1ó9|þè=Z(KjãÇ£åáhÖì¶—_˜HUõÐÔ{ oU¶³ìÂq‚Ì�>Øóî)î¿™¸°ÊŠEdÝd…£•`\C< ͤçã¢A+-cæR ;Ï;�Žæ:ôQ±¹£ûéz´.> S'Õ-òX¿+“UÌ1!ÿ˜A×ê›PÒ<¸´bÚ¾7Ömù†Iœ~u÷ÞytÛ«„½”õû7ocJDZùB°2o;éÎmCe‰B¶7F ëNíÅÃo$ᦊ7º]ífžËËÁã@4ÜmÚ€¹: ¿:�©kŠPdû8¦ªûÏ©&N£ë1”}7v†›°¿äÄæ»5¾{õ#(«™§ÅñA´9c~Ð0¤œ¤iT³A 6Í5‡iþ(nz$“œ"Ì›dÏÇ ï4,�´ÉPî�nA ᨹîT\·ïξÄ娱ß÷ÎÀÝu¾5Ñ·ëÍdãwˆBiX ¯–"Íèp 7™B”’ ßþ¢ú€NÖJe·�ž¢­;uibýO+»?ðe‡e¾¹½Ó“…Qe>’Ä©êca@y¥ÿGüª1�Xeãn¸ü+/ @¸2Æ ECëÍ14?:sO¯ò2 áoÛ¾¢fûkÐPƒ›¢üé™Öi>!D�=çÕ Œß‚+s6AaÌ)Cš.*„@¦O>ë¯å5ŠãÑO¥ƒ±T#ØæýŒ)4žÃÖÎ$±HŸ`œwûï³-=_y ^ô KÊ‚ãå~x‡³"�Ä�ÐÒ8fÚv¡^ãlë&W:‡ˆÑ$Øٰ ýê³Ù€ÛlXXò¤ÓÒŠÇ CéÅR9öÚâ&‹9°¼ÕÒ¾¶ã•Ï…RÙÜåÈ%ÍÑ£ÇÀN¥’ öWñÚ=ka[Â4¢q '¤XÇËW•œ^�Ãÿ��§&3R»ÊNó§ˆÏ£!â¶+´.Á7ÜY”âZº=YŒ>ýÄŠ¾Ž"—É‹¡ðÃ3ff}�ÕVW©”>G…C†0*è.�1 œÅEÉêùUÐ>Ô�quº�j“Ìáά4¸õö¸ÿ.F³KéœPßBÊ‘«„ ÎÙ¬HÁî,=M‰á3™èÖ¶ï×\å™çäeçý‘ëAA¨˜×º8ÄŸû¤ú²Û§� ±TrÓ”î“;Æm‡�¡˜µÏ*˜1ê'¾v–bW“•0uÁ]+1lÇß�ÖìÕÈ>VÙ¼3%FÓîùRt% †·íà§lË€—ïKP]Ó�&ͽ©Á¶$:%Ø1%îïÎ*0¬S�,^•ú•Ö"IP^¨"][5€–¹PñË�*»KXp§,Öó§ ˆ»‰ö=SùeÂW ca(ìoÂ”Š™¸ªð+ËÏèÅVMW6Bà yƒ`ðùõšuö‹PÕ^”Ú•ÈÂŽ­“bUë"—’ÅÝ2þð79ÌØ‘ÀÕ,:D�×¼äk²&pËDÌé¨À— ¶“µi2d¹Í¦—¢ÈjBWÜÁ' ñEh<¼_ÏÝ.™NWû–Sâ69Áû]W˜ô{�&f5ê:?+VÑW‘ú•3&‰Hã•è&TªÕ†ïõá5»:CC§_åÇÚ¼eS²ÍHÉê êgŸ^ˆ@‡Î5&9~Šüço5ŒaÑþ×.ÍhÆÆ%tÑß“Ÿˆ\ÞÉ·£)âï8z))è9ý’¹êˆƒ÷Ý:–â¸GŸ°jËËzfóíß–±ß±± iÔ‹žIô8_Î_®ïŽPÀ§B.ÕFÊ:ÖnòÚEø+ó-wS‚ãKwð†SªùÿºwØŽ©/ÛGVg|aÌ‚GlÁv*’<ÏG^,'¹¶.¨« Ä®š…0¹#Ÿ&UyÀ¬×A¬Óh"½îyº­Íio´ ]ì[Þ,C‰ójÓãÅ u×´ ¥ähR¡6lÿ[‰,§Å×0÷‰ö´ü´#MÞú¸Lt.š;›~%êÀí—ÌmÚ,¶Ýå&ùÕÏaSGˆPχ#ÛMÀPš�ï”±Ðò3=ÒúáØñè,5ÌtVØÀý¾FVW'Çg¥ûÑŠìa¶üT<Û9ó>Žê0H”ž:Ì)ë¥ÔZÿB%Ý5¤���§…¨Ó)˜»F¢Šjip¨—|b{x‘Œ ”ñ§Š»êùVj‘i €e>p}æ^oœÄÏ‘5¢#ŸÅXß¡‹¸'·ï\V€-ç/±=¶6$jäH»§ë1£½ƒ,«Ç JçÁºôe4üy/¸i8‚ý”FöݪÆêhŸºÅ`n€ �ðeZ8|[ œ¿HÃ��öô3B }rèÙ?�Ø4è ò Ïc¤Û+.|ÏRЏPg· < é#>á"·füã}~þ©À/÷â«ãô TÝÔã^·>AÅØõ¬6þ6¤XÁ6’ôä‡ÛY€gý,:†‡oIÁüÑÝ +. 'VsýÒ(ÆN–,·³ËŠÕ]Gµ)º´Ž“ìïa9'gÒ/9ExÓëEÿe­bùí‡1E7�ïö®ãµì¡I›Ûøßß[ø,áV¦$îB- ß6O G3_°òÏc|äØ=S ~E¨ruç´©FØ JÓòPUJzÙ3ÑX¿Ðœrl�hÝ]eZøÃ›¹Ê¶ ¯h×­,Û°¶jæ’¶>·†e6ˆâÔsb4ÕÇ}ÏñΪR` W�wÍñH³&nÙ^‰yÂè ï I1“Á£T’VÏ?G#fÁcCí~¶c÷ ¶ÎÚ�¾�ßrߦ “Ì}Ö,= j.|ÆÚ5)tÀi--«md’ˆwj±�®# ˜Näw~V°-®Xî�²?iu-Q2ôt è߇YÅ^?ü¾§ϘŠÓÙû2U§F’ü…ZØÏŒZÓ»˜Å›XžBO=ÂBÿåða‘»úê1Jxy£Ï¨ö½š›Pgô'öA¢œåü¼MW¿¬„§¯#Ó¿Œ“îÛ€‹tZŠ[RP«6¥-d ƒ[éé'ð`7¹‹î+au´"Äô3 ÍÃÑc(„I“S‘!¹{Œ¡ŸyCxHoM{¼Ž¯øçÆÖe'ñê¾=èaD·5^³—™]áØÀ6\0dÂ-ñTßÁÝ;™3¨d™ýO`£Ãúz, 挼ˆW»8ò¸Ñ‚&:oø¤6Ukż,´“–b mx\g«†Ò§Êx´ú²yý.9D¿¦ÑýíðÞàyîeð˜i(K}ëʘ 'ëÜc°‡:Ýu‘¢CÙUG²ÀÓ'º4¼"€�k•¤í]ÜÍ™ål|ÅSze¯ ›²Ö²¬q(ë¾�vœ,aµ,‰»Â{ô…¥ƒ±|Ï(YÚ²v;•òÓHúÀ ØU5^û-%ç¹’ô§Ñ‹vä«ÑHo[8çA¹+}¸\µ,P>¤À¾­ûɆoÈC+¾g‡'K0gõ+ ]9‘îëõðòm0afÉÈv‘³Í k/Ù…ãîÇ�ù4FwWÓ†'ñð;t{Ô¹œÏ^ŒZÎcîýd+©Ë‡þÑ€„ŸSɫ۞j,åd,6‚åq]ª±º'JL¨mQ")ÜU‚[kR›~ÈÞ=ô�;%¨ëÙ9l¿Ž®å°]v_ØÔáš0Ñ“>,xÀtv\Å>#SX覀G÷+ñWƒéñ"I8ž‹ 14=ŽÖ8AÈÊdAFšX¥ßã^á|nùáÑÀã².pÌ5 '”:€p­?õÄÿb:Âc±Z¶˜$Ã2_ÿ:Âúñð(úªz:j1§§ÓYUÿ'¼ #øå}%Ì@㊫ÐqÁ° —Ï¡y~ˆ1“ã¨qÁ rM…QIèDËtHëØÅ—êsìõP u‰沌³gë /zýõ „`÷–LL¯ÊllMHÇëZv¾g÷žHÁŽ[Sؾ+±ÜÜY·øž~•jÎ+Œ¶×Y€À^±ò¿áFþî]'š1V~¼…!Ö%¼zá_V¼GÖÕ†BœçHÎÂð [-jÌ>‡ý`y[±Q·OEøÀÖævšîaƒ9OðTA+‰îšÊo®Ž'®šiL�b>/ø«wg %…òµJ$«ÁÍ9°‹VâxU€s‹·Ðvl�´oðúçe4êGU—và«®‡¬l·$O= ºraÄÈm\Mj=Þó’õ…}×e)и¨ó F“–H«Ž³¡ƒJÝðat õ„¼A�ª“Lå¿ 6FߎН ëå8iÇG–ë“!æËa½îLÁqÕ?,xŠ2ÿsô&84´—^û/Å7Fþì™ðAÞaê#Ü�ãã;ƒÇžTTœúæEf⦬Wài´švJúÒü{¿X&®¤Oö^T¯¦�퓪ÝbÈá¯ø(-f›‡N‘°D$��ÝÏÍ­Ó£ íÝhœ/ò¯G2XûLqòÐNåEǼgõí�2ø�©”â_ÏÔ÷4ŒYÿº�ó®ŸÅ¨5á\ú’qðež$œÛ_Í5úÓà ËådsjH‡ócçb¨óî]�^ö�%$<à–×kSÝe±KŠÇŸÄ?T†¥‰£(6htµŽh2>V* ±ßL¦ÿ(éÛ aÌ÷•´·`%?�¤“#¤à{f3 ý]¯ÓsYC¬Û¨tŽ=é9Ä}ß“ÙG*+pƒ3¾Ts+¥tÚ¸xWºã”`�g*ôÞ0/ØG]ë ñBÌVZž¶�nœ²ƒ9áàÿ´ óþ\äfió6å=èWWîŽãî­yÃ>&P²îG”•ÛÃüÏ*Ó(¥ñôþh&>öÜàȃ(çÅ“Fÿf<[T‡A1™ðåDšRy”î켊‘òΠ¯8…l/¢?«þ£Ó»æ�±z.S—ªAÍß‹Ðk0Œ4Îgv[Øwÿc|ǹ§Ü“Á…÷'�žõµ‚Ʋ…4îÜVø¤ÔÂÔMŒèä­åÿX¹Æ !ìû÷h ßÃðëEvë¿ÍÔ?å ÙeÎcÇ=²@æz‰®êÃUî•ÚRùüVƒVür :ÍôF±Ýï U¼Ë™jîøŒ\àÆpûº7îuÞ^60õ ªèð¼ŒŽß ›¼²äôüˆ˜µ4¢á”8�ÌN-Á4‡zNgÏÔ^$S­QgÊnKáö 9,NÆŒíŸïHúÖö z% ��0†§‹+©Ï,‚}|¯ÂJ‚ÖÑ­¿b�ýÕ¢2ÌnsÇVó—n„ñ&®óaYK mÿÁÔÖ9Âí”ßøe‘*¸ÝGævÜ’Ô&´p¡ ðͦ÷l¶œß²:�›¸HŸå(†aÝ/kUוpã5Ï<Ï�w -ÙäÂ"ë«lÙ…�Üy7wÒ4ÑäJ¦†±Q¦7°vPçé�Y�Í}÷•Þ­� qró” �ÓFäz¶g½Qd3#yìGG“ÌÑmnhTV3%GmÚ³¶™õÔ/ |‘C°N<Ž1ò'sûЄ+ÿùrÁÀ(Úe‹AÿƒS—jdÏ� ­_ ›Â\¶±û�2˜½_ß]Éâe7ò—4Ÿc3�ÁÄKc!u³?__¿…²`Å#膭´´Ƕ§ALyò6˜ò¡˜–¶ïbªÎK˜p¾6´¥ç’ÏùTŒÕñÃÜ?Ž ™íNëûÙ×î@öŸp¼w³vœ€" H]Jd©Ê“g:މ¹En/¬`Ê¿®3ÂVÜiõæ3ÏtwìØ´“:²4ªwNŒä~~&¦rq4ïlô”’WvÒµ Â9Sƒ²FŽbg÷¥²e~¥xÃSÞ  è´r7{Îuþ»!Á�û±çÞ4È—ú+­èMî'�ó.1kŸGkÑÇO‡i:áú�×±©] ÄNUCÛ IXd˜Eºn©ðìíB 97 …Zòiéë v?õ4.1Û ®SQäï5¶w½ç±×œMU==&¤~xIFÁIçä±U€“-5ÙÏÈ(ÈsV ÏV�¨-4 $/”RmðFX{Y„àÊsŠþ$·]µÐôW)Ÿ±¨�rþFqE‘]ä«‚q2k¹&ѳLëq®{hÄéij€Øñ%lÊÒ©d½d:}8­Ïj¿¼A­ÚüªÓ³õéyN¾k�ý> wû꽡 ’‡Ý‰÷+ƒ/Z+˜®y-}™ñ—5™zñ'?0'§LØ~´—B=•¬_ÕÉÓü'_Ù3׋œ|Š= —³ö·õ¢¥ F‚k�;vlÆÁÕú® ;dµiâ5Ú»¸‘ó:Ô€êfáì4cÎì¢à•ÂÖ×ÞÁ‚Á»8cÂU²¿Àá:[й�†BZìûÔ:ÎD^žž/u¡ÂÜû¨q>œTUÓYHíïÝ@ǟÇq#é[l&FK’óØ›ü×Ùõ‚wN“nO¶O\úéÂìïŽ÷kõ47ø®ùSŠñ:ßðkG²ó/ñA͸¸h�Š–cr¿.>íH¦Ý¢Ö°â°pÕ÷ÅëÙå�6:kGU£c-ü|M‘âŠ0#†§è§÷ùÃ…"h¬L¦Ý™nj(C†2ì©¶ž_‹oì=?«å ¯ÐÚÊ}´Hƒ„Ÿ6KÖÜ‚ ÓáÖ�ôŸÇš§gã}i­ÇvÖ1CÂsžÑÉswØN·VÚ/‚n¥É>M–m™lFÍv~lÛÓ>eÀ€¥Í»L…fª0Jù&„Œ®Â±®NP §G…\¾@Ë¥œmµÌg-I¢°Qd'“øNõ6…ÈÛé�­©€êÄõáå“É`Üü �¬= ŸãÈ[WÊd¯°‡ï“XÓ÷yÌîg {õy|zøÅHëx6)„OŤû>ðÖÉ�ÞÅæT…Q˜â]®>û9ÔˆËZÛf j,Õ@aõx¸P »’Â(øš!:ü®_•´V ßõjÌÙþ$´‰ C¨{?F_úξD’ïîÞÍ‹�D¦ \ØñëVXCÊöì<{�›»¾’nR²U+~ÛŸB¢#DaŪ�”!s‰ÿÓ‡®ëî³õOncª�õÿÙ϶éZç&®¤�›7‚›‹0�K]ŠQtqè(-j–ø­…ýýb<ö4z'ÀüÈb::U®ºïÏIt<{¬ŽÐ¥¦d!<“•^”ƒge:h¡¦%ö±pã Á©©% ¨XÁ4”áòü9x3r>ô8O&^³2³E3¬(4Ü þSéçßý !ËwZôNד–ýÏðþ£/»'h\&W4{*½gKYïÊ\p°ÝÍÌc„¡SÕƒíò)ƒ¯sƒh]†뾩ÆÏëj%sÏr©ñÓ¯m‡í�áNAw–0û:~4Û”d»bàl@þçá÷ÛL¡zÊ ´Ö¨f—´"I¥ý8ï"ÚÎ&�g/ïܧÌq‰[v'K¹«�ðŸÅö^¹�Ï8Îú —ù#–y‡ ¥dË„(¢ˆ6“6îsLD&Ë(!Ä cE´M¯¬Y²e0’ÐNe+Ûs�Ô¢GƒF’ÈÒª�©ˆ¼þ‚óÓç\×õ¿Ô…Xª%M6Ï”iaü,zaÀr�Ä Îy è—etº¶“ëWþ�æh-‡åšO(ÇãTJ—ƒÇq4lö™:Ø^“µè>¼„nycð79æÈ�ì…ÊÓh”eG«6ÑàõlMv&—"¨`:ò{å%±öó “rŽa·a5}:z�MÚ¿€°Ps¨´mgÅ �C"í,QÚ–åí[Aï&·ÓÊw¾a´Î~:J2cŘUi�NCA´ÞÓm²·Rï}1Î¡Ø ž<‡”–-ôN²›bïÏ"]-SÕŒ§ã'Ÿ2UN·æ–õn^3_ ê##áùpÒôÎæ’ëYÁ•yïàÚ�V )�ºfŽ(õm%§=¿Un|†ŽN#åLÜ•…çÓ‰¢{/€¤jVêíIÞkSé´™7:Ž^d~^˨:Æ… fe2׆d–;‡ã†¢NúUì¸a¾N ÈBÛX]| êœØ.±xÆW•Ïó­Â›˜eW¥jž­½n¨.ù=áU±¢Ql½ÊiwiFXª¢œS6øÜÓF-í!¶OÉ…öµœã\¢‘¬=FúzŒ|~XDúãñíè-hÞÇ®>,¢Ow4v¾2¯äyôa½,Zºô±� tj»;ˆÚ†w!¤Þ%{ ¸ý³Ü@w³N¯ Î±pìuÊêAñ�½œ¨öv:uY c.Hp]aÆò; mÛ}.#U‡Î%„Âè5 Ôè/á_¯C…4g8R.‚FÍ2Ó®ü ÌÌqö�X'ÞcmC>ä¯Ã8Ûfv�g .àzÅ/qÝÖ"WìŽ3µ]Ù.›‚r‘ËÌ9o�`ðƒ¼q„� þtÉ eì,¸ýó¿‡[]êœÉ"{œ³_™_Ÿ§…}�aFÿy~DÍŽmNëª>Ñ7[¿�À¤ãc`Ñô'›uåÆÞ+dÊÑdójwëJÆŸ_I1‡Œ4“ežÏK˜È¥ršðq£ªwتÊpsÚM÷eÕ`mæ^Ö`ÎòjÁ¾-Ò7ù~˜îÇz\ñî,}]FwöPQïC¨ÕӯÜyØ'°É¼JÎåY˜î�‰QÍ x¼IšÎ(Wвg ¼ …�J¢°µž�ü:•Ö¸Ò«±TP݃:îTØPˆš�ó‡�}d7üèò|?Úî‡aukk&Ã×ãÂGfd~l=Ìz*Y¯ ò@3x–¡ŠØ°6Ìž\þÌfUm*Ÿ¾ Eþ p¿ó­ºiןíC¥ß«í(#ÛyhÊG•ž×.e_^‡=ÇRIñB%·ìï3 ²UÝèÇÛyÔ.@ë²g¢OŸ"ž¹ªNQ†âô¡· ~Lß¾š�«O;òû–ÚÑŽð|´Ã„<æK2½þ(jLó®šQ:Áæ„®¤éÎÁ|öµ^šSmÈÅÇñht‘zE£Ka�IƒÜÄapO�…�êG©ká'qË’ Ë^*c¦Iß!Ÿ/IÜÛ•$1hDMž£|O½ ÝÙõ;ZÝ\ˆÖç‹PÖñ9NDS°åFüGsÜhcƒ%ædsM•j$=Æ27е›ŠpØ@ò?¶ÁÅÀýmBƒVïYþ.÷æ\œ&„Ú‘e ›E¿ǃ“1¢i€·’ÊÄÎW%ÌÆ¸š+V÷ÃÀŸŸ²Â_–ó6I[I³¿Š/ÈR¢hŸàPÏ9MÿwÅ2ö›N ­ⵇ‰ü‰1~²_û—°Ð%VÓ“sãEøà³Š8¶Á cÊ{“+Ó±Cì¯ïY‹J:ž$j§Š=jÜêó Øoß’ñ÷��d*5U&¦Ûkë9:lOi»M˜Ži ëZìA§4ò¹d“pšÿ¤‘•=8[-ÇíÿeÛ¶�„– ÌgX眜fj˜'*ÇÚóãíòøüƒ,i 8ÓczØ0ÖJÿdq,­A3=Ô)zæR<°7Óç=ƒ—Ë|À9?Q5Žê§B„[iÄ…±Œzâ�ä¬Äi�Ð#žÃ¬Ci¤ó+§·ã6Ì¿]H¶�çhrI ½½n Ÿ†G!p¬‡ú…)4E†!GŠÙªÞh„ýYÚ§&\‘¯‹¥_Ô¨Õjˆž,Ž‚Vã¹”¨)É«‘æl˜‰!»w’VN2:Gµr¥º™øÇï¨ÖõÜPYÆé=ƒ .î1agÅhɱ î�t#ÜQQÆ…ËChu Š®{Õési·C8û?PK-!£¡^ÿÿÿÿÿÿÿÿ arr_7.npy€°«Xœ™é[Oï׆+¡J!2ViÔg¯•(¢$E”9Qˆ¨d¦Y”¥h *"4Híµ %…D‘Púš2‡2=~ÿ³ßíûͽ÷±ïk]çyì8»…sí�¥¥ü¤v�w[ã³Ú{¼ÙÈñÂZÃñº#ǯõòöõ^µi…—·Ûšÿ­Ï\åé³æßº�ǪÍkþÝk™éŽÔŸ<ÅP[wäž‘ÿ¯K!ñÜ ðD;Ó\Hò7㬈ŸÂÆ>($õ"{ôÀµ3>‘‰‘šÝ>$è¯4‚oN+0%¢*KGn%ƒ ׄw¥"h¤kÓ臼yb9 ³¿+ÈýÌ-}u}ö°ìÃëËUùч¥|Ê×––í #ŸÄxª�‚ce±-9Fÿ*eIgÑÒŽ›°òX‰Øîùž”Çòàјîx�ê,·aöÔÔˆ˜È/²èôÍ#‚ヒ˜¶y‰¸÷È\Ì]àHÊœX#(Šÿ¡/®ð–�®xS=ï}Ê.jý0vfOI“ár’ÉZƒ“UØ¥â"L;hBkžÆòÞ‚ö о‘�×—— “üºvÄۘ๪uüüa&Ζ•æào*´)¹�v$¤ÂáåCñdIW½Æ„I|·n¶èË:"8Ds…:LÂã}ÿ@âÂt˜ºõ ©ÇëãÆÒÞP¨ï‰ƒ­ÇÂP4ÃïNxm%ý7ƒŸ6Îʆ…Õudë4ŒîLâ]úiÚ½rX'Ý$Ú H†¨Žo—OíåÝ ùbû¢3hVô®GÏåØ_½i}ëv該dþ«`Ò¸…j'’Áçã$8m_Û,+ÀãÊZ‹P¹p©äÕJwF£>ÂùùvÔxæ0ØÝ» ™}­îMÀÕ£ÔÍÇhD”Ö¬ë{[Å¢éðYœàZŸ†õ»3³éVÒ)Ú¬�CA2¦=/ÔbÏôh¶á.h?iÇ5Þ£a«Þ4áòtÆæˆÏS´8´áž°ÆÎƒöšrïß¡tvØnŠ;;Š4ª™çܶ¢eGƒx·•ƤåžÑõø ‹¦ˆÚÊáhñ̘ 5oÐN†÷¶&¢¥ïlž²i*™èÂ9yWž;N÷û„ñÑß&¸Ûc†ðÚ6ö,}E6eŤ!îpàÈú;)»¾¤³Í†›ßÆ@©B$5{"š6«´_z§(;£ Ç<ø1Þq˜]ú&-n¬ë*Éë¦5þY|¢�Š®šÀdr ýþáIÅßC`­ó r6¼Y*x!Ô/>çt ×,W±}G&XOú é]§ø¬l©wzñÇÓ½©È$ÿúó­?!¿§�•2š`£Ëp<ôáÜŸœžƒ™k’•æA×Úí¢·{¥`Ø],>ÕSæ7A„–Îw h· ŽW*q–ò¼Ý±š»¼ðê@GNŸ«Ž6{pïɆø*<�-^AÔ½=tëâO2šjŠÏ–L§qÁùf°žù5*lÅR×Pžþä•ä÷{/²Y²Æ=Є_?3Å Á}ø„¦ æ$ìÇAÞÃiqÜJ¯_Úoe-ßðÂoe~ì²â8§Ì@Ê3Çó G lÿ¦�ªsxÓP\d1‘Ï–—píÙà�`Ìr×.ÂOàÎø!øÅÅ[€Ð[d7#)øïB™é¯áíáÆÚ£|Ñ-;”ØB`A,}ÛKÍýmxeõÜ|¶KÒ$mÇWoâk²K¸éýcp¨[ˆZœBº/q®_&.ÊXHeλa¹w;¬5L…©_ï 㺻aÜÑ3¼nÙ&³ºyÁ¼ÿÑqïÔ›}–—²a£ 3ÄþŽŸéF®5+ k„3Ov‚|C/îµ t/†cDt$UáSñ<>o  ²E[Å,Xÿx4Š‹^QÀ Z1üðA÷ü º$wœÃ 0j´l±ýÛåÇsÑêR¾®žÊ\ -t=Tl¦àWü¢7‘«y.­ùuŽŽ¤ÄRÜ1¨„·¼�…½’F~•#Ëñû&’�Ê4°³zTª¸Ä¿eô³Ï[³¸ª/_‹×å3‹÷ Acûˆß–ôäéÇEê>•€ú>1¢¬Ì3ŠZ¯È#–À`µ…ØùQƒß…ßíÇ—ܶD=Ü¿€s±&š~ÿ ÝfIÖ¿Ô$¦æ•!t3UbÆäÓÓu¦¸¹ä=8T$ìí ÉçjéÍ_z­g+Ön߀:�%‚ôÊËä»ù2|: E¯®ó†0)Š,É~B>m÷ÚÏ¥‘fTºe=ôÂöA¶¸Ñ#Jã^À"Í lV3…ɧ·G ÁÛä<îa…«ÍÒpŒæ9²½eO¿N®Â§N0'Í™OÊóΛJ‚Ñ \¾o?µõñ O¿"ñʾAwåY¶+8bxîÉ?®€DXª¸¥«†QVÐvVn|Kn ùÍ:YîwJn ´ìp$ôR÷8'“ìÃ’E�õ1À+�–œ?*G’HöÏ ¶Q¹ MýOÐ!Í °¶óõ¸1Su]F¥ã­§w@Ñ£¼´¨T�åW—K\û…¢ôRø4¿%ü­òÛ’ùYFìª4À݆éâæ•)ÂYÛ‰éÉ9èfÎkðôã�o+…SkpÃܽÀ½¨ ©‰67÷#Õè©Tæ‘Égåå…† „")|ë`ÁJŸŠøGÍ]Ú8æ»ðò@6ü=z�ò'%á�e� ;&œ69FàK0Â;£TY5‚e-kaG– ÷ò°"ãŸÊqÕ§�٠xÿET�}jðm,æØ÷†3ž9GBç5¦²Zf--úd7¯ey�¯öLWÐJÚ¯gŠ)éW0utOºÌ›-2Àü¦CB·ax¸@ë¿_aæíxSu‘4¥ )u_+ärä\¨¦ê“A(×ÚS0þ6�ï|_Á ‡p¨c9ví»6ü€Û{âÜ^>´?Û‹îµµßÓÀÀ|¦˜|EÔR¨øÎmáQý1ÉþêhXÛèÎîý±zï ¾ÕM4g•q˜®jÄ=¾•…TËO¡mpí™*¿ZxŽ#«JŬK,ñ?挓Ýp·É¼~x6éÏœÁR’éý„ ­ ¾IyÔ“Y*•d+ŠÌ¡°¥ItÒTâ‰^Ÿé–xš[Œápöä’$c�vžã:l qq©œ¾H¹]AT¥rŒ[j›%�úÙ4ûêRTȯ‡»<´8Ñ-®Ÿb*BÜãÆZÏ”wJëf±Ç„FìØð�«’ñRž6w…ϋş6áì(+N»Jq3àÃ'‰¼ýä®­ÌK‡•Ƈ½ÿ<¤¸¦(´<áÀKÌš¡×Îp|—ôAHy…ëÿNæv†F:øÑH‰f¼À^Ú£é}ƒ ˜J£Ò9¶~³�³CrÁUNªg’,Ó&Ñxkc´íÒÁúæÁdúb\‘s_G†Š~óÞ AÉóQ½ì2L4–£ù“þRÆÍrÌ2æÕ 5P¿è_øŠ'b¯»j8°D™Ü®Pèr9ñ{²Ì¿gWßW÷á§òhlì®Weßöž1@<œ˜ [ÿÊàƒWë!͹Gv¢dC{” Ú�žŒozô¢É/q’ƒÕçûâ¥ã ¨x¾$qöQÉÏι|\Og÷œÃáeCøæÜŠ{Z.¬µ”Ïn‹&û’CTq?�ô×ÅàÊúØsT—{鼆G?^�ºëGð2(ó›qõé©ðtà\jê°¢i +ÈjK Z²…8uš'xÒˆš%ë?õÞ­‚w}Ó�%§¸†M¹:G‹�siaÂ=Ö}¶öìke–�èôpâe.Íä|³V¿ýKÇFÂiï»Bö´YbÜœƒBs©<ÛúmA�Aí4×E %Š# wX<ŒþfÇgÐIÓ,V™@¥ïBéGª…P§Ð‘]—ŽhÕ¸¯ð+{7�+†”î™[qÑÕ–ÎaçÉk(°$P¢Ðï^”À¢’|XõùI¼ÅÕÆ±oå!túµšÿëÙ*æùCÄ+4i×h.NÏ~ ¿.>©øÉñúå<„­,¬K_<‘ÆÏÁÕÔ7sÞ0|Lsz~_¤OÂ^Õù06ÃŒ{á 4›N“oçQ¥æÜì°…ìÂîK¹¨=t=&ÃÝnGáýÈ*Ò[cD§ä WÔ’­~¾xøV÷Åò²t¡ï¸ än³´qäßrXè¨DÆw4àha+Qa[éqxqøY¡ÞgΟ _î„òö¸¥°ò¯&¦øõÅȉ=�µ#øUp¾€ˆû²�3è üJçòG䔣b¤¬<Ž82¥îÉý˼ýùÁÝQzøkž(Þ-'*ü à¶-aȆ2–¥1oGâL×� ÷F¨8‚Ö4'Àø‹_¨8¾´=ÃpB„¿‘é-–÷�¥Œ±ÇåeÃ[maü³T/šÅ—ò†>“1P-Mb}-ÃÏÏãs§Íyω=¼u)Ïùê‰VŸCÁc×rޝm_Éfá골óáGIQìf ÿö‹~ÏŸ‚q®J¼Fý3ì?tŠ´pkÖ~VØ·>ÅDðÉ.OŽ©µEí!¥<ðý:a²³?WüNÉ{¿ Å>Ü{° '§¼‚Çw+Ÿ“7ÈOÙŒl±�OEû…†*´ï[¡°>3¥T#å\éÀuïXúø1�ü÷¾Û¥Â(½x÷;&¬ì%¬}pŸ&™öÆE?€î_NQLYßž\]›H³ /âš+vp(¡Ö8 â “ÝÔçj¨äÈÝù(‡Xœ* 3öFS�µ)=°œ mÙÈj…WÎÆãÁuRp65/+ƒŒò°À!Š~¾�Á¹ëJa©Û:=1‡R>ÀÅÕ—(*`º¾Î¡_ï»E¹_*|ÞÿÈ'd3CtºhŽ QÛ&'þ*žà>»Ä§F±å„³âãÆ­èâ¯Î«í?ŠWû‰BoÓñ¬ß+�ŽõäEOÄRÅåŸà«êcè° åÿ\ŸIFHæÏ1ÙÜý°”S†œu’§±�jC©‡:p–ó)ÄÝ:¸U«žŽ˜�.><Ž×3bPjG^W= +ß åÜ� ˆ[CkãSy”_ l0ÜÞ©ë1M×§ðKèö2bµ†)<`ù ì½ë8¦|'óc÷p¾T9j·OB·Í‡ÉÐg/=�óÓ èho¾}ÔÊÅ¢ ë˜~ø°~Ýê¥Ñ »³¡ÑÃPhˆj"¥o~ß¾ 3NN#ƒ?×ÑÄÂ\XÛE+ÕðíPÌ9¸é-¤•}�x9oç†Ê-ärX‘]«: ü@„`¡9ž/ù ý’Â`_÷2üÓ6šŠ3œÉêÓLl0š z.=§;ó­›Z°ƒì9ô|É΢Ï.@¤ãĦW^C±÷ Ó“;VãÒiñàhGi2jìbw L>�BN6˜ï½/¨N€ß¯?ävýQåE9ËæCSÆT£-8¨3€–ïíÅ6°üÍ:²u6vþ?¶™ñ©v;d·¯‚ºY,Y-E÷y±u2¬Nj[ÖÚÒº)3DᑬÐ7þ!$ÅÆâ[š ªŸMGGO[¼Ð�CrÛLùÉd3>àÞ�&¶ã®™Î’ýLPs‚ÝÚýÓkýÑ*Ú�?bqÁ³q–2G-“eËðpö6:IŠÙ¥ñûÞžqÒèü/ŸZe`J¥"è¼#•I†¸é¨&>>äˆ ™Ü¶*…5¦Žf‰’ßIKe�f=¡º¨z-5âÌŽ£âîz8îïXŽ}òö{´ øû 5%lƒ4Éz˜Ó¸ˆMz ;Þ&ÀÍŠâ �ƒ°àûX0·�þûËüÅ^´ùEÑ;—ðϨÁÔ2³'kC2½”˜qì–æÒëíô÷îlìØ}7E�"Uï îû· žŒÇµnªü 8G.p¥qÿööÅ8wç˜y$O‡¿>ÊCÔËîüSA¯þÍ [5¡(R‰ðûÎ…Ta•ïl%W&Nwå-}Åewã(äÛW6J‚ÌÙ²>�ÇÞ£òü‹¸òI”ÉÝÂ$xtäîŸëÁšÉA¸zŸÞ_ýç“øJWáù[Ò\7»ŽÃí1èwL©Ôõ“˜¼E‰tÔ•±o`¼¾`¿ ò)>'íã�ß4hÍ'UÞ1FUÎìFóF=ÃÎÈ`­óZÉú¾QP™Ùªaø”�ë–3‚ÚÀ쨸‚k Þç<±qþ4xä~YtŸµ ¿¿ŠD×UδÝP†'L³ÂÉëÝØ'r*¿28‡Zdðþð“|÷±.d^™ˆv^twÆ?Ïߺ�Þjc‰“%4\ØÄ~'ÀÌRÕë]yvÅv“…7¶Mâî+j¥7ªðéÁF˜´Ó†}Žðηt.Ô᫟. ÜS-öï93¶†a†Fº/¸Å·çðÒD¼¾g5ä�Uç;KªI÷‘.•V��_«íøs’- 2áEÓ4}º–{Çv^¡ï×BÄ»>/Iiz\jR`-ÕDA¸&B/�L¶½F.U«!æ�6M°à�¾ïà†ÏbžÛ²„{ûdùH{¿”ÝëDè=¬PX¬Ô ªJÑ¥Kç瀪®-äV5¯…]Âá'cJ‡Å·Â2�aðúD–ñ|In'ÑÞöx–xxáµfl–ѽPajÖ6ë?w<^B?N—‹Ã?EsÅ 7áxÚ˜¥í.Ö)Ïä& ñz•)ŒÐƒ1§¸¼h9vÖbÜW ]W Þ«�𲛏ÝþiußÃØ—“ð¤§+~R=LÚÞÓyâÍeš‘ kL£®Etß÷žFç’Ú—-ÿ\.ˆl‚N‰Y^[èkh“˜üH�3=Öð“+ï¨J!�ä_¤%ž2|In ÿ8#a#é�è1Çŀ}”½þ¬à�Y[¢;†Jú½#Óçeüàíè”+¢Q§z@Õù; 8Ý“—jzÀjÏh°þŽÍ#y»¥ì®ÝP¤Ù+á^p‡FisúËÞcÔ ?Œ�Çä…CX…þHZ*ªé¯¼”,n'qÄ8hØÈ‹œVó;£Ñœy£šj§}…}Wíà�î˜ðü >�všþ,S„IæÍ’‚ý6$3G�u6OaŸîx1GŽ ýçÎ’6ýWp7F v˜âXå$¶9wU¨~Ÿc+‡‘kíÕÓûx1Ä9ãG`ôM>˜2œ[^ÅçÆtÿÇЍ€;ncñœŒß댭yÜ<‹:oð×K0gJ7õx’ ŽGjáý<Þºœ9ŒôUvC æo¡þu*]¾½�÷ÏîÏ¿^EIò4Ì÷™Ž•j¡8³Ä‘Ê:·ÃÍÄùXþ<GÕ…�E{+¥,hŸìŒÝþ[¨W¨“ÄãêÜ"\2ƒÌa×kE^°p;Çîš‚‘†¨ðF²zcªøsB£`m<½� éGåQègÊì£ðÒ°¿”[Ù›ÍVdã~‡(aƒîL\ae…Rq÷áù¤›¢Qt@ÉéÏ÷«‹À‹$¬ZßE6C»…ÛíìS¾Jøûb;ú?•VÒëá­ðüŽõÄ�X!å�ÒJ·aìÆD2Рï#D�¸Ax¦¢\¨ÿä““„î·½Ìó?*“¯Ÿ®Ž]©c2èkõHrÈî‡T½¨c‚ž¹êÏØÝ ÞK÷ þV>Õ"În8Ê?Þ÷aq°%�^9ˆÕæùЪ‹½yæ\5<�VºvÇ Ëà¨ÍÐäû#ä_¸Aøøhçæ¦@H~¿;g�¥3ßјš³ö3÷)wˆ>íš~^¼ò·™¾Ê¬†C6ʸ” ‹õoQL1cÁ— ó;žî­î¦‹¿�Ñ f�yßkN˜÷|.n™ˆ£ã4ø–böüœBêÄÒ7`íN¨vráOÇÔØYó;ÕÕG5CE|ë¦Aó»Ë¡+µ å;{zí¶‹Üvãa{!bŸ4z[FuÍ;ØW{-PB‹Ù'„z÷+ô`Ër¸à)Lñ%0{ãÙŸOà±Þmâ —…ìµ|�ꆑ›¤q½ Øfs†ÉF<+Fòö;“Q÷ä�²5óuH³ýzéóUWøèÑul¸é_&žïÃ5Cä¡ð_�•JÁÊ£Á¸wú@¼®˜&© ›È J2yÞ¨rRõäÞ'ôpÕR:þSŸËw™ÐW]eðõ™Š§Iî|«Žz�3, Ñu§š”�îŠjeŠoYÜb ÉûÖ N³•FÜyÆ=d«1¦!”E�SüøV0´_Eaûp^p@™Ã_y¯àÐgrhXsMXvæ4eùßÄ[’X\jíAñ›üÙ©m*îQ’’ìSFïMBöÓß0yäzl|/xw  M‹ ö'éópKj4wA³Qcð¼�ÈëÎCö§DnøÇŸéµ0J}x®Öàxª¡°)4ØßÖ�Ç öa÷ Ô xMKET3§]�A;±�>÷Ù n#ºß�ã 3ÁPf:×tYR«ÁÑfÚMbЇ?ž�ŸuÏðšwÑt2·•,Ÿ ÔþA Ÿ�`/7kÒ±™@}®¨— ÷áÑòQ4[»~>*fµÂ·ãV{&â/_ \yv?ÍÌ)Ê"’å_Ü©äDáó†¿à{¦ ý§œ�‡ŸãÐV;2ä&cÞ?†¾òT{ý!dÔ åßf›H±±Z\2lW)î`…«Í`<¨†�îC>9Ó0iÌsXšõþÎWà±a_Kú½ ’‰ÃÑ÷¿M\”VÈV«q|™ÀNÇ5±µ(RÜÐ6Œ£S”xB¢*~©�6ËzµJ{³0lnÔÏÂòïD§ÊVØ —Í} 7q�ϸX¥ŒÕ]ªØq,GĹù°å¼�à®*c®=éUF.GÍqîn,nM¡ Ô Î\¹“rŸK£Þ¼],å©M}âƒèÑ”n!N~6i»� ¥§§ðV–:¾>¥Ê2ÛÊéKŸ�4²ý›ÿmR:GáæqŽÐä5‹›zñÖ~½Íׯ™“vè^šs*‰n&`xs(x å[“·”N’äÃŽï�±ÁØ‚oškð¨VE<=ׯØ�WÅ1˜b•MËçqµaM鳊%ì}-˜3î­Æ|­¹¤5+”ªóÐ[7¢¤þˆêûgs¥»¼û]PUŒ�¹g¸�Únx­dÒ*i—çsº,i¿«ÄSeò Íãøì‡8=ê,o-zs�R8ï¼9F�š€m•káÛ«.´�NÃ'…Á½è ô"�é%axí'®gYã(îrÞ�+Ž. A‡O€÷ïêw7•Ÿ¹œäOZa…Í ² ‡ëÉLÑÏ­9Âh¬Xð_&½ÐŒ�/‹{—ù;¬$Ó�«¹öüœ>ã·¶¬ÅlÓgðЫŽ/ êMÓ©k©�¹—Ѝyc”`i,«¯Ó/Ô³TýÔ»˜ý/eK¿>øf£4‡üyOþG.€~xl5Yχ§œE¼ ·=Ò©pG¬ ? ñ†¤Ý¾Ž �wqíl}V¸<µ’¸ë²Ê—ÔÓûuÚt«ÒG¿T‚a3¢xBã4Š8}˜�¼¤ÌÂ%”õW•õƒ�X1.–óä·s«º7½>3š_Ê>Å?‰�üÆØ["ö NÍ—•òéic)Jî)<‰Z‰JÏ%ÇšþÃ~aÅ´Rí±à¬vMl›ó.ß Ç?q°foLXãÆb?É•kŽØú¤ÓŒ-8oº>X§:ÒN3YÞ+—) ›ìO�}¥AZm?þ ÑÖ¦½0¦+õ›-éYz-^íƒ÷¥ k¢u³3ªì¹Mwüaë�H¡R¥'Úû—6úi Ôºbí5ñõCsLŸ”Hºw6ҩõã{ ë5?]ù\¬–ñ£JxM*I¬¯¶àh/# ×  gE46n£>™“ù`úbޏ�HÏT7ðƒ§'¸dŽéi×ò,¿`®š-[–r¹|wíà˜U18µ%�ë·jaÙÅônŠ<ª�.ùM¡äý`>N¯¶@y�Ç}Ù{F\Xö”Š÷ÈòëÉ&hö‡<ÇõÞ¥®O‘"דYü8^íà.fª áZ9y¾Ü6?—šâÎã!�¨Ò@5Z³(éx¹¤�¶¾~ëÁæßBжï,º²«Ï™Í›?ÓÛ \pG=Ý*D©çgÏf’B÷&ÊÎ,ï#È“Ýà[Òˆ4•,ï·ù’°DN˜»l]É?ECö¯aÉßløqÑS¢k¶…Ã5Òž�¼°i,h E“­©>YŽB{sWLÚÿ$>ñJ î¿½ùb‰'® YÏY%yÂ�Øpl¥>]è"vØVÔô¹&”M_Ë6Ö=Ù÷í` ×±ök[Ѫá- i}é©ñTXôÞöÊ!÷Í‘<òjOh‰€Q/çà`ù‡âÁi©lN /¼/Y³<�^lUÁUÚå�íê|ª+CvL~}¡½¶Á túç”ÄãÒUÙ°rîj¼ôÁ�GÞÃØ¼^¼âñuo­F}tìñ|VGó�W²ìŸÎi/¯@xY;žÛ,Å›4úCøôÕ¬§‡Ž¡´µ^"î*0m%VÇ¥3vâ_Yb@Fµµs?¥D‚tP_~6fÇx¾~{�Cç§&£x›ãvc�§ü=2�þnpåÛßrIùfZ�Ã(�•,çñÈ1ùÍÈ7ÂÎ82e=N�›€ "QE;ŒZ Ò°koËT ;ù·Q¿º4c™g>º+2H¥˜°Ûd=ù" “ºN+Æ¥±ÔYr³–å¶³aâß÷hÞö‘¬“ªÍê›§@Ò‘-ø%î0̾z„Oš†OôÅ¿)¥1»âŒÇ{ÍžH*„�ÿMƒ‚u+pí¤h¼¼·œm!2Næ� ÒopÿO*âxËbò?¼—ÎEåíxžew¤vrwŸeØëu¥Ð&ˆ fÝ�ïZ6qt 4–6S?YÔºU …Àèj·¤_G3¾ÚPKžN§ä=å4‚íKÒH {ebÓ^V÷6)a¥ï/j^€Ã#pÒ”»œpe#ÔØ¼vvdÃôÊh× JUM¿ƒì+e Q„i_k*dÀõý´Ÿ�)ùΘ^s08�¥jÚJß™¥’«TV�ÓÞY‚Kªù½ÞJÝžG¡ö“ Y~…kñûDmÛ)p«Ñ=îÑŒ¾‰¬ó>}2£ðö lQ]w'Ô˜�¾‹äx”îŒ×ŸÂ£Êа¬P¤{™ò½Ì\q¡m;}ÊOãô9.<Üùd~uåá‘Caåòh>¶5Æ*¸pþ?ªsûÕÙ5´óR*­}ãLî-m¼êáLtŠALÓážgàVø 7-Á%Ùש¶ð*ý^î�®ï_”.ü¸Žÿúc½IǸIµ ϼ–†Ö §½—Ù ¦ã>�¥7 ²+€Ý=n[Òç:(ѺsÝû¦f.iK!EÓAø×s;·<²ã™Û^�…V#x懖óÐ|K.Ž÷ªΘ¡¾M§Áol¨‹ÃågÆ ò’—â‰_¡pLà }íÅ›-°j—+u†.@�ˆ58o† =Ü\-:ÜtBõÔÑ´7±?(T�ã.Yä�A4ðéÊÒ~3’áÔH È9áKa.(]5ß¼G×&O�ü³gj†£Tb²´4.w�E/ÇN›çN.Ùùx"ÿ'~r2œ«Ïa¿��Éd¼Ä÷zmÇt59|ÄšÐ/GJœw<—MöžGn÷ÃM{ଠk8³ú¶Øgp={Ã2ÎxNR•ôÙ¤'ÿîûÓ¢Ù¥Q5-f°Ö¥#´¨Ç.à!á™¿ËøÃž»T5#–³½3ìŠWp�¿™pH+NhÈó`•=¥÷¬’ÅâZGr_é�§¬&ËÍ¿á×¶âÈ„N•šÌ¶u[áì˜Áâë€Íðcüß’'{û ¥µ ÆénüÎÆÖ=ÎS_O6W5澕´íç!¾3î\8øG¼{ë�Ýú.¬�'ÿ€ra«¨§7†'nh�›[YÉ%œžçå‰û­ámÕÏ¥‹n{ ÃË�6u0ûØ9ÌŠ»Êb…]ë�Ä?/Ôù½çßì3„ÝKÁ‘^—þp6#Sê¡"Ô ßÞ\×ÿ½CÜreŽ9�ƒ÷Rýxù°9h}£'î¶Úǧ¬§óÄöµbiV,ŸS³Â¶1udÝÑmš.’ÃðË8µ³”šgë€Ê·<îܼïn?Š„Iè^«ƒ—•–â7‡,¼×m=»é $l=#éb†Èá �a“^?¥�¶óLômìï,£¬‘Óñé�”™k‰ë×.§³Ñ¹lmÇcë>܃…Ò-´hJ2½Pž€‹òèJ•"ph§Öÿ–²|eü\•ņ%�\)%ž[nÊ_�ÀY…ƸÏR <\ƒ0nM1Gul"é¯É ”ÊWîêrŸõ7è‰Ë~\ý²ˆ·îÑõ÷ăâg¸6è!Íñ‹‡Á2ýðë†õøDጞeÌÚý£±iR&«ºðìÃîìpi+jÌŽg–6¤†Óëi hRLqï?Á�{Ô’Òƒî—߀èÓŠ¨’µ�‡Ü©§`#þ4ÁÇ,pÂÌÐã¼&k~plëí ßäE8måqqhœÚÏOg˜{qh{'m�7›{Ia½…1.®®€þŸhþ‹ûôx±34èÜÄZóP7X‰±á„`ÊwýR)}ÎHøÚÖ“æû€áªi<5¼®Æ~!Ï=p4®Šo¹/žP�;môÙ74–�¬ÞËÑoÄyÆ—A5i>wd' säAÙ@Ð"wM˜;§=ÄÓ?;²×­ j¶õ@™�äžìƒýÜG †êƒ°.d5v8NaÙ‹óøRõm¼Ý¯›lŒç¢žo"öµ<˦NçK18QÔm²çžAAxm{�Y¼_}Ê‚?/¾ãø–‰¤­¬ŽO2²²•¿ð]V/,^ 3®k³¬ê°<ÎK&5‚ÄG™i}|ýxH(xÇZfçÉÀj ‡ç‚ã%Jû73W­Kçá’³åTc‹6›÷ýëÊÃü26�_'N!…»Ï]¤?¤Î#ߤ‘ê‡T 6…àÄ)Ó1C8…{cDzçóüsƒìp‡c·§bmD64T<ƒë;”ðÑû—p³è£ø°ì_î�%O“ôû¡Ÿv– 4U�Ýv ƺé‹ùÊŽbV?)ƒŠ�ëÏŸ§ÝiWèõ_püÇ\â»fø�ºX¼E Ël¦rrå7!É.Eü¢1 oùæÓ«aÃÅüôèÝï ÄŸÃôÑê�)øÌ:Èw¥81U™ì�ÁæU4§ízÀ‹öæuõv,´XÙMÊÍŸ“V}žä¿é²U'Ý$вàk1_[*±�ÝFÊm‰˜òÚuLÇlZ:b]>V‘È¢RY»Qã®;ÐÝÎø«æ?áúß(ôpi¥·õÅæÐ\ô-9*ô÷zB­ ­y{&¬ ¾Vòlô"Þeþvy ÃïÕÂ,çþ J¸nEvlÛ~/½¶9Sȼ{>ÊÅÝñm¼rw·0ÉTõ,†Ãæïp¬HC�.R[Û@²o¨c¥[´fUÔ?&;Ê¡ü£…ÏëüùLQ.:FÌ$ZœÀ¦åi‚Û*W,/°�{Ï‹ÆÞ(µz¼ôš¢Þ/|rw8;ÿ;£žŠÐ=®…6í`©i#ù×Y¤ó/¯ zÁ/i�»„nÖø££‚Ø6Ñšj´P{—:êešá Û¡<¿áoÖ–æ£C| Þ{"(ÿ§‰�ùŸ@aÏc¡¾µ†æËÞöÝ¥íã&ð¸†"rÇâ�^CxQé"öu^ÁcãÎAÆ7œ–ý�*þ3"ÕïÅd9Ò·¯}LöF¹P4]Ž ¢Ï FùNp¸¦”/Ç(°çË,ÜqŒÇl¡mÙþø¨vèÜš,q¼’µÕ¸éè&œ°Æ·ÚŸãä†ɾ~Ib™¹+þ YÄõã¨uZ$©Êsâ�ßZkqÑÆj¶YñŽÚVàm?U„«²Ïsހ߀óèñþ.,K¼%ºõSÁn“-—‰žùÛà¶Õa®»r�Åâ4{ØÔgÕ¨‡Áä¡×¹“«øXO+É´ž¢¬Ý%aÂØ¸½ú.\=éÅmOgƒÑ„1ÔTf‹³J¸Ù¦‘âs2yÂÏ(tLü�v…¢÷¥Kx"á-ûµöâ^fÓȪ÷gøò"^˜%‹JùfÜüú=pn »c »Ñž×o3æ ›å8ÕÖŸ‚¨ÿ‚HáØî¼Rí}èØÝc8)a"V¬ø)´å @áy,Ì �íçS̬µ�€û�ñ¼îL,~mÙÏäc�ÒA ¼A>•ZÚžˆ”Õiáñ‰•ç�s•$˜Þ÷+M•ày�UÜQ˜Ê®'Žc�úz¯=VÝ Iý=„ÁäÂ×ÁÁyå�pdÚW@çëìÐùh–:J Ë)–dÁœgÏO–Øë/èYé³q´+UÈ=#5µUh¯Í{�»©¥&ÿ\ß‚ùª�iGÇ}.Ü´çuiÀ2ŸÕx¤vÞùzô çsê„U­SȵF¹Ôöïdò–Éuì5î÷;�NÍþŽ›ˆ1àÇ1{L¹pO…°pL(¶$)°|ß…<Àr$K~6àõ£ÍT¢0š«Þ|¤¦eIØï +®«‚D‰ Éøî¡ôŽX–yu|îfÓ�±í4À+�µúýãˆw¦âÔÕ9¤e,Þ¿W_=ôÙúÝHlœ]Bú'Ò¶®L°×�Š~Ehøºªä|Þ—·\¶ ä�¦–Gxue,¦¶ï‘Ì.¶âý[%8³Ö mv$sÌÄ�à5:— >ìÞž‹Íã”0Ão$ßÌÎ&ÍþžP§ÁÒ’ásÓe8ávuÜÛĵ•5‚zU¶ uÇ{úƒñJÏA< ¶•ÖÜ£ÿÆœ€öÍT§�FëÌ£Ò�Bœ7z'¦��7×ïc s–ÓŠ†q2»‘+hÁ,iv´½A= 0k×)ôl}+÷¾Æ‚ž½ a‡hZ=LX· è•)ð êÓ‚ó@Ìm–ç±ûy’q›¥(ˆOŸŒ¢»º¶¸irZò>qm÷T¨Mö‡e3ÿ÷Ÿ¤?‡¤å µßéñ5kvþv”³%™Ö>`aHQ”¿)�3dÐÞte^…:ÿr¡G2³ÿñk”<»¯ŠE£�ð’F•`¨ºŸ·ÞÀƒ/J ‡ÇœÚ.‡®ñ5(Q\’žØ4ÀG^NÂ�¿“éè¼Ûæþ.hDSÌ[C<å:ˆ –ü•XçÁÒØãøèu çÎ@Îóø nñ—q{ÌXnëô„HG¢òl]jŠç·m ÇÃ>Á¤¨�p¨Á‹×&_d… ¥)ŠxC—îuIJbÕ¡90ô‰Ëö·‚�åý¨,Ò¯V– 2RV¼rHeÏS€Ýy·Èqx^”—ÅŸ:éùö7‚c„ o7‚ÆEîÄ%=;è&œ'áwÂðÜpèmÛ[´|yŠ·Ï‡R™.8 j9O[âeЬç´~KŠ»’qÏ�fqTàX|2»?Äiöj]Ä9ã„=sÛ„>KýA^´Á{óµQù©!ÆüXƒ7>K:Ÿ7ℌ¼óU-�zaÆ-Þ÷s$Þ¶ ç4­óÐϸFxaðŸçôJ*nh¡ññIÂÜÞó±/°QÍl,ÌÊ—·�ÆàZŽù›…­-&ø9vã›Ò£"ðˇ&œ°<¹Å³áD0Ê6Åž;9ûÏ6ÌÐw¨Ì#go ]¾—?Û ç°hFß­±Ò}t�}¿Îà7oç‚a¤ ¿[½Æ£áî¯ð)<�Õ T°À÷°PúXÜ0Ã`û‚Öà2¾ð'‰-Ö,åLEsüx[ߨ£ˆ¥$äâÌçÏhµ²4jŽÚ-Üx¶œn]S‚.ÛÝôᓚùþñõ]ÃX¶O6_nãgž¢ä‚Óð2(�n'yÀÐ cpȱ`jÜ �3ì_¢+ÁBÐöb~HŒÖv¦ß–Ã`˜\’¨·MJrÌl—Ú‚ÆRÉ‚tc8ß-„¶ „W²~ü³Ã�:_Ü¡c«DüTZ¶ëFÂéµ?AwGM°‰¢Ló©pø×)ÒÌÿh–¾~ þ¼ì�aåZÂmcSšóâ‹è´l$>ø|—vKzã£'¿ðبc8hõiaÆž“ü|ô6ŽWÖÂQ_uøpÅ^ï¹�ýÍ!÷ûŸi“w�˜>c–å§ÓSŸƒ p0…VúÇàÑ]áì÷N Ý›qL¯Í(=É �;'áº9d+3œØ»–¦_Ù “#¶Ò�°µœ#× ÉEih1_ò»ÇXìŽWÀ°€jpÒk�%œŸÓ¿lÿ”-8­äî�‘|e¡S]1¼'òêþ £( Ûæ÷¼Ìf6jÍ©å5}'ÑPÏŒkQÀŠä�õaÎ[q•\:pÌ´?�ØÊ·|¢Ð彘ŸèÃA’5¼j[9MQaçî|Á¥ì‘ PåÀ'dbxI |¯hþ.x:&ª†á«�¹X3U×LìYÜÓ$Ü�[�uG`cä³wßË„šô­<áHTtn�¼ø¹�o�Á¿{-ÀŒ�“8®ö.eÇöãàcjØg(;E/WÄÂõõva¦øtQߨëdì¡Ë2.2|H¹ ’u†adâc!{c/œÛLg:¿ ½zÞÖ ä¥ž6XrâÑ]oLžÇN“qZ§=,Ì8 ççð›çJ[Fž‚ÑþWñÖç?àWst´RðFP~=ºšëkpÆÁ‘˜^&�ý³†Àá%Çhãð|é¢&øÞœ‰Co‹Éµ `×âjXÐ<7÷¼DcwÔ�$÷mø¶ >Zà6¿9Ø]?… ÜÓ8×r‡0jÞAì>Bq %�»x�°L-š”O[ÁAš7»šœpnvË<§"ç\Q¿^(:7�å—’öQâwÙ¿f¿yå*¼¿ä†u‚ªO7E=Ë�Ñ„Ççj%Cs²ÂGš9(ßÖùÿøÉñ;ß‹WǼ‘|ÜùF¼a�¡pD:5¯ ;~¯,-xæŒu‡Æ³ÇYþúú­ï^“F UVÇqÍúUÂéŒI²ëx$–ìÁ¾ªÞŒ;‚œ„­*a|£%€”cqv5h\{ÌCkíp¬Y~z½“?¬ò‡ÏÝpwT¸̦¬ð» óv„%@`áT¯FYkB¡2=–TfâŠwJBÄ¡mÔœhÉ�sà»Üqîáåij_ª‘ôƒ�\óý)x·ß#Ãßaéß'ü°  U»phÕ;Z×çÍè­ ÖcÇÓBo5ü­¬Ã· ÛÅþ{záØË“ùÀ6oèÿ2‹.¨!ïZÈéþCÀâçN®7‰¦}Š ø—S™Øßâày6¼<¡Z|”±+—Ù𵾃…øÑ£ËÜ'ªòœ SÁ(r&˜HÈq¢ý.[u›ÄõŠï�Þÿº/EßSe”}Äw^⥬´È;_ôø!ªD‡à�ÊAl—Ö.(œ‹NZ>`Û{)›EwÑ•Íz(ÖÓ@ÿT�i�;Ô?Á¦)y�$ÓBùß'BŸ蜲ƒ•p6ý�‹Ó£±:iˆ¦¹<óÉ~Áò_þ>?²†�wªhí¹8ø˜k@Ù74°²s…ðdÄoÑ/á3“ÍQ§'ANš#¶ µ<ô@äÿQlÞ=ý_¯4ŒHCKŠ–ÑRBõ¾çTš2 )„¶™i)m¥EEE¥¢õ¾¯!dGCÙ›�d|Èøöýî}Ýó:ÏçóñüáB@Òtú`êKFsg`wþëáµw¡,bO6VM¢='S©Á;LªÝEÞjØvþ=_\õ�m»»‰Z-eH<©œ}QS¤–ÁKW·üdŽƒó¦S™•L{—NýÓ¿âö8)Ë»êçÈrN=ºèI�Wñú+ÚëkÓ¨ZA¦ýJ”S§Î–ÄÎ!ï¿ud¨4WgÅR×2W*Ë�â‘R(cXŽáw éüc|·u>¼°½‰Oÿ‡å”qBq<�ê˜O³]5`É•(�-‘„Š'‘‚‹Õ‚ÿ¸“\ól…#ðó‚,B>;Îë‚°Mö¾T¢¼%�pUµÂ<›(oÃ+&zåÌ~¼VŒnúw¥Œ�cÆ+í£ ·®’ X+�O#ù”jx2'ÛNÓƒò#¤²Õ�OžY ‹o!m·yÌœÖð0¼I•V® εø)è0Ž>U† 5ãÕî2vÄÿ$'3;ÿiœƒ¦¿Jü@í:´^»�6~|ÊÏµì‡æ,·7„3Q¥Þ)Ò2Ø�‡¿šÑž[>t¹ö8Z?ØC¡ã¶àÞ?»Ø­{w)®û6h^Eu¡<¼lPEñ.¼`s4Ê]2hjý´ ï—èÀ¢õ"–Ïz‘}¬wÁ:�^žìdž+㹓r\°i ks÷ÃE¦{™ÇÚwìØÂ§h$­Žç+Â=—~ÚŸ�ŸÚvŸ=�ÒÃÏ¢'p•öEzÔ¥È÷Ï4fó´/�ã×ÏLìb2n||­+vâœ?ììƒ÷fî§+UJ–ñ¥°L¿FµB™:-ô²OÖrРƈòêwâªÕ™tQýÔué²2%ü.¥Ìž¬ïb¾¯£P";ŸŠ6Ńۻ™4Fʆ‡HñnÕ¯Ç7*Ôè 'вiýÍUlÖQ˜K‚6.>¤LXÿÙ�jføÑ»ßLÑú/}“³áMG’Õ16¾œ7~f„œ”Xà> JåÏÀ­Vîdñ!DZjÙ2HM{E;&¡û’y8¥g<ˆÀ·¦Ó0çÈCP»4“r§¾‡#’þ™OUlÈÌÞŽB?-ÁnÛJì¾m ±Æyä4M™´æ:AÄDqx5B�*Øbœ[{šzÂÔ{Q{ýªQÞOŸÍæX¨l´¡ïA3h²¾Æ»ÛÑö‡â$’qüã{@5R¤’w6ÄU´³þ±ô¸5“wÔ@½ì/ä×½f·‚çÁv$*s’¯ù—™GÛ­ÀÝWéqìtú[ካåB³‚ÞžVªti�'nü –«„àL½dìù,E’kw¡¯�ÚO”‡¦!.ÌHÂåqÚ(° Çc{ô,îZ»1ºvŸh`5Õ‰ì>çK3n¡ôIzí/O^o?s!É;0]K½ŸNÂÑ=)tN ©ÈêcÝš$´Ó¿Ä+¶èÒ–wXqr$¾P^}k^b÷ÍâÕ¹LJ(™I‚ßSÞÝõØ��ÅzÙfJ {À߯x"ìѯ¤¯«Åè¨Jdn½Ä,ÚÅÿ^fƒ‘�$-LÔ!ãl$H¬F§æK¸8Êvô�ž:BO½»ømÕ¸¡l��‰qT�”G-+$ñ{TdÞ:MjêÕ”¶a™ui²/Fy4öC0…†ŽpJ©…²8üÅow]¶iýÉ t¿"“¿_ƒe-°…šÈî£Ù¢±¡ûÓ*?Ïík[Œ×Spâ™ËB¡øg¦—¤ƒÓ„êôÔ8‰bæ‡ÂüZ3Øÿñ$̱¹ ,}v¸Ábü©q+ææÃ‚æ0RkµýÆ#~4,c'ŸyÕv÷°QšoÕ¾�”3ÝìõÀN¾:“Ó‚qÜÍJ/)ä»JCñuònÚ¶J g ›‡Ž»ã4Õå${>ÛV»cÑ£x¦7¤­«·ŠXªƒ<áù êH7b¸ÍÍâÞkPƒ©ÉVYÁÅÛèXhê�ÎÖ“zh*åÖîçl†Mb/ª×ÒÏnZôÜ/ˆ¦­Šy€ãð‡¾1óÙÀ¿ÛLÙSÊãÞJ‚æßQo’Îþi‰ÒÕƒ¯ ¿JÁ<™s“Cvê�ìªÜKN¬ã>>ZCF™GÙøƒcÐq¢õP®{ }£öíÚ@ƒ{U‰oO'år¸’©ËPµ]ªé�Ø)ÔýtWš®N¤ &f¼Öplüxž%*…Çl5¨qÅ|ŒyñæÈgà¦=X`ãI…yG™÷|{�Ó¸‡ç™cGêkÌm‹_z¾²ôçѯA£Hûƒ.ïÿþÕÍOå¿ n°]�oØü1R;}&ª´=£´vq5ŽoeÃÎÍg·žš“ÝÛ˜‘÷�6m%^Ñ“¤qÓMpwâi6§r"EïiänÍÂL¥V\ðÙ%»ÆÐî “é¨å¼Xÿ€£‚õß‚\ÿEÊÕN¢°üŸ,åò VWÐ�¦·Ò@üÖaøÏ+˜fé çÍ-dÐãÊNÎw².êèð‘Îî4wî+¦Ÿø&Ýe͇XÄ>œÒ.ƒoþ ¡ú‘öôhóZ’<ª�/Þ/£má÷˜JñUº+¸%2e¨Ÿ% +veWr�‰4Ȱà*yšo·»7À2çVº,.ݤg?º)Mk-Vu—ÃþãBºgZ'ªepÚ‘etòh–Ðìö[Èÿ@Mùžlm�)tªÍã"¨{Êkcz&ù‹XN–Råî,™‰�/ñ�v3ŠlJYýœë´Xý,­´™{' FhLàöÏsÀ¹ú8á§)D[¦AÇG®w•$M]LI‹wAb°‘ž8cOd«Ö4Eé"›úm=nòIgÊ;' J›ðyoÞ_^„�çà#� ¶=O”•¼eòW±ÝßïâË€Õô÷S…¶)­ß;6?`EJ^4M£�=Ó2¢”KhvÙ)\þRÑRê�=N^cŽ��¤`ÙŸN&â¤Üy=ºšR„,ô(s—ô"øË éÀL|ë%ͺ«¬qùñ{LûïŒë“E �Stpc¶:‰ñ®Îh°±„�hMuÇZ!Ùs~LU"_µÓ$Lw¢¥çj`#¦±Ç.Ñüä7;ñIþ^tóICåí€%3vALØG¸þ£ £ªNS­ZÆÝô¦äkï©^W@ã�¾±úOÝlZê3~NÕ*Ô}•KÚ›$a‹’æÈÝC�Àqh†8Áú9œ9¹‡yÛ§åÁ”2âÕO�›[ÄQV!¿;ž#Ó`tK™F‹ú.p9ù‰°/k ¤Î™Î½Šë÷A¾dŽôƒQÞíüÛ¿ìrÊo�¦r å<»'È]©Iÿj èq8RþpiìùàI‘ zhw [ÌÒ¡ˆ›lSá7¾¥šB¢Þq~z§éCßQhS9J-R'ð…ì·z½‚ç�áõùÌùÉY;û%*}~ÏžNÓ:x*;}kå--f±DÙÕtmö(öâ@#šqW‹·ºðn ™XÚ¼{^®Ïò‹Lõƒ¿˜×:·Äq«ù}öÒî ë>ñœ;à º")ø~ƒ­¦ñô7p«\<ŸíÙÕÌÊçŒ"ou;ÌÿQ(¸¡ìÄNWóðyõ1Z$˜¹‘ä¶e‚wíA¶U¯„ôÎY»øøí ì}燿Ì�ò¾»wЋ÷VhøSÌ2öúèôþHF‘mD?PÇöåǯúÉ/hoábêU¶ÁÙ…Ò¬èeå(½f'§~Áœçôgõy ˆp¥R~9îÐä–¥Är£†ýmÊaXºÜ�ŽªÆrÅ•]ü»•Ÿ¹k“-±z‰(g%´À½²Åèÿó¹šAÙŠ÷%öã4K(±Êc=Z+Ø$ƒ“ÜÏÀ žÛFÕhwÔ?æg€AÁ¢–·†q–fš\RÜx\«'Óôr¬!ÔTt7>œ^AEÁ^ä¿(ŽÝü]Xèr:ÓÛ¨bž%ô4àí߇éÁ†h6«@·K%ñ‡y&û6áä…/§»“1ãÔEuú�ÄsH{0‹öv©‘tåi” ÙGóEeºì©ÝM’Ñæ¨ïpêk¯ów&¬ÆÉï†zÑV Ú¤ýŒy•&a‚ù,Žô#Éy¶ðøù=vé”;ZÃ2ŒØWM‘ÿôá�ôÒí¹ƒ£Ü?Ï�°ýs-“ª­&�ÏÕ´òöTšdgñdyæ½Ì¡�ïﳬMrló¡*$ÜæKãñ¤g7ˆ$_dî‰~ ô_ØÔ/²´1¤û­˜þé)hfÑç§‘øÖÕ ?N5„ð·)œÅøÉ(×»”.,=Œ÷ÓöÓ~׿lÂzEˆ¹Ÿ@“ä¤9ïê!ž°²%òlfAÍ#šÖ«$3c97ÖÈd1az>ÉÍð!až.÷�…JÕ)X^<Æ3Ç`¸I$…|}Êü³¬è­A¯1ÌÍRBM „¤,0_¶[^‡þÝÉE©@VnxÊä$؉ 4áMó­þ±e×ÝÈkô#Ø*æÊæÖ¢ä&/”�1@Éñø®ÐÂÃbé1w)Ú §kÂÝTg°’ö¼RÅ„�SYÍOÌ®UÁ÷çÕñÇŠòåÆ"\Ø Q]Ò– nÖ2Qþ¯ g—(I'¼eYªÛ¨'A›Dœ5é°mï÷�»6MàÎÏdfÿµâ£.mú?�"b5,W6Á�Ë’öXœbð³–Œ ÕõRXÞiMÆ+ýðøÝûŒK¬ä]¾à‘0ø4\KüéuÒ? Ç³ï§ÓžªXòž%}ÛÒðûP9•Ï»�ê‡FÒóã­ìPµKw+Á9I{©pènÛƒƒÆ;qãOGá’�£Ði‰:¶w§Ó-É2X±å,Ý’ͦŒX�~‡d™�B lÚ͆oÞBi â|O³ùˆ)SqQ6ôÚ†z�ëûU¾›M-+ÞHðŷ˜¹q©÷Ãݱûpó‚¯:"�âOåRgìeÞ/1ºŽ�¦„Jt»N÷L1Òäg0:ô˜î\õ¦/ÉciŠz7�ŸŒî�åømÒC¬��¾uËé„x öÚhSö½0Ì­�ñË�q¶E‰ë‹�ñ½a¼�w~H”A‡;¹L1c=Ï4‚ß� aK®4îmIíAæøT ‚wšp¥“_3¹nT‰òaSŠÕ›n~ÆVuűG#“pוçôUúZÄå�߆U©—°'#ýl˜�[½¦p¶¥lñ²õ„¾1ì£{6¶íÛ SOeÂ˩ݰ˻l#&ÓÞ_Mйê CÍÐÏ_ßÒb›6íXû"­Î`îªËLVé[ø¸ad Å?;&º]ÈY^g5â¢8ã¥üVH¢Y*71î¹1™Uœd†êðU×S21›�V!ã©÷}•uŸg¦­ "5?Ì>£…i¥]Pæ*ÖdX¶ »Ýqê°d|²%™®½ÚÆOøBéúÏ™œÖ"–Z_ÎúÕ|)*Àš¢ �É´3 %š#1{Þ-&«Õ$x°µÔpó¾Ôr…oÏð®k°tÕ–ôõ1³©Z+§ë㑱ä~n6¶¨ØÊD¡¿Èøñû<Ó”�“¶Ï±óýX,I%N_à¶ó 苌acë•-Ó¯ù çÚ%cýwRïyŽe[Ávò)8~z÷¬:—â^ºã9=šjn²ò ô|« %KA½üÐ;|GÁç%7HýêzÊ;S˶…§¢âŒ¯=ÄC}cÑ0L¯LÞH-•Iùè�yÍ=Zó_Ù\§¹ûø©?[ÜâÑýà-P¾½}ÈcÒÁ$¿¬WÅ‘2¨ÐÉ› H–Ëáë{Üà\ÀŒ™Šÿ� @9z‘c�MýEü‘Ú˜í§ˆñ+}è]]!-ž’AV]!°]’t]æcTÂLjSbÏ…[ Uf›_ãÊõ›Já®Wú¸êW½ó¼1‰ÒÊáÄ^'šôµå²£©3d7ÅDìa¹xM6{çŸgëŠ>²NA&ÝîÞˆ'Ç·áÀ½ÍlËîBÞ5µ›FÿVa¡ß†‘Ch ¤®£ç-¦ôÈy Åç)j¥´@µâ#ËÍIu úºá‹Å¬#É´gUý›€¿ØËT¹ æN탚±�°6v*97_ÃLa ñ¢5k`ñ�…EÎbúx�W˜½«ãÈúW<¯yé[•7º)`¨)üP¦'PH>Çf_N¤»¥‘l¸ã óqæWkûIÏÆ„`ÊÙ<î˜ÏN ×£ÄÌj09HN0û 8éü; žZØí^何‰d×ãÉ_;8¡%S(Í!7‡V1;€d¾:R¾b ÍÈžA¾¦Ëawƒ,òHà -£›ž� c‹O¹€í3môÑ�~^§@&…Ïâ®c¯×q–>g-½¢fºxq1ÝsBí­ ìÏ#ñ±oÁ O“§DAç¦�ø¾BU|„lõôø$æ‚1w2iŒÿ\ü·A CDæÐ+CR;z6FãF»4Œª7Â>L£a-ù,k‘,®[ÎWœ7¦íÍ àé�#xäÓ]~FÅ0ü�î�O��¥Ê„éòu˜•S5?�à“Mcøþ—µ(?hÏ-ûv�F,.ƒïŠŽä¾i%¹š#¹‰mæ:ôB«ùCV­”ùÉîJyãÈ#kY³v {IS©¨lexÎ`Ûâ®ÒÞ[Q„æ~‹ÓyšÜÎ@ur,XKÍš© c[o|‚Í\ãKjšñô¥Ø�ñ«Bzye†üaýJ¶s¹8¬ÛvMü'³…LΣñÿ÷�ç½´Ï]ÅcS°Žàth¹äHó|³¡D}hÎW¤„ù¸Dê?8!î“\-ØàÈ$j�φ•÷Ý™ÌÕ-¸îl]¦‹ÉódqéÂg˜œœ5”Éq,›Æ•Í7Ã/˜:ošm,`ã$Rñjeoýñ·@ãˆ9vâV5ƒ`,K»—ˆ®å£àKÑL¶Á7 Ç[¾¡§®r ,‰2å  ôª™Mñ¦mí#øB[q8=âE3ðÇÅC´rÅvrgŸØ’ˆPÖë�Â!¾šRþ•5.·Ã3Ò<8Þ²ðE6Ÿ2r [“1sƒÖ3Ãí#¨_&T¶,d·>9Cª³~6¹Îê}¯p§f‚ë·tÖŸOÇ 1Xd*�äY–Ælº¼IO>_ÆVÜЯ…�xãn!Üq›ô%>±jçä£â íÇîâ�ǧùóm»hóÜåØ0ŸßÞÈe¨Z�®¢nTX‹ݲî&„�¶³l‡­Íí§~o‹!¦LðŸ�;wóTÔ£�-y)à�ó›)µ‚Šf=–=¿Kñ)ah³ Ǩ2hµçß~ d7€ìõRܰÑ–{_;iY¸7Í�E¯·¢¯�›©õ‰üu×õøO;Øy‡‘hûXeKÌ0ëbk~¨A:Øé^›à«Þd á_3š°X'~“à«"‹èuÿ¾Y7ŸœŠ´²”¿}¨Wß{ˆ;SËñAËTîȳ‘¸`þazq¥Ž±;#Q´ä¿LÏ�äS¶’·‰9ó9*ÂÚ§t±EiGà’¯/-wÖ@±�èËŸ.\ü6 OžÂʾ*îï¢ý8üG)­­Ë`sÌ�XÂ4y̯ѢËZÃIêÍk˜²¼�Ÿ¬BE %ÿm8…ÈÙ1¹e9dsGƒf…Ó»¥“yÝI@29ÿY÷©&ó%o¾µ�“å+µ&Ç+©³Y™ØèV6°Á˜ŸÐïŽÂ_Éðw÷¡oîqf“íw²Y´œÙ–¤±é ÷ñÖÞ8š}1M}²ƒ­¾0Q¨¶:Š\W&€ ƒÖuv°O�¿âç9ßéà•nzíÜÀêšnC)bÏÒdì¯�ka+Z�ÃÎø÷™ÎŠEœ ÚßÛ¦¼„g�Ò¤4ÃËý{1ð‚¤@ü@±¥øðk,Mö¤ÎÍ´mÈjçTÃãs &˜âÃÿösGû,>ÏaÛüŠ«»Ïô›D©éŠ $/!*ŸžGJ?úÙ³„åtÍò"É?4Æ—ÂÜ[_%tÝ9‰j} )¡U‡>» °„gâ–ËÚnð‚E"4kÝ6bV éËÍ…?â±Ö§¨íg ®;º ØYŸSôÍ”±ÿº…õù½K›|ö¡ƒîË:œÈ3;�bZû/ü§s@j ƒ”)Ow-%o3BåÍ¥ðæN)ÿ¾žÒñ¢Y7ä�\åi}L=V‡v˜œ¦’ÿT(Kô#šŠžãZôpïøL:ä²ldסŘ?Ôï”B£œÆvïo`$X‡j›í‡4ÚG Å™Pþ7ŸVÕ�ÁÀ]*ˆ�ù9«pÂù, �ÅÜÜ’û‹Ÿ‡é5ù÷ËÓ3ѳ‹» ˜õ×Y(j0M°ôÇVº» ŒGn†à*k¶^ÿvM ÂIS³IRá [«¶\™#\½¦JyQwH®ï¾œ¾�ý,”°¬rÚ9oÑ­Qµôâ{¥,ÊϼÆkñLê{¥ ¡þ"Þ h ü4ùÔ$|/r�õ>g\ð„�6j8Öì+ŸºüÏ«ÇÞ¶»ìÓ²lÞ-M®kÖÐÍ‘<øø“HëÔ›ÇÂwLÀTíлÝE%[nQ‡Ávzüî),hÆÖ½ö¤mD,Ö(Çç*‚Áèd¼«½Sù.ˆÎfY1yÉɨ°¦Œ²®+[Žô‰ä’6Ôà††xö_i™¾0Ä™'Ò…AsHû#P�S%üûãKñ¹Ux,¼@x÷ZÉ'Š‘È�å¼Ä˜¯Æ]©d–¯Kÿ¦³‹ÙB^êp@c¢rˆ8Gƒ¡mk_Äã©7)Е·‹¶ƒZ–{ð/”‚ ÿc†§�ƒYàBT‰ìFÞn9\X$kø>”*ßñì»]µ Sp—‚J]¹Mö ¸oßehÎÒÃ3-zìHëQ nòÄõã’˜ÇÕEàK¶íG—G«°`‹�†�ðÉßÇ}MâæOÑ kþcè{×°X„PgÏyØßç¾N+„ž‘Wáúv=LÒkÁ¾ÁlÛ¼^8qw[£;†ª´zÙª“¢Xßüüñº CùtÁo8 æÝ]4“Ϻ%>qÑ¢ Ð6Ü›ÅàÏô)lzy:ȨbæëX¦Ðû†iî„/y3X^Ütr‰.�™²Ìq²š}¿ÄnšÅ_?-1Nl98zÓ¥±Ãhq§9wÐûçr0—]q{Ï9®ï�;À q’&¸¦sÛ2­(ùÜ®ÛBš)ììÔ¹*ü™6�î$°Ó W° ¡7\�#‡Go8áÝlT”SB›û²Ô¤»ƒŒ6éP®…»™Ïý§o‹lÃÜ_víï4nØ=÷a†Ò!6>Á“Mý±�Nekp zCQõ¨~yÅNÃ<ç÷?+£¼­H•gìhpÒ2½ö–åÎbT½QF¿šAW˄ʴeÁmA NðÛÎí`:ù‰p©·"Ï9ƒX!w¾Å�y³å'š¨$ú÷Ÿƒ{}î;Äà"”ldÚ7$ñá§hâ½¥»c ìÃC8Ï…€îö=�¹Ã’ΫÚÒ˜°x7�Á«wCdÐ n�é#~Ëî³Ìý¤;S©ÉÇ]y¹Lü~6Úp$ºýŽu?Ä—àNek^¥ò'Üü„)ô`û³+†Æe¬òɈøw"׆ÐtùÉ”ˆÍüÒã“Èç`4.zÐÄF\g™·Sð�Š ü¸ #™´]=™oõ¥EæK¹®‡Ã)°BœöÈbµNËjàØç©1j–¾…ê)uœêŽÜÖ¿r죌•ÕÝd¢OÊ óX;8;6ðÆ× áØóX¶¢Ž©œX„?‡žû±�exÒMëûÜö Ú̾²RÿV±ÛgcøÇ[GÐ&/â®å±«]E°ÂKÖÞìä|½R…‡®/Þö™ ™øiq,»Ý¡Ê%Ÿ¶�ÕØ¯qŸ9¿î+ÜßÞFf¯ÅÚ†PŒ9Ýǹ ÙìÃöÖ@‰ÿ­uŠ\bÅ·ó¿ýޱŒõwÁ¿±¶ü«cË%î09�áx­ý9û”ÝÁ2äUÐqÆ þ³aK÷žNGNs†ä\L>á§XN´2MQʆâüIÐS" ªj{Z´²–Bо XH§òÙÃi÷{ÉRy9®ZÕI…oOÀÌêË,´$‘ÌŠ±�B–gy^~[FI?ðË ‹Ø Y³¹&Ò´cÉ*”öÒ“Uy­I],á�:Þ~¥„êrS».ƒÅûTiäÏa¬´x)ªh¯cÆ�Ðkï(æÁѶV•n>=‡)Q‚3}—‹ÍlÎÖdròM‚‡ \õ–ͬY}€•œÑÁínjЭó6´�a¿ogÇ–û�ŒlÕ4‹ÒÓf.ù…,�áõä‘‚À ÜŽgé{Ï¡†¦"®‹¹V¥Ød-c²?£Žb¢I0¯È·H å›`ÛØ&–òâ3œš¦†Š M‡>ÙЪ[Òì•r>ΫË>}) %a—Ÿ}ÕBZD/AX5¬§Þ [ñÚûE¸.ôg­i@'l>3�º5´ÿ§÷SË’©öE‘ƒú:ºT|�)¬YÍ*çXRãò9x åôß €7[‚߇Tüóý› ”×ÇŒe€1s_€S”$-yý öºŽ#õ[ìûh-úýã8G²‹QRÞ†ž¾çaÚŠ2|Øݵ´ñùÑ¡=­»Ê®Ê€°½ˆŒ}³Yaľ¹/l&dW­ë¸—›?°åRü¨âÂøÜlA$`x²((.C©Ž3´9U€gÆ$ÑïÍ÷z¯#ÙÝêá, ÄMOÂÚE6¶+‰i¹ä2ÿˆfºd1¬·bùÖÛ‚ò6¬†ßyU\KÊzîT ’>çí�篓؆ _¬Ãû �ÏÚ‚Ã`Ù0M´ötæÖ+[bùFæ<é#çö-r*DI188îŸ]Þà«�Îb‚OÒG’ Ú ãHéM==ú”ÁŒf/:õMÄ.½W01@dhO·ÂäÎSLrãhúS6 OÉá{›ÎÁ‹ÿ†Så±p 7/¬×COØ6Øy"•U@¬ËÏ)ÅÃ�U}|Ð/ T]ï ÕÊG¹OE»ñÄGZãæ‰Å�(^Æu—T0‹ƒ=,Ù ™Gg<é9´s;æâ�ù»Ùfµñ¨d3…zè'zŽ�Ûx<1èB*V`fÀ$Â[tëç¸ð>ë6dpOüQ§@ ¼#šF±=¾X›¿�G~Ï0YŠÝy�žôÂ¥ÎN˜ºs¸eöÁ}¬|®*(­–�¢_Á-€�¨¬gеWx»î¡n(k…AÇãÒcí¸Ft Ù\8EK]Hѱ Î|Ý�÷ŠÒTx”ã‹WÄãùMwø¥+l@:â7ˆ¾„¯qüýpEtìxÆÜ—¿dͱOبЬiæ(šWÜÏ´M8”®´‡ûFþÚ’®î(`ÊG˜Ø<êÞ±…—©Ám9·™ÛÑ›¬ºæ!ó÷sÕ‡“ÙXïbvòR†ÏÁžßU¼~æQvd™ž…TѨb Š/¨¦ªE™86EŽÙUÞ‚ôš}8¯ôžQ¼JÏôr^_F�‹µ4m•�Ó—QÚÅAœ9“Þ -èËce·Þ öÝs¥Ñ_ª©mÎA~ÃÐŒ]Flb5ög™_Á_H0å¢z¼Pdü ²•o‡>9¨oæÏb~�‹)`t&3jÒ-µN×N++ w~.ý,›LË]˹Öàî—î6¼o) 6Ò$øÓ é"© ��ç%^²Ç�IJě¸=1å¬åa"Æ nP¿qˆ>éc ™åä÷üÔèLM0�Æ´ñ' Ë `ì«´Þ‹]�:¨ÝÊïípaÎbÍ´'°îÒ"šzˆ¢=“pfü4Jþ¡Í4l²!Mª„¹q“ñ¤ã0â.È“ÇÑ*vq©2êûˆ4NWÔæ¬®�³³÷{žp›6Ç’ÉpÚdÚ'XÛ÷‰9àÎ’SÅ‹‹…²¶uøDÓŽy‡Ã¯„¨ÐÏ‚mŽÒÛÁø·F”x€ößÂY± ^$;"ƒÏsýÁÓŠjhì¢�oDZsWnCæ€=;Z NñB¨{³�ˆ“‚�†ü{ÊÊ;$é¬Ç’}#»VÕ’â]l2• ,5µYÁÙÍèÝRƾV¾aA›‡“„�,D�rÂé•8·±?ÖÔ`Iq >py(­uñKÛt,?ÙÂtúU°$FÏææüãµdóØ–¤CLÒã&›Ä[IêD?Ìý¹ïlÚƒÖÅ3¡»ÔŒêÍØŽWÎ(¯ÂÖZìãòfmb«Ÿ$Ñû…ô;ÉŒv¶xöçc鶈éJ+ð&qêdÓ*ÁÝ+èâk¤XæçT�åÚKÓÆäóë5œ?`ó’ì¨ï•‰ðE¥j…¦³_ñºOñ¼f¼� GßVÄÙ¼s§Cb6ï!÷ÊEÎ:,³ggïF¢³Í84ÙÊÿ�K‡�çö¦£vÝQnÓe3öç®;¶÷Ÿ N„ïdaxz@ƒÎìì^AY?lYôÝJÖè3†v<ÞsWðË«NcVâˆÈp‰‹¤wcR}Wœ‰Š¢ØÙc!C_ 6NV£s/lУÝÕN#ùvt )‘µJÅÁIºg„t“~6I4«0D;bXÙ�8è¼ÍW=ãßÌ1CåyÿAØŸxNu¾$f­àšû°7ý,óذ¦ë¸Â©Øå¼*¾êKÁ:£ð8q/�Ÿo p²º\¹Ü b×`µA9f”ÿe¡al̆]Ðs”>çs{òFbmÀ|8ø²¦‰¢_v,ùY©Ñ{é[,àËKîJN:D¬Oaº[`Ï•£l«ƒ•àGÂxü[¾ÏœÕ&¾½ŒÍPµ…"õO¬e¦.>V¿Ø†§ŸéPÓ° ¼æ›Ó¬÷ãjþ­è!²ØÃ¡½–:ý©´#•§0þ›Ö»Œ¢¬Y>P]‹t–Ma²ÜcvvBl~çEƒ÷YQà>Ìsû+NÏb<ŸI+/�åì]ã1Tº�›Æ’GÓµ¦ ”±ê ~(¥Ö°hG&Ó VàÊ%Q¨æ?øÞ«GjIã-[ ¬™gögîù–^¾âÉB�Þ´:zlñœ=›ÁåT- >käIóÇL üüе^\‰ÚsâÑiÍ”¸l„ªj’¨Œlï9RÌ/kôœ€T_3£ákòÐ9އ“냸øák™¸è7H8w :J \t[­Ï�Vª€G·Xîó.ð~p Û]‘TcõÉÙLþÜ‚Xùz-S p«ï¤ßCÌуCÓQSøÍë¯qª%çàúÓHáá×m ûå3ÌÝ·„ZAŠ'w öoõ�ýr¶æ—+Ê—½�‹ÍØ[>ÿ´„¡}îT¬têàg s]SÍùu^°Ý>x´®þ«8Ïä_ÅòÞ¡òø|æšt³ˆ»%hTi ¿ñª*7f_5%cNo³Pã“(®ú”ÛåÎó×±jµ…øà‚ -¯8Ã/%�y‘�ÜéÈ�1†g#Ü|ºçåSøàþÛ��”X¨AÊ;�‹Pà-2%a\~6…½S¢¿Ï÷2ÇÜWPëÐD Sn°íÙ/Ù‚ßä·h:;\5_×IáHÁkØžÞY •´K¿ˆ×-ù ®½ÇáÌ’‘˜FñéÆìºn×�tP30«5ŽLgúnFšŒþfX°ÏOêØË˜Ó c!‡Qç­à¯™!Y~qÃ熿á_p,i´MÀ´{*j/á^>Yƒþ‘&4+(˜})OlLvéà~oH„J‰Q¸~ïmvÞÕ˜Ò: yÜÎάŽc‘1»Q>ä<÷Èb7„ÎÈf"HÍj†§ëf`Ǧlê>~W�6°Iÿ˜’l2g31�Ü5]ÉæÆ[2éNÑô§©b¤yø:, ›» Ѿ D�¤x®Þu'“ùòT9'©±—òÆSŸ; µWQKG�«LiS>æŒzH2ìQæÆ4™4’.ÊëWOoõ±qëû@1wžÏ:Ï5Ô§¡Y¾;½k:ñû·�´ð&|ÖØŽu“&ñU‘>°%Q·»�˜7†ÁÙ9íÐ+VÍî<Ù�S.º`Äê�ñÓráÙ‘Õ8lö~\üW ­l7£_M1 ®‘#gkÔ²»Å\Úª!TÇ…\‡©@Öõ­8?|4hôM¡�-Ê–ß{0±M%|ûœ[|†›1õ÷Éã`Ý<”ÑËFA”<%¬3¡îKY ª{…×Åãúå ñÝgeÜܼޗ1­7ÛÈ$,‹â>Š’y{,›]õÊ™Öö?°DmÈÍ àºÓÑiÖ0Z¤}ƒú�Ç Ö|‹ÁÁÞd 4&Õ]•ì»z?7䤞´ÁãO†¼n$<èúÇÍ[wŸ×ÊW£•_óa•ó-þúC5z¸³‡ý[ÅrÅ@[æPéÝX¼a<éO¿ÌÙ+íÀ¹Ùóä‡a¨Y-Hß�£IËw%vIÓsÝ:ÎóX=}ø}Œ—Á5t›Å |öjtk¸ÍnfØà—oW…‘¡Ó0|»'j·8¢”²7šÙÏ5ïY/äYÊ4}–÷§Ó‰zF†Ó»Eý †ýJ²xìåYá¯�j�Y`Hæ�ëhƒ¤>úŸ7çbøÃ8­tT_2äÝ—^ã}'Ïç¿ ø®/ôtÝLæ‘ÑFSÚWcïùn¬»1•ÞFTñòU™´+b橆ү¾Wxz(sG]Òb.÷ i”MKs{«)Ñ4—Ÿü/‘Z—¬‚P—a´`áÈZœ€Ó³ Û/�"Ëäɧû 'íÛB/ç6 �:§¼z9zŠ(À Û£\öj L–AÆÛ=( /ƒÆäÌÇ·û,Ø­`}2Üq˜4×õ0o鉸"ÞÞ¼éÙ+&ô �¤؆Ë&‹�êå™d’^ÎrŒ"©A§ç¦< OÞuœÓÏXXbnÇbI�û–kÞ(K¸ÇÍþÔþxÒ‚}Æ嵚høn †+3°vc7/ÿf¹0T«‹…ÆÑŒ·›%|ßmHжfL]:Œp[ z´ñ£ÓÿZ|1ÒÀRË…(Œ·¾T²+-…ìºöB&þv<…G¯Dõ–Å8g¨ŸzhíÇÿ„7À ä;qôþÍ8Ä^'×Ãü'ÙHÇÿî5¤­Œ&oX‰__øS“z ©X�à{ZÃùjþ^þ|ˆÝ”I Š¡å™�û)“é÷ˆcä�јpÿ üt“ÀÑu78îN-žî;Á¤Ÿía© ¯`ÙÈ úcM¾q–(X4 ­ŽðCÙAoôkÙ/]køo¤ åÎLÄ´Þ‚Mf2C¹éƒ5ÊØ2±Jfàa@aݨêÐeP9²“#ƒà{NŸ\üv>Ê3_=V³©˜y¥o ÞŽ"æ=N‘$äC ðg >Þ•�¿ ™õ�¯˜¸yê8H°ïÏdHj¥V¥JX†UÀÿÜ’Aà[Š¿{=pò85÷Ô»œC©3�T#p„¾çaäéhØ9(†9“â‡xñ<�n:}oK„8ÝÇü´‰Í¤ýù½¸â�d0/ïÇôk+±q{¹>U§bá6=tTä®ÓÖÎ(Þ”‰'Vì§„05J› ó÷²ZF—T�¶6À=™ÌGäš°§ ÀèÒt¾¿… m ,m›6\�«9½•N_ezR¦˜™)A½®xY?–^ž�ƒœ¥Ó¨Å¼¬çõ³}s×¢Á£ çLÿ¡=¼|¹œ F¡¯X8Êü‹`ÍocÙ˜¹ÚgL�`ÏúO,»§ˆò�FÓ+�\<-™e>i‡]ǵ0úŒ;P}Ë;ÎŽ‡Â»Ã°ëG%U‚ÖØtúU0{¿_b’ç (pÏQns­'~7xŬä³MN[‘‰�„ËgU‘ËIÈ7­ä páÑáh{©€|í\(»Ò‘_ÔÄ ›”É)ñ ¶z{zOšT½¾øº�Dc›­®Cµ+4Ù>‚fj$cꦭ¬…´©M]� Ïõ¥°¨0”é�cÃöbŸK,[¬2Ûl•Ìå�§c‘Òv>߬®~Ž¢_¥b‚@‹º§JER%ÜÔ'š$—Þ@}Ùúx\,•ÍyUÏŒ>Û‚ÀJ•UN_ËNÝÞÎV^žÉÒ_E³ù¿Ÿq#¦æàÞ„Ãx«þ15íH¢Í‚$(\× š�êx`ZDcz¯:bÿúýkðô§IàS�/\ûsÈ;ç�w\2þܬÈ&L½AêÙbx{Öè&ßËâ4õÒsä§{‘U„þ1‰`Ç?ebtÌ2:xLøÄӢΉ¸éå>÷Ü,ºÔw‡Ÿl¹Ù4}äÇÄáÚ*àf]Ì&�ìX¬\ÿKX4.¬Z§³1J'Ù͈P:1?Þ>®Ì6ŒRÅZç8TŸö€6KºÁ·ÒlgK(;³…éÿ1ÀàðT¾`š7ÓÔ„SG¤±eõnØÛï¬ãÈ øsÏCÜôøÇ&oy;;5Uaó—\éÄBL~ý*"§‚‰”7:)IBæŒM,|Àçü6Œ:H�‰É$¾d*öf1¿ë'¸–CÔÜ.‰iEgÙ»~{X;ú·xRþÞ&A§>ßB¥íî8ú½y÷‘ØO'Ó×5—öÐÅ�œÀ!œŽM¡GcÞ²yÊjÜo÷t”Ñ'1>†+xÙM§ÎÔ‘—¥"8üd¥³}‘;I¡ÃŸŸ?°þ3òÁ1ð÷ÖK>mà15×­À9}•|8¼@õ¯dÜG†'ƒØƒ„Pä7+ã�ýÈ5ìÇ'>Xö%B¯q»ð©Ó7'RJfþc0Õ´Qh¿)åõwã¾\}”öðŸî¯¦¨JyÒ56gM:eìÃÔã\›Ç1x|‰¼ÀÉ­øºf¾¯^I®¯w‘Î~Ô¨Úq¬L²œMãÏ:ê2YcåA¬íô$í¹øWG†Zðš»ü)zF-¥zf’_ Z¶ð?1öFµì°¤©Ô[ÀùÁ}T¤²„úga«ßç�ú›/Lò·®¯È^›ª¢Xýt³Þ€z¯ØÜU‡iKT7 >Ý¥¹�ؾ*ïkOeæ\ ë6¢@ã7ôÌ=ˆ_Õ”…W²r·¹x»àeœˆÂ¯ÛÃiâ€"º�>LëãI:øè¤&‡aî´ip®P¾ ç<‰kF[|q·ÚgçÃç$f"u†þ¢™ñ8Eˆ‹� l¹*IŠÿà"IÓ眣ú¦‘T§3…,ÿ½fNLÂ�ýì×éSdÙßzÇü¨a©)=ÚæŠîé{„ZS�…Ye%¸µÀöÌñìÕ„“lç§D^ÎZÖœƒu+ûù �l �NÃêxØ$ãÃF§§²½Ž,VvŒÄl³ƒ¨4VƒéÉï§fËT¯Gz_f÷ýb zPc– o2’°®r7ò[MðÃâvø›eƒ�þÜáYvìÏ3+êh²`ù&�æ÷RÍ>sòK‰&ãÖ•$¬Qe5¾é`ºGŽÒj/°akß±Ö?Z¸¿IYx­Þœt؃ù<{ûˆ _ô�mâgþÀ¯wyØö¥La]ë¯rÆøÍX¥C—*(á†:>Ñ{ÌðßX\*Ô!ã¼fr[bK9w`ôÆ;ô°kÙ¹‚ß]Y²ö²#·Á#$ØPK®)•ôï—T|n‡}gÙ»µBx”§=¤ÞNõ#S˜p�/ ‹åþ›)Ew–Fá± O|I\º7˜œÀ+Ä-‹ž~ç*µ÷ j=Ç1óþ)¼Wðºäò‡{å0Ô�n0í4 ¼Øn‹:³L©hC›â °æMNŸRé“z]ó¹�Š×'á[yeÌ2ž'|˜w•%Í⾉¦Ä�ÍMEµæ.v”WÆ7Ñ+YÜ®Q0gj3ŸP¼E~…²u(¿ö:í¼�Êód©úÅyØjâŽ/;jô­‡îûI¬ÁGugàôSVü¹@º¾ä4ÙïÔ¢Jmðz�¿‡4¾�? ; Ÿ3¡Û=.ëb.Ëв%M1SºGxêŸ&]±©F¶¦zåNÁôöZ.º\žÇšÑöeSøœ÷‡  Ê•þ ®f¦»jYÀ€À;õaئ?ìF¶ÒþküÅ´1¿—Æž‰Â3™©ÔýV»Ç3OùkLiM 6ÏíÂSQ”Ö¢‡û¬ám_M22.lï"mŠh‡WÆ`§Þx<󧎯ÒÓgnÙ�wM)‹×Ð¥øw’tÔ*‰ ÅÔ(lW +Xñtõì‘Û7õR;AÚOž®Z§3‡ðe4&)�vcÛ¥ÖSMËS® –ç"죶B z¿czŠ¥±Vù�_!JIëU¹™f»q²yè·Ž¤'•ÉÌÃö5]1ŸYŸ˜Jï-ðÒKœê9‘;¶u5û-÷œù5Ãèùæ´f]Ãl{b„»Ú˜¿ÐÏk†þsb°–²eï<ðS¸•° ħkÍ¢¬;èëíœÆ‰“\éÈû�téGÅÆpè¹Þ’?ð$™N{MåÎ7¤Zç /ÒÊÏ–ëeU_ÐäUS�ÒnZ¹™ínû~Ó£v£:”Ál­¯ò{^‹“•ôU.ß=%ÚK˜QÏÐûV@…½iøDC;?~fv;×à‰ÿQtf=½Mí‹�H!’ü%kõ;3EÊ–„„Šl²E!"í©TZ´(…’¢…:3)Y*{¢Ù I¶„èõ^=wçbž™ù~>7ç±Cã=Û`ΈN^w¾‡{=�¢=‘’ÞPÍmÕ~×ot©Sô!¾ÛgJÉ$Ÿz(•#,xà’Kÿõs9y‡â°S·xÀ´T¯þWÖÂù.R|Ó´Jôóùwÿz¹cj?zB%–Ñç¹/‘¤uÁ}d*&+É£r³…õ wóçCÃ]™Ò'ï«Qç÷sœ›Î2s•x…e7Ì|†›ð¤¤ÒM‰Ä|£ÍËÚ©Ð\žçÏâñU¼³í*ï”âG�Kø÷èIh[C—�Áå·B)/m2M9OâÇ<ôÊ=ŽO‡ä‹nrcùPÚ=Jý¸ B² µÏ Áxh …/ß(n³Ø€æ ‹Ñm¬}_ŠrNó±ú² tÚ ×ã:ï»’z û7Jùµ—'Ÿ0ÐÄ ³Gp®·qieŒƒ˜$=�‚ó˽8m§#Ü[r�‹FŠ�Î硽ÇÀÒ¤‘yËÙZAQ6^Ø ™ˆín�Å·2rè 4L!«±1°^­—åê¡ZÞ8ó7,ÙÃIK4‹øÏÜúìeÜýb.Ÿü{å‹âØ(0P¨Ü‡èiÉUÚù’Ÿ£ƒùïø,Ž™�A*ÃX£E� å6á\éÞ ñM\c5øºªJ;†a–Û=œÓ¥ƒkNQZ?ì;´_i‚{ÆV­Á"Õ;8ÒªM¸-£ûé /fXó›¯ÖP½ZOп’ïEq���Ôðõ6¸u)˜j� u«ÀûX./Líμ׽?æ©¡é’Hþì*Eš1£ øó|þçvIÂëåX²k Hɤ’Æ'Y~ê“ Ó'žàU]Íö5*Ñ5XsÈÏm»‚õ×½ØgØ~\¦·žGÝF¹¿V¼lª=ŽM«¢-o²!W­7/}©Ç~ûUñ®pš�JÆI«^pñËB1ÍÇ…Ý^N@c!ƒ‚´µÑÅÍ€öÔz@‰ý$\ãà‚¡wx�íWRú—å­e�¼Úp%+TŒç¶�}KýØ‚·kòºgx}Æþk ˜ó¨’¥Ï ¥·³SÑ_w®YbþC‘ñ§Û§‚ÑãD6ÞÜï‡íŽ Q9ñpUñÁ±Šó~mСx€¾Ö?Dé÷ ¤ç]̲ òX_¸Ã7ÓÓ©ïØ:(²NêEhþ~ï aŠCh–â*a@ï\J©n¾éõ¶WnÄ¥ŠGœ£]�RÜ\òž\´œQêâSúà ½G|¥òÝ; /§÷ •à~L±S¥{½#8ãaÐÛu¸ar?ñÍ3MÜ<Ý}ZF¡rVF´ÝÓ8ÎÔðç;g$œ³ï6»ŒÒ2�lŠ=]|ð�uz×°ÅÌawî¹ó?�P&´ÖìnÕÀW—Þìée © tã÷ ÊP ÁuÃâ8eE�ذ¿/.ëüCY}m8e­<öˆôÁQÝq{³?¾:ªÎiß³¹W’ü¬úMÝÊÐјA³sŽà<ƒ…|A½ØlÙìj«OŽ¡[@²Ò›n7™qù_M Ñ�Æ|ìƒûzÀäÌx¶Éº"zGÜÏ}ýyƒ•1†™´€Î�Rd]ºíxrgŒG�o‡ñœE‹¨;ÅíU­øè™"(û£VÎy¶Ÿp†Ú¶äáÞbûM)öø·[f(ÿ¤ÓŽÞh{x.«Ãòðk«86Óÿõ÷'ᥳ{Ѫ@žo ê‡a“÷@¯Š«pF/föÑB·åÍKœ8sK"‡H)М£@|\óUŽgíõÇ�Ê�¸¨t,n™ý˜ô‡£Æ9˜îÝî©AÑ•2¢ ©ÒK—uÌu¸kN6EuYqÙ«8²”¿ÌwO/Åf&œqBx¹ã-]º^ÀþI£8Éd(wuE—‰òw3��½:IN£}ñÂ:Uü(y i†ï/àõÍÜV;ˆ‹‡K™Ý€Þ~‡Ióæ.<]ç§©ÓƋȇ,³ÅåÅ÷ .J¦ÄÓmH{(dó~g^[1%Îß°[&ž)’نɠ=h ¦cÓªã‚Û#/>z³?nš¥í?â›cTC#ÐÊì?Ðìç{%1ر¶·ù—žðjåo³�Õ18v~:ÙÒ$ñÝʯPe¼»8Òç”É£rÿÁ³ãQ8a‰?zÞ¤¾ûsRÌ'áÚ¶³´}ŒH†—µñ¢iʯ°âM|4U‡“öûõ,§{Š;�ßÒáÊ ’¸áëÿÕ¡¦Q æZ…àÃROa�[6êÕb˜D„ÞÅ~hº-½ƒøâëýpêD/¾™oB;²H¨®8ÍÏöÇ ÍÍd¼Q>�Ë.â¶�ôOçÄŒ ˜!ڲ߻ûŸ k?+‡ÉÁ©Âƒj 7_¶€pËÂe•G¼|_»èû~-Í۫óòùýøéÜYwŽk½Ãê=â€Î)ôÿ8-¤'صxŽ`Á[[z‹#ü'°EÕJ´«,@˜Ç Ý(tuœ¸[~|~%CggÌÁ}¦¼bºÎ.iäC{ÎÀùºàÖY·+¿â›¤éïNC}cVŠ ÆÛSÝÁ"°ËSÛ|Õí]0ûãrÜ#q¹Tf¯„¦KÓ »3žCÔzÐöG× Ã# Oøß‡�1aøh{Î<¿†T†éÃn�’ÄðͰ¶­’³Lv¢‹Ç(všrïxðTy´T®àŠ¿é¸é:.ÜmÌ•¯Öð“…gù|­3ªVôç7û¯à¤óéÔòë 6jj�Ff%eÞL¢äÈ<¼Ó'sC×%8óóp^_ûÇûËÑê¤PÛ¢Wâ¹5•w_˜ËnU'J滯cç#øió*¶: ß ¿ÔâɺndëÐ�Ã÷dÉc9N&•¯ùF�QHÈ^<Ê=G8òÉgRØ|×n¹1ò·Ðœ¥ÀÎ4‰[¼�Äo…é”’ÌÏŽXã(Å0üÞ‹qgõ>pÞ”^_MÇ~Ðáíã!xüvQÁºˆ-z c;ç9ü‚p�’.þ”KI ¦¨¾°/æ¾Ëõ'Æ�m¯tð˜t’Xû³—Öuz±ö$ƒÍv+ð%�s^ÃõVÉœ|l*h˜Nòz¥ãâÉ)tõäJ†1íò ò•xµ‚6-RÓÆ¯ïã1N3œÄ»oÈ1µ‹ `#~êw† eTý’#ÞÊ/Ƶy °jü/ÖÍ"q–ZÊOh¢ö/5BÝx~zÀåó^ yÑ+¡ix'ôr†¤?z!­HS†Ð�¾Ü+¥ˆÿÞóÁù×J¢ŸÜ�ì·ñÛ�} Yž�ļÎTüN·æH/-îˉ=l¦Ó¯ÿŽ‚|ÝbñÁwkfG7»ê*¥Žß$ê>VÃgãƒØÊá0ú¶æˆÞ¶²<¥;N}³Ãí1¨=I—n¿BŽ+Õ¹õôiøl$˜OÜH³þõmåy >¨S&.Ý*ÃÏ÷;‘œL%[_7ã¶aßpÆU)ljQâ°M—¨sÍ[º�MCoñt‡íâËkÐûÝSàs<£S9W*Ž÷GgÓåXÊ?ˆp2Žf?·Å-µýÄ~fV8*ošä .ýÝZÌ’_u˜§�ŒÁIs°v×H6ë�E±÷9K”OÒå{^ã9cŠ î’;€Ý–‰8ý¶“¯ßf£…ËððÅ:QþX0ïn�ä›oöÀ(˺³ºÒµKËæ§@¬ÿm qI潟%:®¡dŸ¼�Pì>kuÓÉǧ/MJd³4]óóÑÐ+5ŒËœg—.u©Ãw7Xc`MÒ?‹7ûDskª{7§cîi%óŸ×> µû0ó}Œàwž¡OW8Ö$'â®Éç`Ì _z`ÜfÞ=ñÃ� èºi�;5›£½žpCg2ÞŸv‡þPl[·Hœx—?¨Ìa)'î;gKÐÇÍþˆ3+(îëH «�BÍ¢ûpy€\97’ƒ5÷ШäcTej+$yÊš,aµôýf·“ö‚™‡[m�C»#8åúT¼y�ÛÞRìټM½»&‰9\ý¸¿ 1â/oþHJöNÁ{"ø·ƒ„¶/8Ä6WM¨¥ûEeö<‘ÈIß‚øøÖ`TévE·Mž¨m8°Y[´Ô{M~žÏáD{2�úàŒ3cÑô“†ðˆç$ÒGŸ‰’´J�ß™ˆŸ3#¨~‹,^ùxŒ~«€>‹§Shš½^R‰Wï®aKOWˆv¼C‡?/•l�§wšC1jM¬ùhA±º«…ËzÂøðVÈîÑÆ f±¥Çij™æƒýªKŽ>„çkÔ%KñZ Mø»õ ®Ì…3í°ü—>±þ½�¤'&N‚ŽBï[aÈy{¦ÁÖéxâÞ·ª‚†ÍÿHìŒEÓ(â“Õ´ÿ%åYÑ‚ÉÛ3T—��£æØ–¬|,æÙÏK¼DÂì¡'�„%ÜA²uc5ݶH§ˆ#ˆ~׆€©ëm ·ƒ¿Ó¯‚œV8�Â&¸•�ÀOb¥ù銗Pë¥P5Î}Èì\(é›oáÌõ”™u�ôkÞ@F�`ÓûKš—–ã»ÖÇ ËêHñÈaJØž)H”Ï£†~8øfLF•Âú5ù½˜:p*g^Aîw&†í›@Y›Ê(²Q_ž½î‹‚iÕ‚)˜bZ ´fœ8!‘h—¹©MîvvôÎQ©ôØ�~'ç„.ê=ù^x­Þ`‚‹uxRG6/»MOž?á¡ñO!éYºÛ4ˆw´NÇÕÓ.À¶_»Y< RC2 ÞºL|ðÐ —H%ãÊ –¨õx÷öíË1‰W…öÍfø´cËF”½}È•VóyåÀØ»Ç:憡§ª?Ûô%_¹õ¸Ãðõx¿¤Ò�‹Q]ªh Ü‡_ì�ÅÉÓ²(ýâhloq‡•×MðpŠ=1ÑEÅú=¢ÿr¸ej€}ãa¡“?ñRÚV�W|±¸qIñ|Í$1½W>Úýã�þ愯ˆƒÊî`̤ ³Pb1/+'›åoqfíe±¨\à¾^MP«$v%Lesy‘·.ŒÄ ÒÙ�Ѹ²ìkNæw¥z\³ù*Ï\ž‰Ü”ÎëLqsÚ>`0’�ô�Ϧ} I†Z´¶.WTÛÉ¿lfbYÅÉžæOPQÞJªu°ªDàgKÌA½ø"¹ï³`ý»Y<-ÿ­wìCƒðÇjì¤.yªÌßSÜY.ÖÝý7#N¿xxŠ÷›•Ž+6X³çƼ±rfçèàþò˜{²x{]T4µDÝ¾é°Æ<·&pÎ5ihs!0Ýz�îx!8qg® ;õK¥�ö>¸ÒÚ�g]DMàËû'›�¹‹3…õ®CøŽé9{I×ç à ßnàL¯"ÚQØ-coÀ¦f}Ê{’[sOŠñ“NQ M_2s�Àëí}IûV4Ýì}‹+‡8Òqã ¬¨öò‡TCpƒ �?N�9Ÿ Ï÷A³Íï…ßmÞܵh>¿PŒƒ_2Øôí KŸ‹E®É�¤ßÕ•siZe=^~Yà,ðõÙ +ºac¯PNÝ:Š#CqÄ¢|*Ô-€ú+^°wF…¿Ëoî?$�Ç£S OÿÄ�ÊD©°ÈÌîÈPN:öv&ă»ûMÁÎ?™Ïæ“k[3·\ÀB¯šó©òŠ.ýh”aÿæ_ 5ùØv,‚f+¡Æ$Œf¬ç[7“ƒ…´Ümt4À„?’BŸÐ pŠReWÏð/< y«ÆóV£@>?å0¨˜:Á®OÙdYIoì.s C8<½Y�gŽý §)|ÇÊ…ë\ËéÈÏy¬»¹ãÅhqn×YÎéw{Ì7à‰A¥øä°6„gÂ’;yðY¶ Æ~×fÙ†U¤qc=¼þ—ÓA6‡ »í ¥L‡Ùûæ°•…)» svÏÆæÎMxXrJìSK½Õ–±½ö9Òú»ØB+6AésüûÊ’œ®ýóÄ>Øý7ˆ……£¾ÊoŠ¿´�û޼K†“‚ð“4°ÞÁÁ<Ä4I�Ž»�†ˆvÏPkq2YZ¹cøÝ#Ô±¯:þ¥~›b¡[NÞœ’Í"Pi^Œd}|øŽ-¿™QObéÔ¯8~ã+ŒÜ“9# ^§¹A–—Ÿ½Ù‹n£KÁèÜEž¸«‚ ÒÏ@èÆ{°;Ä�s[Å+3¡±&ŒWXjQ÷[©ÒïF‘|/WŽC¤¯�}÷eôlƒç# p‡ÿ0¾~3^¬ŽÚÆŽuC¸ÉxµÏPätÅhröBkv(àì¶$è0Jtu§”Ý0Wý«ÏŸYÁTüº…:uVsûêIB“â,Ø"1@!°·ð´4�—X/ÇÂmÈWÔò©)ižÛü›önb£AInµ Ãwü*9’­ÅŽÝÍ0ó“2 Ìj†Yi,$E)¬ [÷N£?2þqÁq˜šÄé'@ß³0Nm6ËೕÅXQ5}¦ŒÂºÏS±·$W$å-[‡Ãœ�Õ%… á|Ð(l0ž\¿ˆv=#©ÓÌ—($3ÆÀ„‡ôáµ5Ì5òCѧ–°ÏÌtŽÀœ(Kˆ6}:nÁîÌù°ù‚2T;d‚vc¬è•9^¸èÜN#Ý_Š'-ú¡ýv-x©—À—~Ì‚rW©Ãx(6—ã%G5Ðí—{7^§dÿPž¹ù”�òºÄ代øG_žo>§û¹‹½fXã�ïÊx7¸I\wù=%�·bLÃ3ÿÙIB&ôÂC­bG–7];Ï=àlÊ4˜bs”Ï¿*¤µÕÎbÚ½ZÈ]ð bþÆgË�!J=’Z`°¹øÌr׎°c÷a0O5™ <>#*Lã¶¼òM Åߘ³ƒ�<^ò¢¤X~Û%Íå¦å”ã¤@7 öpÏ�kY_aÖwH“åî+¤™°69uÁñÓ'@*D 7 „~M}ùzrâkày0yW/a]�,„‡%b`æsšˆ+áè?WÚ6{vx%лÈD\°kFÕä nïÓIïñ \ý;–·MãÊ–-heµ”»ºðÍIâã¬êO¯wœv­ÿ Ÿb™rÏL@�äѲ:Ûæ ç²j%ñËïT(ݘÖ?‰­�×â¾é3ùî*ž;Ö�{?»y퓨ßÒç‚íšmøÓ0™dÎ à›^¼éf9Õl‹4jðL·ÁXÐåƒ-váûÅúÜ6½T/¨ —{ñH‹·¤c¼’”÷“†¡è¯Äž©{à¨î 1X; ½ô^…Ÿ­Ë£Ž>Åsðtìn<3'šS ¤Ùl0â@îBX¹#Ä_Êdåsø¿­Ò|wm òÏ—à—Á`+¾€YûưN²7DßëÉ%å7a�ÜN´ï4{2è7\JÜ»&Ó¶¨|c©>¹ÿ�¼-¾Ã§µ¹ðWó tFY@\r òºUè¢2‘£G{áÖÚxüø6”†ŽM¡>'h›õQªª;€-!ƒðyý]rZ~û½XÈæ›sAe‰î~]"œRþ^çƒKü_Ø�›î5Q<}‡?Ë…¹ÿ-àqí®�ì'èöºL›KðµxŽ='þ$§P[ªšv’¿�ã÷Ù—ùÇÞ!5.’L6‰ÎWšh«Œ7Ä@Þõµ ÆÙð”æC‚÷ï™4rx6õNã)NÇñØ %Ìuç(½_Ô+zÎ cYvîlñýì‡ÐÚÛO8+œ_3‚$µI¸Qâ,Ä Pà�FÙ�t68-ƒ‘ËuaØmZñ]šÛîînÔŽ`7Ÿõ´{^ m÷4¤½!ÿüõq9˜ªa„ÄŸÊnG³_Óþôµ/?¯¼ÃûkF•k[ÉìV¾û­Í6â8#L<™¥Ä¾<÷Å~0¦�ÿ¿o@´ÐÈ{ÆÀ±W`„�+ÙP·²w)Œ¹Ù·¿IÁ®…WA¥N†£»ÃýÔdd~˜ßì á›ã~&Ç=M8ëQ˜h8GN¸'‰2,Zá©©ßüX›Õ_ˆ·Žô(=•Y.îí胃ÛLøE¶4­»}Šey“îS*ݾ–ÉÓôŠ8øctà·úÒ¬Ý#ð¬Á`j·QPÙñGBm…¢–”ô5CÈç‡:õspoÓ=šàxV\;ì ‡ÈÝI0óïc:Û¥�yƒ†Sº�;žùö�lë�ؿЪÌ|µÇ‡ïî�ëÓ it_5V1œÁª.¡˜òãÛÜq‚�Þ ðwŸFÝ? 1ë¤D1á_}OÍÁ.ÃYæb(í–wá[[´!<%ž+Ÿ¯áü¡“ÈtÒ\įêlª§ÅÃûÿÛÙíº<μ'–è¤Ñî¿ãáX¡3®†K0yh0OÞ釳ªGàÏ`AXØáÚ7ÕpÕ¢5´6êY>¨þÜþú;Ÿ“ó¨!ØoÝ1xYØH¯��ƒ¯ Ñaj£ÄÂj/4÷×ä>mK @U ïx&°Cök°»«Ã÷þ‘Nïþ|kD8oKÓç}ç9ö7Äø÷À³¼ñ`Â+ÁaÈzg*Èk÷g¹)¾÷¤Ø«\¢–ºíüRpÆu½*àï¶Õ8ù &Ä*£BÊMž5¨Sþ‹¶úÍÀ¨quâÍ7ˆSÌv¡óã�—~~´Ã„Mé�RHW¾¦cææÞ–”K ô¡o“d¯oà—O×`@5‚²™ºy®Ò|¾d6.®§ÂÇz8älOÞ�G/oV’AY–92’çË£Ñ9dºÏ ÷tŽ„‘;º)åU:ïÌ®¡žÿvÚñFW^œ©BK“ϱe{à—c HšEI|Ïíd Vêüòê ÕZ+Ìés�‚sþ“œ(\Gí?†Ãìu !Ù¨n³±ÃnýDy­Ãd[ ‚UÏU÷C•�ðr¯"^Ú÷ öG/ƒ�í¥�l– LÓÉán-øŽ·¢n­�¼~á±Jó0„%*ó»Aö8¯Õ’› l9­ÿ>¬³ö¦å^ý±+,�NnŒc£]yîà鬫¥…‘¦áxä\=-’^ƒR6 øßXöüïn‘‰ÝTlKWâÊ®8D³žüÎàU²á`5OY(7Ž}Æ¥73¾�Oƒ4_|6“TNÒÜÐ{ì½KFˆ(6ç%Ç^sRTÇÜX‰ŠTè¸aoZ\K‰E,¾oßÉ'Ž\‡p4DêÓS—C…ï"VއÇî;˜{öƒþ�uâ9ÇiÜïñTªi†m—'óÏöPn{xÔôà¤g¹ôòô1’‘Ë#Qf?z®4䟳ÜhF°¶yí¢”¾*x¾¢Öéý¦”ê¿ï8ÝØ®ÏëËC8ªA®¶qW"x�û%<—ÎÊ?_�Ô@_¸ºä:[>‡ls%î}9’ ÝB(#׫ü?Ó=y³çÑ™¶°vì*PÕIýJ³ÖÆBº�vV´wqÕ’;fíDýóJxê\=žéÜ�šG«X1«åzýë­N =õú°ýæ6¦ãäv†èôi(õ|O¿Ç¯á¿N‘ï®Á|🠿ý’îG� “cÌ)4È{DÏåf¹pz¹5¸öÂ0ß(ˆwã’ï�úö¹Â¡ny8àßëµt|ßHlܤÊ%RÕ<¬_O<²~><fµçàït¶àP°Ø5LzÊàÎÌ è¡)÷Ïýó0-0…‡Û½§�﮵‚T{-*©ØòßÙi…Ýn'±qÈ?¶¿SïÎä­GÜa¢ÖQþ£†íϣѼ¾<âA�¸mK7Yø/Ãh>Í.-pÓj(þ YB !:¤úx4nYº†ê{­àäÇv”¥ð+¥DãÍ:4ꃯڶl¾Àe8Q %>‰T@÷÷Çp‘výuXË—ZMøÆÏ,fúÞ¦ÚbÞØ| g÷:5Æ?Àß×�?,|ôÏeÿWÞ^êÀ­ÛTpDÐAz;<œF=†rfn Z¶‰F'‚ÉÆ|µ¹�¥‹âXžyÐ�›*7ñSHØ_MAm-âŠ'¥bic´ä¢ÚŠ[�§°ýqSÜ¥éË_ ®ã»ºnصl'>qâØ©ý1xçh» þùTJ“Xsxoì0Kcž^±‚úø†áïîù0½f °¯|(ïq‡Nú‚ëÍS£ö�^¼EÑ÷aÉðÓ<>T‰O:¥K’\c8öíiÎþá [­¶P�|0K˵У~±¹d7Môûër'ÓéiÞÂç˜)œ5,�´bßò¡ÕH_ÖE ÛJö£éúoØ×ÊUÖIžle\ênGe³�¢çÑs%÷?�g׊fÚœáµÁ<²ìÿ5„+?g•–Ƕ׀3…SXN$-�z˜=Ç_¤mÚAØ:ØœÿÞÉ..S¡vÅ I跗Јô‡I™µRàWš�˜ÖÓ¿n÷Äù6¬8u|\‘“×Ia޳5 �¨‚Iºö|½o9½2yEs7Êâ}÷Œ8ËØ}uL·;ÊëgÞ¦ÔA¼}±, — ãi½ ÅœÌ A~� †gá··P«‘Gc}ßÒ;]-îøáÍ1÷ó…À‘êüæõ|‡aø÷ª ÎK €V£W¸èòeÚ½* äÎüWu»b®S+­H„Sï,iÜõ„â)GÌšªìù[Ín?z�úß?§ôgq“�¯xâ°®“ôÅõ†:bSNã^Áì¿Y¼ó­±¨ó2†zç—2é¹vL¾æK«“e´9o}5�CÕŠsêeÄåN pÃäT˜Ä1˜=@‹ã¶DbÁm\ØØócYc·5¯z£GŸd¢·{“¨ÚäË—�ÏÀÕ-ÉâÇ5*¼è‹ Ô¼ó¥ÿLü±~­*U�ö£¨/wháÖü[O›oΜÏõj8Êe(Æ]2Á½ mù°ÃDñóÒð¥ù.� ‚ŠÞ4ùÔ`ü²Âœâúݳ®ý‡ºº “·4œÚÞ._;È­c^¡æ”2¡Ô:‘Þýê‰Ò{�%>ÏTyRÉI 6ÿ×ï±z0=èÅëGÊ…’W®Œ0 7�È §Ï͹«§ ËUËÀØz9Üöx =Ë|M$kÄ·ÆÀÄÙJxlòo¡_ú¶¶KƒoÄ¿~½†„›YþßÎZ#u”[ME*Ù´ˆ·üËÅóÑTðD·8³ÅÇ”�ü�C/ª¢¡Û9ŽnH…MŠ£Yzèb’™îÃaÏ©½ôÇØ—FéÉbÙ÷¾xÁt<’åZïÉôÉ<K3!óñ0ËqÀoiÝ0aß]Št‘ÇÏð��T`ÖÒ^‚ªç`þ”2lý¬1~fíŒ.b“7ų]F¸>á)NŒ2ä^%±¡Õ ê¦À›(\âœÀš#Ó)cLԽ؈&÷àŒF!7u– 'åï £åïS´~;hU¬æìñóyå¡8œqÝ š/¦ÖM£Ø\ÊåÂ^’cïYX{Š^)¬ÆÕ^–d¶a"t<Ÿ"DŽÐG»ßëø’^­�zŸßU�Ïí\¬�ÈCnÏæð®zäiÞ¡Åþ.]®ÚDç$‹!ýÈ)Šz:‘kô^�Ÿœß—xr}â!øä÷ UMRIOå)ŒÌ–ç·±­Í^ Û9ŒC_)@Ë×jɤ°v¶ÕSÀ}¶²ÙÕŸ”Q?™öm Å�æ yDõv\±1”¾œhãîd¾1æ Ÿž5�KÞ,)ñŽPãö^˜œô’ÂsUõ6šíÏ#{'ÀUéyúÿÒ´ãeÔ[mçܶ¡›1úæÝ5uðûi"«ÀNÔ8Êû«ë©Å+�_Nïè…=Ñé¹/í¬Ÿ…—ݯˆ¿Vë2i%qQî<'†s^ÔaÎѤV·ˆ§ÍK�'jaèã²».‘vIJ“a4V±Nž§EO»¯ÖŠJzÑT6#k‡âö)°â`]—ÞãxA8Ø>n̆KäíD­…šø.`ý^Þƒ“£ó0uý&ØáîŠ!c±¸ö?š6ê�ã³hýí)üœt $õQ´þ<®óZF飣u´¶Ìæm;²Åüç{1`êmR½Ø—ÓÖ¼„õZWÐcb$ït¼!.z{ª;¨Àè#[ŒKÉWºJ³Ï¬.êL„¸O!°©ù")¾ë-(?�CcŧŒÇ@ƒÔ ”}˜/Ö–ƒšáêžØ£tú�ˆ»œ„òÙ²æËÞ|¢‰®x(c(¶€�’|¡Íu›DÅc¾_>o f7_=l¿ç„Ǿ=Âäéè<<–órP±J77e~&óÓ‹…ô'/׿ìË2ÊÐt¬ ŒÂ£`HÔn�«&Õ™×à…åØ;1GìÛÏ _*À©uã ÎÆ ýßÑ-�`žq¬ž©=B÷‡°íΩlüÔ†6^÷æsÞA?%_R–ù›-ƒðÛ:¶šȃ{ § ô…Öî«‚›At)9¥= ŸOµ,÷ç5¶­ýMëý–ò ÿI¥ç⪻„ðbÛ.™('™9·Ï:]Mä¦�›�窹 “ÝèÃòõðl眸÷¦Ö¤kPZÓZÚ¿ê /N%j8mÊg—W€×µ~x|ÓÚjÀt·ù ®ìH—ì±(þƒSFÍâY“¼KR?iÁÙl’ï�Æûï�@–Z$6¯æÞÁÛysq�?a‡A+…‘ÇéNx®`eQG±G@}ÛìåeËó÷¸É—þÒúýnä +dqJ�<^=ôN û(êM0ÀK�AoÞLš×~Y4Töä«WÙ£z&N:·¯_¿ŒÝ}b„¤+›ðEìH:óp_ö¬u> +d>ƒeóþv°&„‘”Uš w£]ý 8o+Éc—î!jV`˜÷t¸›±o¾}SÒõg>’ a5#èxé´â×å¶8ôÁ˜°é(5jù ëÅí4°à8<}õ@X ,-J.nE‹{Ž(cØOò¼Ø É:²ù¢shóµZp�¢G†�Cea khއ�=9}ÇGøoïZ*|YLïÏdàF?p××mkຶï´jv2oËG“þÙ� 1qçY>ngîQÔ7†©.c°,Ç€: Ñ,¤7&hêð>å\–Õƒ=W¤Çs¶ñC�ÂoLùZ)˜ÊŠõò¸eû-ØÛ¯�$æ”ò݉[¢'q„ÇK’ßsI|±f!\#ÏêHS¸ª*´}”¿äÚÈéønðÿ(.¯ß& ·k‘D…)*J›BõÎ(цDY‘P²/…¥RZTÚU¢B¡¨õÎÊBö,!kÈOÙåëûžsæ//Ô¬ÅE]S1ùH--Ü4ÅS1úÕ \îŒAñMäù"�Këèªï2¬›½” ÿÐ)÷øš e6(ø6?,,«ûÀ“_?(>,Ä>Œ!³¨,vMÞn}½\Š Ç·ãŸ«[PfÀV¼ù¹~|/�½spÏá(ÜeÀ§“‹¹c–çè~¨qÝ–J¡½šsmCG f³eö0÷².wÿ»I)>{pñ O$“c…GõCq¥ÜAêXRckmS�Ëîfâº*MŽ›$l¹0oUì!sÇh"¤á{òD™æ-0É2& 8…7³Eß?6çVì¦]�Š|ë¥6nSéañÙY¸%Í�å—¾jÒ-8þ_›¸Ÿ°òMM¸Tr€Oùî�r³×°â°1½ééñÊiòx¹¢‚²=w@ŽìAÕh{­\A�þ-,8*ãÐ;ÑB£¶ØYƒ“Ít9î»=ï»ÄtȦKüy£‚níÄ2ω@OJilR"¸?ŸéLÞ5Sùʼ{$-=‰%�?ÊÇ]ŠÇáØ'Úq1 ´ûäÒ©‡ÂöÏ+ñÆEÎ|ö LÎNƒ7:­P­nwQyÅj%Ðÿ(îŠ;/Åè³cìE!¦cÆü»ÞÓ�ö‚Éä!´}ì6Ú/%¹¯‰wvžäÏocѶm«¬oßî&«ÙÚE'~vûáEãë°oñbžðòœ<Ù R¦¥™GÒÅù+Ÿ²õ̱6O¤šJ°qÒDv¶ô¥G§ «Ÿ¯ñ®ŸˆOuõ¹sÜ~¼ü2–ÒGU ÇËéxû–,æ(ªb`~ª0ðù||Q—Ëžæñï%Ê êÃ% _IÁl±;å¢(¦ù*,Ù yޝû?½¹Ô&‚§û„ ÛnàFá¼ñÑ'j·éñ•�ŶZçÆr懴۬VÖo,%ÖñÁ–t?N#eçŠÉšÈhâÊû‡mÀ†kçA®‡ó5dFSí¹žü³è:àsõÚl9NÐËŒßöø²Æ¶:ZÄs-�ðxÊ ›ÿB¬ÿrœ¿{9·vÅaã´“¼]èCæõÆ}º&<í}�Í£áM5‰]1P\×—ŠP-aÝ÷ $¯õÁû¿~†Ëøpa:[›ž[Nú>›ÇyÚùBmf.þ>Ú(¦{âñÙƒøðùnÛUÈ’º}PêQI·Š“›ÏÁ×9�è=`9 ú .œ6}MLZÆŽk–R}• nØõAðUŽÅ»Ìíe‡­28å¸4ž�ßÇçöIpcðn2RÌÙù÷(láqrhèqþ™jàÓ—kÝÙgP&™¿nƒ÷Ç]¸P2úWÚ]y“’<äÙñe«VäÂòɪÜ}qÞçÚö›ŽV3³hQÁE´e6†(”CïÔë ïGÖ¡•C�ÈMF˜î¸L“üð’Ïòm–Á’nx1½¯0Ó² ú¯ÌÄAª{Р­–‚9ÙîévÃW�¸oÿh<7Ë}G8â íö`ö1�ïÆÆÁ±w}PY_еgÎA« šlíÎv¡Å ìr¥—£ÕÆ‘øáE -z±—c&§ 7^ûBçšA,eQÅ׎¯àÿ,zf|£ËKÛ½xq‘¸==�5I¥ðþ]Žùaf[àž�}ª¿Ùš¥ŸÕõfbÉ“|ÃÐýч¬‚)X ±…ŒÒÄ ´®+µåª.e<Ÿ÷NeL$óiÞò û?–å1}Õy˜#c³Q,ÛºU¬‘.“Áz=>·SP3µþË ‘eœmp‚£š† ¦}ÅêM’'ä©×µy´ú€ožosÍ¢’n ¿jÛü2 þýFyÕxäŒ"Ýw¼SB øbìBüðh¶Îí3‡.ãDƒXP–/¨æµ�ˈv9@§=Y‡�ß­ÁfÙnú$�ÝE¸h¼Íþ>r�VêšÓ¬[wÈê˜,ÃôTâ?¡þÕñ 8ÎÛžúüNª Œ–‚Ö5ãý"ž/BOƒaÐö înx ¯úaËêo´x©:¾ýv€Ædoú1ÿ±E�ç1¢‹f$»ñ¿¯¿ÄÀÑù.�.tV²oˆî‹õ¥¹ö‹4~ŠbóBš-™‰ðg8¿‘÷!ݸWzSÿé ù�-â®uάT˜ õiƒÄ·iëiAÔ¸:�áÁ ª¢GP>U´€·äÙ/ý%ä+ fïŽVñÛA¸óG–µ´²sÅ6˜¿74£Û©`S ËXçÂìð£˜|:ž r)fHÞ/U¯®½öœzñÌíñïI£¨J׼ƪózGz^ôJè;$³&1juYTCqô q¦Æp xy¶h•ÓÞ·!d#aY–WE-+ÑúÄ5<ón g¹õÁe ‰§T&â‹Íÿ “ǼÆÖàvqˆö,¼0þ<9_ÑæEƒ40 ö6�Îb“M?X&y*òb‡¾5û¿~¦¶—üóC5Ú_É3~æ±YÃt4O´'(’%b-ác~*ؘÌ`�Sþ3L cÖAÁcK:�xRrÖá’ð^šcÍvň-_äPþ¥ KßÕ¯_ôÎYÆKóo€½úLZ¾ÚG-ˇðc÷„¢Íó…õVf•(‚KweÄb­t zn@’1żþêK¢Òùg„ ¶ë¤qw›‡µÏB¯[™Â铿œÄ-2E3…30ç¥?:<‹s�IEq#§Ù˜`ž�ëN!8¡Ÿ7¢¼ZÎÔ2 ìq⻄JÒö‰òxîj1}ècK¿Oà÷¯Ï¢d–/äy;Ó…oŽèÚ:Ãß®õ Gɨ8¶Ê!tå,ÆMaqz6ím�i úÐó ‹5c;gób \Zö¶†WÁ%=¿”Ãël}®OÚ�/´aFê¥Þ=Ã]‘³{º ÇÆ*’þ{)ÒyuLÎ#«×…´¿ïi|{3UŽíÞ–ü �³X"ƃ‡5�£´ÃѤ�åÇÓ¦½§«�“àJz“X®Y陫h­Æ0néšÇµ½ÀÛ†š%òy å0˜:RwÑóÏ4Q-Î{�u‚…ª+L×î¹ ·Èqw¹Èð»ñC9ÆÕˆ/Þó•ÆÃÚ'1x&οÿQGWý90öÁU8qú°P¡<w.×¢øz ~·÷[ôaóБô¹¹–zMIÄq¦Qõ´ d¦±LxÐPÃc²Ê(äñ±¥ Œ¹6±fÚVo¨‚æ·ã3){Í%qO«:ÞãŽþÅñTß[·mj‡¯·Osãå8Þ¶è0¾¸¨ƒ‰c=`’¼!ÛÙŽÞ³TÔ(#T<ŒÄ£õ ›��m‡m Nù ï8¦Î±5Ÿ`ãMy\\á¦Õ+ÚTöy¾ùæx\óæ�ÐÖ)ŸÙ4F�e›Ci|µÉF_)Äšýøû›¹ì6{½pén'Ï^œ8@­©S°Ãö&ïM–_æ /E Nþ™ã]Mù›ž2Ë.[„ŠÇé��k) gç‡�…ÓŠ{ÈÛ'íî܈Á„éÿ`ãËŽÖ�k;¾Þ 3Ÿ)¢óص|ïú¨ˆ-×,躣î6o¢àYrX=ç‡vúàÜëÙ|´Ÿ)+…«¢ú´ëÕ}5zað¢6Ú�WHWwëñ•…£a•Ó0~³¼…òöÿ'T™›“SÑ'á’Îg|·/˜ò=xhbO&!’¢±D¿�XK rÎ7Ò܇±t¯¥YüpzLKžeó'¬¬�à¡6ÑXÞäÀÏUïÑç·¡r‹5k8eq¢!˜Ò´?Ž·Ï�æ$»¬ ¦º= 3_”^y„Uã¨ÄbìZ¤�ïWš“Ô­Þ<|ê~›:gm-Æ÷¢±­ò³*�Xxu.KaÈöÞàz¡‡ÞBõ7(Dú?Ü vÿìË.?‡‰õˆÏÕÈB9],äJ×ÖVÚ¸_K` R@¿6'þ0rvk¿¢:±ˆm²D“·‘pðSCÍæÉGø’~¨(Í£Áu¬5êöÓî™É‰[�Ññ󣄃{5ÀrW-4¬º»ŠCùEMU ãðy�÷ÞÞ6þ’ä½@ZU•CÆgÕÄ~Ë_]¼�3в9gÃ$æþèÎ.fv?€%Fñ!Ü¡wö g/σ¶Ðé¯i×.”Š5+³yõ§Þ¬pi _K>ÀµŸRÒƒÕüã–·– m�œ×:š†�Ù#fªÛØ Ô]˜,ÔÙIA˜—ý|6�»íöƒßp –/Ýžõæ4¾;™ÚÑ1�Z^Sä&~òÞ'ä¬û@[T�xµI>kZ.¥ÖÚ™5aÅsÙ0#d[ôq†·,|ð¼#¾  HÕèžlVáA/_ ¼U™†˜¬;%Í"©ìÈY¼%§Gÿ²pÔ¥˜)7%ÔnÖhÖèÿ"HÜ´ÉMz8¼ß†8ìú<�'9(òAƒ˜©Ä.£êHÊΉwꦅf"Õ*„Y:º(a '.λMûÏâŒsî8³ì0{U(BeCÎÖ–šæJ`âï�8Új\Üú†kR;a·l'uOIÅðôR*Y´r¬Žrî•Tø°ú«h·×Y4¶<1K$0<)œL6ñÛOr(3o?¯ó9i[þéœpèn2k¹F w^GÀæSýñýÇØY~’”VõçÊ´ÑX™*AO¿{óþ 5<¼Ó¸ ÂÛÔŸäwc =±ÁÅ%OyŠý$Ú5e4¿tGlÓ/FÅW�<>�7Í„ÐE•ñ�–2 =cùª¿*©š�à¨ÕiB«…'¬žÞ&hÏÅåRl×ñSð s§G›îë®J²Öá¡|jq'E>º/¾˜`+Â÷8È$üö:<ÐoÖû‚u‰ÀÃæíý榊Þ'SÿQeðØÜÕÅ>,k6ú&ép·ä|Ü-nßžƒõ~‰”0ªƒJ¯ÉâăR¬yÄ -ÓÙÕó4�Òáq_wS™Õ:Á÷¥šcÁ±Øà=P&Ž|·˜³…áyjÞ7\5“gÕ÷ÃjM#^1Ç›]WÆÃ† ð9¬‹|íŽaé#YÞZ×)v†§ó>»UoüéÔ›Œ%¨ø˜·íÏTœ7à,ÇŒu§¦fwÁ<®›ŒÇ+sU© {¯†7ÚQž®ä ®"û$Ü;M?Uò…ÃPíÎb’ÿÓ¶ZÕ Öu©ñ|ÛM°w®ˆ÷©©«¯§›¤‡Ïr•ÐÑ¿ŒÒ£ç“ÔEÔ(‘š°#!ž.üy!ô <„OíúaëàŸ p4“þ½…Wò¸ãIÉü‹ìÙ7{ m�ßö8‘óÜtàÈD^® SŽÂý¥Ï¨±Ü—‹/="óø>4Ý`>Z4”›ìZá÷Űá„^Ž›Àk}.Â@ýd.z›BÎEƒ… #=z÷]Õ"R�Ù×û¯XÙÕÿvZË ‡šj Êð˜½A ÿ«ýK *…‚Ç»{ð¯]o8óLéAãs2ø3F3[È)X‚ÞJåÐͧ`×¥4ëîV�4AyU_œ·¼ÙIÝ¥¾/$qÔÌ%‚ö9Uî5öŸ¹à�ÐXáŠW–ÐóáÛù¦v4ŒU¯…åˆÕ‡i¹].V_Àôϲ¨8¯R|¨>�çúï`›Î4ê¦ÃS_õ¦myÇ8m´Z÷æ¯ÿÙãиMxE9eœìYÜ\„V jçùtVú©põN«œ  z”€æŸOƒÑ0yÚ,µ2N5»êC¬Ô Ë‹-4xB˜#¬Ñ€·íûyìœ5l»ý}ßmˆ«_‰øb’nq“ÁCuáNm(:œ3ÇÇX&jô5ä9#éÎ×f¨‡[¢NþOpë\ˆºr–Ât¥£>µ?žR.¼9ÆgBÁ.9‚VI+Àg?/n+Ç“½J°z{ mÞ�Ç©�1fÝ\®ùЛ?¶¾¶yù>��H¬ÌþJù÷®Ð— w©ÓÚFðN™Í 'ŸR�[0-^ÌÍßåÑe_€º×§¤ÅÂwÿ}B¥Ë^bR »>ÿ£ïâ§ß=¹È¥ *«\µÅ0‰0*N£ô+1se$®ºL;º—“¼¥@ûföÂû™… Ú=cư}‘QG³š�6|®â·—ÞÑ-£Å(¡ôg¶Ã•e”íèEQ•JøôÍ7Pžè‚Ãjž‘t?, ~)ŽúÐ�¬T¹ò¯,Ý׿K+v‹»Žo8“SÌæñò+2Ü|L�,d¥°1澸·Ò�.�ÓÔb?˜]W—ß+‰·lpÈ0=6›}.Ü�äÞƒ»HÒø#ÉÌŠîݥ̔,š”±N<°®šŸå֓ŇRzÜÞÓÁ=ÿò±üm’}DeêaôÒþ"Ä�"Ø÷wyt˜Ñ;ï·à×kŸXðö&k­Ë5 ãÇá–" >9F—ÓÓ§ó“�óùý¡Y\˜u z•ü#5Wìí„oÃï‹:—lxË©El~¢n4‡’DM0®èÜCOó*àõ�[|ܽˆ.,î¢ÒËÚ`Þw?·Þ…´~ ¨E‰Ž[ xMM>n¿yK\»`çîaÏÝÖè×K~!-ðáòHÁÀÏ_ géÀs И%:·]¡¤tCü ÁY+·s`´1̳À{*DÏœÅÏvå“iõ;Ñt ?V‹æuía¼Vã)Ä&³ó¥6zß!¹¬çkwƒµÞsÍ”ÝÜçë3Ly‚¼ JuÕPŸÝD�~ãøƒæP×Óä±³æ@ß·™BS¿­Ô|¹‹±µ§éá�³¢E,U§å�†ù’xȱ69i3†Š”Ú: G.‘âÑ!ŸÈë«¶ên¢{»¥Œ�ƒÁ¿÷ {*N£¸R�õGÏâºÒtܱХËVc/s x¶Á.쬇 Ñª•~’Ε/�ºÎÇä¿Ö‡MµäÈçˆ mknŽÉ¡ ´Äæ)¦øÖS�'%Áí½øß¾™X8ú?è,8Qኘ0M‰ò âàõ¹ÓD©SÄ÷BÀ4uìxCÔå9h«®¥{P¤½—ë;‚õï»T4χü_}â'/Â5“4Ðéf[ê#•Ý�Üx3ŒT"=i½ßs’ѯ„¤óÁIuŠÐ%:óö dÿò�è:¢Æ9 ©£ xIQÛ)oNá�ôü[6îŸB¿öåóŒV}ñõƃ$ù¶‰ÞYé�_{ýÏÔöâsñƒ9Âq÷V¶h \w»Lx“ôUÔ1½�cÏz¿Ì·)Æê«¨h…Ç…óTýýOùÐãÔÕŠ¸ÚbjõïÁîBè±ú¹@ÿ[© Ó�μ8!>S\¸pg†ÔRÍÈÅð PŽñévqnâ7&;ø£É3ºõu$æ–äÂ-«‰ün�^6ŠÒîçÅt�ìd˜Ä!å Zò²Oφsÿ,¨vaZ�4å©—±U^ [ÇpŠôü&J^×WüGþ–é�í~•ö^Žç¾ ÇNŸ^2GÇîrÀÏÓ9:p;D\º.üýWÀO¬†¢ÇG}2v�·uèS ¿ÿ>¥eíIð pû'v Wæì‡WÇÔ°Ó<„ÍJ'Á(£·t¯&.÷sf�¾’ر?ŠbòRñYލˆ’ÓïŠÛØ«$$ `«•Œ €³’wáèÑ‘|·0†_ äÑw¼¡ê¬:V<ž„3“½…MÜ.NOºM¯æÞ'÷ïÙ~|)-¼Oò\àéÛ× ?!ó\MÁwú#(|¥„‹ÎªbQ›)›ìz&&,šMfCHU´x«’ÇTù×�å´úäZÚ,�¿å8íŸÚ¾ï½®á�æg6]ß´É$Bƒ—&«Ó§ÐjT—Œ�²M�¨ÔÆü àØžpš&Ý~VÁb9?1ÙM¿—D Z›øùó|¼²z µws�ëº~¨ì„�æ³ÛãËðYð`¹÷þl†vh•ÐRs~øA؉Ùô¨Ðík0'}:yÞ"Ƥ›¡Ä`.KÉ£×iÑX¹Ê‹–LÃë׳hE¾"nuV‡ù�‚(òþÛQ37ÑÖÈÓ0Oz9Œ]^sÔÁƒ·nk{|^$ul¦IFÏHçŽ �xoÖC&’æ�i6óVDÐÞQï鿳;…©š'aæ…T´rÕ¦Æ[È5E’ç,”ä¡%:¼kÝ©šo‰æ¶ÙŸŒ9´Aá$Ï<…£HñÙÞºbúuÑÿk9…édÓ‚Ô¾¬åž‡¿f`¿�×È R«� ¿í†Oj«øyÙCPú¥N²vèû˜îl R ðå‹-ÿ„uÍÙàv»…Í)¿é¥ÐýQÎ¥ÎÅ-IÜþØ:· ŒB4FVÓÔg?hÓÈ&àØMÁ¹<ä^œ0ß¼ ÝVkàg§�°'g9Ñ÷¡¸Áؼ8�ãü°ÝñžÞnÓŽ’úCö7„翸OV¦ß¨Âmʘ( 6Üõ«FÂÇ56°P¹zMÁ õ4(ßæ$³ëŒ˜òs<_’‚äÓéäÛ\~—³ÿ=̓J¡rÆNqõÛXRjOá€Í—°0Íÿ…YRì$ Ž�WÃÞkβ�R&ïW¬£y2|v–+^\ÁJ�ãXy�<ëß®L¤‚Á›iF¯44hœÁ_fÌdï†;ó9f¥Ð—îd8n6�Ö? §Øß Ö^«â¨ÏÞ�°$æ"¼˜ ŸÇ·Ò®Ëî‚é› L—¯™âbËúäÙãÃúæëuycüz\lN…×»ÄN¡“|òçàί§Aéæ@ÔrÉ\ Ôq÷õÞàøé"Åf_·mí; \Ñã3VûÑ\6H´HõC=Ä1q`•§…Å‹U`Ôd¬|,�¿¦<†[­–<;jì =†Ã‚úsü Ô·ÁGÂRj,’@qªš\†m'ॹi_MÄq/ÀïƒcáÄóƒᬈõÞªhzr»$ð±ªÞô%c7lŒš…—74ÓÈjݬ„‡?ÍAé QJò-áÕñaÙ¶–žÓ1jÁT6¶Ÿ�²•°udÞ†}¬çÿT©M/öD§‰¼¥BßÌ‘ÃmÎó�6ð\2/ùïÇ˹5…æÓ„¿3<Áu‰,ïþu¦FÙRÌpZwO‹vÓ;é60M‚ÆHERn¼*d'‡ˆ¿�OÃKæ|ÿo',¸9‚Õ‚ú´%%å"ô «¢[~“ë›X<þê/�~TÊ'5†±¥•ÏÜç“ÿn¦’w„¥JP¿“ˆEKÌéÀýe\z·?}¸ìƳÎì²1Vp¥V“5Ð×°uèKúyG’ŸhzÑ!£Q�ï#GK éÙò”û´�Oëò‰öDÐÎþDS½Ü·Èp¦îy Øn†W®Ý¦`™IÄÃö°T]¸võ ߌLÆ…G#ùWÄD4)ÔÀ­·`›¬À?JU9|§þÌèÏu׊ÈóÍ ^¤1œGë'ânå—äß߈þ(I¢Þ]<û÷›øò@í5Ãmë3iÿà!löí'ùöO¡8?G!8`þÿoÆ®ŒÂ“ÞÁãrlRrlN„«ÓظÙ3€®¬Ê߯…g½lùÓ�¨�óg…(áp–¶ŸÑ…ïU‰T½Ã�®-˜Ž²™ß`aïù8ø’"9f¡DÞ,88Œm�Zè·¹2ê®+6­Ú�Wþ‹dŸ7ê¤Û6ž,.¢G)9Ð&Fjå{(Ý~M×a¿ý5áÝPYÌ·RÀØî8a‹»&Þ�¸ÎU ĽýŽ‚iØMx(ç@F­ô[׊›F<jµ"(Ôv � 8ôì5Ò2J ×è²}h^�†¼laxà:�ÑᚻӢ ˆþlª¥QÇÆð�ŽË°rÝs°ØÜ,¶Ô9âz%#¨‘Ì{ƒ‹JÞƒ°í o4Ž4U~<¦ÕÅѰ¢™Iß·_=¸€å·òa–o$8²*¼iã"u8¡Ë´gÕ“–ÇN®•Õ¦ïÅÒœ7. \÷àÕ€þ¸hd^´{'mÔJ€]—Ò ~Ôö–ÉáÛ…Ù_=ùµ„"…y¼ƒ)Ëp¦Ž4D›ïÆh À¼ÀZ¶œwƒ€ÇeBÛØ­=>šÒΜ•ÁÓxÅ«Føâ¬Ââ ÞFï�¼¹Mí·‡áÕ=sxuŒ—mƒÿI6V:#^4`ŸºùxgQ²°ð\%~<2:œÃ/[1úóbi9ž_Eö{cñ˜“2�¿'ôì\¿×–€ÕÚÖüçùÎþº ŒÓ–—cœÔ� tö0Ê�ó làÔ¥þ´±vu�ü²á¬¤¬Ï{51WÝV9+‡/þ1äóݰ§Ù¿\�-AŠ\6x¯éÜÄkUØ@.×9t¤O¦³]2T!Úó��¼³(#¦ «­4ò›O}á‹Wô§³qc\5Œ¥ýïÛ„ñ#6ÓˆgNüÔ9ûC"?Ð?jV1ŒëÇIÂþ¢§”¯ŸŽñ†û¨÷ã}°`³ºpÿgÜ‹‹fÙõy¸·Á ÖçäÂ¼Ô øã…@�òµmÇ_ñü»É-&�bŽÇg^+øµ’78÷±&[ÍËâÑ­üí®*Úé%S@Õ&ú/ç±ðàðh‘=$øoO qý' Ó¨ýØ(áK ¿C{â1rã;Â� C¢æ]¸}²n°�<éC;wO@­k0'ÐzššÇûH`ۘ׷P•B\驇Y±·…š¤C¸1©TøyÀ�~õ{ S¥jðÃmÎÍyL÷G/ ‡w· ñ^Hßp“,v©Á¼é:lS/Å)�ýXmÃlšh0‚vžÍsûJЊ‚ R9rЦhî=Ðz½êïÓãk}iG[ Ý(K¤>åyÉañ|ùIÐJÑ!µøýö þ�h_4Ž5C&¨È°k­ØIËØž/ÕJƒn¯ë {Ïš,ÊûâÄ„ šñí˜pXm0yÍtJbÀPÿ6§üh‡>ÛÃQ"S‘5î_§#¹†8ãK8Ul„ ß_6¸Ž ]Mý¸vÁqÁféLèãËç‡u�›‡NŒ[ÉëÊâà¹Eí<šÀñsGð�ß5Û 2ª?�¹s}3ECÍ¿ 5ÌŸ WÛrý^Kè=u…ÐOfh�¼£Žø~ÄBÐ}9ŠOg‚Ò³m4ôm-ßÈìσyÿF{Ž~UˆP›ƒê~[Åq~‹—Ë{æÖ1€ßu ì<¡[º(¡ÿ¦XO@öD βu窕í¼ÒÄý>¯gÙ¥YJÇ ­kLQ—¬»p?k9¡ÃÏþïC›&Ýÿ h¯?/ìm“Àç]/ÅK½1cÀd¼(÷ÚæÞ«âsôy¼ïzÑB»¶Ûa­åJZ~'E˜9ø ÙZ'’ü"_¼`Åç¿£ÊýcÙÆÆ„Çÿʧ³3ÜaU�v­Wçn©V8’ó�¢î§•ëaCÿ`xꪇsgGsHr j¹†ó­c¾lóÍ‹6^ç U“Yx›Mï·’á Q\µ8J\£gµŽbù¹#ÙçÒIáâD[þ±ù •§/`‡YÔù½š¾Ý7Ÿ(øéÜÀ¶ÿ !X“¿Õ~‰ÒãÅqß#„u&aÜ$® ¼°Ë h S öÁ„*SÁáÐqrì8±îüXiÏ¡Ì11ZmИ}þ¸³¾„‡¯]$Kµæ“ýO³·Ë+´<+�uûóÈtv ŠK`iÑcˆ;ûèm87û•ÛÜÞ%Ç‹ÎTpÈeiÑwP“rÄèÝP}­ºÏë`Pd�V¯…)Ïì1cž wìÀM/5»bl~v‹{õf‹Ò?‚öÇþ`¨±�KZ *© ¶&jת�õBÏõ¨N×ÎOçC½�D²q=MŸSÿÕg9pq\�øzœíáúWôõá ()7¦¯Ù§yÂU9¾ “Hž ‡â›X¾úç]7ÔÁÃEú<u½è׋ÿ�ÍŸÊÇ¢œñÜ‘™øfs‹�él‰NëÇ Üç(ø²DIüëú�²öŸiÏE¼7µ…¥!uÁˆÕ—.¿H�9•–Üçu?œ6dŽÑž†»Rò9ôôNZ¨Š‹Çé³}àzxìeÝôÁ�x”ÜbÂ)Θ3ÿ‡püß5Amïc±·A¥Ž„°Óí -¹˜›íé©òMò�Ö„{728ñu$ÏU †Ua.”Ù²,/ûðŒ3�d<›¾]"Œ{ñ¤áñh}=¿”OÆ{sž€gÖv^y×À¶ñÓd0®Íß|wK/ÞÆ_¤ûÖ´Ê'zonÄé_•¹V}¯Y*�Ö?2 ý²)«)Ÿ‡ÖŸ³qÈÉqÜmìÁ£k©ßz|°Ø`Õ'ê¼?–-shÑgÑçW_~÷H{©öÅ1•KYúÍ<.ò=‹ח’×ÚŸÐi}„žFÍ%éÕªb�ÙUÒÈø +R«ùzîh¾ãM#Ñ÷°1TôÙ‚£ÿòƸ¥ðsüF•–Š :d5?;k±W¶ëFà¤59¬?QšÓZªx±r]ø·ŽÛlÛaÇ·mƒ3zÙ0Oè_ìá›ÚgyÕZ¬¢ƒÑ#ïÒ·êO°Öè8s=D�­Ã„ÀÜga"¶XÐä8Ó¶–uîÆYã*!*j<Ù<.‡ã²,(Ëõ…?7õØä�î{èċϹ *áýlµe4km£¥’4üc.i !Qéׯðà’ViüÞ³SÚU¦t°áH)‚Þýþ¼yYe¸ÊÓ¹á�@µwÅQs&sฟðýuo^4ÓW°qÄJ¸ÛWœ°ß\ð�Ó½áO¡õývš¡2D<óï¾xÎ8‘ާ –ek¸}˜[¨'â¡ÉVä½9Q|ÿÚ,ý˜Jݳ{ü=,ŸÇìX„›¾�`íg3!ôq¶øÊP™†_…m礹ßÒ¯b½NÇýÁï 6°ÞÞ�¬×Ç‘w%÷æ]½tñâÂç╎N¸–Xƒì0uþqñp½.þzŽ×[ÏcÓ0e¨ì¶ÀÀ½�•�P0z(:7¯¢öe‡`UˆšMñðO3œõòQ{hoê�yŽúÉá=ÿzAí%âÔø÷´í"ó¶ QhšÄä¤aþ96›<‹†þ—e26[ ã¤`³›þ´ò…ƒŠÝô"² —GÊqç-¼·&‹ïÐãá¦dº%Ÿ®5Äб½i¸["´Ïé�n>YŸµ’3C+¡<;·\èaÎñ8s_4´iôA³â:NÍC>Ÿô¦zm~#è:�´•Ë~d›ß(àÉ9½¸+q^^«FÞzDù× ©Þµ‰yD’R×P*Wå»I+ikÙ2ÁqL²ð/IŠÿl{Koi�Æg6ÇÈ‘�ïÁ±=I”&Îs×Pü´I.ÓGì� cf[€«¬0௅(®�ޮŧËQ¤Œ öiŽñ¥ÁøW «M«m±rJ�œ–�• ~Xôõ'7mJÅõ/ ðTùTõk¼2‰cí¶~üöÇnYÓ _'ù ºK¬áÜbî~�Hªã¯A•Œ.ñŒ€ÍsËøÈ”™`ók%Ó¾¡Å—é‘Þ6r]• †Ä™j²¸íÁl<»¤�š4æóËŸúèîNÂÇ­«áêí,Þ1s'6jvRÙõÁ#Øõ®,nÿÇ¥M+3©hþE®Ò2áIJdþ8d'¹W�dzyh5N›¯ïYLßôçÀΜ~°ù�¸/7Lÿ¥Ñ¯Rì'}r9“ŸEž¡®{QY˜öät‰ãÏÃéÚ¹å wÌRä›%ãÈõ‹oÌ“åJ`PèjÌÏÚt·ÒZ¡žïëÑÅ 3{ö548åâ� ~³50KË–,ù Þ¥»…O751Yß kç ç©Â®ŸHž¶+ ¾GŽ¢:¶²í7æÜ?ÉC]DýƒŽðU,dMÈ€{NϪfŸ%� ]pëgè%Þ¶Ýø%‡ΤùžyÂÇþ7áý¸›h‘«…O­'Ç%°Å¸Ñìn›-œ;uˆ>}�È“d†ÒìÜ»dà¼�NH'ÐÁË;q¹_î[÷üës/�“‡Áâq—/byÿOP·J=œSÄÙ%ø~p;¬òÛŽ‰ÂyN’˜�gt+)îz¤È[ Ù;eqÈÂÍÂbµHú$}uþô…FrÜ`åÍìÔ€V�Î\U|²?�æ~×'âôm_ĶÄ9¨º¾„õ¦¾ãSm�Ä9ïu©°fo×ã»æýà^¯\Úõú>ìì?Š�.•fHNÍ;<àGuˆðÂÎ�ŸøŒáº9v\ì€n7RpÝòÐσ_\í ²n‘öàe¸²Ÿ>vgvŠ#õÐ8¿RÜ¿aÎÛ9ÇîUæâø�å?;š¾ÐÔñOð¨I5N0b¿¿r´ÉâO±³& ×Q`3¼�>´:²tno·« ¹Ý½ùªïQqoV š¨xaÖ¥@¬ò2<ô'SPÅcX ùNÈÐJ4 ¥ygú–ý¾”rìÕÙñÐWò¢h°zj"¾™x�ÞTA°á>¬Õ]ƒ‹Œðæ씈ƒ#nz¸ÂrzW,ƒ‘�aâº7ô߆قüß�h”gˇ�úS�{Ùü³çY7_ÑÓUÉ‚]Jвð¦.¶ç}>®Â/åH<_I»½®SóÜEdN{éQÂïžÌ}ÖºT#õ]‰ý?BúÎ8Ê‘­kK…ív>X{Ò¦‡ èÖ�…ø§ƒÖÚ Ö>¨œ’O~gV &ý’èÝZ#n~ƒ¼îéÎ>é¹9žç1~H_¿õ¢ó�®¯ÁÏè}IÜ_G9ú½`S£Ïr ›Áh1jgcéðÁ¸,C‘‹ÝRlžOvE³lY>e;—Ìþ‡Ê�¯©i à R…ìßA°Í–O¸ªáŸµR¤ýÅ^Œß&ųÞ�â_ê·Då´F*Ú‹t+åUÃä[õäamÓvž„µ²S@ç\í(ÖÀõI&”=èÜß´–Gš†ãÒãyW“%J–†Àæ+�ÚZOO5×ãÇÁþ)êã›ËCñFŸ<ØØ2EŒK1¡ò$)¤Õ�àbJý¼†ÂÕyOaêË04«? <¾‡ï“F°æ´�]Æëò® ûäDU‚!«§óbµ!¼[c7_Zz¦^: B½i¯ïP¡0Ì�ƒOßJ³çÈÃ8»×�xHG}ûñÀY‘øä·KÄÁéeò8ëçX\{~Ö™}‚´×’¼q´ΔÀœ3.àq~3¯»nk›lZ�#…<Ühñ —?"S%-þúØ/ o ­Å¼ï•Å_sEù•ÍâËøU´$¹ˆ2®Î†çÂr‰•À²a…–_J8eG2Õ7¬ÃI+Áé›á0Û7”\¤^Âô‹_ĈiZ­Sv›†ÏÌ{•QÞ²±�T8ÂÚÃ…’¢Äæœkû2¹×#e¾á=ŒÍebQi%Î-ÑäGRa´àádÌ-‘aÞ§„ÿµ_�íW’lW9µ�œõÈü‚î‘ó™;’§æÿd‹›áÔÂÇ�cžÍcêlXqN4µþ²¥M=Y�SøvÔdCÂEG±ä òjœH^éŸÄWOæó“�"ÌûЇÍ�.õ°¬v&¼ Û?%Bwî Á,Ä’JTðÁénþà!w{z`iŸt•Ä8¯bº'3 ìÒ¸‡5âPãfaÉíôº×¶®ª·Ÿ7&K»X¶›`hÂtyŸKºnjøc¾=.“OÄוxWøÕ÷7aýÄJp³A•wNâïÒ¾ya§P—³š_›ˆ‰ý¯ðÙÌõ=ÿ:ŒG͋ښ'¡aæ h6m·…–ÐoO=-ž±Žn^Å6ÿv¡Ü–Rì÷X“§óÑ”=h¸ºœJ ðoÈ)Øwûø©!‹LyYY®Ýû–æÊò5)}Z–¸‡p½ª&¥ ©±‹è¶åd®ÓXŒOOï¦ÒÝÅ 7ÞSû« >yè 3‡ß¢e4kh+HÎsã’SÁ^æ*�YaÃc§D‚àP‰ÁÛTø·¤C“Àyæ.Âu…±8úï^žñË·é.ãÉÑ�‚úòÓ`‘â„v—´±Oô¼ úýÞA]#£èÍ|m¼}P–ý#<àÒϾ8k“†m¿§6IàÍÏžp`èq¸ª+/.Ðä3}5Øg®%Ïñw…û5îÔgùX|6e=4„‡p—ÞUÛd½(<õ²ðyC&Ÿ”K}â"ĪYP­h�y¯ øz¿øè7üAñaJl¹9bà…èVü—&÷I³-Ey%eqáö$Nn”„ö/xôÔ_qUÅ, T› [žÎà¯Åš¶Þדa&CØ�Ýü^·O}»)ŒÉtÆîq†¸)Ú—wN¹ |$à⾉\¾ÙOh0x�«3qîÓZzºì è?1…œxH¯Ž 9wOÜýn?÷}_×{ÎqOŽ@]·x¾ÑGoõ¥AÝ4Éãâp´ÒQêê^MË5¾Æ 6�ýЧü1ö>»œ>( GNõg}/ì¬0`{'Ääð˼‘’€îE�øòÜUi³öÉøÅ`¯W÷c¬:%w yÈÏu¸òw$˜söz/ym %f¡é&gžloAo†rÜ™ xâØ¨ªÇ¿NÙ{õÖÆ´OÞìâÙGêa…G(Œ(çE¡ºh|·\ô?!àŦׂÖiÙn=–/á�ŽD¡c^„vç#~%°aÑGPY7«c¹Lö%µ—½¥É)¼r’%ÞUÅìœÃ¨ò§P<ܱú [ gÖ—Q˜ÊfhÍ¿›"¨¥ˆ­»Žò½lA±_2—ÝØK¿šsè†�@÷Ö„¡GG)_>�ÇO¤ Æº+âÑ¡w¹`©^ëþr¢· æ Kny ï?„Ü÷èÓ(>Ë¥Y_°áµÏ�³¤¤ÕÙÂåþè:S�õ‚oSœi>èºxBI�+µÍÌ¢öÓš�¾ 6Õ_¦+¦Ÿ¥W=ùýÐÅÜGL§«gób¹ÀÌ8¼·_~¿›¿ÖQ·3õXãKC/ÉaÚÁ‡$¾¶ÆçiØüfO™ø…jÍÑ©Ç8þ“ G¤ùÀò»jx¸ÌË*ŒpqJµ$ÿ_¨î‡•Vh~¬ \;2ºIN¼h¡ìE¹°¥cXß)e°†~çm&’¼¤¥cÓÙÖS ‡^¿7ÛƒµC+ �ÕÄ›�jüÒÒ�žÿšÂ.£ö`õ[Ñ«n¾³VÀ¶v*?: £¦÷áiyúâ¢e±Â‘‡cÅýEÝXoÞYp»ó’ÔºÀ”¿ÉÂ\„cî‡ñHE3Vd{¶ú"J†žŸ@rÙ79áž=Þu•æ§ Ñôë°FûŒ¥{4ïd)ô{ ê«{pâM½ô@:å­$4ô"­-‹„’㎸Yö2¶û:búD_ˆg[®;Ïu±ØÀ�)¹z?.9ê.w;€õ§—SNÁ$Œ1 F† �$žžnëó�Hkì�$ƒ·x’WÑÚ>s>n%ú¸ÇZ{ˆÛ¼’yÂã¯Ôº«ûŸO#í;Ú±Í�5uÐúèxQØ O3*“é´˜V?•Í Éåä šl<\ÿÅã÷÷â]/ð㮂¡§†xmÜø)7–®C÷ò'88xÍ ç¹†7)Ñm#öï9¦ï¸FgðÉî.šµZ‡Àå Ëx ¬œƒŒž¼p~Ö9i„Ä—¦o²ÁÖ¬b¸•JºM;8ãŸ)÷² ´óÙêœn:=æŒá¤à[´Î?‚O%—œÊG•xXó.Š.Ì£ÊûwIkÐnÒÊhµžzòµíÖ¬sÖŠ‹'Dà%9¶~ºZçÃÔØ4_å=�1]*$ •(ZW«Ì+bö¦&`ÓÂ'4ù~wnþë!ÎJê�ß÷'¢·W*ʃ%Ÿó2ÄoÅa\u8‚²ÞÌ #úmЪ+C;»g Þ{?“ÿøžX&Ácç)-9âÇÏÅɹq3±„Μ>G÷S‡0¬.ÄχzóèúybÃoÜ\:O•�$둊ì}Zí 'ˆãW-_Î\rSáEa0z„¸ñÇÉy8òûvÁ±Ôñ“‡#�àZ¯\ü;2Nÿ•aˆŽ¹Ê‚®I�´¶Y ï6vHêuˆT^œßz+ã¥ÕjœªìÃÃ]ðïì'°ìÄ4N6›üç‹Âùîu°ô›’Äòm8Œ-Mf‡9å0Òv ËÿPÀ õR•G÷?G¼ûÙƒ÷�cËnAâ ÖDÃòñYV4íÕ —dw9¤‰`S[‹w=nqDúZz"¾{¥$YÂßžcÙ…BÔú îãs’ü“Ù9Z†ó3zróæéüðX"(–¤äí ÿŠÇsÀ3 ×9Þ¦góò!Ò•ÉÊ!—-ÛBÓº7Ñ¡}63›ÜíFcɨ±¸Vn¶pýMÌ�¸FË´‡CÈóœèzçô×DÓ×`·ÈnžÄCŽ¢¡z�µveŸ·;¨­x�È™L½,΀M¶ …ëlÀ³ ðáÈ=›yO 9® 2«Â±î¡‹5.X¢þ²øà‹mgÄ€ªñ8ãB‹d·™.G-¼K¿G•@æÕžœ57’Â’Œ°_Y»8 àEÝÞÑõ°ETÙçvæ­�!þQøäÚ/š°Jƒ×ºâú=<µs.WßCVš£ñÒ�obìÓ#`ýÚýŸépÛOQ+àÅ…YÁž¾óX#Ù’5 ‘ŽLÒ ú^‹Xu—6î¼Ð×µ‰žÇiÅ£zLqîÆ«roS»^"­› þ{Wí¹Ãq_s-¹>¬Bÿ“ p×X‘'„ûre”þyoNß�qÑÀQ0;q:þyfÀɹVxÌ€Øaô{:1w8:kÎÇöHðªr…Å;>Ò·�J¿ £ð­t!Û‰d°§B\ _­Ù1$6öíb¼\Wë‰Íq%h®ÔŸvÚÿ€Å�-Âkˆ…ñãb釴ï˹B�£"¸nN—WÈ¥áÑgî^Ä7nÙpö”lAc‘;EŸÚ‡³^Œ¥êàß°°rZzl–&¶Ï—þ¼\×&‘møjÞSÀc2aYê#h]vNlu;NÎFãÀÄâ�-�Œ�zïÄc§²¤zƒJÇÅJïÛFáÔm_lƒå÷;!»M‡Í/„ñÆg[Ä£ç}à¼Lï· *,2hø´‹�™áÊ3¾ìÀÅw}Y­8 .ú¹CGsÊC3ÑâoŠT»×Pz_ºždT.°ú¸ º¨*´½ÒÆ’« ¨Óa�;†LBMÙ@þ~%jÁðE¦äcÿHÀ±d9dNS3Æwãiôãµ/ƒÉé÷øºo7>ÔaJf S°ýr6^mÐa  üôó(8|Æ¢Õ·i—ìtÚýì½Þl‡;t¬­Â§lc2ýFçs™wÑ­…üqª|À>šj‚.À¡º¾l­ù‡Þ”v±5¯9Íteûׇ «^ >WZRøûä>é….KÓïí/ë.?ºQÆŸŽÓ_�;Œemß+bïñé£xæX[òéµÞlúÊŸí\´ðòüD´¾�¦ÇVâ÷[»IÇx?OÜ£‰J~¹Ð:+¼²öÒÚÈCpD؇ iÆâägò�íü•US:áB¿éàk“GZßïKÝìnÀÉŽõܹç., Áõþ»…#jxùÁaÑ(ƾäp‡Ž% ÿË.§{íYÿÎ<¸;A†ÁJÂå­[ñf‘3Ç9»â²D>¹W�°éž¸Óc;ýió‚4ßFš1å*ëH�†oŠøt–?Ab2-82F&ö‡Å-c%'õ‚Ñ)ð F<|C¿æøàªµé0Úê|Ȩ üÑÖXU<– `Dï‘X´Ì/ÕìÀ3£q¨0Œ+VrBª�vžxcE/ÌŸÀ¥{ãaxOs8TÙƒWQ‚GŸïÑì1sI/g>ÿëv[œûw.œo�ÒŸÙË�ÿ='¿)ß)ÇSkC^"ÛŸŠ–IèÉÍ“ôÛæ/É|MëÃz²òßÙ$ÿ>/‰"ûü.g9žÂ?»Ëp±r›ÄIÒ�|ô�2N æ\=Z\õŽ ×•Ñ¬U»X¥1�Ïú¸ð~UM~Ýy7W$Âû­Éø|Ü8ç5$üZÃ/’I!K–�m‡Oñ�0gø¾©£÷Ÿäègre½Ï=þùI´Ãúá4ùFéKëÕ¼}¡=':DbÖ�4šbËì­Ú ;ÛTÐ>S@í_{ئ> «Û ¡r¾:×pä«.üôg …6mGÛá¶ä aÉW;ÛÄÚøÅø»x?ž0’gÙÀ§–o…ô©âsãÁ>×OŒÏõKvKe�ˆŽí/§îÙîôç°\?Ô&¼:væ]M€á�&A‹ ¥ÎËÎSÒ¡l—Ùä?†Ü®àõýÌ05Þ‰Ýgì|F½õ8tÞn„ÁOÐ5t!êÉmgçÐÕ¸Âý õú$'VôT¡CåxüÞ86]]�Ë,p•Ñ3a@#þ\R*^xEûæõb-³%tcvO|û�þ*<¤ñö âý¥½@þJ¾z“@žéô6¿”&­Ã¾6¯ilñWPԗź˩83½tÕûñÑ^ê<á¡Zl,„$ëCâYu Ü·¿‚Î^˜Í¡ ÖØÝ jš•à¨Ew¨<´7›ÌÂ9R:Ñg Ú!Á•_Jia»>•ö g Þ¼w&~PèrêÒnÊkÓ_ËežQ$(®ã×o… !]�ÿx §ü›·Š¼wèN´Ž;߯t‚UÄXl]®ˆ3 pte«ôWÖX^cj�<�½cÑeuvŒ¼#l îÅ­N¶Ü\Þ)vgÅ[FK°ZgÄähCÛâ$š\~… ã§Ñ¹s£ø¯§ŽrÏ@¸ú‡~¹Á¹wúã« �di›Î-³ 8Âq¿™ÿ]0»£ÆŠËé[ל´r)·ÏW"Ňñ�í>Ö§ÓÑ ÞÔ\$‹+ŸÑ°URµS§ø‹ó ›eÃséáð‘¼jÑ,^]‰&¯4°áº„fæ-ÁÿÿkvóÙ:^š�;ÜÊ•‚u°iç\é=Ãì2„¥wD?KYa“g ªïVç!²­Âª"TÝ ?^Ëã£à‚^_~àTJ+”Bpªò4øÓ©[íCë9Þÿ¸p{ŸkW#¹¹} ÄLBçÖÒˆ]^=%&¹;ò±9“ønB}S\Oßâ.Á�iÉôø}6ôH}M µÙ´Š½F�Ä»9Ƹô¿/¨â)ÖôUàÃ*×-�èÁ‰ó⻩ÐûùIܤ>—éö0t;“ª ,ðæöRúSä&^—=&³Aâž5+…UJÐ]'æ{îç‘F]³Áù 5¿í®m¥‡]üW9–_Lý ¿~ ¦¡‡ÄЊ àÚNAFÝñQž3¬/ {úŠ_v"¾˜›É¨Wœ@—MûsR�“°Nyöw¯¢óòga¤�œnÕû§»~g WÆI•ÞÝÈa_€7k¹á¿í�ÉT¼L“î�¦¸S1S·£Óø€òþ8]–kNÆ¿Ë�¹m“'Vg_‘ü¶ äÅ‹ïÀfÙHh à%52¯ äÆÀ¶îpÄ»iôC­ ÛçBŽá ”™AŸ/æ`ý¡<:Øh�¶‹ò§CN¼ôÑa¨ÖΡãÝ0Åv÷½ùtP©Ù[qoÏx¡*&•wn²Ãkï Á+“‡üë$¥ÍG)ïfžý\€Ý}_Óï'û ­´7>myzôuÉ=ÓQ7â+>_% Ø�ƒuÞ‘(©Ò-¥#˜^õƒ½¡2\ºWV�¯:ÉCõ;…oEqÜÒjJ-9Jð¥ô©(™8M£Û·ÏÂqk5žûó…ð­¢Jÿ$â¤üYX=s;È�á­A½0¼µ7_Ø7„ø;ñ2}jx\wÃ…+¿è¥µ79}Ãæâê^ý@Q[]¹R¯ƒ©aR¸ßÇ€›þ¡åòkÂÅå±BnË)¾$§Bî‰i�ª0·"ŸÖ{¢¿ÿFKΜ®ëòí8i»GÈïò‡Ÿ¤d.­º¨²Þ>C>ëi‰ØÕy«w6ñF•8*û5Kß(¢Ç¦Ïøb¼�©½°Í¼�¤¡ê‡ÿhª×FììÙ�Í—wã×ÝÜ8=õ1õs6‚(ë>¬QM7~Vѧ¼¯Â¶žÅð´oóÄ�Y6<öî|Üm× Ñåü*±¬c54ú¸ò²~¸èÈLüq^ŸÀfnÕãñbuX)�?ƒªßì1gþyQö+pßœ¦øŠG5u�GÞcñÄÇ$80 HÀyÞ~ê(?zû€z´èóá‘_ióŒSälU²a‰¢r¾w[™+ìT�·‰–>ý`ˆïu>¼~}¥¬TŽ@éšØè¬Ewúâ‹i}1½àÁ#~nAêLÝ"‡ÂiÙNtEV M^Ö¿ŒyðÞ~â©o…P5š´I)ZBÛgg kìÒaõ†>¬\» Ì /QçánœiäÄï¢öa~i1åÙîÙ†0(;Nð:¡&±xyЦh>›d³oŒ"Z×ü…ˆ}²Ø«¼giïFw]Œhˆ¥® 3]øåÌC¤q> ý‰ÇWówÓW¤ã+uøó®0Ûó"4„þ…ÝË‚a‚þq�ßþ6*¾s5Uhkê@ôÈ<Êñ�žýŽ¢?ÿÿÝ‹@ü7KíÖA€ËGñˆ› ô*TÝ­0%Q�‡�-.ßt¿·d³ÂJ ýé.t©§¾ø6giÚ¢þõhV×ÂUÒpÁÿRWëî8 è;¯žÅ£ý8âF3èÆ¾Ww÷àÅ»Æ`SŠ„£o' q£G µÖÙôÒ}�¸¥ÅŽU~–âÈÔH¡¼ªSÔÿú+œõ¹íî1>pÏ“×ñ«ÐÑÒ¢î]M†Zìòa8ÿ1:!u°HáÀæ“l7É�u‡qÀš8î£[ÑwçaÍx Îú…Ÿ¶~§…¯sª—f”�ÅWãwÃ=烸-(N\$œæyÝ�’ZÞk*øCiþ®ìzŠö]攳hüüExæQtBÙ²‹z³JŠš ÜH1ëázýª]Û$¾VTâ¼ê•{JŽSsu°ü¿0ûëË@Ø¥L8µoF¹ñ¦Ï£ñ?k*­¢õ2Z„-ñè²èd&)რ)bÈ -ô�®Á_¶µVÜk6îàuý]yX[o¾nðROjóóÄÏb�7 YF+¬÷ë�eG‡Â¶h ¬|:¤Åö&ÒA鎘úÄ•f®¦nÎEx(fUxœ�6è¹óíü1’9O)áÀ7nÞªÆíC‡Â¥ÜíÜ¿ ±ö¿wðæÕNz¿&“~yvãz7uÜ’8RHóÚW©7?ž&-¶Ç¬¾‡P!G$yƒç‚^Ä@iIL14%(ç­Å!?²ØÖ|8¿kQdÏžƒñuÐdªÈ»ŠÕ8ÚqZ­ê.ZŸz;îü³Šz¸Çò"÷ªK§û£Ž£¼j_ýï7n©§Öåj|¤V¤Æ%›EÑ&Sü/ÜÜÒºó�ˆQ8BiifŒä�–O››çE³©W>=¼¾®ï]Šé ‰K—ò«~/…MÏtØ¡} »­˜ˆoË¢’æS|ù *¥Æáµu3ñê˜*¬OÛ¸ ó»¨®gYqCÕjQ¶¦'µâñ]Nú™ˆ7j lg(uÓ» Ó­‡Cð!Cܰ�µÏ7‘EQ.žül„ݶ„ ?=ÅÚ©ÍPâÔ—‡^>€òº�ä¬6Œ‚·éq‚ÿ.´=� ‚óRŒÜgɲWc™C— ô=ÉOÌ Ç âÁJ'œ{ùì…Œþùâ­3„Œïjhùæ"©…/¥9cnñÕþƒh¨ü.ðÒNÁ×7ºpäÃ]dèò Î[,Æ„=æøòA#9ÿÛņôâ\¹¼Ñ¦ÄÝB–óµý©°â´*ë ;�>Ô ·œqÃó+s©Ûae®�&b�ÑÅÊÅi!dùP@¾´MÍŒJc}9`ìvº«ÙÀ÷Çä²ÊœØø„¢lüxгXL`Ì.{f±eR™hØÖ‹ßVü¢'%xk÷±÷·­Xí7ÎÁoÅ‚$~ç‡Ãõ?þ~NúH¦—™>?×€g×%£,÷ÑËI‘xÊ „Ý÷4Ñþ~é5„æ)z|·æ”Lœ…´ŽâÊ�_ ±f.Zyé³ÿI+ úy’rÖcÁu[j d!Éz( °ÓãUKÏ@³ÞhP §ÄX%iV.y§!q@"Ÿ»Š»ªÔÅ `=[ŸïÓåw—áé‰Î¬×·»$Sq4Éã·{`™¿2Øvªa‚Foίû"ê5Î�/½‚a™² ìüoÍò ÉÂDíʇB`à`ÌnèOye£„òï—ðóà “*b¦ãjý·’°ÜÉèÚ·&ƾ§~Ž=IEM öôª'aþ/xrC‘ã•ç ß÷ï‘K« Ï@¡­,·¹|¦Qa¥0s�5fÛ³§v™ð©)'}J'ÇÉã°OàXüÖ?’•´Ï‚ó÷—db}’Š›ÒæÁ£0Fá<ÝÕáhÓ¥<˲Z�ñ*ÅCï�ðîÎ1ps•5´&þ¡;·Õ1¯þ89¬º?þ,ÁŸ?ÿˆ}Nëa`³ î˜�Ì“ÖÁjKW8|lÊ;Mò_`ØøJ1&&’ÿíÙ%8·§£ž^'TnOÕkd¢–À[P(³À�¯S¤FÛã…�ÓË©úC»è2ïµü¤æçðèÉey° .Ì´&™§„(«ñ¸èÉ �6+@¥ûm�I6Ń'W¢I?/´˜óMܽ.YäÁ§âClbt\ê>\SØ-õ‡%Åß(tô ÁÔMÚ>§K�Å1ÁÇÀ·Û^Œî@ÛõNPµÅ.0 ¿t‹È­u#N³¯#�¸ÅÒTOï¶R�O^0Ý Ÿ=®Óã Zx+Ý�óR-ppœ�Ñ—ð—à;ä8~?ýÊ©nÌGqìïZq•æ1n©ðâÀç‹8Ì<—*')ÀzÓ³,cœÎÉcó±lz70i:A£néÀn7ºæ¹\:hJoNU݆e«¥YEå`9usÂOkÙÐIÀx�vnôˆ&÷"5ð0i¦€~#7_èu.‹ Þï­Û`p™2LÖ�L5ãà1þ´ôÂ\¿wêy7ÑÄêÁ@{·±«ÅUápI)dÀß=~’Ü*9ôéçÏ[sÍ�‰ì¼j= «šX%³d ç-~ÎÓçóæI(z[LÛ²�;¶þ³wØiŠ{n‚«NÞ‘8¼\ŠOö‚Ó©ècr›²§ÈVËk¤aYQ¼+þx`›,¿5ÆcËìàa\TU¿¸/0|ú¾¨Ó�K?Ó5B�i é_j&Öÿ ¹{ÊqißçtdïYþ[Ÿ ½’¹‘µÂZˆŸÍfíí7yÑT,jÈÃSk-Xæ×H~,?nËpð©Ûøâî ~û|Ž0«T‹ûÖ81|wÆ»%ôÓ ðîô:ẙÐÉ^Y¦à_Á�íÊý1I>5× ÃäéÔR2“M^¨Ãþ_X;n·i—J F©ã”€~ºô¹�• 9–Ôÿ² ×Õ­c•˧Àd\‰TU1…ãSJ&Þø%ì³ñà\ó>ØÓ<�„ º5'„·¯XŽéK…˜ôuè5QøYÑQKŽ|à ÿ,¼`ÀÁ¸+{ Ÿ�¿AÏlÀ ÒÞÕ½›-±Õ¤¾w—Å„è Pn›F¾µóyæ­Ù`îf̳sÓã¯}p³éð�Ö±c¤ë½WíʿßÏìeŸæ] ·}.{¤ü&«Åï`ıžØúý<¯räðß+qú- ö4ìCí°eS>WÆÏ­¾Áà'ƒxìÚbð¨Ú¥ çpŸÂ |7ÂèÿwöÅ´GË9àâMØ{q;g´7pÿY³É9i3oÐðŒb;¹Nê‡ ~ÍTØs#Z Sç�+MðBFï.Úp‰’+.¤3ZÞRC¹Aüèö °4QÂ'ÃñÎÒP|v B²9š\R»žZ …†/:a| œ5Çð›E‹ÅïÕ_HfáêsX_´' ]çY(/�Êm{ð[X>e¦5Ã’�ÿ�qH>½·èr^Í2º/vcý&#.óÊ€[QT(ŒoëÎQ‰Þ`|ºÒ5gòê…vØždˆ6*V<ö°7Ž– ¢¹v'ÁTù! X¾‚n(Géû[H£¼'ÌI«l.AÊ�ïá¢L$>ºÕ�ïNåë ñéj}v.�ä+û¶�kQ4nÔãw…1Ò=3lqÍÁ±�QÑßÂûãÛaœk‘$Õx+FÚZáÌ_£pÚ»~ªª‰w^Xðt¹;8NÛ ®z[¢Qèp>—q >»õà!§òQ·o§¤§ÍeÜíŽûmúr“�)šÌ›‡× {¶iaÍ6 Þ<Ù¨ÇóEUÜâ´�gɨó�û#pn»1=Ù²£Û)ìå |û&ƒØ[€îÏÇcÎóMUâìÚµj<ΛÐ.zl�kƬã¸%ò§ŒËƒšYܽu;»‡à!ë3¼f«2'=2§-NЬæsMjþÙ[“Ì8ö�V¯]"|Ø­…²äM®…§€ö}”z>ûvu‘ý4”¸×Ò¯­ádhôV?)—ô·qÀÁs7¡°÷„´—›l\~C<–uOr}è**:™@r}/�¨®…éQš({d8†lwÀiòN�zG“•”x³§ :øŸõìðè³çlÝWë®Þ&Å�Š8)Þ•WÕÎD“ºUÜzÑ€ƒlUù”çTnº'zOG ³uUuîƒÂ0 <Ô#¿êmƤ9OM˜ï¯Ä²‹Áº4¨ã�x$¦DtÍÝÆï`Æêröœ·™ì¿êrL²9üè%Ï'ë9¸e'­û+ î¡BºªqýÎGÓí�Ñ,î…<µ”TCÿÑÛ‹ïy>”íÊÓ¿öà�U8è¢+”a”ízë7÷”ÜÆ/ò9pôg">=¤‰“oÁï‚q<~I˜Í!Q _L.“™K¼‘âÆ®2‹Ùo÷yáÛloîu2ÿ~‡#ªëqº£¥M¾NÅÇ„¸&u¨Ü–ŽÝÏÁò|#>½ö ]W A׿Zw}+ºß<¹»ÍPÙò�˜‘@öb ìWD¡3OÓŒ%³Í�h�I2�-6áý ޏ7o0Ø\ MÞ°‘@R¾Ô¹ÌáÊfVë6ž#¶ۻŠGß,äªÞ0¬ âüð�¶5ºoZ�ï5Ør½ç Fãl$g×\ýçœ6ÛÇ™—ó É2í³»á¥ 8}yõ^ÖåÍK'`õ‚“ôv¬_ŸcÍí^U8¡«kͺúÈ1Ç„ÕÔŽadÍ€ˆ½¸Cg-<ºG~IáxÚru—ŠË'pó¸Ý<8h/,p½%¨˜¤;×ÖóôÚ8uóÉîy=ðBv1½ Ó†ÓgA˜»®°bU7~êi/ìó…‘fiÓlÉ9g?£IÐ6*úC…ûÅ)#({m4jΤ·Yç`�«Ø5¸ó7øL:Þ™Ôh)ÒÛÞÜ]ÂËzG91ìÖ*ÖDÁÓ—àÚqføI~;->: ¯æÆóûajüp^ƒpéÜ:SÑqˆŠø:|ïë‡Ë;çSråøêþRðµŸ�ÇÕ?ŒñÙwf?F‡?í„«nѰ©›;ß54Eêhå; fÕTº Ýã»a¥“¹—,Å5Ø~¸fÏP߇†êÕÔù&'ÛŠû Ì„å—Ò¹ÿú_°ñ_$¯^ �je”}l)mTŸÄŸtOKW½¹ƒb£û9c³/¶BhüM4?·_¤„ŠQú®¥Àk‡òºNU8š=šß6�„¢Þ•czôS„5n0îû2LÜUÊŸŠ±lcv¯ðäW¯ÍÄñGd9d[úT°Aˆ*Î]:¾ÞŽ‘%šdÑäÎñJ›`ĶUeBc¿Zc«xN û“M—cNŠŒá`ýAø\b!Ž:¾†y-×iéT9ù$.·+ ï [àÜ�bt~ ½¾§¾¼¿J.Ó‡Ô¯¤óä:)ÃÕõúwø‰T³v>²ÊàgN¸ ïU5ë¸v€)Þ-vâ…Óû±ýºT¶õ#ÙI&U0;`ÿ;÷ƒz«w£ Ù[ÁªÒ\ÒI'HJ:–ÁöSó0ŒNÁ‹q¸P9[L¸ÿN<;!T|ó»/V)¼¡‡‰çqç’˜û«rž¤ºþŦÝJ87j6�>VJ'—pZ·{´°1—JÌŸòÏž¾\éX$̲”EÍÓxeÅœ¦PBá#PPø^ Óê†ÞYÓ-€þÙ/)Lm(nº_~ÁÒÓrà4é%t{p‘–~ÒGË?2<Ôù˜ø²ho]Y E»ÚÁ·n:Ít‚yãË…E]¼•¥lê&¿rL‡Û#¨]/À¨~–ä}© ®ª†ãÄd}Øû”¢‚‘ m¾¨½L‰/é/£}~“õSîB& §‘Ö®Tàz™j¾¦ÍÕ#þŸ3*´8a%Î/qç-�]±-Ö˜÷¥!µìz1=ù^CS§jÀ—^ÊØ¹%ö�»"½ú¼?öÕØ÷žìÂ'ѽ ,N�-Žvù®Ï .ûZiÏNP³�1,�”ÁÁ¼ôÊ@Zæv øë–xA²Õ¨˜†>ÕEùüƒ<ø\„Ì ¬ª—p ûx¿ï‘“²]HJšÞ/u¹ùàaðÁ¾ìôs)9'jðŠ˜5<±>[pïiË7ÅRqäì ŽÞ>˜ßýî’}ÕIâÝ£|pKf$«…�ç`^ÉaØÑ¯%à@õ—c>–«á©¡›À/±„C5–ãkkC!¦æ ¸½=ˆòrŸŸ `~sEŽ•â3…ÈN¿�?PϾPv­~—€‹õ0Üe� ¬]Î#'�æÒ-¹¤Kî£bñSŽÎ Î⾺õô⪅—Yâ¤?'$wR׈æÛö‹{nÈbÉì_ > W¯Nâ-·›aðÎWöÿ>íE+7úûÉa£© ]0æ]5ÍÂjõ#x¦z~Ý«‡)5¨–Í àÞN´èO:‹Ò[vý›ËéZ} /|%u’.”¦?®Ä¡þybž›]"Ëv÷â1Tùîüýœse9ÄüþB^§üyòVü*&ò؉U]#奺”kÑQ-óøÃI3œ�tóBwÉ)ð •KðëÓpXé¨+ÃW~‹� á›É[I�mÞ|vû[ê�>áS„œ‰÷¤ãgk‚ɣiÅt/Îû7_›á¤Œð©@—b[7Ã*…Xê~y6NMÝ«´^Š »¸ë›È5×M94¾‘ûÆæÀÔº®³®Iáá9ðzÈF †ýðh[3ÝÏì€ Uy¢ž\k儊÷x¶IIãõiiÜ2iôŸ^Bw¶Å«þÁxXfÔ™fàÝH}º™ »¼Ç¡‘Ê<ñÛz)Œ”8?7äïN3y¹¼,ß¿ŸB½ìíxq¸ K—ò«»³(©^w¯ËO:у^ItãÁz4�Ìñá½pð“bÝ!ò?=Ià¿¡à¸m”8ìu$~�žÄ+1õÜ9ø’*¼‹´Æ~;e`|A̶Vä‡ö§é–Þ8¶ò/¨×9r­ÇVŒ¯ŒÀŸ� x¢ òÕÒ\Hè£ŠŠŽZ\äJ°ßV«êßÇ}âÄ�aå‘%¥™2´qŒ·¶tãkÿFòÅLŒGJ¡Ü7°Pˆ1ê�:΅ظ?,�Gˆë¼‹ášqoô(� 972›Jü:°MðÌì‹“Wn­ÚÐê�¾Î½ñˆK -@^pä5,÷ÝÁáí×it„#øˆfwú KV[Aú¦³âúL…o FøEÿ}€Å�x™IËiL³¿„óP(xÚ=Zàw\<7aüùüj‚�}Çþ‚‹^Ò(§ÉâÂÆ¡¼Cw ©ŸúHs éÆâÇTpË~ISxcÄ@éy�Xˆ6Ç ÈWž‚û÷`»Ökºu}2L(Ð<8„·6çâÛ5…xñS2Gçqïã4¾Õ uyråx¬·Õ¤cj#ùàÔ4ÞîâÄ¢q!Œpà'~ªU·Ÿ‚µ•)¼Þà„R_*Δ¬ŸÊm+REÙŠ[5§~þÖeUÑŽ5fgŠÏþª £}Çd›Íä™ŸËÆ,‰WÂÌp-´H0Ä`wÖ�tT¼ÐO‘N¸ó´¨´�3_¼MódÜáeóéÝýd#(9føøgãÛ„�x£ç>¡*¯“W¨Ýï]¤’Ë}Ðöž �ý; T²éÔ¼1RÕªóI@>&þ«·áÛ–B£‰¹/ÿ‘d5`‚—)|‰~ŵ:ßhNNwÔønDI•¡P@Ê8¤î0¿ã…:OëøZâh(�¬‡_ÇBDšolë‡+ÔßPn—wŽ;…w§=‹î»Sha"*R"úíËf±¿¡åõ–:OƒÑîŽ ÿtOÁåÿÒ•7Ÿ ý™û6wfg� ·Ìâ/>‘€é4þœ טÍá›2‹Ä:C=¼ìè�ù“Ò _Ù$~&«‹ã½]µxÑ”,^ýÈ‚ýo8Ò� ½Ù9¼&´‹aí*|èÝb°ËJÇÜK&ž¿ôç–®î8]3›B½¤e­æ ÿ×bÚ´yfÏu¢ã–hüp»-XåI"4QÛ:^üqÅM�ûÉ«#RˆÉ×Á”þ±Âù…Â^ÜEÏîEàí* ¹AcXóG$Ü‹ÅÎ(ñÞYпUOËÔ8³$:BÖàlôÃÏ3õs´¤ /�BÞè�¢ÒÍ#Ò‰Ù‹i—R($鯫-pIu2/0J„ºþÔǹ?¾°ú.ñw+#�]ý0߯þ��÷Í„V­i¡yÝþÀ€ÅÚ‹áþ{8ŽõH…ûî‘w~IŠ~Ò@i'��I‚ßHn8=²o8â§�2X³B�¼ÞwCÝñPn½”Æågs›Ü8!ÁnI”æ^¦¼ªFqJS]›³+¤GÁÇÌšv®Ôàµ+1&ê8$Lú ë^”‰wúj‹n/÷‰=¯Vó:?üÎ�”±ÿkkqgöSz}d-’Dðù~Å X¢ ®xÏݧ/Ù�’Åí�ªµ…‹·J)¶%�ü—ôáæ;Ðç£,ú)Í­ŠÞ(LsGe}9ì3í-ÿ÷â ê¯Ne»ú/U7µ"Pw×c±Éׇ¬Uã1ÕIøqÊû¡&Çà´±ŽCü…îœ|"·^¥'çÜĨö�¬*A…Ìï Yñ“]ûñÇŒŠ|'oŽÂ^B:/¸ÞÀI¥ù¢uñ`QfëZ±<ÌG’_v˜ÛMáXãXÚ“.|¸*ƒCgëŠuPC¯;¸¥½W]Û ½Úž‘ÖÜ$*MQÆö*˜`ýŠB2“Mªª8Rk¯7¸*„ ° §˜U¸jBE�Éç«ûe«?&+`¡a4ê8õÄ÷r±(ÙµT³tIýáhxs.lÅ€Ù— P~ölÙ@+†Sù›ª.®ñš7Óètž<Ö˜RyÖuIL†�ö¦´Úâ zÏØ—'l@£�©´Ü!�¤³~ Ã%…_�q­U-ìt�T®Ö“÷…ñh¾³‘\è¥`�¹‡æ­ìÃ{¿¡߇‘VvT; †õÊò¢“�×ÅHÆ›è·c‹ð±ý,ôëÁStß’èé…©…VøXÖ’[¤†8ÎHƒ?;£µc† ¡ç<¨-ø†t�šzÓ ½Â)h�–ÔmFe­¾Ðpp+{VƒÿjaþÒc³�ºûÆ?ý½ßîJà ÁáÅ;øúß=ª«tÛÞí!ŸMÃ9jm]þæ¾?haƒ<1Åî'?K¾|JÁÚWc…® ø^úl>u9 þ òÛŽ ×Îé“•½Їçã=}¾#;[Üt"�F“ÐWËc6›`ܧPaæe¼1ÐCœr.•#V­á±[F í§àѦhü¬;â,gžÛ‘.¦Å?uWgrz�\[ÙƒçnÕâkÏ…°(Yì±S;À ? ¾‰|Û5Fß&'ïk?ÿ­¸ðX(PR¬ÎÕO †¾ñ0­—tí+ŽQ¥mó—Ñï7ý8EÈ·Ÿ‹så Ù\%ŽW+ñÈsÉqð�G½0­PÊ7‚ZAeœ3„ßK—Ü¢j/%žåv­„vªJÌ�)ë@ætt®Ú%<´8©wçñ•+¿¤ÕPS&Íœ, uÚa´g]¬¸8j�àvn>hÆQg¿ÑèÙ‡Àu{_ÑMÁ1!”[¥O³°£n™`—¯NÆÕVÔÃ{.wèß„ ¸ê¨=†Á/¸ždËsmíHRìÂ#ª[)¼à¨´åÕˆx¤�¦&¹”ý@F¼WçQé»pÞOc<_µ/6×àÕga<Öúºð¯T6 &÷®.ÿ2 `]Á9ÐÉš�£ËÎЇdÞµ~Jx"ydÌ⌱9B?Ÿe(ÑO‚îiÏ©Æä¡poŽ)f…œÊd³ñý8çÅ&TØ1ŸeÏ‚õZxÉï?î Lzô¾u¹ß‹!¾<{²/îüì+Ø+<$½\_¬?t…ODš“hÜ*ÎÁ¥tð(E¢;“úòûOitTT�¿N‚ü÷=”\?™×ù÷Àý¯-ÀÀË•‡Y[quM<\â‚…G3`Ï îÔø ¾ VFaHož“véÁw˜°1|¦{á¢q'Åè‹·…eó×q­×tNT)Ø4)!Ëa¤ò{á¼8�ækì…ES½8à²Kå¼ÚV2 ÿA;¦øRµÁI(•®šoîjÑ,Pž^(©»þT:kãŒ_µ�šY�z`=L� ý×äi÷®8XSkÌ›^;ð õ.©ÂŽE‡y_¿nP¨ð’ëáúŸX|^ãj oTµL9 ?ýNáðYÙÜoʸ²s­V¿A¯ÇŠc¼î‰_R³ÕõåBBÓ'(’�‚l_ C¶ÑÈšw‚Q•?ÿüo0¹ �±ëŒùÜrcÞ×�Íâ0Åt;ÄõD½ÕUÔø]™K¢¡»K…ÐÃý±ôÖü!‚S_€Óžk0äô5Øù`ÿ™5ˆs›Á¾ƒG0æT[ ?XA—Áq{]<È�Ù‰4i©„/œCqá_)5l$øÖãÓsw ¢ð'¤÷ëÍ©9…• µ‡Ø*s~ü¸ÖJƒÀãòP öò‡â^P«RM=n¾‡¤Ë;ùnö$ññ!Wèf/:–¦ßÙà]ù‹fÎ7¢Ëf`{ºFš-‡-çœ;�oÊ‚i�ü¢n:÷ÃÉvÝñûüa˜Ý{¢¤0£”Gõè ~Ü&¼ú*‹ ꦢÜúxî–žÏgIeb8™-ưÑ3Ÿï? „—gòÅÙ·áÒ0ÒÛy˜+þÇÁyÿsý½ÜNö,²¥!*IÏëÒ¢©ik¼©´$ ©”d%# %*[[áõ¼.)•´(-¥½K“´ûú|ÿƒsnç<®ÇýþÃ9ÓmášÜ8ѯ•F+nà{3/Rí+ØeÏè7u>¤%·ÈïJ8l‹¹Ã“•'rËÄ&á"Ì•ôULa…‰H]¹–rÏ�⧃‡aʘô,Ö�ŽøG¦ß—‘✘£TÖÍåyxÁl]½Rë$SÐÑ'ŠÜ#øæÉž'÷–æ¿Sáï‡~Á�¶l:²`«loÖüñçe=e¸-oß:3…ŸHƒ·Ë~¬?oÁ*²rüâ³is2¯?™ {Øp úY\R¸3’TÄÎ%=iÏ-kü›™D¬Ô1HÍÓRµaŠÜo S®Q;.˟̳ñÎÚS,-ã@¯†þ�H?gšÔxþ9åÕ/Ñâ­i`t”ÝåCñ—Óa`UwÏŽ�Œ&,ðˆæ,üéáÌoSå $¬ÏB{9¬Ø¤L—�]À¥i'k�ùN–“¿ÂÆW©¾sÇ&}†{Úæ tΕOî¡à“k×®j¥û©‰~,�¿µF™Áq÷”@Î|aÓê D&˜Gu÷sŹl(üÛ!ô=—uç}3vEqK|Ýw>M‰‘Ò¸Ñ-‰¥5Ó³ÿ†aÿ»ãÀzw•ø§÷(ªòEô_*4èBÉi'ïÚûbŸ‰ ¹z*Ý>þ–Žj¨ñÇ·Æl ó\°è!äôÞÁkŸôâE_NƒA‘€ç^Eຉ‡øÏ,}z:í¶¨Ÿ8{©›w÷êÔ÷=Žá³n>ú+O¬ËˆÆUÇ¡Ò�Ô¾Õ�¿ �æ/wµ¸s°ÿQWä†1“qóý°çX8ëu3ÕÇðÝ@7Œvò¨µ:è´ÕŽ�_ÞÍŸÖÝAÃLÅ‘{“xÓ‹ñ¹ÿBšg1–)ã ˜yÀÚ¹ê¬ûY—�üí/N}„Ó^1ÞÚ3Ÿ‚<µy¾L¾ŽÜ„Cgºð] +6m§öŸÈ†Ëo€åÔLÞ©oÉW 'ó®ÖYØÝi<8óðÛI ×1ÌœQ/²ëQÛDaÏ;;�‘Äýê qµ×5Þr9Þáæß#‡O>üß®TÒsyF[×fKž¬ä¯:ÉüF2‚V,p‘ä$$ ìRP«p,oÐëÍSúñ½‰í4B¿ÝýÂáNq�ÄJþ½d×›„rcÏlœq(‚-ÞŸ…˜?žÐ³é 3fô‚«é�´ôo0oRÐÄ~&ÐûЇñûÍ£YjŒŒpbS¾Ný—%Oc¿}Ñu~AͽXrÿÆÎÈ-Z´ÇÔž±m:6ž€Ö6ÙdÜeÂuÛ½èÄ¢4œ@¾(›b‰Î�<äV(ïoÏ#3ÍùVË}\Þ븸hæ&ÜZ¬†¹�!’E–l¨Tˆ}Ý#LJ6˜:ô2¹­öf›ñƒØÚr|¼5«ÎÍb¯Ç?!§ý6Ô_;¿�¤CJ;@3z&潦×ó£8Ärª^ZDS¬‘|ÏõÇóúû¡Á#S"%U U¢¨Ý°¶ú©Ñ¡æh³mÊ”Þ4î¤Â¾ã+EpˆÖ•KÒ³–�äÉgR/{ ÊÖµCYͨN©ƒceðSÐ aÑ»ý0Îå"Ôƒ=ÿRÖ@¿Ÿ·áùŠd!Óø<4ÆJ» pÝq(NXÍ…Kë)=¹E]B”��g·­#©Š-tmüA~’7_ªjóˆÓ±,/—ÏÝColQÌÀ1_ðŒýn8ÿKŽmŸ¼{ZíÄÝaQÜÜ)4…ÿ�ßÏ6ÒÊýá¼ÞôuªžÙ­}HJå WŽˆL¤¥—ÒaòÙñ\ýÝ—b÷ ¢ISŸÂ¤Ê*õÊ�ÍwEé>»éºÑòV¾.GUiðÑ~øéõRýa T©„fELðŽÕ]!ìò(>ãK¼˜”NfÉ·ÁÉE‘¬•LQ fò4£0 Vé…rç�K¿å°FJFh3WÕ½Ö¼èüCš¹AŠNO²EãËêh»€‡ú(4Ñ}±zæ6(6“Ç!Ñ !xÍSá`çl÷þ&x½îpÜÑäÎ5&7áߊF2NØKŸÒ̹d™ Ä½í‰Æó`ïÓ$½/:qbãna¬Ì~=ÂŒM+Eïb Œ—Ù�g^úSŒ§ä+xð’éÛªÚœæbúºl,�eÊt‡–[;Cí N[è ÏfKñáÞ�@;û=<™ùGØeºŠ– Û082_:óØ“ú�4æ;wÑ–§…þM—(8åž:¢~?ôPË?p¢¼¹(-îÍ”:�íû­Âf}áëÏxŠ—='î»r´Ý¤\)ï‚ÒÛá�ç>äTUÌ[±‚®d.�ñu)Ð<áp�®“ö=TØiBLÈ\Ýk\ù…Ó+¾õ̆Ílµ;†ò�³£éÑÆbÊ•Vy×±¶º0Îp&ªçwÁæ{zœªñ�7O¨ÂgWró�A¸NÞˆ«<™æú7‰ÎSkùKõ1TæPV81Œ#žñùåít.S] ƒ§€¨èi‰ý*V;:´ ã7ëKH?;•gÿHâ)òJ8«ÏL1vðûVØwÀX°è¿_Ô¯î7Lކ1²GQ>/Jœ}`8Ïk¼Ã?ŒÖ¢˜Y‚­OxØz�Lv�­fáýzBO=äÑ‘�Å­9òüË©œpê;ØrÇŽ>?"Zû§@€ÛT(±9).Þ Õàð°T”y•R–lƒ5—¶ã€£/„ƒÍKhAs,èoìvð(#ÎvûSæoçq=ƒ"ñ£b:Ý-xÑ�� Ýjƒ‰²�8gë’öÍâ—gÁ ·?ÅRÙÅ)ˆñûõiåKxýt,Fœè‹ÂqGAgG0 ìûìº8£ýÆc&¾©Ï…Ð�àüðeJ½Ø1p¨=؃›ËΊ#à7d„t¯cÛSc½‹7^)fJZý'�«ÿ„ô§Z˜kf‹ûmÃïzŠzý ñî¶IbÕ%¢Î£E(9¯,LSŽ�üùf…�nî•XD/'ñß.xâ®ÇÓfž•–- [ëÓ³�ù�º ¿:¿¦Cƒã�«È^ýUÕ»áŒò8;»Äaz·[­(ßiÎ�•¹.Fo ¼E0r;l|†ú8ÙBÚ”m�/ŽÿWÍ¿ú¾¯,¤ðÜý ß.MMϬÕëÇŽ;Xs‡,o ˜ƒÇ”MÈÊ ¨—Î`öž×¿€¶Þ€W³¥±vÖôÑ�ºšø¸·ƒŦµ[ÉÎ[Ÿ/²¢©?Úiõ…2p8Ó•‹—@|ÓLÇ·o�‹÷~Œâ}/Ú(Ú¢“O¯—œÏÚç¨ý´Yl:¸ï-;O¡5)C˜Íb ûÄd:Û —ÄÏ¢sW¢r5aÜïù8>[Ÿ0ß^޼È`ŸˆÃÇrŸ7yd¡Aº÷µøî <­‡3L œ�kÊ'ò#_ŽkÐT9‚&¿ßÎ=ŸáË8/œa¨ÊæNשÞÏœ Î ãªHz¤O÷Å?5|¥2‰ÌVHáøEÝþ0W‰BΙÊBqsÏB|º}{VÞ ÷ óÈøÀ ÞS{¦+ðW5Üu|<®š­ÏãË®+– ÂH[0ÜWšy]â¡O¿¨XÿMÍ奉°¨ë…0Ä<ž PÁÁ˜éhè>Mð“�m�G`Ì£ävR ¿¤Æáœ½™ o,Áɾ²hú¢7¯ð¨†s÷’ýöi\~¼ Úçþ«�=…Kþd?�ó6s“�̦#p°ç#ZT-‡ý ;ô™ Jf{ààdzàYäë`¸ÞG如[¿äÛÍÑ­$[�úÉòšSN~㢸`Ïx‹Û`̦™p§ümÛQÎQN!<ôÕÌß¼ V^{F8>™ÜdF"ŸLãAîíÂϹ�}E–äùÏĹé3¯™b[R6ìx®ÆCk®Ô ùþF´1£fû·ô~ïbǯ¯QÏôÌ7[½ŽX ƒ•4YÇ!Ž@Q’åjG®)å?(rÚS®úö¬-sñÚ”·à3?Žg­| ·¥>Š '@Mî|qÓœ¼ï\í2Ö;oøsæ:¾ÙM0ÖÞ†áŲ°*Å�m^fAȾba½æl¶ íp¬ªz+æÇ¸t÷Ôf¡~l ªœé ‹}ô ­!­Õ2l¤ðT $¬üz'�—é‡N�qö}oü·Zšå#ê„,_OVµ< ëŽZ°2üîçζµãް½‚¦\_^ƒÆ˜ÙSŸÕ>tHê8àœaésãY:ôT™:Ås`‘-ÏÏÅtƒ\<½r59ç\$™e\°}‹¤ùl9Ÿ™Ã§Èñ°7¥;U §…¤³‹÷<Ḭ̂ĉËçŠËõ;¡1uûØ�ô¢^ƒ•‹�ìË.ÃM 8±M,Šýþu,lûN!㎰Bˆ9êœTÃŽÐD6Û½C�ç„4pGåƒèìáó0²-Pܵê9ت–¼ãÈ)f'ŒÎ¦®õõ„J+~ý½Š�•‚’½­øçñX±æçKÞ1 K®µa²É1,±Ø#ÉHÚÏfÛ¢áýþþlDèEç¶8s†·Åt¨±úÍÚmÛTÄ}˜.B0VLÇ^Ï©ÔèŒ�é·Ž�Ç–ÁŸ€:jÝëŽ!ÂÞ-¹/<‰tÀô]Ã8«ã™°Ó †K„ñlU•… ÜÏ@Õ4ÑñÅp[¶¹yP’˜°�kÄ>á®ÊnCFàè+'Ѧg—»ÓÈÕýxûûH¥ÌsröQkï»ph˜,6!#¯ƒâ­µhv´–FÂNü¯Ýšû(÷w\(‰âXó±¼Se;|Ðå¶TWRš!Ï11 ¾©øÐbšN{,*¬–âYË<…¾£j„–-êìºÝÕ1äµ3¥š\¥—Ϩÿ`7ž2 öF�à”:žÿo þ×í=ôh¼izè< ÷ü4Ǻ[ãÀÔí™Ð>ï©7‹®¾‚¢Ö(–ŽjÝ,vñ#½Hè-á¹¢øxö랥ÁW_ ÖŠ:pÙè$GÍs¡ÛßókÅâÒ×+ø�f÷ÅaJ—¨M«gŸÅ9g‹…Q¦N¨œ4#Öº±ÔkinÉ>ˆƒ¥Á–ÿÑÝ™×i;Ÿâö!ëÀÁ! š‚za¡^õŸ³Ûö›gÎ�æõ$QÉúÇXðh�íS�ŠOSùè8º©'_÷6Fÿ[»Ø·éyèWÁ Ó�à`?$Ҩа §¾a¹�rNÉ�'P]©ÔëãÑ÷îDž1-*äåB¶] •Ý ¦19ïHæ… Œ‹Ž„YËRiÊ‹;ôÙs Xº(�;&eBû‚Îõ ŸŸ–£mü‰îŒ¸/ºmN§³A¼>y4©dâdïQl_—‚·åŽ@ÁR¸žFšSÔXnä]QkònæÉ�!.Rßå·HÄé�°ô£3~‰jê‹ðIàéµ–V^•�4%|kó!ϋڴÉëM[úRˆ—¯�•ª4l“& d¹ ¾p�àôå…¨·N†Ö¿ç<Å%*¨õ¹ë"ÄöÂáÅܤ`ƒ™㡳£”ÜGììÎôš5¶ŒÃüÔxµz—pnj&=ÿb�}C´p|�=·¾Í‚„[ ý½Bº?xNî º}R“�U%Â+óbНìËúy Ât›Í,ýô½þ{^ì[F_ú·“ý˜ûà7ã°p§ªûÏPBrÃ[�ᜠ9˜“| –Ì„ó&ä“v£“ø3ð9 ½áÎV¶´~º::˜Ž3ëQrt꿚!¾”sF…¿L3Àz„˜` >¿ Fýøê#ËÅïuÊld+EÍk}û“yæeL‰Ð�£è©F·dZ…[œ6Ç‹í;®Âɾ±Ücê70êÀËÎ�ù!ièvC“ìbŒñ¸{*�ÍŸsêâqzµ4úÜH‚í=ëQõ¿q,,S¯¤±×Söi~HÞ s!Ì·P<ÇH2È›믡9(È* ¾ýˆå¬�'ÅÌ«"´úøR;{Øt=˜_»¥IêÔÄJ5rmˆbG[98%}�•?ý&™«§¨ÿ±Ex7õ¤Xü­„¦ÿÒâ³µÙ¬0ð‡$iSƒ¸÷Ž7î௉1´¹K®ºÌìžwGÑzáAm�+~8ƒDÑtoþ˜SH–AÍüáv©cÜ­åT–°¶ìÜ*ès:�ŽVå‰NëL¡híAl ˜–Ñg0ãlÎôh£•*�¢›V2÷òD´’[‹Á¹:ûÍR* fá¿…ß迸g ÿô`´ëm±¿­).øAwúð�iÞ¸7x Ö±f…Ëç¡W›m ‡åRÉhùúŒ¸·Kÿ]^$6¥ñÑâ:zá?‡K4ÞAƒøÝ±í÷!Ø9ó5T.àÁ‡iëÃGâ�Ç86(Ýï÷¤u…Õ;_ŒÌÇ­²®v >X~.­®‚s7N ²�š8ñµ.ÎêeG+j¢qv´§¤A󬺒Ÿ»cMs$n� …Ìæþ4d¹­¨´ÆS|s�"Wž‡£F…¨ÈÁؼ,ÓÇ×€y^1¥u¾î™‚+tßÃåƒ$W+ýñhôdÎIx v.·aÄ”^œä¯Èù‡ChAîª=–K£"ßP¯"C<}h,ø<1äïçcaÛk–‰ðG�ųàhùhòšÎ·¦ÙâéöélbÄN.Ólû9bþ¨?´,¨æ6תDàì_x]ÿ_b×ö.x0¼ZX—iË»{¾ çþÒ˜kÈC¦6�š‰žh¼ø<]0í�ÃŒsPÊn$Ý~Mé2íÔÔ™ ^å�Šã¡Ñ7“ÜÂñqn=ÐB½ \«¶–/Ÿ˜;<·c‚�% ¥(©@‘oϹ#>“ÞëØ’;å,N ’BÖ|® JôÙ:]OØx¯ÇÉ, OW‹„{Aø#uT“Š�L5pJÒO°uSdÃ>Y6]�Û="ð’ý\ºQµ çyÃ]ëuÂ`u�¬ÐoÁ'úÔíW¿vç‚ûƒ H(�ázfµ™Œ\�™ÒØðø¦m¾ÂÓµœXóð7Q-à*].Wà ÝÓ‚ÜR=þtw/˜¸&Ñõ6-X™Õ æáPÏ»ŸpæïBñÏ0=mÊa͵£Ôð)ƒýb@ÿ‚´—‚ýÛYP°û™0*öeaѾXÛŠŸ µ âî²f~¹|pe3ø\y þeEš1Ž4(AÔÅRØPÏNCÏq�ŠjÎ(?L_#Zü)ï÷|ô Þ€½ÿ‘Nì6ŠVm„õ'›7õ�y.û}…‰Âù×Ð|% EèÍN[ Xý¾À9Ž’%vú\×>”ƒ»öáemœç¢. J_Ê?Ã_П-ïiå¥h¸í=]Ù°�ÎÕÀm÷5xGè<²ÌuáK- ŽKϪÁ¸I}ðêä ™CNY¹°nŒ;Y«cQ`w»½Lzi&¶?+HOQÁoÿþÀ« úÜ6å I¥êñ0ÓBú®RÊÏ-cÃþ&(¿HÎxi±‰N_škÙ£ûÞ8“¯çyÉí’Kt\ã\·•ÃoÇ5¹Ú¥T8åx�†t½€,D>y.ÑË„5“ŽB\ƒ�’Á3|¬ùü°8X)�bïmŽq×ÌðÛè�(öÜù/´ùlÞ’?�sÛGóùë3”Ùb“ž‹¯mì(Ág÷)8DënžbEu¼P²›=ƒ}1â“,™>*ߦ‰jm�Øùc ØÕÆ«+÷;*é_g�ÆÜþÆqVæw‰Æ˜\ž.‚ÿ7Gœ%Ó—{þrâü|i¶‹‘ã^ùÝ3k€¯ñ=‹QÞQÐë§lnÜ‚–¶�´Äè,ès™Ü4:è³\=÷¼¹ŽççÕÒæÿN°m³1jmúèXpá,�ÌïÃ哳DýÙ>èêµ—~UlGïлôüëxåÅDšhþBœe¾7»=„¼\e<ö«•ndMÀÊMAôá±.Èë @º _„ãÞâËðlû,¨ ¥µµâ<ÿº)îe;ÃfÈ�5â–KÛE…馘f'ÅOn±Ñ%UÖ3h#�†bº4Bw­Œã®xRZoUª,kãÄ+× Ry8úßʾ2™ ´Y:�à-yÓ2z‹1!pm�Hؾ…#Á…MfmÂÈ«o@)F–ßF¶Âº7Éd§¼L˜}ê"òH†ïÐmq=Ê�âù7Nb¼s [I�ÅÁ¢<…䬠³÷¦ƒœ„«›{€{âaáE‹Ó‹ ðt½/L4ÿ¯ŒÏÁ¤,ÐY…»|Ãqö“X:u¢–ö¨]‡¦† öÞ¡�s6*ÑïeÏy‚­!¶—V£�Q5l’˜Kæ¼—¯Ùø)·÷‘bû©uâšÔ‹Â£S'¡âF.�ÿr™ÜÇ21·ÉúÖ`˜ùò©ø2Ê$ÿ•qĉkÐgøvˆ÷Þ‰º“Üc„úzuÚ£'n*à¡_ ÙÀd NíÅRÝ~ñ8 Ÿ+Ìä9p£/÷ÿ>U’ÂpKšÐ½^qÌa%œeD®—šD•‘×ÉuÚT~¤l¹ž7I[ÛGêz Ï´ZVŒbŸÛÒ8xÌj>,¬ YÉ{Ænࢩü ~iÍûkì(XÂÃç˜Ðn‹çÝ !%8.|½$]Ä‘ç5qŠ^›O¬§úÐalÖ)�.»Èd.â²YËqŽ\ Ý|9ÏNŽ"õÿýõrúÿ)û §NCSrÛ=zGË+É\,A•–<Þ×xVÝ…X’ÈæûpÿË‹xÛEÐ~r™æ†Žæq ²d÷䀸Žd67=z÷‡"<æ)Oà†¿–x±¾/_eu°ð‘Å C§Sô« 35|ã÷†¬Mëž«ÝÜjÛŸfÝ¡°QÛq¨J¯ìT¥äkAß" Vc0WÚF¬O�EEs`Åé»4÷ñFQ·c2P/þ½KŸçå�×ßémk­¨è.Šö™zd¬²š[ŽV =1:õ½Ê”æ¬1·`ºÑñî\ܹ;Ï”u:Û¨Åró*Hø¹‡K\±íÄb‡�o†°Òy Ÿç�Sß|…¯ÊÉÐE†<ºÙäë¹&¨™Û s]0Áõ9eíƒüÇk1iè šXr‚-¥�080»¦�á0Cü-=tþ…½‡MwcÐÖ ôŠU„EŸdjŽ}G\‚VoWNL¹÷´à“¾ÈÇò�Yàöö�dµw¯z„�\€’Ô»b›æZîu<]lÓÂÏ­tAÕ ÖI³ï c’ë�HïÎîÄ'…P7æßðFúšÒ:ÏÔ ËÞÚ¡GþaQ¦± Äk6¸S±M4Sv€‡òVÜÿu<†ý9Â�²;Ðhâ$ÔÿóÜqWn Ü,™!Zt’¬^)ƒOÇü÷Û±_`ëÚ<%�¥`ÊõÓ°üÍ.×^êød)ÑW¹J˜³8�>-éGV߬à²A*™�[Å ô=±±ô!=Jpm~Ìg鏨H …ܾ¢îïyì¡; ÃBTÙÿÕ~PKm¦¯�túP3͌نkæ8%ëàÌ_¾�"Ÿ€oWæ¡ÛUC¾×¹–“·AeE^ÿœŠ_Cíâ3âúÏeâ¤i!Ž%ï ÷å ´Ú‘Êʼn˜ û Æ+½îŒƒ€‡Hùž!„«*A×ö½|íZTØ‚‘«lp˜— ËM܇¾C>Ъ÷ÂúÁlç-ϽÌgq¡ÆqñÆ�õ`qü€pï¿ÉxæE-'¾˜Çdï‚d¯%¾�™Â�‹,¹=Ɉw؆ˆ0¾Qp^s–8ß��Ó!×ܤƹ *�‹hÃb†å†¸ï?+Hëã‹»]i¬Ô~±`v¯Z¿·ö¤«?ãÓu�)qôÐu8)îð 'Fߥwdz¸V6G3»Û[‚¶“Ö¿t°Û"5m3Ñ&SŸê¬¥»ãykÆHž¶�†i}â´qI— »Ÿ0%¬4…ÓÞ›àxpa€7�,í Ò�~Vš&Š¯Ö áG³÷‹_~Ïõ“¦×bWþšùÖ ë}ôq–޾´<$|©NDZlñÎÁ¡¸÷Ô¼b¿ž<Ý7Áv“Tζο¾ÊÑÖŒ}Üû�%ˆZþ¢ÌT-0Û5œú·Zà—Ånüºt#[M~ qÁX™xU=[P/ø’8q� (´VÑ ®…pâ~1„&DB‚¾%Vf€¹“–Â]™Å¼bbìÜ\#ÑÍSd­5Ø>m¸Çy“ž@JÞOa²ê%AÇå¼y1Müêÿ tÆÌ¡§ñû0Üì-YÄÆ Wd"`i²:ÎJM¡€9¸q¤†G�†þ#q{Œ&j±Ã�aðȧ—Žrž�° “êÒÃ-o`Í/eÜØãôý}YC²ÐòÏ0˜{å· h�çÛÏP�~<^¿C>ò™Ã�Ö‚õ»gôŸÍêùb dÇê;Ô¤¨Ë÷ä.Ù/Z»�ç»±ÑÄþ¼Û>Êzãgcè×·Jž»s(&�ßǯ'´Š3ËWàÊ�®¹J !äO>&ÆmãënгS!¨ñ<¥#ˆ5Î_ÁlW~ä¥Ïå+J[¿f>s(�ÞFôbj|çøzA :õ½L±÷�€²ÇuH~é!ú”�ÂD\ Õ.‰P·=–£;âž)‘~ÿ^¸]¶‰‡J%ðrÅo’PaäjPeãg!s¶ç5Ùa€Ÿ=¿ŒÒÁ­ wèá"Y4[,‘xç#“¼�\c’ç8wÉY˜XóˆvE¯¤IFw…ËOã@;CbÇhœu²¿€oßJ¨ï÷&‰ªB´'�¢õÓ= ¬W&~õ”¦ÁâÜ›<—P¢õFXÖeÅoÛcx¤eîv<€S-n¢†¯ÿ¾}‰Â7Gâã1fÜpn+•ᘬ÷âÙ­:x,rþË2áKúC8`€.ó4 °¬¾}Dõ!µôúïs¸zæ­Ð{]Uy§qÇ™.áËÕ8½ÃŒ·}’‡§¯&aN†·C…t†põ·¢°-p4Yÿ•˜E2¸äÝ…$‡O0[Í©;£ßh€ä¨øxíü£ öOëA*«�]Ÿ"ê9†yu8«ôàeQ�p1l2>Mm„Ô[/éÝ«¥p6£TÿÓäU ]¡qüêVªõ{¯×ß<}Ý)zÌY*ö‹é.Öœ–1·ïM„/�Þ“’ÙVÂ…œÝ)‚z1n•4ÚFŽÅÛˆÕ0IÔÊ*€@Ýžx�†;4ÄäÀù+7`ñÜñÏܽÔ/ÃI<°M ]\~�Å k6ºq�οÞ,š)…ròûÂ"U5vW:�ҳƠëâž8(ÿ' ’>»éë5o¾Öþ—ÞMë…#Fן^¬3`:÷µõæÀ¿Þ˜Ý_Çž†ø·!X¢°H2((™žºgЈzyî;[ÀMOgsâ�ó¼þyæuđ§’-y¾ÜçÚiøÜ°“,}ïAù2–UO1Kvcò³Ljë¥Í¶ w¡âE;*ˆçÕ›´j}'X~°Å–­¾8uî-HŸ×$d®ø¤c/¡‡ý<­�厗ñ§søÊÿÞÃ8<„g_ÀlÍH �?' ¾…?ÅÚñ÷�jü¥Ã 6ŒºCoeÂHôyÒ4/ÿžÍ—øÍ·ƒ‚XäKf�eüdè1<6ÅŸ”˜ãÜKè¶¥Žô%³0ñÖ8ÖwM�SÆvãûÑÙtЖïnÅî.Ï¡E£c§Òtîʱ†öQÂѬog«G¿…æN ì]dÇö.ÃÃ-Þ4)؈5ã& oª`ï>Öxt¨¡pÝ#›)ÅàTádÙÍEû«a§x2,&àÓÁ7AáÓmàð˜Vܥ؛/%ç7ûpü�A8ôÍö¯Pé)¦Ø7C�—h¹`¾Ÿg,rv¶ÀöÃɼðÉb¸4¿ª¦É⯛¥ÉÂM½©(ûé ©v¶Òü�“8îI)Í@ÃÚœùÃu ¥k‡M£> ‘£Ñ£@�o«‡ý%^-¨|Ȥ}mÙhÛ.ƒÉÿ¯CýØqÝyÇõްÅùÖ ¼å]$¯õµ„‹ÁU�Õœ$±}¦v†‰hy¹•bUmدhS wÚ0}Á&vVó
¹Pñ¯ŸLYåX1§;lqgå7–x­9…v ŽÅé?iGÄ7:š| ‡ ûWe“ߌ(áĤÝü¡!\\aÛ‡ëÍ–ðôô­,oKŠ9d¥^)¯T …‡Sù�c¿3ós4×�«gåÃk'“y¼ Ïœ²�®íƒ?_ÏE•H>åÙH}¦'qÛÐR‡ESbñNï38·ó4‰gðö/Oȧ,±+É“Æ-GŸÙCye?)� áíÜNQ’w Ó|ÕØK> Ê庄ß7ÇÂÚ'Æ\­dÇŽ;?.ÿ�Ç\]Äñ š´Á£‘š’Yj›õ� ”Æ%øIm¾4YÇÎ1 ÂX™ BÒéþ+e!*÷¥ãòrÂbãj\½üå=0„‚áS%éGÑ Y›—¹ñê�Àäº.©|r§cçPWýt ÊâʳÛÄ}‹û�çó ¡òÜlAzf¬6fÿX*ä:Ž �%'`vl!{®\NŸ>‡ˆ•šqÐu£ˆž‡R|E*¬êㄽ)#ß›om: ¡#·Á_Ó}°i$®ntnz ïúï¢b�ÓÈ;†Û³÷éÚô¹?Ë­³‡™ßŸÒ¨*Y–pѪ=¬Ôó5Õ}¼/„÷u¬Ûtœ[çÕ‘´š'•Î0rÙLZ4Èb]é¥éãµ�(ËntIâ~�nAù«D+`Õ3·S�o$Û[—¡y…»ËM‹’ Ž3ßKìJ8£{v$xÒ‡+žÐ/ ö_öâEÖÒ\¡ˆÑRn¸O—0s�J•k×î¿­É>ÆGðààraA˜o ×â-áe¬u,� ë§§ÇhÌ9ö,é!P âÕç­ðzÂtÙóÚ®e°tI ™*¯j_ÈrH/k§a†Jöüç0e—.ÛøÂôl#lm>LVË yâÚ4n4x®JDUÃ=pöW&ÊGuÕ´l7Æ¢B#ñm«=yëÓ†?àþãX~k0u¹ˆF¦*ˆ6ÍÔÒï.ÿ­ö¦®—„õzXþg!zádÐlÜ�!ñ¼hÍ>s··õ;#„ß�ÿÖ®À;›¡` ö—¬ÒÇ’ßgm³ô4V�ýgd¹%ò¸ðæJoh+ÞÏÅeÀô³θ¿[·D²®”!n=²‹"Ô’Ñ'A=z¾%Éc7þ5o-¬wÅ¥·Kóäÿ,мć¢Kf Nû¾5]Ç^?ŽÀ–#¯)(1€žø*> ¸„¯�]‡ÇW³ÅÏsÐsw#÷QÕàáj*l÷@�£ Áâñ]š(�}*®‘“ïq®›¦„g §Ã9Å|˜rǜ멂û;èÿL7ržãTÑÑ4ÛsPëT;ÆÌÐ#ÏQ{¨øy4›¤Ÿ6LC¿ÄûÜeœEÎÄ^r‡ÁZµŠo©¾§Ì?朵ÖåŸ+Á "cüZu@øýÀ‡äX³ðN—/Hiá’–X¡‡vs?ÁçiÇx‚Mn¹½ ÞœèÁêúWh„à!êï[†ÓÊúòûù�pïv7ÎË×ÓGÈ)n?ô<Œuï&áþ²:˜Ó# ŸFý£ºlúÜ‚/ì…ÇçGó†0vøz f'LgË ’â;ùðè|#Ô¦ ¢ 7u\$ˆUõÛxåÞ'taIŸ3ïDé¸x>::žSõ¤+p¨þ&ÌzšÌÎ�#°ÁG–l ŽÁý¿ž¼Gõ&Œ‘SÂ§Ê Ðt2 ¯Žš%Lú!ðßJÍB¦,­lë ¡§öá ·§ôn 6·ïÑ�¼’Eœ7ö0l *Œ­ÒhÁȼéû1¨Ý}'çŸÆ¿xžóEáÃ& ÔÚ²�»s¤Õ>¤ìöQb�›&·MÞ)ÜÍ©£Û;‚U¿�øþÛ>\·Z�¿·¦Š¾å[iʵ>µÛœu°tÌ`t}×�ª<ýH#§Ó“òøóæ™økðaØì„ã—kÕ¦Ùž‚¶'À,' c�”á´Ç%è­«ŠwåüHmÐ)^»¯ÊøàÌ:+Ò �ÌË7sDæ\ÞøC‰ÏÏ)Å´M9åûO0÷è‹£ósE§*¶‘ë+\ÒŒç{•û º®-ª¾ñ··âÑ,kúJ‰Ì×l漎i ñl<—U­­çøäSY|rd(þYxÜ·­§›ME¸Oç M´?ŽÃ•ÏAà¤QÜÛX ~ Ç¿Þã./îš`G‡? b£V>cèÁËæÄCªàÃjßþ@ÄœDØ{õL}Ü×é�Ìfûn?Má‡ðîöS¸äªÂ7ƳÉ�{a·Ÿ‹B{€×Éñç”Ä=×Ù1º}Ê­ãxŒötËi^ÍZJkæ²ùo ½^W.t$¿¢#¥8öÕ]HޕΫ§³Ö§]üGc/Íÿ5– }yÙçNÉÖÝ?o¹ïÐ|À^¬™¯ÁkK ¸B犱ªó&î’¬îºÃ+}aí–‘¸ÔÆ _±â¼Í…×ï:hÅ›Á¸Úò%ž7œ‰÷kãc_qõ‡P®[:‰âúüÜMsû\r$Û;”—NïºÙ¾ß‘xñíúðiµcDh´D =CËë¢xx��óRA‡sæü0ê<éžêG§½›„–£ÒÜjçIGWëðžéxXÒËŸ¦SJ�l|0—Òß#‘2o>§/)¿{­à¿nù†×w%;Múcܨò8ŽêeAIꫨ¶SŽ>h{ÿÞ³<¦,aíêbô[eޏi‚Uþ[Ñëå |¤çÅý+ÂùÏúÜÜë ¼è5“ óö{¨Xá&h&â­·ƒ1Ïã�º×ó¼öñÓÝgÙÂa>j›XŠ÷¬õ=8Ô¦m “[‚jñ›þ6>X­�“:ÇóÜg×)lM5 ÙC}_taG‘.Žÿ­O½Vnâ-þ.м¶{_¡{ÐQa'OîD\êëŠÏ56s­¼<ç4eá…¹£±WÀ­©éÞtæ—ÅÅ4îI픉çÇ›e¸,ó7]®ßÀ“VŒG™úaÜ6l$œl4`ßwxI¡ÁúbnÜ-Çž=‚ÉÛ�¸ôë)RË>›”Þ&-ËÂ_ÌÌŠ >àÌŠXaú˜\±wF$¦ÊK¡]¹•ÝÀçBœ¿³™×%—Ë�hóv¬êÛÊë©zbò%ÌO•â–“q­ÿºþ.§~tÜo|û ~þÎÂK&ƒppÆpž²è6½úú�–wÐu§9”Ø!àÔÆ�¨‘²_¸~æ�Avt³ÔTTçR±×?s2±é¤ßÂBvÒË`eÙ\”Ï(w¬Ô‹gëÈëblZ'õ}¶•âoò×…U¿ºš$ã’!õ“6ªdÏçÕ½°Û]ûÏKàërN»þÛâ�°ìóAІCþTBCV*ËýkwümgÞN÷s›Oãp ®ZߣT£ÏÂEÃ>©Ý“÷�0åë™±|Ê7/U�Å��hÜ^ªŒNî3xaShŽ4Ç¥ö°sž+—ëFslAµFñþà ˜?Æ�7¥1P~iGb÷WéÏ9—qø÷RüþÊmƒIl‘rKêN Jm'ɘpnñE*j•þxILÞYHC�ܢŪØTrJ½¬º�J§^¡�‡û�8$¦�s£åÖa¦lú¦€Y3&cËÓuß½ÍÎ+Cõô«x,¯ý³-pÍ*–¸™²9¡É£³äÖzŠ}êNqr¶:¾œ\ÆágF³dúÕpÜ¢%� _^ýØ+¼:6šÓì)ÖÁ‰.l?O“/ÊAc�?¤5=‡½Ý[)bk DçÆàäY|Ó+�nlá�é•zÈœ{—sÅ6+�?wTÀ³#ûIiçHJ}eQ{ü„?nóŧÇekßLÙN6›ÞââC·á@‰:øÕþõ¤½±lV²�óv×�uà*œæÚ!˜Nwãqò¹q‰6Ï­øEÛ#ÑDcê9†/¤~’À0\£×Iu‰:üO=_Oï�N½ø`¼+ŠïéÚo%'ÏÄb²Vèv?›V ÙMÉ‹pÞ J·:#~ÉßÖŽÜFyËäk¯\•£�Ú<;;™5¢¿’+Œ[$ƒKÝ“Á²¸”nixâþ�1lñï |žèÍC#ä(oP¯ˆ¸&ï?‰Ç�±<×»�V)èÀ¤!À•Á ($Â��pÈ_—ñ�ÐPûöH‘Ê�´9óóT¾uD ³&¢á}9Úl„‹Æ£�SõøèÑ©ìwD“/GaYV#¼²è…üJÉþL:Ðð üæd-ÛŒ>&*0Bá*Ô›ìÅì{ŽÓIÄ59ÑhsO^(¾•ïvòÜ‹)œÕ“ïï=‡�iŸ¹ø\Œ öÁ£výÏÛå鼌gñ$O-Vlàèéü_©÷áÞ[âè[è+ |(Á‰…u{‡òŠ%[èúÈÝ<¥Èc»)MT„C1ºPº‹Ð£+ê¡ÿÔ¾°úímJŽ©†ÕU/éÿ(:￞¿7Œ·µ”†TÒiQ¢÷ë¾3²¢”ˆŒÈéC-IV*¥¤…”’�Þ¯û¥dÏÙ«doB_ß?à<Î9�Ç}]×óúå,“ÅÇ·Jè©D*¢ç³šÒš¡|·­Jà±Ó @c'“û”��nqF8³LŸ q,æ²Á��Òá3—àgÈl²Ôd™ûûxqAæD��Î9–ôiØ”õs N;>—’J�[Àf˜2PÞí¿{@çÃ×áÖÿâ1ü¼*{GJE»†nN À†‘A‚{0Y¿ž+´�u­tÑ®d$×}ZNkï=‡Vìû´ ë5UÁ¥ ¸«éYóäiþÚ|™Œ³vç—@Oï½x¬R¡Æòq4jl> Z?•âë+eðXþ �ÇošTT-h6º²P›]:a…m_Ü“Ï�Á¥Â°§[ÄÕö·—%× ¸æx2ü �ÊåÁDv0dUÐÕ·Ô6Ó–Ÿjîc´‘®KÇ1^ö i7ýeRëàU”&Û�ÐG÷ g»6õªBÒ;s¸´dO< �ÕnÊBÜB¾¶n6‡Fìä�‡ïÒ°ÁqC|ÕJ6ƒÏÃéÜöž­Â1õ-óÞàáUåi¨:pÎþ¼FúK¤üGóñÚ2W–v‹ÃVå¾ü* wgÿ¦×UWð°ß>$§ ’ʇÑPy^›\ëyð¦@> {áÆÜíh±8EûZ|žÑ_˜¬ðúeòØÏ œR÷ƒ 6‹Q;w`øVNû5“/6 5Ccóš÷Pï+Ê ×ç}6£‡É>LaÆ™£îJN6Ò»Çf<´hxoÀØ3“$ûÔã³+ßi`ý<µÌ9ða+<›åHG†²Jßtˆã·Q–� ö f[ 1+¬ŸþQŵc†rŸe]ðEÎ ¿ÃÊàj<º2ŠºÇ™25K ‹Åay9fÐ Í;)ýN1:žy/&÷(ÅKÏ@”f„ª®æn½|øË»' ^9š?ÍüÃé‰wÉ7|-ÙõQB£È•(¿[oïwÁÔ,3Ò 6D÷w 8$}%ÌîÇuá({Þ[g—|6qÎ�JñÁ½·Ô¾í¡ØM{2§+¸…Ôì�* /”+½ˆA£[ÑÇg>ßiÌ翼 7Û@‹7b¨T³ãæn vã÷뇭lû}¾hã&5Ö$°ZeN,h…û-Â{ÛÛtÃõG9�âĶ4Nñþü܇eÇbGîP(ß ºW•Ѭ‡;¯ûŠ_OrÓ4ðˆ~*v”—ð«‘ÿXÌ=aµä.ÂÊ!Æ\£Mý¿FÿóÅÞüÑ[§ëªþ{ißj¶ÅŒþN¸Ú¸¿\v3šŸÀš]»iDS)ܸV.„ýRço¡ŽØdÞ�ÏÍÀyçnÒ‹ê¼Öv ºEÀVå»�ß’€ûÏãÐ+·I5ï>!2øk�={îGý§l¬ÿB\s'7´Pá€tŽÞïÌ ÖÜ„–�·©òÒqÎÎüHV5ÛyÚ |“ò�Ú“½±jüa.ÔÞL^п.&óÕ Ópjt+g=RÀ[ Á䪙Ù Óé¬jO8q'kßG£¦Ùcèß÷$6®íi„«³‡³w­ö¸q÷­\ “ü|Ù¤§>Žþp>m¨§@‹ÐS s’5Xaöe|Q”'ÎyðNü$¬¶�öÚÂ¥Ue˜&ÕÕ\:u•Rñê‰�ÜYÄéÅ�Ø·h+~ýªÈ# OBÐ#MvuüÇË_Ö‹1âÐZ_aç—X^9!Ã,áªgF¬2ý3žëŽÃ’¤äÉkÜü©]ίüíÉmõó9Aš‚dˆÃ×µ\$ç…œÿYGUY°õ cŽ?¿…W�Öààeéé}X5דûíubÇ›¤¼V‡­+ŸÂ£l>7¢§TH$Ì@Ë!3Ñ,d#¾Þ7ír¶P)êò5¹ÓÔœI;o�ñX|]/ŒIQúç½ð{¿/ÀMW2ùVH§¼ü§ì…”¥G°¤|)îû Ìw.®@½}cѺϨ¹p•«Î¥�Lú?Ð7Ú† ¥ºXvi2ä )…ž­Ãùu€"wº éÿÕ õ>–,N˜°^¨_”L« ÅÓcqÖR;\4ø*Ks»KÂã«h+êAèÀè :½ ïͲã’ß/…‘ëuø×à?’ΩMÜzaçf_”¶€0ïº ð˜ÌLhM]&ŒÐ áR(ÃÇʧo7[^_g'-èp Ú;ã!¯ö_Ìú—уËy¶5ãZz“Å´Þ‰ûQæë½<Ú³¯@nO9·±tôw,ž)? ⬠~ñ}Ìô§é3OЏ°#ŸßmTwkñ¿Ï«Ö”ð‘Ò-Ö—nù“@?¼mq郷Bsg$žé¯ŽøL¡æ“‚2ðs,±¼kFU±†r‡$.R‹ó=úaþ.*¶W¨é±ñ>ý^Íú½õxâSO t°�7ê‚e¿ 2Õ¼-̬Ƣ«%bÂ¥�è�fXuë„-òÇów÷ˆƒ|ϲðÉÍç|Æ(Ç.hš±�ßÚ<†•umbRìqN[œ€‡/ ƒÀ}Ù}éFj^2�_/7‚CËaqÇ1üý)‚»?—çI¯®óìs©ªr+^®½éÜßÚïì#h0pD¯Ê}¼Ã.’¦„1Í®Z†/;�Å.Ù°xeÄЮÌûÐýÛ-N{}GÕ‡a¢[ åyª“œ·ŒÛÇsñ½–¿ÕÉÂ/�3høj 7ÿ—#Ym•RÍà™¥+{®Æ)IÅôÿ¿gpl1*>ÃV/Wê#W ~»iã·ñøm£ ×zãLïZñÔ{_Ž1 ­ºOÁºÇáu^É_�öºøÔ¼žhåß›§Ø6àÑOÓù»\-ÛÞ‚%š&âÎ]«ÑUó*ÅÆU’¦¥ÆÌ—MIA,Œ´Usû$Û6Š>´*óüÁGØnäÊ}�Äß^¼Á! ^0ÛokÂE/¼ÒøOÏèo� ãæþPÛíÔƒQÈ=ï§ÀöÇÙsÉhô8aŒoÕÎrôl õ^hÚWÒ•‹k—³ö�uЧ¡A,OŒ­ï üðqÝ<Ä}Úûóõ·ŽÝ�É1}ڠϳuø©N C´ÆQcÜs>´öÿX› KëÜyWßNèážÈq.A8~sä=—e©â$Þ|ê­µ>ÈÑ:ƒèùú èØ3{'¤ FŸ!¬é^®¶v‹S ÇÁm¬2Ѐ—ô/Ä»¯Hœ+r¥ó^h7Öâ§N ÿøh|þ³Dè} [µ^n‚^ÜP³çôùV\Ù9T+ÀŽœp>Úµ·Ëâûoö /Ãvò¬ ó¡â`M©^škÇ€S¡�Û ž€ Šg±Í­_Z×WÆž¦êG'8Â4’bGµÓ£3åbúõŒÎjä/mâþ™™@ *9®WÙ¿yº)ÎIR i©Ò èÂþR¿ºðm™7ˆÇâE_´/O¦íËI�¬‚I»ùm[�Yꩼ°ÛAªš7œ›�}Ù'þ$©½6¢¦Â\'åQ{`ä+œuƒßªN‡]Q;ññþ9h°~1þx"ç–ª×÷=öB›< |7cxoRr“¦$ãW›I�™ ÿMd•µ7ùh’+^°3ÃýY?P·à¡ð¶°'—È}­"WW Øý &]Yr܈Ÿ<�ÕC`´S3ô•5CÅ}™¬ó:^^{ 3Ç·‰�ñÑ,cã GN�âŠòPjlQÂáE=¸~·øê”ãÏiüÆ1„ïÇ©aIßtwå}èQý †*ޢ̄¨ž»Ðæ¬7†·U“»\¶òFµæùŽlŒXÚL·ì w¦¢úˆî5&æº8)â’tÅSGNÎÍÇ�{ñïIhßykµ—‰»†Eá¤g#©¦sÞ]1€²¢»qFØT”àMAƒÎâ´EZPéÄŸNùR“eW~óJžúÀÝ_žµ£WMRß¡PZcd¤).—ìæûC¿ù½“vüÝL'ó£éc¹,~š¹“¿·¢wf/Éék: (á„\{\çU�Ïöà˶Vª �yYeÕ]7dðíš8±X} y®ºÄ“Í@¥î ©>XCÊ�Ž ã„þ'ÄŽÈ«°@m›‡è°^Ú\iм;’;ᶨf^nÛ %Ž*äkÁ3}{£2ܑږ¶‘åìVq”âs¨Ý/ÁóRª¥6xGkÂæ½Šn2ï·ÂEÏlT¨ÛMC�o‰µc�þÍE‚ž-à¶7+0Þ}”XæpP”?=έ¸Hõwä©üÁD™Æºc:Qçf,|‘uæ»)¯`–— Õ—øã©«5´ i?¶®H†ðоüeÊ;ÑKö©¬Ç[�Š`6/ƒF‘=o’o¡K!Op‚[#;†�“$¨Ý-™ž »9Ÿâ$^”¡�Ž6}Êð¿4/áAz&Ÿi�ÉjÛ~Âùau g…¤Ü¹Ý|f‹­Ó= a×FaÝ/Œ ÅIÙÖ¸$¬Vª|Ž®•‡éÓðw\-�QÊ“:ìÎq�¿Ž�±&xëÛEšXs‡ê'£OòžÒ]V‡±`tœÒڇ͢dyƒ‹{ž½7b²ipò{¨,ïÏ4Ü “¼îàÑÊk0ôêMx}nÙ5IÙ>—6f/៻ÒÙøÍ¸©Ï�÷ÏŠ«7o*ò—á�µ½ð^�‰ôår1lûçƒO“ùÑ� ½`�W_¨ï· ë4 }wšåÞ$ƒõÎÜ´±i•4mìÎ;§Æƒ…ûgðø—õ+Në âЮèÙ ½Æ¥©ï_IôN]ƒ_ójiûô!ôßœ�¸E(7)Â0ùjÁâ?S~O'œ»‘âý夵| oFSëc ázZWbÆõr¹öã¶P)qâ�[ú‚žÑV œƒjw­xÞ¦ã”VFö²…8QbÉ+\ÏÑäT¼þ ŒÃ5yÑž2ZdˆïT™ 6‹.ëÒñ)gÅ ÙŽü~NÏIÌqÛ΂ÉïýèS@sKORßÞ;þuZ'e[H�ýÖÓŽÑ7A‹‚¢NŠ>ÿ¥Ã¿­ µaÎbÚçz!U1 ‹–"®ØMSƒ³ùÅ kȈþ£jNÀôÑ40t2.SŒI9 ¨ ê7¬«žL4Æv…�#Œfïãsp~ûþi¸ ßÞµ¡ÒÙÒóºÐÎKgts+¬8ú�®dƋ޴æÈ`ª_m'q®=)íœúh*.=ðê[O ¯îþc‚ö^�ý}~I9k÷[àÔç—ÈÐî ªÙૹCD¨Ü‡;läùVä>g9ÍæJ“zm’†Å¥Àܯ!·oŒXYF*3àc€2\9H›nîEwÝ»´õ�2Ê„éb‹Ë:ªKM»�4æa—�ê’uY¯OìžØÊŽÅâgau]l±• ïš�íáçpàïc*·_¨©Î«‹ãÅWw7b^ývqÈn†¯žÒØcaRŸa]Íb¾5!НÈ+áõƒ`œ›Èú¯»qÒß Éš…¢Ç—%”éÒ —LGGZÕq–éDø•5]xv¡?\<ž+[æãÌ”ÏTëŒñj÷ÁÄ'o4wÐ)95^ I®ó³³ÙnB¾0ÞS"ÝÚDuï Á·¡ÔlVÑyë"89x �WéÏ&©ð륯É|Ìvú¥Î)a›Ù4g ÔßÞA;�Öâ;�PúCžßKýU”¶K óN~ïÚ#¸ä±™æW½uQ¬X�^Þ3Rè䬽<ú×4V{´‹o¸ß¨Õ‡GÊPXèÍ1ÉN<Ô&]útÊB1w«ÝÆŠ79XlªÅÑ{æ‹–cÁ{´=;¯O?}#l,ÄÄOáªn‹8sê6Xú=”¯ê³�§bµÒ5MܲšS�ƒ2OMëA�EC±ß¤)¢ç½K¢Ÿw :Ï#rþú�ò'?¢Øß�IK{(òÌâ)™«ðßVÜß4K@û¡«ðöï’Ag«y³Ç<<{$-)Mò~Û ¥ö=ÒÍsýc÷L~4°®cª8|Kw*¼ÍÓBÍQÙc5.£Á§ëÿN]¯Fn�SØKn›b†«ÛM0IÉ]¨ÜØLºW@¯ûo¡z­./,&üêq$'⹦k4_–; Ã÷GòþãZœg®-žOH¢�åñ°O47þ-‡W~~ø×R—WçTñ­wÝepâëSx½Åˆ¿÷Í[û>î$Ö€Ëɸ`}dl>BYs¯R�•Oßò…zzNäæy|k‘øpÓ4ÌÎ ÄŒòxœ¡Ÿ ë éÐ�(<^µ òü©½±k»§—Ì„ÍFêì•=˜Ýw ‰ÓáZ©+wM�oãø_Ö•Ie÷�“¢æpÍ[YT½Ò�ÛË((Ü }ƒL Ìo2ÈTFó˯Ýè˜G žÿ”öôdþŠ$\vôC¹Œ%à|ò![­$ ¾ç‰]FanÝHÞy¿=¶XN±_Û$ߎ3÷êÓ�ŒfÜi±n{Pã½£¢Óó|z)[ŽW{-á’1.Ûå„Y~ {²°ªª/¿�•V¯ÒE/;!}QœĬi½èÓó °ÔzF.àÞó÷MÞ„[ÂŽJt<º`ÄE–�­¥}”wL /âFš1ßÈõÿÿë¬qpÂ¥áÊüëè0îèDCc沉® úúóô™ }ܾ©/*ÿÊ®eÏi„¿6={õ’ìeس¦ƒTŒÚ�KäpÙ‰lÁqaW•yª4qd¼Xqk G ¤ù«ai‚jÛMG‰í%X®tG0–‡^·ÎþŽÑ/XKïSíäjzæ×F3Žî„n5´×Ä ›u€âa)÷ªÝƒSgöàÒ+Kùºü)Ú&@Ô·1¸|G<6ïgérW|~x \âA_m‘ŸiÿÇÒ ¶)‰F_%c{^]%ã¦ÓF#¼PW‰1nÜ0†4!†6$` ›r�Gîž½é<ùl“\²¾À¥9�4ñL#¹¾'ÈžÌê?ˆõ}×�EÓ4vjŸËëoÎ¥Ú{þâúuJÐôÍ[ðÖD¦Úq|«é†4×ù-ñy º±¡è¿jƾÒÃÜþRY£2á,ÅbOÓTŽhÑÁ¬¤Ã\ûàô ñå_zqÔÏÛBzøÓ÷~�ƒ‘“ÍÚvB‘CçL„ßQ‹¸Qz˜Õ»•Rˆ†+d¹4sŸ�#p‰òvâiAŠ÷FbÄj_¬p4õk2åoˆc×K"tOˆ‚ê5²¯ÄåÑ\õ›¸aº>v†%°|êˆõm‚%›W£`߃[‹…{j\ù|àö$ZëfÄ^ªýðÏ ({ª7üV•ç ¦ûñ§¼/°*›úXpz­K:LÛÛ7㳈dá´þrô<�çÑfÅ¿ªþÐU,–îX”K56hù2‡W¨,ÇÜžòq÷›gBvÍYøkÏçÜôÙÔÖƒ½l�òìg©ÐíüIé¡6?Ú苼®­ƒ”O¾sÕø½˜^š�àc¶¿%7¶ âÄfZ(©‡žéü‹çÐÞNE.ž.O»dD8¸.hlâÛÓû‚�õRØ–�)?ZDç„Ù<@M­�põ·ž¸R¦j?KÂ\¯‰8*]ÓíáÀbXàŸžV{èÝšÔÖí”Ü¡“¿dñ÷ñal×° íyÁú›<ÝìýÖèÏž—Fsñ¼WÐ÷L7,[2‘ C§±gX¾\ Ÿ@)'+^âyy3pà´1¢æõ1Â�‰Yì¢�¿f°vÀ&ÑV©;ÎU3!Ÿ•9Px¼U„û$}Lï–wÀ› ±hÐ�I#åÄ8úû%–Ï® ÓN¨Š8PûiÀ#GîÅ\Ç(>ÿê¡ë×ç^¸þ�7?¾—G5�1yLNÉÀú¥³¹úúc\Û+¬MÆ…'^AJm°P�x_F¦£â¹éœ±i4ž+�ÎW<’ ¦÷)tq:êÎýËÉPÖŒßÕNFiôÖÚâÄ[÷Ûnè+šѦ¿Ê×…ÿòsxqµµ ×Û4 ös/2¯¿�iš-°Àúâ Åö tyAñâ ÜcÜ«ŒpÉHØ0ý!”¾�q‹•ìFSÿ|Úü Jh¢írÀ-¡Ü‹4E“Š$v«ê�ãÿ;Ÿ’N CìQïJ4ºç ĽsåÄoeÜØ¶–ø "ÕÉ™ðçýÖ9Æ™KíñF�ÛŽTÆÑ7­8ÿ‚M÷Y„ÏÜò¯u磊ú8©´»8öØ{è¶ý(ôq�ÌÞx‘ÂUþº5C"ì1êÕ. �ÃÝC™­ _—FÒð‡¹ât_¢ÄÄÝÐKáL{Û�']A'U3ùñ/‘6(}¤“KÊ& �=Å+‹kyŒSèÊ=dù•+ aËOÉSaåã:öÝrW0:4û÷¹.ýqÄ�ÔWàžç–\² öfaƒª3(Í ÁeÇîP¶ÇyZÿí°tTŠ7¯ÍX€:¶30ΡZ<ê1íŸÁL�<¸Oã©ÒÁKS.R1¸ÑîÒxþe ÷ßeÀqkóa´} Î,ÐcÝJ_ráú� tNbÁ¯zƒ‹ë<²¯QÀßò2øbÜ ¼v;V˜»)éô¬os%‰‡ƒX³P…-GÛ‰w¯u {ÚÌÜw£EÝWÉjÜÉ1prìÇÓòïÞ ß“�®*ã‡mO…¨öjº~δ(°õŠ—B‡ó Ý`ˆ [âøðÙùÜ0h4¾¬×Q�OÅñ "]nÕMÇ Æ‡E#÷Í‚m�]¨ÛjÈ�ÑY0r�v§‚í‚f¥ß£U2¤úÅBœü^ƒWÆ@?­ VzÚ—Ëô-9~àaYŽ-î_6–F¤ö;[‘j[î°Ç‘éÜõá ¾ŽÎU̧A ía°È°eƒ�·h’ËöŒŒáodxÚá#´¢¸€—uL€¾*s©½ýô>àBÊ3¿Rý!w<û$Ž„sÌ+Ö»ƒžÜÝ$¬?ºÃ+ã8b÷Qq„¬"ÏH¹-™Ò÷°dMg ß‹·Ãsg9e‚ÒõFJÜ7Õ5fôEζI†m'‘§ú*ð˜7ºèümÙÐí[ ñJ7ЊÊÄæ±žø«ë.]ÑšÃçfQ~ê˜{ù-ïTÆ^»ê`ýºÁÔú~+z– eèHü`¡ˆ9Õ{©=ËZ¼ü:ŠœÇ�¢õ£+ d�59Ì“à˜ t1;�†.²á\%ôßAðÕ©V”Í\ëJá$ý†3‡�ÅëÎÁÄ�nùÜ4h –Þ©'ê= Õ6›Óí¿Žma€n/ãyL¶/®+èÇnóN‚ì>¶õ)ü(ßÅoû¯G�-&ìÖ¼ÿŸwÅPãû x7 UTžr—x‰^t·d—Ut¬ÇHî×eÇæ>bø}98uÐVîMQG-É\r–l$åæV£`ˆêÕsIÁªî æ­w>Ñ…QãqJ–XceÍ`B�Q‘íó×âM- ÜÞ{\üöKˆ˜oÊF;€—–µ¤ÿ{œ|­\8%ƒÑú¸%©„*>ìÅþÚÒU�þðE_Fœ7v›Ÿ^ËWœó»»Y´þÃWxÐyL|¯w‹Ì–¢áîŸd1=˜/mÃã·šóõRѯVo•ZB²½9/_œÆ ^(ì=è:ËTP¿ú—Žl~ÏÅù=Àÿƒ"ûM[ Súý‚)£-qƒL)lߨB£´p§Â7j§I¯ ½I=IõãOèï¾’ËÇåPFtA=s ô’; úŸÍ0Ró_]Ó²Äw-9y^"½,z ‹ÂË$•ûg‚Î�½ôæ¹)®ââˆúÏ0©9šërÐjÇL<¡5BÔÜß'MFŸb®O¯€_õ60À2�ýÒ\¸ë‡.N»ßƒü÷5ˆ{M6�ÿæ�d›6œSKÝñçþ$(ºò Ž–£�5¤µÇt 1`1lìη’=ñ¶»¹pr` ý,T┌,ú ¤ÑeCwîî�/,ÜÍ¿+áhƒ„#4nÒó5kðâÏtxøÉËUÛ; úá2¡è†ÀÛ_^¥å›è¼ô6½:g V㻣zI,ÑŒty‰}mŠ ¶ îoÝc>€¤=ÛÁ°"&—iðõ{Ö8FæÜ¥ô)@–ÂA:ýr¦<’Á.õ ðßPYé]}+Æ–§4 ðéÖ|.ê¯àQäËþ¼ Í½Upü…"p¹–Þ¯”Ùiýv±áIH¾É³Æ’V×J']q£�°àe™è³ý=íÑ_¹Üð‰†'žøœz]ÁÝz5-!דè;ì’µðÙÉHÖ:0€+ö…³VÛ9Ò_?•ÅQfhî£É——èIý/Ÿ¤c®jèpy!Ùt›‰=\4ðdܘŸoBçMõiºê&8©'Gaqzÿ:!UQž‹^¬g‹ú�¸x®>gØx@â¼Av믔ø‰>ûÁ¨5š¸ù©Vƒ÷‡„òÀ’`q;+G„Pzˆ'º|W¤À“Siê™lîR� U ï2ÃL0ñLu¼ö�8òURõ"Û�`:h;çõZI¿vìù×!OÁnÌš»×C×k+¾}s«�ÊQ‘Š|ü±õ:œf•~ÐûCzqœ[ô–¥g7oCتµ|î` ÄÙo3¸gÈ¡�‘+÷²ÀE)wéàñ¾4îÎVPì9~|`ãx×ÃÜTû ‡÷axrm>螦ï¯ÑŸågÁ‡'ÐWÈFGôðꇔ·¶B_¤Sý°%ÿô5¯¼]Áïör¥§'…– wÕ%|÷ëñ¥³¬zÛD{ŽúðR/Cž²t©Mn!ƒhSŒs2Åà‚k»BŸ•ÙÒ±gßQïcæè“½¬�øýT —!Èð)eÞ%…¨¡t½ ¬íÈܳ�ú/‹Ç¿óE«az(oQ)jÖÌa³ygý‡Ã\îASm3ùÜ.ž;]êæƒ«‘ÚéˆÈ4àɇctÎ\a­A‚0³1“>üøô¾§<úT&´¢‘èb”£Ë¹sq8¦Ê/À#ëÀþ?WãÞoÞ­D]˜‡gÚƒiøµ£`£Q%îõQ�ïå<9F�ΤóÏ‘–tdÎ_Jþ[,Ž›”Hí6síï{ t‚QâUwæ–L³Ë¶aüàËÒÐÈóÈ[ÖIúKU©~ûŒ )=ã2¨Å’„èzêf€¦a<þ šÏøk$_•އ®êž¤5L�—^Â<™ÝbZ÷ ú6 çÈ®À;ã]Á}Ÿ*Õ´ä™?ÄÚOÇ©5Ó9ÆÂ(½rÑ:wš9‹'?ßKÛë}—…ÇÄå½µqAï—t<¾�*æiKõ'T ~¾Ê4nüT›pv:s�Q4óo3™fï-Jÿáúƒìf¸“×]-xŒ…WV/'÷>²Øuʆ¯Ä�©çáòÜoxn¤™éOV— Ÿc=X"?�ò¢ûÒœê}¢×iU.øžõÝA?ÚtÐ+¨”&/?Eîî/àù/y,½dÌ}†@Š÷A8°o2\?b„Ñc È÷.¡`��ʪ¹}~EÞ:¶wÓÁ£»¥?_lÆK�ê|Ùæ 6ÍWOëQv~4¸¦?åö[^tEíE¸x|üI)§´~ÜTµ…#Ý;ÎIƒæ°fÑ·ô¢P±é›°è7ð�~ï„òª/ÒÙ!K9ÈÚPøާ¶íââï uùœÎ>IVÅ a»’‡ø6Uãsì0LçÆ]І¥j(§œDµÁõ™3'”¼�é«7‹3üW¡¯J?¼<Ó�g'gÒ¬‚i$³î4 ÏÙ «½„*·XÚ§sžÆ(ã £Ûéè�×ð|¦*^1ÃQ>oàžF'tÆ ü%m%ØŒó‘l>f€¹IË$- 5yïÉV¸ÕúNH1G]csžœ�.îšÏÆÕ‰³¼tÄrå\ÑøÕrZs,'þUå;’]ü°È§ºXQ,ÃïÀæ¦0<±0×õÌùZ¨pVì˜P% üAOî�†Õ/û‡ããXýb 8úÃÚÿ^†Ï3drUÙhñ×>?´9óŠM®¾…Ëç�Ãî¾Ôѳ,ÆòwëP^“³’Û LxF�<Îé½M,º¬§^߇ïYNh0Gϰ7÷.†1ÊšÜíÆL¾òz&vû^K�v@óëXé˜ qx«¯X♈©ÇFà÷îËÁ8+‰ÿ6å¹ãd(Hs'Õý¹¯íûñß)¶¬>þ ý"Ò°{ã…e&Y¨ð¸†^î8 Ov£ŒÉg%_Œ`»Ûá@G ~ž¬C²šB‚K*lÕ~¦–Iið‡ê¯`b¶“Ž»"ÿYÔýs 2¦wP,k‰¯õÙ.vL_¦ÅeQyF†?è?Ë�çÐÜE“Ôrä‡O÷BØ¡np@²Ÿz�ßçtç�9nP«è-dÞÔa³àƒ9=5t4WÇj¾<¬Äã�Øëqz¼ê�ã:ܹkŸZ‹®è£ú†zÙÉblÔ@ž÷¯[äÁ]q˃ud|c$diŽä’±h�ŸH¾7µp„Vm>¿²Ý f=Ã`…O�D§×úÅâì«/añÐxª6H¥¬wEÕ»Íâ‚\=lúÞ“Í&÷@íþ…–,ƒyÛã#燵^—„�ÙOÅÑ£mA"sUè%iðA]îZ#Ö›„òF}}\üc3äÿºQ×@C;R°þû…–ŒË‡Ô‘&ÜêÊêw.`ÃÏt˹�Ì_N!Y¹fñ|}- ºÂ÷dã¥>oÂ$N¡D57ò‹_[(?ÉŒ‚Ou£ž‹gð‚©6¨Ôõ•4XQ߀càõW‹ÓdQÍ$7¹&F_µVÛ8@àç�â–ç‡àÙv6I�àÇr8gönEæ‰ïj[„ª¯é°®ÏhɪÏ$wµ'qd°¹Px75œ„»ÝÊ)òÀ7Øt`}��ˆ—Nm•.ÔWâ9=“0ôz54~†çÓšë5iýuž?àŠà–{•fåÏäy�âÎSÛEïWÇ!C¶*S·’òdÐ¥(,�_r¶¹ÂIOe$ùrñÛ½žôsl0¨¦ësÍûJŒú6 ÃcñË…eôÌg%%¯Ù&/U‡˜‡}PYk?ª{+ü18@o�J¢J\X¢oÁ³Ÿ,†aCHÚ¯Ã/““�ü©‘.ÎGø´m'ØŒÒážm•’üÌnlD8ޤ�Jü 8  C˜pôÈìI¥®Àeøó{^.ȧ±cbÄsoð±íXïGáf^ÜÑá.h_PuËNQ…ö*‰¬Øc­Òè¶×ihÚ¥ÏGfV¯ÔòhöÝ&È»!ÌlQEŸ±ž�­§"¾(Râ¦Þ)èã–-ôO}J&�ìxËLÙâ€:–�ôô‚¯jYÃëçÁ=å;°ÖvE«Äy6!b\R(ÖnƒM%ýÙÔ<<S'€kç¢`FÏÛtFK„É;�álÃ!ž¼Aî®ûC#ŸŽ'5ßTPb)l°3e#óyÈ;Z0w‚5\�¹²Aœ:O ùŒT!¹U˜�œÀãöò«kãèŠÄ„o´æâÇ^F´ðÝ2ìØc¿ç »–ò¸[)‚¾,ᆯ2h¼‘ê ^H€=hK¿Uø2~7$t/d¿Yåâ—>ødÝú Gmz*è»!džÔĆ ‡ùÇŸêYP!¨�–;ôù¤yø{Ã:¡¦±­µ¼Ù6x4u³ýFCV?+š†Ëeœyß1?¡EÆÝ›Ã3õsŽê4Öû8ïïˆ#Û …‹€}o[ðÞ:‚ÝO ³2ªÅÂqêsruþ㵯Ú(!},ÿ6í��} ؼAÛF…Ý´wcZé'Zι,³ªšÛ ”pz¿Â†I¤µÀSx;þ6å6Û£ü˜%d÷}>ÏI|COe&ñˇ8;5�ÖOIæ//º`B[o¸ÜG�nZM¥­YœáOj*J�þ±GMï„_ß%¡ˆ�®}ðûÑ ª7¯Ù––}&9ðp½=³ ÿð±¤}ìc´ŠÇiÛhî›ÚIÁ‰†\õb÷èi�bp>¨¬Ù˯ÏöÃ¥OÚc»_ä0~ j<Ý‚M'•¹þ†�[öT<:x9 ¸á� )¸«iˆ°§� ƤW[År;W¾òñUn€=kÏÓ€eËÑVº‰Ív9qùo#¼l\�ί7�}°ÝìN’‹áé ø�¸ó—1®p9O1k¶Á�|$C‹X#YÜÆ²£_ŸQDñ¡ªÜÚ±Ÿ¼Ç*³�µ2¿ÔéÊ©­Âé²¾úý$�4ŒÂ›Kó¸î“/gÿ6È”/ïðF‰³/+í¶ÇÏ(Ò«ÉÂ?Òõà+kHsµ…Æš>g€dvy &÷Ï%Õ#ãùy�2N³×ÄIŸ½àÒ€nâ³âü³UÛuåßÙôÈÿÍ èÃɳ™†ÒO!/û=hïƒw.ëò™ÙsøÁÂ\”|¾Ä…™Û(ov ؼí qdr8yHßÁhÓý|ýx±¸:RŒÉ3ÂëIX™ }ÇЙ¢Iâ… ±’‹z2ÜOXÍU )8}Ã:ÄŸÄ0£úô ¡?Qæ<󦲥#Ë�äSSN LŠy@:UþBZ§ªðÆÝKÖ$HãÊ{óänCÙbÝ`¾¥¶gÏÄ!’g*k ½ö‚ =¢Ð%k9xɼ¥ø‘¼õÞhÌÝeÊþñTefǦ‡k(¨Ú¨æe–:ÿ~w¦xB±èK¨ îþ·ß¬/ÚìôïÎõ‘Ï `F&:Ϲ w§÷bãû� ÔÌT°w;Ì+¶ÃÉý®¼óü¬_ 0ó-,¶`õ•Ǥ󷯠qJᎪ,•\䃥hô9Oþ˜Þ“ß®K‚z÷…ðfÂG±655Ïá /ÞI¶&oÍÆ¡½•îK›HþíVáâúHh•~l–þÁcé9`©òfÏž‹üù"üçÜ ñv)”™”÷ƇÂÕÁ×9{Û$v˜iü„N¬=Ló[‘ÊjÎ’Ý@cf.‚MÆE¤ïªÆ³>Öab¾Þ(pƒtyòA[:`æÄícÅQIyêeÁÀr!]{?,Êçä…à�ÉÚÜu6ø¥‘üa4z=_fCS¯!xËæÌXûÏCcYÙ+ 7îh¤}¿÷ã6u{L¥CèÒ:Å4h*ïÕ&ú?y@‘gµ07c¾_oB¾¯ºÓ/‚þ‚EA0žò¶&JÙ,ÜÛ�ñ®6”ømÇêFs^dðô ­èuà$>ß?ŸZ7ò¬ñä“LB/ÎL\Ž5W*èÓ“íXlÁ}¦t½N;²ü]EŽ™SÊ1õ¿`î}OxP¤Oû‹ÀeþgšÓjÀžg³¸òÔ%J¾+[ì¢ç€ 8�È'âg`ôøe ·`?öKdOgu˜³ðl–«Ç-m‚ãž×�â¯ÆOu›!´ô‚Xowk^éãAÿI¢NÙ žT´�ä.‡Ñ¨ÙŽèÔcüìéÂöÃxGÎDª(C’“„*†8êPÍ=t¼µGƒ/«°Ä>]_ì'í^æ³�@´ϧŠ4à\?c¾ç®Jºƒþ€Ëô™¼´¡/o68Ê·ºŸCËnuÂì»CÁopÜÎ-ç!éò|É¡@X.j £¾S O¸ÚÏÚ‹ .‡7n›éê,3ÔœÚèm ­+NVGôõ䂜qŸSµ2BŸk²¸aG�t†/Ú|dkGn7Ý«â¼åƒ8¤q¹wäò9í[à{AŸóÎ]†›ëµqlG5Ébðã¾�{ÔL صäo± ®<9C=Ÿ¿9Çñø_ã`:Ü€í3ïHŠ-48¶¢훌UëÙXV‰®Mž×'âBãHÀ=§IÕ4‡­Ž·áÍ+UÂà¹ç)ª— 1AÛª‘lxH2µ ÛjO!§9Š“{nÂõ¹Ûxþ ]ö�M Î èʺ?PÚIM5Z\9ß]nƒŠß¥6^Ü?A–ú)s�ÏfœÙƒŸ§U8G›÷ðéŠImÅÁ.ÛQ¢JAjÌÍ{‰4Öˆ34Òý§%bÿØRò“ W“+©¼§"Û¶øòŸ&Öè§ËÖRS¨›oE¢v¬x5“‚Ï ÛëÆC¸‚®�쿯�Ô¤†g^ìn™I�ÓÕñh`²–>ûd?‚ÿePÙ[_pyêÛóõX.m6í)›/ÜÉÈwxóKk~4o*z&¥‡»?ІÝG^zÆ¥M'´A»dæwšBÍãJ¨V¶iúD”xà²÷óHç�¹tiÏYh"]7¿õäS/'aßûG¤:µîÔïÐH>zlÇûl�è÷iÚhe~Z¸¦—–»wŠ}�úcý’tÛVˆ-cm)2©žê›×À¸ÂpÒhàÆ¯KÈV¶Y|×ÿ,˜Ž¼RÕ+°¤ë ¼üC°qP6mrNâ‡ðièò›=�l�£¹Ýs $ =O/â­07Wä~š�Qr?è_ΘpyÙ~¦óýü~�,ÖíR¾•—ƒ¦Ú}ÚÕm.Ö4éÖ¼?W…=¬CË޹௸†v?. XÐë•Ìø±K·�7ö»‡€Q÷·$\ÜÅŸ$ ã‡/Ã_Þ1d-;�;àã–cl0v�Ø‘«„�ÅFÜT» |âÓËf œ°ˆ}{FîÑÁº×pÞä™(-ØÆÏL�ÌÅïðÂÛ å'JÉyÆ@VþÑ ŸôÍáGç¦sìÔP¾qZÀÂ?Gÿ,¡–’2°üš 8åk¢Wl½<âÌû ã¸hÏÒ[1…Ïö,êžÎ—Ä„ã,ÛrtýýEq"CŒR˜‰[‹¯‘�/‰ÅS|q©ì(ùßYáÏö½ðJË]ò"D OÕ\§\<(¼è片�£Ù§�x£è&9_¶Ä*Û`BµÝ�[ Ã7pE˜¸^X‚£^‡bÌé$ð~HÒ늓”]øÂ˜÷’»•/!=_¶¦úL;é^‹GÓKùô\šÌ«ÇQm^­(�àú-øÊ@Úõ[N|—|fOæàqK¹ðÇ@Ú��F%¥ÓYnƒ1ÖŧÀO¥<ÚSc!8…"œÚ7]qw\�áEoï�õ Ž«¨†ÁyÕuW Ãî®xN˜Ìý“÷ÃÆŽÂ+ Èo+ë×õÇ›ÖýàÁ……8§å>º®RBYÙ!Ü>A[Xx½‚Î�œM&Á^¸µÏxô9Ò�W�Õk°Î_´„2ù©a�•£¤âÍRžõ4‡;–:aõ·›¢}‚©Òó¼¢6½ZAÎ!'EÅgfÔ°G*šÂoßZ8Z^„©Ï£¸ä(AèÇ(›•‡Ô𺉶¤ÛŸË”[s Úœé¯Wå«ôÄô«hS’7^œ0ºndð�¸…¨!ýÆ LJY?Á¬òíܼо,k†å߽ЭÓW }GL3aäï�Æ7�:¡Þ’5��JºÑ‚—³xÀCKHO„¹{=¤{äb¡¶ µ÷: /掣7“?RÑv{¼úÑ_~žIÕv²¨·¨O¯nàºü�ðî¤7py.ÎꆿFbú—Iœ³ŸóŠƒãy\k5|ˬ▬íÿ4ª„5}N‚�ÎIžþm˜–ŒÃ«æ +úTRCYÖžÙ»ÄÖEvlx ~O4ÅàÖS-Ž}&‡�ö(rh­ ?­š'ž .öGo 9¬óy±¢¤Ïs§ Óy€F)÷ÿàD‘2*8lízgº‘ŒÇ�ç�§(ÌTVx~k*¾ÿ:ŸÞä«s_èà%öl üž~�¿,>;XÂ8AË_>‚œŒc¤TsžÚ—ì–L0˜';ÅrЃI°F#’³+x°ì>Ñí(ƒÇŒy°!ǃœ7áê)ªbÏàeÔgc ÕåBÁ§-ÐJÙD/nƒ¥A!¿ÿø�~ï’rOo ˆ3ÖÖGÃÑšÂóº¼gä"é÷·Öø$ÆL4oˇ˕wéÖ÷ù8@c'~7`Ø»¶ ®»¹²ýêüS�?bŒøgíNxºÕChüŽK{…#¶�ãeÚ‰cýGI)-§ÛÝ,xÆnoì1Fw½—çøS¸Ø~:ÎÎÝ�…'['¡²Ös²¸<FÔ~Ác'è˜M0þýÇ;iÁ`ëØ’dÊ�*Ú‚’éHAvÃY4î�½ã ¸a¢M=ê·ÕqʃAì2§vòï3ª¼.â”(ßêNm .Ôwb3 ‘…8îmž¾n ~ü�AÏ9ÇFƒgšÄÚnå(ã§, ½’%çý¯�ÞÖ¥¼c�fG.ÃÌyzÿX2€·×—òŸ­›ñÎ.Côëÿ›f–�@w9ä} :¬yÛÖ}ò&ë¡Õ�,έˆÏ•SëÙ’›q¹°×!oÞ”¥­ÿ]¦YƒúàúFn𙇄�Å6<Î`;î s@aŒÊ‘ÇMÞ½Ø{Õm8'÷—Òî;¡BY÷Ê”ÇÐ%ÛéÊùØï² �Ÿ «¯ý®[m.×aåYõTv¨‚¿ç»n8Mfúù©sÞ<÷MÄtólø}®“,~½ËFY¼xú]8Ï�Å}0ëÈ8s)‡¾ïý@«Ž B«G¡,Û]Å;;X¶+•Ÿä$á];Žüï/åHF¸“mí\ïQî£'œùá/¼Åßç”Юóó‹ÙÞ¼ÖÍ�S*ûâåŒOÐ÷U,–¥�Ï> Iùý84“«G”ãÛï ’UAmÓUÑ­RÊ!6(ïR·/\F#Ý}±øëw˜’Ç;:¬$ºáüÔO�Ì‚ËðOˆŽž*�.g“é¸}ìØ©IõejÐOF“§ ZÃâÁ2Ôœsœ_Ùºó¾;/„'A9�5â'U9*±ëÄ [:™TÊú£ÖŠ»´mH à9i .”_�²�g±\bñºª�ä¢2‡#Ôo YÏo�l¿Çåë‹/�dèÕŸ}¸Îu]Ë7d¿C;hÐS\YmÌÏ÷· ["w๓ã9ãëkÎ꓉§SõmMR¿ô º¯n‚È”¿°öAë×O…¯úº¨Ñÿ8üꞥX´ø4¼?QN+£ÿþ�ƒóŽêÿþ¸¬¥lE%£�JrÏ!«A©>‰†UÑ–¦Ò2#"edS4H¤!qÏ‘’”JTÚCÒí4èçûûÿ>îãqßïs^çùüã*šW ž½wUìòY#ö««ÙÖððÁJ ½ö%Q}¶/Ç¿¢'Ws×Ý£bBè~–Ÿl‚ê÷óHþX1_2µ êy|È% ûÜìé_µ#tèó@�S°d¥ŠâܵØ­ÑJ¦½nÓˆ\x‘m%þ˜ñË ámù©x)sÝÚ!ضŒƒ(•™¸9dêÿ,Ÿ­Rd}ë:ׯ8ñT¶£ œHúç,G�ãÅsj`@å:î3>˜›†¦²‘"ðé·µtT¾t¬PÄA�øÁ¼‘ô,‚hãøS䲦…¿˜‡°e…5>sLBžR„;ê9J[““ñ&mT£êÖ0Ë�ûb`Þ!Új@o&Þ¤¿ß_VÄ»/—é¹ÿhlÚiņÙñ–™›°dq-5egð”æJ|:ã®Ç�ùÏÙ¬e?™%ª¦óQÝnø>OØ-Å%̓Éô_9ôi†MîãÈúÒö•#äÇ¡ ^yU½O 3ªá-•íü~äSй:–w çîd:UyGý8×]íYšbe«9æã{äÐlúc¶ÞÝ‹îÞÐbW:ev–ëƒYVß�ÖLW'#–y†/–:<¢¥'ã§ß”§Ý£U²4ÔDo�söÌÞ|<‡�Ô�DË_ãÙPµM(ô1Å虦0o�&?�×ÇÑõøgwX`Á§¯9Rø´(ºß+š®[Ñ}ÿ\¾·?–•qÕT‹ËáX·—ŽžŽ·ÊÑW“·à±m$ÕØGû%PfûM¡Ñ6<Ö¯¯=Šf¿AÿÌ;˜1êΈ] qø³»IÌ OÀ´s´ä´:.RLæÒadáøw~žˆoòÑë½Ù|óy4ÑRàÔky°u; šj‡2æÁB‚½û-cáNÛÚÁñ*6`ú†f |NO�ЧŒFÁV…ûîµfïNA´“éËLØû^ PÃs»&ÕÙ¨ŠN¯ã¨íí¨PY‰^q/`š‘xÞ’²Šy.AÏ|òºÍéÂä¼8aÔ®hιW‡%Ó¢„?­ëøOÂT|ô6Æ;Ûó¯¶qxÚ{-ÞÌIƒÑf«…·1ì¶B›O%ÐL©Þß÷ÓíÜ�ƒ±ÑfÌK¾Âê’8Ô•ýÚî�] .Š­g@n´?UùØSе‹âz—¯¤´¥‡c;§SÅËtP}Åbò RfùäptÈ{¾jóg9V1µx;¯�—ÊKÆ fÃ{´}ò.Vw²Äò—a­Ü9ö[š+¤èå‹“@‘32¤©ñš5Œ7›+ÜÛº çh!ؾOu5äñeŸ|¡@/†¾C©x_>{!�‚/<7È[áxgt ìÔÆ¿I‡}âáÝ€³Ì.Š#z¿¦Þ×â½S‘‚û*wþø|Ÿø*6[4x>˜%šm±ñt ¸¯F7ÝÜ�1ªnvâÁ™ \Ö4ƒ ŸOV‹‚Ñü„ mpàç|0ìN„œ5˜�Û߄Ӳäç4’IóÒf4 ¸*.|K<º¦4ÝòfÃË–µZCX1¡n|[OÁ¦îI™0zÛz>Òˆì›o€r}wÃÆ¬7B©8ž;–fÀÙ«ªØ—�æSÙ¿)´­,“ÿžECZNR¢Z6¾®�¤b0¯¿ÏÌ[ÃÏŸ™‰•�üëŽ-®Ù4•ºîKÇü‚ŠåÙ¤¸Bž&÷ðtÊ™=uJq8DÑ™\GºlZÁé�¢ã[ú˜Z†7¯Ҵ©ø  …Ô†‚ÇHÔØ2†÷µ†­Œ„äM‘p´y‘ãiaêÄR¾y;ŽÍÿHa°øÙ¨0~ ˈ\V›'vé;ñ�æïå:ý¿Â汬Y=ÅOa´£¿le*¨¢ÍH~W²�:«À/UÞddÄe¹ø:ÿú:ûÞ¹Â9‡Nñ‹‚CðKf°Õ†é¦¬¯–³eDŸ%œe‘€±ÞW…�‘aü^®[ [ŸÆ‚v‘,.e×W+Eý×T䦃VËk ¦ÓÚj¸�BJ>ÇHîîO²˜ÙŒ� ¡Éø ¤ÝùK%*yBo­Uø“‰«MFB@ž ÖÏ~ˆg[£ð†ü>b€«ÜžÀïªýXE†r|âIÛ¡ç%âñȇâ�hmüî¬Fñó.@pØ Z{‡¶Ý€)Ò `³Ín¨z„ãßÙrœç]66š×uÔòÃ;)Q«Š�UPl€ Îé>.Þ|8Ÿ+¶ð5ÓŸT˜à dž¿D×*ðÛ2 ,”yLÏáO,1"4½Ì*!c}4êÖzÓŠI…u‚®uç­XàºJ1– Ïä{�Õ$P”\–æ“_íØó¶– ÌÀý¾ /ôîÁÒä2üû«SX8B�Í Ó…Ó'…CKtøî~k0Ÿe2¶ù`xTïÝ8¾/šÏ9•;…è’ w´;ž©ñ…‹Ëp«äwÁÔé=ŒE‹)µüj~7½ñ’aWN#X )|Ü:ˆu5ýpÁ4w´4ÿB-�7ÅÓ^5æ¦)n­»€o%¼q‘æLŽßp;wüà¦óò•!W:édašp`à~LÎýWŽ{|D0:UJqíyø¤ÎåOÃmõµô_#mV*^iSDëºÍ4´q/g�Ê¡AygàÞçÛ‚Ûç�âèß�…‘’8s­ÿPï${¿óô2ñ)´;ka[ø ¾:a&­üÂm“3ù†C3¶)™Q@ù7xÕ»oyŸ‰«zîí%¿y5šv˜}r †€iš-ÛëX³Êªh(Û…‡×€°s¾þyšÍ«›Ä†ëèþlUJKzï—&ð¯h'¹“¿4ý‡:1`ìÉl6ú1T›±½&«ï+bß'ÞâM¹ðŠ©coÐ1µvXöHÒzÍ—@r zÙÙòøDSÒ7i€3NI`&'‹§‚•Øiç^t^÷›Þ¹ÕCà {ìya>þøWÈ \„•Ç (Ò,#äõ¹5h/ωqg;£E¼µ{)^ø¾Œ,Ë“@¸d�Z3/Àú¦É¬ç\ißóqüû“âÁ]¢øòÐw¡ÖM›¥Ž›rJ’X]ÕgÛÅwUE,+*ཀྵüº)Ý�Ã8qîEj­SGÃ…áP œÏ+Ljß�Sx@TD(¡—gæÀ'M)ÁóyO=«þì ‚µŽJxα™fN5¡À&Z1"³®¯¤Ð�‹¹èâ5Î��X1¶æ(š˜ûb�åI>¯›ÄŠsãÈoÆcø’”/ˆs*Áèu¤&õB|âyOØÜ’ÀuÍÑè1Èÿ;I#kb¡÷�¡|VÕŸC$ŽâNc‘n¥¤ÐÕâ7pzy¢8oV_óN`+·X�ÉÆ© \}S‹•ΰžÑºgÅÉþaµI¡�éq 7ŸÙÈ¿|ô¸ûŸ$¶/¬…º’žÌKVêÉßjiô—œ»·±ã“ x«cO?w«Üåø¡Ë\vZ¶7Úðñ�Ið¯qo89Öì¶e£”�ô!N ò®Ó«¡éÄ*w�k߯’ñÄ4³xŽ– F7ÏÞœlx˜RÓs4É(Ù‚�®—‘ŸÍh|Ûu?Ŷ ùF\úÛ‰k6NÂq¡_!õ´þù½¿âüÈÿ„’lÜW…ÓDU>œ^ÈOûx°LnŒÃ™\§¥Œ÷]ö±ºþ,ïÓB ÖÇÕ“›Øþ�mÉœHéUµÂ4ÿp.‹êÃâñ�èv•^M™ þ.½ù¼+Ñ倓¼ß6A(ë`2 O‡³óÓ“Ó›1ÒNÏ8¼ƒ£´Ù×ùçî>Tœà€ I‘\Ó4–¿ø…ñ^J™÷”}ëÒIIÞºÂI°â–‘q0ïf#Š~û1çï±*4l+ç~y»~Ä oÕp.îjäe�ZëÀª§NˆìÒIÑý.Ÿz•Û¿­æC¿4§Ý Ç(£+‹÷}Wòo{CÐÉœ*<é’ä²Áqrã#ê»?’º{ ½ê&ò�Á½Ñuó!~ðY.ÍÁfÞ±´äò{HiŒÁéwè\úS øˆï6¾€—®ô{uwEö^?¬ÍºLŠõv¼#ñ0O¿0ô°Ø wí>p4¢Rί®¢‚oŠXTW€5`HÉnÐHb£>(¼ÙK{£6±‰®;ú?WäVŽ´kš&º¹îÇà¼!_ØxÖƒsî…ížö¸¦é#¤õÚÃJRqø­v¶h§Ê#ݽ{( D‚�¤VýV€æçD¾ª°¬ÒbTþìŒIóú�SV]©��'¿�‚ÑOƲŠàÈ“{ž)}W†ö'ã€/ÓPë¤)ìªq¡Iq7hIk =¼km˜Â–§¼È3\™ètý[Õdó/›Âz¿¡ÖQÝØQÖÍÕ©ø«Aš{ø¦Àý©-qãK³Ë„Û÷¢øåYÑ~Ç]-äËœÑfk ù+-À„j:»mûW‚ë\”øûÆ-è[ÀN·.qç‘Ç´ïô2nh†³«ãÑE=˜eŸôÇ÷g>á«â‰lìšÛ:9qÑž=d_¹{–&îã½Kƒ…€;Úö`BE úHíDçÖ=Ów:H‰ßõy¸äO°ïÃ{Ÿœ­h¬Ø‡Ëö6‘Lf'˜?cÉ´ô'ñ‘™¦ø°Û’F?…‹�:):ôÏÔÄIáжY«¦åñüµk³8ôNï8æŠí)ðQ˃Ëí|ù}z(Ë·¤ãÑ­s0Ú´&¯;‚¢ E. á¾ÊHÒò˜)žß\M›ðiÔ=›d‚w{o%×[I-p{¦„N¢"¿Þî:©tYn_‹}¾þÇÃþ·ƒî˜ï[îÅCFœG—p/œî1�cuÒ{—0Ç W%ý�#pîªPtÈ+å)½gâ¢a°6ïû;íÖ`ªv6Ftëó°—¯)b®#|ê“‹–‡•Äã—ò7%~˜éÏþªÉà¯.�lÄ2™á£fj…ï¬(T*ÎëÉ¡mâ¯3ÍÐ~#™–Í} Ç/J` N9º+~‹Tmh×׿?o—–�äY~Ã`eO�¾Q¢è'‹ð™O(¿# –�qïÐ{´¢£?–æî¶*¨™ÆÛÊaëÕ€IòJøRvKŸØ'î¼3�‹ßB}™6̰’”‚ùjút”×øKvOÀ¹¿$¬�߸‹BYV_–¯÷œÛÚüoý/6+¼N§èoK΂ãþ‡ñ`ò+±<ö&Ù‹åøpAoz‹Û÷õgg­¾¸Gš¹(ÍšýZÎQÓâßtHk;'¯ÓÂù/øsÝ$¯x¦¢qñA¾×](~Ú?€2�²­ZÇÅcñ´OÂÙëãqõøI=áü™2?„Àžqoqöt]¾r¥€ßû8`¿N˜d„�Eíâ¶¢%X÷÷-Ì6‡½e¯ð˜!à«.°½1r«ªøêK^]H¥CwR{íyÜ/¥íêWIçñŠÚW�.]{ø³äi˜ë1‹n�øCÒ]á¼°Ê’¦é�’.Vßn—Óˆ_kÐÀ-› ?_cKûóÂþȻԹ2 3” fÏgpïÅxûÄOøÑ]º†ÏaÔù"�ù{Œ¶¿Ø,nîáz‹þCѯý8ȇ€ÒöO æà‰’¾RËü ÀÏ?’î�Iªá«ðSöšóƒÿ&ñÓ£|Ìyá‡_�#ùƒôtÞöæZ ÄvªiV^2U¤\VÕ+ ¼ãkQnDÅ‹ÊüÉf3¨. åó¥ÄµUðwj;´t› ’=œÜëÔô~jÉÏ>ÚaC”*O¿–†¯êvò’ÒûbÃäd¡¶ð /ï‹Ã—]…µË·SIì}Ú®N7ŽŸŸÇÅà³ßÏØöÂpw � ÎÈàÇs6}nˆG'<�L5¬´p¡ÖIßxm¼Û¹Ÿïc/þwÔD°=|‰ž;Ÿ`›²kpé”2M'ÍÕªôÓì2×wÂAåå´>=®1 u W÷páVpû+'Ÿd‡÷â§y*ÖUY`‚²"îü!ƒ_¨ŠÒY›q‰îø,ûÔ78г™j°u]Íp�Jz_KphŸdXª»…¸Ž§cIÇ rÄbvìþ·Z4(=z*Î<,G×û¡ïÍþa% ÝË÷àûýðÃs Ònº+ÊëðX˜ô~}Þjws?Ji¿†Î½Éê$žä7QÑvL‘sà‡„Š¢öBh»2œ_þðãʆ[YA]ž‘~\«n‰â­±™\õö$'ŸûA//o€Î·^p—.~÷ˆ�ýÁÙc#­BÉñ�10ËÀ×á`šVø›ÖtŶI i©Ã0¾òÛûW+ß ®…zÞç‘#¯Âô"åŸþE£ªy{o?±äÜ?2Ú®Åo²”“7^¹î�æ6Ñä­3xŽÅ,µ²àb¹-l/›)LyVήÚqìßrœý¶\ægZy¡’Á¹záðàÓTsõ6|äÁ¿5¼plÙB<ú=˜{[+�äÐãÉÏ^‚ç°*œè ë:ð¦áÿ öT*¾¢T4ß!>ÈÕäʈ ±õâuvës†­�®ÒÓÎÁjl0æ÷dïÛâ¼�n“ÄçYrÈV7Kçs×�éÑ)|ZdÅÊ—‚hƒÃn¼J£'¤ >ðæ#XêÓ‡—GÙã›ÐxYX�CÖ7Q¦í¡A"ž,#™%õÄš_>œ´v¿è£-Å^³Vóïà,AMVŸç}ŸÎŸÆI°û²Ùøñ˜€R¤áÞ°Í<Âé¿óÈàÖíQX²)˜Àf'ûlÜË¡IFÀ;qáe|6³v®”@~˜Æ»ôÏÒ ¡7]~WKWÆl"ýké8m@ga�IOžöw̓Aa([]»—Õ€~Ï\’—ø'ÜÒ³B�sjüdÊ}^ÿYŸ'¨¸¡ZÒ þ”õ n9G±ûÏøeãeÒx¯Îý¿eAkÁPx»î)Þ�:Ìž¯T`T´¶°ðü`š)ÍkÄñì­ö[¬o¯¡ÏÍcPÿã*ù8š�J|1L" |KÔ«xÇfpLЦbúOï8\ˆKàmv|NAlíÆ=þ�Ì&¹œvz}i|BOóöí›8xæzœÔó>›ï[y”JŽœ¸W�*F³cbÄÛ—f±ÕåNÚ¦‰>Ã�Û¸ èX“#FË#Ï8üŽÜÛ�¡kF'4ÛôåI Š >kÊ#p~€"üt‹Äo�®ó–ŽåÐ8%š.W¼sãóh³A_ùâ†êžÑ•?©0ff4ʽ“®|´¡œb¶ à†_[ íÈQt^j»lñ®®kÇ>Á9çÁ=õ@…�Û,[û™ŠrmH¶ô6} �àžy LD –öÖ®-”dÅÞæ¨2ÄDèˆû#ŒR©aõõd3Мv=1e•aíd¨ÕF…óßÐß×ÛðO‚›ÓN±KÔTáÐ�ËØ*BZõ>ìꥋýt÷bü©S°Á}Þ¨Ü!Fj?¶òùpGtQ<Ä9;úãµ5ýY6È“_]Þ‹uŸ6ó¢7ÐÏ+Ž«¾4�pd*/Zm�û �p»óNî®YÍËÒûaœ(Å~’{(dÁPʹü�Ï™KáB™#�ûó ¬Ò³²ª_jÏ{|.³­|>ó­Æó� I²º�r¥ �“ò›ËÑiù9Êìð¡-§Êùwz¨8n¨ŸÕ5eû¿0o1þ]hÇœür‡”òŽ¥»á–Ç-èºwCœçpòèœ×¿˜Ýi„æ$„Αƒ{|k �Qp:ƒS|Or¤gZ…ã¬LŽXfÌÛ\ô¹ùϭH¤Ò(î×ó�ûÌ÷ a›;‰¼:.›‡x}ºW£y­¯ ßJ}JÒÏ{1.\Œ×Oð,Y�þ1“~餢½R-Ðv"™È£Ê~o£Ò“•Â/ëaxat….Pãý %[’îÇxª2 ü‹6qÝ6ãÿÿwÏb÷{ˉ�µ êý:žSìO«œƒaþ0Ux´_™w=²¦É+Û@«´„o<¹I½*öp©Y+œ?1¿°,Úï”…5éÛÅó>ØéC1·*j6œ£ÄI¶|åzx¦K“ôuvÜt.hLgͧw1Ðñ'|‰>+Ül‹àý�_È5ä}ïÖÆY&‡x¡�%—Ϩƒ�äHáŠÈÄÌ…-F‰¢ó;ö[çÄM ,9Æ^»²ðø§Oàã­Â&Ç£&…XŒF#ìÖ</öÛÁgÇóXÅ:HõH)z»IzIŸÊ¥¯jè–ãLþoͱWðL\ÿoú>‰•?ƒÅmWÉëV K†ñTŒ:gâðù ŽÖ}Ä/¹‹‹ßÓîäel-?A¸8âùEâ¨ËhiØê]·V�pÃ�Ž%ä“w.$Û«›yœU¨–ëEÏt�W5|ƒ©—Ò0ôW%õ>ùU€«Ì!鉜fœ…ÓѨgnxµ�"jGÑÜ‚æs"¹¿,ÇË]7Qùå (\‡¯[†ãïm‰8ôŸ¿Õ•’l¨ùò¾ûDpà-‘kÏ�Æl©ÓôrÔ0N÷(¦ï5T{±?ϬNÝÜë ¹¾lÓýÉâØÇèì9 >wõ»mqg±z;\ÎèÍáòér¤¾8jæZ,}SkEY_h�ëNö*^€ë}7rcø@ÊhLâÞ÷A[Á�-æo��†úè(6²¾D¨'\¤ë³o“ù÷0ìó9õÌû²z°&~Mbhf=Þþ’ìÎÃÚÒžz->ŽëC<)qÛ6T_`‹à^ZÔžp¾Y–Si¤6ü|%†YÎáõÓß@å~K|˜½�}Û…ckærì%àu¥FXܑˇ¾[sí¬\HþRB)gô¨fÿ_˜zÏ ‹µÑ¢«‚2¯À>36dˆ¹|dÛ ¸6!‹ïM×ä'‹ø¶ùW85)…òTçÃÊùálxÞœm˜ &_³ñÍ$)–rØ��£¼h¿Ñ*?u‘~zLÆ–‰ûéî4E m•ÅYQ¹4Ͼ�l{̹˜µ¿PhMk•w]/œ…}ZõiÕ­ÑøgÆT°¹â‰®wÃy{·$wvÎĉ‰™ 46�ž¬Ë§ÏŸ7¡�N¶_"ƒÏõ¾UgRzÐì^UÉÏœ'Õv*ÌÇm-cÙê¨æÌëË!áVNæ‹¿¿ƒjyp“œÀnFï@aÈ<`<×§íàŒÎ°b ¡ÚèúJT•tù(�±–yäñÒ�¬+6ÐŒ/—ɳ[0"K }­JÁõµÎkl�©RÜÛqk\YËËn†ñÑ/ʬ&c*Ží·½÷„àãa´ø]1äÔ6º¾¥¦‡Ç80¦£¢nûT1>© –X²TÅrñ�Æ' ±ï°§ =ã,“O?\ìž�¦…ç0XÏE8>á%4ô¿ [ž2 ç|êš“bµmŽ'ø9òz…áÞqÞºÝÜf&‡? Qצ‘\&_ÍmKüh“ån¼;—3�[ÏÎåWŸbß+ Jluƒ»X3Z—eµÁX¥/ÊÌ߯fëã`È›ÿ;-èë­Äã×�xí{=øO*‹ï۞Ķê7°$7~ÜÌWË«d.¾§±çRqR¯C°h`1å&L¡�¹˜5ï´]ØL £0×î>Pk„øó£« vB^a%¨·‚êKnÈ¢¾:¾Ëa'ÙÃçÇÕÀ•³ìl`Œ7¢¦óÙÝC¬$ ª0´Ç™oéæYñvPdÐ%xtÄ‚~@7« ø œ›ËÓO®Å$WYLò¾eõ£è•iF’¼¼*žPyŽ¢®xþ�>q‰�7ìä¼ >üÊÉòNÝ¢tð‰ÝAM=ùtö/A²"‰O¶=#»À^»6ˆÁ³&bÇâl«aݬŠFÔ‘dÕaò÷Ë¢åG†àÞf{nëôŽ+g mú}ñ0ha˜y·ÚNBˉA<éPYM<ˆ׊a\ÿºýP?~Ƕ׋ÛT͹jjfÅþ…*N^93Ç¿£�1wx…W ,ôßõr´<à%ÉŽ×Æ}íðx”gõïL1Ë€«zÓQïð:cø„�£_ÿê ýÒøv!ƒ¯5@¯Â¿BTæ]a’Î#qBž$iˆv5uX<Þ3›ÃQ5ëÞàÇo†ó“g´µÕˆ/M½!zY4z”2Ö×fCFë(¬ ˆ¤;£plãªÑ:Ào%ñûÀ?bìñrJ)ŸÆ#3¹Ö2޶nn ºúX8³<”æ_‚¥ "°Ûr(-P˜Žòa‰œwg�³v ‰ïÉëÜ:ÿåIÞúƒ�‹=yóç`¼a@Øí‡ê::ì# s¯Ž�Øð aüâDܵûÍ;ˆZãyb£7îµÀ�û'à§¢xÑìý1øàöÝKu¸íÚÞgf‹ó/ž¤¿P}ŸÓ¸¯Ž°/lM ÎÛx�[­!5vݾ‰‡÷6–…²®ELî™ër¡ Üzô’p1ú¯)§-m�”rÄC5*ðÓíTŽúM5×iå�d8³‚sôØÄv<ïÚoÈ1±ù8tz¨pnÙ3Ëã}•QêîüœÜŸŸî"Ò)IEI U.“Ä‹³–BÞ‹E4Ï(ŽÂž°*™ÐáÞNMfFl›š�‡b6ƒXW´š¯Îªf(t.¹³/‹³Ó¿9š)ó¥šHg´îZŽYÓÓÈ2¼çŽ+î �«ñã H9A��Þ5³Âð:㑆êgL8§nkM 懎…$_‘ƶ9üŸ{LÚAß�Ô10ÐŒ•+ÅÃ3hÿ¦BÑXÁPì6IÀâ­ˆGe‹%W'òôÇ–Pct_ü•Ž’EËðvŸ5|sŠFOm¯ÃyÖKPíÓpN¹þŽK)r�,°Ð2¾›>§á¦SpRŸ<àí}áE½>M(›#M<±&³ÖêQ~OT>�±ñЬk½ö¼Œ#�VV|<“¾™†6KoP^ILyêÈ?ÌñÞû£Ôô+Ôvrü�~ì3Ò â¿Bž{à~$Šd;äùÐYUñ¡r<8)/Çy/N°‰œ2%…ü¸Xi>cöRºŸŠJËSqãRI”;™c ¨æã¨‚Hþ:‘ÓmŠéçï�bÈ ëð[R”°‰†PÆ;J'øRÜ0|»s¶xhì¡IMcÏXI”¹b@cú{NáåY_ÜõLJøg1Ö¶Äe)ìëý˜f/Ìqîsy ªé¦ Em^tæ±htÉœO¯ý¿�GTÈ>}F'f(2Î[Ê-¯lqXb3�ÈN3�eq4©ÿ KÛìñéÃx({:ÎW,⯲ßÄs›µÙ=XŽ—Ö¥£ÊÇB±ïMOɈo›þ°¹´)¿ð´¤u0ëÞ]x2ñ ¬l¶ÇòiÀò¯9Þí�Â!/¤Øxí Úh¡ûdrÅþØ Uþºò·Ç¹ô~@ñ<È_+×ÁË¿ûAý¤²ð×znå­'^x¦` è¾,â]—yƒß {�¬·o¡ë$°áÂ.¼àÄŸeQy´(x™Œeå?s`ë··¼ÛÁŠŠŸçÙå!/ŒÑs ù·Ús: ” o#°¦Ý ø“î*znq@I…(~¬z– _Á£ŒeT~ˆÿ�B ‚QkWpL½ç[éð®Ø�,Ü{! ’Æ11;hÔð|êü8 ÓL­ØÐ)…öªß¢¯­o©s|™7‡Â‚·wáv[ ßúK^Sý1ì¯}kú'ŒŽäÙGOãmB=´æ_7«*tÇ/çg~ãhî¨8øËpŽú”—ëÒAß™xaÁüºò&Õ\g±hZNÉýMŠgðn†Õ³´é´l6çû vèl52ÖäÜ“­�pr•p:dYßGåGóÑKfæü(æ÷×âÇi Ð[Ƀ_4 §‡jÓ–=Qtsu.HŽYɧo½$«ÑqhS!‹ßín“ìÁVŠ Œ§ñ.{8âXwÅ Ú¾¼\~94¿YÍ}uÎÑàÄ\*+1á«ïV¢ÉMîõ­§—­ã»÷Îãl�`8v?œ-ÞÏb$xKš&ù{ŠkØmº7F¨‡°wÐ|<¸dÿ|k~*óÄÖËüZn ÊL' ý`:í«ŒåNoùΡ<Ú´¦‹æÜwÆc2�éŽD Œÿ0ŸÿêÏí{jàÑ£dúüç¹0w윭Êâò§/Ðy»¿¸13 ;9³{)ÌP‘ãü5‘XPëÉ�ÈéÌÏRïCë¡$Ž)XÈg¾µ¢ÔP®�þkiÜ¥‰*-Åœ–´��š‰§òÏcaðA*R=MõãeqI?e@uâ¹.?r˜`À¡k¬LÿMçÇ_9Ú%˜|¦Þ¡Él ú(sþ ^ï±äØ}^rÇ‹»u¿RÙ�ôUûÀ½‡ið•'‘ü¼Ô%¾ë{=’ôvAq\ÏnˆBÍ9I0ú¯>ÍÔ¹'÷â¯ã²¸‘QyÁ ô>oÂjù¢Üô*ò÷ÜNÃÊÿ‡¯�^ùí°NÌfñ˜,l˜¶ŸUÖ„‹’j§»•¦°Òã%w´€Çœ<ܪLá7Ýø¼|' ¯̆c¾‹«{ÝlçÚ™âEg->&ÿÓå8¯ÛìtË{Ò•{ áŽzu…ýOØšpŒï{ô,Ó¨-Ü=÷G<Öö�¦”ssq"ÚNHáƒæpé¼…\¨q˜~âþ•a|úŸËST– ‰§=½þt�< &W?1‡¢zêÚ¨¢ Ø�‚‹97è”ÎE\±EZ¬³mƒ%ád­šðòËcqâÂ\—“à ÍùRùq&£T¨ïë‚{oH`½MŠ8Hê}Kaøôë{/?A K‰úKõxÌ”°¬‚ ›1Õ >xï³�9Ô�µ Þ˜ˆcôÜzïçu·�Àz�¤xêÝ8>éq”úû¾ûÈ|o ÄWÛ÷qÕ??Nrk Â ¿_ÛðŒ6;Ör™ å1­Ô1ç6Œ \‰žQÃ1ÙX—½N½Ÿ+²OH2LÐ>„¥“ã†}ùâ‘LÜírL“^N š2è'õÈæ˜Ë¼§Ô7ëØÂ”þ<Ûâˤ ãüý=½hpú'^@¹älhø/~Ï4RFùQŒÖ öW(Îõ‡Áq¸7|$ÚÎ,fÝ�£­lÊ&sJö.î5K‡Ÿ'»¡QW)þ•Ë�Õ{ŽÓ¥÷b³»®Û¼€7åZã—àÓtñ�ÿÑ̇Ðo&T0}=‡n€‡¼Ï‹q (å+~«®ô߆n·Ykñ X;×Ó“ðˆ^ûḡ:ÅÊÐó;iøíõ;ÐøNµX^¢‡m[0vÌUˆ78‚f$?'ys[üž�±‡Üí½ES`ß±¼.ý=èŒaqH1 ?ó‘Jy®.z‹Í*–œ»ù ¬çws”„·²>\µw;z®tcó´u4N_Žu—샿hÖ/ŸÍK÷²í÷­$ã’ Oæ˜òîœ{ôÕÎ¥­2pÙé±¼ÆÜ‘-�›ãÜ|Wo'†¹lá7G¾ÑΚZˆ÷¹Žj³–àÙmñ�ÓS˜2UŽ[f»`ó˾P_°îíÃÈõGÅ\ÍTTR¶`¿ëC„G}›ÄÕŽNäœäBšmYpqè®Û�ËÐöìH ªˆ¡û.;ðòöo´åÙ<, š|€‡è/£«\Q��áÙ Ú¬=á>ܹ¹w—zbPË"Ì—ÜŠ à†í†è¹Ä�½š áï Iöš&…µü&Ðf©ü€†q%0ÖÊ™WÍ2å÷îW Ã# {wMá¿ßÝ0ís(9 Ü#Þté͇þŽÇ}Ç«'š·£]Cy…¬<�Ò“áÓç3#ðÊÇQd%Éz÷³IvÓÁG+žç;˜ JoÓZF�ìÍñû ÙÛ¤Ú"Ð<$œïÏÛKÞõ±(¹G¼åÃàZÎ7á·Ûnšu:3p#gm`û»ÐÝU ?xúó¶•~§¿«âð;qê& ,Z∮^o„Fó…´ãQŽ8|€iE˰Chä—@óLj¡†§hÃn)�‘UGeE-*?½ã,ÄÙóÀÞÈ—LJOòae@ÙévhÜL¡G~ u_£„÷­ã±÷ÓD.o»Iÿ=¬¨°ïÉÄs±Ú´cÊ.r¶öÂ]w¼PBÔD‡Žb¿…p$¶¾Ü�ç¶Õ“IÇþ,MxGØ’ï<~B'eš7“ ƒ®€ïÙ&*7ÈÅ[®±â™3¥LEnxNÖšeDˆJZŽ\1Ü•¼kÛ„ Özx3¶KÜùn7töe—ÿfóái~†‹¤m0÷ÑAü=‚í�gнɃiêàñ³0˜LïKóŠ»'Á4ì ¿ª ï\ðzýv°¥ÇvO@!Jûü;ƒò6ñoYœxr×gz;Ñ…ýÝìPuFÓUÀÉÉ ah˸ß4µÝå*oYÞ@õ»Vò¿Ï“§¿ e-¥á¿’û…uã%*·åÝ%¾t‰„a�à4ÖAPëÿ�L=ôèÇC‘ÓÖ$á—_Ñbeß°d�>ù‰F£ 0lÈÓÁ¾ÿ©¡þäa®ãC¿u,ñ‰o j$sß°?0dri©@áW2™h^˜Wùû‰bþÂvúze&ú¬µÃÐ}ØË5 OÙѶ¨ó8¹ë™L¬â#Ù`äj:iÝ�ºº>OÜ+ÝÅç­ðr»2É¥Á/Ž@ÌÁ}°Ï)”Ÿæ?…g™Cq‘Ýqи½<ñ™<è<)aY5¶2|7èãƒk2Öë›V¢b­/¤è²•íR~<™;E h~�®øì¡™E[àm@ ä&^çAþïk¡Þø H~=Îý/[âÂ/»�<¬*ïK[¨¤‰» ãhVÛvÑ'e”U”ž ŽÒAáöØPönçµ ×�Wô|#K~�„S~%ÂoñªUÓ{QªÇ…ü¿÷Æ…É12?ËÝ#¥g Jd!Mpè‚Oó qsûO²©ßCCs\0ûØv.’C[¥£˜¸>¥U�ÇíDJ>XÃkÃ�éJn n3ËèáÒŽ ÞNW±Üµ¢ŸÉðéš7\ÿý¨`±±és‰ons‡‘•B vT>F£¦ d™SwÀŽßˆ³÷GÑÏ©$®M„W•7B…ÿˆ˜‰ì{¡¼ü?<èi þÞ¾KÊs|Ã9¨+8‡Åi¾4ìá3Ð[qŒ:­ëYaz(Z_@¦‘1°^Bäœü¡x�î‹Z+PóGÞ±DÃ^ÇHæãØ0uUÙÛ±ÕŒÞlP¡/”i´ ;Î�!óèb^æhÛw³wFˆwDáæìž¢·ˆý£ûòØ,?¨Rü ÷¬ÆÍ :ìÕØŸ#< i�m¶X6¨Ç“lXHü,TE]@ñ`jy`I,§â^xš¸ ü&àú]ðny ì=¹sÜʸîy$÷ú»Ÿ.G¡«ñ†ÇcÚ_yžª þ‘L…ßý2ôÚ_Bʶ;tÝ`»W¤bJ)üps>ó|CUþëÉ`S«¤N´>Ÿ bC�¼ýœ¦8X²÷‰œ9y<Õ�ûK‰c2ÙÖ"ƒ&¬ b¿•¯à‚ºñÄŒ†ÎÛƒÙ§”±töa0õ¯¤ýRN¬ÜìÍ O•…W£¯ jÏñœ­9¶ÿrÀ3Qq\´èlX—Ä{?ñ›Ùè°?†ÿKŒDå§QhîõŒÞäŒc³blëX�n<-½F[Í› ›Kæ¢ý0DÊJäЩ¦0éÑþúÓŒãü+¬Pî/´Åí#ïVyÒÈˇ+r#ùÁ çà8å|6H� ‡Uê¹øa}ÈQî]‘h?s W{¿©ÛE\×OÈBmq omwä—ñÞ(16þv¾€ªv¤#�WXêÚÞ¸/„dŽ-Ã×±£0°è¡r4M“û ·×ïæøŽh10åb¿kàñ† ¸pêa ½é«Ço^M )¥‡Ñì@¡�¤6†Êo—$� ¯§ÚüæÄZ軜¦VWÑôQ¹”«�ÚR´Îä[oŸ’ê+¶;¨C˶WÄl­_‰2^�ÚLg#VâÍË�âp7i«‘Ãý„�¾Ï°|‰!–f­§ðÙþbÐ¥]lgñN¨hHÀU[Ü@ç±'ë­Á5r¹xxŽ&î_®V4âìT¤¥÷à]f=l|Š]ŽeXý=¶¥ŸÎbë-£1-{’hÑz’â³avî!(³[HõÃðz@ºE·ŠAkæ£cG;J*óÆå*d¶y%:1Rìè—É‘Ïúã¿gá±²¬õæ +Ô…¡ž£,*pÜx°ôÞ8pMóXîÓš"„UN Å±›!ømoe_H‡ ^RD×ÜwÓÕ:CxzK,/ÑKgünãÅeâ¯@lU*Ú¯RçÕ*‡áó·Ñ|m>oœÒ—Ý{q]~&ÜÏ×ã’7è§÷%ÊÐ66 ÑXó"_ÓŠ†?Æö ;rxt‚Žï�¤u­&˜µºQœ,µ¯œ úŽ <÷åA¬^¹'@œø}pR‹ ¿�CêöÝ“<Üq¯ç#P}ûž1´œ'öå;-ÃñUfþß’·qp„ UQgýdÎö˜,VƒêºaTýp"½ZAgßMàUãÈËl ]RSÃUmÙt½÷X~*tœ›^ÑíË“Æ=šÚÕÀsÍ2>·z«L†à 6B¿�·À´Ë�§„jà¡�iô°ÇŸ¼ÜbØ+7Œ?;=ùóCÙóË6.R5àeã’ø�¦øçàC~Ü�ŧJDUƒÁ‚êÍs~9Í}IoVµˆcΛ n{ Í6¹s½ƒíù‡ÁUÉ�UFZÒÞZYÔ?¶Šµý¬è¯ U1½|§ï< ƒÃ[Ç.ÒêÓ((, áUÊ7Än—rº¥ånUBS—m…¿™{yyk0šEÄñb“lzä;Ó¹‹ózióÃ¥~wÆçg'ñ“æ5‰}PñÖl±úE8ÿ�Öãc¿X2/œêë`QNo7™Ã{«ž Gö™rKtJqt¬ÎͷğמÀ²ìƒº ƒž^^Âûd¬w®-‚©sWà¡égÅaÕšÜR/ÍS!æ˜öÅ­Oœ ýã{0;÷€œº'óÆÄ|þ=¬>ØÐ_K:ãë‡ed¸ê›:ëº6�éWœ½ªN¾)ŠÉ |üèQån‰��Cnôæov®Ð.¹––Ò¯|¥ó«bîÆ£Ô­ð¦Þ¶aŸÒ`,3 Œ¥¿ðÜ�Ù¤yó4é,âk6׌ët  $ ÷?ë©0¼Z¸lèwYF|¶Õ/ƒPÜ‘šKŸ{¼]!©Ô«îPº½ÖyŒü?ŠÎ3žËÿ‹ÃŠÈLJJ!Š""«øÞçP²Ú»H¥T)i�Œ¤PÒ&ddSf¸ÏQÑ -å×ÞES{ýýŸßî×ïs]�>°]²$m­¬>(k—Ær`Ë-v3:€EŸVâiÙT™_*.3ض©„–ø‰9k¢ÿ†�ü24·6,âÉ‘|æÝr+�æeº¾À~ÊCóž}på \•ú�ä×^"?«rî´RªŒù,nÍ^9ïƒa¸Þ%îQ†î}ü¿tæ(â6Vdÿ¹Ôm�äÓÿ¨­ÿxçæ§Î¥Ó’efp¿öŽør(÷¨¬Ð’ü´I®u~š>íÖÁ¢§t|t1ý½•KƒâŽ 9oG ý,sh37¤¨òQâè7�èÃÙ.î¸ÉL3âÓÁȪ'&��mSp‰ЉþQxÐОŒO]åà[Μ&»š^1x¤ˆŸ¤yðÒ…œo©À¦íKèòtô¡Ä3¿Šn>sùä%6 ׃ AfäßžHïþ†s�ÖO Š(¤íƒ�0cV>¼iÉféW{qõHAܼÚQ´¾e ¶Óa¥køòÈ?1.^Å÷Ô ¸¬*�HçÎ…Å(×Å'¦~·d¡–ÄhS©JË›â•Â5¸µÑVv&_Þ™:¶J8÷¾ônê…�:-’7QNtrA6K‡‰1ïëE»¿æPwÖÏSÀ=ÛLEë’óÕ´¼µïL¤ÉÇ â,?>T÷˜¶n�Dù·é¬’- ˜ñ›<Šj¸Qs‡ßˆÅ8§=ÓÿAÁŸtž²(ÏFÅáå„@ìm(öIO¾ß§”þ›pƒººÝ×fõI:e�E±¥#YfUßÕ׿5gõD½�ªë3ÔøiùRP:ÿ¹²Ï£"ꨚH»¾ùH •@ò®îY«ˆ]½ù÷—aØ7•þöé2i˜¼TO·äÝmùôåƒW•ùÁP>b:R, <� 6P}MŸïéç�ÓÝôü„ Îúw Õ¯Û’]i.$üÔf“Ã2xzY/áßÊh*þ/•VYöÄ–Ó±p¼&çvibIá.Xó–Æ.‹'õGþx´Gzñ� ƒi¶ž>~ˆÀ²_“OO%©‘G)`úG7¾ˆ‡k†rÔ­x\ÞŸ¬ÊÑâæˆþ<=íŒÍ�^.¨¡«^<˜Œ‘vvxqürñÙÀþ|3ÄU— Pê‹2û.�ç—NÒøÈG†&Åâˆ'x*dž1ÿA3SÓ«NN~,\�û‘̆Y³ƒe-�=&ÊÃnãó~�èÐe´_«5•GкTM@=.á×G€v�m¬4�\OX“¹CxÐى׭®äŠ«s¸=㚆k²êMn-ïÇjå‡Ù¦ý ËÔäæi‹ fßAqÿ徨KË–�}ƒö·waMv€�âîŒq¯oÀ[õ ´=0—–ŸhÇ—/A3dËAOš;%«}Üq‰œ-)Ħr³lZ­êÍ^mÑüyÝQÜe¹€Çëzœœ„å?„Þ>¯Äº51”y‘.«ˆÐéµ�7\#•§µ´qr•xüÁEðë« mqç9aŒ´N­zž¶G¯Àþ´ÞŠÛ’�“WÉrÉ™÷aŽ¡ ?ÝjT|„Ÿé¥5Œ¹êFOÈê]†¯®…€éއÐö²;›fà•…ÝÞþG¼üÆë«´qýñ]°£ì¼àôþÌœ´¾äOGÿÔgŠ-¤]n¥«žÉæþLLžw‚Ï?É•|ê#RÈÛx žaW •~kc"UqFk-Í3Ö‡M ¨p{À§(ñB¡µ”Nû_„3_WÓ'küsµÎú™ðÖ=}gIcŒ­ …MPäÎ W„½ cx÷Ãx²ZêŠÎb`”òPØ0ô0)Ôjò¹FøæùAÅGÅnÑäÝ`î?5Ÿ|"“fÒÈR;ñ˜µ7«kŸâ§ x„çT¬¸!K Læâü«ï„öªì-¹HŸÂ QTÌ@…úì*²Äâ{Ë1]«'æFÎÆI=#ñŽÁqÖl/¥M.nä!Kfþ€µ3÷‚Q‘+ŒÓaÕó‘dýNv;�¸¾Ž–Jío§äŠcÕ3xZúsz}ß^m^!®šÑ c¤ alÌ3Šê” ŠÛ=ñÉ–$Þ�$¦qÉÐ÷ñׯ�hºZ�½£*+HíÞal�ñÂ2É-˜·ã6uŒxáq�¾äšãÑž68ê@lÕî·A4`Ã86aoi¶ä˜ñ1ø:B×XL·¯÷¹áÏhuÞD¾´N DzÎã´©ÿ?ñÇOz5«)BPs©bŸ ï`é^µÔ� £’(:5…nÞ–ܵƒsÇ�ڈɘùE�� S#©`Z!¦-ü,ÞP×ås… 4g²¯™Ç>¹ÎxÇ)ŸÇ•£×Ÿ غ8Šç*š ,ÃP¹í Ýþ»OÒåƒòÓy¿]U|N$“³çèÊÝUh¥©™QÅ÷ž&(åƒÖÝ‘h¸—Ÿžu¡Èè4*ld;«pž˜Œ+Tå»ûéƒ;ÎŽ¦óu% å-¬´� 9úVõÀG3ªKëŠhg¼'•xªÂºì:1äÕö;¿G ãy–ÑÕÎK9§$ˆân §£Ê‘²�r“¹A#”ÒL� A†î–ñ¡¬#œ=¢B|>0] ŒÓôÙ£m¹;ÿÊ=`ÛZ-6\ú4Ö×ÁŽ´8̱’¥üµyh16Š“ÍøRê(,õG[ꡤKŸâÎüÝ’µxês" � ¶‚­ØY}û�Ãg‰;ð³ò®,�Ÿý=¸éf$nQJ…ÕΗà¾å^Œ»Ì¡ÿý�¦²ÚïÁÜ[Š³Â£Å쯉°|Ëþl?\L^No>܆!>©ðg$Á ù{pfl([dLf™mëÄ »ê@ÏHšûÔ÷C¯}Ú|¢+²‹ôd¬ný³“Lo^ƒ8ùE\Vy—ZŽŸÂâŬöœÁZµçœÇò×èÜ…:p´§ìK!µ¾:×á,f¸I�’ûðü©‡{Å E;�ñ¢ÔB˜£Ðnªò`S¼ƒjŽ…«Sõpw£;&;ŒáøŠ= Ü/€ÞìþW£Nw÷I‹õ¦*‘…Þî*óOÇE#ÎdIÝP¾�¯…I—¥¸)³ž·0„ª@ ˆ?ë�½Àߺ•ƒñÃNR“Ãé'äjœª-9úgºo�ß´äñö&)^#Ã-ؽ¼œƒÆôÄ®ÁX±±<û¬ÄÕ…)0¨ÿ~\)—/þ^¡Å>·R ³‡·ú¨BÇ–0° QÃúc ýÿ¬Tú*ÓÁÍAO/–þ¶Þ­:d‰ËTþ‘3ïNѧ‹=#ðîÍË‚YCVœ’eËÌ,ñþÚ^fÒAV¹Æ»¯Å]Uµ°òä06V÷ŸŠ. ßíqiòR6^;…g¿i»öýàFŒæ9ˆcšúòÉIY|rÖlÈy¡‹%¥q‹ý9ø·¾†B^¦à(îÅÛ½ùÞ¸ð6½A¬Íï‰z#pɹ¿0øY;-Kk�…‹ù÷àsÔÔ§—�äO ùˆ�¯„ð±ÊÓ´z—2ÛY÷æH£ƒœøf×n]žGdh€y= Ø”$ÚNß`Ce�‚f@ZpTn&›Î8èÙ|%ñÂëã‚Äo  «LŸÂ%S¿AÃ…Gà¿k0N:|´¿ GÙÎl:¼Â »�Ð^ý„¸½*®û6Éáe6ÿƒ†°­ñ`—» «ª‡ oŸ$€…†&„Zôä3^ŸÁÌ,³ulx~žo¹¯Iêõr4§y#�,¾ÌÖ».WÏËr=¤±þÓøï¢.þõUÀOÛ™oõ…©Å‘öc Õ¾Öæ‘¶Ÿ äýRðW)-õ?Ò͉îT=j#vE'ñ©30ìâ-°]`ƒ’œU¼Ñ/ ].ôáÓbÑËpî4Æ÷e]Ñzn?žõÿ÷Î2-X·¥ƶìc÷Ri^xyŒL fgJD�"KòÛéD_Agú.åw ý¡�÷z¸2¬[å—£iÞ !¢k�¤ÕM�'4oæDõôˬfI¶®üúQ"§oìËÛlBpµáWxÜr§´‘ôþ÷’ÒWupê€/Ø-dªFÐù�5Ƚ±­-þŒþB“'�£Ð#3ØÝÑW ×™ £{\…Žã§(íý:N­šƒóµâ„3sqÓíCÐvS»¦µ€bÕgjë‰Éé=íþ}ýç‚v®?ÁQ&¿DÕQŦË1f[3Ô9äœwrü £ Ömp"1“«fjâÞ%é�½îüÿnO2¯¡ñc«!á´6mI[ËKÿ¾€æGíð!¯’ún_�Ñ£DÜ�?YX YLÇÒ¶cza9vŽ»*.ïf˜'f=¸ÍRŽO fƒù¯ %-–ú®¥€5l³½û†ÿÇ–cûñã,S�›»³:ÿJ½ÄìW)8·G’sv3³Jü—ü«òÖÓDN»fB†kÏsç/[Lõz£1¹ßÚØaˆâ GÜf¹fÔîÇ‹¯ÃáÈ—Õ0¿æ<û`6*øs:[àñÚV!bv%?*5â­Æ×øn±#¨oÞOGÛàðùñüÌ7œšFÒ>ó`|¿²öqp‡ÊŸïèàže4{¾ßW ‚[žïÄsïCØRÿçè% �Ÿ+gi¯b랺¹Õ?4Kqþµý”<•[{ý’µÚÒóM« xJEd]Â�ÃçÒÀÌXÞ)¯“o%> q |¢»Ö Rðd�ÿ² ü§ÈºË³ñî#wôI|O¿¤… ¿À*•ë´¢%¾išàSÙïTЖÃmÑ›±Bö6Í7±­ž=ôDõ “üSî8V8],‡½ä—Áý9Š¢Ý^ º)¯›®Â³¬=<äðŒ_·ŠLŸÁèŸ+¹ãȈ9¹·mÜ‹²goJ3ªGÉÔ€ê­tAݾ�×ß;À{­cµp\ÓôƒR‡_&‹’VR3ŸÉמÆÌŠ èÌŠ„¡w-ñEs ß.rO¶I0ì•/§>-eì~@âöÞ¤íÒ;œMñ©áAø/| mªÚÌ‹2�ÁyõˆóŒÁ{±‰x¾Z›œ¯ð'1ƒbóík³©ê� K�ÏÕv²¸3`ÿ~uü†®æÊÚá¼óS+m(ƒ q¢…Ü(Ø?uî?y‚fž-??£švõÝ’Y·f@¸Û>Ü0yÞÉ�•¯Ðkíhþ(ÓHµ—RXBzÔWú½2Ä®st¸½›1zt®âÁ‰^ºç*™„ÔP^úT�5‡[W’œ¦ç¤îÃOýøÛÐ0ù~–S�I±•û¸ßÇk;Ï@ÿ—‰\ûÓ܉θ'r7_ÙVíXrIz8Ìöy†çNŒ§Ÿò81¯˜U�w³µ·œu0e£{‰Uò{zKœß�¥mIæâ‰�´ëì{P,YÁåˆÒŒ`îyÞU+MO�‡rR³,øw™j #qј×ôÚo ŒRÏ)ªƒ8ü? θêÌòzÊäêfÄÁ³{pîÎ ˜Úò.Xß'„ ÞMÐõ]5i¨ØðÛQ‡ÉfÌað� ý®›‚µû#±LZKx~ÓwÊã®"GŒ9�ôt5Åi7ã¨_½D„ÊðߏT2aSœÜ^j�Žâÿq,¼5ç¬/|*{ÕÄë§qY~Þþb‚êŸ5Q.Å€5ö¦’’‘' M‘ä”Þƒ•ã—¡¤wOæŽ[•CÎ|�ï³÷~‚úÍ÷¯DŒ™MÇ«„˜»¡h,o‹»þ"p†hLç Â6Ûd‚RêshXt£Ðþâ7ì 9ƒÍ?7’å­§T¦¦�1»>��ÊL6Ò*ÞÜ:€sÎÿ åžr«íqZ¿”Ǽ0EÓ˜ö;¦†çd{²ß¾€iÃ1ëù"*KÜϱó0iamo肺Á—1%ž9xâ@6ÓJ¦O³“¡ùq$�+½IkgmÄ)Òãq”ª¤ºfƒ)7\ïÁ/__\�O‚£ é¦5/ú¾/8ßãû�©¤–Ü‹w¶GPWJ_t”Õe;ó1üCú¶ ¿"šoÕGã�åw„‰>wèah²è£Û�OåÂ-¿ßt3Ѻrº{A™÷N´KÓ@!Ô(¬2íÙÙï Orµ§ú».èé0Ô¯¬žóG‡¯wóÅÖaøÈ-WÌ3½Y­UßHó­Í¨‡• }ÞÓ]×H¾\ãÁVgW/¿�a ñpg¯2®ȇ¬Žp¾ö+™æ¬žÂi 沌Y;a¶:F%.†E–ø¦rï4¶`™Ë1°°Ç ¶ú} ŒÌ#�¦3x­·=&›x‰Î–²<Òc»Ö_†b»¨n{´›zâŽAèý³?Ïà�Žwê‹Óa”y´0£N£æW¼[nâµûï rmȪ­ˆW��!Õ*Z]:§-î÷ZЧw)¨®! .RùÐK�©žBcoÔÂŒÜþ,ësì&>Dy¡�Jƒúò�K¸n°…ËË`ÙŒí¼vƒ‡v8�ò°þƒÚIV°Æz%›ëÍÂë¶;铯õj‡9ŠÐôñ(7ìîΗˆ�wnKöýgÁ¶n¹sh>'Í>Mî{”yÓ5žãølûxÒ£�øîûEáÙÆ…Üõa� ~g"îQÞ„qø¡�#R8*�ų½j �½ã­qüù†­¼‡úÖñàóÇ’ª(â£õ~’†¨X\µ:”KV‹åv1(�2¢ÜÒ X+›çöÛ€¥Žê8yo³¸îZ4øùœ¥Ð}óaX|#õù…¦�Zp˛͉;:np‡¢,TéÞ—!Ëiź&Ê‹mèæ£½»òݬÜã7yàø-ûÁÄu&wŒ*ÀÉU²Øæi!ê8Nàp•Zº“_"8ŸµÀ£Úcàè~¨êö�¹N l°¨ tŒÀàæô¿FÛ\îðw]K.°ðÆ}&›1¯æ"+gѬ WÙ"Ç4z ÂÙñm„ZìKe�¹ý¹ü©1jšp…¤Þ5÷jK€û†Ðº ‚–ÀðTsÔ|J2Fh˜šzHŒpî¿ÞèÏT¨ü‹¦~y€‹dêñŒ·ñ½†SŒLØqV8^ê®õîâ˜[ð&OéÏ;nî ¼SÒ|]jZ†Ñø¹+pÃ<Ž EøðßgÈ05…T…NæßÀ\qOµºM“N‹'e$T|e&œy€ßî¹ãô`;Ð=nAž^1¨¹{§dŽù^ÉÚøì¹;­¦`ü­%0ãråR]µtPÍüG†-¬SãsàÈnïÙ(<ÅâÙÏ$Šñc9ÐD‹~ÉÆ±Á•Béà“4¿Ü„ãÜ>�|Á)0ßXHŸUã¡*5w¹}ô3k¸Ob-æüÔDÏ©¸DѳŸkò«s¾¤H¥hó"G†¡õÉ%œ�RÏß¾æ?ÁÚ¨zc8ßç=‰Ôî@Ñ1#»Ñ‡˜T€ìó°\Š;òMðܽ¼ÿ|†ÖŸ ;ãKa\÷mL¹}BHa„‡¦–Sàè5<ÍÍ�]?ЫÕᢰTŠ�Wˆµ 3 õ< ñ Ðí¦¨ð ypS±Pñ‘¦½kÇιèð96ùú–²3£ÅI2}¨ëà&îc¦� §ÀÊãuW ØóÓJäéGqÌLmtÙ�·²Éª}fý©¡Ÿý7ó̽yغ$ÉÄ¿÷DÞé¢Q,®JÜT½½È�mU�Âòa}Yˆ�Z§\PÞ(íœNÔaÅ1IÝÜ<¾�Û7t{F þþtéí_]ýäÔ·jŒ€â‘& µ³ç[{%ä ãÍ'ïϲªÎ8nºóæ^~E²ÞA8pÂ2þñ¨YĤvˆž;îÖ×@LŠý|Ë t‚ñðà)<ªŒ=[‡Aíæ›P¼áˆ pm½°@Ñœ›¥êxÚ­1¤¥bÂå_Eö¶OÍ�‡âdáÄûþœuVó -Ò¬.#-Ú¿òz?2áÞŽ†ø|µ;^ý]l]w„MõÕùBq¹0]z"oÛ1ˆû…”¡’½ >û醃;âp_Ä^eã ópÅ«•“HaÛñÅøå\h°ÿ¸kógã×ðva8Kßß�Žc•!ø÷~¡Œýß�……gˆ‡�íÏš±ËYMþ%͹s\T&ó‚´�¸cÊ;1ûêü[s fÀe¿ü°"}?VÅ´qJ?�Åé›Nƒë®Nêã4ŒÔåk~]9Ä«÷€…Ö)tLr‘hÜûNë›ó~ª¦„UÈäüp<«(�cnŽâ”ãb`WÙYFPq¾1_ƳF1áY©.N~Ú›_¥«Ñ"•_’�¼t<%šóŲ̀Ö�¬¤‰µƒ«Ü·ØðïÇêåÛæ ¿Ú6Ê F-×îQ<»[ÄRjãQÊŸs§vßÎþº†t¹Ú˜_5çóéóÐñþlæ¾êðööN(Z1‘kÇ‚]�éP³P‰ n¡ M´XÛHMn3P?ÒŸ&ØHƒ*þÙ}ULŽH.uöKµfku�»ú�45õí÷Ž”½!—†XY#�6º²v2»rñèò�XýÓ‘¦‡z°îà ÜV¿ˆe Eq—¾!?g‰rA›ñ¸êitÛ‚?õµqÈøîQñ—&z% Ñcžó~2§”/äѬ¨Ÿ!~}ÏEÚÒØÃ=Þ]�î #Ї v{eJ µ{å}�5#²„/ƒ8ÛK•‡$ÓÞ˧cà—Öb´ø«Šùá|äl8¥ÌJçsúCñóÂÜç�)…Äæ±IÏ 4Ù5Œþi{ ýØA·J ®ö¿ÙJkewsc¯ytjq ÙÃMî,Á�*·Xî ³¤Yªi–V¹à²¡½ìB Ñûƒ• ·ß^E-Za¬S -0Äk3oñ¼`î?6F@ñ¨rüª¢ƒö ;ñÙ©rr½ùDÔªü*ö4Û/x®LÄÙ�ƒxìÛS8)}®¾3j-iYb PE¼xÅŒÒÿÊâ÷™I´¥ÞŽgm˜žrC8+÷8‡~Šëô!Ó}Gá�²¡°.p+üŒñ«§»°.¢7¸Â¯¥ã˜{�šyNèqî8—?Ƈ•Óy÷Õ“°Tß_8�# {´*¹ÊƒÜàµo¡üËm%~铯[ÜBu™ ÆÖÖЕŸimÝÁ©½ Ià¡é Xtô÷·ðŒ+Ÿ0<*“íÍ&-ßuÔ¡ÅúàÇþ*˜{ŽÎŸ\ι~Mâµút¼{:€Ô¶¯D­â4ØšT%Ææ–Q’ëUr\ºÈC9HÎ~�ÆõŸí ç˜+à©°ŸW}®ÇÆ©«ÐÀê »¸õ¤®„�°jFÏ«”xl”oeá¦Oõuw м·�îî …Œê‰4sѱcŒ¼Ý”Gű‘¬·Ùœ‡ô_ÀÎí³Ñ¬Ì ,Ú& yùsyf_ Þü®˜¯ý»wïÀ‡V×iÔ×BjÒ»†ö[U >ޱµý>\<+hØ £Fö]<•ÇðûDaI°1îq ¦*çÁÖ _<�õ…VXp§lŽ$�êM>µD¿^ÈË<ø€r{u•‰ ÄwÂWò¶Z_ýlï.²‘µsòžÊ7ÞDP=ÂÔï‰hº%k;«OGá̉Çi¾z$7Í‹‡çaè`€:j&n�HƒŽŠ8øLJDlö†çZIL»l±ô¹yMA�% õ.€æ©à[Q ,­9ê¿$?Î/-”¬Û'âøÅ–è3e7'wî¥È¹ÛØÞ3©ÜX@RŸø’Ušßtc<^uvëÑjO1ôÑRàë{Oò¡Õ¶¸D) •Æ7]z(‰A…í �¬ü’KFâÆžÁlqÊ×i¢uÃ"•w<Š› £îª0Ì}('TIaæçMèX¿Ï­ØV�Tõp §œê‹=ä¾@sfÚ­…ϴΣîð¡ô§"‡í¬r0Úý…èÙéʶ§ÀØ�èOÍ%~³·˜œº4PÝÝ 'Ù•ÓäuûpÛÈ�øÞbø,§ Á|U£0Ð{ˆè伈Uôa{Ù¶œ£æ=;hPó>ž&`ë"uè_òŸðëŽ5l¼|‡Î¯¾É—Î�Ã5Žêlý¦]u£ŒVê‡Ó;U5Ô»¢ •ôšRS²)Á2cêïBÛ©eXéNb¢+Ôý ä׃¸¼¥œ3†¹±[‘¥ðàÒ~: Ó ƒ*µpÞÀNª¾³'f1Å-ðç‡ 3±(¾›ƒ #h�c´ �Rn.yh?½Ü7@v¶kÆmѱÜVäË2›6r¾Ix|‹ïº|6’ÿž^œïû‘l&ARÙh4ÿ»šM? á©ß}°nò2ìw“ùú±˜ô­X¬œ¹ »Z³k£.úÿÁrñZ²R/v\—h¬�'˵gIÚÞ•7&©ñûóKyçò Ñô|6G_q¥fæ¡�þ<ïy 6ÌrÇÚîÝ�4;Ì+^”ð¹‡nøc N4x@%¾‡¨ß‹j›Øƒ�‡,¡gjí<ب„N³ÆÛ”#¶t±Š.¹bxǾ£ª\óbƒ �׋‡ ŸÇCkÆœuàaõÀûûö7H¥ÜÁmüq°ˆ¿ìæã¾{°ô~.vLýFöyëñq_ñ¾éXÜãŸÍï,PçÞcêÆÓ4ðè›q—±tÍ“/èÐ�Õ|`A‚mòT;öÞÒm|üxJ±ØÔrƽ�Âñ�pòfvn�Ì/M ëd/Áµ¼‰â|TøܧÝu°ëz!û­ŒCÏ”i�Sµ“Æ�Vçð� 9¥ù� ¼+š!PƒJõ@åÕsðx’JJß-QÙÆ€�Ö\„þ>›y^r§¥éâ€óÅâb�ºÝwA=O�ž¢ÂæwÜxƒ£"ZÉÌåú3ÙymwÉEãÃpãÑšUÂgú\„ùÑŒ}’R©yáœâÍGô­8ë×-XÚç2.ws�·9X•—ÐÅ—phÍm{Ï(‹¶“Êá«KfõòCaQ,W ¢O2Y¸æÌ=H92ˆgÜÐÁA…6l¢Ù/⸤(‘s†·‰™ |6é%ݼtKWÚ w*7 ¤s1ÿ­Šƒ &ÕzMüüÆ�óbª[¾¯ÆØågxŠËy02š #{ã“É~y<æÜÉË\×c›õPnêÊF«Z`*lc�¥Cñ“V¤³ø…¾²á\ß8t-‰¥{Ç’Pbd‚Aê Ô8Þ„#Û@ä4î’ÝÁcÕN¸�^ÚØÓD‚ÖÀ´s^¾�›Ûä°Íe _ª=M’œp”)ƒµ¥Kñ˜×Œz²�'Ïâ¹ëB ï©L!Øõø-Ü6î?Òõ��9O��a!÷O†cï>…™ómpÖï­,íÛ—�€s¡«ý;Ìb(¯•‰c75@ïQ“°,þ6÷¿o…ª='±ÑÈ8ž$Éç„\s\>`-/ Ë õørÜpÞ™,‹>5nBA”%�9œ©F-°ê°+�;¬Ã¿u-E‹FU»ŸƒIWZ"&ßUâ�îÌ»VÇk6 Ö¤6AiÈiJIÈǤ'dã·J~gйÏð0Xvɦœñá¼ý„ØÞƒy´óþtTH‰œÀÁÿ•G9D†GùÖ|wL]VËuŸ û”&Qaö±köX÷^�§xÊs.APÌC´I¼ ›ƒöÀ·Å/àWÓØtõV{'ÂdŸta¤Ëd¶ÕȃYâUX•ŸHGn†ùÉ“‹Äg`a|߯ø'ú(Þ à„¡Ø%aZiûAtŽ.ãšØu\’Ò,‰u;Â~ÂQ²Ȥ`£õdUnÅËFÊÓÉŒPx¼ Çz�uGpüó îÝOQ°Ê,Gˆ*»ž€TA„Ç‹l:n#t•µ‘ÉiOʰ‰ãKA' m�4†�Pã8‡»Þ…ù~ ž¯¦ý±=éx„—ðç|(Ýší»ÖÂãsGY¥ÐŸ�­z³¹Q0}/úùèÚ©L Æ-ö+Ð!b#.ØF©ÿÂÌ¢épWæm}|^ÍbÍ(Ej˜Gý6ü¤Ë3ֳ̰<––Ô#/Ùòn/®ð­�KWì½Ð y=§QmÂã^µôw–>¼éç$¡Ñ•2Æ×�ê²à˜‹s­ÝðÊWV¹çÃK†ìݯ vŠ|aˆߴ]3Kl|ü›"c¡‘òdŽ¥ÐÄû%»À˜))tëèA¶Ý!#ÜkîEËÛÇñðµ†üï¹V+¡=É£³«Þ*ê�Æþ¬ökR°û1: Ö¸‚©}oT²â¶�îYX‘Ä iÙüÐp;?½ã£†V¾Y¹ן­†+¥ìòÝfC~ôaP÷þI£“]+}ºIÏW¥ð+cúì³›ïF›aÀ[ØîÄ0ó1ÆŸß ÝõÈåæ¼Ü~‰â‹Ë¸L¦ /핵[ùx˜áGÑÌv† #Ê9RýXßsö3•c-ãŸäat”úo2àdû�Ýõœ'Mr*l8ë¸6Oû!SãWÒ[¥e0¶Ã„§ä½nMfû!{hÞkѧ>šjf%¢öˆ1<÷KÙ¶�cò øÔ¯·¢ÿèKR« )é¤1�€þ5sA 6@�»7ñ²l¯5ÞÇDã¿èÃì[uœî ëðŠÃeXéö°ý•˜€ïT½°qðXŒ?ö„ÈG¢ö­™œ®ÙBJ2•¼8*Œ,†¸ÝetqË6|¢ÿÚñ‚öá¬:ÁÔîDPšm8 ‘šÆ`:CßàÀHY» Š›éqÕ9Î[t‘§•5S¸Ót2«�ÏRu|íHuØ_dqE‹¤«|Šo{ò”ÁßñâÚ “×ý]ë@v¥qTh$aÃ䇔ê}—2Ž¥zŸg ž_¨ñ¸¬]¼W Ívív“>â°Ý=ðWÄ >t¶þ¨V¢¯éWtû9ŠÏŸ�ßõÈH–töß ­ûËùЮ“´Å¡Pn�ÇqÑ›ÀËØµò(zn9Gs쇓OVìºAý#3Yý³-ì,NàóWp�í8tûä {MÂC_×à[ׯ´ëä¼:¿ &�þ@/’Šxœ³JÝi1Âý)7”àÁÝVÜKn’¸Î$'Þ»âPB“ÒxÿIo Çï{ôxgô{ò‚vúà· =�r[ÐbŒµÔƒ�™Kqâgººä8�¾7�—»xÑϳSÉaÎ!N-,àWó9ÿéeHlOÅO±Æ¸Ó2ˆCΉ”1óÞz•BŸSÎéX0©Ü�W/GÂÂÈ™¸¸Æ[R¿­�Œ•|ÐÏD·¦øÐ6jœÐŽR‚}¥šJ(¯Ð<ƒ9Ù›¸rë3ak~9lJQÃÃáAµÅx°l›Å¶ÑèýS±ùÏüëàÎЖ£àHl.œQ3a剾�‰yÑeõm©ÆX™G]‰vÛ`r¥6n‘¬—mJ\xm/¸¯þ¨âËî%¿èä"ÙšúÀòï(µ×\äÙƒ{& ^5a ë<|ohÆï±¬�Ÿdk‡)_�OA}©"²Ÿrþ:'àæ-4ÊN÷Vò4—=¸ÏºIèŸ�ØðŸ­ql†i�3° ‡ 9+—nÂ^3s9C¯V¨ôäá�1˜YÂ7��°^„¼à»5i�tÍÀ…1xþå?è·$·3C]OÓåÝ¡¸}}2_¾ñ3ôË…C;> ¾`€©óÔÐ.¤�búaÚéJÌ~ÒÄK%¾8mÜKö["‡GgmÖÌ F6? ŽùkØ'*vúž'ˆr5�ÎkIªåÆ*yHläGPûlAN)*,¼ØËû!õ~;÷�P o×áœÓÓ ¦ç ªê—È ¿û Ò´ï$Û”kÞærÓí'B°SÆ|o…ô? d,&qãâdÜ�ËÂC1Q}"·¯É$7åJú]¡Àz¯Õ pÞWAkO:øCx9s< º�† š¬Dx,Ë6ëáVÿ$Ô•9žd8ttX8O�¹AâùîÜÙC™gO¦ºÀWÿ;&†ŽÈüÿÛá8ëÊ$Ö—ÝG›/€uÅsT;Ô¾·ŽF…| NY‡‡¤kbUKph°fMáÔ£R‘õ¸¹i°Ýß«yx XµFxs¯i:qów4ײã�§t©-…ʾ 25]B…þR‚®QäØÜovÌm^›Ú=‘•£¯Vð€FŽÊÓgu>ï«FáPé8ö–t–R‘¿&«fHÀ;m/$k¼âÖ�{E-µœB½ì ·úö\�bÅ%áÆýú\b€jdí†)­äý'磉eˆ ïÚŸ/]̃05½šá=êhɉ*Ø{?–õë‰çŸûCüÉÝ|4'6°v}í óá´ò ±±a$N�ZÓ?ë’/)󸱱¸ÓÝÞŽæ}¾Ïù`‰1SŒÂ “áèHyL°WfQùyYˆóœ¤ðñƒ¬´!¾�¢fpÚÆD\äu†:ö¿Ä/EÎàv$„¿ÎÙŽ©�¦ýîK��ÎKˆ6º.Üøã˜¯\ˆO~@Ë•îI¶¹q±ôéåFÀ‘H{]1ˆ÷µ„EþîX9ûº;—‡ü º×7Vè+„š‡ó�5‰7Õ³ÚˆQZ^0b]O\îqš,�ØsšZMÚŠj~42œÜ׌eÅG¿„'ú^h·c8Nx³þ½ C¯Qµh%»‘}?× ÛwD¢†›-¬¬ŒÃ E¯ñ�âJž=%‹’û«sZW hÎîþ¯Ø;Î�3ŸÁðkNܸÁÃú}ä̪(î)Ëqó%(o‡³ ìøÔ“LrœJÖD⣑¹¨XUQhõµ¬=GÃÂGvT$SÌ¯é §…th¹'O1àWxèÊ Î/ štð¡Øá_ŧÓWrÉCsžã},“nöçcPÇö+)÷e븞8K|A>¦$½o(«,?Lª½Ã1!p*Ôüä–o—Äm³Â°ÏæR8Ü%‹?%a8b¶¦]€�RÍ�Ä4^2IB³æ�åË�v&õÆ|vå#Ûš"Y®Ü¨ÀOaʵšzßU¸6Ń ïŽD‡h“R�Æ–;„´:ü}ј©5ÿ¦J6jØqa†4÷j&ÏϦÂˉ_H?#„òd›Xo“#ç‡ÒwÝë)¤ÐzÏH²û—ÊyÚSñeóK!%y*oÍËãôë¹<Ãu2:üÉ�„‡ýƽ†qØìÎñÍæ¥(é,áéKxöWHyxÓÐX�Û䂊ó–ò˜::cù ÂRŒÔ=\´ü?PÞZŽ=<~Õ£{&u+ÈõŽkϽÃËÏÂ`5±Û‰ŸÁ{% –êí�ÚÓŽÀ̉±,hÝ —ŠgaéD;â?«Fîµ))ºFû="È@o&¯=ØF—˜ðÖóÉÆDb×YUL-NÑœÔ{6|=„[6%Ó6ç`ízއ®ªf‡×~|>xXÌŒÃß—÷aÄT)z‘:÷¬xJ¹ß�çv=v“¿+DˆëÁæµ#��ÝïòôоbG÷—³û/ÿeœ%M§"zW¥Ëþ7§ò"ûyb†VÞ^]"¾©ËëfÃÎmyAWf°ô‹‘øûÆCš+µ‘þDÛc¤ûa¼ÐnT“}»•Ì¥ûÂþ‰£øÂÝœêÉ¾Õ ;#QnÚ]ÜÛ|—ŒòâESVú¦Ä2)ÑhîeÇaêƒ`uæi,)ÃXÙxnøRvx‚Ý¥c/Á’ÍÇ lÜoÞ°ø7ýVùOPwTã ŽDuGe>7D{–ŒËšëBEOåìöñúñ¤gÅü@#]WÔx®P»f3ç\��¯2.‚ç\wôkí¤u‰Õ¨U­P3Hy;õJfõUCñ€ãW0Ú� âçq–Qõ±=Ã&_Û„Kg#aõÖ703t;n‹äÇOƒrçb¾w¬ r¢+9b² V»,çë¿ÒÂïZØWªÛKÞ>„®qú¬óæ¬à˜aîA-Ôñl ¿ñZsój-�ìç*¯~Tèà×E7ž™q¡¿ — k®~qe(5> ඪ8ðù9$ôI£,Qè³½ßÕÑC#`»Ý‹pÁwFëS@šË½û±^¦V ÷€ïF¥@Ž�PmÞ‡å•vàž÷=økÀ:|çºJ¿ïñ¯mg¹I1ìµg°âË•ÜåØSx26›“ S6òÞE=@ö•<ÏÓ¬ý^X>Ëäm÷¾iáÏÈfz:9™Tz4´Öœ÷ º`¿}¦�G¦ ýð¬éZ�už3áùâoÖ{ȧz+tyAcV�ÁgK´ð_¿°=bë¼h¡öb’�*�ñÉb퇙‚æZÞŸéLî_÷�ê……BCR6jüœÄÿ¾·�ã¯:É‘)~ðýªî ‹GM–Ø–9¨ð{ØàÁ!6pùFj+ßÐü0O(¸È8oÊ!!#DqE6Ω•B½e7…ÚŠ÷âëXŠVZÊ«}§q»ãu¼1º¨ºé 7ü nâÈGýùõìÒOâžà�ð}Û[z[ñ†N*½r÷¥íºàßœÑ8µ`±hãj…çÚÿ<èÇK”táU�1hzúÙ…,f“Þ—("¥ŸÈÂHçy+9‚«ž’áÅjpÑSáÌÄá^›Áre\ykÚ%ä&3®™Kã •Wd¶¬/ï{ÎÓÎÀγ&ÂÀ×-Â�¥+`±ÆYº~Ï�uá7õIx'³ÏR/~Á|üqëÌ%L/ØtP2d”ÅV}��Š ñIq<¹hoç­UÃÐ_/Ú:±�õ 5€å±k(ûÓ ªQ}æp{mÝ8Œ£ÝZI2YŹÛ'�î£�Ö\úú¤�.Å|ó±ÎV㎸á�g³±ôÍZ¼î0˜GªöÁM±L›ÿÇp™ÆcÙ„Q%Ke­èµEŠP‘ž{.-""¥H¤”ŠÊ…ÊNö�DD"ûZâžë!‘”¢}!…QJR¡z}šóa~3s�sþG]ŸûC•<‹á­Ô%f–ÁQ|˜®�¿æ¡Ñ9tOÞ~üùަÞY�M3aïÅX*o+!BÊ�Üâ„ ói†àÝ?v‡ œ!†Ö·�“¿ ØëFC})PêmA—CÑ4genþj…—fœ`m­^þ³ê _[E£ì4TÅa›‘0÷x�/d›êCsu;½WÛNNÙÆÐ®Åáôü²Çd,â&9ô‚„Ù–îçÇÞü:åcé)ãŠã’þ›Ð-R™¸j^†O¥ÓQãÍ­úÍü/q°~”F ݦ•‘Ð$(‚~•L ËÛè¾iº˜|SæĨñ†BÖ¶ñ)9ÿ ­m—WÿÑ·¾4ã¨q_ 0s­8©–Z€róžSãÔlüÙ·È—¡Fny×áŽÔ*ZÍ9„þ²è•g¡Lñ¥AΠG‰”üHÔ¡¼¿VŸWƒÚ Ëà|­p*ÌÉ£,òþt8iÙ‹-gÒßúéèÛrâ+{Içܺ/ï.[Zøš|)Ž&·£ÃÀ‹ç.™B.œõv½6¸�Sòé4}­ëDj•öR“2%º¿öÜÖ¾àE0¾î ö, ¥K>ÇÀ¼¯j˜#…-…ø_Ð2üÏm6Dp~2¢AÚÌsëR’0߉<™ö�žO@~£.ZÖO‚|±³ú:½–ËìõtÅü›4}Káû—Jg„ÐìrJÝ‚¼cëèš™í¤»% ×´ˆ³‰Ç húwS”Œú„‹ˆÉÂoìºÑp³°ÍV¼Ý›¢ÀˆªQîöj«ã‡wœ Jëá6ÿ|vDœüZr„ι~�¸*z¬ÄÅ�鸼$IZ¿Ž´ÕTÐG`B1–žûÀvÖç¡isðæµcpßóYj2H„Ç��¬ ´Š]¥:{’ãIŠÖ áÂ4Ö–»{¿Ý†�ñýÐ*µ€üª¥¿jT©uP¹êÁ){aë£su)çáZk?i¾^/–à¡©¾ð¾h6ò›­eÃ}§Óû±]LÌÐb¾œ~™&Ÿ¶u1+UÂhü�õ®oB“Á­èþ9�5k±åèãžeLdT1¡Ú°ô‡ãª|”ƒo“êÙмDe9ÝdãˆÂÌ7„±Œ£ÅǦúj÷ETpe#gÍ…Ä 9xo]€¢ÒëWšéý÷âøtú]¢ì¯Ëî#Óۧ:$YbsÍuª%Z �zyÀJ6fûÞáÌ›_BnJ°?³Za¢×›^0<Ÿ[u W6�ÖÕèÂÅ›×!î¥8î2+†ÍWìÙÃ&¶xcÁÉz>½b:]µˆ$»YAÓŸdåaý)+Œo]v¡7ÃÐEƒ‚TÈE ^‡ç2w§C÷¦ù÷'œÓ“У64 ›”ÜÓ6òÿ*ÇÉ©p4.M7M`Œ9zÑ × É®Æú—6УY±P‡,YÿoYša [×›à¼�$7µ—�.žWÿDºÂíð…Ö}’|û1ÑVi#ʾ’£þÄÊ3f ܧߤØc5‡pû /6ÿJsõk8ym-F¼§™7"¦8 ‘Ÿ— ÿ ÄÐÄo1ún_AŠjCẔÄÇ3�åXDb!*^nD‹Þ>zrn8±ºÿ±þì!Eê§{h ¤�„–%ÉüÕ7Ê¢¥ªú8¹w&hÛœÁ[wÚù\æÈãÇWŠ,O—x>ÃÖ¬YðBÔŸœè04.e¾=ä…¥ÆöXÇ Æ&,Ž|xU…–ÛEàïÊtÖú,°Êéæ–äñK#RÑÝÕ‡ÐüÏã«_O-½ÍðÊÓå�@=±T¡ŠŽDÓŸÂÕP×á ©›bóLiXüŽyZ4Ÿ‰X±ô,¦»½­1;r!X-+ÇðÁC°«c¼+xÇœìb 6љ䞲Ɨ�'é�™{!zÁ«äë†J–»V ýEfsÙ�üh¾k½;fŠå:m4m¯?c]ù�ý]y‘™N»éÓ?*Pê? lÈÃcé rí‚)°ÿ"êU·L0‘ ‹)«>N‹×_Áov·Io[*{ìt-ÝÙM|•o³¤bz5öQ=¹žYjµ–>¼v– ØáßÔÓØxß m®C ÿ( ’¥«{¶{#“Iû¡å¡uXYÊÏj™x‘ �Î(iØ„ö¿âPÑp;´©/…]ªTù·|ºË,L‡£çÔaƒ¯M÷ ‚þ�aäÒ”'©?çJ°LF‡.\¾ƒ©Ú4JÏøãJwŒ,åWÇC[wB…[ ùÛy“cy 4_ÿ!éùsq¦D�Œ¥uû¯â“ÈV(Êk Ö½˜Nª5�u éô¬¶éÑDS .žn| [:ËÙ°wL*[�N/ÈRÎošë£�'Y´”4�™ù™8¾w€†vÐË.ñdù� �É™œöͬ —Ä.6ÄÏKÔh›‰«çÁäpÝö: TcÓ þ´Ð¶…µŘùÑh^!Il߉ édzÀÓô�ÌýNŽ”§B­¼" p"[‚0 ¨gdÑÈn~,ù$ óæï'ý¢x´Û•-€“{]IØ›P_/©×ÀƒÝj„÷ÖËfS›’HŸ9Zťꟊ�ùÜ_äÄYwà8²?÷/Væ £ßß#p‡IÒƒ8z•ÀÂsDð[œùJê�~fÿðl FÌL(TÒ¥3J³á_çí:=OUZöeÓJ´ã©ñGWª²ä6>¿uŸì¯‚äê<²¡ù$„ ñckOÞ÷-£)Ÿ•p†ÙFÑ¡(˜Þ �.ê(Xt�ºËM²[»‰ßóÃùD ìØKNÿÐ…xåf²ð¥¹¸K•™8áLÈ ¸p¹’Ü9›Gg³[à‚t8ñ=\ƒÚå»@ò”°-lѪ2Ï­”�ø“‚‡"¢ÈÑ% ~®U by|�.+�ö¾A3XŸzs ut?Žïu³E\öj tCVü1b²‡®€�ƒê¡¼"Á‹’Ë[H�c,8°Áìé€y8vS‡Ô7Ââ§É¨]s�äFÇS²x7Èù¦ãꚥ ¸5 •œAѧÎÛâjiXÖà�:JÛpÕŸ"­² ŠžÝE—î¨ÓJn 0¹aЯ¸‰¼°Q…Î>¸T¦ß\eCêMPSÁzªn¯<2Ù¤úis;ÉÉYQ˜ðv’4ˆp¯4Ó¢%—Ⱦñ|ºÿ sÙõ3¤ëÜ۾P! KÿÈbº¾£dužíp'¥.ª¤!¯y£ðòË1¢–I_µfÈÅrjx{׉Äx5²è¿©÷ý~>Ÿ.HQ†;­Á¬uCý›½Øqðz­R¢Û´s!üû%èža—o…�WS9±H†ôüì„{â{ÉÖ�â¸ÿJ(Ü:§ “‰T²Ã<<]É×C×ÉåÓ“ŒfU1á­c@YWõ?ãªt_z\ѽwk¡ÉùE°¬æ9øt~"^²0Û#4âÃ@9Ä™pÎiAÒCÚ¨# <{4qÖ39�6ÿ@Âr2™yko Õ˜9ÜY“G]nNgNôùbãh,NT·ƒô¸ hzâÄñ&êv'_FZÔÛ¥”# ËÑEaK°Ä2ˆœ~�·Êê™çf¢5Ç¢‚º©QÔM€‹é17�ô¯ãP•‹~LI–4S¼¹ žJCY_œý´œdõ¢¼yóT¦ÞÈ.c3ækãí“MdaåGVblnuk§)Ǧ�ûL–ðÎW…è¥æpTcÕ0ØŽ¯OèJÚ¿R�ÞHQD½ëÒÐÍ»&ÍÄiln3�¨ÿFF‚ÐÛ}˜æ äÐ¥¼q¨úÍSŒÄQ¿é%]s1\È2<+—J3–Hпm‡@t¿=VYâ‘ù;AZì2ðew±§þ¥ÁËà`&]ð=5µ§¥ÖN‚Í=ÀsØÞ/K†W¿Ñ[ý28`XBsvpë̪ça œÆ”&“'ü¾Øš7NýUÁ¾zˆù(¦‰Úè$™D>hÔ×h¤­�«AaïSšÝï–¼|\­)n6J³@k<ˆ¾`óÞ$ãæà;d¤!—„]Õ¡TÜŽ©wÍe^^:ßz‚hû. RY_‰¤n6îÖê&#‡cJÙR¼¹í‡óÝž ¥äís ðj-éç÷ÆôZ¬µ+¤CÆtþ¥õS9�êÁ²¤ŠÌã¨÷F@¸°§ÚêÉÞcÓ9 _®â²Ø ÔTo*a{/…�ç²ýÔ*-f]¹|&ð,3Ëø£—m-/ŽšoÄQ÷e±û/ú“¸tæË î9LßÙrØl@�ÛÕ °Í jzP);hǰüɇº<ð¢ó>ù±Uó.ô±!-¿ÉçÄ~òýõ7zr@#]%2 C4K?�Êì˜F¢_á[íCø:ì_8Ο Ì.’®¦-p\«’t‰®ÅД“ôdÿt°J8ÊþØ`JêË"ÈÙù(ù�´W_&N§­ ¾m\Ý7BúCኻ0Î÷ÌÇ�gR‰õè_E#x.Œˆ…¬BûàTM6J~ÓÀ´S•LwÂ&L‰Ë$)^ü T¹’ì¹%M»O¯CÁ‚yS xV¿1x>ŒÊÊ�üJ3}±Áüú‚ìè™`†%P¹b-d ùÂüòòh–/f¯ "j×ú±;c²àñÃU´ô-—bËrSè1¹UD,בœãÓ ;[&Äœ`¼ë ᩨнµØÍ?@³çãÍÅ${^ ÕèZ{?\cG–(Á½'‹Ñ8½4¯ÍÁ¯n0›S�€È½§­=7蛟üÔÊò Ó_J¯®‹€…‰OÈ�»ëéXA µh‡IxéçBêCûÌd¸Z‹Cp­ß¬3œ ±ººè‘ r\_Œ{¯Dy8ñïñ80KTÅ ýNÃf×LœvÇæûì‰…ê´ø»÷-ý¼Ï„;� ª{‰þ=QüWb s"|ÝìV>£ÕÛIúRZgÙ_!§–ØÂ™Æä«ýC¨âµ!»Ï�×û7ÐÝ9f~ŒgÊ`cDØlW„€l>¦Û¨ÜY®L–8ü·¬“‘}XG¼f½çŒ|¦XwZ |N ‘@O‚>;¯ÐúnUTÝWM:nwQ±½xå!‹Ä,áð3ø|Jž¦¡ãã쌃Ÿëo þ¦ÿըџ;s87=x@"z8ú™éc ašg?nÜúá[°¬‡%«F'˜«‘oˆâ©ƒ¸ýk1‘—PÀ\·ò³;•<Ì?Š»›¼¡åÈG˜xöwçí\ØzÝïäÎe-‡f¡kX3}°{’ʹ+žÂâܺÕžì"å #Ì\ó »R Ôg«ÁDÁtöÖ©h(ÈÿJ•ƒm¨BØs%Ú æMÖ›dn‹ï÷¨gÄ=ŒÜ¦zæðÇ$³nm…õ>mLÍB)TmMb:›ÿ`XøCNp‡&»gi•8…··Y`³µ_}ü>èòH‚V£dúcv.|þð�RÆbµ…aÛ~5àËuÁöÀTjùà ‡WKÀ·­3a³±ú©– âTöN»LÚî¿�Î霢Á'´Ÿ/‰äZφÍØ‹•ÇGIo_¯@�ß3¡Gz)ü~z¼·DÐë²?¨NÂJsˆd|d^A’åO–ëœC#n¼¡ïÎ�Оm›ˆžH*Ó¾÷ù�¸_k+>zŸ!/F‰ªû¦bk"æ;„w>ðÈŸB­gç!pḤB|ï‰O‹3ãär‹. €9¯r‰žU‘|Kæ¼Ë¤¢ sÐ57‘”uTC¥–¶¨×’{raÄ+œ¡Ûåܰ@ø>ÖøC J$¡)mŒL‘�é6*ÐS¸›‰ìæ5Xfzà…0®¬øM$¿þÁÌ�-è:iK~¾™2ûäàȱOt‘™Äů#©%Ùph@6gÆ%~¬ð`vóMiÈì.ðŸüÉФ\ΔG¹eŸ¨3 `†l¡N€ƒ¥mdc¯1¾*›Á�.ô®\(¢!›-ëÎŽë“Káýx>«¸nÆ—3×—N_ÐEÖoÆ#Ï2Áà]6ZNÈÃeî5?xÚ7x¢zZîT2¥‹”FiV˜I=} Dú-‰¥ëYÔþB N|B“ù•”sNîͼ4ÅM®Â¸ê),Ùéõïý}Ä�¶DØ�@÷l\® �ºDÉzv&ÔïyN�µ%ƒb¨{ùñNN _2©Ù² ¬MHÎÂßUÔ.«š(;eƒ[ÚŒªCêíOäò×§`˜ÆÃ¬Š×�ñ3I”Gýµ£Ñ÷h•¸?}ÜÌ¡{=cž™?»¿ë‚IZ‰�r „~P þ <£NÜ+©yHŒŸ®Å2‘ð&U²>¹é'ýe™E­]ÙÛ¿—Bݧ°Ù-–Ä�.I¯ÒCÍxUÎÂM¶tï`1{æZ¾�aDö�­Àœ·#ì±u¡(üö ž ÙA tDªÓ“ƒàv‰„•ß!Þª€Íäy&Wû'älû]¶ìº ñqOXþ ÑzŸI|mZ—Ç®yr ïßÞƒnóî�uU8ßOzEýHRA Ƴëè"¶ Ïž-Á k­úÖü&ÔeŽJȈ�Õë¹G×+×ã ‹|2Xãe’T{…<(Ýžãg¶Â½Ã{ðzO?^¼ Œw]ÂãæÂ�pþ ÿ3$q“$Þ°‚¦;¨+ß3¼¡�Ü[(�'}4ÁçÜF¼y'<ÜbàÔü�°Ö ÛŠúèôï`òX ®'ñtèö.¼ü­—ˆÔ©G±Ÿó~ǯ’C¬¾Ù%òÑü-ó—ÀHŠ ŠÓˆžBX±÷5InæC+©ÚœBV8|$y›T¨c_0{ÏÌþk%�EîSç­#Ý×S?UW8n"ۉѯƒôX’ ægž§&áó`“ç ä*’ŸuÈíR<¾—aßñ†Ö¹o©½æ.Ð#ò8æç€kÔËé—(ìz(‹ø Øù:²/BŒ»æy(dõÜ¢‹žž�°Ä+tUÈ5²ð™*w� cS™ ;òNbב(Úf+ —×*äêLúè¶®›³“¯›‹×„TàŠY'=q[.íIB§�È3ç—ä} ÅÄ®T\¾GíÖàÜR!y]œ&ö(žY[A”>Î�Ž’äWàYÜÈñEq ~Э%·àjux‡:áuß&öîØcâqâ3iÊÈ‚æ—!ýëGö‘üXb˜O¶•>åÚö¯Y�/ĸkê,!×½£È×f(•h¡—BbP% –ï Üšm AB°gÖbx÷$öÝDþ˜ŽfR•Æxâ;s .f¦„Aߨ¾º!Ft6ÜdÆ71/n"æÇ–Àê�¥ø\ÔØJ²Íð7ùû»�p Ê©ð¦pôÐ7ÅÉç™Ï«’†‹Pö×eˆÕ‡K@OõXz­·ˆý§Â w.$JÑ­tyÿ6ð;ôŽÎY÷ˆô¾=JÕW `Ü ¼|¤�þò@Õ¾ã4[áìT/Èfú+þP™ÎCÔæä"˜ÜÆ�-Ã<Ü�M±l^ä îO!ÿõz€IÙ0QȰ¹[ü‰ûï±ÏI€áR#|¬t‰Œ5´³Að�èü—«ÅÃÇ@鄬×ÌC‡ÏáTƒùAExr©ßºd÷#ZÑ{”í—Ê%Ož]ÔœC Vɪ®í ¯NqðPBõóÍ Úv»Á.ºœºg=§ol‘λӱóòqzéÙir/;V{Ÿ€e¥^4~èùmÁ̆ôzײ.Ò!Ì\Í'C‘$"ŸÃvîÓÒHTö^�÷¾,c,Ãop.:ÏÂyþrøk’-¼¯‰ž—¨ï±0ts_‡*w.á§Ç£ðî TZ ‚Ó×x°ÿÁv‰–Áò‡ÔÁq')”5Ã_oø¸¡þQö„ ŠnçÃðÉ pÑåE9'w:$¨Šû?n!+ZNÁÐüãè/3›=ò­�ˆTÄ“[Ë嘧‹¸†�ÆcVb¥g!ý›7BôâìñCE4Ÿ wLx v8éâÆ™ÚÔEO¶Ž "d@ j’¬¾»rÌ!Gæ89’Þ£>{u!X\ÞA¥ ÚéÙÂB²ßì!ýíHkÞ?‚îãrøÓ÷;}â%j`Gø@¶ºvÖLƒ›”àýÓ’m„ŒÀú)eœº¬ÚK—(ºÃi&`­ŠìzÇ“ˆ‘«ÁVÑ ‹Æèñ]¡()¶{E% ܆öÒ¥uOéåáW¨`Œ¨óX‰¸ˆCCRNGl²¨óoI»vÜßx¦þ=[^ýŠ3,åñó“+À 0'Û›3¨»¥?f¶¯¦¾éýthÞΠ#¥MIÆxkíl®Äh}¿_¶?Îd4ÄíÉ¢ÐͰBÙŽ3À?á÷Vi:¦k�¥“­øåP"uóLBs­TxÆ{²ëœªæ+@h›®½5L—&Póó™�{³¨¥·åõ°Iާ0àq}¿x:‘J¦Ü/Éħ¾�ùöy~÷™òEû|¦0ì ”HT :·�1Z>Fc/%㩤70™‘@aª3ʶZáí»<з›- äÐÌM“Œ]†bA`E8Q¼j5oÒhÕ¡`º†·•ŽÜ�"…3*‰dß}ì/ê!â]iÃeh,/Œæ…ªxµê0f§UÑÕïþ#ñ—Óavƒêٌ¥ЇŒ{ãwzæŸ>ߌ%DÜErjVê/˜î¥Íw•qÍð'¨3YÎÎ6‘€Ÿ£òôÙ‡Žr‰²0c•–A.Ä,Bß, pŽåÇVY!ØÞØ@¤Ú¢ðxR &lnƒ*—z�Kë¸F+­ˆ�âkšèQÅ9_Ädó`vÆ *^àIe‚Wj‘>÷“¸ÿªô.xC[„S›‡+ñº{^‘€:¸Áª¶1Wªq_ã1XyQø`¹ûc}ç<åÙºO*¾`ÔXÃ.?ñažcðâ{èX�aƒÆE«:Ë ûÐúÖωl<ý‚Ø·’…«Li™~2quŽmNÄÁqp÷¬…±•t~< ’_ ~à Ä|¬Ðá#Ÿ Â8 ƒL?`çÁV!Üp/8Š×QFà,žr°Âó]SÚ>K}V®`z[¿Yw#˜ßz@>�­ÏÉïCÏÂu�ü_%ü¼M=M%~™{0yƒKJqA¹Üq]9_÷à»æÝdÞ¨ ÎLKÁ!PF�Ç|Ž4.J¼FNØ÷Ñ­1é¤Ü&žÏBûèyXçü„Ikû@7½­Ã¨Á*:2w&ž\™K_á›%O}ìcí¦ß!�Í1Äùï4îÚL=”�s¡�£Ó鬎qRÓ|�L(½àôÿ袖³1 FQøùq¾o'Îâ_Yß¹îз”•ùÚz¹×ÁÎmÆÖp!¼Œ |Ç&Ù{�¢é»;FÐ~ÛžLÛ„«›opëÀÄ܇4ùÃJzMÓ 'ÄõPcÎù•C•ÛÓƒS¹ùNJ—drAä’†×äÃqÌ×ÎaS Z ÞH –À2æ5dä�¾�šø‹{ÍwY`ÃÞL9eWÿÒô´út‘9óa¿�Œ­=ÈÚÏ e–G‘>Ô¤~}'á´5Þ™¥�jžÅàr/Œ¨º$à²)õ}�„·g7`”U"¶´±­�Ú….Ûgä’ø]|èaN¿{—¦.�:ª€þٿ蓉Â+gNÈýã0¯�²Ó=-ÁKr’ѵ|Eât^Á«¥"Øök³ANFÉæ–㪚E»öÞ!•ƒsixKéû›Kµd¾Ñˆoå¤8Ü´öŸÅ±±tê쌔6c"œ µ:¿ îI8+,�V[KhJ·<š)ŠËÕ14¦š½è«“ÍäœT Ú?O!+�Àkß+©z€1L³�‡•ãÿѵñÊðýóŒQÝK¥^£Îª#\BKß4pì,óѦÅ(΄•}Œ˜€”-—FNä3‡ïBR0n•Œ.ó‘ßu³ÀÒ6lyKùø2¨_ä ñ´@ðuÆáˆyÿðéî¿O›ö�8·g‰wP¾«?È)jCç�[�^†2ºU“ÇÝ7ž~"Ëvs  e}ÝÄt4yh†Šm2�í8 ‹�’ºÉ,Ìq9[2|0äÊÔª>ŠJ«E˜ “‚˜ÜK>Ø—€SÂßúkê²è8êÂmspÝÆ`†´ Ã?¯)VŸØ ºy+©¯Õ~x¼–ÔZ¢¥ó+öà>M°é§Ú¶môøŒ9䦥Ù1t#ßU€•_a}‘±.ðÛœÀÆåpá5/ä\»HÌÔºÁ¤DÏÊè¡ç¾ÿ`­Ã:øU·d‹hêMgp”ÓEGP°uõQß ·óaCº8¾« ù×ñÊó.º0ù$œ9ÞÀÔLñC`íV4Ê–ãÓOjÄÏ2Ã~Ûà˜FÞ0hçBX¥¼^ÙÅ Z¤rŽ7ìxí+¿7᣻ôÃæ×4*C »W±æòŽÈsø,]œ~Š96+¯÷ �’ºtýŽËyQ{œ7ôg‰­5 ¸®˜HÆ EѺR�¼‰ýŽ#[ç�æÉDªaà'|Ïø°ŒZ>êE¬ÁvÞؼ`6(¹Ø·m‚8EÇG[q`ì:³ÌT BFE±Îý4Q«%×ãÅa¿�6Äðþ¥j¾&Ü(‘ÙD&@‹~Äå¯eÀá®mý£Yîàocn.¤yÈ“% ¸n ±TôÇ5×Àر÷l̦Kx¯ó ¶jj`Íœlôªš‹-Ö]dÈBˆ{ãy*­zo¿ôýƒ´-U^�‡mJåhÛ²woÈšïËAñ{Aƒôz̉HGÝmÎXÔƒœî DݶÓ¯gÒõV©øöé$m¾ã'í ñíi}ºh�Ã÷G‘û6$ ËÈ2é»pYE;ÍX8L¿Ž;Ð×B.8›*aÓö©\]ì’íÔŠüˆyÕàøMs,þ….Qõ¸Æ5:¿Ç÷^EÝÑ$WASç M1ñ&º”çsiØ‹ä8  ±r&ŒX q÷Ó—$ny9ö?JÂöo٠Ƭ�¥Ÿ¬ÀK¼œî½…¿öˆcž³¸§ä½ùæû$U)£®#6­W±ë;nÐ=ñ*OT,I‡Î#ÆQ  >Ìä:¾é#gëhïÌUõ_Eö�ôw�'êSŒ.³u{îb×.É„^±]à¬o…§´ÒÕ3bPC¾�ðÉNi@ð,þð¬%…½kè‡$*Dš±.A°VüY/‚Öºo„k_ŒëæäÓ%rO‰ÏŒ\8’ÌÏuË–�¨íw¨ÑÎ!ŒúáNïF×Å<^ Z*,|6È"_b]ÀVÉ»¾ß'šú[ p5ë§aVrQ⇧?wapákæ‡øMÐw´Bk·ð@ä/�¨žÍý8ÃXf†Eý´p6|fu,"Ç« …Ž@¸ùd;*-®�tÇ00Ë>�—f›/“DcÆtš¬Ó…›~­å.{A3-ñ:†‰'@åþfPïrAŒ× Ï¾ÝÆçÝÀq”‡Ë9vÀ˜˜cùbEî»ò/ÔñöKŒÚò“ÆEd⯨;ìœådíZIîŽ+i¨&k ¯í¥úÑ×PŒyº€¼�ZN{ ï@zô2Ö·ÊþÓå^\m�öul�|(]°…½¯ï’•“_è‚ZcÒ$tŸÆ{³®4DÊù N7$Óm·žÃ뚬D£:Wz< ö×ÃÖg�I܃]§à³ó”fø Шσ T{ÌêKVc¹¤Ø…@˽&qÅBèy< 'Îà¤b5ó÷}3›+EKêb@]Ñçíåp#§Ÿ² è·ï&^*ñô²~)h^‡òL¨]†‚˦C}èjªí£‰_]ðO ¹º:¿°‡P«Þïüµ&Ú“_É��Æ—Ãé.÷Q �5ÞN‹RÎÑKñQøl£7i»9å}Ó@Ý~�îŒ�ÉMk ‡ÚšuäÚ€?<°9Œz…ø¹‚ì7wÓ á—zæÛ¯À•K PÂx7T:ö‘›‹£idYóê‹Û\¡5Ë2ÜWÀ³”ùôd“È2+*,Àu@«\'Ø~ï·d”·-ô•qxY Zûì'Ò5ñOñùoA$”š˜èÕÚCt£€ÁÈÛ£Äm$&lòqýA?Ðý˜€ ‚Ê0ü)‹·ûÐ7cÈ»EOés=I®`Ûh[Ò–’?ä]ô.ù'@~®!îów‚ä°hÇÖÖÏÚyŽ?»\[g³�l鉇‹b—`¡_<ì�N¢ûcˆÉñ乨+x¤±™®Íí¦™;ÔID *lYºewÏ4Xëì†y1YP1¼ÈÀ\Nl÷GàèŽèøA,g 4èy’·²Á’ëK ­æ‘á¹¹L»%ÚÎt�{þeøîÁÆÍH¶þ—šýÑúå\øõ/ùl{N‰:bÔù58¾³³ìY²Mý,îŒÄ҃˰¹í!nR:@øNÄP‰1EÿAïýCÃ&‡,ÒQ/ŸmM�¢ç‹GèŒñlγ{Éx¶Ø§-rbyÏ4â‰ÍÉäøLÜõæ%çÛ¥zÖ4]ƒýÊ@ÝÃ’…ž‘�K*©üsöÝä";ã'ý»|65´‰†àÚ“Ðd[z›ó¡BÍHu©?Y¸åS |Õ‰…G‡W‘|›\LR™…;N[ Ø1™©,­Ý¹;Œ†OƒÉkY®ºb™»+‘Ï4÷‰tðzGî·Û`ÇÇ2ä�€²Ò©tz ®Ê]Œ%þÿèU‘6Ob)ÆÏJd8B 0ù„ÜuŠ%7M�V™Æ]|Ë€jœå§ÏîœÂ#²×ÁâP"Æ9‚Ʊà ª:J&O 0»¢ 5ÒfÀã`èðùH­Æ. ›˜&Ù©â‰_Ïé“ȤoDW\ ^l‰!Þ NÓ㻺‰îû hY—DØÜÀ§#ä>Q KS"aÄéEžµ8'txeN7x ù ÆÑsÿ�…¨>ªñ4‹ ?Ùa4ÅJÈmØ›¼’É-N,};ÂO¿u‚5Ú'à'/Þ¡ô^×|`ØK­Ï9Ô[¤ÆbT¬2¾2Éž«ø@?gjw“Í-—i³Aädñá©›xó?SR¼Kg«Ö±üm•È9þ€h|¿„åz"0¸)éˆ*müØ¿õdUk¢‰‘ôzÒ±%qxñý^¸¸³�ŽM6°/ìµ0tåJ4È ì­ÑÄ&†¸22غ}Ÿß¬Â;PqÓ M@Î8‘ü7¯‰¢¿—cÚ·nê(ÿ‡Î; *Ss~Þ�«§–”ƒÛWhS“»èÝÒx:íÌrÌÏ"«×¿§OñäžÜ6øsö§^@SO=óüts#É+¾Ã*®Tœ ÔÑå7v¥î`¬Ç§KzÉ›’Ùpvë°^ �ÜnK4?-‰]¯FÈÝ?‘xàw9z7­€Õw²ñ?û8ÒÛ¥ŸZò“±ê=ÿ’€� ô¢ ÓWÄí‡r‘ 2/m‰½ÜM24%QrV'*ÈR7YSj¬GÍCH÷`Çø:Í"ÙOOÎ5¡Øyá5M�À\6ND~'oÒ½:€„¼»b怨ƒ,Ñøã |=HÐs=ú–!žóÐ(gªHF�<ÊYT�mqsÀ¢²eZ ÉLñR²Ö!îĹÇ�×>¥]=ì³¸Ž½–*ÄëÄ[:²26¯@/Î<ØrPX­Yüù è‘´ ³®Ó�Õì‚׋ñdH©N‰€Ÿ«ÄðÍúÔ‹¡E|*ÐÌ} î�,-ŽXÀ=ø÷=½ö»–ÿ£ÿò ×ý ô`®ßvð#ÚïÞP‹Y‚ ¸v9Êm+„_Öh¨‘Mó&êµ÷ÓÖ€*¶#9ŽòÛúÃoã,”øqûÜÂñtî3º´ÎaŠ?A•Býðé=UæÅ �Ræ›ÌÞî�ô|¹yŸ~ÿì˜/ôúYƒy0YQCË«„‘æ5� Ž1ÌÚ£HŸìv…C²08Y‰3 /¢ÃÔÜùD‘æO¸äk¨7kài­¹ø§›dOÇúhRîª_ù‘¡¯%Xª¸¿nɇÉgpØ)}§à�äµ�5á^(ÒÍßcQ â5¾÷n³ð9ý¶‘yt,�^PHïŸK¨j{,#>(­¾jóĈðo]h,ŸGf<؉§Ul¨AŸÁ2�™ìŠW–¤%ç çP÷ú,*v¡ÕÖPÿ€e¤Jj6÷}çzüûºC¾§þž—m[5Ê:Õ¼'ÓžáŽ'á(>�bá›8vÖ‚ ¨Ò�b³åq…Îfp늢œ–?ì·žrrÉë=.“œs £úß¿‘-*�jÊOÔãòéù¨v3Íu#qÝÜÜ7à \ìôéy·0p~¤BÆy»éÀ«-°Ú±€zÅ/† R’dɧ˜Í4P«ƒá¸/Å46™Á˜àá$¬cw›}'¥w|1Íä ³Pç 6,]Ibߟī©Á¸%èXð1à÷7 Zd«—{ð´„Ú”Ñí‘mäPDeçxQfO2£ñ3 %Eç’ÙY´k×x; É]{n1Ä7|¢‘ùAqš)ìþ` Ï¥püH<9÷™>87›Ë¹¸jjàÒá[°uør÷ÈÒêÞzÈJ§>ò…Œ�üØ~®{¤3&'òdY~=Oå'z¸|”i]]Êl»¡ ªe×9ɬaèóÙ}Mnì\�ÿô1¼ð8垟 ÿtùh ÿlTÜXÍÎçKgÛ[µèÖ²\¬/àÃè„DŒüˆOÂfãýKäÐã\š'ÇÇå7+e»C D:ŒŒ?M¤ öøSÇõ:ôš?„¬t„ïå"Ü-��ó.”ó?Egâ–óÓ…ñV%-J¢T„’BÏwÎC›¨$…$Y³•5R²”6‘Jû®´’-¢ç;ç)E%-Z´#¢è‡,©¯÷˜kf®9÷ý¹¯k挹û(X¼‡í¡ß7×`m—/ìïZ7 J؜ݲøAÙWÞbk¿HÃõh–>Ò Á³Ó’qr‚6~<£Îl®Ó&§^‹ñ+ªñ\ádÔy†!wÿ²½æmXÙ³•‰ññ"*V©ømk'm<%†çÿ@­7.¼óUGè^"¨“BìB12íÑÎRÃN³É83é\™$�‹�œ$Ÿ�åƒÖ‡ $TÝ•hi!o—æàËÒ ZóŸ$þ.|J߬׀¹'ž’¿{Q^ìツ'<¬A D°·çÍýñK¸Äù ³«Ë«•Ïb†×ÚÔȮիfŒ].Á¦Í³¸i&ëɧÆ=dןYè¾½ŽPí™;Q‹b~5ù“'Òpš¼6þ>àZöƒÌ… i²ìè4òJ`®¹þ¦B³…¸gZ#°Ìã; š¨Ã‹ ´b?�NDý?áJ¶ V­ší+ɇÊ!öåá*ü2Ù–~ú�Ó‡ƒ¢lÕaŽbÌr!ØÔz�¿yÁ~Y=ëˆúÒ•[�®’„9ñÁÀVB-Å\W}Xžtbx"¤Eßño’Ïýj°UË4õì`çî~z¶míœÈ£€Øâ¾GÇÇÑLtnrk'[l.Ó{é=X�_HFŸ^!+œCÉý»ùh¼Ëmµ–ñæÍ�¦Ú{¦�¢ þ-™zfV ©~µ~ÙZ�Cä(�-Ây7ÌáhpYº÷%ü8 µ=*ÉK—LÚzv‚éòZ aï³°6Óþãç’ñŽëØ+q.G�ßP3ö}Ü…Ó‰-/‰t\LÇ�SŠ ZF�/?ðžœ?„®‚×qÓ p_ö˜„¶|‡§Ôl_gç&1>ø9õKY ÉBTÙá‚ûÚ°^%Žô‡«³Ò7àOI1¨mñEÓyŠPc â'ßP]7eX­‰VS‚Á}@?4)bd»ÿ¤€º?G�ÛmŽ*®HË„ÉÏÇdϬpZ»¶…jZÏé&OC¥èûü µØDl÷u£GV$Ù¦ Š•örf}̺ÍX…œäÙ ¢‹[ÛþÃŒ¹é²Új'ý¤ùgfCîò<ó–ZìºIUQ£·„ìŠkÝAÒ»|#°Ä øÐ‹Åò�µí �ý�±­‚»¾ Ãýýpz] µ�¼ˆw ‚†Ÿ~weF™ô?�1û·%l8™ ýepÿN.yö@„ôLü¥r¾ã4.>YO\É%qšòe¯%Ù'Á6°ƒDºõ±¯EçÎ]ˆ­¥è´dÌýÞÏé½ã ]¯qÉæq6ÍÓkô[ØwVÖ°îYçë ¼ëKqÛã^�íàÃÊ“ñÄÉ@=B•à±�.„ýrg‹koS×åOi‡v*µPbÁ¥í(X\ûÂh™\¡ I�é5Ð÷ÅÒ]‘PV\D–/ÍÅßéQu�_Û�ñAïiê;¸¸Ý ¦’¼ÌWø6á,- S‚£8 Es)ºÞ¶DÍñ PÙ‚+ïoèÛgI«O¼Y´ŽÙÙÄA‘¸-±Åö^AC™DÖ:>šÔÒ�ïR¡N(…ä*KAÙiå¼™ŠÂäF�ÀŒ¿Ðóa1†\E”ÚQÂêÉ#Úœ8LkOe;ý…¸f\e~æëÅØ�YG4×.û–{ ¹¾;˜¡d³l44âZ\àÀ9Ù0¿“ùÒðþw/ñô£ÄLs9ÿýÉ/Ôß64•áÝcýèÂÞÀ¡cþ˜ßcX0í†ÄÉBd¦aüþ’âÖ$raÞ-0øî ?ç«°?{Ô±¦×ÊB¯ãè®Çtþè KÑ V2\$˜º+“”´ÜÃ}á! ÙsZˆÿ«8jel‚o@ŸêÚ—¤ ås Ðu3éZvU¾Jà¤GGpõ7a²ÑI“c#Bm.Ã6� “ëMMg6ÐBâD§Ÿ¾ËÄ�G“Þ9ž`ê?~ ‡ó ÒH’S7}™r€æ‹¯¢ÚãÂÌỸkVÿ"6/Ñ,¡»8M=Uìë ³)�®ö/€òï»0uëvø‘iMƒMWÀ%çShr×ÿº˜boGžÏ(’rR6.æø›¯o�Çsº Úü£Ëd!ç» 6Æ+Âì †·ß¼ƒ•Mì"3–’®½§ˆl‹*gƒövöªÚG²á§4ÌrÌÀõïž‘GÅþ0?‡\:¼ܼòˆ°{òÝ—ÓÐwâ|§0]î¹ü_Dnå%45€}j4éš"éþ;“èPM¦r¹G;À%Ñ€Ä$¾ ÝÓ1ôoæLTà ƒ º·à,=d-™îÑÔþÓUœ'¡WýCÐõ§(·if X¶ì�ߎDh¨�<*» lü6�›ÅÁ¯Í·˜ï_á�QKLâ‚eí:¶øâTðÝ nBXÿ†Ö¯5Œ~{\DãÏ„ƒõÀMâD¾ãÖ˜K°_WTµrPjœ +Ô%aÛ:m„�z°ïÌ ¥Ðó³Sð“€|t@{ 7ð5Ëa&þ†×]n¸Ùßgw ƒó–å`nSHå6ä€í©Íì3—þ.¬"¥½ëA�¤ |‰ã³2rJú$<~ ¯ÝøÌ”µº%µ^:Çü kªðä:"àŪFrçëUˆŸÂƒÚ ˆÉˆñÚ€¹ƒHJ¿ƒ¼I|ÚzO ‚Èâ–_Ó°9œÏXÆßF³±Qæ^Ì~râBz¶ûbÕkkªýg5ží¶C~ßYR‘r"™ûô´¿b™…„2}+v™ ÝüŒ>r¼+ÿͧ۷‚Î䆳×lÞé„–œ†É}¤x‰:ª•ÒhÞ ,Û±Uu®S¹Ý½àiñ»]¡¾³ƒv™�ÁþrÎI·kÔ¨ òlSèû·Ì�ÛÆø»±ë6–’ä¾£´¨’ÂÊ[Õœàסt¶ü^ºøPi¸ ͽKaUÕ2|©Ó‰³T�=Šë©öï—4›+ ö³†q,g‚Æ)FÂC�Aò0§ 䣶暜ØK*Yá..ƒÄüé+²ëm–¤B¢tm/¡¼Ê—ä½k8nl/ÿŽÙPûÏS«ÿôbô‚§¬FµNsƺÑ%ìÆÕ.PœåŒ®6Á¥¥Ú�8I’æÕÇâÇØ@Hý›K¿ ÅÓMªàS{>.Éã“1ýlØ)¢J;HSsÛ1öÄîq²’ÿ˜¤3/@AÒJK:ÀDÛ2åœxw튈ZXùo§5Ì1ø€ wBiûIxµ'4Ås1y�ô?û—'e¶âÌ‘´X¦‹¤˜¸CËû£ì‡V¨TL~zÈ£”KMÛÞŒf[§ò�U2ÈÑÚ�?w aˆÕÄáÐݳ„yF0Ñr3 ËñO8áÊúÝâÍ{}F‰$ ¯s!ÓâpÄ"ä| `âg).; 'ŒB[c¯t4/p�á]I.òz¯ªüÐ£ë ­(�éTÀMú!ì×G�…¤ÜÚ>ªúy µŒÜ‘»ò±¡^/iø¶ç2ÚH»RÍÀ(Ö“�§DùÙÛðCË~Oo€¤ d…L#<Ø›‹¿Îb‹]c9¢S…©Ä޲v©¬Ù7J—�¡R%íßg`zë.ºZR³Ä^¢÷/™üƒCŸVù„l2×Êa§Ål®�ÇEpw�Ä#Ú  qm6úxßAýK>2ï3�ó<Žjq¼°MNÞ„ôó÷èÊ�qDnË>º×ç.ÉMdžY»À3¯Xü½ú9ʈÏä.RÁÔŽ<0~ú† Óm61È yL¼—yô™¤r¬I þFûàÛÀ*æ·ž%¾Rù—~æ°r÷6@UÕöêÙÌÝcÃØ8ÃÀ…8eÍi˜W1Rp-üͧ±²ë©7ŽŽD`ó!6gV&µ7¼L_öá,…tf$ÚKMÑ)7ÚYûÔ}˜°Ã¯.À�ÜÔáKT{M �eª¿¶}£çv×Bl¹4ò;ú‰ÒˆARŽPoß öU0ªv‘h1°8¾ÏhÆCYÜ0æØÙ”ãsò1ÀcÒõ_ˆÜˆ |\éÌ49Ìe¶éÂnó,Ü™ì%‘fi 1ÖNBS¢àÞ!yj›€ê÷'AÌ™|S€ÅsSàæ¯&bgy!,�O›éÅ_úâk>›9 ç6-„²@OvÊÀ4xÔjAGßë ëFÜ&�® @—×ÿ2œÄ83insÞ/úûK¦¿�Å£WßF[~¥ meøKìéNmøSxƒt¨ÜB:eôô ÑÔŽð|[•5^…Þ­5èêô‚ôÎWä¶7âœ�Ï!Ê&S¥­ÁªU —T S't†T÷£t– %*âAPÿB:ÕŸÁîzxWêÎ4™*ÃÓS1Ö²›¨=á žÕuZ:u: f‰ð=Sܨ‚eGŸ2Ç$|ñ%~G•aÔô{G3•CxjÛ0­m-.Q>i)Zìs™í0�ðÒ0þç8õ»% 3:'ã©#ñó1]~jÕL¨�HÀ9vctòÙ¥< »ßÄëÜ^ür:W�]$N›Û°:g#‰éß n©°-æ-š$BRÓkäødá²Õ/éóýÖÌÜ×2ø4è2!{ ‘ûÛòM»°ú@ùºú4~²\�oV–ÑéUÄq‰ê°fPÑm‰šéŒí³�d·¥7¬–bRo�GÙËðP¹()á�kf\ü³aäÞn�Ç · ©۽òÝ{@ve,>Yú’JèiÒ¬ÏBxZÒDµ~ÀyE{¨ÓƒÇ¿:ñêÆaÒmŸHÏ�Ô°2ÓOÓfÛÕyËú>`Ýn9¾µ†T=+¢Œ‚1–}k†K.“ÁbI%¼Óæ`qû.l› ODa�Ì52RßFnÇvÆÒ—Æèr\ãÆJ¡ð…3”,U$Ö‹yt±P={øÌUœ”´^�½Â¬ÁGPpD‡òëÙe³Í€}°“cïÀïúHôVLÁ�•0t žZåá¡)zäôF5¼\ŸB §d–:ËR##+ô7º‚›ë”àfƒÍç Ð<|‘:›èð}G¨ÂÝÛt﬩phr Ú3DlÖ‘†UkQís0^PÜ…gK¨¡Û"üsò*�•änßþ†È$À†ü X`§ 6“ñIê$®¦¸ò~‚vR: t¯Ã™Á‰°a‹8îoì¸û™<ÈΡ’½8“óŠÌ:Lž?¥Ûþ­ÑŒMŸ>›‚ç2ÚèÔE6¤(V Ö�=¹³�Ôå7%ú)øk~$Xïa'´¢`Dð©ýØJSV­à»šÃĆ.”ýþ’ÝoÐ{ÛïAkß]t0 Àóô‰HsF¾i`ÔT΂—�g¤¢œ5~à “–¥£˜´'»G…‹Å'Ü`ëoh´=ÇÌør;hÀÅ�"¹t´¹Kâ‡áW­0/8˜S�§’^pÎS /�+@ðÁ{||HˆÊ6£=^ñTwïÆg1²X™wúnþAí‹`tãÿûJü!•·ï€"w ûƒ·ä‚à¬Gœ!F òž‘cAœúy–èiç‚Kã`F@‰*‰£æó7cÚÙHR¼â"Þ’. ­ÃðÙ…Õ«Ù®ú'œW?½ah¥(Ä/‰€–Á*¸�-Åý/å ³\™ N&¾t—•0÷xÜf»žO ãV�ACÕÈ´#C¸Ï-ß„ç�å“ôñ«¸g- ½PLni.‚]SσßåQvº�ÿèøt1Ÿ„~á^¸x8zÕÃÑd†?V­¾Ãëœsƒ9ÿ¦’r§Íã¶Ø×²æ•�­3 ¶ÖW“ø…î¸WéþØ$!žBðêgyM7ò[>’iøâFÆèf˜ÏfÛ_Ï$m�´/8uß³$«Þ‡MùšÏî³íÅàjG¾ßó$¶ö‡JnY�Î[}˜]Žtqö]4Û3™_¾î$u¼~;*_Éõ¸ðùzê~ƒQuEPiz ŽéÞ"ÁW%ø>oÒ©…‹=Ô«OÂK×ÁÆ– |÷¶iBé瘻\‡kn‡‡Ò“A‰ښƾv4‚ *0iG;»gú& ç`î%m¶NçLr<@\‡[ˆáÒ<ºûY1±÷ƒ�ò•ð¨ÔçÿãÈ`éE ÔW±Ï8o-†Ãsåf íù °‹§‰ KI„¾ï×ÝyPzÇöh4’Íø±I™™\Á2‚žxÿõcð“ãaÁðCŒÜCOoœ +ªsÐPHªª×�œWˆ<˜©”M£'tù’ºæ¿ƒ‹ChÐ�7Á¿ƒŠ@•ÓMÛÌ�ôƒx6cò“Ô7V„¼yëèá¾&¨™Jefª /[ЏôhñÅãqGrÙ¿é#>7Ÿ?ç·8ÙFÀÒ»ÿXÑbL#AªS•Fv<„º®Plû‘Ìî±B¹»åÔÔðëêJN㯭K¡µvÍoi¡­å5Üþ¶îÇtS/õPt-Ž‚îàŽ@T>9S´˜û{(CDÆHYd1hv¿ƒ ¯2ÔwxLê_´3# Y"êt ½æpxtp.3Wñ =~æl{àþ>é$o©'œ‰O§ÕBÛ±bÌÁRß8Â?°§"óÔ¨Rå��'CÃWÐ?\×'âf½ zUS ŸI­˜¯�qú o˧ÏnᦘӸ؉Чs_¡è§0z:£·ý:ÇÌ~³mL•hR¯tŒo‚9±³HÐÛ·t¦¹ ¿$Gšo�Dj/pAÕ^ˆk±Ï ÄUÈôÙE˜³á¹jë�Îñ›ÁcŠÜÌ{ñ3(-»¸y‚ž}—Þ3ˆb*|ƒÂ“ÿXÙÄ´×á"_sï½ Õ¾&ìëìüƒ¿öà>%{4•­;EOÚÌ‹Æÿï¥{1‹µ€1м‡Dlí#º¼Ã�Y…vìɯ›Ñâ~ UË!!éç 1õ‘ÚËÓ¬kFÕ:MêÚÍ ×ÂÞÄhU¡ÄBØ“þŠã÷�Ù£±éoéiN&î ÑËÉ”ÏR8Å °Û( ƒ7Âö®œ¼É‚¼äw £B4œwŲ ‹ÈzѸÑbOîÜÔ šƒÝH˜~Ž©æ0žå gúwážsåÄQ/TFJ�d£³UàæÃ`öUˆ<“ÏY†}×nSŸ;½Ð;Å :s²hw­‰ë°„o¡ç0Cß.ª_båy43�ÐO]þê½Vàà«r9�´¾ë{tàÕ>šøS›{Wþ&>xõ‚(p5øË´Òo/ƒ±ÈÛž|Ë&Ûç?‚žÚ˸Yµ�þ7‘¦îÞäÇþ~ò+;�¦ýûÿr¿âe<ÐøOû¿ër/]΀3–óU«6lJ©¬$od­a!N†Uu³ˆ„ž7Ú·ŠfE]EÝ•?˜BÑFürˆEÙ.˜7mÊÙJó¦˜Ámq3èzõO?æ™ÒE]¢†Ò6¹Î)b†b']Óš‚Û¿�ÀýZ»‰bL4/¶‚])ø{ŸÀ××·1¾¿›½Ù#™ë‘U} ›Öàïè<Õö†>_œÆ˜ÞhG#C‡™3€ÑÚ5‚n§‡Éi§B¼'šMœNZ’Ïœ,>ú’d‹' û_!Öp¥*×Sy‚T¾ãƒÖm¾½õ Ô>!Aú[Úð—ý¢ ¿[_YAPÇ}úΤ3þ�ß8÷_&Ón&ƒl´n½‹Mÿ’c#•ôŸâ¡Í}´Iú"›µV�ûv™Â?öHcòjéPÛF¶%ð›[*5ÿ¼”«wJ½«…`aØ!åÿ Ü÷… ÉõÃèy²‰:ЄŽ°5ã!ÚL[Ȥ�Jb@«9s%HMÅ›±Ç/Rú�ìï¬Å�õ˜]²bŽ`åA>ϴDZð2Þ ¿½Ä¡!ºÏ6\&VUéx¶ÁG¶�*¼ÆFÒ8¢¹ Œk½¡Õû8(ŽXaü?_?ü-¦J*Ýoª0é}ø×\¦Õ¿.3~ó÷õÂÀÁlæöàjxqu/™Tà}3'!'n;¨ (£ú`˜¿mÅúR6`î>\f‘@Žl¸F×oAïLM®¬ÞVáƒ: û{÷%ÎÂ�Y8_>bÍZȉsùTj¹(gÇ $vžøÈå ª\yO©Là°ÆpÕG¬v; Óœ¥qîY1ܰ7 «6¢®H¸{ià‰òù�}Ô­MncþÃ$ØÓæO>\÷€JÕ.èê?MW:él]\°?Ÿ$¸Œ�¬ál\¼Iß�žþC͆¯ã—Ø;ôçcú®›…¤å|°ø:ýy;b5—ÔS¡Ø›â %wG†ÑœÄ=x%4¬DP^©â9;Cbè—m*ä•V3èü!0mº6ëzSû ôÏjmü~³êp}ŸNô®$Êýå¼MÅúô²N߬¤��ÿ‹ä1�hÞC–7—’j‘ôÿpÌ�?F¥S+˜7û¶Ó“G­´Ï,Ûg¨A2¨6çÖ•o…e§‘eÒQÖó7ùxê3L™ÁÒøOX�A{VÞ¤ö˶àoSkÞ[ŸWà$8´û àÀ×TA÷,õ]§MŒ£LñK¯ ¸GíÂ…\Ü_B·‹äRöû4¨q“ƒîÿγ~ô¤¬AGû"XhcŽ7$"÷àe: ^O›“¦Ò*…a*³u#:SŽ?Z™‚ÂM×Q…/Žë~¯ƒk«¹¸cúz<Î €Èô‘i,ãùDÛ_ÿN! .)&+Öš¢kÀN 8ú�†ÞºŽõ‡8(6TF\.`Ú燤i© åmõ€MP….û½H{ÖE¸¨]@æ¼m${<ø4Ò͂ߖŸÎõPéu6ÈHÇÒŠ�uxhª-}„+d'ó¿�ÕáÒ7©ûGòòæl U†óÃÂhók~´’U½ëÁ«u1nY¼ýI¸½QôÛ'£óŸ‡ÔÊã ìÞGÉý “‹!Ñc »ET–É€‚hOÌ5HgžÉJ¡ßïEÄúÕ=ZU4zÖó!O[ õ3ÒQ~*ƒÐ= ÎI•À¥l ®£œy½Ø™ßÔ-žjðÃT‚/‚òϳ�ûÊ�M¦ò$Ôz”f9Æ«P|Ž5Z´›<{^‰YîÉäx…¼´Ç~‹ÁùØi˜±P”îú»…€›Ë¢·Ãö«ë\+®Í”2FÐ9KÞº!ÆÝÃøæ—dù§R¬xÏ‚~ó:¨Ý| Â]<8O‚kÁzÉs2g4�^P·ÁL¿8dö–ÜÙ}‰9Ÿš…V«µo-ðèäoòÊ¥–Ù4Å&ç[Á�O™„îÉÜI”ÄãJñAú6ü5‚´]v# ¤ž@âç Q…º£ºäÂF‚ÓJñç5.áM„üH,¯nf—ž§8°ÍÛšÅ$¹®•‰ÙÇ#Ä æ?ªV¸‡1pø§½çùx@<¼Åbo´´È‚77ĸž-ì+KIºODz�’mšÝtQD£%~ ^K�§é¹ô¡|"ì»HûrOâ´lèÈë&îY›É¶ìàú„©Åƒå¤…8f3ÁN¯™–¯ÑÓ;‰>ßRMxÓVCä³0Ò¨˜W?Í m¿Ñ�/©kµþ�g6.�¦NR“©¢�qö!�`&._·Ö?ƒ[·0›Œ`É£§¨ï�? äP>鈣HÛsâxm1®ÙN̯̓]ƒ&°©G€?QÚM³Ýñžœu‘ÅíjI¦Ùì{ªƒê‘Û0øN ÆÒ† š'0(t¦^äJ,o†5êpô£ •h( :Sññ.Ì'nó%°äÂÔiâi‡ùᆉåÃ\Øià'ÿnæDÀ (~j\vóã}l<,Cã5� ÐC„®¦ãúy#œà}y0ºÐ—ÔUŠr«ŽòðKü¸Sz�)~’CòEýpë¼Yè¹*–þ´¿…2§VA�ú Ê¿O§?=”¸)³¿²ºcs°ËZ�¼\—€ö4 ­? pçý­Dc›i4ªÄ{åPøC-~n±�Cý–¨8°Nd¾£WæLá_”ç)eóN™Èq½†Œø1ï¾’É=r '^�‰ßeèÕ)Ù8><M´F % Þ™¼¦Û 5$¾­ú0$¾®Õ ¦5R¿8Ó¾I§™V-¬JO+þçç‰ú-ð(QåªJ “àMuôžn,>pU箨cw>Iaïr/“àÒÜÞÿjÀ{ÆeÚ¿v%®­×ÆŸÓq8ù:Óyí*ÀÞº,ôêºG…œVÁd{}’Ÿ(³ONÐÒ„óP<®Œ+fkÂrM¢2Û$2ˆ€I,ÉÄÆ´‹Œ³ôc°çþ 9²¡Ÿ³^§]Ãó³†ñ°Œ´ùk`Ž¡ �ùDþÿ†LïÇwü¶)ŒõÔxŠ; š7k\ƒYj:yöº‘9#~‡•q¿ê³§ÿ«KEZÿÝfYt—%¿J`m?D±mr‚`,®U÷¥aöæR<;ªŒ Nï ýA%�oø‚r”ð•…ûUµ:MN7[Òè¿’ ðÆ’,ø·>ÚÑWõ3hGƒ:‰ÌˆÄ‹ /HÁ�J´ÎÜ…£ò3ÁõF=z )a‘@IÞTNÖýçJ…“ƒñnÈJ¸+ì0åÏèæ,Ö~ÿK§½¡¹§ôøç?=¡»6ú¡eª`P”¶÷ašü%<)~ B²jþܲæ4|.# †ç‚}r5ýVò„|äo%†6idðˆùoç(ñ2K <¥ëô]ô†×¨ -Ìwz9V�ć¨;ÿ L|!ĕЯ¦[—,ƒ>ÝBr¤ Œñ~ÄÛP_ˆóüÏ�‹§ké®ù¾dË”�ô[w*»dEÖúÛ¡˜RúW¼£Ñá ðDJo÷<%jú±®€ ßk„ã/wR»'Ðôw&ž9¦£Ÿ«È—ÁíÔíj7Ù`ná'¦‚°Æ°ÍÿAä;¡Ñž‡¤Bç<�)‰é•ô´¨ Qè_‚¡Ï.aôMP?Jî«.¡…Íÿö¯=ìZìiOÌ…?1Å ß³Ÿ—,eY?Ü¿{+NÐÓ³xÐÁTs»�’·Š¢ø|Í(4,·‚}:~ÄýZ¬Ï$—õÀµÆŽ–8IbeÿC,>€?óàÞ»Nhp½Eë€òBcè=- _R•qÂ4•,\Þ®Øü–[ vD€ÆæÎ…Î#J¨¤<‹‘<»‡j4áï¬Éè½ëžaò÷vòÐç6ØžÍDï�aôÒeKš/0•Ykw‰ý¹6›Ó¸Ðdg‰që,,pW„ê^ÜŽZ¾Ì‚°VxS»‚öþñ†¥]çé­XOÒºè'1"ê ±™¦ŽSêöݶ5nÃB§YxgLX`‚\Ýš“J£þ€XxñYõ•>¹5„²}èQ×(žAʦ¼ô)»jh¶{ 憽‚�¨Í�«�[Ö«âSç0¼9Ú ¿\@•ª µ¯•àÇ•\‚/‰Á÷Ϩ¼y?¹· ¶x¹bhC ýö³�v¬9‹¬š3]WžMßš„3EsÀû/�ôHÜ¢ù’<2é�2J]i$e}Fô†áu8Ü4•]û'’x»¶ãÁùóáöËxlÞ&fV[4µ™£È/5¶e²ì”À{ÕN|6”MÔû‚�z9lz~×–&QîÞú^¬‹Fuó™ô� -â1=wŽ<™*Ã𠇮ê ã7n=ÇÉC0ÝËœL‹žyžî8 Ë*X¯óŰøül(pèÄQž Þ2¨&¦»RXáñIèÆ*€ƒÑ|”$OõÖ8â³�á´¥EªÖæÐ9ÕvÄÅJˆëb›—.{âØl¨¾JF}Åa\ç.�*‹iIÉDñt7?íßÓïFªðvØïvG²ÿ�ÝŽ� ¨å>€üGßárÆZ�äô‘›Jõt¯ -Ë61yé¡PpŠP‡š›xõaM*ùKGìüaö¬NªT0 wZÝcθŽÛVˆÁrñLß÷N•°üæ£È­¿OFrC˜]sLj» Ã4ŸãÒ§ÁbÒ Ú;(qsvqhõ« <´ &d—3çn‚q–HOnf‹”�¡M©j'öÀgŸcxû¡87æp$ô: ð–æU±Õ+1¥ä&/:HÆå8øb³5Ãÿ�„Îmº¸´a!X˜N‡ô³÷IП§ôÜìðaFU©¾ æä TùÄ@äXÝq8˳Î(6‘ýÓ–ÐÆÛ $d&¿Íí<Ùt.‡ƒ™öoŠÜ3Ǥ ¶"¨–ã/‹ ¢)ó«ú7ãu¶„cw‚‘écâpë{0¶�ÌóA‹ÏjÄ{Å¡7ºøLI6q¯Bæ‚\ôñtÖ$à™†O¤Âñ3±¿è’”¬n© Ô.~5Ì¿Àž+zGöhEÁ£÷Ö´êÃ.{ºÒCÐ��InßäMÞÐA‡™0˜�è·p6$^?Ç~ ¿D[Þ±Rïk°7%€(õ:£Ü Ò^!¾å0¥Ž±k!)KwNãÃ<ž+˜ˆ·„Dš1DuSÿŽ âþUìy×h˺^b4½vácÇb¦6û>M~¾[îÄ9k ¡µ§¿¯Ÿ‰Ó?u³J‡÷“Þ±:˜+æ�óƒè-�ëp§\‰{wY;Ån×>Öàí6¨aVñKˆ’®4”ÜIÅé=q¨p(ƒùÑ&E–¹‡ÂË=ÃÊä!hàû©éµö b.fÇcB],{­,Dºã°tW2Õój$B?ÈûÜLœu.F¹ÁýR{ª>ØlÜ»‹–ìGÜΩÂ5"xoÏJ8ë#F¦˜�•å·xÂ$Ñ ø5ã4ybÕÇ‹N…Ã?uppÄ‹•]�J^-ßzfá�M6áØ.A¯Ázz* ÷A4âÙÔbxW²†xIÉѲ®@"s·š6c CŽ=Â+cˆÿè7úgb)|—Ä”À‹5ˆ\.’ÅZæl~‘$Ów—†<¼23¸êž¦dé‡íìT’�ß5ÅH ·,gNb'œsáÌ'a®bö4x˜‚N½Gʜׯ@�}(’Ùy?.3«]bQ÷Ð]¸;Ã\ÕwÍgvÝìwšsº|{©Ã³»¨¶}#SUõ†ì–XÏä¸ÎÀ§ªv¸wùG¼ð11ù 6 ±¸fà ˜Í‰e=§V`tr+ìèùȸ>}*ï21ýºebC`N�G=B¡�sÈÏ”i8àî€?º†1±a«ü+ ¤<ÎÀ‚È�ôžìtRXˆÝµДu}YoVMjûuâ ò;¤ø’KôþeÜ üdæÏ)c½‚l)kÀó)©?‡z$šäN£æ™ÉÜ‹ézt¼`¹Â$\¡�¸÷�?]<ºÊ8 ß7Ÿ ÎÖ8Oí¸_ìn•aÂÊâðõK!~§À  ÓEèŘ»´bS}åK ëŸR•ªJZœÐC%®@]@.-\³δŸƒÅÉ À ‡ß£�i€dë°÷*[¸ñXm¢Ç÷YñCs°êÞ«è‚`UL)ö!íb är<¤= ‹�wC|f¨~æE§Ð, `—ÎÇ;§@µ¶˜{óá™ø²SPŸö¤?bWT ø ú·ýBs3½ïC/j¥áÉÅ�È©/ï©Áü ê;{)ÔH8p ݵøÎÞŠPó:�ðβ1йäþS/Ôò�àW|H1‰B±OÛàÖ!Pž¼Lü‡hé ›+x¿a .ôÁô3û1º1Þø5=óB”ßkÞˆ®ëôHô"yôÄQBŒ{¨Íýš{÷´­ž |]%̹÷ƒ¬°ÒÂSq FîÃ)sláÄH1IiÒÁ²1BŸæ$Óc¾3ð§‹ l:Йÿ’”G`›…`aUœÛžŒŸ*þ#:“Ê0øõS*’��½÷Ùyû7໩Kð©î"ïeDx5{.ƒ®, ¢â­„k3�HÀó€©Ì¥Û§ÐÊ ˜µ¨q€öV8M¯»ÄU@T˜K‚� `«ÖvØ;øÝœ¨‡““É—3l»‹#ªËø³Ru<2'‹nŠ¢Ì„⃠(®›g–"¸mYªÁó› œ¾f*_­- s2Ø|óVâ6z›#ôúåÇ£ñ�hü事v�>³uT6Àȃ°éý>ü| Ö¿í€ÈµaòÀs¼%I¿»Ò­§ö“ìãä¥N é“þƪô]#íkÄ‘›!ƒóNø¬j\}šõ¸²žF‹’WΩ¨`ÒûÜ.# ÑcÑ$ðzSŽaYðLÑGw$ qkŽ•yÀ½’Hòkì:ms€n}/„M“˜Âü‡˜.èÒ¹Ùpù�é·Œe†jcG½¶ã}­�øGE§^€MáÒ`sazœïÇ’·q ¶Ì ï7Ròaw!õL¯@³__hh¸&ºˆÐGam<Ÿû/‹*O?Mä´�pÆ€¦\÷ÄËq$àâ0u#¢g�rêù«ŠŸ�1¥eäQÊRvÝ‘4ÊÝZÍŠõöáçÌRœa:?O¾µý\AHé9p¦‰|:½�êKzÀ„p Y@�»n÷­�0gª2·Gd#UßG»BZPRT®Û3ÆJ�(À€¾d?\óPŸ–¿µ¥vÁp²ï œék¡Nê›Ñ§'ŸÎ[ý&:âÈqÉ8øÜ#Àßœ%‚Õ[±Vº” o[Eº•<þù‹ô¯úCj;iè’/x+¸‡\9žI'Èæ¡yÂRPîf‹_óöpKJ�ž—âÜñÂl4þx4¨05üÿ�´=N4{õdlý`�"âõ…A)¾·£C�­¨â¿�ùÉV$–­.’…�ÛOà‹ÂaXÑ'ˆ†ÙMìˆ!¶¿õ‰Ów¦A{¬ÿï<بHÞ|"÷<>’Å£†LŒÓ úsúÚ´FƒLÝ_ºùܾ»Ï!´}F°ù¶ ¿̓5Ì'FÚ�7àƒG4[S‹ôgŒ˜üí$7Ü«©õ§#D[æ6¾ÜD˜AþŽQ¾Žk*†–t‚ãP.JŽÇ€• ¹¶�ˆ<ûFžw£œ”4Š.üÇæ�‰i®ÙJ§s;˜SpÜD† mˆB�?]ò 5–FÀûØÌxí9©pü£{~†*nŠøA]_¿Æ½JBäÎmU8xx!®ôž u³NÁö9ñ0èÝDËÕ›ðª¸#¤ÉÇ™ÓÝHÚÜÔ‹¹Œ�z^øâC¬c…!ã@:ø–®@/£\°R] kËR¨.Çúö3¹b×ÛȾIá@ÀÎó;þ¹.×r\èÏw’¤D=‰(ßæBå�$t)Þ…�²3×h�¶i&]èS�38Ⱥ•fÒñDxœ?‰fÑxxyñYÙ:ŸJÜ”Cé4Ò˜À‘»#Øpø-F]êÅû¿E°óõ}<“ÚAG�=!7ì¿€ßSJsÕf`rÕE8ô !ó8Cºã¢t�]õHô¬(´2R ót >¾êI^4¾¦+v«ÁÐE8Ðõ�™Zr�õäÛ�fà3³ûÔ ¶¶/�Gw lÁy*B4ó?qšs±“BÌ´Œr³Ã“ áî säÝë§òIjШ�;¹Õ¸3þ8#Šƒüžpæ:1í›Ø3= OkÃÍ1,:0€Ù÷aue™’ÙEFNMàØg;œ}"Eõ¥¹×Ô§QóÀˆÜDV<þH¾]㽬_}^œßzvÂPˆÄ–ÀûÚþ+—�8´„Í…¸oãÆÐë‘`Ñub*y/ºêp 7\¢=þ‡ðb×¢¨�7J[hâî8·:õFá«iΰiW¦¯¡‹«Áãú" ‹þ‹¦éuªÌÄ¢#ØX}«¾(¢œ�8Ÿkfˆ{ô”ù¾þIEB�hÕ­9høU÷‡Þ"B­Šè“ÕAžN`lý¸/úîª|¯勪ðD<•ž>Z€ø\"Ì_Ÿ$üÚE�fy“ÜySøŽñúœ–Ûº¤BÚUUÏã“ØiÕíäg• wGú}˜]•Nf«gRÏÞ¹¸òõLþÐÙB˜!TL Kp}oÀ¦I³0_ÞpÁeí3iCg6Ô 'sÿÕÃ’ÃþðéìizHÔ˜d©üB�:1~Ôy0\´•ýDèél-bÃÊ…è±ÏKà3JCc‡?.Ï#' Êö*L½ ^¦-�þt>÷Þ�“¨z�jÌí¢\^(µÑ+¡–ò%"OÝmãÈ$r ²¬¿ásÝ6ŽÙm0Z�ÅWAI­—œ ësr蛬©�ÑDòއ¢iD&N{—†…73n7 †ÝÖ[â±á{s±ÿ0Õú �»õ9ð§‰Re3söø,˜ö%?Û£úã ’`P‰;ÝÃéýÛøêA.{W+RÿK ¹Ît‡·8w¯8–ÿ Ã’;uP4¦††êñdß­çdáôx°>6 .~Žé£ÛèúW!ªWUdÑc³1¦¿~ÌV/&u«üqÀ3 §DÛ�ä¤^²ôf3.÷äø¯‚v¿+í¹lôFœ•dŒ�. œ¹ðî£ÔdÞÞ“§Ï>­Â¥ lÐä.z4�ß¾C´NêÓ€ç`Ã[‡Û¸°eK²ani­×­Á 6›qpÂ*�ÄÒrW)¼4·—}u•~žô‰Œî(ÆÔáiÍgpµzº!íw+*mÊOr ‡ôrAþÁ_9±E˜Ãlžµì†TÅqØûRC**-“8Ùn=<9›ŸäW‹ñ<¢$L·»_ÂP½'t£S¹Ó•Kûdî°G:U±o‹3ʺqà]ìÞ_N<2uƒKý•ìË*¾—ÚcŸ{ùZ Ç®y‘-ýiXl×:•¸S|Ë9¯>$Û�¯A'{Žárñ061÷(´éÜ�6(÷{6µ�|Œ;Í‚†ŠWl·™,Dño£àžLvòܘu¾/WVb‹“%zœ„ÖÊË‘¹ðBN7Ñ»SÍèú7,¹ZíG¯ªˆÂöÆ\Ü—t�Ü|>«^MáúžQçD_"YÓoáòòvº‹ØÐ>%G¿ùI¼AE'Xó6G*Ò#û7ƒ`„0·ßǃm&C-· /´î§[bµRÛÞÊ@´`�Ür\1«ˆ† ǃïÓ 8?PŒ=Ù¿š{ß*KRþC‘£–ÌîéFdeÁ>Ô?1AE[§À7]'âsç}ß=/d‚ËËW“‚ƒá$rP: ðèÄ0ß=TÀNVÞ«û¢~Ê)JgSí_݉G2ðø¾Éx¨ï dŽ:â¾EÀ8z3¤>a¯Ÿù Á#�H|ø?m ;;P=å"ðNÄã­Xö¾¼n{v† CED žÿJ†3kqQï.wªc¯Þ¾B÷¨å3Çn$¢e⾚í̶?ƒE¡—ñÚ�ô^Æ_Žâýb:r»Dù›�æðŽ ö�+@³ß¡8xð»±t+¾&„qRÉ ¦Ë<^àï92˜öî?Vî×6È?µ‡øÃ±5�8m�'ßã,Þ·¾ÉJóuFö�AÚTXtB,kÐú÷N0_ó?ŽÎû¯çïãM©”¦e$©Hëõ<�—‰D…�ÞF„D¡ˆöÔÞ[´§JÏóxµDÙ% Ù‘’ÊÊÇ÷û'œÛí\×u¿ÿpnç?Þª-WQH#çl &Q?ùQ}–O+w3=8WWÿ FáÓ:¼t�H²µ| ÷†£˜ 1Xö”& ¦SIçË�;�,�LfÎWf’Ê8¿9ÎÕýA~â>$aÁœ&xü;ÇkÇ(¶�ƒ�Çšü à“‹Nd^šŒƒ¼®<ÇüúÑŠ£Ã™h7OŸŠî�ÂîzA²ýˆ�â*´•ï‘îTh½Þ>½z^šA6y‡QXy[¬jóàÈÝØ"q džôQ±ª'ð5p¾Wà¾'ÅvC´qX�(*üųO¦‚üÁ.jòä6„Û]&œ,=¦ï¹Ô®Å v0©z�|à(ÁœLuÚ µ�W’8“·´)™ºoj‚X#µ¦CºñœþÔxâØ~�¼ø= îhD¢ƒC/ª}.ÇãΦèØla‘ŠÐ÷(›yù-”]¹ð }qé":ù�Å›ñ£F�ÿÆ–ÆÌÂ4]]ÌU™‹/ÍâPVÆ;Á°­�-ÂA4¢75/× Þ6þBnž"ñù·ÈÍИ׶ÊÜ“ =p½?(²WfÑî=>`–¼úmâTL¬FépªdyÓ\�íÄûä åÑx\³ò8¸µn “ŸÐG5àKÌÈsnÄ7¡ñÕ,�Øm–*prYTª!oŽ,Áû÷ÕFX®žIÎ'RÑ,aR¹Í_IfõMÈtÛ/",PÀD†½V‚ÃÑ�kÍ£K†î’ýó^±J¢æðxO!¬Ë±oʼu”T� Òýuu¸>.»ßQO®ñ/ƒÌ…”~z àñ#®[λòÏ�ªŠpï¨?dN£þmæº_P¹a0üÙ(|éoíçM÷ƒù¹ã£}8A�DÂÕÅ‘xÂ[ŽÎG"¹T•|º¶4}ÏÀÄg+<¿ÕY5[ôðF×_Sˆn¸%Ö ‚MU�M�ãÉà÷Þ–ÆÜ Â,Û š±h.oÿ€×}îÔXœŒë¾'Aÿbü®9ÞŸ!7r3šÞ]FVM Ãîy!×/Eï¢Jv&zÎLb›= AOc)siöLîÑÊIÎâ…QÄ,x/vNÑÄÔæ&dl1<5yÅJ5ñë±è›3jÉõSO%A˜6Usu±¶øõ*»D–f/§3Ý´K¯ ®U‹ã·¦Øw-”ùÏ Ö Ù‘ûwk±èþ;41Ü GϨ“àÄ8ûâÜçü–ZH¯€ôõ& úÓjËRXÉ’"²|ü ]x×P~( YSžßàsÌ}œFïÐjs6Nðˆv~F“fÛœ¬ØEJ*“Àñ§0ú=5ƒàh H÷Ñbe�л³Ò°DNû*¢Ä’Q1pìÏiXñ‹N$såÚáø÷£ ôÕ‹kÈlÖ˜žÐo¥Î©hÎ,‚U]º¶”&ò3ÃBtu®2|u³Áüî`x-|ö'û�†n%†¬÷/¨Ñ¹HD²$yÝ»ä¹Nª‘Øçð j›f~6ƒ¶+f0ÿ²)«ÖS… sò[x½Rý›H—#èÄ�Ã/¸»/”>–’Ãã*�™™+ÇZaiõhÓ¸½4†vHÁ¡”Yrã}Ô*Ë­¿:F6OZ‚ù†< ó`×x3û¡Pœ›³½‡·D¿.zÓP—�ÛìX¾ëSàâ¶QJÆ›aYrù¶d�|†ž8óó,4UæÎn>ÍÞ ï"«rî¿Às¥âð" qÁ™H<(L¦,šÍ ’}€½KcàI�›mÚŽWC“·§ÀÖ§G°yv5Z�ÁnÕãF;¤g¼.©eµ°Hý798™«çóf:Ü!ŸÌfp_Ø. 6®±Mî+zè¦Í± ßá�Wîíf¥ –âØßëtC[“~·’sš=[JCż}xL´çn„‘¨ô�Ó}Lj4¹�3„páP)6»/m6²µûPjå.ÿ îgSî®׊צZ•ô¹×V8h/|çl&Â�R¼ŠÜ•P¡Ï?Èsv¼›-î^¸iÞÐÓ3À á|ð‹/"ÓE�[Ë`Sôž¶å ÿÚiœ]�4¦ÊÍLþÈ҂φ¼ûßänA IÓhÆU‡®Ñ+äÌ|#÷™ë"¾€iµóŸïz˜ÛÛ‚*»tyze–(!¨GxëɬºÃèoüŽy¿—½é>~�x»ÿÚÞ³ó[è/�*:¯Ü„®w;‰¾¯oÐúgèuî ­¼n s=T uvÙ…'pÏÄ7Æ|½gŸ90Ù-�°yJ}8‘D»“ÈMï…0/ÂËq {í"(ÍФ?Ö;£Ïõ‹°Ï° ‰1zÂ�x}QŽt]&ïÿ¹¬¸Ñ5ô<ü�po†‹%Ðç6Ÿiˆþ|4ÁÒNW#o]HlûMÞ^�aÉ yÑÞa4拺¼½ ™MqdñRà?ú�\^QF¿¬‡åBӸ眧ïÎíÇßóé\ƒ2ü£¥�:[þÐå¯\‰ö#Ev›çŦi}”>·PA“+àÙšZ"'v*gý‡[¼áÑK²¡^½_&û7e�Ï€†îr�È¥·ºÜ¿O4H£ž~Jùc;pÚº§$¯P�{Ùrlå‡Ò7Z0gòÕå–÷ßKÄä0�ÓJï­±,™ûØjžÅâ–)¯ˆÿte`UF9J6sฉØ®õ§qßrHŸm ºxKr£âßÁû¶5ø¶©Žx.š õ¾WaÿYi\>m3 ‰¼a{NPŸÀ…ØŸ/Åû]n½$X»GÖŠ¿cV_åA{Ø9¥wµ½!öGÓaé¾3äÞ‘d¦XÅÌæV>OÀEœœâCþ4òXä=ÞD0~аã9\€Å»ÞÑ„¨x"/úšž™µ‰Í~Ô�̤×nG¡’/‡ ‹Íà鹺€„Èax³m-þgȃ?Û‘û9¸¿m!ëèä�†wÕh×Óâôí Ìq™ÎÓ÷’!i3Bö’T´7®Áï_Vûz+u± æDO’¥o’ocIê`”ÏbÒŒ%èÔÀ�“TeÖꢳ±!Ü?ÍOy´€Âß¼ãû‹©î| vÉ50³ñÄ¢üú÷>ÔJżùu¸¼4"ç} e}rè©Ø†]ÛkáFt0¾|SŽ¢Cò´„éÌe¾X½‡]7Á´o~r؆Ú[§q�~jÄì4~òåÚrAÞ Œ¥AÕ<�üp�ÇùlHR¸E%ƶ5Ý8®�Ï/½…ªr{, ydø†÷yО3ªÀó}{ ‘VÅúá¾ùÒ¨åWLîÔð`ïÒÃ×Èaã:ÞßÉdnxLWÆ8‹Ð‡tE;Ceèl%\óQ‰ë#ÙM•$)ü,¾Üà�Åâ"8ß7�×zN¼Rp­¾É™2FƒªÉ S>áÖ�›Ö¾»MªZ— Rª}ÍfhŒÓÕ7EÁ57�zµ‰òÞŸÚO¾ýBy¯T4ðjûF’Æ�©,wh; æR¥ë9hÖ}Ï5‹�Uükè¹K˜QY*pC>^p€"wè›ÇO~ßì Ïåÿ�%ëÉ­mÖ 9o3_Lÿ ìFùûÓy“¯ªP$ô8.­%©iÚx<Žb•‡=çuøf�¡ï�ë üqn…e4íkÜ�+E÷£ˆaküÀrÄj–ár[ÅIlÄ4—71©À›Ô?Ùv2MUÍd›ø(˜0Fáþ\|j†cålåÛÛÄ,¹•~ Lǘš:)VCËgÚ(¾ål-m†‡Gí°û�1ÕZæzõÁäáÓNÉÊ@ì±ç‚É‘8d7tSÖÑ�ÈáÌXÔó`PVn w�Ì!Ò·ÓWmáÇZN*î0P£vÚtõ¥N ]¹šöZ=™žÕÀ�} ¿7â­¼¶;t߈Jt£Â(·Ëlï6лJÐ<ÁNðÚA÷e1 s=Ð> o éc¸C&̤ &µ¸‰tѧ>ö~øqu\E¦è†�2ò4uÒ D¦�¯@&¸d¬�EvŸ�i0Åõ›s©ûù�¸Ø¶žêßlwÞüýŠl³Ç­=Àü\Û»£bE$µl�¡«ÌOâ…×ñðÃ'¸R“(_ÀÁw{é3_)¬,YAW´ÿþ�¼2dž¤¨q�¯M!²Rÿ\‘3*ÑjÝ b»Â7yºÀøµ|8t+�‰jDY«iÄxÃ^Ø-¤ S5Óð½Ä(òë¥&1rôZ˜/›§‡‘kø åp;.L…-OÛɲ_¡x²¿{œ Èó «´ºe/Õ³‹Â+EòûX:¨%*o¼xæ L­À.YJ†6Ò¹ÖY¬^•8è=¾IoëºÓñãÑ(¥ƒf×ðžïið)®§§Yo–coºþ*¼±OˆºIDkš@¦]/ê�¶2º¯>âf&œõ{]ÃaÌ6ÃIËÏtüoYp¯Šnú5 æ Ið6¹Ý¦ó xxé‡=j=è ^(ÐÑ)SÑ´£¸ëspálÊfz·³ÛGEy‹ïÕÐna5(Ôg6Æz'Å�@È/j§,Ê­YpŸ1h¡_iã—áqúºQߥ�ùÓ IÎ>Uz#·‡ú¾…\ÕXQ�‚lŸ6Wöf)y³õ.Ü+RkÞã]»4|%»ÒÅÎc—€):Ï‘Ã×1‹¡ºÿqÃnÇóœ9l$ܯÖ$O/)r_* óZBdxâó6AC~ž0ûK²âX‘T ¬z(d†Ä@Ñ5RqÃäÌfŠ]©„�­•ÍG#= :/}rñÐF;Ì8›Œ RÏ0IdÜzû×äÁ²†CÄü„>þ²Ì¡sž7ÛJô‘¼O#9p/r-†³ÄÈä6<¿Š2ÅÓˆÁ)ankÞôçf£µ£ˆIMAƒ;ˆVƒ¨¹ŽËÆCÐÀf‚üý‘�¹�‰‡Ô7Á¬å.pK2ŒîÍ¢¦±¶8.|—÷¡®¨*yà4‰óEÛpT:¹å¬¯…¹¶ —“íÙ;è­šÜk ù�?ãÔ­¼ µzÕȤ7Ð+05:ã9�äS÷(â×þ2–ˆ2‘ Ò8 k¶àüQS4�³ƒ®ö2õ[&™u›#à˧:P/ƒi?V°>ÃGg7¸¡§ôïŽ Âg‚2$<³˜˜þXÀÑëeQðOxƒföFì“9Hž~YÃ1ùA&+¯–i�^Æ™î ÀÜ~‹Ê�‰ÂúTæ\òêä.Ä ­k§~«×õDFã)Ü>Ø@>j5ãcÏ&M— ûL½)Ã�iÌ¢Û|8t雯7‡Ü€¿± üæÀlñ'xµ4¥:–ýöŒLûÀnÉûAŽvüã€Z,Ûbûå¿À‡rQ:GUºÖ7£âºy̧ˆfø®x…„F•š¼Å·�zjÇ£bç"¢>�{«NÙ•ç�Ïk‚Û1@3ÒÛ9‹š®â¶Py˜=º…·™DÏ ÔÛ¶DKæg°Ý ïcë¦Rjìe ÷ËC½š6xŪ¬­‚»î¸÷lȆՀ¥fã.ã­�ÞJn[¿ÃvAArÙA J«v±êÕšöUb�[>åÜžFïl§û}/±—gLI#0#ë2%xŠ'z`åàõåì„¢ž™¸}íØ+¶ þ“Žƒwóà^K7ÉqÏÆ¾ê�o«D¿î¥øÊ¯ ¼ÍRY£CtÝ ]ò^·L¸tïõ[tçòÈü×ó#¶R0]y �"ÌA] ‰¼¼á�§eƒ v|¨¾¦«pþë”ÂoF$Ó� ÷ñÑ5þùÌÅuH'}àØ‘NÜÙ“Ž²1tðGê¿O�µ2hwë%µßGÖLu£Bw*ÉÑœr²Êl6:ž/g…¯:“»1øÕ1™J#Œ×D!�ÍM;.¢Ý' nÄÍbú½ž�>VûÈZ§x‘�Ã)�¯‚gåð¼�I_ïÂ6vŠ£à©sè=îEÿå`–l<1bãáÅuKx—†ªŠ>M5î˜ÿ¥…9fò†�›™Û{hBX!8~Å¥yÞ�¹C�5b±D_Ÿ>5W£�LÕ•Yh;Õ5âÄðYv ÈõKB®¿tcÈgx´~Hb�uS¿¶NïJb¾òÂþþT*£ùwÏ!‰ÚÃÌ‚rY^��8¤÷êquÖ•#ß«Çô‚8?ïOV {çÙvrÄÕç�î…Ÿægð�m4<2²%]­O‰(wô?¢KùáXN $OÇäøD<ú ò_Q�‹Šax¹pK~6“¨ˆB��CʯGÂï=Óðï±~–s”„—­ÀëÖ7Åî°ÆoD¨´ÇIXzÆ~'[ó´j�@é˜t÷4Ò¡ü¿¸+%+ÓÚX‡Ý‰ø0i&qJ”� ¸ò–ŠmôÁªï xÕ!-bùaZÏqt YMF¼ÿÒ+¯RH£˜w“|µ#^ñÙBìm¾á\î3òÂÜ…[Añ¾<8›`Àl;»²¾)Á„ìl×@Áæ©\ùÐL†È9:ÁÜÅ—'áËb$k%©¸E"~ªØ‰'Nò�r¡<í^ˆ‡%Eÿñäb^ü�Dø66µÓ0,׊f}FĦ6’ŸmÕÄÿl 6(úÉ¢Õ¦Ïr?"›Åܬ7ƆY�X¶ü,)ëçád¦"îQœ�ÿý`ÇìÃûš“xBS¡iUˆ;žáû×ç4ê_?Ìã¾ó~sn/F ‹)§ýœlg•‡ÞâËu&§y¯R»âó°íQ8\1ÊÇ¡>ÞÑ=A°vJ嫎Å)…=ø¤|2l .ZOHh¡$q¸¹ëkÈó×h7‹Þ9`üŠ5¸2/€6^þΞøê‹»jÁ×i”Ùª_HK“eÁ¤ê+\,t'ìGÈëÓÙôj:L› Ý w‹0‚çÝ®ÑyŽßaÆžgØ®Ö Gz{¨Ñx ÝëTG^XU’‹ëÏã®àÝØº¨�ô²,\j�C—¸OÄPu:ÏÀT½;Dí°OLž‡‚röx"Ì’y.RN&ùãf…xìœmMÛ'3poÖnzòÅZŸ)‘Ç’©Ë¡çL3ÿ[*>öîÛî¥A×üé¤Éª~¯…ÖGŒ‚µÊT˜wrFÿÂŽ%©ðŸá à(ó ô÷A>þ õtLà.ç+èåHÓsn2M‰+ ¨ I£k7nø”DŽæ%À®Ío'3“•9{÷¬¦ëf¹�á ²j×¼ŸÌÅä…Á¨Ö÷‚ËËÈ>ê¼JuÂ>ã��\¼ßµ€ÉêÉAgVDáÊÕø£¼z'%À`°†9qm=tÙ;àôWóaWm=T$î€ÍõÌNñzp™éN/>œ�¡!äuQ"Ù÷KJ' yÙ=iÁñˆ9œ�|7¸ž?É´Õ=4æ¨&M„üHqž¹ÁKlûÖ>¸ Ú~E‘ˆ�_A‘„²Ç�£éÙJGt‘‘B¿OX}£ÚÃÍéßÚ¸Ov>œ¿§ÿÑ•�»�‰°ãínœ¢<�k˜ÏøbßjC°"øýRìµz‰×bèI@gæ/œöG:ì¿0u3öÓXË2â¦Q “RÒxöÁsNT¾8ù&ì ÇÆЕUÆûßó›6´˜³Iý¾Ä¼þä%6¯Ù‚‘@¸3K Öš‹@ÕÉ r·? O�­Cò<;þ³xÈ( úzgâÏ¡l*…Nl% …Lp†ìK¦:ò*©SSG¿ì:\’U£{ãJˆä`=ŘÐç”Á é@šÊYMÒ‡æ`Øk¶[,J¬æCŽô=lÔO§Ÿƒ¢ß9 �ngÞDæ²òJ¶Øìø çK°ØÝZK¶‘«�Æ´Òß- ÁLW Š… I[¡+v8>¤n*Dá›5[ž”‚ß•úéñq¬NïÄS7Jð•dªhiÑÉ¿<=�YøÕÕÆÍè½=ÇÑØ2ܾLÅKã—áý.}”<=ˆ­³êp‡_­Ú6�²nid…Í!(.Ìg…¬ŠéÊpIî>ÝãØs�zæV‚劳•@»ñB`¯|§—~ð0®Uw|’Ç}Ë\èÆ{ 0öîq0wJX�Õ`<å!=4ô’èt½"ÃFƳIÓùÁ¬·–Ú“„Éã躺ög}„)ðAIj53ÜØMzÞž£ë–ßæ!2öíí�ôbþ[÷ W Ø qƒ«ï•or|îeú‘§÷Ïoô@§< ×zô’ÝVÓ¹{îšÂˆ=Òª s2.˜€#õßèp¯zþ*Ccõk(áé!© Ð#3Û¹% ÙÿpìÏÁêrInÞZ5x¡âL»)ä—C43#{<–~]�'DoÂYÛµ8®%ˆ’WHDTMÿº óóWb÷Ý ¸|•ä?ÆÃ'œh÷ÈØ9èÑgVÉôaŒÎžÆqâ 7 f'ÉàÌÖ\uqnùq�ìî€ B©è3]¢û®Cå‰=ß* O3ˆÇh#[w7™Þ5|HEZ…¸“¶Z`ðô)οsË”Gص¡‚ #-rüð¶_dcHFè2á6 ¿¨%°µLQ…Êé=¥Ÿ–û¡ËÉ�TLWT·ƒßƒý°Ço1/+;ƒ¬¬ê‡“å±LÇÉFƦ±“lèí$“Ñá°Ë  •Þiò Ÿá¼\X"t„Ö&f1ê¹wè¤r pDcaÌ; =Siæ~9^¥ÓMšË»Lƒ§ðŽ)TcEð\ Ÿ›�n.Oé€ë&ªìAé‚ã éF2ñxºè-}ö™…VÅ‚±Ì(Æžä¶é‚úó÷é—´^à—þÉN‹ Ñ ²�$ Uë“hÆZ_Úº^‡g·Bì\̇%Íxá€4wƼ§À=1B¤¸ÉD÷Ó-jcWÎtÙ\CÓÎ.&£Œ–Ç}æ�ûz ³p@gÑ•¸1¦÷B+F�\ !œ çE(o…{êø²î6ÀÓÿˆòðR’í#J^¯zÅ/6&Xt ~üÅÅš¯2TX�V„•ÑËÿÅÐ)NÂpvf(<Ò††Îbjá˜G¾…Û᥂"ˆ¥�ÞW5=Þ×Câ`7Ó®w4£Ã`f[ 6æM™åˉìõÜ'¡,¬Js�S{ÄY57ó¦´‘P¡3 ?ѵ¿?-5‡®»yä~™=1~XÈ\®ß oõ+a4ø'vg†cÖ*Qƶð;�¿Â —ò|hÀòl¹·ÖÚ/…Ç�øèèkR®r�žŸŠ•™dVÔy´5Ø·ßY ¤ÇŸ;�OM£Ñgÿ}1oŒÒD3I×­Ñl”>¹Š.·®Àá•öìªÆ ’ýd;•mLÀ“OÜ Òë,Ž>œó–k €Å(9jí·j€ä3�bµÓR\A¹Ý 8‡;pì{2ST…ƒs³ay÷-”´çÍæyÞ†_º��o»�Ü·ZM¹|~„;D€o¿0ok˜×’Ã�ªëö°em(*$Âã_aÀKQåÆXŽ�±»:¤ÿÙ'\w» B5ë›®'àÅ28= AkkQL!�ޏV�Ù‹�õã¦�UpwU0Ö‘pà©9®Ÿÿ¢ñÌ~”ª9Š7ÿìÂ9*O¨Ç.~˜=g}P rÜOôg²& jËמbrYð¤Ü/ƒdHŽ—äIñgÍÅicùdeSœ‘­‚ÌÉ`¨S:€¹Nm$QIúU�zdçÑ]ßGˆï¡{8Qxí³?T!]è98Æ…’D‡ë052DÏ×£ãè.býð8ý�ý€ìüÔA÷u‡¥Â�¨xÑ‚ßE³ÆéÅtõ‹›¬¤B*îX×CG&Ðç×6H”zÇì‘1ç¶R¸°/š^ŒÁ“Î;Á{i5d´»rÍFvQõ��$q�2®;¸~—¤cò…çô›d8TþóÒÿ¦ú¡Û·¹Ðzç"¼X¤ ú{Ÿ1;®‡RWÑ`8”|¥½†¨ãÏ L¾É�÷,*Ѷs�Ø-,DEÑ»¤Dè9ѵvD×ÏˉpV |LO¢f2(Þn�ý:— ðœá�WÁÀ| ^W®#eÇ*Òdû•‘ÎZ‡J÷c‰Ma �u»ŽJß×�áÍH=÷�cΑ ÙV¶dz š8 íÈMpV¬�¬—Áâý\ðOÕ¤ƒª²ðþŒ Ü9pî�­þ©¬/ãDË6ø€ÁËXœšªJν< 'ç©bU€.+V E3æ&0É»”x+�'aÝÃÏpØE›“ý0`w=Í‹î �î›�×Y‚ÍjQä{H dÍöiÒl|Åî1Ëÿ6°{ÍXjöÓ¦iòiJ°Qa”¬)šÇž¢ûá-NA(nƒ|õ}(0Ó•îÒ+«”zØþ|œüöަÁ¸ðã}¨=Kmž­¡äRš–=ØŠYw&Žô8�A%œ²3=Í�È|Š-.‘�¿+‹V9#¿ô&úC&暊ALõ÷åhå 2C³?“9®àü9Û¡¿±C*àv“z/‹ŸèutùB2Zü©Z]9Ù,€ßNÛS‰¼[Û½ ‘ߣ�fn8×ÕBÝ3 X^›�¬O ñ;âfp@�OµÓèB¼û´¾ %Ó™÷Å0BÜøg¢y" –ÞÓ “%± QæK<÷gÃÍMØË5Å„5óð�¸0ÚËi�~9ÞOGE,ߘ ßâ¹+�Q·Xs æ^ZY€M±'Q·!ÏÐ¥ÅI¬p¸ ·–côœßãï³ ðËÝ!ÜÃg RE ÝÀÚ|៭C¶H;½0ƒœ®¼´cxÐ٧ϧ²‹ó¨™¼9Z©(€¶t0\ß13Ž,;ƒýiɤmÎ Ô�E—·’…é˰RX >4|n²‰;GRÊExâZÆØÂgD×\ÀܨTtîõÀ]±G¨è¥'ô�m& ˜åïuyo× bæÅ 4l¡šu=ÌùeÃxÈ„G&±FL¯Ü2€: Wµ{-ÙtÅŸpBq˜*CFI7ÞäYÃŒ°¿ø°×ý»/#\Ø=8vM‘8enÅ™ü¸ùÒ|h¨ë£¾K à‘j>��ôÇE‡C ëK,ê]¯Ãš?A¸ôœïéô!,›œÎûýe%ëêP|Ö#VzÏ?Þ9†—›Ðü�yëõ�…‡¶íôq_ø“(¯f;ÃBÕ›´\²Õ zh³¦³6`ô-¦“=FDé×:wÑ¢$‰$¹�âG˜äÌÄõs*…ò¯|ìÌ·X�«²`cà>ZTm7]£éäNúzÿ)¼Ýù‚™•H×x�hörü#§KyJ¸É$ÜýAZt*ÏéU^ú—«|Ÿ²HT’Ù¬~›=ÞÐDýoÇÀžµ<òâËr¸[¹�W!€‹’�ÜßüvµtΣb*€cÆpd«5mã¬!ÛúFh¬ê uúš�‰?9k®3Á%roœ…{O•£oÚ¢ÈîGþî¼o°=-óhNì! )-M§¯ñqKµl Z]š =áq<ºc}¸-œIŽvË"È2jÁK³ÒáŠy!Ž®ÁqµXÜøK€÷wC¾Ô¤ELPç…™,^ÎO@«M'¤Ñ®éˆA~Ax®þ !†û°Bžu†à#%7’L2´ t_,]ÜC»Öt“(c²q»ÙYSò Oc'†ÜëÀì ø°"ƒ\È7`Ο� U`fÎ*HËp${¬òkÛƒ8RðóùQÏÚî¾Éµê04è�…×:`†ÊgŽÇM.w¸z -̘–Åy&ÊÇ¡ë}DŽÈQë9´åÃE²Cš‡*#q« 3Ùw0ŽïòD«äÐá1zÊXÏèݸ"Љ·5h S ¢FVÕ(ÀÛ?¥˜¹3uÊbñà6>º–½{}aÀê¸-0…éœ!‡ÊÏÈ¿§Á‘O‚«6ó -yà‡¯ÿñ¼9CiÅÞïxÐZ†Ž&ü‡Ï@ fMNå†tzÀs­º-¬®(ö`ð™kÌüË‹@Íþî-òæõbðzhO}ÏjB>è¡çÅvæAé{òíLùió”>Ö®ÄCýûˆÒšcèç÷ ç°Rq­ºp±Rž†�—HY¡>: ]ÄS!éègì�kÏeQAÅ~zýü¬Y¥ŠRïåyí>5Ô(湡,…OÇ8Ïõ÷ [í Úvðè¤0·ï<é–>ÆI» 2´æ?|/®F B.Á…3É©Ù!¸æÉNúôýZX|`ã"ÁO–ëóP‡•òüB¦ËzÂmK'^\Çu4ç2¶î&K®ðQ—Ô[dGv&ýTÔ�z¶…¬˜k#�=šM½ë!ùösöÖØ±2î|.†ÿþŒ ÑÆnv®{*¨Ä�—)§É©Hmö¥²:\q½I.ˆ¹@“f hÖÓ‰ÀéܪzOˆ1jc+Kb@s�gº g\pFÊçŽÇ–¥B8� ï_c­^íoû†{�#hó+ªûø“bp`¦"-1Ú‰ÖŸtñ'?Aãß·©tÃE°1¹Ý¤¶iœÆÝôF«3‰ 7`LûD´¡sY,¾´Ç^üÁ¨O©f—³ÑD2">¶`cI ´ÖF1Ÿbƒ0âo&‡æá"3ø:<ÌL÷5cšë²Ï¢ÞyÓç4sc2ü°y�gåfÀè#ø\@”÷$OtLá)Sæ ¹}5íóK€:šÍ�¶r�›Á›Ýw@B~9.›ÅÀ Í¡W»»qÇ“s`ß8‹ß6Ãÿ<§ãåg© Vâe.5äæ93Xš B#ì‰^Þ'zXä\ p„YÍ’äsývjlu’u�Â[^œËý1CèG{o?9.µÿ\첤‚0÷ ež ä×¢J¨9ŒæªÃOú[ܼß*°âí©à¨§ËUýåÀx–?Äcwø¸ÎC Ôî^2¨‘#lIáBP[Æ´0ó°iM,cp"†üW¾ÄTÃpc„1ä¶�¤|ï‹ ö§ ^öʤªob¡ôQ„×”áCGK¬::ˆÉð–ù©?¿ºâñÜIÞÝ˵ìþ`Œn6Çøk²ÈY(I®'/ãßÿgbÞ6E¥Œþÿ»ŽV3!Tdùyê›Ûˆþh=½ry>L}G~ç®ÆÔXaxìéƒßžÐáøŽ.d`SÍS:«¬¾N¯¢¾ÃÔfÙ²ud€>òÕÄûmF¸Ì4ï™p/}‹‚gl ìJˆÃ¨oï5«eôÕ #bAߓЕ×AÎÓç>(¥�*ñÂýåìÙ— x}º2ì×ÿ-SxCë£QM гoU%ù\„ëžpØ-K”AÆ. ìîn$ÁÒàÕ.F”{4±ðR8ÖïÇLß‹ l‡›š©Åþµ¸DؘN‰þÀü‚$m'àõžÙTÞMB`¸äΜ§ƒþnj¸6¶–™.Å­c¢Æ#*êø�ÉÄäIÐ.5lå䳄K(vò=FXÇa³c´��Q‡H¦%ýzÌ·bß)RZ2k´1nO/Þw¼@]*Âó?6¡Ä&.ûtu¤PCnÅLEĘ:È¿j +,Ñré_bVõ³ªC9këÔ Ñ;¦3•q¦0 ¸]#"&É‚e•�ïȃ_WR°­·•'Ï�fæÛû…¼Ð½M:¿Æ‚ó 6‘¦ózR¨^e<¹ÞO=PäöïÀ)òŸˆã¡é¼�º=è"Y a7‹ÐEb3­1%ôëÏ“¨0všþÍí…{ÇÛáŽYt˜Ï"žZûQ®[”W+dž¾ïéëú9ðÐF·ÎK†Ì`Ox“ô‚TD½£[/j-‡Äúκá�3Äÿ<ŠëÒ.‚K�cSÑ·:hHüA�~^€ë*`«G ¬&`ô3�ü”7æùß/>Ñ~qÅË®ÑÍ�`Ƽ:¸t$þÛµ¿«YIlÇ ~^W¥—'Á¹j\ù’ÊüU%Š 8–ÐnêZ‰äêþï`oBŸÃ1üÖøÝT�USÁN'óG”L?Ìáà©æK02r›êG�’Ù3†›†¯jÀÄe”�›}ÿÜn¢Õß–‘�º»¨…t:¥3ÛÖ[’¹~Á˜“zŸsÔÁñÖ|Y í×ÝÁõjÑßzÒŸlÄ•#°è›/©Î<‰�Z ç‚"+üQ¬ÞÝ¥BÍN0ÿw7 iC6(uRµËR˜oµŸ<Œm¦‡[´ÒRÓÏßÎåè;ç®Ë†¬3ÐeælPØ-—ºÃ�KäQÀö›î ¸Å7BnþˆÆ¡‡Ñå¯à¿‡�EõEÔâã—jÜ<…ƒæ›maC›Ì¿xïeV³-Mx Ê‰†í»Jµß¦ Å[té¢}Ø‘f 3‚îƒÐ»qzð§/n:@Ð.3™ú¦ÊеߤѤ0 68,ãn•|J"÷“Ío+8w%QÏ8mö¦Ôlîã]×ÙD �ÜnIßS:^�Í��¨¤ÙuöíŽÛ$(5¦®CÑ#kÀ53‹^ïµÀk}R uÿ60uéÊkôã}<Ø;¶¥BíòÓø:ï-ñÍô‚MÎäFd4*9ùãÅðB:iŒ¯–�þ_ª¤MÅs³г:åB{‰Ò¼ *Õ¯MmKT9zGÚÁù£ ˆ]/¤S·†#Ýh\@Õ{Ty“‘]d_k2ðžö‚«uù;£�qz Rfl³Np“׿-°Ñ‘Bɵ´õ¹žöI 9Õ\”÷7Æ(§Ì."‹opP ³#µfâQ~îÄÄüÞeJU«³ðEÚÅ&ïm4õA=93¯‹n@ŸI*Û ÌÏUÿy çËý@ý˜hòw{0s¾×÷�—Dî©)(Ò«H,u1ÑÆŸ¾ÌúÌÌÜ+ŠW¡MÈ3ü¹f6nÿò�î:›ÉÉp{ªßš¨|p<ÈßòÃô-ü¼SæžÙD¥w…¡÷’@(Á pSB|¨5ø®_g?GЗ§iAÂUb€Q“1tã,[ƒþ›‚ãÈ£¤é°a"†ºQ g}ºÒ… §ŸÆ²»éÔœ³ÄQ"ÖïG¢Å­Â–ýj ½¬‹]ÿx<éãâ·}b¼c‰‡‰Ïî«d×¼ ºÎÝäLÂÁÆ£€¬¶^‰íš¯~{e¦Èü*kyCŸt�eîa{òRJ‰. [û~á–Q|£� ±ç>±’[ÍÈÝÓâØ®=ƒ;~Y ·‡¬Àr÷V<G÷ ðŠƒež­Ý_�3x½q mMyOªÇÄ©$ëF”·_ Ö�YÐÌ}H7ú~b¦‡MÓ}ñ|‡ +ëØL?�8KãÅîг‘^�Ë�]÷MP½VÓolÝ_f°%½ãk !òÇIäLK„;Sô0¥K–ÖW©SÉB(É?eªéÉ!‹…%Y™�›ŒÞ`7äÞRÄÈ'¯¿’=|5m±2fÞïñç£$‘3Ý„÷‚[f6Ò�yx{{Þ?µ€ÙssÁ&i9±8\NÖ°üÆÐ‘ÑŒ& .ô^DoˆCèƒ÷49°újÞPS¡%˜:U*ÓÿuˆV(©ØŠÛ»çÀ�d†¼ÐÃxéúîF?{fúN8|ô Ž«6âm§JÌ™±•L¢wA~–$¬É�À×ð1w ‹´I€áQŒé ÒB+q�Wñaˆë†°ÕúŽx5¹…™‘3�˜”&ámït ªú- i[b2|˜ú‘~ÚÙ@=µSˆEK5]§õ ~ͧŸ@NM³·Z[À£7[ŠØÅ`ÎU9î°àN¨Ž ƒKY” …)u#pÌpîr­# |¡h¬õ‚n'É…A`ñѺ_´À¬hEÎI¯ËpdÛp û—6D6&Žœ—„%–ݬfK'5lÃ$%wJ6 ÓKIÄÚó1«Ë�ŠVÒ¼Õ*B¨™˜FwïÍ!­ÕÑxðŽÕòPÆs&°Ó7žØÁÒêI²Ú>Šá?ÙŒ»õ1cï~“ 9 Lx¾�ÆÞTÝ»+Ø9IgQÖ4Ö >À^�ˆ�@zä 鯴ģsÂ!ekt[xÃbÛ,ü´îFPvõÁݼ…¶‚�Û} lð†¯¥ÏðÌmMòì�õ¶È¤q®ŠÜÎîJ² 7ºkFØa�»x»á<žÏWÆ‚ETüwø�¹AVéZ¼T–“¯ãûd“Û–[á@â†×ç ‹Sï3 3Ãáš„§ßóõI|Iþx#mÓñ³l¾œÎ£wã1Å�?9HÂ…©!TØÖ ¯‹¼¤}WSa­ÕMÖtîQÌ«· .ó‰ò>uLu/…ÐŽüW‹>}  “¶�@W�/fiäÐÓ{ñƒkñ Ãð¨0ò¹ë#‰’×À€nuø±%—žŒGQÛ\NEx Õ‘< ÁJ›É©Ø\½öîßJœŒ%xíIs‰Ñµl¹q• 7À„|)æ¬9…ò8<�ŠŒ� е٨Æ'ĆºaZc¸oÿKu鲯3ѯ‹‚@úú|H%ÿ£Ð¼£zþþ8^ÑÞ4¤aT´Þ÷õ);¡ˆdT¤ ©|KSƒ¦¨´¤E!Ñî}_- ¡Œ²J)-#";¿~ÿÝ¿î¹ç¼^Ïñ8ç^H�!�ÇJ!L0oŒ �Â0MS³x:ç» |9žÝO«¢Ã p}™güJŠÂÅzYœ¼ç‡»_¤ƒƒG“ÅUå2$¿ÝàÔ®é\_9I�ýÅàQï¼fØÎTMÌãØ¾ã˜ê_¬Û¸—¥ï©Åö5h(¯¶’ ôÂvGªŸ <€çíN¢Ã`,Hb÷wžÄD^OˆŸ+OþŽîÅ 8×—×ÓÛì–„#˜Z�{Ôšb)ÿWëˆ×ñq<;ö.$ž'òß¾Ñy9ä0=‹ýS~Éîè¢Þ39)í‹Ø¶¿b\ͼmd—~J Þ®ko<Ì~S Gý%íú å–«r: –À‘ÉÇÌðËIº´ö1\ H™|Ew|�" .þ"V÷2?ªçÁHž[e7X#�ÕDʹÜÝîgÀ7COM±øžâÓ(˜?Z o7 Ó¢˜-ÂÙ¹CæØ€½<×á­P'¹ë[†¡»ã0õÉ ˜èªA%¡Uøó%—6�À<~¬Ö, wDà©î-à·.6t™àS~#Èý�Bœ�=§Hrê2‹/“°_|Ôèy ³ä� �ãÏé§·±dã STt§Éß;ÁVíÓ–¢M£„2h;• ZÖfTg` _ºœÒå ä€y"”�݆ãÚòpNâ=Úç¶S«–uPašA]ïnÀjñfeöÈœ‚7R"xÔ§„–Ì\9�ÊxâÝÍÚªÀu8½ò s»Òª­¦ÚŽ[€v‡§ß„1ôF¨Ï¾OfÞï¥cÉšÈßÜFÜÂçcwt© ,¤õóÓÐøu6ˆ+”�Pû @~²>VŸõ}eGß'�¥Z·i2ñÃgšã((]GEŠsTnPÊŸ_D¶_X‡çß‚gNItúÔ<6¿’@Sãd,_¨J_KÈqžz™Â÷]×p¯o+I{«�Ev1}»UU¨nmpW]¦¸#¼L�ƽ=�›½°¼RûØÖ*m\é ~ó½Øôkú &·oåüÄ‘ê{äDç1zzv5lþf~C×Há«­ÔíJ5‘ôƒe³Ö‚ÈÖ+hSŸ‚röyŒ©hÒƒgÉ¿2Kú&> ßJG7ÁhxÒAº5&!z­×óo/¥¿Ž•Ô®½¬ K"¯BÏ5rKɆ8>�'Ý"ºòÇè}¬Ê=»Á 2À~UË£ºd2öêÄS¥õ¹h½c:—3´‚öLã�™�‹ãÀY¤‹f~�§>$ãIcò+ýý›VN#Ãê¡É¿¶H¡Ã¶S{âIlëpIæaº«`4û/)Ÿ(8òˆÖé4ÀoÉL0ÛPD㼪i‰0/t¹ä£ü O:Ǧ ~ráóÐ< G¬^ß!?Ì“QǨ’<�34^mÔ¨ç³.¿*(GÊŒâÕHÔº|�Êh s½,<•RF¦ì>‡<¸é$]U¦‹“ë‹�å¯#“çÙßµ»É<�1ü¸}ýî²±û#ÀÊV>~ðD6ô¦KˆÜüA‚ßuLi¤š,›Y÷\b>~kÀåSœZ=t ßÜ«%s‚¿cƒþiXæ½’òÀä8%©‹1÷Û.²`Í[|tp6«È�[é‰ïrn‚@íG0èqA:ö™�žªç~ö¼ûJÖTÝ«!)ÊÕVAýÛ|¸´(€(XYÀÎ�|lìaî>–ʬÚ@2»·cw~ñ·¼H·‹1®#~ïºå‘me†0úå´ü²£ûˆ2®Ô‘äºïh#áû¸='–XÝY¶Å!è}õ>Èn’áž#†Yñ"°Ú³�¾ÍŽÄÊÅX@ä/†àœQnôšb*“É¥^—Ù_gjáf�ý¾É˜»¹bêJÂ÷Ê÷‹‹ð$ŸÛM§‡Æ“þÍ t¹³>ª2ì�­8ój=aGÓë�fpï‰äš¼Ì’×WgábL"Êœ7A‡í8íÒ$ü>ÃÁïæ`©´ó.ã)_>ºø¬0˜$[²ÓÔØgjH£Ï@ÙG9r´w™ÙTïÂÚµP©»€„zt0Ö›I”ñ'Ú˜ß O>õ€òé0æÜ¶e ¯€$숨ÂîŸqY‹&GȽÓÞ…§µ–€Q€wž@0ùË\Åâ‘sŒ�C mð„Uq^�O´´5É„´._‹çjœIˆÁ‘) ú¾—.Ê“¤.͉°K¸²ez˜…çLÐ7c;¤ôÐþ��´!ùæåöKw€Ç†{7ÅÖmÒäŽÌCRuÜœxáÕ‰ \áL¯Õ2dã"{~t~ÐD›‹SÞ¾ –D4â¥ï“!X{e¸gB ]A¼‹å±ñ¤7ø¾—âšù:ÒWd+õ¤¡h¥â ÁÖ’´cÕY&xE>Ð�~‹ÿ±_þ#ñÿ:H†1Î4w%n»¹*§´~>Ì0ê&ÊoJp6W‰œ5Ša×*ÏçÎ[SNKç˳ߪS¨±V:¦|;F{ ÍñXèQ‹ƒÆWiãº\º-W’{Aý #Z5 …½QlßözØÞºˆ{Žç3ýò±÷HÈâ7¿] lò�0î?ˆÊ•Û¤·~/;>›&HZO»ïž>HÛ«c§×ûèªìŽë'Fmçéx/?:•äCd» ­šýÙbYg=ÚÏSà*òGÒ·ý�41QwÔ`ŃCñòlP?“OãˆËx%±™?I´BL‘÷AñHQVá56œ|[Rn"ßáýP¶s‚ÖK…Ò¤yÜQ»¥ø^¡œYðßlœét†±]¨c“Ù/'Áí%²œèÝ%˜©Ê¥K뢪ÇB�£‚Ì«³ÁÉÑëÅ�™›*·øÃ¸\½/Åâ̆Pjp÷&9kó“.n½ �Û–¡þÉP<`ÏN“f¼õ õ�|ÿ’m•®f†²õ¡DÀ_ /#œcJDIw.”]1#«' è X,Í¥à ²ýÞzç½í®Ô�Û)ß!ðÌY´3’�ÆëùX~í!UÙ:Õ”�~MÝ‚gBz(óÆ_[‰"ïB~î‹õ‹°+Ɉ&ö€�Ö:km!Æÿf€b¨7짆û#¡´lët#Zߓ酘ÃpCä [5‹³Â2«‹¨·L~Î]C"ˆ’Ù5X>¾ ,K@ÃÜ(dôúq¦8×ñ>ÁO?øA¡ý)F ‡ÑÊUb°v�8ïðf»3 Áú3æ¥Ñ¿+!¦.š¶Ÿ”F  Hñ–å&¾v$ž�*€ÆžEñK¨åŸVèÛG©”„ ¬]¦HÊŸÁ†bK8øBþ8MåM×(Øù0•iŽøþþbØ’;uƒèîõøè^‘¾1�säw5~ùp {W�¤ãÃ�£iMþ%ØN�ÅРFŠ#×;WY– <í<ø@pæÕ„c˜±7èæé‚à[–—Py ø“á£n/Ñîë6?³×xûã>OÐY[H{N~!ûÞº2³m†ð¶ý ©yN$¶œƒ›¶+àUu#tZõ¢uQùˆ!_¨Â^¸/�ÁGBi¸ðJ¸®Ç<»—BF�¿’×£Zð>=šuï΄+‡÷Á#ù*º;z*ÌØ†C–‹éÇÍõ´|“˜>·¡ÊŠÙуp8÷4ß²_yöѵ>(ô²Ÿ!)â ÷`Ü™|kÈʼnéç¼XhÚSŠ •pöötî÷ËÌ3󢺊�w$ðUz�æMUÈäª1eÆ©xÇZšÓ.�ë·£Z•Wa©¶D'Ю'× év<Ѻ,`æTü—6, aÜ ™u‹‘¨ó@Yw¢³©’[ZAÌ65-Ö1²ë$aIÔ|¨1űêtF_캟�þ#t×ßø-&Æð”söÜØ Ÿ‰à àp4:3òoÑE�‚8¢ø ëdcÑè]9¦ŸÁ$?PB �rkÅv˜+G’D¹ªÃÉ8òê ®Þ*ÂQzu~*HÀͰ4oÉ¡š®%ôÏNrWËL×Áø¨R—ÏäÁ†H2¼n>®¾{—$ÌâEs»yôyK3ÙXâ #¿óPÛdì{ì�3™MtK22]®žŒ_†×åbæ�½ðçÙV°ÿwš Š£ÑùläºL ©ñý´¸ ” çfâsG üšô…»ÆÌ|Œ¿-ÆhkÄ~ÊzÍfvÏŒ#Äà‰]! ¢ÄÂmÔ�&!©IìOYN¡ª,n¸3ÅP “Aq_.ÞHÙ®/ ”ß‚7§ª£Ñ¶> +û Ls „ÛjéÒw~9;– ¡—6ª!ùy“‰ÓÍE—�¿dl…Ýl@pÓ±ëĵÎ÷;=�ŽÉÛÄìi¬IpƒÈK¦X/±˜;ïW8:a©o5ØMñq‰J¼ÐˆÇ-cýÈÝ4D²Ü¤¹s§­s#¦»…“+‡ÏÐæ×œ-åGñǦ×dh�$jµE‚ˆž<'Ú-†¼8ÖŒc‹ÀBè*©þö„ÙàrÇÜB@~c$\@ÛøõXçPCÄö¦ƒÄ¿ìø`Â=ðÅ‘Üþ΋þÙgQ”o?òþ†ÂŒèås×¼ ]ç;HÕqŽ×ËìÒ&i.o×�èÜå«a A¾V¨Âœ‰,tzSI�/S¯w‡Ø[q+ð«‚–ù�§c:nY?�¼ZKg¹j`ýðAj&mGŽ/¯…#Âo@HÈÜE9²ÿ Ãÿ q_0Jº­°,PœÃ¥áàrÁÿ¼MÞ¤ŸÅ·ãòÓJŸD6°¼%üðmçTmúIÓ¼E�/¿z#«C‹M´÷Š4we˜!Ü«j s܃ØÔÝiP4˜…Gjöchfò,×�é-—ÉôÕ38›ûNâ&']öºíE˜ñ/ÔîaQC"�JÕÅß®ý»¡ÚÕœ¹©²ôö Y´V>ËðÅóp:"M1['�øx†bš³"†ŽÿfÛþùã›íË©cÑ4ì?lÅeÈ Ø½v‚½)aJöj®n Qþ5H ^½ÄÈ䜵�âÅ‘m�²«—ö\‚v%1†¡38Ùþ…tôV6O›�›yç=x9â» YÍ{1d¯ép]ŸXÉŸó‰ÍäôÝ:n£€«‹É¦£Þ´�JÀ—S#Ы+G&>|&5³CqÍœx&–RqërpI]Õö³h¤ÞgV¨ÉŒ.�âBãQÌ^n‚e>WðI Ø5‚”«JÜãeL§O<Ö{Haîi>LÝìM#¶‡Û†v0ûñ\;Ô 3”- ª"Ô¢æpuKGÙøÜ3øÙõ4½3Çþ<Œ!U 9¸¥W›Ù˜ó³ö~`’ÜÕN“Åvêz£¾Æ7*`G·ñ�Ã-â šæêð£¨:Ç–b–ß*‰Áñ5¿©ÌæsÔU¹ØB£t'×p‘5$©­†£—a…EáËv´dËRìÝÚ .Û®aÏêól¢œ6÷ëÚ-¸uì,¨Ú­á8?’�cß0z°ƒ¾™£çýfÔínùBÉÌôèß>ª1#{ªËzáñ{�¡&]Ÿóo¯0g÷wºë§#ÑáPú1Üu®k⣦H (#¯­bÁúW-hhà­íèóW�kæ�Bƒ‚…0>_ŠS¨Fï<°ùñ�ºÕBÌfáäFOØ–iÂäOFÐm›žÕ†É"‰îÇ(îxϹÓFÁÞ±ØFø°öÉÚpø¥…¼´3ò5NC‰c?àøòj$v…h}kyñp9¡Õ±kD�pu ¿Pºa Žè°hè¤L’ƒf“£I`Ö{�Ñçê¯W£œIŽÝÌNO‰Ü}Šé°È~ø ƒBEâ`é)Š7¤˜öÍTäX"ä[ªqD¯û3·2èÉ,_|êÒIEx¨²þðß>NOÞÛDZM–àææf¬«UFù/aøï».Ç!Ò‹ìlpƒ¢Xh›öø—oÇ \Ðò�¬ÿÙ��7ˆÛ‘z,Ü"HgœŽCžCþôô€: ʆg—΃µ�B±lñTöÆÒºYp8öV* �Oî„…`¸:ü'„ÖZÐñ}7†Ïo`n÷T CÁ)Èw€@½CÈ;=_*¨C­Å.6Ù-Ø0q»ÛÆ|ºu*†ž‘#ÿæb¨úq⑤ÎÞÏa– wÖóf4XnDýÚÛ§rn9ÈjÃŽ@_¼“zG%SiŽ­œwûHÜýwÛ,uÙ<Õ¥h»4ÛJVqªE3› W`¦¨¸ÁcìèŠCÏ}5¨öêœØ™MëóÖÐÕ3¥¸É54s¯·Å~§ô�ë32·î5nO“‰rTÚó ZÒX¼[÷Žžš.ƒ­FD{¤ƪ>á“ã=pç ƒš'2¨ÉÝ÷tðÉJ”Q*aM>ï…剋!3´€)}ßNƒ³¿�/ó<™ñãÐ3­—.”;LÇÍiù¤?}øH‡í8r‡]Îû z½*©ºS{£¨®Xj�Û÷£„ý�]þ6NfaxÍ :©©ƒîoáÆ@$õª�ÃÎØ·ä×Òzvi=éW? Š“ÿÀ9X®ëLÐ;ÕsñnŒ-�փ酩´#©F®‘ ßm¸J¬26#<äWò»ÚC&“ƒ×PéÏKF;~‚é¿GNÇð“1ÕtfM•ü”W°(ãRn¹àÈö§¨¹ÏÚÆ@Qª3ÊÛˆ‚ýÀ ”r¶¸­›Œ1ÎÆ(°î xj_§ Sñ ûNfãßÞ0ºØL/&¥ó�0ñðU앲Æ& 5|#–IÞÃoÉuíH�@©¿À÷S/Y±Mù’ûɯrB¯_%žÆ£8wØ|•=Øœ�@KŒ˜‘r�JJn¤A'ç’d9Ý¿œƒZèŽÆÓ ÃÑÐÙ=P–Ö…;Ü›Qx)5þ+@¢�„q1fv¡ð¯&‘%ÃVpíyð¿Å¿§/’´�¯ñññ¢){‹º†t‘Ò³Çñ@¥®ßu�/Ž@áŠa²=:TוA³²QpÕº‹$q�dúG“Ñ-‰¸PÕU�] s/@Dûf|zþ}¼<d䓺út�u; Ü}Îl}£ío4؉gþ¸Ðw){Û[3·‚”Í2ürg¸,”ä°:ô„s'¼ˆÄ6�_$¡(šp¬>‘Uz|ÀìÙŒûw‡Qo£Ô¬HKÚƒçsа´/�ŠŸh!²‡äñädY1„ŽŸ& Cã)Õ=}×â¿ Š›#�ÐÓ*›sN@Û’§¤òÍ`kïÒסâÜß²œC¼™d¦{Øû.ãþ¹ºªÆªÅ·71+uU�Eïr…fØÒ†ÄD’ÐW[W“oŠ“W]èÞ�ÊÏcUßÄÑå�™™Ì޾^M~çjqÎõÂ�ÏKð |�¸ûäfï<¬pžÎ}8õê%z¹LXÈ4Rj¢.[x8:W;A?]ßÂv5÷Ü–pZÔý‰qÞ%÷=ÛðZ¢µ‚¶¨`±^óô]t�¾c–êÞfV‘b¸)±�d.A¼E «t€kGZ¦Ó Û>)ã²Á"ÒuŽMùö“Μ sˆ1»g5¡ò7q®ZD„ï¡ò�©JXÕ˜Á íXÒΘ΋‡-›ò¡ÐÆ ­jÀ -u·Õ3åMÕT�Nç*Y„ãÏ«að;C‰èå~%ƒwÈr(ǬözÙ…n[}/ÀþB?Ó> Dß>$i áÓ~wá4�X{J—FÀÙ�ý¨|œ=ÍöÁú‡ÊàÚ9¼�XÅ=W–Ã2¿ÉÛUkðp%/×á}®Ú:§=å…éM_¨”CM¿ƒ·ÿã£qv»pZð5vUܸxƒ©Û×DÞ²vŒ}x%[ô£˜®z׈‹šÖ2;¯x£ÏÊAŒrm$óf)b±÷]’þøšûtÕMû°éÊ>Ú53©îëf^ލ›:¤åÐËÂy´Å-ZõV#�?÷ÿÿ#ýš…8§§;Ã~Á ¾]¸M8m"'1rÈ߇n…['ÒÐ�[É8ýÚïcAä‡$W_4†õò¹ŒÔ:n(aä«vRê¢ÁÉê|…ÌûUhúßeX™B¡Ž˜æSßO${îvŒk´ƒeëVà‹¬¯ôªþìùù”<+¨fÖç5a£�-x~}I¾E¬`^TåmöÈÿ®‰ÑM UÔ>&‚ŒïÓâj<¹‹_å{™m+Ÿa[2�Õ¹_iÊõÛЗäÏlfÀ†à›xûAúÏàöŒ[qSzÓ°,ï+/4 cj‘ÔG]pábÔ8EÂ÷ÔAÕ£¸Ãlœ=ÖFÛO¢L*VÏ» ¯MT©±é"¸s ܬºqÁ§qÆ«¬ì í5±2(OˆAbqŠÜÿzŽÖOeVI´<á• &Ží÷`÷ j]¶€n—ˆ¡ž{÷cÙµbô7+Äc…±hãŸtÝ÷·”.X ¯:J!;è&Yí¶‡õ+ˆo¨VÝÎ%§I¯º4�ûšQ*¨ .ñÂ/�(úãÞZ<½(žÆ`(ü V%.^ïjÃøOŸãë`ˆ8Áh]¢¦3ª)Š’q-Ëe†+Èü9Ãì3Î<Î÷ê&zò[ iÚ®ÿÜéœÐ80›bQù›­TY¥=›JQ?BRºá�Ù1ªWŠ`c›-—:Š%ôÉ™û0þ¤Ý�®HºM6áôS.KSK“èYö<ñj(¤hÞÚ½J¢rgÙ«Æ,YÊ9‚‚³¡iÕQ5Ø€e†¸ÁgU~fwd�Jû^ܰ$µGʱ‘?ßIwÏœä¿� ¦ÝJê­rè^÷6Ä Ñm!ôYDö_=Ž•÷ðôhVâK¹+8<ÞEºbëèû-½¤&µiŠ].ÒËCÜ﹨À·SÌ/úåó(ñù2êšm�i¿ü-k9ÁAE8ë|*æåªu‚~†?„¿ŸÆ,¶ÀC§´á~‰4Z<ªÂ�’§Hå,)(œb/k¢ú¢Öõ°ß¼UQlû9\,ÆšhE‘ÑYTõ±VÔ¿§‹«ð´ü”÷}�@´» !Ñ iT 󤸒•²€¯&±°Xôû¿1�M‹¸"�QÌ×ða數öd%R9ö&„ì ‡¿Š5aÆéÀ\6£CvcãÒÍôÒ·Abó· èsKšËù£æ¥ Àó3¹õ<5u!?‹iö©ûä�‹CìÃóÀ�Iš|„5|¯’냒ë;aBb%ð‹%}¯½`ôÙ3Æþ€"lR‚¼;›É‰•òø°é!Ùñ+ ƒz1G%¾ÞZĺO¬Ãéyç)¯ù{øã,Á-Ö-b3•Ž¢M‡Y>ÍŒ½e›gá:ó0»¶Ú–Dërþ3ºCÚÞÁ7wÓðíXH]gŠ)6Ì?Cmå¢ßçe˜~þ$v™I»zt�$ Å,|ÈÀˆ8-�È¡ñ•™Ð-¦„Û‚ŸÒ ^O€g<Æ4Q‘û¯ˆø&i˜ðl¤Yí'Àï[6Xži Ú_ ë„8²Ì|ã(LLijc,š’Áá›]³§ƒÄä’¸ù2÷O!ä¿„1ªo#Ò©÷çûÔÙ³–döÇÃ={uX8+‚þ$c|„'ˆ.½ �›î[ü¨ŸÎ5Їÿ÷:sp¹mT�ï§Ì¹€ï1&~O$Kx"éÞ²túÕa³Ê%‘Ñ VNÍìjÀu¥Ð “ ^*té stð¡œØV6½°“EŸQé)^�?yÒã¯ÃŸË!ô)˜v_¸‚‹Ÿ5³ƒÍºtéÊ J¿‡g«ã¹Ž _¬ÎyµX$jžÀ4+Yú}¦'Œ"y£¾Sy‚ÍÍ|Àî]A ³Ÿ±´a­•pÉh,ˆÆn^e ˜LC�Þ« rΟdüHD ÙÇg$I&¸þMˆ‘nÒ+`A¢Nq¨ýßsh;Å¹× ÿ£�®cta�# ¼î¤~¼ßaûȼá\FcÏ|äO”%çñ*ØÞÏ‚:sÖì\*ik[ƒÃ& è}øë•Ñ‹³DLÑ.˜iƒÜì2TØ·†úÈ®æÚ<‚æãÕ´lR™#§²½Ít@†çÝá@©ÜßÂs- ‹”¼ð�NKÝ‘–<ºê/çÌÑFú@WŒÞ¾ô ­Š•¸_ú2Y…—y4€ç<Ä_t¥5Üfý#W-øN mÛÍ{ÅB!þc—ü•‡OákàÔÓÿˆ¨R>Ü=æCâ<êØÕmúÀÙ— ášÓ±’‘äêI‡¢"ïjH¸íˆÕ‚µ4ÒN ÌÜx9ˆRžz56U¾­vd8œ¾©òÇ\qŒ.£Uî�xje‘‹Ne"kè¦ ;Ð,O.Ï6×Ô§4û¿0<²—õ‘¸E ó ífìÇ1Y 05¦?®RzkµÜi ùÁ× e¡dÝ„àJhú|�Î+-@y«ƒX嘎b/ÞãÔ=Q››Üù…Èæ´² æÊ$b4,üÔ!ý—wˉP(aFç¡Ýd§åwRÔ‚�îáÝ„lÐÉÂÄS»Ø�83ø™“D Q_[2x|3Î v‘õsQ"HÊ”¡È}9°< ‡Rp{öÞ¿PÌ8sfV>Tù¨‚r5× Àõ3¹C×ØÏ†é•K°cê}•Çó‘S©7+uÙ�ûÔñ­e…õuôúÛüÔ·.vWÿFrÿ›ú6HõÐnTz±×Ýv''4ßb¹Âʺø*GHÝ�ˆ^hþI�ûQöŠ+œÛ†›^§Mž0bÖ³ˆò­hŒ™›N-ï¤:º‘Ô¾é#¼4 24MéItÃݙѰ}Ó âeŽ.c,TŸ2DÅÓ-pÙ.Ôè‚|è«çJÎ7¢4ý…%wÒv­L:ÿHDþ­¨›ØÂ…�:û@Ïú&púÅðÓcî¢ô]¸tõöì¯n"é˜Ní³î³®?FqÈ¢oϽMÿUÎdæè–àz5 Œ’xGõWãs…Jø®xN´«Ãhz=ºõ&¢ºð‹P®., ÙIÇ꘥¦§ˆdê#ú¥ÑMõÐÀ’ÅÔîZÊTwZç–úÓO·â|NNp#ûXDÓžGÁ^‡¯8_l1˜–þfß¼ÎBÉuWpÍ1+xTc“Áh=+ ê¦ô‰‚MñÁCXÍåUÉ$¬õ¬Øu OYOÐCéë`Rø”÷>#3wn„Ôü T®�)™{p‡ÄipªÏ£3ã¤!½ì•Ñ{�êÔFJõ›¶cÅÞ‹ì†Æ"¼Òt•ÚÓdûnx ÚÆPêþ8#’dðá�éŒ �ÈXª<¦e¿Ãt›}Äöë ­wº„ ÖæTgÆ|:ß¾ëMÔ¹Æ1±´¯f·“£¦OÉùÀsôuG ¾^J?- WTf“Ïa"0aºäÍåX[&ß/ç0U�‹i ïóÐã›[ƒ¢å ÐS&_mÇI¾«!Ùu÷¯ù�ÖbhÅF8™ZJu-gÁñ†˜=S/«üb, M¹¹<œ,}s×õªÜ=ª�x?r/,Û°'F÷C/lF1÷çäï_=ÜÜšLœærùTŒiP7ì¬Ï&÷¢ˆŒv®ê¡ÜE­x=ý.ÌËC�sj ÓÆÃõþ~žµ.†m7JIty lÖÀÇÓ–áWmì¸&E…+/ÀÖù“0px'¬2XŠf³¥`~ëQÔm‰ÆYpÓ=b;ûà{k¬Ö2ÇUƒ¯,’mæáK;Ô«l$†ß}˜ÿ:›™•C á˜lˆð&ÑmN×(g÷ƒÊ„áÑ ZÜ#~âÜ%íhP^ˆÅ ®2ü·©¿^(Ñ{>—2© ':ÉÁsÝÕ`Z[µ»Ð¶ü áTT#·ÿ ™Mƒž=;á†ï.ÜŸ ‡LNÕñ5GA‰y5üÌœEKoœ¥ñ¨“݉ÊÎ’ž;_È*ápœëÈ‹Ò]²(¸sò„ÈˈZŒµÄ· ¿É:7/lJ.ÞiIÔ¡Ð îîSd=þØà§š µP´} I(¡­Å¼rCxÃSOEw¾ÀµL:ùj2Kf‡0k]ø¹æaãLÈ«R´ªº p¯„.àç4Sâ "¬Ô�>tžbJ%Õ`–óŽ´¨‚Á´5°‚ÿ lð™�X¨õûù�v©p¾¿Ç{÷ËÀqÓrÈb Å’¥8]3KØsÓQxk"É;UÁ6ˇ#ó(UN§á+µÇèEŽBÿØtt༑¿špÏ:«ŽIBÃ?\+º•=0tú­`[?[€¢WxS!š$(CØ äŒýe�…Qu<„3}6À\cIîÉáófg¹¢ø€< üâ6RéüˤúÌ=Ó>�ÎK(#�bïYóahèñûñAzÏ[r*‘ÒßXHÚ4ËìÖLq‚ŠuG㎖zò­¶‚®ÿÕ�GŸäÓeCs ýx¶HÓE«CðDØsÚg…QsÝ'r^ÿå×OƒÎ‡gëû«rú‚â ]é$Î0~�GÓí-òšÁ8æ0}Ùû�À¿ð›Èz{Å/â?*c¡çƒ÷¯…òKk þC&þI‡…†V ›5Íx£5!x6~q—-¦F} {ä5òL;NŽÎ¹N}Þ.§Ç+a\}+Ó"ÆE«a9|k7ŠB‡Q3!’¾¸ÞKø»—Â`h.ñ^…h�UÈ£™…«t%à×n ® çåY²›Úß´ï×m4¾€Òä5.ØÀËݵ§’äÌüE†Õ÷±‹ Ñ=ë?Pe¸÷³1î,=?HžjMq[3ªÁiDr{)ί ¡æ®á˜b^ˆ²¾€k_l"ûvo„=÷Yìª�N7=»±Ö"œÂ‚ëø›¿ ê*#0o[:û/â~½õ vdý#¼œþ†L"7s Ÿ»Š;Ï”¢Œv#]®½‹jñÜ$ÑŠÎè<ûz 2ìžu�|)À‹k ûõ|lNãáÔ™ó’ÄwçQ¡Õý¿‡ÃP°X#4ŒøÌ(¿õÈä±Bs¸Ë…ùa)¦0ù_Saþ’*Æ?(F/_$k#Œ©Ð�0ôOù·†5²ýÔRk?Ú÷ä2ÏŽ,aß-f_X‰p‡y5èû¾A[2WJãéÊPM®¾a<|PËG3…y¸p¤ oï��ÀþTZŒÓ¯Ï¦ã»×Wèäó·$‘é€=9°Âé™Å‘² ý÷ð5SY¹Õ�´Q‡ÉÔ=Q ¦ V[0,ÁÃ"ß½%ÙBX'ø’¨L^‡áç‘4Gá-1K"œ•½0í¨2Ï¥!±J�ó¦ð")Nˆ„ ‘‘À;לÆUÁýöÍÀ{ÿäÄŠsÝt¢Éi¿,Tu%'ŠÎѹÕÃäRÄRZü‘ ‰|G, Ï£‡s< �¯!K/— OŠ îÏ{â¯1î™ ¢Ö&Ò&ùm÷€qT.×±b6‚§3Z�üâ&|6>‚òu8ðV&­Ÿ0³Û­™ÐéK°Å¸ dkáÀ…(ö—bj´>ƒà›­ôaÂg"²v˜žœ• J¦ñX_ÕG>íY'/üp¢ ö”CÉýòéS Nv{áEÙ7ôµŸ L[Ä%Ù§ÁjÉeè1<ö»Œô`lÇv¯é[òѶˆÌ(ÇDiMH¾ºˆ;Om;Ý,¹·ÌC«¶ z~E8ù¶æòìÀï…—à„”>waŽ6nZuL|ŒhöÇ ölS1æTŸ˜ò®tl9ó´6e�OÆÁ¨ÿFF?¤“®²œQïQ¶«XƒjYóq2j¸ä—â8›F.’÷lCÛ:˜¿¶ L{šÉÇ—§iï–Cìô§‘4öâJ�5¸� ¡¿Ñcÿs"qa&& ¹Á�h¼øÍ¦,#–çG‰Q–)~ô}NM+,p×é.øó_¹•‰¦íÖ`�_€WÃÖ�X)rÍÁ·[ý0ªÛ Në4Qïfl¹hÂé|ÿcÉ ­—'ÔYƒtܤ+ö0¶¨�< gE2·ŽÇÁl6 ëBÈ mxrð3ýDNµ„7xŲ›»ä‘»ù(»`Éè,È"«Y0¸~Sû¹´ÅåD5°§o§Àò7]v2Ú^"3R‘wPŒc§È..N`Ÿ±*ªó0Ç šð¿Æhã[¬gù,,Ø9K„Aò¦¦\- F •8tÜm<}ÈÈX K¤W�·ez_ƒ§þ�¥a uxyg�yH=A¼ût®7‡Äᑉƒ4­�¥»|³�§8í5KéÛc0f‹´T»ƒPã›^OãR­Çmâ–¡"rMžØµ¹ ~ó+#Ã5@wŒ“Å8Ús^˜¯«S!°MS–[!P ’g–sGû³Ñ ®e‹Ë,ÚFÓ]‡#q}c=;/g„…`œº.÷ì5¸³„._rB-câû#’PYÏl„:j·´'Â!±&21,ŠÓ`ôP Ú¬5¹"òd+û¥�——}£êx¨ý4Ap›QD‰étpÉ…!‰õ ® @,/3ȯ|óež_·DÄî=óÈõœw<—߯­2²óµJ$£Ò’>Ϲ?FJŠMÒT •†–È&d•™-+[žs2R)+Ù¢¥½‹’äç÷÷ó¼ž×yιîëºÞÿœŸ$)1™œÞQ¢ÁŽ�³ÀÇ ?Y¤ãw0V˜ƒS_�[ß3`¥s ¾2ÜH ë¦r¯ÂºÁÈ–uBÞk¸d6…(Å,fó<Ò±ÓZš4<5À¬½¡`~ÔšYpðiPo'Æ;qP%–DoÓ'þk`�öfRX-Ç3‹&<—(Äž ƒe-ÕLæŒ ´ÙîJ´ÎƒÑ¹âà3Ós'êpÓÛ0¤žAô¼Ë P|¼¼¥� ÿ+„o×âäÙ‹TªK•›ÐY¯ˆ‘W•# ñsñð‹3MèÚºó˜úc˜­øÝ–¾™˜$Ä]k�8{g „³¼$/yHø©À÷­eãßEaµo,\ñ¾F–'Ѧ_¶ø¯{àphom»¡o´àÞ{Ê×E\\îRy‰›d Bíã[0ðÎ Ø4Výª˜ö­ÿNC üÉzeÿA¶<‚NÞQ¨ ‚Ù±ÉäþÑgÌ/]´é›�_yb07ÞŠ¿Î¢·lU`s&%,x²2ÂðD¼•ÌóúBK׋W§ßòþ�°Tu%—1óÍ­*vC7[)>òáqt¶˜&&s zyæOê5ùï±#hà†ÝÅp;OŠÞ”¶ƒ yª@u¼Ñ)Ô¸A�PØŸ‡'j—`ÄÙ:,×ù‡·漩o&÷F·Éú€Õo¿2ïŒp"f¾�ÒxQž¨áKLEX†ßOòõ*C#=ÙÙB!öyÍ:¢‚Ž;^Ózó|ŒÛ´/§+TOy=¥Öy€qµÙ¯a~f¡Õ«;…1ñ²0v¾-Ǭáu܆·ß™b…í(só1ü[3ÍW'ƒòå4È�ÆùöZŒÆÃ%žÕ ’'/ã�i1Þ$S½|èª\ÍÔâAÇm pçðØ$®†3s‚jÖ8y©ÚAfLvî )pðµyf6Ž{lãA+Q¸q_ôö-Ÿ BlBñr(Z°£ºÖµ†ý›¿…6:à„‡)XNœ$6²ðîýy&ý]5óy¬–¥³†àƒc£áŠ <~ ¹48“µr¦Ž'?¿�-œ”Ö«-ßQ×b1|ïÞ ÏæÅCa  ¯µ¦ƒI[A~׆áƒ0ûjßȱiÕì—Æ§¤åH­Xò˜ìuøv…ã•tuœmr *ž)V_¤³áÊp {;±‹ˆ? *–BÛ¾ \—”HýãÌ!àL):©§Â•ÑOtÏžä¯7E^Ý1à÷\‚Ó+kñÏ` ¬Ðã~üC[·Æ’îS¡žn‚s÷Öâ4!CÞ/‰28¡Éµ¸Mv”,#^ÉŠ˜çÂÇ�NoàóدäïÌb¬qÓãzràì²yà9ÜŽìfÝm=ñ@ÄY|û®æTi0¢å±dtX ÎΗà™[ß§ž‘»YùÿÖ'¬„4ÔFâ’Z%®öÝXRy˜Û£Ë}a? †Þy¤NÒ™è6M�Qâ¡,Î+רüï΂׶ÌÓüí\VÁtý„Eo’ÑEß,ÖÛи;Ûh‚~ TvûâÇñÎ�xÒêu GaÏ:þi€œpÑä¹é‡ÊâÇ̼ô.Ü¿â»r{œê,&?¯…«ÂB\³’Ù(‘{™„.ïG—ÁY¼¬¡‡Õ ÖÞæ0‡wGÆ­—Ÿ|î‚=넹W=ëÏy-n;Ù LÌJ2}ÕTÖ.Nš˜xú#¯ ‡^ѽŽ6ùîxõ¸ ã{±œ( )@s¹žµùÆ,Ì@� _É…H÷¼võïól‰ˆq»²*ð´ß­#r—NÀ#¿õÐÖœ�^NÉPú2®Ínbsôžàã¿ù¸xT JLQb…=cå°!ê¦H¯€[sp³ñ?Â=g�Çõvâ¦×ràdîÅœ´^œDÓ¤«“XÂãȱ»‹Žã²Út˜ùJAPV‡Ì…}qì~΀“?¾Âɲ‡t”õO~ì�—"¼“ ºÐ˜Ù‚ÿ•+ÓÔÌ`2º@Æã?ìù´€y»Ó†)]ö*4'~“ʧQp)0™Yc„ ޽›ôÒbx8?$š»A¸lVæ �ĸçô0“NÛ$%qDñ,4.ï¢wWäCï¹7T4üq=Iè[œsA,m“aÉÖ ºPЖ®’Adìcù[;ðH9O‡ËÈü-èY=H_(eÀs9$áú6à¿d¾ðŒ‡‡�ý0²î)½üý#ž ‚‚ˆÍìÒoÓÐ3Á¶5-ÆÊÀeøàl •ެ"§¥“©ÔVc¼|áú »Ë}ö¡Õ/*ví<-N…í·kȽ0<­i€ö�®ØžŠ[|hvÜ7°é¯&Ç‹øñ¢áf”z$Èu¼Y‚O8¾x.C�¤™Zâ°ÂòvÌ…rìþLf¡¾ xM¼ä}¡[MÎW c¥ª:迎GÛ¡Üsˆ>Y­7¯bãí.ê¼ê-Y«ÄÇMrî'Š®á袇Q9�馠…Ü]yô×óvØôM†{‡�Á}çóHóã÷à ¼Šh¨¤R™ìtÒ1e}dׇ²Úû‰ÑÌ£Xß’ nû0ï?÷æ¦2ëWHf.¸ŽRž° ­†l›`ó�§CÇiø(õ¦øt™ŽÍðõ¥·þÀHœj‡Â�űÙä$%¨ƒžuÑ24EÉ*Ü %CIÝOöź>¦×¹„.|Ÿ'd§Ð´¡(2ƒX¹Mf�þÌU|ÉJší#†C+{i?´.�kÌtîúêi<Ž¿†EÓÄFIîïUÐëFˆ˜4ÀÏ]Ž ëP-}ùíY©�!;ÂñÓ¡"TnN ÏVÇã§ÜŸ4bô5vßiWP\ƒÑ÷}À÷Š,û«·ÿFó�Ó³pÛ©|ª?/›ù/3Ί*òìçC]à½F,çTcÌê*¦Ôê p«È…�Ë¡±B^IÆwK˜6ã³h:sæM°éq¿áyüR<,|¦Ó”"(l/Å7‹Ÿ3v±}ð6yDejp$¦ïŸH§5±ñ¸”o¯>œŸûc×mòq>ÇíÍ%¼—¿ öÝE2úe¥ÇQˉȮ vSæéuñ³‡rÂè󼿷 ››Œ wq*nùÜ@´æ± &¹¶gÆAl €7SÒ’üRès“à­^i…sp×Õ&XnXEƒvT&+sš“öáÛ«ix4m9i²­%Ÿkà¯ÂaxÜú“ánÖÁL–pï�¹�i÷¤±fÎÙi M|ÄR'}mW«ÖÇ„‚âÆÕÕyéð`[eõp‚Äï!{•øyîÇñTÎ,ú+Þ˜Õ�‡€Ði¬�þ4^]>KcÙË솢PpÇLrà�.ó2"ŠÜ–Ç»OïÓ¬Ðé~B‰À\Ü÷!•Ö‰ ÐÜ^0Ño#;r/1‡W)ñþ?µú��t�l=Œ^+cÙ¬¥X+W·LøãOéÙ—>pô³tðÉÑ”*9êщ×]ŸGÆ$™n ü¸ŒWoa¢tZpöìÙd‰[1î›ãˆ§¾ÆŠLŠš?†þŽåš§äH\ F•²xéo)ÈûÉrß_ª'¿¬ÞÑBÿ…0î£Ä,Õ8)뙾Ér:rv?H/öf³ÕZ=# j=ó}±±Ÿ<5ÈC¯õÇðV])<)K»¨cÔù¦&¾=&Žn�оpº‹n™CbÜu�G@·Úí»”°•ï îsþƒûŽK‘‡Š3¸>¶†¤ÖŸ`N³ð8á8´gò=ÜË‘;ô�ºXhoÁUú{U½“ˆ´7U„ŽÉ>eª7DÅOštü£n­RÅç»&°„ýæËÆHžz'hßzZôêíôŸIð@  ÿÊþc©Õ‡·øÎì;¹2%g\“#Z®ÍTwþU—ÿvrRikëê`}g½±ÄGFßY!3€ bøé— ^I⦵Ւ¡+h˜åƆ6½&ßtÕàîí•8¦¶—þ欠ïä @z»:gO�WÍ~þ>X ü�°ðP¾3oÁsæ�Ñ5ô$´vÿ&müEðf{2š7:à�älÒ›ʺ-Ï�1‰ôfŽ>HÙ=#Ï#£`Tq*×sêZÿ7ˆ¢c"“¾4„ÏR¶ÐÑTo1ûƒãZú¬`O-LR"uï9hQFoXæ1U‡¹x>L{,GHÆïc j¥À“8³מUC§yRÄÝs,LÁ'osIÕý6ºhìˆçk¢ñG[ç�ùµg8† l\ø\<55¾Š–Ã^Ž?¥ú—q]5SVÅC¾k$s¢à ý–�ÆñУa޽Ô|JŽ¥³žÛRáùÙ83¯^ñœ81›òÐu™9ò¦€’T ÝV&˹8õ&ÝoéCÇB,0MÁ�2Ø1w�:yÆ]^w`½}Ž*5q>5Þ#h¢�{tÈÂí¾(þ�eŒNìÇÌîX9”ŽSãÂ9›+§ðÒÒÙ´é+€¿Ô¬#�¡ó{ª£Y„›OΣÅ_²IZfIûn.«Á¬^‰v×Àˆ½ �‰“†Á…ÏiøÑŒÍ8‰ª³ça£?î Qæþ ©Ãt—jäîD&2²PS~39´;n)BÏ„Sõ÷CZ¨þ1œêzÀ á ¤i¨² 6ãÇÝ~dcL6�òéö$¢ü5„¨û›QÅtر²“’¾àwÙ5ÜYO,!¢S•ôçÀ‰‰)¼<³nôyS Æ{ñSô2f—û&ýî°-Áa›,8\ùÇô1GvF‚ÓË0y®Új!$ïj%ý”�'__'záÑdo¤(n �ø–qú[ûñ¸—�!F×QðÁc¬ãKÆï §ÈYÙ©¼U©‰XñëªÙ$˜¸‰“Ž].�£û/IqC.û‘×ׄèB·2zœÛ W=Öáã¾YàÔ$Æ5µÀßr¸øk oßÄ6ò©ë³;“Ðrº.’é§^�õèðé-Þé>cS®TWÛÊùÑ6¥¤d0E÷NŸsM²¿‘5ÑÒÓ ?È]e M³Á¡k1ÚGû‚øE>œÚ3¢�ŸH×Çd8§TKOQT¾Â¾é™Žçý.Ñm~ Äô×’c¼ÉjÛi ¸étmeú³ná»ÏµôvýQ”™s‰h:œ„6‰(Ô1%7À—ïï« @Eö&¸%}böѵû#é)Ýå(óü:ÙÉ^¿†™„iÃ×ýxC¹‰œ¶XA-ßÉ™w߉û‡mìüoÖÕ&ÖRÜÚ‚`jþH �Bßî0’‚èÄ280.„ל—ãàa|�[ &%}S&F„y¢›–#jŠ7bœe8F·Ÿ[Ù)IŒæÌŸfw(îšOÍì.€ª’(oJü sð{:¸'|&f듨·é]²%d /É3�z·I‚òÙhY7Ù5¦¡¬“$ïk»=ôf¶¹þcO×Áâ5¶h×à‚ÏÇ -ßN'Jé‡â5`¹/›>0 »Þ Ã-²pJ9 –FÊ.h“³ñAtéÍruzŒ>,Çû•CúHF;?,}v¶êÕÃv‹p’k1Ÿ ÎÜŽñsBhµOV—7 Îù>¼¦¦}gzIvÞZö™xý’ª ‰Ià Ô�—΄àÂ÷sé½Â7ðË{ ×­x:è94±÷õÚ©MèLÂÏÔÀÂ*~xeužÊÚ™¡t^f pžÍCé/ñt.Ÿ Qæ§¿­Î‘¬V$L�¬êâlL³gz=å±ÔRW†‚õÁ_>~´ù³! uß'anvØ`½€N}TC¦?'ö3ßÑ¥ÂâD¥u jçNã_ZðþJ]<’ŒË×£àþrj¥¤Loï^ö*ëÀ¸àygMô¢‚0ü³8Ó6aMÏ÷Ô‚w@3�Œ]t@´�œ=ý~¾^ácÖ/õ)®©{ >o„Éé ^˜~% È&X³Ó¢ë‚hõÌð!È–zF!3ÛÃÙ»�©ìx:ºñóÞïºA¨ý2Úÿ]ˆûøN ?ÐGk®‚G€/”| Á‘«Áqp�×ÿIŽdÄ¢‰5ÿ3|³…í¦Ú`Å~Ô1Á¹ýYôvvtõœ£Y´Öÿ> 4ÌFŸ ’hVCÑÌbƒÀSy1Þ–´LtUè`†„‹qέWäUÑQä°î�°Ú™dÝ>D”·ÄöœZxå|žw·¡çK^�Õb¶Dàƒ( Y–ƒsæm©§ ï7ÿrÌÔÚLwß"9O뉿:mÿt-´Æ �Dç›'T)W‡':8t²™‘õ¦Ó$Á¹Õ1²÷+ª+óÆÇÒHàQ>ž­Âeö 9F)^#ù’$¼E¾êKZÝyö=Tµºž,A�”»jlo»Í&T¾À·S¸O{ÁÆã ›´};üŒ>ŒÓg×Qø &é° :Ç’ª¿Ý ö)ÚÐižK²³^1+«MhwñQ(š¦ˆ‚—¿Ð¡&Y8PYƒµE®8«h=hs Ì'ù¬ÑL‹áLß Ò:ÝLk |xt þ)‚ICÑ>h™äKx1 4ÍÄÚ9ÂOÉ¿EVL‚«!·Ý× Œk×±pN Ò™!l{q/ï ¬µ-]¬Ëþ™äsSøb‚£*õUjª‰ôÜw¨‘Má¤xBOÕa¤J=Ö-¸¦iîdäþqð ]ÏçF@�×E¨ÙU�MoÇñóÌÿxCJ*P5Ç-ýeQûp8æï¾ߢþ°–R\?5H@Iÿð¢„3ˆ¸êÀ ; ŬÍ!Åö:yÖö„IÚ—NT4~ã&� 6Bù>_ ɾ–Ðd•Ié33ìüV@ã=IÏɹŽäý°3ÝIgòØÅpO߀7�#o[JiŽÕEÈíHbÖ&AŠ¡5d¼ã#?¾-A+³&xßp½b°:aeKÒ€ÙqÔâú7æ�wÜ:+€zФKþ$š~G‡³óÀW3 w­çsý¤r8Æn]#Ò+`³n»ÖñtºŽÑÆ—X9œ¦’*sØw[µauèCâÞwÏÁ,-HÄGÖ�ì¦v|a#ANÚ60"¥ÃpP«²úµÚLzûa"‰r¾�’Z@5Óq—lv»üMzJÑ F’ncëKtcñ{´¯‚5‚£d¥º9ÖÒÁóY¡°ôóˆÿ�€»þFã~z#¶oòöS›|AÜy\ŒŽYýf_ü’äü“¯‡ó#rÕ¾õ/ðe÷kRic.3‰kÐ LÏ}Ol:�&gð�½<êmÿŠŸþøc›ûòãÂæêA�Ü9G”ÀÝä 8ÄR¶@£šiÝ × Upu„ðM“æ=½#ƒ2Ò‡LïA=#{¸ž´§ÎñC?ýrrs�'f4²ðØsøÐ>¨�á¤Ý&**>TúO dßO¦3Júà×:ðï�¡»|4yÕgéïàpˆ,pÀ‡Ù%8�“Šja·dž…÷äùÔ\’nYŽÆS}ÉÀ` Ê(\LJÒÉX9m2«Ø¿tämý�;16l‚�AM…=xòg«°q1/ôMµˆüyçÁè¯M¢2Œ<®Š]3y¾ðªQ™(Tø�¼ 7`ç¢)LÈî(ªb”rK«ÉåµqØ›› eú÷ð|b>еSÖÛµ’½ìÓ�a"ê¸Öd oÑµŠ„b•½Øæ± ïL; *a5t~�Ûæáu¹ýô»É»y2P²c4%¢@Á-½¸¢à»Á ”åÓñýõvTݾ¿™ÆR¦6Þz¨SÿÏsÉ–kçqÓ�6²0p%Þ]øŽnYëN:x…´kå%zÁtòIÀ\£ ¬ŒœFF Û˜;R' ߸=p9�þÊ#Ü'·™ ÆÐ±äU¼:¤­Åe-�ðóë§y<ô >L›¥¼ ¤ÇGb°õO6Î~›ƒ×‹àj³)úéˆÀæ¢NOªTæxÞéBM[!^‰J ½´=å_&áÁ°ë4ø&râs¦BAàzØ\t ‰Ç:T.;ÎÉÐ fç\QŽ(×Jö6¬ä?ŽéÈó÷‰q/�Sƒ2´³£�däσÚ\ò±z ºÇñ ƒÅß|q|Ó|ôŒ!…ÊðrÅ ÐvDµUQäfi0ÖʼnAÑSÐ‘Ž ÿŠq¼d.�:ò;†Ÿ4¡_m"`šÛwN¼{ ɘçÂÆÆ„Ár×ctöƒ ¬H$Šïž+ÿmÀó¸D›Èe´Ù4§<À[éT;½fePýS+`È¿êw2k+šiÂúÞj3)˜ïw\¾Ý#C%h}. Læã’i>(óX{Ýf‘è‘ øê› —¢ÃüŠäî"YàÈn+É ¡�⦓»»V½ÄmþCømô,�,E»ü\ø(’ü\ó�”¬†Ão4 ä‹Q?@bf3µ3Π—c/!1zú�6ÃN[Óˆ.ï¬T #mêKÿ®+Âí홤ûK§4¨CÂ_mäï›7bÏÑK“ÕEÉc;Ž _„$÷ûW�ûÅH8sõÈÌA�u?ðÚ½Pj"äÉÇ]É%‰s$Õh„^�ÔÀ. %ìÿ¡ !àj�W5ÒaünYú"®þ ›dm vuC/¥ãY ##€§m6šRQ<鞊BÑêøA¥ %ßœ"�þë„U±¹Ø;?‚3�ýÒ¥ ¤>$ÈQ�I^1X‰Ä­‰øÃÓ¤ïŅ݃Œ¹„-XŒqî]Có¢÷b§Â~ÐÚ}�î¾]m5 ³N­gÿ“óÇÝoÐÜw�Õ9á Ïω£Œ‘(-6Â�‹à¥“"–šòPm(—÷_Á3ŽûÐâw<ÖœX.ñp"Á´ÂŽ@Ê¥¯d�¤78|æãýü"�òjÓé’ÕiŒñh"+áˆÇLY|4e,û‘C¸e8“d>+'ÑW©gÃRòý§-N‰6€Ÿ�öè²mê–ÝÂoÇuIç¨ØiÊ£þgdÊVãßá**Ò”GÛ%£0Ã`*ºÿ($ZÎ7iìe?|üs�ô¶ZââªXøž2é±7zIùùÉižLñ‹6Eù� åf—s#1ûAíç¸!7HZ­þá³·§öŒ˜¯ö»=í�'cb”³"gb•¸#õœôWãW?07c!÷�ŸP×ÉnãÆÇýµŠÀmש˜wo÷z ¤½d]¯äàÖ²N˜>¸•”GÔã«Î½L«?H=óǯçvѪì<ˆ9ŒobnëÒèw"-�^�®*‡ŠÉÖéÁôL‹ÚÇWà‘OtÝÝY`â5œñ—&¶—èÓ®ùDfîmx»_>ÉNíux›ŸH õ‡qÊ‚Kðo¯rs7#«˜« ¿ðåZaHám"m€]OsàùÍýä¡íšì?Ɇª/©CÜ3ºöjd‘ ˆ×Ý…"ª—!´˜…m»ª0iÊz|ïEôäª|ü¬SÒ ^Eè?©©ùÿn‘@F�™£×M?“]¨¡¤�ëùzé<­x¦öÃïw„‚jU®Vg#Y*Ê{ðKt laVó îee x0á ʽ¿ DgÈ£ÇÜHZ*kî§ Ðêz99Þâ O.v3{�ÞV']Vƒ½Ù:(;ÏÆŒÍhæ�|´ð›�ü.oéÊAäo¹Êú¸¶l;±h¤e±‚|ã*ÑëË'DzéAG,iýM#Ã/Ñ?ïk8âÜbÖmåbH”ÕåN÷§Õ.× �Ì`œ¥&×�ê@+´%ÁÈh>OR§†l~PsõQõNˆ,Vbd©-®zÚNRnóH~‹ ‘½,JÅVÎ�é»bÈ‹ó`u„%ñÁQ Zò¾ð·Ñ¤…OHú‰ÉýÌGƒ¾DWŸƒÛ�¼ž[ÌìåÀF !^^ß"´-éóù8ýÞBöÑ‹}´;_˜¨®Á¦sSy7yŸÉ'?¢|_›., ¥Ž[tˆë÷»lòÍUxìI2½)Â�Ö+ò ü!,\¨ƒßöo‡S³6£óÕH�žä›Í5è™ïõÀ]g«¦Aû%áw±Íp<†rÊø# þÅe&©Ö ݧŽszˆøO9Þ¬‚5ø ÇpÌ÷š�E ÚxŠ!Ø’DþµÕ�ûnß骶¿ »{ák¥Lù:×]Ä©ó/’#w›9E-±T�{Š^´Ï2èü›ƒ &½_樼á–Âîº�¸ZÞNF-¯øVb}<Žß+EÉÓW¡22?ÿ–À ³rq¶ÏO©¿CžHÒß5öÐÐß^==b:{½ÃØU3àš™;¦'êsJ,úéñGÀ¬oFÜ{CâvGÑq·¥lã¿jT|RÀž|TÃÖéå …g =Ôtì�]€z¨Qq@Ÿ³�t½×AÒþë}è)�‚Ößñ¶Ä6¾ïGYwÔøíêweèBí8䣋–µß`Xñ=©è(u…tt:zÛ§½bCšò°¨m;Æ^øˆ+T��Ži�ÍÍÓ¸ÂÝ­N£†Á3›_ìýA&6f˜òU‰Ñ¢zèæõ‡¨m˜†óZ¦ðf_–ÅñõþhtÆ n5½ƒYþÅ,wk$å_$¯þ£t^Hã··Ÿë¼ÂdûÃXßl@w'S�ýñø=þ RàáïÛ‚¸IóLnetš"¨OTšµ<€Ÿ²†Œß$ÿS“ðuŠþÏ&ëNt¢ÄŽ \ô0~²Ÿ®À»÷º�·e Ï$Á’VeÑã}BôòÇkÕ½Oy~šÙ\TŒ·;öácWNæ´Äd†§ž‚‹B¢™³â`X6ãîv$Ûôµk¯i5xÒ}ó%Ñõ† ta–”Ó_âs>…³.Àú¨10©›g`ÑtG´*‡çüÉT aÉPÌܼ•VUQÓÊ'8«¬•ºûñ2§÷�ôaÆ÷ª;ƒ”O÷Á˜ùY¸ð�XLvRKÁLêºDÖ$Ô!¤cˆ©Œr„V½Vü®ßOž�ÖÁ)æeÔüOŒ†³Yî&\Ç„;x£ñ()9Ñæ»[qZÐè«FâÚ{ü0¤o€+oe¡‘Ò]ú ‹LqŠ$Ûb6Áª½ûÈ¥Ñtú]6†šÀ�æolè_{Ô¤ªhÐD— )з©K¹½âóÉ·ëoHÓ;5k±ø½<w> ²Ÿ «ø¹¹^ÏAdþYxÒ¯Œ¿´ò óŒí{:ÜÏš›±È1–5JÂm/ôÐÜéŠó±øÎ<�>òœ Ö…gÁ_loéðpç�úä¿ÏDR1jC“° &ü’=é;×CŒ²\©:üWüGCVÍÏ�c ¬·è¹SçÖÅØ0êB^_Eó€‡D­|&}ÍG¦nzI?,‰Îmøáwë¦C×�ãxIÛïMŸËÓ/C)¡dò3{>ON* Õ ±G{£0âÕ_"(Ús^Ý!_àFÝ}Ä2¢¸/¶ �VbŽ\8ã¼ÈŠÓ" Å[Áu€ª›'è&³X*÷V;›â@OÜwže@õûgX×#ýʉTͰ�9íƒ^_„±Wu9ظêMç�Æ }ÕÓ£ú«÷fcþŽÂXÉ€ëuÍËíäÇ•”¯c*·ºÑ z¿%Bú�BØz§˜Íqƒ/ó©S¥7sêO(Ö¶&CÁ_[T°™Kâôœ…-^|°ˆFL �n¡Pð½;é}ñOpÑkg¢ÀÏÐ �<¾^D×¶ld/Ú´Á}‰òîXŒ6Hñ �ÈÅýðZÏ ú�á’ÒzŒÔüKÕ/ÔÃÛ¦xM±�õ^¤K_õE‘ÝBèöÈÞÈ “Ö–Îêäë¯ðOª9n#€]]ó0H=/ˆ¥Ð¦û›ÁáikÛ\ýwÉSˆÂøRµ«ÚûZÝ}žŸ7P@>Ër7ugÂÐ}clXh­"ºpá^.v=—À[³êpÛ9Œj„ý‹ɳpvZL‘ûö�[àó²»´ôÉ%œ]ÏÅR]¬ F�!AX7�–?&&cœØ¼#�ÜðÔ°X±‹‹½¦÷²|ÈÈ® Võ¡9ïCòUfVó_ætãVâæp ?ÞxEs4,xɧn’ä—¡Ð�³¡Õ¶ Àò ¸Ý˜ ¾Ú•jm‡)³Q .UˆqIc5kõÆa4Ãi9–‚ûÂŽÓoï=òaѶç�j·²w®™b_Ðüñ/‹Àï£æ°K×ÛõÇÙÞœ½`ê„[U!ù«~<{‹žìºOþÅLÏËhñ}]˜KâÎPþ‰¬}=bn—`Ãm?rÔÎÖŽÒªeC\t–>† Ù«Ñgò}¯-§±O#óï^Ä49,µ®ÅŸÙݬ±ßc:~Ø»ù©xLo=ïíàîT:v…äîAoXr#ƒ6§fOWFc@v$ôÖÿNý+âÂE<æÑCžÛòFÉ®ßàžÍ(X@ϵKàʯ…äÚyC^€*ͶA˜³CGþhù„zúêòCjŒ‘xÒcf–Êcµ£�w懿ßn1Ø¤ç¢ üxÍ­½ø,AÛC”Ý4ÄìvZåÇ�ÃŽzìœïIúŒƒŒqQ&@y'M:ù,$k‰¢³&$‡Ôæ’é*è}å!=üCÙNC᣸-=¨‘{UžÛ÷]´ÿÑ0Ý]Ÿ‰é®dÈÀ‰Ž±»ÐöôGúºU‹v\·ƒ‚€DVMóÆ”Ëн‹Nà肘ÿ�Æ*måV¦ôC�¶ý«¡­çy_¹œ&y úî/YõY°÷ÍäŒä8£b¨+vùïß+MàÖmÏÁ¸¼tvU�s,h>XìGoµ¥á\µh0ø:•ÖwLá]ÜšC«o×aÑ—i¼ W—Ñß›ÀâémðØ-ÄU6ß Wäd¸ù5N´?(šgÑÌA Ù¼ukl`}ò#h“��Üš¨|ö |øëM´¸cëöЋusÐÎ\ å6(aß kXþ¼ bv’ÃçÉÚÛˉôêí¼C‹vPûUÏqnP0Jæ£ú�ŸpÜEJf†‚\zéý”ˆõF™`~ˆÉrK¼zX¦·‘íî‰ÄĽ Ê–øáÚ1^¦B¬‘ÁµIBŒëfi»¦Ï)ÿ•µ¯l«k÷ŠƒtM"µp'̸ª�í×¶RÕiuxI-”`TþtÚôþ ccžUÁU¸ç‚?Y{¡ cøÁ?øS#ÛŒ¡~ò¼š�ÌŸ3éÔéàlœ®ŒÏ´z©ªÜ;¬¶ã‘\3:¦ò’¨ÎŒ¢~Uà•³OÅS5fhbzÈ-ÒéÆÏ– Æ£÷Š)¸UHôWâ­¿-äõ2%ž@N+õ¶�Ÿ\ Ï�Ä…ÒqŽî;fíkzòï(o7̾x$ 8äMl¹�w]>’å{°Ûø'óü ¼>ãË­Tqq³&ÝY†6+ÖÀÞZäû$ʬƒ£ý¼Ÿ{hž4÷{`ÉɆ6YØ6§€Ú½o†½òÒø¯Û‡>Í^E#5¦‘=‰ïèó²áj­.?th»½úí¨eº‡ŽÄšáÓMcd×@Ü©R#m8~ê?0“<F.¦�9% ‡F“¨f§2ÚEt2Ò¯¥¹§¶¹@—|Þ ºž(´]”÷éÔu’ªñ.îqBvj%ÂoI´ˆž ºÇ±[(’øö­@…Ü£ÄGì.Åaã�Ø!³MB×ÑÝa|\/_àN“¼@û¯|%©Y'ÀBé=Z]î#ÂU©Õýæx¹ý.óÚBö4¯¥‹»RÈàê:hzˆèÙGNì€ùQàðá8ÍZ�õÓjÑtF$TݹD>(žGÕ²²¡«‡ôÜó�?cñtÕ Üê }7s|Äø¹ûª„y[/Æó9c¸wA8¦îŒ•–f4üü‰LøìDËåaÈwˆŽ\Ó� w^BPZ\ "Aå‹Ñ¤¥»JÛÈÖúŒÙù©Twü¸?v<• 1¥ôãð wx°@ÅTç‘ÖEù(É«…_¦Óáî|ªÚ®(†~Óú鄉ÔVv îQ®ÅÆy;áÈ®ïÕ{.¾Ç_1-Ø=;Ën‘Ì92cí1Ä�§lh®Í}Xº-�žöüFgeŽPþO^èy¥ŸL�£WN”b¦À!ÔÆTmèÉ÷€ ]?j"�‡ub ˜ª3MØy?ƒ|Ù`Èt•4À¥EÎ\·­�äØÚKäß§ rª¥ˆ(ûÄ“ÎT î{"‚*·´Aøýq2mE(qE+†6£éß22�’-E+!¶iµÙÚ ‚>Áôd“:6ÜЀ`¥•ä­ä5x[úˆô,Z w^ÚÃ×Ã!ð·EK%?ÑWùÀ~õ {·kbîn ¼ú(/64 Pƒ‰² «î¿�ŠG;faú©{õ°ßðËG%²s:>x–NWlËÍíä«A/ûçâZX›ŽAm±4vþ<žè<Œ²ûF¬¢ÿã~VÌ$šª"d–·I‡ßÌ'röô)”\÷˜úvÓœÁk­“H»¬Î îòrÖ2Î ¥nA€ÏUtPlAËm^¨Ú&ÉÝY1�g7zœdoy„G=‘˜7¶T"C+.þÓÈÇ}Ÿ¼;=`…J!2§‘û_“ì!ŽMg©|Šî=ùššÎûH©i/i­W ðœ?uÜMü_]#[|Øø”-ôT„:Ìýg‹)Rc´sÃóêsuìL³Ã^ÙÇd•üˆåzÀZ‘4hvÀîÌgtmhö¹í§³wxœ…‡¤9”çŠÖmÕ9AÁÌ«åü`)ë†AB<ÍA7–ÿþlöZ¼ʧƒiQX“OŽæåãŽåþ`~)š l¬&_Ry—v:ÔçJ=uªpî¾(Zrû+®wúA¥¾ÁÖ&AVöà ²p‰ }¤pâ®Ù’<‰'ÌË#>˜íz˜¾‘�Ç3æˆ�°º:*s0=vð£á�å )’HÜ” H¹Àa&âd,5_΀iHýuU„û)¸‘¾ÌOÆÍÏìÃB!*2/™†?™; asQ-N9…JÏw ªwè;ªr†öF㋼»�˜ºmy¢ð­í?L>²šzœ®§‚²©¤¡h„.I?}ÒŠ0‘òœ*sCˆç­”óÊžñž(b肋&µ|ôz�Fê áÐX8Ý€/Ÿ†ÂÄÆtŒ9“�®OØÿä×AÞsQR³ô-ÉLggQ´ø³ùÏaÑM1¼3ÿ!œ£„hÜMc-3«€?è.,#Ar`‡É*ú®Ìš¹Õ:ÎD7ç’£sæãÑßÃ4øfMø"E£6§€–~=&rܺ9}Êìð�{2ÊôóPåi6MU:_×K±§îiS±?q$)ÿþجNìOžÇƒ;=˜°Òö¯¦ à›dx·í(M»s„®^›�/W �¹ïj@F¾�tMц­¹Á˜"ÛLîß�A;^#�KF)¥Õ�.jO÷2!ôUV.žz÷‘þwíì¸X ¦@\W8˜x”!zíðˆ?Å)¨:íËß—�ÁûŒXN‰Øüª…‹7A?€þ쿬˞w f4@u·‚ÂËx±Î�øÖN%Åýѱ�›]Ž1Ì95rg¶:½Ö#OGÕq[°3öXÁK/KÁÍ­%T)Ñ—ˆ<•Ä¢ex‚ws]�1sMRuSE(ì^¼t~Ò·{ðÔÍ�̬}œ ‹¬P·s&ĦCjȼäAÈ& ^‚Ö¢r¨õå.)>’Æ6ܳÇ7"Xê%ÕK„qðû™—9¬4ÖrVñã”–9 ê²ÚãÆ”n¹p‡]réßš$¢¶EV? À0ƒ8j¢·‚áŽÔPÅ×6“ë9OôÓ¶€ÖT!¬©‡¦ È=�ºêr`pü".Òpk�IMòÕÌóxXã&iqwG·‚É,9ó‚¾ ÅO–Ú`§2éy./±Q6 þ)úás3Xéð�>°Ø€unÝ``4ôþÞDöBÁ=SQ^¦‘ž\ô‡\DÝËב>´wë¢Çµ�ÜÛœ‡ŸÃVÓà9xÔ�‹žU4ãŒûîPOµvޱ›fŒºÆ{hNA"ù—OsUñkëøpz=Æÿ°¤wF¥Ð{v9-·§;J- õ®?uêmÅŒÙ1àõ� ‹AŽÉ.Øzpnž%Æ{!˜¥oq]b œ®˜ _­ðB†4¸·.á>ß2•»kx!a£ôUÛ5÷H ox@Åblj]ÈvĵÂ*¥Lß�ú§“ìÆ7©×i�V|IXZ?Eñl§6÷ÎÆª4ɳsV©àŒýÅ8k£7^2c½S©BÙc¬MÚ 3¬þGÑyÿsý~aÙ;’RɬD$*ñºÏ[ ¢E»”¨”JôÉÞ;#!dïláuŸ·d$¡RÒP¤)•ÑÐPß¾ÿÀý8çÜ÷¹®ëùÓM?h¨@íŒè¹†Î7ŒæÏùAÌ^¼×!}ä)•ànæ*’;"ÁT,¼Š|pãÁ 燴Ó;¤Œ˜µ˜Ó»ùl�}ˆ ë;’ôÝð,\‡În¨C—冴6‰—°,&H„ÀêµÎ¤úuñgàFk†®é�ˆïUT}Ïe´Úé�a=¡ö[>N¯‡öÚ1æÞû�sÞŽ¤¸­~Xã¼Ì=š±¹%ücà¦d5ººÇ¢ñú6öªf }òL ß5Ÿ£Qy¸ÌÎrs `á#L:Ÿá67ˆÔpíšJ> NƒOÓ�³Ô-™ Ì97'­1g/Y¢��œQÖ1¶V§É1*tn�šŠ&RA¯Ùÿ\³ékH ³Åý‰X÷xÕ—‰ ÆÎåFëÎÚÀÓ¹Xšš‚;�­EÉÍÄ0£NÍw¤j«´XS…Yt™æ¼–?JÓ<"0жšqܵ�1TþëSòƒ9g¾!_�@žÎ’qP¦.ÏN…vGô‘7+ÑQg My"ÍsÁþW.Óۉ­d\ù*“äæá1�¯øwC5œïb[<ž3ÀT-°Z†–‘FÉ7¾alŸn|ù†D];Cí¾©¯%ô„R7ñÏ&üæ#¸¤\ ?+àËîsðW·U^[ß6òyg,‰ž·T%¨^ü*vÍï'¤yŸÔ5’ÁëïQ£½ J|1çµ #Ì„£¾ú ª)n…mÓÑm* ÂLª‘™ ïéH}©ÀY[6¯ÜA¬R„Ð~ �º­ç#FnÒ\�/™(ÀÄÒ‹JÁÄ?«Ž)rôÂôEÕå.0ø{î\6Aä>�Bd†êƒÙÁ,¶¾×Æ’ýä-¼·IÍCƒ°^ò²ë=YTÃÁóûyqM€,{ç×yÖ*Y&¨ã»MH6Ö ›t Ûõ÷2¦êÎF•9¦X#<ÉÊH€¢<ÎÅPh“ÈbrÖöBèÒ�ü”�sefÓ¿÷C˜ì^ÌêW—‹ºt+Þ�ßbA˜VSCÄŸJ‘² Çi\× ð{‰�î¹qÌ»”„ ÐLß‹\±'3¾sÈĉ!f­[>Y&Ë5’4®?÷÷:]ôL‹+ †ÒÑ�¤X£¥â8: yâ \>J?<8ÞP|b׬åµ(‚þ;6P£·¿Ü¼‰þWëqÿšÃ¬½©×Kwk&ºÏØ^„éá¸ÛM“sÛß {ÇEÿ�†Ö×' l¬BJ�°Þì-n[^ϬnMÇmC5hÍïFOŸ8òŸŒaÉÐajéŠ}Õ�r°“Ž,Æ ¶Sør¨V«~f?¥z`LGÃ鄜Öjö¨Ù$]s²—¼¾ØKú·�¦«Šðªº�oLÒ.Ï„ }ö½ m³ ÁRÁ4à¿9œ¹ 4qKbý|ù5éSVáFœ=�»²E*—!P5ÎT¤vÙ³ð±vù¿9Ü„\¡ZÐ?¯I°:¬û^DÂuµiT|Ñn®šÛ"ü6Ó¤­q�–$W$+�ýOu�È×ogdNÝÆz··°çá?ÞjúßL‡¢¶:ø“.…ÅBFçÛÆéµ  (m3mXðш¨¾`}³ÌñåÇeTTåjn좳žÃÜßN î›ÍÆeÒMò�àò"ŽùxÆLZÙ ŸEL¹s(ìÛxdÑ®­f`}Ù“ô¼ë+W›Ò_öï‰ÀçIŒ­üKjVëâ²�h…ƒ¶£MB+hEø@WÌ.Ø*ꙋø‰iÑFÌZÕGÈBK2ö÷ªáLÕ’ƒï„Lˆæ¹óÄF?–¬�NÇ\Hš�ƒÛå]aS#íYIù×+2b³êÁò¶ÞžjbX¥K8KúÚ�OƒYÏ»!<@‰{ÃC:«Û³9F–F•Ìo9sø»T˜šZÍÆ�ÅF’àF­Ÿ{±2Å3°õ÷G’Ûý�¶=ðÀsáþôxQ—£Cäéa. 8L¾üÚ ¦ÛP“¹ð4žC‡~­Àû>\í•Ð=MˆÃ·f Õ^%»}“áhŠeÕØJ6ÍVŒkÇ.‚gÆ)Ðe±íõGÙÊ9‘0gËö9© ·Å£u“ˆêó4HšËñðóôÑíQ¬^]iÝÍèÄ"[ᙬ?Y$,HJ¼³ ¼=ŒN·Õ¤ö½¦Š5,”ÏWBžÉ‡è!6 »_¼+�Hf[Æ}ñ'":jˆGŽ­½ké^K/´{"ÇHÂ#_à]r”;ÛãÍ’ÍСBÒÔ/À”fÜ«÷Âç2°,Q�„ 1YvùNBʉ>zÅá ¨å¡¤£:ËÚ ÐýFô¹° t•›`Ój-˜ ®¤ÝR5¤§3˜Ú]‚ß3¼@¦ê¶y~�yø¤²Š²nzDd\#�¡ÍÚ `µå<3à…ì;`¸�‡¸wˆî“{$jn8™™œ1:—qO¹u*\IÜtJè…!JïÊ÷ÒX•MØÕv„êù uÓxÃüÎÝ�xy%Z-ÎÇ¢àVÜôy9Ñ�½*[¥ ¿/ þô:Qá2Ð4ûÄL”‚õH/•}€ +o�–îÍ!m)2&Ó„—ÞªÀ‹æ58w…÷¯ßc>;LÉ#]Ã*П?€c\)ÎÌ’ýxkïBÔ1ÀÝ¢ŒÆy[Øîa†Š\æ.Û‰1:)X.{Ý ¯Û îþ^pœ½5) Ï<†™âÒMðçIŒO†c×�Eÿ+›vÍŒÆåˆ�ûú(VÏîC+¯v‰ê"Û×'‚€!šÙ£ý÷™t­c/�¸³|JÜÁþC)yä½ t L£å13]¤¢gr½=’X¡Ÿ  +Ã¥.™˜Õnήùó×EêqmÄÎÑûþr´I,…§%‚ìÃÃèõ¼�†©ûcÅ™z5Q O¶c>ËÇé[]„ î3ð\²\SüIrk¯à+�+è±-ˆ¸0 –jÕàá�ð˜/ ”ü¤È”îOjýÏçï䟆4çHÌò "ÿjM_Ï%;öb^ÎЙáÌ6¢Ta�s­’ì6ýIÔNl$ùO¦è†Ñ‰†÷ÎÛp‡G&ÖÉ.ä~í %/«Äˆ¿²‰êÊÃÔøh:P˜„0ÓÑzîŹLõMÂxm ƒJ¬av¾vƒ ½0mt:*·ÇÐsIàwµ•¤…¢÷÷d"Ñc¶×FIÉÆdÌ{^ Ö!å¸úè¨Z­Á]Ù[™ÓdA¿Í®ï‡N{U|‘�nIs÷Ε„ÞOðäÉ3ì®öÐÎÉ‹ôê¾$ö^×w�µÇµÏ°`ò'Æ}Š­‚(2ÕH/¶~€3�–_[&ûHLÖô6í%+Ãȳ„eà§`�ƒåô}d Fx4‘3ÁïØÂ óµ®þB± øÅÅ@åàJ˜ 2h6*ÎIy{‘~HB½^ÒsR™Øöy=Ž��¥ˆ”¿%z}ýÉøw®€ÀÁ]©Ä5Šò@³+_ðqØØ¿x”-óI˜aÞÛ”OÃ?zÕ£à8ɺñ„Ýã6ŸQ8»ƒnu¼ýæüP|Íe Û˜5ÖCÌîýLîö ¦èe>.þŽÊÚס#z€«ÊÓ–+!�õõmÒ¾Š0¯ýì­á²åÒu0çí:ÃZÎüE‡-þ£çü¢æ¢Z·$ài·b2÷ö º­Íž ¯E§m•” Ȥ“ìì¶.2üZ"�#HÆÀ ùáOŽñ‡O •ävæ= ù„ åÁ‡ÉNØì.Àuôç¥#b`ºç¶ššÜÈ“›<\¹v¶j’xñ�)�ˆ‡ÉÚ ÚÁœÎIK&Ãß¿¢ÛÂöÑ) ·£·¢ãÓx²L—þ÷”'|ɺ¯¹ bHêz¢™ŠY͘2Úé\\rÎFÇQÿÁQ²çá5tçF¼9‡ÅÕ‹¹Váþh¥¼ÓÖU2ú‘&ÏVâ¼ñVÇ�áÄðW:µ¬‚ _FAcÆzcƒþÛ f䎫í¢ßºã%à pq�2Ä-r¥+n\±«n r>“J'Šs³w®æv˜9Áw±w´mZ4fè_ó‹âaÕÏ`õ–”d÷2#s:ÉH¾"gìË!7Ÿ{vW¹™ÝOÔfZ‰1ä±T ãö;Üw@ÈCHW²% v#y—†îR¹`aˆî‘­¤þ#\ÒXĶ÷e**Þ“›û¥àÍÛ(�‹[ •ñ»à齯̭¹f“Ì–±ÃTðñ(p8ÓAá!ši4y=¾�™W-G-Ð;Ö ÇcöÀìÊnt=}™L­xA<.ÅÃÈ©ZòGÀ†p†³ÑË. æŽ0'[Õ0Ò¿”–ò•ã,7UœGŠ]�â �—ã „»ˆ­;ì�—và¦4?ŒMWæfûh’9Ö~h™Î2Ó›äáøª™œöI>Øþí 7t36ø!oäÄ ó=¨‘nÂz—N�øÃ‡hs´©þ)ˆ¡}çP:ï·ßÉ¿#©qÇ0²uHCÃciåm&¯²Äˆí-a8`>�ãY�€)o§Ã× ;T|1ÆŠéKÂÃmŽÀœ:tq9áÏç>Ò¡' ÑÜV T$¡äu$ŽH…ÂÚ¡“äæÅbRüçQŸ ¥[µûŠ”ŽRãŽO}PÍ¿eG± 'Pw^ }�?®òT¢KWôòß„göÙTÇË�Ä8~oøðT‚³jÕN®ªh �UïKC¼iÏú(ü®äî:ærdë "÷[émæQ}|•n=š‰>{QY/ fI÷*ºmãÐé„iÿUãhÝ"¸kÌ!CÛ¡U.‹ÝkV…[¬ÉÎÁ¹œñp L|5�.{€$eû&ôÂß+]˜ì˜ ú³~ .½?Nãßgÿr¾À2<>PC§´+и žµ¼%yÃÁØÚ³ »ö±�Öƒ¸ÙåNüë¿J»Ä6_�J PpçÃÈ\²s�ä}t‡7ýPüÞl|T”ƒ[ÍH·Ùu:âoÁ-~@èÊN4ÌÖiø8ÔLR‡±] GIå¦0ˆTûAuV»ão±)RÀËÙàõL½«(0pµ¦6øè^ÞÜÈ qxñE$ß·ù[ñlÉ nº„«7Ç£ëÛ6ú+ñ;×S„is‡|¼cÀV’„Sáx¥!ß>ùIn7Ò]W#Ø,¢ERŽlÄÌ%ôþü!Ü‘�†kÓŒ@mC-œd|qZÓ‘ŠÿÅ‚ý¸ ¸¼ÝÊ.ÂÍå>xþ– þž‘OC66Ã2+aX¤3 6sr`özŒŽ¼†t« 9òD•˜¾¼]Ð_÷Òñ¿ÈN tT§Ï;‘…K‹‰Šr1H—Ü¥eüœ…Q_Ax­$gGô>¦;p:lüN Ýom bó£ð�áðœ‘NT£~�š¹ÎäYøWú¸òƒ£¿ï¹'Â剸‰{õ:!ì¿pêÕo Of XI;6Ï¥õ‹£°›G…û¯%6¨[Aþˆ ÌL_À)M€úúÚ‹4j½ 2úOhuT«Q|ÎïŽÅ×iöD%%‘–=©@³ß)Ø4 ]/̓T™Ü3¬"™êþ°|°d{·£Ê~üóŽDL¾ÇÈJoÆ0ìÚ&ÔÒÆªEØ«v™¶ÿUÇ ç-x}¦] ÂËuû†JCÁøæl?ÓÒ´­ëÊh_ù× ‘ŸV…¿.Ë`�ŽÖ½üLc"«QN> z÷N£œÅ8 ï‡ªE?HX¯(jö—Cý©zê¦ån·##ǘ´Ñ«´ÄÏäò7Ó·F?àûì[x«…âž¿FKÊnÀ¹¬*2¾hhßSCùmvDdûÌÜ ÌI=-˽¼Zø6£¡ýqúìå.öâÁ\„R}Ž1µÇ;›æ`× }¨sÅo_’Ñ^= ‹x5ÁgŠCÜ´1äv9^ÿ2Jf=Ï£[uð|\ͪ½ù×qË~N"àžY©›ŒK•ÝÁ?ÂéÌa»Í-@ÿm)Fä°34ÐGý j¬=�){Öâ«ÿ6C_R+9–ÒC¦…ÑÜa%,u‰€7¦WhœP ZY7Ó/? °»O‹æŒÓUÚd¯€˜T?Xþ¼E¥ù_74µ2øV…x¼I„:ÁBèܽVYÇ3…¨Û ¼«(Ì)¹eަ¦¨}ø­_€cBoØwŠR`šP ØQOîÌÒ@ùôM ü·;²Üúɨ÷Ü Þkt©õzâ’» ¯þ)½Oõäëq:5Yã°˜î6á� ¿BᦇðÒé%&±Ž$‹·$�¿WBNª¢� C2¬”J‡Ž¦×)ÛZspÄöëL‚à‰ñ]tz-ñõt B#jy8 õL�èß]‘Ð|"Ž|«†Vÿ|°”æŠÚ²ÝÛîþó€Yxð›>R(ÇQŽ*>LÂ¥išP3}ûGH,ìW@|Ç"\^©æ}_Ù²É(2ÛyÄzGÒß{Øo6Þ8tL«þ¶c ??ö§­Ew'%ÔÚ‚°ÀÔƒ® BŸ«Ïi¯ >®SØ J®z8¶zRNÖn? C®�Œ÷©Rª"VHÎG®‚9ó�¥ì=mòhK(ý!ôìÒLÚî‡ícêÐpr%<ú _2W+œ&Oqž÷MvR% Tì˜à�ˆ7ßCí•iüâj\�¯Ä=Qóƒ�Ò…-Ÿ£ÉTÄl/– š#é=�74@ˆp§ ql†§äùàt•žžåb×Ú©¡ÕUâ©� @CµötŠ’@£Lb\WÃpoƒIÜ3; ²%±ü£6Üé3a¥¸»`Ùò«TIÝ;çÒ�TqUyÖ¯žˆãxŸLóã»±€(÷8ÀN îm÷»¤P¨­…׆tÔ<—e]e.‹†Ò¯dÃ5`Jiš^ßM´ºA³F/�,'uø˜q’¥Zrùõ¶Áýpx¼Åk;éÖö|øõ¼�ò‚&Ç [›ÉG»$R ïM‚ÖÀ²Â¯$JX^*“ è±Ï†ø¼'÷†ûbØÑF|å–�N=!Ëæô ™¬×¥·ƒäœÒ@­ qxê4“;=Lš6*eÃû�qrÏ ˆ,™¼Ãšë‹�ãÆkTim?þxc€.&A˜üz±Zä˸G)a�Ç=Ú‘“‘snÑ~ŸÍœBe1L{NgüV#‹Öiã/w^Øöë$å�?JãL§Á¼ezä“yŽYéƒç¼d|8+‹Ö;ÐøãY°©r?[ÿÄO×~‘˜{½ÔE(ФÛ<"�Í"̳01T~‘ƼóqõeÁxìüu"f›nrÉp¶Ó™ðñäQ�iwqï‡ü¢}â÷Ü îRäœ[ôìã…'Kü¯|1˜**rD…ÄH–bå}J"#&Ù ;OÒ#k1¤VêÄ%@T­�uÿVD37\'Î=YÄ�¿–ö= U9²ˆÅ‚8k�*ÙG2o6éÑÕ|ñš¤-¸¦ ¹çI>ï[òbÿâ v°5a5hŽt`�¬›ÞKŽ­hB™ØNfh²ƒÈ+£_Òfq„/LP“· `Í› ãX�º†ã�îQá[mðvÄWlÙ•Žß¿ Q§ô@°P±£<œOí ôÆòTˆzð‹ þý Ôb  ø�uëxë*I­Ÿ>�½C�W>#~ÛDÑb�9òy­…û Þ¬Fó+’^hÇ|:‡Ì‚“DfX†”Ñ¥¢ýM�Û"€¦I°�/5VŠÀ…cpO""ª)s^ׄ“+®g³”É-'7jóÈpi2¨6e’ȉN¹Ü»ÿ<âÚîPÇ� Ì�»ˆ\~’NŸ ËÁá[¤Äu˜žíìÄ”ƒ2èãt”¼Õ¯ 7¯ÈÀQÑPfñÉ;¤òÀ(¸ p8÷Ü.ઘP´ˆÄn;_j´ñ oZ•éF8½cÜ—ÿL%ÖL`øÓR²5¨–´Ô¶ãéIX{<�ît&/g Þ‘Tl-Ë`Füä9�°ðjf.S# "gq­ÀeªÉàŸûª°G›ËÜè‡×G(Ÿ·Ôôy¹³„ ÎksÎUšûª®˜p×z®IÍ'²èžýgáJ´=Ôß^IÔ?dnJ¦r„•¥¿.:B™Û'Ì/Q„DáùÜÉ\Y¨è„¾}ìݲ„»~É;²Së6 ²ào8HëQmð7ù¹.œV~õ‚̳dÔ¼ _Af¼äCëPž¥åÑ… ö›.Æ]ëøq yt`=ùîÎVÿM;z¶nõ†?2÷†âŒâG`¶^ ¦3s5t¹ ¾�]íI®L|£súCÇ¡[tï™Çdhd¯¹h’I!E|¦"…Ö)ö\‚x3UÐ1zF>¯ÛOK#Êé³ T»›÷-gÁ»cuئ3 ‹¯L‡©õ©°pöLŒœWT_xƒÅ?˵qj{*¹ðù!sU¹¦ñtR‰YØj¬�¥~1`ºmñi,BéõØQ#ÃyHcÜsNz/&©Æ eÏ rÈ@ +cq=4>ÚA‡×.†Íú‚œ¤u;@ð…<¼÷U8â—Âànck¼=——yˆwïÿ% ®þ ¢g`½‹fó}1rÍ-k‘t°ë‰a­³¨öç*²²ê!Í;.¹±ðqÕÑxCm_�ÃËE"ÌõÅíKý0ÔÒˆÄH¿ƒKô *ä¥ö'ÌWMîO­ÃdÎ6iü–rmwŠpvLD±'á°wš@”‹ßvߦN;çR¿³ˆ'ßô‘·'.³ŸoÎdKß¡¹~ÜØ€í§r©ôBd7kBÜÃøº$G_2þ5¹¥àç©Ï±Ù»KÏüóHí4r^·‘†Å]‡pqMú;§–ñä;ŸŒ¿°Yw¯àˉnvtô«aŠ�'c½;<�¬ØÞ Î-áOè2šKzôñæ1_œ*À}’ ç&õ0øØ:æ~M–ßf�ûR&þÍ^=¨º³Zh†S+y©·ÌóDÀû¶*šKÏ�‰ûiª¢.ªŸW¦[ePTôõ¾tøÖu1:�ìñÂÌ%ÔÒz6'ØŸ›¬¤�úGvâz×"xý³š~åĆƒ6ôÈáõ°w1p³ŠÈ'11®ûŠjlγ¤Ùÿé‘å4u<ïl9�s/ø)SJø\eAf1‹ìâkÄÜË£ÔèŽó‰Ð»ÕŸ»øo¯a8µÔ øŽÑUdyžOƒñ?—È"Û@ØoÉ’¦È+XâM Ä×±‚×Ðÿ´W"g˜œ}õŠè?<ƒµ‹Ú¨‹ÿSrÀú¨t/h¸3(…¤û8=¾Hµaóc]´×óÃésëÝHÏÒd&ܵ‹\`¿[Ì=ñͨ%þ1Æö˜A­‹ÌX´�¶iÀWƒ)aÿñ«g">ÞªA*뉀b$ rÜLdz6ƒó jíëI»�LqÕT#U_·�ª©?;è—®Æ�—³èßÚ&äOä¡<÷ÃÈ—½Š UUƒ[.¹Jp^x-:˲6žY(àŠcÝp˜LCÉ;(¿ð.X~šC 2AÊóÝo�Rl5yxÉ�ù,»Ÿ½le ‡çÙ °DžFW÷ÇŒ>Ù�“ù#TbÕ#8xį¹!–Aü‚ß§ñâóN8~ºmTƒHmF“Ï›‡<Üp¬ôK†K÷jiû¶ºçÈXj• Váù¸'PÜÄu¸íÛfr\CDݧ°Éh>Ú]�‡žåS4üÆ,jg5ÀèνB_ϨķÙÚ �;”côu‡Ñ�¹Ýd¯¹2÷õ¾7X~F ­=éAòñhù¸¢–Æ Ñ_%�}œÚ X�ÛÎü®Óž+WBmóÒ{+´%‚‰†âo£+™Ó‰Ïo>p•X‡›W�¡�Üvº¡ŒŸs~ð åK¼D^*ÄÀ+Ë'p­æ þç$Œû$Ö`i~é*tD©'½ôüO j¸;�îó­Kq0W6ˆÝ=Ÿ›ÉI8b¾ŠÌ9) ™Þ_¾–ßL€GË;°*þ"|'6?½Ð¹Ó—áãQ%Ú¿§ÁüÝÿòÒ¸>�œG?v³3çÝÃ]r³Ñrçý[­hŽW¿r{D[Ù�[$ÁØQÞ ÇBq‡1‘¼òm3TANÐ�Zªð+$ Ûhjp2l�c` æƬ¡ä²-¨7ê% qh¨xG¤œ Ù¢'1ïq˜Õ­žb•Nâ¸u6µ]…“Êðºœw4U¤•þ²¤Ã#Kki(¿9œî¥Í®â`<B~�ØaQâ5êæZ�s}#j’r`Ïj↓©õm�‚è\ÝQjÿˆ”ïc´Š.0­›Õ©®I<óF³ ½4SqtàY{³ /¼úMŒ¶ƒn«?n;›‹9Ëñø] ÌÏVCë«èf‘H—|›�^+«É²à=x2ã1-ä/¤³oÑ] €ýàÌ%ñCÈ¥Ø9`¹JŽè HüÑÉ%uø¨E~eÉ‹d |ë ó/CÉÛht^.‹äÐ 9Þc s·¼¥ê•DW¡Ýx†akÕ*†Ž¿#O·NüÓ$SjǨš°,TUÞÇ©Ir(ý6Ý'Žk^`IØ/ü‚ƒp5à0©ø� ‰ž»hBqŠòâäBaŽº«?(?x �»Ëq'<Ü]QˆCO‰Œ_(®ÿ(ʽ`S‰Žþ% ñ<Î�ª•ãQDëQ7y‘-k?�oÓUà“’"gåkæ¼v*VÚùÉþ$R™4 ¯‡ÐÅσäpÜ]KÔ¥Û‹×À£¿•/u�/çL¸ié38§�\%+ùĹíûM1éúfÈq„&ÖeÀhÏѤêŸÙÒ§M†ß¯äÚÞûÀŽK¥›"ˈ /˼) Dí³°ÉG-¬öábÕ,ì,¾Hž' pµ¥ ´`œŽOu²Ü·�h¦œ…_£ÕBÓç�ªÀgYÇlÞ‹ý©9l¨À=ãŽgCîá—âì±C�ÈH“È4ýb÷—AÆòƒáAùÞ�ÔC›HÄ=#üäúß1,>}ú”úÉÙà×!_eAzµá³‘ú·]“Z Sw é¸e0“ô keò(Ö†lƒJ!sja�kÎ@#/ º ²Çæ”v GzÌ®&ö‘«Ðsª£6µb[M¯KÓ…­Þ˜)5›ú[œ…Z‡!âÒl‚Woávà% ßváìÈ·d¼B›Úäÿ OÛgs‹s©ƒž;8õDWGR¯;‚ÙžSð¶;šè4¾DžÞ­xëR”T„ñÒyFÌý¶À-“JŒÙ0Hîƒ'½ðÆt÷·£â#LwiÁ—à§È§;�³þÑ1fÉ?�üø*…Œ®«¢’3Îaí-EC|qðÓwª*„γcälG X­T‡m»iË÷ û©göéàó9õÀd-öq8,f~ᙤN¼0Ð6{ÉAÏ<9&�];ð­t}}ä»<¤Mý‰xì’0ä:œƒž~/Ö{q ‘5 e?:,¾èk^Ií[O—›çáÔnè<öž¼¾!‹[¶®fŸ�s!÷÷ø³62·©�æ*”03…B÷o´yÞ(>õQ„Ü/¼Àww!÷µ’þÿÿÛÃ7+íqõg'ØApÿû""¼àm*"W##ᙾgަa šñļLÌ^œŠþ-C !“d6E—Øó¨LŸcÝç§ŒÄïËd£ÍiгØ±a˜ßц“}Bܦ²Ãth@�\÷Û�ËrR p„ƒ¢±ðWÊ´i½;(ž¥ëE¿áPj®èK¤O7�:yøÔ�:ƒ×#ì çà>ÙUp­‹‹ ‹b±ÉÁž‘~n‡…é¶œ(\Ú¼”«>›Ûaªó¶ç“©Ð‘C×<ütý;ë;£�]ã_ÁJî»"óÎ�§j7aæ^¥‚'ßR·i’xµü½~IÛÅLpåžD«m?¿ ,h®'C�COÍrnè;ظäŸFO«…’ –øe•2ñÑ.Ű*YŽËçÝä„hx|^†sÛeÁ"7ãMªq8ƒ4œùïùp8N Gc‡›¸tÍqèÙÞK–¤Ƴ…v�ôâ6Úl�I³&|É9ƒÜâ勞ô/³x(ß_¥…÷n0Ìp ºó¸Ò@ï,X¦£�Çv£×í ÈB÷V¬˜ÚË2ÐçÄ êr$6érhò h8_AÁñ Ú­úJÎ }&ÆT©Ùˆ$®¿Á…1䘃µlÆíGB@rh/.?a|kÊiÍu=xxWo?N¿Y<#ÝNIX äIÄÒ�>ŽO‡»KÐ3¨�ÝQìH÷vAtÚ6êZ°“&D·Ó�}³‰éý%x r”|и‚œ¬6ºxÉÚ·)vÈüboŸö$cŠr\…-ºpB+ÿCu\ïÉO×ùˆBQ«çF� Þ¾RA~Ùp;̰3'…ýÆîTÔÀÛ)‰ø0ñáé_Œ-ePVoAÛà½ÌDÜéLu+çs vêÐEn5äh¼'(IæÌ‚Ýœ f³÷6ö¿Ô"¸ØN|¡j¾ÈÝ! æïoPÎãX8"•YÛ‹‰Ûç±1gÐsuy¦�Z¥¡ðVT“áD¿¯[ÝYŒéçáuîN,]žß¥xÉí¨C(è&F˸eX±º…ïTDEꇓAs°Ø¢œx_Ž <&VX?}gÓvÂý°¬ýŠ?’-ÍoŒ.%Ï%ÍIô‚ö%â´q:„º5Ó„ž`ß±~…AñnS ëFØ.¹xzOPŒë|UmhØÝ4ò�Ÿ^½#5U`2Ђ �ñÛß_TÌkÎrŽ…”jW¬+�UmÄP9�Í:À`ea%OÁùhðbý°Åî+i¬eô1·ž=bÎlûÉ®ÞPÇŠ5Ť”…TCm?¾rÂ÷Wú˜�Ïév¡50vg–qïáéÍcd]�3¿¢Çö*ì¦×ÿíuKÇïž‚5ß—p·ø¡ñ‰ <·>�8ħ'‡�0kJEFÚ(wÛc<™¯Î½ÞAn:˜Â—¼y8ïÀJ|Œ©’d…ó+º«G�Ö‹¾ 7ßÈÁùü48éI">Y¡ë'Øl _Ø?ƒ™Ôs×꯼«î¡Ä=rÊ…�4¬þÇ¢qp™·„fŒÝ3Ê~lˆ·ƒ|0ª¦ ?t�¿NÁ¤gúX;(å1Ç¡Û¬Žˆ>dŒ4§òHWT æyü!:!u4o§ H˜¼†”šhØ6r‚jÐ¥ÝÆ2!_!ÕÐL~ ¸yñ“¶h L’ Â5ãòdÕß§F×+ÒazÏr$^öØ}b\ÿlÅ�›#¨–Éz°ý±úËsçÎäúMÎç…­‡¥<¡ÀïgK¬œpôúcªº ¨?œ ?Ž/+óðœ·5Ƭ‘Æ¥ûǘ��ð?Î;žËïýã6©¬ŒDÙJ(á}Ÿë�¬J‘DBÑP𒆢²¥¤d†ìU6E¸Ïõ&RJ”ÙBCKêSŠÆ¯ïïÿó×}®ûõz>Ïã¾O²D1ã´¬g6‘¦ ¦^½ˆäåktëncÂ.�¦¡&Í´IëõÑÖ#jSp±Í£?ÉÿN[˜+àY€_DÁöxŒj+œìh¢ >{™Ú ”–0„�•rÔÐz>¬tìb®$.bfóÃ_6 ýG·;>0?ÑI–- ¯ïL‡Ý.Êès' 5 ·.OÆÃª# 6ÒŒ:ÙG©T—=zÕ›}Î Ø/™Y7éü~]ÕÀ þ~ðתÆuü‰¹ÓYÜuû ³¿%N}K`,¹€ª\üoïzúíÍzxè¿¥}&q¿&�ùNt–+Àö¨st^™Óß̯QÁ¸ñ)”M¶‹îh±%†}2‰q;äàÁq$9Õ)8‘wÿ«Ñ¡‘6jVÉjןCËXKæ²}=°w#îäâ¥ð[¬~‡.O4æ^>ȃ7²Çqìœ/ÊÀ{ræòCNY‚/ý°u:h9ÖQ�© ¨èÝ åö χsˆNÊ\S*��T™8õˆâUñ¸ñù ûÛÚ�|9´�¾^eNëWUšw¥p#Ý€÷4å3ã¼u˜ÕŸ¿U†e°²GTÝ_P«qUX!ñK2¢µŸ'…o/1¶T€ºŠ<†¢_)°q�8È®¹¦Ѱä…8�¼ƒ_ uÏnöû WÙÜAf–ëÀ­E›h¼¥.šÉ㊧úX›‹ÞÙ᤾!Ä¥�À2(!‚hGV�µ“üÛI`si\ÖãªÙ'Ñ>¾Ÿ¢¦Î9 nt‰ÕúÓÁ–\ÇÍ ÿÑ%ãÎ�Ï�ŒßÙø)ô,ݰ‡Ç�}�jˆ’•!f¾ÎÈÉ3¨qž ^§!W®2×[w2!w�Qçö%fµŠ7fÉÌ„Ø'½¤ã{U’* /R¾1M2'a×|'Þþ6W8rÔ¾™èÀÐÀxSQ ÖOæÀnAZº¢¥û�¢âŽTryG =üà cÚ!1|f™Þ&‘KÓð÷©bòz‹ÍwæÍÌ9Ðh½„êb õ£Î\ž�9–¼o§ïÒïnQô±^$¬òY†•O• #=„ŽŒ²Ã�3�¡ÛD!â3§G+>ÔV×˼ÇbH¨îÛÂê‡ÈÂZq-°á`ÝÏ©Ð6m<è‘FÛ«�æ‘nûÎÀå@ö}ËVš¥GM ‚“wœ¡ðW-d²©`áF¢¸ÈÔ&yØ"Ê�gíâPüH1çʱõ2£02B²A¶–BNE?e"l¯ v CxÉEd&8 ] ô¸"¥M ñΫÍmGœp©ÆLnãÄjÔ]‹±?Äÿùg.õ(m¡¯˜ÑÂ(Ré2L³ž ƒÍî$¸•k ?·×Q�H Äx©»xÀ]B¯µ�†LÉ$ŒðÛmEªàæ^ TÎDd 0n8-ÇïQ¾ñÍÜÕ;jI+[†mS¸æ Pž©!;”JAöîBr_�àPì6ði’dE´øyZ¢KH±n­o‹‡ïºž(œ ÇU m ¯ @x ƒ…ý‰Ð¬%`\)ŒÓÇÅatõ$ñ¹�p�»º‚DaöR®óª©�)ý„öO¦¡Hs $+‡Â¸U›Ò¦ˆO³³‘_ “�ž³Š:<�bŽºO¡;Œº``2›¦•L��;ùHC½/¥ €awêhÙŠ� ¹­ƒS¤h!óï rýœ®ã÷}o)ÏÁò¢�Ð; 嘄@ÛÚt ka··³9ñµŽUÀ5V§Ñ9õ¦æQã´ÊÁE«nâƒàT¿€QfÅ0qÇf¶ ì;1”ßšô ǘáJºoüq½`A-†´x5?ç�Œó5&ζõÖUÿ㵟æ�Û±Úbù;}T>äC“¯Axð• ˆ?Áò…K¢ã™\*~¢–j§UÏ7�„8ôOåN­Ø�¯2G˜è¥×A5M˜ëª™†Sä‹0Hà(™®�þÏdxÏKp=OŸ&%Ç?Rõáld§º‚Ê‘;8Ù(ÊKøÓŽÒ³Áz™zhÌã�Ý�ti�}°ï yó¾””ÀRI^Ð�õLkl½rµ:¯Ò‹Îv0«Ž·¶û’:VŒ§›ÍÀÞ)˜èð˜ë–p9t&IÝ[Çš^‰E9~žKN/ñø¨L.õoólwøRQF Ôµ0ö¹ 7ïÎ0ºµÏA Î÷Ïöd“ "f—Ç*Œ¹³{T‰˜Å8Ò¬à w'3û>2c7ÿ1í >žQ«Ó©«ˆ‡úAËí œ®÷b¼‘w›qáQX²2Vl[./81u±TÛâ.åúwÒüëíäç} šâà€k{îÑ¿/?ÒÞ« ql5õ––&—â€÷ní3Zi¯Žkµx°'=žuYcŠn©Q¤mòµÉ¥ÞM‹ÁÊ*&¹ÿ\Æþ++Âͳσä³Yд)7ñ§ÑïÙ‹˜k258P/Fom;‡)íÕ8·> _rIÖ¢bl¢ †ÍÈú�lô2©Å590pw>>æÑŒùÁ´å§1\PKDþäU°S]ƒæ„\ -ü¯É_u2ä=�ì�r#g]›9ki.9Y‡ †1èp,îOåAT›2¾Éš‡þ`­p(”- Äxù r½ïH_^ãz¸ÙÛ›B0WG„÷äa33v·Î>*"?Nߢ׎\€Ï¶^黎‚õÉ4ím0ö,„“ÿÞ·]‘Hð7;X+JÚ¶›RkõYf[ùAFa6®”ªÁ‚îWØ¿Y�ë" ä3KH -HÊ#jŒ |êò"\c\_!6è\ƒù•{ñyæA*ö}nKé¡å&a®Ý_ª¸O ³ÅWâã¯'Ð,—#zÒ 6Ïv¥©bÂ8øJ�;œUEꆒ0×£‚òg„Ùk©°{^2E®¸ÔQ%‹y zŸ�ñ Sâ>1#Xè,9° ÒŠ¿ \é[LÜ�‡y+âàùo2^¸æ¹÷¢ÔlypÙ>·á¿’‡Ì�Ì,0í¥›g, ßn$ÇoæÃøBÜw1ĽE*’±Ø”¢P™`á¡Íp N–r?†ôôîcrÏq<Lé²W_é/1|�4ñÖ£vE,Qø—m'îáñL~ù·O—î'P³|rf˜Á¸5Š�ùëFÚ^H0“ û!ÙLˆ,ÕYНú§“ìÁy¼|Œ´îwGÿÌV/4Ri{\q“¾;,‹ œQvMA.Y4|žþ.E¿˜[ÄÊ»”œ ÿwæ–n»©oõ}Œþ“A£~��Å9nTsx”�¶'“™¡îB0À#Ôºé6?S,1 …Ämsq¸ù1ÔñîãŽäh:ö( ¯©Ð¡L ðíað°ÔLpSqÀ#_á‚Ð%�yNm ?XüG=O½w Wˆ.˜~ Gßïk™LŸ+ø=ï/S|˜¸Ä¼£E¿ß’ïS¶€/œUp8 a¡ð׳ý°¬ù&ýÐÙ‹å^íTÌ!€¾ÈáG m%®ãóWøLoŒX_)dr(V?}ÂX–À¢ Puù69|í0~9_Ä®×LaÌVÅÐiSˆßÂdÜ÷Ešyþ=“Õ¸– Ÿ´9w�HùN36úAìêÀ/ëîà•Ͷ\û•'àLÃ<ÝZA…›ñ†¯ çÞÃÀ½ïnŽ„×q˜#YAŠ~Ê£e™p"FŽ)]L•'p¾Ø‚;G¶BÏ“{øçY9¢×áÊÜ×½ÐÎýÂLo~AŽœÄ?ƒ°ÿÕ#6qg9ù¾t>Iîlø²ž4ÎZ�ÅÕXó£§=E5ïræû žç {öˆà?‡’Cq _Ùƒ»Á5Tˆ“ãz¬u!­æGÈ¥óGȇ½}i[uåzBØèc2�¤?eÑ�{ BîÞ¤�•òÁ.º˜ðkUÑú·’Økh‰Ÿ´Šñ×Ô©¼@ót¨å{eNê\Xc‹æ™*?mÏ*@¡&'<{óÙu =Œ±ùåmb×mº¶¸P¹¸CµøU—…Û§ë !í,\òMƒáD 0ÕT&×äoбÌß4âÏ)¦Ãö1ø7Swß|åЃ«á€fsý¨=Û!M½>Ç ðAò$ô&ľ=O]+=ÿ¹én’02• #`ìë%’>c;ÄÆrf»«à…Nc¼«‘Bo(¨#õuÇy޵lQÝ%|þž,5ÿN=} 蜚?ÄÖf9ÜWÃé�ÿ®î;‚Zuìúþ‰%÷ß“£AGayù<œÃ݃—9Ò̇àmS9I‰›‡Þ6nøiæ2Ô)ÄÃWü°èu0™s¤†Þ7Dï/±€�ïAzùz f  :†'„X³5©0øŠ<÷6¡¶sYÒ{m6/¿,O ]c4ÆÁòqœqP˜õWŠ7eª}X'üoÑý F¸2ņ~8ȇ ò�1å²�̦öXU¸”äŒa$ì:Ê¥�þMY¨úy�pMËIE�µq”ÄŒœ �ô:kêѺ«ƒJþêAýV;PØbFäæÞáOÞ¤]–¥E`å•ì¨ÇòBæS¸t!<»¡I…?è½^šBÆñNÀT)ˆ%¶ Ü…d‚°Í]0³ñ0Ø4·�aÃë†ë1� êa˘΅ðYÏèžÛmäÝf>ÞÙeºÒH ½k\°+š X’ kûx)îØ@UÔB âLM5ä‘Á©Ûh߯ øOú.9÷a!�[ÚŠBs¥ çàe,Ž~BÞ®ŽÆ…§Áà÷lº|±T§–¡rc”Emf$¶Ã�X‰³Ÿ í«½à£´™_e‡³Jë™Ð�Ò¼ -ÚI èÆWDè�0Ra=W‹ñz\Ãð�ù[ª] ¹N‰äžr eú”p®ãF69^†GÂÝ­ƒ}R›÷øã ç[Ã#ôÊrã´I´á¤°$`¨/æ°lê>y|ùè"­ÙãƒK¡¹ìžs[Çç û™Cزâ%8>‹‚o—ŽÇ<8xáí‚hù�ëð& Öçg3ŸO�…Š¡Ÿ ç�),pšÉèf[‘Ͳ÷ÚM41‡�T[¦v˜�/ÅÊjQT�ÎOÌqþ ï…˜ÏøÕà4o"!MTC)Y$±�æI.ÙoëaÑAc°NØÆHïÂ÷~y¤.xĬ˜ß<æ‰kbiÆu ý‹Wý>1ÿûn¬àÎ<îW„q×§�Oš5‘-…3§Ì ?í T²’ûAyÆ:²øÚ!(:™C%…§Á­û4ÿÞHQIÇ-)éxõh:5J/¥p¢„0:�-Êy´*|>Dï–Å•K…yá>ù$'�%'›µyªoXÅóÙôxg,ˆ¯Šzf±$y±9x‚rØš»ÄŒ�Ó[w“ïEÀ©·ß>=C*LÞÔßú0ìoÏ� 3ÐzqÑ¿z�‘Õ¦B qd%ŒýâÉò\:qloèQÌ×SâE0ç$¥èÛOdËøT¼6yN>O´÷­ÁUѤ² îÛÍA‡µ5ˆ;Ž‘wò=æ#¢襪K†2 @xEu›m–×`¤÷.šmˆ„ͦ!ìÄSu°}ÑJ^Ÿïí÷Øò§É5,=Ô Ž·6ŸgÑD"ã:‰PáùqyðG*^Ï­Ãǹz<¥ý¥(eµƒî@÷s@·úŠÓyÙK@ÞE…©LTV“…,Þw¾ÅíIçtkúØA’H­½Ã,»G>u«Ò—»iºìFÔ�ˆß«»!\Ç’Ö(ýÇ¿ôá~+àsº…oVÀâø‡lWëÊ7´ÐÃ_WaA\:ý½ô[¤Ã‡WR’ CT�hÝ”ä (¿ÝÊ`±2—*G» Jé4ð6-Ç9—_וÊеK�Ûôò2:^2ƶñ‘†ÝJ{`Ï+ ¸?£Ÿ�’‘5CìäIÜ ìAwˆ×˜¿P—vVݼÇÒc§Àö¶/ÑWÊEGÛTFyI4¶—Òìónh5?ƒ/…AØ&g¸Å_€üît\F˜vàˆ…Ýñ#,ûJ†+5ð“scþ x­²…å6ý¤ûOœ‡þ-�8Ê$CBäÜ]†^Èîó˜(þ¸ÁN×sžyáæíwɃ­ôSnú¿'ïÏßf]Ï^¥ß4£ˆ‹ Þ› qæìd{ ¼w/&rGBhºõT^ÚS¼R’ ¿\/ÒÓŸ‹°/¸ }â>S‡‰Hœæñ‡œÌ³$[¿nÄ»û—ÁÌ»yXQg…çH3îqJ§¿Ô4éàá#Ø—lE¥B×âi)q¼žØŒíš‘Ôëx+nMë¢ÌÅfP(†æë ÐíéGŠ81Hkü`wj¬X—ÅÇð ü;`ÂëK¨aÎ~ýŠ…x–±çpáœJ IÿM·sбwÝݾ΀pwb~K!¡ª0—œÅ§jþB‡Öé¡ïl¢ñ] $tû^dö]aÞ|^ ±E5ôëðqÚbuVw€9o z§èbÒ�µ4ÇÍ‚NoýM•¿(óª,m¸{“²Ó1nr ¼>Ôõò5Îá½™÷Šª¦"c»…[®`V•;®Ì>G‚ôž‘¿_gà¡ar�¶c‰—ÿà§jyœgWH·DO…žÝ4K¾¹Øþ:M´¢ô"~ ÙÖÃ¥ph¢…öKEp¦]ægœ6âÕMóà§ÔIý盵G0ƒ‘áÚO]†xäÜëÁÎÈC8mÑu*8ÿ*½ò¢¯Ý2Ä~ë ªSÜ ž>lÕd$›>ˆŠß«Ét¹C0ZdˆžRÅ8îÝGÝjõÐW+j%£°òu nýô’Æø‰â’¡ª ÇÉ×û�ŒÍŸ:iù…MwüH;—€ îU!^týÝåôôÒ j ¦~v ؽù×ÍòÄïUe�ºê8˜qSóQÐã=ñ-„ØÏù ùJ1Àà<ù*Ej–¾¦ßwo ;cÜvßTüaqF*·Ì‚JÕá%Ÿ¿c£·6Ñðì*L^RŽ.•²øê{2#gw—¼ÔªÂªY*¬ùúÛxlS2®y’Í\-¾únP±�⸴TnÒ,‘e�(¶›©ìã’ykRÐ÷W8,¸u+YÀÏ™[¹’Ü“û<˜9!©(+¹|•КöÏW¡P\/­] uÖϱ~ÁË©1Äü·&ˆ«ÉS�jôTÏFHˆóbíî•9˜îR(°u”v¯r¦ƒœL—@¬\lŠ‚™ˆ’~4H:Vá¤Z6¦K, ‡�o©x|§ÜÛºëõªXÁ½Sàíã×fºê[QxŠ.U8¨Æ\^¾–lhm€–ÇøÊ-„¤^j†àýYÈÉXƒ�wÉÙ4WîñµqLQ{<œITã–“ó>Q½3鬓ãtÙ—}àdd„Á±Êì‘qRw§•~ibV»&ŒÞ‰cb Gˆ°V4U¸³·a®º Tü¸Dë!—©ý ¶Ù7uQXAˆ½Ö9BÖA8æDÊóX£ÂEÅ(Þ.�Û káà�LÖ½Ú þEÆs³àµûvøÎQÁ}S ñÚª7Ìz�hã?Gæ�‚Ùœdæ®`,jÌ‚_ãÿ�Ÿ�í·åË$¹†Á¹lŒÕUòÃàúŽ' þ™Eã/Ûý(ÿøæG3‚]i$vi•ÿoæBÊ<ò^¼à䈧]ÇIöƒH²jÛ/vgå$Æ%1rg³™NC%°ýr}âôxFôú}røkÌ2@Åce�\»¶:Î"ócÝð ÄÍVê8»y7þK$íwfÀñ½áس®¥dj°oû˜ˆ´‡÷óCÉõ4(KO�ù¢Þ„Ý}�Ö%]ë�bäœþ"”¾í‡{Ûgâ´c"(5û+Çý€¯±,«ŠkiÈí7˜z@9iOAº` bC7l™-Íd;uw›‹ö—ïᇫ[±[o-{kF ~ÐÚE7ö‚ˆ� ÑRgKLÎÀŠ?1wÍ�Ö'È=¾»l�²q§íÁ<­·݆}:´ÒpÖä;�ð#Ìçï�k·OƒBÿCH¼~w>fâ�^Ó¤[æTm7�®…0Ö§—�Œ”eà&\ ®ẨýxOA£…ÁÛ §`î!!hµ€—Qé(,þo"ÖÀ­Ò­Äñg²Ë�Ñ>f.‰~æhm·¢öÓ©J�*Fa}Cgm‹�5KyªëOÿ.'NÚ•¥0ç²ñžr˜˜º…›>¿eƒ>esDöwÁÊ©¸èK<|r~| –0/¤š臃ZÇ6œ"…Û ÚÐIT}­¾Ã×2šgøݸç%)˜—@{bCت,-šsw-–om¨‹û`‡¼"M0�Å–{¾Tæ.P, {fËÁòÃoˆÐíiøH-J¥fsŸŽkÁ «Oô¾+A�ŧ mG ] !Ñï™MEé4¡EçÖ~¢F7 ¨Ï}\f:ŠF«�@µæiØìjKî µ éÓfü;Gîéq@ì¾®I‘å ŸÑG×Ï©´Gj?<½VAeÜ%ÈaéShwt˜d]rÂù]jxè]qféµÙ9Lô¡×p±,žcíÙ„Þã‡è™1+r+Á‰¼Êcûl:iñ¼hb¡o“* äõÎ|RéGEEÌqáD ^i=O¸ÆaÅt²Âg NÆØÃ—£» ¦n)Úh”�å‡,˜\ ¸Tîø? ý¼'ÌבX(Ïã�X:•wAoniÑk�ix9Z™W&P†—àòÖbP{$® δçeþØf¶‹ójLž9Šáå³Ñôój·± wÍÔ„êò²ØawƒáàshåvG«uàŽ_ø—†¢•Î98ós&שσ±� ]çËY'en¶óˆúÕ�º7—‹@Má>#ä—ƒÃ3†PUk=<ñ·ÃW–|ÜM‚`ÿß2âuÒ®ibP�‘éâ�¾—A/èn€{~�T=°›�hbN]:Ý—_ÚÙ äþ¬3ÈŸ¹˜ {еO*!¬¾�†ÍYY•3 vµ#•8Ú@‚r”èC: «Å¹o’î³5â0CT‘þ‰ÆHÇ öÇ4Gð—Ÿ nµÍ4ºØ·pÒNítÓ)OÔ´Ö„ŽÜXTÅÌhdvžo€Ve[ç}8ô&‰ÉìÂ3œ!Â|&îýŸWe€NÕ XÒŸJÛ¦ñÁyÉFòõù)0I{Àw�ZÑýœ-«½pkÁ"쌚†£yh"ØMD߇À˜öxÃg›…øÚX‘ÎzJzžé¢gòe¶¥¾�6Ccî—&]Wã—£¯ó€ô¯ §lZɘØÌ3_ œ³@ÍfÖ�÷åbp¯êÆÙ"…¨-6F•Ï�£Ú&Ï©¿•»!³‡tiüãÞçƒdÃqQžÃÚ“¤/Ý ™šÝtÖÂPâYßÇžH¦S¬„ ýi¼GyÂpöÒ†¨Ž|ø£’4×]§‡ø¿’�C\ì;igCé;²š¾<á�kVéà ~að˜@Â:¿e…Êëá«h;.�ªÁÜoßèÇØÅ`šaé‚ Ì>¬_( •}áX/:Í\V, fTAÛÁðûÔJgyïƒÆOT5ÛPÿÞr1)ÿÐó“Ua× 3Ê —Řê"4+|L­ÚÏâÂy‰TlS| ¹�EçaV}1Z¬I‡É,ÒNü0ër؜م3NQÒä©C~EÔpîøBW¢[Þ GïM G¥Ï$¾}+™�ÊÌ—?u¸è~áì߀ü†Ÿ@N)Š /j$æK:è)Û!Úó9¯�l‡%KÝi¶k%ö¼¾A§ÿŒÂ¾gZèš%�Eƒš°õ¿P˜³‹ù÷¬;ŒXÁ´·y`YŽk¸x[C™ô ÉcÕÜõ8jÞ‹õNUè´¾˜¨È8@Bv5öœ2 æ9¬Àžê%UÁh[è!v2Ì>³%o¨‘¥qôûaLc,ÆY=Ç�¨e®€Š©´ÉˆYm{ŽBxZt3Ä4É �ºª¾»—d2Eê˰ýÂ-X4Cߦó›çEæ“ ‡A†µ;Y{['ü•À"Õœf¹akq<¬r›ÆË~&w�MåYU·Óo•ÑP8·›èyŸ¡�67¾�÷è܇!ÔFê©(üŒßKþBT×H]ÑCjBþÂÑã¯É×ÃüØ/7gòo6 L¿Šóù£—ãe˜²!Êg0k½ÝïÁ�¿/ $¹ÕPc3»?ûaä£>’[ª J7‡ÉâGM§ê17IªÍ T½ €"_ã,]Üé¬Htbè�ßb }Ê—>9¿ šýÃç\è)}ÇOƃµÑ}zêº^Í$¯m·Ò²­3ñË™|p®gÈÚSxj7Ã%yôñ“å¾±qÁµb\-ý4¬8¹VþZ†– èM‡ÐÿžŠ?¿“ÕÛá”ÓÜ­uƒìRJ �{ñ˜×yØæù“ª3Ä¡[pAÎ\\b_„Œ† $'h¡r%?¨³âhuR–òɃÊä¢QùŠ{Y÷ÎüFýø¥©¬¾-HÍZBî”ÙÇ0n˜£ x'|eDóÇè~”N:Ž“«£ÀVH†w¿\›Ög�.õ¤ü–;Éë7·Í%vÞ ËSŸ‘Ö$¨ö¼NZ÷üS´ˆñ(ÍíšË–É3–G °2)¾9õAÚÊß4VJ–„ž¹DUw†àð»røk>çÄž#y�þT©YŽ4tà„ój4�™šº�t sˆœO›ŽýaÓ@²m ìåç‘Ú™jøÊ×�l0駃¥¥tò†2š …`éöFrðÕQz®A‰yæé™ç}fõŽ´D¦áŸŽZ¨4Í¢Š;ýqtÕEPÐsp‡ØmiTíãl &1F¤Ùo?È}‘£#ã=T9¹–ÎóІÍ|r¼ŒE>Øg#È ;fO—xv±w¤x/ï¶ â ñOу×9]¬Ø$÷µ‰ãéõÍ`%>‡Ìòçãê�ïÇ‘†…0¼±™éþ­IŒ_–°ç š¨ãÂ-x»k’šÔdR÷Á”dË$@à¼"ñú2±ÞaúÅ(ß[ N¢ùèQÈ�›ê#°`ÙTîæòöÜ¡åÔB,¦c+U21ždŽD˜ÁÝ8”¿ú�íwRÃ�?ÏɇoãìÕÈ{‘&V~ƒ"H|ɬ‡½Ÿ²Tr˜;˜ÒÁ‡p=Û&®ZR‹‰)Xþ£�e¬V ßw-6pÇ1ú¥ˆ�·Ã…¼ØÇ:¨îÇ©ÿ­•7 âçÊ`oò :§–�;–¿ ò"g€áµd”¸ž‹qåÿ»w~9î÷Âmo/ãoÀÁ-9�Ø´„kVŦeîãØ·­„¾¹ïè†U& 5¢øªV„ãuaοŒ�õ!ŒöÙ¸æÊQÜa»×mU§MЙö•µWÍ¡ü=jð›ÿýZ¿ åE>!~¼ŠÊBPÇ�Oĺ vv†0;霂nü¡¡Švwª°4)ƒ©pv¥]RpÅ:}�TËd'ÍÂð­ƒ3ÌÕ]‡ú©”T¾¥OX<ûhò_àê â¼³š…¸`Ç(;ÿÈ ªk»š.öÌ$"© xUªlôa^ôI\:SOÈnAi£Ùb›Œ÷“ðè´¯m—^üyŠxØÝa6¥CÅ·E𸫭ZŽ’o˱¦O¾Óº�HšdÂ39LnH�—3¥ð!_;>çÀ!S�—¾·vf2¿÷GãŸÚfØST�G&rѤʅ¦íýˆ&’·Qè” /`O*(ĘO-µÑªÐ%XtåþÊ„ÇbjèY/Þ#føÜêé¹3Tl’‘v Ƨ³­k,àJŒ#š™[ãièƒåfæÈqåºgœFW™QòDFŽZ·[àÝÅCà¼"õW€ßënz7)v뢛±-D‹nïi·ˆXœ9ñi·Ã_»o`o½4ˆ9CžÂ›‹yÔxó'j­Ïú{oâÒXAn»/2?Å{1‰õX)ú€\òë£iÕš8�ý ÄewŽ6’wjÕ4áÞ1¨s¨gÚrl¹;Bf#žZÆŽìΡGª9X꜎> E(ꥈYóëÈžw­¤~ ‹˜K¥Öè’¯!а²"nͼ€3ä èÉ)šû+€¯°'¿ŽOàÌ-òÌÂy’2œ9{1=õ ½yQ7Ë}#æÏÓƒW|ó÷aäÏ 3òB¨ßé=ƒ©ž9DJó ü ñ€JU} Ö Å“¡’<ý«=x´TÌDGÐ]ò ͸`IŠôö!OŠ¡Å~ÝÐÛïGZWv�ˆ'ê 9ËãÇExcAaøÔ:–­t1Ý&¼w‚£�¾.R(¥&}"ÜLU#º³æé.hƒï"aÑÈilì¬Ç¶×�8 ášCàýúµ°)÷ £¥ÆeµEKȺ(}X⺊“ÜY` §,Ѝv­—š �R1S8'&ǽ·ÒŠ—åÁ­_«ÈŒOÿz ßÕ[ë i’s¡ƒv8*®‹i/Åqÿá|vE€7lð{„»�Ôã¾;F äJÞyN¬òÜð¸ñ,â§iÙH·¬"ÜWæã9-\N® ¯x˜…Ò¹s³Q5õ/�WyÊêR‘‰SNã|¼Ù^@=lÏcûX™Ìm$«ž¼gT'?â>‡cäœç%l0“ÄyáõXӧ޲ö‚DâÀF"q®“ä†=……‘çà½ùHÃ[–î±Ôä lÙ;¢gp·^ã6?uA‘•÷I—àa"á·kùagçM´ïbé»F=HNê'zv«ÁIk5ôˆjN‚‡øåÛݲçN$1Lǹ 6�MŽìTÝ; ®¬É&¤©õZÇ>Y°ò¿þ¿Ç™­OIÖ"~xÖ’I›©åÿƒ«Ÿ¥¢Xd©çs„˜Û_8¢Ö º|NìºQúv¡/®üð�-ß,Á356BæY+TœeJƒQ'QN&jƒ¸L/ì àr“ß™âÆGG¢„y ݉Æ[%Øå°&L§µ…7áfy1S½ÞÎ.¾‚'Çn4ÈØeÁl¥ËxÞ i’l0-ýKrMåPi¦!ï·Õ+vFÄ#޲\»òÝ^Ôí4G�IUÞÑ?IàÚ®HÏ}œOæ,’ãÞQL ÎØÁó� ÀÃ>„™_´¤ì„¸±ºÛÐö‹ÊJ7ÕqÐðnЧÛ:•P:zx¬âÖì±€´“þ°‘X©ù×KÎþÌ —už~»Çc9.å ´í ãgõÉ›ôQФ­ŸdéõúÀ/{’Þb„�írðjÏ܆£äyª�¤â},F¾�$n U­DmßûcùŠ/˜q÷(v‰žA9ŽÎþûw~=�kÃjéü žÖP"ëÖ«O]F�qVè7›m½”J\X ˆó»£ƒ0öuËÏÄ7i6Øþ˪×yQà-üœuz‰ýË\ÜßCl‹%yÚå¶$ïQ:ÙÚ] Zw4Í#*±%B.½×ã5'�†YnAÌðf¯%© :}A-ú.…–ºPw\­®î ž¢páp)\ÙLÜÍ’uÍe8q ÿ¡:öñ?jÐéÍ$‚%Â`¼@[žyÂÎ OøÌßNÆ6¶À e oä–¨(pâÅba¡X¾±…'êè úl”®«£gn¦1mæ±øÐ€âzç‹D¶ñ36ÏžÆ:ÿ—‡F7GîêSÅ›#зc-Õ�ó¥%Ÿå¡›ÓPoÒˆU’ ÞšÙ(nR;cýicñ%š³ÿ ¤àz)]ø¯s {Gî6»˜¾‚=ë¿PåÓ ”ÞM­{ñ²� .”�†^ë—ß´ 0MÃ_p¤¸QKªxÊx(�%¿KÊho $\~EmÏ–£VØ,ºsV®›ó GGËð…Z $v•AT°4×Ôb>|ù­Çòh•D(ÈîÃíœ8ð �˜:Ò-�ò ÝÝ„ûäó˜ÇëòÑ®O�çÛÓ %A"8÷joî§—Ô^™u®ƒµÏÁޤ“~ÍDqÒüâ,yg²f ðãôSMÄLe)¼=¯Ÿä>…9ÍĪ dvêâ&ŽÎ(l„³cMÄ<áÙÔêѲ‡?!äÁT|h\Iå…"q½õrZ£Ç*Žx’ÒR-bWü’W=†Ÿ[�‘Ç Ø, ŸŠÑur7”æ�S‚º0—ÿ2ýèü“j)Pl¹õ”¸ºy`¢NU.}³Åxêã,}â®�Ó#àvê#Ps…È·þ$Äÿ|z6Nn\NGcÔéðÆò ö iL£y­¹xB&N¨ðó²g+âWŸ€úÂU2XbiC$ScIA´h¿Z ¹9¦YÇ9Ú²×n’GÅÖeèžäˤ5ÊrïÍØ }ò¶4x}4”,B�×?ð¦·%ì çÙ׿¡ç*a´6ׄ$ïnZµWN›Â[¾m 4Õi£()$qÊt�ì)´zI³êËY½‚�ÌõäFÐM]ÆÕciü”Ø\tÎÇ»`*[ÉyßZZÿœ=† ÙxM{#Jµ0ϼ¶ÒåÜБ…ñ߯3ÙË�ï7x•¡+ „¨4G�JÀCÑR�"PÐÛ“ä‹£³ê;ò#>œù%Œ] æô9"Z<n¶ª<¾uñdÛg(Ú€¿�Bé`%¦0°­2‹S`Ò0ÚÀS%>æ²PôÝ»D¥¾Üež|àœ:xÒÍ̱ͮ™¨þ�ƒ[ÿ£YKwÒ‰íl¾~�|îÁ蜇ù•åÔª¸ž,�ÏG2ñ¢ÿq"O¤Ðû·ºñb¨ 8ÃFx,›kÁBÈô„qøLáeà“Ê{$ F®h(cUâ#Øa4øÅr°©`íÃJésSC0jI¡>oã$gly”J @ˆô´< EFmh\1L¤ŽQ•ß_èà¬fäþMÄJ‚ðÎŒì´ý¶pzLDr§cŒÖZôÔ¨D«M¯™”¶_œÕµÞxkú6Ô’•_C=Ø&#ïnÀÎòµ(h—Ä6ûÞÀó‹WÂé©N$;© ¶m±äÞˆÝ ¯zþ�©£éÅüóDIs ]à³€»à`»có[vïÞSd¨ò ñ°oĩ̕ß~”á•¶…!S8P„l®t0\×]ɹ"ˆõO‰d{:=do.s§C©s;Ii$› àÓ1R¡ÿ–_ 8Å‚ÜR˜Ž�sCðUÙwz°pŽKœ%=££õcµÏYãa)ÜÑ)È»`ý’ZQÃZL+Á]}×È×çKÈÖ'ªP'áË2™ˆ¾ú0îHo§�{x…2­ô�ËKÒ59Ëù“סÔkEU™~ƒäúv’â ´q¯¥¿$mP¡ô=é›N¿Ä®Æ“YŠ8ºF³¦EÂ߆ ¬úq o¥ ¡øŒü•žå5”/êFóø<:£Ú†¸¦]£§:ñ\f\y)J+%£añ@Jl®Cÿ>jmRMfNgvöªà·ÕçHRAUØ4Fv¹•Ð*åwl®Ã�ÎÓ!ÇnµbÜL¸(ÝK–‰‚¦AH.Åãí·¡nù6ôk£g÷.ƒeɉlÚëüôµ â~ë“¢ÏIt®¿—X ÛÂiÉœÓtýƒ©`\àŽ«åãÐ%_"7ŒÚpÍíråf2üêì†ÿ”ž"g¡¦«cYçd“Ìò™ðööYòMrêÚ¡©¯ è„UàÉíwÈžVkü¶M„÷ì¹�ÿÎô6žÀÛ³¶ÀÕõêÐkã7®‡`—ÃXwñ+™Óm†R¬Ì?o½K]ª?RfÆUtò*fã9Çq‡ásªÿä%˜lbwÉ´Ñ)ÛWQ=&²ïšÐ½ó.0œ[UX!s�ý¯Éó yHD, HÎÑ\<])ŒÂÿ­9�:6ñš?=\IJ_RËh÷�xó~ˆ–e‹pµ’¨XL }?v‘PÁIÚk¼%¯»âù»g+ËÑ�ã� 7Öà€Þ@}â¨�C¦˜Íƒ|šIu¥BèâoôÝn;üøÁËö僟Ñ.lŽh�:"xƒn�þB93~°�¡�&†VP;ežð^žÅê¢äÆ8äÞ˜Á»]�žmw©ú=vŠgŽÆëâî�sàðÎ:މ·&x¬ò‚×ٺ࠴õ”`ʼnnº2( Þü•¤Ÿž ²nŽ—ˆ± /ÎjÖ„ÒouÔ=ü2ôæRÃÞ.fß1wò]t�ézÇ¢È«ÅØƒme×Pÿp.ê¿�SV©Ò|ç'¤eΤ;¼Ÿê&Ñ{..4ìK(èVìa …ÿc” @zë<™±l¢PéPT­9WšÍðÍngX^¿ o«ÆÁË1qÌÒð!'vžÃÌ’ºÂ_Þ½­Ä¡G[Á\$ôÿÿMú3RŠ;V!c:^Ì;Œ§¼Ûé'%¨x«÷Òþ`–5~­Ndîž?�»Üö“uÇObqe!ª¨ñá²@ÛO]¥[TcæÊdz$[Ç,ÎâŽeOérµæ—ÐE¦ãº D”¯Â¼ŸI¨ùÏ·Ìs‰àëv*.!ayiTÅÇ”9jÒF£2XöoÐëêûš %œÇª“ùÈê_…ãœMà�`‚"‰òD"Žû¸ãÆ_Xö±•×¶iSO;7º>Ë<|ÁÏç<ø³ø=]Q³S÷|¢¡JЏÜd’œ0WÀ%ïþcJ~Î' ò>Ý‹V‰|'�zbËX"­ ª?­³lÇÖût.+Çu9}§ÁÀ2„–êËãp¬;ÎÉ”ÂS]íDÜ#Ÿ®ºó�ÖÜ$q—T1¬x ûñVÜŸU‚¶yS`J®�8Ðn_JØ|ùØo2Ae:-h7M#Ǭ¦c†“ ëù¥7ýãUÙMêÜë盈áÑda� ·Îƒß<ôVÀÎØ`2ýÔƼ1‘kÑa¼ú×£¶vr¨î$éVåç�M+©4kz\á~ºlŠË‚ÁÑ�HüY˃/Sð²SpT4 Æ\þ�ƒóþÇú{¸‘BÃ(•™áu®; )ï4¥©T¢ÐP!{Ϭ²#¡$Qî×¹îBÉJ"•" B¥�Oßï?pçqÍçó‡s6Ó§ÓàÝh,õ,Å÷ó’p|6Ö~Ã�#gð�þ,Røb#ÖWÁÚÓ_X»z¨Xwv?¾ äñ%œîT º*vL/›žy¼‘Ê1!{;žÓêB úø�?[=èó‚‹4ê¤1jØÕÓï'�`»ârØb¢j~íVÙý1Ñþ’Ê^ú>=³Iœ¶4„%>ƒMqÍ�;ç)c}¼ÇfD#óx5Ô—ÌÆ˜=½Š]&J·ŽCÝ�}¸ê\&sö¯÷®£*ö/žI'2 iåî¦}yðåàW¿`-ܬØÑ×ý¡àý30ÿ- )§Ó¸®BQLÓ? ô݈ &$Gd=Veù¡ØN'ò¬ÌŠ_í�Š)?ñámºÛø1¾þ YöW©²± ,ÌsBŽ›2LžÅ#�®$Ø»‹‹¦¡Ç@ÝjÞA[UŽ•Øê6dAçX;Â+ɇxRNEÏŒ±{®Kñü±C•.hÀ™…�{á\I¶æ®MUcþ;}Ÿ9íFnÇeè|9ŠWNô@ªf6­ë�¤K\Û±Ýä/�Ü ç|ãÞ3)`Þ„ßã×À>£”þI6ð`Þ¥³Øæ~‡t‹D°ùµ54¢ë cç¯Ãó–.FaúÀì;köø½±Ãû>¢9“C+sPïI ȽO‚¶÷/©\Ñ;p9wMä2°f´’$MëGÿ mÔŸw|Rå`“|%ÎJ¸Ï5Ÿ5‹î?Ë6GIÑÒÓþ�üoÁš;ytÃô Z»Bâ3ý㯹¿™é¦÷™jtÚPËŽ•’L‘Zhj �³iîeªÉ›8|’¶–†œ…š Ó±?çd¸úaÜV?ø$ÞÈì4”Å�›}!xÕ;jå>“§ºü)üÊ’ÆÑ‚F2å³LÈ" ó21íÑÖúçžÏ1´F_Ç-†Ö†çª=ô/,:PӲǩžð<8⹋hzúS&]²�2qßcÆ?¢¶†û‚¡Ó5zéeª¨Jâm'€ow0Ac:Ñãu°˜œ‹Ë,ñ�Â+è|ŠÏxì+ÿod"x7,9Ú]Ï�ÙS…÷T•é!ÓLÔøBe¾¤Ò[Þà;Dèà%¬³ ¹/y4~¸›^]ÖK‹Ýb@(¡ÔÔ×5¬›±˜Éµ/‡¾ë†Ðô0�þ÷É—6æ}#'«~’)¯òIσL>¾ŸèÝmgí rÂðùüRìR_Du¯…àì;eŒÌX “&—…íjz |5–¶_VbKÂfðüÒ¤Hs6JuÓ»ùÝDÛó©ü|˜6IDbéL~Þcãh•ï%v¿3èͲH xFݿϡI _Ð~E6ܾõl-Dá#Ѝ8/�Ô¶�M‰Øh¶qÃ5b? ÌB©åÏ£t—Ó3|b ÖÜBT™í¶í~à»u¨]‰ĬúT•Ü�sÎÜ'S,”!Or„'âþE30;ÖŸnü»™¨-^Lª‚�Â+)Y¼oI-m´º¦•öÞ}K¾Ö/Å!édX>ö‰�9ËëŽ�$ZÃ�ˆ¹B è¶ÝƒE;÷âµmZÐvÃ]‚ÁNáÍpÉEˆ“÷+…�f/I¾7 ¦Æ}¥ë>Ý!ïÅÖ¢PD4£‘í®éû!짨)> J‹/cáÁg°Qué½ú�áî€ánM<¥h‰–Ëà«=:ôíÇHºt`œŠÌ�mZHåóГ<d¤º‰U£>\ ëbz7�ÀÌ|\IõUï2‰Æ×©lˆ&ûK-ì£0ßËŸŒIÏF7)ø[¹Š8þ~K=LÑ�â�W‡1z¨Z„HšÝ/`y™¿$JŸ`›Úï@@añ+ËÆ‘Ù¿‰IÏŽõ¬j´-‰ýJb �‚µ&ÀÂΔ}ΤS¾{$)NŠ}žbý›Wðó¨&^âŠÑ�‚¦x(Ý‚ÎG€ ý$=€‘ÄrE/=iTŠ'ðwœÍ| ÒŽ À©M#38˜Š€Wdà †œ.s„â .úÂæt±(H‰¥cÒµépY¨ŽlB‰Ûqwý=�Hê%®¾Åø«Ÿþ²@_÷›ŒÆÜ¿à i›å ›ŒhÎÙ= §Z kwÏÁïÛ~].>Ò™N®_˺hþ8`ŒF[—Ð}õñdÏtM¥�+Þ²¶øÒlÛ*Б>ˆ+—T0Ô+¶$Ðþió˜[‡ò°å¿¹œÿîøß=¨¤½ zwË°Þæ’(œ‹ÛŒÿõìæ$�· ö:y’•+Ó`é½›P¶÷“o¨Îü9 Yw5`‹�<~ ¡4'ŒÝa žÊ㸈 ŒEÈR'yqôþõ¸€ÔG°]cDŸÅ»¡]°*vHIaÕº ¼•?‰Å’ùôÝ>gˆ©¼JŽ�,Ú¼ŽŽÊ]Ä�NY¢÷|¸Ó�ìÀÖ¦€NI¼E B®2›6N‡€Èyàf NÝ-½ðÓÏRX¿¢.o Åq¢KTW À›„nfvÑŒl¤0Ãå"ž™>²r¼nÃ9‰XV "¡Äiäï`AÑ Øã'Ä 9ñ€¸\œÃ ûÌ(QÉ‹�ðö�’› E5Ó©ðl ÎìÜôÌÏv,É;Í¥©‘äqÒjÒ}~¼�÷Çú÷ŸQª³œ$®B‡,3T.o  ËÝ™âÓèç0Ï^|F•,вã>¬¨³Ù�ؾ>Q·ÿˆê7‰ÏEažw=u¬$¬È(¶t‡G/àòïSpN¦:ü~½‘šµÖ`�¢®}ÏGß…‹aáÒt|²®”�ް&¢-Ÿ ¨´ÿ;+n Ï9¢…^ßf }—ÀìîYüô¸ÔÔrä2-äÒÆµ´@çz‡H2U¹}sd,ΧŽ-ê¼Ó~‹1¼ï*™ÖÜB£ñõúŠO\«hìeH©×Áæ:8ºâæý…Y4•/l¡_uÎcc <êjEž«Ì~½^ó-çÅô\Ƈý{Ðj  #�Óç“ $É4†.>"�ê¯7A’l3\aðâæqÆrbn}_ˆð[”×ðî¦QªÇತ¹P¬°‡ŠôÀʪƒ¶¬¤Ï•hGÕö©ü_v~t Ô§Úáòá ô´JŒÔc·ïmÐJ•¦oð£D¥!Ѽüƒ¶ ½‡+�b´C¿´žÁ¿¢Y°èA,¾u®c‰tàZ3Ù¨hºcv ؘ…|F³�O¼åo|Ev­ $ŒÊã2¥H|·ƒÛl5ʬê�"ÂóDi1ŒRõÇÕ$oÝ1xãçŽÝkM¨¨­oóÀv²Ö4÷8ÓGc®¸¢Z¿žçìZmׯ=§jŸ¼0ø‹8]A+``W Þh] &n;±ª[ M�$Âá5Û¡¸ƒËžÚm€ëÞ óWË郋QÌ–Ã’—ùQäÔ\8©A5ÄyeRi˜Üë:#¸9Ôrõu;L’f›À¡u]Äìû-×J¡öwáxŽ.õ®îGÏuWèò!¸¸­æô.„ó‚fÔ¼å •üü ."ÿŸ%xeÞ7†^ -½ñ™=´(’Yb{öޝº&ìn³Â·ñ—é ¦”¶:‹£˜๲H�BÏ‹œE nÀ¢WêŒÆÛ2Z;ôo¯{íC‡˜lôíI¢ß¼CèwÇ3ìÒ)\~îÛtç6ý“ö�¦%r™i ¥¦°ß�ÏS†§K[AÕRÅ‚‡ î¨<¯f® d4ÏfB'¯ÓU#k)×X”H…2SÖ™ÀªoöÈÇ7“õ|¹—®¼DæŽÝ&Ù‰EÄ,^ƒþÐ.¦ OºÈ�¤PR&Ä3ŸºƒQ1<ÌЃ]4-ZÍ=ùxW·O¥ßŸêcØJ;äÌÉyÇrzÔ©@DÚTœÖ1 ;ý_ᣵøçD8y7õ Ú‡›‘SváTo 'Žà½1N’Á[ZyÆe*Š©à‘#hÐhɼ3(&àòˆz¼ ÷ðÛrè*þ» ÇL*Pwê×Ph.õ›ÄÕ±S9ÖÚ1[ø&}|þÕ¿w�–oýμ·»;ôù¹CóVÂ݆]Ddëyê˜�co¯“…‹[Ù³²»ˆîP\OgdûÂÛe¿Ù+�öS¯~~z]¨íôõ0#ðàRm í|©Bd„<ÉìE‰xØGž®ß= £¤5ðÎ ,ú5‚jgÐ~I$ñ¬Ÿ]Bñ¹0 �«ý¥SîyRó O(K(£—NjȽÔЭóBŒ�!w@7ˆ{ø�ã½ÉçøÎ&‹É%¢ð{6 V¯}Ïú˜Ã:]}EƒÔÁµÄ§g�Ç홨ÍwVÚn¤/ôm�³tÕ퉥çž2Ö]»�vÝ#¹ìÑ¢4—4a°¸•Gkm±ìe&»™3 û¡‰^ë3‡³…?ÈÜýD¯ÉÏEëC W%pk¯q3o4‚ÈÈÃúLxåR押yAN i ²YɈwç“1Krd¶o×r>øû²Ži·ÎBÇÝOAwú%ô–�A7š,„w~-HŽ­ÅpGó6n5��¿&ö‘�°�”™åc1?“¨mŽMi߃‘‹[ ûd*n7¬‚�!®4¢w/$þº‹FEØ—Nù gð”—8£ZL4}f:z@«FËဠr³Ö³gKÕPq~üüðšïÃ}lÞ2Õ»*ìµ< è#ü"·þÃ";nÆÖ NÇ ßõa˪Üte¯pa.j$¯ië»<¬ä{†pk'<Û#ƒ»f�ëŒZ&¾t‡N*ÃpëRžoOYQN6ðß%‡¶‘;ÿe®ß�åí«Q#w¶´‰Ò5 /­‹S'ãðŠop-.`hÙ_R³¿DÑinGÈÈ 7bíwŽè+‚ùîÿ¿aàNÃÁ=0—+§L±"¹½º:K�Ð�ur»XìD7âñeØÎÕÅ¢•è F’ÍõácÎI§+`š›#w½#76Eà+Xu¾X€-Ó®‘ѱõ¸üêt,^!†_ãóhåòê¼9SnGPíì1rþÇÂû.@Æç”aÎGš(¬Ï\Æ%WZ@ï´6l¬)7ÉÚm�V½eãK9m8H”÷Cñs…LÂŽÅøq¢•Þ·S¾¹nX&f…6òï°Ç:ƒFÓ¼ßvøAÇÝtLëa ¦á:Í)¼'#ALS�o¥%tmõÂxþD@Ëxºc¿8Ç";€ÞK2ƒ»67p8Á6Mí&…§>ÑåëâÈ(¢ZÚ'±Ó—G™v-h:½Æx¼9œNÔiAȈ8¹ôá)qÜ? ¢9†àù^·¿Š¥Î÷eÐÖ±ö+�SÁcÓébf„u>k‰îÆ·áÐáR²x…>Ø2ŽImDÆÍ ®Ù÷`�,�zdFeÏ42—”ó˜øáEȹ²4M2ÉúøTÖ$â>èoÏ#é‹C Ù»W' ës¸u:îÙcL®^0Ęû‹™öWÌ“%r�t›ëä`2’¸þ`&<ÚÛŽ-Úaø5e&ï‹F;Û⦇8Am¹Ápf¬neÎ…§ŸÄq£Ó/XòGÑUXíú“–y£ûŽ 0ÕG´½iQ‚&ì ¢9^è1_„vÖ8±z2R§íPqhŒ(�™œzæ>y¢ËO¤‹‰ÕÝxd€ùËíÈÊ«‹±Å&�Æí¹¾}«9©óióV?¬·ÿ�žK„ðì»,e™IÚœ‰Èì'˜˜Ó>E‹‡”L”³Ôµ¨Ú»5`gÜrªr´ÜôXºÚ]�¹‰ðv_n!Zä=á£x™<[Ÿ�ÍŸëA* ü6¾¢Ë×O3i7Ú¹î „&lá=xÐF7„Rç³ôÜ¡dT²ÙC�#a‰¬”X~ÆŒÜ÷D=süz¶”òµÆ‡vÔüq wSl:ûõ—„�õ‚O 8ïìže�2uf¾Yãæ1¬¥6ž5^ĦNÖAè¯T¼·ö:ÉR¥’ù(vM¥?ÌÂIeSöTõQh*ƒÒnº~ÒþvvSåÁpS�ŸM8¶\‰ÃD©Bæ¨!öü>ÇxÔ¾#Ým×qY€Fw<„ ™*ÞÏÕw“§¼´;�ü>jFdb×ÁûU×Psg$ä3 Z�‰|g3=S,Å{?ˆ¾ÝØN�>@—Ü~J…kèм[ôÍQupöÍ¥ù{Zpö̵älˆ4'” @·ÅN^f‡ïÏÀIn&ÝÎEƒì@ü:-$lNàoÇ ›ž€»N6Óq#úkë*š’ÞJ?½]Š}OôàâÃ&S{ƒJHÛ9†;Ïc2cŒ¯Ìdp ô ÏI"¦¬� ¾y½Í[o£—µ'Rxuu7lîËG·R†jH;Ãé°L5Þ¾â’ÎYþ�²ò2–�aÇ^¢õ²7A.è ©} «c  ì¢þwBÍb“Ó»IÀ·TâxõÛÎ ÚÀ�yǃaC÷4Óõ'7\6ù®IOÇGÃàö¼²î+j)ËË߇ƒ}—¨ê÷ÿ ïûuq–ãoj¸;ü2Õ¤pq·5Í}ù™„ÏU m¿<áóÇ ¤; ÏÈfÂMÛ9Wõ!pü±†]™š?�<ɇ²;v'çbå±? nB£ÖêÀöE+¡rÓ$¨ŒG·)žQmmûæŒúE—H¬@’ º�ÝîOl7ö�eÉQôþÛ |=ϼýEu�ýY�gkp× /ºKã2€{ü}ªÀÚ*ÆÀ�•‰ ®û=.è§Ø-¸fÿ|¸á8´ŽßE¯<Þ­‡»ˆÒˆ(›¸u .¶ågþ›©µ Åh¤6úFûðQ¿U+Ó¤†A�ÿ”=%‰%ÅŠ´Êf§bI|^kk+Æ0n3âØêó%—iê"/Ðøô‘f&ÞÅ :­”y< ™S*¼œÍæøtÀvÉ�‘¾'�ðæüIÖe)mŒÇù½}”;U›Tˆ‡ÌÕ$’t£5Ô{R�ñxËžÁ‰Ý°uÛ|ð+Q! š#À¥$ ø· á“á×h%4‡ô¶_Bý K˜>g.o¿&ÿ±$w {é ËA*!æ‰çö/¤_›QiÃv\¯ƒB�)ì¯Z!ìØ´ Š–'ÒAÛ9dæã¥(’¤�C±¡è¤ ‰íѹ¾i*c:§‰²9„ÒΟéÜCÇ@,Ê�*wØÁ|Õ?ôÍñõTåe"¸…H2›‹bé§¾lPPÕÀa—F0=ó5ÿÍÝyëXë)°änñdRo§s›¥añMl¶¹M¸SÛaûŢḲlšéÍ{ÙôÇq{–‚=¼ëi"Ý•+qÔæ½½8‡žWßNÓ—“51'áéÊ&¼¸Z Y“£4Áæ ê÷Ê¿oµ>lIZò |~s ÚFHÔÜr`Å':÷Üjà }%Ý! 1ç‚;®ñS€n<‰”Úg Ù±äÏ¡4ø£Žû[çðŠç-AÏ®e¨ô_.ƒµ0œü“ôj? üÓ!ôé.»ò‘˜Æ—1ÿe¢Õ—9Œ(#J}¥Û‰�É —A'Õ$t¸vëµvÐwa.ð5¤N1ohÓ£4J¡ÄÔBþÞÞH3d×¢Ä�$ æ��ŽIDyêúZy/ŽÆÿ»Çôu  †i³E1¥é8 tq"V1/I“q²æ^´êo麗OV¼1B�‰{´4xZZ}§dâŽYXy:ˆ,ÞžN³ÊgÀŽU´j°-Ê¡Œ€"ŒË$bß™gTeq=¬°ùJ%%ß0¿‚|þL Ôý@¦G&«/âö™»0¿(ëŽQìUÇ}ˬA²…‹!º­Teí$³õ©ÏK¿ªÓƒIÜ héQå}Y°$mäáÎ?èñœ�o<ˆØvyšæ*JÝ"C¡.ÚÇÃ?š^´šÝ+6Bw4ÒvÇUxtbÝæÙJúÌ ã{ã±SôžiŠy6ŽÕÏâˆÍ¯ã'肆|ñœh'ŲeW˜Hµ8°4I‡,©—ðjÜ‚\–áQ©Q¢ÞûˆÙ½O‘íü‘ˆC~Å g%ô›ÝÀwØ÷}!¨]ÚGø_E¹žP>Ò��Õ†pjdy¸t³êÜGr›³¢ 71öoüນm�Å]סãz�hûŠ´ú.øtJ&Û醯hñúY0ØC¡©\9Ÿâ Lqxÿ»©ëqbå9ø¨vµâÙ6[C¼ºr>¯Âm;þל B³æ±ú7bˆÑ‚•Dx< £oSRqW“x…Ã�ç8sOÂõÅADCpÕÒƒ%®0_1ŠÊà[–Ç?~Ü„†ŸláCI.vêøÑõ÷8"í©#·ˆ§ò*üÞˆ]×îãÕ|]øé˜i¿i_ûqöIÆ=‹4Hâ±`ü3w+�¾5 ®«�R¡n;ÒÔ|‡<¾[нɿD÷×|ÏWá#zøøÅGäM™ íôô¶?åyÕÎ…¯Ã\º×|%ìÔà1¨œ¯Ÿ§ Señ³q¾ºä­ïaÏúy—Šá#k€ï�ùZêðS.çFã‚h~Þ#ç8|"^œ²ÄkßWC›þM&*n/HyÍB¹ §@tûqºz˜ßX îUEÔÏí ˆÍÎÇAÝ´CälØ\I–é%²†Ÿ° UôAÊA/¸˜ÎêoÅS fÔ),‚äÏ‚í�çéS½\¶þ³ÜâÈ‘‰ÜEtË~9x˜žL^”ȃ‡½P��;‹tpFv –5wc™_/�z›‹ß$ÿ�ò#;‘gû‡ýz0…pî=' ã�¸V|‹§™b^˜/Ï|$€>h'ª’i¢?ÚÀ¡Ö¨Pá4Â`§~ÞF#‚p]p;®¾®‡"GUA¼ÐŽî-»E�LªÁaj#Êà´¾ßö(æRLÞÌÓ„à„`b Òkú‰ý¶VÆ©ñ!.7‰{ærøo'9ã¾·Ô Sÿa)2½õ>V~ÎÂ~÷0róJ^¬ïAoû)˜ 5�:yX@ÔñHTþ+@-¼Í¡µþÓpö.ñ±ä3•åç¶�c|µ¡áNEwÔ÷&«�€ŸéDáïmì–ýCG†Œ £*“¬ä4µfQ¹OOèæžU�bæ�&]ʰkßkòåZ¥PsCK1bQ�[‰œï%¸·? Ž¨ÃøµB�ztï•÷é]ÌÎE>°eúR¢:úŠmÚðŽåi‹¡ÿ%ø“ŸF©ë©&K/µq%ö±BkxtöX#ù¦ïgZ¤^ ®–’x-Þ¿ï�¢¿òe1²¦�}º ³RèÍURôïË RÝ@¯ìŸF«Z@£�8(܃M• ¶™- ¡²6Õx÷šÃWóš8Y bÀ ŽÕ—)8ÕMòªoÃlf͸0¹}êPo+…þ7ÎbÒC-ü¦9ûÍ\áÍŠ*rGk GviÎÈ ƒ�|l– F@÷æ[$©«B7 ’®À¼¶aJu™°C›ÍP’Ù‹s©‚ÁWpQ¬S„ˆÍ´쾑Cl?õ‘SÆþŒä‰hL*„„Y¡Dyœä<“ÀÏ–w逃 Z®Ê@ )U»Ñ¦~õ‰'_È‘ù³©¼K–µÌƒCZšÌÑÒ\œõõÔ¤¦_öFa§GMË)B¹¹Óé2s}â½ÿ0étk'' N`k°<¯ðœÆ.Õ"6íÿbÚ.M®vÜ# kɇ”ÙœwGU8-Û`ÏŠë¸ÐY=[¨Sw:ØUERO&—zÿ ¥†e µ·Ù# ¥“6=9A£Úσò®L,²P=óÚ�ö —øšŠqU1äûR�µž‚­'5þQ†³ìñÊŸ x£1Ô¢¼™¡…™0yAŠ÷VÙ…Dø¡ð¬Ã »œeßG]+ÓBô˜´ûs°Í+‡ð;ƒ³‡#T�D⮎puÎ6Ðã åÓº‚ZP}*O &Îi5Þ´21òs£?œIÄoÑ:<ŸÙØ—ånI)ùx�E‡á�i*�SØÆÊÀ ¡LØËÇLüA‡˜<æ\ñk:hJ/ϦcãÌÏïã$sn*QÜ]·^~!:Q=„o}„_„]®uh¼Sœsã¢< ¼M¬ôâСx({BÏv.Á•—à<ÐIC»fA¼a#þ'Æ¥÷Nvbî`óºl�쀒÷!4õ-©µÑ§ù¬>XÖ¾À¥fñ°ÛøÙ‘÷Ï�|HÖ�0²¡¥lÞ£ÞùÊUϤ[J?âð—P1SdО(—câÞ|H±ôk"ìð˜¥Ó«Ÿ)E]�*Е•àÅœ…€ƒé;‡ÝX©åÂfÄÌÄ*IYrþW±¸K›ùWÀ§¢Y{ÍhXΫ#I!þÐyoøýÎÛ¶•´§¿£{ö¼@ïk a^÷ö¹oµÆd¬òi$ãâ'H©Y 7VZœ)—™}‘ƒt+0”©‰��}1¤Í÷¦\7Šg>B’œ >vޅ󟟆þ­‚¹»´¸Û ƤW«Þi¼ØŒ·Œ¸q >S�Ãæeâ§¾ÜtÉ"„óÙÑ7ò`$C” ÙÖ³\6×�IÞV¦½?™ê4EÒ¾Ã×1¨Ëˆ¸|ÿÇ;/„0KJŠt~³§@7´[•BäϦãÁê²GSž£ÙÛO5r­±³1’4'ªÐÌ8 ¸—Ì2ÆÊLNCòä9ª³×VFÑȽýôn²§ò�<¼}~€&ÅWÁ?­cGlÞ0wƒ¡qÙ¬60§Õïy»WgB¶‡6F—�RŸ&4�Äæ'Ó`xÄõ4› —ÝCñÊu¦Üp6¨‰˜Á­4Zezšl¤¶dµ·#²w1ã¸îþì›iÒPù`&99ƒÒ·¨ùziŽT‚oi¿r¼±!°ŠЇWiùÔ mªï?ÊŽ–œè—Òð_Ýw4ψÀÈ}»àòÉ6R6TÌ|h¾‡‘јõÚ†ýýð7»Eù½W€B'Zén—hZµÅœQqzÅafaîÌaö ÄüB1]i:Î4!/ŸøCC³]½à÷̃Ò¼!™Ì=ø�TJ!7b ª?|‹C[$§Zñ•�‚žÿÅP‰tuèlú ².Ø¿yÛiA˜f–º)˵ž³Ìo]üò¢U%~P•|3ðhÆþ]b«wšƒ–à%¬›uš„ Ò YGFaoY·'–�ÄÁ´.Hÿ+�r𳉖¸8ÝùT„Ö—’°êÏDú욺9‚:öc½ò‹®Çƒªè¯[|&ËÍŒ§¡'+°gç\fUÃ(ì…Û]Û)¿¯Tº ZšÁX×Zå²²ƒ|'­RÐ0I—¹AA»ƒ¦Ö÷±¨Z–µÄ½v)ñ29�&‰õÅJùïªÜ}fSeQª;+�MÏŽfoÊ^¦š¡ÉäF¶¬ÐœƒûÇ eÆ>l(Ÿ$!ÅX÷ô1tKWbOó}Ëáû®8vßï»´OB}·âN™(i–BÏšJ2»\@ÅÎÚ¢ª@#Ñhósj9+ðêÑ÷X®€ÇÊ;‰€g;¹«v…uhO¦ ³#ñÏø'L?�—çX¡EZ6ZïÃ¥�W‰g‘:FÃãûÈL¥HxÓ„ç/.Åœg QBþØÙ4Ò>½gL¥ÿuX¥r·ý·Ò~äSÉY×és¼A,ZI³c,U/çÇ£iÍðåz7}܇Qs}�ýð–YГ Ú=ýtÙª”ÿ‹')u‹„¡ˆ]xÚà XÔ}a‚tLaAÒfìë{B›X3h½J.þs*›U (|­’¸k™ƒ�B p_Ë`L_ “*†¯÷ÿ5 «:�Ž�š í3…§W“CCë‰úQw-B=WJWEámç™TÀñ*6 Zs¿éõÑçw�¯&ÙTjħÝgy1òd׿Úí˜âDùŒËðö— âô3×…£ÿ6j3E cLËÑh‡ Ó ¸u2 _.��œ«!¦²ŒËˆfÐØ»dÙ‡Jö®Þ-²ÝÉ�<ž�¤×}‡ÏWr4Ó‘D×%b¹°5¡Et‘Ç%Ls­ƒ«—m`2û2æ ß#¿òŒ ÕOú�·£[ò=*­{Å�ÛA¬J^~æÑš·UÈ1ÒF©4°VƒøÃ‰˜pï+½ItÀèß\Õ±Ù�z îà»Ç·€Ñ`­ÖQèØ¼¶þ\ 9ahsh”.쎢Ö�Q*ô£Q˜½E œwå9ï�Õ”áY_9®�þ�™ò8�ÈëÂç0+ˆY‘Ÿür¨ZR ™ÿÌ8eh®?NRt;É“¾VüfuÎòƒlALk+èÄvÑñ6( +ÿ;ãLKä1|e²íÖ5Òãx øn\ 3V™À½A5l’,#ŽKœ@ÿ@$N>=BÒ—š±kÓ$!†m%›í–BÞÚ�dô±V-†/›B©Cú;6½¨”(”¿±ºt_q”þ¼ñ—f,ÖÆgrxÒ´ ÇRٻϓ Ÿ¹ _IbF9ÁåI'é¾³-$ØY�ýj)ƒÚ+�0`“�…]ج³§ÆiáÔhOÔ‹»lúÃß›=6åø5“¯†éöóÏ §a3Ô\‰À…9ÞDsºÏ6m ´]ŸM�M90kŠ ÎüCÅÌÄà×¶Å)•E.Ÿ«†£×H¬w Ê¥8 ºP³éû^Ø3é�«†CqnQ®DNŒ0Çö@”;òÆÏà¨wq]ý’º’`äïÝ‚o¹pbRœ:ß—…-N¦øB{ÅÓ}¯�ÐÞä-¬%z'Ð÷CAø2(޹j’ˆÜzká$êp³0ò\Zm耻Ò_Ø$Áq€á%pýírÜ)ußc�v=؎I=dP'…è\½Š<1Oüv™DŸ D§¶™Ú¬[5ùÁ€9�:Óî‰Ï‡zýt48©H_ŽQr­—Òè"œºýã/ yw;9߸&?Õó$#˜zR�tdÅŸÖ Áèo*â� CÁØì2y±}.O¡æοù 8ªáÌ•Ç!DÃy U�@»Gïéëù—0£a}:n‡*ªhev ˆ¼87\G¶Eû’ßj¹Äê°;óÃ`–ì‹5‰<–†µ½[X‰qy 9)Kµ'¤LÅRY¯b?Z=J‡•Ðâ AŠ$ÐC·‹p£¹ÍÊØ¡UÉhXDM óÀe�>læ]ë ‰$6Sžø-+À=ÿ ðÄ䪙ß d]]1\Þl…^¯ñ^©„Ç>eRZù©WÞwfïæaÂ.ð¼°ŽfA ”EL£Ïþ:£[I¹•׌çws«žÈ” sº>wá‰ß_艸Ö²i ŠìÅy Ù¤(ßòÖ{AÉÛ*š»ëÖhb§ÂJ¼!±–ž-‡Èáhr)g!𓍠ÂgrÌ8¹šÌpp)j‹kcö†Dz}k65ýÏC:qøf‡.Ä…²ígP‰ƒ/H„±>Q||·¬�¢Ö{Ûˆû¦ Ô«xh:×bUOÃGqaöÕ÷Dnú˜ã"£ÕDŠ\¡ý¿£ áS?¶Ëcðm]ÜüeÙþ<§,Iƒ€Áìë¿"œå¯Ãy×ÙèŸÕ‚/ÊòæLµÄò…§H‹^*ö©'‚,óˆ¦ñç¡ÖJ–ÝøH÷°„W›â�ŽELÑÇÿàÎÏU¤âöQ�½ÿúÒ3 sq ¬§Þ¸ÓÞ¡Vp(Çñ�±´Áä.Yšê ¾Š…¸hÐèÜrš&!�Gâ~Ñ ‹˜•ÜB¥Ù™þäZ¬2'pqŒoÕø[,«Ÿ¥WuÒ ü£8ÇfŸpýÓÙ§¢Ar·̵ÇþºVx²ü7嬛Aî÷ Å¢àR¦/½uõ9X‹ä1úœÓðk@ “äsñùÐ.L�Gœøf GeõqýdZ彇!¯wÄ0þM¼ðF(^Ny‰±ÙDaÆ*ìá‹gË@Ê€?¸ ¥™Ö@Ko•2Ÿf?@A¾0Ð_ô–Æ¬Ì š0U÷8 Þ�ä£Ý"ÐÌ ƒ}¯GXN€*~ÉjÃ5¼o¦'îÀ5&Nè>uÐÔAãê:öš.[e€we¦Ñòõ“�Ÿ%Å©²ê¦¹ã]j—KøõÑé¡Mÿˆ?O¢_: p,…h{ú3öÅ5üã°ÖÎߊî9npƒ¹¹2=—(Avjýð"’,HU‚¼Ïâ0ßC�øÞ9F<¡…œàyƒ¦Ð?Gu€o!‚«³á¸ófá_5�Í…¤ÌXœÞìK‡½Ì0mjÃsOüé¿h›—Fß׎Ð&¥,ðŒŠÅ›·%àà xð¼…¦+á‘àqn{p¬Ý…ó\+!eåNÄï%í¾¹ì²Ÿ8��·:¾Ós:ådïÃ8±_�s’€’·Ý&ük{Ò…§ý¨ÓKÒZïŒ_Nž…9�ÔÂy 8èUà�Éw0á°]¯ƒÉw-æoÕ<œ±¹ŠDil ì2´ÃÕZ©ìûÐL2è™MjʯÓô¬w$¹©Ó4ùÊ*èõ ¢[ê…ɼmìáØ!òÊT‰ºŒCqU"Ýï*…&�¡4É5hýc÷Þ•\fæó Œ`·à•ÙrxûÉ *nP„¿?Ä–£e�Hhãn{àEKóÔ?ßbŽìäp¸ëÀóm3•)½ˆÉxƒÕX†Ñ_$ËŒÈØÖsØýt?æí�cÝòYPÁLÖµôý¼ìlÝ*ON­€k·€î}Xœ¦ÛÜ�¡Dq 6L¬%ò×_�8o3Xæqq’\ÂouHµ8Þx{A)³rù5ú&è ÌÉ]DÃ?Ýg]H%;ñî2)Y¼ LM.CÎŒLÖ*$?|ÞJ릭ÆõçTï¼&N¶Ã^ñ(*tH�<ž»€{»2ë˜rôèòö^�Âi)Ç¡84“Nà¤i—l6µ<¹ƒå é@@�)9l "üÎ1ݪϼ�£¾žñÁç»4dæIxµ"96°zá¿øßá�òßç´ªQ†ÄYôçk³1&ç œMŶë‰\pØÖ< SN|ÏÃÆ8^ 2¬-\=•€±g£ ÿNŠ-À÷i¢ÿv*—1S‚ûˆ+Jé�0Ýօ踡gY±LV4‡än�€£'qknNUÀ!b]žJm†Ôˆ|r¶é;”?Ìï¿\E¦V‹�‰ûHÛÎ^þ™Øÿ'„9>í9‘»�E]œÚÙ3 –8‹§?]`“—…Ò�›ypó£<Ô¯J€ö®ÇŒç§6ºZj*ÝÿmVk-Áô ²’[œY ðô«6›”�ß›µ¼Ò¹¢¼õ6˜à¹™èû—×�×é¤ï\9¼dÖÁ4)-ìþ6IÚZ§q6õmGÉ3¬ö‰K0^}—µóÀgô›Ý»X�® Ã�ûEÑ1ï-�kR@ªìxõì *ïœϯòa_P&:þK•Ë3¡)ƒK «Bqç‡ 0–_ïTfBuí5’[Á‡/@ï*@ú°“l¼×…×Y2Ððоm‚žèÇ8Öý„}qƒ¾)M¢ö¹Ä²ñ-µé? xØè_'ô3Ñíºø¨£Ò�ðp:GE)ß6ø:+¿/XF¯x¨ÁÚJ 4½ë$Ÿ ¡„ókxy©6Mý€k®¶À{»<ç%Ò.Ç@s›0ÈOÔ7¼6Á=xŸ<âÊ�õ¬öë�>ìÜ ÄÈ¿^þE}ä®ô#‚/é~£C»ñR‘P¼ikç>$g¾ ¡ëÉÔsFñ·“çî=f "£ R§È­ßšLJôÂÈ”P/åùO“-¯ÁœÓ,RÃH¸ûß^Œ�7ÃcÚIäÖVæ÷ÛU”Gd„yìuõŒX*m>t~r`+7Ÿ.~ò™Ü©¯"¼6X(ŠßæØ‚Nçó:óž§ËT³ Þ$–<’ýN-µôñ5€ {0ví"Г¬€§oQ²a°~šq9³8'vGËpéºLêîÆÇùµz.ñ ê;ØÇËy6ª€ÖY*Üî°Z¼n±‚¸,ùD/}ÝŒlŠAª®ü„Á%)ôzå+xk¦P/-ª?]ž@Ïtr[û$Ž»Ý†Ã~UdaI}:7¶3ÎxÄ[œëUü™nêå'ÙŸ•ñXŸ*ª…îB:Gx_%»i’Œ›ï 7–“rm›ÌŸCñbô�ÅܯS³áüŠøÕ¿¤8ɳö÷ ®(òý³¨ŒÂ¡ÚpTÞ±�¸%{Ò¸ô÷÷ÓhóKL¿ûÓ‰%¨«sŸ¨‡–±�£éà%Ck¿8Àý7ÜÐàKðÓ˜³lnAªÕJìÓ³€n‡Cðåi%”{HAÑ|5ŒqÙŠ½mRðmÇrΑœ0â²p=œ)‚üœr<.t�/†·éá•Ôfö"p‚ïL!I'wÃ\‰\A2*‚æà3*X4I]ÿKv¡(š ‚ÿL?’!)üñ~7äÄL›ôr4ب‡›sñަ ˆ»ï@‡»@|Lj͡(PA ÿWtý»9´Fõ7· ÀCõ…´Ñ° ÿ õR®AÇ›Eð®ä"½âBÞŽœ‡YëÅ1H%œ¾OÍÁ£Ì>â<ðÙî-jøCÞM[õ3Z¨êþZtÞLœs„¸lA*Y(œ¹çôPÌX U�BbÂz” _�ux�L,×#jêÌè~]P[~.õÍà(õ¦á‘ƒ3q†þ˜qp'xz²( ‘‰· >’Kòéoþ{fã±È ”PÍEëÜ×ôàþjöúÒQøäÕ Õ¡¿˜4e |ÜB$åÞbûöÏô?Û$ú>°„±²5€g]Î Ÿ®�ƒïÎî™oÊ3#/ºŽ‘—yÍôÉ�oäéóR/ÎĽmËé©„ �mƒë+Ÿ‡ã¾ç(Øu ¶ä�ºËªúæsþB+õ‰YJ/Ñàæ(E“½ô¡»2–ë�PQ­8ˆyržìñ­¤¬î[œ›ô†|u(C&z6i1–e†I3¿‘^Ã…8Óqt_ žOëÿ„8jn/„ÖnÜzQ‘µ^æ g|,ðFÁk�z��ê“å:+péCÉ×øbø>©Ý|5 y ‘j’þ?§À3ó+}²b¾ò,E5èq¾ z+£a޼?)¼#7ü�ðÁ¯SD]ÉתŒã5?hüoS¦#õ&YÞ¸�–Ï–D|&�mÿ¸ÒÙ=÷_=¥wK@äh&ÎÐ…~fØú‚�l�Bû:†O^NÁ©=’*µ]#RÐoØ ç)Nâü9ÑõÕAÝðGî:]¯ù‡žÐ¥ rS‹ôÎÒÝÜ©­F3+÷,ËÝáG–‡3{-åȾ$+šò¯›Ãm>Pñê!š²W/îû‚W�Ô`ô?Çñ”' ÕÌóX.®²•f–\†-* àYù­ºî•÷è›Y®ìóÍ›!zßÚ›¦ŒŸWF¢´�*>ØÛZ³¥pçüßt{•[x‘Ñ "üÞBÄÛLJ ªDÓ„©>€þD¤ÝÿH7Ïó É›CÊ�Ä!Îü‚K¾¬ûç]Gáˈ)Úq›à×Ûóä¼ÙûD’+ýµø0ï2¯“G—ãË`9slÙ~˜¬«`f%Ò‚ãI0z�—Ùø…²ž©ÕZ7RõÝL`p3Ôò¸ÐÁŸÏ0@2Ò@‹þ\²xëZˆÿÈÏ� 4@‰Žq²Í¾‘^ÕD™E'q«Ø”ui¡­WZP æeœß‘¡¶a|øt:‰¸«V©7è]»/0›«Fò™`f%·�‹p&nFÖ»ŠPð]Ù1}¥¤Ñ&:èáßm3Èö– ЗgŒAµÅäo˜ Ä5Lû±0ÝE· �&ÅlÄÉ/„ÜQîéo4äå 8eËË�R_ˆSU©d݇�bEéÅ|øñózFá¯A¬âj6ùØ¿L,¤èõô2 •ÖC-}p-.§Ž÷ W4ÓÙÙDZ)¼žl_†ñ®Æ8%Z€A³:éŒA ºöý¨¥<áù´åÊØrëú& b3™£°x½*Ô]Q-Û|ºmé'®ô�Nx ÐͶsàYýzße’Ý'S@b3¯"ßļ-€ºEqCzú©¹z‰PÃ×åk8ù ÷ÖôƒŒ½Ü ²Æéѹ”�wt·bº¶@É�¸,†y’þíÔ9Ìÿ�Hßk¥âÝþQ’ËÞíjbn<ÑÁý3„I u¤¯/†Ñ=5@j\ÄsŽºœkŸB°Õ ¦Öü $~ÔËp!È§®žÄyQÖ¸J¸�½=À%%Û7A-›M&ñ{'«áö±Ýç!Ê</§;âÀ~7ˆ1ûÛr»atZ7˜ö× -Wu¢‹=÷˜Ï™^¤µ “ÆÍ“†[Óµ¡ZÐ�Ί®@ã™íÔÿ} ò?v@¥c$õEJõ®Æa/I<¦˜Fg}$‹^òÁÃG»hY1/GüoÓ£´�×úÂão�è�ã&Œ_—$•«h�É”µÌËúƒä?¯|Ø»b#†|C¾4øSI;ö¥âõ„byù’m[7Eók¸Ïš·ÑDÉ.L•t§�¤vL2$*€5Ï~Ægû/”ºÓ[¼•`§�¬¾fu�¬äŠz²ÿòÜÑeŽß(±·ºGhØÌ°Ý“À.? ݵ¡¤0R?±cÝÏæÌÉ\Fn¹){}Ù €&JÞ]XK“ù>‘õO”AÁà\¼«ZŒsWk¢dÎðžI-¤ Wy ³äî »*Ën³°³ÿ tp"EaKaWé=ÌÛ„›®iã“óêzoýð¦§ßÆ+v•Ô^öTü~NÏ®ŸMW¼/ÁT°Ç«¦Ã†JUÒp¡‚òøû;‘³°é/gžÂu~9›Ú�õ0ãeñÀy ·™_V›ÙÝyGá‚],ª*¡çšuÁ)j ÑÛðóè4Ø—:›Æ\܉·-ÆÇûîaÊngL¶òÇ D|Æ´f®'Úö�xê�ø…z@ÕÒ¥`¼žƒYü^8û¾å¿ïôœ‹’À¦&FoI$<õ„ÙÁ¼f&avH9ÞÔ‘GQÁ2&ÓÖ“Z~üM}­çÓËžKØï2Å4< ŠÚب@Ô™f« ‚5˽±r(š^Ð$ﯧÓq_>ä™·Óu[�M‡¡H(„¾g.ÓÝø•ý†Â¶sž~CwÓo¤º<•>ùƒKØp«ý¾[Bn)tîý|ì»ÖÍÌ¿A|LXâV/-<ðk4�4n; ‚éç±9Eþ»¸¶J‚ýóHà)DÿÝ*ó¾0Ö7ò>šlÛ‰‘aÛa2U™;U ‹Nî„ã\Mƒ"Û¨þ²`6Bñ#ûlç Håu€c;Ðx8 Ž‹|ÅÍ·\YÝ[ÓÐzõ8¬ÿý‹¬³ Ž�-)ç“ ¸È¤“§�v(�ÉnÑb&~02ÃVPü$ }޼¨w?Š­î¿©óƒi8vmdpJ¨ÍáÕÄDã>[¶ÛŽ­�¿Šü÷ôÊ<< ÃÞ1Ë\-+š;€Ù8‘w n^؃–‘‰ô…vq5Ü‘!›d+!óëR4ò¹�êÓ½P´O¥Îü®Ëûx’èú}¯ÝœÞIæ~àŽëv’‡r•ÔµS~ÿYE½«„QZÝ-äæbôºeäf_0”/É#ß•ÈÍ1+há>>j@ Ä ÐÊ&šl—•ÃÅ$=!‹é-±E6J‹ˆ¸ªÂù?ðµ´×V\o#sgFçÆS²$_ŠãYò…¤U¢ÒA‡`‹OÕÛ­ýA8�fã…ig¡PÚ‰ürq…󪙷–A:•€}M•f÷“»°ÑVó5bá¢ú»åÿopOy�Ã-�ÿ.Òð¯U†ì�‰$G½œêÞ_K„µ»èïmi�m.XÙý"eƒçÉ“3Úõ–Š/Iõ]oZëóŒ=ÿ¶´öÆ@Æn'vÇ–ËPýâ¢ÕU¼*lMFç?c>ê< ×Úe¸3ke¯ÿ¢—¯EàÏ2Yv±”"Ô6ú Rª�¦‡¥Ø&Ó`X7R„ó–y¸a{)@üŠ=Ð�7‡¶¿9ºVoˆYs->8ü·Ö¡ÊÉ2Ò«Œ ã÷ˆæìËÔ}ÝnêaÆ€mY-þö*„ÍÏö€ì/|ïnˆ•ßÓ U‰sI½µh¤Ç.‚�/)ãÑÈÁ&;Éé™xx©3«9‡œ6 „s¼Ú »ê^ÙH ®¬­wÐZŽÏo�íú2sŸ ¶½•ÄúÙ/°ìÄ0Lþý·ë2!è'܆²¢êØí�†_Œñµ@©Ó¼ÆJ ¦R¿?[¨ëµAb7ØJJl£|E5ðkÁmºKoΘºNæF˜±¥yý¤¡=ûþü!†O¿³QÁ ±Ö�\"]ôÐMa1+…çÒ²Ð¥à‰•9rx{ÅÜàþ7­©¦ÛþÿÏ™ã~ÔÑæ{dcMÝq Þž]L"ÞGâ£�t¸1^‚>kMHÙYox[wˆÜ\[Œ×›—’ee²ZZÊ'P½ë Â…Fò¬ç,˜[ÔÒ‡æê4&®uõõGSì4Aw§Ìïí�i’�†­~{�«ÂY=1°�n�õ3á=MÃ�ƒ=ôÊ‹ZœÑï ÿl£ÁU¨¹/¾}÷‡ÏÖ Z6ýb÷�Å£ìËwšÁΤd˜Ü}bÆJ©ÇX6ùÖPNf ‹#ÿ¬@pp¨pM¸zºˆ:ó‡Ê~ûR�Œú"¬ gåzDp ð%¹’0Lî�QÀa×4²õûn—fi÷{Zß}}Z÷ªÁo”¿ÏkØN‡)"Y®‰7å±1{®¹ë¶j`ýŽ&̳ÄB,&c�º4ý·3ø¯t§O߆²{·«“on3ÐiÓ“oÁÍ/ðíö•L›Ø:Œÿ«OßñìDïöRLj£¸9ý ³H©ÿ8(£DßlT}•îØe û$MHvþ v‹ýçyÿoh¹˜¼®àîë2ÂãZF; vÃùNi²ïÉbÔrƒE%|ùb’Ú:  ä‹!Æ:,‘æüfKËs�¯è¢Ì§&8a½K­åè*™ƒ°þŽ$Ì{·ú¾ÜÀד°gö \/”�¡�ç`®þªFÀ¼¢kdþp?-/þ@G¥Sí…'HílQûíŠ%§ï’&±."&èƒÿ…l„ç�äðy�½€û-Â)¯e:Y4A»žmG¾ AÎ’-’(&ò–6�öZ?à/-Åø‡¿pð–™¡9ÝsnâÉ¡ üÊ�*^(»}C¤!F LsëBkñúÑ5øò«ýbv†~¬ê¤}°ƒy2¶EÜ¡¦7@ø°ð„D£êáIR!«ÆI®œ¥%ÿ2ªÔBu®Dž)p®� Ovž7mËÃBÃ+ ½üNû×÷fߨH§šø8¢Êo)8ñqùÏøRŸzÖçŠ8èèòbqV$dgµ¢þ‰ï†_wåÀ3õî6rAz:nmØŠ§¼çÁ©3Ÿé]ÑÚ³ûõjõ@Õ«Q´¿ø ]�õ†ù2Fe.”DA õo€�pÙY¤ÛøˆNWÍOi…—f|†5 „ð1é!H˜`{ï p¤üQ+¼Ï;u§–Õ(¾åÚê)Á7ä@?¾èõ¦š&>T§?•¦[» –e ÖÁ³%0ã’=5j܃oæàø÷$TœÏ ‹ñù�ò@‚ M&›1ChåeØ–Édl?/„½Fú%ø“Œ‰ /C°üê)6Qü“�•‡žûÈ:}-ü³)�xx/†å¹`œ`èÅ·¶(X²ï ŸÊü5"Û£Ìà˜Ø UÚx‰æJV¢íÛß$cVþ×sÜ;=!ÅÁbþ(qOþš&tý•ƒ‰÷ÿÝŸ¥dþ?ÃÕ»cÈë¡>Øæ% ÷o=¤YWqou î0Œ"/¹Öp%wÀN‡vbÞV·®Â _¯N"i&‰Le^ ©^ô•ÚiîE×ç™,@f¾ Ýꩃz IŠ¿G`¬ÕÕ²IÉa{¸’UHw*‘_s9¤¸ä.–æÓ6þ*´H¤®¶Ó ¿ ™åÅó¡&º™(T¾$kõðqÔE�ÅBpOF}ÕµíØQc[2Ä8_þyÿÜ•DçÓGÒ{`•¼ò }7£ÚBKÖáåUšõ©?”‚tñtŽç+uèR[ç3˜È³ÛáëÁ›ÔÊï+:?Mýn‚l¦#ûâ"õà½B6õ•S£rf͸–¡:û¬ñ²½Y³Ã‰¾ðà¥çëMqxúG¼ô©ƒ‰_,‹Y| &L5¿¨;•Uɬ2_…—trißåWäru©Öé¿BdÌù3[+ñ“ŽÖ\»G¯ !䑚w€ªzD5/TáºãvÈ©/ ÷Bóa÷œêU­Ñ·ôha›$�ÜeÌÞ3ýJF~Ûp\œkKJE�ÆäÓµK„°¾&‹¼BËc ”—ao½pé)õ‹B™ `îlÆ�j_©Úàj´ÖoEŸ�…æ4(MÂËÉü¹Å¨›©€è݀ܔ÷ô^âZö\®2=g™Nc—¡`jœ1<9e+bï÷4\<1�ä¸t0ÖFý'ê4Î¼ŠšžÀû{¾³+ܯ‘t­Ëì˜Úwêsî?±‰òÿ½Dõ$6ÐŽ¢7DŸóuÌñéÀaÚy[å.Á¶Þï˜V…§S‡½k- QïP#´]¤^R6äÛÑ™vö$¼7^³cçb±ÔTÙà�¯à1a#(Ýþ¯×ÞóèÑfs;2óg]ûª™8í¼k‰/—¦Ã›-ÏÈ‚Ü0‹¯D,¨qÌKvѶv§^@�µ(¶4Î&-y•Ðûqôi,‡N ~È–†o®â gÕ2«Ã?+d0ÞúÓ¨‡ï4Ø+ß)ã:à]šu!þv'µ6‚„Ëèzm�‘g©¸¥"r¢ïÓJ§]¸±fŒߎ?¦wÔ? óâ‘ý¤â—"” ãýÛ+1•w’r/HÑÒÔ«�óPœ;gE%¬9]Ç(>#ùö‚¾±:§çbµ�VÞÏe6Ì'Ð"ùŠÔÔƒaíä˜Ýf}XIŽÕ†[°CÞO°?c,é4¹…°pX_|ºˆ&GQqV-ýxo'bóq�üsj°*‹Rä ÐÑ�ŽæÝ¡ØAe”q²CáÈ+d­|.Ùûî$þåß ÷-`î‹@`„“1ÔØ³×(�s:Øqp1s4$ošÅñè¢�èóÇ£BF™2sYá*”<%›×æ�߇k´ '‚vz�sç[hÃ!=G¦ÃPù:â%yw»hãìÖ]ÐOX°ÒÇy®-$&o„ŽÇ†3Û/¼fFFãè]îG&TY�L¯\±ôPï0-nþ\~ +Ä”À“u"ß6&‹‹•xÇbýš¦Ÿ ¡#ð ý–Ü„Çx©Rj.¥ B‘I�ˆ¾Jý�gS%o×mž{ñQæOrÈ+,5n1®Qψž{Y;åÂü.K„îÈ˨;ÑŠßžºa7o4ýl›Š§¥Ôa‹ñõÈÙŸÍ•ÀÝAŽ Ø+`}ñ Ö=}„ûX~,ý:@O<íÀ§ûÌÙ¡ÃÌZYWtÓ¶CJ×ðEЪ$5S˜E»ÅŽÓŽgsØ;—q:W_Ã-úÂdÙRŽo_(ϼƒ¯×Ý̺G]܃ùjIt÷IÞúa!cúæÛkœn3@ú˜�”ý* ªzE£3H�¬.8¨Ãì壡ÎiØb\A�¶ ŸU]x̧½ó¤^kÌp­¿q~–B]–ÀEÁ]¤ø�Nmçà‡ &¡T¬ƒ6€Í‘¥˜nDfUÃ%öŒÙ¶L?˯>HD…)«ÅÄååoHŸZñûcîõ"h*½¦EN bîÐŒ?8°5–WÃÛâx|NÙª;‡ãá¢E«-ßÁÜo×áâ`jùYCfŒ]õÍ&¾#l¸b Y5Ëà ™«´&Ⱥ§Åd“ 9 'Êiè]Âzš\ &Ú‘†‘«ÉÃeáxXK¥=7‚{�,‰¨,Å-Z„ϲ‰‰Ü‡õýÁTl*I¬…@ãnzñg1};iÉØŒÒ—OÓ[_Ü€4 ÔdŸÓ²%ë1x[¬2�Ë­ 8‹ˆ.d>…Í¿`úi5Z²ë1Íi7†e¿k1ðœjo8‡9#ް+ç&Q]àOCÍ ñqÝKjê>ϧÅ�Í ¿Èr�~zùÌ;TçŸ"ãœlìhsÄЉy¸ý�0:Î,%kj­[ªüaåù™ðyl�&(¨b¯.Cv�EÀó]ÄÙ™àÞÅ.˜UWKïû¨cX}?‰Y,�†÷e`{¨,¤öuÓëË\iZr31{ÜU?¬òœ¬+m#c-‡É¶nvºÎ}rÿ±32Ûf’C!çPÛÍž*óŠ’¦�ê`X[ Ïÿ³ctZ0Bò˜B?$ÍTy°‹~í;I@þ.¹?²‘˜� �gq±8ß7€MtuÆ‚ø»dYq:õ»*ïãqô 5tz.Æiož‚Åf)æŒÌ4örD¤‹+aÆÜ8º! ˆœ†Œ‡×\€ÛÙZ°:¿†¼2¶a·n]�ï “NŒÞDÕÙ˜ÓW‚‰_0/67¹ðœ€œ´—„gpoä©zÇssI›>ª–è°nÈ�ë1;8z„šN_J%‡£è,+ürª…xHƒyÂvÜ2ï(��w†œ�ó·ÞGÿéYØÆÐœÍŒþôBúu/‹5w“èOîlh¿r�ÊÚËàW²YnÛ;}ÜÒ¼¿ö…cÎÛ[”=öœÕ>@lÒDaǧJêš`å»´ ÷J™Òð%U켜�xÛ÷<Þã"³ê$ªY4�¡ÓÒ4Fà% \ ˆ –¯3ÆwÚÓ óý3HåYLö™Òx)½ôß®~ÆèÌDœé‰l•Ã)ÔÞYÁþúçõoJʰQÿ)¹~·š»Ì8:äÕînúýǪᶲå@D(•d[@¨Ã²ãÚqô›æ€¯‡¦Èn¯7$­ñ"~Á&2óþ4 ñ&³5Šp¬—�;÷ü+r²«‚±¦Î@Û À6] ’‡Ø«w“™ó)ÆÏí%èž0aƒÃ šn IÖv†Ý¥uD¡à —þ„bܲëÁ%¢�ù™¹—)J, b°:>œZfa]`ù´.Ÿ€<½*Ù€6QÞ°=6ŠB³È Ì5Ð1‚Ý[MHÖ9¼®â„¯¦ º%Ðñ,mY“¹ÇéN/eX?çý6Žp;ö"\s¨ù9¯i› #ÊŽeêH’M^“ÄÐü5\Ÿd=…Èbó0vm9°0ù\wœŽM£7¨Ç`v=óCsé$Òsû ܸ1ƒæb03í:ÿ–"ß)C¬þÖ°3£•P§È†íYúƒ½óo šQ†“šÏ<é!J¦è>jˆ›§•ágû5صPÒ ®€–»Ìh¦ÿ=#‚žJ†® ‘°AÌí‡;@¦åÑ<.Äã}çz€æU0L‰ð2¢Ãlž“˶´â¾¼ÀvÚ×®R#]ôЫ(” ól)ª.#G÷OÑ5O9(×Y‰i‹?P¹n+Üóº œv³«ÇTàV”œ |HºÆƒÉÔ¹@ÊÉ›�FáÅ].Í9ÒŽ±4ön9œ3¥Ü“÷I–.Å7ËÏæ)Bã°X�ó�»ãƒ |"ª»¡Ê£*äW…d�xûíw²E÷-éLšC×ÔÇaDU››b ÑŠÇ 7Œöзž é¥Y—~™.}cô�=GhÙR¨éK™ gHh ÅG·ƒq¤¾Åü'}0³x¦^«bn¶÷’½<ïé2W ’sw[bfާÎLã–9ð“þ†LZ4o6XÅhƒ´ÛwºÑ=‘ÍÛe8x"’iþ‹eŽhÙo‹OP�îöF>*Wš$ÃÍo…¸‹‡ÔéÆvÁމ"ð©O'õ¹Ôbvù?N)�»M!¬½ïÉt…ÞS¾tŶ=øWg%ôŒ¹áîÖm¸“ËâÏ·…¸nÍÌÌÞ‹GE}qÍh"© q†�kHˆ~&fø0°#ú{‚I¿^(øÏqÀ˜ÂeðŠL’[ü"&?A_Í$3‚pz–d.§³´6ÀÛëƒä€UYu@NÁ­£?iËJ®cømø*¨�Îy ûÙs q{sÖ/ÁOYÚÔÁK—E©µ$áb—±2˜ôÐTtÛ*‰"så©EÙCP��ky Ât%³kšhwìÁSùZ4VÄ­ýv0«ª�¤ÿž“¶x=Œ!dQŠE¿'7Ô1××/|¾L[?T¢h­nùÌR“ÚIâ6¥Û Uq»œ!g­ì ) luå?´ã¢'Vvˆ*N´¡ýØ-¦ùÓRt’[K'ýYK¡GfW[Ó¨þèõüY ‡j¶#dTeü}èÂîSÛEÏ^«‡®½ZtíñÅàÞüvÕËâêÒ4AæÏÔ’^UoÜ×5�ÊÈý¡<¶wp–L)½iþt‡Ùž#ŒN»"tO_DzG��ÇÇì´¡v¨zz—ž‘—‡ÙE;ÐQN¼Žƒ¶È,Œ�òÆeY®í”*>n®¢—ä¡ýW#N8õSÓ±Ùø 5i>ARøøñŒ¥7=žžÎ>WÙ‹®B¬ù8t?Û«¤à̰1Ä­jÄb?IvÕ/ÒþÃŒ6ÛH€ÛZJ&ÓÉY ó†:uy3F 0òÔ3R�˜Cœ0b:]ŸQ›ÚÛÈã}„¥ õ.K¿§¢(VLº“MÉ70ËYcU?PóDKøò°Ö¹GŒ{¹ÔûR<émæÄU,£FbõJßx‰„ìUÁè†ihð>|fÕÀÚæ_ñ®ÖëÒÆ™°VôÑü"A’hõ‡$Xî˜LœR)¿÷¿Í®®bßvèºQ/ì`�i'Õ½kˆLs<«}Ä:z€º£‹Yã”Yô²®)›ç˜Ž�ÿ�WÛ0U6 ŸO'ªûŸRÇÀ-$Fh5Y$¸®$u±ë•©¾…'Ùdí…�»4QÒk:&¼ºJ±ö)l÷Ë¥»ç �g-nÛ°‘Ý>¼z-$½. ᮯŸéáq¤m>‹ú㘹Þ/hÍ·¥´ûV1œ)LbïFEáŸOÓYÉf4ÚV^0 |nˆ¡nc œ{ÏòÜ,7.Ùg‹Ê_®2"K�ôº·U³ÚM©û¢Ä«7�Lˆ ƒ}ÇG¼r0�*¼RO Y¼ù^y¾ž ‡3É¡mâ�ú¶†Ì•FýOT¯ƒ‡«þƒý #èÕ:Ìhƒ¡ >äÓs#­ ƒ+œ17?R¾P·Ùì� Á¤ç²(gõjd/©­ó|):ïág¦)e7ðÛ¶¢QP)5�¸Ê0ÙQœ[‡Ë%@Ri%p¼5\ùë+F^˜ ‡ ƒQæÉN¬¦›Í§¨Nù]Ú±s ÌSwÇÿ޾®ç~Ì©ïln£zª¡˜¼0 »ƒ±}�4$ÙiqÝæháÁ(Öèl,5_ÛOÓ00§å;ó1r1¶TÍ£KÂ?°³‡ƒGb ÊV†�ã4–'~.—±åpGr66õá¡‹®tþ‚#øò°(Äþcös–uPÝ%œ“VÆ’ ™´z6â74{&lßg¬ìQ7mµM”ijª÷àóP4ÞÒ”æè=~HÌ·v¡ƒj!9ÿ| *ÞÞK¯‚pBàEÕ:±`+м&óNm&²<9pšÿ;ÑŽTCÙsŠôÃéûtÖ¦8XO éÃqÒóüõHL#y"“´å`"Mˆr ­Ç}`¤xŒ.žáƒëBñ¯Ák\—a@•ã¥9móa{g5XèB™.ÀðdN—ás7óqãØiæe$`æ>:å±”û½n)úŒ§‘uÎ÷ðmã{âcš€J E¤¥Ñ˜>Ž\D2mñ°o ³3Aû;Þ¯þ^ ã%^�ÿÓ“Üfp»Ý£§ ‰×Á¹¨úŸ27Â×ò.\'ÈG†ö.%&œºr—Áš4?²<^—ì›åÎ.ü¼‘6H¨ƒ‰f4ÆÎ3«iaÈ�7ðÚÑ Ã«¾¥äjßÑ.€D]Žº+ÇO©Œ¶(^"qoã…·$ùœ–Íš‹i×8`ytìɘ†‚C4ø©(ðrzhÁÞ>f×6Iœ½Ê�fíÂèX7zRAO] YISôéó(tÖtÑÇ�øLm|�óbc´WÕ®ü~L¶;Éâ»]GÈ9%ppɇðxL·He„ÿ› ÍÏp©¸;T˜÷#¿ïLøÐ&�ê_"ðÇ«{lt 0÷ì7 ¬U¦Õ9ŽPüešŸh&û9Ü»æBàO04{@2Fâa/ôSÞ­`k‚ÜK‘;°f®,B+Í'õš½oñ~¦ÉZŒôÊÜôÍßAä3ÖP÷?–TÒÒ§<`ýI|³ô6‰mˆ&‡Í»ØÝÔHÔ`!ÔnDÓe¯ÈöYºø9Hô™¬ü4Nï­C"Ó?ž,ð…þóôÊšx¥ì¦šh M—ƒ ¿õbúb$SL#±:ù:ÑöñJîn«óìÈ|3¼�jJ²Â7S¥3�L§�÷Ø# 2 ᜢþÌȬ?°Á½^­Ï”^u™ ÛÊãñîµxüØñ‹¼¾›Dïo¸A¶ê¼A�…FPhð��.@tb©K›‡ÍEÈÿ-ÝO¬Ç:µ‹T_~-VM1Pü;ŽlÝž ªp+õ+6ÆÃ5û�@Ÿ~l »5gBxV{ì�¬^ïÙ ¹lï'E\'´óÖ™ ÏY´×‘ }Ž«{TQÂ_ 7V‘—!~ƒZÔ%C|f8,èÒ“'µð70ƿΡKã�pÁ½V²ËÀ’Ýè9DN}& ÉÐ(±)3u¨ï›KËäfʇó‘ç—à¡ë·çpQîø„8X>¢¾JÉT4è5]’oGKIyÑìM^ìž^Á‰¯'áA=d�l-µ8M[VàõoJ¸Ý"�h¶-Fßò\Ô9IÚ~ÆBïô$rBˤ|?Ó™/æc^^# ¥OwÞPÀ‚­¡ e<—D®w†QVK—‘ÜÓwÈ™ieÔÆO›ê]¾ kß“Ñu6ôIEÝ|¤‹>µûDmå¾akµ!ôdÙ-ÃåçJPhs6È>ärýƒñÑ9´~Fáž?´ú‹âïÍ·a¯ø#HšÑÅ&e ƒljª.z…ÓÊèƒwá8kN©nP#m¿ƒt2N^%µß<õ¸¶´õó>rz«+,˜Å+’§° ñH˜ö¾Üû¦š™â!”ß6ô°ŽÇ²á�ÃøêUƒ×iy™*Ù¼ö å?€LX9]ã½:ûÇÉ ­"é @Ötˆy¢üˆ™ö6—qw?…}*¿É¤Ã4¸8; |ø†PöšÎö�¡E;çóÎTbØ�Š›G�V­0hû!�<šÖèî8Z¿u•y%¶šø8,ÄÔwO©jó>Ö:iéºÉƒ9ò߈ŸéKò~ÖG�,XYßa²5Vðqu¦ñÁÌ�ʨú5‹<›u«•Úé·Ÿ{èî» …w¹À³¨W°yÀ—úyÜ�ÐÖ4æ$3]wtøkNÜïUQ+quTkKÝ}úX–9DoúOü‚–vP:ǘ¸©1j]ÓpÔÔ6?çÇŠ{©èÓŸ4èV/~TÅ+ÙOH¢Ò)(*í"ÉCCì¡KèáMíh|ů{Ìä I—á’ß%ðd–8'àù c<.ÌÜV‚߯4Qt×,HkµÞ]Ú$;|&ã–bBÏý¨Íh. ΙG>\oÀkûéßK�¨øh)þ±—.­Å”W�Öv’Ò“‡žü«x‰MÀ= j0¶”à…­ËAk�*ÝÕ2A*ÝÌiÄö+tùòc`ñ6˜¼oX¢qμÎ$üwÁ¸f, ߌ2ô|èGÒÒßΈ¶*ñi'éë³¢8²­x5Pû¯š'‡Ï›õÓ½“èC­˜Q{�=ö^’+4¹;À÷Âü3”[cÕ`ŠM­w2÷«`×¼v'‘®á[D~¸Ûðß 2ÐfÒ©(r˨˜ÞÔJÃÑ’ËÌ{5îˆEñM´ÒDˆ»+E‘+óS‡¬Y·švkÁÒ¼CTøü""²Ú•:=�„'žê§ÀR“7�YœðúÉ¢¢¼žßþ°~ׯÛÔ©ò$CâãU æ®NP²|�a½’jœÖ€ÈÐ�¯|sXCãO! œ”ˆõvõ@Ž- ©ÀF–ëµù4Ýûa€­’`äE塨£–úqKh|ƒ >å(ÙjÂDèÅ œšÅËå©äÊ/°�_†KNÀÊh5­ÄV¹%ðÅ·�IöL…T›ø.’F]2oárî šÜÆe!—¨»¨*X† úoûZk Ð®œ~FúgÅ�+¾™Ð«— ¹s`Dw�VX�ƒûiXŒ¹õ¯½±iÔ‚é®û͈f `ÒóTûo8ÈÃ=¦ w±;.‘»Ý}õ§§òÐrI9³e† 9¶)“¾ç!.‚]äáÆAÜŸŸ‡å"‘8Y¨Dë-Ç™8Ë+ÀÄ]Â�q3é3¹Qºå�Úñ Ó2Zƒ;]<È¥×q”çÎN*{7–ÜR´£TÓ­›@û„:êß4„�^µ _³}¦ßaâ�MÈûÝ6ÄuϺ`æOjR5µÜ?ÓŸEûÈ×å�™w| ¬±ƒ²Öb¨ôñ…gö@ø–tj{²™”…Ÿ£M–)47ÁŸÝ9lêd=ô^Nc�í&ê“)0«5bJmà‘�q’ü�×—pÑ*ï=éˆ/ÊLañÔ\÷7šQ’H‡Ùìjr`ú8�*ºFå"ÇYÉ\øf  ïÞ‹ã‚~ŽŒé2’#föÝLA¯%·íÉpôNòÞS‚(ï¸K=ä®cT~¦¿icQèn\éVB“™ù�ÝB‹Üp©Ózd÷øßVô ²D®ýmæv0¼¯ù¹ûí§hQè0\ŽH$‹練‘�i‘‘êù­ÇÚªêûüä-K€àƼö#–� %ã qcÅù±Í+¥@L›"Ö'Û¡²ï-ò6ÌŽ¼YIáÈÜØèðŽXÏ&wen�û¦Ç eÎÅ�døº ÏÜH×€HèÙ‘õ%d@´™ú(±NƒQ�°J ‡V듽¥Yh³+Žv~«ä…[²èÃc¸ÖÀù™‡_ÎoÇ+TÚ”vФ©îïuR¤ü$E‰�22fŠÒ"-•†–d4ˆæý½Î]4PD¡PZ(£ÈVÉÓó/œëœÏûó~]—VQæL'9¤~R<îû¢(¸lMð««½UJ嘀ŠZzoè<³§Û”¡Pï#u}ù�Oq€wY7pùsê¯�Žƒ%¡p3}>Y^Bš[×�ÔFhß�Ó[´°k¸‘[7€º.Á‘oý k�3mzÁa· mm£]�½Tys2]qîäùP»œ­ôJJöŒfшO ! *�sõÙ舞�2Ú\r›Êꥡtá¡ãÜ\“Ó`3¨Žf‡t¡¹Eƒ:?„ f_Ú¥?Ë\å•4gڣɫ{º„o¥b`Yé8�V®Ž­m’Ð<’C~MÐ\+;Üê(ƒÍûëX9•HÆSaÖ¤c¸ÝUnÔýJê  ןñ£SF/É›õ‹z[f¢¬ZþYžIkÃSè×·[È´,üKöÐWÿ債Q(˜´ÝÀéÏSaã'ˆ1>Y¦ì–úœì1û�]hÞ·5Ô~�ÌNûIÔ¼7Âpd [˜D÷�ˆ º¯ 9&ElýtY¿í¯È£”8<èjK=¨?'©ò±Ñ8Cï¼äÁR‹z:fN6ô퀓¬À{Ÿ¤yuB;;åWd<•…‡Q¶l:îêµÏ»Ž°åšìT7Ä‹ø(ìý+ˆ—¢*‰Ÿ‰î &9dg…­Wˆ¸ ¤I üv]‹³¤ÿLò\Ýš¯Óÿ]ƒy…I”_2™VJʃ¿Çö*œSB‹MC°T@·=sa¯öÀ›î“˜Éõ„§{ O# ·6ÁC<{i—,ª“JÐÖW@„~ÝàH´sAê� 7ýH‚bÉóMÙ$føþÞ-€Ar;ˆT~.dØ¡»J 7ÞDûVøÑI’˜/@Hea c ˇ‹BsaUÚ&¼ZúL(îÀŸ‡ÿÀ·±:ÁçOg1 ÙŸ%‹u?�Ì¿BÌ6ž…EŽb•¡5hH)‚M£0:ó½"/'ÒT™]TàE:”ŠÁ{ö*Tå �ÃF.øt�&Yëއ[{1yŸŽF§A“Ÿ#3s ¬½è /9ÁÞ¾«ø.ËŸ^(£o–ÝÁˆÀ~ º“I‹Î?…!]]¼^ýKAjJ5�=–ä]züW²•}¶ó6(ÝFÍâUøóO;ÓÛÐM/Ùðã üÒ=Nû[g’!§Zê¼ç>~¸uUïÆàNóÙ²ŒFÛLˆ|øÿÿµ©ÝÔó4ºái»i$'�%¹—8÷¸³É‘ò. ¶[ *7?×þEh*v�dŒ)0íÓì`îÒHÜéÁ{]¡ÕR”§–T�KyÆdÏ¡pöåG;L`ƒÿöWBÏÉËèLBa—í<"o›ÃæÆ&‚‘c ÍO"Û%ß°qŸv�Kë{L”øF7Žq_Œ¶´‡Ê{çÓǧƒè®'¢OÆlªÍmªçýŠW@}H8JÈ�MÏ8îž ³£ !8Üöˆ*‚¶X5ˆ^¾F¿Ž˜']«¥ž×v’ÌKïé6™Bäg.ÂÝ$VdÍ"ºS/æ,Ä‹â<ú´¼�UŸL·±S�tm)ËHÌ­ Éo¬XÿiãdÙ°Ñ5®fK*ø1ëˆ ýÓ= e/�öÁvP­ÊeNçœÃ—u‡qmv.Yf½/Öš¢ñ¼stÙgѵAÆÔîã,Ж1ßg=D§•…êv%Ü5”LÞ÷H1ÙN=�})5C¡EJ×›÷‘ÊiýèRxq#�êÝRCOñ�»NœÜÖàÑÛr4àm:úƒZùîÉÞ¢GgS–²*¸øÉ5�Úà>"È©€rvèÒ9´¼„N¶Wé”{N8¦ç½ïU�ú<$Þ2�cv�ö¾¥…ÚÁh¦º‹©“ ‚‹Ëe¨ÒüK`:÷0á+mÁ/->4^ëI9mJwKž'5Îræ¾§ÎÐEØào ‚ËVBËÃ"з å›)¤éü>Œ\ý‘|äÛÍÈÜ(¦ÅŒ#vˆœÆï…p\}ƒYÄbâv9 ûdgÀ �~\Ùs�u×býS�Ñ Á¦W]DÐb€¬.6$Rû?Ù%õìËSѦ÷?Ô4¦û†{Ø'öê˜Pb ê:çaJÇ/º4lÇÒ YÙ§Éÿ«‹�æû ÛéË[Lèß¹DŠWC<çõÒÅ^\ü«p } >h¼!•P5×*(ß¾oÔóÜf�žHazT¹äFu6­JôFî³Óð[ã>>˜UEs½Ô)ß½µxÛö$Nu”Û}öU£À\�Ú W2ˆì¾R²Ô-•S ÃÎy§c.µ�õŽ'i]®x/Ï~[1@‚#©qô“>½šÞnGÒ%¾üçõã@� µôަ?ìH+]D^v¢ê·û$xP—Î�ûŽÓyhÝݨjõ½ìŸ Ùütêž- RbvW˜§ØòƒÈ^PÅaÌ;à ý>á§ï· ÒH¡V=3Ûî¾³í¥ÑkKiWãø~ ]a ôYdrî™^%>ï6V_ÞeF³wܦ™«ž’Áš• ã>ƒL”‚˽e´=œ�'½N™É¹ 9'£_ý\îÌ‹æ—ÛF¨æµ9ðâ¤Ló�QfâŠ@AâGXå¾?¸Vb{ŽmZh�¦qJQ�#£¦IO± ªˆ¦™¯ÃËoZA/‰ýãtXw<—FâÊü»ì7ge·®’­¸p’Ú-Ìg„§æ‚ö'}ì Ý„ú»×™?r b@ûOtõ¼E’xÒf6wQž*½ýA$ÚNcޱ6©y«ÑÚ dÚÏ!Â'©ˆ¼¿‰oì¬ð´Ç'܇8_;Ä Zû?Ï£–âÊÄbÇHßÙAb4ý \m ;}Ã2|}ï-åß'‚Ü£ÂØÕ#ÂKÕžI\çøÑ~Ž'~]5‹¼c`ñ§Ç0)Öå5…Œ•ð‘ƒu3áàÁ­ø/(‹"²pÿ…ldnÇãŒ�Þ ý•Øì²¡¯…ÿÁóCüt<Z·ÂMçåà€A õÐj…$ï�ߥ›¼‚Q4ö9³CôöÓ¬aä±X<²•„ë–Õ ]y•s~Qá“yªOáºÑ÷Ò…‘K*h|M —¾¸HÊ:ë˜Ì™µ¸½1ê§ ™–¶*y÷`ÖV J2¡¸éí LÜL§ÿTÆ¿}`f›1 ‘ˆ&7ÝÂaXâ;Ý‘ ÌúRÒvÞœìQÀçÆF °'2>ý£}'Ž�ØÒÕ*\‰ÚsUaVi8�ï§“NV‰t–ðó®zËÃnŽiþs>†œ¤¹nšàô-¬ôÍÉÅ×ÁÌMSE?/·(-D£]—‰ÙÜz�/Á«ù›H9‚Å èüL%ø–² ]µ“Pç!ÖúC!”5KAò›gÄÓïs[Ęd‹ƒ˜z¸ü„–·d€\?Ïþ~ úÏOœ<ÍñÑ�tÛF4ËtQ0ÜNÚÿ#õoBÓÖ8ø³³—·2&5¨ùô‹¨’PÇ„U=&‚qkÍT\gÏD¨|0Ä's àí%xòd5e’Yg諚—œ¦~ðl|„–ý–o÷8ü⸔½”®Èpþn%C^Ïiÿi_2—=ý"ev›�ÝÕV¶6‚2'´ñ¸NÞÒFá­E(­ÏOCª'ݺÑ2&˜k×>Ð�2‡1/Z8ÅšpyÕÖ®=5›á¬wNÿpÞ®© Ò|.°¢üé<�ïÿêQo­cØ^àK=*“M&Å�», w•Váj»\òç¹ t¾ÌÄHÌ'믤Q9­–¿ˆ’š6αåÇÜêȧ³Ï¯Å)›~Ó[Xh"ÐkI Œß2pw. CËdyó‰å ~9JÔ£ ÉþƒP;1—–Ä_ .;• 3„CŽÄ¸ ¤�^Rð†J… ¸¾™œÎ§5~Óyf>Õ. ’ã•J´3I­U?£¦# �Oóéò± \åK’DÌQoM?'ôI)òÓi•ªŒÅxCl^9 ×ÏuOåi$™Íi„šGEÔÍ¢…^p¯'îÄÄøÇÔ£T‘r—à:& øÚU€§ŸŠç’QiÚy&rq |Þ5 zuðФ4>pbuª&Èœ ÚçVÛ9'põ‚GÄôàB\]1·­«c û©°ë5\¯jJw“‚Õ_¹t[ 1º5\8ñðçtlDùâ—ôâzW4¸_Cž¯Ñ‡˜Yш�Kaœ˜-kÇŠ ¯áÇ)yH1dÇ;céJ3YltÞŠJT¢Þ¯¤�-�fî‹ÔàÌ÷ZûÅ7‘7ð{¿%Ø&ŃÁìÝ2ÅüøïhŒlŸN›Ò‘ã™Dr·‹Ò¿Ý•P)6›B Gò Qzú §ßdSþº´«—¼;aþ¾zh>†ÏKa§ÌS€ƒÒ-Tþ¶2uð|o¦íÏÍ»y˜[¾†Gò½ôñ‘T>Jƒmœ 83µ†Éë%ÿ^ªC·ˆÞ퀹¼àöû.»zµ4øKy¢è`(^O¦1�#!,í õ¿³ V$«‘ ‘AøK¸˜uúï|ß7 Ó¶ ¢ŠÆb\íºŸŒ6%`í^ˆñuª6ü“ð~H] 3©àÈ žrÓCZ©ÜMÂÞì JÒÕôcw¦‡>†yŠæ¸ùÉvL€ÂÇ5€žþA6Yù/MŠEŸN X”ØÏ˜Nv=CßNTòKÛyàÐû,öÅ™o gÿ…³�Ƀ4CÓæŸi%‰0ûöŽâ§Hãe’ÅŽ†xOvŠùÜÄû3ö ¼Gzvt±“ä-¯'©¹ >ë7�.{¶�[Àjï´;ITÞÝ„Uë`kš=X•ù jŒ,{Þ-³âÓ¡¯0„޾©!\9sœM»;Tá}n?N\pâòö.�qÊò$Ö£Äübp9F¾Ïܲsá@ïURè}s6çR�pðóõ!^ú�î"%p]>yÛ¢4µî9¥+­é÷5:ë¶rutpÅGhê'«îÌ?§GhÓ¶|v±˜s„/.øø‡©æ¦‹Ðþ~+ÊV9ÃÒ{ƒt³õràû&Øè'÷s™-¹±’&þ~K7¾~B½¼w�ø  3ýT¿ÁRžDÁ²D�ª•Ç(±³¤oÉ6¼ÅyLú;ùI,ç±RÀþ7dôØY<¤Q@ùO¡êNêäØioÜ%ŒŽ|W@KÇŠwç£JQZÌÐg“‹äxM U;bÚç¯Àô+ù˜&|ž¤‹PÛ{ÊØÃ3…ðÙ¯Ù^k”Þû‰èO„c¡„”Ý[Å›r"�”jLáÏ¿I câ`׳$rüL2éÊÐÆ3s”¡ïG\Ý 2«cñC]7iN‹£Tyü^ìÆ4ÍDNÅVú_I>6‡àHß8ýd†î—½©nàkÒœj‚Yº¿ÙF§zÆy»…2qo¹su"HÍíG¤ÍE„¨ü‚6-M<?…¹ð¥ ¯”ÍÆÄyé„ïh9IøëÉè—Vw9�ÆÓscq¥¸&Ÿ-!S›Ãào3Í» ROha£…ùïá xñ£vyÁu·‘½G3P8}€ð®éa5‚«@öBŽNé£o‚\ÙüÔ9`1†Û@×Q9¢yu†zà…`1Êw,¡ù)Þ{â#ë�YíŠí¯VÁOÁSàåg@wEZ£Ùý?´×¨•vÚ®£œ•n¬�/a›®Å2¾ÖªÐ¾²œr‚Rq,LÀ\qãk4+ËØ:†Ñ/%˜•U�ºMÊ“lí¢[¦Š˜«¦År� Éã�H÷é÷4Ì~¾+õZ5º¨;m,.ÓÅ_·c�ÀY¥€R’sÁå±*~~4o]@)¡éæ«3ÑWý �ÿ8Bcª ‰DŒ%Úd‘j©7$k�„ù�øLö÷p7ùÿ�vvHbO¡*Óñg[>0mz}‰êµx¸4å'ꀖÍï¤ó³ûèüמ`ò~6ŒòIóô#–`Âõ¦ëçš Û`í´ýh(,I¶ãö_ÓÀwk>TUÝ$G†ò@#¡øšoÒ=g�D°«Ì›èÀGxõĆTlÜ];$ñÞûty–@¨["©nUƈ¬1¢,ðþ3̓“IÙ8óòwº¯Ú ´ÚJa»£"MîOì—1ػ٘XöÎç¹ÿ‹fßʨcû�D#ÇŽ§}þhúIw}(�ȱ&�Z½º¢ûh‹Âb~ßöªµavê5�_†§î¤B_epƒ«œÑ´¡³¸Ë`шêÔ€rG4]£kŽù�Ý4èÐ+çH4èaÕ‚QRZ¼ìò&©‚(AÄŽ%äf£™úð'½1êá÷· ”¼#Ó¸v=®…·2Àñ¬Î~±"åeÁ9h€µãôùH!Ç$Š,sQ§ÇòΓ‡M`ÜG�v„cƒkÌIæLšÕ â|�Œgý¢—þÞ‚¥ KqCÜÌR§_p%T×ÃôlaÞ|qE¸ãº“töìGÞ·j¦$p¢ŠòÕÑïLa±è)ÎÆ±©›±1ì3á³vc5ãßѱÌ&ò/=_œ(À£xò‰GÉvá"²¢Bê̪ØÍ«¥qÅÞ™¸ä£Û"J7�Ùûn4-$îÑÂYa% \­|äsuÀ[2 àxq%ÊÛòèòŠgŸ…¼Ç—iür 8ß­Ì ·Ò+Ÿý˜¯"�$I9¤í!Jd Vµ)â®�_è†YgЩà ÌxW†ü–Fäpg >Ó°`÷(UB]ÖBH)`ÙòP˜¼¯oÐãØŠÑòEƒ¬»Ó[`ÿBíQ}%³7œ\Žî5vð¼T š—RX¿Ê†“ãlNËH#åï¢7ª‚îÂ$@V5.ÑË;–á‡Õ&x`�3>ù~‰<üi Ê¢1vç>Ès±¢�ªI˜¹&VW¤°éÌz’ž°�¨]5Âód—­…¬¯S`§?›ÑnÊk]îîä]Ê5˜úÚäMQ-@¬$áp§ž˜YAÂöÿ¥}gÓ๒,Ñþ£ ?Œd Æ*Õ*¸øÅ$„Ž 7sµåb 3(�Îþ’D=t$Á×ñØbmÒÿã6TÔÅž‹ñäç`|ú2tÅ ˆzØnÐTŒ€öïi›�4œÖxK8Í$He|QH€}Û”ðú öɯò3¢™»¼&³WÓ !,;6m*,é$ºšh¯R+õOøE“7^bîÚ ¾Î-DÇÕÃìõ˜qYþ ¿‚©çäð4AøÜaÍÎü„n`Ÿ7›2‘Ok ßø¤³z²‹—ÎÁ‡¯déЮ`œí^8éäÝðþßZ26½‚…¿‚îÚ7Øé0H®¿RÀÍŸ^à³_3±kh’Oßñ¸¸¬ÈÖÆ�”Û8pc/.kmG8öÔ�ŽÛ^€Çgî‘0�*°÷ 'ÖçúÈ…ÛÄ|ˆš2�KŽ£ø9k,Ûb„£ßeéuGjßõ“ýW"BDùæ`êÐ/*ö¦ŸäÜNŒüõhªÖ+ÖÁó ÜM’C…¼b½q >\¶™<ß½ Ï%Å‘G/Kè«¢#doƒ1Ó¢Íà Ê ìé(ÅõnZ°:�V[í~FZ†8Ì“RÜ,ÈÝå Ðu1�„|¥ª_œ øì â²öÉŽ“Þ%WÐÿÐ3Ì×ã…l ÃÞo‚æa>áÔÎáh¤.ĽZ¶¸mîõêEa”õkúNfú§1ã¢ôþ×ótÙÏøSVWŧ­Ÿ³LïPÅGy§È'G'ø‘¦D–GÇ“ ŸŽ^ïNX°.„lëH£•ï~ÑY‹™ÍÉÕä×KQš]†ë2‚`q¢ 8P˜ªv�Q{‚�të¸dÉf0ÏT‡à;�" �k'ýà™ž¸uG" ãó”Þ½uƒ&Ì¥[DÛ`¯Ô]Îì†ßÔÕ‚xnQÕ›6¦ ¦ÀK§mØä&“o}õnµ©ˆÃ¶[çðÇò¯Ärê6êv[ÏašÔi˜{K2ͯӃåÙŒÜ<Ù9Ôg ÁèÝgôYRûy6hviFß!�®‹ì=úg‹ ÑØ#‡±Q›`Æv0HúNYëH¼c½þ”*Òʰ?§Œù÷ÙÃïA¾ë”_ã-±Ûqƒöú¾‡:‘hìT_‰²�á΄ ¡{ð¼,™œ™v�sø¡hê2\ç’_xY¤>·ºãõÀMD ÌÞéÁƒmßèVÅï jÐê+ÀÛ½ó7™¥�·梟ñì<— w¯Ã!Ó³àPô”þPK-!Ùöÿÿÿÿÿÿÿÿ arr_8.npy€0✗÷;×ÿ÷Çí!£¡%dd4x=Ï1*¤”ÌJ(+J»�‘½"¢R¢H¢a=‡hHK)¡Ð. ¥=¼ëÛç_ø>®ëùÃã\×óºžÏóxÜÏývÏZäæè´LXh³Ðö©þá~aS-´¦r�fSõµ¦††E„­ ñ óø_ÝvÕºð€õð UþíufÎÒ×2žnb¦«¯µSëÿµd,5ÎCDöiÒ’>îͱÂ'âczI{Ð…–.£GAþ4ð;½xcbÏC0m BÅQ"lÞC 2¼Ì¥˜5BL·ÎÌÑ•À½ÜÚæ«`òNœKj8ËǾ1Çɧ‘È·¼>V7sÕó9 ·B‹äfŸaú—fbÕÐÚâßÛÀNnbÅÑG »_œî2îí§||l]„Šsëi†ÄQŒtóÅ‘ÛÓA?g6·îém¸TŽ5{pUÁ=°\O7¨Ÿë?Ò`•/é^¤Cõ‡!ñ‡ФyЖíw˜›>BöÝ:{ç ;gÿž�z¡„ßî¾áC“¯âÈs-îÜ)¢ôIø‹‰ãåi›ÈÓÊ äë q™é:*iüŠó¯ngz.#éøÃ'ü�Âxxdµ3ŸÅ�g�+)}ÆŠ–Ç ZÊlòº[F;;åq +é@7l»1§é�R߬@*ÄWÎÁÞ‡6ØüÎ 7Oê€kÇСD :~ù5x¼œŽÕ[O±ù Y܆sá¦~ž†é�ÈEÞùc:ú·<…?ÿ ðã(ÑÐ� ¼²¶»Ž QÞ§X’oÿ¦ÏÓAñg'™xÊYv.O1ñÇœï†u¸e¦Í\‡…#òáýOØ ó]ÌЕ£yÛ›˜²@JÚ1`K;KLkÁÛŠc,…8ÀKÉT™®�^¾šäœ¶/ôÖñ|D§ˆ¢¬uk]¥@§æ¤àªO>ló«;Lûëa~�Y ÝMðã¬Gå`Äõ{L§_–hO„MsD�¢’áû‚D:ßdX|„5—g7Bãh}Ÿ"ýn@õ—[Lvo7ùi .¼PÎÌc$£OMÆŸÒâ#lÓƒCÓ¼éîP"}Ulá"‚ä¾#diê�Ç6ަ‹›6£¿�4ô¬½Æw/Iª·›!Ž–¿Ä©´æx´�`SÇ&³‚Õ›i¸à'×§'Kõ›$)ÆòŸ1Ûƒ�Ñ„E»Ã0À^\t7Ëlqâ m)s�Ý–úl¹ªIãyY{˜Þá…º-ɹÆ“üodŸ¹Ì ÛaÝ1Ú4uèæyÁbÄŽÑôY|>n«aç×ׯÅõ®•äõ&/ëRb¨Ž¶Ã½aGXS¹µÞ{‹7¹¬­¦šåFÏÄù.QpÅèå7{&÷'N·Æ›5øºá#\Å×l(«èdA§fãžèÑÔh~æmJ&Ãý ™†³òp‰õtŸaÄÊsÁ�G(ññ&'ÙJ,rwÂŽ0gvCó<%h…BëqJÚ ¶,gÔ‰(±;¢Êx­µ löá“Ò`+–ʺíb¦ú'ù!Ç? ›ÍM’$™qƒìïRWjm¿Á\ü:YÖ%!z¹Ó†Ût~*i¥_¢§b]‚)º9T6PH\1f‚5îIsÀ ¶v81U# w)y2�Д;!€Ö-—¤µ’+¸_ZÇéFY;sÿ õ)@G—HhöûL&•‡˜Ê˜•¬ü˜?|7™‡w÷�ë#½°a6:ô°E?‘®\(Ç1óöà"‡ýœþl>A/�*Òð”pÒ)N>Ò3¨«,�&†S�‰%Fö5ÂõBaõÂÕËæ >ì³Æ¢`6¹M‡õ%¹¡;úìBCVöx¾Œ³Z&ÁEm˜òe5¶Þ"…w'QÿŒ-{\0ž~æJÁ·â3x®] Ï]ƒRÞ….�0¢�îâ”oÎùIŠSâsW¼t¢ ŸÁG¶æyü™ìB¥Ò·Ù2ÕLpÓû Î1�T~s4ò‘}{fiï^�ÇŒ¦ãªÁxs42E¡ß»g’0éDRd±®.ç—×hÆÂk¬´iEföóJB”¥Ã˜_b M ‰çÞË¡ºô,Ñ#�-Îé$‰»KqÇèZ&6� ª›+¡à¾Ù�|È= …º/غÔ8ê’.ÝÒ‰ÄÜf¤ÆÓE¬ûësðRUÀ‹¯ YSè NzÚ¼h��ÒºœöÍ8ªÆcµ*ÏNˆN¥þÅy¬êç}vöÊ:j_©Kßû["ocñäcÜþ$ ÍÄPÐíM¯.� w]öÆÈ–oŸ Eµ‚ØœxÍ=νxÃ¥nû33á‹åW¶à¦>õVqwKf¢æ;1Z¢"ËLÆ/€Ò‘÷ø1á4iBáj=›Ù #„Û!O³ýØÊ´Þì£ ßÃplG‹²›†:[× îë§l܆�½J Ü^H§,[`ü(EË zÖŽðC?�•l]L¶&£ÐZ{ª¿»P·UÌ¡÷YXÒê+PÖ‡1»#iÒ=Qz®ÀXóÜÕ÷lŸƒ`òÁÚh xW¡ŽÒ‚>p »ßPSóËöù!9XÓžžV6½,“¬saóìQTìQͦ¯øw\ý½°iª-vßã½’xN‡/]DZ Vxò÷´ñ¨âL,0\‡Ó29âÒø/ï…Ù'ÓEtI0�žoÚ…ëC:Hû9’ˆÿëÓw–ßr§_€!ukœ½}ÿ¼ÕL5£Ðxò঻C÷Ÿ—lê´,ì>…Œ2Ãi‘fLµ¢3zyhkd�j®&ðAk$}ì�Íöø&c†èzš¹£.VÚ�ýÄäÚ™øüÚ?\:�Yf—Ø*udÕ¾r׆ H´">¶Ïç�,!áÅÆ›ßWóÖ·¡Ð;‰õЉ’¶ñG€Ãú–*ŽÉg“q´Ö^èÑ¿MwõµñþŠnWª†vK-aýÇkðs�>ò£­¦A$W´?Ø?¬»žJeíðäcfô¬•ÓÞ{™Dîÿ™ºöû=ÀY”Ô˜ÉtkyvÏi^8»`‚x:º«‰ ­ŒÐÆ{$;öêÄGì‡u�Âdö>˜.—»ƒ•^"_SC�¶a‹<îpq¦éLÑD­� ÜœŠã>%sbª)üÓÀT¬°M¦’ßãYʈ�dqê<)ÝÐgLn Ô—ÄMšÅè?‰Ç}îÝ,\'ˆ\$f‘]`+ øœÅ¤ç±4iíZZvц_h`ä5,oª€ÕžºÐ‘äAe«ÅÑ_B’|$Õq…@‡38o�’‚±<î™ ûÜ$!_N¨1®Óumh@¤ «<äP"þ1^0 ¡q¿‹8¹ÄÉÔµl!Yú$Éf?"‚Ê6ÞÃ��—ðq‰-üû�2C5Þ¨Ô«)÷Ü èX} ´ä›Ø)×K¤©¿Ÿ>\/"©º$<µ£�}ÿt‚û>æ9F=®…íÏØ(ù8ÓY–Ž\z€f6pôš.°›©Àv½èýÇZÒg`°?§;œ…™‚Pá]K0ôÁß.‡P%°ôm`Èv$Y)/´ð=™cå¨,‹á£ Ü\xœ¥ŒZf�_çjˆ71À0^‡4O ³Ì™­¶;Š?†…,‡4Z°¦F÷K¾á­öi’[².nZ(BšcGBe©89{á¶½jØ~5�ÌÄØç€EàÙUk< °×-_ ©ðzvøùÌ ”>y¾=r@·@9š¾É›<-\ÙÓ]o`$£o­(‹oÞBM¦@™‡<Èç¦!jZQÀöuÿîÎ'Þùª-3l+$íæ¥cvRö8²O6 *µ Pø@?ëhÊÃ'i—`UL6þÝË)šüó£jÐîº c¢Wp­;) 0–j&îCÑù˜âHMe,%1 ·ç�‡øãóqqlùÖ¨³_÷üéˆÏ.Ü×ø†æY£›á*n†&Ï-†½S¡"t5ÌÍž€ûuòèÞ“k°ùþ%´Ûù *Xácw¦k]KG²AäS(µM;‹�é<Û™°�ÇNCA�ëYÝú’ŽzŸæ¸¶—ðø`N‘•¤ï¶¢øÓ'Î�…c’J¨`BÐwe-�ãÄâ÷W²á·Õôѳˆ‚–ÓÍÝeøqgîrP`ãã¢ø7LŒô¥ïÑôW©ØcgÆfE4м‡õ‘ß·¬ph·‰…áŽñD·rèVÅ\p¾zßb÷ÎRnÒ–v»spJ¶M½rµ ݸ`Lþv™¶ `úº™$õÃÆÖBMéT|²õ)äœÄó>€™óÇÑ;Eö£4ß-£‰ë"਽ä z‚¹©yy'Óœ%š¸nî[öûU8§†Â†ÍËqêç`Œ¼ Ù–G¾-ÍåC?ïÀßÌæH$Çձ癇ø_�ÃwÏGwoǰ öŽ0Öñ° 5d%mÞ‹u9Ps«�<*€wË3ÀnÁ"üÛ V{Àá˜�|Æ>%£mŠß–År-¢ï¡Eç;“ۯظ%I‰žMÙÆÎÚxÒóÉjìùþ‘è_qŸ‹/gÌhõM(=8¯h¼ôN¿Š%qøÊgåo줣–B(*ˆÆ¬7¸ ´“‰ìQ£ ^+)êª'?(U&ØvüIƒŒðLf6ÍWÃSƒÏAë?7šft€Æ½4d b¥-_»Äá¤âÚe¼�Lm¼éüÀg²Ì«B>u‹Õ°çf /9‰šmO¡§¹}p²€�{¦2ÿÙ쥮:ä•ZÖ±k­lü³Óì¦zµHw�ÛÙp¤G² Âk†3H[M u÷­G‰ J”Õf…G6µ³isÿ²ã�Kió­” k°(õ+&¼­¥WëD,mÛøó8*¼¸ /å)ùœ!jÅ݇i¾n¨=?�…‹žãoº&ÐCÉvº|{�m?k „ió¬“ ˆ¶�àc]Ð8G€dÍèqþa(_®†rþÏXúë8\é*†Æ’cé©›³%nññ„ Ò¾�ßc1T;’NæKq[ï=˜ró8•©ÿdÊ2«ñÃe3fr/ŽÖý>ʬ­fÐkÅ Lîú'&3F‡ÿs"�Õ¶`€­"[Ÿë€;›•á̈‚1[…ùæŸJ¸RÕ%r_cb•8-Kò¥äï+pFGSÞq ¶Ä ô# Ò“g5Lß\&H´§_7`]ÚqÈÿáƒb’k˜Îª]$¿àcÃÂæ#è¹õ9“ñž CN3™ +пïm”x…Åÿ2èã—«i¸´Œ›iå¿’âPfh/Î$}§],yV)x�i§4™)&GÁ#Ÿ$ÒëîâÚ¦h¢’¹#n J¦;*¸ìœH°”û€§Ó‡ â &KÝ!OAÄéùÞ³lÎIEîaú9šlõ•Y¹Ä±àAuXè'EÈl±ßE•)”j²ð�õøY!—ò2çaÚP•ż£j¤™»–%&Aw†~„m'�V*ÏW—O!‰ÑXÝîL%~(uø9 ûž€c»W"=žÅ�xáG>»­°{½+(· ã�§Ø�©=ËÛ¤GMþ1ì:ž&×·&x ¤ 4>¡Ñ�rvþò8º:Ú¼×_†…_Á¯´ uš?À û‹ÌWûתšÂ7Oà�•1|úv¦‘FÒŪD׫`pâD:�Ïö~>šÅƒÐPƒ�‚:ÍÐ+`�e­ ûW–~¥áÖ� tB ê<×”¡„ü-&,õ„Í™ðâÿÓ%�—‡XȃÔÿÊÞÆ>åA[‡†ŠnSØ:cZ]ŸÂvYpÄŸ°%ÑÀ-Tž8]wDÁ‚ƒ3i®®[)·e+Åðí¦«(s: ³f³oóîsj!R¤;¨vÖz\Þ;wèìãÇ}¼Cm¿uQ£9ŸÙœ $Ï= ³g=çï¼WÄçQú8îñ,¯(Æ¢x²ÎÓ„C(|³ƒ[&þ^”®d¦‹ï±U5(zA/y¦¼fÍçS¸»¸¼a7›ù9…ô¼’éïl?(,~ÀBdu0ôÈP:jŒ³ºUQìý6ÿÛf<¼盥Cù—ìmõK¸ÿ=“Õ¯½Ú“hþ†J¶ÊFþ Ñ ÿ|føê œlagÂe±ó­3,ý틣잰ÛÇò™zôMætȤq×%aPšPžY3¨ož»ÆF’¿ìR[6oÛaéO*Üñž…ÎÕG׺Ãð%9‚ƒ˜Ïpª" í"Ó—Q¸Wý i§µ[Ø÷KXèfC&1i2?­,e?¥ Ö߉B½  åüžæb½\h¥2ÞqI…IKÂØÂuxÕ#›iýèbo ýèlÁ«¯%Ç`Ãý‘xú¦þ9qÅß|…Ç£ñ¥­?èÙAUqÇx‡ ¬ž¬CŽ27áQhi/Ob 5ÿ¸e‰;<ò; ${ò(;:“™^0"Ë)z”²Ç�SòJF¯£¿î*´éA%fž»â áL¸¾‘‰äÍnÚò¾÷vQÝñP ~:…âÅ�ñZZìý¬îž¬<+œ¿Š„êÇABx)ú7WÀšÜðt‘Â÷tø4õ‡àC~"}» Éd¥Â©O>x[ûÐ*Öi´Æ©}€Û«ÙëŽËlåÛyl®Én¼ôé)sözÃ:î+³sóÖÒû$¤�Âgœ[Ž3ŒÖ¡TŽ ¿ãÕufFŒ)”?Æg³÷AõªrÈKyF_Œ:PÅAØRSÎN]¯D¿&(TÅ}»¤ kŸ^¨•ò¸¤I�æ½·§¿ö[Xä¦)hð�23Í„‹ªÿi€€FÉãü•µ,du)m q£mîN,ߤ<ôUðsåYT2&žnè»j:]ñàç¸ûóÔÍ›�Å “°à¶ 7‰1o=ÄÅš‰(»  KÆÍü zFhq?o¹Ò¦k7@;ЀZ…5©oTÙÄ@Ø‘BäÓ£ÑýéKÐUÅ‹ÝRøG³«>JÑ‘m²ÞçH‹,‚”/–ãoƒ'xZò"K;WÒyOYït3�|M8pÞ³ž�gŸž+¡¤” 'zç yñÊpAòÆ­;É?5!IOG¨ÙÝÀ²nwpia¡“i‹ÙjËf¶®=ôåYç–tô¸ »†®R«¾Mô;†³W×€Èò41”Éwß²Åý?7Áº“»ÁvÆ!µü,×\7�[3pZLeÝâ‹ô€¯¨~Í� YM>¤tJŸQ£�zý£étöV˜Ú Š´)[å:û-H’�±$u㛽?Ÿ½±¾ŽSSLW \­`ç3Æ¢¯D>-=̳ĀÔ­¨ Ö£€.©#°2¶Š�²¹†“‹5øñŽóISí«¯¸FK´ƒQËm)ÿc‘³SÛ8ýi[ÑröZ¦fÈ×Í0¿O]� åã"�-ÉçåÕ0ª8—~ Wž³zOê›uú7T╇›˜C³"9ûõ6¼Ó¥ºõYx¶E¼_2wY‘F5¯±¬^ˆø‡cÕ˜ŠêGv°Ç ïÔrß4ß3¿cרÆa›¨›M‘‹GƒÏ‚Ýh½pÛà .‡‘”­W Aï,+|$"†uZ)t2$�S¿Å; ãM�8+·TEñút`ÏèýP4„*d¡Åã)ðBÝŒÿnhNÑ×öÐÏX´ßíF]gÓ¨üävrµ1÷>X‘æíWÇîgŒ›‰Ñê�þ†";/—D)ÊG)¢y:îÊÉ–ù@¢ïFÚeÇ®TL¦é},m·-wªKŠE&i¡ÈؗЧ×Å÷Ÿ*<É.æEÜd{ï]†SæÉÔâ�i®dÑ΂&NƒÏ`¼AKRßrg㫜g¬ìO3>ž‡ˆå¯ å¢ë̇ üè<Ž =ÉK:—™p›w}㽪ÐôÛ¡ÿ²ÜYŸ˜Çºž¨â¶º.XµøKï€!“d^zñI*Žíž½X›‘Cö[¦Óúš} ß&�+—µ´29úÏ|g×GEÛŸUxf÷gC‡ö!&7ã(.Z˜ŒŸ 0gêO¦ŽŸ˜då|¸ìUÌæšÀwñ]Ž~Ò’‚F®l¯¿ŽØ ‚3üÈI2�˜Bin�€7NB¥ Â�6 >ÑÝœô¨FÁ�Àg¯u@Vf‡Õc²èj]+K¥ŠË¦qekµqg�œÀî�†¾½Ì T¬#ø_ú`k¹;iTwò›¸E÷¡Ô=‹«×§ŒpaÈólÁÖ«fÌq÷,ÚçtùŸ¾gÁüJtÚ…GÕ°QSæÐǭȱY»Ùçc°ppEîyÈ­~Ã@Ä€l:^ÂìŠðy‘4ö¥[S†Cw´lÝÕó=‘1(cZÉüŸ�`/œocdÂ[ü�‹ÓÿØqw+ÿ@änE´ô/ÀÈl ,ÌÀ /;¸a‰Æ4ïë,4>~Xÿ»v m I“�ù£?'ÐȰl4ïÅmoy²õ ä¦É<ÅýÅ«i›½¼ï2!Õ¬ xX£ÍyÍ8Ç„ÖéðÅ®°%‚[¼ý°,sì›E±!æ("iOÁ¯EqíõЉodéjG˜F”(ÙL BO]G�_¢ŒÙ»‚°ÊP�êN!�À �¥�@ÇZ¤˜ü!vY7 Æ}A›ZIœ1Ï‹ ë‹d)qÂ`v“Õ�é»î,Йú<K ?ýË^–d¦T˶xfá¨�ÜÝ•ñ|Å&u<¸OyÞäãìÕq z•`YT »-ŸÎÿŒ‘!“'žÌM¾„ÕÙ ^.gÑÇ'¶Lwd! (}ÏD6÷ÜB0öµÆ·�Ø%UÉ¿¿™nûµÐ˜'27¾dzµ¡à{m‰<ϯ;åGÆ#JµÞ fÍNs¯NÜ› ilQsþ°T»ý0?Oˆ–ýãåU‰,»½/5áåà#,¹'—œ·ÆSe²"å´ø““S´fwÓ˜×æ"ðYáaSjùÐSf(ÀSuYkhæÙæò¤k°€}r¡{÷3žkD‹ïFã/vßd4†^"øžd€Ž[‹hAæ8÷8“"Ç_Eƒ[’ðM2}’›ù['ñÛ–³Xý{ ýÔ›I“pdß+~~y%}Úä5M ttNx�Ɇá½Ã0¹ îø!Ü9¦�¶÷ a�)Z”LÆb´=eº^œIw�žñÁ%�°eŽ7í<¹ƒ«þO½áÓ¤ ìM‰œ¥Ñ¼ã¨51K s"�ÖøÀ´$’ø£Š›´}IØIç*„ãùêj ½›*†ÎW´@ùç~¸ÒH~þ4ï§ÇYœ¢Û4:³Ð�ð¬-ðö"Tæ4E"î1%¹‚g{·E­ ù×Ï6 ƒÀæ5ô§`ÅÊõ�&¼—»%�¡/žÂ Ÿ,æ™;—4Í`_£Ò?~Ž#o«Ïl~õJØe:§¹} Oþ²îOÝØ5ÌÍÑ‚V2+µß µA‡˜üñ$¦tÛ—%?�¤Ü¼k xz%Œ G›ú`áˆ(ürµ®?v`wø&Öôi'[·áèä+ÀìâXZÛ¥‰f{sÀb\–ï‰ÿlÐ*¾—93 \w@FÍ,eQ?’ l´j×{“Nßeæiød÷+à˜ïX4õ#¸Ôý¶ø5º2µ×Sñ¶m �Ïïô`ÌÞ °sì7ª€ý¬üÅaÖ±ø5”¬5‚—ßm,4‚7㥈8¼ë4†űéÃmä¯+…Þœ®e™ÿ°w§™½^̾ÿeúË´Ùj|;ÿ1ðÇ™nìv\”ð•½>™XW>KÓÒMi'•pópíª® SŒÛqSûfN¢žÃ©,|Š*X/eTp}% g!®ª{È:ÒCàÚ¡KP™û ¦œödzÁ#èsñ°â+¾tšÞIRí…ø~BÎ�—EG挱¬ „Ê…haPÄï~ÒÏi J}/a²¾n¦‡ ×kÑñ9ºäì•HN¿'`”ˆ4Ó¼×1,ð/²‘Q{ÀüÙLlµ¤5W¬ø?UÉ(,ú˜ÿÍáÅJW|íÓÄÊ{þpi*”´\ Óù‹,dw*Žü}�–X†à7ñ6çM%Ï�ZNzV¾ØñÖˆ¹.¥È�ÊìÙ¸`ú¾½�ÆXœ¡ãd謮(�ó7`ÿç7 Ã# ñu“;D^’g›G&âÚ½¡øx™>šŸ‹ÅÇÝá4<%”œ×m…_m®Ly÷IÐ? Å4¦Ýc‡úß°gßÔðšˆ,•¿¾$�¸P€ÑÏÄÐÊ(’ÿÓp˜<½U‡!’ÂIìé-f8q-¸dŠ¥ŠÉÙ?ÀŸ–ï@>¤•ŒcÝQ2Ɉ�tÛ†ç[L™—aÛ`ãÌæŠ:à‹™iă8Ð8ǪîFÓ¯yœº} T�ÛÙ°sX—ÒÇp!“5ñ½u!>œp°;‘]¸¿ïÞÜÀ~½¸&è;r²?¨*ßä+³XàôZês<ü'GŒ»bÊñª¨»67Ÿ¯üÊônú�³Ú62ȷįo»˜¹ÄbÆê­¹NcE22:SJ™žÂ¼'½ˆ¶Ô»ã¸©ï9]Ee¹ÆÍ_XYñ!Ú®èÇÿÞ~�?½ ”°S–<ßâ×õÊÃxá¬�ÿAõ–E˜¸æ Ü\d3ŠÆXš61ü—ñ6�ØNë¦óÍÓÇÐ(GE*¿;ƒ°8Û�=ÄeÖÿæ’Uy½…Ž€žžžBÑwy�¥ûñFÖ2Œ ÊAÉ·7aèà4–j÷S`qæ"Ì� ä_¥Šã„�Ñ”¼| åöªaöLÞ=ß�vf}‚¿a#©Áf": ™‘Ñ¡”öÁ¿„ aà¹XÐjO¤Aµû,on&8øÂ"°™[E1ûóúe´•†nÅÂÆyÿ¼¾·›ù�3¤EÍD3ºIµ²Œ­¸ÒžßÜ3~ZÒûioÀBk€O|qt÷±b�d\R�ÕP’”Œé… û¼“ëgNhƒùžt»R7$áÉèzl¼)bzT¸i3˜óìÛóóì¹�* ]=ÇòŸÏB¦„¥Þþ¸mu$~§ ¯¶W‚úûVø,�ß\±‡õ¹õqåìs† WÙy–¶ˆ°ÜãÑXÓ¯B½+í£õ;~3©´�Ìå�7;V „V>—@[%™õ§Î‚Ã�z´Ô3UÌöð=¶ô{— zw?Ä߃¹`u~ ][ÙÃ6K¶0GÇ>.,mî µ¥+êç Ýò+û²óœ’.e=×Gb‚b-™Z2ùû(´§žvŠ­Ãü�¾¨"»Œ"5bð©”%½Ò­¦+’8=ËI˜±Ë”¿-¦°‹â½}9?ÓÁ²ª@áwO²#2zøw÷h4E±íˆ–žÆÕòùè|-Þ­8„»ÍVÐŽ2K® §û üÖÃj^"¾m‹¤ó·Òù–ß`´þ;®rЦµTÑ�äðnN (_ù ]Oõ)Êg˜^ÄU±üh¾A§s¦i©¢Ë[#\Ò N¯›p„ér:'UÉËÓø™ ð‡ÔZìÉÁI©g¨·=~9`¼«:/–—’ý¨=Ê•Æý¶f¢J&ôÃc“÷¾Êb× Ñ°œ7žü>‡»ôð�ÖtN¤�% (ÿî6ªÁ|p¨õžjãªõ6¬wq4û¾1'©JbF¦Jñ;È_²ž ÏBùÆ}¸ÝT ×[ˆáâÃpϡΆqË£èp‘ ?z‚]߬pÎÞïväHÜ�§ˆpþtÆ7è½>�ÜÇÎÀa¯5à�.JÊ7ýqûú7ܦÌ+4]A‘Ú¦ˆ £‹/;²¢÷¡ÇšàØXU\a{²%Ü1dm'«Ž ¿AÐþ! Ï�€Ÿo™Ò¬ýî¬3¤j´èoßZféï�µÑǧšÇì¹,¬ž±‚ªÍ+Ô_ #Ó+$¾—Ðoy>?t7Ãô#Ù»•¯YÝkM¿0k† EŽQÚl\|y?kŸvVqVøW$‰4öáy½~0¬û�eW%%WªÏzÌy6e@ƒöþ‘ÇÅ2Óx+µkìù�š@ÉW ½^‡à)Wœ5?�E�É‚sš} ¼ ¿½òƒ]¶·†>GÍ�“hòHŠ–Ü/c“¤ ð.¥¨â*ìÜô‡¬àÙ¹ÆÇ¡ðêÞöG¶„•¾ŦՌ–˜ná�# ÍúŸ•þ½oL'ö2³±‰¸üÖ&óM�|_zSaa/D¸?Åü¢Df½2†9w\eGßX¢£ßrV1·”Ë«}Ç æÛãíx6V½œ>I µ-Ÿ-Ö†R >nV W<¤ê—ÅøßôÊœgHo«…¸€C¥ Ö8Šz|Õpùkkô\—Ì» gâ®ú‡LÖ¼“.Ͱ$‹÷ûèÜ|·é,šÂ¢/LÆÎé'Ø€A µ¬Jbõ+!»Ý•³=qj] ôÞpC©M;YÐæi04©˜È•ů5Vì±G�ޱÜÈLغ=¦ÅRŸƒ<Фi’ò®cdš 8ºH–^tLÁÆÖÔÐÐ#X¿Ð‚æ ‰áÝ”êeÇM¼²q<%¬ÞG3æ~_…t6_[—î�´ÆÚ¥©ì†s#þ¬ŽkÓÙˆ[ªì§²1=ï~ÊÚ„×ÒÏ9ÏøËÏ/“š‚»šëÍ»“°Ù?‰9.šòéî#KßÙñ8Œx7©ŒÕ²n¾ô†)›®w¾Ž¿C¹�ÃøÒK "ë50¼p÷I?wޝgá}̤ª‚Õ}ànYvCòÆlŒË|ËÄtR€a¹@¼zCÎsÑöë~Ø9·˜*„ëÙùÛ®T/–Î~WÌ�RA/Ë39ÂÛ¿ÓA'ïiüñ¶ 8æËIzö-žÜÙOÃU9èÙ;»2óÀÚ+ &9¸Ò óÏ,?i,k�¦ÍSÝðµ}Í2¡ýR³Érå2Tj¡êwý°Å´›õϼ35¹»æÒxçôh Ÿ+@«Ù8åyL×.svLLI…ž |èOUó“ë¸q¿æÓéíöçc“Q¥ÅÞä;¼áâìT “F4 mÉ¡#½œr cS}m¡}› kìšGÑz¬E:œÍ»nÍJQ—�eìæÉØ¿‹ŠWýc‰�{qý“v€Å¦0$ÉýÓY ä;"I8Æ%E‹öfâþð»ÐºâÎ]ñ•M˜§€ÁXÄœÕÄQßÝ §_2$c£…ØÔ+‚¾[kèÕ€ßa�ëwžßª‚¦*ðf¯1&mÚª‡ÌhàèZ0ù¾'¦Öâa‘š«çs‡ÛùìÁÛ¿Ò|Çù|˜¸f )�=‚ï+÷Àû¬¦¶¼›³éh#¥™‘èñ·´ž`K븇û]aÑ©û´­$žÍK(F󯩸&P’2V§á«؈{ylTŠº¥ö¯LJ/‰ïC&“åŒ=ô¼ý&Œ�²"-iÆ|ŽhÀ¤C–Tëö‹Iw@‰ÄJ–­åÄÕt�àõlíèÑÓÕ8/N–H”Öˆ¿`'´i”…&kë™â›hÞ›ƒ{óý蘜һð& ‹x¿»9pÍÉ�{ñË‚}µ¿ÇÆÎEõ�·‚é>r$0ˆ¦‚¸ò©· èd •<E»è"wð~~ÝŠïc‰‹9Ý0\iŒ¯…4óýBàŽuY“¡I›þùH#×™dŽ ¯Y·‰$\=HÎ^V8YtºÛÒùùÙ54øY¿Js+ç“\Qˆ-[Ió†D¿Jµ“…ï_æ+_ÁTþñ_Jº»7pßÁ—�7g.ûáº~¶)£;áÌñ«Ðù¥M”¡Ø©˜¡û€WeÁ¯×Íe¥øÑ­,²V]GWàz‚oƒªXªFh fêèi±¢Ë×N±;Y7ø]e ô¨½–õ§¦‘S.B–—»ßù íÁÐ’óÔjŒ'r„™Ç‡ ¬Þ$J§e娧_ƒý™fˆsJIo‹"ëÉv¤ïç×ÿë‹=ÜRRÄÌ”ÓüÈwS¨¼-’µ–@EWvlÓCÕÛciIô~ô®aQ³UñîŠh ¨AWŸ;Òm�ÿDΔ5Ü¿q¾ý:ˆ¶/$)]ßÓ§‰PÆœÃÔỌ;°-šÚ[ÕH¼A k£\¨u÷i6Vs7ë1“¥âR}P™r–­ŠF¡z ÊÛ Š�¬iÖ"�µêƒ�‹åá«ÎQzø¦Ÿ/Ù9‚J +ø1“¯ðÇ~KàE�X¸¯•—ùãì»–XôíÌ>3 »“&±[ Ë+¿²_tÐpÌNòŽ„‰FúyNš 78Ѓ>TÛðï±û§ý{çà¦L·52ŸšÇõñƒBÐ5ô~»�€;“ÖBͯƒ‚E³n€Úì*ˆÿ¯Yà奓¯æÐ{õçÌ´Ï[&«sÒú{I¥†‡±¡,Õ±ò—t1³âùFÚŸ½±Ä.Tpê¿xÊ=‘¼7Ãï‡1ðãv&›´dž[RNcŒÒèå.}”Í/g¿ÖF³c#YñÀAùö"õhJ®©º³ô~Òdøò·¹s ;àÝW·5m=H,��î¿Ù•‡ N&“ªì¼{-�Ïœ«NïÔ„Á»÷8žì‹†›yÇÁd:Þ~�©ÏþõûÀ  Kù˪ùMs X–:âo}V>éªE@ÂR}½çÙ8‘Ð�ËdøÏƒK›c[¿�i oZsÙps$5è¹SÙ†3àU¢A÷×Q¿Œ#äΊâ>ÖëË4ÅŠàXèRžNö½[Ùøê±&oe÷0þP&G†ØdE6⥆:s!²ôo@—Air|ö�6ðG¯�㾑µ3\ÄàEM oÛ3õÎCªÌF6Òd=5\Li@…è JÎ�Ï%M™Ûî;CÚ˜¦|ˆtg”Tóöâ^¹t¸ý_ Û¬'0Ž h œYá}L½MˆÖ-\ ½/WcÈìX(¯Í�”2ä|C—""ýë�ÎXð[–哨]MRû‚…zºÈVýEŸ*îoÝ$�Ê­å…i`®1ÙU$ÖßT6dÍš:‘^Ø@²å”ëèÂÚ/BíUÚ¸ñs f¼X„ǽÃ@«‹�ù0F ˜bHa)Ó9·ß²§r êj³i·ƒ1=§�uur,½lmÛ·š…G@ßxž´6eNLDP¨?Ùÿ‹ý¾ô¸á¥L¦ÝÿYwáðØ%4ivÛ`o��òdÐÅI€Ïaé�uø³ò0ö­rǵ—âq¹ùphÉQü 7•†‚p‚ûLšÕV€wÒ—QKe9Žê†-­*ôî¿5ñ6�~¦|f3¬ŒQi_7÷ذ²£¢�ddа&{‹ßÑÊù|ÐD§êAS¥…ÛË7!šu±�§öT3s�ä‡âÖ¨88V{jÕvÐë%§¹‘ðÛ7W9áò”>*K ÁC,Ûl)UÔšƒ\œ1›]kJ]·Úa|�&­=§„É€#“þ°Îû+qôÉô(ÿÓö#ý>aÒxD¨i¾Õ,Ǽ…òµâSÕðÖ‹?LÙ~»ìyª¡kÍyLy /?•óg¯‡cÝ-StØšG(À–ÝÏG¯õØ;Ö‚–.8Â"(ïF ï¹¾>ß•$÷[³áÄ VG7òuø[n·9ö0„çG ^í8~ŠªÇ•6ÒéBæ^ñ¦¤™µlÇc#ÅùÕöoX뺒üª'h›FÆA s çQ÷xós¥ ŽÊi¿h1ø<8Î|Œè»òVú›V‰ž‹�±ƒ{¤iÞ=1ú&Ñxü"+\æVhu² ž™,²_ wŠè�Dì¶¿$…)EháÚ –‘@⛞3s�Y– s³0!·‰EIšQ�X.Í}$diò±�Ò~?å�LÁ\M´y=À~mƒA¥«P]0ž½Tü­îËëÈž§èÖº|Æ� ÄÌqlR »÷G=òØK×ñXÔ—K“�¤ñØ%38*/Àd¿™¬«1´…êñÕ†eìÝ8I\ÒSD‡ÿy…«hãòs õ¾µ¤"Óm9ZN›¹W~íð-Ð…[>Õ7dÆ0WúΖ`¦¸óp6ä7NÙ L縲 Ï}8ìì.sÂñ™×Ø£�$F:§Évƒ5¹ŽÊfôõ1òê1îz‡#&֙⹃є˜q—õÙ>âþ¿Åw òikq­`eÓxÜ?QµBîærvëý3�Ý:ÌññÍ œX„Ç÷›Ñ¾… Æ@ÑíøÐB¸œ¢D ,Öà½ÃѸ¿=Ÿðˆ[Ä¥qÚà°àg5¬4G…Îû†ÿu¯’næ–ð:™Z¨¿@¥žNÇ€qÖh6õ9˜�¾ šø‘�� b·—îÃPs'–Ôm¸xÃM‹Ø«�õðÉ©� Ô;8�©Áœ–Ò"¢  ïWCÛõÓ1bÃ,¸_ óïËÃÙÀéRï@dúUpÊ"Mé|(ê'š0j<•¤ŽBß/†hu2 _©ìÄ�ª¹o¯3ÉE/ Ô³ÚáÜÆ0ô_¬Fž+ĉ³Î¡ÂѽiœK&íâ熜¯¯/?Fò¯§àʧzl”ÇÔ�� Ñ+òoß…f� ½‰½Ê¯ý�Ñ⎌W\€›nº£üœ×¼ÈÁvÚ{f™JÁÎM²�µ_œèþœ+˜ö½ÉøSÍ|ŽÇíÂ�¥™ä¥·Õ,Õ0Ci7-éhB‘EÅèW7Ÿ<Ë41­¼ŽÍ÷0@¡E�°a|&[î‰�«çÀs-yØþì2ðÊê ­»z ë‰ «ð¼pÕ ¹10}·üY™‹«Ö%óÞ^¨ô1f3\4èDW\DÉüÌ"”2¸ ³ÛvÒîå²$u™gÎ Uõ>Ò(·Ë‡~Œîƒoà¸úØñP@vbï Öë\¸ŸN2 “ÑûéBË'f4´»V C-Íc¹—"`JåAÊÙ®GñIª¸§¹̳…ñ‚q«êŸÈô�¨%]—¼Õç]d{±C%Çù³êÓ« «µ Óß�‹›m�mÑǨü¤ Ê-rc61�¤#�{ì'³˜Õ píçj—˜R=7YÇð(;¹Œdm/ƒÆ“J¶¢ÜyÇèNù˜ðá*³ËbùÓßÀx�N>S¤“zÚá˜Íc6ãaª )î<Ó|2�R–YÑ[g#>Û:€[ýÝÓƒ^6¾Ð…æŸlM‰ΟM׉[‚s >è>ÓÆÒý…oે;<û:×Ft.ï*ÞÍŒkȤ۰µç âç. ‘é×­|ªN(åfç¾„Þø Ô Ô ? Ø*3žÞè>�‘ŸsØ—ñmÐV2# �Ž'®aéSD¹(æ_~ vw¢ª\Èý€6.¦&8)î�·F�#•hWjývš~³`ü=ÑñÇGnåFn’¾ULøÅœ¿šüô ŸÆ¶º# oÜ©Ý[aïËh¼t��oR€*Í;ìö…£YèfEãÝ‹™æŠ- -:ØÑÿÞÁë¬ålq�ÞQ9E!Kͱgýjªn¦!Ÿ­¸ñÉ}zÝá‡w¢²ƒqر³Ò¬Ôq½™.Ý¿¢A¬í¶ bÙ Š¿ï€Üæü`dÜêL᮪1>¶ýŒ@xSmÛ�—šðð–ýT~š�÷Íe{G\Ì­?F%ýûhM§o«ÿãÓ„“Ø]!{|”H¦–óÊî_Ù¦«é–±,i¼¾Íê«ßÀ›Žtüª'æii㼂ãpêl5wäèX:öBŒýCé`ƒ?ö;kQd]9îÞ%-·°`‚4]8¸|Ími„‚Ž9œÌ¯˜ëÃn¿®Bû†zXtæ'K-΃êºï å>šŠ]~p—à»3pïårvè×\>èí¾ =°k›>-JÉl€§ö×9µ²ÉøÊU›Eº¼ä¯P¢†_—qÖü6nûª›œÝ�Ñló¤Lš*!Lo¾7ÃkAÙÿQpžñ\ýoG‘%$+eD‰¤É÷Ü7Y’$•úµ4´§†Œ4Ìdd‘¦•pî[DEÒVÑÚÑV”¿ÿë<=OÎçs½®ëý~rhͽ§Â­¦¸{˾øx. 2ߤ37[¤<µ2T‹±¥ì•¥ÂÕ‰sн֓‡ê»`Ÿ¼,ú¶)“ûʇá:å“ä?Å€79$ÒÖà;à²Wä7>èów cmé½³œ_¦>‡¶aÐu-ž›S*?“üh9^s5Ž}šbè´Ã/oä‹NÿòÙ=›±qÞJ¡óÁvÞT–‡ÕF‰\8Ê‹¬’áBÕð�Ræ~^ä!M7”Êø¹‚  ò8xùV^ðÙO8:;œ>¬ûG’q¹Ìp>ÿò*ì˜Z�Nß’úôí(V„¡ïÜf¯ÄæºÀíÁ©¢JŒD©©rÕ)wÖz6.ÜÏ£¸šû÷m‡4<‚C½£Éø'÷‡ÈWb s¼{È£D©‘ö`aóZ¸êòõV[±©ÆyúØ1eh¶S"e+šJ¥»!²q>mÛß eÓ$hØé@ï+—bH��›#/Êf}?É‹S’Á½Ë=?HñyŸ3paœ9ÛOÏ�áéì™�Û, °ŸA:™Žãš·—`äÄšñ=t×ð&»f4ûšÑ -¾|þŸ/ #ÙÞH»à¦è�Æ[±¡q èëÎ@ƒ'=hÔ )¨4y‡¨ocÁÒŸ[„Ï7Ú@e€#¶Ê\ŽûñÚ›ò|;ñ#iJɈ?¥&-0yy,�/vÇsØî¬7L/€î©¡S?ìu¢Žw6© J)IpZ8¼)¨ø¼xÕƒÆ]V²?]5„ …“qèŒ�¨Û¢/Dôwä\­aÆðFxÒ9™¼ûgÑØÜ©x=å …œÊÆñn « ÎÀòà`qd/-ª\H-6—áWÑó~£±ép=I�E�3³dÕÝaäPzŒÛ§-Ç,ý<Þ×$mžö¯š&ÈÊñxI-4È^`Ë×m¤–ÜO,뎨ëÊ=ömãJë0ê›?C†ir‹N2­Þ§Š¨¦‡ë÷‰�½F°Åu=ì7ÀU¯¥Ñv ôn/°Qyá„�oN“tt*� Î&­Œ(ÖXåD‘—ãAæžN)é$û›)ôÇðô‡áÑ^àaÎbpR™h2#Žƒ_ì¥ÆÞZŒM_÷·áФ+6z–;hÒ žÑØǦ¸r‡toî×ú ÆÏý)®÷÷;í±8±˜Ì¦ÕñïÁ2h`â!h&|G³§Ô¾è»hÛöUŒméÉæ÷\ùMÿ4à½{ðòà¡l¬WÉ&áTs'HqðÅ’>Šè;üå(ÿ€��U‚DM÷ß}Kç7TPpÚ^, œ ¾Ü†ƒâüߦx20e('Y?Ôoƒ³×ä€^Ð#òÕŠ%�§N|vEG¹òŒwBï91’+Ú º-*½ÕÄIï'â¾_#)lîdÎýAÜ|y$hÌñeõ™+ød˜ˆsö„£×Ë `Ø®öáRüáð=zôV‹ež(òŠ ·…}‡nÐÔQ=hæøZQ—^åÒùAµ!è�ÄóýÎÄ~íkÀ½�ÂÃM¥°ÑbN]zˆí_x‚fâ*!Ó,žž¼ˆá×æÂ¥ž¶ß^¥P1�4¿Ðñ§�¨´ãƒ èÝ“§[[€’Ÿ?‰}Cr;~”;~wDÙBY êf´7}¤ðàÛLzòïê´ÍÄ�'šÄ…#=q½¤=Å—Øw¨)ëÝ�%/âœÃ«Q)ñ€ðWø^w&Ðã~ÃqÁx?6›Ì¥ýnƒÍ•6X™Àݱüì‡ œÖÅs»À¥µTT¸ŸÃM§ó}u|Xœ �=5±Hÿ{ù„Ûw`ó¡“�¢¯Ê™4ž²þBá`oÜ»Ë oTÃó¥@jV–8è· 7¬ºê#u…Ÿ]†X�ðNÝ®…ÓÆÇHº´…‚•O‰µ”Á׺…ª’Ÿ í'~Á°Ä +>¦ÐíI¸¶ùŒ<—[&µ$›ãf%Ž â“RÐQ[ƒ¯B¦ ƒ¿Ã¥ß‹p]ѵ1ìž\Á…ï‹èî‘lRVÊÕñõ‘Ó\Øl‰•1fhñí0YwÝ'ߪf°˜ïÚªâè¡7Å’Lƒn9œÆ}Žéöy;Ž5ƒtL¸Gx W~:Kç�¦Å=]ÐnQaª97dš‘ò¬9à´/ vÿS‡‹òýùÂÝÇÐðt&6Õ{ÑA·ˆ/[Ç£ç³Ü†Ã6WM'±—�;ÖMQé¤ÃÂSAw²>_Ô)-ÿ»÷ 4ÉÉ^cyëH=ŽÜ¼‚T¬qÍ&½—_´Axb<æk¸°84�Ì¢+¨%%Š "€‡ÌÅ…õªô¦SÞ�°Àu=•f�AGçëXsr¼=K§;³üä6(± <çÂçÓ}Qª—B™Îù0T¾±ÌÿTQ¨R?ñßԥ$áø`r#$Í÷CòˆÆ,ß18åð~nÑTô¬æZ|»º¾éß¡= î\ã µ_ 9S±”Ã=Ö’—G_ž\lÁãžIxÄ¥ÿhi𠸚Cz®³)rQÅ<ÓNïz Ö*Ùpóë[ðó܇?Ü¥üs³)ü··nˆÇ§�éK�å‡&àU@RïûsË€¾Yz�ROapAÌ<\oÉŠªÓøÜÁû|ü.ßPVcÿ HÑÆ2L”{U*öΈ.›«hÕÇQª={Î3Oã_þƒdï‹äÝeï+&ð¸ù×hy¥ŽpçQ®ë}†F—Iæ˜*b·A0«27Dì¤,—�¨Ù%]WE%«þ±ÞÏn>ci®¼ùPr¦±wEòíJ°>3‰­\E«²š oF*x|»EÒýRÈDƇFX AÔ|/¸NÏ'Ÿœ÷% }¦ìÆÛÝ=ñ÷\üªÎR$TÑ+žÕÂñ(��å!&ç…Þ1ªð8Ojµš`é�Õt²¦'»b¼µ=H¾Ø±óƒI,çœ.¶W†ñ^ÇÕ¨™}‡e2ç‚Å$îZZx\í…¾VÀ^±4', o�‹Æ]7äg¾Öœç¬‡íž®øÇ}-*þ @y™uà×¢Ž5F£qœÉRQïÍ‹w ¡¹¡AœüíËiÆÓCBzÈT<à1”.]^À˜ñ§áòžq\ÿÜ^ˆ¼:Ї*)³]Ó2ú™™…þ]\.HÿǺ¾ Üø­N(^¨ìªGGËÚ ×�‘à$Uûµd8p !ÆæXпs>¸¶,„E¥ù 1I Cm +&©.%¿k¸*0 sÿhbÃ'ìT@ÞþÇ-Ö„·–lÓ£�ÍÌyf|=ü×êGÛä½…ùŸ´ÊvU¥Áç€}l™µ ¯ÊÁÔªB,Ò¹ L/·+Ûíq]Åa¡‡ùPV¼¨…¯{%1¿ùM'XcEýH¸ç¶Wœè4¢ÇbåD/†Mû`ýíõ˜{Ã{nQ…ÃN‘6J’¼Ïq¼Ã'.+œº&�o�%å½Üºóíp�OËl¤¨�²|SÒ"”Ífí!=x‰0g{Ý‚~V�”í>{}"ègT—ר%ðÓ· p¥|x#J:²@oÄ7É<õ=°HÛ™eSö‚Ñ­hÔv 憖²Fµ«cñîA%¾”A=ÜûSý<%l3xãœ,hi€9tuF_�/ÂF—?dù~Ìöýñ‰™¼q¢_Þ¬ÀÆÊºœñ줶NÂCYÉbÈ©{`ÿø��¤Ë×5}°t¼.¯œ¨ƒ®{±p†:­J™iÞñ¥LøR¹–X‰Ñœù6vÀ’ ð#"kíJúÎüNg—M‚I‚¸úF0}Ù !�p2�äK)×µCøô§ÿWʺŸÜsCÌ:„¯'™kQQÿšržÃdÈZˉ·žA›çÇ•´)Tðk+¸¨QÕÒ:3x2ËõNfÝ›Àî+tqÙ P�ó‡Ï1¶°ói |¬YÂçgÇ`5⮤ÝuñÏóއv�:*¶Ï§á� b€ÃQºÞ'Hø2E]ÆÜVx¾Â…w…‚òÐþ¯œ�ÒÇSŸz॒‘5댨ÖS–³6~#ßã-�ªÍ“}šàx¹^|ÁæAo`€«wYØ¢¼ö&¡ÀíR™Tí=IËŸžø=®Q\ØÐ çœ1â¦.<þÛqí0Ç¡Eé,ü^Àù»F ¯ÿ08m�ÄxÅ��¹+néw’ÿUÙqà SÔë3çÚ¥ o[/Ð�Cóè†ô,ô>;O ÄE¤Þ¬i#upö�[4æb*ÚNÔÂñ¯ Ó‡¬ÆÉ+ƒ„÷¯òàÈŽQüs­-“‰DK×Wä2å­‘q£å®Z97šß¬�Îæ“âÅL®IÌËF$ Ï’y~½<Û�øI– ;8?¢‘ô6ÁÅTÞ´|1+^ø#¤¸¡ñ³�JÈ€]û·Ãõů¨ß³A¸¢´§ø®ãGzó0¤ÿ/õFQ- ]¬Ëí ¶sØ­šr©ÝkðèäÛåƒãÿÁбwypÊ-5a¬w8÷5åå{ôáÆú8unÜš$M?Þëó5ßA(­Q7«Ä=y:hy~+~ª­üzàPUŒ¯-ëî9eèm±.‘=´�4d=k´Ìû*màʼnGäzø¨�&1ùž5Žø¹‰bµS;ÍÜ÷Ò,œœÃ3,ÎcŽœ«ç¥ò¿˜ Üh¼[ÜË¥oBÂæ‘0~ÕPÔ?ªï_ûòÒ9„ãÅXëþiz´) óv§ÐE›(Ú¤*üX¬NãBW¡Fwæ^l]�,vRè˜)ü0á}‹ì�øÏÚNSÒé µ¦0¸¾�Üi‚V½pR¿ýåj�¡óþz45ÝŽ}öEÂ¥u§(øpLù$•0ÈñÊž’*ر àð Z�êà <ûð$ª§_Çz±â ,Øv` ¾¹âJS{Ðîs±øéº¶$nKH×>!OI9‹,†WÁÕ~³ù›�&<¯ÝíE!:ÁŽ£ì‘è ê•Ú(Žl{'\›È|»r7W«R^ÿ½bpï$˜u¬WNé�µóËJ�CÛÅ·9»ðæ€Þâ²Ãã¡(U[˜¿SÎöý¾"Î:ö‘~ª«ñ§îì2÷)Ý8Ö,Û Žë‚ û]nkþë’~‹ƒƒs¡BH‡°‡Ëpðå)œrHƒÎ´ÂmòYpEèÉ3zq÷+xÍÖ•5 ¦P…Å0 i»DƒÂgbç“h5û-KÚy«ê(^ž_Ù½‡R¸óâ:’¹?¯Ò>ð{ÓDOÞD‹â7[Ê�ßF…iý¹() ž\k#ã?»ÁåJ’8r›G´TK¦Ÿ]Ž’«1Ô�¥ÌWÖ>AKû=tl®‡ð͘ eŽ�'ê Ô%šwGHSaÕTT:=ªü“pnòu:®V :uf(Œ�š‡¡Û—ñˆÍ¡`äË5uIpX�§¶|å.Fq}f 6lË…‰¡I¤>°UØ1 éÍPUÌ?È>¶ß)öˆ·�Hƒ »Ó¸ôö5ºéf…M‹“èê� ŠPåweÀÍé„ñnwèÕúnYüNÍ7Æ•¬áÅ€³âØiÖ´¸u%ž8³QP­>Àôë=^åOEWdñ�óAžf6—â g=ØÈS·þzo ÃæÙ#±òö#x<Ž�¦¸³O /Ai¢>Ëî¶e±ø9¸º{r͆&:¢?¹±0æýl‰mrè“C Ö:»b`¨ Í,ø+9ôÀPèpŽƒ­qL×q²þ‰hH«úÅ‹T/÷ä Ì•­òxy£“øêx÷¾ÃmÀâê ¼9] £tdx‡¬ Ö¿ÑâÄwÛáï®`Xau&þZ&< 6çÆ‰½¡C*Cüø ŠŽÆ©ÃwóÍÁtR$mû©LÑËÕyC’&l8º‹ü€ï—œéð�MT5ÓF˜¬Žì]Œéú…t©(–æ;îç›ï±³p:nÛ�ÌêÒ£ø²j+œ¤Co©à�÷ÊÒá—.ËèšÊAºÖ7ŸCËh‡ÉUÊ“®€mÑcùݳT¾öe*¯»´S(9á„kÖ ðU6„ôE±ZI½.8”Ç‡ÎÆ2�\•d‚ÓKW@±Çrl=Ï7&¯B™×£qlB#xÎW`·°ßäà|ŸRŠú±Í‘6j›u žžxB[»ùË`¬©xîg6ßë‡ …'©3Fg;ªñÖßCqØ¥htþ[ þþk©qÜ}ˆÝ /çÕ ¯wa¤²jï~�Þï†wöGðe@e¹nU3Ý¢•í¬°ÈÿÈ�¤³‹T ¦tK×ksù¬zèwþŒÓbñº -¨�éƒÏ‰WTÂ(îgoÜ?lzùe%Oœ¶)–{½ݬ�“ç…apö;qæ’DØ6z.´„KxÜebë)6´‹•¼ì¸$JsÆ% 7M†áNW;ö7ú *Én㻟ô4èŸ)Ý?¨ J{#0ùêfü £æUÂöþK!~‘ÀAwOqë²·u^[<»§-”·Iª]–"éöe)¯8Êý{¼ìÚï=8ò]�(lÇI]…b-”K»Åþ¹«Ñma×°'`u§ÛwgwФuR,�o�Þ Fléâ@=FBšùyÒFb•9[×’§é$r\Ï•ÔpA“×Yà¾6ym${löÇÑ×ÑñÆ“r×v~´g=þœV–÷D¥…óøuÆcØÿü6¸¶ß§!!²xtÑ"®±ãŽÇo`Qþ[š{Ö€”¤2ydþê­>» ž­—QtÚ}:9„§=í®WBÈ«²¹ìˆ{óá�ñвÏFb‚b„ÍM‡ªÈžøVªÊßÅN÷1ê?#\4ú+ŒO:JÏÍæ±˜=—~ìÊ)Õìàöëà‰Ó"x;á±ätÁ p7ï‰ÏVmÁï·# "À‹­ —Kê5ö a’24žyT¼Ñ¿-fý†ŸVVâæo³Ñ4ò w#gk² ÎØµÀàyêX6à …›AËÎ0žô^–ÕHžjùˆÖ[ÌYÏ(�Ö/'ú¶× †h¥pýνˆ¯bÅÑ!¯)ëê_˜¬³ƒŠ�Þ ÏKñÅ?n/†ê³Ëé| Ý%�þ=7®Úôì”BÒ�§ í²‹ûç(�ã¬(¼ÞÚüö£ŽI�IÍa4W/ZB½•b¹ï}?Ð…q³¥qØp9è ŒûœL¶^­6¯u¯ƒqî~#³†¥zæƒj¹7§_4”Ø”BÉË;°#OŸs¼û«²ræ�8{Š?ÜØ”Œ·Þˆ¦æã—‚›_©èáNÈQ¦E²Ñ`7WüôÞûû«ñt«a¦–ž½ž�é  qâ-ÁÅ4 —Ö�gú!h­öÁue“ÄÏ Éä¾4ˆwËhá•“µø¸v?ÉMgš«¶&Ù-Ü6x�|ˆ Í9ù¼sã!Çuö30¼Œc�í_az¯j ʘÃU®é<¿ü>=PÀ¯ öðUq,+÷LÂ]�\yßïñ${7­»_ÒÁ÷¼4®qžŒ#§æŒ¿¡åšZÝLzM†~\�ÆÓ C‰ýN2Ò á;f¢]b/鸧fLåH5sáì&wô³;Â^Ã2xæ—@÷3!ýø#è}1Ö_¶á’÷î4pÀ6Ð ËŒÖÃ$Û0{îM*4ÔãÀCÃzóÀJ éMÕC—ópL¹?ö>óòô_Sñe:ñxç{í–\ô?€ë¿)óXÛóB¤›9GŒõ‚C¿B�v8iÍÛWîB»æHÔ? ¿(<ãsÛ#h�‹:¯3l†vIGïzøc&µõ–x-po�ê‚u�møÃ¨Y€=¦(³‰k,¹Þwá.ûÕ|adÆ|îA¢Š<_\_C3‹]a†q«Ðà’›_§<9øùXåùPµ&2\¬ˆ9MpøF..»"Ë£Q—ó.„±QÆ@þ¢zXÿŒè¬m»ømv?*cJŸõ/Px[5©¡Š¾ÓøøØ‚Wps™ê×|süTÛéŒ/¶NÒŠÐÆˆ‰Põ¡ˆz­sfï·v(ž­9épžñPïåÆ�÷¸>ûQU¨:¡Bû}å`”–6Êv‡«-!˜ÿ¡Iø\yŠúùŸeïwñ<ôï h÷xµ¹Ð˜fN×1Rðq¨…LCD¯ÞèXu Þw:A¿é—'¾8K;“œànÙEIñ¯Kd7ÙeK :]Ôƒ˜MÀN�à­ó>ô'ÑM(�ܾžXàƒþêøyËYv­e,Å‘×%§¯iñrÓ%p©:AÀ‚{î­®‡!ÏIn°;þÕÞ®Ž<ߤ~�O6x�‘ò,IÄðøu±¥’Ê(=¹×,·ö´Ìóß›Ä�!ƒñÒ*yöŸsHx¸ü¶(vû÷ÓIXvP™÷5Éã�Û?i˜‹9ÛNi\Çn‡”\+ô.ËùëÇyZEÎïJîSé‚0*�BÇ‘®xÄýÊåÃæÖtº4씘ôG—ÂÚ�ûLĉGá°ç�¨ÅÞ’Pn˜j�ýqäÁT¾§í†_ÆžÁ=‰ÇE5£O°iZ\¹ü¿Bq»g½pÚž`†?�Lx½º*­õä€Ë ÈGGŽÇ-Jykf2MûÍåÉKxÊàÒ½,mÃ÷ZâYÝ0¾ ÖFòÞ§pé×:=õ4ÝË™,F9À‘1ð.ºæ,¿õXßnVQr|keYñ9+Sü¸uĪ•8Hôpâúo0½~+>ÿûÜâ)ép÷½Ï>DÕ)¼Ïmÿ=wœ¦˜Ü¾;Ùpy[ˆpJcÿ81 çün¢èakñól)‘‚s�bèÏë xAÌŬeM´¢®ƒfÄ\ƒžëìÄócúÓëÍîï`†¡@¢öÊ\á¾vuyË‘X!ç[»Ø'n©ZŽúÃñ¿�;á‹}2/z{ §6o"Iç4ö š‡‹¶sGñržù×}[òÏA¼¡ N,k ä)†Ô˜ÙŸz8…±µš Ï�)ÌÞÒ‡Žîü Á«#Ù¾CKèª7Ç‘Æäp}åv˜ã˜)Þ˜¤0¤®ÖâÂÊVЬ)¬OG[³Çâá¦Brºy�>½�áO"EôÚCÿÚ»Ñ "†å/oð ÃRØ×ã3ìØ:�ä è•é86Ñ… ~XéF¹‹ýQ?Êoø·BÙë8òš†_Gd£Iónðº™Ï‹Ó#)«¡(=@ŠïÉŠå_Á½ŠÁ/8çÉëâºêŒnNœKÑ{a »ð�G)TÚ|ûçCÀžV2RR…ì̃Tÿ‰çno.WºæÁ·“Ös€Å>äkÚ•’Ê»ÚÊy²||˜kÇ›×t3é­CðsÇ|œàÁPÚUÌIÕ$o£ÂÑ®ý -ܬ æ_…‘ùù¯á"À�÷Âaw >Ñ<kJŽr]Z;)Õí%ß=Z¼fo _[x޵ã}ñò¨xž§þJ.­QÆŽÝóDËÓSàÃ�k’èCÆ8MÓ솔ü×wNr0§Ì'ãpÇ4€„‰¦¾—:ˆâ7Íø3¤·>]Ãí/$¶?+xÃØòºª„‡ªò9;ÁO¬H2Å+— YöÁYþwê LTÀ£^6B/ÔA¹Ï<û_Y}H$¯ïÉ<<çmlò�eéÑ0lË^8tÅËì¾Ñ&§Çºô°è–óÂJ×`͆X®^ƒ‡4Q«O)ÅYXuûï Rm<ÐS oÌHÚó"p­\þgÜŽïôÄmw‡ŠŸ·”ÂïÉ�åÓãòˆþ½AaîZu+#ú]ƒaÎÚõ€¬¢¦ÐóÊZ€U<´>‚ºýç¬ÓêuÛèåáX „ñ¿�Ù0«xt˜Ë«ëvƒÞ2]ôX››§™Z+i¬§oá;ùT·?í2ì‚W~²'–€]~šŽ6ŽÁÅwíÙ§éñ¶Ç¤¿Š<éÄ)Ò»kF›e–`lb«äcõUX°Ÿœ~D•öß`—CŠ} ½;|ä‚�ÌI˜q_åd#Àgx$þùlͧf¤¡¬vŒMqóvTœðúF�Âx};§î Ã'bGA%ÌœeŒÃVsŽƒ>rW@”Seã %z~)7'¼†ìŠñtÌYM¿®ÄCžcеûÑNŒ!Ã1[8ͼ?×™‡þªö¸8\�–ìÜÁ9œ½+¶Õãƒú-¸É ñ]µ;ÞZ• yï²UÒøœx_8sv%¯�‰µ‡Í`Áf4»|¯ÿÛJ�«ñüL�Ì2äð”ª7.õÛÌOËቢß>q Êlï�’½¨¬R*t®éÁªåã ² †tÜ‚²Ï¿ÈÇY‘ÜÔ±uX,ÇŒK‡f£,¼³%†Rî‡KŸ–gEãߢÒ�ñØå>†¿”¨À ¾-z›L‹wñо¨rÅËFõô�JhBõ1lú°§mÿ ý/«¡ëìZP6I‡õN"‹Ì¬8òÆgxöeõ³¤ý�Wøá9Š¿lG¬ÐË ÙÖm1÷Þµü¾÷âU¹µ°õ�g€&|íW/˜ö¶GÃ2O{0Šî¤ßGNˆU=+î?)*ŽTÞù©·ÄýÁ�’�lv€eg 9ö ¤Ë܆ Ù7 IªÁfÌ(õì�{ \ïyœ3ÍýÓ‚°ö€*f4|Bó©sñ¸O'=™¯ÉÕ£_î‰^øXÓœ÷¥¾Ça)"z3O°Ö@¡w<öm»Y%|ç>ýKO¤|ñ‚Š.�=0•ß©Ak¦�úRÇ.u<ÛŠk’’XFÛ‹¥E�ÝÎ’;¯Ç°rš> k&[£4ahèêš�ÇSû‚{TÑ1£™zÔÆñü€«ÛÇL¼wJƒ�6ˆô±y þŠ„¡£f@êÙшcò`ÊŠ%¼ö[=’ëÕð‰¸ ûìBÚ ±Ðy¢poµnn^Jyå—ÊV÷uÆÎ€-¼ÿ2¹jë èyBì—'Š{ ·bc¾Þ]Ã|çG… : µcX˜œ �?} ôìS�z–Éï.Åçõëáµ�ÝÔƒ·+Wáj‡~X:-@(n05\“'xOTªV£vH,÷9XÀn¯uJábM hê‚QƱ\­cËG[™b×ATçOhã׾뺸?T‚ 6Ÿf½�…š·$–Zã…åãlpB½Yý½%®V9€šK–CË�áiÂmü|+ï�î$•ù§xãÑõøÜ)K|d)àO!�×Ú#ªÖ\Å­Ý`_Nsþl—DÉ™£ÂzG4È©„š`Äæ�°aê ®ù4“ýo�äfûµ‚Ë k4úœ"*oеïBÚ…—•ÍÞìá�gµWÁãÓúBö»5øAÚ ý¾fpP§?ªUÇóFGMÛÚÝûÁì¾D’»=—3­¾ …Æžtå�7¦Õ2o¹ü c;ü�ÎAÙIT¬í"±šÿ�ä·ŠNz�ˆÖþÄÊ�óWU^ã½§ÿ[�_gCyD^•&c`éFT2÷æÅs\ñù×$²l4†^•~¸üÂdØÓX#qõ[ÊŽ;^”iI­àgßgA�Ž z÷üч šNQð‘4þ% ‹úœã.98S�¾sÁ8#‹Ç$m*¿•±�7ä~/_6$º\&k7þ,í„ -7|*ÚòýÛ~Üãª_Ð5èÞë4>™"‹~Y2<ûÛ!¨ñ¬õ/ƒãßÁëÜ/�wLÕ2àñŸ¯ÐxøT½N‘]Gh^Â.Q.ê謲㦟{¸ù¨høµC\²¦M'sÏpv•kçÏ¥™xhJÆ"Úï~)s6ò�¹#ø˜ŽžPv†c$‡k„—÷È·Çìó+YG×[Z#@QL£Àùzé°—Ü—Ç5Q(«gÅûKëÈã÷`�…G5¾‰·Â¥±wÏ:±ßDi|j³šOLÃs+ôñübg¾1`*ŸÖHÖe÷éä«ÔrjÞ £(1—~H†M�¼<3ˆâýbõçRX×%Î6N…áº4eÆ|¾|³Zì?¾'/ôSã™ 5vÏÄêòU6uÛH;ëyô–Z+§s°Üb(.÷ –‘Ÿ8}îSrŽœ ävžoC5�9,žˆº)(è~§ä¸çïÍ«Þf°f¤7DFü§Ý0£eN{ vöÞ¼LžÖõ¥M`г_­IcœWþ�RÍk¸ÿU;8 –†Šfz4Øä Zn ç³áe¸;¦ò�˲ë|)ÜTÑB7e?Ã+=9œÏÉ÷BŸÙø=ÖH(à¸Ä}7ä¿óâ«—ÂqDÓZ;^ŠzÔ8³Ô*UP¹â¯TaWëhªø%H.ï\:FÍ¢Ðoé茛Ýwr@ÌL‹RÑY¶¹ôþ¯7Ã{_�âÁç¾CQ•9ÖŒ½Dã#_âðZKn;$,|ôRˆs]À¡>ÏÅN,ý'†Kª�ÅÀô0|±s™5À9%[¡6pÖ[`ó v÷‰¥w~ÓƒÈ‹äø£–ü�v÷¹öS0Èʆ»Kzsæ¼@¼y°™-«¥œŸq†ÃâY»E°ÏöL•N.$×ì€jV=ÐxZ1Ÿ•ï+ž¿ûÔCõ0ã­;GJÂãI}Pñ‡/Þ]çÉ¥z3hàtŒé; ì�‡ ›òµÐI.Jðœú†š­û°|˜¢› =~ïƒÀ>lœû ŒNœÇ¿Ö£àÁV_>óŠ…3ëæpDà>^+·B·º³¤&‡ý¶ð!³sd5¦œÖܾ‚·•{ÂÃD%>ô~!œJÛ†²^D;ò¥Péˆ Ûx¦á{Ïk4lþG‰«}>�›µò¤ÙÿŒ g·�Á£+ŒøÂŒ×A?éìª6O•:`÷_ò€ÒUFwz6ÿ6a˜c%\X±Ì>­åø�'Eý´Aâ^]Û̘ÉÂÀ&]qÈ ¥1Ž@N!¯ °#Ç]+[èƒòøüÄ”O®˜�eÎ;a³Í7šöª»—äåð|À¨ßzbÅ�¨÷²MØc8®ÂË#l¹ê};hh¬ÂÈM˜ÚÍ3+bñSáJ¢4 ØòæI ¿n,„Þc•iÒ_˜µq[y¯Ä_t1 ßïG]•v°2h+®]ž-ºE…SÝÙ1¸0±ïûjAà¶Çp®Â“ÝJbV­¦—$C�š?¶Z;âå�ÎÂÚSÍtW Ïß§Tn0ÌsWíeëTš.¸MXнÕðk?ô¿½‚:¤©ë˜4zõw‹ª+¨=`]ò`Ô5.-/É5¥ËùNð{_0(MŠ {Òg·™è¥AóÓåXЮ3íøN‘ ·ëÝÄÖÙwa¥»?ü·ïéYgÐû�üé¥,þ4t�Sǣɤ\[¿ÄÃþcçaÑŠÔòØ1ìñd ™¿¹ÆSôÅÌœ~Ü1pç�±¤Û™ÿ¡ŸZ¨dÿÞøÎ¡’Ö¨®x¯ÝÄOo]¡ï‹tÐç­è;Á—„—&ü4w¸¹½¢£œù•ÃZJ/rçû«]yݲ|h¨Õ·ÇEÀ�|cISh1-û—ˆÚÜpBÿ!Ø|'.t¤f—a Õ3zv$�+ïB×géÐÙñþ� Fp¾ðÁW�æ6IãîM‚Ú‚pþ ¦xMñ/]¸O[6`¢ôLp¼îÇ›ãw³eñh\è’ _Tæá³ì:†Å²¤eêÏèÞÅ/Â"ÍFò¼�ÄßÇìgÿ”¾8's0{üE¿3GQ¿WgAe˜-ž3~@½­Û ¹Ïyð²? S•pÊ•šn¶HƒÌàaJŸ5#%¢Y�‹yoÉM¨YCeKÕÊ_¨ÕPd°î9½›zý‡: �ˆ¿~ö‡mOëéÙÝóÐP4Š›æØÒe”᥋°™Ÿ>ô¸ÔNû’×ñÝ!᤻d†X¼ø zõ]H·|Dz&xçôYAéÇqX\ÛYÈá]çŠò3‡žPI‰‡¸Ò|*>èÚÊ’ÐcÝ]"�¿¯ÅàÏi6]eçèuPí[š…¯ça‰Ú?ÿŠ!žå¡xŠ^l.ëž+rÕ1#®. äƒ4Ôõ�…âñ ß[¼&o¡}¦à_{Š·ÚLž/+H¼=ƒ–nÕå9[ÒÀå¢2WôrÌr±¥¦¤üÜeÄ«»ØNvö½’MQfœÓèÎ~ÆQå3N4Š7Ÿ_¥‹†�¢ñ*Œ±•ý�áÔÓe”3L¢þ¥ÒÓl~¶G‰½_EŠ*ç.Ð¥„½ø£Y›ÞÆ$pò•XŠ6ÀEóáá§�˜31‘pà£í´Îüý7~¥à²h>ëi  ÇÅ_©(Á�[[ ‚« ^Ó­çHaÏ¿ky·J#Íp>\óáG?{ó‘¶øÿ‰[vÄ‚ý‰tÞ}ö•žƒ££…YÐçK+™>û‚ÔÂñÞñAØgÿ hTØV NÀƒÿ¢àeœ'EööCW‰,>©ŒÅ„o ¨jÑ �dTøàž‰<µDY<{ç¼._ g VQº¡bE±b ì´†ƒŽô%¥‹ Xw©„焬â�ßKpÍÍî]wƒÌZ?�ì85¼rù'ý·c t­³Æ$q#?ûÚS­M1;H ¿^ªíaÄ«Z÷Âù ˜ÑÚ?¿8 S®3û,‚y˶±×ä8<½1,3µâ2å•�“¸�o kØ‚Ž1àܹ?ļGê´{vŽ�ö;‡›—ž§ÓA§xýû9Xñ¶ŸXš¬Ûbë„c"øû´Åìµ¹´ÖÐîqOi³{‚͉¨^¶Q™é<'Úç(Õ=¬ád\"üY7ƒ­3#x[’4—Írƒ¢èÓ±BZû½MP½hoiÊŒGú2c?¸¥ÐÛÏ vb¶io’:¸“‡9*à‚Ï3pU/Küð·;çŸ é׿±¼ôµ-Ü×*díÎGâ {¸~Ä+Xýùͳ¸èÂ|Qó}¹è tŽþÞ5ä?AWD¯»1r·wóßã lø&Røk›“nÝ¥Õ@[ÆJ¸Ï¢žüÕ#}Sçð#É$º]ŸÉ!{`š}'8Z�Â{ xÐlið®�ÀŽ¿lðï® Z¿ºÛn½G!£ù¯ôôôÀ¸“ã(?k ¯_YLU§¢e '|Ê“‡Ó_n“ŽgºØ…%Îû{ 6 †“†PÿÜhz0??êJJK(yÚ ØÕužƒÆ%PÛ¿¿Ð’°…žÈßäâ—¶˜gÀü|õÑb^–,ÙÆ3Ç”�¦²…ÎZ,ùÑÂÖE<´h—¸ÝÑÁè)¹˜N¾ñVêÌPÆÂp°^ÿnÙC“·ðZÅtQ;#„Ú)ƒñ|Oñ³ù1¸Õ5f†£qÞPÈÒ窜h�S+u,°Ovp—V†.0à†çó„‡ï�,Îe×}YjˆW–\Åv5)®¨ÊG�¤zìs¶Çì«J3NÙ=šK=ÑrÃtáÝЙ¬À«Ôøîaû2‹_1µÚR\¹Îcöœf¥É÷¨ðd9\ï°�I¡LóÒ� ¢‹#s¿‹Öª~ÛØÙ` �€%ߎ’tO%ÔMî…öÆñ6ï/c«¶xv3ek‚(åy„H/¡�&7U–åvM£½ñ¬ÂP–1ÑaÇÎ[4¼¡™{©Íà–ÍN≠¼ôñ,Ï“ÇÅ'w‰&ß÷à³X?ȲM£ì€¼-3‹6ŒÞ�*?sPéO޵tæk:0¡)Òüïw ¶àƒÁX¿2R°�Û�曹G@)>hï» |x2w\˜Šá�¤m>®Dßã7HCï=�_ÿÚÆÑcˆPñ-œ¶” oûžãw ù$"­¹ñ(%Côï‚ ïð”�êûWáÈ5)œ™©Iñö¸a`$eû(s[â]cÌç÷Éãa4ÿóýC7+pÞ±±àÖ¶˜Ö]¹Ž½áB�Xz&•þE‹+6_çŠíŒ3”h‡ÜI[…"‘�â«•µ$_›kc¥¹iÍO±gê^4= Â"ÕfvNi_íÇ´ü`0hˆÇ¾•ð#Ó Ö®Ì…žo³` ¬ÄAžô«£}-ƒ­Gñã%¹ôhHo.�šÁu�aGgÄg {Öÿ¤&¯ËâÑ´D!oÔ>dy=xoëŒ*FG >ã:ýhΦ…Öì²3�iÆ—á›1þã šàŽþrÝ\a°Š;×Õ’FÕŽ«”A÷™³xÓn´9‹f³ƒ™ªÏB¸æqÞ0ò¤~é‹*¶^øñ@%IôÈÂI_YƒÞŸÒF_µãŸ–³É�ßô,ý x¾›'œ­þAUÆ-ôzÝ1túõ®¶”)fuÑ�u#¹ÚÀ¿–ý¥v]=>¬t††Å?KöÙ|'`é÷Ò´mÑ]Ð0’Å›‡Pšk ßÿ Sç â·±ÃxjŸ:²¬èÍ«êBÊÍì Í~!|æüÎÙñ�ˆªiº‰§¾Aÿ”ë¥ËÂÏ‚ßXlö?Òíà'àƒ‚¼éhÆÍƒ7cu®=gÝ9Ï<0^\óéoþcx�%ؼ~ù Nÿ‘]k=FŸiï¥!î@òãÁ<¶¡�âÙ‹¯´¦±ºy)vY†E·×²³�”ZïÁÀE£x×£ ¬îk·r°Œ"k”æÃu—Η¸M°ÄÊÃøtÒѬ,š#Ì`µÕO1¸t,_ª%˜×[¡P½ƒ­ZÈ»îªãAìFÑÒ'¸à—5(¬\Ãt2K)}7Œ^b€ƒ»¹>$ì¶0ÕB‘uþHS˜û 8ßjʃ㗉Âê`ºßç9\JŠýVƒç{ ¡dë:üu¬v9´‹Ïo䂨v?ß&73c¾qà)Ìœ+YÔsÄ<<³&c¼”fŸ>"*Œîů¬,¸ë•«jŸfEê‚J»Z¨côoMþ²ÔŒ·Þ©ÅÔ:#°Ôo¦�•S8åÎSq®½1ü˜/�+þ Û »½g×6ÌœÙÆ–»ép¢/¾n†JI…â’L_°û¥Ïóä•p‡• ¿RÚNvËÐÒÔpñ\ÁK!90œk¶… Á§2úY»¯–Ö‰±kèæ!¢~Ý–ÕÀ SüÖǵ‡X ÷b´ùÙd],�iŒ[Ö@ÞÌT*ˆ½ ïKqö1/ÉÞÚ|.=¹œîÕøÓ¹ã=øÈT#T*§‘—O ýò‹öß?Áÿ€~) ,úÉ×o’aÖZ}Žö§Ð0›pü´Bg½ŽãŸÿн~ÿ�µ3øGiôkŠu¾SIå÷<öu9ßI'õrâ3+Bˇœ^Í™[ö µý5Ø`è2|±LÕoyb™ÂD®¬ŠÆÿz >&‘Q ½×®ãÝ…+(oH†ÍÉ™èI«¹Ð@OQK½ˆ„cõÂþIÿá®r9*ÖªŸŸ¡×ðÇ¥=Û׋¯;®‰óƒavlo0ÁT9�=mI2s(nÞQõÇÓ”mÒ�ûZòmåfa†3 .Xÿ{¯O�ë�”è]âbòºªCÅ^¯è�°O˜âTOQ#T!"8áòDzyÜ–w¿*…É9`»·YõÅu›…ã[0!Ùˆö,þú?ŠÎ;¨ÿ‹ã(!$#›JKdɸçh* -£B{(¤E%•вIV©H4DÆ=G¢EHK{*ßJ*íRýüþ¿Ïs?çóÜó~¿^]!pøn|ï¦Í•¯ Òh‘É0Þ74š_H\oíï†k:7aæ¶hŽx¾×éÝ¡YOBÅM]ž¼·Â�‡Âp¾[gU#¹±4˜l2Ši¥…7×,Ï#g}†mf·¡iÓ)Îrú@zm`/,Á‘­ÿ`†ÉQúoåbz:¦*fôÇvŵè=@g&=„¨ËUð¶å¼}yÚ:=÷w.çÂuü}p JﺷŒaü>ì8‰Öh¿´{Ë+ùÚœ^ì½é%<‹à#wcHívvO®\€V“X°e'Ï·ŸŒ. äÌ)À)˜6¾ ¶¬.¢-;°Hcÿz�D?ïx⤡÷ÈJúìêÝÏÍ w2‰Ì¤Uq¨þ8X§µ ´™ é©$!âã2^³xMñ?ZÒn‰mÛòÙtúÚµ\“ïˆÃÕ½‰v‹SP1Ý˧ñøÉŸ«œì}é«C>»Î‡.�l… ÍÀÃxíšwäPÒÎeØâÅþ€eó΋%¼ÊM‹“ço↤I0zs5:HvÀ�w‡¹âálüýo¯›"Ì[›‚ œÕ[@£�|³º‘x¾ÆîÎØ £ú[ˆ_ý ‚ÁN˜®ÅÃå:à—­,—üHk¿§`ùă¬÷É”·,ð—y‡bêt+L 3óu©ëºxªŸfÕ]„:ë8–lŠ3òŽAI/ ¾U}�®,‚sY}lÇn/¤cu4kR ›¯òBc<÷>¦C TóüJëCæQDxªßÏÆ§§RðãBÐïÝ,D7[ð’¿Sùüçdº6> � q‹ñ�S–`¢]ÀŠ-BÖžˆ»ÛãU¢\Ò\{tZ­ÎÖÎeâÑc½qÛ Œ~ðŠn®þ�b•É$ÓÂS+DÙgÍlÐï-ejã#+[—ÆfºhQ$f7Dƒüä&ÐÝø‚ÈÍg¯aóØgÜ=»Ó×÷ãM½@xð{˜ì Ÿ_œÃÔ�ÌÌøKl­¸õLü7t/ë]Uëal-¾˜ÏgÊûð Ÿß”säH?¬¢•MÆ\|?ƒoóN¦Ò®ÅÛq¬»ŽJ­„óÆÑ¼màf6´Ž†Íkäpá?\~d_UjÞn¡—Är¾šþ*kcàœ9üRË5wx`ç2Ì6wG¡A¿÷жú ùw�Áù äªf }ž ¢¨«ubüƒ|rÖÿBóG/F™@eþ9ЧÞôãð`yÛ›ÿ‘‚ð’Ì.¸‹Š½Î@à�©XñU‘³òƳ¿4Ül·/|�™ùÚÈÿÞ‚ßõ"¼t›úŸð§™þÞT—y†'&ƒb‚;ˆ”C½´tÔ•ó6Cê[]Œ `^þgÃm)®Õ1àÈZ+ÑÚ}#¦™ú±…M87úŒâD× wP‰\nÞ–ØH׎o²’á)9v(CãASJý‡Îà¶O5ƒI\^þ�Ú~l¶ûÓ0@ÐŽu¿>‘âøÚ �³9Æ$žÉz4Ìí3H�ºÀ3�Žá a0?h�:ú ïž~|éuìnôÀœOÓØë~QsÌqÂÑfûVƒ?Ì—«6@]*w£�É3Œ;~�“ÊÇâûºè¦‚] k93Ô‡´V<¡™÷Qõ+ Ž©ë¢õÁ�xÑIÝjíhrœlñ¥ºxÛ üõm Ó ãýÕZ¬òõ¦�±s*VG~6¹îáGAY”÷Z“Îþ5n%WÑÂ)Fßhö†ds%J/l“‹ðß$uP1–EEjÁ%†Â¶Ô~ÜS¬«P¡~3Œ ¡ÇáBʶŦëb¯kF¼yqéµ\S¶ s¾)ô>ч,Óâ3O,ª^]Vbã?_¨lÅGÈ/<(þvÈ%&ØÐݬ°;ïÞˆBÇW¢œ”ETÇ VJ],8g»ç¡$ß{°ýÆJ£Õ¹.»wòêbd\9\.Ú�Þ&Æøv• Hº¨€òÁ©8ûÃT^ÑíÅ{7¤‘¹ôx,XÙ‹Â-e�!AP¦ÇBí dŸ¨ ‚D$[ý~ 6o#@åÓ4RSC¹CìÇfáíjâ‡Ý¢ËøŸôuâL¸b.KýEZWʨ5ÜŸ&Ø,dŸ%Ò*Ï4ŒU0À‰’ÃñÛ{_ˆèɾ7·{^’n€oûËA‹PL;œ¿Šz/+áµ\+¹¹— çŸ>&LY‚ÿ¬‹¾…î8Ĺ'épr‚/ϲRaÛÔÃøîÎ7q·ýe¸0›»U¯óˆÙâÙÑO£ÛެW"ÍVÓg#_Ú†õ�¹ó™¯%ÔðSülJêžB±ácP+Þ˜Ug fß}Äü’Gâ8:•õ ¨ÙO½¯O‚J«ùôÏí=¹`ÉÍgƒ¦k›°(º.ó a|äQR>‹!%±°ZÆ‘UbSéäý 4š¾e’ž²—wè÷ý€`®ïn¯úQ܇¥ojc”¬¯h¸HyM…ߟWq~ó jØ’�uÏøÌ¤éÔBK“ríVþ ÀÒ 3q�Û,qm/äÎÁ¿»`å9–,Ù/$lªCM“xl— Üúz�åCWá3©»à”*¼”q ¿È86™ýr8ú†$¿{QŽÞJ2Ôß²¶~Û€Ö‡K…g&Kìž¼‹×©sJ…1øÔ„ã‹WÅØ=Wût.ö©haC¥þy©ŽzªÈc÷$:SyY¼ô"fkãÚ={9�5—³F\/62Ä}¤Úé‘×n*»?™‡û¬àÙ×aZ²ÿ¹"Tü8žJ%cä‹þ°tÁTÁ,¹Ò,ò#7q–êt ÂåÔï«2úϬÈ ì9Ót.¦Ào߇¦§Û9<`7õ‘ÀÍ¡oÍ6¼�\EûŒ.QÁ�t­Žaù€3¼¢ä¹?i´ˆáw —èÁšáh5n§ÝÄqc·ÑÍxðΡÛ4’W5vRÉêPª5¶e9?A^< «[à£Ô*š"Rî¬tSþ±˜�Ð_ök„ÜÝßíº%ö`óŠTo:�Ó’“ÙÛWŠ÷½XKv>)Ðå rlÁø±ï”øµRQ° Þ�MC^ÒXóþpâî Þ;b=Ë÷vÆsu[aÇÓ^P²¼ÎŒƒå I¢³ÈpUq´Œ^¯Š%-¯¥¶Ý–l›ôW˜ó}>¹/D»O_¢‘š3 ésy¸å%ž÷ø�!:EƲvëp¼’OÙ5Wá—ÉÌ—­äï�Eİr=ݽГ‚ª¦î ¦iÇv¡ïПô¸˜ñÞ}gr½p|?†XÓ3˜Zì�®MÞ8VŒ³Óžµ�§ˆ¿—~�C‡‚àËeÜåËCb,9ï¸2šöFÙŽ‘¸ã…)\hñ¿~ÿ(¶C_•¿„´¢�Ð=ë�nŽ0âvÜyFÑq�Å];†°Í‹Q88÷ 羞—ÕäXïa‹h+s�üV’ “nÈ7ꪨåH%ǺsM@$ýÙË=Ž‘åƒ›d5ò&,v ÄßÏN‚ïÜx§"gy:³Y\º¾ ºÇB|òî¬>H œ÷àœqr¼ê¡ÛvÐÿïq•hø€ æÀ!ãDº\ùˆ[t¯Ò¿Xˆ1T§OQéâz}4rÛ'šI—°Á3غ$3” °Úx;ßÿu“iÁ¨²ë‚›Gþ?&OºÍ?öÇ`ÄÉHA|!ö-¡¸'²•&Ä¿ªærÿž¬ìcj[¥…„•{(Äw6^ª\BÇÒ)çO y=¾T^'A¨z÷¡Òfà´5û!sò¡‚¿‚†(ÎHL¡þs Ànà*x·¢n¼x@#oDPxš;ï^/…‡Þ"?ÉW¼óf6\±�A�ù‹i°‡Žpòq$ôSkƒŠüH>õ¾”4tB¸,K�VÚoÀ,W#œµ_…*žž�t@ÇPþ)sÿ¼‚É*:x½»”'”‹«µ›é=øáý‰ô¾Ø7�,ÁÛãžÑõ0m|w1†7Ôш×þ¸ug6? “vþ�Y‡ýØ{îqšp¢[ööÅ/|’ä§«sÎå¿pê€ß»YÂSÔѲo3žùu›Wž�„þÃC@ ÆBÝ»ÞPåí^}¿ §b!÷æ ðÜ]&:_Q �Ï"à`^)Œ~çÇé‘-xí+‰T,pFƒ~.+°[å=šlo¶ �øyt)j0æ¼™Ó—ñZEÉžNÌgãñQøÍa>?Å7¶ðâׯ8þ¼Û|ˆÁï‘úhÖ!$ø/áÎãWÅܯ ìF85ÀÑ7:œvw&G[ïå*ï£{‘þZOÀÑÒ–è ?˜ûZŒfÿ¤É<µû2|Ï ÅÁª*üÐgÝ´ ½Çò'Dzå?–¤g«òd×>Õ�¿&µi\1Q×DµãçEïIg§$/º÷Eð—[ kÌŸvƒ�›æcþ÷X1½ÅmmäÉõ9øø¹çÚåCвÐ5³nž*Æùç_'–Óhá8œZ¿–ü„óÞ•ó­ ZÜÐp�%}û³ßÛ~ðÕZ‹¦¸¾µÛnzžn¶r…ÕSH>*‚²Î;Û•Ï÷‘œ†4j=? ÈŒŠFÏãc¹{íTH¸·PÈŠý-È^>„qzfüïèq0 Ÿ‚3¼r9ù�GÄăÓüÛ`ùg~Ú¶ˆv¨íáØÆŸpüh’Ð×=Ÿî™å Ü/4§è*¼õÜÉ£¾jÒv룴tÀ8Ž?çÏ%r±ìßjt�¼A~¾²â,-yNVÎ}Š£´KŠØœjWûr zUÂêyÇÐÿµ?2N…Ç_2øW¯=äõ´Ϫ} æÏkðji ^ ÚXŠÍùJ|Ëë5NþM‡þJó­‰Hñv’êX¯¾: a®^ô×W»æž!½'Gp®²^ÃâFáí·3*ç#kóýìTt \ÌÔ±cGÎ>Ú ¶$]äÇ}¦\cÅ)Ö¼8vøý»ÞåòŸÜ%´e ªõõ`©MkqÁxeÌÉÙ…3 ¿õ:ÀoU Ý, £C+TI¬Š¿ÕÊ!ã±>þÿ?K¯vÑå÷ÏÏ>¿ ":…>N-åC9ˆ“ô÷bc’$* ¨eá4Tî€Þß×ÐÍ�UÉ÷“ÄêN}%zyóPõmèôfåMÝÌç6œá2·…¼ÕX]‡,皯‰èVbÃ3,�¹yÇ&h+..9º–Óøqº ûdÌXòŒ–MqÅ!eÃðçÄRœ6N–‹ÆdbÙÅZ–²ØŠM~uØïÌ=zÛã€×wÞîA‰Õ¨Íjäðúw[¾©š+ŽWo¾yÂ?ÝÃØ[6�=}.’|ÝCñ¢±«)~ìGz¡÷qCÄoúö{¬»®oÏ÷s½N 9otàÑÓNõä¡3œ¾m�³ÞŸàµ?E|7«³'Ó%iö†ÓÂ{· UU6�Fͬn˜/˜»¼¡þŸ•Ð3 IК¼Ú-Ï�Ç•™¸kü^J¸®a¿Ob,ïý¤‹3VDâQ[±;§”.Iä^o Ù^ó!éosç¹GAAá ËÔ�Äeu#aýœ ôþt¾à2U†T’úÈ7¨~¡g¯nÁËGa„Lø©Ï£æigˆb-àèÃ>¸6ìªXŽ@-q$–O‰àÈ$yl±N‡M T6ºí�ÂŒ‡1{×23òãÍ^ÝT4¾[œ{e K¤]�Õ[ëÅ„{¡±p8h&�:ÂWÕ¤ª» YÜõJVh^UAWÆÜ—•|°+ñ5åë9E¼]JÝ)<û> }d[avaîH]EW‡ýGÕwÒ[ËhòϧT¢xÒž>É÷L§ãÝÂét`á~ö+ß@’{£ðjM:ø•Ú]r‡àÿq±¼ÿIž…*ƒgP‡A9?O€ÿ¼êhuVöþ}ÙôCÑâníÃõãxå„ôanƒè¢þ™b×¢io“ñiC"{Þ „8‹Þö£B1½¨…,sœpÞ YÜï4 ¦ÌC'«þôäý(ty/W}4¼‹ºÛ/Q‹æA¾1‰;d–sKŠ�JZÂe};©x‰9ÝoKå.rx³þ¬M†Ï#Á÷ïØvôÝ9�7Læ†�N›£Æ?›/ ½Í?ð–¥ɽ‡SÇG¯NIs‡ÚYhŒvæ¥Fýyb±«…Àf:¼aD)¯•Á´à¡OúÏ£±³Ú�­ý[„7‘ gÏa‡%×( =„|ütyÜÊ:6K•LJ�ê`Z¿Žl>îw–»µx«íkšáþF(/MÄqž½ ùŸ>–Ùí団ñXr.+Ñ�¡OÅów ©¶ý WºÎÇ fª8]ÊÇöÁÑŽQœÄ”='iÝVz‘Ђå%UÛÔû“ãè#в°DËdzÔÎ3pïÊiô0$n»áƒ}¿b×üHqjƒ õŸŠO2DZBc j(\à öfìøó ½¾…þ“Û ÍðNåî�i”.{–'%ºƒAzoqù8�¯ŸEÃ5Ûqë‘#vÂŒw×_¢ Î×aôÍ~¸^ÅŠöŽçóö«øß…(CVq™A»ø±Ìƒ¯Ëâ?ÐÞ]zøÛ2Ët¦rîälòðYƒ¡£¨Ã­Ç•¼xgr…XÖ+žBrûòâq™êžp“QŒKͳÿlW�O‚ÚÙ­œe|èMÖlÆÓ“†Ñy…lJ7Œâ±ZM¢I“î.ÄK­7ò©­ÓÀº¯¦�ûV鯊©N~4f�Ü5­Ó—TÐÀä^üÞu#®û‘�?Êòõ%¬ü·7g÷Ò¦Úe+AºíÜìÚ‚õqÊxèé4J|Ca!¤*±'«ÑH«lñ{Ⴊ½ß±Ü¹7ØxM Ûå7 ÞÅ>•ƒ‹g€÷’�¤Ùç =Ø!|˜¿µç€uÓ#ñÒçôPß„œ}³0 o)Nĵæ¾üxòIRø¸“^·sr§1êý7ÏoæµR‡ð͈×›³Ú¢'ÔY(¬2Ÿ#|Ü&œí cO*ý÷ÈŸ—õ]^¼r½–��²>‡ÞŽÃ¦† wã�ë€:»i&·pÌác”ž4‘6 F¿Î5räï¦w@cY*¦ŒšÌ�ê¯Õ¾ [ëÑ`h8?9�zºy´ò“¿ð´\ääº=p†ñ¢ýq÷^|’d�^ƒøÈÜ›pE# í-aç'à›oøß½£ôŸ‘+?ŠÀÝ(_ &…3Á€xåѯ‹"­´Ì¥Ôñùo±/î=*‹JÛسn2ÿ7ùÇè¾rþ‹bå™f¼Hæ ì)(�¤ò"}üúg!&X¥ÀÜ…mo4wÓÎѺ\1ËθMàñ×­ñÛCšk<ˆW$¸²ìÜjZ´¥M¬MŸÉcíWàÒÎ8œæªD¦ŽF´î^µàð±Z|°p(ªžOágMò¸}þl^#qŠ$×drÃ)M° oaÝ™ÅEuª(Ø·ýk¤ø¦éX¨I^sŽbмhªý1„ï>÷äÂÖ0¹f‹rFÛÄ<>æì¼ÅûÝ>ÐH;n ¯¤‹—RÁ&LíNdˆÏ%äðÀ†ŠÇ–ìÔ?œÖ.íK²XÌòg†Ã I±`d2ý躃î�oyÏùÊzm#™­GøX¦ ºç,ÃCnYBÞËa(½a;j®7Ã2 k7g2¶–Ãÿ”ä±ÈGÄ ‘Qüz©>Ï”H´ºJˆý� ŸsQàZÑÅà4;®›Œc+û¡£í/”ô~�’c»ilªyå»^MøùÓ+ÈýÉpë|E¾¶½”§=¾ï5™{ø>¶�<µ‡÷ôSG�à 1QW ?¸¢Âä»’�¥°×V•Ëž%ˆeÏ1yu8çì‰åÞùWàΦý¼Fí ½‘ÅI íƒ<±Eë2õsÌì|A[e¼x±qÜvhÁ(´Áˆ�®,²4ºª¬Á¸gJôgËUª¹�ŒÇU$°Ý¡™“Ö½ƒÍ{b@çy–­†z<5í;…—/¬¢S¶Ùó}¬°F8‰ãÃGñ±’Dø]¡Ž¦×Wâi�bÚw@Ò~Êt¼�4›ó’�Ùe¨$þÛmËuJáox#¤º¦ÛΊءè†|Mp®¸–¯A<'&©ð/ÓÁXhjË#Ÿ®¤;¡ï)-k$gm‰ý}�â]ô »BŠs|s¹YõbÌ0ðh%™Qù¡9õ¹"Ú{ýƒ°È[xOó ÝÚ)l9Õ w'-«Rg§ÌÞÓ­ß�¥}Þý|AØÛr *†êT^»ôƒb/�­o:}ñÁ{ߪÄoo-ðü‡ÿàMÍ- åö xæiwÖq‡,3¡Z£yHÁ,¼¾ä œv�’!.?(w7:rm¯Õp5j ¸^ɳká€ï·ß¢þÕÑg¡÷‘œN•¸”·ôm„ójþÖûY�ã°ï×@Ù-È�Þ—çtÁbŸrè’ bËõõ0Å>�ÎZåòƒkyñ½«<ýÌv±QVÖ^§ö!ef–rŠ8Õ'KÀäïHi=Ïž"¹ª@Ú Óqûïábû¨zÛùV7ªºLßÚm”]FikþÑYS-6ßñG¼Ÿ'Á/êjá¦Ã2ò L¥ù/ìùÙiKÔüzg{ü…º9hËA®ÞÕ‹ý¤¿BBþú¸Úƒ·ØÐ=SSXùïÿ±ÈÆÎIÅ´79tÊf)öW̶Háâ—MèàDÙ2…bÖùj2KzûÎMÃî‰3ñÂO\?¾ ôý}xùª-ÑYI�ëÞŠF&{!ý€Ë×>ûïçÇÿàˆ…!¯�ÏýqhõóÙ÷P²#„öjNƈh a|A[û&ÑÓš�èÙÿ,žø©…‰“ãA#Ù—ÖGÑá‰� ôr9_Ìpá¾®VxÓ�ñmÖ~L ê¢FéÏ|Pù}¶˜Dgë§¢¡Ì%úoŠ.ùz’d¥ìwh�š™%çæ¡µ%¬|“ J�©Ôꬸ¶I�Î�� %Ç\é…CTÌ6C‹–Vªyä„Í£=yîv?ÖôRÑñÖž ÷— Ü©iËa®@Ó‹yšñ0^]{‘2‡ý¦ûµGm¯Oí¹¿sBL ¸¨4Óë{ž`¼ÛN’÷mDS\åòÔV iýEg’&€ÁÕÇt~úlÒÞ&lÎb�?¶\zslìD«Ši¼ÉEÒSÏÚ¶X{Òž^¿�ÖR+øÓHV =ÈñÚ%¢šúA-l þ}³;ã¡þAm|¼’ÀYÑá”`òPØX<€¥ÎNÇ7ÊcÑú}6×¼¨×ç‹pçàwbgöMø9nºÐ® a%’Ø÷Q=GK†÷t¿ØzÒî}®)™ßȨ2‘¿CK:{³ŒwM„TÜœÜsÛzayö0*Ë–Çïl8i޹oæÚi¼RÓjBpàêz±Æ~3ø™©aL¦XÖÚu/틇L‘¯¼EÁ@šc‡h’Ùàjp6š]ö½¦ˆ¡¡š+ Ž’}xÊ„U¸ûy8ÜiƒqžÚÜ�[ 2é?Ig@dÕÓ�lyKåvù€ß³s°¸ò›¸{A H½Ò†8“Ç«b\Ÿ¡O¿Vœµ›ñƽsâñ™]_Á9%œêŠUá ìµCÿÙ†ãû•Â4?X¿l5E»y å0;ô… †ªUš(7d#ÜS"ñX©.:W(¢½t¸è_1æ�{k÷õT*ÝÉ<\5Qc o�<w”܃ÖU¦ðutNÏKq}ËöP_À±•ëĈúzJr<Ç ¾¥âìgÁLù†ðU) _NÅSöãá„?vM«á¯æ~4ÀîKçØwH“}XSéWOGžF[u/ÜŸ«Iù¥KP[ÆO*j¡ä­04÷í�C:eàÈͳT¼CǘjQôI¦˜/¶8iÞ^°_K4·ß’7–#M÷ù¸m¬ýUý k«ûr²¶6�Õ¬„¢;.ø%eî™B³cFâÚ%Uë*ì¾êΆÿ© u KCÓðø´\sLÎ^÷êWaÊû,ÑËÕüd®æ¼TAšøs9îÜK>)í=ß½š½XÏyNʼÔû=Ÿyˆ–ŽBíF=ò:ñ“^]r_ö7æ× Øox Lª�ŠÁ•ûèBD·0næFž1<›Ó¦?GÇ’Ôµ`Šù=œÞ&þ±oµ"øA¨•2U„®G™cÞøvSeM^ ±-j<*k®Q`K׃ôóR6‹¿-Y/³RmgãÓ‹¶ø'+V9ÍõøŽâXyè,uª¢¤á;qSßÛ‚áè¹ÔëóXÐxV%:^˜g$AN+†ÀÄÈÿD?û(nñsç)6/é¦rCVZ¦Þ¯Š vj/QÒŸH¬^˜ÂÇôUñT€jOxüˆ9 Ô†’yÐ`xgÕŸ¯Ž4¢þ ¦ì­�­ƒåqàqIæÜ‘¨TÿšF§t’ã‘;´(ÐÞLHF“Ÿ÷)ŠnC[©1¦ÙÕƒãöôî¿fÐ)8+æþ¶áòà,Êvrä(My>XœN3®ŽåðŸ¡ÜÑï‡Ø^0©¢Trþ‰ýVö�}Í}±ì—t|‰/î…bÐåbYS‡ßž`¤I¯Ê±Ì`�stÅô!Ýda;˜UÏn¡ ¸Vh[�ä�ǵá½9þv’í¦An°çÊû…¹+(:îÜ3 ƒ5ɵó-1)¦ì½…UWÜyÓÔïTX±�ås~‰�z˜-åXW¶ÌÆÑ—´qÜ­ÃÜY#+¦$¨Â}s”\*M)§ÖQpäœöz*ZU¤ˆEyÚ‚ì�70qàL ï�—\±òÄ:rY•Ë[’¸®gWO2Ç“¯9Òt ÿEk¤íç? tpרM¼³ú°Ð4÷%¼Q‰%ê®ÈÏmÆ€îfCþ¦ÆG]7V7Ö|N¥ÕÖû å¯�¯ËUòëQŽæãmnãxÚµhž°×Ž‹ÛèÔÛ0ãÈ×îÂÓ ›Ø¼n2~ÿc†qßï‰7Jï“î‹ixÈ.�…â_tirôªê؉¯Ç³÷Ÿ~¬P >F¶bF@oöÐ?DÃ<(ñÂ2\>ç2®�Š1Ù– ó4íu‘—ÏÚ'd—xò#í±àŒÞ7{2˹ú³~Úo²2–ç{ÓCHפ nÌX€›í¹nªw­Y‹?¯éÐ…¾ÛySá-ˆL9€°I‹›\ƒm��8öŒ Á%/0Ûð�ƒ”×ñE6ça)sÓzîc•Ï›G˜C—N0G: •IÛž¹Õ%î>?š§ÿ&¤;}¤ª]�¦ûˆ4vÄ‘ì÷}¼ñTÌHȮە°¸uÖXfФÞÄ•×:IEÆGì³ã}ªÀ{jÎÀìW4ؘç2öÒÛÎ&Èöˆî§ç¡ªÉb¾²¨/ydç‚ĸÑxtç;ÁÇsgûËW>û­�}Ãõ°-ZšëÌ›ÞPqËìW]ûTÙ.ç¬6[NÑk9õ€.~2ÿW¥ùù¦¸ëãòY”S®OD%Õ×Ðß;ö^Ù%*ïÊmÊ{ùñÈ6R¬é�¡‹5îX}¯¸ŒVúí½]V8´c•Euþc^u¦D•�Ë•Ó;µ ¼&g‚3ó—APQ,yÔ{eÌåõûá½åî`u"šoºÐàîÅÔ¶p7KvuC‡žŒpÈ~ˆÙp)G‡ß=ÛG/NKŠ>¡ž¼ùÎ4 >ñ«^-€¬ ÏH1¬jl{ó±f5¾9ÖUšãxkh4;$JpTPzëgó)ÁƒKëÓ@ÎÀ’Ã'zòÃÝïÅæŸÁ¢ÊªT’Z©ƒY;¤yÙ¥; “V$HäÜ<ÃãOÆNý >ôlí.Ú+Fä B§ÜÛäë=µtwc·v®k«ôÚÝÐb>âÌ:x6>�•sMÐЪZþÏ—Æž„K�…Äí¿Éºí.íÞçF#Þ†Ò“J;í÷k¹­å-µÚDâu¿Ñt|i�²‰ç@©0Þç`Ï×zó¾ø`.ßï'¢ýw<˜w�3x NSó‚Âo{àyPˆ™ùtlCYõb{{{ŪBõQ|“ÖàÃ}+9?0˜Ï=ßÄgeyÎòlHCÑC/PžG(«mŸŽWUb0þ†*¦šÉñm“89VeeÆÙ꾎S³º*RÉnxÚ T†¿±.>V¬ª*8l¼?6:Æà¼¾•$éõ‘ÚŽ.áM)•44–ÛîÖà̹žUŸ­ãmš³?Âæ“ÇPßr,¸4‰g-î�›² PzçJ=2 ¤÷Adž! ™ü‡ºÔÒêóJ¬ro«h;. ´ÚéqáqºRd%W.ŠAs¬ðþý7d¯—}ô¸¸·1~ +ã?ÖÂá¯Þ<4"^”“ØÌâ¼bº(õ…ú:ºqúÂ!||ÖPüÐÃ*º†¡Â÷²vд�¡å�‰=\üôdóÐú":ó¹Ç;(µ1Mx·h¶øªªCXpø¼Ý‰‘“`§ïTߣ�sÊhÐÎ œìšO;7ã“Õœ7" —¹ERsÓ=¸T(Q­tk7Ež‘Á£ûl7$˜F”Bý%ìZtZ/Ü&ÿ‹ÃÇŸ¥0gÕÐL”æEÛîCHìC2Zg†Wì £hêà0 5ʵ·šéÒ÷3äè9�cô^SÛ‘ZË`Î[=ÞîZÅ[ ‰¡Sy©ôcáQÅÔožþxT‡ýGü¥µŸâ1#wî‘òÀš™€7w-«ƒ-ÙJr®ò7„�qy¨6-¼jÇÉxx–z7—w �jÎøù 'ž,4çwqxÔx8åªÚqþ²^èªÂ}³Ÿrúé à^}Y¸£$k_(�ŠK¿¶‹Cþ3ÂSQFq#?[¨Hº³Ep35%ŸÝ'xú1+øûÚ�úo’ý#‡`Çóv*ªýL?­W°‹å,Î »A[\~ÒãO³èŠÕæv@˜·Þ3ïaç7|¢bŸø„sß•¾ì>× —‡cVl{UÛ™x IŒøK5¶÷esÅéøäýb,ûª‰óïæÀ†ûiIx y� –ÛpÓ�è“_K?¯EÅàžù¯M½ÞTA¥ä&;©º¾ÂäÇSÙzP:,©ß Á?{Óô^'Éòd%j}ª˧¾|M{:NE Ý Zxh7¯.KGÏž ;<¯�âUŒ°÷Ÿ_UŠè=$v뼇Ô_'y¿ç5²è!6-O†æ¦­Â‹ûúô '  Ó`#ÕD!>{ys2ßdëãÛ€ÝBW«-·f¼±ÃîY`ɯ³ç¶g`@/uŒVþMÉÆi|uŒ HŠ—ÄûƒòØ[!‘ËB)åô:©}C ¶†iwD€æÍøª*[r2ŽæžŸ*ä&à6§™`þ¶�4çldõ¿B©u 3ºV^4f Ìéÿ"£K81]²ä.ƒŸúHlâŽÙÓ«6C½þ9ø~êKj|áO!UÉ]k?j­®¡í3ÌpÍ' z¥ZØ·)š-¹84KüPt•Þ|h_øfv{ªŠŠ&3ù…u ö©†“Sª$”ÿãŠè±ôCõœÕפûÒùôI:gFµÇ»¨¦‡�Ïv­}u˜´2žë·Òþ³î¸¿å lò‰¡oKö‘�ù•âçëàT—øøF›pVØÀ•·`Ýçx¼A¿… Â>›¹’NãÓ]ÇÙÒb\i[ˆ×:ÀÅõIðso}{„7T¢±Ï °¥çù µY»w¨Ðæ¼µÒ›)pÌñÉðp~öõÂÀ}Â[`›Vxvj-—d»½Rì ·�6§ÐÌô—âwëxÁ®ÆÀîíÖÛ•µ²«â½%+Ÿ_òï”=…¢ˆâàMß(bª¬*}!JÏŠš¿³ /íä^”ÅW«¨—²Û� F<ÒáþîÕâ†mYûòboP�}3ÆšŽoíWðÕis1cj,ÎP•âÇÆÕè¿ÿhß^DòãUÇŽT)Ø£—g- Ã+wb^È7z¨ÕDš”´ð1ýí·D8(ë„‚á~±Üljf¤¾Âv½5u¿Ú'6PªÔDaí:ux_$IJÒ|±å‰àve(o?|Ÿ¬�ø’›— ߬߅ O(8·†}ÒÂO9ÚÜ´¥Â.ØñUÿþIžŠ™Üq-VLC,Ú �Ú‹üøN? 'ìªMNÂ…˜ôþª<¨±C‹K²t¬ßzá‘Ùвn«“Â1gÄ€Û"üíõÂ}‚+?~F‘ïáL 4-XU¸—PO”QoÐ|1æš¾jo¤ƒ¿Jñß›…¬X2=Îy‹á9ªÂ[Râ!Æ.w¶ Oõ“ö–8ã¼È1TàšAê¿qæ.[*©îOºLaëßídú4ÄN%¿µpñy¶LˆÆˆ{N¶õ.£pôI´nOÃ_òñØ�}˜yEðù¿qôæOUÕ|°]6r _�0íjGÞ0_|‚íÌÖ›C™Ç6 ÖäÇÛ¶�ßOsJkÈÓýŒ1¨ª„CÖgóÒâ‘Ìý§ó'ò¿±“§ý®¶éN½ÈÍgîÛŽ^x>�ÞCÁöþ(sÏŠ;Â.¬ÏŠæ­°Â`´tÅ–'ÄeCη2˜­¾€Ã©I¸epµ¼û��[t·?�ûÆ£gÇ*6^yÝðú`ß9‚ E÷3€'µ½†f�íø#B×ì¿C~)"ÈÛ/6;¥â:“$¬nÔbåûë!Þw>³<ùPOÁ¿í,Ã��‘ÓgºeÀ�3Ò�h'X«¤/ËÉóärAí×S1Ë/˜›'úà‹{ðºÁ‚³öúôŒz 7M ´-ùRÈ2;;ÈÑl$ÅK˜aRé0ÑCº’.šnƒÅ¼)×l/»„½wŽ˜Ã[ÛªV[º¢Éym(ÌÜÄÇæ(1U¨òk÷[UÒ#ñ�EçɾóËü6äœ^ÙBAÄ|ÔR‰ZÆ@sM4[&k±Œöyˆÿ¸� ì¾õøØ^Z=ÿ<…Úu�çËpò®2×&˜›Š?o ag¯1,¼úˆã¼'é€�´Ö^§š6ƒ‡s öIÝ v-Ç­wqD¾KÌ–¯�¥‚('¡kˆ;šßÊb•«Sx�0/Ö,D•�­$§|‚¸ŠÍ ”åQ£Æ® GЧ¹-ü%Ö�¤iö8SQ7<ŠªëÊ{X[åç05É¿¡]åq<æKî=¼Ž?Ï�Ï-²è¯øÎÞÓáʉ}íï.ÖÃC§Ñ^}$5�ï‡�ޱZµ1æ+Þ%)µyB…Oˆ8òŠ#¸y|†——ßÀìrÞt© þ-‹¤#B1ù– ¾/ ç>£fs¢’:÷ùºG(?†çÃðØl9~Ù«€U�üG�4æ1)T]ø•θ@ñQC|Ø|•Z‹iÌJ7š¹#–WlÔë9÷ìJoîç\¥_4z|;l³»Nm*épûÆ0Œß¤ÃÝA§`îº×våŸõEé*Þ5ënüÒEÆ;Ÿƒós„g'¡Åc+˜òr+\¼‘ ›oøˆNëðBÅ|aËf59]9=x$wœOâ ‡‚8=ª“l,|&Sº�åUè3™�Wá op°Ç)Þ2à9Õn½[b÷r³¯�q”dwôâæ˜ðj]ûÅ×õ©ŒVò­ŠÉp¥& “‡Á«A·ñ�|wÅê#ׇ�KC´àûõ˜à6´Ãî—‰lž×�Í9ÑS‹Ó¸{Ä+>éŸøÀv~žl†‘ËññO0ûþ“Æh¥‹/VU%V=Ç®!¸aĺ¶ô)¨Li¿“„åó°îå«btJôßÇmø(|<äÊ//qДtÏ:‘{ç\¦ïGzƒáÄîUgÈÖ¡â�ᆘÛjÆaQt§°K˜.±O«NÁ×Ü&Ž«çsVz ÿÀ¾DÝ>Û¨âÁop| 5ΞY¸À¡êÞ<¤n´ð³ úŸ~Äúwb`X­::äÎÄ´ ÁÖA賡<ªÅÜÆÞ²œ~ª ìí/ÇcZèK‡7fÅJíSÂîp%HrÆÐ“yWÿÇ a8”ÓVª‚Í`+~3”x¶ ËáÑuû 'mÚ¤›SÑÈ“èq`3ìÏœ‡‹/â2‹p_w îå%ºÁUû|•9×c ^t“º¬õà½l;ô¿½›ûË¸âØŒnzäº_ÐÚÉ› faÃxx®;N“þEïkNSÍú= ñmžÍs�ë»q‰|0¿‹ „�mpï´ótbÑuˆ‘ô …©Üît·¼y�_”Dçú=\–“ß݆0ÕBŠt6ü*ÔÃÏ_ E(g?ݰ€Íâ娰¥±^‚µ�µä*£D¯*½0´Pžc çãÛRjJº&~êoŽ7œ)zc>ó�…˜=]ÿp%˜î û\�•FzT[R••pœ«gߥ×-ÔÖ~ Ô7MƼy™xYa\ÕYÇ'bÏÑ܇Z\Ù¦‡YëöÒµçåœ!?6)Í‘|²â¦xDë›ØUyB�QcmýbûéËU9ã^B@~&îÏ4…�zXµã4�Ti§C¯ˆ³æ¡–Ã_±ã^«ÎåUƒŸ‚L�«›;w{ä¢SªG?RãùšÒ¬S‹š\ñUr=%~O!×ê¾¼rÍœ(ÝΓåÚà”N>ÙxšÁðݲا<ß}úK“ô÷ÁtÅ óêz£ôÍeâÖîP|k•„G)þé÷éÙ7%Âujü#M,Õ? ƒ†­Å(ÅÇ¢‰««¾ ï4'bpk6…ÉO¾žˆXy¬µÂ Ý>\ø“˜LíÛÇáç6èÖñ¦âIUS;b¿¥‘⇓ø\¤ Zœ~Ã5ùÊÒÞ0x¬&�²t+¬Ç£áh:|ß¿,‹ÆûgàR“EÜçÊ^l«i#*šy©¡éhL“•b“‰^xvtªèµôÖ›îÂͳÚHw¯d›m‡¿=ÞÒ´ÇžÔŒâoJ[ª¦õ—¢_éÅÔ«;�|;³ŽËI¨Y-'.:·•-ìÓí¼ò"é¡>¼Çµºº PbA)Éâ ©J´îºNÎÇñ¯'OÈß¾…ªƒnë`¬Ùó–.TzQ׬>׸T¾-†—»£/œ´Ýá²+ˈ× Â~ÙCPwzK®YÊ—&®Ç¼?.¢uæðù4š�O�sç‚úJZR`j1¸pƒ6ôÿ$ž�­À-A;x­áp»2�ÿ¿3´ªø¥�œ�1±³òa»Fš”SFé:qÜ~gÔÿªØýÅ–zœÉïì´qŒîj1 úãCѨÐKš¿N”�GÅødØB,UöÆÛ¢¹xÎ!г Ô¦ÙrFI#Ô³kågЀµì90“~˜kà"#w~ã\$>o`Ê›nÄÖ™ÇÄÂ\|�RKÓ‹» ×1P°O½!º÷OÆeÛ&ò‚ËèI¥DMÌ„ª¥ïÛKsÙôÐ !¤Ò_k®âpYn�üe·t½€ËMWÉÞüA{�–sic#™�"X��M#oðÖFKhÚ½[ô�KñÞ}iÄH%Qîôh2¯Ldçmâëì÷°é‰.4t‰á~"d¹gs\�$zþI"9G Ì*[Ï'½†eUz˜¦·{ê±ÞéSt½s/^3)aßî«8hOÊïi€«œpØ1) øþž”ÒMðU­-_]ŸH!’ù¼Æâ¤ðù|GUGåôÖ‘â}E½i­„&ïÊ‘F§&5L|Þ‹û.W€ðVÞý:[o﯇ãð†K… 8õéNÅp4ê’ãQa{PæÎ0Ô_t¦êZž9>l-=âÈüüQüû1\÷Þ+ZE¬g…1®ê¬'ÞÕ=Û~ŸãªŸ]ô ¬š¢Þd’œ»;µ&æ moó~·2hlÿ$œ:xÊ:ì4LÒà¯K*´úªàZO^œ§Æ-¿È¶(ƒ"ó;èÃÐSà~o,öûÙ-úhí¤o ƒQâ=‘âÏÉéH‚°j»>ÃÃÓðóþ)¶6>óµü:Q�öU^¤÷Þ„‡6Н¿/¤ƒ>ëù¿i ¿+Îÿù?†ËïÇ6ŠÃí©ARi£¡¢T¿çœˆ¬B™I$e%¤²G{'¢Td¤T ¡’ê9G’M"oF"›ìŒloÿÀ½Îçþ~¯+× ~R;/Z†\Æú'‚»‡EªiáúyL•õàí—öqÜíë4»§ª®Rc¹¬�üÃ7 _­[í0q…ÊJ[Heò¬.�̦!?AG)Nüá™í\öh/´)ôæ kEÒ:¡�W›¢ÎÅKT3o'l ÍÀw¶u5ÒûŒáÔû¢Cb×£Zr÷\•�´,�ª—Q^Ät>ûoÏ+Û�ª=×и“ ¨…�äA“UPz…ÊœHÃaîÁ΃¯i´Z\>å4„*ME“5üßëåNó#ŽcHöb¡å @ظƒbÇôO¢ßù$x¿à,ˆþýhØä Úü»I83ÅÇå2ø¢ J´Ê)«G'(~~¥þïè{À|Ò*ÜÂv:9´x¶+ë�y…ýYˆ]v…-ÔÀ-™›â_CO¾Yg‚³Žƒtå¥höîÙ÷áè®Ó‚ÒËh”^ø £&ÔBÆ yøqwOìw§ZÖ¡ÖmiüÐà‚ÇǤà䨰KÎ'yoâÓ¦»é÷Èè÷ú<±bÃ�Šº$ûDÍ'×”F&æ�•ö2®x»ŒW…öÃs×pÛôÍ(£d�:�m1m½Wy.¯Ú ç°ö rY™£6Ì%¥¤ï‚ZQÖ·ÁŠ]ÂÆ¢·ì2>/•rV—QàêóÙ¬2£„”4RiÜšdÓÄýG_tÓQý]aí×Ç»ÄÃ[ `Âù{tò�*¹û†qÑ]®þ<šæEõÂß N¯Û…úµ§h¹×jqò�ÑhžkÈC¾­E›øQ Ñ&·ÄKS_�˜7r~ZpÃóW&¤È+qïEcp†b.|úx†K¿ Õ]ÈV¹*¤œpk-ªé ûÅ}aÇ…W0S[ CäŒ(I"-t°&oN2f«Æ¡xcÉ%ÊôU0Œv4O¨ðõøvJOæïA½×Yç >ÓðêÉ�‚Ù¹ôu<ŒG ZEÇ‚V*s˜ç›Á*í¹¨çóM yŖÚ™£p3¶“†fJ�a2<Ä…{rYB‰P™¾„¥–Ñ÷Ö?°èáš³; _Dîæ;éËhc¿÷ð}ñ5Ñ~Nî²Ï�¨�쇞s¾H·ËCˆ×R*+»E£º¼ÙøÈRüàíJFëýàܳDÐv; É÷ `µj$œÐÿ—§<¦¹[üÙáÙ!aÏ9c.PR$;k†‡¹®Ê#céæÁD®8•?߇³¡¾K^o!ƒŒ¿ô¼Å‚›+Т§I¼_ˉ�Ý åCU9íllx_F7Ÿ§ai %¹×íóGKqÔ¢j<½¾§PíãÃùÕT[?¯�V†-ó`yõb4ÿD/ÖêcÓ ´gì5Xh»ŸéVPî™ha­¥D´|øv}KclMÂ9]�õB›²>ƒó¶ÓéëL+!¡Ï#šk&к(øõ˜Úz\æúM4iuÂáj'hP]1Ä7iq¦L'íÊé>»› u{ÉŸºDÞœºgoGË`þºPXš-Í ïËâY?²Õ9] ÃnáÜäAµÖm‹ñÎŽipýú*šBë‡âmŸ¤‘äôÁk`$ù6ïçÖ®(¾rô¬ð$»¯°PM‡÷ÜØÊ�nN¬z:B¸©ì=ŒI)Fs]EÔæÊM¦7)Qß‚NÞýJ;LåùF¤,þžÙ„É­vï“M'–ÏÁKÛ0æ¡:.“} ¤láùë;QáMl�š+2ÛŽòí&xh}#yG)`eolrr ï—¦¸çg³8öy¸ô:,šr?Ô-ëï `—½cÑ:Á¦š9BùÍ!,ßõŽƒ}k É£Û’{œ¶Ÿ Ïæ{±e<*3M0Ý®‚í¶c|òr,,Ve™¢DÞ=Ë3¬ \ú‡ó�w²4Ÿu›CÄ^[4ñ}ÖÖѱA©“r(Ì ÄRÍHuI Uu`xz¶œ½1‘”ÔÙÂe%}@ë}ÕÙ/„°å‰ðg™€zMsØâåwjÜæ¦RŽJáu?ŽŠêÓ…RwþÝÕ—¥éã«�oae°Õz-ŠGÒ�¢¨âÍY?Ûù!ÔX¼”ÿ­º-—¹‹êc)ÁÔXPXž9>CÉÃÐ ¿˜8ñ¬¯“ðxS™¯�Ÿ'ãë}½Ø$j£¿,^jôÃÃ×£Œê8^¶ÂÓ–œ¥[_†£‘g-›ÅÙãäµnìômŽ/R3´àà=ÞœoJãJ){m½Z¬ EÔs¨>°*ãé]jதå!É„³ÂÒE_@Å׉[dÅ;º±X±§•vçߥ¿Å÷3‹`ò„Éh°.»âƲWìaг7º¹:ÅrÛQFô@Ñ“¹ŒÄˆ°î[1ßÏ­Ýo/`ó'ª´ì|™ð!1‚¬¥£ñE%þµSŽ/.õž¿M�É=áEX!Ú�˜Ãc¯®Ã0¥™xØÆItn*Íõ”<~&d¨w€sK›x$?MX7)“RìØÇø( ‰–`·p"¯yWÁU=ÕùåàdTnšÉÿ¶5ñaÝ¢k`޹í@#º½üË“jú7ÈßË®ÃñÚ¨$7üj)v„OG~ýRF˜ûà°ðá½/lk×£ØJ\´YI"wíŒäÔ aã¾±°<ûŸ°j„«äžÖ_½)~‹W⨻[ððêÁœ1î1ÜÿmމcJ±äWk-]ÈÂæ1«y¥ºÏ^׋VeLá1®Ï„ø´Ý¬–<nxß!ù§‹„äÂÝÔßZ ó‡2nÛ(qÒ8QË‚¹éç3aÿÌZ_9�–÷åÖëæ˜ssÔŸWg¸Çë2;`ù€Yèj'O:×|„Ô±÷$<ð9‘—„ 㼓ö˜òb‡Û&�E³¼èvé4¿|’Þ!ý�ÀÛÖ8ðô†z i®%„jêçoÉý¦Ü®æëû½aŧǠl?™£ì/’ÚÓt}ñ&\\8�U$½ù펭°e\:Ê_}ƒ÷f/âºTö–ŸèËfÙ.ØÃ@@¥¦P¾10ŠŸ‰ßÍc×öѳCÙ‚^.Ç�µÑA}>¼ž% Þ¿¬jûȪ«ë �® Žª&ø«åìÙ<}j=(ò¥5÷³Qû)ÀÀOùâƒÂ�bå¾~xñÂHê\þŒfꃮ¿Å¿#”„ǬU°Dw¥xEf§¤oE=é=ÙN™÷L°2q§Ø?kÂëíì÷ÚûJ»ñ¥öŸð¦ä³pÅq1»Í^ �x)y �l;FËfóKƒT‰Te#žKYÍs Êp´W.È–³g‹1:\P·ÛÝìÒF�ºµ\àår#iBÍQçI”dWði±-è’0îÝØÿtH×ÉbšB)Ÿ˜Åµ�&‹¾™âŠb\?Nœw æ�/¥!¿Ž¢÷§ùT¸v‡(ZÕ ú´°Þô=ÌF.š;ke@cO .vln¸à‚Õ…<êÖ>´{$Ʀ�¢�íqiáNî0(¡®‡™h´Û�¯^×Fi•HvŒÚK÷ž;CZ‘¾;®G#ó·bø©m‚iŽ/˜…ö‚ŸçÌùPyïÖ7Tt<ðgÏõ8+UI­œøWOÜyO-‚Éô’Ú =ÕF³ñ+¬ºŸ@Þ³5xþÜX7Iö<‰ õKÂZsáìÏý°[ðå°O=¡wÿ|ü°€W�#ÚúO4Ë “�Pðþ¯Ð(:ðƒÜã?�Wµý‘¸((‚•ß/òrCÜû)L§âz6£’•ëÁ)»�½h1ÏÞ\Ìvž”?×°›OcÅ_Ý�Ö�ë”Òăû•Ñ¿c…a ÍÜÜ$Ô¿\ßM|qµÊ.Ò{cή– ­÷’ù­M,Ô”`û4sÞ”–'¾ÏÙ®•ïéGz,šèÅ_¶ ç ”Y[Ùf�ÊefV@h�n~u˜/,ÄœÁ #Ü7ÞÓ×áœÒ(ØjD'“ñ–B.Ù%þ Ú·fG‘¾c:j‡ÔsÛ‡kÐ[]•u>̓�Ð z‰³a˜½!ß]D¨–!³ \#(ñÇtrŒÀ®ÊñÞŃ19ê�¨<¶PôÍùM:í*øçË'˜|·„B|\¸çͨÓÐ,Ü¥E�I‘tܹÞ­˜ÅM—„ µpæøQtåßÞZƒg•0ì¶?CQ–T¼èyè¹Ø±ë…|v£�›nAÀç^ho,ž•êÇ;Ýz‰ƒ6÷ᣇRÄm ªL·{á»§¥¸µò•4¼¢OmÊl~O ùž ªôi‡[ʯÀñ‘!þX>µ>(±¾ä0/ž; ±¦`Ý9dºµ—dì"¹Ö�PÖ×Å;ÕTeTKï'†bú!>1“ÏPÙ8W¶’û(Áô¹Ø[Î�ߥzò+õÙ€sê„ÞR8ÌQ�×»kךëbg»y QŸÌO «Áîx´ÐOm·M˜½F�ã ¯Pûì)³ñ$Ô)“D§�B®Ëá¢Y=ØNµ€^o—ÁK™ýÙÒã>Å�.¹jSX›îȵª®1Âf&WeÓÑ—ƒ±§— zïþ “»sn�éDÈ)¸&Ä©,¦Šá‘ôѲžäŒCj^ïf¨bs÷eº4 i«œÐ6JúwÕÜ´ÃãsyžÎ^ ™0‰J¶Š –ï%xhdòÏŽ÷´µù¤�ÕíÐo,†�ûnÀŸ¹kÐîÉ šŸKöìÄìë²ØÜG^¯ó„+¾Cø’ž)_š™€cúAÃûrœ4_m[ÁIê àÑ™m’wszágþ»£ä؈¤WKøÃsŸ‡ÄOÁýÈAXÁ«=|Ä÷k"èС~»éÐb‚£ þ?6|š„>o å¯uµÿù®„žÅ+ Ãk6ŽéÕ‡ž&‚G�,ËŒ£¯UK9ª¡›o“ŽQØŸ=ØãçAVðY§ÿë _�—qk²37kÀ�!aå—&ü÷·hÁ2>°l'–‡2tÏ;I½˜ —N"–ÝCuÞœ8äŽ$0ÄOpÝÖF<ãøBˆ ´säeçÆa_ÚŒeÃúr– iÜ\¬ú’gv÷z¡I5­¸ì-NïaÆ�}‡áó=¾›áÉ»ä-Ò½°ëe{…³uÍAÚ—ð�2m ãØwñ^[9MP( ‚7M¸ý²fŽZ‰;Î)òWÍ7ÂK…¼mhŠ2¶èØŒ½/o"OÏLi¯EçC«3Â&7Eœ­é GV8ñ ½7à)ÉM,þ’£q†`ê:ïÒ¬çúÜ•U$3èví@gÖŸqƒ¶í:Mgî–¢N­3ùÖJ‘§PFa—²Äq¹º¬¿c*žÝ¥@éƒ>Ñ]Ô\ø�*¿ŒÀ�·éX•ÑÍ5C¹3gæZ±rñXÜôZ_ü:Ë÷¾¯äå¯lHqû'A}ìYJü]#øèÌÄ�G�‘ôÍ',]1 ¬8c¢+ÏߪÎóçxÒkø{îiE—‘çk\W‡,ç�äÃÏ›„™“ÂáµÛk=| ê7Fqì¨"x,A{nWÁÅRmƒ¢q—�^½jÃC ÿHÖ•=7ž<kÚiÝjMx²%‰]�hC÷<}ÚB¯×g`þ$ñøS<èö–Þü\.ÂŒµç©äj ÅÕÊ�âYmA®ò?JúÏž«Ã’yLðZ>Ð=£qvžìbÑ‹ó~צ†áJ÷0 1 Å#º‚è8ˆC,ºó½F�þª`eŠ �¤óÁ“ã;Ͱ!ÅT˜zõ ü:·³4#j=ÎŽàg‰CyVOþmt pŽw\‚.Ú %·OL�¸“Þì_Õ'kE�Òèùxñ¹ žøüboÓ©øà?ª'¯Zõ—–¦Ÿä“¡fSÎØeuríÎ#ðjÄ|8÷A‹ JêÁÚ622÷b|óýMù�q~Î$nê�i6 ñž®.™Ï[‰óê×ò± wÜæw‡›;ðÐ¥…˜Ýÿ•9 c�œ�s!Óy«›,ž�6Çì÷çøÏe<û¶õåüAÉœõÝ‹’7òû|OðÓüFyG‚Èè“îsWô/>CúV•ä7°Fó·—)dð!]|hržW=�É{oGáéàzJYrZ¬�ўˊ´¬gÅôÌ¢ÇUмí4®žè3×�ãŠVšq2ï˽…ßCÕÄýǃ±ùÚ7É¢w",Z€§‡ÈðÓêcpxÛxšýö5ú²MX7…Žçµ'ÁóA¢(óD–#-Þ Ëý;kk/\§C^©<ÑÙØÙíÂþpr™WÏr?gÓÆ­¿…GÃã¶pÔÔqçä3ë`¥0‚ì£qÅÚñ¹rWg°ŠÆ!\úp›ø¦A¤¶ñãð™ÙHžSæŠÏ {PŸÙ÷iÉ*)"œå¾bF® ›W ä©NÑl6¹šnàeÅã0b‚7ìbíSðUÅkeJâÂMF)Ö§CðïwÌåù,Y“�åÞêTc° ö%Æá¦ú9ø¦3¯eYq¿ˆA bó†›wŽÂǾFxüðÇZÏ@-Ô8£Š… ú°é‡=ÓñY8û¹1ÖýL%3ƒ#´?+œG;‹`q§vܾOíãa·F<¿µoº]ãVƒ>hõâíп(‰�;œ'ÌÝ[“´>›>Ÿ��$eŠY4JŸŸ¡÷e`xèCzüYG´‡ƒRwO~›†!¾fØûã.IŠõ_ÑOÇ‚§-[96ÉMêÞ£�¼JwÓÂĆ«¿(ÚÊs”_�Ï”…d½ô8Æämä ÿÍãýe9ëÁ|ü�‹Ç}Ã÷c¤ÔSjßõ‡‡Ù½Y¯î‰0ZË¿�‰'éÔ­ìwK˜6f=ÌÔ�à®ë_k¯­$Ï|YìR~/…§¾¿À,ļ–Í„ÏC~½®ûÁ§[Q`ý"•lV á£bpaA«˜cb€õ£=±0`6f,9J³\qç±\ز‚Ó†ãÈÉ�œß FÓñ�î8ìÿ­°›obØgø:^}½˜ý*¦ ߇´Ü(“µFëqâ÷•p¹¸'®yaR»>Õ×†ð « ø²Ø W~åìw»quQ*LÑÿn ©¯|ñDÊYü�וAƘ~ä5mêµ Z_Oæ¹Q4¡©_òžÈ®šõôýzýKÌå¼y—qÓø�t¹_,~\}ÖUWá&+,›© Nc£ùäÏלDzçöᆢwB¿•:x9âØjaÞGu<³8˜½dzÀ˜ñ`a£¥%u`�s•´ÛNsð J˜iÙ3vð¦ïóðË… ^3é©�qag­†Z™w™¢§Ç=N¹£‡V à”#OIõÆd¨ïé.êfëÐd�"ašË`\ñD‰êßbÇÖtÌ·Wåòµ;øì¨áÓ¡ÉÔïÏH˜ût°9/8¤[ ½?ôö.ÿ­±¼Èp,}+Û"òÅÃôË£œí¶Šÿ�>#øtHø`š[ö®*«aepýCò [È�3;éØÐ¡¼ø´5NúÑJG¯‚ª´Y\Z~Mô[ž/| ëÃlÅûzáú»Îh{ä*t�؇­º™P? þ+áøMƒE¿KºX8ø%ڣƎ�}…ÌÅ´¡,Hò(²œ®[¨cÕ÷T,f�¯¼9=¨PÁÏ·{pVâRªP™IÃ;_BÅà€?æF`ÇbäÂEIWÙA=ÚWqß{ÅÌØÞÜös�]™Ë-¿ÖÖÜØûJÓhÚGyÐÜVНÄí‚B®2;ùGÁ¦þ°ñÂ0~™ù‚ü&К#Z0ᓚ’â§,°g>šœ£Ík ñÕ�&ê“%ˆ«ßVÁ·]6(2 ½W<v{€µÒXÞ{ú? sK‡ÚÅòÂM“œ»´so§‚ÛD�fÜ_ƒ‹'[rÉãY4Åf!?»3 e{Ø�Íî\]‡û¾jð¿=kp÷Òaèx «Žžâ ^޼ÅxûIIè²÷@î¿Ì�vîýf© ã¦öɼm}¼ðÕÑš¾–.*Ü÷q•Øî„¡GhHWýÙ|†gÉIL~ÍÀ à–¸¼’7‚K­Å¡yÅï25øhó´¨%¸¬¹NOÝ|³…ÿÊ#È7ú?a‡¼4ÚíÐaùU?éG‚Ê{d¢Ã¿züBíá­âhÞ}Sšïiöäã§ÛyZü.ÈzP%y¯‰ó'&Ù‹e¸ÔÌW¸Ng�åÝž´23>ÄIŒ-´ñäØt4°¨­õÑÛL}L¤@^& ¾ûž€»3'¢ûåžh’¿ˆµ¦¢½z–<øž+m,žÑ;K6ÍÅ0{u Tˆtë¥*”Wˆ§{§†c¿à¡wW·�'ó°Úˆærèk7�¹rSt¥ ¨8ŽÙG¡jŒ* Ô®¿®18ÓQ?m_Ͳ%&<¸Å’ÚÒ²dUý"ñ*ÉÄ¿Ymâ‹´B¼žÊbÚ¬šüŽÛÎ…+ãe¹Çß+ÎmCEï¢` -™ÅÖÖâ_=r¢Á³_9$¤|„';�‘Ïø5ñXßêÏÀÏ©Ž\¾ÍŒŽÙ M¾Wðݶ@¼ø¦N‚á»Å.—�ÂH+{48ƒjÞ%¬ºf[—¨Ð#ËñÇðp=084…uKÈ`µ_8;½L¨ýo,+%ˆÐ,•ŠÒ&ÏÉcªjT Æ–~ZX�Û›ž(A¤Üx”Û†K.ÏÄhÙXÿíiáÐò4z “‡O¦øÑÒ{@iÛTˆ9êJñß_�ºŸq]Eo¬M8®o~¾ðR¸2$°æEU,Ç(Ö:-UÒ€T­;µ&›Ñ–·ú(ë5‚Õë v©¡œ ‹ÐUþª-Á[fá|x˜ Ž™«ˆ¶­rXë&Åéžg…öiùfÃWhmVá»c�xÆý$}û,ÿ ëHÔy í[ ¨yt-ˆ ”ëCÅHí¯´Då·s˶Qä2Ù˜ÿ©{s­ÃD¸sySñ¤uvOúF£ï&‰“tS`ÕíñoôÑPÉP´}4„žÎŽá8¤,Üb^ÒáK Ô3J�S]•±÷ÛÅ4+Þ‡¾$©ÍФ�;.,ð#ÅæhPxöœ»*QÝ�Uø{Úyj‚2ê7À–·M R•«4°8��¿ö¡Þc¥ùŽY,¬6úÆ—äaÜÚ: 9( ;(~ *#ëa ±1•R¶¨ñÇ ’:UI{IñÒ§vpóÇO!Vg3´ª€À½§…ðÁ=„×=KÅ‹,…×ç³e©£H�V±oÆV:øë¤³ãÏꔹ«0äFYC^Ýq01WÂ'dzÏÂvú¸õ?á@”+èG+,©hÞ~×úG'$5 Y6‹î5Aí{)±äd<˧óW„žÞ2¸ð %?Õ�ƒûý©6l#�Ù£z³¨± ŠZÅ�­%Ts­ˆŒÖ~¦ó£Í±çÃ<òŒ€ïûÕοX'.qÒ¤‡›Ž@ïÊ@®ßHæ½Ía~ÿPœ*…u3·ÂßÎ) ¾É”ò5‰²Ó —×OaÁsJï½õ½oQчsÄõÛa�I �Y×H×wC}ÈéÃæËjq†¤”ÌΨà cuø;® £]q™4jûpÞ«âÊ.0€ÏíŸÆZ×�éÛYVÚ“kz$BË |ØWÂ@Þ�À0q§,¿.”#C�X¨; ¼÷}"ËMøwö4Ejßí²zq|9lYù®ÖÏCÇêMðþÛ~L�–§–†? ý:k©AÕŠ_!Ô÷ý#Ú¸|ËæA€úzño0÷—}Jׇ5׆ò·“\yn./œxþíºçïÙAF{3 ­ðVÁ7�]Q#‡O¯âÇßÐÓ§hJˆ~Þ¥_‹„9浤¦Ã�ªëÉçÎ;€ ›«‹3i0îÞUAˆíË®¡+è€N2÷;i‚>‡é“}˜tr5HmÜúŽÄ]s6Mœ€É—Þjj@—•,E?Kz~²MNcuã¨|ÑH^<¦æèŽEx5=�zò¹q[q«ž9|=ö–^N¥+ìôéË2 Ë(ÿÐ"l˜ÅWZò!íýxªÍí€ñGFñôß_ɪUªáËûûgèå3yÖ” ]Š{ðs¯D ýcŽ×å� }u.YœÿR{UºŽæmÐÆ ßíô=ç”hãØEWUÇÑôq9¨0òŸxO˜€§P�Ã�Íh’Z#l—ßFuõP’>–×*Ò%„~pmz›éþ÷ƒ¥øM­Û¯Uákù xÌ^îi¼Œó?¾ßÜɤÞÔ~†]yKœœœ kýo‘ìá}µó l®ÓÞBž$ òXr,‹v.û ó%Gøþ×*¸S²¬I ïŸÞÎ’äƒà=º?mΧ•/ož÷á:™‰P¹whßó@‚3åÓ¦žíp&µŽîå ᙥx³ú~ΞÛJCÛÞ G+ eÏmªks9�Fz£Ñƒ^�¯‚’TMþÔËQEÿ¨¦¤ ²%Äô2¤/¢ùë‰=téå|Ò”Ž�¦Í¿kCK,y¦ã l8a†&'p؉0|Þܧ;cmj=>|Ë>Öàã_Å‘ûGRMËcñÑȹ¢{ÔŒUI9í[჻‹ƒ$(v�£Ø^¹ÐšÔ—ÎFž‚ëÆÃ©éJ`ôÁÒ·+“Õ-*ºVEm³Qæºï7fñŠT>;É£qÉi¼•Ô��§Çó,©x(Æ›í2ðÙ¤…‚΋M¬ÕæO‡!9 ²çκÛôÚw?u,Ô“%)„î6töE¼°ì€ÿÓÈÇ'}2ÑyŒ ¯;Œln#¥ò]âÁK·œãþPç #Œm¶ãÅç�C‰üy²)�aw¦aÄQx7û*;'í£Sþ{%Ô Ä‚ ?)åÑ>xòí¥”®b鉷Ä/–™ètÎ ÷¹CÇR7ÌUŒ¡õS<o¥Ñ–ò `.3"9�î ÷€‹ ZÛ»$Ç…CUš.ª—Ö _ª mx†ÒëŒq„ñ`Ø*cÅ3b3ÀëÎ3¨pއ-ù1 b<ŸUTþ öµW`“t/ŽXÝ"¤ÒlÑzßH¿€“<4±H^ ƒg]Ã�[ÕiÿØM�úÑÝÅ`P‹¶gf‚¦rfí‰ÃŽ˜ÓqÕ»»SWêìùWÕ-:T¥�«ŠKÙU×QîÚcÊ>'?¶ÆAkÅÈcÊÐf·�l·ÈrOËLÎÞµ–¯ƒ ú'ÿ†yf÷hÏ ü°Ã˜çÆ<£Ê˜&¹ßçWow ;­ÄूÔUügæÊZUŨ3z9¿»ç‹ce{HþðCPŠ~XÀòtMŽ×•çɇãòU¼ªb”�bh‚Sº¶áíg†\}4Büþp:¦NVD·±Áì®ò�V_Òæåã?BÔï}<×i(Æl…Ú f⤶{Ô8¬/³wF‹ ·¡W[»¤æÇe¡ð€ÝùÕÉt7 ´ãdùòÉé–ŸO�7<™5ûa{�­ó®#[ÈüŸϰÛÇÉþ5ÂÍ„4hûØ/ðàeEwÔŠêWrÑùøLÍ: r% ìåShÿo/Wë[ðâoׄ·!=YýŸ=9jðo…ù$½Å�Î â>OuÚùP!›¿¿ÊÅŽ`¡ ·%«–›`Œ»wœø!>ãAèÓB¤ì¯*BÑ€Ô�_D�'Eú+xó×KÝ~¢âËïWÒ�ÜùléĉzZ¢�»d’¾Ž/nKÅ ÖÝkŽÿ(æGµ ËmgWŽDt�¦!¯{pä�átMÞû××påµÕ5§šÐž«Ë©ÚW†ûž)6LÒæ©Y?ÁûÅOÁ¶D‘öd<¦>ãß�Óˆƒ4 —«,Çê­áà {tù¤É6“¤9·ï}ªñYÁý“Ù;Ĝ󢋻ùëOíï[�AsÓ ¸]°€»fÜ¡‹y»°X~<½¾ZFûÇ[ñzmyn]kŒ�z¥¤ø œ¿x¡¹¥<µ^h�>ë”ÐôÀYúëæŽ­ä!í@4fœŽ`‡¢�Bµ§®¸ºÌV²Gz'J+î ³¾ˆ‹k¾Ñ˜hg¼X|Ψîc�eÃøåî<ÖœLíæÕz�Uu¹8ú¬ÎR“Ä|°ÇÖÇǡϿH!Ùn ‡'/„#Ñyâ)²Au�Ûta�†\-¥U‘wiïýáüH»EX¬êIÿf“ŽÛzþÚ)ƒ6¶—Ä™s3I´‰µû!¼wk"õ³úCä Íun¤¼ü0û ƒYjÄÌ(¬!ýƵxåR‹Ó¬Ë¿IC·/�ÎN¡ã2*î¶àúœ.z–�(z¼èMs_ið᥈í˜uøD¶YŠËLËŲžc@Ò/jüó\2Úû’Ó¦êl’ªO·ÎhrØñx¾ù´ÜQ¾î6Ø'Sóéã¨aÑ)‹äpQ’©>éuÒ0÷@Ôl1Äw9ZîÁSZ7ò‹ .t.¥Œø› óS ƒÂbÉà«z¯WâõI{àÃ�éú‚¤ßÌé8¢ÍKMJêƒrwà?×Þ~&i\�~Ù pFÞÛz6èÌÀE_wò—��4~ÈWðú~ ,ÿÎÃ/î§Ä ÎC¿Oû„Y犡FcoÐ�¥U1Â�¿×!áðyg”J“Oõ§¨ ‘¸ãþ+q ·z­û«ü磉ZÅ”»ðí×›$#.¬'ÈË3è¿-ù°Æì Õ,ÑâÀÎu¢Wx1¨n…ŒØ~xbÚ ak§õ9W¥¯ë»;g†ìµ…‰ŸJIZº�&t5KÒ­fÀíSôgƒ3ƒrÁ«7°.$‘cÜæáðþ´ÔLÞ«¬Õ6 <™÷¬ÇšWZÈ¢¦S¢�#wHxÉúq”;0AðϨRþ"¾vš„Ç8‹VÅõ _„çNøÌõ åÞJ€KŠKpÕ#¼å¯&öxì.Ę�ÿè[óŒìm‚–¥Î¯GŽÿ*jçØ™ sÚßR×Êzعx¯oÔâm_’A}ÖÐùxÂÞ4€ý��tâB¡°ÿÆ nîÁ&xšß8o°ÙÛÍjÄ ÇàG¤Ô_x Ôö�AÍP®‰’ÂÆ„·ó¨óO2æEEâ•Sî¸$}¸ð;°dšÈý¨)—2 °Ó/ÉYç¼,·äÙçFPåÈþlÛ7�8d?œ1*â’F%R ÒçÒ�£Ð¬z(>ž;ï~9{/]墥�I|¾—è®Õ šŠœ\1~Ý#šIÓòÌ0xIL©®"ã½ò¼²ÏHÞ÷aé¶C›CLmíGg¦ž‡i%#àËxEÞgfN®­1?]ZK)zyÂôßû1ÊWêÌ*­Vxý"/§UKvFþ¥¢AßapL*a^¢xYïÌÆE Fh¾¯7—V—³CŒûO2çƒ=L9àòB1«ý?;vœ'ÆvÂÉ1äh�×òºîÖ1 Vœ‚žž&<ä„-_< Ë÷‡ö¡�I�âˆÌjqú…+½q0Åì+$öò@½{ÕB—Ïkúgs‚õ÷6€óævrLÝŽú�ßH¦îoá¶­GPÔõåíWÍx³©€:«áÑÜ©´÷N/“(Ô^Føj(þõóåŽ�¹µ”¤ 3X½þáq¯�)=Ï焤�GÄúŸ&¸¹â±$í¹…`yX‡Ÿ,� ' DWõ#VÌW»*)ncìÛ——]™Š…oÞÒ5Í�üä{!ËdÈB×Msáê “™�Xn�Mq2ج6“å…�éU!Ú<ùI¿« Ѱ~8üÚBö:xØx¬P’‚^�!¬j¬P÷ô<Øè�:iÛÙa¿)¦NõŸé @cœ:OÔ`·¦°ïJ8U¯ÓãÑ· ùŠÔaªŒc§ÒÓÎúþá;(Tð°“ÑÝΧËê§«jw,ïÅjßS%Ûþ�ç”5¼jzWÔY ¦byêË!Ðp;Jôé» f�(£SÅi|Éë]ÔŠ—�qEûiÔŽ½(úç8à¡.Oº£µŒ7fÀÅ“óÙøC5,ÓæöS?EµÑ´!e+ÍIsá ïvÂÆ�gHÃz¿nOî‰ÖÐ4Á'¤fc¾e /m+£//3@½Ã­æœß¡­A GÿŒÃNuè5 /xC™Ã,Ì2¹ ¥ ¾¼z­›à×5›}çN¢#¶£Ñóp6•·I!)x±oÁwÁA bð\�ž®‰¾«Õ Q”Çv•Û80G…GîMnú�)òìÐAy6ý'˰ª·à3ð0ŒŸ� ¯r{ã´¢¡bŸÈu´aÐ+Z´ïÕIíì¾l…7Q|öú:(_ã+úÞ è;(96Øå/ÓœJ n>dÓoSsÇ;0êÃsú ?ÇmæûQMPjÝwk6±à'#Fh]\÷«aö›]�¼;…N›£Ê½RøÉ2yz0þõZŠV�‡—! Þ¬‰Å˜©peé&¾MÆþK!¸É#F]• °ˆÏ¤ ¶>\¢Õ&Œó¨A÷T{lø'AÇû3…Aÿ>Âg˜%¡„{WÅQ{ä9¥›×ç zøo…žy1ßÔï»þÁ‡‰_©8b¦\ÓE8ÐÂ;øÃšI¨Ã[zôf‚ðüü2Q¾àL7/¤Om°¯Ÿ—6a@[ï|4yš|¼Ô�cŽÇc’qÏšÍfñž¦ƒT7Å^<5´¦›�yôJSŒñ¿½ÜÙåùD<–³¿öä¥/sià’hnvÎ#—Ðß0òjêÜE– bÙWÏh£K(ë•>MNª«YTË[ÅÃÏ uþÒͦ ¼©z‡°Ð׆<©¤9û[h£õúÓ4‚æ4Sú¯L¨ú§ �- üÌ2:7èàÝ¿eè;¬v”Çs–ùjÔ:¼Ÿ5üÓÑQf1Öuw­•‰>jM¼‡-[ÒຠõµÊâ€<N•êåÜóÁ,ßm f?¡î~‰xol1ÿþÞj ð›ÃqØxE�ÝM]é‹ÃZ4>Ný.¤†Â[$ù¦)8÷¶™ó¹°úlþ¸2œŒ·ëscg"œ{Û Çâ�~Ù\2­»}O ¾3œÐoüVþ“*àî!ËIk]ËNöçæ×ÞÂØ¼¼ië?ñcwæ¯ É>KË`—C)_ÉÁ ¼§`ò葦ܟÿЦ0èül¡ìÀVÿüsM\M§Êñ9zöÈ…:~¢‘å24ž|TôÖ âL­“´Èªli:ô•LfÄâ•ÕqክԒ[W�ºšw,ÁâÒ,Ô�ôL8³¾ê—b®cJV±äû÷KaÇ“xN)‹5‡ã÷´ãdëq™ò^Tá�žE<6é ü¾½^Ä °it<½ó²ç…¾Ôç¨[m}MÛ.¬‡¡—ORÅÄ*ÑM{3˜”Y [c:©LöZôÚS/lëü´ñü'Ü3u z�~ Ŷ媈³B^ï ð1é(=M¯�llL‡{†Sùúš}0tç^ød8 j‰èž½+Û~QÚT-|53„Uô´ñp·+Ѳd"ãy8¹0›„ÚÝe˜ ^Æ <Öã†Ê‘Ôrã»0ʵ~§ðï¾øÜ ®Ÿ¦Œ%^À¬HU˜œaÊ£ÓÔ¸ã£6ëÍ#žM¡öð§ôÄ—ïÁSê7ùhèL.7ræ6 âÛÛŸ 9ëè÷¡+4w°7Ejd ’š(’>©H›/M„Ó{ jÞˆÿÁ܇þ¼·t'œŸ¨À 7ÚQûÅyH�6¡®¶0ºœýCÜžþ\X§f�Oôâ±e€s—b‘‰;úxirÊÏ(xôlËÎ�Ðlw-T™6‘¿¤Ú¡²g3)nxNº+E“‹¬ÿôo)‚�ÔþJÒòÜx™ÄŒ«§Dgy6ÖG7‘ÒŒrÌ{҉ѽ&ñêx/îÙpBºrÐq^ üÌ^Åë[’ÙÎ5h·(±6²©7þtL~1öœ¼ÍnÅyÒ¿Ãyз=¦Å1hñ®'ö˜òN½ƒ·1sp”'ŠÓý:I®‡)Ýêã2Û{ÛÛBmjöèÛCX:u<8­Sáé7¤àOL®8ÅÙ�+�(c Œ‘­ä‚¸«Tógï–½Aw/äQFÕzÉõ%}àüÂ,Š‹vÁV͇‚�ÉqNò Ûðàyî7DœBŠq:;`Lõ(t“@¥Ê�g¶�ÑÕ$œ $q…wË6æQüL^ðN‡ãÒ·¶˜±| L±�Æ ½¸N'�טîà÷ª²8Ï¥‚‚W/cÏ- ?Á“�&»ð?/KÜ·föj‘ÃÌi=P¡£.°’­� æ#KaBÈ9çÓ.ЙËC8ã‹k�­¤Ñ â«-X-+“ê_Ò×cÇiµ]æÞ%;¢œ‹&óEº�‰}Èe HŸÛšøï¤‹0qÔ¼+„Âä?�ìºz|¹±2º�\fŒ4×Ξ„PðQð’—§Sañ`7µZz ØpÙ›?WÃMÛßb~¼² ÒÞ.†<é o•£[®Îm‡kù]ËÁcÄF0ú¹—Ø~"£o^é˜7 ©´é³0mÞ|.ÿ° zf ƒVEÿSÀùqðcpįy~†›ñOm–¤ œ.&Í8YlΔ£Y16¸{Aü;¼Çþ¸‡¡kñìÕwÉ<øÊaêm´áØ8•ÆZ ìûÀ�ê·áõ»ÃñóÒù¬s~ý÷f>Þ\ä—µ ¹Ëõ<¤=×�Ë£IÂpIàõU¨·Ý”_w>¥�ÞÁT>>§Î_%†n=CæÊÃae�9íQH»ô¡qC$³X�¾åNâˆuýÙC9‹Æijç>ùÒ’Ÿõ?'ô¼œ�Ú‡ Q§›�:')s¯”Ñöp9ÛhVŠÖú ±ÀÈÈroéð^-Ü…Õ”Ýó®à;ºÛúŠƒ÷Èì|$žHzOJ†ÜK¼ú±ÓaÁÛÉÐÀëÑáé$1ß±”Ë&ëCý+yË4ÂÓ_¥X?tª¥ôƧ6›ØðÏ`^^‹OŽNgõÝqØ9¯äíÕQÜ0¼/{é¹ÁžúB„ýEñö¡$|:s‚|¹­ðø‹Q¦ÄŽo†À…mŠ4w¡'´º †ñ¦¸“&bï¨-tk[²�9Ë žèlâ†ô]âuTîžÓqÌ}™F�/'ÒE·Í(g‡%'Ì=%™;PËÆî´‹d¶îkܳç<—�ºP ûuøsа�P34�ÎË Uñ§¨v²7Ú,üYÃÃè‘\>pÑ{ê¿·¶6ÊYÍGØãˆM¦ôÚ¬¿ÐóA¸àÙ–ÈßåpÏ~EôöRG½w·iÿ ‘ÐQ6�^Èi ›œ Íh ò…ÐÞã%­4Þ ý§ËÃk‰"˜�œ‚j¡œ1ôŠ ëÞL¼^†ƒ7¿…ÝÛ)÷”=-�w+²LÎ[jÞ2�ïºÙð’ôøtæW´\0Š+]ƒÊ½qñK1õä_š6Õƒþ™I>Çìĺ• ÄçJm“Ë¡ô�*T.D<=ΟZ¤~(UˆËm4ðÁÅÂÕþð«æ Å¤Ì€W’ÅÖ±ëp�Á9áåŸb°wÛÄã“Frtpšèàz�¢§í…ß21æ’~Í.ÿ«päR›B08º¤•6Áâ¾§ùwÜ;rHâ¬:�¶ü€•n.䔮ަ×~Cßt-:Q¶ h±.~tJ§ÓY'ÈfŽ–ø­@ wÞ=ß"ÞÒ�¶8qíÒŠP/¼ß SêD!¿RŠWnyÃáKNK¾hl©U~á#<ú†S.ÂØ?WE]Ÿó gÔHïnЄ}=Fض¯’XÎÁkµGãŒñá°kU¸Në"gнµkƒ–¤ÈÔ× Ó.¸^H} éÉÇhh¼Kp*êüÑG¿Öôå£o×SÍ´ñ¼}ÚJ^cl¿›ÎÐþ |5V‰=ÌôÀS³ÎlrÁŽuÇaa?mìùc:þŸCûû‹AC®CXü/±4s 6æ Û‰¸u––ås€|=p*ƒ)·B —“?mÛ Ãg�¡®€ZJoZßÑ”«ÑÖ—ëµJ3–àµÕÁX?Gl>¢;LñËøCø3ù˜p*^GžÜËN×�Ö´8‚}õR±«Eš"Ô1¿ù‹h0åDJ)`cº÷»„>«Žñóèí¬=è­x&K{ë»ÃŽÐÏâØ@UI¿µÇËK+±!o– Êõ£­ç÷óo#Ê ]âì?4/$~"³-KÄK¡£Qçµñ ¯P…›×�‚é#ÝI ð»Ñ_ŠË?H —¿ƒøSo„}ÙMBê¶dT{ÔíH'ü8ÕÉ»6HÇjýk’Æäñy¯ÁüeÆ«ÚãSzó”gJlç´ìmxËÞ�Ô<à:<Ù›'™}¤»;¦ c·½ƒ^0÷°É¡i¬pX‘£–L¥‹«ø@dMþY©+¼ ï*œ?6ü¿NÂí@®�è‚sMjà2 ÎvÝMTÌùJš)_ ð¹UUl(®™2<…ÝäÞþXøñß'z–e‹[�—Óù oILýÃñçë…E+`�è‰fŽåÐÞÍFµñÇ`jµÔX«ÐØ™õ‚þ‘{´ò”««ó�X(\-è·ñ‡ƒ½9ìåê?<˜eÃ¥Y+¸Úÿ—Í•:k¸­žÅM¶"®\û?çý×óÛÅñvJC‹h(EIC2ªÏûœŠJ!"EF²’Œ�‘•©h*J$£l*ŠzŸƒ’RHFBÈ,[2¾Ýî¿àz<®×¹^çùüåb‰ßu¼Úƒß§è¢�{ Ô°3fÜÚÃóì'ãå¯OáÚånAñÒ�òª[9jÒv ŒÃ3©Wz§9^&ç CÁpt7\˜P¼jÒ“ç¸\lHÅ«è«\¹Ë=¾~?-B£X+b,yxœÌ_VÑýWCÀ¸p—+M eá ù|ÌAL;™ =ÚÐß©�ô*BäŒsÐÎz¶Ðd¼ ´7þaC{=x©å¦ɮŀÊÓž’›Ç\[cNgo9cLB¼xt‘8½-|óÔÁáÞ,šouMÇqÕ¾¬Û8�LÞ\£Gú²®: zˆ»œ�Q(êÅíÝudrj¯’f隉Øë¹”Ó—/ZÜ “ÁÇÉUð¼ß öwCOC_Œ¸¸÷î°Á{ÙwPß«dµ—QNÙ1Õm¥‡Ë·b±¤‚Þ¶¦Š—çíåç¿‹ÀB¶ퟠ†^+-Höð ÑìÝXì•`�i½¥Yñb#ýU~ ·´Ê´ÇÁå#ã¹_e:¬°õ$Ì ½eDZF£¯N8[§ˆJNãÄîSbˆÑlj8ÿE|7ÞOÉ…’Vù˜Ìå·Žó·°“8Ë4VÌš(Þ®qe�++ðä°«´1kkd/ãyÁ[qVQ$ç öÄâ bÚà¸{ÎD_;A«k7|Y}œòqÜ)êžáUnníÆ–ÕŠ�ÒÈÔ«U¿yu‚RSßSåKRÔ°æ†æ$ké(wÞE¥sø´v2�—‰V¬`™ †Ä±×19ÎnÙC ³·³œ[ §$h±××Ãt#Ù„•eê`[j<諾w6ÐÙ=cAêÌLPžž€»CÒ . ÑêûQ¸ö×Tð˜øE¢d9Ÿ�£7³ÍþôÞ¤ï÷ŽkíZºú¶æ-xžÖmþ`¸Ðœ~ nÕÇÓ„¥{0ëo ¸üþU.gÌs’À&Mši7Œ1ò�k!ü²²¥ìꦑè÷TÏÆ|béPñïXi´î¹ˆ=ió’.qyÁ:Úºð÷Öx«8þ˜OKý†~ç·ƒuá-òF“¾L'ùÓ½ÿ1¼,ÙWÝ££�³P˯N7¤a¦8{»ÎäMv˰¯å#Èÿ,Å2Eò¨<݉æ>Q&ç˜<—5JqqµÙð‹ÓWÀ34�U¶œ�ã^ŽÔ£å1�{‘Bnf‘`O�S�pó{žóeüwJS“|Ðwm XðÐ��& r´‘Ë.ùci� V¯¿ÊR]ܧŸ†®’aý }6öC!_"À í1Ôô*â±£²9æT=õtÏl»;Äê;izÈ0ªÍ+%w�”t³ŒãEt´âÖµédf׋hé÷9üëåo²Æ»”7¥ï‹ÞBwj<Ø´ªì_†Iè{Ñ-Õƒ¸mÔ~qãôõ�òð Mø�†J#¬ŸÓà^ădáÆ¿š¸Æû ŠðmÓ¼[d ‰«@£·µ¤x;üXˆ©w°‹„s<æ�ò†þcN{¬þqâ6!¸ªA¢õ�÷s…b�¸ <ðj=0wÝy³Åœ‡3!dŒÊnofµDi1±©'^¾•Në~õÀÂU¬¶ò_ ‰FÚ¸Gú |ôHÀ¡ã—q’Õ*ɬР4ÆV™gM²ç×É´âê^šôÆ…ãäšA®9 s·ãpÅnØyeÐÁ)çÈþ«©–Ö•·(ì!cÉPsè5øiõbËÔ0°t8H­/nÁ«iÃ`—¿,ÖE¢“ÑWê=œ!ÆÃ’àrèXá½ådì§¹ŸŠ¦;ð†ßPnÔÓ’ïA¶«O”XPÙ¤>øeñ!–j0�qý*iÃ7¤Z…GkKyаiüŸ‡—¿É#—¯#°‡O>éç~§bõv²,ʃ¹[ÿ£š9Jœ;ç U�û. Ó·ÿ”Ü0³a8ló •áÖ9i¸’ClºÀ¦pò%}Ôm,æÕzIpyéø4os¹Sì2x‡6¬1£œ‰ÿInd¦_‡ÞÒ‘ÏÚ’Íš5L¯ÆáZ7%Ô-uá³�¥¸=¥›FÙœ”7=£ucshwδ~Ö†Cò9™‹‚L}¤äµ$m âc=:Ü7‘ªeãÀ¡Þª¿€îºжí-·+«‹õñ¦Ô^ZN»‡6à㦑dsg-ìµl�G¡y‡+ìÐVÄâë�)ø�)]�›ë¦áÉÓghàü*Hý:‡¤æG—¯QI¦ñ§UiÝ'Wl?˜ê·4é{z2>Rl"·ŽG¼åÔ�± ãpSðøŒ¦2¼µE^îà߈m�iþ5 îÝ ©²§@½ô2Åjå‘ò.CˆiE;Ú2¨ÞQM¦ŸÓÚnÂépéN ¯Y%,­Ž£ßò®¤6ÚÏ–ì'ǹðÁu¦¸qÕ¶«PømUÍ®xƒ³¾FAŸ˜�´0¹ÌS…£îj¡rÁ²©1ÂU�Û1åº+lyðP<£þU”ÿ˜+¿k‹¡ê­äœ,î׊;í¿ ‹�©àÖsZå¢Ãkîo¢º®,®î¥‰3LF ÞnмØGY ‚4¯R´Z—CE×ÉDh¢Œ5¨Ø¯Š tж²póÝt6pÐã”Æét{ÿñ½çP©ù �1tMq-|ëÈáq²/©Óú¨ÎÞ��¼žÀÞ }ÜgçÆw�"·>}Ư¶ò’K;ANI‘šeñÅ–a0ÚÄ,£ßÂÊÝãaÌ›Õp|­Ò¾B¿�5Rޝ1Ö} g3¥iÖ;îüõÔõÇÐÔÍù”•ü]¤|¥øº‚F„ÂëC;YÖÆ‚4²wóù~Cø`„>rÇÂúß4í@,,·Ìv|ñŠ>¬XBn_/ƒ¿Ö4nr]EêÝ=èøL \oD÷¥b¹ÿ•âc÷çbQ¡1Öú­Â)šk…šÝyÜš ƒç1_UD‰-«7YZÏó船=é<:EA¿w¡fÔ]z+ùC·ô¤q~ÆmÁsT>mº{N-"íAêäýQžd¿•ÓÒ͵/-ƒ™RV¥‹Ë⤎ÝhV¥@ÿjƒôëðGé!O­¾àjEÒ`TãG OÐ¥—þe÷¥ÑjÃ3ôù—?F' ”³%‡:EaŸ²y[GSÀsN<§’ìà ӰšºWÚ€Šé_ø ÓŒ©´ý$à3üõ8]ðTÅqñPÕÚÅË]ÐAS…?ïéƒGóŽá9Ó… l*ƒÉêï!ŸWáªóõT¯ “›×r‘û=0»íI×ÿ“‡&]n�9o7´Â¨“VüföUüsCoûïu¼qÙõ§HX=ô:MÎú=}ýˆ|ú×øòo»NûFµlQWµoy_;Sj‚6- 4âz ‰÷!µÑŠ’£q|�Côüu ˜Ä^£Wê ÝDWè×®ƒêGr¹×‹üX©?vú ç+crûHX¸WA8!Ö‹zõ.T½Ö’ï:¥>R°2k.Í[ºÇ4â Ÿ�_±"®àM¯‡&ñ¼]¾p «'õÙ¢Ž3ü§â¤û=qÜä:ò|°ˆ\>[ WÎ'¸V¥Ì#ô”¹¬üå­ïEö'¡Ýì+ ÷o¿Ë9³š�ÛÊ$1áïmÈ�Jà“_ŸÒFE Í¥føl«,žÊ��†“ߪ_bð¬Iü'V†ãæÖ‰Æ¢ò§,>² ¼OÙ}m`ñöŒ?8Np˜/Òk”ž¦ ŽñWamŽ#þž”ŠRì°_Al¾ð’V«“‘�=ŸÊï&å­Oaø¼pO›Mq.j|¾^…�ö(çõ1vÌHz2®Sx³þ5-:_S¾zÿ9 \’*ŒÓvƲÔ#Z³“^úzáÒ³é16³uì ~›)oÌ5CB‚¥¥ ^=¦=›7²É¬’9ª�<#©?i|‰ÅU½.C|ÓzV}Ì®Oæý#Ï–K.,íï.!ß�è\sƒôd=¨qÞ@Ί.Ã!¶Ôr=_Ÿ¸Ží‚'F–øÞ3·<©®?ްæŽçú(jŽË0ÏG‡�ÖäP£úWbÊ“v¦‹²±GÀ1Ú‚?< 7ªö0îÉFšìöÏל{sÂ/MÞ&¿„&¢ù–ž¼Àá™%Öe �¿ËËæÙs™…2ß©á#'†røbÄ]†¶ôÙí!tš”ˆã Îp\žþ§ç„Ÿï…asrüAsôûhÏ-×cI^-ê �⼫ëÈüt¬ôIgñXÊ8³ÈÆ&Jó¡’I<ù*AwÇ<vð3´÷"³S9|Üá�wň>Ç›>#iÈr5\ûéÏNpàY�zñáK¤æˆ³Vg“ㆠ ÛPO]ïc¨ôROÜdt€J§jà“ð`ü©×Bée _Þ?þùMmšïiäEiœª1_˜mÅÅ¥Á´öáJ ²©e²"Ùl‰ ÿuˆ…×ÊeûóëÞÉ`È%üáj'?º€›-M(­X®éҼϾ`l¸m* y¢öx:Ð-ËY3BØHã=5ÜOẩxï¶å&5J”�ÜWÝ Î”Ì-ñ…ðÍl+ýšçá½°èä@6_PÅçóU@D‚gß}o$aÖ oAêÕ{°©Œ.g50ÇÚœ ´÷âÓ+ø41$kœ¹jó$ÈÅ;â7�¾:P·©ÈZÉ»g«£§½ÛÄÛ¯gð3ÙëâæñÓ¹lï2aúàH.¹^ÄÙnˆ¾¹østOf¥œrÜŸL+ú¹à¹´Þð`B=}o\ÉÇ3R±£*[²üù<þ²ßŸN~ ƒYÒˆ²}wQHh…Pûò{¨‚{/•°Ÿ­)ÌøΞýòš0ûÈØ´u+f®{ÊÑ·5�FØ âŠ'�J “‡½=+}yø{?Þ_݇��Û så¤ypa:•îφþy¬q/›Gž€Ž)ö3-�m:Žð¯ãÀøÍA¨šS_NCÚaØ4,(SF6+f| ìÉɦ°JúùÑ«@…”‡è¼Âî&mƒµtÉÖuOÌ�Bë~Ø£t$>+K¦ki޼É7€•Çþ–=F<«²„…סÏ'zÖf̱ÇüĪÆ/åÕõ¹.=ž'ô GµéDZgy^ö‰ÂýyfmùK¬ø—žÎPÃÎ/›ÙÚ'ŠÏ>�á?œ�ñ¯§?6‰zœî÷A…ÁixøÍ;ºÖ!�ªg˜vPt�!Z„ëÁ/·]”ÖÇ«<6‘®Æa:y&‘œ^Ø– þ«€ÚçS¿Ó ¨ç| öNna·UÙøå—ù¯{MW�[`R|ÿç8k\YOÙ¯.ã¤�åd¸oÇŽìÏ.Ñbñš5Õ³FïŠaȳÀ7±Ò"žŸ¹¦Ñ'_~˜˜I ŽÚÜûóŠì:/Vh¸ãÕ÷¸½ê„¸Š\½17t,dÆoüç²Ú±ŸOÈct�'Ë®,¡É+�Ã@9d0‘Wê?ÃVö�~–1`vÖšk¯ŽaïÑYh³iX<~:¸ FP=îɦñ�wAêaÎ[OKâI¨ÚFg³éÔƒ»”â¹ïú9À8Á/®N ÈizØù©€‹<€ÃÒI¼ýö]¼™m†ë°U¿�¢KOÇn¡�z˜~£ìã¾´{giv}§ØTM~='ííMQ±&8áô¿û±ˆƒ´-›¡³{¼ì8Z. —/Ø‘íxiy0¿—€åƒ!ÒË’¯-‘f]ßqܽɘ3wÅ€ñäkd2X–·w(\:Úq˜rõ.⸛eX»<�šW±B’*ŸŽuÂ…oŠ0–õö�ÆÁ1q0öŒ:d'¼j°ógÔy$£™oï™CÝ�?˜!yòüú‚€¸j^»•Í]›A³«Šk²�b¥×6~/ŠÂN|¤g­ê˜à û;Düp¸Fø¥0€�wéAÓokÒˆ”ã®1­(ñrdÛx'ôÚ ¹ï|$ÚRRâÍs’TÏC‚»C6ÍÔàÜ›·iðÉå]Ë +·ŽÊ÷£]Æá€™é‚ñ›¡ü56‘'¹&æ¼×æäë¾ ja�Ö6—/›Æ¨lüQXüœ”?¸òýH%‚ÑIdõ¬ÛÀpÃDn´—M>³0­$ ª× †{¤ðÍÏt>“0Æ÷l¤WJhVÕ>Γ¨óžÑ4,±„à»êï§ØiõbŠ…­Ü7še½Ý‘w1âŠ3î0¸Eg“»é©Ôiœ"¶PW0�ÿÓ“å}æôæ6ƒy ¨ü´?Êh`�ßN|*éǰþ¼ �®8GE{‚Y§ò$_,XÌмéÈε´âÎ!:Í…=�çÑÇ Ì‰ÒǬþÕ`¸ã²à5Ç›¼þ®‡.�½¸ÎΞîFØa}ßO`êHw |qÝŽ:ðrΩ½°ÉÄÓ‹¦à ç]ôÛìý‰ûKÒ¯àçÆí8p¹.—c˜RcKÁÞ|+ ÛßL�<3~6Ÿ½ß«¬À_vˆ«%˜¸À™m©áìMI¦w�ÂÀ9Cèëéɨ•õ‡¢¾ÏD³©ô­4 â‚vð±’"`ýÓBÖ[œž(Ì8¤„¾e€â_ºn¹†ÓL� ßeb(AéŠ0­9‰ õ_Àã ì.s›HI8\uÞþŽ]NÁ‘«ÞAþï%üåãYêÇFy~8r¢<VS¡ˆðYBYM‰¸!i½åFÇÆàê#"WlxK† q‘2�ßú*8�ƉrK©)Í“—ë¨BLcÞ·âõ�ª£ú=î8¡»Zì÷m[ÛYâª5 ÂßçØtcoÌ ß%>�˜Gó“Ç—‘Ø_:–,´vú>€Çö=Q{Ѷ1˜@}Ö“ÜÇïðúô¼^ÖIÕ+(|ùgñf¡é–³Â¾¤å ýË�úΙ�“;»á[¸-\ø ܺöÑ~íQ|\è�ï¾Ñš?R¸qÏ> 1™Œq+¬9l®M¬•á¾ÿåâ´#$÷t¿�a-MR¤ü� 9ã�&\niâ(ð%ùo¼çˆV[7ñVǽ0Uë„™|¦¾× ~‡ò•ìÛàlƒ‰›™n7 ;b u¶Mb¥¡H¶+UŒ¯)íq·¼ç48¦ l¥¦Á�•V|ð¯"Y¶¶ÞŠïÌn‚ïÆçóÆK¨=ë´ìË…W—Aø×ñ۩Ѹ'Y½¥ 9Íu¢h¡VåG”E‹…n˜5�ºó��ç¿ ›kzòÚ+ ºËeØÌg9ª„AÓØ_P$%ê. GZœ„…#LиÁ�óˈ‡s[à¹pÔ.SEÚ¹Œnl5cÛ§ûA9b,ª¯�G—®ß””%ÇGÞÄàÀÍGÈîà\»ðo¹oË1e%XQ¯Ë…ñ–X¹i+Ö+©ó±ûòì\¶�Oê¤b´â6è¯w‚ ‘Ím°Ôó:h;ý¦¥‰å¢ôÍ-dôµ¦\vŠZE.ÄÚO�PðJ�c·Ü-¿²{œä˜C…cËxyøì9&�~FÓV]…ŽZ·c9xõ•æà}Õ MvàÚ û`§Q"ïÜuU¬´_Œ*ÃâË#,÷°ÂåAŒªE0ànt¶ ç/Ò‡ÎÅ0Vf1 ):ìW¾ƒRkÐÍÏ饳º|³g¹¬" OºhÊu¤Cí›áVÆ#ñ©œ=~®{¢Ìšó£‰:Ò&qঊ?"Áª4yÀ)Öë¹ÉŠ­µÖªÿ„øm ü`ª¾YÆë`Ó‹‹<ÍV—NW¥ã÷s¡¡ñ¤ÄúJ8:™Dã¥�I�”«/yÿ‘¢û­�‘«{±˜´˜ö½lÆj¬'÷©¹PøhÜ2öÏZ9ÊŸhuFG™ë‰‰œóçùüAøïùOº´U?«; °yeMÞm¯_RÐÇ~\}ò(x¡,Z'—ÐxÿèRVÆ8³¦òw×úòÝËÕbÜì×Ô<×—õ=ƒèðó2tO<Õa+ðØ·¹¬Õ%3±\.®ÄbÇžçä&–?p-¸TÅ�;Ëõí›KÓ8I¾UX`/-¬Œ��Ò?ûíL KSŽB«°G(ö’…ÿîŒÀA7=8iµøX+ñø‡m`è�ŽÙ‹´yÞRC (ÎÇF'æQŸvÐüËSó¯94cïZj쩊³…„Ÿ'éÆŽˆÞhîø¨{|‹ù@ÖzrüDu˜Y­a…¹êtk‘œ8¡ßvŽÐà ¿X1ó-y/Ï„íûGñ)•½Ô2×Þ3a?£å4cEÞz|4ï’âZùK0+¥ L]4Ð(é9Ù&”©MÞêhtLf ûÖ+rÌœÇåÅk„앱°Û?Š''¦€…îž^ñ‡®f/†�`«ÎOÃä¾\YÙ=h@É*J3Ÿï» vîGêo‚^�%¥/éÖÝå?²–<¾*qaè^H_éEïõÀCóh– „-’è€O�¨,—ß½ž$6P2ç¾èÁ>]9;ŠK›²éêË46¼Æã>a”C æœg4e¢w÷šÛ[‡æ”­¥4;{ÔÙ½>¬ ¥Ãµ}ÑÖ{woO¥ }3HQj%LME«Ý¤�„ÛŠ”ñ÷­î½¢•ÖoéÅ�Ÿiö7*5ÌCí“)ÐÏŽï;ŸÆÛFÃzÛí¢Ë´Ÿ¢ÎìøÏg0\ÜËSg€¨ÚÙ“sç kŽÝƒ±Fó“è œ[;�|ßTÂÄÙ¿Å»¡ÛáðÇξû†µÿ¤­®£ÈëÏwœq=�vEÐÒüc�|ù¦�ñ0èßÙ¹ Ëó±òèº|ú”pK³ŽÖF°Ÿãè·†ifJ ÍéZ@îç>‹N)7Ëbw*ãÒK½$íújÜðb [jGgžå‘ýŽ}ø`�;W'¦SwF~Xp}ûªZçC÷qov• Æm h²ªvšK ±W΂]Pˆð`ðSj8cËç·ùмNy8f 癇ò�@^tÏšbŸÛ�¶ìpèPc©`@�3Y¦¢Z§KŸØ 9âóަüˆŸ»ÃOÕÏ€¾ÆXn±Žd`¶–)ষôåŸçf ÷Àr¶šåßÂõíÐm7#4èÍQ¼ïQ$ÏŸž#(ý¸ïEu,˜¶vï9DÍr;aOÇyÐÛhÍ6Õj¬¯<—4K ÅÎU­Ôpy0Š ®”0c%oÓølc:õÉ÷€j¥ã³a:–óÝÝøâŠ?.Ô2‚¶€p|>#Ìí9ç¨,ŸÛ÷­Zòåµkëy¼R §åàúÙÅ´Yn:Pî<±ôûN(TÖÅe[v€ó+;”m½®£"ñéÌ��ï"‡ìÿ‰*‡û’ûÖf¦W5âáÊß“c)™Mf.|Ú?½Ô<.3Ãï�ŒÍ'ù¿kQ¡2ÔÔ�"ÿÏ­Ôªu ×è-¢m ßÁ>] 3ì9ÿb Ôì�S^¥W}“¸oW¥\Éãy}HoÞrbÛæ˜ñðö�py¿%LI]ƖϽx¨ ¢·;&[Eѧ9|â†Þ w=¶‘âßO†áÿÿ;ùåðˆÎÔNDÍ(9:"½çé\ú+¬¢ëÏÌ(ýèê a¾ìdLØ�L1*c©×/Ç55’IT/±Âƒ.Wæˆýï8s@I0|j[K§š€ÓÎ u_—{´õäóÏüP¥òù̉ÄÈh "×(~}µ…j:#±òœ•ÐV|�Þþ9“šW¢‹‚¶˜Ž+@þ¦�˜ðñ<³ §Y6½È!«Œ}s*¢ÛQ®ö>å«Wpu Sw‚¤¡è¡è—@p2 {·ÄÂÎ^^ôrçCÑ¢éµÆŸ'׺Ôk¹û\À;?† ¹ÃRÑÄe'°_—)l 8ËO[Éû±ŸTEêª2`êú{4Pïw0G­b1"^ &…¨a¯;ÙèþÒ“•DÝûq`ÖXdñ^¼15VT‰1‚Ð[òÐõ4O´0’Ãáþ…¼âÔa|óT�ÓŽÉ“ò¥8äw *©ŒfÙIÿ\ù¦=ʾ™'déÊc~r#©4í¦+˜¾ù)x$kRáá¯bòC_ ?©�õÍtâ§N¹û lÿã�x³§+�ÿ#†*�çœ8 ‹&K¡Áü GHn!ã{ É,^‡}<3ÀäóJø1q¸G¸£ìH9t4ÖçÕqq¼p±§O;‚_¦AMt?öèØ&*-æ�TØ–nÆÅʦìÃQõ¦ø30>j*oÌꆵ—NScål²ÿM•.íð÷Æ5X‡›b$ Ñ9Ö<š„MNþø§v-M�é�*ý�¹EØNî½ç‘_¿šqv(*©Ÿ”¤Ótž8]ŸWIW .ë_Ò˜6xãÖ3ú²í�ìº =ÆÌ£íŠí\kÀ]ùkPq�-Üë[m†â˜ £aäî X®2�oSTç^qd†n¬¿Ho&îàŠ?/Ũ¡ Âx�Ý‚¥^)Í{M#re0R%§hŽ£ql¹&ÂŽõ]V°òù7ðþj:^ù}‚ÕÂöŠ×m¾Ó¬¨�ôÀRŽ3WOæ¶mÚØ4ª?ÖåÀ`µÓtók î±þ~{F.-Ê8lU8�Ý®ú-†\Qs‚Ú6Ï¥ÜD)þsk,¿õŠ¢»V²|6ÜëÜ×Ђ“Ú8lY_Û^ö@ï½ðgª1Ë�ÏÁ?ÈmVVtWйô0ø ͤzgzN¥m–¼®K›6UR{ÿLZ«ïŽY÷Ó©K%€=ò"©ïYmê­½‹JJ›Ó~ÌÍ\¬ Ìâ·èë-‡ôi­1.d%yØ<¼€"³µxyÞI(;xÅÁöÖÒV�Æv͆´÷[�Ø–õP¸¾á:äí“ã¦WÉçâR���6l&¯ÉÜi4“cT­Ø4$Šh•ê̵ã°`~„å.ª¡ÔE›º~QÄ¢;ô|‘¿B Æ3J;„�“¤þuð®ÒñFÅGqàvu4]¢QW'ÂóÖ—´H§rú—¢ß÷FØäx‡T?åS¾³�½ñ�I�DÅd¾89Ï–‡·Ý†Ï¿mqö�\è]Ðc÷?µ�#èˆg�ð|v“Ø£z/;íÒ¤!mGïDÞ¹A²qƒ¡PØg7ɽ–�;2³9mû*aŸã˜uì:¨}É¢=9|}ÒM¸£Ôƒ½Mj…)g¢éü4#ÒY&S®e=>Fqàl^½º˜Æü½DÏ%á¬'íbz£N K¥ßê |Û.’ß�âhçy^”ÇЧ Èîn¾^Nk6s™ûFa~™\5†ïCbi.¯_ÎßÁïdi�Á\|b%¶Npa�¾š¨~J�-ÜÄ ýËÀKÁ{ŽqÁðîxƒ¼ÄOt„ÅKxö%î·¨×@ÃM¢uš£ÑâTVyÙ“2p~Šæ÷J€}Ù¦d|ÿ œn?€£ç¾¢öXuZ¶Î›>g ç/Å[Ë·…ÊKdmH†æäâΙ°þòwx‰1®½4Ë:àÄ÷Q´øR-x ½,TWÀ˜í7èGÜøüå çŽ5§kš… >ÝÏÃÑõW h.ž†Geï�WóNžLe÷¯Á’úkª˜]*6ƒ,uZhãž r¼éh~ÒÜ/}ÿƒî¿l+Ýþ+‚�¯ÃáVJÞ¼{ìëŽ9Z°ñÆK’ÝgóñUP©�¼_^¬½Ú(žN�€ªá|â‰J†º’÷³5øh–Žðlé5*Ÿ±K(X”]21%WE—ú²é¸fÈ{ò•vì�6 |C[øŒ“F4-åükâýóv°oŠ”h3"޳nçB¦C.žÛªŒ‡³MÝö0I%”ÿ9€;b¥pó"UÜ4�æ©öcéøþÙeˆ‡†«£ªde»�Œ«y@O�ÛbÝšj«xK‹S¯ †Oô±q‹<^<´/~4w,Ì=w€¼Ç™ãWåtŠM–Á¡Znì4TW�ΙϣñÔðatiØAò°ºLdª€o6ÅS½ç#Á1þ½xõv”`lS,x†æÀ‘âðKªâØ¿ë�½âÖ;`Ém„¯ûl àöHú®|œâ3õÙJÎ Uš7pÑ­GbZë+º1-š¶-=E3ÂG°Ë¡5pw ”ïÖaëíÁÐ'înùÂ2G<ýµVìüqZ|ª’D�“é±ôv¾.O]åþÛjHfƒ�u‰ÅúñðÒúmÛ[)´gÕRp«SÒ-¸‘…ÛÕ°ü±þ]hÊïƒ:pšû?¯™¤W¶qжP²§ÇKÌÑ&¸7Ô?? U­±©V†ºž=¡’´ƒlïÀ.?î@ȱ^XW}„ý$@¥Ù@ܱ÷UR…�éI<åL<ê,œÊusëax�9öñχU2»„âßáNå6nïú —;‡bðõL®_>�®vÛ�}H"ý4R@ëKn˜›ìL{õƒÀ ËœçgKøúŸš‹ýWÏäšèBŠ K†[²KÏÝüëlÔæ�ʃµqÊЙX UEa߇âŠif¼GN�ãd{rúábÇaHRk*/œ�æ“æŠwö©ðCKp¼/ö+ùY¾´lWYE„/›í¤µkWAÿùœ1¼Ío4r�5w+vrRp)|œì†ÏÓÒp×Z?¶¸Û›SÏSGª7o­�gwÄù;ŒÀÝ@…^–ä6�ÿ³+E»¡»…ç넯 ?ŒÂÂnô-¤{‚Z'ªðÜ!ítý¬Û?ßÍ>?åùSýMñBèV”³ùDOä^® +z׈ï|j`[–ÎüÓÚ—jâCßn¸¸e+»l(?wà­T_‡%=€«©Ô?·RÀË=ÑfÜ๘÷w1ž’3Û ^ƒÎð|(õÕÇççWЙ֋Ðû½)6ÿ‰¦¦HÍ•{ÄbùcP4ŸæE|rœ^S-'™CŽßâQù›äâý‘:§g¢]½&è8ÇÜ-˜ïøïbðô7T)ÊcÓY°.þ ýïÇsßJ?Tß–O–öY¸øG"¾–U ÿÔâV½¯âÓ÷Ë0çÀ)‰!Ž 1AËaføÓÌ—óÌÅyÇÇð�>ÁtfD Õ˜¼v] û§ á?ÍX¸_8ŽØ }5¬èó—>œòw"-éÐ’®ÞƒÂ/vQLdµ"8}@—úëßËTUÈ?|$¿˜1ü»OŠ“MîC´~ Üj]ŠKË®9†Pûÿ¿–ÜKæ*|5‚ VòæH‡ïi!'%U¦VƒªÏÌ”¹½¾&˜L¥©BÈÿz›^šO3·ò€(-ìÓ¯\T Rôؤút‚àì~âà @ïõ§Ñ¡Ù‰ôuêmú´Z‰ÿƒ—žaÍŒÓbïkqTS” �ßÝcJ͇ÕS2a ß2ÇíĹ‘ hQ…>%9Í û´“px,ýYñõSp�¼+Eèuý60†÷˦ã‹åÅ"ßi �v<øÔú”�6º¥t|M6 |#Á£R ¬¥PH§†ÍÄW+„S ¥ °¥?µ<+6Åíã ¯yFJ3�tœ+Í:GøJgºœÆÕÃãéæél1À×>Œcšú�'އRÔèõ¢þ’Á$Íflè¸ §u27h ÍJ“9(ÉNNÖàÔ”'t¢ê…ðõÈ Ü¶íì¾TLŸu÷À§óýaæ›s°câ.Z¾±ž*åÓ¢U‡ÄƒNWèªm(Ï|ø^¬ë¹N _pG¼×Ͼjƒ±#aпY‰ÅZïxÉÝ)н¥/ÖÍÿ Íw¡RÏŽ×÷à£6»é‰Ï}gù˜m—܃¤áoÄÞK«èèžÇxê}ØÉáÄ1Ÿhû È©±ã�ÊÌ‹ôš§Žkåtx¾U˜èý¸–f-Þ†¶_2áÍSþ1ê2=x0Œ ]lþõ` )Žø%ޙ߇d/Æå™þøÕ$•ÝþÈqïî <{dŸ0‚CPµH½¢ê¡;Ô€w'¯¦âeýð™R'�~ÿ j,_ ‹ÏÝæÖ×£�Ö߇ÂmÊÁ,�Rôñœo„º•Ÿ(y™öëî‚!³Ð¬×5ò[už½Ô@�Yc9fŠ)ÚZwäV‹]•CQ/º†r¤RÄÚø"öŒ°E_„—¡x ¡?޳©ãƒ'ûH¾ÿ9Ón·ÓµÀû4êÔf8•ßJã{ð–‹&�`²› ’…ã7 ¸]ö9éÅ„â¢==91û™Ö¿LÕc(z7½pı¥ÁlïÃÖî§‡Ž ü¡ê1¬Z6ŒC¾A‹E•Ë:³ÒØmCH�?),óÕ¡MÊoÅë‡òÐ¥]å£�Fâ†�$Nh«ƒECWfœà–Ug…¼Ëï@!þ‚˜%“G TÀìðxä;Ëy|Þr2Ûï rúyhVtAHù7ô'#ÕÇywÉÜÚñÔpñ-�…ßÿä€ÏëšÜÙ—“dÛ.ÞŒÖåÁÞR8¥ú9Å?£÷ûسÓ�ìãC茺5+ÿóí•-…ŸEø‡ ’»‰¿ÈSk3ÿ�„ŽCqªÃ<\´ÝTx¢ÁÅËÈ's(÷å!¤Do£Ê¬Ñ$ÙÌú$Q»™Þ�³ä+ØÎl®ò´àVÏ8«á‚CçLäÎåàÙy>IÁH×íìsûRy®Ú0qªÕiÁ4¾„½-*aÊø ´ºË‚U—› Y.²Y÷šŸÃŸZc!ãå{RËO…ïZ“À©h&V´�;9,(…‡ݹãØ;qæ®*újÝAÙËFò©ó'x½ÛàŒ™'Z=Ø%øOFþ>ÞÔùk,JñFý EÂôU~ÜZ@CG“çP÷â ý<7휥ÃÏ ÑÜIôºd!š²�—×9àÑ÷Oïí‚›3È=î+^›íŒ“¦ÓMá.ºßÔÇYÿìÌlX‚¬ÊwÁåÇTIÊñåÐøÃ”£4R¿ûZ´fúflO–§'?Š Ó:,¼ÖÃqù´ò5uÊ\¿ç±pa¼#>\7��8rïcùzón4ÙrWHiUcÃâE°0oZþö¡7}~Caç5a�e¾0ÞÿWYf†¦˜ú5òÌ¥Y)ÆÜñuVo¤HÞœ{’n.n…Ÿ£5HA^§¾,å�6aèÇ`®¦Ívgæól«ñ¬õÖëßÜöÅ·{ `¢:Ä}1zü‹†FïƒbÈXô ־ݓrÏá®û$Ú–VPÂÑÏ”R¥ÊS•† ƒ×€–CȬ#�†¯´v Ÿú7:¡’¡*ûFo„©}Eïqéâ.�µ[�PÛ#'„²¹GÎÕT¤ž©›iò%wþËE‡{|Á²5ä,-Á}Š“Aû’-úŒ›IÙoµðFj$LÙÛùÎ/asÀ$¬n¨‚cª'pù JˆîÅ›ß%Ðó´žh¸ç(LÏP†—ú¡¡ÃáÝÊY”³Y›­/Ø—�Ý»—ž?5ÇG¯FÃó�Ý‚{åêÝ ÉçU8Ükˆèsy.r0ÂhçOtS³‚Æ�2%½ >ü¸Wýù<åŸëwƒ´GOÞ5§þþ(+Ì_ Ö/­ha­;9[&d®~ò%0çh�XR&® O„gþ�A¯áéî0ª^"ËãÆ`Þ°ëtnø#p�0Äôoºü´Ø›Æ§øÒ†+cÑ|ø :.ï€O3 ànŠ-ZÙCz¯CiåÖ@6®4�” á⌠žZh�Šªi\²&’*N 3ïßìò¥xkÛU0˜e'õwRVS0�8ˆáEV$_ÕÃÒ¦â€Ï ÂàœYßÑ&AŽGM­ÄÙ£ÑO)0M5àíƒY^E�üÜM%’rAÚ}?¹=8$jÊŠ0u»!.ž=žë�>¤‹ºj¬o«ÂB[ ÊÏ ¬Ì碑B ¥Í=OúKëØÃTìS{ŒŽv\m�IóŸm_é±þY˜g7Š7þ&çByœcr1Âû)ã03©7O´>ú�·ì`1mÆøÊÑìdw‡*n‰M!Óhwçh´ë-zni–”q ý,3d¿Ùæ0Áv yÄ÷c£Vm6JZµï? ð­Ö@VKQy»ŸYM#JÊÎBÏÕ½1~ÿ­ò…�å¢Ý÷+t×Î�oè-ÇìÍ3ñIS¤¥/ÄÇKïJÔz Ö‰‰4L¬šGòyý"ø¤v…4¬�c©¥—·PçÔñ脳ôO,(²>�Ò‚NBÈÏs´aËipi: ËÁxªÏJ¼·��¾ú@¥Wj`ôôLø>J¿xÙÐÖ‡ÊÍ–ôA¯C[ ÷²îÐaé2=ÜÞ;Œt�Τ�“EÒ™Æk—o¡Í*Mb•3 î›—ˆ3‹½ÐIs1M°è¦Ø§7…ëK«ÀòQ‘¸³îdùõà^É9ü[&”Ö{7�º²â#Ãã.åàæÝË8ìv<=}áHähÅÍB“¸ð`ƒ ž•¨®ŸÆZ×ì8³—:Ïz•Æsáéµ5Xe¬Jótæ¡mÂC˜Õ7.Œ=EâûFº)Ý+G¥cõõDÜ&ÙOÉ7RpýÌG4qüàå1øº2¦|´ò8Ç›¢”Ú#±}šŽîpO­2ðsS¦”�-¤4ûšwXÏ_ǵ´—¦"J)Iiˆú~î;%[Ù! [BÊOFK*•’¢I´(‰�­ïç¾+«ŒBDÈÊÞ{§Ïÿç:œsÞ÷ëýº®c*d»B�1G¨Üj ]ðž„À�Øjè,–œ¾*NÿDHì¡È};X[A0r“ðäDx™”Nv]¸fî1€ÛX–3r×óõ–ƒày)K.GïÛƒ8f›�|ŸÎ##·‰'7i «NÄgSM…)ª´ª)Õ£²ø¿Íåxø®w_*]ãç®…ÂF4þôÈÁ_çqø(|+ðЂHü¹j}É$Ê=ªáf½>‰/Þ¶ç“�hüùåxá²:º¿JÇîÑg-o{¬úéŠ2»cAZh%oªƒ_lùÖ»ûÔKn*ghݤ²Ç±$3k [Z(âø'9°Ü‰Ÿ`6Øìÿ-®qPÅ[GÓÔÏÁT�{5œ9âÔ*j)Kb° Þª‹æÒúò:>šz÷Jƒüž†èk¿ }ŽZÀ¨c¹ÜÑG ;„ÃÁþ¦Öx>ßvàÇö#ñìîCÒÛæªð®ø(E¼�ÃÁGFS¸D–3• L-šZ÷Ó俦œlw†«ì UåÁ($á)ºë C¶êÔŠÑaÏQàYý÷QÍ ]zk¦„{’±*w$M‹ÔáeùÞ_ñ†t"ðÐâÏ ð`çÜNââñÉtךÇo|ujrþ@²;r�VKzÁ¯ø\_Õ³ÄéîÜviÇäÒµ[¢´È∎^ ?Ò4ñþêP6;Ý‹n½3^ù.�­³¤¶ÔHˆHªWKe¾öÇŠ®YP42 Î+àáï;ÄY|Z¨ß ÒÌ#èUû”.+­Î‰_K#É'ȉԮ<…6ý�Ôvµî³“‚Ö bg3µÔ5ðŸ@ zx/%„Ùq¿ub›(Áã”q’eÉv�ÿ›ŒÝ ´9=yŒ¨c¬‚.ç'`[̬͛Ì÷f­¥QYkéA{ :�PÃÜ€�¼¯ÎGöH‚Î~hVö�U“ñþé÷d*ëÁçïVRí¼á<~ë41ù¼N¸º�“*žòŸS4óÐ0^äY+>©IöØdÃrÓ4~tg�I”A�]“ØíË[i¦�ßT\Å”8ެ7Ͷl¾—7‚¿þMƒ=Yð[ÎjÎ]4‰Ž­)€�9›…û¿°ªÀTÌó.Àm#X®ù€˜¤‰Vº­œ¸ÆMÿuöaâ+p­·„þë§Ò²,Yr‘Ü¢v‚ÿç¤3±zúL4]=—Ë;ÛP´ Dñª*&›=¡n?’–R,-xñVÿ›c6£¶‹.rS°Û4G¿c0T®…ì¦ö£Íá§éYK¾Hž †×-b•õZ¼xªf.© CÞ¡’Á‡¸ßé\¼ 1s¢9úÎQZ ž ø«OAÃ>p#S›­Û=¥ñ¯E8ä.ÌhõÂz{qÑ…s�„ï§\þu©É Û¼´Ÿé£®ò0Ýþž×éf‘‚–þ.<ëÜÀ�Ý^xmíê<¢Çšzÿ|ÜX�—[ʲ§ý ˜·n É{zòg]ú(j¢rßÔt;Œ+MMheñq—¢¢›Ž{1lúqžþþ„õ펓N¯ÆÇ|ÎwcëK‹ÄñË÷cÅEúüu­ ñà²tõ‹nØZ»“{ž¼Oé;`¤Z9Q£ò cè¥â#Êx$@R·28^cáNú¬ŸñWÌjz)üÚ[Kz`E•!¤'ŸÁÍS½©Qï"͈.%c3®˜÷ï=¶vã—Wz@À/{<þ÷¯Ô$§;I|&ã+Ì€Ì˽৚"õ¬ø�ëä°�7 ÞËÇK~]Õ&oƒ]Ô,§„çŽÉpus�89b<ÿãHnF=¸îé’Ëï „Ëæ$LúÝI/ü*„\'œ[”Fà£0¢ÎŠýNÞå’6Ø�R)înn&ëÇ;!ã›~Òþ�to?¥MtÂ’Ø´6‡ßŽØ€É¼¥zÐÔ7\þ´‹�Ê�Yµ>ƒ1¿ï=ˆs׿h³ûpHØÅ#^6‰}ÛCÙäŒÚ»Ý-~CH­#Ë>ÛG…ž98ú£5*ºáˆêVè7ü®_éŒošxJÀTxôë‚K£šÁ’˜¢®Æã²Íð�^4}ËK¢gû !lºoµ€G�ËÄ)�"èúÕ‘XT~�:Ž7 mqxì±2íVn£a50pf>¾yqD\ZÎ÷V¿…üªTÌ»2Uk–PN¨÷‰°ÀÃTCk‚s%ã9Ep”ÛÅŽ6’®Y7Þ¬aG›ý “;Ûhððɘ4¾Tüþ¤/‡î !ký}‚I·¹dð$žVFõEùæ7hñ:�”fZAè9OÖ™²FL¾÷�C†Ô`FB×y‰XúÄm-wà9­¼hÙFvh›#™ï·šWGÌ¢-Óó9¬Þ�è÷ahÕá9ó§Bºy£Økp3UвøYª‹1õ-B|õF!¥né0#‡ÃãØLµ‘Þ—n%í¢mèŽ%ª\Óï )颊yeÂw¥Ù|ñêA>f×�´†ksQE6¶©êPÚ«}ÜÙÛ†“ïË–�dÕY9œ£á€CùS¦;„ 5öÿ$¡f4F÷!@=ãMŸ=–�I¬PNº](Í çóÙ}xjÑT¨3j�úc ,wí1�uèÇ(qøàH¨ÓÆäÑÃÅ+÷´QÕiu<F_YÊ�ZnÜrý))~Ü ߞб9‡÷`� Ró¯[às� Y8€þ»¹��¶‰dôÇûìPÅI‡Ö1“ÁÐ=Šè¿}žõ0ĽQ/)Ýã�ôL¡&)ËæJÔ“î‘“›-œ¤÷^˜XÔæËÁ¸fó™'D‡µW ÒÕÖ­¾ Q™Šbpº·«Bäpìp˜Æ7‚RaÖiÒØ`�í‰èû³×¥�É¥‘-ýPyªÍWs¤ã2!Å5Žu&öG±:…ì‹0ÄÂsµqùç=¯—„ã Ñ'j=‰h'§6æžO4¹þÂO�i€SçÁóùJÁ°îµ´eP“`?±‹:s¦£óµoÐ0�ZBþuï<|*ïˆJÝaå˜?4G3D¿ý.¦zbüx©x²ô¼�Ö¥ð�×ÁÀä+MÊŽ¯±–â³G2úñ/¸X¤ÓÅÎ` Í(%óv¬¹ü¾fõéþxoãfJ­E´>ÂWlNQà±hRªÍoü'zY@ÕoQ4såþp, }þÃ{u ÀyNŒxê�ˆz6¼<ö+%?î�$¯•ÐñÞ5#�¾øÐstˆëy™á}pH(ÃÂs÷¡ûÇÞ,ÕÀ½Õ/…ùýò¸Öé+Èyè Yo]¸™¿Š+µçCëë%t¿ù£¨¿sŽÐ‚EÕëxí kE½�[‹rárn×ûuÑ›>3!fE¾äÖ}‰`±õ6nÊ€çs ²ÏQT)Z„;&PÒ( Ó8"z܆~~X]9÷õþ {IGYrǽɂǖJЙSJ ƒoÀwß‹Pï+‹.Íãé|ïVzöÞ–gõ}ºs\°Wÿ5ô´öT Çð´$^.’Êe|>ä¸5ä€Ú¯w ›7‘?×�hv{+^lqÂMæÎô̘–\íŽt¯€ÚíÜ0Év“Pò({õ*¥ÿ}¤¨E”áº6Ììû[Y°NÌ… �—èf"Ãh8jNßÛÏMæ›3†£ËŽkBÑ�¯�=c\ÉYÆõ6·ª�tôÙL=…Òëåa™¯)ëè°»�¶µ›ÛŠºÅl M C]ðTóýòÛÃʹÁ¨³m¨Åøc/ÿ¾¸)«\x®YOéëúsÞ›ÁPrU ‘¡Eæ<@Rôê°ØU|„*OéàäÈ0e÷%Aw† ¤7l€¦—3*ŽBÁ ä««nŠÝe’ùpo'|Órn¿¬€Ä?Þ`q£R¸¾òÙl÷À¡‹Ÿ‹cþØàVå|ÖÈßG²îÓþ¹Y±ßÆ3šv‘y ×~è‚…ä9kÒAÐïÌÅi¯†ðhÇ\ÖíZ ÔÝ®†ÎÆø ÀÝozÃHoXèÜ“WΫ/o®-]EïÎäm·Ò+U1ê³ä¬ÜfÔYÕ? ùcîOÚ™šNËB4yêW>1s%âÞ|53׿– ]ÖèBß³›¨Ö@-�w€Ûá�°vçpnÌ!ÿì.‰\*`Tëˆ_êÍõQÇ(Zo)ëŸ{#D'úð%QøÞ¼VÐ7:HC'xó’]òâ%1W©8A÷ONXúÊdS¡lk*¾˱2áÔ¬.ƒê7"Ñ~æ\ ~‡S/Ÿ§ÑÁ�a—¯<º™"ÓðI(ž67ô«—~nÅ¥½—Km6ec‚r™ ñ-V9O#®ÄÒ8¹á�¤]YÐH·•×Ñh(^’G%½¯À⥣`¹S Œª°dçÂÖâÝô(Ýþô�ŽJá�ÇjxJ3ÇÎÁÇQãÑ|µ{¦n'û ©4qÁÊ—¦âߨABÉÚ=¸û’6Ô¦‡ÖGñ(Ÿ¢Œ—¬]ùäœ$´ë)rŸc ´ÏÕͨ¦3û/ _îÕÐ/áìdeôø‘HS¶Bß� n°…Çè�熯æA'Íq]~öTçF ¢•j|þÔØ†âÐwp3dƒàý<ÅÐH¸qãß§ ð\u¾‹A«UüQµj> N—ç†�Ò]ŠF¸?n Ì~<J'KG­�½ ÉÔÿÑCj×ÐÄ‚yWíâŒ,‚ÊùÓ„™Ï5±÷ÔBOØûÙ›Öš³Â”ñ\b¥Ìo}Y\4Û�ù Y®"º4r¿`Ô—?~ŒÄ›Vàö ÇaòBOŒø#«È@=Ï)\=z‰dK³3¿û¥ÇQú™°Ùrn3Ý�c�%´éÓ…êÆ'•v¿ ̶êñ­ýámþ~Žnɧý±kpÅăiûð–†Û­¤äU[ÄŽný„S* o–÷Ï ¿/î£1�¦A ç,«‰Üñ¿Ì�Má”Û¸yH«0 +µÏ–±žUwöè:,º9ƒå»~S€Éì·{³.vÃÕ+_é¤ièj\Ä«<…SVŸaCÊeøØ–L™Oÿ�O£FÜïÁ¹'ÊÙ"]c/iàí0,ÚWhŽ:VŠs¤Œ5OÑ¢õæÌ]WèäÚÑÀµúôòœjÅž£¯³Ê¨zj)ôr‰=¶�û¿‡¹±ÑrloÐÅ„vɀ߱¢îÇ¡<_wZYÔÂÏ?Á]Ò Ÿ}fÿä5�§b\Q&çþw„äBã°]³î8%´W*‹»öF“OÔ2êéׇÿcë�Ë©àIÿRÛŒŠ7%œo¾�<³zá¾$Js¾DºææÒg5;I1b îZ_'»p’*àeŸ—°bí'È4»†Û¦dA¤ä ùÆ¢‰Ò!ø]®Š£rGÀšÍªÂªç}ñxr!Ö'§BsP(üÐM8¡-+éº:‘®Íqã{3ôùÙÔ³´æ©"'OÛ.þ}§Äãݶ‘Ž‹1„hÊp~³uϸ®êƒøQË/|úá„Øé¶˜Þ½B¡Ó¿]z× '}—êMp„¶Ü8ìß¹7k¿ ­[é§ �á£EWÈöÍ$Ñ2ð1-xv„®Dûa¶ÿ.ÁuþV YÅ׃Ès»ÙL3À°‘'©× Õ®iµyä×ÙJ†ERáàDthŠ0v}w¼4õ’°crŒpgv ¼Ú§I'‹û°õý‹ÐE^('?W°b>ÝŠJÀ#Ra¾Ær“? «š#¡9'�íqTÄ5A£íê òß[ØßÔNËmùÍø�}e=ù­)½{¤ãfLæ’ÔˆêãS«²Ä�_(ÞÆ‡_$x°az|þN´X2¾É.Æ�…ÝøÛÊ…œ¬5ˆ*?‡yŠ2=à�èÖ#Nª¬ž�§u3x.ª{'¶/‘ácÇñÃÛ^4äå;*»ì Y' Å·ý§àÙÒx68>‘úÕ¦?I3¨l…¿J?HïηŠ{+b…½J9Â9YÛ½žó§›q­V!e–ÃÑ9Û(»:®Ú x耷ÿgM7û®‡ûß\áæqþïéi˜°ŸK.;¹ØÞNÀçþ›„1QøŽËHÛDÛ[�Gyér®¥»*¡/±9Bé¹)X5ö±èõ¡£Úbí¨wì ÎVüãÁ ®tÓ§ôöÁ誣(¤ygÐ%§Á˜±)Ž_놵K±Ÿ_oœtÔ›69 x©Ó?6|¢R}cÁùc(•ÿÚ„Õ»OÑÂhŠO¼•Ì>ó"øŒ�'êÙöååEéÒ“ka–ö¸nâM3Êðð³ μøAò5-]�URh�>v]—£–Þñ$3y&ÿ8厮cDÝí¥\3»ï[·ŒšŽôâŽ3i€0ƒÇl™�j¥g(ÆQ›GÜ 8%ë™0øp�t©GÝ?ÙÎK ·Î¤ÒÆ\Ü¿± c´‰þ¼8-I¹²Ž6Ș dô±-¼Œ|kù}�DžWb�õ^ Âk«d´v9 �… ©ÑD)è÷�Ó³1þÆz.SüLCoןzA*»r¹ÜÖ[lH]Ë÷»;cσI0Qö©Ë1+_#yù÷t`Ú™õPP'vTƒ¥‡ (^Ê€¯?÷CGxGϩąˆ‡¦ÿ¥.èïé�»¥´è‹ƒO9ãßã�ÜoÃdÉá~7i³NwÜGr™ª†ÃÞФ…“Àáél¬T­…9å]â|=ÜÇEl–5Á…3�A¨_ů½ö ‡.k²ò{¼qý>ýM´&óÑ'I{ÖHö)”¿É û³r¥]¹(Íö—¹÷CõC}Ù/p:›ÑX(Ç)ÿö+³Tˆkwc?›#0ªß/±è‹ äg±yÃP|2t3ôÂJ–K:uÜð‹|JV¼!‹y8dT˜›ÏÙž~Øó²˜dZq D6}3ÁàË<:3®ƒ_Nk‚MUÓÈñú ê™ g7ߦª[¹W°.ïþåËŠ?¨.s/}æÉ×S(k‹T=¾Aò£ÿãä±ß¨ôÉ\8vp,^Sð�Š5}}vKñÛkåÐãïÿ‘V½+N”„câž•àõm1—Ü» ÝGÑÇ Cñ€ò7Ú³ƒFD%SV«-ž<šN[á ½ž³žÒŸWpɳáÉ�;ðç¼4þL³ÚCøêð;ìVLsý|ùÍ„™èun&¬¥Y›©ûÌq8Ls.Ü]g�?RIæÓ@qÈ!y²(§®üÇôÓd+DneÉ×Áغ¯‰ô.&PÕ­ùØÙÁÂ@/%Þå•CÏl·Ã[ßD©Ùžo–lÉ×6w‘k˜ dkŸÀ½Íž¬¶t$NœÚÌâÃ+û½Rk}}²œ�ð·Ì*.-…Ÿ³Tõù �jI‡§;ßÙ�øÏ³FM|N˺=Ó®H¸Hz�Oæ^£ã>¬zKÀ³ªaB”±u´�ÀÃ!"tþ¥q6üõðL»¨Á.‚'©­%çYyQù2¤°¼[ÂkÙ§°rV3ÝsÈeù�ßèKÄX¼°@ÒwK[lIây2O(gÈgéUÿ7äzÔc™!iDSþrs,É.ÀùÞ~(Û£çÐ� caÂéè¶N‰»w fN­�”ìµAÏ|'U& …²Œ#£ï†<KT-Ynk8%­¦ÌƒW±[g"†(�õY�PºR„¯ÈKË�ÙÐ]À•PŽ#½?’Ô9FÔ$¢ú¢¹bŠÿ:¸m4œ—Ÿ¶§êÐùÐdõŒÔ hÁóZZèŒcÏ«ñ Á�öÊÁ½zÒ÷¸J+§ ŒBSÅ‹=y“_ á5}ü Ð.éy_"ù”½ÆUÂé�¼çÈPxââÆZZ(®™ÈÃwÌO7Ž�îo"Xãõ"®É3Áé÷,Ñl—È?Ñâ—_EÔÊÓg‡Fk^Ö*‹“´øúóL¨×Ü ýö�>2‹Ôíì<�‚¡g0àò1V“ÃäÌ)x¹×;z7í�°qæRÒÖœEÞé°üßùþáÀ’›A¡ø(„ÏQŽ7½iïÁ2¡'š»K½¶ÿ„šö¼§ŽT‚Ì9¿èªïÜ-,ÞêšÃ·Ü˜ƒ%}úð%ëMꩇ*³ò© è€88½º­½ 'Tÿ͹ΗÒ}c9êçOŠPÓu}¼% T”(Tψ'õH†àÍZâ}73|»i9äÉxc‡^ Xý©úçmæÔóú2¸ó’ARÿN0RTpßäí�ó.®ß¯ ü»JØ[ÖÒJs¨2y&—z#λÛAm’7Š�!#Ú�GÅãk³N8åïKË÷ üÕ0‡– 盿ûá6£-t¶bœxr¦š—‹`õkÈöá»o›Ùl¥~‰IÝãiͺøý­:ÝØT qƒ-(ïвܔFϴdz—ò,Þ)Ó‹•CË0Öë $¤9f“°~öÒRÂí§oÚ§âÞ0-¼3ÉŒtÅr! ¦£&çüE&õðÊ2k7NøS±™oüéMÒsq{ç.üVÛ Ý'Cå÷ÍâÛS£ð¢ùg¨xå͚ɳØ[Ò ~{`–®®ð@–àë½p¿d³è4UžS0Gÿ0|ŠÆ«?ÔÙb‰�[Ë`ËNÑ!"—ö]O U%+ÈbÕe6ji @ï T?¬ v”¼eú0¤Î¿+‰ îÉ)woüë©7ÉÌ¢LÍóAvÝ@ò²Ù ‡×IIïN=Ç›Ì|/œ•è×ô…àÄmp@¥2·oå¢B%níš�µõ9©~67{Úã±Á 0d‰þ|öfe¾%£3`ÑÑA˜ÐÍöþ�ä?…p“ÂÁCØ5ô·¨pî0d?:oóø°ÿ#B,ê«Æ #–®†;¡‹xQb:+ÝIsÏ?Î*yr·.øTnœ÷„ëÓÁd×9ŠÎ>N}–��Ïy|oS8vk Z?!L¸;—�ñ“M7âì'£ñåoP*°‚&Õ�ôòÎb¿§º·EO¶ü¶ó0KØ×D´’(r°&ó  ¼TV<”§4PSp>”Ä&BYâE2/ 7þlã5Çæ•}öòagüb2W},ÖÄ<¤s]r蓈»þÆáöügTu/Ql˜gHû#Û`ã>Y-–“0ß�:'.€i!Óм#@Rq@ííÝP7Yd r£ãާ§ØqAÆaJfÉ}v­‚´è¾:£Â#ŒÈZ"ÏÎò¶÷ÿ¿Ù'{àXaßkm¢õú®Ñýß~”În_{ctr–Pû1G¿¿/® šÈQ¾ó°×KsöúòAX³E‘k 3¸ïç!Ôôé-r[‰¶[àõž+”^ÿìïϓ穣‹ósŠ©ìÆ)Åg(¤úªP­°J2øÄRVŸÖ@ÏfÛ°çYö²[üÕb‚ú^ŽàR}€¯~ÿ ÅF‚ÊÝx¼ü¦/_½²¦Îr¦t0mÓxœð!•÷õ`‡€(°þçâãß”Á÷åóØi ïª™†}ÌÅ´›¹´FÞŽKž äGÞ&4ôÁ>ŽZ˜.ĆNÁsÊG8jôgqdÝY1=µ�Ç : _ˆ*�]t0z®]VE¶C£À¶g*”|¹KO:Þ’Ý},œìŽ‹¬¾Jƒâª`«�µ-¶� EQó(*¬­ƒ Ñ X´…;³ŒÐqp"µç¾’ÎñùM3–w …~¿!õ° 0ÛëR¡µç}X•ß ‰lÀøÏlîyòA÷ñÔús9üµ/†¹ž²Ã–üëF“2îÀÑ8ž·U¥�z�¶ƒgí1Ë£'Í"6¡?¥ÁÏU×àÎg5ZÙãŽÄzÌ8ÑSãù6-ODKeŽf‹æp‘tëÎÒì7r|9e �ÉØ §¦…ñÔ÷wéVEWkX�ü‹ý\{=�Ã{¦ð±èш»T`ЛN!jSõ|9 [tÅm™óÀI=�õïVÃv?#*õ¥þ E‘G„fŸFzô7/�¹ n?ö�ù+>90^èy(…"�÷âLÊQ¹.ž}“F�VWèF‘!úñüuR.Ôu<’ÎöQƒ†˜V1t®Tð*'ôŸxÔÏÓèÇ`uO-lÝßD>ª´`N ŒØ¾ŠMƹ<7tûL•9ÅäWjG�hÜ‘$qï/¾T(ÅÙßMpQ•ä¿ß+6®ÅÞËvr}îqãvKZ¨à aj+ -[Žùœ‰±¹õÛIt[2?Û�»TôÄÂßGªb%®[;Aë¯WÍé…·ŽˆE“†sÕê@üÑ“Ï(¯^xg¼—w†Ü÷NÜÇ|+*½ÒC½U(þ™©¿àöè!÷ˆ,ÿÜÓS' A­•®ìûN¡FÛ|z1dœ<]Jç:‚P$Žù0¹2•:Ki¸D }'äÑï’µ8 ûˆ [~¶s$Ù·™<¦m4?È+ ³Ï륓Cþ¹}ž/fÿãë„)Ý�ŽúÈÞ—�õáœâ6˜iº\Ðè5ƒGl™ÈKzA÷"}iô.‘5¾ ‹sD³©¡îŽ„šÙ£0úE0GÝ. Í¥følú`ó#ž[�ÄXŸU�^šÃë§¹ÑÙ_í�þùLÛÛƒçi^Ï­c±ƒwAö¬DÚ}§¦.Ø _ÏŸ¢!Ráõ†—¢Ä@–¦Y-£®£:°ºŸù8ô�ò÷„;ƒ”ðØÅùx^z–Š!’ÚÞàØ¸:(‚Ù°ó€à»¡–FÀ¿ÜÄAgÖ%áø\MÞÿp(?]ÆÁ#u(Iý鎱äÉõ›`v` q\‰« ƒÄüšžx6Û—'ÍÀCQMp[4ÃÄá6äób ýظ–Œ:æSE�LQc` ×9a°n2­Û! rú‚ÃêÖ9<ýKwÖ–HO$¹ð«â>ÌN.mGÝ£)¾è¹n=½6: O�RýBœ³£/ËÄ7SÆ=_P辊žÑ€ÙË’àÔn=©ÓoGHU}°@…!’[u^âÁ®~˜ºƒNÝÒFÓùÖ<}†< .CÄÊÇJ¬�b ŸC,1^³P”ÙÈ ÆÃÂE±p¢t¾¸æ éL�%lv·†G�:ð~øR_‘ƒº-5||¥#ß“›„Æcíhöˆ \°ì ô õ`éýÝ´`I;9Ö¾nYûó˜#2l(³ ÖX«°òª68§¦�ŽKýñZÍiñìÍ~èfh�±»Ïñ§äoàÿ³U¬�xYâÔá†÷wÂß3^({b5}›Ÿ!&;~’{EÒŠÈD¸¶Ö�õGžçÊ|Øš#®çˆÚ�]T^TM¯Íááþd=žüH¢¾v· êÔ\Ü|Qž›MUy•Hš±§>Nƒ†dpZ*‡íKA2×ÊuB¦jp¢½K“ùå·xôø;Ö mí7õDIt«X ¿�&w¾ãfTHõ5fq—Ý«[2Å´ñI!™9öa‹Ã²âéO.`SAÉ«FñÑ£Ý8jŒ3tÑá}ü˜>ÏåÝÖ ¹Ï6YŒrìÅkrÀôót¡Ê”=Ûl°ðÀaÌ~'â–ŠqÛÓ¬¼ÇBhHTOýX}èÁ ˜eµ‰—ß2GÙÛ)´RÅ•nt&‘Qhˆø[$µ­ƒ-ípcò}ПáÊú½éE´þòj3ÿñ¤ÚKFøÔÛW)±Ú øýÆ£µ/�öüjê¾[Wê©ø�}šï'QÖÓÍôŸùÉÕý¦¬\òAzª¥öl;€«*T@=nÔLôÁÖY\§ê�N~ò³–Úbdžu°©ÎioÚ›-ùÑ> QÍcžóõ–C¤ìWÉ—-7ènìœ4rE[=¡A_ì`Ñ(exXóY<½þ3h©Ç¤û¡îV/,*Öo A‹ä‹pî˜ º ó¢w>—Iî})ÿ¼/ƒc†�þN�®]‹„›ë¢ÁP;ŽÿèƒYåZ˜”¹žþJÇDmE0òŽÃsaú�x•:,üÄé2 ì:¼·ý]Ggn�Ç_.V_uš†'¼K¹çê¨b¶Ÿ&„{ñÈŽ) £Ég«“P<Ÿ/‰ñ'¹[Ò �“ä„â+=ðØ¿¼cr†p·/€ýÂZ±Øä¦¸Ãr7.”‘Á^¦Jì¢2G|oôLÐú3–/[Io>�ä3ÔPƵLÚã�%÷l7Æû&â®J9Á¨î‚0¹« ´Îƒˆïš”›§ÎÊ�Ãè¤U®ÜÑ tÏ'Iwü·bl"WNä Ó*Tûé`óA }LjhÅá\plÏ‚»-ž¬|°6ïOfÕ¿G©w¬%-º¶ürÉxÛp V nª›S}ÆʳØ С<7šÎÇR¬¹ïr.UÈE×3¨%¤=ÏÔáÄg­â‹åF¼ãÚ¡ø“l½VÊÿÊ“Uèäëó®Í£Ù7|:Ä4ýcY[»°h`.(÷ÞÅêvz¨`=�î ߈[{Ó‹$}a½]¨©Áòq»'†«„Ίiìóû�0¨°„ƒ #9j$‡Ö; +°Ÿ°j…kôÈ+~©`y¿x~|f—÷`Å·ˆ«õ³U‹Ä7‡¼ÁÿÉmØàd)Îï¦KkÃw²N±”øGŸ°êÅÁA}øPËP욬ÂËèù’M�ûÚ�·Ücèÿî lüzˆŒÓݹÓLž�¯ ª©×„Ì„g’¹Áþ⊙½IÉEg¯îçê”Ó%\ Ú€_šÙ¼0—Z:;©©‡#h×ÄÌþ© Ÿ'ᇋ&%»€â¥é¦1�ò¢?QÎ"}œö,LX¼‰úLZ†3ï‡9¶ôÇÔ‰Ý}ÊiÛ>¦ÙºCè›[ �}!Ã'ú?%Ã0!Ó¹±º¸)•�î!¥ #8÷Þ’ŸÛÝ®¼ý—CyŽÍÛ>c«ÿ¹ít48Ä5)Ã)øë¸{L“ãz®âÂ%7iRp¼Ð=ªCˆì&Çš›6qOŸ*œ§ŽÉ÷e8<}2„ïÔãž·ïÐ&– ƒù;ôPûB‰Ã��\LK÷Ú`ÞoK\°9EÚ)aÚ±å‰øØ¼ -‘e}0 .Ã�ÞƒP«: |÷�>~8 q•æ�¸M¤÷çšQKåŸñ¯Ï!¾xÞÚ§ÝŒ–XIÖSK½£táÖ$ œ¦M�vAâºËöðà%¤N6_ú*’ß¶CÒ©ÝøÍ0k!éísîW4‚¼ÒªíVÝ£»]îxÞtµôS`aï œçiή­”(ó᫽ùÈ—¡ì÷½MÌ_°Ò•2…‰Ó�ùñÅ pX(µ×'ˆ›W]„¶Ð|Þ>ªUlµÝ,,? +~�äXϰ7]ÈaC>�¬�¾�#3GÕÎ’òPÿC°-¶V0^yC¸¹‘"—Æ‘íìïpÊg$~瀅Nº´2N›o™Fpj� OiM&³”`õÚ‘f†ÿ¢Šq‹‘ ÂÚaÅÔ<}=x>IÐlŠçö_/`×î¼»r4{`Í ïO£od9¬4ë–¢)EJmOXõ¢ˆF¦_…–½Üµ#ZšhÐÚlýZsé’¢7Nœ05&®Ç$#=¼T‡};íøKÅ]ñÈæ ®8u_Èk<@G¯vÇ�ZOÁÒñfuÅôÝBdïrÑ×R„ÿb¡ììèÔM!ok œ½WƒÃ¿;�Id‰¸tj<Ý?ï@º×OЂÜ咣߈+d IuŸ ŽK¿A°¼7ÿõ K¾NBËa»Ä]F ñá�fÐ^M6±ÔTŠ?ÚÖƒµª÷¬ò%»„»ÐnŒóV¤ñÉÐÏP™`ÁÙ3\¡°F‘ŽÞ‰kÓ‡ÐÃìÓÂ+,+óľ‹t¸uÓUºfÌã†Úà¬Þçaøƒ-Ø­²�B†‚�ùŒžwJF¿ƒYÓøj\¦ÔïE¥à”ó ´·�£‹z¶xEc'l_¨N\ÿÒn â¹êæf|²?fóûŒ^¬™}N8k¾›÷Wí!Ë#]ÂkkÚÒ—‚z‚!‹ñ¹áþm²‡v*Õñ]¥Ô’W¦eW–Ò}YÄÛ*xçêTYw L6,e…I7à£ãii•W”°pÀðo‹ƒ�Ëè`Ï]`?Ù‘bOî$³¦³÷ÑCÐÙƒ^u …Õ¿t¡ýÞ�þpæÓ‹;…­Ø©'a5¼xõ',N·‡©‰ðvóp’}1Îk©aÂ¥þ°Ó°òž/Ķ´<~/Ä„ÎÙɓø@Aíî‚Cõ9/j5™§šÂäéï©á±29«.–¨<õAS U3Ãâì2±(0“þ‹?ƪÛúº……h£ÈM¶ÏÁ%V\Ã[!ñï~>éźcjiæåYX2+ŒŠ"séÈn]Wój3|<'žOìù 'Ü¿Áà:p-U@–Vqâßwu¾t¥dÈÍzèØv�ZïmÄ0©)Öe ÀÔÊét¥ð3¸Üqfogy¶9ï�ó¢‡á§}èp]1g< …nð [ĶS¾4|¢�0mÝ1Ⱥ©‚«µ¡äIÄÈ]‡mÛ6¤ƒé ê[?3÷·´÷Û(ÎÛèCy?ç¿þxÅ$”OÉ…¬h;~·ôÌ­ËE5Ù{âœÒ�l<Ó•�ÒÄ—ÁÛ¡Ív6ol:®ßMÅ¢ÅùÕtyê‚,qóÜòH›� < ¡—ÿZ>Wý‰n‘ ÆZIpóB�xz»5G¾êÃ&—mÑÿc¾ÔßÒ‹r–³³ÃìÂaúi‡ìÁ/'¦ Ç?_¿1MGlÑ«qÕ+ÚˆÉÙýyÝâ}Âôz5ôéP‡Oêv0¥Ï,È5Äk…*¼ì–w„NÚΣÎÔtä— 8÷š)Ìs¤)½Kqƒ|4° Ü^­Â: Šp´ œ�/˜°bq±¬ÅÕ�ý¢ÑáÄ_ÁO]Ÿµ®ƒr³£4h{"Oןïï\�QÇÕx¦íUVå‰pgýM˜sÛ€Îø÷`}ål¡�œh™ñuY³”Â6tÐïõ¼\' òrIHÌïÖ> º»ÊðÂõ˜Øö‚ù^ú¸Ú¨/^rF(Ì �?à5U—%A‹’àœI||VGÛ«{’Óåaùî=°ëékŠVù.x}¤Qùf<Ù%®ºÓbjjÅ ÃôtÁHx@%X¾}$_ÔÚG‰�ÒhŒk=~xàÈ?¾oæµñdb)¥Hh¬Õ5ñ»ÛQrV*ƒ“2Üqi„<Î V—i±¸n7_zcC9’˜°üµ5“ªûöà¼%Ëèö¶‘læAóàÎõiÔžaÌkøà¥‡y¨:.¢ ’àll"KìWѶð¶ê¬÷Ëh¥]»¼ø&…hÁ;SÒ04mmÒñûOáÅÑ ¾³&K8~x'Ýçµã%z…+°»®ßVW€¡·fð¹ŠB(;íDGvÕË9?šöI!¿þªð~âºpú<¥%„Àk­�Ù‹a“�Ùöà±”m#O€hƒ¢}Ô!TC^ÙO‹bƒiaàa²I.ÎYý]èÌ=‘§äp•êCQ:x6ŒäÊÕ W@¿-ïÅñ¥ÀÏ7àÛ¥ 55g2h_µ©x¶ÞE¬-ïÉ£ò³ OÅÚ×;ñ’� VÏQfƒßhtA»´-#|±Ï3ĨmgIÑ£KÒ/&™Vï¾C¶ÇsY>Ïמs$ÓGi?WŠE{HeÎKpò‰¦…¨fŒ *ò$óB1}ô]pR�B;Õ�ÐÐãùnÍ Í²©l8¿V¢þ¢ ¨/äÁºÚ¸xzw©žš&/Üý_ $•§YðyY*ªïŒå«‡J!©}ßö±À‘ÁÛp÷´Bj=QjIàì•¡ÆÆüSå œ©†ïNņaJ|ÿ“~š®D�‹âqâƒyähÍîé:Ò…6⨷zPÜKTÖ;�­VhwQ‡«KW±šLoVÜ0˜3r=ðæün(óq¯ñ1Û°dÈÓ™Ëön¡¬‡?ÄÚ€&È¿Zœœ §YCé±Z¡aÒWÒ³øRÃXîùLœ%Ámƒ‚ÉÑCÃú ÀµÃ-ðUL/m>—Ÿ”D–Íe�áGùk’æ¿ö^÷öâ¬è �ÕšÇ�òH)|Ù’foÖ²Ià¿îªÞ ·5{àÜ”a0W¯�~Ä¡ãû|±ìênì={"ÌŠuÄK�¹`|p7¾=vR2»ñ¬»7M/„+Å£¤zO†ã® 2§LŒ?®�_Êí¸1z2ĦUqQ“%7„»^Ø‘Å`w PÙ$¼þúƒÊ=ôù{Ùhê¼U…ýmÜȬü™�Ñ¢þgRy×Þž­�¿{Ëâ™Ú&÷h+œ·s¡‡K{�_…:Œ?ÒÐäî¶È&e„²äÏG¡Oàè«ý TÊà^_ *|HǰÚaù‚ìüiCÏbè3ó™ðln=9MíŽi‹æÂUõçB= ªÉ“!ÿÔIœK¬ëxµƒ=ɱä¿WEAMf£`»ù1é QÃíjKØÝ͘M&÷ÇÕÊy€åo ÿÞMñ÷Þ$zx­;δdý“&ë@§&¸¢�çB”úÏ–\�"±îÄfŽ=nšn!Õ×ÃA2µ´’ãOwßÒM÷t‘©޾�‰ÑJ�aOù}x¡#µô÷ƒjóÙnüsÚ~(Ç:˜ðØâG`ëðÒ|ÕÄó§3hDq?Iï…EUÝXÞp%v]ræµ?µáQÿ‰œÑ:o†ö‡)¯×ƒ¬‘»ø~I4‰5‚åp�ÿNØŽËÇò‘î˜:ñ2´ p¹š=O½ßFƒ?w E›]°þÌ/Ñ7Ë„îœþFðx4y´ÔSÛNyšÁ^¦‰d÷¢‘‡GÁ„yÄçµÑ+ó ȯÐá¹çpÞÒî8sšˆoTeðbè*örÓ�ÉöUËè„sþÐH¬ŠÞÎÅ`Ûí¬©ùK knŠi‡<Ь*.-XÆŸV­1Ý[!¡A…�M^Ò˜{Öðàg% ÙžÒ" é‡Yâ­)Á¼Á²'Ê«`ìC]x…/ï¹°ÔkßÓúJ!{Á¦ÛRl³‰kjÚ—›ðzEÜZ;‰vlú&Ú.±”l[„½N#\¹“CÖ®Øþw-)œÉ~lLæwß‘âÖÎÅO½àzª9û™•ÒÑ>Á¢vLäßÑÁMË9ë@oþÕçM7Æup²«êT>�=‚È}Œ"�6¢eç.zø–~üs—æýåä¼™{šèÀ´Sâ®á„56º¬ÚæÉŸ> û+5ln1á/݃U–±ÌKe:‘<‹ÿkJ›N„Å»¨<¤� ëRÃrm´¼Ü"U²�ÒdÃ2áG{uÍQÁW¿ÂÈ")´òoаàpÐØ©ÅûÚEwgðÒ”çÐÚ üùæ-Ôo˜ÄtÂáÎü¾þt)hpò¦ 𨎕Ûp0Ï>mÓĵÖb³ì!áÉ´v:çp„ÞqWÞã­AÇñùžÎ�4“�Ϊ¢L5oð °BN·¸U ßÓâÐZ©/¯ÉšÆ�¦+pB-`Ú¸?ô}çK!!¡vZÇRŠèNÎ�ù`+ÝO;.œ‡o'•8îi)/5i¡{òQûë¤:q8ßëã%<_}EèûÄ m7°ßåâÌ[š\u®{�qàqˆWÉ ŽY¦èûp?+Oxû7ÍN ÅßÝMÞ婬P}ÒÛ‘“×Î…ê³10H?fçÛrÂþ³(«{ôæûΡô÷Þ oëÇ/fŒîÑ#yê•ñá½ÏoÐ�ÒÃôÓß?|ø ›÷ÏÅ!+[ið3k°ÝÛ¯Ç൵%_SʽÕ.fF0vëëˆ�i¬4ájìÛO³‡žÄ9Ë Ðy4àÇi¢ò”ècgón|“¸?«¥CFAø$ø$u«0t±Ü¥#ú:®À©Ÿ–ðÒ¿êüæm '^°àG*!ø½ß[ÊúàÁB€<[Ý7ÁÚd5ŒON§˜ï/àëžõ‚cfÚO’Rà�~¼,`-àÿQtÞÿ\m/«²fV”dµ�|Þ×E)¥´ ß %•ö"Ù¡‘ŠJ >ïë"‘%*i)í=5(ÝÝÿÁyœëu^çùüåœ}¨?w1ê—á®?™¤ò¶ö™ïà�Ê?„ÆÑbLý+úöw ·x\¥Œ²¸úŸY׈§eªÉÅO�†Å€úµñ�ª`H†˜á¯³õÂýæ2qmL"ž¤ÉÕ :åwçiá‘ö é0{ljZÇ8HewK==‚p­™V>Ú#½jò‡&î¯n?´Åœ† é¸åJèí~˜¤'¯À‚ð ä¹ÃŠ·,Î"Ã…Ö3I}Ÿ@ sÍxümuJ_G3ì3A¾Â�’Ò†Ò³ž¯Å ·ãp¢óu>W™ÁûjãÁu¦Þ žÂ‰ ÝÙ1èŒ õá¶Eî¸1_‹¢3È[ý«à6é0üµ’Á!q _¦/ö13�à¹-ÒKÆ•—L3 æÏJ4l’+®¶*…nÏô9eú!¶f¬=“ÎGF%ò�Me¤4çªP°ÌÆ)Þ¤œ[ѰoÝØ ôú·w^+õø"ÇÖf‡ cØaØ<¢€ø‡ �Þ¬ò_±N²öNõ…š¿ã8Fu'·†)B°¥!?ê6™ ^Þ~ÿª‡ê‰¦X°�4ßI¡ÜÔ._¨¡ÏÑÂÌÖ#äžû†{†àöuž‚d€&ê½±¬¸~}!OWîΡ‡ßÂ�ÝÀx“˶ ±¾gaïÝ?Ò�10Úr¸{O¬gaÝ��¤mY ÍÆ¸¥dj)÷çE~F¸+ÖT¸µ1ü¼MhÐùéøëK¶´ä”,+.í‡-+-�(–Þ,=Á^g�Y«ñ )tõÆMÎUâŠ+ŠO.‡‰ËÎRgÿ3ܰì.$ÇÚñwÉKˆNê�f»*±QéÞωæÜÛÞp1m=Ò›�mƒ@³ ‡_ê[(°Wƒ0ø*�¿Âl°¸Ú!WÓUôï9 ,Ô¸A±›Ðtf36¯(!ïòÍwwÄLÉþã;µ\›Å�¼`Zöu&Ó4â•kcàIÛ#Šžõ œ/ý%Å·¡l…E‹�ææ ÃKð © ø=,„^çsèÀšX>2 æ}²¦Wk`©¹”Ž7ìÆeÁZ| M Omˆ²ÓBy�¸KÔ—äàž›»0óÂQ2øØmn´QÿéG!@,Ú_ƒ±Ah’2ë†ÓVþÅ;O¼£÷ Å ¢Á˜9¤'?^89A„Æ=ËX /�ñÙe¨b\õIx¨ÿXaÍáÁÞ<²rÞ†³î K7°nB i¯É9S¶ÃT½0:ëÏn Ùrà]q½âQ6ë1’}»y ³V¾ìªUq]·Z”êŽ énm þŸ'.‹Ù‹fÝñè�+Bƺª”|Õ³ z–î€ײi{ÆŽh/€Ô?k‘o¯Ão’�øÓÄL·ô¢:á#�3šŠa«öð¯ü¿´hY9œ<7ˆ;ÊpÝEš¤ùž%MGW! O1iHà΂îŽk”áKQ/îåN�†ÂÑOêhþ1Fh‹ÇváIØœøŠä­�¨+6Ž>Å^[óhÖÚÕ´±~64ü˜À–Ë"øÝà»Ò´Ý“xÃïÐX ³&ƉUë¯Ò•ÄLú~ö ](޶RÁ„€9âK™P|3YA\Ê)‰²`pí�]ˆæ½!��ã…�O4@X>]¿Oâ2‡^¸þÜdaµ\8Tþ˜ÂÍJ±áhM»$Ö‡�¡Z™xÖªaJ6ü7>D,Ó5 tž�a®šä¥§ÏçoïF«ÖX2ì­ nW)¡ÜSµBì1ðèÏBPs쀚èz2Ϫ`›ýס°NVöŇ�3ã`¡|v…QŽ*lø£”ªâ ùáð3¼Q+këz‰§º{±JòT1φÝ" ºS—tK*O„–Ý6�¡¹êf¬¡ ³z%ós‹,l^G¬šm�¡åy§ä¬)4¼=3hÀu{ºÿWžßoNı!ïYï(ƒo¶ÝƒëäyÛ6 v,)IÚ�M¨\Lj¾ÛÝgggÒ5ïuâL™°ÿ¿eÁÚ ö ß”6ÉÙáhýxe˜3W?|§|œ®93n*Òþšd¾¦’)Üh›Žü5L„„·)¢×ª‰hmUΫ䩚 ‹m¸ln,ù†Èò:Û&rUŒÅt‰jDÑ�¯/Å»ã�œþ�ÚgQ "“Ayt|ø5ü©��ýn-EIýH 0˜À¹ß&ˆ.ѩ«t˜þñ¸µÞнL"ßwÊøêÊ¿=ZñîߌºÄœþ;ènönéTï±<ÕÏ„ŽŒà‹f]”±H•ý†kÓý¨#¼¾í(8žܤ³‚~*ëàY—bñºªùè;¯<ø°·=°íƒ‹_ü€ÍÐW]tà‚*erRô”¾Ü­OŸÖt?ÊÞI‰äý"6M�îÑÑ‚C.Ï*˜ÁöqDÝ!àþD¶ �‹Vç¬ײë0ÊÉÅÈZ¡æg3¨Ù¯ÅRµ§töX;mÏ—L´Ðm¶Ót¥nñ{0ôȘ‰£¯ÇñïÞè‰Ê.1¦“hÚ„s°fj>~?wWÆ'�³¹±Ñ�Š ºóíJÊ— åUÓ<…Ó¦*l*AÁ‡åBA_w:¤>÷¶’ŒÖa0l�`ÿM¸ÓÑ�ë& áW�;Ä_/I»ÆâÞ müýu>7ÌžŠ¶Ûñ˜ˆ°kñkº¦Pų/²“�@våÁ·Å4EÊ^—Èjã·‰½¿–Ðæ ìÚÛnj%’/2ŠX{w>.]Hyþ ýNkjð¶E¼:d"öVõâÇF±å@áh œõŽT6ÊáÐNwÖ[? Ç-+@Ï‘ž¸ß³�êÍo‰ÿX½R1ÌŽA=õ…P¨}W4ÒX÷ÑÒRwù¿ÝÄß! Xñ¾/´­£›6ýùt{\xž%h¢ú¼¼$®/¾œq=[ÌP{»3ø<£¾c‡ˆ®Àã^çJ/N=BÁñ �>¡Q� 9 %¯Ærðïápû`ø'÷á›+ípY‹•½#ùcS©c¼:ÎÜÞBɳ  ×�Þxý´<_è°MïÍ·L—öJ@|w” ý�(kÙ ®óȧèb�Ï5ÇÂ'+1hf½˜<­J¬zrOFåsÝ›Áœ2'ФB¸x¾Â?<ø 6Iª© ÿåO�÷Dâæ’ÿ(x‹„ÏE&¡Ìˆ p¡`÷³±'¿Oþ0#ÏâdŸ’\ú¨s½ê±w„³—Õ¡êÜsú9hG¬ðBÏñ„9Ë©2µƒŸØó"ë¹¼ËNcš‚þ0EXÄ¡òp>dUçá0›hpjX"Ø/™IÆ‘¿Ë? 厵 pë^;Ìó´ÇÆS¡(Ù`JÃGûYòY™½¤ÿYCj³Z ¸À³¨pxM6~6ú•lÝgÀihì)ö*j.Éêä¾�ãŽ9©¶öEEuÃ-Ñ_hΦS¤dlÃ|3àÑý}Ø·ø?ì,o–ì õuPçƒ=å$<ìG&þÙ�‰…«ñ™Ú4ZîjÇ£î ä&·:º÷6ª,²Å5“½pÂÊž¼!- 7v>nìtz¦'ÓÖ²&vóïƒuª*x3í6MÉ¿KôãEOè�3w\þ7‹n’e&R‚8��{æ·‰w(jôwÌêNG:>ÁK¥NPˆ:NÝÒuyZH ìQH£óÄ…í[öÛóåů³x½– m|±äÞ„½9ÁÖNŸgš\°¶½Ý ÍÍ¢áóP^t�¤Ä´ ádÇ5ðåìkàÈWJo |½'Ül×€·�£I&eŒ¸ÉÈŒsÖ¥¢¥Êê á~â@þ™ �öã¿’×¾>âÇk¿(óã�(íƒ †(í…´í�kˆùz6|Ís'{˧Á·™7 Gœ'ºªgB»ÿKÒÚ‹¦¿Œç…{á¤Ñ†¸àþ0:¹É€\ÛÄGìß@ܦ 0³¹Œñö}Q±ýÙŒIå»@.*òeíò(ÖO>Ž«Gà× %ÁuGiã±ç[¥#|cŠYÖ:¼jG“4æÕZº6[Þp†©¹ýq îPœ^ÆKÎgÓ™õ&üõøz¸àœ8öÇÚ'sŠÝ¸ˆtçúó›ñ n4ï„8þ==ñþÁ?ðÁ,šn�}á',8Ͼ‘ŠzünÃÔOóÀå_ÊÙpü ¬Ì: éî´êÒØºû�pÿ² á‰pÌvÜÆý/X’zN f�»*6»“‚3Qܦ>&Š$3À‚Õêû°eK¶KWÂY£ZaˆÚ.™BqeÛé.>…èÏÁÕ×’~ØxþkÃÙðØë>h FE‹t6J‡àêD¾éUKë÷ÓÂøn¬V“Hâ? §ö�Gƒ�Êø¨GO>µé)d�è‰]i¬i-èhks©™ß‹|B5Óº±Î¿|¹¬¡–§azS|XÓDõï·‹G~^ ÔPÐy®:wçï¥Æ…µÂÔoê¶-„.M8âP3tÝý†»ßôfßjx£ý4ŽY KlGðäb31e%Ê�3æroyöâbÜP#ñƒâ*éÔ_'0§W5§Žds“Žü´GáçE:�œA–ƒãý(|9` —¤ñÁJ¼rá||·’‡Ô¡üßùhÞ¥Ïû®¦ð€èÒ .¹—)l—7‡»åЩX¼Ús'ú¨¡{xˆp³Å–ÈË…ÛWLe§6ù¹Êmg×9p^§[öUÛÈÜ¡¿j×RnY+_,áƒ�;at·ñóÆ~¸y‡³�\xB_Eà©-(ÓþUÔÌN' §Ý õsŽÐ ’ŽK+ö0Ɣѓ’tж¹„Ÿ5ÄØ‰ª|ñÆ~Vü5Œ_ë~£wZµ�ß&C^?Ö‹_ÝH…}Q(={ÂGÜ*<ÃÖ’s4Wé5¶®€9ÑÆøúÌXÞ®ë‹AØã^ìñþ²ôÔ«|JÅJ³µ(S^F4ËLÃê!ØðÂl¶Á]*Ýé²÷øºãÅüÇš‡58¿3„\î- ¥U†¬�v€Æ=«ãÒkÓùÍQmèâuhî§À9‰—9ݰ;ÞH ¢’³G àÂ&ÊÝÝ—ïuü…áïú ñÓaि°Du³à1q?zi�sú9ñ%‡ºÐÏ v¶hÀ,ÃD~Ûï2LZ!ƒÃzUñ¥k�pæüXœ½ÑExÐ\Ã.ƾè¡Ñ‹Õ·8ÒRUt¨ž {šª!eå.z”-Rå|UÞ#;–w†pÍXj΃jÛ1\_Ó±÷ØA|;éb‰9~I“£Ï~'ñTúœ�€�í ½¬ëŠÞA–ĆSs7Š9!#À:#•.B ôû{€ïÿh¡[·ÿõÀ‘…P:ð½x­z$:´¸â¶'üe(ò5»hÓ¸@Æ“ßa[ÔuI\öIñôGŸ7ÁØrßÍç-€–²»”¶õ ;tLÆ;c•QX�»¸Ít(ôüoWNñÇççúÒ& 5ò×9�¥êõàb¤ÁSJ°k/WšWiGëGÔˆãª}ØbïyðX³Oð×óÆß²cøeÆyJª±F÷¸äð��-ŠqIV>ܬâ¥Û_Óì¢qÎÿÿå–ë Y¶ö¾”‚ušãÙy£fÅ÷ #\8y0ʘ&«;‹èÆÐ!âç úe׋Sõ~ÂÑÆ 8âàMPô÷_¬­¢ ë ðFYYvŲ‘r3My¿VH&â·tŠJ™ òÖ*Ñÿ²º×gËTi¬#q—Bö]U r}ô°68AÜéž 3¯„á0‡0¸<ô«˜ØB×í{cÆ-cø6Í’bïv‰V—÷ mÂ%l�áwËÁaÍ>Ì^žFѪ2,ÿð0)¼²a…>¡ü6'•ï(šrþÇÕ´ûêúlÐ�6'׉ZÊ9´{tš´§Gt$” UctúPziÓ%úQê�kúÜ�̉ ‘ж|Ðü*õ²¹!áÅ?Ïä CìpÈ4y(î‘Æ�Ý<Ä}“ÖãÛ°|.=¦‡Zçæá³ž«¸wM›Ø±@=YÞþ^�Þ;7Ðø¿ÈU!e�eÕ7¬)1ÑÐ÷F89¿Š_…ÐòWµÂÕ‰#ØÂæ+«öu,Ñù†3=sšOF+qY�½0WÝŸ“mäO}¡ßövÜU1û�/»�ÎmÀ58ݵ1kM¢0YÃc‡úàÍ[aȮ֜«j|w)î¸ Q“¡©\•CÂÔðÕ·èió˜,ëFa¿°¥ë-Ç^ù þ³ŸÃé¤qØ jÄí~1ìÚ»>îãŒq�Á‚å xê‚Ûî÷Ãï<ÐR¿µ<"5ž?˰ÇûžŽ³f'BV=àüKíb æyÑíS,·ç‘ö s<ð-–"=£¸D¥Œw‘\O¿¿¯•âÆ:+ä;ÎôûÎ*|¶¡ „^òœþb:NϦª¥fxlðW!èåiÉ·�k¹¢) ?.OÁÑ{ŸPé¶;Â|ËÔôƺnFÑД\Þ#Nzw—ææEÐíùÓiHWôÀõ�æxlj%/™‹;nãæ¯ÃùàFUX­Å;­P/5›î^¨ç§ßз[W$çõO3öÀ¶ ûa—c>åꎂ‘gàäuŸhÆ`yôšgÎC]ì0àŸOµíËþ�ª|ÈaÜ{Ñ&&™yãËAxÈ%Fý�‡ ëõ˜_DH®.�ãë7kaU¿Rè³8™ß^jÿ{? ÷Àß‚¦Þdn{²ßÍVÆiuœë^ £V|×D©²$f ì¯Ú[–\Ñ*”¾Ñb7•$¡kÏt²[¾G‹�z EÔ\6Ùñt’úRUG(XÏé içŸÑEu¾2ÞNö\U¦½ÿÍnŸù2—–Ip›ñ4ܲM¼ˆË¯Jñ�Šÿ2> %F6 ßã(Í9�úßpW±\YfÌ#ðÙ8Kt}èO± M\’„gê¤G>¤¢�ùÑø_Âõ¯~|ÁªÛ½uñºÕVÖšB³G Ü~ÓŠüfˆ“Úü܇ û|ÑÛÚWžI»g@…ÕXìÕw,žÛÑ%ŽuÕÀÛ­¤}'†oìYÈž/àôb)­ú¸ UšA\§.*ý¦ô0¦©Ð‹GíZCoǪ±£bÈíWåO W9§=VlMè‚õ�>hí¿›æ»fÓ�€=Æ‚?µÊ€MšôÊù0_ôŒdÏý»9ü„›²'��Ï;Bò`uÅ-¡6PÂÓSO²÷Oe¶ÁÞëË`à6©É¾K?y<*3U_ì`³…SÀrÔxc¿�Ÿ�>œÁ'T¡Fý!הư|E/0-ïÇ݆Eñ€�rtmVÄû쀲?úèãPÙ�OÁ(X_tºÝ ͵38t �7Ý��ÇÅÿ?ߟ»Àüz(L<ÙNïÈ!Иf½xG¶Iÿ8çE%Ni㛿T–áÃOOªc^‘È‹·¬Æ¤n)ÂZ?ü‰ —1aðæN* ˜�o4�x—˜¦ß…ÁÒAxþ|>wV*”µ�”þ”îçÚÅQÜ™§Á›[ qëŠÕB·Ýhþ€L¾ôò4/ÿÒ)¸O‰�†Erd« ­q�ì0{Î\J}·˜¬#¯ŠïÔrhp¹n;ùÅÁdíM8ëp´ÒwS�ejþX‰þƒ›gh„p³�w9¹ã¶øîø´[8×–uÀá1BÁ<®PËö†£4/‹C•wÁG#QÜ:é2\Yðš4Á{_EÇ�u°U't‹ImÑ#6mØ¿nWÁÐ}%pì™fv,„û×��ù¼<ž10–£³·¢ç}Ô¬ÒåKq3¡£%üzÝöS×d;~á«À³×^>Ü®"éW‰â^ nߟæ1UB•áE*®ÎÆ´^êø§i#mvïËËïsºô?ŽûñKÔ~¡‚ïÕSy]‡xÊ<”®ik³O”p©ó+pïU÷솢œƒ {7}´�€mË1a_º;KozÁ†Íz¦ «Ç gÝòLI#þÌQcÐÛŒâö|‡¾¦œÜx8=º6þß'Ë`ñ‹üþÃ{\ØÏ¿ûDá�ëNø¤p;õñö¦·'°sK7‰Ý¤]zß\(I.�¦ÁX=qŽNûJ/~ b·¹‹Q£vL”�`ƒ”ä÷ĘÏßòåÐÜ$1¬O:Fœ†LÕq¸ìäx´G¯¨åI½q÷jÄþÙüÑ[˜jÜ!ž˜/öÈ]�e¶2Øyï6ý °§g‡×@ÐÖîœôKÞ^“‚VØEx©Äó^nsh6Mã¢åÑxç¦\ ;@…a—…üdsì˜ÐD¦úv¤Ò|g¨}ƒï›¯Ñ�ÉžômÄJXr îàó_ ´ú#|V'|�$‰ë zÙÃz©Õˆ›G)¡4t ÎÆ±2—õTämjbýHk,¸}JºÊx=hú@¡¾ïZŠ[SsiÅ÷'\Tyœž-RÀ3Ó”)âq?ôI«Ã\pÛGWþ<ûÆYBÈìrê>O�ׂ�ã¯Ø÷ÇܶPÎòðéØËtªI·ÂñØRTœ7vÅ,ÃúÂ$lÝj‡*ËEaäÞ{<8Ó†—Ohƒø¬™¼Ëò9\èyšÕ7Máè ü>ª…V½±Ÿ^ôר�vN{á}‘:x¤…på?ßž»? >†’5‰(Ìö¢ñ;¯L6²ÿ¶9L”+…ÖYßéeùÜ£=–¿y_ÆÏ«5xØ„Q¸FE õËÃsûx¸÷Ì{gÈAc–²*a½QOÌn ÌætAÒæfárc ,6­əԧ̇dæñ$õj(ýqƒlGç�ß•ŠÄ)î8"æ±0U)mÛn‹A'ÇãŸõŸÉöWª¸Êè©0Úz"»Ÿ>ÂV}çÂüOŒØÜÇqôµ%ÂѱK9èo>¨¼§ÜÓ1=/JÚTŠÅv&è'²³®ö'Ï€?ó)cQïAŸ¾^€n'÷Sh§%?{ þn¶é`}äLuˆÆ^Ûit»NJŽ¡ÉmÏ ôÒjþoý¿Mß™ ó)`è@~vc0Fü6 z½"QñMŒdF† u?w á¹ÐR¯%ÏwveRÝñ(ö߉…+qqÓ* ¿U™O& ëÚdº¤b§9S77˜OËóiÊ×ÿ@L[Í6~´£Uƒ‡þî'F~˜C" Ñ4û‡°Þ¿žû>Içuø�½ƒî3àío7ÑÁW¯„Þ:Ùp|h<è>”}±Ç�‘´Ö_—^ö[C»•û¡ó¿ŽÙp K?Xaƒß¬Ò_É?NF@¹îTî;ÊœÊÆã¹WxÉW?éÇsè¬PB—jORQs_œc¶„;çÝÀ• g© d:L S‡ÔKÈÑÄ‚.µŠ AÇéó^×%•è‹)ðàðÜÕÇ û|™å‡zâùŒ4vððÁƒB ¹Ïù‹„ÅØ¥C|¯g€(Œ&íd_̉²ÿç^éÞ:‰]Ÿß!½¶stüØ`vnS‡ö7sð…C0ƒBOQ;Ä�Þ,J‚¦ÃDŽٳVáÐÉ Bj¤ /»ü�†º4‰oÚ¿Ó‚ÏO!îõ6Ô½xµXð¼§SðððMè8šWô9*œ^aòº‚ºÍ^ÒËÈ‚£±Ê\_ÒIxÕ‹ý™ ƒ¿{Ó^»pÑÁàº8âë[¸wp5oÉ�à*e'nÑXM ìû¬…«~õå¦!z´Ã8 1ª†²Jôð�‚§ðÆæµè1sD‰y{øSÑÕFÇ­©…ãSßÓT�&2XlŽ‹3 „÷t0ïº9Ÿ .¥+Â`Û¼@ÞÓAŸü%4õ‰èܯ¬¼!v¢¢»ï%#Ý ²Pë¢'‡”qlô*,Œ¶Åæô}àÈÂfÍ2ð¯K…ûyþ¨/¤§¹ÚÆ”e눱›eñ–R­å‚¿õòaJöLv¸º…Gnɇ…UÂØy4ÖxøÕrø[Ž7ܱ•ö®Gr/M"•ò$ÿ$æ}©¢Ú pÛ/´ÏxqÑ™JP}°°6B2'¯ŸÚ=‡G›èbwÇ,A'w+ÿwpΈ•§•EÃHþE †$Ì‚ïŧ„ åïé[å%Zðó(ØÞ­¡ÓGõè«ê)°>éLÆßŒé¼×-z°Ë˜ÛRCiÇL/ìm¾^âjÿáì9:оhªðÛ70ùþ\ö.’ãÁ·/ �wE•ùª¼+ô©Øi¿f_Ž¢y—»èÁòa@¡ÚOŸ¢dÐGn-[:¥€ÚóA˜s.YôË/ühYƒ—F‚ òÜ6x$µN¹„ 쓹cO6+T›ƒßũŠîì½R�}ze �%Úì¢i!.Y �U®É`=Õ Š]]ÄØ 5iÀ¼Eœ¾«Î.ï[þxä1:%~„”]òÏ[_]¹Bùf˜g[ë{9A�oÌÛp,ú8¬èŽÇ/|›¤páá«Bwí\ÿ`8[MÏgúП‡Š¡ wñ¤Ž æ•5vq÷*œ^š„²ãrùŽeoå… jšüg§†h2V™«[fbìσdIJ‹9áK.2vàé‹Lp’Ê&¨”íI¦¬81Ê µð’Ó3®ý& #î,™'Çñ ës¾x_Tò¹YÙÞgåOâ?�’±ôñ4JôH汇 üá'1h‡7ºŸÎ™›yhÃ|œ2í¨ÏßJ�Ÿá×�£ùµû-qçI+– „}�íâ '¾P)‹ÝsÁy®Þ¼T {ϯᲃŠx0âWÌ\BÚÅìô î<ï+ošŠßEsØ·u¸6@Àä) ·]“zŽŸ�+�Âñâî8!gäZZ· £ £žFM[…®ð%¬µ£\ØŒRT.LÁëAMBl¼ÆÎÈ'‡ç�èb“$‡4 �мãy�0iÚ/h^2“¯X+D?@?ÛçãºÒÛðêK–Œž :'ñÚ,eLlñ¤]a‚ZðIªtnÁëÞ[ þÎXÎí["=øùŽÛ²‚æí; /e�ûò!õE|-}-n*ž.ôÐödKùÁ3Oyî.Ž8•,Î3nƒùë{ã•=êü~¯.. }+VŸU äJU|äDª=‹±\Í…ß~_Ç¡Ù×Äã‡/Á¦~&œ9Ʀ ¨‡%kÖ ¾ Ûéâ•XP¼å*×û“0aßCaå«’õ?$<Ÿ]Á}„)b|o;”q*8üŒ‚�½WÀ«ÆdrJ��¬O£¼³„ת˄„¶ùÚC¦¡mÛ(óôRsaËôzzÐJ9²×`ëÍžØlSÍÿ¹®~Ïо8ÚAéÑ�bšXD3¯ß ÊX'7ü�©üæ°ÙÿÈ 3—&/ø!¥ëãx¬N¨ æ4õ÷a™�âÚ š$Ô¦ÂcM%ô‹U)ä¦Ë¥[³kÖ.,œóï“£€NE^z)’~GÂ>×I˜–EÛÛ^A/]9!cæ'èX¹‡‹2ÞCÊ6Sõ&ù¥QvJšô×ЋBÖ�£ÒðD[§w£¿ÿ¸¼õÒ- {`Àyɨº@{ë°æƒ8ê¯2·dDÑO…k´­¸•žëMAÉp\×èCOº)£NC1Ü›9þóÀ«ñÙl7m1(Ù|#iÀM餯ýx–åY MÛÍÏtxÚÇIå7Æ|…1#saßÑ“â€M?iÐÞZéƒÒYX{ÓV;tç§ŠýØ}÷]Z~¾»ôäÑš¼÷ ¸ç9Ù;®@øæ…<÷Ù*Ò9d Š?£Yþ¥cyK¾ —Pem�Þ¹:|ÓÛ�ÕS+`óœ™h�ÃzíF3•É$nª…:!‰4ïÔJN©MãX¡¢öé!+¢çœ¢þªì¥b Ž .¼¦ú«¶¸Hë'¨½Aëç=¥Õ3®�Qû<Àcñ°ô÷4¾¤y–FÂÏùe,ÝÇÆãèeñ6×%ñ÷räSun‰)ÝÇ&ä°Î“øb•Y–¸r�&>.4áþ×wð×€%â/Ca¸}ø|¾¶U€5´"ú7ä.$Zà3§÷—ðùáñ >Æ×U7Ó™¾ãù¬Ñ~Rſtè]òÊÆÀ¯©Å¢‰Ó6ºtiwj�·Ù~©Æ×t˜Ýï·‡õ†y£¬é÷žì«8НŸ‹ã[�GÐwY?˜-fÖ­ÅþúG°Û�^`¦ÃæÓ§#Š0ª£SÓTxJZ[¾[Ç?§f ›ŠpˆæŒž€>�Ë,ÇGä1xäQ¬z.Çó›ÍùJÑ è˜²G�ÙÉ/üôpÃcUNñÄC¦Ðõ*b»±&ë�ÖÅ(…UbùÖÁØ9"£ˆZƒ‡ò®ÜPú’‰S¢—×|—£¡×Ë@©5 ýÖ‹o?'g�ƒ}ìÁ"(’ã,=`èó|ÈšÿÙÔÓ™‰á¸ïÞqü ¥ÀòC<ù𵄏a2&*êó`åI˜fJe¿ b—ÇBÙâÝ$;0Œ’Lûsç‰k ;å¦ðç@� SÙK ±ïk¡±G®Ð÷χòH§rô5 »M™ÍsƒâéFT!îmvG»y –E£\‚àÌ­H0}¢C× ‘RÝo8Ñò¥âê, }µ˲ÁÖa"Ǥï�ñV°¯ò_èHèˆYj>ào%fPð©Éh.v‚GVH‡¼[/¦ÉO�gcÑu„N?;߄̀p[e±¾ì3‘×/É—Gä½w$=šóKh‡/´?¯H:¬{Ìi‘áµ³¡ö_ÆëÑN·‰�©d"92 à”Ž.Y¾œÜ¯?—/ŽÅ1úŠü>ä ¨éÏÀŸuqÂ3U …k*žøx…3¨»Ž’{Ë¡[{‹Ã*�(]Äû2S$žóSyÂÚ4*ÚìÆµ.Ï…OÂ}±4Š‚í&y³#zÌ2wü€ýCPØ ô­i¤q¯þ/ñ4˜–ð+cWø9÷ʢòø¢g}&Ì8}‰Ž> —,|ÒN «û“½j› ×û˜ØÇ¥/_­ô†£=¾ÂÙ»‹pmÐV¬~š‡OsÔ ÍLžý¦R·ÝtôŸW]ø%‡ãÍòIË ?~~Øâú㶘ЙÍ×O®s¨ˆ ÂYûnÑ™í‡4ž;²$ùõ«Wàà ×IY¿|TÇóÍêF2ŒØŠÍ¯^À K/Êצ ?ó¥[f‡Šnqêø"ÝOÑŠ'èêÑ|¿ÜY|Ûp“¸Ö�]I Õsì0º¯½¸öf „'xs—Òzø&Gÿ1„MûŸÃƒæZÁâ÷!øÓT%Yô%[xº¥_Ô ÅÑûÅg¦ï„ZË~¨{TÐØýA²­#Ÿ>Í%ÿQ§Å3ueš��ð`åQmË�¸W¢Ï6� ô¶ç¿>½ø@Ès‰¦S²ÝpLÿ_à|>ŠOî ¿çhñ§Y‘BóýF/z‹§¤¶ÒrIÂÒ‹z0%é€pXõ†y…ÑâÕ¡¨÷-±¨] Û�±¼Ì”Ц5_¡êý{¨\&Sv²Èœ¾8T ÆŽ•*\m°Æ±�üê nöF¸aœ�hsÍ•š™š‰ãêèùñÇ$‹&x彪ĭæå½2aÅ–ý˜w¥˜’ÿ´A]oU®¹zös?þ”„Û�÷ƒæ mþ¾°ì96o�P‰‰-~Z¹ÞUw”OQàÎèçàpz ö³u²_³È%ò<‰M]4þ¸!6—¥í/K1Âñž× ¨jhBrŸýy$!KjɳŸÙ´ìK%…€n×¼i¦k†h_³�No8ËÚïdÈëÕ/Q¿ø�PÁ9¸f0:ù-(75†·'£s_à �™0­C‰TÝdWòf�þ,Q. ÕWó!=º ·�Osð HÅœHeô’íÎNu¾´gJŽÔ½q9¶Î*n:Ez²Ñ0wüñ˜Þ*r5É$ÿ‡²l÷k0ÎVÕä©/ªè‘B $K›Ä æ ´óòŒgÉÕ÷>Šû³“ýt|e:üãÚ¥[hëÑ×Xzx Ûö>,ìt4 ÓÒâªÀüpÑx֖סÈ'­âúãCIJk˜Ñ/”ý—nÅC×w “N�†&‰+G­ü�g*Ù¡’•�w´�€ZókáXãqÐ||–ŸLW’š%nÇmÃu9L_ŸÛtPÏ;¯@+~&º °z݉ŠR2IÞQÛB°[k …þ\ˆÞ‘ùšÍ)¡Ë¢˜o;Ý¥gA§Å Ÿs4dR_ÔùÇ·ÏÃâ'£°x„9˜¾êGy¹ÆfÇVˆcµFâßÙüÖué{Søò±Éé‰d� xžÌj°l¸„c×ÿs�:%öú¼Ðè;‘mO fûövÔg4˵§H¢©œ�rê$GÚðÆ6ØÞø�Jõ3©c‚© !s›´ËL yK Ȫâð©¢®G&fØ£ˆ—„VÉbÕ.7ÑoúO*?n�û/Êcw=òî[#Ý5Aw¸ *¶¼DåIz�øà ¹úLÆŒ%×`ßÝVZݹ“º}°§éŽÝÐõb-5ø«âÎäH>ñ·göl¢Â¦ ìþ>_´øþƒJ~ÉðdË–sólÑ£ñ$ͺêÅCåýÙíâO0ûrˆZÌcèÐy_ñãê:N›™ÍÛ2|Ñf„!G.¼ió×ñ^ŸýØÿðfÞêÊ6axTcWÊ^'—5:â5‡u'çRþë\oÓƒ W_Ç•KVƒGb)]vþRú6b·8ßM_fœ¦�eñàö�6Ñs/áüpF?ÕÎò.Ç…ì)â!ÏnÛ ?B‘S5mÜ,Ù²ç0.)8 ]g~�âþÕø©ç´¦Ð^ÃZx4THÏ¿/IvžŽ> jl}~ n)˜ÍŽw>Kâ¸â‡jž“Èï¾àî_5¸â´%Ÿ7›Gƒ¬‹„ƒUp]±‹è$Û“W®ŠW~É`Ãã Z–±¿P· søí½XÜúÑÝR À¼4»Ý¼Nî:;±äÅ<¨ó™Ö9À“6NÁê=±Ò±Ý;ÉçM_}ý Úö®àÿÚàÍ}%\#ß“ýwçCãÐnœt-]Z®ý”¬ÂazÐ,ž4? ޼ÆVê¦0²EJ¿Cr(5j-Ýþ¯÷䓸èÑ�¸FZAp¿’„™£xé�TAnÚ0x¦TDï=' ×"Å®bx·, +Í0~|9 ÈŽd—¢·ÒÉKzJVùeÐÛ‹&x.V_L¸·Çeó£µüÑÇ…[G:ó€YŠ8µû 3–ÒyU/˜jÄÅí»°iæThYZ �¿,yÁý§Bbä>‰eà{ÿù<+‘çàJSš·qìê=ý¨&m†ž²7©ôö?ßw©¶ÿ=å&—UõK‘/}íɱ†ïèþ¤©Q5�­«{̣ĚöÝÔ{¬6¾SŸÁ2Åñ¤XÛûG=s›Ó¨ü+�è¨aîò@Zxx(E“o|ÿý‘ˆ£PzÆnð8Ÿ‰ÚÉO1ñiu¼wf3òW.’¬˜1&'Eá'l“¾™v‘ÅÇ�’Îc�ÜÔ Ïùþ‚öWêàk|”2[¿ÓCí]TlÀ—iáÎzÆÌlݸ zYTÓ­!—yqV8{îšsuj鎗+›}Ǫd¼óg' q/Årã÷Äqø«y­‚oµ+ára ;/Í“oǃU=qãÞ\†¥¾\`™Àkd …ƒSÇ oÏ뢬×>á”ËH|¹Í€Tõïâß,TÖOàµ5Ä?ŽÅÏžU°`ï^4òi拚ɯ²Œ2,1j½ x,Y c4yÇÀ0+¤â¤Ø$ð*ÿ~$ö—W°˯h”‚fExÿsâÙScYµŸ”ÿ?Ÿ3ËDl/ƒUÑGpØBºÐK?ÆÖAË�ÏÒç[t°ó|9º£7®ÕìƒÜÍqmkªòú9Ïòã# (ØH‰VØ2uol³¥�%ʘÙü¬ÓžÃŸÅßøÄèÞ~ßû­ìGNº±“‡>öpÙKzŸ¼±¦Ì­ç ‡ÒaáLîVì娓O½üÅcÂç³úx:=�./ðcxY,Ùþm�+¤íƒëø‰úøø~ŸkX—ªrPÇ  ݧ€ÕU ®�{+Ú[rW÷Û ÓOŸÏŒÛÃ5ScémI3x¨†¤Åxˆ‡vü<qÇåqäôÞâ9–ç�ØÅ†vð”MôýO(+ŽÂ›Ã“P}…)^ü•BZ3ºáø19#v(G%ÆñoÙ 9ÿ�UJíÅ›ùûàçÊ â ÉÉÅ�ö\3݃ۺ,±R½;|18;�=ÂÔ B2ßþ뵋pŒ_„0lÍ2a®aO´uŒªûÐɧ½°ß+{vY/ÏÊ]ëiÜß½|_NtèYŽ�O~ÃÁ?!"¾ÜJ—¨Rÿ¿¹¨ÛðIŒøÏ��Ùà³H¾BµûMTPÀãê1Ð÷N$%}†´¸<þô15['±þûß0øÖ4ç)⺅K1r–jYháñ”Ð'q—¤Òœ<öÍ|^2V:Tv:qõOø¯| .}RÐ�¹^êiàò9¸Ì¾Š~ûJhú»÷d§¯€™!ý1xh«äÓ$?t—*„Åð›¤Q· �]ó‡áÙæ0nëëÉO ¬ñÍ‚uvY²¯Ú+QK:‘;­OS`ôLÔ³�ëÏÛ¡öûHŒ~ЄûúÜVûvG§û䲎éÚRßJYÇ¥/7Ð÷œG4_e7ÞÑ'œ4ùFÏzÓâ8Í–BÇñÝðîª7/º%zõšIÖÿºIvÀ0b÷r²Ñ‰'ýÄ» ã~ˆY,ÄÎ p÷Z}ÉõÄ9Ÿ@¥o-�wËá�œ«÷Xò ‡CLÏA{‰?8O» ¥Ë'ã½EZ¸r�5fæî!×=1xö˜„‡Í¥i­÷x/DZ÷‰-,šOƒ…ºñJÉX<‘óeA¤~‡ðng Õ>‰Ö=¯&»�mxæ}>>™7�FŒEç có–Rª{Ò=üÀp@“`S¨‰­©c¸Ÿé´ –\k²r¶öå“·N³ãa)Õ¸é 6‚=n¿~‚×-Ú‰Ÿ£kƒÐF)–Æ($ãG£¾4uÜ}8ºï:Dô_Hµ³¢11T—N Hv0Ì Áƒ «!Ý«bÝwqG«ŠcE¤œÕôЧx$^�ñ¢CÍÓÙçRNOæ·ûGŽç\)‡Ïž$pÑ ")SHÔ2…æ/ bk™,ç¦Ä æc™£(<®†*›è׆‘$Wiˆ5zOE¹ëñË&+žœg�Æ–øàf‘¸nîAÜd¡Í2Íß`ÝLQœ°“n&Ìû8—n®×æ^«ÿ þ~g‹3úLÉášœ°q~–QãŽ}Ü=ý¤T¡#”¾NzÊÛµ)ë`$xž�çƒërðnA_ô¹ÿœbçôâu­Hm�7NîVK)‡íÑ,[‰G]sêcÙÒ£x¿~7ªOõ“[áE¯&ìúi‚—„ƒ¼r¤#lüòB˜š}”ÎŽœË†ÁÇÅ4Ù=¼bÛÒœpG6š’Ê U´èì/á˚ɸºó ÙÆ çåvO¡÷H-\âÉÔv=Ÿ²d`�Š59;™²Ì{t˜î†óLy|Õ¾b%Ç*C€ê¡Ëìær2ÝæÐþ个±�|'®Âm³ïKÕ6d‘ÎÏ"ž³ä*}sƒøs¿TŽ? ˆžúbù´Ë )ß UšsÀ±É•7ç^�˜Çƒô[éɰ;’ Í“´Ùφ}Î\SóË0÷~”háÙÉ¢œÜ~÷±ˆ-‡;`�Ô�>O,¢A‰ûÄaiŠì6kv«ß�mó9/.Zxêú’&Ü­¡ãûöCf’=ŸL8Ë´ÏAò¿uN°ºÓÜzsö-lõòÖæýxÆ-‡(‡â³Ûf¼#r4:ù½¢9Ž‚n#ÇùXðÌë|ÂùBýlPµRÄd�{�þø À~4lÿ î7ÎÐZÁ@¬[>‡ÿk !Mïhø}¤?]ÊïÉ?ôÎ@9Å2=i¡>¢|Vƒ!!Ÿ„ƒ){øºä+ ÍJ£hÔæÆsjSeì=ysQðbbõó ¬¼/‰wÙÿ?çô�I*ýÔ‡z¿dÌ�&ÒŸÍ;ÐèN¼à4â;]nM¦Ð ×`uº �Lùj»/¬¼ZSÁwmñí¾GBÐ^%þçýˆåû`+-)"«E;’÷9‡Ê-Êh)MšŸ4m!{“Q’RÅûœ£]ŠöÐT)ISZ´¾}ÿƒû‡s®s]¿Üži¤›;œ›»þУܴq|ÀYÜ•±Ç:?ÇÎÕÆQŸh_È[PJ�¡qž1Dó„¿@zð’(Ú”¬»I%Û–ãï^äÕ7èN§è�¦°}ŠZ-]å7?‘•ÿ9|f‰¢ê,v›³\Øë<„{ “⥳IxàöL®,6ç?‹¦£aPÊVÉ£±gßÒ÷IcðU~6^Íù ç<‹É\w.xW-Àèð¾xõ»"ÚyO– lë$¡nÆïçÞ®�úþ6[Ým‚ße@{Í£f‰_�5•Þ|�#îù˜„³�'SøUt>B‚g(ÆÕ„B‰Ñ{±\ã 5Íë$Çõà°´˜|vwG]L‹\…(ih×[€ÍªDš+ãŽõ¿ÇˆïŸ&QX{<×ùÆ‘°*†N7 è8%û¦ÂØ„‰t!ö9$¤äHNê”@™o™œ# .ÿ�Ô ¡ß3©îÆmŠkxùÔXwPŽ�XHÞ… `œq’,'ñýKœÓá‚ÁË”8ø¹ 'eàÛ€ëp1À†ã“š)­"c»Ûâº|k¶<¸_xÜã?ˆ­œ†C]ªøSF´Ø¬û‹ÎõÑäæænìðç™LàÁéÓyýÖ ´Úd'�ž9’/—ïÁ-sÓI ˜$^8?”Ì1•}Td…º¾Ø³hŸÎv•äa{4‡±´âyMIâÏJöÔ”›@±„í\_R—Ñ`N&°ÝÁâ0®´Iò¬×=“aýó‰Ð|÷*Ìž.¼u¸já²òüþ·_vkxé‚ÙQ“ÁïÒ­þu°uß´ ¢ĺû[ù­ÞqÑóó}!!` ”e¯dýÓ•5�šê¨yknÑùJJ®2ü-gþÙx’~–Y�yk í0hÝžÚÀ“×oaÏ[UÐæQh–«/Eu§¾˜¶í1Ó1âj•0¬(*ô;y˜Š.»Ó•$ ÞjˆIÕ qì¤tÎí++ž[«+Ä~–gíe¼­ùò½Æ°·Ö@\5y#©ç¾ƒÐyتäLF³pù«áBïì¬hn„'àìóÚ6Æóm0Æùþ¯DK× 6\ß‹;By«}Oä¡„nëÎñd�PÑ{ÀEQçÕ_ÞsS‰wMu¦µæõ8cÖd®‘/”VžÚ¥ƒµÑ²$SÌ¿¿ÅÃ+ÿ,Üö+­<«FÁ–l2{Êf� ®·SçˆZ¼|@~ºÙ['{`Ê’XXì¢.ÎÆ’?>ט5ÑO9e l7£k&Û©ðPw¿_§ì÷ PêL’/9tp|úä‰NûÄ×¶hûÔ±üXWõf(‚b›~mЃ¬º4no ¦ ç,ˆŠ®BX¯Éï§ ç—}S…ïSïÒ™é—Åø¥PT3š2»}R®€º·mwÏ‹û Aß”ãØÉ ”®ØŽîÏô1Sá«{© fÄX<î*o9Ã*_F8ñìÊ{Ôºo_àgbíÜ­˜°@�¶Þ£¬ëàlp;tmù+IÊÿ&|úÂw&CÀ‰HñåøÃ4kô7ж\ ;K©×Ù:z³ã ܳ·Âµá 5Ç�‡_—.—Ê3•ŒqÌ”}äÑaGãvòˆ (ÜÑÕ Ã¼�{gÄãö½0öÔnº?CòrÁvXºÝSìØö•,‡:ƒÉêpz�(ÏêóFð†~`E�ßdf £’ª`Éí:òž¿%/¿Ñã—=Ð#vg;î!ùg„y§KiÎÂh¸oì@_‡:rŸ¬ÇÀûû�ûâ2Izë’–fáX¿uÐ:)�Å({X1µ'„˜�÷o ðÔmùÚ0ãKp* e{ŸÓ4yÈ5oÁuìA(ü±™7Î r¸²›üÌ„ÞÆ½yNëo°¬–Ç Ã^øß‘ª»ƒÙº…üΤ·ÞÆQ€U(ΓpÑÜD^˜û‚u€›ÇQ\y#çªQè«XÚêLpƹþvˆí“ •žå—†eË!±DWLÇQÚ¼GjÊ›ÏÁÔŸÆXj¼šæ„_ !CèBãgÊ�ðÀ¸q{à¦d =¸› ÏFAqçIq¥ãq:>Q 9î.™Z�´PáùÂìoÏ{‡AÔ46ÈQg«¿®üæËÁ»G,ÙuGZÿ@O².¯~ÖƒU»ÞR[Š-©¾M9äy7\l¦äáS�t±å¦>?¼:¯ 6�…}ºÚ�·à6^òöÚÅyI\³cÕ‚‰ÚRéò¥¾g’iîþ54×{Ú™ó„ÉW8mêÔ:Çž‹¤·ÇÙ¢Û¹#8ÕÉeñPtÿhŠíéƒ0pËLÌܱTPýkJÓëãèçxK’R„¡túnï 8ßg€`±p0jv­Â³þíðeçr<«&8Í÷çGGÈðZô¼;½>ÏÂÐ÷‡Å®ÑѤaµ‹?m¼#¿XFeòòlkúAÌ•j“ðÓ¢WÐ}o nŠK|qÏ^yœí¬ÄÏ•Vq¾Z0Ê_sáUYª’ùš¸dÉ!LºƒëF€kÎA6ôúzøzùø¤FÙâºþÆ�»4�ã0\˶†?ŽØÃå>|l‰ÄËË�S™Ó IÂeYܯ—ĺʚ0³ÏY’³úK¶+œx‰L–uöAƒá¹­µ d�Qx›2�zÖ£Lc-5}çë„뢃 Ó<ƒ/<ׄOÏdùrá\ìš¶ $Ї¤®ÂÅ—OR¶Ó8U³Wªð݃~ æ/JÏ©aÝ(Ž\ùT\¹ Äîø×Ì~ã—áf›B6pÝMF»ÉkÑŽ»çÆë´…izø}÷{!Õ.€ &|†¨Ìn¨±ñ(”ü²†¤ßoaòŽ ˆè¶–S^oä�U.Rÿ¡±üwo[Œ)Â~ôFº°5K„ZŠÎóVláÕ™Û9àäg¡àˆ:Ù‡ÂêzR¸Pm‰‚�õÍ/M~FiŸñ`ƒ ;ÈúsT~øçP„Ž<©ìñãä„;`¾| _øy�–’5ØÈ$‹Þ;G‚[þ úùÎü¾LÓL½pùÇiÖ½E<ükŒ*Ò¦ÃÓgƒ–~)ý Ó7 õ=þ{)‚GŸúKòÕkPCé ¿{�,Ú¦òÈå0q ?¯?†jB¥Pì°�õG-«çLe£)ÆÂôÃyÒxQz(,ŽÏh–^T=t}·8Ï1ŠSÎ ÖrêÖ þ’ãËêWpã¦S®ß_N'ÏœƒSmš±9;“Rùo‡7-ÛŒm÷OJ§øf‡ËSP·¶/ïµX� On£·b,{Ý�‡©%Öä6á*‰OuñÊ%rÜÏ¿ä2pWnhÍ:�xanÓ!ÁÐ%w‡žà¤­=hÖªY’ô-X¹a,ô?˜�õ´áŠ“,^/¨¤¹ýÚ%9¸O&™¶ LJuð¡ƒî|’H—‚ä`�îQjXrGš†SçæxVÚr»×&§sð°)š&¿øKFB<íìU-^ûJ\dІÛú²�g±_çÆ�)éPóñ –†>c†¤òʪfA}î}(8•%¨¼JÁwñ“8Ç%öºýœ»Åo‘G¡C»ŒšæáÑçS¸uxw<ºålßÃÃ4MéU®£¸ª½Rœœ|�>bX;¶‹ê[MØúl6ÝÈø­qIªiø=ý zP#¿!,Q1¦~^ƒYÅUGðüö ýeñà“TõLOŽ{‰;:Ãi¿îaX?{*Ÿ—æ%•ð‰Ä}à¾A�S‚ôà÷¡”«Öò}(Æ¥ à&:ºÖðØ¥%�×�*Í85ï=—LnùÂg{[¢î®õ´Ms)¶Èãw=¤>! üÃägVð=“hl�M£ýúâŸaØÔÏ™^Ý2`ã¨îè´­=ÏÈç´Ýw%©{ÅPÜí~Fû[CkB¶Ù•×�’1N<'u½ƒï�³I³ü‹ ûÌŽ^¦l…äá›xRÜ)Zµ=Š-ÆSÐÊ—”SÚOÎÂ{OT¡ÕÑdÛlØY9^¯S;sAº’ w$wÃÓ?LáÉÛk¸çÖ^ôû0^¸\ÎAc"Hú͇�×#å[äcµœ—ŽÂ˵@Ú‹§0e×”{cŽIaóÅ&(Ëy!db ¥Ä€ÁM¨·A ”ÇÔÁá× ø©ËpÔ}B™CÃpóãrÐð; KËëðø¹ÃxnSÞ>^›ï|'-ÔàªÄ×d¶Ì‹‡ß¹UpY¹)/Š9 ­^¥ð¡0}ž½ cȽÃNð¡Äuøãå;rzÀ׎€)¿itÆm:«¬À«Ïw#oß‚Wr)Ô|×ÇMSJùå¸�R]•¶TÎ*ƒôþ¡Ø¸2‹M,°èq$6×&aK¿‰Xf»—=#'ó•+ÁuÜQÚ¿$PÌ{"âBÇýhïô–·¯ ÄcŽÊ,�:EòŸG`|ÔSàfwTÝ| ’®¥Ã´Ñ1¸vȨwÅv³íѨžiJžMz5™_”ÛÐóG£Ñj€TO7ÇÏ7NS^È(ì~öH¾¬¡ë Çⲿ ¢ªb.¿]sJœT•ÈWKî{Dà˜å˜ïÀ’©é¿£–ë†'ós«E|ò[ ˜ž¡Ã§þã¸;¤M'\óˆÏ CÝHüÏ=ϼ‚Ë ¤¬µ —d�–‰��¡¬7y^í¥U›tR{>WÇ™)ËÅvûx±õv/Î6Þ=ö醴/`…ÌŒJ~O^fQ�·El:¿�=¼Ï 'V®ã± z`騽88ý®XâÖ›+—+XŠ.X5.•ÿô¹n“¯Áš/LµuÁ•¶sÚ†»+vcϰvaÏÚVÑß5ŽÝÆ{“aL9¾T�¢ªâS{MéYÐ78Ñ¿)”ÞÅèø îým:Ü…‡VÖÑ�s'©:bf>PÛE=ÐÇõ3¿ ÐÁoÇópÕ¢î<ù¢„©ÌMÝ�rØ¡¥´|©F¢¬`_lŒãŸû`ø®c€®)b‹N&W:ü� ? \ÔÃ]åòH:¼ÏH^xÿ |»ûWrããyˆY%N³tÃA¦Ðå醷�½3p 'Q'ÖšÊC^ð6ÛF4øìˆEö¬*y†WsþñöÏ8�CæOaq|_(̳„Õ%GaìèžÑ}&¦6¾¢˜'}Ṭ. Q÷H~Iº*înáRi ‹Ðà¹ÿYñ�cØ{/í<,gåÍZ7×ÎgVà[wHÝÞE¸Ì. {tñÏѶàS`„—k.ƒƒy%Ô�ÍÞ2’*ãcÀO{%÷ºä Yõ)ä½× èl"Rÿ9þi{6pȤÊ| y ÖA4ß8†Û¥ôñ�‚ÐÕYAÂÕ͸V@Î+PçiŸã�®!ºeªXùE�í­vÁúQ|-H c\' }, BÿÒ‰ògp]00’Ç Yލ‘½Ÿ{¶w‘ߤ¨}h'œ»&¥¼açy£©81Í�žvÇZ÷N©SE¢ ùsš†–�@sÕ8¶ì‚Å0ý‡pá—�”Kå‡5¹¸64E2ë÷2°Íæä,K~qe ƒÇ=+ÿC±ø¼�åê¨a¯)ýоZ£š£@b<îÎ Ø•û"U¯á'÷¾ìÙ:œ8Ü g£ åH?í†u Ú¨9í(µÖåAÎ#¼ªôG¼òäÍÁ¢ñ0g>ñÙ‚3eHøš‡¾yÝy™\¤€{Ö˜U_CCmÓx½›Èóå~ÓÖ囸`âDÒÏÑ`ŸìëÒª’"à=ýPþà îZÚuf£BÎ2S�Æ–KÕh÷x"}¾6Sh:·žîæ–9ŸénK:Ûv8²ÅôžÂÎmBØcî%ø¢ow/*9BâlÆ»Q©"Ä? Îçø0kG$5R}²ç.›%üž?‹‡öï]‰}±eO=¬œŠz'?²xÌ›®äSÞ}Ê–öñÇÚÝœ–žG«{´@HpŒÄèçe1H£A2ý*VV›D.'[`Ÿ¾ ?|PN‘Úïøí«`| ¦í‹ºÆ÷Ñ$âœlI¤0�ÊÚ¿ExùfJ”Ò#ðë¾)îû^¦Á’*²«ù@’hÙ~4:.ƒí7K¾É:”ðp0ë÷T¦ �(Ä�a¬`ÆÑ; ¿r3-žp <`qþÜYg‰gÓí¶�˜ÞÏþ îü²7Gg ‰%Ëávr¢§Æÿ9éÀÄ% °°«Mär LÖdÑê9©¬£•éÿz×M§¼ü>œö;ærhÉ”ÍÝ ¥C±úLE6Oç8…¸eóúU�ðiú°É° œ‚3È!ªè¿„î©?áÆA+¨X)²o¸ 6«„ ƒ‡ƒåŸi¬ùõß oHâk7xå¼€õ‘÷VdÀÎFÒ7pƒ=?9ºE…ÕâÈÛýE¼Ü�ïä6sñ};ìõ> ²?P‚\0–ÑD«?0°W$y¤õ«�`4“'xHa Eñ޶±Ð¤iH2jq4©~ U;Ù�fÚf‹EFy0þ²+˾`¿{É4rW<ßz«JÛÇ ¯É œ«-}û²jó!!qh±nCoáä›X¡ÅΘórre¸MÊhgµ áëš&³”í�ñæÔ�n€“ýJʧûùþU=hHý"þôŠIóW`‡z <¹W,^ê”òú– àÕn bq�k$¶9\€wÕa¨òc9ËO™ËÇFŽÀƯwé÷º/â � 6 «‚!mþø"ëþAnjoÀ`üI*'þ½_!N•ÝÉ3¢¬0G¨†“¿ÐŽÕ Ñ(ã—8P½ƒ¯÷£×IÜþrϸÊÞ5E8«Ûq<«7 C‡ŒÅ‡¹~¼ôÀLöï�E5j)|8ñ<ÏÚ oŠô©ùÅ6íþ�g·»±Oà9¸x‚0Ám?”�Ç?Y£xåüúQu�+ ÜÁ=ʯO ê ÕÚ…$[½˜÷ÖSÏ·w!ïU´ð�@`[“ 7ê3•µ^¢nƒ °q¶›à½Õ dÝÞHíæçÀ´I{Ø2À_4+•Æ(ž§�BÍ×þðÊ–lŒ¶=Ê××þÿßÕ—p_KÜ{EƒOf i9ví³ãÈÑÁøe® ?2ª#¿%Ô‡®T n¦˜ãCù”šÏ™Œ.‘âe^lB˜Ê/nçÒ(±ÁŸ„AôÈ �oi¨Êûs†Ž>+­ŠK¬�ýë^o^šV%\ÈÞC¥;—Kõ§ž§ý fà\É—›­ô7z½I„3Û­Y±5–Îøú²Óâ~ØÛÿ;lžV í«xÀù=°Þð,»èæ‘O° ú¦8ƒýÕ‡øj\'LóÜ€fNª<ðn³ô×Ò—ý�Ëøx@ï÷Áâ¶’gðü°Ÿ:UÅzQS1c˜<½'ËŸæ"Ík7ƒÚ̯ä½e'?:úT¨°Y*îZjnIC4Gñ·WºìÙ|¥ÏyˆÖZÅ_2Ãù—úi Lã’›y`Qxž_ünüÙBö?ó‰}øÕë2imÏk{5�ñè5üákªúoàûVëðÛ�ɸX^›IàEs¿“¡åX|”­ÄZÿ ùeN¯•G«}3‰ý z³j­½³GäóæåÅ9b?éy‘[‚Jéôq±ŸPÌ¡œÅyqCض}„ûõW 9ë)Ûõ͸r Ì•ÐZøàeORÜÔ�•NÃ1!°ñØ xtCŽ“X›¯†öàúCÕ·£'õ“¡F6çäD=ËCíÆ\\l¡i¼Œ“x²I¾„¯ÈaÁqyIËc}ÎÏé�‡—¦²\GÙ(Ÿ·š^‚8­âuø±\žßûà ›¥p|f 4,�à †áJÿvá´ò Á“†«ÒçÇÁ˜ôânßzTX;,™ÿn¨­Ù¶bfŒ´åÍ' J_‘Ûãnè8û™øå¿7æ¢+�½¿–Óu¥”îûïæª.„7Êa­·1_;¾�›Þ9ó�0Ĭ„ãbÁª­I\6%š7ØmøçêÙìfÚ ÍÏëøkÒ4n} ïƒxüÙ2èùMƒwœ^Ž_¼7òð ëqBÔQáûó>òz1ÇÜÙC«¿G‘õ¾9PØ?Gþ~Nï=b°cËHy '}NµrÊYÒAÛVÏÅ…±ýñEË9ZÚË]jüCf?ê?2ƈ;�”ö1B\r3½ä!‘w…´£†ü¼Å7éLÀs‹÷ãöµ.œ¾;‚|žÁ"�wt¾Ú·wRÜÂc0øO<Øì½[ýLá ©?Ùƒš7å8;É΀ß&Z³Âª:>ùXR�^�¸w1O‰MâqvÈ›?MCé ?Ãéñé6\µ°*g€Þ.yè´—ãyM8 · ¾œþžŒŒç㮉»pÚ˜HÁ»{>nsWo;G¾ËeÑc·&*}êÃÎgúòüÜǬ±Ë —¼ó¥¿3,(ái/ðµ°@ýJûÌsƸÀ!âÙ�;ÐðP!~Õ>y¡­÷5NPÌJf�T}e&ö®&ÎþJ×UÒY¥m8V6F³ÖjMR>±X¼62WèÖ¦ÅÍæ%R÷eq´±% ª/Þ¿¼ÍY‚ª$ºw)á­y~wø-éO7¤¾WÍ¥1á4òLJs®=rmy’)-°÷£±÷.Г/¡ð«%Ê7f ê}ûQÙŸP^º ¡7}¿\ÀmÝôqÊZo˜´ä9xÁÜ)L6e[~ ßç“×<|‰„ÿzî «Urœ*: _Ý{ìÕ÷-_”ƽì¼ùœ–"5÷æ«f•ôù‚-_œKrÊmT›4 /O‰æCƒ¸çöüÅ3æmǨ›a#w‰ W•�Ûî}´æ >ñ¿`²å=®·ñ“ûazâ0. òÇPƒƒ·„ðÃûsùb\©à_‡¤B_ó'hîžL~…ëø²ê|À¾‰¹á¾†[ýêÆœîÃÿ…¦ásƒ6xxJ»Vâž!ýsï#tnpä_CãÄæì˜1Žªí“1ó½.öjlà�gÑFΜ|¬Fbƒ£<iTă£ÂIaL-ž†;œ¶päùÞÔïÜž>ëtÎýÊ¢ž…G„¿å{À麄£cb›o}›.{¢Ç$óš=ƒ¯gÍøô&Í÷7Ùâ‰+v«†­¤�›/Fóøy_@eº*¾–JN^Ý0~!LIoÂ�á28äèuH¬½Fù£’p©êbhí¬Á´ÓϨ¡T•¥ïúQœ�…�cþ£�¹ø@€–`ø¯³çk�[G+›lYÖÉ™Œ–âdz˜»„UUz ÞÚð�7aøâà>Ö7œÇ£«>ŠFëó0©Ý óå“¢ ¦,ˤ g‚Å�øÓê+�üÙÆþ�—e¦ãÜskXËî>r ñ¤+«9LåÒcJ”LްPÓ:õúà ÖÁE}òyã¥y¬:&zß÷¦ãµ[CÄ›á³øÌø ØÐ�î—e9îU= ô€È_!÷�:��vN\Çi‹ã¸¿ÕM´¸²„«§<„[ÍøÌ²³Íöá¦<¦díñ`ì6ƒRm‡á5×<áö®½üè�è¯ïÏeÂ�΃ࠩ-¾9댳ûh±ù™qhD@uºøñ¬),?.FX�ã¥WöCÕ‰+”¡­Gc½Ýiê(5²ýùU\x˜Å;U'ðWÞ#4íÃÝÍ�ÚÖ¨¼‚1Ãf§ðf\* Þ¦�{wãwÅ<Þ�•UÓ¸/]p»çÆ#“øãÈ5’Ø´*\¿ø1¨‰#Xy²m[� Ë´£ÐúÕwኇ7I·ücâÐî\º§ã_÷OAEŸ«Pó§ †8PÕ+'>ã!ÏMÛ „§sïÑý½­4 œ¤ W�r÷!üãÏyZߦÂÛ&Îæªi|ýÉîÒ¦},¤ã2ùÚt;�ŇRY»3žGmšÂBÌ>S\¼ªCw:’¤dPïÀlÚ°õ<Øßþ-y™ÕKŽß§½ÇÐÏK9d8E '-Õo¾X#~»ÝlÜŽú+ñN�ç\%žâ †5bpA ‰Š04õ&?²Á5N›ðb�îs¯ø·gðïŒfÁȽ�hå·Œ·ÿÕÂùú�‚jÇPŒ<&Ãç_(±®Ž±à¤�H�›žòf…³`r1/¸‚ÏßýÂh�øÐeŽX¹y‡ã¼ñn7ËŸÎÇ¢O ¢!êð„iµâ-¸¾;rÅa25ø%¹Ôû?PæI—Òü¸qŒ?©H¥Þ©†°üŠ&?•I·f&ÁÍ"+Ú¤cÛ®>�ÇïÑŸ·´ä»‡ªÎD¬g›•�ü¾ë¹äÎö^¸(ä%Ýž¨À~•Àp÷Ç ™Õöj¡kFL[p”¥ÞM Ü° §ûƒ`7‘Nµ³Ñ¬ja¬‡šØ¡ÇŸ¯ÁN¥AœoØŸapBÖ�OÌ /uÏA{eÞK[Lš+VòÏБp1/5m`}i Ÿ,ô„nÎοâÐÙÿ V“âÅÅ+ÇŠ*§�â×iKX¾®·5‡Võ~,W& ¯›§â�?AòÅ-ö=µ0¾ë�®z,¿Ñ”Þÿ�{©e õqœ«è�k†«ðÂ'ðóµC8ì¦5¼WŽƒ•}6àç´*pÝ·ŽœT3yòŽP8z]ÈÁPúø¢'ºOP�Ç9â�, þl¼–—~òÄ-2Ý!m«>ú�áÀG^8v»ängƒ›‡ÅÍN3©\ý¯¤ÿ€gìùò…ðfO½ðqÅ@hŸ+Ôܬò¤î75ùpû[ZfäÀ_–*âÂ÷#©Q?B”]„wßSÿ?iõC}éé�z ¾îÁ ö|â\¹ŽÙ>òTr%“Žô‡–š½àÓ¸¼_1’�çTðNýøýŒߪóÃoOÞ mæ+rk(Gè‚,d±*#Ó_¨â»�NÁþ¤<ùëˆWÚ „á’7“6*Ò[W{>òŽ t’¦àâ}�ºVÙ Ç®$×@0y¸?v<¢yö¥è4³à›èÜë#×xFã ûHiÖ©XiìúCŸ«ÈhÎ,|9¶�åYåtÆõ|{‰‰èõüÜß=ƒõä}Iön¿›+Füx 3,¯cïñIÒ¢î¢pJ.‡Xeðçϱhë�gRpÖ�nØlmˆ�ÚêœÞí.ŽS“#ÅíˆïGðï~m´éc Ôu¥sIá8–›…‰°ž‡IöAÇŸ teH OÓh�ìB6�9÷� Œ�0üö´ÌyqéÈ,TW0ç±OõPòC�þó^$˜Î��  †z<Ÿ ‹¿\ñ÷Ò Øzq"ɽ�>öeÒx•¦z†ÀÞ]æ�íôá†ÇV<³Žgþœˆ´Q>qß*}*ù -Âîï?*SnPêòï¢ç ñB¶ _ûÓ å¢sPڔ̊³ÜÉvW!DwÄY]Ä1Æ ™ë‰·L�`çô(¾5™÷nìÛF|†»139­±ZüæÞÝn`‹ó´!!�œ£$|)¦QHõÞÍ‹¢ôìhÎÎŒFçÃqÔãÌxÌ\x•ŠÞ>ÀÅ© Y}òHú´µœ½"oQ‘K(7z/ÇMûçàÃK)býsú¦Ð“.ï[ � V¬ñŸ.®‰O…?£cð§Ö1¼yÓ?Íä[º;qò… âø ‰Ø§ªÖº”òçëºh²3†ÍžŒKCÎK-ç+ [R›˜u)‚×¾�¡ÜÎÒ‚O×Ñ~N#½Y…Vƒ*)ªy¬ÐnN•âÑÓÏw,îG.΀UñYð ǘ7OÅ)ßXëFî�VsÇñÇMÿq�ñ3 ·÷àíZ\ìrOZ5þEA)¤¦`°ª9÷yàHŠ—¢ í�¶U$Ë÷îåçæCI}¸DܶÛ�§YÆ 6ì­ùæXiò]Œb3»_x”džá¬ÕƒX¾xÎq»@žu0öŽ&¶x]§NÅL¼{æ„ý} aõÍ`yð¬4bàjX¦ŒÍÙõ¬0¢=…ßÒÄž75±S_;v8ÑŸ¬vAÜ0�»Vlg›:dÀm©á ÒÚoxœ:ÙÖøÃèˆh"“}}]9:ЂƒÊ£µ8 ŠSâ0ôØxÈÔî‡Ç' âùûA#a:ö›8õôpYàUŒ<&Þ™¡Â3�40²ÿ àÿ¦ò„ÎýìW% “ÈÃÖgsÛê}°kù~‰Z‚EèvŸ,�Нӣ:äŸþÒ ÷2)[À±*1pÐÜ�ƒæ;á˜ÖáÜ_.ë® Â£©ùÞ#K¶|ÿ‹Ô(à±âlÖý; }*IÃZê HQ‘­ƒÃiaÒ²ÓRÊ«Ç?JäÊyôýdæõDÝ>…Ž�[+öñ úçò§ÅѺøíÔ38沿_,åÜsŰfÇ ©çÎu8!ÞŒoL!�:>Uíâ˜9pDûŠÉbyÝXÔ%¬ÍOÀ7{‰ÍnÓÙeÿÈ\•Ûê UI£_x¥m/UÌÐÆ��c9©HŸÿØ ÄV·L‰»yâ+旅Á¾ç)ÂcFT©ð½Ãh~î/(TŒ‡ø7‘¬0m .�ZGŽ�€ÃO§R±r¨WÚájè¤Ê—Æ\˜…ýÐëz$¯‚M8d±<ªæŽÁ—{Ëh‘ÿ$üv�i›e}7ïÇE×ûqÏEñ ¿ZßͦSk )9)•í{i£ì%'þÀ~°zÝaá#Åûñ9ºhòãÚ$*ßÇ)Ë‚¸öd*%¼táK놠áÍ ¾0I V›p]è ”ËJ"YÛ2öÌË¡ü¾¹0¤Öáw-ÿŒç–SMbÆÔ|£Ùì¥ã@çëÆáv)ÉYá×”™¸õt$¹¥ÆrÏ3]4óq\;/-eÑç0ÉÑ'N8ãÇu¶Ý¶o=üD–F{ÃqEaœ5Šk…Ýpíý'X $Ó°Ûàü‚‰tU§M0íTÇ]þebÅt~} ™âßð1»6ñé¦Íh,w›wô¼Ä¼ákŸb”¬>ÎWº�·GFÒO¥7 }{¼ô®[Šàm–�…¯`môs(þ¬…×çÑ õÑ YÁeõtX×uÔçîÀu+GPEk9ôøÚA7Ú/QKSêÖÝ}Œ‚aÿë\,ŸÏ%³Œq©r�WVæ™sg¡Í´Hœÿ²f¯,€ÛzNÀKN ¿maUâF–ÄÈâœÀ),nI¥Èíƒ9ø²ø–ÇÁa;�t©ÂgnŇ»çq×´+’Ç� J[/Ò×ä"^÷°hœ£ŸJ­n÷)ùCw0.Ø.ôÏž€¾£Ú‚)‚éøz5®/vN6†/ãcA§g zÝkÍo9ò^ýt|Ã;1;}Hg–Bίl4}cN×¹‰à5ØýÕ!¿—áàõp*™-˜Š¼¦ vÙ…Ò3�«0´Ï@É ë6ºp¼ì yZ×P‰i‡Š‹ŠìeŠy=‹ðMX1—Y°{¢€I‡î’K“,Ætîå%M)Ò'—Zþj°…Ó{èn÷PT_¤ÁWåtÉûª>Ø�ËÌ� O‹Ò¹kC8i'Q¯ŠM,=\¶?NS¯ˆ&ðpÖÍ]Iûö˜àÔ}EØè¦I£³.ñ…”$¼7h=wÞ‰[{®Ço¿ä©èäJ5Q »MN¦åW\¹º|), Ç3M‘l£öŽôdò-¾¸˜ñ¬[+Ùf¿�°�†ë çC°¸ÿQúzÚ„G?ÜŒ•ʉlh»—Ðv\6\#uæ‘f¦UÞ8&.ýš†_·ëb¶I޽ «T7qxï.n8¢…}î?‚¡\¹[èš×²¯ÀÚ8-Ü> ‡Ë¿Š_ïd?ítÑ­÷P<Ûã8•Èn@Õ²Odf†“6E šÅzöš1ƒLî�O¯Ýüñ�-KÚ ÇÞ¥%NÙ&ž¾x¾882jÆâ#cÈÚ²šú[“ü²Þµ/€»s»±GÓ:Î\QʪÂ%Œ ÎÀ“/SHY×�µpj®~°~$†œ]E)ÍW >ãÆ”H6} ¦©oKåkjpVçcPz|Ÿ¶®ä-g{qû1-vÜÆUÂ…¸yÒñúáÒ–Aõtú€*iN|-=¸«w(™b½ßZñ‹âT8¡‡û˜ƒÝn_Ìþ ø{ⳊG⬊ոjµ*zÜû@ZR¿Öx|ó¶W÷̧[« hIŽ3šù•Áã¦Ò]ÃK…Á {ó˜5•d·ë0G>:Iau�ìþ瑨2¸˜ÔêNKíüîS�ö ¾½¦?Þ0�!Áò [<ôBËf‡�ÎFmRƼ}9¨·« kâ,±dP8ï÷–’öeuºì抋æ?õay$ŸR³°ãÄö›„§tä¡Ãæ|ˆ•§-Ùð}ˆX™çCÓÝjèæ¶>ðõXõŸ¥ÂÙoöÁXÿ'ì¬ôJšg§ z�·óuÚ¸ú•0çæ¼µnî˜0‡wûö`­»øú»%Fx~ Ï*2û+ô·¶‡­ó¸g¡9‰Þ-ä(oç¶/Ü?%–npÇÀžw¨ÇE~]­È¹©Ïax­·Øë�1ÚT©ÂðçÉteÅ2Ò°>†?½ Ô+aßDGŽú³—K7֚їƒ¬°ÛD>¤—J_„«’CG´øË¬dî3í±ØeÆ+b7³E÷iXÅ>+TpN£ŒPà‘3¹ïÆ]4|D¯Ún™ïxTA3¬—ð™@Yœ´Ã—¬› cÃ/ð,çÄãPŸW–r\?]J x�¸…ºì,Ø~p-|†>¦LÇ«[~ƒý°^h”ƒ3æ~`SI(u¿×cz… TMpøÞ3¸·à”¾-û×®¨Î®x<]„ Ü`Lè? JÎùóì*øˆÖTl¦•U³ªÁañô†nhô{>åN8ÃãÌÍ¥ïmçsÊKTξ‹kß~„O{�€›d1iÑ¥éê|çX.´B)ìyý’ÒŸjS³NØ~ñÀ¯Miú&XÕt¦ËÃè Élsá¡EeXD–ˆçºgSzìȲû,�köBýKÕðñÛfœy±/Zô”PÃê=¼ø€7¯¾ö�CbùnòU8vñXß}!jÓp¸z™¸!ö ivÎA›£Ñ¨¬%‡?R wîɰ¦ÇT#o%2G0ÂLj}„òQ9{¼X!|4àuεðvÌt(.Ó` å21×Ó4îÖSGýŒÆ0¥ÛBàÑsÒú·—áüód4Õ¶Ñå?nÖÅÑŽ3`Lg97?ÏÔZŸÒ&y-üoË(Lܡƞ5É8ÅœAo`8ïmÚº­¾XûZ •ý›ASv°Á—¹ðg‡%¾�ÍÁ¿ *Uo‰…‹ô]¸OîV¡nÂBaÊä«8pVN_2ÿë¸Ñ3*Á!ù; šé€» ­EÇ«½pööƒüb§ ž5ÛÏOÛJˆîDã»Înü¡WúO{†�SÃù|ï—¤“ðIH_ý õéF}–XòŠðÙ,·¨ƒÞˆ£Pvžn²B’RÙ =M‡á‹OJ¼Ñåµ8o¦ ÎÐÆ!¿�Q³Óf­ÝC¿|“±õ„…ÐûÞ0ËUVѶq8�Õ°@¹üRWu^¼–WJ“Þ¢•ðø–)Ž:±…{©°×“Wôñ³“Xߢfa•�2MûénüJ¾¡Í=…]9t1whçŠç,^‰}r†b�Mš¸¼v ³‹þZ¢ŠsÕ�|ÚTtÉ¿@NÂY6Þ¾ü “œØjkqGEëª%‹î9ñ€åÑlÛmÌœ±lZõŸæoRGÃ1a8GòÀ|¶øç8ááGøŸ`bžç ¬8QDóE[ž�P ‰�NÂ×»Ýñ±T„�7hφ &aøée¯ÚuW²iúÍ:Ô'Ÿ_Éî!Ý’_PsQ�dCkÄÞmyØ;×€×\Ñâ¹™r8BòN\ÒÑY·6£�R7èq OhXò÷E™hú£–UÕÌhP³‡`8¹†Ìæ´=.88ÊâÚ7�å¨-s¹lî%˜°¦‘<ÂçãT¿"xô�‘ûmF=/[(KšÍ³›½±cyœ¨²©]Ú¯áj�lvÿ9$‡{¼ì ®µm0ËT4ÇK`ù@ŒG¾ž ^ xÏ2�/=ˆÏŸ¢Ñr=p’Ìfšñû!ŒY5+wÅ"dANŸj1qkÞw½\“ZäÇËëë•"ÁkœáÚ¾úTòBå¼ð±çrhjìË·MßÒ¾õ&  ÛôöÀšÜ6R|º­oèáßs¨6_�KÝ®‹á½}%—Þ)ð-i5õQíYûéýlšib ié#8ߦ'fñ¸ÑWAg÷$jë3ëÞj’Z¸îsh†#I ´l~4ºç¹ÂþkÞ¬ïpÒÏo¦œ‡ñ´Â¨7m Neö+Ä– wÜh•D×›~P$(àΙ%âÊ¥9`Ò_•¯ðf¾¤µRü”u�6ªõåJR²óWH]“ÝúZáÍ¡¥ô_v¤ðûe,Ç{®ãØQO Kv2ZîE7Õûpªú>LÙßB†óìIûÔH,¼ôãŸÏ+×êiýóÎÉÎßþ�b�ãéîÁ˜¾Ž¯¶s“ëÈÿ7›!ãjyר&øÓ>,:¯€¶½KE’)'$sŠ¿Qqþ!œv­/*;íàzÏ<üVÛ3?àwÚÍ?ëXtáÎ#�4°o:lJ®¥b“FT±]ÈfÙ¥x·Ç+qqPª;é1.¨£?í±jðMH(>SV¾á¿�µE[GÔ�½Õf݆F\ñ)Š«¦À¨‚¾¸3#YPû´¯žlã’fì 9œš‘Žï]&ðþÃé¸itÇÌ—à2]åšË\áÃQ+<é]Møe?Zù¡öáJ´T‡àŽ«¾¬rÙón¶°JÐrL4H벜þ+/o’©7>—• ú>àöÍBÞ�ÖªÙøâ1­¾˜´rcñÃæ`üãöVŒ¹šÀò²xஜïÌ%U}içkYË1¦Q±¤”3Ç7rÏ®£¬®üž3ŒGZ^¼ò’Ouª’Óç|4f×øäð#•e´Îg+›öìɉ•ãàgÅnö³=€oþœáôŒ‹ø|åF8¯ùתäÑ`ùþœ{˜wȲ~{".k˜"µ¯\…Ó�Âk^v/"™r{2L-WŠ¿¤Xæù›öþZ†ƒ||Ña(aë™TØ8†Ê>Õá†e“9fäìÁGýCñ¾¥7ŽÁ°ÎX_Pyš‚3îGReéHõg»X%ËÁKÓ.Óz¸tn$gé™âÿ8:Óp.Ÿ·�“}MH²µÙ*K´sÏõ�!I«”JQ(¥U*Y³%”} Ù·•Üs}‘%d«h¥’J%Å©¤Çÿy9o昹g®óüœÇ13÷w¬% ·„C¯äzòèh!FÀ >̘_;-ŽÁ!”Q�(®Í�p­H=æ#jÎæÞX¦ÈQ×È�àãܹTŠ·¾ýïýoÎüõ®ø^Xü�”¦¼D�‰�œìkPåó§¸LÕt9�ùØ bn÷°¢ÐÆeWܹ�æ§¼¹í×�n  tŽZ$u6áãØl€¾ü+Ä!¼ŽýH‚ÞmÚ¤5“SÎQÄ€ôxÌû|Rq§¼oÙ¾§oN&¢Wm8ú<$Ô²»Ü¹%O�ãì'ö°PÊÆ|gáý‹1pip¾úû—ÉnžÜË`ÝšnVr‰ø>]¢#÷вÿ Q0¯'»/Ú¡ú¹°Òçiÿ„’·ðl·7î™ É¿ƒ‘­xB-½­(¯Å=¸2ƒþ»ÖÀ1ÑÈß 3®1K”-ÁjN,¶½Š×Õˆ]±®ù Þ ¡¤4�yUÓ£©PSüJ× <§™¯Ê+õ¿Æƒ"Ÿ;ú¶áŒuÁ„çZ8QôÍ$~Úî¸á¬ ®¬ØL¾¶ðÁ¨§>›Œc¢ÊHh‘6.®£;Lrá…›†]÷Ç_€·á*:0&À}Vrá~Á¢›4*þ8ŠÜÀczµø}ïÜõÊd“Y…)í¯Y×·dNÒ½·¤¨‹u-¹\K®Žóq7eÉ#’Œú #ØÐ±ˆîëm‚èÇ~¸³{ÖrÖ‘Í�Æqÿ™nº ÿÑÉ÷�V–G¯™ì‡çÞaZ£4Iòq¼›“±ÏAƒ:°ˆº´µ±\ILoÁ3OPÖ%:g¾£ù6‹!%Ž!ísnÓÒ·©¸/f VON΢^ß^!ç­+–ŠAº¯isb&3`kzá?—ÓtÇ 9t4åÈžßMcEvÃ*3FÕ1–5óÓFîò-\ç6+ØkºtN+rŸÚÍÀð¤44Yóƒ=ÛOƒ }ÈÔæ&\'eî‘NlG#·»l%� 8‹rݼ¦Ö«j GÓPÕrš‡BÄþæA(p£TEËŒì¥c§œ†jKݘ_4•´«:£bž,¹”¢†³Ž<…¤º ¶2mV×o¦ÉÞGÉ=Í™œS[Óõ/ñWÏ@xël¿åjšwø/¹äh°ãÀiˆs^N•ü¤Ýó¶Aóy'hÝ6ĈX„0ÒÍ»@ |%¸DÕÀDù18¸3L˜qžuG!·Gäù?“c¿Î€´íΕª(Ìé€óæ¼P€ìfÄâAU ®.ΤÔ3“þ àÊ´+PÛùn\yÁgÌòá4¬1І ³óÕ˜°ìæÅ«šæ�ο‹~�¾BŽ]A¸h7J®¯¢²¥Íp(Y+ËJ\('l1ž‹WƒÓm§ÈÕ GÉ­CApn¦4 rîæ6™Î€��ÛáV¯7½¥çEŽ“OJðwï.”pøN„ò¯ÂÞqÚþ±” .WET`Ã4Q0kw åKì B§õ®Áç×ùaþ›½S{i�×óq¾Sä>ð˜]yÇw"‰ž�¾ :RQï?ö¶ b|RìԹܯÌñôP”9å£íÓ8±¦õ¨­‹Š� \ݵç>ËÄmëü!BÆ¢¤mÐ,5þé‚mß3²¿d!g°»—ÈûÍ')U‚^4‚?uo¡—ˆž®º�sV…"�Ç8¸ �þÌ™Â9èX‡¾ƒ{éÀox;9 úvù²hTFÔŒ‹0�MÄ 3Ix+ W4Pí[:e›l%�Lñ¡Ü òÁÝ}ïîG/³|ÑŸ€¿…á´3oÈ>µx:ÊÝM-þe‘E¹<œ%Ÿ›Àï».”7üüÒÅØ~¾‡8]q„3zÙ'¥}l¬L/lH›åçb5'åÙvàÐ6Ÿ«což+æ‚Ï—l&÷â_êy¬—þXlÄÙk„QOœ²Ž£ë'œ¨óÄÚ$<Å·‹¹‚þ°]G¤L´K!÷> sVþξè9sŽ¢öõzº%÷­�ÒáÝÊ#±�¬Úkv7´³ƒ3�Î3†Œr1X{QFZ¾�Ùÿ%�‹i*v-8�M�GHt”ˆg–Ú¬*<ü*ÊàC¤:ç|ê#zÜqrN4¹ÌÝÀ8¯L¦­’Ó©z1Åmõê\�/Y´Yî-¦œ& p[”N.ÍËÅB÷ט+sÚoSG¶„(PRyö:[7P)uô˜Fˆcùœy^ú/»…}«”ULJXk£0šš9ÈFo:‰]ýÀ&=ar;–CHïNh´rÁ¥_‹!X§“ð9Ž’[®£Â¦d’q§³»–ƒrj ˜ ¼•%éÀlŽÝ‘ŸlñólÕ´áÜ>— ™«~�|#])ªº þn §r)s!«û(³Ñ¿оl¥EŸâígžx¯Iø¿\eíúgq¯&\§g>l†óõb OVFÊ5}ñ¤Æel»ào\Çá˜#/y�soëµ1øB7çÿaí£a±õz<³Gè“ (ñ.BÃOwðdÆb<ÿÛžÝ]¾ˆL*v�ºf˜5›�c' {ºù±�„3çÃ`[<~”’á�˜ àl’F‰­‚Ð¥À ~j ϯjÀH\:­:VÅRy¦Ñ jþ N6Nã|:lE­bzhƒs�&äByýe¸ßÃãÁäÌ1+2áœz.Íìù�ã¹Þ˜ÊcRå)Ðô�„.îv¬ƒ."ÓAK4÷ ¢~�9+a¼–¸—L%ÿ¢ZYo 9¯ÊÈ«’Ù°’Q84ÞhPº V9í{ÀÜ“Ÿs¨A‹ó ËZ¤áËsy¦¯z6Güè_½þ=fˆFÓ³�çpÉá6FîK5µè¼KÆzûáÆTžÐ©k#Ì‹F¦�£wßFB÷‚ÝpéO ‘#ÐÅÜö-’Q‡'Z™7µ�صçLä ‚ÓoôÐ?€ïÖˆ’hñ>Ü(›Šša×ð]Î"xú¯šmP%ÿÖzЋªi 9+«œÄšO6°”Ï‹´þÐÂèÀ~Òý+W[wÑç›·Ñó�J\+a-̼ ¥¼"ÌÝÑò˜ü¸C�Έ‡c<>äï3¬ò”žøË˜×·˜´‰Ði{nÂùI{�Al¯9RmŸ‹·Úø=4­’ê�Ù£±/Ÿ‚ŸþB£W2j§Ú™²h¬–H³?‹áó7Q8÷Ž ¤?¨´3 EY‡]äýX‘7Ikꎢ›ë 6õÒ1¬—ñEï`=øtQƒG:S™skH¯ ¼è¡<î5”Íõfs (cq´†Î�÷€œЇY© .4Jô=•¸E»›èƒWq¦àNhX9ŒÊ–€›”8µêå…g§ÃIîƒûì‹�óQì¼'�ÿëÔm0©ÿ8±âãcUÙ�8q^é5�ìò�oć«ÎKw>$²3á§zjåCo<»'ÒÜa²i5®ôÁI—+pÂyJûJàSÝ>°†ÇÚº”~k~¢U¯ýé{žFܲ~9Íë¶ ©ìz*9‹ˆÔ·ú3ñüÝF:´dáÈâ/Äóª]ÚK?t†‡afOqÓCæ{Ÿ+–TÈàìqüpC€qØ­¥Á¯É…wY¸©Ü?ÚˆbÛÛLÔ½V<ÿ(Gæ"îé«‚Çö7HqT;}SeF™H_ ½¾˜tUHÑ ®^é=ðÛ$ƒgO’ýÊ%ø4ïì‘ÙÅ<.á!¿Ü…ÐÏÒ¥yˆƒ®+éÚÎ!:ÝOie�ºŽ,¦�›ÅáiÛu²© IˆgºÈBXâ¸\% R³—BÃÇHœYM, ¼Éá”"âqrŽ&8Oé"*.¥¶Î!ؼ&á0v�n±¥û 7ÒS*[éÜ€Ëèà¤BÛÖ¾¦)ÅðMê6ÉŸ—@+;í(Ò �š0"ô–d’9(vî{×Oñ¸mwG;Ó0ÊÌÄK`Ý~E°8�J†K%à÷‡9äë¥L§Oæf‡f¯÷¦“~ÚÀYøƒü](Ä9èQBØ÷ ø3òy^SÍFôv1ûÆnSµŸD¹4–ÆÎ{Ç\Â(”Åš‚z¼!¨V[æcÑ3Ñ-rù2t–œ½fObßÊ1‚3ÃAY=OÏZ·�’$Ñ<µ{=<�g?åAÙ̉‘Ù¨~Љd4´QãVÔÆ…þ‹�Üdœ>²€¹zqŒ8бEB©¸«h„.ÎJ‡£¯™{<®ÌÁã—ɺæ½xáêG¦óòtT92TâïÁƒ=DEÕ§÷=ÂÔÂS4ðS0뮌ÙöÄÚ8ŠÌÚÌGÆö^ÄíLØßaðzì^œB¿öîë3š0\˜L2[sil®(ŸÊdø‹ÏÃùG­”<.¤*=¦Ä:hyÉ�>îD 5Xð'×ð¥áBihIi¡ÓEêéF—4¬˜IMŠß’’kpØÐ¼»BÁLÉ gXg‘‰ «°ïë8sÈGˆßWú¥Y†ÚRFkMg°]ó¿Væ[nÂÆåçPŽIÂ.�Ûø¤_™Õ ¬€+�tÇYr“jAÊsž»%}±­Tç�?}²'7د&úNA˜nýOønÝh„à„�hêØÂîg‚1ÎÏÆeXhóËD½q9ôMi 1ë•@¶­›dýò$®÷…I’yy¦;Ä´ü'‡®›ûiúá•�¦4D^ä÷“gªÁ¤.…ž �yš Œß™TVH5ÔYÑ8Ka2\넯Ž/Äòãò—¾�DÁ‚ Ú4òyWzÉËâ“Ã̡2-xÿá9i}(�/²DhÈ™7TmÔ Wº‘ ßÖ‚šÄt¼¬wÜxæâÅ­s°K�³3xsõjðo@žÇ<è_ Š}ó¯ÀàNxð¥Œ^3Ú„{²MQ<7.hm¤'§w°Œ:X럢`™ÓF&rÑSXž$ï¹¼›„ õd‰ÒФ¯ÎGÂ…rp<5æ+Áòï¯àÅgÆÙƒCöé¬ÆÈ»6øÊL•Ix@bî]Ç�V¡ÄtÍ:PsßG»^!íºJ(Æ›Bú|kH㺠PÞ(@*U§“a³è6(‰ƒqÒ\i°�¶ˆÓ˜wñö¹8båk1ù”{¬ˆýsŽ�rûÙÞî[Ä7ï:]Mœ‹ÑÌê 9R�9C4$é u’=I–ò�Ñ�vŒáÙÆxxû!H§©wé�F°7×1_f;2®‘¼-5s<ãRRéùV•Êä6B�,!¹XïUJ–Ü̦ö'"ØÙðîüþŠN¡b¹á<Ûæ è®gMÀ_ñ8k{§Š6/%žýÊ_#»¶³ÿYߢ7ýî°Á‹ò‹@ž <Ñz ‹|èémoˆÎÕ�ÝŠÝžÙdÕ̬2µ$¡A;é�GNÄKlp8ŒŸöÅÁ3‚`ÓJ�Ë—£ßËrº ˜�¼dä§Œ9·þÁ ¦Ü9OÇ$b»{*5M DÛþ88aÅ2ßâ#‰Ûü9´jÍ,3�Ààìv«…'Zò•“UKáÇŸgÄÙ×�¨ª@¨Ûa¼3+Ž‘Y°Œ’¼Év÷ �½²˜òÙŒæÆaDœð@q{uÌ"¿»›hÔ÷ú¶³®tÝÀžqqäM_–^¤Å£¬>GÝ„`z%ôkÃHZrëUÜ@þ9øÒ¼Å¶°Bò ޼BŽíùG³¶@öñ¿äºV8m*ÜOûwñ‚vÄÞ{1Ih†SN’y¸Ýš'ÝÐ/=¼÷šâ4ç X×lƒ�9èÜëcÄöÂRÔÔ³µAL$‰=—@ë–™œþ‡lðƒÞÒ‡4Id;¸o¢{­o3¾�ŸÓ³%õÔmÛ²á‚qWvÃÁ@q ;@sï�±Ä)B]¯Ñþ,~F¾±îÏüŽï“Æ 9ð4R]úDp+3ÔÁïR£?å¯á¦Qo<¢" âÁ­$ñmÞù5ŸÖPß›rð©Oùˆë†ôñèšóñÚ¯Ò€nQ¸,¢E¤Fˉ…w9¸(Ù’Èð’ÃÐà‚Üœú/XB‹å1[ò7Œ·ü¸y>rîÞ¦½¡\Òá¤�R'”¹+GXºë$¸0 l¾L+²"iÔêÎÐ9rÖ¿¦A2?± ÀB»©ÿ’'ä~Xs:è%ÙõÏJÚ‰—ëuŒ«L"¶©JäN¬±*‘š fp“Úî©C+åÃôoëö;o“aÜè8Y8#—;e'Ýa*òŸ)µÛ—€7k�À4{&™çm[/èÿ÷©2TÁ Fïè rR*�ç°�Xw¯¦d˜Ÿp-Ô‰ú W¶B%:¬y },ŠœA—ínÄh£¼©z(Á?mÙÄ~A‘Hf¾=(¯¸„ÿ–§2�¿J±o@w8Œ½‹§aÁêbRØy§RdËK:kA81?³Ç"„IÑ÷tâC”±ÙÆÇ?< ­cÓ W`;¦DŽí¿­TïR†{5’׎Þd…lüºV VO–’m²ÏÉ�ÛQÌ øÍšqÅøV0]‰uÕ}dݳ|ô{~G¢ilÏ7tv)¢™šØ3÷$~‹édwyg^õùŒœË]H8f„BA݆ù#hetéç0ê A ãJ轓ͨ5ÅéÉCùL£Æj,Ö½„–öexb£ ˜ÆüdMfpàw\-vIÕò¸>÷ìÚ ‚ú·+óæÞ Q7e`p¾?¾J‹§ñëÿÑ@ƒÔù*eÌOíc–šý!½kíÀÎH†~Ya°…[Â!Ú‡%é™e⌖™ Ò6’kg5ÐÉ ø× ÷OmGc¡y`kŒ£°+è �^ܵ©�'=¼°Îi€DTò0ÂÖÁHn×ýE…¸´°…W�Ü�§Tt$½‹»˜mñ-ÔðÛ¹³{„ŠDGS %ŽT%?_J»¾épp™0˜ù|¥û+¢ñ°Üúöùkºðf$ãz¤ƒ[æOý¿,'¾Ëµ¨X¤~w}G–‹ÕÃŒ}H3ž�\·eT%bˆ»È%%GN ÇCYΜ{Š0ýW>�w7¹ø×¤W«‰ º” ·rcPM¨…û^Céê°qrrƒø{v(·e køÓÍyIðÆá²á_å ð4JÆsžA íhð¤E›P\&NM_>BA¥odqb ¶¦.À„àõXQ˜†‹S¥@0Ç™j’žÅ‰´ä÷Q䎇ÁM“¹˜P–Œ÷ 6ÐáOð,lyfÄ%/”Í@¤S–svàÜ¥áðYÃÿ÷ès7Aúòæêôøᵸ]¥²°tÕlò¥]�È5Ü£yaDÈÿ¹â¸„éþ}Ì�Ÿª¼°#� n�Á]ÚiqŠ4±:|†Î_+Χ;iS/ƒ¶-‹ HWµn•ÖÂ4rÖå ª¯*’7�,÷e ´<ìÈc¯~—Çßsåñlû 9_xfy.DY÷ˤ.Í.mUgÙ’"<â5rcVáæ¦øó`ž© £ÆJœO7¢ø%°s«`6ߊ…ÿÊ qýé*æÂA3<ö"^þWÎd/ÌCÉ{·Éƒ�2(7÷<>jÔÀIgØB »Ó!ì~ |�…7~x ¸jz“¡ hr–ŒŠ§æ³ŒéZü�Éo†ÍÁ,èfÊ�‚èm5°óý Ù;É×å“Ôß`?u*m¦gÜ0ïy3xÉ’zræÁpUp¨—%Þ%+ðû¡TCÛnì¾MÜžš€ôL#øà$CÖ~àclgsðaëAšÚé9å| øÜj:üáD×i²@*áÚ“2ó‡¦Nì„Ô”ïäÁ|!`~ËrÓ˜˜e¯ GÏ;UÖ\ëÃ}—°²ÕJ o¡�'6aúJP½æO?¶†O©�¸ØÂM^ša؆ØJÞ‚ÏôngKîçaL·ëÃ:óbÛ® nnF˜˜ƒ§2©Ë€6ÅGà)Í;ÐY?Ž&ÅÒÂöe Ÿ÷™®*p¦Â#Îìþ›—9_ɘ—d±}ßÅ\gkÔR¶Æ.7HA‘¾9}�–@ôÄcÐO\ Ô½|`&Ÿئƒ5Àº|'²Ïr‘,™Nºo/Á†ïoQç�z�úÑÇaÆ °Ùe« ߯E(]3B�jM‘°ÉFž %Eû*©áãf¯f3í\?N,Úç¡ÏóAš3`DzJO1ïž  `§ B6|Ñ1Cžµ{PT@cRgÿÒ·4+dš¯7c‹U›3›ñ HÓî³ÕÜ™#ç¨ÓÎ:\ûýÜSÉ#E -~^Çú¥¾šº&`Ž*°™ûi‹àÃõLÇÂY¦ôÁSzßKl}¥Þê:œxëKœç&Ò�zJ°rÃ"Éõd_ïK¡kVÈÀ kqºv+ACí˜û²7Hb$R«»Â˜4˜Gy7:ÞŸ&fû.{b‹ª ­h‡ÛFÓ8ÍÚ”¼ƒ~Ž©µ½:Øð®‚Þ~}âö^cU2€Ïu’VOÍú„¡>4+ü:¨ë·]ä?g)Ìq¦ F{­é—¡áÔhÒÏ= üÕ¸õ¯[¹�þ¶þ­¯ÚÙ/Ê5àQUCgô3Óš×@ØfEè<šLûEN?Éú <—ÊÕ-ó�—4aõ ôúMB å+“•Ðsu2S J¨ºéqŒWrÇÊl ð~G”Mó(ßñfæhñazð«"η¾Áñ;D’œØ‹g>3çG–býÖ[h[³žv¿ã¬ÛNMžg@ˆŸ"Oå‡*É4hpØ@wÝj¾óèÒ²ÙÐé*ÎÕ¶MÂwp ÏþÚG›Û¿½÷YTCÆ=P`Ï}fÇ_Eö`AÝÜ[C$Ž‹ ÔTVöZî�7˜ü��dßD¶y„@wú,­*ö@~ˆê¡ÌîÙ%�3ñ—éJJÄ5#4äæ0#óÁ ©àcpŸñ„ÊÁ†ÇRhüÓ†HH(bi×,Ø¿Fc;ïÓ¹�¶³ÖîûÖ7Ѭ÷�ie©/¾9ZýäHÂÅ,ˆ8 +‚²¨ŸÛk²µÉÙ Ô2þ#åbI[¯>a:}¤ ÁßÏ Í.œ¿mÄÍ̤†{Œóˆz}°�§…4åÙ%ºiÚ!Ȱ*¤?“qþ†â³NЗ§–Ó5¥Ïh”õi°ÏՃȾúbùjÛ›ÍÛcðö‚,¢õé2™þ�–LlÆýLjn‡G 98Ë*.õóãµèDâà)އüβ=Ѳ¸?P™ÞH�ºAôøsH²¶UzNoðå�‡ã9ÕxÀ>‡žº‡w¹wY?��k³€ðýØERiï ½J"6FÃÎ% îL‹Ã°OÁ©H5²q¸™*«Kv–ػ†+W,‡†@ ômDÕVYëÞý¯LMÊIxÄÉ’3žÚZ�ÆYT»5ÞÍÛ>5^'ÆùÕ=¸6| í„O�°·À¿Qœ<­‹¬üuÈêT �ðqZ«¸V]«&Äñ2qd_»ê Üj�"3jèõúÙLwëQì}dƒ±e ¹Ö¼‚œÐ£WÑËçá”§ ÐD�¶­ÔÖÕh™¤8¶1Û¤®ã)Ù›¼ÖPä)�õ¨ˆqÓý±æb4 ®s'ºÓXYi�éž!h6o̹‘D¼nƒçï}@‘ׄˆY¦ã»¦Ë »n€Ä[&Ñ ^ ­(ŽsG�3•+qûô§d°{3þù°•�s‰¥®—6éìõ÷¨u%…xÒÁ^^îî˜âÏ碰ðÓCâiwžiȰèEßô»q<œ™ÞÏtkš@ÿ[¿Ê]£~ «F伄Ƚör¨O§ëí&ÅóñÛßudÏ“fŒ;%‡€Íâï©å´z"ã�J®ÔoZˆRµ"TúŠ.¨·ËA¬ã,”`"èà[5”štŸh<ÙhI˜•ËÐäÝ)»Œ«:maNÒ09«ØNm�íýׅ¬ýD~ ›Ú ÊÓA£4ÔŠ?G_ùc£XÈD…Ԇ𤺊Dûšáƒ€ÝÐÛð•� ÏÞabóøíújž¨a¤‚AwœÉ½ÌIbÔô’¹óW¯ A‹“;zŸZ* VÅFpÚi1Vþp­]!Eåš®“•*IÔΦ ^º»Ã•:I®±/^~©‚‘¢YTvÉ5:ãÜZ²®U†ÊÙïÅm9KÙ+¯<é:3^J`.ÛÏ'M9y†< žÙ1€áÁ;ñ¬»‰§÷PÇ6�ªõ6Á¼V èÛc‹ eÒëèIÚNý7 ÅË©ïÜžEÏŸ ÅVŸi¤xýø·S¯Âb·bjp§Ÿù³´‰¬<·�±Î\ÌvXßeÏo*bÃ_KAõ°-ù¨âLŒ´Ð­Iðwý¯Ç›þáäáø j?iO}¾PÙŸÍô«íZœ¹«nF ãÏÍçÀ#ßû‡Äß’™5ÿbعë0 ¥ßß]ÕtÇ­!R*ÐH“å�åQZˆ/_\$ÚËY†�·„]þÅÂð¹”$T±ztO“­ú×Ü-’…nÛBº°ª�i[¹ÏÝ™�ë3w’ÅÆ§py�.°Ëï‚ä”VM¼ºÆ¤IJáŠoŠP Ï‹åºVDõº=ÚZO‚溡„{‹á%´XÆOÇß&ŸCòÈ x6ý8îJâz·ãõêÿÏ&!Ö{‡ù´Dd«�u”8<®ÝH,ž3D_* z÷9cž�*ìª(¦º[¢!x6?’�¶äõ33ð=l ¡²ÓÒñõÑÿý«vÄìdIS]¹cGý/q xÖxRRq¿°â®<ìÇ^9©€ŸŠÛiìÙ�mzƒœï¿dXuÀ¯’©º„çÏþeê¥æ’_#«A?ð,-¹g¼ñ…ÂRä¿ú�Î0{Æ{­€[ß�“S¿ìA¨UˆÖ ­Ä-5z˜§-:1ó¦4÷so¼Ì`Xo}g–ÏŽL‡.kôu–„݃AøsÑ vPáp®ïBWçF6ýg Ù[åHfµ¯ŽðöÚ#|É#Ã}¶½—]¸žŽIô†£ îrÏpÿK)¼˜—GîŒ&‡ü@rMÈö_Ŷ-à2±cµ|qx<“t«ÖÒìS¡D¹w=yµ¤‰n‘ GÍ€Ÿ^U®/o¢›.íFú_ÕÔðC)]7æ /—ÿë Hn8¦ºª¾¾Àœ e•¿ž¡ò‘´lã4N¾•4™þ…ˆh/‡¤ÁRbªå [õ¤pñ•‡ÔäJ+Õ6 5­waú´ã½Œš÷ê!´§ß"¡¦ëÈ[æ(3`¼‘®­å£ç¿æ3Ÿ˜dš›w“·îLqd,µ–¢¹Ê\\”‚s�“}i™#ŠŸ¼jIt%mŒ‘VÁÇA(uWeß�b2w½ìŸ÷”üR¨&wãïS•y¬ºQ"U*aèíÌ/o¡M‚�¬¢C$¾cw�ÚRÅ/…x,fÐPwà5y­ê˶˜TÁ„ñV\*KÒjÔáFþz§¶ˆÌ¿òšÍæw¤s?7�á†fÈ. ‡€¬mèïü�n·é Ó�Nm%.ÙÞýk^ŽÐ•O °ÏG\×n€9~�ñZjˆq~_pÁ�磆q>œ›ø@”5ÓPcñWÒŸÇxlÏÀ¿+áfá«TÍ~í{³«Oߣ*3àmš x6§iOÃÁü4�|1e¨ S�ä¹vµ‡ßÐ̾f&xº&ýc´ÒnÁed¨£¢C_“ãþ; ²N…¡ðz5îEMK¬j¸‰Ï²Ó!eÆ0Š2`�£"ó(< ÝMV9Úƒ¤‡*<Ï!slSh#û‰\Ic–ÝXÀœ5WÑËjLÒë ªd1«ÊŸP‡õ1¨¼ôòhá�›`Gƒ9ˆÝoÁ�'ã°%; ƒ†�ôËp!§â^='K.^bÒÎk!ÓäKõ’”ïÛõ5ÁS!i0<� Oj³! ÌrÇ�U¸†|WŸQáükÀ¹4“Jqn“Nk†[wR­ÏšB¿‰ÖK‚ªàIškC¨¾» ½gÂÁ‰Žµ '" ÝÑßé’Ô.¸»íq;ŸN·‰–ߟüÌ�ªWz¨’¥,œ+ÑCzƒœ<Ä)‡^�îlqh_M~²ô±U]QòŽjõâuÇ_„—eñ�Y-ÌéäûÿóV|gPCò$éÅ�¯Ao’!^ .˜¿Ó¶¦ã‰‚>KpMù Vf:Ø/)KC„Òä_…ôÛ'TŒmÃ`3iÌ4�êÿÛâ=w 6XÊaíþHp{|¸LïÂÛ ß²–Yïrй=ŸMМyÛ»�èÍÚ‡šíAÙ¡ßõ€,Æ£¹çi²vo¬|M¬Ë?Bo¿´žµ§Zò(8o-wîÇ~Êsê%(ô ƒÔ6–Ì p‚lwkx®ZÏ´¸ÜäK¥oÄñÕt‰E ÆNú`I€0J?XB‡�ŠCèCWð]9J£ÄÜÈí"dÑœ>ö=O?¤ïÉ%g�þÇÞ”y¥ÁƒOîÒŽWž÷"yûfô³bÁËI—6^ŸN'~]Ä„Vß‘ºJ»›a é8ƒ¤EÑW·™4‹q™ÕD?x†±'³Kñ þ週¥‹PÅd5n¼IÝ\£i‘ƒ!ôž¿‡°ô)#î8Ry_¦€ýÝš‚¢n’ýïbyG&JÆ”¡Á§>¤Íª¸Êê -‹K A¾Wèɇ’²/ÄeºY³õÿÀXR�$;pÒõ:3ó»-¾¢™ô?[2ëe=ðÛ‹†õ/…oŠsAcM>9Ü–KB�ƒCq˜<Ï‹ÃÊ#–ÄZx$œ—á®Úƒi“2Ü…›ÖÃÑ\Ø¥ é¢qŒÉ²6–቟tbç4n�\�Jô%)RÞðå`!=Q·z>ÝÅÙá×aÞYGœÓ™O~üÀ«e< ¸ð1|_£~[Ù‘’˜¼ù%î““¦¦«SqFP Môp‚.Á êÁ1£uM¢”;ã=Ý-Åý¦W�Ǭ>¡~ä]’PÕN6$„ÓûS:öîU7Hí)GÇdaŽÙ‰’0£Ü†¨W7€¦µã\·r,[’ óbÐ_;˜VÞåSº<йùŸˆÙ‘p|´¨²ë_`ÌïlCÑÁ\ìh–Ƨé8S~„yq&LòÏ’/o´Á÷ ?Ú~½J B¾0£œ§ðpi1èhMÇw©V ¤ÂÏQÛ«†Ÿ›éãmWqbJ›<˜äÜ %p%¢Vw^þCï¬‰g\"¸ÅÓÑö#>ÄtXgT*’_¥ºTÊ® µà"mX<‡Jzå‘+K1pÑa2ÿÃ"ŒÕàæn¬c�Ì*†=NÍÔȈ AióHÐ3p‹ÁGÛB m/þ¾‰Ó·?ÂÏ©ÃD愱·…»¿kVÛI^ ‹ud¡ìçT\iɈäÖCcz;Ö5§ÀÒÔ,Ø}t-Ìû#Á•íQ¢ý:(�ãFrSf3hb~xèÓ©d8jüªM“È«Z˜VQ Á«³@42šõ~ð�öD× ¥Ø* "} üéWŸûÓÝäi¤B8ö;’ÖÒä]d,X±ت:2ú>õ5û©óK^îÀ!aš#¹{Jû¦j_·SöK·!|y›êÿqñeãUè{2N‚Úy9³ø@RýŠÞ¤9T�P�t¯Ÿ»oåcy{÷šï�uÌÁ”`~EÍ„È\5,+ÐÇTiiºðî$Ó"ΕUí'Ó½hhçLø/äá©�zâ—ÔÇ„-g‰Þ–pøÈR%‡Ï U¸�ËÑ­�¹T3G↵‰OÑE*€U'¬¡IlS “ÈÏïhïø 4TúÉFykÜ™¹ãæ¤Å½›¯Ý« ¹=‹@ìϪ¿QOÇ^'žZ¾dåU+dW�!½Àw‰ýJE²H2 8«\�g4݃z‰Ñ®�¨xf3 jiã݉½$·ú1Qü]TÙÄS„ŸÂÄ îi. ز’5NV 1›·‘ÃñîtÓã•8¸å1öÛ†NúÚx_¼j~â’O øe†7'n•ëA½îØpØ^{ ’ß ¢äèûVâÛW�Ž:1«ß‚öù Ã×u°ƒ[Cm¶‡Ñ+ª1$ËÏ�°<ТûÚ„�as¥9”Ï©Àa‡|¸nÚO¶Žcw>ŽcB…FˆÌÖ?ô4¶Ò‡“3QA7Šy;ÕÿáŸU¨Ô]€×â-áðçjz}ª~ަ“¶¯©ÇdÝ‹ÂQ¹d8$Ëc²C•ø±·‹ã_±·†}\}XÏ+„ZÜ cÔ…l×0ê‹e“c²ðÌʳÄdʃsg‘c>�$kk 3‡m%o0†wêuËÀ{?”W³¥r™¸5òûè{)3ùæ {^ 4F_£ë òíä ùÓFzKÁxu3ùü…æ­æ‡¢—¢(¶Å´œoÁzû4Ñ ¡Þ�lñÚÖ1jc8—Îÿ9—îví¢Ü #$@Ö /w“-·W3ooÜgßÚ rW~0E‰ÆQŒZ-ñF9"¾¸0Ã�©ûï#'ºŽÛb` /¿š“†/¢�¶³ Þ!FËU+—<#l?ÚeáªOî\ÊÒ…?o<‹„ê‡Jįd!ðjÉ‚£b,Õ�ljµ§I\fÜìHþ~Ð<ÌÿVùâ˜îÑZ Ëf80}J;˜a*•[AÿF)€«@Ùò{1²ÝÅ@ëÚÈ—…•(ó‡Ÿsrb[ë¸x>§þ­T`$üú€k~ʯ…¯H¦:V`ÑUØGÕêtaÍL?º |œUËí#Ù�óhÖŽ�¡MÆøVSy›pò £kXÆòÁ;4�,Bí ¾¸ ¥9òð´G ¾Þ `yŒ½N²>RŠ"©œ!ºãy1ÂEÞOHËÛÀ6w£¼ÐI"¿…õØ@òJJ‡3¦ /êžà>sOô ŠÃSri„“d‹•¡#ðgé6˜^á�]VSQ¶‘^œ# ’³¡’×£’ß&úÇÿ�ÍæÉà!‘ Âs€wžtåwœUšeº¼¨[\ZacH¦Í=O�?¢«C’¨³bŠÏºÉHþ·”;ùXþ]Þ û–>Z-¥6IÌ ¤«læ ïu¶(…a�ìoW1°..¡V­iäí+x,v‹,È g&5tˆ*•¦çüƒÑÞP‚ûF; ‚îúÀÛ}Òt†B½®q—”,J§_ïmÁÍMòJ oœ†W†x9ì—÷äà�õØóõ­Nè‚ó|ðKXNRysè^¥ùy„…¬'y¬QN q“é�›pAdÃhï%ºú€ª Äac˜‡5Sk�Ûè`×Lwì–áp¯c‹é/¢ZaB­è%»‹möã�`ª]sC9³ÓÔî^>õ˜ÉR�Œ«,³×“Œ­zB²�j±`R ñ§¤!ê)n)‚HÛ…4h)æø›¬ó°w÷qj)B?|o¢|›ÊQ-L*�B^-ä^…¡â2flùuêeŽ9Py¿9ãÅÕå+«RÊ�=6É|pP¤œœ\úÔÀ6zž@Ç5[À-:µÿUãÅðLÂó7�Ž»d‚O�–Y5Àa5wòºb‚–½Ñ�¥öCÔuû{òBý2) 4�^dYú²£}jHkÀæ«þ4®g5yüy ÔŸ g>òŠ’ì7¼$p³÷Û¬ÓRÁÇ©2? Ö+ïðmƒˆÂrsë8±Îgž6Á5G͉‘ûrœfa˽îÛKNø"ÌO¯yCTw šå#q¿v VŸ¬!íz]¦bÏã+„ÚË™JÁ¯ eŠ˜“´žd‡a+EXùeÄ7|^¾r¸ÓÚ¥Á´  ª%›À\!¯øðCÉ·28. Luî‘IbdýeíÞž¥ÿô}¨ ‚ëæ&æoœ ª¡w²Ë™Š;°ÉJ�šoVÂ*7!îÄ¡l›ÿ,&¨›Æˆ£Dí½Ž�Ç‘‘Èe08èt°éKòíO2{¹«h÷+)(öiÆ¿GC`×D0¾¿;ˆjm9LðXV=r {÷éâšþHØ;5#³nbvÔ0f™}õ™P¾»zÄ�Þrc\gÙJ’�VÌQ¶ƒ[ñÇðÀ¡©Œþ¬ ûf~5y/•ØB.-ºs¶Xî5™>§’4ÔKÑB{ˆ)SƇó®ÁÕˆ5rŸwï©@#¬¹ÞóTšá�ÀL/»ƒ»ÆÏ€×•w´íãTn¨¦Àþ=%x¦õt7�Àà50z!�³]ÉM_×� ¡_8�–¹ª»Lpo¾5¼åÈbÞñ6"4Î{£¦²óàâ4>hP›Cy—I³½gáïò-Ëûê–á+‰ÊSÌËy©ý–8eÎGU‡DhùVFª,~ó}ç¡TÔ•¼-Ÿ‰ØÙè1ó ùä|·²—Af÷7öóö� œ°•öóÎÇþHbÄ:±ûY<Õs‚” !îüV\7­ƒ*ÄÍA%Ï©{=¬å~P<Ó›QmÆÓpårmÞÂÉŸf¨Ð]Güg=&Oueᥟ\ª÷‚(x"ëG¤Œ¥°¨| Ô¡x%Ëb_U «µ$fEÁ= _UÑ-<øŠÙ"_¦šâÛ!*â# Ê®À�3ZV#͙˽ASˆ$†Œ0V‡Yñiœžz. ËJ ¯G.U&ÞÊØÖaFMÊüȇmîÀÿ·‹^™©‡"Ó,ñÃ244ÖÃc÷Vâ á³P[ôI;„OgÄ£Jt|Z—MyÚ fF"«&—KVdb ®ÂÁ³©û¾4K¬øž”O£Jç¡×Ý?Ì«aiΧ‰ÅxbÊ-m® Cž¸¼tãã~—?÷WeR÷ø2¢ÿïP…ÿ;3,7Çë—·ÂYaúM0 ãWá¥*+8墌½éžC¿œ¸ 2Žqt¡‡4™Ñ÷ŽmPÈbß¿›b1PÞ·�î�8G6D‰�¤Þ*楶"$íúE†ž"µÇ¼aÇØ-`jÂícÏqðõ=H˜hBÁL_:v'•Ijp O I‡ikË™òÿ9äpž*™}ÿ$qI Þٵ̊0'üé:Jgß§Ýìp…£ú( ö0i¼©øAnμ'ˆf³°¼j;£â×@ìLJ·<%1wáé�pã\Ê.œÆ-Œ;…²ã‰$ÆÙb|l`Ë~cÚïØŒ’±¹¨òшJªÜ!323É’zEzKÌ ±fx­Fˆ(òlÅ5Cý´Ýz8–ÇÒ™†ú`s=çšÿoÇî~üÉO5-Œà]­4%3˜3QgÑîÝuÓ‚<wn(va÷¼YŠ7ž¿�òu»é¯3Y$¢E€)B¾ê(˜†Wß®ˆ È¢ƒoî�ÍÓDøõ?j;û3~#MÔ«üIÇ—UK󇼉7·-,.R:÷ð4’š‡ñÄkÑ ÆB÷,d yaÓêsô£8Rmã¿Dÿl½m‘�—Ü4ý}Ð…F”Á´ÀE´¹h&ߨ ¿”ï »¡Ø8…Žû§@qÄ><šéŽnžÏ�½£ÿ²È`S¾ÿÖˆª™RXã¶rš¿`÷–Á=IsfqÏvº.G”^�Gž·'à (u­yš~OÍß ;—odŸ­ˆ¥Ã[µLg¯>‚–-iØ©? ÃßQú¹4º+é׸px,Ló�/†LÿÐ.à�É>•๫�fÌà$¸Ý [b½ªÇö`>4}D2„ב˜’&rúVópÓRÄï/Ð×á“|8úž *%‰Š�¾� %|¡ôÑE[P ‰"Š ×P7SËà6Zé MM¼$¡¿•zòÇÀ˜F]¢ì�œ=³á9±Ìì§'Šœ¬Òí¾D,W A‡Ý(ImËÞ®»ÔFhÀ$´A\W�3//áPÚrm›½=}�x6®ÆÌ¾Lü¨¿ FRèœåG`ÖÊ1ÜÏVañ!Ø›+ChñìЇväÞápðòBí~X¼}í¨ÿP=ü{(s¥ñbÛ0µ™è¦?3}'šH¥ùÃàĽ2Ç}ÓÚ\B|a°;ì%‰ž~‘vù¯µH¢e©±ÅBîÆ¶˜ó: d.¬-Ä·‘ ÜüUêÜ·_V“�¹_Ùe ?š<·*%·j;a[éLnƺ`ô*݈ùw×ÒÝ'g£­¨wÆÅƒTUj¾ÚjÍÚõ~‚KWÂÏ?»é3ÍVê5ZA3/Qó{ìQg‰f¼9, ÉÂk«�nß…çÖÛÐVÄ!i/:×MRËés1.³kX”ŠºOž¶…ó…tS­%™HE݇éôŒçrná»ttNy†±ò´Haùz õLž“ŽNn\çqÔUšê{§4sÁ$1¨ ¤VËÏÁßÇð×Ù[Tš±sã"2qø»Çƒ*ÜŽTã‚ÓÏLd�ˆ“C «Hd’/ˆõ�1cžŠtë¥ÜðÝáeWœ*ñ§Ù{S¹I, @oÃ!²õH ÷±j²{á…hðž²ÃØž…ÜôˆÅÐ~z&áÛ¢ÒO4lýާ¹ðþÚ œèF]hP$£czhó³·[²Æp)É™¸O �GÖòœ—/Ü�9´ž||ÉèÃOÈZ¬Ë!1OèµËxký,ÔKÛ 6kâÓUõà»Ü˜¨�¶2åÇ+[”¹³vÂWÓ¶Býh øî[L ¯BOãH04娼&8yì-š‹¾¦Ÿ[¯A}U M•ñlj‚5èáóÃrºHÅËu¨= ?‘9E_˜â“nxʱBªðÉ‚o0MðË÷ùjFç ÿÈ^„cŽhÓ­K‰˜ }¿’‹òçèZ!È,äÑH„%‘,|r¹„¥'IQñŒÙûã®ßGmwf¦ÿk8ðâ8ð-m…¾ûÁ°!D›ú]—@eyMοGµ $ßC·ÌoÁŒà3¤Û"YuO9üÄC_ÝhGú1z?Åãw/Б�ûô䀱.Ë =_hnÔ\Î�—CXQ^ÂŽ÷n¤¿ÃÔPÏ`-K|¢›*Çiµ‘0&÷WSCÎòȽsÛó©Ò O¼ð¢ã–ÃÎv¸mÌÎêr&ŒŠIYnžy™Î®Ì/Äâ¢'D'g�Ѿ}�zéè „íXÕÈÒ{+ØhÓ*r² UVUòb¶Ýv*íO®|¢Žé7ˆwk»ÉHóh»jXø?ïtÇE¿™±#þ´@ï ».ÝœZÆí øA¼¦úØ]3 …_íF¹°qê1»º™ÜyM�pÏÞê»Mè6õ90œx��rt ™€< 4óbá¸ßQR°ô7̼&� 㮪qå›IÇe T‹üJ/>ÓGµwÙ0êY’Ñ·á½E1ùYϘ�øáz+t�xF7üÖ#vßD¸ªK,1Òu?è]c¶¹vBL�0 JáÀ+ûLºCÊ�¹ñ.´m‚¸vÃðëi.å?QMËW/cT©íFv0B˜S)]×f˜¢ØAÙ0AT„^bÝ“NÚo¬ ûÅR0^n�FtåP™»ŠàüŸ2÷µ‹ g÷‘Uä”�6Ï)¿¤ch:çz»`6-Ÿ÷ ¼Ë¨v m‡âÉ6dÿoÒ=ã--&¨Ûœ• ì7Àé¬E™ânü6•Ÿ³ßž"gúÀšÙ#ô¦Ç?Å“ð´y-p:x2Q*)Çi†š€FqŠ©G9‹?âAYsšô¼ÁM±ÒUxÛ¯\Äú+RÜÍ­äDEš †>e‹Ïp$¡ŠFüÉž'9ô}¹.zƒ$ûâ?fø\JŶ› þç>U}oƒ…pM¯6hÊyÀ¦Í±8A'i=Ì!>qõ„ßå5þ­žþ§îÁ&¥14˜Em�õ0k—".ß‚øWs/&âëg‚ÜÓ³Ý1õÔ>ÜÖ÷�U9‘…}›&ð G›;qêÞ £QÏ6ŒΦ¶=✳F¤ƒ|€�óˆä­£�Ê»’&�‚Ñ4 ˆxI©}Ö+r~v'I}9åúþöPÕžIr!´P˜óc¨¶\´Ä¦ Ù`6�–.æº=1á¼X,ÄùõR‡$ÿ@«Ñ"ô}�ËÄ8îïx9“¯¢+®åOâ±°plæ1xÒb½­8¿®¶@ŽL*sçh-ù0I'~Ñ77,àÉŒ¯ø;BÖ~7Æ¥e°C_¿|áÏöŸn3}ëÐs4æÄéG ¬q¡÷AweIë'ØÞÒÌ.Ta`Ÿ.í×2†È‡|Yâ ?ºRÓ~ hO(%ÖE8-Ç™~Ê*¡æ©»èæåø­S½ÇÓYõ� ê9Nm¢i£o1ù¬"Ìíøô Û¶¸ÒàßOˆÌ™käÀJw¸¡ÞF7-ŸÎÙÀÇÉ#a¨ªC¦Í?O¤éÞ:M¶Q@?•…ЇÏbÉ;n#å[D+’fâó•*œ�~�A[ì.â*b÷ôök¬#õ|úh•O:ûÅiåv{Îðå'¸îX<–yCcTV€±�·¤NεrñÕLqέ!AnÎíhôØ ]VÅ'Ku¸Jx8½T9ô:0¦À.ŠÅÜ5ó9aKO¡€¡•›Š®½y$ã1‹Õ7ÑšÆR:wn*yܳ²þHà×éŽÌEïP2ù#€³7ó,[ò®7<²ë‡ûÉ…4_8`x$+úHQ^0ìøù¢xKáÇï\”~Æv�ôhYg¨i?Už†®ôÔe®à*‹º-ÆÇí…aÆZ>îñŒ¥8�¥‡¥V 8–«#h“£ uñ$ÙÐeˆ?G ý©w|£áݬúçÇ#ºèF ®‰òwìpKP¬ök€Mì4n•—×ûu?\p%L…ì’-ÈâAíhÚü{+z˜òÕ |\V3šæÁçEî`n:zÊÇ�9\Éž¾åˆ"_-Ùÿ,•�y Þ•Ôém»¿šDÊ®Cßÿ^±'T`Ü �¼k~KáñÚTÞª‡Å@hc}äÉ[qÆ+’azô©Ý‰­øpA*=Ýç†*;¬ !ª¹Bà‰/œü«Š.Šz(Dó0,\’H¹\ ½“¶¬Sêæ3Š“¦P•¾[\ O¯8¸–ü‡Å³kè�œ6NçêƒÕ‡XH=1A–M㸇ÓÅQdæt-t M$ävf…Áo%ø¶æÜ\¢Œvû¯àÓË,©lZJx·Òëƒ0ÑF–¯‡î3‰Øç·‰<\ ;×yá¨y4¢õMlNs²ÅuÇÎ�ŸÚÉ$ûu[ÈÊr£6ªë:}”¾Ý�I�ÜÃ6°}k8jµá‡q>NÙ˜:¨¾´@›Ô×pªáX.qÆ9â߉ú5pвÄÇ+ÓÁŽXÿG­»¡>ÿÝÞ¹xï¼À&'ŽÈún2ÉYGï¼ ÀÝca¦Ï½¡wëZˆ�ˆ&ÛmAê_i}y �›Þ%R:ÉŒaG'4·ü…„o0}áo¢ð¸M4séÜš6ø™Å…k#¤VÅ�¾Û¾�šß׆�Oú࡟%ö® †öÖt44©Á�ã8/iœÑ´|D g§CÄT�^?PI¢Ü¢™·°Ï[нâ°óß/2ì˜E=ÙÁ~ËS°¹~’(<á�¥š œyöMø”Gë rLƒ% lC1ÝûœNœPç^1)€.­.ü}½农aÏ¢^LàRTt%îc�™ñÆA:ÖYˆ ëx¹1 3ªy8-†FyïY�âEj•1æÓ xYCÉÇQ¡í ¹9ÖE7Nk'‡ŠáØÑjòµê"6WÇÁ?#5Xý¾U+Q‹{ì5GA‡(ÏÅëÀ >�^°6¬¦Zâ{äiîÐ#i"èx먫Ȁs{(¿¶×ú¤¡Ëœ[ðv…/ÈëKá ›(HÜ÷ ‹¢ÁÌL�{ôW x¬ýü¯¨~Ì4ôK¸…_¯ò^Œ³Ù-‡_Š€¨®ŒzøÃo—>ò‚+Æuüf£#h<©„ïJÔiˆ±~By°7ä?–¢ÃQ¥'Ù_Öùy%™´�ällÿ�‡Ã¥‰f‘UÌæÁ�;OöÉ`œûņJÌœ�–‹b“Ã?™Þ7DöGk€éà�† »p¤ñ�ðT!�#üÐ}è]—d œ®1Ç·\Bmë9‹1¡r+7Äòè¹ôÊi{\eÇ‘²æTû¯&ÏU~1‘½1c8–dòäìpne:ŸVÁæßnØÔ-ÅŽWãó~;œø~o©"¿ð¼_S‡Š�]¤ï„&×j¡ N&ÙÕ²×wäá¿5\ R຃:Jg‚j�9åH€Æ7Rí\âx¸»ÆâØ5+Ÿ:]o€¨öròh FL~Ƶ™>ôÆjâšÜË>ÉŽ€8AKâõª€åñ€×çÅpÉNïå'ï„â•6A”{¦�Ñ;þ2Õ1;a`ì9,ë·)¥Ó$T{*FM0•º\ß[­TV7žÎ3é#®GÔ1F4e*kÛ±ÖBÝÞâ¶°jøuõN†2ÿ¦Ñ¯’½ÀüþŒJòø0úûÓ£·OÉ‚KÈ8NÇú¤tîÕÔ䜳ÛU±ãî ­V†‡kN£ÈUp�á°úk<ñewÁÃ9råº+z?VÀñµÁÄös?úŒ_~H »DnÖ‚¸ŸðTð1´¿ Oýï3Ùé`úßeÊ®› Ã~TÄWÜêc‰Å•kûÊ…q£¨˜…§‚®¾##œ ““ Ñüu&”üG\ø@×à-q‘™¥¥cÄ!¼•.%ó§ž;e»CjÉÌԛĶÂr¶<Ýô:Œ{ w q-ô„!ÅÌ�¬,üƒa NpÇ vŠç^€×³ÿ +:2ÖDá6ë&j%ÇÝœ8izóîztÐà�ã*i(ŸG_wÓ`“/ð“Êíf/ÅYâ­ ªõ‹MZ–‚ ç,ž›}ŒÊ@;mý¯“Ž/{Á.ßŇûŽÎÂIuXkÙʨ[|C�§ûqÖGp5cy|t~ùrƒøýýAÛZJ@uÖ j6Uß±¿’¡’møÉá.y1Iøÿ!ëo(ÑcOƒéŽÔ0À}Œ"Ïq†P>k¢¡ÙAƒ¡úø®M‡ï‹gqvE Àã}Oñ®CÇs,QÈ\¿ø€[+"‰åY_4“W‚\‰4êvLJZíÎâ+ôè_qnä�g¸þÆdr¾�g–°*§Å;oà.Ù Üä|Çê‚ ÷¹?*Íj ‹FNâ®gþ”cVʬŒ!±>[Ṉ#¸“çCkÀÙF®‹.À…ÃT5R”cÑeȶö^¡…>6x¯¡ƒ˜ºßbsÆ>±ç¢Ž“ ‡DÖÓsqvœ˜Ã}›‹2›JÐÛe•k‰1ý%(†Ùg˜gy¸kgk�‡EŽ·Ç0LæbMj§g§øusË:ÎÓE�vx`¾-~s? KâÿR�¥YTÐj5‰>ú–H{Ù£fÃ6¨:±‹øœM›ÏÀ�™’äùL šïÒ?Q×hózªc`…A./ˆÞ ©»}�¼êÿE>ÍøC³’°rd>� � WŠ_³rqÓ.SL�6Çc5n`ÕdÙw˜›çï’=#»¨wÃ0ÌÏþßNE‚G®´<�….õG(Ø}™þ­ÿDT·ÏÉS[¨¹¢­ˆ'o9z¤ Ìúû,ÀÔ9ù`BîwW1NÜ¿”¨~Ædy§Š”Ã]ì® øåâV·�²k,~I Û!Ž–y¿É|ØØÏñÿ•ÓH¹œ% KÍ £ÜDgÇyÑ×—ˆlr9i= ‹÷‡ƒ¥™,z¨~#»–XÀ¥*3¨HŒÆBõ((ým@íô+aN¼7æ”ûÁÊuÅd‹›9íSáÈ“äÊïƒYFì±!¼5ÑI_%^D Þ$Zo=�ë@&´‡¬ºÀ‚�ÿ$ôDÅ@Œ÷fá.‡Þ=²ÐXô ª}BPÒ#íW4 �¸ ³1eL´<¤]³eq¶D?UL8L�TÒy‡®‘µI°%¬ûlÉUÍDøh~�º…%¡cÔfºJR‡Æ\ZŽ6ÅØVöùF„¸g£ôA޹Bë”ÀÞë-37f;Ù°û%tÎU¡•Z:à—[DG2€Wõ5; (}]ቪ¼B¦Û§ê¢¬yq1ù4/%e„ÐV2wItâó%oq–Îq|`þ7[§PŸ’sèü·]•F©ÆÁ4TyÄ¥›v0«o0äÊÏ,�WAÆBï—Xt¶®Ìúöjò“¿ÿä–³kãncŸ§<'÷ñᔋTqÃÉÑk¹š™uô³XYÿÁŒ^ø4Íþ¥Q�íƒ1PY÷í¤àýC ÄL‡ˆ|ÑQ|k]A^¾ÐâZjslDE¸åÕi˜—°‡^�™G}cÎú°hB°y£ ïÍtP!\µ¯Ö‘¡…ÍäPÁ:ÚXš„¶û�Ñg`H'~‚áÇÙîàªÜ?Ú÷ÃÛòßBÆÜ—¹RŸŒeQ‰ ^ôÃÉJrøÚÜœI(ãE]w¸�»ù;QØkOÍ�GH�+2_��Ä€Çè$ŸbKE r‹¦EV, ÷D»°9ôŸ³f¼aqXÙžkº_Ý'+`X!€µ½Íþ¾_<Â�¿o€6'á¥Çl“îRq0E4´AÚ~Ì):C§wˆáÄá{¸áŒ-׿KõägSÁI¨—y,7ÁùŠBxž ÍI}MÖ­5ä\5cþkûlúk³&×Ôø½Å?ÊŒ-¹�|²utš[9þQA‡† I'%ZLö-cŽ—D0¾óy±*Ϭ®öPQOè.�MŒv&’(‡o¤«è14{E^§þftÓ^“ÞªyxZJ LX!ÎÅÑçÇË‹·œ(Äùä2?¼pð¢>\µ4‚}'Þà1É;ô«CÜá-'Ì›Æù†/tOâ“^®éŒpLøýƒzõÎ¥s+\hœ]-]<‡óÆ �r—ê¡¥ÁmßóAe—5qNÎ!k²gÁ'û‹ cÓJw™JC]Š ëV’K*kщ&Ä*“Ê|}K_l†GAq4¡¦ ö_ÿJ]ü¤Á%Øi1 ¢ï`Y˜ çnë~ˆß}fzÁ#ÐÈççvVk€â&S�9ZN_‡_‡%é,<‹âá=% ÈrØÛÀ\_+l¿[D¯Ì G™¸:à�8„ok»*šÖô�¬EJT'è&xUìÄíb© z;ƒ¹ŠH÷X‘6.-ùá:O©ú‹iôê‚+ôÔ!Eœ¦´ž¸Î´‚ºùBpbI$nxAdÌ©á‚OäöÁJÈ;w½¢&O[›Ñï‘»qNB,ìó¦LlÔ·MÒWÏÊ!Z8†’±è”*$}Ǽ?ë¹»ý?˜ªzŒ¡Š§¤K˜xRp4M\vQ³†›tÜ'ÄÞÁ²ô±¡Å‚Üâ·*ð©èõPSƲ…íäTcºŸî£j›T1Vµœ}ò [¼ʖϘƒÂ³‚!ÿ¢˜|Í`g»¶W�7œg±�t¯U þ§F‚+™vÞèŸÖKÖEâú³•P½(„ì$±˜¬q†í¿ô•È‹×?­û�XK1]îã?·AºÀý7(r¶œDO-[ܬ.ÌýÅ’KCÏ1­D”ŒÊª£Ç_Mz+ÙuîKÑ<­¥¬ºÃ}RÀ£ÈÙÜ6 WOyÚñ¢XìŸ3@ÿ+¥‚O‚`Æ È—Î!–e{@Hðdj^¥õsº±¿b;Ø$•ÚþUtfR&JP—GUTÉ3ÕFÌPUä4Ñ.úD/]âç†>6C¯rE¼i¹’zÎH"î)â¯akÈiÛ ¿œ³�‡¯ r¿Ç€ã»f²z1Æyá—æµ4þp ž/ID­L[¨,ø�†,E«‰V©ÞFÕÃ%€ç› ž 7 [H�6Ã#uH¨¡cµ:°ÏéžëÅàûÜ ÃO¬#— ï�‡EÍ—¦¾ïƒLºÅ3£RY ÿ/²¼ÏÑ’¸KnoEAº÷\™ãݾBôÍó°Eâx»îMófÓ~5—û¸¯îÓ…Œ“b¤ÖU„k4ý 5©í¥iY³¡üœ%–¦HbÀY _›F–^¥gb2©‚¾(V¸£šx8öÎŽ`~œ½�µ>ž„wÝ3(âã¾ZfŽn½¬®4ø\;ó+ƒis8»FÃëÅ¿@æ¾~©]Mî£Ým ê$îL®#y®ã"ZuŒ(�þm°ÿuQJZDŸ¹§ã™Œÿ˜a sÌ/÷11\q²0�Ê®½¯e`p¹^Ù㎠ß`cæ/�«¨‡%‡ø¹î Ç÷Áq,?+A›FŠð»¾<<5…ÞWÜ´DwlÎ> g÷¯àÚ™@­WúKÕPm{E\þô&}Â^FíèÀæ:)d@\ß<ª­~Ÿ\�~ îî/€ày`¦„'Ló‹`;V%´.î¥ ±øRß n›[âbY´^7Ÿ,W[KwÎD¹k¨!ÿüo±.ê^¶€D¬FÙ«á0f˜C䮘 Vó6°YÎQ]%…™§íÈ åûdçƒbrí¶0–Îè€>Å*l?$*ÛÆ1·8 æßbÎ,q¢$œÒü« =M~møIÅ®â�>azu¢�Ä--‚OÇî²Ë¶{€ý+xf'þÛë1'¡s ¿"ïˆ2 §$Cû‡pxyMšCUbñvd 8æ\Á¡-âh_lª«á‰ª‡+áóÇhXT{¢ù%q¬œ‡5¼Ø»m;%êm´í—p²iEÝòJ{Z™N�Ô÷Ù||†3õf2?‚ïP:Õ[õ…N„Ó6%sløô…2¢éð¬¶g$ß ¿²iEÉmN`œvÅàîieJ_[híétÚÿ)“ê}¨,_og¶ôAîòFJ+;áhì-¬vùD‚üv²[mà�ûB~r_|ºÅ6H­ÅV›hºbQÜñk¦ÓWKÀUZ$X#¿K@êD™%¤NÜE%¸Çÿ‘Äy‹èò¸’Ô0F§†ÿƒ½�7ÑÄ2EreÁO¹�`–4>Õæv~C|'�e!Ô&pª^Ù%�,^×j�dŽ$ºLaÁËqbZ¾Œ‘Ѫ&tñy¢½©‹ÈñWãÏ|*’G�wèá5Ž,Z½È/S´¸xž®“‹†r{í)wl£G}¬8ã“6”ÌÊ£f;òáíòh¿º_ÿp vDW:žèµç3b•D–p†½èþµ‡¼ï»@^Öš:�Œ3-N›¤ùx Éd6T©ùaá·Ú~™¢ŠßÒKópqýs2ÿ—hD41¡þf ³©嬮S� Qš2ÝŒ´¨Ã¶³VxP\„ŠqÔ¸_ÞâÁÍ&È»9ºývR×ý�̨³±7²ã˜THð�É7+q•âç¨<º@f˜‘ê�óù³ñð]Ø+؇3E9{doBc¬+ª-í[¶ÕºqÊsÁÌ¿óPmÝj²a{ êûÀ»W§àñX®Ø0DÊ $è–û�½%•¶üX£ë¢–i6jYT±;%öS……ÚðCe<¿HdŒ›Œ'´kl~hŽ`íw$_“<¾ŽNÂà'ÍdÎ,²J<4¢güÜÕ›³I ^³ ¤4A½Ìeb—g-ôXFwCGúò’"<’„í»P.ï,ºj$’ÜÆ7tn—08\ ÄÆ‹e¤‘Ç«ÿs–*«áMÛ­h•»BÛ_aÒ­›èΈáÆaìÙ-ǽV‡Z쉟üø¡\ŽGî%·Œ@ë‹ 9§…ÿ ¥�ßû3è/j {yUIqñWê¿ØÜ�5Óy+ s³(]½�±G¶"4êãžmGÐ=D\RÏŽ çÝIí‚bõP-Ø”óÉ1ÔÿX ®ü¢xc÷й]µKÞо�^4Á¡§9­¢Kï»âÇwsÉHš7î9}N¸ý¥kî›c¿H ¹ D|Ã&P�ÿ+žñ΄ɔ¸ti1sÚK*v%EJ0Ùë2¾qŒ�ù¦šØÌЧøb©ŒΗ¹@ºWïgg‹€ÓÆj/K¨Ë-uˆößG¹ãqÛñbÛìÕÈAUÇ SŒ¢+ä_ àÀæ÷)r±}„ìŸ~ ö.RÅÅiÄ©æ?<}i•”SVù2|Rh£_ù(ýÙ[c{2qºÏã FœŸûuPЏ¾ùJ´ÙB_$KÎZá¤ç%Æ�'_�g.Ù@Wš$N áû C\øŒ†oÿFO.¨&f^ àËÓ]¸/LÏmœT·Ò¹ãK@,T¥„MißyúßkÔóæå¨_ ¢÷çG0{kÑìo%†¯H«•Ë¡úÅ6´ZÈúEÈâùz¿}6lžXÆ*§ˆ­ÃJ¸0Û†–«\ õÕE0}ÍQð|"Ï›€U–)O½rž_©õ´<º=Ýt-å�”\}_@jîÔá‚ø62¯lª7.#™þ(—Ìê¥8XÂ…îÓIÄ"1äK•©õ›!Éâ%„'KÃ2U9è¾ÝŠåÓ�îJ€G®~ô Ÿ*w—Ñym¹ Å·#ÈÙ²TÚQÝÆ6ë&“qá&æHµ:Ô×’0õ‡ø%ÓÀ1+¨l¼‰Wëj1mµ¦8yÃðš‡D§þ+�öÕèZt’VHså´¸²›(-^ 3� ÂåOÉÌAN<I.gÍѽgø‘'/�S51º]v:Gøp4œÿ®gݦ™�©`ÚyÖŸ�‡ÇŒv¢sàYlìE±Ò rí|)Øš¢«K~°«Âµ¯R‡~úúÉXû ñ¤© 2¢Æ°©�¥�…¢Ü‚ÊM8ý@[Ma^g¨."_¿ëpƒ».CWï&"6©‰+úL‰É…§$àa Q­^D+ËËa™ ­ôמbõ%`uQnZßCc}uª,§Òï×Ññ9qìqËót~B:ñÐѬH¼.³�ÕÚ�Ž›Òw³Ph�7´VÇůàÇCô›±4ôÞ³@c ”„ØùOI÷ô2ð_5Xºã=ž¢òàòIªx¯«åJ Ï�f¼ÙnÂÞ»�UÛö“®Õ§pKÙcœ"¬É;¦tì}Öû�ÈÉŠÀ;ûw~ˆTl¾‰Ù!®c�ì¿ö‘HÀôvaúç^¾ð”¬ˆZjÀÍÝoºÚH7¯­,Õ¬®€ñ€0Ë­�Ìál€Uo{ÐÖA¯þYÃíaežαÛË&r­¡jáBxY÷ uzàö}?Üç*ƒ²sX»«²Ì�´;$ ÍMè©‘DÿÓǰ®Gì£~Ð�Çí$�нúGö\† #³!a@ê5–�#"ûeLχ½$ªß6a›£);6ÞŠY'éÞ•šlvw:˜à‘ŸÅd·š0'ïÍ?r¢Ýˆäi CÝÃt2½ûoD·¹-(Îw }s®)qç}~€÷„Ñý9ù0ZcGk×ÑK [pç™$hÙ F)=¯„'ºíh ¿8cqDŸé%ß§¼Ùç°î 9@·} !µÖ’8?xj‰ªÇÛ‚!éoé6>ÌTï“À&œ«¬ƒÂºILLï¿ÿ¿å5i ßIt:J¡m8‡Dѹ:÷1]%øø£Ð{]4‹¥pù˜Ø;rét¶�9U÷’ò,bñ&¯'œª¡-Oµ@HMŽ.JŪӸ귯i‡ËèÜ`Ã}+Rv?¶�-?LéNy®×àlü÷u5ILî…¼�Úd›­w¢D“}à ¬Êf«d…9gêÁ<ªÒ}æQûj$Wͱ‡û“ž[¡Šƒ™K9ÛlãñÉÎô’Ð#8°O˜òÙ.£�x¬m3Ðr$FÓ±oE-3ž²¬† °¿; ¦kÌF³{ávËzôàuZp®œ´×³)‹W@»J¼T‡r9®ø4W�#ž�Cÿíßï‚Üi²‡.w‡ùWÈÛÞÉ~«”…˜¸'4ÖÉß<݉ŠÐV*†ÎsÐü€!¨B}cìG¬ýjðƒŽ&½þ" œ‹ß”€€7[dR½@“„™Ží)EøgyA­�TvkQ©] ·BqËß·ðö×bŽwh>l™ïFÁ%…ín":3ÇY;U)8öà]¿ôsY/‡.8¶œ#Î`8 €�j¾1þB/¤ ÃPž<^ Ý�C–�‹@.½÷›¨:бþ†r›TEíeèÞ›5t #ɽœzÅÔSÖˆ¤=¡uõ%tۉߤä‰5\Ý“„ÖÛÒ‹–ó él;÷„Èÿw™ì;ú ÅýMá·¼_­�†.k—kl—ÅC÷†HùkW˜ÞÎ|Ü·×u3P®¸vñsJ´éÐõKô´„Ü·ÏC7qo”JøŠg+Z¨Ê•0<¿†¥~iŸè¾úYXŃÀâ9�sùÞ´MÏÑ´Ï!›‰x–Ž·ä—Ò5A¤X’ÿ+Ìdv‘VÚøW‡þ«L†£bø´L„{_Ì´"ÈO”1Ú!Df6©aÝÏaèIm'ZÊëqgHméù ÞTàäñ3°ÞX’û1¡ö9Ç­'Ùži1ŒÏî8"¥hO?dÖÒ·ýÀ;{3žT ‚#=]ìöSË@(ó{�,lR_�žk:qn†SÁH¾…ÁƒG#X‡ûpžêÔ,þ� oA"«¶¾‘ú_wÂu© $½&÷íh%+:ÎÂüݵÀmºJ:fm„•wÓˆ(_™^ÅÂu§¨¶‡#T®x@*L½ç½TØ� y„áÏÍ’P>�v´â§*šóÊ£JXfß@o*‰‹‡ÂIûiAL åA‰{¹¬‚Ó=œïßÁ\í¾ŽI=q4ñ¯œ�bÎLrúu"Í4º‹fß—¡ÊñbŒù[Í„Ùý¦�(“a€³.¼7}~g5„#°i]7ñ{¦�ý1b¿ô/»s¯$‰.—"?Î$Ã[¾0r¢?\Äêäi3œÆñÊb\/òpo®Äá ³ö có£Å_„°Jû÷¡À˜.6¬~¡ç)³ŒòkàõÄ;¼k#MÃ;I‚²&Ü#Ãð³H ëb‹Î�¤ÿr`[³<ñ«/… *ÂUúÙ‚úФ±y+~}MŠ£—v¥+ä8SÕS�Èc^ài+#-ÎWp|xâݽYá¼zàÙ¸b_ûÓ_ÿ•3¿·a¡æØê³�ý"²žªŽÎàzÛîCMq*iCzÆdß%=N·jQZ!LFDÅPËñ/8Jyâý TÖÇ}²GAóÃ[ ¯bÝìÇé4AHW]Úɱ°æË'b±2ž�eÅϺ†.ï¯Âõ\’89J_öÝ ‘ßLqµð\ºâz0E»çйæ~;vDßÝGÅO�8kL+ä`ݹB²Ýc-”WÉsïÞžƒÚ3[h¾b ¹ÿ9õ`¾çÿQtß=mÀ$-•2J; %’RŸ÷¹Jfe„¬dU$BHFJ{/ mM£4Ph¼¯ë“(Ñ@HF$»ÈW6©Ûýœs=Îy�çë§“Kæç¤å¬‚ôv'‰WTRcñi�³Žæÿò"¯ÁZØ»æ#vŸË`-ÉŸs¸P³o}H¢èÔx*‹|Ê~y&ãüïõø³ê†¯:{ýÉLþ#ó[û?´Ã±žd¼ “É„�’ì|ÄC–QO>Í„93+É7o9«ïœÃªtq‚þ:(P�tç ³ûD1#e…9Ts¤�+Oªeh ´m¥é¾ïÇQñЏTKTXðFÒLKaPTÞ‡Ï`’í“ °³Ëc†ØOgêÝñ•íù¾ƒ,wvãÙ–¸TTE4@ÂÖMäÞNâÏÝaIçHÚÔªŠKº?°Õîòè·C ^;T³ãÛ>’Ò…vüÍASðOxþÙb{7‘ì¯hj®wÇ!‰‰BOçd^ìr¿qqë7ú �Dô«?¯lƒE;½@}U-mÝîJUZªÔ¨äÈž¿“eù{ºñ´A#ëW‚ÑwSáãÌ~¸¼æ:õ¤9Q¡¡5}ÿUÆS¢õ 2ukǧf§8gzdº:zt˜úVK¶Jf4D¹¾ãl¶�î´q$áeBo4qáu89–¨mIjKQíŽüô]C8çÌu{?–¬Ö{aÙ#ia`Äöcǘ-2š½—@fóå[`= .èJXª¾8NŽs]©ëu$,:M1ãñæ‰#p$ø–«TRÒ¨`:Ÿ$à,E¸@µ2Ú>×�lU @Ê]² ”³¼à³NÂ-!<9°DE¯Bëéih¡Œ+ª?aƒÛôq­9Ì; ý:mD‘Y´ž÷ÄM”]z…gË1w3E¸ð…Á´s–léæ·ÌçEsµêÎB,¶îIx§Æ‹Ûz|/sÈN$öËfýÐ¥ :UÜàŠnð*¼Bf’çñ¬J8hù0¡¨$�0ja§µàÇÁߤc“ËõYŸ„¿ *lïœqå\@ÕvÑÔ_rŸ$–‘ßDyá@ÐMöC0•ízÔ†þ}sèÂ+9˜ø¶©{-z§H¥?㡵§Ç\ ̉‹�f62\ª¸Û†oU&Q“¥ßâ1xÀð=s,-Üšc ê?ƒÀ6­Š ·T‚Q¡d*¿ÔâQU¥˜Ô ŽÁ÷áZP¥o…RŸÖÀa--pXG4­„Fa F�âe6…Cžì{ÎŹ¦ýë³’e©Ð¸¶Æ¥/„u3ÉmyëjÕÿçÄ­0O`N™bidoõ¤z¯H2•\ë\„篫ÉšÅÔE‚•æiNǼ‚í;–ï iä3¶}j3ûïœ'üßi¹Rp²Aª¿Ÿi³†1])RtÀG†cá×Sìãðžâ!˜ ûÉQÌ ,GMaN0 þ»we™‘ò‘|&©^„C¶m�)¤¢h15c™~r¡Nûqä:ˆyskH:®Ž(�â&‡½‚}]qtÃM†òÎ4qæ®SèÅ•‰˜Q4„fJí¸'X™®,¼Ç |ëøöî¢íNÆà²ìÎ4]ÀGÛjÀé€F�ðm ¾†]ñÎņ/É�¡¤§7 Ž›Ò-�t¹LY˜Ú¼ƒÍú…‡ƒd,ýüRèÖ:å «Áä@ËÕ aÙ4²�§·“šˆÏ¸Ã%¹Š.8™nO.ÙÂ[ŸÐ¸„..xv¬z(*<Ü’M…l‘�%¹É ƒß(Óƒ8vüË x}«†44§ 2)ÒÝ.jùÜ)ào/œÍ¶'C'7�›ggæ³¶ÞC0ñf%–¬¤ýC�À#"õžX€Ù�§Ìðc(™4“tX4æÎ~ÂG lü7û4¤yÔç’ÊLgÌ›·.”q*Á]l¬k2$––àsߘ#ŸÇòxj)E‹wÓííí¸sŒñ›(¾. 'K±ä7©ÔÚ} îH£*pz¸˜pXêÁ9iqšœ>|^8q6G’–ªÄ—›“Pt”eè´³ã°�Z¾­�ÝO®ÃýyQTÖj õ^¾°vë ºž’K_ß\bu5!ü×Þ$1c¸OàK§½æv-†Éª± ÷ä$ø$¾€Ó‹‰ˆŒ³ó(™Ùù„°Ykjý1îDÿág9Ȱ«.¼6+Ÿ¬Gʳ�Æ™õQ”Øåcÿr–ük½ üMN•Â^.‘¦ë¼ÀC[÷Ó©EÑ”PLI)©4So,è΃ñ-R ¢&g9¾Ø•=/¾Î_+_ �‰£„£jÝî~�pݪ\r¹‡'ÓšŸR¼×˜|&!)Ãÿh³ ·-LúmÖ.#ѵ4õ ¬škOã'ØàRÏb*ü@Å7¼Y°Â#~Ô7à–Í%…áf0Ñ[@3Ç.åbFDÐðÄO¸µ¬„fµÝc�.§Ñéº:ÚðuHý¹"ºdìGW�ã—/D÷„o2ÉáðîÖ²’�®þPDø­i#ÆþÚP-?g¬qÓáÖ¡Ñ«> p-x’ÃÄþ¬)Ca×ÐzîE£"-:ð—„KƒšÀ,Ͳ9;·m<ŸþGø�³Ì<�ÍãÚhåøN¶® ÒSÎÂE=!üÊx}_zš'�¾Nœ×–P|¤¹­ èYZ1t7NÃ*eùêªç ùÛîS©Oc)ÈôæÀ—ükpü¹>mX™…f¤§þRGŸ%o—l©Åj¬]/Ág-OåA¬Fù0Øî«‚üáï±hUn³Ê«)ŠP·{TõßÀO:"eo–¬¦‹�:¸�ߺØê^} »�Äø�£Èw¹Kw› îRùšèÝçC�W¢¹íŠ’ÂRÕÛ�:ø�wüªKü©àr1\X™KŠ“Žà;_wú6æÿy19Bî£ã²,2¡µÍžt{“;ú¼÷§s» ØÝ77ÑÔç#¼NnÃ%9u�¼Å�ÿ=ºÛç·³ç«D-;�m1à·6×õh1™à.–F�è° {ØJÕ»M¡gì#æië_î§²»VÔwžoþ�¼^²„ñuôlõLaæÜl:ìÌ/Ì™Ž)G¾‘óÑC7†•ÿzÎÒU àB‹ôî¼'?…+˘FŠ ®ûŽì'2¾¸ž~ÊÙ£èÐ�Ú±p]©Í¢2×h|`,a ÂE{,)=_ÊÒ¬n7×·ê�ÃiÞ!ej:LÓ“nðÊx]f�?w–ÁÎ#òpúßË|êôÎÇq,F “…¦¸Ž;¹àqÓBeº1G8›óø“ÏÄ_÷ Tj™,‰aé],³y"N2ŒàŒó£aÝÁPªõŠ}¬î¢g­ÑÐ~!€­¤FœãjEçµYvx4[çýŽ “2À1JßPú„�5<‚2v£„w�}e7]¬ñ‹àe;Ã<J­½FrÁ�5þ{ÃJõã´ú¨$]×›ÆRv+ÀÙG­,ó·)ÛyZJXµô<�½©_u£ù.»´ƒ]ŒP†–øs´¹4WÇŽ‡¬XU ¿6œùÖð7ú#hݧhX{0…\»8ʼØ@i…Ë`ܰ‡tqbüp‰¥am,¸,Uݦ�ÜðE$a9›nþë!ê&½¨áTÎÂJàúHjÏÀâMÜáTMØñèn=& «ê’±0ü=W(ŸÈlwRdýØ0ÒæÔL…7PÝØ<éSxUE—k5 .RŠz?4^‘ ¿wà•‹J–½¢3„í¿;hãÊxoÞŸÿ$‚‹JXµÕ�àýÏé$4]ø³¢�W4í¥¬yPÐnBkIá^åuÐy”eޣШOF­š@È›—KÙðga>ÓNØE&žõL²áŒ~{±áÒb–š‡HÕr7™lOcÖ¶•ÑÝù²œåÙÌå:ü(ë§ ×óGîïa9íl‰[(§¦Dëv½­v´ùE9nq‡¤GRÄ" fÓVÃ*=ê09à;°`6ž›wƒÂ–æÃ¸Ï×aÎå«ètó?¢÷‘Àí�„ðVìYþ›@@âh�:’É�T/‰Z¿ˆY«[± ÿ9Q­o©•ÑÒˆïÐ8Ý……ï»y~…üçN[xô´ˆÙo÷c§¾ÈeÓ¬© Œr“àuû+úoc4FèQjûIœp¤Žu�€™G�6¦ùÅPì„"R·Ÿ-\\w¤¿ðó½0þX+މª‹�5ÈÆ¬MÇç\fÊå.à85áÛ·b É7~BáÖ•˜PHÞ׿£pãzê�ÔÃü'Nd²KžÃ‰“¶Pß¾žNiGR—ûïÄŸð^Æ‹É2W°¬Y+>¢Xý ~Ž|–L¬¦še²8ìE>Ú«Á7''§‰hÁ’ÙÂkž¸özjDE°‡ñƒ˜>n7“7ýî´*"…æÆ•ŠÚÆR÷­\ÚùpÛ·ý Ei6L¥Ú¢<‰C¸Úð¬}/k¥ëè}Û'6‡÷fç=¤Ñì£FKB½{,3 ŽÀ¶�g0èS�P‰‚•µ÷Ù0áXÚqQXs¬bÄ,šE¡ wÙ4µ8<ÑŸ ¢˜L-öùífº\¿•…7Ç[/°ïg,ì5œÖæ7£#H@ßüìÉ~¾Ðõ4M#ík£©R4 ÖÛµC£çèzvíO…(2`9õ7¨Çg‹ÛWŒvûq0á›9q¯Þ  ž§)Õ%™ÙœO¦((—êwÑ£R«Æ'xu&Ò˜¨ 5U*r0F4S04÷ ¬^UɉÛ©¦ 2úúZà¤J_O ›k”Æ^MTE9£½pc¬.êi€]cÝà�¢gMÉ®öýñš?b.Þº­{›\鮺#ݽÁÖ½`�fäÀ«oÑyV%yË> yKí X(ýµÆë†½ûËÃhIƪÑå{o°Fm�Ÿ»í§m„OED»:ñV_ó^m�G&aÃu–•Á�·Ã{¯Ÿìˆ÷s0?xX0~þZ2¨^ÃEÛ+’›äxhú2z6äSŽ×xÔ»iJ§#óañ â ‹—Ó6oc0©‹ÁzkŸbM›Ž€ï½Ÿ8ÐÓj5àûåÙ`sÙ„´‹X¦3Ï×\æõo¡�ôxˆР‡Nbt9û*lßgÀìþ8±Oâ¸{•`eÎC6êá2xq?¾ÆXšŒ^O¬†‰Â§üá”EtûÀ-ʈ‹€4Ñ2€³ãéÍÕ¶Ûì5mzý˜�{4mNË“dý9Á õà<oͼνÙu¬|¦QæÌ&Ðý8·lC¶ã@ ÊKÁ{Zâ]OEJ™ìÞãJ&5`B÷Û3éZÔK\f=È$"\-dFN#‘–ùì�Î2nÞ ÃçO#='{š•„){†‘Í‹4vô¦*µ¬PA“³}œáöµäy·˜_xñÍŸw�=ÈI„+;B8Þ8›³Îª Iš6t>—φΑ ¡Ñ0›ÞßAW5•àŠóÓ.át'�†š|Ïîbw^4ÒÕ÷Ø3áÜõã.Y9Šûª@ÕcL�_ÅO„sW  è‚ Íðn¢ËæïÙ±+èâ8u®é{¶M:]„9ìÙlj_]B%«/“ÅþpX»q´eQïv±I‹¬ïFÀ¥L=r½Íö7 `»è,WÛ$5¢Æ® š”)þçkؼŒë0«Ë+e«ifX.ìyÖ;/„¨‘ÑtnÜk‹íÏèþk0 }Ž,ÄSáí‚ëÐæs™Õ>–†´Ñ=¼fG E*iÃäÇ" ºSì�` Û£1x¨†r"#ñªÆ|¼ûî (—ß…›Õz$¹Þ‰’½ZJÉ>¸S=&Sßk5šÞ¶˜½=Ë\g/ aÁM¼Ì^#hì<Ékµç³§V3Èe]¾W·ütÔ¯Fké:r¼ Dç´N’”²)­×�GM³,H-â¼YS\ôËÄg�\’v [ »|.�þ”Sì¬qß]7¢ ^c‰´ïb’¯aµÆVP é"_…÷8¦0 M^}CÛ�GH1Ô 4NΣ÷²3)ÓJž·0Û€¢q�dËÓë£SÈn³/f ˜ÉÁ}½+ø|©&L›�Mì„#¿{Ï4�¾u‰Û•) ¾-ç°$àkÝ% ?6'1Wã.þRé2è*4 ßkåt9Qƒw~á|jQ`WþÏw%¬m©8+ËÓ»ð^RŸóDÙ¨è¥\ßÔL«Š-…·tvð¶Fù¼b³¦¥Üæ0)~1<û²„Gáùª@Öôà<Ó·‰&CåÕ ÷4Šeîcû­÷LrÛaZ§‡?"'Ñ“Ù�ب±*nNaÞçU˜ãåEÔ~ø+~z�k·Zü_×eôƃÜ'Ó™ƒ3áSÇI>ëŽ(‘?ª*/Æ0¯l‚œ-4é5ÒSJ#£T-h§V¤ŸòÏgZ0�<&›FÒ�d3<®ò…~Gl�¶Ð(˜q–•úI¥᷹$�p\1¿ƒ$Ãh.�Æw,hÑS+Ö%1¥$œø(­:&sxU 㦠š�KÑzèFf–ó;ÎÐ÷cúä5Q â㎲7xœužZI—>ÐUö;¤‹ÿÔ@´²9+8Ї‘š¸µOFt]!n®6Þ:Aý×å¨Në;²·é}áx¸1_œ @FsoÝïG¯Ô MÑ€;�Óàû;;XŠÝ\ïdŠž-Bƒ1ÓÑqÈ '¯-bJ+`EÆh”Q²‹ç(ìF žq¡Ã��˜c‹,ÓU·<øj×·X�}Ìh†ó¹Ù«s m4·²}çuÙ9 ÏKQ葉tBÇC–¶0ó¬,\¼Ôœv}ª§±°&]™%›L FÕpº¡,Ê[¦J²qÛœ!5÷Z•%Ðåî“,}a&\ÛüK«¢À°ÎD¸daX�?N½³á÷¤ ~(ã.T«�…9ù²àiß™$Eöå0ìçìû}ÔÍìäÇ=¶ã”$ŽÀ�D'>}]êµ{P¢V;'Ô/…IçbÙèÚW`¥(R3xH“ÆŽ�aó�qÍxžm¬¹ÈD·ÕÓãê‡ø:ï,£«9ÜlÇM,Õl=ìZµg:Ú±§;cÙ@§ôO7§¨Ø}¼é„`ø³ß†éšBçjò\Ip”Xr8H\|Ó’{–ÒFÅt÷&CÛ–{잇'ÇšÓÌÌ\× òRçq§×¾à MñjnZó�àù>uªYª:ÍeÍð« }@R믳Ã[è.ƒ›{/°�óu°Öë"V§Ûa\×r0qJdU²ÉtñpN}ðf%„²>×gè\gÅ^Þš!ºíl±T!¥»ÅÒúv(w ›Ò1íÉ ã™RŽ5G¾dY*˜Õ¡¯´‹bÞj•Ìâ¡4Õz€ßóZ°ê?Ƚ€^ö�-÷nöÓtyÑBˆ«ÝFU—““a3 lˆÆ;.R˜{5DÛ†‘ýhO’4”‡Þi›¸5ý'QæÉ+6$1–®=‹æ ñèT?x‘”[y„ЇÒm¨2ÅŠr^Ðs½ˆ|¤ ºCg@þñDV`¥GóðtúÐÑYåüµÿüaÔùøÙ«O'¬Æ€ñp)Ë ½ìÊØ™ÄÂzQFð—EÜ=3´ŽQõû§0^züæMØüØ©d¿Þ‘ø‘§)]!ÊBóN6{5›hXmï!~:=sðú /Ø-’Î|T„Ü_ÑûìšrЍ1£°xnÝ_¼ç¹õßlþ�k|³4ØýA¦ÒqtïÛ>™Y4BÞ”¬Ê/Qfß|�ÓB?ÙB:²q /vuÍh•…'WÔPÆ´Ÿ¿ÕÙϦÊ(¡–wWeÒŒ¤ÑÆ÷lŸ#è_ž+Óñ¤’ŽG+®î¯çõ#“èµê®¯Ñ–Ä­vCG…�MöÕ„eqPúÖ s»#P4c9­ž0j�‡q7â`v¦?�|ÐÁd..G1q¨Ò�¦×³œéÌUxêmµªPBWÀï»!‹|?¿&POm6V¦HÇÿØ@Ö wJ�Œ•9³à؉?¬³©K&Gâµè0ªœs ¾Z~Æöç°É$í¬áu½°W¢¡)W Öé[½ÄšÝkÈÖõ²`ßhiº_ÊAmÕtX¾e)dúßF¯³'©¬6‘Ì÷úÐ7•Ú|ZƒÎˆ.ÍŠrX·OÖ5‘õjÖžÅ:ºƒ!Ǹ‹ZWrϲXá¥÷Ü—^In¾ßVnKõ¨žÒ�¢’ [e ¯J; þCŒ ­ä§ì¾ÂŒ�O�”k*`}ÔœÇØÁ«í²ìåÙT*\MDù ¿gÂ%3Wjóÿ�>ôQºš#hFHÒu‰40îc“\†Á‡Á]ÌAæ8�;cÆIìëa–[™MÍ :}÷n' O…Ò38ÐÃÆ4ÛP¥Aší²_¯_‚M—3¨8O……û²¨r¿&l]$†s‹M@ÖۦȰ_­Gh@y n”Ì€òêô×Eé!b䨵”2gµ•ÑnsËýrŽ©'³©ö¦ÞÇœnG@a½K ާ�£Ïã�¯ÃpxD Öë÷1gÓ#Ì{ÇYø½,½ßö±Ú�>ôÛðØ=¼Ë\I�ŠíNãyKÝq‰ž¨…sV/ª™ú�Ûôù6ôm*ЋÏÙÍ6K¯ {¼¶Ÿ CÚŸ=ŸgA¦‚<®Ýç4£”è�¨4ëûn…ÍS²`œÿmö©g “ñ*€YW‹À;ÑŸšþ ³tr9â¼ÉI‹|X ¥ó>—Ø‹ãw1õÄe\aô-ÎSŸš$™ë—ÌØB+7=åšÅÐZ«]Ud!¿f$®é> 7o¾f ?û´ôé°å…Û¸í†Êø‘ëC¸6˜OkbP(» õòáÚº/ !€'ViðÇG¤aÈÝD2ñ‘búös(,GŽ­.›/È)Ï¢aß,)ç„™¹À§}²iÝFëcßcõùD.°K’e+Œ€©*ÛÐÿ‘L\•ÌòÞîÛ(yP½ô‰^ÝÍ7ó½¨h¢€½G°k¬×|dyÆ%�¼”6ž«{Ö;ª˜Ú¼jzüÁ¨ÿˆWN'—Ì98sÏC¬4Cbvî`7ÝŒ^:3©¥j´2ѵÅ꩜ÿ ÖbgjFÏ^‡~°é˜¼î!±4Lªi¦/ƒƒd=:or0�*é›M7¶ù¹³˜uœ÷]ö_i5, ôÄÛ¾°éïRkúGåàPŸ5Ìè¬Ç•:‡@´3��ž ÅÜ~À$’ݹqó-(ÖÜ =^onË{6Ò™£(Ÿ:±|.Œ«õ€!·ÞTþ {'ÖL.½›qÒ™úšiËîÃС, ž¬}Knk÷“XÐ'ºä„“ òÕÌ«Š^dwÿÂ7 ô)Kîæ¿Ë¨ý*BߺÑëñ56qK5výlQ=ý$‹¿ªÁkôùs9ø·¨€ÄÕž"å¬Ãî GqlX5„ƒ6ÄQüÊxÒT߀KbÍy‡Þ<Ü^Û‰÷ÜéÀŽY82{G�ÉVSîä]Ô T‚;ïo2ó› :g9)íL…í²Hi¿œ‰¨¥ ·=ð°6ŸãIÌ«�9ö(ãîóÊö‰E'Úw²ŽOÞ™çÌ/ÚK/]¢}£S`Þ†¾ÎAì²D MY~O°FåL2!¿"zÝ¡ë/•¡çا\®_4ŽðJ¥· ò1»f&gìú�WN'¥ªJHmíı É>`,Ê/1_(Bêäxrø•z+Ó™Tí.øÉEµõåðp¹”°=| éµ^„ðem,ÇUž�í�ƒ•‡.šwUײÔR)8~mèÎd x �Y‰Ai‹.D™à½�EôßîFÏðìž&§¯ˤi»³78ñ Ì;/– Ø9Æ‚FÁ¥#ôd¢´”zÀo³jp«» ËCgá`‰,%(¨Ð�EóAõ^ {â_L)¯Î‘bg§»;†ª¢ÌÍrŠw3§Yï2Øà=ëë`cŸÕqrk~bˆÒl�i /£àÞDýßœ zT”lÈM}ñ¼kæ‚ËÁ58Uk e?„8w9æÓdH÷6÷`æ›VhN dû–³âÕSAlüR6V Œ#«hžÙ>øë¶�ž-?FsÖ1O«+L¿xcád¹ðLµGỜ§Üãî™4½Ýž2Qº2k*¨/7ƒç%RÃÄ(òN½œµ�&•¥ÓÍ´;˜›'Ë OÒŸ_|å승üCªÖ¯É½�ú@ß·f£ÉF�¹#%ýiHÉ€oýbZ_ÚùCq³ÉfÅ š¹g>ª­dý ªP×5�MžS„‰“ÓéÍ¢�ãZÈZõGÂmÍVÚµþ4;¾À‰Lz§�AÐbz&§HÂ)x5N@>næ@;ÏÂÁØÔ°ö84e—Óȯul�@€n›Í¹óž)”æ±H$â wn`Ó”jÆX+ÐÑ~Ø™"*<.ûŸzº@^Â.�Ñ :ì¹²‚ko†˜�1´~ÓF´’Y b5?mò:VÕ¡@#fF’âÙF8n8žvg“éžÏgÓµ0}Þª þ Ëï}íu1wx&¹H1™ä`HëK¿¶íø k3“ý›…]Þ°ÕŽ´ùùœÙþV*·¢Ê«å\ç–.R™ÊL†ü¡ò³;šo{ÎnM†�ó7ðÂÅ'Ðl&ÀéŠtN.û% ïÜO>N[hè|(K«ÃoËYˆ„3ˆKÃn{é·9ÀoÚ§®ép›ïïƒZË$þìË taÍä;³‹_¢ÙèˆJ ƒE‹iÄ-+ü™ðŒ.�Ýå3¨õ³)T½ÿÄ*¿ÅÀßqþ¤é6¾Ïׇn€3zZ¤r@‹^šnæÝ2õ`n‰Œn‘¶,Ÿ£Ä8æÂ¶Õ•Ã"×û°l·*hæÞgzÜ\º1Ýšegïd±íQÔÏzŸ½$ëùÌuZ ¢ùøäp­<…%™P¹-†¾7æ²è¿aø:;›­Ù{>Œï¬–O MñgìÈšpèîß�Kb'�j1ã˜�\ôË— [¾�zçR¯x2›«µœKk0Åô Ç ü»>Ú'ÑŒ­ù þ|Ý–[ü@ÑtV5PËõ_ �Óìè6Ú£¿ ‚vdTB^é ôñýÂÒFßa+Ã2ÀõÎq¾ãº5ûxé)æ^s%Cwj87ŸÍ’½:Q§øW�èRÙ�Í{³«‹÷° g¬¡ÎqéNÖ…G+þ÷?+O”jw`³H /¥Á¤éRð¨ßl„q i¶„ò‰oøàxOx•äO—æî¢”墩ö»bpÉÍ$º0-™�¹Áb8}~ð¯(o3%ž…÷›4B%Æ“7¿Ie¼+ø¹9œÍäQP9u?¿&¾j;ÁjüȵNe)½&´Þo"k·«åwÎÖÆîN:傿Q¹5FÒzàž¶�;ܱ”nò.ô|ýN0\ö’i,ZA©5·Ùv—$´D�yº¶1w± °µ „½“Ö0…ÚÍ,×SéÿвÄXà¾Z2ù|TìYµ²È† 6­$�wœÌ–xÁtéª�ÙÆÚ%£k²ïÀßï¹èØü„mØáÄ^äúî$[s’-ÊV°”Jô¯noõIÜÊ+¦‰eDöBû\À±æ.‹'%|e<ƒv÷sвyC zŒƒ¯­]hü9÷ G»¶•Ð]l�Z XϨ»ìÞå\š3ÿ EȾÀ߃q*¿”ŠNõâ^5šð´›¹lQ‚¹Jµ¸_aù+t£‘v*FÔ¯£ Yþ$Ö!!õk&íQ3x¹-‡à–¢ Ý �+bÙPv¡†=Î? JçॽEp`ów–ö¤„µH¤óþï¢Ö¶ÍxÖ:ƒÌÂöÁ×»¿XYÿ<>].·Žc’òõÍSè…Â*ÈwSf#%œ°ð©!ÜvSÃcqaNûF*­Ÿ‡"çãËç§©ãs1šn|�åwbRÌk¶to-§»(6©¶B¿d8EnÙ”"7‚UÔ—Ã-KmМÉB·ßÀ…ûTaÆÁ·ìÔÃÉ´.`Ý8™Ž1[0ÃߎɈQıq섬6 Gr¹C3È §”ÓS¸ˆ•·oòû§GÃË71\ÉêdÞê§AMËïäޑ wFÀü-n´Ì!š�À)�Ñð]ãyKMw–r8—os%G³Ëü5·,¸ö¸�ZgnÇE‡¥Añò rÉ3໼ìU¿Þ&ÂHó0%g•áì•ÇQvÍv�Ÿ¤†?¿1«Ú_쿨‹Xnº�=h.ø°ÛÝ—Bþr}8²jé­´¦´–lö6o8dÈy�ZN>§(\‚oÓæ“ÏèSÌNää,* å¢ ØÁÁ4f˜N"*†¬a´-~a�W4Sö9[Z;3‹^|°&õ·WȳyǪPÚv]fK±„mAØ:ñ+Šwd±¬ !´ î =/†›!h󿯄*�íñzÈÚ¿”D Lá×¶pJ~ÓAUélÝ.eÝ•…��`È%�Ý7˜Ìæì8E»œS`íèHÖö åŸ —RªÌM¶crÿR< f+Ô±—rvòŸ‹òë#!b?�†st²9‚­?’…ÝW3YïC’º"« wàÃ÷~Îß]ç`Aq “�xÀ­K•÷„ì¶Îg ü$GÛ;ûyý¾$?i%§8Ãø¹ú¼Uü’¥©ýÖX2ÞoC§ÂvBõÎ%˜8O„R¯©ÀÐWúÛ ;9`‰þ#f»¢›î ñËâ�ÂÏ\As¬ÅæÁïY�†Ùà¨* šÃ¦’�e>Ûº.M�çÌÁ�–.éÁG²ŸQ/{õª´³Mêîàd3–.�±âÄü¶�ƒH4(W î\¨`»ÆN‡fãÇlCÍ0L˳b£"RØýžŸèhÅ^)6QŸøXu5„Yô«Ò‘¼Rj\¾„6Ö~á^}°âCÜ9î0 bmshîo[\åÞ‡|{:T^f»¦xÐîtkÚ½A–Ô/sìïc�š7œ¾U·«2Ø#ZI*Ú—°·†Ð>>š©�W§›oŠÙÉsЭ`ªEQÌYn£Z¯¦ C’ß•híœïl¾œŸn/_~�¦ (Áç&ÂQU€Ð.¦âLûÕÿù¸3˜ŽŒ²¥Ç‡F’çqËÓÃx‹øè%G¬uòXð)‰ÎþbÆ‹Z>—SÀ“ofC„|3÷µù1ÝÌëC×�pŠ[µœÿ¾"ŸM—Œ§Y¾OÙd’ž¨ áæqQrG3KhïdmW5áIcÊ^cyî·»…±ÖŠ©0\Âfß•&Mürâ_>¸îámŒŸ¢Àž^[³Ž²ÔB3ÃkôÆIŸbÎÊÑŒO¦Twk$lnñ£èÇÕLaË]Ú˜ŽdšAÛê6ì<ÿ‡dæ(€J¢ˆå«fp6Šâs?£zs;´<}‡Vs£àöø>ögïXJòØ#¸’G7€=b{VãŸÚÃdÕùÊLÏ\¦\�aëµð§J ÿÄ!�; 諳Ì] ûÅþ2ç&}aó}]:ëí@.6-¸ÑE ­ŸÆrëg?åž¶–ðWº¯âM/X¶ÌÂ’hnzowoˆ+*±#‡vÑ?Ï×ø«LÅõ¿Ûi‹®rг‚Øþá�˜‰óE&ºÐ Îß9¾s+ÐŒf ¯ììáäš[±ò‡2¨ýüM²â ò¦—@Aã2�OEª¯‡‹ÚyQ£©p &ž‰…¤¢›R$w÷É4îø2xºz Iý]AçÆr%;taPl =ý—]›ìpcò,¼<‘º7.À¨Û±ÌÆ\Z +š^@æ¡s¸l`×ÒAo: Yý±±ÂvÙtüÛ` ›õÑ×U0©µ€vy¨r›ÝÍ¹Ž‘ÅøÑ5…š$Ãi% ¶>3�VL"õ£Á0w¿L{yœÍ¶0¦YOd„’W¯ÃU½Vº¶S.î¸~ ‚âoÁ8ÏÒƒzàî±âpº{7Ai`ç’ʺòo ZÄ HÆ/•& ;±zm-Jά`‡V½bCõ›©üä *Ið¯î¸×E·Noý+ÀO¬�š«Ãd��kVîKw*/® Æyªq% ¬¸ÿZ£9áåˆù¨C �Ó`ÚDv#è~è ú¶s;?ã>“´û‹g¶UÔTæG£Xàu>!ã33¯¾'޽âêŸq�#µIkÚ¾§B”?Cêk“¼�•XnƒUóÿuAïa–{ÔL!Âe;m—ÇbMK©™ÓÅÛŽŠ8ÝY…MŽ<Ãù~™Á±CF3l`m€óö4aû¦/ÜÉ@ô¾oÅ2î~`'öRø]QK«±¶\’¦|ÚÃp2€�gpÔ`/×°‰ÞÃ\#!ø�,ü^û4>|1DU– zFWªav4ÈDëPJv®®Ô¥ï¿$ ú·xîpƒUSÈ!²„6|ŠBRtƒÃÅF(æaÜTiœyý‹ãžÍ—iö²KlÎ5'J],ÿn†“U« å¿“Ô¶+–ùØõãX¥�8©Ï o½·€ÑošÉñÑkÖ8غ½ÙLêÚ]NN£‡Û`µ”öšã�«ñb¾'lž$ËZ|N±½¥ =ž˜2³û®~‘N›˜7=Žu€¹[á„ý(Âð¾i€@ÛÊ€�2§¬Ûpdň½¿�*쇾Uº Úõâ GC=¦1açgŸ�X¢s¤�u¸ó²E$ôìâ …ÔtF¥+º(Ðâ6•¦Î¡L៚³ú®Ðj:‹éÜ;D“ÎÛaÉf/*ϯc_z ñþ¤s¤h(NM²ª$w¥†[dŸ /ÕÒiš|3/û~ŽPá_çúy`/6œ™�b�²tkh7ØdÓC³ƒðÃò9˜yþÆ_é#é¹W[õ|©/ìÇÖ=$¡GÏN±cÚÕÀO5_ûtÊÑÁË&qh¬=ŠvF¯ÓÕa°=byÏ9ÏÖ(€ävCÈ}A TsqŽQ $>ö$Þn­³²Oõ)%Ì”ÿo®9­xø­²ŸpkíçU§ò³`Ø<ýá$þ0} é>I´oñZØ*p†Ë:”ïû›ðƒIšÒ¼¼slE3´HL妜ãßóÅþëI0yÞ2V™l/uãèªG0ã¹�Þ=ãÔ•7ѵ1Ml^}®=™N“OJ±�€C°Kþ=ûØ ù9®$öæ®>º“¦¬Æ©ê쪬ÖKš»WÀÉJ¸¿@†Ÿbâ ÷q{ÎJÚ,³¬Î…Ô8‹1]IˆÔK¥�ŽÔ=¿ ÷ï�8GcV%UϼUi(ð2ß4K6`ÅäHZ¡œ ßë¶¡fÓpRñ»‡Ï¢¶€{�<˜üA×;*@juû<~3Ó¼_KJŒÑüi'›ºgvÍ9Þ LºQy¡7J«Âiõ<4yYÅB—Þ¡jÿv,}²’¼è—ýpøu,ïÐ:&±9šn|ò©r!Ìo › ê ¡†Üùæ4®jGCRA.¬>3ŠMÊ´aßÔΡå§`6ÿa¹�/Á)VRøb`I¤±�‚™Ðø_5�zð—}ÐJåð#|jM Ý4ÜÏ5ÿ[_Aä56wÆpêø:¶¯¹ÆT:@î»3i<Ü�Ž`»+80]»äz ð`%i«g›~c‰nÔºu°¥zã`NB(Nœ ÕÊ�@½«$+NPÒ]#4Ž‹…K«ÆQã?+¯IŠ¢2|�I×Th{b>îŸfO‚?rÛõŽ¢NÅiü4æçÀÓâ¥\dÄ9ˆ|:CO³;w4@ñã$˜”ñ‰WRŠb¿;Yå§zØV3#>’׳íd2P %kÃYΧ×\ÉÇàk9 >ÞPZ’s?’ö~μW…ók–p™×KY’é«¥X¥rÛ¾6øSÔ[xøCš]�ŠÚëjø¾åѸ×UfícëâsÈð–=d Á •ÕTyy…gŸ¯Ñ.t…•µ ~n.†ÏÒUt?Ο6ùFaÅ�G}Ð ”Ëx{aÞyÇ.i ‡õFŽôDZäÓ$0_{ þ¾×…ºñÅø„UÌO'.+@Ñ#šá›DIæÎ´·¼ݬOVeï¢ Î03Äžžšär*kosoþ“CÛ{ß0nô'&�Ób×Ç}€å»‹Éâü$õŸ‚‹¥ÊèJI"� ü N"†ìÒYÆM.Ý�Ú…Aðl[ŸEžè^,HXŽ¥”±å ÞQTâ'Ö_`SùÙ#pR£ µõÂQMž…ˆ]ãìjäá>ZÐÞqØ^\¾Ž}Ø$¸Oç<¤ÐïF Ëàת#”à{ê›BˆÍ…ògß)uèø;(±ÇÖq˜T±Ž>.zH«¶v°»õÕã»Ó`äEhó`¶ žœ=Ë?|^ƼA¹koj¦}ÙEq3¢`éˆB¼Þ§ÊËÚ\aÑï²ðùeþeX9kü<ŸKÞÚûÏ-lgê!fï« ’¯±SíR�·ƒå¢û¸ÞQ¾Õ[ž)>ŒÖ®Ì’æåѳŇI¤+”Mï©‹‰#@®ü À< ­ã}É騭©\Ï å'Ò€ÝFߣ ´¸?ž [pùÅJ´ÙNfžGgÝ$(ï[ó ¶€½Á uÅšFUÀ—ƒ0©þ0ÆGF�Nêf𓇵æ›pÐSœ„Ù�0x“3Kþô€O·ÝžF•Xq6�+ ˜Z«s>}�êÀ0?+�õűì² „…¨Ü æ;íQ^5š%1bÃþ#_{ °!<ºô™¡ÕäÐÁþ ë^Ær8MÐmâ.—ÅPµÛ8¸rVVð£gM%uÑWÕST§°<ýbîΧB´1}€•à h û2 P\EõÅ_™tß,¨¹)B_RH*¦‚×VÜÁ/ÿj%›Í¹ÌvSš»p$,ÎÕ×ö÷äâ;�?™Dß’MY‚úXö»~ÿGw:z¬—§š/hY”NŽ¿½QÿÛ/¶ëñK[GYÈi§)]t×Ã2^Ž š°ß¨»ê#êÜeí¯7ƒ_C-Ûæ…§œ6°gkþàs‡`Ön3žO· ÷Ät¬ºi 3ÌâÀ½ò3v\ cíW‘‹¹:m¹a הּhøŸœh—I·bïñ^[ÎÀÛ÷ùtù·vbËõ&AqÛLölê0ð8°ˆUì9‹¾ýìqY1MÉMevEÜ=gDÛ@>ó_6ÈV…úP¶g.¶§JÁ»g·(*F Ǻذ i(Új-“'Òþ_£Qè©AÛãà}ß¿î6û8;ÑïÁm�U¥Ò.æµJÎö£øMIt¸Ñ“¿ebOnU÷9ƒûc@ik0Ý»í•ÂhÚì�ÈÍú±´K¶�ÿ¯,˜ÆÃæã`ßSÒÝàNï=EÓõ†|Þ¥Ì1:(ØEýáÑÌûÊm4ëÖ$Ãè ¿w¤Æø1QM 2VÜÇwz‰Ð&™š¾…Uø\ã$N?c’ï&Q ôM¦+Lá­ ‡÷®ó¸Ë•ŠäyQŸ7wÖæ,GÁM^/é5;¾xŽW�C›+3È_õW�\˜‹—ºÃgí�¤ùá .täûo¥ƒIƒlŠ £2ý8T+p`[Ú«éæ�/—>æ•þN§ó±'y‰±dô¥ÿ¬“¦¼ÝöôD/�fsÆMدN'³ûsÿeô.ÓLnÕ/ßž ç~ŒÇCS¾ãHm†¥Ó~°Èî«äi&I«‚þÍûÜ)˜³)#óM³å¸am"Lmz6Í¿‹W{V@ç©$Ðr<…½,âŸO~—Šà÷½)Ìn„5ÞHÂ^ÜõÉ#¡ÑE�¬ÌaI¥6¹©-@¿%-´îÇ™žÿ‰åU63/? ‡;Ü5Ö¦9’YÒV3âO6½²þˆ_d…¨gá܃zÁOÝX7ÍL œv2½nã0{ø4ë;¾{êKãžµ2ù'6L]äÄF°í}µ¬w£ù|º‡S¦€ÑÕhø’û„ž”­ SEjmK,@ض›­<�wK·âÿ.ïx.Û(gËÈH%[Q<÷ùQÊ›JŠTˆJS%J*$›2"3²3³’žûü¤¤(E!)!ÚE…–ôöÿýǹÏçûùžëò‹�BûÕö0î•AÂîõâþ5Tg}®¾37ÙKã´u­Ä)eø¼Yz�O\r—Ѐó¢A]Þ_£Ç‚·@ú;1¬Ûc�o½:Ð1Y˜[ ®ÁÇiëÖÇôÄqu4ë#¯•&鎹k`·5/±=VFŠW¿¯_éò†¬ù|7-5‡7¯õQú]꽘Ý(÷˜ÑÒd•:‡ijöLpÚgL;%íA‹ï=Y�¦’9´¢«�ÎO ¥š©4°ßZԥ饶™ì‘–¸¬ZBÇEqÏé™(³=:Iá¯À×t(+=�^ .&Dî¶0/ÅÌã&p\h!°Çñ°Øc|V„|ÍßIŒJ!áþ3%QHÁ«Ô`ÜuwœÍfR@×Qh„E&ë6IC&Yê(±ºB®É†U™!àó]vÝœ$rMü­ÉzA%ª�¾mÇupøñà_þ�˜oØ=•òg,³ÅZs uƳàV�„œ¾ËÚ}-å¾VRÖ†“saÇGIœw¾‡Ä×äÓGFåp#Î�ÜðÀþ,fŒ7Ò+‹Ñëw$åÍæÖ‡ÝÀÍ¿¬ ®Ê›¾¾ /MÕñºŽ=裤VYïß'èÒš™ØÛhMRj´ñÁAIÚvü\4|Oý¶±³:‘[¹É°Rº•ÝÖÅ�=é ]v{âaƒkdzT‘§Â“´Hú1]ή¡§\fâåª"4}ÑM¼Ü·¶ÙtIÆ _�/‡ÒÆhYXçÔJ„,a^¬%õj"k t`G–ØÿwÈâ°�:ñŽr!'ôTPÇ•¾v ¤ˆïG¬ÞТ¯îP÷m„Ìl}G?ޥ럄¡ì×KPì¶kޏÐDigðÑ£{¦sØ¿3:pαat‘N®Ÿ-)ÆÜ§AÀ½9Bk,kpæ3ñ”‚®3q°9^”keË%nžDº™Uân’@õsà•ŸA;2ì±B€KÞ™§Cî@%nçpF½è‘Ò Ð:˜ˆ>¹ÍäC\6U“ާõX¼;–ðøÌ N³æ°uöãdÑU[\l+Kù/È@Œ¼3sæoüu('eI C ç[™išÇ boöÄGƒÉY|ת‚k/îA'—~8ê¢Î¬o56?žŒaúOI„“.ysìÚØ^¡íi–ئ¶²üf`¼ý"V¦$� ýC¶µm�e�ÒE÷ž“ïëc¨ò«8ëv ÷w>§¼b¹`Ü•Á†ÚúSy—•øäQA´€Ü3~C. t-�TÓ$D;0|{+yÿ�þçÃ�Èk¬âþˬ‘Û:zåN“´ði€�Ji8ÁÁΟ¶Éd•õ0³1l'ë^°�~ÜÕNÖææPÇ0ÜŸMöÚ’à�1*¬Ï$öñ&0tÏ÷�5ô�xÑnŸ¯Šxà±æÊVfÓæ€| §Kˆ|h íUTGÉfs�o¼J'þ¤¿cutßWØàÄîjN‚ùVûIpÙ5\˜ÿ†ì4é¡{†2`]ÛAœ>éK;5± v)¢ï›QZȃ­ì|8vp˜Ñà6`P�*&Èœ€O:Âè‘}•ê\¯eïÆm¯ßìÁO§Ì�+ÍÚo¾EÝŒÀ"q&j@S²†r6Q�wËpá?Æ/áHãɾd( yž]oɲ€j6¶M„qiT º2W(]ËNó>ÊnS÷„ºæ5@Ú«àÐ8ð^è‚äÓ[`ž{‘ûò“Œ�; §JˆÖ3¦uö:¶¯á&]k=&»=aŸæ1òâ¹06.'-¦�±ó7¢Ó³ùô`�¬»¬ »Gn0âÇD‘¼ÔŬÞ¬w±‡Žï­Ìø²X:5ʇòf—°îÕB2š·Þ«Ð«5wAbº2ø�üÁ2½bPLÄÒY¦d7½jðß�L_µÃß÷ipñ’ <ÿó™uÿú›V>^CŠÛìØçWr¨ñ]Róoöý™§�7@’¾.ÇO«½±`É"Òe§%ç>’M;`îçFÊ« O#q¾–8´--¡ã³év…`ÐÛÄ`àa]üËB›¼nö± ÄiOR¶e=yùðÄÊlÀB¡R”ÐûJLÅÔ)/þ»Qû±2òÞ8Gn.(>S†ááMõé•u*kâw ¾¨<’ôfÿ!Þ}‹ êX ZíýAm5z™Ç“zð²ÉV5ó°ŸÇöâ™9, @ªe?jv¹ÂåÆ\œw¦œÜót#µ6›Áúõ Úç¥Bš9,›çNÙM‡_»Óëý as–#–çʆ©VÑÃf&è_mŠÓ‚�É‘ŠFú:F2óa�5À‹2CÜ8hEd7®`<ÄÙúˆ6P3ÀrÛú6(˜ìöÍܵ[¤�t3§é*©i\ÕYÊÔjä ÕË VêJPÐçKõž€£§,.�ñ'& Z˜‚}vÌŠoêôµ›( t¦wš¾‘g ¨øš§Ì`ó]Ò_žL£ßç²݉ägaÖŠàNã):½O÷ý9ÌLýÕÉAÌOÀ‰ç¡{†Dòí"ÊŸe E)„gͧSiɬgö([œ]N|OR¼rI2WNÐ:ÃùôÍ ²ÿ~4ÞS¥ŸfÂóiQ°Ã¼“Œ»¿'‘±ë鄨�JÖ=~{�ôÄö“B¸‰?n¯Ã£—f¡ïÉïL÷8>§*6ÓÁ©¬Ÿ¼¯– »!žÍ©�îH—ñÕQ=¼ßr™ºénd ò—¢ßQx¶ü+QZnÂôXh@Åf0nš‹JƒiêçxÆ÷žr_ÊcÎûz:]Db}‘Û>‡Þ7d½Á›³2»ï·²�‚%Ñ#4¾Z¿§5�nƒqÞC4ûr…jóÖ±o–Øt7Þ�7UvmuRƽk0w~qn6Ä¡ïù¬3ûÎÄ!r.¾ÊÇúÍsÑÔå>k<��½ov";‘@Ö½–ź‚*rÏô'e-°x¦3,ïÒ�Š�´ÐTç%\@ýÕç¨]”ã¹ôýž’ÂüRâÃ"mvÞOyžÃn‹T"ãïpŠSˆg• @Ý2û©%]*Äaqb½rû^8cüˆöÜ= ë3~C¾Ãcü)aÜÙ0ÄæíëÅ–¨]põê.ŒÐQÀÕáý4Ew¹¶0 £‹/zák}šü“àê-"j”[ÿaÙæÚ¥ è¼ï.9Ô%‹½áOá\Ž ªþ„{µçÐBE-‘áŠ?˜†Iïß¡ý‡P¸,z‡ÒGÿ�U0Ò¥+¡]Çl„Ûf°¥ä¾™2CîâiôLÿ}:á¿»ÒŠxΑÆÓKȃµÓp‘Y=©_¡ŠŽ0JJ´àzÏpV§û³aóqy°) À~¹zý“;ŒFO¹‘cñßoPŒÅ¼Iú;íí91‡ðd}GÅLÖ °±4ø�»ÂÞw£žl [メ2¨”ÍñÜJì�à}ƒƒð)í2ØgÅã4Õ4PÁ�ÙxI}ßk§©M®¾9D߯W`CW8mX: †?I¡á…­°b¡lMÆ>ç`òëÊ;¦_n?Š0�ôJÇ{&¯Ê^(.íeN4§IôZÅ ÐÄ�îßX7¸¶ƒÑ;YßxK'ÅÒ‡÷7ÒxÙéPœ²‡ì/íÄæ«Û‘uX #oŽÂ»19ˆò0ÕÔ9tçêf\p\- P·è ÛéükÿÛIþ“ÉC½Â4�“å:;ÄRÝ*b&¶ƒ£Ÿ“畉�N:µ1à—ªcVˆHa„Ñ[Œ›ÀM1�ÞÙMíÊÍ©VAÁΫµ×Vü%¬ÓC©à§tÉ_Ux-éH|Ü›@QÑêŸoÍ%'.„âÃÒdë,wúàÚu ³[ ÍŸç±! «À`o2Þ–Ñ€X§Ôxë *<£›Õ,Z/âŸÐ(Ï‹´~à X%ƒðøtZ5?ï*d··qÛ{Ó®ßÓP¸Y’VsèG“³(«…¡CçÈÂ'wñà†Ó0cþ/äk‰gý—נDzz�§åôÂ_1x:¸uŸê‘·RuÄÎY†&ý‘�Âm»‚ºoƒ/õá\KŠv.¡¯¢ÅA² Ÿ^œbÆœ‡Ës¸”ûí ¬ 4™—s ’öb„D9ÝÀdãÖð>Ô³ %ͳýé“SÀ?dŒ[¦¯¹ºO´’˜Ââ'�pèjÈ3™à¶|1˜•i‘œ¦Rx®8N·Æ‘í)wŒ� ÁZN�Ì £b¢’�zÙùFÿÀ ±&öÌÓRRØÐmRÅuA×.9ª¨üÏÿ.a}{»Ø�ê{˜ËO"Й#dDù’ÀQ ê'ewÜQÛ2”ü‡RO‘oƒ_Éå)+B~'’’�î¬Ap”ªfCÈ{k’a}›°JhU%�a1ް´rØÝš‚g'^ÎMªã5,ÿÒ«Ô²xŠløJ;O5À‡W—Iÿ­ïÔýZf…]£®K½ÑGä]l»x0:ò`ÇóäÍ-r¥j9ž·M'~õt‡}ñŽV�°o uîüñ0†�] %h5Ì4YÆÎ�¤ÜÊlòp]œIóØ«:‘'é•eà˜þ…å8HRï÷’À½>›Ú¿hÁ"·ëø øýûE6¼7c\÷€Éú+ éu®=X‡÷bŠÀ©ºf¯Ã×wÏT‚ƒÞ+ñÃ_bÃÿ�Þà2³nÁ޽´øÊ:èáåÖm®fUw~bñE±G�Xßœ‡Î -àå—C`b ›N%£ërY\x±šZòobzŸE³×׸SçÛbX.)÷#g!çêJÚs&’wcyG+Søãv¦˜Cr `Ï4ì“߀¦¹V¬ÕÐ~j�®„MÚ‡ÉÂŽr(L�úÒ- ¯h^m&Špöি±�7’DŽóÎ…„Û¹ØxBø~Ò q¸ŸÆ�!‡ü€I”Àe—¡IuØøh.$×d�ÂÂsôÀd<³¡#ŒÌö“çVóÂdWâŠ"鸵û†î Ý Ørÿîào£�äþ9�NÅÀçÈtomíhÉ!¼rNhœð‘š\ÆU­¸Eã'mãaq(ScA~Èî|LÝ2r�srî6o•Yh€/@Ù÷‹˜`�óº/ÅœxZ£…ù± x— "Ÿ›ÚnÌÑŠÁÞÓwa}é Bç1sèÊLHszÉÜ(-ŠBS±ñd}í_îõ«0¤Þ�]°#u¶¥2ÕÞ=p€ÏŒÎ<åD�úŒ“{íŽð­x1~–¯£pvÈTÇ*ëk�vÈ„�Lá�/†÷¦u R�ÿ’LX‡AŸå ª|k6ìp0ùõˆÄL4©áÔW¥ÂÖˆwà5n _JSAñàEB“jr¢IÑ®TÇ\—ŽK‚ð™gdwZñžŸM¶^ȇ‘£~ðËî¹SMôjè"V dÕ0lNe^u’Ð}õªŽ9ÄtéO=·GŸÉõdeØr€«{x5Áv¹öÍ[ ‚á‹ 3ß–œÚˆ/vk‚À]J“þ®¦N…׉i£#´¦¾BÃçCtòòBÔéž«¾wÐü�cZO-�oÐ¶Ý �R&é`À ][{¾ß}�s¬©îœJÐÏVû)~j³ŽÙ“”…Y�O©ûÉUPÿõ 6{)‚fˆ>êt½Àv ìi$·�ÖO™GA¤^šè\fýoæ™ðOÈ6Ç'Áýdº?ç5ˆÐúH¸yȗꇕ¦85–IôüvBTÕ<ôt3ž»±ˆ±íZ ½ù¡Çü7»’æ°Éwϰ=uKpõ•TÂVB¢`§¯ë·ð_FŽM{hÃðâÕϣә-ך°AÝOOÍå�·hÿ*'è…%ãÉ jÊGŠÔ÷Óí»n§Ý{°‘§?¨AjQ>Ì­£+ÇÜ�{ã(ì,ÛJk B7bኯdèïl2ªzõþ^¥?–­£ß¦]`6Ç�àïŽX2±Ô5K~Ñ]ÉM+Þ \ CïnÒ5UQèØµv¬ø×%R5ä—ÂITM #ûj1Üs;fùБý¤ù×GváYÜãc+H÷&QÐÔ¸Aõì9ZÝ)xs2ŒâåLtûô‡œ>�Œ›®€êžz¦!…¨©'Ë?fлû/Àôåâàq ˜Ž!¦»Ø�K¬•æÍ4=À5W JݲØb­otá°x¿~ÎÆ”SyŽz>ðƒò{²LTeJ‰–i(3×iÒR;2$. ¢%Šð�3Iãæ] f›Ñh+¨6÷59±Ð ÿHSÜñ•¶Ÿ.®ß\1 ìxØoçö`“É'VHÀ�:Hè“þ31Ri¾±t´M�Õ¯�¦‡�eñke0Ñu<‡±BÎPþ&šêo—bgjk¢ðÁvvÝQ8é/ 6/z‰¾†7š\ËD“¦4ðs ÆTp¢É¯¯â{Op¬ÜyK)UÕ=@[PìåurÙá £ÉW€âsÂð�‘8gnt©J_‚b�©xM6LfÁ'[#Ì÷)Äëa%´ò¾/m^‡j²áZgTN\39÷á4ÝÑÈÅ×;­I’Å[ÒpÝ @T‚Sö…‹×n@ÜG)Tû@f�ÿwŠßÐ<%I¼üulųgÂîꊇ•H\y"l³6 ÉÆò¸þÀ/z)@[(Ÿ¤=é0ˆÁ ãT3ÌÌNÆU¾ ÿ¦emÛ*#UáfXg/M¶¸muR\N®Éd³Q¢[ahQ9k©rÖµå¢Tt0ì×Ê!Ù÷üáXhSk2 »4ÜXÍÊL眅‹™¹ôŽÑi”}^E-Œ ¡ÙÒ �è,òðÙa�3t§‹Êw?¬÷.OAcŸ`˜ÿÓÒmy™ó þ­>/Š£x;> çØá ·ÃÄ.ƒ|�æp°|{)6óG›“ÙXt4FäƒOò"ÐÿÍ�’³,ѹp xËâTîeX0ÿ½Xâ m)€ítJÊçûlÀ>mEª¸¢œ,?{“Ž(|''ŠUàx¿²É6ÛDüë~‘‹4¦URð2¼’�¸ œii̱ãÐø�qw×€-w.£T�1¨<1!Ïzxá´S6‰R_„‡Ê,¨úC'TÕІW¯BØÌ#`VyÎáõ¤»â ñ$O›‰Æü<šmE+½„qöËBŒIÙ‡MS‹pi�$÷áþBú¦¬4ë¶èØØ`h|ƒ±#oógA%sC/wÿ±ÅÏâì¶Z*í4�ÎÓ Aû jÿÇ„ølÏ„S°™^-tFî4ʬÑÿ�»n0ñ;@î{jAË�W #üˆ>ƒ"ŽpýÅàPøý/í0 Ä 3\5_6Õ×ÐŽr¨5 `N¶Ä¡y†2lÞ;NßùˆÑj0 3õ4ÁéçÑŒ1#%²è¸/ˆVê`ËW:̃ë�Z±èï¿=¯ö–0ê+˜è_|Då¼90KÄÊya¿°éº’@O6kÕ½°:Q«pö ¾¤·aý„/.�ãÁK˯AçŠé°^[€ðªñÁ8ï5ÈlÁ!—`ºóCŠ?7€K‡Ô(<¯¥òé³H@zõl ZG`ÅLŠ…�ÕðÝ5 ðÎå‚¢^#Æ'5Bhä8­à‚ê�æº�b5°Ëw Ê�—àÊ«6¨}w§oÒÃ�QìÇC¨úñHêòè(†ü)ý—Ù ü£»‡$8åé†ñ»<ê,ê6’Ž´ ؾ›f�¥R‹¹Bôv­8¾¸?B¦-�£¯ïg¢Z¨2:N3Ák_·bfL0êÍ™In'‘»c²˜�çZÊßèùòx2Øì¥½Š¤–±Ya³ÈZx�»b5Ýâ€õ:asÈ£ßZÐW°#&l Úâ^.€eïØðtQnÛ¯;4]º Ó%2I”�!�c•`ÖjsÐÔG¹Âÿ¨à3o¿GÑ’¿Å/¡ËÆžã=¯f²¾O'Å ë¥j“©p‰8\wÁ¥ehõ¶0dl æÕh¢®�0�ŠÉ¦w“�@¤óM?ƒ,Ø~�:Êž†±Â 𻹢߬Ægú¸öY7ÝÔÆ�ÎHcËÕ…¿N¦¬ÞøJ:Yuÿ6Í»]ƒSÈ?^êÁ€A3ä›ßÂ’HB^-f�åRƒ_ÀžŽ19µ‰±Š­d‹G›˜E<7H£‡ ñ/ʤƒGíÙI³3=ããt'NÇSj÷éÊ™Qì]  îçp‘¼ .ÚE7ۮǾN#nüø¶8†Ÿ3`CL¶a‹øøžß§ñ#s¶¾5ߤu‹íh•”$ ´9Ml Àæ€ Zó¥–6™�.jT^2ƒJ0Ðé]¯ÞrZ"7b’K⩤±=cdy_7]|Ægõ¡`ï_â�©­i†ôÖŠ@p_ °0y’HúKÓÚæâþ¿Ó`jÌ9þyQ0}j&1ûZØCåÒÔò¼¸;n'§šæ�ÉÊ8RÁè¶*‚>{õ‡�yþ‰Z<LâZH¥n+Íû�V¥ý{Ù¹7ï€ðálŸÚ£{™è‡,nvÁ×—× øòUÌî€enèK2Nز�{pÆÅ7äÌß)¦|S>¹ä'N ­š™w«Þ“'6¯èËŠÓp4@‰íŸŠ�vVô¦#¡ÂwŸ’½62½sùUõ ¶, óŒ®CžQ>ÎõßAäÈbt¼-–Ø h—§;�ï&Á¼ÁôZêR­ïHóä«ÑÉ6µê£ak{Ù#\K´Ó³©ÐÐYx+5o2¿¨§ùVrã•wmcL½�™UFÛdšõ;6 A5ÌoâÒç)ØÞì�h¬Nq�ºbW°Ÿ&œ>Šzûg‚ß6ˆþ¬Dîqtpæ- W¼ê»Ò” \J—oÎ%m6]ž(¬ÍCu¤² ©ägÂj¦ø¾&DüøOÈá²ôdò¢¡„mH - 2äô�&˜À9O§�VïûÅ| ÞªŒ¥þäÐݯ´8éy'ºŽådÓµÿþ²áÖ8Yæ@3²AÃŒAïû¦Dg³1k~; GI£×{jçUŠgîS…u;!§Ÿ`â7¼¾êŽšÉ譾˶ÿ�ÆÕj×Èz£°ªÂ5–!n Ú²ëãààÓWÔ±8ž]ÍA-Î ¬¨²¤gùŸP·Ü÷Äøn3qÜ’ ©÷OйÓÂInö'�=SoÛ,†ÓÏ]¢ã5™„ãnÌŒzËuè_§]"­ë`šÈ?†‹1§*à•ÐM éÅ‘xËS9-�m£SO„°K �>ÙÓM=W-eÕÖÀ»°Wh³m.B£©^æ ó%XùÂM{ƒðú¼/„¯¸Êd¾bžk›²{ÂÊ9ïqÎ�$ºáq(4?Û…1eê4¥þ Q\K½×šÒT UüzÁ°m7¸ç¢yP8ü6¼‚óø%Éj]wf™‰8­ië¯åà´g\Ø�6û,èŒa Ïï�‰êÿzí`¤|=Žy-ê°X7–žX!O™< *ÕÓ8&"ºàÕ� º³‘‰­ ‚þ• PVà…"÷Õ ö—&®ÖCëA¼S4B™‹�˜{"�Bž{`ç^94+Ê@‘ú0’ö—a>?�¹ò±$H#ˆòE–âòøçäHçläÝd@+ ’àÚ¹ü¯dÀäOí¶‰Ý$ ‰Ôô�-ê{¨ÒiíKààÔ^ÔØ)Hm³ÏƒÏ,SQ¡…‡gaf—Þ,3„è–;x@d ŠêŸï"2v;‰^°°e}�tи¯|´Y² ÊÞ-$[ºtHBkÉãуGÂó`õÜÞZ±hm´jæáÜK)Å3üqñƒlö¢tþsºouÚæáª^(õ|ÆÜ:]LŶÌcÙ¥_˜ÙÚ ¡½ ÇÒVÀÀ;wÔ&‘�[D¸:žã,VDãøÿ`ÚØšõq-:;äвìCq'¶¯‰ ¯Òš =µ ¡¾I»ý9Ï8p·"k6Œâ{±hb6âM­CëþXX'tÊy§ÃŸÓÙ4"išÍÒ¥w‚qtÎ]œ4×`Žˆkpn Æ5~Á¸ù=ù··ßJ­Ð<–Õ¢‰ÍÌTp?¡×7©ãÉËçðð“0H¹&‡O1™Øè‡.×¶c‰GÜucË÷tÌž Ÿ• ý³ ˜wÊièÕ–H:½ý`ì\+³"Ü·±‚äXK,Q¹qô grÒ«Oâ÷˜£4ÞØžžªŸ¦¦ïéÌûøaíu¾à„Kÿe¡qÂR–n Åð„úÍ I»I\÷oÓI/ š$—}ƒ¹á¢�\´ø7‡bë›íôéyºt·+БH”½!l<½üe¡_«±û¸$´nÛ@$×\®ò¡�ìÒNtšö¡m¢ ¸F.‡£ÇžafZ2uÞ4Ȏ̶+ÞðƒK¯ö|gRçÃé³ÛèøÑVì?D ä”6+CÐU]ˆ?P ;´ñÞ|sòJ@NG rò{ÓÀ¢"™ÈN€A¡7œ�Hù+h�YNVì—8W>kŒïÔ>£ÞsK²hÓzæ\ Èb|�D˜Ü9]�¼(ÕŒ±ÄÉ/\"›�Ã\~™ ï6’%hô™,‰O†”“A6Ò¯ªŒéÆÀòßÙÕ€ s¸SŒU܈: Ý„šOW)ƒÑŠ"2«Ò‚œH~ƒ×.í£ëí[ 3±÷®Ðׯ±øÛçò<´Á{ZIHÅÜÆu S/iå6oصéó„c ¿ËÁ­K$%¨çÉ{Ö3ËbˆÜüœ³öÞšKÜ¿.€ï?WBÐçDTyv eeþqòî-YàV´Î;(ÁaË~z,%–¬z$ Wžn@ý‹wÈÄþÙpÿ±v�Æm˜ –å¹T2íJ¼Îd=—•ÒÛcFøè×r¢ Ì®Ë$Ÿ?J3¢ç·‘£²èz¥‚ %šûDëÝK¦˜\àzünâ'ß÷ÒöÈ\P›üQé¨Xm€½BAµ²„Q6»Ãî\ï@ǬÀä²%R �†g‰”6ï“á>^Ùo¢¢§ˆ _Qö»¦ƾ†ŠÏñPÝô’á‘Ú‚Å™KivH1N“ââÝݬk�' iT j„wÁ_ê&ö€šŸ61� ]%7»Hv7Æø¼ÈÉŸO¥o1«~³ ¬ »œEpú¤$ܨ�¤“ÊqG2HàüBö`úE8¡>ƒÜ²(ÃÞÙçaåjU8ìWA­S[é"¹PlùÞG?.ÒÂsàØÊ¥^§‚ÍÕ§ÄÐrÙ£{ Öžâ�3ÒJèí=H¶[ËþZr˜–ú|¢Þ9 tÁŸ¾×¥ú&´7I�<œ“DÍ·§¦•8cM<Ɖ<Àœ—<Ì™üT—@_åË0ÿ�mÌ=�œV{¨ªÖ&¹cÖ#oP›ÑhPÕ|„Ÿ� ѳÒ¤¸k6ÅÁYm¸f·ƒVKËrà3_(‘¼ÐÅËÞ«`¤šàÜ<5ìfšE·\“@UuÈè0À¤á&â:¯?'TCâð áƒÔt>ôõï¡j'Ö`S²q¿þ’H—·1Šôqh(û?¥¿R_C‡Û\,½£‰·~.âüÖ~ŽïG!æýc˜qí"¸­õ%½§®Ô5«(qŒ\V¡Üîqò8dÔ¤àzTÚ]¤ç¥Þ°"Qb(ç1ׄ}óÓ«Ay[ (4½…¯ö4°yŒZ ¨c¿m:IôZ‰3oÇÑŠ¤�ÿ±-ûbp·ÜMzn`˜9çËÇž¹ê€4ñû®Qzƒ¯oÊ„Á]»»¬¿ÜgöaB&Iß³2æÊaOžX¤yÁÈ~ÂÌðI7‰KÈ"ÿ©‚ýÇCif`"Û�Áb8[!š©… rf©xï|Ï\fÝÈõß7Ø´¿&Â_ ¿ÅH�¦¾Z*®bx]ý±ÍËŸ‹»¢N·) MÄâ…oÿ¸;9ÎvùàtZ†?—¥Q÷™²˜õßyXu/£†&‰á»C¬§üJ?\N³ãö€æúCTöEÍ}JïØ½`Z‹·Ð„¿„u·§irC8óÎ ð—þ^Q^‚/¼!:¹Â0,+@¶å9caÅ 95)‹£yò ÑœÇ.à-¡ìi{ºû�/ã.0«!ÿ9¡ÝQo¸tõ:)¤Ëî)€ý‚£e¿ƒ¶Eÿ¤á&ÃTrF+É�¿ÍXå4Õ�@5ý¯2ÇŸ,Ä|==š-“H§—'¡’æR:o�´ˆ+àM)®Õ“"*Þ}g-ça¯Ã¤¶áÆûË¡nH©îæ¼VuÄã›Û™»ƒ¸äm&—`ÐX&%¦Ðµ‹C0êtUß4 ƒOÎâV†ÓÁúó¯¸Ãׯو�ª°c^ ØôÁ[Ñäð�@ŒØ&Dà kPàÄeÊÿR’nÝX€ûvÓ~#0k}ΜR(&£þQ s¦ în¶„—ãG`†U Ñ%·™­3fAž9|�ùIÍÀº­ÙÔò³(¼•ô€…*�øë_Gš‰wÂDøzzãúrðA-}^ꕜv�ä’è�o‰ˆŸ$8œm€±N>¸Þ�¢KÅðÏ¡yx¿b-9ëAòI^ô®Úй[É � ›Ÿ Æùc´::y¡Ò[[ž§çùÙx;Mâ[¿“¹ØNÈ» ŽÚJ8û@›xC!ëlæ>Êñlðñ‘$Ó¾)ã¶| FÇ��sð}:¨5�»¼"ðR½¹áp‰\»ÉRA­]°Àž�û*}=,Þ)€w„‡‰_°à¾%NEQ] z_ËÖÌ~†Zl¦ªû’×üâøÝÒ‘• ʆ4lKåÅ�ãh}$ âþÚ�ùG„�eóIªš|tƒÎ©[TÊh1楎©Ÿg˜…õ¯0yÞT�ù€(]þ�>¸Q‹AÅ2Ç?ÎËÞ‘Dp"«ê<ë»O{ƒbv&ZHÚ'?“ÅçßÒ·¢ÿvºzHÜ�"†çñëH-ì}¾ 2&®Ñbç Œ1ƒ_Ï_§F1”ôúÉ€0}„eüQTÄ'“œ„p0@€»JÜ›D”¼Œq¼§áÙ[;\<ñ„¼r.&;|ⶈ¬¢ÑtäÉœj*†<{]Ξ?Ÿ�6)üýò-ö·2‡ú×¢Bœ 'Ýq œßÃò2MüðA“«‡t9ê÷„ÀáŸK;f7Á�JrÖÂ[¿l‡_ÁÒÞ—f8×ð'�òSâ€Ð8û]yŠÏ ¢¦³áëw"p# c^¯â~*¥•eÛX…“ËIà3�øv²Ì„¥ûõPôÄi¼é;o‘9‰°éþ{æ¿ÜH²í·í«JEï†<ÚKÞcö·ˆ–Vâ†|3ù®+Íå:~Â݆�ð+åÚ­Y‹ë†?k·b’qo9=ß¼ ›¿kÒ—P5‰\Ìÿ›¾ú]_”üaÇþ `Ó»DµLà¾tŽ{Æ3êÃ1.éŸçVñq.¯Š@ÏÄdØàòAÑx$«‹eE½Ùu¿ÿ©Ú'ôÝ%8zP ¾Žy¸)q@!Ì–]‹1·”QûC7½¡q• ¼~ˆG>¦ãÊûÍìI¡F�”S#RËÔè¦;cd£”>ÔÖ‚WËSÒ¼¯�]åé Z~ëðJé\Ú|Õ f/ÁÏw¿“}K¡Àvé{i�nZ¤s~#z4¶°?jÌèâ‡Z8ûâ4úð©ˆ�Ësž'`Ù±LÖ6~0ŒÞNÔ–ü„uð•‰üǼùf§‹£P]*šÁ²ïøóÔLX�í½¡ }º1 º!–'I1‡¿íæþnd›æòpÇZý�^Q,ÆG½Oé«¿¢¸(ƒ%"–«¡Pí |«Á+ùü`Uvê ´ñ¯x&züåoàŒºb¢¿í(êØ‘‘J×V 39»²¥¸ùFë¹Ó,OѺî·Tàv(Ú->MVŠ à¨ÂG,~>–´Ï‡ Ë"ðé}V†ÜdìÝúPjÍ0 úœK¢·®C­n5*%¼Žhšhrž_;�_“!~0—.arQÿ¥¬‘“Æ”š7¬—óJR¦&È ØÒC¯û�¡M}`S ƒ2‰ÿÞ%0W�¯ÄúÙðAî;ª\¹E×ífV˜7ÃSó"šà’ ¡_L¬°ª³B°óº?�‘’C7ñ‡áïòIl*•@¿¢yTÀ=ä–¹€ œ,vh§Ñ3� áMI>MÆ·ÿ1ŒãfQîß·3€sq6ùó[TþÝj#!oCü,€Ï¿ãlA1îëA©úˆ�C´|ç;4ù>Áz®µ¡æ›FÑeÁê¿#âŽá¾S©aMõ�-À:Åß>ë­¯5…áâxfýU0>¤œ4>z¡'…¸é“Á­apHôœn¦à¹Q–) æç–ít'ß{ÐòÇ~Tü‹wed FÛ~&ƒ� iC†í ƒÛõÏnžCÓº¸•™Kv|,  ×ã¢ÔT�Ù.ƒ5öWÈô3»¨GÉ^ÖÞÌüj=Ç|Rå…¡µæXR˜ÊW†’è'©ùòE*5L #ö�-Úç±deNUŠ€vïr¦ójäI\EîœØR-ŠØ[N“Œåð˜e2É__A[çü`ò®[€ãWXif‹çÚ…ÈÍH]r®QÆR´¸ýq tÆË Ð7 �ß?fà†È·D?o Zzø’Ç¢|ðq]å…P3¿ž”]ØC2ÚøPX©†­»¨…\$ÃçU6ƒDmDwª}4žž,À>éÏXf¬G‰ýa&7—T åÙZ³æ'�ðøÐ¿“u°ñ¬*Þê†×wsÏ=šÍ‘mu�Ý¿b¨öˆY‹Ì5Ø=? —(ö`í�?PÚ e'­PËî®/DÜo�1‹³´qÛ'!�퟉¾É`ÎÀlLÐâ�ŸAª�`ö—H šBZF>Õ?› çåà—˜{4`:ª~gèˆò0^QG5Žñ�îìT¢5÷Æ>F½Gº(X<ŸSaiÇÝ,ÑC‹›àû�ßLÔöh¡6ïmä›Qˆ½ú|œ3?�9D¢ý=¥Wâˆgæ92”zÓ*MJBæáéü~ºnõwö4çusãᎵÀñ еúF]åâÈDº0J78‚÷¯Ç´ÚbFe\Àî’9tþŸŒ°†ƒÅ•ôãÄ1è8=E'Om�ÏoS‘ˆÒßo–Q‹bëÕ›½Ñ üfÑ�›AAW­ÆèS ™?Û\©Úé.æ,ï%ä »Ýú‚¤¬Ôj\ÿÒëOçpsùeÑù<º'í\‘H«ô&Ú­€.Þþ…Ø/j'VŸÃhícg'»ƒó”31Ò®Þ<œÝìaõ¤4çö«S°ýè>Ð3]E½½~cÀÊ8´›è$µ–ÌÌÃØoÇß;{ÉÝ*o²µî(Ùh “%AcvqÉ‡Ë 6bp”7¦ß™d”6Á½‚-0TÛ‡Œ;@ež¬ ´€ËBJؽT·¤ºƒ�Ûz°n¾†¦qwÁ®!$;»Hè¶âd¼+5ÀÎ/œ¬Ý·ŒM5 Áòÿ*¡tc)^‰÷g¥t˜s‡¸¸èt)ZGf aõUèdçÃès>Ž�Ó)ðÿš�¬�-³¸m…8.½•¼ Û†ž•ñôûî#à÷²öªp_ w±'�sœ7‚/_@y"™¿$Ž~?‡âwÅ °MZï%Ò†«!D>¥‘ÄN_�JÞØåÓCä…üLª&®ÛEÖ‘ºLqÌyqž­ÑŒ#©M‡Ùè¼xò få׃Š[$è_›É¹ç�ÏZ‰‹�!Ú¾] þí1ààêGb ¸.ü^¨ã5Jž-bzÚ[hÁöD’'lmÏÓ6^An™Á)œ¦*}ÑÄÎú$.º[J+‰Ð!¦¤^™£ÓÔNܯ½ Nìù/"Y£ž‘G+L/¡ÿÎ,Ðl b¡Ÿñ–Ï r{zݪ„°0 §,&ðTVæŽ*RãÜ ÔgS�=;JOq¶•Š=°Íâ7pììÑí{2¸<‹Áw²`F±0t/kc{CÍYǽ3K¥QÏU…#vÑ *VªÙ¢i¨Ç¡:%é4Ob Ô(䀿*,W:žYÓÁ)º ¾JûáÓþ/pþLðÂãðgôîeHJÐç¨Å‹Ã§E!X¼“‚Y|33–•7‘!šsfpt½Œ¸·Ul˜ÉvM¬‹œiÎò8÷L3Ó9¾�ÞkyLeüÄ`ï ˜•Ub`äEÜ'ª†Á=.àè±™�Sæã^’mÀ1� ˜_ ·…@âƒ¨Š”bœÂ'˜P¤1¸cÈ�’O>r0Pî ƒ'tV,Ñ¡¯ÉnüÁƒGƒç€¾Û%¬ðX��ö1ôãÊdËà½^6a²)¢ Ne¯›àýŒÇôGn=yTi�Fa¼Ü5þ‡ ö­9-&Îí¿w¢Nâ}Ã!2‚¿aïø(ÙTC kn \÷ôÁÛ&XTÏ’î {°¾ð“Þ𑢎EçØ99ùÈL;Ç®ÿïù&*†;VšCŽlL˜8!ï¤+p»ë°§£Œ=n¨J~ )ÀI±p¼tÔ“5_ÆX¼þŠRÅÏXçµy¤ ) Í#;kóKrí' e[ï°j¿bÀ5¡ŽYš�ˆF&}ìâ—¸�ö‘ÐΙ¤õü"N‰ÖW’x—=®�êÑÌ\6Á°6ü ´¤?öÌ'ÇÈRð8‡ro†““ÂóPEéñn ¬´ä@¥E?5îg¦Üĉæ—nÐ3 Y)kañÌj~& D\Y|iÑE·ò=SÀ� çȺ$IlSŠÅ‹ªIîî5`Ø&F¢U3 Z&×í›G~éÁp% :[-pº`/\mûNÚ.™Âä¤þ¹y Á¯š5úý”¹U‘SÿÔè+ùµ¯�¼~dÎ2Yn;µ“HE}3/ýCÒ]áÌ^–�å wŸéqÂ^5‘{ 2`�Á-œT Ç}%è~íw0P· žVâ>ï:cb/o&ígêWO«;"ÞFkB¿�Ñ�7ôÒŒ„q5;­hž—O¡Qï’zPúZoŽÿd–}¾ ï.›á™ï”:�]¤~÷�ñïór‹§€4έ%])rpÍm Õ­/¬Ý‡ïK+à3GÆÜ£s¿õâñ™²xs}Þs ¥cÄNŸôa-\WqÅ⇢lŸÑ˜2|IsÎÀß,úøO9êæâ€î>ÔX‘ÄtYðãçË{©«–ñ]s¥cXÝ—ŒÉ‹Í€:øÐE»Éõ&UXWZGŠ‚LÀ¢0œM?�‰‹Iíð°ñý�óìQ2Â�âe8#ÆU s³�ùYHçš&e=.â Ž’¿!$Úôc÷ÃPÂ?JÿŠ 1;VÄABêu<ÝUÅøK*�ð=�PÝ»·�‡‘Çåþg Ÿó—ï×oäúõY˜+@²O=@“[|8ñ©Š}²±‚¸¼ ¿§¸Ù’lª¿V�“1| “¿K¢�€0§Cÿ>ê§¿¦†å«1+Ø&¸—©ëã/¨w@” é|å{l}Ê|NÒKütô"ZðuüsŸ@¸åõ—Ì…¢¶¥f’Ê·" Ý}@à éA[f–­*ùnÀ è4×ä'ÅV!°¢i¬ã e¬Ø]¾åxÚh)YÇCóÍȧ' ±3"™ÂÜAòq×Ù@\|cyºR�L|g™ú˜Ÿ¨ÀšØÎÄU;8þV©Tßå3fnåÅõ_Üñî¥|·v&·¶ã ìU²„®#ßXåñõ8ïÏ.¬/ÎÄç˳(¿n/™áÌlpÑÔ‚Ók3ÒüI³ëz¶1¾ˆ¿^�&TSbÄw|cÒÔ|Ñ4g.F©üóCsl_€÷Úù¡¸á÷½TN\øJçì!W§õÒÕÆb\ óý^QfÉò­E=”êÇhdå<“g7†-¹³}Ö� ¿®8¶réÕ¹Ž&È8Ê‹ÊÛœÑWíæW,‡ÿ6 £íaR?SW•ìžàÁÙpé:"ñ`Ö|Öüêf˜3E€IAÉÈlü”i>¦EéðÈZœx{É¡ÏQG,l˜Éé[ŠzWŠÈšäT×a ë|_BIëyrÇ"ݶ⛇wq´X›ðOÛen"DùÂrx¯ÏÏÖµ¾!b­ œ§³JHÆqYjØEŒÌ1-Zž`i¿É‘'®à,ÃTÚ/ ¶GßÂ.OÊìÕØŠ|¥pïÜ.² 3² þc›øóà­ô{üµƒØ´4“%+ãÀëÝ’õßvóQ ¬'× Lè¹J6.‰„…Söh¡ 'šçqÖ`ÒßÃðù�3ó\6Ÿ¬À9�Q$RùUn¦èçáï&£OI†Ö¥˜„¬éc¬¥µñçÚExù÷nFAª‚œ[gþ’`ÏéE07ÎÃÄúÞRÎÇ«µhÜïJgÎÂd4`ðnC4öŧÉ:—ó¼°w†Uþó‡:K¦BðÉA0™7.²¥èÔ6Ë­†`¿jô?†’áFù½Æö^Mìù¹e&TpÞÓ�h:P��¬ðçü«HŽùà*�%HIK^Íi7í÷TIá§4öE!ya|�¶Q bBsQP÷,Up—¦=u�¸lbn}ìD�'Óë/|œ·oZƒáûçõÕ_¯RñXyŽÓKE®Qè+òÂõY·.”â¾ÕødQ%�í#Ì2jxD Zô/ÂÃm ðdÕvzsã®ÿ98w®¿÷�Û›ì(IFB$¤ð:÷»¢¢T* EC*-«m“]vfFȈÈz¿Îý–¨Ì(I4´4¥(�Oã×÷÷œs®sž�Çóºîë€ñûY¼žvÀ-%Dè½/úƒöp•T×¼£·µgq¸Ï/à§}·¡Zÿ_ÎÓ,ü”Ä è Á‚ûW­f-ßFfî’Skƒ�u&ã·{ ‹ÿÝÕ‘Qô¹²ý~íB�þÝ´ó¿µì—3½Ð¼=’U4ëƒà°"æOÊJ°Q¹A‹â·óîØ3P²@K£é‚5ûàîÅ<Ò:]Ýd*ɱTŠëv|ÃŒÄ8:Uô,Á×· 6VÆVráí€6|}X�Ël³®ˆ8õüEž�(¢Í¦pJòTNÙ —ª;¡ßw‚8×®¢“Òþµ˜ËÂK#þžÊØ[ÂÏÓTòÃ'& Š�ÿÇ—¯£Œ«�Æ>EêQG©ÓBÐ8�B”.„ç\è9GNnV&Ó3É­1:µîdÐZÿMÁ²!%p(@�Ž!4—*‚úkcŒû–*ÞÞC+•¾Ó£=,nº~ ³ó°,ï]| ±Ëzp€Á;Ã4$S„6/Wàe«.§ê'Šiá©mè4±ÒU71Ò3ÃÀé2Øßæ%rBðæK €óÅͰ<<Î÷þë)±p�vW†ÿo6®ÊMÛë©Sf!m÷ÖFƒ~!UõÅ^ãyäô­�økW#¾A¸äHº{‰q¬žÉÐbµï´�O­Ý7÷çsŒä 'o£õ�7>LÎÿüËÚêO ¿á ý.ØM½~#Æ.¥hç=†¢��ßñôšýDø©6zÿ½N�Ãñðg?Vsx èîÍ¡û¢ŒQ×-Ol��[®/‡†�dú»´M÷a–()!hþÅÂW‡é‡sÀ¬,Ÿ�*Ýò„ïÀK(¦Ë’.ƒóÈG¢)‚ÒRµôI%lø8‚þËÐ÷ÈN¥�¬”·ˆe¤(í*ú»Äb�ð¼¶x³{ð/lЄûA³S#¢',±G+‡~«< ó.¿ W+"á[`.4wÁƒÊ8x)žŸ~ä@uï-¶ÐðYúKÙj™ÎYÐK§*«†ËŸVÆO§Êc_ .ŠK$3_Ó’ýoÉÒ`…’Hú….ræÅ4ÜߦKT3TŒ—�{5€^U7ììܲiBk7ý¦¤ˆ'â)©[kÊÑÏ?É]››@>$)áÍ¿™¿–µ`÷µ ÔøMáN‰{yJ)¸/ÁÖbW¼ÿW.<Æ/M•ÔûÓ&Y± "…?Óo}˜{È�•!Èï\fWyd÷[[×Ú„ªqYÄì¾?p)¿éšâ8×ÐÍÅø0]ùZfe/n3˜ �žÀ0ºgŸ$/’AJUkW‘®º(|R7 Úé±è¸b€f¬ ¡9÷à§¡�ë0—“»êNý±˜óëHûÂÀ™:pÖˆ†œ+Ù«ðþYÖÈ/ä‰ͦûft`E—%,4æí]vƒ¿¸�!™’�lj Ú‹ß"Wj3#Z1 ½ÕÍpµõ[\új&D&e’¼]+8×� Ðþè øØðI“C˜9g”ÜÿõTëu £ÞvœÿÀ4~ÎD¹'ºt“w ÏÚ‡MkÞ�¯±Â¸O¢Î>]KÖœ]A�,ÉÇ®ô"É"3Ï‚g}’•Ûq½¿\ç2¿µ{Iv¾&¹u3ˆ¬.I�«3�6Ý:Óþ.»F 쌠|ÏtxV}÷päN…�lò#ðÔõ‹ààôo(;EÜüoÑ/¾òPê_Íý²�–ÍÞL8Ⱥ›5dî�^j5¹L¢f¡ÒïäIoò)p rèPï¦bçp§a0Ü”|OöË¥atÐNÜ+~ï:IBÝ(=ÖXÍ.³Ñ±¾ ø/è0d•²zÏV�Õ»HØ‘}wÎù 32¤àOo—Â`Ê>°¾Æ®�þç€÷÷â¶‹ò¸»ò¨ŠìaúZ3»Ý�³&eÇ@…k�ùʘqv€d¼Ù€ê")X¾:ªí�<Ïi�$ú��ÄÔyÛÉ£‡éÿ’|MÙ“¸ÜP÷kn�'^àx›7ÔY8S ÿ²¾ËõNä…⸸4ÝÃoLD×/Å­jŸ€¦ˆQÉÂ/ÂÓ’[{6¦’c£·±Vù9~œ�·?l%1ÚQAnl-�ÇSÈòPo²Y,½ÊéÙŸðè»=ÞûyËïúCý;+øOcò_Ï]×[·€· ‹oôjðšŽ:&r×âó•â0÷v0ªüw ßý‰ƒâñ"�OþD gs!IVC³žÓÈ#âø¥èÿBv�Ã%1�o“;¡tS0á×´F¾ri”œ‡Âü[0G´‡L3ÚæŠl¢?Whƒë;UNCÐJÐ;ø”ý™Æ3w'CIï2äÈ‹qn|I…—G|!úàRÙêqü°©¾¼ x­÷ìáÂÝG4S[ä�rhtº^•ÊÆ1ãa’ù¥’Bì˜ìå¨2+·9€»ˆ8 ž´õ꽄ó{ܬÊMû•ßïoFgÛZ6tÉFT]= v¾àÈÎçÁÇo­ÿð“S·_Q5qQŽïÛ¼å°÷«G©¶òÞc*^'�É��`ó¡Ïô¥dú Î¥ÛoÑتÎj¼‘àü0w†ê¯V‚—Ë5H†O&®†‡Ú¯ 3EuyödX؇úŒ/¥wcC¸ÿù~Cõâ<«UçÏâ…õÏØ ¬§óm–+XQÁãj 0¼òO‹“#’·‰øïØ£‚¥3E�4G@ÊönrHø‡UØ¿7¿]~;žQ[Ç´Fº´JÓU�š"C¨¥^ õ.Ù´¿2 ü©¤Mšçã·ûÃ(øåÍ^BÓ7áB­Vzܦ‘úf}‡ãK#Ðõì†ßX‹´ öâG�EdÏžóø}Â6=7QèˆÏ ‹ã÷aò©_ܨp]ÞÛ½+HÕˆ'MÇ4ämL Û„a«=Ð7fÕTÆÑ ÿÛ8AÍWF£ÅÂ,’5³ Û—Ü�'N¯Ay§ '¾3š¸y¼¢¼M°üŸ‡x~.'öC}¸?>”ߥà¹Ó¢4Ê<_cÆHˆ7¹× ûN 8V7‘ÖGWar¡8lÐòfG§ÌÄ Êí•PZð“ ‰Q¹ÏSa´ë®�hˆI•Ãò0Þâ!Ù÷Aj]§ñÌ[5pÑq-[½ÍeÏMÁH¿oÝ`åÆ`\õ$þÅ:˜7`ïGZVy‹ì< —¡µ[^^ð‘ü(TÄ„Ëg¡@·®‘Ïøwv#†Lzá‡2?è­œ…ß<¢al]cgëŽ ¼£ðá i ߉^sà³gï Mߣ£Ôé#…`hsýAŸ§CÉŽO$“SÂ*¦m‡°C;IkÖ{¢à-®ßÁÌ4ŸðygS× �ÀZ½—Ü95D³ê×3Î�ÁxS’2íú gQ�»Êy$³Yp0U‰T@h³;�µ1v(µ½Bè¯Ñÿ(é·Ä³1tÓîzôaû×ú3Äéeœ•R_†ìÁ÷\£†5øexj_ØÏã�ó‹s˜ó×üÙz-<þH�jÿc™AI\ÊÜH¸ŽÎ pc#Ì+}Ž+œçâÌ»G±{á[*Õ»ƒæ´d€å‚8˜íÈ+Çl˜ÁG£!á‘8UîÇ{·˜¼ö8³ó5É[ûŒìöG"XŠ•ªâ òÏg,<ÑU·‚5Ñå‡. YÎ_¿•0MTo“›Y)˜Üý–”àØÐK ¦òq&ætàFÓ^’v2’H˜‡�qÈÀ1µqô¾&Ì»¨Äké†Üë«PïÁ!¼Ð~�}:'Ÿ^4�#�F¨ê�öîí$8qfN ¦±Ž’¼u©ÍÀQocµÇÒŒÍèk¬‹A¥%ðÕEÈŒ*–{‰>ù¼çWW?­".CÏÛo3‰óbqí��Xøˆzž¥À8²AUžæu`ôñ!Ì6�‡Œ[˜,ûB“ÎAWˆ=!Œ+ÌÒ)x–F¢ﶉ%Èé*#ßú*ô4:Bsþf‚þu6Ñ*üté:qžßF× ÅX…d•0]=a`ór5éœÆÁÙËoÓõÊgðŒ·¼�ÁÓž~�Æ/8IJßû2)×#¨ç©l|-~™Jã“à0ö‹í›X uOµ0º·ƒxKªãœìŸdºÑNþ[ÍÆ£—èתHvD•ûÒœ¦/�àr‰l­›Â{QQLj¿~…ŸÃíña™ïÛÆ,tz_Çn;ÕK�nW�U;ÖãåØuø€¯ ® >¤vµøX£µ�‡Ðb›ft�üÜý8‡™$’/’+ÇY*�‘7èÖ¸|ÔÍšGÃ>qa¢·€:¨éa÷£ÿÏ‘jzÛ³Y�­öë£Â�!£óÒ~ã'�4Ðì¸Ë•�¢Ëe8¿;®£ùEI\'?B®Õ$·Ÿ{B{Bªe~®ª*ÇGpRS7€ØÙ|¢àšÃì­p£‰fØš¬ “ ˆ/ Ñ—`§Ï6Œ²%8-œ2ødHüùÇ•—;1©] 7ØÑÊçAmk Ý~ý1�pS…½eøs�K Ë�+­æìª&¾ïÅhÀµHŠ¡úá’œ»ß aäš+S)c ¯ö§€…sL6VS³ò48*ä�Gð ); :E�må„S3:pFþ<hÔKw­ýD…æ’Ñ]“ä›1öˉ@ŒypLÛäYíáyté€î’pø2¬).�çÌRÒéþ©qOè=æÓ.GÚDZn ¡ŠüUFÀM œCAËÌèÛãšÏ« à›+:>=�úû{Éš‹ÃpìN(]´°6÷œ†lVÞ$„‘ ›>PQ3œÕõ‚ðh£Ù&OÜ�±‡'Àéè¬*ßOí�„yI’"¼=nêp:é û|b&Zí‹_ÔwrZ;\ÀÿÔ¤áñ•»øûµONÁê‚� *Ï›HOæƒ7Ÿâ¶øû£ .w® �Þ.G;>U¸\ß �¹?ÁAŒ’�šÑV¡+¥x§/EC!¹B¶*)3™ÛÃP¨Æ”¿Ó¦°˜ùAÌÖXÀ³J§_Ì =6™P±MLîGãê$|Ú,�M*Ϲ’_"³Ï…l¿4J·îÇæÃ¿ÑáB1“;ØL<Õ>¢Äägö™d6œp¹I÷>Ê`[–?C·MBø¨_4ß^ÅA§*œ¼y†5*K}‡"fó¯šô|%è»R7àТ' À—²cüô@÷àtHY…®ŸˆQU6ܹ�BL¦žÃß’˜Ö± J¯M§§¶‘ê#ÙÔa2Yi"òëɾ×edãa =³o<ÃÔmþ¨Ï¯‰ê/ΓÀݳIÛÍ!PY]Nžö­îpY¼â=Ðï¸4Y›Fov¨Â—?V¯ßª�à ]¨p÷9Üs2ƒ>v°QúŬ��1î;Î\Û¹¶,úüºµ¬ë;-޾E$è…²Ah<2 äòȽha\·¤Èò[Ð,óòÀöǨô–%Glæ�QÏr±¡–jzt2Û6mÇ’L>hTw}í·dA“yñ ÇÒGq1Ñ[0ï÷ˆ@žn•�5¾ BkU`4ù/»dÈ ¥o�ÙSž0[Úú0jô/-=9•Ì. ‚ëðÚ¥.ô4N&Åm/È{þ= ä‹å'ué¢-çˆÜ—`TK°C™Ç–øa~UÓ+E·+‡¬Z„BúCžSA6­XHëƒÀ<òÕ2˜‰Ÿö×à¡—èß°óÌ·ËÃĸ&õ}”¬Ôv¤c¯V öªí‡§«Ž@®e­‘Ó·ºò£K%‚iªjhŒ¾†“Ù?¬x^@Ò×´à|Ù^|e×FžW‘;ÛŸ2‡ÿ ƒÓ¶äAé�ðÛV•9b[àL3�Žy Òí¶ÓÑdç-X÷Ešì£*ÞÏá¤"?0üœ&ï¹ ê�•ˆùòjsï ùé� Õ�/A…•7­#±à"<}]ëž:€Â¨ósºäƒ½—ÖÑ:Ý™øæD•ê2ƒº·(.0Å·ó”ñÏè=4s–¥3nëqÃBHjÙEòÜÂþ©%VºsjiËš{ÐzT�W<å ^¿4£¤ž`ÐWgfÕ^1^÷K<±½Ž¿œŒbëì™N%^»°Jmˆé�$²uV i˜ÓI_üëie(Ý1Ⱥª±q§f`Šñn¬£„[ž‘ÃZz¼~Åj8ß™Ã<åÎNÑKºZH…#¶9ü?×�•çÆ12âÆd“=wƒköt;7‹ãnÑ�y$på>)PÜ*†ëûô¹‡²¡Èr tÚOM©¹phÝ/rÄ5$‹Ð5)¶Ñ,™â¬Ûÿø_`BÖþÞ@7IöÒ†¤óØ—ŠÚ ù�yhQL®Ìºڇ˰¬©œev�è¡<+óZyN±}5œqµ…”Ô˜ªT“žûº0Þ,�ómÁ]²—†-‚«÷S9) ˜ß§…‹¯{Ó…qNÔø’îó®gw9$2ÙOƒéϦ (ÁGNހ͡ݘ^@œ¬=áùNðw‰ '@Œ˜Ý2„šÂpÿU�‹šÊ³;MÞæ= Ýc'éÇ%•–É1>tÆ5Vû´27ÉG"¸3Àsm9.ÿx‰(¼,EéÜR¢ñª…^ìÇq}>vœ…©r›¡’]Ie“Ãp÷n"Sò�üþžDÞdæ�¦Í—�;g©µ(Ï&ÅÙô̹eøa|”løÀí{|Œn[‚…§'!´=7^fE�š±£@–]{}6”œà¼ñÆ(E8W}ÊÒõðV ŠªÅGK¯£©o",º2ÞÐùž Á™:²:þ›‡§·'À´É_Ìt�áÉ%z·¹ÈuÉ¥^ ˜“u™Œ½DáÞÇW‹ž‚Ùb3ü(ÛK§ÿ-åügÌËç%–*ó‘äEJ¼¹_îá—…Ñ쯢0vÞ¾|?ÆN”Ü¡ÇÎÒ˯ùáîØjtÚ3ÆÎmeÜz��Ñ' ¸W¯Íû krv�+ÿru¾f�Š:ôÏo_2™n}ì‰kB'®°ÛÚ`ð¼(,KÌÇ¿çàxpy²Ò[VQëï‰pEÜׄ¥0/˜3¤iëQúm-—ù|E® ,Å¢›2èå4àÀkÆWVŸ¯ûM�ብÿÁs¾,¸‘óŽÚk§ìu#~+r´Ï¥EÃÁ ô7Üf½Æƒ¯Âiâ °åŸÏ16èd �‹Þ?ÄÔËGº€¿Î›$=f©kC<†»MÀ’z}Ð÷8�;;ðR[-Ýú;�4J°MSW€¦� ªâo÷2ªrFó•»ÉUGuð3äÌPË!’uõ”¿5 ÷DÁÇÛXÖ¿ ¾Ñ›~xî#O‘:±¯ŸHsd/ú(èRû{SqÏ 5°›ý‘¨8Èr&?¼!+¡­ø Ut¾@Ý:ÚÉ [J¦ìZ?\¤1Fp23ÿ#^0ñÆ‘udN£‰×sèxí¯úâþ`8~qF³* ^Í¡ÜCäÇÕ`ÜË+FsµkØíbµÿ- ¶»Ö“]¸Ó¼0JƒžIA®Ý¸‘ÓÂ-°gýsRévÞ¦ŠóøNêÁ{{,.φ‹ßIue8£m o>ÿ`VÖ$+ŽãžXQК¬ÇÙº÷IΧ|r‘³lž% o>3òR“Ø:žJ¤N*ƒÙ;!øö¾¾É�«ÆBýÏû°pc]¯j,“‡Yõš2\Ö *ôÄ›zœ¬ÂRy_òp஥ß�2U¶›&e[‘Q©«(ÑU1³}1mµ¬:´�èÈsp»&òe’õ÷þ9ô}B^¸bEÌ9ødÕÈž¨¼ý0­®�ŽÍBÏ^Sph¨¡1™ºt¾´6~ÓƒË/9ijU�Çwÿ0î>0J�¶Ô#^©†)Û‹±½û µéÒÁÍg‹°9ïq³ #ì6SLm ÁGUƒpó‰,üšçÏ/½l•]õ —ž÷�=Zças`1¹[ƒ›�¢àd«35ßÙÆÆ]k‚æ½ð^M ,?ÑS¶–À>颉s¿ckh5×7N _±ä®ª{’×?Ó²žD”Ò9�²‡pb§#u_‡¹ –FÒ˜ÿ5BÍ_QQîêÛj�'ãÃá§î 2{Ó4ÎJCNuŸ—H¥þ¬€¬)ì1‘L|©˜ØØwƒKòš m*…ŽÎ‹¨Ü�Šá’(’g|+ ™û;uÐèŒæ\mcþÓØA?ç“ ×U`¾9 Ó“¯à/ %fp8 å˜gGnÑ~õ,l\…>ú¨Šça,§¥(2;Í0UÏo~©€«ãˆ}_Ü×c„.1^6äûYy8—j‚S½ã°ä‡[Ú€¾m:Fá€`îY§… ç:àuqúkG®UA ¡ŸO`÷Í0NÀC”ú‰Ñœ£h´é4v¤d ä„7í>„F¦°¤Ó Nãò|X<+’vîK"‹¹Гàƒ+s„!(j=ˆ«¯g¦ ÂñÑàrY ôü×A!fï”õ$˜ "«¼WS?Öôéb€òHR›ò�ðÿ‚�Þ;hêtq´'ñ¬qƒîù½^ÙP.´�„]5×É»‰lPÿ�JmTw¢Þw1ëʲ°üfuŠáÎÈ÷�j}žMÑë#û"-áþ¼K´í¸[Ûon“#WŽ’aüœ“ÄqKo ®°^CFS.�ÓbaX8‹ºˆ”Ðþãìí¿–ÔÏ%ÿj�#ëßÄ0Zƒ½;U»K¸´ s7ŒÛñÓ`¡,º%ÖʶîÂÝM…D�?.ëxÆì1<�ÞßõI†g³åôùɰ4ú${ýD½xŒX>D-—Þ¥;BÞ³¿_|`ŠG¨écC\o½ZxRp@¬móîÓ;'öÀ¡þ;¤{ßljtë%x߽̾s�`J,Æeû=É-ûµh–Hî³Ë žB‚ûTFÀû™Q=Îõaû#ždÕ““'µÁå;?Ùzö,M€x­&:Òj…1çöc '‰ŽÉ,¿i`Ø^@îL¢�¼ƒ‚ds²ô£'þyØÉ�Ã厓Pl8ÔxèÂ2¶¡˜ˆºÁäÞíeo÷FÇCºM˜•3Bîx6™Ÿ=J«>«ÀæÛºðªbu�Ù@•nGÓˆåá8ê·�ˆ ðƒuP"øÛ-‚ÛG�`Ýx:–ºèÀ‡ÄH™�âþiåÌê`ŠJÐ?O ¬Š ÏÃëC$b¡'=5H”�£Ó%å ¼ÝÕ ¨1Bw¯ÂÍë�ie›ÉÎø@_\ ø¶�*ÈÁjÑjü½<ÖÆ–­‡`rf �ìw¡ïó»ðÍO׉ýëßÅÞèk ʹÀ¹í‚¹f׈ª—$¶½™Å^ɺñNj´bN|›w‘º?‡§Mb0ôý6Z>× Ö æ‚Ø>$+®0¿Oü ’¾hš@Þo» ©ÓÇHÎ÷ÓÄõØUè¹kæŠ1à5×6Ù½§ËWMà¡„kô‡t"êÍ�&Žæ'ààýp^òŒXñO‡Û_âHkÎ6ª`3ÊÐò;d$35'ÚáƒX¤þ,#ß¿Tà©`ÆmúÃu¶Ðƒ§|bTC­ ”.ȃğu˜RŒ%[•°uÆR¬=_Ëx]2£Wè ©<Ê‹pF�ÌÍðæyeKB`e:uÚq ®E5ঙš$¢Ö„šå+RcÙ“´ö�ˆÉ•¢Lq$Ípµ¤¦ùÕæXØëóŽ)›+‰ïR…Ø‹“iRóvÔn—ä½=øŠË;¥ 'Ù™p"�²SùíRÕÆx¾ø*L™ò†\€º©¦4°Û“Ô''‚ü÷ÿ˜߉©G;ôÊfÒ#v«ÁbÒˆ©•_„;lüÑ;Ö ™Ç¿ÊGR?§¶rü$äú‰Ãtéiè‚ÓÁzÙWVù~)£ÒëŠÝ»­2v.£ÉQñ8­ó»x™.îžu™NÖ¬¥†w>‘ðR¬‹^­×É>4Ä#f²äÙúìktǶœOLÌ� :»/þºˆ¯k%°x—²·A„¯+™?-æ7g j*ÀCæ,ßýPü&±îûMMbìÑçàcºÊqZÌn±2á"Z›xd×''èéûn¥ 2L]¨ ~ÍÄö`8í¶ÿN^P!Þ²£ IÞÜAöˆƒ'í­ÙFró@M/|œ\Ñj…!~mÁÞ-‚¬þÎA²ýÒ>x*rƒi. ¥Vg7¢åݽ¨þ$˜m|Dô<2@#¹‹Ä¯¢;făçÓQ8P, kŒsÙ÷%¢xÆ!�3¤ ¶GÀ:Ý·Ä÷z%,Ú-@Wß„cÜsðW0“:¯žJ–ÇyÀÒ–HØŸâ×=ÖÐð…ZôùþCðëCâ…âáo›$-úYIJãh‡O9w®‚Ŷ‚œn .^áÞ«ÇáVN©ßˆÌÉT:uC#}ôb7ÈipúïÔ²�{¦�[õK˜ Ëå`^7'v�+j蔢.2ÇÝŒ¦ÔåâžšTjþÑÝ£ŽÚœ©©L/î�o²žÑßn“¶3¨*¼�uS¥-tñ¶ÓRcÿ‘¸±Yvæd³y6IhZŽBN„S>�Áão‰ù�@ŒõÜËÔ?ÐõÞ&Ä‚ÝC—.ßˤ­À�AAPŠ>ŒæŠBu­®ÞÝfî©\¼¨ç J¦— †cL«–|ÁÛý}0`ýƒ=,H×ËÈŒÂP�ø£jÂû),�Áv>¤%SN;Üî(œŒ—&œ¬hï÷ršš‚§zîPŸ€J’ÆÓ‡8=¼~Ù%¬^Ш üóú/ô¦±` »Ž×šBÓ¸ÞAígÃÕÇñôêâGôÄd-lq„'Ž•LÞ:Òb) ;nê‘crðk°—üvÕfõÕ䍿ÛýÌ­ëÚÈ7u æ)OGÛ\`¦sÉËTÊËZvÂè3ç¡ti2y çDÎåbunο¹„9a˜×½ú÷»Í18è�G·²ÁÌÉœÙà¶õê¶>bõÝÑ“nB»Ì{}�»ïo5º®a®ûUáú˱ÔéN4õ 0Á¡R<CwxVôÎjäZ?ÔÀ§ýÔ['™¿ýUvÂÍ ª°ÓM’láßmµf`#‰Œv&\[ ˜r‘nÊ"]Žå°èlÌcþ0ºïÝÈßìÈ^–·ÊiqÆÍƬN ÛaîÚ¨7ï¤q#Þ ñÑœf = J¹¯™Cp2*¸RGÄÑ^6�yp‡�W[>BÍJ�ÒÏêØÓ½Ï�ŽZ%³TñÙæ¹0ÛÆ�4Ðí•|Ä.ï³ôá Œi[„‡–òÓQl|m=D^ E°Vóf?¾U,ÿ‡o”°�ÈjÉ¢WG‰VQÃ{ÅÀøá» –îö �£61ø$x l 9õ”x¹>F¨*‡Ïw3ßÃÖcÖëÿÈ‘$ØYx³GêaËFMÚatZ‹‰çÒ!æï,5رõ5¹“b¦©ãPÈ%äóàÛ‹%8¦n ¹íÁ Ìðغx:<)@�•î@ŒŸçWÂ*üùá yÜ�Gî ãï¦8݉ÌûCÒdŠ©! ù±‘ð„ïÑkLÁ}L•N&SΧs¸þSîv¢KîñÃÕƒ—顯@x³ðïU@X‰óº5ÿÔwBq 7ÊJDAÚ=h±ðÇŽûòؾ2 øßœƒßcáß–wã1‹n(‡MCD}®úÜâá©ÊM´ùr:ÚýËð“¹Â¼]sé…–vvJ_ Û»ñ.™½‹~*)Ã1·\ ,H·0 jïõ¤WöÎÅx¾ ý3—¶ÜùM×�Yp‹7Ý¥6W1òËŒ”W‘šCWq­ˆ8SehMcÓV`¾EY•rŒ”(Í�Oèàù‹ÀϨýþ|È �…l¥éT9ö9‘wh$Ò¾cŒØÕ(t(¬°Z*Ó…íƒZp¸» ~/JÄäãa m( rm!ÄÝÇ: ôaìÌ,ðүáœWÌ»-üXçQiÈ�çR�#wþ£Em×(�#…¶ÏÁHñl¼®iïk¹ð½ÍæÙfãOE ÞÓû«¡S¶ÓÍ3Fò à�?CÉÕÿ4¹½;´aZòšæxG¬…EAtx¿UúF¡’8¢vÜJàÛÙ‰]³­ñ�׌ j$ëb¥ ¼wõ�‚È¢ð™P³â,3»¦•ØrÀæGÐé†ÜîB†ÛíOó…—‘èÎðHvÆp5˜?’AÆ«ÏÓ7#¦Äs�÷Y@R¾‘S#^¨6œ YÖÓè›Ä�È{޼ç]¤+‚0NæýÖ—A*ª« à–øê> *7Î`bÂ3â�(‚Kâé×d„ÀG.V µö<©!„Æü©žW?+õâÃÌ ¢ A^¬fÀ%?aO׺œEA£!b}e'õïþA஽±,ò¯mFÕ®t´Š“¥Uzª´Ì÷9iY=VŸ+¯I øpëH\IìB~Pƒt ’)AùL;T~ëŽ Š7q·]ÒÿÏÁé‡N‡zÛtvME®ß ˜ØðoÏͶøâ@-ÄýW5ÿY³‰U]T²H–|X�irɽ¢!zqeq˜.B�Îe÷–‚ëþdÈ>ª�O¿ì¡§¦xBµå+_,_m"°ôà7vûDnVC‘+;�û¶”÷�V‹rÎô³bíáÈŒ_¦æYg°`ÆäŸ$̉4¸æpÎ*IîŒÕŸ`í% &f—ÈO¾mX¡-Ë»Qª†Ÿý­ m³™˜ú½,ü¢FˆþP9óc^Š Lõ!ºyË^´t)a ¥I…Æ R÷6qÐòÅó­?èœøÙ¨òß\zM²Çe+ðˆÜ€�Ë´ž_�&âXœ"À+¸¾‘—!=ɃNrÁE^ŽöL[5Ù[Qòa6SÑfÌìN®!X|0‚F\rÁ¯Ò°Þƒ!¯ôžÓp£­ýÑ•N­“½™ù•[ÐLt9(ÎÊ'GÌ{Ä[ĈŽÌ|5u9.ÈÉ„3/êÉ?ŽÕÌM4Ûëá„.‡¤&GÔ‘KÁi-ë`æ'f†¥/‡·ë¶@òç9ÿAM¯�#]|ߘ”kä@‹)¤ Tâ¬/ïÈÕ~òùù ø¹‡†½WB‡@uÞ„wœé­¤ŠÇØG•C$~ÆtbÛ…ó«!&Ã(ü ‚]�8ïŸ�íí¤IãmäÒú©d§°«¤M‰iû9Âc?j¤éÿ9Õ·º :>Ž½ê» óÅUx-ƤGø™Å\¾@&s¥5*¿”ÆÿöíeIoìYÚG’ûF™p7[š^7%TS`›»6ÞØÜŠ%WbÇÑ• ^-Úg-ÏxH¾š�Ñ'³œ/JtùÌàOɸâgÊû¾"ŠdÄ5a;•ÆÆb‘s™vù ŒÆ|öÆ®,÷ª†?7gãîbu×>viÒÓÇ®àŒXg?l@gë•Ð�Ckñm#Kc‹vA¡­-®ÝûwÿÿyŠ<‘ˆ¨!°—4DàòÙéð:UÌÖ·Ó‘Ø/Ì´²ÙpS^ hQŽ4<wŽ ÆópXÇ1÷õ²Sön�û®î Ý¥7¸?A)Š CR5­®•�%’¥”õ,6jÚ:¸[NÓÊkèDÛH;«Êi3Å:Ýfäkìf¦˜¯Å…\¼}…ƒ{w¬£i¹spÉÍHŒ‘ŽEKŸk°7¬JÉ;YmrçòZpl<É>Ÿ†2K0 2AqèþçdO·ÑÙê© 5ž«h×Ìe¸cÛ=üתÖdaqû|Ó„;5à©ÿ¦eA³m |kºNïí.—vaõü†�§uãÿ<0í±•ÿî0Ú8v Õ³¨[UZÈ,§Zјxf%þž6AfÔFâ�æ pü’ÕV_M;¢øð$†ÃÍaO6NÚ Ì.–Ãþ¸y¨Ý“GB•Bèˆ!´·œ¦’�Xœ´–=\WÎæl9@çż I/Ïb©C&a3StmG£‚¼úh’pƒöé‹À¨H3M¸¶Ë6ÛÓ�NWˆP§0|]È]ŸHU_j Ãn!žWw­:­wñWqókÐ79žBÀèœ*5_´ªó„°'=ƪÊù=f ÿ"™KÑ÷ëaúbýIVVT‰~5ê!§÷¯Å²íG@øôC¦ {ÛÖõÂv) šÒÛ‚/ ¿²øX5ò�l ”ƹºVçÛ…9ÞÅÅ`?«,ºC`úÔ×pAf%¨˜'ÐÓÓ'é²£—pê½BÌúäAXuyô) Ö óáæ‰`àñ™8GYÏ·#v†�—í‡U2{±*Ç縃ŸÏ$K2%ðÒ«bPK£SYÞ©øåϞݙC·X² fç@Ì~þ„(a=ðS†ˆpJwmŒçÎÛ¿Œj^"¿÷jÀïö‚d9+ˆƒOkßÓΫt_¢>j[ûÂW=LZ$�†`ÖëEÄŽyî�C¼çc´û‰-<²a0iò ôG+àÇÒ|š&Ë¥�Gà–spêtSfï¹µâî �Ús¶É´â¹}˜­´§sr?Zµ?X:Óã¡âØ>¦òoD -ÁÜŸÂ$¦[å] IçÚ2¶ãÔjàóu»™Ñ{IJ€0¬SäV×¶`—Ò-L¿¹„×Gáò_á ¿t Lº÷�Š-h!ÞJ3õÊh³f ûô„ò}IÁå߯ùê¶uŠ|J>ŽÜµ¢8²8·÷Db…W;ñ¶8†*åŸØVšh`üœÊЬ‚'~–Tæ^$h'åÑ—æÓ!Æé!}¯þÓUvÑ#çX½�´ÂknNø>€ VGœúT�Ë$s¸NL[A1˜§*‡©sB­Ò¶Ï¦¶.Ñàx+‚.1„íòmäÍ—RxË/„"W±É3¨?EÿóµfÃpÑ•a^˜ÿ¥¢ËÌ`÷§T8àM¶ßÂÍ® |žò�nˆi$¯ÐF¾JZtQ‚q´YÆÈFˆðzÜ0÷ŸÉ{t3}®z.Ìù+ö‰´úMP9}yÞªïY`R‰òí“VV[/·R-Y ƒv9Ìvå!àÛýˆvüÈ�™sCÉ…œ“$¾Ä ýÏNÀº½ ò•9„�aÕ%s¢è~–6 Ðw‡�íy¸|á<ÆÇ÷‰ÕŸ²’T¬I4Ÿü…¥òj̵Å^˜¤] ÷.�¡_lîX <›ŸAFí¡èî4"˜ö�´�ïÇêú°ÈF#V(ÀþQ2½¦™÷fbvb#î M€�2�Œ¿I ÞTn¥Öt™ôY¯çñ@ñjûóÆT4¡þý:ºÅ}&è4õÑŇ=pp.ƒZ«764L¬DÙ³ *–Æ^�‘‹fZ\˜a-Ä{¹M‰UËúƒ �hL&ûÖB�“81VùŽÑ­É²XlYNgÞ=†23¯€lÕ'&Íg5Îý©‡ÍtдfLY÷€2!ó±±-Ù¶PÐ9GàUô<Ø ¦ÌŸúõdy´: ´×£À høm�?bV¢d÷øóEòO…â×QB¯n ¡e}adCä0›šNG‚ öˆ¼(¬'üùŽÀWs�x%µßdg�ÊWÅœ�=ÊÉô±É+Ò!]Ц¿óUXŸ_�ﳆˆ¼ö rCPÞE]²ª¿'ˆuŸT‰Ô�[ÌÐëç¨DRÖ€ßx[ò±ŽÞ7óƒƒë>!H]§­¡s᳆ͶaÈ÷)ÍŒ´òxÃT�Nê±ñˆLíolLB…ôIúhj6Ýv+œ 9'„²Ž›P¨b<õ}G›¶�‘ýí0˜®‚w�OÅš‰ó¤ò­LS€³êË@/= ò*ÙÌ~%z¥-ïX»*ÜÞ΂º—«Y÷Ö^8ýc.ª|Ë£_Q¿E¹Ð‚O’¼³�E¤C%Œ÷q©§fäå�%ø°y'.ê²Ztñø¨½'Ò{àÇÚV¢ãF¯åÿ…¾ònRà%‚Jb±\Õ§žÐ~2˦åázÿÈ8cÒâ¶#ÚÌöª> Y…”9u÷nËÂ�•qä`¦5æ›jpŽº ’¨·‚¨9«›ý8=€ŽEhÂ{¦Ÿ�¸œ>žN–·Ž‘ñר¿–ôxMUœ%HÒjyð´\ŠíKÒà~{>‰s‚èèA×-XopM„ƒáÏ»kxÒb‚<ýà�×—,E ójZ!Œ*u²¨þ6ˆ˜MÜ FQÕ¨ˆŽïæ³×¼eè®eTeê-jµdÚÈ%‚ù“WpËï±ÖLÁ�–Ẕó„Dn쇵¤´>Žö\yJ"næ`wæšç³•f4µâ¥ý­¬]ÝL»³³§Ì!•�¤\Ô�cÓìƒÅ¯c`�“=,‘‚Œduº)û¯®'mbŠx¸·š˜üØ‹‹G¨»\®›nŽw¸µ™ ç¬'Kì�1snMÁQz>Ú?¤)3ɳ%D¯NZ6>¥I¯ÃºÆè—èqêÍ7%ï˜ÀèÝ—ÄÕ ž,>B¦”İ93~àò�¾°ÖF†¾ “q}4{Ù0³Pw‚,)«D]ÿ!ps¯…Þ8¬Mïc÷×Ëãƒàdbü»“Nù-ÌÓú‹ ÜŸÂËö+Bµ7�ñÀíTªm†*¶r$ž!³Qf7ËœP¸ˆœ•ߘZåjðc1œ¨Qƒsü÷Ñ8A‘çßµ ÝÒû¹'ØÃ|I�%6 ¯Øì!Ãþ5T9/ŽmŒ…"÷ã´Ðs ”Þ¦SåñÃ@kláRWûˆ„ŽÌt¸Âvß Ñ&Å”L\ I¡æZÐnµ[–{¬;*„¨PÔ4�‰²€ü„P¹LíæžÇ�§Ê¡6?޲k‡‰aL}|Ó Z P�baj”•E:N¦ã®MF˜p%Ÿd.ÅäüfìM æÙ ¡Î¾= >w Ù»V Û9ÁAηtDzPb}È—.}ž�ÏFr¨ôEÎW¾mÜcSAîn)V�RO§µ”›+Ï,I7†ƒóqº®5þ:æ©Ø1 mò¼´eÓq ô(zïoÅ‹R³ñõ Eœ´Ÿ¤Ê›¶ã—¥?ñZoâ¦AÔja^ßU:òˆGÙ}+­dt ©ýAµm˜�-m™¸rÙÿ‘tžñ\ï·2"3Iˆ-IÆû\ Iˆ¢ŒŒ†Ñ2*-{ϲgV) )Äû\ŸH›"*Y©4Å·´Ç¯ÿã÷Ü87Îã\¯×óy眙ܷÂãø¨À‘Výå¾øœÕœí|+ÿÆ��O®1!J téî´‡Dë¤Ü|ÿÿˆLÒ{ß∿«¹Éús3ñ¢ˆ,÷Qr/9xÀ¥Ê`íà=êÒ-Ýd¡&¡…º¤;®Ž:JÏC#qŽÙmŸs©šŒ2žKÏ$]'‘Ûî‚æÛËlJ¥ 4YäÁ•¡&ýrÈÄ›÷ô™ëf*¾Ê•L–͆y�pïÝQ²7¨^0¸N?f|ͤ�‚©Í™!3Aóëj;OO7ÄS¯‘hPt{9,‹äôs¨O? Ý¿ˆäÒÞØôÞăãŽMN˜#Jˆn°0GOzWù?/§�S¤DàŸÏ3²¤ºÞ9_±3f!Ó–t‡˜ºeÒ;Ž�ßX!óuñ�æOo–“cÏÖÁ¾’ ´êü�´JÀ¡õÀT|„*X\%�fšfAΦ^YP< mÙV ðI’ØdÜ`Ì4”pÇÉ`9ÃÖ-"{õã0ý¹4Øþc�Ùð)£Ï/Ÿ²W–. ¼‰ÇÜPÁÎkhaö˜ŠÞ3€+êú¸J¾Šî/Õ£!6ë©–²çâËjúi¦½%è‹[÷ºC«Ö*²NJ1=Û�Æè÷U’`}žX fWˆƒ^ÌVó"v%¡êÎè½Sj²v‰Zs#ß-ð»lÙ·nÑ{§w€lìfü;í -©ŸŠÃ‚xÎ+ŠêZ‚Ã&AÌ˾‰Zÿ­GíKq†] í3p%)»«›¼|ãÑ+É�øÁæ>L‡©Ÿ¨cÆVKUÄ:a£ùbzm;ô(¯'�Ûä¡fv¬M¸�S}3°ë” géuM\§· ¯½$kV˜¡ÐQ(ºfƒ)'p¦}8dØÇ¾ ˆ¥«_nĵùÂTL_[ÜRh©©4ÌÝ'6)$}Ûm|Ò Ç­Y[‹ñ%›‰]l5XX§‘ßã‚(ߊcééŒÒ[~ŽÀ;_êã¹ dwR�]ñ�åÉ–††|)²˜g1Õ�òÇûCó`¤ð Ü3Ü„o6B@ˆ,÷©Ã5×Z�{W ~³w”7Å »U7ƒ€*š<¨ß¬^+ʵÞ‚éç"`éÔ$fýØÂû³I¼¡+>¸€Jr^zªØäwåq²oÓL4ã§Pwó(5x· ·­ÍÁú�g =á=šâe‰£LåB>Vv«(�y|ì9ü³BÏ�Ä�m hH¢ñi½0W t9te8Á³[Ë©£ŒõúØHJwÀtE2Ç~Èÿc€¶x7dWŒ“ЉùL]sån)ÀˆÝ¢Ü»ÙÏpéÉ—P"R‹ob@~÷O”ÝâN.z ’~€F}¸ ^EòÌÏðbbºF™™êúK�¬ÖRÍqž°/Ǹ�;”éVÀ_ù‘pX@_‡ÁlÍ�äkÚ"šLåó07wTR\öÔ€HÝk˜úët–d2‰‰ôÉ­~’¾á ¿åÖSÍkÁä� ©,@ãÔg˜÷T´KÊéÙú9è²ú9ìÙ„kòÃHA¬ }jwâuÅ Åâ&ÙÅÏÂÀgzî¼/8N߇IA¼£,'ôçR0ü“Ë„¾´äF¿“á<¯@à±Ä‘øL’×¼Ä>E`Wá‹fN/…S!¦8¹#…^â…×4èmA]òf,SíÁbï-ö¼ò7*2O‚nlIÇ5|tj„ÅÍOõaSLjŒ~¹�‰d¦µ‰ÙSgŒ5Á%,æ�Íâ*YHÁÎüDâ¤>œP�€mmÈÆÏ›.X«—$vø í΃V”�ü¨ ÓN…1³äšPi²‚�ySŒ½£íw5¶™vÅàèLøþÏCö‚¨$/â < ªŠç2¿’òeÿXÆx8í.ã¨:�liÔB!𺔺 n$á&%wu_àÙƒ0å>íjš/iJrm¸´ÅesS„ÇS˜6L¶o†{ß0z•ë±Cû5Á ¹áa׌“U† ø­%�mª.Ï€¯ÒÑ¡Ÿ‹BŸŸAxÀz"r-†ÔÃfã½D#0š¬ºæ…CKjQݱ Ný|F[÷$“MuØ­›ÈºIÐäºÎ|íÜlð·Š´ÆZ`ÒXiŠ|B‹Üê~¼ 3mì¡O?�*½=�gOñr¢ƒ´Ét>[Ô.úHø„7’Å™Üb›lÒ<óú{uâœÃ�‰e²$½¡ÜÆŽ¨dÒ£‹Cˆ•‰9}6�Eâ#±åÄúZé «vq!XáEÈ%RÞËÑDZ l—ó‚ubé\ÅðvýG•_…{Åéôt¥‘©ÄcßL:-݃ / ‡³éqaTÞÛ€ÂÕ`ï©õô`V »$F�ÞÍHlúH„¹ë×–¡æèbp¼™Dùµø96�ÄLÈVÆ…�v+]¢��Ì3F¥Ä·é@ÚœqHt¸I_…5R³!]´ˆ‡[‰n›]€güV™p•J™CÉSÔ°fU›/Â-»Î̶0@¯Ä,ª©ô ïΣ.ךqÉõÅ·Þ¬#è”§iŸcúçWµDAŽJÓN}Î:Æ9{᳿‚=ýôï’xRî�æyô×…rv÷p h©ÕàÏ4^lð§p"]’3mS-fþ惄˜íðnõ0:‡ÔâÞ3õ�s¶˜š­Ñ…�KTaáÂ\ëÃ�i‰¤Â‘íôSV m;Ã…oó è¬sCÔÐ- ƒÏÑ IMrcÛY\å{•f}Ó%6tð\Ö *tå Ê­Z‡ƒÞWÁôÅ(Ž„‹qý.–¡·­3xÌ?‰Ac×ÉŽütÐX6�Ÿo¦Câû©X·2^ }�õ�¬˜c�¸n4¥2Öq×” Ó× ™÷„Ú%Bâ_RXÎÏ}¥P†1N¥8®µµ.Û¡hÊb.#ï…³Ã"q¯»î(¸û‹gsÆ”ÇØ fÆ:ï‚­«û}_vg”@¢v¹x© ¹YÑ;8С݉¯,ýÉSÊÁ…�ëiºñIöˆDþžMTÜ &�£þ5–7;|±ÂÆCÒ”?GŸkÿgzÒq è@cÓpf·F<Ê�" ÆpÕ�œ¿Ž±í|´?©›Î;€Þñt|1RÅÌpóJXeÜ…Î6ùØòÇ cÔÁwCl¼ìˆú󕸳EÎSöãGb똃%Űùù9x…µW[ÛŽ�åÈ>,–Aƒ×«ÑÛ¢‹>~q²b&aèp/ðý f�y`iÀ( *±å,tð‚­Ì4*9ã6®m/ƒm~iêC¬Ûø _Už!#}Ih>~ÖºŽ4Ï|(�ƒùJP5c܉�Çõ·­8™P´Bœü9‡�³'iýE'X1ñ… ˆ CÍ}%ävo'¶ñD#¹7¾bH•‚Ô­B˜(Y}µÉôHÎØ…G&syQ¦ËïÞu˜…Õß1/z�XÚ¸ÿÝDlˆàðlÜÙ¤„£âاŸ„¶˱Å$œ EðBà oòÒI|ØUª‰avòåsЄù Z:�KŒ×#1õŧ[I@°áR‚=»–p…BЗÊñ]Þ8œj–Òµ¤nN vu ¿ ‡{êŸ æ™.U�ná úâEœY½lè;)T*…ÊšÒV¢ õ÷;0Y³‘þœ¡Íõ~ =½’&ø`1í ¹@=Ëá´½&{&¿Iv:¡2Ó&É)«zVG‰T·*š¬>µ”Ôœ¿Æ¾X°UD/BŽJ ,n%Ïž'Pûc"¤+"‚Êh'Ã{g>Ný®Ú©沕)Ö|¢â>ÀóYa¦Ýcc&@©g&8ê á•· ÌÍ·£¤cÉiÔ-ý׃aröáljö í¼WˆÕyhåZ¡cëÎ�³ Áx¤¹qÑ×[7n¸ßGÿ•TÑâT”ÁHOtŽY¢ä\sT\¼ŽìÏA,@úIÑ›N.ð`ºÊº©÷½£øüÖR:º¶ÂXùë^8ßÑ Â—pùË)¸6Þå|” 5Ë9/Fã¨çî]P“¡Ûc^£÷IÎáó/ÉÑ 8öo-aÏ3:Wï"þ Æ”óŒQ|Ü>AøÏHqš~ýÍ?uÌ¥êm�»o6Jê�Â$Ñhªöè YP^@Ê«3Hó×ÓôFòlp��Á¯;Hûµn²Xɚ؈há[I[6ÖÑX9�+Sò“NXªsÊ[†p³ª'ÕÅÀèF}àtåá�·Ö<‰¾i³ázÈÞ"Æ’­(à5Ú|´�YÊp›®s°¬q’ý˯}dÿtΤ'ó�Oß 29Æм2¢í�¿P'D<`øvÇÃÕ«ÀÙ÷Ù�jˆ '¦Øe{Hß›+DËç?ZÑ J�Âh¶þQÈ.Fw îêW³8_p8úQdÆ4>ŽVöòåé+úKX‚Ãu8éÌá�UÔÇ@ÄÑÍð¢5v¥¬áüI†H¥;›©{ÜOfNÇGæÙÒL`#¿kq/DŒ–È…é"Bp²&ƒNˆB¬ÕÄø1ʽMÝf(q6,H`¢î àD�9(­ž1ÔÕ˜‡H³ò5ABn\/aC«dQxz9ÔãDÄ3NãêMÃÍ­’xðó0Uoó û øÓÕKºúŽ âÉ�Èt�¾×�'w®p#Ïçaâ a~KëÑ\L’éŠ ÙÄIõ+ømºA~»Ëpeçh0{êdძ$¥zàY�ÅöROZ|ü<Û3~’~PË"!+~Ð]2{¾8~ÿ tÖƒÑÄW¬7Ñ Ó?;⸟ä÷5›�—�·¶@ÇÂT¼qHÖRä6¶d³û+îýóîVYã¡' øs_ PLC÷¯ŽÜe À’7Ås×_ÐS„9C6�쬦wÀÿ)�öŽ813<ðð>o(Zs �úð¦Vªï ǬKšàu®”>ô?B¿>Ï#Õk8×7pà³á=Ìom�»ùÍ$«ñ;,LÏN~ˆ5©€´Š"°ÿÐ ÊÓš±vvò?þÈ6ñصœ³Ùá>3.Ó‚÷ñÈè,Xy)”ž¼ˆe"ª0zë"®¨<€64»_�sÉm1ž¯£}Ó0ï‚\"Ý´YVž´ßׂ96Õ0<ÞK�ÀQ½‡ø.£µöÿ¥SWºá¡P,üLß©¬¦³1ޝ=KïÝã�ÏÓŸÓ¡á#´KÔ_�÷’Æu½ø¼û•ùYM’û¸âŸ{�« øºØe”Èßåîøù’ 5Ù ÙóÜÀy¸÷Ä©bì.iô+^ÏÄ}ç�&:G?ÀÏ:x}¤ öujBmýÐ�(Æ¿‰éDÀç Ññ gäè\rBè!=¥„í_DáKÒ/r/^—sáâ*ÐKð¶X8*/<×|¬=�væ€îÎq²þe2ÏÎÃbW):éZAbÝËÈü“½8‘HiÍv|ÐAzKM¡øJåô5‚×q>ÔQŽlòÙ]�Ïÿ^#5^�lÛÝvq œl×@¼^6>ÉvŠƒï\o²[æ ±Þ€›w¥’Ø=}�•eŽ7Uéý#Ãd¢LÇUӱŕ‹žHÍã¼}°¡Ü¿´QF‚N+’àÆÌ ù¢â\}s>®[³÷Y{%1{êAÂ3üqW(‡Seüwî3V§<¿D烷Ø=Ì\TŠœ†9Šnt~s2Úî.A¿ÀT©¼ a {0>*ƒ´Ì梆8?‡ó4 fO»Jl'äQ)Ñ~E[C´Ï�W6bc�Þœû$}2¥X%n+Bûba0]ƒãU9‹{9QÎÿ¸Š»uá>-^P9ô ²š¡m2¼©,㾎{K¯Å"dk´£ÊÐ=¸’ÝŠë¼B‘|tu\~(J ï’û÷ ÏÍÍ`v8ƒÆ&`b†¬Mç¡uCDCÑ€Æ=ba“™'|¾'I+»bÀþ÷¸ÜÙƒµ¿S‰�çCX|v•�«£¨SÁp/å…ÿ†Üó Ã\Ѻø7~Í}ŒË¨ÂÎD¢>F á2z¦/å ÇaEÙhyÅ’éêéœÑp8_Ã+ÒÕ±Tö=¢&Ëý qà'Ñö ‚Í~~DýªQÞuõWO€ÉúitOcÄl[�Ëht�×{q¼4KE^$Y]"`±çë4’%{•qìiLß6 Ö¨äÂÑGñм|TH“ãú_> ™¦?!Yö)m¼ˆP}æn°; 7ßô¡` <ÅÈ.ÇzúËji6‰R³shšn¸XŠK¯1л_~›9Q!“µ\•=óô)Îk›…;èm¹&¬­Ud§ºòàæ± tÉ>Yp2¨Ä~ëpÇ|SƤтvìjyk“}?èísÁú—¹ÿD£•ì1ÖÑ¿rB¨é­,RhýžÉMBÃSIð>l–Õ\2yõª‡yìêBþN.¥ë©.sû¯/Ä­0`w\ÎÅÏnë±!à­1SÂ…GÈUG£…%R>!ÿï0ðëé;Ý¿ã1k%l8ÈáèªaýêP5ù‰~æŠøŸ”:iW`Þ‰LÛ×D-¿O¾9LÐë÷¾“•Zè9£ÿãJSíý³ÑÜ,�.Þñ�YL I ùëæÖb^ŽŒ†%Ò;ÞDqn'Ñ®k„A‰cøJ¨}î—Aq” ¹ïa ²«U¡ìO>k†þ_ÒwîîôÛQqkF�IÙA­Ýmf[�Ĩôè¼¢«kÔ¸ÅÎúè5' õ.§‘Y§ Á{ÑS°8F¡çÐ4r/„♈ ‰Ân÷j SxM¯¾%�>±�s²éû*[ì®ôÀUêÜEëy9…Ÿqôó%bº¡ƒþ0…„ýß±¾Qv DâÚ@¤Ò*bðbø(`Õz®ÏkФç¤CxÑ ºsÁ3hÌÔ‚æ`jú– k1…;Q›Èå‰t<”ñ•6DU�²ác8÷Ì#¢§<”¯F‘]KŸÃØk9òøŸÉŒ<ØÉVgC«v“úªˆŠ¨¨ÿã$U“çRílÚ³3øúÉàtÒýsÇHÐrH6 ®JO‰ˆ¯<î2“'÷ßòqoŠ¡®ôyØÔ 3HÜÎàã^Žœnìp=?�õ³qZù$Ìé9·µ˜dÝ.ƒ�,.Ž(§Àö�‘xÈYœ[åñƲ <ýÔF¤$�G»ªcûa†Æi0�û‹:I…cãÜQÜ£²ëÜ­0T#Žt_‰ÇÍ«ð@¯8Ú¾ù¿·žµP>R]jgpñÙÒ0áL|#�!æ!pö~)ÛԤ߬ÎðBr¬8¾—HÂ#‘s8¼` —o©pù¼–£M0'ÛÚ-ç3lîÇF)ý¤rÒc v¹‹îŸq ‹ÓÈó‹ÚPxÊW›¼ÛI·�©Ç¤ºiè>Op³Ú,Æ�ûÖCþíƦvÃW÷�µ4|6ø R²‰ci?VÿRC'ãöfÛñ3DÚô:ºÉ�²džnãë3Óa3Ü ˆ¹ÝuœÆoˆ7tú�ë2—Û°z&.¹9Ä8ËD¢áHšÿ—ˆL÷ý•*PŸ<¦¼ÛÙ…zc´pYq.'ÌAÅ\}  m“;è½§x0 ˆ���½YøD>šÚa/¯éd5<òh®QNÛ©‘i'Èó¶Ó8ë¸is¼["\=1I¾I– ·\;ö¬íAž`mP Ý� ²C<éÃHE+r{_ì‚_Fs0·è!’®3Œ1 472)I; 7Wj³ñÓšyÔÒ±Ã:‰ªï)E’\ @œ ãJ¾’Á�¯AlF:œ,R@UiKÜØ×É n§‡žo'·î©â×[šxÿÛ¼_ó÷uÈpâ%‡É²�%Tes èraÝ, -³yP[­s­Åà—ï VŃèc)ÄSkÙ…&V8Âfâ`Q(!�Wàì˜XJqWo ,qZ…7b…8ÌßJ˜Ì> ‹7 s0õ"MÐßùÿIhÎâ*¤ó3'†/Áòž L Ÿ¤•ß•›ìŽá'Ín,^¨„T\7«W’ÿ¸»Õ×éΔPØäÍ¡WÚ†ˆu¤ VYu´Yn�% Ê$6ç¥Iãx,ÑPÇì×gØe’m�â{�ºí›†…¢~pS”Cïº ÑA�%lõ÷—ðé\%6Õï�Ö¬\x6¶¶Æ�Ó=[gq›²“ɥ˭(Ø+Ê]l9†ºÈ.0ò$Óäjèb ^<}ÖI¢œ�0é¡+ã}á�NÙΨAYðL0„ˆ{áÿs¦ÏV e9çª~ÂÇðŸÆ{Ò(×Ïy€eõI¶(±ˆ�‰Ú€��ô€M*Öý(%-Ù vó8½ c‚ù4/7¾Ù÷D*QñOfÃ�s!øÌ6¦Öv 'üK#Õ»6L¢##q£=Xr…¨n½ON}È9&^ÛN‚È|yÔûú›}0‚{úÑô`«-½O×Ü¥ž§î±fW]PûÓ�S "n:ÇaçÜaˆÎO©¸î\®’†w‰ÙA"QûoÍõ ã²—¾˜;›»<ÍÚdÛf;Òs §—H_KèòÆÈYžž;—¤Ø&Ѧ³1•w+ñûÏEú<è3]ŠM%{è^ço0EÊCBñÙ�ÅÐÔÌ%!�싽“TÞë ]1g̤²`šÏ:”¿Èe“ÛŽa' æîDóx¸Q�Ó<Õ‚âª�Àls–ÉN>äv¼!9i:t^Í¥aû'°í $«ßÇ }al�z ™›¶“J�\ðÉæ�Ó¥Rµï¥ŒFð0m˜G].ðáò‰M¬¢�+ûrÙbü¾ßÞ»U½ž‡^žT»' |¨#Ÿe4ý:c òjî'Á}VX¥Þ¿›1`‡?tëÕã­Þ»x#¨‹Þ âhÍéE“ö)¶ÚÛ‹Û¢u x�\&J=%ä%·ˆ™_Ÿ‡}7rH¹GØ3gIv�'y]y�Ì3ÑBÝ×ôæmAT¹j!ù»Àni"ý—NÖ¾= kK�pQ^\žZÀñU5$â']AEú)í?ª6ñðè—w_™.Çò�;~rýù[tˆý ©:! 0–ˆÛ©cÈØC’ý͇òZµáëY…ÙYJÊä ©·Gv­ ¿šâ×é¢c;p}I™ñä½Áê³á»6CÜü9œŠŒ2 k¾ÞÙÉOE€ž«·K;ß\ñc^ñp±t—Š·Ri×x²Í|–q@wï!l{›�`á÷Ïì»~¸×oó<0´_–^…Ë'qÜ+Ÿ{Öe2º|)õ™sŠÌ`:gùVÞ†°ËéÈã|ƒh1Ñè^ú›Ý —ˆ·æ©b†|=ã¤à‰Üÿ¤°f©†øõ‹¥D¦VHŠAüáé1w¸\»†ŸVÌà¶ùºr'ÇY—Ì1Ð_ë¤8•‚éhP|=}JI&SáÛnjÓ8ÙFþÌég d�ñ?–ùK®î§Áv¿±Žß*îäÐû_k©¡e:{aµ¾øUÃ<¦�tËÎ.,�¶å¨^R�"MJæþ@=Õh¼,ƒn•ÍL‚á“àf+ÔкE?mùœ¦[l‰8ƒÉ¦CÄêþ0=lZI¶\oû©[¬“÷lZùø5ˆmúæ(|A=–Ùƒ‚ûRZ·J϶?£½Øu/—_ëÁ!ð@ÙÎ4ˆ¾ù�Ñ7®Ëña}UŽfI�ê7%ªãa×-{Jô±ið)À‚«9~yò‰11Éa[OVÑÙ9êÐÿë.ÙMø91÷+ÀÄ䙽~×Coê:v)¯/.Ãö¾Ø$ðy±Á Íÿ rª¤ïBݲEÈ3éïÕË@âpѦŽ(PÞC>j_ÇÒ%Ò0÷ç2bxˆÂú‡ôï >P©¾ëþ*à¦QÔ¦_Ä3Ïê°ýÄ?Jøøž4‘Z<›Fʈéîï$®I7àr”Ÿ”Cñ’ºBYéë xk‰‰[ÿ“tÜ} Á’æDtÛ„m]p[è #¶hæ·¾…·˜9ò\öÐe/ˆ›ªg‚.ËQK±½„çÍRp:ü˜¿~G�UâÖ/G‘ÇAÁøÔp~52"ú« °æ^,¢¼´iµ ¶e“½sÞaèÖ ì ãÒcÖr˜}&Š«ðF.C&Úú¨B™ §f€»Ð~ÐtîÀÏK6ÑEµ•ðò•D „“‡î'è2ùßÔÈ@wÜ �„WBþ$uÁ[ºy^>Þ¯wDp-§Rs›©\Lyò§›þ©�§gæ£gíf<{øD«à–ñH»ww¦—7ûïåE‹câ¨)¶“¾ãƺz t84÷9}$öi‰èØðÚ$2'=—Å í«ÿØ¢küèásýþÊs¿IÁë±HKlü¯àë‡r¸.'û«‘'ÈVl#ÌÙ`{M¨1l6è^GOc×ñ ¸-_ßôÒé0Öéœ!§=fÑ›f?p{¡†*ÏÃy|^ø'Ê‚¶¦… °õØmòe•76¹¸�M1±`l•{ y Õ<¯›œ¥.ºàc{âY |ù8’ò%¾àDïûÄñ6†½  ¦Þã\Gx¡§‚ŸôzÐ^¬Œ–ÍŽ¡»†h´™\{4L—*l § ç»�®Móñ`‡¶¹Êý îfÙÓtA�Ô�Æ— 3¸Ê™ù³Çw�´ ÈÓZñÐTûÝðÓ_\öÃ;¿ö¢CyNÍ r”Q}Žs]z*µëbSJ!Lo;ã¾ >yT› ŒÐuä 8\ d¤ P¶ NvC­ôFZ×W"¯t1OÖ}$s!Ón5ÞY|d·¿kvsœŽ��ÞtQJ É<^¶Hî.m†“ÇbðûÕ0˜±Ü‚>ÑgA#ð ;ñCõ'P²qèw:㩊ìP�L7�ï÷s¶*W×3GŸ”BLj ~»EÖ…·›½±48øÙuyuÚÇY×·o°S,¾ s³sáâÅ,õnÅEƒ·©fÃ{ˆÞzX1xW…�Kxðø|yÎÕ[(³ù>ð ’¾” ;’ ÷”˱ïl08èÄé[h\w. ¡¾ CUd£òÂÞ› ÚÕ#P¸O`k1]tÀ㱃4m¥—ö÷³ƒn[q΂ljˆ†füÜšÑs´e— B@ì?0Ÿò%ãû°Û•ET׉pÿ,­ÀÕÓÓIßôzìËÈF·ki03\Ž»¯0 ÆÎD‘·Ki`US“�ŒÇꄘ�ï7±Jn#ÉGfÑþr.»¬*\Dù òÛBÜó=‚Yš³šmIPX2•ˆøH³„±ß»£š$^îG¡Ìå(Ü÷Õô+ÉHÐ0Æ  tr ÍžMìÞÑM'«�S·ßÖ†B£B<Ù‚§<‰,}æW§19gܘô—{鼎lÜFýi²A { Q¿É³dT3ì$FQ02GÂàöD<ؽšš�—B±%á ‘GüTó™Õ_7à‚'÷!9ƒËÌÖÈc;%oáÀ:Ià;d€O»Æ‰§ÐM4«5…Ûé~Œ'º—}L<‚ÈÞŽgô w”X<;ƒ§ù´Haù¯’ûçd¿D<8¤³$ÂeA'µ€gqé^5y:�œmºÉŽ,¦¯‹ݱrT”3�U²mìI~ÐüVÌÄ  ØX!v=Š¢¾IÒœƒÇæÀ«eË�ÓÚF­þ;SŸSááð3Æä²­N4«b”Jº�8ZF_fbé !:Ü3&NÉ`õ}ĺ Ã�Åêà¸*ˆp.4àeîÊßà`ü>è…,w £ú“è�/ñnI �})x¯ÁÛY?ɰc)î˜ÛûfNÜ¿Òõ¢È’sNà7|dVh�ïLxÝŸ‡w&b0<‰5yt\…ö^EÑÍŽÄâ?¾°\ƒ¹jdíÊ.áî 5e´:¤™uM?»dàü-GªtɵÂÑø‰ ®¸ß{gO‘¶-a„XZá õ{ì5¿y˜S;A*“/Q>g%t><·› á™ËtßË`p‹$}çÈ,ª¦9þ¾X'ž ëW^­á]Dòà2nô­²^§…fÊâG…5܈ùgé‡þK`õó 5 ©Â¦ßç¡�.Õ®ûñ±BûJ®„&3aÚþH4SÚ ¿¦Ay}*ôv.‚fÇEá¦gʆ ûæ3’»U‚«u1›kŠ¡²¼šníþH¦Y…’Ej·˜/:¨ê¬b\¿v+võ}„½å•pâ]8„„"�KkI\˜4ÖGðp|Vý`lô•Œûk–q*ÝÜ`žÖ3ò!¡–æåPk� pU(Ž4jäSÿ…ÛAäŸË¶*ªÃ½`¤Á1º«¯.ʇÔJH¿ÒŽ»î*€…‰5ŽV÷3Er;h«Ñ r*&�=x¨L÷¬˲Š–a™ïàÿî#Dö瑆PÖÃ/9W£ðËRg *Ì÷yóé‹ä:vy%yÑÄÚ'�¦égçy42[ƒW5á)þÓtÎtA`×érÿœ÷Å»¥“ì�ßÛ@/~'ã×úsDâädzSóX>‡u"�®2&ÊÙÑ«ó¶“;ùøVo&n §ª²>¨½òk”x”|MhÿÆBúWP \e¼áqí8¹ø6í§NB£àYŒí¾Ï´/XY›TA~0—þ'u€XyÛc„â$pñ0^[f§GðJYó†hû0Œÿ\Vð}šºåÔ³�NS©ìÓ(5>Z-UIòcì87R’ñWà;äqÓ×’B/öåÆ&AÆuIÔU˜…6ÆãXÏš1Õ?d Ÿ5ÌyÕ¯1z¡îØTÊó<¿� ïFr!¿­ŽkÈ� In@+šžýÇíª©è+Ëa�Q|ÌYLž1ˆx@Þ§„ÓUjÕ8¸;”â_wfPÏ(1Αõáà÷s/1š,û:<ÿGþMO[ âÅŒ(üx8ý3Áð|Jï’äN³äòônònN&øÞÑ£ëvV³‰ÆYì›(Sx³ÖÞÎLÀ!Ó9(z¢‚MôqÇþ{Øí­ÅI·Œ�še 86;½^äƒÚ=¶ÁBM_ÔÏïBZ4C†*Æ ºÐ[‹ÞA³ásòÔñ 5Z�‚‘Gp’¤çÀ e,ütælTLebŠO@öö›t_û#2]è<šo8E k{(½CËu¦Cn\)Ô™šÏÅär@Ù®ÈÏà×I“ý#`‘Ýø‘&†­�Á8þ=‚Ì;eßR{ño'MC£&ÿ£Mž<ÜÒw•0°+©è E�3¦é‡¿G70øÎ¡‚÷"äo%0±ž.n+¡Ñ7�B÷Fi<·Ú[–mÇ5>;-t1χº8»½2õ�7UÉÈŽAª_¹,R¯ƒÍ#î#Wuá`½Õ]ì±m§ÕzßYÅI¤Ú@/÷MѰ„B>,Å=‚oi~™0®ÒÎé1Â'ùœ>x´ÒVŽÁ#Å94Ò‚%’y© —N§5l¢]ÛiÝÌ~ù�ƒ pû�™$Á`9·§g6ò×/ÀÇ? mÛ È>œÈ^pB™xö�úÒSa ­—³a¼ýÍÊ>ç+BÂA\¤i�®Îç�ÒOß࿉Rë†1ò¹m ’ù×Ðýk!¬ÍIÇ—ìMŒ9»²Šp·†}¤“î¿ÉÃBvÎYˆ)ý$áÙ H¶;„ß§qÇÃÊ! ð8¶)Ä:Ÿœ ‹ÅYr¡&~Ço‚—n$ºÿ¸I“}Ð+j u®KÀ§œ´Do<¼{’©ûk Ûÿ€óÙ4´Íñ'¡(W²K;©�oݶûcÓòxÅæ«za¡÷)ºÈÁ:”9¸ IžÙ¤‡û¿'Â�;–�>°•ÒÇYør§4†�•ÈÆºáDËÈö94RšòyjÓÙû>‰þÛKähV4†+¶å �ëzž:+̃2U²‰÷ýo=T,°Eÿãp\ó±¹­ÂänùDBZàr’�¶8ûñ3VÙ÷j Ö˜É9Æ–Í#è13êv?ÃÞ¿žpÞŒ’Å�6s·æ¡ÕËÿð˜~ ¹—i��=j³7!�D>3ýj’¬×ÀÎL+ Æyü¤0) '� À0ÝkC^ß(¼£ ]o¤ÑáP4I Å”4Àwc (´¶‘ =ãÄ÷çjì­dzõUa¾õ ŒZyb-á„äe\:–Bg\ã üê%Çϧ{ƒ$Áwç+ü2.fY)Ãú¶nÅ‹!±(¡¼ê«$¸ñ.-ìÒºbXYûT„šqY×Líb~ÆGÓu¶”yÆÁ*uQð/$œy:8÷‚ö)²/f&AÈ` 6Û{‘­ÿic¸ƒ.:–@:­ãØ‚£Ë`Ù|=8þÓ{sáoX÷·fz£ê5{xºm€¬nUÇò‘Ʊ’)¨æÒK¹@¬N!œ^öŠJ¯^ÂÝéhIïùåÑž‡Jhó~Ê¥Ä⑇Šp¢í=Y)°”âÒš/´¶=CŸœ8ƒËvýsµ>b!´=gI_½ÓÑC¸7_ÃL�Œ%ôóˆÔšYÃĦ=0û;cœv ªÉm¦-;Œ54ßZÏ/ÙÌøòãqmrIà#û;ë�4Àmƒ ÞÊÚ×½VýàVæÈ]ÅҼ踹_é„çZ°Ìkņ¶d:Ú IÝ9t!¯+òÎçÜî &·"%¹ËûŸÐK»#Øú¶ù\žÛàO?Å ¢Yž =ê:H×ç ¸<ÿV6gÀûhnõÒ¡£­r´ñw8^ˆPby¥ÌÕ¹K¶º(á–ùV°¼C€{ÕÐ9º xgí‘æòs¨} —òãí˜]`Óã…ÿ¨fJÞÛ•Ž{°6H�Üús ¬×èÚMC ¶® ½ìÅ`N1‹…Hfˆ:J½mBž¬}(OB�p7.OW…œ�ÕL ±)<Ÿ‹&g¶ãÁïÉø¶E©ìsÖ27#*Ó2ËL¦üM h{Ð6õDè7§M�¶@̳P\€¸:�º$§’„W`$a#Š;-†”¿áMÑ{f“ü+!¸g½/sII’º¯ÎÞíOÄþ9Ø¡SBܞɦ<;M5F4ñú¸ˆ­: þN©ô×âÐ>ÞÿÏÓOüc©Püuà:òÈLÒ&8·QŠËþeày1”.^� &sqÞVA\¬¦k—ÿ&]Ýe >óÎÙ5Òôw€Þ¶5På!À™Ò·`:öÒ¤?<èpÍ‘^\!�«_Þ�­ùÜ®)Xy¹™m|N‡Œõ¨ÎÔIÆÑ¿ ¼Fë¨ñ{“¬Xî%²%�à‚¹/`ü™yӬ͵`i"Ÿã4qâ“]3gÞË÷ƒºp T—2ÃÏ�Ñ5¶ ‹ WšÐì šü=Ûh¿ƒÇ(ý»�•$×ß^©%�®k‹²Bé¦Âl±ÿ<Ùy¸¶Å"ÒTÁ¸á%©{×ö<1Ì7+• ýÍ{wÀs·0úóGtܤœ‹@eÕ‘]æ„ Þ©ÃNý=Øp°î½£—Ó�@Ö,Ø(›@–ex“<ÙpcK*Iô;MŽ/}�Ù]vèdÍÕá¼PØÐŒz‹ú¨ÓQR.»‹…®wûE­NÊcU·†¸ãÌ5èò•ýÐß�ØwZà)ùlôÑœ‹kçaÓàyúÇü=ÓnÞCÔ] ™¤•:{¾§UZi$þöøœt‡8ç �Éž3 éçFï¾õ#`ë ƒ:Qðæ•*3×'�JmŠ'‚ÿåþ H*>F£Ï’1•88Æ—‚<_ ¹¿žoâ–ÉCVѼäŸj-Ux«” ÆŽI:ôácyý1 Góƒ‚?Qv"µmrd`ÔΉþÇNÿ˜Nš¤oS‹ŸÒˆÙ¨P»•Þóq¼4é½à�É[ìn탺ȱzXî´òA ùæ�^µ�»×†Imø�–Ê}�Ñ?é°64ô^¬¡¼ÿÍ€ãƒIFy’šÐ¹ó<Úþ�‚óŽêùûãx{—Ú"M"i¼ï«²**D¥¬(+I6í½‡” íÒ®Ïû¾>2Ó”ŒÐ0‹hßH?¿ÿï¹çuû|<î9÷þgæ4.&Õ Õ¤sób2±ª†¸ ‚æ‰s`ó;ÍbdBž’º­³ˆ}E7òïeú+}Éñ®�¤ÈHL3z‰‹€+œ°Ó=;˜ŽŽ�páÚCZ(0Á44ñ�€#ºäûÛ³¸õ€ˆ™•ôÓwŸ‘v ©C´Ç85üs’kɃúkG_/ Òù5оÈ÷š½%¦Š–4`ý.z·ä>1Vw(¿É{¢-�×ÞhâJKY³õíÛÉû+� ïÕ¹±?Êt²À”µ¦�’]¨™ß*+U¸FêäÅü}r—Ù­‹ÍãZ™# Ÿ¤�ó"Øq�;;jÁç)KµN…�UŽ}Å�Ì�aa½ñöëaN~.f%Êq™‹×õ9íp[[ J‚ع¯¦cw•#Ù|ZŸy^Áö¾fŠî2p!x7È«ØÀúä~r–ðb—|6òme8|ÆÍ4U¡�H˜ì ›Gùð€ú0m¹-�Q7üH™$ŸÙÛô´ö;H9ÿ_Q®F¿&3åsTZ¾ T÷¨pwÕq Ýú@õ�d1“Ôà#—ÿË#²ýp6(uR=~Sî¥óóñJÁ9²ûQ5�ÓÂôس8:« ‹.øö�yþîŒÎ©#ϧQÛ‹GàͼX°’φ ¯êÔÅ£Ï\c;ycÈèÆ~Ò91‹‹÷i›p4“Ÿ´Ý}ŠðolÂz¯ãt‰Æ.lÝ¬É –ƒì>ÓovÍÄ2ö7æWzÆ8íÆÚ½©4Òq&:¯La5ïîÉ¢bص,cø#¡eð¬*üW ·J5ò³DߎËPûþÞØø“òG·åŸð˜àn¯I§Âƒ+áБ5ø£Õ,DÂʪ¯¬åõQXôŸVMÞ…>oØh¨Aù÷¤Cê´4b*¾/3kx5?Ë0_|ýܦÅN·âÁå/³0£í,Ý—XL Ÿß"³ˆ3#÷ð1I³‹#‡®ÉàÎÝN8aN£Éô©5c—ÕbÌ\®Áj,>Çβ|J�õ%a׳+˜,¾î¯U!Ö×�@hVjP¡�~úcÐ?ú-=×ñ‰: [ÂÑLÞª {Èv:Æ_«fóÞdCö·+ÌÞy3a“ØZèv+ÇUWü‰âß~&Ûk>º»m‚—_^Ñ=^á“�*=kEÉÁõ§0·Oè*Üq: Ý×8§«ì}(ŸŠ.pªµÑw~0ê}¬@ï–Iˆ•ðÀmÅ-dmÍ3꬙Ž»aºÀ;’ÿL_[sczâ�Þ‰×ñ› !î¼CWÜ0#mû5 lÙvWQór6‘W ÕQ0+ŠNƒƒ-a’ø‚®×ÍÚ¸i%´bÝR åãZgg ÿ½LXbž€¡}p Â”]ýç:ðÅH ô9äÆu’`�HzÇU–3}¼‘ÂÅæ/hø»Pf&�Ó¨§Ü;h ÆnI³öÞGpÆJžkàØƒ¯.Ü~©�DŸóA“†MtÏÒzê.ØÍ²söÀ̇…ÅøÝIü›\ðÿIs®¬Ã;³öƒ™S㥫ƒ£«½™}õ&d‰õSx׎‘—Ô±áU ¬Uè‚ë²ê˜y_2%€‚øuä?ð…é8ù‘<ünÀ–”ˆœÊ`ÿÞ©g…X�ì`.¬_´ÙNæÇSñ‰{P´è2i5‡£Z—°)M eå`O¯ȘˆÁÓ]AX鎕ùôó¾LêTøœ4¾w“ÉïÄwÒ,¹K°ÆFW·$¼gÔðÓâ'x~$3yo¡ûPLÓx Á.)°ä±€Ù×>{ˆ9¨‡fk�ƒëï24gt¡ðÓw8�@üj?ZÒÿ‚Ô×LjáŒ×\Ž}ô-–Ç¼Š¤&3[®–¢Š¡j(ÊâØ‹lZç©AC‹°õRµ;8›lÓ`‰A’8ÄÏB<ãHlîøã²Vf®Â;*Õg‹¶“‚ôÛÞ�ÒYȾž�O>dÂr�.8Õ7Efóeƒ¶ñ«¿ËÝ–å‘8ž ò>³›U0D‘‡¸le Zô-rv”Kýe#Dáf<ŠRËA356¾ÅEŠ|Üm½K‰÷õ¥(’Jq|WŽ©ùœvLz)­´ÝA9±^¤Bà>¹úº‡ù¸ÙñîäW¨¼;ÊÁ + øÏDÛ,UU1ɵסvchPÑ<*¢Ïâ«;5P߈/Ť©ICë«Ù�«Š ÈV„F«ŸYiKÖ‚$¹Ž[èðé=ðŠm¥6Qvˆ½·©¡¦ .rX‰¶Én¨²î:Äó¬¦ó.fµ–‡¢ýïÙðÝ–Uã“ÐmÒŽ{ïN²%Ë:�×¾ a:fÔÉ= ßOo£wæNc.fì%ͧ�Óô1Ëeã]$ >‡DðÍ'®fÃôå­ßÀ›áL6 -Aý¯ú˜ð:¾ÎþJçêÈøc8ùók%æõ÷‘”ÿ¶á¦§‡ðdè,$Ÿ-Á:MInè‰;äóË$zÿå%ÒQ³‚XKiÑ«fèl�½ Š|`¼w;è�‹Û—§=ɰÜâ&ÆY‹sÏç¼G¿"Ü#J:‡¢ÀØmXß‹ÆÜ¨«ðÅï 1Y¸æ®|‡g*õ¸á‘ ø1.M×UÑ/"³d.^øz2ãÑy{gÓ-gÕá‡_”ŠŸ'+GwâÓc -z’Œ‚ŠûjWÙÞ�xÌbO:Œ™j¼–DÖíFn”Dn³7dw— ¡¥4&z¤Äö}° ÞpRÐå‡ÅÙQxç`1£yWŠÕâ´BQ› GqÚeÖ+m)\¬DƒÌ$žuŠTQß²…®À¶ $ÀCö—æ ýíïtɵ4lQ—2s½ wmñ·²9Ûz©”@• ³œOËîÖ Ó§û�õ.ŸL.- N‡…ñE«ûÀƒE¡ÿØp$™º¦Ÿ'_¥»É½ÙütÁ ®¤W.ËiË¡V7KÈêB橜4Ù\_jZRo.÷’�ñn£WšÔèä–ꤒA~¯úEfŠÂÎÄ\¼ •ŠC£\Ó§Ìê+"éo·C¦ð1|™ü™É¿¬ %ù¤åE™qà Ux´–íÏè£Ì°ˆYØy $ÒOð¶èt®¡ïq�³Ðä4äƒ C¸1k;l_ �ÞæðÙê_–FöÐ�ìaRdø”ÆÖý&»|à ”7 ©s,UîÜ㬜,öÀ÷êäç7œè€²âúâ£$Í|Š`üe!¼‡0²´ý#Ѹ×GÒî’§Ñ2\Ëî(�?l$A‹šâÐÁÿHˆÐ,ÚgÊ8�˜‹}×ðêzSè¬ß¶É@Ø^"Ü8­× àÆ^>߆}ú>0rG¦¦O㲓WÀ©’…#!aðÕû>ÍÏ6ûØ¿ù÷l0¡··¡ŠZ1]0Áúu*f탛áèâ &ÿÍÔÚcèþËèdäƒÞ-´âô\ÂëÚCÝMzêÕY[ÖÃdq7“ûL½GÖ†HÖê.x‚/�Ó‰`Ì(‘>„óÕ4ÈÓÚ äôýhœr@•WrïT8:ˆŠ–)Ìlùià¹æ¾øI~%”£’“ TbAìi°ÿ‚0û½1èñ…cÿ E<.÷�Ú½“ÀSê�¬Ž¼;,ü¾—p_of\¿ÜÂ\§¥xöóf8Ý�È*lJFr‚ÞŒ<º]4ji#;ôþŒsH÷•ë$~pœu¹q >®×#ÑÇËÐÙ‚—ÞåW@ÿ× ÇðÍ®ÁšFNÝfMØØÜ‡�Ç6µI¡Â¿Þ\ýËÇžö‘îKá8¡Õ„´Ú$~žÄY3¡àR9$Ђƒ éR“4yXLBü^±­�2?ýaѽ¦+t³=зò€p×ú)s ~søIj?â—ðp`‚ÖTâÔÖ jü�蜠u�4>8ë5kq}R!–=�—¶’µ½²eGɦãÚd0Y $›:ÈËŒu8â7\–�“–P2| ŒÓpCÑgK�‰/�Àgš`•?_%'Æ`T­&=E´ Ôé kZ‹bkéÕñPü‡â°Úü?˜0Ü„2{ðWa%óhî¯g~ŽÀŽÃëñü¸0‡F…~àà“‚YäÞGHïL„¤‰F"¹ÃŠYðg9¹ÁU‚4q®Ç÷KÔ:è “~;–+´3??Žá±äH86ý\UWħ d`óOeð0ZƒãñäèAq Ø'_B~MÜÔû;Õ…ñæÂT?{'M+}AÝå³éŠƒÙxn½/{¦Ïzœû@-|gàR�kÐïQÉlL¼ZF þ±úî’4Ø«ÍRÎJUr]H¬[�“ÏHÐí[>çÒB²¸é;,êþNÏ¿¿†[:íàóót<ô�ì)ùDíÝaØ,†:úp€Ï$¦«3à­›ÄݯÁ]^¼yc7s¹¹ƒÎµÐÂ… �ðñüêkÈõ¾e�•›Ó�æ`û[8°p�Ê�¢�j3ðϹ—hí`K%ÎoÁð¡nÒ÷ŸV‘"ñÙhµÓ”žKF9AC2²ê2Ì=cÌêåEcFÖœ:¿’ °ŽA?þÿç!'/4…yTô×g:ÜÌ..Çõæ_hƒ‘ ÿ013:ˆê; 4Ë#% 7ß$’„K°ð|,Í“å Ë®.�ïñ�̯#‰Ð5MŽFûRõ©’¨²™q,n‚k«ˆ[ï3:Ø!kü·“ÆÚNvÛ`4”‘;ŸyPøU#ñ‹ntp‚ûX¦0íÙDÙ¨y,ßÖ xû¢fnë ;ë—‚­§4ìn0gw¬SÆKCre²ÖÏÐ$ Š‘ÿÑ3üµ¸šf BúFä÷\}þ©AžM8Ì· ,þ ¯;œ;ÑÁÚa-„%Û’�Þ£ôIDó=F…éX E ÷^gGذ¸T’ä.åEm5³�§ ÿs4Y{½ˆù0¿ž(Mm÷ ˜q2‰Ü]xÕ–Éæ•¿…õæè)ðžÚÍÓàV) pÃ1PÑMUGS 3¿ï?+…³†üÐÀkÀ~¡–B’Ð9ÿÇî‘9à6F8yÊ(Ú†>"´�}�¶ÎÛ ¹ Ü_oÇ®¦bòn¦=õ¯í¡$³sŠÌpšÎ1È;ïBêÈøQ˜c�p¡Ž*Ý‘Á°Wx©$J# 2°§†ÃtÎĉv>ˆÝ§‰Ã?INT!Ý&Šs«½‰L®€Y_¶žú™Kþt ‘W3ÐBÐ\ç‰À1Å^R¬Øˆm3üp(¥Œú„ª¢ù÷J¬s}L—¬7‡•Ûjé<»*‡èn ̶à^ï€ê6p×.ƒ© ‘uÿœ©Ýí:YÃû•ý VD:G?ÒÿxcñÕžpÜ*U)æhüŠŒ•žFkLïÁ[sQæ«é>ºÄê8,_Ø…VÛʈ ÝuX™I·jÊã¾L+|’¼W®¬á±>Éy[9‹•Ñ cS>ì„37eÁ’Ÿ‡–œè†µ9ëPXBÇèáhÝu þ^‡ž´�Ð!¾ ’�ãêÉB¼zÞówôßÌJ2kúøN°2^í§j[…0qiêßQ�žÎSÿ�;ɃËË!1D?ôØ£]y£-·¬æ~€Ù—J᥯9茓˜’J¦ÔÐsjnÒ†Äçè‘3òO'‰™d6›tÐí‡è“)EÜ^û�ý,D4Ü>§gβ¥m¿©cHõqK€ÓÉ4ô55 ºÝLí�Óñg¢aÒ½ÁøÞM´Ó½�ëûð¸šq¡²àxÒ â]qæ³÷¤Xk”HMJ‘76«ñÏ!5ø”ÚH­Š³¨­¯ªghÐñ³Á6U9|_ÿqïLbµ”¥ž÷ 1Wèî—X/Šþe¶Ýþ)�BäyKÀúH6q*/!a–jìµ{šÐÿ“Ó{ËŒ$|�ƒë‹EÙvƒ6âóëŸïL\ÀÓnÅøVoææ³¯î1šÉh$‘ èã[)´÷Ã9²< ‚pÊ/#óÁ×]gEª‚ÈâæÝäaj:;޶+Ãæ Æ)BÕSªÿ©Ú-fBÉù.ðOcçõ:ÆKv}]ƒ“VƒRlò—µ�Õ¦˜R< ÊDµaj¥8Š8ìŸzÓн2Ž ürÿ ÍÄ3Z�ÌþeÕØU Ç ÷±%š)‚®WÕ¾øÏNdÑçw°[ã¾Í‘„�—kسV.¬fˆ,¦qjH£á°›j$«xXÜú§�Î9ü *³Äi×4¼9 ‹¥õÈR©²JK–_^…KrÑaA £+ð3VÞB˜`¾'�Ó• PbYÙ~ÛôX� ,É 2—FHœü x»u•žþ™Øq˜{Ù py .XÖˈ„Rsò›��"óZñ±ž,Æ\ÿÇ\r:ÔöÁ ¬¼µ”LIÜ%W÷=�õŸShÁÝQ3¸—Æ‚0?¸¿Ýä6“€xy,5]H´oVQ¿¤ä¤D}µóáML¡ :µ8ì© ß®Ÿ$�èãç­rô¼G (6,@ÕM?˜ßÞ“7c‰¸Hb NÞ¢§/â†eÛiÈýT8³–È+\$yÍ?ˆðÆ¥¨—.ÌÑÀzY†zž†®í%ìŠ –TW`>>ŸÇ–xîÌà {AOVóàlGšl³C—n€{E»páÙlêZªOvÜ4�«t§ª-n€sûz°@| ¤\'is¿+rÉpè,Òœ ÅŠpÕÐàß\|d¥O\í¨„-¾&×ZlˆÎæ4öQ¶3–Ï‚,Ñ5´ú`Ý©?¤¨×Ç*Ã\e>îæ½1tºqغSΧÞV_×8^Ú;�M’Áì|<þž%ÆÝŽ-ˆßÁƒ�½�~órðÑ‹Kx6»ƒ9i7�ëûë Þ9@hTÄs²i²”êª7×ÎS#‰ó$ÁIí;��7a®mÃà¢"hV½�a�âèÐÝ.ˆÏ7A¥ãôQôz¼Ød ÓŽ–çSËÑK"¯œ+%Gò®Ó·�Xh N~çƒÚååDˆëLϬ÷Ç?:R8Ä)¡äÎÓ�~I3÷yÏA]HÞýXAKœã1~éOÒdw†+ri¨ìN6W � ­ü—Õwž‘e¼tmßX.¼§yÖÒÄÊ@˜Î¾"�­5AaÍ]6Q~Lé]'§æ Áî_ìDÒa[ƒû>Ò¿`¯ËF´5Ê€Æ9K¸³e~Pý*‚. ãÉ­ôPéÄ¥<°xµ1 XÖ„Ê«2é@–-ÌB™þhœ™žÒKW$œ@©ÙòŒOr ¶Nšq"~#‰—¹«'šPCV ésP¤ýšž ÚGÔ·c³Ûó×þ«$¹Ÿ]ÝuE�âû+�t ù$=²ó4ZUËš~þð�ã.PON"55!ñfîì–ÎÄ�¯€¬>)ú«àÀ’oœW�rlgÿÂõß�bMH3](õ‡M[׊Õ×ÌÁw`‚l´¿ŠúÝxÝ%ÏíXGŠUVƒdM)¸M=N×Ò!M´Ü´®ËýÀ£2B¸äÙU9n |FXõIÖ¾}G•1‚Ø+6RÛÅߘ¸ÎÍÄaÄ’6Õ¶Âê¾vHþ‚tÔÀ”ŽÜ¾ˆ'Ôn21¸ �ÝpÔò$ü¬8GÊZôIíœ Ì5Ù„¯u4P‡G«? Ò=óôXG·(¬Û⑽*ø´a4ÅåáôÛað”“ÿÊK±flÞÅz˜YÒİÏ$sh)hxF6£%w ýC�8óz/8‡/Ê þ?æØ3ÛÝÆøpW‰nÐ8EAm¢öKrLóš©ÈèòõµÄixbÐÃh2ÞN‚F ìî]ºz]X+‘ojàp] jÛ'ÑEì�¦$k¿­Ù™À88ÚÐÛÖ:ÜÁ|�£=I=O91¼÷M?í( ©!#tÇéÚ³²™XWö�Ž/»Jöò €íªM&û“€õz3¾ƒ�ÁQÀû¦0 \¨×ñ¥¦© w€öÃŒÕ÷aÈ9†8ãc³¦ö^/¾*œN�Ï�»žÑ4þˆ.ùÐØH;]„Â%Kè­ütâó1³ÔÅAý¸"áóæ+•©c\ ©›GÈó¹NXò èßYqö¬9M ãÉÆ£å«m œ';=â`DBÚlzç5fð¯Xö-† .‚X³5ÂNøÓ�š+°g§ Þ’Nƒ¡0Ðãþ"kw�ÿ9s±wÚf,œR7ÿ´‹¶ Íï�F X¹£Ýž±¢·W‹žwô‡‹/©ÛQâ/?ÃÕ�RÀ«š�ª1ïI¦�*.=d‚Çå²HšR"Äg$á)E8_œ2!cä·÷lèØVÎ>OxD�ĸ$hï Íîewò;‘°ejä‡v.iœ•H½w·Ðæ"WŒ¶Ì¡¯Ÿ5‘íÓ:iÎæ¹È. §åoåð‚Õ�ý‚fû°wþ,¤Có¥AÎX f'åƒÏŒ2Gc%4ô!}Ç5'û<碔âØ¶ƒ ½Y…×D—’f¬æQFž´SdÏuˆ¯UðaÛ)š²å‘ü<›ƒà’}1ñÂÜK£hMm$>â¹ÏQÒ@ÅÖ%T-«ƒ¶œ½H] GM³;Z07F•¼ßßBf›ÜBë Ydû¼÷¦£Û•¡ŽuЯ<Ç,5c#ùê|íÜ'™åë.ƒí·@Š+)®I&w5c µ_“¯ûá§ù9DoŸ,' ¶Ó½»¡-Å?mÍò6ªÁ›izPä*Ã4‘cxëܜֻVø¥,•ZO �y]hýÄã UQç®(¾üð�V•Ò[�3át° ÑÚ!B{“®Ñi¢Ù¸`•«é[A™Pœ«:L?«áB‰ Œ(àR^6†¶t][v•ÖKjô¤‘x½)&…•Ÿa¢$?|Ž%–'’ÉßDÆDuövœàëÚb@y#Qè†#˜&ß"g‡o”–¢8¼Ö+¬"CÔ 8 •ü½´�WÆß-Dヒí™IŽ FWtPÄæÚéÔít�‘QEÚ—øa~J$»Üú5,“¸Ìn݇n<¿è£âEèuð]ÔAÃþþLxd¿˜Ý°ü®rì"ô«aG{›iô‚ªýU…Xÿ×4Ü9µŽŽ‚°t“)õš¶ç‘hibqÌl>™2k£ÈG£nzÖæ �x¢Å6ZÝ2½,ÜC†OWc¾åõTž £'•ðK‚" E+T ]N.·¬ÆÉ3c?ƒ†¯#Ï*ÜýPœÌúÏ ®Ý$ÒÑÊ0Ïà§zò+JztÅ�A"Zzoûî%ëü¶€vs?´ }ìÒ»‚ÿ�‹£r«HÝ~Æð߸+å�™ W]0NV‚øÓqqÁÐày›ª3@4'×M„@¶Ðuòs:¤ÎÚÍ NÎÅw2Þœ�v¿Xþ ÐSnoù p>3“�Scʪ¾MgÏ”ÅÀÑŸoÈBçJäˆ'eÜ9 kv‡9æ�Ù³RqÌõ*qt«éÑwvôåë"x¶;›Æz­ÑÙ8âjÆ.û°¯ê±±1y`·+�–DU™&\®'YÏŽÃîGî¸ð¹)*^ sœø 1¨šæTãò¾Nš¼>žWMB§a �¼ ×üõAô½)’Á�ÔI½å–Þ¤Çé=�}ØÎXª$`‘ƒ,µ¿ö�J„k÷À!:rÈ‹\4X—¯X€Ê¹2ºmö5ªø{!ô­V§¾+Ê~#çOÀ´Ü ÜmmÁùÖ9Nê+E˜&ÿQr²c)–،ګR©éŸGÔ¢¸‚n‰á¥mLFà<6/C$"ÛÈãÇ“ÔÅ›�íÙæðæ�ªicê j“Ÿ‡ÏŽ*@ÖŸ!:Éÿ/×ÛQq ž ²~~£Z· èü¡‹Øo1—™"Jûˆo�1üI+¢<ÃÁÓ7Ég±Pb1ÿ>Œõ×`ú5w­æŸgªT}ä�^ ‘Sw9ªCÏ7ã¥Y÷èNóºà‘—©’~,“W Ž­ì¦W´W`Û�Ï *?Îè¤i¡åA!.khI·.„ÖõÒ´^`ÉÒk¨ý«Ô‚d¸mõ�/b0÷‚1Æ*ÕÓº¤¨âÇ­¿I�Ñ*Yù¦påÕ4°?ÙCÂ,_‘¢1ºFc:*ÅÙ·h}ÑìK¯D÷Ñ•©¡ßù”ÍT¼,“É:û¿ WæÓÑáEèêÕÆ,+[„Ea0}�*Êë–ýó¯ÝPqEJ³t‰‘òêåQÅÚI£ã?,ïŠÀ˶@ÀÇ�%þ‘‹ÐÓÑ tõÙN씎çJÂßñÔøe,~ À"Þ•&O‚g’4yÜ.»mœýh`ècX}x'ôz D >ÅIpߥ>¦º üÐtÓiE§Ÿ¹¤KH“4®ž"ܬŒùÒH›ò� Ä£—ypXKâÏûWaÅ™@:�9€™‹(*Ùo€:‹øþÝ…•ÛÃàÚ¨¢»!笷„³þ£ùÉÎÇôœÃešÚ`ˆU·ià�½ä( Þ?N,ïE!;q°÷J�ÑØ}¥n R³¡zY!Ôßɠäyx± öo‹À.ùÔ)³…òGŒS½éFÌÌéµÄ3ç&š`®ñ§À™�8?5‡x•åÔÊÜÝHGg“ÛI2P±/·¨ËãÇù™xêÔ~bÑ;�Hw¿`Ëy^à}]¶Ê�Þ¹öƒt8pzϪB»U ÞÏN…™;.ÒQ·nrÑj+Ø¿ —-z‰ª�|ˆ‹«TCØ9ÿòئáã7ŠœÏ¼y°­NJW—Á¦IŒ¥õ"t( GŸ¸¥Æg–™0UjI˜RMjr¥aÆý/4Og' 4çáº/Ë$.9;çóëJ ñ�¶ûzÚ3’Öýe�# {°.¤oMÇšƒ« ±Ì ²ë0÷LüÔ߆¹b.Œ�úIÒ±<‹Ùù€9¾ŠÝ»m’Î=G_qˆîkôìµÄHÇQ²n×ÚŒ�I£| v,&?¢�ÑÆP�¸¼àǹ6a¦{ÌÁ»L ÊlýñêÈVÚâÚN~PÂim-¤úw5qa3踒 —Á´˜ŸØºà3¸s ˜h=›Åç‘o…ZqÄÞò0Šïí±¾­‘­~ZNyÞ<€¬wá†\"²õ_¨‘¯(ᓑ徎æT¿79ãÎl×0‚¦å‚°ä˜Xñ”SÓåݦâAq®k-Î,(�öÖ�¸;û*í�IE}]êþ€€Ò•(Ô€N²Ò;“´‡<¡%óÂñØÌßlÀFGx­8 ì3‹‰R“.r3‰ñ�µ°Á(TÕryYi ^ä¼ ‚—ž ¶)NêXÁ²_…x[Þ7n„ ûD ÎùJn,&Õ¼p›c9q{1Ý0š•ªP|S<�/pƒ~Ór:ëa}úÕ»G:à†¤ žR…ó&äÁëíxù“1¶7Óc'àn·&ð¾… kÒûº'²}Þv�±7lc\DH© ?Ìsx ³3ÍéÚj8s0Òv‘°Ûÿ@ã ñ¹ñ–ÊôDÓöª¼a1®³e*ÃÐ{%�`�Áý{—™Gío‰ýá ÈÊ€Ïëlià‚sTõ€ôð%úfÆ[jàù­ã¢žˆ ÞWO ÓÒo23Å95¼5Ó€r¦­íú÷" ÍMÅèã\H ÛÉêäâœ4 v0S~@¿ó]ÃOûTÍî;EêŽöÐ!ëfzkÓIºî·о|Μýk2?R Ç·À¬Î¿t¬œšÏÚ“ÃûÁÈÅšL4áç_¤·,SÃŽ�ã~Eèévù;ßQ¯K•t{‚&ñêã ¾V~à·ývx7OŒ{�Çx‚cˆèJEæÊ×P°<¶k´@Ý'ŠØ†ùúw�4t\”äžÜ�õU\|â EKœÉ„¼0WKË„KYÔþV͸ÅÃåîØehÂ~§÷£ã yŸ98‡��Žë³ Ïy'õ/§¢ýedTz„JÚÍ€«ÏóØ™y$"¥?ùÆ£ØÉ(ºnñ3“â!I˜µˆóªø"þ�ý–ž^X‰3]dñËŽ|æÕm,HÀoÚ—`Ö-ä}%ó tžÍÃW�t0M3¾þÕ…Rç‡taº*dÝ5ŦŽ$Z*s×näƒéR¨8äv»�‰¹Íâþéý](L;ÈsØÑ"ME½Ä¹ô_�®V6óQ©ÂI›$Ì i0•V?_]ê¨z•¤±rTaÆÔé»FŽþÌÄPùpX1^Mí¦fá&Ín< +…ב럃¡l¤ƒ¬«œ‹©×ð‚_1{{Û 4æßG[Þ¾`wŸ†ú]ƒØñÜzlrñ͇0œ«¿ƒ„33¡ÍO6¨ù’†ÛÇQ2t3Íw'�“’ r–ÇÁsûMº.|'‘ÞäŽR�rÑûìúWü4Îæ|)¯¤!/\áH£*kÏ!IÉ�ÐDÕi‘ï VnRŽ;5ýsÉö mTC,½…í‡Ï†šcŒ/³çëõдÈ|Zçå‰oÃ@ðsÛ±öã³9žD’û}œ«¬>ê�ÎÄšgÃDgZ#¥VM¶œ×dOνNç®­Þcnø5Ÿƒž%“¢r9ŒÒGRÊ퀾è%s.6çâ52@<‡c±SBÓ^ZBoÖ I:hÛO£–¦+f ÞÆ‹ަÏÄ7cóÞ‡T¾Ñ¾¬¹EÔVéƒfF-ô¼¿„ <�y®õ³ ¾isg¯ZL_?I>© Ö¦Xœ"×â41˜¨f†«™uʃ@Œ39ìÓAÈõCìÆùºìǃ™`Æ©‚0íaÀ»™œ)ÊÃI• zÀÿ®Áî[èú§_YÕöspßB O|"›$g’ø¦Y¹a#JÊJç�4¨]âŒv’sǧHAs9«ŸÀ™öOé3±Udsã_šgîˆ÷'‹Øùï…ÁùÓj¼áhîÅEcÂäá)³MSHŽÃNþ"¼ù<½Õ®áõÚ\¸`çK²–Ì Q[>�‘ú`�õ’Lë}Ü®|-ð…ˆ•¬Á=‹H6_q6æ3ë¯YÒa¸ªrü|õŠf¡Âê)eÇ>“º\Qtí©ƒu›—Re¡*š KQ¤ÂDÎ ‘ÌiÛhÄjGØX'„}Ó¯1.�öF+zdoæ˜-§Ùj>๞¸Ÿï å­S¦-ÿ\kñ´Ùp:²ËôøÅ(Ó¯i§PÏ;‡Ê×Wãß.ûG�:NË`wÍ$Vç~‘?SzÄùñT2±¢Ä`óœ ˜:m7¹ý9»U’J=q˜Rw¢Ïx·Ð¦Ÿþ$ÃÿW€=í¤ûÍÌ©:G€Šm7§ƒVãÊûêðíC´V—¢®� õ]iO¥ W’ÎŒwø>V§w4³ÓçAZ„¸‰ZÛnt {MKaîÚ)Áã}j°h•Æä¥�ÉVØ£ä@?Çí†s‹°ø÷UòC’Š2ÍÈ+uTm¼H²÷ËÀÀZIšxdFK® Âi�ôsL7«•Oå.¼'óF°}6�U‚æ•ÉŠ«y4�ç æö àû7-àèU -Ímì‚N ·” 0]ê(ñ}‚Òü˜q‡pà%Âûc!hšà‡Ré÷ÿeÍ?Ÿ»ŒZž:Æd¾¹AJÿî¦n³ÉÕ2JM�èÈg!\ûÌìÄkÉ¿êÈ.Ÿh’bú"¨‚îgÌqéGÇ—©Ø¸.ˆ«·‘­Ž€{#…0¼¸‹ÆNA5CRXóÖ´r½¬ø¿›dºœká�Ósjûp’ꮯ~_- eúÍt¹” ¨zÂé‰QR$} Ûv”Ó-ƒW0ÿÀs·p’º@.gq±ޝÚGÚo¼#/»làð'Úú:–NÌNÁo ]à�¥™ aż <•‘ 75°ücz8`‚ÂÊp­?›‘8"%�·ñiãy´a ùÚ‰K+ôMë ÂqÖm7rÍ)G?l©Þ‹ôð8‡š3¡¤Þs4=¹ÎÈ?�Åxg]0ë8‰ÓN¡bÛzXv)æ4«àã¹,1»ŠSéîf0{ð—Îß,ЧœôAèùE|úð h»cº´j&!;¨¸®®ú.®Ëg�uŒ<,?OJªÿ&z€-„ÿ4.Ã×¶MÄD¾…ú8)Àšàiø( 9™ÂÐ_ÀÐÓÏÐáý‰´O6ĶäÐNu?D>C†ï¯9 —9Lž¿¬B�\;”‹Ñd¶ P5“£¸ûw œ¾ ŽR)çY›“ùö(HýI\v¸Àë{dLu3j9ðaÍ¢Óxr· ©=ë�ɱò 4û?tUàg¾Ou³%'æ€%JÓÖ©w”Sëa81(=ÜíÌÑÌï¸ÎN†¯_€�‡Ÿb•Ö{¶9˜K¾y.Cÿ€Nª™8ŒI¯ÛÈ 'ò³¶™,s€5ëoÑ=½ýôÐã„÷°›ùŽƒþ¹Ì…²7p28ŠòÆ{Q´=Cv„µÁ÷¬¶'šv¥&LZ3²Õ™LŠ®üÚ6×ç¸Á}›0|f¿›‚• k�;lö:ÊŠŒ‘d{ˆ9›/äÈãDaè&N«€Û½ñã›T¦çx´ð}£n/iל1V­<kT.ÁªÀ òéV,m«ç%ÅÜÛ4qcq$Çf¯fzl¶â©-€o¬?_Í/¤ô™‹‰“Ö]j0¿y´39:íì/‡¼~7”}ø2³1¯]�Ì©Çî¥tÎ)ulµë!EsHDjüø%µvÅ&‚Ši4*¼€¦…F1 ‘üdÎkò¥6’à „øÅkP�J+—a»Ö=ª·Qu7‚z޳.)ŸÖ¶ëàÝ[ 1ÿ1�ôN€==€I ˆj¡;h4ÐŒÞ{ôÑò4ö·V¢0‘ Q±óà`bY:W ú/}£/–%aýžLø¯<�ŽxÁ‰‚j.˜ÀƈÉÃSï0ïågºŒgb¶³:Éʨaß–~2}š4LÌÌÀÇì75‚ÛƒQåþQôc�iù~Æ_r„(ÿv†ÔWÈïýÓ©ªÅs´Ê:Ldb¢PüZsˆ[FÔ-msø Å6š$^ 7†bQñÑVp3 euŠ@(×Ëë¬@§CÅÛBä9<ˆ§ “Ÿ‡RÔ¦à ¬Ö&_< À`}Ý.9 L 3˜ùf5˜—KœNó!yw�MªJfÌ_Âý‰Dùõ6²Yý>ÎÞ߀Eû�a_÷¿uK§w{7ƒ÷Æ%„ÄQ˜I4è¦e\wˆT>ÆüÅ,1âyJʤ‚€xo!nÅF£’£¨è% ­—0Úó2�´Ðî*Ò?qŸŽèF@¶k%[—»�œ/<¼Ú©¸±7š´OúÁ"�[äqg6‰5 �ËrôÒt5èZ ƒ3ï«@îu%ÔïŸ�©YYdöö|ùU§™•’�9³`/}€íO^µŸjsn+ú.—FÃÅŠðK�—y—` 7übQö]2޳êÜûQD�ø{ÿ|.glœøáW•4x�Rºmœ56iåwçiñüM¸ûØ%ª“6Ä âã$¤V—Nã÷ñåäFÏâRr S“¹p7÷óÐb!؆ˆá¾Å·ñÇþÛœÿöì…»:å$eÑA²åk•á7·hwèC<}‘Îä¯#¦_|�'d5hfKàª}/ÙV=¸|y;4+^@íúvÈ‘( ›k–ãá›(15 W–<5iÍrÄÖoIpÛ¨›š½¼�M­þôÞw|yÏ9»™²‹2ÌroY,ªeÐùåO:Kæ$ÎkÑ�#ðóf£U剟õ éÂÙ‘¸?µ�Ý ]ôï0‡®‘*§J¿“¦¾L8#˜NêÂòÙ=Ê–&üuØhq3Õß2=ƒO¨S‚L=K„b«Íp©ô�Òn¡ñJÑÐ+å��ÉÀ-Lé…F{ó¡Ë¥ˆÜJoÂ;óL·]¦Wú¯�Í�È•ðÅäøŸÌ�,ÐåÕ‰d@ëGÅq�l¿> æŸBê»d™~à/X)7ÑûV6µù"Nž"§½¥¸c‡ePdš·ÔWÁ,aÕxv5­ì¦¾‰‘©.žøHÀ2:ûýdèØæwì¶×±än:þhYŒ­ó*‰ÆaaL¹¹¥ï ¢R©½†Òï¶Â‡õ $z!_c*ÔÔÞddù¹Ø.ªJç—¶ Z p‡•ý¢ oËÒÈ“jd.\áÁôF[Æså¨*PÅsŽ¿ð̦)’ý´…�÷¬‚ùïO,�j&‹\ד²c·©—û záOÞrü˜+#Omöúc«äæ�B0i¾ý�“-Æè›õ+؉¡:Öý�8ïñ&ó pÅq=\qh´»b©¿(XS€¨�Rj §žÄ±ÅÎ10Gm±Ãÿ¬–Ó}!Õ°£æ3)؆¥ë¹éÍñø=0g IÒuÖ¥$›9žo*†é2¹ ( ÿJ[×@¥Ê/Ò5rˆ¯‹ÅߣE�äÖ@Õc�‘§�û1·y„8•Ucï:ä÷ÿû}úìã˜UDoõ‹ ¥{ãâÔ@bŸ1ýo,—Œ£ë��|‰9#êŽßþˆÃ2¯ý”ÆK“�¬Ä3߈´Àß±@ä\¿Ñéd> %›ñ¡RÛZJnžzÇJvÉÒKx‰å?/jÑ€69 ÊZ°Á¡�˜hÆÁ®Õòf}c Ômj>}¥q½7M’ŒˆEtRYÔ¬oW”p^“ƒ+üé�”¸n[þ�áòpǺ�ÂxV¢HF"‘l…~ßód¥eTJE)ÑZ"dd—½™)¢¨ðûžGDÉŒ¬2B¢ŒÒ[TRoÿÁ¹®sÎý¹?pôÉZz¾$­n:¬r|Lî§êâ–aš�l¾\KC4„.ÁnÞðúk> ¸ÿ*Žl4¡†M·Éî¯BŒì.~Lñ=Ä9*�Ãþ9ŠŸSAëånؼí5û+ñ+9®Ý@Žn؎ܱjfTÀö´¶‘X±yðûò?ß�h ^÷[ØŸÚðëáÿ(Wë>MöªAØþOÄáµ6]Ò¢Fû"(“ãÍÜ\Ëjê]7à^ ¦j¥Šhµy©?V F©ñ0}î\{Çé\ç’ òζšdâ‘yhIî zAlå3bµ¿ƒ¨:=C“2.Õ‚ém`ÎPŸk‚¨ëT‰Í¶ÓéªïUdšý."R¼�™É¢g�Æ¿Q†™ÊYnî(9¿Mƒ&Å¥�áŽxøC¶ŽN’Š\uP*@:èI¿�^ƈï¿HD!7#�¯ªÍâN˹�[¯ƒüx²áôlÖDÇöK¿ÅqÚA´Ž-Äç·Ñ‘Göñì`?ÞieSjòPcÿKjS¨LeŽ¿$Ëî–<÷±64:‡¶óc`ìØ[(½ƒkðÉ>;°4ËÄðo±è0C…¶Ç„ã ]–¡8ÿÀyòѦû¾ŠRÙ ß¡o¤Êð|·}yp?‚øá1Á½}t}é¹{.‡$5I�»ô9´½]DïE•Íä’°5{Aƒü¹Ð÷•ą�7|®5b¶eY£Mè10ólB¾Xp«%_‚±vÓpyp�‡±8U~D›Ç@<¯·X,ú ûÝì¼ZHrÿÝá‰w ½ Nýö&Í•¿È&›¹0Yx–Ì+o¡ï ¼qÀŒ—ZÊâŸ�ð·Oˆ8-Ö*)²‰À“i¥À¤ qÒWÖ’ˆènºúŽ Ä¹9A°Íu”Ðbi•LŽaðó¦È¡ /uò¹BÒ~n=iíE:özÓÙôÈ› \±�^ÈuÃÇ/¾ £/ ?’ï—„­Õ£‡ä2= J$×¥‹=a]FÚýžáï�\ýµhéç^âußþÓ8HkÄcàá·[Dyx|P=HcöÁ7î­¿ˆM/“ÅvÚoÁ›üA�ÐâŽÙâdïv,( ¶—N@¿ÆÅy�<6GŸe»1÷“ ¤Î™ƒ§ë-áÔóPûß?–ã÷ÉöKÏ͹Ôè}/uÿb@ó—¿¡f;±ðPÍ_¶~|O@ï=b¨:?•ªwa—ŸÀÒþÛDs¦žYÿ›»1É ¼åÃë»ø©În7²¬O š¸˜$!Á­/;K_ß»Cjÿ[…pö1æ$ S�T‡$»$rõÝ5öœŸ ìhgîµy¢äDu2£��7µ7ÉQs'¬Ö8C¾í9†ÏW«Àžž0ø})YÕÿ‡“$m–§¡ç-&«�SrEµ^mõ%rV©XÐhŽ;ÛÒ‰,ÎÆÐP=úm{;�žlzD°ŸžQ-fÒÔI„š5Œ½rÆþaXñK•~�mîÙhÙÿƒ0ýY$Einû8I]7mGÞŸ¿ÉÆ�“TkËÈÚÝF¿(^ÅAþJŽÓ ëséêÀ¹G4a�i-›&AȔÒøÀ�8&í5œWpG§-çü*¼…—ê÷ASˆkV²¸ñ¿V$.—TîxJ>ñBÞNìýOÊôV£G‹kp8 í'á°‹ ññãÃUäQáŒ1{ïe1ýO( O,êÅŸ=}´ãJ.IM’%¾ûf¡Éž\6 %nm-i%,cêÑ~Jw÷ûე(\úE––ç@¸ÍUr笭º·�uW‡ùæ)à¾ÞFÛyÁìÄxª%Æ9±t€^ž6LœùšKzÕVƒ÷ûtÚD/ó*‚UÖab¹J�Îúê µ+PMk7ÎêסÁw›è™Þzv�øt‚דٟ¦ëÀ5b>ÌnUEs¸ƒ•mð‘q<�µ%é 3õ/±|Ģ킠ž'’èäÌÃÈÒ<¨–ÍÇYçÃaÅ]D;ð?ÿ�ž´o¤9EôWê|8¸O÷¼©¢w›µà�I Éoe§Tk¨¨Ár´+ü« ooàݱ¸è¯æ-0 'Öäà¤F$Ì]BŒ[f“5 ÅÐíC1ýà‹ÛÇ.AØb<”§‚7ÕßÀÃ?ŒÕU,ôÆòÉ Ò}WãXc©ôcX8œÚ¡±+ÑÑ/3½ôá™®2Ψv{ô( l¥=^‰àÍó�Ü9dp²3 >X) J"-°Óá?ò|]/ý³ÍO,Ëć_âh˜£2 ú˜ÊZ$V‘…:0l•ºI`RÅb‹/ÎK<ª{„c7¥ûQP—¦Kú/¨ÂŠBÒ»UNXå€äÁÚ~Óš“òñËÛµôú~cÚü÷†šÅõ¾©�ú±‡pͦfº>Þˆ>;.OJ,âŠÇ­Á¯ç ‹¬t{¨ÎÕ“pÖ˽ä1µ¾„Ê'´‰Z:=J–FfcCÁyô�¼GrJ“pÁµ$*,´&mOBL÷cjtoû£Ä�Ì�ÜÄðÜ�Äk7-ÈÍh.Lo~ Ñc»áMçt|ROÄWÜÜ/ÒO–âU1þ×ôØ21œ!ÿ€F|3Á†ÐpÚ^»šsdª“v9JSÍ'ˆƒb S#PFìG_’o£'q¬}!>‹0@ev¸½`wGöÒGÝÊhWXC˶\0‚ËkáÞAÄë ÀÄ´Šý}ï1•1ýEo,ˆG¡E‰Ðu 7y p ­�Ö ~´ª¢OÕ×á¼Fx>¼ „·a)Ö¦ñÀ4Ãøs�Ùgv =-*‰}d ikÚHw�.e>©Ó…l2ml9òo¯Í†k©ðó¹xà�¨VÌàøÎzB7´€¾—>îÓ¢›+¾°9ïÀ§«jèýê&ª5SÅ•?°ä2?”X†`Z¿:e¡ÚiÚ”?Fˆþ9©‡sÜê{­šbËÇq$¨Â ÄfÏÇöW„GÑ“žŸU€í=†°ÛqÚå²´þ@ s9‚mÙñ¸mî~¼òºý_X‰Rg»ÈôO†Œ¹îT;›Ï­¥oÝfS�6��â-P·d¨´õ)4¨r…¿3ë±úÐ,-¾ÇãOãþAcÒsÃ�t)¸sü ª´qÉš¹7©ÿü ”O£snŽãß°wäæQÊÎä#]ö3Hô³ùpix>Yè�C ãìðãÆ¬îK§çD£ó� ’Qw€¿ÍD1ÿŸ´xC4«zì. t¬¥½K/b—f ½47 =_ó�%â¤û~:4Å’Âþ4´é‹.I òcüüx >öúàÖâí¸Ùû2jAàVÀžú ÃÁ›är­ÕŒ!º²ÐQ׋eýú¨Z…ÉO�{cìfž æÚƒ-Ò\”‘Áÿ8z«&¶Ü žûÈ„ü'Zž¡È°[QÍ·ŠØ;5J"sBas–+NÌà¥ÁÛØm&³à×Í«TÞÇ‚ä<ÝKíþSÁwë:±U¨Š(‚®ô4ôáf¡û¿\îèNŠ®,Déò^h4[„¿Ô¼qÙ2[•( ºÚŸIÆkây-ÇDÀ¨þ,uL¡ Œ¿S§%D×Ô2Q5ž¨î~ˆN{Å~²Í€®àoÄf¿òB]qâå®I_¬°ƒª"q¨Ó€ÝÃöèc¡ÓÞÐIs檎êöÒã‹yY%aVZ(É@=ô6Nžƒ¼i!αŒ-}ÍK_hÛÑaL¾ÕN~fQHxL c/=¤*€ÆExy‹Æ©Z�°slü„‹õ¡múQX¯7G«q†—&äeÃò[_I^‚"�g’MÒ£7âݲÃX°Ñ¾È¿¦g¤kèº,iòëÔy€ÚyBÇ¿»àÎüßôÅ}+`#3ýÝòy“>êXÞ‡òY¼G6Œ¨ÖÁ�P[_—FÞ‰!ßD7þ]X�*‹Øe~º ®}Ã�óñÌé{XáÑ„^Ì)êQxî9ë‚§±?$í¹…>ÐñMÏ,Ñĵ�f�À7›[«q�”KÞ%ÙDºbæW&·y7œ’±CçeÓP*2 ‹t"àG«ú07ð&g‚¦¼¢V»yèé†ðâZ, V=�Æâøq\ ¾>ou£HòçÈaœ÷ç=mxhJ/KÇC2òÕs®ÓÐø ¸Z�N˺áâ›é„ÚEà)¯6êÿ]‚¸‡Žî{gèN4¸#]xhø4ÊK¢ÿ€T8ÍÄ:ó9÷‘^:"­¡ô9�.È–°UqÑ ¸tŒ.ò€‰utßÅËÜzŠý=óѽ&¯©0üÞ0�›ì‚÷ZlÁ³ë5¾ˆŸ Ù Gñ£�-Ù?ô•õÒ¯£~{�tÛ“s:¨žõð?ï’–®RP¦íôšH5Ûn�oþ£)ùNTö@49 ½‹ýœ‘@–íP†9·ÂpßýÆ""ÎÙìÆù_­HÛÚFjÛfgvq �~b/‹úÐÜÝ=Ìöás ÃÓ6ài·ihåý¯ûó÷±Be± ~8 6úס_ìOòcöØ4nô�%iԲ؀f\[‡ì~>DÙ=ØRÔ�Fˆ‚þeøøîùõJø‚M`ïg[vh$ —ÒýD8ë‰ñöƇIߨžCüÞ:IC#×áÎÖot[½ã2þ‡9¬`Á~0²�­¯þÝqH}7P@&RÅð^S<ËÊ+ù»ï9Õ^L¹ r(³Žÿ>|GþÛQH?iPè÷]H/=ÎKë ð‘ #…ǰý„-$Ö(·»v <\½†Nä°æ[˜=@V©À`Öd{±¨GÀ¯¿×á6HBׯÍXùxòæ ÆšÍÄ>Úƒ�]=`•?©â†¾—ì Žj÷w0ÂÊû™Áû§‘ZçjÆ�¶43½žÔ% a‹îmšV®ƒvüèÎÃÍäƒ[ 茟<¾þŠx¹pÈ5…Dx½z£Jþ¹;sbÖV0Üþ8Ó5Œ~W\ƒ%çUˆÔ²0µ¿’ú»­€%ÿ{)¢·G„"î2ëc ç4tGÇ¢ØÓ‹èrg„ Îÿ�g2ípÁ�¹Ü-Û[±¬ŽŸUê¼DFÿÄÁ‘ÌéP”ö�šïtƒ^¹åXmµ�ľ.…/>Ò6þ!Fí@-®ØÕO7Î8ˆü¥gÁýÞ Ùu^’Ü>N–8D€bË[Øœc|jâx®l,›ÎKÂã_½ª• W±‚^S”çܼ‹OSÁÔi=f^WE�HQj!gi@˜64…õž$ç]ßÉatŽr©ÉbSÎÌ�iXm C¢nå`}g>ãTõøûÓà­¬7ªçkƒ¶g(µ÷ÑarmX”ç¿JÉ,í ç�ä GôFLe�î}ÆX™š‚�Š8Ó3šÔ­pEŸia›Á";³ä[öcìàr(òt¦ 5Çhƹ×p,*…�ô/dX£‚ž8™–"BýžìÂ*‡}ä\÷jlY^„ñÅåøTÒþß�ì`t« Üœ|‰.ç'Kr­¾Þë‘ÔrèÝ-?öjf‚Ée¤µ.�ÈxÝjúñ)«“íJj9J”s> ¦_NF£=Ì«œ±%Ô¸D!Ú‹Ît£­·†ˆ³DòMû�|ø½œñœ�ë&cHO@ {;ä$„†Â�s±¸z†?áûï&�sžt§`Ÿ�ù§+èi7! cHÐïõœ.µµÈÛÄAþ¢ÄT� jNòœ¼Õ�Ø÷Œ|8! ¦IåŒòþ|틚†7èúÖ Õ%Fÿ;Üø/{£±íå[}V“„Ty±Ò«“ɧ³íà9o|PÃ!«ƒ0�e�ã‡LYÛ¦>�±¿ß›ñáìD==2zjpàù~â=haøþØ9êýìêSäê‡`æô|òüÖa".ù™9Ÿá{Õá�àvrcÉÕ’Γ(lhH¤÷Ý…Êy±ÏdŒÜq�ÃuòÇ«–_±%ì¦a' 5‹¨þùòà»4õ'ul ÉT!±ÙíäæG;œZE\œ¬ ¿Xg¾-¢Žª½%:³-@ÕÆ´®äà‡á@tõ™Å5Wða8+ÖCîŠlX?M…AË?8êîKî|tÂBÏ}´ëÒv§¾'ñkTõ}јùù y'#ÊhŒ¤´Z æï+å�R³%‡ÌìïÆUW¦»í á±Ð—‚ ñ•£?}bÈ>iìÞ,†.Ÿ¨ïènª—ò¶[­£j„8Õq½dw÷|’Í n•˜[HѨéÞTÝÚ'ëüÁqf.©Ï9‚6`NÏm�£Â"°jó7zNd:†þàÁ£kØRìC¿¦ÈáAzCI7Þ¾ƒ*�¢1'}5Îìc¶¶Ñ—*,ʰ|Ü‹Æçé¤KY±�¡7ôŠ>Õþ(5Ó„¯ýÐ$d6ì¢Áôúæ�¤¥ÞƒòñáIùM`Z< ¶vŠO!kòpëCwÏÍPÏÏBÃeêšJÈÕç®8ê\ 5Ú\X6€�™šØ¶¯ƒJ çzáÔ|eر?… ”!{�Yâõ´ÌÀù° ¾þhƒÞE~pù‘/-hÄèga´éw¹9fŠî ÓA££T¢g9Ê{ò`Ü�Çä]|:½ë6—û'ô¦[°Tðy Þy>›Æ]+�){^HôqE½Üð9G œV{�ú} ;ËžJq?×¾%¢ÊWX'GL¿.ƒÿø¹ø»1|q[�Ó ÕÌËuAtšBóÁU‡6 —üÀ»x%w?ŸÁÙí�Vy�$àêW,È5‚§—pæ6çV2sÑøç_â˜|Õ9ÙTèC/5Tà!\qèMy‚g½­é´�¼ÅÚ•`°÷q¬ˆ$¼#.¤ñ§2œ-/…ö·¤åÏ[âqrm‰¹ï¸·£†rï'œçVHP6MûBc=aéÚí@ò.aʉ»ðèµ3Ðþ+¸ÛYª¿hS[ͪ²íî¼—Œù�ÑŸ JuDÒµ �6AîË=˜"|�‰R^ÇœyImÞ5S�½yDB9þ<Ü ÂVáioàÈò৆(Øs#v$³‡ÈÎRÒ¨âLž¶’)9'ÒL-ˆTÝNô*7Á›¦³@P-Û@§3‚.‚\Ê+FÞê„1[Tg¡�º~@·ù9Ô䯮×�Et”áÆáWøð�:oZ€òº ¨ŒÓõcàFõ}0¸¹Ï´…àúÅt£®îdõ�ST¤¦ƒ4äM13Þ†uá¾øžxÃEÕcÓÅG äÑéþ5’ø‚ŸÄ=8�A9$a /׿ùQøõb‚[1}äÛ¥):"ÀCí·Q[J’JäÒ+ÉÐêlß'�¿ü£¡C0šžÙ¹f³ûè<áÓL·‘ iV]€Z*…´3ËšJn_A#àà?g­ V­üÿ¸ÉÇešîã°‡/º[â E¼ô»ÅÖ+â:Á%¤-R†ƒÎˆïÑÚÃo0F8�gàÙô t§éÔÜÓV,£ü‹¨](.•%¹åwÈf‹(’v·G‚©\½Š[·]a=$4à“‰3¹³m7ä‰ þ^NÆ‚[N·Sƒ¾ ¢ó Ÿœ•”ƒiÂsàCß'æ‡Cv‰m,!&A¦x¦q]‰„ÒsèVv!÷ºÉ×?6Ô¨ÕtæÚ³¨¿ˆ#Á‰À'¥!0¸hŒHD]¡üâœ%âÅ`dQLè�X´£ƒ¦·òàŽ Mßs2˜Ùpn0d}%ÐR< [wb\}‘©:ƒ/gJ³: éädÐ9>òæ»}%9»mÐÞ£$#Î2ÓL ‰Ê…½$Øì üo'ó6ß™‘œeNT´E0§!—)ኀ÷¤0gvL:-¯$›‡ˆÑhQºŒZc,�»ë7xô¡iÙ”XÝ‹[^.ÆÛnGQpæ1B'xß�gî “³6ªLPû ©­ÎÑ;V .å{ î¡�>GâžÃ"Üõ…xöÌ{ØjC/ºÂoK3àmr »ÌÙ˜4º§Ëð¨[±ûìÑaömÕ�02¡|eôçÖ�t›¤(Œoã‡Ê»•xË�ךQäÛŠŠû#ÚôÑý_ðÎ,{8߇f! Y0\Ž`Ôþ¹�\TÚñqÒGÝI†óm‡;/'@%E€ëðÙ€ÃÝõŸ÷5Ð%º¡x·Ÿ—»øq RJ£K÷Ÿêu%KZ0$¸ÌÀPVŒûßAôºq9ÖxìÕv:Û\‰ªÎ˜á<œuTP»‘“¯ãøë4j¾ÖŒoäÔ½ç’÷›ôéç÷ø{ÀŸ¸¿^B\£æp\ÚÐ¥Ú~¾NÁWJçpðÄ'ô[ ?ª)¬0N¢1÷6¢KÀSº,vÚ, ÂK~ULuÝ Q° %*×Á¨W °Üÿ! ãÖ“†#jp`í­ñß ycÞ¤«~1™7–Jw‹øâKƒdT¾¦ÃÄË; ”«×j›Iz±�…&™ÅpÛZÕ$»ð©Ðaú¾;Þ5Ð7,†M«‡hiðîœý‡ÍÏbøñ‡Þ©¬fØîPUM7þ7eVAX¹<Ó…K6S3 Žðtð>ã�^- Píò��A—á€B=D æQ¯]_P¦8f]Ø‚OU‚H´ÿ ¬[x„\’Ëþ!”Î\Ï]Ñ’�ƒ�§Qê�7®YL‚¯À�VUzõ’#ÆZ†àò=ëý�dìò8Aã y UñûºX\yýKɧï™ Eš\½-&€¼Üú“³�B„#1(Ç ³…ÁÖјCïÃtAÕmœ9o?FĨS'¶ùäò±~EÜqemª‚ òÂrHŸë›lˈ¡©™÷æM­-$-×nÀ£WA4D$Œ’oÁ²¢O„éGò²/žF˜Ï¥M?r­\ª™Gh–³çãwAN©ø \7ý.ú\¿ˆçW;”Ü“ñ¥ï—\Âís|q»‰7 ho‚‹cP?hªU^‡Éqî°¶+éi#fѪäõåðU'ƒøúí¤>9 öñ.&xzÃrky¤¹{Çúñ­d>s&ûî²5‡÷cÁ˜Ð‡MµºäÁ3 ¿·ˆpj.^bû¦ë‘;"“J]-} ±·Ü9…¤yK5©Ý˜DΜ0�Áˆ>_zB-7dÉÁKüMîËr–Í0Äû¯­¹ÝZàÆƒlÔh˜I¶ï�¦-û[Ù�YåÔJ#ƒåý¼�hÜZ=WÁËCáÑ8—,/~.khå>â»Í†;dÏʼn°klÏ]!nKÉ{æ—�j‹¦Òô„üvø®œ˜�Ã*ç!\+ƒ…Ë2Á•KˆjÅe¸z ™ƒ>¨Ð4Ì—éœý{8ùËÞSÛ[`³÷šÌÞ Ü+¨çäáËyIÆÄ1™U…[IVm?áå ¦º{>ãA3_X˜–HÚúô0ÂH|Þz¡A¦Ûµ2˜~‹J†Ør ö:Ê�ÅJ!„[ý>ÌiGñßÿñÀ%äýàtüF†%,lÓV&ΣJÔ:ÂKü¤Þ�ÓƒRÓá®z �µƒiÚá@à]! $�©I  ï4†ëJšz³y�O�Þ¦Lì+üç!šXzpaIëøVVf>‘µ<“–Cëßóh§aÁ•¼&��M²x×ë!&¼ŠA)50“Ÿ;|ç,ºåU�oê44 S]´¸ÿލܤOGÁ¥6]8ní æŒ,ì»l ɇðžþ:CîÂåLׯ�ð磌¶.â¤oXǸ¤ìD^ù¼ý.²¤o«<¸ª€6_‰Ã÷5å†_ü ½í$¦ù´`¡E%¬»-OÖ¯*C!Ùã Áµgº§žÉÜRf]w,®@Áv-°¼ÏƯÖcîgß8�cKë©Á16z¼‡9y©”¼t C�‘q¦çÝz�´M#ByÿºP¬×Ý0vZ1Ôø®(ÇÈàÖ~ ¦µ�Úøþ‰Ψ¬bwæbÏNC|q¿›Ì«#Ïe»¯ª)®þùˆ±_—T"ö@vK• i“'Uš±—(e¤¢H±N©Ô‘Jéqì5ÝE3»‡©ðäuȵ¶'·/:¥Õ|°öëWCõÔïŒ2¿¯¾£/0u m¼Ï,�?Ȇ|Õ„yeŸp× 7vNÃlîûØO¤ý¥?ž™à¥Šñ•P=v¨(?§Ùâ <ûY`8{é4(Zóss¬9>�?H›~4n2A~e,}ûª’PäÌ:ʳ� Ñ pèál¼o€o¤¡èB2iã‘A»©q’Y®�‹ãÞÁ=áÔ­Jf$£‚S °R®’…%ðøü {Ëu²Z‚ß$S‹§ÞànYÏ+’ÀÛýŒÝ§ÿ³)'ؾ2‹XI_$Å_Œ@“}æµ^0ÂC8Ëæþ$/êô8‘ÇdHþsªW~“ú¸ÔãtÑ—xt˜—ßãálŠHEÁmoéíCÚ4êrÍNx@²äAPã6F DÁI_'Òñ(€Z§É fO"m]¬WþÛ†?¹ž¿B]ûRˆ |Kç aEa¿`ˆ¼‹€;§Ÿâ'N*tì £b60zö�n,'–ó�÷¾/œø“BGuR©Ps,$çÎæZËå¸îih ×€¹o3¿`7>+ì_f:@ª—'üÚD-…¯Æ7@ÈõN=ŒÃ•‹T4{Iz$‡>#ÙЯ™ o��ÇÀ´¥°|£ÇðÁèðp š)—è3ÉFBƇ. M&ì�hâxµ“þ•\W7ÑÕCYÀóá4Î3ú�YÙNû”gåã)Ì�ÑHü�LBæâ�ƒéÐ)¥OLãè�]§ÉƒøKøJ´€èöyC…w0ɈÄi×¢ñ„ç­´3i0�„ö¤H’ÙCšwuîÉÜ þ €CÁB:f.ÊUX¯üJøîb2“a‡qrid–'%Çœ¯ÉÏF{dÿ› ³–/†UƸ’ÆcaíUb�.…<þù¢7—¦M¬¤w¯fÐC.…`d¸ Ciq¾y†ñÊG€]÷Ã"çroM†�«éÖ‡¹$:÷-:é½üǕ״ÞÅ I>]©ý¹¸æ®|ËÒÿNÆP³Ä§pÞ¢žj(X1–!—Jêϯ‚9‡4`œ‰‚òúo”·ßCŸ(ÑöÂåœã•Â0¥l@~•é p¦6¶ÿ§€¿“½àÜ…‹P6‘Jö[m�"ãrò§Û*,ßâ÷ò-xåó}pt}@Ý‚¨Œó+ºÂ[ŠÓð{r2ø¹¦ã[ˆOh‹¦rÏÓ‘Ös°F˜›ãˆÏMc0Àð ñK¢—b+(üu`6˜�ÓNO'ÈsîYôÝ6J'l±Ûí&H'UзªOQÉ^�äØVrtߎNÚEÐûfE½~;°©Ã38'_vR›SWPVè QØûd/Ê4Ü'²ë›ñ&ç \€‹Š9x�¹Lr²C®­Á[U{€›®x1Ác’œ>ÌRþ¢Mäv.ìŽKƒkŠ=Ô®tÀ�ɸ|¯\¨!2 ¡ø¬“Ô·§Òƒ"Il„š‡ëÃ�£Óå`çQè�UDº–­ÇáëùdLå�3eªTVEE~ß ]:ݬaP#þf-Î?³öžQ€ûæ^XŸ%Âé÷âå�ù;�|p{J3¢ ‘­h!ï™kX¾T�»Íï1»«?]<‚ùyH÷_/Iþÿ½]%}H¦þcÈú‡»ýÿ¾œå�B¿­ðº·6µõCYY ;�!ñð%Tˆ‹«¤aÝ·B�áŠq�yÓ~õLÕ)tn1Cþœä‹êF�M?×êBú˜]R> ½äPmKdÏ¢b®¼´g„ƒ““e ©ÅEã5º°èe¤FOR¾§”5zwãÍVâòÉgäO!'Ã"V”ŠÁ†*\üê »UÈ®MíÚiÜy'Š RLÓ‹.€’Ò:èˆ`ÙÒ§*X°NNå5�Ú‡°­´Œ¼’ý3ýÕéâ]i¤ø2¨áøÈÊÒaîh€fl)l¾'Îñ,7Û—°›ŽÑ…)ÿ²²Lš œ}k\\á�ßSüÛ�F6hÏàJ¶–BÙ1úà–"¼Ö’ƒXrºÃŸ�¯6³‘8-Â_)ÃXQ�ÌÊd¿­Ø—®c�/SCaÙ%ðâÃ)LÎF”Û»‡f$¢·q ˆX‡3û ÜÀÚ7ý5ÁéM«³à>ªîï!ïF| Ó<¤µ~£èÝe8¼¸=¦º‰Ó|K´ðW†æ—ë Ô^™”E(“¿+.ƒœU ©­ Ë wêDÎäh[ñrs«è׃Q�¼·¨Ž°Ò�»ˆém\»X‘c«fˆy[„PV#•í}¦QÛ ¨Hø.’ ëJ³ÁĬ€hZðÁÈD=|kòÝÁøjJ€» W�Sy:ƒ¤œ ¥MÏC•Ð,”ž»šÛ/] ²+=ÉÁØ´‰ØÏ*=fíŠ.ÓMç:™Âq"$V�[¾¥³Fj¨q_‰Ëõ?€Òªkð¤q1ŸÙF“ÆOSî?Ôáì(wÇ:¾f¬ïq…êï•Ô‹ç2ÑÉ þç_}¸àÄ0»‰oW=…û©šÇòZ˜±û¨ úÑæ¿×àÞ3¨:$‰Ïk‰…Ýa +Æ­ùGÑt“\¤ Q�°êÅ8ý~K˜ ‚Rø¢®Êäò‰áíiœMzÇ0hå¦Rø7ãS‰AR žø"Åí¶grÏ^¦[ÏÇ–"YΆ¦1²ù?aî‘!²M~OÚK§ÈÏÞŒté�v0�õØPOI…Q;¹ƒqûtŠ8ŒI�ôݬ¯®Ão¤Ãf®6�{éÕ(gÌâ“å–7:/GlšLÂÅnã°§uÌJ‡¿¦˜qá>š¿˜ËèD©B­ñ�î�9ßIXÁLnåç0�ÝÆúä×¢e™ê5¼ÃâoÝèß%Äec,W“ëp<ý3å-Çø«I(‡Ý;æÐš=ãd]Û\4wÍf–sƒa*m1&_RR׬¹Z±Àhþ¤WDÄqn€ XüZæñWq—î *�1„õ•œSî‰LÐ( 5pçöåXÀ"‡&T¤{á8“˜±3¨ä} ¶ÏM cŽøCÈåå–ãP|­[¨Gv@ÜÝÿ°ïw]ð{7%'š¿y;¬Z+ >©VhUyϰ߉—ûàˆØ«ì†ñ‡BØþ¢‘iN8‹Jü܉X(oiDÓ7gQ_3œj�ÌB¯Ð%Ðt-3yn�à�/Pl› _i\G1*SAâyC�#_q¶ÑUäW{L�4¿Ámr\Xé¸ýâ¢0äÒLÚQŠ—gcOŸGEsÎÌ/ÆŠöðÝö$lÛœ¾K_ÁÌÌ`a-…‰÷[YÝ SxSó)˜ìê ÷¹….o8)ØCÛóÂ!ìy=ÅKk,gp�Š”ieÕy?9Ÿþä­…;Ë“°Ý×óßGÁƒ%ø¢ü‘Z�ÚÆ8t[né5ø¸/˜^³½ ‹dó@t‹ú×—‘›’ \OÉ*žËáÔtô’{K^AÛPì2ïgÏ[Š£Äè4zw”tÿŽÆ¶È0ä=ÇÇ ÝAÈ‘H4»ê‰ÇÊzˆÍÎ×Ð'Á¢­ :”wÌ¿“þ¹¼ÖæVI§ëyÞ¹»Böœ+`}Ó Õp§ùíMºÁ –ÙVôކ7Ü~õnˆ)±#Çz®áËÃÿJK%œÚÿ‹XÍ-Á#åÏÑä™Vteâ–á|œ—•Ž’©Ôž]�q߸ï×ã ]ªÛÀ@à´%dËHŽï*'¿»žÑ{ÍÓ@ÛžL‚Ÿuñc­™îM¶ Æ.Áè!®�d¾.:º2zŽ“»S/à\„7¾øOšM€ð¤×ÅþÈ«d÷’#Ô8¼"V =q޽+œó›KúVÝCo•9˜Þ*W7§…‹ø©£ô2vE‡ûsÝÄ߃T¤D–›1;�éFƒrtíµ_Ëa9Ö˜¾¨ šÄ}áÌÒ1TÛÙI.r Fz‰ˆS©ù�;NOÑõsbȹy\ãê"Ÿ†«Êíé¯cç°S@‹–c»)(:d§ÓV¿Í Òñ�¾,H‚#5 ìÖ½Â\\_N§š�ú›ùоw™ç¬ðƒ×êŽèç↥ý´Þ[ó ¢ë‚µ¨84·.ÓÁ�,pª£šêY°YxvVDAoŸç“Ý’*`«ÄÇñk=©ë–“?*÷'ï–Ÿeó]fPK—ùpD4M{w¢þár²·å©}LR<ðhÌQRÈôµŒx YÏžbÐïlÈâÔQïÅéÔ¹õ_çÉ·¥ ¢HÎ×pZ!KÍzÅQ².T¦Ê˜lׇèÆLTKCNu8©?„ZýäSq6¬zzOu?"‰Ò« ^Dñ¢ÄÉJ´=ÉÒ¿Öžkóñɉ àä^�/öõâs±bÒrf”,òÓÇôqô©½¨Óë„gô|¡ìA Ù%^y‹1ãº)dYèêR‚M/žÂNO'z{ê#íæ] 9‡o;/7ðÜœkÜ‹ß�„AšÈ–_Ê'ÑaÌ?äBÚPÅú&d®ädÙé‘[Ö×àÅÁs #¬ ù*¯�ÀåKˆbR àv xzjàÇVoj. ´8«#f�ÚþqbôµŒÔ>ž‰á åpé[,sâb?+pztÖàv™IxÛføÚá ù!,Ê5ýŽ_�oaì]˜õÁ\{ 0xóLê’ på|%ý 7îz„€óží~{%i�ýA_‡®BýO¤IQ‚îÈn4VÄÂ=!Dïòlœ{Ì¥(ùvë±i|Nž«HrÖ8Šq-eÕpê© LùpÿÖn!-þJ¡õ¦Ú¸´I€k˜å޼;càÊr3òã¯6¦Ìߊ¼»oÒò£ž¬†v>×VGO¾�ôªºJÿýLy*<á±m"Õò1†‹_x9FîÀ@Õ+V]Ó?¿P¦»oA�ðý¤,)9F_œÂà=™tù�Ño«¹‰�˜öqbþå­–¼&';~Üt°¦Zn«9)û `²±�ÒÞ•�6¶ãnÍâžÿô�fGøã5ÍMì¥÷÷°Fä)£ÿ§{Žw’‹“¼ º˜+“Çk÷ü výùt™K:\¾‘‰‡†—Mưð¤<¦kÝ=Þ&øî›ϯúAÝo>Χ,àå‹{ ª1ï]8ÞOvFº¡Ï3 aÛŠÃÞƒÀ_ƒ—¢¥Éy f˜W‡%ÿ³{y8˜ãD –’‘Ã:¤Ódœ1Ùõ„$¾\Ïìõ7&‡ŸocÌyA 3Añ?Æ0{¬[6‹ÛXÒÆ íˆÂ‹ù]ä±ò]Ø7¾_/•ä*Ÿœ»DKQ*ix)N”,R§« fáóí¡DòûÝ>«”}¦® óO®ÂÈñBHVœÍ½ä ͧz`|c=»HˆŽ,¼Mf¯�þ…ø]3�¾Ý¼Oø@ã”'FzgAšïz¸áù ”‹<€Û XŸ_O¶¹ÀAoT�'ÇùxC‹vù°¿ê {õÖ3¦(ß|0ïv ó7í¥ÃxW9ÿ­@bÕPîÉ'ø3$ŠuO�ãúvÐïáMÿ¨.@· iïÙ�‘6 “©áJ�M-v‚šÄ�…±Îtàµ\ÌJÙÕ09êÈ=^ŒRç/àöæMðÐ\€3Ê¿ô¿ág^XøÛÑçÓcъ̓½ðz±ëÖƒ%~ 81‰‰R_ ¬î)•I*¥—Ü$¸Æs3í·HþúZ3ø’nº)]T—IÿJ`Þn†y'ø¸š÷�›Z@l!™ß?ˆéË õ©:X•òã‘�©(}6ê6,¾CohÚÓ�¸zwúŽ–0^6‚¥º8¾³5…·zÞTÚËyĽÉÌ.&âF2‘׆ک 8¶(�–¯Š¥W.òC‚û-Ú“ˆƒv†˜rç%cŸZB øÀ‘”L(½¾ƒé}õ”˜”Ý"uò› `·.?»´ChéLHÛµ—*�M‹ÆÁ¼�Atóîììí�U.�›­Š‰ÖR3ü9Û–žr™d‚[÷ 29\TL¡ŠÇü°8‡àxüc¯øš}d׋Ӱ"õ%Yqt-s�~‹+ñËÊ�xôÖì>çK«ÏdèÎähHÝ‚fÅ ¢u¢Œ¸Î®…«e¿ÑZ¼�ÎÊR¢²¼Ïèm=^ÔXèƒíŸ%¸<&èµ3›Ì<ÚLŠwzឦpÚ`ý{>6Àït/xoNåN«ƒW¤.6zêq¥l¶ÃõÚ3Œ°yöCX©|Oˆ”¡l:§�´® Ï-x žeQߎœãi/�Ä(Óv4ø”ÄXœãU¹ô�n0©“•ÃSû÷¡Þ›NøÛyª+¸8¸^‰{ùÌ"6Ë�u[’12oI0³…ãa…°(ȇy2+Ì´]üÃ$jF˜¦?"R{Þ“ 6‰D8Úƒ2e|^Cyï`í� Ñ—®Ç™ÞïÈÚÇ~$·½ž}ã2½k¬aî°;ºˆ¬!5õ£plºÆÚ/Â…L/öü‡òP?üvÇFµÓÍ:ìDH ^1qa>­=FK&î°Ÿ.yAÍÊ Ø¶ù.[¸Ç´ÓqÐæ`èShìó ǹ2Ìé(Ü«x�­Ûȱ±6gºwg“CáÈ—Od®¿.÷¡áì|£‹^s¶#�ó\2œ–‹^«‚v/Ôž6ÄŒñÓ¸kÕnðAM4èQÁ÷n´Ø3ˆQ™°ÙÆ|[gInê?űÉCÄÜáZ?rD;×bbdø•˜¬(‚UÆ’Æ"C÷³`“cV?hgÿ~ä„–…°Þ¢Ó9vab\û%b0$æç?6f Š,�ôÀk6³±bÞ•ËÒ&ñó>2Š……8Ô�E‡ë2ÞÇÛp¶‰í]ëÀ´¼n…-ZE^%‰HóËqé ,ÓOCÉ—Ûh¨íf†wßs: 4v\‚&V‡H�Ç �¼Hl&"é�õÊøñet¶ÒÌJA<Ÿœˆç^¶Ñ9Ó ixŒ˜a~Í,¼–¹€¯ÕBS§yðUAƒºMTs|èÙ[Q¸þÂfõžCLê9qþØÑr‡�>µÒZŒwF[š/A[áuz&ׇº,`|¶:1UÛL’fÂàƒ¿Dóñ-±š€ï0ã³è —Гª|ðóýÙQ*…N[Ú‰Ù]l?Ô‡ùgM`Àî_?ùw�)-Ë0{Ú5`fnÓž`º©Ÿ(iÕÑŽû‚¨¦jÎ(íñ'ª¤r�¾à- Ááˆ7²í`xY5ö ñâöö“øì¦}äØKכхŸéÔ”Ø%…ÉÇÄð„ãu²¤K'[G°c¨ Ò®àÂ|p7¸œè\¥—óªéç túêƒR–aÔ×V„u_v ÅõaÕÕg¤µí.ù"2�{’ùM5í¿À¶ÐdfÀ°Jµ‚íy{áÐu„tI`Œ¸)»&}{aÉ"æÐÁPVa¢tâ^mA|•ØGÏÅ\Gݽ6(òð2äZwЭ˅ÀÎ%-ƒ2_VKCž{'’Ëò¸è¦,gªç¹˜È�­®æÜ’ÀÆÀ&”Š0 ¸?›ðZdªÿ”†í§É/L='oFBÆå³T_i(ºÄÓ-¢2àÿ›©¼±“ø÷SÞ…­Péz„ÝŸg†nÃÞäyåVp6]îÕ�ÈõèP¢ÜàKþÛRUw®R�·³XÞ£ó9{ Ô JŠ»ví~ö�ówÿwŠ…­ pÂˤDC`­à \»ú9gÔA_&Ó½ëéÒŸz´µ{&ÏÍDS÷2,¿ªJ6u÷‚Pð+f¥ ƒY;g–¨|†¸û�1ýâyÌvgéøjüRï$#Ïß௿A"ù8<=×Hv{ÁÁÏŸ(¿}0f5åÂÈ™Ã`ꨢP \—yxØN 9ÿWpÞ�X}F‘¢2²…H)Yñ9ï»(--Eš*Ñ@V"DÈ…ÈÌ,[*÷}Þ÷W%£¬"«´Ke„”Tz<Àùíu®s]¿‘Rsý4øÛ¤Ñ?c—L›€Ûv ¬×Òà*mí†yï TÔEäÚEãþvsl:ôƒbj1tÑý¡®�27øYgšè·lJ´ÁÚûAËÅ9GáÁ‚Säø[LQ»�ÍQ”ý; Þoûbsóa*â!g§\#ÿÕCû8æ¼5ïo�Ðô…(^™LÓ7‚�ïCÒ"WH¥>ü£:ú·!M*Ë×épNß³‚ÔAÝ"öD‚¹Å±_"A<"83?Šl<˜Í$›¸X Ó¯“Ðþg9&(»ãèJH'™$Cæ~4-áHçûsG;Ðø‡Xï,ÀílO'j‘©${{<œ¦ÈÝ€¡3üáÚH.¶,»Ê‘hÕC•ÎMxJí8Ö[—AÕ  \�vÁ9~®ÈNVÁÌ×^0°k&îɤN¯ú�O%‡ú„ÂÆ M¤·ð÷G-ÙWJÎÜ“g U¬É›“ðµÁ² ÿP·ªÜÄu_)ÛL“õWAJœ)sÊX‚ ñ¡È&�ƹ*Eè3S yŒ'@ö‘Üÿé…fƒv°]L�õÆ4TÕCA§ë3Â^³g Ø —qävtÂXJˆIò¬9¬•ŽÕ´¦§�TúþÄã§L®”8Žév@uX!$PLê(aŽ/®„Ûoì©cZ$¨Ýr€-ЉìÜz{Ì9ð2Ú=k7ÝÏWE'Ý-A™€Ã“ì�Oð}ôU–Í«±hP"à=þ‡ærŠp^AµÊa™0ª\†ìŹAKqÏµÝø¦S�ÓZ ϵ}¯Œ Ë v[Iû Á�“^Šç¾6i úéŒ ¶,8„;ü~Q� ¨vã þý µýRc[|÷}H8ì˜æ�LI‰ Æß¡ëQ4Äù�€gÛcpƒ ëè•Hx Ab£ÃéÙ?¹(û(ew‘ì9ŽÈ¬ÁÊËÞ�û…›èîw«aÊo1®åg¨Â“bø>Ì÷‹ÃÍn~nA=õ]”JjfßBG1ˆæJ`‰3?”Ö%Vg¼1ز�iòþˆÂNàÝAŠB<Ô Í 6_ÉíS È'¿éºïIp-Ä„õǪšÒ·¼¬ÞöÕ0Ð_Ži—è7‹ÏhÒZMx¦°¥{5l(Ý‹Bì\´ˆ Ç¡ˆÛ —1™uh’¬˜ÛCîMn@ë)t«o!2ùÞÔö›vzˆqyMÔ\Ð#ò™×Ýi(*žƒ–gªˆÜSsø#(Åúž¤ÆiÖD‡ñ$õU ¬4Ûë¼pÙ_ïD¡SÆ_ŒÐá�î‘Çä´!³°â�qÏhT�ncú½.Awm¨gý£I++©N¨/üyµžú— ï·0Lù%ˆ«özCKuª½éfŠÄFpb)$'Ï“ÄÅ$Lg€hž”dí_hGŽïMD6jÂë[» Á¶‡x®“¦®gþbˆŠ¬©—º(L­È„·Wmá̵FR÷$ NìÆN85ɦÿ*»p¢©™Þwˆ8]~ž2átñgAœK3[D¥�½=�qÙ„8¶°Œç;ÂïÛI 9ÇŽzâ|û ¦wV+u.ÆâÙI$)è‰ÎR‚ ¯áݽ;´Câ%Í^{Ë/+£Ÿ¹¤¬ÀˆŽ¸°W¢âpé{ŒW�¤{Ž_å´:ÀÑÚ òão¢*: ,Á�K 9|Ï3˜Í½�쮇|«Žã“NORn_thá’}è-Œó�hƒÄ´æõÇ�Q!NÐé:NlØbòàõ òèxçÐVU\XoTÝ�@ã�¢)û½­Ýu ’<6�®½ùØÛ„MÝs«fU¸l/K>è“8-ŒæÃŠ»�mù˜´lZ�r惤âž+O ��<#£³šL–¾eá‚ßEÐ!’ŠÛî.Àžê¨ì%Ä*ÈM K+bØ'õ ìÍô}N<8O„6ˆ±Î>ˆ¤‹L»ÉÒRØõÑ×EEÂʯ7á';S7ƒsV"ó.âg¬Çæ¦HÊ}7Nn-ÀG±Bäá5töY‡sÖ¯�¼M PE½™Ù™%S6J´ÂS�5®q›Ü=D 6L;ª3(:ŸK·&à…è[ôÜ®TŽó�lÎüBrýŒíz™zž-ô¶M Ko¦i4ƒ|!k1h –�Ä?Exç=Iƒîàû»Oˆ›%�J>§–а„çä¬ôH92f¹TvG?:Š.a½r_u'ÎrDõg±4§0ÙF™“�¼JÒv.¢ÄÚ˜rŸ”`Ø57zã÷:ÿLJŸ·¬„è'"Ìø�< îüpPè5.�3^\®·“òMÄ’‚¦j<â`öXçfÉcLÙ \XUKŒ´ià«¿$0º&öL÷ºÉ ¨—³‚í![p8¸ -ö^¥+n_EÉx‹?•QŒ“$ê m ˜àäFbóµ�H?RÂoÆ‹ñ‘Ä*ˆ>EャóQ9;¸t– q�„ÙP‡¨ëÌªÇ ð­& bbioÎNTH÷Â%«þïªÒ:©‚—ÞE¡õÌÇð®HÂy"0*ŽÅzæÔ{è]ÔQ‘b¥Î˜�I§ í¿v"<ìÞ¦Èó~6n¾õ…Ó-­‚*"?è&©�˜5$Ìšã%êÿRé•b>( –fòß[£©þÛ}«j•à¸ö�ƒ�†¿dA2ÃÚmÀÅsË?“¤àÙ™„êþQ0”ÐÑëRÉV�Oä›ÇE<ýp?Þªö#ûöAJQy™[E?Ùî7f \ûó„²×b¾7 øl†µg|ÉnƒBSv¿œ»‘ SÂ+Ñ÷™l6ÓÙÿhÓ ~b»(ކ^6æ6T2kÓN±%BïÒG®øü�&tõxbô—§øïA"~ô!&3ƒ#!]3W]Á¾�BT–sÅ£’’,æi�i]HOí»ˆÏ,µ¿$gÍaèTŠÂEÜ—w�Ä©ÇuWfù+b¤t„z䨂e‚:•˜_»s_.Ä¡c9 Lç³úï-Gõƒqðë(+¸¡¶| Ö^ÁÞÏ&ºM¡¨yÁˆLÙ&'*Ó‰`ý l¿¸ëÅê°9ôΡjzg¡ÌÖ:ÆQˆÙCºÞ%Ÿ*>Ð1^RvÛõ6а¾enÅ…×÷bÏ\X¹EÚ‹ùXÑ%œG²¦U‡ß�‘Àïi`0Y5!¹4㤄mTàî9Iöz˜–e¢¡l¸ jØS0q"˜ì»¨ýf«m?÷ ù¹v"¤öšHhüd¶¸?"çgÚÒôçâðëælÖUiTtÇÃ:4æ×Q ¿ßÞ…Ò�ß™�A&À/ö™þKë¬ ¸È@Œ}ÒgœzM½$; zÐïð/B«3ú8Š:óÏcסp¬i*ÅìIJ“ûµ¹hÉÂd³AXU~ÿrÒÙÇå¸î«àäÌ<߬ΠÁ ŸíäH�"¬Î�EÕ¸0üþß\ºrÍb¸ØÉ…mIyx¥c‚>è)!mÛê0¾/K'Û FÓŒö÷0{k“1Ù�ÍUÖÛr!2¾É PüÇe\\÷bEp5”yj@“¶®M.ƒÞ÷øjÆvJ9ªè~9lLÏ‚¾Ü)<õ0›�£€Êkž8€+Põ?7iÎ¥"\’½�>PXÅRªzƒëÁ~Ù ˜J• ìîL|¢¡V¯¶@DücÜÿC—µ)ŒA‹oQDëP6'{öujÔ˰¾ô-âùƒ4,²wxDS�FTQ؉· g€ÞŠL¦&*�œàZ£&ç¬èË„÷äô÷¿ðñã!2ÖögŒ/ÁLï7ì'ÊÁAWì�ßÓ2g>N_Æ0\‰ß F&{°$} =ð†h•ÀäO™~¿Ûa@ùÔ«!GsÛØ®¼Ó-¶lnozBùG`ýŠ`¬¨îsÿúê�‰s˜º,¿·Ã² Òbhzûb—ãÀÏ­ÿ£€£¦\M)0kíGç²wtÇ?%Œ]#ÌL¨à¸D€m¤?m’„]GðÂjo˜uí. Ú9ƒëžÜÃnY$™ÉöðLT¶�?‡Â"iÀΧðÍ]º—ðã€ýÒã%Í:³Ñ€*øîûg‚ÔÞ0“à¾+Ži šì3£‰E„9‰Czs!TT'ׄs.z#Î;_}·b´�”6Ò’³Þ ]üšîëGΜ»Èe‚j©Ý„Ì&h|{”X ß¶îJÊW:EËKÜð§S2³g÷,2g®*Ç;› º\Z3D‹RB€·HR¶£¬€¹ó{M›öT€ñýûôìÓ0zOˆÛ±á©:þšLŒS«ëµdýt—:~Y�ßnŽ`æ›Pn!Àm–äåÎ2=„‘å¢88*Ž_d¸ÚÕt¨§²ŽÌd ›YBͱ3t®ú(©[q€Ü€¹·ÉÛa Üz·½Ïƒá±ç 5:gþ$z÷ÏÁÚ¹ÝTV£­$eilÝ0¶mˆKÛÈÑÓÚøÿßVî…øS= ±ÓˆF¼«!«·~¾ZtqiG›`{8¦¾€‘yeÈ6»ož·…•©b8ó½ ô¨øÓê{ ä×ÒrÓ΢‹°å“j =A§·ËˆçÜHËïA)Ù)¦w¶$¸u}!k¿ª£xÄ\ºð>ñx}ï•ÂI­Í8t¡�.È’‚eIŽ8‘”Bå<¥¨Éˆ–ìù@K§YX1íãŒl/ÚuÐów])ßt+‹…I¢‚Ñ2êx(œ„O;Íîn¹«ýˆM%8ê†ÅÑVPùQ†�å@~&gž×Ht·‰ SîLî scî’ðñk,ÉŽP�Ù—Ò@º*�ïªÃ]|»â¾HõG+i€²;Z°6k=†l„:ño`zˆ¢”„¼³'?+@Èk>pÕf³®iSâQ3Dô»(—w¼R‰Ó©¯ôBù05 襄mñ€Ÿ´õÃ…›ðí™^Nî³x˜e›ŠUŽÍ(¤»•1·á§ž+í𾔤ÏÜÁñ'õøT2ƒDœSÿ; X¾®Ó´5àîµ¶�uGGA* Ÿè¼ò‚á =WŠŸÖ«Ò|ãåT4}±K€+gÏ�g×¢×gI ^UÅF¹t�Ù"–û†ÓˆD>®z[ö¼i¡²2zäÈ®²“öo¹N;>ÿ¢×6aíP œ�‰ /Æú‰Ÿ·˜Å¸Òv·=Ä(ôv<æaµ¶Áô½þÇþ!%­R¢ô�V·ô˜ô”­Ä´C—qL;”+¹ÂÅBÒŽàgf�ÞNX)±†jZ~k ÕjYÇ–¡‰«5̳ÿJÛ•fcϼ®½�;²d/~è\‰ó‹ÁSß*S7A^®þ‘·ŒÛé!ºi| gnRáþz·ž.ä*’gü´h~–)颴³&1û ÂÂËYÉרÁ¿¥,--qïH,6‰¶“5õW0ÄÜSw]%Ζ¦ R�ù7�U¸ƒÙ1¦9‡”IÓQs¼¨+ÃLÉ¡‚¶/N¥ÛÁNÞËxi,}¼�•m“tåïïçöü|ëqQ¥c ™[†�sþÊ —`¶E–é«qâ_ãHòr©êP ­;ºÕ%Îë�ñ&yˆ^"Îý¶!‚j«ÉsSöõÿ×÷°Õ7 ðQ F<¢Æ ÛÆOj.¾§|¹°ê¿µôÂvM¼!¬Gr¥À{~2Vl ¸h­{¢.\e‰?ÌÝ´¥Põb>Ks¢„s Ï Z,!xÀ‰þ;ıݬFJæÝLÄ«'8ª�…©wã$Œ¯ˆW�ìg­u«§óõgã7R®¶b¹0ﲫùy%�¨fÄS-á8;¬zöRKzy™Nz„aH�15k%h¸>®Ëw�=™Ý¦Æ÷G˜Ó3ËQy{ žZ÷››ó0Nx1.TƒG—Ö€LÏêê7ž#XBMŠ”pAh}ýãÙ¾›²UÔf±<†N“7‹î€kcÚ^Ÿ Çö¬‚ˆ•lüø|ºÕRË‘(òs×bª·¢‚æxߤ¯E‹L–çQÛ·4ºh6·sÁ<î�>b¤ý�ÊÛ~Ä¥Q†ð'²«ö]gß�ö‚„ý‚Üž_Vàäw¯ÅØ!1�FŸY0ËŸ‰b~…þ ¡¹¾ú>IÖ)K1»?±ËMÂàŠ`+d]+çÔ¼�„¯>“H�Mððy(v�$ŽÂ'àëòj|m‚Šp_³o9ó°ÚRX¬…2¤Íïã .ÂmT€ ×38 ½³a�ÿ"h•xˆî¡ÿ¡î~~ìsˆ«¿Ë0êIî¯À^¡TÝwýE¼¡ù´ çéºJZk,�êŽ[§»¦�TZÄÑ@§G 67•Yû›�7ëàânìßôŽiô‰^ëBXîC,¨oR:‡WÄg&êk<¬'oß`õ¡qæ¸ënøôçº4ïÃÒ/*xx…þê›Ä�¿8‡Ÿn†Ïe©.òqßø&£xH1§à’©cöxëîZZÂ/÷/¦Ân¾œ«|‰Õ*jçQ^âäôžËib/®iÐÁ›Ãvp2-’ɤ�Ù±»èl/R'(@f&“cóYd•\+¨-K‡® Nèk÷\\2“’ußsàìˆÖBw|ö7Ž=Gó§qDͲ­}‹HôÙõÜ{›„ÉT´5º™Í?S;íÛð'h1z]zǼ—µ­ï�ÐeÞC¨+º‚õGü¨Ðp ñyª‰|ư3á;l7ϧ?>ªÑçe×`^T%JLnå™í£eñDÐ\¬Í"p·ÓSX(”÷ï߉Âó™¡4àÀ^�ñ¹CLh@«ñ \úµ˜šnu%!ƒd©F(Ñ]` ÒæäËö Xôº²-n“[7ô¸3Ú”Ð~Þ27!6 ˜PË�j¸¦l5Ž Ôã¡]§!‰+*ÛdñÜØz\×{êw7BQ?fN³j©‰�ÊGÁD(ùb £ùv8õ£…<–÷¶‚póý6  ý‘‡T°™CûjHA÷R”n5#ü±…Ðöúµx@í,«àÇÜ%ìµ¹ 䬶Xrnb…H-­ Ç4 5�{« Áß�Á(/”|-�oŸYgYvtÜ¿›®ÌñÃ(•v)ŒÛù¯ñ#[ üÅ/äo,�u=°ñh2¶N!ãó·Ãˆ¸&ë`”.p�†}½ÔQè=ó_ÖðøCž³ŠÉñ²ð¤.žº{m£}‡’m;¢Ö»·Ô›¯õ ˆæ@'öûäÀFY6>ØEÂŽ'МÉ,røìZr—¥=úl” q…ìÛÎ0ÀÄÒ5L‰›U¾²ŽÁ¹Q0^<‹t +£í™Wœß7VÂ|{ºY´ž ¢ :–,žf¡><(¬Bê:7XS—cÂÜ’*k8ìq ¢õ•0Hâžá €D¶+û£jt &6¬'·7`bÔú�Î&e¡äû«‹ÐÒ•�¡ÁxDÈ×löÁ3c/9çO¬B‡}nh{p„œ¸¡ ƒáµ²#~±æ2â~wÐëÊe¦43—ìòÃëwÅY idVJ ^öʇ ’yX'N¶+TÉA‘feR<àBÕ#ä!ò]‘P�îꎷ0dÆã£É YË\[ZÆ–“8ƒ—43°ÐZêfn„OTÁdS<ʶÆ­üt&·{l½£¨PU:nv(f–w0/’�8“ókIñQ�¯êÜüeøVNV~¹€‚ßVrý�aìäëèŸöë Zß@£#dñ^ÊAèì}Nçµr¶Êf£Ïb4Í€ž>îS—ÿèï5ñ¸B!’ˆI^‡~�ëØ¡-À 3Y "ç»Iý˜$œ)í!FI-øð®‹ÿõ—k'•]>$¬å%™­+Íêûóù4iÙϟ̦ X?y]VùãyÓ[´¿Jç|Ë‚øk´ÊÙ‡}'‚ µù¦¨Ÿ…›b°cÇ\ÄÇ m,À¾KpŠ<™˜°¿±¿œÿB35…hÛ“\ªT‰©Îjøî�+éžØ¥å/°t_þ:N·¶}EÙ’ظë)cRwë�ïÀ ÓB\#–‹Åóg°:u1 8“3ñ$÷ l!Y.á`:YƒÝ¦$Ýå}¬.††Òs?~à”Æ7pRÆ{@G1„~|ˈíÒ"kÖÓ‰ÙŠÄš÷ 7´„§’R9AÒXNöD°“Ÿ¥cp’+ô¿Eƒ¸xè=ô‚Vïý’I 6í }^^ÄŒ»“žzê.IÖɈ‘9H·|_O¶wñCƒðq¬ ±£ì˜½hÁ¶v¼n*CÛ @¥¶²&·—âÔùDÐ_£}o…ÁÖd7žú­ ’—+1á\Öí˜ËšµgL†@±²5é;Æ3í�× OJ mŒüpôsúä/ f& AEl<ÒNë"•L�Y¿ðjÃküHÖ“cyZþ£KZÖ“±7 Þ“E×ÙâÖú r©|†Ü¼ Ê ê°4Ì5õ€2šT0†Ó$P&¯´ßJ±ªí¯r^:žÁE¿frúº#è•G±L¯J>Îrÿ„ûo;0-mDéQši¸H!'íöˆÿ …¾widIÄÕQ_÷;¸ì£\ø~ÜŸ¶Aû”3®[F®Ÿc!�°n0¯Ä¯ Œjé‰èsLŒvIaË3q¬¸¨±à2(eÏ…ÚoZûä0|]쇤7 3Z®Á )øŠ±HI î"pLa+Æu'zOL”k~3C^i«ˆ¥ Jhùý%}1±n4'Ócá…Ô7ŠйÇð¤¶53 Á´ÌÏÔ¯²ŠÊÎØhê0½é-]‰Bz3M¨–æ>l–ƽ‹�싇cl_bã–AÊŸDƒ`Á2–b6’à ±¤óÊ m9ü¸� ]A0¢Õ\ãÍQýý(`3 [Ï�{� Š\Šýã�Tô'/kr+í;)?8folaˆuÅ�þ’v³lúl×grëª>·<²û/:³gøM „í6 êùxØT½zÅPÞé;Q·y�ß½â�ûº�'oÊòû–�îQ5dÀº—ÑwÕäJ¨_E#u9±ª#úF[`å„&øø ÒOYÁWD°³¬",ȉÚ*ÿá„|�Q|æ Ü̯E™«b(æi$F.$\‚(WJ<å|áàÍ…tKö\õÒtÜ•Ð°ä ±P;ƒœ ( +¢'Bâqî½ j²?qþU<÷{e较×ájœfwÓgE&¨·ˆK£Êá·ü»Ä²l3lÔ²߯ehö7–4Úñàá@¬TÒTm¬À¿Ø$X.z‹Q|±’#¸_ ^/;K‹/‚®Y85]�ò6Ò}ìýv1Í<ðô£ÛÈ™fbvmIIÄÊçIøÏhø°<Vϼ™J¢p™‡�â‡ïà¶åMâÛ” zõ¢À¬]§ç©s?ÅBýŠËPÉ»�ì ܃õs*HÁèìÙ Ë1à cN¥%ùص uçXr¬†� '@’%…Âpéì:4�D8Ü9LM?‹âÖAú{.9›H�gÍf}º"Œ#'tÈË?¹¤Å¶ùdÚ³1�zf¥`ÁVR¦‚í²‰K­8wä¦.�¤–Izh€“«qVº#'�€v7=៮µ3ÇF¼t|ósÐE–ÈØîÅYÖKÑßñ;£ã�°E'=E¸­ý]¹G’œ‡Z�!�®Öe¸A®„ض„“‘$y°+~Fj„Û˜§}ÁTåѸ(! çB±q}& þyÌ_Làœžbœq};"ÉókEÔŒ;DmJ‹‰JRVEþÆ![”·�Æ_:ؾ£õÀŸä Vj“¤÷v*©™¥ÉêN,¥c·ä!_Lv Ý…Ûß“ˆ­(+Âû(<-àáÆ8m$N_@»¡•d†Ý¡Ék\9kÉ/bž«MzK?‘Uûz@ƒÇ ãK¢ˆ�àJød׆Ïf}¦œÀFp³Q@Mé^jxÄ®*_££‚\Òr„üN2$kÉßÀNrüd:æïºD^(þ zµL,û 4É@TF7‘ÏJeŽ�öáG>9ȘJCU,LŠêC ·w9ÕÀ “]äßyލ££ ªÐK®‰Ãw©˜dÉqou·Ò�ç˜æ™ìm6ÿhK„8ë¯ /ð�ûáxôQ2¾Jš$—cŠ6˜`ò®a8Úy”œ-¸ÎN¯] z¢!Ì“&CäáÙÉ~�Œï­ïàïþ�ÜhÖ;št¿‡&ÃÒ\O´‰R"<_ò@ÚÔ£àÀ <ÙAðeC.ìO¤¶î«h�¢]¬¶Ž?ù‡�‹fÐËn]äúù«(¢?�JrÇáí†ÝÈùº}_ŒâëÉ9P9.BëåÓÔ¼Sc“ô©Ø/zÁ3�–oäeY¡8lÑf黆€*+ õ_ƒo Š)ïSqÜ¿wºqù`‰Ë{’sY ‹R8×2äðÒ‡`vr;Þú`IN¢6Û×~)ý›*ŽW–$àüôÕ¨&}Ç&cù^楻3fˆFƒ¨ú4GÅ×â îhC5vð/Ã-ukàøŸ LûòhÚ\±ž~zIº·õ㺹2Ð^e Uš`9‘C7 qò—òsoš�ÇT5œÙ8áV»‰Ff9Þˆ�Ôgaô�ÌLpù2_ b]¿="�ê´FKúÍF«Hoôú)E|Úø¸ŠÚ¡pÜø$ž“fñèÆ“�ªa—ò,p»ÝK n¶ßÿVC]áI2“ËÏݶߊl³ÔÅg‘¬áþ“dE¢>KÂÐ+;ÅðÄ«u Á6§â&àe ! k§¢Jô¿çª0ì/ƒIÎÓžg¸oºÎAg¶]ð‡9•ö…(Mw¿uV\9ù•ƧtS¾Ÿº`ûX’ûZ~JyÄâø·ÓðíÖ0yîdĨµçAëù@Ø/ŸG{…û¨™ÎÏé}Ý£^®Ð^ÑŒq¿KaÆÆl|f·™�°Ò÷ :S»�<ÌP�3TŠ» åìT™7e6›ÀÈtðÇ· »ÑóŒ؈ëR3%Êû*¯¦Á·#µ˜ó‹ íI©pM/?¾ŸÍº¼Èmï¯`ò1%åÇIµe?µŽªÂÖôØ._NF>™ÃÔ:o4± ï¹ÉdŸÐmðh!E¯%!Ë·Žü×: ßÏ'ᵞOL³}ѺÏC¹+nÒŒ¢)ÊÖ�9£Ò÷D‡0Tô1³¦³ƒ�ñC��6¶¼m^P´­AI©LZ¾û?Ú³É ®‡“•Ù_L¿ï¿ˆŽ#[P¬ûcsÌÉN�ݸs¯5º?\Ž 8ïKÄ4`ýÃYêèœg‡3V)ÂÔÇxR0Ä!{o*•Ü€Q\kºH^Kï»Ó¿'ÚÀrÕ Ý%Âxˆ›“5ò¸)‘…²{ ",óÇÒ<óg¤Ç1äÇOа¿P‘gŽ ½¡ö§PÃðiG}åNÛ£ÖB”“éæTU%Óbn -+å’©­šxâè ¼Ñ«„S[`§Í|Zãµ”YuéH—WÃf¿:b¾Œã[÷“ź‡àCÙØDG�žTyø9˜Ã´ŠÜ' 9�œlÒ§%�5öÇåê*¿=š„k�ú„8˜Ò(»w߉CV,$½!ÊgÝ0|V'>[ÆQlÞ ŠITÛe!��/Î}î¯:÷ÏÒÖµ�“aÌH>„!Û(:Ò!�¤XÐPðwVœïe ç[ØÁ�å-Ut7¹ÅÙ+wru%È›ßßépº/Ñ_š�"¥Éà¨!É-ŽDNW0)©ãBRà1zÌ{=»jñ ì— Rò“V«®�¬¼(è.A>ž€Ò¢·©àÞÆ…âKƒ:Z·7‚¨™ÿfø˜˜¤KÇÀ�BPýI¸Õc2¸Ë^‚~ñÂÙE²ø¿M8VYm*÷1 ï7Ô“m›~Kþ ¾ŽdQ­‹éþŒ—ä¥\hp¯�;½ X2*O»�… ‰/ •,^ã^?rÚ'}ÜĹ‹Tﳇ,: Ïü7½øfÔ´)V¿ ¼�g6}'L„äe}$߯¨¿¾?¬û'@zngà‹N}øÐX„'AIV™>Ï ‘¹Ãd�,%Îï8à©?‡Éº‹tKaÞ“ |šª�»ï‚QA&Ü�Þ Ôi8Ôä¢ÓÌoP¶f.º ¯¢OÇçqí$‘Uîpxµ ~`M6LÐ[ÆÁD~q1ÇÖ×r„Ó¸%»ŒÚša’×mÒvË•îóp>=þAfž]B8¶Ž(¹«”´îªZJþªû�KµK‰Ù.}6[ùò%߆)B{ç2H7È¡.NqÞÛ5-Ï}X9ÞÅ‘Ÿ|Dëi"=Cç­~™aŠ+dHŽ9dì\bd+™}®—Èû$æœ�¦þÕ»±üV¼5®!/Õtñ9×6sÆŒ#àsàsâ7?….�úGuï‰a•\>ª„»UT¥Çšªw^ÝLE�Kzðïuº~“+Ò{¨p" õ^þ%‡,(ûÜqø0®‹|±q˜qå,Zž™Yë ÜÞ³ºœ`Ûž}¨rNCó–¸[Ù”ŠmÇÅübX¯±…î28ß|þPK-!µþœ)ÿÿÿÿÿÿÿÿ arr_9.npy€ðÿ¦œ—ç?Ðï÷Ç͆EDC%$Iá}ކ†Qh�ŠŒ†–´ e'#«!%[Q´¬xŸCII‹JŸRÒT)ÚóÛï_ø]÷®sãçœÇ뼞©sÌvr“”Ø*¤·lù&Ÿ�z–Úz 3=Cm½ë7nÞèå·týÆeËÿ/>Ãkí¦åÿâ›|½ü—ÿÛë›�7Ô6gj6ÚP;Dûÿµäæu^ÃîïüVm…¨R‹»>»â­yø¾� ÙÅeÚè×¢*üÔ;C¾~‚)ÆÍ 6ÿ¶0£t*7j•�Ô­þpÔì0Žœ© ùkPÈyÜ||ጅ"%G9¡Ê¼�\n÷Â6øó†kÚ¼lçÆªíçü¹ò»,ß ˜ˆ«W�ä73L@:7‚dOÁö¾Åtïù\à�Œ&;ÔŸuˆ›$CñᥭØU¶Ž®9…B�‘Ê­›�K§îäe­˜Dpíã\oŽb¹ådÊ} ß@ÜÍ“°ê”Ç�K?½Õ掶Tu,—ˬ Ä,óFXeéL‹NÅbÛR±Ë3Š› ï Âü·à›9œº�?£?jžhra_™“ƒ?-*ÉÌR•=ªá‡Q°ýR(&9ÁGŸN¢áŸ>‘¤ ˆVæùQífÔôV9àã,iØüü&(„î÷çΈ&� Úé$;^lýWce‰'žª»Âi_ý9\Í\&Ks¹J!…iì7„Ý&¯­UB[ñ3vò.<ؘ 2]Ò˜>q?û]c‡O—'vÓéþD½†íB «>%Ò¸»ÍЙTNs÷®FsÕõ¼zqüܶ-ïÚâšý›ðøÅ7‚¿‹$Žÿ©ˆ½†vSÁøßÐâæ‡ßoäPOýy®óœ IöA¨!oÀ’ &áÕ5¤d0z¹öÅ÷�óñ:›²×J <.âÂP™�úÅŠ,|žÉ¾Ûꬂ•ê(öíyzz¿‘”ÏÊò¨`òÖßÄ‹ž¿f#‡"|¿|7kŒæiµnxGqö«��½>Ö�Tï&ø±EÕúéû¾läø†—eÛpu€5Ú"B÷#;~äkȳ-ŸÑ»i›Ñ9¯SsÖª9´l{”µP�ç9<òF+vQj|¿Hù­oŽÁñé§)üS2:Æg`éš™`•qòž󜸥|îH;ÍsÐæ_›íéïºxÞrÒ�[ž«¡Û¡/‹NXò¥½yp×-Þª±<­ßÇWÉO‚–1P¶¾„³p0¿}}€ÓâàÝBcZZ‰ß ¶s‡ÿm·/C÷Ÿ�æ'Åš_üàÚƒ“¨òå™Ð~Ï"<Ʊé•:2~­À&Y ©¯“onAü4Âúvmµ8¸7á·Kî©ýSØ¡aŽš—*¨-Å}:•ÄtZ„ïÖDñÊ‘ç!Ãþ6}WHÄ-3zqß=?OÂ�g1/ëß»–„¦3åxu¾>ܱ™vL©ÿÙç�6T‰†<ºLsÒ©R8KúÚ{y~âÞ~¾­ºÏ¤=ðÛu%>Ý.‹[s^�ÿ £Êýíøe__Š À³–¡”¹ÚGûVŠ\kë�?b'ñ†ˆX~™ù‹vÌy|n}³:º^—áâ�¯©ß5S1¹âÅÝÚÍg'.®š×9‘ãbþ‚ -…qï§C±æ 8v�³ÃTpÄ…éZ;c\_�Õ`+rP�ȇ"”øš‡›N8 úÊá‹z“xrá'qÂp9.ºµ’gÝÞ…Íê–8Wî” ™&i¾=â eîÌýª4T|ɆÐAÎrð(c‹pËO Uj“÷Ó¤{&h–ïÎ{g‰f/<ÑÇBUì{|=/Mɬ^ZîŽU©/éúÞ“°f}0È Ûç\6 SS2ÔkŒ`…ã£1÷Ï{ë,ÍùܷƲu!†LN¤âeh8̇3.Ïå5Qúh3Ñ ÞÔߤ]Í%¢Æ5=U„b²3’°žV= g­7±’H¥G&ðÃÐ)BïQµäùªƒ®—ß‚GÅëqÓÃ5`b÷T8ê3�ƺgºxNf�¾m‡–Z�ÕÇÝP{ñXÌ—œÄéYùg¼£�C¼ùy¨O3ùCôúÔD¶ª‹*“« 1C hÅ1ˆx8œ†êâµ™ãÈx«x¢. Ë>„‚³çva£Ç`~âš‚ÕéÈi™%ä,F#Îå¿ñèy7Î^)SžÇ�õé〠K�xgv{}×½¡(cÝa'ƒŸ£: zT~NYȶBŽpãÉ$v뛈ß…²}pòNuN"S³A÷0Ü n «¥Ó-Ÿ/úBWÌ&bY°7ïh–æf‘X¶ˆ@¹5Ÿ]»åðrã_±¼Y·½3ækJ1‚ß7eäY›èýÂ&:·ô>&/˜c{öqRè*¼–-<ŸÐ- Óež~îT&^!u sîו‡öâqZ™ÒN#L—â�K†xS/P<´| 5æhUÓB«Öã‹‚ów7–ÍëG�¢5ãðñ”%¸!C–v RþËÏòíØ�ŸMóþÓÅ!OaZD“p¿3 oøÇñé0 ¾ög/olÈbCò¥©ù¦¨®Û#ôÞF•I¨_‘Êq i¼%À“íߪb}OŽ„,®pÂþ½ ³z)ÆE˜a[¸5¦™öFAy2w§,ÇÚ¢¶Û%–»I, ·Àc}Yõ�gq‘Æ+±ïHƒšc:`ǸÙb‹Ûnôp¡ú¦ˆBv0{¬9˃ìx¶a�©+ç/;×U7ªjÑ“Úv|^ ‰6ñxrôV´T[Hïï^€gÃCyÊ;Z(г”ÎÀÖïå\ü¹�Õ:'°Ñ‰4(xÆ^Æ«‡,kÀ»‡Û(%îýNûº‹R8õÇm¬GÐæ~”®M¡77âDýëÕ÷GDcæš<½y½¸d航ý.¬j�ÁÝ;Púk!z•SõGNð„Q EáTdßÌy†_£ÿ«aV‡ÏCíŸxï^—Õ ³o´Bžçdºðñú/tQþÖ¿ëg-“ÕŽSGÝù½„EÚY?$‡Äz°¢ÅQÆh¿³<¾ª¯…3¯’yÉdWð2X'$t×Wõ™1ýë» _§‹_hªÎ¡çâ ìõP‹{áY^%�¥ãW㕸"œýú}žaÆÕW59³ó Ë|ý »nžâ[V6hÚ»‡˜ó½Ïü©Ç…¥FŽékÿQeêU˜¤ò¥z󿾊�W§�†íqLÈ êÐÄ×ÇÍñÊÝ«âk7ÛºéŒq çN7FãÔ©�œ“Èo.øðvÍ<ŒøÑR}o÷*|ú1�Ÿèl�ì€ùüªÑ/Í%¾½‹‹²'ß!çÑ¿èëM~+†D�"ñ&^ÓÓ#`dÔq^Ùß‘¿ҘəáŽÜ¿|wõéS³¨-6Gï³ ÃUtð±ã.:B–Ÿ�šGmÑüì0Qk©%n¢Òà\̳öç‘Ñdj§ÊÂ}ÔÕ}\ݰìˆ8¿çouÊ„m°Å+ƒT*Àòa½t.ëM=]m·:–uv @^¶ò7ÔïŠ)å•âžéºä´Œö�^å!í÷>þø2œYHñ3•…X2Çš•Ÿã®ð?”¢7K°ÏL†¿b!4hX´"6}XÈ!ŸÞÒöÒƒ<äFý÷kkÕû€Ípq‡ŽÐþÌ�†æ¬ó(cX<èeÙáÀðÐØ´w Qì§‘G3¬uQw«6_óžÆ›§¢Ç»±T°± ¦Ïý*&·5P@t*T×¹ò S¼â8¹ö¢Y'ŒéaÜ 3¹Œ· uu¡OôpüÔv‚-Žê‘W]–ý´ÀÆølr}?„ŒôRyeŽ3¸ý«Ú¹XÂÚÆõ‚øøþt0ÿ™D¦¿-Pëwï -Í4õáBè#tµßÌßÿ÷¶ì”Yei:v ÆJ�‡Ç_øñ´0.X�#ž0H竪ü ¹–o©¸açT5k¯ùO…>¥Óihí^þ¸}—¼ońճÅa³Šh �w¾¡Üµ9PÖ}S¼tÀ†ó_xò§Ã�ô[à‰Õ*P°ƒÞågqÇÅx:lãÍJ;çð*—Ôrj-^|¼ƒ#n¡ðÅ+PíÙ^LïÛ@/FšÂþÌ�PûÈYô¼*ŹAŽ˜Yù~Ö*�ŒG*¥W@aåg’Û"Ã%ž3°Ò«“¾j‚‚ÙPÑ'ǹX7"Õ0<Í^Ô�¹&¾½Ö ÿÑã#ötv¼Þ‡‘´ÁknáÚplÇ(U1"U_¸³T'‰û¬6ó¯ý8z¾.Gž™Ê‡kRôŽ"HxfÂÙ¦/Å¡·7À\Ýþ¤9lëÆÂ�53ÄM{êiUrž_¦‹ÛdHÚh5®¸·®yçÁþaï J|!Nñ¢ã5 ”¼H}Þ&Á§<†ñ¿3%¥jnͧœÖ€ë˜Yœ˜F`|Ûê˜e9ÕÏyERÓ.ÀÛ‰ °Ö“ììEìiÙ‘VOhÌèã\:¨ävÏÀ¿ÎÃ� {éH› \˜ËZõ7E¹)�ð'k©¸Å%U\ê…½ZÕqm§–æHÒÁ]Gx„a-€“3vï0À%·²ÄK9aԲ߈U‚cyÍ8mlÚ�›î˜à¦åëñežP]fÆ-6ÓʼçÕÓ$ÇãOÎjÎ×|¿B~ú)øõÍ�uÏ”�ÂSì¤ûxöÕiÁ*¡7†­Ž‚t,jsǘÃ'àŒ·„ ãÐ@îI}¸`§Ø=»)ô´’‘Ù-°7 ô§i Ñž$,_:›ÈG“*—»sïZ�:S6cû±i»Ú‹]m"ùÏë_Ð×,â»·‹/ÖÜá)]±0lI8×h !d:�5xÊ19ª¼`�Èù ù)<ñÆ^±kÖ nܧŠÒ tÁ}+ŸìÃnN[ñü?±£×_Ê/܇ËÍŠñnü^>ýˆ\æB%óÕÃ�)-p-í ͤ¦ù6`‘Aðcæžp"Õ.¯£áÔÁg“&zgŠÇMÜá£Ó+°´ûHß ¤) ׎È_äÓ¢7o9Ww^ Ûv¡î™!,q¹�v[YZMV`™¬Ø÷ä'(½9�Ù QÑØP<ô¥�{¬€’³{ñ£=X�ZÁ¡›Sh˜³– "/·ût|qÞö4uöh⟆;Õƒ„tÑÊD.þ¡³A1üpö**ùî�ÝFþܨò”ÖkÊ`ƒa—·ŒÅÕLJ lù?¶ýVÊ{jHsÄfª Ø ‡4¼ÉôÕžâ%Kº]áFÈSò O�Ü®Ây©!œÚSÊNýgÀ�¯ÌÃ>?G‚ZÕZ6�FY×Ô„Ÿ#tz‹÷l3Æò“ÿ6òô1zÇCùà×&±.0Æ*ÇÄ›.‰ŸÖŒE�½bÏ„>Ø5ô3Ý~&'Ø=M³’ɽÂ_ìû’8áC·*…Ñò‚}忀9'‚àâ‚lÒï|Á^IbS¥nøäëÜÝC;™¨7ÓÈ—~¸ÌC�%çÂÅ�ñxãJ_Œ�ÚŒnCÿõóÎì¯íN!^'xÐ5iL}ˆƒ‚'sWÛyR$3LZrJèJÏf[¹6xö•¶ë€çÏŸ qn›0ìæIÎèÙå=§ eA%ÿ�ÖÂBUC”|wC”P[%dWŸº:q¿‚F�Ž�]+Â@þÅ(æ‡o)¯UþŸ (ºDÓRx½´Š>kÏÄ]Ý0÷œ,lv¶$÷Ù¼Ã1V®œ(„›§ÐäroöZ‰7$_ˆã°†çùEá �i8cþì�á ‰�9 !qK'.®XÝáØ�¸|I,Ï ÌŠMy”Þ:“Ùì@3ù—Tþî›øøi<ßòû^}º¶Ö2|YlU©ä­G¥Ñ[7—…81hMî/�‚ßæÔÃÕ¼gôGÜ„¡â“Q«y@ã1Ö¨x(lYô]”Ì®åWíáDR½P.%Ž?¥šRGç'Ðh\ÀFýÿÊš‹±Ò>œ¸�¿üót/ÊòèL)@õîp1ãV¸*<#«É#q֙̋ çNÒ(7T‚:µqÝö¾³°„ïœY+¨Û›áÜY®¬è¯Â#Œ|qô.œ¯ïФû‰þ  ùŒ9Ý›Ç-¼C_ôáæºÑÜkæL´êXíxá5Þ/QÇü¹³V—ööµ³Úu:SPxðOÿç(ð¶Šr¾q ågYâÿÐ<Ÿ …{~ƒšL+ù 8M:ª9°Ô»Ò«FaöíšØÛ�ŸÆ¤ÀC§¯Ð|{6GËü¦WO“8ìÙAT«ƒÊc:„Š‘U�6ù¹2lçî"“+±jk1æ)& šRD\b)Zê´�Å™ß1r¯$&oõ…#¿ÅB‹-ü7m7>¥wº>�ýå¼­¡7�Ñþ+Î]ú†&•ŽÁ´u…ä·8‹54#9fód¨ö‘€éo`êÜ"*°PGÉ# ò|3äD Á2Ûa¼Êé99O°eÍÄqØ4÷DÝZ[/®ù; f ü-Áž|ºFk”¯¢¶pnÉ‚ª¥é|�±jcyýâø˜ZŽëΑ‡R­à‘”N^¾Áj9ºib�±²{ãaç�©tAåä wÅÝ|L6WÔ|Ý[¬þ³”?”xñõdÑ ý876¶RÔà`šÑ{'7›ÈŠ7·¨ñ££Øð��ÿ>Še�$‚�ø†™ÆqQÑl„–“ÇqÛñBJ0tGÇ)IÿãAüüu Ên\Èa &qIú#v›áŠáûN€Ã4Kzþ0GŒ°I@™‘°ÔNn!.Ÿª¯ ï.�e2[‰gŒÛ”8ºdàÉeYïɶ­˜æÜ»KwŠ™*õ4Ôí…8øÙ²‡ók/ñÖ^M¾ä«ZãâÙ;³Ä‹(|pŽ)o]>ä¾³ÆyZ®Ý<—«Oß“ª*å«ÖfVá4Ë`Öi€¡BiÉN£{?äøN¥×[xðˆ¶[|¬"†^ F#Ë^¸G/•sú£×u¾Vw‚z¾ âQ�²˜ößÔ7~/žéÃk†·Òµ sð>gƒSêòÅ_{z£ÜF/q™o+˜Þ“;€Å'(ÕožŒ8ž�s!ÞÚ T<ÐÏã(K÷ƒ™—59ä¦%ŒÞ�í#¨SÃŽçÈg‰£µðëšöê_QÏøÈ·Ý¼,R•;ölD·SÍðêíi+Ëõ«…?³æÂ™cÇ¡}uÿÓFÉ«üpÄíI<Ý|24”l„9=Þ_P„’ mÈõä`aÌ|I\%ÎB…ô3<éÇ”\ È_îÇÝO2ñG³"Fj��líO0°­Äêà3Y™„8Q3³áa«7À«ý0Ñá0ó.ü§É-¥øÙÕÁ|=•ôÆP�W6üJ?ƒ‡H°úp¢ç#ÂÑtÉáêSçôñt®*/Y•Áƒ5ßžM£ŒfütÉCX<¥A„¨äe]bÕza&Þ»]KÛ{ p¤ªOöŸÀ ?_@Ý…]¸.ý0ÙM¿MwÅbØfœveVÿfC·°I§—´ˆ½Q¶öH:n¤]ÆåBÒ‘ÇÐpø*¼ì½_‡šîVhØøƒÌã/òj­; à`Çm÷³ÐyØwº¯£LI®ê¬³l ÕÆ?‰c96î›ð›�Û„º‡GÄ®›Zè£ šÇ ž<¹ˆ÷÷Åø�.8î–}ŸoÊ›\*-–„ ÕÅ7Iýé¿¢+ŽØ²Mrp#'rvw îÿ˜h³áV›ù {–jp¸¹*ší¸(>)Œ¦ ǜĽãiAs?¼w~FÓT#yåN2FnñG}ó6zêtfŸ9ŒÒã qï—c–�,ÁcŒ D$ÆÂú™áük^tó#vý¡~ áfƒ>vL3äÝòg«¿þgÎЧi•›-tÉÉàïá¶|6ÿ\ºšúFq댡p¦`¯å¯C� ÔG<õZ^ñ–³‘4¾«Zf\|ÿ祎æ.-§_–ànx4RU1©]�†Eƒ=‡Ž$«£¡g@É"†ÒçÞÏÿYÁe“Ï@rÇ^JÎìOËÖÒÐìxzi‹¥yNúWH<¡Š#i-/ ˆÓw¼Ä�ÅŠX"ÛŸ?vD°µ³ ^^!‹êφˆy _°ï‹$aiRìUñàÖ¿‰`00•5æMcÉqï„?ª1Ø(ç¶4^Ò[“/OÀUé�˜ûD™�pv,OüVFò“ŽZ~ ý�úkijä‡.±yK{Uìà$1Á©º·òdHSWß]\›0FœQ·ÍÇò…9äÝpàZ4Œš™ÎÛžT“mk=¹£OØà£ GÔ9‚!VÕtýñøã5¾»G ƒe1wÅAV=3]>; ý“0î*¿&:9´ƒ‚ó!Zrb-ô�‹¹-pâ¸&¿OŽ“ƒÝ¹ì�*뾟…iÃ{蹟z,»CW˜“J«&ŠWBàÊ•0²Ôô´Ê»wÔõ› ÔwO/r€I54éz¼Ø¢+ÞÕŸYÇyÔçô¸i&øÏJ€îYùà'³–^eE’ÍZG^j�6%Iä_zéAOj2=lœÉï•TØyÆ0ÜéF#ã^ Õ¦‹ðr÷3¸VµDÔý&�J—wÀlïÔÑ�Ü—¼¥ÐÊ4º>Þ„� øm½Ý×PÄŸ3áVñxœ*ÎÆžQdt±™':°?ÔSyÙ(z4¼FØ•Ö k ñéAØOê”&”柂³ãHÌ9dˆº{A“ä:wý’ Ó?BÜï›`åd]ÝãªÏsìÙc4§<‚WM›Ë{¦®ä!©[±Ðì>”ŒÝƒŽôPGÐSV/¯#i=Ô?|�µFóëÅUô¥u?? ÇV ÙöĆ:`tÆ14W^‘ÉR|ÿX,ÞÑUåQÓ¿ÁñÇ4¨"vHQ{«*…©�äûÿ ËTäyvùÂt©$ïi�GG8?�=™äý¤xF‹7™�¢Å�b‘y ½mMÁ¸îs$–è`´ÞL QN¢æéæ±�ÀG1Ñø½ßPv:±ƒm¾í+uX.ë$ g›Òñ˜tv7 RýOŸéã1)E ;…Ò¥qØ(i|,çÉÉÏÆÐÏþønå~˜§Y�»ªšš}’0¹"…ëñÆF�þ˜+ܲÃõŒ7A�Ê[��ùE‡� «ÿ3~·?Wܧ¿�'L{ Ÿ�³¬"2Só«` òHÜñø¼pz±½à�<ßë™Z=û!‚jåTÖ^<‚·¦¤ª¨Z˜~²ž?Éé’›L4/Ot&ß�ž4ï|K| CÛ+U Þ0ŸDõEýåŸDG9Žß¼–\’M¸>1€÷–ŠöÆ’ìùÕ²ç�ˆóÁŸ¶.ôà^@g/,JMá¨~ù�àã�G×}_‹:Á¨û�•Æ�wd8iží„¢ª%è+Œ4~—ü$xì©£8Ì*_¼¾#~íl¥iré�ú š¿»òޤàÉ*~_Ô25ÒézÌkêÒXNÒùghV�L¹à†]'œñj¸>w/R%ù(sžx¤ξS ¿~¾¡ùvÛ¥Ÿ�ô«9Vª‘ŠüþÒ%~~)þþQàþ®]ä¹­7/’½S­2¬pÓ¸j‰µcãy¦´?©¦*aWe�ªƒ¦šaÐ¥fˆ?¼§sAêVš0/mócùh¸;y<.õÈjËØxÜ¡`Ý®ÌÕòhCã Ñ"-‘-êx“„ ÑåKòfñ ¡ßé`‰,oüH—Š_‹¹/"0fý|äßWEýl#”? %š¿Ž�ãè¶öj(íÕ›BÑÍuȬb�³)Xp\»gØ/hï+$ðú_÷„ Å>ØïàB>.Á™òhø?íRÌ<ûbáŠÙ餼å ¹V|ÌÃ@NÂ’×çvÒùOÚpþjÐ×\ñä#?^’aHr;}¡Õo2^ç�×÷䃅±!ü¾ŸâÛúQ¯nØbÔ ‚~¼$‹˜³bÀ´^0KÒ[ð^«�ñ–ß߃È4Bꦱl›�‰² K>�ìø¥¬z‹Ç¼¦\/®]LIâ÷O¶ø­%“LJ@ø�Éj?” Šü!¨Ä‡î¸Ö³íeohh¹‰>3ÍDÏŠõd¿À ¯|œ2®�xgÔGqnñ[ß·‹3CÆáÍsÚÔ#®¦ù·Æ‘Ä›\¿J˜sý4zÂ..uà^†U;†aÙN'Îìußoë†e&{IxîË/‚¹¿žòsá­�TkÕÆC§Ñ�Ä|!a�Æw·ToysßÔAI“¯ÂîŽBÞ�³ ‡\�å·,°ú˜_y§ «š±íÅ�ýƒG¥C`ò^ºT«ŠO¾<í0:36�+K£8Q½RV›ã²X'^[BÇÞÇî|”%Á�žOÆMîQn¿�0æuª¥Fg77m >ýu¸b¤{ŽÞÀ½âäî½tyë2\»TGúá Sðýôvú*£�û Z~Ê—¢rVLš’®Œ±^„™³7QŒî+j©sÆ—i�«[}ÿRÕŒlê<ßÕ,~ Í“³Óƒòûôá½h¾�îß->ç6v®;ÑCg¸pLQ�˜vEÁÚUŸèuÃ?nTÒàê” ¬ÝP‹MÒŸáVÌSö"2%Áìüb]r6^1m<¦-À"C%Öùµ��F‰5¯'aaÄ?¾ÙÁ“¼ ‘#tÐ'­>L½¾çZX¸vI´0ȆµÛñê#5¼Óäk)¼›�3_΀ÍO醱'÷d@Äíó03<œv¢÷Òqè¼å¸UWa~y8O¯–Ä� J–wOÅEz�à<)Ÿ »– lþ9ò¹·ïγªÙu ·®@-o¼±ÿ ëô®À¹‡Fcÿ {Ñ^º7êË7Pî¦ |ÄÛÆjU’+VüãÆ¦{)ø£õ|Ý3•ï¯:™¿Ÿ¢^?6Ô:ª÷`¥–.¿äÊûg}¥ïe¡øKÎÍð�…Qh$kÊ;¦uÒóOú0Ý"�îûð©Wu�"�ÜçÊOá~f)i¸/â›·‡²�¢ÎËò$eM¦1Å“éë¼F ²¾3užS¬I"&î{+Tl¯ú«2ü)@ŽÙ_ׯ4‰ ÞµÑÀöy�wº‹f-xAÃí_LPà~“Ú†ð;¥¼ö�7§§ÔƒÞÁLè6Y„ß=S1#Ù‚3Ÿ%é®CÌð^Üýß°h(¨ŽTUà¹OM¡ØûžUï²2Ò Ôå­zø]Ñ^—OÄV‰t~®žQv{6X¯Æ§“ŒÁÏù Lx'Å}¼k(Nê:-Q׆E×o’v_U*�ègétÄÓÓ"Eý��kж}b@H=GW5¹9èÙ÷ø ËÕ=á‹·(¦ÎØ…¹Šøxü%ø6O3ŸÏ£™“0ïqí´M˜‡õ ªOÙIZ;ïÉ热Fmž Êë×b¡¸…ŸöäZ}CÔv¸—Ì3Æú½°r³#I¾Ð‡¨„'vÉ“ËÖ¦âµ+Þ°c¿O¥(…xÊ[ �c$ñzï!<¹âY1›åfÚ¡ô-Cì–”ÇY:Xð¤²ÞÉAo¿QX¤”@ù9ƒ­o.}Cwï…Û§}IýU<�ªû½³'÷üÅÂâù‹ðŠñqÜ“‚C�§sÍ>9<XJù ßahÂVò[�2hŽaI½±»£I,¹¼ ³›§ 6ƒåy´÷|lP ×CM±c€5ž2~n¥5p ?-WCnÑÕ(LoØ:ß’MÓ†b—M-Iš)ài«yBPQ-ÖÈOgÝ¿èuòѽuû�ê…÷BsIÃUVšãkü³ªJ8;9 <à ©²ÜçŒD ‡-U÷+4àéñY\–ØÓŒ¾‹©y:h•y�´ö̤ÐÌHaŒš+®Ø×ßo�B¥µ"+¤`ׇí¸M§žt'ó  :õ¤~>\Œ#5w�©üNd�O…K¢pýÜw`=4‡y,eí–O°ì¸ý‰HÆ�’Úàù.mU·ó…ØCTÛÐ�Ñò¼€X~»úk¦ðó{Áü¹Ê—þÝÇ�z6‘»„=o“îÍU‹�éãø¥˜ñå84¶g`«Ø‹OOñâ™o–²´÷TZP>—Õ¼wqçðu`¾½?Ôir^ý*<¯¥†16añ�…(õ± ¯9uPí ¾-þO«†¦³i©®=æ�ÂŒJPf½º…8cï—óа؎ïµCÕÄ\NžrDpyTÈ{K±ß8Àî“Õ$õs'Þ9ZGoÎm¢B­LpXA=¢×Ó�âóÕ Ðÿ­Š ¡ �‹‹òª¯õJ„„÷^8<õ-êP½.$� ¯V‰ïŽØâ’á]´æç%ºRSÝvæ¦xi÷.n;‹ÿ‹Ÿ�‰ùÏëáºj µý»kVKýmW¤ ÞqPññ”œLƒK¤¹iE©õ7ÅÚË·Q¯÷Z¡Ëw4ïpSàæ´côiu S—Á ;“ÙÃa&þí �–cÉb3�éHÄ»;Vr/?ñås%šÑ¯œ‚�Ãá¬~ð$3‹M NÁ¸µŸáëì$1(¸/JZHàïsƒèæÚÿÀ¥tŽÕ£¢@¡âð討Áí:*‚Îè|þ«Âßå*«lf'Ð:ÓßX֩Ÿ]¾ÀýÛ�è¡=ŒC[ÔAmlßÅã[Qwx$ª¨E[yQ¾[ ×yú°}û1²]¡‚Ÿ�âÔúÒÒ�„_[¥<€»úÕèøáõ}'�E¨ÏU}úbâxw„�†BLÍ*^ŸtÒr�ñƒ�Ù´ýWhÉÎåt¿-8ÂD'Z<¢™‚'À;ÏW´Xþ�nüœÁB¸uœø—Ï�^ðnß0|éœEÅzßñÍóþ,Y’P}%Nö¯ïƒƒóä��ªp̹W$7ÂUøÖÇBÜ“ã/L5ÐÀ¬™ñ î-‹®6Iüm¥¶¹6Ã&µ-ø¼Xl7…‘¶¬"#ßⳜX±Q쀫¡õ–'¼Ôö)îÑy)”ºÍÇïǵùj÷œz/ŠuÎ?‚èŽt’Hj'„K°Ó—�µ¾E²Ze•¨;¯ðüi {¤³zsvM?+LÝ\‰½'Ý!³¥ËðâU´ûr•î>É€)§§Áœ`s¸6g H™>ät©ú˜s›jª®’na/Îu’8¨–^Õ/Œ'æ€Çg_XSåfemœ�Jƒâ`ÒÈnqnÔ'Šüó„Ví¡ƒgÎr©Ö(–[S-Ä (X]¥l;슚ŠW8KѦR%þ,kå•Þ?‹égÅw0ÛÑBÛ&ì¦û+[Ù6M¯ôwä-×éžI« áys�_ßDª¸¹‘Öe×£ÛÆ"\ÓŸåöÅøö@êgûW<´E’/(ËÒî—öLYñÜÝÎêHù©€©Ã�ÂÚ‡ƒh÷þ`\ùe8+O3¦®½‡Î):J€¾Æ\~\8k(‹ÏöÒå†òAè|'Œfoø.¦ìꆡ~5Ä?Óï+ZèÝGã3FC”qì|Ú�ƒ:&Rqä3˜]_ § Çcvßi—F'ÝÔl‡y]8Ziœ’˦»™Ñ Ÿ—+vŸ‘Aÿ¼ÓXRëNêIƒ„_F}áïÃËôyü9ªÒá=é�´zö3ú�‡ÀßŠì“ØK¸rÙü}4nϾoE¯æC•özòÏÝ�‚¹Æ:änô•’¬Ïˆ�”w’÷µ‰¼k�ïð“ÄAûuðvþZñù£¨öë�ú™aé©*’ĸÞ|}¡NËT†µ7 ›–ypà®áÕ×ݵqÛå]ðk´‚ð¸:š`ù_zš—@¥¾è<ÿ®¢¾œèIX‰±7wqòäOE`ºV6„ÈXàÄ%Iì|ÔÞýÝN’'&ãõpëÉ$*ø]»"sÀñi=XÙLëÛÖsÕ„x6­ãÃ`èô�â÷÷õø“êÐL-£“jføâãJˆsÐÇ7²ñöå�âÏ.3nËé(§— Ä~*Éôµ</W÷]~MÓ†•ÓPÏì½? ùþÁu>Ð$…Ÿ¤ªoç´³Ô¹�=ˆ‰íÕ•Z45(V.ËÆù R,ØvÑùËÈ,È-V(pÚ¾kTõ%®¼Vg»�ꜞtXŒ§p¸ànˆ¿Sž¥7K¬Ý$vN¼O¯ñ!P¸mx�;mB°<8Ý&b…ôCª»Ý——åjáÒí³9ïJ7d,Sãž+?@ñïWx/äÏÇÊÁ}}š¾{ÿª:È+æ„VëŸQÄk Çaû¹2pkÌàŸfÅVÅ7¬d?ïÆ—žÃqg~>SrÀø·›¬âLÐ$•ôe›»Õ[�8 >úÏg»Ÿ€ÕÚñ¢“Å~LÞ�k”'Ã]Û´ÇvØ|Šá_-g©bƒ$(ÖyÝ+MZÁã+¦ å�®Ò%õ°ê® Ñ«e!íûœ‰1‡Ü±f¿1ÅE|†Ã.½¨S+œF~�K&LÄ/Ãþ1‹“ _OVæÔ°! dfCéCQ6p7Ì…Òj©BΖ�¶}ª>%‹5»a~¦wÉý&³M(Ú´ÿ—ñ�/wa×xt �Ýr iôEú±f?ô›Ý‹r nŠm8‡ûÏj±ç[Þîé ÷ï†AìeqÒÑU<±JW�= ƒëM°ßýHÞßA®nû ö¶"¶µÃ…ÒkÁÐÏÙ*B/€Ëú)ãg÷@ÌÉ¿¦¯÷rfÜ…ßMIãLl‹°fn·¬êŠö‡×=›àÀVYüoŽ)þ]¸‚�^“gŸ�oh½Þ:Öj„'ŧtOY��®v…ÚûÃðËÖ¢6=°A#›„j·ˆv:r¾’­ÚÂ�neb´“=gΨ†ä©T줈:—¾Á©—¨Tr-«zd�Ïç�4¨{%ܦþýÞPÌöÿ`ÀÄÂܖ笼‰ÂÚ·`³ÓvZ=ÖòÒ„«Õ¼GËt§�BŸNð\™ksÜ(Ä=žÜæûräï¥0ó”4¿¢WBAêN¡rÙG˜ä§Ì·~_·î]hsv;¸$´ˆÙné×+J½7H̸qG¼R𜼠P¨sÅ¡‘!|�•øIŠ!¾;•ªoVÁäUˆél·.˜ÿk<ƒ�wöðž§ÐwÜ1ˆ¸u ¤¾v’Ç£TT®ØGssqßÂÒØ4§*«£Bíì¹öZðpTæ˜ÅË0`€ºµÍÔ\8±® ö´S¯R+”Ü’�o?7çY«t]”¿!øl[þ>†·9ØR†¦q‰tû™$.ñ³ç?MžXÕñ‚r6Œ2n­D‡z]Æ{'E›fk^ }yÎ=lLÆ�{&ãÂã2ÂPé•è«©Îû·…zŽ.�¸=Ø]pìX€egoÒ«œãtMá=KAS©£»O$êUÙã9O5T˜ Ív…1|È|®šãÊ–ùq�ˆußCŸG ê¢D³WƒHíG?ür.yàÀ&øÁ �:?GŸu’­qOô1QeaÉ;^ÆžlbôrèÅÝÁÂϱÄg¬qüvß&SÄYmüØ×˜Îo}À…&2¼ o)Œß¯�šîÇxká á©ñpÊMK#©;ýÐ¿× |p?›V�Så~#¯cnF6ëÎ:Œ l† ¶¥pÕ-œ&µÏ£ÿ  ò K:·öØ{1¨÷„ò�öñ¼h×g1`ÿ44ÌÆË+ü¡Ÿ½„P™VGVêR—‘–�ÆÉ. ø”¬0¶Àãî+ î.BÌœ üðr/2y|—–šL†æ°l¸fà‡§]\±~ëI@7I¹#�mÞØ`Ÿ_ Ÿ„ÛÆñ‘ÏcxY�7(àµã&–«�þBUÓø–yŽÌú7T3Y�’'/bH§&ÎuüDR&鬕�ÌrǽÀ®Òœ­CŽâ4�èíÒNY´ˆKÕ…ã³µp¡Ô ^q‹U.ÜËSzHåÛDžÓðQÐ]EÝ-¿Á+PžÇ� Cs¯‚¼}!è<ÊûoÁÀ·ePå Êw‚ 訃.¼6»A5™BdÿWÂâ£áwÂqðKñ®… ·gáõ¡d =‹Çüw×�à^*ØRt f¨Ÿ¼”5q_Ç *>/¨nãù4z)Ô�; Ùñ´öþxSÓAÆNG>ÒA�µ'0·Y‰VÒǯQQT^¶¡ï‘ed�õ‰¢•ÖC½k"jLÀ ™Ž¼¡óØô|£Ê{O¡ðE.Ù(®åÝÿþµ~} ßo<;GLdØŽÙÓ_‹ù[f±éárKm? ¶�:)ÇDajÚÒ‹Z�¾Œøuq7º0w;,Òà¯oÇ Ù½¿PÝCt?ý„fgXóêR½K$Ü{ E[)¢É#|® ]&ãŠJÂÁ·Ê "·‰Ä­nðMï-œ“7¦�§hO×}øáv©Âîú*üõC•î�·  гx‰Ëft·ƒ´e+ÞÒ Ý_ïE½a i~Æ?&í¡¤å&œ¦æM?åJinÔôóÞÏM‚Ÿó~þs¥üò°Ü·Å¢a¯D>²f¢A.Ô†mæ®Ø>ü;�Òz¨óºÚx>ŽOW˜@JN½LÒÁɾ™|±!ˆ×¬ùqv“„ÅQòhV•õž>Øì­�Ÿ‚øµ¡6Ôç³Ã—@ÌøâÜкô}Šv…�3™‡Kà•ÿYþh"%osÜ1e :cù4L¦®ÜøF£ûëñÅkÓXñÂ`îÕÙ»dT93N 7ÇàÞïAœõê:¬‚5|aÜgÚem�c‹Ò9�Ët5³/†,ö„7³†³ÅÚi¸hD›¨¦óúqò˜»Î‰õ�¡wàÛÕFìX®Égd¼ÄšÖPËL¯F±éÕ ì²¼%œ)Uƒu9¾è¶v½ØØ©ÝÐ޲òQÿúJ8¯¥5© i]ËÜœÓ _¿˜ˆ•�ÂH3ëwÓ$wí,t"#z˜�ÁÅÅ‚xâ -òîÃnþ{íÉë¹ÍÉVt…á3å¾XÖ¬ �ZÙ<Ó¶E*{ÿ´0é˜mÔî‚Dö?ËÆI7 ͈hÅ!çf5�Ñž_œ–ÜUªÒóŽÒÐ#>8öáqýÙÉ´÷ÛwÒð £uWpr¨ ¥ZØñ"·‘¨Tí&Nõœ ±ÚÊu²Ò� ò°û«Ä—„Š~cmpÉèµÓ7(¼n.dGþ&¿sóiwÓnÝQÍc®Urm¿>üܱ *~œ‚îç/ðº;‘:C?¿› &ó>ц}«Ð2Ɇ¸|ú-öÆ ÓsègÁáØ²áüöa ey-C×î“i¡o®¼Õéq?…¿WvƒÕ§¯0pýpw=�ånÖÀ¹„‡´ÛaªiôÆÿºäaÎíã¤9°FH:¾LƒVòh™f©vp+È/¹%œ“íUyf×GºU艊–7¤–­ÓøÝÏKœ¹þ:D‡DÑÕ¦X¼Õê�}ò/À¯“X}\œØ<Í„w7/ÂÚá“Ñï^w¶z Ð�OªpÎ`-þ¾ØÆlM£�{7Ò€“c¨îmjÝôçMn’YõQ¸r9?…LÕ÷j¡P=�…¾ûÄ+³Õi˜l §Íy _~Ì�~²XòÇå>~&§�“ú‚ª.`î¯nPz[“µÆŽÁžÒ3hjÈwåÈi}åó‡¾Ìö¯”è7\B'‹»3»ñïgûa®d Ì7ýE[ði[yÑ8£.)gÛᙘ½~(>œ¸“:w¥Adúy˜·ö7èO? #”O±²÷1ºÖ+ŒWv_*ì_ä‚ f?…«?�÷C÷OEC+ ŽtZ rJ]` '‹ë#òvÍ1”r±NŒè¤ßW—á„Ù¥Â2å7bʺ}8½Ç)Üp}!Ô¥6Óñ�,ŽVt„dëKBëŠ`Îý®ƒUÞ+±%3Uà£r|T¥“fOžNsÊ|`ƒÜNžq-�Kƒ0,ä#ÔÞ¢õ¶Ò¡÷aŒ^ :?�Y¡I–Ç�¯Áç§=øæ7¹ÊTx¦]°QS|ö½�ëÜgá�¸j³Sä ¯¾Pçny©Ùˬó@Á>ì…tSX.)[½''ßܾõ3YÅÀ€ ¦tèAÌáîàÞ.ƒe²u0ôÃ$lùhÈ‹l,ièíÓøô@_É+ÙT*–(pséY| IhÒžA« £Ö–˜€>“çqÖ#,;§ÇÁå�æUáœk†V÷©qE8ÇÍ Í.å¼ñÚRL±SÃÚ†EBQøiV9¼ v'Ï�…�ñYü<3O¦¬_„}Ïž§ý¯PÁù{ôàu´ªŸŠuQ Ÿþ8Ca¼ÓYA#SoŽ÷Á–ÏñböE9ðé \sã³Ð˜¨Á¾Dzec8wg oè¾�ïèê°l§Ù ºiÝ幨a.ñüÇIï.H69I­÷eÙú¤%ÌÊØÁ×5æanÜ1Š)¬‚Ž€j÷½Ëg¾Ö‚�ª!ŽúhÅ“>‡Z\øX"±ì‹aÙ·8í£#/Ú~=ÄÑÂ�Ü9|vìpIßúBþ˜b¡Þy&å[ªcµ9;f««Ð”_ àü›AØ(¸ðgåªv*Ä%ÍCIt ¡b½î˜¡dÅ9­Ô5ò‚0E»§÷I=Ï&ð}²ŸZzÄðœ©Jè±cǸÙBý¯~¨¯ý‰¾ÄÃJ8,}*ç̱Í…Ù?öÁL³JRI—¦×«ÐòŒY¼óª3G�Hâ ÖåýíhÜòM|;¡õØqäÛ�A¾m _ȸNŒ+'ä‰Î¾ƒÑë{4ÝLñ¯ûeqÀ†1fxOŒlKá†À™ÜúD•Ÿe„I¥Nà©ÜUÿçÍy©ÀW‡ã�G÷¤&M Pô!“{¸õ‚ò”nxôåÖ²�ë:¢Á sºZ•Mƒëaa’oû°LÈ©M¢G[Î «žÛBÙõ†ïyÏίÇ�ºg§?ÌËú.áŽûÔ¹ü ݃# õ™É.£SŠã©�`�O¿“ß+sÎ ª=2 32Y7ÂŒ "ìyËÜØŠ/ ÐÛ£™„´‘8&ÉŸ¼ê¡êd�ppßWš^Ÿ ·–[âPykRëУ?Ç ·ŸvÆ_Á©úYüôZAâz>mrÆÂÓ¥žh‚okF Yÿ©âî»Jhðb–pïP>M0¦ ÷…ܦ”‡žV�‚y Nøj…Âß‹É<]»U*›ú¯·ºkAÕ—>ø"=ƒV~NÄŸaþ`ÕU‰Ã÷ó±ÔhtÅ6q ÷(v–K£´WZä;þ�0%Õ½)#ûÆMŽl_ïÎKvô �“¡bèc2ÐÑ•—MqÚ[+ئ·–n]vsÊŸáΔ Ñøþz~¶w7ŽÿD+ñ•ßЭTŽ$ûc`«ìsÉ–y’w ’ÅÖ¶ÛåsfO£3ƒo’׎IØo@)9Î^Î楈¿ôà‡îÕ Ó–(8u…@ØZ5 ¿²t—©ðçŒTÌY�ºÆS¨Çˆ!ØÕ o~MÆŒwÅæñ!­š‡Öi‘B‹X+Úžˆ£rF¢Æ:K8Xx„Íb yÎ.OzÙg%ŽžcW �›tN>®+nƒKï Tòœ\¶~Ì'iò�Mü¼ «¬ûñå&]ËÀ#y!7.›õt=I®ë­�Á/a€�a¿(Å*‚Ç©àë{˜r&ºEã�œ~ø¥÷GqeI�mR!oæ|\|þ�0ØC ÷vCgC%<¾P‹  ÇÈ ükIŸ*ÞŒÚÄV'Áh[màhÙ®0‰» h²÷?™¸:î7Ò)¬~0ƸEðâ>ž�5.?ñá“ë+Á`™~¨ÙKº/¼0’À{F‹ÛEùi¡”<ä-G�xoüKEûFaûä\ÎÝMࣃc~ªóƒq3©|ÄtiØ�~¥7ƒ·© 6FE’ׄ ´v+©È™Ó&yLæ“ ÀHS éêáÔŠ<1¿¹†}Ÿ-Ž»–#( þE᧯A¾K/¸¡X6Fk;ìsÓ‡_K@¯æ¤ø`‡!Ú®ŒÄšJ¨wGPßZ(=¼x޾śk Që¼ÿ×Ú‡FäWÁµyX“[Á¡‰ Æuàð1™Ÿ‡ƒ}„¡EÎ|E¦�ÿ»6ƒ•3úð­éNpLõ´põTºÙŽ„Îox^Á]ˆe‹uJH5ÝáPŠÞ™&N–…š²…pbÓ@tœÙ†3æåJ:Îñ”µÃ9äœTí&ƒÿMφ¥öl~?Ehï*üwžÿ3|Mï´>P‹Í1¥Æ„å5P{éü pˆ&zÄñ@».º\—ÁcÆ6Ó§Œc¬¥Œ~׊h%}$¥%âœçu¢VP%LsϤK%¥)« ñÕYa�V•ÉÁ®Iƒ9¢ÁƒFÿ WÃÞƒ³ÝK1¨hæÛÙòàùr`ô[Šë¢n‰fy·YN"—]ž¸ål&5 oB�ê…ìuN GMß Ï3®¢âOA´Ú”Âò±tbÐt0™ûZº¬ö>“qáÉ;H ¦�æÂ÷P°ä²ØØ•ãÎÇ`C~4ÏKÍ /góQ_eü´p$®ñW ”"ä3j}±üÛa8uþ,²·æØ/Ïa©¡OÑ9/,êß ì·$sêÜPdy¢»áG±¿€­¾Ò+QüÚú�*‚« Ëÿ)èhpÖ�/-þ,nl …Ö`¸å•pS嘠íq R§aìaî×b¢e^”å¼¹¥ô»*Bhñl¡WÅrxqâ*šæ×“/l ç¢e2ì?tk<}ÍŸV¤ Aq)X}£‰æ„8påù~p?0Ê`Ÿôôc�µÌxqÂItn”¸þqL-&Uí÷™:X²c«,{vŒ:¯Oº]ÚÂ�[A®u‚X#IhŒÆa]ë)¤¸�>åö…[>] _˜*né¯À¬¯Án¡ãy§š9ºp�†Ý?L¿OÈáSuRÚ"+ùpµ’^¦‹’Œâ¯a“¸oÃ"Ž1 VŠ ›·Æ ¤­’úæªmÅü0ˆGªÿ'î™ùJ\®Ón%ô©‹¤]I´je9¹íÁƒûâÚ°‘ø ë øéç‘ë‡@œzûÕH®ˆ¸±^,ÙâÀ—5Oã“iMôu‘<;÷¹âª-¢\N4,/Œýúsèì(pæ)l ÂQÖkQKs›�ê‡6þGaÖM0VKàß_7ð¡¬ùvRŠløÔoÄVü¹ÿ$mJ<Œƒ ×pÜh)tå/ä¯�ÃS- a’:ŽÀ2ZL½Ä¤rJ/SeÝlkú ;†—÷QÁ«ãâ1š¯CìL;zaê–£â´Î ŒWöåÇëÙÎcëZbìƒw`{c ;�œ+$éð“¹pÐç5jþˤj‰[Å~ŒZñ Îd'òÞŸrüÎê­û¶œÌ©`á86àÅÎ8€' z«_(�Ÿ`ŽJÙj䪺�Š Á—jÇÉhÉ9\ý4•r"ûÒ²¦2áv_;N8�»ÕÞ.»?–ÄGéÐÕ§�Ü4Ï•[¾¾F¤”BAö>¬^<‘Co.„㎠°«5‡3^—æIîZíÇ]wÅ]z�Xÿ²'Þô_Í…!kÁùI9}•NÀ^)+8aßV* =+(Ù¦SÇD>¦¾&]¸!þÍÝ7,¡#ï1ÓÔŸ†öšÊ›ßçàâM5BÜqOL|ò‚:9–d>‡AþÜ |3n/›Ÿ*qµ< cèî³ú÷~çu x&ô‹¨çy�èö$ì™&Ãf›ç±º‡#º¯›Ï'^7óâeÅÒA�Ù¤t+6ú/¤UÏkPéjOº+ÕE¿?nÔ‘»�ïN|YÕ¥p ø)l)BO­˜>”_ï‰�¿u9x¹·�TnÈcÑùÄx4)–œ²ÎãÕѶž‚D»‰�_Ý�eœ~‹cèfkËc”m°0mY£èþ­–N¨´‘ÎÚU¾d©?~ƒ¡ÂÑßfÎ7Èã2pÿp=¬W“§�ÑïÅa]µ°7ñä¿®6§ Šg¡zʾ^Ýh.±úÎrÜí³1êÝy@yq?LPiØaZ}d=½ÌO ™ÊžŸ]¡Iyr|2ϸtŽ:÷—€›v0ªÌ·Ç]¶ã0ëÅ@4ø: âøã»ÕxÈu3¤ÕìCŸŒÞT >]5žŸÞé�‘…ÑxÓà ²”¡Y¾<œ^$„•œ£gsðÇKÇø\âÄáZ¸ãÌnÚv¿//É|ƒÅ^j¨”8�û:êñy-±Ú°[Ìæ‰}$ô°e$L¶V2ûI¿4óæ›ß[ÀðËsÑìFFèÅYéýq‡³wz ö{ÄŠ‘·WÕßä4«�{¬N„¶?ª¸ÎXAbÒÖNyÓ i“G,Fkû í_»ÄLû;´ÐºÊOúý•¹ùægPX R¬s#½˜¤Owwììºcõ('�kü%YjÌ39#�¦¬“•gÁ,ÿ%hš} /NЕjúeKd–ÛâÜY™øéiÖf#X1¾¼ú/ÆÛmÀÛ}BùܘÍxÆR“ <…ÇÆPñ7¦À^µðý¤ö˜‘&®�–ËwBôxßüšŠ¹éÛy•ÒTV(Z,‰«\N?v±Ç¥x̺ñ›":úÀµ W\ŠªÔ"„fç@‘å7êñhHüÄe¹]pÿ{[oÒ…EƒÓ0%[K¦:sÇf#\R{4”Ý¡¶w»h<Õ Æk|¦7LðÔ+Þé뇲Ö:n`S8tÁr¡Y/J2Ó)1t{ínŇ™¡ÒöEÄŠçě̠û&Q Æ"ØÊX‘~ÌʼnzpJÝm¡½æ�N…–;¿•{öm)¤v¼ ëÖ4ä§/¶Oáù3|YÙt™)jðáý›°#Í‹�¬¹æ½ü:¡#®*? KŸM%ý a”¡"¹7¹;GGa¯¯õàû0øUïC?«ÞئUA:�9?Á’�ßd�õ¸¥BC±Í~Gá’,~¹ç?êWõ‰v˜Ža2àµßö~>\�âñ9„fµáè}æxP«Hª·sžNå.×ZRíÿ†Nî)TªOƒŽu IÝâøÅÊ·ô|Ñ&®=�Dzeyç…ò «§èµÌNj ý&¶íPe ]Ú¢�Î!'á–ÙrÑ]ý©�ýÅŒµ§/Á¾3Wá‡Ør2"”Ìûq…¶€ô&Rò†¥¸$r:øÌ,ÀQ¼D©²7 �àÛZ¾² Wž‡WLî“wqø6´[¹„ï®e ÿž(”�àF�>4µÌ÷Mg¥QoúcöžUâž¹FŒ+[@w…;—í²"ã�ŽT–χM—"@cùx^5YSº}6Ñ�¥uƒнbfFË/Õ@uÄÊn&N\h˾کpð–/F*À£›»¸ÛŸÕdUß(�¯%K7˜1чéZðªµ&|~Y.ͺúês•pðÌ菉¥˜öxcÚø"z³l)xOóÃŽ”Ë0m²”Ú^Ô “·Åóc¶ÛmJ{ç¼¾,ÂæI�.w�ÀN–›õÍP£×l,+u¢ 7sqØý¼Ù ŸÒeádz‡yØ.UȼxNúêj¾n˜ÂS-”Xmâ'˜¬z³¯w�²ç:¶¿�vi&㬳ò¨8c8oÒŠÇ9û�=ë@qäa¸[yˆ^¾~/\ÞïÏÿ1ȑۜû'�û�� “ ªKGã¢%*ØûÖ#pzèËù…ÎücsÕ‘‚w fKª—ÕBÛKôq{)®ýþRÔï‹#~Ã¤Ú ±èS&øÝöÅáÇ„»Ú²ð#¦–lnCßÅöÔËj*æÙ ëK ϰŽú_‹Ï Ã1X²‡§´­Å!»ÞÀ�P¼3/më)\SXʵs»C„ëX [{¯Ôã+ÑÃù{ß8Œ5BÖG“jÈ;±A>/í÷ਗ਼ÝQ»k?:'uçwãÚñêCrÙ¾€*ß`õ”éðcе7þ†D>D�ö­,ÅÉÑö�XDÿ½-'L�`½ºl¶‹ ÁŸo¿AÝÙÛ0tãR.j0c»†dÈP âÕe8rW™ÐgËï¯ôaÒÅ­öCØìôIŸÍ¯áèíQÜr[Kœl-‹ç/@ÝÈ*þp�jû„c¡‡Å™f=9+èo‡•˜cTÉ¡‡ êf„˜ó½î™àÂÔ¹¼ l¶·ôã¹:æT}L‘ò]>’uÜOº×€¾�†q-{¤ÏÄÒ‘q ±vôJZ‚ÞŽŠØtn­Îå�˜1æ\Ë™*~t—]ç›pbS0=zz[Ü;k#E½KÀ.ʨYˆ5†CAi÷*|ýÓQXóu6ß ðåKsx›Éãû vãÛáJî<˜àÖO�ØU²˜Mz ¡»%Y4¥Ò ãYâÂg$w+ˆ}‹dXºÜšt¶(“CÀ:T:·—Š×&pò¢.h7‚Õv³ýHEüt¥Eâ_˜.LÊ)¥4CO¼Ò.X… âU-¯áÍ|C^×íÞ˜Ö6�t%rOý˜ÍrîIÔ>4˜n)WŠ—£~SÒÛ#ðn® Ý̺o½Gãì›­` Æ…úÍàUйîê8hÜ0vHþ!i™À;_%ÃZŤ¢‡+¶Ï褽hwÛ?Ø Æ9 zàÙføSjÈÛ·KßL׃ϫ ›.àöi²ÔêùTŒS ·§öæ¹Ó]±Åæ›EÓ‡Jâ§,›9µ 𺣻+ŽÅÂWE4æÚYHËÚŠí…`¯Ñ“ýBŸ‚‚C&<ˆÉ¢:ëf|×ú”ç¹Ã™]y~¸·ø4ì�P^eÁ›'ÔÑçúá¸üÍPŽŸ*SŽ/§ïÈ1„û›t 'Wž³G›xÇ€§TÛ�-Ç®ã÷ý6’©q•¾ïÎ©ë® Æî}©f¨ 9s;åÿB½Ã7[ÿBòp9~ž8†_\¸ÌAN•8ÏÔ ~šâ—g?“SÒ: -6Å{×ò .ù´Ð4³NÙ …a¨wr2”À‡=;9Ïî%¼WdÓÙß z¼2_~Ù—¥¡à`)|HN‹ñî8´*H´ü/FôzúÏóS­Ñ~ì#þêûBª„=hžW*œÊ=�Ã߈ÂÒ5v¨Q©hÕ¶U—=­zr_ÓX^°²/×Ltư�ÅBbé!!«ºÌ7/6,L7Ê�¦]pí‚'B¿Ìóè_¿Ø2Ìq ™¶ØIÃö‚ªCÿþÏ£6ÍÉ¥þs[±(ü8雲ÔÔ dd*ã_öÂ?nÙ\O‡è¿Ó�è«q[ü¢9š—ºÎEUÿ>lª '¶ýG&!õôp¤k¼/¥Ìܱ•«‚‡ÿì£Z³S˜cÖSæŽÇ‹m� `°œ·�vÓï×òÕ¬™ÒQOÌPåùG2Ü2ËŽX£ÉŸîšÀ—Í· •þ…b�üGHq»ÏiÊj¬9(^T?éÄæÓý+†ÓZiÁâøNå>õÊì�®&�x`"êš$<šá^gVpãkÂ¥†™¸þùs 0b—#gÉØ,¯š tvô>,¯ŒóüüYfÀ*ô_ÏÙš×À?î2½�Ñæ ¹E0ï’rEÑHÖˆ¾ û½-:jÄQ{1¼1_ÐgÄ ªù¬ž‹—çžÃ-�ËзÛt´ >KÖá=°äÕ.üfEÕžÇa˜ÿVÞ_D:–�bâþ²ŠÖàlœþZÁíþÔ“C~Û–£vÌvÁoó&ñeãžðŠúM=‚ùs¡ÑÉ̓6 �æèšaÍ«-³`]O[ÌéR÷Ë[hlÖ$!)ß�oÂïÕe’¡Ú¿�A‘¸îS"ÉM-ޭêÆéP8 E[Ò mý/šÐ¿/çöŸ(Þ7ùL¾O´Ù¬éܵü¯â÷Cö1½ÆcGÂn»�ê¿ >Ë�ÒDøh®‚;±†}ó€¾T9ÜÙÖ�.¡9¥7át’[÷QáOÛé�çg'úñ�§Bõ� sq?[‰¥Zã�ûUÀ^ÉsðWÈ_öòÓ†þ“açÏp85ð¦D�àô‡1\½ê MÙž',Ù<ƒÓ× âa�½ùú�±ºqe-]ÎÂ’Ãs#2 XÄÑSæ²Üút0ÿÇÎ�PXÿ©h´¦¬¼äÚ_qŠ|ö¶]�î'¡Ní.o*›ËЇ¬qìÚTøÿl$ÆHp‚Ú||Ù¡�jØþôý,,WÞ©·8uü°)­\6ÃÃðpF Ž™IUÕĄÃ"¤‚¯W£0æÀrœ:å;wC×gMÁ ™· aK%í>Âå^‚n/C6(šÇvcW£V§.m7ðzÍ cë#PôÙL§?º ³šåà”³9®ñ•°IXzÞ‘‡�³ø�K=¼—‹�`ˆÍS.”x¼� §Ÿ¸B.‡ÔpÇWþÓèÄS/°bH»Ø¦ÆÝn½ÇçäÒ¯a.œj£€ß&X‘wå-Ú¤ÐIm‹¶Ã6·ñä.ØrºCO¼ýíÔh:Ëaíö ‰ï×xþap `­¿©Kc7Ä]Í„xÇý‚ôõh}ìÊÒÿ40=ˆºïêyó\v0OÁ u›yÕ ïöÔýõ¸[�ÝC‚™î5dYç+¾úÚYwàLJ0wøüc�?Çðõ•L8ùñc®É¿üH ‡ê@�¿û\ŸÏÏT…ÓÖÇùióC°>Sî}”þp2ƒSsÀ[­O]ý ©é:X=Ö '¾¶d£¿w(!ê…yÓîu*£›}$Ϙ8v[¨a¿ËÉ`­Õ*ã§¡ã{ Ò›”ü‚knѸš-ÝëTµRê‹°ÍG›«/®–iQf£%J5ŠÁæC)ÄH†Ò¾ä§b„b.pô㚢Obë®'ü²Rƒÿy‘Í¢ ¸—rô»£RÝn<„÷¤�ßò°]_<ÔCð«²?®^Ï­]I¸yËVvKÙÅ —œØPa2¯‹�×¼ça‚g.UUEò�çTÞó?ñì—j°\¡ƒ=Ìæ€{ÒiìcœMÎʆl¹níÊk¢!8䢔r ígÿöF�¤S>ë±W²ä;Ÿ¢N‹6¸˜÷ŸÐ÷S‰à™SBöšm¤[9”e…²Dq:»~É• ·>³"¬P¢·†K¤Ç;#qßî꿦Š4òhaïcB×Ñ2òZæ…Ö¨´m‚õyZR]Ó èFpôìQH:†7¡â‹7º+eеY+øø¾0ÿñ~L§�Ær!ëc?P[ý ŒRÔÈÏ?‡dÆÚÀ¨úîèµo%æ�F·#£p”|­ÿ|ÛÚ‹/é\†ö^'Å�™SaN®œ: +ÞÑüAZ¢KšûhàKñ2ª´¦G„²­KønË¡‘å¯Öûê3,øpz#ôÉy#-º§Ãk·Súý>#é.OÌ€&Á�KÊ‚ >ã ™©í>ò uÉr„£>g<·?[_Cîê0p Ï7.®FÃaBÿ�xsH1ú*°ñ„\´xi€CFêà¢à7t1=‰íç’¢HÞ¸z4Wj¦£ywe>w}"«¿~^ñd…Ž%”EKgªŸ‡¥ã2yhy´ß|.¼<4ÄꛃÈ2ÑÏN ¼t|'¦žÉ‚¢~j¼ð}ü¶XÊö5È&7VÂÆübɣמ\]ö ÖzŒ6>®¤9k,Ø>D ý¯GPµ±5æd!îªÍ—œ3W`ùÃÑĹCXqo?…®©hS³M¿*—¤Ž“ §$ˆ¿Wìæ¯ñéÀ¼ßÂñwgðž¬�ˆ�U×fÁ»ë9¼y¤©t®al®ˆÄç¶û¨¬ß0úØÿô¹è"~XKzn°ãb<:ü=H¢å Ø®9•»†=åüƒñÂ'q0GZßßÕNÀƒºbˆº01 ç.NôÇè<–Ìôâû[»³ƒÌA¬±8Hvù‡Y£O hdT éû0r^¯zíÀåçhæ–þ”ÔG+†&Bž†ß“I!Qû0õP ‡?‹«Óÿþ;~&5}z)ñmœÁïþ ¦¥Sàí4YV¸ò�È~e’œ~KúÁ£p‚Þ &YSü ©ôGÕuXñ.N®¥ð"óϟƹÅpC%.~ª#·áÐSYûY§<Ìãe1Xþ‚ðâù¸6)o’ñ^ žU”¡X3ELþ£Žû®¿†QDÕ|ði?.ÑÞOýqÊ�ÙE›5F¢æ‚8òþñóú¾¦¬�©èuc-ö�[,­xœKüéxŽ+©=³cù^=Dé�x$±LÈrÅgÄt¹èÌø0P0Øc'÷¬T;«Ng5ËHók†ôÅÀ"*õ¶gÁQ ƒ'ñ\SKî>Ä×h¼„†Evœ±ó/¶™�ÆýŽˆÞvi[¦Iwôóæ¾*)ªeމj’ nœÇo>§ *?šÅóÆZØv­“OfÇßQ¨_pU3 :têžÖóÇJK\þ!Ÿ+žA…׎¨)Ç#3My}éc=ßœ›Ö„ó$¶æ©oÎw&Ÿ}¾|Þ,-36µ 僞ÁbÝ«’™?é×¼)¡»¯+­æä}jå}š»»¶ ; 4Ä>[Œñ\ñJŽ˜ù€òÆäIr}xÝÄXkéÄ%màà’Ìòße�WjPwŸnHïy£×¼ª¶mîéãœíRÉãC!ü7ÓGØ»%Õ¬áÙýðnš\ŽKcC„Å‚nlÞ{—ÅcôCÐÌ©’V{n!ûIÛñùŽÝ8ಠz­Œ[^h@ÚLsÞ¿á HÔØZ¹QHŸýT ÿ5 Ý—-Á[Ë¢øâje\¬‹�Vî|õ¨¶è|w�ª(¦Ò˜Þüáç>q`¾H¬R81QèùM++9Éy&ýÙy�6ìÓŸ<ž<2Â&ï¤v!”_y7€í©Iàˆ²y~âÌ|¶AäÁ/£qÜü Tã¼›�ÉÄ©>cèý\èÖ›/_›Ž–ýd8mÚÜ4²�\wbN·å¸©è¤h®=�µ¬Ç ÓOìf½Ê烄»LV0o©*~ùY šAh:7Æ?øN+v¬ÅˆÑ½Øìt%îÞŸÄ�×?ò�ãIWƒèNn=í0u#lŒbù£ûÅßë à“�ƒ”Y7ª”Ý\ÖaÐ�G°3i$fžÚÏS÷¸°ÅGM<ÔÙ Wº…ÁãºLðŽæóñÙ?/½ö„²„]8´Æ””ªNQ½R~dŒ·óopѾQÛAƒËÖÞ§kž¦˜h™ÿÜ&¼g–¡ƒ1Ã@x±ŸÌiœåžAè da}€ØŒÐçå�æ¡÷ª<ñcç o8|6GMùÞø¨4ô_Ÿ%Ð/MVq+ǰu‹pˆÅ!œ>+ì¶�â¶ ‘ú�-ÀV�Á¼ò�9ÎxdAJq~äºMŽñ8¼s-ï|r";›�‡�mï>`ÜȧKÃùeœmøVØ÷üÏvÇ·«U1b^!}ïPuT>›¨ƒ´hoÚ1á´nŽå÷gá˜r¼sê{sãœV< ïŒæÐoJ¤sÀ‘÷h%BcP¸D˜£j”/¼Þ‡ûþú綻܋¡¢/ ®„úöyx4c÷¢ÃÒ~}¹~¥ SW)K#»Q±óÒ1.�] ØwMˆdŸéPa‰Ã`ŒM^Îï†aÚÝã”ÞNže2–vØk�¬Å¶‘æ‹Åƒ£ðîåPîxpU�ÉQ¡_!ŒŽ6�¤êTaÇàx¸¶«|5C—’#XŽZ;®ñÊZ8Æc0N>œ#”ºÛÁÏOÚüÃCg„œ„ÍŸC`cB þú�ZŸß†lçK4Ýû:7™†òy‡Ðb`ÏûG‡2­:’sf¼c¶§5�†aÖ“qÛŠ8ÕÕWHŸ°g$öoÅ#cpÀîù¼>7œZ×wã,3Ü”u�'ÚȲl¬ S6llh‡P''\í1†e4¢ÈP�cñEÏ™· üý4èÜáñ\i‚ï׎eË G9f{uËÀƒò4oùî´�ƒ§š�Hg?0�Ñ©!t»8õ×WÊ�X Õ’^xáíâãò´,\öúv'ŸJS( ¶â«'ƒaƒ�¿¤çµ‹ä:ý«¼¹ˆmU=p|¥N\¦‹a£᥊™`çµ:lÏñxï"?a�ýŒÃ7XYz¬}-Ä´ÈÃþ¤ xuô ÄšgpR÷¹°Õv>Öë¿Êÿ¬å˜ŽÑ”l…v}½èÞý)RG¿Ï4Úç-]™m�öºÁúè*˜[½AäI§x×äÂ<—%ø°RŸówZ éùQ¨á8ýÞ¤‘Ÿù®ÑX,,û;…øg‹ÕÁ§h«n1žXUB‰û^_ôbyÒ¦'4­¥?m�ŒgïÚ�ÌZE \Ï2µ!|Ð^…ö¿#vhÖ ’Ç×ø€ïZœþ²€FÜi�ußM9ó“?ì1­À??^[ŽÝAw}.SAj \Ûq�.›|¤ÿz «ä�ܶ'P$Ü2|$xHA§=;šW‘Íã)ôͨW¾ƒLh¡{;}žà�‹Ê»ãªãÁÓý´0ÄÍÇÝ,†îûã)uaö˜X#Fz¥`³Tä¥ï"xyßPa”“âÙq ‘2Üu÷,ïû×m_cÌñÚ€EpOå3<¼¿åЖÆW ©ƒr_+›…Ƹð¶6þ<‘V�G[„„H<±ÚM*~y.v<„m×hÏ«]bÔ"TÉ}(¬aÜz«’ÖÕ7 ;³Ë' %¸ó®“·XÅ9†�Õ>%çÚ#BÓÇëмё»?ÊÄÿÔ+AkÀcÁwÐp¬^äÃÛ¾BlM5në‚G-Ë93ÆunYÿÛ·l¼ù‡= ¿,´çééî¸/}öúÖ �þÇÖá_mõ(ßx>ôK£æ�ÈrŠ6n¾v‚Ì”qçªÂùSÞ!7 Ï�*§ÁoãÓïâ=Ž8Ü�e÷NÁ#c£`ÐÁ×âÌ+t¨ðÀ‰K‚Ä凷ƒðl=ÞØ,9r+ z_¸KåC9Wc6GŸæÂeÊM�ÆGt9eÿ[!çf.­^ù–~ºû V¿„£�uðUÌÒšÇχÐØ9¡Ü>p7¯IÔ4âþH#·MæÁ…¿…— óQ¶XµÆüh›*mõOÀ7ú ñ‚©9ÞÖšK'>€�Ûल¾8É îúJ+·`Ë&O.ZhJÖÛâêÚ¢ÂÔżð�1O¬TÅ93z}�©aÛò;œR :m�£¹[Ï£­á2ØÑÃ�¶ö¹#Ðá~¾ø»Ì‚cëö +6mãv,‡öS‹éœq´tnaß°›¾HëéÇú4üœ?Çér¬ÇXvivL)¬‘DòFÑ�õ_/“l®�Àÿ.œ£]>-”‘¶„|¨aý÷*ûfC5~ª³ø¡ÍEU‡NæŸîºY·›Ì: ¿ªÔQý�:ãàÙ°sûFÜpr?}í̧ð1+¥­ÿßîCúßÏÇ<ÃRÇn¸þÜPl+0${[}Lœ‘„O�‡}%£P×f4(žYÈ[—Š«þñ°Þ÷›Pëþ†v?‹É¹R<¹{(ȹÊQfbÕ {Jm „“ŠG1[9–‡m’C»ävAL)ƒ¾O‘#›ÞÃèŒn þ3o#oÿ(Ô êÉ'Cä8>1V”;¦ÇW¬„©}Ë)üÒ<ûì&²ŠÇãq"Ù¼®¥þ{Š…, ãW£A£ÿ*øy¸Fa°ªVôí Þúºø4(ŽšTCùhÞx|^EzºGxk‘†6Ùb@bj»ùñïNOêv$ÒTŠ�|»4ðШÍlª1·øöE»7òè‚Ï:Ï�Wþ17{>Ÿûæf×VcŸê8cë:¾sÊk!{³c ¡;‚#½>€æ®e|©÷ œž×(•è,Îæ:ÁŒÍ>�5vÎ^ÕˆÒ–p(ªŒ£ÓZrü2U»ç[²çÔùx%8„Hÿ º&‡H¿:&C¿ý6xÂxœ°Ðb»#}ñʧ÷ÐÓ0†O¹Ýå ­ÓÙÖ¤çkø_�]¯\è\mˆs£#qT§¥øh¯?ºI&âKÚç»�”Ž‰Ç W¡{hüþxYxw]Åjg@?�Äü¥[ƒG°Ù`+ˆÏ©‡†u貸�]weK·DÑõöü¦(ÒT^ßF· -y¤Ýb6ÒúÆ}YyàÖš¸N’°†ÌƒèëÔ“¤ímŽŽÙâÍè˜ôµN\˜Ê½ÆSù®ù·O_…ûSnJ®—[ˆŠÙ¹; çû’±®Þžk��ïô]‘ÄWŸ’@åØÌÚäÂ鋿ãâíIh®hG?ë¦rVœ•жä.yoë€Ñª¸®| ¾Þ�ºb¶â ãoÂã Ô¹ðUXù²Š¶?LâsÁx{常x NɶàŒÚÞü®Í‘⦶€ž¶ D(.çU±Ú¨Õ-œ›e�!¤ÌŠS…k�©xßz“h÷�ɪ_÷ ÑNŸ7‡¡ÏæuB¯ÍSÙ{u"Y Õâ+ÆîüâÊyé.Û*:}±;ŸÔ²åuoÔñjú Xj‹vä.ry4¬*ƒNäŽD‹ hÞËŒ}ï>¥Þçàbq?F CW—~±W¤·irøí¬=V�5¾ ÉóH!Šàùß4ô©®/…7v •³?�Âp™«ä;€QI;k’H{éàúƒø¹O/àžóyÒë±Ðk† ïî�$èŒàsº“ÅÍyã™å3ÉÖÀ?ÜÚ‡9�Í´[m� K m{´©xôA~[W*d™ÔÒ·žª|²àœùbLi‡ˆCM·R7ÓžÜC±–9%HXq¦>}C“ìï{ýÌGNÄõgEu�%P°Ô“#öôçâ0],]|*G³xê4€â²¿ Ô7‰å’«°¹U…û_€× µйþèK–¼J0æ23°pÛ'°Yx˜.L5%·î�úüÏÔ4_Oï †aeä13 dLm ýÕq ó*¦òÎÐWç´°äV+%®¾F·ÍípaJÒìtK‡Å‘�Ål4y:›(Ÿr¿¸Ð¼zS¡ÔÖ ç(®QI Ŧ’Æo<ë±gÌÏ„KèÛ%˜°%eöèQ§æZüõ¨? Ág¸—k:Zmÿ. Öã^6;ýœR~¿-„Fí°� #�ÿÇÁ™Gåô~m<šK”’" )!é9{‡(™*CdŠH†$|‹HšTT*JR"™C¡¢ž³w†¤ŒQ )C¨!„äõ{ÿ?ë^ûÞgïëú\ë¬u¾'އ߫‡b¯õm�›�Þ™êüã©FLyM j íG?î«øŽj:Âñwn†?š®:Ø]ëÖØ‘¸7Æ Uª#À³è©P­ÒbWpÕ›æ¨D£ú”/”_s•Öž¥³~¢Ä»"¯^!äM‡Ôn¿hWþDN_¼MtµŽÁ Z¨þð,\j�uoµ¨®·Múó5¤ê|gÏi¤—Á9ì°Pç5¼^r ú†F ãÒYÜÃÿ5lHÔÁclʵ�ã(G*K#’ÓPîñMôñ¸‚yÆZíŽ~fkŠÎm·ƒ‹=¿C;]^öî*]²ïç‹qýïÛ|.ý Á NpìÅWWÑ‹Óç˜ë,ùù¶÷0[ŸHÿ[9h¶ž…áwsÀ´´ƒÎ缤ì•|öß5!WÁ ýí†/óº ÓU÷âÓ{¿Õù<�öQ®Ò¶J»iK3éÕ¯�t©]�û-qb¶p~áh¡ïGè6>™/u£gžthÂ5ºîPL¡==øâNy¾ôS….Ý�ågK3XæC%ªÍ·ÅéW/SÍ8%4¹— '•ÒWGzíñ…ЬC9_XZšˆuaaÔ>‰ÎÅÞñþŸ>�Åÿ2ŸýáŸ`¾C¯X[‹¯7íâ·šå8wð$ißwàû‡yXS¤�“�ª ¯\LY3‰ßrå^–£ph(2„欇pEvÊê� ¬ôðDÕA>W=#±}Ÿ€‹ÚXoå’æhq�ÖNáw¦+jIŠì¶ú Å}SmÐîÁkèð2åüéU´8,�«ÎÕ• ¸sø ^`Æ1“Žá&li]Å6ÏÇqÝWw²UèÍiïJ…®Ë[ቹfdÎäJm?Æ!¼µÍŽÈù@GÔ œåìqr"·TZ««E_—ûе_fƒã{/PöÞÇï›#ÁOfüý-‡Cf˜òÁÂÒêqã¬J¤E_ió—V Ô×€™øf•2�P-jR¾ŠªõÛ„WÁËéïk,˜ý¯ç‹NbèõT´ñk§ÅFùØÃTwT‹J¯v�‘ïeP‘k…Îs›ñh�«¸i.ùÐ)]iÑ Ç›‚‰[åñ÷álüoË(þj{€·ª±ÙÆOà¿9€5}f /ouФß;p]‹Á?öŽ¡U•­2·Q›[˜xôüpô¡‡ãw¢aËy”†ÌŽNy@ó·Ã~ín¨í&`œ¶š©m§Î°Å¼]ïéЩáÜw¡~1ø Þç£G§,qŒcj ÄWËíx”âUºïëÃ}«hòWtù5®õV�áG‰š÷c¤†¦û(ó¶F žœô˜ä|"�åmô2|#,Õ1#ãþ‚P«ˆéò±ì ™´|Áü¼S°%x¥V{ÿó“’�üþîHìu{4ˆGpÔ‡)ÌçF@�´†¦Ÿ{ú—D… §!aR"OòÇL³•lø-¤²ÊÐ(qwL ];tW( ŒÂøÒ¡œwd-þ]”—z¸s¿:XpCZ™’'ä¥ÜÀ=›×pE$�罹1VSí6×È‘I·Bú— qÉÊÜåÔE}÷]�M‹€³¿]£!ÏPÍÑŸ\ ÎŽnT\Ê7º@éäRTXÀ_‡BËŠprœ f<Ø#é7}/ýptFž ¨6i..p-�ôi:˜�w?{ ÊcØS²’£³,¹B®Œ¬¥ “c31ž¦Ws§éV®ÝÆVCÆÁ®îçÄ :"û/q,­ÕÑÝõno«�…†x5¨ |óÍQæå ì›Á‘õqõ3'N1ÚMû~¾…§eat°Þ•ýÒÄ-�Ñ|ôáSú;ë ï®5⯠hZyˆWžm€Á?iÜTüùØÛ¿¹`ò±©¤aìHzÿÓ—çöë^f×rã ½ê:˲õM’ÔŒÏp ßÔˆÓÒ« �÷×þ¼(¶VÀ‘ñݤ'\¤Rµ›Yø²¨¹y§Q‰¸.j7ÙßÔùÿÿÒ¾»Pb¬r�®ŸUFyá¥0™_öÙQ{{𦠤�ÛŒ)F ” ;ƒÍfèœ{–CëwRÀ,EŽóþ)v¾êÃQ[úÒ#àf&õ¶�£·Ÿ&è°ï⫗ݽ$¸zsϹ ¾ê=‘Ÿ;½*GàÇžŸ!.jÝ»+a‹ÏjRÛ5p}ÿáx¸µpfe)´‡dàÒÌnðô± f¹çãž ¼uá)\›~Q¥T4°€JùWÜ.ʳ÷Å0‡�’¿ÅðkT.h‹Ã»¦Æ8ý’9ož¶œú›E±L·21¸z:¤çó»Wí0H[F__†mñãø–Ÿ² Z0—?¿MA½ŠÙ4³÷yŠëõš¾gFcªE‚¨Ÿ|¯¸KVy ¦÷Ìð¨í8l×ϤeO‹Â‹‡BäÆ8Ú2ì$�‡ÿX싲Ï_ ö%ÖЭg•=�@�ƒ£y_‡.[j¶Âo‘qÎÏp”©ÇÎÔaèö¡TS·PŒÏ(æÐÍ€jÓ� óõqxp¨lSĈ¹†dµ»Ç™·À¤s†\hûFK²N„Cöée’ã^ˆ÷ƬŅe»h{©®­¹€S+ljó.À?&V|+xû|}IŠ™…ôß¾Cx²(…ïúl¥ðª*˜gr´RJh½q±ÔÅ¿Ž ÚÌurÏAçY,t‚Ç[¤bŠM™tÐô“°TJtͦõþ!v¹Ô‘Å[e^²û<«Šf¥æ¾½nª»Dq`ï¾aývmÅÿà0~?1‹…Ø=Ü'ØË'Íãß½%¸|µãï|§3[J½yTŸÑI‹Ÿ¶ˆ?Õ®“ÍÍñðuÆúõ ×ï1|õ¸[|%±K4ŒÁqc];��7¦rôŒ™¸j*·ÄàÄYõBzüxž­¨‚ñ±tóõ ¼0>üGl¦Iê1,ó„Võ®d>Ʊ_¯rð˜dŒ¾Ï|qqš¬p!ê ™=Uĵ“Ña×u¸\ÿ~쟈?†4Á�'»8°á5‡ü8D;]žPu·©B¼™Þ8hƒ>¡OàIt&È-`åþpŵíÐ í/6NÅèŠj©X¦Ž�^?M¶„²ä£¯ýs°l�Å©Þïèî@–`ašà½Z Þ¯–á?ï͹Q)Œ›<ŠxøôûÂ�ÛÖ4ò�,88äSO‡ßløék±š§;Œ›ÆO"Œ0â{‡]û #¾rø´�ÄË�‚u}édéb˜Ñ2î/ÁÑK3¥{iXO™Vñ؆8|HíeVs{’Ÿ{–o™�£k²Áú‹#½ˆ4ŸÈÙl)Çõ{€—ß&I2¾\!)(}‹àì¡…ƒx£°Lg÷–fÝŽÂMž—…NMëo{ÂÌ'ú1k/+VŠbÂMu\VSV§­ùá�5ôzåYš˜ù ¦îcZ\Æ“µnŠï�&rà�t´šëÁ|uŸxF6 ³ ÙáÝ h¬Ý�B~¡xmmºÔèâ#©_|E¨ 3¤õ6¯yÈ€…ÜkUo´wÇÞ?¢hKŽÞ¬°D·@¼<ÈÕþ.¤ñ-*üí˜1ì91[Lu0ÃÕ²¸�e±Ð$|ÈÇ�‚i4.@á@¼xy4ê¾ëŵЯè4šÂ«/ƒ^“!ÝžàÆÄêM�©ñœ/NT*£Ý©òøÊ&íó®ˆ×š“(µa˜ø òJh´Q$‚³V·|£3Ð1–T*úŠ’µVôàO,=y+5è˜ÑzÞÕ»žFLwƒÿ}Èùh�¡¶¹T!¥¼mµÒ›VÆ‚]Ö!Þ9gewÝ¢›ÿГi`¬°Lþåû£Ž‰~ Àn¼=®y†ßŽO ›¹…›yÃø»«n½jxóáœhmAcæû`ïeV<|àEzf–Iç¾>�ÄÎ�h;aÊŒ¡ÿæéÉÉÝlù<Þ ŠY;ùM|"ø•DŽ)ŠJ€óãd°*"ÒCé�j¤ð¼Ük#Ê©>z?/Áª S“ê,lüS%®U„}!“Ñù«*v/×$™½·¸›½'—YTñ¶±rvÆzޤ2ÈP<¡Z‰-u=X-zµ�¾FÎÛaL‹xÔãŸÁ38ï§/õ Þ'L[£'JÞiòÀ;`fêí5ÚSg¤‘çàÿmøeÐVöþ¤Ï߷ȱ¥O)Mh»…+²pû54Ô‹Áû²Ê{q½°m¤Ç§wˆ®¼Fx¤ºCô=¤lÁÆ 7œså0,l÷…¨¨—ÍöК± º½^û�µƒpâõ@R›º‘gMÈ�Þ.±ð$÷)]½eLzìÄMDß?{y¿‰=Ëì-îµë‚ëªßh�‘#œ‚[ñ¹‚c£1Ñ�Ý(œFýó1?Co½ïÀN¯îÒIþ¡c]�)Ï}?žàÍ­=¹néP^aŸ�š7=aäêD¶UŠ2ï…?^j%¦MÇ(gš)·À¢Ñ™x6ù;T�rã^;|è|Èwêæ4‰3>˜Ó­8%ÒíšÂªÀ襺oÕä~ @º Xï°–DëPêj��iö5A��·òõFOJ²µ µUA|Tâ-±ðuÀíYóøZÑ|ÒoÝÁÏß­—,O†,™hút/¨ê¸ÂÙ>°lÀ¡fI¸‘¢T¢·úE7¹óކ+’}cõXìÚ@v|²: ÍzgÓ‚â¾xj‚ŸpåËRÐoƒŒ‚èûÒöUEÏW Xx­?�© ÖÁÎÿv¤Éê/½-×�X ~·í´÷¥bÝ‹³T[«ƒYÓ�âU¸I`°ôœ/Å;ÇuЊWû0ci¤ê‡ó=ŒÂ†óš0Ï猰êÆJäê§._Åðªík„~¥z¢ÁOÀ¥owÁt¹å4J(í튣lLŽÇ¤Ÿ6†Á ¶x>sIÑÞ>~7D åO¡‚bE?¾½‘L§\—¾r¼þ´ 6 úZì¦ÔShȺáÔrµ;–—ß kê+„ñ­qèßg+¿Š�ÞSzà…ÛÀùŸ_Ì»óN º«ºG¡fÖHÚ¢¥Îg]WŠCËË¡pÏM~ÛhÀFü¬Z,<騂>Ã=8Ñ1…N?ŽcÏ›¯ùdè9x²³Äåãù¸L¨­®„.×íühù~~âB¤=%ŽÂwÆÃ€8£™GaäİiIugóŠSÊ<¨Lä¼Q5¢“A§à[È�ùî9ìfýþ[©æSŽpÛižÛ‘•µìtó©òZ‘:÷J8}þ:\Z)‡þ±~°m×fzf»={•@va•_JîSp­Û2Ô>šn×´¹7lšË¯ó‹¥ƒ5`È«âçIi¨0=àŸwâÊÏ$‡<÷â@�“¢Z“%E¹A_'3~wù”nËaãŒçô3Ý” dð®ê5|ÐŒõ»Ã-ׯÁÙçêln¡�~â 8}7¾˜¬É•Ù•ôãÊfœ`dÂ�…—úuâäæ7’ÐÃ)¸'ç7üˆ9Ì£ú¿ !V†b÷9€›<ÞÑí¦6Þ;;ƒ×èi³®«‡O-ùÖ{Ò“¿ÔY~—†ØP¢Í• Èiv›íú±Ýøíøj š µ»ÅÑN|ì¨ Îs> +¯÷åŽÔ¨ÕE3W_…²-Šä¥µƒß¤?‡¹v'9È ‹ô�úÇQÝYz¡ª³/KtÇ­"7­ý<ÜïÕ…èbÌ�Hxçÿo?V`é¢�ÂKÙKtl´/–MQ¶C¿±cÄ`IãàTøõ¬;õÜýr«Q¥»ß.Ò?¾‹Ý&£}§5;éw»†‹’éÉ�Û0°¹Œ×¿z&>^¨Î.‘ý 4f€8}¢&›_Õe÷£shÌyU4Ø}�÷½ˆç0¯n%~O­0-ê:ìVÝNÙ ¶ði‹÷�yý˜:Î_­Ê>kÌyiþR.[Áï2öÒÚò»ôw£5õËìÉ¢H[zNí7à�?¬ûz‚°Xµölö iå}„Ê›³¹—y4¬~y3ÿþ ¯ïÁûÃAðúZ-ŒÑÕåøÙ.—p•æôÅÒüÔV¨Â~'mØOK ‹+ðþM}qư¥<€4íŸk‘fßwA#»z¡·š„¼µwãžísyËØ¸qÙ\ÔÑÖAÅ>üsÙb¼S1†ÿ «ï|mè{x ‰ä:ô¶ßgw·÷ˆ;†Ö|pj8Wõöœ¯PdõZðóì’„ÆßÕÍÀy�c¯w¢›lÉßú«ríÌCüu¨M룈†çÏ GNÆ�†ÁtµD’Øp—F]OÆlš‰[‹RÄŸñ’$µ¾8^k¬°¿0ˆVí§»GœéDp‡�—yœ#«’p©ý1.ÕýNG<ÿyê®Cüìl6§‰ýÐÃ`>Í(Õ¹#9öl5îé;=ÿÄ`ˆ¶2¸ö4æ Ý@l˜¥F´qQ‚9îÝs_Ï»ËÓ¾fHï+õD¥‚«øEÃO½ßœîF*bhðNt¾kÄ9�êy[ç¼¶Áž�CÙÃXŽ{»ÍÀÚÀ¨<ì2å8I ÌàŸ‘\…kÙ¶3Ž `ßZÊ‘¤Ðr%üaœ~–ó¨}õ ¤ò‹p OŠtCõt>>!���‡š‡uÑÿ‚!G%~“Ò&Ñ¿®;¯VŸÎcËòÔÁ#ù˜ÙháfÕg |ßLÁ_v�QW2éØî¤Œ>{±ùÏ)°ŸÐ &}É?3õXÙ<‡“Ïi¸]¡Åõ„ ÝãpõÍ9aUTþq¾â�‹¸0ºT˜éwóCÌùͳðñ 6À`åËÔÇnˆÄf³ \¸(üâŒçê•Ñêf)ŒþXJ’[û(½¶•4n e§ºÜèý‰õó®H¼?~¿‘ªö{Ïkñü ]Œ-‹Ž†ÿú\ŽÕ4˜­¬ÂÑòyhþ(G›8ÒÚýçxEü"éxSàmRwp<³Ô¯Œå5½¿QûÖ»c?Åä€÷—ZR›|F´øš‡©^è(Þ cíf°k¥wWÂæV[ŒGe¾Їcgкwàæ‡Ô¿õÏÙôY·þfݺU3¦“VD(œ³í�¨|š}ÆnGePЬ#ÿúzºzSÂNÛ²ú» ÇÆ“0qú!p¬éƒ/ª°#¶]¸”ãE›üïÐß�ZúÏyZfvÐ0×ùðXù¸(QWu4ø¾8—eÏÀï}*Ü4> ø®"CVjŹª®øÊ?2c­ÐHz�ÝþÆÀÖ!R‰j—±t|i,{=U‡YG�{IƒÊ÷ùÜÆ{pýz*lútŽ”üÉ5îÊݘ“³éÍîù¨»|Þún�CR’fã³ÅºìšÁ©){q{l'Iµ®€OŠÝr [¾MgÕŽÝÙ}ªvC^m2–Xc[Y6�“Œ‹l±¶wÔÙ¹¢¹� ~ÓHZªÃY埾äºJCz˜Â…¯.(ïc £»ßd«±yµÒ{±ç!wØ7ÿ¢8ÃÊòœ9áhò¾7/¬j…ÿƤJ¿…ŒDÖÜ|†^ EMÞc¹Sg Žï¦‡v7&‘{Ó Tùî)Ñxa‹™fŽ;׿šåaüIm¼åÓ&쪿 GgjcÓÈuØ«cG^.5¥P4 4„˜šI´~¼ô�âjîn§·*VÕME5k/éê3ÞØ¸ÆmÞ5‚ëÐp«ðE�[ÀÊ'°Ø¢»ýÓsRHõ¨"gŸ½bp´çM#rkxé³�ø!דº|ñMÞ~öZ�7"ìyþCU|œó›äw²Rª>š< ‚ c$¿ÖŒ£ã§nÁüŒ§Ðx<8ßHn…rð±c¢�ÇF¸âëÀ—fj‰ذè [;× ÊÏ-Ç•#!&æ6¼h}-¹‹Ø‘<¶åÊ‘ýE×Yiti^°(÷u©$§p"L>=KXìÜ ×wæ½×GðƒÖŸóª'? ãцÊì]ò„#F'à x*3ýɥ݇¯ÍˆÁ™õ~|wÓ œ#qd‹M‰°ùêzðx_kÒÈjd¦v…2¦-:rBÏ^"5¿ÈŸðU6«a´ò&nˆþÇx3ÎÀ£kW ðâ¸ä¿ž)ÂGÝçÞ_W@Ôʽ¼Iú„–_ÚÊçüÕ©ù˜1¨àÀç—éK�2ÿ¸’Èc�ïCHÚ!©¯ÁÜí.Ômȧa oùÂééœóD(û/]œn®eùص¶BŒ˜ÿŒ|/€¿¹ë©}‹Š½î"G(›gÄ,–óôGˆÁÿXÔ-*‹ßÎY‰jFAËTÒ£‡¢w½f®^Ï»þÆòqÃG°D7ª�®�ä#ó1õ�Ì�³@ýÓïÁ8‰Èd–·`Z.ßZàÉÙש씱ðâûkŠ8VöÁ&h<¶œŠõk¸¯ƒ;::¹˜í0}çrž¨S–ß—¦á# ×lváÇ‘£ÙúbÔù{!:UœÃÂ[ð0.œ33·ã^7^i¿Žë‡á9‰.ÍkQᙡô¥ù;½J‡ ·Ç€ÿO9LÎ[‚à§ÍG ¦ÀÄq¯hlbšì¨L.?èõªDì¹ÀN¬Z‰Å'¯ÃíQOA7oÞ_Á·oïÅ¿zƒ ¨=U–|¢ÏÕÚ¸E>€+Ç=ÃÍœé|ÊjÒÛÄÕ»v€KŸÍ +ù—}¢+¡WÍTJ[~Ž«=R±’,+zÖˆ?*s° – ºÓ‚¿’2¯Ÿ·—¦Ë/äÇW-Ðí±NRDÜð£šå¿#¦#°¸ºŒº†šò­¼!0B_zÊ@wÏ‹ð2LJ5âfóMãx^öQì0戧 ù]¢] _†{4×su¿Gd¹ÃÊÖôƒiO½¥¾§¼1>ï$lùMM !ݨ^r9ª¶¨å›. ™FÜy£ŒNîŸÉiÿ äºñGy…u¤Ž¿f~æ´Ç¡ í’Ø-/ §Ü?MŸ¬'a’÷J ߦ þë’Ái]1$ëÅñÜÞƒ±S/ž'W¼FT ÔxÄZh5F¹Ð÷âK `£î7ÜÑ-ÅåûÄ¢¼*èµÄ‘‡Æ–†`Å?v+T‘a÷´1PýùÞ?ðöŸÏ…uÃæá÷ÕøÇ �8+P/ìλÄn6ý0ÉÞ7Y.‡¤­wà]‘®ÔíøúUy…F>]Å}ÇÂÝ["èS·Í ¯Û òïâQZ|‚w<ù„eyê<÷Œ:û)p–ÝJjS =;"Á«]‰zQ½`*þÚ݉m.Œgx\~výÁ4ë5Œû©I¯#”ñçé*¬ Ž }–ðA�%B�Ö[ʪz=P!Ùc/;©ÈXV´*¸õã¥#æÇ²‰÷e˜»è eÔÜ„+½“ÉiŽ ž+³æO š||ˆö˼D?Œ-°È6:Wíæãv&˜búÖG=¾w‹n[,fÖŸM�2Îlš3K4Úül†êrâ´=ƒû8¢áº©°&@E�ÿ<Œ•'‡bËÔîÄ?G¥€¸B»�œ´X·m¸8¯O39Œç†uš¼¹ÿaÜcÊr� 'îÃ@™BÚS£ËÛ^ÚsúíDÎ12ÇYÞÇ3ßÛi¶÷~;) #Þ¶ÒçïhX:n°æ¤—vYõ è[(fñæçKÉ]vx¼ùE×4ë‹]\J±ãÈB”ds”]2KâÕ…ã·JèØ²iÈ xîÍîâ¡æbÑá«FDŠ&·­Y’Ço{b™µ‡¸ö_ï|ýù]IG?tE­£TKË…«-xêç¥8GLá×ÏÃy…b*ŠëN£)Ž ëYì0äÊîŠl=_“ßÔcÇyÏ©ÿ�@úô¾*¶s›¾&¾³¼²z¿9¾�,ö¥ó¹óÏÝp©0Þÿ:+”a�Š¥X´´¢8>:�cF:à÷íOÐI) J5Ù{ákòºõÚ›øˆûgê¾e>ȆNeù” üÛýš˜Ûs%ø„­¿‰X“’„] ¹K"Aí·cÐGÍkÌe•rœaRBëGY ûá!”¼{öO‚Žë¡TQÔq qHà{*N|>v' Ó9&Î.WÇðUÚUÀvzRQa Öü¶§KShmW)]y°ƒ…=±’Þ+UQi~3ôh‹ùâøþf/“/ÝâÇ¡|åhü¬.·ŒdÅqæ® è<õ’ðy²—ô-iÒÉ´¨ký›xJnm¶äH·NÉJýørð>NÙÊí5½q¦Ýi¸ÿn5Î�Àw"b±þç8¡`Éuxã'¤ÝÆ¿G@``yqùÃ,üœtm ¤YsÖQÏŒëàṪ´·âþ²6aÈçq`—ÛÎËÑO]»$êq,Ž;·§%ºòÙíÓèO[í Y„ÌÄó©«Èªü\Rë ®ˆjÁ#ÝPº’áÅøt©Ùçá|±ó5ù>—`UÝ[hlÈ–¼<±Q²M–Hޝb« ¼rÝþ3ÄO:­&N¸ú;êŽÁÞ®éØ{ç:ž°Æ�Ìgy`ÚÎXJ¦Ê>ß4H[O‰"…UŸ?QˆW8›–%áÛÔýü5(€�=—r{Z K/\à#ϵDYýÝÒì¦í‘ç€ùµÕœ>6Mœ1ît.¨Â!ùâÖø” ñ �0 ì¾OxX£Ç^V·EÙËš\Û.ºÍŒ�§�ŸhÄA›9 ‡N :ëÅת¶ârûhÚ›7’'+ì䞆[ó” ðüÉSl5xÂå“R Q�Ðj’ŒÅK7àíaYcF6Ë”’Ëü³¨¼±ƒFl»)>6·àtõT»,©?Wú‹`RbŠS¼øfë3þPÆÇZuqÝÓÍ\˜ŸÀ“B’qiy2VýgÈQ�QxþÆ7òÄõ0lÂ!jU� f1Î6S°´Œ®ëÝ�–®uø{·3¨�ÚŽ½´zÀŒ%SxSÐøÞï K�IäðÜ“ÕÚvpvêqˆ(Kæ+–ôlÛbj :ˆ=pvŸfþw³ÅT;ªA0YÙVC¨‡ì^ÌÌ�ð õ^P¾¾žTwÇ?ÃÁxŒn¾íO1-ÿqå|}\,wÃ>OåøÃ{ØöŠþJ~#¾ùu?öPuþ_AÿÛh”½M%¡'„y×éë½¢µƒ:=ü÷¼KØDüZ:›RÛIfÜIÖ½SƒÇžtÒÛ§£é[Ä¿û¨�…÷'úQ�þhµ E÷ît°{&K7Å£ÐÛ�ƒKþŠæˆ)çeq æÛZ8êö“’ Oñ14Æ/r¿…ný´Ùòb…û"WÚ)£œE-fL³†Æ\WéÏmT5[†™a´ä„¼u� §Ò°I!U»!g ’g5Ä™ýÏ¢êÎ[‚¾¶6uû,AI_œ²8ÃŒqÝ‘ 05ý;Ô¬õ¿ó[þå[KÞý¹àúø,öŽè�3×ÅÃÔÛös òAûO(Ë})d›^%hSkŒ.²}(¥ê�ì´$M±”«Öü�/¢�Ôdv6èý^̵zѸ˒e.†¢ya2=ªl‡ƒPCL~ éN¢Z«Õ7 A-ß$½W¨ðÈ�Wi³y/¼”¸¯Æî‚Ì‚:þó8´ìV(Ù0yã…^»°F÷0/èˆáæ†hˆH‘‹fÞ‚„è²N¿ÿ ÎÍõbÿðfXv­^´þu"_èb¥?—£¨÷ž­ÔüN³còDs­)lüÊ©z^ï²wCÓÄC¤ZÝ�äμ¤TK[ÔÏ”Åà¹30iY•ÝÌ�Ï:Z…ty‹ã_Od‡ÉZ¼ÙÐ%~Y’¶¿VXrO†ËÃ;èZÎ>vzuóŽüîÝùW{(²ý“0lOêÁ#WóĦT¯3õŽÅV�7Pp«Dìÿþ>¼H ÇH•ƒtðwŽ÷I'ãsƒ1ïòþÒ(Î,�ÃRÍq}`‘8wlÄw¸apÛ,x7Ü’‡µ¤ÁËÅ8Ö8¯Wˈ“¯¯Åv�Vˆw>ÎÓ‡Ýà¼A;¸êœ#i®n¢Üƒÿ˜JÖ�_­y‡n‘Xì&ÇsebZ’ v>}*©4žß縇lËÂwP©Êw|îÒcß«òÖ{¹”t5O\9Ä ³{Fà>Oqàëôlƒ6gµq¶L1Ý>·ˆîßÒ >UK(Ñ�x{o}êþxzW)ZUÊã¥?Q¨Q)~:7‰Fgh káà!E´µž�rz4ÑG¿<”C÷´vh˜û<¾’o‡ ›ççà�´0ñü®Á|&L0üAt}œÆ¢ÁÒÕ¼SwÛ•ÍÅïãO úŸip:Õœf'Þ�žÍõ ±d¼~;ŸÐö¦ÞVCã»#Ñpˆ8šƒ…�‡©§}8 þÌç·¬eç?/ âSšPQÙ*öTžÁSŒº¡eÛKø3!…Tvg‘rçy­'Ú_0Cß6k×5Pp´�Áø Lïy[\9ö! o £z£Ršï‰M£&qÂÄ(>“ÃÍ®m➪¡ôúØ>†œ©xxq¦Ö?†C²0ñ¬7¾Ÿóž–Á¥Þ3¡È¾\bÅϾ¼¢¡ß•JÜàˆk“ðI”•ŒdóÂ9Ø7Ö�ç®:¿�!#˜„)]°÷Ó}!zy7,öèÓªîByÐb¹Ê üÅ"2šqU4w;R@�›çA²Å6|>CL_'DfÜ”*Œ dUµßBk�VÉõwqèfÆn·ˆ_¬äy€k64+Ÿ‚ù’¥ü6>Žæ§éòºµ^œP¾& XÍ£wðÞ¨õ-Œ/œ¹Ä³<‡±yèØ;Ò»ºŽÃ �réÊà @+o}3ì‹j%:Ø´Û WVŒBÕáãxä¢|Z^Y{ú Âmã� Žªâ2Ùå1c>Ö© ¥ÆèT3ƒ{æïaËrY<8Nî Ü 7_&_.VyWˆûOÐ+ï.=Zó‘ŸÑÉ1éÜþ¿¥WWJ…ljñbô…�bø¹sÔѧÞ»yq®ª&ûï‹BÛ–ãuÓɼ^N—?í‚ñNÃAkúП‘K¶çG3ú)fEã‘©~°ÿG_®;`Š*öñÜMèŽc[�A¿�½ØÁ{7Ê}Ù.½®«O»�¾‡.á/¬«1¦oÇ ¿m¯�ãí�£0jÐ ,j“çÀkÞwp"_r¶%«úüY™·ŒL£,$ð¾¼qÎI6`ÅBœ0¯‹N/Žã¾JJÜèÛ‹õVΖ,x?EçíoF?ƒ ·Cù�÷?Í:P ¥¸Ç½8qÚD:¾J/3¥ƒgT)Ûr3/9ÛNqrãVô¼§ÌÅÒ×Ó…5j=Æn¶¿‹/�^•Àdç\!hJ»šºƒ~ZÄ’­›3_],ƒ�ž¢^Û½á?Ý<ï› ÎüàÊ=VÌG›¥ËP´ÕÂè¤#¾üÉŽÓå°Èh®Ø?[¬�KËVÝ£·}yÑi7.,‡qAgpÛý$ñîˆçÅß®`çë6xAÑÜníO ´Ø‹JSåQ QçÁ9Q\÷hÄ�„¬)Q>å\ÊB7óÕ0?d¾xu•—M5æÍµhˆ×$ò©‘:öV£ÆùºÐ-* gEWS\Ýx�ݺ|\ªD§Ò£ä,LˆôsF‡€Z xõ›Ô:àºÍ |›Ç<üE �L\Ë:Û\á~н)WMÑ¥Y¯CAGõ?8³í9ôu ¡³€ïe¯ùá„®øU`'"œ3hæÍî‚c�Ï~Av®0ó³¿püH&3äyÈÊ^Ä+º£j…÷²¿?Ú…õÃ{’Ls,Ïy”Â+TàÁ¼�üØ¡’Üvòˆ'²øûFÑ?_€ŸÔǵÁOÉK°qP²é”âÝG©ÂF7Qrmm6nS4FM=ÌÙŸBWšU0ñ¾.�ç‘ë�0mýKƒ¤ж>^š5‹ŸªKefT‰ ¿Õ¸²½N¬Ã�µÂ(ßl–å4»I“ðÁøŠ6N½y“Ðë{ÜrYÉWÞijuâAOï©ΑDGK�ötƒÃƒ�`¬b–˜  â¾TØg^+¤¬úKa~¹pW{4mú:Cï’å„RiÕfí¿“hRp}í̧ô‡ÁÔ6LÜç+ŠùSÞè–yì¿”3Þ܇Þ%ùøóÒ'ÒJ‘.›"\¼É�`ꊓÔXíÉMÚbáFúügh'<Û+Ì ÖÃKÑoj2�~`Æ×7>«a®( Iæäw`lP*Mm÷+ßôV{Їªã¡ÝΑµJ¥úQ;ÑöY¼ð'ÈFm|,:lò¡âÛ7Á錌 £žBÊ_ÞØ}²…_¦T�kO,«êIæ+´QÐZ†ñk7�íy[\û%�‚¾¹bþ÷q¼wÄñFì\¾ö‘´.& ¹‰sønš%O‰Nç½ R ¨ýÕ� öã"�©,„ë_úÀ¬ÄøõQº?aÉsZò@0›e¯šd¹£½®{A™SæñØt¨ß7z5$–逸¬à³X´z<÷×ßKù0q¨,ˆäØiº‘þóú#xX¯á¾½îÒ¤hoV—ßI=2‡sÏeäÔk)¬•`Ë…%<8T޳ŒÂ·ŽñðR}'zY†AÞ n¼íM…àÜñÄâÅ’í:+(­2䪆ÃýgÝp×asòÁò?Ü)Ô9¤^¢Ö‹½ÌP»Ò� ¯åW£-QéwøÆ¤¢ª»-ÞšiÀ÷óMaíÔRš7 g•¡¿‹…®áå0ºx-›8/真àvúÜxØ GMJdýAs(sIû’'ÉOBº¥çæú3+¾ƒá] }”#7šMf§oKø•š'&ÈÛcÚät*K�ô2+°÷SO»>¾Öb€–©ø½i §n[Š¿Fúñ Q›zwÃЭj%+‡é‘Á^m¦—³è£‚èümÏöÉ—æ¯ÖÇó×*Åâ´ýÔ?Tžœ  jåþ|pÛ!^Ð…°eP8¥ˆ«2Y^_™R®½ÄaŸaĉ�<òâWZøã´û”‰6vª¼Å3¦õãý2¨1ÙG´ÿ$ÁȤeì ¯?�EµÞ5¤’ž�^JF¡Åz0‹NGaù(W¼ã®óÛz’¦²,~½ÝkHº%  �t865½žñdôูµ´÷²¯—ïO¦÷Ö9z€?¿÷À·¬ðä�˜³ä¯t†8™ëâ’öÆ• ff„ñé8ôv“àz~ ¹pœè6öLÀnv¿Àô…<ôZó…òµ¢q×”[ô[A Ì„âyÀƒJžn¢mëú�Œó~Ü}ö7¤Ì…¹Æ·afGÇÿ.â Èw íu–<.TC7ƒ›� �í«]…_6ÎTçQOlî�¿lö(à‰ôEŠ˜œ•'ãˆwº³žø·ü,å -óê —† £©ß½yúöët�Zað‘°ë])üL§c »ã˨Á|­n¾4yûD�‹¼Dã‘ ~:ÈcÖäòƒOpe¥ ¯Y9˜'¿9]ÜOóÅ[‚‡ïã°—QÿöÚÅÝbp“Fü™#¬ZŒù>¡´r·T éª�ÝþÓ圛�4hs8)ºŒe¹äBÎÖ^ χ«`ÐÅ<ü™6w˜RæÉR*W‹…ļ§¶�ëA[·ÉÛGüc—cþt¿ÖH˜zx>Ei‚Ü·¾Üï�Ù£yз)ØCùO “þŸîyv==\s€m¾ºÃ‘Ź#qƒÂ¥JB·”St}´²  Ëv!èV¸)¨ÎÅׯöÁg—³Bõ"Wý½ŽŸÎ‚?&™l°ÄMÔ2s†ä¤Š@{zòß$¼éu—ÜÇ÷ÇmPìÐS<ÿÂÙ»£Ry*îVTæ­í‡i{—9ÿ”We®Þã%�s¸zu§ôá— 2ù~ü äÞÃÀnˆ"DØŠ‘ úðÌ�oñv�ø¨pÖYTïá±sÃQÑ&‹3ü°íIwVm ¦V[¼±6÷Åhà(ó甦jÀ»—ü˨ "ÜiÁìn.Aq 8š{‚ÞÓù—Úhög ™Ð<õc‰0ǦGiü„ôV³Äv;súoÃÜùxž7iA™ÀCÃ÷Kæþ:,š®TG™K¨›ýϧ¯ÃqûÒÄ_õ¢ÕǾqÖ\ö€Ö'àkW,0š.ú'ç}+#EÛ^m8çÙ øûî�¸{˜ûI±W¿yøb½?(ö Î…}PñèTø\Ñ ›žPÍ�Léï�œv·v sc­ß�h²é¸ æb×`.mÿÝ»K}þó#å}3ØÙ²B¼v5Êï7#9×w‚Þ®çØ¨­‚eî0-â7ÈŒÑóßçAu·6(Ÿ!³ks§›ex‡É@òªYhx= ‹îÌ è�¹Róž²,ÿwžœÈ“›.òÖMûh‚›}�üãòghß·»¢äQ3�X¨Ææeªè½¯œ&�ÜŠ81Ef%Ô}êu)_P–Ó`ûŸ§‰‹¾ÿq­Ui#^ßï¹ã´—žj†}òBsÙ~ðøì&á'÷‚¾æÙ0%d?ܘ7š[K­ð…ü{0 ÜE}^ÈÒF»¾¤X7€¿}Èäˆï_ÉQaæ7m}ÿ"ðé7ˆß_ÊÃOÝ·�Âg ¸Ì»Æ•Å&¬Ó%'yâ~ó?å‰îÍõ°ñ� ]÷øé³l…êïÓ±çý"š('ÇoY I»%7ñ…‹£Þ=ô༠ñÛoèÑÖÿ$׋?G+°ásö�²æŒe1Чì�±Ób¥©#¹xÞ[êðhmÏÆ]ÏãÒ´�ذo¶$=i:­1ÞïÛC(;ÏGT-Í £†¤�¶2×_¯¥¡Ÿi«íCˆý&Ký^¶À%Kö›p úYðëu!8GLK÷pJTN¢›w³í[¼y¥ˆ–7F ÓÓEX -„ÆÌñ|žDqAÅ%aî¼õ‚ÖY,{^ÌÑÁ£yƒóü;`Lj°|ÊÁaÖZk;gY¾Wvcý üp±:†�Äžóë(Lï)KuùôÂã°nSw>ú²‚ïßíÁWÖ\Ù�lª”&~È…z³‘lºã»ÐÙ§¿Tq޲8§råo}F�kÌÙ¯«€#û ²a·ˆÇòëS&ä>n‡X¹Ëšÿ®Î…£ÆÓñ²VOêŽÜw°5Þ�= ¼:Ø%Z™Kóª÷ó‡žM8oB'<ŽKGvw§boª1�§îg?’鞷Т�ÂaÛ§ ÷÷¼8÷E$ï±5geåõä¢ëu[ g‡ Ljƒ¬“‡i—W³páî8x)¨PQa}تÇ=žµBÙVYˆ³ÔãÈÂ,¾›i›)æjès¿ÍÁíç|o�¬ñ‚tu2`\B!Þ—î y¥0’M5äý^ÿñú W¡(ø<˵aOÅq¬òd_ú&é<º”J‡ÍæôÖ”ô6/_•ê3ñcVoÞaêˆý%_ÈŠ�‰‡¦®d»DYì¾^ßJð�Ž._ÈvÆý4Ç¥‚êéå8¼*›Ÿ‹ßìl>éPéîgðÁ@AzL;¬ÇêâGƒ%ÜWÞd¿ø?ŠÎü¯Ç§‹ÃQR*¤Ò"-JŠ•-Ýç”BЬ¥(Be ‰ŠÒ¾P‰ QiQI¨>÷9Y"‰"kÄ—ì$!ûöxþ‚™×Ìœ÷ûº~Ü´@žŸÀP�qü%lr4Ä5Ry8âòhÞæ Ï›VàW'Eˆ}šƒv}¢\‰3ψ�ÀžgßQ„QLÿ9–qCü äð^¿Ñ÷pN8¼‰ÿ;zZ²”>�«À—Â6sø²éüâÔijûÍê{ŸÀ ãCÔ‘ä€z»t1ìùqòsÖ¦>GîŠBÖP‰täv~Àxæ#nhn¦Å-V0– Â[�ˆÙÙ0ðöSØ=â>Ìõ- <çüv!‹;Ìú�þÐ.Ь?un <óz�}?¥!oxœÙJN¼o†àèNÞµn8eá¹›|]-§Ö é›D v‘©]Ð)”É«‚‚à�wßrHözÁ¡òYRØOÁúO)�ÏÖØôã·îqìû–�û¥iÿ¦**8&ƒYà�7c9¥½\’�ŸÂ½•oÂcÏÉü:õžP›× ¾Úõ›‹?©mÛ%òPˆåÉÆÊìþЀ+Ë öÎ~6þYå1¼R/ŽþKL±Íqb,ný‰#ÙoKÿ�4˜�³Oëˆ#¬ºöϸ²an�™+¾U¼Ü†å¾QxZ8Bov·Óó|k�5iŠ֎Ÿ‡ Gø®¬«f5ÇXô�?€÷×7ˆ‡n  B8ìq�ãi;ºIC9‚’,k ûíO¼ÿÝ—ø¸²ŸZI5¥ Sþ‚¶¢"VØ MÃÉá·ü_p|ÿŽ]y•&ڦÚ©}ð[¡:ËÜŒ¥sÆNÂ�v7l·0å¸�|ÎC™A)²äe¥ØcÄ /¾ms†VÜ£Âű¨¾c8[VCúæxŒñŒÃÏ%àdÅO˜³ï\°SgõŽhÌßrŒJÞ™pY÷EákÎL6µ-ãËÃ�ÈܺAè\eƒ¦“þã˜zoæ)'À&Ü·æWÀBñþ’^¸Û4Œ~Uiòè¹G±NÀ×–rîÀåÝ„w^Ò¸ªh:^:F×4ryÔ�$ø©c¦má�^uôñ@íX4‡}VGmm_”žh€µ6ît5î|ø¸ ÆÊ†¢‡Ñ‰Cæ\”O²›cw€¤5†ï>oÿç¬=ùòC¦Ž�Ñì‰AÒ2‚K.m[î<†Jßá^­>%Ú_�ÕŠFpÛ~,[™ia”o6‰_5Í`Ÿ~"v Å�K–‘¶åa÷ã-Tª} fÊLj'­=«ÐÆTŠG˜(Á¶±Kpôó)byèOún:ëŸÝy­âûÓè’�=¶ØøòçøÇÔx}ýL,áÖ—id< JU^Nßµ¢õÉã1z‚ÄE„Á® }aÄùe\ýú>»=o�Å^×YßP ÇO9'¼”‘Üq“ Ö}´÷âaÙʨꨂm*s$ͲõBúÓ ­@♉WAga8Z¿)°ºm&`Õ“ÛãßEêúØ5“Õkðð˜q³Â~¬Ä½ÐpJƒ´jOÂx6ð$6ûDðÏcäòå�dˆÒfxû EÓZoÁâ¦z¨ÉÝ 3J¶P¥òñý‡8é×>a×�lt‘Χüñ–|Z܇׳–`aM³˜×™ÄÉF-Tx7^œu{|� ó…x¿íü§¡‚²BGñÇ%.óè£ zbõ¹@!zr_Ü~§J†¶KšGFÒ±-+ÀP-U0˜{ˆ >æQt[‚«`ÛÒé¼Ïn2^²»‰G®|å¤wð¦{èâð&ò¦�핱 ü¥+ ¬WŽàF9wa§Ÿù|Cw—¼ã6̇>‚€£Ï(Ù ‹ÕðtW|4dx6Ëâ‡´ÝØ$]ˆûwY`R?L÷ûço[SÇ9¦ W.\¶uõ7D'廜9É‘cÞ… ÝÀN±e�7IËTÓ.Ëã,ý¥2œô±ùÚ&R9Ä-}åx‰ƒ€cÌœqš£*ÚVuã‚‘¸ª÷xÖˆr¤³ ·àFÁX­žCE]©øQáÅ_˜ #Þ'sOFÖ�g…Ëñ«¨tZ³Œ^AÜ{!êÍ,=WAúz†BrÂh¸îÀ™# pl§%Ô„¬àä­NðÛ/‡^¦i²§Ì`|©YL ‡|o餓ý=Þ?e?ôÏ�¢‚×Iç¨<ƬHy©ßéÅÃÅìÿr/Ç7îƒU‰oWÀSÈ }þÝoàÌ?’Ž[«)*h�v>’rÅüÚ.Z çEÒ ïóÂÝΉà2~äPÖÙ<Á7�œ5`»Å¹¸%æìy³“£n¥°àåËö{}qœÕ^IUÌ ®ó�'»­YTp&•“WÂr—°;£7¦Í’/ÿ#F¼!û~Ãð«œæÇ‰ ½·sîÇsœp͆[•ÏAê{8;§„ÚÕøVº<«‹7[?Ò§* üxÐAKN@)³m¸hÇF^üü2E:-¦¼™eðqÁa�ÏfT ÷“ŽÏ°öW&ݹ6—»¢aT×p”šŸL)ë¤Ðfí/óö«Ø<QYÅ›_jȱÕço’Zàù=8ÏÿÚxAOŸ+�Ÿ²›¯HqZV7%C·ž?½¦¡onÑÒwmP8«–šãáCf<"é0 q¹EKªîŠ-6v<òàqï=|³b8-ÞÐwW›p…õ zbd�µÅÑÍOé\�ù‚JB�&~£Ykìn4Öp¤éõ‹Pv÷ vòÕƒìT t_]AC"6{“cä|ùQ÷7ú ùõžøzûŽY�ÈÃÞ6’¿ò1î7o“x©Ñ„w„¼£sGà†ª ˆ[’Ê*;¸M^Ÿ.�à…‘ƒáöÛBÊØ�ÅC¬.Óµq‘›sî—b¡8«n†bÛÌYÂïRPËŸÝ’ÐÄâ5ùy@áóKà•k Hm^ŠmëÍqV¹)ÜŸ¯‹ýç)aê$- ]#Œý3ƒG!�]Ћ 9Íösy·ÙA<¯_�‡6u@óˆú%.ÂAqê ÎÔãIŸVIž„´Â¶Sól× ‡5óªðeÁ4pûJ,Ïo£O™•4åÍ»oÂÖ³`/ ðѸüOˆ�Qã½Õôð\· Á�~3èkÏnáPÞ=ÿ³ cÑÁkòó‡ª_WàË�á7œ/¿�= m9oOаtS8ÌnÞ†Š &±6œäG ñ¬W55:œ£ âàãU\\ùšÚK§rbönZxÝeŒFÀßßqt8q—°¤÷%áÀÖK0^Q§láÏ·‡óEÿ˰rövo„ì¿T ç=XÄ ørãsH÷ŒÂ={e®iÙözRRxÎUñ¼­*†æÚð‹ÜËb÷õ—¸×0Ž%G£…-ó ø}Ü,8m2gçÜF ƒi˜øP¥ä ù¡×€ñ7×WÀð—D0üJÛgbJ¯�|ãH\ó¶”{2”ÌË…2Ê䔉Z8`iÔ¸ú�¨!Õ‰9�£þ)†¢n¤;™÷m§¨%©4óÍCh ®ÁÁ7'²Ïö:ÛÀ–QxåÏXê.!W›äaö¬76±mï*vý›D's\(êC½X¢ƒWƒ×áù”:Ø<Õ•/_dÕ×P}N2ìsÔÄ~çö¢þ¼t.,<ßO\†ÛO²¨,ÁšíÏp¡µ=oªtâ¬;Ç�?a4dLxD6_JCzŽc�®þµæ*&üüë<>&€ØêŸ”ít�\£á,ý,_;g»3O+ï�2E™Ôâú Ž©!œÜdŒÒõKA±ºŽ­3Ç�˜JX03”¯Ý¢ß¶3…®/„�?·`Š9p ió½áS ÍÑ�ß»ÅbÓ•8íÕuÒûÙƒ&Mìø–‡õ×,ÁÆÿWþÄž}ÓÊA­°N~IÙÁ�»¹vÄ Üg}�¾»a鿬~ÌʸvÜži:·ÖoÆñ×\m¯A¥J¦4zª t}í‡BÈÛÅ­f>–,Ïðà?zÉøZ_‰ CGa[ÛAèñH¤|›‹ S%‡×üÑ„e:Øþñh® {Žª¬¹QêÀʺ»ù¦Ãe–‹M ŠÈ*»ÓB®eø^Ô¢ï{ÞÚ~‹>@ŸZ¦‚Ѩïôý¤ÿðÈwþ¡V\òû%;‚Ú KQ5´�^äMÃ׫GóªÎÉèÎn|bÏìµM�§¦ÖÚN¾«ÎZgå9X¶Š*ï÷àî�v¨;íMÓHY'y”ˆÒ&±|(3Eô?$�=$ÙÐëQŽ��g�&3É)íS |õÄyRì7rÈ�m¡ïSm±NlMÖëp�J>�ÁˆÚ:™j[ö¢û¥a¼¦_¿:m þ’ÅÕv²úr“RƤ‚­¿©P2T‘­Uáà"gÿ³Ðå—E5}ƒñ�ßCR>_ ž;y&¯Lç®ì@�qÙ�{�Eÿ¿‚nê@1dÍ7ø¶¶ƒŽÌ¸ ]úøeÏx¡tÊ´ØXLë÷‰ Mâ»1óyç´)8<é´ì¬¦Íy Â5ý$ó}/�7Ž']ᬾdHöŠ›ôäðvÄfªMOä;%ÄM�Ä>%€¥“}éÈÆ|p>úÂvgn»Ïƪ7¢¤q´#|Õ¦ŸÍÃV F!¥„q[Þñ�!Ò(“^'8 p…NýXŒsm†Ò¯‡2xæåìî7”•¶TAD†„N�F~]¶Í:FÀ<�«ô£õ/œ ‘âKæÓ�X9©KÌX¾#_A[Ï%Xí�åóúq¾�=Ú8}¤Ð c9Tì « R �s ð¥2ÊïK¦Wç~€û¦p:¦ºŠnºõ„;C ±Ös%,9"�_ø•`Ã4bØxP=XÔèMµãîBé? žw€w7:Ó™Ñ÷`î¢i↞_Ð|ʾ3f4„BȦ¸LQôN¤ÇÂ�}!ôeóý‚.[âYööC‘³ŒO½*À§OOÀ!–¾Zߦ$Ù�ì0ë9)„lä~Ñ5T<Ý‘'¼åé·ï²Ì®Ÿâý‚ÐÏó2¦Y æ~뜹ٓñ¶S+¬ÀrÍÅhs¬P|ûÏÝÕb“IX>W>ü�:,öSè‹2°ÚPBƒîÀ}]Gº|XÞŽºÈý‡´h è—ŒDY¯Y\½f4- y¥.ðà%éLºGfa̧ÕÐCw‚àù³?v¶mà^7*È@õ°�¾?ª¢Ù³F�t_ªñ¥$”™·‚«.´Š=W�ãU×3…ö¦\;»Z»eŠ`n¢ÃáO’…-nÉX—r 6Ž”G‹´W’Ð�oÀE„õfÉ|wƒ 49®æ÷-óé‚ëbî=$ߺñ2â´È÷åf¼ÃiÔ&þ°é¨8Ñf ÉÁígäÐ=O¬¾ÁªÖƒXg›'–ç÷Âgºˆ{Ü|¨åw_¸[1†cUN!fÀ†ºl’;™ˆ‹þvÓò©1t‚Ûàó_�Wa¢©>ÜÙ?Ht]›Û ±v²!úTNÂ÷ê±~w à•³”¬ M+~S«UëÁ¬ñÀ&�é¶=g˜‰OS2ÈÖì½ð8K•R¼æ`§ö¿Ì;ÓQùNƒà!/�5{UÙ³O�;O‰¸0z2v¿¸þÃ÷°ú„ráÝIkÃÖ ¿«�ßk'V¹ž‡>Í�8Uíè._Ek«±Ê¥¾ç9ó~î -òLç]“‚¬7�…CÅÙdÚöš:¶hBÙXGÞmkËŠ·Ÿóã�È«k¨ñ’‘Ð=¥_ÖÀð�&âæŽø±ËŒ‡Ý^�nÓRøé®÷â’eMô¦}þy‰ïÞI“‹Ó6qwP%MîWC3¼awr[«EáÐû—è¢z0) GÓE |±‘ p¥¶'%Ï`éyîtgøQtuÍáUðð�ŽØ>áÀ Up”õ"]µP–n´쳿BEò5ª>w”�òwñ ¥»´ÁfŽšÀS®-æñ‰{¡oðZü2%„ö,š$»œm®æ“ÙÚbÜõ£œh?‡…œÂ×As þÓã«Þ;ñNY•<Íay�~ö8éšZ€Ý¤lIû´¡kT¢T °WÁú#—ðÁ�¶ ÝÍàž‰ã,ÑÃÃ;§¬æÍÕô:ãáÖÚfºàXɦ}¾Ëz`˜•ÏYnŠn½lÙO)�ÆÐÛ¢'ž¼©Èñ÷¦±é™T|;Ùš«§¦ÂšÈý<¼ß¤ù¾ËV2T“3¦DãrŸ(žÃY7c Ì$�e­“ýýW Þ’y@ Wyƒº‘Y´,(@ôž�/H†ÏW^„ƶ‰,>±¤Û}ñ²‹¿®¸�Ó[÷ãÀ“ÇqøÌó‚°2Š�JßPÑÉQ�SfF‹‡´ÐǨiè7í QÁ!>z8�ÊöÊÓöúû°ca:Ú È¤%Û4ÙÒ4¿ô1“›£ðDZ£¼ã¤3ZO®€ßf8fz¹8˜~�¢Áb”Y&Í_;‚Ì?Þñžª‰É¿Oðž=üòÁ�™oÏGÒÆpø0]ö�zC–K\„;{ôÐîo?poÏ亚iXìÝ CîFÀÇ�Zh;)FY£F’©¸»¡L*gSw•ŠÐ_y^5•�¦¯ Ô7â;•+vB‘“; )óí» ¼/ìo~]£ŽÎäuè¼ã}«pã+Šá´¡€–}^ˆûaÕÉ¿‚âÝ=øÜÓýú@¡òf8¦Ã€w~J‡Û­'×yâÎl ¾3¯2¼(q¼÷tÛS½±sÈ>o$©Ìp°Ó§ú¯§�t¾›³¿]Ä�£ºheÎQuÈ>Ú³ÙÕ+µ±Ò4�viY`Eøª�­�9¥=yï•RpÒ®ãÐÍ{IñÅV|7 ÷|zAs‹¡Ûå\_º™¦Ü±Æœ‹9´®a3˜S?>¬¿߯ß�)üÝZU~ưnd5Uu/ÂS—‡sÏæVIýqi¼üú �Ûí%:É<€ûñ·èÆÓièà$ð7Ç¡¼†áa™'+Ø¿�ÖÞÊH·§R×—,Œ“‰ÅKS;m3œáŽ{RÙ2gªë K¥€K÷‹s'œÂñþ–ð|X-LÖº(¶X M‘‡Þƒ’ ¸ã}žîzÏá@/™BTuqxÕ‡ÒÔíÉÜãM›x'w¥pßp€Ý{Õm¼Ãe*úÉ`}í[0¨w‚÷Y¤ü&§öÙÓ�ƒq°]wûëlçì[Æ=z-ª,óGßLâocbø�¾=)î"ÕºUh~·�—Zôç>QãÅ(·‰8dò^|#q\듽üÚ7Cðõ(ÇšÕ ÜÙ_ šš S®8áµtg^óÙC<»É„ö˜¿¯Ò7½ O–Êó¬[wàØÃOðJ· Ö6¤“ô¿ù_ŒÆìæyåîÙòÒ°5¹f×ÓÞôDnÿ}©‹µÞãèÑÉÏàßË¥FXðQ`W}‰v£×—î‡Æë9pqÓRÌëpÇZ¿gPÊKö�¤à/qì¾l8fXHCJ¤2ÿç&eÑ�Ú¸L0`3}Ôr¿ò¿‡á»[Š<î°„*Z•�îæà ©Z˜x4‘â[àÔËN<ÉÂC¬Ï®D¿µQâ`�§Ô§²GÙ§Ò”·ýpþÁ;pr»&l3Z@ƒ=ö�_i'X—ÇÂ�¢4Zöf7º‘ÇMG4μAý÷óZ§*ÞØ§Y(•ì¾v–À˜B) ÊÇfé¶øfF7V}¼I}‰õÈ·=êš'æ¯TÃŽÈ}b𗙯ÅÿcN;îÛb‰WÒÊ�Áæ$�Ó{ºcÀļܞ 'o[ •„ñ%‹EÅ5ã0ôàÅInIÞ:â¼·Ž|&Å®<�C•ó…„­©{pÆÔ‹EIÖè]…xïäZžžÇÑ•Ï` ÿ) o�įűx+K¤±ñGaÙû"ÑÇy3¿÷¿‚7»špN‰__(Eg„ÆùôáÄ¡¨phíìöUðæ•:�˜Ä:§H{ÖXÛ`OUüðôm­ž"®Z£‹ÛFº{ø¨(ÇÆ7úÚé8DSŸ_ÝлoÜžwF\ØÞ9q:¸jË1!~¢’FøevU`•ß44|ëuNVÁu&„�íF�S¾V;>#å‹°:S‹í/×fã¼}pí`)yG�GËÁŽ,û`<ïØ™FÓìõp�M6Ènž� ¶ÑYÙûfjðšªï¸uíXmÙ¡Ñÿº¸®7g•뢫ÊÿÿŽ€îÚ·dæhÃi³_Ž0ƒþR`k§‘°éâb6�0Ç©‚ÿ°¬¡œàØ»…íb°ëôÞ¼Wí¬¨Bï[ŸàF¯uf_ÆÚ˵yO‘ŽxTÝ– $ Cý$ô媆P©}â. Âä+½Ù¸ö}lA#o‰ªGnH <úpåÞ¦hÞ«=”nÿ‹(¡õÄQd;g"«ú§píYG¸==�o]TÇ=!_AgâGîu“r#úò‘ ªYð”Ä�� 1ö&í/EäÐëBö› 8{sI• "Ƕ âó¿„•ÿ2âÞ-Y.<7›ôb¹Ç¥0£=—’‡ÄÒDA"š|±F;won©8CÝ©±A güÒáæƒõâ÷öÞœö7жÊ^« ._é³÷ö[äòÖ &ÈXÓÀ»oéW‚||ðg™5,Í2ÀûF·èªÙ3qâ˜:XXA²weùféñˆ…¾É ¥'ºŸáí÷Vi‡U�Pyò=H½2¤Já౦ø�¤>:Úh1~|Ú�¯”â´5_ÿÍÒ8z|I…ÍN�§áŽûÀñè+1Ý?5_{Øì¢…¡!hóñ¢ØóÅD>âI¤Ü»¾23œ0_/›>¼«Æ/0ÿï´ d.J�?F'öf£Îjøä›/vvmÃ6¦¡Òù_´`æ`:×ã( žSp†b�•›ÄOe™¨ó5¹&8ºh>ð~“ufñ¶‚LŒZûöžïÇ«í„ǓΠٗHsöSñ®æ$Þuú;Ø�_‡38žÿ�Ÿ£±s¨ÉìúM—JÓHfX½ žŠéï'Ñàþ™p1p(_X� Ëvaªô)^wðh�6Áz|6¾U†\Ër8¿Ð”/†åˆiÞŒç¶çkð?ãwпè&e4÷fwÛVaäj›��Ý9×}š¨Á`ÜèÕëáùaSRœìK!]…‚„ÒiƩܟ+’ÎÐ×åƒÑ§‡&ÇW¢×§‡¼.‚Ü,"xŒÐH}Ë*9ú{¯RÝŠmör XEðÆ”ç°ú[×Tø%ç?¬sØN†ëôÑ'j ¼>£Šo¦ûñúm†è:ï̬;Oùpìά‹£“oJ°Z‚ÔöÃ3YàÃw£@íïrã“ 0l!/šmXSÙæ+œßÿ�Y[дQÆ<ì¸ 'é'rêÂh2Äy¼%(._é€çkí$+¶JqÝcS<�ØL/ÔITzƒ1EËy´^9½Y®Ìæ+ûàmÝLÁìófÙs-§tÚáÐÓ=k7ÏÄäMñPõ<“ý¶]• -ÍAkŸGPàþ˜”“ŸÁ X�«ר¾›¬Ã{S°Çßdný>R�rσÖ#’gpõ ±kþš½Ðuç'(:á+dX¹‘ÐGBXlŽc]Äëk"…—CÃ`¶žâ¸ŠÝ㘗ýD=…¿ÂÔYîô£4{ŸÎ¦È��`Îì \èÿÌ÷ÅùÁ $VÙÚ\¤Ï¿¤KiÀžC¹â�«Ê he|ú×¶#êÅǵªütû~Hµ) ®Õ—`\ÞHkp…‡-…Xý©/Þ¾Ö�×%ô㯧݄•¡IB‹ãN~p-þ y%|Úl$œs^Ãkƒ£Ð¦÷,8úW‹“ûrpY|¯&zŽÑ`{3[£ ‘&8ùs·AMП̲C}ø¡×jôl4¿­yV�@¶ 5£Ó>ñò¡U´»©ˆ¬Ã�ùRëxn>åªrñžyµÐGaÅqS^ï_ Ö@)EPWíËüGè¿‡ÖØÓâ®'“°à…õw0"·k„ÏÝ'ÕíC…vÚÞ™‰#¿èbBhÞxïÉ9X_팹Ë“Fiÿ»ÔÂ1“øçüO$¾öe»Ë–\\ŸÆ›¬æþ Vh?Q–Kú6‹U2yàt½?¬�.§GÃg¢Ù¬�ÐØ¡†k¢Æ üô1e÷R^ZÛMò‘1`Ô�¶†"_SºFŠÙnt×|ÑáÁ)Ыý"^˜ÍÖÕ‡HÉ%g›äŒû©x}Üè4JƒÕV‘.†AÚ8e©áÏ™ {ɰ.ƒ�¾ïåömðßú�túÐx¥FÓ‹_šA%¿”y†›ï:uŠg¥G�{«ú®ÒçÚƒ1FÐÁ�…1OQ‚£ w=PáÐ",Ž*fÿÇi‰è>y.kˆAÓ†UXÐß[ µÀ”ÍÆpQs¿p–.t‹ž9ìƒÓN«iºß¢ñ^¾4'[+¥_ó#Ý~û©ŠFíŠå^;`~�Ÿøª¯6Ü�§Àã8¬Í†<·ÂβrÁ j«Ig†>5/ä%=ŸÛf¸8ÃM—&ÁÆÅŸï¿Œ†?Òùü {œû7Œ÷×úp·êÚ£wˆµúÛðb»6]8‚ŹD=¿…l´ùM7ÜÂø7€MôqYäcôß¹˜[„ápfq1Ù÷ÿN�³ÌQ¶¹…îÍ=Oλð¦ìb:| ×,Åáß¶ãrÙn(+¸Í‹©aq6ÆìtáÑ¥]4ªè!ÏïI2Óî¸�Ù5^>ÓiÈΙæU ’/òø¹\…Í}¶Kðú°tîg:õà›¤^ÜIZ…ÒØfì€K“›„¬W ¼ò¤¦Ÿ€M�¢ðõ“‹ÂçéÑxô Àvήœ¹¥_$“Ç““‚å¬ßâ¶ÚµÊ}ô±ÆÖ ¿6iâ™·n´²×`i/‹“ëçŠ]?”ðÏÞ ïuïɺñô‰¥�)Úp�o¤P³Á†+ÞK¡Ì›ƒläÉCžÙßœˆ¥Z#¹éÒfT ;-Ù˜UŽ6Ü¢úÅ#Yöh­Úc&ÜüTÉ^ E:rÐh:Stý7ÏRFIÜi¾(z‰ÞûÙidÖXç x8ŸÙDòë*¸ìåÄÓȲí×xz/O«1A•ü‰ühMœ^Vã×ÉÐï�—à±ýIö_¼J�ê€Û–/§ŠÕ-°_§–§«ó›$?¶ÔŠ“WŒDÿkcxÂF-´Œ”çþ‰ùxæÔ ~¼èEæÖ‘D«'N9XzF_$/Í£¤PþÑ ôù0IøúÅ„o¾Icòøü~" £oE4o�9WQI�< á�Öüs¢)–'>ƒ¶f+SÔ fnúNI³}xXßøY*þ.ÜÎZõ \2y!mB#þOW—=úñÂo†hçXˆ‡k‡qºZ<4ðA;}Ôu÷‡sWûØ%Y á$¯u¨ø²,ów‰+†Mb¹©2P¸]À·ÓŸ‘tV›×ôÁƒŽK(Ç{'eô»MÇ6š Ù¯¦cΓïp3²•Ï«¥Úöî€|†f¡ù¡›¬W_Âú‘å™��{à Í^¦ÌîsœñHˆç¿XÛ{:¹.a…1«¹ó›å}߀ǻcàü¬‡@c­Ø÷ÅW:Û*Å­v¨+ýUØÇ¿Ï_Æ%²´qõ*qöÑ(Õ;@» [ÄDƒ\vr›Œ;ý†RŸ†à?<�?8 0°ÞWòòª/;[fˆ£¬_Cʺj�=5=.NÅ…K¶ ¯—×`­;vèŸÊÅ.ù`6¼ŽF=‰–~så•{tqtX&®’}¤B Í6Œ >tp-I2 xäÊk˜˜®Á'kÀÞï¹ ÐXî´ÿǘó=H¦S™ÔÊðc <�šåÍ 2qdºf [* «4R¸8ifOÎƼ[�OЍîk~iô¥Š¶­ytûZÚN{ó—Þ¿�šåû`§Z/8㳜?ÛÇÁšÝ¤úw‡XÕ Æ¥¤®u{¯tãã¡cÙ3ÒŸnn<@'Ú6 3/& ÷~Ïd©£ýÐ|“ÜMÈç¥xáF56ðéÃ{g†ÑÍÜR¸¼hÿ·X•WX(£V=²iw4 â(Za"—Žª¥Óñÿ¶óŸC›QªÁ›Õ>àÁ!\¶“ºâi«Z8ù M¶­·-ØFiQü5 œ8 &EJÀDÅ£{œçÍgµù×¹vèuAÆnøVSðVª¤’wVhsÚ§èš³þ#N˜9<¯@æom~­%…‹_ºSá_Kj ¨'ÿµåâ@bqûM�Aý; ‚‡š¸žC÷saj¡ØùÃ5Ã~Ò“oR<¯;Zøò÷!©Dodß§7H*¹' *ŽÄt¥'”ÑÝÈF‘Þï~³Ç�0Àä'›±Ím3Où!�1mcpü£Å|jØ:j}/¡›²©Ð^ÖûÍMw ʹ»Ë«·uÐ'g7ûf(uä1 3”ŒCHúª ZúŒ•œ¸"AÇY}!ÒÞžß”MÅgšqlŸäÄUÝN˜]äŒ_Æ¥°éÿü¢Ÿ¿íXB›²=èË¿³˜=|.Ìn�F*‡GÒ¡sAè¼þ eÄ_AïÄç´Ñ|-ŸÞ²”Ž/˜‰vI êtÝú½lóÅaNú :Ñç ò¨-])|pv'Ißûà¸m?k×ãOýkqcŸ%Øë…;ÏJˆÁš•¶ø`Þt5ŸÌZ›?“λ3F¡®ˆµ�8`Ã*çø2½bxVÞiнØF_ ùïÓp X×NiþYä{òDÊ­‚î®xÈì��ϳÕq}âL˜»µœª�^Aåa?úžYËKmb ùý3*µ8M[VÇŠ¹iZ 4È‘‹?ì£q—dÅù�ŸQÏd)ªmÚÆ×ÂŒ©E2‰í«V¡±þUh7‹¤ŸõÆ\dÓ5¼?Ñ®Ç?D¥¯0wr&ݺs˜6ÚMçì¶±ÂnÜú.ú×8üÅz4#Ƨ@ŸéàøgZ¬÷Füélƒ1K²ÄÀ£‘<<.M´÷•!ÔE›øÍÎÍ¥m/;m—ëŒãêq‚kˆgä½"§>A¨Ó]ö*pÜÄPRªÅ³¯Â¾5:ðýì`ñÛw-®Yc"9éC±Ž]�úü‘V;¯)²Â­r\ep—‡çf’Õõ:4LzFÞ6hY#y›æ,Œ:а©ù<$¬øI™‡tøøÍí´­ã¼5è é?w >ïc…‘ÃÜ9ø½ œ™u:ºKðàxe±°Çcjî’¸.°æÖ·^âô?s*›iÆý&2rNçþ—?â±M?@¬)å…ý;©X[�‹š;Äí mpÙx7ì“ú‡$w|]ØÖHý[óŠî¼Æ?Ú¼K¨öé@žÔlı‹3`§e¾¤)¼Y¢Áîz#yÁ³?”§ ®œo�ÕnçTàÈ“¡ÜwÙdœ2zÍêbë‘ÕHüËÐ#h[FËòÅ|Ñýö6#`ê kxÉ‘o°÷Ž©n äÜÁ{…6£Élë¶J\ÐÏ{UK„ÉÁSpã›·Pk}¢ëüp×`UŽöO*‘]Tóèr�§µ+UéåÆ<GÞ�ÿ½ô@ÝìP\ÑÓ6XÕ‹õž†pùBcÌítømÌÉÐãrs®ð)�üÒÑÁ‰iòœ³f+þ휂R§Bø÷SàO[7cõ# ­5GoÍ*þ¤zV±RŽ‹ì{ÃÁ—Yh?½£aŒ}ýž.8*ò�‘»ðq±1ŸÓeøºdoyÖ„ãî(bDK=i–Ïçß-°Òw4ÏñZËÇw|˜>3Bz²mÁ%.‘k·õž·×*Ôá¼ÖÛ±>õ>—±ZF.&~=%Äí> —ç��á­h½k*ºXÌa™VØ*ýÊV«ñnÐÛ ^öÁÐwë¸.á1åW߇¦u¶,Y ަ¡ËI¶xeιrF pœ ¾4’Ӈ؜øÏé÷¢‹Ion¾v] ¸.BÜÑO”Ÿ6¯|™$¾|èÝXïú(6êÏ]a­t"_…›õåÙ(Ö�«†mGÑ”hÖÚüàœÃ×Ne}©]´ïÌV7·Pp–�ciá”­^ù AûU'Ïvá˯àN¥Žÿ”…§ÆÄ³¾g¤àj¯Ž¶šJáVŸ¤ŒæCdØfÁq¾{c=z”âw¬E£8LÞÁ�§bøaë œ¨žI3¼ ÑuøS²ýït–C¡-¥|ÔhšZú—hãA9KîžI´ÀhJ-¾n`>Š©ôóP¨ÉåЋ(Å·ª™áó¿®8«—_™8Ÿ«Îgà‘k:ì{ñšXà~•Ä7:�LæÜâêDÎÕ âõjSt¸™ƒ•ÏSqkU£hfßÂG½²ÑÊQ™¤Â²ÈVc6ø$—À…duÜ>Ý�lÓâó"ea¼Õ)>ß= Že§³Þ™o ö-ž¼Ö¢ŠS‹p¡ç:ñÇ¥6£MaçSÙd©)«)+à½n3Þú_�Q·æmiå¶Ã'cdðwa–G¬¸þ�öŽáäËö¨43�v|\ʵòæ¼ÓS�cÏD±±�,î7�Óöi””™†Ìoà?¯~ˆ_^ù€|›ïë? O¤šÅŕ⪴\Ökß1‚•$ÉZ+RíúóƒNCÞß7 ·ºlæmmßÈ4Åœ&(&ñ8ù~Ñ/6·Sâû(J–¬}Ï­B£öwŠð¼EŸ«›xù¡vö ?Y¶^VŒœ}‰‹:a¤BO<Ü«aü¤ALË’—òŸa xÎ-6"*?²âØñGÿ9|_jŽ©}P³}+<ú>¿çáŸÕ¾¤º°…:Läò•ÂÑ,;zt@ —ñ´¡�CÆøáèU'yð‰ Ü�X–òºƒ‚Ye\>ç 8Ò(„õÏÏg EÚ1Æ”Ï >€îÙ=ñ¸Ž*:næ[½vðÌO½°n\5V>]Çþ`ý';(0/lŸËý&(Ôîú"Ï�gòŽ c^›>–ެù+Á˜s™àRÞÅýŸïæ_‘å¢Y½:¨mA\¹sd è—ª%»ÜŽ ¾õ«is¥7Ü_{˜?¾‡ûÓ½èwÂ’ÌRK¯TbpiC+î4<*l,˜Åù7_ÐÍkQØ(©£ßïÞQmð,”² ‡òggèoG“mªÿ:—ý~ÜJE—¹K`_ªŠWƺ¹÷Ðo·++ < Ö£™lvø*bms*+êèâ²Ì6òöZ¢6÷¤­çS±32Ž¥ÖéN„~‰‹¨lÃe(ý¾‚–j%ólÓÿ„�5ïᢟ‹xôÂ(;Ô_h*Jƒò~KKfœÄB{Êõ ¬ùCjèž¼C•å±ô+\ÚL„ûG‰-Å:¢gÊ>´Xòß=z*Ìöý ž[àþì"Nœ}ê+]ø¥±!Ï}ªÀíw«éSg¼˜Š]¢[{šÄÝ�¡«xLoî@é''¶<+¡N£¹aÎlrûM}oÚbëQ¸ÐphíÍ¡xqN ý‘EïÊõ ¢£v~óÇ®½ÚszKè�¬ Ænäc–'ÄÉ�Ó�†àɽaðòSõ ù ΛSè‚Ò&L êÉ‘™JÂêv/ö�g[#¶™b�£&”ÁõåÐy!Oü~(û<�7ž|ƒ[nÛZßùB :3Pmeêô¯ås*wavˆ �ÝÜC¥�ó¦p‚p“®)÷fã×<;áDO¶Ô‚»HI6·Öe³²ßPÚ?+“öä9_óG» ýÓG�(Ρ|2P«¦?Kʶi Jü�7 Áâ!üÝ\ÊmhÀõëkQõôkŠôt·Ûr䈼iÊ+Þj_ÄÉÛâÛ+Eì$Ï&õYr÷ºàj9 =ò´ # ”WØÏ£‘OîJäOÈØY÷uæu®Þ8Fû ô|$ƒ/–€Õ§»iÒ\Y¼,< U}‘|ï FõìC2å;_š4ƒ›d_Q«T"}šU­³røê§ÕüÂ=˜VrÆÕŠ›ú¹³›”¾|9·Ææóp¼@6ÚKɼܑ7NìÇã•i™Ño�SßS3Ádv7W ù‹Yñ€³!*^ÞËóý:…k Ó@Ú§”öœ]Çbaï? (¥3–/û½Ü‡soÍlþ¾Ûö[Œ4ÝÔ�HFv݃ô4C|ÚWsw{Ó›Æ#üâl/aUñ5ËXÓÃb�œ�ËšóDÉ1o0Y£ÆqyV˜s®/.©'Ïð |M¯?…Åì6/±S; ü'Õ )ç508d‹ Éë‡"¶¯ÛCËõˆƒOÉ sTî‹®þk0ÒêPÇz|œ5ƱÑ[SºUKÃ~­Ú,׳sâtÛâpÛ#vQ—èÙ$wÞ¢fÆ<‡!O"!Ï_…Ÿx³n¯‡ÂÚ۱䪶pS^ß=< gƒótœ´C–¨yrŽþlõ˜Ë)®ÅÜœÛPëÜ�Çh–íMûðÆ‹ì•úœ¼ªø_ˆzH]m¦m/å!°|7ýޔǿ:ejÇFbSÚ) ¯¿‚/&¦ ¶²€NNˆ Ká°Y}ì57J?Óû°g§+¶g¶@ÐÎS`žòTnË3{[�kk%/oÉ„7¡ � í‡.ѹõk±°M…½e{ÒÖÀ¡{;(äPÝD‰–åôrÍaÅ‚ñ„b&J” …¢dÀ�¬e¤ø»T .˳ÿÍÉ`ý¾â#ÇúSîRãù n�1jXÌÑÇ¢°ív2¿o¼/¾_› c> `QV™Óy=i†N£=ôy±Í)êx jEkÅ·¤{í ÄØ@‡Êól#9¶¼÷L|»5X|8ÕÁfÈ5Qh´/+f@¿Ù±léQ"Ùÿ`ZÙ{p{A´p踤¾cçì±¹´Êˆ*ß6Rû’.Ûž>Cñ@cœ}æØ}ä1îOY~o1Ö-ø †·.qÞ¢bj¹#á,õ}|Â~"H3Ãe4”oýë?)ÛbAïN©ð[î,†OÄÜ›gàéð�øtÃzì‘ПËö¸²ÊìtjY�ÿy˜—xFÐóØ\ ÿ¸r½Hï-…dßÁØ«¥‘Û.¼»©®‚êÜœçn‚O"úQì¶½™õìÝ‘‡)¡ÛÅU�%8â^ä÷ÑÇûݤà:5Š™´…åœòÈJ5�ox¨cƒÌü~M¯äVÁŸ€xŠx‘ RvËén`?Ö}ðœ×9óÚ Î˜­=ŒW|ÉÃɽÓà˜Ú#¾ä ÏIºÿ£È¼ÿ�|¿0nd¤PF"…BƒD¤ðœ£MÑP’¦)4”JKÉÞ²¢�ŒBÒ'<ç�†vi’––Rii(êÛ÷¸¹Ï}®÷ûzݼã|iþsè1[±&. |Ãùøð×¢´©.gŃ{ïØvA‚¿*Ù#Å£6¨Ä„À26~\ƒa§û⟣1œž‰úCVq¹­*>#ƒu÷tqÂöV’Ý9Wµ@Õä©5]úõ5C"8ß7�ÍFY£ÉÀD~¢>ž'�¯äÍ•¦ÜÚ-Á÷î6Ѐu›E½{}1Ê팘®Ø$óPc…gœ>(‹W�™²+z¡†RõŒ·Gý…Åp¢V ï[kâ3³êT=7þºM¿- åÃ+äb|Žºúª³Ó®PÞVcˆ£jDzÉÝa‡Œ¡€­Â‘ýÎôjëÔ$± xnåƒm ´`èRúÕ|Ÿ¶ÃДøèªðnËBÜqYˆŒë‡ÏD�Íü Ò¹ xno~–Mcø|øcXY<• šaªŒ)ÌùƒÙ_§Bü‘—X³)•FœçõRqV¯dÈÎRCÕ'x«Û8Vß_ÌPëËæ¥1diG<”Ú6ÞYç £-ªmVYèâê“ÙíÒK<ñ¤ŒÖªJa¯sX·­œUÏS³Š<ß6ÇŠO¶‚Ñ¡o=³ÕžÚbíë^|píEoh9„5:’¶ãkqò 7;…¶çV¢otÄÙ½¤k–[Ð\~�¢‡6ÿ°éÚ³ó<`œCJϪÆé²k ô‰!¾É5GÁò;k®?bÓ9Ä{Å›ˆï:Ÿˆf;Ç‚óÖÞh¢ÔÆ7c°Çµ ~FP‹Ê6ÓW†ÿÛ1„³ÿuû^&$%1Öl‹ïRÂ9é´ Jü�O+ðþÄ ,a\ a[vÿc¶¼Ø¦ ˆyª9Øvê ^éýž†UÇF•“‚ýâ×ÔQ¥¡UkjÎ[çñÏý¼ôõh:[:µÆú˜–½~OíS1ÅZŠRÖ9ñ«ué�õð) -`£1¹ «Õ*|<)Bß]½L®çFAúŽ?â\yG¾ü¶ V¾K�˜Ãkuܰ¡™NÈxà ��¸j¿Ÿ3Ä8a]BÝ>C¶u²ô%ç#$7>å·£;aŸ×F%±‹'l›ˆ]{¾“AüyÁlðŒ&਒t¿UÂæ…äPŽœ[ƒý÷±‡‡3‡ÞKSOÝæ[}ãÙuç÷.5Œ6û*µ÷`MP:�$'ð>QŒ¶kÝq�”ò]C¾aéÇ£$Wˆ'ž¡Ê3ëñEð®}äŠo6’Þ ¾áÛ@£nVÓåüiÖ®C2Rà™�žügázV©Ìºÿ áˆÒÔèÆ�¾‰¾ã�U÷«zÞõ$÷(U>@½}2N>|[ðì0ż]2hlñ€ªe¿À„ò…¼Ìî†ÍÄKÊäxü¯½ŒKó[ÉOmdh©@™q<<ºó„N)Ybü§ó•uu¬�ÞâåI \úf2zÜZF�™½Ð|ÀjÜÙ'”þ£eòÖø°d%,/ª� ¦4L àyŽX¶ O <Å»— FUÕ·�¡7¾°Ró ð¶üLS¯àÀ7·8»&X¶``Åfôo^$܈‘ÃLßrlé8/¶9âkã›°.T纲æm °6—Â�Nél:¦™î÷}Í%*Öhh²™âY#'ÖñšÂ7ô¢xX† YÉ!ËäqœúÖzx€ÕOý‡.í39ã¨8[ŒbÏYaâÁâ¬>UGŸ¢¤Q |ƒóÔ¸sí\ñ1_wE`¿à]œ¶: ž!|;Æóì�ñXeí|pRK“iÓù¡¼EGR¬:÷˜*Ï~öŪ¸HŽK×S£AëJXìzU´Ì“G�ôá¼5{?^T‚ {^ƒ}U<ˇ  ÉâRïMtìÊ”t—‚t¸WÂa0NðÁÒ—ÕÂU¥Ål VD ÑÉ VõŸ‰U¡AìuÇ™‡5Vry“"”¨ƒ!˜aÞ©ÑbôŸB�Žfáp»16IæÂåþ’˜æÞ›¾ÈeQRB£0âë ád»2Ç´N„Ž°Ý¨%tÐÆkpÂI¬Ì ëÏË©}°47؆ñ·» `ÜÃÅ`^[Ĺå«Ñ|ÊÔm±Ä§cÈÍv,­ü‹²ƒ¸ùá(•ì¤Àº?≠ÇpâÒAx}”2·åæÃ˜Çiàž+ðò¦XT:ïÅÛ.GàÐKëñbª2¨OŠ£WW`àÃïáßG¸o-ÁpýE>ÔÄÆ¤°"Ä;÷‰X[ÄS-¾ˆ]µûÀ@ëMýï¨8гզYR>è !ó¢OÔ©šCùGðö¼Z2º§ÅŸ4lFtÁù»ýø×›u<±n ‹·±èã�ܯbSe1­­¶Å£G`²> ö–Öürˆ‡ËÇ‹¶°3VÅ’GÚ4,žÇw¢Vç}r?<™÷¬Så#ÖÑx\MnŽ—³o8xØMZºQ•ŸŒm+àžÅ±ØÐ¢ÅaÝx½½Š×=`”m€åùÔñ¢OmÅo kÚ [ãÁÈ‹P×L�ýhæÄW0¹s? 4=H3êAúè,\¼\ õöV�»²,'Œ+´iøU!y¤„qÉéï87+ì•Ó-”=‘+ºþÍIõ1¨ïÑæý¾#qÂ")|ý�ÕÃxšà§K?ð«™%›O„4ÉçàÑŸÍz/Ç¢›ÁÌî(ru/œ–DnªþâÙ+“ ªý9z4AÇà-ìº|ºJ®æTˈ¯¯tÍ'0ZÊ‚kÛÉO%�¹ßú«¨|¢…†>²¥ýéÊEÀ�²‡a×µá4¿ê¼¨µ€JC3¼t!‡å�/ÑCû#BçÀ|8÷PtSÃõ§¼èåÌok‘,Ž”¦]w-hCÀn1âA :^‰ÁC›–€Od9�97\…í\òã/UîÍñ2úxuÙcáýYvŠ¿O³6ËPßæp›k/4¡Z3œ—·ѨôÛÔ•‡æÝ!­.gôl´�çŸ|äî´fGúц˜Ñ;‘"‡ïcñF3) ÆÖ'òxÂE?Ì‘øÇñx.VjÀ§©Ý`3| ¿.¿{³=y‚œô~ªˆº‚ ÿJ¬„Š€^~h,¥u»À’ƒïH|PG­Éò˜P=Ž.›Gk+õ(ý^ ¨­ï�»ƒƒðGÆ%Λ~�âÍ£U{UÈlèa mñdùŽñzawн¹Ìý0„ feŸuØÜ¦‹¯.�»�Ç,ÿm3ç­>ì˜�ú]dÅmYü&û› ³®^_Í#?w ‘Ý—ÉÖ4‰�{þ£Õª— ,Ío„…Áûö[6þ¾Fh1ˆ}Ï Å½&ÝY˜ÎÏÃÓ($ª7úK¶ ;»K`YE;¬L0CÍM‹Pë̵šö¨t¬NŽ£@¯Õ5¿®9Ñœ¯¾›gÙQßÝA˜34 æšù`ÙÍÞØÇEóV9ð/‹5^dËÉÛ/‘Å©«¼#̉|ïOC¹J (,Œ‡œ»ú°jU–8<›Ô¼†k A˜jy€LÛ-xlVd�598É6Ž~Èó—K7 9ìŸDZã‰5Ë8íaúþ´�Þ;©kç|JX^È'Åž¯1Iñ(„‰hõÝ’_ïtµ>­;ƒÞ}kšÍŠq ×"!½ÃG;d Äßï€cnÃÐØw&6x­Ág ž¢ÊsX[ŸI¯]/pIê Þ7Q…Áƒþ·èƒq¯ÚmÈ%¹®l8Õi#Ã9ñö4 ÷߀áii<ôo3¼=§2GÌèÞò±xdEiã9ÔTÛâK ÃU�gÉáö�Ÿ(Þ9Éæîë«>ø»Bƒ•ÛJø�÷k µtL½áQÕaü*ˆW–' Ñ61¼WÍ]oïç€Ûõ�9d,o2Ò ¼;v#V—¶°º›îu3ãè-×…Öv ¿ rñã]ðgD+ü¼ž,vŽn³éÜûÖŽ,¬m×B—òò×™ÉkÓ%y³ÑÜqå °¦Ü�>>Ù€âE8—r‡À‡Ò¤’ؽt ·7U�_Y!Ïî n|ÜGc4LpéJ¨hÎÆaÅÑÜQ ìŠ>‹�ÓºÁohÎÇ—‚‚fuçÃÏ1ÊÐ÷ûk(=µ›Û5àÍäñÔ¿]‚=~·ƒÂäqÏ£ÛsØ9b4¯ß™�mÍqöïÜýLÎd€r)ªÜ;'ÜF"qÎÙfµÂÜ&-ÚSi�§yðŒ,iqü¡`ò\°€"[†aú�¯6fv l±_žƒ}Si­0ï‡0¼¬~bS¸aîrì‚ÙŠêl3Å.ûNƒ7E±Ëƒ›ä>û„¸È×…¯Í�î/ˆZ >1Šw]-³yq V¹=¿ì2êÿIE‚3£u$ìú8ÝxYHcÎÕ2ÚuÃ}ÊÕѳ¨\”<5’[zñཤd“+—Â#‰~œ°ONIæÀwÛTöÌþLŸ}s0¢Ä¯6øãƒ*¡p¢;èúü‡Ó½pj@¼V?‚‚;Õœü‹6¯"'é8öûÂ:øV^oðÜc“|IK¼¡ï%œ­C¦)»8®hþ� â¬ÇU¬r{ M�Ý#Ù‘iCÝÊ4à ¿$0ºm‚ ãx@põêr%û�ï XÜÌú>†G}NÁЄ4¬›ª� Ç•yÎ1Kü2U›ëk§¢Fz0+õÚ€Û_)[wÖF¯‰ÁègIøyyU.ï¯�„•Š4O>�?±Ž Òã¸í²|UU–?J¢×gia£ì{2©Pb­¾±|;ÿ¯Ðÿb*ì�öVMñ–8'rkïüæ­"ÒŽš/³ßU]þd ¯ý^Ñ¡Ï/i¼S›ÏºH#Ç×Ä*ʰu€w(râ‚6¤Ó ºßA¢À‰ìõí ßî�wêâÑÙâîÿœ-Ünr‡Úì*’UË‚éËùTÎg®”ÔæÏõ-­´={¶MÌDe7#̹#‰îv²µŽÁOÉ41„¼VÓ½Œnz—±�>WgàÚ xÁ�1¬ßj:óf1´Î0Á]ÊcÀ«- æüMƸQ)¸?`êuj -Ž7 -Ÿ„�_ °ÏíêinýIõg>Ž/´ÄÜôœ»±�V=±Ã¹cV÷ü“tøâ0(¸~‹îã¾>›¸{\ßp©„w9½Ñ$Lж^8(|øO]Èç´ÔPk¦"NÑü-#þeà³Pr­aeáÌ«ròŸS,˜3DhæRÝY'ôx–Fï¯AëiWts+ÁчJÄõ¯¶ãõaÜvê ÉWHáx…›”Ø_—ïv•á�÷ÃÌ 1,�¢…º*8Í÷¸°`¼>~‹X ^Æ&0ðŸFg]ÿ) 3á¨¡Þø%ºU¼xVæ©ÁèeñLS7㺛gPJõ$U_•‡úØá±¶¹?*â,·j¡+²)˜lþ[(LÜ¥€r§9Ozål¥´!âÓ2hÙ=G°³Ï!ú�•öèɆ)¼É¥¯½u�¯¥ùàÌdUÔV4£C\ñ»¯>ŠÅ)5᫦³ú‡F8_¹ o™U¬³bŸx1Z¢¶Øæq�R˜ì”.¢…Ö<Éé%F}"/+¡eƒ)_ù2Üæí€àUÙ&­½†ÝîT™z�ìT&�ÓRyîý²ž’½íq€J(nݹ^,¿šbê||Y;/ýQAóͽPÿJŠz¿ªÞ�êÀxÑò,VÿRŽçE[ÁéÖ$žz†(…ƒØ,ÉUKzª_ÌØÇ½Îo^Šý#‚fa+�q*£ ¯.ÒŠ±êxvlŸ �ÃÚ¡\òë_õv®uu }½òɳÃ�‡èc½i!È/zE2n'ÝŸ7Õ*òÎ×ç(Áüv†±‹®«ð¢p$RŽOì’øIT1ç=Ͳ¶XE:'W§fåÃê`N×8 ¡ã ]ÏÏ΢Çã{Ñc¾°v-“=$D–Úñ.Ïÿ¿£ó!eòª)jäõÑ+i¿m«’É}ÃS˜æ=‡›3´Aªn>_Žì–Hß?µPþ,«‡ç·ážt=”{ÕJæ;ÏñÇEk¸¶¸DŒ1sæ±E�ÐWÑÒ½}pýùkT|WT+™ŽÚA¤Þ¿„¤Óah„ ~Ð�TyìÔ�%®ÅÓ3Ây÷ òͲåÛS¼h–ÅSš½x1]¼2†³LsH4ÞÃjKÖÙxëm#ÞuF¯�…-î31­w'i†C¢Î x·ÓF<%ŽQ™€zª1€¥¤¸›U¶á,Ÿ0ŠÏˤɋ«ÅÓçF@g@¢8Éî'˜þ2áÍÕYœÚO[¼zDGh§BøG7ìþl*ùäBÔ ÜëÅVe“~N_tut#÷„³Â€A28ÿ¤Ï½7'“Û¶>ä©¿�øgÁ#Ëñõ2\ÊWEüÎ}�C0{ÈK÷ç€hl4‘Ÿœ‘Å£•ûàÏ”~¼ã§˜NÂvky[˜�ׯ“‹Ñ=x?fR½7ˆ}–s£,N1öÂ/½¦aÓç8(ΟÌu—”¡®m0žë{†·OHÆ4¸¨_…`úQäéÑåTj¸�ýƒÁsœ ýwn4̼L–£NÓ¶Ž~èð®�>ßv‡ 3áì‡PÁeo)XG™óWI%<œº”®ž…Ù÷û¡ìæ`�;¨5®9O»;kàñœônÔçËÓTrÃÚØ¡N÷^X…†À²æj ‹¤Ó3òHzT>k�ÈoXâJ÷š’3œ_ô ¹5£øëŒñ“ÿzwJŽ‚oëÓ`ÃdnF¾q¡°!'/t.†€yý`‹æ LˆI£ê3jÂë0=öõÝÅ ûTQÿ‰Lþy–z­fž“èä�:lÕF� u°«×{ÑoüYÐo}Rµõò,º'¥År È£—Á §gðØÃ~·Éd3±­ÿ\é6�¦È_¤‚v#Vœ•Šf; Y'¿“n•+òAß"±tÚ ÙëMƒ’–`Ù2Q0™–3ír±Ã§ nZR¡g:ìI�Æ—ºÅ6t¸ˆ+4Sù�I5Tú®¡¹ãØâKOßüc�Õ^|ÞÑEs{ LB[];!cßáyòN6¼†`¹ù °.q뜾+ÿ�_Å'¨ø6þ ’gÝÞ®8üòÊ:zF?¬«ßìÁ}xÍ“}T0÷.›©ÈÁ}qÞåáüõi§®î¤x× ÌpÛUÎ|ï¦>îµ]Á÷»;Éßò2 2ºL}5ƒ)¹q .4×ÅÜ_–{x…fšW ŸSáâ ³h·j8™ÌZA?›H±f)¶ß—&ƒ!Tñó4Íp·ÄJÇqœÕ(,ÅzNÝÒ›ÛÇþßL�E÷‡�–„bÜÖ·¿Àè5©|÷¢$=PÞL©ÚC©Lï8'[݃±.QL\=�y<—'Œ¦€5 xïð_pu‡#z†€£Eeè'�’ß~nG úWaä 'Á)æ¸ØÙ®ƒ{å5Øq‘)îÌ÷Yž\jßDß ÙÚtûTOçÙWšÁÅv|Ñ?Ž#V/çÝðǬ־¨’w�îª|¦ÅÝ�à“_ÂÉ[·‚n¼VÆÖ51Ð�-m³ò¥9Þ•µ‡ÝtaYýL(~Z 5n #}.ÐÖÉÅð¶ä"ܵI‡çq�0wåHŒÐØA´ü9nÔú£ž2ê 進)_št’N¼ÜO¶)IB�¤½°½%Nl3(Äóûâx@í5ëÛgًס¿âLö~_BšÇGàD™ÙL’¿`’áTÎ_ú‹öfíå×¢ åú%¸¼ æ}š…Ûr®ãŸru~ÝÝC;ljo¬òANïè+^€ g¿ÒeõYlwýŽèTŸS³ûy ÍT¾,FȤBì„pAú›5¥ŸócÅOSÐbe1ܹµ”ûh,1Ë7·˜ÁéLÜ0_ŽŽÞJfµn§ì=¢&fR5@�;׿ˊJÑÆQ 7žW…óÚ{`ïõ ^[0›j^ìÄ�¾*0Ð!”t&Oé>œ»Júo¬xêÊÞ89BóBæðÛ#»¾üýÚa0y¸ü™�ñ®ó)C>öŠ=7d¡Ú�'°Ý6ô�óÁ¹%šßÍ4\þR Âx�y#îŽþKV%ò¬êv6˘`?Ï2:µé~6J{×ÌÂÏâS«ŸF2¬)m#¼þ6ŒÜ_máÄÀPh5È*Ó«àlômH(%‰Æ(?}ov…ß¿¿ÓOc-N*ÍY[,…­ÉÑØ×ÔÖFñôoÆãù(oúœ^ kç~ æ_K@%¯/XV~‡¡~!ÿxlÅÚÖÿ˜o¶�W›Ý$£€8¸m~¯«Òn›pn7ÎÎJäQšWà§é'òN &«•i±g8yxŠ_­à_ 1&c8ŽW;OÕ›ÖÃÛb-¶-M­ øñœÿj Áãb¨–ú&LÏ̧—j±BôÎÁ|1ÙŠï)ªÒ1'%´ŠáŽ˜™Øýt4®uX|Ó]‡¶�>QН*_zHs\PkßsZ'm î=Ïå:ã“×£á¤q.P˜¹XPÕ&ßé�ƒ6FwM5Ûî�»xnW­4„†¡½¸Z>“Ç{„ýMRð³˜6? …M%Px׳£nŠîïåiÁÊ#˜0?’6µy-µŒLH‚á_g"f»?—]ó¬£Å•�óË�ržä@l© k¨ÈrŸ·R˜µê>Ÿ¡Të¿=“œvÀø¼¥<Ìç'/MƒEššpBÙ6 °×J·fFöcœ¦…ûãÓÙëž.Ê×ÿç%ƒUçWàð©)à÷6gD@at Ø?«Thh·¾6²<î+ÆæJs­—,oUÿ?¤IÙDþˆçÞI2°öÓjyU�;?ƒöëXܵ‘ûIJqÁë!œSß‹Þü%´O†M݇iŠÉj›ÙHOdب؞¼…¶] Ë7nÝzb\RÈ,|*ÏNÂö’H^£JnG¡´ÏYQ5y Š2VÐ4ï. ÿ ][:÷e1[”jrwÄWÁ]jÙ$pªß=È=æÎ±Fwpé­©xoÜ)Z~ü .¶ÂmlPâ7ŽÄáÒ­wûxº ´�¿·çÑî /^õÒ|ÍÃ(OgÿìŒ?^ÚÆ^cÿyi´½Ø±àÐö@Ük_Л忣kç{L=)�svWñ¦}j¬Ø0ÆÝãâ{Z<(à)y<Rµ¿Á¿p)•9cð•*:"Âå’²xòò0|¨0•Œ-ćíAØ54�'Â�Çvpìl/Aºf3,qÊ‚ãQŠh-ãËõë;aý°/°dðG©~Iøa^ˆpLò¼tÐÁ/ Yîðò?mË÷åN z£nÒ§ÅíØjåI¾G¡û:i襎¦|£É#6¡‡Ê/ù»›¦N¾G}´Ëù×0ææ%Jÿ¶:Æ™à¯4wîÚy4¢l°+d޶j¡o¹…PQ­Ë‰§ àÒ¯¨µâ©øa¶4ZiâØS¹ÚÜ�øòú–=Œ­$àÛ”TÙ”¥Çûqÿå‹ÁUλb©µ%’j%8/*„d%HñO†|çDÆá>Y<ñê¾ðPÃßþÍ¡¿�Õvl,™œèl?ö"÷™å0ôS"]îpE¹bµž1޾pƒ'åãØñK ï·Þú<K‡ÔrùÎ^¶úÚѰhûÚ<2´¿>¹†DR“6¤¦2+¾úá7ý|DÎ]âãf÷1¼.ƒ•XY׿�<ys¹Rq5ÉžËÀKÖíôKp‚š¶fú]ü ¶�Ú‚5@L÷uëÑNëù¿€ý4žñU—>œ>#^XíeËÓûÔÓ§?&ÐõK ÝýIñå¯K�h†ŸZAÛ¾kðé‹C¸e€5_ÔÁ·Ã¿�V¶!,ÌÕÅU±·`ÙtºÕGصùÒÖ/¤ûV ¾$p�™*h<áÃðçì¼§€nÏXÑu+Å·}8h¤„°¨ºŒ¤GüÛ…]þl£»�ÍÔµðw¬�øM÷l�ó‚&*±Pœ7à'ÍÈ žøÕ¢âÁh.Œj{£N…;ìõÐC¹?Ž^ŸªcïÁÐŽ?�¬DãÒBá¯ýBøÛKGŽWÀ_Ç~`Ü®ÍÙËm9)Ñ‘b ¬]L'¢Ïj9^_Œtˆß�Û§û�˜r€ßŒÊI†×)!x»87`nÌþ]¸’ÛNrÔ¯d0ª9�ƒK�øÍÏÎê°¯yTÜ”J‡ #]œhÝÞ2GÂæ/à…rŠ5ïÿ¹Ëµuy埼VÑ#«RÐ2¿�æªÉá3‹Ø|Ï3”+k^Ôî%µÅ<¢È‚=ÈÛÊ� 'åOQô+I—ìÖ¦Zÿ£â”Ù<{Í>º°‚‚ô>€Y† ¬™ #:ïÝË'£/ÁkýbË®RKg�Iñaåp}òûv–Ï_ÜÃ*Ñ7yz÷xC Ì:†þ)/ £xÙïÜÃ÷l «ÞýØ�š›œ)Wnÿ8ho�·ßÒiäƒþüó± u¨4 —VÍá Q·†iÃþ%9ëý6o�Ÿ—þeöÒ{´8´Ì‹¦éŽ94Èדå9Rð£.¨‘™Áû˜rVì)–ÜW;Cûåèô CÚ)f¢/[«I9ËOÀ*×­X”° –>5¡Ôö(hWSçe~xpf¢°àÍ'ึa/3ýõY¥¼uµ�ÅÅõ<ù†Í¡ £ïLœ"½!¨ÿv—š�»íÃЪüÍ …Ÿ×3ñ‡¸«w@�ù¶¾|ó¡5nsë¢k¥Ã¡ãânò8¶îuĪ¿)è{÷z<¦-Hï}½°âs,¥|Iæ°Gý Lørš?Nç“J‘Ðä•„{"§ãÄ4;Þ²®ú”ñ„d±Í]ÙrÖ,ŒÁ~)XÜ9’‹ãšáëÅý4ìïlêHS„Ÿ¹ã× Ñ?ÎÇfÑø\aóÞÿ OÆÚ«ùŠDO;!¦U�sõYú3pZ8©ÓB— <ôe {ŒÝÈzB„s!ò\¦S¼?\\uv Ê÷ÕFß•><õz4öG ¯œ‰âÖ'°vþg*^¬ïmÓ’)+³ˆ–õ…© W…•ŒÁÕnÁ:(¹üZÔŠ³aÍ·mÐq ”Ëeùâ´¥øþJ,Kœ(Ÿ� õ�âxóp~h}ÎÞÿçïˆÎ/*;’f`Ç!S<Ú±J|ùí:4þ°à W碱ÑZ8¬`Ž;Ïnå÷ð„ì¦|Ìï¥cÖN=¼½+„ëkpηX0±žBKJM¨×û|tpFsn<Æø’»tdø`–V¼ º¿ƒ×•G`i–IÏÓchç£u�›“ÌI»Ä6''ì§ïÌV§Õ¹ÿË)0õì*ZY‰o«tð“L…M‰Å Ù`¬í³ªÇ�§Wëá£ÄUتÐMK#ïÐø?ý1�;¡¶(†ú?† ·b¶ÿ®å�7žÑ� ‹8£ïx<2R ¿ž¸R³è®ºPvï¯P;¤™®ªõÐõͽÑJÇšlû‰Û6,â¨+–(磄kZdßÞ—nÐQeº‚89ó?¨./ƒàÌ™à%ÿ¼"Q†ÜoH‰3ŒÂ:ïz1[;†+†°³Úp’Ý¥n/&±JÓ|½À­52©TKZçGÀËÒý<æðt¬W4ùlÇ;Lá´[ŸÀ{˜&õ¿õ¶JK£¿I1ëíŽF�·è;Ì–~«^¿’ª±<›—Žðæ�ãi¬�ãAã÷žŠå‡A¼W"ÅžyEÕeçÑ©}”?À÷* c­��á ^~ÿ2ÄN5ÂÞ!™<ûe|ˆ þÇþ}pwóF�ÚþÖ-píÙ*¦_ûðúÚRtù(/úú –4Ù¨»Ýçßê€bm%ÜÖ`Bó9¢dG﨣  oN%Õ'O)éçjö™Ç¡CIìBX·.†6.ÖÃsùc`óäÞøZÖu\ñ/Ÿ*ñ•CYþ®æ/NQgCí>\Øú�ìƒë öêXL{”OÏæÜ€Ó6Ùâ-^¼s>.;ó½Ô>)*yÎçÀ¤dH­5ù^§à]« ú)ä¿€B~_^Xyßý(ƒýäƒÿÙYŠß˲łµ `o2é÷„üb=ž8K„¤qlÓ}�õo Ÿµ³)¿È®G"oYÚ…ïÆå¢Éík°*¼?Üt{[Cp̾•<£ÃC'·Ó’ã½ãlùÅÏÞÕ ƒÍñXû$¿ÇìÀ/Õ–èvv4Zoç‹ISp§Š›´Ë`jF v$ Þ�“@i�N4¸MoŽ™sŸ½ñÌx7Ԍݣ�¸p|.÷½ŸÏo�›L¹Ìö<=ù×Sûú‰·l$ÐòÀB®^û‚{õÍ ü8×MV_Þ�Ê¡ßßàɮ霦 ¥AlüöÊ4(ò¼¢"LíßU_äÀû£¢ðr@ŽÐKo)ox›„£ì—Ѥ%h2}#Ý®•Äᛂ¨¡o H]ô�ÓÃÐîìv¸§“’'vÓm•xN|¢�fU äÓ¿=™áÙG;t’³ÅnœóÕ™+­T°ç•ú¸Èã8�vПœ€9·Áˆ#[19Ë›G%¢Î¸1NˆÁ†BVÙ4\fTˆ†z5Õq'Àà–å¸÷Æ@þ0Þ÷ !Ÿ¥‡….s`D{6ëÓ÷‡›x§DO?ñ†K« šw4ñë�¿ô¬É—›{l� ê' ZJŽtsô0Œ{�BÎÏ_‚câ|ÞXyÖ©G»eîúÖ#dy¼åô2ÌÔ-†ý)¦•á6‹ΦæC™Øsx]»“zuŸåýF⪚`èÒ—á—}âoƒz±)JBX¹uj9Dó¾Oû„ŠÞI:´Ð¦Bb§)Ý¥Goð�Ç8â¿4ª}‘‹ËãééóRù£åö\Üê ÒXÝf˜îñJ\Ù “¶‡pì"o�YàA‹$n8~¾=¬¤Â+²[¯ÇŸ#îòŸ¿ïª×Yúã¼W³Ùä¼2†Œ“ÀSñá©— öQ�àQçA[W–(vÈóMãq´µ±‰2‡œ¥Q¯¤ `Ty�|))µb]ÖM2ªLå—½ñqë) { ðR" �K·A�޶=:ÍÇGAÝ�“ðО,8·/œì-¢¡o–¸oþN=; ¯ß~^ÿÍ…j'=äûŽÒ¥etzû;è"3R8PB}$ZEíŠ ÒÞÒŸ¥›bçY¦O>ªÆ-¬4ð»Ðþ# ëFsý÷ 0èÃ|RžžC�ž9�¾q¨:ŒaOTy¡ùznE|©¡ áÈ!r @/l?¢EוÑÕZŠŠ@¢¶ËÉ3=DzÚ$SÎi&Ò=ÖŸ�M\ :È�í£Ï‰1£´éRË’W¨bÆ"œuwfÏ)g×Åkm>Ý;Bwª4è‡ó2L’…Ú»Æxku?[Q&$‚´œ9õ·°ùøå\—6doÃvXσP1~ YàëN7!Ûã+ ©}lSò2¸iéS’o­˜O[’Lù¾º+é)Àóº|*¶�ÄÊ‚èäÚ‹g4„Fo–6Û >}¡È—É“UþSÁuÉK¡m„3_ŒPå‘SÊpÝWW;r7y �:ÙM'\òèËÉjLé‘å«ûÓ¼òiñì˜kGÒÎXäwLžùQ„c;$éMÇó�ܬhÓû¿±ôàÁNн¢Ž£èéù…ÜkÙLvýì€!­Ñ¨kçÍ %êÁIr<®> ònØ•+PÚ|ûnºhßy†l]‰zÛƒhSk8k6¸á¿“ÐgÛRìפ‰æ‹ÚøÑâFþh©,¦DŽÆ­;t{îy~|ËÜš”gbåñèg G÷¦�œÅ6£ï�ÇmWC¨0v(Ù=|G¯$Ь7¡Ü8V°î’=·Îït…”ÊÏ$³m×ÌÔ'_�4zößÑ7o"•]|D¶9–ôjkÜ”ºÀ®ç©Öx$Ûšqý]¼!¥lÛÐ-�W$Uðì,7V>¶€»/öãRË¿4Ã,ŠófL',œ‡Cò"ñe�,Û¦÷áAQ~¸@æ‘ðø®Æ«=…4¬§í¿iÓR-˜òà ž>©ÁS‹§€Ã¿Ù•�È£oF±¢¢Ž4­Î´ÅPÅ<¾¶Ö<Ž�GùQ82n.OЯ£éÎ×ðÜ)~}!ƒÖüs^*-"9åFМ$:G)à‘Ó²|È5�Kÿ…)ïÛˆ+Ýp¿b«P�Ë÷{+à´«Fxbº$wdÙ“áÝ�”"37Ë�¬VW0–jsÕ<íF^Aí^‡¹ç°²mÑŸ9¨z6šª¯7Ó·Ö@Hß¹…=ÚfcC«(Ž�“|lY¨Ã1³OÁ·‘޹ð ßÏZ ýp@j:,‡ÑÎ{`¯E?,lÜÁu%‡X1¨ ¤m»„&�Hüyc téá勹â*Þê=UôÜæÀE�J17à.ÔNzNµºcqn™!÷VÔlj~—ÀËø4{YRØš@ôÍ/ó„1]þS4öþ"(Í:Af©aþ#–¨·¤�Ò™ø!z9Wª'Ÿ‡«™û9òmïaøvÝ%¢«è8Óf·‡Â×O  èU‚`ÿ~>\è�›mÒnaÑfƒ3�©ögÿ€·¤»æ3ù¡lv¯#âú¡FÞ]ÊÓ@ŠcösRÊD÷ð1ù8ŒEù›2Âæ÷k¡ác)éYcZÑÑ1+˜ÿ†¥Ó.¯q\¼­‡*Œáª]Bâ{<ýŽðŨ§ÂÊêƒ@_õùLƒ{|8…'§Œ]Y<æUFÿÅôÀò{Éxf•˜âÏ+÷ˆ0eð¼šušæo^ˆF1Râ»®�¸lêcZß' ²ÃC/[j†Xoá}^smŸCy³NW à‹êÓèù£ð5å+)™]~͵@ïùr|ÁÉY¸i{N¼ÑÓ‡go¼)TOÛŠ±¢†Õ_‚—ϯYûßXƒêËÔ1ö¨% MWà—u7÷>Kê¥[iƾãPÔ¹Žòï%S}¶Îi•`ßyÉøwÎ>«ÚDîs梕ÏX~øulš³¸C†³œX§¬†Ñr½yϽEØ»¾Lüd·œWû&ÂâQÁ_ÿ¹ø6ÃŒü�öãÌgú6&÷æ£úÕ`±³Ø•ƒËå8@=VÛâXÃÑ4õòÏz¬Ø”C+.M%©w�qkö 1÷ŸËî|Nu/.óÒYïéò¥û´nIo~¥P“:``i2M5ÂïáŽôûÁ,ïš‹ÚCúbÈ._á‘·6§4í…oyGqå…"r›ó‹$K= |ì”ÒÙã\;àE|�±ÅÌè¶‘Àí†SqŒÖM8ü€„e®BÞCŽ÷ÎÁÛÂꧤAom¸0ÖFHT±àÁ廉úköM©fÆ´Aè¬öô«CÅÌCšüws ¼uX '÷HNʨ©4_¾S´sàNéOÑ{‹vnÚ&:îìç´Om&§ cX4í�í¤¸˜ª/J†ü]å�“Ëf[Œ@+ç°pß«“Ü"<ù@E¢³zVࢴô|ÿü¿[hé]§1ËÄ5ÒÐw¢+†®ý-ü¹}�¢Æ§Ÿ.¦Ì@/¬)4§¾‘ŸhÜ�ûd1p *d‹ušÜ´d~Ô@#ŽàÌÓ8òï`¸½Ý”'º¬B»ÏÂ�@=4ÉÞ†/'üd3Ë¡<}]ÔuG‰²]˜a1‹ÿd¾dF¥W¯¬LG~ý¯ ìéÏ öîœõ_Ýhœ‚½‚àêÝÞ¸4âÜ8Þ�»æ[qGÿ4qú‹P¬¨†í‹”Q±Øz?§x]UÔhÒ…1¶ƒY;0–©RxH5V¨æ+vàÛrw:8‚ÇÁ>ð[�mW'»”Aæ¦:RÍLwVWÔ4íÎ«ÙØbÇ£¤‚P[N^½Rà—_ãO#YŒšÖTSЭšÏšØ¼e=ßì]E¾¬÷l�­ê^Ö±µçI¥é°Zm(^=Ã.ü=ŸG¢F_yö=º’É/�ò´zà¶‹ÚvÞ¢‘RÄb·n¶ÃÖ�ÂßÁ—éÀžCؽð?8»gý,†¸ æÜ98ƺ`îçÕâßLèÉ[ßûÍäá®WiÖ6NÓl •_ßÀ®¤otºÛ—'úhóÁ3gX¶õ‚ˆëì'ýË ³f?å*TÁ)¸.M�_êg♟¿ÉÉg-ßÛ;Žî§šqóÝmhç|AhÐ1áà8s¬ù/„÷šÎãòÒR©$Q«–-”&*ñ¶Þç¹Å´‘¼úáÉMjô®qN9Ø.¦ §¡çšÍËO‘œŸ» Ï�íÙ*¯aˆÇúÓOާEÍá6Û <úNõœÇŸ]¯Ö°ÏŽ‡ÐŸ ðqjì'ÒdÙ œ³¸Ÿ-FŒákYïó:1ºü!¬+‘ƒ9=´úN Zš‹4âa�pöÈpí+Z_’Ĉ9Ÿñ믺PÐRcç`1y)˜]šÅ^ê#yÿÏ%l7꾚Þk—#/ÏÈÅu6ÿãà¾ÿ¹zß8€›É%2*T$I„ò>÷õN"J$*i�¤ÒP>ÊhØ%{fFÉJŠä}îK²* MT -DˆJR}=¾ÿÀyœó¸ïëz½ž¿œ,…ÔG �­yÒ×p’ä�Ý0¤‹gç!ç:AÜ|*%‚)ïw9�Î@+‡©0æÛL2G_0'û^Ò®§˜Å]:ÜØMÜyÖ‰·Ñy 6Þ«¢Ï†  üÓ6xåõ•þë�9oB1®¯‡ì™ñ›¾¯�Ã�ºåôó_WÙ�o*ÿ›oê$}özðóp /’ Á:8׊æá� ¤øB yµÔ›ª>HF‡\>¸øy N½Ãp/Ü`‚ó}I¬m!ˆ“¿oi�— £°m =Qw…óÚì>e™[¨stŸ±"mÄ"ºš7,ç j­‚ ôß-¢¥ÐÀxÔÿ‡‚|agU5d›/c»ùAí\>™_ŸZHw”]zýóÜj‚àßC(X…Å9ϰCàUYsËfÏ¢1&e-r¸É%=ÖKpX¼a$_S•›Bœ#�V_ÖáÐ{ò+j t ¡‘Œ\ò[ ‡"Çðú�ñ+ŽmP^%ì9ÔŽÈ Q—v3·üåadµ0žW¼FRïêà ³pPh¤ç×[T…ÝS˜('ªa�‡ì¦®Â>(~îßMNõû3±§Ü¨á÷PÜ¢£IKÎÆ» âR )5·X‘?®‚ÑÚ]œ'3Û@ù³]êSJõ6qÀwf.™y5™}º+’8ÌÏ'Wf¶s\ ŒPZé>´eÔÑü2½3îc¡`\¤CC¼ø9˜8‹^Í‘ãlìÙI÷¾�`’ëRÉà—ÅÄì�$Ú|–gT„¢P0V ýÿœ¦¥{…A9dÔÐpöýí´cd9J-ЀݚØÇöƒÅvWôº%YŽw¨ãœfIYhž_22a°ÙÉ”ÄÀO$‚§ys2œ,ð�ê<ÜñÕ•R‡%¸xï0³þŒ½"šˆÝ+| Üþ±š·›h6­Â¢¼6—5@UnGq§0zL5”ºèwQ ÑÅ ¡uÎHE’ƒÏ,±®~‚ðrNÜšJrHý6Îm˜Ã8¿š#Œt'•ßÜ÷ôýÐàÎ0¥Faë±Hê)ÝÓ-ÀL ýCn”Ò+OãqŠÄ*lÍ[Œ«ƒ½`wlÙ1ÕTGMàÁ>+\|##EÈL- ô1/Ç—«”XµTôW‰FúókÍWbÔ•?Ù�ca‡Å%\;ö€.›RŸeÑÙ¬8þÑvƒ­·YRúÓ·pì]ëÉoC~¸ißÿíK#¥�³©ß¯xè€âmùxÁdaå2�:#ä¿:[xyWŽ®=gCŸ…yÃ<-œix‚Û>c‘²>„íì¡G�ÇÐÂÒyìÛí2ŒÆãZ0í(ž*(GyáYôëîWd§D ü¼âHN *ÐÙ+N�QC;òs±Ì®ûL¾Ü”éǵ¨ùx„ rY ? ›Ù‡åqÔð}3YùÉ ÚŠ5@úÔ¢µc uÜ{ ¾.‰‚‹Û0õâN°ÞS çæ¼Æö`iöNY3ó]*�>O¢D„`Ynë.D°Áåv5˜ÝêwÕGþÃzM´óI6xMÖÂBЈ³ñU ó�N÷fÇ`lz9�þi¤®ÀŽÙ²ïU`“¦4FN䡃þ^ø äÖè WÉ�š´Ñ±FE<êe%+èîÿ±V_ÖãÝc$ßÚe²ç2ËÃÒÐ!a*é,V-YÇÓøˆ6“òtë] ¯Âá¡é7vÖ�²’Áˆžc )ôô¼ °ï…ô먠Þ"]ª[äÇ‘QƳk°÷³ötLÅ%Ï!%ŸÁM'T`÷§~"|Ù ½T÷‘®ŒX”˜oƒŒÿ|’0¢H¿ÎæâÐÏUär¹ ̸›Fåú.ãá1;˜ž©†Ùº›ÈOøš9°1´×íc> œÀi.ˆŸ´ã;šH}VQ‰� P}M�»ç(ÑÞtƒïáe™14+»A˜éë™áÌ ØOÛé!Œ†Ê9!°°e;0­Q@—¾âLñT¥áay̲+Jõ“hþ{XcÙÂhz_B¿Ó†XÐÇ£bÍW™®•É��Ó±4ªgp^S=Zѳ„\/Àˆê*â¶c˜U=}ò*t¨¹÷oNæømb¥×NÛÃÅ€oÞatÎ2Aõ&¿K…Nõ¬Äšg&xû…1“ª‹ÝÑuǧRUw?›9gfþ¤)ëLPôEN:�~ Bñ§Óè}+sì]耽±úèÖº Ï»ªÀ»ø}ð©Ktv%ë5b(ìT�~»ÏbàlÖbëfVE&‚ê:ÃÈíyd­v>é1¾A:Ž$Pcå#Ôýæ~j�:$2¤¬AR–Ï Å‹ó¡$böÚ=¥ýâuDÿp­¼ïÊšßJ^4‰Ê[4è¾7ù“�CYDè]7Q ŠGÕe¼5R‡¢Ò²ènJo¹”ÓÒ™Ñdª 2Ô—Ì"CΟiGG.lÊÿ‘W¬ÛF™†TìsÑ%{�UqÅU:Q`€aNp_ÙšRSLŽ3¨Ýùšu¿�JåªÃÍD8ïiË96MïÞ´‡EédlÚiòü—0~Ö©q(Õs>, ]„ñnëqºj|͇;;²áPÑc€'1Tœ9 ÃYFp¢5Ž•|Ç%?Ö�yßè¡,¼õ×…hÏž)ê?`åHL)ÔÀC¯µ«÷É�…æÌB”Üd€¼þ(òŸ§'œ¯ÓBÕüDØø¯�ð•o†ÕEàÛ‹3x9à±ËÉd¾•ö ½uâ¹ɬ|¤Ýkå±G:œœ7ˆåñMhc´NÒÙRh0Í:6T“Q9TOÌf‚gÛÑN²ŽŠ/xEaSð×Í3Ä,@Ï®»…ù"ùøú¤;0á³è¬ß€•Ï>, F_m'Âײ‚¸OIT®?´ÞØtÚ>rÃq æwïÅúðÙ!7~›9Bë«2ü±f åœÑ×'¿€ü€.¿V£‹¬×’6í) PÙˆœ𠸇¿22ЮS:bóÈ©l ø´Fƒubºxþ×ð—ŠdVŠÒR›&¨Vƒ%+9 ¨U›"¦ùºâ<Þ—-'Z›FI«c±&¶ô“ý~ze|&p.Ñ"ƒº|é ˜wh&Üv0ªâ4únÄÙ~:óù¾(‡þ=ÍùíE®5vèa\U;‡<¢»VÍ…ñ¨?ô‡¢µ²-% zã©UÏÉsOx›âmS™½Ëì ‹LOûÊîÐ-¤‹î‰ƒ|îÙ­ò�ä˜iA¼ë%|±ßg*=À×Í ÌGþ@ÖÑw£ù�ÎÛ Ãau*su &$ÔÓå® P8°Š\éŒ�ƒ±47Ñgq�G¿ð…1®'µaWâ.œ¡}‡ª¾òÄW2)À½z <~×à*?H°yLÅ-¤ñú°è¾’¤ßV/&®î³aÚW¹I§OÕ¡4À)Åô‘Ý.vgÜ)°Ñ˜ÖNÞ'—9¿è¬c}¬¸ù*Þµ«­4¿6î¤pA®· ½á8qãô’säÈTaìYˆdÙ<{ì‰Z ò?ÓU-ŸÈ=Ï_´az&]•{’ˆÞo"©Û‚q¡\ ñ�¹Êˆš _Íé�gÙÝlÂç—�¯-§qfñ ¬^…;“uÐúÅAªÒ èüX÷˘]^ËŽ�$ã¶�õàrK·>;Æ.vÑÄþùðÉ'’¿(AÏݼ«5Á¼Z3'NîÇ2e9®€§*PÓ4Ú4­~íß‚Ûãn’  C0¦÷ÿàüâ›Â|xÔ½ö-³&-žfr`HÞ‹ìäá M[øU¬'΢è[Y r˜Ë\úeDôíúÉ¿!>ÐtµÀêˆ"ßéÞ�xؾדùñ]K$©“ù@Þæ£í ÓQÒ"…•['‚½¯�÷�]ôò2>”L°"Ux§)Œ`Yòv��G;N‚óžX"{n,‚ú«éDÏI�›öÛ‰n­ºÈî ½MVýÓ'�ºk0ýø¦0ú¶ÊÇó=ÎàïŠÇO‡‚wž8·ÁA¨F¯²‡šÄ†Cé–é5ÕË'ýe‡M³îU�¼¢�ÚÓ¹œE°üR95�ÆDf Œ3;ñçh-½šÛ«’PÛu5 ’ÉÇôµvdÛú 0Ñš |&7X®÷\~ù—ºˆá¬çMÈUy…ŽÒ‚if(±X}–:c°Ú5(ë¼€{•ø‰ÑнðùØ=XPû›x9>`VÅfÀ–�wñ£Ê Lõ{@ìÏߤýõßéߨEøe¹7<{�@Á÷ –|»“S¡öxøHî¥øl°Ðk [Þ'é}½¤â¾1˜Ù‰¢Íå9t¶¨;ùêx ì³`¯ß=º‹M!Žfqpéŵ_O“bz³ÇÍ¿oBçÓâ «Çë Pìe°—r„°ÍhWÇ\ëeŸLQ”{–ž '°8å+Ù£lœè/TMo€‘¨#;<„i@ÞSv‡Þ4Ú;ã,_ÚÂÎû2VgÓÒ]ò ¦²†åQ(¨‹*í'#½g`ŸÅW¢±R…ò/@¬Üµ@=,gÍžŽß”ùÁê’š®]M³Ä/áÛDL ͦƒoÓ…ÎÑr¸}h?ÓÉWˆ=ý (ø/½Ã3ç/^-ù|°æ¹4YZg�<$F¥CåÓÇÔñßi5àœïióiS¶x׺€àp5&¿­¡_—j‹Teì8*ÆýV"ÁîfKÏú Ä�óté|z9PÏG„#ÏWÜåéÌ*‚pWwT4ð%'·-��w¼a ÉÅóêáüš&ö‚Xò¤ŸÒ *ÁÐ8¶âÖ.]zïÐ/x£reŠÔôZ&wó[øðÎÙ˜…õú1³!–�v®¥Ü ˜ÚÇ™ÙE!QtŽÌ´§ª*!pIzÑŸÌ«:}8ü¡‰œR•õØPá…ßm¾‰Æ*VìØcjÁgJÃZËèºÙ‘4âWY ÙEžK¨sµõ§Á¥çÑSµwU䯸Œ|U ÃûœÑ9G \ž& ÌÝ"ªý…èM—”ðá…"{|6,ˆ«Bnã‡ûÈL‰ çܩއ N'À‘´Vœ6ZC×I­�/>"TÞÃ�®J,­cÅ¡ÙûLwg4úm[¿K”õË@“`i§Æu/~L “ÐÓŒ®‰ 䢘 7£'/q:霃½bãt�Ûy ÕdWž[‚ù†¤¢©ôžYÒ¬· �sÕæ[  Oz5áèÅ à~“TãÞ$½_'HÂÔy5�à°±‚i~ÇŒ>µF‹¯ÎðÊx9ŽX<¢Qݒ܉M;è¥bêèWO�·HÔÜ;ù‡¾|ªƒænpðÉT°ÜRV‚Üâ©ítÌF"Ô7²ÛÅè;é ˜:,PÓp§?ÉÏ‚oŸ§wï\²ÛO*~�†÷gN‘Û[ óôTèY:>'‰ÜDˆ¾k YˆÜºï¬ÎZ8påödß1Àï-Ýôת>2ëÃwö÷ë7hþsÆe·Ðí’öS½ê'ü¨g«�o_È:lq#U¿P»©Š�o�¹�8|¯¶ºSô‡‰Z` côþ„OäBè,A ×¾FVxñàÇ9˜³ü!~ØiLäV8ã|FÔ|[à`¦ˇ’ªžH´©!b›PÇÞ“Ó8¡I+úœÐ£]c:át¦‚ñâc «s¤ð »ñ·9 ^@[ÿRfOñUê¨QO"³d¹Æíéè|ªŒ®'.»Â3 AêÛ\ìiœ[.ÓÔ”ŸtãA%ÒÙ?:¨ûø€{su˜ÆÐ§QF#w•ŠQÆ—ŸVÒŸoÂ1u, ¸šAKÿ+™°¼L.ªÍ€w‹ÒØñø[äþB;ˆüJäsyÒæ‚b(€‰gÙaß§¤Ùx‚LL>g|ß^´ÐbˆVH+ŽowbF-d>¿üË ^w…mM|W‹hws u}™H;®Kp­FøH‚`£XjŒæ�³áÉY¸vï u‚ƒdÎǜڟ€î.6àn‰çº®Ó5�®�ªýMˆ‹~Ibÿ?7`É�t_×fü½ ­W–­iù*P³9\o¹ÕáiÃ(’³ü2 J §í×lðà,S:¦­LOĬCö0Ð[軋.¡¤÷ihlzŹü¸§l\…óODa¹®f$ýæTuÛÂk¾M8½EFûÑfa=[[Ép~õÓ /œÉ^…—Vš(!¹ßëIñÛØßw‘ �?%â#W˜…ñrè-H)?cMB�, rÆèú?—ÉIÿy`™†¼]Ó‘ »aµÄiP�„iÎGOàð} ©^JTF3ÚUk6—§�½Ø6µA¬ü—¢qÜ8kö1¶Ûf¡¡u1 ¼XG?‹²bQP<èNe”D‰À4¼¹Ç=~ Ô<Úv˜jM“QÃVfÎèRžÆ�lŒ© Ek4£ŸÎÔÓi^ΰaÌ ;•[Ø\è#^纙-KÏÁŽ6:uYÙó¯ŽÈ¨µ“ÃÛÚØŸcR8ìóœJŽN£ò8#0…K7OÉÀy’9ø£Êþ&ã3þšÜ -ŸÌ€Àõ�0|ð"Z=dO]<ÇØ,~Ç”mƒ‹š&`VSB_¸ËŠTÏ�úo!´]ç!ñÔ`é­xx�–¶XâDŒ3Yf´ž'7›%Å©Dcözèo Â…³î"×Ç�«ýs<ñ†¡RØ• yé5Äñß^<ås“þü: �G×åÖ 4 É…Ý«‚É¡�ßiǦ@à�žÆ ñÐeybL—¢¤} Qd“п§ù.Üg%ØoÕ·çâ1¯U8þ°Œ�‘>zJAÃeá±PY«¸d¦áz]Y´Ùö†nþ±—¾*Y‰¦ÃsI祥øƒ7Æ8‡côÓ$rzB‚Û­yB×´ïsi•n)~üµ•×ÜdgÐßgÆÉª¥à�íS¢¥�×J³Æßn€q/…0zW­šZi@SÏO­§à}A;{þ¯#�‹ÉиÚ¼œ�Ù÷—ˆcËÏ ì,ˆÃ;òx&H¦æH}x-šœ}Þ fÃq>d÷bÕ®JAï% BçÙ�a‹@Þ�¡+„úØMŸOýKÙCôØØà²Ÿ�ÙŒÓï"C• °ãæBpÿ— •zÝäѲ½ ¿;P^‡®]~´/‘ðl&eÐNt„NÇDfÆ��¤ §ÝúÈës´¹?‹œ~3lš„©­Ñ 8ܯI§¾b^´Í_âx߀C¡® ʇÞP7N¹¡‘ ì’³h›ƒÚèD”2Í{u ñ©ž¬O)‡ë_“—[àß­K°µ�ü bŸuO%îÿƒÄÈ+““·ÑñŽwDi..“FÝ”ûôÝÇû¤Y-“Ô¤À)ò ·rTí½ñ§x|2ŽÀ�ÙîÈUpÄh~g0Ó]ŸÄß¢Ì '[n ²w�á}NøÇsÙE²¨¯÷ €®õJ8íÛ©æçÇ$ÜC‡=)ÏÏÎÍŠ„9=†(ÅçÇ2»Ž�Õ§�2~öÎ�'ƒÏÐÍ^«afª^;ÉÁkuñòÜ×`™~Ÿ}µR¯ßÓG×ÁìÆJ8_|"y¼+——â¦ü³xÃ8 #„Ip¶&._ŠBvÁx"#ZÔû‰Ss8Æe\ƒÈd¬Ê½À¼Òòň¿ŸØf…#äóYŒ³d†ÌÁí¤0nN°‹~Œv †ÂC{èýÊ$êøÕ—pº]‡Zp¥ä3ò!Æ‚¾)Ý�æüÝDJÁ|ÚÛèô0ÔÕÌÚšÞ ¯–�©Ùé'}Ñ3­|^ÑϦ¯™ÒÙz´*,Ÿœé(Àìá¯dä�-ÝwÊ⧤acØ.Ôu‰BÍdy|½Lˆ=9¢m‘Jö'À†MØ1N¼`À¿o V˜®ÞŒ~ª˜N9ëcPµe1™ÈªÂe¥d' ¼þœ#cÕýÔ7+ |®š`ìNE¦÷ý&x¼8–“¹ZÚ>°xÿ§B#I3RáΨͤ­¬ ¦K/Ï®Ä&ÛD�ÏœÑÈ«^ÿÏ‹Éz<Ÿy—È1KÈm³ÏÐí¸ý3>ÒŸz­tÝm[¬�°‡zs)0Qàš&-té[ËÕv›�&w8ðOQ Ý:œhÞÆP\ðë$Yöì6H‰dà¨øÌ�i¸šhÿbI*ʹû¨/¢RWpOz6hùB~¿¬ØÁsIøÂ.\* מÐwk ¨r¸%y÷á2˜r”ààÑm V²�ñ˜éK¿K«Ã—£æ8{f>¼jZ”¼ßg‚Z™QdIðOÊ·u.�93z2Km0nOS|â1±»ÿ‹]÷B�ÎË ÿŽKr×9cè]øÕÞ@†’ØŒu8÷ïˆ}„4|LϽ³Ãƒ».‘7G7ã¾Y‰5à�¯9C–%†°6}Éæ#* ¦ômçÐÓcáÚTö†Dm:5é¡Ý�7(­.F×\)ÈïË ù*Êð°Üx€ãŸ5t�h)zÈ+à·Õ!46øÔ:׃ީº\Ö™(Ç‚L¬®rˆ ¥û¾�í®‘0Ã%ñcËx?~Ýsµr¶ëÀ—»+ ehUZibƒCD|‘±—ÝIþÈúÇå¨Ä rŸu�2ꛋñœ|0jü¼zFmxOFl%BÉÙ-7‰Pø]H(Å7íR8=6ûx}MV‰ïÆý’‡P®)GPL^qÀÜ´ç‚3k _�˜?FçPÜv9ì|ÑÇî¨w§ëÆNo½Ê`bc€EI)è¿JJx@gÑ)ô]Bý]¿¯Lt¹'‹‡Âu±ÞãSΟO\€©1P’ÃÛI_9Z«ƒÈ];|ºô)›4Eò:>ÐHšßÚ‰”.Å–®Xšvò#zš_w‚9÷$,´€Y»�“‘xTö,%_sZéÚI˜²Ä7Þ´a4÷�ƒÑoñØþ«Pÿå&ûÓÆŠîÙÑKJB’ sãQ’­Ü¿ÎÐÞ׿h¢S:ÑZ ÂÝöß7¬Ý†)àD'>Y`è¢X0õ+a.èðØ¢ªflèØ‡ ïn1w^ƒvWkrd�#ú¼B^cØÌO‚Eõ&4 ¯¿¤ÝàxzFk<‡¯ÓèTôœU�+ËÎ;ÿ†€ Œ¸=$?ïSßçEää}72ÍF%,ÊéÂÚ|øiÍ£W¿Fâ¾úÍ4bê}<ç .ÿy›”g-£áKÂèø^%¼Å®Â *+z°ß€Juy`ÝÓUØ&ò̯û“/§oÑ——v^ò ¸õÁ­õ·à™§ðð¢/À33¹µ  z¼�–.)ûÁDò>¯XjAc!Åö°º.kœäΊ�Þ‰f5-!7ÿÖÓýwòÀ±Sœ>lÚʘÞÀ]]½ÎI¸Úy,ÈšS®•c¯ú:ØûªŒvq÷Á5ï;ôlˆvjÊן³ðãÙ8>Ph€ýÊC´&~5^r"$ÉKœ¤ðó� Á’3i×OoØ#Ã1ä|¾q¼C^·©ÔØ�ì¥æWàé8v|a´w$CŽc-&nVfèÞõPt±Ž,"¦OŒa¬Í€Y}€S·.›Ýq§”šK�Ô#ø ,¾ß8†B�­‰Òó2è[W«âBÑCC2çBžO ¤’&!ãK>žjáC™BE2'UŒ6jMZyg#ïÿÒã³|éNüãNäMºÈ¶mCà⬠N;ž±ë|2‰XbÍ3ˆ�¢4’µä<ùíN>{þå8º'ÈÆ ðÞ ”5\ÅF›VúÆg:*9·Q÷už4yûíÉBù?O† Óù‡èðo—)™h~,|CHGBÞ ApÌØ£´¨éA:Ëq¶�(6 þGߊÿ¥¥\=XÐȃm»“È\£8úœ-ÿáƒÑ wÏ^í: J¢idz·hVÝΑÕÒÄ.sEüz^‹Üß­ƒwÇ\àŽÏEøx:ºER#?Mo‘ áªôµ §_L¢–ùt{u™±£»’äÈGõAò1-™•9LþÞHüÝr–´}òñ|~(Ør Ä$šÑkÔ#-öAýÚZTÿO·kÞ#o­øaþ×HšÞø îÍ>†»è`ÊÐÓ­¢� ™êãCò>nÅVQô²t€—ï�CµÅtx0›æmóƒ9ŸÄ@_5ü*$w¦{�‚r+bsê&<~5§æêû8h)ÃýÇŽ0Œç Øvf&Wúbga“3‹®}9L´w~#|ÏõasÐpkÓ¦ï&B•Ã5L»M‹‹TpÝ5AÜ!oŽþ¿KHÚ0°H€k¦ä‡Êõé’%"pEà‘þ7Ìè;nDùN}õ—u>b‰�W¥¼ FÑ1eÒàWÅkøprßD8½ãõ­�$�ÊMèjã‚5&�àçÂAH»žˆW_mÆsí§x¿=ò`‘Ìešy—xJZÁ@n%í ³Ã¿¼7Ù&}~ƒÞßÙKt¾k’¾­9¼½)ØyQ2Ÿ;‘�˜xÎj‡^䎖!·]„Ù~Nˆüð™�?Ö¤Ñ5éqÿ5<¹Y›Š;Üůí}$fñb0í�§¹ÆÍÔ0c-;çõ Rª·ަǃÍYx›Õ#ÒáŸéà45Ü`{šñ9žŠýï©•Ö!ˆQ“¡—ØÃ£¦E5eÚ#Ôd¥3Ì�ÝL/+δ§cttÖ(ÜØJ_eN‡ 3ÃàÀÌ ²Ë> Nm¶GyÃF,ŽÃÁ|Ú "ç$p|©¡ñždŽŒ–ñŸGÑ¡$b˹†?Nl€uS.™ôÿXlÙËuÒY×éOÉ5ƒu5£k·�u–ä×ú¥¸ãM¾dÀèhø^côÅÐÎI�JÚ±Ô³ cI2jÝ­¦WoÃÁS+qï! b•½^A;ä*@²¤!Ù�°#/Êàrù©xåÊR“½‘h°Çñ�LôM`Ôö MzwŒl)‰ ›>VÑ7–9³\�»6f1jœ¼[— °·ç:mDtö=€ö¨·ôÄ–Rºlü"ëwTu®˜áê£äíÊ­8<+’ª¡;µDnê 5ÑÇŸl%Úý£?e‘)K‰sÂZØ·2”ŽÞøKëzÞàÈít²o@áütfX;�Øøë€¬¬(ì -ÝiÜÂ�e4‘̬Q»x >ŒBØeH™³\ �Ï…¶ä>â~ž¡åÏŠñÈË«Xžï�Ù%/˜’²$*ãÜFDÛ²AaÀ»”�ím¨Ø„¯·Ý$³/�Á-gbÛˆ$ýìŒ^�—¡R…ƒÁ¬(|;l»þ="ó&­þÜÏ©éÀãø£h£ò›Š?ïÀ_InDN½ÒC?•çÓg“Ýdâ˜,YyÝ :ûµ1;{ÜL7Å´ë\|R„äØ'ºÒ³žøÿEr=� ÊŸ£¡5`”̸QF]öòfž9Ë %ÎÀíUìÐZCÜöZšr”øè†<>šíïËN=q—ÝòÍžÍ÷&ßÄÅ^O/Ž„äd“•Ëcளþ6WE-9¼J(£›ý]IòÇmì‡7Þœd]%Ÿüæì?‘äÊùØ8»­Z±ê,v]ÿ@—^T¥âgàûAm·é­ ?‚s5Z'çð$-x.Ÿ·BˆO0í 㣌þb�a�ó{OÒ‹æ0eª8^k]J¿<ß)«kX![w&ïoˆEÿ"êö* ù ‰Ê÷JÒùândS?e]]EaÞÎV²wƒ(HTëƒî©Hü\ uµoa0Í$Çr!Ò\‚Ä~rbSʆ‰UQ4“•ø6ž³b&`ä´8èø’=×U»Ñ«_¢¼‡5+ä¾)“³2}”–ß„ÅNµ4ÉN:/ˆU›ïU‡µkðHd†ÄœãØqgÂã¹øîÊ fãŠ(œ‘<—NõÇãK: ðè%º½ª…Ü�‰%BZÙ’Ä«’¦mª}‰œØf©ƒjL¸ñJ´Ì]„[¬oÀ!Í×ä­Å\ãZ�>á<2;`9Fi–ñ-B¸÷ɹ#:çyeÂt©ƒpâÙiPj#Êý[™˜¬ôÐÛjÎè.%ü¤éÌÔIßb²Ã¾Åžnúoâñ4L‹»žxç¥7ªmí&ÍzÓ0ls=nûp�d˜LÐ{öÓÏéôxRx=yk”à‰Ð2Ó}Töd+ñ;çÜ¡•_Á& ¤R)ÓÇL›ÉsÚmœŠ^JœÕß… À2œžLåOßWÓ嘖9Á*L÷¤J]äaõTn“Y qR™ƒwïP¹ï¤c“+8j8ýÿ_ ®&…týÃyxry£|Ê›8= £ÜNº¶i�Jšg¢sÙÞcj5vûÓà^èKšþG\ªÍðßöu¤P½¤º4¾_zÓŽ¬…h�q\&2Ð'Çœ6`<[öEº{EHÀ�$t¿´ ”)Cmi&»²øÉõµeÖ ”2wn®#×,gâ:u Ö�^à/x¯3Ÿvëà²ú¤×}&%ÎQ´xÞ~j¨ŠéŒ)[¨G’o<¦½Ë.Mîäí¸MýÇu<BÏ �~£Q†‹6Prúý¤úŒþû¹ >ž²fýÏn ‰ZSÑæÓF88¯�–À¢}ÊÓ·Âð±cŒÓú,�c «¾“Ý«4ì’?Y½´ûBK1,S ¿[„ÚC©tdA&-ýÛÇò Ño…Õ|ºrZ�ᬇ|t�ÒMºÓ˜KS$˜7âc$¼µ ë»ô!8nÌÁ`gI¨3 Ió·SKý\H2žŽ}VV¹€¹øà‰›U‚�þ�Óhc¼Æéf¬þ¤‚Ëg‘Ú©:ØÐB×Y-¢^‡s!ª³Ó’%ñXÁ9ž{”ý:>�öÅz“Ê{¯yÎoì@bÓ8zäšÁT^ØØ  ƒ®+£PüžÚ/�¼yÒøâR=KŒ šRíMdáx$¹–ÍÖ4;ºÂW‹üظš0Tä€Ì¡ÃXdXƒ<çC¿—>qk„]�fØö)…ØF•SkÉšÝ:8­³–nO¦ýJíè¶÷³S4�Ÿ�»¹7Á}u?•ZŒÜšy5„=ô¡JR‰“”>.™½§ІÓr)xë€3«ûû"&îØ@ílaêÛLï)•û5Ì.’I¥û¤â°<[Œž>d·x?á“ ÐcöeØåâ„ò/b¡ZRv¿Ú #R³Óˆe�4Å…à;Eˆ3»‡f‡¥¡Hêh(ºÃÚ¶N²AöEû`è;³™UÅO;SÉ£­±&ßeµqª§³Á%�7Á$Ñ z0ø‰ ”œU„ÒGpߦ3ë§Mß ¼�®Ð÷ÌÊe×h@úýèý„(¸v`3|½ä°U_[·4 6 q•ª¢è¹ïõtE¿;­Z†ÆÒ�üðSÐ6ú\Kñ…« Þ!ònÒL¶ ?z,�…’ËkpôUdi¦£ÑÌ4"u½Ÿìí)¡îã”ÂJ²hý=úÈâ%¾ m¥›?E0~fÏàÇQ9®éˆzÝ¿Šc=Gáá´T\Ÿµ ”,?‘CÒ ¤"´&6Ý&…7¾²¦ßœ€Çeüv'‡$èL¡ÛªçÂÒ vº}û2[j?¼9CäÇ¢ØÌ“DLQ–u‹BUóêCøjâ¦<#‡×lâî®j¤1E°½bÒ¿ìàvK4}ùÏ€Îr­#x!…-Mùvï[‰Ó™@ÜX€ù¹—Á®ÀŸ·×²¯Òýá‰À�62…{Àæ#�i댲ѭ( thÉÐ�æ|¶½ ¤~#�+Þ±)�ÃhMb|iV‚ÅKp%- o™²8!`AøA27ÛdUAí׾ϸGM«%À¾+•[»ÃÓÛY˜60ˆç˜!èa¾‘X—<Üíáƒ.ì ¿ÊE ìHO›aÕÈïóÀ]l §pä~eÛç€kÙ]^_PGÌ–ƒÜ2gIl[ULFC¸÷n+”ñ§ƒœ–ås64àÌ—ÍL¯ÝUºäå&ÜÏ1†á U¨1œÇm¯ûäT½&T§’s—¡7’Z¾×—KpA^ìо:µ»¡»!Š]13ú£ñÜÆÚä[) ›¯X£È‹#Ü7ô“¤#^ý˜Í¾g‘ž¡Òlù»%wáÏw˜„ïö°ð˨¾±ó€3e(¶^�ãJÞq#ÉËÖ`¼Ñrƺ!”Ì»°‡—óë –4‡�gð6Ð~dN]æTAæòkðuêOúÙû! ¥þD°=žŽ¥ÏÇF—¡yî0]ÙІŸM›¢vàAV…Í(­ýJ|Ř�:!¤ÇJ §ïÿ†fbuÌòÏ6Z£9 wwD`èÝçx?³‚ZGÕŸ‹ $Oë@i~®¥åyïy�´Çý¤Ý˯B—òB`§AŠ•/˜§:ão ;Ï4 ¾±¥08qdšÐ½o6vï· 6ÊÐb½†pU ‰Æ�õpýYÞ›'Ç½î´ ,x‚QO^S¿6[ꙩ{ÓÿžáÌšÕñtñÕ}(ëªó"ŸÃ'oPØw�9³J%�}é:‘è�ý…¡º  ð‹¸³'âYh:éFó°|ÎeOm|T‘ƒ §pFÂ~¨½fÄžWî‡ñìDÔOWÀp³[$ÑQ•x’ �ɆZ J?X‘ô­z�ß_FW%îfÕ‹¢1äqÈΘFÝ#2IB±d\‚iéÑÄ6ù#Õš¿ï/á ì †¬…Ëð„ÁzaÆUgeX…‰É|²/gk 98ôª–XtæÃHÍQvÞP,È/¼ž;`xè ñÁ› ’šÆÝ[ɤg$â9³Up-%×x`éýçLM` .ßOšoí§ê¬kÙ nÜ ؼƒœytmÎ{ÂIt[¾­c4G½#[Ïçáðâ'ðö»*œÔ7¥Z~¨«V§s~ ¾²Ã˜÷‡%óEñù3èÀtW– Z=9 餛Îy"…F…%$AXôd-¹‹bE)›YH†ªó€ _ÂSJ+ᘟºÕNvѽŰ:3�{ñœ–5®yTXË8Šìƒ¢œ)xðµ¾q“ì«#õ_ß,¯’ƒ½™3¹[µ+Øý*WÀ´f7E�šï·‚ЫD‹Èœ¸‡m…Ï©K5Ý‘kCV³*¿?ášE ¤w<?}«!'ÛD¹>�f± Iúº•.hP&ÇÔÓ±·“/ºÑ=U™ÈËÏÇ�yOILB$f0ÔhÅ7ߌ.¦Ð×™À´7¨£QŽ“¨@…-m Ø��ü KÛ7ÁñŽ.âá {xñ1æø%ÿ>‰_Š ‹×S“CB´Nã&òj³àÆçËt¯Œåæ?f�~]ǰºmèJV×5{À[YZ.ÞÀ¤¤aÖuÓJÈçÊã£ÖÍpzåM¶±¾ž*‹XÃÊW¯éµ1dïë+d¤Ö -cý³¶Ø''ŠwЍèòLx[%DÞ‰Åc¿mÈüÃ}Ë€Ø�ý˜ŸÎ®–÷ :CQy™R�N×ÂÊ[O8•©ÿù‡jþ ÓdÓÉ­}´¿Y¹fù€<(5'ûÝwàðüí«ã+Àc½I¸-Šù®ÔrA r¶†áÍ�iôÀ±Të—¤8Ðú_ó°"> ÞÜLŽùxÑ‘³VÈîŒÄ—?Ü_H²æ³ö É·)dq½¦Êž /Lm';ìV|®Áy[0ÍÖm$xvCÞ ÒGŸÐßú[Q™š5®As{”nƒ‚Z°éø™{%’l­K··nãØÇd&c` ¶ýø�›Ö�€m $q~ ø›9ANuþøÓHããî€ÈîµX²à.¹uÇ‘Nsï'BÉ–ìØŸ{´ê� ˆ¼ '™[ÒIFåäî´Ÿ†u™/¡ò© ¼ôÜ�×,Tá‰Am]–‰wBs`âÎ2°Þñ—åo2ïSˆÈDt¤Tx²æÄD€È±ùPÿ¯¯ÒÄY™”¹�Ð8ê �¸Á{ãúèƒ:.2„îeºð¬×*÷VïÕŸxƒsqI'â‰7Clê`Ü“Ñ þºRpÁC\uò°Øf!&¤G�ü ÍWÍàÑ[ˆ^s�c[4�Ø|O~óýæIGMÅž•Ÿˆþª,˜z»¾Nån28 nO.µÓ5´ÏÒ|Òë—éûbâöÊ4{ ¸åŧL¶ð%ÐBш^¬MÖ[Û“¬M´Xª ‘?ßO£ØÔD|¢l {ÖDaR¢)n›u“8l�@3ëó ²^*ㇺgðŸª|ó袭ÍÒTð´QÚD›ë½�O�ŸÛ¾^Ì6þWN4cµ 4žŸ9*¼ ÇßžƒÈܪq`füÕF‹ŽH’±=œJ>!žN‹ÈÔz~d÷ñß�¼îgk©zKÉI{Aw›.§Üg,q¬&»ô8¡Ï`Ù‰›¼÷I7˜¢Ï~¸±ìÔEVÓ%×öÓ~qüa ïZÏáUþ§ [DøšTq¼ãyx¼�ˆ•¥â½=5ø«ûUl¡iõ#4h2l¸KiçæÐê< Þ¶?8�£dð¾)x×J€UÆt¸.²ÄŠ@g«¬dßQÞŒ½Xš�ÿÞ“Á”È{EÏf&r*óìH¾µ Ø{KÖû^JOé¿_GA×m ÷Ì7#/zî‘·†C¿–†B¯H¸¼àÝs 5½Ì•‰èJ¸ÍV*%a<½{7Í Ûb/0 ÂJÐVáE2 É�+1$¿Vµ&æ—)h„œe^í{¤Ûi‹—-™ý‰I>J¾¿KÅ]yE¨;#—úZl�M‹eá¿iýDfÊZ”‰W‡¹Z×A+R»ÚhO#ü|ÕÇ䫿� V�·Ò—iÑâ`0ˆm¢;ß—ÑnAôõ—aVtIÂ5sÈ÷¼I¥�ä^w&k6ŸÅÃw �ßö™\‰«Æ:Ÿípvü®[Õ‚½Ê¬O“ÊŸY›³8d ‘·mðôÌXFÃ%^ÖäbÂg/¼bcòÝ­�DÏzIîöžñÛ…˜ëV†o• Q~q´®üÒ—Eà—zI; ¾d“¯Â>ȧeÊÞí<Ë{p%�¬M%—´Ò©Õõt #ßw<ƒÆVÜ=ÿ8úi̤-WÓÀŸ¯† 㬢ºqí~KÍ„Dj䟠*]á¤wb æh��Yœx‘Ã8�:Cz˜þ9ÿžyVS‹ÆÓUð‘ñF\÷ÄòWË`ÁÓzNs‘Üø/€ÖÉ»à°Q4‚ú8‘+^ËH™&áÝ98ìiŠSA zÝ ¡áŸ&:È_ç™7ÆÓ}¾P.ú)µš`éåÉž¥óð3îr™Iæ{6ƒôÂ% ·Ú昒³¬ªX¯@ë1-t‰ÿÊdüyE}n\"ϸJøNý Œö¥�Y ®“ÌÂ6d«�±`8›³¥Üƒ™˜E£#»°}ìÙ,+ƒn‚Äuí90qüCvéEAΜxh¶ä‡U[pêç)ÜŽ­‡èúŒDFÍú.M}ÜBSçÇ“Ÿ%�xáo"mH¹Gº�¸ƒ¹påÝJè›<Ë}!µìùd|dÛOߪ;ÏÛ‹é‘EÉ«Uiï‘\à8†òæbè[+Œ}á0:/‚¬kJÅf–rÍîPëöT˜Üò?ŠÍ3žëï ãöŒ²•„h�2?çÆ¯I¥­ˆ’(E“TRvöHd+¢4…Š|?÷-)JeDI*Ñ”öÐæßÿÑy~^ïë\×ûÁA“Ž(Ó�+Õòm,Ö´Á#ÅÅð_u2ÛS>@¢ïØáÒ0rÒ)DÇ�IM¬láHíái¨–΂š[¥,Ñý/öçLéó×¹o¢A,pÉrè�·žêKõÈ Üœ¤¤ìÜ?Ú°z—ƒ°ÎñŸ3\ô€¥Fm¶wÈÓË#ºn­Ã:«vñ›†E“r¹³æ„Þ`�kåhûØ  úptß/ÿ/Òl¬øtøèš+¨xªÍ·9SÙ×;ÜrG~ñIa[4u¨Xj=ŒœêFu àæöavi� ýªúÈÙ_ƒ|�Ü1l‡ö«Ðð%»ÈÁ§ìÁ'5Úpã‹á´Àà­ÆŒ�·‘VѦ·ÕÆtãB,lïüÎJ§Tq²>ïX¸·K–�€·�b úU};ÊÙê·;ÁvËa\簾¢µT›ÒÍœT}Ùýu?q~@•¬>…ZKcÙG±48n�F%ß©²½�Í‘ÏßùÈΛC�^-Š×W®uY¯Ç¶Ç^Çž3í¨› ò'ƒsÊ(�¥îƒ�dòˆ%Y‚”qhÝÐd*êÓ‚¿JFtYÃ"ÒBw²c©ékDsré~™!IMñ E«±ÐÜ‘KÒóž1ß]×àÛ©›ìÇ!Öpå›ù‚³Õƒþ ÂØT¹(vÙø+ }÷Æîp -†>ìÊ~ý5„ÐöCpYE�ö[bÇ‚@v+P̼æc˜³0t¯e×$s l^y‡‡Ñ°Ö9ˆ*t¥’IŸqkçdq-¥¡øý(Ö”Hºž'¹úsVÔ.tl÷³°É±ÌÈ®ŠL'êÁÐ›Ãøô“=ÔˆQÂ'oZsÜÕVh“nF”æ¦Qzj´ýjh�êŠSX×-ÁŒ2QwÖÁŽ MZ5äÊO½±„µ ]‚Šß(ÕÖ§&˜ƒm’R )©ƒÐíz^Ø\¤Ö5öso ¦kß©wà<„¤§‚CbÓËCqZy©n/Ò峿 ª)[ꈭø¨á-n{\Ž7ÝmÙ—˜dx´Óš©.° Ì YØg¡ÑtrŒ-VÜÈ„‹+¡�K;½ ‘öhj‹…cæý‡ßZ?³ifk)©¯œÉÙ«P�ÜþÄn'8Šö�8? ïšî…á´ïOä‡Å¢¦xštJ:†¦°´ÙEÌùd¨/Ô§‡'ïB�R2&ÿ�…Å7/ÁÎø•£F¡›};�^úžÉ®L‡K'oR5M£q ½iLýXšé1•o‘ãÖŽÛÏSz…?u…�ß3áí%7ŠšßÁ\òØqOŸ ¾ A¶û›íÁ1Z°Ô˜5†&�ÅÆVᲚ<bB¿2Þ‘‡ Ç¥aqìV>­¡Ã?Ø¡•™¯¾8�i{H3³¼ø»Y×¢08`)W›æ¾÷ûÉãáQ øÇ.Œœ5õÑQw2º0>B>  LaÞí;p:h2]kŒ€ÝBW`ñ[¿?ÉÔ.i.Š¥f›#¸v5 )À°cß™J§�gÙ*«vÚ~½MKg]‚M‡ h{ãL˜·xhéh’ffÌú<’¢bþaûé"6œI'·=œhõ°`Ôú0Ö­8Ón�ƒÜW#á»îX}ˆâ²“ñÄç^¦ý`”FÞAIÙ(¹M.„lǽÔÈ ‰Ø‹÷iaH>3+¯ä5†š}n,#`)»Ë€ˆ)imzǶ�ò¥,yI';J¯+¨T4ïÌ—Dé$p¿s‘‰ŽØHO—;á§ŒG‚ãë—c�n žë[Oq�ðékvTAø}~ZÝ*ž—^ïZñøÐ"È;ÿ\°"ö‹íªö4å´Ä$.Ǿ©`ØA-IŒÍÏs.Û²dOß û1,h' ¦“Xï,Ï]Š’gÊ=¹H�OSÑöS!}ú9�–ØØŸ�§Y\]U´ÇZ'YŠÝ*àÊçE“ÊíXÕ"BNϽl7¹Tðƃjô1ø=={‘ƒ¢Øê Kz©äÂL�‹¡(^˜6M¹9‚]ÿµ’÷Ú9òòw³ÐÇÈ7àU´Åtܺ vDÛ‘Vñ¿óO*iŸ¢Wùk9ç¸ tê²7]“ºÎŠd=AØ «úÉG¡Ÿ%6ÈÒcöœmri…ÅÞ†¬¬ï(¼3V Åý]�–k¥½²à“ÞÀî¦P¡ êrޱƲv=Ö/ù I˜�¨gY7Þ>kA_q üdáhwü“i*ƒý“®¡û¬Õè×ðž…ìN"ýÏ'©!j-4JÞ¤Û3Hs¶(�´›AN|å²4Õií][Tá…Ji~+nÿTêg�åDG²~E’ž_�SÇ}`mJL%ÿ,†\Kgkýa𘠄ÝLäô¼üÈå°Xí´=ýìæ�2Zgø;ß$‚FF7ùôDP_¾0XÔ/…€êtþ³YŽ Ò<Š®ìÀáÕ*´ÏéŸÛ{´†Ó Ð+®,¨¯q¿›Gòº ãbç4Or�)éœÇä@RVèÀ¦Ðyc"UÝ|ÍZ…ò8×#Ñ‚‰µŒB·ãÜ *Ûü<'ˆ®üƒƒŽ�ìÐú*:­ÆSÍ”%lOä ö"*79[‚hñ!Ö½:7ŒCwuf|)Jtº˜ù—XL®˜I¿Æ%pÊŸýIM¯´lÿC)¿_|°ý^vØÛŠ}«û .Q7XÜŽµP f ªËžà¯)þ^÷ÿù`^$ŠP¬hx~¨EÏž›lñÝ'�à4Ä”ç(g§ U³6Qê²|ô4˜Ä³—&ó�—qÕ½N–¾Qš µkà)¹ (ZcÅÊZ„í µJaß� ¼m<ÆËORG­¹¦lß8Ä´ÎE‹ø±p-RôN[ƒ�t!]Iz™#j¥Ž$Òh¯ýÜæß“éOß%òç+¿äd$×ôôí}]�o”¿±�ÜÅh}y V¸€¬þ7øõ7�öed¡ÓóÑÔ¿—¢=cè~�ˆ�…$_ÞüÿsAâß¾_48Ž¿uý/ŸoK׺à‹Ô¦ïîÎKL]„Íž:8~H ò{çƒÀ6Œÿ»Í† \Ø èÃæ‚9ä±ß¸Æ?L‘õ…ÈÚM›»ƒ‰™÷AB�ý2Ÿ�ct´Hô¾I>šOX@ÔK’ó9êµ»éˆÒ=Öæ!Ïæ¿µ†+ Y|�Ì+ õ'qM?**|ÍÉUÁ§yãØÖ}«ÙŠfÀó™¡E “mžO-›¦ƒ|…%“ñ›NâË3�›âŠ5·„k•]a³ôhÊ'Ù­=æ¨ =no¢Ž+¹ÜÊ/¾sÐVUDêŸi§âÈ5y0¾ìlßdÇÒóÐõy¯R‚¤­ó¡ÿ­í MÁ°Ç³ÙÛ‡ét¢í Ê/gÎ3ÜaÉ9QV~ fì�³Šà\UOá¼¾/´ùóg6ãé#ÜÇù¢Ù¸fBûÿ``²'|XW]«îò:×çÁ¼1À’�Ȧ¨]Å<°’m†¼sƒ\�¢‰¸œcRælRz54mgÛs6á}�K(ñã«ñœ®«BÒ¨*[çþñüd}~æDuCó1hT© N\��‰’¥í1_˜—a"Õý³º1)æ8®|®Cy]êl(Í$%'sÓÎHrmߤÉpeÙ?*¦bß8Ëgã¼ýåxŸÿÌI˜úáóÙ¦4òÑl”5RÀ¨’LÞ½è«}šO[ü•XÅ¿])&+B'ò†ÿí×Å´&ô1×¶X”,Vۑζ>îLùŒ™È’öN£„¼�Ò£�‚}½[i‰o4ý:¿šK…¬F’:?�Ëú…Íblë7û‘mh }–ð„`‹BüxÅÞ/�€´ød·h ùåƒÓSs£óÎ&�£±óuxaÏ‹äÚÓÉ”­°Õm4•Þâ¬è`e¦j¤2ý.ϤwW�)9Ø ßôdÑ;PŸËÖ¤ô°žŸWYzÌ l;r‚WØ“Fç5ÕÁûŽ<-ÑŸF^Š0{«!5Dj·Û›�íó¡¼)>$úm (%xS‡Ùh˜¢¿˜*çÒò7Å@úNœýx ¸q^˜]k’²ûry%©œŠœÎTvõB%¬¾ãgo��¼pSÀ6#8øÕ2Ü+Id�\·Yë9ÛâÖÑ™10 ’̯ÛP Ne�8k ?03þçW5x»m ö+4rÃëÜ &Ñ—S~Q�NÙèå�/üœi¤YÜÍ\’FaGÃgt’l¡�pÖ~ äj„/ ó•K3`Xþó”–çºÈ+? Ñ-j”‘~’yð¤ç§/‚]ƒÝÿ øi¾»sŸ›µÂ…EáT^¿Uï„òo)�ÄÓ¨Cçœ_¸™N7•*0ð`tÿsW¡/áìÅ•,Ì*¬ q’‹,Só?EëÖèBö“å ±²B]ŽðÕ0»-Bæ_þù q1aœ~t7 ß¹ˆ&Þ;̾à s†0¡ø*Løì5VM‚ë›MÐ^O�Z4IÉó5 l^F¯—�&½õlÑÈ(öÏÕ•ö$%œOó³~2ó輑Z÷öP ¥ý™F7ÖàsCwx,{ípáð5&ã9Xž <úÆ»8Þ`³† ÙIÛB¼è‡íccA¤ñ�mïÚzÖ¶4oóz§€˜j|ݵŸâ>\áG+´òûð)ÃÁÐù‘–—iÐöOXm€YM X?¯»Ot ôds?Ï{UŠ×*4x@õÄ• ük Ò—KØkÆÐÄÜz¨¸ ŠË¸ãth:ϼRk™Mt,žTãèšØ8:9ã?ò½!K®)®Ü÷‚'lËÆ>¾x÷¶bဠSb)®~ˆô¶3‚Ò ß³¾]½ÜÄV7þnd‰·—Øx�_#<“XEÝßmÖÏŽj,gBVSÉ^d��¢?>.ù—=y¶�èðo.g”?tEèS‹ˆ'x]Éeû݃óSŸ`ÑÁFæa¡i§ceÁ¢’¿ º†!¿}¾<ðòÖÌü—8îïÔ‚ð‡¹ããÈö— Èt&ãÆsËÀuÆ8z5ž:r àsb%v|«Ýñû7Çñ»ò=<=¾£su3xι½èe>u6Ôh‰û벡og¬­Ë/iý°Ãv©`}­.eß6%�zy+Ôœ½@ßôRéëãlV´ê2ÿׯ�Ö‡®��zÒ·iÿœŒÇÂ&×i¸$³ß]¿B;^+²Òã^ôyæsÖâ`Êã%`®E ã%,@óH>œªV£ú‹0Ô­NIIY$uf.,=·‚%�|ÃVWct¾ŽUzW�3§ Ó¦ÌfKR1qÕ\¤VÂê4, $¦•¢Ö‘±^ô/z€ºUÚ¤Z}‡O‡ ¸ZF®åé ñ“óL1t� ÷¬¤TŸJÖÌJáÆöù*í‰ÊA»IKè)«sÊgWÒdsCÎî\=5äpfÁU¶[¯ Çg„Ck—?>ù¾‘�û¡M¼œ-jͤôüIܧžH^{zz¿XÁkïÂ&Þ¬WåÀM9Wöiðäm+#‰¤Õ¼K–ÅËÑ�9¶S»’,¦ìe¦K7BÛM3Œ\‡›¬)y,bë"=>ô¹?¨oa0ãíoìV<ÎÆËgÜÑÔbnY“®.L1Ò¦pPûSï,„m¿% yÆ ð5€®åá±�ÉØÊîä{„˜á…�µ,oÞ ØªÜ‡zÄ.q%Ë�ßñxý)öeÙYôžéƒcÎȂ𱛶â�[@¦Q#eÐ7°„¬J?¸âO…ú×(xjL2,…ÇäÀ¾ï#Z¶;ÎéB×¢(Ù�Dª‚i„Yè$r×_Üg.£.£Í-¿9–Bï”/ ¾ÌV™ùR3÷”ך—Ë�hŠ¡„ÛiàñJ ïçÛ£Gó®|� ëñ Ü&oJ5U�Ó^ãñX×W–|õ=¨_ÃöK9ØŽ+è垪Y�´«èæ Ðí_7aÕèÑLa8˜î|èbaéÿœç9éÔ½áÂí>ÛòžË°R[Œ‰?^/Ö¶‚ätž5¼\Ãß¾³mÿ\B}Wl=~ƒ)™Wóû9#IG<°p:}?˜JWÆÙ±»w^cóR¿°WEÓØ;X�º„†«R DEÈny« ¤&ŠPºŠ(SiNf÷’��ôÍ{$3¹‹K¾µ lV¸“Ö]k\7î$êÄ“Ù÷SänÍøô¶8Vˆ7àÓåÿ0É'd¶q0þ§”:œ¢[ãLh(Ô›µ11ŠP4¥ãå´ô.û~£#¾Sð# nL€aËw,vö ~Ö†ÔÓ>0ÓâKP­fóÁSJ™‚~N'¿>sz}š¶¤iâ÷íÁ4kÒ)~ê/Šø½ }ÇÅÌ•WÉ(zm6ƒ4Ÿ'@ã/+2÷~Í7Z‚ï�@ö†³cÞúj$W5Ûz¬XÄñObÿõ¥-rå&lotø¿;š¿�Xqv©elÝã=4~Ò¤û°]ì kë*¢z*®¹7„"ÃyLf8פÐã—»!Õ2–a-° ´‡çðSïr´Üo5À¥±Rƒú\À�‚ר$ÈgÕ"AøýC ì�F3TzÐR3%�”òC ]{+ÙŽŠÍS!+�‘ïò6¥q½”±>“v–�†Ó‘yð×ðÿµ7 R3Ðÿýkj ÕàûP “¦È€·�=ZĆÓÏgÔ>=ƒùª™‘æLip¼˜ùd÷V¥C¸ã92áÛYp¤(Û´RŸZ‹~òé8Û–“sm"Ö\å±Ûq¬]ó›¹? ‡®ÐlÈì•¥/â¯xÇÓ¶è\Œæ+Û˜ý[òêœH¾s-àĦl¨w†ßK À«Ã”É(…‚áÖzÔœw�:K2èîGW:Þ`ÉõäÓÈ»“è}Z/ßoõŒ¥oO¤ñÕ1ø®ÌWF0Íq¹Ø,3ȹuÀÉ3;·m7¸…�Åðªõ0wÏw5ÝÒxŽSÛWQNhî_,§/�űÏ#àE¥ÆUSßqáÇÑ`P'õ}b‘5²K�ŒNL‚ù¬ÀD6�Â4]ቘ5J‹îcüÈ~ßs#®°;·ìá�� ¿†í€ÙóœüØw¶Ót%ÁêP,èÜÝEÉ;n¡Ñ¬E`m ç ´¸•Wkмä_$\Á™ú÷°iQlãŒë|õ3Ž�1€ßÑû¨ÿ–8¼ývˆ½ÉÇ]oo3õ¹ýX«!KGªsXKc2¿3c÷•§á¯:˜¾¼v;\åû­éÈÆ,ÛÛkàÓyÐ|ÛlÓþ>†Ú®¯€Þs�俲c•Ú |·B­¾Î_´6ScËÕ�Pˆµ9×uÜ æup²i`=ršôPßÎJưŸýI,Ðû)œú—¹˜”óFÒVJ°qQA¼þ4<ÈÁ¤Û·ñíøZø$¼Šë8Z}ç$¾Ö.E9²‚"±.ªÙÌðŽê3~듼î隦ö›û¹[†>IŽÇWãØÞ¹Ú´hw1ìYþ„»ª KšQ½ÎÌKŒatårê2 ÆÁg(ïÐRLOéÇNBÍÐæÝíÈu•ÙÓÀ”ž:û4†/Ÿ"±Ð¶|/e›&R̓’µ ,¼ZÌP»•? ÈÁ"ë4’}W:«Wü`³VìÆÏ¿¡“úGT¹6t`Jz©J Cyð5~N•�LíŒ •tXÀkÂòè4Z¥L) Á¡E D^2­Œ‘T´¿š=SžË'–ž`J¶ó‘jÙ�s[n|ýŒŠ÷â@7a [¬Ù�dz³êù´[h¾ág?r3sÊ[ ç’CB?5ä=Ö—–ñ—¬3(ïr/2èe>c©¨ý.s ‰†Ó£ ©Óěݩ6…÷ñp_j“ˆñDÿÄ<}3…=Xꀟu›ýï±qƒö˜Á€Â¨Ÿ;‘iö�啳áŽ~5/g”».?¡¨ûù�Ô'×ÿæ3½Ü0¸9; ÙÀØÃøßñZtpƒSR"0ËÒ›Íç€Øx%˜Úx –DáÈ3 é²EõÐVœSò–ñOý Ê¿…^l”&—-7Ð`÷Uš+)¨ìkä†$ïCs�Äÿö"å}ol£÷¤ÓAÇ\TèÓÀ û³lúÚ>¤ ®§âihåXú6³‹m~Û�Â×*I BÕÉ}P""‹çÖ8Á^ÿ=ìÖ;w[ƒ-\¤Ôô˜¼ŸÓH1çmo-¥WóáKw8UšáeGÄfD-™�,ÉÉ™,Ä9È:©ÂÎE5² ­Øí�Yį�}k³égÔ1ˆ¸ÜˆA&GÙÓ�Ê0}Ím–sŽÚ¦âŠ›i¸lüoæº'ž=ý/ŒlZƲU~ÓéT…˜Í±-ž mê˜ð^%’[Ƙ”×NЗׅ9³L؉“Ö¼qb­¿þ˜$£ïýà‹:â6ée0뱚ÀHçç‡Rÿø÷œµgå­W#:é¾tMŠ {ª ‹˜í”&@ý’³t#7 §oŠ/àð2Õ¶X+’>H˜AH¹*M_� ›ÎýàÒÏt³ícS(âN='"º•I¹¯e &õ¶s?9Ò›–Bò¤¿LØ*•M‚ u¥ ]8KýCŸøÜZy8·Pl86¬±–DõDk‡É�*M ŒË"ýIy 7²ÑŒKLc{ržÂ»Ê,¶2ï°™4ÎTÙ抃ùßp²[ƒ„÷T�¹¶þÞŠŒ}ð?ëyÐjø9…eì™z,‚ÿ ÐQ§3,“„Ç÷êÑEk8!Ñ•õîh3–¼L`s²£g^a�Ï2´[ÇWiFÁº£—hÊðZ¸u+î¶h�éõù´¨ç/æU¬ã›|½ï7¯‡¦.6 u�£Pã¿�$ÀÕ·/òom¢Þ[Qxñ©1ØeŠÒW. •]QücÐ}>Š5|~è6|yaup c Ý5é`Ó_&�ÊŒ£äøz-éEªru3f³¥v1¬Î°›-³�ü7xøëD.¥a]¤lþEPˆl`ß®ÜFŸïwaêȘÄ9%^¢é¢¹¼{ÏH’6NgÅÓrÑß¾Ñ>»$¶c]’ ì¢=™ÊŸ¾ó.kHCΖxX³f2˜ír„o“ è‘Ö�ÖÂÉæSÉ Äš¾,£VqEÈRéÄkË A3úöGsiÓÄ úÚOÆŸyÃÊ‘ú:eúø[‡æÿœÚ›¶±D E>4l¹~(aoÒ¥j¿ê-Ç#�'Ð;|„y[Œéý�lÚ¯?™Y*dÚZ.øÀ*¾ÚðR-)ÈßÖ€üVÖÚ¡‚BŠ /ò™_9û =œ°v̈$ƒz9¼¾Ù’ãÙØqä$ñowöç@@‚ÌDá@Ô-^ÂëÇ/!ïçÙá‰Ói§ìdZÕ¿¹í­lû“BÖ"¯ÌÕÕ[P[íeƒ}ñõÈ]ÖV�gÈ+V™;Us0&¾¬ëaã:ºëélýõœ§êÅ"].¡îŸËà{huu‚Zî¼ ½b�Í8‡­e !ÿÇSܱÆu’Pºf,lXº˜´ªóøÀe£Ø•èq´õølÜÃO‚á›èè]EøýA’ý�“³›Òu™û`•ƒ*îG˜ÂF Ø8v ›ìµJ0ö›|÷ìÄÍW4àÌÕ¯l½ƒmê^ÇŸižç«&C¥ËH8þô/ÛóT�Ýt¨…µ¦�ìãü˜À‹R÷z}ö`ÎÊþ`KFüÂ}EFL5üÛi±~ÿWC^Å»ÿ�J™AbX&•©îƒêà…`Àžãkn=zoL¦Ö6ìJUüY M›çÃßš1,··„Ö> ëŽôñ!O7�»ß,zïÏ�èW�B­"O)š�Èb·âž;™Ü7é,öêc>³Ý‚ò飱;ÁÚÖ¢ÿ¿¬á!{�À_ødÂÙ§QEîAÖÚÙYSú³¸mB¢»T‰E¾b™ƒ¯ÙôÇÖtåå-vG¿¾:Àå\ZªTÃf|æ×6í�j‡E‚«vSÙÇïøàè"Xäþ�nNF%áRÐÙµ—T‰Ó‘1Øb½½dÞ–ìe®²7Õ!d"L'úÅaÂ-ÆâÓŰùª*Ü÷ ‚¯¥01Ô™òÜÂè–™Ë¿ŽøÃ$ް�IôòçJšÛÄÿÜ) ©25ìå¹ ÒPǯo§�{]õþw¤Œ˜…Wn½•�ú´`Öâ2|@G2cᯙ¤àý<±Úo?Ù’—²ô”»Œù+Â@¨%�Ý º�ó4ÇQ¢ŸÈ?¿u¥9BÇ¸Øæ&z3,L/Ä AÒÊîG,£1í4u(†ÿhÑÊŸWj‚Ê—Ó�­ð*,T:/ðŽ^Þôg|)ÎÙ¯ŽVá=!1ð÷ #ÝB]˜Ñâv·C‰ÞYbh—é.v5qD š˜¯,±€©ß9‰æxm™Eí¡·À-2C¼4øo GØ›?¸Û—Ùº Ϙ̄_èe˜É‚%ÅÀùš œm�ìŸPz¾1êçž$W}mÔq„‚ émÕ+OéÇè¡B…¶’ÿè 0qëAÔ¼¼„¾µY›ßg>Ö¢ðÎèÛ�îO¯“’¡µz)¾ÉiÄ �LöìHHÓ~ ‹îû]8'º7M«¦‹Ò}Ë6´û5�Õ™!Þú£Fu�=°8ÔˆµìTÍÒäãÚÄø–/0myz @½g .àK¥vqm5ƨp�9§¸@Û6K¶5׃½‰ˆƒ¼¥Ž,uX‹ê6¿ç>ž8�G×çBpÛIVß…ÒJpêïE¸Õ=•ö, ‡ö)†d$¦º7ðÒ�C8ÿ€‚~)ë®~�O«¡×y$õdécÞDuhvˆ€þ‘näks ÚýÚ¸M“}¡®w„} ¿rÂ\רovMêéÆš_…œPEN¸Z�°¨ésý ¿@} Hð2híU3›ÎÒ÷Õqx5µ�]­]¹ü:;\Òc{ª'‰«Sp×o6ãåwŒ)ï²5>çLwÚ>â�‡ªTáV€ÉV¿jöЏR�µÊ)–@Sf�-s|Æ�œž “3ÚØûwJèšãŠcÆŽ&½¢”¿ÛŠ&(âÉŸp}ê2�÷ ·:å´_ô£CšìÅI“®ÐçÆ,xÑ8÷`/'‘@ LSp™ÕŒýäJK)+$‘þéŒq"/çOœ‰ÆS¶Õ, _ ݃°ovž¯Ú×�õ1;ëµðqϤÚú…i‚öƒé’ÑNÜvaß1á�µ‡™-Žöíâ^¶bÃl=ÈQe*É”ò©¾Ý ‡CºT6ŠŠÂEéZff7sdV¡GŠ_;¹“¹?@n²±Sßñçu±Ë·hñ�vnžð|æóª”Íþ´Ùª5t®8ƒý½—¶D#¯ t¦tF3‰Ÿæ6Ì/ü„KûR\Æ_fU°Lo€iu¾gç6𛽀.'ºCY@ØËÅ‘LŽh$ÊÒb9KÒ¸n‰–AÌ ·’-î;�7›%`Dçø¹ÆŸ‘J¡kï©`A%uhÖïF‘Ý“qÖZ5H}¿�êv/¦Ã1¹Î_Êÿéÿ Þ¦AYIòàöbÊÍN+NÉ[³h¢þW~ƒŽ�þ‘Ä>rL÷ê,Zq#˜Ež9‰Ó-É¿Ú;Êbp@¹�-ôá2i?¸\·Á™�Bµ^išÆjšoC)>Ä_J&—гÿV�‹Ñ×…ÙÑáèN%6âG4Û£šMÇ~¡_Ã!Üñ+™¿ÞÕÀ:*O0¡ýšpú�£œåh9é“ÔGþbßOÞ#|$ûzUÖ®p&ñ¬hÜf«ŽSŽ,e['ŠRÂnyèu&¹~1ÜF–3¼C(){.ÐZÓ ¸£w1åœ|B×ÄLé}ýî|Àyí;‰#·äÑå�mLû¬3UÍx9xžMjnQx™ìkº‰Þ>}¶£ëÕ ãÌ'²Y5‚œ]ׂ| I@¢ù‹|V_#ñÃTÂgjêpEs‹M�ãפ<Æú„ ˜¹å<^gí”ÓÄ]í�x牴d­‹–|™Ú rþ;Ä:…� K^š8¹mì´è¾ä€™ŸÎ‡}^6¬wJÞž>2þ\o‡3ÇScÇ5î §¹«ûX^‹4H: ücÞOʼnӔê,¶ÿY<Ýs©e† GÀ¤éèôî"\ðÂÛ>±,‡ªqÚÎ|væ.­^ëgFCv�%¥Ü»ÖqyT³X˜*T»à™�øŠ¿À†T Ø*IŠ‚<~Bã?>¦�ÁÖ¢6´,Id¯&lcÌk_qHÍný¾%` —ƒ2qàúÒ�ÂÅž[Ý 4ÈžjRoCBÞ.>Ml%«?³(Ø—eë÷°¹¥ÅêÑM�£ÄH2hË”‘À›·ÚÙ {´nŠ•Åç˜ù£½�†Q wñ«K" F|g“À¤³·°ëh.»Û„‰KzmþËÔà¶Ä¼‚�©Ux×FæœÛ {Îç°ÑÏmxÉ�º¨`Hkj'ãÕ1�8÷ìD­6™骓qÏ ˜óýk¸í‡~^ñXõ¸ Ä+rñóÌö�-Æ*–¸öp—ãe ïÿ3€9*Él“á ÷yC‰›ØÝõ™6�—Ôõ‚õiÜ`úZß‹±â×`·•7.Ú½—«ž)±ëÞ±+m—ø°µ9Ä=)¡èÌ'L¢µ»^[0ÙÝxïÑ ¾çÓLÞôn€àXG8T¯T†ažàW„Ÿ^�e­-TX›ÎVÎ]„eiãÀ§<ß®›Ëx} ’±ÍæWŽ8qO. \þí…‹- ŽYÇ\„í5u3ÝI'˜ÙYtY"L3¤~²cõ¹5­!¸õãèˆlúQÃî6–ºs`˜°�¬…óXíä>ö(–íÙx®'=¤x¹+ ú­E‹…¨õÒ9´ºÕËF…‡°Á÷ј¥W„ã=¡‹±&õðbôÐQ³¿ ÿ^œ#.¿B÷¥gÈõs ŠÊdýãÊàØ|-à�gA¨×t(x—MO62—Iv_éºN Þœ.¸æÛ�Ësg�×S%®\Jã¢ñ³Õxœè‰¥z´mÜÜMI ú¹ðvôùà�‚Ód:þ(Ë"ðÝ샺w+)ÌSžvå2¨É¿H£g/Ä9:«ie¹TÉŽ�M‹R™l 8ó:S k¿�á� EÀÏÙ¢p¾ý1�x)N‚ YÜ¢ö³ì‚Fi›„3Ϙ0^þ±%ll/Ö6ãÑ„ŸLîæ%¶j|+ˆ•Ba˜1€•!yÖ¬€M¿nbÛ¦xèjæ@ï•U/Lbí1·q›´„Ì‚Ëç“Y£G?skØ›+§À7îÆV>>’·P'&¢W^⡹œÛuÔ„)˜´Á¨²S¶ö&öldç îN]„w+ÚYG¡-}VîÁ\œa oóÞÂè ³VãƒØ’éka°ÂïÿcÉ‹3@ýd³ö…­·ÿ mŠã,Â_€Â²*fw×ߥ†Áìý`ߥCü°+ÜÌ ã;•â?:I¬ºóBVÐ!%:_Œß<4ÀëÎ3|%½… ªÀÙ¯³¡Sõ)Åt�Öìl·ÄKð_&Ž�Þ5g»þrÙAy”ëACß× <õ°»zT_Y «õ,pðö&$7v~O…¥ö 3·�m›ßÍ^�‘gÎfOiiý»ûR5Þn¤?O·³0ñ>,�ÅNJá&gÒùùe6£ÉCòРr½â]‡¥ôkÚXðëPÂl±Þ#.œ;e±žõM¨íÈ�f -w’Í´QÔûc"¸ÜìaFÇ” л‚$¥�[o \jÙE¿Ý¥±1ý,·Ú$“¿Èr'Žî…Å#®a»åvÚ«µ v^Lf¶�D(ÂÚ 64\£ÄîtÊ;Q¢ë»ñŠ×TînÜ:"v Ê&ªAÉ&#`U"°2°‡½Ý˜È‰�ö€ÙÏäjoüºÂRЧ±àxYzb~ŸdãCÛ!�×üt¼þ£�['B�éææÌ´çždi6³`¥Ð<�Ì.$A§/84’M_dd I£ Øý¦· ±¡ v_Ý@æóUèg´6ü’ �•Úyã³°Õõ6{:× {Ò×QÛ¼7,�sÀåcèOS#¥OäÊoƒ�ö;xwS$·C5 ÓÅ8·W†`ú-’¿ŠÇîe‹ÉØQÖ?€î-Á¤ÿf!ü}¥kC¯ó«“2è’ÉtŒñú‚{«Þ°«¶Ò|ý‚%`vNߨ¾¥ ÞðÏ”„°¨*çŒn¡þÆôzØÂvá/-hÒºŒ)ÙBÔ((¡ä°lú؈6õ�ôE~=û5y;”½â ky*r_…S4x¼ ¾×—ÛnŠ7ã×ǘ±ûþ*älµלÄ�ò.\XoÃoN©b†²©>«™éOÉZ“½M+„A°s�+*©­Ž`÷Ýø ×´àN¢’�†¾ç`V…oaac¥}S‡kYÎØþc'ê·\Çã¡ lÜóSð)·� JÖ®\£D¾Rª4Þq"Íòm7'k7ZǾ|°Át•6n`ÛYRº0ÌR-ÞãÑU•d3BŽ®(Y³[_ŽA¼Îúœ™€i×j« ÅÐ`ä zøM ·'�ÅZç$f/�ù*­Ìío j™c‰Û¦‰W²_³pƲw8ëÀ%z·‚>®mcûù2Z8s¼MugCV³P%¢×¶b†é8KŸ«¤ Îÿ!œ”\È~¸‡¿G¯"Û¨bˆ¾§ w½N³ñ;ÿâÆÓèüg ˜r*œæ¬§Â¸GŒJc6¢Î�Ÿøƒœ%±¯8ƒÉL«`ÞvQ =ê‘ý„—j=Æ6Üë€îÂwho4Ÿ†.[¡òûF¼hVGž§#™M½óÉ©ë†poÞæ^+€K’ßð“¦�OW�+–+¡ùR&¼¹o .O4)mËøê1‹_àÛµWiû²£”§ôk¤SØÌ†Kì¾}"ûP^![˜qì~¹·2õ?N¦ñ—§á÷”&2±~ÃnÏïÃçâ'ÐfÌ:vcÉ–o5Ö)°�SŽƒtØ|ö{®}&;xí´çlÊU» /-)« {:6Àƒj!øtä=z7«QoÔ%ÊIrÄt%6uá#–VSÂR‡Ö“ªwx™$�–™" ¿žé˜®¹Zð™W£ãÙ¹‹s�áR½ZU|q·»üˆ*!Ž�›ø€i³àêð ’ M"‘˜&V–}…ÙîK¾ã·ã�ƒôBQ£=¿±�²,¸›PM;ÌÐ «8Þ1ò0 ¡4bÍJlÏ6eN]4Wô°fáFظ¹§<(†ÃÖ0ÊîÇ[_�GcÍi³ËP}´ ͬeUª­x(ψ¢e�»ª ˜¥ÿea! ¨¨Þ¶Êíƒc«‹xÛ±þ:)’Z–Ë��îG+Õ}@¦WŒVpƒœ‚xüh銛Ì;¸ y´º�Ì‚�rÙ‰¾sìµ¢!¸…çÐNËœOrS™íB…öçØÏì„„=ë/"«w Ld`9é§ÐÞ—Y‘Â{vOûxtfFwHÎ*¾Ý»øD˜'—C©MŠlïÆ|Ú©_ÏÔ­ •U ,;»“]wžÉFxº‘˜R8\n6¢¼œ4–²q-QÏEÙbøyù&¼h …�gsèÏÖMLdó(Pºy‚'å¾óXäg=ûNaŽòHÊ­ 8 Œíxÿ*°Rï[¬½Æ‘ù2Ž}PW«Õ”“µã³jñÇÍ÷¬n©�ž˜¾ûÂAbØNi ¼©òŠ,út‘r'Æ`v¦%[ýG~¬Šá??ô'%þ|ñd�\ü–W¥t])ŒÜO(0Î̸€gÿe3çx:T½h†´Ö÷ø.Û•ªü²jÞôp´}Í|îp§3ݳ…ø=Ð6eLqGO¼ŽöÂÖtx}* ¼¯ žx˜ŸajŒ[WÔüãE-j¨/p ,ÛÝÀ…h²_Þø™m·jòF¢by“]C‡4wÀó¨7,ŽŸOåL|“†X±× ò±š»½I_7œÎþÁ¶8…Ûv9ðcot¡Ì' ‡4Ùàq=x}Uz¤BÑ\ö0²-ÚÑ€»ßZàËw0x4ŠªfDàö±yÜž£.8.l|Ï?�æp=à(�;„òm9|ÿ§¶¦|3œk}�'šƒh^ÉdÊuÎ#ý\ezR°¸¯ŒäŸ@dÃgöûÐ:ØZPŽÓ´KP`jÖRíñW|úŸE|ÐÃÜc…‘5ê9¡û ø¸ì³š#hqí´Kì=~�\ £÷ͬ=þq1Ž�gOúÊNu±ýXNç^AÞ–­ì›•ýRU—#3ép·ýêàØ©ÅJÔ2^›æœ±-R;Ètܘï­mÄë Õžã )¼ä3‹¶?ˆ—cŒéž0£CG¹¸O~ÿ:rì }™æ*TºU ‡ ¨ê£,Ýøï2ømý{*HHt}ùl`·Lr\Íä}Ï7ñ."bÔüÄ›v-ûÃî[]b~g&’v­"½È¥}júltÇ%éèû®0çú^tʃÎÊèÚÍUÞÄGG_接½d�v!p:غÃqšûÖ€ù4åÚ�¾ë`Á NÆiù*ˆ¾íhÇ}M«A¡ö5Züëå»KYÊŽEðhÍ<¼8ÜÄžN>F^ûiIR;õ|›Ho%'2TÝ›/©ÁÞõº¤”¥JU—ÕíL¦ÅìÅ-øu”-.öÄéÒîði�PÂÑÉ7w¾¡{fC¦–&P?<�]’¡§5SˆŽÄ°ªäÛ(kÉìJzè½j#‹Ðþ.h/6F´‘kï(’Ÿz— \€(ñ¹´`ÁvÚã@¦»€ÛjE7�� Ÿ=eì7×´¢›ª‹Zðæ¿ºÞ\tœ€í¿Ý™øLUÚùƒB!ÌŽRØä!9ò<+  ëþqF¥½Î÷fk¤C[Â]e{>·fn³àÐ}!º8þ�åaunèd4¼Wk³ôš$FŸn¶ ²ÄŒ{ïdç'…0"¡õ?(ÁH³ß¼íCÜ2-˜»9ény ¾A×™s+±¼~ur8.g‡í̹Zj® Y¹o�÷•ÈŠ.®ÖãRPqÊöʘ·Èõ£ÑV!œ'A †Ó©åˆhM°ÑILNljûZq¦¹ÄZ^àMðƒÆö—5Ù tµ�@¨C-ÊÝ›e(|¿>| dSbOÑ%Þ ¬OŽb'\Äuaͤ™2ŒUÆRï‚9°gîà?¼=ŠiEóa¥º*q«b3Ϝɩ|FS&K­.gʺîß1‘Ÿ}à-rb'ØÑ¨çœÃ_9Œú¾†Æï¹Š¦¿Þ³ë«w±Ã!•x¶¼˜½u�‚³2pê†e4˜^�Þõ,þâlš×¿‹4½w�—çS /^ÁFuÊÓ´G-ü䘼�cki(faõŠ5}Öq:ÏÐÑݦ´õà~Ö�:ö¾F—+YýŒýM›É Ú‰Ÿ£Ñ…÷¬ŒN±ô�Á¤§Ç“ iaønº{¾æ¼½‰uýÁ¼÷ymЀïË^À ž©¬A.º•{áɇFA_Hßêly–¿^Z þå¤8 îAJ>g)iFZãüùwQ/ÙúšI¨Ò&IÁú×§¥Ã —ZÞ¡ÔæJ+ÿ;Jί.ÐøW"t'ù,ˆÍ)ƒ1Ò–` )4EÁ‘^ûÆasG!O’àZ×#ÎLfpàÖ]lH’Çg¡EÄð˜=Q‰bn€¥¢÷6RjcÑö é�ë^zÜÒŒÓgÿ£�^6Ûá=Öm˜N'¶ÀËçž°{ÂiTh›ö¾ñìªMìr�Ö?o~ËÉ%Ÿ¡«¾+è~ƒ+ Ô«±°eê¶]£xß”ýu™P3ðÑ‘FÜÌ¢ÿÚGÔdŽ‚®Ú�ÜÀÖ"´ o/«%͇³ îÌÞ“åR_V-ç!" �¿k-ZÞ!Ñ þä_ïÉÞ³4ÐVýþ�Ëõé×)HÔÌÀ÷UápçG+uóʹ½¬?H„g퀫=p6D¤f÷Á�Ôq£=r¨nË$îou·ua#®z4–ä*”À«aŒþ´‚¹MáÁ­ÞEo6S×§ è�(„jónã¾æhªÙ8žýtüŠ"7B¹Ñ~éãþùf[TÐýÁ»Ÿi„ÙBµ”ÖÐÉŒ²ÆPÛQ60m,^Ι £�dHÌ¢š~i‡ñ«2&‚Ø�,Àœ4¦õh4¬<ŽŠùa¤è.^Ã�êzÆrõqTŠŒ{ò‹o‹ci¢˜Õë÷ì¸ùdè“¿…s²lè9[.«ÉmÁ'Ló•ÁŸ«‰]éhdÁäHåwU@õqæK}Äg"NœÙüj˜¾Ò€»åô˜}ù"AWõγ7s–‚ÃïZV¹Þ{k«©¤®Ÿ-|"E*2ñ÷íd,Žfó­àƒáZöå¾=ëKÝÃzg\c•¿FÂÒLyŠÜˆß¶¯Á_vÙ`X26^,à–s«¨AS˜nõ”RžÊKo‹X?ʤ¦C÷Üa\ô}3´¿Ó#÷¦kÔX*I]}¬N$žÖûC¿å+ævï0ó6?Ǽ»ÄiùÂ&²¸ÔM%r"øæÌS\­ca¥Aœªe8‹uXFó–' îÝ‹¸)h4”Ìbº’H¦ŸtÃøÍ6 i¤Ü'Ln²aG _⧤V–—Pѵl¯�ÆY´ò¹_=öµXM Ižôm+f¹ù@¢ê¹í¨ÅÐE›ààYKu³#Lbån·g,º&”�¶ì/Ëù…ñ`ñ·“Ø—Ž*¸ë´R•·QÊñvÌŒŽã³O´`PÚøúÇ™ŽºÌÁÁÊÏ8ón3¥)B IÝMû`ÁÁ ,tÃ)·ø*Ë?7ž+’f�®ýa"}b4õ­2mví§ãàJã&<("Á?“¸#hü§oÕG`®ƒœ»“½Ü˜ÄîI&ö.Ô2Äö‹¥xÊ9°0^ÝBÀ}‰3œ d*"øÈæÉÜCÿYpVäËÓ  =3¾0Ý%Þ”“iÃü¥.Áºäµ,fJ?3›úb;�âøõÉ”!�€ò¶B@Ò’ð«ÅŠúcê‰Ë_Éoë…/ÏF±Ò“6d:6‚,:–CþŒÃ|÷ù&¦3/jÅa™Õò– õÄpÜžËáçéH]*Z©MÖÚÐTíæ]Š¢a³®‰äÆÐî�*v_ö)‹}z3ûÛðéµi¸ÂÿŸ–•.ád}¤`ö¬Wü”™4|Í›"OeÂ~çû‚ëUjß°ÂÃ?$Àº"�÷Ï…ª-¶ìïe �¥Yp|ë|è.øÊ$_h×cÖ¯ö\Q<ÃE©í­©_«Þ¤ŸI9¶Àø&OÀk¹xPÈ“EÕ|àÞ½®’´q‚Ó÷°8¦çýÒb�_4³?¥ëA+¤˜Öe€ÅÕhþ ¤iþ”¦9ý—©Ö¢€ýt�Cge“U\~\îzÅDní&ÿ�s¾ƒ]_:±&;é íý§•ZŽ´*ò£¥ã�'\©½8žx­ae¯ &×Ô‘Ï_[ÁÙ€^._k<:WŽ#b³ˆì$êu�s%ºÔsƒµ¿nƒÒåñ`¿h.ù{US Æ4<ùiìM8²é8+‘¶ÚŸ~ ¦/@¬ƒ&õØ<áÎc1}“A\f†VÙSÞ‹L8~s$) Ÿ£’Œgøþa»bäžÿøÙ'á%æ(©Ò}%¬³™^µ{Á¬Çwp_;\Hî†RVó�ö€þºõðŸöH:ð÷:ý(Š„ßùR”šž@sÆ÷cª™}8ÅWñ#GéÖrORÃÔñàUiXúñ1×;¿ˆÝÿ݃E�fRÙÌÓ|ÑÐ4Ð5I»Ö¡­‹í˜8•c’céGi=Î|F?wɲöDÊ~îBu¨œ*CÕÖrtvó08/ÈÄÅ«ª™…÷¶íÉ^»ïwê—M+ß ¿ŽNƒ^�KxZ>‹ìþj‘”¼‰´kƒŒ¨:�¯w…ÖeBh-YÄ«M¿‹V ²eÚQ4Ñø0 °€Õ²·¨6r>³É³#�D'A†ž9-ñ½ÉO{”õ¬5…ª/ï£È‘ –î„+õË™¤ýrQÌäOü\Ö43·ØKè º“”‡Õ³tÉùßÛfÈ7ñ�ë²AJ¢ïTÅ[^Ÿk �jeèWé<:zºwµê•¶ñ5±n‹ h”9�Ø :'©.¦*'@Û›Säÿó$ÝÙñ ÷«HÞhD�IM'ž²ŸuÝ%•qü�|5½Ì›ØŽ7úî¢o¡µºŒ€I¾Þ$6á3>TþÇöÛ·2e^Àûá¯M¼áš¼òîGL»¦� ëHÔÌ,*…‘¦†´? (7­ _Lñ…¤½��>& $ç>¸^Èó%ÓYϘ1аf6§¥"ÍZâ“�eò›˜Ímˆv�Sÿô3é¿ÛüZq þ)Ø*ŽYÃF`Ö{ìÓàºìvì)ÜþS 6®óßÒ8z“I�ÇtðÝ¥?è-ÕŽEY d²‚¶«ô¡ ^gë—î€õ~!,qtév6a“î#<×<ƒW?P ·ïg¾+É)á4¸ ¬¥O…“™¢ËjZói>µt?åæmo‚÷Â/øIMðß  i‡k¬‰ûžÆ*ƒs¸Í¯–“ïs,jõAÓb«Öº&R•Ä\-C©­ÄÕûD 1ü?öÑÕž× ¾ŽiS‹asŽ5Ä ‘Ÿ†*µÊ@tÜ}ø”2·¢ föÊ ûG°æâpnK¶^®ÃÙ�ã¸áã! +]J±®�x«ÿŽaôül6¨äÈÏ-l®#r…íܹ®ßS¡_þc­ËãÈÃù,Î;ý³ÒÚ¡ô¹ D+O$Ñ'yä3Å®„Ìa¶œ`ícWƒ‚„&]ù*ÖÉãÁdБ �`[­YËènÁm‹PÑ=ÆšT:YŽ%)yJ29©*î×·üú¥•›6B’jä&ÓLÏý‚ÇÆ*ìÉO�ˆc.¬YœÆæ+üb¾:AØí��9MÊ®À¶2«ú¶2˜×Ë_RU€Å’š4Câ>·Q¼“m©Á0Ä&J@Ñá^æhPÏDl´húÖ<~‚dgí¢çð'§%agª­À8ÇÕ6þÄ«<ÖsízI¾c.Î=ÓkW ã˜wË ,´ 'öq;ë>m|ñS¾�¦žˆ[–:‹µÈÈ8cíê°xĦq²’¦�øÎÕ²ã,¡y*„ŒMŘº xý}Ÿl£ËúÝ„¬ -¤Ñb¡Ø!‘¶é›hîò£¤lŸj©É$»AŒ’�;‘ˆírH,t¢ÁïÞèx[‹žmAû�õˆïÞÀ®¥(àûsš¼F B2X8·tcvÐ{‰*úS~”.¥†R¡w(ÔÚô’í'%úÚÉ¿ùs?÷üƒ+ëªêÄ%é¿q¢¥}É>À¹ÌÍ‚ÁZ':(&&·:ÀJ~ 颵ñ~Ð}·œÓª|CP¯fi¨º¬ƒz\”Áj¹'Î}£N×öq4``Bº¿²G"–äjfFV#6àr£næÛ|…^DÞ Ó¼vŠ;!ÎÚÜ’³3©¯ð‰E@­²'øZèÂݦbÇ my7wå³€ô¦›Ã¸=Ò¤¶±šz|ƒa¯<èh 3ß^³YÇðÅ©Æøë¼ŒSn….áIÜ¡U Tw� ö0yþí¢. éΣg£Çœ•Ç�ÿ4¡ú¼LÜ–B½rQÐ%»r.¤„ß1kË îO¤I¾‹ø—sL tº-§Þ,dõÐ)îšq{Ÿ”¡¹úôŸ1 ÷…¾…ž6b'®}gN"É,ÿÞEذãßNÅL¤/B£h…ô ¶L`C‘*S@ÙºuÍóáïa ¾“ŒƒížÜ/CxúJ•ÍÒ¯„‘Jg–ÊÑÃév 4»›-ú—S}Š™^&Êè™RÝ+\ß?�ÞÚ]çu¥Þ1oç4î|A “ayT‡·™¦¡]ˆ]†J¯ÖC_g mò¢‰“9ÿ­·1*Ò�l&-€ü%‘`1Ù“özìbõQðñÕ3š ƒš'83.Žê­a³Ê~£ÌßÿðVð Zkg ´ÃŠä©Ð�q¿.üº#@{“½´&I£§1û¡fà,;ø-‹}Û4•‰ÌmªÓoðÓsA+Á {__Æ“šÙ(ËHò“ºÉ®¾�ÁV±lÞoåR4–ÙLµÏåˆO脲•ìÇŽiô´'>AðÒtZ*õŒ_e=®;ãÚIpw3¤þý´Ñ§‹v$nÂÍüMÖ§Q‡]ŠAp´â eÖÙ‹ó=¡·Qã?e8u=Ÿü룥۽ƒ|­U×fˆ | =kÅ4f�!|È›M7Ú/€Š—2ôAé�¿¦¥A³Ùgv°$›]hGà%vòR nX3“joÏ¡ViœN� 4)(ðN³F¡P±÷¢È¦¯» «4X|–:í}“s{îáT?}Zfè N¡]8ÊÅŽæØÌ†Q¶ðçS ç—Mêâ×ÙËÜ“´+õÛtu·O£9Ú›Ù¹ë1T¥š�n'Ÿ<½)7¥ÝÝ·ý�!xÝš¦:‹­(èá+¸%,¨x9ygfáõejlïˆ&òýÑÈ}-ãßDV1{¡´sU,w^%ÑÄ1†Œ„Ìi™Ì-hy5W~ÇK¾Ëéž~8åmmb˽ª°À#ƒJR—ñ…Ïø°�­Ø¡™I-“÷Ó\•Úvéœô¿CÜ%¨JÂŽL‰b+¿ŽcZkë@~è6=Û8 ÅÍ.°]AÏaÇ�lXTƒ¢×[È†=ç÷¸Õ Œ;¢iJ›6Kc²8åŒhû6Ãô=ëÔ@i�7Ϻ”ßo›"ùœåƒüb)ò{¸’»{ë;ßβRþ4�z˜Ç&†¦cûx |äݹ¶CW˜ç5/|\rZ¤”Á¶F•ñ÷÷® Ña5ÚÝlKïúÑ¢Üx2}ü�ÃŒÉÛh,™O¢m«–@®p [ Vú,ñePþ-ƒ·»EHný(¸èg mM˜§Ê~ì½£�fzôw–‹t)åRõ?~ò€kKèË! r=ɯò�Å=8“åýLd.†Épà#^ßÒ†Nöã¡yì(°›KÖtàóÊtŠQ…Ct!!×Ùð¦¨w�c$ëIc¹¨^¸Í/kkæ¾ÛËBÜÙ\KÿíL\ä:™‹M´Š�?Ì~ Æ-Ÿ¥ù*Y úöü6ÎN¬EiXnœÉžýö†)‰7x±™'ª[ýç³UöÍØ2 É®ô•ÁÄý+H*Y&�ÌAëXü—ÌÅù¢�V ½3bv«(³¹5º‘ÀmÀálä/ò_¡~c.û{¨…ï ï²|p0ަŒ|ÆÂ¿5Ñ.E¼‘»�ºÓ‡¸›·L°¹j l‘!÷¥÷ŒÁ’V ¸õfuù¦²Óó¤jÖÊöRÁ‘“÷ß LY”Žþï#HÛÛžlòò 'lÜ>¸ŽÍu0�›bŠˆ¨Bï¢ÅtTÿo bà=y1wäTî ¡L'4‹°‚ÌG¸~.ƒ•¿ÔaÚåîØ\êÀõ*™txÈÒ§ ÁûÓu°m8žë~´�N­™‰ÆO¿Â.u-òHV'Õ¿y4Þp%U‘¦Ðæù¯„N×"áçÂ\–:OÓ»NÓ¹ßw¡¾2†dÁñ”õ$>BŽÝ<( «3Y‰^&X†–ÐõµÞ’GLA×Ë€»Ÿ›Ó{Ð\ò›ôi55 n$ã¾wxÕ³šûð™'ŸmÒ4¾Ð™„ŠáÅ-bà‘NÚd³ä,ùIöCtV(Û6üD»3 �N1QÛd�ظ„œýcÉ),äjʯ²ù‹’H½-–æ˜N…ࣳA|ÒV²HÑ‚°;O˜hóæ•QÃüNЫÂŒز‡?ßÁ:ë«–{eUéÕ�W ¯Î/ÌxB‡†âùÛ}5¬e‘/(f¯Æª�A¼îœŒë+f-kGÁõ[JYYÏ•ŒédµU7ÈÚæÝï² ‡mÿÎÇNfß>ç°bÏwx½W§k áŠv” êæ6{ZÓÁ\HÒ™…à~È»©�VÜòF‘¦n.¼| èH“s…Œ+k¢Ë¡òÜÒácдšn.–S½æÏ%>J» tåóÀIlí»1 –ùL†¶€K ýø�©Æ  è…Rpü®ö˜”8³Ö®]ðñÝv:w%ƒÿºÍ„Ú×ÂÌ&…š»+ŽCŸÛ<¢$ *'9w¡•pÎò-×�=È%µ.¡Q×�RÊëѤóÆ‚éJ,#ÙÊX?6||A·û¢é£ñzX²Z NLÞ@‰qÁ”¾X„ÕŸ=]Ê5^–~](c#�/‚²ƒ e›ZbâýÚm¸‚S°H¦…£-@ñ÷2Z¸`3 ´™þ�q,¶%Ýbl~þ6«${Ï(8½R’„gšÐ�·ê ¡ 6ÍéoþaWš 9&ÂV�[ èõ�(úõ@@;^—�û1ºZÓ€ÍòÑËö‚‚ØÓ—‰0o‰üíL£ÉâÂüîêB`ÏË6ÓtYL[¶…MY0•ú®3Xœ–�Ã�ø²ª Å=ì ˶‚ĸzóú•Ûf1jk!l‘0þž�ÏŒ2׳÷§v1Ÿ k`‡x´(%roáSÊN\*8†qîc¨¥y+KXHþ«ø·u¥¼ö»+”¿#€Ú*–Ñ­O�ôwºcîÞ¢=T(ÜDû¤ƒ¸Y÷›Ùòè|ÑÅ[ä¬t+ ¸�ZEìCt,(z/†Üdÿy¡¡ˆ( “ ’o� ºH–WOS˜Ÿ›D—Þk³uOC¨¯x:¶ŒzŒâwäaÎ0U×hÊ9½z¶vFųˋƱ%^A'R@E?Ÿ€jX1s]r7LxDæck¸©ñ`ö°˜æ B±Ó: ö æÙèÐõ{WØ÷)[h‹ÏÂ�>§4ý~$³}%¦PÓ=û¡ŸŠÍ(AÝâ¸GÀ›i�C4ÇOŸ4öÉ®"í¿:Tzj<†ÙÓ‘ô*šãïÌÞOw¢oüØ÷�d<÷Æl§ mƒ,Ècn›PG"Z0«:ú޲·ƒ1½ >|DñÓ3àÖ’­ÿæ ­Ë½8¡ôYp¼=…Ô´}&ÀÞIR8zÆ*|²™eΩ„Ï*cárþË-ÍÏqUK2„ô¾¤‰4Aî}鉌„©Ê)0å}7›úÛ˜êŒþ²«wZnß^ñï~ pYÁ nˆ±ù‰˜:ð ×ïE‘0UØ›ÊqÇ\ÇC—Á�©‰"Ñ„ švû/Þ5W°¢c$ÿë2Ý /á¸Êõ¬À¶›/wpâŸZÁ¸6{¦——Ÿ‡–AÇàRÂ1*PªdA"8‰ãëaÛ5Y²ú7;.1ë–”aObs Ø7Ã4Ø ¸—Þ¦D‘BuýYîcéâÖO½ÌèÛþ^1fÙÛ¾olã„\:œ^ÎÄMò˜…ëEü¡œÆ¾í[MÖ÷ ˜Ç�•¤2ÚÃ% ™©u8•=¹j“ú�ïVÄrqï¿á£&¼k–ÅŒroáÏZ65¹­¶®ù”N6FòÊ *â¡rxx¼�-®À&úÔið“¨<€“¤_³©eÝ\PÊÄ¿ž$:Ñ+O…æ?pqÄ.ÜxeöM?Èöí(äWî]‚ª½Ë@þÕwl µƒìÝjtc‰»Q0‡¾�D�üMÕvÁºLeJ|vd×ÖÈÂÅæ_l×'[Ø\=ßMü_^…ø#!Pb% ™a3)ös’áÍ�àøjcÖE±yŽ´¨ÌîCŠF¿,IŸôo&+Kå„·|Ç8ÒˆòÍäRd èðr¢ãg² åA ¹>ïâ;Dò¡åT«S+Ùc £v…\âaãI˜¶P¹&xãcä'EÁŸUòØ(<›õ%‚çêËôvÖØš‰æ™�«¿MÌéLæü>ƒ×?–¢ç¿�w- Öêùø-êÞ̹†QܪF,H= Ú!´¼ß�Š<¯`@N+D«ÉÀœ�±RË�M~” S]‹Ypˆ)l1—‡»éfÅ2œ|n\Þ‹Ü×;èýŸ×õ ¼Ò±{ÆX�÷¥yóv²Ï�šph±0Û1UΪ¡ò"PáhòúáòqT¹þ2 Nv¤�Û/ÑÇø6Ãp-o•­Ë-(èI�wkÄðëÍU4áù�p‹�’)$\�"ßçrÃç·¢¼ÁLZw¤€î,†L'¥ÃÝ¡”Ý9“-SalS,�ä—Ë5ÐG 4i<CËt1iÒZpX̬ïé€Hè¶ÈÒåç ö}ùÇz¹KiÈã*ùN„O^ìyùJ\ú_Äé슅8£" ÌÒA±-؉þo}?~+ZnÐÃ=ÉK|îav.ú43Rö;Ýe££êçÀ¼•)pï@¤©:³þ/!0¬¶œ™o¬†©!°>—a¯Q,°ÙüÈ{ÉóÒ�«þ[½óW$¿îðÚ>| Gµ¤Ñi— ܵ® &£M-B¼ðÅÍäöQBÎÁü51¨_•põŠ4PŸ>ä¯î`g.ªYÉ|; ¦?“°ÂKŒº$�6½ÓX"…Aáq8©/Oü¤hVP´„®tÁÑõï¡Â¥�%wÝ`­{‘ž à]£i–ÉIòo[@ïGÿã õkùªBÔº}ˆË|Ê£ŒI»÷ ‹’îi±:élþŽä¤XAÁG²Ù1é LOy=Šma÷O×1­/?ifV,�ž_‰®ur“OÌËâTÖȉ„®Ù5‡µNSsm°�)T:´‰%à�û(=[Ö·/a+§Æá™MÑ!û&Ó˜#¡çciþüÏLH=š ;ÖQh{øªÔâ‹JPéÈdï [AíV0üqæ´_ ³SŸGW—ŸxÅKm•‰ä šÙ ñ?,¸Áé?Põ»ìy˜mÉùF€xb?æ~�É7êeÇ<á©™{¶ø ÞÊ4‚ñž3 ¡ƒ£¥onaâÃ�lÄbŽ”Ô&ÒKñß̯$v•'À¸ŠttÄÜ0ìµ9™ðål-ž› hš2¸Fá²Û(Å’"ÏÑܹ&¤û€§´1’”p3 ¤!œ{3¾Š»_L!9KÙìñÏá¢okÝ:‡V«‰Ñç�š´J¼T­¼ÈÉbˆ­ôªcc}¸7 YôâÇh²Ê,À4wgZ¹µ’m9°†;p<š;üx.)—fE®øJo)zD¶’}³\ÍhßxÌøM·_ô²ÖÛÏq´Ô ð\@5¿ŒI5¥ˆŽo½Ï¶—Â\«£8ôº–tµö2£ˆ~öIWz¥ßa–u ×ôç#“2Gé¼Tºù6öð�Rê°ÀZ‚daÞ·@VÓ¬—)JóåàÆêUørÞÎôu#ïߌ¥ª1\è °oU·Ú0no†Šødþúór:)°‚Ýx»ŽÆ=6¢˜§ÙÉ+G¹ËVÒÏè5áÇfò¿æ‘Ч ü³¿c­zò"Qlâcö>¤Ë^�€eŸ&“Ù”pr£œeJ÷©?áÈÞc»{â\š$F µÅðƒun ZD¡{OÒP­€wüú‹ÅÊò�IÑfJdøsçÛ³Ú´mu‚7Ûì¨Êç7ZµÓß=œ”»™ôÕÒIÞôhߟ@ù­«ÈDÒ ß�;B›Ÿ�§ÐK»¹¢á�»í»ã0Ìt#óèºa)T=OÅëú ¹& •’Ãiëî]°I{4­nÒ¥ôù•l…¸"=M4 þ}âd!?�r\ÌY£ióQ©×c¡¸JI—®tñlK2ÁL·É´%Íœîøc'»‡�ckdX„V!.¸fÀô—M`�Ýßù]>£¬ê_§¢½O2J(pwž‡Z+_ïn²“¡ýz-¼ ùÎ>ΟÁTìËHô`=Ø$BW„†9\Á*]ò`èåKÉ?eå�Ž<΄XºoЀ¹¾fÈòA=<žTR,ApÐŽönˆd£š/ÑåMÃxt´÷ÍšJ‘‰E vY•®pjY£IZè”»%Ð4U:8Ý„L¯8’®K;®óØÆ�ܬIª% Wô›ÙtŽ*·ÄѦׅðò¿,´ÝN«¢ep†¤63v“êûM»aq°&mï]·mû—9ÌHö54]Fu9*Ph4Š>Ц±7~Ÿ°x–.u8K®/\É‚íæ@X£)iø C�T L¹À½�8@›…£x²��eÌ®&ÂÙ;�¬_ã:ÖV¶°gº‘¼qqÍô–‡t}}Rúq æJ�…1ž»@ëËjûx’ V1�;çá’tœzˆ•R›àÎ)-*”\NŸï�Fï]/™Å‡Ϋþ i4Í"ë¢6^'Ö¢>RBi>4§×¢Ó†^NÆÇŠ–©î‚š «ëåÉ,Ò<ófÑ˦2h8@¹ëÎâîÂŒh>`yøŸF„ÚÛÒú�¥0f^…e{ÊîÎz1F/µP1o/_›[n©—ú‡{3PÈi<‰ãõG``M ü“COœe-µ–üÆö[rš»—RžÇò·;zQ°CVù„¾ZÇÌ•Ühî„xk>šÿoG<ë¨wÃañí¾Ú=�îlüõo ¡¥òþdøÅ ]Í)Ui,^9ÌÖ)±'+/°�~�è±p)OQ¨qµIgñÊØ€P9:•ÛRÁßÝX°. L}yöôŸçê�‰§k…çñÙŸ n݆‡øYöG}å°–3¡ô¾ -Ý·¤üÀ�z&Œ¤~%è7|Šf‰´ò¡¶T¹+ßšAåbìü�98£^¤}ÔèûÉ6œ°¨œß÷å;/�ÃizeЧû¬#/óí§Ñò• ü±á"Tžô–�¦ õÔåâeÉt�âeZ RAÇsê1CËî—µrKF¥‚žÜzä.4 “øQššzŠÎõ‹O‡#’¬âÁ þU¡;ëØc5YN[ü9þ¹¸ž_Þ¢M!^/Øp©�˜ÛAéN�)¶”FèO"Åg&tÚh9 ‹¥lò‚kþðsÇ«ÂŨ·8oe›²y[‹«A¦½ÈR4Mœjg:AØöJöl„žm†hÔù‡ÍJ«`巧µäùl­à{ê…­î½<ÆLBPë­- p¬ºƒÿJãÂ!¨Ð-NAaÌkG>8lÆVÿID¯‘JØ:À,w¢žÃ4êñ¹Ëv…ÓåÍPÿü2qÆ ­Š*Sð†5sz²˜Ê)¤¶ó\Ì+ˆ˜s†Y¾Ï±ü)‘''ÐRã‰|ÚöËÜ>³Tœ÷{䦞€#вhsf;Û¾.•ê, EØ–ePSFv¾†xªb3'̾3cÿ ä͜ظ‰šLmÑÈv‘Á3%)¸bL ~ø–ê[´Ái»6yÆ‘–Ó ’¹÷Ç(…sþa èë] bR,5+Ü÷0ÍÎ\ýiž¬çÇV›³±ëÌP îa›!pÌ2¨skà¤nŽeñžLµØ¶¹^³4nõ$‹ƒh\þ#ܬh 7-¥áƒæu¶wg&Ú¹’LTµèpÅdØäD gþòzO·ÂªtUž™^Æ{+gAÞäVŒ JÂï9^ç„'2u^æ3:%jWNª£Ùòh&4y ›æïHswäbHz$T¹Ï�â^)ºágOçR|YèÆe”0¼�&÷K�’‘ í‘K7‡$Iȧ�=Mp%Éœ/œr´Œ ïÀ‡ósXɪpÜeþ‘Ÿvôkr“G÷ÒåôçK¿`áù@Á¢¦…´ö²+kÿx ž9±ë„? 8‹åûàÇ>xï{ݟΡ�áf6ˆ5èüü Ú<�à»3ËSÆtÁ¹h?¢k�ùty£.ðOÖ²·«8!Bê´^ò1ö¸iaã}3‚=(»/7SmA9Å› ýÍ©34Œ;3ÈyÆdPò’DAR%oq¸–•�íÁo1ÍØ® ï_èê÷qí"°H®=ÛÆ`öÃ0.]Žgz¢ )ð¥ :˜‚×Áõlãô�èôw3…nç³å¸Âû| w¬Oq»,4�Ó•Ñ’ôçFsž6—õïL§¥A^¼VL0Ÿ4•Â/ŽÃ[F+Øõ½út¡Ì‚\cîELæëmüíæÏRWQfÐT:4¶¤zdd^Üø�MžŸ�ïìNâ××Ó(Ó¥.Åœ�È‚PZöÞ‹¶ŒS½ù$²Ž£D­GLvF,;qdT䌤F]|ÍÍ£œI÷\˜Ÿï@«qîºÅø„{­¿’©™“Š1ô‚2­nÍÇ­_Šk~”²G,6†}Æ×ZPèWÉJF¾ÃŸ¢™âÉ\xa,!_£ÀxÆ(öþÂ-� ÖKaÁì 8öD«¹ ¡3euq¥Œ7«›®y®\ÿ �`mJïçü s÷ÍA«ÌPz¤eÌ–Í;CÊÉrdìÛÇùýx‚osÖZÞ´!½ôa&©©ú‡Y`—ÄmËáǘ¬�þ%X¿4”MP,—±^‘„æ— 6Ùÿw5ËÝ’‰\ZTý2hûù-^s‡ç–ƒ¬}Çrð›âÂtS�¡XýÛôŸV—²Ó'ÏÁü7Áq –}Z‘ÎÜ‹w’]ûg :SÊÓ´±pÅñ×>1š 3 Æ‹Fñ×ÄÐÖׯYMýjfmw’Wyüžå‹Ýd’å×(§x"]¾À± ¹3pwö9|µz:n³�âKÞ’Î��0nî~¡ÖN¼²nˆµ â¶pwØ>žÜâëuj˜óËxL{ Ó–«‚Øq ˆ·©ø�ü6~ Ýß¹>¯®V[: Sf‹âd]iøÓ[_æáão(øÝäßã…ÁeÝ„r¬Pa!È3Sß!þìw†*Cºlù Q¾Ø„k'.İÝhagŽ9—–à”•§©§ºß•^DËÙ�T–щ'¼«qí‰B¶3^ù%³¬8ixr~»Ú7 g4�¡6‹vÿŽËœaä4�ÚÜ{xƒ%lÂé^ö1/-ë®áé+©~äA<5E™\¾3‡`Yvylóìä6é+À†=®Ð¤nÎÖI¡ò©C(�é¬ö k¡}æ­²Bp76�|À‚½pÃÔrÁ‰ŸU(º«Šê�æ4$xµ ]¼˜Ä^š8¯ù²JÊÜ»•î•Ì%sñTº3ãKî^I³¤ äÎn®Vø,ù+›RÇVE\uèþšÿ”kÖÎ`Â.ðlj:}ÁŒ¸QH48†QÏT©Êô ×õ]Ž¾Ý–§–›é(tGM}¥ás— ,îhEc>M R¸�)˜?£.§aœ’·Yƒñ®(æÔ÷§zŠz:ZÑ›þɰÿÞn?4ƒ½Ÿ…Iã)>ñ*Ö‰¨AÃâÉü̹‰XßiCÙ3§ã£ÎûLÌEV u%–„Œ»ñõQ92¼pŠõ¿šÏoL Ëb”%yóO’\ôZš� ŠÃG”àuÕ*J<¾Œ&ëÞg°1´0çïwi dYÊò ÔwGš´MUaL‘2ë”oÇÊ‹à;ù;X»BË Zk=/:Q˜ÒÑŒ·¢åˆvìÆ£Æ'IþÖarÇ ºøwèÅáðú$¾y� ¿�acÔ8pÐieig_q»¾; ©}‹DfÄç¹!ü>›&·ÊÓŽUÅ8”k9åã)"æ>«Y#½�Ç0Ï:e~AõCJ&t“e³¸ã‘‹GÖ#û³v<¾û⥧a—Båû+ƒÉÖíÌ‘®à“åT}a”:«‰Dϼ&ö§\X–Ì ±ìw‘ž8u²d“‹¨w1o¾zÅô?¯ci¦Ù°ÐH“NY/†¡]±ôU¼_˜æ!yoéC¹£'sD¬R ¢û>X&™Ã$ãéÑì5 t£o\ÛS„í¡i�›óW Æ²Éªë'ï\;—FL‹ÐëLlùTÈ]ª ú¯�À=±h¸—®L5-ºC‡WœM3¢ÙOùk„"& h]ÛìÒéRkÛxËݾͤW¹2°®"���ËA&œêНœ•êÞüf<·?4‡yzÞçŒRKP˜ËXú£‹Â—G³­¾9øìì]Jû /urøƒþÓ@×Üfÿ7‡e2Å¾Çøm˜£ºæ?iÇ�ïv Ú§3Aàlry=öÿ1,q†¤¡ö\VšÛ”àË—#–Ö>sHßô, eW-+Xóˆ3,Òâ<[ÒrƒÛ>^\´óð÷ÉJNþǰ|§IUkª™”m6I=g.¹_ñÝåyÜ�b˜Ó<ƒ<…¤Ã�¬r‘uÈ+Øîa/VK€Âƒ§ìÌÚ“Xl©H“ò®X¦,™îSÊVF´“Oe*®ãÉpñXå o†¢à@jÓn.`KŸ†³··¥P¹ ˆÝ.bÓçI[åœ _­FÓ¯´*ÎNs4·¢|Kuú÷݃¼¸Rž¹Ä¾P¶w²{1�ðw}/9>�¯Ý×�%ÓM@Ä<†n?äùö SZ5²¶îÞ‚ç Èï›KzuŸe>^ tYÔÂ$å {vW˜žv;ãŸÞPî£Ç~ÂLòÌäÆºÎG¥¿¯¹Ò6C¸°E•ÚOì'm±PªmÙ³ý.à� Æ4á|5Îqè`”%ûK™ÂÉè -q©¸üæ®äÓx榙Æ:üí–[¼Í6)ºœYÆ‚÷, g™é¬ªò îoXXø×$±μñí�v㦈Œ€� ÿ8íµ/q; ¾“:9ëkÂ=›w‡~xQÊ™ïl§K JŸHE´\˨èy4[�]C‡œµYAl6¹ ¯€‰“Æ’ß‹2æ•;‹=’(†Ãó¼q›¢izµÀjÏFÊh™§­ ÙýÇɰÃ|€Ÿ1>Ê-EÏüSìÓñn|û¥÷'î†ø²óÈ_ùÆîž™Cå¡8íƒ�¦8¶;{émîÅ kö°žG9¬äÌ1öÂÑ”&Å[­mMøù{5KÛü“Å÷ñlÏÎ�Ðù}\ßÏÎKè“À¦ˆ*4c%O�ƒ”8§0ýûñ"Ÿi(ŸÀSs§ÁŒg™›Þ¸¶œ,ëOðf>a,Ñ­›3·Ýο™ ïõJa—Ù1Œ|¸”ýη¡ƒËBù"/æží û%•hž�")ä‹Óm¯aöp^圚É×->KŽÓ´ Þ8Ò;‡9BGÐîiS³­­výG�òƒ™&ª�UœÁJꥸÿl¶’òþ›n¯ÏÉ4QÞ¾¼}ò5\Í>Ê5œÇäÇÉÀ˜Ãª£¸a–*˜m‘�»á:¨¾G…¤²”q×ß ”[7vÜ×�“jçéÓ›yÿÖˆÊí¦çŸž ô ýPbŠ–j6™´ZÈûÂlyCT4 ÀVA¼Ê+¢›{DjÞ”Ìf¯üýð…r•m<�ܹKé?ø[Žˆj홸9OªFþp3ÿÙå—ÚzRg4ómO›X€¶k±€/1Äêq]ÿz:ŠÖˆW�BÊ8hx< ~d¼�ÈÁäe½ÇjvŸ(›a™C$К<ÔYJÓ&î̽rC >zbN¢ít,Ú™Û/ÿd³l{Øe{C²ž¦TÓø\�)–ŸgÙ/H£2 ÖJ–#´Áj½fÁÚYýì\îiØ"¯ÙQhHë¾FR Ê1pË9BòV£áT@&éÚø€óÌ8º'¶“â&çòS=}á‚´”•iŒ´·GÀؼ¬ý›éWŒ³Z.µ‚Æ4KBá8c^(»vÂ+·Q°_q<öyÄ“¨I1{Ðð€æ6�B^“ÅsýnR�/åï‚q…!LþÂ< Â)jk4žZ÷ЉEòq ÓkNoµ²÷ø@�Õ·`se5¹m”‡,eW2r‰‡‘÷6BfÂÌšâ5=l¥ß#x¥†¾ P�WYHGî^Â[wÕè_1ª‰­käæäÊ[õMM/MÙ¹\Ò4¼„–{ÑU^Ö*÷Êz!cCbÙ‡ÁG»�W2ôªvo»ÉtTÕé�Á]>ȆWÿpÒª,›â)‰³W�åø—póñ ö½S’b 4¯Ù « bÁR¥†ksÒ„ÝYøbÞ(¨iÈår�@xx1†èM…Þ­ú”?Ìý)΄“§f[}ÿ¹T”«¹}¿÷ÂÑË47£Ÿ%j�›¶s|û“¢îŒ‡{}¸šì»ð¢\Š fOÁÛ’ð Íßëï‹ãF) É,+#ï{¤”J %TˆPR’¢(e„콩”iÑòyŸóÑ^F;•Ò–´HãÛüõûîãÞsï9¯×óõxÜ/"× /ò4&'×@ļr¶A{-(^ÞŠ_UƒK‚ƒª³tàV=œo¼Œ:Y<œki‚Ÿî¾ü¡‚X¸h Gkn‚Iª2•,ãt9�þþ˜I%¬¢—1³h[Cˆ‹‡³ñCI”ú÷ k?rï›G�šÆm’RW„—³@ä±™pöäda~¥ ™OXŠÆ‹åɇIÛ˪¬%õ!¦=õ3hKÚê:|é”–·CÈ:c"�»Ä­“øK6m‰lɃI´yC Í6ô¥ùTw·ÄAo²¨P¼�í�¿>Žk.D÷4ÎJXˆ�l Ëbó†ò;²SK²@nêp�ðQ ­+.†‹í›Aò¤ †N—G Õõ"B~s·@rlƇ\`#”ñQG“ÉsF÷îŠ9ŒyQBƒ� pêQx{LÜÞõº>JûN`;«†ÿ|î,©7ã­eµ0ýY¨‰ßÃúIKþéG äž·"�%7PfÂðz)®Ž #iZ�ü[†ÃëŠáÁœs,8¹•VWaYI:¾ò\‚Ö^`_LA¯?éÝÍ»Ô9>B»RéÔÉJvn=¸,ÕdRÝ*¿{~2Ã9w0«ð/½«¢¬m÷HyA ¹Æ¤±Ú–×vs,'ÃF­7p&ŒcŠ‹¾â$9M¦rd£wûÉ*È\Û§Q‘ÎtamÌš¤˜Vþ5Ò%FïMÛYàù_’—c+Ó¥@—*B�­ñøçÉ0¤õ�§Ì Á%ûO²)ãá á,xÏ™À]ÈóË ‹¿5é©Q!\tš"çÕaÎ7Eˆî]�]ûTè¸üG0� CS�ÑÍyâÂG¸¦38ÍYâfsˆ>Ý£}ÍíÝ#B ç‰ 4MѲ¿ýo}ãÄ$x:ö<¿OWòƒ²Qºe¥ÐÚa:f4?�ªlIaV¢…TTÑöoSa÷—DZ)•=;ÿÿÍ¢°=v-%,ÙNÖìÐ ª“OšOÊ(&œ¢1Š<3TÈiÔ=Îfƒš÷u!}(c‡‡ ·� ‘~<²—ÊŸ]æ^ thgº ÌÍžŽ‹Dí¹ [qù²ç 0Qšâ¯5ACµº½Š¾­Øp‰÷ œ þ “h­ÍB6çmš]A¿ì»�«öS²[%ö¸MßÔ‰ÄmF“g°y›…¶o2bØãKböQŸòáÛ¾7p¶Kßþ´a3Y®.�Ö±š3ÿ'þ°¦�Ú6è”1|%\Ѓpªõ?Åz=˜V]˜Œ^#…ú[z¹µÑÂ]š¬ó�+�Š‚Øc ”Ýy—^Î0‚VÝ(OŠ ©çÁÚ‡w­i#í½Í±+Á ô.¸•«��®½�ìg*ù¸¦°™¦^¶³¸*�ʬÞ@†vm*†Qyâöú‹ú@cp'ã  Þ¥9xsɹIÞ^Yœ�ìSÒòùœËÎ Tõ垀Ù^_k!— |Æ;½o…ç 4(ñéLaÜéS”>Æ>¢Ãu[dÉ\¬Ÿûk¹…žeݧI±�dÌá`T9{7?‘…Etq2㜘ä*yêoxË,c`lœ8¹lFÏ®1ë¤BÚ0a&uk¤Á´—Iìð©dvQ—Vh\å&µP… ˜‘G÷XÝg&í{­'44nWÞîO�¢{ñ…L �Ö æ¦Ò�²¤½PNh#t�Ê'¿píßl:ÁЬª¡ò°/T8¼Ô:¨V ïƒ*aú_}rNË£'BsxX�ƒWú‹Ø¼èx5º”fj/¸ÚBd›–#£Y¹¾l—ØÇ‰M/eNÊQU°ÑÏkLSe6¼jßÇ­/€ñŸ“è}ÀiL»rŸ�Š´Ã‰+ ÊT�Iùvâβ¥ëBOûÿP@l%•< /Ækh¥©´=SÍ�ßÚe@‰SéÉþ{\ÁVUz5s5¼¾ÕR.çOM{¾¼mmííû¨òÇ!,‹ÉÅOsFЇIã§ß»Aua& %¹Ò+°lôlyðö?¸“ÖË É“;œ`OzvC4"‚'ÍU¡´Æ~�þ“OÎ%×€áh,x½œIû×Ù¦­Ö#»»é}j.„Íu‚»«¢ˆU¶@ÅDLcz7d[Á^íaöJ‚#TQLò†BГ9Ǧ\HÿŘ€å°L8ö£ß{¿'­Ôº}±ƒZfÛx¬¢…ÛJÐoV ÖTªÛ�‹ë‡öÞ·¹›"+�‘õ럼×J˜,\�ÝY^ÔŸ³^IV�×ï½ôÉB‚òÛÇÁy3U¡²Ñ.ØYÇRF¤�aŠM¿1ï»;Ú'þ=BÉoçÂéÛŽT·ç/_¸–pwn*/2Vøöp ýËÿ‹Ýèʆ\”=šœ¾_§…Ò0;Ëm-ÄX™ìoê, …SíÃÏýø'Éâ$ª<\øBR m×ÉÂ0#O¸ežÌMUÙÀ¾Ú~ hÝÝ´eÍ|ò>¡){’aÓƒ!>!�´�JÙ�ÙSO:ÂRê6¯ÅQ'§`†À Ÿ›çáVÅ:U2RØiè@w½vÓ O1º³b¿X´*j�å“áÄ$Káóq h)mHô6SРÇUrpõI#ø7/aúÿ­¦Øªnò“9‰ƒ Os©÷_€CËJˆ{_L*׶ö3‡Ara¬øŽ,º>ËÜFÀõK“(k¡ ™Y“oÍ0¡~Yª…Û­H"ü!^L‚‰ZX.¾ƒ®>Y•Ó|’3� ßp7]À9‘¸¯1—×Á¢ÜÑ¿�.ÈåÂØ}ø…`™l’}ÄAU²š”7V@\éy6ÓÃ-}Oœh½ö½…_¯%‘ña¤¿]N¸*ú,Ÿ{è…jy  ò©éícþQŠ)ȼïeõÿto’˜¨œè�e*R�¶o[šBuqÎìɾS�|؃óÛ9œ®6sä¹T”,¦ÉƒDínóŽCl†u#ˆzRËýAp×íÀ�9Éi4¿ðeü>ŽsÞ\‘eÁÏl7ìû2Õ~É•ÉPì[ƒ2�ú>ÁÉþ~¿¤ýótP T†âð lt® +;YÇü×gð¢§Q+;¼R@9Ã0òW>EmnŸ/rkbÄ„ƒj£ÉÿgÌòê€}9 $¼OÐIó4fV¹›ÿædi/ Ï̃'¦°þ÷T4GËÈlà!˜LÛIùÿ¼«ó‘ˆ}ëq!Í8™MÝ}_¸)�Žvz§ñwµ²Ï±rÂ_�^ÂØŠj~EW3¶ï„÷Ëþ0韓…çõì�й-yŽþ.¦Ð.½“.Bqw;|¬wOcg¯ M†Uø,!ÿŸfÙÚOõCÁÛ¤…ö²%|šþ>’¹2Z¨cÔ 7�Üç‹T¬ìK<'Ñëh®_Ù­N€ŽÝ]l±w<ä4‰Ùkκ‡+6±ë—v‘²z'þ6�›1�Îq¤ah³nH±K™S!ØØœŒB……MÃí×_êÄÕCÃh]O;¶ó¬ÙjkßymmýëΚãßâüôK0²EŸ<Ç+ ]¦kÁü‹5ôÖ!ƒ%šÄ’íí`py›®+Ç’bÆu\û �´?â"¡´}ݦ ÿ³4^ö0‘¶ÔôÉ“Ûðß=²r …z ‰?v„tŸÕRÞè¤>²ŠÚ×w²51géqe/mï>GçNÉÃWB™ú¬ÌûâX¡š%‡L…Ý#ZHïë:˜±c5ló(„azãɦ_T¨}Þ€,³bQ¯ONøñí>ùþ·Ýù“¢B㾊3=ÏX|2~žÝñ!ULô¡ÝÉœ«w£%5bÈt´ÉûïY¸¤oßÖ®`²ßÂËi‡Ù¦Åz,%ÂaÝkÚšáÌ)ª}†3;‘�¢¨\Íâ­´©»xø'ýšOA½7ØÐf j{3…F•ËÁñk±à–¿’s¼çˆ§ë 9‘oÑÄ €n9Ÿb•g¡›¦8ëiÛƒº¿RXl{0»îAŸáYÔ£Nï ´kµiôîDÍ0‚ÀŠù”µõˆÌœ+Ö+¿>žmúޝ«Ù·È·]=b>gÉ*µìØ"3h9ÀN§õcKöSø¹®»¯q¾ä=ìkžM—¥Âé놖 uRà|b)Hø•ÁÎ'ÚlýGLw•hžè#}‡…-Ãñ þ7PÆLÅÅ„R¯Ú•ÿÔE\˜Ç)ÏU„Íù[ÙÔ¨*mI&+ÑÁÿâàÉg2û&ܬH©ÓÜÞ³² ÷-:Ë–kÏlñ õ´.¼§7Ô¢»ùO†45[JV(p?;F‘ÒÓJÚszkü)*»Ÿk@'w“%§`ê4QøXv6VZðíw21}ŸÐh;Ü�9LX—qôŸýËæ—ÏÓÉ*þÒä4Û_Î�lU`�›©êÅØ’ç…×MY™™/·ü)ótzG¶Ù)\宯yþ?˜Õ#5|þt?¶MÑ¢Y2$Õ¿´•[¯Ö3É—ªOO41™Î9ýûÕÛKæ_KùWóšÑ´ÔœóZ1‡/kwÁE“ͽg [^ÑdÏÍìÁ/cŠPïãs Vî %o€{ P¹Õ ”Ó3Éa‹&Ñõ½\E½4ÿ.CYW7zc{�5 ü‚Ò-`ñqÝM‹‚�2Ø¿~;®¡˜Žz±+ U=n._L�ÍζǛ@çfìu &© 2°ùæó¯ž3•Ã�:Üü•EdPWgÒtõä6<Òs +öo¦Q{ÇñÇŸ˜ÂïïCxîrì°&Nè~ç?ޤ}/ÎÑóLqY/ÉÔªÿ�¹y XäÁVWP«­žíiž ›zGЕǥ´Ç‡�3æ™BX5|Ÿõo>×®¦¦?š (ùE`«½#ÅÝÙä]e áü”­p‹Ïåõ”«iŒ†èË—�Áâ ¸*»¥1ò“(îÝô�ý'6“v/Ú1fÙ$“·’5tëÓ6M ²½îÏhÖ¶ wØ–}¾X˜øRƒv_·#Áœ‹hòƒÍ+ R×êp_Ûi, ø‹ N©l{KÍ,Ç'y*T83ï÷±‚£ÙTÀO‚«~¸9z!;Û×ÍÜßÊÂÏwDA1ôq¬ý-˜É¦‡]Å1JØÑ¾oë}ÆÙž@Io‚�åJôhæ^v8ßÆÍŠåNG•1óqÿòç,Kpôg‹•Daõ×°m]Ìÿ¨"·7~µD¢çe:¡¦ Ò£Ûí¢‚³éþ°µt'j�mç›|›¶*0]LYâ'ìúCG� V•žÙßâÔ,¶ƒ´[\L[B�^¡Fç¨Øì#‰W§5rÔ»Ô�ú"Wý¸ÌB*�hÂ狘ڙb§ûÖN³(¸þ}=HŒg*‘FÚQw˜wvIˆ¡EÛe6Þzz+‡ÓÈv6khÒ§$ríáÂ]ÔànÌ.ò·÷å—ˆÈ2·ÑßiعaÐ’LÚg_òÛ4äA΂Z„(%Íãqóp%¸Î?å­c hAI:fû®�‡/¬øµ¡9¬¸Rm!4º“hþ¹ü£3æZçÑ„… S®¾‡)›º¹¸­î$:\@ �å“î+Þþ¿P0µ�¥˜DqãêÙÀò‡èþæL9sžx…‹¼à‘ÑYܼ¼Žo«¥[ÖñØ_ AsGÉÀ¾À`ð :„º»C ÷÷KLé�HŠæB6ó� í¬¢€/Ã)öÞZôPJ$ǯŠä±½W�‰ “2ï£9ã$)43†K†ÆŽ=”:֚ў sÇ‚ûî,¶:Sß1ÖîEÖhzu}$$ T@q¦.]³¿ù·ÞazDÜhw…K3¾²¦àelvýqHû"�ïwÉ�ü–9´kR?º²“E-˧Y&í(?k"¬×¹„jÛ=m_]¨g¯\~²u_ǃ¡e$'„p3”jáw£¨}•^‹5³†;¡³IÎ]��Ò=]Nø \vÔ‚ÂðDªÌ%‰¥]<¿GŽ••ã•)ªÔ5r*î5¸IAß7²^åµøºe˾iJ|þ{ìÒ�Åç @õÏAæ#Cj ËY©¥5©Š‚¾ÂWö©KÌ>}vøåN Ÿ›þÔåü¿ƒæòöÙ£÷£¤Yl¦€Ÿ¦!«ùx®V܃“{ËÙ¢%ÊlYGž]…ª8öI¤Y�ÇÙðMÚ ¿ë3sÊ]-ÿj¸™WؽߵlbélØ—R *‹ÈõˆöØ”ÒQg7ÐÙ¼…¸øSAS®4YN_;ö’½âú(œÆeŸmá"VörG¯Â¨cÈØ¿›J¿bÁáÍp5Õ ËÚÛÀlÈ�v¿P‡çk¨ôl~žü›‰ìÛú/÷äaçݶ(µ=%Åà‹O??—'Ìt9n4ÿÄo&«áÅà¡ïB2r±¢ã]¿¸5ñ ¸Äúµ@ | –\´Õê0—­»‹Àaaáö wó-'î¡îg<¹œšƒ\̶fÞWÝ ³·2Hl+ç?=xaQ°’²ìä·~‘�̇q°îÞ”tšBŸ%÷‚§ÒQpqz�÷=äa�3ŒÂpåk:6ñ9 m³ð¨é#6Òˆg]†Ã(©Ã®®.'µrYx7r–* ã RãáÕˆOvÁ?M8­ÈêT`ýç@ˆç@..“näi‘iøôܤc¿ûh)yTDz[;à\æL*êɧñ¡l³ÆIr1,£Y~ŽTäÕ‚ó"¼p¿Q$U_AîÖ0þw®¼¼˜ö9hS¾-¥¼o!˜x3‡—<ãÛõò©/Ñ ¿wáDIÊ~ØÈ½ŽLû4€1w‹ÈéÛX�¿P‡Þ½×Y^l/U6*AšÖ=nóŒdñGÀŽ_“åþ\Öá5BôaÂw6Ê2•�–\ ‚žw´ìG(33™Š½ùãG²K7”ìÁ€_¡äì¯jvìUÐDè¼âÏ›®ó A®rL<8þ•µ{<þ,mý�a7䵎¬ÿcŸvg’er&]x�GÏî=ÄdõRŒÎkƒ¿§ÄðŠ{5Ûôh&¥Dgk›´°w¤½‹qr›ßSÕp9:h;j›s@Ù3~Ú‡£•|Õ¨|ô鉺¾GèôÇì²ênø±”~ôYÓ¦j 6ýÞ^;»�p/´‡ýÔÛ@'lLqüø1´×éž4îEßæxõÞvbsN�O`J}=ŒuYkð1´rZÈÜútñ~H;Lé2‡Ñ0‰�~ÿ–„~Á%õްÉ˶ŸÊÆó¿*¸ðÿzYàe{ÒV8†eM‘lªÓÌ80Ž-œrŸòp2Žr^AJ½«¡ÂÀö©;1íU¸#ý»bÓËêæ`ÝÁ}l±†�I+c�zóhîÓJ®*÷¬ÝDÕv[U/+’ù´Ånñ­]\”—æ~…VÚh�nÿ)¬�tÅ'U§ðÆ/f嬧uG‚èø=üºàºíÝÑÓÈeb6�=hh)û¯àù|Ü‘éBò_nТÃUìªL/Ðk ÿÖ´rò’GØÃ§]øœßÀFLÍÇUÆÇAþÔ{Y¬ŽåÉZ0U~AR#KzÏÚ,�žÛé¼S©úÎdKÞfÙ5gH7f-L9.‡ÅÆ-Å'1£¸×Ì;9>]¸�š¾ùP·ŽOëÐÂÒ)#°ëÐo»å›ÊYŒî„W+Ð+ô 7[€s» ä÷hœùTâ»2¹¿?RÐñsI>Çê›>L*ü<£�Tþø|{þÆ6o(Ír¢ð1ö0OEÔþEƒ1TÏ'ͤåü¡í~$íoS.0….Qûµ×Øc�±y?Ø;fgÖtŸþhM¥OcOQKÔBèkž@‡‡ò*½-,ào^sK[®¤’ôþ*öe¨‘¥D«á—„ä°-&”TƒÑðt4ª›©×c I£›é¸ö£èÙXț܈'Æ9²œR58‘îlwàq)Ìê/ UŠýL¥Ø~z¼‡uÕ¦ä8Ë•º_äÑY³ ¦>ý)“b—)�hG6$Ⱦf�ÇÂYî¯iôæûì^0‚6¯;Î&Ýwg>^æ7ŒÞtš³9WÈ-d.$DºÓ�xGþQ¿ èßeà•R÷Oß,±u½y]- €ŸÃI=ò/{yV’Îýn¢•.%8ÔëE�‹šÉGµþLÛü5hýQÌZÃ!'ª‘ÿÖ»’d†S¿W (Uà/Á%C¨»•~¥ÈÁžïûXü¬b8}÷8k–Šç7lŠd—‰brªHãÀ(X~0n Î72Ÿ±ëXm“•`Üü|=/¤Œ!V¢éY¼Rö[ÞòÜ¿}4¿qIµÅ,é~§&ñšoèÁ†¾Лân.çˆ Äh4Ñ7åÛ`+à±÷b!Ù]¹ÀéåV±¶Ã9ð÷Ö3x¹J†eõØ¢e÷oSÜÓ¾6ÇvRRÁ>pÿ—eSoüÆ´UÈ®’„Mo,ØÅ¢(vÁî¸'SµªËu-&$“±.ôd¤"¡üÝMêæÓ™Ôê/\bÙy ëÉa:Ê…$Ñò‘åJiÚ9¸›~,¿ÂnV—ñp¾šs¹:Ò,5¨¶. g ¶±”EiLº¡gWF!³�†g¸L¦N³îDŸÎÅØŸiÁ,¢ô(ðÇ{¬ÞÙËrÞr‡ÕXk¬ ޝÍÀƒ3€Â>]à ¯†±eo‡³ë¯O°‘¿_°ØªÐ¡Ô¾&À_sm2¯¾�15âTzÈ&QõXGÂÞ±¢p¥w#‹~­„·ý`Gv^âyçg,Éë'¯²>�܆Ÿá'¿ŽaQ�$vW‰Zº«ì¦&dÁ1>Kúcø�²8tɯ?H^¹`ÉËÓ¹d}㿪L~öTàȵµÜñ¼Ã‹™ô´j.)ãHR0ÑÄø/î¶–AvLö]Lš"J·“jÀK<�Y–ñŠ[mð~ïNªzr˜I‹*@Ô›p´°jÁথL-khd/ÀÀ÷Ú´ŸeK¦ œ«¤¸VÁ] ŽFûŸ²;Ñ,áRÈõÇ3ý9ØµØ z¸�¼OŸÆêŸqɼ÷|†-ؽìe7¯L�-κ¤Àv’R|-\½¦MnÞc¡žõð¦M2*�z\SH\]ÄÛN±5#'°5£NcP•&mIÞF^o§aÿò Èœ¾ˆŒ¦×à«æ_Ìã}éo�O¥Ÿ�±îLm54Žt*›ÙÁÁjÌ…–4îq!«´ÿä>a=' 1ëqñ»Éñ\(û¨¢éÎc‘Û£‡ÃRÛpJóÖ3[›â«ó§œò‚[×áp+|o)ó�…z£ípvÏ]Ö¼-�Y‰±‡œ2ëÞ=™Ì_Z�_f‘àjQ8ý¸ ÌjåÒ«Õ•`ô:µ„ò=ÿr(ŠÍ[÷‰ó¹úÏÛ qAµM`ôJMw–à·íM4øB ÂþÄCU­‹\VF=.ÅP®OOÎn€3/b)wñ윅3;ȳ3�VôY^„ZdrI«t?W�jƒÒñ0Éh4+“Ð�Ü´?¸l¤6û8‘ùÏ^J›^·pë—~ÇÀl) �€ê»yfò7æ‰ä·h†Í£â[è½£‰šFŠÑùðD˜P:{|Øò�]Ø6a Y‡Ã¼ÄH¬A~i‰Ã„îùôý§$ü×°•¢uàîáF0*É€^o%ŠÝûˆ� ɦ;ÿøv²z9îšÐUç8‚È‘ÿf¿œ“ëS`²_®ò¿ýwƒiº Å+?euVÈy WàO%8ffËŠ‡®ñåq– jøÄs¬€Ïd41�� ž5òß°=GŠÜ‡^ A¤Ìw¼@q¥ýè´q>¶Kgr†í¡\žÙ¨jXÀüRÔàlÿeì_©Ž¶+½YéºÓ0¥¶„*7N"ÓwÆP;§ÅE.à1N‡)k=äì¯#�/�PÜ2î¿Åã)æò¦–Ö±ßðsïVªd Ÿ�ópÎøBÞÜë»ÚêÎL(Rœ×djø§ ¾’X|Ð dÇËSf”Å‘ÉåLxØ–5%³pŽgŸœk°³Ø >è;‚FÚŒLÎ�Y�y¶dØc¶#5�ÝSÔå—«›1Ç'ö`~—ýòȰsžÅ³"‰=tÄa9­of­OTQæpk¿çe÷xÉMšVù˜›±ªÝlj™á¦Xé›Eµ_~2Û�åô¶ÜNI½ÁÃÒ'Ðá�3Ø¢ºW�YC÷m8*÷†ÙTèÁ¤òn¶¿�‘äžwÜ•ÖÈ3Ê¡öj".4°g_&ÑW¥µ`¶e7ÌXTéér,ùiíø"CÏ[äðü‹ÍHåÖêÎø§!× {00UrlmÙ:�\äý¦£hž+S…![ßð¯Æ ÷U�ðªd$,n½Éüõ÷}Nõe(_ö$úåÝg½s ñú']ö¾;ƒ«uS"íµèóç83zìÁÖˈQÁìlØ Mæ; Q´t��‰èFظºÌ¶öz Ý•ð'_ã–ÿX Ç7m†ž‚Q4,Z•Ü‚EHEôꤙ‘z™"‰˜XRäÌ|ð“ÂaÓÈ<5¢™E\îÆ©Ë᧦+lux.„¯•�ÛfÏP´ýkœðŒ¥ÏÛÂvY:³ý[¾ 6MC¹ùoñå¥V1x�¹vøÐŒ‰\s—;N¯œBí�GØãË¥œÛ©œoÓ-X3 �55qüšCítçóƨJ£ÿå¨Ö;ÐñX�9¶Ç²�_Î1ߥÿü®?KLƒ~·ùêK‹YËï50Ïz?[µbÄéëÐ�(þskâ„ â0å[ �}“îžDïÜ7\þ×ܤ¯)|¥ÞKì©èg{V^Ãׇᑤ M(þ|“ŠâÿØ1Æök.Bã½n·ÜÒW‚L/}�Íîb[…ˆ#<ýhÉ‘�4½X‘‚Öî³1»(ÏëÎøù÷ß³¥o'ÙûÑ\IÞyôß1‚[þEš=4¹Ä­ŠÎ‚Úì)äžÉ¤$Nq;’p_—«“i™Ü™÷‹»œ²žÌvÇíoå©êýOÖðñ �‰¨Å}!Ð0/L ްµ?�ò¯d¨gÃVšÑ¦3Bíá›r+Ó÷„óÎÈv�‰„\§¯±ëCÓ“Ìl˜--z˜ÍçÜIñÔUr�ä¨[~$ù»Z‘¦Rå¶±O�,×i'i ±m‡ÃpŠ¥7õÃÀλôub=�Ù&V—ñ’ëÏS�ØN ðÔ¦Á34î/÷ÖÁ¨º<«v'…Ëc!£ú »��� ùÿæàðÙ4Èð4€q ú¸‰±°):ƒ‰»*CwôG|&±ŸÔ¶ßaßrö�±|«:”"j‹Ar»¨ýíÅ Ât–ÔÆ7m¿‡ô³ÉLþ3Þ•õÅ¥KÜÁF_™À§N16+ùgl� °J”¨Ì ¯qbvq§ž²’zš}ìFK�Ê þÀH¶ÿëköþ<¡ZntÎùÛ©íB6v¾ÐªÖ…ûµÙÔÞ –‰Ë‡ÑŠôýÐö:G;ç1‘Üš»“ËN|ÊOár03ê,-�þw…µ,mêZt—‹©Ã’¿=彟¸�¨Ûk¤;“™Í�iôc’'¨TÇRpÞn–ZhŒoNüd[üiºñz;ìÙÊvvÝag‹e¡j¡2dù/ ]ciåîÿpiÆMìè�d>Jž´j‰1È¿)„€�Ûè¶à3ûª¢I_̼p¨Mž¹�dY媴ÓÕ‰}ò  „_¶Ì!IÀž¨íçdg¯§Š€X<õ{�‹¢/þ-”³X–ɦRv’mú¸?¯sõdptÛÂ&VÓõ�ÃØÍB š¸þ27íõ&uÈ’®TøÂ Ó8X„4"4�Lø¤ÇõLç¡#Ûçc@‡£ºÑæ£<\ü€ÉíáàÛËÌ5Ü…Š2—¸¹{k@ç©èZ†1Óh êzcþý²næ8'*m»Å?òëàîšÚÀZÃ5Zn3f¹-‘˜ö!ö˜í�šUKÙ•?1\ ØnmÇÒñU+q¡.áú€8ö+s·;þûsїŠìáÖæ0ÎdõÀó‰saç397©”KYr™uæÄómn aS N{Ŧ¼[¸¿¿ðå½­pãL¾p……%�tuÊ^ÖqBß9+±]ÂÙ–þxþ÷ˆT½t–¹Ô²:³îi�j«0p† Þ:ìBÏŒ÷ÃZä?WžÃçŠKBè�0ôŸh@× S`•v-hŽßÍ®‚Ù†}LuåCXœ†ãtsõ½¯ù¢YêÛ½ônT&=M ^'ÈÈìgÇÏñøéÄjê¨ç§Þ¾ÌnÈ„°²9o [â )Ú�ÉáÒ4å«%^|dB -j씹‘è�R<øÔ‡FL¾Ä´ãEÀ¸(�ì®f�Ùlû»—î^_'h<ËѺ�k`ÿ÷¦ª«q—°ˆø7Ì8`‹)žCr}i t¤ Æ„AJ®L?˜ÃÎÊö³ø› Üs ÅåÜçIkøUÑáºl0›}‡ìDer`¡œ(eÇ·ñ;KKñsê5n¢Þ¼a¸)´î¡í+<ñ…¡Hw̧Ù"·1Kü=6u7³órtÿìcÜoÛÆNÞÇ�jµ  Ó2|o– Ÿþô1«˜0Ðr ᪸ÿÿ?,Ïjûy›…ð«[>6ÎD×#m˜{C‹]ÐËúŠ8# 1Xo2(î¹Nµ›¶`nË¿^Ø�ÝÓE  BÆŒö„™Ãlùe‡Íà×rsf¸…·ôÎb^*a,ìþ&â_ñö>‘²¦÷1¿‚$¸ìwüë»ûš4ç˜7Üʧ³rÖôäÄúýÙ‚ößúÃ~k&÷2¢îËüQÙ”×(¢¸ÇÅg²]O�;&kÊ7g ²ÁQ|õWž£¾,)ÖÜÂûîþƒ“Áì¾-̽f­jc~kŒ©þ¤%Fþ” õe‘l©G3 ÒŒàÃÅ*½ù‰�Uhw£#^ßÊcG+\Y³•½y½�nêŸÙ:îb\ ÚžŒfé+�«éë¢l÷œ‘”›—ɂƦr»ß¾¦ëÒªPžp ­ìP&ܦÏÒeìö?Æ]yŠõäDÙÊxwÑuzBY˜ù9 Qé6Ÿ¼ú®ÕˆSZ¥iGN2Ì ¸Ì^÷ÅRý†(&ÿW·lÚ€ÙCŸÙË9•x4zG�Ë!VcŒ.ÈA'¶‹w®xÀîù•¦¾Äù·^ḓ êÜn8W½’–Wa)FÃ�kPuñ/7Μ…I®£±Sûïú=Ž ä[˜ù{3öl‹ l2±>e÷Ôx²÷Šjðkeð´ŒôWLã�)iÔQ–ÈrªÜáÀvæžµëô+f~ßÓ0Äü:üò ‰´ÁÍ(Cg.ï@£ŒÈЮÃû&Ç1°%Ë�=þÃr¶¥QçÊàw\�¡3‘Òp/ϓμ�†?þùl¸´œÚN­Ë*¹ŒöUÜSGŠKv%Ã(M¾ Ü;L@Û{¹ë½d)îïPÓ*̽bLÃ4v¾0 GÜ»%“±jG…ý_˜ñþvtÇhòì!ÎQ]Œô�5’C} Ö˜ÅãtïÇ‚ú3ûð£­,׊ ¥µ"d�ÖÀöŠËQÂÀNf7–ÛPUÐl´�cS ¸ÀM·:�–¤\gÞd G�™\",¹M�«ÔÀ$¯�K•HY8’Úµ / Þò�ËÊíxû‰ì²o#JGÞeÃÛ¤pRö+v4aÕ,ODQOÖ'»’V“\�6©}ÿÍ_é�ëb&R“î>LLOÂ�îèg˜ˆ§ŽÀ+)Üw¡JäÝçCÛG¢{í;œ\“NʱfôÍSÇ®RSF$XfP4³ú6‘LÇL³=´¦*©²ë�!¬iPäNã2øÂ’¦ÿ‡ËŠ˜ÏÕb†wÌÀ&æ.·)š² ­ÁàÞ"’ùŒÉùßÙ¾³âü›21îï”Ü”pÁ�Œ�¬¤EƒQ‚{D ±í!g.² ÍJEaæô¢3_>…ãŠýCx4L…d}žã†:¸ìUJËÿDÂËØsânížN›�÷leœóa’Á ¬^ØÅ™n]N²ßçbù¬x$Îæ0ç›>páT7SN3¡´k18>I çµøQXÏw“6œ®½eó€NT5ƒgÁb��°ö¹œëzæ£CMó½À”ÎÀIþ¬ C嚣8ý—k}›�ÅvÒäÐvµ/)r®¶R´–^þ9Äâ¦fÐÞ’0ØæØÌ/?³BÓø¤Š‘„c0çaÎêNŽæ–7wRüá¬ow!oþAjú[Ðîg ®w–ÿõ«Pzy?sóðÆÉGQmm#/·Rnw³àµé ÿ.¦<ž£"w’ý§‰¨+¦ Å ã¡l7‘T7ƒjm°{<‚>-ž·×€ÑùîZ_^ú—SœÃ—Ѫ3$ïVgrOBup @ü¹»˜Øú~¾X‰÷.²æöÜHÝ P}Y€>÷9G‡ùtþeÌ—‘ ¿=ìùpMZðm4}êD»Û-ƒœ�ìC6�’ÍGg�‡Ü'rd<8��Oµ¦þד™{ám0y-F»'_‚í>Ñtµ¾ž�¼#Ç”VÜçþî¦.qta¾ ¸Åà™RˆªL…Ë“àlX<ÝJàS—b…Ê\PН{Íqk‹ ðí¨í»ÊbPÒí?.Íq-;b:ƒ\£c˜À»t46s�[ÖÐÑǯ™ñ©•\“G§Ý³Âý‚±[•iÛç§Ø4·‚Ë›œÉ–ðß1ÁÛ’nŒ²†Ÿ J#ò5`õ‡ßxÊÀ»Û�÷°N†Òj4Á­˜ò#Or»½6ÐÒ 18ïK +¨d›û]Ùźf6}J?¦_1„æ�ÏxÇ´<¨«Öd*#SÅ}<ÓÇŠ·+@ö›3Xqû!û1Ò•:/±'�Yt_禙�'Ms¦?qÎ~s…¿®:d-üíÎÇð¸�L|ñÌH +7+¡„ú#þˆÝx˜:º�v–Òе,¸ cÁìÝ^1�yÙxêÂX!×Ã^$ÔQÓE˜i±kgV2ÿ©Yì�G(p åú±}�¿ðƒÆ[Ë�ˆj#›ù˜‡¼fÚ %La×ÿâµC¥ÜI“>´xaj*Çq;ÈÃ׃-FþwñàŸ9L¦Ñ˜ÖÉÝS¼À—+üëïá@'1‘4ŽÉòáh…­{ `ÚØc¶õ,»ý[ž?UƹšÐëÿ™Û½kØn@]—±¶/‹©£y´^Îǰƒ´ owd«,×:ù(;tÄnþ— g’©¿'­O­fÁbOpÜK°7­âÜ}H¥ð.6 ¼ãmo\a'†‰Ð—oõX}z*�Ò àöžšKÓm™lÈh–ÿK‹<Þ¢¦ùRZºú w+<,»fr…bOñªÛ PwÆ×� ÙšÃg0ÊÅ€]˜ógŽ>ƦwŒ £o/aow9&sê0.ù,çd-Š·9(ÿ±¾Ofaañ¸iòš{!£òŒþõ·h,Ýþ—-ÖQ¢YÑ1։ݙ¾‡�)ûíTx è—ßÁ®ZÂÍÚÏLE ñÄjZ¢H/Ú�› ÚQP)÷ùÌi<”bJü~êº"ĤÐñÜŽÑ+Ùñ#J0ïú fñMœô.6°G ËH^I ú ÅɴφªïO¢KÙ¢(s¨¦ÕÍó;®˜Ù�L™õùµ–7YÇÆJ2LžÈmSt„OÒ‡¡Ës:è}h@ã;xNá:3÷+kSs¢© ¿ófá{éò�•X,È#vHŸ­I>†’VÐYcJEÚPÖ׋±V*°ïTk˜ª³ÃN¶,òVCùwgñÂv vU)ÂèI4ܽ€ ò^ðãæs<*~Œ¥õW²¯Ê’�¹÷#¶+Ô²SO´Ùω°þG/KØ›¡at«²šÉL9ËEÚtñÚñçy¹‚D*ÿü)²›9Ždù9k­ó@²5‚VU±«rà9nÿ÷¡.Üÿàƒr[÷2�P³JŸiÔ6²ËZxq®ˆÖ^+e3Cmh{ùV”¾„½·Këoñ†­ø±ÍŒŠº2…ñ\aŽ5-Ûk·°SÌþ®HÊ\…/K5è{Pï¤v—ÅŠšaÑÙ xפ…—ÝU† sßq;O £¨Ì·¬>ª‰ÙÍ×€ í3áXæ °žÍ\ECy“á ­[‰å>[hA×>–±¢�˜l‰†ö"¨pÆÔ¦°Cñï •Øñå¦tõc\øp„ÙJ�Ç¢¸ÕL↠%ªÂŸ½ü¯ÝÁŠm­`öuRó½Æ)>ÝÅ ê@�\?ï³ì{)Ç`¨­:¨2j­ÊyˆK txÕÖ÷ݪKø=©�3 ó„ø§ÈG. L-ÆS®ª>ö÷ïeíƒ:0±ý<¿ºGµ?a¢áØR—ÇŠ¿9BýCÌô­‡‚sãùgdá€)0ÑU9pW/‚lêëhݘI´»c¤¥çã;§–A3%–ìÇ2C¦á4ý/L­í å ¸m>W´^’ó²ðìÕ…`à�*r»ìú«¯Ò¤WkÙ‚œ¬�Ïf/”Tá“]"$X�§›Û!bÑvêèÛÆÏzZB¹$ÁôÙ~a¾35*eÉ™ytdßT5ÝÁZòi…cÌÞºÈö»Ú~ ÕÛ0R«œI¨Þ¤ÛÅ 8+,˜›Ñ8™îž ×\¨ýSÏ6þ}Çcn£®« uz¼¤SËeȰ͂»;Ooš wŽI¯.Â’ÿúçv>Z7‚ÒžÊÃýÒàš>“=Òà§(OdSô>p'¤ZÙ„„s|�ñ=|p&“ýy Ó2ãhqT0,¹µ“+ö–�õo›ðáÁröõIÎÝdA/¾Må“®Þ€yѱÌ7G Îßæ¸–¡ÎGRƒ¾:ÏÃ`ã“xñIœ(Õ¡Õ_·îÎS¥˜¿G±©%wúÄ.üʯ4÷%ë Üœ-{áTk ÉpΰlÁRÊ vQâΤÿ"ªƒTHM¦ŠÜÛŠðÙÀöí…8í¤aaù/†�~ô<Š IäâÂEáã@Ûx Ü›ç�íÛµà(ôhÑ{Ë<-;مμ‚W:ÕÒh°IXO® ¿ø�ŸÑ]e 4Ö­æö>ÖS'ÂÙ;ªÌÕàÏ´•ß’iRO-*]R¶`ôˆzh5Ÿƒ#¾}çDZr&]ü#ßfBàŸñ¬Wí/õYL‡$H ÂV±Fšæ4*S\Øöa�`!¥ Ñ˶јG?ñGð¶~M*Ë>÷ˆ’ˆœ™ìI�#Ü`Ñ+wª¢püTÈ Ê‡ÁqÞ€–íØÅœ�_çdÇJr¯+^Ø]É­eE:"ô|Ánü49ßðzÅ4© ûøì€:œ¢³Š=®yÊò&¾f†ÊÙ†5“©ß¦`©ôTÙ‰.šŽ*'–À‘yÆpúTƒå|ØøÂÀ̹Lÿ„:tÝïCóIyœ/lw^ÊþKZƒRªóÙ‡œfl Ú å æ‘ÝU‚YFxbî0ÈÌžF//H‘¿ö!îaú|e€›Â|®‘W%aµ§ØkËlæ3›t²ìbF ®ïhA ïFQÆÆoüuíø)¯ŸgÛòJöÏ1ÖôÆ8“Ô´Aœå9 N6Ʋ–Ìó8_Kœ¾k�ñŠë𬒕´ªÑù§V8l•[!ë©—óÁsa)X“ƒ¨&/;£‚Lwáë]ãaµÇ1v,ï6ìR§»q›l[En2�óñ»©󩱃ã±L7­“5Ñζï½´.²„Ù+àÒb!ª¸†Qáèõ¬]ªƒ%�ÂZ¿ýlbc"HÖö¢�ó{^þ횟x—Oð‰åRŸA@ÖTtŸ·“J¬Óh§W2pÒ"äs\�r4ޱ�TKŠë¿Æí,¿�×ïØÂ÷3Æü¶¡l~èŒ&éþTûŽ¿lxQæ´½#âÑâ̆*:ÌYúþéŸL6ì ¶×gÞ]8ýf›ž¹–Mð?IËÃ'°©ÕÐh.˜~ü%7fÕ§4yéñmfHÑöì¯á 2¹èË«øæãf-WŒ¹asÿ³bÓTn·ça6{w×·á9k�uЉ-,ç^îðÂÅ+„ÌM­ŸïU¦¸– ö1Ý„ŒC®Ã®ü'üÏ9¸^­‹ÛèòböÒ:ÉMÐß¾�»pp]˱±s+7îÊg±ÿ£è¼ãzþ¾8ÞN{I)JI4̨÷9( …ŠP’Y$Bff…–RRJ’2*šŸ÷9‰Y! eD!|�ÌŸßß÷qïãq÷Üûz>ÿ¸÷¼£¦¸¾°½ïÎÈz%þz×Lß.Ê“‰É2N‡¿˜ 4=;Ýè�¼„z=úB¯+ïB–÷ *m•80ïuM¸8Üf—•Ã�ý‡Å"Ã2öØ4ö¦?¥Ž;»±ëÔh2û,ŽXÜ�ï}yoìjXL†‡ÝqÓîyo ¸�8F7&]A›�±XqKŠ¢ÓïÒ�] ÐP së¾Ð\³ ´l3îòõÁæÁª,o¦ÀkÌÖâÚlÝÇwK½‡Õ6u\ñ% /óWßV蘢ЇE“Gø;aÿ7,7 ׯ€£“"`þèkâÛýü+?¬öÏä̳¿Ä«mÈ G™S泂mÛ=£±o4Ðw˜|¿v’Ý� “{㟴4H½ò„¢’KéÏÜ.ÈÖ]A¯j•ùTœ:íéÏÛÃ)£¢EÜ3hM•ºgìÿG�/J”L‰PÅ�aæ(5fFËp�]CqÓ�}¼ó§öÜ!‡´ùüÂvÌb…Sê³¼ª•Gñˆ³'éú×&Ò)èáxùò"ü]à#f¿ „:ãÝ´näv~øºI�´ÇQ•Ìr.ž¸ævOÅ''ùúãõ½{W4ìµ”nZõAÇÙ¥ÔvÏBÐÜGcëéQôö±4é-I#g]#s•‚‰Û3­ùˆæà|òšøµHà¯AÊÜÜ®ˆ�]‹QoRçš�ýC¯Á#g–�§œdÐý„)|¾LîJóõ‰ôl‡O¬Mg¿ÜÇ$ñ>}ê1Ò­•«ß8�]Ö?$þ«þÀ“º(pµP£•WÃS‡ÐÏh.iâ¡™Ñìš~I/'�i‰–ðëåN¸žq&ÏzN×{�å£^ê4mQ÷¿p€Ã­L#_œWëéR‚ � º¾IjD(¬ô–GܧŠë›m•‡<£’ƒQ¯æº^¤û;¦âªyCÑ#i .û.KR®›X›GR”ÌCš ü n,{N+üQ­²‰ƒVÖÑü OéÛƒÃh6s�äìæ$Ž ˜€“ÒêÉ|¸=émDšMS¹{Ã>4ô5Íý@›=pל×ðFi6”º´RÅÔž¨45„r<èè¢|áÇ‚bÚöŸ%dî"÷/G7½ NJ(§3%:AØfsñBf «¿:Èw.Æó·heß4jôÑñ;?'/Mà=ÄV%-z^Äo¡40| ,ªÐÆÒõI¬5a Þ~þŒÎ¯9NŸ\æp¯ ê˜_i…ù>/Ñç öK 1>Ï]ÌãÍúãÑ[KqKT{»ùâèAã…ÛÖÛè–ÃÛùÃNÀÌ>[`Á–¡´¯cý¤À�<¥wS–aá¡^Ø;ð&©ÓÆuõßÈ*Ù ]SýhDM °úú'z�¯€‹úpè ?d5/jï�ÿô€U­ñà½/•5ÿë Ÿj¼ÄEZ÷Ä–ŸŶ·S9à°,š¾½Iç¼K¡:ð:|y0—ý:¥¸¢¦�Ê´×¹ðâ$?ìªÑbO&0|$+Æ$rÒäíœu_‰œÛÙ®Ê#¼Ñÿ)LpÁë®7V”Òð¿|øU0Ú´^ #7-j»<ÆfŽEµCí‚‚N¹hðµ9Éø>¥š¾g¡ºé°<7šb µ°pø1qðÈ!xÊÿ¶X2i¯8$±滽¢!?d°ôÅ,ñÌ¡wÐà>ƒ”ÃïÒɰNÑÅT–Ôf™ÒíÔ£”ž3Fɬ"™sýaÒªalår nÚLÁ?æ}áL¦z+;Á¦¿.¡×ÿÿw{þ·¾'ü^î+ØØôá¼;ÀKB[à^Ao¸ ÊW{ãò¦ƒÔæx þtÕñ·p:ÚSŸ–& á’šþüÛ¶/L›Å_:Tp¨ówñäÂ\0zz–‚ô.óé`_ŸeNkC§¢ÑÊXñWÈ úØÝ nkµ„éÖÿÿG~›XÖ¯�òdTIͦ‚"62l¦(NU]‚²wKàÚC!´ÉÞ¾º(,üÙBK¼š`XÛ¥»Kã˜VBùᥤ½«ÉãÅ{»¬ßÖ8¬x(êNú]O×ãáˆÇÔ¿3Š47 =ý>ì÷ÏßZtɹæ5YL3FÏÝuT E4(e!>3ÇPÛZÒ}>%¯Nb•¦=.žcŽË;kIê—,¬Š/˺7Á¬7“9ø, Möl!µ¼‹6¿¢éäéWTošðRì“Q¼iÖØø%�~$ÎcûäCê(‘fl*¤Ÿ‹gpˆÒ»£/ÑÚâ^,uäM«ÙKdz�Ãýù\{¼Ÿ˜ãN‹Na±sžìØ#^øúZ2ËÀ nÞ~WÎòê‡S¸õãxTîeƒÚf£Ñ»> 4Ì'ã§Xk^§f _ÆØÀÏÇD¹æQ�)OÔX8�Ï?wÀ•GÀ›²xò±¼ K:êéEtj(.» Êy··Ò=¹ äçጪCñŸ÷õ,Y¦Á³ÎvRY³ ûÅ‚®æ?š,–áÈž'¹x‹:ȨŒ¢àô;4ÝL>}•åT£Ã8£x\—�ï9�-MóìnÍŒ¦aÚÃ8;d.«½�‹|b�d.xžáwƒôñà$ |�2™Íܳ¦Ã#RNœ«{6ÐìéƒøÖ úã´NØ9x pàtŠ˜zý"¼\q &8¦g*IúA‰øjg0·åo �fðK¶Íî¦Á^èR,Ãášs1盟¾š|NŠ ô‡àËq4@^u/ÖÐÄùžð™Þ‰ræà”¶—Í8_¬ì<%t,øc7MP€ºŠ^¼N†°ûY*é5xòa­�úz&N-œO7æ‚[➈¾vòçô.¤àÁyè±,PÞÕ›ÖY6Ádó7ô²e&šD¸PÌíà7wžë˜Ï‡å-èüëcä6ó¤ð¸Ö ‹“¾Š3ûÑì¡1|²pª_#î/C‡O÷â3öêxqÞwhY±“—µeÍê×`Ûk�Ýæ¤FQ¾ùœ5A¸êÿÒ?‡ÃÒ2Kl FUÔÔWãÌ#òhóg}ò®�9Ÿ4Ñ!ø ¤yn»ÀÒ™—iò&sáôäRŒØØ*<÷’êÇ µXU�îA «ûoWg¿Ýg¡a“Àc—¤>3×`áCiÞ¾µ ”Ž%J<²×`ëi1ùü4Zfop\çTœ~@§:2û¯èY²ƒü·Û@–Šʽ.Å+ª WñÂðpœß=’e´ˆÕjÉ“T?H�—~�Ó¶woÂü®~”2P?箞ñh�+D¼MúÞ¶FT½ǧn¡·òxýšV:�œ‹së/ÒW=Xê Å}® >ý¤pʧ0º¹ÞžÝ;:àbÆs8µý]Ý³Š‚&œ†ÚÀ,’ú;Xl˜PC {˜ˆ�ãæÀŽÓºðbB¼×ÕÇ#ÍiÃ?'Øÿ³Nrcg:ŒLvãCUÜàcNÎ÷,yï9e¼üb#ç|ñææÝ€‡+—âÔךx5æ±8Á¤/tÄ/ÇOòéhy«P;9—e‡5‰õ³áÏÐO ÷¬+Tq®W6\Ìn¶ë'8V•i½¤‘§*Y~€ ~RGª®Öç ;VÚ&\”Æ�+ƒ£ÿgoÛž‹J…%ív­Û³h†K(ö¿œLŸþcÙ/UÈ÷¿Q„xÁîGm Êv«ó›°Úû–izñ¥�ÒY°\a,ej(€cN>LÈ üÁívG'-§˜EÛ@K¡Ž‹U4ÔÊŠïîu¡\�fØ×=ƒV�ÅÄΞãº;¿ÐjÇ+x7j3¼7¶äýßк <÷ôx+¹K)Ø—,ŸEáñx¹´7å;¾€ç×ù‹ótAnÑh°8wƒ»ÌÇÿ–øãÆÔ>¥6´fRlÿ8a’ÊZîîˆâÇöÏ!4«{ÿžÍç™}hY‚#ÿ½â‡®£ï⣤S=©àïBi›šs©¬ôa뉿I™V¹@Ÿ�Çò‹á ¼|Ÿ‚è»Ø†§¼DcËÂ!ûöfÝ‹uR]pö»aÜúPExPt\0¯ü •íªä7$O(ѳâõcFñu›£Âäùƒ¸ô{_l¾m‹'¢Ž‘w„z­SÀ‹7¶pl£*h5Kñ–òðz¥1�õèŲE/ÅîEÛ(aÎHt{tžú?”Æ�YúøLc…­­ñt¼k`%$_Ë�߆Éüð¨<]¾Ó.é;Zýt’œ q¥C#Góžaå"ˆ?³˜šý ó‘žâP• Ô nëÅ={Øëë|ÚÞÌi9÷¨¿žð§÷#þý²?º ¼DKUœ1Ãa"7êI¡†q,/&O†2* ·7�_øBÒí¿„Ñ¡«XNëu»èâûP>n0ØÎ“di„0¬Ž�Ãùw£Åîà“P²wž•Â^{ö°û( (y�’ÝF=6xBݺ…dúF‰­+´04±’#®§`Ã"Q÷Q1l�ïdÑe_›˜]›@3¯/ÂùDgb�Óñ‰+ðdËÉCC}¢½UÈÝÑM¦aèBr–Ï>_+š&°gj.»ëƒ ê³ò62MD™q&l¿÷嫊”sß—0á d7Ê�{Ÿ4áÅA6ËmƒûÇ,Y?í…p'ôI­;%4¶$’Ãþd˜[8“7®`>ÿë(h›6ƒ…y,Âûë8vÊP­Ãß¾ðÊ¿iÚÇÃB¸ëk¡üÁqÁþé ¶8Ÿ÷d¼„ ÐÅ› Ž`Ìúϰµ9D ¶ <ÿÍ}Zé/ŽÅ+Zz,sÄgªîåó(Z Mzˆ—|ÝPçÞ8rœÕGR¤r„´Æ½¢–? ÕßçÙp¼Ÿ?/ZŽ…[ñNU’øjÌmaL¾ ´¤ªãñF3>¤¨À �¾¨@™˜½u&� Š…Œ7-p9ö hÔG‘£ÛqûÌ�ìõ!€çÝÉãåkãhÆ y~j;m;Oˆ£OÙ¡é5Ú:ÞsîÕÓö_áßS.FÙñ3ï÷ðnm í¸8‘Õ–¥šÞ7é›C½\ÐD“òìaÖì>Pÿ€œ«„¿=ãÔÁ�è^¨*�ö}kWã¨ãâ3iD•»¸B½/j¯�Ãÿn¤@­(ª¬¬ƒ¾#/²·Oçôø$\u :R†²ßÓ3’©ÚóèàÏËüõ¥9?’l¥—ã÷Ùiïš…’^+Å k»à“¦÷¯¨†w¤ëÇz²fkA•´ž**ËĵO‹,QZõ „ù+â£ö˜°MσîûÇ)Uõ]K—E¥©ÇÄiW&ò6õ0|«5l}(Z3¥³f µMtœ+ƒ«±ù‹!×™cËñ™Ô^ì5V‰›fCéúrz7é›h�ÌIß`rörž’·—Ê@ŸË^èò�}:Ú÷`ŸDž½Å‰Õ¦ü�Xîß�ön—Œ¬¤ú鯤´~™¾/¼÷ù’þÛ"ª¿üÛîÊËQ˜'m…®;²è·£l EÀ³¼eº‹]©âÓª0ì4öÅñÖs09ÜžßÕ1Ô,-z1Å®V!˜cÒ¿P¾u.yõÚÅÿñV–Ìñ£_s—CI¤ž°�_Ë… €D”Ÿõž]ÏFª? qÇf!]â@ýg ¡y~ÿØóÁ_z³ª„üÇZà‘­ Ú¨Ïò‰©Ü¶â±ÄvL—n^‚ÂçÍplÛ:ük¦Åw«ã sq y�8 …¾× däkÚhòTpÑŸ#IØ>'øF[7< Ç™ ÐøÏ+êë­ÎÉ\/|]uv�½üZf.>øÏ˜?GPIT½¨÷u:i&Š#ÕŠS«Gò¹-W!>ì+æ�ÚC—['�[ú0‡ŒzM%™ì£š(Íë6o~=qÄSõš Î-ÇwU†ÐkÁlœ'úq‰�1/ÈL·½1À•ô#W � Àà‰Dê»F@¯ �aþœ X°4ž,f ¤ï÷ƒ9ò£#ÆFß§ Å8–uƒºŸùâ©ÃïHÍx׆_¥ì¸|õ7—ªÑ׬Sã,U<øïéPþb~DÈ:‘+sâ1Å?•½Tÿƒè? 2/žœƒ¦ÃM{itm›Œ‰c“YæHj‹Â�&·ð�¼οw ÚVög©Ì 8ÓÏ‹ŒÚ§§ÙÜÔÕ›k]làöº|›däLø‚ß(´º<Šfë|Æ ~´TN “~ïYôŒ"lïÕ?׆CÅÚýALýqK¼ûÌξtwº”’üƒ•lñÄnã½löQÀùîʼö½-)Yù… ÿÅQo.,ŽK5mqI$R׳z ]?�_\Rƒu1‹YybÉß6Aµ±s1ü[3tuÞ£”/ ¸E9 “3Ó +àÍ¿:�ŒÛ'Ëò�H=êÞx•æ=>AîQ¦<ôÏo°ôɤÌÈ4Aœ¨…º~ûÙ}ÉBš±e&Ç}w‚ñòd�ÐÚ¢Átr+SE :¶ˆ}>׊›BfðQc-º¿¦ê¨iqŸž�ÿ’é_3‘ã'®@Ø�`‘âˆoU`Ê›)<*ÖE"¥4�ÞÅÃòH-ún$‹‰Ù³ipXˆ0W^ U®…·¶ÐáZÜñ-'Œ•´ ¬6AÜæ4…N Š!²ønÊ!q¬V ¤¿ù*Ü�˜Oolòyãešù Ÿ•«ñϲÓ�_q¯röÉp¼í¬ «3i¶ÁW±ß¾%Û¥Ê;sóQ#|u¼�Ì—ç@ˆzOøºs�`ø�'ó‡¹ß þìj}ÚNóÞ¶ ²rg¿ú‡ã¼®‚SµÀGŒ?ÂØ<&]�w°mX-í·Âsæ?ÅëõC)º9 ]!Zx°=çó4+r4‚uç�Ñù\,¼ˆ²n÷à%šýðʼnôk¶qËÈÙ” )™IÂ$�œ|„Þs¢Éµ,Fù–ScÅ/aÎ.^q,—zTÞ‡W­ã°R3›~~óã�ÇsyÿaY^;4‰— é� §.àÁ÷c ´³Ñºr/+%¥‘ÙãpàÐaúeø‹6[�‡è·–vÙÑq8@öu·X†ñÛØüñ4;nƒó½OÂÁqÅüU6f œ�ŽâWéƒüú�  òg~>X|øCGV—S­b¤0þa=¼Õµ'í…ý ¹OžÙs \Óêáé�íйr7ºŠF°ÿÑ3têµ%„OŸJÙÞÕ|ìÙ_š°Z†7_,"—Bz4ý•` …n¦')má4NZ£_=¾r̞ؕ:ÍSôÑ?º”:¥qÙX[ÔjXÎ)éCx•Ò}XÆ{à�ú:º6 Û#úÓÒËØi| TÒãOÂ0Ç18ÍÜ”E)CŸ�Â?»Õ(F]žÄâÿžÜØ'¨�ú\SᮿE«Àb:1G“·ÕÒ¬Ûæ|êRï�ôÁÕÖvK¯=9µVAK½²Æ¡Á4¯\�Í.N¼ç몡{î‰wgÂ-ñîµhH8¤À×Íf‡ §Kî¿P@N5ÐÞd!®S4c÷d n]ó–åÇ)rËõt:á•OÿõR¡IqapãÚ#QSú·¤á™7`á�Ú5±T·»™",æ�ÓÞ!X¶ ÛnKanZÒ8x•å+J~lÿ~#ß‘h`áÍ­KvXbÌq�_œkäwâAý‹BµÛî›-C¯ú;ˆýÛÆ‚çÕ�šº+Pl�ûìW££F(¯[O äÀc’;)àKZ¶f4êøãKÔbýòsºp{¼ÿ0”mÖLBõA3ѤëÌü™DkõWâéÿú�%TÀ®Ú/neñ|¹`4=’ãÏgF å%Êð)bŸ¸is›­êºu¨¸×‹{Û£Nº2GtÕÀŸ,UbÅá/9kMœ>ÓïÌ äjñxÚéC¿÷{ÅÓ·S¨åÖ3(ªÿMƒ²ký}›�$Hýã�XjÓž­8N›C·³Ô@#”D÷å•“CAS%m¯÷ŇOÁë?ídЫ�ÃŒ9pÇ9Ñ/b®+O©E±¼pé%xní$HÙï¨ ½(hþ:Ž5xÂÓ?Ðx6“c�´i\×8ŠËÉlØDþ°®×þ€¯ÿ¿·°0üsPÏößâà©J´ßìmeâë"q߃•ó>nåúá€í©P7;¼|&|¸{�²·_áØð}Ý". ãûxñ÷=09`wf•<†½–�Udzìú|ô™‘'œÇa|†+›%ÊÐÉ”`ñλeÎAÞñ] >r)ï:RŽÏc¬èómy¬Ú2B|Üf†ßŠ?‘\Ô^Pš2š·\3¦ýÍ=0®¯3†î: ®Ë3ðáÕ�ô:„Š¿‚Ѥ‹»Z²ðÐ¥Fð²ßÍiƺü×g-nê½ y@°jUgÓ~}x:¸þ* ÆÞj”Ô¬Ž?³Ïõáô3Ö|º_$þ7_Ëo¦‘—³**kÌ⇳]ÐbÔ.ny·ô"&óà†PjÞòÞI£Ï®[4Äwš5MƒOÉjœÙÓ†˜oDƒ^�<Ï�]e,°óãyìž+|Põ…ÆÍÉÐËÜ\5¤1uU#äíƒuöÏHº×s¡ïú*¡¿þ'Þ¡4�-^ܶ;25ˆ[šäxé>p)BÔ-Ë ³Î/à‚o ü ‹¤�ÊœnÝŸÏÑæ·ÒK©»AŽ,?ñÌ{SÀçñdLM ¤çˆs[H†ð~Õl¨¸~pl(Û=ÝDS[¡Î /M ÊV��Çf�»iÚk þõ Ñë© {Þ[+ÍöÁà{ Ø¾î …uûð›ý=Q®¿4>öî$A÷ <ñêG‹¦ºqñý¼ü3V¼5¢„†ž�ì��EÇW14cIž0íÜ?ï+6'�;{Hò溘|vq­§ìÏëylñ{¾¢)Ò2yœ[¿ŸK+ÐÏ3õ¸Å}Ìšµ}̤1ÍÒnõ™ƒ¶•uÿ\΂ÔëHŒ`Ö࢒ò%¾ºo %ȉv çÕ¹=ø(ù8ªáŒßƒðï”Hù$�ࣸõ3ûи�ñ‚e×RÒ*qäþ‡Ö“åÑñ8CWšŸœ~XµJ÷·øyü0®ìÀ k#Øx»<Œ›´›O¹=ûžÍ'Ûî\~5l …ý·*åïPLø z-<�í.8Aû¯GŒ Ö¤²Ü`èéŽKµ"iФmp!å ½{»ŒeDZÁÇFzù(Z­Žßæ½3ô-!Já†pö€7÷²Me3…UbJŠ&ÖÄV¯‹NÄÖ•�˜ 3þü�)xn–#ú¸Ä²Ò:m|ûMO�; Ò¥q¿­Ä¥½¥Øæa¸°�ÂÔQc`(×(žÃ8W3LÕWE¿£5`wÖs] L&’߬G¡´¬'Š/ÒÕÂ:|°]R¹À|?ov ê³F(5ǵ›çâÅ;%BÝ$#²*öÄŠS¸µ} 矠RYGÜ"åÆËcÑïñ,–’ÓÍ\}ÞžåÅfgy‘û˜ö'Uˆ€uüéÆXnèñ¬6GïÆ›gÂÑò^B?õø4� ugÑWÃgÂ×RY’ÊøNvÛÙ¶w¥Èzᶘ0ðy¤FÅË»èÖZÍꢫ�`¹ÍŠVÅ�·)²ÞNº®e³¼ä=I�Q¡'F“ùÝÕßÿ|ßR�3€.6üuGÀtz:üÅT¦ã­.è2æ¤xÊ¿”Ô£‚iøÈZvÚd)þæP/ªp¿Rd'.ì½ í]S¡ßÉQ4¢Ç¡ø† Ï:ìGÝK0¡à<(>Äe–òÉÔÿˆÜnƒÍþhÖºœ–ªâóíô}H&� ±ý`7vY‰ÂÜgóÈÕ×�[ÆçÄå÷i£oNY¯ �G‡Ï;ÜµÊ Üôô0Éâ;h�Üó#Ž7ÔàYW{“Ü}uÝxp‰ñUõñà¬=|ùãEÌ=è+¤ zÌý®Á)%°ÉPB=¥$Lè¯Ë.dÌî.Ãb»HÏéèËŠe—hößm$Vþï�{)‹—–õe/i jó]¨õÍf[g¢á§Ý™'NÍ^ û}³pR�¥øjÉI\a:•[Tðç`S&É?&W²ä–ÉÍ`Ý÷MyžCïoLÂFyoT£Ã£�s6ãá›Õ¶N+ßÀ›¡µØôv*ºy_¥Ç=¢¡{`‡$rµ@R£zÒŸO 7è4ø_E7_„B×._[“Í£*'¢¯v.¨^uRlf³n 8_i„'B=©+`<ßnÀ­ÿÍàŒY¹l�¤L“M†â ¯+phRÜrm‡â®§ҙàz"�^-NƘ~Gh„ÆeÛ†Èv1««ŽïõA}ÿD»—¬8àï)œTšƒçN^ ÓÂw¼²n"Gµ_6„ß:ž(bF$l~º�µNü¤Ñ×ÜùG÷(R¼ONpæôô�›Ëxóˆ7FöN¦í¯ÀËõ¶Ð>ÉóÛ5j·ÎÆ�w°ìº2‹ åÈ£i<-€âÀºUôñ® ì�xI¦=z �2+ÿdPznƒwëÝpµ¶!_þ±/Ÿ…ø±Öü~~#ùû7€Ì²Øk —,zËz5¹µ3å8,vîXµïV<ÀÔŒ÷êxRÔÖxÌ•Ñãïs P9vyÕ ‰=ÊM5€‰«ÃÐ'xl;8˜Œ.J¡ô¨´JÊ‹üŸ»CóŸ·BdñÒˆ6b%rñ,l?=ó_λòÀà1ã}ÞŶÀÌ%{ñur&>ûýl¶…>/SZ°Œ µE“±Ç(N=–bU΃A÷\~õS¬Ú6,©Ã²Õ*8|j3L h¦u£°ßhK^’-eS¦;«àKj׋)¼¸ [µžŠ; ƒ‰þoqK¿›@OàÛåv\õ8šŸ�d×ÎZR6­„ E!0Ïd:n-O`å]4>(J¥T“畃‚«R9D/ß,,I Á·‡³WÎ"û[Ÿûjh°Ó m±ª¯<¾ñØÌFú%ðx|zÛ "Iû³Ƨ<ä†þ¦vûvùgkEÙñÓ÷GâUã±´fÞcZ}êÍ' OÖ·“ø¶€<ýÍ$ß^ bg…\É=öfÇŠ@ˆ¸qŠ„¿£¬–±ìµ›œ{ci­9ç_ÚÎ —µSÞã|ŒÞ›m*ϯo¢áS±ëœ"Z”VÀ…‹gТu®¯¿'yiö¡*óI?öÛW)®ü8Ž…‘ÿÁ£ÿúˆAY´£�èÃî nÌ�¥å[ ùÅw\é:{­ž‹ºª}QJÖ›¾Û Úïõ|QÙª…ˆ³��ðÇ…˜áÓµbw³þM̬ۋýþùN—BOÖM:„! 纲©_XJE×wU±íÖAþ„!} Ë�ZÞ‹�ü<„›/JóâçÿêîçdÔêJ‡E;£Íš¿ôµÀ”Ϭ0¦ñçžÑŒ¤aÐqâ4GÏþNûÜ0SU€ß÷_ß¼^ÔÃ})M/*fϦváHC0Z,dã²E¼fÞn¾[¦ÃwÖ¥ÃÆíBÒ1ü={ 8ûºJÓåxkþòrðßÇ+”ÞÁ³«.ÞùJÓÂ-%žc«àtã>ޏ~Ó$êœcYÄO‹åyz®,kû¥Âë—ãq‚â-\¹3\<;hDÔÆÃÇjžÇÀ6;‚åçßj Á‘ 7Юø4žúk_ïÆ=s…ÂMº¸Ø®ž¹ºSŒk¬¥(Wô€O]€Jv ÎÿomF!¸ȳC@ UÆX  ¦Ø•*à‡&Sú�üJØ£¨�e/Ú=‘ ÂêpžUPÏ/ÞzÙF½8Zqæ²%øÇß@5q¦ÄÅC}Óp}û3qYªv—ô¡è^!âã�0(i:Dû–M³ øŽ¯BTj›øR[¯§)Â�¸ièœÁöúÉönœ�A$h¬å¬9N£Õ'ÈÀ·Œ i.o)¸ÚzŒ»�À ûûáõÇè;üà8í·B‹²¢˜éßsEgìÈÌÏ·gÁ©‰ÁBúÈ<èȰ§Îà pÓþ$5Oö§£ý— ¿Õ/s»æj\“�†ëÖ»@¥â69žHùÍ'ß'ëJY©îý†oð-­‰Ž7GØõ"ü¥ò„4}Ïò­Nì"å,1c„õÿøöùÀx!õ gŒÂšä¼“ Y;�©_½6F™‹¶ƒÌ°¹s¶”âôçµ0oÍ,X3îçO2áë}4Ù»R‘§vwQš[qæJ,]bÂCâANU…g,zн—Dqu›*?L·Ç£_ú"Œ0ÄŠ³Ü«&_,»ÇþMÁðxß[ÁuÝUÚ™›‡%CÜá‡üQž¶5Œc�«@çP>õT¾N ­hlí˃ýXø8;—7©FRÿŸ.!Äîc‹éRêb|Õ(Âˬ$q/^€ÏÁ/ÅÀèéü[i'Ìé„ß= $ G®�à š±t0[‡=oDTèÈ¥„%Zà;àÍZÑ«&Ž »Õ}¸îø'pmq•ÈÕ c�¨dòTì�çÆIñ™á?Á¥€È«BQÓ–I~&Ú|ê�‡z7l5\Ê`5�ÉP³©7š/Ûk÷óŸ³|‰‡;§ž¬Îp¶i>)¯i¤‡7ãø¤ÑEj¿Š»Ç_–||®�ï·þ€W­ËùaNŒïEôÚ³ìs¸üò:¬÷áЇ¹í  öU ƒ|ËAx=w/?Ô?IýŸòG mÝ�‰Æ6ð$ƒ£œ«…¦ q�%û^…BÁ¨Vpº¬ ~'°b˜5> (æûr'ø�³¦m.´[¯1‡·ŒÄ¨3qü�ºpo¨<�>‡jãö!öÅâûÐy´[È”™ÆƒoXrN³¿½œöO×C…ÇïéŸö¶·D¯¤ôâ^5Mýï²�° haˆ·ðð†.àA¾d7 ¼S¤È1ýñì…4ŽôÒ‡›Vî âÐD+|&€wÐ|è=¹Û¿J±Ø<‹º‹ªŠ'œ¦“FÙϤsÜœÎ�=sáñÀáê•£¨2©ƺ÷ÀãT9½§4x Â3ßÖQÆ‹Èî–EqT;šàÖ¢û8{æ!ñ«±4ë› ¦¼ú( ^;‚ßÍŸÄ—ŒÆ¢ÒB^Õ™ Š.©õ�‘]’ÞDܼJ�;ò4™õ7à—m+ñqv ý°±`�Ê«p“ÖÀ�˜áP’¾‚=æ¢Å†[`-NƒÐýŠøÑÑ“‡$|æ¬<'¿žÀE†bJqÀc^j%Gowÿ±ú¶^Óû±úî0»t¹üå�µ¸qBêÄ’`ëªGë‘hø¸`莇3§ó û}|àJ<­iÅWã„ÃÛòà•¡?|>Æ®xê áÑ›½|Ñeð’%X°i³ðÕ÷'¼>ÞIs'Ñ~‡›°sB>”{[ÀŸÄÕ b¡�ç»Ãh·r8æé¬¢ÓÛ(¼(îÂs˜y´�šr\!øÖ š¶8…oÂY;‡E(áœ%ª|¨&³!Ÿ«æMœ(ð¶8>¼ó6F�z-Ú¿ ^ú£wøqxÒÖIþ—§ÓwÃGŸ±Ðž|ÅE˜xÁ†éì ³K—â­æXê;ìï^vÿf­ædIeœÛŒ ‹OPçÞ¥¨â´“3s‡ˆ}»µùyy‰â€@îô8 4÷ZÕö{ûð£$‚ÂgÆó³ìbXâ°•²¥Äì¯Ê’‘ß×ҌƩ”WeÃO&¬¥~¾Ed…7AvQßô:ðÿ€ø±Q�‡ê¶ •Ýþ9ïq»U÷ç –‘5¾Wž`«pï5=­L]¥et¹æ[§xpÝÕÝÜ}y#k÷U@;wŽî©Á \ñnt(«Î­d£7§À)û<^ÚÂ[ŸHÊ®æÚ ;¶ýŽë@¡� ×…I·‰ á@s25:ê¢íõFA-Ò�i…À�Eô«é™ðªæ.[yìF¹û£éýˆ8™GF§‡þãÆhžøë€x/£]pmñç›LD·õZ,ÔÄã+Õ:N s"R½qÞ³•ðèãòœïKUþoÉIV„Sçjyމ+ìɧÓçŠ7 ΑZ]û9Œä“®ß¹sR ŠJ /§†w{øÛò•Î�ÓÊ[iâÔ½+µçá>ŽÃ¯ó_CÛ…ó<ÏYà¹p]�³%á™jpðÙ0j³`¾ÛwÏÿ�û`�ß@�ÖsÀ¥MÐ^žCŠþ6´%t>;ÀF<eþ|wË$xúz–dâšZaC/ £¦ ;p°Ÿ1»D.€ØG§°x±&Ìïk‹= FIÚú_ SrÅ>Ƹ¥3>·ø±F×-zo©QõòHvêÂ� ­”�¦„›Õo pË›·¤GqEW ËÞºGvrC¸¬Ñ‹&6Gâ—²ïB&Ï¡üòV>¥Êô�‡Þ Œ!ý;!¨î�yë…EÃqðQ?0ý0.”'ÂÎ�ëL_p‡So¬MúwÞ?¶ÕlÕª¼ójÉzâY‡œðnƒ/QãsÉhïB|¤´œßòq~£!C’>¸7¾Ex_¬Ë~÷ÈÆ¯œÿù$·*pBÉ{¸—sÌ®xãŸ-£Ù¢ûùj‡ç÷ÊcɰBHøGyš³éþ£MPŸ¸/ôèÚM’»¯Ì†WIW騨¹ú¥Æò'LÑnÈ-èöÛ‰k]�Š\/¨Îå\{S1õ¤›Ì¥¾]? z•6™u{â™,}”ïôá)!ÀÏ;¨è,B¿‰púÝ1¼C}¾Ÿ'…#Åð>}½k½hw>Ø M¥óhú„Ò9êÏ�uÀïÁ•B]OO¾1.žõª�ñ^‡9åÙÃS¢GSe2 “‹·CΧ¦ÊQŸf¢Âp>3Ø„³öõ4;[qÏÚnšÛ—• |y—­ÆË6CÅ¥ ؤ-§–‹îɲÂ)Y*ÿº%ºRÕ�¼�M¢ðÞ«ðv æ«m›ËË9oI&èÝB}R¹ŸÑXºcgIrpÆÛ¿«špÖKb¬×Õ¦¹Çy\òpl™-¼ŸßIoÔšÀæÓašÖï;üÉSæû’ÛtòÔ,˜#2¢YE-’ »k¨¦×b¾}I/4©cPÔ^Î(qØÅH^ÿc(Ü<®ÈƒWÂè7~—e§HsÊ!ñS ÿµ�ÂÚwÓx¯ï IZk,è<ðâò2œÕÇ'úÄш4gŽš'‡O¿?µý¸PŸ&on®S™îqŽ‚ß=Ðú¼æÿ„¼Žx2x"¿ÀÒœœóªO8?„M”þƒ¬í�ô§ì³!õ7 Ã3ß»„ïO“Øuãt^$\…¥7�p¿³ÆÅ/¿ýôÆÿQtÞÿ\m§l¢RR(*£ä+‰Œ÷u}¢45µ„v©”JV©$‘(;²ÉÈ*%R>ïs)2" ‰Ò��´h‡rwÿç:ç:×ëù|œN³¤mß �ê;û™Ñò8<Ð) G®Ft¯~&¯gÛ ãú JY®h äœ;B{ÚãØÜkåÂßÚž8dqÛtí(#T–6|Ð#·\}¦­+b>RèWCWâéwa”bñd·úS4í`×vNf¹2'éú‹Ð÷V?U¿àÛ#îàÛô+P§ò ön¦#é÷°Ö1é±ËÐuçô^GÙç9�“~‘Eù ǰË}Å£ó`àémÖd$O�Ý£è£*6¢ù8V†®¦êìn¶õ¼(lY<ƒöü'B Ny4éäv}åu¦)Ž% ôù³NȰ ǶMxnG8²>%Úªˆ´çú’í–&Ø×ô…[=·˜o«Ú“¿~ãƒ"©¿³˜LuÏÒ· ¬d_^ÈOe ›iŽƒLɇŸ_x\$_òûÈT¢ÌqxûG(°âJo"†Kÿ@¼È"ü³d€}<�¿ åOÕ퇟�²åSáL] x2µxÓ)x¶ö˜6H¸bÂ*œw�#—ñó¨8^—ì½|axV>K1þÀ§$yà-ƒ!f½ì?/ò.õ–¡”ÿ글o’ ˆ‚Ó•/™Ñ*¦æ¸ŽvÃrãfÖxl/æé¥á»¤ìXÅzNDó Dƒ©Ê=œPQ@WßÔ³¤�×è#}O>šN †EáÚÅÇxUW+}޶†�€f�.ßx6_E¥ÀK= ô�–#©£;QÔ(’Kš—ŸÝJZ „«‡v1-wœ·<=ßmGÁM!·¶C¨9m3oc&[vPˆêLúq,̬úö,6!HÆÂ™E©hóaž=ü<«#dõ­hR/sX‚ ·|ÐR¿\rƒÕ­zpéyì·/ßöqë  ÉKûMFp¡9�Ør`¹ÄÙÓ-§YÂõ‚Kxê•]ôY‹*ñ³�ûbÄFÿ¶Ã“ëã`Ÿð9‹ rç»{RHi¶îžpš?:éWQ“…Ù§”XßW<0wñÓ&PÑj-Úÿ2…mª)ç,S³høË‡Â¸£kP\iN)ù eט÷õ™Ô+Lãym|üö§üDý4êu;Êüý´è�|õÈÿ„;#NÓÏïþ¸ØövÌ÷a¯üãQæï0¬yZÆOþ+ƒùúçÁ¿a¥Ždšy“¨ª7ÃwN!CES¶ÍbÕïXIï§àªé-˜ZÈÛ¨$‚ë(+\çJGƦÑò†9¬Y.Œ_e»F'ËC¢¬,¿}aW®¶˜­w±¤C÷•°]ÐK ÐÙ.1E1ópjü+Cm)O˜Ãm Ò3¸Ï4å•–#HWû««Gz‘¾Ð9tß�I†üJQäæšÿa8 ~·A«/tV©˨s(ú7–EÏ’ ‰“Ê¡zß9&3W• ¿Àîygqó`&|óÝŒmw3pnÕWV<šñ3¦½bû$ñ�Í~ÜÁm´O¡ÀìPštHàéK’T§´‚mL²¥mûçÑq£­hHXã¢*ÜÓg–‡_²%ÉØáäJXõK“žß­Cõ­ È-µ‚ÐY’4©±<.½½ÎÅ)Ãä\[Ÿ‚«\Öàÿ>vY¾Ì¼õÃÜÚìL±_=YÍÆm裶–èFƒëX‚™·…Q7vÀÈÑÖT[þ€Nøâl8Æl´ï°Y¿8ëóštÂ÷—2ølò”iûøÅôËIš´qóEÜe5œùF-Ç<ç áÜg#ð|ú$ò¨ÞÏ.ÿÒ~W“«9aÅ$â?Ähñì†ñ03$•lLSã{KÌkó箨c£;Fòcâ3ÙIåáüP¸Sè?j(ÿÁ)Ú‡WÖäÒqƒ+¬p½ ¸ /Áö&SÚ-üέìÔ�Sÿš‡¿… \{sÕËU¬?w–”/'�õøg’%ëYÂrç 8ð-§Iºðù&—émG­»¶Žq w†3Ù±ŸúpyôpêÉ‘ä>.’f‡@-Ò’¯ßþ…›7e1}ß~ƒ½é�CëÇãE™Ôå>ƒ¾_NA½ópßv!“\»�Œ~"¾­¬2ÄÓÇäSÆIêèÛÁò^•2é¿“hΕ×P¿Ü›dXÆ·õða*~Ø¿ž¾w åÚ'°5ÑdRrqü…-™s”FÆ‚0§\– Rûÿ"#�[Óm�éý/9wÉ"èƒO¾(«5 ƒÏC]ÈL¸² ÎLÏ'»×B”U²ÃN‰ÊUÇà†�!¦‚(/šºö7¨}ñC×àݸ[6Ž5É�i$\eN›ÉKY„5\7à Ãbh’Âc>nÌQÚó±žÕž3Âì{¤-Š�+ŽÂ¦ZŽÔõ'b�­:ÅïO@SÑv\Ї7¼À »2|_�fµÌ!u?¾^IÜÔZ*9·œé•k²¬ê˜{v€ý<"À 9|üSK*˜ò¯ßÌUéfvu°ËÒ®äYq‘ee¡Ó—™Ü°¶:>m¸Z<ês'*w±ɲtæ â¬G”ý4ƒµè�enuÕ Ù>Ÿ½²·åe¼JXœÜ(>jqKZ”Ž.›;azËcxå� ÷¾go÷«³uWV@rw›µÍ·ý’*™XâBQOôØyWnÆã:îlºíñò¥O³‡˜¾�žƒÝ7Ùñ¤-xg¶÷úT%{Ó–O?Z<±wY?Ãg:5?2cÖV¢T¹v3_|iÕÀ>»s~o­@iÛØñVóùlfÁHLlY \Ë_n¹(ÏWˆÍ‚¼½†�I["˜åJ=Õ8•¢g¦ë•þpÅ}L˜õn½,>¸;€Z×YPp³”À#¸†[_ꊊcpìÙ:;÷·Ms)u]`[¦ ÀŽõg¨ùj(•/Ö¢‹ºÙ…ehÿ¢| ºÄ>eÍ«zÃBšãYÇe8(Òc^þH�²Wª²§mIlZN¿³MH»Æ½f¸¦[ž£¡C`sÆœžõXá“4MÊE�¹i->ÄD°ãÏSXø‡ñtLjÌwó¡�AÜ£³ê“ZJûèѻ͑ll‰îSècþŸ²ù)'Ö¡]9PñÊlVþD†>]1M1îw’ÍìyÇâ.†Ã`L'UOVߨCö¹â)nΑeçd¨wÚ *Ÿž„õ÷ÒôT5Væ?ÊžãLª õXœ–›0”„cV‘ª“*}si$¹i˜xQ…Vµ�¤q*‡Éaã?ö=5ž†W5±Ùi‹q ù-?­I&𵓷³ÅK8GÎŽÉZQEÈ ´5ùÃ8IKá¤}%l™Þ˜µûÃüÜËt¥®�Ý ?E•“¯Âã›Ý¤èkÌ,D~ÁLÁÂêå86h3Nxn jäÙ×ßà›`1�]�õ†Ë²'‰±ØôD_þšBúˬHöO6>hzÍÂÏÞdK>Ü`7'GP|ßDz­à¦~Oá¶„1è�ÔÀëuúl~L4{“~—Ìçî€~Í4–ÔfJ{†WƒAæTfX÷–gùÝÁ¯úm€yb”k±�ú­uèaýX«þœ}{ù*ûþ°¶Ž§|ÍnŒ´-‡±v©”¾¿ O�\ ³½èPŽ$Õž§ñÞ¾4 Ƀ¯PƒŒFXübÝ¿cèÖ–3¨}¹‚¥«åÓ³Œsìt~6œÈ¸B ×ÄpÉÿE’jx(Uœ“€„gÿΩtiweBÿ*´onÅÌç<—¼s{ZXʪ§  ¤f-ÿÙX>ûg�Ú¹hn¾ÉkßѦâÁ%œ’—ßê¶›Þ%ª¢Ýœ T=ºäãóXûã¿ ®‘Àüf™ÁZþ$‹¬=B3lûØDK14zäÎe§ü‡ºí*$›<—T#~°q·×0çÛKèþx)z•"Aý*ýlËŒ¼#AΦ±.ëƒLÿªþåC~'¢Äž5ÌÑ} T0Ó«gÍ_T]�Œo¦Ô!R¢w?€²ÞŒä�{Tp»4§Râ¡ 5£œeº¬§ ìØäU¶œ®};²´LŽD�ƒì±²2Ú«ÿ(¾¤HÇgŽ£YšüؕɳÉýV/¥9ÊVtåú: x–K}ï.²Ç–biG0MTCî¾·ù%µ;hÇzy4¾]‚³=NÓÌSEÌá‹)íh‡qiFOÂõí157êsBØwéÑ´æê ºÜ{–R‚žÁÞù^°âèqR¾ÕIq^h§šJ»²�)x›Úí`í²2ÞhÓD<îlˆ!oÙ~-sÌòÍ„�ÃpN¬¿œDJlRåaêÂ4Æ}‹Aù=ºüº¸)칚TIèØkà­¶ˆn88à):�yÞçØç UÜWïylŒî~n]8XßcJY…‹îzcBÎCx¼<�ÕÛyÁxƒÉ(;æ$>΢Á%A¤Ô4†Ý—:NÑcw’t‰‰P�,M×u‚pRÓS–A• øYžƒ‰³´„kÏ’ÎÓ2p«|spwqók8ɇšù�Õ�,›ëæ=OÿmT�™Cù湞԰â1õª²G#çÓ—§Ýðn·kûíÁÎ-S¢N¡¾×‚—§J!Wb=Ý9ÌÑÊîËlS`½;hE~=Ûpàg:{ùý"íL¼Ì¼}“Ù£~$ãxšêϡõNЬÀçï°p¦ ºtÄÓöß:ЗÙäÐø÷<´\M»Ò©hB ÈnŽÆ»:apß0^mÉâ69âà!MfߢHoÖÎàzybBs‘0ãñخƪ61÷«ù4½z+½ÙqÓÚì0¨Ô7™.Àâúã|ŠMÃà£IÖî„�Á f<:’ÞŠ_ÅR(4i,g§ø“�ÍvaXWiî{2OÕëÑÉsïðrípÈâ•Ì SO¢´±&fÖ’Á€"ìNNA½º@¦îy“–b~¡߯Pò]F(öÊ öVøC� ÏœâÀä¾4˜Ž:H*3ÞC›Ã(n¿t&Šn¨`ǦŠÐú¶Nšp±‹{~p·ÑdÍï>GÛeýéuQ5…‹†ñçþÜc¢ˆûÜãa¢O~noàµÀÎx#¾ôÊc.?¥0Aøž¯¸é ¯M³Ù��H]‚5»Œ@¤e.î< N‚«ýÌFU—ì- X¨@Ï=ƒMÏ‹¹¹¿ ™�Z?[b½�NܘEÅ-lL‚"æ^ý;岿ãùyZó½Ÿç¸Ã­u�h^¢½�ÛW Do—7°l'}Œ\â‹»Ýã�²¡¬<ïÇ_åjV?w¢ßûô¨hŒä† ¼èøŠkx¿F.%ÎÎÈw¢Õwpéæ|îàÎ_˜ôz1jj>f«­!wÅUl±XBѼ€8-ÃG§€rÝ]\ÿ>ž 7³¥Y±L7“£g·ÔpÙ’³ÔÔYDQAUè£ì÷O¾Ïbàž­lAîd&¦4i�-T9‹û’q±K(ú]™�þm¿ØÚÄfhnÔÄ¢ƒ’ø¶x‰êøã'B¥ª ôõSågWBžf><‡»žý,ªï"š4ˆ‚—؈°Cú^=K¾¥ÇGÂð´¬þí‡1¿½PDBÕ"0{e?ðó=T"÷Ƀì“j÷Õ1‚wÕ�HþZ”fÒ“Ô,GÞ ƒ� I&{9‡SgZ¿\d–¹g³/Ö­‘ÕL9,ÝŸB«×ör'‡8”ž8šß£¹D¡'i¸?…þiJ°Æ^+•ƒ!Æý<Ý;ð“Ÿõë(76l\)¿½×ûÙ�Û§À`xkÓÈ�¨u?xvã#k?ÇlW,¢ëùߘů°BZZàg¹†íA¼yÛ*Ö°ëŒ[y†&Oqd„Ï„ŸÂµðcx(xÈoÇÿ¢�Y¥«S^|›éÈ^Æg‡W¯9°ãÇV£�8vÆw>ÊÎðAá k:z[‘�ë½Ãø(1¬zoÆ^nË�}¡rTl0 BdtÙ彬âÄÌvŒ¦•a†¸Ì7“Öx$ƒr‹:íÏŠxr7WX£ùº—ÂöëŸ`ÌFq oµÃW ~˜oxšÞ(SåšKpâ‹®­5¢šÉvôn‹s3wÇb«kl¬L³Š˜O¡•‰hºhLÔÄv)þ¤?Цþ¼¯,bÁOaÛí ¬jð.'¬9‰òƒI¢u*ø�õÀ#î›â*˜ÞØÄê/æSIì9,Ý“�nd`K+ƽ€}Û,q…”¹Ì®ëôùŒ#Xo ;³ Ð�¨MÞ)>tÊ´šÙIÉ�Ù½Ñhvr<6®Ìã|fn�)�LÃ(§/Äv]:w0‡M˜¼›�{–ñoØÔªfPjN£²»¿ØÐƒ ì»ÿsþ�Âb–õÒ Ï‡è`ÄÜö5]‰‚R7áš·¢,¦%, ävFžÆti „¯5PÇ1‚ÖÿÇç_&£žÄ4<N79v¤_—m²®góã+ájÝhZ²ËŠodñ±Oa~Ðhœº»¢3×Pÿp5^gÃ{0Óÿ ïDNrïòÀõrA%¯|& \U² «Y"\ðë…þ2{Òo^Ì~z¡iÿXj Þ‹b«²½.æ,³Šº~¯Á9NÞ8·ó 3Ú|#Ãn1ïÌpص.îìn¬6¾qjĶë7@Ê:�M ¸k~tª"Í]p�MT/Dyíd(º‘üŸœ§ç±Øœé@Bç+t_/畤)_"©Ðl4>L6½ÝŸ÷u¥ŠØï~Y~ZòJ3»L,W‚ªÇߦ<§M0{ú ø˜@G>Zу³çIÓq®ÞÜÆ*Ç»™§Ž;Ñ£ŽÐÁ…ûùÝ~t>ã ;×þ�S/÷á{O¾a�ÒQèhgOûL:YòãaèÞÓek&ãÈÃ÷Ùý�J¬iIíËÒ¹çsW“øØÉ%Ú3cèØÏá4ä¼ö¬Ž]銴;}žH‚Dõb¿•OHÎÅÇðºÄ�² zqÛÝ˨¿aNÊs†'óŒÈn¸%'þw7H<‚E埸¼«ÈäÈY0JúaŽ‘8ØÉ‚ÆÈÐýY4{ú=°¿øâÓ%˜xåpx› sÃÄAt°Œ+Nùç£ìÐmÞì)÷¥äž)$ú¢š]]*K^¶±¸âTg¦àÊøbM’ǵþËyœGÅ»\³ÑMÜd2…îº\`Ån!é `LÔô’¥O¦ êÏÍ�k³‹ÆèáÇÁ+Ì?ô.”p¾4ã†(}}Êêxàóc©xÈè¯ðí:=Jô9G‹4çqøoŽŒo›Ë«(ˆ’�ÂSÎþƒ Ž\äÅš­¿°îo/ åÅ ”ý õ¿‡˜ïk[zQ*Nm“[¨T»þfayµÔ0^bç=Aé©°eØ+ö÷èèJ“#mÝ�\Qþ\§ñîý«æ“_=}¬‰éJZ¤ µ0“ÃWÞ´1Ü�¯ês¹çN°ïÎ'éï6i¬Þ,.¸V ¶Û—б›®äE¿1é�oÍ�»ör¥n>üÃûtìx$îYÍÛ»7�ݲ0Ìó§áúјŸ¯I}F¡ü×µ8Öî=t¬læ«lËY°¸oie�3ÉŠy7/yÜ\•Í‚¿´ãÀ©ßôõã \ðá'>Xˆ-LCc£ÛT?-ŸmÑÏcß.¯Äæ¾,z®ý-t%»H]¼Ógâr¿£ì¼w L}ô‚ú’éð÷dîïþ 6NAÈ Æ�Zy=~�üɸ¬²³DÖ‹Äy¡×Rî4)ì9ÜŸ¨N£eÏ£Š¨=ú+>àô¦ë³¡®“0Ìð kNÇ çñÑ´ÚœÑÎ=¬%oÉF®Ãû\· „1³þâ 0ç—ûÙÓá±xt¬º—=çõF&ÿ«p¸Z�êöÍøMâí÷0,±Ÿ‘߆öÒÏŽ$m\ÂJÝ:Xä™X²·ÇT–:±•‡4Ѽ3Ÿ,߇ӞôO ¹+v�7Ä(ÛÏìëŸÇ8°×—Ôã†Ñ»XšÛ’D-QûINÁÙlšÿLš÷å$:¿G㯧˜ùý°ÛÿÍ$Ã;…ø:~žq³„š@ º­Lxï"YY²¯-Ÿ¸èÈát桲à×µ“¤^ý€Mê æWO÷- P¿Ï�1ãPÜ<-‚˜*“¼8Óì›ôi*QT£çOþr땆a¦ÚSšo6ÍL#ƈ]¶Ëú§²O„í&óYî“*^Bì^W´"‹¼§×}ë—¤G‹nó ëº(ðª?Þ:n<§À2É>è.çd š·µÀ®¸›Ž �xÍ—LÔ™7„±ÎÅpÞ& ãæÏ@Q©·´9¦^OŒ£ sÈcw&†“ðúéQ,Tcí/dÈB ˆg“Öb¥Ã/Ö�¾=vãìãß›ND3~à>5=ýÄ>).C§Äe¸¶5’K]wŠ4´¤©úV=ˆiJ¡×�£yliµ¤ªAqtXº‰þü­ÁÁ—‹Iu·½k*ãòrC ”éÁåûxÃà&~àìç�EÊkÃӨдÝzסd¨fÉ¢¦J¤ÿ¾V®en6ñäÆï¡Æ[~èÓ- MË])µ4•U(Ñ÷íChê“È<ÆÌñw:ì]k/Êy (¨~ x�̤ ‹Ú™÷me¶é ’À?^-Ý ;þk€š¿'IºLœi&ã›Iè>'T³,h¾½.‰4¢èƒÖØO_'²á4Â2�^…¶‚ìóÌÀß'º< bÛxºs« ì7ƒaùóbéà')I�GMØl¹~زÓ�ÉØ€mZT¯ ‹OÅ»áœFS:܈�·œFñC'ðåùLrè6îq˜ÎÂu¢pwÂ)zu¹€EÏÙ€=‹8�ú,¦©‘L‹v,�#Ée$£}�­Zx†²†xÚ›•I¡Â0šn­Š¥ÿò-E¯HÄë‹hd;åQU_=\íêÀñ­¹LGp×U½¦ÁO)l›Ž6½­_ż›þÀ-…÷ sZH¡3W`‹üZаÅ-¢´O²�BwÎ*?�¸o®Ìóê ©îŠ£˜(?ˆ™ÚAŠÒr”úþn°�é�dlØSE\¤ÇæU,¢ïwåhÊ0CöKã+],샽¥,Æ#ƒ­·¼ÃÔ6Üš=¯œÞ×ìeÛõ¯ÁÐ’éPûÓßüXÏ,‹õéi´"^þÞÎýZQÁ„Uàß‹>pûÝs]œS6vƒI×<=îŸ1¦¤ÕËêNŸ#�ih‰þðùí9 >ÁlÆê�Ì)Aò*ªl^C�¡#ÉMä¼ ‚ÝÍǨ8@Šts¡ýí íºØÉ6�ûÈr‚óù?¨)o#Êì‰cÊ+×¢œ¡‹ÐÈ%ZËÚÐDÌKWú²_Ñ»Xƒ¿9+X±Å††zí súÈ"’îÒð qÔtI,µÂEak(púGîk¿Æ�üMöõ¹>pk‚S8ÁÑ×üÖQÉ|Q&kŸŒ›ªÿÀôwrXnuóŸl8S¤çFêßOÖS7PµëwnZœB‰U¶7U¦�€€ÖUxýÒwPõêà6•/D³ }ôùÆ9ê¨]Œ=’RÙ¥}Œýüw冿‹Ò¸ïóèAa(êŽÇgË*„—>JR²‹ *¹�§ƒ‡ÆÑÂÝ Z¿×2ckC|{à5ßåxˆ»%sÒö›‘õÍ´­Ë§gè W›û0™@û±Oµ¬M0Š~ÕŠÃõ�Úêi¶M÷Ùî,Ã)㔨ñÜj,êì‡ú’¨zû;�˜KØ}¶žîÜÏÔòÚéó&<œ÷œä=ÌAꃄàÀõ“Œÿd„^)3ÙyÑtæ²ðí]ö…/;\GëÆ1åe¬âßZ®¿HAk¿tœgy—Tz»hTš´zVY)ŽííÁ!ãMôPÁCL0 ^„ïõ’Ø·ô®,i*9ãwëYltr1¯%› ZÙÄŸ�äõ«ðçDE:u5 yÐGP¹hѲ�ž¯X‡±¼H‰—ö^òtƒÝ¾± G ›¡³|!gÎJóÅ;’Qy¼~ov¦ç×Pú' RÒUdþ[õ0F�g\c!×þr$š_ÈÃ1WÔpðõf¨÷ˆ.Õe³‚Üpn· .ùöÒÙìsê¼-·š"ŽsXü}?ˆ��¡·ì-*¸ñ.]�ȉ›p£o'–ŽCÏŽAöC£Û¼ëH«<¶®«>ÓomL½á(ʸO¤„AiêÍÙˆ±­OXÓ@8VZѬ¡4<íð���æAïp«¼4Ñúç|6Òà·l¤ GØY«ZÓTóÇ´gnLvSD'ÇR<7]‰¶gÄ2_´9y‹²6”’áÅzÆ0$MQ9­Ë��SK£u÷˜wä.8êd‡»/÷ÐV› PÔž…-½tk¹8«ó¼ÍñëÌÃ\2ÀæqL(•h­ÞŠî~ÆO&À¢u7`ÚsÒðÚ„älÁtû8œ¶‚Açÿß5Ò§)1x¸å ;Xr�­*æ0éî<œµ÷E|áf{q\SH2=R¼@O׉ ®«:Âòæx\Û%„uCê8*ò9KoªƒIJûÍgB!ëì†î“£ÐQBžÄ‚¤Kí!H’Æ. &–yßN|Š>â«qü®hÎd™fRÅßS½¨¨å:óÔMßoÛbÃ-}Q9ÈUÐ,`ÖH"ËYcÒLJ^lMKC/ÀŽW&¨©{ZvÞÇ ¥÷ØŸ¥ÿ• e~÷Ùp4º®MÚ-ÒøfÚi\‘ÍT;f³>aÞ-¹Œcrw ŠÔ0x;ú"µËOÀE™›ð{m8>?2•–fÇáã€TT½Š�À{%åCj'Òßp}*žmÞ3S”«Yu'ïÐg¯[(0¸ÖÑ¢…)LªTšÂΡP­õ´ðïCÊéšñÏ'–¡­ÖJŠW¬æ}ö-ƒÆÛÃiNfôOíƒãe„«·\€®hw8“‰½yC÷úÂÑ´¥ƒNñ­–ZTµÑ¬ ñüšƒ”²›êÇÏa/[S¡hÍtvÁ³œÉ©ÓPötX¢r‰’^Ãk“váÜ{’;fÉ7Úׇâ×øC[ÎIì?½›f¸]¡swÒö–nn¥Y.­÷ek OA> “¬Ðý�YItd!îü®?dU(|ÙòÈ>�§o^^QµÁž¿ŸaÕyÄOì3:U2áÔL_zèxEZÑ|¥å(u<“n®9B[ÊýIùÎ(Ñ‘¦´‡ôÀµÍ\]­‚^‘ÿéí� î?RQo»œàÜÕU¼kóBÏýÕx×ÀŒä‚åphÙIÖ”{‡|£ÇÀ•«¹LT¢Ž• 0E°'¾ZŒ�¬~ÁÝlž~—�ªEŸ¿Æ…ù®ô¡`õ‰´ãh ÞR¾F/nŽÁþ£_P&a9ÍNžN«jcõ~¬ëŸÉÞç+�þ/uÎè[(›V ŽÍ {À”9³s­a|²ô~Ö´·…ïK�¦Ù‹Øã‹é¨­?+Õ€ê[zæbEcVcPïXóŒyœþ 7¶`£DÉ>§Ó¬ôQ¤©æñ½Îr%Þ!ËÔ˜€åÝ&°ãp å‹ã�ÿl|»æ89¥ýË’¨PVæÍª’~¢ç“LìÔEé§+ÙåÞæ´Œ L �{±¨tî)ýw�²Çäro;žÁË?ðÆ» åŸ.@¥-ï`ýÞ:æ«~”Å.Î:F©bpÛU¦ðJ’æýµ†­&ÃÎÊKÙ’El‚ç[&–ñŒ)ã”®z ú+ãÐSj/fÈÔ›³YÆ�=S˜ãƒ=×F‚Þ¸hzd=Ài«íûÜ7`Ô*}­³`Û \¥Âp¿áVLʳg;tΓÔW-ªx>‡FK>�ÄØ›`/¯VòÓê;5Ô¤bè1:aô ìÇžÄIçÓèã¶•’ê�¹wŒ~¢ŽÖWjàXt9Eª“ »D÷ õ©,8›n}“ˆ-‰dÎýRæWJ„&aÀ…ñd(Õà ·áÏ:*¨+äì–ëÓ¸w÷ᆖíûø�ëÉ¢È-GXý:?XW7QÐx-´ø˜Î^fÏBPË8ÞW¤Ñ>« møg¦,+M²[aOT+ëÑÍÀÔígÑ©8‹ ®]–6O^â·1,þëÉÂZ‡àEËÏÌ®5¸ÄûÐþì7[õbæ9�ng®ÓÑ%ÉtkÉ+ ›+޵º‡Øùg!LÛ¡„ym®d)q÷É­­Ý“ Z ¦á¯¯çÍßÎ�Á„³’µ¿Ç@CÏ4{�ּ˹̅^JÄÐÕÌq�ýŒÅ†é—ˆ¿É`Á±â é‰OÿûBCu³¨º÷ |]J Óm¹ÝBޏd‚ ¨ÒÅÜecÉ/ä$ív×.ÙùÑ�>¨ÛÒ-ÏWøeØ+�sµ¦]`ÛÝFb®î–£gÌË'>Ü7ÄÈ­û©èÅJÊ´¤Ô3}�=é1k7?‹&‘/øž >tfâó�ó¥èñsÒÈg®§bçGeÁáQSÐû’ZN�%]~˜ú�·ü ÈÙsŠ…-x u÷ HnÍ0Á� ÔÅSvXÑëD¬¶ Á½iI˜èÞs÷ÒƒÈ0z#‹?�ˆYúÈ_síê*£Ñ¥(5�¥Uij×+ȹò ?ºè ‰ÚMãØOÜ´ZQ |L…ìÅ‚‹Õúú8�{~ŠdÖÛг'�¿•ŽK»¥)ìÕrºÒÍ6štÁ¶ñ~8Yç"¼?T#̇ƒf†ñÌÍh€ÉLº�¥CÃ(,á,†MÌuçÇ”E 1"y]x)Kæ]âð¸Î›f˜ƒYKÜY£½%šÈÐçæ\(ÿsòÏüe‘Aò4å [n+O{ßÇ¢Ñ~D“?Zå\zs•å»�dzÿ¢Tž š¢GKضþF>rø&0»”O¥µ�l¡aÈÆ4³9ùÞ$²�ïKâ½eïÀR�L: ƒömƒL¾Iéð{dŒñÖÉ+E ê“5ÃÖ¯™Nf–ï/g�B¼1Ù…Ôzz »-Ù§/Ã/uvç–¶=–ÇÿÿW~WŠ >ª‹z üù>Õgtk² •™LÇ�óN“nÍzÊõ{Æ)ææQËÒÑÐôž¹DÙáþ1ÿXç�ü–˃–9Ô1IE§èXÜ×÷óó ¢�ïEè�h$î¿GfÈá3^Nèfc¨_ ²IÁàõÌ{O£üv+McWÀðcMÄ•�ƯÿPZ¼•¹FDÝŽ\Gì]ù.´¡©£üðÛÁó ë�ŠWjþeqk!™Loa{´¬1z_ o½&•ÛóÿZ=gݛ棢¶‚ÀìÞ}fÙVÈf­×Ä�oД騭ô’Zö_ÀóºZX>93j“èØ˜V*t„»«cØÅû¼¨½ý®&4_g�jêhWø0Ú$WF‹“ò)èf è‹�­ Þ$r÷�Ò�§²]>,íÛ&šžáÂN&_3��©ãË#'bÃ�?Ð=Ö€¢bƒaÿÄ}hjôú^…ÝaŸYÝÎ@á'ÇU¼ûÔëÈÔýYr¾„ÕamÚx¢}À¼ª{+¥‰=Â+nY(+¢FßïäSÖ�@ ’TUI²¢: ^$ Ý=… ¹^(õl;¨ÅVîþ·ïÔȸxÅÅ©r#oØÇy¡˜j§X²*}½SÉ`dÞ°$«ÿrðöº,ÌØ†_ã/1sÝ f^:ƒnMÐEë�Õì^¥ ÑåF~�ü^ê Ž.þãÃo¹ N':»©¢A‰k”¼NÈ€Gu”t £YbêtÚ³‰îÎuÄÎr1Á«Îóìyéø;àfS:—ÿ¿ÄT¡äbG´2úŒélÛt1œpbÜÜÓ_ÊÎp>‰_Icc3-Ò$És·ÑW¹G=| 7jì—Ð/ÙíUNý Ãþõº ΫÉŠ§³í[GSù×ßLÙÅ�5ù‰í-ƒ õWŒ}‹Ä=q†Æòå¤5ø–Ýœ³?lÊ¥û[pòÕZ)Ê zç€ßÛ7ì“ôv\=W“Žm ‡¥ÊžìDaµ‡Mùš ãv¶³ÐÏôZM£®�ô[=‘"„ªøÙþ«åîê6Sl{{�椌ÄëÞÑ(j7�·sœ@ãÔdðÝ;7,V&ë ("vÓ¼H[ª‚­©”À}år%óUÄ…§§áì¹kñ}C,ö”º=¯"™¶;µ°ó¢!äs°”êmyØ3S�1�3üáYu%izúà“› (ÿMBð;%ªšÔÐôÇS¡ˆŒ1—0ð°õÄÀGy8+»˜ª^·±‚WcYJgª®‚/Ù·06;†÷3 �ÏÄž3m$~è2Hס-6±`wÅôìÁ:¡1DGàãÜ+8°[¼¾@ú:nT0x‡5ï1¡)=Ϙх#8~J^�ÅFºUÃöVofñ_º°þµÊ÷šÂ¬‡Nd]S„y¯[ÙuñäçQâ{× BüR�˜ÁþTnàûظð,‚è"4™ý‘|Êæ"­ `õÎÜV™ v±ó2Wlå§æd³ W_auv*»iV‡¯jìQ'qšwÐb‹Ó´ð€€ªÇ¢L59ü⟂õŒ±öMt\}FÆkú ÚVµD¾þ7ÌÒ|Î=›š„ÙOÃÉKk?þê¨F¥E/àj %«êš‹=ý(vw ÈÐ�×J빞"ã~lß±³¸]ltÚn…њׯSò¯ ÙÇáôþÎqvj` êWC϶¯ÜŸÏ¡˜¾Lœˆ‡`߇~¾dÏ+6sótJú|ƒÕ/¹f{è‡Òzö4Ï“„ I˜ç¹w6ã©]Òh¶±V8)²žIm�£Ã#R@ øœF(ýAó¼É%³¾ ¢ÿ¨ùhájE»½Á75Xñèºø�Â~YIZ9êu鬄0ØXv€&}ò§‚ûTogCÏÛDÁ/E„"Ǧ2¥ÅŸ™«Áu&¡VFÕÛ¿ƒŽÃnrPX…N½B ž j—Ú˜ºÏê óÆ)[åQ:!•¼~g�ÔòzÜr2‹N,Å+’»Ø4Åíæ‹ÞÁz ŒÆ+b¿‘æÇ¶Pý‰#´DZ™Þ¬_Èû8ÁŸw>tÇÛÕz13xµ¼±•s™ÇæuÌᣎɼ„ŸF]d9¥EL%_Mk „¾n ’È¿…¦íÊT\jÏ\0œžÌ£E©tq¯:Æ¿ÒgSÂîÑ\ó›œéæxäû/PQ$­ëc©(ü?g Fµ°÷¸4yn—¬ �£•x{MÍñ¡8å/4úAlñÔ$IÚòYQ–˜yí[v{ž\& ½ÜX6!(/nI¢­*¸£»_`ik mÙQ†ïjvàèil}ë:êýù˜Æ&o%õàó\ …Añ„…¸ßK„¶þÔ@9+MÔÑSÁâ)¨ ©{+zÈ”DÉarSõ1 ý2 \$Êäu)’$¢²ˆ7N½D/.¨CTC ê¼SL—Ÿ†‡~Õ‚ÊöõD,ý¨…Oa‹Y§A½¼-ËcÌYÑÏ$ø¯½ N¼x‡K¬`œÇ¬UÖ¡ÑBè•äÜôtÂçUȾó-;ï±ý]Eð§f'f «£P‚écn �ÝE�l)¬š8�úç^Â�6“éËT¦sz=÷Ò:‰šóßÁ«È(Ÿp ÂÓiL=íûφ&]¹D"ã¥ØýÈQT°½¥ –1ßwë(ï` î•[MÉW΂iWšÙ�nÛ ÷Œï#¶‡±†ªâ™L’�Uð¦×~ kl£š�çÙKÀ†çë˜kU'ïì­�6—rð’m;¤%ö¢F�&±–@4cLa&ñ°Þf›8}Q]Y�âäC=éôz/»vð§cšØf©—ðb”8Wîø‡¬SesÞÏ* á-¹QÒÚè~®5&)a`S6ƯçŸ|·¡hém¤ž‹ïKØ�ßÙlöÇ `ú@Nàlò¦¸éáÌÐTˆZëé­yàÔ„U]¬º¯ŽÝ¼¼vº¤âá"F?Òcñ>óå¦Y”ÓÔ;òìÚ¬d~¦;z½4¦÷QéäèüN4=E‡z}ë¼ðPÈFjœI‹¾½bo×õ±ÌÊÛxÄóÛt2�= ±Ç9‡WÓw5wÐÜ^†“ZçAÔä)dõi$jF�)ñ½XÀ9&²Žv#X²w L,¤mæÄ_}Ãì¥Éù¿glê†rf¸¯¾^z¤¯ofwÌŸRñ�1”³^Z`7,žM³ZFÊ3Áæ½/~ŸQÍ�]ñƒn –¡Xw+xîA+OpÙ8Š6B 4èJá© C:\¨@Õ†©8sC óâÔ¨TÚ›4Ä>³ê¨b¶ÉÑ”Ÿú”1á"ÜuÒ ã’ñÅã‘&BKÆÌ£ñnØi¶fÒHšñì kZÃ?¼½£Ï¤±)fÏÙ•Â,ºP•F£åf±®BL ù̲í^ ²Ïj”9õŒÔK™ÑþS¸È%[?в¡dqœZªNÏŽŠðKVÐÝš‹d8v-DÎúÎÎY¬¤ž"jû2‰²+NÒ¦ {,Û°…ž¯WÁÞ¿'©¹i>>«š‰yƒNlïË;8Ç8›ŸÁR1@q$Uÿÿ;r�Ú]Ö@æÍñ%3>£xò-LÔédQÎЈOi,¾ èò5Ü&�‡ wz±ÞniŒ<OŸ¯£ÈS(äA,-‰cßz‚¶i»3n ͼ»“Vß°£½%èH~ -úÄïyŠZè‘´.�¶6k 6¤c3‘Î\“0ßðû }/M{ño (cõ|¸gZý�u¿yÏÚ³¶âÓ%/àµë)Rsœµ�ͲN�Æ{qWX«~!sù=HcçVPƾª3jnù¦Có�&ðõ£Qëm.ßò�^ZCy?å–…¾LI�GxË’Ï+Së~•óÃKÃjÙœØ�`ú ;Ì™ÞP¿ÂŽ5L{¸:N™; ݸƒŒñ¢‚ Ÿ­Ðu  ;Ì#“85¦i/Q"&‹ëгyŸºë�Á ©ý—££‰ôj›už^�?JåéÃéë^£�HI¯ž÷-Ù@–¾0!.–$Æß¢ ‘’Gm¨w ~ó]Îx,`Ú��¬Ìp5¨×™M¿ÒŠ‹2Úi÷À,¬T:Š9±—Ð~Û(nÑŒ–-‚£TûX¢ëfò»¬TRîv™%>†WNçqÖä0Æó ˆ„ÇâÖ8öq’04ö žùCŸßˆRoòœ}àœÞ¤‡Fö¨»³—V]]†+ÍŽ³7 x£úŒ9hNþ ¥8™Ž«¨>M‰tkÝ)¼Jžn·Ê“ùâLzªæ ’¹Piœ‹±1¾ôþ÷Lü1옉?•]† IQ$”"‘Êyö:%•x %D¤’I©H2K†ÌSæ!dˆÏ^Ç)%%•JRšTòõý{¯µ÷}]›ws0k‹ÏÀÍ+Oè³]: kÂYÚýŠ®cŽ“@ikX(/ž­Ã›�óq$þ9y˜Ê%�� .u RÎ^§sש`ã"Qh7ŸMÇ,ÇjÞï¼@FzN„p'i-‰bÍ�m lC=ö)7E’«úA¸ä[#­OÄ‘� hKH¡Ï#gbƒ…3YoS‰Ë/�Q#§å”¨øq ¼ÿÐÏ:áäȳX¸‰`õkX%hK“5(h&ŠÚåðÕ(‹µË|GÞ´/àü2§eg@>a\ÔăµÇ èŒ/�R²¡³/^ÅÑó-ø©]œñ½‚—WÂá;Äza3M\ó÷w|&ËÆn⾉̬‚›�}œ?³pããVŸ ¿7,ÇŠ˜LhŠo…O3/à‡âãt]ˬÌX Í' h²’®&DÕ¯v$æ�Ûæç0ͽ™½f™s=f¡ÓÂwäÖ;uܦy ¼Ÿ|‡˜‡ä8'U’p�k<Ìiïbýãíß+ׂþ¥¹Œˆ`ºÐ7ÜÝøk&A2¿ªÅ#ÒJ3äJˆÞ%/˜Þñ7,™ª»þ°®Z1�«d˜†G܇ÙÝ Œè†óp­ßŽ<ÕXIØØ¹ð¢¥—t´ÅÀîeÅD×v7Æn˜Ce“s˜:Ï*ãSc„5êE/2B›êµ§áh]#™kéûf…¡¨l!«n÷˜4üíà8kÃãFä\ã0ì=.I×É‹¼¹0ÃZ�×´®ŽÞ»½–DÖ¹ õ5 85@TjŠðUÖs:=mbÿr¼¢ÔéçK˜¹³j�UÎæÆ?¢�ë ñ•†8–ÑMå�¨±ÍWrXcœ~*¢ËB¦pqw(yåýA—©»‰î’ðÝÅ&gÑó“‹Ù'STàûÐjqúÙ±°Êþ6‰ è ÛmçÐü/ïÉ¢èÿPlF{>9�Ф@#aɵŸZ¨Ä½J�¢3©¤63…Ìg¯x÷Â"öeACÙ?�öY •ãÀ”� ÌÚá‹á±ü ï�‰F¨½µ·U’Vr’�ÞçÉ2'<Éæ¸×Q�|œ=5a¿FÜàŸ�æ{Ï£ˆR­­žÍtÍÄ@Þ È˜c‘¦ë°¼+ ŒéIPÑŽÅ�‡åàô¹HfbÇ?À�_g®{šù…cBÉl ;dNUŽ-Ï?r¼ÙW:è=áxØ©r×—ÃÕ%7ÉdêZÌ>A,^30om>•åù_äubþÎ~yÞá„xh£U§Ú½Ï%Dz¥šþ¸éæóEééåŠxlØ›xÊ{aèÂû¬÷Ä}¢£À&J€FÏgtmeý|Gˆ(×Û¢çÜt7™®\-�§Ž˜àKÑfê=³€Xî-Ãc§×Ã†Æ 0¹J7\hcm|†+þ©PûU r> ÓHÍÛt‡•ûR¤Š¾§=Pi��ø‘Æ×mhöÝ�VˆqM=…È�C<²Ló3©[êË^ý³‰Îû�‡Ž–2»Äþà‰Xôø¸ xSö`qq;™y©YUH/¹�½סÌ<�Z ôÌÓ…þÉë0o©+y.ƒºÅ¡dh/»jC#”DËbVP só™ ¶Tÿ ŠÛP8õuÍõຸ<ì^[ˆ»zxŒ’…|°"g~\(Ø@7�¸-<ó4í ¸�]#º\Hþ O¢î%Ÿªwj@>Ñ aÇ>tã“~'Ò7l„1Æ/ñtFô�R§ËºoÝD·Ô¿$u×mÀ°'‡ybBÎp�}�áéæL¢8ª¢b ïû‹áÜÜÀ›Î‚—ùï™/�YðB¤9xöb ;è¶›Uá”SÒù‹¸?œ¬îN‡þé¾èH¤`4l.”¯wiY¶½ÛˆOÖÂÕ°àw"ÏÐeû³pÂv:5óPÆCí9p«m'¸î¾Ãù쮟» ÷ý}LŸK÷«kÂHFê ”Ó,©'ð*¢Ú§¢ò2QdýžÀ¼º ²;6ˆÔ¯O¿c† ³Û† PÿYœèì ÃÈ÷þ0ça7ÓäÌú\?Kk2†pC[6Æœ™�Ý+ì)”'“+VÓÙÝuDëûIj² €Î{ìG—¿LµFd°9í5FJ¾d厠Dg0?‰´ý¯?æÏ•BÓ °MˆsGî G«ßg/ „®æ8d:ÉaÅÙô±9.Kmï\äJ×öèÁIãç° ðÔà]ò'5Ú½,à×àFý‡.õS‡Ñ75¤÷š0VGÝÇ �[ æ«nYcö®¿ÍF\P¡ÅÓkŽèåãí·ÁLŒÑU,hŸ ÝxƒŒ:_!"|þd¸o¬šÌ¥¾íÏaŽÌu‡O’èº.Ôª�ƒG龨ô9ކ|œÊX¬üÀü ;Gß�­‚§bqûè|Ô²YBÕ»,ÐÎíôLáCÝâqrµO�ÌØó‚~õYÄÙç  ÞÐ~ú{ì<èžÛ†¹{M1ç0œÑÛöψÅZS ZÓ† g}À—û‹ŽÖX7ÚN´“ÎÃÛM˜è­æ³¾Ò˜Áß4ÿÅ­ò %UŽçu<œkFèøX D'tÈ @f»1;+Æð8Ê.]õžŒ»3  õ’Ö^~€1ßá¨ü6êj¼ mª-™WkkÇô¯L$»æÜ‰�;h‹o„|€/±…´ø]7¹¶ç¬Ík" Þ; XÝ„±ñ}ŒOíã¡«ÇEôÏ‚ëæé»OV B”«&n”Þ�³xô‹Ð5ró¼>ñ„ŠVKü9c%½0z™ÚG�‰ ê>ø‰ β§kàá`$\ìeþÓS¤[µ¤ÁBÜ7t¦‘æ7a(&�÷-ÏÀ» »Pº1–lv‡ã÷iKT<{ô‡ÔÈ7Ãzæ ñ¹C_�æÂ¬€`¬²±†�Ë«0)¶ƒnwG¾�rW Æa+¦°º‚Réc¹Jòéƒ ÙO ¨üþ?Ìþão©uÇå±ôeýh˜í?Š£ÏɦÈàŸ·šõ ^’ÂI4ví+jŸÌÒÿTdPqêtHp‘àòi®Â‚e0‘àB­—½ä¨'m„Ι»°:Á÷º˜béýh’2ëpo|'ÍþjœxÛhî(‹�s/ѩє”È!B¿?Óš’¨ÿæ&ÈÝèú%yJøfÊ¢Ú¹n²&ñFµWÔe Vx`W ¹ÒEìtc1WaäzO%úíÛè•%hs ü’–¡[ -±[¥®WRúÆ?N¦Û}ÍÈÊ’ýh¿^ÓšòñÆÆSiQIœvÁ‰'Ap懙x}€$/i&?%Ê(g¯)µ�ø„ª6�ðY%úkoãܾ\šø3„¾µÐc¼7x×]Lëm!¼a Óâ>ó Õ5ù`T}Ÿ•Ë‚ªÚ"<»á*$žÕ`ÌŽ-æ ðèRøjÇßzðÂÙ›ò3)6(â!ik”Ib¡å’2 UÌ`‡ôƒÀÕ²^Ð.Ò³_˜< Q“Ch°  ß÷O…VÏÝ ôúœ)Í%ž»“@£Œª´Ë`am$“ïÿƒÎ¹ *Ù^0¹ØÃâ6’[hƒ—”ÿÐEžS�S^ ˆ"}ï Z¼N`Ç9~ØûA ÛÞÖ,jˆÀ€îhUdËÖÝ[Œ?²´1Á1‰Ì—G©¹N »¶�L,aô'láuÙfªVØGÇ/Ѹq˜j‹¿¢�iR<ª„¯Âj l ¿EÊ]æÂIùÿH‹N NЛäÐÖ­$^"ZË­Hë”lºÿj,ž“ÌÃç�ø=~#t¼³„Τ¥Øÿ»–NzãQmb¾¦›:~ÑÁ݇VÑùBaðnfé_‡ç{0el Sp§†<¥1G—1›W¼cDFÏSyˆA•½k1ç€$·=â,†[{3w�œÁ×… wZÓ&¦‚gÃ~zÄ~¼—Σ!o?°—dÀã‹Uã)¨ªƒeŽ)¬@Ìü¬ @–öÑý÷ 81D ¢„ZÑPnŇ`Å9¤c‹�b¥»Žîu~Yp8ÜVsàô8 ÎòƒÐ�þ�­Ä…¯±Ó©W²ðÙÇ:ïPÚš¦éÙ¯`vÖ}Z!.Ê›ó¦78ÞF©ax¾J‚ˆŸ�Èø¼Aj�z©t~IÅuabh2 ŠqIš¼ówí™u¡ëÑ%!†È9ðó¾I ‚â`0|Ôà}’^Æ[X´¦5(Ó×'úi¬ÃJrÏ6²ºka6©(¼ûãþBÀùhöÓ§;®Æ��arÉÿ[ížÁòŠSàî¦*âº÷ô¡›eýpä~N @“%=üŸidzHxö-ŒügâKøµöÓ·bÓxþÒÆdÏ ¼e£­UeÁl�@4÷ÌÁ⌹˜d+Cª µé¼‡ó©è�4ÔÎ9Z"×oIËT°šþ ÔbÉCš³íªOo oz?‘oËçÃü¶ñDQ0c+Z˜Åë{SÆç—péÏ©sQñâlxUO‚Sâ`¡ü*`£/RÕ‹q$¥…˜iû/í—ðñG:YtþÔ¨Â-)К'͙᱈h߃´Ÿ×àÖûÏО‰±E9¯ÏlÚxu>8�Ô1¥Å‚è¥5QYÿÄ8«£ˆï ³Ðu#Ã{Q†"GGéÅ9ÈÕZMT¬Ëyȳ–\6p�ôuEŽ›òÕ–QUmk\’9›î6)!Ž9éØ?TQÕÇ¢>X«ÔMÞ¼»Oï ¤_TµèÍ,6u_>æè—ã‡�»áæ¾Ûø°­‹žÌO"–ٛȺŸ¥¸F.�ì3ŤÐœÿñ -êô«"Ÿþ$“SZ`s$êïÍ…ôÒÜÌíB°©d8HûàÀÀG¢kµNŽEçÆz¾Á äm5€—‡º¢äeÇ[ðdL©ÿS¼¶ð FxgÀæ#0¬•@ÁL±ZƒAÏ|aÔ±�Jÿç\Û”èi¿lö¬�F¶xbéä&ì<Í$¥®OãkÐÆ^ƹäíöýNŠiÆjŸÀß[¼±áú7òãk~—Žàä|à¦È’³_W“¨È4zÞŠÖ½>AM÷Ù)ÃP0½‹eáºD#M�ÌÜw— l¾ðoo]ôB‰o±DqÞOT%KˆŠÉ|sŒ‚3‡šÈ߃j8õy.4Ë.å–GD™»�Ì4õ: ¢\ «³°Ó»~H/…sš7éÇüûtoW0)\K•?£ØÊ2ð*—*ßéûñåôzè I·ÏûJ× ØÀ…Àøu­O�p4³…4ìT¦²º>Xû•ÁkµüèýHGÙ!Èô¡ë3©Q{F‰g¡‰¸É>�v‚;ý�*š–âéøÅøxÖkº%ט¤éaµKe^% öÅáÃ@‚:ªw‰at x¶&Ö‹ÓÕ5©0[E�~ˆç T¢ô¹Íë»·àÕeqnêJ?š)¹šžY��#ŸˆÎ›f$X�7&ò„WqðÖÁgjd._/;1_%oQ±ÊHòý^<–‹—MÕ0 Ñ}Á_Õ›ª×l¯‰ûñ;n…gJ)(Ñ{„>™« iÅ˨¬Îr´e<üð›Ù|s%|¾ÛN—‡’²›s!Ê¢ŒœZz…QŠ˜Þ÷½1z �3Ñf‘pλH—·ý€×Róy“é¢Ð/· D[†1ïY`ùÌò¦„ ¿›;¼þà‡Ãy²ÜÒÐd|O >Øé›;ñ\e¹êªIµä±qûüÂ/OMÍ"u)Av»�ò™Cy»Ú¨Ð�Å)”s×’ô ,‡âq_h>–«‡#›VX3[çÚ¤Ø`Ê�0xé4¯8ý ŽÞ0ð”aæ(ÀÅyîê >¬±Ýrب-�-g iX)Ñ­únÊì¶�ÂZKnÂ�ìñf«,îlI¥_n؃[ô4L5SÅØ?oí__ÈÆyûÑÇK�7™ G%6ÆÒı`Z…¸ø›œ*˃oq$¦¢§g=$Qÿxé@ç:Xl�H² ¢aAˆp�Êa±ÂìËTdž‡5 þ…8Z9cn‰Þ<~ü[çÆ$® LUTíü?„Ü›QOŠ% Í¥Tf'¹ø³�|{ŸÎYÛC¾¾m£>—ocÝ*uL΂7† Ð*ž<³TªoÝ3¿’†4k¼éˆ×¾]ƒs�,/ǪR.$ùG`Çeð»�ýÏ[.’Wk•°áG/‰j°€ˆAÙç1�Ët˜Ð¬j}ÝIªõÛþ±§ÿòºÄŒTsI^Û€ƒ>sþ:ß²†Þ³‡¼ ƒ¨ð¥ŒØm ©‡Ó‰]Ê ,ø¦Iª¶È‚Õï/D×;�n˜¡EÔûà £«ìïïsÇÏ¿TØ@-mW ê¾~ ßFnÁ¥Cÿögk­M7!6t æk†à~qøµ´�ª·ÅIwG°ÓWO˜‘¢øb—[ùœHU- vŸ¸,ëYI[ä ‘/òc�CäJæ®ÝŒ*’€®OÑháX^&‚<íiátÑASz!´ ×ø1'"ÈZ{KØ‘"|ËV�8i) 90ÍrÓ©ãîu(ã—ˆƒ:ÖÔ–;AsKNÁ'[ešC´P'}’§ï„+–О×FÔKpó½2˜žáG"U�3lj­€!dÈÀ¾ ­ÿ:Ô�™ÝAoëÙQ± ?8}ü8ªf¨ÒÌó´^4éQÂ3GÿÃ:«T’#H¾\� ö÷›¾ô � ׃ªC”ÜžœƒMŸÓ’˜…XVí ×Ê®à<Íé¼d;¾|8“]ò$ŒÜXN„Ï„£ÄJQN´xÔ?.>„ë¶ðqEâ®CÎÆ °=ç˜hC–Ý]`{ËjÊ–8ҟӚؕ üASp„ùåµ�W؃q\VÍ7m†TâéËí°du(®SÓ'Ù“ê(ž4�J9‡0qc4ÿJ)ùq#ŽìT}G¬”GY#ž\s¼ÈH÷øÁ§{÷ÈûRлö?ÜXù Žg’_{]qäñ9*¤)€^‚‰ðèÑu‚Ú­G@øá,”zþ›Üg]2ðMG ~SÙ aùÔuK|ü6â³”»”_}¼ÆŽœ€Yÿæ÷óðR;ðŒ­3IÁ§Ok~ž×º ò^E‚߆í˜îñ-dfÍ ãëá÷Ÿ«äñNQ\«‹ï7œÆÀSj´˜hXéá�Oè³ÔùØw`ˆ$ü‘ä^¿àMÞÞ‘ÃJÕ0<°~Õ:ÐHqð.Ú_W$‚š øÊÁücØ÷]Š ê¦+ð)ãÏûœ�÷à_&á á°wF;™8�÷3I¬ƒ³ˆ8"gŽxíEA¬à}–XNþ%r§s錮lâè1º®5чBF8ðUŸXÀ ÊÚƒ¾4é¸&¸S1á-œ¦°;ô¾ä|žœð%, !—K¦Ã€º^ã®Åº+~Ìš‰.ÆïP¬ÿ+F”/¿b/û¬õ� e…§¸hþȬÞCî÷`’˜#+ÊWcÕ™ÍÔqþMf«~ð‹€¹L }1àJí>탴›>¨ÆáçfvÜÃèþ\Z%ñÚ˜ =U–ˆR¿¼0ãV*Ü6þ×’ �׉·î̇ÈÞݰü]*.~ÑH&~~"†Wiß3O\{$…Î/íb­vØæ–2S—ð89ѲŸ eÄ·äÚÀ k:Öf…ƒÎ;vBUŒVÕo�¤ét¿ïTÚJlÛ·Ÿ^ùZB¤rGÉA÷/ y ‡µNh¥¯ôWâO^Ýu¦„´G…B¨Z"6UÃ/£2¸ž<ƒ}þ>…•ï˜ÄuegÁô§Ù¥y�ò—>¥¯Å¦RµÌ½pvø&»e¬·…3+‚1ký¯Ð„ýºÎ¢ü•p•ÄZœáþ�™“íB•îèÕ(?=‹£n®h"]�*I+ñþþ[¤S—Ÿâ‡T¾ƒtú;5Ø.“H–¬=�FòhUÅÄ­5x¢F˜$�i!qÞ6Ë*Ú.¾‰*»–‘¦­ èä9_í §ë]:HÑ�BwPÂða®õ;Èü1þ qä~š ko‘íò ž«p:Šnnfë¦:¡ô¹²p\š´þº…eÂ?Àán òýfg¶B‡Œ+¸zbÚÉ"4câ™À(gØÞÀü,›$Dñ)ì�ŒÀRNÔ¥½Àâ¿Û!þ�7SÈUÅ"ëÂêßò äðœlˆQNÃ8n,Fç#õX>�÷'ôZžòeÏhLÃóU°õ„(iÀªô1æ?~òØá;»Ñòé/þJMN7Úô�Šn1ç®»ÎÓboñ=Eí}÷I�y &¼S/ TIý 7>nÁT—“èo2I*¹ä¸ßðÜž¼mQ üÝ÷XÓ»-xÏhÎ6yI~²=¤BÇüÎõBÞSô_¶{ŽœÅ{ÛC Vt7��ÖàVs—CE«Íûº˜L;�=cÑnÞsÈÙ�?…�á·lÖ®3›,o%_Ï©bŽï]|em«tdñÑiœ;÷ùæUJÍ�уÝ4÷Ž8žyëy%é�ꨉnÚ;i¨lø Þ€;)»�ëK†ª^’øÍ„gna„ÓtA«ä„l³A=Ó%ÔÁõŸoëŠá,cYf‹ 9Öä¡Iç|îžàpèú9Iõ©/‰p¨‚].mäÇîDÌzÏðRö)âIa?ªºvqVÒÂÇ»J‰ïÌø¦u]4Ýеa./{ajg˜Á�ô çànIžc”ÙõS�—ÜÌœLëÁ+µÙdæ:Þ ÙïLu¿�ýt½«WQMã\ÜÝ9ƇzQRKŠÿJCìòmä€XÓ½?�VnÃ+aLêç~[è «|¦p-ç/Æ€ÇÅ0w¿ÞÿjI—ò‚ Ö?=c 5Q•J^Ncö”Â㘓Àû=�Tñ%’¿—lñ‡Í4Þ÷{ ôN›ÚJ¶‘ Z5n¯Qܯħ«„°>÷ßW%•¼<Q¼LÒ¿6ÒT�}P{a9Þ ââµãA«üŸ×…V»äÍ…96þs¤öÞ‹ù ~ÇžÕ1‹ýoʼ\žõwÊ�S[£ˆmÌj|¼›¢y¯•~ïCðþ<ØìŽÙ*-YOÂ^¿‚¥t¹ýfªåæ‡?&ú9�oGAÅœ Êdák›–­¥[éäíèœÅàjåPÌ—‹g^=Ââê`â¥#DöV(ðÔR"Ñ‚´áº”ùìï;Ýì‚Ï2¼^ý.ª²<”ÑñS©‰Ùú‚@ef~Ë] ¿çjÛb5[[8¤y_=9ŒÎ Øp:‡†×�Ìe%T?áN.›V&ŸñWîWjyî3> øÌ7ÿæð™ Ñá�BXüz&ož�Ø �r½'N&DÐŽ~>„ùÑзp/z“&ï¥o;ÖÇHûd°3ˆñmºýÏÓü!°‘Ã(„¡YÍiÔÐ%Ïò’ðä¹�LÚœé(¸™dªZ[Bq,c=<7ƱB´üâ[Ý»�›Y‹°èc �fEæë�|æXñ?îrºˆ·3Kÿ–£Xí´éœÅMè�õ àåæ?ئNž˜ØÁê˜(0þ�±ºbJ{ûÑä·xk Žs&¢°öúhêOôð/'gŒ£9Ÿg{@’A%S½gœœŸ‡ìÿ£Ëv=§66gPÂ6“xôÈBò‹kÈÝù�`ì"üùÇ÷¥ ¢|™×ôuZÈ@Â3c²jÉmxÜìIïÜ^‰Ã³á?YenÁéµ�Wzˆè:•à£ö­à&¯BþÿoÎ)È…œ£U$—:wϚ˘jºÔä󉤒'T]ÇjùŸÔ�WKx~+à²Ó4�HùN]·Åƒ^¯œÂ‹ÙT ëÿ¹ñ–Ã{‰rUg‰ÔkroP}2QJE€VyA´Ã[ŽbÒ²aò7Z�x]ÃîSJTúM .¸ÑDb^ë¬4ˆ÷£Ñîü¨þß|Ø·;:W©€GBZÇÁ»¬$úôÎSºËؽÇâ˜%µÛ±ëH*¼žbJû~]!�´tñëÄIˆÿº™^ï"�"—óöuÿË.·r åë¥ÅŠ+`s ?Ðg—HËp:/É‚½¿þeIøsòÌÁíÅw!íÞ…‘^r°Ãu! Ï4 Íßé�YôÐñ0ºHÖøëGQk‹ê'òH™¶;M”—úÇ â¤¨)Öªr¡s“*Š*c[nvר(M¯×jØî'Ê•X¯ÂÜ™‰ºrùDñ}?-YE_i^ƒ+oÐŒwW@[RΉ Þ“Øátœñص³C'˜áI5âmWÅðsÙ/Áp/y*ć @Ö>9%‹¿ˆâ5™l�æ›Åë÷¡þ_h@R(¾ëBû[É5s¼·b¤1)d…”4ˆ<£÷1½Y‚ÓÛI|�ÈÚ½f+®ÅÓ¤ {ðN]*ö9Œ’õwë8}OFÛèñ82íÊyXsf¸|gš²w§Ù³j\ îùj4`4¾ÐÀ¥¢Ü“#«°éÃ.Xqz žy s¤ Õöd|_ˆ‰¯‚SÖjÚWRL¸³\pûˆÚ×±}ñÙ¬„ö%bê;Ä´÷†½§IJ‘†å¼DmA‚Ç4»‰ò¥ã0äøï® °>mñ$8ð+I£ñCÂ<³û­¬@ën“ànv¿0©+ÿ@ºmÔ觪m }I ?ž%W¶e r¡ª.Õ†;'ÌÐ`…ý|â:™ÝEwt}'¡•_É;½â§× �"êlëãrÓ÷0Ü_®�Ù~ÙsËa†Ji½ÛKµdxG÷ q¥ýÂÀ8{1ÑL”Å÷~i$Wº d³ñ§x&u­�H£¥Ü^L&kï ‰eàÊJ èLicÚ<äÁ&ê,òmÔâÎÓwGõS˜XøŠ®«�Í«T ‚Æ"1´ºWJ‚b =î=|5>_*&àµÒ Ü8†ËY»`/XÖs�ú¿”£Köóq9çÐi�QPü/<ÛÞ./•á×ÁP‚7铺 ¬¹nœ"¿ßÆRã°$È)˜†ò¾ºpH€«†ñ‡Â~<Ø޽.ë@FZ’÷Ò÷¯IÜloê§ÑÄž{刷ÆN’A­f”uÔ*le¾„�Ô[•dÔ6O:bë¹� o0~¹ºÐ{%ØË9TgA"Æ¿‹aÎnò†è“¿Ù-ü ´ÓO‚<o"¦%á숽9Çr G˺!™oý1÷;j:¶Ò§ '°ë¹ ìPy„3oõ`£H7]¨–‡¢êÀùt¬_‘Ëg0ø5DꔂЫÅýO%2çBPvƒ?ªI@“ñ£ ¬—hö%`a— ï?®öæw·â*,�<Î06[ègívzNj &è8Á1ýAX3žTóa e“Ýía�Q Ô×,!]M3p]ËU8ÓN.vHbÑü °¶$ù=Ƙf)!Ôìž N6Wiu층ç0J;Í á`”~ž˜E{ƒVϪTóîn�Ío‘XS²ƒž�å)p„¸Ç~¿€™’ùXÅ÷‚Ý·óÝä0Ý 3 yÇF ë«Qoo­ý"‘Æ í¹‚ªAÅŒ±M(dõÆát1„mön`ò³·N­¤ÖãtoË7r¨¹:½Þ ´Á´È¨‡‘üôú©eœÐ¾@xPÖ@C~†+ÝOÈ<'5y» ¾¥r×st·œóÁúÌxºÛ»–^Óº�‹•0Y~„tkçqœ×ÐCqÌ¥‡è^Ë{Tgúf²_²ƒNʧ {BGC,ì,v@ÅÓ±¸û}îœak;|0¨�ť±wU>IÂjÇ0QcðÃìXÝnχ3ñP†3�u¨ W>p„Res"v"‘N&‘?í±ÔTí¶ßuÍ™spÙª�XiÒH3V‹Ã9æäîH Ýíƒ%*§áÑ‚[Jÿ¹ÖG0­Üy§´ñV¾f9+TxNA©øÌÊ‚éýR�¦† |Œ€yFÝt=·?¦ÀÄeß¡öÔAð^·­èÇó�ÿ@©V΂væT—ˆ’^ƒäˆ©œ7¹ê8¾&d/eN9ùt5éºuÖì™F2–ìAû„/Õ¾Zk@,./L9‹ŒÅ¥��äBÚSšG†ûâiå–D"ûHŸyòø7Q?ÿ–îlÆØw1p<àS{ËL ·ÀÕ¶Îrÿ|hïé†ØÙ¢�)šŠ©†ÿγd�Åd¹Ôqà‘Û䜒>is CžåpŠã‰ö?�aÙd" lËG]óÅpe_8©]ŒÐVŸ}Ù 3*â|Ñ“¸l î †á¢e�¨FÎ}ÔN@�x>^èÝ6"çšç‡NÕ º$Á™%)ÔŒ_ m2±¬.�f¶üe˜¶¸Ð¯…hL¿‚Ù›§aLÔ,tÌ«vcúìÉL`ß>"’Ów‚l°¾yDé¡ìÛ ÊU?YßbKˆÑf?ØèóœÄœ£wEƒVX9äT\‚¢Wºy3‡òWô�ã¨3 `TJçš¿åH8ß@·ÆxH·¹ ?ügÒ¨‡šØ•-Å›ÆÉ%rÒI´ôUr@OÛ@úì䞌Ã4¹¤}m˜þ—¼ÌÑ&·b¶Âó¿Á´ëñ8lШ þTò{4ë«Q¡²h}/ koLá�qDè/ÿIÖòÚ8I½½ÎΖf‡^w�æ‚TG-¸rÜ‹ÙmÐ6'n^Fæ´–¦ï¡Lð-zñÌvðîNÁú `ù>¦<)¬ëüÁlq)fØcÁĬí(v¶ý÷/\\¦Eà¥Å“p¾°#º<ê`].ü¦÷¦r×¶© zêRZ[L–K-ƒg¯k`ÎoKØÖ»†fßÿIã´Óé­”&úß¶zX}Ý|²x̾€k8¾§ó:8¹æª~x�ZM¹ggÔ2É�]à°3žŒžŸ š‘þ(ñóáû5‹u·î¥O7`ƒë~òè°æôAJo=3Ì:½Ü�µkÀiÛ¼wž ê›£×æRö÷µz¼ö VÈV Öò…°XŠ‹Çï$V¡‰ÔyõlòÄm*a6žçˆaûu~î¥á>`§!�k¶¡Ý99(õ¦|©v$- ßì1áœÐÛ»/ Âïö ¼z-ø ã'=ñ�Ð€ÛÆùF×§Kq—d0óŒŽãI§h¶ëˆê”b´ù7¬ëÁ¢¼ÔŠ^òÓ²ÙÕ&Ö –‚õÛL„M†9¬ÆXÁø·$5.>ñkU`¥5ƒ;öõ }í•ÏYtz#‘7U@�ëàf™‚ë\B@UÎxÙŠ¸J÷I»I>]>N�þîFÙÄ-Pù�À »Ø:K”ÙбN„ü¡w®òãíÀzÆE|7u¢EäõªPPí gÅõàË+4ºú‘<È|N“¼&¨/ŽŽ¹Ér=öD°Yentž–kz' š–äRùE+`8¿ˆmÎxÉ2]¸äÏ[Ý×§3ÀΩš˜é˜�…Ó«±Û¹OÎ^ù|+á¨è^äúqpÝuœæeB”®<³[í¦j™E¡ Á¤#ߨã=U´^IíN=Â-$“\¬¤‡;_ÑK–mäúÏ8ö¿fWX”Ћ¡Iáãç ¸{”vÓéæ¾ô]?3œËòsœù$fÕç3bžßèÔ=¼Et±ä~´El�˜ AVĵ‚1UQ�úKj;XL,Ì5ñðª•ìåóÛ±ßc*<>9ÁfÏpCÉgG1SÁ�ÄÙ‘ûÑíHd1þ••8¸ô ,MFÛj=Ø(ï�ë^��‡}!Mî9uU=ËXðÛcd0α–N2»1bÖ%º'¡Ä¾»tܬƒ1X�DXCA¢¸Ûç×}çÌpÉežß-¢£F×ðÍyI,»M´´XlÝ•ƒ¿�ÅÓ¶þ¯ŒUæjP{û Êú•xB¶ÕUák í¶9t�Fç¯mœúÍõä²£ lÔë�ÚuƒôjW,«—÷‰µºn‡2'Ühå½AìíúA/„‘¢7 ¼;ÕŠmaß±Ù<éù¼MïN3×Bâ é÷¿7¼^_î @Ñ=Ÿhç®)mû�åv¸À¡¢;Dv6z./@kíyo3Y×û{8ÌlœsxǪ@x¤u>:‚Ö–øhêjÎÁ¸Æ*k' »fAúˆÊgpÔ+6©wG%…#Œú¬üsô&ìý\GÎöKñ¶D½%³a·\ÞÒNį2<5A€Gƒip�f’ãºÊ„n˜Å›ºo>·ä¸04ľÃòbIT=Ny;<€#Û@^}›ÆÝð •ÌüQFó ºØÚO•hżc¼4¨èÁ zcí¬ÉW¥!ýßéìË}¤ÌÌ *šÔqç~ÜÊ’h«yìãqô]�O»~M“ª+ä�±(¯„]†K.ÁœÝ×ahq6¾�ßE�î3ÜÞWÚä�µ*²CÁèq8”^Ï eûŒ§ó¬åƒñNÂöÍ÷é�½2¶øNá ¦W‹bg‚Íe þ/ˆ†Ì:tÖ7<ÛM§´Æã®»™èîv h)q×rB•Ç{I{þ:ˆË:½§…á^¶œ¹VÒÎpLû$jU+ÐÜ9ï6Ÿ¶uCš3�4ÕXàˆƒ8dZFÁÔšè·µ>4‡P—-¿Ñmຟ¸‰[çíAÍÓ;`È"|CnÀaë8ZM·8yy#HN|"‘Ž¥¤i¾<¯mתäÿš¶I)3%w]�8 ^°q³xÛ2Iw˜0ze¹�ã1…œzÉ.@ßw5hÐZ‡=²£ŒÝÙ�øvÍ’jk‡m}‚´WVBSøðä¿A$†´3Ñ‚OéÚOêTÄïµs1ÀÔÁÓ(”¯�K_Nå^Üz‹Úo8As"•áÞ [:z>´xpIfEþ¢¥Ö?ÈÑÁ!ä/Âã „]é¿¥A�ÿ)x�àÇkG8¼ "Wà‹¬É_w�+–áo˻Զ(ßò Òú¦F�‰“ß�på¿Î´¥g•߀ƒ™q³J#+Sdࡵ9=È![;bdŠ_u¼Ñ.ÈOwics¾l“ ÷zßÑã9 &…6‹aß‚] ·¥‹¡†ôOG-)={§ßà¬xäL·»-ãžÏ[Î[u²Ëg†°SR5#®¢¼–0±¤‘M~k�—ôxt•ÀØÍ¼®z�v'ç¶ÑÏéÆ ³=–n‚ç—¢á©ël^ìÂj%ì‚ÝæS±0Y€·7ÅŒš�yEvíY‰ñÅyHžÐ=Ž…8d$Œ)+šÉ©¿å èåLöU.‡æôÜö©/á�gí3G5¥6j–ŠŠ{Pk_¼œÍÇÝ*¹µ<5Ù-jxçï(ç¯W5³-÷ ÊM´ÜŽ`¢ÞsêŸë Å%Šs烷©Á®€P|±Dˆçàó Û,] ±RŒûûÝ!ºjkx(·�õ”h¶``¼¹ó…ÊýÁ¥E 0`—3©é¡³¶Û ×î™uo3èºÿaßLó"Å>?á܈=U#ƒC«1^þ l6ö¡Ï ù m‰4D½¬‡Â÷Sé{_ð’ûMtêÜÀ}×sí+À�òhòuøR öö’Ÿ4õ™;(.ZÀ]òQ†4ô½$¶ ‚°Ä\ ›3¹ÓmpÓ„ÔÞØWïMá5ï¤â‡‹ ¯Jš×=z œÔ%ʯAn|=Öl–Ý77!âã Yè‚^l1¹èüD×Z £ÅYÚÚd ÝÇ ië•å$Ï´²¼E¸�3Õá¿{6t™ÓRÞþòzÔØ]C"\r‡óãÁ�®¦ò*ßp~¹¹¿–‡“ s ,TŸ>¹)�Õù8W«Á0õÛ}‘TŸT"V }h_…�ŸKÎ Ã@�F�á…æf®ˆ¦�°…äÐ~æ°úMx0¤ù£©£é Ü©œ€á¹C`ïC?«Èáö)@ÞÆdâ�Ò“ôÙô-ÔÆdMvÿëùCðÇ| 7bµìÕwÀ�{/cțټx›3²Á 2qÚ¼6rîhV×逾½WL_ˆ¢¯Þ_@ËcƒWn¢Ræ<È< {'ƒè’tu²;™ù+|Zˆ÷?ÿ�5¬ øïÇýæTYÔâ­JDmJ0J9™p¾…—“FCaÒt{?:˜‰=Wwá‚ÍìÂÑù4ý]"sýÛ\¾à.-/RÄß%¿'ÑA&ïÆo&êâsSûýÀÖ“Ü KùDQk–-9õ/?}Š"¡VÛV¬T¿0[.ÄÕ›äx³¾�ÃÕ¬³e?lëư )Û(UfÎ,ðPЄ´š9DÑE„'ìÌœ!cI89£5�ûãÑ øü2Ÿ4‰Æ)øÞ�7n®aãéÁS^4¾P7ÛdÒ¹™È}¡T8Rº �>˜Îû"u–³“›6/`âÝ8· ~�üŒ&�è’F•Ý1½£Ô)W ’nÓëÅðméP¿²8ö_éÜ/}02v{ôÀV>ìžyQp`ñ^ªQý­¯/ä=:òªŸî`Öÿš ïfð\ ¬™©þtõ]73ÜŽM‹S1�j›B¡]OˆrÍQ˜åOùSíZÔ+þΈÿçÞ‹¹mÁéæ#‘øõ¢*wûÌVTNM ÊÃÙh³‰^÷|/Xëï±8eanºMž3ÜØr;0æE‘êãhç¿„á)xÂLç©Ü­‹t ÓvÖeóCt?¯Çî+#>ÜŠÍÓwÒ×Õß@"¶J „IG­Þ¶FNä+Ï&«ÏØãb¿vò6¥ˆÚ,?g!^®>?� {C>íDÿO‚èåJº¾—Á`òwÒþc±w$ ŸŠ¨×™µ¨ûK‹n– �š‡yÔ5&65€Å&õ¤…ø)&Ñ}qcŒ¸ÌTndV䇿¥:�®Œß§@ì“}IÂy¿ÉÏ1!®h|-&,zJßyDÃŽ&|·Çæ'M€a•ùô IbCuâa"ñ)ùï Gr¼IÖ€?NmËdÆå#¡²ô™|sB×åñ-ž= À»e“DjÄ Ÿ³ }å|½Cpó¶©¼=Wóhþ3Hª˜Æåz@bfv“… Ôõ2Þ>‚NÔ4fÅ© à4u: \!Œ¯Kï�…�ä�º(4øÁ}{i®ñŽ;5É›Dè†4Kw,Œ®pÛ†óš m¾}wd$¯U¡·MýQgRÏù÷ýëùË´Èz=&…:›õ‘(„�cE<ܹV„'}Æ”E2ÐUý>\&G¶)P‘Iã]X$¹��çÌ•cøY­›Tí¼Áô‹póÔnR�¨e<³ ¶mzXÿ×RuŽÐ±ûâX´Nˆˆª¬Ãø]-t¯y.Q— Àýÿ]¹é®Ô ÇÔ)ÐÔ~OöÙG ®ý¥B\ãÜHL#§aÜÅ.ú¬g3 q^‹�¦Ïq[€"�·ÿù[%Ч¶`eÐw^Äùlk—ÛŠ]óǨ߰³>^ �¬^’½Ÿ>Q=‡,rÉT¹Æi4—›”bè«;¸úÄ]PLSAŒC±Õ½e+éìÕZøe£¾qãr!<Ö+MŽèwcÉ‹+h•}ݳ�!ÎHœ Ö}A�9•��$‡Ký¾ÓàÐÙ5:w§qG¼DàÓµ�PîhF¨M3^ýzú>žF¥#‚`Ð(„·ÚS0þÑT_Š‘ñ›piUظLÕɱÎTZç}ðÈÚ@5 !it¶fxǶ�¢O:Ü%~µÔy¨Š Ó›h6nнùCh·*¼ÏC³�·á™Ü5lâIBôÅ "x ÔKâIö%~ ŒHº3‘ý8e- �B¡RkædÄjŒ{å�Yݰ|çsz×´ Ï¿:€9]�(–t³ýSa[¥¸‡x‚ÝûBšêx‘^õJ j;'uϯO&ç8aÚ ºõoüBAœ2+Ödêá‘òfL(_À8ž®¥ ûT‰÷ôÇdx�¼ øZB4n«âÌ?µdRº‚=ªY�çü±%©�=œâIŒj.“ÂÎ5cZCfæÊòò þÒ¥a‘p&NçŒLã>T\Œ�eæèôÍùÁžñVÖ#ÈÏÿcâwëOƒ³C/u\´,÷¶P·!²Ò§Ëå\Ù‰‘äDÞFê5ÉÇ[s+ÇÒú©É´@Hvh£�:÷‘š#ôÂY ²Z}#Æû„ã£Æºê '(CÉâ÷ÄõÍG\mìIdÂ0S{’LÔ‰àÔÀþ¦p|ZïD6ì[�]I¦xëd*97<ÊüUãC¥m—Û@á Å)5ÿ¡‡m$6´põj²ëZ:Ñ* ¥ßÌ*qO8#:I¯HûB¿Ø3šÞ}ßGݧ_b*hùãs$«°~ ðØ—SAcº6—XÂàwš³îœ®ÅÛ[dÚ,+x]¶»cMÑY ”z<íÇ™~ÿ:ÇÃ�xB w,E!­^¦ôch=ІΊëTl´‰vÎÕ¦7û�ÖÀuéÐtT ÷�ŒÑ›[Úá“§=<«Ù ¦•ÖœS|ZP²ëÓÄ®þÃåá�e†a{df+›Ì( ṯ·¡¡DCŠT*m}I²w”•�M4e>÷õZ‘¤¤EIEF%%Òøúîßï¾Îó<2÷é3ü²ØÄÞ ßàmWŸOe'þíZÂn—QæîMºOª#©ŒñkS/ z?ýxö7�6Oœ67¢´µøH§² 7²�LW——E$&> y (sô†o^ 5a—Àúš#³¨ ƒZÙ)ᆆû°nm¬P dpó°=ïJ­ Ûü• ŒÊW¼ð•¤Áão$‰¶‘*(f5ÓY¤óØÝ¡˜|"Ûþcü‰":º1*ZŸÓËO«aE(wíšiœÌqŽB­3þ´W÷þw£GeÍðõC¸cœ=ß×FìÍý©æé}8Oy;ø7fì^BtŵÑ%e„ö-Ã>Ǹõ6WM8 ÐP[ì—AÓf5“`Œa%} ‹æÕt¾IÂ�> pïW;F?ôYÿî.,8¹¢ûj¨°b¾Ù”X#öüŸ»¹E¾Î0 ÍBHÙúY\­3EÖmF!¨|á”]#� DZaÖ3úe*¼¼@4䉵®¦f0ƒ|W@ZX^%ây÷ 9ü×_·û3Œb"q}hMôšIhË;ˆñl†ØüŸT(â �ŸËY;ÿH¹^¡ö§2èüíì?nýgCŽ’S‚°n~¤¾¿LÒ#-èwÙ^ª[ÄüàŸm_[±êÈI¬÷”ÇMÏNC´ÌKÐÍ[Oó²1öˆ4Óm‡ V­öyp­8³fÈg!Î7u#7lÒ?:íTML¶¹›á°ÑVöpl ë$ÂÕÇQøí+"'cÊ–ÅcPýºGhÊòÔaÑI[2C1�¸þâ>�6ÅŒÐUd¼fŠ– ¶’ñ]" Ÿ©³7þ iA)ÐÙy�>Ù¹Ž>\BËzRÉïwaÄãÅ"Î9F�º,6…Ÿ/ÈÀ±·»ÇüÒ±Äé0-û*9»’Çëpò¿ûÄG¹›Êù‹ÓU„"Íì-{u<åQJL¿xBÕþ?tÙ þ¼½�lsÿƒ·m;áKeŽ,àBžÝ\zdf#¤ÿJÞä;Ásý"*þ¾R'Ѥ]¬þ�H¶à…²ŒÜü–’³^>ôÝ‘ï5JŠt­ó|ùú>ý¨û œ®ès�ïyz6ÉÇBÀ¿ÓæÈ<#Úí¨ÓŸn¡’Ô²=N?õ€˜€Üúà>(¬ +wt’Ú‰^Ò`rïuï¢kW“óÙÖ¤�ÇŸ›¤�üž`¸=`€f sáÍ’³5Wþ™ÔñHüäv ‡W�BG#Ü3à…?:—b—ÐR4ؘMõ®Þ‡þ?ié,]ÎÛ¿€œ{»¡üGTÌ] %gÀPÔÃ_ ååæ­GPØŸEhæYèÍ] &Çñ•è›sO¾™v-óÁÈ1ÈÀ=äï( ³8A&:0«^yx [ê¿ þ�%ÓdRGôÇ5!9ׂz¼H�Æ¿ú¬È3ô0¨F#+\·ÿíì×dµ¾Õ‘?‘êÄ dL÷ò¡ü±iŠß»JÔ´Ñë5:¨~z® *¡isʘT==(à?G�Úðщ½°øC>.|¤’Ž__³”ò]#*ŸºX]~m²:&¹FÒ˜¹f �Å>¦•m/j$3h¹Ž/Ê4i˜¨q¿ÚCfD'S‡îYð±±_9ÞÆïÑx¶ø#Ñž’†}ÊÑttƒn?Y÷A[4jÈwÝDVÙÖ˜øZyMýPzàqÊ©ìôD êµ»¾uh�ྠ&£GFì‡Õ¯§¡UDl³Æý-~y`„Ê?$ £?gëÈáø‡+h3ÛEŸfÅŽ\# zÂL£íú=#hp±¢x=�,x@Z³Éþò°ë¼þ˜>JO‘dǬR6ÄéÒkñ¥¬8ÈoÆ¡Ç+aw–>Fr�ðçúlŒ˜ûƒ¶ö €¾Ì>ØqŠ8ô׳;Mu‰yI'þ×åûq°çŠëÁ¯%kú·< «ÿ|" …Õ0•j%oiׯxzóa2�æ2“ì]öˆÈÏ�Ç]ú•Ä.6‚„0?´k•ƒMqy¸S}œD;Í!º¾)øu«Õȇ¼ï*ÿísvÞ”nûxy;‡ £ðÃucP\”F"ƒàÚÄÁ*$‡¾¥2[º »¬œ°NH™XÄ”ç§�Xð÷�õçÄV²£\ù�Qg*ÕšOSÊš@Ì]U湃»Ìàž}ÒEÄö0{Ãiì_Ø÷ñѧÍ`?êõ ŸÙi°½‰ž³ µ›Áòƒs0ä•-®±ãªLÐYÍ�ȶº ¸æ?ìßFa§̶Eé”ÿhxýj|ñ øÄ±øìI_VÆÜùð•ÓðâWDß(ˆfTÌDß§ \úŠ*¼ª‡ýõYìeW^Þ‰�Þð¨ŸDèĆ/æè³CWBÂrW¨:x…|’�jÿºañÉÛä“d <>Omg‘w~,,;~‡^òð†%o•8¼‚If¹)¦ËÛ~ÎÔ•èIÃs]òã}*Î68")�¸lQ1ØkÄÛZIز¹ ãû`\ø ܶäN˜l‡ th('otfí4Ѓð¶vÞà»:“åÙw ¯È_!KžÜÃ]W‰ÌçŸôÕÉ Òï®Í$� àó2…Oùþ¹I—]¡3È ËK]™d8Xû5æ£éT2YÙþ‹Ôv@o|Dj½¥9‰[yð^Ñu4ÖHÂ੎Æú=»A‹,c¡ñV8©ÝÁ3k‘ÉÔ Ô}ž/Yã`N6ôùôµi§€�¾ÉCøÞPø’G[Z¼Ñ·0#�Ü`àðoád ·6Âõ‰d3ë¥gDÓ˜†—Dèy9z—ÛÓrý·4â˜4½§‡d}™ Xœåcžl`öX=¢êǽhÆ·~ÒÖmÇÄÍáÌUë¦!ßbØ•­Gð»µ0'æÎk¢6œŠ~IiТýž<œŠï¾§ ¤ig¬pÿÚûXfk†§“Àÿ;·³üÇ–f¸úý4ºÁÄÈ4Q—r%¼±–þ׎+º~nSe lÏ—‚F³Xºën.9Ò¦„ÓJü�ïã–i+‚œÚ öÀahÄï4ãàUú^}Œ~Ž[@j ó±3»†¤œþE}r ñî¬M„#©K0Î7„ÚUY·?7ÁÁØQP‘áÁbûê³à8¾î6&ד�™4ôRTß<æÂìf‘ [“‡×%] ôþ,ñÚHÿ2É[â0g>›Ñï3ìq¿Í7ú²â:,ý:2Ë^Ý!7ЕÁ�ÖœOæs´Vã‚V%ÀUlþM‘§ÇJáþ÷(¢¸$ ¯Ý$ŽU¾èRwL´]ÀÄl:úQGzÑ·Ž¯&ž�ß¡ÿÂAôÙŒ+žÎ ¢šÓàkeÏ9Cƒ¶…1�…M6­ 6bA]<#T·_ ì"×Ràpb$dº2÷?’8ÞkôfÒ&ÿáó‘Ϭ¥ëShùƒTb;N9'ƒÍÝ7Ìõ¶ù0»Ã;¢`jÑ\Øñoc®ƒ´ÿ3*1q›f(…Q¾‘fêá�\àŒ±xà¾ò¼Jx�ÎÇY̓$Ø!ß%�¤v»§È¹u‚D÷M ØÞ˜Õ45p’÷és­äÎâœÈ‘\ˆ¨~OÌ,…Y»Èc)ز>�Ù~]Â臔ø½¦ßV—"p ×;ª�zš-|LЇ¯ÑÝ�T{q Þ³/Á²v%è`ÌÐ:Ì SžÐ)KñS—Ø™“ á67¹bÜ¢,xÄ™À4™Žš@#’�¥qÚ»pkû+Ú§skã l^T¢ÄÔ[º¯ó]¸)—ÿ¤¦rÐÈ8“S¡5GÅQª¥ ÌŒ¢{V³ßçÚ€ËÓß$'?Òþ…;QUôï4è›ÝJ¾ÿ·—¹%áäÏ0ü<¾œHš ÁŠ»óñý©T5�"ÿ à‹u�Ôò9?±6¤ïÜóPj0†h\ÿçMWéÏxùót¸®�)Àt´ã&9X½o:¶¤�ß§âa ^�Èò cž±tb—.¬ykqÛ p?jâ×§a zS‘./G�9÷ jä .˜7 ?<ž„†½ØaK½Žî”±gp:qÔÆfZ#ìë°Ã—n½€“t]¡"GîÚ#Ú5ç'æãd�dÓç'ôÔ•w4õ‰îà¶ÑÓâ1Ôä?OÐ ?ŠJ­‡È‘èdqž8×låbÒ8bDô¤?Ñ7³�™{ÑC3GÐiéIú‡Æ¡ÍGñÍBÔ*Y€í׬¨�éBÎÍͨ$¢‰–oŠ€gµÑ-_®ô6ùYèŠö67h£Â=ú®±�ºßNÂͼs 'æ ¶=Û�·fO‘9â?~7‚üEñdÖ.ÅÊ•AÃÜ«0žXbà %ŸSPNr»t«PMœè% -XÜù�Kcà™—8T=Œ"A‰«AF)V†«AK†þÖo Õnªø‚cP³¯õ4øÞªQ5$ÚŸÙ;=·Iþº~²wžþé‰3ñL<‘cFBÇB°£n1l͇"7!Vá3/z§S²fËWÂê/c°ï¿x™Q]vÆx~¯g\d”9vÓˆhÎ)ý{+–~)¿>èÎe¾Ütd¬óƒEyu€i™<óÃ5#U»`bã &õÆrðˆÖB¯ì[¤ˆñ»:èº5B°uÿ™ì.�Ãë–ÁöuÁd¶Ü}ð‰ÇC¼ k<éï—aÒc1鞀…¥n` t¶‡„á#ÅNˆ­VÁ½2äÑŽ<^HEO_†óF+`ÓL+¼iºå“õÀÊÙ�h$áî¨aÊJeÃy‘'p['V݆R#rZ«CÊþ1Óø%<øûߦD9’¶àÙ°é)‹¿,‚ 'd陿z&Üäù5§ UíNàÝÐÅT˜»€Øo-…/f¿˜ÏûÛ°BÜä˜÷èn»c%~‘¾Ñïhàt�UQ6‡³ûÂ2»:²¯� LÅæéåN6*Ó›¸;áȈ7O&’™žýšž«¤wZu¡a$}Âl eŠCþ[ÏTï‘£Uh5¯�äu\ÁãÒúx@J§[síˆ=ŽwKsòfxÚ4”8Ñ&&š–|SçÀ5U’ΧÅÔÍûIïÄ>¦þaal£± Ò `™—5ñ•žƒ úËÚÀ…JpñÍ/²{ÁM _J¡_W�”<Ú ÝméxXì'ÞèÆ°§2àwª– ¸†ÖHzµ’\ÿ1:WDòfKrg¶ùSÂ`yš—£±� ßÅ ºCw–¼T±±œ­„äö¿÷þãOÏm¿ˆ°² îšÖNäŸSÎNð¸¨DüÔo3J¼)Ø2e‚{–¢œ‹-->«€ON{3®ÿØöWy+Xû„`s6]:”Fÿj†A•ø{VBó YV|º¤æãr‘vP›7 õ5QãK½ŒP{5•Ù £ó éìQ�zÿЦ•Ë�]¯WÊu:»sƒn�ô`‚aíÜDz,µ†ZÑ’ªÇÉÊ­ÄóÔfV­b%üñXÓÆ…0}ý·5‚ ƒRÐ2½ Ö¶B°öb>†—£ó�1’²¸‰ìlá‡Èýk  r>hZ/ÀɶxpQéeÝJÔ±¬¿Š&,ZN ²­°%Éö_ŸÁ›`à¨Ù0;¹ã*õù£‡d-›Ž_w€ìä32ÿ$†¤ p£¦.‘hY8¿ö:ž;¨‡#ÏàÝÕŽ¤AØ ¾º„m#†Ü?¸Þ¿X„Wm˜W.ïÉÆRÙNU›‰Ô4Ñ$‹9xø5þíë£ `êÇ0•’Ìf6Oܨ‰PòCÏ[Õ6¢¿­×Š—A{­>îÐ�Å SØÔô›ø2ºpÞ ˜ÖhkcKzžÔwa×û„Á™«2Ðê4EwKÜg·J:�—�w^ùù¦8© þÒ^tdy§Í¥ËBxfÞw"õ�œalV-ÄÎikð¿�XrZõ(œ‹,ǰiY$¾×{·ã6‹ûTH¿”½‘ÇàÎ�´ýÅjˆzSƒg¦>±‹.˜ù©’ô¿…è꿬ë¶H¢4g1Lú_F—¦rÇÜ×–gP·å 8ûè*(of޼/f�õ¥¨÷»ùøvÞ(¹<㌿1Â�‰¥åûI K$ —PÒ›v˜¦ê>§z*šºq¥Í—*:úŽÄ{Ôýëµ›ô§…š>”xZF>؆0ƒ¶ž0dÄmŠÎóUàȉ=(ššÊ(kt£¿^(tD¬`Úî˜2�›¢éû¦ÅlÂN-ÖkÁô™� Õi‰{BÚQ7—K>W›wÆ Z\vß’Ðâ}ôÇgÖ¦q³D}^„¸¸+vZâpC!ºž/Áýª×AËç6±ZU f‰ä5ÛIÏ?¤‰�âÐ2d'ÎYš/¾ sòLû±zQ9�ÿ{+ü’Œ¥.ëåð‚j3 ¯ª……:Òp¼56d‹s{£@Ÿs�þ( ۞؆³É˜ÄG÷i%(ý5?´ÙP-Ï…˜›¤EÏØŒÓ�·P1²˜h™Ä¡Náq¡‡� 0¿ª’^ÁŠ/Wɽ6'Щê#*úVˆ£­( X­ ÉÛÑdå+0Ы‚™‹7P¯¸'4[mxH³ÿ &'{‚,vo%‡ä(Ý⚎ÚÇwc�ÅwêÅkmG¨öŒxL‰Jƒä�¯™h÷XL¿Ks×DÁxá89”ÍÃÙë”C·©nÅEûÁi…0õˆòeï-Ò…÷—Ð!³‡&Ë ¿§ Hºº`‡F/}¦'žŸ!­ßhÕÊ·TYô4ºFãþˆ[tûjy¸õÏ)]-7±£i·qWñ|ëõ Ž–®Äp‹uàÚ +×òàú«'¡.ï±J’ƒÇßÖ²…§o@§ßä¢Å/¬5T&;ÕÖâæ%¤!qö´¾! 1Íp6½‡„{“ü”¹ 3ò� ø P¾i XXn®éˆ�‚emíTB:ˆÊ;ª�ç¯CIDf,,ùÏŠÖ¿5àÄãD§.¶|æN�äÒñþÀçæ /æS^L¦Mƒ�¸P> Ö¥WÖÝåè%¾yg‡ã•—Ã6½ö¿l"ö aÐÈ3¨3] ÛµºáëK~îÒÌjâ_͘<}JKÅã…žyœ[O¾â¤èqpú}çú2eó‚árÝ\Œ¾ÔB‚þàéøcôÙ§jÊÕ `ÄùóðrÐKêqQ:÷™OðKøB¦.ARU€w|šAÁÙ¤fÑ€wÚU=Öðü2.ŠŠâ�(–ÿZ8y3u”ÝZÃìËh‚D{i0c€WkNÐ"39g�{ɧYX½°‡|?~*LóQ4ó2Æ—fBȾsè.ó ×Í;PÍ÷ð]=hÊ\“ã¬ÛË ‡Œƒøg©/½ßJ‰ r2„n²sZ@'¯�4 êq´Å×B×ö]ðzÆ\ÚÄ1CiKeŽI*¢gîm|¬uŽÝœ=Þ:Â�ÁÆEÉL²�Ì„±µrÜÉéGQÖò ;u�VªÃãìyÜÝ%‹Ë)\''Åy=Kv–ßbŸòö£y‹0¤ÝCšÁ¾²/ð‡íè)Ý3;3áîÞPvý2ý¾  IrM®GÁY•D¼±ò1Ԕ㜳ŸÅùÚ—BÏ'Sä:pnÆZáG­|3Y¸ùôºÍ%› iÜ'yÂ_;X%OÌ‹3cïNΠ ¿M òOL_ ŒyËÅ Oÿ¹a"Û"s 8žïQ~$3Cz1qê }YB”ÄOÒw²àQÍýçÕþ°×ê$hºià³@M˜±™‡c‘ôˆNÆý„W.5ÄÈéè]ÿM:ý…Pëô<:F»ÇIÞ¦6ü.~›6Õ§¢sâ/4ø—ßXÌ=L5him0\]!¥‡Z¨;£Äs}\ŸRŒYÓð·ßFÜá• ½÷¼¨ˆ±9€À(ɵXÆN¦�¥íÞ…°Mú8öt+!¯–4T-b¾5{¢¡®�-ØKéw3¸¤ò��gchf,‰'a„ç~>#- Ë=Øh�ÒYüР:†ìÌ9ZO.8fòY4}ÏwúšFüU‘Óù!ôõ�rR£‹6œõã¤ìD ˆõgÖî ÆË “´®d+>PÝÇvFÍG±™¥pÙ:ŸÕ„àÉêÓ¨9RMÏlݦ†^ÏÒ =o R:º¨[–&ÇE´¢ �…]¬ywƒÈœ?Ž÷:Iíå:¼Q Bå•tÑðU(å±ad߈sºêà £ð�±òˆÆL¥ÛÔ­/÷-Çme 8Õóûj.ÁÇš7Ø=›'ª›Ö$ã‰?šÜ�ÅŸa^NÛ«[ëÜŸA²¼#áI'‘¹0üÀ°&¤Ê…;Äýæ ÒùwC�Küs:üå˜�ÛQÕ}yÔ.ÄŸôŸÏ³ˆÛÒØÒ^ ºß6‚±Ý8­�‰†"H Òŧ‡ø9î­œžçg™f�0eR‚nç÷`ÆP6,Uª£|3æá‰²Iœjþ ²eø¹üsU^™Q¯vì±¥ø~±Þšk…+&ÙůoÀØG0W"ÉÇ 9W5Þ¡‚vÊÖFÂé»^à÷¶žZžgï]KCiåóThäñ¬x‰‰U êóˆÙç�vƒ{QpZ0þ9ÝFN>eIø5zæ…°?W��¼öÐ×ðˆÑŸ&Ê‘ž;Ÿ]Sº;››ia�B)ÞÝã@¢›sjº¶ÕЭcñCo9©8›AuÖÏ…âwµD²ë(aÆw@µb1·×æœùy›¼ ^Ȧºíäêùþ[ÞƒD|*mè »ü–ãr³lvIné¸%fÆÑ}�»ÀZx!˜¿Û}2÷шõ€—k ,T-ìOCMá H]–�ãkeðüˆì ‚¶-£´í§ïh£ÉjÙäo°>ž©�$ϱËšøPÂï3¬ ç EŽ ¦eTâÅйp£?�ô÷Z!oå;ú^ª•jwbk}.L ‡ÂïÓ¶�; šªÃñ qÇXþ ºÉ©ˆytï:¹ ù¤ž†bÃÚ‹˜›R†¥uÉ[ESœ±- ¶µ$bžßGº¢ä5ÊĬ!ݯ"h ¦ò°ûF+Q/¨†ßô«g ûúŽ�)�pÈ9>u'“ÌSæyÞ\ ?·ÒløŸ¤áá³’œªÎ ð4ë¤U1éäwºÜ1­QÞúžÚ>Ýn´­øUá–ulaOž�†Ÿ³`û”ËÎæþcê-•/@W¸�Úן€Û%Þèm8@j[CzR±6²ÑÝÂDwïV8jþ›,W¿õ¼©¸é³Jl¹C^ É`óP»�®Û ®–ÔHÌ5ÅÌ[°Ôˆ+þõ\ö›¨WX~(2§…ŽíUæºÙ¼£X'HzXK"¼k¬sýðî<ÖJ¯kã.äH—,k¥‰¯béøM–Ùï.H«åWÁíG”õÇ1L¡ŒÿöR€Ì{w�l_ºÏë$¾võ´ó;/õ<ä³ I®i\ú«Ë©r_‰ök#IÅú·Ä?=î«QÈë•‚Ýù�©Óo~α’´4× ÚTmÏ*º%“–æ’‘$it>“E¤¥,¡¨½¦Føê Ü,Þ†‚®qx6Œ¨CÙD­êX†Þ…e˜ðW”µ÷SB±:œÛ6jtô¿*×.‘>¿J|¥8 µ®\¤ÊVÉô€¹¶ÎÿN„=zéÊN»VVOŒŒÓWõÙ˜?ó#^ÉÎ&S;x¸AÙC˜ž¢X½û4²ÉvBÐ¼Ê ¶ÚYCžÇuë+�³×ñõOØ2ÉzôS—õZøFè)\ÊN€OR[`)yK:†‘ˆ×NƒÄ׺ã•â4fiÔ7¼W)#8ù>‚t¢ÐGã.KôD¯$mtv6@×þkøß›—ä(~„VÕùìO>ؽœ$—“`rË¿ øk‚³Ìæ˜p“v) þ 2‡R‰ztÞh AúÞ½,øôé™›]°êܦRg l-D EwMw®9ÿi>앬"’s‘«õpø¸¯~/Eíh<ý3ê"¿Â·%dòîs¬X±•ÆkÖ¢Ô÷p=,‹Sç‹Áìì[8å‡f¯ö�élr.Oºæñ×Ð}~‡|‹Îñ~ÊŽu×+hNYA•ï� •Su¨k#KµÔ¢hï׫ %’ƒÝÚ¸R2í¦«pN ŽP�áà| ›{:Ña«CoÑ5=1pâÖZ=û¨L”Ôh„¨âôwºÐ¬· K’;èæÒ`6ËE�É�úÀÌkæ`Ð# l\jD^y7Ñ'æcXgXg¯„‘J—£Xª[ˆê·¢`â?þíÏ!ÓJý°¯þ&Ž.Ä›2ú 2ò ÆL¨l]½næÈ½•ù§Acf ¨Êð€ð¡  ”éO¶}S‡¦Rm®=×–´j¸“ÐsdﵫdÕ�ü[åDjo¢ç›|xø*“:;\‰ÏGð×"569�õݤà•Ô¯XHœ8Šñwe¨£M¥Ü†pî3iìßPÈ>U˜ƒÒŠqLtRŸýšMX{©1Ê÷K™¾´"Ââžx�§�nuÎ)3v±˜8.µ{�íÎ;^M^ŸÆ ’ QÑGþþóà¦aVvY&xïÅý �´ÿÔ/¸u�¤�ë÷� p4&±|/ç™òNxðnlȬ Õⱋ§!Hl˜Èé>‡ñ6Yæñø¶Hm?S߀ofÜ…×Òq”ì/¡JÅ ì’‚o`xÅyû¡=©Uï½`%Ý� Ë-ž2Y˜Ž=`¨aÇC_2ÿ9•c ÷»"®ëÅ#0Îmܪ¼Økå¢À�& ³Ø¹8&ñ]îf2ÁÁ�¡õ 7ûÓ9Ü|¤.þÞÁ\+*'ÚGJØõý öëå?0º{Ѫ9ƒ}R‚([3ÉLÌÞÌrë’èÏù!xUB�«ô7šÎ,Àî¹?IÅÛ…´û„ÝtaGˆ-Z aUŠœ;9óA]¸ãx<¡ò‹Ü\·\ÂyÉÏo…À|ÚJ—m ‡'FwÐwRv:¼'‚öZ6ú9í¨Â~ÁuEzd¡2èðÀÍ¢Pwö…j`ìó H‡�Áúz¨ˆ$“YÇŒñÑX?®î£ /î¢;‚{I¬~Í™]G˜S—3°â½-쾑ŒGת¡øÝc@Kzðˆ‚<1ñ~HùDÐ]ÁI”»Î}žS³«ÔGÎòaà¯Wd®¸(:Ï­šzè—šÄ?4Ò=žÑÈ_…4¶xE�¤O˜8�óJƒ ÀEcØþQŸZ�o!Ïd±ä¼v7¼ §ºùA©7T…¸C¹S¬‘ÿLÜ2È‹®wÖ0LáׂgØÔšN_¶F૸2zý$6Éœ'Ì yKŒ Ÿ`4¯k¦Ö�ÒhÄRM( ñcÕÒÿ†'¦°6nüÍ6ëxÓ4‡›,¿šü0@AåH¸HgSγ¬Vâe8#°íw/ÀÎýa cž…1"('ŽÛ%À#Ε·gu.òºñƒÌö+俽K9ÚoSQáy8‘ €®¸ƒÔrü%½ß~ŽJîë&| “ñOÇ$»ÁåœzO�'÷’T7�Q¼‡ª_jéù�@²FrQMÁu;0”¿†1ÇbQäqwMâ£X¹æ»'4¥ÎÎǯKìêIlüwo!wc±Q÷"Ù ¨óŸS\¹T|ŠEî^dŽŠcظ:jYjà�Uwÿ¹V ;¯Ïû›TQê)N}4÷±¼þ³Œ5ñ£NW0Â'ÿFÕЮB ^Ÿ‡ÛWD`‘n©�"AÝJÌÉÑñê¶ –;t‘´ãšp²&“ª`B¥‹ ZÒí�肵™ê’¯dXýÌM´‚Ñk˜ú‘»¹”#pœ K ·=àH‚üY›�ÛÝÃñ7WcˆÍI~¾òõÈn!8jZ…¿Ó¯Zn2Uæì�;»ÿ1g=/B¬ŽÅBO H–ÖÍðp¡"ç“ÜZ·û<=Ô/FY©¥`ë~ƒ Ôû³¦ÛÍ€sèû«jØýÆøuÞEp³ÔéüVæÎ Ø`,ÂÙ+†PN¡eGÙ™ž›q—™;6î;@„/ECG˜(26L_º ¨î<�E+èáýƒŒ¡× ¨[^ÎÌ|û–ºŽzÒŸÞ!`þ¨_§ ‹y0Ý=ã3‰K¹HëlÃpJ¼Œ”'»J½€Êsº°JB�SöQŒùÀN/w³ñm{J†"§Ÿw®œ¡¯q›êr�ö*€Œ§±0ç„=c¿»™1Ó}‰Û á¡f:sj;©.)‡¸‹7¨ÿé(ŸÇBÏ�Ûh¼²‹q÷:ÅæÅÄ£vûwö£ícÒà~Ÿ¹¼à3Ïñ�úàO¯ù¼£ç÷+ƒ—ç5ØÐ~I=¥vv ·P•ýª ¼n'°^¯*#¶�P¾Ä}êmµ{{'-pTý_…øìÖlzÕmöâ² ¨ÁÊÄ›”CúНlí‚i˜9´5E9ùŽ7¡ö¦+êÍ ¦Á/ƒ©ïÜò™AE+bGî[S†¤zàýö‹’I‰Ñ޲íÑQ›úi¸þ(Ò>°L0CŠ£Ê>)¼ŸZ 5~½`Ú£Dó®`IF,fÿøH€%×¢tó|JŒ³àyº4\»L3Ke8 ¯¦ŸáX9o¥kJɺ§Ëa›…õ!Î-�Ú÷š)î"Û(Z튧’7ÑCš‘øžþfmmÝi‰]3 /áÇÒ5z¨â ¹·ÖWíßM%;” ÷C$ 5¤|†Ó5Õ˜/–¶=·©óÐJü�Ó Hi®.1óX"ù_8+øMB?%“‚å¬sd"™•U†cc§ X B?f±Y"ª¤kç ðNFõü÷d÷1búyÉV±½°ju ›´$Çò¶‘ª�0ìxŽÿwô· à§õu¸ÇBƒn9´ÂøÐÍ~þð–Ç&ÔMi³T,ñ3¤þIë±'Îå_¨@Bø4SP§qÙ_þíB#k_OO ½$—ïÀ8E¸¬~—ÎÔâÒä,Q¬ˆBO­=hªâ×ýÛ’˜ÈÁ h`MF,1N} ‰/…9k1R›ï7„ÉÓ×™9+Þ‘ÿl.BVË}¦eÚº©ºƒòú'a¢ÜqìÌjfF”g�½3v»Åt·^Ìò™FwÞZ‚kÞ„BzîÙ(2Ãæ“ïý3=ߨˆ×Oƨ‚i@-~Ó?ˆgÉ‹ù6ëÐ6ÏzM®'Í€Ú¹°¾BóË´áì½+¸Æ*LÝlz £a©êj°:þ£¦C&”~¶…M©×Ç|µÎçÆv3;tæ€ ¯öÐm¤èò=v3¿û-GeƒL¸gtÖø•Ré�ÆÀ7ÄÇÝ>¿‚þBQ*_1 2ÖCʺv| ¾½Z ÇŸá¬ðxH}SÁšY=¤±MuttH  ô0´Xö8V ü6a<0yŽ$º‰pROúâzß ð1-6›zãaë¬õ5' ÿ²m9î þ�Ò‰©âÂ/ÓC\uÁík]ôžÛal ~4)}!.Qæ!§úŽÓ{WD¹Áò'É>½•ðës%ë¾G úßô£Ê©6â;x–tÄ…ûƒ�­ƒD� uV-ǫᎹ+`AQ54më –�§ðG}1¹~)‰v-¡ õwÑÞb3“DÍ”§ªúàò´ùò]2F~Ô!f�²±›6¬½OŒV.c]æëq\Pf÷ÜŸÓï>´Þã#BýÖÛÓÖWU°åC �QMü:PM×ÕQzïÍB&këY\y5 7hÞ„g|3`®Ñ¸ñ±¥÷\Òa‰¾ëÅHŽælÙF¬5j `N{çÚ',ÖKG›ÏÓ1FQe¶’¤M~lSEa;ŽãJåb,? ʱ°sM7¬ª#zÛÕ!Eó ³ð» š%T¢ƒ²¬ñJ&3?>£Ïž¾%e½«Am‘9Ñú�c#§6“3ýE ÛÏj�Öâ&P8ðVuÄѳ|ŽÈ» ŠTíŒ"‚ªÀ¤Èü1«ÄJçMðÇ\åjã9ZB¿Ü0Þ+c$ÙÝÊß b„½>—âe(ù¢ÏS²Àzº34”¿¦£¡´î�h¾N…Œ‘¸èb[0��[ti¥€‰¥[á{,…,4¿C ~ ÀŒN'Œ�_K7mžŽ�<§wn1Q‰Ûèö–Vh[4)Ö¢rF/éü—ðté'Ð9Jî~‹ ]£´é¡.ÆFÇdÔ[UŠ�ÝÄÇúé¹<›�%n01FÌ6`á9'\-a…¿/¥Q÷Êé(tw’䙿¡ÝçIÆ›%(Ø%‚—þ{‡â¦ý8©×L¢4í0©Ÿ�[ùÎ “K-ØÉøRló{ÀØ'øÃŠºò¥g:Ú|ÛŽC÷K‘pqN…¤Š8Òdï`!Îi9ø‚¦�àAI¤.þëCAøP>›´¨÷ rað-»°g=®˜Eï*IR ç_Ôz« Ž6�õÁx]qQ¥™Tô”¾ÏÛà?å_6Ö;¡ÔT†gf’ê}q�Ö¼:÷ñr&ÿnyžO´9Sˆ»ÇXï¤.GáÝ1ä?þà9²ÖLFં;L–“Y.S¹à»E â\ÁWÐ‡È ¿Ã+¡Ùd ¾™‡  óÓõ9çMlñР-]¿³�ö�KÃ,Õ_tõ¢ì [/͇‹yÑt(Æ„ŒµÍDî~_e éß?Õœû=Æf†³ì8òswÝ…>‡ði²FT¬Á¤60±Yç¿U%ÆùPY:™ï¨FÜ!ÔÉndŒ*ãžÌ6T1d=Ã�’&©fºýÜ7r_°‚Ì+œM—OLá½½E´¿Í¾J¸Ò¦ÊðëÇ+ê·ê)º[]¡Rr®°™?|+¡Þt+ò|˜æt³¤¾l ¹2‡G¥³QÞ †tîõGnøUu-¸ó;±ÛLƒVÛà4ù ๊ÖAÆ î8›Ýð�žú›Œ ~éè:”Këö„cõH7Î=Wmš¦ÇÝ7„sæÿÄt“u\{?e£´ª îp"I#ûXž—HùDÑ$á ý´4 ˆÉ ¾ïd}j4æl¤¨3V �üP8ØOÿøþ ›þ8Aôö§äTÎ}Z0}+5TpõÛ'°Š+‡0/ž �§ÇÌñcÎz|û÷¡hã±³ {E¤0î¹5î|7 ÷Î"“ÒvpÿŠ$nšiA %ÁïfKC¢ }`”k·Áç‰Jüï<�+* è Cž±Àsv z?±Å}B¿ÚAz�\Oú‰À9|<à-` iY"ÿÖÞûóà“)Ôëe-<}óžÔFA^Y6ù{J 昘bžü-pIÑà>>K†v ÙÜù‘�+Sb˜�K2é¼kª4hAþ•ùIªí_P­¥ Lig£XÚü�J›Ü¥euSX¶ôü9Öõ"pÀÛÚÿ§Ð¼ã±üÞ8ŽŒ2’=#E¢PòÜçz�6 ¥ACÚHJ‰”‘-{fψTH‰ç>×SQ’$RÒP©™íú?¿ÿÏ_ç\×çýy߯[#¾Ð57ÎÒ°±KÔ>ׯæ`e-3Ø$Ï7ô“ó)Îaœ‘>öPÙÓ;Ñe?“ŒCsÁ§�ÃVœˆ@—1†ÿúþCòï]µ·T¥KWMdà¦YزZ�_ÎáNp¼CTJ°Tù Œßma2ù È‹f‡sjaÑ•)ü“FÜ}ÉyàfõŒŽG{2SF3°,9‹ ¿P�í;¡lã"ØsœOf„°G®_CqÍ©t4O�»=ÆŠÚ{¢õâ_äoÝUôz¼“ì>‡ç4V“ÌYdM™t_ÞG‚1}úð§W+»Äh:äm5*4‡`œo ;½ê><�0hØDo¸ß¤+¦"ó[·çô®„]e2ü;–‡ÁÒg_bÇuÿG wëm²ké)"¼�Å ß›lmÈüoè<ì°ê¢AfÀ}½÷ìÿH¶ÒÂoˆæÅx‘|C×X2 d÷Ré€èw2]¦˜{íÈþÍ£ï_̆ñ·?¡u|$=“Ĺ“Õqa²÷¦G,|v•Á)Ht+“`hÍ~úv±ÍXm�œütˆ† aþŠòܪy]å¨ÐÁÈì²€û¼G4ým7={x.õv¥Å†–0Ãz*§jrN¾¬‡¦B=tï·›TJ/ ’·†S}Ž2Éǹ·� Ê¯{I4 U1D’…EÿÊQ7˧ä߈_D®UŸ¸w ½Êttî ÆLù ÊõÙ âàUÀ9ì²bÅü.¸Y!µ1c×Ê<”/=ïƒÊÚí\‹-ñhz.¼XoE7–{ ÆbE~*?_œî'wÛD@kÀ”Tü‘æÛMV‡³©Wq~íXU=ˆ¥«U©Â§$Üqel3�¢æ t&'+GÂy¿›ná‘~ˆ8?M‡NÂÅWµtŸÓ*àYþaóîÀ*!˜jg :æ“©pµ8*+/+ ø¾Ò§l¤^�¨€U<$¯Š†ô†Iü˜.)!ÏÎyˆ¥‹ˆÇɧtN‘;Ìùð—ì�ûΩ¨þ�Õ�áÎø¨cÂ]œ¶�ªöúû¾)Üõ­èy?›ÜÝ�ˆd—a|Ócš&. kÃ;áÜ!Ÿì›þ2YTô�9Æþw�DmT'_ ùxw±mù�‡"x˜"q³‡³(÷Øjâø¸CwªBÃg|Î-¡Îánü­€Ä~&Ýd5 Á o ¶æ/Ø‘ åˆÇ?ÓË~ÑŽçˆÛ ô�ÞBGçOã×- #‚ì<¸ðj6)>=Š�5`ZÕ ²$:Ÿf{ÏøBçýDûô¬éFK®ÉÀTâã³´÷oÅ>Koh¸F½´?ç™òQŒ»ÊUڤݻ =ÈÝa1j„?˜çÛâcTÖë8ظΒ¤fÌÃþîsÃ_Sà¥l[€ã[˜‡?“±¾A"ÿgˆ] FËÈ^xcVYKŒÒžCÛ·PHÛó„þ–ÛæÎÆ°Ê͆[rhÞ7†µa~xÿU (𪡻i ~{" .m«ë\J�+½Wˆa;³÷Ø'ú¯ç1­»jN+DbÁ-ç#Àšbª¸Í–Ø|$¾cdþß2òìûTb–y´ J9<Ï¿Tþ¦'ú©©AôÜãDBØš¾Ö=IZšUá¿poÒ¾®}Š5 ©ZŠ.{q ¶å=Cpë*h<‘ÙYÆ8õÚB¼>„¤yj4ù]S‹Ç5=Iµ‚8×{þ3Ÿ,&›—o�3âè÷J‹¶TPï…äØg},ëtƒLaè\qãF|Þ3ïaçÊÇÑ׎ iûþy¸¬Kû,’ï±sÐÃ<”oÑ’÷ñ…Ø9Ø£²»}–`3s�ÔèÌä_ðÙCó‡òˆ†½0·SE4eÒ±AL•ÌúæLíWiá/™%Ð2ÁôÄš~ŽhG>”ч:é\0»î€ºûŸÒòÍo‰dÏEЈ½O[Ë1ãÄX½à®™ô”¹´ü4Ù÷¡…g âê?äb“µ*#~3üQñêWÒT Û;3.b°Êµ�Ö�òxS¦ybâÒŸ°!=ƒ˜žã¹3� <"ïgCNg<öêÝ&J –‘þµ´[�€æìzü»ûnp餯[Bà¦�>Q>­Cßié5/JežÊñOݹŸMLˆÝv8¨¦RN´Œ'Ã%&»pÛ§dDHëa|ÚÑA6>{BýM‚½‡/bà¼"ôµ[ƒ�ѳy‚tnæ4rm+§2%šN}Ó@ûµEÉôñ­h:�Ol“¯;‚@áJ$ýe¬Ï´\ø {"SØN$'�ŒãÌ©bÜK8©(�禊âV™vêM¾¬ýNœÍ�ávB ¯ÚEö-E�­ûýÍ¢è÷ß^sP.Ü(…¼±Hr#ñ<œnÙ… C}LýZ8ÚJ…ÖÇ€R®þUJÅQ¿çô€Ý[X*؆æ ÔwM4¾ÕÏFÇý{p9C¸ûÞ’~‡ hÿ(MgM& AÏhV^:íìH¤ÅH–ï¯`�=Ïâ…ïõà� Ä-Zv”£#ŸÃº©§!'hÎ+¼F+ý�ÑÂ=“<—É¥!ßj°ÞóÆç€Åù“dCž;å§SƒåE¤7a=·;N×ÇþIQ褾�V$ÌD�Ü`òªû%Iud¹+™këÞÐ/»�>˜�‚'»£ˆÎ³ ¯X{Õ .AöÒëÀ‘Wà«W�Qîæ(j^O�3ÑŠª\aŠêòÑø#‰Eÿ°l"ùO |;ƒpŘþ œ]¿µ0÷Å ®I"‹ ÷hfídî-�¬þâ ^¹à�ø.6ªC’1ŒSfU¯ò¢ò;nÚ}í#¿Ð�b&4íñ<ö¨d S¨Xåf†ü­œÉäUe¹èRþ­¤ÉÙw) �Umi“Æ´fab|ð6�ë®ÄÚl ÆÖ…m�tTu'ƒ°¼�Uû‰˜˜QçÕ¿úî-@…�b$¼*šþÔJÁá�3>O�Wç`¤‰)<¯“Ç=¶ÛðNÛRAÊ¡‘·örìYƒÏ˜k$ywûÔÇŠâìù,¯¶à"¢Õ»…¦›�Þ²iüÓ²mlIþ$Œùü›Ú’ÕÐî [OjQ'Ù›$õ¯<„ÍÊD¹á¯TAªŠ‰®œŒ™ÊÚèÝÛ�­rAÆMü§]Âû»Ÿ²=¿CPw›hW!þ1L@ó¡Æ¿3¶çÆÒV�ÀûÉ#òÏ·‚¼Z’I -ªmø‹z^Ì$ËknÃXÂÄ�¼E·XmÇÏk#H̓V¶×Y çšâð T�¼ªGX&PJº÷¤Ð=+–Aëà šloî'|ȘÂ>¼i�‰ Úð~÷8y4…wÉîDM6ÂÊÓ©ôjò+Úë%�™¿2 vZá)Mãòþ©“ÑFIèKH‡§J›qKvzìØK_þ5ÃO¾¥°dãfÚ\UA® $9QKñÂÛ øÅŸŒ¾oákVÚÏבÅüýtOòwœ«ˆƒ;]’D’ΔÁ·çó�s¹‡EÜG=lîPÂçG‰Ÿn (–ãŸ�%ŽÍ)ñ4peþ¨T‡é¾kWvЭÏ2Ÿ³ÒX‡]ÇàFÏ\zASÝW-C*²äÒRAä¬.Ê¶ìÆ¦ÑfxRz‚ÎC-HȘCN®‰Ãiú[§O_9‚»}<ñÛI7öP¯ITuÝGƒ§Y#_~Œ˜OåÖÔ>Å’"óÖàŠ§ßHâd4 ‹Åg¶WQ7Y–ø;ÿ"UqÒÜ15#:\ÕA”ë°¶5 ¯c_=ƒ¡COèj EŒI,‡ýÔìbøôX@è8\�\ŠD̈cF.|‡1½{¨CömfOôB(‹ô)ÇÄÑv \‹i‹«;qµ`,ûíª fÿ †â8&2BÜçpgéÞª[!OSŸÒÌ€`rSÉêk�Tô©(9ä�oEºH€×¬Ø �1¸¿=-7¸aºÜS+ÕC =Žií[©êÂ=Pw|”‰V¿H~æë�DÏQrÎ#�xÃiÿ%PvõÌ©;ÙÙÒ`ÿ¸Ç/šÁêÝrø®¤Ž˜¨÷-¦z÷a ·™°‚XÉû¦˜ðL,¢w�Å®)¸R¥›Ä=ŽE³æ2Ლ'³'îsFÖ¿$ÏúÇà…vñ4ÌBé¹s郾bŒ.›OTÚÞÑÃ~îà©U ñãµx`ý Øøà­#Å~]LWÝZZg- gÿ»Êòä¬ÐvN}ÃR«Vw|¼qh‡l8î‚K¬Ýëœæ­ÅÐP"Œëǃ˜¶[PlÜ‹ÏNHcü B‡òHh”$¼M¬!âÓ1Å�CM%æaì‚£túöVòi±ùtáÝÃZVõàæ~‚·Vd€½´Ô)³&ž3 yC"]ÝhÂ+Þ!IŸöÓ¬²íàÒ+…§>aÐô °YU‹�ÿO’O­ãéEI”òÈ#…¼JÜ�*‚ί&Ì´]¸$WŒx<;‡§g…áçc™ØPŽVkáþuü’<.F]ÿ€“lþÁàD�1ÍäkÍý�ì[¸ò2u׿¥//ÔŠþ=Èìý‡n]¿A rð¿ER«0Eþü�6Ø–o_p®ÅØã¿¡#džûFòbðvv’•ÿ™Ò�«É˘Hø[ð�åwSÛCšÔ’o�{l\™Gµ  'À�J;Ct-Óð¶ŽWï‚8 GƒóÐ øT¿c>twð¨Z‚1ëõ·�°� à«Ô÷æšöMš…ñÙüc¢¦Á„Ü#ÃÜõ¼èõ ì|ß;4]î�}“©´àŒ˜«p³$|~ à—å»Ð0`ÙeýšÆ©Ûà…sà:×€ Š•�$R¢‚è;À'ùÛô—–"Îö­íly|a ™*4¿ü9¨ÈgÒöºÿ`;ÏŠÿ½éQíš5Κ¸¨ûÉ‹•ÄiñÛÉÀ¿~Q("¤û;�ª¨Cñ¬­x61›–où�ØhEn¾ÂŠmáPW|ù·¦ã­@y¸¾Ñ %§¼ SåòèòC�t²�&ª‰çÂëÁ6'`œÎèf¯¤¼#þeï·ªeØôÏmvD³KZlóÀMÖ¹D…¿|žÌZ~�šW߯ýdÎ(PãB[,ÖE·ø:츳“Î^eÌü.!µb÷¡˜&²?ÏÃ3¯&¼6›ÛX\ T'Ñý¹fxþïb„·× wµ7™Òñ5¿�±ßr§öÿÿ"žãÿ1PÇxÁ( Sòôp}Bt[Mè†ÄbŽh–;šÁuYøµ=�‰ôûHŸœƒí¯#¨½A#6Š/$^›Óv¥ƒÐ´í"¬¯¿¿vÞgríEç¸'ÔX0µ Îâ-5lïyZþÓù‚I%¸òå9PøÐJ�-™ ü¦yø^;”Šžh¡zGu`O€ ¼3¢2=´¢k©>_A*ÎübÝþ�¦b™cè,þ‘ |A“Ò„À¨ü4¾¾(DªƒõN}ªÍ<‚m{[Ááo Œ]ÒÃwÕçhéß=ÜÆ÷Ë¡bV:+‡À”…20tÂF”ƒiaS#ñâ5ë÷á͸tçõ=FíøôºÖžxšxg;Éî¹A •OÒ¤E+˜/Ù˨ÁúXŒ ÉWmLkx*ÏÛ†…é"WÚu²}ñÛó`F'·¿Ä#Þ2ùH/Ùã}Äe²ù²-ã\âIÝöUìÈÖõxËŇÊóñË› z›wãg;£Êqòô®(þÁÙøð\8í2üN×Óçš0:þæ‡è‚¦mÈqÏEã—‚Åð;*•<¹YûÎFÒ¶÷tÅ–©xÎlL­9ƒ†¿¢sBO‰¿ËòöÃ÷Øòªø8$5`k£ó-ÇFä`áçpÜ5Ó‚Z.bF�žŠ3xûæ ¼‹×yª…‡Hޱ6¹?; fžUÇä¢ý$Bñ=FÌóAaj¼¾@�[áÄÃgŒw”Õïé™9ÊüiRk06.þx›¢ÐíjºôM-•O†éI¢`øh.X}ßOo%4ÂíÎtÚ�APï˜gAönÇÆÃð]:™þîŠ$ŒÃNœÿ}cS¹ßlŽfÙýÏá¸üLäL‰bæ%�‡ñbüàºèz¸…±¨ê¦Z‡š¨‹o' Уo„°¦§—f +a·è1”WœEÄç%à¢ÙtþEnÌ©X�íC…ˆøn|KŸo²…Œ‡2LîEìPh¦1³ñØ3ôwÁë_šÙ–ø¨b†/j—ë>túUO\iUHªÇÈ'�HúæŒ"žÙvš:K‡�´�¸ûýML¸öüߘAoE<#W±»ÇÎÆôÝœG´áq?aÃ'»ÉÔÿ¶:ØÝ¹@Ÿ®’¢#rùdæÛ°Ú�’Fø«N³Þg3[¢|è¶PÙ¾RŽŸÓdÇ#§‚ŪGتò�·¼ô{j«!ãõ9™>ñ"§Í%!nIùÚ2Ž97ˆÁf®öLCÑè¹à(híꀚK=p«r9Ó]—Ÿ”á–Ä0xí gÌ#é�¸ctêÝ{ ýª %,äbxo¼µ‰ó†Þ¹ñµ'ÑoÅsPp-ÆíRwèÔ¹" ~ïÕ%Az¸iÀr¿:rñ¤ îõ Xâ}‹S9÷TåŸÆ^îr+gß³üJŒ² ÷S3àóIcœî×@ǯ6Qß˰à_,È­d[M¢±Æ·–LrXé{.á–¶LjæÊ‡ÔE/à„úm"—×–2FXÂóâµžß Ì¡TmÇ2Ô÷«q9°Hù€+5@vü\ÌMc7œ×¡ï“Eá+§çlÞŒ÷»sè–PJæœ[ cã©ifVÇx@² æšØ`žÀ Nú„Æ)rlë—EÄÔµ ´•Þi|°%‰X뤢_O#›µ{ m¿ìŒG“�-Qþ½m´M'æÐZg”ܾåÃ)í°ä¿`âQ¼Ã_G—]Yèi@oن‰£cøaµ/Ò×õÒ¶X÷]Ÿ$•ÚƒKX –ØÚÃjÚDþ£¤ÜÖ†7.„�ð¨`#Ì™W‚ÖMí86sím¹~msI¿eÍ’†¿O62‰õš¬¬�? þ*gxß&2Ø4J�ZisuVNQá ?#fúš¸÷Æÿ¿+Ϥ•WÉšk¿Y…Ëárr’3.ðjÚ4:«YG´ÒЬRt¾Z˜ †P™?¨qËbØ1_štf†Àõƒ]Ä?b�ƒA4êÖKfwb‘šfC}5ˆõ1þYþL®oT©‹càŒ?Œtẹ=Þõ½†Í.äûžuôßÍv�j>K|&Y€Ût·Ð�³…0ûm6íÖ"Ù2B0pp72uÖôãòAò­'˜ÔM#°Ü~InG*É3} ¥œ,X;²¸¢�ñÒcþ:%a<˜—MNšI[.Ôü¬÷]gi–·&4”ï¡‚=ÂXðI7×Å� ïTü=—£ž@ñºæ¼Ý+Þ 3*‰ÇpDà;¹½;oM£œqET¹•€%>x|¶6¹ûê-œ}¯ë+ ¢ª4J:l#׺‰è»&r!$§¶ÁÊ[jtÅ­µ”Nï'Ã.…°¸UJƒ}èÓúDTeγÀú|ÞÍ@7|N…j#aîæùÓù¥å3ˆ‹Øa´¾“+µ½hšnxñ¿P�] ¸î¿lô”G}õIØü�nš&ƒe;7ѵחaîÔfâøŒ@GìS:t9DŽl«óæóàjf"öž _&ù“– ÿØ—¬É®íʤÔw¾þmE”´6’>ïÕÄû§^¶4‚F½»ì‰œ =f ®GîÛ#¸±õ=="ºòŠS©Ç� #Ûa/7NåïK¿AªYóºÚot1{46—äô‘ÍIŸÉ¹è&üö:•Èý¸IÕbä  EKÏdàÇ5Òï? è°M,î¶”A×ÎLò¾š@_Ký±þd_'X�Q$‘LÚÆnŸJ§ÎœLÓÃ[ ­a|êÞ“Ëpî RþºØ~—C¾ÊÕ£Ru9'íb-Ÿ¤É_–è3”½á‰^)êfˆ�TƒÁû‡8¼$bbš¥s¡ú•>5z‘*º(,A f·‚OÊ~üŽqWè0 ͤLEÙª §úÜÁ�ò!1"ÿô:­÷4‚5ÏPV-/g´bé¨<.ž…fKoÇñU´|¯0×yE*¹²ê"ý’èÃɤ§œïÐÚÀx3ØO 1Èìý{~7¾H,£N^‰aôçïðT·„0WÖ@B×6œå²î ¸S§¶&Úsÿ{RH Ÿ}sãÝ9´kÿR\·tŒ (®GùæE´xqIü�ŒUœ]0=_Ë˱Ûï'<øú‡_‚‰åR™G: AYëz sЂcHž;ŽPuP‰½F +¥(©Jt ^àê´.{g€»"²HŽe‰NЇÌÀ(ºèÔ5T]ÐD�¬üÊ.­*„É×";‘±ž¿90ÿ¾Í2¼‡+]Õˆ½í)ø[ô“|³ ÎõC´7Uk SÁoòtß߸«¤ z°Fe2ÝþRíŽå‚¬Ð}ª<¦FŠÂ¼±¾@¥ñ72f-JŒßbW¾÷›ãq|ŸI@ßb&|øÃ"ÏïÓÁNyËP¬^QËh„=$¯Ý»ÉÙ–ú3T?¾SâYDdðþjÈs>ÜÂÜ8®¹;ké÷½›àÀ¤o´-w7òŽˆÐœ/?É�"GZÓ¡Ò¥Áiõe&òì(õ½d„ŸôsGE�ØõnzgLïóî±®Êo¨fÞSÖJþ$�©™ÈítËŸ¼q#�ÜПÞ)Ü6â°+è9ˆ�AŸ“ëðêÌt2 ¿´S`°±ç&Åಪ<Ó/ ¿—µR¿‘JÞc…âóì#ቩbá�'4#¸‡ìÝÑDªóÝðоÚ³ï1¼Ô¾‡EšK)Çr¿ª)ž¼l·¤ó’âpõ€Ý)ƒ÷UùH„ƒú 0ÞÜO÷z'�§5Ñ��èDÞjñqÉ¡Dø¯ô!y°ì LÊë#/ÙU8¥Tž?~Awí“EûôGäåñå Rõï$`zš Ü_žŠsÕÎg‘`PˆÂïjˆ×ÚTœ¬Ð€�6eâÑûÁijR?˜°°\ËtKh³švë=e=1 Ê�EòåÌö/—7ÑáRðÖZ>Ù­D0/A–ªD̃‹·àï�Îi¥98Y׃¾s¿@ŽoÖBƒ3t>gŠÒÖŠôÐÚp:ÅØ�ùcðÓHAÒ%3"ò½�n›¶«ê1ñuˆÿ`{Ó¶ƒZ¨8W#Ý�'‘Þ6²óà üØ÷†sù×dµtG¿9�gúƒ\ÓI@».I:/µ”É1=†ÊŸ_�c] °îø>ˆŽ.%¦%qñ¯jRæÓ�×·Þ¢�ÉÉÐ'�BÇm@ [ˆó7 OíÙºxÃÅ#Pån JsŒþBi=J€ Å?9»|a§›{�7´ž…þ'EXsÙ;²“Q|i 9ŽFsfc‰Y6ÈT _ušå[AFóôºX^°365Ér�n{ALtæ¦ñéUk®‹Ão²þµÿÂi>ˆý\ˆé?VR¥½ÃÔ|H“Ï470 #àíhªnIdGìoCwÒc*sÏ×*¿$sÔdè•]ò|¹ƒ©Š‘Sä>µ�Ú [Xr�%YSéIˆ[§lLÍL€ûç îd°zvì6Oa¯šã¡†µdCßL¨/ŸFÛ,æÂ�~)»�¿3½ñšÿfZì$€ºÓRiÞ;�Út–ðbhóÅy(nº’ú™‹ÀWƽå†Áé]Æè&Qƒß�dÞÎ >8ö¦cê«ø¨Æmm¦ž×e¹†çÌ isÓl+Ý_àúÄ{÷”3(%æ€U|©Š_ �ËÄ‹jñÔL5cwŠò!rsvàŠ3‰DÇíìûð�Ê_»FŒM!×Ô£µåtÔµƒ|¦r ›MänÅ¡õ­cTHÊÃenñž%9ÆSê¸÷z¸Ž AP±œ3)$îÑEøö£¾±S†¼´P …¨½¤rx †ÿ‰€0 p»àá§Ààæ+š£2‡oÓý=Ó×#Zþ@Å2$ã^8䟭äl»ü‡Þl™‰™œýh{O�k¾2þþnBvlJkÝEãwŽT(Ǜʎ·1N‹ÆáÕ"#Pµk„½?öáÆ†*Ò´¤~ÊΞŒº'͸çïÎÂW¼Äþ4'µå‘EIÀÈvÃ/õù$~Hy>�øPú<�Vq“\~…‰ î¿SKôn½%÷Ÿq§Ï{K½â¡â…QšbZDn5+söšÎEú^x;?ÉÉÝueŽ'e»ãé¶7æðÚ¦.½¾D\|ZèÕUI¨¼I•{·,�Õq«ÅÌñ÷¼Ù7}Ábì6Šo½Žu·‚zs1½¤wO¹ãÓ§ãô£±JŸÅ‡À�Þ2úxïðG±H%6½å‘´Hƒ©—ØdÜZ艗ó™‘gsétÓ:|«"þJ�ÑyÙ(öŠú q‹48M‚:Ž(̯e@ë°6æ®ÈÅ åKy~—Ö�3†dXÊ ír�ÐâîWzUS §øt¶허Á©2v��);в 3Ë —:“}ó’0븙WJæ^”áFi•€ø:¸éôM/Šðo+€nr^ùÉòuk J¹>‡¯ÅÝNÙôt¹ ÷¬†6*­»J»~y€àéû ¬ZJo‰q®¼ü� 1Ó©Ax)h6¼hµÁJú‰,ß4*&‹�à&?|­…ý†wðÅI)´._R§TøB¡¸ëð9”Ó}€ ¿v;áï¬{ÓyŽQJ ow J‡„¸3¾Í„ìó$üÊ:â§O;S@ýW‹¹Wúàéð/rl’!½ºI@J’…vC>úŠö÷‰6¸±_þ9�éDZ ë'ýÔ{ž÷da¶K6éß(ȹï<“=óv”à¡¿©ÏÎtèÓó#¦±9ðÏ0‡13ÕÄÙ[Ñ4™(¨M§®VÚ8uE §Û¼ŒÚoòÀw凉Áä—´à^oX‡^ù²äcqÈ?@æ„_ÄKa|Üÿ5ËVß$�ëùs'?¥‰+µAåSLÕ¦”}‚ïÇ©gänðlñ&’Kw¼(#h-¨õþ"›×¥ìXÔ:"‡ýOCðåO^êÁ3¨4Ñaþì,Á©§Y¼ž¼W)eŸäïÁ¬ùxé�ΓçZè¤.Ľ¹ÈbÒœh‘Å]ÆmÿZx�qCw”FE‘¿@ñe}ƒ°Üh„4IÀ÷�½àRA Â6±â¬ª$£]@0uýk�aËE¸OÈÎUÿ/ŸÝðþ;ã_ÆY¾ëÔ è´tƼ °}Ñ:w,qåsMZ¶*Âì4À9sŸµgÙX³ct|¥,½iχ·M`èËÆYý -€W âÞ露|+6ÆWBOÿüu§l�DÔæKÀ–sí°ŠãÁ9µ+ÍGL¸âY©`û4€åž6B1Î.×EoâÇ7‡PîvÚ=»E?Ì…àãvpü„LmRaàQ'ç¨Àf°pŽfõ"5ÉÎÞpí¼+NÞu˜jN� “.]f&û'‘¿ZèÿJœ¼>«KåüƒéSIîÁëàÙ øuÂíæNâꊮBßKÍ(ÇNâ«G `ñ�+Ô³ lyæ—¿^gßp ™cãèQפÄí5Ї†�dÅ´Lây  �šñ»o=U·Ÿ¥h㸔xuhâÌ.X¸ðhEßùt¡Êj0pƒ%“;qJµ×ÿ™×4ý9ÁMkÝ(uoê„݃]�ΠU| ú©¡ð>\/}Šªm.D鞉ëÚF[7O¡G¤Mpu© $VÜD§=–pÁÅ÷?Äšæ8Ôõ w=Š&úóWµJž9 6/®%3½Ö¢–²ùÏ8ŸÊ}>ˆ~ò%ð5í,U8ÂA‰Kt (£mç8šÙK]±¢âWËØßurÌŽ£š0¶ý 9Ù5“»{—,žÿä„çdc3yFƒ ÝÐ/D$¿æR¯ÛÖL°q ,.†U;ïጲTÀb29+“´§v�Å4åÂHÿ ÝÂë,>ö;òçf݃Ù�<:‹FUí®wOIxηj9óR÷‡ªøÕpã¯-SËè©êDeð:¸EIã‡Þû0|û�뀇£Äˆè yYï(º]{Ë·*¥#NCu¡RW¨ÍÈZXt5ÝÂq‹ñ$˜¶艿ʜ-Jë0Af%,Üé'Lãéî&ü-ù™®Av3{0FHì¾ ÏãKð�£ÂÍ¿£…ëöVЇæSè>k \)­¶EZX¾I®àð“Pûè ­ÔB׿±F£f*x^…/?ÐGª¼ï�˜DÚö:ÛrõÉ»‚P3üоÑ!ðaþ1>;þ»X §7…1ÇN2ìy¼×D½ £ÁÓX¬Ð~ E);à¨A>y—H=˜Úü&‚JÕ&ÙQªàú Ÿ»¢”‘®kwdþ¬—‡ì PÜ%‡îEù#gþà—?ŠÜ+�£¨ÙT-R_±„ö«–�ßJ äËÍ]tXNÔMôéß¡·¤Æ%rÎ�]ÎtˆÙˆßíÏS»]§˜¥µ½lü !Þ³²´qïÚœ6;…}„ÑæÂ;¶@ŒÅZ(ƒ¡Z%Z¡ºž$‘äÇ®[O\&rÙÖ¹,¬eKž¦c~�l�D]L>16r�DxÆúóZÏEæ'eÎŒB³“:½ðFƒ�>Øþxû*s”T8O¡Îõ«&rÅ�¸Ÿ`æÆÐò{‡Áϸ‚*«ÛC-_–{¦Ýœ2†›ˆ>~"oeÎA€¦+Xmˆ%BóÌp�Â0­Ô!��oˆ½½,ÏÎÝŒ„ýiX'º“ts=èŠ6F9z½ö‘¹6Âhûcäøjq.«¼†üe\tôíeíÀÍ¿ž>zÁƒÄÔ`XºÕwº±Ø´í;û×g;<š¼ù¡˜Å¿Bù* ñu,Þ^ÄZÜHÂJ%È«èÃÑXHÖ{ª¹ÃDîW¹ï*A'nÁ7éÒöK(Tù—è Ãy³ª©N³1þËD÷uá�u®¢òKTŠ¢viGèÀã…DêSùù¤Ž½FÂÖ;²Õ‡�`ý2/´ù)Š ¿öúó‰˜óUìh�fÅW]€*•Õ¸2 �üQ&ïÌ®SÇ¥g %U”»~»4|ÿù�ØZ´Qíé)K­³â¿»ÃÐVëù¸b¢ÇNn¹ ÇÌ©k˜MmÄ]æ¢ÜÐ@#fðB&Œ’¸1Y8l[JwÎ</ŸòUî\ç´¥ldaöƒÚ5” •„q†ÁG¬:–HOξËL[û�üÙ¯úÅ»Ñð‹ÝS¡CV½Ž!É1§ðÞã©@fÆOéÖ«¿3L¬0tÔóîdÉ_‹P¡R÷í9N$5#ȵiq´©-˜¶ªªBEŸü|!@ü9‚|­¼ô>oNÞÏóÃA‡”/‘cuºÀž&ªµÝ&ûLdÐ]x°®fL–;%¤¿Ü¶Ûcsàv¢ˆ[ÊáæÅA8ÜaÊ1©áDü@Ë5n¾©1ýcXJë—Ì'3ÕmpQÎ�-Ü�}ÖA´mž4zšw³Kõ>ÓÝ k@Ko%˜x&÷Ü>ÒøKÏ0A´“nâœÇOŽ‹1+*{ÿ«åí3°ÁÍ \Ò¿ç#<ø:™ÌjM¶ÈoÕ…?Þ—p°L%õ�ÀøHVy›Ó†öÏÐ{¼��‰J!ÞšväÑWîLÛš°x þ箉ÜuÍÈι»Sf¡Õ�DÆ@!*”a€˜-Þžè‚\sü÷EŒ/t¨�¹|;2B݈°|<,ÙÙÀy3ÞDÎçîB=Ñ(¶ÛOî*tóTV ƒÏ¹dhf0uN8UtfÙ¬/·ÀŸ÷ßÕåP°<‚òÏ÷3ë(ÑÊàà¥ßè{±}N. *˜ë1á¹d.Žå§£¯�'.ÈówštëÙQÚUG¾>½8Áù…Ìá#UtŽÕ¨Px ý ²˜¨sÒ2'˜RÙÊöuðIr\Ù1­„¹4•ƒ/´ã‚’Rr(Ÿ«†âo}u §VdÒN!|¦ì*™MOâ è÷:v™ù]<û+fx ñçÎÆ­ƒgé²ñùè‘ÂÑJ—Ýtíårvhm.ž­¢–¶Ä¥‚o¡q(ЦI‘Â×ñÊÌÛÄ1KŽ= 1^nDÖ®–,£t½ç|%þ0I['¡Æã3à¦QKÜ®øP7Áaöž¾0_·]”l¢¤}¬õ °êrjÍÀk«bß}pØϓð‹ÿ®‰â¶•Ù³d ÌDá°tßðœŽL ïf1\r/„ŽHkÑŒŒ�0×ɾ^ fx$wqgYüðlÔ3ázÝÌ‘¾3¸]$Ò!•†é+Â{U!ÌX�·$M1ýà4ô¾J�^Äš�Agë;âBócÌŽºXk'Ìw¯kfŒªrÈ£Kw »¤ïɃõú(šöY„knz–ÓîÚJ¼âSé¡“Žf›B�ÑczoS4ë&/D^/‡·.ëp¦°3Ó/Ôz‡�EŒ¾>¿E6”$ÐŽUX" Ç÷ìC±öóý(пœ�žù3aJí=æÃNqô7Àµ©Š —ü’H x(î¸e÷r¤ÌÀøäih7i/ê&vö¹ÌäôÆ+Ë»�›?�§¸" îf³+O%À‹ža<Ö½•s¥b6~Ý€†š×I‘ÓNþj‚Ò*7ñ¦ç{©¬™} ÞBòUbpÑøaÂIÀèôH*à‰Ñ]дޞ�Jıéý7d3·#HÄbT<’Ó�ÃìV½5äÁšù°Èë"‘üv ¦)‡G¬wãôÐB~H·~Š„Çoi3A8'ù �6€Õ 5àÛ®ôÙÞNÐ1E©Ëø³ œ �=ŠÊfƒ¼/ÔyI « Cfè¯bÈquvÌ>aÞ[ø ¡Ä½QÉN/dWÛ—`RµxÅȱqÖðÚù Û21S‚œ Ùw>ÎöPµ…—!}­/Í*bðÂÀcxo㉕ÅHRn ±¯fþC#•t²·N€Ë=²ŽäÿÙŒnö7ถ1)¶¢k?3úó·b[[+¹ñî.ì’ %_)ãÑŸv ¡ûºüG ›ñŸÖ/z.µŸÙÑÔ‹B�úØpþ9ü•V 7ö×Ü`:žõ�MKÙÀÌZë¤ÉWdî&üç�ñô§ïìŸ 'ˆ'›œ¯@5Ÿ¯8‹óœø$u�ûöWinr:?ì ØZ(éûI®Gƒ”ï`ÅÃ`~_!®yaˆöwâàäw 8vÝ> Q©Ë1çª#ù,uŒîý}†¾<�³=3Á/²¯w`ât;<.PIªkaV¸- |�q³ÐÿQ2J×®!:³—ƒÊîíd"ñÖ²—x â)51ÛÊk5ø‰^­Œº6¡QÕE(T$ÉÖ÷Ù£Ÿ[¨çOØuÖ¯¨ùڲѮ –K³Wo<$k`¾y>žXÕKÏG'Ó@ŒÜxöëUÒçå1ÿÐ¥܈Ja<)ô‘Ö[‹»l5‘y/ A>�ðÇa5Zwí›p–.)ÇitØ?�HÊŠ¡®¹8ìÈ^„aå8Úu‚èÌW¥çfßdïŠ\ÇÕ¢¨RÆzúH*ßZ‹ÇåàÚÌgxç×r, í`}ÇÃAûTÚýK ýƒt±L'1×:eYpá¿Et“éR¶Ì­ŒN�ØG�¾4…e’áîÏúu¤Λ¾'kÛþÏ {)·F€ßß;‡\Š;BÎe‡Ñ;¯„a|®ê‹i± § Ë©ë°wX7D�L§®¶4àþéÚ„î÷—³«¹ÇÏë’îÌr¨ÿ.�C]ÉDOñ?ºîÔrzµÂì7Ʊ™ƒ· 7¦šáµ´b;¬þ·²_ã/ñ°<†K·œÇ»±Òü¾ìvœú\šQf²< ëÝkd½B�¢´~9 ooƒ I�´÷D0ù÷+†€Á ¥leÛæÓÇbÑ('POszVbKI<ý€Ón�ÈÏz�_[‚í#äòQ#xy:oÏšLUä–R£µUxH�â]úšì\¼ÕZµåG©ÅWàžûÀ9g�ÄØ.=·<„�‹LhðÞdXÿ ®>,¿¾ù ÿá<ÎèÇÁs‰v€¢NSÈ5 ¥pg¬ O%v³gãE‹^vûæAЫçÒ9p÷[2úªŠ`³KtÛH¡åœã–7–ҧ烅L5_· #fÌÃàW?IÕñ��¡ý�.pV„JWO°QÌ�ê{ÇÁA£›IsÄžÝ_@cc)\Zjɱ;9Ý ñîî0¸|ð Ù¶;™H¯êâìÛqß¹.„;ê íü9z§¦Ò"ó2?M ¾^iÙ‘ tÉ/WHy5áî6ùðÍ­»>Ñ{#{ °ñ,hõšâGée˜,ÒH¿=~ §Ç¯`óÙ•ÄažÜr·GI�(Ú¡p�ˆþK�»6+hÉ’3hŸ÷ßDßTÃÑÔì�u¥w @'»žÔŒÝæ(+^#ÚKN?r!Û”a͈û“�À×äÉR­¦¾sù°ª?•.{úŠôÚ¾†M¦D¢Z ŒÎ—£î‚ xëé;ê'Çô&öâ’¦¯L¡«faAL|Èå§ÇV“Ð?á§açƒW¤A=ˆšæ€ï‚:FyîllÖ&Á§åPÉjÙxDúƒPàC‘¾& 93OÀú †ýo¨�&ç{Àö€fro} ñ2ûJ8Ó&†Á™ƒÖÝntï·s¤Î¨®íUÆ(ÅÛ¼Oé_�7v†z)DbÐ{ÔxßM€Ÿî'5ˆC©.M³%**W‡4¬wOáUZ0eÕ²÷g jŸOôräa``<ÔËK}؈K{„øîe à¥`NÎ'V¨ùÕŸ{}?€ß±J²Ml7N©t ŠÁAÄù¼¿ùµ O¥M—>ž™K×ÌA‹3›1ô¬w³á9ºØøuPŽDøÌšHBÒÐL%¨žŽs'ÿ%’™YtÕÀL½‘AKVÂõ¥!4³˜êÀzÊ7BJéÇ\$C çwÑË®…3EÑr\ýõù߯€ÉýÈš+q�>ÚÁÂÍ›QLÿ!ÚjŽ5ÑGÁIY‡÷ñHÉÃkðù§¶…ã¬&è1Æ%ÿÆÏéç¡c¤–éh¢äYèv ¥¿O`âÑhh÷ ×]¡KßÂT5úw[2êGᓸäVŽ$hÌH ó£nÅþóÂë¸ßUâƒÖÒç@`åˆ'ÙmºˆU}b�¿o×~oñè{ÂK™Gh¿S=ffÎF·¤k(~u.ªÔ½¥ÿ²…ø‰NXx&ݽK̦ãíWRxö g$ÿ`—ôNÂÚ{%ì‰8ÜØ;¼ÏÚÂ=SMÞqŸŸÄèìNàzrX 9 ”÷¢&¡a¢ª¼·À¶�_ñùÖ>ª®$ÆÝçqߺ1v1“0î’–‡ÙaÎIsܧ�K¢\£q�ô\iCKvÌz±ß8jâKU#²·%œóÞ]^�”'ùmèžg‹§Eã$ïDšÖâÚ9Ùk|^ZJ3ª×µŠù©|ï l#z½IÐø"Õ¾%3»­¦�m)¡^è$É=—‚ëø&è[�/Ê4õàÑ¢rðÐ;…R÷$È_gMþýœå´Tn„¸ ƒˆgdðlã-æÛb¸ÅÖàÜÈ` g¤è¶zo2dØÄ)Óß¹c �^Û‰Y–Ûù³åVR±ø&bu*2´nÐúj0¸-ÜbmðÈ`$f�”“³i€Ö@“c¨—å~˜ÝöŽL5{AÆ:â)„¾ƒ‰$jÇúSÐÚÈf¦ÊNø3*$ùwRKSN�]T}ÓE‰¯²x¦A÷—²ñ¾>Ð8û3ûãË[^V½?.ëDó0쪙O6— c¥Â ØRñ‚ñ.ã:¿ó q^ÓPÁï6]T—Dgk•â_ÉDK}1TkµÒŽ�Åt›\ )_¤}+^Ñ—`ð›µf­œ Wv=b"'ã¼ïÿàÌݬTÉäðÒ�èæÙ‰/.�‡s«Ù_wëÑ$ÊÕÎgaÿ‹V*wvj›2cþfèÍɦ~ª#¸qf(¸~¿Âîµ ‡lVŽ®¦Ê \ 1EìÒÁí8Sü‘¿ª�^i&w\Štô zéZX0Í /m~Sª)jÞI&ÂûïÁ÷7Bpì�½ïðëÛ¦â~EG²SÇL޶ÐÍZÑØµ¼VÚQ›`öæøB´šØýÀQòz¬žØtÕãŒH'�_µ·üáÕ³™E¤ºv˜­Kü >¯èÃ"‚§jˆ�’¾_ƒ�œ·Ãó¡Ë°ôò æTÅâuù ?=Ζ¾³dÛžE‚§ ÿ‡§žÐ®¢Sïj¢™ÊKº<Ÿƒ�q\ø-¶cî‹ÞZ†„窑ì¡ø®¬‹žü&¢~�Á¶Ç=ì‡w´²ŒÁËt9í8`E“†8ªŸ�P¤ÌØÐHœóŒIð†³xêHFÛ[àÙÉôÂVm<²kÜ¥Évª ýÎ’ËÐNþ JÍš�–Eº�´'3:ÞáÈ w\�ý+úyûR7‘ßJÀ¸íô7�¢„ëøÝf#õ~L·ÚRƒô5ØÒ�{ÑV$†ìëÉj+Ibø5”>蟌7¬C ¦§{Os0ø‹æ�SZÚþ‡ä|`±”3¾œ5#!6TW.ˆÊÒª]~T.l‚3‘ÞTUÜ# ¶Òl�c 8¥‘¬ªã˜ïކ¦æGT%:€ùuZ�\¾$Ìj{a!ù@ß“*b¢®… ÅŽà§a„ÌlM”Y0û Œ·äbð¼ÝTgµ9òïÒDŒ�õ ¦xWy9=¡§€Ó?ÌGã›?`×gM¼³_˜?çÖ Ié¥þ!øéÔfT~×ÎTkŠóÆIT¿ÿDŸÇ=¡^ÏbIq)ñ›ÒK†nÎApy@—ÎÛòUö0îx$š¾÷„Ø9®ý˜²†ÃP0Â�$þȇ°eqD´Í‚œMdiG…^ì¥ä¨ð4x˜aL*y2|»‰{Ü�Oæõ†Á{ϯDåö&˜ifŠI’Ôsl2®œB œìÀË�ÒYyMdsW9Ñ’ Óó`¤®ŸÚOd�œ* änašÏíÄxù#të¢-8ôY›­ž·7âKG!®¶©�d\ˆ–‡ÿ+ÿL {ºÈÍÂ3è±²•9ª’IC5Tɤ~eØ:›€„’dúUPÞkL4ƒféUDsÙr(–'¤Þç2ü Œ¦=ßòaÓb þe× g«[ˆ‡çüc;Φq‚ªœñà5TÊ�ä¿û¥ÉÖ?öÆY_¡í„;¨Å­!tµ–Cƒ«uhüÇ<íþ°q_#™÷1ý´²ÿ,mx©Œ‰Þ?}ZÀîôp!¼ØYTQw#¨Wm¡å2õœÛ ×"‹x ¢_¢ý¨£Ö~˜×Q·®}\ÓÙ„o´÷€ O'S{RGn‚âüºêØO,Ë{C]ÃÓí™8kõÔÿQpÞá\~o7"$²2›RYm Ϲ¥ˆ†UIƒŒÐR‘Ñ”‘¬PI’$"2Êþ<÷ý‘†¦ÕR(i(IËWCñóû÷¹Îu=×9ç¾ßï×û:ÏspĈå¨g'jžf‘ÃP3¸¸"€~¿n5ɯðnÎX~“WÛ½O‡šfÞœÜ>�A5OœE+øU÷ºAÛ÷Ýû¤ï™€Ý󳼬ÞÒÿ«É�ɆòöSï+äžLÖ_úqÌ—¹ðgX%»ÿ.(ʲç†â”V}˜ÄUKpÇwwê^ÔÉF;Œ3¬=Ñüõ¹z4ùM5ÿIS˜MØ�.�¦Õÿ¡ò¡>æÜü�ŠÅЩÝÒp]ñˆYÒÎ.Vøtu|t¥©»e蛡Ô^Õ0“àéÐÖ��Î>0³ú³ø.‰ 2Í‚óªSI3è�iÇîM¸ÕBiHÏm¨ãò!Üm=vÓzÖšäa üÁY°x¶7]ÑÚÎÌÞ8ƒÏ9sõ’Ùtø¥(,Ï¥ÁA-¦þ2MoVbÂIxQ¡ 9ß“é{Î9úSwŒY÷íæex–76­§ýêQ”àzóæ)‘�º(-âÕg,¤kÛÜ"âø*ï7o]¤@®­ƒŒËœƒž±iÔ&aº‡´aŒ<ÊnFÍ™t4k)Móµ‚᳿°Ž­bpåÒ!ò2üˆW×R‘޹fDSå®b³oj5|¤ï¿ÂƒN8|ö0ôÍ+ÊUás®†¥«C¡¿&¼’¬Æ¿ n±]L1»ƒóUNÅ,§StGÛfJAõØXÚ)¬ ìg·ñXêòŸ{ îúø‘ÅŸbøýð(==f˪÷ަÒw6&×›šÃÍ –%Ñ)Gð•�(ü¸v¼Z×˹Ʉ3>Œ.3/ÃÍݰêè'6Üx&Ù^¹���2`å�ç¿W»�0#ð(3êšGÝ�çK~Е1aøYz–Ö#ÝÛÆíÕé´}w€«±Žàø#^z†“@t<ÒþÀ4VÝ£Š°ä� -Ë{ Ãú’éúûrÖ»!‰lߌÜÛAJQ<θ”%0~½8=.`¯ófÂþ³¨@ã8–J€ò¤‰ìÅ›Õì}»#-*Î"s¸J’ ¥x0NÜ,þá-²Ò³c—ÅrG¯™€}�•yºôÜÊŽž�h†‹˜¹SŒ÷+kCF£°`É*ú�ãXDT�9£¶—Hùª*ì> ¡3΂ͽ 4{Qkõ’Á!G)ãl1J…Õ“ÆÇT–p(†z[Ç’ðm7¤�{ZeY £4+©dÏg�0“£¶òLt±Õ‚Ë1ï`ú*MÖ¤²�-xNO$öC\P v¤�‹Z)X[µ�nvê‘ä^ .N§Ëlë”8ðö5 ßÅK ³]�º‚y}K �L`2=Ñ$,ž xe1<7œŸëz…º% 'ŸÀïÑ䟿Æžšj‚ÜòÇàG—AÝEb†²Yçüƒ$z¬Š�/Bü÷ zéÓŠ3óXO€/“6˹�SáæŒp‡É¿æ�ámuv1:€M-fSžAÙ€›¬wm"{Û>ÄË¡ªlqE>¦l€¯/µ@ðð<™´UËØ0QuuΧ-ܽUe6²*æ°·= G3®L†­^Óðlw)ÿAä55ýÕ?“BØÝbLkk±Õù ¡w¸ iù€®ú·Æ¼z«MØÓÜPΩ£‰g£Ñ{B »¼S’2?ö Öpù¤ Ž•´TÍ­_'ÂÖdxtQ$òÇš]ãälpÛl«¸W›‰Ä+â¡]Õ€i¼÷¡ÎæÓ ¹—y2sš”>ôŽ‹þ&–Ï6+çÒ= `†”¬›N3oƒž—ùOÛ™³¤øÿ6©“ÃÉPæ¦?‘ÚC$!Àý/_R³—nàoZîÀ´SîôìÆ,ؾ¡„. €-êÊÂú×mØè’ kÓ©£ä4)¾ê³8t ·"…kIeÊgp^Éò*SÄ‚Ñ[^…Þ«Ú‘�õr;µ–Kž0»c+ÁªõnÑ‚/Yx9Ü nŽcQŽc`ÔsWÒ˸Hæ) ívƒ¦xNrœ1U»ê‡uØÞMF´=ò m6—&Ãô‹P¹n–ps�8ÌÊÀ­bÁLWb/ã,»èß°/0õe;w"xˆõc)ëô56ur$ |Èzœ¡ñ� ­�»ýÖàÛ®Ùœíº_ì;Š|œbx»‰Séžm $4³®Ç~œWÏ]Üô™‰ˆÝÆø»WÙüPŒ·ô/Íóo›ç}òN;*jîÖ¬s?ž§×¹Õìt½,�V5†€‘�ü–ª™�¦­À»xçâÙ>76sÑBÞÊßš6¶üf¦ ¬)Ö•jûѪgE ë"Fyá£á‚ç/ÁÑóÊQuJg±E׈¢®œÇžÈRÐ*<6Š/دB:TrŸÎ\”"®â-K„N÷¦ô ·Â´½'Ðjã¼þ7-êºYíú}Øå¾�5õ å h.aN%Vreæbìs�4ìy@Ÿý÷`åø…ôºÆ�—mÈaƒWº©·oˆƒÝBÙÜm‘¸Ãø3®E+WÝ3³TKgEv{ÐyÚN–Z,,ïŸÍ�ñ?v ¹¸|Ù´‹�òw|/²›û\hJs'ÿ‡bñ'È%\T>ñ=›õ3…vv®"�ñxÇd>u¥q¢°Ën99hL4óâÇl€9®ÅäškÛþDòsb4qÓr½*û"Cx½à,ÉnÌánë'ƒ²p3S½QËo¾ ðçõn�zÏn´)CϨÔù–Gçý(~äL°tŸJßO.ÃÔ=E¸Ã)‘¿ ��OÓ,,9“J#¦ÌË8gˆßÛV‚Q€ uê¹ñÏú¤'ŸóuSwûŠû�‹ýº‰,ú]YÖ"E¨6’ƒªÄïÜú«†0ï§$ ¿ÿ¢:i™\&�w°¿,š}ŸÐ::™ÇdkØ2šÍ¶ô'ßÃ'x5õ.ÒY¨Ä¯®1%õbEás3VžSŒži®xÈŒ)¦ö—¢Ô÷î÷a¯ .xïÜ ¿móŠOÒ=g˜î[ÅLwÒ˜?Z¤oöž7 ©A[Ñ%èâ%G Ú½˜î‹Clç§Q”üï;»ô»‚t /SLôG¬oG2î³Ñ'i/VÍ�‹O,S l¨Ižü¬å$üJyÉ&QáÙÞ)´÷ÊlHîØúýŽÌ%†ÇÝcî²E¶?y¯×§8ÿxM*>¹Þÿw›%pWYC®¨PìS¤.YN�6àÓÖ‹]Ñ×Y¶A-'ïÛH³à2Iû†QhØZ<ó7õž­²˜ŒÞc½Ø‰jw ÊænÄ_a®p¦TDAü^)Xç·L[Þ2·žñtÏû Êl�‡Cÿáðú2nW‘KQuQÕ�Ì’­"ì�7/÷]Š? ´+À®o8ÄÜÕL˜ö ò°ñœ(¿WDNÝNe}F²Âˆuæôš†üºfbm¥ö„æR÷‹ííЂù'ty©CÅÎoOq%qàÚ–ÅÖ8�ÄãL~¤ 4ª`ÂMUzuE÷·P…Îp^ƒ>1e̦í !oþkÀýŽºÀ„“©s¸‹²žfã¹óÜv)#ºoéCqö¹8ßOš6ü ¤0H|$ømÕãú!ßÛ°ŠG¤ÀÌ25Tÿï+¸WDº©Ã„ñE©Î™øþ®2´”Ô5½QÆkVO㮥s~†h¾NÕ¼5dbÈÕñd={(g}Ç‹%páÄYè5׃]OÏÒ|ßÙô±x»¹‚:?XѾ�º´ÙÉ—ªÏ$±'¾WØoõ± V¼¶nÙw«RHnÙiV ³�¾—´jHPšu4®ÿ4Öü÷׵ܛU?1ïuÔ–u³žìe8°¼ŒìâסáøÓïÖ9ÒȯxðŠ÷l¢µŸO“ÆñÙœ¢‘8Åÿ^J%)TR;Œ­�$Y5F�©- ÓGl1Û—%`9ÙZоT šO…pƒºú a ùçï’ç+!¤°Lº1ÂÀìi¡>}M±ƒ•½oÙõ»oÑùùtò€ùpÏô£Àönš`ò¦ùŒ‹¨¤ÈwÅ”"J�È9^Âýç7ÀzÖlÿ ŽX^ÎymÞM‡x_:4"8ˆ›w�S‚vûp3¢ƒ“o Ù¦t{Ôyö¯<ª éÃ/mP7<ƦJ¥íÍŰI¤'÷-¡ ¡§¨pJ@ý9:tBÄÜk²9NÓ…³ƒªÔ{u�›c;ümõ,£re3ª6Hò£ýldìvÃu<ýXUMs¤÷â©9ÉXâ“ÉÍ�‡çó²ñzC;ßxù"%ÄÀNKŽÝ\^Å„[Âç£+°aà-ö»±:ÏgünÅ œ,û³9âãñG}>õÏŸb ¡ä‘pò8'¡�˜v²1y.¾Æ/�}Àw§,¢kÊnxäg ßÔBKų̈²b ý^žÊ$t‹)ÿ}»z5…žÙß)É@4Ó¼Dßöœ |•{ÐäâO5Ç@F\ÞùàŠ&XJã%Ì¿œgæ÷~ ªZmv9ÌÒ7—A¾ç frpIl·ñ+bðïv:Oœ`åÂP<|}.w3y<¨:G3©{Ad�,d·ÏV’™ìuöȹž¹7Ñ2Çã41ÑMð| G›Ó‡ƒÒ æÒÇ ‹ªÁ�!+aãÁýXá°Ô—ß§"{5uH¿ Hn•�Iv…›dOm@Eý ‚âOÃ@ñÑFJ6iÅ�žcIùÁ<²Ø€¢5£H>GŠ›ñ¸%-zx‚´×ãI {:Á»óÆ‚4ÈJ¸J{÷Ï!gu¨ßÕjÖô€K©ÛŒZãfQ´ä+fy÷÷ýM*xí,æ{²| ¹ÁœœràÅ¥Ââïâ´øÑo^Ä�‡Âœ"þq˜™|“FÅõÒÙÉP+n-Ö!ó-(݇Qf§�¬úŽq’6ÔàöÆO€{“1¬"ÂlóS´‰ŒAM…#˜kƒ�×,¤ÛƒìFÇ(*Û«ÈÒ¥6à¼ËŸ¹Õ±—ýb¨³&„ŽˆÌ‚vßJÓÉgî±2Q?Jo‰csŠ‚±Z|9l–)�)éì¿Î=¼•¯?&«�…ì{®Mò7â—ÔÖ¡$�¥Í§Øi Yz3 €†=Üåɧ‡|nõœ=ŽiÑ @gò,X¹ O[Kçç"÷àí²Ôìª Ï5› /ˆL}Rth†º²Ù‘âï[£ýç#Xz‚J6 T.™ü J3b¸£‹U阜V/z‡?Ò©}l<çbu…Í(˜ �ã]aË»Qæ§_H±ôQ·ØòÅæìÉAµªŒBŠoNá®Ç`E€ŠPç~ �sV×B¹½K.s>º°c.²Å·ƒ©dÇ~°Wä_mezIf‡ûÀ�± üù§ù¸Áë.;¶µ”¾?¸ÀŽW¤ª-[¡OõííÕeFzõÌX?�™zއIZY8º*Z>g�Õ %?3ó7Øo·0¿Ü:Þ8Ô7Ù�¤ôšóƒÛá—Œ‡ÏŠSרJê}¡M«‹�ØÂÇzvßU âˆo÷Ž•‡[Ð6Í\÷¹‹X3c hÇÍ7¸àD7v[ƒ‹ý{Œ¼`®üã½Æ�ï¨LP>K‹wOb†=³ÐF/ ̇­Æ¢®xúbô ­¿×sÂ[lLÎ±š”®Œ$S�Q$�u¦ûû>à]3˜÷ü=² ›Ç¿ÇÀÈjˆHNÀ Yßб ûíf’ØqIóž'ñLâÍJ<5vÙÃ–à±‚Ø +S·•GH,Ìœ¸ü‘0xc”p”ý Gßâx6�…‡É¡,}¶®y©û(ê{¯ò2q,ºÉ€òv…RÙGÈëÃz»p[°‘Z½cÈy•7w©/ÏÆƒ{¡øM›P¨ ¢ï¦ð_ö?eR-®à3i%ÔÞr£¦á�Ø‘¿žLüÈa6þ ó5¶…¤xP’ݹy”Ÿ˜´›m»lÆ ¥¤I~Û(ycÊA\CŽ6F¤±Á…R0lß{Ôma{³Êid|[ð;‡Ô=%ÈíÂJ:«Ì"wõÓèKÞøvØ9x¯GYÉ=,àù-<Ð'"LfÙ4aFÓX45v¼„ÎÈ:¬ØJ;6®#~ ÃÞsKéF½3[‘}'«G©an|�ø{¨~1ƒ&� Æ Za;åP\¨&ìÌìÂå^_pÙ�\´‹"Cn±Ûæ½ô×jz¿KÝÊï¸�¿gCÛpüCµÜxÂz7þe‹äŽ’˜‘¹œn¦7k•`iy7ŽNwc³Ö§3ß²82ç<^þô”*%�àWýu®êÅ9¼s½žïÍN…ÛÃXPÅQœqO‹ôž¯%«Àwüí®oL~|¼xŸ‹ïv\_yŒ\—‡ïTaú¤)t"vH>‡Ê~ g9ÃÑ8­ÑäëtâQäÒX¸x)þZѨþLšt®A>kvŠ�™ö%°4b„ùØsÁCWš6åÆÒÓId|\ìûöR‚—.ØW}`3Å6cþ�m�¾RôZîpc\n± ÅÏ|DM7${Û²‡"áMbëÏ1;}�~žëÄ¡lÀPÖ,Å{fÀ¯Ñtö:£�á×Ùå ôAr&þ‰L1ó>ÝÃrÕC¦ûZÊz²v˜L�ß{i@ï§B³É¿ì™{Ê,X«Ž~j­‚Wxn‹³æˆÓ¸…iLÛZ›˜ût¯ëáR~i�CøJ9øŠbóœØÒË"À=܃šW%èÖªxøßÊïM�9Ã)’@Ù$?Öäà¯Ìý¤³/žÄ×C»ËF¶ÀýóÔ S‹rÑ»ïç1I†ê¯É“X‡ü«¥)sZq@1+kë0õóq>+û6q¢7Ù2cý“~7Ž¡iE×Ùô #ØÖ¹68Þ¥›•.‡Àª¿ü¶Ö´àâËg“ñÀ†ûè2U¾}iÀ–šÏUc ]÷è"¦cH«ÓéÒšÕ4¸À�s�˃soö;±“‘)­²”†/{Š'^ ±3ÈX};ºï¨`{$_C›ÍP)BvůؼKÊTÕ<O¦�Χ[ž; ñ_ w\¬™;Uºud\Ç ‚,žûáùÐtmÉt(;|�››FÛ£ãXÁƒ`üì3ƒ^Ÿÿ‰�™NpRrEß‘æ£SÑ'bH 5·£jêmN]ò;Ù×Á²_uáþ°8Á¨eKÙ¯I4ËSŒ©U®$û¦#h¿D VlÊ€ƒO–ÓÄÖ~Á¾þ?x½¤•2‰=®-fz±{¨3hפB«Ž |VÒ!„ ­hÊ¿_ŽiÝVp°$âÇ'€öïäW²rÌ'1]æÙlŒ«ê'0ƒîH–Û¸W�†R¯³›é¡Ðð¦·zGõ2T  †î ZÐÍîÌjÑ1[ wò99²WYK¾Mçaš¬l¼Ò›_u°ÄÙmXs( "[§�÷ùQdáSÌ®Ï7¡LçNî@ƒ˜l�m%]¬úV&ù ªaij"X|ò2+~»Œ_6QžTe£ðh$І�NöhÓvŒù¢bÎßù‹k¬�…½=*Lñ¿9(ã-#¼øÿ²6å³S«Ù3«|°ÞšFçú”(»:VÆH£r­ [1¬—Ù;ŽçA¹'pÂôÝpåÑd¶Ãm7ó»<4oÝ:¸p´‡© cUéÃHPÞ  0+öÛmô—,ÙI\É <·$ U^Ò¿� ¤ë4�wmsƒŠå/ðË1'¶i¶ Ë”úËÙ©¶ƒ@"›Tí"ausofùB‘© ¸yÒ¦ ðëÌy&íz–®JúÕÍßy^W�¹=¨ÁÖ±¾¤¬òŒÏ§ãõqçЦ^� @rþ}ÅÙ+èhk5,þcdÕ±ä^5í{i6�Ç‘áä �ud4ÆE’`¥ÆTº9œ¦ºl…óVá0í’4¿+#<w8¥·ëÃèÝûðÍåƒ$i4�ö»è›{Ü� Ü•ìWÅY2if¾eÌbnŠ­;iÎW£ïœ.í›ì�WÇ yã}áÒ§#AµÒ·ÎÜɶ·&‘ѦŸ(úi�.ªåEŠC™åö´CÆ®º :SŽróî{PϨ§r:údÂë«v°(±†�x‘Owßô‘ VQ)'CJ#�³º¡ »­éñ&3Úué9û&ÐÔÌ<ðÑXOQ�Ü-¥®Â©‘ª¿–SÆóLèBÙlÒu> _FG1©Ù²(ñîkršH¿¹X(\^Ãä?“Õ>lÞ,evÍôž©Ž“¶^ÃX÷ÿ76—|ÜüéÌþþBÉZ9 †7O£Þ_Ú”�Ja«É-÷*º/iîo™CLY’�5—÷.£�/®B©|íú›Nv6šÍ(È$�™0f½:×Ü™Ìøõô_…“ËCmþgQÜé:F?Œè×ÂÓìÇ„"êï˜òéêØ”…⪸¥xßq“`ä·XŽèÿ77�:Ê6{ø ÅžP "Â�šú8-PD¸Wø—^ÌHdfÑc¡p¿Be­•7Fßþ�$/¤•\þt&VÛ?Ü,Õ¾‹ËTI 5�9°:K�dÈrãßRÉ�lãÊ\Ò¿¿‰žù®¦ùÇ´Fd.+ ûZ-ÑV‘F£éòå=°kEŒyú…^�.æöü¾ÁvF~ä>x§ªÀ[‚ižV¸ã—8då¹ÒüIÞey‚/Xùܽµa×à|¶ÌîºÃg­Jš+m�!ñ¾Ø·ú>mù2�^”µÁûî™æ?mDH×ï4vD©ñÅfTª£œwšvoÑÇ&pC4K¡R«ÕŸŠ¿í±¢i/:ðLàÜñ©ŽE¦�Æ÷…À8c<`hÅ·ô”P»Ü0¼þ`�ý‘°# q h^ÌjŽçs¯›KQA5œôüDZG’_éÕGþbÝxx3>‘ëú¬êcžÊØN%�?6`éç/ðúÉ\¶ÿõºñß^t)Œ€gKŠHó›�ÖŸo¡Âó›éòê«l)~$ïÔ÷X–ÞA¥e9$3îŸøïÊfÿ0S쳇b¯ÿð¾°6(úâëÎkÐòí{àÑŽ³v�‚ ùÏ,×¥¥W$³3['P‡#�3<çÁÜ{ûh`#|ˆçUó›‹eñr\Ù~ï$Ådmˆ‰îý}%(ø1‰Ró�†(Ýnôñ'}‘¥9zÀöèå7‘e�0·|´ø:ªex°…�i¢ãZ’7‡j;2¸Ë›�ùÎ|šT„½‘$:Ñõ o¡þ¸§¬}S$4�²‡Ùs@çÃèìž#­à·'³iŽfKô¹–%Fæo¾¬Å*É…ì�¼YN©¦G:Š.iî‘¡�…ð�^iO[Wõâ1#b2b-\Äv_ød²y£™Å�Iæ2aÒ�c�C÷æ–âCoÜú5„ºešXؘ8YÅ]Ø>ÝòÞF³[þGùû¡'¹¼+YÈIMsÅ®B>Ø÷6_Yø�T£ÆCoÃVVh‰Û¥ÕhMؘ[íKó{Ç ;å£ü ñ©¿/}ÐX‚š{ŠàÏfsãÏU4Lä9̿ŖÞxÁFŒ»F2‡Lð‘ÄZÞù6rZ"îðNMƒRj ©®1†2 NÁI�)x'Ö¾®Ð§_ñ™ôYC�Ùkȳo?ÓáÆ‰~ÎðÍ#l±q€¤˜Ô–>HÌG¯õ¸q­f³L÷|[È=)MaÛ£¿bxÒtÊøŠs£Ó™”�ý±´¥¡Œûñ�ƒÊ.QžÆXã Ólæ]~ìïÜ„»Zi°MØ:�JPh¦æ °}5lM[òÎbOò€YèÖï¬üAªí<' '“ÉòOü÷Y P«iÛJi“Öº&³$ÓÏ,;,�&�6·Ü¤DãßžåÓžÝÄsùJ`:¹›ÚÏRú.#úiÒ‹dz˜gIÖOÑ"µ{µø%ë&M™´Ž¦”ágÕA“¤À‡°zÅzlXõ4%ûiâ‚ϸxÙd6ÕÝ ¤OŠ˜Ôü†Qý/YÜàN‰dõÅ9ìµ� ÃQØÒD_¹_BA�æð{;ö@Òµ ´#D&å=+7k$ËÀýÆé¬|f'_=^ŒŽ¦/¡�y•èËaÉc²�³N™…Ñ�þÓcéíà!lÚü‰…mE‹Â¢R˸�Ý¢Tµ±€ÍuÈ�ª´{NLëæïy‚éél˜©ÛÊvÆß`ïzÃh¦§{U´Šl=ŠèF¡¯ŸÍnw‡q¿ècšhFPÞô.Öý{"÷Ûã* S9Æ|·–Ò¶eÏXÛs:|ý7o¶1Wº”RÛ¨)(Ú »Š¼ÁoϺ¿=Œ^¶½ærÖ6ƒ£Û×Ó�³÷™Ä¹85!�’�ZÀHj¥!›¾j½ aÇSÁËKb4·Y êt„YŸÔ12Ýš`�;;ð�]Y<•q9ÉÜcŽ`ò¦ÑDô3�ì(F²GnýÌNßž 2ôßÞ§±>çù<ËÕpk¬¨0iË È¬•‚}»/ÒéUVøôg wøÌK<2ƒ.õpAO¥Š°Ñ42?üåÝ{‡øù¾ðË ø±/ ê7ƒvÐ'X:o;þÇÄŒ¾Qá‡ß .{dÍè¼äk¢ˆW–”€íaM–:i%Ë ¦-»Y"'aÞ÷»ÚÓ �$;°6Çhxï …ÜŒÕRð\ó1Dß:ÎJŒ@îÅgÔ»0‰Ðð88­}Cs¬ë¹r19|}e Œš5^>û‹ms·³s©êP×ÉÙn{Ľ(/£Q­·aô¹l¸óuÔžàÚ}Ç ½cÁïåVú·€n¿7<}$‡SÆÕÁEû (ïȵíSÇ]o-©þ 7lß/MÊ¡0`× %?Ôè›Âgì•�‡Ÿ_ØMƒ§¬~¥ý1p#͈Óà\ä«u£Í˜™>áÌx`"�H´žÅþ棋ÅrŒ¨§‡EwØ}—|Î…Âêæày”Ç«ºÞÐ?Ó‹2�L(uåZªºó„uHx⥓TÒ�P|F“ž?V�;~ù¨m'¿V“Î.s~ýáCì¿!p›;ÊÝ�Nv?Z—ܦ‚�ß!Tô-H†‰2ƒ æüÌŽv®iŽ<ú•´AÙÌCT2”ÍVO?Í·,„Ĭ9$_k‰«ƒÑÒ�Ã'¡Èm6»CêîiÌJü>q1Ñ1¿Èù\--µšÊÿ¿sL¤…žïPw­¢ùn£ÕàÔ7ƒußΤÊÚRª™”K¿¾%QÝ'°75mÔš½©DÌ)ºËÊæœgÓhh ‘W¢%#• 9;ƒ ùkLÍÏÂÅÛì˜ò–£T J7¶î$JÿËõV«ÓÇæE8©\ Œ¢VCÍa â”ìà‚c$Ûü1þ;uš3áÅÍö{$ ±IìÏN£MæâÂH‘–¾üü\ÑM¯‚O°™ã#Èyâ%N3NŠVå72�W.LÏ\žÒ¸½«¬¨hb�™ª@œ‚J+`ïag6 hÎ"[‡V²˜Ì&YØaSƒ$Û³¶·j¤þa~0;žžª¹Rz $âheÖ²zÙdÐ`è ÌñËå%¶�„¿Z©eÒl~Ù°\Öœ¬E�#ɺ˕ô† Ù÷õ/YÞCu4 N¦7‘r´áºŒù•,±á—µ­€e†Ñ•¼Éà3y"V6™Ð“E‹i¥M!•+ÆÀ�ˆ š�Š?>¤�ìl}òZb„ÉQ½ŒŒš¹©Zkø×§y‹p ¼éO·÷²ÆýÚŒbdÚ£Kö/ßs§æ€áÄ4^i ñÆoèIE¢Àýy-¬{bŠ£ccÀFTSÌ,È2á ü ­gú÷Å„_]&“Õ¾st²ñ¾�2€Ýÿ†Ãr3MŠ:« l¬�KjjClëêÊÏÐ:{´r©@Ó‰ý•Ôd÷ö‰ÃëtÜl¡ÈÙ-ÒÇôaIJ(’‰"R·íff¹O¹ªG'H8â9{_ô„™IW—Ó‡îêÃ(%¿íƒV¡ÆïM¼W°©ÕÊòYyf &ùíTþ™þÍò`íó²G•ëØ½”xî?>�·› ï϶¢Æs`®éü{a3ëœáN^§Â`~ë#Ô‹ÇœÏ}¡Õž û“Àf.=Μv‡�|‘Þy»k B�f˜àÆI\¬z“•u€E˜`Ëþ]û̺×ç�ÁÝ9ä�B»îxÒ‘3Æ´=G…é/L¡Gò…$5¹æÝ¼ë=¿0a)Ë~ãLÃv›ñß=Öq-�¦8iaUœ–$lk~ûF9¹ê¯}—«1àúÛ…Ùþ)åæ]wLJbÇilS7m¢:WNÅÖ+˜¢áB‹ÜäEÓ£ÆbÅ•õd¥q•®*BÙ¯e¦÷ÏçÃi_I¸×ĵ�šÏñ-®Lê�ÆDåõÑoùy‘í¿\ÜPX9éÙ†ò Ô|a±÷q·´ÐŸåíÊeS·D£ti³ž¬ÄŽwm‚[j¦41î&ÿêA48èhRÅÎ×Ìæì{,¬ÇññS@éÄeÔ^˜!Øqs޼Lµvq 85î|‹€G­ñL'HÜ:&Â�ùlßÊ{ÔtϦ螡® 2Úç"fž´¼¢¥e¨¢§œn/–67^=äŸ)PÄy9ó÷pVcºdÍ”¼»FNÑÌKTÌ\ýyª óOµY¤1“Á 48a˜P²ßAð*'ÔWþa»ïÖAÇ|Mä/PPk9›úï7;«_‰¿¶³¿ó”Ù(Ãc,Uí&M‹1dR'Ó«¤Œ­Žîô 0äö^1b�OÆQö¦;üK_k"Å&§iÀ”ö4r—ºLóß9ÑŠŒXÒð΢G šèÄáe?]r«S†�{)ân©‹�© ʬýË*ì?ŠíÔ1ÝИöTÊ‘ÖÝàÔ-ý¬¿MÓÇ©›{�,J?àvä(à9KÚýØ‘Ž»'шú ‚Sô(.u"ýÀA|Û�Å&%Õƒ_ìO~âé7|ª…Í�$w¼‡ë¬LÙþC8Ù¤Cª î´ZÔ5Ÿ�G�Ÿ±é“¦õ»‰ôQ�f&n«9HÓocÓ–ãTðN×ü„^$_;– ]å„ýÅé x ‘=}½–Ò[è€f-¿1´§/ ô›†xë(è¹£ƒ³Gà.A0=H“§nßç´Ôn ÝÜÇ6&/gªÿúXÙÚ£¸ù“4;•QMG3Ýï±bk$,¶8ÏŒ¦Á¸@)aiïYœVчCüSymœZ!N]Ö¾èÔs�·¾wgŒ7û-µî|¤;©£M^Ϲº%Iäž}о/t¡ÒÏÞäÕ÷+Cïqâ))8ÇÁÿÎH¸ºå.³—Õ.üÀ›ÊÄÂÇù+!ŒwD±P 2›XÅæœ4¤12`Úüs-#É£DšB-§GVPÿí"}pa›çmà?9âÜä­ÁE?¾¦m`ºý,}ìh:ÁëÓØºðÈ ŸZhíc\;¼”î¾,a­!ÜÍ~Ù!¿µ„�Gjpƒ–†·±ïF‹µóhËvEäGÃÛ<`´Ás|$µ Œÿ,¤¤PKšT…®Ê\Ìi.iÇqOóù`²y±%0x_Ÿ´–ÊÃeÍ ?UµöÅA‡BnîÑ&ù5yè,ž�üP–V<ŒY^LgÜ;Œ\<’†4(_o<””ËA0ÿAÊí6¢¼ÿ"h˜]´àäËC¬uJ*»Ÿå€è‘…毵٥1p'¬rã)aª"ЫI¤škOú¯;ظ¥Ãi\Žõè's�¯®Óú.)j´ ǛџÙÝWßPN‘‰ž2h=BZP0¬SüÉæ½@%]Oütu?œoßL®•r°âª²Y¦Ã¿Ø²EÑ“Hä¹�t‚Ïq…æad«Ï Åo2ý¡5^Ö¡O%-ÒhVÜÉpžtM�¶¢TvpMS­f«}ô@G¥�ý¸c‡s‡mÃ#ó´ùÏÒq—­� Üâï3©—™êÏ¢äwÎlû’ òÑ_Âú²­àeO6ç"ïÍ î Ì"þ\gé ¾ôñ²LÍ1¢æÅJ°l´. ô¡GËr’‘^ûì�‡û«VaýL$ÖŠÖlŠÆ™¿ð‘M� í�}ºƒAó%àÙPÞü ~…Ÿq÷%8�T¦eyÜý ]ZØê ±—?˜>Ÿ~�Ömù µ£ÖÁ£’æ…§Ïpow¨‘ÇÕbª™ÿ�M›-”2Åi_�1Éé u3–ͪòg Ó�àúv:91‚ü² ¿çàþq-p"Y”mÂÑPçÿ�kio8äs£íËñܤ3pÑ? ^E}æÞö £¸=^œ{^³½tžè·©¡U)u/ÁÂYš3½¾D7JÃ×&¹Ó�BÖ¬9‡ìÅC²ñn`²2Bnå;\<\Æ\éw$;*wÏh¿_+9ÚøÚ€žÝצÐ+iØÔŸ“ãF€DR%48øÃœqN$ÿóîükMÝBžž‡”�¿Z"KŸåI”¨ 5Êç0t „¿(ó̬µÄ÷Ì”çLì)5ƾ�œJõç±û*뇴G‚×QÐâ÷=¼Íl ÒÆgÕäwÔŠFL€ÌëŸÑëÔy&6«ÈæK4ÑA¥‘pu:Áè¡1ÃâØžåǰï§ÌØeùéÉP³|?MåÚŽþ _î«arÐ#ná${:wÍìÏÞ#ë(m.¸fœ�†¾0[9 ¿ �„᥶̣y&ˆ¯»Dþk- _¸«w²ùg±8P:ôwQ|öbjÿÁÎúo¡†ËÖìØ´'‚ÌcôêàRH“N¥®3@I3PRW™.=ÞÊKì�OÛ\€¦ž'ä°õ6u£¥]É‚+_³ÁÇ&’²ô”˜°W{)už9Z Üà¾%•ç�WñªšL|“ Kv¥�Ú„1`Kùtmù?,½9ɬíÉQü4ãsò]¢{9}ëhÖ«Û{vè²§Å ””rëS/íëÓéŠ\3ÖNdmA�±ÊF·ëš“¿M#�N+C2p@< & ò±>í0Ì»A)3óqS•ÙlÕçlKïTøäZ‹Gâ�M÷yäò/ç42þj7Ë̪ä¦)Çã Í%´þ›;�sÚ‡G?>d»D6bŸæovüØL°mà̪PS5·joÚô—MÇAå äg´Œùš…³m:·ví&×–“ð)=’Y¸ƒ¬Ãúj©Lö"kadu9u¸SÙügÌ`¤étrIoYŸì!ú5m{\�ÅŸ*IfÕ5æ&»P°)6ª‚YQÁwV8÷ ;§ñŠËbéÊœZtlû„_.Ž‚”'íÌlú}ÌP¼„S/qôeËHî¥W¬ú�IQùÒæ¿+²ñOnNœÊô¼¥èÚ¡_üé¤{lØE+^|Æ|ж¡co idU·@LÍ#¯)À¤=šP[Ÿ…�ÄB êÙÛq² §­D}ãrØÙÕåè •‰²ÙïY¦»#›tç;™Í`óœ;ÜÚêBÜ›‘ÅÙybÖ¦{¸Œí>,~z{äy ¼óŽ3‰¦[f.]Ù¸3ô14•°q\YœEë G²Æ×!ÿÅK\÷˜Ìì°Ød:΂¸ÖR¹uøkž,n�¥�¥™ø»Ê”rüáåÝ»ì~åJzºÍFKÒƒÀsì"Ñ]ir¿Ç¹ 3Aƒ&_°¹zŪHV_’ü¢^²˜Þ]”·¼YàÓ d±Ûká´ÿºµÖ‘»n§S+óÛàÓ:Gjy~‹2÷F NŒäŠ%S‹n9ºÿŽ‚�á²4ÁæÆ$jÓBíPL<– sæQžì2>¹W�®;ÂöÕ{`ÑŽ`òÞâÏ Õ ´™fqÁ&õœÆc>c¦D ¿á*�Ö17¹I xüõeüyÌÒOð›Ï¿Æ çã´Íõã/N—W1Ü%ŽÍ3ÊÁaç`tòE9]‰Í€Í²®àuRBèø¿&~cW«€¨Ré9>á=·½a�'8ˆÙôŒ×õúmf»êÎ>ó…ßx¨¾ùÈcæúOÜÑF3R׫GÝŠ±Pýk…Þ–ãÓnòJ¶¦à(öe­JÈnÚdøá#«w5àæ€±¤%y‘¢«3©ªB&ŒN™…ÏðA`ªÀ‡Û˜€]¡­ÏKd¹±ãÁ½îØ'–Q¢›nZ-i>Ûá>Û3NÒ¿šcƹUCÏ[Ñùê:¹ß‚êôÁ53‘†ù¸c»¬_ˆ…ô·ˆOºn‘Éô³hOs¡3Ú€ùº ‡eÃh²J “ëŒbÖ=Ø“÷‡e—$�V@ÄØº³Ë~+Ð{yÔ¾ã&»�ÃwÃ˃œÅþ]ôC Þ _Á‘Æ/‚Q;’‰>ò‚k;*(y²"Énm&÷W-¸þØUÿ(Ÿn9çàç1ô\²ŽSjzÇÆ|—g…äØ[›M’�K–Op’kéX�íùé " ŠqÉ 4+½±ÖÉÒüѨÑ ygŽ@sõfò@ Rÿ‹�#þzlinKKI¢øJSª™y€T}¸wMN�%oÇnþeN�×ÑÂiñf®ïmà~ÇIl|[Î&l«Ãy£X�G/&½‘®ß‹F%·dÿ%ÚÌËçÿ…Æ�«,æý:º×6Húõ:¤”’Çk—C]g,ßæºŒyÿ|À¶·ÜC¿]Ú´OÅŒwÔÒ†žGÌûÕ;4™Öu¿˜îÎ æ¹ÆP8m ¨ ]×Sçç4¶ÆÉIð[§ÎÌþÑ}&ÿ€ÁÈôAœ¾»–M¿L¡é_˜ŒXÓÚ3�-OÊ2{>l/÷jÝxRA.¾º,)â3ÞÕ�ڦœ³Ö’óˆUºâvÍxJÜ/=>� ƒ‚N ;ÔK"ŸVP™óbÀŸÐ2ãgTpW¬7I uH4QÃÄ«›à�Vw7PÂÀ¦ç8‡×­_ïö±Q rQå—+|Î) ëÃfóAÚZl ÃŒm-EÛWãÈ1¢ðß¾‹0'D•Ü~Î`ÿ¾í‚’³{)å|”¬Â-Mú÷æ+ë6Q¥ R”˜ÑÏv)åðÉM¥¼�í"À¢·toÝVæØ³¦.þÉÞ%$æŠÀì¤FA³È1æ³¼œís;ÏŽ“æ#Kš+9þtjs‘Âãø%äI«Ùƒåq9ªŠá`«Ç P3Õ¡@‡ü…Ðwü~›F¿²ngšŽ¢Â•çð´�9%ÙÙš<òÅQK›Ù…Ö,úÆpο7‚Vø,å—U´@FØ'î_° };ö—O‹`KÖÜ…›uÉ4Va=vc!Ûˆ‡1n×8Zü-f†„S“zuñô²õ«ÚšÌ–>^�6‡ßàä݆ô¶¬ŽÔô®`ØÙ³üפ׿†ÆJŸó ¦{Bã+:ÎÎf®æUPþÚ‚^°®P Z1…( K°À¼š6e®‡óti˜}ñc٩lj4[pƒ·ÑB¾�¼v?}ß’†3·jÓé bðW¢O,#ÏGñ€ÿ"èe[ ´xIPÆL;*ý-ÏGç>¥~¨`ë5lèÛa_PüÆù­È‡·@Ü+ô£‚é°ÂiÊHoæ¿M¤ûSðÕ5Oº#n^¦ê‚e?Úh ã-ù2TC}ih8r15e~F““²B£ýâæGgô ¾þhàî¤1;Ï­P4|�,¥‘ÊS¨2D@–¯ÈÂßÂÅR—7bžzóÐlƒXþý¾Ñ¢‡M[ÚA÷<Å@éâv}õ25^xWC†òžŒ¡G'Fš¶°¡ðè–®#Å:Ãî³2ávÒ~j>[-™Fr™­ 5s!õ)í%œ0�ú«_ÐnwQJ2.daãÑ~u œ’}�Oe@èätlç9v}æîõ²a =rÞ–c N²6eQxñÀR³öÃôñkˆ­=Mëüò¢m¤Rºd­VÑÞ¢h²Yº¼&8Áí•'(¢ªd�†à; Lç°½nµÃ›Í7àÇÖCd1b ­IR£cÏt؃~]˜0ݘ^?Ö¦°*æ Ë4ˆ=>Œ³1¶sì4¼º›ÖÞRc ó™‘•!›Ùq—UüÃsã¿r ¢ ðÔvìÓc Ù‹ðÙþìù›ïN¹²ÍGøãšÆ”._­etj}µñ…ë#k™rùyÚº+Šs­ßJã{2@òé2³ž%/YýÃs|Rt14˜f›ùCŸ÷,ï zškp´þ\¾-„V¸Ó¡huŠÒÓuß$:ð_ øµ%ð‚=gèŸö ºû¸�îè*ƒho:}’÷cÑ~á¸c(OÈΈ£QÎO3QÇ<•3öÓ›Îù0f÷ü3<ý§È‚lm2K(9—˜A¸­ilT‚Üù�Ðum=ýagXÛØVcOZ‹ [jq�þNÚýP‡ßÑB‹çàŠº*x¾LãïÖ±»&¯Øk‘iÂ#‚Y¹Ê—~¬ºFŸ£¾`zQ<óÜó÷KFå²mô«W•»‘žŠ‡£dáàÙdLlëfKÔgBRû4Ü~Üo~À UÚðN…ö¼ }¶é»-y ²ãk òY>É]û\±4Í™Â^;³÷É6Xâeü‘ñ™±´ù�=Ø/O ³£UYúc½t%¼WÌïÙµ¤UAü¥#�F’Öç6íz¼§H·Z r^'›Üó5ÜÈ�5�6ͬä@e½%žšÉƒÌŠ"Ü´|Wsa)µj¤2«uÚn).¼:a)ÿú9�èÉ…úuÏñô:_(Úì‹úm;áÛL³ªüZX4ĺ×üÙTÛãÜÅÀOl‡ð8å-i�L,™·…¿¥blˆø©à6ßq" ¹b¾pÍ>Wn�½¸¾�þt:‚ú–ÿ ·¼'}­¢A�[8f`-Ý*Ú»ì“ðrc&ÄÍŠÿ|'xXò�Ó[ô•eMzŒ‚¥LnÍÉ$ÇkÁ`£ð�‰o»Š®Þªô÷Æ{\”¥Mé7CÐYIÖü¿ ÍÃë¯�ãY‰([!d¥Ÿ(Šû\w"ŠˆJ´(Ii¨”’½³·¦U„ßsÝFY¡¬¢”BÒ.EK<=ÿÁ¯ëóy¿_ç˜s`f, ÎÃàœ^tµxN@q+Ù­Áñu4 t!»ðÝêú1ŸÍâ"s�ÿy{Eü±§g•‹ƒ\Su)È…ä‰ R#Íܽ›Â¼|ÃG”P§†!¦³*Vû_Æ“B[þI)Àc�ót£“2ý,ßx÷ÜC›BQξê�dNÆK:ÃÿÃÐäÖðݦÃÎ7Öb—Ö*»hd5Ò ³&¨5¼ÍÜÊœ!g3 Á¸ÍÂóÌhÿ­–šÒÒJl­áìj•. r‡¡«\D£™¡u&lj˜Z!,ݯLn»i€X}&É}e’ž…‘ÕO×ÍÇ {}*«•NÛÄqå�Hrâr;õ©þÊjX¯Š½ 7PrÂÞ0òþ1ºÕW—¥¬J·¥ Î{ÇH…Y²2¼wBé‘FúÙ÷ ˜pš‰û�/‚ÑÈcâŒÚµ‚œE£æ$jÏ8Í8ƒ}�Lùô zü·¾ ‡vïèR™YÝé [¦õÁòÛaVÓ/n¸«¶×î£ã±1Ð2¸f¡îljý\öúnÆÔ¥>Tm˜à¬ïa(¤ÓXóIE=Ön“rÆOc5i«¨ÆœÕáð®8 ›]æƒÃóðÞlQ¾®ÀÙ¥-Œ<\æ´Œ�Š-bÐí®Å–?N#�‘ÖUâ8®tŸbGl²H†{ùmtý™ê;÷këÌìSNƒàde¼Ö¢Š©sE釅¼(œ&‹_=£Àr©š_€*�^Bê�òɳN,'yq4·Æ�Y�Ô7¤ŒÑ¨e^Þ&Æœá—Æm+=ñÖòõdrõ-hµøf”ãAz¬ÓQÎû5£ž¿“&Œi�êè´^\ú:µðfý'Ò¾ý•˜m öl` ¥z�ssKpqÚ=btP'R[AùX$m¸—B¿ºK“^fz�`›¯)lrÒ`x‚¾Òá��˜±æ>ñ¿¨/ä‚ £¯ Svf�É͈¼¸>êâ’É7°*]±f—f嵺�>‡+1­%•eâèCùStd§™uõS\+Œ»yF˜ŽYýDV}#ÊL_€¾Ñ08`¾,V%CîÁ ðÞ‚7?ÑÄ5 !u³Ì[¨2ÊëhÑÏ2:|y©á¿LÄ囟˜š«Ä6X¦‡õÿ…`×]ÌUÞÎ�Óâ ½dbl+œõ�¶”¾�ƒ9ýA ×@îΔ“Cr2윉HÍ:‹Ï–Ôtý^Àaö„1õÈ­‚fQÕi¼a/`Ô7r—ê2þF=.är¤ ­8á«‹…°³;F ‚ÐÓU�÷g ô=°?ð�õfeÞ?.I"áõ+XéZ±¤ÛÕ€Þ›ÀŽÜ4ª¸ó)0¹Ð;åŒÑ‹ëè¯2ôÀ;gl}¶Ïõ‰úyeh·Çïua$; S9ËÁmJúîQËÜR¬X€ËpâØUlÚ�þ[ÕqãRkò½ýáݳ¶Jc°RJ–70îU©Ôøjü½qºüi‚ÆCËÉÀÕËèÑKVœ "'FR!ÿ5ê�Ðòêjt˜H ¯Ã––›ô¢eQ.j¹K¯+B€g-¬!û‚‘¿p%Dlk4ë‹?¹™ ¯çO£Yb$dí\…ñîšÌ±Pò@b6‡%5Æ­Ê„?‰9ÔqÊê+[1õ—ìIÀ‡Ï¶€”¹ < « ¥kw�!ÁUŒXÑ(�Ö†ce»™É Ö@¯]o~�F] cæí0FW;2{Ÿ1¨ óâXÄujúÄŽî2øK\�Þo%×_)b`E"~üÐHžhfc‘r&©›€þèÒ^hO62á,Ïu�éºG�¬9Ãaó¹"®{FgÒÇY«xA$?«Ôž0ÍG¦j¸¦\À4£Šfk•Ðû îò+˜œ<“j¨ršC.‡kA6´À²7õFÙÁ+ñĹY´¸C t'’±ÿø}¦Me5@v0$J˜Ÿ%«è-ã$ŒèŽ¡Q�º�Z tÁõT †\ÿAºµœQî—ù±\�þQÖdF·=¡UóôYo³pIxö ûQ•Ï »(ŒˆK'²BsÈ×_Q¤™ÏÝ2ƒû=ÜÜÕŽ±W_“ôluZ3mBœOU³¼¸#qè*?î2¶bºMàç¼Ð<¢…�1 ôHM-ðgâ¤Iá?:†Çÿñ /•ëͦrbÄÖû +Ñ`f”ð‹Ñš}RxÒw†¼\~™e{´…VN±þ^;ÿÙ¡³E"�=‘B"xÏ’)�$ÌÔÏ"–WV ¯ø¸á0ô¥ ä\7‘«ÆÏÈ%ÅzÐäïa¥Ö[B!o¤Q®dþ^‡|ºt�ä}zû2ÈoŠ€¿¹q$¨~‚áo»JmPG�®Ýàþ4ÝÍc G/ �ʽ™¸t½òðcËÝšý6 $¸fCcÝMÖ§Š�Ô„ß¾2è¯ð•ÔN™1vN (°|¼öG-?ÐÓ™®d†Aw ñrlò‚˜�"´ª¯ªØý…è1ÜpáPåžøF?´^Ã��—vÕüIS…³ÑÒÐ>ø�9°ë‘­iÂ$©xbÂD£ö?�ž`MX,6Òi^ó£ aƒg# õÅ¡¹c3)¶Í£� G(D!9wÊ‚È1Бt¤«(–DÕ^_„sU…Xš½³Ð%­›\ªº€z<è'ñ#4\‹ �7—¬rlë$¾'ØPá³–®�ýíóñ·òaü5,€Õœpz<6\Ï5S%«"*î:J~8z°Úvã­è4ôçM%ÅEÖà–·×tjàèjKPôúEúú|Éw…5Ð¥aH¬’…;óûÐXÖ ,Üö‘2sè±™ƒ+Ö¾&{ãÖ¡¦ÊkJ%ü�íU…™#Ž�öÑFìañþv'�ßÏM«pOvN�·Ý1Rã{ Hý©!!ƒÁ g÷ÒÈàãkº%-óÖl�˜°kh®°�¬qÔ‚KL'Îø&2Ÿæ_……j?î{Ø\ù²¦Àû.SŽž×ý»AÞv­$wí*È÷"+jœ!åúßÁâÑ[úz‡Éé �æÅ,ÔÙ4—L;›“ät�;3ç 4ɦ5›€x .[R˜„yNÔ@Ù‹tÞ8�É[®<Ǽ_™ÐB=ˆr¬|–ÿHÖJnÆŽ+m(¶4Œ~øD"ÅP冦% “‡[;Ànƒ9½a™•x�XÿxŒK2sˆ]sø}ªE9ˆûOÓdøÎ+ª¼žoíá06£ô·z ô)è A¨?+º>}ûíiì¾�SŸ3¶Ð+ÍatÏCíS�h»" þë †áÄ¿^€ä™Ó'ɿڦtÎb³ç:ª8æDæ%B�•jöÚbþÕ0?ûˆôoC‡–/èÈÀ—–ÙœSbð Qvv/pNÈ�D~>Ø:€ÇÊÒv‚‹Sô<~ìίµPxÜÝÒÓ1ÇÓ]¢Ä±’]jŽàÁ¬0 ÉÄKõáÑñk¤Âj”´Ÿã&×¢2‰¹¹;“´ä��ÿ¹’ÍŒÏí[äu€ªfs£º1Y67Žå$˜�)“±0hʃb'ÊéïöÐ.XÒ¥ÃtdÈeÎ.Ò¢?†+æ�°zÛC~&7lï1‚-ÎY†"w±Ò}(!™B'v^‡·ýQè{A6ß?ÀŠùtJn,æ*Άà(*_žO.m¼Í|PX Ί'ð?Î1òíäkrâüòxp´Y˜áþØ�Øzo6�5Ì�Èú}¬(÷—äö51f¿¤-9/¾}HÅ‹\Ê„^eîË¿!ú�¿¨µÖSšÐ†Š=›òyÙ™V¾Ä1ã¼áD°6XVÚT‡ðò€Ø5 pòûÁ°|$Qb¨‚ü+D·‘mªÅ¸Ì»Üú?‘3ëu¡IKîj×Pë;dÑÅþÃMðÔ„~KòÅï±M¤õ.ÅþCàÿS�ó{ù"šÝ%Í™4=BzH4ó}YÔ=6CmÅM}Ãh2¹ÿf{' [V…sr—£o•+åZ2z&cît-<ÛÉ$KGso),ìQ$Ù¡!ôt« 4¯Ï&ËÉ¥cשH¸#åΘd�TÖChˆ`4ïò:(’âÏÂd¿"ªî®ÃÓë iôv_L~£ SöºDÉSʶ2$݃—í÷ò(ùùü0ú¼�¢ºÆ°E#Ÿi©½ˆí•Ÿ°*›{'žÑ¶ðkZÅÀ´®Ù‚¦Øùû5Um·§Â\.̹ñ XéïBþLêa�Æ~´Ræç«WèÞtæÇmCNûJnÎѦhkÊcÆeP ñ$Þ¼D§^=%ëö(ÂTÀGÔÈœG³X�oLáyl064úàÖ6)(êÁŽz€…üqû.Yœc¶ †ËªÈïí.à·VˆË£Ý–¥¸©ù ëtÂQØÕßH3D |:8 ï8.àÒ|‡Bì°OÐß=*%ª0²4“6Ê%ÓEd¨1œÙá–BÃÄÊHˆx2dŒ5`Ò…ƒäùæ½äÞƒ>”âŸÆ(ƒ7¤Ìq} Ÿ¿,X¤Æ„vTдïp)ŸŽXOãAkqKÓ¢â|`™åŽñ³Ø}Jù¾Å†Ešzç# °z �ôàÂæQpÞ³ V vÑÜþG¤ÙK {R#!ÿ CNÇ,„ås>�öºó9 ¬*ÿ²ç:Ã…Ê$ôˆ å‹°Âtš”Ù:Ò³�öb4Sˆîᶸÿ‰Ór3,1,fâ¿rÃÔtNëä‘  ïí•©Êõ¬úÄ—(5¯ú<¥â‹TYCßÕ©™¼ö5kQûîFì·à_‰Ù CgÁôûzzóáNÌ^O­Oæ³ìÅž€¾Ò˜œ±…‰”Ëdºü8½ø>ÁèïÉ.l6#–mñѪSðBm€u0È“%(¡H7_�¤ößávû0Õ áĦ~%ù¯"“ø½ßuiX⣎Ÿ$âàá‚AÔ1»†;æÀÙæ”ÏIÃw{úÉWž8ôò{Dwø'C«×mZA/ÑmT›n¼PO‹<¦òÜðYÙ_r+ç%ɾUGúâJqù‹x>Sgk¦áÿÿ¶ìïl…5fèâ´%ðN"â·º³dfþëA8¦BËY§q>T׳°Ì²¾¢ òHÓ'kàáEóP?‘ƒ­iT°í0lßW ªk`IÛŒ½æˆKÎ¥¿«ÈÎø=ÂÏ)+r¬Y§Z„¢ÞÂ$<'—ÞøY@Þ®vFõv~ø{Rr>=«®�la¹;œB�X�¾æN†<ÁøK™ý”"ÿ£Ëm”ñM³(ªÎ^‚7ã]kŽ:ƒ¥³¼àÎç0¥‹aýqPÇ‚â›ë‰’w<9bÌ‘Ÿ¤&¶Ýs@Óî-tÉnutú¥Iú 7P.9øöMµK©�SáÏ º&­yÙW $Ù\1ɨsÞã² ðÒI!¸}* žyÛðëà<¤8€Üò™×kó`«6–�13‡¨Ãø3ðótÀÛ¦™0—g6Jžs&6òò¬÷÷_056ñà$ ˆÛðÎt5�„Ës@FA .ÅmŪÒE ³ò%ÑAåxT&J°_+”¹;6«]ÝI¡…ûFˆgé@ n]ò–¬ùj™>°›(²çß/ÁÍ‘ µ£‰Õ±€³#m=Î5g¨øž|¶BÓbq¿l z5̃åãÞ4/oˆiz‘{õEà4ò•nQž [»ÎÓSIIt»ò9’QwL|àÊ£•˜n” ?¬nP&ä?Žn/Ü1Îaéô½„ãI9`›| 寧“߃XN=‹‘ÏZìfJÁ¥@>4ÌEÑÕS¬ªÞÛ(0X'û=àÅÉ/Õý|O©QO$&ÊŒ_I/”i¡J™4/`ŠóC‡ÞJ°Ü=Ž#sFéá ~Ü¿ä8öùa«õmšxZ�n8tùö‰‚WI,$—MP©›dVí´tHî¤ü&¡àþú1.ÜÌ@iy4åe3ò¹M4ª(¢¿�±¤°^fº™$Ãÿß'YÞú¶�²«OVz@˜µyêèE¾Y¿¦œ²V4ص´f@Ú õÚs Ïæ 3õ'Œh)‰ î,wZ©Á!;c°çÙjTZs“Ά&�ôä¥ÀçMxÌß@×x]¨Fü¶ Sáï*ô[¾6:\¸oÅ�@‘m`MÈI§ ÐìFª7*BXy8ªÖé¡ÃZ^�ÛF¼ì1•Vé«%Ìí“YX ËÁàaCŽæ½t2â,ZåáàîjÜ{Ö‚ £ð,§®ÁçÏ«pÍž¿0xà%®ñ£Õå™�xsê'<ßõ4÷ÌOµ4m«=„éàZ¹cD<é�UÓ‡4!i ÷7…è/üð2Á….ßd»}–ˆw`ù4þ¦Í¶Zø¡f5FŒ‰�Âôƒ í–†c]Ëáòý%ämFÚ¿sH…¥žÕ`ñw%9Ü0)ErÔPL ÔEãä[AøÞý‡w…‰,Zxª‹œº3÷ 1[ç¤S§­WÑô¥¾/¢†£ëW൘ÃNj¶ÁãÉøÁí°Ý|#4ÿ»Ce»#(y½’¾R׿Øð½§?ôÖ`·E*Ú‹%R«C!�Y…Œ<1>«•îØïNÔ³:ÉÈ2(}^�‹\!ñro±Î¶™Y}Mƒê—q£öQê›FïJðð›izøüS †;+˜“Âëáâ�9Œi5 \N„áJò…^»êEï†rÒ2{Àùñ˜?E6%\€wæ ŠŸß#ÂŰwÓYªÑ ?ÂDp³B|.¢‹7ªÂ¸t'Ž?‚[‚ðÙÍާ÷R7Ó�üEôÁÖ3¤T&ÛÓr`À2R_Fµ[},GÙ[ÕYE>¬æÎ:"^Â,7æbwOÁüeÔl”RáØÔŸ!Z›cjƒ_�uqéôÝÏZzÉ3˜Œp:èãhQö†ÐlŒ¿û—DÙÎ�Ç¥sIQbë{¨ýÐXCûŒ5Àd¡ þrñ Ü{žã¸–Y+ÀÃå}F¥‹·àÔÛÙìOøAyr6´ž½I.Ïw |áL±y?šò�ÀÀt$Ü9±/p‡PŽ}'%Ï?£¿wš�«`qA½*ahñ/"k&nT·(Þb©ió¢]ÛQ2!y•Üw#ؽ^œeà5Bß^âÇÛ.‘Äiýcø©ýšå’Ó„zÓPà WÏ R™AqN¼X;}7 Gj-†÷ÓžCˆÎÁo‰W¡5Ýwq´ 9ì½ÒKbѰð_^FÅ>_%Öß¹À{ÛZ·;o4°&øŠâàaG0¼ç骻Áðõ̧ٚ,šÐúHü6Œ±¾^‚ÌW!¸)(6HÈÁ”ñF7‡Qª<˲dós:KÃè—¢+(pšޭL!bRú¡„]6Âìé¡z´2]…ÒuþF#ÿüøúé½ä´¡6ÌUbòu4�vÞ‡ˆæº¤³–xÿãí„WU¸ä] ³ñ!£�ödŽÙ$“-?…‹ê�ÂmZŽŸbñCl7üçx’x9)“Oo @Nß–)x,Åù¬ …KmÕQõ—›G³–nu+D¿¶åxàÂW~ì‹ü)¬X‰WTlÏ+âÜ[LQC–•WÛÌÇñí "«L 8fiSnOc̵ ‚‡¨ÔR¢Õ¬î§·@ZN4Ô»åƒqS9Å)Aö¯ó‰tsÍuÖ^×`Ž“å5{5ÉD;\ÇŽ2`ÿ5§Eÿ%€^øZbÊ’FéS!xLf#s ªY©Y 'tAgqÍ¡æQ°<§�d°åq½K È‚:ø ý„4M]ÖBñƒ$fY›Ó#/�£Åáø“~ «&fÁ§¨\j¥UI?•a°³ªŽ=Få3,:3ùþ>_WâÉ÷UÔ�Ÿg¾|èõ€®ê£‹Ì…H´þË¢R O‰¢Þ(•íH½w³Ù?ï}•af&ñ,„Í+ÂSîè­•M™xÀp–"Ç�‹‚|ª%0¯Ј÷‚œ„cST¢,ïxÁþ¡ T‹� x- Ê­Šá ntÚþÄ�·ïHÇ.Cüá’Bùõ ¥)ˆœû©Jö>YÏIœ§Iß×áCkÎÓà«”õf^Ö·Ã×rz‡#ÆvðaÎ,ƒ!÷€-ù†wÜ!*_ ˆôøj™–�w*îV’B>3,¿£€Ç ¦ÉµÏ @át-Á¢p^s‘1åWEØ\xq¹Ÿy6NN4`A±6†Çü8°‹¸ÿ”ÇÛr�ø^«¼r¯³b¸E9ß}Wa⺷�H‹�ƒ8Õ¯d�ÞKzrM(y2÷%9YÙú¿Vó ¨ŽºB“+vÓ+²¹ØéË…–·pD·„õûv6³`™[-8óg_"O]“ÉàŒìÔ23³=ˆó†Ód©]ü(#[ô‡åíêOëÿeÍòäà+wŸnÎûÇ%÷49 ]„¤ì”EçŠù êJ÷›"1l¥Üf*ØtO¾ôO“[ÎQØZ4L¥O<†ÿxO‚®[ cð]H›B£hÚË]ÀËϱBäµQs¤5Ò”‘ëZ•ªrƒ°¢6Ü;ô_¨– Îê»ÀÜÒ"Ù_Id‘{¥cZÏáXÒtqLýÂè?�§Ï÷FÃ’Æ�ðá�&sûEõM†³ky�¯ b¸:ÁIn-Õ73`µ”×ã=©[às`9Œ¬þÇ£‡¬1Õæ-SSÁ¾ >Üâu>º…7›�iÐÝ}ÀŸ Zyüp?©ÃQ—»¿ŒWÇË O(&‘+OX¬¬Í÷¡qþ¦ý| dð>„³’› åE(¸¨ Ó R¼œ¡m.8\غ3Ÿ–Ú#}.‰“ÍTa¨š¨O(‘µ½?Ésž�XÕºU¶Ä²Ì·ós¢în#²)ƒ¬’  B–|Ø\Š„èùAøàÀl*¶Ýˆ‘ØÕ‡!xÓ<ˆ*´€øöµ¨­c�ÞÆ<`Q²œî¨êÓ½Þ.& ½þ¯±[.è#˜�|¡ r&oÅœ§tÝñÝäm_(®h9jf‹P&E ÂÝÕI–ƒø˜¨â“‚h?yÎ?ÛϬ/QdYD­‡p]NôÈbä* 9Š?éî #z¤m%‘Þ¥D¦•áG»Ôæ‰â’}Šøi–=n(ùëŠé]?ÛÆøly,ÍVãWíñ`üyʲóìÐøë{4ìœÁUKgáïy‡ð˜R©‘\ ìù—s¢L­°Ò‡�CòàPµˆªMÏÆCïN¡9Íj$ÂZ‰¾],~Ñ›ÏQl±d/ÓúDŒ8&áŠ3ñÀC�4æUÓ­å’$½µ’ÊÅÀréYæ��4*ÁlíÃùÉ÷œþš1¨º`2î÷ûœJ”�¶õ &ôf¸»ØÇˆý×s ªâÙÆ0VUUžì EQ‹Ý(çõÏi[àhot/‹ •ÉE 4y\*T tûzܲ­Æþõü‡Ã²ql¬Ò!q›¹�–̆ ™nÉmÍv2å ©h}|‘”}Þ›êé¸Ì2XöËÊ]Ùd‡¼#˜^y�Ëô3ˆOa-*„yÃì0 ØVàEO_z5òe¸³^…âë {*�uÒëûLðöÅ“ôûê}èYŽí­Gr_åR eJ“ÓÈ�%‘˜”þ”ú&˜á—j!¼ûÇô4/ÒÚÂN"¦«Ï˜d^ťŕôeÌ^Ê#�Ù=íä'¸3Ü?îâô^¸ñ¼—XÇ'€®N-½�C8zW‚Si�Pí×^IE„h;Ž’ƒ1aäéÛx_‘Û‚¡G¹.ç½aÛžg¨üêç´rÉ~´^ᄾ‹zQüÌ[¼`‰qr‚¨ôì |îÂ$½7à¼p”ˆ,Ÿ<À±µƒÐÔ]¸Àü3‹¨Ÿðö‡ÔîQ<¹%„õyÕx-¨%„t¡ö´Ég­†J—ïøš÷TØÜg¬Û©î¸:¦øâŒe(<ËÕ‡ÆÛaxÙÊ™yת‰ùÚc Ôˆë~XÂZí)F?¬ŽŠ¤mc.ºàH÷Bh’N¥²Îƒ Ð\Oì\5à™–&¬âÚ€WŸ#É8‚ºžfàSÎwô¯¢oZ�XÇGk â£n¶â‘XXwŒ ^ê]‚ ÁŒ³BÕ›EvqÕð^Ab¶ˆR7«0êw¢‚q÷˜BÍݰ…Gmå”ñRÐ\_�<<,Ô–}õóI‘;î`¶»¸4gQ.ø Å�V™ ¸gÙ3²Rü2NÚØãF< Bˆ—Ï1RîDÜŠz˜us‡�Ãfd¯ô )ƒÙÐîKO§6’¢Çyëd úæ¢XvΕ” wÏmÕ´«òiV{ Ck¸ÙÂ%N”‘xC5e#@#½þ“æpmK€Céyt�•w”a‡Õ=§!É©ÈÅ™&ÕÆAøâáwB¢V Ö¢7<7ƒÕ‘Zj×Þ…û¶µÞKé(å³üˆ£ÚÜWUÎd°=Šo4A’ÐAêáqÃh°ßϾ †\ ÉÿPK--!“æìAµ€ €arr_0.npyPK--!¿Äý’ˆí€P €|µarr_1.npyPK--!É`tN€� €?£arr_2.npyPK--!0daõ7€P €‹ñ arr_3.npyPK--!^Ó0€p €») arr_4.npyPK--!Ï×ë&+€0 €Zarr_5.npyPK--!£¼¶v€Ð €ltarr_6.npyPK--!£¡^«X€° €]ëarr_7.npyPK--!Ùöâ€0 €CDarr_8.npyPK--!µþœ)ÿ¦€ð €�&arr_9.npyPK &»Í!scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/tsv_10_fields000066400000000000000000000002401520735541300260150ustar00rootroot00000000000000buh na de nuh buh KRRGRHRGRBAWAOMPWAMPOWAMP na de nuh de 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 $ 3 3 3 4 4 4 4 4 4 4 % 4 4 4 4 4 4 4 4 4 4 % 4 5 5 5 5 5 5 5 wat 6 ^ scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/tsv_8_fields000066400000000000000000000002051520735541300257450ustar00rootroot00000000000000buh na de nuh buh KRRGRHRGRBAWAOMPWAMPOWAMP na de 1 1 1 1 1 1 1 1 3 3 3 3 3 3 $ 3 4 4 4 4 4 4 4 % 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 wat scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/whitespace_only000066400000000000000000000000571520735541300265560ustar00rootroot00000000000000 scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/wrapping_as_illumina.fastq000066400000000000000000000017031520735541300307010ustar00rootroot00000000000000@SRR014849.50939 EIXKN4201BA2EC length=135 GAAATTTCAGGGCCACCTTTTTTTTGATAGAATAATGGAGAAAATTAAAAGCTGTACATATACCAATGAACAATAAATCAATACATAAAAAAGGAGAAGTTGGAACCGAAAGGGTTTGAATTCAAACCCTTTCGG + Zb^Ld`N\[d`NaZ[aZc]UOKHDA[\YT[_W[aZ\aZ[Zd`SF_WeaUI[Y\[[\\\[\Z\aY`X[[aZ\aZ\d`OY[aY[[\[[e`WPJC^UZ[`X\[R]T_V_W[`[Ga\I`\H[[Q^TVa\Ia\Ic^LY\S @SRR014849.110027 EIXKN4201APUB0 length=131 CTTCAAATGATTCCGGGACTGTTGGAACCGAAAGGGTTTGAATTCAAACCCTTTTCGGTTCCAACTCGCCGTCCGAATAATCCGTTCAAAATCTTGGCCTGTCAAAACGACTTTACGACCAGAACGATCCG + \aYY_[FY\T`X^Vd`OY\[[^U_V[R^T[_ZDc^La\HYYO\S[c^Ld`Nc_QAZaZaYaY`XZZ\[aZZ[aZ[aZ[aZY`Z[`ZWeaVJ\[aZaY`X[PY\eaUG[\[[d`OXTUZ[Q\\`W\\\Y_W\ @SRR014849.203935 EIXKN4201B4HU6 length=144 AACCCGTCCCATCAAAGATTTTGGTTGGAACCCGAAAGGGTTTTGAATTCAAACCCCTTTCGGTTCCAACTATTCAATTGTTTAACTTTTTTTAAATTGATGGTCTGTTGGACCATTTGTAATAATCCCCATCGGAATTTCTTT + `Z_ZDVT^YB[[Xd`PZ\d`RDaZaZ`ZaZ_ZDXd`Pd`Pd`RD[aZ`ZWd`Oc_RCd`P\aZ`ZaZaZY\YaZYaY`XYd`O`X[e`WPJEAc^LaZS[YYN[Z\Y`XWLT^U\b]JW[[RZ\SYc`RD[Z\WLXM`\HYa\I scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/wrapping_as_sanger.fastq000066400000000000000000000017031520735541300303460ustar00rootroot00000000000000@SRR014849.50939 EIXKN4201BA2EC length=135 GAAATTTCAGGGCCACCTTTTTTTTGATAGAATAATGGAGAAAATTAAAAGCTGTACATATACCAATGAACAATAAATCAATACATAAAAAAGGAGAAGTTGGAACCGAAAGGGTTTGAATTCAAACCCTTTCGG + ;C?-EA/=60,)%"<=:5<@85@7@8+8<<3;=4:DA3%<;=8-9.A=):B=* scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/data/wrapping_original_sanger.fastq000066400000000000000000000017171520735541300315540ustar00rootroot00000000000000@SRR014849.50939 EIXKN4201BA2EC length=135 GAAATTTCAGGGCCACCTTTTTTTTGATAGAATAATGGAGAAAATTAAAAGCTGTACATATACCAATGAACAATAAATCAATACATAAAAAAGGAGAAGTTGGAACCGAAAGGGTTTGAATTCAAACCCTTTCGG + ;C?-EA/=60,)%"<=:5< @85@7@8+8< <3;=4:DA3%<;=8-9.A=):B=* scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_base.py000066400000000000000000000321761520735541300250570ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy.testing as npt import numpy as np from skbio import Sequence, DNA, RNA from skbio.io.format._base import (_decode_qual_to_phred, _encode_phred_to_qual, _get_nth_sequence, _parse_fasta_like_header, _format_fasta_like_records) class PhredDecoderTests(unittest.TestCase): def test_missing_variant_and_phred_offset(self): with self.assertRaises(ValueError) as cm: _decode_qual_to_phred('abcd') self.assertIn('`variant`', str(cm.exception)) self.assertIn('`phred_offset`', str(cm.exception)) self.assertIn('decode', str(cm.exception)) def test_variant_and_phred_offset_provided(self): with self.assertRaises(ValueError) as cm: _decode_qual_to_phred('abcd', variant='sanger', phred_offset=64) self.assertIn('both', str(cm.exception)) self.assertIn('`variant`', str(cm.exception)) self.assertIn('`phred_offset`', str(cm.exception)) def test_solexa_variant(self): with self.assertRaises(ValueError) as cm: _decode_qual_to_phred('abcd', variant='solexa') self.assertIn('719', str(cm.exception)) def test_unrecognized_variant(self): with self.assertRaises(ValueError) as cm: _decode_qual_to_phred('abcd', variant='illumina') self.assertIn('variant', str(cm.exception)) self.assertIn("'illumina'", str(cm.exception)) def test_empty_qual_str(self): npt.assert_equal(_decode_qual_to_phred('', variant='sanger'), np.array([], dtype=np.uint8)) def test_sanger_variant(self): # test entire range of possible ascii chars for sanger all_sanger_ascii = ('!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOP' 'QRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~') obs = _decode_qual_to_phred(all_sanger_ascii, variant='sanger') npt.assert_equal(obs, np.arange(94)) with self.assertRaises(ValueError) as cm: _decode_qual_to_phred('a b', variant='sanger') self.assertIn('[0, 93]', str(cm.exception)) def test_illumina13_variant(self): # test entire range of possible ascii chars for illumina1.3 all_illumina13_ascii = ('@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijk' 'lmnopqrstuvwxyz{|}~') obs = _decode_qual_to_phred(all_illumina13_ascii, variant='illumina1.3') npt.assert_equal(obs, np.arange(63)) with self.assertRaises(ValueError) as cm: _decode_qual_to_phred('a!b', variant='illumina1.3') self.assertIn('[0, 62]', str(cm.exception)) def test_illumina18_variant(self): # test entire range of possible ascii chars for illumina1.8 all_illumina18_ascii = ('!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKL' 'MNOPQRSTUVWXYZ[\\]^_') obs = _decode_qual_to_phred(all_illumina18_ascii, variant='illumina1.8') npt.assert_equal(obs, np.arange(63)) with self.assertRaises(ValueError) as cm: _decode_qual_to_phred('AaB', variant='illumina1.8') self.assertIn('[0, 62]', str(cm.exception)) def test_custom_phred_offset(self): ascii_chars = '*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\' obs = _decode_qual_to_phred(ascii_chars, phred_offset=42) npt.assert_equal(obs, np.arange(51)) with self.assertRaises(ValueError) as cm: _decode_qual_to_phred(ascii_chars, phred_offset=43) self.assertIn('[0, 83]', str(cm.exception)) with self.assertRaises(ValueError) as cm: _decode_qual_to_phred(ascii_chars, phred_offset=0) self.assertIn('`phred_offset`', str(cm.exception)) self.assertIn('printable', str(cm.exception)) with self.assertRaises(ValueError) as cm: _decode_qual_to_phred(ascii_chars, phred_offset=127) self.assertIn('`phred_offset`', str(cm.exception)) self.assertIn('printable', str(cm.exception)) class PhredEncoderTests(unittest.TestCase): def test_missing_variant_and_phred_offset(self): with self.assertRaises(ValueError) as cm: _encode_phred_to_qual([1, 2, 3]) self.assertIn('`variant`', str(cm.exception)) self.assertIn('`phred_offset`', str(cm.exception)) self.assertIn('encode', str(cm.exception)) def test_variant_and_phred_offset_provided(self): with self.assertRaises(ValueError) as cm: _encode_phred_to_qual([1, 2, 3], variant='sanger', phred_offset=64) self.assertIn('both', str(cm.exception)) self.assertIn('`variant`', str(cm.exception)) self.assertIn('`phred_offset`', str(cm.exception)) def test_solexa_variant(self): with self.assertRaises(ValueError) as cm: _encode_phred_to_qual([1, 2, 3], variant='solexa') self.assertIn('719', str(cm.exception)) def test_unrecognized_variant(self): with self.assertRaises(ValueError) as cm: _encode_phred_to_qual([1, 2, 3], variant='illumina') self.assertIn('variant', str(cm.exception)) self.assertIn("'illumina'", str(cm.exception)) def test_no_phred_scores(self): self.assertEqual(_encode_phred_to_qual([], variant='sanger'), '') def test_sanger_variant(self): # test entire range of possible ascii chars for sanger all_sanger_ascii = ('!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOP' 'QRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~') obs = _encode_phred_to_qual(list(range(94)), variant='sanger') self.assertEqual(obs, all_sanger_ascii) with self.assertRaises(ValueError) as cm: _encode_phred_to_qual([42, -1, 33], variant='sanger') self.assertIn('-1', str(cm.exception)) self.assertIn('[0, 93]', str(cm.exception)) obs = npt.assert_warns(UserWarning, _encode_phred_to_qual, [42, 94, 33], variant='sanger') self.assertEqual(obs, 'K~B') def test_illumina13_variant(self): # test entire range of possible ascii chars for illumina1.3 all_illumina13_ascii = ('@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijk' 'lmnopqrstuvwxyz{|}~') obs = _encode_phred_to_qual(list(range(63)), variant='illumina1.3') self.assertEqual(obs, all_illumina13_ascii) with self.assertRaises(ValueError) as cm: _encode_phred_to_qual([42, -1, 33], variant='illumina1.3') self.assertIn('-1', str(cm.exception)) self.assertIn('[0, 62]', str(cm.exception)) obs = npt.assert_warns(UserWarning, _encode_phred_to_qual, [42, 63, 33], variant='illumina1.3') self.assertEqual(obs, 'j~a') def test_illumina18_variant(self): # test entire range of possible ascii chars for illumina1.8 all_illumina18_ascii = ('!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKL' 'MNOPQRSTUVWXYZ[\\]^_') obs = _encode_phred_to_qual(list(range(63)), variant='illumina1.8') self.assertEqual(obs, all_illumina18_ascii) with self.assertRaises(ValueError) as cm: _encode_phred_to_qual([42, -1, 33], variant='illumina1.8') self.assertIn('-1', str(cm.exception)) self.assertIn('[0, 62]', str(cm.exception)) obs = npt.assert_warns(UserWarning, _encode_phred_to_qual, [42, 63, 33], variant='illumina1.8') self.assertEqual(obs, 'K_B') def test_custom_phred_offset(self): ascii_chars = '*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\' obs = _encode_phred_to_qual(list(range(51)), phred_offset=42) self.assertEqual(obs, ascii_chars) with self.assertRaises(ValueError) as cm: _encode_phred_to_qual([42, -1, 33], phred_offset=42) self.assertIn('-1', str(cm.exception)) self.assertIn('[0, 84]', str(cm.exception)) obs = npt.assert_warns(UserWarning, _encode_phred_to_qual, [42, 255, 33], phred_offset=42) self.assertEqual(obs, 'T~K') class TestGetNthSequence(unittest.TestCase): def setUp(self): def generator(): for i in range(1, 6): yield 'goldilocks: ' + str(i) self.gen = generator() def test_seq_num_too_small(self): with self.assertRaises(ValueError) as cm: _get_nth_sequence(self.gen, 0) self.assertIn('between 1 and', str(cm.exception)) self.assertIn('0', str(cm.exception)) def test_seq_num_too_big(self): with self.assertRaises(ValueError) as cm: _get_nth_sequence(self.gen, 6) self.assertIn('end of file', str(cm.exception)) self.assertIn('6th', str(cm.exception)) def test_seq_num_just_right(self): value = _get_nth_sequence(self.gen, 3) self.assertEqual(value, 'goldilocks: 3') class TestParseFASTALikeHeader(unittest.TestCase): def test_no_id_or_description(self): obs = _parse_fasta_like_header('> \t\t \n') self.assertEqual(obs, ('', '')) def test_id_only(self): obs = _parse_fasta_like_header('>suht! \t\t \n') self.assertEqual(obs, ('suht!', '')) def test_description_only(self): obs = _parse_fasta_like_header('> suht! \t\t \n') self.assertEqual(obs, ('', 'suht!')) def test_id_and_description(self): obs = _parse_fasta_like_header('>!thus suht! \t\t \n') self.assertEqual(obs, ('!thus', 'suht!')) class TestFormatFASTALikeRecords(unittest.TestCase): def setUp(self): def generator(): yield Sequence('ACGT', metadata={'id': '', 'description': ''}, positional_metadata={'quality': range(4)}) yield RNA('GAU', metadata={'id': ' foo \t\t bar ', 'description': ''}) yield DNA('TAG', metadata={'id': '', 'description': 'foo\n\n bar\n'}) yield Sequence('A', metadata={'id': 'foo', 'description': 'bar baz'}, positional_metadata={'quality': [42]}) self.gen = generator() def test_no_replacement(self): exp = [ ('', 'ACGT', range(4)), (' foo \t\t bar ', 'GAU', None), (' foo\n\n bar\n', 'TAG', None), ('foo bar baz', 'A', [42]) ] obs = list(_format_fasta_like_records(self.gen, None, None, False)) self.assertEqual(len(obs), len(exp)) for o, e in zip(obs, exp): npt.assert_equal(o, e) def test_empty_str_replacement(self): exp = [ ('', 'ACGT', range(4)), ('foobar', 'GAU', None), (' foo bar', 'TAG', None), ('foo bar baz', 'A', [42]) ] obs = list(_format_fasta_like_records(self.gen, '', '', False)) self.assertEqual(len(obs), len(exp)) for o, e in zip(obs, exp): npt.assert_equal(o, e) def test_multi_char_replacement(self): exp = [ ('', 'ACGT', range(4)), ('-.--.-foo-.--.--.--.-bar-.-', 'GAU', None), (' foo_-__-_ bar_-_', 'TAG', None), ('foo bar baz', 'A', [42]) ] obs = list(_format_fasta_like_records(self.gen, '-.-', '_-_', False)) self.assertEqual(len(obs), len(exp)) for o, e in zip(obs, exp): npt.assert_equal(o, e) def test_newline_character_in_id_whitespace_replacement(self): with self.assertRaisesRegex(ValueError, r'Newline character'): list(_format_fasta_like_records(self.gen, '-\n--', ' ', False)) def test_newline_character_in_description_newline_replacement(self): with self.assertRaisesRegex(ValueError, r'Newline character'): list(_format_fasta_like_records(self.gen, None, 'a\nb', False)) def test_empty_sequence(self): def blank_seq_gen(): yield from (DNA('A'), Sequence(''), RNA('GG')) with self.assertRaisesRegex(ValueError, r'2nd.*empty'): list(_format_fasta_like_records(blank_seq_gen(), None, None, False)) def test_missing_quality_scores(self): def missing_qual_gen(): yield from (RNA('A', positional_metadata={'quality': [42]}), Sequence('AG'), DNA('GG', positional_metadata={'quality': [41, 40]})) with self.assertRaisesRegex(ValueError, r'2nd sequence.*quality scores'): list(_format_fasta_like_records(missing_qual_gen(), '-', '-', True)) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_binary_dm.py000066400000000000000000000136731520735541300261120ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import tempfile import os import numpy as np import numpy.testing as npt import h5py from skbio.stats.distance import PairwiseMatrix, SymmetricMatrix, DistanceMatrix from skbio.io import read as io_read from skbio.io.format.binary_dm import ( _h5py_mat_to_skbio_mat, _skbio_mat_to_h5py_mat, _get_header, _parse_ids, _verify_dimensions, _bytes_decoder, _passthrough_decoder, _set_header, _binary_dm_sniffer ) class BinaryMatrixTests(unittest.TestCase): def setUp(self): _vlen_dtype = h5py.special_dtype(vlen=str) self.mat = np.array([[0, 0.1, 0.2], [0.1, 0, 0.3], [0.2, 0.3, 0]]) self.ids = ['a', 'b', 'c'] self.tempdir = tempfile.TemporaryDirectory() self.basic_fname = os.path.join(self.tempdir.name, 'basic') self.basic = h5py.File(self.basic_fname, 'a') ids = self.basic.create_dataset('order', shape=(3, ), dtype=_vlen_dtype) ids[:] = self.ids self.basic.create_dataset('matrix', data=self.mat) _set_header(self.basic) self.basic.close() self.badids_fname = os.path.join(self.tempdir.name, 'badids') self.badids = h5py.File(self.badids_fname, 'a') ids = self.badids.create_dataset('order', shape=(2, ), dtype=_vlen_dtype) ids[:] = ['a', 'b'] self.badids.create_dataset('matrix', data=self.mat) _set_header(self.badids) self.badids.close() self.noheader_fname = os.path.join(self.tempdir.name, 'noheader') self.noheader = h5py.File(self.noheader_fname, 'a') ids = self.noheader.create_dataset('order', shape=(3, ), dtype=_vlen_dtype) ids[:] = self.ids self.noheader.create_dataset('matrix', data=self.mat) self.noheader.close() self.rw_fname = os.path.join(self.tempdir.name, 'rw') def tearDown(self): self.tempdir.cleanup() def test_binary_dm_sniffer(self): with open(self.basic_fname, 'rb') as fh: self.assertEqual((True, {}), _binary_dm_sniffer(fh)) with open(self.badids_fname, 'rb') as fh: self.assertEqual((False, {}), _binary_dm_sniffer(fh)) with open(self.noheader_fname, 'rb') as fh: self.assertEqual((False, {}), _binary_dm_sniffer(fh)) def test_h5py_mat_to_skbio_mat(self): exp = DistanceMatrix(self.mat, self.ids) obs = _h5py_mat_to_skbio_mat(DistanceMatrix, h5py.File(self.basic_fname, 'r')) self.assertEqual(obs, exp) def test_io_h5py_mat_to_skbio_mat(self): # test DistanceMatrix exp = DistanceMatrix(self.mat, self.ids) obs = io_read(self.basic_fname,into=DistanceMatrix) self.assertEqual(obs, exp) def test_io_h5py_mat_to_skbio_mat_pairwise(self): # test PairwiseMatrix exp = PairwiseMatrix(self.mat, self.ids) obs = io_read(self.basic_fname,into=PairwiseMatrix) self.assertEqual(obs, exp) def test_io_h5py_mat_to_skbio_mat_symmetric(self): # test SymmetricMatrix exp = SymmetricMatrix(self.mat, self.ids) obs = io_read(self.basic_fname,into=SymmetricMatrix) self.assertEqual(obs, exp) def test_skbio_mat_to_h5py_mat(self): fh1 = h5py.File('f1', 'a', driver='core', backing_store=False) mat = DistanceMatrix(self.mat, self.ids) _skbio_mat_to_h5py_mat(mat, fh1) npt.assert_equal(np.asarray(fh1['order'][:], dtype=str), mat.ids) npt.assert_equal(fh1['matrix'], mat.data) def test_io_mat_to_h5py_mat(self): mat = DistanceMatrix(self.mat, self.ids) mat.write(self.rw_fname,format='binary_dm') exp = mat obs = io_read(self.rw_fname,into=DistanceMatrix) self.assertEqual(obs, exp) def test_io_mat_to_h5py_mat_symmetric(self): # SymmetricMatrix mat = SymmetricMatrix(self.mat, self.ids) mat.write(self.rw_fname,format='binary_dm') exp = mat obs = io_read(self.rw_fname,into=SymmetricMatrix) self.assertEqual(obs, exp) def test_io_mat_to_h5py_mat_pairwise(self): # PairwiseMatrix mat = PairwiseMatrix(self.mat, self.ids) mat.write(self.rw_fname,format='binary_dm') exp = mat obs = io_read(self.rw_fname,into=PairwiseMatrix) self.assertEqual(obs, exp) def test_get_header(self): self.assertEqual(_get_header(h5py.File(self.basic_fname, 'r')), {'format': b'BDSM', 'version': b'2020.12'}) self.assertEqual(_get_header(h5py.File(self.noheader_fname, 'r')), None) def test_parse_ids(self): tests = [(['a', 'b', 'c'], ['a', 'b', 'c']), ([b'a', b'b', b'\xc3\xa9\xc3\xb8asd'], ['a', 'b', 'éøasd'])] for test, exp in tests: self.assertEqual(_parse_ids(test), exp) def test_verify_dimensions(self): self.assertTrue(_verify_dimensions(h5py.File(self.basic_fname, 'r'))) self.assertFalse(_verify_dimensions(h5py.File(self.badids_fname, 'r'))) def test_bytes_decoder(self): test = [b'', b'a', b'\xc3\xa9\xc3\xb8asd'] exp = ['', 'a', 'éøasd'] self.assertEqual(_bytes_decoder(test), exp) def test_passthrough_decoder(self): tests = [('', ''), ('a', 'a'), ('éøasd', 'éøasd')] for test, expected in tests: self.assertEqual(_passthrough_decoder(test), expected) def test_set_header(self): def mock(): obj = h5py.File('bung', 'a', driver='core', backing_store=False) return obj m = mock() _set_header(m) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_biom.py000066400000000000000000000045031520735541300250640ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io import unittest import tempfile from pathlib import Path import h5py from skbio.table import Table, example_table from skbio.io.format.biom import ( _biom_to_table, _table_to_biom, _biom_sniffer) class BIOMFormatTests(unittest.TestCase): def setUp(self): self.tempdir = tempfile.TemporaryDirectory() tempdir = Path(self.tempdir.name) self.valid_biom_path = str(tempdir / Path('valid.biom')) self.invalid_biom_path = str(tempdir / Path('invalid')) self.writable_biom_path = str(tempdir / Path('write.biom')) self.nonbiom_hdf5_path = str(tempdir / Path('other.hdf5')) self.difbiomver_path = str(tempdir / Path('otherver.biom')) self.table = example_table.copy() with h5py.File(self.valid_biom_path, 'w') as fp: self.table.to_hdf5(fp, 'unit-test') with open(self.invalid_biom_path, 'wb') as fp: fp.write(b'this is not a biom file') with h5py.File(self.nonbiom_hdf5_path, 'w') as fp: fp['stuff'] = [1, 2, 3] self.table = example_table.copy() with h5py.File(self.difbiomver_path, 'w') as fp: self.table.to_hdf5(fp, 'unit-test') fp.attrs['format-version'] = [3, 0] def tearDown(self): self.tempdir.cleanup() def test_sniffer(self): self.assertEqual(_biom_sniffer(self.valid_biom_path), (True, {})) self.assertEqual(_biom_sniffer(self.invalid_biom_path), (False, {})) self.assertEqual(_biom_sniffer(self.nonbiom_hdf5_path), (False, {})) self.assertEqual(_biom_sniffer(self.difbiomver_path), (False, {})) def test_biom_to_table(self): tab = _biom_to_table(self.valid_biom_path) self.assertEqual(tab, self.table) def test_table_to_biom(self): _table_to_biom(self.table, self.writable_biom_path) roundtrip = _biom_to_table(self.writable_biom_path) self.assertEqual(roundtrip, self.table) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_blast6.py000066400000000000000000000143771520735541300253430ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import pandas as pd import numpy as np from skbio.util import get_data_path, assert_data_frame_almost_equal from skbio.io.format.blast6 import _blast6_to_data_frame class TestBlast6Reader(unittest.TestCase): def test_default_valid_single_line(self): fp = get_data_path('blast6_default_single_line') df = _blast6_to_data_frame(fp, default_columns=True) exp = pd.DataFrame([['query1', 'subject2', 75.0, 8.0, 2.0, 0.0, 1.0, 8.0, 2.0, 9.0, 0.06, 11.5]], columns=['qseqid', 'sseqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'evalue', 'bitscore']) assert_data_frame_almost_equal(df, exp) def test_default_valid_multi_line(self): fp = get_data_path('blast6_default_multi_line') df = _blast6_to_data_frame(fp, default_columns=True) exp = pd.DataFrame([['query1', 'subject2', 100.00, 8.0, 0.0, 0.0, 1.0, 8.0, 3.0, 10.0, 9e-05, 16.9], ['query1', 'subject2', 75.00, 8.0, 2.0, 0.0, 1.0, 8.0, 2.0, 9.0, 0.060, 11.5], ['query2', 'subject1', 71.43, 7.0, 2.0, 0.0, 1.0, 7.0, 1.0, 7.0, 0.044, 11.9]], columns=['qseqid', 'sseqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'evalue', 'bitscore']) assert_data_frame_almost_equal(df, exp) def test_custom_valid_single_line(self): fp = get_data_path('blast6_custom_single_line') df = _blast6_to_data_frame(fp, columns=['qacc', 'qseq', 'btop', 'sframe', 'ppos', 'positive', 'gaps']) exp = pd.DataFrame([['query1', 'PAAWWWWW', 8.0, 1.0, 100.00, 8.0, 0.0]], columns=['qacc', 'qseq', 'btop', 'sframe', 'ppos', 'positive', 'gaps']) assert_data_frame_almost_equal(df, exp) def test_custom_valid_multi_line(self): fp = get_data_path('blast6_custom_multi_line') df = _blast6_to_data_frame(fp, columns=['sacc', 'score', 'gapopen', 'qcovs', 'sblastnames', 'sallacc', 'qaccver']) exp = pd.DataFrame([['subject2', 32.0, 0.0, 100.0, np.nan, 'subject2', 'query1'], ['subject2', 18.0, 0.0, 100.0, np.nan, 'subject2', 'query1'], ['subject1', 19.0, 0.0, 70.0, np.nan, 'subject1', 'query2']], columns=['sacc', 'score', 'gapopen', 'qcovs', 'sblastnames', 'sallacc', 'qaccver']) # Depending on Pandas version, this column may be string, object, or float # (np.nan). Converting to object enables passing with all versions. df['sblastnames'] = df['sblastnames'].astype(object) exp['sblastnames'] = exp['sblastnames'].astype(object) assert_data_frame_almost_equal(df, exp) def test_valid_nan_handling(self): fp = get_data_path('blast6_custom_mixed_nans') df = _blast6_to_data_frame(fp, columns=['qacc', 'qseq', 'btop', 'sframe', 'ppos', 'positive', 'gaps']) exp = pd.DataFrame([[np.nan, 'PAAWWWWW', 8.0, 1.0, 100.00, np.nan, 0.0], ['query1', np.nan, 8.0, 1.0, np.nan, 8.0, 0.0]], columns=['qacc', 'qseq', 'btop', 'sframe', 'ppos', 'positive', 'gaps']) assert_data_frame_almost_equal(df, exp) def test_valid_minimal(self): fp = get_data_path('blast6_custom_minimal') df = _blast6_to_data_frame(fp, columns=['sacc']) exp = pd.DataFrame([['subject2']], columns=['sacc']) assert_data_frame_almost_equal(df, exp) def test_custom_and_default_passed_error(self): fp = get_data_path('blast6_default_single_line') with self.assertRaisesRegex(ValueError, r"`columns` and `default_columns`"): _blast6_to_data_frame(fp, columns=['qseqid'], default_columns=True) def test_no_columns_passed_error(self): fp = get_data_path('blast6_default_single_line') with self.assertRaisesRegex(ValueError, r"Either `columns` or `default_columns`"): _blast6_to_data_frame(fp) def test_wrong_amount_of_columns_error(self): fp = get_data_path('blast6_invalid_number_of_columns') with self.assertRaisesRegex( ValueError, r"Specified number of columns \(12\).*\(10\)"): _blast6_to_data_frame(fp, default_columns=True) def test_different_data_in_same_column(self): fp = get_data_path('blast6_invalid_type_in_column') with self.assertRaises(ValueError): _blast6_to_data_frame(fp, default_columns=True) def test_wrong_column_name_error(self): fp = get_data_path('blast6_default_single_line') with self.assertRaisesRegex(ValueError, r"Unrecognized column.*'abcd'"): _blast6_to_data_frame(fp, columns=['qseqid', 'sseqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'abcd', 'bitscore']) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_blast7.py000066400000000000000000000233601520735541300253340ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import pandas as pd import numpy as np from skbio.util import get_data_path, assert_data_frame_almost_equal from skbio.io import BLAST7FormatError from skbio.io.format.blast7 import _blast7_to_data_frame, _blast7_sniffer class TestBLAST7Sniffer(unittest.TestCase): def setUp(self): self.positives = [get_data_path(e) for e in [ 'blast7_default_single_line', 'blast7_default_multi_line', 'blast7_custom_minimal', 'blast7_custom_single_line', 'blast7_custom_multi_line', 'blast7_custom_mixed_nans', 'blast7_invalid_differing_fields', 'blast7_invalid_no_data', 'blast7_invalid_too_many_columns', 'legacy9_and_blast7_default', 'legacy9_invalid_too_many_columns', 'legacy9_mixed_nans', 'legacy9_multi_line', 'legacy9_single_line']] self.negatives = [get_data_path(e) for e in [ 'blast7_invalid_gibberish', 'blast7_invalid_for_sniffer', 'blast7_invalid_for_sniffer_2', 'empty']] def test_positives(self): for fp in self.positives: self.assertEqual(_blast7_sniffer(fp), (True, {})) def test_negatives(self): for fp in self.negatives: self.assertEqual(_blast7_sniffer(fp), (False, {})) class TestBlast7Reader(unittest.TestCase): def test_default_valid_single_line(self): fp = get_data_path('blast7_default_single_line') df = _blast7_to_data_frame(fp) exp = pd.DataFrame([['query1', 'subject2', 100.00, 8.0, 0.0, 0.0, 1.0, 8.0, 3.0, 10.0, 9e-05, 16.9]], columns=['qseqid', 'sseqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'evalue', 'bitscore']) assert_data_frame_almost_equal(df, exp) fp = get_data_path('legacy9_single_line') df = _blast7_to_data_frame(fp) exp = pd.DataFrame([['query1', 'subject1', 90.00, 7.0, 1.0, 0.0, 0.0, 8.0, 4.0, 10.0, 1e-05, 15.5]], columns=['qseqid', 'sseqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'evalue', 'bitscore']) assert_data_frame_almost_equal(df, exp) def test_default_valid_multi_line(self): fp = get_data_path('blast7_default_multi_line') df = _blast7_to_data_frame(fp) exp = pd.DataFrame([['query1', 'subject2', 70.00, 5.0, 0.0, 0.0, 7.0, 60.0, 3.0, 100.0, 9e-05, 10.5], ['query1', 'subject2', 30.00, 8.0, 0.0, 0.0, 6.0, 15.0, 1.0, 100.0, 0.053, 12.0], ['query1', 'subject2', 90.00, 2.0, 0.0, 0.0, 9.0, 35.0, 2.0, 100.0, 0.002, 8.3]], columns=['qseqid', 'sseqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'evalue', 'bitscore']) assert_data_frame_almost_equal(df, exp) fp = get_data_path('legacy9_multi_line') df = _blast7_to_data_frame(fp) exp = pd.DataFrame([['query1', 'subject1', 90.00, 7.0, 1.0, 0.0, 0.0, 8.0, 4.0, 10.0, 1e-05, 15.5], ['query1', 'subject1', 70.00, 8.0, 0.0, 1.0, 0.0, 9.0, 5.0, 7.0, 0.231, 7.8], ['query1', 'subject1', 90.00, 5.0, 1.0, 1.0, 0.0, 0.0, 2.0, 10.0, 0.022, 13.0]], columns=['qseqid', 'sseqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'evalue', 'bitscore']) assert_data_frame_almost_equal(df, exp) def test_default_valid_mixed_output(self): fp = get_data_path('legacy9_and_blast7_default') df = _blast7_to_data_frame(fp) exp = pd.DataFrame([['query2', 'subject2', 100.00, 8.0, 0.0, 1.0, 0.0, 9.0, 3.0, 10.0, 2e-05, 9.8], ['query2', 'subject1', 70.00, 9.0, 1.0, 0.0, 1.0, 8.0, 4.0, 9.0, 0.025, 11.7]], columns=['qseqid', 'sseqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'evalue', 'bitscore']) assert_data_frame_almost_equal(df, exp) def test_custom_valid_minimal(self): fp = get_data_path("blast7_custom_minimal") df = _blast7_to_data_frame(fp) exp = pd.DataFrame([['query1']], columns=['qseqid']) assert_data_frame_almost_equal(df, exp) def test_custom_valid_single_line(self): fp = get_data_path("blast7_custom_single_line") df = _blast7_to_data_frame(fp) exp = pd.DataFrame([['query1', 100.00, 100.00, 8.0, 0.0, 16.9, 8.0, 'PAAWWWWW']], columns=['qseqid', 'ppos', 'pident', 'length', 'sgi', 'bitscore', 'qend', 'qseq']) assert_data_frame_almost_equal(df, exp) def test_custom_valid_multi_line(self): fp = get_data_path("blast7_custom_multi_line") df = _blast7_to_data_frame(fp) exp = pd.DataFrame([[1.0, 8.0, 3.0, 10.0, 8.0, 0.0, 1.0, 'query1', 'subject2'], [2.0, 5.0, 2.0, 15.0, 8.0, 0.0, 2.0, 'query1', 'subject2'], [1.0, 6.0, 2.0, 12.0, 8.0, 0.0, 1.0, 'query1', 'subject2']], columns=['qstart', 'qend', 'sstart', 'send', 'nident', 'mismatch', 'sframe', 'qaccver', 'saccver']) assert_data_frame_almost_equal(df, exp) def test_custom_valid_mixed_nans(self): fp = get_data_path("blast7_custom_mixed_nans") df = _blast7_to_data_frame(fp) exp = pd.DataFrame([[0.0, np.nan, 8.0, 13.0, 1.0, 1.0, np.nan, 'subject2'], [np.nan, 0.0, 8.0, np.nan, 1.0, 1.0, 'query1', np.nan]], columns=['qgi', 'sgi', 'qlen', 'slen', 'qframe', 'sframe', 'qseqid', 'sseqid']) assert_data_frame_almost_equal(df, exp) def test_legacy9_valid_mixed_nans(self): fp = get_data_path("legacy9_mixed_nans") df = _blast7_to_data_frame(fp) exp = pd.DataFrame([[np.nan, 'subject1', np.nan, 7.0, 1.0, 0.0, np.nan, 8.0, 4.0, 10.0, np.nan, 15.5], ['query2', 'subject1', 90.00, 8.0, np.nan, 0.0, 0.0, 8.0, np.nan, 9.0, 1e-05, np.nan]], columns=['qseqid', 'sseqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'evalue', 'bitscore']) assert_data_frame_almost_equal(df, exp) def test_differing_fields_error(self): fp = get_data_path("blast7_invalid_differing_fields") with self.assertRaisesRegex( BLAST7FormatError, r"Fields \[.*'qseqid', .*'sseqid', .*'qstart'\]" r" do.*\[.*'qseqid', .*'sseqid', .*'score'\]"): _blast7_to_data_frame(fp) fp = get_data_path("legacy9_invalid_differing_fields") with self.assertRaisesRegex( BLAST7FormatError, r"Fields \[.*'qseqid', .*'sseqid', .*'qstart'\]" r" do.*\[.*'qseqid', .*'sseqid', " r".*'sallseqid'\]"): _blast7_to_data_frame(fp) def test_no_data_error(self): fp = get_data_path("blast7_invalid_gibberish") with self.assertRaisesRegex(BLAST7FormatError, r"File contains no"): _blast7_to_data_frame(fp) fp = get_data_path("blast7_invalid_no_data") with self.assertRaisesRegex(BLAST7FormatError, r"File contains no"): _blast7_to_data_frame(fp) fp = get_data_path("empty") with self.assertRaisesRegex(BLAST7FormatError, r"File contains no"): _blast7_to_data_frame(fp) def test_wrong_amount_of_columns_error(self): fp = get_data_path("blast7_invalid_too_many_columns") with self.assertRaisesRegex(BLAST7FormatError, r"Number of fields.*\(2\)"): _blast7_to_data_frame(fp) fp = get_data_path("legacy9_invalid_too_many_columns") with self.assertRaisesRegex(BLAST7FormatError, r"Number of fields.*\(12\)"): _blast7_to_data_frame(fp) def test_unrecognized_field_error(self): fp = get_data_path("blast7_invalid_unrecognized_field") with self.assertRaisesRegex(BLAST7FormatError, r"Unrecognized field \(.*'sallid'\)"): _blast7_to_data_frame(fp) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_clustal.py000066400000000000000000000267031520735541300256130ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import string from io import StringIO from unittest import TestCase, main from skbio import TabularMSA from skbio.sequence import GrammaredSequence from skbio.util import classproperty from skbio.util._decorator import overrides from skbio.io.format.clustal import ( _clustal_to_tabular_msa, _tabular_msa_to_clustal, _clustal_sniffer, _is_clustal_seq_line, _delete_trailing_number, _check_length, _label_line_parser) from skbio.io import ClustalFormatError class CustomSequence(GrammaredSequence): @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set('-.') @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return '-' @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set(string.ascii_letters) @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return {} class ClustalHelperTests(TestCase): def test_label_line_parser(self): self.assertEqual(_label_line_parser(StringIO('abc\tucag')), ({"abc": ["ucag"]}, ['abc'])) with self.assertRaises(ClustalFormatError): _label_line_parser(StringIO('abctucag')) def test_is_clustal_seq_line(self): ic = _is_clustal_seq_line self.assertTrue(ic('abc')) self.assertTrue(ic('abc def')) self.assertFalse(ic('CLUSTAL')) self.assertFalse(ic('CLUSTAL W fsdhicjkjsdk')) self.assertFalse(ic(' * *')) self.assertFalse(ic(' abc def')) self.assertFalse(ic('MUSCLE (3.41) multiple sequence alignment')) def test_delete_trailing_number(self): dtn = _delete_trailing_number self.assertEqual(dtn('abc'), 'abc') self.assertEqual(dtn('a b c'), 'a b c') self.assertEqual(dtn('a \t b \t c'), 'a \t b \t c') self.assertEqual(dtn('a b 3'), 'a b') self.assertEqual(dtn('a b c \t 345'), 'a b c') def test_check_lengh(self): self.assertEqual(False, _check_length({'abc': ['adjfkadfjaksdlfadskfda'], 'xyz': ['adjfkadfjaksdlfadsk']}, ['abc', 'xyz'])), self.assertEqual(True, _check_length({'abc': ['adjfkadfjaksdlfadskfda'], 'xyz': ['adjfkadfjaksdlfadsksdf']}, ['abc', 'xyz'])) self.assertEqual(True, _check_length({'abc': ['adjfkadfjaksdlfadskfda', 'adjfkadfjaksdlfadskfda'], 'xyz': ['adjfkadfjaksdlfadsksdf', 'adjfkadfjaksdlfadsksdf']}, ['abc', 'xyz'])) self.assertEqual(False, _check_length({'abc': ['adjfkadfjaksdlfadskfd', 'adjfkadfjaksdlfadskfda'], 'xyz': ['adjfkadfjaksdlfadsksdf', 'adjfkadfjaksdlfadsksdf']}, ['abc', 'xyz'])) self.assertEqual(False, _check_length({'abc': ['adjfkadfjaksdlfadskfda', 'adjfkadfjaksdlfadskfda'], 'xyz': ['adjfkadfjaksdlfadsksdf', 'adjfkadfjaksdlfadsksd']}, ['abc', 'xyz'])) class ClustalIOTests(TestCase): def setUp(self): self.valid_clustal_out = [ StringIO('CLUSTAL\n\nabc\tucag'), StringIO('CLUSTAL\n\nabc\tuuu\ndef\tccc\n\n ***\n\ndef ggg\nab' 'c\taaa\n'), StringIO('\n'.join(['CLUSTAL\n', 'abc uca', 'def ggg ccc'])), StringIO('\n'.join(['CLUSTAL\n', 'abc uca ggg', 'def ggg ccc'])), StringIO("""CLUSTAL abc GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCAUCA def ------------------------------------------------------------ xyz ------------------------------------------------------------ """), StringIO("""CLUSTAL abc GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCAUCA def ------------------------------------------------------------ xyz ------------------------------------------------------------ abc GUCGAUACGUACGUCAGUCAGUACGUCAGCAUGCAUACGUACGUCGUACGUACGU-CGAC def -----------------------------------------CGCGAUGCAUGCAU-CGAU xyz -------------------------------------CAUGCAUCGUACGUACGCAUGAC """), StringIO("""CLUSTAL W (1.82) multiple sequence alignment abc GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCAUCA def ------------------------------------------------------------ xyz ------------------------------------------------------------ abc GUCGAUACGUACGUCAGUCAGUACGUCAGCAUGCAUACGUACGUCGUACGUACGU-CGAC def -----------------------------------------CGCGAUGCAUGCAU-CGAU xyz -------------------------------------CAUGCAUCGUACGUACGCAUGAC abc UGACUAGUCAGCUAGCAUCGAUCAGU def CGAUCAGUCAGUCGAU---------- xyz UGCUGCAUCA----------------"""), StringIO("""CLUSTAL W (1.74) multiple sequence alignment abc GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCAUCA 60 def ------------------------------------------------------------ xyz ------------------------------------------------------------ abc GUCGAUACGUACGUCAGUCAGUACGUCAGCAUGCAUACGUACGUCGUACGUACGU-CGAC 11 def -----------------------------------------CGCGAUGCAUGCAU-CGAU 18 xyz -------------------------------------CAUGCAUCGUACGUACGCAUGAC 23 : * * * * ** abc UGACUAGUCAGCUAGCAUCGAUCAGU 145 def CGAUCAGUCAGUCGAU---------- 34 xyz UGCUGCAUCA---------------- 33 * ***""") ] self.invalid_clustal_out = [ StringIO('\n'.join(['dshfjsdfhdfsj', 'hfsdjksdfhjsdf'])), StringIO('\n'.join(['hfsdjksdfhjsdf'])), StringIO('\n'.join(['dshfjsdfhdfsj', 'dshfjsdfhdfsj', 'hfsdjksdfhjsdf'])), StringIO('\n'.join(['dshfjsdfhdfsj', '\t', 'hfsdjksdfhjsdf'])), StringIO('\n'.join(['dshfj\tdfhdfsj', 'hfsdjksdfhjsdf'])), StringIO('\n'.join(['dshfjsdfhdfsj', 'hfsdjk\tdfhjsdf'])), StringIO("""CLUSTAL W (1.74) multiple sequence alignment adj GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCAUCA ------------------------------------------------------------ adk -----GGGGGGG------------------------------------------------ """), StringIO("""CLUSTAL W (1.74) multiple sequence alignment adj GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCAUCA adk -----GGGGGGG------------------------------------------------ adj GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCAUCA adk -----GGGGGGG--------------------------------------------- """), StringIO("""CLUSTAL W (1.74) multiple sequence alignment adj GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCAUCA adk -----GGGGGGG--------------------------------------------- adj GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCA adk -----GGGGGGG--------------------------------------------- """), StringIO("""CLUSTAL W (1.74) multiple sequence alignment adj GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCAUCA ------------------------------------------------------------ adk -----GGGGGGG------------------------------------------------ """), StringIO("""CLUSTAL W (1.74) multiple sequence alignment GCAUGCAUGCAUGAUCGUACGUCAGCAUGCUAGACUGCAUACGUACGUACGCAUGCAUCA ------------------------------------------------------------ ------------------------------------------------------------ GUCGAUACGUACGUCAGUCAGUACGUCAGCAUGCAUACGUACGUCGUACGUACGU-CGAC -----------------------------------------CGCGAUGCAUGCAU-CGAU ------------------------------------------------------------ : * * * * ** UGACUAGUCAGCUAGCAUCGAUCAGU 145 CGAUCAGUCAGUCGAU---------- 34 UGCUGCAUCA---------------- 33 * ***""")] def test_tabular_msa_to_clustal_with_empty_input(self): result = _clustal_to_tabular_msa(StringIO(), constructor=CustomSequence) self.assertEqual(dict(result), {}) def test_tabular_msa_to_clustal_with_bad_input(self): BAD = StringIO('\n'.join(['dshfjsdfhdfsj', 'hfsdjksdfhjsdf'])) with self.assertRaises(ClustalFormatError): dict(_clustal_to_tabular_msa(BAD, constructor=CustomSequence)) def test_valid_tabular_msa_to_clustal_and_clustal_to_tabular_msa(self): for valid_out in self.valid_clustal_out: result_before = _clustal_to_tabular_msa( valid_out, constructor=CustomSequence) with StringIO() as fh: _tabular_msa_to_clustal(result_before, fh) fh.seek(0) result_after = _clustal_to_tabular_msa( fh, constructor=CustomSequence) self.assertEqual(result_before, result_after) def test_invalid_tabular_msa_to_clustal_and_clustal_to_tabular_msa(self): for invalid_out in self.invalid_clustal_out: with self.assertRaises(ClustalFormatError): dict(_clustal_to_tabular_msa(invalid_out, constructor=CustomSequence)) def test_clustal_sniffer_valid_files(self): for valid_out in self.valid_clustal_out: self.assertEqual(_clustal_sniffer(valid_out), (True, {})) def test_clustal_sniffer_invalid_files(self): for invalid_out in self.invalid_clustal_out: self.assertEqual(_clustal_sniffer(invalid_out), (False, {})) # sniffer should return False on empty file (which isn't contained # in self.invalid_clustal_out since an empty file is a valid output) self.assertEqual(_clustal_sniffer(StringIO()), (False, {})) def test_no_constructor(self): with self.assertRaisesRegex(ValueError, r"`constructor`"): _clustal_to_tabular_msa(self.valid_clustal_out[0]) def test_duplicate_labels(self): msa = TabularMSA([CustomSequence('foo'), CustomSequence('bar')], index=['a', 'a']) with self.assertRaisesRegex(ClustalFormatError, r"index.*unique"): with StringIO() as fh: _tabular_msa_to_clustal(msa, fh) def test_invalid_lengths(self): fh = StringIO( "CLUSTAL\n" "\n\n" "abc GCAU\n" "def -----\n") with self.assertRaisesRegex(ClustalFormatError, r"not aligned"): _clustal_to_tabular_msa(fh, constructor=CustomSequence) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_embed.py000066400000000000000000000213541520735541300252150ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main from pathlib import Path import tempfile import os import re import h5py import numpy as np import skbio from skbio.io import write from skbio import Protein from skbio.util import get_data_path from skbio.embedding._protein import ProteinEmbedding from skbio.embedding._protein import ProteinVector from skbio.io.format.embed import ( _embed_sniffer, _embed_to_generator, _generator_to_embed, _embed_to_protein, _protein_to_embed, _protein_to_vector, _vector_to_protein ) class TestWriteError(TestCase): def setUp(self): self.tempdir = tempfile.TemporaryDirectory() def test_write_function(self): # note: tiny_embedding_file stores embeddings for our 20 seqs. with open(get_data_path('tiny_embedding_file.npz'), 'rb') as fh: embeddings = np.load(fh) emb_list = [embeddings[arrs] for arrs in embeddings.files] # note: pdb_hits.txt stores sequence strings for our 20 seqs. seqs = np.loadtxt(get_data_path('pdb_hits.txt'), dtype=str) seq_list = [" ".join(list(re.sub(r"[UZOB]", "X", str(seq)))) for seq in seqs] embed_list = [] for emb, seq in zip(emb_list, seq_list): embed_list.append(ProteinEmbedding(embedding=emb, sequence=seq)) # create generator object for write testing embed_list = (emb for emb in embed_list) file_path = os.path.join(self.tempdir.name, 'test_pdb_hits.h5') write(embed_list, 'embed', into=get_data_path(file_path)) self.assertTrue(os.path.exists(file_path)) class EmbedTests(TestCase): def setUp(self): # single sequence rk = 5 # latent dimension of residues self.sequences = ( [ ( np.load(get_data_path('embed1.txt.npy')), Protein(('IGKEEIQQRLAQFVDHWKELKQLAAARGQRL' 'EESLEYQQFVANVEEEEAWINEKMTLVASED'), metadata={"id": "seq1"}) ), ( np.load(get_data_path('embed2.txt.npy')), Protein(('QQNKELNFKLREKQNEIFELKKIAETLRSKL' 'EKYVDITKKLEDQNLNLQIKISDLEKKLSDA'), metadata={"id": "seq2"}) ) ] ) self.tempdir = tempfile.TemporaryDirectory() tempdir = Path(self.tempdir.name) self.writable_emb_path = str(tempdir / Path('test.emb')) self.writable_emb_path2 = str(tempdir / Path('test2.emb')) self.valid_embed_path = get_data_path('prot.emb') self.invalid_embed_path = str(tempdir / Path('invalid')) self.nonembed_hdf5_path = str(tempdir / Path('other.hdf5')) with open(self.invalid_embed_path, 'wb') as fp: fp.write(b'this is not a embed file') with h5py.File(self.nonembed_hdf5_path, 'w') as fp: fp['stuff'] = [1, 2, 3] def test_sniffer(self): self.assertEqual(_embed_sniffer(self.valid_embed_path), (True, {})) self.assertEqual(_embed_sniffer(self.invalid_embed_path), (False, {})) self.assertEqual(_embed_sniffer(self.nonembed_hdf5_path), (False, {})) def test_read_write_single(self): for emb, seq in self.sequences: fh = self.writable_emb_path obj = ProteinEmbedding(emb, seq) _protein_to_embed(obj, fh) emb2 = _embed_to_protein(fh) np.testing.assert_array_equal(emb, emb2.embedding) self.assertEqual(str(seq), str(emb2)) def test_read_write_generator(self): writable_emb_path2 = 'test2.emb' objs1 = [ProteinEmbedding(emb, seq) for emb, seq in self.sequences] _generator_to_embed(objs1, self.writable_emb_path2) objs2 = _embed_to_generator(self.writable_emb_path2) for obj1, obj2 in zip(objs1, objs2): np.testing.assert_array_equal(obj1.embedding, obj2.embedding) self.assertEqual(str(obj1), str(obj2)) def test_write_generator(self): sequences = [ ( np.load(get_data_path('embed1.txt.npy')), Protein(('IGKEEIQQRLAQFVDHWKELKQLAAARGQRL' 'EESLEYQQFVANVEEEEAWINEKMTLVASED'), metadata={"id": "seq1"}) ), ( np.load(get_data_path('embed2.txt.npy')), Protein(('QQNKELNFKLREKQNEIFELKKIAETLRSKL' 'EKYVDITKKLEDQNLNLQIKISDLEKKLSDA'), metadata={"id": "seq2"}) ) ] f = lambda x: ProteinEmbedding(*x) objs1 = (x for x in map(f, sequences)) tempdir = Path(tempfile.mkdtemp()) writable_emb_path = str(tempdir / Path('test.emb')) skbio.io.write(objs1, format='embed', into=writable_emb_path) objs2 = iter(skbio.io.read(writable_emb_path, format='embed', constructor=ProteinEmbedding)) for obj1, obj2 in zip(objs1, objs2): np.testing.assert_array_equal(obj1.embedding, obj2.embedding) self.assertEqual(str(obj1), str(obj2)) class VectorTests(TestCase): def setUp(self): # single sequence rk = 10 # latent dimension of residues self.sequences = ( [ ( np.random.randn(rk), Protein(('IGKEEIQQRLAQFVDHWKELKQLAAARGQRL' 'EESLEYQQFVANVEEEEAWINEKMTLVASED'), metadata={"id": "seq1"}) ), ( np.random.randn(rk), Protein(('QQNKELNFKLREKQNEIFELKKIAETLRSKL' 'EKYVDITKKLEDQNLNLQIKISDLEKKLSDA'), metadata={"id": "seq2"}) ) ] ) self.tempdir = tempfile.TemporaryDirectory() tempdir = Path(self.tempdir.name) self.writable_emb_path = str(tempdir / Path('test.emb')) self.writable_emb_path2 = str(tempdir / Path('test2.emb')) self.valid_embed_path = get_data_path('prot_vec.emb') self.invalid_embed_path = str(tempdir / Path('invalid')) self.nonembed_hdf5_path = str(tempdir / Path('other.hdf5')) with open(self.invalid_embed_path, 'wb') as fp: fp.write(b'this is not a embed file') with h5py.File(self.nonembed_hdf5_path, 'w') as fp: fp['stuff'] = [1, 2, 3] def test_sniffer(self): # make sure that the sniffer throws errors as expected self.assertEqual(_embed_sniffer(self.valid_embed_path), (True, {})) self.assertEqual(_embed_sniffer(self.invalid_embed_path), (False, {})) self.assertEqual(_embed_sniffer(self.nonembed_hdf5_path), (False, {})) emb, seq = self.sequences[0] obj = ProteinVector(emb, seq) _protein_to_vector(obj, str(Path(self.tempdir.name) / Path("prot_vec.emb"))) def test_read_write_single(self): for emb, seq in self.sequences: fh = self.writable_emb_path obj = ProteinVector(emb, seq) _protein_to_vector(obj, fh) emb2 = _vector_to_protein(fh) np.testing.assert_array_equal( emb, emb2.embedding.ravel()) self.assertEqual(str(seq), str(emb2)) def test_read_write_generator(self): writable_emb_path2 = 'test2.emb' objs1 = [ProteinVector(emb, seq) for emb, seq in self.sequences] _generator_to_embed(objs1, self.writable_emb_path2) objs2 = _embed_to_generator(self.writable_emb_path2, constructor=ProteinVector) for obj1, obj2 in zip(objs1, objs2): np.testing.assert_array_equal(obj1.embedding, obj2.embedding) self.assertEqual(str(obj1), str(obj2)) def test_write_generator(self): sequences = self.sequences f = lambda x: ProteinVector(*x) objs1 = (x for x in map(f, sequences)) tempdir = Path(tempfile.mkdtemp()) writable_emb_path = str(tempdir / Path('test.emb')) skbio.io.write(objs1, format='embed', into=writable_emb_path) objs2 = iter(skbio.io.read(writable_emb_path, format='embed', constructor=ProteinVector)) for obj1, obj2 in zip(objs1, objs2): np.testing.assert_array_equal(obj1.embedding, obj2.embedding) self.assertEqual(str(obj1), str(obj2)) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_embl.py000066400000000000000000001067311520735541300250630ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from unittest import TestCase, main import skbio.io from skbio import DNA, RNA, Sequence, Protein from skbio.metadata import IntervalMetadata from skbio.util import get_data_path # Module specific execption and functions from skbio.io import EMBLFormatError from skbio.io.format.embl import ( _embl_sniffer, _parse_id, _parse_reference, _embl_to_generator, _get_embl_section, _embl_to_sequence, _embl_to_dna, _embl_to_rna, _embl_to_protein, _generator_to_embl, _sequence_to_embl, _protein_to_embl, _rna_to_embl, _dna_to_embl, _serialize_id, _parse_assembly, _embl_parse_section_default, _serialize_dbsource) class SnifferTests(TestCase): def setUp(self): self.positive_fps = list(map(get_data_path, [ 'embl_single_record', 'embl_multi_records'])) self.negative_fps = list(map(get_data_path, [ 'empty', 'whitespace_only', 'embl_uniprot_record', 'embl_w_beginning_whitespace'])) def test_positives(self): for fp in self.positive_fps: self.assertEqual(_embl_sniffer(fp), (True, {})) def test_negatives(self): for fp in self.negative_fps: self.assertEqual(_embl_sniffer(fp), (False, {})) # Boilerplate for EMBL IO tests # TODO: implements all setUp needed class EMBLIOTests(TestCase): def setUp(self): # to test ID line self.id = ( # This is a derived record (non-coding, rRNA and spacer records) # (feature level record: # http://www.ebi.ac.uk/ena/browse/feature-level-products # TODO: a Uniprot record? (['ID AB000684.1:1..275:rRNA; SV 1; linear; ' 'genomic DNA; STD; ENV; 275 BP.'], {'division': 'ENV', 'mol_type': 'genomic DNA', 'shape': 'linear', 'locus_name': 'AB000684.1:1..275:rRNA', 'unit': 'bp', 'size': 275, 'version': 1, 'class': 'STD', 'date': None}), # A standard record (['ID M14399; SV 1; linear; mRNA; STD; PRO; 63 BP.'], {'division': 'PRO', 'mol_type': 'mRNA', 'shape': 'linear', 'locus_name': 'M14399', 'unit': 'bp', 'size': 63, 'version': 1, 'class': 'STD', 'date': None})) # define a single DNA record (with no interval metadata) # M14399; SV 1; linear; mRNA; STD; PRO; 63 BP. self.single = ( 'gtgaaacaaagcactattgcactggctgtcttaccgttactgtttacccctgtgacaaaagcc', {'LOCUS': {'locus_name': 'M14399', 'class': 'STD', 'division': 'PRO', 'mol_type': 'mRNA', 'shape': 'linear', 'size': 63, 'unit': 'bp', 'version': 1, 'date': None}}, None, DNA) # define a single protein record (uniprot) self.protein = ( 'MAFSAEDVLKEYDRRRRMEALLLSLYYPNDRKLLDYKEWSPPRVQVECPKAPVEWNNPPSEKG' 'LIVGHFSGIKYKGEKAQASEVDVNKMCCWVSKFKDAMRRYQGIQTCKIPGKVLSDLDAKIKAY' 'NLTVEGVEGFVRYSRVTKQHVAAFLKELRHSKQYENVNLIHYILTDKRVDIQHLEKDLVKDFK' 'ALVESAHRMRQGHMINVKYILYQLLKKHGHGPDGPDILTVKTGSKGVLYDDSFRKIYTDLGWK' 'FTPL', {'LOCUS': {'locus_name': '001R_FRG3G', 'status': 'Reviewed', 'size': 256, 'unit': 'aa'}}, None, Protein) # define a single DNA record uppercase (filepath) self.single_upper_fp = get_data_path('embl_single_record_upper') # define a single RNA record lower self.single_lower_fp = get_data_path('embl_single_record_lower') # define a single RNA record file path self.single_rna_fp = get_data_path('embl_single_record') # define a http://www.ebi.ac.uk/ena/browse/feature-level-products self.feature_level_fp = get_data_path("embl_feature_level_record") # define a interval metadata (see skbio.metadata.IntervalMetadata) imd = IntervalMetadata(63) # then add interval object to interval metadata. Add source imd.add([(0, 63)], [(False, False)], {'db_xref': '"taxon:562"', 'mol_type': '"mRNA"', 'organism': '"Escherichia coli"', 'type': 'source', 'strand': '+', '__location': '1..63'}) imd.add([(0, 63)], # the second True is beacause exact location is not known [(False, True)], {'phase': 0, 'db_xref': ['"GOA:P00634"', '"InterPro:IPR001952"', '"InterPro:IPR017849"', '"InterPro:IPR017850"', '"InterPro:IPR018299"', '"PDB:1AJA"', '"PDB:1AJB"', '"PDB:1AJC"', '"PDB:1AJD"', '"PDB:1ALH"', '"PDB:1ALI"', '"PDB:1ALJ"', '"PDB:1ALK"', '"PDB:1ANI"', '"PDB:1ANJ"', '"PDB:1B8J"', '"PDB:1ED8"', '"PDB:1ED9"', '"PDB:1ELX"', '"PDB:1ELY"', '"PDB:1ELZ"', '"PDB:1EW8"', '"PDB:1EW9"', '"PDB:1HJK"', '"PDB:1HQA"', '"PDB:1KH4"', '"PDB:1KH5"', '"PDB:1KH7"', '"PDB:1KH9"', '"PDB:1KHJ"', '"PDB:1KHK"', '"PDB:1KHL"', '"PDB:1KHN"', '"PDB:1URA"', '"PDB:1URB"', '"PDB:1Y6V"', '"PDB:1Y7A"', '"PDB:2ANH"', '"PDB:2G9Y"', '"PDB:2GA3"', '"PDB:2MLX"', '"PDB:2MLY"', '"PDB:2MLZ"', '"PDB:3BDF"', '"PDB:3BDG"', '"PDB:3BDH"', '"PDB:3CMR"', '"PDB:3DPC"', '"PDB:3DYC"', '"PDB:3TG0"', '"PDB:4KM4"', '"PDB:4YR1"', '"PDB:5C66"', '"PDB:5GAD"', '"PDB:5GAF"', '"PDB:5GAG"', '"PDB:5GAH"', '"PDB:5JTL"', '"PDB:5JTM"', '"PDB:5JTN"', '"PDB:5JTO"', '"PDB:5JTP"', '"UniProtKB/Swiss-Prot:P00634"'], '__location': '1..>63', 'strand': '+', 'note': '"alkaline phosphatase signal peptide"', 'protein_id': '"AAA23431.1"', 'transl_table': '11', 'translation': '"MKQSTIALAVLPLLFTPVTKA"', 'type': 'CDS'}) self.single_rna = ( 'gugaaacaaagcacuauugcacuggcugucuuaccguuacuguuuaccccugugacaaaagcc', {'LOCUS': {'locus_name': 'M14399', 'class': 'STD', 'division': 'PRO', 'mol_type': 'mRNA', 'shape': 'linear', 'size': 63, 'unit': 'bp', 'version': 1, 'date': '02-SEP-1999'}, 'ACCESSION': 'M14399;', # accessions (could be more than one) 'VERSION': 'M14399.1', # a genbank like version 'DATE': ["16-JUL-1988 (Rel. 16, Created)", "02-SEP-1999 (Rel. 60, Last updated, Version 3)"], 'DBSOURCE': 'MD5; c9b40131b8622946b5aafdf5473b3d43.', 'DEFINITION': "E.coli alkaline phosphatase signal mRNA, 5' end.", 'KEYWORDS': "alkaline phosphatase; signal peptide.", 'SOURCE': {"ORGANISM": "Escherichia coli", 'taxonomy': "Bacteria; Proteobacteria; " "Gammaproteobacteria; Enterobacterales; " "Enterobacteriaceae; Escherichia."}, 'REFERENCE': [{'AUTHORS': 'Gray G.L., Baldridge J.S., ' 'McKeown K.S., Heyneker H.L., ' 'Chang C.N.;', 'JOURNAL': 'Gene 39(2-3):247-254(1985).', 'REFERENCE': '1 (bases 1 to 63)', 'TITLE': '"Periplasmic production of correctly ' 'processed human growth hormone in ' 'Escherichia coli: natural and bacterial ' 'signal sequences are ' 'interchangeable";', 'PUBMED': '3912261'}], 'CROSS_REFERENCE': ['DOI; 10.1016/0378-1119(85)' '90319-1. PUBMED; 3912261.']}, imd, RNA) # define a multi record. File path self.multi_fp = get_data_path('embl_multi_records') # define interval metadata (as single metadata) imd1 = imd # define interal metadata for multi 2 imd2 = IntervalMetadata(743) # then add interval object to interval metadata. Add source imd2.add([(0, 743)], [(False, False)], {'organism': '"Ruditapes philippinarum"', 'type': 'source', '__location': '1..743', 'strand': '+', 'mol_type': '"mRNA"', 'db_xref': '"taxon:129788"'}) imd2.add([(57, 444)], [(False, False)], {'translation': '"MPGGKAGKDSGKAKAKAVSRSARAGLQFPVGRIHRHLKNRT' 'TSHG RVGATAAVYSAAILEYLTAEVLELAGNASKDLKVKRI' 'TPRHLQLAIRGDEELDSLIKAT IAGGGVIPHIHKSLIGKKG' 'GQQAK"', 'type': 'CDS', '__location': '58..444', 'protein_id': '"APY18893.1"', 'strand': '+', 'phase': 0, 'product': '"histone"'}) # multi object self.multi = ( ('GTGAAACAAAGCACTATTGCACTGGCTGTCTTACCGTTACTGTTTACCCCTGTGACAAAAGCC', {'LOCUS': {'locus_name': 'M14399', 'class': 'STD', 'division': 'PRO', 'mol_type': 'mRNA', 'shape': 'linear', 'size': 63, 'unit': 'bp', 'version': 1, 'date': '02-SEP-1999'}, 'ACCESSION': 'M14399;', # accessions (could be more than one) 'VERSION': 'M14399.1', # a genbank like version 'DATE': ["16-JUL-1988 (Rel. 16, Created)", "02-SEP-1999 (Rel. 60, Last updated, Version 3)"], 'DBSOURCE': 'MD5; c9b40131b8622946b5aafdf5473b3d43.', 'DEFINITION': "E.coli alkaline phosphatase signal mRNA, 5' end.", 'KEYWORDS': "alkaline phosphatase; signal peptide.", 'SOURCE': {"ORGANISM": "Escherichia coli", 'taxonomy': "Bacteria; Proteobacteria; " "Gammaproteobacteria; Enterobacterales; " "Enterobacteriaceae; Escherichia."}, 'REFERENCE': [{'AUTHORS': 'Gray G.L., Baldridge J.S., ' 'McKeown K.S., Heyneker H.L., ' 'Chang C.N.;', 'JOURNAL': 'Gene 39(2-3):247-254(1985).', 'REFERENCE': '1 (bases 1 to 63)', 'TITLE': '"Periplasmic production of correctly ' 'processed human growth hormone in ' 'Escherichia coli: natural and ' 'bacterial signal sequences are ' 'interchangeable";', 'PUBMED': '3912261'}], 'CROSS_REFERENCE': ['DOI; 10.1016/0378-1119(85)' '90319-1. PUBMED; 3912261.']}, imd1, DNA), ('TGTGCACAGTCTACGCGTCATCTTGAAAGAAAGAACTACACTACTCCAAAAATAATCATGCC' 'TGGTGGAAAAGCTGGTAAAGATTCCGGAAAGGCCAAGGCTAAGGCAGTGTCAAGGTCCGCAA' 'GAGCTGGCTTACAGTTTCCAGTCGGACGTATTCACAGGCATTTGAAGAACAGAACCACTAGC' 'CACGGTCGTGTTGGAGCTACAGCAGCCGTTTACAGTGCAGCAATCCTTGAATACCTGACCGC' 'CGAAGTGCTTGAGTTGGCTGGAAACGCAAGTAAAGATCTCAAAGTAAAGAGAATCACCCCAC' 'GTCACTTGCAGTTGGCAATCAGAGGAGATGAAGAGTTGGATTCCCTAATTAAAGCCACAATC' 'GCTGGTGGTGGTGTTATTCCACATATCCACAAGTCACTTATTGGCAAGAAGGGAGGTCAGCA' 'AGCCAAATAAATTGGACATACTCATTCATCAGGGAACAATGTGTAGTGAATGTGTTAAAAAG' 'AACAATCTCATTGTGTAGCTCTTTAGTTTTATATGAATGTGTTAACATGGTCATTCACATCG' 'TATGACTCATAGAATCATCTGTGTATCATTTCATCCTCTCATTTTATAGCTCCTCATTTTCC' 'TTAGACTCATTAAAATTTTTATCTCGGAAAAATGTTTTTTCTACAATTTTAGCATTCATTTA' 'TCTTCATCTTGCTTTTATGTTTAATAAAACGAACTTATAATACCAAAAAAAAAAAAAAAAA', {'ACCESSION': 'KX454487;', 'VERSION': 'KX454487.1', 'COMMENT': '##Assembly-Data-START##\nSequencing Technology ' ':: Sanger dideoxy sequencing\n##Assembly-Data-END##', 'DATE': ['02-FEB-2017 (Rel. 131, Created)', '02-FEB-2017 (Rel. 131, Last updated, Version 1)'], 'DBSOURCE': 'MD5; cbc730cf7a8d694b50fb7dd6b993ae0d.', 'DEFINITION': 'Ruditapes philippinarum histone mRNA, ' 'complete cds.', 'KEYWORDS': '.', 'LOCUS': {'locus_name': 'KX454487', 'class': 'STD', 'division': 'INV', 'mol_type': 'mRNA', 'shape': 'linear', 'size': 743, 'unit': 'bp', 'version': 1, 'date': '02-FEB-2017'}, 'REFERENCE': [ {'AUTHORS': 'Yang D., Zhao J., Wang Q.;', 'JOURNAL': 'Submitted (27-JUN-2016) to the INSDC. Key ' 'Laboratory of Coastal Zone Environment Processes ' 'and Ecological Remediation, Yantai Institute ' 'of Coastal Zone Research (YIC), Chinese Academy ' 'of Sciences (CAS), 17 Chunhui Road, Laishan ' 'District, Yantai, Shandong 264003, China', 'REFERENCE': '1 (bases 1 to 743)', 'TITLE': ';'}], 'CROSS_REFERENCE': [None], 'SOURCE': { 'ORGANISM': 'Ruditapes philippinarum', 'taxonomy': 'Eukaryota; Metazoa; Lophotrochozoa; Mollusca; ' 'Bivalvia; Heteroconchia; Euheterodonta; ' 'Veneroida; Veneroidea; Veneridae; Ruditapes.'}}, imd2, DNA)) # define the feature level product obj self.feature_level = ( 'AAUUGAAGAGUUUGAUCAUGGCUCAGAUUGAACGCUGGCGGCAGGCCUAACACAUGCAAGUC' 'GAGCGGCAGCACAGAGGAACUUGUUCCUUGGGUGGCGAGCGGCGGACGGGUGAGUAAUGCCU' 'AGGAAAUUGCCCUGAUGUGGGGGAUAACCAUUGGAAACGAUGGCUAAUACCGCAUGAUGCCU' 'ACGGGCCAAAGAGGGGGACCUUCUGGCCUCUCGCGUCAGGAUAUGCCUAGGUGGGAUUAGCU' 'AGUUGGUGAGGUAAUGGCUCACCAAGGCGACGAUCCCUAGCUGGUCUGAGAGGAUGAUCAGC' 'CACACUGGAACUGAGACACGGUCCAGACUCCUACGGGAGGCAGCAGUGGGGAAUAUUGCACA' 'AUGGGCGCAAGCCUGAUGCAGCCAUGCCGCGUGUAUGAAGAAGGCCUUCGGGUUGUAAAGUA' 'CUUUCAGUCGUGAGGAAGGUGGUGUUGUUAAUAGCAGCAUCAUUUGACGUUAGCGACAGAAG' 'AAGCACCGGCUAACUCCGUGCCAGCAGCCGCGGUAAUACGGAGGGUGCGAGCGUUAAUCGGA' 'AUUACUGGGCGUAAAGCGCAUGCAGGUGGUGGAUUAAGUCAGAUGUGAAAGCCCGGGGCUCA' 'ACCUCGGAACCGCAUUUGAAACUGGUUCACUAGAGUACUGUAGAGGGGGGUAGAAUUUCAGG' 'UGUAGCGGUGAAAUGCGUAGAGAUCUGAAGGAAUACCGGUGGCGAAGGCGGCCCCCUGGACA' 'GAUACUGACACUCAGAUGCGAAAGCGUGGGGAGCAAACAGGAUUAGAUACCCUGGUAGUCCA' 'CGCCGUAAACGAUGUCUACUUGGAGGUUGUGGCCUUGAGCCGUGGCUUUCGGAGCUAACGCG' 'UUAAGUAGACCGCCUGGGGAGUACGGUCGCAAGAUUAAAACUCAAAUGAAUUGACGGGGGCC' 'CGCACAAGCGGUGGAGCAUGUGGUUUAAUUCGAUGCAACGCGAAGAACCUUACCUACUCUUG' 'ACAUCCAGAGAAGCCAGCGGAGACGCAGGUGUGCCUUCGGGAGCUCUGAGACAGGUGCUGCA' 'UGGCUGUCGUCAGCUCGUGUUGUGAAAUGUUGGGUUAAGUCCCGCAACGAGCGCAACCCUUA' 'UCCUUGUUUGCCAGCGAGUCAUGUCGGGAACUCCAGGGAGACUGCCGGUGAUAAACCGGAGG' 'AAGGUGGGGACGACGUCAAGUCAUCAUGGCCCUUACGAGUAGGGCUACACACGUGCUACAAU' 'GGCGCAUACAGAGGGCAGCAAGCUAGCGAUAGUGAGCGAAUCCCAAAAAGUGCGUCGUAGUC' 'CGGAUUGGAGUCUGCAACUCGACUCCAUGAAGUCGGAAUCGCUAGUAAUCGUAGAUCAGAAU' 'GCUACGGUGAAUACGUUCCCGGGCCUUGUACACACCGCCCGUCACACCAUGGGAGUGGGCUG' 'CAAAAGAAGUGGGUAGUUUAACCUUUCGGGGAGGACGCUCACCACUUUGUGGUUCAUGACUG' 'GGGUGAAGUCGUAACAAGGUAGCGCUAGGGGAACCUGGCGCUGGAUCACCUCCUUA', {'DATE': ['02-JUN-2014 (Rel. 121, Created)', '04-FEB-2016 (Rel. 127, Last updated, Version 5)'], 'DBSOURCE': 'SILVA-LSU; LK021130. SILVA-SSU; LK021130. MD5; ' 'afd116bf2c1a13acbf40d63d82f0218c. BioSample; ' 'SAMEA3865288.', 'DEFINITION': 'Vibrio anguillarum 16S rRNA', 'KEYWORDS': '.', 'LOCUS': {'locus_name': 'LK021130.1:74067..75610:rRNA', 'class': 'STD', 'division': 'PRO', 'mol_type': 'genomic DNA', 'shape': 'linear', 'size': 1544, 'unit': 'bp', 'version': 1, 'date': '04-FEB-2016'}, 'PARENT_ACCESSION': 'LK021130.1', 'VERSION': 'LK021130.1', 'PROJECT_IDENTIFIER': 'Project:PRJEB5701;', 'REFERENCE': [ {'AUTHORS': 'Holm K.;', 'JOURNAL': 'Submitted (26-MAR-2014) to the INSDC. ' 'Norstruct, Dept of Chemistry, University of ' 'Tromso, Science Park 3, NO-9037 Tromso, NORWAY.', 'TITLE': ';', 'REFERENCE': '1'}, {'AUTHORS': 'Holm K.O., Nilsson K., Hjerde E., Willassen ' 'N.P., Milton D.L.;', 'JOURNAL': 'Stand Genomic Sci. 10:60-60(2015).', 'TITLE': '"Complete genome sequence of Vibrio anguillarum ' 'strain NB10, a virulent isolate from the Gulf ' 'of Bothnia";', 'REFERENCE': '2', 'PUBMED': '26380645'}], 'CROSS_REFERENCE': [ None, 'DOI; 10.1186/s40793-015-0060-7. PUBMED; 26380645.'], 'SOURCE': { 'ORGANISM': 'Vibrio anguillarum', 'taxonomy': 'Bacteria; Proteobacteria; Gammaproteobacteria; ' 'Vibrionales; Vibrionaceae; Vibrio.'}}, None, RNA) # get the feature level file without FT self.feature_level_fp = get_data_path( "embl_feature_level_record_no_FT") # get a genbank file in order to to file conversion self.genbank_fp = get_data_path('genbank_single_record') # a embl constructed sequence file path self.embl_constructed_fp = get_data_path("embl_constructed") # a simple embl version to perform embl->gb->embl conversion self.single_rna_simple_fp = get_data_path( "embl_single_record_simple") class ReaderTests(EMBLIOTests): """Implements test for reading EMBL data""" def test_parse_id(self): """Parse ID record (first line of embl format)""" for serialized, parsed in self.id: self.assertEqual(_parse_id(serialized), parsed) def test_parse_id_invalid(self): lines = [ # uniprot line (should this module handle it?) ['ID 001R_FRG3G Reviewed; 256 AA.'], # missing unit ['ID M14399; SV 1; linear; mRNA; STD; PRO; 63'], # missing division ['ID M14399; SV 1; linear; mRNA; STD; 63 BP.']] for line in lines: with self.assertRaisesRegex(EMBLFormatError, r'Could not parse the ID line:.*'): _parse_id(line) # current status of protein support is described in issue-1499 # https://github.com/scikit-bio/scikit-bio/issues/1499 def test_no_protein_support(self): """Testing no protein support for embl""" # TODO: add protein support # a fake protein line. handle = io.StringIO('ID M14399; SV 1; linear; mRNA; STD; ' 'PRO; 63 AA.\n//\n') with self.assertRaisesRegex(EMBLFormatError, r"There's no protein support for EMBL " "record"): # read a protein record Protein.read(handle) # return to 0 handle.seek(0) with self.assertRaisesRegex(EMBLFormatError, r"There's no protein support for EMBL " "record"): # read a generic record skbio.io.read(handle, format='embl') def test_parse_reference(self): lines = ''' RP 1-63 RX DOI; 10.1016/0378-1119(85)90319-1. RX PUBMED; 3912261. RA Gray G.L., Baldridge J.S., McKeown K.S., Heyneker H.L., Chang C.N.; RT "Periplasmic production of correctly processed human growth hormone in RT Escherichia coli: natural and bacterial signal sequences are RT interchangeable"; RL Gene 39(2-3):247-254(1985).'''.split('\n') # DNA, Sequence and RNA data contain newlines lines = [line+"\n" for line in lines if line != ''] exp = {'AUTHORS': 'Gray G.L., Baldridge J.S., ' 'McKeown K.S., Heyneker H.L., Chang C.N.;', 'JOURNAL': 'Gene 39(2-3):247-254(1985).', 'CROSS_REFERENCE': 'DOI; 10.1016/0378-1119(85)90319-1. ' 'PUBMED; 3912261.', 'REFERENCE': '(bases 1 to 63)', 'TITLE': '"Periplasmic production of correctly processed ' 'human growth hormone in Escherichia coli: ' 'natural and bacterial signal sequences are ' 'interchangeable";', 'PUBMED': '3912261' } # read reference obs = _parse_reference(lines) # See all differences self.maxDiff = None self.assertEqual(obs, exp) def test_parse_assembly(self): lines = """ AH LOCAL_SPAN PRIMARY_IDENTIFIER PRIMARY_SPAN COMP AS 1-426 AC004528.1 18665-19090 AS 427-526 AC001234.2 1-100 c AS 527-1000 TI55475028 not_available """.split('\n') # DNA, Sequence and RNA data contain newlines lines = [line+"\n" for line in lines if line != ''] exp = [ { 'local_span': '1-426', 'primary_identifier': 'AC004528.1', 'primary_span': '18665-19090', 'comp': '' }, { 'local_span': '427-526', 'primary_identifier': 'AC001234.2', 'primary_span': '1-100', 'comp': 'c' }, { 'local_span': '527-1000', 'primary_identifier': 'TI55475028', 'primary_span': 'not_available', 'comp': '' } ] # read reference obs = _parse_assembly(lines) # See all differences self.maxDiff = None self.assertEqual(obs, exp) def test_parse_bad_assembly(self): """test for a wrong assembly line""" lines = """ AH LOCAL_SPAN PRIMARY_IDENTIFIER PRIMARY_SPAN COMP AS 1-426 AC004528.1 """.split("\n") # DNA, Sequence and RNA data contain newlines lines = [line+"\n" for line in lines if line != ''] with self.assertRaisesRegex(EMBLFormatError, r"Can't parse assembly line"): # read a malformed assembly record _parse_assembly(lines) def test_embl_to_generator_single(self): # test single record and uppercase sequence for c in [Sequence, DNA]: obs = next(_embl_to_generator( self.single_upper_fp, constructor=c)) exp = c(self.single[0], metadata=self.single[1], positional_metadata=self.single[2], lowercase=True) self.assertEqual(exp, obs) def test_get_embl_section(self): """Verify to have a section for each embl ID""" with open(self.single_rna_fp) as fh: for line in fh: if line.startswith("//"): continue # test that this function doesn't raise exceptions try: _get_embl_section(line) except KeyError as err: raise EMBLFormatError("Key {0} isn't defined in embl." "KEYS_2_SECTIONS".format(err)) def test_embl_to_generator(self): for i, obs in enumerate(_embl_to_generator(self.multi_fp)): seq, md, imd, constructor = self.multi[i] exp = constructor(seq, metadata=md, lowercase=True, interval_metadata=imd) self.assertEqual(exp, obs) def test_embl_to_sequence(self): for i, exp in enumerate(self.multi): obs = _embl_to_sequence(self.multi_fp, seq_num=i+1) exp = Sequence(exp[0], metadata=exp[1], lowercase=True, interval_metadata=exp[2]) self.assertEqual(exp, obs) def test_embl_to_rna(self): seq, md, imd, constructor = self.single_rna obs = _embl_to_rna(self.single_rna_fp) exp = constructor(seq, metadata=md, lowercase=True, interval_metadata=imd) self.assertEqual(exp, obs) def test_embl_to_dna(self): i = 1 exp = self.multi[i] obs = _embl_to_dna(self.multi_fp, seq_num=i+1) exp = DNA(exp[0], metadata=exp[1], lowercase=True, interval_metadata=exp[2]) self.assertEqual(exp, obs) # current status of protein support is described in issue-1499 # https://github.com/scikit-bio/scikit-bio/issues/1499 def test_embl_to_protein(self): # TODO: add protein support i = 0 # there is no support for protein at the moment # when protein support will be added, this code must work # exp = self.multi[i] # obs = _embl_to_protein(self.multi_fp, seq_num=i+1) # exp = Protein(exp[0], metadata=exp[1], # lowercase=True, interval_metadata=exp[2]) # self.assertEqual(exp, obs) with self.assertRaisesRegex(EMBLFormatError, r"There's no protein support for EMBL " "record"): # read a generic record _embl_to_protein(self.multi_fp, seq_num=i+1) # deal with feature-level-products: ignore feature table def test_feature_level_products(self): seq, md, imd, constructor = self.feature_level obs = _embl_to_rna(self.feature_level_fp) exp = constructor(seq, metadata=md, lowercase=True, interval_metadata=imd) self.assertEqual(obs, exp) # deal with constructed sequences: ignore interval metadata def test_constructed_sequences(self): with self.assertRaisesRegex( EMBLFormatError, r"There's no support for embl CON record"): _embl_to_dna(self.embl_constructed_fp) class WriterTests(EMBLIOTests): def test_serialize_id(self): for serialized, parsed in self.id: self.assertEqual( _serialize_id('ID', parsed), serialized[0] + '\n') def test_serialize_dbsource(self): """Serialize a complex dbsource entry""" # test with a complex uniprot dbsource exp = """DR EMBL; AY548484; AAT09660.1; -; Genomic_DNA. DR RefSeq; YP_031579.1; NC_005946.1. DR ProteinModelPortal; Q6GZX4; -. DR SwissPalm; Q6GZX4; -. DR GeneID; 2947773; -. DR KEGG; vg:2947773; -. DR Proteomes; UP000008770; Genome. """ # split by lines lines = [line+"\n" for line in exp.split("\n") if line != ''] # parse objects parsed = _embl_parse_section_default(lines) # now serialize them obs = _serialize_dbsource("DR", parsed) # test objects self.assertEqual(obs, exp) def test_generator_to_embl(self): seq, md, imd, constructor = self.single obj = constructor(seq, md, interval_metadata=imd, lowercase=True) with io.StringIO() as fh: _generator_to_embl([obj], fh) obs = fh.getvalue() with open(self.single_lower_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_sequence_to_embl(self): with io.StringIO() as fh: for i, (seq, md, imd, constructor) in enumerate(self.multi): obj = Sequence(seq, md, interval_metadata=imd) _sequence_to_embl(obj, fh) obs = fh.getvalue() with open(self.multi_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_dna_to_embl(self): with io.StringIO() as fh: for i, (seq, md, imd, constructor) in enumerate(self.multi): obj = constructor( seq, md, interval_metadata=imd, lowercase=True) _dna_to_embl(obj, fh) # read all records written obs = fh.getvalue() with open(self.multi_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) # TODO: add support for protein # current status of protein support is described in issue-1499 # https://github.com/scikit-bio/scikit-bio/issues/1499 def test_protein_to_embl(self): seq, md, imd, constructor = self.protein obj = constructor(seq, md, interval_metadata=imd) with io.StringIO() as fh: self.assertRaisesRegex(EMBLFormatError, r"There's no protein support for EMBL " "record", _protein_to_embl, [obj], fh) def test_rna_to_embl(self): with io.StringIO() as fh: seq, md, imd, constructor = self.single_rna obj = constructor(seq, md, interval_metadata=imd, lowercase=True) _rna_to_embl(obj, fh) obs = fh.getvalue() with open(self.single_rna_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_rna_to_embl_flp(self): """Test writing feature level products""" with io.StringIO() as fh: seq, md, imd, constructor = self.feature_level obj = constructor(seq, md, interval_metadata=imd, lowercase=True) _rna_to_embl(obj, fh) obs = fh.getvalue() with open(self.feature_level_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) class RoundtripTests(EMBLIOTests): def test_roundtrip_generator(self): with io.StringIO() as fh: _generator_to_embl(_embl_to_generator(self.multi_fp), fh) obs = fh.getvalue() with open(self.multi_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_roundtrip_rna(self): with io.StringIO() as fh: _rna_to_embl(_embl_to_rna(self.single_rna_fp), fh) obs = fh.getvalue() with open(self.single_rna_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_roundtrip_dna(self): with io.StringIO() as fh: _dna_to_embl(_embl_to_dna(self.single_rna_fp), fh) obs = fh.getvalue() with open(self.single_rna_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) # TODO: test_roundtrip_protein # current status of protein support is described in issue-1499 # https://github.com/scikit-bio/scikit-bio/issues/1499 def test_roundtrip_sequence(self): with io.StringIO() as fh: _sequence_to_embl(_embl_to_sequence(self.single_rna_fp), fh) obs = fh.getvalue() with open(self.single_rna_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) class Convertertest(EMBLIOTests): def test_gb_to_embl(self): genbank = DNA.read(self.genbank_fp, format="genbank") with io.StringIO() as fh: DNA.write(genbank, format="embl", file=fh) # EMBL can't deal with genbank version (ie M14399.1 GI:145229) # read embl data and write to gb fh.seek(0) embl = DNA.read(fh, format="embl") with io.StringIO() as fh: DNA.write(embl, format="genbank", file=fh) # read gb data obs = fh.getvalue() with open(self.genbank_fp) as fh: exp = fh.read() self.assertEqual(exp, obs) def test_embl_to_gb(self): # EMBL records have more features than genbank, (ex more than one date, # embl class, DOI cross references) so I can't convert an embl to gb # and then to embl keeping all those data. But I can start from # genbank record # do embl file -> embl object -> gb file -> gb object -> # embl file. Ensure that first and last files are identical embl = DNA.read(self.single_rna_simple_fp, format="embl") # "write" genbank record in a embl file with io.StringIO() as fh: DNA.write(embl, format="genbank", file=fh) # read genbank file fh.seek(0) genbank = DNA.read(fh, format="genbank") # "write" genbank record in a embl file with io.StringIO() as fh: DNA.write(genbank, format="embl", file=fh) # read file object obs = fh.getvalue() # test objects with open(self.single_rna_simple_fp) as fh: exp = fh.read() self.assertEqual(exp, obs) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_emptyfile.py000066400000000000000000000021111520735541300261250ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import io from skbio.io.format.emptyfile import _empty_file_sniffer class TestEmptyFile(unittest.TestCase): def test_empty(self): res, kw = _empty_file_sniffer(io.StringIO()) self.assertTrue(res) self.assertEqual({}, kw) res, kw = _empty_file_sniffer(io.StringIO(" \n \t ")) self.assertTrue(res) self.assertEqual({}, kw) def test_not_empty(self): res, kw = _empty_file_sniffer(io.StringIO("a")) self.assertFalse(res) self.assertEqual({}, kw) res, kw = _empty_file_sniffer(io.StringIO(" \n \ta")) self.assertFalse(res) self.assertEqual({}, kw) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_fasta.py000066400000000000000000001365431520735541300252460ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import copy import io import string from unittest import TestCase, main from functools import partial import numpy as np from skbio import Sequence, DNA, RNA, Protein, TabularMSA from skbio.io import FASTAFormatError, QUALFormatError from skbio.io.format.fasta import ( _fasta_sniffer, _fasta_to_generator, _fasta_to_sequence, _fasta_to_dna, _fasta_to_rna, _fasta_to_protein, _fasta_to_tabular_msa, _generator_to_fasta, _sequence_to_fasta, _dna_to_fasta, _rna_to_fasta, _protein_to_fasta, _tabular_msa_to_fasta, _parse_sequence_data) from skbio.sequence import GrammaredSequence from skbio.util import get_data_path from skbio.util import classproperty from skbio.util._decorator import overrides class CustomSequence(GrammaredSequence): @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set('-.') @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return '-' @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set(string.ascii_letters) @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return {} class SnifferTests(TestCase): def setUp(self): self.positive_fps = list(map(get_data_path, [ 'fasta_5_blanks_start_of_file', 'fasta_5_ws_lines_start_of_file', 'fasta_blanks_end_of_file', 'fasta_ws_lines_end_of_file', 'fasta_blank_lines_between_records', 'fasta_3_seqs_defaults', 'fasta_max_width_1', 'fasta_single_bio_seq_non_defaults', 'fasta_single_prot_seq_non_defaults', 'fasta_3_seqs_non_defaults', 'fasta_max_width_5', 'fasta_single_dna_seq_defaults', 'fasta_single_rna_seq_defaults', 'fasta_description_newline_replacement_empty_str', 'fasta_multi_seq', 'fasta_multi_seq_spaces', 'fasta_single_dna_seq_non_defaults', 'fasta_single_rna_seq_non_defaults', 'fasta_description_newline_replacement_multi_char', 'fasta_prot_seqs_odd_labels', 'fasta_single_seq', 'fasta_id_whitespace_replacement_empty_str', 'fasta_tabular_msa_different_type', 'fasta_id_whitespace_replacement_multi_char', 'fasta_single_bio_seq_defaults', 'fasta_single_prot_seq_defaults', 'fasta_10_seqs', 'fasta_invalid_after_10_seqs', 'fasta_mixed_qual_scores', 'qual_3_seqs_non_defaults', ])) self.negative_fps = list(map(get_data_path, [ 'empty', 'whitespace_only', 'fasta_invalid_missing_header', 'fasta_invalid_blank_line_after_header', 'fasta_invalid_blank_sequence', 'fasta_invalid_blank_line_within_sequence', 'fasta_invalid_whitespace_only_line_within_sequence', 'fasta_invalid_whitespace_line_after_header', 'fasta_invalid_missing_seq_data_first', 'fasta_invalid_missing_seq_data_middle', 'fasta_invalid_missing_seq_data_last', 'fasta_invalid_legacy_format', 'fasta_invalid_whitespace_only_sequence', 'fasta_id_whitespace_replacement_none', 'fasta_description_newline_replacement_none', 'fasta_6_blanks_start_of_file', 'fasta_6_ws_lines_start_of_file', 'qual_2_seqs_defaults', 'qual_3_seqs_defaults', 'qual_3_seqs_defaults_desc_mismatch', 'qual_3_seqs_defaults_extra', 'qual_3_seqs_defaults_id_mismatch', 'qual_3_seqs_defaults_length_mismatch', 'qual_description_newline_replacement_empty_str', 'qual_description_newline_replacement_multi_char', 'qual_description_newline_replacement_none', 'qual_id_whitespace_replacement_empty_str', 'qual_id_whitespace_replacement_multi_char', 'qual_id_whitespace_replacement_none', 'qual_invalid_blank_line_within_seq', 'qual_invalid_legacy_format', 'qual_invalid_missing_header', 'qual_invalid_missing_qual_scores_first', 'qual_invalid_missing_qual_scores_last', 'qual_invalid_missing_qual_scores_middle', 'qual_invalid_whitespace_line_in_seq', 'qual_invalid_blank_line_after_header', 'qual_invalid_blank_sequence', 'qual_invalid_whitespace_only_sequence', 'qual_invalid_ws_line_after_header', 'qual_invalid_qual_scores_float', 'qual_invalid_qual_scores_string', 'qual_max_width_1', 'qual_max_width_5', 'qual_multi_seq', 'qual_multi_seq_roundtrip', 'qual_prot_seqs_odd_labels', 'qual_tabular_msa_different_type', 'qual_single_bio_seq_non_defaults', 'qual_single_dna_seq_non_defaults', 'qual_single_prot_seq_non_defaults', 'qual_single_rna_seq_non_defaults', 'qual_single_seq', 'qual_ws_lines_between_records', 'qual_blank_lines_between_records', 'qual_5_blanks_start_of_file', 'qual_5_ws_lines_start_of_file', 'qual_6_blanks_start_of_file', 'qual_6_ws_lines_start_of_file', 'qual_blanks_end_of_file', 'qual_ws_lines_end_of_file' ])) def test_positives(self): for fp in self.positive_fps: self.assertEqual(_fasta_sniffer(fp), (True, {})) def test_negatives(self): for fp in self.negative_fps: self.assertEqual(_fasta_sniffer(fp), (False, {})) class ReaderTests(TestCase): def setUp(self): # each structure stores the sequence generator results (expanded into a # list) that we expect to obtain from reading, matched with kwargs to # pass to the reader, and fasta and qual filepaths that should # deserialize into the expected generator results # empty file shouldn't yield sequences self.empty = ([], {}, list(map(get_data_path, ['empty', 'whitespace_only'])), list(map(get_data_path, ['empty', 'whitespace_only']))) # single sequence self.single = ( [Sequence( 'ACGT-acgt.', metadata={'id': 'seq1', 'description': 'desc1'}, positional_metadata={'quality': np.asarray([10, 20, 30, 10, 0, 0, 0, 255, 1, 255], dtype=np.uint8)})], {}, list(map(get_data_path, ['fasta_single_seq', 'fasta_max_width_1'])), list(map(get_data_path, ['qual_single_seq', 'qual_max_width_1'])) ) # multiple sequences self.multi = ( [Sequence( 'ACGT-acgt.', metadata={'id': 'seq1', 'description': 'desc1'}, positional_metadata={'quality': np.asarray([10, 20, 30, 10, 0, 0, 0, 255, 1, 255], dtype=np.uint8)}), Sequence('A', metadata={'id': '_____seq__2_', 'description': ''}, positional_metadata={'quality': np.asarray([42], dtype=np.uint8)}), Sequence( 'AACGGuA', metadata={'id': '', 'description': 'desc3'}, positional_metadata={'quality': np.asarray([0, 0, 0, 0, 0, 0, 0], dtype=np.uint8)}), Sequence( 'ACGTTGCAccGG', metadata={'id': '', 'description': ''}, positional_metadata={'quality': np.asarray([55, 10, 0, 99, 1, 1, 8, 77, 40, 10, 10, 0], dtype=np.uint8)}), Sequence('ACGUU', metadata={'id': '', 'description': ''}, positional_metadata={'quality': np.asarray([10, 9, 8, 7, 6], dtype=np.uint8)}), Sequence( 'pQqqqPPQQQ', metadata={'id': 'proteinseq', 'description': 'detailed description \t\twith new lines'}, positional_metadata={'quality': np.asarray([42, 42, 255, 255, 42, 42, 42, 42, 42, 43], dtype=np.uint8)})], {}, list(map(get_data_path, ['fasta_multi_seq', 'fasta_max_width_5', 'fasta_multi_seq_spaces', 'fasta_blank_lines_between_records', 'fasta_ws_lines_between_records', 'fasta_5_blanks_start_of_file', 'fasta_5_ws_lines_start_of_file', 'fasta_6_blanks_start_of_file', 'fasta_6_ws_lines_start_of_file', 'fasta_blanks_end_of_file', 'fasta_ws_lines_end_of_file'])), list(map(get_data_path, ['qual_multi_seq', 'qual_max_width_5', 'qual_blank_lines_between_records', 'qual_ws_lines_between_records', 'qual_5_blanks_start_of_file', 'qual_5_ws_lines_start_of_file', 'qual_6_blanks_start_of_file', 'qual_6_ws_lines_start_of_file', 'qual_blanks_end_of_file', 'qual_ws_lines_end_of_file'])) ) # test constructor parameter, as well as odd labels (label only # containing whitespace, label description preceded by multiple spaces, # no id) and leading/trailing whitespace on sequence data. for qual # files, in addition to the odd labels, test leading/trailing # whitespace on qual scores, as well as strange number formatting. # also test that fasta and qual headers do not need to match # exactly, only that they need to match exactly after parsing (e.g., # after stripping leading/trailing whitespace from descriptions) self.odd_labels_different_type = ( [Protein('DEFQfp', metadata={'id': '', 'description': ''}, positional_metadata={'quality': np.asarray([0, 0, 1, 5, 44, 0], dtype=np.uint8)}, validate=False), Protein( 'SKBI', metadata={'id': '', 'description': 'skbio'}, positional_metadata={'quality': np.asarray([1, 2, 33, 123], dtype=np.uint8)})], {'constructor': partial(Protein, validate=False)}, list(map(get_data_path, ['fasta_prot_seqs_odd_labels'])), list(map(get_data_path, ['qual_prot_seqs_odd_labels'])) ) # sequences that can be loaded into a TabularMSA self.tabular_msa_different_type = ( [RNA('aUG', metadata={'id': '', 'description': ''}, positional_metadata={'quality': np.asarray([20, 20, 21], dtype=np.uint8)}, lowercase='introns'), RNA('AuC', metadata={'id': 'rnaseq-1', 'description': 'rnaseq desc 1'}, positional_metadata={'quality': np.asarray([10, 9, 10], dtype=np.uint8)}, lowercase='introns'), RNA('AUg', metadata={'id': 'rnaseq-2', 'description': 'rnaseq desc 2'}, positional_metadata={'quality': np.asarray([9, 99, 99], dtype=np.uint8)}, lowercase='introns')], {'constructor': partial(RNA, lowercase='introns')}, list(map(get_data_path, ['fasta_tabular_msa_different_type'])), list(map(get_data_path, ['qual_tabular_msa_different_type'])) ) self.lowercase_seqs = ( [DNA('TAcg', metadata={'id': 'f-o-o', 'description': 'b_a_r'}, positional_metadata={'quality': np.asarray([0, 1, 2, 3], dtype=np.uint8)}, lowercase='introns')], {'constructor': DNA, 'lowercase': 'introns'}, list(map(get_data_path, ['fasta_single_dna_seq_non_defaults'])), list(map(get_data_path, ['qual_single_dna_seq_non_defaults'])) ) # store fasta filepath, kwargs, error type, and expected error message # for invalid input. # # note: there is some duplication in testing that fasta and qual # parsers raise expected errors. even though the parsers share the same # underlying logic, these tests are here as a safeguard in case the # code is refactored in the future such that fasta and qual have # different implementations (e.g., if qual is written in cython while # fasta remains in python) self.invalid_fps = list(map(lambda e: (get_data_path(e[0]), e[1], e[2], e[3]), [ # fasta and qual missing header ('fasta_invalid_missing_header', {}, FASTAFormatError, r'non-header.*1st'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_missing_header')}, QUALFormatError, r'non-header.*1st'), # fasta and qual with blank line within sequence ('fasta_invalid_blank_line_within_sequence', {}, FASTAFormatError, r'whitespace-only'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_blank_line_within_seq')}, QUALFormatError, r'whitespace-only'), # fasta and qual with blank after header ('fasta_invalid_blank_sequence', {}, FASTAFormatError, r'without sequence data'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_blank_sequence')}, QUALFormatError, r'without quality scores'), # fasta and qual with whitespace only sequence ('fasta_invalid_whitespace_only_sequence', {}, FASTAFormatError, r'without sequence data'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_whitespace_only_sequence')}, QUALFormatError, r'without quality scores'), # fasta and qual with blank line within sequence ('fasta_invalid_blank_line_after_header', {}, FASTAFormatError, r'whitespace-only'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_blank_line_after_header')}, QUALFormatError, r'whitespace-only'), # fasta and qual with whitespace-only line within sequence ('fasta_invalid_whitespace_only_line_within_sequence', {}, FASTAFormatError, r'whitespace-only'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_whitespace_line_in_seq')}, QUALFormatError, r'whitespace-only'), # fasta and qual with whitespace-only line after header ('fasta_invalid_whitespace_line_after_header', {}, FASTAFormatError, r'whitespace-only'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_ws_line_after_header')}, QUALFormatError, r'whitespace-only'), # fasta and qual missing record data (first record) ('fasta_invalid_missing_seq_data_first', {}, FASTAFormatError, r'without sequence data'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_missing_qual_scores_first')}, QUALFormatError, r'without quality scores'), # fasta and qual missing record data (middle record) ('fasta_invalid_missing_seq_data_middle', {}, FASTAFormatError, r'without sequence data'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_missing_qual_scores_middle')}, QUALFormatError, r'without quality scores'), # fasta and qual missing record data (last record) ('fasta_invalid_missing_seq_data_last', {}, FASTAFormatError, r'without sequence data'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_missing_qual_scores_last')}, QUALFormatError, r'without quality scores'), # fasta and qual in legacy format (;) ('fasta_invalid_legacy_format', {}, FASTAFormatError, r'non-header.*1st'), ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_legacy_format')}, QUALFormatError, r'non-header.*1st'), # qual file with an extra record ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_3_seqs_defaults_extra')}, FASTAFormatError, r'QUAL file has more'), # fasta file with an extra record ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_2_seqs_defaults')}, FASTAFormatError, r'FASTA file has more'), # id mismatch between fasta and qual ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_3_seqs_defaults_id_mismatch')}, FASTAFormatError, r'IDs do not match.*\'s_e_q_2\' != \'s_e_q_42\''), # description mismatch between fasta and qual ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_3_seqs_defaults_desc_mismatch')}, FASTAFormatError, r'Descriptions do not match.*\'desc 2\' != \'desc 42\''), # sequence and quality score length mismatch between fasta and qual ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_3_seqs_defaults_length_mismatch')}, ValueError, r'Number of positional metadata values \(3\) must match the ' r'positional metadata axis length \(4\)\.'), # invalid qual scores (string value can't be converted to integer) ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_qual_scores_string')}, QUALFormatError, r'quality scores to integers:\n100 0 1a -42'), # invalid qual scores (float value can't be converted to integer) ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_qual_scores_float')}, QUALFormatError, r'quality scores to integers:\n42 41.0 39 40'), # invalid qual scores (negative integer) ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_qual_scores_negative')}, QUALFormatError, r'Quality scores must be greater than or equal to zero\.'), # invalid qual scores (over 255) ('fasta_3_seqs_defaults', {'qual': get_data_path('qual_invalid_qual_scores_over_255')}, QUALFormatError, r'quality score\(s\) greater than 255'), # misc. invalid files used elsewhere in the tests ('fasta_invalid_after_10_seqs', {}, FASTAFormatError, r'without sequence data'), ('fasta_id_whitespace_replacement_none', {}, FASTAFormatError, r'whitespace-only'), ('fasta_description_newline_replacement_none', {}, FASTAFormatError, r'whitespace-only') ])) # extensive tests for fasta -> generator reader since it is used by all # other fasta -> object readers def test_fasta_to_generator_valid_files(self): test_cases = (self.empty, self.single, self.multi, self.odd_labels_different_type, self.tabular_msa_different_type, self.lowercase_seqs) # Strategy: # for each fasta file, read it without its corresponding qual file, # and ensure observed vs. expected match, ignoring quality scores in # expected. next, parse the current fasta file with each # corresponding quality file and ensure that observed vs. expected # match, this time taking quality scores into account. this # sufficiently exercises parsing a standalone fasta file and paired # fasta/qual files for exp, kwargs, fasta_fps, qual_fps in test_cases: for fasta_fp in fasta_fps: obs = list(_fasta_to_generator(fasta_fp, **kwargs)) self.assertEqual(len(obs), len(exp)) for o, e in zip(obs, exp): e = copy.copy(e) del e.positional_metadata['quality'] self.assertEqual(o, e) for qual_fp in qual_fps: obs = list(_fasta_to_generator(fasta_fp, qual=qual_fp, **kwargs)) self.assertEqual(len(obs), len(exp)) for o, e in zip(obs, exp): self.assertEqual(o, e) def test_fasta_to_generator_invalid_files(self): for fp, kwargs, error_type, error_msg_regex in self.invalid_fps: with self.assertRaisesRegex(error_type, error_msg_regex): list(_fasta_to_generator(fp, **kwargs)) # light testing of fasta -> object readers to ensure interface is present # and kwargs are passed through. extensive testing of underlying reader is # performed above def test_fasta_to_any_sequence(self): for constructor, reader_fn in ((Sequence, _fasta_to_sequence), (partial(DNA, validate=False, lowercase='introns'), partial(_fasta_to_dna, validate=False, lowercase='introns')), (partial(RNA, validate=False, lowercase='introns'), partial(_fasta_to_rna, validate=False, lowercase='introns')), (partial(Protein, lowercase='introns'), partial(_fasta_to_protein, validate=False, lowercase='introns'))): # empty file empty_fp = get_data_path('empty') with self.assertRaisesRegex(ValueError, r'1st sequence'): reader_fn(empty_fp) with self.assertRaisesRegex(ValueError, r'1st sequence'): reader_fn(empty_fp, qual=empty_fp) # the sequences in the following files don't necessarily make sense # for each of the sequence object types that they're read into # (e.g., reading a protein sequence into a dna sequence object). # however, for the purposes of testing the various # fasta -> sequence readers, this works out okay as it is valid to # construct a sequence object with invalid characters. we're # interested in testing the reading logic here, and don't care so # much about constructing semantically-meaningful/valid sequence # objects # file with only 1 seq, get first fasta_fps = list(map(get_data_path, ['fasta_single_seq', 'fasta_max_width_1'])) for fasta_fp in fasta_fps: exp = constructor( 'ACGT-acgt.', metadata={'id': 'seq1', 'description': 'desc1'}) obs = reader_fn(fasta_fp) self.assertEqual(obs, exp) exp.positional_metadata.insert( 0, 'quality', np.asarray([10, 20, 30, 10, 0, 0, 0, 255, 1, 255], dtype=np.uint8)) qual_fps = list(map(get_data_path, ['qual_single_seq', 'qual_max_width_1'])) for qual_fp in qual_fps: obs = reader_fn(fasta_fp, qual=qual_fp) self.assertEqual(obs, exp) # file with multiple seqs fasta_fps = list(map(get_data_path, ['fasta_multi_seq', 'fasta_max_width_5'])) qual_fps = list(map(get_data_path, ['qual_multi_seq', 'qual_max_width_5'])) for fasta_fp in fasta_fps: # get first exp = constructor( 'ACGT-acgt.', metadata={'id': 'seq1', 'description': 'desc1'}) obs = reader_fn(fasta_fp) self.assertEqual(obs, exp) exp.positional_metadata.insert( 0, 'quality', np.asarray([10, 20, 30, 10, 0, 0, 0, 255, 1, 255], dtype=np.uint8)) for qual_fp in qual_fps: obs = reader_fn(fasta_fp, qual=qual_fp) self.assertEqual(obs, exp) # get middle exp = constructor('ACGTTGCAccGG', metadata={'id': '', 'description': ''}) obs = reader_fn(fasta_fp, seq_num=4) self.assertEqual(obs, exp) exp.positional_metadata.insert( 0, 'quality', np.asarray([55, 10, 0, 99, 1, 1, 8, 77, 40, 10, 10, 0], dtype=np.uint8)) for qual_fp in qual_fps: obs = reader_fn(fasta_fp, seq_num=4, qual=qual_fp) self.assertEqual(obs, exp) # get last exp = constructor( 'pQqqqPPQQQ', metadata={'id': 'proteinseq', 'description': 'detailed description \t\twith new lines'}) obs = reader_fn(fasta_fp, seq_num=6) self.assertEqual(obs, exp) exp.positional_metadata.insert( 0, 'quality', np.asarray([42, 42, 255, 255, 42, 42, 42, 42, 42, 43], dtype=np.uint8)) for qual_fp in qual_fps: obs = reader_fn(fasta_fp, seq_num=6, qual=qual_fp) self.assertEqual(obs, exp) # seq_num too large with self.assertRaisesRegex(ValueError, r'8th sequence'): reader_fn(fasta_fp, seq_num=8) for qual_fp in qual_fps: with self.assertRaisesRegex(ValueError, r'8th sequence'): reader_fn(fasta_fp, seq_num=8, qual=qual_fp) # seq_num too small with self.assertRaisesRegex(ValueError, r'`seq_num`=0'): reader_fn(fasta_fp, seq_num=0) for qual_fp in qual_fps: with self.assertRaisesRegex(ValueError, r'`seq_num`=0'): reader_fn(fasta_fp, seq_num=0, qual=qual_fp) def test_fasta_to_tabular_msa(self): test_cases = (self.empty, self.single, self.tabular_msa_different_type, self.lowercase_seqs) # see comment in test_fasta_to_generator_valid_files (above) for # testing strategy for exp_list, kwargs, fasta_fps, qual_fps in test_cases: if 'constructor' not in kwargs: kwargs['constructor'] = CustomSequence exp_list = [CustomSequence(seq) for seq in exp_list] exp = TabularMSA(exp_list, minter='id') for fasta_fp in fasta_fps: obs = _fasta_to_tabular_msa(fasta_fp, **kwargs) self.assertEqual(len(obs), len(exp)) for o, e in zip(obs, exp): e = copy.copy(e) del e.positional_metadata['quality'] self.assertEqual(o, e) for qual_fp in qual_fps: obs = _fasta_to_tabular_msa(fasta_fp, qual=qual_fp, **kwargs) self.assertEqual(obs, exp) def test_fasta_to_tabular_msa_no_constructor(self): with self.assertRaisesRegex(ValueError, r'`constructor`'): _fasta_to_tabular_msa(get_data_path('fasta_single_seq')) def test_keep_spaces(self): fp = get_data_path('fasta_multi_seq_spaces') # test RNA, DNA, and Protein read_fns = [_fasta_to_dna, _fasta_to_rna, _fasta_to_protein] for read_fn in read_fns: with self.assertRaises(ValueError) as e: read_fn(fp, keep_spaces=True, lowercase=True) self.assertTrue(str(e.exception).startswith("Invalid char")) # test generator obs = str(next(_fasta_to_generator(fp, keep_spaces=True))) self.assertEqual(obs, "ACGT - acgt.") # test Sequence obs = str(_fasta_to_sequence(fp, keep_spaces=True)) self.assertEqual(obs, "ACGT - acgt.") class WriterTests(TestCase): def setUp(self): self.bio_seq1 = DNA( 'ACGT-acgt.', metadata={'id': 'seq1', 'description': 'desc1'}, positional_metadata={'quality': [10, 20, 30, 10, 0, 0, 0, 255, 1, 255]}, lowercase='introns') self.bio_seq2 = DNA( 'A', metadata={'id': ' \n \nseq \t2 '}, positional_metadata={'quality': [42]}, lowercase='introns') self.bio_seq3 = RNA( 'AACGGuA', metadata={'description': 'desc3'}, positional_metadata={'quality': [0, 0, 0, 0, 0, 0, 0]}, lowercase='introns') self.dna_seq = DNA( 'ACGTTGCAccGG', positional_metadata={'quality': [55, 10, 0, 99, 1, 1, 8, 77, 40, 10, 10, 0]}, lowercase='introns') self.rna_seq = RNA('ACGUU', positional_metadata={'quality': [10, 9, 8, 7, 6]}, lowercase='introns') self.prot_seq = Protein( 'pQqqqPPQQQ', metadata={'id': 'proteinseq', 'description': "\ndetailed\ndescription \t\twith " " new\n\nlines\n\n\n"}, positional_metadata={'quality': [42, 42, 255, 255, 42, 42, 42, 42, 42, 43]}, lowercase='introns') seqs = [ CustomSequence( 'UUUU', metadata={'id': 's\te\tq\t1', 'description': 'desc\n1'}, positional_metadata={'quality': [1234, 0, 0, 2]}, lowercase='introns'), CustomSequence( 'CATC', metadata={'id': 's\te\tq\t2', 'description': 'desc\n2'}, positional_metadata={'quality': [1, 11, 111, 11112]}), CustomSequence( 'sits', metadata={'id': 's\te\tq\t3', 'description': 'desc\n3'}, positional_metadata={'quality': [12345, 678909, 999999, 4242424242]}) ] self.msa = TabularMSA(seqs) def empty_gen(): yield from () def single_seq_gen(): yield self.bio_seq1 # generate sequences with descriptions containing newlines (to test # description_newline_replacement) def newline_description_gen(): yield self.prot_seq yield DNA('AGGAGAATA', metadata={'id': 'foo', 'description': '\n\n\n\n'}, positional_metadata={'quality': range(9)}, lowercase='introns') # generate sequences with ids containing whitespace (to test # id_whitespace_replacement) def whitespace_id_gen(): yield self.bio_seq2 yield RNA('UA', metadata={'id': '\n\t \t', 'description': 'a\nb'}, positional_metadata={'quality': [1000, 1]}) # multiple sequences of mixed types, lengths, and metadata. lengths are # chosen to exercise various splitting cases when testing max_width, # including exercising the different splitting algorithms used for # sequence data vs. quality scores def multi_seq_gen(): yield from (self.bio_seq1, self.bio_seq2, self.bio_seq3, self.dna_seq, self.rna_seq, self.prot_seq) # can be serialized if no qual file is provided, else it should raise # an error because one seq has qual scores and the other doesn't def mixed_qual_score_gen(): yield self.bio_seq1 yield DNA('AAAAT', metadata={'id': 'da,dadadada', 'description': '10 hours'}, lowercase='introns') self.mixed_qual_score_gen = mixed_qual_score_gen() # store sequence generator to serialize, writer kwargs (if any), and # fasta and qual filepaths of expected results self.objs_fps = list(map(lambda e: (e[0], e[1], get_data_path(e[2]), get_data_path(e[3])), [ (empty_gen(), {}, 'empty', 'empty'), (single_seq_gen(), {'lowercase': 'introns'}, 'fasta_single_seq', 'qual_single_seq'), # no splitting of sequence or qual data across lines b/c max_width # is sufficiently large (single_seq_gen(), {'max_width': 32, 'lowercase': 'introns'}, 'fasta_single_seq', 'qual_single_seq'), # splitting algorithm for sequence and qual scores is different; # make sure individual qual scores aren't split across lines even # if they exceed max_width (single_seq_gen(), {'max_width': 1, 'lowercase': 'introns'}, 'fasta_max_width_1', 'qual_max_width_1'), (multi_seq_gen(), {'lowercase': 'introns'}, 'fasta_multi_seq', 'qual_multi_seq'), (multi_seq_gen(), {'max_width': 5, 'lowercase': 'introns'}, 'fasta_max_width_5', 'qual_max_width_5'), (newline_description_gen(), {'description_newline_replacement': ':-)', 'lowercase': 'introns'}, 'fasta_description_newline_replacement_multi_char', 'qual_description_newline_replacement_multi_char'), (newline_description_gen(), {'description_newline_replacement': '', 'lowercase': 'introns'}, 'fasta_description_newline_replacement_empty_str', 'qual_description_newline_replacement_empty_str',), (newline_description_gen(), {'description_newline_replacement': None, 'lowercase': 'introns'}, 'fasta_description_newline_replacement_none', 'qual_description_newline_replacement_none'), (whitespace_id_gen(), {'id_whitespace_replacement': '>:o'}, 'fasta_id_whitespace_replacement_multi_char', 'qual_id_whitespace_replacement_multi_char'), (whitespace_id_gen(), {'id_whitespace_replacement': ''}, 'fasta_id_whitespace_replacement_empty_str', 'qual_id_whitespace_replacement_empty_str'), (whitespace_id_gen(), {'id_whitespace_replacement': None}, 'fasta_id_whitespace_replacement_none', 'qual_id_whitespace_replacement_none'), ])) def blank_seq_gen(): yield from (self.bio_seq1, Sequence('')) # generators or parameter combos that cannot be written in fasta # format, paired with kwargs (if any), error type, and expected error # message regexp self.invalid_objs = [ (blank_seq_gen(), {}, ValueError, r'2nd.*empty'), (single_seq_gen(), {'max_width': 0}, ValueError, r'max_width=0'), (multi_seq_gen(), {'id_whitespace_replacement': '-\n_'}, ValueError, r'Newline character'), (multi_seq_gen(), {'description_newline_replacement': '-.-\n'}, ValueError, r'Newline character'), (mixed_qual_score_gen(), {'qual': io.StringIO()}, ValueError, r'2nd sequence.*does not have quality scores') ] # extensive tests for generator -> fasta writer since it is used by all # other object -> fasta writers def test_generator_to_fasta_no_qual(self): # test writing standalone fasta (i.e., without a qual file) for obj, kwargs, fp, _ in self.objs_fps: fh = io.StringIO() _generator_to_fasta(obj, fh, **kwargs) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_generator_to_fasta_mixed_qual_scores(self): # test writing some sequences with qual scores and some without is # possible if no qual output file is specified fh = io.StringIO() _generator_to_fasta(self.mixed_qual_score_gen, fh, lowercase='introns') obs = fh.getvalue() fh.close() with io.open(get_data_path('fasta_mixed_qual_scores')) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_generator_to_fasta_with_qual(self): # test writing fasta and qual files for obj, kwargs, fasta_fp, qual_fp in self.objs_fps: if qual_fp is not None: fasta_fh = io.StringIO() qual_fh = io.StringIO() _generator_to_fasta(obj, fasta_fh, qual=qual_fh, **kwargs) obs_fasta = fasta_fh.getvalue() obs_qual = qual_fh.getvalue() fasta_fh.close() qual_fh.close() with io.open(fasta_fp) as fh: exp_fasta = fh.read() with io.open(qual_fp) as fh: exp_qual = fh.read() self.assertEqual(obs_fasta, exp_fasta) self.assertEqual(obs_qual, exp_qual) def test_generator_to_fasta_invalid_input(self): for obj, kwargs, error_type, error_msg_regexp in self.invalid_objs: fh = io.StringIO() with self.assertRaisesRegex(error_type, error_msg_regexp): _generator_to_fasta(obj, fh, **kwargs) fh.close() # light testing of object -> fasta writers to ensure interface is present # and kwargs are passed through. extensive testing of underlying writer is # performed above def test_any_sequence_to_fasta(self): # store writer function, sequence object to write, expected # fasta filepath for default parameters, expected fasta filepath for # non-defaults, and expected qual filepath for non-defaults id_ = 'f o o' desc = 'b\na\nr' test_data = ( (partial(_sequence_to_fasta, lowercase='introns'), Sequence('ACgt', metadata={'id': id_, 'description': desc}, positional_metadata={'quality': range(1, 5)}, lowercase='introns'), ('fasta_single_bio_seq_defaults', 'fasta_single_bio_seq_non_defaults', 'qual_single_bio_seq_non_defaults')), (partial(_dna_to_fasta, lowercase='introns'), DNA('TAcg', metadata={'id': id_, 'description': desc}, positional_metadata={'quality': range(4)}, lowercase='introns'), ('fasta_single_dna_seq_defaults', 'fasta_single_dna_seq_non_defaults', 'qual_single_dna_seq_non_defaults')), (partial(_rna_to_fasta, lowercase='introns'), RNA('uaCG', metadata={'id': id_, 'description': desc}, positional_metadata={'quality': range(2, 6)}, lowercase='introns'), ('fasta_single_rna_seq_defaults', 'fasta_single_rna_seq_non_defaults', 'qual_single_rna_seq_non_defaults')), (partial(_protein_to_fasta, lowercase='introns'), Protein('PqQ', metadata={'id': id_, 'description': desc}, positional_metadata={'quality': [42, 41, 40]}, lowercase='introns'), ('fasta_single_prot_seq_defaults', 'fasta_single_prot_seq_non_defaults', 'qual_single_prot_seq_non_defaults'))) for fn, obj, fps in test_data: defaults_fp, non_defaults_fasta_fp, non_defaults_qual_fp = fps # test writing with default parameters fh = io.StringIO() fn(obj, fh) obs = fh.getvalue() fh.close() with io.open(get_data_path(defaults_fp)) as fh: exp = fh.read() self.assertEqual(obs, exp) # test writing with non-defaults fasta_fh = io.StringIO() qual_fh = io.StringIO() fn(obj, fasta_fh, id_whitespace_replacement='-', description_newline_replacement='_', max_width=1, qual=qual_fh) obs_fasta = fasta_fh.getvalue() obs_qual = qual_fh.getvalue() fasta_fh.close() qual_fh.close() with io.open(get_data_path(non_defaults_fasta_fp)) as fh: exp_fasta = fh.read() with io.open(get_data_path(non_defaults_qual_fp)) as fh: exp_qual = fh.read() self.assertEqual(obs_fasta, exp_fasta) self.assertEqual(obs_qual, exp_qual) def test_any_sequences_to_fasta(self): # test writing with default parameters fh = io.StringIO() _tabular_msa_to_fasta(self.msa, fh) obs = fh.getvalue() fh.close() with io.open(get_data_path('fasta_3_seqs_defaults')) as fh: exp = fh.read() self.assertEqual(obs, exp) # test writing with non-defaults fasta_fh = io.StringIO() qual_fh = io.StringIO() _tabular_msa_to_fasta(self.msa, fasta_fh, id_whitespace_replacement='*', description_newline_replacement='+', max_width=3, qual=qual_fh) obs_fasta = fasta_fh.getvalue() obs_qual = qual_fh.getvalue() fasta_fh.close() qual_fh.close() with io.open(get_data_path('fasta_3_seqs_non_defaults')) as fh: exp_fasta = fh.read() with io.open(get_data_path('qual_3_seqs_non_defaults')) as fh: exp_qual = fh.read() self.assertEqual(obs_fasta, exp_fasta) self.assertEqual(obs_qual, exp_qual) class RoundtripTests(TestCase): def test_roundtrip_generators(self): # test that fasta and qual files can be streamed into memory and back # out to disk using generator reader and writer fps = list(map(lambda e: list(map(get_data_path, e)), [('empty', 'empty'), ('fasta_multi_seq_roundtrip', 'qual_multi_seq_roundtrip')])) for fasta_fp, qual_fp in fps: with io.open(fasta_fp) as fh: exp_fasta = fh.read() with io.open(qual_fp) as fh: exp_qual = fh.read() fasta_fh = io.StringIO() qual_fh = io.StringIO() _generator_to_fasta(_fasta_to_generator(fasta_fp, qual=qual_fp), fasta_fh, qual=qual_fh) obs_fasta = fasta_fh.getvalue() obs_qual = qual_fh.getvalue() fasta_fh.close() qual_fh.close() self.assertEqual(obs_fasta, exp_fasta) self.assertEqual(obs_qual, exp_qual) def test_roundtrip_tabular_msa(self): fps = list(map(lambda e: list(map(get_data_path, e)), [('empty', 'empty'), ('fasta_tabular_msa_different_type', 'qual_tabular_msa_different_type')])) reader = partial(_fasta_to_tabular_msa, constructor=CustomSequence) writer = _tabular_msa_to_fasta for fasta_fp, qual_fp in fps: # read obj1 = reader(fasta_fp, qual=qual_fp) # write fasta_fh = io.StringIO() qual_fh = io.StringIO() writer(obj1, fasta_fh, qual=qual_fh) fasta_fh.seek(0) qual_fh.seek(0) # read obj2 = reader(fasta_fh, qual=qual_fh) fasta_fh.close() qual_fh.close() self.assertEqual(obj1, obj2) def test_roundtrip_biological_sequences(self): fps = list(map(lambda e: list(map(get_data_path, e)), [('fasta_multi_seq_roundtrip', 'qual_multi_seq_roundtrip'), ('fasta_tabular_msa_different_type', 'qual_tabular_msa_different_type')])) for reader, writer in ((_fasta_to_sequence, _sequence_to_fasta), (partial(_fasta_to_dna, validate=False), _dna_to_fasta), (partial(_fasta_to_rna, validate=False), _rna_to_fasta), (partial(_fasta_to_protein, validate=False), _protein_to_fasta)): for fasta_fp, qual_fp in fps: # read obj1 = reader(fasta_fp, qual=qual_fp) # write fasta_fh = io.StringIO() qual_fh = io.StringIO() writer(obj1, fasta_fh, qual=qual_fh) fasta_fh.seek(0) qual_fh.seek(0) # read obj2 = reader(fasta_fh, qual=qual_fh) fasta_fh.close() qual_fh.close() self.assertEqual(obj1, obj2) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_fastq.py000066400000000000000000000702251520735541300252600ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io import string import unittest import warnings from functools import partial from skbio import read, write, Sequence, DNA, RNA, Protein, TabularMSA from skbio.io import FASTQFormatError from skbio.io.format.fastq import ( _fastq_sniffer, _fastq_to_generator, _fastq_to_tabular_msa, _generator_to_fastq, _tabular_msa_to_fastq) from skbio.sequence import GrammaredSequence from skbio.util import get_data_path from skbio.util import classproperty from skbio.util._decorator import overrides import numpy as np # Note: the example FASTQ files with file extension .fastq are taken from the # following open-access publication's supplementary data: # # P.J.A. Cock, C.J. Fields, N. Goto, M.L. Heuer and P.M. Rice (2009). The # Sanger FASTQ file format for sequences with quality scores, and the # Solexa/Illumina FASTQ variants. # # See licenses/fastq-example-files-readme.txt for the original README that # accompanied these files, which includes the terms of use and detailed # description of the files. # # The example files bearing the original filenames have not been modified from # their original form. def _drop_kwargs(kwargs, *args): for arg in args: if arg in kwargs: kwargs.pop(arg) class TestSniffer(unittest.TestCase): def setUp(self): self.positives = [get_data_path(e) for e in [ 'fastq_multi_seq_sanger', 'fastq_multi_blank_between_records', 'fastq_multi_ws_lines_between_records', 'fastq_multi_blank_end_of_file', 'fastq_multi_ws_lines_end_of_file', 'fastq_multi_whitespace_stripping', 'fastq_blank_lines', 'fastq_whitespace_only_lines', 'fastq_single_seq_illumina1.3', 'fastq_wrapping_as_illumina_no_description', 'fastq_wrapping_as_sanger_no_description', 'fastq_wrapping_original_sanger_no_description', 'fastq_writer_illumina1.3_defaults', 'fastq_writer_sanger_defaults', 'fastq_writer_sanger_non_defaults', 'fastq_5_blanks_start_of_file', 'fastq_5_ws_lines_start_of_file', 'illumina_full_range_as_illumina.fastq', 'illumina_full_range_as_sanger.fastq', 'illumina_full_range_original_illumina.fastq', 'longreads_as_illumina.fastq', 'longreads_as_sanger.fastq', 'longreads_original_sanger.fastq', 'misc_dna_as_illumina.fastq', 'misc_dna_as_sanger.fastq', 'misc_dna_original_sanger.fastq', 'misc_rna_as_illumina.fastq', 'misc_rna_as_sanger.fastq', 'misc_rna_original_sanger.fastq', 'sanger_full_range_as_illumina.fastq', 'sanger_full_range_as_sanger.fastq', 'sanger_full_range_original_sanger.fastq', 'solexa_full_range_original_solexa.fastq', 'wrapping_as_illumina.fastq', 'wrapping_as_sanger.fastq', 'wrapping_original_sanger.fastq' ]] self.negatives = [get_data_path(e) for e in [ 'empty', 'whitespace_only', 'fastq_multi_blank_start_of_file', 'fastq_multi_ws_lines_start_of_file', 'fastq_invalid_blank_after_header', 'fastq_invalid_blank_after_seq', 'fastq_invalid_blank_after_plus', 'fastq_invalid_blank_within_seq', 'fastq_invalid_blank_within_qual', 'fastq_invalid_ws_line_after_header', 'fastq_invalid_ws_line_after_seq', 'fastq_invalid_ws_line_after_plus', 'fastq_invalid_ws_line_within_seq', 'fastq_invalid_ws_line_within_qual', 'fastq_invalid_missing_header', 'fastq_invalid_missing_seq_data', 'error_diff_ids.fastq', 'error_double_qual.fastq', 'error_double_seq.fastq', 'error_long_qual.fastq', 'error_no_qual.fastq', 'error_qual_del.fastq', 'error_qual_escape.fastq', 'error_qual_null.fastq', 'error_qual_space.fastq', 'error_qual_tab.fastq', 'error_qual_unit_sep.fastq', 'error_qual_vtab.fastq', 'error_short_qual.fastq', 'error_spaces.fastq', 'error_tabs.fastq', 'error_trunc_at_seq.fastq', 'error_trunc_at_plus.fastq', 'error_trunc_at_qual.fastq', 'error_trunc_in_title.fastq', 'error_trunc_in_seq.fastq', 'error_trunc_in_plus.fastq', 'error_trunc_in_qual.fastq', ]] def test_positives(self): for fp in self.positives: self.assertEqual(_fastq_sniffer(fp), (True, {})) def test_negatives(self): for fp in self.negatives: self.assertEqual(_fastq_sniffer(fp), (False, {})) def test_illumina_sniffed(self): fp = get_data_path('fastq_single_seq_illumina1.8') self.assertEqual(_fastq_sniffer(fp), (True, {'variant': 'illumina1.8'})) class TestReaders(unittest.TestCase): def setUp(self): self.valid_configurations = [ ([get_data_path('empty'), get_data_path('whitespace_only')], [{}, {'variant': 'illumina1.8'}, {'phred_offset': 33, 'constructor': DNA}], []), ([get_data_path('fastq_single_seq_illumina1.3')], [ {'variant': 'illumina1.3'}, {'phred_offset': 64}, {'variant': 'illumina1.3', 'constructor': Protein}, ], [ ('', 'bar\t baz', 'aCGT', [33, 34, 35, 36]) ]), ([get_data_path('fastq_multi_seq_sanger'), get_data_path('fastq_whitespace_only_lines'), get_data_path('fastq_blank_lines'), get_data_path('fastq_multi_blank_between_records'), get_data_path('fastq_multi_ws_lines_between_records'), get_data_path('fastq_multi_blank_end_of_file'), get_data_path('fastq_multi_ws_lines_end_of_file'), get_data_path('fastq_multi_blank_start_of_file'), get_data_path('fastq_multi_ws_lines_start_of_file'), get_data_path('fastq_multi_whitespace_stripping')], [ {'variant': 'sanger'}, {'phred_offset': 33, 'seq_num': 2}, {'variant': 'sanger', 'constructor': partial(RNA, validate=False), 'seq_num': 3}, ], [ ('foo', 'bar baz', 'AACCGG', [16, 17, 18, 19, 20, 21]), ('bar', 'baz foo', 'TTGGCC', [23, 22, 21, 20, 19, 18]), ('baz', 'foo bar', 'GATTTC', [20, 21, 22, 23, 24, 18]) ]), ] self.invalid_files = [(get_data_path(e[0]), e[1], e[2]) for e in [ ('fastq_invalid_blank_after_header', FASTQFormatError, r'blank or whitespace-only line.*after header.*in FASTQ'), ('fastq_invalid_blank_after_seq', FASTQFormatError, r"blank or whitespace-only line.*before '\+' in FASTQ"), ('fastq_invalid_blank_after_plus', FASTQFormatError, r"blank or whitespace-only line.*after '\+'.*in FASTQ"), ('fastq_invalid_blank_within_seq', FASTQFormatError, r'blank or whitespace-only line.*within sequence.*FASTQ'), ('fastq_invalid_blank_within_qual', FASTQFormatError, r"blank or whitespace-only line.*within quality scores.*in " "FASTQ"), ('fastq_invalid_ws_line_after_header', FASTQFormatError, r'blank or whitespace-only line.*after header.*in FASTQ'), ('fastq_invalid_ws_line_after_seq', FASTQFormatError, r"blank or whitespace-only line.*before '\+' in FASTQ"), ('fastq_invalid_ws_line_after_plus', FASTQFormatError, r"blank or whitespace-only line.*after '\+'.*in FASTQ"), ('fastq_invalid_ws_line_within_seq', FASTQFormatError, r'blank or whitespace-only line.*within sequence.*FASTQ'), ('fastq_invalid_ws_line_within_qual', FASTQFormatError, r"blank or whitespace-only line.*within quality scores.*in " "FASTQ"), ('fastq_invalid_missing_header', FASTQFormatError, r"sequence.*header.*start of file: 'seq1 desc1'"), ('fastq_invalid_missing_seq_data', FASTQFormatError, r'without sequence data'), ('error_diff_ids.fastq', FASTQFormatError, r"header lines do not match: " "'SLXA-B3_649_FC8437_R1_1_1_850_123' != " "'SLXA-B3_649_FC8437_R1_1_1_850_124'"), ('error_double_qual.fastq', FASTQFormatError, r"Extra quality.*'\+SLXA-B3_649_FC8437_R1_1_1_850_123'"), ('error_double_seq.fastq', FASTQFormatError, r'FASTQ record that is missing a quality \(\+\) header line'), ('error_long_qual.fastq', FASTQFormatError, r"Extra quality.*'Y'"), ('error_no_qual.fastq', FASTQFormatError, r"blank or whitespace-only line.*after '\+'.*in FASTQ"), ('error_qual_del.fastq', ValueError, r'Decoded Phred score.*out of range'), ('error_qual_escape.fastq', ValueError, r'Decoded Phred score.*out of range'), ('error_qual_null.fastq', ValueError, r'Decoded Phred score.*out of range'), ('error_qual_space.fastq', ValueError, r'Decoded Phred score.*out of range'), ('error_qual_tab.fastq', ValueError, r'Decoded Phred score.*out of range'), ('error_qual_unit_sep.fastq', ValueError, r'Decoded Phred score.*out of range'), ('error_qual_vtab.fastq', ValueError, r'Decoded Phred score.*out of range'), ('error_short_qual.fastq', FASTQFormatError, r"Extra quality.*'SLXA-B3_649_FC8437_R1_1_1_362_549'"), ('error_spaces.fastq', FASTQFormatError, r"whitespace.*sequence data: 'GATGTGCAA TACCTTTGTA GAGGAA'"), ('error_tabs.fastq', FASTQFormatError, r"whitespace.*sequence data: 'GATGTGCAA\\tTACCTTTGTA\\tGAGGAA'"), ('error_trunc_at_seq.fastq', FASTQFormatError, r'incomplete/truncated.*FASTQ'), ('error_trunc_at_plus.fastq', FASTQFormatError, r'incomplete/truncated.*FASTQ'), ('error_trunc_at_qual.fastq', FASTQFormatError, r'incomplete/truncated.*end of file'), ('error_trunc_in_title.fastq', FASTQFormatError, r'incomplete/truncated.*end of file'), ('error_trunc_in_seq.fastq', FASTQFormatError, r'incomplete/truncated.*end of file'), ('error_trunc_in_plus.fastq', FASTQFormatError, r"header lines do not match: " "'SLXA-B3_649_FC8437_R1_1_1_183_714' != 'SLXA-B3_649_FC'"), ('error_trunc_in_qual.fastq', FASTQFormatError, r'incomplete/truncated.*end of file') ]] def test_fastq_to_generator_valid_files(self): for valid_files, kwargs, components in self.valid_configurations: for valid in valid_files: for observed_kwargs in kwargs: _drop_kwargs(observed_kwargs, 'seq_num') constructor = observed_kwargs.get('constructor', Sequence) expected_kwargs = {} expected_kwargs['lowercase'] = 'introns' observed_kwargs['lowercase'] = 'introns' expected = [constructor(c[2], metadata={'id': c[0], 'description': c[1]}, positional_metadata={'quality': np.array(c[3], dtype=np.uint8)}, **expected_kwargs) for c in components] observed = list(_fastq_to_generator(valid, **observed_kwargs)) self.assertEqual(len(expected), len(observed)) for o, e in zip(observed, expected): self.assertEqual(o, e) def test_fastq_to_generator_invalid_files_all_variants(self): # files that should be invalid for all variants, as well as custom # phred offsets for fp, error_type, error_msg_regex in self.invalid_files: for variant in 'sanger', 'illumina1.3', 'illumina1.8': with self.assertRaisesRegex(error_type, error_msg_regex): list(_fastq_to_generator(fp, variant=variant)) for offset in 33, 64, 40, 77: with self.assertRaisesRegex(error_type, error_msg_regex): list(_fastq_to_generator(fp, phred_offset=offset)) def test_fastq_to_generator_invalid_files_illumina(self): # files that should be invalid for illumina1.3 and illumina1.8 variants fps = [get_data_path(fp) for fp in ['sanger_full_range_original_sanger.fastq', 'solexa_full_range_original_solexa.fastq']] for fp in fps: with self.assertRaisesRegex(ValueError, r'out of range \[0, 62\]'): list(_fastq_to_generator(fp, variant='illumina1.3')) with self.assertRaisesRegex(ValueError, r'out of range \[0, 62\]'): list(_fastq_to_generator(fp, variant='illumina1.8')) def test_fastq_to_generator_solexa(self): # solexa support isn't implemented yet. should raise error even with # valid solexa file with self.assertRaisesRegex(ValueError, r'Solexa'): list(_fastq_to_generator( get_data_path('solexa_full_range_original_solexa.fastq'), variant='solexa')) def test_fastq_to_sequence(self): for constructor in [Sequence, DNA, RNA, Protein]: for valid_files, kwargs, components in self.valid_configurations: for valid in valid_files: # skip empty file case since we cannot read a specific # sequencefrom an empty file if len(components) == 0: continue for observed_kwargs in kwargs: expected_kwargs = {} # TODO: # some of the test files contain characters which are # invalid for RNA, so don't validate for now. Need to # fix this if constructor is RNA: observed_kwargs['validate'] = False expected_kwargs['validate'] = False _drop_kwargs(observed_kwargs, 'constructor') expected_kwargs['lowercase'] = 'introns' observed_kwargs['lowercase'] = 'introns' seq_num = observed_kwargs.get('seq_num', 1) c = components[seq_num - 1] expected = \ constructor( c[2], metadata={'id': c[0], 'description': c[1]}, positional_metadata={'quality': np.array(c[3], dtype=np.uint8)}, **expected_kwargs) observed = read(valid, into=constructor, format='fastq', verify=False, **observed_kwargs) self.assertEqual(observed, expected) def test_fastq_to_tabular_msa(self): class CustomSequence(GrammaredSequence): @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set('-.') @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return '-' @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set(string.ascii_letters) @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return {} for valid_files, kwargs, components in self.valid_configurations: for valid in valid_files: for observed_kwargs in kwargs: _drop_kwargs(observed_kwargs, 'seq_num') if 'constructor' not in observed_kwargs: observed_kwargs['constructor'] = CustomSequence constructor = observed_kwargs['constructor'] expected_kwargs = {} expected_kwargs['lowercase'] = 'introns' observed_kwargs['lowercase'] = 'introns' expected = TabularMSA( [constructor( c[2], metadata={'id': c[0], 'description': c[1]}, positional_metadata={'quality': np.array(c[3], dtype=np.uint8)}, **expected_kwargs) for c in components], minter='id') observed = _fastq_to_tabular_msa(valid, **observed_kwargs) self.assertEqual(observed, expected) def test_fastq_to_tabular_msa_no_constructor(self): with self.assertRaisesRegex(ValueError, r'`constructor`'): _fastq_to_tabular_msa(get_data_path('fastq_multi_seq_sanger')) class TestWriters(unittest.TestCase): def setUp(self): self.valid_files = [ ([ ('f o o', 'bar\n\nbaz', 'AaCcGg', [16, 17, 18, 19, 20, 21]), ('bar', 'baz foo', 'TtGgCc', [23, 22, 21, 20, 19, 18]), ('ba\n\t\tz', 'foo bar', 'gAtTtC', [20, 21, 22, 23, 24, 18]) ], [ ({'variant': 'sanger'}, get_data_path('fastq_writer_sanger_defaults')), ({'phred_offset': 33}, get_data_path('fastq_writer_sanger_defaults')), ({'variant': 'illumina1.8'}, get_data_path('fastq_writer_sanger_defaults')), ({'variant': 'illumina1.3'}, get_data_path('fastq_writer_illumina1.3_defaults')), ({'variant': 'sanger', 'id_whitespace_replacement': '%', 'description_newline_replacement': '^'}, get_data_path('fastq_writer_sanger_non_defaults')) ]), ] def test_generator_to_fastq_kwargs_passed(self): for components, kwargs_expected_fp in self.valid_files: for kwargs, expected_fp in kwargs_expected_fp: def gen(): for c in components: yield Sequence( c[2], metadata={'id': c[0], 'description': c[1]}, positional_metadata={'quality': c[3]}) fh = io.StringIO() _generator_to_fastq(gen(), fh, **kwargs) observed = fh.getvalue() fh.close() with io.open(expected_fp) as f: expected = f.read() self.assertEqual(observed, expected) def test_sequence_to_fastq_kwargs_passed(self): for constructor in [Sequence, DNA, RNA, Protein]: for components, kwargs_expected_fp in self.valid_files: for expected_kwargs, expected_fp in kwargs_expected_fp: observed_kwargs = {} # TODO: # some of the test files contain characters which are # invalid for RNA, so don't validate for now. Need to # fix this if constructor is RNA: observed_kwargs['validate'] = False expected_kwargs['lowercase'] = 'introns' observed_kwargs['lowercase'] = 'introns' fh = io.StringIO() for c in components: obj = constructor( c[2], metadata={'id': c[0], 'description': c[1]}, positional_metadata={'quality': c[3]}, **observed_kwargs) write(obj, into=fh, format='fastq', **expected_kwargs) observed = fh.getvalue() fh.close() with io.open(expected_fp) as f: expected = f.read() self.assertEqual(observed, expected) def test_tabular_msa_to_fastq_kwargs_passed(self): for components, kwargs_expected_fp in self.valid_files: for kwargs, expected_fp in kwargs_expected_fp: obj = TabularMSA([ Protein(c[2], metadata={'id': c[0], 'description': c[1]}, positional_metadata={'quality': c[3]}, lowercase='introns') for c in components]) fh = io.StringIO() kwargs['lowercase'] = 'introns' _tabular_msa_to_fastq(obj, fh, **kwargs) observed = fh.getvalue() fh.close() with io.open(expected_fp) as f: expected = f.read() self.assertEqual(observed, expected) def test_generator_to_fastq_no_qual(self): def gen(): yield Sequence('ACGT', metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': range(4)}) yield Sequence('ACG', metadata={'id': 'foo', 'description': 'bar'}) with self.assertRaisesRegex(ValueError, r'2nd.*quality scores'): _generator_to_fastq(gen(), io.StringIO(), variant='illumina1.8') class TestConversions(unittest.TestCase): def setUp(self): self.conversions = [ (get_data_path('empty'), get_data_path('empty'), [ ({'variant': 'sanger'}, {'phred_offset': 42}), ]), (get_data_path('longreads_original_sanger.fastq'), get_data_path('longreads_as_sanger.fastq'), [ ({'variant': 'sanger'}, {'variant': 'sanger'}), ({'phred_offset': 33}, {'variant': 'sanger'}), ({'variant': 'sanger'}, {'phred_offset': 33}) ]), (get_data_path('longreads_original_sanger.fastq'), get_data_path('longreads_as_illumina.fastq'), [ ({'variant': 'sanger'}, {'variant': 'illumina1.3'}), ({'phred_offset': 33}, {'variant': 'illumina1.3'}), ({'variant': 'sanger'}, {'phred_offset': 64}) ]), (get_data_path('wrapping_original_sanger.fastq'), get_data_path('wrapping_as_sanger.fastq'), [ ({'variant': 'sanger'}, {'variant': 'sanger'}), ({'phred_offset': 33}, {'variant': 'sanger'}), ({'variant': 'sanger'}, {'phred_offset': 33}) ]), (get_data_path('wrapping_original_sanger.fastq'), get_data_path('wrapping_as_illumina.fastq'), [ ({'variant': 'sanger'}, {'variant': 'illumina1.3'}), ({'phred_offset': 33}, {'variant': 'illumina1.3'}), ({'variant': 'sanger'}, {'phred_offset': 64}) ]), (get_data_path('sanger_full_range_original_sanger.fastq'), get_data_path('sanger_full_range_as_sanger.fastq'), [ ({'variant': 'sanger'}, {'variant': 'sanger'}), ({'phred_offset': 33}, {'variant': 'sanger'}), ({'variant': 'sanger'}, {'phred_offset': 33}) ]), (get_data_path('sanger_full_range_original_sanger.fastq'), get_data_path('sanger_full_range_as_illumina.fastq'), [ ({'variant': 'sanger'}, {'variant': 'illumina1.3'}), ({'phred_offset': 33}, {'variant': 'illumina1.3'}), ({'variant': 'sanger'}, {'phred_offset': 64}) ]), (get_data_path('illumina_full_range_original_illumina.fastq'), get_data_path('illumina_full_range_as_illumina.fastq'), [ ({'variant': 'illumina1.3'}, {'variant': 'illumina1.3'}), ({'phred_offset': 64}, {'variant': 'illumina1.3'}), ({'variant': 'illumina1.3'}, {'phred_offset': 64}) ]), (get_data_path('illumina_full_range_original_illumina.fastq'), get_data_path('illumina_full_range_as_sanger.fastq'), [ ({'variant': 'illumina1.3'}, {'variant': 'sanger'}), ({'phred_offset': 64}, {'variant': 'sanger'}), ({'variant': 'illumina1.3'}, {'phred_offset': 33}) ]), (get_data_path('misc_dna_original_sanger.fastq'), get_data_path('misc_dna_as_sanger.fastq'), [ ({'variant': 'sanger'}, {'variant': 'sanger'}), ({'phred_offset': 33}, {'variant': 'sanger'}), ({'variant': 'sanger'}, {'phred_offset': 33}) ]), (get_data_path('misc_dna_original_sanger.fastq'), get_data_path('misc_dna_as_illumina.fastq'), [ ({'variant': 'sanger'}, {'variant': 'illumina1.3'}), ({'phred_offset': 33}, {'variant': 'illumina1.3'}), ({'variant': 'sanger'}, {'phred_offset': 64}) ]), (get_data_path('misc_rna_original_sanger.fastq'), get_data_path('misc_rna_as_sanger.fastq'), [ ({'variant': 'sanger'}, {'variant': 'sanger'}), ({'phred_offset': 33}, {'variant': 'sanger'}), ({'variant': 'sanger'}, {'phred_offset': 33}) ]), (get_data_path('misc_rna_original_sanger.fastq'), get_data_path('misc_rna_as_illumina.fastq'), [ ({'variant': 'sanger'}, {'variant': 'illumina1.3'}), ({'phred_offset': 33}, {'variant': 'illumina1.3'}), ({'variant': 'sanger'}, {'phred_offset': 64}) ]), (get_data_path('fastq_wrapping_original_sanger_no_description'), get_data_path('fastq_wrapping_as_sanger_no_description'), [ ({'variant': 'sanger'}, {'variant': 'sanger'}), ({'phred_offset': 33}, {'variant': 'sanger'}), ({'variant': 'sanger'}, {'phred_offset': 33}) ]), (get_data_path('fastq_wrapping_original_sanger_no_description'), get_data_path('fastq_wrapping_as_illumina_no_description'), [ ({'variant': 'sanger'}, {'variant': 'illumina1.3'}), ({'phred_offset': 33}, {'variant': 'illumina1.3'}), ({'variant': 'sanger'}, {'phred_offset': 64}) ]), ] def test_conversion(self): for from_fp, to_fp, kwargs in self.conversions: for from_kwargs, to_kwargs in kwargs: read_gen = _fastq_to_generator(from_fp, **from_kwargs) fh = io.StringIO() # will issue warning when truncating quality scores with warnings.catch_warnings(record=True): warnings.simplefilter("ignore") _generator_to_fastq(read_gen, fh, **to_kwargs) obs = fh.getvalue() fh.close() with io.open(to_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_genbank.py000066400000000000000000000363431520735541300255520ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from unittest import TestCase, main from skbio import Protein, DNA, RNA, Sequence from skbio.metadata import IntervalMetadata from skbio.util import get_data_path from skbio.io import GenBankFormatError from skbio.io.format.genbank import ( _genbank_sniffer, _genbank_to_generator, _genbank_to_sequence, _genbank_to_dna, _genbank_to_rna, _genbank_to_protein, _parse_locus, _parse_reference, _generator_to_genbank, _sequence_to_genbank, _protein_to_genbank, _rna_to_genbank, _dna_to_genbank, _serialize_locus) class SnifferTests(TestCase): def setUp(self): self.positive_fps = list(map(get_data_path, [ 'genbank_5_blanks_start_of_file', 'genbank_single_record_upper', 'genbank_single_record_lower', 'genbank_multi_records'])) self.negative_fps = list(map(get_data_path, [ 'empty', 'whitespace_only', 'genbank_6_blanks_start_of_file', 'genbank_w_beginning_whitespace', 'genbank_missing_locus_name'])) def test_positives(self): for fp in self.positive_fps: self.assertEqual(_genbank_sniffer(fp), (True, {})) def test_negatives(self): for fp in self.negative_fps: self.assertEqual(_genbank_sniffer(fp), (False, {})) class GenBankIOTests(TestCase): # parent class to set up test data for the child class def setUp(self): # test locus line self.locus = ( (['LOCUS NC_005816 9609 bp ' 'DNA circular CON 07-FEB-2015'], {'division': 'CON', 'mol_type': 'DNA', 'shape': 'circular', 'locus_name': 'NC_005816', 'date': '07-FEB-2015', 'unit': 'bp', 'size': 9609}), (['LOCUS SCU49845 5028 bp ' 'DNA PLN 21-JUN-1999'], {'division': 'PLN', 'mol_type': 'DNA', 'shape': None, 'locus_name': 'SCU49845', 'date': '21-JUN-1999', 'unit': 'bp', 'size': 5028}), (['LOCUS NP_001832 360 aa ' 'linear PRI 18-DEC-2001'], {'division': 'PRI', 'mol_type': None, 'shape': 'linear', 'locus_name': 'NP_001832', 'date': '18-DEC-2001', 'unit': 'aa', 'size': 360})) # test single record and read uppercase sequence self.single_upper_fp = get_data_path('genbank_single_record_upper') self.single_lower_fp = get_data_path('genbank_single_record_lower') self.single = ( 'GSREILDFK', {'LOCUS': {'date': '23-SEP-1994', 'division': 'BCT', 'locus_name': 'AAB29917', 'mol_type': None, 'shape': 'linear', 'size': 9, 'unit': 'aa'}}, None, Protein) self.single_rna_fp = get_data_path('genbank_single_record') imd = IntervalMetadata(63) imd.add([(0, 63)], [(False, False)], {'db_xref': '"taxon:562"', 'mol_type': '"mRNA"', 'organism': '"Escherichia coli"', 'type': 'source', 'strand': '+', '__location': '1..63'}) imd.add([(0, 63)], [(False, True)], {'phase': 0, 'db_xref': ['"taxon:562"', '"taxon:561"'], '__location': '1..>63', 'strand': '+', 'note': '"alkaline phosphatase signal peptide"', 'protein_id': '"AAA23431.1"', 'transl_table': '11', 'translation': '"MKQSTIALAVLPLLFTPVTKA"', 'type': 'CDS'}) self.single_rna = ( 'gugaaacaaagcacuauugcacuggcugucuuaccguuacuguuuaccccugugacaaaagcc', {'ACCESSION': 'M14399', 'COMMENT': 'Original source text: E.coli, cDNA to mRNA.', 'DEFINITION': "alkaline phosphatase signal mRNA, 5' end.", 'KEYWORDS': 'alkaline phosphatase; signal peptide.', 'LOCUS': {'date': '26-APR-1993', 'division': 'BCT', 'locus_name': 'ECOALKP', 'mol_type': 'mRNA', 'shape': 'linear', 'size': 63, 'unit': 'bp'}, 'SOURCE': {'ORGANISM': 'Escherichia coli', 'taxonomy': 'Bacteria; Proteobacteria; ' 'Gammaproteobacteria; Enterobacteriales; ' 'Enterobacteriaceae; Escherichia.'}, 'VERSION': 'M14399.1'}, imd, RNA) # test: # 1. multiple records in one file # 2. lowercase sequence # 3. DNA, RNA, Protein type # 4. variation of formats self.multi_fp = get_data_path('genbank_multi_records') imd_pro = IntervalMetadata(9) imd_pro.add([(0, 9)], [(False, False)], {'organism': '"Bacteria"', 'type': 'source', 'strand': '+', '__location': '1..9'},) imd_pro.add([(0, 9)], [(False, True)], {'__location': '1..>9', 'product': '"L-carnitine amidase"', 'strand': '+', 'type': 'Protein'}) imd_dna = IntervalMetadata(9) imd_dna.add([(0, 9)], [(False, False)], {'country': '"Brazil: Parana, Paranavai"', 'type': 'source', 'strand': '+', '__location': '1..9', 'environmental_sample': ''}) imd_dna.add([(1, 8)], [(True, True)], {'__location': 'complement(<2..>8)', 'product': '"16S ribosomal RNA"', 'strand': '-', 'type': 'rRNA'}) self.multi = ( ('gsreildfk', {'ACCESSION': 'AAB29917', 'COMMENT': 'Method: direct peptide sequencing.', 'DBSOURCE': 'accession AAB29917.1', 'DEFINITION': 'L-carnitine amidase {N-terminal}', 'KEYWORDS': '.', 'LOCUS': {'date': '23-SEP-1994', 'division': 'BCT', 'locus_name': 'AAB29917', 'mol_type': None, 'shape': 'linear', 'size': 9, 'unit': 'aa'}, 'REFERENCE': [{'AUTHORS': 'Joeres,U. and Kula,M.R.', 'JOURNAL': 'AMB 40 (5), 606-610 (1994)', 'PUBMED': '7764422', 'REFERENCE': '1 (residues 1 to 9)', 'REMARK': 'from the original journal article.', 'TITLE': 'a microbial L-carnitine amidase'}, {'AUTHORS': 'Joeres,U. and Kula,M.R.', 'JOURNAL': 'AMB 40 (5), 606-610 (1994)', 'PUBMED': '7764422', 'REFERENCE': '1 (residues 1 to 9)', 'TITLE': 'a microbial L-carnitine amidase'}], 'SOURCE': {'ORGANISM': 'Bacteria', 'taxonomy': 'Unclassified.'}, 'VERSION': 'AAB29917.1 GI:545426'}, imd_pro, Protein), ('catgcaggc', {'ACCESSION': 'HQ018078', 'DEFINITION': 'Uncultured Xylanimonas sp.16S, partial', 'KEYWORDS': 'ENV.', 'LOCUS': {'date': '29-AUG-2010', 'division': 'ENV', 'locus_name': 'HQ018078', 'mol_type': 'DNA', 'shape': 'linear', 'size': 9, 'unit': 'bp'}, 'SOURCE': {'ORGANISM': 'uncultured Xylanimonas sp.', 'taxonomy': 'Bacteria; Actinobacteria; ' 'Micrococcales; Promicromonosporaceae; ' 'Xylanimonas; environmental samples.'}, 'VERSION': 'HQ018078.1 GI:304421728'}, imd_dna, DNA)) class ReaderTests(GenBankIOTests): def test_parse_reference(self): lines = ''' REFERENCE 1 (bases 1 to 154478) AUTHORS Sato,S., Nakamura,Y., Kaneko,T., and Tabata,S. TITLE Complete structure of the chloroplast genome of Arabidopsis thaliana JOURNAL DNA Res. 6 (5), 283-290 (1999) PUBMED 10574454'''.split('\n') exp = {'AUTHORS': 'Sato,S., Nakamura,Y., Kaneko,T., and Tabata,S.', 'JOURNAL': 'DNA Res. 6 (5), 283-290 (1999)', 'PUBMED': '10574454', 'REFERENCE': '1 (bases 1 to 154478)', 'TITLE': ('Complete structure of the chloroplast genome of' ' Arabidopsis thaliana')} self.assertEqual(_parse_reference(lines), exp) def test_parse_locus(self): for serialized, parsed in self.locus: self.assertEqual(_parse_locus(serialized), parsed) def test_parse_locus_invalid(self): lines = [ # missing unit ['LOCUS NC_005816 9609 ' ' DNA circular CON 07-FEB-2015'], # missing division ['LOCUS SCU49845 5028 bp' ' DNA 21-JUN-1999'], # wrong date format ['LOCUS NP_001832 360 aa' ' linear PRI 2001-12-18']] for line in lines: with self.assertRaisesRegex(GenBankFormatError, r'Could not parse the LOCUS line:.*'): _parse_locus(line) def test_genbank_to_generator_single(self): # test single record and uppercase sequence for c in [Sequence, Protein]: obs = next(_genbank_to_generator( self.single_upper_fp, constructor=c)) exp = c(self.single[0], metadata=self.single[1], positional_metadata=self.single[2]) self.assertEqual(exp, obs) def test_genbank_to_generator(self): for i, obs in enumerate(_genbank_to_generator(self.multi_fp)): seq, md, imd, constructor = self.multi[i] exp = constructor(seq, metadata=md, lowercase=True, interval_metadata=imd) self.assertEqual(exp, obs) def test_genbank_to_sequence(self): for i, exp in enumerate(self.multi): obs = _genbank_to_sequence(self.multi_fp, seq_num=i+1) exp = Sequence(exp[0], metadata=exp[1], lowercase=True, interval_metadata=exp[2]) self.assertEqual(exp, obs) def test_genbank_to_rna(self): seq, md, imd, constructor = self.single_rna obs = _genbank_to_rna(self.single_rna_fp) exp = constructor(seq, metadata=md, lowercase=True, interval_metadata=imd) self.assertEqual(exp, obs) def test_genbank_to_dna(self): i = 1 exp = self.multi[i] obs = _genbank_to_dna(self.multi_fp, seq_num=i+1) exp = DNA(exp[0], metadata=exp[1], lowercase=True, interval_metadata=exp[2]) self.assertEqual(exp, obs) def test_genbank_to_protein(self): i = 0 exp = self.multi[i] obs = _genbank_to_protein(self.multi_fp, seq_num=i+1) exp = Protein(exp[0], metadata=exp[1], lowercase=True, interval_metadata=exp[2]) self.assertEqual(exp, obs) class WriterTests(GenBankIOTests): def test_serialize_locus(self): for serialized, parsed in self.locus: self.assertEqual( _serialize_locus('LOCUS', parsed), serialized[0] + '\n') def test_generator_to_genbank(self): seq, md, imd, constructor = self.single obj = constructor(seq, md, interval_metadata=imd) with io.StringIO() as fh: _generator_to_genbank([obj], fh) obs = fh.getvalue() with open(self.single_lower_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_sequence_to_genbank(self): with io.StringIO() as fh: for i, (seq, md, imd, constructor) in enumerate(self.multi): obj = Sequence(seq, md, interval_metadata=imd, lowercase=True) _sequence_to_genbank(obj, fh) obs = fh.getvalue() with open(self.multi_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_dna_protein_to_genbank(self): writers = [_protein_to_genbank, _dna_to_genbank] with io.StringIO() as fh: for i, (seq, md, imd, constructor) in enumerate(self.multi): obj = constructor( seq, md, interval_metadata=imd, lowercase=True) writers[i](obj, fh) obs = fh.getvalue() with open(self.multi_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_rna_to_genbank(self): with io.StringIO() as fh: seq, md, imd, constructor = self.single_rna obj = constructor(seq, md, interval_metadata=imd, lowercase=True) _rna_to_genbank(obj, fh) obs = fh.getvalue() with open(self.single_rna_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) class RoundtripTests(GenBankIOTests): def test_roundtrip_generator(self): with io.StringIO() as fh: _generator_to_genbank(_genbank_to_generator(self.multi_fp), fh) obs = fh.getvalue() with open(self.multi_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_roundtrip_rna(self): with io.StringIO() as fh: _rna_to_genbank(_genbank_to_rna(self.single_rna_fp), fh) obs = fh.getvalue() with open(self.single_rna_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_roundtrip_dna(self): with io.StringIO() as fh: _dna_to_genbank(_genbank_to_dna(self.single_rna_fp), fh) obs = fh.getvalue() with open(self.single_rna_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_roundtrip_protein(self): with io.StringIO() as fh: _protein_to_genbank(_genbank_to_protein(self.single_lower_fp), fh) obs = fh.getvalue() with open(self.single_lower_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_roundtrip_sequence(self): with io.StringIO() as fh: _sequence_to_genbank(_genbank_to_sequence(self.single_rna_fp), fh) obs = fh.getvalue() with open(self.single_rna_fp) as fh: exp = fh.read() self.assertEqual(obs, exp) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_gff3.py000066400000000000000000000321361520735541300247660ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import io from skbio.util import get_data_path from skbio.metadata import IntervalMetadata from skbio import DNA, Sequence from skbio.io import GFF3FormatError from skbio.io.format.gff3 import (_yield_record, _parse_record, _parse_attr, _gff3_sniffer, _gff3_to_interval_metadata, _interval_metadata_to_gff3, _gff3_to_generator, _generator_to_gff3, _gff3_to_sequence, _sequence_to_gff3, _gff3_to_dna, _dna_to_gff3, _serialize_interval_metadata) class GFF3IOTests(TestCase): def setUp(self): self.multi_fp = get_data_path('gff3_multi_record') self.single_fp = get_data_path('gff3_single_record') intvls = [{'bounds': [(0, 4641652)], 'metadata': {'source': 'European Nucleotide Archive', 'type': 'chromosome', 'score': '.', 'strand': '.', 'ID': 'chromosome:Chromosome', 'Alias': 'U00096.3', 'Is_circular': 'true'}}, {'bounds': [(147, 148)], 'metadata': {'source': 'regulondb_feature', 'type': 'biological_region', 'score': '.', 'strand': '+', 'external_name': 'Promoter thrLp (RegulonDB:ECK120010236)', 'logic_name': 'regulondb_promoter'}}, {'bounds': [(336, 2799)], 'metadata': {'source': 'Prodigal_v2.60', 'type': 'gene', 'score': '1.8', 'strand': '+', 'phase': 0, 'ID': '1_1', 'gc_cont': '0.427'}}, {'bounds': [(336, 2799)], 'metadata': {'source': 'Prodigal_v2.60', 'type': 'CDS', 'score': '333.8', 'strand': '+', 'phase': 0, 'ID': '1_2', 'Parent': '1_1', 'rbs_motif': 'GGAG/GAGG', 'rbs_spacer': '5-10bp'}}, {'bounds': [(0, 50), (55, 100)], 'metadata': {'source': 'Prodigal_v2.60', 'type': 'gene', 'score': '1.8', 'strand': '+', 'phase': 0, 'ID': '1_1', 'gene': 'FXR receptor'}}] self.upper_bound = 4641652 self.imd1 = IntervalMetadata(self.upper_bound) self.imd1.add(**intvls[0]) self.imd1.add(**intvls[1]) self.imd2 = IntervalMetadata(None) self.imd2.add(**intvls[2]) self.imd2.add(**intvls[3]) self.imd3 = IntervalMetadata(None) self.imd3.add(**intvls[4]) self.seq_fp = get_data_path('gff3_dna') self.seq = Sequence('ATGCATGCATGC', metadata={'id': 'NC_1', 'description': 'species X'}) self.seq.interval_metadata.add( [(0, 9)], metadata={'source': 'Prodigal_v2.60', 'type': 'gene', 'score': '.', 'strand': '+', 'phase': 0, 'ID': 'gene1', 'Name': 'FXR'}) self.dna = DNA(self.seq) class SnifferTests(TestCase): def setUp(self): self.positive_fps = map(get_data_path, [ 'gff3_multi_record', 'gff3_single_record', 'gff3_dna']) self.negative_fps = map(get_data_path, [ 'empty', 'whitespace_only', 'gff3_bad_missing_directive']) def test_positive(self): for fp in self.positive_fps: self.assertEqual(_gff3_sniffer(fp), (True, {})) def test_negative(self): for fp in self.negative_fps: self.assertEqual(_gff3_sniffer(fp), (False, {})) class ReaderTests(GFF3IOTests): def test_parse_attr(self): s = 'Dbxref=GO:000152,GO:001234;Note=fooo' obs = _parse_attr(s) exp = {'db_xref': 'GO:000152,GO:001234', 'note': 'fooo'} self.assertEqual(exp, obs) def test_yield_record(self): obs = [('data', 'seqid1', ['seqid1\txxx', 'seqid1\tyyy']), ('data', 'seqid2', ['seqid2\tzzz'])] s = ('seqid1\txxx\n' 'seqid1\tyyy\n' 'seqid2\tzzz\n') fh = io.StringIO(s) for i, j in zip(_yield_record(fh), obs): self.assertEqual(i, j) def test_parse_record_raise(self): chars = 'abc?!' for char in chars: lines = [ 'ctg123\t.\tgene\t1000\t9000\t.\t+\t%s\tID=gene00001' % char] with self.assertRaisesRegex( GFF3FormatError, r"unknown value for phase column: '%s'" % char): _parse_record(lines, 10000) def test_yield_record_raise(self): s = '##gff-version 3\nseq_1 . gene 1 3 . + . ID=gene01\n' with io.StringIO(s) as fh: with self.assertRaises(GFF3FormatError): list(_yield_record(fh)) def test_gff3_to_interval_metadata(self): obs = _gff3_to_interval_metadata( self.single_fp, seq_id='Chromosome') self.assertEqual(obs, self.imd1) def test_gff3_to_interval_metadata_empty(self): exp = IntervalMetadata(None) obs = _gff3_to_interval_metadata( # the seq id does not exist self.single_fp, seq_id='foo') self.assertEqual(obs, exp) def test_gff3_to_interval_metadata_bad(self): with self.assertRaisesRegex(GFF3FormatError, r'do not have 9 columns in this line'): _gff3_to_interval_metadata( get_data_path('gff3_bad_wrong_columns'), seq_id='Chromosome') def test_gff3_to_generator(self): exps = [('Chromosome', self.imd1), ('gi|556503834|ref|NC_000913.3|', self.imd2)] obss = _gff3_to_generator(self.multi_fp) for obs, exp in zip(obss, exps): self.assertEqual(obs, exp) def test_gff3_to_generator_empty(self): empty_fps = map(get_data_path, ['empty', 'whitespace_only']) for empty_fp in empty_fps: obs = list(_gff3_to_generator(empty_fp)) self.assertEqual(obs, []) def test_gff3_to_sequence(self): obs = _gff3_to_sequence(self.seq_fp) self.assertEqual(obs, self.seq) def test_gff3_to_dna(self): obs = _gff3_to_dna(self.seq_fp) self.assertEqual(obs, self.dna) class WriterTests(GFF3IOTests): def test_interval_metadata_to_gff3(self): with io.StringIO() as fh: _interval_metadata_to_gff3(self.imd1, fh, seq_id='Chromosome') # only compare the uncommented lines because the comments are not # stored in IntervalMetadata obs = [i for i in fh.getvalue().splitlines() if not i.startswith('#')] with open(self.single_fp) as f: exp = [i.rstrip() for i in f.readlines() if not i.startswith('#')] self.assertEqual(obs, exp) def test_interval_metadata_to_gff3_missing_field(self): exp = 'ctg123\t.\tgene\t1\t9\t.\t.\t.\tID=gene00001;Name=EDEN' imd = IntervalMetadata(9) imd.add([(0, 9)], metadata={ 'type': 'gene', 'ID': 'gene00001', 'Name': 'EDEN'}) with io.StringIO() as fh: _interval_metadata_to_gff3(imd, fh, seq_id='ctg123') # only compare the uncommented lines because the comments are not # stored in IntervalMetadata obs = [i for i in fh.getvalue().splitlines() if not i.startswith('#')] self.assertEqual([exp], obs) def test_interval_metadata_to_gff3_escape(self): # test escape of reserved char in GFF3 exp = 'ctg123\t.\tgene\t1\t9\t.\t.\t.\tID=a%3B%3D%26%2Cb' imd = IntervalMetadata(9) imd.add([(0, 9)], metadata={ 'type': 'gene', 'ID': 'a;=&,b'}) with io.StringIO() as fh: _interval_metadata_to_gff3(imd, fh, seq_id='ctg123') # only compare the uncommented lines because the comments are not # stored in IntervalMetadata obs = [i for i in fh.getvalue().splitlines() if not i.startswith('#')] self.assertEqual([exp], obs) def test_interval_metadata_to_gff3_multiple_values(self): # test multiple values of db_xref are correctly serialized exp = 'ctg123\t.\tgene\t1\t9\t.\t.\t.\tDbxref=GO:000152,GO:001234' imd = IntervalMetadata(9) imd.add([(0, 9)], metadata={ 'type': 'gene', 'db_xref': ['GO:000152', 'GO:001234']}) with io.StringIO() as fh: _interval_metadata_to_gff3(imd, fh, seq_id='ctg123') # only compare the uncommented lines because the comments are not # stored in IntervalMetadata obs = [i for i in fh.getvalue().splitlines() if not i.startswith('#')] self.assertEqual([exp], obs) def test_interval_metadata_to_gff3_empty(self): imd = IntervalMetadata(None) with io.StringIO() as fh: _interval_metadata_to_gff3(imd, fh, seq_id='foo') obs = fh.getvalue() self.assertEqual(obs, '##gff-version 3\n') def test_interval_metadata_to_gff3_sub_region(self): seq_id = 'NC 7' with open(self.multi_fp) as f: exp = [i.strip() for i in f if i.startswith(seq_id)] with io.StringIO() as fh: _serialize_interval_metadata( self.imd3, seq_id=seq_id, fh=fh, skip_subregion=False) obs = [i for i in fh.getvalue().splitlines() if not i.startswith('#')] self.assertEqual(exp, obs) with io.StringIO() as fh: _serialize_interval_metadata(self.imd3, seq_id=seq_id, fh=fh) obs = [i for i in fh.getvalue().splitlines() if not i.startswith('#')] # all the rest lines except the 1st are sub-region lines, so only # compare the first line from exp self.assertEqual(exp[:1], obs) def test_sequence_to_gff3(self): with io.StringIO() as fh: _sequence_to_gff3(self.seq, fh) obs = fh.getvalue() with open(self.seq_fp) as fh: exp = fh.read() self.assertEqual(exp, obs) def test_dna_to_gff3(self): with io.StringIO() as fh: _dna_to_gff3(self.dna, fh) obs = fh.getvalue() with open(self.seq_fp) as fh: exp = fh.read() self.assertEqual(exp, obs) def test_raise_subregion(self): im = IntervalMetadata(None) im.add([(0, 3), (7, 9)], metadata={'type': 'gene'}) with io.StringIO() as fh: with self.assertRaises(GFF3FormatError): _serialize_interval_metadata( im, seq_id='a', fh=fh, skip_subregion=False) class RoundtripTests(GFF3IOTests): def test_roundtrip_interval_metadata(self): '''''' with io.StringIO() as fh: _interval_metadata_to_gff3( _gff3_to_interval_metadata( self.single_fp, seq_id='Chromosome'), fh, seq_id='Chromosome') obs = [i for i in fh.getvalue().splitlines() if not i.startswith('#')] with open(self.single_fp) as f: exp = [i.rstrip() for i in f.readlines() if not i.startswith('#')] self.assertEqual(obs, exp) def test_roundtrip_interval_metadata_generator(self): with io.StringIO() as fh: _generator_to_gff3( _gff3_to_generator(self.multi_fp), fh, skip_subregion=False) obs = [i for i in fh.getvalue().splitlines() if not i.startswith('#')] with open(self.multi_fp) as f: exp = [i.rstrip() for i in f.readlines() if not i.startswith('#')] self.assertEqual(obs, exp) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_lsmat.py000066400000000000000000000302201520735541300252510ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from unittest import TestCase, main import numpy as np from skbio import DistanceMatrix from skbio.io import LSMatFormatError from skbio.io.format.lsmat import ( _lsmat_to_pairwise_matrix, _lsmat_to_distance_matrix, _lsmat_to_symmetric_matrix, _pairwise_matrix_to_lsmat, _distance_matrix_to_lsmat, _symmetric_matrix_to_lsmat, _lsmat_sniffer) from skbio.stats.distance import PairwiseMatrix, SymmetricMatrix, DistanceMatrixError class LSMatTestData(TestCase): def setUp(self): self.lsmat_1x1_fh = io.StringIO(LSMat_1x1) self.lsmat_2x2_fh = io.StringIO(LSMat_2x2) self.lsmat_2x2_asym_fh = io.StringIO(LSMat_2x2_ASYM) self.lsmat_3x3_fh = io.StringIO(LSMat_3x3) self.lsmat_3x3_whitespace_fh = io.StringIO(LSMat_3x3_WHITESPACE) self.lsmat_3x3_csv_fh = io.StringIO(LSMat_3x3_CSV) self.lsmat_3x3_fw_fh = io.StringIO(LSMat_3x3_FW) self.valid_fhs = [ self.lsmat_1x1_fh, self.lsmat_2x2_fh, self.lsmat_2x2_asym_fh, self.lsmat_3x3_fh, self.lsmat_3x3_whitespace_fh, ] self.empty_fh = io.StringIO() self.invalid_1_fh = io.StringIO(INVALID_1) self.invalid_2_fh = io.StringIO(INVALID_2) self.invalid_3_fh = io.StringIO(INVALID_3) self.invalid_4_fh = io.StringIO(INVALID_4) self.invalid_5_fh = io.StringIO(INVALID_5) self.invalid_6_fh = io.StringIO(INVALID_6) self.invalid_fhs = [ (self.empty_fh, r'empty'), (self.invalid_1_fh, r'1 value\(s\).*2.*\(2\)'), (self.invalid_2_fh, r"'b'.*'a'"), (self.invalid_3_fh, r'extra row\(s\)'), (self.invalid_4_fh, r'2 row\(s\).*found 1'), (self.invalid_5_fh, r'2 row\(s\).*found 0'), (self.invalid_6_fh, r"delimiter '\\t'") ] class PairwiseAndDistanceMatrixReaderWriterTests(LSMatTestData): def setUp(self): super(PairwiseAndDistanceMatrixReaderWriterTests, self).setUp() self.lsmat_1x1_data = [[0.0]] self.lsmat_2x2_data = [[0.0, 0.123], [0.123, 0.0]] self.lsmat_2x2_asym_data = [[0.0, 1.0], [-2.0, 0.0]] self.lsmat_3x3_data = [[0.0, 0.01, 4.2], [0.01, 0.0, 12.0], [4.2, 12.0, 0.0]] # We repeat the 3x3 example because there are two file format # representations of it, one that is messy and one that is not. Both # should be read into an equivalent object and written to an equivalent # format though, which is why we duplicate the 3x3 objects and strings. self.dissim_objs = [ PairwiseMatrix(self.lsmat_1x1_data, ['a']), PairwiseMatrix(self.lsmat_2x2_data, ['a', 'b']), PairwiseMatrix(self.lsmat_2x2_asym_data, ['a', 'b']), PairwiseMatrix(self.lsmat_3x3_data, ['a', 'b', 'c']), PairwiseMatrix(self.lsmat_3x3_data, ['a', 'b', 'c']) ] self.dissim_strs = [LSMat_1x1, LSMat_2x2, LSMat_2x2_ASYM, LSMat_3x3, LSMat_3x3] self.dissim_fhs = [self.lsmat_1x1_fh, self.lsmat_2x2_fh, self.lsmat_2x2_asym_fh, self.lsmat_3x3_fh, self.lsmat_3x3_whitespace_fh] self.dist_objs = [ DistanceMatrix(self.lsmat_1x1_data, ['a']), DistanceMatrix(self.lsmat_2x2_data, ['a', 'b']), DistanceMatrix(self.lsmat_3x3_data, ['a', 'b', 'c']), DistanceMatrix(self.lsmat_3x3_data, ['a', 'b', 'c']) ] self.sym_objs = [ SymmetricMatrix(self.lsmat_1x1_data, ['a']), SymmetricMatrix(self.lsmat_2x2_data, ['a', 'b']), SymmetricMatrix(self.lsmat_3x3_data, ['a', 'b', 'c']), SymmetricMatrix(self.lsmat_3x3_data, ['a', 'b', 'c']) ] self.dist_strs = [LSMat_1x1, LSMat_2x2, LSMat_3x3, LSMat_3x3] self.dist_fhs = [self.lsmat_1x1_fh, self.lsmat_2x2_fh, self.lsmat_3x3_fh, self.lsmat_3x3_whitespace_fh] def test_read_valid_files(self): for fn, cls, objs, fhs in ((_lsmat_to_pairwise_matrix, PairwiseMatrix, self.dissim_objs, self.dissim_fhs), (_lsmat_to_distance_matrix, DistanceMatrix, self.dist_objs, self.dist_fhs), (_lsmat_to_symmetric_matrix, SymmetricMatrix, self.sym_objs, self.dist_fhs)): for fh, obj in zip(fhs, objs): fh.seek(0) obs = fn(fh) self.assertEqual(obs, obj) self.assertIsInstance(obs, cls) # Above files are TSV (default delimiter). Test that CSV works too. for fn, cls in ((_lsmat_to_pairwise_matrix, PairwiseMatrix), (_lsmat_to_distance_matrix, DistanceMatrix), (_lsmat_to_symmetric_matrix, SymmetricMatrix)): exp = cls(self.lsmat_3x3_data, ['a', 'b', 'c']) self.lsmat_3x3_csv_fh.seek(0) obs = fn(self.lsmat_3x3_csv_fh, delimiter=',') self.assertEqual(obs, exp) self.assertIsInstance(obs, cls) # Test that fixed-width works too. for fn, cls in ((_lsmat_to_pairwise_matrix, PairwiseMatrix), (_lsmat_to_distance_matrix, DistanceMatrix), (_lsmat_to_symmetric_matrix, SymmetricMatrix)): exp = cls(self.lsmat_3x3_data, ['a', 'b', 'c']) self.lsmat_3x3_fw_fh.seek(0) obs = fn(self.lsmat_3x3_fw_fh, delimiter=None) self.assertEqual(obs, exp) self.assertIsInstance(obs, cls) def test_read_dtype(self): fn = _lsmat_to_distance_matrix fh = self.lsmat_3x3_fw_fh data = self.lsmat_3x3_data # float64 (default) exp = DistanceMatrix(data, ['a', 'b', 'c']) fh.seek(0) obs = fn(fh, delimiter=None) self.assertEqual(obs.dtype, np.float64) self.assertEqual(obs, exp) for dtype in (None, float, np.float64, "float64"): fh.seek(0) obs = fn(fh, delimiter=None, dtype=dtype) self.assertEqual(obs.dtype, np.float64) self.assertEqual(obs, exp) # float32 exp = DistanceMatrix(np.asarray(data, dtype="float32"), ['a', 'b', 'c']) for dtype in (np.float32, "float32"): fh.seek(0) obs = fn(fh, delimiter=None, dtype=dtype) self.assertEqual(obs.dtype, np.float32) self.assertEqual(obs, exp) # invalid data type for dtype in ("xyz", int, "float16", "uint8", np.float16): fh.seek(0) self.assertRaises(TypeError, fn, fh, delimiter=None, dtype=dtype) def test_read_invalid_files(self): for fn in _lsmat_to_pairwise_matrix, _lsmat_to_distance_matrix, _lsmat_to_symmetric_matrix: for invalid_fh, error_msg_regexp in self.invalid_fhs: with self.assertRaisesRegex(LSMatFormatError, error_msg_regexp): invalid_fh.seek(0) fn(invalid_fh) # Asymmetric data only raises an error for DistanceMatrix. with self.assertRaises(DistanceMatrixError): _lsmat_to_distance_matrix(self.lsmat_2x2_asym_fh) def test_write(self): for fn, objs, strs in ((_pairwise_matrix_to_lsmat, self.dissim_objs, self.dissim_strs), (_distance_matrix_to_lsmat, self.dist_objs, self.dist_strs), (_symmetric_matrix_to_lsmat, self.dist_objs, self.dist_strs)): for obj, str_ in zip(objs, strs): fh = io.StringIO() fn(obj, fh) obs = fh.getvalue() fh.close() self.assertEqual(obs, str_) # Test writing CSV (TSV is written above). for fn, cls in ((_pairwise_matrix_to_lsmat, PairwiseMatrix), (_distance_matrix_to_lsmat, DistanceMatrix), (_symmetric_matrix_to_lsmat, SymmetricMatrix)): obj = cls(self.lsmat_3x3_data, ['a', 'b', 'c']) fh = io.StringIO() fn(obj, fh, delimiter=',') obs = fh.getvalue() fh.close() self.assertEqual(obs, LSMat_3x3_CSV) def test_roundtrip_read_write(self): for reader_fn, writer_fn, fhs in ((_lsmat_to_pairwise_matrix, _pairwise_matrix_to_lsmat, self.dissim_fhs), (_lsmat_to_distance_matrix, _distance_matrix_to_lsmat, self.dist_fhs), (_lsmat_to_symmetric_matrix, _symmetric_matrix_to_lsmat, self.dist_fhs)): for fh in fhs: # Read. fh.seek(0) lsmat1 = reader_fn(fh) # Write. out_fh = io.StringIO() writer_fn(lsmat1, out_fh) out_fh.seek(0) # Read. lsmat2 = reader_fn(out_fh) out_fh.close() self.assertEqual(lsmat1, lsmat2) class SnifferTests(LSMatTestData): def setUp(self): super(SnifferTests, self).setUp() def test_match_tsv(self): # Sniffer should match all valid files, and will match some invalid # ones too because it doesn't exhaustively check the entire file. fhs = self.valid_fhs + [self.invalid_1_fh, self.invalid_3_fh, self.invalid_4_fh] for fh in fhs: self.assertEqual(_lsmat_sniffer(fh), (True, {'delimiter': '\t'})) def test_match_csv(self): self.assertEqual(_lsmat_sniffer(self.lsmat_3x3_csv_fh), (True, {'delimiter': ','})) def test_match_fw(self): self.assertEqual(_lsmat_sniffer(self.lsmat_3x3_fw_fh), (True, {'delimiter': None})) def test_no_match(self): for fh in (self.empty_fh, self.invalid_2_fh, self.invalid_5_fh, self.invalid_6_fh): self.assertEqual(_lsmat_sniffer(fh), (False, {})) LSMat_1x1 = ( '\ta\n' 'a\t0.0\n') LSMat_2x2 = ( '\ta\tb\n' 'a\t0.0\t0.123\n' 'b\t0.123\t0.0\n') LSMat_2x2_ASYM = ( '\ta\tb\n' 'a\t0.0\t1.0\n' 'b\t-2.0\t0.0\n') LSMat_3x3 = ( '\ta\tb\tc\n' 'a\t0.0\t0.01\t4.2\n' 'b\t0.01\t0.0\t12.0\n' 'c\t4.2\t12.0\t0.0\n') # Extra whitespace-only lines throughout. Also has comments before the header. LSMat_3x3_WHITESPACE = '\n'.join([ '# foo', ' \t \t ', ' #bar', '', '', '\ta\t b \tc', 'a \t0.0\t0.01\t4.2', ' \t', 'b\t0.01\t0.0\t12.0', '', '\t \t', '', 'c\t4.2\t12.0\t0.0', '', ' \t ', '\t\t\t', ' ']) # Same matrix as above, but delimited by commas instead of tabs. LSMat_3x3_CSV = ( ',a,b,c\n' 'a,0.0,0.01,4.2\n' 'b,0.01,0.0,12.0\n' 'c,4.2,12.0,0.0\n') # Same matrix as above, but delimited by whitespaces instead of tabs. LSMat_3x3_FW = ( ' a b c \n' 'a 0.0 0.01 4.2 \n' 'b 0.01 0.0 12.0 \n' 'c 4.2 12.0 0.0 \n') # missing data INVALID_1 = '\ta\tb\na\t0\t1\nb\t1' # mismatched IDs INVALID_2 = '\ta\tb\nb\t0\t1\na\t1\t0' # extra data lines INVALID_3 = '\ta\tb\na\t0\t1\nb\t1\t0\n \nfoo\n\n\n' # missing data lines INVALID_4 = '\ta\tb\na\t0\t1\n \n' # no data lines INVALID_5 = '\ta\tb\n' # missing leading delimiter in header INVALID_6 = "a\tb\na\t0.0\t0.123\nb\t0.123\t0.0\n" if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_newick.py000066400000000000000000000304621520735541300254210ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io import unittest from skbio import TreeNode from skbio.io import NewickFormatError from skbio.io.format.newick import ( _newick_to_tree_node, _tree_node_to_newick, _newick_sniffer) class TestNewick(unittest.TestCase): def _assert_node_equal(self, n1, n2): self.assertEqual(n1.name, n2.name) self.assertEqual(n1.length, n2.length) self.assertEqual(len(n1.children), len(n2.children)) def _assert_equal(self, n1, n2): def name(x): return (str(x.name), float(x.length) if x.length is not None else 0, len(x.children)) self._assert_node_equal(n1, n2) for c1, c2 in zip(sorted(n1.children, key=name), sorted(n2.children, key=name)): self.assertTrue(c1.parent is n1) self.assertTrue(c2.parent is n2) self._assert_equal(c1, c2) def _setup_tree(self, kwargs_list): trees = [] for kwargs in kwargs_list: trees.append(TreeNode(**kwargs)) trees[4].extend([trees[2], trees[3]]) trees[5].extend([trees[0], trees[1], trees[4]]) return trees[5] def _setup_linked_list(self, kwargs_list): last_node = None for idx, kwargs in enumerate(kwargs_list): new_node = TreeNode(**kwargs) if last_node is not None: new_node.append(last_node) last_node = new_node return last_node def _setup_balanced_binary(self, kwargs_list): trees = [] for kwargs in kwargs_list: trees.append(TreeNode(**kwargs)) trees[0].extend([trees[2], trees[3]]) trees[1].extend([trees[4], trees[5]]) trees[6].extend([trees[0], trees[1]]) return trees[6] def setUp(self): # Using the factory functions above, we will construct different tree # instances. Each tree is expected to serialize to the first newick # string in the list. Each string in the list is expected to # deserialize into an equivilent rotation of the constructed instance. tree_blank = (self._setup_tree([ {}, {}, {}, {}, {}, {} ]), [ "(,,(,));\n", "(,(,),);", "((,),,);", " ((,[ this is a comment ]) , , ) ; ", "((,[ i_can_do_this[0] or escape unmatched '[ ]),[more words],);", ]) tree_leaves_named = (self._setup_tree([ {'name': 'a_'}, {'name': 'b'}, {'name': 'c'}, {'name': 'd'}, {}, {} ]), [ "('a_',b,(c,d));\n", "(b,(c,d),'a_');", "(b\n,'a_'\n ,(d \t,c) ) ;", ]) tree_all_named = (self._setup_tree([ {'name': 'a'}, {'name': 'b'}, {'name': 'c'}, {'name': '[whaaat!\']'}, {'name': 'e'}, {'name': 'f'} ]), [ "(a,b,(c,'[whaaat!'']')e)f;\n", "(b,(c,'[whaaat!'']')e,a)f;", "(b,[comment] \na,('[whaaat!'']',c)e)f;", ]) tree_all_but_root_distances = (self._setup_tree([ {'length': 0.1}, {'length': 0.2}, {'length': 0.3}, {'length': 0.4}, {'length': 0.5}, {} ]), [ "(:0.1,:0.2,(:0.3,:0.4):0.5);\n", "(:0.2,(:0.3,:0.4):0.5,:0.1);", "(:0.2,:0.1,(:0.4,:0.3):0.5);", ]) tree_all_distances = (self._setup_tree([ {'length': 0.1}, {'length': 0.2}, {'length': 0.3}, {'length': 0.4}, {'length': 0.5}, {'length': 0.0} ]), [ "(:0.1,:0.2,(:0.3,:0.4):0.5):0.0;\n", "(:0.2,(:0.3,:0.4):0.5,:0.1):0.0;", "(:0.2,\n:0.1,(:0.4,\n:0.3):0.5)\n:0.0;", ]) tree_all_leaves_named_with_distances = (self._setup_tree([ {'name': 'a', 'length': 0.1}, {'name': 'b_a\'', 'length': 0.2}, {'name': 'c', 'length': 0.3}, {'name': 'de d', 'length': 0.4}, {'length': 0.5}, {'length': 0.0} ]), [ "(a:0.1,'b_a''':0.2,(c:0.3,de_d:0.4):0.5):0.0;\n", "('b_a''':0.2,(c:0.3,'de d':0.4):0.5,a:0.1):0.0;", "('b_a''':0.2,a:0.1,('de d'[why not]:0.4,c:0.3):0.5):0.0;", ]) tree_all_leaves_named_with_distances_no_root = (self._setup_tree([ {'name': 'a', 'length': 0.1}, {'name': 'b_a\'', 'length': 0.2}, {'name': 'c', 'length': 0.3}, {'name': 'de d', 'length': 0.4}, {'length': 0.5}, {} ]), [ "(a:0.1,'b_a''':0.2,(c:0.3,de__d:0.4):0.5);\n", "('b_a''':0.2\n[comment ahoy]\n,(c:0.3,'de d':0.4):0.5,a:0.1);", "('b_a''':0.2,a:0.1,(de__d:0.4,c:0.3):0.5);" ]) tree_all = (self._setup_tree([ {'name': 'a', 'length': 0.1}, {'name': 'b_a\'', 'length': 0.2}, {'name': 'c', 'length': 0.3}, {'name': 'de\' d', 'length': 0.4}, {'name': 'e', 'length': 0.5}, {'name': 'f', 'length': 0.0} ]), [ "(a:0.1,'b_a''':0.2,(c:0.3,de''_d:0.4)e:0.5)f:0.0;\n", "('b_a''':0.2,(c:0.3,de''_d:0.4)e:0.5,a:0.1)f:0.0;", "((de''_d:0.4, c:0.3)e:0.5, 'b_a''':0.2, a:0.1)f:0.0;" ]) balanced_blank = (self._setup_balanced_binary([ {}, {}, {}, {}, {}, {}, {} ]), [ "((,),(,));\n", ]) balanced_named = (self._setup_balanced_binary([ {'name': 'a'}, {'name': 'b'}, {'name': 'c'}, {'name': 'd'}, {'name': 'e'}, {'name': 'f'}, {'name': 'g'} ]), [ "((c,d)a,(e,f)b)g;\n", ]) balanced_distances = (self._setup_balanced_binary([ {'length': 1.0}, {'length': 2.0}, {'length': 3.0}, {'length': 4.0}, {'length': 5.0}, {'length': 6.0}, {'length': 0.0} ]), [ "((:3.0,:4.0):1.0,(:5.0,:6.0):2.0):0.0;\n", ]) blanaced_all = (self._setup_balanced_binary([ {'name': 'a', 'length': 1.0}, {'name': 'b', 'length': 2.0}, {'name': 'c', 'length': 3.0}, {'name': 'd', 'length': 4.0}, {'name': 'e', 'length': 5.0}, {'name': 'f:f\'f', 'length': 6.0}, {'name': 'g', 'length': 0.0} ]), [ "((c:3.0,d:4.0)a:1.0,(e:5.0,'f:f''f':6.0)b:2.0)g:0.0;\n", ]) linked_list_blank = (self._setup_linked_list([ {}, {}, {}, {}, {} ]), [ "(((())));\n", "[(((())));](((())));", "[[(((())));](((())));](((())));\t\t\n" ]) linked_list_named = (self._setup_linked_list([ {'name': 'aaa'}, {'name': 'b_a\''}, {'name': 'c'}, {'name': 'de d'}, {'name': 'e'}, ]), [ "((((aaa)'b_a''')c)de_d)e;\n" ]) inked_list_distances = (self._setup_linked_list([ {'length': 0.4}, {'length': 0.3}, {'length': 0.2}, {'length': 0.1}, {'length': 0.0}, ]), [ "((((:0.4):0.3):0.2):0.1):0.0;\n", "((((:0.4)[not a label]:0.3):0.2):0.1):0.0;\t\t\n" ]) linked_list_all = (self._setup_linked_list([ {'name': 'a', 'length': 0.4}, {'name': 'b_a\'', 'length': 0.3}, {'name': 'c', 'length': 0.2}, {'name': 'de d', 'length': 0.1}, {'name': 'eee', 'length': 0.0}, ]), [ "((((a:0.4)'b_a''':0.3)c:0.2)de_d:0.1)eee:0.0;\n" ]) single_empty = (TreeNode(), [";\n", "[comment about the root" " and its properties];"]) single_named = (TreeNode(name='athing'), ["athing;\n"]) single_distance = (TreeNode(length=200.0), [":200.0;\n"]) single_all = (TreeNode(name='[a]', length=200.0), ["'[a]':200.0;\n"]) self.trees_newick_lists = [ tree_blank, tree_leaves_named, tree_all_named, tree_all_but_root_distances, tree_all_distances, tree_all_leaves_named_with_distances, tree_all_leaves_named_with_distances_no_root, tree_all, balanced_blank, balanced_named, balanced_distances, blanaced_all, linked_list_blank, linked_list_named, inked_list_distances, linked_list_all, single_empty, single_named, single_distance, single_all ] # Invalid newick strings and list of error fragments that should be # a part of the error message when read. self.invalid_newicks = [ ("", ['root']), ("This is not a newick file.", ['whitespace', 'label']), ("((();", ['Parenthesis', 'unbalanced']), ("(,,,)(,);\n", ['unnested', 'children']), ("(()());", ['unnested', 'children']), ("(():,,)", ['length']), ("[][[]('comment is the gotcha':0.2,,);", ['unbalanced', 'root']), ("#SampleID\tHeaderA\tHeaderB\n0\t'yellow'\t0.45;", ['whitespace', 'label']), ("))();", ['Parenthesis', 'unbalanced']), ("((,,),((,,));", ['Parenthesis', 'unbalanced']), ("\n".join([",".join(str(i) for i in range(100)) for _ in range(100)]), ['whitespace', 'label']) ] def test_newick_to_tree_node_valid_files(self): for tree, newicks in self.trees_newick_lists: for newick in newicks: fh = io.StringIO(newick) read_tree = _newick_to_tree_node(fh) self._assert_equal(tree, read_tree) fh.close() def test_newick_to_tree_node_invalid_files(self): for invalid, error_fragments in self.invalid_newicks: fh = io.StringIO(invalid) with self.assertRaises(NewickFormatError) as cm: _newick_to_tree_node(fh) for frag in error_fragments: self.assertIn(frag, str(cm.exception)) fh.close() def test_tree_node_to_newick(self): for tree, newicks in self.trees_newick_lists: newick = newicks[0] fh = io.StringIO() _tree_node_to_newick(tree, fh) self.assertEqual(newick, fh.getvalue()) fh.close() def test_roundtrip(self): for tree, newicks in self.trees_newick_lists: newick = newicks[0] fh = io.StringIO(newick) tree = _newick_to_tree_node(fh) fh2 = io.StringIO() _tree_node_to_newick(tree, fh2) fh2.seek(0) tree2 = _newick_to_tree_node(fh2) self.assertEqual(newick, fh2.getvalue()) self._assert_equal(tree, tree2) fh.close() fh2.close() def test_newick_to_tree_node_convert_underscores(self): fh = io.StringIO('(_:0.1, _a, _b)__;') tree = _newick_to_tree_node(fh, convert_underscores=False) fh2 = io.StringIO() _tree_node_to_newick(tree, fh2) self.assertEqual(fh2.getvalue(), "('_':0.1,'_a','_b')'__';\n") fh2.close() fh.close() def test_newick_sniffer_valid_files(self): for _, newicks in self.trees_newick_lists: for newick in newicks: fh = io.StringIO(newick) self.assertEqual(_newick_sniffer(fh), (True, {})) fh.close() def test_newick_sniffer_invalid_files(self): for invalid, _ in self.invalid_newicks: fh = io.StringIO(invalid) self.assertEqual(_newick_sniffer(fh), (False, {})) fh.close() if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_ordination.py000066400000000000000000000353371520735541300263150ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from unittest import TestCase, main import numpy as np import pandas as pd import numpy.testing as npt from skbio import OrdinationResults from skbio.io import OrdinationFormatError from skbio.io.format.ordination import ( _ordination_to_ordination_results, _ordination_results_to_ordination, _ordination_sniffer) from skbio.util import get_data_path, assert_ordination_results_equal, assert_ordination_results_equal_np from skbio._config import set_config class OrdinationTestData(TestCase): def setUp(self): self.valid_fps = map( get_data_path, ['ordination_L&L_CA_data_scores', 'ordination_example3_scores', 'ordination_PCoA_sample_data_3_scores', 'ordination_example2_scores']) # Store filepath, regex for matching the error message that should be # raised when reading the file, and whether the file should be matched # by the sniffer (True) or not (False). self.invalid_fps = map(lambda e: (get_data_path(e[0]), e[1], e[2]), [ ('empty', r'end of file.*Eigvals header', False), ('whitespace_only', r'Eigvals header not found', False), ('ordination_error1', r'Eigvals header not found', False), ('ordination_error2', r'Proportion explained header not found', False), ('ordination_error3', r'Species header not found', True), ('ordination_error4', r'Site header not found', True), ('ordination_error5', r'Biplot header not found', True), ('ordination_error6', r'Site constraints header not found', True), ('ordination_error7', r'empty line', False), ('ordination_error8', r'9.*Proportion explained.*8', True), ('ordination_error9', r'2 values.*1 in row 1', True), ('ordination_error10', r'2 values.*1 in row 1', True), ('ordination_error11', r'Site constraints ids and site ids', True), ('ordination_error12', r'9.*Eigvals.*8', True), ('ordination_error13', r'9.*Proportion explained.*8', True), ('ordination_error14', r'Site is 0: 9 x 0', True), ('ordination_error15', r'9 values.*8 in row 1', True), ('ordination_error16', r'Biplot is 0: 3 x 0', True), ('ordination_error17', r'3 values.*2 in row 1', True), ('ordination_error18', r'proportion explained.*eigvals: 8 != 9', True), ('ordination_error19', r'coordinates.*species.*eigvals: 1 != 2', True), ('ordination_error20', r'coordinates.*site.*eigvals: 1 != 2', True), ('ordination_error21', r'one eigval', False), ('ordination_error22', r'end of file.*blank line', False), ('ordination_error23', r'end of file.*Proportion explained section', True), ('ordination_error24', r'end of file.*row 2.*Species section', True) ]) class OrdinationResultsReaderWriterTests(OrdinationTestData): def setUp(self): super(OrdinationResultsReaderWriterTests, self).setUp() # define in-memory results, one for each of the valid files in # self.valid_fps # CA results axes_ids = ['CA1', 'CA2'] species_ids = ['Species1', 'Species2', 'Species3'] site_ids = ['Site1', 'Site2', 'Site3'] eigvals = pd.Series([0.0961330159181, 0.0409418140138], axes_ids) species = pd.DataFrame([[0.408869425742, 0.0695518116298], [-0.1153860437, -0.299767683538], [-0.309967102571, 0.187391917117]], index=species_ids, columns=axes_ids) site = pd.DataFrame([[-0.848956053187, 0.882764759014], [-0.220458650578, -1.34482000302], [1.66697179591, 0.470324389808]], index=site_ids, columns=axes_ids) biplot = None site_constraints = None prop_explained = None ca_scores = OrdinationResults( 'CA', 'Correspondence Analysis', eigvals=eigvals, features=species, samples=site, biplot_scores=biplot, sample_constraints=site_constraints, proportion_explained=prop_explained) # CA results, numpy backend axes_ids = ['CA1', 'CA2'] species_ids = ['Species1', 'Species2', 'Species3'] site_ids = ['Site1', 'Site2', 'Site3'] eigvals = np.array([0.0961330159181, 0.0409418140138]) species = np.array([[0.408869425742, 0.0695518116298], [-0.1153860437, -0.299767683538], [-0.309967102571, 0.187391917117]]) site = np.array([[-0.848956053187, 0.882764759014], [-0.220458650578, -1.34482000302], [1.66697179591, 0.470324389808]]) biplot = None site_constraints = None prop_explained = None ca_scores_np = OrdinationResults( 'CA', 'Correspondence Analysis', eigvals=eigvals, features=species, feature_ids=species_ids, samples=site, sample_ids=site_ids, biplot_scores=biplot, sample_constraints=site_constraints, proportion_explained=prop_explained) # CCA results axes_ids = ['CCA%d' % i for i in range(1, 10)] species_ids = ['Species0', 'Species1', 'Species2', 'Species3', 'Species4', 'Species5', 'Species6', 'Species7', 'Species8'] site_ids = ['Site0', 'Site1', 'Site2', 'Site3', 'Site4', 'Site5', 'Site6', 'Site7', 'Site8', 'Site9'] eigvals = pd.Series([0.366135830393, 0.186887643052, 0.0788466514249, 0.082287840501, 0.0351348475787, 0.0233265839374, 0.0099048981912, 0.00122461669234, 0.000417454724117], axes_ids) species = pd.DataFrame(np.loadtxt( get_data_path('ordination_exp_Ordination_CCA_species')), index=species_ids, columns=axes_ids) site = pd.DataFrame( np.loadtxt(get_data_path('ordination_exp_Ordination_CCA_site')), index=site_ids, columns=axes_ids) biplot = pd.DataFrame( [[-0.169746767979, 0.63069090084, 0.760769036049], [-0.994016563505, 0.0609533148724, -0.0449369418179], [0.184352565909, -0.974867543612, 0.0309865007541]], columns=axes_ids[:3]) site_constraints = pd.DataFrame(np.loadtxt( get_data_path('ordination_exp_Ordination_CCA_site_constraints')), index=site_ids, columns=axes_ids) prop_explained = None cca_scores = OrdinationResults('CCA', 'Canonical Correspondence Analysis', eigvals=eigvals, features=species, samples=site, biplot_scores=biplot, sample_constraints=site_constraints, proportion_explained=prop_explained) # CCA results, numpy backend axes_ids = ['CCA%d' % i for i in range(1, 10)] species_ids = ['Species0', 'Species1', 'Species2', 'Species3', 'Species4', 'Species5', 'Species6', 'Species7', 'Species8'] site_ids = ['Site0', 'Site1', 'Site2', 'Site3', 'Site4', 'Site5', 'Site6', 'Site7', 'Site8', 'Site9'] eigvals = np.array([0.366135830393, 0.186887643052, 0.0788466514249, 0.082287840501, 0.0351348475787, 0.0233265839374, 0.0099048981912, 0.00122461669234, 0.000417454724117]) species = np.array(np.loadtxt( get_data_path('ordination_exp_Ordination_CCA_species'))) site = np.array( np.loadtxt(get_data_path('ordination_exp_Ordination_CCA_site'))) biplot = np.array( [[-0.169746767979, 0.63069090084, 0.760769036049], [-0.994016563505, 0.0609533148724, -0.0449369418179], [0.184352565909, -0.974867543612, 0.0309865007541]]) site_constraints = np.array(np.loadtxt( get_data_path('ordination_exp_Ordination_CCA_site_constraints'))) prop_explained = None cca_scores_np = OrdinationResults('CCA', 'Canonical Correspondence Analysis', eigvals=eigvals, features=species, feature_ids=species_ids, sample_ids=site_ids, samples=site, biplot_scores=biplot, sample_constraints=site_constraints, proportion_explained=prop_explained) # PCoA results axes_ids = ['PC%d' % i for i in range(1, 10)] species_ids = None site_ids = ['PC.636', 'PC.635', 'PC.356', 'PC.481', 'PC.354', 'PC.593', 'PC.355', 'PC.607', 'PC.634'] eigvals = pd.Series([0.512367260461, 0.300719094427, 0.267912066004, 0.208988681078, 0.19169895326, 0.16054234528, 0.15017695712, 0.122457748167, 0.0], axes_ids) species = None site = pd.DataFrame( np.loadtxt(get_data_path('ordination_exp_Ordination_PCoA_site')), index=site_ids, columns=axes_ids) biplot = None site_constraints = None prop_explained = pd.Series([0.267573832777, 0.15704469605, 0.139911863774, 0.109140272454, 0.100111048503, 0.0838401161912, 0.0784269939011, 0.0639511763509, 0.0], axes_ids) pcoa_scores = OrdinationResults('PCoA', 'Principal Coordinate Analysis', eigvals=eigvals, features=species, samples=site, biplot_scores=biplot, sample_constraints=site_constraints, proportion_explained=prop_explained) # RDA results axes_ids = ['RDA%d' % i for i in range(1, 8)] species_ids = ['Species0', 'Species1', 'Species2', 'Species3', 'Species4', 'Species5'] site_ids = ['Site0', 'Site1', 'Site2', 'Site3', 'Site4', 'Site5', 'Site6', 'Site7', 'Site8', 'Site9'] eigvals = pd.Series([25.8979540892, 14.9825779819, 8.93784077262, 6.13995623072, 1.68070536498, 0.57735026919, 0.275983624351], axes_ids) species = pd.DataFrame(np.loadtxt( get_data_path('ordination_exp_Ordination_RDA_species')), index=species_ids, columns=axes_ids) site = pd.DataFrame( np.loadtxt(get_data_path('ordination_exp_Ordination_RDA_site')), index=site_ids, columns=axes_ids) biplot = pd.DataFrame( [[0.422650019179, -0.559142585857, -0.713250678211], [0.988495963777, 0.150787422017, -0.0117848614073], [-0.556516618887, 0.817599992718, 0.147714267459], [-0.404079676685, -0.9058434809, -0.127150316558]], columns=axes_ids[:3]) site_constraints = pd.DataFrame(np.loadtxt( get_data_path('ordination_exp_Ordination_RDA_site_constraints')), index=site_ids, columns=axes_ids) prop_explained = None rda_scores = OrdinationResults( 'RDA', 'Redundancy Analysis', eigvals=eigvals, features=species, samples=site, biplot_scores=biplot, sample_constraints=site_constraints, proportion_explained=prop_explained) self.ordination_results_objs = [ca_scores, cca_scores, pcoa_scores, rda_scores] self.ordination_results_objs_np = [ca_scores_np, cca_scores_np] def test_read_valid_files(self): for fp, obj in zip(self.valid_fps, self.ordination_results_objs): obs = _ordination_to_ordination_results(fp) assert_ordination_results_equal( obs, obj, ignore_method_names=True, ignore_axis_labels=True) def test_read_valid_files_np(self): set_config("table_output", "numpy") for fp, obj in zip(self.valid_fps, self.ordination_results_objs_np): obs = _ordination_to_ordination_results(fp) assert_ordination_results_equal_np( obs, obj, ignore_method_names=True ) set_config("table_output", "pandas") def test_read_invalid_files(self): for invalid_fp, error_msg_regexp, _ in self.invalid_fps: with self.assertRaisesRegex(OrdinationFormatError, error_msg_regexp): _ordination_to_ordination_results(invalid_fp) def test_write(self): for fp, obj in zip(self.valid_fps, self.ordination_results_objs): fh = io.StringIO() _ordination_results_to_ordination(obj, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() npt.assert_equal(obs, exp) def test_roundtrip_read_write(self): for fp in self.valid_fps: # Read. obj1 = _ordination_to_ordination_results(fp) # Write. fh = io.StringIO() _ordination_results_to_ordination(obj1, fh) fh.seek(0) # Read. obj2 = _ordination_to_ordination_results(fh) fh.close() assert_ordination_results_equal(obj1, obj2) class SnifferTests(OrdinationTestData): def setUp(self): super(SnifferTests, self).setUp() def test_matches_and_nonmatches(self): # Sniffer should match all valid files, and will match some invalid # ones too because it doesn't exhaustively check the entire file. for fp in self.valid_fps: self.assertEqual(_ordination_sniffer(fp), (True, {})) for fp, _, expected_sniffer_match in self.invalid_fps: self.assertEqual(_ordination_sniffer(fp), (expected_sniffer_match, {})) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_phylip.py000066400000000000000000000254241520735541300254500ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io import unittest from skbio.io import PhylipFormatError from skbio.io.format.phylip import ( _tabular_msa_to_phylip, _phylip_to_tabular_msa, _phylip_sniffer) from skbio import TabularMSA, DNA, RNA from skbio.util import get_data_path class TestSniffer(unittest.TestCase): def setUp(self): self.positives = [get_data_path(e) for e in [ 'phylip_dna_3_seqs', 'phylip_single_seq_long', 'phylip_single_seq_short', 'phylip_single_seq_relaxed', 'phylip_two_chunks', 'phylip_variable_length_ids', 'phylip_varied_whitespace_in_seqs', 'phylip_whitespace_in_header_1', 'phylip_whitespace_in_header_2', 'phylip_whitespace_in_header_3', ]] # negative tests for sniffer don't include # phylip_invalid_empty_line_between_seqs, phylip_invalid_too_few_seqs, # phylip_invalid_too_many_seqs - because sniffer only reads first seq self.negatives = [get_data_path(e) for e in [ 'empty', 'whitespace_only', 'phylip_invalid_empty_line_after_header', 'phylip_invalid_empty_line_before_header', 'phylip_invalid_header_too_long', 'phylip_invalid_header_too_short', 'phylip_invalid_no_header', 'phylip_invalid_seq_too_long', 'phylip_invalid_seq_too_short', 'phylip_invalid_zero_seq_len', 'phylip_invalid_zero_seqs', ]] def test_positives(self): for fp in self.positives: self.assertEqual(_phylip_sniffer(fp), (True, {})) def test_negatives(self): for fp in self.negatives: self.assertEqual(_phylip_sniffer(fp), (False, {})) class TestReaders(unittest.TestCase): def setUp(self): self.valid_configurations = [ ([get_data_path('phylip_dna_3_seqs')], [('..ACC-GTTGG..', 'd1'), ('TTACCGGT-GGCC', 'd2'), ('.-ACC-GTTGC--', 'd3')] ), ([get_data_path('phylip_single_seq_long')], [('..ACC-GTTGG..AATGC.C----', 'foo')] ), ([get_data_path('phylip_single_seq_short')], [('-', '')] ), ([get_data_path('phylip_two_chunks'), get_data_path('phylip_varied_whitespace_in_seqs'), get_data_path('phylip_whitespace_in_header_1'), get_data_path('phylip_whitespace_in_header_2'), get_data_path('phylip_whitespace_in_header_3'), ], [('..ACC-GTTGG..AATGC.C', 'foo'), ('TTACCGGT-GGCCTA-GCAT', 'bar')] ), ([get_data_path('phylip_variable_length_ids')], [('.-ACGT', ''), ('TGCA-.', 'a'), ('.ACGT-', 'bb'), ('TGCA-.', '1'), ('AAAAAA', 'abcdefghij'), ('GGGGGG', 'ab def42ij')] ), ] self.positive_fps = list(map(get_data_path, [ 'phylip_dna_3_seqs', 'phylip_single_seq_long', 'phylip_single_seq_short', 'phylip_two_chunks', 'phylip_variable_length_ids', 'phylip_varied_whitespace_in_seqs', 'phylip_whitespace_in_header_1', 'phylip_whitespace_in_header_2', 'phylip_whitespace_in_header_3', ])) self.invalid_files = [(get_data_path(e[0]), e[1], e[2]) for e in [ ('empty', PhylipFormatError, r'This file is empty.'), ('whitespace_only', PhylipFormatError, r'Found non-header line .*: ""'), ('phylip_invalid_empty_line_after_header', PhylipFormatError, r'Empty lines are not allowed.'), ('phylip_invalid_empty_line_before_header', PhylipFormatError, r'Found non-header line .*: ""'), ('phylip_invalid_empty_line_between_seqs', PhylipFormatError, r'Empty lines are not allowed.'), ('phylip_invalid_header_too_long', PhylipFormatError, r'Found non-header line .*: "2 20 extra_text"'), ('phylip_invalid_header_too_short', PhylipFormatError, r'Found non-header line .*: " 20"'), ('phylip_invalid_no_header', PhylipFormatError, r'Found non-header line .*: "foo .*"'), ('phylip_invalid_seq_too_long', PhylipFormatError, r'The length of sequence foo is not 20 as specified .*.'), ('phylip_invalid_seq_too_short', PhylipFormatError, r'The length of sequence foo is not 20 as specified .*.'), ('phylip_invalid_too_few_seqs', PhylipFormatError, r'The number of sequences is not .* as specified .*.'), ('phylip_invalid_too_many_seqs', PhylipFormatError, r'The number of sequences is not .* as specified in the header.'), ('phylip_invalid_zero_seq_len', PhylipFormatError, r'The number of sequences and the length must be positive.'), ('phylip_invalid_zero_seqs', PhylipFormatError, r'The number of sequences and the length must be positive.'), ]] def test_phylip_to_tabular_msa_invalid_files(self): for fp, error_type, error_msg_regex in self.invalid_files: with self.assertRaisesRegex(error_type, error_msg_regex): _phylip_to_tabular_msa(fp, constructor=DNA) def test_phylip_to_tabular_msa_no_constructor(self): with self.assertRaisesRegex(ValueError, '`constructor`'): _phylip_to_tabular_msa(get_data_path('phylip_dna_3_seqs')) def test_phylip_to_tabular_msa_valid_files(self): for valid_files, components in self.valid_configurations: for valid in valid_files: obs = _phylip_to_tabular_msa(valid, constructor=DNA) exp_seqs = [] exp_index = [] for seq, id_ in components: exp_seqs.append(DNA(seq, metadata={"id": id_})) exp_index.append(id_) exp = TabularMSA(exp_seqs, index=exp_index) self.assertEqual(obs, exp) def test_strict_format(self): fh = ["2 6\nSeq1 ACGTAC\nSeq2 TGCATG\n"] obs = _phylip_to_tabular_msa(fh, constructor=DNA, strict=True) exp = TabularMSA([ DNA('ACGTAC', metadata={'id': 'Seq1'}), DNA('TGCATG', metadata={'id': 'Seq2'}) ], index=['Seq1', 'Seq2']) self.assertEqual(obs, exp) def test_relaxed_format(self): fh = ["2 6\nLongSequenceID1 ACGTAC\nAnotherLongID TGCATG\n"] obs = _phylip_to_tabular_msa(fh, constructor=DNA, strict=False) exp = TabularMSA([ DNA('ACGTAC', metadata={'id': 'LongSequenceID1'}), DNA('TGCATG', metadata={'id': 'AnotherLongID'}) ], index=['LongSequenceID1', 'AnotherLongID']) self.assertEqual(obs, exp) msg = "Each line must contain an ID and sequence separated by whitespace." fh = ["1 5\nI_am_a_line_without_whitespace\n"] with self.assertRaises(PhylipFormatError) as e: _phylip_to_tabular_msa(fh, constructor=DNA, strict=False) self.assertEqual(str(e.exception), msg) class TestWriters(unittest.TestCase): def setUp(self): # ids all same length, seqs longer than 10 chars dna_3_seqs = TabularMSA([ DNA('..ACC-GTTGG..', metadata={'id': "d1"}), DNA('TTACCGGT-GGCC', metadata={'id': "d2"}), DNA('.-ACC-GTTGC--', metadata={'id': "d3"})], minter='id') # id lengths from 0 to 10, with mixes of numbers, characters, and # spaces. sequences are shorter than 10 chars variable_length_ids = TabularMSA([ DNA('.-ACGT', metadata={'id': ''}), DNA('TGCA-.', metadata={'id': 'a'}), DNA('.ACGT-', metadata={'id': 'bb'}), DNA('TGCA-.', metadata={'id': '1'}), DNA('AAAAAA', metadata={'id': 'abcdefghij'}), DNA('GGGGGG', metadata={'id': 'ab def42ij'})], minter='id') # sequences with 20 chars = exactly two chunks of size 10 two_chunks = TabularMSA([ DNA('..ACC-GTTGG..AATGC.C', metadata={'id': 'foo'}), DNA('TTACCGGT-GGCCTA-GCAT', metadata={'id': 'bar'})], minter='id') # single sequence with more than two chunks single_seq_long = TabularMSA([ DNA('..ACC-GTTGG..AATGC.C----', metadata={'id': 'foo'})], minter='id') # single sequence with only a single character (minimal writeable # alignment) single_seq_short = TabularMSA([DNA('-', metadata={'id': ''})], minter='id') # alignments that can be written in phylip format self.objs = [dna_3_seqs, variable_length_ids, two_chunks, single_seq_long, single_seq_short] self.fps = map(get_data_path, ['phylip_dna_3_seqs', 'phylip_variable_length_ids', 'phylip_two_chunks', 'phylip_single_seq_long', 'phylip_single_seq_short']) # alignments that cannot be written in phylip format, paired with their # expected error message regexps self.invalid_objs = [ # no seqs (TabularMSA([]), 'one sequence'), # no positions (TabularMSA([DNA('', metadata={'id': "d1"}), DNA('', metadata={'id': "d2"})]), 'one position'), # ids too long (TabularMSA([RNA('ACGU', metadata={'id': "foo"}), RNA('UGCA', metadata={'id': "alongsequenceid"})], minter='id'), '10.*alongsequenceid') ] def test_write(self): for fp, obj in zip(self.fps, self.objs): fh = io.StringIO() _tabular_msa_to_phylip(obj, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_write_invalid_alignment(self): for invalid_obj, error_msg_regexp in self.invalid_objs: fh = io.StringIO() with self.assertRaisesRegex(PhylipFormatError, error_msg_regexp): _tabular_msa_to_phylip(invalid_obj, fh) # ensure nothing was written to the file before the error was # thrown obs = fh.getvalue() fh.close() self.assertEqual(obs, '') if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_phylip_dm.py000066400000000000000000000356571520735541300261410ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import io import numpy as np from skbio.util import get_data_path from skbio.io.format.phylip_dm import ( _parse_header, _parse_line, _phylip_dm_sniffer, _phylip_dm_to_distance_matrix, _matrix_to_phylip_dm, ) from skbio.io import PhylipDMFormatError from skbio.stats.distance import DistanceMatrix class TestHelpers(unittest.TestCase): def test_parse_header(self): self.assertEqual(_parse_header("5\n"), 5) self.assertEqual(_parse_header(" 5\n"), 5) self.assertEqual(_parse_header("5 \n"), 5) msg = "Header line must be a single integer." for header in (" 3 7\n", "1.25\n", "hello\n"): with self.assertRaises(PhylipDMFormatError) as cm: _parse_header(header) self.assertEqual(str(cm.exception), msg) msg = "The number of objects must be positive." for n in ("-5\n", "0\n"): with self.assertRaises(PhylipDMFormatError) as cm: _parse_header(f"{n}\n") self.assertEqual(str(cm.exception), msg) def test_parse_line(self): for line in ("", "\n", " \n", "\t\r\n"): with self.assertRaises(PhylipDMFormatError) as cm: _parse_line(line, 0, 1, False, False, float) self.assertEqual(str(cm.exception), "Empty lines are not allowed.") with self.assertRaises(PhylipDMFormatError) as cm: _parse_line(" 1.23", 0, 1, False, True, float) self.assertEqual(str(cm.exception), "Empty IDs are not allowed.") with self.assertRaises(PhylipDMFormatError) as cm: _parse_line("sample\t0.25\there\t0.17", 7, 3, True, False, float) # The following test doesn't work in Python 3.10. Skipping... # self.assertEqual(str(cm.exception), ( # "Non-numeric cell values encountered in line 9.")) class TestSniffer(unittest.TestCase): def test_positives(self): # A typical file in lower layout with 14 objects. Header line has preceding # whitespaces. ID column has a width of 12, whereas all IDs themselves are # within 10 characters, leaving at least 2 spaces separating IDs from values. # This is often seen in real-world PHYLIP files. Yet, it is considered as # "relaxed" in scikit-bio. Columns are separated by whitespaces but one column # separation was intentionally filled with tabs for testing purpose. fp = get_data_path("phylip_dm_valid_lt.dist") obs = _phylip_dm_sniffer(fp) self.assertTrue(obs[0]) self.assertDictEqual(obs[1], dict(layout="lower", strict=False)) # square, relaxed, 5 objects fp = get_data_path("phylip_dm_valid_sq.dist") obs = _phylip_dm_sniffer(fp) self.assertTrue(obs[0]) self.assertDictEqual(obs[1], dict(layout="square", strict=False)) # lower, relaxed, 4 objects; IDs are incremental integers fp = get_data_path("phylip_dm_simple_lt.dist") obs = _phylip_dm_sniffer(fp) self.assertTrue(obs[0]) self.assertDictEqual(obs[1], dict(layout="lower", strict=False)) # square, relaxed, 4 objects, as above fp = get_data_path("phylip_dm_simple_sq.dist") obs = _phylip_dm_sniffer(fp) self.assertTrue(obs[0]) self.assertDictEqual(obs[1], dict(layout="square", strict=False)) # square, strict, 4 objects; first and last IDs are exactly 10 characters # (therefore touching values without any separator) fp = get_data_path("phylip_dm_good_simple_strict_square.dist") obs = _phylip_dm_sniffer(fp) self.assertTrue(obs[0]) self.assertDictEqual(obs[1], dict(layout="square", strict=True)) # square, strict, 4 objects; first and last IDs are exactly 10 characters # (therefore touching values without any separator) fp = get_data_path("phylip_dm_good_simple_strict_square.dist") obs = _phylip_dm_sniffer(fp) self.assertTrue(obs[0]) self.assertDictEqual(obs[1], dict(layout="square", strict=True)) # same as above, but only last ID is exactly 10 characters fp = get_data_path("phylip_dm_good_simple_strict_square_reader.dist") obs = _phylip_dm_sniffer(fp) self.assertTrue(obs[0]) self.assertDictEqual(obs[1], dict(layout="square", strict=True)) def test_negatives(self): negative_files = [ "empty", "whitespace_only", "phylip_dm_invalid_empty_line_after_header.dist", "phylip_dm_invalid_empty_line_before_header.dist", "phylip_dm_sq_invalid_empty_line_after_header.dist", "phylip_dm_sq_invalid_empty_line_before_header.dist", "phylip_dm_invalid_header_too_long.dist", "phylip_dm_invalid_no_header.dist", "phylip_dm_invalid_no_dists.dist", "phylip_dm_invalid_zero_header.dist", "phylip_dm_invalid_too_many_columns.dist", "phylip_dm_invalid_too_few_columns_sq.dist", "phylip_dm_invalid_wrong_number_dists_lt.dist", ] for file in negative_files: self.assertEqual(_phylip_dm_sniffer(get_data_path(file)), (False, {})) class TestReaders(unittest.TestCase): def test_read_positives(self): # a small, square matrix fp = get_data_path("phylip_dm_valid_sq.dist") kwargs = dict(layout="square", strict=False) exp = np.array([ [0.0, 1.0, 2.0, 3.0, 3.0], [1.0, 0.0, 2.0, 3.0, 3.0], [2.0, 2.0, 0.0, 3.0, 3.0], [3.0, 3.0, 3.0, 0.0, 1.0], [3.0, 3.0, 3.0, 1.0, 0.0], ]) obs = _phylip_dm_to_distance_matrix(fp, **kwargs) self.assertTrue((obs.data == exp).all()) # a large, lower matrix fp = get_data_path("phylip_dm_valid_lt.dist") kwargs = dict(layout="lower", strict=False) exp = np.array([ [0.0, 1.7043, 2.0235, 2.1378, 1.5232, 1.8261, 1.9182, 2.0039, 1.9431, 1.9663, 2.0593, 1.6664, 1.732, 1.7101,], [1.7043, 0.0, 1.1901, 1.3287, 1.2423, 1.2508, 1.2536, 1.3066, 1.2827, 1.3296, 1.2005, 1.346, 1.3757, 1.3956,], [2.0235, 1.1901, 0.0, 1.2905, 1.3199, 1.3887, 1.4658, 1.4826, 1.4502, 1.8708, 1.5356, 1.4577, 1.7803, 1.6661,], [2.1378, 1.3287, 1.2905, 0.0, 1.7878, 1.3137, 1.3788, 1.3826, 1.4543, 1.6683, 1.6606, 1.5935, 1.7119, 1.7599,], [1.5232, 1.2423, 1.3199, 1.7878, 0.0, 1.0642, 1.1124, 0.9832, 1.0629, 0.9228, 1.0681, 0.9127, 1.0635, 1.0557,], [1.8261, 1.2508, 1.3887, 1.3137, 1.0642, 0.0, 0.1022, 0.2061, 0.3895, 0.8035, 0.7239, 0.7278, 0.7899, 0.6933,], [1.9182, 1.2536, 1.4658, 1.3788, 1.1124, 0.1022, 0.0, 0.2681, 0.393, 0.7109, 0.729, 0.7412, 0.8742, 0.7118,], [2.0039, 1.3066, 1.4826, 1.3826, 0.9832, 0.2061, 0.2681, 0.0, 0.3665, 0.8132, 0.7894, 0.8763, 0.8868, 0.7589,], [1.9431, 1.2827, 1.4502, 1.4543, 1.0629, 0.3895, 0.393, 0.3665, 0.0, 0.7858, 0.714, 0.7966, 0.8288, 0.8542,], [1.9663, 1.3296, 1.8708, 1.6683, 0.9228, 0.8035, 0.7109, 0.8132, 0.7858, 0.0, 0.7095, 0.5959, 0.6213, 0.5612,], [2.0593, 1.2005, 1.5356, 1.6606, 1.0681, 0.7239, 0.729, 0.7894, 0.714, 0.7095, 0.0, 0.4604, 0.5065, 0.47,], [1.6664, 1.346, 1.4577, 1.5935, 0.9127, 0.7278, 0.7412, 0.8763, 0.7966, 0.5959, 0.4604, 0.0, 0.3502, 0.3097,], [1.732, 1.3757, 1.7803, 1.7119, 1.0635, 0.7899, 0.8742, 0.8868, 0.8288, 0.6213, 0.5065, 0.3502, 0.0, 0.2712,], [1.7101, 1.3956, 1.6661, 1.7599, 1.0557, 0.6933, 0.7118, 0.7589, 0.8542, 0.5612, 0.47, 0.3097, 0.2712, 0.0,], ]) obs = _phylip_dm_to_distance_matrix(fp, **kwargs) self.assertTrue((obs.data == exp).all()) def test_read_dtype(self): fn = _phylip_dm_to_distance_matrix fp = get_data_path("phylip_dm_valid_sq.dist") kwargs = dict(layout="square", strict=False) exp = np.array([ [0.0, 1.0, 2.0, 3.0, 3.0], [1.0, 0.0, 2.0, 3.0, 3.0], [2.0, 2.0, 0.0, 3.0, 3.0], [3.0, 3.0, 3.0, 0.0, 1.0], [3.0, 3.0, 3.0, 1.0, 0.0], ]) # float64 (default) for dtype in (None, float, np.float64, "float64"): obs = _phylip_dm_to_distance_matrix(fp, dtype=dtype, **kwargs) self.assertTrue((obs.data == exp).all()) self.assertEqual(obs.dtype, np.float64) # float32 exp = exp.astype(np.float32) for dtype in (np.float32, "float32"): obs = _phylip_dm_to_distance_matrix(fp, dtype=dtype, **kwargs) self.assertTrue((obs.data == exp).all()) self.assertEqual(obs.dtype, np.float32) # invalid data type for dtype in ("xyz", int, "float16", "uint8", np.float16): self.assertRaises( TypeError, _phylip_dm_to_distance_matrix, fp, dtype=dtype, **kwargs ) def test_error_empty_file(self): with self.assertRaises(PhylipDMFormatError) as cm: _phylip_dm_to_distance_matrix(get_data_path("empty")) self.assertEqual(str(cm.exception), "This file is empty.") def test_error_wrong_row_number(self): fp = get_data_path("phylip_dm_invalid_too_many_rows.dist") with self.assertRaises(PhylipDMFormatError) as cm: _phylip_dm_to_distance_matrix(fp, layout="square") self.assertEqual(str(cm.exception), ( "The number of rows in the matrix body exceeds 5 as specified in the " "header." )) fp = get_data_path("phylip_dm_invalid_too_few_rows.dist") with self.assertRaises(PhylipDMFormatError) as cm: _phylip_dm_to_distance_matrix(fp, layout="square") self.assertEqual(str(cm.exception), ( "The number of rows in the matrix body (4) does not match the number of " "objects specified in the header (5)." )) def test_error_wrong_column_number(self): fp = get_data_path("phylip_dm_invalid_too_many_columns.dist") with self.assertRaises(PhylipDMFormatError) as cm: _phylip_dm_to_distance_matrix(fp, layout="square") self.assertEqual(str(cm.exception), ( "The number of distance values (6) in line 2 does not match the " "expectation (5, as specified in the header)." )) fp = get_data_path("phylip_dm_invalid_too_few_columns_sq.dist") with self.assertRaises(PhylipDMFormatError) as cm: _phylip_dm_to_distance_matrix(fp, layout="square") self.assertEqual(str(cm.exception), ( "The number of distance values (4) in line 2 does not match the " "expectation (5, as specified in the header)." )) fp = get_data_path("phylip_dm_invalid_wrong_number_dists_lt.dist") with self.assertRaises(PhylipDMFormatError) as cm: _phylip_dm_to_distance_matrix(fp, layout="lower") self.assertEqual(str(cm.exception), ( "The number of distance values (1) in line 2 does not match the " "expectation (0, which is line number - 2)." )) def test_error_matrix_data_parsed_as_id(self): # A special case where a strict object ID is exactly 10 characters and it # touches the values. If parsed in relaxed mode, it will raise. fp = get_data_path("phylip_dm_good_simple_strict_square_reader.dist") with self.assertRaises(PhylipDMFormatError) as cm: _phylip_dm_to_distance_matrix(fp, layout="square", strict=False) self.assertEqual(str(cm.exception), ( "The number of distance values (3) in line 5 does not match the " "expectation (4, as specified in the header)." )) class TestWriters(unittest.TestCase): def setUp(self): self.dm_condensed = DistanceMatrix([1, 2, 3, 4, 5, 6], condensed=True) self.dm_square = DistanceMatrix( [[0, 1, 2, 3], [1, 0, 4, 5], [2, 4, 0, 6], [3, 5, 6, 0]] ) self.exp_lower = ( "4\n0\n1\t1.0\n2\t2.0\t4.0\n3\t3.0\t5.0\t6.0\n" ) self.exp_square = ( "4\n0\t0.0\t1.0\t2.0\t3.0\n1\t1.0\t0.0\t4.0\t5.0\n" "2\t2.0\t4.0\t0.0\t6.0\n3\t3.0\t5.0\t6.0\t0.0\n" ) def test_condensed_to_lower(self): """Test writing condensed DistanceMatrix to lower triangular layout.""" fh = io.StringIO() self.dm_condensed.write(fh, format="phylip_dm", layout="lower") result = fh.getvalue() fh.close() self.assertEqual(result, self.exp_lower) def test_condensed_to_square(self): """Test writing condensed DistanceMatrix to square layout.""" fh = io.StringIO() self.dm_condensed.write(fh, format="phylip_dm", layout="square") result = fh.getvalue() fh.close() self.assertEqual(result, self.exp_square) def test_square_to_lower(self): """Test writing square DistanceMatrix to lower triangular layout.""" fh = io.StringIO() self.dm_square.write(fh, format="phylip_dm", layout="lower") result = fh.getvalue() fh.close() self.assertEqual(result, self.exp_lower) def test_square_to_square(self): """Test writing square DistanceMatrix to square layout.""" fh = io.StringIO() self.dm_square.write(fh, format="phylip_dm", layout="square") result = fh.getvalue() fh.close() self.assertEqual(result, self.exp_square) def test_not_enough_objects(self): fh = io.StringIO() msg = ( "DistanceMatrix can only be written in PHYLIP format if there are at " "least two samples in the matrix." ) with self.assertRaises(PhylipDMFormatError) as e: _matrix_to_phylip_dm(DistanceMatrix([]), fh, "\t", layout="lower") self.assertEqual(str(e.exception), msg) fh.close() def test_invalid_layout(self): """Test writing DistanceMatrix to invalid layout.""" fh = io.StringIO() msg = "Upper triangular layout is currently not supported." with self.assertRaises(PhylipDMFormatError) as e: self.dm_square.write(fh, format="phylip_dm", layout="upper") self.assertEqual(str(e.exception), msg) msg = "'xyz' is not a supported matrix layout." with self.assertRaises(PhylipDMFormatError) as e: self.dm_square.write(fh, format="phylip_dm", layout="xyz") self.assertEqual(str(e.exception), msg) fh.close() if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_qseq.py000066400000000000000000000316051520735541300251120ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from skbio import Sequence, DNA, RNA, Protein from skbio import read from skbio.util import get_data_path from skbio.io import QSeqFormatError from skbio.io.format.qseq import _qseq_to_generator, _qseq_sniffer import numpy as np def _drop_kwargs(kwargs, *args): for arg in args: if arg in kwargs: kwargs.pop(arg) class TestQSeqBase(unittest.TestCase): def setUp(self): self.valid_files = [ (get_data_path('qseq_single_seq_sanger'), [ {'variant': 'sanger'}, {'phred_offset': 33}, ], [ {'id': 'sanger_1:3:34:-30:30#0/2', 'sequence': 'ACGTACGTACGTACGTACGTACGTACTTTTTTTTTTACGTACGTACG' 'TACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTAC', 'quality': [26, 26, 29, 31, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93], 'machine_name': 'sanger', 'run_number': 1, 'lane_number': 3, 'tile_number': 34, 'x': -30, 'y': 30, 'index': 0, 'read_number': 2} ]), (get_data_path('qseq_multi_seq_illumina1.3'), [ {'variant': 'illumina1.3'}, {'phred_offset': 64} ], [ {'id': 'illumina_1:3:34:-30:30#0/1', 'sequence': 'ACG....ACGTAC', 'quality': [50, 53, 2, 2, 2, 2, 50, 2, 3, 5, 6, 7, 8], 'machine_name': 'illumina', 'run_number': 1, 'lane_number': 3, 'tile_number': 34, 'x': -30, 'y': 30, 'index': 0, 'read_number': 1}, {'id': 'illumina_1:3:35:-30:30#0/2', 'sequence': 'ACGTA.AATAAAC', 'quality': [39, 37, 20, 33, 1, 33, 38, 40, 55, 49, 1, 1, 38], 'machine_name': 'illumina', 'run_number': 1, 'lane_number': 3, 'tile_number': 35, 'x': -30, 'y': 30, 'index': 0, 'read_number': 2} ]), (get_data_path('qseq_multi_seq_illumina1.3'), [ {'variant': 'illumina1.3', 'filter': False, 'seq_num': 1}, {'phred_offset': 64, 'filter': False, 'seq_num': 2}, {'variant': 'illumina1.3', 'filter': False, 'seq_num': 3, 'constructor': Protein}, {'phred_offset': 64, 'filter': False, 'seq_num': 4, 'constructor': DNA}, ], [ {'id': 'illumina_1:3:34:-30:30#0/1', 'sequence': 'ACG....ACGTAC', 'quality': [50, 53, 2, 2, 2, 2, 50, 2, 3, 5, 6, 7, 8], 'machine_name': 'illumina', 'run_number': 1, 'lane_number': 3, 'tile_number': 34, 'x': -30, 'y': 30, 'index': 0, 'read_number': 1}, {'id': 'illumina_1:3:34:30:-30#0/1', 'sequence': 'CGGGCATTGCA', 'quality': [3, 7, 7, 7, 3, 33, 51, 36, 7, 3, 1], 'machine_name': 'illumina', 'run_number': 1, 'lane_number': 3, 'tile_number': 34, 'x': 30, 'y': -30, 'index': 0, 'read_number': 1}, {'id': 'illumina_1:3:35:-30:30#0/2', 'sequence': 'ACGTA.AATAAAC', 'quality': [39, 37, 20, 33, 1, 33, 38, 40, 55, 49, 1, 1, 38], 'machine_name': 'illumina', 'run_number': 1, 'lane_number': 3, 'tile_number': 35, 'x': -30, 'y': 30, 'index': 0, 'read_number': 2}, {'id': 'illumina_1:3:35:30:-30#0/3', 'sequence': 'CATTTAGGA.TGCA', 'quality': [52, 42, 38, 44, 43, 1, 6, 46, 43, 11, 39, 40, 54, 13], 'machine_name': 'illumina', 'run_number': 1, 'lane_number': 3, 'tile_number': 35, 'x': 30, 'y': -30, 'index': 0, 'read_number': 3} ]) ] self.invalid_files = [ (get_data_path('whitespace_only'), [ {}, {'variant': 'sanger'} ], [ 'blank line', ], QSeqFormatError), (get_data_path('tsv_10_fields'), [ {}, {'variant': 'sanger'}, {'variant': 'solexa'} ], [ 'read', '[1, 3]' ], QSeqFormatError), (get_data_path('tsv_8_fields'), [ {}, {'variant': 'sanger'}, {'variant': 'solexa'} ], [ '8', '10 or 11' ], QSeqFormatError), (get_data_path('qseq_invalid_filter'), [ {}, {'phred_offset': 33}, {'variant': 'solexa'}, {'variant': 'illumina1.3'}, {'variant': 'illumina1.8'} ], [ 'filter', '0 or 1', ], QSeqFormatError), (get_data_path('qseq_invalid_read'), [ {}, {'phred_offset': 33}, {'variant': 'solexa'}, {'variant': 'illumina1.3'}, {'variant': 'illumina1.8'} ], [ 'read', '[1, 3]', ], QSeqFormatError), (get_data_path('qseq_invalid_x'), [ {}, {'phred_offset': 33}, {'variant': 'solexa'}, {'variant': 'illumina1.3'}, {'variant': 'illumina1.8'} ], [ 'x', 'integer', ], QSeqFormatError), (get_data_path('qseq_invalid_y'), [ {}, {'phred_offset': 33}, {'variant': 'solexa'}, {'variant': 'illumina1.3'}, {'variant': 'illumina1.8'} ], [ 'y', 'integer', ], QSeqFormatError), (get_data_path('qseq_invalid_lane'), [ {}, {'phred_offset': 33}, {'variant': 'solexa'}, {'variant': 'illumina1.3'}, {'variant': 'illumina1.8'} ], [ 'lane', 'positive integer', ], QSeqFormatError), (get_data_path('qseq_invalid_tile'), [ {}, {'phred_offset': 33}, {'variant': 'solexa'}, {'variant': 'illumina1.3'}, {'variant': 'illumina1.8'} ], [ 'tile', 'positive integer', ], QSeqFormatError) ] class TestQSeqToGenerator(TestQSeqBase): def setUp(self): super(TestQSeqToGenerator, self).setUp() self.valid_files += [ (get_data_path('empty'), [{}, {'variant': 'sanger'}], []) ] self.invalid_files += [ (get_data_path('qseq_single_seq_sanger'), [ {'variant': 'illumina1.3'}, {'variant': 'illumina1.8'} ], [ 'out of range', '[0, 62]' ], ValueError) ] def test_invalid_files(self): for invalid, kwargs, errors, etype in self.invalid_files: with self.assertRaises(etype) as cm: for kwarg in kwargs: _drop_kwargs(kwarg, 'seq_num') list(_qseq_to_generator(invalid, **kwarg)) for e in errors: self.assertIn(e, str(cm.exception)) def test_valid_files(self): for valid, kwargs, components in self.valid_files: for kwarg in kwargs: _drop_kwargs(kwarg, 'seq_num') constructor = kwarg.get('constructor', Sequence) expected = [ constructor( c['sequence'], metadata={'id': c['id'], 'machine_name': c['machine_name'], 'run_number': c['run_number'], 'lane_number': c['lane_number'], 'tile_number': c['tile_number'], 'x': c['x'], 'y': c['y'], 'index': c['index'], 'read_number': c['read_number']}, positional_metadata={ 'quality': np.array(c['quality'], dtype=np.uint8)}) for c in components] observed = list(_qseq_to_generator(valid, **kwarg)) self.assertEqual(len(expected), len(observed)) for o, e in zip(observed, expected): self.assertEqual(o, e) class TestQSeqToSequences(TestQSeqBase): def test_invalid_files(self): for constructor in [Sequence, DNA, RNA, Protein]: for invalid, kwargs, errors, etype in self.invalid_files: with self.assertRaises(etype) as cm: for kwarg in kwargs: _drop_kwargs(kwarg, 'constructor', 'filter') read(invalid, format='qseq', verify=False, into=constructor, **kwarg) for e in errors: self.assertIn(e, str(cm.exception)) def test_valid_files(self): for constructor in [Sequence, DNA, RNA, Protein]: for valid, kwargs, components in self.valid_files: for observed_kwargs in kwargs: expected_kwargs = {} # Currently not validating the alphabet for qseq # files that are read in for this test. if hasattr(constructor, 'alphabet'): observed_kwargs['validate'] = False expected_kwargs['validate'] = False _drop_kwargs(observed_kwargs, 'constructor', 'filter') seq_num = observed_kwargs.get('seq_num', 1) c = components[seq_num - 1] expected = constructor( c['sequence'], metadata={'id': c['id'], 'machine_name': c['machine_name'], 'run_number': c['run_number'], 'lane_number': c['lane_number'], 'tile_number': c['tile_number'], 'x': c['x'], 'y': c['y'], 'index': c['index'], 'read_number': c['read_number']}, positional_metadata={ 'quality': np.array(c['quality'], np.uint8)}, **expected_kwargs) observed = read(valid, into=constructor, format='qseq', verify=False, **observed_kwargs) self.assertEqual(observed, expected) class TestQSeqSniffer(TestQSeqBase): def setUp(self): super(TestQSeqSniffer, self).setUp() self.invalid_files += [ (get_data_path('empty'), None, None, None) ] def test_qseq_sniffer_valid_files(self): for valid, _, _ in self.valid_files: self.assertEqual(_qseq_sniffer(valid), (True, {})) def test_qseq_sniffer_invalid_files(self): for invalid, _, _, _ in self.invalid_files: self.assertEqual(_qseq_sniffer(invalid), (False, {})) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_sample_metadata.py000066400000000000000000000053131520735541300272570ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import pandas as pd import tempfile import os from skbio.util import get_data_path from skbio.util._decorator import overrides from skbio.metadata._metadata import SampleMetadata from skbio.io.format.sample_metadata import ( _sample_metadata_sniffer, _sample_metadata_read) class SnifferTests(TestCase): def setUp(self): self.positive_fps = list(map(get_data_path, [ 'sample-metadata-comments-comment-char-id.tsv', 'sample-metadata-comments.tsv', 'sample-metadata-comments-mixed-case.tsv', 'sample-metadata-complete-types-directive.tsv', 'sample-metadata-empty-rows.tsv', 'sample-metadata-leading-trailing-whitespace.tsv', 'sample-metadata-leading-trailing-whitespace-split-id.tsv', ])) self.negative_fps = list(map(get_data_path, [ 'empty', 'whitespace_only', ])) def test_positives(self): for fp in self.positive_fps: self.assertEqual(_sample_metadata_sniffer(fp), (True, {})) def test_negatives(self): for fp in self.negative_fps: self.assertEqual(_sample_metadata_sniffer(fp), (False, {})) class TestSampleMetadataReader(TestCase): def test_reader(self): fp = get_data_path('sample-metadata-complete-types-directive.tsv') obs_md = SampleMetadata.read(fp) exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_df = pd.DataFrame({'col1': ['1', '2', '3'], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) class TestRoundtrip(TestCase): def setUp(self): self.temp_dir_obj = tempfile.TemporaryDirectory( prefix='sample-metadata-temp') self.temp_dir = self.temp_dir_obj.name self.filepath = os.path.join(self.temp_dir, 'metadata.tsv') def tearDown(self): self.temp_dir_obj.cleanup() def test_simple(self): fp = get_data_path('sample-metadata-comments-mixed-case.tsv') md1 = SampleMetadata.read(fp) md1.write(self.filepath) md2 = SampleMetadata.read(self.filepath) self.assertEqual(md1, md2) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_sequence_feature_vocabulary.py000066400000000000000000000107661520735541300317200ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main from skbio.io.format._sequence_feature_vocabulary import ( _parse_loc_str, _parse_section_default, _serialize_location) from skbio.io import FileFormatError from skbio.metadata import IntervalMetadata class Tests(TestCase): def test_parse_section_default(self): lines = [ ['FOO blah blah', ' blah'], ['FOO=blah', ' blah'], ['FOO']] kwargs = [{'join_delimiter': '=', 'return_label': False}, {'label_delimiter': '=', 'join_delimiter': '', 'return_label': True}, {'label_delimiter': '=', 'join_delimiter': '=', 'return_label': True}] expects = ['blah blah=blah', ('FOO', 'blahblah'), ('FOO', '')] for i, j, k in zip(lines, kwargs, expects): self.assertEqual(k, _parse_section_default(i, **j)) def test_parse_loc_str(self): examples = [ '9', # a single base in the presented sequence '3..8', '<3..8', '3..>8', 'complement(3..>8)', 'complement(join(3..>5,<7..9))', 'join(J00194.1:1..9,3..8)', 'join(3..8,J00194.1:1..9)', '1.9', '1^2', # single-base locations with fuzzy boundary (issue #1666): # e.g. lambda virus (NCBI J02459.1) contains # "mRNA complement(<23231)". '<9', '>9', 'complement(<23231)', 'complement(>23231)'] expects = [ ([(8, 9)], [(False, False)], {'strand': '+'}), ([(2, 8)], [(False, False)], {'strand': '+'}), ([(2, 8)], [(True, False)], {'strand': '+'}), ([(2, 8)], [(False, True)], {'strand': '+'}), ([(2, 8)], [(False, True)], {'strand': '-'}), ([(2, 5), (6, 9)], [(False, True), (True, False)], {'strand': '-'}), ([(2, 8)], [(False, False)], {'strand': '+'}), ([(2, 8)], [(False, False)], {'strand': '+'}), ([(0, 9)], [(False, False)], {'strand': '+'}), ([(0, 1)], [(False, False)], {'strand': '+'}), ([(8, 9)], [(True, False)], {'strand': '+'}), ([(8, 9)], [(False, True)], {'strand': '+'}), ([(23230, 23231)], [(True, False)], {'strand': '-'}), ([(23230, 23231)], [(False, True)], {'strand': '-'})] for example, expect in zip(examples, expects): parsed = _parse_loc_str(example) self.assertEqual(parsed, expect) def test_parse_loc_str_invalid(self): examples = [ 'abc', '3-8'] for example in examples: with self.assertRaisesRegex(FileFormatError, r'Could not parse location string: ' '"%s"' % example): _parse_loc_str(example) def test_serialize_location(self): imd = IntervalMetadata(9) i1 = imd.add([(0, 1)]) self.assertEqual(_serialize_location(i1), '1') # single-base with fuzzy lower/upper boundary (issue #1666) i1a = imd.add([(0, 1)], [(True, False)]) self.assertEqual(_serialize_location(i1a), '<1') i1b = imd.add([(0, 1)], [(False, True)]) self.assertEqual(_serialize_location(i1b), '>1') i2 = imd.add([(0, 2)], [(True, True)]) self.assertEqual(_serialize_location(i2), '<1..>2') i3 = imd.add([(0, 2)], [(False, True)]) self.assertEqual(_serialize_location(i3), '1..>2') i4 = imd.add([(0, 2)], [(True, False)]) self.assertEqual(_serialize_location(i4), '<1..2') i5 = imd.add([(0, 2), (3, 9)], metadata={'strand': '-'}) self.assertEqual(_serialize_location(i5), 'complement(join(1..2,4..9))') i6 = imd.add([(0, 2), (3, 9)], [(True, False), (False, True)], metadata={'strand': '-'}) self.assertEqual(_serialize_location(i6), 'complement(join(<1..2,4..>9))') if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_stockholm.py000066400000000000000000001232671520735541300261520ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import pandas as pd import io import unittest from collections import OrderedDict from skbio import TabularMSA, Protein, DNA, RNA from skbio.io import StockholmFormatError from skbio.io.format.stockholm import (_stockholm_to_tabular_msa, _tabular_msa_to_stockholm, _stockholm_sniffer) from skbio.util import get_data_path class TestStockholmSniffer(unittest.TestCase): def setUp(self): self.positives = [get_data_path(e) for e in [ 'stockholm_extensive', 'stockholm_minimal', 'stockholm_rna', 'stockholm_runon_gf_with_whitespace', 'stockholm_runon_gf_no_whitespace', 'stockholm_duplicate_sequence_names', 'stockholm_duplicate_gr', 'stockholm_duplicate_gc', 'stockholm_invalid_nonexistent_gr', 'stockholm_invalid_nonexistent_gs', 'stockholm_no_data', 'stockholm_blank_lines', 'stockholm_differing_gc_data_length', 'stockholm_differing_gr_data_length', 'stockholm_differing_seq_lengths', 'stockholm_duplicate_sequence_names', 'stockholm_duplicate_tree_ids', 'stockholm_extensive_mixed', 'stockholm_invalid_data_type', 'stockholm_malformed_gf_line', 'stockholm_malformed_gs_line', 'stockholm_malformed_gr_line', 'stockholm_malformed_gc_line', 'stockholm_malformed_data_line', 'stockholm_metadata_only', 'stockholm_multiple_msa', 'stockholm_multiple_trees', 'stockholm_runon_gs_with_whitespace', 'stockholm_runon_gs_no_whitespace', 'stockholm_single_tree_with_id', 'stockholm_single_tree_without_id', 'stockholm_whitespace_only_lines', 'stockholm_all_data_types', 'stockholm_two_of_each_metadata', 'stockholm_data_only', 'stockholm_nonstring_labels', 'stockholm_missing_reference_items', 'stockholm_multiple_references', 'stockholm_runon_references', 'stockholm_runon_references_mixed', 'stockholm_single_reference', 'stockholm_missing_reference_items', 'stockholm_missing_rn_tag', 'stockholm_different_padding', 'stockholm_multi_line_tree_no_id', 'stockholm_multi_line_tree_with_id', 'stockholm_multiple_multi_line_trees' ]] self.negatives = [get_data_path(e) for e in [ 'stockholm_missing_header', 'empty', 'whitespace_only' ]] def test_positives(self): for fp in self.positives: self.assertEqual(_stockholm_sniffer(fp), (True, {})) def test_negatives(self): for fp in self.negatives: self.assertEqual(_stockholm_sniffer(fp), (False, {})) class TestStockholmReader(unittest.TestCase): def test_stockholm_extensive(self): fp = get_data_path('stockholm_extensive') msa = _stockholm_to_tabular_msa(fp, constructor=Protein) exp = TabularMSA([Protein('MTCRAQLIAVPRASSLAE..AIACAQKM....' 'RVSRVPVYERS', metadata={'id': 'O83071/192-246'}, positional_metadata={'SA': list('9998877564' '53524252..' '55152525..' '..36463774' '777')}), Protein('EVMLTDIPRLHINDPIMK..GFGMVINN....' '..GFVCVENDE', metadata={'id': 'O31698/88-139', 'OS': 'Bacillus subtilis'}, positional_metadata={'SS': list('CCCCCCCHHHH' 'HHHHHHH..HE' 'EEEEEE....E' 'EEEEEE' 'EEEH')}), Protein('EVMLTDIPRLHINDPIMK..GFGMVINN...' '...GFVCVENDE', metadata={'id': 'O31699/88-139'}, positional_metadata={'AS': list('___________' '_____*_____' '___________' '________' '__'), 'IN': list('___________' '_1_________' '_____2_____' '_____0_' '___')})], metadata={'ID': 'CBS', 'AC': 'PF00571', 'AU': 'Bateman A', 'SQ': '67'}, positional_metadata={'SS_cons': list('CCCCCHHHHHHHH' 'HHHHH..EEEEEE' 'EE....EEEEEEE' 'EEEH')}, index=['O83071/192-246', 'O31698/88-139', 'O31699/88-139']) self.assertEqual(msa, exp) def test_stockholm_extensive_mixed(self): fp = get_data_path('stockholm_extensive_mixed') msa = _stockholm_to_tabular_msa(fp, constructor=Protein) exp = TabularMSA([Protein('MTCRAQLIAVPRASSLAE..AIACAQKM....' 'RVSRVPVYERS', metadata={'id': 'O83071/192-246'}, positional_metadata={'SA': list('9998877564' '53524252..' '55152525..' '..36463774' '777')}), Protein('EVMLTDIPRLHINDPIMK..GFGMVINN....' '..GFVCVENDE', metadata={'id': 'O31698/88-139', 'OS': 'Bacillus subtilis'}, positional_metadata={'SS': list('CCCCCCCHHHH' 'HHHHHHH..HE' 'EEEEEE....E' 'EEEEEE' 'EEEH')}), Protein('EVMLTDIPRLHINDPIMK..GFGMVINN...' '...GFVCVENDE', metadata={'id': 'O31699/88-139'}, positional_metadata={'AS': list('___________' '_____*_____' '___________' '________' '__'), 'IN': list('___________' '_1_________' '_____2_____' '_____0_' '___')})], metadata={'ID': 'CBS', 'AC': 'PF00571', 'AU': 'Bateman A', 'SQ': '67'}, positional_metadata={'SS_cons': list('CCCCCHHHHHHHH' 'HHHHH..EEEEEE' 'EE....EEEEEEE' 'EEEH')}, index=['O83071/192-246', 'O31698/88-139', 'O31699/88-139']) self.assertEqual(msa, exp) def test_stockholm_minimal(self): fp = get_data_path('stockholm_minimal') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([DNA('TGTGTCGCAGTTGTCGTTTG', metadata={'id': '0235244'})], index=['0235244']) self.assertEqual(msa, exp) def test_stockholm_rna(self): fp = get_data_path('stockholm_rna') msa = _stockholm_to_tabular_msa(fp, constructor=RNA) exp = TabularMSA([RNA('AAGGGUUAUUUAUAUACUUU', metadata={'id': 'RTC2231'}), RNA('UGCUAAGAGUGGGGAUGAUU', metadata={'id': 'RTF2124'}), RNA('GCCACAACCGAUUAGAUAGA', metadata={'id': 'RTH3322'}), RNA('UUAGAAACCGAUGGACCGAA', metadata={'id': 'RTB1512'})], metadata={'AC': 'G2134T23', 'ID': 'ARD'}, positional_metadata=( {'AC_cons': list('GGGACUGGACAUCUAUUCAG')}), index=['RTC2231', 'RTF2124', 'RTH3322', 'RTB1512']) self.assertEqual(msa, exp) def test_stockholm_runon_gf(self): fp = get_data_path('stockholm_runon_gf_no_whitespace') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([DNA('ACTGGTTCAATG', metadata={'id': 'GG1344'})], metadata={'CC': 'CBS domains are small intracellular' ' modules mostly found in 2 or four ' 'copies within a protein.'}, index=['GG1344']) self.assertEqual(msa, exp) fp = get_data_path('stockholm_runon_gf_with_whitespace') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) self.assertEqual(msa, exp) def test_stockholm_runon_gs(self): fp = get_data_path('stockholm_runon_gs_no_whitespace') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([DNA('ATCGTTCAGTG', metadata={'id': 'seq1', 'LN': 'This is a runon GS line.'})], index=['seq1']) self.assertEqual(msa, exp) fp = get_data_path('stockholm_runon_gs_with_whitespace') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) self.assertEqual(msa, exp) def test_stockholm_metadata_only(self): fp = get_data_path('stockholm_metadata_only') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([], metadata={'NM': 'Kestrel Gorlick', 'DT': 'February 5th, 2016'}) self.assertEqual(msa, exp) def test_stockholm_no_data(self): fp = get_data_path('stockholm_no_data') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([]) self.assertEqual(msa, exp) def test_stockholm_with_blank_lines(self): fp = get_data_path('stockholm_blank_lines') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([], metadata={'AL': 'ABCD', 'NM': '1234'}) self.assertEqual(msa, exp) def test_stockholm_with_whitespace_only_lines(self): fp = get_data_path('stockholm_whitespace_only_lines') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([], metadata={'AL': 'ABCD', 'NM': '1234'}) self.assertEqual(msa, exp) def test_stockholm_single_tree_without_id(self): fp = get_data_path('stockholm_single_tree_without_id') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([], metadata={'NH': 'ABCD'}) self.assertEqual(msa, exp) def test_stockholm_single_tree_with_id(self): fp = get_data_path('stockholm_single_tree_with_id') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([], metadata={'NH': {'tree1': 'ABCD'}}) self.assertEqual(msa, exp) def test_stockholm_multiple_trees(self): fp = get_data_path('stockholm_multiple_trees') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([], metadata={'NH': {'tree1': 'ABCD', 'tree2': 'EFGH', 'tree3': 'IJKL'}}) self.assertEqual(msa, exp) def test_stockhom_single_reference(self): fp = get_data_path('stockholm_single_reference') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA( [], metadata={'RN': [OrderedDict([('RM', '123456789'), ('RT', 'A Title'), ('RA', 'The Author'), ('RL', 'A Location'), ('RC', 'Comment')])]}) self.assertEqual(msa, exp) def test_stockholm_multiple_references(self): fp = get_data_path('stockholm_multiple_references') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA( [], metadata={'RN': [OrderedDict([('RM', '123456789'), ('RT', 'Title 1'), ('RA', 'Author 1'), ('RL', 'Location 1'), ('RC', 'Comment 1')]), OrderedDict([('RM', '987654321'), ('RT', 'Title 2'), ('RA', 'Author 2'), ('RL', 'Location 2'), ('RC', 'Comment 2')]), OrderedDict([('RM', '132465879'), ('RT', 'Title 3'), ('RA', 'Author 3'), ('RL', 'Location 3'), ('RC', 'Comment 3')])]}) self.assertEqual(msa, exp) def test_stockholm_runon_references(self): fp = get_data_path('stockholm_runon_references') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA( [], metadata={'RN': [OrderedDict([('RM', '123456789'), ('RT', 'A Runon Title'), ('RA', 'The Author'), ('RL', 'A Location'), ('RC', 'A Runon Comment')])]}) self.assertEqual(msa, exp) def test_stockholm_mixed_runon_references(self): fp = get_data_path('stockholm_runon_references_mixed') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA( [], metadata={'RN': [OrderedDict([('RC', 'A Runon Comment'), ('RM', '123456789'), ('RT', 'A Runon Title'), ('RA', 'The Author'), ('RL', 'A Location')])]}) self.assertEqual(msa, exp) def test_stockholm_to_msa_different_padding(self): fp = get_data_path('stockholm_different_padding') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA( [], metadata={'RN': [OrderedDict([('RC', 'A Runon Comment Without ' 'Whitespace')]), OrderedDict([('RC', 'A Runon Comment With ' 'Whitespace')])]}) self.assertEqual(msa, exp) def test_stockholm_handles_missing_reference_items(self): fp = get_data_path('stockholm_missing_reference_items') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA( [], metadata={'RN': [OrderedDict([('RT', 'A Title'), ('RA', 'The Author')])]}) self.assertEqual(msa, exp) def test_stockholm_multi_line_tree_no_id(self): fp = get_data_path('stockholm_multi_line_tree_no_id') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([], metadata={'NH': 'ABCDEFGH'}) self.assertEqual(msa, exp) def test_stockholm_multiple_multi_line_trees(self): fp = get_data_path('stockholm_multiple_multi_line_trees') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([], metadata={'NH': {'tree1': 'ABCDEFGH', 'tree2': 'IJKLMNOP'}}) self.assertEqual(msa, exp) def test_stockholm_multi_line_tree_with_id(self): fp = get_data_path('stockholm_multi_line_tree_with_id') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) exp = TabularMSA([], metadata={'NH': {'tree1': 'ABCDEFGH'}}) self.assertEqual(msa, exp) def test_multiple_msa_file(self): fp = get_data_path('stockholm_multiple_msa') msa = _stockholm_to_tabular_msa(fp, constructor=RNA) exp = TabularMSA([RNA('AAGGGUUAUUUAUAUACUUU', metadata={'id': 'RTC2231'}), RNA('UGCUAAGAGUGGGGAUGAUU', metadata={'id': 'RTF2124'}), RNA('GCCACAACCGAUUAGAUAGA', metadata={'id': 'RTH3322'}), RNA('UUAGAAACCGAUGGACCGAA', metadata={'id': 'RTB1512'})], metadata={'AC': 'G2134T23', 'ID': 'ARD'}, positional_metadata=( {'AC_cons': list('GGGACUGGACAUCUAUUCAG')}), index=['RTC2231', 'RTF2124', 'RTH3322', 'RTB1512']) self.assertEqual(msa, exp) def test_stockholm_maintains_order(self): fp = get_data_path('stockholm_two_of_each_metadata') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) msa_order = list(msa.metadata.items()) exp_order = [('NM', 'Kestrel Gorlick'), ('DT', 'February 5th, 2016')] self.assertEqual(msa_order, exp_order) msa_order = list(msa[0].metadata.items()) exp_order = [('id', 'seq1'), ('AL', 'ABCD'), ('NS', '1234')] self.assertEqual(msa_order, exp_order) msa_order = list(msa.positional_metadata.columns) exp_order = ['SS_cons', 'AS_cons'] self.assertEqual(msa_order, exp_order) msa_order = list(msa[0].positional_metadata.columns) exp_order = ['SS', 'AS'] self.assertEqual(msa_order, exp_order) def test_stockholm_duplicate_tree_id_error(self): fp = get_data_path('stockholm_duplicate_tree_ids') with self.assertRaisesRegex(StockholmFormatError, r'Tree.*tree1.*in file.'): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_stockholm_missing_reference_number_error(self): fp = get_data_path('stockholm_missing_rn_tag') with self.assertRaisesRegex(StockholmFormatError, r"Expected 'RN'.*'RL' tag."): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_nonexistent_gr_error(self): fp = get_data_path('stockholm_invalid_nonexistent_gr') with self.assertRaisesRegex(StockholmFormatError, r'GS or GR.*nonexistent ' 'sequence.*RL1355.'): _stockholm_to_tabular_msa(fp, constructor=RNA) def test_nonexistent_gs_error(self): fp = get_data_path('stockholm_invalid_nonexistent_gs') with self.assertRaisesRegex(StockholmFormatError, r'GS or GR.*nonexistent sequence.*AC14.'): _stockholm_to_tabular_msa(fp, constructor=RNA) def test_duplicate_sequence_names_error(self): fp = get_data_path('stockholm_duplicate_sequence_names') with self.assertRaisesRegex( StockholmFormatError, r'duplicate sequence name.*ASR132.*supported by the reader.'): _stockholm_to_tabular_msa(fp, constructor=RNA) def test_duplicate_gr_error(self): fp = get_data_path('stockholm_duplicate_gr') with self.assertRaisesRegex(StockholmFormatError, r'Found duplicate GR.*OS.*LFDR3.*supported' ' by the reader.'): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_duplicate_gc_error(self): fp = get_data_path('stockholm_duplicate_gc') with self.assertRaisesRegex(StockholmFormatError, r'Found duplicate GC.*SS_cons.*supported ' 'by the reader.'): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_empty_file_error(self): fp = get_data_path('empty') with self.assertRaisesRegex(StockholmFormatError, r'File is empty.'): _stockholm_to_tabular_msa(fp, constructor=RNA) def test_missing_header_error(self): fp = get_data_path('stockholm_missing_header') with self.assertRaisesRegex(StockholmFormatError, r'File missing.*header'): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_missing_footer_error(self): fp = get_data_path('stockholm_missing_footer') with self.assertRaisesRegex(StockholmFormatError, r'Final line.*only "//".'): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_data_type_error(self): fp = get_data_path('stockholm_invalid_data_type') with self.assertRaisesRegex(StockholmFormatError, r"Unrecognized.*'#=GZ"): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_malformed_gf_line_error(self): fp = get_data_path('stockholm_malformed_gf_line') with self.assertRaisesRegex(StockholmFormatError, r'Line contains 2.*must contain.*3.'): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_malformed_gs_line_error(self): fp = get_data_path('stockholm_malformed_gs_line') with self.assertRaisesRegex(StockholmFormatError, r'Line contains 3.*must contain.*4.'): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_malformed_gr_line_error(self): fp = get_data_path('stockholm_malformed_gr_line') with self.assertRaisesRegex(StockholmFormatError, r'Line contains 2.*must contain.*4.'): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_malformed_gc_line_error(self): fp = get_data_path('stockholm_malformed_gc_line') with self.assertRaisesRegex(StockholmFormatError, r'Line contains 2.*must contain.*3.'): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_malformed_data_line_error(self): fp = get_data_path('stockholm_malformed_data_line') with self.assertRaisesRegex(StockholmFormatError, r'Line contains 1.*must contain.*2.'): _stockholm_to_tabular_msa(fp, constructor=DNA) def test_differing_sequence_lengths_error(self): fp = get_data_path('stockholm_differing_seq_lengths') with self.assertRaisesRegex(ValueError, r'Each sequence.*11 != 10'): _stockholm_to_tabular_msa(fp, constructor=RNA) def test_differing_data_lengths_gr_error(self): fp = get_data_path('stockholm_differing_gr_data_length') with self.assertRaisesRegex(ValueError, r'Number.*7.*(8).'): _stockholm_to_tabular_msa(fp, constructor=RNA) def test_differing_data_lengths_gc_error(self): fp = get_data_path('stockholm_differing_gc_data_length') with self.assertRaisesRegex(ValueError, r'Number.*12.*(10).'): _stockholm_to_tabular_msa(fp, constructor=RNA) def test_no_constructor_error(self): fp = get_data_path('empty') with self.assertRaisesRegex(ValueError, r'Must provide.*parameter.'): _stockholm_to_tabular_msa(fp) def test_unsupported_constructor_error(self): fp = get_data_path('empty') with self.assertRaisesRegex(TypeError, r'`constructor`.*`GrammaredSequence`.'): _stockholm_to_tabular_msa(fp, constructor=TabularMSA) class TestStockholmWriter(unittest.TestCase): def test_msa_to_stockholm_extensive(self): fp = get_data_path('stockholm_all_data_types') msa = TabularMSA([DNA('GAGGCCATGCCCAGGTGAAG', metadata=OrderedDict([('DT', 'February 1, 2016'), ('NM', 'Unknown')])), DNA('ACCTGAGCCACAGTAGAAGT'), DNA('CCCTTCGCTGGAAATGTATG', metadata={'DT': 'Unknown'}, positional_metadata=OrderedDict([('AS', list('CCGAAAGT' 'CGTTCGA' 'AAATG')), ('SS', list('GGCGAGTC' 'GTTCGAGC' 'TGG' 'C'))]))], metadata=OrderedDict([('NM', 'Kestrel Gorlick'), ('DT', 'February 11, 2016'), ('FN', 'Writer test file')]), positional_metadata=OrderedDict([('AS_cons', list('CGTTCGTTCTAAC' 'AATTCCA')), ('SS_cons', list('GGCGCTACGACCT' 'ACGACCG'))]), index=['seq1', 'seq2', 'seq3']) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_msa_to_stockholm_minimal(self): fp = get_data_path('stockholm_minimal') msa = TabularMSA([DNA('TGTGTCGCAGTTGTCGTTTG')], index=['0235244']) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_msa_to_stockholm_single_tree(self): fp = get_data_path('stockholm_single_tree_without_id') msa = TabularMSA([], metadata=OrderedDict([('NH', 'ABCD')])) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_msa_to_stockholm_single_tree_as_dict(self): fp = get_data_path('stockholm_single_tree_with_id') msa = TabularMSA([], metadata={'NH': {'tree1': 'ABCD'}}) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_msa_to_stockholm_multiple_trees(self): fp = get_data_path('stockholm_multiple_trees') msa = TabularMSA([], metadata=OrderedDict([('NH', OrderedDict([('tree1', 'ABCD'), ('tree2', 'EFGH'), ('tree3', 'IJKL')]))])) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_msa_to_stockholm_single_reference(self): fp = get_data_path('stockholm_single_reference') msa = TabularMSA( [], metadata={'RN': [OrderedDict([('RM', '123456789'), ('RT', 'A Title'), ('RA', 'The Author'), ('RL', 'A Location'), ('RC', 'Comment')])]}) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_msa_to_stockholm_multiple_references(self): fp = get_data_path('stockholm_multiple_references') msa = TabularMSA( [], metadata={'RN': [OrderedDict([('RM', '123456789'), ('RT', 'Title 1'), ('RA', 'Author 1'), ('RL', 'Location 1'), ('RC', 'Comment 1')]), OrderedDict([('RM', '987654321'), ('RT', 'Title 2'), ('RA', 'Author 2'), ('RL', 'Location 2'), ('RC', 'Comment 2')]), OrderedDict([('RM', '132465879'), ('RT', 'Title 3'), ('RA', 'Author 3'), ('RL', 'Location 3'), ('RC', 'Comment 3')])]}) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_msa_to_stockholm_data_only(self): fp = get_data_path('stockholm_data_only') msa = TabularMSA([RNA('ACUCCGACAUGCUCC'), RNA('UAGUGCCGAACGCUG'), RNA('GUGUGGGCGUGAUUC')], index=['seq1', 'seq2', 'seq3']) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_msa_to_stockholm_nonstring_values(self): fp = get_data_path('stockholm_nonstring_labels') msa = TabularMSA([DNA('ACTG', metadata=OrderedDict([(8, 123)]), positional_metadata=OrderedDict([(1.0, [1, 2, 3, 4])]) )], metadata=OrderedDict([(1.3, 2857)]), positional_metadata=OrderedDict([(25, [4, 3, 2, 1])]), index=[11214]) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_msa_to_stockholm_empty(self): fp = get_data_path('stockholm_no_data') msa = TabularMSA([]) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_round_trip_extensive(self): fp = get_data_path('stockholm_extensive') msa = _stockholm_to_tabular_msa(fp, constructor=Protein) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_round_trip_minimal(self): fp = get_data_path('stockholm_minimal') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_round_trip_single_tree(self): fp = get_data_path('stockholm_single_tree_without_id') msa = _stockholm_to_tabular_msa(fp, constructor=Protein) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_round_trip_multiple_trees(self): fp = get_data_path('stockholm_multiple_trees') msa = _stockholm_to_tabular_msa(fp, constructor=Protein) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_round_trip_single_reference(self): fp = get_data_path('stockholm_single_reference') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_round_trip_multiple_references(self): fp = get_data_path('stockholm_multiple_references') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_round_trip_missing_references(self): fp = get_data_path('stockholm_missing_reference_items') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_round_trip_data_only(self): fp = get_data_path('stockholm_data_only') msa = _stockholm_to_tabular_msa(fp, constructor=RNA) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_round_trip_nonstring_index_values(self): fp = get_data_path('stockholm_nonstring_labels') msa = _stockholm_to_tabular_msa(fp, constructor=DNA) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_round_trip_empty(self): fp = get_data_path('stockholm_no_data') msa = _stockholm_to_tabular_msa(fp, constructor=Protein) fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) obs = fh.getvalue() fh.close() with io.open(fp) as fh: exp = fh.read() self.assertEqual(obs, exp) def test_unoriginal_index_error(self): msa = TabularMSA([DNA('ATCGCCAGCT'), DNA('TTGTGCTGGC')], index=['seq1', 'seq1']) with self.assertRaisesRegex(StockholmFormatError, r'index labels must be unique.'): fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) def test_unoriginal_gr_feature_names_error(self): pos_metadata_dataframe = pd.DataFrame( [ list('GAGCAAGCCACTAGA'), list('TCCTTGAACTACCCG'), list('TCAGCTCTGCAGCGT'), list('GTCAGGCGCTCGGTG') ], index=['AC', 'SS', 'AS', 'AC'] ).T msa = TabularMSA([DNA('CGTCAATCTCGAACT', positional_metadata=pos_metadata_dataframe)], index=['seq1']) with self.assertRaisesRegex(StockholmFormatError, r'Sequence-specific positional metadata.*' 'must be unique. Found 1 duplicate'): fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) def test_unoriginal_gc_feature_names_error(self): pos_metadata_dataframe = pd.DataFrame( [ list('GAGCAAGCCACTAGA'), list('TCCTTGAACTACCCG'), list('TCAGCTCTGCAGCGT'), list('GTCAGGCGCTCGGTG') ], index=['AC', 'SS', 'SS', 'AC'] ).T msa = TabularMSA([DNA('CCCCTGCTTTCGTAG')], positional_metadata=pos_metadata_dataframe) with self.assertRaisesRegex(StockholmFormatError, r'Multiple sequence alignment positional ' 'metadata.*must be unique. Found 2 ' 'duplicate'): fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) def test_gr_wrong_dataframe_item_length_error(self): seq1 = list('GAGCAAGCCACTAGA') seq1.append('GG') pos_metadata_dataframe = pd.DataFrame({'AC': seq1, 'SS': list('TCCTTGAACTACCCGA'), 'AS': list('TCAGCTCTGCAGCGTT')}) msa = TabularMSA([DNA('TCCTTGAACTACCCGA', positional_metadata=pos_metadata_dataframe)]) with self.assertRaisesRegex(StockholmFormatError, r'Sequence-specific positional metadata.*' r'must contain a single character.*Found ' r'value\(s\) in column AC'): fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) def test_gc_wrong_dataframe_item_length_error(self): seq1 = list('GAGCAAGCCACTAGA') seq1.append('GG') pos_metadata_dataframe = pd.DataFrame({'AC': seq1, 'SS': list('TCCTTGAACTACCCGA'), 'AS': list('TCAGCTCTGCAGCGTT')}) msa = TabularMSA([DNA('TCCTTGAACTACCCGA')], positional_metadata=pos_metadata_dataframe) message = (r'Multiple sequence alignment positional metadata.*must ' r'contain a single character.*Found value\(s\) in column ' 'AC') with self.assertRaisesRegex(StockholmFormatError, message): fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) def test_rn_not_list_of_refs_error(self): msa = TabularMSA([], metadata={'RN': '1'}) with self.assertRaisesRegex(StockholmFormatError, r"Expected 'RN'.*list of reference" ".*got '1'"): fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) def test_rn_data_not_in_dict_error(self): msa = TabularMSA([], metadata={'RN': [OrderedDict([('RL', 'Flagstaff')]), 'Incorrect Item']}) with self.assertRaisesRegex(StockholmFormatError, r"Expected reference information.*stored" " as a dictionary, found.*2 stored as " "'str'"): fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) def test_invalid_reference_tag_error(self): msa = TabularMSA([], metadata={'RN': [OrderedDict([('RL', 'Flagstaff'), ('foo', 'bar')])]}) with self.assertRaisesRegex(StockholmFormatError, r"Invalid reference.*foo' found " "in.*1.*Valid reference tags are:"): fh = io.StringIO() _tabular_msa_to_stockholm(msa, fh) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/format/tests/test_taxdump.py000066400000000000000000000175671520735541300256360ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from io import StringIO import pandas as pd import numpy as np from skbio.util import get_data_path, assert_data_frame_almost_equal from skbio.util._testing import _data_frame_to_default_int_type from skbio.io.format.taxdump import _taxdump_to_data_frame class TestTaxdumpReader(unittest.TestCase): def test_nodes_default(self): # subset of a real NCBI taxonomy nodes.dmp file fp = get_data_path('taxdump_nodes.dmp') obs = _taxdump_to_data_frame(fp, scheme='nodes') exp = pd.DataFrame([ [1, 1, 'no rank', np.nan, 8, False, 1, False, 0, False, False, False, np.nan], [2, 131567, 'superkingdom', np.nan, 0, False, 11, False, 0, False, False, False, np.nan], [543, 91347, 'family', np.nan, 0, True, 11, True, 0, True, False, False, np.nan], [548, 570, 'species', 'KA', 0, True, 11, True, 0, True, True, False, np.nan], [561, 543, 'genus', np.nan, 0, True, 11, True, 0, True, False, False, np.nan], [562, 561, 'species', 'EC', 0, True, 11, True, 0, True, True, False, np.nan], [570, 543, 'genus', np.nan, 0, True, 11, True, 0, True, False, False, np.nan], [620, 543, 'genus', np.nan, 0, True, 11, True, 0, True, False, False, np.nan], [622, 620, 'species', 'SD', 0, True, 11, True, 0, True, True, False, np.nan], [766, 28211, 'order', np.nan, 0, True, 11, True, 0, True, False, False, np.nan], [1224, 2, 'phylum', np.nan, 0, True, 11, True, 0, True, False, False, np.nan], [1236, 1224, 'class', np.nan, 0, True, 11, True, 0, True, False, False, np.nan], [28211, 1224, 'class', np.nan, 0, True, 11, True, 0, True, False, False, np.nan], [91347, 1236, 'order', np.nan, 0, True, 11, True, 0, True, False, False, np.nan], [118884, 1236, 'no rank', np.nan, 0, True, 11, True, 0, True, True, False, np.nan], [126792, 36549, 'species', 'PP', 0, True, 11, True, 0, True, True, False, np.nan], [131567, 1, 'no rank', np.nan, 8, True, 1, True, 0, True, True, False, np.nan], [585056, 562, 'no rank', np.nan, 0, True, 11, True, 0, True, True, False, np.nan], [1038927, 562, 'no rank', np.nan, 0, True, 11, True, 0, True, True, False, np.nan], [2580236, 488338, 'species', 'SE', 7, True, 11, True, 0, True, False, False, np.nan]], columns=[ 'tax_id', 'parent_tax_id', 'rank', 'embl_code', 'division_id', 'inherited_div_flag', 'genetic_code_id', 'inherited_GC_flag', 'mitochondrial_genetic_code_id', 'inherited_MGC_flag', 'GenBank_hidden_flag', 'hidden_subtree_root_flag', 'comments']).set_index('tax_id') exp['comments'] = exp['comments'].astype('O') obs['comments'] = obs['comments'].astype('O') _data_frame_to_default_int_type(exp) assert_data_frame_almost_equal(obs, exp) def test_names_default(self): # subset of a real NCBI taxonomy names.dmp file fp = get_data_path('taxdump_names.dmp') obs = _taxdump_to_data_frame(fp, scheme='names') exp = pd.DataFrame([ [1, 'root', np.nan, 'scientific name'], [2, 'Bacteria', 'Bacteria ', 'scientific name'], [2, 'eubacteria', np.nan, 'genbank common name'], [543, 'Enterobacteriaceae', np.nan, 'scientific name'], [548, 'Klebsiella aerogenes', np.nan, 'scientific name'], [561, 'Escherichia', np.nan, 'scientific name'], [562, '"Bacillus coli" Migula 1895', np.nan, 'authority'], [562, 'Escherichia coli', np.nan, 'scientific name'], [562, 'Escherichia/Shigella coli', np.nan, 'equivalent name'], [570, 'Donovania', np.nan, 'synonym'], [570, 'Klebsiella', np.nan, 'scientific name'], [620, 'Shigella', np.nan, 'scientific name'], [622, 'Shigella dysenteriae', np.nan, 'scientific name'], [766, 'Rickettsiales', np.nan, 'scientific name'], [1224, 'Proteobacteria', np.nan, 'scientific name'], [1236, 'Gammaproteobacteria', np.nan, 'scientific name'], [28211, 'Alphaproteobacteria', np.nan, 'scientific name'], [91347, 'Enterobacterales', np.nan, 'scientific name'], [118884, 'unclassified Gammaproteobacteria', np.nan, 'scientific name'], [126792, 'Plasmid pPY113', np.nan, 'scientific name'], [131567, 'cellular organisms', np.nan, 'scientific name'], [585056, 'Escherichia coli UMN026', np.nan, 'scientific name'], [1038927, 'Escherichia coli O104:H4', np.nan, 'scientific name'], [2580236, 'synthetic Escherichia coli Syn61', np.nan, 'scientific name']], columns=['tax_id', 'name_txt', 'unique_name', 'name_class']).set_index('tax_id') assert_data_frame_almost_equal(obs, exp) def test_nodes_slim(self): fp = get_data_path('taxdump_nodes.dmp') obs = _taxdump_to_data_frame(fp, scheme='nodes_slim') exp = pd.DataFrame([ [1, 1, 'no rank'], [2, 131567, 'superkingdom'], [543, 91347, 'family'], [548, 570, 'species'], [561, 543, 'genus'], [562, 561, 'species'], [570, 543, 'genus'], [620, 543, 'genus'], [622, 620, 'species'], [766, 28211, 'order'], [1224, 2, 'phylum'], [1236, 1224, 'class'], [28211, 1224, 'class'], [91347, 1236, 'order'], [118884, 1236, 'no rank'], [126792, 36549, 'species'], [131567, 1, 'no rank'], [585056, 562, 'no rank'], [1038927, 562, 'no rank'], [2580236, 488338, 'species']], columns=['tax_id', 'parent_tax_id', 'rank']).set_index('tax_id') _data_frame_to_default_int_type(exp) assert_data_frame_almost_equal(obs, exp) def test_custom_scheme(self): fs = StringIO('\n'.join(map('\t|\t'.join, [ ('a', 'a'), ('b', 'a'), ('c', 'a') ]))) obs = _taxdump_to_data_frame(fs, scheme={'self': str, 'parent': str}) exp = pd.DataFrame([ ['a', 'a'], ['b', 'a'], ['c', 'a']], columns=['self', 'parent']).set_index('self') assert_data_frame_almost_equal(obs, exp) def test_invalid_scheme(self): fp = get_data_path('taxdump_names.dmp') with self.assertRaises(ValueError) as ctx: _taxdump_to_data_frame(fp, scheme='hello') self.assertEqual(str(ctx.exception), 'Invalid taxdump column scheme: "hello".') def test_invalid_id(self): fs = StringIO('\n'.join(map('\t|\t'.join, [ ('1', '2', 'family'), ('3', '4', 'genus'), ('x', '6', 'species'), # 'x' is not a number ]))) with self.assertRaises(ValueError) as ctx: _taxdump_to_data_frame(fs, scheme='nodes_slim') self.assertEqual(str(ctx.exception), 'Invalid taxdump file format.') if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/registry.py000066400000000000000000001160031520735541300223140ustar00rootroot00000000000000r"""I/O Registry (:mod:`skbio.io.registry`) ======================================= .. currentmodule:: skbio.io.registry Classes ------- .. autosummary:: :toctree: IORegistry Format Functions --------- .. autosummary:: :toctree: create_format Exceptions ---------- .. autosummary:: DuplicateRegistrationError InvalidRegistrationError Creating a new format for scikit-bio ------------------------------------ scikit-bio makes it simple to add new file formats to its I/O registry. scikit-bio maintains a singleton of the :class:`IORegistry` class called `io_registry`. This is where all scikit-bio file formats are registered. One could also instantiate their own :class:`IORegistry`, but that is not the focus of this tutorial. The first step to creating a new format is to add a submodule in `skbio/io/format/` named after the file format you are implementing. For example, if the format you are implementing is called `myformat` then you would create a file called `skbio/io/format/myformat.py`. The next step is to import the :func:`create_format` factory from :mod:`skbio.io`. This will allow you to create a new :class:`Format` object that `io_registry` will know about. Ideally you should name the result of :func:`create_format` as your file name. For example: .. code-block:: python from skbio.io import create_format myformat = create_format('myformat') The `myformat` object is what we will use to register our new functionality. At this point you should evaluate whether your format is binary or text. If your format is binary, your :func:`create_format` call should look like this: .. code-block:: python myformat = create_format('myformat', encoding='binary') Alternatively if your format is text and has a specific encoding or newline handling you can also specify that: .. code-block:: python myformat = create_format('myformat', encoding='ascii', newline='\n') This will ensure that our registry will open files with a default encoding of `'ascii'` for `'myformat'` and expect all newlines to be `'\n'` characters. Having worked out these details, we are ready to register the actual functionality of our format (e.g., sniffer, readers, and writers). To create a sniffer simply decorate the following onto your sniffer function: .. code-block:: python @myformat.sniffer() def _myformat_sniffer(fh): # do something with `fh` to determine the membership of the file For further details on sniffer functions see :func:`Format.sniffer`. Creating a reader is very similar, but has one difference: .. code-block:: python @myformat.reader(SomeSkbioClass) def _myformat_to_some_skbio_class(fh, kwarg1='default', extra=FileSentinel): # parse `fh` and return a SomeSkbioClass instance here # `extra` will also be an open filehandle if provided else None Here we bound a function to a specific class. We also demonstrated using our FileSentinel object to indicate to the registry that this reader can take auxiliary files that should be handled in the same way as the primary file. For further details on reader functions see :func:`Format.reader`. Creating a writer is about the same: .. code-block:: python @myformat.writer(SomeSkbioClass) def _some_skbio_class_to_myformat(obj, fh, kwarg1='whatever', extra=FileSentinel): # write the contents of `obj` into `fh` and whatever else into `extra` # do not return anything, it will be ignored This is exactly the same as the `reader` above just in reverse, we also receive the object we are writing as the first parameter instead of the file (which is the second one). For further details on writer functions see :func:`Format.writer`. .. note:: When raising errors in readers and writers, the error should be a subclass of ``FileFormatError`` specific to your new format. Once you are satisfied with the functionality, you will need to ensure that `skbio/io/__init__.py` contains an import of your new submodule so the decorators are executed. Add the function ``import_module('skbio.io.format.myformat')`` with your module name to the existing list. .. note:: Because scikit-bio handles all of the I/O boilerplate, you only need to unit-test the actual business logic of your `readers`, `writers`, and `sniffers`. Reserved Keyword Arguments -------------------------- The following keyword args may not be used when defining new `readers` or `writers` as they already have special meaning to the registry system: - `format` - `into` - `verify` - `mode` - `encoding` - `errors` - `newline` - `compression` - `compresslevel` The following are not yet used but should be avoided as well: - `auth` - `user` - `password` - `buffering` - `buffer_size` - `closefd` - `exclusive` - `append` """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from warnings import warn import types import traceback import itertools import inspect from functools import wraps import skbio from ._exception import DuplicateRegistrationError, InvalidRegistrationError from . import ( UnrecognizedFormatError, ArgumentOverrideWarning, FormatIdentificationWarning, ) from .util import _resolve_file, open_file, open_files, _d as _open_kwargs from skbio.util._misc import make_sentinel, find_sentinels from skbio.util._decorator import classonlymethod from skbio._base import SkbioObject FileSentinel = make_sentinel("FileSentinel") class IORegistry: """Create a registry of formats and implementations which map to classes.""" def __init__(self): """Initialize registry mapping formats and implementations to classes. This separation of binary and text formats is useful because there are many situations where we may have received a text-file. When this happens, the binary data fundamentally does not exist. We could assume encoding should be interpreted in reverse, however this misses the bigger point: why would the user ever want text to be treated as binary? They already went through the effort to hand us text. Therefore, during format resolution, we should skip the binary formats if they are irrelevant. (They are incompatible with such a filehandle anyways.) """ self._binary_formats = {} self._text_formats = {} self._lookups = (self._binary_formats, self._text_formats) def create_format(self, *args, **kwargs): """Create new file formats. A simple factory for creating new file formats. This will automatically register the format with this regsistry. All arguments are passed through to the Format constructor. Returns ------- Format A new format that is registered with the registry. """ format = Format(*args, **kwargs) self.add_format(format) return format def add_format(self, format_object): """Add a format to the registry. Parameters ---------- format_object : Format The format to add to the registry. """ # See comment in the constructor for an explanation for why this split # occurs. name = format_object.name if name in self._binary_formats or name in self._text_formats: raise DuplicateRegistrationError( "A format already exists with that name: %s" % name ) if format_object.is_binary_format: self._binary_formats[name] = format_object else: self._text_formats[name] = format_object def remove_format(self, format): """Remove a format from the IORegistry. Parameters ---------- format : str or Format object The format to be removed from the registry. It can be a name or the Format object itself. """ if isinstance(format, skbio.io.registry.Format): format = format.name success = False for lookup in self._lookups: if format in lookup: del lookup[format] success = True break if not success: raise KeyError(f"Format {format} is not in the IO registry.") def get_sniffer(self, format_name): """Locate the sniffer for a format. Parameters ---------- format_name : str The name of the format to lookup. Returns ------- function or None The sniffer associated with `format_name` """ for lookup in self._lookups: if format_name in lookup: return lookup[format_name].sniffer_function return None def get_reader(self, format_name, cls): """Locate the reader for a format and class. Parameters ---------- format_name : str The name of the format to lookup. cls : type or None The class which the reader will return an instance of. If `cls` is None, the reader will return a generator. Default is None. Returns ------- function or None The reader associated with `format_name` and `cls` """ return self._get_rw(format_name, cls, "readers") def get_writer(self, format_name, cls): """Locate the writer for a format and class. Parameters ---------- format_name : str The name of the format to lookup. cls : type or None The class which the writer will expect an instance of. If `cls` is None, the writer will expect a generator. Default is None. Returns ------- function or None The writer associated with `format_name` and `cls` """ return self._get_rw(format_name, cls, "writers") def _get_rw(self, format_name, cls, lookup_name): if cls is None: # Handle generator case (cls=None) for lookup in self._lookups: if format_name in lookup: format_lookup = getattr(lookup[format_name], lookup_name) if cls in format_lookup: return format_lookup[cls] return None for parent in cls.__mro__: # stop iteration at base class if parent is SkbioObject: break for lookup in self._lookups: if format_name in lookup: format_lookup = getattr(lookup[format_name], lookup_name) if parent in format_lookup: return format_lookup[parent] return None def list_read_formats(self, cls): """Return a list of available read formats for a given `cls` type. Parameters ---------- cls : type The class which will be used to determine what read formats exist for an instance of `cls`. Returns ------- list A list of available read formats for an instance of `cls`. List may be empty. """ return list(self._iter_rw_formats(cls, "readers")) def list_write_formats(self, cls): """Return a list of available write formats for a given `cls` type. Parameters ---------- cls : type The class which will be used to determine what write formats exist for an instance of `cls`. Returns ------- list A list of available write formats for an instance of `cls`. List may be empty. """ return list(self._iter_rw_formats(cls, "writers")) def _iter_rw_formats(self, cls, lookup_name): for lookup in self._lookups: for format in lookup.values(): if self._get_rw(format.name, cls, lookup_name) is not None: yield format.name def sniff(self, file, into=None, **kwargs): r"""Detect the format of a given file and suggest kwargs for reading. Parameters ---------- file : openable (filepath, URL, filehandle, etc.) The file to sniff. Something that is understood by :func:`skbio.io.open`. kwargs : dict, optional Keyword arguments will be passed to :func:`skbio.io.open`. ``newline`` cannot be provided. Returns ------- (str, dict) The name of the format of the file and any suggested kwargs for use with the corresponding reader. Raises ------ UnrecognizedFormatError This occurs when the format is not 'claimed' by any registered sniffer or when the format is ambiguous and has been 'claimed' by more than one sniffer. TypeError If ``newline`` is provided in ``kwargs``. """ if "newline" in kwargs: raise TypeError("Cannot provide `newline` keyword argument when sniffing.") # By resolving the input here, we have the opportunity to reuse the # file (which is potentially ephemeral). Each sniffer will also resolve # the file, but that call will short-circuit and won't claim # responsibility for closing the file. This means that the file # should only close after leaving this context. This is also the reason # that we have to use SaneTextIOWrapper because each sniffer will # wrap the file to produce an appropriate default encoding for their # format (if unspecified). This results in the SaneTextIOWrapper being # garbage collected (using io.TextIOBase results in close being called # on our buffer by the deconstructor which we wanted to share with the # next sniffer) with _resolve_file(file, mode="r", **kwargs) as (fh, _, is_binary_file): # tell may fail noisily if the user provided a TextIOBase or # BufferedReader which has already been iterated over (via next()). matches = [] backup = fh.tell() if is_binary_file and kwargs.get("encoding", "binary") == "binary": bin_lookup = self._binary_formats if into is not None: bin_lookup = self._reduce_formats(bin_lookup, into) matches = self._find_matches(fh, bin_lookup, **kwargs) if kwargs.get("encoding", None) != "binary": # We can always turn a binary file into a text file, but the # reverse doesn't make sense. text_lookup = self._text_formats if into is not None: text_lookup = self._reduce_formats(text_lookup, into) matches += self._find_matches(fh, text_lookup, **kwargs) fh.seek(backup) elif not is_binary_file: raise ValueError("Cannot decode text source (%r) as binary." % file) # else we are a binary_file and our encoding did not exclude binary # so we have already handled that condition if len(matches) > 1: raise UnrecognizedFormatError( "File format for %r is ambiguous," " may be one of: %r" % (file, [m for m, s in matches]) ) elif len(matches) == 0: raise UnrecognizedFormatError("Could not detect the format of %r" % file) return matches[0] def _reduce_formats(self, lookup, into): """Reduce possible formats to only those which make sense for the given object.""" pos_fmts = self.list_read_formats(into) return {k: v for k, v in lookup.items() if k in pos_fmts} def _find_matches(self, file, lookup, **kwargs): matches = [] for format in lookup.values(): if format.sniffer_function is not None: is_format, skwargs = format.sniffer_function(file, **kwargs) file.seek(0) if is_format: matches.append((format.name, skwargs)) return matches def read(self, file, format=None, into=None, verify=True, **kwargs): r"""Read a file as certain format into an object. Parameters ---------- file : openable (filepath, URL, filehandle, etc.) The file to read. Something that is understood by :func:`skbio.io.open`. format : str, optional The format of the file if known. If None, the format will be inferred from the file. into : type or None, optional The object which will be returned. If None, a generator will be returned. verify : bool, optional When True, will double check the ``format`` if provided. kwargs : dict, optional Keyword arguments will be passed to their respective handlers (:func:`skbio.io.open` and the reader for ``format``). ``newline`` cannot be provided. Returns ------- object or generator An instance of ``into`` if ``into`` is not None else generator Raises ------ ValueError Raised when ``format`` and ``into`` are both None. TypeError If ``newline`` is provided in ``kwargs``. UnrecognizedFormatError Raised when a reader could not be found for a given ``format`` or the format could not be guessed. FormatIdentificationWarning Raised when ``verify`` is True and the sniffer of a ``format`` did not agree that ``file`` is a member of ``format`` ArgumentOverrideWarning Raised when ``verify`` is True and a user-supplied argument is overriding the suggestion provided by the sniffer of ``format``. """ if "newline" in kwargs: raise TypeError("Cannot provide `newline` keyword argument when reading.") # Context managers do not compose well with generators. We have to # duplicate the logic so that the file will stay open while yielding. # Otherwise the context exits as soon as the generator is returned # (making any iteration fail as the file is closed from its # perspective). if into is None: if format is None: raise ValueError("`into` and `format` cannot both be None") gen = self._read_gen(file, format, into, verify, kwargs) # This is done so that any errors occur immediately instead of # on the first call from __iter__ # eta-reduction is possible, but we want to the type to be # GeneratorType try: return (x for x in itertools.chain([next(gen)], gen)) except StopIteration: # If the error was a StopIteration, then we want to return an # empty generator as `next(gen)` failed. # See #1313 for more info. return (x for x in []) else: return self._read_ret(file, format, into, verify, kwargs) def _read_ret(self, file, fmt, into, verify, kwargs): io_kwargs = self._find_io_kwargs(kwargs) with _resolve_file(file, **io_kwargs) as (file, _, _): reader, kwargs = self._init_reader( file, fmt, into, verify, kwargs, io_kwargs ) return reader(file, cls=into, **kwargs) def _read_gen(self, file, fmt, into, verify, kwargs): io_kwargs = self._find_io_kwargs(kwargs) # We needed to get the io_kwargs from kwargs for things like # _resolve_file and for verifying a format. # kwargs should still retain the contents of io_kwargs because the # actual reader will also need them. with _resolve_file(file, **io_kwargs) as (file, _, _): reader, kwargs = self._init_reader( file, fmt, into, verify, kwargs, io_kwargs ) yield from reader(file, cls=into, **kwargs) def _find_io_kwargs(self, kwargs): return {k: kwargs[k] for k in _open_kwargs if k in kwargs} def _init_reader(self, file, fmt, into, verify, kwargs, io_kwargs): skwargs = {} if fmt is None: fmt, skwargs = self.sniff(file, into, **io_kwargs) elif verify: sniffer = self.get_sniffer(fmt) if sniffer is not None: backup = file.tell() is_format, skwargs = sniffer(file, **io_kwargs) file.seek(backup) if not is_format: warn( "%r does not look like a %s file" % (file, fmt), FormatIdentificationWarning, ) for key in skwargs: if key not in kwargs: kwargs[key] = skwargs[key] elif kwargs[key] != skwargs[key]: warn( "Best guess was: %s=%r, continuing with user" " supplied: %r" % (key, skwargs[key], kwargs[key]), ArgumentOverrideWarning, ) reader = self.get_reader(fmt, into) if reader is None: possible_intos = [r.__name__ for r in self._get_possible_readers(fmt)] message = "" if possible_intos: message = "Possible values for `into` include: %s" % ", ".join( possible_intos ) into_message = "`into` also not provided." if not into else "" raise UnrecognizedFormatError( "Cannot read %r from %r, no %s reader found. %s %s" % ( fmt, file, into.__name__ if into else "generator", into_message, message, ) ) return reader, kwargs def _get_possible_readers(self, fmt): for lookup in self._lookups: if fmt in lookup: return list(lookup[fmt].readers) return [] def write(self, obj, format, into, **kwargs): r"""Write an object as certain format into a file. Parameters ---------- obj : object The object to write as ``format``. format : str The format to write ``obj`` as. into : openable (filepath, URL, filehandle, etc.) What to write ``obj`` to. Something that is understood by :func:`skbio.io.open`. kwargs : dict, optional Keyword arguments will be passed to their respective handlers (:func:`skbio.io.open` and the writer for ``format``). Returns ------- openable (filepath, URL, filehandle, etc.) Will pass back the user argument for ``into`` as a convenience. Raises ------ UnrecognizedFormatError Raised when a writer for writing ``obj`` as ``format`` could not be found. """ # The simplest functionality here. cls = None if not isinstance(obj, types.GeneratorType): cls = obj.__class__ writer = self.get_writer(format, cls) if writer is None: raise UnrecognizedFormatError( "Cannot write %r into %r, no %s writer found." % (format, into, obj.__class__.__name__) ) writer(obj, into, **kwargs) return into def _import_paths(self, formats): lines = [] for fmt in formats: lines.append("skbio.io.format." + fmt) return lines def _formats_for_docs(self, formats, imports): lines = [] for fmt, imp in zip(formats, imports): lines.append("- ``'%s'`` (:mod:`%s`)" % (fmt, imp)) return "\n".join(lines) class Format: """Defines a format on which readers/writers/sniffer can be registered. Parameters ---------- name : str The name of this format. encoding : str, optional What the default encoding of this format is. If set to 'binary' then all registered handlers will receive an :class:`io.BufferedReader` or :class:`io.BufferedWriter` instead of an :class:`io.TextIOBase`. The user will also be unable to override the encoding in that case. newline : str, optional What the default newline handling of this format is. Default is to use universal newline handling. """ @property def name(self): """The name of this format.""" return self._name @property def is_binary_format(self): """Return True if this is a binary format.""" return self._encoding == "binary" @property def sniffer_function(self): """The sniffer function associated with this format.""" return self._sniffer_function @property def readers(self): """Dictionary that maps classes to their readers for this format.""" return self._readers @property def writers(self): """Dictionary that maps classes to their writers for this format.""" return self._writers def __init__(self, name, encoding=None, newline=None): """Initialize format for registering sniffers, readers, and writers.""" self._encoding = encoding self._newline = newline self._name = name self._sniffer_function = None self._readers = {} self._writers = {} def sniffer(self, override=False): r"""Decorate a function to act as the sniffer for this format. The function should take one argument which will be an implementation of either :class:`io.TextIOBase` or :class:`io.BufferedReader` depending on if the format is text or binary, respectively. The sniffer will always receive a filehandle which is pointing to the beginning of the file. It must return a tuple of bool and a dict of suggested keyword arguments (if any) to pass to the reader. .. note:: Keyword arguments are not permitted in `sniffers`. `Sniffers` may not raise exceptions; if an exception is thrown by a `sniffer`, the user will be asked to report it on our `issue tracker `_. Parameters ---------- override : bool, optional If True, the existing sniffer will be overridden. Raises ------ DuplicateRegistrationError When `override` is False and a sniffer is already registered for this format. Examples -------- >>> from skbio.io.registry import Format >>> # If developing a new format for skbio, use the create_format() >>> # factory instead of this constructor. >>> myformat = Format('myformat') >>> @myformat.sniffer() ... def myformat_sniffer(fh): ... check = fh.read(8) == "myformat" ... if check: ... version = int(fh.read(1)) ... return True, {'version': version} ... return False, {} ... >>> myformat_sniffer(["myformat2\n", "some content\n"]) (True, {'version': 2}) >>> myformat_sniffer(["something else\n"]) (False, {}) """ if isinstance(override, bool) is not True: raise InvalidRegistrationError( "`override` must be a bool not %r" % override ) if not override and self._sniffer_function is not None: raise DuplicateRegistrationError( "A sniffer is already registered to format: %s" % self._name ) def decorator(sniffer): @wraps(sniffer) def wrapped_sniffer( file, encoding=self._encoding, errors="ignore", newline=self._newline, **kwargs, ): self._validate_encoding(encoding) if encoding == "binary": # Errors is irrelevant so set to default to prevent raising # a usage exception in open. errors = _open_kwargs["errors"] with open_file( file, mode="r", encoding=encoding, newline=newline, errors=errors, **kwargs, ) as fh: try: # Some formats may have headers which indicate their # format sniffers should be able to rely on the # filehandle to point at the beginning of the file. fh.seek(0) return sniffer(fh) except UnicodeDecodeError: pass except Exception: warn( f"'{sniffer.__name__}' has encountered a " "problem.\nPlease send the following to our " "issue tracker at\nhttps://github.com/scikit-" "bio/scikit-bio/issues\n\n" f"{traceback.format_exc()}", FormatIdentificationWarning, ) return False, {} self._sniffer_function = wrapped_sniffer return wrapped_sniffer return decorator def reader(self, cls, override=False): r"""Decorate a function to act as the reader for a class in this format. The function should take an argument which will be an implementation of either :class:`io.TextIOBase` or :class:`io.BufferedReader` depending on if the format is text or binary, respectively. Any kwargs given by the user which are not handled by :func:`skbio.io.util.open` will be passed into the function. Any kwarg with a default of `FileSentinel` will transform user input for that parameter into a filehandle or `None` if not provided. Parameters ---------- cls : type or None The class which the function will be registered to handle. If None, it is assumed that the function will produce a generator. override : bool, optional If True, any existing readers for `cls` in this format will be overridden. Raises ------ DuplicateRegistrationError When `override` is False and a reader is already registered to `cls` for this format. Examples -------- >>> from skbio.io.registry import Format, io_registry >>> from skbio.io.descriptors import Read, Write >>> myformat = Format('myformat') >>> io_registry.add_format(myformat) >>> # If developing a new format for skbio, use the create_format() >>> # factory instead of the above. >>> class MyObject: ... read = Read() ... write = Write() ... def __init__(self, content): ... self.content = content ... >>> @myformat.reader(MyObject) ... def myformat_reader(fh, cls=None): ... # These lines enable any subclass on your class to inherit this reader! ... if cls is None: ... cls = MyObject ... return cls(fh.readlines()[1:]) ... >>> MyObject.read(["myformat2\n", "some content here!\n"], ... format='myformat').content ['some content here!\n'] >>> # Cleanup >>> io_registry.remove_format('myformat') """ self._check_registration(cls) def decorator(reader_function): file_params = find_sentinels(reader_function, FileSentinel) # This split has to occur for the same reason as in IORegistry.read if cls is not None: @wraps(reader_function) def wrapped_reader( file, encoding=self._encoding, newline=self._newline, **kwargs ): file_keys, files, io_kwargs = self._setup_locals( file_params, file, encoding, newline, kwargs ) with open_files(files, mode="r", **io_kwargs) as fhs: # The primary file is at the end of fh because append # is cheaper than insert kwargs.update(zip(file_keys, fhs[:-1])) return reader_function(fhs[-1], **kwargs) else: @wraps(reader_function) def wrapped_reader( file, encoding=self._encoding, newline=self._newline, **kwargs ): file_keys, files, io_kwargs = self._setup_locals( file_params, file, encoding, newline, kwargs ) with open_files(files, mode="r", **io_kwargs) as fhs: kwargs.update(zip(file_keys, fhs[:-1])) yield from reader_function(fhs[-1], **kwargs) self._add_reader(cls, wrapped_reader, override) return wrapped_reader return decorator def writer(self, cls, override=False): r"""Decorate a function to act as the writer for a class in this format. The function should take an instance of `cls` as its first argument and the second argument is a filehandle which will be an implementation of either :class:`io.TextIOBase` or :class:`io.BufferedWriter` depending on if the format is text or binary, respectively. Any kwargs given by the user which are not handled by :func:`skbio.io.util.open` will be passed into the function. Any kwarg with a default of `FileSentinel` will transform user input for that parameter into a filehandle or `None` if not provided. Parameters ---------- cls : type or None The class which the function will be registered to handle. If None, it is assumed that the function will consume a generator. override : bool, optional If True, any existing writers for `cls` in this format will be overridden. Raises ------ DuplicateRegistrationError When `override` is False and a writer is already registered to `cls` for this format. Examples -------- >>> from skbio.io.registry import Format, io_registry >>> from skbio.io.descriptors import Read, Write >>> myformat = Format('myformat') >>> io_registry.add_format(myformat) >>> # If developing a new format for skbio, use the create_format() >>> # factory instead of the above. >>> class MyObject: ... default_write_format = 'myformat' ... read = Read() ... write = Write() ... def __init__(self, content): ... self.content = content ... >>> @myformat.writer(MyObject) ... def myformat_reader(obj, fh): ... fh.write("myformat2\n") ... for c in obj.content: ... fh.write(c) ... >>> obj = MyObject(["some content here!\n"]) >>> obj.write([], format='myformat') ['myformat2\n', 'some content here!\n'] >>> # Cleanup >>> io_registry.remove_format('myformat') """ self._check_registration(cls) def decorator(writer_function): file_params = find_sentinels(writer_function, FileSentinel) @wraps(writer_function) def wrapped_writer( obj, file, encoding=self._encoding, newline=self._newline, **kwargs ): file_keys, files, io_kwargs = self._setup_locals( file_params, file, encoding, newline, kwargs ) with open_files(files, mode="w", **io_kwargs) as fhs: kwargs.update(zip(file_keys, fhs[:-1])) writer_function(obj, fhs[-1], **kwargs) self._add_writer(cls, wrapped_writer, override) return wrapped_writer return decorator def _check_registration(self, cls): if cls is not None and not inspect.isclass(cls): raise InvalidRegistrationError( "`cls` must be a class or None, not %r" % cls ) def _setup_locals(self, file_params, file, encoding, newline, kwargs): self._validate_encoding(encoding) io_kwargs = self._pop_io_kwargs(kwargs, encoding, newline) file_keys, files = self._setup_file_args(kwargs, file_params) files.append(file) return file_keys, files, io_kwargs def _validate_encoding(self, encoding): if encoding != self._encoding: if self._encoding == "binary": raise ValueError("Encoding must be 'binary' for %r" % self.name) if encoding == "binary": raise ValueError("Encoding must not be 'binary' for %r" % self.name) def _pop_io_kwargs(self, kwargs, encoding, newline): io_kwargs = dict(encoding=encoding, newline=newline) for key in _open_kwargs: if key in kwargs: io_kwargs[key] = kwargs.pop(key) return io_kwargs def _setup_file_args(self, kwargs, file_params): file_keys = [] files = [] for param in file_params: arg = kwargs.get(param, None) if arg is not None: file_keys.append(param) files.append(arg) else: # set to None to mask FileSentinel when user neglected argument kwargs[param] = None return file_keys, files def _add_writer(self, cls, writer, override): if cls in self._writers and not override: raise DuplicateRegistrationError( "There is already a writer" " registered to %s in format: %s" % (cls, self._name) ) self._writers[cls] = writer def _add_reader(self, cls, reader, override): if cls in self._readers and not override: raise DuplicateRegistrationError( "There is already a reader" " registered to %s in format: %s" % (cls, self._name) ) self._readers[cls] = reader io_registry = IORegistry() @wraps(IORegistry.sniff) def sniff(file, **kwargs): """Detect the format of a given `file` and suggest kwargs.""" return io_registry.sniff(file, **kwargs) @wraps(IORegistry.read) def read(file, format=None, into=None, verify=True, **kwargs): """Read data from file using specified format.""" return io_registry.read(file, format=format, into=into, verify=verify, **kwargs) @wraps(IORegistry.write) def write(obj, format, into, **kwargs): """Write data to file using specified format.""" return io_registry.write(obj, format, into, **kwargs) @wraps(IORegistry.create_format) def create_format(*args, **kwargs): """Make a new format.""" return io_registry.create_format(*args, **kwargs) scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/000077500000000000000000000000001520735541300212335ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/__init__.py000066400000000000000000000005411520735541300233440ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/data/000077500000000000000000000000001520735541300221445ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/data/big5_file000066400000000000000000000000051520735541300237070ustar00rootroot00000000000000§A¦n scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/data/big5_file.bz2000066400000000000000000000000561520735541300244110ustar00rootroot00000000000000BZh91AY&SY²â*¼E € 0ÍÁ¥âîH§ \EW€scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/data/big5_file.gz000066400000000000000000000000431520735541300243300ustar00rootroot00000000000000‹à[�Ubig5_file[î¸,� &Óáscikit-bio-scikit-bio-a3beaa6/skbio/io/tests/data/example_file000066400000000000000000000000651520735541300245220ustar00rootroot00000000000000This is some content It occurs on more than one line scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/data/example_file.bz2000066400000000000000000000001241520735541300252120ustar00rootroot00000000000000BZh91AY&SYý¯ÝlW€@ *gž TPÓL Sõ2�S&ôÔŽƒ*#$jëê²ô6óèÉ6ðŒÙ O)/œéà»’)„‡í~ë`scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/data/example_file.gz000066400000000000000000000001231520735541300251340ustar00rootroot00000000000000‹wT�Uexample_file ÉÈ,V¢âüÜT…äü¼’Ô¼.Ï…üääÒ¢b…ü<…Üü¢T…’ŒÄ< 'U!'3/• Š�ô5scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/data/real_file000066400000000000000000000000121520735541300240020ustar00rootroot00000000000000a b c d e scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/data/real_file_2000066400000000000000000000000271520735541300242310ustar00rootroot00000000000000! @ # $ % The realest. scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/test_descriptors.py000066400000000000000000000615031520735541300252120ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from io import StringIO from skbio.io.descriptors import Read, Write, _docstring_vars, _extra_kwargs_docs from skbio.io.registry import create_format, io_registry from skbio.io._exception import UnrecognizedFormatError class TestRead(unittest.TestCase): """Tests for the Read descriptor.""" def setUp(self): """Set up test fixtures.""" # Create a mock format for testing self.test_format = create_format('test_format') # Create a test class with the Read descriptor class TestClass: read = Read() def __init__(self, data): self.data = data self.TestClass = TestClass # Register a reader for the test format @self.test_format.reader(TestClass) def _test_reader(fh, cls=None): if cls is None: cls = TestClass content = fh.read() return cls(content) def tearDown(self): """Clean up test format.""" io_registry.remove_format('test_format') def test_read_descriptor_creates_method(self): """Test that accessing read creates a _read_method.""" self.assertNotIn('_read_method', self.TestClass.__dict__) method = self.TestClass.read self.assertIn('_read_method', self.TestClass.__dict__) self.assertIsNotNone(method) def test_read_method_caching(self): """Test that _read_method is cached on the class.""" method1 = self.TestClass.read method2 = self.TestClass.read self.assertIs(method1, method2) def test_read_returns_correct_class(self): """Test that read returns an instance of the calling class.""" fh = StringIO("test data") obj = self.TestClass.read(fh, format='test_format') self.assertIsInstance(obj, self.TestClass) self.assertEqual(obj.data, "test data") def test_read_with_subclass(self): """Test that subclasses get their own read method.""" class SubClass(self.TestClass): pass fh = StringIO("subclass data") obj = SubClass.read(fh, format='test_format') self.assertIsInstance(obj, SubClass) self.assertEqual(obj.data, "subclass data") def test_read_subclass_returns_subclass_instance(self): """Test that reading with a subclass returns subclass instance.""" class SubClass(self.TestClass): def custom_method(self): return "custom" fh = StringIO("data") obj = SubClass.read(fh, format='test_format') self.assertIsInstance(obj, SubClass) self.assertTrue(hasattr(obj, 'custom_method')) self.assertEqual(obj.custom_method(), "custom") def test_read_method_has_docstring(self): """Test that the generated read method has a docstring.""" method = self.TestClass.read self.assertIsNotNone(method.__doc__) self.assertIn('TestClass', method.__doc__) def test_read_passes_kwargs(self): """Test that kwargs are passed through to the reader.""" @self.test_format.reader(self.TestClass, override=True) def _test_reader_with_kwargs(fh, cls=None, custom_arg=None): if cls is None: cls = self.TestClass return cls(f"{fh.read()}-{custom_arg}") fh = StringIO("test") obj = self.TestClass.read(fh, format='test_format', custom_arg='value') self.assertEqual(obj.data, "test-value") def test_read_with_format_inference(self): """Test reading without explicitly providing format.""" @self.test_format.sniffer() def _test_sniffer(fh): content = fh.read(4) return content == "test", {} fh = StringIO("test data") obj = self.TestClass.read(fh) self.assertIsInstance(obj, self.TestClass) class TestWrite(unittest.TestCase): """Tests for the Write descriptor.""" def setUp(self): """Set up test fixtures.""" self.test_format = create_format('test_write_format') class TestClass: default_write_format = 'test_write_format' write = Write() def __init__(self, data): self.data = data self.TestClass = TestClass @self.test_format.writer(TestClass) def _test_writer(obj, fh): fh.write(obj.data) def tearDown(self): """Clean up test format.""" io_registry.remove_format('test_write_format') def test_write_descriptor_on_class(self): """Test accessing write on the class itself.""" method = self.TestClass.write self.assertIn('_write_method', self.TestClass.__dict__) def test_write_descriptor_on_instance(self): """Test accessing write on an instance.""" obj = self.TestClass("test data") method = obj.write self.assertIn('_write_method', obj.__dict__) def test_write_method_caching_on_class(self): """Test that write method is cached on the class.""" method1 = self.TestClass.write method2 = self.TestClass.write self.assertIs(method1, method2) def test_write_method_caching_on_instance(self): """Test that write method is cached on instances.""" obj = self.TestClass("data") method1 = obj.write method2 = obj.write self.assertIs(method1, method2) def test_write_works(self): """Test that write actually writes data.""" obj = self.TestClass("test data") fh = StringIO() obj.write(fh, format='test_write_format') self.assertEqual(fh.getvalue(), "test data") def test_write_with_subclass(self): """Test that subclasses can write.""" class SubClass(self.TestClass): pass obj = SubClass("subclass data") fh = StringIO() obj.write(fh, format='test_write_format') self.assertEqual(fh.getvalue(), "subclass data") def test_write_uses_default_format(self): """Test that write uses default_write_format when format not provided.""" obj = self.TestClass("data") fh = StringIO() result = obj.write(fh) # No format specified self.assertEqual(fh.getvalue(), "data") def test_write_raises_without_default_format(self): """Test that write raises error when no default format and none provided.""" class NoDefaultClass: write = Write() def __init__(self, data): self.data = data obj = NoDefaultClass("data") fh = StringIO() with self.assertRaises(ValueError) as cm: obj.write(fh) self.assertIn("no default write format", str(cm.exception)) def test_write_method_has_docstring(self): """Test that generated write method has a docstring.""" obj = self.TestClass("data") method = obj.write self.assertIsNotNone(method.__doc__) self.assertIn('TestClass', method.__doc__) def test_write_returns_file_path(self): """Test that write returns the file path/handle passed in.""" obj = self.TestClass("data") fh = StringIO() result = obj.write(fh, format='test_write_format') self.assertIs(result, fh) def test_write_passes_kwargs(self): """Test that kwargs are passed through to the writer.""" @self.test_format.writer(self.TestClass, override=True) def _test_writer_with_kwargs(obj, fh, prefix=""): fh.write(f"{prefix}{obj.data}") obj = self.TestClass("data") fh = StringIO() obj.write(fh, format='test_write_format', prefix="PREFIX:") self.assertEqual(fh.getvalue(), "PREFIX:data") class TestDocstringVars(unittest.TestCase): """Tests for the _docstring_vars helper function.""" def setUp(self): """Set up test format and class.""" self.test_format = create_format('docstring_test_format') class TestClass: default_write_format = 'docstring_test_format' self.TestClass = TestClass @self.test_format.reader(TestClass) def _reader(fh, cls=None): pass @self.test_format.writer(TestClass) def _writer(obj, fh): pass def tearDown(self): """Clean up.""" io_registry.remove_format('docstring_test_format') def test_docstring_vars_for_read(self): """Test _docstring_vars returns correct values for read.""" name, supported_fmts, default, see = _docstring_vars(self.TestClass, 'read') self.assertEqual(name, 'TestClass') self.assertIn('docstring_test_format', supported_fmts) self.assertIn('skbio.io.format.docstring_test_format', see) def test_docstring_vars_for_write(self): """Test _docstring_vars returns correct values for write.""" name, supported_fmts, default, see = _docstring_vars(self.TestClass, 'write') self.assertEqual(name, 'TestClass') self.assertIn('docstring_test_format', supported_fmts) self.assertEqual(default, 'docstring_test_format') def test_docstring_vars_invalid_func(self): """Test _docstring_vars raises error for invalid func.""" with self.assertRaises(ValueError) as cm: _docstring_vars(self.TestClass, 'invalid') self.assertIn("'read' or 'write'", str(cm.exception)) def test_docstring_vars_no_formats(self): """Test _docstring_vars when class has no registered formats.""" class NoFormatClass: pass name, supported_fmts, default, see = _docstring_vars(NoFormatClass, 'read') self.assertEqual(name, 'NoFormatClass') self.assertEqual(supported_fmts, "") self.assertEqual(default, "None") class TestInheritanceIntegration(unittest.TestCase): """Integration tests for descriptor behavior with inheritance.""" def setUp(self): """Set up test format and class hierarchy.""" self.test_format = create_format('inheritance_test_format') class ParentClass: default_write_format = 'inheritance_test_format' read = Read() write = Write() def __init__(self, data): self.data = data class ChildClass(ParentClass): pass class GrandchildClass(ChildClass): pass self.ParentClass = ParentClass self.ChildClass = ChildClass self.GrandchildClass = GrandchildClass @self.test_format.reader(ParentClass) def _reader(fh, cls=None): if cls is None: cls = ParentClass return cls(fh.read()) @self.test_format.writer(ParentClass) def _writer(obj, fh): fh.write(f"[{obj.__class__.__name__}:{obj.data}]") @self.test_format.sniffer() def _sniffer(fh): content = fh.read(10) return content.startswith("TESTDATA:"), {} def tearDown(self): """Clean up.""" io_registry.remove_format('inheritance_test_format') def test_child_inherits_read(self): """Test that child class inherits parent's read capability.""" fh = StringIO("child data") obj = self.ChildClass.read(fh, format='inheritance_test_format') self.assertIsInstance(obj, self.ChildClass) self.assertEqual(obj.data, "child data") def test_grandchild_inherits_read(self): """Test that grandchild class inherits parent's read capability.""" fh = StringIO("grandchild data") obj = self.GrandchildClass.read(fh, format='inheritance_test_format') self.assertIsInstance(obj, self.GrandchildClass) self.assertEqual(obj.data, "grandchild data") def test_child_inherits_write(self): """Test that child class inherits parent's write capability.""" obj = self.ChildClass("child data") fh = StringIO() obj.write(fh, format='inheritance_test_format') self.assertEqual(fh.getvalue(), "[ChildClass:child data]") def test_grandchild_inherits_write(self): """Test that grandchild class inherits parent's write capability.""" obj = self.GrandchildClass("grandchild data") fh = StringIO() obj.write(fh, format='inheritance_test_format') self.assertEqual(fh.getvalue(), "[GrandchildClass:grandchild data]") def test_each_class_has_own_cached_method(self): """Test that each class in hierarchy caches its own methods.""" parent_read = self.ParentClass.read child_read = self.ChildClass.read grandchild_read = self.GrandchildClass.read # They should all be different cached methods self.assertIsNot(parent_read, child_read) self.assertIsNot(child_read, grandchild_read) self.assertIsNot(parent_read, grandchild_read) def test_list_read_formats_parent(self): """Test that parent class lists its read formats.""" formats = io_registry.list_read_formats(self.ParentClass) self.assertIn('inheritance_test_format', formats) def test_list_read_formats_child(self): """Test that child class inherits parent's read formats.""" formats = io_registry.list_read_formats(self.ChildClass) self.assertIn('inheritance_test_format', formats) def test_list_read_formats_grandchild(self): """Test that grandchild class inherits parent's read formats.""" formats = io_registry.list_read_formats(self.GrandchildClass) self.assertIn('inheritance_test_format', formats) def test_list_write_formats_parent(self): """Test that parent class lists its write formats.""" formats = io_registry.list_write_formats(self.ParentClass) self.assertIn('inheritance_test_format', formats) def test_list_write_formats_child(self): """Test that child class inherits parent's write formats.""" formats = io_registry.list_write_formats(self.ChildClass) self.assertIn('inheritance_test_format', formats) def test_list_write_formats_grandchild(self): """Test that grandchild class inherits parent's write formats.""" formats = io_registry.list_write_formats(self.GrandchildClass) self.assertIn('inheritance_test_format', formats) def test_sniff_with_parent_into(self): """Test that sniffing works when into is parent class.""" fh = StringIO("TESTDATA:some content") format_name, kwargs = io_registry.sniff(fh, into=self.ParentClass) self.assertEqual(format_name, 'inheritance_test_format') def test_sniff_with_child_into(self): """Test that sniffing works when into is child class.""" fh = StringIO("TESTDATA:some content") format_name, kwargs = io_registry.sniff(fh, into=self.ChildClass) self.assertEqual(format_name, 'inheritance_test_format') def test_sniff_with_grandchild_into(self): """Test that sniffing works when into is grandchild class.""" fh = StringIO("TESTDATA:some content") format_name, kwargs = io_registry.sniff(fh, into=self.GrandchildClass) self.assertEqual(format_name, 'inheritance_test_format') def test_read_with_format_inference_child(self): """Test that child class can read with format inference.""" fh = StringIO("TESTDATA:child data") obj = self.ChildClass.read(fh) # No format specified self.assertIsInstance(obj, self.ChildClass) self.assertEqual(obj.data, "TESTDATA:child data") def test_read_with_format_inference_grandchild(self): """Test that grandchild class can read with format inference.""" fh = StringIO("TESTDATA:grandchild data") obj = self.GrandchildClass.read(fh) # No format specified self.assertIsInstance(obj, self.GrandchildClass) self.assertEqual(obj.data, "TESTDATA:grandchild data") def test_format_listing_no_duplicates(self): """Test that format listing doesn't return duplicates for inherited formats.""" formats = io_registry.list_read_formats(self.ChildClass) # Count occurrences of the format count = formats.count('inheritance_test_format') self.assertEqual(count, 1, "Format should appear only once in the list") def test_multiple_inheritance_format_listing(self): """Test format listing with multiple inheritance.""" # Create another format and parent class other_format = create_format('other_test_format') class OtherParent: read = Read() write = Write() def __init__(self, data): self.data = data @other_format.reader(OtherParent) def _other_reader(fh, cls=None): if cls is None: cls = OtherParent return cls(fh.read()) # Create a class with multiple inheritance class MultiChild(self.ParentClass, OtherParent): pass try: formats = io_registry.list_read_formats(MultiChild) # Should inherit formats from both parents self.assertIn('inheritance_test_format', formats) self.assertIn('other_test_format', formats) finally: io_registry.remove_format('other_test_format') def test_sniff_filters_by_child_class(self): """Test that sniff only considers formats appropriate for the child class.""" # Create a format that's only for a different class unrelated_format = create_format('unrelated_format') class UnrelatedClass: read = Read() def __init__(self, data): self.data = data @unrelated_format.reader(UnrelatedClass) def _unrelated_reader(fh, cls=None): if cls is None: cls = UnrelatedClass return cls(fh.read()) @unrelated_format.sniffer() def _unrelated_sniffer(fh): # This sniffer would match, but shouldn't be considered return True, {} try: # Even though unrelated_sniffer always returns True, # it shouldn't match because ChildClass can't use it fh = StringIO("some data") with self.assertRaises(UnrecognizedFormatError): io_registry.sniff(fh, into=self.ChildClass) finally: io_registry.remove_format('unrelated_format') class TestExtraKwargsDocs(unittest.TestCase): """Tests for the _extra_kwargs_docs helper function.""" def test_returns_empty_string_when_attr_missing(self): """Test that classes without the attribute produce empty string.""" class NoAttr: pass self.assertEqual(_extra_kwargs_docs(NoAttr, "_reader_kwargs"), "") def test_returns_empty_string_for_empty_dict(self): """Test that an empty dict produces empty string.""" class EmptyDict: _reader_kwargs = {} self.assertEqual(_extra_kwargs_docs(EmptyDict, "_reader_kwargs"), "") def test_single_param(self): """Test formatting of a single parameter.""" class OneParam: _reader_kwargs = { "constructor": "type, required\n A sequence type." } result = _extra_kwargs_docs(OneParam, "_reader_kwargs") self.assertEqual( result, "constructor : type, required\n A sequence type.\n" ) def test_multiple_params(self): """Test formatting of multiple parameters.""" class MultiParam: _reader_kwargs = { "constructor": "type, required\n A sequence type.", "strict": "bool, optional\n Enable strict mode.", } result = _extra_kwargs_docs(MultiParam, "_reader_kwargs") self.assertIn("constructor : type, required", result) self.assertIn("strict : bool, optional", result) self.assertTrue(result.endswith("\n")) def test_docstring_includes_reader_kwargs(self): """Test that Read docstring includes _reader_kwargs parameters.""" test_format = create_format('reader_kwargs_test_format') class WithReaderKwargs: _reader_kwargs = { "constructor": "type, required\n A sequence type." } read = Read() def __init__(self, data): self.data = data @test_format.reader(WithReaderKwargs) def _reader(fh, cls=None): if cls is None: cls = WithReaderKwargs return cls(fh.read()) try: doc = WithReaderKwargs.read.__doc__ self.assertIn("constructor : type, required", doc) self.assertIn("A sequence type.", doc) finally: io_registry.remove_format('reader_kwargs_test_format') def test_docstring_without_reader_kwargs(self): """Test that Read docstring works normally without _reader_kwargs.""" test_format = create_format('no_kwargs_test_format') class WithoutReaderKwargs: read = Read() def __init__(self, data): self.data = data @test_format.reader(WithoutReaderKwargs) def _reader(fh, cls=None): if cls is None: cls = WithoutReaderKwargs return cls(fh.read()) try: doc = WithoutReaderKwargs.read.__doc__ self.assertIn("kwargs : dict, optional", doc) self.assertNotIn("constructor", doc) finally: io_registry.remove_format('no_kwargs_test_format') class TestInheritanceEdgeCases(unittest.TestCase): """Test edge cases in inheritance behavior.""" def setUp(self): """Set up test formats.""" self.format1 = create_format('format1_edge') self.format2 = create_format('format2_edge') class GrandParent: read = Read() write = Write() def __init__(self, data): self.data = data class Parent(GrandParent): pass class Child(Parent): pass self.GrandParent = GrandParent self.Parent = Parent self.Child = Child # Register reader only for GrandParent in format1 @self.format1.reader(GrandParent) def _format1_reader(fh, cls=None): if cls is None: cls = GrandParent return cls("format1:" + fh.read()) # Register reader only for Parent in format2 @self.format2.reader(Parent) def _format2_reader(fh, cls=None): if cls is None: cls = Parent return cls("format2:" + fh.read()) def tearDown(self): """Clean up.""" io_registry.remove_format('format1_edge') io_registry.remove_format('format2_edge') def test_child_inherits_from_grandparent(self): """Test that Child can use GrandParent's reader.""" fh = StringIO("data") obj = self.Child.read(fh, format='format1_edge') self.assertIsInstance(obj, self.Child) self.assertEqual(obj.data, "format1:data") def test_child_inherits_from_parent(self): """Test that Child can use Parent's reader.""" fh = StringIO("data") obj = self.Child.read(fh, format='format2_edge') self.assertIsInstance(obj, self.Child) self.assertEqual(obj.data, "format2:data") def test_child_lists_both_formats(self): """Test that Child lists formats from both Parent and GrandParent.""" formats = io_registry.list_read_formats(self.Child) self.assertIn('format1_edge', formats) self.assertIn('format2_edge', formats) def test_parent_has_both_formats(self): """Test that Parent has both its own and inherited formats.""" formats = io_registry.list_read_formats(self.Parent) self.assertIn('format1_edge', formats) self.assertIn('format2_edge', formats) def test_grandparent_has_only_own_format(self): """Test that GrandParent only has its own format.""" formats = io_registry.list_read_formats(self.GrandParent) self.assertIn('format1_edge', formats) self.assertNotIn('format2_edge', formats) if __name__ == '__main__': unittest.main()scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/test_format_imports.py000066400000000000000000000126751520735541300257240ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import os import inspect import pkgutil from unittest import TestCase, main import skbio.io from skbio.io import _exception class ImportModuleTests(TestCase): def test_format_modules_imported_in_init(self): """Verify all format modules are imported in __init__.py""" init_file = os.path.join(os.path.dirname(skbio.io.__file__), '__init__.py') with open(init_file, 'r') as f: init_content = f.read() fmt_dir = os.path.dirname(skbio.io.format.__file__) # Skip these special cases skip_modules = {'emptyfile', '_test'} for _, name, ispkg in pkgutil.iter_modules([fmt_dir]): if not ispkg and not name.startswith("_") and name not in skip_modules: expected_import = f'import_module("skbio.io.format.{name}")' self.assertIn( expected_import, init_content, f"\n\n\nModule '{name}' not imported in skbio.io.__init__.py" ) def test_all_io_exceptions_importable(self): """Verify all I/O exceptions are importable and functional. This test covers ALL exception classes exported from skbio.io, not just those ending with 'FormatError'. This includes: - IOSourceError - FileFormatError (base class) - All format-specific exceptions (*FormatError) """ # All exception classes exported from skbio.io io_exceptions = { name: obj for name, obj in vars(skbio.io).items() if inspect.isclass(obj) and issubclass(obj, Exception) } self.assertGreater( len(io_exceptions), 0, "No exception classes found in skbio.io" ) failed_exceptions = [] for name, exception_cls in io_exceptions.items(): try: # Test instantiation with a message ex = exception_cls("test message") # Test raising and catching try: raise ex except exception_cls as caught: # Verify the message is preserved self.assertIn("test message", str(caught)) except AssertionError: raise except Exception as e: failed_exceptions.append((name, str(e))) if failed_exceptions: self.fail( f"Failed to instantiate or raise exceptions: {failed_exceptions}" ) def test_exception_module_exports_match_definitions(self): """Verify public exceptions from _exception.py are exported in __all__. This ensures that exception classes intended for public use are properly exported from skbio.io. """ # Get all public exception classes defined in _exception module defined_exceptions = { name for name, obj in vars(_exception).items() if inspect.isclass(obj) and issubclass(obj, Exception) and not name.startswith("_") } # Get exceptions listed in skbio.io.__all__ exported_exceptions = { name for name in skbio.io.__all__ if name.endswith("Error") } # Internal exceptions that are intentionally not exported internal_exceptions = {"InvalidRegistrationError", "DuplicateRegistrationError"} # Check that all non-internal exceptions are exported expected_exports = defined_exceptions - internal_exceptions missing_exports = expected_exports - exported_exceptions self.assertEqual( missing_exports, set(), f"Exceptions defined but not exported in __all__: {missing_exports}" ) def test_exception_inheritance_hierarchy(self): """Verify format-specific exceptions inherit from FileFormatError. This ensures that users can catch all format-related errors by catching FileFormatError. """ # Get all classes ending with "FormatError" (excluding FileFormatError itself) format_exceptions = { name: obj for name, obj in vars(skbio.io).items() if inspect.isclass(obj) and name.endswith("FormatError") and name != "FileFormatError" } # These exceptions have different base classes by design exceptions_with_different_base = {"BIOMFormatError", "EmbedFormatError"} for name, exception_cls in format_exceptions.items(): # First check if the class inherits from Exception at all self.assertTrue( issubclass(exception_cls, Exception), f"{name} does not inherit from Exception and cannot be raised" ) # Then check if it inherits from FileFormatError (unless it's an exception with a different base) if name not in exceptions_with_different_base: self.assertTrue( issubclass(exception_cls, skbio.io.FileFormatError), f"{name} should inherit from FileFormatError" ) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/test_iosources.py000066400000000000000000000036411520735541300246630ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from pathlib import Path from skbio.io._iosources import IOSource, Compressor class TestIOSource(unittest.TestCase): def setUp(self): self.file = 'somepath' self.file_path = Path('somepath') self.options = {'a': 1, 'b': 2} self.source = IOSource(self.file, self.options) self.source_path = IOSource(self.file_path, self.options) def test_attributes(self): self.assertEqual(self.source.file, self.file) self.assertEqual(self.source.options, self.options) self.assertEqual(self.source_path.file, self.file_path) self.assertEqual(self.source_path.options, self.options) def test_can_read(self): self.assertEqual(self.source.can_read(), False) self.assertEqual(self.source_path.can_read(), False) def test_can_write(self): self.assertEqual(self.source.can_write(), False) self.assertEqual(self.source_path.can_write(), False) def test_get_reader(self): with self.assertRaises(NotImplementedError): self.source.get_reader() self.source_path.get_reader() def test_get_writer(self): with self.assertRaises(NotImplementedError): self.source.get_writer() self.source_path.get_writer() class TestCompressor(TestIOSource): def setUp(self): super(TestCompressor, self).setUp() self.compressor = Compressor(self.file, self.options) def test_can_write(self): self.assertEqual(self.compressor.can_write(), True) if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/test_registry.py000066400000000000000000001623701520735541300245250ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from io import StringIO import io import itertools import os import unittest import warnings import types from tempfile import mkstemp from sys import platform from skbio.io import (FormatIdentificationWarning, UnrecognizedFormatError, ArgumentOverrideWarning, io_registry, sniff, create_format) from skbio.io.registry import (IORegistry, FileSentinel, Format, DuplicateRegistrationError, InvalidRegistrationError) from skbio.util import get_data_path from skbio.util._exception import TestingUtilError from skbio import DNA, read, write class MockClass: def __init__(self, list_): self.list = list_ def __eq__(self, other): # They are only equal when the class is EXACTLY the same. We don't want # readers to return knockoff instances... return self.__class__ is other.__class__ and self.list == other.list def __repr__(self): return "%s(%s)" % (str(self.__class__.__name__), str(self.list)) class MockClassA(MockClass): pass class MockClassB(MockClass): pass class TestFormatAndIORegistry(unittest.TestCase): def test_add_duplicate_format(self): f = Format('Example') r = IORegistry() r.add_format(f) with self.assertRaises(DuplicateRegistrationError): r.add_format(Format('Example')) class RegistryTest(unittest.TestCase): def setUp(self): self.registry = IORegistry() self.fd1, self.fp1 = mkstemp() self.fd2, self.fp2 = mkstemp() def tearDown(self): os.close(self.fd1) os.remove(self.fp1) os.close(self.fd2) os.remove(self.fp2) class TestRegisterAndGetReader(RegistryTest): def test_get_reader_no_match(self): self.assertIs(None, self.registry.get_reader('not_a_format', MockClass)) def test_get_reader_when_only_writer_exists(self): format1 = self.registry.create_format('format1') @format1.writer(MockClass) def format_writer(fh): return self.assertEqual(None, self.registry.get_reader('format', MockClass)) def test_register_reader_on_many(self): format1 = self.registry.create_format('format1') format2 = self.registry.create_format('format2') format3 = self.registry.create_format('format3') format4 = self.registry.create_format('format4', encoding='binary') format5 = self.registry.create_format('format5', encoding='binary') @format1.reader(MockClassA) def format1_reader(fh, cls=None): return @format1.reader(MockClassB) def format1_reader_b(fh, cls=None): return @format2.reader(MockClassA) def format2_reader(fh, cls=None): return @format3.reader(MockClassB) def format3_reader(fh, cls=None): return @format4.reader(MockClassA) def format4_reader(fh, cls=None): return @format4.reader(MockClassB) def format4_reader_b(fh, cls=None): return @format5.reader(None) def format5_reader(fh, cls=None): return self.assertIs(format1_reader, self.registry.get_reader('format1', MockClassA)) self.assertIs(format1_reader_b, self.registry.get_reader('format1', MockClassB)) self.assertIs(format2_reader, self.registry.get_reader('format2', MockClassA)) self.assertIs(None, self.registry.get_reader('format2', MockClassB)) self.assertIs(None, self.registry.get_reader('format3', MockClassA)) self.assertIs(format3_reader, self.registry.get_reader('format3', MockClassB)) self.assertIs(format4_reader, self.registry.get_reader('format4', MockClassA)) self.assertIs(format4_reader_b, self.registry.get_reader('format4', MockClassB)) self.assertIs(format5_reader, self.registry.get_reader('format5', None)) self.assertIs(None, self.registry.get_reader('format5', MockClassA)) self.assertIs(None, self.registry.get_reader('format5', MockClassB)) def test_register_reader_over_existing(self): format1 = self.registry.create_format('format1') with self.assertRaises(DuplicateRegistrationError) as cm: @format1.reader(MockClassA) def format1_reader(fh, cls=None): return @format1.reader(MockClassA) def duplicate_format1_reader(fh, cls=None): return self.assertTrue('format1' in str(cm.exception)) self.assertTrue('reader' in str(cm.exception)) self.assertTrue(MockClassA.__name__ in str(cm.exception)) def test_register_reader_over_existing_override(self): format1 = self.registry.create_format('format1') @format1.reader(MockClassA) def format1_reader(fh, cls=None): return self.assertIs(format1_reader, self.registry.get_reader('format1', MockClassA)) @format1.reader(MockClassA, override=True) def duplicate_format1_reader(fh, cls=None): return self.assertIs(duplicate_format1_reader, self.registry.get_reader('format1', MockClassA)) def test_mistype_reader_registration(self): format1 = self.registry.create_format('format1') with self.assertRaises(InvalidRegistrationError): @format1.reader def left_out_parens(fh): return class TestRegisterAndGetWriter(RegistryTest): def test_get_writer_no_match(self): self.assertEqual(None, self.registry.get_writer('not_a_format', MockClass)) def test_get_writer_when_only_reader_exists(self): format = self.registry.create_format('format') @format.reader(MockClass) def format_reader(fh, cls=None): return self.assertEqual(None, self.registry.get_writer('format', MockClass)) def test_register_writer_on_many(self): format1 = self.registry.create_format('format1') format2 = self.registry.create_format('format2') format3 = self.registry.create_format('format3') format4 = self.registry.create_format('format4', encoding='binary') format5 = self.registry.create_format('format5', encoding='binary') @format1.writer(MockClassA) def format1_writer(obj, fh): return @format1.writer(MockClassB) def format1_writer_b(obj, fh): return @format2.writer(MockClassA) def format2_writer(obj, fh): return @format3.writer(MockClassB) def format3_writer(obj, fh): return @format4.writer(MockClassA) def format4_writer(fh): return @format4.writer(MockClassB) def format4_writer_b(fh): return @format5.writer(None) def format5_writer(fh): return self.assertEqual(format1_writer, self.registry.get_writer('format1', MockClassA)) self.assertEqual(format1_writer_b, self.registry.get_writer('format1', MockClassB)) self.assertEqual(format2_writer, self.registry.get_writer('format2', MockClassA)) self.assertEqual(None, self.registry.get_writer('format2', MockClassB)) self.assertEqual(None, self.registry.get_writer('format3', MockClassA)) self.assertEqual(format3_writer, self.registry.get_writer('format3', MockClassB)) self.assertIs(format4_writer, self.registry.get_writer('format4', MockClassA)) self.assertIs(format4_writer_b, self.registry.get_writer('format4', MockClassB)) self.assertIs(format5_writer, self.registry.get_writer('format5', None)) self.assertIs(None, self.registry.get_writer('format5', MockClassA)) self.assertIs(None, self.registry.get_writer('format5', MockClassB)) def test_register_writer_over_existing(self): format1 = self.registry.create_format('format1') with self.assertRaises(DuplicateRegistrationError) as cm: @format1.writer(MockClassA) def format1_writer(obj, fh): return @format1.writer(MockClassA) def duplicate_format1_writer(obj, fh): return self.assertTrue('format1' in str(cm.exception)) self.assertTrue('writer' in str(cm.exception)) self.assertTrue(MockClassA.__name__ in str(cm.exception)) def test_register_writer_over_existing_override(self): format1 = self.registry.create_format('format1') @format1.writer(MockClassA) def format1_writer(obj, fh): return self.assertIs(format1_writer, self.registry.get_writer('format1', MockClassA)) @format1.writer(MockClassA, override=True) def duplicate_format1_writer(obj, fh): return self.assertIs(duplicate_format1_writer, self.registry.get_writer('format1', MockClassA)) def test_mistype_writer_registration(self): format1 = self.registry.create_format('format1') with self.assertRaises(InvalidRegistrationError): @format1.writer def left_out_parens(fh): return class TestRegisterAndGetSniffer(RegistryTest): def test_get_sniffer_no_match(self): self.assertEqual(None, self.registry.get_sniffer('not_a_format')) def test_register_sniffer_on_many(self): format1 = self.registry.create_format('format1') format2 = self.registry.create_format('format2') format3 = self.registry.create_format('format3', encoding='binary') @format1.sniffer() def format1_sniffer(fh): return '1' in fh.readline(), {} @format2.sniffer() def format2_sniffer(fh): return '2' in fh.readline(), {} @format3.sniffer() def format3_sniffer(fh): return '3' in fh.readline(), {} self.assertEqual(format1_sniffer, self.registry.get_sniffer('format1')) self.assertEqual(format2_sniffer, self.registry.get_sniffer('format2')) self.assertEqual(format3_sniffer, self.registry.get_sniffer('format3')) def test_register_sniffer_over_existing(self): format1 = self.registry.create_format('format1') with self.assertRaises(DuplicateRegistrationError) as cm: @format1.sniffer() def format1_sniffer(fh): return False, {} @format1.sniffer() def duplicate_format1_sniffer(fh): return False, {} self.assertTrue('format1' in str(cm.exception)) def test_register_sniffer_over_existing_override(self): format1 = self.registry.create_format('format1') @format1.sniffer() def format1_sniffer(fh): return False, {} self.assertIs(self.registry.get_sniffer('format1'), format1_sniffer) @format1.sniffer(override=True) def duplicate_format1_sniffer(fh): return False, {} self.assertIs(self.registry.get_sniffer('format1'), duplicate_format1_sniffer) def test_sniffer_warns_on_exception(self): format = self.registry.create_format('format') @format.sniffer() def format_sniffer(fh): raise TestingUtilError("Sniffer will return False and warn.") fh = StringIO() sniffer = self.registry.get_sniffer('format') with warnings.catch_warnings(record=True): warnings.simplefilter("error") with self.assertRaises(FormatIdentificationWarning): sniffer(fh) with warnings.catch_warnings(record=True): warnings.simplefilter("ignore") result, kwargs = sniffer(fh) self.assertFalse(result) self.assertEqual({}, kwargs) fh.close() def test_mistype_sniffer_registration(self): format1 = self.registry.create_format('format1') with self.assertRaises(InvalidRegistrationError): @format1.sniffer def left_out_parens(fh): return class TestListReadFormats(RegistryTest): def test_no_read_formats(self): format1 = self.registry.create_format('format1') @format1.reader(MockClassA) def this_isnt_on_clsB(fh, cls=None): return self.assertEqual([], self.registry.list_read_formats(MockClassB)) def test_one_read_format(self): format1 = self.registry.create_format('format1') @format1.reader(MockClass) def format1_cls(fh, cls=None): return self.assertEqual(['format1'], self.registry.list_read_formats(MockClass)) def test_many_read_formats(self): format1 = self.registry.create_format('format1') format2 = self.registry.create_format('format2') format3 = self.registry.create_format('format3', encoding='binary') format4 = self.registry.create_format('format4') format5 = self.registry.create_format('format5', encoding='binary') @format1.reader(MockClassA) def format1_clsA(fh, cls=None): return @format2.reader(MockClassA) def format2_clsA(fh, cls=None): return @format3.reader(MockClassA) def format3_clsA(fh, cls=None): return @format3.reader(MockClassB) def format3_clsB(fh, cls=None): return @format4.reader(MockClassB) def format4_clsB(fh, cls=None): return @format5.writer(MockClassA) def format5_clsA(fh, cls=None): return formats = self.registry.list_read_formats(MockClassA) self.assertTrue('format1' in formats) self.assertTrue('format2' in formats) self.assertTrue('format3' in formats) self.assertTrue('format4' not in formats) self.assertTrue('format5' not in formats) class TestListWriteFormats(RegistryTest): def test_no_write_formats(self): format1 = self.registry.create_format('format1') @format1.writer(MockClassA) def this_isnt_on_clsB(fh): return self.assertEqual([], self.registry.list_write_formats(MockClassB)) def test_one_write_format(self): format1 = self.registry.create_format('format1') @format1.writer(MockClass) def format1_cls(fh): return self.assertEqual(['format1'], self.registry.list_write_formats(MockClass)) def test_many_write_formats(self): format1 = self.registry.create_format('format1') format2 = self.registry.create_format('format2') format3 = self.registry.create_format('format3', encoding='binary') format4 = self.registry.create_format('format4') format5 = self.registry.create_format('format5', encoding='binary') @format1.writer(MockClassA) def format1_clsA(fh): return @format2.writer(MockClassA) def format2_clsA(fh): return @format3.writer(MockClassA) def format3_clsA(fh): return @format3.writer(MockClassB) def format3_clsB(fh): return @format4.writer(MockClassB) def format4_clsB(fh): return @format5.reader(MockClassA) def format5_clsA(fh, cls=None): return formats = self.registry.list_write_formats(MockClassA) self.assertTrue('format1' in formats) self.assertTrue('format2' in formats) self.assertTrue('format3' in formats) self.assertTrue('format4' not in formats) self.assertTrue('format5' not in formats) class TestSniff(RegistryTest): def setUp(self): super(TestSniff, self).setUp() format1 = self.registry.create_format('format1') format2 = self.registry.create_format('format2') format3 = self.registry.create_format('format3') format4 = self.registry.create_format('format4') # No sniffer for this format: self.registry.create_format('format5') @format1.sniffer() def format1_sniffer(fh): return '1' in fh.readline(), {} @format2.sniffer() def format2_sniffer(fh): return '2' in fh.readline(), {} @format3.sniffer() def format3_sniffer(fh): return '3' in fh.readline(), {} @format4.sniffer() def format4_sniffer(fh): return '4' in fh.readline(), {} @format3.reader(MockClass) def reader3(fh, cls=None): return @format4.reader(MockClass) def reader4(fh, cls=None): return def test_no_matches(self): fh = StringIO("no matches here") with self.assertRaises(UnrecognizedFormatError) as cm: self.registry.sniff(fh) self.assertTrue(str(fh) in str(cm.exception)) fh.close() def test_one_match(self): fh = StringIO("contains a 3") self.assertEqual('format3', self.registry.sniff(fh)[0]) def test_many_matches(self): fh = StringIO("1234 will match all") with self.assertRaises(UnrecognizedFormatError) as cm: self.registry.sniff(fh) self.assertTrue("format1" in str(cm.exception)) self.assertTrue("format2" in str(cm.exception)) self.assertTrue("format3" in str(cm.exception)) self.assertTrue("format4" in str(cm.exception)) fh.close() def test_that_encoding_is_used(self): formatx = self.registry.create_format('formatx') fp = get_data_path('big5_file') @formatx.sniffer() def sniffer(fh): self.assertEqual('big5', fh.encoding) return True, {} fmt, _ = self.registry.sniff(fp, encoding='big5') self.assertEqual(fmt, 'formatx') def test_passing_newline_raises_error(self): formatx = self.registry.create_format('formatx') fp = get_data_path('real_file') @formatx.sniffer() def sniffer(fh): return True, {} with self.assertRaisesRegex(TypeError, r'`newline`'): self.registry.sniff(fp, newline='\r') def test_non_default_encoding(self): big5_format = self.registry.create_format('big5_format', encoding='big5') @big5_format.sniffer() def sniffer(fh): self.assertEqual(self._expected_encoding, fh.encoding) return True, {} self._expected_encoding = 'big5' fmt, _ = self.registry.sniff(self.fp1) self.assertEqual(fmt, 'big5_format') self._expected_encoding = 'UTF-8' fmt, _ = self.registry.sniff(self.fp1, encoding='UTF-8') self.assertEqual(fmt, 'big5_format') def test_non_default_newline(self): formatx = self.registry.create_format('formatx', newline='\r') fp = get_data_path('real_file') @formatx.sniffer() def sniffer(fh): with io.open(fp, newline=None) as f: content = f.read() self.assertEqual(content, 'a\nb\nc\nd\ne\n') return True, {} fmt, _ = self.registry.sniff(fp) self.assertEqual(fmt, 'formatx') # Temporarily disabled due to a compatibility issue with conda-forge. # See: https://github.com/scikit-bio/scikit-bio/issues/2088 # def test_position_not_mutated_real_file(self): # formatx = self.registry.create_format('formatx') # @formatx.sniffer() # def sniffer(fh): # return True, {} # with io.open(get_data_path('real_file')) as fh: # if platform == "win32": # fh.seek(3) # self.registry.sniff(fh) # self.assertEqual(fh.tell(), 3) # self.assertEqual('b\n', fh.readline()) # else: # fh.seek(2) # self.registry.sniff(fh) # self.assertEqual(fh.tell(), 2) # self.assertEqual('b\n', fh.readline()) def test_position_not_mutated_fileish(self): formatx = self.registry.create_format('formatx') @formatx.sniffer() def sniffer(fh): return True, {} fh = StringIO('a\nb\nc\nd\n') fh.seek(2) self.registry.sniff(fh) self.assertEqual('b\n', fh.readline()) def test_sniff_with_errors_in_sniffer(self): formatx = self.registry.create_format('formatx', encoding='ascii') @formatx.sniffer() def sniffer(fh): raise Exception("OH NO!") fp = get_data_path('big5_file') with warnings.catch_warnings(record=True): warnings.simplefilter('error') with self.assertRaises(FormatIdentificationWarning): fmt, _ = self.registry.sniff(fp) def test_sniff_with_encoding_errors(self): formatx = self.registry.create_format('formatx', encoding='ascii') @formatx.sniffer() def sniffer(fh): fh.read() return True, {} fp = get_data_path('big5_file') with self.assertRaises(UnrecognizedFormatError): fmt, _ = self.registry.sniff(fp, errors='strict') # errors is set to ignore by default, so our sniffer will return # true even though read() didn't entirely work for ascii fmt, _ = self.registry.sniff(fp) self.assertEqual(fmt, 'formatx') def test_binary_sniffer(self): binf = self.registry.create_format('binf', encoding='binary') @binf.sniffer() def sniffer(fh): self.assertIsInstance(fh, (io.BufferedReader, io.BufferedRandom)) return True, {} fmt, _ = self.registry.sniff(self.fp1) self.assertEqual(fmt, 'binf') def test_text_sniffer(self): textf = self.registry.create_format('textf', encoding=None) @textf.sniffer() def sniffer(fh): self.assertIsInstance(fh, io.TextIOBase) return True, {} fmt, _ = self.registry.sniff(self.fp1) self.assertEqual(fmt, 'textf') def test_sniff_with_illegal_encoding(self): binf = self.registry.create_format('binf', encoding='binary') textf = self.registry.create_format('textf', encoding=None) @binf.sniffer() def binf_sniffer(fh): return True, {} @textf.sniffer() def textf_sniffer(fh): return True, {} # Should skip binary sniffers fmt, _ = self.registry.sniff(self.fp1, encoding=None) self.assertEqual(fmt, 'textf') # Should skip text sniffers fmt, _ = self.registry.sniff(self.fp1, encoding='binary') self.assertEqual(fmt, 'binf') with self.assertRaises(ValueError): self.registry.sniff(['some content\n'], encoding='binary') with self.assertRaises(ValueError): binf_sniffer(self.fp1, encoding=None) with self.assertRaises(ValueError): textf_sniffer(self.fp1, encoding='binary') def test_binary_fall_through(self): binf = self.registry.create_format('binf', encoding='binary') textf = self.registry.create_format('textf', encoding=None) @binf.sniffer() def binf_sniffer(fh): self._check_binf = True return False, {} @textf.sniffer() def textf_sniffer(fh): self._check_textf = True return True, {} self._check_binf = False self._check_textf = False fmt, _ = self.registry.sniff(self.fp1) self.assertEqual(fmt, 'textf') self.assertTrue(self._check_binf) self.assertTrue(self._check_textf) def test_sniff_gzip(self): expected = "This is some content\nIt occurs on more than one line\n" formata = self.registry.create_format('formata', encoding='binary') formatb = self.registry.create_format('formatb') formatc = self.registry.create_format('formatc') @formata.sniffer() def formata_sniffer(fh): self._check_f1 = True self.assertEqual(fh.read(), expected.encode('ascii')) return False, {} @formatb.sniffer() def formatb_sniffer(fh): self._check_f2 = True self.assertEqual(fh.read(), expected) return True, {} @formatc.sniffer() def formatc_sniffer(fh): self._check_f3 = True self.assertEqual(fh.read(), expected) return False, {} self._check_f1 = False self._check_f2 = False self._check_f3 = False self.registry.sniff(get_data_path('example_file.gz')) self.assertTrue(self._check_f1) self.assertTrue(self._check_f2) self.assertTrue(self._check_f3) def test_text_skip_binary(self): binf = self.registry.create_format('binf', encoding='binary') textf = self.registry.create_format('textf', encoding=None) @binf.sniffer() def binf_sniffer(fh): self._check_binf = True return True, {} @textf.sniffer() def textf_sniffer(fh): self._check_textf = True return True, {} self._check_binf = False self._check_textf = False fmt, _ = self.registry.sniff(['text']) self.assertEqual(fmt, 'textf') self.assertFalse(self._check_binf) self.assertTrue(self._check_textf) self._check_binf = False self._check_textf = False fmt, _ = self.registry.sniff(self.fp1, encoding=None) self.assertEqual(fmt, 'textf') self.assertFalse(self._check_binf) self.assertTrue(self._check_textf) def test_text_skip_text(self): binf = self.registry.create_format('binf', encoding='binary') textf = self.registry.create_format('textf', encoding=None) @binf.sniffer() def binf_sniffer(fh): self._check_binf = True return True, {} @textf.sniffer() def textf_sniffer(fh): self._check_textf = True return True, {} self._check_binf = False self._check_textf = False fmt, _ = self.registry.sniff(self.fp1, encoding='binary') self.assertEqual(fmt, 'binf') self.assertTrue(self._check_binf) self.assertFalse(self._check_textf) class TestRead(RegistryTest): def test_format_and_into_are_none(self): fh = StringIO() with self.assertRaises(ValueError): self.registry.read(fh) fh.close() def test_format_is_none(self): format1 = self.registry.create_format('format1') fh = StringIO('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): return '1' in fh.readline(), {} @format1.reader(MockClass) def reader(fh, cls=None): self.assertIsInstance(fh, io.TextIOBase) return MockClass([int(x) for x in fh.read().split('\n')]) instance = self.registry.read(fh, into=MockClass) self.assertEqual(MockClass([1, 2, 3, 4]), instance) fh.close() def test_into_is_none_and_no_generator_reader(self): format1 = self.registry.create_format('format1') fh = StringIO('1\n2\n3\n4') @format1.reader(MockClass) def reader(fh, cls=None): self.assertIsInstance(fh, io.TextIOBase) return with self.assertRaisesRegex(UnrecognizedFormatError, r"Cannot read 'format1'.*Possible.*include" ": MockClass"): self.registry.read(fh, format='format1') def test_into_is_none(self): format1 = self.registry.create_format('format1') fh = StringIO('1\n2\n3\n4') @format1.reader(None) def reader(fh, cls=None): self.assertIsInstance(fh, io.TextIOBase) yield from [int(x) for x in fh.read().split('\n')] generator = self.registry.read(fh, format='format1') self.assertIsInstance(generator, types.GeneratorType) first_run = True for a, b in zip(generator, [1, 2, 3, 4]): if first_run: fh.seek(3) first_run = False self.assertEqual(a, b) self.assertEqual(3, fh.tell()) fh.close() def test_into_is_none_real_file(self): format1 = self.registry.create_format('format1') fp = self.fp1 with open(fp, 'w') as fh: fh.write('1\n2\n3\n4') self._test_fh = None @format1.reader(None) def reader(fh, cls=None): self._test_fh = fh yield from [int(x) for x in fh.read().split('\n')] generator = self.registry.read(fp, format='format1') for a, b in itertools.zip_longest(generator, [1, 2, 3, 4]): self.assertEqual(a, b) self.assertTrue(self._test_fh.closed) def test_reader_does_not_exist(self): fh = StringIO() with self.assertRaises(UnrecognizedFormatError) as cm: self.registry.read(fh, format='not_a_format', into=MockClass) self.assertTrue(MockClass.__name__ in str(cm.exception)) self.assertTrue('not_a_format' in str(cm.exception)) with self.assertRaises(UnrecognizedFormatError) as cm: self.registry.read(fh, format='not_a_format2') self.assertTrue('generator' in str(cm.exception)) self.assertTrue('not_a_format2' in str(cm.exception)) def test_reader_exists_with_verify_true(self): format1 = self.registry.create_format('format1') fh = StringIO('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): self.was_verified = True return '1' in fh.readline(), {} @format1.reader(MockClass) def reader(fh, cls=None): return MockClass([int(x) for x in fh.read().split('\n')]) self.was_verified = False instance = self.registry.read(fh, format='format1', into=MockClass, verify=True) self.assertEqual(MockClass([1, 2, 3, 4]), instance) self.assertTrue(self.was_verified) # Remove if read-context management is support in the future. fh.seek(0) self.was_verified = False instance = self.registry.read(fh, format='format1', into=MockClass) self.assertEqual(MockClass([1, 2, 3, 4]), instance) self.assertTrue(self.was_verified) fh.close() def test_warning_raised(self): format1 = self.registry.create_format('format1') fh = StringIO('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): self.was_verified = True return False, {} @format1.reader(MockClass) def reader(fh, cls=None): return MockClass([int(x) for x in fh.read().split('\n')]) with warnings.catch_warnings(record=True): warnings.simplefilter("error") with self.assertRaises(FormatIdentificationWarning): self.was_verified = False instance = self.registry.read(fh, format='format1', into=MockClass, verify=True) self.assertEqual(MockClass([1, 2, 3, 4]), instance) self.assertTrue(self.was_verified) with warnings.catch_warnings(record=True): warnings.simplefilter("error") with self.assertRaises(FormatIdentificationWarning): self.was_verified = False instance = self.registry.read(fh, format='format1', into=MockClass) self.assertEqual(MockClass([1, 2, 3, 4]), instance) self.assertTrue(self.was_verified) fh.close() def test_reader_exists_with_verify_false(self): format1 = self.registry.create_format('format1') fh = StringIO('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): self.was_verified = True return '1' in fh.readline(), {} @format1.reader(MockClass) def reader(fh, cls=None): return MockClass([int(x) for x in fh.read().split('\n')]) self.was_verified = False instance = self.registry.read(fh, format='format1', into=MockClass, verify=False) self.assertEqual(MockClass([1, 2, 3, 4]), instance) self.assertFalse(self.was_verified) fh.close() def test_reader_exists_real_file(self): format1 = self.registry.create_format('format1') fp = self.fp1 with open(fp, 'w') as fh: fh.write('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): return '1' in fh.readline(), {} @format1.reader(MockClass) def reader(fh, cls=None): return MockClass([int(x) for x in fh.read().split('\n')]) instance = self.registry.read(fp, format='format1', into=MockClass) self.assertEqual(MockClass([1, 2, 3, 4]), instance) def test_read_kwargs_passed_generator(self): format1 = self.registry.create_format('format1') @format1.sniffer() def sniffer(fh): return True, {'arg1': 15, 'arg2': 'abc'} @format1.reader(None) def reader(fh, cls=None, **kwargs): self.assertEqual(kwargs['arg1'], 15) self.assertEqual(kwargs['arg2'], 'abc') self.assertEqual(kwargs['arg3'], [1]) yield next(self.registry.read(StringIO(), format='format1', arg3=[1])) def test_read_kwargs_passed_and_override(self): format1 = self.registry.create_format('format1') @format1.sniffer() def sniffer(fh): return True, {'arg1': 15, 'arg2': 'abc', 'override': 30} @format1.reader(MockClass) def reader(fh, cls=None, **kwargs): self.assertEqual(kwargs['arg1'], 15) self.assertEqual(kwargs['arg2'], 'abc') self.assertEqual(kwargs['arg3'], [1]) return self.registry.read(StringIO('notempty'), into=MockClass, arg3=[1]) with warnings.catch_warnings(record=True): warnings.simplefilter("error") # Should raise no warning and thus no error. self.registry.read(StringIO('notempty'), into=MockClass, arg3=[1], override=30) # Should raise a warning and thus an error. with self.assertRaises(ArgumentOverrideWarning): self.registry.read(StringIO('notempty'), into=MockClass, arg3=[1], override=100) def test_that_encoding_is_used(self): format1 = self.registry.create_format('format1') fp = get_data_path('big5_file') @format1.sniffer() def sniffer(fh): return '\u4f60' in fh.readline(), {} @format1.reader(MockClass) def reader(fh, cls=None): self.assertEqual(self._expected_enc, fh.encoding) return MockClass(fh.readlines()) @format1.reader(None) def reader_gen(fh, cls=None): self.assertEqual(self._expected_enc, fh.encoding) yield MockClass(fh.readlines()) self._expected_enc = 'big5' instance = self.registry.read(fp, into=MockClass, encoding='big5') self.assertEqual(MockClass(['\u4f60\u597d\n']), instance) self._expected_enc = 'big5' gen = self.registry.read(fp, format='format1', encoding='big5') self.assertEqual(MockClass(['\u4f60\u597d\n']), next(gen)) def test_non_default_encoding(self): format1 = self.registry.create_format('format1', encoding='big5') fp = get_data_path('big5_file') @format1.sniffer() def sniffer(fh): return True, {} @format1.reader(MockClass) def reader(fh, cls=None): self.assertEqual(self._expected_enc, fh.encoding) return MockClass(fh.readlines()) @format1.reader(None) def reader_gen(fh, cls=None): self.assertEqual(self._expected_enc, fh.encoding) yield MockClass(fh.readlines()) self._expected_enc = 'big5' instance = self.registry.read(fp, into=MockClass) self.assertEqual(MockClass(['\u4f60\u597d\n']), instance) gen = self.registry.read(fp, format='format1') self.assertEqual(MockClass(['\u4f60\u597d\n']), next(gen)) gen.close() self._expected_enc = 'utf8' with self.assertRaises(UnicodeDecodeError): self.registry.read(fp, into=MockClass, encoding='utf8') with self.assertRaises(UnicodeDecodeError): self.registry.read(fp, format='format1', encoding='utf8') def test_passing_newline_raises_error(self): formatx = self.registry.create_format('formatx') fp = get_data_path('real_file') @formatx.sniffer() def sniffer(fh): return True, {} @formatx.reader(MockClass) def reader(fh, cls=None): return MockClass(fh.readlines()) @formatx.reader(None) def reader_gen(fh, cls=None): yield MockClass(fh.readlines()) with self.assertRaisesRegex(TypeError, r'`newline`'): self.registry.read(fp, into=MockClass, newline='\r') with self.assertRaisesRegex(TypeError, r'`newline`'): self.registry.read(fp, format='formatx', newline='\r') def test_non_default_newline(self): formatx = self.registry.create_format('formatx', newline='\r') fp = get_data_path('real_file') @formatx.sniffer() def sniffer(fh): return True, {} @formatx.reader(MockClass) def reader(fh, cls=None): with io.open(fp, newline=None) as f: content = [''.join(f.readlines())] return MockClass(content) @formatx.reader(None) def reader_gen(fh, cls=None): with io.open(fp, newline=None) as f: content = [''.join(f.readlines())] yield MockClass(content) instance = self.registry.read(fp, into=MockClass) self.assertEqual(instance, MockClass(['a\nb\nc\nd\ne\n'])) gen = self.registry.read(fp, format='formatx') self.assertEqual(next(gen), MockClass(['a\nb\nc\nd\ne\n'])) gen.close() def test_file_sentinel_many(self): format1 = self.registry.create_format('format1') extra = get_data_path('real_file') extra_2 = get_data_path('real_file_2') fh = StringIO('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): return '1' in fh.readline(), {} @format1.reader(MockClass) def reader(fh, cls=None, extra=FileSentinel, other=2, extra_2=FileSentinel): self.assertEqual('a\nb\nc\nd\ne\n', extra.read()) self.assertEqual('!\n@\n#\n$\n%\nThe realest.\n', extra_2.read()) return MockClass([int(x) for x in fh.read().split('\n')]) instance = self.registry.read(fh, format='format1', into=MockClass, extra=extra, extra_2=extra_2) self.assertEqual(MockClass([1, 2, 3, 4]), instance) fh.close() def test_file_sentinel_converted_to_none(self): format1 = self.registry.create_format('format1') fh = StringIO('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): return '1' in fh.readline(), {} @format1.reader(MockClass) def reader(fh, cls=None, extra=FileSentinel, other=2, extra_2=FileSentinel): self.assertIsNone(extra) self.assertIsNone(extra_2) return MockClass([int(x) for x in fh.read().split('\n')]) instance = self.registry.read(fh, format='format1', into=MockClass) self.assertEqual(MockClass([1, 2, 3, 4]), instance) fh.close() def test_file_sentinel_pass_none(self): format1 = self.registry.create_format('format1') fh = StringIO('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): return '1' in fh.readline(), {} @format1.reader(MockClass) def reader(fh, cls=None, extra=FileSentinel, other=2, extra_2=FileSentinel): self.assertIsNone(extra) self.assertIsNone(extra_2) return MockClass([int(x) for x in fh.read().split('\n')]) instance = self.registry.read(fh, format='format1', into=MockClass, extra=None) self.assertEqual(MockClass([1, 2, 3, 4]), instance) fh.close() def test_file_sentinel_generator_many(self): format1 = self.registry.create_format('format1') extra = get_data_path('real_file') extra_2 = get_data_path('real_file_2') fh = StringIO('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): return '1' in fh.readline(), {} @format1.reader(None) def reader(fh, cls=None, extra=FileSentinel, other=2, extra_2=FileSentinel): self.assertEqual('a\nb\nc\nd\ne\n', extra.read()) self.assertEqual('!\n@\n#\n$\n%\nThe realest.\n', extra_2.read()) yield MockClass([int(x) for x in fh.read().split('\n')]) gen = self.registry.read(fh, format='format1', extra=extra, extra_2=extra_2) self.assertEqual(MockClass([1, 2, 3, 4]), next(gen)) fh.close() def test_file_sentinel_converted_to_none_generator(self): format1 = self.registry.create_format('format1') fh = StringIO('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): return '1' in fh.readline(), {} @format1.reader(None) def reader(fh, cls=None, extra=FileSentinel, other=2, extra_2=FileSentinel): self.assertIsNone(extra) self.assertIsNone(extra_2) yield MockClass([int(x) for x in fh.read().split('\n')]) gen = self.registry.read(fh, format='format1') self.assertEqual(MockClass([1, 2, 3, 4]), next(gen)) fh.close() def test_file_sentinel_pass_none_generator(self): format1 = self.registry.create_format('format1') fh = StringIO('1\n2\n3\n4') @format1.sniffer() def sniffer(fh): return '1' in fh.readline(), {} @format1.reader(None) def reader(fh, cls=None, extra=FileSentinel, other=2, extra_2=FileSentinel): self.assertIsNone(extra) self.assertIsNone(extra_2) yield MockClass([int(x) for x in fh.read().split('\n')]) gen = self.registry.read(fh, format='format1', extra=None) self.assertEqual(MockClass([1, 2, 3, 4]), next(gen)) fh.close() def test_read_with_illegal_encoding(self): binf = self.registry.create_format('binf', encoding='binary') textf = self.registry.create_format('textf', encoding=None) @binf.sniffer() def binf_sniffer(fh): return True, {} @binf.reader(MockClass) def binf_reader(fh, cls=None): return MockClass(['bin']) @binf.reader(None) def binf_reader_gen(fh, cls=None): yield MockClass(['bin']) @textf.sniffer() def textf_sniffer(fh): return True, {} @textf.reader(MockClass) def textf_reader(fh, cls=None): return MockClass(['text']) @textf.reader(None) def textf_reader_gen(fh, cls=None): yield MockClass(['text']) # Should skip binary sniffers instance = self.registry.read(self.fp1, encoding=None, into=MockClass) self.assertEqual(instance, MockClass(['text'])) gen = self.registry.read(self.fp1, encoding=None, format='textf') self.assertEqual(next(gen), MockClass(['text'])) gen.close() # Should skip text sniffers instance = self.registry.read(self.fp1, encoding='binary', into=MockClass) self.assertEqual(instance, MockClass(['bin'])) gen = self.registry.read(self.fp1, encoding='binary', format='binf') self.assertEqual(next(gen), MockClass(['bin'])) gen.close() with self.assertRaises(ValueError): self.registry.read(['some content\n'], encoding='binary', into=MockClass) with self.assertRaises(ValueError): self.registry.read(['some content\n'], format='textf', encoding='binary', into=MockClass) with self.assertRaises(ValueError): self.registry.read(['some content\n'], format='textf', encoding='binary', verify=False, into=MockClass) with self.assertRaises(ValueError): self.registry.read(['some content\n'], format='textf', encoding='binary') with self.assertRaises(ValueError): self.registry.read(['some content\n'], format='textf', encoding='binary', verify=False) with self.assertRaises(ValueError): self.registry.read(self.fp1, format='binf', encoding=None, into=MockClass) with self.assertRaises(ValueError): self.registry.read(self.fp1, format='binf', encoding=None, verify=False, into=MockClass) with self.assertRaises(ValueError): self.registry.read(self.fp1, format='binf', encoding=None) with self.assertRaises(ValueError): self.registry.read(self.fp1, format='binf', encoding=None, verify=False) def test_read_with_binary_encoding(self): binf = self.registry.create_format('binf', encoding='binary') @binf.reader(MockClass) def reader1(fh, cls=None): self.assertIsInstance(fh, (io.BufferedReader, io.BufferedRandom)) return MockClass(['woo']) @binf.reader(None) def reader2(fh, cls=None): self.assertIsInstance(fh, (io.BufferedReader, io.BufferedRandom)) yield MockClass(['woo']) instance = self.registry.read(self.fp1, format='binf', verify=False, into=MockClass) self.assertEqual(MockClass(['woo']), instance) gen = self.registry.read(self.fp1, format='binf', verify=False, into=None) self.assertEqual(MockClass(['woo']), next(gen)) gen.close() def test_io_kwargs_passed(self): format1 = self.registry.create_format('format1') @format1.sniffer() def sniffer(fh): return True, {} @format1.reader(MockClass) def reader1(fh, cls=None): self.assertEqual(fh.errors, 'replace') return MockClass(['woo']) @format1.reader(None) def reader1_gen(fh, cls=None): self.assertEqual(fh.errors, 'replace') yield MockClass(['woo']) obj = self.registry.read(self.fp1, into=MockClass, errors='replace') self.assertEqual(obj, MockClass(['woo'])) gen = self.registry.read(self.fp1, format='format1', errors='replace') self.assertEqual(next(gen), MockClass(['woo'])) gen.close() def test_read_empty_file_gen_with_format(self): format1 = self.registry.create_format('format1') @format1.sniffer() def sniffer(fh): return True, {} @format1.reader(None) def reader1(fh, cls=None): return yield with io.StringIO("") as fh: gen = self.registry.read(fh, format='format1') self.assertEqual(list(gen), []) class TestWrite(RegistryTest): def test_writer_does_not_exist(self): fh = StringIO() with self.assertRaises(UnrecognizedFormatError) as cm: self.registry.write({}, format='not_a_format', into=fh) self.assertTrue('not_a_format' in str(cm.exception)) self.assertTrue(str(fh) in str(cm.exception)) fh.close() def test_writer_exists(self): format1 = self.registry.create_format('format1') obj = MockClass(['1', '2', '3', '4']) fh = StringIO() @format1.writer(MockClass) def writer(obj, fh): self.assertIsInstance(fh, io.TextIOBase) fh.write('\n'.join(obj.list)) self.registry.write(obj, format='format1', into=fh) fh.seek(0) self.assertEqual("1\n2\n3\n4", fh.read()) fh.close() def test_writer_exists_real_file(self): format1 = self.registry.create_format('format1') obj = MockClass(['1', '2', '3', '4']) fp = self.fp1 @format1.writer(MockClass) def writer(obj, fh): self.assertIsInstance(fh, io.TextIOBase) fh.write('\n'.join(obj.list)) self.registry.write(obj, format='format1', into=fp) with io.open(fp) as fh: self.assertEqual("1\n2\n3\n4", fh.read()) def test_writer_passed_kwargs(self): format1 = self.registry.create_format('format1') @format1.reader(None) def reader(fh, cls=None): yield @format1.writer(None) def writer(obj, fh, **kwargs): self.assertEqual(kwargs['passed'], True) generator = self.registry.get_reader('format1', None)([]) self.registry.write(generator, format='format1', into=StringIO(), passed=True) def test_that_encoding_is_used(self): format1 = self.registry.create_format('format1') obj = MockClass(['\u4f60\u597d\n']) # Ni Hau fp = self.fp1 @format1.writer(MockClass) def writer(obj, fh): fh.write(''.join(obj.list)) self.assertEqual(self._expected_encoding, fh.encoding) self._expected_encoding = 'big5' self.registry.write(obj, format='format1', into=fp, encoding='big5') with io.open(fp, mode='rb') as fh: # This would have been b'\xe4\xbd\xa0\xe5\xa5\xbd\n' in utf8 self.assertEqual(b"\xa7A\xa6n\n", fh.read().replace(b"\r\n", b"\n")) def test_non_default_encoding(self): format1 = self.registry.create_format('format1', encoding='big5') obj = MockClass(['\u4f60\u597d\n']) # Ni Hau fp = self.fp1 @format1.writer(MockClass) def writer(obj, fh): fh.write(''.join(obj.list)) self.assertEqual(self._expected_encoding, fh.encoding) self._expected_encoding = 'big5' self.registry.write(obj, format='format1', into=fp) with io.open(fp, mode='rb') as fh: self.assertEqual(b"\xa7A\xa6n\n", fh.read().replace(b"\r\n", b"\n")) self._expected_encoding = 'utf8' self.registry.write(obj, format='format1', into=fp, encoding='utf8') with io.open(fp, mode='rb') as fh: self.assertEqual(b"\xe4\xbd\xa0\xe5\xa5\xbd\n", fh.read().replace(b"\r\n", b"\n")) def test_that_newline_is_used(self): format1 = self.registry.create_format('format1') obj = MockClass(['a\n', 'b\n', 'c\n']) fp = self.fp1 @format1.writer(MockClass) def writer(obj, fh): fh.write(''.join(obj.list)) self.registry.write(obj, format='format1', into=fp, newline='\r') with io.open(fp, mode='rb') as fh: self.assertEqual(b'a\rb\rc\r', fh.read()) def test_non_default_newline(self): format1 = self.registry.create_format('format1', newline='\r') obj = MockClass(['a\n', 'b\n', 'c\n']) fp = self.fp1 @format1.writer(MockClass) def writer(obj, fh): fh.write(''.join(obj.list)) self.registry.write(obj, format='format1', into=fp) with io.open(fp, mode='rb') as fh: self.assertEqual(b'a\rb\rc\r', fh.read()) self.registry.write(obj, format='format1', into=fp, newline='\n') with io.open(fp, mode='rb') as fh: self.assertEqual(b'a\nb\nc\n', fh.read()) def test_file_sentinel_many(self): format1 = self.registry.create_format('format1') fh = StringIO() @format1.writer(MockClass) def writer(obj, fh, extra=FileSentinel, other=2, extra_2=FileSentinel): extra.write('oh yeah...') extra_2.write('oh no...') self.registry.write(MockClass([]), format='format1', into=fh, extra=self.fp1, extra_2=self.fp2) with open(self.fp1) as f1: self.assertEqual('oh yeah...', f1.read()) with open(self.fp2) as f2: self.assertEqual('oh no...', f2.read()) fh.close() def test_file_sentinel_converted_to_none(self): format1 = self.registry.create_format('format1') fh = StringIO() @format1.writer(MockClass) def writer(obj, fh, extra=FileSentinel, other=2, extra_2=FileSentinel): self.assertIsNone(extra) self.assertIsNone(extra_2) self.registry.write(MockClass([]), format='format1', into=fh) fh.close() def test_file_sentinel_pass_none(self): format1 = self.registry.create_format('format1') fh = StringIO() @format1.writer(MockClass) def writer(obj, fh, extra=FileSentinel, other=2, extra_2=FileSentinel): self.assertIsNone(extra) self.assertIsNone(extra_2) self.registry.write(MockClass([]), format='format1', into=fh, extra=None) fh.close() def test_write_with_illegal_encoding(self): binf = self.registry.create_format('binf', encoding='binary') textf = self.registry.create_format('textf', encoding=None) @binf.writer(MockClass) def writer(obj, fh): pass @textf.writer(MockClass) def writer2(obj, fh): pass with self.assertRaises(ValueError): self.registry.write(MockClass([]), into=self.fp1, format='binf', encoding=None) with self.assertRaises(ValueError): self.registry.write(MockClass([]), into=self.fp1, format='textf', encoding='binary') def test_write_binary_format(self): format1 = self.registry.create_format('format1', encoding='binary') obj = MockClass([b'a\n', b'b\n', b'c\n']) fp = self.fp1 @format1.writer(MockClass) def writer(obj, fh): self.assertIsInstance(fh, (io.BufferedWriter, io.BufferedRandom)) fh.write(b''.join(obj.list)) self.registry.write(obj, format='format1', into=fp) with io.open(fp, mode='rb') as fh: self.assertEqual(b'a\nb\nc\n', fh.read()) def test_io_kwargs_passed(self): format1 = self.registry.create_format('format1', encoding='ascii') obj = MockClass(['a\n', 'b\n', 'c\n']) fp = self.fp1 f = io.BytesIO() @format1.writer(MockClass) def writer(obj, fh): iterator = iter(obj.list) fh.write(next(iterator)) fh.flush() # Flush should be a noop for bz2 for line in iterator: fh.write(line) self.registry.write(obj, format='format1', into=fp, compression='bz2', newline='\n') self.registry.write(obj, format='format1', into=f, compression='bz2', newline='\n') expected = ( b'BZh91AY&SY\x03\x89\x0c\xa6\x00\x00\x01\xc1\x00\x00\x108\x00 \x00' b'!\x9ah3M\x1c\xb7\x8b\xb9"\x9c(H\x01\xc4\x86S\x00') with io.open(fp, mode='rb') as fh: self.assertEqual(expected, fh.read()) self.assertEqual(expected, f.getvalue()) class TestModuleFunctions(unittest.TestCase): def test_sniff_matches(self): exp = io_registry.sniff(['(a, b);']) result = sniff(['(a, b);']) self.assertEqual(exp, result) self.assertEqual('newick', exp[0]) self.assertEqual({}, exp[1]) def test_read_matches(self): input = ['>\n', 'ACGT\n'] exp = io_registry.read(input, into=DNA) result = read(input, into=DNA) self.assertEqual(exp, result) self.assertEqual(exp, DNA('ACGT', metadata={'id': '', 'description': ''})) def test_write_matches(self): input = DNA('ACGT') exp = io_registry.write(input, format='fasta', into=[]) result = write(input, format='fasta', into=[]) self.assertEqual(exp, result) self.assertEqual(exp, ['>\n', 'ACGT\n']) def test_create_format_matches(self): with self.assertRaises(DuplicateRegistrationError): io_registry.create_format('fasta') with self.assertRaises(DuplicateRegistrationError): create_format('fasta') def test_remove_format_no_format(self): with self.assertRaises(KeyError): io_registry.remove_format('nonsense_asdf') if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/tests/test_util.py000066400000000000000000000564701520735541300236350ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import tempfile import shutil import io import os.path import gc try: import responses except ImportError: has_responses = False else: has_responses = True import skbio.io from skbio.io.registry import open_file from skbio.util import get_data_path class TestOpen(unittest.TestCase): def test_open_invalid_mode(self): with self.assertRaises(ValueError): skbio.io.open([], mode='a') def test_open_invalid_source(self): with self.assertRaises(skbio.io.IOSourceError): skbio.io.open(42) def test_open_invalid_source_compression(self): with self.assertRaises(ValueError): skbio.io.open(['foo'], compression='gzip') def test_open_invalid_source_encoding(self): with self.assertRaises(ValueError): skbio.io.open(['foo'], encoding='binary') with self.assertRaises(ValueError): skbio.io.open(['foo'], encoding='binary', newline='\r') def test_open_invalid_compression(self): with self.assertRaises(ValueError): skbio.io.open(io.BytesIO(), compression='foo') class ReadableBinarySourceTests: def check_closed(self, file, expected): if hasattr(file, 'closed'): self.assertEqual(file.closed, expected) def check_open_state_contents(self, file, contents, is_binary, **kwargs): result = skbio.io.open(file, **kwargs) self.assertTrue(result.readable()) if is_binary: self.assertIsInstance(result, (io.BufferedReader, io.BufferedRandom)) actual_contents = result.read().decode().replace("\r\n", "\n").encode() else: self.assertIsInstance(result, io.TextIOBase) actual_contents = result.read().replace("\r\n", "\n") self.assertEqual(actual_contents, contents) self.assertFalse(result.closed) result.close() self.assertTrue(result.closed) self.check_closed(file, True) def check_open_file_state_contents(self, file, contents, is_binary, **kwargs): with open_file(file, **kwargs) as f: self.assertTrue(f.readable()) if is_binary: self.assertIsInstance(f, (io.BufferedReader, io.BufferedRandom)) actual_contents = f.read().decode().replace("\r\n", "\n").encode() else: self.assertIsInstance(f, io.TextIOBase) actual_contents = f.read().replace("\r\n", "\n") self.assertEqual(actual_contents, contents) self.assertEqual(f.closed, self.expected_close) f.close() self.assertTrue(f.closed) self.check_closed(file, True) def check_open_buffer_close_behaviour(self, file, **kwargs): if hasattr(file, 'close'): wrapped = skbio.io.open(file, **kwargs) file.close() self.assertTrue(wrapped.closed) def check_open_file_buffer_close_behaviour(self, file, **kwargs): if hasattr(file, 'close'): with open_file(file, **kwargs) as wrapped: file.close() self.assertTrue(wrapped.closed) def check_open_gc_behaviour(self, file, **kwargs): def mangle(file): result = skbio.io.open(file, **kwargs) self.assertIsInstance(result, io.TextIOBase) f = skbio.io.open(file, encoding='binary') mangle(f) self.assertFalse(f.closed) f.close() def check_open_file_gc_behaviour(self, file, **kwargs): def mangle(file): with open_file(file, **kwargs) as result: self.assertIsInstance(result, io.TextIOBase) with open_file(file, encoding='binary') as f: mangle(f) self.assertFalse(f.closed) def test_open_gc_binary(self): self.check_open_gc_behaviour(self.read_file) def test_open_gc_encoding(self): self.check_open_gc_behaviour(self.encoded_file) def test_open_gc_compression(self): self.check_open_gc_behaviour(self.gzip_file) self.check_open_gc_behaviour(self.bz2_file) def test_open_gc_compression_encoding(self): self.check_open_gc_behaviour(self.gzip_encoded_file) self.check_open_gc_behaviour(self.bz2_encoded_file) def test_open_file_gc_binary(self): self.check_open_file_gc_behaviour(self.read_file) def test_open_file_gc_encoding(self): self.check_open_file_gc_behaviour(self.encoded_file) def test_open_file_gc_compression(self): self.check_open_file_gc_behaviour(self.gzip_file) self.check_open_file_gc_behaviour(self.bz2_file) def test_open_file_gc_compression_encoding(self): self.check_open_file_gc_behaviour(self.gzip_encoded_file) self.check_open_file_gc_behaviour(self.bz2_encoded_file) def test_open_underclose_binary(self): self.check_open_buffer_close_behaviour(self.read_file) def test_open_underclose_encoding(self): self.check_open_buffer_close_behaviour(self.encoded_file) def test_open_underclose_compression(self): self.check_open_buffer_close_behaviour(self.gzip_file) self.check_open_buffer_close_behaviour(self.bz2_file) def test_open_underclose_compression_encoding(self): self.check_open_buffer_close_behaviour(self.gzip_encoded_file) self.check_open_buffer_close_behaviour(self.bz2_encoded_file) def test_open_file_underclose_binary(self): self.check_open_file_buffer_close_behaviour(self.read_file) def test_open_file_underclose_encoding(self): self.check_open_file_buffer_close_behaviour(self.encoded_file) def test_open_file_underclose_compression(self): self.check_open_file_buffer_close_behaviour(self.gzip_file) self.check_open_file_buffer_close_behaviour(self.bz2_file) def test_open_file_underclose_compression_encoding(self): self.check_open_file_buffer_close_behaviour(self.gzip_encoded_file) self.check_open_file_buffer_close_behaviour(self.bz2_encoded_file) def test_open_binary(self): self.check_open_state_contents(self.read_file, self.binary_contents, True, mode='r', encoding='binary') def test_open_binary_compression_none(self): self.check_open_state_contents(self.read_file, self.binary_contents, True, mode='r', encoding='binary', compression=None) def test_open_encoding(self): self.check_open_state_contents(self.encoded_file, self.decoded_contents, False, mode='r', encoding=self.encoding) def test_open_auto_compression_binary(self): self.check_open_state_contents(self.gzip_file, self.binary_contents, True, mode='r', encoding='binary', compression='auto') self.check_open_state_contents(self.bz2_file, self.binary_contents, True, mode='r', encoding='binary', compression='auto') def test_open_gzip_compression_binary(self): self.check_open_state_contents(self.gzip_file, self.binary_contents, True, mode='r', encoding='binary', compression='gzip') def test_open_bz2_compression_binary(self): self.check_open_state_contents(self.bz2_file, self.binary_contents, True, mode='r', encoding='binary', compression='bz2') def test_open_default_compression_encoding(self): self.check_open_state_contents(self.gzip_encoded_file, self.decoded_contents, False, mode='r', encoding=self.encoding) self.check_open_state_contents(self.bz2_encoded_file, self.decoded_contents, False, mode='r', encoding=self.encoding) def test_open_file_binary(self): self.check_open_file_state_contents(self.read_file, self.binary_contents, True, mode='r', encoding='binary') def test_open_file_binary_compression_none(self): self.check_open_file_state_contents(self.read_file, self.binary_contents, True, mode='r', encoding='binary', compression=None) def test_open_file_encoding(self): self.check_open_file_state_contents(self.encoded_file, self.decoded_contents, False, mode='r', encoding=self.encoding) def test_open_file_auto_compression_binary(self): self.check_open_file_state_contents(self.gzip_file, self.binary_contents, True, mode='r', encoding='binary', compression='auto') self.check_open_file_state_contents(self.bz2_file, self.binary_contents, True, mode='r', encoding='binary', compression='auto') def test_open_file_gzip_compression_binary(self): self.check_open_file_state_contents(self.gzip_file, self.binary_contents, True, mode='r', encoding='binary', compression='gzip') def test_open_file_bz2_compression_binary(self): self.check_open_file_state_contents(self.bz2_file, self.binary_contents, True, mode='r', encoding='binary', compression='bz2') def test_open_file_default_compression_encoding(self): self.check_open_file_state_contents(self.gzip_encoded_file, self.decoded_contents, False, mode='r', encoding=self.encoding) self.check_open_file_state_contents(self.bz2_encoded_file, self.decoded_contents, False, mode='r', encoding=self.encoding) class ReadableSourceTest(unittest.TestCase): def setUp(self): self.read_file = self.get_fileobj(get_data_path("example_file")) self.gzip_file = \ self.get_fileobj(get_data_path("example_file.gz")) self.bz2_file = \ self.get_fileobj(get_data_path("example_file.bz2")) self.encoded_file = self.get_fileobj(get_data_path("big5_file")) self.gzip_encoded_file = \ self.get_fileobj(get_data_path("big5_file.gz")) self.bz2_encoded_file = \ self.get_fileobj(get_data_path("big5_file.bz2")) self.binary_contents = ( f"This is some content{os.linesep}" f"It occurs on more than one line{os.linesep}" ).replace("\r\n", "\n").encode() self.decoded_contents = '\u4f60\u597d\n' # Ni Hau self.compression = 'gzip' self.encoding = "big5" def tearDown(self): self.safe_close(self.read_file) self.safe_close(self.gzip_file) self.safe_close(self.bz2_file) self.safe_close(self.encoded_file) self.safe_close(self.gzip_encoded_file) self.safe_close(self.bz2_encoded_file) def safe_close(self, f): if hasattr(f, 'close'): f.close() class WritableBinarySourceTests: def check_closed(self, file, expected): if hasattr(file, 'closed'): self.assertEqual(file.closed, expected) def check_open_state_contents(self, file, contents, is_binary, **kwargs): if is_binary: result = skbio.io.open(file, mode='w', **kwargs) self.assertIsInstance(result, (io.BufferedWriter, io.BufferedRandom)) else: result = skbio.io.open(file, mode='w', **kwargs, newline='') self.assertIsInstance(result, io.TextIOBase) self.assertTrue(result.writable()) result.write(contents) self.assertFalse(result.closed) if self.expected_close: result.close() self.assertTrue(result.closed) self.check_closed(file, True) gc.collect() del result gc.collect() def compare_gzip_file_contents(self, a, b): # The first 10 bytes of a gzip header include a timestamp. The header # can be followed by other "volatile" metadata, so only compare gzip # footers (last 8 bytes) which contain a CRC-32 checksum and the length # of the uncompressed data. self.assertEqual(a[-8:], b[-8:]) def test_open_binary(self): self.check_open_state_contents(self.binary_file, self.binary_contents, True, encoding='binary', compression=None) self.assertEqual(self.get_contents(self.binary_file), self.binary_contents) def test_open_gzip(self): self.check_open_state_contents(self.gzip_file, self.text_contents, False, compression='gzip') self.compare_gzip_file_contents(self.get_contents(self.gzip_file), self.gzip_contents) def test_open_bz2(self): self.check_open_state_contents(self.bz2_file, self.text_contents, False, compression='bz2') self.assertEqual(self.get_contents(self.bz2_file), self.bz2_contents) def test_open_encoding(self): self.check_open_state_contents(self.big5_file, self.decoded_contents, False, encoding='big5') self.assertEqual( self.get_contents(self.big5_file) .decode(encoding="big5") .replace("\r\n", "\n") .encode(encoding="big5"), self.encoded_contents) def test_open_gzip_encoding(self): self.check_open_state_contents(self.gzip_encoded_file, self.decoded_contents, False, compression='gzip', encoding='big5') self.compare_gzip_file_contents( self.get_contents(self.gzip_encoded_file), self.gzip_encoded_contents) def test_open_bz2_encoding(self): self.check_open_state_contents(self.bz2_encoded_file, self.decoded_contents, False, compression='bz2', encoding='big5') self.assertEqual(self.get_contents(self.bz2_encoded_file), self.bz2_encoded_contents) class WritableSourceTest(unittest.TestCase): def setUp(self): self._dir = tempfile.mkdtemp() with io.open(get_data_path('example_file'), mode='rb') as f: self.binary_contents = f.read().decode('utf8').replace("\r\n", "\n", -1).encode('utf8') self.binary_file = self._make_file('example_file') with io.open(get_data_path('big5_file'), mode='rb') as f: self.encoded_contents = f.read().decode('big5').replace("\r\n", "\n", -1).encode('big5') self.big5_file = self._make_file('big5_file') with io.open(get_data_path('example_file.gz'), mode='rb') as f: self.gzip_contents = f.read() self.gzip_file = self._make_file('example_file.gz') with io.open(get_data_path('example_file.bz2'), mode='rb') as f: self.bz2_contents = f.read() self.bz2_file = self._make_file('example_file.bz2') with io.open(get_data_path('big5_file.gz'), mode='rb') as f: self.gzip_encoded_contents = f.read() self.gzip_encoded_file = self._make_file('big5_file.gz') with io.open(get_data_path('big5_file.bz2'), mode='rb') as f: self.bz2_encoded_contents = f.read() self.bz2_encoded_file = self._make_file('big5_file.bz2') self.decoded_contents = self.encoded_contents.decode('big5') self.text_contents = self.binary_contents.decode('utf8') def tearDown(self): self.safe_close(self.binary_file) self.safe_close(self.gzip_file) self.safe_close(self.bz2_file) self.safe_close(self.big5_file) self.safe_close(self.gzip_encoded_file) self.safe_close(self.bz2_encoded_file) shutil.rmtree(self._dir) def safe_close(self, f): if hasattr(f, 'close'): f.close() def _make_file(self, name): return self.get_fileobj(os.path.join(self._dir, name)) class TestReadFilepath(ReadableBinarySourceTests, ReadableSourceTest): expected_close = True def get_fileobj(self, path): return path class TestWriteFilepath(WritableBinarySourceTests, WritableSourceTest): expected_close = True def get_fileobj(self, path): return path def get_contents(self, file): with io.open(file, mode='rb') as f: return f.read() @unittest.skipIf(not has_responses, "Responses not available to mock tests.") class TestReadURL(ReadableBinarySourceTests, ReadableSourceTest): expected_close = True def setUp(self): super(TestReadURL, self).setUp() responses.start() for file in (get_data_path('example_file'), get_data_path('big5_file'), get_data_path('example_file.gz'), get_data_path('example_file.bz2'), get_data_path('big5_file.gz'), get_data_path('big5_file.bz2')): with io.open(file, mode='rb') as f: responses.add(responses.GET, self.get_fileobj(file), body=f.read(), content_type="application/octet-stream") def tearDown(self): super(TestReadURL, self).setUp() responses.stop() responses.reset() def get_fileobj(self, path): return "http://example.com/" + os.path.split(path)[1] class TestReadBytesIO(ReadableBinarySourceTests, ReadableSourceTest): expected_close = False def get_fileobj(self, path): with io.open(path, mode='rb') as f: return io.BytesIO(f.read()) class TestWriteBytesIO(WritableBinarySourceTests, WritableSourceTest): expected_close = False def get_fileobj(self, path): return io.BytesIO() def get_contents(self, file): return file.getvalue() def test_open_gzip(self): self.check_open_state_contents(self.gzip_file, self.text_contents, False, compression='gzip') self.compare_gzip_file_contents(self.get_contents(self.gzip_file), self.gzip_contents) def test_open_gzip_encoding(self): self.check_open_state_contents(self.gzip_encoded_file, self.decoded_contents, False, compression='gzip', encoding='big5') self.compare_gzip_file_contents( self.get_contents(self.gzip_encoded_file), self.gzip_encoded_contents) class TestReadBufferedReader(ReadableBinarySourceTests, ReadableSourceTest): expected_close = False def get_fileobj(self, path): return io.open(path, mode='rb') class TestWriteBufferedReader(WritableBinarySourceTests, WritableSourceTest): expected_close = False def get_fileobj(self, path): return io.open(path, mode='w+b') def get_contents(self, file): file.close() with io.open(file.name, mode='rb') as f: return f.read() class TestReadNamedTemporaryFile(ReadableBinarySourceTests, ReadableSourceTest): expected_close = False def get_fileobj(self, path): fileobj = tempfile.NamedTemporaryFile() with io.open(path, mode='rb') as fh: fileobj.write(fh.read()) fileobj.flush() fileobj.seek(0) return fileobj class TestWriteNamedTemporaryFile(WritableBinarySourceTests, WritableSourceTest): expected_close = False def get_fileobj(self, path): return tempfile.NamedTemporaryFile() def get_contents(self, file): file.flush() file.seek(0) contents = file.read() file.close() return contents class TestReadTemporaryFile(ReadableBinarySourceTests, ReadableSourceTest): expected_close = False def get_fileobj(self, path): fileobj = tempfile.TemporaryFile() with io.open(path, mode='rb') as fh: fileobj.write(fh.read()) fileobj.flush() fileobj.seek(0) return fileobj class TestWriteTemporaryFile(WritableBinarySourceTests, WritableSourceTest): expected_close = False def get_fileobj(self, path): return tempfile.TemporaryFile() def get_contents(self, file): file.flush() file.seek(0) contents = file.read() file.close() return contents class TestIterableReaderWriter(unittest.TestCase): def test_open(self): def gen(): yield from ('a', 'b', 'c') list_ = list(gen()) for input_ in gen(), list_: with skbio.io.open(input_) as result: self.assertIsInstance(result, io.TextIOBase) self.assertEqual(result.read(), 'abc') def test_open_with_newline(self): lines = ['a\r', 'b\r', 'c\r'] with skbio.io.open(lines, newline='\r') as result: self.assertIsInstance(result, io.TextIOBase) self.assertEqual(result.readlines(), lines) def test_open_invalid_iterable(self): with self.assertRaises(skbio.io.IOSourceError): skbio.io.open([1, 2, 3]) def test_open_empty_iterable(self): with skbio.io.open([]) as result: self.assertIsInstance(result, io.TextIOBase) self.assertEqual(result.read(), '') def test_open_write_mode(self): lines = [] with skbio.io.open(lines, mode='w') as fh: fh.write('abc') self.assertEqual(lines, ['abc']) lines = [] with skbio.io.open(lines, mode='w', newline='\r') as fh: fh.write('ab\nc\n') self.assertEqual(lines, ['ab\r', 'c\r']) self.assertTrue(fh.closed) fh.close() self.assertTrue(fh.closed) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/io/util.py000066400000000000000000000255041520735541300214260ustar00rootroot00000000000000r"""I/O utilities (:mod:`skbio.io.util`) ==================================== .. currentmodule:: skbio.io.util This module provides utility functions to deal with files and I/O in general. Functions --------- .. autosummary:: :toctree: open open_file open_files """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from contextlib import contextmanager, ExitStack from skbio.io import IOSourceError from skbio.io._iosources import get_io_sources, get_compression_handler from skbio.io._fileobject import ( is_binary_file, SaneTextIOWrapper, CompressedBufferedReader, CompressedBufferedWriter, ) _d = dict( mode="r", encoding=None, errors=None, newline=None, compression="auto", compresslevel=9, ) def _resolve( file, mode=_d["mode"], encoding=_d["encoding"], errors=_d["errors"], newline=_d["newline"], compression=_d["compression"], compresslevel=_d["compresslevel"], ): arguments = locals().copy() if mode not in {"r", "w"}: raise ValueError("Unsupported mode: %r, use 'r' or 'w'" % mode) newfile = None source = None for source_handler in get_io_sources(): source = source_handler(file, arguments) if mode == "r" and source.can_read(): newfile = source.get_reader() break elif mode == "w" and source.can_write(): newfile = source.get_writer() break if newfile is None: raise IOSourceError("Could not open source: %r (mode: %r)" % (file, mode)) return newfile, source, is_binary_file(newfile) def open( file, mode=_d["mode"], encoding=_d["encoding"], errors=_d["errors"], newline=_d["newline"], compression=_d["compression"], compresslevel=_d["compresslevel"], ): r"""Convert input into a filehandle. Supported inputs: +--------------------------------------+--------+---------+-----------+ | type | can \ | can \ | source \ | | | read | write | type | +======================================+========+=========+===========+ | file path | True | True | Binary | +--------------------------------------+--------+---------+-----------+ | URL | True | False | Binary | +--------------------------------------+--------+---------+-----------+ | ``["lines list\n"]`` | True | True | Text | +--------------------------------------+--------+---------+-----------+ | :class:`io.StringIO` | True | True | Text | +--------------------------------------+--------+---------+-----------+ | :class:`io.BytesIO` | True | True | Binary | +--------------------------------------+--------+---------+-----------+ | :class:`io.TextIOWrapper` | True | True | Text | +--------------------------------------+--------+---------+-----------+ | :class:`io.BufferedReader` | True | False | Binary | +--------------------------------------+--------+---------+-----------+ | :class:`io.BufferedWriter` | False | True | Binary | +--------------------------------------+--------+---------+-----------+ | :class:`io.BufferedRandom` | True | True | Binary | +--------------------------------------+--------+---------+-----------+ | :func:`tempfile.TemporaryFile` | True | True | Binary | +--------------------------------------+--------+---------+-----------+ | :func:`tempfile.NamedTemporaryFile` | True | True | Binary | +--------------------------------------+--------+---------+-----------+ .. note:: When reading a list of unicode (str) lines, the input for `newline` is used to determine the number of lines in the resulting file handle, not the number of elements in the list. This is to allow composition with ``file.readlines()``. Parameters ---------- file : filepath, url, filehandle, list The input to convert to a filehandle. mode : {'r', 'w'}, optional Whether to return a readable or writable file. Conversely, this does not imply that the returned file will be unwritable or unreadable. To get a binary filehandle set `encoding` to binary. encoding : str, optional The encoding scheme to use for the file. If set to 'binary', no bytes will be translated. Otherwise this matches the behavior of :func:`io.open`. errors : str, optional Specifies how encoding and decoding errors are to be handled. This has no effect when `encoding` is binary (as there can be no errors). Otherwise this matches the behavior of :func:`io.open`. newline : {None, "", '\\n', '\\r\\n', '\\r'}, optional Matches the behavior of :func:`io.open`. compression : {'auto', 'gzip', 'bz2', None}, optional Will compress or decompress `file` depending on `mode`. If 'auto' then determining the compression of the file will be attempted and the result will be transparently decompressed. 'auto' will do nothing when writing. Other legal values will use their respective compression schemes. `compression` cannot be used with a text source. compresslevel : int (0-9 inclusive), optional The level of compression to use, will be passed to the appropriate compression handler. This is only used when writing. Returns ------- filehandle : io.TextIOBase or io.BufferedReader/Writer When `encoding='binary'` an :class:`io.BufferedReader` or :class:`io.BufferedWriter` will be returned depending on `mode`. Otherwise an implementation of :class:`io.TextIOBase` will be returned. .. note:: Any underlying resources needed to create `filehandle` are managed transparently. If `file` was closeable, garbage collection of `filehandle` will not close `file`. Calling `close` on `filehandle` will close `file`. Conversely calling `close` on `file` will cause `filehandle` to reflect a closed state. **This does not mean that a `flush` has occurred for `filehandle`, there may still have been data in its buffer! Additionally, resources may not have been cleaned up properly, so ALWAYS call `close` on `filehandle` and NOT on `file`.** """ arguments = locals().copy() del arguments["file"] file, _, is_binary_file = _resolve(file, **arguments) return _munge_file(file, is_binary_file, arguments) def _munge_file(file, is_binary_file, arguments): mode = arguments.get("mode", _d["mode"]) encoding = arguments.get("encoding", _d["encoding"]) errors = arguments.get("errors", _d["errors"]) newline = arguments.get("newline", _d["newline"]) compression = arguments.get("compression", _d["compression"]) is_output_binary = encoding == "binary" newfile = file compression_handler = get_compression_handler(compression) if is_output_binary and newline is not _d["newline"]: raise ValueError("Cannot use `newline` with binary encoding.") if compression is not None and not compression_handler: raise ValueError("Unsupported compression: %r" % compression) if is_binary_file: if compression: c = compression_handler(newfile, arguments) if mode == "w": newfile = CompressedBufferedWriter( file, c.get_writer(), streamable=c.streamable ) else: newfile = CompressedBufferedReader(file, c.get_reader()) if not is_output_binary: newfile = SaneTextIOWrapper( newfile, encoding=encoding, errors=errors, newline=newline ) else: if compression is not None and compression != "auto": raise ValueError("Cannot use compression with that source.") if is_output_binary: raise ValueError("Source is not a binary source") return newfile @contextmanager def _resolve_file(file, **kwargs): file, source, is_binary_file = _resolve(file, **kwargs) try: yield file, source, is_binary_file finally: if source.closeable: file.close() @contextmanager def open_file(file, **kwargs): r"""Context manager for :func:`skbio.io.util.open`. The signature matches :func:`open`. This context manager will not close filehandles that it did not create itself. Examples -------- Here our input isn't a filehandle and so `f` will get closed. >>> with open_file(['a\n']) as f: ... f.read() ... 'a\n' >>> f.closed True Here we provide an open file and so `f` will not get closed and neither will `file`. >>> file = io.BytesIO(b'BZh91AY&SY\x03\x89\x0c\xa6\x00\x00\x01\xc1\x00\x00' ... b'\x108\x00 \x00!\x9ah3M\x1c\xb7\x8b\xb9"\x9c(H\x01' ... b'\xc4\x86S\x00') >>> with open_file(file) as f: ... f.read() ... 'a\nb\nc\n' >>> f.closed False >>> file.closed False """ with _resolve_file(file, **kwargs) as (file, source, is_binary_file): newfile = _munge_file(file, is_binary_file, source.options) try: yield newfile finally: # As soon as we leave the above context manager file will be closed # It is important to realize that because we are closing an inner # buffer, the outer buffer will reflect that state, but it won't # get flushed as the inner buffer is oblivious to the outer # buffer's existence. if not newfile.closed: newfile.flush() _flush_compressor(newfile) def _flush_compressor(file): if isinstance(file, io.TextIOBase) and hasattr(file, "buffer"): file = file.buffer if isinstance(file, CompressedBufferedWriter) and not file.streamable: # Some formats like BZ2 compress the entire file, and so they will # only flush once they have been closed. These kinds of files do not # close their underlying buffer, but only testing can prove that... file.raw.close() @contextmanager def open_files(files, **kwargs): """Context manager for :func:`skbio.io.util.open`. A plural form of :func:`open_file`. """ with ExitStack() as stack: yield [stack.enter_context(open_file(f, **kwargs)) for f in files] scikit-bio-scikit-bio-a3beaa6/skbio/metadata/000077500000000000000000000000001520735541300212425ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/metadata/__init__.py000066400000000000000000000036331520735541300233600ustar00rootroot00000000000000r"""Metadata (:mod:`skbio.metadata`) ================================ .. currentmodule:: skbio.metadata This module provides functionality for storing and working with metadata -- the data that describes other data. While a typical data table (see :mod:`skbio.table`) stores the measurements of features in samples, metadata provides information about the samples or features themselves. Examples of metadata include experimental grouping, demographic and clinical properties of subjects, functional categories of genes and metabolites, etc. Sample metadata --------------- .. autosummary:: :toctree: generated/ SampleMetadata Metadata columns ---------------- .. autosummary:: :toctree: generated/ MetadataColumn NumericMetadataColumn CategoricalMetadataColumn Interval metadata ----------------- .. autosummary:: :toctree: generated/ Interval IntervalMetadata Abstract classes ---------------- .. autosummary:: :toctree: generated/ MetadataMixin PositionalMetadataMixin IntervalMetadataMixin """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._metadata import ( SampleMetadata, MetadataColumn, NumericMetadataColumn, CategoricalMetadataColumn, ) from ._interval import Interval, IntervalMetadata from ._mixin import ( MetadataMixin, PositionalMetadataMixin, IntervalMetadataMixin, ) __all__ = [ "SampleMetadata", "MetadataColumn", "NumericMetadataColumn", "CategoricalMetadataColumn", "Interval", "IntervalMetadata", "MetadataMixin", "PositionalMetadataMixin", "IntervalMetadataMixin", ] scikit-bio-scikit-bio-a3beaa6/skbio/metadata/_enan.py000066400000000000000000000071231520735541300226770ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2016-2023, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import struct def _float_to_int(number: float) -> int: # convert float to a native-endian 8-byte sequence (a double): # (alignment doesn't matter because this isn't a struct, and since we are # on the same hardware when we go to int, the endian-ness doesn't matter # either) bytes_ = struct.pack("=d", number) (integer,) = struct.unpack("=Q", bytes_) return integer def _int_to_float(number: int) -> float: bytes_ = struct.pack("=Q", number) (float_,) = struct.unpack("=d", bytes_) return float_ # 1954 is an homage to R's NA value which is a quiet NaN with a mantissa which # appears to represent 1954, birth-year of Ross Ihaka (source: Hadley Wickham) # http://www.markvanderloo.eu # /yaRb/2012/07/08/representation-of-numerical-nas-in-r-and-the-1954-enigma/ # It also happens to let us tolerate small negative values (such as -1 used # in pd.Categorical.codes) without trashing the entire NaN. # ('Q' from struct does fortunately catch this issue before it becomes a # larger problem) _R_OFFSET = 1954 _DEFAULT_NAN_INT = _float_to_int(float("nan")) # at this point, calling `bin(_DEFAULT_NAN_INT)` should produce a # 64-bit positive quiet nan: # 0 11111111111 1000000000000000000000000000000000000000000000000000 # https://www.csee.umbc.edu/courses/undergraduate/CMSC211/spring03 # /burt/tech_help/IEEE-754references.html # unless Python changes some implementation detail, which isn't a problem so # long as XOR is used instead of AND def make_nan_with_payload(payload: int, namespace: int = 255): """Construct a NaN with a namespace and payload. The payload must be in the range [-1953, 2141] The namespace must be in the range [0, 255] sign exp mantissa v v---------v v----------------------------------------------------------v +qNaN "header" (includes 1 bit of the mantissa) namespace payload v-------------v v-------v v------------v 0 11111111111 10000000 00000000 00000000 00000000 0000 0000 0000 0000 0000 The namespace + payload requires 20 bits of the mantissa, which will support both 32-bit floats and 64-bit doubles. The purpose is to allow enumerations to be identified and values preserved. Custom enumerations will have a namespace of 255 and will require user guidance. Other built-in schemes should organize themselves within an unsigned byte. The enumeration values are then stored in the payload which uses an offset of 1954 to distinguish between default +qNaN and an enumeration scheme. This also permits small negative values in the payload. """ # To be safe, we will XOR our payload (instead of AND) so that we can take # the difference later, even if the default NaN changes to include a # mantissa payload for some reason nan_int = _DEFAULT_NAN_INT ^ (namespace << 12) nan_int = nan_int ^ (_R_OFFSET + payload) return _int_to_float(nan_int) def get_payload_from_nan(nan: float): nan_int = _float_to_int(nan) namespaced_payload = nan_int ^ _DEFAULT_NAN_INT if namespaced_payload == 0: return (None, None) namespace = namespaced_payload >> 12 payload = namespaced_payload - (namespace << 12) return (payload - _R_OFFSET, namespace) scikit-bio-scikit-bio-a3beaa6/skbio/metadata/_intersection.pyx000066400000000000000000000443541520735541300246630ustar00rootroot00000000000000# ----------------------------------------------------------------------------- # This code is taken from bx-python project and added with a new function # `update` from line 195 to 211. The license for this code is included in # licenses/bx_python.txt. # ----------------------------------------------------------------------------- """ Data structure for performing intersect queries on a set of intervals which preserves all information about the intervals (unlike bitset projection methods). :Authors: James Taylor (james@jamestaylor.org), Ian Schenk (ian.schenck@gmail.com), Brent Pedersen (bpederse@gmail.com) """ # Historical note: # This module original contained an implementation based on sorted endpoints # and a binary search, using an idea from Scott Schwartz and Piotr Berman. # Later an interval tree implementation was implemented by Ian for Galaxy's # join tool (see `bx.intervals.operations.quicksect.py`). This was then # converted to Cython by Brent, who also added support for # upstream/downstream/neighbor queries. This was modified by James to # handle half-open intervals strictly, to maintain sort order, and to # implement the same interface as the original Intersecter. #cython: cdivision=True import operator cdef extern from "stdlib.h": int ceil(float f) float log(float f) int RAND_MAX int rand() int strlen(char *) int iabs(int) cdef inline int imax2(int a, int b): if b > a: return b return a cdef inline int imax3(int a, int b, int c): if b > a: if c > b: return c return b if a > c: return a return c cdef inline int imin3(int a, int b, int c): if b < a: if c < b: return c return b if a < c: return a return c cdef inline int imin2(int a, int b): if b < a: return b return a cdef float nlog = -1.0 / log(0.5) cdef class IntervalNode: """ A single node of an `IntervalTree`. NOTE: Unless you really know what you are doing, you probably should us `IntervalTree` rather than using this directly. """ cdef float priority cdef public object interval cdef public int start, end cdef int minend, maxend, minstart cdef IntervalNode cleft, cright, croot property left_node: def __get__(self): return self.cleft if self.cleft is not EmptyNode else None property right_node: def __get__(self): return self.cright if self.cright is not EmptyNode else None property root_node: def __get__(self): return self.croot if self.croot is not EmptyNode else None def __repr__(self): return "IntervalNode(%i, %i)" % (self.start, self.end) def __cinit__(IntervalNode self, int start, int end, object interval): # Python lacks the binomial distribution, so we convert a # uniform into a binomial because it naturally scales with # tree size. Also, python's uniform is perfect since the # upper limit is not inclusive, which gives us undefined here. self.priority = ceil(nlog * log(-1.0/(rand()/(RAND_MAX + 1.0) - 1))) self.start = start self.end = end self.interval = interval self.maxend = end self.minstart = start self.minend = end self.cleft = EmptyNode self.cright = EmptyNode self.croot = EmptyNode cpdef IntervalNode insert(IntervalNode self, int start, int end, object interval): """ Insert a new IntervalNode into the tree of which this node is currently the root. The return value is the new root of the tree (which may or may not be this node!) """ cdef IntervalNode croot = self # If starts are the same, decide which to add interval to based on # end, thus maintaining sortedness relative to start/end cdef int decision_endpoint = start if start == self.start: decision_endpoint = end if decision_endpoint > self.start: # insert to cright tree if self.cright is not EmptyNode: self.cright = self.cright.insert( start, end, interval ) else: self.cright = IntervalNode( start, end, interval ) # rebalance tree if self.priority < self.cright.priority: croot = self.rotate_left() else: # insert to cleft tree if self.cleft is not EmptyNode: self.cleft = self.cleft.insert( start, end, interval) else: self.cleft = IntervalNode( start, end, interval) # rebalance tree if self.priority < self.cleft.priority: croot = self.rotate_right() croot.set_ends() self.cleft.croot = croot self.cright.croot = croot return croot cdef IntervalNode rotate_right(IntervalNode self): cdef IntervalNode croot = self.cleft self.cleft = self.cleft.cright croot.cright = self self.set_ends() return croot cdef IntervalNode rotate_left(IntervalNode self): cdef IntervalNode croot = self.cright self.cright = self.cright.cleft croot.cleft = self self.set_ends() return croot cdef inline void set_ends(IntervalNode self): if self.cright is not EmptyNode and self.cleft is not EmptyNode: self.maxend = imax3(self.end, self.cright.maxend, self.cleft.maxend) self.minend = imin3(self.end, self.cright.minend, self.cleft.minend) self.minstart = imin3(self.start, self.cright.minstart, self.cleft.minstart) elif self.cright is not EmptyNode: self.maxend = imax2(self.end, self.cright.maxend) self.minend = imin2(self.end, self.cright.minend) self.minstart = imin2(self.start, self.cright.minstart) elif self.cleft is not EmptyNode: self.maxend = imax2(self.end, self.cleft.maxend) self.minend = imin2(self.end, self.cleft.minend) self.minstart = imin2(self.start, self.cleft.minstart) def intersect( self, int start, int end, sort=True ): """ given a start and a end, return a list of features falling within that range """ cdef list results = [] self._intersect( start, end, results ) return results find = intersect cdef void _intersect( IntervalNode self, int start, int end, list results): cdef int send, qend # Left subtree if self.cleft is not EmptyNode and self.cleft.maxend >= start: self.cleft._intersect( start, end, results ) # This interval if start == end: qend = end else: qend = end - 1 if self.end == self.start: send = self.end else: send = self.end - 1 if ( send >= start ) and ( self.start <= qend ): results.append( self.interval ) # Right subtree if self.cright is not EmptyNode and self.start <= qend: self.cright._intersect( start, end, results ) cpdef void update(IntervalNode self, int start, int end, object old_feature, object new_feature): """ given a start and end, replace all objects that match the old_feature with new_feature. """ # Left subtree if self.cleft is not EmptyNode and self.cleft.maxend > start: self.cleft.update( start, end, old_feature, new_feature ) # This interval if ( self.end > start ) and ( self.start < end ): if self.interval == old_feature: self.interval = new_feature # Right subtree if self.cright is not EmptyNode and self.start < end: self.cright.update( start, end, old_feature, new_feature ) cdef void _seek_left(IntervalNode self, int position, list results, int n, int max_dist): # we know we can bail in these 2 cases. if self.maxend + max_dist < position: return if self.minstart > position: return # the ordering of these 3 blocks makes it so the results are # ordered nearest to farest from the query position if self.cright is not EmptyNode: self.cright._seek_left(position, results, n, max_dist) if -1 < position - self.end < max_dist: results.append(self.interval) # TODO: can these conditionals be more stringent? if self.cleft is not EmptyNode: self.cleft._seek_left(position, results, n, max_dist) cdef void _seek_right(IntervalNode self, int position, list results, int n, int max_dist): # we know we can bail in these 2 cases. if self.maxend < position: return if self.minstart - max_dist > position: return #print "SEEK_RIGHT:",self, self.cleft, self.maxend, self.minstart, position # the ordering of these 3 blocks makes it so the results are # ordered nearest to farest from the query position if self.cleft is not EmptyNode: self.cleft._seek_right(position, results, n, max_dist) if -1 < self.start - position < max_dist: results.append(self.interval) if self.cright is not EmptyNode: self.cright._seek_right(position, results, n, max_dist) cpdef left(self, position, int n=1, int max_dist=2500): """ find n features with a start > than `position` f: a Interval object (or anything with an `end` attribute) n: the number of features to return max_dist: the maximum distance to look before giving up. """ cdef list results = [] # use start - 1 becuase .left() assumes strictly left-of self._seek_left( position - 1, results, n, max_dist ) if len(results) == n: return results r = results r.sort(key=operator.attrgetter('end'), reverse=True) return r[:n] cpdef right(self, position, int n=1, int max_dist=2500): """ find n features with a end < than position f: a Interval object (or anything with a `start` attribute) n: the number of features to return max_dist: the maximum distance to look before giving up. """ cdef list results = [] # use end + 1 becuase .right() assumes strictly right-of self._seek_right(position + 1, results, n, max_dist) if len(results) == n: return results r = results r.sort(key=operator.attrgetter('start')) return r[:n] def traverse(self, func): self._traverse(func) cdef void _traverse(IntervalNode self, object func): if self.cleft is not EmptyNode: self.cleft._traverse(func) func(self) if self.cright is not EmptyNode: self.cright._traverse(func) cdef IntervalNode EmptyNode = IntervalNode( 0, 0, IntervalObj(0, 0)) ## ---- Wrappers that retain the old interface ------------------------------- cdef class IntervalObj: """ Basic feature, with required integer start and end properties. Also accepts optional strand as +1 or -1 (used for up/downstream queries), a name, and any arbitrary data is sent in on the info keyword argument >>> from skbio.metadata._intersection import IntervalObj >>> f1 = IntervalObj(23, 36) >>> f2 = IntervalObj(34, 48, value={'chr':12, 'anno':'transposon'}) >>> f2 # doctest: +SKIP IntervalObj(34, 48, value={'anno': 'transposon', 'chr': 12}) """ cdef public int start, end cdef public object value, chrom, strand def __init__(self, int start, int end, object value=None, object chrom=None, object strand=None ): assert start <= end, "start must be less than end" self.start = start self.end = end self.value = value self.chrom = chrom self.strand = strand def __repr__(self): fstr = "IntervalObj(%d, %d" % (self.start, self.end) if not self.value is None: fstr += ", value=" + str(self.value) fstr += ")" return fstr def __richcmp__(self, other, op): if op == 0: # < return self.start < other.start or self.end < other.end elif op == 1: # <= return self == other or self < other elif op == 2: # == return self.start == other.start and self.end == other.end elif op == 3: # != return self.start != other.start or self.end != other.end elif op == 4: # > return self.start > other.start or self.end > other.end elif op == 5: # >= return self == other or self > other cdef class IntervalTree: """ Data structure for performing window intersect queries on a set of of possibly overlapping 1d intervals. Usage ===== Create an empty IntervalTree >>> from skbio.metadata._intersection import IntervalObj, IntervalTree >>> intersecter = IntervalTree() An interval is a start and end position and a value (possibly None). You can add any object as an interval: >>> intersecter.insert( 0, 10, "food" ) >>> intersecter.insert( 3, 7, dict(foo='bar') ) >>> intersecter.find( 2, 5 ) ['food', {'foo': 'bar'}] If the object has start and end attributes (like the Interval class) there is are some shortcuts: >>> intersecter = IntervalTree() >>> intersecter.insert_interval( IntervalObj( 0, 10 ) ) >>> intersecter.insert_interval( IntervalObj( 3, 7 ) ) >>> intersecter.insert_interval( IntervalObj( 3, 40 ) ) >>> intersecter.insert_interval( IntervalObj( 13, 50 ) ) >>> intersecter.find( 30, 50 ) [IntervalObj(3, 40), IntervalObj(13, 50)] >>> intersecter.find( 100, 200 ) [] Before/after for intervals >>> intersecter.before_interval( IntervalObj( 10, 20 ) ) [IntervalObj(3, 7)] >>> intersecter.before_interval( IntervalObj( 5, 20 ) ) [] Upstream/downstream >>> intersecter.upstream_of_interval(IntervalObj(11, 12)) [IntervalObj(0, 10)] >>> intersecter.upstream_of_interval(IntervalObj(11, 12, strand="-")) [IntervalObj(13, 50)] >>> intersecter.upstream_of_interval(IntervalObj(1, 2, strand="-"), num_intervals=3) [IntervalObj(3, 7), IntervalObj(3, 40), IntervalObj(13, 50)] """ cdef IntervalNode root def __cinit__( self ): root = None # ---- Position based interfaces ----------------------------------------- def insert( self, int start, int end, object value=None ): """ Insert the interval [start,end) associated with value `value`. """ if self.root is None: self.root = IntervalNode( start, end, value ) else: self.root = self.root.insert( start, end, value ) add = insert def update( self, start, end, old_feature, new_feature): """ Given an interval [start, end), replace all objects that match the `old_feature` with `new_feature`. """ if self.root is not None: self.root.update(start, end, old_feature, new_feature) def find( self, start, end ): """ Return a sorted list of all intervals overlapping [start,end). """ if self.root is None: return [] return self.root.find( start, end ) def before( self, position, num_intervals=1, max_dist=2500 ): """ Find `num_intervals` intervals that lie before `position` and are no further than `max_dist` positions away """ if self.root is None: return [] return self.root.left( position, num_intervals, max_dist ) def after( self, position, num_intervals=1, max_dist=2500 ): """ Find `num_intervals` intervals that lie after `position` and are no further than `max_dist` positions away """ if self.root is None: return [] return self.root.right( position, num_intervals, max_dist ) # ---- Interval-like object based interfaces ----------------------------- def insert_interval( self, interval ): """ Insert an "interval" like object (one with at least start and end attributes) """ self.insert( interval.start, interval.end, interval ) add_interval = insert_interval def before_interval( self, interval, num_intervals=1, max_dist=2500 ): """ Find `num_intervals` intervals that lie completely before `interval` and are no further than `max_dist` positions away """ if self.root is None: return [] return self.root.left( interval.start, num_intervals, max_dist ) def after_interval( self, interval, num_intervals=1, max_dist=2500 ): """ Find `num_intervals` intervals that lie completely after `interval` and are no further than `max_dist` positions away """ if self.root is None: return [] return self.root.right( interval.end, num_intervals, max_dist ) def upstream_of_interval( self, interval, num_intervals=1, max_dist=2500 ): """ Find `num_intervals` intervals that lie completely upstream of `interval` and are no further than `max_dist` positions away """ if self.root is None: return [] if interval.strand == -1 or interval.strand == "-": return self.root.right( interval.end, num_intervals, max_dist ) else: return self.root.left( interval.start, num_intervals, max_dist ) def downstream_of_interval( self, interval, num_intervals=1, max_dist=2500 ): """ Find `num_intervals` intervals that lie completely downstream of `interval` and are no further than `max_dist` positions away """ if self.root is None: return [] if interval.strand == -1 or interval.strand == "-": return self.root.left( interval.start, num_intervals, max_dist ) else: return self.root.right( interval.end, num_intervals, max_dist ) def traverse(self, fn): """ call fn for each element in the tree """ if self.root is None: return None return self.root.traverse(fn) # For backward compatibility Intersecter = IntervalTree scikit-bio-scikit-bio-a3beaa6/skbio/metadata/_interval.py000066400000000000000000001055471520735541300236130ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations import operator import copy import functools from typing import TYPE_CHECKING from ._intersection import IntervalTree from skbio.util._decorator import classonlymethod from skbio.io.descriptors import Read, Write from .._base import SkbioObject if TYPE_CHECKING: from typing import Self class Interval: """Stores the bounds and metadata of an interval feature. This class stores an interval feature. An interval feature is defined as a sub-region of a biological sequence or sequence alignment that is a functional entity, e.g., a gene, a riboswitch, an exon, etc. It can span a single contiguous region or multiple non-contiguous regions (e.g. multiple exons in a transcript, or multiple genes in an operon). Parameters ---------- interval_metadata : object A reference to the ``IntervalMetadata`` object that this ``Interval`` object is associated to. bounds : iterable of tuple of int Tuples representing start and end coordinates. It is *zero-based* numbering. It is always inclusive on start bound and exclusive on end bound. fuzzy : iterable of tuple of bool, optional Tuples representing the fuzziness of each bound coordinates. If this isn't specified, then the fuzziness of all bound coordinates are ``False``. If any of the coordinate fuzziness is ``True``, it indicates that the exact bound point of a interval feature is unknown. The bound may begin or end at some points outside the specified coordinates. This accommodates the location format [1]_ of INSDC. metadata : dict, optional Dictionary of attributes storing information of the feature such as "strand", "gene_name", or "product". See Also -------- skbio.metadata.IntervalMetadata Notes ----- While the construction of an ``Interval`` object automatically add itself to its associated ``IntervalMetadata`` object, ``IntervalMetadata.add`` is the typical/easier way to create and add it to ``IntervalMetadata``. References ---------- .. [1] ftp://ftp.ebi.ac.uk/pub/databases/embl/doc/FT_current.html#3.4.3 Examples -------- Hypothetically, let's say we have a gene called "genA" with 10 nt as shown in the following diagram. The second row represents the two exons (indicated by "=") on this gene: :: TGGATTCTGC -====--==- 0123456789 We can create an ``Interval`` object to represent the exons of the gene: >>> from skbio.metadata import Interval, IntervalMetadata >>> interval_metadata = IntervalMetadata(10) Remember the coordinates are inclusive in lower bound and exclusive on upper bound: >>> gene = Interval(interval_metadata, ... bounds=[(1, 5), (7, 9)], ... metadata={'name': 'genA'}) >>> gene # doctest: +ELLIPSIS Interval(interval_metadata=..., bounds=[(1, 5), (7, 9)], \ fuzzy=[(False, False), (False, False)], metadata={'name': 'genA'}) """ def __init__(self, interval_metadata, bounds, fuzzy=None, metadata=None): if not isinstance(interval_metadata, IntervalMetadata): raise TypeError( "You need to provide an IntervalMetadata" "object, not %r" % interval_metadata ) # Intervals self._interval_metadata = interval_metadata self._bounds_fuzzy_setter(bounds, fuzzy) # Metadata if metadata is None: metadata = {} self.metadata = metadata # add this interval feature to the associated IntervalMetadata self._add() def _add(self): """Add the current ``Interval`` to the IntervalMetadata object.""" for bound in self.bounds: start, end = bound self._interval_metadata._interval_tree.add(start, end, self) self._interval_metadata._intervals.append(self) def __eq__(self, other): """Test if this ``Interval`` object is equal to another. The equality is performed by checking if the ``metadata``, ``bounds`` and ``fuzzy`` are equal. Since the ``bounds`` and the ``fuzzy`` are sorted, the permutations of them during the ``Interval`` construction or assignment won't matter. Parameters ---------- other : Interval Interval to test for equality against. Returns ------- bool Indicates if the two objects are equal. """ return ( (self.metadata == other.metadata) and (self.bounds == other.bounds) and (self.fuzzy == other.fuzzy) ) def __ne__(self, other): """Test if this ``Interval`` object is not equal to another. Parameters ---------- other : Interval Interval to test for inequality against. Returns ------- bool Indicates if the two objects are not equal. """ return not (self == other) def __repr__(self): """Return a string representation of this ``Interval`` object. Returns ------- str String representation of this ``Interval`` object. """ if self.dropped: s = "{}(dropped=True, bounds={!r}, fuzzy={!r}, metadata={!r})" return s.format( self.__class__.__name__, self.bounds, self.fuzzy, self.metadata ) else: s = "{}(interval_metadata=<{!r}>, bounds={!r}, fuzzy={!r}, metadata={!r})" return s.format( self.__class__.__name__, id(self._interval_metadata), self.bounds, self.fuzzy, self.metadata, ) def drop(self): """Drop this ``Interval`` object from interval metadata it links to. If the ``Interval`` object is dropped, you can still get values of ``bounds``, ``fuzzy``, and ``metadata`` attributes, but you can not change their values with the setters. See Also -------- skbio.metadata.IntervalMetadata.drop """ if not self.dropped: self._interval_metadata.drop([self]) def _bounds_fuzzy_setter(self, bounds=None, fuzzy=None): if self.dropped: raise RuntimeError( "Cannot change `bounds` or `fuzzy` on a dropped Interval object." ) # Casts to `list`, validation, sorting, and setting of `bounds` # and `fuzzy` happen here. if bounds is not None: # check iterability try: # check iterability bounds = list(bounds) except TypeError: raise TypeError( "Cannot give an non-iterable (%r) to `bounds`." % bounds ) # check it is not empty if not bounds: raise ValueError("Cannot give empty `bounds`.") # check each contiguous span is in right format for bound in bounds: _assert_valid_bound(bound) spans = len(bounds) else: spans = len(self.bounds) if fuzzy is not None: try: fuzzy = list(fuzzy) except TypeError: raise TypeError("Cannot give a non-iterable (%r) to `fuzzy`." % fuzzy) if len(fuzzy) != spans: raise ValueError( "The length of fuzzy must be equal to the length of bounds." ) for fuzzy_i in fuzzy: _assert_valid_fuzzy(fuzzy_i) if bounds is None: # `bounds` and `fuzzy` cannot both be omitted. if fuzzy is None: raise ValueError("Cannot give `None` to both `bounds` and `fuzzy`.") # If only `fuzzy` is provided, set `self.fuzzy` and don't # change `self.bounds`. else: self._fuzzy = fuzzy else: # If only `bounds` is provided, reset `self.fuzzy` to # all `False`. if fuzzy is None: bounds.sort() self._check_bounds(bounds) self._bounds = bounds # reset all the fuzzy to False!! del self.fuzzy # If both `bounds` and `fuzzy` are provided, set # `self.bounds` and `self.fuzzy`. else: bounds, fuzzy = [list(e) for e in zip(*sorted(zip(bounds, fuzzy)))] self._check_bounds(bounds) self._bounds = bounds self._fuzzy = fuzzy self._interval_metadata._is_stale_tree = True def _check_bounds(self, bounds): """Input `bounds` must be sorted.""" upper_bound = self._interval_metadata.upper_bound lower_bound = self._interval_metadata.lower_bound if upper_bound is not None and bounds[-1][-1] > upper_bound: raise ValueError( "Cannot set `bounds` (%r) with coordinate " "larger than upper bound (%r)" % (bounds, upper_bound) ) if bounds[0][0] < lower_bound: raise ValueError( "Cannot set `bounds` (%r) with coordinate " "smaller than lower bound (%r)." % (bounds, lower_bound) ) @property def fuzzy(self): """The openness of each coordinate. This indicates that the exact bound of a interval feature is unknown. The bound may begin or end at some points outside the specified coordinates. This accommodates the bound format [1]_ of INSDC. References ---------- .. [1] ftp://ftp.ebi.ac.uk/pub/databases/embl/doc/FT_current.html#3.4.3 """ return self._fuzzy @fuzzy.setter def fuzzy(self, value): """Set ``fuzzy``. The ``value`` should an iterable matching ``self.bounds``. """ self._bounds_fuzzy_setter(fuzzy=value) @fuzzy.deleter def fuzzy(self): """Delete ``fuzzy``. This set all fuzzy to be ``False``. """ if self.dropped: raise RuntimeError("Cannot change fuzzy on dropped Interval object.") self._fuzzy = [(False, False)] * len(self.bounds) @property def bounds(self): """The coordinates of the interval feature. It should be a list of tuples of int pair. Each tuple stores the start and end coordinates of a span of the interval feature. The coordinates are *zero-based*. They are inclusive on the start and exclusive on the end. """ return self._bounds @bounds.setter def bounds(self, value): """Set ``bounds``. WARNING: setting ``bounds`` will reset ``fuzzy`` value to ``False``. This is not totally surprising because it is justifiable your old ``fuzzy`` don't fit the new bounds. """ self._bounds_fuzzy_setter(bounds=value) @property def metadata(self): """The metadata of the interval feature. It stores the metadata (eg. gene name, function, ID, etc.) of the interval feature as a ``dict``. """ return self._metadata @metadata.setter def metadata(self, value): if self.dropped: raise RuntimeError("Cannot change metadata on dropped Interval object.") if not isinstance(value, dict): raise TypeError("metadata must be a dict, not %r" % value) self._metadata = value @metadata.deleter def metadata(self): """Delete metadata. This sets metadata to be empty dict. """ if self.dropped: raise RuntimeError("Cannot change metadata to dropped Interval object.") self._metadata = {} @property def dropped(self): """Boolean value indicating if the ``Interval`` object is dropped. If it is dropped, it means it is not associated with IntervalMetadata object any more. Notes ----- This property is not writable. See Also -------- skbio.metadata.Interval.drop skbio.metadata.IntervalMetadata.drop """ return self._interval_metadata is None class IntervalMetadata(SkbioObject): """Stores the interval features. ``IntervalMetadata`` object allows storage, modification, and querying of interval features covering a region of a single coordinate system. For instance, this can be used to store functional annotations about genes across a genome. This object is also applied to the sequence alignment. This object is typically coupled with another object, such as a ``Sequence`` object (or its child class), or a ``TabularMSA`` object. Parameters ---------- upper_bound : int or None Defines the exclusive upper bound of the interval features. No coordinate can be greater than it. ``None`` means that the coordinate space is unbounded. copy_from : IntervalMetadata or None, optional Create a new object from the input ``IntervalMetadata`` object by shallow copying if it is not ``None``. The upper bound of the new object will be updated with the ``upper_bound`` parameter specified. Notes ----- This class stores coordinates of all feature bounds into a interval tree. It allows the speed up of query-by-bound. The building of interval tree is deferred until necessary to save computation. It is updated from all coordinates only when you need to fetch info from the interval tree. When you add a method into this class and if you method need to fetch info from ``IntervalMetadata._interval_tree``, you should decorate it with ``_rebuild_tree``. This decorator will check if the current interval tree is stale and will update it if so. Additionally, if your method add, delete, or changes the coordinates of any interval features, you should set ``self._is_stale_tree`` to ``True`` at the end of your method to indicate the interval tree becomes stale. See Also -------- skbio.metadata.Interval Examples -------- Let's say we have a sequence of length 10 and want to add annotation to it. Create an ``IntervalMetadata`` object: >>> from skbio.metadata import Interval, IntervalMetadata >>> im = IntervalMetadata(10) Let's add annotations of 3 genes: >>> im.add(bounds=[(3, 9)], ... metadata={'gene': 'sagB'}) # doctest: +ELLIPSIS Interval(interval_metadata=..., bounds=[(3, 9)], \ fuzzy=[(False, False)], metadata={'gene': 'sagB'}) >>> im.add(bounds=[(3, 7)], ... metadata={'gene': 'sagC'}) # doctest: +ELLIPSIS Interval(interval_metadata=..., bounds=[(3, 7)], \ fuzzy=[(False, False)], metadata={'gene': 'sagC'}) >>> im.add(bounds=[(1, 2), (4, 7)], ... metadata={'gene': 'sagA'}) # doctest: +ELLIPSIS Interval(interval_metadata=..., bounds=[(1, 2), (4, 7)], \ fuzzy=[(False, False), (False, False)], metadata={'gene': 'sagA'}) Show the object representation: >>> im # doctest: +ELLIPSIS 3 interval features ------------------- Interval(interval_metadata=..., bounds=[(3, 9)], \ fuzzy=[(False, False)], metadata={'gene': 'sagB'}) Interval(interval_metadata=..., bounds=[(3, 7)], \ fuzzy=[(False, False)], metadata={'gene': 'sagC'}) Interval(interval_metadata=..., bounds=[(1, 2), (4, 7)], \ fuzzy=[(False, False), (False, False)], metadata={'gene': 'sagA'}) We can sort the genes by their bounds: >>> im.sort() >>> im # doctest: +ELLIPSIS 3 interval features ------------------- Interval(interval_metadata=..., bounds=[(1, 2), (4, 7)], \ fuzzy=[(False, False), (False, False)], metadata={'gene': 'sagA'}) Interval(interval_metadata=..., bounds=[(3, 7)], \ fuzzy=[(False, False)], metadata={'gene': 'sagC'}) Interval(interval_metadata=..., bounds=[(3, 9)], \ fuzzy=[(False, False)], metadata={'gene': 'sagB'}) Query the genes by bound and/or metadata: >>> intvls = im.query([(1, 2)], metadata={'gene': 'foo'}) >>> list(intvls) [] >>> intvls = im.query([(7, 9)]) >>> list(intvls) # doctest: +ELLIPSIS [Interval(interval_metadata=..., bounds=[(3, 9)], \ fuzzy=[(False, False)], metadata={'gene': 'sagB'})] >>> intvls = im.query(metadata={'gene': 'sagA'}) >>> intvls = list(intvls) >>> intvls # doctest: +ELLIPSIS [Interval(interval_metadata=..., bounds=[(1, 2), (4, 7)], \ fuzzy=[(False, False), (False, False)], metadata={'gene': 'sagA'})] Drop the gene(s) we get from query: >>> im.drop(intvls) >>> im.sort() >>> im # doctest: +ELLIPSIS 2 interval features ------------------- Interval(interval_metadata=..., bounds=[(3, 7)], \ fuzzy=[(False, False)], metadata={'gene': 'sagC'}) Interval(interval_metadata=..., bounds=[(3, 9)], \ fuzzy=[(False, False)], metadata={'gene': 'sagB'}) """ read = Read() write = Write() default_write_format = "gff3" """Default write format for this object: ``gff3``.""" def __init__(self, upper_bound, copy_from=None): self._upper_bound = upper_bound if self.upper_bound is not None: if self.upper_bound < self.lower_bound: raise ValueError( "Cannot set `upper_bound` (%r) " "smaller than `lower_bound` (%r)" % (self.upper_bound, self.lower_bound) ) # List of Interval objects. self._intervals = [] # IntervalTree object to allow faster querying of interval objects. self._interval_tree = IntervalTree() # Indicates if the IntervalTree needs to be rebuilt. self._is_stale_tree = False if copy_from is not None: for interval in copy_from._intervals: bounds_cp = interval.bounds[:] fuzzy_cp = interval.fuzzy[:] metadata_cp = copy.copy(interval.metadata) self.add(bounds_cp, fuzzy=fuzzy_cp, metadata=metadata_cp) @property def upper_bound(self): """The exclusive upper bound of interval features.""" return self._upper_bound @property def lower_bound(self): """The inclusive lower bound of interval features.""" return 0 @property def num_interval_features(self): """The total number of interval features.""" return len(self._intervals) def _rebuild_tree(method): """Rebuild the IntervalTree.""" @functools.wraps(method) def inner(self, *args, **kwargs): if self._is_stale_tree is False: return method(self, *args, **kwargs) self._interval_tree = IntervalTree() for f in self._intervals: for start, end in f.bounds: self._interval_tree.add(start, end, f) self._is_stale_tree = False return method(self, *args, **kwargs) return inner def _reverse(self): """Reverse ``IntervalMetadata`` object. This operation reverses all of the interval coordinates. For instance, this can be used to compare coordinates in the forward strand to coordinates in the reversal strand. """ for f in self._intervals: try: intvls = [ (self.upper_bound - x[1], self.upper_bound - x[0]) for x in reversed(f.bounds) ] except TypeError: raise TypeError( "You cannot reverse the coordinates when the upper bound is `None`" ) f.bounds = intvls # DON'T forget this!!! self._is_stale_tree = True @classonlymethod def concat(cls, interval_metadata) -> Self: """Concatenate an iterable of ``IntervalMetadata`` objects. It concatenates the multiple ``IntervalMetadata`` objects into one coordinate space. The order of the objects in the input iterable matters. The coordinate of the second ``InterableMetadata`` will be shifted up with the length of the first ``IntervalMetadata`` object. This function is useful when you concatenate multiple sequences. Parameters ---------- interval_metadata : Iterable (IntervalMetadata) The interval metadata to concatenate. Returns ------- IntervalMetadata Concatenated interval metadata. Examples -------- >>> from skbio.metadata import IntervalMetadata Create two ``IntervalMetadata`` objects: >>> im1 = IntervalMetadata(3) >>> _ = im1.add([(0, 2)], [(True, False)], {'gene': 'sagA'}) >>> im2 = IntervalMetadata(4) >>> _ = im2.add([(1, 4)], [(True, True)], {'gene': 'sagB'}) Concatenate them into a single coordinate space. The second ``IntervalMetadata``'s interval features are all shifted up. The resulting ``IntervalMetadata``'s upper bound is the sum of upper bounds of concatenated objects: >>> im = IntervalMetadata.concat([im1, im2]) >>> im # doctest: +ELLIPSIS 2 interval features ------------------- Interval(interval_metadata=<...>, bounds=[(0, 2)], \ fuzzy=[(True, False)], metadata={'gene': 'sagA'}) Interval(interval_metadata=<...>, bounds=[(4, 7)], \ fuzzy=[(True, True)], metadata={'gene': 'sagB'}) >>> im.upper_bound 7 """ interval_metadata = list(interval_metadata) if len(interval_metadata) == 0: return cls(0) upper_bound = 0 for im in interval_metadata: try: upper_bound += im.upper_bound except TypeError: raise TypeError( "You cannot concat the interval metadata " "because its upper bound is `None`:\n%r" % im ) new = cls(upper_bound) length = 0 for i, im in enumerate(interval_metadata): for intvl in im._intervals: bounds = intvl.bounds fuzzy = intvl.fuzzy if i != 0: bounds = [(start + length, end + length) for start, end in bounds] new.add(bounds, fuzzy, intvl.metadata) length += im.upper_bound return new def merge(self, other): """Merge the interval features of another ``IntervalMetadata`` object. It adds all the interval features of the other object into ``self``. Note this will not check if there are any duplicates of interval features after merge. Notes ----- It will raise error if you merge an unbounded ``IntervalMetadata`` object to the current object if it is bounded. This avoids partially updating the current object if the merge fails in the middle of the process due to the possibility that some interval features to be merged may live outside the current defined upper bound. Parameters ---------- other : ``IntervalMetadata`` The other ``IntervalMetadata`` to be merged. """ if self.upper_bound is not None: if other.upper_bound is None: raise ValueError( "Cannot merge an unbound IntervalMetadata object to a bounded one" ) elif self.upper_bound != other.upper_bound: raise ValueError( "The upper bounds of the two IntervalMetadata objects " "are not equal (%r != %r)" % (self.upper_bound, other.upper_bound) ) if self.lower_bound != other.lower_bound: raise ValueError( "The lower bounds of the two IntervalMetadata objects " "are not equal (%d != %d)" % (self.lower_bound, other.lower_bound) ) for intvl in other._intervals: self.add(intvl.bounds, intvl.fuzzy, intvl.metadata) def sort(self, ascending=True): """Sort interval features by their coordinates. It sorts by the start coordinate first. If they are the same between two interval features, they will be sorted by comparing their end coordinates. For example, an interval feature with [(1, 2), (4, 7)] will be sorted in front of another one with [(1, 2), (3, 8)]. Parameters ---------- ascending : bool, optional sort in ascending or descending coordinates. """ self._intervals.sort( key=lambda i: [i.bounds[0][0], i.bounds[-1][1]], reverse=not ascending ) def add(self, bounds, fuzzy=None, metadata=None): """Create and add an ``Interval`` to this ``IntervalMetadata``. This method creates an ``Interval`` object and inserts it into the ``IntervalMetadata`` object. Parameters ---------- bounds : iterable of tuple of ints Tuples representing start and end coordinates. It is *zero-based* numbering. It is always inclusive on start bound and exclusive on end bound. fuzzy : iterable of tuple of bool, optional Tuples representing the fuzziness of each bound coordinates. metadata : dict, optional A dictionary of key-value pairs associated with the ``Interval`` object. Returns ------- Interval The ``Interval`` object added. See Also -------- skbio.metadata.Interval """ # Add an interval to the tree. Note that the add functionality is # built within the Interval constructor. return Interval( interval_metadata=self, bounds=bounds, fuzzy=fuzzy, metadata=metadata ) @_rebuild_tree # type: ignore[arg-type] def _query_interval(self, bound): """Yield ``Interval`` objects that overlap with the bound.""" _assert_valid_bound(bound) start, end = bound intvls = self._interval_tree.find(start, end) # if a ``Interval`` has many non-contiguous spans and # multiple of them overlap with the bound, then # this ``Interval`` object will be returned # multiple times. So we need to remove duplicates. seen = set() for intvl in intvls: if id(intvl) not in seen: seen.add(id(intvl)) yield intvl def _query_attribute(self, metadata, intervals=None): """Yield ``Interval`` objects based on query attributes. Parameters ---------- metadata : dict or ``None`` If it is ``None``, return empty iterator; if it is ``{}``, return an iterator of all the ``Interval`` objects. intervals : iterable An iterable of ``Interval`` objects. """ if metadata is None: return if intervals is None: intervals = self._intervals for intvl in intervals: for key, value in metadata.items(): if key not in intvl.metadata or intvl.metadata[key] != value: break else: yield intvl @_rebuild_tree # type: ignore[arg-type] def query(self, bounds=None, metadata=None): """Yield ``Interval`` object with the bounds and attributes. The ``Interval`` objects must meet both requirements: 1) overlap with any of the spans specified by ``bounds``; 2) satisfy ``metadata`` specification. For instance, you can identify all the recA genes that overlap with (10, 100) or (900, 1000) with this code ``interval_metadata.query([(10, 100), (900, 1000)], {'gene': 'recA'})``. Parameters ---------- bounds : iterable of tuples of int pair, optional Specifies bounds to look for the ``Interval`` objects. An satisfying interval feature only need to overlap with one bound. Default (``None``) means all ``Intervals`` meet this requirement. metadata : dict, optional A dictionary of key word attributes associated with the ``Interval`` object. It specifies what metadata keywords and values to look for. Default (``None``) means all ``Intervals`` meet this requirement. Yields ------ Interval ``Interval`` object satisfying the search criteria. """ if bounds is None and metadata is None: metadata = {} if bounds is None: for intvl in self._query_attribute(metadata): yield intvl else: for loc in bounds: intvls = self._query_interval(loc) if metadata is None: metadata = {} for intvl in self._query_attribute(metadata, intvls): yield intvl def drop(self, intervals, negate=False): """Drop Interval objects. The given ``Interval`` objects will be removed and their associated ``IntervalMetadata`` will be set to ``None``. Parameters ---------- intervals : iterable of ``Interval`` ``Interval`` objects to drop from this object. negate : bool Negate the drop operation, i.e. keeping the specified intervals instead of dropping them. """ to_delete = {id(f) for f in intervals} new_intvls = [] # iterate through queries and drop them for intvl in self._intervals: drop = id(intvl) in to_delete if negate is True: drop = not drop if drop: intvl._interval_metadata = None else: new_intvls.append(intvl) self._intervals = new_intvls self._is_stale_tree = True def __eq__(self, other): """Test if this object is equal to another. It checks if the coordinate spaces are the same between the two objects. If so, then check if all the interval features are equal between the two objects after sorting them by bounds. Parameters ---------- other : IntervalMetadata Interval metadata to test for equality against. Returns ------- bool Indicates if the two objects are equal. """ if ( self.upper_bound != other.upper_bound or self.lower_bound != other.lower_bound ): return False else: self_intervals = sorted(self._intervals, key=operator.attrgetter("bounds")) other_intervals = sorted( other._intervals, key=operator.attrgetter("bounds") ) return self_intervals == other_intervals def __ne__(self, other): """Test if this object is not equal to another. Parameters ---------- other : IntervalMetadata Interval metadata to test for inequality against. Returns ------- bool Indicates if the two objects are not equal. See Also -------- skbio.metadata.IntervalMetadata.__eq__ """ return not (self == other) def __repr__(self): """Return a string representation of this object. Returns ------- str String representation of this ``IntervalMetadata`` object. """ n = self.num_interval_features l1 = "{} interval feature".format(n) if n != 1: l1 += "s" l2 = "-" * len(l1) if n <= 5: items = [repr(i) for i in self._intervals] else: # intentionally overwrite items[2] to make code cleaner items = [repr(self._intervals[i]) for i in [0, 1, 2, n - 2, n - 1]] items[2] = "..." return "\n".join([l1, l2] + items) def __str__(self): """Return a string representation of this object. Required to inherit from SkbioObject. Returns ------- str String representation of this ``IntervalMetadata`` object. """ return self.__repr__() def __copy__(self): """Return a shallow copy. Notes ----- The ``IntervalMetadata`` copy will have copies of the ``Interval`` objects present in this object. The ``metadata`` dictionary of each ``Interval`` object will be a shallow copy. See Also -------- __deepcopy__ """ return self._copy(False, {}) def __deepcopy__(self, memo): """Return a deep copy. Notes ----- The ``IntervalMetadata`` copy will have copies of the ``Interval`` objects present in this object. The ``metadata`` dictionary of each ``Interval`` object will be a deep copy. See Also -------- __copy__ """ return self._copy(True, memo) def _copy(self, deep, memo): cp = IntervalMetadata(self.upper_bound) for interval in self._intervals: # Only need to shallow-copy `bounds` and `fuzzy` # because their elements are immutable. bounds_cp = interval.bounds[:] fuzzy_cp = interval.fuzzy[:] if deep: metadata_cp = copy.deepcopy(interval.metadata, memo) else: metadata_cp = copy.copy(interval.metadata) cp.add(bounds_cp, fuzzy=fuzzy_cp, metadata=metadata_cp) return cp def _assert_valid_bound(bound): if isinstance(bound, tuple): try: start, end = bound except ValueError: raise ValueError( "A `bound` must be a tuple of exactly two coordinates, not {!r}".format( bound ) ) if not (isinstance(start, int) and isinstance(end, int)) or start > end: raise ValueError( "`start` (%r) cannot be a larger int than `end` (%r)." % (start, end) ) else: raise TypeError("Each `bound` must be a tuple, not {!r}".format(bound)) def _assert_valid_fuzzy(fuzzy): if isinstance(fuzzy, tuple): try: start, end = fuzzy except ValueError: raise ValueError( "A `fuzzy` must be a tuple of exactly two, not {!r}".format(fuzzy) ) if not (isinstance(start, bool) and isinstance(end, bool)): raise TypeError("A `fuzzy` must be a tuple of two booleans") else: raise TypeError("Each `fuzzy` must be a tuple, not {!r}".format(fuzzy)) scikit-bio-scikit-bio-a3beaa6/skbio/metadata/_metadata.py000066400000000000000000001311561520735541300235420ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2016-2023, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- from abc import ABCMeta, abstractmethod from collections import namedtuple, OrderedDict from itertools import chain from types import MappingProxyType from warnings import catch_warnings, filterwarnings import sqlite3 import pandas as pd import numpy as np import skbio.metadata.missing as _missing from skbio.util import find_duplicates from .base import SUPPORTED_COLUMN_TYPES, FORMATTED_ID_HEADERS, is_id_header from skbio.io.descriptors import Read, Write from .._base import SkbioObject DEFAULT_MISSING = _missing.DEFAULT_MISSING class _MetadataBase: """Base class for functionality shared between Metadata and MetadataColumn. Parameters ---------- index : pandas.Index IDs associated with the metadata. """ read = Read() write = Write() @property def id_header(self): """Name identifying the IDs associated with the metadata. This property is read-only. Returns ------- str Name of IDs associated with the metadata. """ return self._id_header @property def ids(self): """IDs associated with the metadata. This property is read-only. Returns ------- tuple of str Metadata IDs. """ return self._ids @property def id_count(self): """Number of metadata IDs. This property is read-only. Returns ------- int Number of metadata IDs. """ return len(self._ids) def __init__(self, index): if index.empty: raise ValueError( "%s must contain at least one ID." % self.__class__.__name__ ) id_header = index.name self._assert_valid_id_header(id_header) self._id_header = id_header self._validate_index(index, axis="id") self._ids = tuple(index) def __eq__(self, other): return isinstance(other, self.__class__) and self._id_header == other._id_header def __ne__(self, other): return not (self == other) # Static helpers below for code reuse in Metadata and MetadataColumn @classmethod def _assert_valid_id_header(cls, name): if not is_id_header(name): raise ValueError( "pandas index name (`Index.name`) must be one of the " "following values, not %r:\n\n%s" % (name, FORMATTED_ID_HEADERS) ) @classmethod def _validate_index(cls, index, *, axis): if axis == "id": label = "ID" elif axis == "column": label = "column name" else: raise NotImplementedError for value in index: if not isinstance(value, str): raise TypeError( "Detected non-string metadata %s of type %r: %r" % (label, type(value), value) ) if not value: raise ValueError( "Detected empty metadata %s. %ss must consist of at least " "one character." % (label, label) ) if axis == "id" and value.startswith("#"): raise ValueError( "Detected metadata %s that begins with a pound sign " "(#): %r" % (label, value) ) if is_id_header(value): raise ValueError( "Detected metadata %s %r that conflicts with a name " "reserved for the ID header. Reserved ID headers:\n\n%s" % (label, value, FORMATTED_ID_HEADERS) ) if len(index) != len(set(index)): duplicates = find_duplicates(index) raise ValueError( "Metadata %ss must be unique. The following %ss are " "duplicated: %s" % (label, label, ", ".join(repr(e) for e in sorted(duplicates))) ) @classmethod def _filter_ids_helper(cls, df_or_series, ids, ids_to_keep): # `ids_to_keep` can be any iterable, so turn it into a list so that it # can be iterated over multiple times below (and length-checked). ids_to_keep = list(ids_to_keep) if len(ids_to_keep) == 0: raise ValueError("`ids_to_keep` must contain at least one ID.") duplicates = find_duplicates(ids_to_keep) if duplicates: raise ValueError( "`ids_to_keep` must contain unique IDs. The following IDs are " "duplicated: %s" % (", ".join(repr(e) for e in sorted(duplicates))) ) ids_to_keep = set(ids_to_keep) missing_ids = ids_to_keep - ids if missing_ids: raise ValueError( "The following IDs are not present in the metadata: %s" % (", ".join(repr(e) for e in sorted(missing_ids))) ) # While preserving order, get rid of any IDs not contained in # `ids_to_keep`. ids_to_discard = ids - ids_to_keep return df_or_series.drop( labels=ids_to_discard, axis="index", inplace=False, errors="raise" ) def save(self, filepath, ext=None): """Save a TSV metadata file. The TSV metadata file format is described at https://docs.qiime2.org in the Metadata Tutorial. The file will always include the ``#sk:types`` directive in order to make the file roundtrippable without relying on column type inference. Parameters ---------- filepath : str Path to save TSV metadata file at. ext : str Preferred file extension (.tsv, .txt, etc). Will be left blank if no extension is included. Including a period in the extension is optional, and any additional periods delimiting the filepath and the extension will be reduced to a single period. Returns ------- str Filepath and extension (if provided) that the file was saved to. See Also -------- Metadata.load """ from .io import MetadataWriter if ext is None: ext = "" else: ext = "." + ext.lstrip(".") filepath = filepath.rstrip(".") if not filepath.endswith(ext): filepath += ext MetadataWriter(self).write(filepath) return filepath # Other properties such as units can be included here in the future! ColumnProperties = namedtuple("ColumnProperties", ["type", "missing_scheme"]) class SampleMetadata(_MetadataBase, SkbioObject): """Store metadata associated with identifiers in a study. Metadata is tabular in nature, mapping study identifiers (e.g. sample or feature IDs) to columns of metadata associated with each ID. For more details about metadata in QIIME 2, including the TSV metadata file format, see the Metadata Tutorial at https://docs.qiime2.org. The following text focuses on design and considerations when working with ``Metadata`` objects at the API level. A ``Metadata`` object is composed of zero or more ``MetadataColumn`` objects. A ``Metadata`` object always contains at least one ID, regardless of the number of columns. Each column in the ``Metadata`` object has an associated column type representing either *categorical* or *numeric* data. Each metadata column is represented by an object corresponding to the column's type: ``CategoricalMetadataColumn`` or ``NumericMetadataColumn``, respectively. A ``Metadata`` object is closely linked to its corresponding TSV metadata file format described at https://docs.qiime2.org. Therefore, certain requirements present in the file format are also enforced on the in-memory object in order to make serialized ``Metadata`` objects roundtrippable when loaded from disk again. For example, IDs cannot begin with a pound character (``#``) because those IDs would be interpreted as comment rows when written to disk as TSV. See the metadata file format spec for more details about data formatting requirements. In addition to being loaded from or saved to disk, a ``Metadata`` object can be constructed from a ``pandas.DataFrame`` object. See the *Parameters* section below for details on how to construct ``Metadata`` objects from dataframes. ``Metadata`` objects have various methods to access, filter, and merge data. A dataframe can be retrieved from the ``Metadata`` object for further data manipulation using the pandas API. Individual ``MetadataColumn`` objects can be retrieved to gain access to APIs applicable to a single metadata column. Missing values may be encoded in one of the following schemes: 'blank' The default, which treats `None`/`NaN` as the only valid missing values. 'no-missing' Indicates there are no missing values in a column, any `None`/`NaN` values should be considered an error. If a scheme other than 'blank' is used by default, this scheme can be provided to preserve strings as categorical terms. 'INSDC:missing' The INSDC vocabulary for missing values. The current implementation supports only lower-case terms which match exactly: 'not applicable', 'missing', 'not provided', 'not collected', and 'restricted access'. Parameters ---------- dataframe : pandas.DataFrame Dataframe containing metadata. The dataframe's index defines the IDs, and the index name (``Index.name``) must match one of the required ID headers described in the metadata file format spec. Each column in the dataframe defines a metadata column, and the metadata column's type (i.e. *categorical* or *numeric*) is determined based on the column's dtype. If a column has ``dtype=object``, it may contain strings or pandas missing values (e.g. ``np.nan``, ``None``). Columns matching this requirement are assumed to be *categorical*. If a column in the dataframe has ``dtype=float`` or ``dtype=int``, it may contain floating point numbers or integers, as well as pandas missing values (e.g. ``np.nan``). Columns matching this requirement are assumed to be *numeric*. Regardless of column type (categorical vs numeric), the dataframe stored within the ``Metadata`` object will have any missing values normalized to ``np.nan``. Columns with ``dtype=int`` will be cast to ``dtype=float``. To obtain a dataframe from the ``Metadata`` object containing these normalized data types and values, use ``Metadata.to_dataframe()``. column_missing_schemes : dict, optional Describe the metadata column handling for missing values described in the dataframe. This is a dict mapping column names (str) to missing-value schemes (str). Valid values are 'blank', 'no-missing', and 'INSDC:missing'. Column names may be omitted. default_missing_scheme : str, optional The missing scheme to use when none has been provided in the file or in `column_missing_schemes`. """ default_write_format = "sample_metadata" """Default write format for this object: ``sample_metadata``.""" @classmethod def load( cls, filepath: str, column_types: dict[str, str] | None = None, column_missing_schemes: dict[str, str] | None = None, default_missing_scheme: str = DEFAULT_MISSING, ) -> "SampleMetadata": """Load a TSV metadata file. The TSV metadata file format is described at https://docs.qiime2.org in the Metadata Tutorial. Parameters ---------- filepath : str Path to TSV metadata file to be loaded. column_types : dict, optional Override metadata column types specified or inferred in the file. This is a dict mapping column names (str) to column types (str). Valid column types are 'categorical' and 'numeric'. Column names may be omitted from this dict to use the column types read from the file. column_missing_schemes : dict, optional Override the metadata column handling for missing values described in the file. This is a dict mapping column names (str) to missing-value schemes (str). Valid values are 'blank', 'no-missing', and 'INSDC:missing'. Column names may be omitted. default_missing_scheme : str, optional The missing scheme to use when none has been provided in the file or in `column_missing_schemes`. Returns ------- Metadata Metadata object loaded from `filepath`. Raises ------ MetadataFileError If the metadata file is invalid in any way (e.g. doesn't meet the file format's requirements). See Also -------- save """ from .io import MetadataReader return MetadataReader(filepath).read( into=cls, column_types=column_types, column_missing_schemes=column_missing_schemes, default_missing_scheme=default_missing_scheme, ) @property def columns(self): """Ordered mapping of column names to ColumnProperties. The mapping that is returned is read-only. This property is also read-only. Returns ------- types.MappingProxyType Ordered mapping of column names to ColumnProperties. """ # Read-only proxy to the OrderedDict mapping column names to # ColumnProperties. return MappingProxyType(self._columns) @property def column_count(self): """Number of metadata columns. This property is read-only. Returns ------- int Number of metadata columns. Notes ----- Zero metadata columns are allowed. See Also -------- id_count """ return len(self._columns) def __init__( self, dataframe, column_missing_schemes=None, default_missing_scheme=DEFAULT_MISSING, ): if not isinstance(dataframe, pd.DataFrame): raise TypeError( "%s constructor requires a pandas.DataFrame object, not " "%r" % (self.__class__.__name__, type(dataframe)) ) super().__init__(dataframe.index) if column_missing_schemes is None: column_missing_schemes = {} self._dataframe, self._columns = self._normalize_dataframe( dataframe, column_missing_schemes, default_missing_scheme ) self._validate_index(self._dataframe.columns, axis="column") def _normalize_dataframe( self, dataframe, column_missing_schemes, default_missing_scheme ): norm_df = dataframe.copy() # Do not attempt to strip empty metadata if not norm_df.columns.empty: norm_df.columns = norm_df.columns.str.strip() norm_df.index = norm_df.index.str.strip() columns = OrderedDict() for column_name, series in norm_df.items(): missing_scheme = column_missing_schemes.get( column_name, default_missing_scheme ) metadata_column = self._metadata_column_factory(series, missing_scheme) norm_df[column_name] = metadata_column.to_series() properties = ColumnProperties( type=metadata_column.type, missing_scheme=missing_scheme ) columns[column_name] = properties return norm_df, columns def _metadata_column_factory(self, series, missing_scheme): series = _missing.series_encode_missing(series, missing_scheme) # Collapse dtypes except for all NaN columns so that we can preserve # empty categorical columns. Empty numeric columns will already have # the expected dtype and values if not series.isna().all(): series = series.infer_objects() dtype = series.dtype if NumericMetadataColumn._is_supported_dtype(dtype): column = NumericMetadataColumn(series, missing_scheme) elif CategoricalMetadataColumn._is_supported_dtype(dtype): column = CategoricalMetadataColumn(series, missing_scheme) else: raise TypeError( "Metadata column %r has an unsupported pandas dtype of %s. " "Supported dtypes: float, int, object, str." % (series.name, dtype) ) return column def __repr__(self): """Return the string summary of the metadata and its columns.""" lines = [] # Header lines.append(self.__class__.__name__) lines.append("-" * len(self.__class__.__name__)) # Dimensions lines.append( "%d ID%s x %d column%s" % ( self.id_count, "" if self.id_count == 1 else "s", self.column_count, "" if self.column_count == 1 else "s", ) ) # Column properties if self.column_count != 0: max_name_len = max((len(name) for name in self.columns)) for name, props in self.columns.items(): padding = " " * ((max_name_len - len(name)) + 1) lines.append("%s:%s%r" % (name, padding, props)) # Epilogue lines.append("") lines.append("Call to_dataframe() for a tabular representation.") return "\n".join(lines) def __str__(self): """Return the string summary of the metadata and its columns. Required to inherit from SkbioObject. """ return self.__repr__() def __eq__(self, other): """Determine if this metadata is equal to another. ``Metadata`` objects are equal if their IDs, columns (including column names, types, and ordering), ID headers, and metadata values are equal. Parameters ---------- other : Metadata Metadata to test for equality. Returns ------- bool Indicates whether this ``Metadata`` object is equal to `other`. See Also -------- __ne__ """ return ( super().__eq__(other) and self._columns == other._columns and self._dataframe.equals(other._dataframe) ) def __ne__(self, other): """Determine if this metadata is not equal to another. ``Metadata`` objects are not equal if their IDs, columns (including column names, types, or ordering), ID headers, or metadata values are not equal. Parameters ---------- other : Metadata Metadata to test for inequality. Returns ------- bool Indicates whether this ``Metadata`` object is not equal to `other`. See Also -------- __eq__ """ return not (self == other) def to_dataframe(self, encode_missing=False): """Create a pandas dataframe from the metadata. The dataframe's index name (``Index.name``) will match this metadata object's ``id_header``, and the index will contain this metadata object's IDs. The dataframe's column names will match the column names in this metadata. Categorical columns will be stored as ``dtype=object`` (containing strings), and numeric columns will be stored as ``dtype=float``. Parameters ---------- encode_missing : bool, optional Whether to convert missing values (NaNs) back into their original vocabulary (strings) if a missing scheme was used. Returns ------- pandas.DataFrame Dataframe constructed from the metadata. """ df = self._dataframe.copy() if encode_missing: def replace_nan(series): missing = _missing.series_extract_missing(series) # avoid dtype changing if there's no missing values if not missing.empty: series = series.astype(object) series[missing.index] = missing return series df = df.apply(replace_nan) return df def get_column(self, name): """Retrieve metadata column based on column name. Parameters ---------- name : str Name of the metadata column to retrieve. Returns ------- MetadataColumn Requested metadata column (``CategoricalMetadataColumn`` or ``NumericMetadataColumn``). See Also -------- get_ids """ try: series = self._dataframe[name] missing_scheme = self._columns[name].missing_scheme except KeyError: raise ValueError( "%r is not a column in the metadata. Available columns: " "%s" % (name, ", ".join(repr(c) for c in self.columns)) ) return self._metadata_column_factory(series, missing_scheme) def get_ids(self, where=None): """Retrieve IDs matching search criteria. Parameters ---------- where : str, optional SQLite WHERE clause specifying criteria IDs must meet to be included in the results. All IDs are included by default. Returns ------- set IDs matching search criteria specified in `where`. See Also -------- ids filter_ids get_column Notes ----- The ID header (``Metadata.id_header``) may be used in the `where` clause to query the table's ID column. """ if where is None: return set(self._ids) conn = sqlite3.connect(":memory:") conn.row_factory = lambda cursor, row: row[0] # https://github.com/pandas-dev/pandas/blob/ # 7c7bd569ce8e0f117c618d068e3d2798134dbc73/pandas/io/sql.py#L1306 with catch_warnings(): filterwarnings("ignore", "The spaces in these column names will not.*") self._dataframe.to_sql( "metadata", conn, index=True, index_label=self.id_header ) c = conn.cursor() # In general we wouldn't want to format our query in this way because # it leaves us open to sql injection, but it seems acceptable here for # a few reasons: # 1) This is a throw-away database which we're just creating to have # access to the query language, so any malicious behavior wouldn't # impact any data that isn't temporary # 2) The substitution syntax recommended in the docs doesn't allow # us to specify complex `where` statements, which is what we need to # do here. For example, we need to specify things like: # WHERE Subject='subject-1' AND SampleType='gut' # but their qmark/named-style syntaxes only supports substitution of # variables, such as: # WHERE Subject=? # 3) sqlite3.Cursor.execute will only execute a single statement so # inserting multiple statements # (e.g., "Subject='subject-1'; DROP...") will result in an # OperationalError being raised. query = ( 'SELECT "{0}" FROM metadata WHERE {1} GROUP BY "{0}" ' 'ORDER BY "{0}";'.format(self.id_header, where) ) try: c.execute(query) except sqlite3.OperationalError as e: conn.close() raise ValueError( "Selection of IDs failed with query:\n %s\n\n" "If one of the metadata column names specified " "in the `where` statement is on this list " "of reserved keywords " "(http://www.sqlite.org/lang_keywords.html), " "please ensure it is quoted appropriately in the " "`where` statement." % query ) from e ids = set(c.fetchall()) conn.close() return ids def merge(self, *others): """Merge this ``Metadata`` object with other ``Metadata`` objects. Returns a new ``Metadata`` object containing the merged contents of this ``Metadata`` object and `others`. The merge is not in-place and will always return a **new** merged ``Metadata`` object. The merge will include only those IDs that are shared across **all** ``Metadata`` objects being merged (i.e. the merge is an *inner join*). Each metadata column being merged must have a unique name; merging metadata with overlapping column names will result in an error. Parameters ---------- others : tuple One or more ``Metadata`` objects to merge with this ``Metadata`` object. Returns ------- Metadata New object containing merged metadata. The merged IDs will be in the same relative order as the IDs in this ``Metadata`` object after performing the inner join. The merged column order will match the column order of ``Metadata`` objects being merged from left to right. Raises ------ ValueError If zero ``Metadata`` objects are provided in `others` (there is nothing to merge in this case). Notes ----- The merged ``Metadata`` object will always have its ``id_header`` property set to ``'id'``, regardless of the ``id_header`` values on the ``Metadata`` objects being merged. """ if len(others) < 1: raise ValueError( "At least one Metadata object must be provided to merge into " "this Metadata object (otherwise there is nothing to merge)." ) dfs = [] columns = [] for md in chain([self], others): df = md._dataframe dfs.append(df) columns.extend(df.columns.tolist()) columns = pd.Index(columns) if columns.has_duplicates: raise ValueError( "Cannot merge metadata with overlapping columns. The " "following columns overlap: %s" % ", ".join([repr(e) for e in columns[columns.duplicated()].unique()]) ) merged_df = dfs[0].join(dfs[1:], how="inner") # Not using DataFrame.empty because empty columns are allowed in # Metadata. if merged_df.index.empty: raise ValueError( "Cannot merge because there are no IDs shared across metadata objects." ) merged_df.index.name = "id" merged_md = self.__class__(merged_df) return merged_md def filter_ids(self, ids_to_keep): """Filter metadata by IDs. Parameters ---------- ids_to_keep : iterable of str IDs that should be retained in the filtered ``Metadata`` object. If any IDs in `ids_to_keep` are not contained in this ``Metadata`` object, a ``ValueError`` will be raised. The filtered ``Metadata`` object will retain the same relative ordering of IDs in this ``Metadata`` object. Thus, the ordering of IDs in `ids_to_keep` does not determine the ordering of IDs in the filtered ``Metadata`` object. Returns ------- Metadata The metadata filtered by IDs. See Also -------- get_ids filter_columns """ filtered_df = self._filter_ids_helper( self._dataframe, self.get_ids(), ids_to_keep ) filtered_md = self.__class__(filtered_df) return filtered_md def filter_columns( self, *, column_type=None, drop_all_unique=False, drop_zero_variance=False, drop_all_missing=False, ): """Filter metadata by columns. Parameters ---------- column_type : str, optional If supplied, will retain only columns of this type. The currently supported column types are 'numeric' and 'categorical'. drop_all_unique : bool, optional If ``True``, columns that contain a unique value for every ID will be dropped. Missing data (``np.nan``) are ignored when determining unique values. If a column consists solely of missing data, it will be dropped. drop_zero_variance : bool, optional If ``True``, columns that contain the same value for every ID will be dropped. Missing data (``np.nan``) are ignored when determining variance. If a column consists solely of missing data, it will be dropped. drop_all_missing : bool, optional If ``True``, columns that have a missing value (``np.nan``) for every ID will be dropped. Returns ------- Metadata The metadata filtered by columns. See Also -------- filter_ids """ if column_type is not None and column_type not in SUPPORTED_COLUMN_TYPES: raise ValueError( "Unknown column type %r. Supported column types: %s" % (column_type, ", ".join(sorted(SUPPORTED_COLUMN_TYPES))) ) # Build up a set of columns to drop. Short-circuit as soon as we know a # given column can be dropped (no need to apply further filters to it). columns_to_drop = set() for column, props in self.columns.items(): if column_type is not None and props.type != column_type: columns_to_drop.add(column) continue series = self._dataframe[column] if drop_all_unique or drop_zero_variance: # Ignore nans in the unique count, and compare to the number of # non-nan values in the series. num_unique = series.nunique(dropna=True) if drop_all_unique and num_unique == series.count(): columns_to_drop.add(column) continue # If num_unique == 0, the series was empty (all nans). If # num_unique == 1, the series contained only a single unique # value (ignoring nans). if drop_zero_variance and num_unique < 2: columns_to_drop.add(column) continue if drop_all_missing and series.isna().all(): columns_to_drop.add(column) continue filtered_df = self._dataframe.drop(columns_to_drop, axis=1, inplace=False) filtered_md = self.__class__(filtered_df) return filtered_md class MetadataColumn(_MetadataBase, metaclass=ABCMeta): """Abstract base class representing a single metadata column. Concrete subclasses represent specific metadata column types, e.g. ``CategoricalMetadataColumn`` and ``NumericMetadataColumn``. See the ``Metadata`` class docstring for details about ``Metadata`` and ``MetadataColumn`` objects, including a description of column types. The main difference in constructing ``MetadataColumn`` vs ``Metadata`` objects is that ``MetadataColumn`` objects are constructed from a ``pandas.Series`` object instead of a ``pandas.DataFrame``. Otherwise, the same restrictions, considerations, and data normalization are applied as with ``Metadata`` objects. Parameters ---------- series : pd.Series The series to construct a column from. missing_scheme : "blank", "no-missing", "INSDC:missing" How to interpret terms for missing values. These will be converted to NaN. The default treatment is to take no action. """ # Abstract, must be defined by subclasses. type: str | None = None @classmethod @abstractmethod def _is_supported_dtype(cls, dtype): """Return True if dtype is supported False otherwise. Contract: Return ``True`` if the series `dtype` is supported by this object and can be handled appropriately by ``_normalize_``. Return ``False`` otherwise. """ raise NotImplementedError @classmethod @abstractmethod def _normalize_(cls, series): """Return a normalized copy of series. Contract: Return a copy of `series` that has been converted to the appropriate internal dtype and has any other necessary normalization or validation applied (e.g. missing value representations, disallowing certain values, etc). Raise an error with a detailed error message if the operation cannot be completed. """ raise NotImplementedError @property def name(self): """Metadata column name. This property is read-only. Returns ------- str Metadata column name. """ return self._series.name @property def missing_scheme(self): """Return the vocabulary used to encode missing values. This property is read-only. Returns ------- str "blank", "no-missing", or "INSDC:missing" """ return self._missing_scheme @property @abstractmethod def supported_dtypes(self): """Data types supported by this type of metadata column. Returns ------- tuple Supported dtype(s). """ pass def __init__(self, series, missing_scheme=DEFAULT_MISSING): if not isinstance(series, pd.Series): raise TypeError( "%s constructor requires a pandas.Series object, not %r" % (self.__class__.__name__, type(series)) ) super().__init__(series.index) series = _missing.series_encode_missing(series, missing_scheme) # if the series has values with a consistent dtype, make the series # that dtype. Don't change the dtype if there is a column of all NaN if not series.isna().all(): series = series.infer_objects() if not self._is_supported_dtype(series.dtype): raise TypeError( "%s %r does not support a pandas.Series object with dtype %s. " "Supported dtypes: %s" % ( self.__class__.__name__, series.name, series.dtype, ", ".join(self.supported_dtypes), ) ) self._missing_scheme = missing_scheme self._series = self._normalize_(series) self._validate_index([self._series.name], axis="column") def __repr__(self): """Return String summary of the metadata column.""" return "<%s name=%r id_count=%d>" % ( self.__class__.__name__, self.name, self.id_count, ) def __eq__(self, other): """Determine if this metadata column is equal to another. ``MetadataColumn`` objects are equal if their IDs, column names, column types, ID headers and metadata values are equal. Parameters ---------- other : MetadataColumn Metadata column to test for equality. Returns ------- bool Indicates whether this ``MetadataColumn`` object is equal to `other`. See Also -------- __ne__ """ return ( super().__eq__(other) and self.name == other.name and self._series.equals(other._series) ) def __ne__(self, other): """Determine if this metadata column is not equal to another. ``MetadataColumn`` objects are not equal if their IDs, column names, column types, ID headers, or metadata values are not equal. Parameters ---------- other : MetadataColumn Metadata column to test for inequality. Returns ------- bool Indicates whether this ``MetadataColumn`` object is not equal to `other`. See Also -------- __eq__ """ return not (self == other) def to_series(self, encode_missing=False): """Create a pandas series from the metadata column. The series index name (``Index.name``) will match this metadata column's ``id_header``, and the index will contain this metadata column's IDs. The series name will match this metadata column's name. Parameters ---------- encode_missing : bool, optional Whether to convert missing values (NaNs) back into their original vocabulary (strings) if a missing scheme was used. Returns ------- pandas.Series Series constructed from the metadata column. See Also -------- to_dataframe """ series = self._series.copy() if encode_missing: missing = self.get_missing() if not missing.empty: series[missing.index] = missing return series def to_dataframe(self, encode_missing=False): """Create a pandas dataframe from the metadata column. The dataframe will contain exactly one column. The dataframe's index name (``Index.name``) will match this metadata column's ``id_header``, and the index will contain this metadata column's IDs. The dataframe's column name will match this metadata column's name. Parameters ---------- encode_missing : bool, optional Whether to convert missing values (NaNs) back into their original vocabulary (strings) if a missing scheme was used. Returns ------- pandas.DataFrame Dataframe constructed from the metadata column. See Also -------- to_series """ return self.to_series(encode_missing=encode_missing).to_frame() def get_missing(self): """Return a series containing only missing values (with an index). If the column was constructed with a missing scheme, then the values of the series will be the original terms instead of NaN. """ return _missing.series_extract_missing(self._series) def get_value(self, id): """Retrieve metadata column value associated with an ID. Parameters ---------- id : str ID corresponding to the metadata column value to retrieve. Returns ------- object Value associated with the provided `id`. """ if id not in self._series.index: raise ValueError("ID %r is not present in %r" % (id, self)) return self._series.loc[id] def has_missing_values(self): """Determine if the metadata column has one or more missing values. Returns ------- bool ``True`` if the metadata column has one or more missing values (``np.nan``), ``False`` otherwise. See Also -------- drop_missing_values get_ids """ return len(self.get_ids(where_values_missing=True)) > 0 def drop_missing_values(self): """Filter out missing values from the metadata column. Returns ------- MetadataColumn Metadata column with missing values removed. See Also -------- has_missing_values get_ids """ missing = self.get_ids(where_values_missing=True) present = self.get_ids() - missing return self.filter_ids(present) def get_ids(self, where_values_missing=False): """Retrieve IDs matching search criteria. Parameters ---------- where_values_missing : bool, optional If ``True``, only return IDs that are associated with missing values (``np.nan``). If ``False`` (the default), return all IDs in the metadata column. Returns ------- set IDs matching search criteria. See Also -------- ids filter_ids has_missing_values drop_missing_values """ if where_values_missing: ids = self._series.index[self._series.isna()] else: ids = self._ids return set(ids) def filter_ids(self, ids_to_keep): """Filter metadata column by IDs. Parameters ---------- ids_to_keep : iterable of str IDs that should be retained in the filtered ``MetadataColumn`` object. If any IDs in `ids_to_keep` are not contained in this ``MetadataColumn`` object, a ``ValueError`` will be raised. The filtered ``MetadataColumn`` object will retain the same relative ordering of IDs in this ``MetadataColumn`` object. Thus, the ordering of IDs in `ids_to_keep` does not determine the ordering of IDs in the filtered ``MetadataColumn`` object. Returns ------- MetadataColumn The metadata column filtered by IDs. See Also -------- get_ids """ filtered_series = self._filter_ids_helper( self._series, self.get_ids(), ids_to_keep ) filtered_mdc = self.__class__(filtered_series) return filtered_mdc class CategoricalMetadataColumn(MetadataColumn): """A single metadata column containing categorical data. See the ``Metadata`` class docstring for details about ``Metadata`` and ``MetadataColumn`` objects, including a description of column types and supported data formats. """ type = "categorical" supported_dtypes = ("object", "str") @classmethod def _is_supported_dtype(cls, dtype): # pd.api.types.is_string_dtype(dtype) # Older pandas returned 'object' for strings if dtype == "object": return True # New pandas has StringDtype dtype_str = str(dtype) if dtype_str == "str": return True if dtype_str.startswith("string") or "StringDtype" in dtype_str: return True return False @classmethod def _normalize_(cls, series): def normalize(value): if isinstance(value, str): value = value.strip() if value == "": raise ValueError( "%s does not support empty strings as values. Use an " "appropriate pandas missing value type " "(e.g. `numpy.nan`) or supply a non-empty string as " "the value in column %r." % (cls.__name__, series.name) ) else: return value elif pd.isna(value): # permits np.nan, Python float nan, None if isinstance(value, float) and np.isnan(value): # if type(value) is float and np.isnan(value): return value return np.nan else: raise TypeError( "%s only supports strings or missing values. Found value " "%r of type %r in column %r." % (cls.__name__, value, type(value), series.name) ) norm_series = series.apply(normalize) norm_series = norm_series.astype(object) norm_series.index = norm_series.index.str.strip() norm_series.name = norm_series.name.strip() return norm_series class NumericMetadataColumn(MetadataColumn): """A single metadata column containing numeric data. See the ``Metadata`` class docstring for details about ``Metadata`` and ``MetadataColumn`` objects, including a description of column types and supported data formats. """ type = "numeric" supported_dtypes = ("float", "int", "int64") @classmethod def _is_supported_dtype(cls, dtype): return dtype == "float" or dtype == "int" or dtype == "int64" @classmethod def _normalize_(cls, series): series = series.astype(float, errors="raise").copy() if np.isinf(series).any(): raise ValueError( "%s does not support positive or negative infinity as a " "floating point value in column %r." % (cls.__name__, series.name) ) return series scikit-bio-scikit-bio-a3beaa6/skbio/metadata/_mixin.py000066400000000000000000000435341520735541300231100ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from abc import ABCMeta, abstractmethod from copy import copy, deepcopy import pandas as pd from skbio.metadata import IntervalMetadata class MetadataMixin(metaclass=ABCMeta): @property def metadata(self): """``dict`` containing metadata which applies to the entire object. Notes ----- This property can be set and deleted. When setting new metadata a shallow copy of the dictionary is made. Examples -------- .. note:: scikit-bio objects with metadata share a common interface for accessing and manipulating their metadata. The following examples use scikit-bio's ``Sequence`` class to demonstrate metadata behavior. These examples apply to all other scikit-bio objects storing metadata. Create a sequence with metadata: >>> from skbio import Sequence >>> seq = Sequence('ACGT', metadata={'description': 'seq description', ... 'id': 'seq-id'}) Retrieve metadata: >>> print(seq.metadata) {'description': 'seq description', 'id': 'seq-id'} Update metadata: >>> seq.metadata['id'] = 'new-id' >>> seq.metadata['pubmed'] = 12345 >>> print(seq.metadata) {'description': 'seq description', 'id': 'new-id', 'pubmed': 12345} Set metadata: >>> seq.metadata = {'abc': 123} >>> seq.metadata {'abc': 123} Delete metadata: >>> seq.has_metadata() True >>> del seq.metadata >>> seq.metadata {} >>> seq.has_metadata() False """ if self._metadata is None: # Not using setter to avoid copy. self._metadata = {} return self._metadata @metadata.setter def metadata(self, metadata): if not isinstance(metadata, dict): raise TypeError( "metadata must be a dict, not type %r" % type(metadata).__name__ ) # Shallow copy. self._metadata = metadata.copy() @metadata.deleter def metadata(self): self._metadata = None @abstractmethod def __init__(self, metadata=None): raise NotImplementedError def _init_(self, metadata=None): if metadata is None: # Could use deleter but this is less overhead and needs to be fast. self._metadata = None else: # Use setter for validation and copy. self.metadata = metadata @abstractmethod def __eq__(self, other): raise NotImplementedError def _eq_(self, other): # We're not simply comparing self.metadata to other.metadata in order # to avoid creating "empty" metadata representations on the objects if # they don't have metadata. if self.has_metadata() and other.has_metadata(): return self.metadata == other.metadata elif not (self.has_metadata() or other.has_metadata()): # Both don't have metadata. return True else: # One has metadata while the other does not. return False @abstractmethod def __ne__(self, other): raise NotImplementedError def _ne_(self, other): return not (self == other) @abstractmethod def __copy__(self): raise NotImplementedError def _copy_(self): if self.has_metadata(): return self.metadata.copy() else: return None @abstractmethod def __deepcopy__(self, memo): raise NotImplementedError def _deepcopy_(self, memo): if self.has_metadata(): return deepcopy(self.metadata, memo) else: return None def has_metadata(self): """Determine if the object has metadata. An object has metadata if its ``metadata`` dictionary is not empty (i.e., has at least one key-value pair). Returns ------- bool Indicates whether the object has metadata. Examples -------- .. note:: scikit-bio objects with metadata share a common interface for accessing and manipulating their metadata. The following examples use scikit-bio's ``Sequence`` class to demonstrate metadata behavior. These examples apply to all other scikit-bio objects storing metadata. >>> from skbio import Sequence >>> seq = Sequence('ACGT') >>> seq.has_metadata() False >>> seq = Sequence('ACGT', metadata={}) >>> seq.has_metadata() False >>> seq = Sequence('ACGT', metadata={'id': 'seq-id'}) >>> seq.has_metadata() True """ return self._metadata is not None and bool(self.metadata) class PositionalMetadataMixin(metaclass=ABCMeta): @abstractmethod def _positional_metadata_axis_len_(self): """Return length of axis that positional metadata applies to. Returns ------- int Positional metadata axis length. """ raise NotImplementedError @property def positional_metadata(self): """``pd.DataFrame`` containing metadata along an axis. Notes ----- This property can be set and deleted. When setting new positional metadata, a shallow copy is made and the ``pd.DataFrame`` index is set to ``pd.RangeIndex(start=0, stop=axis_len, step=1)``. Examples -------- .. note:: scikit-bio objects with positional metadata share a common interface for accessing and manipulating their positional metadata. The following examples use scikit-bio's ``DNA`` class to demonstrate positional metadata behavior. These examples apply to all other scikit-bio objects storing positional metadata. Create a DNA sequence with positional metadata: >>> from skbio import DNA >>> seq = DNA( ... 'ACGT', ... positional_metadata={'exons': [True, True, False, True], ... 'quality': [3, 3, 20, 11]}) >>> seq DNA ----------------------------- Positional metadata: 'exons': 'quality': Stats: length: 4 has gaps: False has degenerates: False has definites: True GC-content: 50.00% ----------------------------- 0 ACGT Retrieve positional metadata: >>> seq.positional_metadata exons quality 0 True 3 1 True 3 2 False 20 3 True 11 Update positional metadata: >>> seq.positional_metadata['gaps'] = seq.gaps() >>> seq.positional_metadata exons quality gaps 0 True 3 False 1 True 3 False 2 False 20 False 3 True 11 False Set positional metadata: >>> seq.positional_metadata = {'degenerates': seq.degenerates()} >>> seq.positional_metadata # doctest: +NORMALIZE_WHITESPACE degenerates 0 False 1 False 2 False 3 False Delete positional metadata: >>> seq.has_positional_metadata() True >>> del seq.positional_metadata >>> seq.positional_metadata Empty DataFrame Columns: [] Index: [0, 1, 2, 3] >>> seq.has_positional_metadata() False """ if self._positional_metadata is None: # Not using setter to avoid copy. self._positional_metadata = pd.DataFrame( index=self._get_positional_metadata_index() ) return self._positional_metadata @positional_metadata.setter def positional_metadata(self, positional_metadata): try: # Pass copy=True to copy underlying data buffer. positional_metadata = pd.DataFrame(positional_metadata).copy() # Different versions of pandas will raise different error types. We # don't really care what the type of the error is, just its message, so # a blanket Exception will do. except Exception as e: raise TypeError( "Invalid positional metadata. Must be consumable by " "`pd.DataFrame` constructor. Original pandas error message: " '"%s"' % e ) num_rows = len(positional_metadata.index) axis_len = self._positional_metadata_axis_len_() if num_rows != axis_len: raise ValueError( "Number of positional metadata values (%d) must match the " "positional metadata axis length (%d)." % (num_rows, axis_len) ) positional_metadata.index = self._get_positional_metadata_index() self._positional_metadata = positional_metadata @positional_metadata.deleter def positional_metadata(self): self._positional_metadata = None def _get_positional_metadata_index(self): """Create a memory-efficient integer index for positional metadata.""" return pd.RangeIndex( start=0, stop=self._positional_metadata_axis_len_(), step=1 ) @abstractmethod def __init__(self, positional_metadata=None): raise NotImplementedError def _init_(self, positional_metadata=None): if positional_metadata is None: # Could use deleter but this is less overhead and needs to be fast. self._positional_metadata = None else: # Use setter for validation and copy. self.positional_metadata = positional_metadata @abstractmethod def __eq__(self, other): raise NotImplementedError def _eq_(self, other): # We're not simply comparing self.positional_metadata to # other.positional_metadata in order to avoid creating "empty" # positional metadata representations on the objects if they don't have # positional metadata. if self.has_positional_metadata() and other.has_positional_metadata(): return self.positional_metadata.equals(other.positional_metadata) elif not (self.has_positional_metadata() or other.has_positional_metadata()): # Both don't have positional metadata. return ( self._positional_metadata_axis_len_() == other._positional_metadata_axis_len_() ) else: # One has positional metadata while the other does not. return False @abstractmethod def __ne__(self, other): raise NotImplementedError def _ne_(self, other): return not (self == other) @abstractmethod def __copy__(self): raise NotImplementedError def _copy_(self): if self.has_positional_metadata(): # deep=True makes a shallow copy of the underlying data buffer. return self.positional_metadata.copy(deep=True) else: return None @abstractmethod def __deepcopy__(self, memo): raise NotImplementedError def _deepcopy_(self, memo): if self.has_positional_metadata(): # `copy.deepcopy` no longer recursively copies contents of the # DataFrame, so we must handle the deep copy ourselves. # Reference: https://github.com/pandas-dev/pandas/issues/17406 df = self.positional_metadata data_cp = deepcopy(df.values.tolist(), memo) return pd.DataFrame( data_cp, index=df.index.copy(deep=True), columns=df.columns.copy(deep=True), copy=False, ) else: return None def has_positional_metadata(self): """Determine if the object has positional metadata. An object has positional metadata if its ``positional_metadata`` ``pd.DataFrame`` has at least one column. Returns ------- bool Indicates whether the object has positional metadata. Examples -------- .. note:: scikit-bio objects with positional metadata share a common interface for accessing and manipulating their positional metadata. The following examples use scikit-bio's ``DNA`` class to demonstrate positional metadata behavior. These examples apply to all other scikit-bio objects storing positional metadata. >>> import pandas as pd >>> from skbio import DNA >>> seq = DNA('ACGT') >>> seq.has_positional_metadata() False >>> seq = DNA('ACGT', positional_metadata=pd.DataFrame(index=range(4))) >>> seq.has_positional_metadata() False >>> seq = DNA('ACGT', positional_metadata={'quality': range(4)}) >>> seq.has_positional_metadata() True """ return ( self._positional_metadata is not None and len(self.positional_metadata.columns) > 0 ) class IntervalMetadataMixin(metaclass=ABCMeta): @abstractmethod def _interval_metadata_axis_len_(self): """Return length of axis that interval metadata applies to. Returns ------- int Interval metadata axis length. """ raise NotImplementedError @abstractmethod def __init__(self, interval_metadata=None): raise NotImplementedError def _init_(self, interval_metadata=None): if interval_metadata is None: # Could use deleter but this is less overhead and needs to be fast. self._interval_metadata = None else: # Use setter for validation and copy. self.interval_metadata = interval_metadata @property def interval_metadata(self): """``IntervalMetadata`` object containing info about interval features. Notes ----- This property can be set and deleted. When setting new interval metadata, a shallow copy of the ``IntervalMetadata`` object is made. """ if self._interval_metadata is None: # Not using setter to avoid copy. self._interval_metadata = IntervalMetadata( self._interval_metadata_axis_len_() ) return self._interval_metadata @interval_metadata.setter def interval_metadata(self, interval_metadata): if isinstance(interval_metadata, IntervalMetadata): upper_bound = interval_metadata.upper_bound lower_bound = interval_metadata.lower_bound axis_len = self._interval_metadata_axis_len_() if lower_bound != 0: raise ValueError( "The lower bound for the interval features (%d) " "must be zero." % lower_bound ) if upper_bound is not None and upper_bound != axis_len: raise ValueError( "The upper bound for the interval features (%d) " "must match the interval metadata axis length (%d)" % (upper_bound, axis_len) ) # copy all the data to the mixin self._interval_metadata = IntervalMetadata( axis_len, copy_from=interval_metadata ) else: raise TypeError( "You must provide `IntervalMetadata` object, " "not type %s." % type(interval_metadata).__name__ ) @interval_metadata.deleter def interval_metadata(self): self._interval_metadata = None def has_interval_metadata(self): """Determine if the object has interval metadata. An object has interval metadata if its ``interval_metadata`` has at least one ```Interval`` objects. Returns ------- bool Indicates whether the object has interval metadata. """ return ( self._interval_metadata is not None and self.interval_metadata.num_interval_features > 0 ) @abstractmethod def __eq__(self, other): raise NotImplementedError def _eq_(self, other): # We're not simply comparing self.interval_metadata to # other.interval_metadata in order to avoid creating "empty" # interval metadata representations on the objects if they don't have # interval metadata. if self.has_interval_metadata() and other.has_interval_metadata(): return self.interval_metadata == other.interval_metadata elif not (self.has_interval_metadata() or other.has_interval_metadata()): # Both don't have interval metadata. return ( self._interval_metadata_axis_len_() == other._interval_metadata_axis_len_() ) else: # One has interval metadata while the other does not. return False @abstractmethod def __ne__(self, other): raise NotImplementedError def _ne_(self, other): return not (self == other) @abstractmethod def __copy__(self): raise NotImplementedError def _copy_(self): if self.has_interval_metadata(): return copy(self.interval_metadata) else: return None @abstractmethod def __deepcopy__(self, memo): raise NotImplementedError def _deepcopy_(self, memo): if self.has_interval_metadata(): return deepcopy(self.interval_metadata, memo) else: return None scikit-bio-scikit-bio-a3beaa6/skbio/metadata/_repr.py000066400000000000000000000150101520735541300227200ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import itertools import numbers import textwrap from abc import ABCMeta, abstractmethod from skbio._base import ElasticLines class _MetadataReprBuilder(metaclass=ABCMeta): """An ABC for building a repr from an object containing metadata. This abstract base class constructs a repr string for an object which contains metadata, positional metadata and/or interval metadata. Parameters ---------- obj : Type varies depending on subclass Object to build repr for. width : int Maximum width of the repr. indent : int Number of spaces to use for indented lines. """ def __init__(self, obj, width, indent): self._obj = obj self._width = width self._indent = " " * indent @abstractmethod def _process_header(self): """Build header for the repr. Used by `build` Template Method.""" raise NotImplementedError @abstractmethod def _process_data(self): """Build data lines for the repr. Used by `build` Template Method.""" raise NotImplementedError def build(self): """Template method for building the repr.""" self._lines = ElasticLines() self._process_header() self._process_metadata() self._process_positional_metadata() self._process_interval_metadata() self._process_stats() self._process_data() return self._lines.to_str() def _process_metadata(self): if self._obj.has_metadata(): self._lines.add_line("Metadata:") # Python 3 doesn't allow sorting of mixed types so we can't just # use sorted() on the metadata keys. Sort first by type then sort # by value within each type. for key in self._sorted_keys_grouped_by_type(self._obj.metadata): value = self._obj.metadata[key] self._lines.add_lines(self._format_metadata_key_value(key, value)) def _sorted_keys_grouped_by_type(self, dict_): """Group keys within a dict by their type and sort within type.""" type_sorted = sorted(dict_, key=self._type_sort_key) type_and_value_sorted = [] for _, group in itertools.groupby(type_sorted, self._type_sort_key): type_and_value_sorted.extend(sorted(group)) return type_and_value_sorted def _type_sort_key(self, key): return repr(type(key)) def _format_metadata_key_value(self, key, value): """Format metadata key:value, wrapping across lines if necessary.""" key_fmt = self._format_key(key) supported_type = True if isinstance(value, str): # extra indent of 1 so that wrapped text lines up: # # 'foo': 'abc def ghi # jkl mno' value_repr = repr(value) extra_indent = 1 elif isinstance(value, bytes): # extra indent of 2 so that wrapped text lines up: # # 'foo': b'abc def ghi # jkl mno' value_repr = repr(value) extra_indent = 2 # handles any number, this includes bool elif value is None or isinstance(value, numbers.Number): value_repr = repr(value) extra_indent = 0 else: supported_type = False if not supported_type or len(value_repr) > 140: value_repr = str(type(value)) # extra indent of 1 so that wrapped text lines up past the bracket: # # 'foo': extra_indent = 1 return self._wrap_text_with_indent(value_repr, key_fmt, extra_indent) def _process_positional_metadata(self): if self._obj.has_positional_metadata(): self._lines.add_line("Positional metadata:") for key in self._obj.positional_metadata.columns.values.tolist(): dtype = self._obj.positional_metadata[key].dtype self._lines.add_lines( self._format_positional_metadata_column(key, dtype) ) def _format_positional_metadata_column(self, key, dtype): key_fmt = self._format_key(key) dtype_fmt = "" % str(dtype) return self._wrap_text_with_indent(dtype_fmt, key_fmt, 1) def _process_interval_metadata(self): # TODO: this hasattr check can be removed once all the relevant # classes have interval_metadata added to it. if ( hasattr(self._obj, "has_interval_metadata") and self._obj.has_interval_metadata() ): self._lines.add_line("Interval metadata:") n = self._obj.interval_metadata.num_interval_features line = self._indent + "%d interval feature" % n if n > 1: line += "s" self._lines.add_line(line) def _format_key(self, key): """Format metadata key. Includes initial indent and trailing colon and space: 'foo': """ key_fmt = self._indent + repr(key) supported_types = (str, bytes, numbers.Number, type(None)) if len(key_fmt) > (self._width / 2) or not isinstance(key, supported_types): key_fmt = self._indent + str(type(key)) return "%s: " % key_fmt def _wrap_text_with_indent(self, text, initial_text, extra_indent): """Wrap text across lines with an initial indentation. For example: 'foo': 'abc def ghi jkl mno pqr' 'foo': is `initial_text`. `extra_indent` is 1. Wrapped lines are indented such that they line up with the start of the previous line of wrapped text. """ return textwrap.wrap( text, width=self._width, expand_tabs=False, initial_indent=initial_text, subsequent_indent=" " * (len(initial_text) + extra_indent), ) def _process_stats(self): self._lines.add_line("Stats:") for label, value in self._obj._repr_stats(): self._lines.add_line("%s%s: %s" % (self._indent, label, value)) self._lines.add_separator() scikit-bio-scikit-bio-a3beaa6/skbio/metadata/_testing.py000066400000000000000000001461741520735541300234450ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import copy import pandas as pd import numpy as np import numpy.testing as npt from skbio.util._testing import assert_data_frame_almost_equal from skbio.metadata import IntervalMetadata class MetadataMixinTests: def test_constructor_invalid_type(self): for md in (0, "a", ("f", "o", "o"), np.array([]), pd.DataFrame()): with self.assertRaisesRegex(TypeError, "metadata must be a dict"): self._metadata_constructor_(metadata=md) def test_constructor_no_metadata(self): for md in None, {}: obj = self._metadata_constructor_(metadata=md) self.assertFalse(obj.has_metadata()) self.assertEqual(obj.metadata, {}) def test_constructor_with_metadata(self): obj = self._metadata_constructor_(metadata={"foo": "bar"}) self.assertEqual(obj.metadata, {"foo": "bar"}) obj = self._metadata_constructor_(metadata={"": "", 123: {"a": "b", "c": "d"}}) self.assertEqual(obj.metadata, {"": "", 123: {"a": "b", "c": "d"}}) def test_constructor_handles_missing_metadata_efficiently(self): self.assertIsNone(self._metadata_constructor_()._metadata) self.assertIsNone(self._metadata_constructor_(metadata=None)._metadata) def test_constructor_makes_shallow_copy_of_metadata(self): md = {"foo": "bar", 42: []} obj = self._metadata_constructor_(metadata=md) self.assertEqual(obj.metadata, md) self.assertIsNot(obj.metadata, md) md["foo"] = "baz" self.assertEqual(obj.metadata, {"foo": "bar", 42: []}) md[42].append(True) self.assertEqual(obj.metadata, {"foo": "bar", 42: [True]}) def test_eq(self): self.assertReallyEqual( self._metadata_constructor_(metadata={"foo": 42}), self._metadata_constructor_(metadata={"foo": 42}), ) self.assertReallyEqual( self._metadata_constructor_(metadata={"foo": 42, 123: {}}), self._metadata_constructor_(metadata={"foo": 42, 123: {}}), ) def test_eq_missing_metadata(self): self.assertReallyEqual( self._metadata_constructor_(), self._metadata_constructor_() ) self.assertReallyEqual( self._metadata_constructor_(), self._metadata_constructor_(metadata={}) ) self.assertReallyEqual( self._metadata_constructor_(metadata={}), self._metadata_constructor_(metadata={}), ) def test_eq_handles_missing_metadata_efficiently(self): obj1 = self._metadata_constructor_() obj2 = self._metadata_constructor_() self.assertReallyEqual(obj1, obj2) self.assertIsNone(obj1._metadata) self.assertIsNone(obj2._metadata) def test_ne(self): # Both have metadata. obj1 = self._metadata_constructor_(metadata={"id": "foo"}) obj2 = self._metadata_constructor_(metadata={"id": "bar"}) self.assertReallyNotEqual(obj1, obj2) # One has metadata. obj1 = self._metadata_constructor_(metadata={"id": "foo"}) obj2 = self._metadata_constructor_() self.assertReallyNotEqual(obj1, obj2) def test_copy_metadata_none(self): obj = self._metadata_constructor_() obj_copy = copy.copy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNone(obj._metadata) self.assertIsNone(obj_copy._metadata) def test_copy_metadata_empty(self): obj = self._metadata_constructor_(metadata={}) obj_copy = copy.copy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertEqual(obj._metadata, {}) self.assertIsNone(obj_copy._metadata) def test_copy_with_metadata(self): obj = self._metadata_constructor_(metadata={"foo": [1]}) obj_copy = copy.copy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNot(obj._metadata, obj_copy._metadata) self.assertIs(obj._metadata["foo"], obj_copy._metadata["foo"]) obj_copy.metadata["foo"].append(2) obj_copy.metadata["foo2"] = 42 self.assertEqual(obj_copy.metadata, {"foo": [1, 2], "foo2": 42}) self.assertEqual(obj.metadata, {"foo": [1, 2]}) def test_deepcopy_metadata_none(self): obj = self._metadata_constructor_() obj_copy = copy.deepcopy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNone(obj._metadata) self.assertIsNone(obj_copy._metadata) def test_deepcopy_metadata_empty(self): obj = self._metadata_constructor_(metadata={}) obj_copy = copy.deepcopy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertEqual(obj._metadata, {}) self.assertIsNone(obj_copy._metadata) def test_deepcopy_with_metadata(self): obj = self._metadata_constructor_(metadata={"foo": [1]}) obj_copy = copy.deepcopy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNot(obj._metadata, obj_copy._metadata) self.assertIsNot(obj._metadata["foo"], obj_copy._metadata["foo"]) obj_copy.metadata["foo"].append(2) obj_copy.metadata["foo2"] = 42 self.assertEqual(obj_copy.metadata, {"foo": [1, 2], "foo2": 42}) self.assertEqual(obj.metadata, {"foo": [1]}) def test_deepcopy_memo_is_respected(self): # Basic test to ensure deepcopy's memo is passed through to recursive # deepcopy calls. obj = self._metadata_constructor_(metadata={"foo": "bar"}) memo = {} copy.deepcopy(obj, memo) self.assertGreater(len(memo), 2) def test_metadata_getter(self): obj = self._metadata_constructor_(metadata={42: "foo", ("hello", "world"): 43}) self.assertIsInstance(obj.metadata, dict) self.assertEqual(obj.metadata, {42: "foo", ("hello", "world"): 43}) obj.metadata[42] = "bar" self.assertEqual(obj.metadata, {42: "bar", ("hello", "world"): 43}) def test_metadata_getter_no_metadata(self): obj = self._metadata_constructor_() self.assertIsNone(obj._metadata) self.assertIsInstance(obj.metadata, dict) self.assertEqual(obj.metadata, {}) self.assertIsNotNone(obj._metadata) def test_metadata_setter(self): obj = self._metadata_constructor_() self.assertFalse(obj.has_metadata()) obj.metadata = {"hello": "world"} self.assertTrue(obj.has_metadata()) self.assertEqual(obj.metadata, {"hello": "world"}) obj.metadata = {} self.assertFalse(obj.has_metadata()) self.assertEqual(obj.metadata, {}) def test_metadata_setter_makes_shallow_copy(self): obj = self._metadata_constructor_() md = {"foo": "bar", 42: []} obj.metadata = md self.assertEqual(obj.metadata, md) self.assertIsNot(obj.metadata, md) md["foo"] = "baz" self.assertEqual(obj.metadata, {"foo": "bar", 42: []}) md[42].append(True) self.assertEqual(obj.metadata, {"foo": "bar", 42: [True]}) def test_metadata_setter_invalid_type(self): obj = self._metadata_constructor_(metadata={123: 456}) for md in (None, 0, "a", ("f", "o", "o"), np.array([]), pd.DataFrame()): with self.assertRaisesRegex(TypeError, "metadata must be a dict"): obj.metadata = md self.assertEqual(obj.metadata, {123: 456}) def test_metadata_deleter(self): obj = self._metadata_constructor_(metadata={"foo": "bar"}) self.assertEqual(obj.metadata, {"foo": "bar"}) del obj.metadata self.assertIsNone(obj._metadata) self.assertFalse(obj.has_metadata()) # Delete again. del obj.metadata self.assertIsNone(obj._metadata) self.assertFalse(obj.has_metadata()) obj = self._metadata_constructor_() self.assertIsNone(obj._metadata) self.assertFalse(obj.has_metadata()) del obj.metadata self.assertIsNone(obj._metadata) self.assertFalse(obj.has_metadata()) def test_has_metadata(self): obj = self._metadata_constructor_() self.assertFalse(obj.has_metadata()) # Handles metadata efficiently. self.assertIsNone(obj._metadata) self.assertFalse(self._metadata_constructor_(metadata={}).has_metadata()) self.assertTrue(self._metadata_constructor_(metadata={"": ""}).has_metadata()) self.assertTrue( self._metadata_constructor_(metadata={"foo": 42}).has_metadata() ) class PositionalMetadataMixinTests: def test_constructor_invalid_positional_metadata_type(self): with self.assertRaisesRegex( TypeError, "Invalid positional metadata. Must be " "consumable by `pd.DataFrame` constructor." " Original pandas error message: ", ): self._positional_metadata_constructor_(0, positional_metadata=2) def test_constructor_positional_metadata_len_mismatch(self): # Zero elements. with self.assertRaisesRegex(ValueError, r"\(0\).*\(4\)"): self._positional_metadata_constructor_(4, positional_metadata=[]) # Not enough elements. with self.assertRaisesRegex(ValueError, r"\(3\).*\(4\)"): self._positional_metadata_constructor_(4, positional_metadata=[2, 3, 4]) # Too many elements. with self.assertRaisesRegex(ValueError, r"\(5\).*\(4\)"): self._positional_metadata_constructor_( 4, positional_metadata=[2, 3, 4, 5, 6] ) # Series not enough rows. with self.assertRaisesRegex(ValueError, r"\(3\).*\(4\)"): self._positional_metadata_constructor_( 4, positional_metadata=pd.Series(range(3)) ) # Series too many rows. with self.assertRaisesRegex(ValueError, r"\(5\).*\(4\)"): self._positional_metadata_constructor_( 4, positional_metadata=pd.Series(range(5)) ) # DataFrame not enough rows. with self.assertRaisesRegex(ValueError, r"\(3\).*\(4\)"): self._positional_metadata_constructor_( 4, positional_metadata=pd.DataFrame({"quality": range(3)}) ) # DataFrame too many rows. with self.assertRaisesRegex(ValueError, r"\(5\).*\(4\)"): self._positional_metadata_constructor_( 4, positional_metadata=pd.DataFrame({"quality": range(5)}) ) # Empty DataFrame wrong size. with self.assertRaisesRegex(ValueError, r"\(2\).*\(3\)"): self._positional_metadata_constructor_( 3, positional_metadata=pd.DataFrame(index=range(2)) ) def test_constructor_no_positional_metadata(self): # Length zero with missing/empty positional metadata. for empty in None, {}, pd.DataFrame(): obj = self._positional_metadata_constructor_(0, positional_metadata=empty) self.assertFalse(obj.has_positional_metadata()) self.assertIsInstance(obj.positional_metadata.index, pd.RangeIndex) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame(index=range(0)) ) # Nonzero length with missing positional metadata. obj = self._positional_metadata_constructor_(3, positional_metadata=None) self.assertFalse(obj.has_positional_metadata()) self.assertIsInstance(obj.positional_metadata.index, pd.RangeIndex) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame(index=range(3)) ) def test_constructor_with_positional_metadata_len_zero(self): for data in [], (), np.array([]): obj = self._positional_metadata_constructor_( 0, positional_metadata={"foo": data} ) self.assertTrue(obj.has_positional_metadata()) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": data}, index=range(0)) ) def test_constructor_with_positional_metadata_len_one(self): for data in [2], (2,), np.array([2]): obj = self._positional_metadata_constructor_( 1, positional_metadata={"foo": data} ) self.assertTrue(obj.has_positional_metadata()) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": data}, index=range(1)) ) def test_constructor_with_positional_metadata_len_greater_than_one(self): for data in ( [0, 42, 42, 1, 0, 8, 100, 0, 0], (0, 42, 42, 1, 0, 8, 100, 0, 0), np.array([0, 42, 42, 1, 0, 8, 100, 0, 0]), ): obj = self._positional_metadata_constructor_( 9, positional_metadata={"foo": data} ) self.assertTrue(obj.has_positional_metadata()) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": data}, index=range(9)) ) def test_constructor_with_positional_metadata_multiple_columns(self): obj = self._positional_metadata_constructor_( 5, positional_metadata={"foo": np.arange(5), "bar": np.arange(5)[::-1]} ) self.assertTrue(obj.has_positional_metadata()) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame( {"foo": np.arange(5), "bar": np.arange(5)[::-1]}, index=range(5) ), ) def test_constructor_with_positional_metadata_custom_index(self): df = pd.DataFrame( {"foo": np.arange(5), "bar": np.arange(5)[::-1]}, index=["a", "b", "c", "d", "e"], ) obj = self._positional_metadata_constructor_(5, positional_metadata=df) self.assertTrue(obj.has_positional_metadata()) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame( {"foo": np.arange(5), "bar": np.arange(5)[::-1]}, index=range(5) ), ) def test_constructor_with_positional_metadata_int64_index(self): # Test that memory-inefficient index is converted to memory-efficient # index. df = pd.DataFrame( {"foo": np.arange(5), "bar": np.arange(5)[::-1]}, index=np.arange(5) ) self.assertEqual(df.index.dtype, np.int_) obj = self._positional_metadata_constructor_(5, positional_metadata=df) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame( {"foo": np.arange(5), "bar": np.arange(5)[::-1]}, index=range(5) ), ) self.assertIsInstance(obj.positional_metadata.index, pd.RangeIndex) def test_constructor_handles_missing_positional_metadata_efficiently(self): obj = self._positional_metadata_constructor_(4) self.assertIsNone(obj._positional_metadata) obj = self._positional_metadata_constructor_(4, positional_metadata=None) self.assertIsNone(obj._positional_metadata) def test_constructor_makes_shallow_copy_of_positional_metadata(self): df = pd.DataFrame( {"foo": [22, 22, 0], "bar": [[], [], []]}, index=["a", "b", "c"] ) obj = self._positional_metadata_constructor_(3, positional_metadata=df) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [22, 22, 0], "bar": [[], [], []]}, index=range(3)), ) self.assertIsNot(obj.positional_metadata, df) # Original df is not mutated. orig_df = pd.DataFrame( {"foo": [22, 22, 0], "bar": [[], [], []]}, index=["a", "b", "c"] ) assert_data_frame_almost_equal(df, orig_df) # Change values of column (using same dtype). df["foo"] = [42, 42, 42] assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [22, 22, 0], "bar": [[], [], []]}, index=range(3)), ) # Change single value of underlying data. df.values[0][0] = 10 assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [22, 22, 0], "bar": [[], [], []]}, index=range(3)), ) # Mutate list (not a deep copy). df["bar"].iloc[0].append(42) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [22, 22, 0], "bar": [[42], [], []]}, index=range(3)), ) def test_eq_basic(self): obj1 = self._positional_metadata_constructor_( 3, positional_metadata={"foo": [1, 2, 3]} ) obj2 = self._positional_metadata_constructor_( 3, positional_metadata={"foo": [1, 2, 3]} ) self.assertReallyEqual(obj1, obj2) def test_eq_from_different_source(self): obj1 = self._positional_metadata_constructor_( 3, positional_metadata={"foo": np.array([1, 2, 3], dtype=np.int_)} ) obj2 = self._positional_metadata_constructor_( 3, positional_metadata=pd.DataFrame( {"foo": [1, 2, 3]}, index=["foo", "bar", "baz"], dtype=np.int_ ), ) self.assertReallyEqual(obj1, obj2) def test_eq_missing_positional_metadata(self): for empty in None, {}, pd.DataFrame(), pd.DataFrame(index=[]): obj = self._positional_metadata_constructor_(0, positional_metadata=empty) self.assertReallyEqual(obj, self._positional_metadata_constructor_(0)) self.assertReallyEqual( obj, self._positional_metadata_constructor_(0, positional_metadata=empty), ) for empty in None, pd.DataFrame(index=["a", "b"]): obj = self._positional_metadata_constructor_(2, positional_metadata=empty) self.assertReallyEqual(obj, self._positional_metadata_constructor_(2)) self.assertReallyEqual( obj, self._positional_metadata_constructor_(2, positional_metadata=empty), ) def test_eq_handles_missing_positional_metadata_efficiently(self): obj1 = self._positional_metadata_constructor_(1) obj2 = self._positional_metadata_constructor_(1) self.assertReallyEqual(obj1, obj2) self.assertIsNone(obj1._positional_metadata) self.assertIsNone(obj2._positional_metadata) def test_ne_len_zero(self): # Both have positional metadata. obj1 = self._positional_metadata_constructor_( 0, positional_metadata={"foo": []} ) obj2 = self._positional_metadata_constructor_( 0, positional_metadata={"foo": [], "bar": []} ) self.assertReallyNotEqual(obj1, obj2) # One has positional metadata. obj1 = self._positional_metadata_constructor_( 0, positional_metadata={"foo": []} ) obj2 = self._positional_metadata_constructor_(0) self.assertReallyNotEqual(obj1, obj2) def test_ne_len_greater_than_zero(self): # Both have positional metadata. obj1 = self._positional_metadata_constructor_( 3, positional_metadata={"foo": [1, 2, 3]} ) obj2 = self._positional_metadata_constructor_( 3, positional_metadata={"foo": [1, 2, 2]} ) self.assertReallyNotEqual(obj1, obj2) # One has positional metadata. obj1 = self._positional_metadata_constructor_( 3, positional_metadata={"foo": [1, 2, 3]} ) obj2 = self._positional_metadata_constructor_(3) self.assertReallyNotEqual(obj1, obj2) def test_ne_len_mismatch(self): obj1 = self._positional_metadata_constructor_( 3, positional_metadata=pd.DataFrame(index=range(3)) ) obj2 = self._positional_metadata_constructor_( 2, positional_metadata=pd.DataFrame(index=range(2)) ) self.assertReallyNotEqual(obj1, obj2) def test_copy_positional_metadata_none(self): obj = self._positional_metadata_constructor_(3) obj_copy = copy.copy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNone(obj._positional_metadata) self.assertIsNone(obj_copy._positional_metadata) def test_copy_positional_metadata_empty(self): obj = self._positional_metadata_constructor_( 3, positional_metadata=pd.DataFrame(index=range(3)) ) obj_copy = copy.copy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) assert_data_frame_almost_equal( obj._positional_metadata, pd.DataFrame(index=range(3)) ) self.assertIsNone(obj_copy._positional_metadata) def test_copy_with_positional_metadata(self): obj = self._positional_metadata_constructor_( 4, positional_metadata={"bar": [[], [], [], []], "baz": [42, 42, 42, 42]} ) obj_copy = copy.copy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNot(obj._positional_metadata, obj_copy._positional_metadata) self.assertIsNot( obj._positional_metadata.values, obj_copy._positional_metadata.values ) self.assertIs( obj._positional_metadata.loc[0, "bar"], obj_copy._positional_metadata.loc[0, "bar"], ) obj_copy.positional_metadata.loc[0, "bar"].append(1) obj_copy.positional_metadata.loc[0, "baz"] = 43 assert_data_frame_almost_equal( obj_copy.positional_metadata, pd.DataFrame({"bar": [[1], [], [], []], "baz": [43, 42, 42, 42]}), ) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"bar": [[1], [], [], []], "baz": [42, 42, 42, 42]}), ) def test_copy_preserves_range_index(self): for pm in None, {"foo": ["a", "b", "c"]}: obj = self._positional_metadata_constructor_(3, positional_metadata=pm) obj_copy = copy.copy(obj) self.assertIsInstance(obj.positional_metadata.index, pd.RangeIndex) self.assertIsInstance(obj_copy.positional_metadata.index, pd.RangeIndex) def test_deepcopy_positional_metadata_none(self): obj = self._positional_metadata_constructor_(3) obj_copy = copy.deepcopy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNone(obj._positional_metadata) self.assertIsNone(obj_copy._positional_metadata) def test_deepcopy_positional_metadata_empty(self): obj = self._positional_metadata_constructor_( 3, positional_metadata=pd.DataFrame(index=range(3)) ) obj_copy = copy.deepcopy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) assert_data_frame_almost_equal( obj._positional_metadata, pd.DataFrame(index=range(3)) ) self.assertIsNone(obj_copy._positional_metadata) def test_deepcopy_with_positional_metadata(self): obj = self._positional_metadata_constructor_( 4, positional_metadata={"bar": [[], [], [], []], "baz": [42, 42, 42, 42]} ) obj_copy = copy.deepcopy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNot(obj._positional_metadata, obj_copy._positional_metadata) self.assertIsNot( obj._positional_metadata.values, obj_copy._positional_metadata.values ) self.assertIsNot( obj._positional_metadata.loc[0, "bar"], obj_copy._positional_metadata.loc[0, "bar"], ) obj_copy.positional_metadata.loc[0, "bar"].append(1) obj_copy.positional_metadata.loc[0, "baz"] = 43 assert_data_frame_almost_equal( obj_copy.positional_metadata, pd.DataFrame({"bar": [[1], [], [], []], "baz": [43, 42, 42, 42]}), ) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"bar": [[], [], [], []], "baz": [42, 42, 42, 42]}), ) def test_deepcopy_preserves_range_index(self): for pm in None, {"foo": ["a", "b", "c"]}: obj = self._positional_metadata_constructor_(3, positional_metadata=pm) obj_copy = copy.deepcopy(obj) self.assertIsInstance(obj.positional_metadata.index, pd.RangeIndex) self.assertIsInstance(obj_copy.positional_metadata.index, pd.RangeIndex) def test_deepcopy_memo_is_respected(self): # Basic test to ensure deepcopy's memo is passed through to recursive # deepcopy calls. obj = self._positional_metadata_constructor_( 3, positional_metadata={"foo": [1, 2, 3]} ) memo = {} copy.deepcopy(obj, memo) self.assertGreater(len(memo), 2) def test_positional_metadata_getter(self): obj = self._positional_metadata_constructor_( 3, positional_metadata={"foo": [22, 22, 0]} ) self.assertIsInstance(obj.positional_metadata, pd.DataFrame) self.assertIsInstance(obj.positional_metadata.index, pd.RangeIndex) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [22, 22, 0]}) ) # Update existing column. obj.positional_metadata["foo"] = [42, 42, 43] assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [42, 42, 43]}) ) # Add new column. obj.positional_metadata["foo2"] = [True, False, True] assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [42, 42, 43], "foo2": [True, False, True]}), ) def test_positional_metadata_getter_no_positional_metadata(self): obj = self._positional_metadata_constructor_(4) self.assertIsNone(obj._positional_metadata) self.assertIsInstance(obj.positional_metadata, pd.DataFrame) self.assertIsInstance(obj.positional_metadata.index, pd.RangeIndex) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame(index=range(4)) ) self.assertIsNotNone(obj._positional_metadata) def test_positional_metadata_getter_set_column_series(self): length = 8 obj = self._positional_metadata_constructor_( length, positional_metadata={"foo": range(length)} ) obj.positional_metadata["bar"] = pd.Series(range(length - 3)) # pandas.Series will be padded with NaN if too short. npt.assert_equal( obj.positional_metadata["bar"], np.array(list(range(length - 3)) + [np.nan] * 3), ) obj.positional_metadata["baz"] = pd.Series(range(length + 3)) # pandas.Series will be truncated if too long. npt.assert_equal(obj.positional_metadata["baz"], np.array(range(length))) def test_positional_metadata_getter_set_column_array(self): length = 8 obj = self._positional_metadata_constructor_( length, positional_metadata={"foo": range(length)} ) # array-like objects will fail if wrong size. for array_like in ( np.array(range(length - 1)), range(length - 1), np.array(range(length + 1)), range(length + 1), ): with self.assertRaisesRegex( ValueError, r"Length of values \(" + str(len(array_like)) + r"\) does not match length" r" of index \(8\)", ): obj.positional_metadata["bar"] = array_like def test_positional_metadata_setter_pandas_consumable(self): obj = self._positional_metadata_constructor_(3) self.assertFalse(obj.has_positional_metadata()) obj.positional_metadata = {"foo": [3, 2, 1]} self.assertTrue(obj.has_positional_metadata()) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [3, 2, 1]}) ) obj.positional_metadata = pd.DataFrame(index=np.arange(3)) self.assertFalse(obj.has_positional_metadata()) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame(index=range(3)) ) def test_positional_metadata_setter_data_frame(self): obj = self._positional_metadata_constructor_(3) self.assertFalse(obj.has_positional_metadata()) obj.positional_metadata = pd.DataFrame( {"foo": [3, 2, 1]}, index=["a", "b", "c"] ) self.assertTrue(obj.has_positional_metadata()) self.assertIsInstance(obj.positional_metadata.index, pd.RangeIndex) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [3, 2, 1]}) ) obj.positional_metadata = pd.DataFrame(index=np.arange(3)) self.assertFalse(obj.has_positional_metadata()) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame(index=range(3)) ) def test_positional_metadata_setter_none(self): obj = self._positional_metadata_constructor_(0, positional_metadata={"foo": []}) self.assertTrue(obj.has_positional_metadata()) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": []}) ) # `None` behavior differs from constructor. obj.positional_metadata = None self.assertFalse(obj.has_positional_metadata()) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame(index=range(0)) ) def test_positional_metadata_setter_int64_index(self): # Test that memory-inefficient index is converted to memory-efficient # index. obj = self._positional_metadata_constructor_(5) df = pd.DataFrame( {"foo": np.arange(5), "bar": np.arange(5)[::-1]}, index=np.arange(5) ) self.assertEqual(df.index.dtype, np.int_) obj.positional_metadata = df assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame( {"foo": np.arange(5), "bar": np.arange(5)[::-1]}, index=range(5) ), ) self.assertIsInstance(obj.positional_metadata.index, pd.RangeIndex) def test_positional_metadata_setter_makes_shallow_copy(self): obj = self._positional_metadata_constructor_(3) df = pd.DataFrame( {"foo": [22, 22, 0], "bar": [[], [], []]}, index=["a", "b", "c"] ) obj.positional_metadata = df assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [22, 22, 0], "bar": [[], [], []]}, index=range(3)), ) self.assertIsNot(obj.positional_metadata, df) # Original df is not mutated. orig_df = pd.DataFrame( {"foo": [22, 22, 0], "bar": [[], [], []]}, index=["a", "b", "c"] ) assert_data_frame_almost_equal(df, orig_df) # Change values of column (using same dtype). df["foo"] = [42, 42, 42] assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [22, 22, 0], "bar": [[], [], []]}, index=range(3)), ) # Change single value of underlying data. df.values[0][0] = 10 assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [22, 22, 0], "bar": [[], [], []]}, index=range(3)), ) # Mutate list (not a deep copy). df["bar"].iloc[0].append(42) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [22, 22, 0], "bar": [[42], [], []]}, index=range(3)), ) def test_positional_metadata_setter_invalid_type(self): obj = self._positional_metadata_constructor_( 3, positional_metadata={"foo": [1, 2, 42]} ) with self.assertRaisesRegex( TypeError, "Invalid positional metadata. Must be " "consumable by `pd.DataFrame` constructor." " Original pandas error message: ", ): obj.positional_metadata = 2 assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [1, 2, 42]}) ) def test_positional_metadata_setter_len_mismatch(self): obj = self._positional_metadata_constructor_( 3, positional_metadata={"foo": [1, 2, 42]} ) # `None` behavior differs from constructor. with self.assertRaisesRegex(ValueError, r"\(0\).*\(3\)"): obj.positional_metadata = None assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [1, 2, 42]}) ) with self.assertRaisesRegex(ValueError, r"\(4\).*\(3\)"): obj.positional_metadata = [1, 2, 3, 4] assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [1, 2, 42]}) ) def test_positional_metadata_deleter(self): obj = self._positional_metadata_constructor_( 3, positional_metadata={"foo": [1, 2, 3]} ) self.assertIsInstance(obj.positional_metadata.index, pd.RangeIndex) assert_data_frame_almost_equal( obj.positional_metadata, pd.DataFrame({"foo": [1, 2, 3]}) ) del obj.positional_metadata self.assertIsNone(obj._positional_metadata) self.assertFalse(obj.has_positional_metadata()) # Delete again. del obj.positional_metadata self.assertIsNone(obj._positional_metadata) self.assertFalse(obj.has_positional_metadata()) obj = self._positional_metadata_constructor_(3) self.assertIsNone(obj._positional_metadata) self.assertFalse(obj.has_positional_metadata()) del obj.positional_metadata self.assertIsNone(obj._positional_metadata) self.assertFalse(obj.has_positional_metadata()) def test_has_positional_metadata(self): obj = self._positional_metadata_constructor_(4) self.assertFalse(obj.has_positional_metadata()) self.assertIsNone(obj._positional_metadata) obj = self._positional_metadata_constructor_(0, positional_metadata={}) self.assertFalse(obj.has_positional_metadata()) obj = self._positional_metadata_constructor_( 4, positional_metadata=pd.DataFrame(index=np.arange(4)) ) self.assertFalse(obj.has_positional_metadata()) obj = self._positional_metadata_constructor_( 4, positional_metadata=pd.DataFrame(index=["a", "b", "c", "d"]) ) self.assertFalse(obj.has_positional_metadata()) obj = self._positional_metadata_constructor_(0, positional_metadata={"foo": []}) self.assertTrue(obj.has_positional_metadata()) obj = self._positional_metadata_constructor_( 4, positional_metadata={"foo": [1, 2, 3, 4]} ) self.assertTrue(obj.has_positional_metadata()) obj = self._positional_metadata_constructor_( 2, positional_metadata={"foo": [1, 2], "bar": ["abc", "def"]} ) self.assertTrue(obj.has_positional_metadata()) class IntervalMetadataMixinTests: def _set_up(self): self.upper_bound = 9 self.im = IntervalMetadata(self.upper_bound) self.intvls = [ {"bounds": [(0, 1), (2, 9)], "metadata": {"gene": "sagA"}}, {"bounds": [(0, 1)], "metadata": {"gene": ["a"], "product": "foo"}}, ] def test_constructor_invalid(self): with self.assertRaisesRegex( TypeError, "You must provide `IntervalMetadata` " "object." ): self._interval_metadata_constructor_(0, "") def test_constructor_empty_interval_metadata_upper_bound_is_none(self): im = IntervalMetadata(None) for i in [0, 1, 3, 100]: x = self._interval_metadata_constructor_(i, im) # the upper bound is reset to seq/axis length self.assertEqual(x.interval_metadata.upper_bound, i) self.assertEqual(x.interval_metadata._intervals, im._intervals) # original interval metadata upper bound is not changed self.assertIsNone(im.upper_bound) def test_constructor_interval_metadata_upper_bound_is_none(self): im = IntervalMetadata(None) # populate im im.add(**self.intvls[0]) im.add(**self.intvls[1]) for i in [1000, 100]: x = self._interval_metadata_constructor_(i, im) # the upper bound is reset to seq/axis length self.assertEqual(x.interval_metadata.upper_bound, i) self.assertEqual(x.interval_metadata._intervals, im._intervals) # original interval metadata upper bound is not changed self.assertIsNone(im.upper_bound) def test_constructor_interval_bounds_larger_than_len(self): im = IntervalMetadata(None) # populate im im.add(**self.intvls[0]) im.add(**self.intvls[1]) for i in [0, 1, 3]: # error to reset upper bound to a smaller value than seq/axis len with self.assertRaisesRegex( ValueError, r"larger than upper bound \(%r\)" % i ): self._interval_metadata_constructor_(i, im) # original interval metadata upper bound is not changed self.assertIsNone(im.upper_bound) def test_constructor_interval_metadata_len_mismatch(self): for i in [0, 1, 3, 100]: with self.assertRaisesRegex( ValueError, r"\(%d\).*\(%d\)" % (self.upper_bound, i) ): self._interval_metadata_constructor_(i, self.im) def test_constructor_interval_metadata_len(self): for n in 1, 2, 3: im = IntervalMetadata(n) im.add([(0, 1)], metadata={"a": "b"}) obj = self._interval_metadata_constructor_(n, im) self.assertTrue(obj.has_interval_metadata()) self.assertIsInstance(obj.interval_metadata, IntervalMetadata) def test_constructor_interval_metadata_len_0(self): im = IntervalMetadata(0) obj = self._interval_metadata_constructor_(0, im) self.assertFalse(obj.has_interval_metadata()) def test_constructor_no_interval_metadata(self): for i, im in [(0, None), (self.upper_bound, self.im)]: obj = self._interval_metadata_constructor_(i, im) self.assertFalse(obj.has_interval_metadata()) self.assertIsInstance(obj.interval_metadata, IntervalMetadata) def test_constructor_handles_missing_interval_metadata_efficiently(self): obj = self._interval_metadata_constructor_(self.upper_bound) self.assertIsNone(obj._interval_metadata) obj = self._interval_metadata_constructor_( self.upper_bound, interval_metadata=None ) self.assertIsNone(obj._interval_metadata) def test_constructor_makes_shallow_copy_of_interval_metadata(self): intvl = self.im.add(**self.intvls[1]) obj = self._interval_metadata_constructor_(self.upper_bound, self.im) self.assertEqual(obj.interval_metadata, self.im) self.assertIsNot(obj.interval_metadata, self.im) # Changing mutable value of metadata of the old interval # also changes obj. intvl.metadata["gene"].append("b") self.assertEqual(obj.interval_metadata, self.im) # Changing old interval doesn't change obj intvl.bounds = [(3, 6)] self.assertNotEqual(obj.interval_metadata, self.im) def test_eq_basic(self): im1 = IntervalMetadata(self.upper_bound) im1.add(**self.intvls[0]) obj1 = self._interval_metadata_constructor_(self.upper_bound, im1) im2 = IntervalMetadata(self.upper_bound) im2.add(**self.intvls[0]) obj2 = self._interval_metadata_constructor_(self.upper_bound, im2) self.assertReallyEqual(obj1, obj2) def test_eq_populated_differently(self): im1 = IntervalMetadata(self.upper_bound) im1.add(**self.intvls[0]) obj1 = self._interval_metadata_constructor_(self.upper_bound, im1) obj2 = self._interval_metadata_constructor_(self.upper_bound) obj2.interval_metadata.add(**self.intvls[0]) self.assertReallyEqual(obj1, obj2) def test_eq_handles_missing_positional_metadata_efficiently(self): obj1 = self._interval_metadata_constructor_(self.upper_bound) obj2 = self._interval_metadata_constructor_(self.upper_bound) self.assertReallyEqual(obj1, obj2) self.assertIsNone(obj1._interval_metadata) self.assertIsNone(obj2._interval_metadata) def test_ne_diff_len(self): obj1 = self._interval_metadata_constructor_(0) obj2 = self._interval_metadata_constructor_(self.upper_bound) self.assertReallyNotEqual(obj1, obj2) def test_ne_only_one_is_empty(self): im1 = IntervalMetadata(self.upper_bound) im1.add(**self.intvls[0]) obj1 = self._interval_metadata_constructor_(self.upper_bound, im1) obj2 = self._interval_metadata_constructor_(self.upper_bound) self.assertReallyNotEqual(obj1, obj2) def test_ne(self): im1 = IntervalMetadata(self.upper_bound) im1.add(**self.intvls[0]) obj1 = self._interval_metadata_constructor_(self.upper_bound, im1) im2 = IntervalMetadata(self.upper_bound) im2.add(**self.intvls[1]) obj2 = self._interval_metadata_constructor_(self.upper_bound, im2) self.assertReallyNotEqual(obj1, obj2) def test_copy_interval_metadata_empty(self): obj = self._interval_metadata_constructor_(self.upper_bound, self.im) obj_copy = copy.copy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNone(obj_copy._interval_metadata) self.assertEqual(obj._interval_metadata, self.im) def test_copy_interval_metadata_none(self): obj = self._interval_metadata_constructor_(self.upper_bound) obj_copy = copy.copy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNone(obj._interval_metadata) self.assertIsNone(obj_copy._interval_metadata) def test_copy_interval_metadata(self): self.im.add(**self.intvls[1]) obj = self._interval_metadata_constructor_(self.upper_bound, self.im) obj_copy = copy.copy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNot(obj.interval_metadata, obj_copy.interval_metadata) self.assertIsNot( obj.interval_metadata._intervals, obj_copy.interval_metadata._intervals ) for i, j in zip( obj.interval_metadata._intervals, obj_copy.interval_metadata._intervals ): self.assertIsNot(i, j) self.assertIsNot(i.metadata, j.metadata) for k in i.metadata: self.assertIs(i.metadata[k], j.metadata[k]) def test_deepcopy_interval_metadata(self): self.im.add(**self.intvls[1]) obj = self._interval_metadata_constructor_(self.upper_bound, self.im) obj_copy = copy.deepcopy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNot(obj.interval_metadata, obj_copy.interval_metadata) self.assertIsNot( obj.interval_metadata._intervals, obj_copy.interval_metadata._intervals ) for i, j in zip( obj.interval_metadata._intervals, obj_copy.interval_metadata._intervals ): self.assertIsNot(i, j) self.assertIsNot(i.metadata, j.metadata) self.assertIsNot(i.metadata["gene"], j.metadata["gene"]) self.assertIs(i.metadata["product"], j.metadata["product"]) def test_deepcopy_interval_metadata_empty(self): obj = self._interval_metadata_constructor_(self.upper_bound, self.im) obj_copy = copy.deepcopy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNone(obj_copy._interval_metadata) self.assertEqual(obj._interval_metadata, self.im) def test_deepcopy_interval_metadata_none(self): obj = self._interval_metadata_constructor_(self.upper_bound, None) obj_copy = copy.deepcopy(obj) self.assertEqual(obj, obj_copy) self.assertIsNot(obj, obj_copy) self.assertIsNone(obj._interval_metadata) self.assertIsNone(obj_copy._interval_metadata) def test_deepcopy_memo_is_respected(self): # Basic test to ensure deepcopy's memo is passed through to recursive # deepcopy calls. obj = self._interval_metadata_constructor_(self.upper_bound, self.im) memo = {} copy.deepcopy(obj, memo) self.assertGreater(len(memo), 1) def test_interval_metadata_getter(self): self.im.add(**self.intvls[0]) obj = self._interval_metadata_constructor_(self.upper_bound, self.im) self.assertIsInstance(obj.interval_metadata, IntervalMetadata) self.assertEqual(self.im, obj.interval_metadata) # Update existing metadata. obj.interval_metadata._intervals[0].metadata["gene"] = "sagB" self.assertNotEqual(obj.interval_metadata, self.im) self.im._intervals[0].metadata["gene"] = "sagB" self.assertEqual(obj.interval_metadata, self.im) # Add new interval feature. obj.interval_metadata.add(**self.intvls[1]) self.im.add(**self.intvls[1]) self.assertEqual(obj.interval_metadata, self.im) def test_interval_metadata_getter_no_interval_metadata(self): obj = self._interval_metadata_constructor_(self.upper_bound) self.assertIsNone(obj._interval_metadata) self.assertIsInstance(obj.interval_metadata, IntervalMetadata) self.assertEqual(obj.interval_metadata, self.im) self.assertIsNotNone(obj._interval_metadata) def test_interval_metadata_setter(self): obj = self._interval_metadata_constructor_(self.upper_bound) self.assertFalse(obj.has_interval_metadata()) obj.interval_metadata = self.im self.assertFalse(obj.has_interval_metadata()) self.assertEqual(obj.interval_metadata, self.im) self.im.add(**self.intvls[1]) obj.interval_metadata = self.im self.assertTrue(obj.has_interval_metadata()) self.assertEqual(obj.interval_metadata, self.im) def test_interval_metadata_setter_makes_copy(self): intvl = self.im.add(**self.intvls[1]) obj = self._interval_metadata_constructor_(self.upper_bound) obj.interval_metadata = self.im self.assertEqual(obj.interval_metadata, self.im) self.assertIsNot(obj.interval_metadata, self.im) # Changing mutable value of metadata of the old interval # also changes obj. intvl.metadata["gene"].append("b") self.assertEqual(obj.interval_metadata, self.im) # Changing old interval doesn't change obj intvl.bounds = [(3, 6)] self.assertNotEqual(obj.interval_metadata, self.im) def test_interval_metadata_setter_len_mismatch(self): self.im.add(**self.intvls[1]) obj = self._interval_metadata_constructor_(self.upper_bound, self.im) for i in 0, 1, 3, 100: with self.assertRaisesRegex( ValueError, r"\(%d\).*\(%d\)" % (i, self.upper_bound) ): obj.interval_metadata = IntervalMetadata(i) self.assertEqual(obj.interval_metadata, self.im) def test_interval_metadata_setter_invalid_type(self): self.im.add(**self.intvls[0]) obj = self._interval_metadata_constructor_(self.upper_bound, self.im) for i in [2, None, "", {}, []]: with self.assertRaisesRegex( TypeError, "You must provide `IntervalMetadata` object" ): obj.interval_metadata = i self.assertEqual(self.im, obj.interval_metadata) def test_interval_metadata_setter_empty_upper_bound_is_none(self): im = IntervalMetadata(None) for i in [0, 1, 3, 100]: x = self._interval_metadata_constructor_(i) x.interval_metadata = im self.assertFalse(x.has_interval_metadata()) # the upper bound is reset to seq/axis length self.assertEqual(x.interval_metadata.upper_bound, i) # original interval metadata upper bound is not changed self.assertIsNone(im.upper_bound) def test_interval_metadata_setter_upper_bound_is_none(self): im = IntervalMetadata(None) # populate im im.add(**self.intvls[0]) im.add(**self.intvls[1]) for i in [1000, 100]: x = self._interval_metadata_constructor_(i) x.interval_metadata = im # the upper bound is reset to seq/axis length self.assertEqual(x.interval_metadata.upper_bound, i) self.assertEqual(x.interval_metadata._intervals, im._intervals) # original interval metadata upper bound is not changed self.assertIsNone(im.upper_bound) def test_interval_metadata_setter_interval_bounds_larger_than_len(self): im = IntervalMetadata(None) # populate im im.add(**self.intvls[0]) im.add(**self.intvls[1]) for i in [0, 1, 3]: # error to reset upper bound to a smaller value than seq/axis len with self.assertRaisesRegex( ValueError, r"larger than upper bound \(%r\)" % i ): x = self._interval_metadata_constructor_(i) x.interval_metadata = im # original interval metadata upper bound is not changed self.assertIsNone(im.upper_bound) def test_interval_metadata_deleter_empty(self): obj = self._interval_metadata_constructor_(self.upper_bound, self.im) del obj.interval_metadata self.assertIsNone(obj._interval_metadata) self.assertFalse(obj.has_interval_metadata()) # Delete again. test idempotent del obj.interval_metadata self.assertIsNone(obj._interval_metadata) self.assertFalse(obj.has_interval_metadata()) def test_interval_metadata_deleter(self): self.im.add(**self.intvls[0]) obj = self._interval_metadata_constructor_(self.upper_bound, self.im) del obj.interval_metadata self.assertIsNone(obj._interval_metadata) self.assertFalse(obj.has_interval_metadata()) def test_has_interval_metadata(self): obj = self._interval_metadata_constructor_(self.upper_bound) self.assertFalse(obj.has_interval_metadata()) obj = self._interval_metadata_constructor_(self.upper_bound, self.im) self.assertFalse(obj.has_interval_metadata()) self.im.add([(0, 1)]) obj = self._interval_metadata_constructor_(self.upper_bound, self.im) self.assertTrue(obj.has_interval_metadata()) scikit-bio-scikit-bio-a3beaa6/skbio/metadata/base.py000066400000000000000000000041151520735541300225270ustar00rootroot00000000000000"""Base for the metadata module.""" # ---------------------------------------------------------------------------- # Copyright (c) 2016-2023, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- SUPPORTED_COLUMN_TYPES = {"categorical", "numeric"} SUPPORTED_ID_HEADERS = { "case_insensitive": { "id", "sampleid", "sample id", "sample-id", "featureid", "feature id", "feature-id", }, # For backwards-compatibility with existing formats. "exact_match": { # QIIME 1 mapping files. "#Sample ID" was never supported, but # we're including it here for symmetry with the other supported # headers that allow a space between words. "#SampleID", "#Sample ID", # biom-format: observation metadata and "classic" (TSV) OTU tables. "#OTUID", "#OTU ID", # Qiita sample/prep information files. "sample_name", }, } FORMATTED_ID_HEADERS = "Case-insensitive: %s\n\nCase-sensitive: %s" % ( ", ".join(repr(e) for e in sorted(SUPPORTED_ID_HEADERS["case_insensitive"])), ", ".join(repr(e) for e in sorted(SUPPORTED_ID_HEADERS["exact_match"])), ) def is_id_header(name): """Determine if a name is a valid ID column header. This function may be used to determine if a value in a metadata file is a valid ID column header, or if a pandas ``Index.name`` matches the ID header requirements. The "ID header" corresponds to the ``Metadata.id_header`` and ``MetadataColumn.id_header`` properties. Parameters ---------- name : string or None Name to check against ID header requirements. Returns ------- bool ``True`` if `name` is a valid ID column header, ``False`` otherwise. """ return name and ( name in SUPPORTED_ID_HEADERS["exact_match"] or name.lower() in SUPPORTED_ID_HEADERS["case_insensitive"] ) scikit-bio-scikit-bio-a3beaa6/skbio/metadata/io.py000066400000000000000000000533521520735541300222330ustar00rootroot00000000000000"""Contains io functionality for the Metadata module.""" # ---------------------------------------------------------------------------- # Copyright (c) 2016-2023, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import csv import itertools import os.path import re import numpy as np import pandas as pd from skbio.io._fileobject import SaneTextIOWrapper from skbio.util import find_duplicates from .missing import DEFAULT_MISSING, BUILTIN_MISSING, series_encode_missing from .base import SUPPORTED_COLUMN_TYPES, FORMATTED_ID_HEADERS, is_id_header from ..metadata._metadata import SampleMetadata, MetadataColumn class MetadataFileError(Exception): """Exception for errors with Metadata files.""" _suffix = ( "There may be more errors present in the metadata file. To get a full " "report, sample/feature metadata files can be validated with Keemei: " "https://keemei.qiime2.org\n\nFind details on QIIME 2 metadata " "requirements here: https://docs.qiime2.org/" ) def __init__(self, message, include_suffix=True): """Initialize the MetadataFileError.""" # LH NOTE/TODO: in Qiime2 this linked to the specific Qiime2 release. # However since this is not Qiime2 It did break and I removed this if include_suffix: message = message + "\n\n" + self._suffix super().__init__(message) class MetadataReader: """Reader for Metadata files.""" def __init__(self, filepath_or_filehandle): """Initialize the Reader for Metadata files.""" # check if the filepath_filehandle is a path... if it is check if it # points to a file # TODO: Refine this check to be more specific if isinstance(filepath_or_filehandle, str): self._file_is_filehandle = False if not os.path.isfile(filepath_or_filehandle): raise MetadataFileError( "Metadata file path doesn't exist, or the path points to " "something other than a file. Please check that the path " "exists, has read permissions, and points to a regular file " "(not a directory): %s" % filepath_or_filehandle ) else: self._file_is_filehandle = True self._filepath = filepath_or_filehandle # Used by `read()` to store an iterator yielding rows with # leading/trailing whitespace stripped from their cells (this is a # preprocessing step that should happen with *every* row). The iterator # protocol is the only guaranteed API on this object. self._reader = None def read( self, into, column_types=None, column_missing_schemes=None, default_missing_scheme=DEFAULT_MISSING, ): """Return a Metadata object read from the given file.""" if column_types is None: column_types = {} try: # choose the appropriate context manager depending # on if a filehandle has been passed. if self._file_is_filehandle: cm = self._filepath else: # Newline settings based on recommendation from csv docs: # https://docs.python.org/3/library/csv.html#id3 # Ignore BOM on read (but do not write BOM) cm = open(self._filepath, "r", newline="", encoding="utf-8-sig") with cm as fh: tsv_reader = csv.reader(fh, dialect="excel-tab", strict=True) self._reader = (self._strip_cell_whitespace(row) for row in tsv_reader) header = self._read_header() directives = self._read_directives(header) ids, data = self._read_data(header) except UnicodeDecodeError as e: if "0xff in position 0" in str(e) or "0xfe in position 0" in str(e): raise MetadataFileError( "Metadata file must be encoded as UTF-8 or ASCII, found " "UTF-16. If this file is from Microsoft Excel, save " "as a plain text file, not 'UTF-16 Unicode'" ) raise MetadataFileError( "Metadata file must be encoded as UTF-8 or ASCII. The " "following error occurred when decoding the file:\n\n%s" % e ) finally: self._reader = None index = pd.Index(ids, name=header[0], dtype=object) df = pd.DataFrame(data, columns=header[1:], index=index, dtype=object) # TODO: move these checks over to Metadata.__init__() so that you can # pass column_types with an untyped dataframe. This would require a bit # of a refactor and doesn't buy a whole lot at the moment, hence the # TODO. for name, type in column_types.items(): if name not in df.columns: raise MetadataFileError( "Column name %r specified in `column_types` is not a " "column in the metadata file." % name ) if type not in SUPPORTED_COLUMN_TYPES: fmt_column_types = ", ".join( repr(e) for e in sorted(SUPPORTED_COLUMN_TYPES) ) raise MetadataFileError( "Column name %r specified in `column_types` has an " "unrecognized column type %r. Supported column types: %s" % (name, type, fmt_column_types) ) resolved_column_types = directives.get("types", {}) resolved_column_types.update(column_types) if column_missing_schemes is None: column_missing_schemes = {} resolved_missing = {c: default_missing_scheme for c in df.columns} resolved_missing.update(directives.get("missing", {})) resolved_missing.update(column_missing_schemes) try: # Cast each column to the appropriate dtype based on column type. df = df.apply( self._cast_column, axis="index", column_types=resolved_column_types, missing_schemes=resolved_missing, ) except MetadataFileError as e: # HACK: If an exception is raised within `DataFrame.apply`, pandas # adds an extra tuple element to `e.args`, making the original # error message difficult to read because a tuple is repr'd instead # of a string. To work around this, we catch and reraise a # MetadataFileError with the original error message. We use # `include_suffix=False` to avoid adding another suffix to the # error message we're reraising. msg = e.args[0] raise MetadataFileError(msg, include_suffix=False) try: return into( df, column_missing_schemes=resolved_missing, default_missing_scheme=default_missing_scheme, ) except Exception as e: raise MetadataFileError( "There was an issue with loading the metadata file:\n\n%s" % e ) def _read_header(self): header = None for row in self._reader: if self._is_header(row): header = row break elif self._is_comment(row): continue elif self._is_empty(row): continue elif self._is_directive(row): raise MetadataFileError( "Found directive %r while searching for header. " "Directives may only appear immediately after the header." % row[0] ) else: raise MetadataFileError( "Found unrecognized ID column name %r while searching for " "header. The first column name in the header defines the " "ID column, and must be one of these values:\n\n%s\n\n" "NOTE: Metadata files must contain tab-separated values." % (row[0], FORMATTED_ID_HEADERS) ) if header is None: raise MetadataFileError( "Failed to locate header. The metadata file may be empty, or " "consists only of comments or empty rows." ) # Trim trailing empty cells from header. data_extent = None for idx, cell in enumerate(header): if cell != "": data_extent = idx header = header[: data_extent + 1] # Basic validation to 1) fail early before processing entire file; and # 2) make some basic guarantees about the header for things in this # class that use the header as part of reading the file. column_names = set(header) if "" in column_names: raise MetadataFileError( "Found at least one column without a name in the header. Each " "column must be named." ) elif len(header) != len(column_names): duplicates = find_duplicates(header) raise MetadataFileError( "Column names must be unique. The following column names are " "duplicated: %s" % (", ".join(repr(e) for e in sorted(duplicates))) ) # Skip the first element of the header because we know it is a valid ID # header. The other column names are validated to ensure they *aren't* # valid ID headers. for column_name in header[1:]: if is_id_header(column_name): raise MetadataFileError( "Metadata column name %r conflicts with a name reserved " "for the ID column header. Reserved ID column headers:" "\n\n%s" % (column_name, FORMATTED_ID_HEADERS) ) return header def _read_directives(self, header): directives = {} for row in self._reader: directive_kind = None if not self._is_directive(row): self._reader = itertools.chain([row], self._reader) break if self._is_column_types_directive(row): directive_kind = "types" elif self._is_missing_directive(row): directive_kind = "missing" else: raise MetadataFileError( "Unrecognized directive %r. Only the #sk:types, #q2:types" " and #sk:missing, #q2:missing directives are supported at this" " time." % row[0] ) if directive_kind in directives: raise MetadataFileError( "Found duplicate directive %r. Each directive may " "only be specified a single time." % row[0] ) row = self._match_header_len(row, header) collected = {name: arg for name, arg in zip(header[1:], row[1:]) if arg} directives[directive_kind] = collected if "types" in directives: column_types = directives["types"] for column_name, column_type in column_types.items(): type_nocase = column_type.lower() if type_nocase in SUPPORTED_COLUMN_TYPES: column_types[column_name] = type_nocase else: fmt_column_types = ", ".join( repr(e) for e in sorted(SUPPORTED_COLUMN_TYPES) ) raise MetadataFileError( "Column %r has an unrecognized column type %r " "specified in its #sk:types or #q2:types directive. " "Supported column types (case-insensitive): %s" % (column_name, column_type, fmt_column_types) ) if "missing" in directives: for column_name, column_missing in directives["missing"].items(): if column_missing not in BUILTIN_MISSING: raise MetadataFileError( "Column %r has an unrecognized missing value scheme %r" " specified in its #sk:missing or #q2:missing directive." " Supported missing value schemes (case-sensitive): %s" % (column_name, column_missing, list(BUILTIN_MISSING)) ) return directives def _read_data(self, header): ids = [] data = [] for row in self._reader: if self._is_comment(row): continue elif self._is_empty(row): continue elif self._is_directive(row): raise MetadataFileError( "Found directive %r outside of the directives section of " "the file. Directives may only appear immediately after " "the header." % row[0] ) elif self._is_header(row): raise MetadataFileError( "Metadata ID %r conflicts with a name reserved for the ID " "column header. Reserved ID column headers:\n\n%s" % (row[0], FORMATTED_ID_HEADERS) ) row = self._match_header_len(row, header) ids.append(row[0]) data.append(row[1:]) return ids, data def _strip_cell_whitespace(self, row): return [cell.strip() for cell in row] def _match_header_len(self, row, header): row_len = len(row) header_len = len(header) if row_len < header_len: # Pad row with empty cells to match header length. row = row + [""] * (header_len - row_len) elif row_len > header_len: trailing_row = row[header_len:] if not self._is_empty(trailing_row): raise MetadataFileError( "Metadata row contains more cells than are declared by " "the header. The row has %d cells, while the header " "declares %d cells." % (row_len, header_len) ) row = row[:header_len] return row def _is_empty(self, row): # `all` returns True for an empty iterable, so this check works for a # row of zero elements (corresponds to a blank line in the file). return all((cell == "" for cell in row)) def _is_comment(self, row): return ( len(row) > 0 and row[0].startswith("#") and not self._is_directive(row) and not self._is_header(row) ) def _is_header(self, row): if len(row) == 0: return False return is_id_header(row[0]) def _is_directive(self, row): return len(row) > 0 and row[0].startswith(("#sk:", "#q2:")) def _is_column_types_directive(self, row): return len(row) > 0 and (row[0].split(" ")[0] in ["#sk:types", "#q2:types"]) def _is_missing_directive(self, row): return len(row) > 0 and (row[0].split(" ")[0] in ["#sk:missing", "#q2:missing"]) def _cast_column(self, series, column_types, missing_schemes): if series.name in missing_schemes: scheme = missing_schemes[series.name] series = series_encode_missing(series, scheme) if series.name in column_types: if column_types[series.name] == "numeric": return self._to_numeric(series) else: # 'categorical' return self._to_categorical(series) else: # Infer type try: return self._to_numeric(series) except MetadataFileError: return self._to_categorical(series) def _to_categorical(self, series): # Replace empty strings with `None` to force the series to remain # dtype=object (this only matters if the series consists solely of # missing data). Replacing with np.nan and casting to dtype=object # won't retain the correct dtype in the resulting dataframe # (`DataFrame.apply` seems to force series consisting solely of np.nan # to dtype=float64, even if dtype=object is specified. # # To replace a value with `None`, the following invocation of # `Series.replace` must be used because `None` is a sentinel: # https://stackoverflow.com/a/17097397/3776794 return series.replace([""], [None]) def _to_numeric(self, series): series = series.replace("", np.nan) is_numeric = series.apply(self._is_numeric) if is_numeric.all(): return pd.to_numeric(series, errors="raise") else: non_numerics = series[~is_numeric].unique() raise MetadataFileError( "Cannot convert metadata column %r to numeric. The following " "values could not be interpreted as numeric: %s" % (series.name, ", ".join(repr(e) for e in sorted(non_numerics))) ) def _is_numeric(self, value): return isinstance(value, float) or len(_numeric_regex.findall(value)) == 1 class MetadataWriter: """Writer for Metadata.""" def __init__(self, metadata): """Initialize Writer for Metadata.""" self._metadata = metadata def write(self, filepath_or_filehandle): """Write metadata object to passed file or filehandle.""" if isinstance(filepath_or_filehandle, str): # Newline settings based on recommendation from csv docs: # https://docs.python.org/3/library/csv.html#id3 # Do NOT write a BOM, hence utf-8 not utf-8-sig cm = open(filepath_or_filehandle, "w", newline="", encoding="utf-8") else: cm = filepath_or_filehandle with cm as fh: tsv_writer = csv.writer(fh, dialect="excel-tab", strict=True) md = self._metadata header = [md.id_header] # NOTE/TODO: The Metadata files written with this method # will always have the directives of type #sk: # even if a metadata file with directives of type #q2: # has been read. This can be changed in the future # however we could also decide to just stick with the sk: types. types_directive = ["#sk:types"] missing_directive = ["#sk:missing"] if isinstance(md, SampleMetadata): for name, props in md.columns.items(): header.append(name) types_directive.append(props.type) missing_directive.append(props.missing_scheme) elif isinstance(md, MetadataColumn): header.append(md.name) types_directive.append(md.type) missing_directive.append(md.missing_scheme) else: raise NotImplementedError tsv_writer.writerow(header) tsv_writer.writerow(types_directive) if self._non_default_missing(missing_directive): tsv_writer.writerow(missing_directive) df = md.to_dataframe(encode_missing=True) df.fillna("", inplace=True) # since `applymap` is going to be deprecated soon # and `map` may not work on older versions of pandas try: mapper_ = df.map except AttributeError: mapper_ = df.applymap df = mapper_(self._format) tsv_writer.writerows(df.itertuples(index=True)) def _non_default_missing(self, missing_directive): missing = missing_directive[1:] result = False for m in missing: if m != DEFAULT_MISSING: result = True break return result def _format(self, value): if isinstance(value, str): return value elif isinstance(value, float): # Use fixed precision or scientific notation as necessary (both are # roundtrippable in the metadata file format), with up to 15 digits # *total* precision (i.e. before and after the decimal point), # rounding if necessary. Trailing zeros or decimal points will not # be included in the formatted string (e.g. 42.0 will be formatted # as "42"). A precision of 15 digits is used because that is within # the 64-bit floating point spec (things get weird after that). # # Using repr() and str() each have their own predefined precision # which varies across Python versions. Using the string formatting # presentation types (e.g. %g, %f) without specifying a precision # will usually default to 6 digits past the decimal point, which # seems a little low. # # References: # # - https://stackoverflow.com/a/2440786/3776794 # - https://stackoverflow.com/a/2440708/3776794 # - https://docs.python.org/3/library/string.html# # format-specification-mini-language # - https://stackoverflow.com/a/20586479/3776794 # - https://drj11.wordpress.com/2007/07/03/python-poor-printing- # of-floating-point/ return "{0:.15g}".format(value) else: raise NotImplementedError # Credit: https://stackoverflow.com/a/4703508/3776794 _numeric_pattern = r""" ^[-+]? # optional sign (?: (?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc | (?: \d+ \.? ) # 1. 12. 123. etc 1 12 123 etc ) # followed by optional exponent part if desired (?: [Ee] [+-]? \d+ ) ?$ """ _numeric_regex = re.compile(_numeric_pattern, re.VERBOSE) scikit-bio-scikit-bio-a3beaa6/skbio/metadata/missing.py000066400000000000000000000064411520735541300232720ustar00rootroot00000000000000"""Defines Handling of different Missing classes for Metadata module.""" # ---------------------------------------------------------------------------- # Copyright (c) 2016-2023, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import pandas as pd import numpy as np from ._enan import make_nan_with_payload as _make_nan_with_payload from ._enan import get_payload_from_nan as _get_payload_from_nan def _encode_terms(namespace): enum = _MISSING_ENUMS[namespace] namespace = _NAMESPACE_LOOKUP.index(namespace) def encode(x): if not isinstance(x, str): return x try: code = enum.index(x) except ValueError: return x return _make_nan_with_payload(code, namespace=namespace) return encode def _handle_insdc_missing(series): return series.apply(_encode_terms("INSDC:missing")) def _handle_blank(series): return series def _handle_no_missing(series): if series.isna().any(): raise ValueError( "Missing values are not allowed in series/column" " (name=%r) when using scheme 'no-missing'." % series.name ) return series BUILTIN_MISSING = { "INSDC:missing": _handle_insdc_missing, "blank": _handle_blank, "no-missing": _handle_no_missing, } _MISSING_ENUMS = { "INSDC:missing": ( "not applicable", "missing", "not collected", "not provided", "restricted access", ) } # list index reflects the nan namespace, the "blank"/"no-missing" enums don't # apply here, since they aren't actually encoded in the NaNs _NAMESPACE_LOOKUP = ["INSDC:missing"] DEFAULT_MISSING = "blank" def series_encode_missing(series: pd.Series, enumeration: str) -> pd.Series: """Return encoded Missing values.""" if not isinstance(enumeration, str): TypeError("Wrong type for `enumeration`, expected string") try: encoder = BUILTIN_MISSING[enumeration] except KeyError: raise ValueError( "Unknown enumeration: %r, (available: %r)" % (enumeration, list(BUILTIN_MISSING.keys())) ) new = encoder(series) if series.dtype == object and new.isna().all(): # return to categorical of all missing values return new.astype(object) return new def series_extract_missing(series: pd.Series) -> pd.Series: """Return extracted Missing types from passed Series.""" def _decode(x): if np.issubdtype(type(x), np.floating) and np.isnan(x): code, namespace = _get_payload_from_nan(x) if namespace is None: return x elif namespace == 255: raise ValueError("Custom enumerations are not yet supported") else: try: enum = _MISSING_ENUMS[_NAMESPACE_LOOKUP[namespace]] except (IndexError, KeyError): return x try: return enum[code] except IndexError: return x return x missing = series[series.isna()] missing = missing.apply(_decode) return missing.astype(object) scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/000077500000000000000000000000001520735541300224045ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/__init__.py000066400000000000000000000005411520735541300245150ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/000077500000000000000000000000001520735541300233155ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/000077500000000000000000000000001520735541300247435ustar00rootroot00000000000000column-name-conflicts-with-id-header.tsv000066400000000000000000000001001520735541300343770ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalidsampleid col1 featureid col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/comments-and-empty-rows-only.tsv000066400000000000000000000000561520735541300331720ustar00rootroot00000000000000# # Hello, World! # Foo, # Bar, # Baz scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/data-longer-than-header.tsv000066400000000000000000000001041520735541300320470ustar00rootroot00000000000000sampleid col1 col2 col3 id1 1 a foo id2 2 b bar overflow id3 3 c 42 directive-after-directives-section.tsv000066400000000000000000000002231520735541300342750ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalidid col1 col2 col3 # directives must appear *immediately* below header #q2:types numeric categorical categorical id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/directive-before-header.tsv000066400000000000000000000001371520735541300321460ustar00rootroot00000000000000#q2:types numeric categorical categorical id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/directive-longer-than-header.tsv000066400000000000000000000001551520735541300331220ustar00rootroot00000000000000sampleid col1 col2 col3 #q2:types numeric categorical categorical numeric id1 1 a foo id2 2 b bar id3 3 c 42 duplicate-column-names-with-whitespace.tsv000066400000000000000000000000771520735541300350770ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalidid " col1 " col2 col1 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/duplicate-column-names.tsv000066400000000000000000000000651520735541300320500ustar00rootroot00000000000000id col1 col2 col1 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/duplicate-directives.tsv000066400000000000000000000002151520735541300316100ustar00rootroot00000000000000id col1 col2 col3 #q2:types numeric categorical categorical #q2:types categorical categorical categorical id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/duplicate-ids-with-whitespace.tsv000066400000000000000000000000741520735541300333340ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar "id1 " 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/duplicate-ids.tsv000066400000000000000000000000651520735541300302310ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id1 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/empty-column-name.tsv000066400000000000000000000000611520735541300310450ustar00rootroot00000000000000id col1 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/empty-file000066400000000000000000000000001520735541300267270ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/empty-id.tsv000066400000000000000000000000621520735541300272270ustar00rootroot00000000000000ID col1 col2 col3 id1 1 a foo 2 b bar id3 3 c 42 header-only-with-comments-and-empty-rows.tsv000066400000000000000000000000761520735541300353140ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid# Hello, World! id col1 col2 col3 # Foo, # Bar, # Baz scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/header-only.tsv000066400000000000000000000000221520735541300277020ustar00rootroot00000000000000id col1 col2 col3 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/id-conflicts-with-id-header.tsv000066400000000000000000000000721520735541300326470ustar00rootroot00000000000000sampleid col1 col2 col3 id1 1 a foo id 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/invalid-header.tsv000066400000000000000000000001041520735541300303500ustar00rootroot00000000000000invalid_id_header col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/missing-unknown-scheme.tsv000066400000000000000000000004061520735541300321110ustar00rootroot00000000000000id col1 col2 col3 #q2:types numeric categorical categorical #q2:missing BAD:SCHEME INSDC:missing no-missing id1 1 a foo id2 2 b bar id3 3 c 42 id4 not applicable missing anything id5 not collected not provided whatever id6 restricted access restricted access 10 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/non-utf-8.tsv000066400000000000000000000001541520735541300272340ustar00rootroot00000000000000þÿid col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/qiime1-empty.tsv000066400000000000000000000001301520735541300300140ustar00rootroot00000000000000#SampleID col1 col2 col3 # A QIIME 1 mapping file can have comments # below the header. scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/simple-utf-16be.txt000066400000000000000000000001541520735541300303240ustar00rootroot00000000000000þÿid col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/simple-utf-16le.txt000066400000000000000000000001541520735541300303360ustar00rootroot00000000000000ÿþid col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/types-directive-non-numeric.tsv000066400000000000000000000007451520735541300330570ustar00rootroot00000000000000# All sorts of strings that shouldn't be interpreted as numbers in `col2`! # Note that the first few values in `col2` *can* be interpreted as numbers, # just to have a mixed set of numeric and non-numeric values. id col1 col2 #q2:types numeric numeric id1 1 42 id2 1 -42.50 id3 1 id4 1 a id5 1 foo id6 1 1,000 id7 1 1.000.0 id8 1 $42 id9 1 nan id10 1 NaN id11 1 NA id12 1 inf id13 1 +inf id14 1 -inf id15 1 Infinity id16 1 1_000_000 id17 1 0xAF id18 1 1e3e4 id19 1 e3 id20 1 sample-1 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/unrecognized-column-type.tsv000066400000000000000000000001271520735541300324470ustar00rootroot00000000000000id col1 col2 col3 #q2:types numeric foo categorical id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/unrecognized-directive.tsv000066400000000000000000000001111520735541300321420ustar00rootroot00000000000000id col1 col2 col3 #q2:foo bar baz bar id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/whitespace-only-column-name.tsv000066400000000000000000000000701520735541300330220ustar00rootroot00000000000000id col1 " " col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/invalid/whitespace-only-id.tsv000066400000000000000000000000701520735541300312030ustar00rootroot00000000000000ID col1 col2 col3 id1 1 a foo " " 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/000077500000000000000000000000001520735541300244145ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/BOM-simple.txt000066400000000000000000000000701520735541300270560ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/all-cells-padded.tsv000066400000000000000000000000361520735541300302400ustar00rootroot00000000000000id col1 col2 col3 id1 id2 id3 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/biom-observation-metadata.tsv000066400000000000000000000001561520735541300322110ustar00rootroot00000000000000#OTUID taxonomy confidence # optional comments OTU_1 k__Bacteria;p__Firmicutes 0.890 OTU_2 k__Bacteria 0.9999 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/case-insensitive-types-directive.tsv000066400000000000000000000001361520735541300335410ustar00rootroot00000000000000id col1 col2 col3 #q2:types CATEGORICAL CategoricaL NuMeRiC id1 1 a -5 id2 2 b 0.0 id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/column-order.tsv000066400000000000000000000000541520735541300275570ustar00rootroot00000000000000id z y x id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/comments.tsv000066400000000000000000000010461520735541300270000ustar00rootroot00000000000000# pre-header # comment id col1 col2 col3 # post-header # comment id1 1 a foo id2 2 b bar # intra-data comment with another # sign # ## # comment with leading whitespace is still a comment. # comment with tab characters is also a comment! "# if the first cell is quoted, the parsing rules first process and strip double quotes, then check if the first cell begins with a pound sign" " # same rule applies if the de-quoted cell has leading whitespace (leading/trailing whitespace is *always* ignored)" id3 3 c 42 # trailing # comment scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/complete-types-directive.tsv000066400000000000000000000001431520735541300320760ustar00rootroot00000000000000id col1 col2 col3 #q2:types categorical categorical categorical id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/complete-types-directive_w_sk.tsv000066400000000000000000000001431520735541300331210ustar00rootroot00000000000000id col1 col2 col3 #sk:types categorical categorical categorical id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/empty-rows.tsv000066400000000000000000000002561520735541300273030ustar00rootroot00000000000000 id col1 col2 col3 id1 1 a foo id2 2 b bar " " "" " " " " " " id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/empty-types-directive.tsv000066400000000000000000000000771520735541300314320ustar00rootroot00000000000000id col1 col2 col3 #q2:types id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/jagged-trailing-columns.tsv000066400000000000000000000000701520735541300316550ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/jagged.tsv000066400000000000000000000000551520735541300263730ustar00rootroot00000000000000id col1 col2 col3 id1 1 a id2 2 b bar id3 3 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/leading-trailing-whitespace.tsv000066400000000000000000000006271520735541300325230ustar00rootroot00000000000000 # Leading/trailing whitespace is ignored in *any* type of cell, including # comments, empty rows, headers, directives, and data cells. # Double-quotes are always processed prior to stripping leading/trailing # whitespace within the cell. id "col1 " " col2" col3 #q2:types " numeric " categorical " categorical " id1 " 1 " a foo " " " id2 " 2 b "bar " id3 3 "c " 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/mac-line-endings.tsv000066400000000000000000000000651520735541300302650ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/minimal.tsv000066400000000000000000000000051520735541300265730ustar00rootroot00000000000000id a scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/missing-data.tsv000066400000000000000000000010041520735541300275250ustar00rootroot00000000000000# Missing data can be represented with empty cells or whitespace-only cells. # Test that values used to represent missing data in other programs # (e.g. pandas) are not treated as missing (e.g. "NA", "N/A"). Also test # columns that consist solely of missing data. By default, an empty column will # be treated as numeric data (column "NA" in this example). "col4" overrides # this behavior to make its empty column categorical. id col1 NA col3 col4 #q2:types categorical None 1 null nan N/A NA " " NA scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/missing-insdc-no-directive.tsv000066400000000000000000000002541520735541300323100ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 id4 not applicable missing anything id5 not collected not provided whatever id6 restricted access restricted access 10 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/missing-insdc.tsv000066400000000000000000000004111520735541300277150ustar00rootroot00000000000000id col1 col2 col3 #q2:types numeric categorical categorical #q2:missing INSDC:missing INSDC:missing no-missing id1 1 a foo id2 2 b bar id3 3 c 42 id4 not applicable missing anything id5 not collected not provided whatever id6 restricted access restricted access 10 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/no-columns.tsv000066400000000000000000000000151520735541300272400ustar00rootroot00000000000000id a b my-id scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/no-id-or-column-name-type-cast.tsv000066400000000000000000000001101520735541300327060ustar00rootroot00000000000000id 42.0 1000 -4.2 0.000001 2 b 2.5 0.004000 1 b 4.2 0.000000 3 c -9.999 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/no-newline-at-eof.tsv000066400000000000000000000000641520735541300303760ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/non-standard-characters.tsv000066400000000000000000000013731520735541300316630ustar00rootroot00000000000000# See the corresponding unit test case for the goals of this file. The file # tests the following cases for IDs, column names, and cells. Many of the # choices are based on use-cases/bugs reported on the forum, Slack, etc. # # - Unicode characters # - Parentheses, underscores, less than (<), and greater than (>) # - Single and double quotes. Double quotes must be escaped according to the # Excel TSV dialect's double quote escaping rules. # - Escaped newlines (\n), carriage returns (\r), tabs (\t), and spaces # - Inline comment characters aren't treated as comments id ↩c@l1â„¢ col(#2) #col'3 """""" "col 5" ©id##1 Æ’oo (foo) #f o #o "fo o" ((id))2 ''2'' b#r "ba r" 'id_3<>' "b""ar" "c d" "4 2" """id#4""" b__a_z <42> >42 "i d 5" baz 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/numeric-column.tsv000066400000000000000000000001571520735541300301120ustar00rootroot00000000000000id col1 id1 0 id2 2.0 id3 0.00030 id4 -4.2 id5 1e-4 id6 1e4 id7 +1.5E+2 id8 id9 1. id10 .5 id11 1e-08 id12 -0 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/override-insdc.tsv000066400000000000000000000001371520735541300300700ustar00rootroot00000000000000id col1 #q2:missing no-missing id1 collected id2 not collected id3 not collected id4 collected scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/partial-types-directive.tsv000066400000000000000000000001131520735541300317170ustar00rootroot00000000000000id col1 col2 col3 #q2:types categorical id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/qiime1.tsv000066400000000000000000000001731520735541300263400ustar00rootroot00000000000000#SampleID col1 col2 col3 # A QIIME 1 mapping file can have comments # below the header. id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/qiita-preparation-information.tsv000066400000000000000000000001541520735541300331260ustar00rootroot00000000000000sample_name BARCODE EXPERIMENT_DESIGN_DESCRIPTION id.1 ACGT longitudinal study id.2 TGCA longitudinal study scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/qiita-sample-information.tsv000066400000000000000000000001321520735541300320570ustar00rootroot00000000000000sample_name DESCRIPTION TITLE id.1 description 1 A Title id.2 description 2 Another Title scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/recommended-ids.tsv000066400000000000000000000000731520735541300302110ustar00rootroot00000000000000id col1 c6ca034a-223f-40b4-a0e0-45942912a5ea foo My.ID bar scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/rows-shorter-than-header.tsv000066400000000000000000000000441520735541300320040ustar00rootroot00000000000000id col1 col2 col3 id1 1 a id2 2 id3 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/simple-with-directive.tsv000066400000000000000000000001371520735541300313710ustar00rootroot00000000000000id col1 col2 col3 #q2:types numeric categorical categorical id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/simple.tsv000066400000000000000000000000651520735541300264440ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/simple.txt000066400000000000000000000000651520735541300264470ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/single-column.tsv000066400000000000000000000000321520735541300277210ustar00rootroot00000000000000id col1 id1 1 id2 2 id3 3 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/single-id.tsv000066400000000000000000000000361520735541300270240ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/trailing-columns.tsv000066400000000000000000000000751520735541300304430ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/unix-line-endings.tsv000066400000000000000000000000651520735541300305100ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/data/valid/windows-line-endings.tsv000066400000000000000000000000711520735541300312140ustar00rootroot00000000000000id col1 col2 col3 id1 1 a foo id2 2 b bar id3 3 c 42 scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/test_enan.py000066400000000000000000000025341520735541300247420ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2016-2023, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import unittest from skbio.metadata._enan import get_payload_from_nan, make_nan_with_payload class TestNanPayloads(unittest.TestCase): def test_normal_nan(self): normal_nan = float('nan') payload, namespace = get_payload_from_nan(normal_nan) self.assertIs(payload, None) self.assertIs(namespace, None) def test_roundtrip_payload(self): for namespace in range(0, 256): for payload in range(-50, 500): nan = make_nan_with_payload(payload, namespace) new_payload, new_namespace = get_payload_from_nan(nan) self.assertEqual(namespace, new_namespace) self.assertEqual(payload, new_payload) self.assertNotEqual(nan, nan) def test_user_namespace_default(self): nan = make_nan_with_payload(42) payload, namespace = get_payload_from_nan(nan) self.assertEqual(42, payload) self.assertEqual(255, namespace) self.assertNotEqual(nan, nan) scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/test_intersection.py000066400000000000000000000177741520735541300265430ustar00rootroot00000000000000# checklist.py:CopyrightHeadersValidator IGNORE # ---------------------------------------------------------------------------- # This code is taken from bx-python project and added with a test for a new # function `update` from line 195 to 211. The license for this code is # included in licenses/bx_python.txt. # ---------------------------------------------------------------------------- import sys import unittest import random from skbio.metadata._intersection import IntervalObj from skbio.metadata._intersection import IntervalNode from skbio.metadata._intersection import IntervalTree # Note: More bounds checking on input parameters are performed # within test_interval.py class NeighborTestCase(unittest.TestCase): def setUp(self): iv = IntervalNode(50, 59, IntervalObj(50, 59)) for i in range(0, 110, 10): if i == 50: continue f = IntervalObj(i, i + 9) iv = iv.insert(f.start, f.end, f) self.intervals = iv def test_left(self): iv = self.intervals self.assertEqual(str(iv.left(60, n=2)), str([IntervalObj(50, 59), IntervalObj(40, 49)])) for i in range(10, 100, 10): r = iv.left(i, max_dist=10, n=1) self.assertEqual(r[0].end, i - 1) def test_toomany(self): iv = self.intervals self.assertEqual(len(iv.left(60, n=200)), 6) def test_right(self): iv = self.intervals self.assertEqual(str(iv.left(60, n=2)), str([IntervalObj(50, 59), IntervalObj(40, 49)])) def get_right_start(b10): r = iv.right(b10+1, n=1) assert len(r) == 1 return r[0].start for i in range(10, 100, 10): self.assertEqual(get_right_start(i), i + 10) for i in range(0, 100, 10): r = iv.right(i-1, max_dist=10, n=1) self.assertEqual(r[0].start, i) class UpDownStreamTestCase(unittest.TestCase): def setUp(self): iv = IntervalTree() iv.add_interval(IntervalObj(50, 59)) for i in range(0, 110, 10): if i == 50: continue f = IntervalObj(i, i + 9) iv.add_interval(f) self.intervals = iv def test_upstream(self): iv = self.intervals upstreams = iv.upstream_of_interval(IntervalObj(59, 60), num_intervals=200) for u in upstreams: self.assertTrue(u.end < 59) upstreams = iv.upstream_of_interval(IntervalObj(60, 70, strand=-1), num_intervals=200) for u in upstreams: self.assertTrue(u.start > 70) upstreams = iv.upstream_of_interval(IntervalObj(58, 58, strand=-1), num_intervals=200) for u in upstreams: self.assertTrue(u.start > 59) def test_downstream(self): iv = self.intervals downstreams = iv.downstream_of_interval(IntervalObj(59, 60), num_intervals=200) for d in downstreams: self.assertTrue(d.start > 60) downstreams = iv.downstream_of_interval(IntervalObj(59, 60, strand=-1), num_intervals=200) for d in downstreams: self.assertTrue(d.start < 59) def test_n(self): iv = self.intervals for i in range(0, 90, 10): r = iv.after(i, max_dist=20, num_intervals=2) self.assertEqual(r[0].start, i + 10) self.assertEqual(r[1].start, i + 20) r = iv.after_interval(IntervalObj(i, i), max_dist=20, num_intervals=2) self.assertEqual(r[0].start, i + 10) self.assertEqual(r[1].start, i + 20) class LotsaTestCase(unittest.TestCase): """ put lotsa data in the tree and make sure it works""" def setUp(self): iv = IntervalNode(1, 2, IntervalObj(1, 2)) self.max = 1000000 for i in range(0, self.max, 10): f = IntervalObj(i, i) iv = iv.insert(f.start, f.end, f) for i in range(600): iv = iv.insert(0, 1, IntervalObj(0, 1)) self.intervals = iv def test_count(self): iv = self.intervals r = iv.right(1, n=33) self.assertEqual(len(r), 33) left = iv.left(1, n=33) self.assertEqual(len(left), 1) u = iv.right(1, n=9999) self.assertEqual(len(u), 250) # now increase max_dist u = iv.right(1, n=9999, max_dist=99999) self.assertEqual(len(u), 9999) def test_max_dist(self): iv = self.intervals r = iv.right(1, max_dist=0, n=10) self.assertEqual(len(r), 0) for n, d in enumerate(range(10, 1000, 10)): r = iv.right(1, max_dist=d, n=10000) self.assertEqual(len(r), n + 1) def test_find(self): iv = self.intervals path = sys.path[:] sys.path = sys.path[2:] sys.path = path for t in range(25): start = random.randint(0, self.max - 10000) end = start + random.randint(100, 10000) results = iv.find(start, end) for feat in results: self.assertTrue( (feat.end >= start and feat.end <= end) or (feat.start <= end and feat.start >= start)) class IntervalTreeTest(unittest.TestCase): def setUp(self): iv = IntervalTree() n = 0 for i in range(1, 1000, 80): iv.insert(i, i + 10, dict(value=i*i)) # add is synonym for insert. iv.add(i + 20, i + 30, dict(astr=str(i*i))) # or insert/add an interval object with start, end attrs. iv.insert_interval(IntervalObj(i + 40, i + 50, value=dict(astr=str(i*i)))) iv.add_interval(IntervalObj(i + 60, i + 70, value=dict(astr=str(i*i)))) n += 4 self.intervals = self.iv = iv self.nintervals = n def test_find(self): r = self.iv.find(100, 200) self.assertEqual(len(r), 5) def test_edge_cases(self): iv = IntervalTree() iv.insert(1, 1, 'foo') iv.insert(3, 7, 'spam') iv.insert(8, 8, 'abc') self.assertEqual(iv.find(0, 1), []) self.assertEqual(iv.find(1, 1), ['foo']) self.assertEqual(iv.find(1, 2), ['foo']) self.assertEqual(iv.find(2, 3), []) self.assertEqual(iv.find(3, 3), ['spam']) self.assertEqual(iv.find(3, 4), ['spam']) self.assertEqual(iv.find(6, 7), ['spam']) self.assertEqual(iv.find(7, 7), []) self.assertEqual(iv.find(0, 8), ['foo', 'spam']) self.assertEqual(iv.find(8, 8), ['abc']) self.assertEqual(iv.find(8, 9), ['abc']) self.assertEqual(iv.find(9, 9), []) self.assertEqual(iv.find(0, 10), ['foo', 'spam', 'abc']) self.assertEqual(iv.find(6, 10), ['spam', 'abc']) self.assertEqual(iv.find(7, 9), ['abc']) def test_traverse(self): a = [] fn = a.append self.iv.traverse(fn) self.assertEqual(len(a), self.nintervals) def test_empty(self): iv = IntervalTree() self.assertEqual([], iv.find(100, 300)) self.assertEqual([], iv.after(100)) self.assertEqual([], iv.before(100)) self.assertEqual([], iv.after_interval(100)) self.assertEqual([], iv.before_interval(100)) self.assertEqual([], iv.upstream_of_interval(100)) self.assertEqual([], iv.downstream_of_interval(100)) self.assertEqual(None, iv.traverse(lambda x: x.append(1))) def test_public_interval(self): self.iv.traverse(lambda ival: self.assertTrue(ival.interval)) def test_update(self): i = 1 self.iv.update(i, i + 10, dict(value=i*i), dict(value=-1)) self.assertEqual([dict(value=-1)], self.iv.find(i, i+10)) if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/test_interval.py000066400000000000000000000772251520735541300256560ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from copy import deepcopy, copy from skbio.metadata._interval import (_assert_valid_bound, _assert_valid_fuzzy) from skbio.metadata import Interval from skbio.metadata import IntervalMetadata from skbio.metadata._intersection import IntervalTree from skbio.util._testing import ReallyEqualMixin class TestInterval(unittest.TestCase, ReallyEqualMixin): def setUp(self): self.upper_bound = 100 self.im = IntervalMetadata(self.upper_bound) def test_init_default(self): f = Interval(self.im, bounds=[(0, 2), (4, self.upper_bound)]) self.assertTrue(f._interval_metadata is not None) self.assertListEqual(f.bounds, [(0, 2), (4, self.upper_bound)]) self.assertListEqual(f.fuzzy, [(False, False), (False, False)]) self.assertDictEqual(f.metadata, {}) def test_init(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) self.assertTrue(f._interval_metadata is not None) self.assertListEqual(f.bounds, [(1, 2), (4, 7)]) self.assertListEqual(f.fuzzy, [(True, False), (False, False)]) self.assertDictEqual(f.metadata, {'name': 'sagA', 'function': 'transport'}) def test_init_iterables(self): f = Interval(interval_metadata=self.im, bounds=((1, 2), (4, 7)), fuzzy=((True, False), (False, False)), metadata={'name': 'sagA', 'function': 'transport'}) self.assertTrue(f._interval_metadata is not None) self.assertListEqual(f.bounds, [(1, 2), (4, 7)]) self.assertListEqual(f.fuzzy, [(True, False), (False, False)]) self.assertDictEqual(f.metadata, {'name': 'sagA', 'function': 'transport'}) def test_init_generator(self): def gen(): for x in [(1, 2), (4, 7)]: yield x f = Interval(interval_metadata=self.im, bounds=gen(), fuzzy=((True, False), (False, False)), metadata={'name': 'sagA', 'function': 'transport'}) self.assertTrue(f._interval_metadata is not None) self.assertListEqual(f.bounds, [(1, 2), (4, 7)]) self.assertListEqual(f.fuzzy, [(True, False), (False, False)]) self.assertDictEqual(f.metadata, {'name': 'sagA', 'function': 'transport'}) def test_init_bounds_scrambled(self): f = Interval(interval_metadata=self.im, bounds=[(4, 7), (1, 2)], fuzzy=[(True, False), (False, True)], metadata={'name': 'sagA', 'function': 'transport'}) self.assertTrue(f._interval_metadata is not None) self.assertListEqual(f.bounds, [(1, 2), (4, 7)]) self.assertListEqual(f.fuzzy, [(False, True), (True, False)]) self.assertDictEqual(f.metadata, {'name': 'sagA', 'function': 'transport'}) def test_init_no_interval_metadata(self): with self.assertRaises(TypeError): Interval(interval_metadata=None, bounds=[(4, 7)], metadata={'name': 'sagA', 'function': 'transport'}) def test_init_empty_metadata(self): for i in 0, 1: # test that no exception is raised Interval(interval_metadata=self.im, bounds=[(i, i)]) def test_init_out_of_bounds(self): with self.assertRaises(ValueError): Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 101)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) with self.assertRaises(ValueError): Interval(interval_metadata=self.im, bounds=[(-1, 2), (4, 6)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) def test_init_bad_bounds(self): with self.assertRaises(TypeError): Interval(interval_metadata=self.im, bounds=[1, (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) def test_init_bad_fuzzy(self): with self.assertRaises(ValueError): Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(False, False)], metadata={'name': 'sagA', 'function': 'transport'}) def test_repr(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2)], metadata={'name': 'sagA'}) exp = (r"Interval\(interval_metadata=<[0-9]+>, bounds=\[\(1, 2\)\]," r" fuzzy=\[\(False, False\)\], metadata={'name': 'sagA'}\)") obs = repr(f) self.assertRegex(obs, exp) # test for dropped f.drop() exp = (r"Interval\(dropped=True, bounds=\[\(1, 2\)\]," r" fuzzy=\[\(False, False\)\], metadata={'name': 'sagA'}\)") obs = repr(f) self.assertRegex(obs, exp) def test_drop(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2)], metadata={'name': 'sagA'}) f.drop() self.assertTrue(f._interval_metadata is None) self.assertTrue(f.dropped) self.assertTrue(f.bounds, [(1, 2)]) self.assertTrue(f.metadata, {'name': 'sagA'}) # test the idempotence f.drop() self.assertTrue(f._interval_metadata is None) self.assertTrue(f.dropped) self.assertTrue(f.bounds, [(1, 2)]) self.assertTrue(f.metadata, {'name': 'sagA'}) def test_eq(self): f0 = Interval(interval_metadata=self.im, bounds=[(4, 7), (1, 2)], fuzzy=[(False, False), (True, False)], metadata={'name': 'sagA', 'function': 'transport'}) f1 = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) f2 = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) f3 = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, True), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) f4 = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 8)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) f5 = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagB', 'function': 'transport'}) # scramble bounds/fuzzy self.assertReallyEqual(f0, f1) self.assertReallyEqual(f2, f1) # diff fuzzy self.assertReallyNotEqual(f1, f3) # diff bounds self.assertReallyNotEqual(f1, f4) # diff metadata self.assertReallyNotEqual(f1, f5) def test_get_bounds(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) self.assertEqual(f.bounds, [(1, 2), (4, 7)]) self.assertEqual(self.im._is_stale_tree, True) def test_set_bounds(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) f.bounds = [(4, 7), (1, 3)] self.assertEqual(f.bounds, [(1, 3), (4, 7)]) self.assertEqual(f.fuzzy, [(False, False), (False, False)]) self.assertEqual(self.im._is_stale_tree, True) def test_set_bounds_bad(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) for value in [1, 's']: with self.assertRaises(TypeError): f.bounds = value for value in [[(-1, 2)], # start < lower_bound [(1, 101)], # end > upper_bound [(3, 1)], # start < end [('s', 1)], (), None]: # invalid values with self.assertRaises(ValueError): f.bounds = value def test_get_fuzzy(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) self.assertEqual(f.fuzzy, [(True, False), (False, False)]) def test_set_fuzzy(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) f.fuzzy = [(False, False), (False, False)] self.assertEqual(f.fuzzy, [(False, False), (False, False)]) def test_set_fuzzy_bad(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) for value in [[(False, False)], (), None]: with self.assertRaises(ValueError): f.fuzzy = value for value in [1, True]: with self.assertRaises(TypeError): f.fuzzy = value def test_delete_fuzzy(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) del f.fuzzy self.assertEqual(f.fuzzy, [(False, False), (False, False)]) # delete again del f.fuzzy self.assertEqual(f.fuzzy, [(False, False), (False, False)]) def test_get_metadata(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) f.metadata['name'] = 'sagB' self.assertEqual(f.metadata, {'name': 'sagB', 'function': 'transport'}) def test_set_metadata(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) f.metadata = {'name': 'sagB', 'function': 'transport'} self.assertDictEqual(f.metadata, {'name': 'sagB', 'function': 'transport'}) f.metadata = {} self.assertDictEqual(f.metadata, {}) def test_set_metadata_bad(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) for value in [1, '', None]: with self.assertRaises(TypeError): f.metadata = value def test_delete_metadata(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2), (4, 7)], fuzzy=[(True, False), (False, False)], metadata={'name': 'sagA', 'function': 'transport'}) del f.metadata self.assertEqual(f.metadata, {}) def test_set_delete_on_dropped(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2)], fuzzy=[(True, False)], metadata={'name': 'sagA'}) f.drop() with self.assertRaises(RuntimeError): f.fuzzy = None with self.assertRaises(RuntimeError): f.bounds = [(1, 2)] with self.assertRaises(RuntimeError): f.metadata = {} with self.assertRaises(RuntimeError): del f.fuzzy with self.assertRaises(RuntimeError): del f.metadata def test_get_on_dropped(self): f = Interval(interval_metadata=self.im, bounds=[(1, 2)], fuzzy=[(True, False)], metadata={'name': 'sagA'}) f.drop() self.assertEqual(f.fuzzy, [(True, False)]) self.assertEqual(f.bounds, [(1, 2)]) self.assertEqual(f.metadata, {'name': 'sagA'}) class TestIntervalUtil(unittest.TestCase): def test_assert_valid_bound(self): intvls = [(1, 2), (-1, 2)] for intvl in intvls: try: _assert_valid_bound(intvl) except TypeError: self.assertTrue(False) def test_assert_valid_bound_wrong_type(self): intvls = [[1, 2], 1, [1, 2, 3]] for intvl in intvls: with self.assertRaises(TypeError): _assert_valid_bound(intvl) def test_assert_valid_bound_wrong_value(self): intvls = [(1, 2, 3), (2, 1), (True, 0), ('s', 'r')] for intvl in intvls: with self.assertRaises(ValueError): _assert_valid_bound(intvl) def test_assert_valid_fuzzy(self): fuzzy = [(True, False), (True, True)] for fuzzy in fuzzy: try: _assert_valid_fuzzy(fuzzy) except Exception: self.assertTrue(False) def test_assert_valid_fuzzy_wrong_value(self): fuzzy = [(True, False, True), ()] for fuzzy in fuzzy: with self.assertRaises(ValueError): _assert_valid_fuzzy(fuzzy) def test_assert_valid_fuzzy_wrong_type(self): fuzzy = [[True, False], 's', 1, (0, 1), ('s', '')] for fuzzy in fuzzy: with self.assertRaises(TypeError): _assert_valid_fuzzy(fuzzy) class TestIntervalMetadata(unittest.TestCase, ReallyEqualMixin): def setUp(self): self.upper_bound = 10 self.im_empty = IntervalMetadata(self.upper_bound) self.im_1 = IntervalMetadata(self.upper_bound) self.im_1_1 = Interval( interval_metadata=self.im_1, bounds=[(1, 2), (4, self.upper_bound)], metadata={'gene': 'sagA', 'bound': 0}) self.im_2 = IntervalMetadata(self.upper_bound) self.im_2_1 = Interval( interval_metadata=self.im_2, bounds=[(1, 2), (4, self.upper_bound)], metadata={'gene': 'sagA', 'bound': 0}) self.im_2_2 = Interval( interval_metadata=self.im_2, bounds=[(3, 5)], metadata={'gene': 'sagB', 'bound': 0, 'spam': [0]}) def test_copy_empty(self): obs = copy(self.im_empty) self.assertEqual(obs, self.im_empty) self.assertIsNot(obs._intervals, self.im_empty._intervals) self.assertIsNot(obs._interval_tree, self.im_empty._interval_tree) def test_copy(self): obs = copy(self.im_2) self.assertEqual(obs, self.im_2) self.assertIsNot(obs._intervals, self.im_2._intervals) self.assertIsNot(obs._interval_tree, self.im_2._interval_tree) for i in range(self.im_2.num_interval_features): i1, i2 = obs._intervals[i], self.im_2._intervals[i] self.assertIsNot(i1, i2) self.assertIsNot(i1.bounds, i2.bounds) self.assertIsNot(i1.fuzzy, i2.fuzzy) self.assertIsNot(i1._interval_metadata, i2._interval_metadata) self.assertIsNot(i1.metadata, i2.metadata) for k in i1.metadata: self.assertIs(i1.metadata[k], i2.metadata[k]) def test_deepcopy(self): obs = deepcopy(self.im_2) self.assertEqual(obs, self.im_2) self.assertIsNot(obs._intervals, self.im_2._intervals) self.assertIsNot(obs._interval_tree, self.im_2._interval_tree) for i in range(self.im_2.num_interval_features): i1, i2 = obs._intervals[i], self.im_2._intervals[i] self.assertIsNot(i1, i2) self.assertIsNot(i1.bounds, i2.bounds) self.assertIsNot(i1.fuzzy, i2.fuzzy) self.assertIsNot(i1.metadata, i2.metadata) i2.metadata['spam'].append(1) self.assertEqual(i2.metadata, {'gene': 'sagB', 'bound': 0, 'spam': [0, 1]}) self.assertEqual(i1.metadata, {'gene': 'sagB', 'bound': 0, 'spam': [0]}) def test_deepcopy_memo_is_respected(self): memo = {} deepcopy(self.im_1, memo) self.assertGreater(len(memo), 2) def test_init(self): self.assertFalse(self.im_empty._is_stale_tree) self.assertEqual(self.im_empty._intervals, []) def test_init_upper_bound_lt_lower_bound(self): # test that no exception is raised IntervalMetadata(0) with self.assertRaises(ValueError): IntervalMetadata(-1) def test_upper_bound_is_none(self): im = IntervalMetadata(None) # should not raise error im.add([(0, 1000000000)]) self.assertIsNone(im.upper_bound) with self.assertRaisesRegex( TypeError, r'upper bound is `None`'): im._reverse() with self.assertRaisesRegex( TypeError, r'upper bound is `None`'): IntervalMetadata.concat([self.im_1, im]) def test_init_copy_from(self): for i in [None, 99, 999]: obs = IntervalMetadata(i, self.im_1) exp = IntervalMetadata(i) exp.add(bounds=[(1, 2), (4, self.upper_bound)], metadata={'gene': 'sagA', 'bound': 0}) self.assertEqual(obs, exp) def test_init_copy_from_empty(self): for i in [None, 0, 9, 99, 999]: obs = IntervalMetadata(i, self.im_empty) exp = IntervalMetadata(i) self.assertEqual(obs, exp) # test it is shallow copy self.assertIsNot(obs._intervals, self.im_empty._intervals) self.assertIsNot(obs._interval_tree, self.im_empty._interval_tree) def test_init_copy_from_shallow_copy(self): obs = IntervalMetadata(self.upper_bound, self.im_2) self.assertEqual(self.im_2, obs) # test it is shallow copy self.assertIsNot(obs._intervals, self.im_2._intervals) self.assertIsNot(obs._interval_tree, self.im_2._interval_tree) for i in range(self.im_2.num_interval_features): i1, i2 = obs._intervals[i], self.im_2._intervals[i] self.assertIsNot(i1, i2) self.assertIsNot(i1.bounds, i2.bounds) self.assertIsNot(i1.fuzzy, i2.fuzzy) self.assertIsNot(i1._interval_metadata, i2._interval_metadata) self.assertIsNot(i1.metadata, i2.metadata) for k in i1.metadata: self.assertIs(i1.metadata[k], i2.metadata[k]) def test_init_copy_from_error(self): i = self.upper_bound - 1 with self.assertRaisesRegex( ValueError, r'larger than upper bound \(%r\)' % i): IntervalMetadata(i, self.im_2) def test_num_interval_features(self): self.assertEqual(self.im_empty.num_interval_features, 0) self.assertEqual(self.im_1.num_interval_features, 1) self.assertEqual(self.im_2.num_interval_features, 2) def test_duplicate(self): '''Test query and drop methods on duplicate Intervals.''' intvl_1 = self.im_empty.add([(1, 2)]) intvl_2 = self.im_empty.add([(1, 2)]) self.assertEqual(len(list(self.im_empty.query([(1, 2)]))), 2) self.im_empty.drop([intvl_1]) self.assertEqual(len(self.im_empty._intervals), 1) self.assertTrue(self.im_empty._intervals[0] is intvl_2) def test_duplicate_bounds(self): intvl = self.im_empty.add([(1, 2), (1, 2)]) intvls = list(self.im_empty.query([(1, 2)])) self.assertEqual(len(intvls), 1) self.assertTrue(intvl is intvls[0]) def test_concat_empty(self): for i in 0, 1, 2: obs = IntervalMetadata.concat([self.im_empty] * i) exp = IntervalMetadata(self.upper_bound * i) self.assertEqual(obs, exp) obs = IntervalMetadata.concat([]) self.assertEqual(obs, IntervalMetadata(0)) def test_concat(self): im1 = IntervalMetadata(3) im2 = IntervalMetadata(4) im3 = IntervalMetadata(5) im1.add([(0, 2)], [(True, True)]) im2.add([(0, 3)], [(True, False)], {'gene': 'sagA'}) im2.add([(2, 4)], metadata={'gene': 'sagB'}) im3.add([(1, 5)], [(False, True)], {'gene': 'sagC'}) obs = IntervalMetadata.concat([im1, im2, im3]) exp = IntervalMetadata(12) exp.add(bounds=[(0, 2)], fuzzy=[(True, True)]) exp.add(bounds=[(3, 6)], fuzzy=[(True, False)], metadata={'gene': 'sagA'}) exp.add(bounds=[(5, 7)], metadata={'gene': 'sagB'}) exp.add(bounds=[(8, 12)], fuzzy=[(False, True)], metadata={'gene': 'sagC'}) self.assertEqual(obs, exp) def test_merge(self): # empty + empty im = IntervalMetadata(self.upper_bound) self.im_empty.merge(im) self.assertEqual(self.im_empty, im) # empty + non-empty self.im_empty.merge(self.im_1) self.assertEqual(self.im_empty, self.im_1) # non-empty + non-empty self.im_empty.merge(self.im_2) self.im_2.merge(self.im_1) self.assertEqual(self.im_empty, self.im_2) def test_merge_unequal_upper_bounds(self): n = 3 im1 = IntervalMetadata(n) for im in [self.im_empty, self.im_1]: with self.assertRaisesRegex( ValueError, r'not equal \(%d != %d\)' % (self.upper_bound, n)): im.merge(im1) def test_merge_to_unbounded(self): for im in [self.im_empty, self.im_1, IntervalMetadata(None)]: obs = IntervalMetadata(None) obs.merge(im) self.assertIsNone(obs.upper_bound) self.assertEqual(obs._intervals, im._intervals) def test_merge_unbounded_to_bounded(self): im = IntervalMetadata(None) with self.assertRaisesRegex( ValueError, r'Cannot merge an unbound IntervalMetadata object ' 'to a bounded one'): self.im_1.merge(im) # original im is not changed self.assertIsNone(im.upper_bound) self.assertEqual(im._intervals, []) def test_sort(self): interval = Interval( self.im_2, [(1, 2), (3, 8)], metadata={'gene': 'sagA', 'bound': 0}) im = deepcopy(self.im_2) self.im_2.sort(False) # check sorting does not have other side effects self.assertEqual(im, self.im_2) self.assertEqual(self.im_2._intervals, [self.im_2_2, self.im_2_1, interval]) self.im_2.sort() self.assertEqual(im, self.im_2) self.assertEqual(self.im_2._intervals, [interval, self.im_2_1, self.im_2_2]) self.im_empty.sort() self.assertEqual(self.im_empty, IntervalMetadata(self.upper_bound)) def test_add_eq_upper_bound(self): self.im_empty.add(bounds=[(1, 2), (4, self.upper_bound)], metadata={'gene': 'sagA', 'bound': 0}) self.assertTrue(self.im_empty._is_stale_tree) interval = self.im_empty._intervals[0] self.assertEqual(interval.bounds, [(1, 2), (4, self.upper_bound)]) self.assertEqual(interval.metadata, {'gene': 'sagA', 'bound': 0}) self.assertTrue(isinstance(self.im_empty._interval_tree, IntervalTree)) def test_add_gt_upper_bound(self): with self.assertRaises(ValueError): self.im_empty.add(bounds=[(1, 2), (4, self.upper_bound+1)], metadata={'gene': 'sagA', 'bound': 0}) def test_add_eq_start_end_bound(self): for i in 0, 1, self.upper_bound: # test that no exception is raised self.im_empty.add(bounds=[(i, i)], metadata={'gene': 'sagA', 'bound': 0}) def test_query_attribute(self): intervals = self.im_2._query_attribute({}) for i, j in zip(intervals, self.im_2._intervals): self.assertEqual(i, j) intervals = list(self.im_2._query_attribute(None)) self.assertEqual(len(intervals), 0) for i in self.im_2._intervals: intervals = list(self.im_2._query_attribute(i.metadata)) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0], i) def test_query_interval(self): intervals = list(self.im_2._query_interval((1, 2))) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0], self.im_2_1) intervals = list(self.im_2._query_interval((3, 4))) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0], self.im_2_2) intervals = {repr(i) for i in self.im_2._query_interval((1, 7))} self.assertEqual(len(intervals), 2) self.assertSetEqual(intervals, {repr(i) for i in self.im_2._intervals}) def test_query_interval_upper_bound(self): intervals = list(self.im_2._query_interval((self.upper_bound-1, self.upper_bound))) self.assertEqual(intervals, [self.im_2_1]) def test_query(self): intervals = list(self.im_2.query(bounds=[(1, 5)], metadata={'gene': 'sagA'})) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0], self.im_2_1) def test_query_empty(self): intervals = list(self.im_1.query()) self.assertEqual(len(intervals), 1) def test_query_no_hits(self): intervals = list(self.im_2.query(bounds=[(self.upper_bound, 200)])) self.assertEqual(len(intervals), 0) intervals = list(self.im_2.query(metadata={'gene': 'sagC'})) self.assertEqual(len(intervals), 0) intervals = list(self.im_2.query(bounds=[(1, 2)], metadata={'gene': 'sagC'})) self.assertEqual(len(intervals), 0) def test_query_interval_only(self): for loc in [[(1, 7)], [(1, 2), (3, 4)]]: intervals = list(self.im_2.query(bounds=loc)) self.assertEqual(len(intervals), 2) self.assertEqual(intervals[0], self.im_2_1) self.assertEqual(intervals[1], self.im_2_2) def test_query_metadata_only(self): intervals = list(self.im_2.query(metadata={'gene': 'sagB'})) self.assertEqual(len(intervals), 1) self.assertEqual(intervals[0], self.im_2_2) intervals = list(self.im_2.query(metadata={'bound': 0})) self.assertEqual(len(intervals), 2) self.assertEqual(intervals[0], self.im_2_1) self.assertEqual(intervals[1], self.im_2_2) def test_drop(self): intvl = self.im_2._intervals[0] self.im_2.drop([intvl]) self.assertEqual(len(self.im_2._intervals), 1) self.assertEqual(self.im_2._intervals[0], self.im_2_2) # test the intvl was set to dropped self.assertTrue(intvl.dropped) def test_drop_all(self): self.im_2.drop(self.im_2._intervals) self.assertEqual(self.im_2, self.im_empty) def test_drop_negate(self): intvl = self.im_2._intervals[0] self.im_2.drop([intvl], negate=True) self.assertEqual(len(self.im_2._intervals), 1) self.assertEqual(self.im_2._intervals[0], intvl) # test the dropped intvl was set to dropped self.assertTrue(self.im_2_2.dropped) def test_reverse(self): self.im_2._reverse() Interval( interval_metadata=self.im_empty, bounds=[(0, 6), (8, 9)], metadata={'gene': 'sagA', 'bound': 0}) Interval( interval_metadata=self.im_empty, bounds=[(5, 7)], metadata={'gene': 'sagB', 'bound': 0, 'spam': [0]}) self.assertEqual(self.im_2, self.im_empty) def test_eq_ne(self): im1 = IntervalMetadata(10) im1.add(metadata={'gene': 'sagA', 'bound': '0'}, bounds=[(0, 2), (4, 7)]) im1.add(metadata={'gene': 'sagB', 'bound': '3'}, bounds=[(3, 5)]) # The ordering shouldn't matter im2 = IntervalMetadata(10) im2.add(metadata={'gene': 'sagB', 'bound': '3'}, bounds=[(3, 5)]) im2.add(metadata={'gene': 'sagA', 'bound': '0'}, bounds=[(0, 2), (4, 7)]) im3 = IntervalMetadata(10) im3.add(metadata={'gene': 'sagA', 'bound': '3'}, bounds=[(0, 2), (4, 7)]) im3.add(metadata={'gene': 'sagB', 'bound': '3'}, bounds=[(3, 5)]) self.assertReallyEqual(im1, im2) self.assertReallyNotEqual(im1, im3) def test_ne_diff_bounds(self): im1 = IntervalMetadata(10) im2 = IntervalMetadata(9) intvl = {'bounds': [(0, 1)], 'metadata': {'spam': 'foo'}} im1.add(**intvl) im2.add(**intvl) self.assertReallyNotEqual(im1, im2) def test_repr(self): exp = '''0 interval features -------------------''' self.assertEqual(repr(self.im_empty), exp) self.im_empty.add([(1, 2)], metadata={'gene': 'sagA'}) exp = ("1 interval feature\n" "------------------\n" r"Interval\(interval_metadata=<[0-9]+>, bounds=\[\(1, 2\)\], " r"fuzzy=\[\(False, False\)\], metadata={'gene': 'sagA'}\)") self.assertRegex(repr(self.im_empty), exp) self.im_empty.add([(3, 4)], metadata={'gene': 'sagB'}) self.im_empty.add([(3, 4)], metadata={'gene': 'sagC'}) self.im_empty.add([(3, 4)], metadata={'gene': 'sagD'}) self.im_empty.add([(3, 4)], metadata={'gene': 'sagE'}) self.im_empty.add([(3, 4)], metadata={'gene': 'sagF'}) exp = ("6 interval features\n" "-------------------\n" r"Interval\(interval_metadata=<[0-9]+>, bounds=\[\(1, 2\)\], " r"fuzzy=\[\(False, False\)\], metadata={'gene': 'sagA'}\)\n" r"Interval\(interval_metadata=<[0-9]+>, bounds=\[\(3, 4\)\], " r"fuzzy=\[\(False, False\)\], metadata={'gene': 'sagB'}\)\n" r"...\n" r"Interval\(interval_metadata=<[0-9]+>, bounds=\[\(3, 4\)\], " r"fuzzy=\[\(False, False\)\], metadata={'gene': 'sagE'}\)\n" r"Interval\(interval_metadata=<[0-9]+>, bounds=\[\(3, 4\)\], " r"fuzzy=\[\(False, False\)\], metadata={'gene': 'sagF'}\)") self.assertRegex(repr(self.im_empty), exp) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/test_io.py000066400000000000000000001573241520735541300244400ustar00rootroot00000000000000import collections import os.path import tempfile import unittest from packaging.version import Version import numpy as np import pandas as pd from skbio.util import get_data_path from skbio.metadata._metadata import (SampleMetadata, CategoricalMetadataColumn, NumericMetadataColumn) from skbio.metadata.io import MetadataFileError PANDAS_3 = Version(pd.__version__) >= Version("3.0.0") # NOTE: many of the test files in the `data` directory intentionally have # leading/trailing whitespace characters on some lines, as well as mixed usage # of spaces, tabs, carriage returns, and newlines. When editing these files, # please make sure your code editor doesn't strip these leading/trailing # whitespace characters (e.g. Atom does this by default), nor automatically # modify the files in some other way such as converting Windows-style CRLF # line terminators to Unix-style newlines. # # When committing changes to the files, carefully review the diff to make sure # unintended changes weren't introduced. class TestLoadErrors(unittest.TestCase): def test_path_does_not_exist(self): with self.assertRaisesRegex(MetadataFileError, "Metadata file path doesn't exist"): SampleMetadata.load( '/qiime2/unit/tests/hopefully/this/path/does/not/exist') def test_path_is_directory(self): fp = get_data_path('valid') with self.assertRaisesRegex(MetadataFileError, "path points to something other than a " "file"): SampleMetadata.load(fp) def test_non_utf_8_file(self): fp = get_data_path('invalid/non-utf-8.tsv') with self.assertRaisesRegex(MetadataFileError, 'encoded as UTF-8 or ASCII'): SampleMetadata.load(fp) def test_utf_16_le_file(self): fp = get_data_path('invalid/simple-utf-16le.txt') with self.assertRaisesRegex(MetadataFileError, 'UTF-16 Unicode'): SampleMetadata.load(fp) def test_utf_16_be_file(self): fp = get_data_path('invalid/simple-utf-16be.txt') with self.assertRaisesRegex(MetadataFileError, 'UTF-16 Unicode'): SampleMetadata.load(fp) def test_empty_file(self): fp = get_data_path('invalid/empty-file') with self.assertRaisesRegex(MetadataFileError, 'locate header.*file may be empty'): SampleMetadata.load(fp) def test_comments_and_empty_rows_only(self): fp = get_data_path('invalid/comments-and-empty-rows-only.tsv') with self.assertRaisesRegex(MetadataFileError, 'locate header.*only of comments or empty ' 'rows'): SampleMetadata.load(fp) def test_header_only(self): fp = get_data_path('invalid/header-only.tsv') with self.assertRaisesRegex(MetadataFileError, 'at least one ID'): SampleMetadata.load(fp) def test_header_only_with_comments_and_empty_rows(self): fp = get_data_path( 'invalid/header-only-with-comments-and-empty-rows.tsv') with self.assertRaisesRegex(MetadataFileError, 'at least one ID'): SampleMetadata.load(fp) def test_qiime1_empty_mapping_file(self): fp = get_data_path('invalid/qiime1-empty.tsv') with self.assertRaisesRegex(MetadataFileError, 'at least one ID'): SampleMetadata.load(fp) def test_invalid_header(self): fp = get_data_path('invalid/invalid-header.tsv') with self.assertRaisesRegex(MetadataFileError, 'unrecognized ID column name.*' 'invalid_id_header'): SampleMetadata.load(fp) def test_empty_id(self): fp = get_data_path('invalid/empty-id.tsv') with self.assertRaisesRegex(MetadataFileError, 'empty metadata ID'): SampleMetadata.load(fp) def test_whitespace_only_id(self): fp = get_data_path('invalid/whitespace-only-id.tsv') with self.assertRaisesRegex(MetadataFileError, 'empty metadata ID'): SampleMetadata.load(fp) def test_empty_column_name(self): fp = get_data_path('invalid/empty-column-name.tsv') with self.assertRaisesRegex(MetadataFileError, 'column without a name'): SampleMetadata.load(fp) def test_whitespace_only_column_name(self): fp = get_data_path('invalid/whitespace-only-column-name.tsv') with self.assertRaisesRegex(MetadataFileError, 'column without a name'): SampleMetadata.load(fp) def test_duplicate_ids(self): fp = get_data_path('invalid/duplicate-ids.tsv') with self.assertRaisesRegex(MetadataFileError, 'IDs must be unique.*id1'): SampleMetadata.load(fp) def test_duplicate_ids_with_whitespace(self): fp = get_data_path('invalid/duplicate-ids-with-whitespace.tsv') with self.assertRaisesRegex(MetadataFileError, 'IDs must be unique.*id1'): SampleMetadata.load(fp) def test_duplicate_column_names(self): fp = get_data_path('invalid/duplicate-column-names.tsv') with self.assertRaisesRegex(MetadataFileError, 'Column names must be unique.*col1'): SampleMetadata.load(fp) def test_duplicate_column_names_with_whitespace(self): fp = get_data_path( 'invalid/duplicate-column-names-with-whitespace.tsv') with self.assertRaisesRegex(MetadataFileError, 'Column names must be unique.*col1'): SampleMetadata.load(fp) def test_id_conflicts_with_id_header(self): fp = get_data_path('invalid/id-conflicts-with-id-header.tsv') with self.assertRaisesRegex(MetadataFileError, "ID 'id' conflicts.*ID column header"): SampleMetadata.load(fp) def test_column_name_conflicts_with_id_header(self): fp = get_data_path( 'invalid/column-name-conflicts-with-id-header.tsv') with self.assertRaisesRegex(MetadataFileError, "column name 'featureid' conflicts.*ID " "column header"): SampleMetadata.load(fp) def test_column_types_unrecognized_column_name(self): fp = get_data_path('valid/simple.tsv') with self.assertRaisesRegex(MetadataFileError, 'not_a_column.*column_types.*not a column ' 'in the metadata file'): SampleMetadata.load(fp, column_types={'not_a_column': 'numeric'}) def test_column_types_unrecognized_column_type(self): fp = get_data_path('valid/simple.tsv') with self.assertRaisesRegex(MetadataFileError, 'col2.*column_types.*unrecognized column ' 'type.*CATEGORICAL'): SampleMetadata.load(fp, column_types={'col1': 'numeric', 'col2': 'CATEGORICAL'}) def test_column_types_not_convertible_to_numeric(self): fp = get_data_path('valid/simple.tsv') with self.assertRaisesRegex(MetadataFileError, "column 'col3' to numeric.*could not be " "interpreted as numeric: 'bar', 'foo'"): SampleMetadata.load(fp, column_types={'col1': 'numeric', 'col2': 'categorical', 'col3': 'numeric'}) def test_column_types_override_directive_not_convertible_to_numeric(self): fp = get_data_path('valid/simple-with-directive.tsv') with self.assertRaisesRegex(MetadataFileError, "column 'col3' to numeric.*could not be " "interpreted as numeric: 'bar', 'foo'"): SampleMetadata.load(fp, column_types={'col3': 'numeric'}) def test_directive_before_header(self): fp = get_data_path('invalid/directive-before-header.tsv') with self.assertRaisesRegex(MetadataFileError, 'directive.*#q2:types.*searching for ' 'header'): SampleMetadata.load(fp) def test_unrecognized_directive(self): fp = get_data_path('invalid/unrecognized-directive.tsv') with self.assertRaisesRegex(MetadataFileError, 'Unrecognized directive.*#q2:foo.*' '#q2:types.*#q2:missing.*directive'): SampleMetadata.load(fp) def test_duplicate_directives(self): fp = get_data_path('invalid/duplicate-directives.tsv') with self.assertRaisesRegex(MetadataFileError, 'duplicate directive.*#q2:types'): SampleMetadata.load(fp) def test_unrecognized_column_type_in_directive(self): fp = get_data_path('invalid/unrecognized-column-type.tsv') with self.assertRaisesRegex(MetadataFileError, 'col2.*unrecognized column type.*foo.*' '#q2:types directive'): SampleMetadata.load(fp) def test_column_types_directive_not_convertible_to_numeric(self): fp = get_data_path('invalid/types-directive-non-numeric.tsv') # This error message regex is intentionally verbose because we want to # assert that many different types of non-numeric strings aren't # interpreted as numbers. The error message displays a sorted list of # all values that couldn't be converted to numbers, making it possible # to test a variety of non-numeric strings in a single test case. msg = (r"column 'col2' to numeric.*could not be interpreted as " r"numeric: '\$42', '\+inf', '-inf', '0xAF', '1,000', " r"'1\.000\.0', '1_000_000', '1e3e4', 'Infinity', 'NA', 'NaN', " "'a', 'e3', 'foo', 'inf', 'nan', 'sample-1'") with self.assertRaisesRegex(MetadataFileError, msg): SampleMetadata.load(fp) def test_directive_after_directives_section(self): fp = get_data_path( 'invalid/directive-after-directives-section.tsv') with self.assertRaisesRegex(MetadataFileError, '#q2:types.*outside of the directives ' 'section'): SampleMetadata.load(fp) def test_directive_longer_than_header(self): fp = get_data_path('invalid/directive-longer-than-header.tsv') with self.assertRaisesRegex(MetadataFileError, 'row has 5 cells.*header declares 4 ' 'cells'): SampleMetadata.load(fp) def test_data_longer_than_header(self): fp = get_data_path('invalid/data-longer-than-header.tsv') with self.assertRaisesRegex(MetadataFileError, 'row has 5 cells.*header declares 4 ' 'cells'): SampleMetadata.load(fp) def test_unknown_missing_scheme(self): fp = get_data_path('invalid/missing-unknown-scheme.tsv') with self.assertRaisesRegex(MetadataFileError, 'col1.*BAD:SCHEME.*#sk:missing'): SampleMetadata.load(fp) class TestLoadSuccess(unittest.TestCase): def setUp(self): self.temp_dir_obj = tempfile.TemporaryDirectory( prefix='qiime2-metadata-tests-temp-') self.temp_dir = self.temp_dir_obj.name # This Metadata object is compared against observed Metadata objects in # many of the tests, so just define it once here. self.simple_md = SampleMetadata( pd.DataFrame({'col1': [1.0, 2.0, 3.0], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=pd.Index(['id1', 'id2', 'id3'], name='id'))) # Basic sanity check to make sure the columns are ordered and typed as # expected. It'd be unfortunate to compare observed results to expected # results that aren't representing what we think they are! obs_columns = [(name, props.type) for name, props in self.simple_md.columns.items()] exp_columns = [('col1', 'numeric'), ('col2', 'categorical'), ('col3', 'categorical')] self.assertEqual(obs_columns, exp_columns) def tearDown(self): self.temp_dir_obj.cleanup() def test_simple(self): # Simple metadata file without comments, empty rows, jaggedness, # missing data, odd IDs or column names, directives, etc. The file has # multiple column types (numeric, categorical, and something that has # mixed numbers and strings, which must be interpreted as categorical). fp = get_data_path('valid/simple.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_bom_simple_txt(self): # This is the encoding that notepad.exe will use most commonly fp = get_data_path('valid/BOM-simple.txt') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_different_file_extension(self): fp = get_data_path('valid/simple.txt') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_no_newline_at_eof(self): fp = get_data_path('valid/no-newline-at-eof.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_unix_line_endings(self): fp = get_data_path('valid/unix-line-endings.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_windows_line_endings(self): fp = get_data_path('valid/windows-line-endings.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_mac_line_endings(self): fp = get_data_path('valid/mac-line-endings.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_retains_column_order(self): # Explicitly test that the file's column order is retained in the # Metadata object. Many of the test cases use files with column names # in alphabetical order (e.g. "col1", "col2", "col3"), which matches # how pandas orders columns in a DataFrame when supplied with a dict # (many of the test cases use this feature of the DataFrame # constructor when constructing the expected DataFrame). fp = get_data_path('valid/column-order.tsv') obs_md = SampleMetadata.load(fp) # Supply DataFrame constructor with explicit column ordering instead of # a dict. exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_columns = ['z', 'y', 'x'] exp_data = [ [1.0, 'a', 'foo'], [2.0, 'b', 'bar'], [3.0, 'c', '42'] ] exp_df = pd.DataFrame(exp_data, index=exp_index, columns=exp_columns) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_leading_trailing_whitespace(self): fp = get_data_path('valid/leading-trailing-whitespace.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_comments(self): fp = get_data_path('valid/comments.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_empty_rows(self): fp = get_data_path('valid/empty-rows.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_qiime1_mapping_file(self): fp = get_data_path('valid/qiime1.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2', 'id3'], name='#SampleID') exp_df = pd.DataFrame({'col1': [1.0, 2.0, 3.0], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_qiita_sample_information_file(self): fp = get_data_path('valid/qiita-sample-information.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id.1', 'id.2'], name='sample_name') exp_df = pd.DataFrame({ 'DESCRIPTION': ['description 1', 'description 2'], 'TITLE': ['A Title', 'Another Title']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_qiita_preparation_information_file(self): fp = get_data_path('valid/qiita-preparation-information.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id.1', 'id.2'], name='sample_name') exp_df = pd.DataFrame({ 'BARCODE': ['ACGT', 'TGCA'], 'EXPERIMENT_DESIGN_DESCRIPTION': ['longitudinal study', 'longitudinal study']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_biom_observation_metadata_file(self): fp = get_data_path('valid/biom-observation-metadata.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['OTU_1', 'OTU_2'], name='#OTUID') exp_df = pd.DataFrame([['k__Bacteria;p__Firmicutes', 0.890], ['k__Bacteria', 0.9999]], columns=['taxonomy', 'confidence'], index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_supported_id_headers(self): case_insensitive = { 'id', 'sampleid', 'sample id', 'sample-id', 'featureid', 'feature id', 'feature-id' } exact_match = { '#SampleID', '#Sample ID', '#OTUID', '#OTU ID', 'sample_name' } # Build a set of supported headers, including exact matches and headers # with different casing. headers = set() for header in case_insensitive: headers.add(header) headers.add(header.upper()) headers.add(header.title()) for header in exact_match: headers.add(header) fp = os.path.join(self.temp_dir, 'metadata.tsv') count = 0 for header in headers: with open(fp, 'w') as fh: fh.write('%s\tcolumn\nid1\tfoo\nid2\tbar\n' % header) obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2'], name=header) exp_df = pd.DataFrame({'column': ['foo', 'bar']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) count += 1 # Since this test case is a little complicated, make sure that the # expected number of comparisons are happening. self.assertEqual(count, 26) def test_recommended_ids(self): fp = get_data_path('valid/recommended-ids.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['c6ca034a-223f-40b4-a0e0-45942912a5ea', 'My.ID'], name='id') exp_df = pd.DataFrame({'col1': ['foo', 'bar']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_non_standard_characters(self): # Test that non-standard characters in IDs, column names, and cells are # handled correctly. The test case isn't exhaustive (e.g. it doesn't # test every Unicode character; that would be a nice additional test # case to have in the future). Instead, this test aims to be more of an # integration test for the robustness of the reader to non-standard # data. Many of the characters and their placement within the data file # are based on use-cases/bugs reported on the forum, Slack, etc. The # data file has comments explaining these test case choices in more # detail. fp = get_data_path('valid/non-standard-characters.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['©id##1', '((id))2', "'id_3<>'", '"id#4"', 'i d\r\t\n5'], name='id') exp_columns = ['↩c@l1â„¢', 'col(#2)', "#col'3", '""', 'col\t \r\n5'] exp_data = [ ['Æ’oo', '(foo)', '#f o #o', 'fo\ro', np.nan], ["''2''", 'b#r', 'ba\nr', np.nan, np.nan], ['b"ar', 'c\td', '4\r\n2', np.nan, np.nan], ['b__a_z', '<42>', '>42', np.nan, np.nan], ['baz', np.nan, '42'] ] exp_df = pd.DataFrame(exp_data, index=exp_index, columns=exp_columns) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_missing_data(self): print(f"Running things...!") fp = get_data_path('valid/missing-data.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['None', 'nan', 'NA'], name='id') exp_df = pd.DataFrame(collections.OrderedDict([ ('col1', [1.0, np.nan, np.nan]), ('NA', [np.nan, np.nan, np.nan]), ('col3', ['null', 'N/A', 'NA']), ('col4', np.array([np.nan, np.nan, np.nan], dtype=object))]), index=exp_index) exp_md = SampleMetadata(exp_df) print(f"obs_md: {obs_md}, exp_md: {exp_md}") self.assertEqual(obs_md, exp_md) # Test that column types are correct (mainly for the two empty columns; # one should be numeric, the other categorical). obs_columns = [(name, props.type) for name, props in obs_md.columns.items()] exp_columns = [('col1', 'numeric'), ('NA', 'numeric'), ('col3', 'categorical'), ('col4', 'categorical')] self.assertEqual(obs_columns, exp_columns) def test_missing_insdc(self): fp = get_data_path('valid/missing-insdc.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2', 'id3', 'id4', 'id5', 'id6'], name='id') exp_df = pd.DataFrame({'col1': [1, 2, 3] + ([float('nan')] * 3), 'col2': ['a', 'b', 'c'] + ([float('nan')] * 3), 'col3': ['foo', 'bar', '42', 'anything', 'whatever', '10']}, index=exp_index) # not testing column_missing_schemes here on purpose, externally the # nan's shouldn't be meaningfully different exp_md = SampleMetadata(exp_df) pd.testing.assert_frame_equal(obs_md.to_dataframe(), exp_md.to_dataframe()) obs_columns = [(name, props.type, props.missing_scheme) for name, props in obs_md.columns.items()] exp_columns = [ ('col1', 'numeric', 'INSDC:missing'), ('col2', 'categorical', 'INSDC:missing'), ('col3', 'categorical', 'no-missing') ] self.assertEqual(obs_columns, exp_columns) def test_insdc_no_directives(self): fp = get_data_path('valid/missing-insdc-no-directive.tsv') obs_md = SampleMetadata.load(fp, default_missing_scheme='INSDC:missing') exp_index = pd.Index(['id1', 'id2', 'id3', 'id4', 'id5', 'id6'], name='id') exp_df = pd.DataFrame({'col1': [1, 2, 3] + ([float('nan')] * 3), 'col2': ['a', 'b', 'c'] + ([float('nan')] * 3), 'col3': ['foo', 'bar', '42', 'anything', 'whatever', '10']}, index=exp_index) # not testing column_missing_schemes here on purpose, externally the # nan's shouldn't be meaningfully different exp_md = SampleMetadata(exp_df) pd.testing.assert_frame_equal(obs_md.to_dataframe(), exp_md.to_dataframe()) obs_columns = [(name, props.type, props.missing_scheme) for name, props in obs_md.columns.items()] exp_columns = [ ('col1', 'numeric', 'INSDC:missing'), ('col2', 'categorical', 'INSDC:missing'), ('col3', 'categorical', 'INSDC:missing') ] self.assertEqual(obs_columns, exp_columns) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_insdc_override(self): fp = get_data_path('valid/override-insdc.tsv') # This file has INSDC terms, but they aren't missing values. obs_md = SampleMetadata.load(fp, default_missing_scheme='INSDC:missing') exp_index = pd.Index(['id1', 'id2', 'id3', 'id4'], name='id') exp_df = pd.DataFrame({'col1': ['collected', 'not collected', 'not collected', 'collected']}, index=exp_index) pd.testing.assert_frame_equal(obs_md.to_dataframe(), exp_df) obs_columns = [(name, props.type, props.missing_scheme) for name, props in obs_md.columns.items()] exp_columns = [ ('col1', 'categorical', 'no-missing'), ] self.assertEqual(obs_columns, exp_columns) def test_minimal_file(self): # Simplest possible metadata file consists of one ID and zero columns. fp = get_data_path('valid/minimal.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['a'], name='id') exp_df = pd.DataFrame({}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_single_id(self): fp = get_data_path('valid/single-id.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1'], name='id') exp_df = pd.DataFrame({'col1': [1.0], 'col2': ['a'], 'col3': ['foo']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_no_columns(self): fp = get_data_path('valid/no-columns.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['a', 'b', 'my-id'], name='id') exp_df = pd.DataFrame({}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_single_column(self): fp = get_data_path('valid/single-column.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_df = pd.DataFrame({'col1': [1.0, 2.0, 3.0]}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_trailing_columns(self): fp = get_data_path('valid/trailing-columns.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_jagged_trailing_columns(self): # Test case based on https://github.com/qiime2/qiime2/issues/335 fp = get_data_path('valid/jagged-trailing-columns.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_padding_rows_shorter_than_header(self): fp = get_data_path('valid/rows-shorter-than-header.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_df = pd.DataFrame({'col1': [1.0, 2.0, np.nan], 'col2': ['a', np.nan, np.nan], 'col3': [np.nan, np.nan, np.nan]}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_all_cells_padded(self): fp = get_data_path('valid/all-cells-padded.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_df = pd.DataFrame({'col1': [np.nan, np.nan, np.nan], 'col2': [np.nan, np.nan, np.nan], 'col3': [np.nan, np.nan, np.nan]}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_does_not_cast_ids_or_column_names(self): fp = get_data_path('valid/no-id-or-column-name-type-cast.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['0.000001', '0.004000', '0.000000'], dtype=object, name='id') exp_columns = ['42.0', '1000', '-4.2'] exp_data = [ [2.0, 'b', 2.5], [1.0, 'b', 4.2], [3.0, 'c', -9.999] ] exp_df = pd.DataFrame(exp_data, index=exp_index, columns=exp_columns) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_numeric_column(self): fp = get_data_path('valid/numeric-column.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2', 'id3', 'id4', 'id5', 'id6', 'id7', 'id8', 'id9', 'id10', 'id11', 'id12'], name='id') exp_df = pd.DataFrame({'col1': [0.0, 2.0, 0.0003, -4.2, 1e-4, 1e4, 1.5e2, np.nan, 1.0, 0.5, 1e-8, -0.0]}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_numeric_column_as_categorical(self): fp = get_data_path('valid/numeric-column.tsv') obs_md = SampleMetadata.load(fp, column_types={'col1': 'categorical'}) exp_index = pd.Index(['id1', 'id2', 'id3', 'id4', 'id5', 'id6', 'id7', 'id8', 'id9', 'id10', 'id11', 'id12'], name='id') exp_df = pd.DataFrame({'col1': ['0', '2.0', '0.00030', '-4.2', '1e-4', '1e4', '+1.5E+2', np.nan, '1.', '.5', '1e-08', '-0']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_with_complete_types_sk_directive(self): fp = get_data_path('valid/complete-types-directive_w_sk.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_df = pd.DataFrame({'col1': ['1', '2', '3'], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_with_complete_types_directive(self): fp = get_data_path('valid/complete-types-directive.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_df = pd.DataFrame({'col1': ['1', '2', '3'], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_with_partial_types_directive(self): fp = get_data_path('valid/partial-types-directive.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_df = pd.DataFrame({'col1': ['1', '2', '3'], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_with_empty_types_directive(self): fp = get_data_path('valid/empty-types-directive.tsv') obs_md = SampleMetadata.load(fp) self.assertEqual(obs_md, self.simple_md) def test_with_case_insensitive_types_directive(self): fp = get_data_path('valid/case-insensitive-types-directive.tsv') obs_md = SampleMetadata.load(fp) exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_df = pd.DataFrame({'col1': ['1', '2', '3'], 'col2': ['a', 'b', 'c'], 'col3': [-5.0, 0.0, 42.0]}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_column_types_without_directive(self): fp = get_data_path('valid/simple.tsv') obs_md = SampleMetadata.load(fp, column_types={'col1': 'categorical'}) exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_df = pd.DataFrame({'col1': ['1', '2', '3'], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) def test_column_types_override_directive(self): fp = get_data_path('valid/simple-with-directive.tsv') obs_md = SampleMetadata.load(fp, column_types={'col1': 'categorical', 'col2': 'categorical'}) exp_index = pd.Index(['id1', 'id2', 'id3'], name='id') exp_df = pd.DataFrame({'col1': ['1', '2', '3'], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=exp_index) exp_md = SampleMetadata(exp_df) self.assertEqual(obs_md, exp_md) class TestSave(unittest.TestCase): def setUp(self): self.temp_dir_obj = tempfile.TemporaryDirectory( prefix='qiime2-metadata-tests-temp-') self.temp_dir = self.temp_dir_obj.name self.filepath = os.path.join(self.temp_dir, 'metadata.tsv') def tearDown(self): self.temp_dir_obj.cleanup() def test_simple(self): md = SampleMetadata(pd.DataFrame( {'col1': [1.0, 2.0, 3.0], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=pd.Index(['id1', 'id2', 'id3'], name='id'))) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcol1\tcol2\tcol3\n" "#sk:types\tnumeric\tcategorical\tcategorical\n" "id1\t1\ta\tfoo\n" "id2\t2\tb\tbar\n" "id3\t3\tc\t42\n" ) self.assertEqual(obs, exp) def test_save_metadata_auto_extension(self): md = SampleMetadata(pd.DataFrame( {'col1': [1.0, 2.0, 3.0], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=pd.Index(['id1', 'id2', 'id3'], name='id'))) # Filename & extension endswith is matching (non-default). fp = os.path.join(self.temp_dir, 'metadatatsv') obs_md = md.save(fp, '.tsv') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadatatsv.tsv') # No period in filename; no extension included. fp = os.path.join(self.temp_dir, 'metadata') obs_md = md.save(fp) obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata') # No period in filename; no period in extension. fp = os.path.join(self.temp_dir, 'metadata') obs_md = md.save(fp, 'tsv') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv') # No period in filename; multiple periods in extension. fp = os.path.join(self.temp_dir, 'metadata') obs_md = md.save(fp, '..tsv') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv') # Single period in filename; no period in extension. fp = os.path.join(self.temp_dir, 'metadata.') obs_md = md.save(fp, 'tsv') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv') # Single period in filename; single period in extension. fp = os.path.join(self.temp_dir, 'metadata.') obs_md = md.save(fp, '.tsv') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv') # Single period in filename; multiple periods in extension. fp = os.path.join(self.temp_dir, 'metadata.') obs_md = md.save(fp, '..tsv') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv') # Multiple periods in filename; single period in extension. fp = os.path.join(self.temp_dir, 'metadata..') obs_md = md.save(fp, '.tsv') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv') # Multiple periods in filename; multiple periods in extension. fp = os.path.join(self.temp_dir, 'metadata..') obs_md = md.save(fp, '..tsv') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv') # No extension in filename; no extension input. fp = os.path.join(self.temp_dir, 'metadata') obs_md = md.save(fp) obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata') # No extension in filename; extension input. fp = os.path.join(self.temp_dir, 'metadata') obs_md = md.save(fp, '.tsv') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv') # Extension in filename; no extension input. fp = os.path.join(self.temp_dir, 'metadata.tsv') obs_md = md.save(fp) obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv') # Extension in filename; extension input (non-matching). fp = os.path.join(self.temp_dir, 'metadata.tsv') obs_md = md.save(fp, '.txt') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv.txt') # Extension in filename; extension input (matching). fp = os.path.join(self.temp_dir, 'metadata.tsv') obs_md = md.save(fp, '.tsv') obs_filename = os.path.basename(obs_md) self.assertEqual(obs_filename, 'metadata.tsv') def test_no_bom(self): md = SampleMetadata(pd.DataFrame( {'col1': [1.0, 2.0, 3.0], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=pd.Index(['id1', 'id2', 'id3'], name='id'))) md.save(self.filepath) with open(self.filepath, 'rb') as fh: obs = fh.read(2) self.assertEqual(obs, b'id') def test_different_file_extension(self): md = SampleMetadata(pd.DataFrame( {'col1': [1.0, 2.0, 3.0], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=pd.Index(['id1', 'id2', 'id3'], name='id'))) filepath = os.path.join(self.temp_dir, 'metadata.txt') md.save(filepath) with open(filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcol1\tcol2\tcol3\n" "#sk:types\tnumeric\tcategorical\tcategorical\n" "id1\t1\ta\tfoo\n" "id2\t2\tb\tbar\n" "id3\t3\tc\t42\n" ) self.assertEqual(obs, exp) def test_some_missing_data(self): md = SampleMetadata( pd.DataFrame({'col1': [42.0, np.nan, -3.5], 'col2': ['a', np.nan, np.nan]}, index=pd.Index(['id1', 'id2', 'id3'], name='id'))) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcol1\tcol2\n" "#sk:types\tnumeric\tcategorical\n" "id1\t42\ta\n" "id2\t\t\n" "id3\t-3.5\t\n" ) self.assertEqual(obs, exp) def test_all_missing_data(self): # nan-only columns that are numeric or categorical. md = SampleMetadata( pd.DataFrame({'col1': [np.nan, np.nan, np.nan], 'col2': np.array([np.nan, np.nan, np.nan], dtype=object)}, index=pd.Index(['id1', 'id2', 'id3'], name='id'))) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcol1\tcol2\n" "#sk:types\tnumeric\tcategorical\n" "id1\t\t\n" "id2\t\t\n" "id3\t\t\n" ) self.assertEqual(obs, exp) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_missing_schemes(self): md = SampleMetadata( pd.DataFrame({'col1': [42.0, np.nan, -3.5], 'col2': ['a', 'not applicable', 'restricted access']}, index=pd.Index(['id1', 'id2', 'id3'], name='id')), column_missing_schemes={ 'col1': 'blank', 'col2': 'INSDC:missing'} ) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcol1\tcol2\n" "#sk:types\tnumeric\tcategorical\n" "#sk:missing\tblank\tINSDC:missing\n" "id1\t42\ta\n" "id2\t\tnot applicable\n" "id3\t-3.5\trestricted access\n" ) self.assertEqual(obs, exp) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_default_missing_scheme(self): md = SampleMetadata( pd.DataFrame({'col1': [42.0, np.nan, -3.5], 'col2': ['a', 'not applicable', 'restricted access']}, index=pd.Index(['id1', 'id2', 'id3'], name='id')), default_missing_scheme='INSDC:missing') md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcol1\tcol2\n" "#sk:types\tnumeric\tcategorical\n" "#sk:missing\tINSDC:missing\tINSDC:missing\n" "id1\t42\ta\n" "id2\t\tnot applicable\n" "id3\t-3.5\trestricted access\n" ) self.assertEqual(obs, exp) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_default_missing_scheme_override(self): md = SampleMetadata( pd.DataFrame({'col1': [42.0, np.nan, -3.5], 'col2': ['a', 'not applicable', 'restricted access']}, index=pd.Index(['id1', 'id2', 'id3'], name='id')), default_missing_scheme='sk:error', column_missing_schemes=dict(col1='INSDC:missing', col2='INSDC:missing')) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcol1\tcol2\n" "#sk:types\tnumeric\tcategorical\n" "#sk:missing\tINSDC:missing\tINSDC:missing\n" "id1\t42\ta\n" "id2\t\tnot applicable\n" "id3\t-3.5\trestricted access\n" ) self.assertEqual(obs, exp) def test_unsorted_column_order(self): index = pd.Index(['id1', 'id2', 'id3'], name='id') columns = ['z', 'b', 'y'] data = [ [1.0, 'a', 'foo'], [2.0, 'b', 'bar'], [3.0, 'c', '42'] ] md = SampleMetadata(pd.DataFrame(data, index=index, columns=columns)) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tz\tb\ty\n" "#sk:types\tnumeric\tcategorical\tcategorical\n" "id1\t1\ta\tfoo\n" "id2\t2\tb\tbar\n" "id3\t3\tc\t42\n" ) self.assertEqual(obs, exp) def test_alternate_id_header(self): md = SampleMetadata(pd.DataFrame( {'col1': [1.0, 2.0, 3.0], 'col2': ['a', 'b', 'c'], 'col3': ['foo', 'bar', '42']}, index=pd.Index(['id1', 'id2', 'id3'], name='#SampleID'))) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "#SampleID\tcol1\tcol2\tcol3\n" "#sk:types\tnumeric\tcategorical\tcategorical\n" "id1\t1\ta\tfoo\n" "id2\t2\tb\tbar\n" "id3\t3\tc\t42\n" ) self.assertEqual(obs, exp) def test_various_numbers(self): numbers = [ 0.0, -0.0, np.nan, 1.0, 42.0, -33.0, 1e-10, 1.5e15, 0.0003, -4.234, # This last number should be rounded because it exceeds 15 digits # of precision. 12.34567891234567 ] index = pd.Index(['id1', 'id2', 'id3', 'id4', 'id5', 'id6', 'id7', 'id8', 'id9', 'id10', 'id11'], name='ID') md = SampleMetadata(pd.DataFrame({'numbers': numbers}, index=index)) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "ID\tnumbers\n" "#sk:types\tnumeric\n" "id1\t0\n" "id2\t-0\n" "id3\t\n" "id4\t1\n" "id5\t42\n" "id6\t-33\n" "id7\t1e-10\n" "id8\t1.5e+15\n" "id9\t0.0003\n" "id10\t-4.234\n" "id11\t12.3456789123457\n" ) self.assertEqual(obs, exp) def test_minimal(self): md = SampleMetadata(pd.DataFrame({}, index=pd.Index(['my-id'], name='id'))) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\n" "#sk:types\n" "my-id\n" ) self.assertEqual(obs, exp) def test_single_id(self): md = SampleMetadata(pd.DataFrame( {'col1': ['foo'], 'col2': [4.002]}, index=pd.Index(['my-id'], name='featureid'))) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "featureid\tcol1\tcol2\n" "#sk:types\tcategorical\tnumeric\n" "my-id\tfoo\t4.002\n" ) self.assertEqual(obs, exp) def test_no_columns(self): md = SampleMetadata(pd.DataFrame( {}, index=pd.Index(['foo', 'bar', 'baz'], name='id'))) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\n" "#sk:types\n" "foo\n" "bar\n" "baz\n" ) self.assertEqual(obs, exp) def test_single_column(self): md = SampleMetadata(pd.DataFrame( {'col1': ['42', '4.3', '4.4000']}, index=pd.Index(['foo', 'bar', 'baz'], name='id'))) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcol1\n" "#sk:types\tcategorical\n" "foo\t42\n" "bar\t4.3\n" "baz\t4.4000\n" ) self.assertEqual(obs, exp) def test_ids_and_column_names_as_numeric_strings(self): index = pd.Index(['0.000001', '0.004000', '0.000000'], dtype=object, name='id') columns = ['42.0', '1000', '-4.2'] data = [ [2.0, 'b', 2.5], [1.0, 'b', 4.2], [3.0, 'c', -9.999] ] df = pd.DataFrame(data, index=index, columns=columns) md = SampleMetadata(df) md.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\t42.0\t1000\t-4.2\n" "#sk:types\tnumeric\tcategorical\tnumeric\n" "0.000001\t2\tb\t2.5\n" "0.004000\t1\tb\t4.2\n" "0.000000\t3\tc\t-9.999\n" ) self.assertEqual(obs, exp) # A couple of basic tests for CategoricalMetadataColumn and # NumericMetadataColumn below. Those classes simply transform themselves # into single-column Metadata objects within `MetadataColumn.save()` and # use the same writer code from there on. def test_categorical_metadata_column(self): mdc = CategoricalMetadataColumn(pd.Series( ['foo', 'bar', '42.50'], name='categorical-column', index=pd.Index(['id1', 'id2', 'id3'], name='id'))) mdc.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcategorical-column\n" "#sk:types\tcategorical\n" "id1\tfoo\n" "id2\tbar\n" "id3\t42.50\n" ) self.assertEqual(obs, exp) def test_categorical_metadata_column_insdc_no_missing(self): mdc = CategoricalMetadataColumn(pd.Series( ['foo', 'bar', '42.50'], name='categorical-column', index=pd.Index(['id1', 'id2', 'id3'], name='id')), missing_scheme='INSDC:missing') mdc.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcategorical-column\n" "#sk:types\tcategorical\n" "#sk:missing\tINSDC:missing\n" "id1\tfoo\n" "id2\tbar\n" "id3\t42.50\n" ) self.assertEqual(obs, exp) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_categorical_metadata_column_insdc_missing(self): mdc = CategoricalMetadataColumn(pd.Series( ['foo', 'missing', '42.50'], name='categorical-column', index=pd.Index(['id1', 'id2', 'id3'], name='id')), missing_scheme='INSDC:missing') mdc.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tcategorical-column\n" "#sk:types\tcategorical\n" "#sk:missing\tINSDC:missing\n" "id1\tfoo\n" "id2\tmissing\n" "id3\t42.50\n" ) self.assertEqual(obs, exp) def test_numeric_metadata_column(self): mdc = NumericMetadataColumn(pd.Series( [1e-15, 42.50, -999.0], name='numeric-column', index=pd.Index(['id1', 'id2', 'id3'], name='#OTU ID'))) mdc.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "#OTU ID\tnumeric-column\n" "#sk:types\tnumeric\n" "id1\t1e-15\n" "id2\t42.5\n" "id3\t-999\n" ) self.assertEqual(obs, exp) def test_numeric_metadata_column_insdc_no_missing(self): mdc = NumericMetadataColumn(pd.Series( [1e-15, 42.50, -999.0], name='numeric-column', index=pd.Index(['id1', 'id2', 'id3'], name='#OTU ID')), missing_scheme='INSDC:missing') mdc.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "#OTU ID\tnumeric-column\n" "#sk:types\tnumeric\n" "#sk:missing\tINSDC:missing\n" "id1\t1e-15\n" "id2\t42.5\n" "id3\t-999\n" ) self.assertEqual(obs, exp) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_numeric_metadata_column_insdc_missing(self): mdc = NumericMetadataColumn(pd.Series( [1e-15, 'missing', -999.0], name='numeric-column', index=pd.Index(['id1', 'id2', 'id3'], name='#OTU ID')), missing_scheme='INSDC:missing') mdc.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "#OTU ID\tnumeric-column\n" "#sk:types\tnumeric\n" "#sk:missing\tINSDC:missing\n" "id1\t1e-15\n" "id2\tmissing\n" "id3\t-999\n" ) self.assertEqual(obs, exp) # TODO this class spot-checks some of the more "difficult" valid files to make # sure they can be read, written to disk, and read again in a lossless way. # A more complete strategy (with fewer test cases) would be performing a # roundtrip test on every valid file under the `data` directory (e.g. with a # `glob` and for loop). class TestRoundtrip(unittest.TestCase): def setUp(self): self.temp_dir_obj = tempfile.TemporaryDirectory( prefix='qiime2-metadata-tests-temp-') self.temp_dir = self.temp_dir_obj.name self.filepath = os.path.join(self.temp_dir, 'metadata.tsv') def tearDown(self): self.temp_dir_obj.cleanup() def test_simple(self): fp = get_data_path('valid/simple.tsv') md1 = SampleMetadata.load(fp) md1.save(self.filepath) md2 = SampleMetadata.load(self.filepath) self.assertEqual(md1, md2) def test_non_standard_characters(self): fp = get_data_path('valid/non-standard-characters.tsv') md1 = SampleMetadata.load(fp) md1.save(self.filepath) md2 = SampleMetadata.load(self.filepath) self.assertEqual(md1, md2) def test_missing_data(self): fp = get_data_path('valid/missing-data.tsv') md1 = SampleMetadata.load(fp) md1.save(self.filepath) md2 = SampleMetadata.load(self.filepath) self.assertEqual(md1, md2) def test_missing_insdc(self): fp = get_data_path('valid/missing-insdc.tsv') md1 = SampleMetadata.load(fp) md1.save(self.filepath) md2 = SampleMetadata.load(self.filepath) self.assertEqual(md1, md2) def test_minimal_file(self): fp = get_data_path('valid/minimal.tsv') md1 = SampleMetadata.load(fp) md1.save(self.filepath) md2 = SampleMetadata.load(self.filepath) self.assertEqual(md1, md2) def test_numeric_column(self): fp = get_data_path('valid/numeric-column.tsv') md1 = SampleMetadata.load(fp) md1.save(self.filepath) md2 = SampleMetadata.load(self.filepath) self.assertEqual(md1, md2) def test_all_cells_padded(self): fp = get_data_path('valid/all-cells-padded.tsv') md1 = SampleMetadata.load(fp) md1.save(self.filepath) md2 = SampleMetadata.load(self.filepath) self.assertEqual(md1, md2) def test_categorical_metadata_column(self): fp = get_data_path('valid/simple.tsv') md1 = SampleMetadata.load(fp) mdc1 = md1.get_column('col2') self.assertIsInstance(mdc1, CategoricalMetadataColumn) mdc1.save(self.filepath) md2 = SampleMetadata.load(self.filepath) mdc2 = md2.get_column('col2') self.assertIsInstance(mdc1, CategoricalMetadataColumn) self.assertEqual(mdc1, mdc2) def test_numeric_metadata_column(self): fp = get_data_path('valid/simple.tsv') md1 = SampleMetadata.load(fp) mdc1 = md1.get_column('col1') self.assertIsInstance(mdc1, NumericMetadataColumn) mdc1.save(self.filepath) md2 = SampleMetadata.load(self.filepath) mdc2 = md2.get_column('col1') self.assertIsInstance(mdc1, NumericMetadataColumn) self.assertEqual(mdc1, mdc2) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/test_metadata.py000066400000000000000000001207071520735541300256040ustar00rootroot00000000000000import collections import unittest import warnings from packaging.version import Version import pandas as pd import numpy as np from skbio.metadata._metadata import (SampleMetadata, CategoricalMetadataColumn, NumericMetadataColumn) PANDAS_3 = Version(pd.__version__) >= Version("3.0.0") class TestInvalidMetadataConstruction(unittest.TestCase): def test_non_dataframe(self): with self.assertRaisesRegex( TypeError, 'Metadata constructor.*DataFrame.*not.*Series'): SampleMetadata(pd.Series([1, 2, 3], name='col', index=pd.Index(['a', 'b', 'c'], name='id'))) def test_no_ids(self): with self.assertRaisesRegex(ValueError, 'Metadata.*at least one ID'): SampleMetadata(pd.DataFrame({}, index=pd.Index([], name='id'))) with self.assertRaisesRegex(ValueError, 'Metadata.*at least one ID'): SampleMetadata(pd.DataFrame({'column': []}, index=pd.Index([], name='id'))) def test_invalid_id_header(self): # default index name with self.assertRaisesRegex(ValueError, r'Index\.name.*None'): SampleMetadata(pd.DataFrame( {'col': [1, 2, 3]}, index=pd.Index(['a', 'b', 'c']))) with self.assertRaisesRegex(ValueError, r'Index\.name.*my-id-header'): SampleMetadata(pd.DataFrame( {'col': [1, 2, 3]}, index=pd.Index(['a', 'b', 'c'], name='my-id-header'))) def test_non_str_id(self): with self.assertRaisesRegex( TypeError, 'non-string metadata ID.*type.*float.*nan'): SampleMetadata(pd.DataFrame( {'col': [1, 2, 3]}, index=pd.Index(['a', np.nan, 'c'], name='id'))) def test_non_str_column_name(self): with self.assertRaisesRegex( TypeError, 'non-string metadata column name.*type.*' 'float.*nan'): SampleMetadata(pd.DataFrame( {'col': [1, 2, 3], np.nan: [4, 5, 6]}, index=pd.Index(['a', 'b', 'c'], name='id'))) def test_empty_id(self): with self.assertRaisesRegex( ValueError, 'empty metadata ID.*at least one character'): SampleMetadata(pd.DataFrame( {'col': [1, 2, 3]}, index=pd.Index(['a', '', 'c'], name='id'))) def test_empty_column_name(self): with self.assertRaisesRegex( ValueError, 'empty metadata column name.*' 'at least one character'): SampleMetadata(pd.DataFrame( {'col': [1, 2, 3], '': [4, 5, 6]}, index=pd.Index(['a', 'b', 'c'], name='id'))) def test_pound_sign_id(self): with self.assertRaisesRegex( ValueError, "metadata ID.*begins with a pound sign.*'#b'"): SampleMetadata(pd.DataFrame( {'col': [1, 2, 3]}, index=pd.Index(['a', '#b', 'c'], name='id'))) def test_id_conflicts_with_id_header(self): with self.assertRaisesRegex( ValueError, "metadata ID 'sample-id'.*conflicts.*reserved.*" "ID header"): SampleMetadata(pd.DataFrame( {'col': [1, 2, 3]}, index=pd.Index(['a', 'sample-id', 'c'], name='id'))) def test_column_name_conflicts_with_id_header(self): with self.assertRaisesRegex( ValueError, "metadata column name 'featureid'.*conflicts.*" "reserved.*ID header"): SampleMetadata(pd.DataFrame( {'col': [1, 2, 3], 'featureid': [4, 5, 6]}, index=pd.Index(['a', 'b', 'c'], name='id'))) def test_duplicate_ids(self): with self.assertRaisesRegex(ValueError, "Metadata IDs.*unique.*'a'"): SampleMetadata(pd.DataFrame( {'col': [1, 2, 3]}, index=pd.Index(['a', 'b', 'a'], name='id'))) def test_duplicate_column_names(self): data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] with self.assertRaisesRegex(ValueError, "Metadata column names.*unique.*'col1'"): SampleMetadata(pd.DataFrame(data, columns=['col1', 'col2', 'col1'], index=pd.Index(['a', 'b', 'c'], name='id'))) def test_unsupported_column_dtype(self): with self.assertRaisesRegex( TypeError, "Metadata column 'col2'.*unsupported.*dtype.*bool"): SampleMetadata(pd.DataFrame( {'col1': [1, 2, 3], 'col2': [True, False, True]}, index=pd.Index(['a', 'b', 'c'], name='id'))) def test_categorical_column_unsupported_type(self): with self.assertRaisesRegex( TypeError, "CategoricalMetadataColumn.*strings or missing " r"values.*42\.5.*float.*'col2'"): SampleMetadata(pd.DataFrame( {'col1': [1, 2, 3], 'col2': ['foo', 'bar', 42.5]}, index=pd.Index(['a', 'b', 'c'], name='id'))) def test_categorical_column_empty_str(self): with self.assertRaisesRegex( ValueError, "CategoricalMetadataColumn.*empty strings.*" "column 'col2'"): SampleMetadata(pd.DataFrame( {'col1': [1, 2, 3], 'col2': ['foo', '', 'bar']}, index=pd.Index(['a', 'b', 'c'], name='id'))) def test_numeric_column_infinity(self): with self.assertRaisesRegex( ValueError, "NumericMetadataColumn.*positive or negative " "infinity.*column 'col2'"): SampleMetadata(pd.DataFrame( {'col1': ['foo', 'bar', 'baz'], 'col2': [42, float('+inf'), 4.3]}, index=pd.Index(['a', 'b', 'c'], name='id'))) def test_unknown_missing_scheme(self): with self.assertRaisesRegex(ValueError, "BAD:SCHEME"): SampleMetadata(pd.DataFrame( {'col1': [1, 2, 3], 'col2': ['foo', 'bar', 'bar']}, index=pd.Index(['a', 'b', 'c'], name='id')), default_missing_scheme='BAD:SCHEME') def test_missing_q2_error(self): index = pd.Index(['None', 'nan', 'NA', 'foo'], name='id') df = pd.DataFrame(collections.OrderedDict([ ('col1', [1.0, np.nan, np.nan, np.nan]), ('NA', [np.nan, np.nan, np.nan, np.nan]), ('col3', ['null', 'N/A', np.nan, 'NA']), ('col4', np.array([np.nan, np.nan, np.nan, np.nan], dtype=object))]), index=index) with self.assertRaisesRegex(ValueError, 'col1.*no-missing'): SampleMetadata(df, default_missing_scheme='no-missing') class TestMetadataConstructionAndProperties(unittest.TestCase): def assertEqualColumns(self, obs_columns, exp): obs = [(name, props.type) for name, props in obs_columns.items()] self.assertEqual(obs, exp) def test_minimal(self): md = SampleMetadata(pd.DataFrame({}, index=pd.Index(['a'], name='id'))) self.assertEqual(md.id_count, 1) self.assertEqual(md.column_count, 0) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('a',)) self.assertEqualColumns(md.columns, []) def test_single_id(self): index = pd.Index(['id1'], name='id') df = pd.DataFrame({'col1': [1.0], 'col2': ['a'], 'col3': ['foo']}, index=index) md = SampleMetadata(df) self.assertEqual(md.id_count, 1) self.assertEqual(md.column_count, 3) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('id1',)) self.assertEqualColumns(md.columns, [('col1', 'numeric'), ('col2', 'categorical'), ('col3', 'categorical')]) def test_no_columns(self): index = pd.Index(['id1', 'id2', 'foo'], name='id') df = pd.DataFrame({}, index=index) md = SampleMetadata(df) self.assertEqual(md.id_count, 3) self.assertEqual(md.column_count, 0) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('id1', 'id2', 'foo')) self.assertEqualColumns(md.columns, []) def test_single_column(self): index = pd.Index(['id1', 'a', 'my-id'], name='id') df = pd.DataFrame({'column': ['foo', 'bar', 'baz']}, index=index) md = SampleMetadata(df) self.assertEqual(md.id_count, 3) self.assertEqual(md.column_count, 1) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('id1', 'a', 'my-id')) self.assertEqualColumns(md.columns, [('column', 'categorical')]) def test_retains_column_order(self): # Supply DataFrame constructor with explicit column ordering instead of # a dict. index = pd.Index(['id1', 'id2', 'id3'], name='id') columns = ['z', 'a', 'ch'] data = [ [1.0, 'a', 'foo'], [2.0, 'b', 'bar'], [3.0, 'c', '42'] ] df = pd.DataFrame(data, index=index, columns=columns) md = SampleMetadata(df) self.assertEqual(md.id_count, 3) self.assertEqual(md.column_count, 3) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('id1', 'id2', 'id3')) self.assertEqualColumns(md.columns, [('z', 'numeric'), ('a', 'categorical'), ('ch', 'categorical')]) def test_supported_id_headers(self): case_insensitive = { 'id', 'sampleid', 'sample id', 'sample-id', 'featureid', 'feature id', 'feature-id' } exact_match = { '#SampleID', '#Sample ID', '#OTUID', '#OTU ID', 'sample_name' } # Build a set of supported headers, including exact matches and headers # with different casing. headers = set() for header in case_insensitive: headers.add(header) headers.add(header.upper()) headers.add(header.title()) for header in exact_match: headers.add(header) count = 0 for header in headers: index = pd.Index(['id1', 'id2'], name=header) df = pd.DataFrame({'column': ['foo', 'bar']}, index=index) md = SampleMetadata(df) self.assertEqual(md.id_header, header) count += 1 # Since this test case is a little complicated, make sure that the # expected number of comparisons are happening. self.assertEqual(count, 26) def test_recommended_ids(self): index = pd.Index(['c6ca034a-223f-40b4-a0e0-45942912a5ea', 'My.ID'], name='id') df = pd.DataFrame({'col1': ['foo', 'bar']}, index=index) md = SampleMetadata(df) self.assertEqual(md.id_count, 2) self.assertEqual(md.column_count, 1) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('c6ca034a-223f-40b4-a0e0-45942912a5ea', 'My.ID')) self.assertEqualColumns(md.columns, [('col1', 'categorical')]) def test_non_standard_characters(self): index = pd.Index(['©id##1', '((id))2', "'id_3<>'", '"id#4"', 'i d\r\t\n5'], name='id') columns = ['↩c@l1â„¢', 'col(#2)', "#col'3", '""', 'col\t \r\n5'] data = [ ['Æ’oo', '(foo)', '#f o #o', 'fo\ro', np.nan], ["''2''", 'b#r', 'ba\nr', np.nan, np.nan], ['b"ar', 'c\td', '4\r\n2', np.nan, np.nan], ['b__a_z', '<42>', '>42', np.nan, np.nan], ['baz', np.nan, '42'] ] df = pd.DataFrame(data, index=index, columns=columns) md = SampleMetadata(df) self.assertEqual(md.id_count, 5) self.assertEqual(md.column_count, 5) self.assertEqual(md.id_header, 'id') self.assertEqual( md.ids, ('©id##1', '((id))2', "'id_3<>'", '"id#4"', 'i d\r\t\n5')) self.assertEqualColumns(md.columns, [('↩c@l1â„¢', 'categorical'), ('col(#2)', 'categorical'), ("#col'3", 'categorical'), ('""', 'categorical'), ('col\t \r\n5', 'numeric')]) def test_missing_data(self): index = pd.Index(['None', 'nan', 'NA', 'foo'], name='id') df = pd.DataFrame(collections.OrderedDict([ ('col1', [1.0, np.nan, np.nan, np.nan]), ('NA', [np.nan, np.nan, np.nan, np.nan]), ('col3', ['null', 'N/A', np.nan, 'NA']), ('col4', np.array([np.nan, np.nan, np.nan, np.nan], dtype=object))]), index=index) md = SampleMetadata(df) self.assertEqual(md.id_count, 4) self.assertEqual(md.column_count, 4) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('None', 'nan', 'NA', 'foo')) self.assertEqualColumns(md.columns, [('col1', 'numeric'), ('NA', 'numeric'), ('col3', 'categorical'), ('col4', 'categorical')]) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_missing_data_insdc(self): index = pd.Index(['None', 'nan', 'NA', 'foo'], name='id') df = pd.DataFrame(collections.OrderedDict([ ('col1', [1.0, np.nan, 'missing', np.nan]), # TODO: it is not currently possible to have an ENTIRELY numeric # column from missing terms, as the dtype of the series is object # and there is not way to indicate the dtype beyond that. # ('NA', [np.nan, np.nan, 'not applicable', np.nan]), ('col3', ['null', 'N/A', 'not collected', 'NA']), ('col4', np.array([np.nan, np.nan, 'restricted access', np.nan], dtype=object))]), index=index) md = SampleMetadata(df, default_missing_scheme='INSDC:missing') self.assertEqual(md.id_count, 4) self.assertEqual(md.column_count, 3) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('None', 'nan', 'NA', 'foo')) self.assertEqualColumns(md.columns, [('col1', 'numeric'), ('col3', 'categorical'), ('col4', 'categorical')]) pd.testing.assert_frame_equal(md.to_dataframe(), pd.DataFrame( {'col1': [1.0, np.nan, np.nan, np.nan], 'col3': ['null', 'N/A', np.nan, 'NA'], 'col4': np.array([np.nan, np.nan, np.nan, np.nan], dtype=object)}, index=index)) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_missing_data_insdc_column_missing(self): index = pd.Index(['None', 'nan', 'NA', 'foo'], name='id') df = pd.DataFrame(collections.OrderedDict([ ('col1', [1.0, np.nan, 'missing', np.nan]), # TODO: it is not currently possible to have an ENTIRELY numeric # column from missing terms, as the dtype of the series is object # and there is not way to indicate the dtype beyond that. # ('NA', [np.nan, np.nan, 'not applicable', np.nan]), ('col3', ['null', 'N/A', 'not collected', 'NA']), ('col4', np.array([np.nan, np.nan, 'restricted access', np.nan], dtype=object))]), index=index) md = SampleMetadata(df, column_missing_schemes={ 'col1': 'INSDC:missing', 'col3': 'INSDC:missing', 'col4': 'INSDC:missing' }) self.assertEqual(md.id_count, 4) self.assertEqual(md.column_count, 3) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('None', 'nan', 'NA', 'foo')) self.assertEqualColumns(md.columns, [('col1', 'numeric'), ('col3', 'categorical'), ('col4', 'categorical')]) pd.testing.assert_frame_equal(md.to_dataframe(), pd.DataFrame( {'col1': [1.0, np.nan, np.nan, np.nan], 'col3': ['null', 'N/A', np.nan, 'NA'], 'col4': np.array([np.nan, np.nan, np.nan, np.nan], dtype=object)}, index=index)) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_missing_data_default_override(self): index = pd.Index(['None', 'nan', 'NA', 'foo'], name='id') df = pd.DataFrame(collections.OrderedDict([ ('col1', [1.0, np.nan, 'missing', np.nan]), # TODO: it is not currently possible to have an ENTIRELY numeric # column from missing terms, as the dtype of the series is object # and there is not way to indicate the dtype beyond that. # ('NA', [np.nan, np.nan, 'not applicable', np.nan]), ('col3', ['null', 'N/A', 'not collected', 'NA']), ('col4', np.array([np.nan, np.nan, 'restricted access', np.nan], dtype=object))]), index=index) md = SampleMetadata(df, column_missing_schemes={ 'col1': 'INSDC:missing', 'col3': 'INSDC:missing', 'col4': 'INSDC:missing' }, default_missing_scheme='no-missing') self.assertEqual(md.id_count, 4) self.assertEqual(md.column_count, 3) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('None', 'nan', 'NA', 'foo')) self.assertEqualColumns(md.columns, [('col1', 'numeric'), ('col3', 'categorical'), ('col4', 'categorical')]) pd.testing.assert_frame_equal(md.to_dataframe(), pd.DataFrame( {'col1': [1.0, np.nan, np.nan, np.nan], 'col3': ['null', 'N/A', np.nan, 'NA'], 'col4': np.array([np.nan, np.nan, np.nan, np.nan], dtype=object)}, index=index)) def test_does_not_cast_ids_or_column_names(self): index = pd.Index(['0.000001', '0.004000', '0.000000'], dtype=object, name='id') columns = ['42.0', '1000', '-4.2'] data = [ [2.0, 'b', 2.5], [1.0, 'b', 4.2], [3.0, 'c', -9.999] ] df = pd.DataFrame(data, index=index, columns=columns) md = SampleMetadata(df) self.assertEqual(md.id_count, 3) self.assertEqual(md.column_count, 3) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('0.000001', '0.004000', '0.000000')) self.assertEqualColumns(md.columns, [('42.0', 'numeric'), ('1000', 'categorical'), ('-4.2', 'numeric')]) def test_mixed_column_types(self): md = SampleMetadata( pd.DataFrame({'col0': [1.0, 2.0, 3.0], 'col1': ['a', 'b', 'c'], 'col2': ['foo', 'bar', '42'], 'col3': ['1.0', '2.5', '-4.002'], 'col4': [1, 2, 3], 'col5': [1, 2, 3.5], 'col6': [1e-4, -0.0002, np.nan], 'col7': ['cat', np.nan, 'dog'], 'col8': ['a', 'a', 'a'], 'col9': [0, 0, 0]}, index=pd.Index(['id1', 'id2', 'id3'], name='id'))) self.assertEqual(md.id_count, 3) self.assertEqual(md.column_count, 10) self.assertEqual(md.id_header, 'id') self.assertEqual(md.ids, ('id1', 'id2', 'id3')) self.assertEqualColumns(md.columns, [('col0', 'numeric'), ('col1', 'categorical'), ('col2', 'categorical'), ('col3', 'categorical'), ('col4', 'numeric'), ('col5', 'numeric'), ('col6', 'numeric'), ('col7', 'categorical'), ('col8', 'categorical'), ('col9', 'numeric')]) def test_case_insensitive_duplicate_ids(self): index = pd.Index(['a', 'b', 'A'], name='id') df = pd.DataFrame({'column': ['1', '2', '3']}, index=index) metadata = SampleMetadata(df) self.assertEqual(metadata.ids, ('a', 'b', 'A')) def test_case_insensitive_duplicate_column_names(self): index = pd.Index(['a', 'b', 'c'], name='id') df = pd.DataFrame({'column': ['1', '2', '3'], 'Column': ['4', '5', '6']}, index=index) metadata = SampleMetadata(df) self.assertEqual(set(metadata.columns), {'column', 'Column'}) def test_categorical_column_leading_trailing_whitespace_value(self): md1 = SampleMetadata(pd.DataFrame( {'col1': [1, 2, 3], 'col2': ['foo', ' bar ', 'baz']}, index=pd.Index(['a', 'b', 'c'], name='id'))) md2 = SampleMetadata(pd.DataFrame( {'col1': [1, 2, 3], 'col2': ['foo', 'bar', 'baz']}, index=pd.Index(['a', 'b', 'c'], name='id'))) self.assertEqual(md1, md2) def test_leading_trailing_whitespace_id(self): md1 = SampleMetadata(pd.DataFrame( {'col1': [1, 2, 3], 'col2': [4, 5, 6]}, index=pd.Index(['a', ' b ', 'c'], name='id'))) md2 = SampleMetadata(pd.DataFrame( {'col1': [1, 2, 3], 'col2': [4, 5, 6]}, index=pd.Index(['a', 'b', 'c'], name='id'))) self.assertEqual(md1, md2) def test_leading_trailing_whitespace_column_name(self): md1 = SampleMetadata(pd.DataFrame( {'col1': [1, 2, 3], ' col2 ': [4, 5, 6]}, index=pd.Index(['a', 'b', 'c'], name='id'))) md2 = SampleMetadata(pd.DataFrame( {'col1': [1, 2, 3], 'col2': [4, 5, 6]}, index=pd.Index(['a', 'b', 'c'], name='id'))) self.assertEqual(md1, md2) class TestRepr(unittest.TestCase): def test_singular(self): md = SampleMetadata(pd.DataFrame({'col1': [42]}, index=pd.Index(['a'], name='id'))) obs = repr(md) self.assertIn('Metadata', obs) self.assertIn('1 ID x 1 column', obs) self.assertIn("col1: ColumnProperties(type='numeric'," " missing_scheme='blank')", obs) def test_plural(self): md = SampleMetadata(pd.DataFrame({'col1': [42, 42], 'col2': ['foo', 'bar']}, index=pd.Index(['a', 'b'], name='id'))) obs = repr(md) self.assertIn('Metadata', obs) self.assertIn('2 IDs x 2 columns', obs) self.assertIn("col1: ColumnProperties(type='numeric'," " missing_scheme='blank')", obs) self.assertIn("col2: ColumnProperties(type='categorical'," " missing_scheme='blank')", obs) def test_column_name_padding(self): data = [[0, 42, 'foo']] index = pd.Index(['my-id'], name='id') columns = ['col1', 'longer-column-name', 'c'] md = SampleMetadata(pd.DataFrame(data, index=index, columns=columns)) obs = repr(md) self.assertIn('Metadata', obs) self.assertIn('1 ID x 3 columns', obs) self.assertIn( "col1: ColumnProperties(type='numeric'," " missing_scheme='blank')", obs) self.assertIn( "longer-column-name: ColumnProperties(type='numeric'," " missing_scheme='blank')", obs) self.assertIn( "c: ColumnProperties(type='categorical'," " missing_scheme='blank')", obs) class TestToDataframe(unittest.TestCase): def test_minimal(self): df = pd.DataFrame({}, index=pd.Index(['id1'], name='id')) md = SampleMetadata(df) obs = md.to_dataframe() pd.testing.assert_frame_equal(obs, df) def test_id_header_preserved(self): df = pd.DataFrame({'col1': [42, 2.5], 'col2': ['foo', 'bar']}, index=pd.Index(['id1', 'id2'], name='#SampleID')) md = SampleMetadata(df) obs = md.to_dataframe() # TODO: preserve string dtypes in `to_dataframe` pd.testing.assert_frame_equal(obs, df, check_dtype=False) self.assertEqual(obs.index.name, '#SampleID') def test_dataframe_copy(self): df = pd.DataFrame({'col1': [42, 2.5], 'col2': ['foo', 'bar']}, index=pd.Index(['id1', 'id2'], name='id')) md = SampleMetadata(df) obs = md.to_dataframe() # TODO: preserve string dtypes in `to_dataframe` pd.testing.assert_frame_equal(obs, df, check_dtype=False) self.assertIsNot(obs, df) def test_retains_column_order(self): index = pd.Index(['id1', 'id2'], name='id') columns = ['z', 'a', 'ch'] data = [ [1.0, 'a', 'foo'], [2.0, 'b', 'bar'] ] df = pd.DataFrame(data, index=index, columns=columns) md = SampleMetadata(df) obs = md.to_dataframe() # TODO: preserve string dtypes in `to_dataframe` pd.testing.assert_frame_equal(obs, df, check_dtype=False) self.assertEqual(obs.columns.tolist(), ['z', 'a', 'ch']) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_missing_data(self): # Different missing data representations should be normalized to np.nan index = pd.Index(['None', 'nan', 'NA', 'id1'], name='id') df = pd.DataFrame(collections.OrderedDict([ ('col1', [42.5, np.nan, float('nan'), 3]), ('NA', [np.nan, 'foo', float('nan'), None]), ('col3', ['null', 'N/A', np.nan, 'NA']), ('col4', np.array([np.nan, np.nan, np.nan, np.nan], dtype=object))]), index=index) md = SampleMetadata(df) obs = md.to_dataframe() exp = pd.DataFrame(collections.OrderedDict([ ('col1', [42.5, np.nan, np.nan, 3.0]), ('NA', [np.nan, 'foo', np.nan, np.nan]), ('col3', ['null', 'N/A', np.nan, 'NA']), ('col4', np.array([np.nan, np.nan, np.nan, np.nan], dtype=object))]), index=index) pd.testing.assert_frame_equal(obs, exp) self.assertEqual(obs.dtypes.to_dict(), {'col1': np.float64, 'NA': object, 'col3': object, 'col4': object}) self.assertTrue(np.isnan(obs['col1']['NA'])) self.assertTrue(np.isnan(obs['NA']['NA'])) self.assertTrue(np.isnan(obs['NA']['id1'])) def test_dtype_int_normalized_to_dtype_float(self): index = pd.Index(['id1', 'id2', 'id3'], name='id') df = pd.DataFrame({'col1': [42, -43, 0], 'col2': [42.0, -43.0, 0.0], 'col3': [42, np.nan, 0]}, index=index) self.assertEqual(df.dtypes.to_dict(), {'col1': np.int64, 'col2': np.float64, 'col3': np.float64}) md = SampleMetadata(df) obs = md.to_dataframe() exp = pd.DataFrame({'col1': [42.0, -43.0, 0.0], 'col2': [42.0, -43.0, 0.0], 'col3': [42.0, np.nan, 0.0]}, index=index) pd.testing.assert_frame_equal(obs, exp) self.assertEqual(obs.dtypes.to_dict(), {'col1': np.float64, 'col2': np.float64, 'col3': np.float64}) def test_encode_missing_no_missing(self): df = pd.DataFrame({'col1': [42.0, 50.0], 'col2': ['foo', 'bar']}, index=pd.Index(['id1', 'id2'], name='id')) md = SampleMetadata(df, default_missing_scheme='INSDC:missing') obs = md.to_dataframe(encode_missing=True) # TODO: preserve string dtypes in `to_dataframe` pd.testing.assert_frame_equal(obs, df, check_dtype=False) self.assertIsNot(obs, df) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_insdc_missing_encode_missing_true(self): df = pd.DataFrame({'col1': [42, 'missing'], 'col2': ['foo', 'not applicable']}, index=pd.Index(['id1', 'id2'], name='id')) md = SampleMetadata(df, default_missing_scheme='INSDC:missing') obs = md.to_dataframe(encode_missing=True) pd.testing.assert_frame_equal(obs, df) self.assertIsNot(obs, df) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_insdc_missing_encode_missing_false(self): df = pd.DataFrame({'col1': [42, 'missing'], 'col2': ['foo', 'not applicable']}, index=pd.Index(['id1', 'id2'], name='id')) md = SampleMetadata(df, default_missing_scheme='INSDC:missing') obs = md.to_dataframe() exp = pd.DataFrame({'col1': [42, np.nan], 'col2': ['foo', np.nan]}, index=pd.Index(['id1', 'id2'], name='id')) pd.testing.assert_frame_equal(obs, exp) self.assertIsNot(obs, df) class TestGetIDs(unittest.TestCase): def test_default(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'SampleType': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) metadata = SampleMetadata(df) actual = metadata.get_ids() expected = {'S1', 'S2', 'S3'} self.assertEqual(actual, expected) def test_incomplete_where(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'SampleType': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='sampleid')) metadata = SampleMetadata(df) where = "Subject='subject-1' AND SampleType=" with self.assertRaises(ValueError): metadata.get_ids(where) where = "Subject=" with self.assertRaises(ValueError): metadata.get_ids(where) def test_invalid_where(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'SampleType': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='sampleid')) metadata = SampleMetadata(df) where = "not-a-column-name='subject-1'" with self.assertRaises(ValueError): metadata.get_ids(where) def test_empty_result(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'SampleType': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) metadata = SampleMetadata(df) where = "Subject='subject-3'" actual = metadata.get_ids(where) expected = set() self.assertEqual(actual, expected) def test_simple_expression(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'SampleType': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) metadata = SampleMetadata(df) where = "Subject='subject-1'" actual = metadata.get_ids(where) expected = {'S1', 'S2'} self.assertEqual(actual, expected) where = "Subject='subject-2'" actual = metadata.get_ids(where) expected = {'S3'} self.assertEqual(actual, expected) where = "Subject='subject-3'" actual = metadata.get_ids(where) expected = set() self.assertEqual(actual, expected) where = "SampleType='gut'" actual = metadata.get_ids(where) expected = {'S1', 'S3'} self.assertEqual(actual, expected) where = "SampleType='tongue'" actual = metadata.get_ids(where) expected = {'S2'} self.assertEqual(actual, expected) def test_more_complex_expressions(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'SampleType': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) metadata = SampleMetadata(df) where = "Subject='subject-1' OR Subject='subject-2'" actual = metadata.get_ids(where) expected = {'S1', 'S2', 'S3'} self.assertEqual(actual, expected) where = "Subject='subject-1' AND Subject='subject-2'" actual = metadata.get_ids(where) expected = set() self.assertEqual(actual, expected) where = "Subject='subject-1' AND SampleType='gut'" actual = metadata.get_ids(where) expected = {'S1'} self.assertEqual(actual, expected) def test_query_by_id(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'SampleType': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) metadata = SampleMetadata(df) actual = metadata.get_ids(where="id='S2' OR id='S1'") expected = {'S1', 'S2'} self.assertEqual(actual, expected) def test_query_by_alternate_id_header(self): metadata = SampleMetadata(pd.DataFrame( {}, index=pd.Index(['id1', 'id2', 'id3'], name='#OTU ID'))) obs = metadata.get_ids(where="\"#OTU ID\" IN ('id2', 'id3')") exp = {'id2', 'id3'} self.assertEqual(obs, exp) def test_no_columns(self): metadata = SampleMetadata( pd.DataFrame({}, index=pd.Index(['a', 'b', 'my-id'], name='id'))) obs = metadata.get_ids() exp = {'a', 'b', 'my-id'} self.assertEqual(obs, exp) def test_query_mixed_column_types(self): df = pd.DataFrame({'Name': ['Foo', 'Bar', 'Baz', 'Baaz'], # numbers that would sort incorrectly as strings 'Age': [9, 10, 11, 101], 'Age_Str': ['9', '10', '11', '101'], 'Weight': [80.5, 85.3, np.nan, 120.0]}, index=pd.Index(['S1', 'S2', 'S3', 'S4'], name='id')) metadata = SampleMetadata(df) # string pattern matching obs = metadata.get_ids(where="Name LIKE 'Ba_'") exp = {'S2', 'S3'} self.assertEqual(obs, exp) # string comparison obs = metadata.get_ids(where="Age_Str >= 11") exp = {'S1', 'S3'} self.assertEqual(obs, exp) # numeric comparison obs = metadata.get_ids(where="Age >= 11") exp = {'S3', 'S4'} self.assertEqual(obs, exp) # numeric comparison with missing data obs = metadata.get_ids(where="Weight < 100") exp = {'S1', 'S2'} self.assertEqual(obs, exp) def test_column_with_space_in_name(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'Sample Type': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) metadata = SampleMetadata(df) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') metadata.get_ids() # The list of captured warnings should be empty self.assertFalse(w) class TestFilterIDs(unittest.TestCase): def test_default(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'SampleType': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) metadata = SampleMetadata(df) actual = metadata.filter_ids(['S1', 'S2']) self.assertSetEqual(actual.get_ids(), {'S1', 'S2'}) with self.assertRaisesRegex(ValueError, 'must contain at least one ID.'): metadata.filter_ids([]) with self.assertRaisesRegex(ValueError, 'must contain unique IDs.'): metadata.filter_ids(['S2', 'S2']) with self.assertRaisesRegex(ValueError, 'IDs are not present'): metadata.filter_ids(['S1', 'S4']) class TestGetColumn(unittest.TestCase): def test_default(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'SampleType': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) metadata = SampleMetadata(df) actual = metadata.get_column('Subject') self.assertIsInstance(actual, CategoricalMetadataColumn) with self.assertRaisesRegex(ValueError, 'not a column in the metadata.'): metadata.get_column('not_a_column') class TestFilterColumns(unittest.TestCase): def test_default(self): df = pd.DataFrame({'Subject': ['subject-1', 'subject-2', 'subject-3'], 'SampleType': ['gut', 'tongue', 'gut'], 'Height': [187, 165, 174], 'Weight': [75, 75, 75], 'Species': ['Human', 'Human', 'Human']}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) metadata = SampleMetadata(df) with self.assertRaisesRegex(ValueError, 'Unknown column type'): metadata.filter_columns(column_type='hello') actual = metadata.filter_columns(column_type='numeric') self.assertEqual(actual.column_count, 2) self.assertListEqual(list(actual.columns.keys()), ['Height', 'Weight']) actual = metadata.filter_columns(drop_all_unique=True) self.assertEqual(actual.column_count, 3) self.assertListEqual(list(actual.columns.keys()), ['SampleType', 'Weight', 'Species']) actual = metadata.filter_columns(drop_zero_variance=True) self.assertEqual(actual.column_count, 3) self.assertListEqual(list(actual.columns.keys()), ['Subject', 'SampleType', 'Height']) df = pd.DataFrame({'Subject': ['subject-1', 'subject-2', 'subject-3'], 'SampleType': [np.nan, np.nan, np.nan]}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) metadata = SampleMetadata(df) actual = metadata.filter_columns(drop_all_missing=True) self.assertEqual(actual.column_count, 1) self.assertListEqual(list(actual.columns.keys()), ['Subject']) class TestMerge(unittest.TestCase): def assertEqualColumns(self, obs_columns, exp): obs = [(name, props.type) for name, props in obs_columns.items()] self.assertEqual(obs, exp) def test_default(self): df1 = pd.DataFrame({'Subject': ['subject-1', 'subject-1', 'subject-2'], 'SampleType': ['gut', 'tongue', 'gut']}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) md1 = SampleMetadata(df1) df2 = pd.DataFrame({'Height': [187, 165, 174]}, index=pd.Index(['S1', 'S2', 'S3'], name='id')) md2 = SampleMetadata(df2) actual = md1.merge(md2) self.assertIsInstance(actual, SampleMetadata) self.assertEqual(actual.id_count, 3) self.assertEqual(actual.ids, ('S1', 'S2', 'S3')) self.assertEqual(actual.column_count, 3) self.assertEqualColumns(actual.columns, [ ('Subject', 'categorical'), ('SampleType', 'categorical'), ('Height', 'numeric')]) with self.assertRaisesRegex(ValueError, 'metadata with overlapping columns'): md1.merge(md1) df3 = pd.DataFrame({'Weight': [78, 56, 63]}, index=pd.Index(['S4', 'S5', 'S6'], name='id')) md3 = SampleMetadata(df3) with self.assertRaisesRegex(ValueError, 'no IDs shared across metadata'): md1.merge(md3) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/test_metadata_column.py000066400000000000000000001024631520735541300271600ustar00rootroot00000000000000import os.path import tempfile import unittest from packaging.version import Version import pandas as pd import numpy as np from skbio.metadata._metadata import (MetadataColumn, CategoricalMetadataColumn, NumericMetadataColumn) PANDAS_3 = Version(pd.__version__) >= Version("3.0.0") # Dummy class for testing MetadataColumn ABC class DummyMetadataColumn(MetadataColumn): type = 'dummy' supported_dtypes = ("float", "int", "int64") @classmethod def _is_supported_dtype(cls, dtype): return dtype == 'float' or dtype == 'int' or dtype == 'int64' @classmethod def _normalize_(cls, series): return series.astype(float, errors='raise').copy() class TestInvalidMetadataColumnConstruction(unittest.TestCase): def test_non_series(self): with self.assertRaisesRegex( TypeError, 'DummyMetadataColumn constructor.*Series.*not.*' 'DataFrame'): DummyMetadataColumn(pd.DataFrame( {'col1': [1, 2, 3]}, index=pd.Index(['a', 'b', 'c'], name='id'))) def test_no_ids(self): with self.assertRaisesRegex(ValueError, 'DummyMetadataColumn.*at least one ID'): DummyMetadataColumn(pd.Series([], name='col', index=pd.Index([], name='id'), dtype=object)) def test_invalid_id_header(self): # default index name with self.assertRaisesRegex(ValueError, r'Index\.name.*None'): DummyMetadataColumn(pd.Series([1, 2, 3], name='col', index=pd.Index(['a', 'b', 'c'], dtype=object))) with self.assertRaisesRegex(ValueError, r'Index\.name.*my-id-header'): DummyMetadataColumn(pd.Series( [1, 2, 3], name='col', index=pd.Index(['a', 'b', 'c'], name='my-id-header'))) def test_non_str_id(self): with self.assertRaisesRegex( TypeError, 'non-string metadata ID.*type.*float.*nan'): DummyMetadataColumn(pd.Series( [1, 2, 3], name='col', index=pd.Index(['a', np.nan, 'c'], name='id'))) def test_non_str_column_name(self): # default series name with self.assertRaisesRegex( TypeError, 'non-string metadata column name.*type.*' 'NoneType.*None'): DummyMetadataColumn(pd.Series( [1, 2, 3], index=pd.Index(['a', 'b', 'c'], name='id'))) with self.assertRaisesRegex( TypeError, 'non-string metadata column name.*type.*' 'float.*nan'): DummyMetadataColumn(pd.Series( [1, 2, 3], name=np.nan, index=pd.Index(['a', 'b', 'c'], name='id'))) def test_empty_id(self): with self.assertRaisesRegex( ValueError, 'empty metadata ID.*at least one character'): DummyMetadataColumn(pd.Series( [1, 2, 3], name='col', index=pd.Index(['a', '', 'c'], name='id'))) def test_empty_column_name(self): with self.assertRaisesRegex( ValueError, 'empty metadata column name.*' 'at least one character'): DummyMetadataColumn(pd.Series( [1, 2, 3], name='', index=pd.Index(['a', 'b', 'c'], name='id'))) def test_pound_sign_id(self): with self.assertRaisesRegex( ValueError, "metadata ID.*begins with a pound sign.*'#b'"): DummyMetadataColumn(pd.Series( [1, 2, 3], name='col', index=pd.Index(['a', '#b', 'c'], name='id'))) def test_id_conflicts_with_id_header(self): with self.assertRaisesRegex( ValueError, "metadata ID 'sample-id'.*conflicts.*reserved.*" "ID header"): DummyMetadataColumn(pd.Series( [1, 2, 3], name='col', index=pd.Index(['a', 'sample-id', 'c'], name='id'))) def test_column_name_conflicts_with_id_header(self): with self.assertRaisesRegex( ValueError, "metadata column name 'featureid'.*conflicts.*" "reserved.*ID header"): DummyMetadataColumn(pd.Series( [1, 2, 3], name='featureid', index=pd.Index(['a', 'b', 'c'], name='id'))) def test_duplicate_ids(self): with self.assertRaisesRegex(ValueError, "Metadata IDs.*unique.*'a'"): DummyMetadataColumn(pd.Series( [1, 2, 3], name='col', index=pd.Index(['a', 'b', 'a'], name='id'))) def test_unsupported_column_dtype(self): with self.assertRaisesRegex( TypeError, "DummyMetadataColumn 'col1' does not support.*" "Series.*dtype.*bool"): DummyMetadataColumn(pd.Series( [True, False, True], name='col1', index=pd.Index(['a', 'b', 'c'], name='id'))) def test_unknown_missing_scheme(self): with self.assertRaisesRegex(ValueError, "BAD:SCHEME"): DummyMetadataColumn(pd.Series( [1, 2, 3], name='col1', index=pd.Index(['a', 'b', 'c'], name='id')), missing_scheme='BAD:SCHEME') def test_missing_q2_error(self): with self.assertRaisesRegex(ValueError, "col1.*no-missing"): DummyMetadataColumn(pd.Series( [1, np.nan, 3], name='col1', index=pd.Index(['a', 'b', 'c'], name='id')), missing_scheme='no-missing') class TestMetadataColumnConstructionAndProperties(unittest.TestCase): def test_single_id(self): index = pd.Index(['id1'], name='id') series = pd.Series([42], name='col1', index=index) mdc = DummyMetadataColumn(series) self.assertEqual(mdc.id_count, 1) self.assertEqual(mdc.id_header, 'id') self.assertEqual(mdc.ids, ('id1',)) self.assertEqual(mdc.name, 'col1') def test_multiple_ids(self): index = pd.Index(['id1', 'a', 'my-id'], name='id') series = pd.Series([42, 4.2, -4.2], name='column', index=index) mdc = DummyMetadataColumn(series) self.assertEqual(mdc.id_count, 3) self.assertEqual(mdc.id_header, 'id') self.assertEqual(mdc.ids, ('id1', 'a', 'my-id')) self.assertEqual(mdc.name, 'column') def test_supported_id_headers(self): case_insensitive = { 'id', 'sampleid', 'sample id', 'sample-id', 'featureid', 'feature id', 'feature-id' } exact_match = { '#SampleID', '#Sample ID', '#OTUID', '#OTU ID', 'sample_name' } # Build a set of supported headers, including exact matches and headers # with different casing. headers = set() for header in case_insensitive: headers.add(header) headers.add(header.upper()) headers.add(header.title()) for header in exact_match: headers.add(header) count = 0 for header in headers: index = pd.Index(['id1', 'id2'], name=header) series = pd.Series([0, 123], name='column', index=index) mdc = DummyMetadataColumn(series) self.assertEqual(mdc.id_header, header) count += 1 # Since this test case is a little complicated, make sure that the # expected number of comparisons are happening. self.assertEqual(count, 26) def test_recommended_ids(self): index = pd.Index(['c6ca034a-223f-40b4-a0e0-45942912a5ea', 'My.ID'], name='id') series = pd.Series([-1, -2], name='col1', index=index) mdc = DummyMetadataColumn(series) self.assertEqual(mdc.id_count, 2) self.assertEqual(mdc.id_header, 'id') self.assertEqual(mdc.ids, ('c6ca034a-223f-40b4-a0e0-45942912a5ea', 'My.ID')) self.assertEqual(mdc.name, 'col1') def test_non_standard_characters(self): index = pd.Index(['©id##1', '((id))2', "'id_3<>'", '"id#4"', 'i d\r\t\n5'], name='id') series = pd.Series([0, 1, 2, 3, 4], name='↩c@l1â„¢', index=index) mdc = DummyMetadataColumn(series) self.assertEqual(mdc.id_count, 5) self.assertEqual(mdc.id_header, 'id') self.assertEqual( mdc.ids, ('©id##1', '((id))2', "'id_3<>'", '"id#4"', 'i d\r\t\n5')) self.assertEqual(mdc.name, '↩c@l1â„¢') def test_missing_data(self): index = pd.Index(['None', 'nan', 'NA'], name='id') series = pd.Series([np.nan, np.nan, np.nan], name='NA', index=index) mdc = DummyMetadataColumn(series) self.assertEqual(mdc.id_count, 3) self.assertEqual(mdc.id_header, 'id') self.assertEqual(mdc.ids, ('None', 'nan', 'NA')) self.assertEqual(mdc.name, 'NA') def test_missing_insdc(self): index = pd.Index(['None', 'nan', 'NA'], name='id') # TODO: note we cannot make a numeric style column of entirely encoded # nans, as there's no way to indicate the true type of the column series = pd.Series(['missing', 'not applicable', 5.0], name='NA', index=index) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') self.assertEqual(mdc.id_count, 3) self.assertEqual(mdc.id_header, 'id') self.assertEqual(mdc.ids, ('None', 'nan', 'NA')) self.assertEqual(mdc.name, 'NA') pd.testing.assert_series_equal( mdc.to_series(), pd.Series( [np.nan, np.nan, 5.0], name='NA', index=index)) def test_does_not_cast_ids_or_column_name(self): index = pd.Index(['0.000001', '0.004000', '0.000000'], dtype=object, name='id') series = pd.Series([2.0, 1.0, 3.0], name='42.0', index=index) mdc = DummyMetadataColumn(series) self.assertEqual(mdc.id_count, 3) self.assertEqual(mdc.id_header, 'id') self.assertEqual(mdc.ids, ('0.000001', '0.004000', '0.000000')) self.assertEqual(mdc.name, '42.0') def test_case_insensitive_duplicate_ids(self): index = pd.Index(['a', 'b', 'A'], name='id') series = pd.Series([1, 2, 3], name='column', index=index) mdc = DummyMetadataColumn(series) self.assertEqual(mdc.ids, ('a', 'b', 'A')) class TestRepr(unittest.TestCase): def test_single_id(self): mdc = DummyMetadataColumn(pd.Series( [42], name='foo', index=pd.Index(['id1'], name='id'))) obs = repr(mdc) self.assertEqual(obs, "") def test_multiple_ids(self): mdc = DummyMetadataColumn(pd.Series( [42, 43, 44], name='my column', index=pd.Index(['id1', 'id2', 'id3'], name='id'))) obs = repr(mdc) self.assertEqual( obs, "") # Extensive tests of the MetadataWriter are performed in test_io.py. This test # is a sanity check that a new MetadataColumn subclass (DummyMetadataColumn) # can be written to disk with its column type preserved. This test would have # caught a bug in the original implementation of MetadataColumn.save(), which # converted itself into a Metadata object, losing the "dummy" column type and # replacing it with "numeric". In order for a MetadataColumn to turn itself # into a Metadata object in a lossless/safe way, the Metadata constructor needs # a `column_types` parameter to preserve column types. class TestSave(unittest.TestCase): def setUp(self): self.temp_dir_obj = tempfile.TemporaryDirectory( prefix='qiime2-metadata-tests-temp-') self.temp_dir = self.temp_dir_obj.name self.filepath = os.path.join(self.temp_dir, 'metadata.tsv') def tearDown(self): self.temp_dir_obj.cleanup() def test_basic(self): mdc = DummyMetadataColumn(pd.Series( [42, 42.5, -999.123], name='dummy-column', index=pd.Index(['id1', 'id2', 'id3'], name='id'))) mdc.save(self.filepath) with open(self.filepath, 'r') as fh: obs = fh.read() exp = ( "id\tdummy-column\n" "#sk:types\tdummy\n" "id1\t42\n" "id2\t42.5\n" "id3\t-999.123\n" ) self.assertEqual(obs, exp) class TestToSeries(unittest.TestCase): def test_single_id(self): series = pd.Series([0.0], name='col', index=pd.Index(['id1'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.to_series() pd.testing.assert_series_equal(obs, series) def test_multiple_ids(self): series = pd.Series([-1.5, np.nan, 42], name='col', index=pd.Index(['id1', 'id2', 'id3'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.to_series() pd.testing.assert_series_equal(obs, series) def test_id_header_preserved(self): series = pd.Series( [-1.5, 0.0, 42], name='col', index=pd.Index(['id1', 'id2', 'id3'], name='#OTU ID')) mdc = DummyMetadataColumn(series) obs = mdc.to_series() pd.testing.assert_series_equal(obs, series) self.assertEqual(obs.index.name, '#OTU ID') def test_series_copy(self): series = pd.Series([1, 2.5, 3], name='col', index=pd.Index(['id1', 'id2', 'id3'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.to_series() pd.testing.assert_series_equal(obs, series) self.assertIsNot(obs, series) def test_encode_missing_no_missing(self): series = pd.Series([1, 2.5, 3], name='col', index=pd.Index(['id1', 'id2', 'id3'], name='id')) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') obs = mdc.to_series(encode_missing=True) pd.testing.assert_series_equal(obs, series) self.assertIsNot(obs, series) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_encode_missing_true(self): series = pd.Series([1, 2.5, 'missing'], name='col', index=pd.Index(['id1', 'id2', 'id3'], name='id')) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') obs = mdc.to_series(encode_missing=True) pd.testing.assert_series_equal(obs, series) self.assertIsNot(obs, series) def test_encode_missing_false(self): series = pd.Series([1, 2.5, 'missing'], name='col', index=pd.Index(['id1', 'id2', 'id3'], name='id')) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') obs = mdc.to_series() exp = pd.Series([1, 2.5, np.nan], name='col', index=pd.Index(['id1', 'id2', 'id3'], name='id')) pd.testing.assert_series_equal(obs, exp) self.assertIsNot(obs, series) class TestToDataframe(unittest.TestCase): def test_single_id(self): series = pd.Series([0.0], name='col', index=pd.Index(['id1'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.to_dataframe() exp = pd.DataFrame({'col': [0.0]}, index=pd.Index(['id1'], name='id')) pd.testing.assert_frame_equal(obs, exp) def test_multiple_ids(self): series = pd.Series([0.0, 4.2, np.nan], name='my column', index=pd.Index(['a', 'b', 'c'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.to_dataframe() exp = pd.DataFrame({'my column': [0.0, 4.2, np.nan]}, index=pd.Index(['a', 'b', 'c'], name='id')) pd.testing.assert_frame_equal(obs, exp) def test_id_header_preserved(self): series = pd.Series([0.0, 4.2, 123], name='my column', index=pd.Index(['a', 'b', 'c'], name='#Sample ID')) mdc = DummyMetadataColumn(series) obs = mdc.to_dataframe() exp = pd.DataFrame({'my column': [0.0, 4.2, 123]}, index=pd.Index(['a', 'b', 'c'], name='#Sample ID')) pd.testing.assert_frame_equal(obs, exp) self.assertEqual(obs.index.name, '#Sample ID') def test_encode_missing_no_missing(self): series = pd.Series([1, 2.5, 3], name='col', index=pd.Index(['id1', 'id2', 'id3'], name='id')) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') obs = mdc.to_dataframe(encode_missing=True) exp = pd.DataFrame({'col': series}, index=series.index) pd.testing.assert_frame_equal(obs, exp) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_encode_missing_true(self): series = pd.Series([1, 2.5, 'missing'], name='col', index=pd.Index(['id1', 'id2', 'id3'], name='id')) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') obs = mdc.to_dataframe(encode_missing=True) exp = pd.DataFrame({'col': series}, index=series.index) pd.testing.assert_frame_equal(obs, exp) def test_encode_missing_false(self): series = pd.Series([1, 2.5, 'missing'], name='col', index=pd.Index(['id1', 'id2', 'id3'], name='id')) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') obs = mdc.to_dataframe() exp = pd.DataFrame({'col': [1, 2.5, np.nan]}, index=series.index) pd.testing.assert_frame_equal(obs, exp) class TestGetValue(unittest.TestCase): def test_id_not_found(self): series = pd.Series([1, 2, 3], name='col1', index=pd.Index(['a', 'b', 'c'], name='id')) mdc = DummyMetadataColumn(series) with self.assertRaisesRegex( ValueError, "'d' is not present.*DummyMetadataColumn.*'col1'"): mdc.get_value('d') def test_get_value(self): series = pd.Series([1, 2, np.nan], name='col1', index=pd.Index(['a', 'b', 'c'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.get_value('a') self.assertEqual(obs, 1.0) obs = mdc.get_value('b') self.assertEqual(obs, 2.0) obs = mdc.get_value('c') self.assertTrue(np.isnan(obs)) class TestHasMissingValues(unittest.TestCase): def test_no_missing_values(self): series = pd.Series([0.0, 2.2, 3.3], name='col1', index=pd.Index(['a', 'b', 'c'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.has_missing_values() self.assertEqual(obs, False) def test_with_missing_values(self): series = pd.Series([0.0, np.nan, 3.3], name='col1', index=pd.Index(['a', 'b', 'c'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.has_missing_values() self.assertEqual(obs, True) class TestDropMissingValues(unittest.TestCase): def test_no_missing_values(self): series = pd.Series([0.0, 2.2, 3.3], name='col1', index=pd.Index(['a', 'b', 'c'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.drop_missing_values() self.assertEqual(obs, mdc) self.assertIsNot(obs, mdc) def test_with_missing_values(self): series = pd.Series( [0.0, np.nan, 3.3, np.nan, np.nan, 4.4], name='col1', index=pd.Index(['a', 'b', 'c', 'd', 'e', 'f'], name='sampleid')) mdc = DummyMetadataColumn(series) obs = mdc.drop_missing_values() exp = DummyMetadataColumn(pd.Series( [0.0, 3.3, 4.4], name='col1', index=pd.Index(['a', 'c', 'f'], name='sampleid'))) self.assertEqual(obs, exp) def test_with_missing_scheme(self): series = pd.Series( [0.0, np.nan, 3.3, 'missing', 'not applicable', 4.4], name='col1', index=pd.Index(['a', 'b', 'c', 'd', 'e', 'f'], name='sampleid')) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') obs = mdc.drop_missing_values() exp = DummyMetadataColumn(pd.Series( [0.0, 3.3, 4.4], name='col1', index=pd.Index(['a', 'c', 'f'], name='sampleid'))) self.assertEqual(obs, exp) class TestGetIDs(unittest.TestCase): def test_single_id(self): series = pd.Series([1.234], name='col1', index=pd.Index(['my id'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.get_ids() self.assertEqual(obs, {'my id'}) def test_multiple_ids(self): series = pd.Series( [1.234, np.nan, 5.67, np.nan, 8.9], name='col1', index=pd.Index(['id1', 'id2', 'id3', 'id4', 'id5'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.get_ids() self.assertEqual(obs, {'id1', 'id2', 'id3', 'id4', 'id5'}) def test_where_values_missing(self): series = pd.Series( [1.234, np.nan, 5.67, np.nan, 8.9], name='col1', index=pd.Index(['id1', 'id2', 'id3', 'id4', 'id5'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.get_ids(where_values_missing=True) self.assertEqual(obs, {'id2', 'id4'}) def test_where_values_missing_all_missing(self): series = pd.Series( [np.nan, np.nan, np.nan], name='col1', index=pd.Index(['id1', 'id2', 'id3'], name='id')) mdc = DummyMetadataColumn(series) obs = mdc.get_ids(where_values_missing=True) self.assertEqual(obs, {'id1', 'id2', 'id3'}) class TestGetMissing(unittest.TestCase): @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_missing_mixed(self): series = pd.Series( [0.0, np.nan, 3.3, 'missing', 'not applicable', 4.4], name='col1', index=pd.Index(['a', 'b', 'c', 'd', 'e', 'f'], name='sampleid')) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') missing = mdc.get_missing() exp = pd.Series([np.nan, 'missing', 'not applicable'], name='col1', index=pd.Index(['b', 'd', 'e'], name='sampleid')) pd.testing.assert_series_equal(missing, exp) def test_missing_blanks(self): series = pd.Series( [0.0, np.nan, 3.3, np.nan, np.nan, 4.4], name='col1', index=pd.Index(['a', 'b', 'c', 'd', 'e', 'f'], name='sampleid')) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') missing = mdc.get_missing() exp = pd.Series([np.nan, np.nan, np.nan], name='col1', dtype=object, index=pd.Index(['b', 'd', 'e'], name='sampleid')) pd.testing.assert_series_equal(missing, exp) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_no_missing(self): series = pd.Series( [0.0, 1.1, 3.3, 3.5, 4.0, 4.4], name='col1', index=pd.Index(['a', 'b', 'c', 'd', 'e', 'f'], name='sampleid')) mdc = DummyMetadataColumn(series, missing_scheme='INSDC:missing') missing = mdc.get_missing() exp = pd.Series([], name='col1', dtype=object, index=pd.Index([], name='sampleid')) pd.testing.assert_series_equal(missing, exp) # The tests for CategoricalMetadataColumn and NumericMetadataColumn only test # behavior specific to these subclasses. More extensive tests of these objects # are performed above by testing the MetadataColumn ABC in a generic way. class TestCategoricalMetadataColumn(unittest.TestCase): def test_unsupported_dtype(self): with self.assertRaisesRegex( TypeError, "CategoricalMetadataColumn 'col1' does not support" ".*Series.*dtype.*float64"): CategoricalMetadataColumn(pd.Series( [42.5, 42.6, 42.7], name='col1', index=pd.Index(['a', 'b', 'c'], name='id'))) def test_unsupported_type_value(self): with self.assertRaisesRegex( TypeError, "CategoricalMetadataColumn.*strings or missing " r"values.*42\.5.*float.*'col1'"): CategoricalMetadataColumn(pd.Series( ['foo', 'bar', 42.5], name='col1', index=pd.Index(['a', 'b', 'c'], name='id'))) def test_empty_str_value(self): with self.assertRaisesRegex( ValueError, "CategoricalMetadataColumn.*empty strings.*" "column 'col1'"): CategoricalMetadataColumn(pd.Series( ['foo', '', 'bar'], name='col1', index=pd.Index(['a', 'b', 'c'], name='id'))) def test_type_property(self): self.assertEqual(CategoricalMetadataColumn.type, 'categorical') @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_supported_dtype(self): series = pd.Series( ['foo', np.nan, 'bar', 'foo'], name='my column', index=pd.Index(['a', 'b', 'c', 'd'], name='id')) mdc = CategoricalMetadataColumn(series) self.assertEqual(mdc.id_count, 4) self.assertEqual(mdc.id_header, 'id') self.assertEqual(mdc.ids, ('a', 'b', 'c', 'd')) self.assertEqual(mdc.name, 'my column') obs_series = mdc.to_series() pd.testing.assert_series_equal(obs_series, series) self.assertEqual(obs_series.dtype, object) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_numeric_strings_preserved_as_strings(self): series = pd.Series( ['1', np.nan, '2.5', '3.0'], name='my column', index=pd.Index(['a', 'b', 'c', 'd'], name='id')) mdc = CategoricalMetadataColumn(series) self.assertEqual(mdc.id_count, 4) self.assertEqual(mdc.id_header, 'id') self.assertEqual(mdc.ids, ('a', 'b', 'c', 'd')) self.assertEqual(mdc.name, 'my column') obs_series = mdc.to_series() pd.testing.assert_series_equal(obs_series, series) self.assertEqual(obs_series.dtype, object) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_missing_data_normalized(self): # Different missing data representations should be normalized to np.nan mdc = CategoricalMetadataColumn(pd.Series( [np.nan, 'foo', float('nan'), None], name='col1', index=pd.Index(['a', 'b', 'c', 'd'], name='id'))) obs = mdc.to_series() exp = pd.Series( [np.nan, 'foo', np.nan, np.nan], name='col1', index=pd.Index(['a', 'b', 'c', 'd'], name='id')) pd.testing.assert_series_equal(obs, exp) self.assertEqual(obs.dtype, object) self.assertTrue(np.isnan(obs['a'])) self.assertTrue(np.isnan(obs['c'])) self.assertTrue(np.isnan(obs['d'])) def test_all_missing_data(self): mdc = CategoricalMetadataColumn(pd.Series( np.array([np.nan, np.nan, np.nan], dtype=object), name='col1', index=pd.Index(['a', 'b', 'c'], name='id'))) obs = mdc.to_series() exp = pd.Series( np.array([np.nan, np.nan, np.nan], dtype=object), name='col1', index=pd.Index(['a', 'b', 'c'], name='id')) pd.testing.assert_series_equal(obs, exp) self.assertEqual(obs.dtype, object) def test_leading_trailing_whitespace_value(self): col1 = CategoricalMetadataColumn(pd.Series( ['foo', ' bar ', 'baz'], name='col1', index=pd.Index(['a', 'b', 'c'], name='id'))) col2 = CategoricalMetadataColumn(pd.Series( ['foo', 'bar', 'baz'], name='col1', index=pd.Index(['a', 'b', 'c'], name='id'))) self.assertEqual(col1, col2) def test_leading_trailing_whitespace_id(self): col1 = CategoricalMetadataColumn(pd.Series( ['foo', ' bar ', 'baz'], name='col', index=pd.Index(['a', ' b ', 'c'], name='id'))) col2 = CategoricalMetadataColumn(pd.Series( ['foo', ' bar ', 'baz'], name='col', index=pd.Index(['a', 'b', 'c'], name='id'))) self.assertEqual(col1, col2) def test_leading_trailing_whitespace_column_name(self): col1 = CategoricalMetadataColumn(pd.Series( ['foo', ' bar ', 'baz'], name=' col ', index=pd.Index(['a', 'b', 'c'], name='id'))) col2 = CategoricalMetadataColumn(pd.Series( ['foo', ' bar ', 'baz'], name='col', index=pd.Index(['a', 'b', 'c'], name='id'))) self.assertEqual(col1, col2) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_missing_insdc(self): mdc = CategoricalMetadataColumn(pd.Series( ['missing', 'foo', float('nan'), None], name='col1', index=pd.Index(['a', 'b', 'c', 'd'], name='id')), missing_scheme='INSDC:missing') obs = mdc.to_series() exp = pd.Series( [np.nan, 'foo', np.nan, np.nan], name='col1', index=pd.Index(['a', 'b', 'c', 'd'], name='id')) pd.testing.assert_series_equal(obs, exp) self.assertEqual(obs.dtype, object) self.assertTrue(np.isnan(obs['a'])) self.assertTrue(np.isnan(obs['c'])) self.assertTrue(np.isnan(obs['d'])) class TestNumericMetadataColumn(unittest.TestCase): def test_unsupported_dtype(self): with self.assertRaisesRegex( TypeError, "NumericMetadataColumn 'col1' does not support" ".*Series.*dtype.*bool"): NumericMetadataColumn(pd.Series( [True, False, True], name='col1', index=pd.Index(['a', 'b', 'c'], name='id'))) def test_infinity_value(self): with self.assertRaisesRegex( ValueError, "NumericMetadataColumn.*positive or negative " "infinity.*column 'col1'"): NumericMetadataColumn(pd.Series( [42, float('+inf'), 4.3], name='col1', index=pd.Index(['a', 'b', 'c'], name='id'))) def test_type_property(self): self.assertEqual(NumericMetadataColumn.type, 'numeric') def test_supported_dtype_float(self): series = pd.Series( [1.23, np.nan, 4.56, -7.891], name='my column', index=pd.Index(['a', 'b', 'c', 'd'], name='id')) mdc = NumericMetadataColumn(series) self.assertEqual(mdc.id_count, 4) self.assertEqual(mdc.id_header, 'id') self.assertEqual(mdc.ids, ('a', 'b', 'c', 'd')) self.assertEqual(mdc.name, 'my column') obs_series = mdc.to_series() pd.testing.assert_series_equal(obs_series, series) self.assertEqual(obs_series.dtype, np.float64) def test_supported_dtype_int(self): series = pd.Series( [0, 1, 42, -2], name='my column', index=pd.Index(['a', 'b', 'c', 'd'], name='id')) mdc = NumericMetadataColumn(series) self.assertEqual(mdc.id_count, 4) self.assertEqual(mdc.id_header, 'id') self.assertEqual(mdc.ids, ('a', 'b', 'c', 'd')) self.assertEqual(mdc.name, 'my column') obs_series = mdc.to_series() exp_series = pd.Series( [0.0, 1.0, 42.0, -2.0], name='my column', index=pd.Index(['a', 'b', 'c', 'd'], name='id')) pd.testing.assert_series_equal(obs_series, exp_series) self.assertEqual(obs_series.dtype, np.float64) def test_missing_data_normalized(self): # Different missing data representations should be normalized to np.nan mdc = NumericMetadataColumn(pd.Series( [np.nan, 4.2, float('nan'), -5.678], name='col1', index=pd.Index(['a', 'b', 'c', 'd'], name='id'))) obs = mdc.to_series() exp = pd.Series( [np.nan, 4.2, np.nan, -5.678], name='col1', index=pd.Index(['a', 'b', 'c', 'd'], name='id')) pd.testing.assert_series_equal(obs, exp) self.assertEqual(obs.dtype, np.float64) self.assertTrue(np.isnan(obs['a'])) self.assertTrue(np.isnan(obs['c'])) def test_all_missing_data(self): mdc = NumericMetadataColumn(pd.Series( [np.nan, np.nan, np.nan], name='col1', index=pd.Index(['a', 'b', 'c'], name='id'))) obs = mdc.to_series() exp = pd.Series( [np.nan, np.nan, np.nan], name='col1', index=pd.Index(['a', 'b', 'c'], name='id')) pd.testing.assert_series_equal(obs, exp) self.assertEqual(obs.dtype, np.float64) def test_missing_insdc(self): mdc = NumericMetadataColumn(pd.Series( ['missing', 4.2, float('nan'), -5.678], name='col1', index=pd.Index(['a', 'b', 'c', 'd'], name='id')), missing_scheme='INSDC:missing') obs = mdc.to_series() exp = pd.Series( [np.nan, 4.2, np.nan, -5.678], name='col1', index=pd.Index(['a', 'b', 'c', 'd'], name='id')) pd.testing.assert_series_equal(obs, exp) self.assertEqual(obs.dtype, np.float64) self.assertTrue(np.isnan(obs['a'])) self.assertTrue(np.isnan(obs['c'])) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/test_missing.py000066400000000000000000000070351520735541300254730ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2016-2023, QIIME 2 development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE, distributed with this software. # ---------------------------------------------------------------------------- import unittest from packaging.version import Version import pandas as pd import pandas.testing as pdt import numpy as np from skbio.metadata.missing import series_encode_missing, series_extract_missing PANDAS_3 = Version(pd.__version__) >= Version("3.0.0") class RoundTripMixin: def check_roundtrip(self, real_value, dtype): notna_exp = [real_value] series = pd.Series(notna_exp + self.missing_terms) encoded = series_encode_missing(series, self.enum) missing = series_extract_missing(encoded) self.assertEqual(encoded.dtype, dtype) # the non-null side of the series self.assertEqual(list(encoded[encoded.notna()]), notna_exp) # the null end (but in the original vocabulary) pdt.assert_series_equal(missing, series[1:].astype(object)) def test_roundtrip_float(self): self.check_roundtrip(0.05, float) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_roundtrip_string(self): self.check_roundtrip('hello', object) def test_roundtrip_int(self): self.check_roundtrip(42, float) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_roundtrip_bool(self): self.check_roundtrip(True, object) @unittest.skipIf(PANDAS_3, reason="TODO: Need to rebuild NaN metadata handling in skbio.") def test_roundtrip_all_missing_object(self): expected = [None, float('nan')] + self.missing_terms series = pd.Series(expected, dtype=object) encoded = series_encode_missing(series, self.enum) missing = series_extract_missing(encoded) self.assertEqual(encoded.dtype, object) pdt.assert_series_equal(missing, series.astype(object)) class TestISNDC(RoundTripMixin, unittest.TestCase): def setUp(self): self.enum = 'INSDC:missing' self.missing_terms = ['not applicable', 'missing', 'not collected', 'not provided', 'restricted access'] class TestOmitted(RoundTripMixin, unittest.TestCase): def setUp(self): self.enum = 'blank' self.missing_terms = [None, float('nan')] # test_roundtrip_all_missing_float is not possible with other schemes def test_roundtrip_all_missing_float(self): expected = [None, float('nan')] + self.missing_terms series = pd.Series(expected, dtype=float) encoded = series_encode_missing(series, self.enum) missing = series_extract_missing(encoded) self.assertEqual(encoded.dtype, float) pdt.assert_series_equal(missing, series.astype(object)) class TestError(RoundTripMixin, unittest.TestCase): def setUp(self): self.enum = 'no-missing' self.missing_terms = [] # no missing values, so bool and int are not object and float def test_roundtrip_bool(self): self.check_roundtrip(True, bool) def test_roundtrip_int(self): self.check_roundtrip(42, np.int64) def test_roundtrip_all_missing_object(self): with self.assertRaisesRegex(ValueError, 'Missing values.*name=None'): super().test_roundtrip_all_missing_object() if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/metadata/tests/test_mixin.py000066400000000000000000000106461520735541300251500ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from skbio.metadata._mixin import (MetadataMixin, PositionalMetadataMixin, IntervalMetadataMixin) from skbio.util._decorator import overrides from skbio.util._testing import ReallyEqualMixin from skbio.metadata._testing import (MetadataMixinTests, PositionalMetadataMixinTests, IntervalMetadataMixinTests) class TestMetadataMixin(unittest.TestCase, ReallyEqualMixin, MetadataMixinTests): def setUp(self): class ExampleMetadataMixin(MetadataMixin): def __init__(self, metadata=None): MetadataMixin._init_(self, metadata=metadata) def __eq__(self, other): return MetadataMixin._eq_(self, other) def __ne__(self, other): return MetadataMixin._ne_(self, other) def __copy__(self): copy = self.__class__(metadata=None) copy._metadata = MetadataMixin._copy_(self) return copy def __deepcopy__(self, memo): copy = self.__class__(metadata=None) copy._metadata = MetadataMixin._deepcopy_(self, memo) return copy self._metadata_constructor_ = ExampleMetadataMixin class TestPositionalMetadataMixin(unittest.TestCase, ReallyEqualMixin, PositionalMetadataMixinTests): def setUp(self): class ExamplePositionalMetadataMixin(PositionalMetadataMixin): @overrides(PositionalMetadataMixin) def _positional_metadata_axis_len_(self): return self._axis_len def __init__(self, axis_len, positional_metadata=None): self._axis_len = axis_len PositionalMetadataMixin._init_( self, positional_metadata=positional_metadata) def __eq__(self, other): return PositionalMetadataMixin._eq_(self, other) def __ne__(self, other): return PositionalMetadataMixin._ne_(self, other) def __copy__(self): copy = self.__class__(self._axis_len, positional_metadata=None) copy._positional_metadata = \ PositionalMetadataMixin._copy_(self) return copy def __deepcopy__(self, memo): copy = self.__class__(self._axis_len, positional_metadata=None) copy._positional_metadata = \ PositionalMetadataMixin._deepcopy_(self, memo) return copy self._positional_metadata_constructor_ = ExamplePositionalMetadataMixin class TestIntervalMetadataMixin(unittest.TestCase, ReallyEqualMixin, IntervalMetadataMixinTests): def setUp(self): super()._set_up() class ExampleIntervalMetadataMixin(IntervalMetadataMixin): @overrides(IntervalMetadataMixin) def _interval_metadata_axis_len_(self): return self._axis_len def __init__(self, axis_len, interval_metadata=None): self._axis_len = axis_len IntervalMetadataMixin._init_( self, interval_metadata=interval_metadata) def __eq__(self, other): return IntervalMetadataMixin._eq_(self, other) def __ne__(self, other): return IntervalMetadataMixin._ne_(self, other) def __copy__(self): copy = self.__class__(self._axis_len, interval_metadata=None) copy._interval_metadata = IntervalMetadataMixin._copy_(self) return copy def __deepcopy__(self, memo): copy = self.__class__(self._axis_len, interval_metadata=None) copy._interval_metadata = IntervalMetadataMixin._deepcopy_( self, memo) return copy self._interval_metadata_constructor_ = ExampleIntervalMetadataMixin if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/sequence/000077500000000000000000000000001520735541300212725ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/sequence/__init__.py000066400000000000000000000423661520735541300234160ustar00rootroot00000000000000r"""Biological Sequences (:mod:`skbio.sequence`) ============================================ .. currentmodule:: skbio.sequence This module provides functionality for storing and working with sequences, including molecular sequences based on IUPAC-defined alphabets (:class:`DNA`, :class:`RNA`, :class:`Protein`), sequences based on custom alphabets (:class:`GrammaredSequence`), and generic/non-biological sequences with no alphabet restrictions (:class:`Sequence`). Additionally, this module defines the :class:`GeneticCode` class, which represents an immutable object that translates DNA or RNA sequences into protein sequences, and the :class:`SubstitutionMatrix` class, which stores scores of substitutions between sequence characters. See the |sequence_tutorial|_ section for working with biological sequences using scikit-bio. Sequence types -------------- .. autosummary:: :toctree: generated/ Sequence GrammaredSequence DNA RNA Protein Sequence utilities ------------------ .. autosummary:: :toctree: generated/ GeneticCode SubstitutionMatrix Distance calculation -------------------- .. autosummary:: :toctree: generated/ distance Abstract classes ---------------- .. autosummary:: :toctree: generated/ NucleotideMixin .. |sequence_tutorial| replace:: **Tutorial** .. _sequence_tutorial: Tutorial -------- Creating sequences ^^^^^^^^^^^^^^^^^^ Create a DNA sequence from a string of nucleotide characters: >>> from skbio.sequence import DNA >>> seq = DNA('GAATTC') >>> seq DNA -------------------------- Stats: length: 6 has gaps: False has degenerates: False has definites: True GC-content: 33.33% -------------------------- 0 GAATTC Optionally, one may attach metadata to a sequence object. Details of metadata are introduced in :ref:`annotate_sequences` below. >>> seq = DNA('GAATTC', metadata={'id': 'S1', 'description': 'EcoRI recognition site'}) >>> seq DNA ------------------------------------------- Metadata: 'description': 'EcoRI recognition site' 'id': 'S1' Stats: length: 6 has gaps: False has degenerates: False has definites: True GC-content: 33.33% ------------------------------------------- 0 GAATTC Sequences can be read from :mod:`file formats ` recognizable by scikit-bio. For example, to read a DNA sequence from a :mod:`FASTA ` file: >>> seq = DNA.read('input.fa', format='fasta') # doctest: +SKIP The filename "input.fa" can also be a file handle or other readable objects. To read all sequences from a multi-FASTA file into a list of sequence objects, you will need: >>> from skbio.io import read as sk_read >>> seqs = list(sk_read('input.fa', format='fasta', constructor=DNA)) # doctest: +SKIP Sequence grammar ^^^^^^^^^^^^^^^^ The three common biological sequence types: ``DNA``, ``RNA`` and ``Protein``, are :class:`grammared sequences `. That is, each of them has a defined alphabet (character set), which typically consists of: - :attr:`definite characters `, such as ``ACGT``, which represent the four canonical nucleotides in a DNA sequence, - :attr:`degenerate characters `, such as ``R``, which represents ``A`` or ``G``, - :attr:`gap character(s) `, such as ``-``, and - a :attr:`wildcard character `, such as ``N``, which is also a degenerate character. Use of any of these characters in the sequence data is valid. For example: >>> seq = DNA('GCCRCCATGG', metadata={'name': 'Kozak consensus sequence'}) >>> seq DNA -------------------------------------- Metadata: 'name': 'Kozak consensus sequence' Stats: length: 10 has gaps: False has degenerates: True has definites: True GC-content: 70.00% -------------------------------------- 0 GCCRCCATGG One can customize grammared sequence types, for example to include modified amino acids, methylation sites, or non-biological molecules. Refer to :class:`GrammaredSequence` for instructions. Each class contains a degenerate map for lookup: >>> sorted(DNA.degenerate_map['R']) ['A', 'G'] Check if a sequence contains degenerate characters: >>> seq.has_degenerates() True Identify the positions of degenerate characters: >>> seq.degenerates() array([False, False, False, True, False, False, False, False, False, False], dtype=bool) Likewise, one can create a sequence with gaps, and identify the gap positions. >>> gapped = DNA('ATG--CAC') >>> gapped.gaps() array([False, False, False, True, True, False, False, False], dtype=bool) One can efficiently remove all gaps from a sequence: >>> ungapped = gapped.degap() >>> print(ungapped) ATGCAC Exploring sequences ^^^^^^^^^^^^^^^^^^^ The primary information stored in a sequence object is the sequence data itself. It can be retrieved from the string representation of the sequence: >>> str(seq) 'GCCRCCATGG' Or: >>> print(seq) GCCRCCATGG Under the hood, the sequence data is stored as a NumPy array of bytes, which permit compact storage and efficient, vectorized operations. >>> seq.values array([b'G', b'C', b'C', b'R', b'C', b'C', b'A', b'T', b'G', b'G'], dtype='|S1') This array can also be viewed as ASCII code points: >>> seq.values.view('uint8') array([71, 67, 67, 82, 67, 67, 65, 84, 71, 71], dtype=uint8) A sequence object shares typical behaviors of a Python string. This means that you can apply Python string **indexing** and **slicing** approaches on a sequence. For example: >>> seq[0] DNA -------------------------------------- Metadata: 'name': 'Kozak consensus sequence' Stats: length: 1 has gaps: False has degenerates: False has definites: True GC-content: 100.00% -------------------------------------- 0 G >>> seq[2:5] DNA -------------------------------------- Metadata: 'name': 'Kozak consensus sequence' Stats: length: 3 has gaps: False has degenerates: True has definites: True GC-content: 66.67% -------------------------------------- 0 CRC The output of indexing or slicing is also a sequence object. This process doesn't copy the original sequence data. Instead, it returns a **view** of the same memory space, which is efficient. Refer to NumPy's `copies and views `_ for more information. >>> seq[2:5].values.base is seq.values.base True Some Python string methods, such as ``count`` and ``index``, also work on scikit-bio sequences. >>> seq.count('C') 4 >>> seq.index('ATG') 6 To concatenate multiple sequences: >>> seq = DNA.concat([DNA('GGATCC'), DNA('AAGCTT'), DNA('GAATTC')]) >>> print(seq) GGATCCAAGCTTGAATTC Sequence conversion ^^^^^^^^^^^^^^^^^^^ scikit-bio supports convenient conversion between DNA (two strands), RNA and protein sequences. For example: >>> dna = DNA('TGCTACATCCAGAACTGCCCCCTGGGA', metadata={'name': 'oxytocin'}) >>> dna DNA ------------------------------- Metadata: 'name': 'oxytocin' Stats: length: 27 has gaps: False has degenerates: False has definites: True GC-content: 59.26% ------------------------------- 0 TGCTACATCC AGAACTGCCC CCTGGGA Reverse complement a DNA sequence: >>> print(dna.reverse_complement()) TCCCAGGGGGCAGTTCTGGATGTAGCA Transcribe a DNA sequence into mRNA: >>> rna = dna.transcribe() >>> print(rna) UGCUACAUCCAGAACUGCCCCCUGGGA Translate an mRNA sequence into protein: >>> prot = rna.translate() >>> print(prot) CYIQNCPLG By default, the standard genetic code table (1) is used. To use a specific table (see the :class:`GeneticCode` class for details), simply specify its index: >>> prot = rna.translate(11) # Bacteria # doctest: +SKIP A DNA sequence can be directly translated into protein. The output is the same as transcription followed by translation. >>> prot_ = dna.translate() >>> prot_ == prot True Searching for patterns ^^^^^^^^^^^^^^^^^^^^^^ Sequences can be searched for patterns, a.k.a., **motifs** in molecular biology. Except for searching for exact substrings using the ``index`` method (see above), one can also search for flexibly defined patterns using :wiki:`regular expressions `. >>> from skbio.sequence import RNA >>> seq = RNA('AGG-GGACUGAA') >>> for match in seq.find_with_regex('(G+AC[UT])'): ... match slice(4, 9, None) The returned values are slices, with which one can extract the relevant subsequences. >>> print(seq[match]) GGACU scikit-bio has a convenience shortcut ``find_motifs``, which searches for contiguous runs of purines or pyrimidines. >>> for motif in seq.find_motifs('purine-run', min_length=2): ... print(seq[motif]) AGG GGA GAA Comparing sequences ^^^^^^^^^^^^^^^^^^^ It is straightforward to compute the distance between two sequences. By default, the Hamming distance (:func:`~distance.hamming`, i.e., proportion of different sites) is calculated, This metric is useful in analyses such as sequence clustering and phylogenetic reconstruction. >>> seq1 = RNA('GACCCGCUUU') >>> seq2 = RNA('GCCCCCCUUU') >>> seq1.distance(seq2) 0.2 Hamming distance requires that the two sequences have the same length. This often requires that you **align** the sequences before comparison. See :mod:`skbio.alignment` for how to align sequences. Similarly, you can calculate the percent (dis)similarity between a pair of aligned sequences. >>> seq1 = RNA('ACCGUUAGUC') >>> seq2 = RNA('ACGGGU--UC') >>> seq1.match_frequency(seq2, relative=True) 0.6 >>> seq1.mismatch_frequency(seq2, relative=True) 0.4 .. _annotate_sequences: Annotating sequences ^^^^^^^^^^^^^^^^^^^^ Metadata describe the properties of a sequence or some of its regions/sites. scikit-bio supports three types of sequence metadata: **metadata** (for the entire sequence), **positional metadata** (for sites), and **interval metadata** (for regions). ``metadata`` stores the properties of the entire sequence, such as ID, description, source, function, etc., as a Python dictionary. The following example creates a DNA sequence with "gene" and "product" properties. >>> seq = DNA('TGGTATATAGTTTAAACAAAACGAATGATTTCGACTCATTAAATTATGATAATCATATTTACCAA', ... metadata={'gene': 'TRNR', 'product': 'tRNA-Arg'}) >>> seq DNA -------------------------------------------------------------------- Metadata: 'gene': 'TRNR' 'product': 'tRNA-Arg' Stats: length: 65 has gaps: False has degenerates: False has definites: True GC-content: 23.08% -------------------------------------------------------------------- 0 TGGTATATAG TTTAAACAAA ACGAATGATT TCGACTCATT AAATTATGAT AATCATATTT 60 ACCAA Access the metadata by key: >>> seq.metadata['product'] 'tRNA-Arg' Modify the metadata of an existing sequence: >>> seq.metadata['organism'] = 'Homo sapiens' Many of scikit-bio's file format parsers can automatically populate metadata fields. For example, the FASTA parser reads the sequence ID and description into the ``id`` and ``description`` fields: >>> from skbio.sequence import Protein >>> fasta = '''>NP_000591.1 interleukin-6 isoform 1 precursor [Homo sapiens] ... MNSFSTSAFGPVAFSLGLLLVLPAAFPAPVPPGEDSKDVAAPHRQPLTSSERIDKQIRYILDGISALRKE ... TCNKSNMCESSKEALAENNLNLPKMAEKDGCFQSGFNEETCLVKIITGLLEFEVYLEYLQNRFESSEEQA ... RAVQMSTKVLIQFLQKKAKNLDAITTPDPTTNASLLTKLQAQNQWLQDMTTHLILRSFKEFLQSSLRALR ... QM''' >>> seq = Protein.read([fasta], format='fasta') >>> seq Protein --------------------------------------------------------------------- Metadata: 'description': 'interleukin-6 isoform 1 precursor [Homo sapiens]' 'id': 'NP_000591.1' Stats: length: 212 has gaps: False has degenerates: False has definites: True has stops: False --------------------------------------------------------------------- 0 MNSFSTSAFG PVAFSLGLLL VLPAAFPAPV PPGEDSKDVA APHRQPLTSS ERIDKQIRYI 60 LDGISALRKE TCNKSNMCES SKEALAENNL NLPKMAEKDG CFQSGFNEET CLVKIITGLL 120 EFEVYLEYLQ NRFESSEEQA RAVQMSTKVL IQFLQKKAKN LDAITTPDPT TNASLLTKLQ 180 AQNQWLQDMT THLILRSFKE FLQSSLRALR QM ``positional_metadata`` stores per-character properties. Each property has the same number of values as the sequence length. The following example annotates three types of sites on the human TP53 protein sequence. >>> seq = ( ... 'MEEPQSDPSVEPPLSQETFSDLWKLLPENNVLSPLPSQAMDDLMLSPDDIEQWFTEDPGPDEAPRMPEAA' ... 'PPVAPAPAAPTPAAPAPAPSWPLSSSVPSQKTYQGSYGFRLGFLHSGTAKSVTCTYSPALNKMFCQLAKT' ... 'CPVQLWVDSTPPPGTRVRAMAIYKQSQHMTEVVRRCPHHERCSDSDGLAPPQHLIRVEGNLRVEYLDDRN' ... 'TFRHSVVVPYEPPEVGSDCTTIHYNYMCNSSCMGGMNRRPILTIITLEDSSGNLLGRNSFEVRVCACPGR' ... 'DRRTEEENLRKKGEPHHELPPGSTKRALPNNTSSSPQPKKKPLDGEYFTLQIRGRERFEMFRELNEALEL' ... 'KDAQAGKEPGGSRAHSSHLKSKKGQSTSRHKKLMFKTEGPDSD' ... ) >>> import numpy as np >>> sites = np.full(len(seq), False) >>> acetylation = sites.copy() >>> acetylation[[119, 304, 320, 372, 380, 381]] = True >>> methylation = sites.copy() >>> methylation[[332, 334, 336, 369, 371, 372, 381]] = True >>> phosphorylation = sites.copy() >>> phosphorylation[[8, 14, 17, 19, 32, 36, 45, 54, 182, 268, 314, 391]] = True >>> seq = Protein(seq, metadata={'id': 'NP_000537.3', 'description': 'TP53'}, ... positional_metadata={'acetylation': acetylation, ... 'methylation': methylation, ... 'phosphorylation': phosphorylation}) Once created, positional metadata are stored as a dataframe. >>> print(seq.positional_metadata) acetylation methylation phosphorylation 0 False False False 1 False False False 2 False False False 3 False False False 4 False False False .. ... ... ... 388 False False False 389 False False False 390 False False False 391 False False True 392 False False False [393 rows x 3 columns] Likewise, scikit-bio's :mod:`FASTQ ` parser can automatically populate the "quality" column of the positional metadata: >>> fastq = '''@S00001/1 ... CGTGCTCCACGCTCTCCTGCACGCCCGAGCCGTTGCGGTCGGCGAGAGCCATGTCGACGGCGGGCTTGAG ... + ... DDAEGGGGIIIGIJKJKKKHIKJAKKKHCGIKKJAJGICKKKAJEJA:G1EJJKJHJFKJIDIEII?=DC ... ''' >>> seq = DNA.read([fastq], format='fastq', phred_offset=33) >>> seq DNA -------------------------------------------------------------------- Metadata: 'description': '' 'id': 'S00001/1' Positional metadata: 'quality': Stats: length: 70 has gaps: False has degenerates: False has definites: True GC-content: 71.43% -------------------------------------------------------------------- 0 CGTGCTCCAC GCTCTCCTGC ACGCCCGAGC CGTTGCGGTC GGCGAGAGCC ATGTCGACGG 60 CGGGCTTGAG >>> print(seq.positional_metadata['quality']) 0 35 1 35 2 32 3 36 4 38 .. 65 40 66 30 67 28 68 35 69 34 Name: quality, Length: 70, dtype: uint8 ``interval_metadata`` stores properties that span a range in the sequence, such as genes and regulatory elements. See the :class:`~skbio.metadata.IntervalMetadata` class for details. The following example annotates three regions of the human H4C6 gene. >>> fasta = '''>NM_003540.4 Homo sapiens H4 clustered histone 6 (H4C6), mRNA ... GCAAAAGTTAAGAGTTGTTGTTTGTCTTCGATCATGTCTGGTAGAGGCAAAGGTGGTAAAGGTTTAGGAA ... AGGGAGGCGCCAAGCGCCATCGCAAAGTGCTGCGTGACAACATACAGGGCATCACGAAGCCCGCCATCCG ... TCGCTTGGCCCGACGCGGCGGCGTGAAACGCATTTCGGGCCTCATTTATGAGGAGACCCGCGGTGTTCTT ... AAGGTGTTCCTGGAGAATGTGATACGGGACGCCGTAACCTACACGGAGCACGCCAAGCGTAAGACAGTCA ... CTGCAATGGATGTTGTCTACGCGCTCAAGCGCCAGGGACGCACTCTGTACGGCTTTGGTGGCTGAGCCTC ... ACCCCGGCTTTTTATTTAACAGCTCACCCATAAAAGGCCCTTTTCAGGGCC''' >>> seq = DNA.read([fasta], format='fasta') >>> _ = seq.interval_metadata.add(bounds=[(0, 401)], metadata={'name': 'exon'}) >>> _ = seq.interval_metadata.add(bounds=[(33, 345)], metadata={'name': 'cds'}) >>> _ = seq.interval_metadata.add(bounds=[(385, 401)], metadata={'name': 'stem_loop'}) scikit-bio's :mod:`GFF3 ` parser can read sequence annotation into interval metadata. The following code reads a genome's sequence and annotation from separate files and combine. >>> from skbio.metadata import IntervalMetadata >>> seq = DNA.read('genomic.fna', format='fasta') # doctest: +SKIP >>> seq.interval_metadata = IntervalMetadata.read( # doctest: +SKIP ... 'genomic.gff', format='gff3', seq_id=seq.metadata['id']) If the GFF3 contains the sequence, one can read the sequence and annotation all at once: >>> seq = DNA.read('genomic.gff', format='gff3') # doctest: +SKIP """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._sequence import Sequence from ._protein import Protein from ._dna import DNA from ._rna import RNA from ._genetic_code import GeneticCode from ._grammared_sequence import GrammaredSequence from ._substitution import SubstitutionMatrix from ._nucleotide_mixin import NucleotideMixin __all__ = [ "Sequence", "Protein", "DNA", "RNA", "GeneticCode", "GrammaredSequence", "SubstitutionMatrix", "NucleotideMixin", ] scikit-bio-scikit-bio-a3beaa6/skbio/sequence/_alphabet.py000066400000000000000000000211071520735541300235640ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np def _encode_alphabet(alphabet): """Encode an alphabet as a vector of ASCII code points. Parameters ---------- alphabet : str, list, tuple or 1D np.ndarray Input alphabet. Must consist of single ASCII characters. Elements may be string or byte characters, or integers representing code points. Returns ------- 1D np.ndarray of np.uint8 Vector of ASCII code points representing the alphabet. Raises ------ TypeError If alphabet or its components are of a wrong data type. ValueError If some elements are not single characters. ValueError If some code points are beyond the ASCII range. UnicodeEncodeError If some characters are beyond the ASCII range. Notes ----- ASCII has 128 code points (0 to 127) [1]_ (not to be confused with extended ASCII). Therefore, output values are within the range of [0, 127]. References ---------- .. [1] https://en.wikipedia.org/wiki/ASCII """ errmsg = "Alphabet is of an invalid data type." # string if isinstance(alphabet, str): alphabet = alphabet.encode("ascii") return np.frombuffer(alphabet, dtype=np.uint8) # list or tuple elif isinstance(alphabet, (list, tuple)): alphabet = np.array(alphabet) # 1d numpy array elif not isinstance(alphabet, np.ndarray): raise TypeError(errmsg) # if alphabet.ndim != 1: # raise TypeError(errmsg) dtype = alphabet.dtype # integers represent ascii code points if np.issubdtype(dtype, np.integer): # ascii code points are within [0, 127] if np.all((alphabet >= 0) & (alphabet <= 127)): if dtype is np.uint8: return alphabet # cast data type to uint8 else: return alphabet.astype(np.uint8) else: raise ValueError("Not all code points are within the ASCII range.") # encode strings as ascii characters elif np.issubdtype(dtype, np.str_): alphabet = np.char.encode(alphabet, encoding="ascii") # bytes are already encoded elif not np.issubdtype(dtype, np.bytes_): raise TypeError(errmsg) # must be single characters if not (np.char.str_len(alphabet) == 1).all(): raise ValueError("Not all elements are single characters.") return alphabet.view(np.uint8) def _alphabet_to_hashes(alphabet): """Convert an alphabet into a hash table of ASCII code points to indices. Parameters ---------- alphabet : iterable Input alphabet. Must consist of single ASCII characters. Returns ------- np.ndarray of intp of shape (128,) Hash table of ASCII code points to indices. Raises ------ ValueError If the absence character is not in the alphabet. ValueError If one or multiple characters in the sequence are absent from the alphabet, whereas `absence` is not set. See Also -------- _indices_in_alphabet_ascii Notes ----- The resulting data structure enables efficient conversion of a sequence into indices of characters in an alphabet. The hash table has a constant size of 128, which is the total number of ASCII characters. Code points absent from the alphabet are filled with -1, which is beyond the range of ASCII characters, hence the maximum index in the alphabet. """ idx = _encode_alphabet(alphabet) res = np.full(128, -1, dtype=np.intp) res[idx] = np.arange(idx.size) return res def _indices_in_alphabet(seq, alphabet, wildcard=None, gaps=None): """Convert a sequence into indices of characters in an alphabet. Parameters ---------- seq : iterable Input sequence. alphabet : dict or iterable Input alphabet. Can be a dictionary of characters to indices, or an iterable of other types from which the dictionary will be constructed. wildcard : hashable, optional Character to replace any characters that are absent from the alphabet. If omitted, will raise an error if the latter characters exist. gaps : iterable, optional Boolean mask of the sequence representing gap positions. Must be of the same length as `seq`. Returns ------- 1D ndarray of intp Vector of indices of characters in an alphabet. Raises ------ ValueError If the wildcard character is not in the alphabet. ValueError If one or more characters in the sequence are absent from the alphabet, whereas `wildcard` is not set. See Also -------- _indices_in_alphabet_ascii Notes ----- This function is versatile to the type of characters. """ if not isinstance(alphabet, dict): alphabet = {x: i for i, x in enumerate(alphabet)} pos = list(map(alphabet.get, seq)) if gaps is not None: for i, gap in enumerate(gaps): if gap: pos[i] = -1 if wildcard is not None: try: wildcard = alphabet[wildcard] except KeyError: raise ValueError(f'Wildcard character "{wildcard}" is not in the alphabet.') pos = [wildcard if x is None else x for x in pos] elif None in pos: raise ValueError( "One or more characters in the sequence are absent from the alphabet." ) return np.array(pos, dtype=np.intp) def _indices_in_alphabet_ascii(seq, alphabet, wildcard=None, gaps=None): """Convert sequence(s) into indices of characters in an ASCII alphabet. Parameters ---------- seq : ndarray of int Input sequence(s) as ASCII code points. alphabet : ndarray of shape (128,) of intp Input alphabet as a hash table of all ASCII code points to character indices, or -1 if absent from the alphabet. wildcard : int, optional Code point of character to replace any characters that are absent from the alphabet. If omitted, will raise an error if such characters exist. gaps : ndarray of bool, optional Boolean mask of the sequence(s) representing gap positions. Must be of the same shape as `seq`. Returns ------- ndarray of intp Vector of indices of characters in an alphabet. Raises ------ ValueError If the wildcard character is not in the alphabet. ValueError If one or more characters in the sequence are absent from the alphabet, whereas `wildcard` is not set. See Also -------- _indices_in_alphabet _alphabet_to_hashes Notes ----- This function is optimized for single ASCII characters. """ pos = alphabet[seq] absent = pos == -1 if gaps is not None: absent &= ~gaps if absent.any(): if wildcard is None: raise ValueError( "One or more characters in the sequence are absent from the alphabet." ) try: assert (wild := alphabet[wildcard]) != -1 except AssertionError: raise ValueError( f'Wildcard character "{chr(wildcard)}" is not in the alphabet.' ) pos = np.where(absent, wild, pos) return pos def _indices_in_observed(seqs): """Convert sequences into vectors of indices in observed characters. Parameters ---------- seqs : iterable of iterable Input sequences. Returns ------- list of 1D np.ndarray Vectors of indices representing the sequences. 1D np.ndarray Sorted vector of unique characters observed in the sequences. """ # This function uses np.unique to extract unique characters and their # indices. It applies np.unique on individual sequences, then merges # results. This design is to avoid concatenating too many sequences. alpha_lst, index_lst = zip( *[ np.unique(tuple(x) if isinstance(x, str) else x, return_inverse=True) for x in seqs ] ) alpha_union, index_union = np.unique(np.concatenate(alpha_lst), return_inverse=True) index_bounds = np.cumsum([x.size for x in alpha_lst])[:-1] index_chunks = np.split(index_union, index_bounds) index_lst_trans = [x[y] for x, y in zip(index_chunks, index_lst)] return index_lst_trans, alpha_union scikit-bio-scikit-bio-a3beaa6/skbio/sequence/_dna.py000066400000000000000000000345131520735541300225530ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import skbio from skbio.util._decorator import classproperty, overrides from ._nucleotide_mixin import NucleotideMixin, _motifs as _parent_motifs from ._grammared_sequence import GrammaredSequence from skbio.io.descriptors import Read, Write class DNA(GrammaredSequence, NucleotideMixin): r"""Store DNA sequence data and optional associated metadata. Parameters ---------- sequence : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Characters representing the DNA sequence itself. metadata : dict, optional Arbitrary metadata which applies to the entire sequence. positional_metadata : Pandas DataFrame consumable, optional Arbitrary per-character metadata. For example, quality data from sequencing reads. Must be able to be passed directly to the Pandas DataFrame constructor. interval_metadata : IntervalMetadata Arbitrary interval metadata which applies to intervals within a sequence to store interval features (such as genes on the DNA sequence). lowercase : bool or str, optional If ``True``, lowercase sequence characters will be converted to uppercase characters in order to be valid IUPAC DNA characters. If ``False``, no characters will be converted. If a str, it will be treated as a key into the positional metadata of the object. All lowercase characters will be converted to uppercase, and a ``True`` value will be stored in a boolean array in the positional metadata under the key. validate : bool, optional If ``True``, validation will be performed to ensure that all sequence characters are in the IUPAC DNA character set. If ``False``, validation will not be performed. Turning off validation will improve runtime performance. If invalid characters are present, however, there is **no guarantee that operations performed on the resulting object will work or behave as expected.** Only turn off validation if you are certain that the sequence characters are valid. To store sequence data that is not IUPAC-compliant, use ``Sequence``. See Also -------- RNA GrammaredSequence Notes ----- According to the IUPAC DNA character set [1]_ , a DNA sequence may contain the following four definite characters (canonical nucleotides): +-----+-----------+ |Code |Nucleobase | +=====+===========+ |``A``|Adenine | +-----+-----------+ |``C``|Cytosine | +-----+-----------+ |``G``|Guanine | +-----+-----------+ |``T``|Thymine | +-----+-----------+ And the following 11 degenerate characters, each of which representing 2-4 nucleotides: +-----+-------------+-----------+ |Code |Nucleobases |Meaning | +=====+=============+===========+ |``R``|A or G |Purine | +-----+-------------+-----------+ |``Y``|C or T |Pyrimidine | +-----+-------------+-----------+ |``S``|G or C |Strong | +-----+-------------+-----------+ |``W``|A or T |Weak | +-----+-------------+-----------+ |``K``|G or T |Keto | +-----+-------------+-----------+ |``M``|A or C |Amino | +-----+-------------+-----------+ |``B``|C, G or T |Not A | +-----+-------------+-----------+ |``D``|A, G or T |Not C | +-----+-------------+-----------+ |``H``|A, C or T |Not G | +-----+-------------+-----------+ |``V``|A, C or G |Not T | +-----+-------------+-----------+ |``N``|A, C, G or T |Any | +-----+-------------+-----------+ Plus two gap characters: ``-`` and ``.``. Characters other than the above 17 are not allowed. If you intend to use additional characters to represent non-canonical nucleobases, such as ``I`` (Inosine), you may create a custom alphabet using ``GrammaredSequence``. Directly modifying the alphabet of ``DNA`` may break methods that rely on the IUPAC alphabet. It should be noted that some functions do not support degenerate characters characters. In such cases, they will be replaced with `N` to represent any of the canonical nucleotides. References ---------- .. [1] Cornish-Bowden, A. (1985). Nomenclature for incompletely specified bases in nucleic acid sequences: recommendations 1984. Nucleic Acids Res, 13(9), 3021. Examples -------- >>> from skbio import DNA >>> DNA('ACCGAAT') DNA -------------------------- Stats: length: 7 has gaps: False has degenerates: False has definites: True GC-content: 42.86% -------------------------- 0 ACCGAAT Convert lowercase characters to uppercase: >>> DNA('AcCGaaT', lowercase=True) DNA -------------------------- Stats: length: 7 has gaps: False has degenerates: False has definites: True GC-content: 42.86% -------------------------- 0 ACCGAAT """ read = Read() write = Write() @classproperty @overrides(NucleotideMixin) def complement_map(cls): comp_map = { "A": "T", "T": "A", "G": "C", "C": "G", "Y": "R", "R": "Y", "S": "S", "W": "W", "K": "M", "M": "K", "B": "V", "D": "H", "H": "D", "V": "B", "N": "N", } comp_map.update({c: c for c in cls.gap_chars}) return comp_map @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set("ACGT") @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return { "R": set("AG"), "Y": set("CT"), "M": set("AC"), "K": set("TG"), "W": set("AT"), "S": set("GC"), "B": set("CGT"), "D": set("AGT"), "H": set("ACT"), "V": set("ACG"), "N": set("ACGT"), } @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return "-" @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set("-.") @classproperty @overrides(GrammaredSequence) def wildcard_char(cls): return "N" @property def _motifs(self): return _motifs def transcribe(self): """Transcribe DNA into RNA. DNA sequence is assumed to be the coding strand. Thymine (T) is replaced with uracil (U) in the transcribed sequence. Returns ------- RNA Transcribed sequence. See Also -------- translate translate_six_frames Notes ----- DNA sequence's metadata, positional, and interval metadata are included in the transcribed RNA sequence. Examples -------- Transcribe DNA into RNA: >>> from skbio import DNA >>> dna = DNA('TAACGTTA') >>> dna DNA -------------------------- Stats: length: 8 has gaps: False has degenerates: False has definites: True GC-content: 25.00% -------------------------- 0 TAACGTTA >>> dna.transcribe() RNA -------------------------- Stats: length: 8 has gaps: False has degenerates: False has definites: True GC-content: 25.00% -------------------------- 0 UAACGUUA """ seq = self._string.replace(b"T", b"U") metadata = None if self.has_metadata(): metadata = self.metadata positional_metadata = None if self.has_positional_metadata(): positional_metadata = self.positional_metadata interval_metadata = None if self.has_interval_metadata(): interval_metadata = self.interval_metadata # turn off validation because `seq` is guaranteed to be valid return skbio.RNA( seq, metadata=metadata, positional_metadata=positional_metadata, interval_metadata=interval_metadata, validate=False, ) def translate(self, *args, **kwargs): """Translate DNA sequence into protein sequence. DNA sequence is assumed to be the coding strand. DNA sequence is first transcribed into RNA and then translated into protein. Parameters ---------- args : tuple Positional arguments accepted by ``RNA.translate``. kwargs : dict Keyword arguments accepted by ``RNA.translate``. Returns ------- Protein Translated sequence. See Also -------- RNA.reverse_transcribe RNA.translate translate_six_frames transcribe Notes ----- DNA sequence's metadata are included in the translated protein sequence. Positional metadata are not included. Examples -------- Translate DNA into protein using NCBI's standard genetic code (table ID 1, the default genetic code in scikit-bio): >>> from skbio import DNA >>> dna = DNA('ATGCCACTTTAA') >>> dna.translate() Protein -------------------------- Stats: length: 4 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 MPL* Translate the same DNA sequence using a different NCBI genetic code (table ID 3, the yeast mitochondrial code) and specify that translation must terminate at the first stop codon: >>> dna.translate(3, stop='require') Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 MPT """ return self.transcribe().translate(*args, **kwargs) def translate_six_frames(self, *args, **kwargs): """Translate DNA into protein using six possible reading frames. DNA sequence is assumed to be the coding strand. DNA sequence is first transcribed into RNA and then translated into protein. The six possible reading frames are: * 1 (forward) * 2 (forward) * 3 (forward) * -1 (reverse) * -2 (reverse) * -3 (reverse) Translated sequences are yielded in this order. Parameters ---------- args : tuple Positional arguments accepted by ``RNA.translate_six_frames``. kwargs : dict Keyword arguments accepted by ``RNA.translate_six_frames``. Yields ------ Protein Translated sequence in the current reading frame. See Also -------- RNA.translate_six_frames translate transcribe Notes ----- This method is faster than (and equivalent to) performing six independent translations using, for example: ``(seq.translate(reading_frame=rf) for rf in GeneticCode.reading_frames)`` DNA sequence's metadata are included in each translated protein sequence. Positional metadata are not included. Examples -------- Translate DNA into protein using the six possible reading frames and NCBI's standard genetic code (table ID 1, the default genetic code in scikit-bio): >>> from skbio import DNA >>> dna = DNA('ATGCCACTTTAA') >>> for protein in dna.translate_six_frames(): ... protein ... print('') Protein -------------------------- Stats: length: 4 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 MPL* Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 CHF Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 ATL Protein -------------------------- Stats: length: 4 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 LKWH Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 *SG Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 KVA """ return self.transcribe().translate_six_frames(*args, **kwargs) @overrides(GrammaredSequence) def _repr_stats(self): """Define custom statistics to display in the sequence's repr.""" stats = super(DNA, self)._repr_stats() stats.append(("GC-content", "{:.2%}".format(self.gc_content()))) return stats _motifs = _parent_motifs.copy() # Leave this at the bottom _motifs.interpolate(DNA, "find_motifs") scikit-bio-scikit-bio-a3beaa6/skbio/sequence/_genetic_code.py000066400000000000000000000744211520735541300244230ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from typing import TYPE_CHECKING import numpy as np from skbio.util._decorator import classproperty, classonlymethod from skbio._base import SkbioObject from skbio.sequence import Protein, RNA from skbio._base import ElasticLines if TYPE_CHECKING: from typing import Self class GeneticCode(SkbioObject): r"""Genetic code for translating codons to amino acids. Parameters ---------- amino_acids : consumable by ``skbio.Protein`` constructor 64-character vector containing IUPAC amino acid characters. The order of the amino acids should correspond to NCBI's codon order (see *Notes* section below). ``amino_acids`` is the "AAs" field in NCBI's genetic code format [1]_. starts : consumable by ``skbio.Protein`` constructor 64-character vector containing only M and - characters, with start codons indicated by M. The order of the amino acids should correspond to NCBI's codon order (see *Notes* section below). ``starts`` is the "Starts" field in NCBI's genetic code format [1]_. name : str, optional Genetic code name. This is simply metadata and does not affect the functionality of the genetic code itself. See Also -------- RNA.translate DNA.translate GeneticCode.from_ncbi Notes ----- The genetic codes available via :meth:`from_ncbi` and used throughout the examples are defined in [1]_. The genetic code strings defined there are directly compatible with the ``GeneticCode`` constructor. The order of ``amino_acids`` and ``starts`` should correspond to NCBI's codon order, defined in [1]_:: UUUUUUUUUUUUUUUUCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG UUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGG UCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAG Note that scikit-bio displays this ordering using the IUPAC RNA alphabet, while NCBI displays this same ordering using the IUPAC DNA alphabet (for historical purposes). References ---------- .. [1] http://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi Examples -------- Get NCBI's standard genetic code (table ID 1, the default genetic code in scikit-bio): >>> from skbio import GeneticCode >>> GeneticCode.from_ncbi() GeneticCode (Standard) ------------------------------------------------------------------------- AAs = FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG Starts = ---M---------------M---------------M---------------------------- Base1 = UUUUUUUUUUUUUUUUCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG Base2 = UUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGG Base3 = UCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAG Get a different NCBI genetic code (25): >>> GeneticCode.from_ncbi(25) GeneticCode (Candidate Division SR1 and Gracilibacteria) ------------------------------------------------------------------------- AAs = FFLLSSSSYY**CCGWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG Starts = ---M-------------------------------M---------------M------------ Base1 = UUUUUUUUUUUUUUUUCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG Base2 = UUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGG Base3 = UCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAG Define a custom genetic code: >>> GeneticCode('M' * 64, '-' * 64) GeneticCode ------------------------------------------------------------------------- AAs = MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM Starts = ---------------------------------------------------------------- Base1 = UUUUUUUUUUUUUUUUCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG Base2 = UUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGG Base3 = UCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAG Translate an RNA sequence to protein using NCBI's standard genetic code: >>> from skbio import RNA >>> rna = RNA('AUGCCACUUUAA') >>> GeneticCode.from_ncbi().translate(rna) Protein -------------------------- Stats: length: 4 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 MPL* """ _num_codons = 64 _radix_multiplier = np.asarray([16, 4, 1], dtype=np.uint8) _start_stop_options = ["ignore", "optional", "require"] __offset_table = None @classproperty def _offset_table(cls): if cls.__offset_table is None: # create lookup table that is filled with 255 everywhere except for # indices corresponding to U, C, A, and G. 255 was chosen to # represent invalid character offsets because it will create an # invalid (out of bounds) index into `amino_acids` which should # error noisily. this is important in case the valid definite # IUPAC RNA characters change in the future and the assumptions # currently made by the code become invalid table = np.empty(ord(b"U") + 1, dtype=np.uint8) table.fill(255) table[ord(b"U")] = 0 table[ord(b"C")] = 1 table[ord(b"A")] = 2 table[ord(b"G")] = 3 cls.__offset_table = table return cls.__offset_table @classonlymethod def from_ncbi(cls, table_id=1) -> Self: r"""Return NCBI genetic code specified by table ID. Parameters ---------- table_id : int, optional Table ID of the NCBI genetic code to return. Returns ------- GeneticCode NCBI genetic code specified by `table_id`. Notes ----- The table IDs and genetic codes available in this method and used throughout the examples are defined in [1]_. References ---------- .. [1] http://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi Examples -------- Get the NCBI thraustochytrium mitochondrial genetic code (23): >>> tmgc = GeneticCode.from_ncbi(23) >>> tmgc.name 'Thraustochytrium Mitochondrial' """ if table_id not in _ncbi_genetic_codes: raise ValueError( "`table_id` must be one of %r, not %r" % (sorted(_ncbi_genetic_codes), table_id) ) return _ncbi_genetic_codes[table_id] @classproperty def reading_frames(cls): r"""Six possible reading frames. Reading frames are ordered: * 1 (forward) * 2 (forward) * 3 (forward) * -1 (reverse) * -2 (reverse) * -3 (reverse) This property can be passed into ``GeneticCode.translate(reading_frame)``. Returns ------- list (int) Six possible reading frames. """ return [1, 2, 3, -1, -2, -3] @property def name(self): r"""Genetic code name. This is simply metadata and does not affect the functionality of the genetic code itself. Returns ------- str Genetic code name. """ return self._name def __init__(self, amino_acids, starts, name=""): self._set_amino_acids(amino_acids) self._set_starts(starts) self._name = name def _set_amino_acids(self, amino_acids): amino_acids = Protein(amino_acids) if len(amino_acids) != self._num_codons: raise ValueError( "`amino_acids` must be length %d, not %d" % (self._num_codons, len(amino_acids)) ) indices = (amino_acids.values == b"M").nonzero()[0] if indices.size < 1: raise ValueError( "`amino_acids` must contain at least one M (methionine) character" ) self._amino_acids = amino_acids self._m_character_codon = self._index_to_codon(indices[0]) def _set_starts(self, starts): starts = Protein(starts) if len(starts) != self._num_codons: raise ValueError( "`starts` must be length %d, not %d" % (self._num_codons, len(starts)) ) if (starts.values == b"M").sum() + (starts.values == b"-").sum() != len(starts): # to prevent the user from accidentally swapping `starts` and # `amino_acids` and getting a translation back raise ValueError("`starts` may only contain M and - characters") self._starts = starts indices = (self._starts.values == b"M").nonzero()[0] codons = np.empty((indices.size, 3), dtype=np.uint8) for i, index in enumerate(indices): codons[i] = self._index_to_codon(index) self._start_codons = codons def _index_to_codon(self, index): """Convert AA index (0-63) to codon encoded in offsets (0-3).""" codon = np.empty(3, dtype=np.uint8) for i, multiplier in enumerate(self._radix_multiplier): offset, index = divmod(index, multiplier) codon[i] = offset return codon def __str__(self): r"""Return string representation of the genetic code. Returns ------- str Genetic code in NCBI genetic code format. Notes ----- Representation uses NCBI genetic code format defined in [1]_. References ---------- .. [1] http://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi """ return self._build_repr(include_name=False) def __repr__(self): r"""Return string representation of the genetic code. Returns ------- str Genetic code in NCBI genetic code format. Notes ----- Representation uses NCBI genetic code format defined in [1]_ preceded by a header. If the genetic code has a name, it will be included in the header. References ---------- .. [1] http://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi """ return self._build_repr(include_name=True) def _build_repr(self, include_name): lines = ElasticLines() if include_name: name_line = self.__class__.__name__ if len(self.name) > 0: name_line += " (%s)" % self.name lines.add_line(name_line) lines.add_separator() lines.add_line(" AAs = %s" % str(self._amino_acids)) lines.add_line("Starts = %s" % str(self._starts)) base1 = "U" * 16 + "C" * 16 + "A" * 16 + "G" * 16 lines.add_line("Base1 = %s" % base1) base2 = ("U" * 4 + "C" * 4 + "A" * 4 + "G" * 4) * 4 lines.add_line("Base2 = %s" % base2) base3 = "UCAG" * 16 lines.add_line("Base3 = %s" % base3) return lines.to_str() def __eq__(self, other): r"""Determine if the genetic code is equal to another. Genetic codes are equal if they are *exactly* the same type and defined by the same `amino_acids` and `starts`. A genetic code's name (accessed via ``name`` property) does not affect equality. Parameters ---------- other : GeneticCode Genetic code to test for equality against. Returns ------- bool Indicates whether the genetic code is equal to `other`. Examples -------- NCBI genetic codes 1 and 2 are not equal: >>> GeneticCode.from_ncbi(1) == GeneticCode.from_ncbi(2) False Define a custom genetic code: >>> gc = GeneticCode('M' * 64, '-' * 64) Define a second genetic code with the same `amino_acids` and `starts`. Note that the presence of a name does not make the genetic codes unequal: >>> named_gc = GeneticCode('M' * 64, '-' * 64, name='example name') >>> gc == named_gc True """ if self.__class__ != other.__class__: return False # convert Protein to str so that metadata is ignored in comparison. we # only care about the sequence data defining the genetic code if str(self._amino_acids) != str(other._amino_acids): return False if str(self._starts) != str(other._starts): return False return True def __ne__(self, other): r"""Determine if the genetic code is not equal to another. Genetic codes are not equal if their type, `amino_acids`, or `starts` differ. A genetic code's name (accessed via ``name`` property) does not affect equality. Parameters ---------- other : GeneticCode Genetic code to test for inequality against. Returns ------- bool Indicates whether the genetic code is not equal to `other`. """ return not (self == other) def translate(self, sequence, reading_frame=1, start="ignore", stop="ignore"): r"""Translate RNA sequence into protein sequence. Parameters ---------- sequence : RNA RNA sequence to translate. reading_frame : {1, 2, 3, -1, -2, -3} Reading frame to use in translation. 1, 2, and 3 are forward frames and -1, -2, and -3 are reverse frames. If reverse (negative), will reverse complement the sequence before translation. start : {'ignore', 'require', 'optional'} How to handle start codons: * "ignore": translation will start from the beginning of the reading frame, regardless of the presence of a start codon. * "require": translation will start at the first start codon in the reading frame, ignoring all prior positions. The first amino acid in the translated sequence will *always* be methionine (M character), even if an alternative start codon was used in translation. This behavior most closely matches the underlying biology since fMet doesn't have a corresponding IUPAC character. If a start codon does not exist, a ``ValueError`` is raised. * "optional": if a start codon exists in the reading frame, matches the behavior of "require". If a start codon does not exist, matches the behavior of "ignore". stop : {'ignore', 'require', 'optional'} How to handle stop codons: * "ignore": translation will ignore the presence of stop codons and translate to the end of the reading frame. * "require": translation will terminate at the first stop codon. The stop codon will not be included in the translated sequence. If a stop codon does not exist, a ``ValueError`` is raised. * "optional": if a stop codon exists in the reading frame, matches the behavior of "require". If a stop codon does not exist, matches the behavior of "ignore". Returns ------- Protein Translated sequence. See Also -------- translate_six_frames Notes ----- Input RNA sequence metadata are included in the translated protein sequence. Positional metadata are not included. Examples -------- Translate RNA into protein using NCBI's standard genetic code (table ID 1, the default genetic code in scikit-bio): >>> from skbio import RNA, GeneticCode >>> rna = RNA('AGUAUUCUGCCACUGUAAGAA') >>> sgc = GeneticCode.from_ncbi() >>> sgc.translate(rna) Protein -------------------------- Stats: length: 7 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 SILPL*E In this command, we used the default ``start`` behavior, which starts translation at the beginning of the reading frame, regardless of the presence of a start codon. If we specify "require", translation will start at the first start codon in the reading frame (in this example, CUG), ignoring all prior positions: >>> sgc.translate(rna, start='require') Protein -------------------------- Stats: length: 5 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 MPL*E Note that the codon coding for L (CUG) is an alternative start codon in this genetic code. Since we specified "require" mode, methionine (M) was used in place of the alternative start codon (L). This behavior most closely matches the underlying biology since fMet doesn't have a corresponding IUPAC character. Translate the same RNA sequence, also specifying that translation terminate at the first stop codon in the reading frame: >>> sgc.translate(rna, start='require', stop='require') Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 MPL Passing "require" to both ``start`` and ``stop`` trims the translation to the CDS (and in fact requires that one is present in the reading frame). Changing the reading frame to 2 causes an exception to be raised because a start codon doesn't exist in the reading frame: >>> sgc.translate(rna, start='require', stop='require', ... reading_frame=2) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... ValueError: ... """ self._validate_translate_inputs(sequence, reading_frame, start, stop) offset = abs(reading_frame) - 1 if reading_frame < 0: sequence = sequence.reverse_complement() # Translation strategy: # # 1. Obtain view of underlying sequence bytes from the beginning of # the reading frame. # 2. Convert bytes to offsets (0-3, base 4 since there are only 4 # characters allowed: UCAG). # 3. Reshape byte vector into (N, 3), where N is the number of codons # in the reading frame. Each row represents a codon in the # sequence. # 4. (Optional) Find start codon in the reading frame and trim to # this position. Replace start codon with M codon. # 5. Convert each codon (encoded as offsets) into an index # corresponding to an amino acid (0-63). # 6. Obtain translated sequence by indexing into the amino acids # vector (`amino_acids`) using the indices defined in step 5. # 7. (Optional) Find first stop codon and trim to this position. data = sequence.values[offset:].view(np.uint8) # since advanced indexing is used with an integer ndarray, a copy is # always returned. thus, the in-place modification made below # (replacing the start codon) is safe. data = self._offset_table[data] data = data[: data.size // 3 * 3].reshape((-1, 3)) if start in {"require", "optional"}: start_codon_index = data.shape[0] for start_codon in self._start_codons: indices = np.all(data == start_codon, axis=1).nonzero()[0] if indices.size > 0: first_index = indices[0] if first_index < start_codon_index: start_codon_index = first_index if start_codon_index != data.shape[0]: data = data[start_codon_index:] data[0] = self._m_character_codon elif start == "require": self._raise_require_error("start", reading_frame) indices = (data * self._radix_multiplier).sum(axis=1) translated = self._amino_acids.values[indices] if stop in {"require", "optional"}: stop_codon_indices = (translated == b"*").nonzero()[0] if stop_codon_indices.size > 0: translated = translated[: stop_codon_indices[0]] elif stop == "require": self._raise_require_error("stop", reading_frame) metadata = None if sequence.has_metadata(): metadata = sequence.metadata # turn off validation because `translated` is guaranteed to be valid return Protein(translated, metadata=metadata, validate=False) def _validate_translate_inputs(self, sequence, reading_frame, start, stop): if not isinstance(sequence, RNA): raise TypeError( "Sequence to translate must be RNA, not %s" % type(sequence).__name__ ) if reading_frame not in self.reading_frames: raise ValueError( "`reading_frame` must be one of %r, not %r" % (self.reading_frames, reading_frame) ) for name, value in ("start", start), ("stop", stop): if value not in self._start_stop_options: raise ValueError( "`%s` must be one of %r, not %r" % (name, self._start_stop_options, value) ) if sequence.has_gaps(): raise ValueError( "scikit-bio does not support translation of gapped sequences." ) if sequence.has_degenerates(): raise NotImplementedError( "scikit-bio does not currently support " "translation of degenerate sequences." "`RNA.expand_degenerates` can be used " "to obtain all definite versions " "of a degenerate sequence." ) def _raise_require_error(self, name, reading_frame): raise ValueError( "Sequence does not contain a %s codon in the " "current reading frame (`reading_frame=%d`). Presence " "of a %s codon is required with `%s='require'`" % (name, reading_frame, name, name) ) def translate_six_frames(self, sequence, start="ignore", stop="ignore"): """Translate RNA into protein using six possible reading frames. The six possible reading frames are: * 1 (forward) * 2 (forward) * 3 (forward) * -1 (reverse) * -2 (reverse) * -3 (reverse) Translated sequences are yielded in this order. Parameters ---------- sequence : RNA RNA sequence to translate. start : {'ignore', 'require', 'optional'} How to handle start codons. See ``GeneticCode.translate`` for details. stop : {'ignore', 'require', 'optional'} How to handle stop codons. See ``GeneticCode.translate`` for details. Yields ------ Protein Translated sequence in the current reading frame. See Also -------- translate Notes ----- This method is faster than (and equivalent to) performing six independent translations using, for example: ``(gc.translate(seq, reading_frame=rf) for rf in GeneticCode.reading_frames)`` Input RNA sequence metadata are included in each translated protein sequence. Positional metadata are not included. Examples -------- Translate RNA into protein using the six possible reading frames and NCBI's standard genetic code (table ID 1, the default genetic code in scikit-bio): >>> from skbio import RNA, GeneticCode >>> rna = RNA('AUGCCACUUUAA') >>> sgc = GeneticCode.from_ncbi() >>> for protein in sgc.translate_six_frames(rna): ... protein ... print('') Protein -------------------------- Stats: length: 4 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 MPL* Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 CHF Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 ATL Protein -------------------------- Stats: length: 4 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 LKWH Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 *SG Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 KVA """ rc = sequence.reverse_complement() for reading_frame in range(1, 4): yield self.translate( sequence, reading_frame=reading_frame, start=start, stop=stop ) for reading_frame in range(1, 4): yield self.translate( rc, reading_frame=reading_frame, start=start, stop=stop ) # defined at https://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi _ncbi_genetic_codes = { 1: GeneticCode( "FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "---M---------------M---------------M----------------------------", "Standard", ), 2: GeneticCode( "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSS**VVVVAAAADDEEGGGG", "--------------------------------MMMM---------------M------------", "Vertebrate Mitochondrial", ), 3: GeneticCode( "FFLLSSSSYY**CCWWTTTTPPPPHHQQRRRRIIMMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "----------------------------------MM----------------------------", "Yeast Mitochondrial", ), 4: GeneticCode( "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "--MM---------------M------------MMMM---------------M------------", "Mold, Protozoan, and Coelenterate Mitochondrial, and Mycoplasma/Spiroplasma", ), 5: GeneticCode( "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSSSSVVVVAAAADDEEGGGG", "---M----------------------------MMMM---------------M------------", "Invertebrate Mitochondrial", ), 6: GeneticCode( "FFLLSSSSYYQQCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "-----------------------------------M----------------------------", "Ciliate, Dasycladacean and Hexamita Nuclear", ), 9: GeneticCode( "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNNKSSSSVVVVAAAADDEEGGGG", "-----------------------------------M---------------M------------", "Echinoderm and Flatworm Mitochondrial", ), 10: GeneticCode( "FFLLSSSSYY**CCCWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "-----------------------------------M----------------------------", "Euplotid Nuclear", ), 11: GeneticCode( "FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "---M---------------M------------MMMM---------------M------------", "Bacterial, Archaeal and Plant Plastid", ), 12: GeneticCode( "FFLLSSSSYY**CC*WLLLSPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "-------------------M---------------M----------------------------", "Alternative Yeast Nuclear", ), 13: GeneticCode( "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNKKSSGGVVVVAAAADDEEGGGG", "---M------------------------------MM---------------M------------", "Ascidian Mitochondrial", ), 14: GeneticCode( "FFLLSSSSYYY*CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNNKSSSSVVVVAAAADDEEGGGG", "-----------------------------------M----------------------------", "Alternative Flatworm Mitochondrial", ), 16: GeneticCode( "FFLLSSSSYY*LCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "-----------------------------------M----------------------------", "Chlorophycean Mitochondrial", ), 21: GeneticCode( "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIMMTTTTNNNKSSSSVVVVAAAADDEEGGGG", "-----------------------------------M---------------M------------", "Trematode Mitochondrial", ), 22: GeneticCode( "FFLLSS*SYY*LCC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "-----------------------------------M----------------------------", "Scenedesmus obliquus Mitochondrial", ), 23: GeneticCode( "FF*LSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "--------------------------------M--M---------------M------------", "Thraustochytrium Mitochondrial", ), 24: GeneticCode( "FFLLSSSSYY**CCWWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSSKVVVVAAAADDEEGGGG", "---M---------------M---------------M---------------M------------", "Pterobranchia Mitochondrial", ), 25: GeneticCode( "FFLLSSSSYY**CCGWLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG", "---M-------------------------------M---------------M------------", "Candidate Division SR1 and Gracilibacteria", ), } scikit-bio-scikit-bio-a3beaa6/skbio/sequence/_grammared_sequence.py000066400000000000000000000703101520735541300256330ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from warnings import warn from abc import ABCMeta, abstractmethod from itertools import product import re import numpy as np from skbio.util._decorator import classproperty, overrides from skbio.util._misc import MiniRegistry from ._sequence import Sequence class GrammaredSequenceMeta(ABCMeta, type): def __new__(mcs, name, bases, dct): cls = super(GrammaredSequenceMeta, mcs).__new__(mcs, name, bases, dct) abstract_methods = cls.__abstractmethods__ concrete_gap_chars = "gap_chars" not in abstract_methods concrete_degenerate_map = "degenerate_map" not in abstract_methods concrete_definite_chars = "definite_chars" not in abstract_methods concrete_default_gap_char = "default_gap_char" not in abstract_methods # degenerate_chars is not abstract but it depends on degenerate_map # which is abstract. concrete_degenerate_chars = concrete_degenerate_map # Only perform metaclass checks if none of the attributes on the class # are abstract. # TODO: Rather than hard-coding a list of attributes to check, we can # probably check all the attributes on the class and make sure none of # them are abstract. if ( concrete_gap_chars and concrete_degenerate_map and concrete_definite_chars and concrete_default_gap_char and concrete_degenerate_chars ): if cls.default_gap_char not in cls.gap_chars: raise TypeError( "default_gap_char must be in gap_chars for class %s" % name ) if len(cls.gap_chars & cls.degenerate_chars) > 0: raise TypeError( "gap_chars and degenerate_chars must not share any " "characters for class %s" % name ) for key in cls.degenerate_map.keys(): for definite_char in cls.degenerate_map[key]: if definite_char not in cls.definite_chars: raise TypeError( "degenerate_map must expand only to " "characters included in definite_chars " "for class %s" % name ) if len(cls.degenerate_chars & cls.definite_chars) > 0: raise TypeError( "degenerate_chars and definite_chars must not " "share any characters for class %s" % name ) if len(cls.gap_chars & cls.definite_chars) > 0: raise TypeError( "gap_chars and definite_chars must not share any " "characters for class %s" % name ) return cls class GrammaredSequence(Sequence, metaclass=GrammaredSequenceMeta): """Store sequence data conforming to a character set. This is an abstract base class (ABC) that cannot be instantiated. This class is intended to be inherited from to create grammared sequences with custom alphabets. Raises ------ ValueError If sequence characters are not in the character set [1]_. See Also -------- DNA RNA Protein References ---------- .. [1] Cornish-Bowden, A. (1985). Nomenclature for incompletely specified bases in nucleic acid sequences: recommendations 1984. Nucleic Acids Res, 13(9), 3021. Examples -------- Note in the example below that properties either need to be static or use skbio's `classproperty` decorator. >>> from skbio.sequence import GrammaredSequence >>> from skbio.util import classproperty >>> class CustomSequence(GrammaredSequence): ... @classproperty ... def degenerate_map(cls): ... return {"X": set("AB")} ... ... @classproperty ... def definite_chars(cls): ... return set("ABC") ... ... ... @classproperty ... def default_gap_char(cls): ... return '-' ... ... @classproperty ... def gap_chars(cls): ... return set('-.') >>> seq = CustomSequence('ABABACAC') >>> seq CustomSequence -------------------------- Stats: length: 8 has gaps: False has degenerates: False has definites: True -------------------------- 0 ABABACAC >>> seq = CustomSequence('XXXXXX') >>> seq CustomSequence ------------------------- Stats: length: 6 has gaps: False has degenerates: True has definites: False ------------------------- 0 XXXXXX """ # pre-cached Boolean mask (256,) of valid characters (False) __validation_mask = None @classproperty def _validation_mask(cls): # TODO These masks could be defined (as literals) on each concrete # object. For now, memoize! if cls.__validation_mask is None: as_bytes = "".join(cls.alphabet).encode("ascii") cls.__validation_mask = np.invert( np.bincount( np.frombuffer(as_bytes, dtype=np.uint8), minlength=cls._num_extended_ascii_codes, ).astype(bool) ) return cls.__validation_mask # pre-cached ASCII codes of alphabets __degenerate_codes = None __definite_codes = None __gap_codes = None __canonical_codes = None __noncanonical_codes = None @classproperty def _degenerate_codes(cls): if cls.__degenerate_codes is None: chars = sorted(cls.degenerate_chars) cls.__degenerate_codes = np.asarray([ord(d) for d in chars], dtype=int) return cls.__degenerate_codes @classproperty def _definite_codes(cls): if cls.__definite_codes is None: chars = sorted(cls.definite_chars) cls.__definite_codes = np.asarray([ord(d) for d in chars], dtype=int) return cls.__definite_codes @classproperty def _gap_codes(cls): if cls.__gap_codes is None: chars = sorted(cls.gap_chars) cls.__gap_codes = np.asarray([ord(g) for g in chars], dtype=int) return cls.__gap_codes @classproperty def _canonical_codes(cls): if cls.__canonical_codes is None: chars = sorted(cls.definite_chars - cls.noncanonical_chars) cls.__canonical_codes = np.asarray([ord(c) for c in chars], dtype=int) return cls.__canonical_codes @classproperty def _noncanonical_codes(cls): if cls.__noncanonical_codes is None: chars = sorted(cls.noncanonical_chars) cls.__noncanonical_codes = np.asarray([ord(c) for c in chars], dtype=int) return cls.__noncanonical_codes # pre-cached Boolean masks (128,) of certain character sets (True) __definite_hash = None __degenerate_hash = None __gap_hash = None __canonical_hash = None __nongap_hash = None __degen_nonca_hash = None @classproperty def _definite_hash(cls): if cls.__definite_hash is None: cls.__definite_hash = np.zeros((Sequence._num_ascii_codes,), dtype=bool) cls.__definite_hash[cls._definite_codes] = True return cls.__definite_hash @classproperty def _degenerate_hash(cls): if cls.__degenerate_hash is None: cls.__degenerate_hash = np.zeros((Sequence._num_ascii_codes,), dtype=bool) cls.__degenerate_hash[cls._degenerate_codes] = True return cls.__degenerate_hash @classproperty def _gap_hash(cls): if cls.__gap_hash is None: cls.__gap_hash = np.zeros((Sequence._num_ascii_codes,), dtype=bool) cls.__gap_hash[cls._gap_codes] = True return cls.__gap_hash @classproperty def _canonical_hash(cls): if cls.__canonical_hash is None: cls.__canonical_hash = np.zeros((Sequence._num_ascii_codes,), dtype=bool) cls.__canonical_hash[cls._canonical_codes] = True return cls.__canonical_hash @classproperty def _nongap_hash(cls): if cls.__nongap_hash is None: cls.__nongap_hash = cls._definite_hash | cls._degenerate_hash return cls.__nongap_hash @classproperty def _degen_nonca_hash(cls): if cls.__degen_nonca_hash is None: if cls._noncanonical_codes.size > 0: cls.__degen_nonca_hash = cls._degenerate_hash.copy() cls.__degen_nonca_hash[cls._noncanonical_codes] = True else: cls.__canonical_hash = cls._degenerate_hash return cls.__degen_nonca_hash @classproperty def alphabet(cls): """Return valid characters. This includes gap, definite, and degenerate characters. Returns ------- set Valid characters. """ return cls.degenerate_chars | cls.definite_chars | cls.gap_chars @classproperty @abstractmethod def gap_chars(cls): """Return characters defined as gaps. Returns ------- set Characters defined as gaps. """ raise NotImplementedError @classproperty @abstractmethod def default_gap_char(cls): """Gap character to use when constructing a new gapped sequence. This character is used when it is necessary to represent gap characters in a new sequence. For example, a majority consensus sequence will use this character to represent gaps. Returns ------- str Default gap character. """ raise NotImplementedError @classproperty def degenerate_chars(cls): """Return degenerate characters. Returns ------- set Degenerate characters. """ return set(cls.degenerate_map) @classproperty def nondegenerate_chars(cls): """Return non-degenerate characters. Returns ------- set Non-degenerate characters. Warnings -------- ``nondegenerate_chars`` is deprecated as of ``0.5.0``. It has been renamed to ``definite_chars``. See Also -------- definite_chars """ # noqa: D416 # @deprecated warn("nondegenerate_chars is deprecated as of 0.5.0", DeprecationWarning) return cls.definite_chars @classproperty @abstractmethod def definite_chars(cls): """Return definite characters. Returns ------- set Definite characters. """ raise NotImplementedError @classproperty def noncanonical_chars(cls): """Return non-canonical characters. Returns ------- set Non-canonical characters. """ return set() @classproperty @abstractmethod def degenerate_map(cls): """Return mapping of degenerate to definite characters. Returns ------- dict (set) Mapping of each degenerate character to the set of definite characters it represents. """ raise NotImplementedError @classproperty def wildcard_char(cls): """Return wildcard character. Returns ------- str of length 1 Wildcard character. """ return None @property def _motifs(self): return _motifs @overrides(Sequence) def __init__( self, sequence, metadata=None, positional_metadata=None, interval_metadata=None, lowercase=False, validate=True, ): super(GrammaredSequence, self).__init__( sequence, metadata, positional_metadata, interval_metadata, lowercase, ) if validate: self._validate() def _validate(self): # This is the fastest way that we have found to identify the # presence or absence of certain characters (numbers). # It works by multiplying a mask where the numbers which are # permitted have a zero at their index, and all others have a one. # The result is a vector which will propagate counts of invalid # numbers and remove counts of valid numbers, so that we need only # see if the array is empty to determine validity. invalid_characters = ( np.bincount(self._bytes, minlength=self._num_extended_ascii_codes) * self._validation_mask ) if np.any(invalid_characters): bad = list(np.where(invalid_characters > 0)[0].astype(np.uint8).view("|S1")) raise ValueError( "Invalid character%s in sequence: %r. \n" "Valid characters: %r\n" "Note: Use `lowercase` if your sequence contains lowercase " "characters not in the sequence's alphabet." % ( "s" if len(bad) > 1 else "", [str(b.tobytes().decode("ascii")) for b in bad] if len(bad) > 1 else bad[0], list(self.alphabet), ) ) def gaps(self): """Find positions containing gaps in the biological sequence. Returns ------- 1D np.ndarray (bool) Boolean vector where ``True`` indicates a gap character is present at that position in the biological sequence. See Also -------- has_gaps Examples -------- >>> from skbio import DNA >>> s = DNA('AC-G-') >>> s.gaps() array([False, False, True, False, True], dtype=bool) """ return self._gap_hash[self._bytes] def has_gaps(self): """Determine if the sequence contains one or more gap characters. Returns ------- bool Indicates whether there are one or more occurrences of gap characters in the biological sequence. Examples -------- >>> from skbio import DNA >>> s = DNA('ACACGACGTT') >>> s.has_gaps() False >>> t = DNA('A.CAC--GACGTT') >>> t.has_gaps() True """ # TODO use count, there aren't that many gap chars # TODO: cache results return bool(self.gaps().any()) def degenerates(self): """Find positions containing degenerate characters in the sequence. Returns ------- 1D np.ndarray (bool) Boolean vector where ``True`` indicates a degenerate character is present at that position in the biological sequence. See Also -------- has_degenerates definites has_definites Examples -------- >>> from skbio import DNA >>> s = DNA('ACWGN') >>> s.degenerates() array([False, False, True, False, True], dtype=bool) """ return self._degenerate_hash[self._bytes] def has_degenerates(self): """Determine if sequence contains one or more degenerate characters. Returns ------- bool Indicates whether there are one or more occurrences of degenerate characters in the biological sequence. See Also -------- degenerates definites has_definites Examples -------- >>> from skbio import DNA >>> s = DNA('ACAC-GACGTT') >>> s.has_degenerates() False >>> t = DNA('ANCACWWGACGTT') >>> t.has_degenerates() True """ # TODO use bincount! # TODO: cache results return bool(self.degenerates().any()) def definites(self): """Find positions containing definite characters in the sequence. Returns ------- 1D np.ndarray (bool) Boolean vector where ``True`` indicates a definite character is present at that position in the biological sequence. See Also -------- has_definites degenerates Examples -------- >>> from skbio import DNA >>> s = DNA('ACWGN') >>> s.definites() array([ True, True, False, True, False], dtype=bool) """ return self._definite_hash[self._bytes] def nondegenerates(self): """Find positions containing non-degenerate characters in the sequence. Returns ------- 1D np.ndarray (bool) Boolean vector where ``True`` indicates a non-degenerate character is present at that position in the biological sequence. Warnings -------- ``nondegenerates`` is deprecated as of ``0.5.0``. It has been renamed to ``definites``. See Also -------- definites has_definites degenerates Examples -------- >>> from skbio import DNA >>> s = DNA('ACWGN') >>> s.nondegenerates() array([ True, True, False, True, False], dtype=bool) """ # noqa: D416 # @deprecated warn("nondenengerates is deprecated as of 0.5.0.", DeprecationWarning) return self.definites() def has_definites(self): """Determine if sequence contains one or more definite characters. Returns ------- bool Indicates whether there are one or more occurrences of definite characters in the biological sequence. See Also -------- definites degenerates has_degenerates Examples -------- >>> from skbio import DNA >>> s = DNA('NWNNNNNN') >>> s.has_definites() False >>> t = DNA('ANCACWWGACGTT') >>> t.has_definites() True """ # TODO: cache results return bool(self.definites().any()) def has_nondegenerates(self): """Determine if sequence contains one or more non-degenerate characters. Returns ------- bool Indicates whether there are one or more occurrences of non-degenerate characters in the biological sequence. Warnings -------- ``has_nondegenerates`` is deprecated as of ``0.5.0``. It has been renamed to ``has_definites``. See Also -------- definites has_definites degenerates has_degenerates Examples -------- >>> from skbio import DNA >>> s = DNA('NWNNNNNN') >>> s.has_nondegenerates() False >>> t = DNA('ANCACWWGACGTT') >>> t.has_nondegenerates() True """ # noqa: D416 # TODO: cache results # @deprecated warn("has_nondegenerates is deprecated as of 0.5.0", DeprecationWarning) return self.has_definites() def degap(self): """Return a new sequence with gap characters removed. Returns ------- GrammaredSequence A new sequence with all gap characters removed. See Also -------- gap_chars Notes ----- The type and metadata of the result will be the same as the biological sequence. If positional metadata is present, it will be filtered in the same manner as the sequence characters and included in the resulting degapped sequence. Examples -------- >>> from skbio import DNA >>> s = DNA('GGTC-C--ATT-C.', ... positional_metadata={'quality':range(14)}) >>> s.degap() DNA ----------------------------- Positional metadata: 'quality': Stats: length: 9 has gaps: False has degenerates: False has definites: True GC-content: 55.56% ----------------------------- 0 GGTCCATTC """ return self[np.invert(self.gaps())] def expand_degenerates(self): """Yield all possible definite versions of the sequence. Yields ------ GrammaredSequence Definite version of the sequence. See Also -------- degenerate_map Notes ----- There is no guaranteed ordering to the definite sequences that are yielded. Each definite sequence will have the same type, metadata, and positional metadata as the biological sequence. Examples -------- >>> from skbio import DNA >>> seq = DNA('TRG') >>> seq_generator = seq.expand_degenerates() >>> for s in sorted(seq_generator, key=str): ... s ... print('') DNA -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True GC-content: 33.33% -------------------------- 0 TAG DNA -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True GC-content: 66.67% -------------------------- 0 TGG """ degen_chars = self.degenerate_map nonexpansion_chars = self.definite_chars.union(self.gap_chars) expansions = [] for char in self: char = str(char) if char in nonexpansion_chars: expansions.append(char) else: expansions.append(degen_chars[char]) metadata = None if self.has_metadata(): metadata = self.metadata positional_metadata = None if self.has_positional_metadata(): positional_metadata = self.positional_metadata for definite_seq in product(*expansions): yield self._constructor( sequence="".join(definite_seq), metadata=metadata, positional_metadata=positional_metadata, interval_metadata=self.interval_metadata, ) def to_regex(self, within_capture=False): """Return regular expression object that accounts for degenerate chars. Parameters ---------- within_capture : bool If ``True``, format the regex pattern for the sequence into a single capture group. If ``False``, compile the regex pattern as-is with no capture groups. Returns ------- regex Pre-compiled regular expression object (as from ``re.compile``) that matches all definite versions of this sequence, and nothing else. Examples -------- >>> from skbio import DNA >>> seq = DNA('TRG') >>> regex = seq.to_regex() >>> regex.match('TAG').string 'TAG' >>> regex.match('TGG').string 'TGG' >>> regex.match('TCG') is None True >>> regex = seq.to_regex(within_capture=True) >>> regex.match('TAG').groups(0) ('TAG',) """ regex_parts = [] for base in str(self): if base in self.degenerate_chars: regex_parts.append("[{0}]".format("".join(self.degenerate_map[base]))) else: regex_parts.append(base) regex_string = "".join(regex_parts) if within_capture: regex_string = "({})".format(regex_string) return re.compile(regex_string) def to_definites(self, degenerate="wild", noncanonical=True): """Convert degenerate and noncanonical characters to alternative characters. Parameters ---------- degenerate : {"wild", "gap", "del", str of length 1}, optional How degenerate/non-canonical characters should be treated: Replace them with the wildcard character ("wild", default), or the default gap character ("gap"), or a user-defined character (str of length 1), or remove them ("del"). noncanonical : bool, optional Treat non-canonical characters in the same way as degenerate characters (``True``, default), or leave them as-is (``False``). Returns ------- GrammaredSequence Converted version of the sequence. """ errmsg = ( f'%s character for sequence type "{self.__class__}" is undefined or ' "invalid." ) if noncanonical: pos = self._degen_nonca_hash[self._bytes] else: pos = self._degenerate_hash[self._bytes] if degenerate == "del": seq = self._bytes[np.where(1 - pos)[0]] else: if degenerate == "wild": sub_char = self.wildcard_char if not isinstance(sub_char, str): raise ValueError(errmsg % "Wildcard") elif degenerate == "gap": sub_char = self.default_gap_char elif isinstance(degenerate, str) and len(degenerate) == 1: if degenerate in self.alphabet: sub_char = degenerate else: raise ValueError( f"Invalid character '{degenerate}' in sequence. Character must " f"be within sequence alphabet: {self.alphabet}" ) else: raise ValueError('Invalid value for parameter "degenerate".') seq = np.where(pos, ord(sub_char), self._bytes) return self._constructor(sequence=seq) def find_motifs(self, motif_type, min_length=1, ignore=None): """Search the biological sequence for motifs. Options for `motif_type`: Parameters ---------- motif_type : str Type of motif to find. min_length : int, optional Only motifs at least as long as `min_length` will be returned. ignore : 1D array_like (bool), optional Boolean vector indicating positions to ignore when matching. Yields ------ slice Location of the motif in the biological sequence. Raises ------ ValueError If an unknown `motif_type` is specified. Examples -------- >>> from skbio import DNA >>> s = DNA('ACGGGGAGGCGGAG') >>> for motif_slice in s.find_motifs('purine-run', min_length=2): ... motif_slice ... str(s[motif_slice]) slice(2, 9, None) 'GGGGAGG' slice(10, 14, None) 'GGAG' Gap characters can disrupt motifs: >>> s = DNA('GG-GG') >>> for motif_slice in s.find_motifs('purine-run'): ... motif_slice slice(0, 2, None) slice(3, 5, None) Gaps can be ignored by passing the gap boolean vector to `ignore`: >>> s = DNA('GG-GG') >>> for motif_slice in s.find_motifs('purine-run', ignore=s.gaps()): ... motif_slice slice(0, 5, None) """ if motif_type not in self._motifs: raise ValueError( "Not a known motif (%r) for this sequence (%s)." % (motif_type, self.__class__.__name__) ) return self._motifs[motif_type](self, min_length, ignore) @overrides(Sequence) def _constructor(self, **kwargs): return self.__class__(validate=False, lowercase=False, **kwargs) @overrides(Sequence) def _repr_stats(self): """Define custom statistics to display in the sequence's repr.""" stats = super(GrammaredSequence, self)._repr_stats() stats.append(("has gaps", "%r" % self.has_gaps())) stats.append(("has degenerates", "%r" % self.has_degenerates())) stats.append(("has definites", "%r" % self.has_definites())) return stats _motifs = MiniRegistry() # Leave this at the bottom _motifs.interpolate(GrammaredSequence, "find_motifs") scikit-bio-scikit-bio-a3beaa6/skbio/sequence/_nucleotide_mixin.py000066400000000000000000000253521520735541300253510ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from abc import ABCMeta, abstractmethod import numpy as np from skbio.util._decorator import classproperty from ._grammared_sequence import _motifs as parent_motifs class NucleotideMixin(metaclass=ABCMeta): """Mixin for adding functionality for working with sequences of nucleotides. This is an abstract base class (ABC) that cannot be instantiated. See Also -------- DNA RNA """ __complement_lookup = None __gc_codes = None @classproperty def _complement_lookup(cls): if cls.__complement_lookup is not None: return cls.__complement_lookup lookup = np.zeros(cls._num_extended_ascii_codes, dtype=np.uint8) for key, value in cls.complement_map.items(): lookup[ord(key)] = ord(value) cls.__complement_lookup = lookup return lookup @classproperty def _gc_codes(cls): if cls.__gc_codes is None: gc_iupac_chars = "GCS" cls.__gc_codes = np.asarray([ord(g) for g in gc_iupac_chars]) return cls.__gc_codes @property def _motifs(self): return _motifs @classproperty @abstractmethod def complement_map(cls): """Return mapping of nucleotide characters to their complements. Returns ------- dict Mapping of each character to its complement. Notes ----- Complements cannot be defined for a generic nucleotide sequence because the complement of ``A`` is ambiguous. Thanks, nature... """ raise NotImplementedError def complement(self, reverse=False): """Return the complement of the nucleotide sequence. Parameters ---------- reverse : bool, optional If ``True``, return the reverse complement. If positional and/or interval metadata are present, they will be reversed. Returns ------- NucleotideMixin The (reverse) complement of the nucleotide sequence. The type and metadata of the result will be the same as the nucleotide sequence. If `reverse` is ``True``, positional or interval metadata will be reversed if it is present. See Also -------- reverse_complement complement_map Examples -------- >>> from skbio import DNA >>> seq = DNA('TTCATT', positional_metadata={'quality':range(6)}) >>> seq DNA ----------------------------- Positional metadata: 'quality': Stats: length: 6 has gaps: False has degenerates: False has definites: True GC-content: 16.67% ----------------------------- 0 TTCATT >>> seq.complement() DNA ----------------------------- Positional metadata: 'quality': Stats: length: 6 has gaps: False has degenerates: False has definites: True GC-content: 16.67% ----------------------------- 0 AAGTAA >>> rc = seq.complement(reverse=True) >>> rc DNA ----------------------------- Positional metadata: 'quality': Stats: length: 6 has gaps: False has degenerates: False has definites: True GC-content: 16.67% ----------------------------- 0 AATGAA >>> rc.positional_metadata['quality'].values # doctest: +ELLIPSIS array([5, 4, 3, 2, 1, 0]... """ result = self._complement_lookup[self._bytes] metadata = None if self.has_metadata(): metadata = self.metadata positional_metadata = None if self.has_positional_metadata(): positional_metadata = self.positional_metadata complement = self._constructor( sequence=result, metadata=metadata, positional_metadata=positional_metadata ) if reverse: # this has to be before the interval metadata code, # because __gititem__ drops interval_metadata. complement = complement[::-1] if self.has_interval_metadata(): complement.interval_metadata = self.interval_metadata if reverse: # TODO: this can be revised to match # positional_metadata when __getitem__ # supports interval_metadata complement.interval_metadata._reverse() return complement def reverse_complement(self): """Return the reverse complement of the nucleotide sequence. Returns ------- NucleotideMixin The reverse complement of the nucleotide sequence. The type and metadata of the result will be the same as the nucleotide sequence. If positional metadata is present, it will be reversed. See Also -------- complement is_reverse_complement Notes ----- This method is equivalent to ``self.complement(reverse=True)``. Examples -------- >>> from skbio import DNA >>> seq = DNA('TTCATT', ... positional_metadata={'quality':range(6)}) >>> seq = seq.reverse_complement() >>> seq DNA ----------------------------- Positional metadata: 'quality': Stats: length: 6 has gaps: False has degenerates: False has definites: True GC-content: 16.67% ----------------------------- 0 AATGAA >>> seq.positional_metadata['quality'].values # doctest: +ELLIPSIS array([5, 4, 3, 2, 1, 0]... """ return self.complement(reverse=True) def is_reverse_complement(self, other): r"""Determine if a sequence is the reverse complement of this sequence. Parameters ---------- other : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Sequence to compare to. Returns ------- bool ``True`` if `other` is the reverse complement of the nucleotide sequence. Raises ------ TypeError If `other` is a ``Sequence`` object with a different type than the nucleotide sequence. See Also -------- reverse_complement Examples -------- >>> from skbio import DNA >>> DNA('TTCATT').is_reverse_complement('AATGAA') True >>> DNA('TTCATT').is_reverse_complement('AATGTT') False >>> DNA('ACGT').is_reverse_complement('ACGT') True """ other = self._munge_to_sequence(other, "is_reverse_complement") # avoid computing the reverse complement if possible if len(self) != len(other): return False else: # we reverse complement ourselves because `other` is a `Sequence` # object at this point and we only care about comparing the # underlying sequence data return self.reverse_complement()._string == other._string def gc_content(self): """Calculate the relative frequency of G's and C's in the sequence. This includes G, C, and S characters. This is equivalent to calling ``gc_frequency(relative=True)``. Note that the sequence will be degapped before the operation, so gap characters will not be included when calculating the length of the sequence. Returns ------- float Relative frequency of G's and C's in the sequence. See Also -------- gc_frequency Examples -------- >>> from skbio import DNA >>> DNA('ACGT').gc_content() 0.5 >>> DNA('ACGTACGT').gc_content() 0.5 >>> DNA('ACTTAGTT').gc_content() 0.25 >>> DNA('ACGT--..').gc_content() 0.5 >>> DNA('--..').gc_content() 0 `S` means `G` or `C`, so it counts: >>> DNA('ASST').gc_content() 0.5 Other degenerates don't count: >>> DNA('RYKMBDHVN').gc_content() 0.0 """ return self.gc_frequency(relative=True) def gc_frequency(self, relative=False): """Calculate frequency of G's and C's in the sequence. This calculates the minimum GC frequency, which corresponds to IUPAC characters G, C, and S (which stands for G or C). Parameters ---------- relative : bool, optional If False return the frequency of G, C, and S characters (ie the count). If True return the relative frequency, ie the proportion of G, C, and S characters in the sequence. In this case the sequence will also be degapped before the operation, so gap characters will not be included when calculating the length of the sequence. Returns ------- int or float Either frequency (count) or relative frequency (proportion), depending on `relative`. See Also -------- gc_content Examples -------- >>> from skbio import DNA >>> DNA('ACGT').gc_frequency() 2 >>> DNA('ACGT').gc_frequency(relative=True) 0.5 >>> DNA('ACGT--..').gc_frequency(relative=True) 0.5 >>> DNA('--..').gc_frequency(relative=True) 0 `S` means `G` or `C`, so it counts: >>> DNA('ASST').gc_frequency() 2 Other degenerates don't count: >>> DNA('RYKMBDHVN').gc_frequency() 0 """ counts = np.bincount(self._bytes, minlength=self._num_extended_ascii_codes) gc = counts[self._gc_codes].sum() if relative: seq = self.degap() if len(seq) != 0: gc /= len(seq) return gc _motifs = parent_motifs.copy() @_motifs("purine-run") def _motif_purine_run(sequence, min_length, ignore): """Identify purine runs.""" return sequence.find_with_regex("([AGR]{%d,})" % min_length, ignore=ignore) @_motifs("pyrimidine-run") def _motif_pyrimidine_run(sequence, min_length, ignore): """Identify pyrimidine runs.""" return sequence.find_with_regex("([CTUY]{%d,})" % min_length, ignore=ignore) scikit-bio-scikit-bio-a3beaa6/skbio/sequence/_protein.py000066400000000000000000000227711520735541300234740ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from skbio.util._decorator import classproperty, overrides from ._grammared_sequence import GrammaredSequence, _motifs as parent_motifs from skbio.io.descriptors import Read, Write class Protein(GrammaredSequence): r"""Store protein sequence data and optional associated metadata. Parameters ---------- sequence : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Characters representing the protein sequence itself. metadata : dict, optional Arbitrary metadata which applies to the entire sequence. positional_metadata : Pandas DataFrame consumable, optional Arbitrary per-character metadata. For example, quality data from sequencing reads. Must be able to be passed directly to the Pandas DataFrame constructor. interval_metadata : IntervalMetadata Arbitrary interval metadata which applies to intervals within a sequence to store interval features (such as protein domains). lowercase : bool or str, optional If ``True``, lowercase sequence characters will be converted to uppercase characters in order to be valid IUPAC Protein characters. If ``False``, no characters will be converted. If a str, it will be treated as a key into the positional metadata of the object. All lowercase characters will be converted to uppercase, and a ``True`` value will be stored in a boolean array in the positional metadata under the key. validate : bool, optional If ``True``, validation will be performed to ensure that all sequence characters are in the IUPAC protein character set. If ``False``, validation will not be performed. Turning off validation will improve runtime performance. If invalid characters are present, however, there is **no guarantee that operations performed on the resulting object will work or behave as expected.** Only turn off validation if you are certain that the sequence characters are valid. To store sequence data that is not IUPAC-compliant, use ``Sequence``. See Also -------- GrammaredSequence Notes ----- According to the IUPAC notation [1]_ , a protein sequence may contain the following 20 definite characters (canonical amino acids): +-----+---------+--------------+ |Code |3-letter |Amino acid | +=====+=========+==============+ |``A``|Ala |Alanine | +-----+---------+--------------+ |``C``|Cys |Cysteine | +-----+---------+--------------+ |``D``|Asp |Aspartic acid | +-----+---------+--------------+ |``E``|Glu |Glutamic acid | +-----+---------+--------------+ |``F``|Phe |Phenylalanine | +-----+---------+--------------+ |``G``|Gly |Glycine | +-----+---------+--------------+ |``H``|His |Histidine | +-----+---------+--------------+ |``I``|Ile |Isoleucine | +-----+---------+--------------+ |``K``|Lys |Lysine | +-----+---------+--------------+ |``L``|Leu |Leucine | +-----+---------+--------------+ |``M``|Met |Methionine | +-----+---------+--------------+ |``N``|Asn |Asparagine | +-----+---------+--------------+ |``P``|Pro |Proline | +-----+---------+--------------+ |``Q``|Gln |Glutamine | +-----+---------+--------------+ |``R``|Arg |Arginine | +-----+---------+--------------+ |``S``|Ser |Serine | +-----+---------+--------------+ |``T``|Thr |Threonine | +-----+---------+--------------+ |``V``|Val |Valine | +-----+---------+--------------+ |``W``|Trp |Tryptophan | +-----+---------+--------------+ |``Y``|Tyr |Tyrosine | +-----+---------+--------------+ And the following four degenerate characters, each of which representing two or more amino acids: +-----+---------+------------+ |Code |3-letter |Amino acids | +=====+=========+============+ |``B``|Asx |D or N | +-----+---------+------------+ |``Z``|Glx |E or Q | +-----+---------+------------+ |``J``|Xle |I or L | +-----+---------+------------+ |``X``|Xaa |All 20 | +-----+---------+------------+ Plus one stop character: ``*`` (Ter), and two gap characters: ``-`` and ``.``. Characters other than the above 27 are not allowed. If you intend to use additional characters to represent non-canonical amino acids, such as ``U`` (Sec, Selenocysteine) and ``O`` (Pyl, Pyrrolysine), you may create a custom alphabet using ``GrammaredSequence``. Directly modifying the alphabet of ``Protein`` may break functions that rely on the IUPAC alphabet. It should be noted that some functions do not support certain characters. For example, the BLOSUM and PAM substitution matrices do not support ``J`` (Xle). In such circumstances, unsupported characters will be replaced with ``X`` to represent any of the canonical amino acids. References ---------- .. [1] Cornish-Bowden, A. (1985). Nomenclature for incompletely specified bases in nucleic acid sequences: recommendations 1984. Nucleic Acids Res, 13(9), 3021. Examples -------- >>> from skbio import Protein >>> Protein('PAW') Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 PAW Convert lowercase characters to uppercase: >>> Protein('paW', lowercase=True) Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 PAW """ __stop_codes = None read = Read() write = Write() @classproperty def _stop_codes(cls): if cls.__stop_codes is None: stops = cls.stop_chars cls.__stop_codes = np.asarray([ord(s) for s in stops]) return cls.__stop_codes @classproperty @overrides(GrammaredSequence) def alphabet(cls): return super(Protein, cls).alphabet | cls.stop_chars @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set("ACDEFGHIKLMNOPQRSTUVWY") @classproperty @overrides(GrammaredSequence) def noncanonical_chars(cls): return set("OU") @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return { "B": set("DN"), "Z": set("EQ"), "J": set("IL"), "X": set("ACDEFGHIKLMNOPQRSTUVWY"), } @classproperty def stop_chars(cls): """Return characters representing translation stop codons. Returns ------- set Characters representing translation stop codons. """ return set("*") @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set("-.") @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return "-" @classproperty @overrides(GrammaredSequence) def wildcard_char(cls): return "X" @property def _motifs(self): return _motifs def stops(self): """Find positions containing stop characters in the protein sequence. Returns ------- 1D np.ndarray (bool) Boolean vector where ``True`` indicates a stop character is present at that position in the protein sequence. See Also -------- has_stops Examples -------- >>> from skbio import Protein >>> s = Protein('PAW') >>> s.stops() array([False, False, False], dtype=bool) >>> s = Protein('PAW*E*') >>> s.stops() array([False, False, False, True, False, True], dtype=bool) """ return np.isin(self._bytes, self._stop_codes) def has_stops(self): """Determine if the sequence contains one or more stop characters. Returns ------- bool Indicates whether there are one or more occurrences of stop characters in the protein sequence. Examples -------- >>> from skbio import Protein >>> s = Protein('PAW') >>> s.has_stops() False >>> s = Protein('PAW*E*') >>> s.has_stops() True """ return bool(self.stops().any()) @overrides(GrammaredSequence) def _repr_stats(self): """Define custom statistics to display in the sequence's repr.""" stats = super(Protein, self)._repr_stats() stats.append(("has stops", "%r" % self.has_stops())) return stats _motifs = parent_motifs.copy() @_motifs("N-glycosylation") def _motif_nitro_glycosylation(sequence, min_length, ignore): """Identify N-glycosylation runs.""" return sequence.find_with_regex("(N[^PX][ST][^PX])", ignore=ignore) # Leave this at the bottom _motifs.interpolate(Protein, "find_motifs") scikit-bio-scikit-bio-a3beaa6/skbio/sequence/_repr.py000066400000000000000000000102421520735541300227520ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import math from skbio.util._misc import chunk_str from skbio.metadata._repr import _MetadataReprBuilder class _SequenceReprBuilder(_MetadataReprBuilder): """Build a ``Sequence`` repr. Parameters ---------- seq : Sequence Sequence to repr. width : int Maximum width of the repr. indent : int Number of spaces to use for indented lines. chunk_size: int Number of characters in each chunk of a sequence. """ def __init__(self, seq, width, indent, chunk_size): super(_SequenceReprBuilder, self).__init__(seq, width, indent) self._chunk_size = chunk_size def _process_header(self): cls_name = self._obj.__class__.__name__ self._lines.add_line(cls_name) self._lines.add_separator() def _process_data(self): num_lines, num_chars, column_width = self._find_optimal_seq_chunking() # display entire sequence if we can, else display the first two and # last two lines separated by ellipsis if num_lines <= 5: self._lines.add_lines( self._format_chunked_seq(range(num_lines), num_chars, column_width) ) else: self._lines.add_lines( self._format_chunked_seq(range(2), num_chars, column_width) ) self._lines.add_line("...") self._lines.add_lines( self._format_chunked_seq( range(num_lines - 2, num_lines), num_chars, column_width ) ) def _find_optimal_seq_chunking(self): """Find the optimal number of sequence chunks to fit on a single line. Returns the number of lines the sequence will occupy, the number of sequence characters displayed on each line, and the column width necessary to display position info using the optimal number of sequence chunks. """ # strategy: use an iterative approach to find the optimal number of # sequence chunks per line. start with a single chunk and increase # until the max line width is exceeded. when this happens, the previous # number of chunks is optimal num_lines = 0 num_chars = 0 column_width = 0 num_chunks = 1 not_exceeded = True while not_exceeded: line_len, new_chunk_info = self._compute_chunked_seq_line_len(num_chunks) not_exceeded = line_len <= self._width if not_exceeded: num_lines, num_chars, column_width = new_chunk_info num_chunks += 1 return num_lines, num_chars, column_width def _compute_chunked_seq_line_len(self, num_chunks): """Compute line length based on a number of chunks.""" num_chars = num_chunks * self._chunk_size # ceil to account for partial line num_lines = int(math.ceil(len(self._obj) / num_chars)) # position column width is fixed width, based on the number of # characters necessary to display the position of the final line (all # previous positions will be left justified using this width) column_width = len("%d " % ((num_lines - 1) * num_chars)) # column width + number of sequence characters + spaces between chunks line_len = column_width + num_chars + (num_chunks - 1) return line_len, (num_lines, num_chars, column_width) def _format_chunked_seq(self, line_idxs, num_chars, column_width): """Format specified lines of chunked sequence data.""" lines = [] for line_idx in line_idxs: seq_idx = line_idx * num_chars chars = str(self._obj[seq_idx : seq_idx + num_chars]) chunked_chars = chunk_str(chars, self._chunk_size, " ") lines.append(("%d" % seq_idx).ljust(column_width) + chunked_chars) return lines scikit-bio-scikit-bio-a3beaa6/skbio/sequence/_rna.py000066400000000000000000000337221520735541300225720ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import skbio from skbio.util._decorator import classproperty, overrides from ._nucleotide_mixin import NucleotideMixin, _motifs as _parent_motifs from ._grammared_sequence import GrammaredSequence from skbio.io.descriptors import Read, Write class RNA(GrammaredSequence, NucleotideMixin): r"""Store RNA sequence data and optional associated metadata. Parameters ---------- sequence : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Characters representing the RNA sequence itself. metadata : dict, optional Arbitrary metadata which applies to the entire sequence. positional_metadata : Pandas DataFrame consumable, optional Arbitrary per-character metadata. For example, quality data from sequencing reads. Must be able to be passed directly to the Pandas DataFrame constructor. interval_metadata : IntervalMetadata Arbitrary metadata which applies to intervals within a sequence to store interval features (such as exons or introns on the sequence). lowercase : bool or str, optional If ``True``, lowercase sequence characters will be converted to uppercase characters in order to be valid IUPAC RNA characters. If ``False``, no characters will be converted. If a str, it will be treated as a key into the positional metadata of the object. All lowercase characters will be converted to uppercase, and a ``True`` value will be stored in a boolean array in the positional metadata under the key. validate : bool, optional If ``True``, validation will be performed to ensure that all sequence characters are in the IUPAC RNA character set. If ``False``, validation will not be performed. Turning off validation will improve runtime performance. If invalid characters are present, however, there is **no guarantee that operations performed on the resulting object will work or behave as expected.** Only turn off validation if you are certain that the sequence characters are valid. To store sequence data that is not IUPAC-compliant, use ``Sequence``. See Also -------- DNA GrammaredSequence Notes ----- According to the IUPAC RNA character set [1]_ , an RNA sequence may contain the following four definite characters (canonical nucleotides): +-----+-----------+ |Code |Nucleobase | +=====+===========+ |``A``|Adenine | +-----+-----------+ |``C``|Cytosine | +-----+-----------+ |``G``|Guanine | +-----+-----------+ |``U``|Uracil | +-----+-----------+ Plus 11 degenerate characters: ``R``, ``Y``, ``S``, ``W``, ``K``, ``M``, ``B``, ``D``, ``H``, ``V`` and ``N``, and two gap characters: ``-`` and ``.``. The definitions of degenerate characters are provided in ``DNA``, in which ``T`` should be replaced with ``U`` for RNA sequences. Characters other than the above 17 are not allowed. To include additional characters, you may create a custom alphabet using ``GrammaredSequence``. Directly modifying the alphabet of ``RNA`` may break methods that rely on the IUPAC alphabet. It should be noted that some functions do not support degenerate characters characters. In such cases, they will be replaced with `N` to represent any of the canonical nucleotides. References ---------- .. [1] Cornish-Bowden, A. (1985). Nomenclature for incompletely specified bases in nucleic acid sequences: recommendations 1984. Nucleic Acids Res, 13(9), 3021. Examples -------- >>> from skbio import RNA >>> RNA('ACCGAAU') RNA -------------------------- Stats: length: 7 has gaps: False has degenerates: False has definites: True GC-content: 42.86% -------------------------- 0 ACCGAAU Convert lowercase characters to uppercase: >>> RNA('AcCGaaU', lowercase=True) RNA -------------------------- Stats: length: 7 has gaps: False has degenerates: False has definites: True GC-content: 42.86% -------------------------- 0 ACCGAAU """ read = Read() write = Write() @classproperty @overrides(NucleotideMixin) def complement_map(cls): comp_map = { "A": "U", "U": "A", "G": "C", "C": "G", "Y": "R", "R": "Y", "S": "S", "W": "W", "K": "M", "M": "K", "B": "V", "D": "H", "H": "D", "V": "B", "N": "N", } comp_map.update({c: c for c in cls.gap_chars}) return comp_map @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set("ACGU") @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return { "R": set("AG"), "Y": set("CU"), "M": set("AC"), "K": set("UG"), "W": set("AU"), "S": set("GC"), "B": set("CGU"), "D": set("AGU"), "H": set("ACU"), "V": set("ACG"), "N": set("ACGU"), } @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return "-" @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set("-.") @classproperty @overrides(GrammaredSequence) def wildcard_char(cls): return "N" @property def _motifs(self): return _motifs def reverse_transcribe(self): """Reverse transcribe RNA into DNA. It returns the coding DNA strand of the RNA sequence, i.e. uracil (U) is replaced with thymine (T) in the reverse transcribed sequence. Returns ------- DNA Reverse transcribed sequence. See Also -------- DNA.transcribe translate translate_six_frames Notes ----- RNA sequence's metadata and positional metadata are included in the transcribed DNA sequence. Examples -------- Reverse transcribe RNA into DNA: >>> from skbio import RNA >>> rna = RNA('UAACGUUA') >>> rna RNA -------------------------- Stats: length: 8 has gaps: False has degenerates: False has definites: True GC-content: 25.00% -------------------------- 0 UAACGUUA >>> rna.reverse_transcribe() DNA -------------------------- Stats: length: 8 has gaps: False has degenerates: False has definites: True GC-content: 25.00% -------------------------- 0 TAACGTTA """ seq = self._string.replace(b"U", b"T") metadata = None if self.has_metadata(): metadata = self.metadata positional_metadata = None if self.has_positional_metadata(): positional_metadata = self.positional_metadata interval_metadata = None if self.has_interval_metadata(): interval_metadata = self.interval_metadata # turn off validation because `seq` is guaranteed to be valid return skbio.DNA( seq, metadata=metadata, positional_metadata=positional_metadata, interval_metadata=interval_metadata, validate=False, ) def translate(self, genetic_code=1, *args, **kwargs): """Translate RNA sequence into protein sequence. Parameters ---------- genetic_code : int, GeneticCode, optional Genetic code to use in translation. If ``int``, used as a table ID to look up the corresponding NCBI genetic code. args : tuple Positional arguments accepted by ``GeneticCode.translate``. kwargs : dict Keyword arguments accepted by ``GeneticCode.translate``. Returns ------- Protein Translated sequence. See Also -------- GeneticCode.translate GeneticCode.from_ncbi translate_six_frames Notes ----- RNA sequence's metadata are included in the translated protein sequence. Positional metadata are not included. Examples -------- Translate RNA into protein using NCBI's standard genetic code (table ID 1, the default genetic code in scikit-bio): >>> from skbio import RNA >>> rna = RNA('AUGCCACUUUAA') >>> rna.translate() Protein -------------------------- Stats: length: 4 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 MPL* Translate the same RNA sequence using a different NCBI genetic code (table ID 3, the yeast mitochondrial code) and specify that translation must terminate at the first stop codon: >>> rna.translate(3, stop='require') Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 MPT """ if not isinstance(genetic_code, skbio.GeneticCode): genetic_code = skbio.GeneticCode.from_ncbi(genetic_code) return genetic_code.translate(self, *args, **kwargs) def translate_six_frames(self, genetic_code=1, *args, **kwargs): """Translate RNA into protein using six possible reading frames. The six possible reading frames are: * 1 (forward) * 2 (forward) * 3 (forward) * -1 (reverse) * -2 (reverse) * -3 (reverse) Translated sequences are yielded in this order. Parameters ---------- genetic_code : int, GeneticCode, optional Genetic code to use in translation. If ``int``, used as a table ID to look up the corresponding NCBI genetic code. args : tuple Positional arguments accepted by ``GeneticCode.translate_six_frames``. kwargs : dict Keyword arguments accepted by ``GeneticCode.translate_six_frames``. Yields ------ Protein Translated sequence in the current reading frame. See Also -------- GeneticCode.translate_six_frames GeneticCode.from_ncbi translate Notes ----- This method is faster than (and equivalent to) performing six independent translations using, for example: ``(seq.translate(reading_frame=rf) for rf in GeneticCode.reading_frames)`` RNA sequence's metadata are included in each translated protein sequence. Positional metadata are not included. Examples -------- Translate RNA into protein using the six possible reading frames and NCBI's standard genetic code (table ID 1, the default genetic code in scikit-bio): >>> from skbio import RNA >>> rna = RNA('AUGCCACUUUAA') >>> for protein in rna.translate_six_frames(): ... protein ... print('') Protein -------------------------- Stats: length: 4 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 MPL* Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 CHF Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 ATL Protein -------------------------- Stats: length: 4 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 LKWH Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: True -------------------------- 0 *SG Protein -------------------------- Stats: length: 3 has gaps: False has degenerates: False has definites: True has stops: False -------------------------- 0 KVA """ if not isinstance(genetic_code, skbio.GeneticCode): genetic_code = skbio.GeneticCode.from_ncbi(genetic_code) return genetic_code.translate_six_frames(self, *args, **kwargs) @overrides(GrammaredSequence) def _repr_stats(self): """Define custom statistics to display in the sequence's repr.""" stats = super(RNA, self)._repr_stats() stats.append(("GC-content", "{:.2%}".format(self.gc_content()))) return stats _motifs = _parent_motifs.copy() # Leave this at the bottom _motifs.interpolate(RNA, "find_motifs") scikit-bio-scikit-bio-a3beaa6/skbio/sequence/_sequence.py000066400000000000000000002335721520735541300236270ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations import re import collections import numbers from contextlib import contextmanager from typing import TYPE_CHECKING import numpy as np import pandas as pd from skbio._base import SkbioObject from skbio.metadata._mixin import ( MetadataMixin, PositionalMetadataMixin, IntervalMetadataMixin, ) from skbio.metadata import IntervalMetadata from skbio.sequence._repr import _SequenceReprBuilder from skbio.sequence._alphabet import ( _alphabet_to_hashes, _indices_in_alphabet_ascii, _indices_in_observed, ) from skbio.util import find_duplicates from skbio.util._decorator import classonlymethod, overrides from skbio.io.descriptors import Read, Write if TYPE_CHECKING: from typing import Self, Iterable class Sequence( MetadataMixin, PositionalMetadataMixin, IntervalMetadataMixin, collections.abc.Sequence, SkbioObject, ): """Store generic sequence data and optional associated metadata. ``Sequence`` objects do not enforce an alphabet or grammar and are thus the most generic objects for storing sequence data. ``Sequence`` objects do not necessarily represent biological sequences. For example, ``Sequence`` can be used to represent a position in a multiple sequence alignment. Subclasses ``DNA``, ``RNA``, and ``Protein`` enforce the IUPAC character set [1]_ for, and provide operations specific to, each respective molecule type. ``Sequence`` objects consist of the underlying sequence data, as well as optional metadata and positional metadata. The underlying sequence is immutable, while the metdata and positional metadata are mutable. Parameters ---------- sequence : str, Sequence, or 1D np.ndarray (np.uint8 or '\\|S1') Characters representing the sequence itself. metadata : dict, optional Arbitrary metadata which applies to the entire sequence. A shallow copy of the ``dict`` will be made (see Examples section below for details). positional_metadata : pd.DataFrame consumable, optional Arbitrary per-character metadata (e.g., sequence read quality scores). Must be able to be passed directly to ``pd.DataFrame`` constructor. Each column of metadata must be the same length as `sequence`. A shallow copy of the positional metadata will be made if necessary (see Examples section below for details). interval_metadata : IntervalMetadata Arbitrary metadata which applies to intervals within a sequence to store interval features (such as genes, ncRNA on the sequence). lowercase : bool or str, optional If ``True``, lowercase sequence characters will be converted to uppercase characters. If ``False``, no characters will be converted. If a str, it will be treated as a key into the positional metadata of the object. All lowercase characters will be converted to uppercase, and a ``True`` value will be stored in a boolean array in the positional metadata under the key. See Also -------- DNA RNA Protein References ---------- .. [1] Cornish-Bowden, A. (1985). Nomenclature for incompletely specified bases in nucleic acid sequences: recommendations 1984. Nucleic Acids Res, 13(9), 3021. Examples -------- >>> from skbio import Sequence >>> from skbio.metadata import IntervalMetadata **Creating sequences:** Create a sequence without any metadata: >>> seq = Sequence('GGUCGUGAAGGA') >>> seq Sequence --------------- Stats: length: 12 --------------- 0 GGUCGUGAAG GA Create a sequence with metadata, positional metadata and interval metadata: >>> metadata = {'authors': ['Alice'], 'desc':'seq desc', 'id':'seq-id'} >>> positional_metadata = {'exons': [True, True, False, True], ... 'quality': [3, 3, 4, 10]} >>> interval_metadata = IntervalMetadata(4) >>> interval = interval_metadata.add([(1, 3)], metadata={'gene': 'sagA'}) >>> seq = Sequence('ACGT', metadata=metadata, ... positional_metadata=positional_metadata, ... interval_metadata=interval_metadata) >>> seq Sequence ----------------------------- Metadata: 'authors': 'desc': 'seq desc' 'id': 'seq-id' Positional metadata: 'exons': 'quality': Interval metadata: 1 interval feature Stats: length: 4 ----------------------------- 0 ACGT **Retrieving underlying sequence data:** Retrieve underlying sequence: >>> seq.values # doctest: +NORMALIZE_WHITESPACE array([b'A', b'C', b'G', b'T'], dtype='|S1') Underlying sequence immutable: >>> values = np.array([b'T', b'C', b'G', b'A'], dtype='|S1') >>> seq.values = values # doctest: +SKIP Traceback (most recent call last): ... AttributeError: can't set attribute >>> seq.values[0] = b'T' Traceback (most recent call last): ... ValueError: assignment destination is read-only **Retrieving sequence metadata:** Retrieve metadata: >>> seq.metadata {'authors': ['Alice'], 'desc': 'seq desc', 'id': 'seq-id'} Retrieve positional metadata: >>> seq.positional_metadata exons quality 0 True 3 1 True 3 2 False 4 3 True 10 Retrieve interval metadata: >>> seq.interval_metadata # doctest: +ELLIPSIS 1 interval feature ------------------ Interval(interval_metadata=<...>, bounds=[(1, 3)], \ fuzzy=[(False, False)], metadata={'gene': 'sagA'}) **Updating sequence metadata:** .. warning:: Be aware that a shallow copy of ``metadata`` and ``positional_metadata`` is made for performance. Since a deep copy is not made, changes made to mutable Python objects stored as metadata may affect the metadata of other ``Sequence`` objects or anything else that shares a reference to the object. The following examples illustrate this behavior. First, let's create a sequence and update its metadata: >>> metadata = {'id': 'seq-id', 'desc': 'seq desc', 'authors': ['Alice']} >>> seq = Sequence('ACGT', metadata=metadata) >>> seq.metadata['id'] = 'new-id' >>> seq.metadata['pubmed'] = 12345 >>> seq.metadata {'id': 'new-id', 'desc': 'seq desc', 'authors': ['Alice'], 'pubmed': 12345} Note that the original metadata dictionary (stored in variable ``metadata``) hasn't changed because a shallow copy was made: >>> metadata {'id': 'seq-id', 'desc': 'seq desc', 'authors': ['Alice']} >>> seq.metadata == metadata False Note however that since only a *shallow* copy was made, updates to mutable objects will also change the original metadata dictionary: >>> seq.metadata['authors'].append('Bob') >>> seq.metadata['authors'] ['Alice', 'Bob'] >>> metadata['authors'] ['Alice', 'Bob'] This behavior can also occur when manipulating a sequence that has been derived from another sequence: >>> subseq = seq[1:3] >>> subseq Sequence ----------------------------- Metadata: 'authors': 'desc': 'seq desc' 'id': 'new-id' 'pubmed': 12345 Stats: length: 2 ----------------------------- 0 CG >>> subseq.metadata {'id': 'new-id', 'desc': 'seq desc', 'authors': ['Alice', 'Bob'], \ 'pubmed': 12345} The subsequence has inherited the metadata of its parent sequence. If we update the subsequence's author list, we see the changes propagated in the parent sequence and original metadata dictionary: >>> subseq.metadata['authors'].append('Carol') >>> subseq.metadata['authors'] ['Alice', 'Bob', 'Carol'] >>> seq.metadata['authors'] ['Alice', 'Bob', 'Carol'] >>> metadata['authors'] ['Alice', 'Bob', 'Carol'] The behavior for updating positional metadata is similar. Let's create a new sequence with positional metadata that is already stored in a ``pd.DataFrame``: >>> positional_metadata = pd.DataFrame( ... {'list': [[], [], [], []], 'quality': [3, 3, 4, 10]}) >>> seq = Sequence('ACGT', positional_metadata=positional_metadata) >>> seq Sequence ----------------------------- Positional metadata: 'list': 'quality': Stats: length: 4 ----------------------------- 0 ACGT >>> seq.positional_metadata list quality 0 [] 3 1 [] 3 2 [] 4 3 [] 10 Now let's update the sequence's positional metadata by adding a new column and changing a value in another column: >>> seq.positional_metadata['gaps'] = [False, False, False, False] >>> seq.positional_metadata.loc[0, 'quality'] = 999 >>> seq.positional_metadata list quality gaps 0 [] 999 False 1 [] 3 False 2 [] 4 False 3 [] 10 False Note that the original positional metadata (stored in variable ``positional_metadata``) hasn't changed because a shallow copy was made: >>> positional_metadata list quality 0 [] 3 1 [] 3 2 [] 4 3 [] 10 >>> seq.positional_metadata.equals(positional_metadata) False Next let's create a sequence that has been derived from another sequence: >>> subseq = seq[1:3] >>> subseq Sequence ----------------------------- Positional metadata: 'list': 'quality': 'gaps': Stats: length: 2 ----------------------------- 0 CG >>> subseq.positional_metadata list quality gaps 0 [] 3 False 1 [] 4 False As described above for metadata, since only a *shallow* copy was made of the positional metadata, updates to mutable objects will also change the parent sequence's positional metadata and the original positional metadata ``pd.DataFrame``: >>> subseq.positional_metadata.loc[0, 'list'].append('item') >>> subseq.positional_metadata list quality gaps 0 [item] 3 False 1 [] 4 False >>> seq.positional_metadata list quality gaps 0 [] 999 False 1 [item] 3 False 2 [] 4 False 3 [] 10 False >>> positional_metadata list quality 0 [] 3 1 [item] 3 2 [] 4 3 [] 10 You can also update the interval metadata. Let's re-create a ``Sequence`` object with interval metadata at first: >>> seq = Sequence('ACGT') >>> interval = seq.interval_metadata.add( ... [(1, 3)], metadata={'gene': 'foo'}) You can update directly on the ``Interval`` object: >>> interval # doctest: +ELLIPSIS Interval(interval_metadata=<...>, bounds=[(1, 3)], \ fuzzy=[(False, False)], metadata={'gene': 'foo'}) >>> interval.bounds = [(0, 2)] >>> interval # doctest: +ELLIPSIS Interval(interval_metadata=<...>, bounds=[(0, 2)], \ fuzzy=[(False, False)], metadata={'gene': 'foo'}) You can also query and obtain the interval features you are interested and then modify them: >>> intervals = list(seq.interval_metadata.query(metadata={'gene': 'foo'})) >>> intervals[0].fuzzy = [(True, False)] >>> print(intervals[0]) # doctest: +ELLIPSIS Interval(interval_metadata=<...>, bounds=[(0, 2)], \ fuzzy=[(True, False)], metadata={'gene': 'foo'}) """ read = Read() write = Write() _num_ascii_codes = 128 _num_extended_ascii_codes = 256 # ASCII is built such that the difference between uppercase and lowercase # is the 6th bit. _ascii_invert_case_bit_offset = 32 _ascii_lowercase_boundary = 90 default_write_format = "fasta" """Default write format for this object: ``fasta``.""" __hash__ = None # type: ignore[assignment] @property def values(self): r"""Array containing underlying sequence characters. Notes ----- This property is not writeable. Examples -------- >>> from skbio import Sequence >>> s = Sequence('AACGA') >>> s.values # doctest: +NORMALIZE_WHITESPACE array([b'A', b'A', b'C', b'G', b'A'], dtype='|S1') """ return self._bytes.view("|S1") @property def __array_interface__(self): r"""Array interface for compatibility with numpy. This property allows a ``Sequence`` object to share its underlying data buffer (``Sequence.values``) with numpy. See [1]_ for more details. References ---------- .. [1] http://docs.scipy.org/doc/numpy/reference/arrays.interface.html Examples -------- >>> import numpy as np >>> from skbio import Sequence >>> seq = Sequence('ABC123') >>> np.asarray(seq) # doctest: +NORMALIZE_WHITESPACE array([b'A', b'B', b'C', b'1', b'2', b'3'], dtype='|S1') """ return self.values.__array_interface__ @property def observed_chars(self): r"""Set of observed characters in the sequence. Notes ----- This property is not writeable. Examples -------- >>> from skbio import Sequence >>> s = Sequence('AACGAC') >>> s.observed_chars == {'G', 'A', 'C'} True """ return set(str(self)) @property def _string(self): return self._bytes.tobytes() @classonlymethod def concat(cls, sequences: Iterable[Self], how: str = "strict") -> Self: r"""Concatenate an iterable of ``Sequence`` objects. Parameters ---------- sequences : iterable (Sequence) An iterable of ``Sequence`` objects or appropriate subclasses. how : {'strict', 'inner', 'outer'}, optional How to intersect the `positional_metadata` of the sequences. If 'strict': the `positional_metadata` must have the exact same columns; 'inner': an inner-join of the columns (only the shared set of columns are used); 'outer': an outer-join of the columns (all columns are used: missing values will be padded with NaN). Returns ------- Sequence The returned sequence will be an instance of the class which called this class-method. Raises ------ ValueError If `how` is not one of: 'strict', 'inner', or 'outer'. ValueError If `how` is 'strict' and the `positional_metadata` of each sequence does not have the same columns. TypeError If the sequences cannot be cast as the calling class. Notes ----- The sequence-wide metadata (``Sequence.metadata``) is not retained during concatenation. Sequence objects can be cast to a different type only when the new type is an ancestor or child of the original type. Casting between sibling types is not allowed, e.g. ``DNA`` -> ``RNA`` is not allowed, but ``DNA`` -> ``Sequence`` or ``Sequence`` -> ``DNA`` would be. Examples -------- Concatenate two DNA sequences into a new DNA object: >>> from skbio import DNA, Sequence >>> s1 = DNA("ACGT") >>> s2 = DNA("GGAA") >>> DNA.concat([s1, s2]) DNA -------------------------- Stats: length: 8 has gaps: False has degenerates: False has definites: True GC-content: 50.00% -------------------------- 0 ACGTGGAA Concatenate DNA sequences into a Sequence object (type coercion): >>> Sequence.concat([s1, s2]) Sequence ------------- Stats: length: 8 ------------- 0 ACGTGGAA Positional metadata is conserved: >>> s1 = DNA('AcgT', lowercase='one') >>> s2 = DNA('GGaA', lowercase='one', ... positional_metadata={'two': [1, 2, 3, 4]}) >>> result = DNA.concat([s1, s2], how='outer') >>> result DNA --------------------------- Positional metadata: 'one': 'two': Stats: length: 8 has gaps: False has degenerates: False has definites: True GC-content: 50.00% --------------------------- 0 ACGTGGAA >>> result.positional_metadata one two 0 False NaN 1 True NaN 2 True NaN 3 False NaN 4 False 1.0 5 False 2.0 6 True 3.0 7 False 4.0 """ if how not in {"strict", "inner", "outer"}: raise ValueError("`how` must be 'strict', 'inner', or 'outer'.") seqs = list(sequences) if len(seqs) == 0: return cls("") for seq in seqs: seq._assert_can_cast_to(cls) if how == "strict": how = "inner" cols = set() for s in seqs: if s.has_positional_metadata(): cols.add(frozenset(s.positional_metadata)) else: cols.add(frozenset()) if len(cols) > 1: raise ValueError( "The positional metadata of the sequences do" " not have matching columns. Consider setting" " how='inner' or how='outer'" ) seq_data = [] pm_data = [] for seq in seqs: seq_data.append(seq._bytes) pm_data.append(seq.positional_metadata) if not seq.has_positional_metadata(): del seq.positional_metadata pm = pd.concat(pm_data, join=how, ignore_index=True, sort=True) bytes_ = np.concatenate(seq_data) im = IntervalMetadata.concat(i.interval_metadata for i in seqs) return cls(bytes_, positional_metadata=pm, interval_metadata=im) @classmethod def _assert_can_cast_to(cls, target): if not (issubclass(cls, target) or issubclass(target, cls)): raise TypeError("Cannot cast %r as %r." % (cls.__name__, target.__name__)) @overrides(PositionalMetadataMixin) def _positional_metadata_axis_len_(self): return len(self) @overrides(IntervalMetadataMixin) def _interval_metadata_axis_len_(self): return len(self) def __init__( self, sequence, metadata=None, positional_metadata=None, interval_metadata=None, lowercase=False, ): if isinstance(sequence, np.ndarray): if sequence.dtype == np.uint8: self._set_bytes_contiguous(sequence) elif sequence.dtype == "|S1": sequence = sequence.view(np.uint8) # Guarantee the sequence is an array (might be scalar before # this). if sequence.shape == (): sequence = np.array([sequence], dtype=np.uint8) self._set_bytes_contiguous(sequence) else: raise TypeError( "Can only create sequence from numpy.ndarray of dtype " "np.uint8 or '|S1'. Invalid dtype: %s" % sequence.dtype ) elif isinstance(sequence, Sequence): # Sequence casting is acceptable between direct # descendants/ancestors sequence._assert_can_cast_to(type(self)) if metadata is None and sequence.has_metadata(): metadata = sequence.metadata if positional_metadata is None and sequence.has_positional_metadata(): positional_metadata = sequence.positional_metadata if interval_metadata is None and sequence.has_interval_metadata(): interval_metadata = sequence.interval_metadata sequence = sequence._bytes self._owns_bytes = False self._set_bytes(sequence) else: # Encode as ascii to raise UnicodeEncodeError if necessary. if isinstance(sequence, str): sequence = sequence.encode("ascii") s = np.frombuffer(sequence, dtype=np.uint8) # There are two possibilities (to our knowledge) at this point: # Either the sequence we were given was something string-like, # (else it would not have made it past frombuffer), or it was a # numpy scalar, and so our length must be 1. if isinstance(sequence, np.generic) and len(s) != 1: raise TypeError( "Can cannot create a sequence with %r" % type(sequence).__name__ ) sequence = s self._owns_bytes = False self._set_bytes(sequence) MetadataMixin._init_(self, metadata=metadata) PositionalMetadataMixin._init_(self, positional_metadata=positional_metadata) IntervalMetadataMixin._init_(self, interval_metadata=interval_metadata) if lowercase is False: pass elif lowercase is True or isinstance(lowercase, str): lowercase_mask = self._bytes > self._ascii_lowercase_boundary self._convert_to_uppercase(lowercase_mask) # If it isn't True, it must be a string_type if lowercase is not True: self.positional_metadata[lowercase] = lowercase_mask else: raise TypeError( "lowercase keyword argument expected a bool or " "string, but got %s" % type(lowercase) ) def _set_bytes_contiguous(self, sequence): r"""Munge the sequence data into a numpy array of dtype uint8.""" if not sequence.flags["C_CONTIGUOUS"]: # numpy doesn't support views of non-contiguous arrays. Since we're # making heavy use of views internally, and users may also supply # us with a view, make sure we *always* store a contiguous array to # avoid hard-to-track bugs. See # https://github.com/numpy/numpy/issues/5716 sequence = np.ascontiguousarray(sequence) self._owns_bytes = True else: self._owns_bytes = False self._set_bytes(sequence) def _set_bytes(self, sequence): sequence.flags.writeable = False self._bytes = sequence def _convert_to_uppercase(self, lowercase): if np.any(lowercase): with self._byte_ownership(): self._bytes[lowercase] ^= self._ascii_invert_case_bit_offset def __contains__(self, subsequence): r"""Determine if a subsequence is contained in this sequence. Parameters ---------- subsequence : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') The putative subsequence. Returns ------- bool Indicates whether `subsequence` is contained in this sequence. Raises ------ TypeError If `subsequence` is a ``Sequence`` object with a different type than this sequence. Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUCGUGAAGGA') >>> 'GGU' in s True >>> 'CCC' in s False """ return self._munge_to_bytestring(subsequence, "in") in self._string def __eq__(self, other): r"""Determine if this sequence is equal to another. Sequences are equal if they are *exactly* the same type and their sequence characters, metadata, and positional metadata are the same. Parameters ---------- other : Sequence Sequence to test for equality against. Returns ------- bool Indicates whether this sequence is equal to `other`. Examples -------- Define two ``Sequence`` objects that have the same underlying sequence of characters: >>> from skbio import Sequence >>> s = Sequence('ACGT') >>> t = Sequence('ACGT') The two sequences are considered equal because they are the same type, their underlying sequence of characters are the same, and their optional metadata attributes (``metadata`` and ``positional_metadata``) were not provided: >>> s == t True >>> t == s True Define another sequence object with a different sequence of characters than the previous two sequence objects: >>> u = Sequence('ACGA') >>> u == t False Define a sequence with the same sequence of characters as ``u`` but with different metadata, positional metadata, and interval metadata: >>> v = Sequence('ACGA', metadata={'id': 'abc'}, ... positional_metadata={'quality':[1, 5, 3, 3]}) >>> _ = v.interval_metadata.add([(0, 1)]) The two sequences are not considered equal because their metadata, positional metadata, and interval metadata do not match: >>> u == v False """ # checks ordered from least to most expensive if self.__class__ != other.__class__: return False if not MetadataMixin._eq_(self, other): return False if self._string != other._string: return False if not PositionalMetadataMixin._eq_(self, other): return False if not IntervalMetadataMixin._eq_(self, other): return False return True def __ne__(self, other): r"""Determine if this sequence is not equal to another. Sequences are not equal if they are not *exactly* the same type, or their sequence characters, metadata, or positional metadata differ. Parameters ---------- other : Sequence Sequence to test for inequality against. Returns ------- bool Indicates whether this sequence is not equal to `other`. Examples -------- >>> from skbio import Sequence >>> s = Sequence('ACGT') >>> t = Sequence('ACGT') >>> s != t False >>> u = Sequence('ACGA') >>> u != t True >>> v = Sequence('ACGA', metadata={'id': 'v'}) >>> u != v True """ return not (self == other) def __getitem__(self, indexable): r"""Slice this sequence. Notes ----- This drops the ``self.interval_metadata`` from the returned new ``Sequence`` object. Parameters ---------- indexable : int, slice, iterable (int and slice), 1D array_like (bool) The position(s) to return from this sequence. If `indexable` is an iterable of integers, these are assumed to be indices in the sequence to keep. If `indexable` is a 1D ``array_like`` of booleans, these are assumed to be the positions in the sequence to keep. Returns ------- Sequence New sequence containing the position(s) specified by `indexable` in this sequence. Positional metadata will be sliced in the same manner and included in the returned sequence. `metadata` is included in the returned sequence. Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUCGUGAAGGA') Obtain a single character from the sequence: >>> s[1] Sequence ------------- Stats: length: 1 ------------- 0 G Obtain a slice: >>> s[7:] Sequence ------------- Stats: length: 5 ------------- 0 AAGGA Obtain characters at the following indices: >>> s[[3, 4, 7, 0, 3]] Sequence ------------- Stats: length: 5 ------------- 0 CGAGC Obtain characters at positions evaluating to `True`: >>> s = Sequence('GGUCG') >>> index = [True, False, True, 'a' == 'a', False] >>> s[index] Sequence ------------- Stats: length: 3 ------------- 0 GUC """ if not isinstance(indexable, np.ndarray) and ( (not isinstance(indexable, str)) and hasattr(indexable, "__iter__") ): indexable_ = indexable indexable = np.asarray(indexable) if indexable.dtype == object: indexable = list(indexable_) # TODO: Don't blow out memory if len(indexable) == 0: # indexing with an empty list, so convert to ndarray and # fall through to ndarray slicing below indexable = np.asarray(indexable) else: seq = np.concatenate( list(_slices_from_iter(self._bytes, indexable)) ) index = _as_slice_if_single_index(indexable) positional_metadata = None if self.has_positional_metadata(): pos_md_slices = list( _slices_from_iter(self.positional_metadata, index) ) positional_metadata = pd.concat(pos_md_slices, sort=True) metadata = None if self.has_metadata(): metadata = self.metadata return self._constructor( sequence=seq, metadata=metadata, positional_metadata=positional_metadata, ) elif isinstance(indexable, str) or isinstance(indexable, bool): raise IndexError( "Cannot index with %s type: %r" % (type(indexable).__name__, indexable) ) if ( isinstance(indexable, np.ndarray) and indexable.dtype == bool and len(indexable) != len(self) ): raise IndexError( "An boolean vector index must be the same length" " as the sequence (%d, not %d)." % (len(self), len(indexable)) ) if isinstance(indexable, np.ndarray) and indexable.size == 0: # convert an empty ndarray to a supported dtype for slicing a numpy # array indexable = indexable.astype(int) seq = self._bytes[indexable] positional_metadata = self._slice_positional_metadata(indexable) metadata = None if self.has_metadata(): metadata = self.metadata return self._constructor( sequence=seq, metadata=metadata, positional_metadata=positional_metadata, ) def _slice_positional_metadata(self, indexable): if self.has_positional_metadata(): if _is_single_index(indexable): index = _single_index_to_slice(indexable) else: index = indexable return self.positional_metadata.iloc[index] else: return None def __len__(self): r"""Return the number of characters in this sequence. Returns ------- int The length of this sequence. Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUC') >>> len(s) 4 """ return self._bytes.size def __bool__(self): r"""Return truth value (truthiness) of sequence. Returns ------- bool True if length of sequence is greater than 0, else False. Examples -------- >>> from skbio import Sequence >>> bool(Sequence('')) False >>> bool(Sequence('ACGT')) True """ return len(self) > 0 def __iter__(self): r"""Iterate over positions in this sequence. Yields ------ Sequence Single character subsequence, one for each position in the sequence. Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUC') >>> for c in s: ... str(c) 'G' 'G' 'U' 'C' """ for i in range(len(self)): yield self[i] def __reversed__(self): r"""Iterate over positions in this sequence in reverse order. Yields ------ Sequence Single character subsequence, one for each position in the sequence. Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUC') >>> for c in reversed(s): ... str(c) 'C' 'U' 'G' 'G' """ return iter(self[::-1]) def __str__(self): r"""Return sequence characters as a string. Returns ------- str Sequence characters as a string. No metadata or positional metadata will be included. See Also -------- sequence Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUCGUAAAGGA', metadata={'id':'hello'}) >>> str(s) 'GGUCGUAAAGGA' """ return str(self._string.decode("ascii")) def __repr__(self): r"""Return a string representation of this sequence object. Representation includes: * sequence type * metadata keys and values: will display key/value if it is an understood type, otherwise just the type will be displayed. If it is an understood type whose representation is too long, just the type will be displayed * positional metadata: column names and column dtypes will be displayed in the order they appear in the positional metadata ``pd.DataFrame``. Column names (i.e., keys) follow the same display rules as metadata keys * interval metadata: the number of interval features will be displayed. * sequence stats (e.g., length) * up to five lines of chunked sequence data. Each line of chunked sequence data displays the current position in the sequence Returns ------- str String representation of this sequence object. Notes ----- Subclasses can override Sequence._repr_stats to provide custom statistics. Examples -------- Short sequence without metadata: >>> from skbio import Sequence >>> from skbio.metadata._interval import IntervalMetadata >>> Sequence('ACGTAATGGATACGTAATGCA') Sequence ------------------------- Stats: length: 21 ------------------------- 0 ACGTAATGGA TACGTAATGC A Longer sequence displays first two lines and last two lines: >>> Sequence('ACGT' * 100) Sequence --------------------------------------------------------------------- Stats: length: 400 --------------------------------------------------------------------- 0 ACGTACGTAC GTACGTACGT ACGTACGTAC GTACGTACGT ACGTACGTAC GTACGTACGT 60 ACGTACGTAC GTACGTACGT ACGTACGTAC GTACGTACGT ACGTACGTAC GTACGTACGT ... 300 ACGTACGTAC GTACGTACGT ACGTACGTAC GTACGTACGT ACGTACGTAC GTACGTACGT 360 ACGTACGTAC GTACGTACGT ACGTACGTAC GTACGTACGT Sequence with metadata, positional metadata, and interval metadata: >>> metadata = { ... 'id': 'seq-id', ... 'description': 'description of the sequence, wrapping across ' ... 'lines if it\'s too long', ... 'authors': ['Alice', 'Bob', 'Carol'], ... 'year': 2015, ... 'published': True ... } >>> positional_metadata = { ... 'exons': [True, True, False, True], ... 'quality': [3, 10, 11, 10] ... } >>> seq = Sequence('ACGT', metadata=metadata, ... positional_metadata=positional_metadata) >>> _ = seq.interval_metadata.add([(0, 2)], metadata={'gene': 'sagA'}) >>> seq Sequence ---------------------------------------------------------------------- Metadata: 'authors': 'description': "description of the sequence, wrapping across lines if it's too long" 'id': 'seq-id' 'published': True 'year': 2015 Positional metadata: 'exons': 'quality': Interval metadata: 1 interval feature Stats: length: 4 ---------------------------------------------------------------------- 0 ACGT """ return _SequenceReprBuilder( seq=self, width=71, # 79 for pep8, 8 space indent for docstrings indent=4, chunk_size=10, ).build() def _repr_stats(self): r"""Define statistics to display in the sequence's repr. Subclasses can override this method to provide type-specific statistics. This method computes a single statistic: length. Returns ------- list List of tuples where each tuple represents a statistic. Each tuple contains exactly two ``str`` elements: the statistic's name/label, and the str-formatted value of the statistic. Ordering of statistics (i.e., list order) determines display order in the sequence repr. """ return [("length", "%d" % len(self))] def __copy__(self): r"""Return a shallow copy of this sequence. See Also -------- copy Notes ----- This method is equivalent to ``seq.copy(deep=False)``. """ return self._copy(False, {}) def __deepcopy__(self, memo): r"""Return a deep copy of this sequence. See Also -------- copy Notes ----- This method is equivalent to ``seq.copy(deep=True)``. """ return self._copy(True, memo) def _copy(self, deep, memo): # strategy: copy the sequence without metadata first, then set metadata # attributes with copies. we take this approach instead of simply # passing the metadata through the Sequence constructor because we # don't want to copy twice (this could happen when deep=True, where we # deep copy here and then shallow copy in the Sequence constructor). we # also directly set the private metadata attributes instead of using # their public setters to avoid an unnecessary copy # we don't make a distinction between deep vs. shallow copy of bytes # because dtype=np.uint8. we only need to make the distinction when # dealing with object dtype bytes_ = np.copy(self._bytes) seq_copy = self._constructor( sequence=bytes_, metadata=None, positional_metadata=None, interval_metadata=None, ) if deep: seq_copy._metadata = MetadataMixin._deepcopy_(self, memo) seq_copy._positional_metadata = PositionalMetadataMixin._deepcopy_( self, memo ) seq_copy._interval_metadata = IntervalMetadataMixin._deepcopy_(self, memo) else: seq_copy._metadata = MetadataMixin._copy_(self) seq_copy._positional_metadata = PositionalMetadataMixin._copy_(self) seq_copy._interval_metadata = IntervalMetadataMixin._copy_(self) return seq_copy def lowercase(self, lowercase): r"""Return a case-sensitive string representation of the sequence. Parameters ---------- lowercase: str or boolean vector If lowercase is a boolean vector, it is used to set sequence characters to lowercase in the output string. True values in the boolean vector correspond to lowercase characters. If lowercase is a str, it is treated like a key into the positional metadata, pointing to a column which must be a boolean vector. That boolean vector is then used as described previously. Returns ------- str String representation of sequence with specified characters set to lowercase. Examples -------- >>> from skbio import Sequence >>> s = Sequence('ACGT') >>> s.lowercase([True, True, False, False]) 'acGT' >>> s = Sequence('ACGT', ... positional_metadata={ ... 'exons': [True, False, False, True]}) >>> s.lowercase('exons') 'aCGt' Constructor automatically populates a column in positional metadata when the ``lowercase`` keyword argument is provided with a column name: >>> s = Sequence('ACgt', lowercase='introns') >>> s.lowercase('introns') 'ACgt' >>> s = Sequence('ACGT', lowercase='introns') >>> s.lowercase('introns') 'ACGT' """ index = self._munge_to_index_array(lowercase) outbytes = self._bytes.copy() outbytes[index] ^= self._ascii_invert_case_bit_offset return str(outbytes.tobytes().decode("ascii")) def count(self, subsequence, start=None, end=None): r"""Count occurrences of a subsequence in this sequence. Parameters ---------- subsequence : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Subsequence to count occurrences of. start : int, optional The position at which to start counting (inclusive). end : int, optional The position at which to stop counting (exclusive). Returns ------- int Number of occurrences of `subsequence` in this sequence. Raises ------ ValueError If `subsequence` is of length 0. TypeError If `subsequence` is a ``Sequence`` object with a different type than this sequence. Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUCG') >>> s.count('G') 3 >>> s.count('GG') 1 >>> s.count('T') 0 >>> s.count('G', 2, 5) 1 """ if len(subsequence) == 0: raise ValueError("`count` is not defined for empty subsequences.") return self._string.count( self._munge_to_bytestring(subsequence, "count"), start, end ) def replace(self, where, character): r"""Replace values in this sequence with a different character. Parameters ---------- where : 1D array_like (bool) or iterable (slices or ints) or str Indicates positions in the sequence to replace with `character`. Can be a boolean vector, an iterable of indices/slices, or a string that is a key in `positional_metadata` pointing to a boolean vector. character : str or bytes Character that will replace chosen items in this sequence. Returns ------- Sequence Copy of this sequence, with chosen items replaced with chosen character. All metadata is retained. Examples -------- Let's create and display a Sequence: >>> from skbio import Sequence >>> sequence = Sequence('GGTACCAACG') >>> str(sequence) 'GGTACCAACG' Let's call ``replace`` on the Sequence using a boolean vector for ``where`` and assign it to a new variable: >>> seq = sequence.replace([False, False, False, True, False, False, ... True, True, False, False], '-') Let's take a look at the new Sequence: >>> str(seq) 'GGT-CC--CG' Other types of input are accepted by the ``where`` parameter. Let's pass in a list of indices and slices that is equivalent to the boolean vector we used previously: >>> str(seq) == str(sequence.replace([3, slice(6, 8)], '-')) True ``where`` also accepts a boolean vector contained in ``Sequence.positional_metadata``: >>> sequence.positional_metadata = {'where': ... [False, False, False, True, False, ... False, True, True, False, False]} Let's pass in the key ``'where'`` and compare to ``seq``: >>> str(seq) == str(sequence.replace('where', '-')) True """ if isinstance(character, bytes) is not True: character = character.encode("ascii") character = ord(character) index = self._munge_to_index_array(where) seq_bytes = self._bytes.copy() seq_bytes[index] = character metadata = None if self.has_metadata(): metadata = self.metadata positional_metadata = None if self.has_positional_metadata(): positional_metadata = self.positional_metadata interval_metadata = None if self.has_interval_metadata(): interval_metadata = self.interval_metadata # Use __class__ instead of _constructor so that validations are # performed for subclasses (the user could have introduced invalid # characters). return self.__class__( seq_bytes, metadata=metadata, positional_metadata=positional_metadata, interval_metadata=interval_metadata, ) def index(self, subsequence, start=None, end=None): r"""Find position where subsequence first occurs in the sequence. Parameters ---------- subsequence : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Subsequence to search for in this sequence. start : int, optional The position at which to start searching (inclusive). end : int, optional The position at which to stop searching (exclusive). Returns ------- int Position where `subsequence` first occurs in this sequence. Raises ------ ValueError If `subsequence` is not present in this sequence. TypeError If `subsequence` is a ``Sequence`` object with a different type than this sequence. Examples -------- >>> from skbio import Sequence >>> s = Sequence('ACACGACGTT-') >>> s.index('ACG') 2 """ try: return self._string.index( self._munge_to_bytestring(subsequence, "index"), start, end ) except ValueError: raise ValueError("%r is not present in %r." % (subsequence, self)) def distance(self, other, metric=None): r"""Compute the distance to another sequence. Parameters ---------- other : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Sequence to compute the distance to. If ``other`` is a ``Sequence`` object, it must be the same type as this sequence. Other input types will be converted into a ``Sequence`` object of the same type as this sequence. metric : callable, optional Function used to compute the distance between this sequence and ``other``. By default, Hamming distance will be used (see :func:`~skbio.sequence.distance.hamming`). ``metric`` should be a function that takes two ``Sequence`` objects and returns a ``float``. The sequence objects passed to ``metric`` will be the same type as this sequence. See :mod:`skbio.sequence.distance` for other predefined metrics that can be supplied via ``metric``. Returns ------- float Distance between this and other sequences as defined by ``metric``. Raises ------ TypeError If ``other`` is a ``Sequence`` object with a different type than this sequence. See Also -------- skbio.sequence.distance Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUC') >>> t = Sequence('AGUC') Compute Hamming distance (the default metric): >>> s.distance(t) 0.25 Use a custom metric: >>> def custom_metric(s1, s2): return 0.42 >>> s.distance(t, custom_metric) 0.42 """ # TODO refactor this method to accept a name (string) of the distance # metric to apply and accept **kwargs other = self._munge_to_self_type(other, "distance") if metric is None: import skbio.sequence.distance metric = getattr(skbio.sequence.distance, "hamming", None) return float(metric(self, other)) def matches(self, other): r"""Find positions that match with another sequence. Parameters ---------- other : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Sequence to compare to. Returns ------- 1D np.ndarray (bool) Boolean vector where ``True`` at position ``i`` indicates a match between the sequences at their positions ``i``. Raises ------ ValueError If the sequences are not the same length. TypeError If `other` is a ``Sequence`` object with a different type than this sequence. See Also -------- mismatches Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUC') >>> t = Sequence('GAUU') >>> s.matches(t) array([ True, False, True, False], dtype=bool) """ other = self._munge_to_sequence(other, "matches/mismatches") if len(self) != len(other): raise ValueError( "Match and mismatch vectors can only be " "generated from equal length sequences." ) return self._bytes == other._bytes def mismatches(self, other): r"""Find positions that do not match with another sequence. Parameters ---------- other : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Sequence to compare to. Returns ------- 1D np.ndarray (bool) Boolean vector where ``True`` at position ``i`` indicates a mismatch between the sequences at their positions ``i``. Raises ------ ValueError If the sequences are not the same length. TypeError If `other` is a ``Sequence`` object with a different type than this sequence. See Also -------- matches Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUC') >>> t = Sequence('GAUU') >>> s.mismatches(t) array([False, True, False, True], dtype=bool) """ return np.invert(self.matches(other)) def match_frequency(self, other, relative=False): r"""Return count of positions that are the same between two sequences. Parameters ---------- other : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Sequence to compare to. relative : bool, optional If ``True``, return the relative frequency of matches instead of the count. Returns ------- int or float Number of positions that are the same between the sequences. This will be an ``int`` if `relative` is ``False`` and a ``float`` if `relative` is ``True``. Raises ------ ValueError If the sequences are not the same length. TypeError If `other` is a ``Sequence`` object with a different type than this sequence. See Also -------- mismatch_frequency matches mismatches distance Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUC') >>> t = Sequence('AGUC') >>> s.match_frequency(t) 3 >>> s.match_frequency(t, relative=True) 0.75 """ if relative: return float(self.matches(other).mean()) else: return int(self.matches(other).sum()) def mismatch_frequency(self, other, relative=False): r"""Return count of positions that differ between two sequences. Parameters ---------- other : str, Sequence, or 1D np.ndarray (np.uint8 or '\|S1') Sequence to compare to. relative : bool, optional If ``True``, return the relative frequency of mismatches instead of the count. Returns ------- int or float Number of positions that differ between the sequences. This will be an ``int`` if `relative` is ``False`` and a ``float`` if `relative` is ``True``. Raises ------ ValueError If the sequences are not the same length. TypeError If `other` is a ``Sequence`` object with a different type than this sequence. See Also -------- match_frequency matches mismatches distance Examples -------- >>> from skbio import Sequence >>> s = Sequence('GGUC') >>> t = Sequence('AGUC') >>> s.mismatch_frequency(t) 1 >>> s.mismatch_frequency(t, relative=True) 0.25 """ if relative: return float(self.mismatches(other).mean()) else: return int(self.mismatches(other).sum()) def frequencies(self, chars=None, relative=False): r"""Compute frequencies of characters in the sequence. Parameters ---------- chars : str or set of str, optional Characters to compute the frequencies of. May be a ``str`` containing a single character or a ``set`` of single-character strings. If ``None``, frequencies will be computed for all characters present in the sequence. relative : bool, optional If ``True``, return the relative frequency of each character instead of its count. If `chars` is provided, relative frequencies will be computed with respect to the number of characters in the sequence, **not** the total count of characters observed in `chars`. Thus, the relative frequencies will not necessarily sum to 1.0 if `chars` is provided. Returns ------- dict Frequencies of characters in the sequence. Raises ------ TypeError If `chars` is not a ``str`` or ``set`` of ``str``. ValueError If `chars` is not a single-character ``str`` or a ``set`` of single-character strings. ValueError If `chars` contains characters outside the allowable range of characters in a ``Sequence`` object. See Also -------- kmer_frequencies iter_kmers Notes ----- If the sequence is empty (i.e., length zero), ``relative=True``, **and** `chars` is provided, the relative frequency of each specified character will be ``np.nan``. If `chars` is not provided, this method is equivalent to, but faster than, ``seq.kmer_frequencies(k=1)``. If `chars` is not provided, it is equivalent to, but faster than, passing ``chars=seq.observed_chars``. Examples -------- Compute character frequencies of a sequence: >>> from skbio import Sequence >>> seq = Sequence('AGAAGACC') >>> freqs = seq.frequencies() >>> dict(sorted(freqs.items())) # display dict in sorted order {'A': 4, 'C': 2, 'G': 2} Compute relative character frequencies: >>> freqs = seq.frequencies(relative=True) >>> dict(sorted(freqs.items())) {'A': 0.5, 'C': 0.25, 'G': 0.25} Compute relative frequencies of characters A, C, and T: >>> freqs = seq.frequencies(chars={'A', 'C', 'T'}, relative=True) >>> dict(sorted(freqs.items())) {'A': 0.5, 'C': 0.25, 'T': 0.0} Note that since character T is not in the sequence we receive a relative frequency of 0.0. The relative frequencies of A and C are relative to the number of characters in the sequence (8), **not** the number of A and C characters (4 + 2 = 6). """ freqs = np.bincount(self._bytes, minlength=self._num_extended_ascii_codes) if chars is not None: chars, indices = self._chars_to_indices(chars) else: (indices,) = np.nonzero(freqs) # Downcast from int64 to uint8 then convert to str. This is safe # because we are guaranteed to have indices in the range 0 to 255 # inclusive. chars = indices.astype(np.uint8).tobytes().decode("ascii") obs_counts = freqs[indices] if relative: obs_counts = obs_counts / len(self) # Use tolist() for minor performance gain. return dict(zip(chars, obs_counts.tolist())) def _chars_to_indices(self, chars): """Convert characters to indices for Sequence.frequencies.""" if isinstance(chars, (str, bytes)): chars = set([chars]) elif not isinstance(chars, set): raise TypeError( "`chars` must be of type `set`, not %r" % type(chars).__name__ ) # Impose an (arbitrary) ordering to `chars` so that we can return # `indices` in that same order. chars = list(chars) indices = [] for char in chars: if not isinstance(char, (str, bytes)): raise TypeError( "Each element of `chars` must be string-like, not %r" % type(char).__name__ ) if len(char) != 1: raise ValueError( "Each element of `chars` must contain a single " "character (found %d characters)" % len(char) ) index = ord(char) if index >= self._num_extended_ascii_codes: raise ValueError( "Character %r in `chars` is outside the range of " "allowable characters in a `Sequence` object." % char ) indices.append(index) return chars, indices def iter_kmers(self, k, overlap=True): r"""Generate k-mers of length `k` from this sequence. Parameters ---------- k : int The kmer length. overlap : bool, optional Defines whether the k-mers should be overlapping or not. Yields ------ Sequence kmer of length `k` contained in this sequence. Raises ------ ValueError If `k` is less than 1. Examples -------- >>> from skbio import Sequence >>> s = Sequence('ACACGACGTT') >>> for kmer in s.iter_kmers(4, overlap=False): ... str(kmer) 'ACAC' 'GACG' >>> for kmer in s.iter_kmers(3, overlap=True): ... str(kmer) 'ACA' 'CAC' 'ACG' 'CGA' 'GAC' 'ACG' 'CGT' 'GTT' """ if k < 1: raise ValueError("k must be greater than 0.") if k > len(self): return if overlap: step = 1 count = len(self) - k + 1 else: step = k count = len(self) // k if len(self) == 0 or self.has_positional_metadata(): # Slower path when sequence is empty or positional metadata needs # to be sliced. for i in range(0, len(self) - k + 1, step): yield self[i : i + k] else: # Optimized path when positional metadata doesn't need slicing. kmers = np.lib.stride_tricks.as_strided( self._bytes, shape=(k, count), strides=(1, step) ).T metadata = None if self.has_metadata(): metadata = self.metadata for s in kmers: yield self._constructor( sequence=s, metadata=metadata, positional_metadata=None ) def kmer_frequencies(self, k, overlap=True, relative=False): r"""Return counts of words of length `k` from this sequence. Parameters ---------- k : int The word length. overlap : bool, optional Defines whether the kmers should be overlapping or not. relative : bool, optional If ``True``, return the relative frequency of each kmer instead of its count. Returns ------- dict Frequencies of words of length `k` contained in this sequence. Raises ------ ValueError If `k` is less than 1. Examples -------- >>> from skbio import Sequence >>> s = Sequence('ACACATTTATTA') >>> freqs = s.kmer_frequencies(3, overlap=False) >>> freqs {'ACA': 1, 'CAT': 1, 'TTA': 2} >>> freqs = s.kmer_frequencies(3, relative=True, overlap=False) >>> freqs {'ACA': 0.25, 'CAT': 0.25, 'TTA': 0.5} """ kmers = self.iter_kmers(k, overlap=overlap) freqs = dict(collections.Counter((str(seq) for seq in kmers))) if relative: if overlap: num_kmers = len(self) - k + 1 else: num_kmers = len(self) // k relative_freqs = {} for kmer, count in freqs.items(): relative_freqs[kmer] = count / num_kmers freqs = relative_freqs return freqs def find_with_regex(self, regex, ignore=None): r"""Generate slices for patterns matched by a regular expression. Parameters ---------- regex : str or regular expression object String to be compiled into a regular expression, or a pre- compiled regular expression object (e.g., from calling ``re.compile``). ignore : 1D array_like (bool) or iterable (slices or ints), optional Indicate the positions to ignore when matching. Yields ------ slice Location where the regular expression matched. Examples -------- >>> from skbio import Sequence >>> s = Sequence('AATATACCGGTTATAA') >>> for match in s.find_with_regex('(TATA+)'): ... match ... str(s[match]) slice(2, 6, None) 'TATA' slice(11, 16, None) 'TATAA' """ if isinstance(regex, str): regex = re.compile(regex) lookup = np.arange(len(self)) if ignore is None: string = str(self) else: ignore = self._munge_to_index_array(ignore) lookup = np.delete(lookup, ignore) string = str(self[lookup]) for match in regex.finditer(string): # We start at 1 because we don't want the group that contains all # other groups. for g in range(1, len(match.groups()) + 1): yield slice(lookup[match.start(g)], lookup[match.end(g) - 1] + 1) def iter_contiguous(self, included, min_length=1, invert=False): r"""Yield contiguous subsequences based on `included`. Parameters ---------- included : 1D array_like (bool) or iterable (slices or ints) `included` is transformed into a flat boolean vector where each position will either be included or skipped. All contiguous included positions will be yielded as a single region. min_length : int, optional The minimum length of a subsequence for it to be yielded. Default is 1. invert : bool, optional Whether to invert `included` such that it describes what should be skipped instead of included. Default is False. Yields ------ Sequence Contiguous subsequence as indicated by `included`. Notes ----- If slices provide adjacent ranges, then they will be considered the same contiguous subsequence. Examples -------- Here we use `iter_contiguous` to find all of the contiguous ungapped sequences using a boolean vector derived from our DNA sequence. >>> from skbio import DNA >>> s = DNA('AAA--TT-CCCC-G-') >>> no_gaps = ~s.gaps() >>> for ungapped_subsequence in s.iter_contiguous(no_gaps, ... min_length=2): ... print(ungapped_subsequence) AAA TT CCCC Note how the last potential subsequence was skipped because it would have been smaller than our `min_length` which was set to 2. We can also use `iter_contiguous` on a generator of slices as is produced by `find_motifs` (and `find_with_regex`). >>> from skbio import Protein >>> s = Protein('ACDFNASANFTACGNPNRTESL') >>> for subseq in s.iter_contiguous(s.find_motifs('N-glycosylation')): ... print(subseq) NASANFTA NRTE Note how the first subsequence contains two N-glycosylation sites. This happened because they were contiguous. """ idx = self._munge_to_index_array(included) if invert: idx = np.delete(np.arange(len(self)), idx) # Adapted from http://stackoverflow.com/a/7353335/579416 for contig in np.split(idx, np.where(np.diff(idx) != 1)[0] + 1): r = self[contig] if len(r) >= min_length: yield r def to_indices( self, alphabet=None, mask_gaps="auto", wildcard="auto", return_codes=False ): r"""Convert the sequence into indices of characters. The result will be indices of characters in an alphabet, if provided, otherwise indices of unique characters observed in the sequence, in which case the unique characters in sorted order will also be returned. Parameters ---------- alphabet : iterable of scalar or skbio.SubstitutionMatrix, optional Explicitly provided alphabet. The returned indices will be indices of characters in this alphabet. If `None`, will return indices of unique characters observed in the sequence. mask_gaps : 'auto' or bool, optional Mask gap characters in the sequence, and return a masked array instead of a standard array. The gap characters are defined by the sequence's `gap_chars` attribute. If `'auto'` (default), will return a standard array if no gap character is found, or a masked array if gap character(s) are found. wildcard : 'auto', str of length 1 or None, optional A character to substitute characters in the sequence that are absent from the alphabet. If `'auto'` (default), will adopt the sequence's `wildcard_char` attribute (if available). If no wildcard is given and there are absent characters, will raise an error. return_codes : bool, optional Return observed characters as an array of ASCII code points instead of a string. Not effective if `alphabet` is set. Returns ------- 1D np.ndarray or np.ma.ndarray of intp Vector of character indices representing the sequence .. versionchanged:: 0.7.0 The array data type was changed from ``uint8`` to ``intp``, which is the native NumPy indexing type without the need of casting. str or 1D np.ndarray of uint8, optional Sorted unique characters observed in the sequence. Raises ------ ValueError If alphabet are not valid ASCII characters or contains duplicates. ValueError If gap(s) are to be masked but gap character(s) are not defined. ValueError If wildcard character is not a valid ASCII character. Examples -------- Convert a protein sequence into indices of unique amino acids in it. Note that the unique characters are ordered. >>> from skbio import Protein >>> seq = Protein('MEEPQSDPSV') >>> idx, uniq = seq.to_indices() >>> idx array([2, 1, 1, 3, 4, 5, 0, 3, 5, 6]) >>> uniq 'DEMPQSV' Convert a DNA sequence into indices of nucleotides in an alphabet. Note that the order of characters is consistent with the alphabet. >>> from skbio import DNA >>> seq = DNA('CTCAAAAGTC') >>> idx = seq.to_indices(alphabet='TCGA') >>> idx array([1, 0, 1, 3, 3, 3, 3, 2, 0, 1]) Use the alphabet included in a substitution matrix. >>> from skbio import SubstitutionMatrix >>> sm = SubstitutionMatrix.by_name('NUC.4.4') >>> idx = seq.to_indices(alphabet=sm) >>> idx array([3, 1, 3, 0, 0, 0, 0, 2, 1, 3]) Gap characters ("-" and ".") in the sequence will be masked (`mask_gaps='auto'` is the default behavior). >>> seq = DNA('GAG-CTC') >>> idx = seq.to_indices(alphabet='ACGTN', mask_gaps='auto') >>> print(idx) [2 0 2 -- 1 3 1] >>> print(idx.mask) [False False False True False False False] Characters not included in the alphabet will be substituted with a wildcard character, such as "N" for nucleotides and "X" for amino acids (`wildcard='auto'` is the default behavior). >>> seq = DNA('GAGRCTC') >>> idx = seq.to_indices(alphabet='ACGTN', wildcard='auto') >>> idx array([2, 0, 2, 4, 1, 3, 1]) """ seq = self._bytes # mask gap characters mask = None if mask_gaps in (True, "auto"): gap_chars = getattr(self, "gap_chars", None) if gap_chars: # encode gap characters gap_chars = list(map(ord, gap_chars)) # locate gaps in sequence gaps = np.isin(seq, gap_chars) if mask_gaps is True or gaps.any(): mask, seq = gaps, seq[~gaps] elif mask_gaps is True: raise ValueError("Gap character(s) are not defined for the sequence.") # according to an alphabet if alphabet is not None: # get wildcard character if wildcard == "auto": wildcard = getattr(self, "wildcard_char", None) # encode wildcard character if wildcard is not None: try: assert (wildcard := ord(wildcard)) < 128 except (TypeError, AssertionError): raise ValueError("Wildcard must be a single ASCII character.") # extract alphabet from a substitution matrix if hasattr(alphabet, "_is_ascii"): if alphabet._is_ascii is True: indices = _indices_in_alphabet_ascii( seq, alphabet._char_hash, wildcard=wildcard ) else: raise ValueError( "Alphabet in the substitution matrix are not single ASCII " "characters." ) # process alphabet from scratch else: if find_duplicates(alphabet): raise ValueError("Alphabet contains duplicated characters.") try: alphabet = _alphabet_to_hashes(alphabet) except (TypeError, ValueError, UnicodeEncodeError): raise ValueError( "Alphabet cannot be encoded as single ASCII characters." ) indices = _indices_in_alphabet_ascii(seq, alphabet, wildcard=wildcard) # according to observed characters else: (indices,), observed = _indices_in_observed([seq]) if return_codes is False: observed = observed.tobytes().decode("ascii") # construct masked array if mask is not None: indices_ = np.full(mask.size, -1, dtype=np.intp) indices_[~mask] = indices indices = np.ma.array(indices_, mask=mask) if alphabet is not None: return indices else: return indices, observed def _constructor(self, **kwargs): return self.__class__(**kwargs) def _munge_to_index_array(self, sliceable): r"""Return index array from something isomorphic to a boolean vector.""" if isinstance(sliceable, str): if sliceable in self.positional_metadata: if self.positional_metadata[sliceable].dtype == bool: sliceable = self.positional_metadata[sliceable] else: raise TypeError( "Column '%s' in positional metadata does " "not correspond to a boolean vector" % sliceable ) else: raise ValueError( "No positional metadata associated with key '%s'" % sliceable ) if not hasattr(sliceable, "dtype") or ( hasattr(sliceable, "dtype") and sliceable.dtype == "object" ): sliceable = tuple(sliceable) bool_mode = False int_mode = False for s in sliceable: if isinstance(s, (bool, np.bool_)): bool_mode = True elif isinstance(s, (slice, int, np.signedinteger)) or ( hasattr(s, "dtype") and s.dtype != bool ): int_mode = True else: raise TypeError( "Invalid type in iterable: %s, must be one" " of {bool, int, slice, np.signedinteger}" % s.__class__.__name__ ) if bool_mode and int_mode: raise TypeError("Cannot provide iterable of both bool and int.") sliceable = np.r_[sliceable] if sliceable.dtype == bool: if sliceable.size != len(self): raise ValueError( "Boolean array (%d) does not match length of" " sequence (%d)." % (sliceable.size, len(self)) ) (normalized,) = np.where(sliceable) else: normalized = np.bincount(sliceable) if np.any(normalized > 1): raise ValueError("Overlapping index regions are not allowed.") (normalized,) = np.where(normalized) if np.any(normalized != sliceable): raise ValueError("Index regions are out of order.") return normalized def _munge_to_self_type(self, other, method): if isinstance(other, Sequence): if type(other) is not type(self): raise TypeError( "Cannot use %s and %s together with `%s`" % (self.__class__.__name__, other.__class__.__name__, method) ) else: return other return self.__class__(other) def _munge_to_sequence(self, other, method): if isinstance(other, Sequence): if type(other) is not type(self): raise TypeError( "Cannot use %s and %s together with `%s`" % (self.__class__.__name__, other.__class__.__name__, method) ) else: return other # We don't use self.__class__ or self._constructor here because we want # to construct the most general type of Sequence object in order to # avoid validation errors. return Sequence(other) def _munge_to_bytestring(self, other, method): if isinstance(other, bytes): return other elif isinstance(other, str): return other.encode("ascii") else: return self._munge_to_sequence(other, method)._string @contextmanager def _byte_ownership(self): if not self._owns_bytes: self._bytes = self._bytes.copy() self._owns_bytes = True self._bytes.flags.writeable = True yield self._bytes.flags.writeable = False def _single_index_to_slice(start_index): end_index = None if start_index == -1 else start_index + 1 return slice(start_index, end_index) def _is_single_index(index): return isinstance(index, numbers.Integral) and not isinstance(index, bool) def _as_slice_if_single_index(indexable): if _is_single_index(indexable): return _single_index_to_slice(indexable) else: return indexable def _slices_from_iter(array, indexables): for i in indexables: if isinstance(i, slice): pass elif _is_single_index(i): i = _single_index_to_slice(i) else: raise IndexError("Cannot slice sequence from iterable containing %r." % i) yield array[i] scikit-bio-scikit-bio-a3beaa6/skbio/sequence/_substitution.py000066400000000000000000000741501520735541300245660ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from copy import deepcopy from typing import Any, TYPE_CHECKING import numpy as np from skbio.util._decorator import classonlymethod from skbio.stats.distance import PairwiseMatrix from skbio.sequence._alphabet import _alphabet_to_hashes if TYPE_CHECKING: # pragma: no cover from collections.abc import Iterable from numpy.typing import NDArray from typing import Self class SubstitutionMatrix(PairwiseMatrix): r"""Scoring matrix between characters in biological sequences. Parameters ---------- alphabet : iterable Characters that constitute the alphabet. scores : array_like of shape (n_alphabet, n_alphabet) Scores of substitutions from one character (row, or axis=0) to another character (column, or axis=1). kwargs : dict Additional arguments for the ``PairwiseMatrix`` constructor. See Also -------- skbio.stats.distance.PairwiseMatrix Notes ----- A substitution matrix (a.k.a. replacement matrix) scores the substitution of each character by each other character and itself in an alphabet. The score usually represents the rate of substitution over evolutionary time in a biological sequence. A higher score usually indicates higher similarity in chemical properties or functional roles of two molecules, therefore a mutation from one to the other is easier. In sequence alignment, the score can measure the likelihood that a pair of aligned characters are homologous rather than by chance. This class provides a generalized interface for substitution matrices. The alphabet usually consists of individual characters, such as nucleotides or amino acids, but it can be generalized to any iterable of scalars (numbers, strings, etc.). Therefore, you may use this class to construct substitution matrices of complicated biological units (such as codons or non-canonical amino acids). The score matrix may be symmetric, as many existing matrices are, or asymmetric, where the score of one character substituted by another is unequal to the other way around. Only square matrices (i.e., numbers of rows and columns are equal) are supported. Multiple commonly used nucleotide and amino acid substitution matrices are pre-defined and can be referred to by name. Examples include NUC.4.4 for nucleotides, and variants of BLOSUM and PAM matrices for amino acids. ``SubstitutionMatrix`` is a subclass of ``PairwiseMatrix``. Therefore, all attributes and methods of the latter also apply to the former. The default floating-point data type of ``SubstitutionMatrix`` is float32. If you create with an integer array or nested lists, it will be automatically casted into float32. However, if the input array is already in float64 type, the type will be preserved. The underlying array of an ``SubstitutionMatrix`` object is guaranteed to be C-contiguous, which facilitates row-major operations. Examples -------- Create a simple substitution matrix between the four nucleotide bases "A", "C", "G" and "T". The value 2 in the main diagonal represents a match between two identical bases. The value -1 in the upper-right and lower-left triangles represents a mismatch between two different bases. >>> from skbio import SubstitutionMatrix >>> sm = SubstitutionMatrix('ACGT', np.array([ ... [2, -1, -1, -1], ... [-1, 2, -1, -1], ... [-1, -1, 2, -1], ... [-1, -1, -1, 2]])) >>> sm.alphabet ('A', 'C', 'G', 'T') >>> sm.scores array([[ 2., -1., -1., -1.], [-1., 2., -1., -1.], [-1., -1., 2., -1.], [-1., -1., -1., 2.]], dtype=float32) Look up the substitution score between a pair of bases. >>> sm['A', 'T'] -1.0 >>> sm['G', 'G'] 2.0 This matrix can also be created using the ``identity`` method. >>> sm = SubstitutionMatrix.identity('ACGT', 2, -1) Load the pre-defined substitution matrix "NUC.4.4", which covers the four bases plus degenerate codes. >>> sm = SubstitutionMatrix.by_name('NUC.4.4') >>> sm.alphabet ('A', 'T', 'G', 'C', 'S', 'W', 'R', 'Y', 'K', 'M', 'B', 'V', 'H', 'D', 'N') With a :class:`~skbio.sequence.Sequence` object, one can efficiently map all characters to their indices in the substitution matrix. >>> from skbio import DNA >>> seq = DNA('GGATCC') >>> seq.to_indices(sm) array([2, 2, 0, 1, 3, 3]) This approach enables various subsequent operations. For example, one can efficiently create a position-to-position scoring matrix between two sequences. >>> seq1, seq2 = DNA('GGATCC'), DNA('AGATCT') >>> idx1, idx2 = seq1.to_indices(sm), seq2.to_indices(sm) >>> sm.scores[idx1[:, None], idx2[None, :]] array([[-4., 5., -4., -4., -4., -4.], [-4., 5., -4., -4., -4., -4.], [ 5., -4., 5., -4., -4., -4.], [-4., -4., -4., 5., -4., 5.], [-4., -4., -4., -4., 5., -4.], [-4., -4., -4., -4., 5., -4.]], dtype=float32) Finding indices of sequence characters is most efficient when the alphabet consists of only ASCII codes (0 to 127). This can be determined by the ``is_ascii`` flag of a substitution matrix. Most common nucleotide and amino acid substitution matrices only contain ASCII codes. However, one is not limited to ASCII characters. Using Unicode characters beyond code point 127 is valid. >>> sm = SubstitutionMatrix('äëïöü', np.array([ ... [0, 1, 2, 3, 4], ... [1, 0, 5, 6, 7], ... [2, 5, 0, 8, 9], ... [3, 6, 8, 0, 0], ... [4, 7, 9, 0, 1]])) >>> sm.alphabet ('ä', 'ë', 'ï', 'ö', 'ü') Any iterables of scalars are valid alphabets, granting flexibility in working with non-character data types. For example, one can include words or tokens in a substitution matrix. >>> tokens = 'lorem ipsum dolor sit amet'.split() >>> sm = SubstitutionMatrix(tokens, np.array([ ... [3, 1, 2, 0, 0], ... [1, 3, 1, 2, 0], ... [2, 1, 3, 1, 2], ... [0, 2, 1, 3, 1], ... [0, 0, 2, 1, 3]])) >>> sm.alphabet ('lorem', 'ipsum', 'dolor', 'sit', 'amet') >>> sm['lorem', 'ipsum'] 1.0 """ @property def alphabet(self): """Alphabet of the substitution matrix. Each element (character) corresponds to one row/column in the matrix. Returns ------- tuple Alphabet of the substitution matrix. Notes ----- This is an alias of ``ids``. """ return self._ids @property def scores(self): """Matrix of substitution scores. Each value corresponds to the score of substituting the row character with the column character. Returns ------- 2D np.ndarray Matrix of substitution scores. Notes ----- This is an alias of ``data``. """ return self._data @property def is_ascii(self): """Whether alphabet consists of single ASCII characters. `True` if every character in the alphabet can be represented by a single ASCII character within code point range 0 to 127. Returns ------- bool Whether alphabet consists of single ASCII characters. """ return self._is_ascii def __init__(self, alphabet, scores, **kwargs): """Initialize a substitution matrix object.""" # cast to float32 (see PairwiseMatrix.__init__) _issue_copy = True if isinstance(scores, np.ndarray): if scores.dtype in (np.float32, np.float64): _issue_copy = False if _issue_copy: scores = np.asarray(scores, dtype=np.float32) # make sure matrix is C-contiguous (row-major) in memory if not scores.flags.c_contiguous: scores = np.ascontiguousarray(scores) super().__init__(scores, alphabet, **kwargs) # `_char_map`: dictionary of characters to indices in the alphabet. # It is to enable efficient conversion of sequences into indices. # It is compatible with generalized sequences. self._char_map = {x: i for i, x in enumerate(alphabet)} # `_is_ascii`: whether alphabet can be encoded as ASCII characters. # `_char_hash`: hash table of ASCII code points to indices in the # alphabet. It is to enable efficient conversion of sequences into # into indices. It is optimized for ASCII sequences. try: hash_ = _alphabet_to_hashes(alphabet) except (TypeError, ValueError, UnicodeEncodeError): self._is_ascii = False self._char_hash = None else: self._is_ascii = True self._char_hash = hash_ def copy(self): """Return a deep copy of the substitution matrix. Returns ------- SubstitutionMatrix Named substitution matrix. """ return self.__class__( deepcopy(self.alphabet), self.scores.copy(), validate=False, ) def to_dict(self): """Create a 2D dictionary from the substitution matrix. Returns ------- dict of dict 2D dictionary constructed from the substitution matrix. """ return { id_: dict(zip(self._ids, row)) for id_, row in zip(self._ids, self._data) } @classonlymethod def from_dict( cls, dictionary: dict[str, dict[str, float]], dtype: str = "float32" ) -> Self: """Create a substitution matrix from a 2D dictionary. Parameters ---------- dictionary : dict of dict 2D dictionary of substitution scores from outer characters to inner characters. dtype : {'float32', 'float64'}, optional Floating-point data type of the matrix. Default is "float32". Returns ------- SubstitutionMatrix Substitution matrix constructed from the dictionary. Raises ------ ValueError If outer and inner characters are inconsistent. ValueError If scores are not numbers. Examples -------- >>> from skbio import SubstitutionMatrix >>> d = {'a': {'a': 1, 'b': 0, 'c': 0}, ... 'b': {'a': 0, 'b': 1, 'c': 0}, ... 'c': {'a': 0, 'b': 0, 'c': 1}} >>> mat = SubstitutionMatrix.from_dict(d) >>> mat.alphabet ('a', 'b', 'c') >>> mat.scores array([[ 1., 0., 0.], [ 0., 1., 0.], [ 0., 0., 1.]], dtype=float32) """ alphabet, rows = zip(*dictionary.items()) alphabet_set = set(alphabet) idmap = {x: i for i, x in enumerate(alphabet)} n = len(alphabet) scores: NDArray = np.full((n, n), np.nan, dtype=dtype) for i, row in enumerate(rows): if set(row) != alphabet_set: raise ValueError( "The outer and inner layers of the dictionary" " must have the same set of keys." ) for key, value in row.items(): scores[i][idmap[key]] = value return cls(alphabet, scores) @classonlymethod def identity( cls, alphabet: Iterable[Any], match: int | float, mismatch: int | float, dtype: str = "float32", ) -> Self: r"""Create an identity substitution matrix. All matches and mismatches will have the identical scores, respectively, regardless of the character. Parameters ---------- alphabet : iterable Characters that constitute the alphabet. match : int or float Score assigned to all matches. mismatch : int or float Score assigned to all mismatches. dtype : {"float32", "float64"}, optional Floating-point data type of the matrix. Default is "float32". Returns ------- SubstitutionMatrix Substitution matrix constructed from the alphabet and scores. Examples -------- >>> from skbio import SubstitutionMatrix >>> mat = SubstitutionMatrix.identity('ACGT', 1, -2) >>> mat.alphabet ('A', 'C', 'G', 'T') >>> mat.scores array([[ 1., -2., -2., -2.], [-2., 1., -2., -2.], [-2., -2., 1., -2.], [-2., -2., -2., 1.]], dtype=float32) """ alphabet = tuple(alphabet) n = len(alphabet) scores: NDArray = np.full((n, n), mismatch, dtype=dtype) np.fill_diagonal(scores, match) return cls(alphabet, scores) @classonlymethod def by_name(cls, name: str) -> Self: """Load a pre-defined substitution matrix by its name. Parameters ---------- name : str Name of the substitution matrix. Returns ------- SubstitutionMatrix Named substitution matrix. Raises ------ ValueError If named substitution matrix does not exist. See Also -------- get_names Notes ----- Names are case-insensitive. For instance, `BLOSUM62` and `blosum62` point to the same substitution matrix. Available substitution matrix names can be obtained by ``get_names``. Currently, the following names are supported: - `NUC.4.4` (a.k.a. DNAfull): A nucleotide substitution matrix covering all definite and degenerate nucleotides. - Point Accepted Mutation (PAM) [1]_: A set of amino acid substitution matrices, including `PAM30`, `PAM70` and `PAM250`. - BLOcks SUbstitution Matrix (BLOSUM) [2]_: A set of amino acid substitution matrices, including `BLOSUM45`, `BLOSUM50`, `BLOSUM62`, `BLOSUM80` and `BLOSUM90`. References ---------- .. [1] Dayhoff, M., Schwartz, R., & Orcutt, B. (1978). A model of evolutionary change in proteins. Atlas of protein sequence and structure, 5, 345-352. .. [2] Henikoff, S., & Henikoff, J. G. (1992). Amino acid substitution matrices from protein blocks. Proceedings of the National Academy of Sciences, 89(22), 10915-10919. Examples -------- >>> from skbio import SubstitutionMatrix >>> mat = SubstitutionMatrix.by_name('BLOSUM62') >>> len(mat.alphabet) 24 >>> mat['M', 'K'] -1.0 """ try: return _named_substitution_matrices[name] except KeyError: name_lower = name.lower() for key, value in _named_substitution_matrices.items(): if name_lower == key.lower(): return value raise ValueError(f'Substitution matrix "{name}" does not exist.') @classonlymethod def get_names(cls) -> list[str]: """List names of pre-defined substitution matrices. Returns ------- list of str Names of pre-defined substitution matrices. See Also -------- by_name """ return list(_named_substitution_matrices.keys()) def _matrix_to_vector(mat): """Flatten a square matrix to a vector of the upper triangle and diagonal.""" assert len(mat.shape) == 2 assert mat.shape[0] == mat.shape[1] return mat[np.triu_indices(len(mat))] def _vector_to_matrix(vec, dtype="float32"): """Revert a vector representing a flattened matrix to square form.""" assert len(vec.shape) == 1 # a square matrix of shape (n, n) will have n * (n + 1) / 2 elements in the # flattened vector; the following code reverses this equation to obtain the # original shape of the matrix n = (np.sqrt(1 + 8 * len(vec)) - 1) / 2 assert n == (n := int(n)) mat = np.zeros((n, n), dtype=dtype) mat[np.triu_indices(n)] = vec return mat + np.triu(mat, k=1).T # Defined according to the matrices hosted at the NCBI FTP server: # https://ftp.ncbi.nlm.nih.gov/blast/matrices/ # Note: "N" is the wildcard for nucleotide bases and "X" is the wildcard for amino # acids. They can be automatically recognized by `Sequence.to_indices`. # Note: "*" is the stop codon and it usually has the lowest score in the matrix. # See: https://bioinformatics.stackexchange.com/questions/21705/ # fmt: off _named_substitution_matrices = { # NUC.4.4, a.k.a. DNAfull "NUC.4.4": SubstitutionMatrix( "ATGCSWRYKMBVHDN", _vector_to_matrix( np.array( [5, -4, -4, -4, -4, 1, 1, -4, -4, 1, -4, -1, -1, -1, -2, 5, -4, -4, -4, 1, -4, 1, 1, -4, -1, -4, -1, -1, -2, 5, -4, 1, -4, 1, -4, 1, -4, -1, -1, -4, -1, -2, 5, 1, -4, -4, 1, -4, 1, -1, -1, -1, -4, -2, -1, -4, -2, -2, -2, -2, -1, -1, -3, -3, -1, -1, -2, -2, -2, -2, -3, -3, -1, -1, -1, -1, -4, -2, -2, -3, -1, -3, -1, -1, -1, -2, -2, -1, -3, -1, -3, -1, -1, -4, -1, -3, -3, -1, -1, -1, -3, -1, -1, -3, -1, -1, -2, -2, -2, -1, -1, -2, -2, -1, -1, -2, -1, -1, -1, -1] ) ), validate=False, ), # Point Accepted Mutation (PAM) "PAM30": SubstitutionMatrix( "ARNDCQEGHILKMFPSTWYVBZX*", _vector_to_matrix( np.array( [ 6, -7, -4, -3, -6, -4, -2, -2, -7, -5, -6, -7, -5, -8, -2, 0, -1, -13, -8, -2, -3, -3, -3, -17, 8, -6, -10, -8, -2, -9, -9, -2, -5, -8, 0, -4, -9, -4, -3, -6, -2, -10, -8, -7, -4, -6, -17, 8, 2, -11, -3, -2, -3, 0, -5, -7, -1, -9, -9, -6, 0, -2, -8, -4, -8, 6, -3, -3, -17, 8, -14, -2, 2, -3, -4, -7, -12, -4, -11, -15, -8, -4, -5, -15, -11, -8, 6, 1, -5, -17, 10, -14, -14, -9, -7, -6, -15, -14, -13, -13, -8, -3, -8, -15, -4, -6, -12, -14, -9, -17, 8, 1, -7, 1, -8, -5, -3, -4, -13, -3, -5, -5, -13, -12, -7, -3, 6, -5, -17, 8, -4, -5, -5, -9, -4, -7, -14, -5, -4, -6, -17, -8, -6, 1, 6, -5, -17, 6, -9, -11, -10, -7, -8, -9, -6, -2, -6, -15, -14, -5, -3, -5, -5, -17, 9, -9, -6, -6, -10, -6, -4, -6, -7, -7, -3, -6, -1, -1, -5, -17, 8, -1, -6, -1, -2, -8, -7, -2, -14, -6, 2, -6, -6, -5, -17, 7, -8, 1, -3, -7, -8, -7, -6, -7, -2, -9, -7, -6, -17, 7, -2, -14, -6, -4, -3, -12, -9, -9, -2, -4, -5, -17, 11, -4, -8, -5, -4, -13, -11, -1, -10, -5, -5, -17, 9, -10, -6, -9, -4, 2, -8, -10, -13, -8, -17, 8, -2, -4, -14, -13, -6, -7, -4, -5, -17, 6, 0, -5, -7, -6, -1, -5, -3, -17, 7, -13, -6, -3, -3, -6, -4, -17, 13, -5, -15, -10, -14, -11, -17, 10, -7, -6, -9, -7, -17, 7, -8, -6, -5, -17, 6, 0, -5, -17, 6, -5, -17, -5, -17, 1] ) ), validate=False, ), "PAM70": SubstitutionMatrix( "ARNDCQEGHILKMFPSTWYVBZX*", _vector_to_matrix( np.array( [5, -4, -2, -1, -4, -2, -1, 0, -4, -2, -4, -4, -3, -6, 0, 1, 1, -9, -5, -1, -1, -1, -2, -11, 8, -3, -6, -5, 0, -5, -6, 0, -3, -6, 2, -2, -7, -2, -1, -4, 0, -7, -5, -4, -2, -3, -11, 6, 3, -7, -1, 0, -1, 1, -3, -5, 0, -5, -6, -3, 1, 0, -6, -3, -5, 5, -1, -2, -11, 6, -9, 0, 3, -1, -1, -5, -8, -2, -7, -10, -4, -1, -2, -10, -7, -5, 5, 2, -3, -11, 9, -9, -9, -6, -5, -4, -10, -9, -9, -8, -5, -1, -5, -11, -2, -4, -8, -9, -6, -11, 7, 2, -4, 2, -5, -3, -1, -2, -9, -1, -3, -3, -8, -8, -4, -1, 5, -2, -11, 6, -2, -2, -4, -6, -2, -4, -9, -3, -2, -3, -11, -6, -4, 2, 5, -3, -11, 6, -6, -6, -7, -5, -6, -7, -3, 0, -3, -10, -9, -3, -1, -3, -3, -11, 8, -6, -4, -3, -6, -4, -2, -3, -4, -5, -1, -4, 0, 1, -3, -11, 7, 1, -4, 1, 0, -5, -4, -1, -9, -4, 3, -4, -4, -3, -11, 6, -5, 2, -1, -5, -6, -4, -4, -4, 0, -6, -4, -4, -11, 6, 0, -9, -4, -2, -1, -7, -7, -6, -1, -2, -3, -11, 10, -2, -5, -3, -2, -8, -7, 0, -6, -3, -3, -11, 8, -7, -4, -6, -2, 4, -5, -7, -9, -5, -11, 7, 0, -2, -9, -9, -3, -4, -2, -3, -11, 5, 2, -3, -5, -3, 0, -2, -1, -11, 6, -8, -4, -1, -1, -3, -2, -11, 13, -3, -10, -7, -10, -7, -11, 9, -5, -4, -7, -5, -11, 6, -5, -4, -2, -11, 5, 1, -2, -11, 5, -3, -11, -3, -11, 1] ) ), validate=False, ), "PAM250": SubstitutionMatrix( "ARNDCQEGHILKMFPSTWYVBZX*", _vector_to_matrix( np.array( [2, -2, 0, 0, -2, 0, 0, 1, -1, -1, -2, -1, -1, -3, 1, 1, 1, -6, -3, 0, 0, 0, 0, -8, 6, 0, -1, -4, 1, -1, -3, 2, -2, -3, 3, 0, -4, 0, 0, -1, 2, -4, -2, -1, 0, -1, -8, 2, 2, -4, 1, 1, 0, 2, -2, -3, 1, -2, -3, 0, 1, 0, -4, -2, -2, 2, 1, 0, -8, 4, -5, 2, 3, 1, 1, -2, -4, 0, -3, -6, -1, 0, 0, -7, -4, -2, 3, 3, -1, -8, 12, -5, -5, -3, -3, -2, -6, -5, -5, -4, -3, 0, -2, -8, 0, -2, -4, -5, -3, -8, 4, 2, -1, 3, -2, -2, 1, -1, -5, 0, -1, -1, -5, -4, -2, 1, 3, -1, -8, 4, 0, 1, -2, -3, 0, -2, -5, -1, 0, 0, -7, -4, -2, 3, 3, -1, -8, 5, -2, -3, -4, -2, -3, -5, 0, 1, 0, -7, -5, -1, 0, 0, -1, -8, 6, -2, -2, 0, -2, -2, 0, -1, -1, -3, 0, -2, 1, 2, -1, -8, 5, 2, -2, 2, 1, -2, -1, 0, -5, -1, 4, -2, -2, -1, -8, 6, -3, 4, 2, -3, -3, -2, -2, -1, 2, -3, -3, -1, -8, 5, 0, -5, -1, 0, 0, -3, -4, -2, 1, 0, -1, -8, 6, 0, -2, -2, -1, -4, -2, 2, -2, -2, -1, -8, 9, -5, -3, -3, 0, 7, -1, -4, -5, -2, -8, 6, 1, 0, -6, -5, -1, -1, 0, -1, -8, 2, 1, -2, -3, -1, 0, 0, 0, -8, 3, -5, -3, 0, 0, -1, 0, -8, 17, 0, -6, -5, -6, -4, -8, 10, -2, -3, -4, -2, -8, 4, -2, -2, -1, -8, 3, 2, -1, -8, 3, -1, -8, -1, -8, 1] ) ), validate=False, ), # BLOcks SUbstitution Matrix (BLOSUM) "BLOSUM45": SubstitutionMatrix( "ARNDCQEGHILKMFPSTWYVBZX*", _vector_to_matrix( np.array( [ 5, -2, -1, -2, -1, -1, -1, 0, -2, -1, -1, -1, -1, -2, -1, 1, 0, -2, -2, 0, -1, -1, 0, -5, 7, 0, -1, -3, 1, 0, -2, 0, -3, -2, 3, -1, -2, -2, -1, -1, -2, -1, -2, -1, 0, -1, -5, 6, 2, -2, 0, 0, 0, 1, -2, -3, 0, -2, -2, -2, 1, 0, -4, -2, -3, 4, 0, -1, -5, 7, -3, 0, 2, -1, 0, -4, -3, 0, -3, -4, -1, 0, -1, -4, -2, -3, 5, 1, -1, -5, 12, -3, -3, -3, -3, -3, -2, -3, -2, -2, -4, -1, -1, -5, -3, -1, -2, -3, -2, -5, 6, 2, -2, 1, -2, -2, 1, 0, -4, -1, 0, -1, -2, -1, -3, 0, 4, -1, -5, 6, -2, 0, -3, -2, 1, -2, -3, 0, 0, -1, -3, -2, -3, 1, 4, -1, -5, 7, -2, -4, -3, -2, -2, -3, -2, 0, -2, -2, -3, -3, -1, -2, -1, -5, 10, -3, -2, -1, 0, -2, -2, -1, -2, -3, 2, -3, 0, 0, -1, -5, 5, 2, -3, 2, 0, -2, -2, -1, -2, 0, 3, -3, -3, -1, -5, 5, -3, 2, 1, -3, -3, -1, -2, 0, 1, -3, -2, -1, -5, 5, -1, -3, -1, -1, -1, -2, -1, -2, 0, 1, -1, -5, 6, 0, -2, -2, -1, -2, 0, 1, -2, -1, -1, -5, 8, -3, -2, -1, 1, 3, 0, -3, -3, -1, -5, 9, -1, -1, -3, -3, -3, -2, -1, -1, -5, 4, 2, -4, -2, -1, 0, 0, 0, -5, 5, -3, -1, 0, 0, -1, 0, -5, 15, 3, -3, -4, -2, -2, -5, 8, -1, -2, -2, -1, -5, 5, -3, -3, -1, -5, 4, 2, -1, -5, 4, -1, -5, -1, -5, 1] ) ), validate=False, ), "BLOSUM50": SubstitutionMatrix( "ARNDCQEGHILKMFPSTWYVBZX*", _vector_to_matrix( np.array( [5, -2, -1, -2, -1, -1, -1, 0, -2, -1, -2, -1, -1, -3, -1, 1, 0, -3, -2, 0, -2, -1, -1, -5, 7, -1, -2, -4, 1, 0, -3, 0, -4, -3, 3, -2, -3, -3, -1, -1, -3, -1, -3, -1, 0, -1, -5, 7, 2, -2, 0, 0, 0, 1, -3, -4, 0, -2, -4, -2, 1, 0, -4, -2, -3, 4, 0, -1, -5, 8, -4, 0, 2, -1, -1, -4, -4, -1, -4, -5, -1, 0, -1, -5, -3, -4, 5, 1, -1, -5, 13, -3, -3, -3, -3, -2, -2, -3, -2, -2, -4, -1, -1, -5, -3, -1, -3, -3, -2, -5, 7, 2, -2, 1, -3, -2, 2, 0, -4, -1, 0, -1, -1, -1, -3, 0, 4, -1, -5, 6, -3, 0, -4, -3, 1, -2, -3, -1, -1, -1, -3, -2, -3, 1, 5, -1, -5, 8, -2, -4, -4, -2, -3, -4, -2, 0, -2, -3, -3, -4, -1, -2, -2, -5, 10, -4, -3, 0, -1, -1, -2, -1, -2, -3, 2, -4, 0, 0, -1, -5, 5, 2, -3, 2, 0, -3, -3, -1, -3, -1, 4, -4, -3, -1, -5, 5, -3, 3, 1, -4, -3, -1, -2, -1, 1, -4, -3, -1, -5, 6, -2, -4, -1, 0, -1, -3, -2, -3, 0, 1, -1, -5, 7, 0, -3, -2, -1, -1, 0, 1, -3, -1, -1, -5, 8, -4, -3, -2, 1, 4, -1, -4, -4, -2, -5, 10, -1, -1, -4, -3, -3, -2, -1, -2, -5, 5, 2, -4, -2, -2, 0, 0, -1, -5, 5, -3, -2, 0, 0, -1, 0, -5, 15, 2, -3, -5, -2, -3, -5, 8, -1, -3, -2, -1, -5, 5, -4, -3, -1, -5, 5, 2, -1, -5, 5, -1, -5, -1, -5, 1] ) ), validate=False, ), "BLOSUM62": SubstitutionMatrix( "ARNDCQEGHILKMFPSTWYVBZX*", _vector_to_matrix( np.array( [4, -1, -2, -2, 0, -1, -1, 0, -2, -1, -1, -1, -1, -2, -1, 1, 0, -3, -2, 0, -2, -1, 0, -4, 5, 0, -2, -3, 1, 0, -2, 0, -3, -2, 2, -1, -3, -2, -1, -1, -3, -2, -3, -1, 0, -1, -4, 6, 1, -3, 0, 0, 0, 1, -3, -3, 0, -2, -3, -2, 1, 0, -4, -2, -3, 3, 0, -1, -4, 6, -3, 0, 2, -1, -1, -3, -4, -1, -3, -3, -1, 0, -1, -4, -3, -3, 4, 1, -1, -4, 9, -3, -4, -3, -3, -1, -1, -3, -1, -2, -3, -1, -1, -2, -2, -1, -3, -3, -2, -4, 5, 2, -2, 0, -3, -2, 1, 0, -3, -1, 0, -1, -2, -1, -2, 0, 3, -1, -4, 5, -2, 0, -3, -3, 1, -2, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1, -4, 6, -2, -4, -4, -2, -3, -3, -2, 0, -2, -2, -3, -3, -1, -2, -1, -4, 8, -3, -3, -1, -2, -1, -2, -1, -2, -2, 2, -3, 0, 0, -1, -4, 4, 2, -3, 1, 0, -3, -2, -1, -3, -1, 3, -3, -3, -1, -4, 4, -2, 2, 0, -3, -2, -1, -2, -1, 1, -4, -3, -1, -4, 5, -1, -3, -1, 0, -1, -3, -2, -2, 0, 1, -1, -4, 5, 0, -2, -1, -1, -1, -1, 1, -3, -1, -1, -4, 6, -4, -2, -2, 1, 3, -1, -3, -3, -1, -4, 7, -1, -1, -4, -3, -2, -2, -1, -2, -4, 4, 1, -3, -2, -2, 0, 0, 0, -4, 5, -2, -2, 0, -1, -1, 0, -4, 11, 2, -3, -4, -3, -2, -4, 7, -1, -3, -2, -1, -4, 4, -3, -2, -1, -4, 4, 1, -1, -4, 4, -1, -4, -1, -4, 1] ) ), validate=False, ), "BLOSUM80": SubstitutionMatrix( "ARNDCQEGHILKMFPSTWYVBZX*", _vector_to_matrix( np.array( [7, -3, -3, -3, -1, -2, -2, 0, -3, -3, -3, -1, -2, -4, -1, 2, 0, -5, -4, -1, -3, -2, -1, -8, 9, -1, -3, -6, 1, -1, -4, 0, -5, -4, 3, -3, -5, -3, -2, -2, -5, -4, -4, -2, 0, -2, -8, 9, 2, -5, 0, -1, -1, 1, -6, -6, 0, -4, -6, -4, 1, 0, -7, -4, -5, 5, -1, -2, -8, 10, -7, -1, 2, -3, -2, -7, -7, -2, -6, -6, -3, -1, -2, -8, -6, -6, 6, 1, -3, -8, 13, -5, -7, -6, -7, -2, -3, -6, -3, -4, -6, -2, -2, -5, -5, -2, -6, -7, -4, -8, 9, 3, -4, 1, -5, -4, 2, -1, -5, -3, -1, -1, -4, -3, -4, -1, 5, -2, -8, 8, -4, 0, -6, -6, 1, -4, -6, -2, -1, -2, -6, -5, -4, 1, 6, -2, -8, 9, -4, -7, -7, -3, -5, -6, -5, -1, -3, -6, -6, -6, -2, -4, -3, -8, 12, -6, -5, -1, -4, -2, -4, -2, -3, -4, 3, -5, -1, 0, -2, -8, 7, 2, -5, 2, -1, -5, -4, -2, -5, -3, 4, -6, -6, -2, -8, 6, -4, 3, 0, -5, -4, -3, -4, -2, 1, -7, -5, -2, -8, 8, -3, -5, -2, -1, -1, -6, -4, -4, -1, 1, -2, -8, 9, 0, -4, -3, -1, -3, -3, 1, -5, -3, -2, -8, 10, -6, -4, -4, 0, 4, -2, -6, -6, -3, -8, 12, -2, -3, -7, -6, -4, -4, -2, -3, -8, 7, 2, -6, -3, -3, 0, -1, -1, -8, 8, -5, -3, 0, -1, -2, -1, -8, 16, 3, -5, -8, -5, -5, -8, 11, -3, -5, -4, -3, -8, 7, -6, -4, -2, -8, 6, 0, -3, -8, 6, -1, -8, -2, -8, 1] ) ), validate=False, ), "BLOSUM90": SubstitutionMatrix( "ARNDCQEGHILKMFPSTWYVBZX*", _vector_to_matrix( np.array( [ 5, -2, -2, -3, -1, -1, -1, 0, -2, -2, -2, -1, -2, -3, -1, 1, 0, -4, -3, -1, -2, -1, -1, -6, 6, -1, -3, -5, 1, -1, -3, 0, -4, -3, 2, -2, -4, -3, -1, -2, -4, -3, -3, -2, 0, -2, -6, 7, 1, -4, 0, -1, -1, 0, -4, -4, 0, -3, -4, -3, 0, 0, -5, -3, -4, 4, -1, -2, -6, 7, -5, -1, 1, -2, -2, -5, -5, -1, -4, -5, -3, -1, -2, -6, -4, -5, 4, 0, -2, -6, 9, -4, -6, -4, -5, -2, -2, -4, -2, -3, -4, -2, -2, -4, -4, -2, -4, -5, -3, -6, 7, 2, -3, 1, -4, -3, 1, 0, -4, -2, -1, -1, -3, -3, -3, -1, 4, -1, -6, 6, -3, -1, -4, -4, 0, -3, -5, -2, -1, -1, -5, -4, -3, 0, 4, -2, -6, 6, -3, -5, -5, -2, -4, -5, -3, -1, -3, -4, -5, -5, -2, -3, -2, -6, 8, -4, -4, -1, -3, -2, -3, -2, -2, -3, 1, -4, -1, 0, -2, -6, 5, 1, -4, 1, -1, -4, -3, -1, -4, -2, 3, -5, -4, -2, -6, 5, -3, 2, 0, -4, -3, -2, -3, -2, 0, -5, -4, -2, -6, 6, -2, -4, -2, -1, -1, -5, -3, -3, -1, 1, -1, -6, 7, -1, -3, -2, -1, -2, -2, 0, -4, -2, -1, -6, 7, -4, -3, -3, 0, 3, -2, -4, -4, -2, -6, 8, -2, -2, -5, -4, -3, -3, -2, -2, -6, 5, 1, -4, -3, -2, 0, -1, -1, -6, 6, -4, -2, -1, -1, -1, -1, -6, 11, 2, -3, -6, -4, -3, -6, 8, -3, -4, -3, -2, -6, 5, -4, -3, -2, -6, 4, 0, -2, -6, 4, -1, -6, -2, -6, 1] ) ), validate=False, ), } # fmt: on scikit-bio-scikit-bio-a3beaa6/skbio/sequence/distance.py000066400000000000000000001707321520735541300234500ustar00rootroot00000000000000"""Sequence distance metrics (:mod:`skbio.sequence.distance`) ========================================================== .. currentmodule:: skbio.sequence.distance This module provides functions for computing distances between biological sequences. These functions can be used directly on two :class:`~skbio.sequence.Sequence` objects, or supplied to other parts of the scikit-bio API that accept a sequence distance metric as input, such as :func:`~skbio.alignment.align_dists`, :meth:`Sequence.distance `, and :meth:`PairwiseMatrix.from_iterable `. Generic distance metrics ------------------------ .. autosummary:: :toctree: hamming pdist logdet paralin kmer_distance Nucleotide distance metrics --------------------------- .. autosummary:: :toctree: jc69 f81 k2p f84 tn93 """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from typing import TYPE_CHECKING from inspect import signature import functools import numpy as np from skbio.sequence import Sequence, GrammaredSequence, DNA, RNA, Protein from skbio.sequence._alphabet import _encode_alphabet if TYPE_CHECKING: # pragma: no cover from numpy.typing import NDArray, ArrayLike # ---------------------------------------------------------------------------- # Functions of this module are organized in the following structure: Each # distance metric "xyz" has two functions: # # - `xyz` is a public-facing function that takes a pair of sequences as input # and outputs a single number. It has several attributes specifying its # behavior. See `_metric_specs` for details. # # - `_xyz` is a private function that consumes a 2-D array representing the # ASCII codes of multiple aligned sequences, and generates a condensed # distance matrix between them. It is typically called by `skbio.alignment. # align_dists`. Optionally, it consumes a Boolean mask of the input array, # representing valid sites, and the type of input sequences. # # Distance calculation on a multiple sequence alignment follows a common # strategy: Each sequence is iteratively selected and compared against all # remaining sequences via vectorized operations. This strategy ensures # efficiency while not inflating memory consumption. Specifically, this # consumes at most n_seq x n_pos x c memory, in which c is a constant. This # is on the same scale as the original sequence alignment. # # It is possible to construct a loop-free, fully vectorized solution for some # distance metrics. However, that typically involves casting the sequences to # a 3D array of n_seq x n_seq x n_pos, which may consume a significant amount # of memory when there are many sequences. # # ---------------------------------------------------------------------------- def _metric_specs( seqtype: type | tuple[type, ...] | None = None, equal: bool = False, alphabet: str | ArrayLike | None = None, ): r"""Specifications of a sequence distance metric. Parameters ---------- func : callable Function that calculates a sequence distance metric. seqtype : type or tuple of types, optional Valid sequence types. Can be a single type (such as ``Protein``) or a tuple of multiple types (such as ``(DNA, RNA)``). If None (default), any ``Sequence`` objects, grammared or not, are valid. equal : bool, optional If True, the two sequences must have the same length. Default is False. alphabet : str, 1D array_like, {'nongap', 'definite', 'canonical'}, optional An alphabet of valid characters to be considered by the metric. Can be a string or array-like of characters or their ASCII codes. Three special keywords are recognized: "nongap" (excluding gap characters such as "-" and "*"), "definite" (definite characters, i.e., non-degenerate and non-gap characters), and "canonical" (canonical characters, such as the four nucleobases and the 20 basic amino acids). Keywords can be used only when sequences are grammared. If None (default), all characters are valid. Invalid characters will be removed from the sequences prior to calculation. If ``equal=True`` is set, positions with either or both invalid characters in the two sequences will be removed. Returns ------- callable Decorated function. Notes ----- This function serves as a decorator for individual functions that calculate sequence distance metrics. The two positional arguments of a decorated function must be two ``Sequence`` objects. Additional arguments may follow. """ def decorator(func): name = func.__name__ has_freqs = "freqs" in signature(func).parameters @functools.wraps(func) def wrapper(seq1, seq2, *args, **kwargs): # Check if sequences are skbio.sequence objects. type1 = type(seq1) if not issubclass(type1, Sequence): raise TypeError( "Sequences must be skbio.sequence.Sequence instances, not " f"{type1.__name__!r}." ) # Check if sequences have the same type. if type1 is not type(seq2): raise TypeError( f"Sequences must have matching type. {type1.__name__!r} " f"does not match {type(seq2).__name__!r}." ) # Check if sequences have the expected type. _check_seqtype(name, type1, seqtype) # Check if sequences have the same length. This is for metrics that take # aligned sequences. if equal: if (L1 := len(seq1)) != len(seq2): raise ValueError( f"{name!r} can only be calculated between equal-length " f"sequences. {L1} != {len(seq2)}." ) # Return a NaN if sequences are empty. if L1 == 0: return float("nan") # Get valid characters. valid = _char_hash(alphabet, type1) # Calculate character frequencies if needed. if has_freqs: if (freqs := kwargs.get("freqs")) is None: kwargs["freqs"] = _char_freqs((seq1._bytes, seq2._bytes), valid) else: kwargs["freqs"] = _check_freqs(freqs) # Filter sequences to valid characters. if valid is not None: if equal: pos = valid[seq1._bytes] & valid[seq2._bytes] seq1, seq2 = seq1[pos], seq2[pos] if len(seq1) == 0: return float("nan") else: seq1, seq2 = seq1[valid[seq1._bytes]], seq2[valid[seq2._bytes]] # Call function to calculate sequence distance. return func(seq1, seq2, *args, **kwargs) # Transfer parameters to function attributes. wrapper._is_metric = True wrapper._seqtype = seqtype wrapper._equal = equal wrapper._alphabet = alphabet wrapper._has_freqs = has_freqs wrapper._has_gamma = "gamma" in signature(func).parameters return wrapper return decorator def _check_seqtype(name, this, valid=None): """Check if the input sequences have the expected sequence type. Parameters ---------- name : str Name of the metric. this : type Type of the current sequence. valid : type or tuple of type, optional Valid sequence type(s). Raises ------ TypeError If sequence type is incompatible with the given metric. """ if valid is None or issubclass(this, valid): return if isinstance(valid, tuple): types = tuple(x.__name__ for x in valid) else: types = valid.__name__ raise TypeError( f"{name!r} is compatible with {types!r} sequences, not {this.__name__!r}." ) def _check_gamma(gamma): """Check if the gamma distribution shape parameter is a positive number. Parameters ---------- gamma : float or int Shape parameter of gamma distribution. Raises ------ ValueError If gamma is not positive. """ if gamma is not None and not gamma > 0.0: raise ValueError("Parameter 'gamma' must be a positive number.") def _char_hash(alphabet, seqtype): """Get a hash table of valid characters for sequence filtering. Parameters ---------- alphabet : str, 1D array_like, {'nongap', 'definite', 'canonical'}, or None An alphabet of valid characters to be considered by the metric. seqtype : type Sequence type, which stores grammar information. Returns ------- ndarray of bool of shape (128,) Boolean mask of ASCII codes of valid characters (True). """ if alphabet is None: return elif alphabet in ("nongap", "definite", "canonical"): return getattr(seqtype, f"_{alphabet}_hash") else: encoded = _encode_alphabet(alphabet) valid = np.zeros((seqtype._num_ascii_codes,), dtype=bool) valid[encoded] = True return valid # Mappings of canonical characters to indices _char_indices = {} def _char_index(seqtype): """Get a mapping of characters to indices. It generates a vector in which indices are ASCII codes and values are indices within the alphabet. Only canonical characters are included in the indices. Other characters are masked with k (k is the number of canonical characters). For example, DNA will have: A: 0, C: 1, G: 2, T: 3, others: 4. Parameters ---------- seqtype : type Sequence type. Must be a subclass of `GrammaredSequence`, which defines canonical grammar information. Returns ------- nchar : int Number of canonical characters. index : ndarray of int of shape (128,) Mapping of characters (ASCII codes) to indices. """ if seqtype not in _char_indices: chars = seqtype._canonical_codes nchar = chars.size index = np.full(seqtype._num_ascii_codes, nchar, dtype=int) index[chars] = np.arange(nchar) _char_indices[seqtype] = (nchar, index) return _char_indices[seqtype] # A special index for nucleotide sequences. This index is uint8 to save memory space. # A: 0, C: 1, G: 2, T and U: 3, others: 4 nucl_index: NDArray[np.uint8] = np.full(128, 4, dtype=np.uint8) nucl_index[[65, 67, 71, 84, 85]] = [0, 1, 2, 3, 3] def _char_freqs(seqs, valid=None): """Calculate relative frequencies of characters in sequences. Parameters ---------- seqs : array_like of int Input sequences as ASCII codes (0-127). valid : ndarray of bool of shape (128,), optional Boolean mask of valid ASCII codes (True). If omitted, all ASCII codes (n = 128) will be included in the result. Returns ------- ndarray of float of shape (n_alphabet,) Relative frequencies of characters. """ # This is an efficient way to count character frequencies. `ravel` makes a memory # view of the data without copying, unless needed. `bincount` counts frequencies of # all ASCII codes. Then only frequencies of valid characters will be returned. freqs = np.bincount(np.ravel(seqs), minlength=128) if valid is not None: chars = np.flatnonzero(valid) freqs = freqs[chars] total = np.sum(freqs) if total > 0: return freqs / total else: return np.full(freqs.size, np.nan) def _check_freqs(freqs, nonzero=False): """Validate character frequencies. Parameters ---------- freqs : array_like of float of shape (n_alphabet,) Relative frequencies of all characters in the alphabet. nonzero : bool, optional If True, frequencies must be non-zero (i.e., positive). Returns ------- ndarray of float of shape (n_alphabet,) Relative frequencies of characters. Raises ------ ValueError If sum of frequencies is not 1. ValueError If at least one frequency is negative (`nonzero=False`) or non-positive (`nonzero=True`). """ freqs = np.asarray(freqs) if nonzero: if not np.all(freqs > 0.0): raise ValueError("Character frequencies must all be positive.") else: if not np.all(freqs >= 0.0): raise ValueError("Character frequencies must all be non-negative.") if not np.isclose(np.sum(freqs), 1.0): raise ValueError("Character frequencies must sum to 1.0.") return freqs def _build_dm(func, seqs): """Construct a condensed distance matrix from pairwise distances.""" n = seqs.shape[0] n_1 = n - 1 dm = np.empty((n * n_1 // 2,)) start = 0 for i in range(n_1): end = start + n_1 - i func(seqs, i, dm[start:end]) start = end return dm def _nan_dm(seqs): """Construct a condensed distance matrix and fill it with NaN.""" return np.full(((n := seqs.shape[0]) * (n - 1) // 2,), np.nan) @_metric_specs(equal=True) def hamming(seq1, seq2, proportion=True): r"""Compute the Hamming distance between two sequences. The Hamming distance [1]_ between two equal-length sequences is the number of differing characters. It is often normalized to a proportion of the sequence length. Parameters ---------- seq1, seq2 : Sequence Sequences to compute the Hamming distance between. proportion : bool, optional If True (default), normalize to a proportion of the sequence length. .. versionadded:: 0.7.2 Returns ------- float Hamming distance between the two sequences. Raises ------ TypeError If the sequences are not ``Sequence`` instances. TypeError If the sequences are not the same type. ValueError If the sequences are not the same length. See Also -------- pdist scipy.spatial.distance.hamming Notes ----- This function does not make assumptions about the sequence alphabet in use. All characters of each sequence, including gaps and ambiguous codes, are used to compute Hamming distance. Characters that may be considered equivalent in certain contexts (e.g., "-" and "." as gap characters) are treated as distinct characters when computing Hamming distance. If this behavior is not desired, consider using :func:`pdist` instead. NaN will be returned if the sequences do not contain any characters. References ---------- .. [1] Hamming, R. W. (1950). Error detecting and error correcting codes. The Bell system technical journal, 29(2), 147-160. Examples -------- >>> from skbio.sequence import Sequence >>> from skbio.sequence.distance import hamming >>> seq1 = Sequence('AGGGTA') >>> seq2 = Sequence('CGTTTA') >>> hamming(seq1, seq2) 0.5 """ return _hamming( np.vstack((seq1._bytes, seq2._bytes)), None, None, proportion=proportion ).item() def _hamming(seqs, mask, seqtype, proportion=True): """Compute pairwise Hamming distances between sequences. Parameters ---------- seqs : ndarray of uint8 of shape (n_sequences, n_positions) Sequences to compute the Hamming distance between. mask : ndarray of bool of shape (n_sequences, n_positions) A placeholder. Hamming distance always consider all characters. seqtype : type A placeholder. Hamming distance is irrelevant to sequence type. proportion : bool, optional If True (default), normalize to a proportion of the sequence length. Returns ------- ndarray of float of shape (C(n_sequences, 2),) Hamming distance matrix in condensed form. """ # When `proportion=True`, the result is equivalent to SciPy's `pdist(seqs, # metric="hamming")`. npos = seqs.shape[1] def func(seqs, i, out): subs = seqs[i] != seqs[i + 1 :] p = np.count_nonzero(subs, axis=1) # normalize by sequence length if proportion: np.divide(p, npos, out=out) else: out[:] = p return _build_dm(func, seqs) @_metric_specs(equal=True, seqtype=GrammaredSequence, alphabet="canonical") def pdist(seq1, seq2): r"""Calculate the *p*-distance between two aligned sequences. .. versionadded:: 0.7.2 *p*-distance is the proportion of differing sites between two aligned sequences. It is equivalent to the normalized Hamming distance, but only considers definite characters (i.e., leaving out gaps and degenerate characters). .. math:: p = \frac{\text{No. of differing sites}}{\text{Total no. of sites}} Parameters ---------- seq1, seq2 : GrammaredSequence Sequences to compute the *p*-distance between. Returns ------- float *p*-distance between the two sequences. Raises ------ See ``hamming``. See Also -------- hamming jc69 Notes ----- *p*-distance is the simplest measurement of the evolutionary distance (number of substitutions per site) between two sequences. It is also referred to as the *raw distance*. *p*-distance effectively estimates the evolutionary distance between two closely related sequences, where the number of observed substitutions is small. However, it may underestimate the true evolutionary distance when the two sequences are divergent and substitutions became saturated. This limitation may be overcome by adopting metrics that correct for multiple putative substitutions per site (such as JC69) and other biases. This function should not be confused with the :func:`~scipy.spatial.distance.pdist` function of SciPy. Examples -------- >>> from skbio.sequence import DNA >>> from skbio.sequence.distance import pdist >>> seq1 = DNA('AGGGTA') >>> seq2 = DNA('CGTTTA') >>> pdist(seq1, seq2) 0.5 """ seqs = np.vstack((seq1._bytes, seq2._bytes)) return _pdist(seqs, None, None).item() def _pdist(seqs, mask, seqtype): """Compute pairwise p-distances between sequences. Parameters ---------- seqs : ndarray of uint8 of shape (n_sequences, n_positions) Input sequences. mask : ndarray of bool of shape (n_sequences, n_positions) Boolean mask of valid sites. seqtype : type A placeholder. Returns ------- ndarray of float of shape (C(n_sequences, 2),) p-distance matrix. """ npos = seqs.shape[1] def func1(seqs, i, out): # identify differing sites (substitutions) subs = seqs[i] != seqs[i + 1 :] # count substitutions (`count_nonzero` is faster than sum) p = np.count_nonzero(subs, axis=1) # normalize by sequence length np.divide(p, npos, out=out) def func2(seqs, i, out): subs = seqs[i] != seqs[i + 1 :] # delete sites where either or both characters are invalid sites = mask[i] & mask[i + 1 :] subs &= sites # calculate sequence lengths after pairwise deletion L = np.count_nonzero(sites, axis=1) out[:] = np.count_nonzero(subs, axis=1) # avoid zero division when sequences are empty out[L == 0] = np.nan out /= L func = func1 if mask is None else func2 return _build_dm(func, seqs) @_metric_specs(equal=True, seqtype=(DNA, RNA), alphabet="canonical") def jc69(seq1, seq2, gamma=None): r"""Calculate the JC69 distance between two aligned nucleotide sequences. .. versionadded:: 0.7.2 The Jukes-Cantor 1969 (JC69) model estimates the evolutionary distance (number of substitutions per site) between two nucleotide sequences by correcting the observed proportion of differing sites (i.e., *p*-distance) to account for multiple putative substitutions at the same site (i.e., saturation). It is calculated as: .. math:: D = -\frac{3}{4} ln(1 - \frac{4}{3} p) The JC69 model can be corrected for site-rate heterogeneity by assuming that evolutionary rates follow a gamma distribution: .. math:: D = \frac{3}{4}\alpha \left[\left(1 - \frac{4}{3} p\right)^{-\frac{1}{\alpha}} - 1\right] Where :math:`\alpha > 0` is the shape parameter of the gamma distribution. Parameters ---------- seq1, seq2 : {DNA, RNA} Sequences to compute the JC69 distance between. gamma : float, optional Shape parameter (:math:`\alpha`) of the gamma distribution for among-site rate heterogeneity. Must be a positive number. If not provided, no gamma correction will be applied. .. versionadded:: 0.7.3 Returns ------- float JC69 distance between the two sequences. See Also -------- pdist f81 Notes ----- The Jukes-Cantor 1969 (JC69) model was originally described in [1]_ and its gamma correction in [2]_. JC69 is a basic evolutionary model for nucleotide sequences. It assumes equal base frequencies and equal substitution rates between bases. It models sequence evolution as a continuous-time Markov chain, and corrects the observed distance (*p*-distance) for repeated substitutions to estimate the true distance. This function returns NaN if :math:`p \geq 0.75`. This happens when the two sequences are too divergent and substitutions are over-saturated for reliable estimation of the evolutionary distance. References ---------- .. [1] Jukes, T. H., & Cantor, C. R. (1969). Evolution of protein molecules. Mammalian Protein Metabolism, 3(21), 132. .. [2] Golding, G. B. (1983). Estimates of DNA and protein sequence divergence: an examination of some assumptions. Molecular Biology and Evolution, 1(1), 125-142. """ _check_gamma(gamma) return _jc69(np.vstack((seq1._bytes, seq2._bytes)), None, None, gamma).item() def _jc69(seqs, mask, seqtype, gamma=None): """Compute pairwise JC69 distances between sequences. Parameters ---------- seqs : ndarray of uint8 of shape (n_sequences, n_positions) Input sequences. mask : ndarray of bool of shape (n_sequences, n_positions) Boolean mask of valid sites. seqtype : type A placeholder. gamma : float, optional Gamma distribution shape parameter (alpha). Returns ------- ndarray of float of shape (C(n_sequences, 2),) JC69 distance matrix. """ dm = _pdist(seqs, mask, None) if gamma is None: _p_correct(dm, 0.75) else: _p_gamma_correct(dm, 0.75, gamma) return dm def jc69_correct(dists, chars=4, inplace=False): r"""Perform Jukes-Cantor (JC69) correction of a raw distance. .. versionadded:: 0.7.2 The Jukes-Cantor 1969 (JC69) model estimates the evolutionary distance (number of substitutions per site) between two sequences by correcting the observed proportion of differing sites (*p*-distance) to account for multiple putative substitutions at the same site (i.e., saturation). The distance is calculated as: .. math:: D = -\alpha ln(1 - \frac{p}{\alpha}) Where :math:`\alpha = \frac{n - 1}{n}`, in which :math:`n` is the number of characters in the alphabet. Parameters ---------- dists : float or array_like Uncorrected normalized Hamming distances (a.k.a., *p*-distance) between pairs of sequences. chars : int, optional Number of definite characters in the alphabet. Default is 4, which is for nucleotide sequences ("A", "C", "G" and "T/U"). inplace : bool, optional If True and ``dists`` is an array, perform correction in place. Otherwise, create a copy of the data. Default is False. Returns ------- float or ndarray JC69-corrected distances. Raises ------ ValueError If ``chars`` is less than 2. See Also -------- pdist Notes ----- JC69 is the most basic evolutionary model, assuming equal character frequencies and equal substitution rates between characters. The JC69 model was developed for nucleotide sequences (4 characters, therefore :math:`\alpha = 0.75`). Technically, it is possible to apply JC69 correction on protein sequences, with ``chars=20``. However, this estimation may be inaccurate due to the profound variation of amino acid frequencies and substitution rates. This function returns NaN if :math:`p \geq \alpha`. This happens when the two sequences are too divergent and substitutions are over-saturated for reliable estimation of the true evolutionary distance. This function assumes that ``dists`` are valid *p*-distances within the range of [0, 1]. No validation will be performed. Input values outside this range will result in unexpected outputs. References ---------- .. [1] Jukes, T. H., & Cantor, C. R. (1969). Evolution of protein molecules. Mammalian protein metabolism, 3(21), 132. Examples -------- >>> from skbio.sequence import DNA >>> from skbio.sequence.distance import hamming, jc69_correct >>> seq1 = DNA('AGGGTA') >>> seq2 = DNA('CGTTTA') >>> p_dist = hamming(seq1, seq2) >>> p_dist 0.5 >>> jc69_dist = jc69_correct(p_dist) >>> jc69_dist # doctest: +ELLIPSIS 0.823959... """ # NOTE: This function is currently not exposed in the public API. Whether the JC69 # model and its name are suitable for generic sequence types needs justification. if chars < 2: raise ValueError("`chars` must be at least 2.") frac = (chars - 1) / chars is_scalar = np.isscalar(dists) if inplace and isinstance(dists, np.ndarray): arr = dists else: arr = np.array(dists, copy=True) _p_correct(arr, frac) if is_scalar: return arr.item() return arr def _p_correct(dists, coef): """Correct p-distances in place to account for multiple substitutions. Parameters ---------- dists : ndarray of float Raw p-distances to correct. coef : float Correction coefficient. """ # There are three categories of values: # 1. Values exceeding frac become NaN, as these sites are saturated and the # equation cannot estimate the true substitution number. # 2. Values == 0 remain 0. # 3. Values that suffice 0 < x < frac are subject to the equation. dists[dists >= coef] = np.nan dists /= -coef dists += 1.0 np.log(dists, out=dists) dists *= -coef dists += 0.0 # optional: set -0.0 to 0.0 def _p_gamma_correct(dists, coef, gamma): """Correct p-distances in place to account for multiple substitutions and also do gamma-correction. Parameters ---------- dists : ndarray of float Raw p-distances to correct. coef : float Correction coefficient. gamma : float Gamma distribution shape parameter (alpha). """ dists[dists >= coef] = np.nan dists /= -coef dists += 1.0 np.power(dists, -1 / gamma, out=dists) dists -= 1.0 dists *= coef * gamma dists += 0.0 # optional: set -0.0 to 0.0 @_metric_specs(equal=True, seqtype=(DNA, RNA), alphabet="canonical") def f81(seq1, seq2, freqs=None, gamma=None): r"""Calculate the F81 distance between two aligned nucleotide sequences. .. versionadded:: 0.7.2 The Felsenstein 1981 (F81) model assumes equal substitution rates and allows differential base frequencies (:math:`\pi`). The distance is calculated as: .. math:: D = -b\, ln(1 - \frac{p}{b}) Where :math:`p` is the proportion of differing sites (i.e., *p*-distance). Factor :math:`b` is calculated as: .. math:: b = 1 - \pi_A^2 - \pi_C^2 - \pi_G^2 - \pi_T^2 The F81 model can be corrected for site-rate heterogeneity by assuming that evolutionary rates follow a gamma distribution: .. math:: D = b\, \alpha \left[\left(1 - \frac{p}{b}\right)^{-\frac{1}{\alpha}} - 1\right] Where :math:`\alpha > 0` is the shape parameter of the gamma distribution. Parameters ---------- seq1, seq2 : {DNA, RNA} Sequences to compute the F81 distance between. freqs : array_like of float of shape (4,), optional Relative frequencies of nucleobases A, C, G, and T/U, respectively. Should sum to 1. If not provided, the observed frequencies from the two input sequences combined will be used. gamma : float, optional Shape parameter (:math:`\alpha`) of the gamma distribution for among-site rate heterogeneity. Must be a positive number. If not provided, no gamma correction will be applied. .. versionadded:: 0.7.3 Returns ------- float F81 distance between the two sequences. See Also -------- jc69 Notes ----- The Felsenstein 1981 (F81) model was described in [1]_ in the context of maximum likelihood estimation. The above equation for F81 distance calculation was adopted from [2]_, which is consistent with the implementation in ``ape::dist.dna``. The same equation was also described in [3]_ under the equal-input model. F81 is an extension of the JC69 model by allowing varying base frequencies. When the observed or user-provided based frequencies are equal (e.g., by specifying ``freqs=(.25, .25, .25, .25)``), the result will be identical to that of JC69. This function returns NaN if :math:`p \geq b`. References ---------- .. [1] Felsenstein, J. (1981). Evolutionary trees from DNA sequences: a maximum likelihood approach. Journal of Molecular Evolution, 17(6), 368-376. .. [2] McGuire, G., Prentice, M. J., & Wright, F. (1999). Improved error bounds for genetic distances from DNA sequences. Biometrics, 55(4), 1064-1070. .. [3] Tajima, F., & Nei, M. (1984). Estimation of evolutionary distance between nucleotide sequences. Molecular Biology and Evolution, 1(3), 269-285. """ seqs = np.vstack((seq1._bytes, seq2._bytes)) _check_gamma(gamma) return _f81(seqs, None, type(seq1), freqs=freqs, gamma=gamma).item() def _f81(seqs, mask, seqtype, freqs, gamma=None): """Compute pairwise F81 distances between sequences. Parameters ---------- seqs : ndarray of uint8 of shape (n_sequences, n_positions) Input sequences. mask : ndarray of bool of shape (n_sequences, n_positions) Boolean mask of valid sites. seqtype : type A placeholder. freqs : ndarray of float of shape (4,) Relative frequencies of the four nucleobases. gamma : float, optional Gamma distribution shape parameter (alpha). Returns ------- ndarray of float of shape (C(n_sequences, 2),) F81 distance matrix. """ coef = 1.0 - np.sum(np.asarray(freqs) ** 2) arr = _pdist(seqs, mask, None) if gamma is None: _p_correct(arr, coef) else: _p_gamma_correct(arr, coef, gamma) return arr @_metric_specs(equal=True, seqtype=(DNA, RNA), alphabet="canonical") def k2p(seq1, seq2, gamma=None): r"""Calculate the K2P distance between two aligned nucleotide sequences. .. versionadded:: 0.7.2 The Kimura 2-parameter (K2P, a.k.a. K80) model allows differential rates of transitions (substitutions between two purines or between two pyrimidines) versus transversions (substitutions between a purine and a pyrimidine), while assuming equal base frequencies. The distance is calculated as: .. math:: D = -\frac{1}{2} ln\left((1 - 2P - Q) \sqrt{1 - 2Q}\right) Where :math:`P` and :math:`Q` are the proportions of transitions and transversions, respectively. The K2P model can be corrected for site-rate heterogeneity by assuming that evolutionary rates follow a gamma distribution: .. math:: D = \frac{\alpha}{2} \left[\left(1 - 2P - Q\right)^{-\frac{1}{\alpha}} + \frac{1}{2}\left(1 - 2Q\right)^{-\frac{1}{\alpha}} - \frac{3}{2}\right] Where :math:`\alpha > 0` is the shape parameter of the gamma distribution. Parameters ---------- seq1, seq2 : {DNA, RNA} Sequences to compute the K2P distance between. gamma : float, optional Shape parameter (:math:`\alpha`) of the gamma distribution for among-site rate heterogeneity. Must be a positive number. If not provided, no gamma correction will be applied. .. versionadded:: 0.7.3 Returns ------- float K2P distance between the two sequences. See Also -------- jc69 f84 Notes ----- The Kimura 2-parameter model (K2P or K80) was originally described in [1]_ and its gamma correction in [2]_. K2P is an extension of the JC69 model by modeling differential transition and transversion rates. Meanwhile, K2P can be considered as a special case of the F84 model by assuming equal base frequencies. This function returns NaN if either :math:`1 - 2P - Q` or :math:`1 - 2Q` is zero or negative, which implicates over-saturation of substitutions. References ---------- .. [1] Kimura, M. (1980). A simple method for estimating evolutionary rates of base substitutions through comparative studies of nucleotide sequences. Journal of Molecular Evolution, 16(2), 111-120. .. [2] Jin, L., & Nei, M. (1990). Limitations of the evolutionary parsimony method of phylogenetic analysis. Molecular biology and evolution, 7(1), 82-102. """ seqs = np.vstack((seq1._bytes, seq2._bytes)) _check_gamma(gamma) return _k2p(seqs, None, type(seq1), gamma).item() def _k2p(seqs, mask, seqtype, gamma=None): """Compute pairwise K2P distances between sequences. Parameters ---------- seqs : ndarray of uint8 of shape (n_sequences, n_positions) Input sequences. mask : ndarray of bool of shape (n_sequences, n_positions) Boolean mask of valid sites. seqtype : type Sequence type (DNA or RNA). gamma : float, optional Gamma distribution shape parameter (alpha). Returns ------- ndarray of float of shape (C(n_sequences, 2),) K2P distance matrix. """ npos = float(seqs.shape[1]) masked = mask is not None # convert sequences to integers 0-4, which will facilitate bitwise operations. seqs = nucl_index[seqs] def func(seqs, i, out): # identify transitions (ts) and tranversions (tv) via bitwise operations subs = seqs[i] ^ seqs[i + 1 :] ts = subs == 2 tv = subs & 1 # pairwise deletion of invalid sites followed by length re-calculation if masked: sites = mask[i] & mask[i + 1 :] L = np.count_nonzero(sites, axis=1).astype(float) # set empty sequences to NaN to avoid zero division L[L == 0] = np.nan # filter transversions (transitions are not affected) tv &= sites else: L = npos # counts of transitions (P) and tranversions (Q) P = np.count_nonzero(ts, axis=1) / L Q = np.count_nonzero(tv, axis=1) / L # calculate arguments and set non-positive values (over-saturated # substitutions) to NaN to skip logarithm a1 = 1.0 - 2.0 * P - Q a1[a1 <= 0] = np.nan a2 = 1.0 - 2.0 * Q a2[a2 <= 0] = np.nan if gamma is None: # the formula (Eq. 10 of Kimura, 1980) out[:] = -0.5 * np.log(a1) - 0.25 * np.log(a2) else: gamma_inv = -1 / gamma out[:] = 0.5 * gamma * (a1**gamma_inv + 0.5 * a2**gamma_inv - 1.5) dm = _build_dm(func, seqs) dm += 0.0 # optional: set -0.0 to 0.0 return dm @_metric_specs(equal=True, seqtype=(DNA, RNA), alphabet="canonical") def f84(seq1, seq2, freqs=None): r"""Calculate the F84 distance between two aligned nucleotide sequences. .. versionadded:: 0.7.2 The Felsenstein 1984 (F84) model allows differential rates of transitions and transversions, and differential base frequencies (:math:`\pi`). The distance is calculated as: .. math:: D = -2Aln(1 - \frac{1}{2A}P - \frac{A-B}{2AC}Q) + 2(A-B-C)ln(1-\frac{1}{2C}Q) Where :math:`P` and :math:`Q` are the proportions of transitions and transversions, respectively. And: .. math:: \begin{aligned} &A = \frac{\pi_A\pi_G}{\pi_A+\pi_G} + \frac{\pi_C\pi_T}{\pi_C+\pi_T} \\ &B = \pi_A\pi_G + \pi_C\pi_T \\ &C = (\pi_A+\pi_G)(\pi_C+\pi_T) \end{aligned} Parameters ---------- seq1, seq2 : {DNA, RNA} Sequences to compute the F84 distance between. freqs : array_like of float of shape (4,), optional Relative frequencies of nucleobases A, C, G, and T/U, respectively. Should sum to 1. If not provided, the observed frequencies from the two input sequences combined will be used. Returns ------- float F84 distance between the two sequences. See Also -------- k2p tn93 Notes ----- The Felsenstein 1984 (F84) model for calculating sequence distance was initially implemented in the PHYLIP package [1]_. The model was then described in [2]_ and [3]_. The above equation was adopted from [4]_, which is consistent with the implementation in ``ape::dist.dna``. F84 is an extension of the K2P model that allows unequal base frequencies. When the observed or user-provided based frequencies are equal (e.g., by specifying ``freqs=(.25, .25, .25, .25)``), the result will be identical to that of K2P. F84 may be considered as a special case of the TN93 model where purine and pyrimidine transition rates are equal. This function returns NaN if either of the two logarithm arguments is zero or negative. References ---------- .. [1] https://phylipweb.github.io/phylip/doc/dnadist.html .. [2] Kishino, H., & Hasegawa, M. (1989). Evaluation of the maximum likelihood estimate of the evolutionary tree topologies from DNA sequence data, and the branching order in Hominoidea. Journal of molecular evolution, 29(2), 170-179. .. [3] Felsenstein, J., & Churchill, G. A. (1996). A Hidden Markov Model approach to variation among sites in rate of evolution. Molecular Biology and Evolution, 13(1), 93-104. .. [4] McGuire, G., Prentice, M. J., & Wright, F. (1999). Improved error bounds for genetic distances from DNA sequences. Biometrics, 55(4), 1064-1070. """ seqs = np.vstack((seq1._bytes, seq2._bytes)) return _f84(seqs, None, type(seq1), freqs=freqs).item() def _f84(seqs, mask, seqtype, freqs): """Compute pairwise F84 distances between sequences. Parameters ---------- seqs : ndarray of uint8 of shape (n_sequences, n_positions) Input sequences. mask : ndarray of bool of shape (n_sequences, n_positions) Boolean mask of valid sites. seqtype : type Sequence type (DNA or RNA). freqs : ndarray of float of shape (4,) Relative frequencies of the four nucleobases. Returns ------- ndarray of float of shape (C(n_sequences, 2),) F84 distance matrix. """ npos = float(seqs.shape[1]) masked = mask is not None seqs = nucl_index[seqs] # base frequencies piA, piC, piG, piT = freqs piR, piY = piA + piG, piC + piT if not (piR > 0 and piY > 0): return _nan_dm(seqs) piAxG, piCxT = piA * piG, piC * piT # intermediates (Eq. 2 of McGuire et al., 1999) A = piAxG / piR + piCxT / piY B = piAxG + piCxT C = piR * piY # coefficients c1 = -2.0 * A c2 = -2.0 * (B + C) - c1 A2inv = 0.5 / A C2inv = 0.5 / C AmB2AxC = 2.0 * (A - B) * A2inv * C2inv def func(seqs, i, out): subs = seqs[i] ^ seqs[i + 1 :] ts = subs == 2 tv = subs & 1 if masked: sites = mask[i] & mask[i + 1 :] L = np.count_nonzero(sites, axis=1).astype(float) L[L == 0] = np.nan tv &= sites else: L = npos P = np.count_nonzero(ts, axis=1) / L Q = np.count_nonzero(tv, axis=1) / L # arguments a1 = 1.0 - A2inv * P - AmB2AxC * Q a1[a1 <= 0] = np.nan a2 = 1.0 - C2inv * Q a2[a2 <= 0] = np.nan # the formula (Eq. 3 of McGuire et al., 1999) out[:] = c1 * np.log(a1) + c2 * np.log(a2) dm = _build_dm(func, seqs) dm += 0.0 return dm @_metric_specs(equal=True, seqtype=(DNA, RNA), alphabet="canonical") def tn93(seq1, seq2, freqs=None, gamma=None): r"""Calculate the TN93 distance between two aligned nucleotide sequences. .. versionadded:: 0.7.2 The Tamura and Nei 1993 (TN93) model assumes differential rates of the two types of transitions: between purines (R) (i.e., A <-> G) and between pyrimidines (Y) (i.e., C <-> T/U), and transversions (i.e., between a purine and a pyrimidine). It also allows varying base frequencies (:math:`\pi`). The distance is calculated as: .. math:: D = -2A\, ln\left(1-\frac{P_1}{2A}-\frac{Q}{2\pi_R}\right) -2B\, ln\left(1-\frac{P_2}{2B}-\frac{Q}{2\pi_Y}\right) -2C\, ln\left(1-\frac{Q}{2\pi_R\pi_Y}\right) Where :math:`P_1` and :math:`P_2` are the proportions of purine and pyrimidine transitions, respectively. :math:`Q` is the proportion of transversions. And: .. math:: \begin{aligned} &A = \frac{\pi_A\pi_G}{\pi_R} \\ &B = \frac{\pi_C\pi_T}{\pi_Y} \\ &C = \pi_R\pi_Y - A\pi_Y - B\pi_R \end{aligned} The TN93 model can be corrected for site-rate heterogeneity by assuming that evolutionary rates follow a gamma distribution: .. math:: \begin{aligned} D = 2\alpha\Bigg[ &A\left(1-\frac{P_1}{2A}-\frac{Q}{2\pi_R}\right)^{-\frac{1}{\alpha}} +B\left(1-\frac{P_2}{2B}-\frac{Q}{2\pi_Y}\right)^{-\frac{1}{\alpha}} \\ &\quad +\; C\left(1-\frac{Q}{2\pi_R\pi_Y}\right)^{-\frac{1}{\alpha}} - E\Bigg] \end{aligned} Where :math:`\alpha > 0` is the shape parameter of the gamma distribution. And: .. math:: E = \pi_A\pi_G + \pi_T\pi_C + \pi_R\pi_Y Parameters ---------- seq1, seq2 : {DNA, RNA} Sequences to compute the TN93 distance between. freqs : array_like of float of shape (4,), optional Relative frequencies of nucleobases A, C, G, and T/U, respectively. Should sum to 1. If not provided, the observed frequencies from the two input sequences combined will be used. gamma : float, optional Shape parameter (:math:`\alpha`) of the gamma distribution for among-site rate heterogeneity. Must be a positive number. If not provided, no gamma correction will be applied. .. versionadded:: 0.7.3 Returns ------- float TN93 distance between the two sequences. See Also -------- k2p f84 Notes ----- The Tamura and Nei 1993 (TN93) model was originally described in [1]_ alongside with its gamma correction formula. This function returns NaN if any of the three logarithm arguments is zero or negative, which implicates over-saturation of substitutions. References ---------- .. [1] Tamura, K., & Nei, M. (1993). Estimation of the number of nucleotide substitutions in the control region of mitochondrial DNA in humans and chimpanzees. Molecular Biology and Evolution, 10(3), 512-526. """ seqs = np.vstack((seq1._bytes, seq2._bytes)) _check_gamma(gamma) return _tn93(seqs, None, type(seq1), freqs=freqs, gamma=gamma).item() def _tn93(seqs, mask, seqtype, freqs, gamma=None): """Compute pairwise TN93 distances between sequences. Parameters ---------- seqs : ndarray of uint8 of shape (n_sequences, n_positions) Input sequences. mask : ndarray of bool of shape (n_sequences, n_positions) Boolean mask of valid sites. seqtype : type Sequence type (DNA or RNA). freqs : ndarray of float of shape (4,) Relative frequencies of the four nucleobases. gamma : float, optional Gamma distribution shape parameter (alpha). Returns ------- ndarray of float of shape (C(n_sequences, 2),) TN93 distance matrix. """ npos = float(seqs.shape[1]) masked = mask is not None seqs = nucl_index[seqs] piA, piC, piG, piT = freqs if not np.all(freqs > 0): return _nan_dm(seqs) # frequencies of purines (R) and pyrimidines (Y) piR = piA + piG piY = piC + piT piAxG = 2.0 * piA * piG piCxT = 2.0 * piC * piT piRxY = 2.0 * piR * piY piR_AxG = piR / piAxG piY_CxT = piY / piCxT # coefficients c1 = -piAxG / piR c2 = -piCxT / piY c3 = piY / piR_AxG + piR / piY_CxT - piRxY c4 = piAxG + piCxT + piRxY piR *= 2.0 piY *= 2.0 # pre-calcuate a bit mask of purine (0) vs pyrimidine (1) bit0 = seqs & 1 def func(seqs, i, out): subs = seqs[i] ^ seqs[i + 1 :] ts = subs == 2 tv = subs & 1 # separate purine transitions (ts1) and pyrimidine transitions (ts2) ts2 = ts & bit0[i] if masked: sites = mask[i] & mask[i + 1 :] L = np.count_nonzero(sites, axis=1).astype(float) L[L == 0] = np.nan tv &= sites else: L = npos P = np.count_nonzero(ts, axis=1) / L Q = np.count_nonzero(tv, axis=1) / L P2 = np.count_nonzero(ts2, axis=1) / L P1 = P - P2 # arguments a1 = 1.0 - P1 * piR_AxG - Q / piR a1[a1 <= 0] = np.nan a2 = 1.0 - P2 * piY_CxT - Q / piY a2[a2 <= 0] = np.nan a3 = 1.0 - Q / piRxY a3[a3 <= 0] = np.nan if gamma is None: # the formula (Eq. 3 of Tamura & Nei, 1993) out[:] = c1 * np.log(a1) + c2 * np.log(a2) + c3 * np.log(a3) else: gamma_inv = -1 / gamma out[:] = -gamma * ( c1 * a1**gamma_inv + c2 * a2**gamma_inv + c3 * a3**gamma_inv + c4 ) dm = _build_dm(func, seqs) dm += 0.0 return dm @_metric_specs(equal=True, seqtype=GrammaredSequence, alphabet="canonical") def logdet(seq1, seq2, pseudocount=None): r"""Calculate the LogDet distance between two aligned sequences. .. versionadded:: 0.7.2 The LogDet (meaning "logarithm of determinant") estimator of evolutionary distance is robust to compositional biases and nonstationary (i.e., changing over time) character frequencies. The distance is calculated as: .. math:: D = -\frac{1}{k}\ln \det\mathbf{J} - \ln k Where :math:`\mathbf{J}` is a :math:`k \times k` matrix of proportions of character pairs between the two sequences. :math:`k` is the number of canonical characters in the alphabet of the specific sequence type (e.g., 4 for nucleotide and 20 for protein). Parameters ---------- seq1, seq2 : GrammaredSequence Sequences to compute the LogDet distance between. pseudocount : float, optional A small positive value added to the count of each character pair to avoid logarithm of zero. Default is None. Returns ------- float LogDet distance between the two sequences. See Also -------- paralin Notes ----- The LogDet transformation was originally described in [1]_. The above equation of LogDet distance was adopted from [2]_, which is consistent with the implementation in ``ape::dist.dna``. Although the LogDet distance is mostly used for analyzing nucleotide sequences (*k* = 4), this function is applicable to any grammared sequences with an arbitrarily sized alphabet, in accordance with the original paper [1]_. However, a large alphabet (e.g., protein sequences, with *k* = 20) often results in a sparse *J* matrix, due to unobserved character pairs in the sequences. Consequently, the LogDet distance will be NaN. This can be mitigated by specifying a pseudocount (e.g., 0.5) to regularize the matrix. Additionally, the LogDet distance tends to over-estimate the evolutionary distance when the character frequencies are highly unequal. Consider using the paralinear distance (:func:`paralin`) instead in that case. See also [3]_ for a discussion and a modified LogDet distance to account for unequal character frequencies. The LogDet distance between two identical sequences is 0 only when the character frequencies are equal, which is rarely the case in real data. However, when constructing a LogDet distance matrix from a multiple sequence alignment using the :func:`~skbio.alignment.align_dists` function, the resulting ``DistanceMatrix`` object forces the diagonal (distance from each sequence to itself) to be 0. Be cautious of this when self-distance is involved in the subsequent analysis. The function returns NaN when the determinant is 0 or negative. References ---------- .. [1] Lockhart, P. J., Steel, M. A., Hendy, M. D., & Penny, D. (1994). Recovering evolutionary trees under a more realistic model of sequence evolution. Molecular Biology and Evolution, 11(4), 605-612. .. [2] Gu, X., & Li, W. H. (1996). Bias-corrected paralinear and LogDet distances and tests of molecular clocks and phylogenies under nonstationary nucleotide frequencies. Molecular Biology and Evolution, 13(10), 1375-1383. .. [3] Tamura, K., & Kumar, S. (2002). Evolutionary distance estimation under heterogeneous substitution pattern among lineages. Molecular Biology and Evolution, 19(10), 1727-1736. """ seqs = np.vstack((seq1._bytes, seq2._bytes)) return _logdet(seqs, None, type(seq1), pseudocount).item() def _logdet(seqs, mask, seqtype, pseudocount=None): """Compute pairwise LogDet distances between sequences.""" return _logpara(seqs, mask, seqtype, pseudocount, paralinear=False) @_metric_specs(equal=True, seqtype=GrammaredSequence, alphabet="canonical") def paralin(seq1, seq2, pseudocount=None): r"""Calculate paralinear distance between two aligned sequences. .. versionadded:: 0.7.2 The paralinear distance between two sequences is calculated as: .. math:: D = -\frac{1}{k}\ln\frac{\det\mathbf{J}} {\sqrt{\det\mathbf{D}_1\det\mathbf{D}_2}} Where :math:`\mathbf{J}` is a matrix of proportions of character pairs between the two sequences. :math:`\mathbf{D}_1` and :math:`\mathbf{D}_1` are diagonal matrices of the proportions of characters within each of the two sequences. The matrices are :math:`k \times k`, in which :math:`k` is the size of the alphabet. This function considers only canonical characters in the alphabet of the specific sequence type (e.g., *k* = 4 for nucleotide and *k* = 20 for protein). Because :math:`\det\mathbf{D} = \prod_{x \in A}\pi_x`, where :math:`\pi_x` is the proportion of character :math:`x` in alphabet :math:`A`, the above equation can be simplified as: .. math:: D = -\frac{1}{k}\ln\det\mathbf{J} + \frac{1}{2k}\sum_{x \in A, i \in \{1, 2\}}\ln \pi_{x,i} Parameters ---------- seq1, seq2 : GrammaredSequence Sequences to compute the paralinear distance between. pseudocount : float, optional A small positive value added to the count of each character or character pair to avoid logarithm of zero. Default is None. Returns ------- float Paralinear distance between the two sequences. See Also -------- logdet Notes ----- The paralinear distance between biological sequences was originally described in [1]_. The above equation of paralinear distance was adopted from [2]_, which is consistent with the implementation in ``ape::dist.dna``. Although the paralinear distance is mostly used for analyzing nucleotide sequences (*k* = 4), this function is applicable to any grammared sequences with an alphabet of any size. However, sequences with a large alphabet (e.g., protein sequences, with *k* = 20) often result in a paralinear distance of NaN, due to unobserved characters or character pairs. This can be mitigated by adding a pseudocount (e.g., 0.5) to regularize the matrices. The paralinear distance is fundamentally similar to LogDet (:func:`logdet`). Although developed separately, the paralinear distance may be considered as an extension of LogDet that considers varying character frequencies. When the character frequencies are equal within each of the two sequences, the paralinear distance should be identical to the LogDet distance. Unlike LogDet, the paralinear distance between two identical sequences, with equal or unequal character frequencies, is zero. .. note:: The LogDet distance computed by PHYLIP's `dnadist` command is actually consistent with the paralinear distance implemented here. The function returns NaN when any of the determinants is 0 or negative. References ---------- .. [1] Lake, J. A. (1994). Reconstructing evolutionary trees from DNA and protein sequences: paralinear distances. Proceedings of the National Academy of Sciences, 91(4), 1455-1459. .. [2] Gu, X., & Li, W. H. (1996). Bias-corrected paralinear and LogDet distances and tests of molecular clocks and phylogenies under nonstationary nucleotide frequencies. Molecular Biology and Evolution, 13(10), 1375-1383. """ seqs = np.vstack((seq1._bytes, seq2._bytes)) return _paralin(seqs, None, type(seq1), pseudocount).item() def _paralin(seqs, mask, seqtype, pseudocount=None): """Compute pairwise paralinear distances between sequences.""" return _logpara(seqs, mask, seqtype, pseudocount, paralinear=True) def _logpara(seqs, mask, seqtype, pseudocount=None, paralinear=False): """Compute pairwise LogDet or paralinear distances between sequences. Parameters ---------- seqs : ndarray of uint8 of shape (n_sequences, n_positions) Input sequences. mask : ndarray of bool of shape (n_sequences, n_positions) Boolean mask of valid sites. pseudocount : int or float, optional Pseudocount to added to counts. paralinear : bool, optional Calculate LogDet (False, default) or paralinear distance (True). Returns ------- ndarray of float of shape (C(n_sequences, 2),) LogDet or paralinear distance matrix. """ # NOTE: ape::dist.dna's "paralin" might have an inconsistency in the pairwise # deletion mode, where it retrieves base frequencies from the original sequences # rather than the trimmed ones. This inconsistency can be revealed by running # both complete and pairwise deletion modes on an alignment of two sequences only. # The current implementation addresses this issue. Therefore, the output won't be # identical to ape::dist.dna's. nchar, index = _char_index(seqtype) seqs = index[seqs] masked = mask is not None n = seqs.shape[0] n_1 = n - 1 # number of valid characters + others (see below) k = nchar + masked k2_inv = 0.5 / nchar c1 = -1.0 / nchar part0 = -np.log(nchar) # an offset added to sequence 2's to facilitate bincount (see below) offvec = np.arange(n).reshape(-1, 1) # Paralinear only: Calculate the logdets of diagonal matrices (i.e., character # frequencies) of individual sequences: ln(det(F)) = ln(prod(f)) = sum(ln(f)). # Available for complete deletion only. For pairwise deletion, we need to # calculate this for each pair of sequences. if paralinear and not masked: seqs_off = seqs + offvec * k freqs = np.bincount(seqs_off.ravel(), minlength=n * k).reshape(-1, k) freqs = freqs.astype(float) if pseudocount: freqs += pseudocount * k # Exclude sequences with any of the canonical character(s) missing (e.g., a # DNA sequence without "T"), as they will result in logarithm of zero. else: freqs[freqs == 0] = np.nan freqs /= freqs.sum(axis=1, keepdims=True) diags = np.sum(np.log(freqs), axis=1) offvec *= k**2 def func(seqs, i, out): # number of sequence pairs m = n_1 - i # The following code computes the count matrix between all sequence pairs. # `np.bincount` is highly efficient for counting, but it only operates on a 1D # array. To overcome this, two tricks are applied: # 1) For each pair of sequences (i vs j), compute i * k + j, do bincount, then # reshape to (k, k), which is the count matrix. # 2) For all pairs of sequences (i vs J), offset J by k^2 each, flatten, do # bincount, reshape to (-1, ...), which returns the counts of each sequence # pair. # The outcome is a 3D array of shape (m, k, k). pairs = seqs[i] * k + seqs[i + 1 :] + offvec[:m] mat = np.bincount(pairs.ravel(), minlength=offvec[m, 0]).reshape(-1, k, k) # In pairwise deletion mode, all characters other than the canonical ones are # given the same and maximum code, which will be trimmed off from the count # matrix. # Complete deletion mode does not need this as all characters are canonical, # which saves some compute (25 -> 16 for nucleotide sequences). if masked: mat = mat[:, :nchar, :nchar] mat = mat.astype(float) if pseudocount: mat += pseudocount total = mat.sum(axis=(1, 2), keepdims=True) # drop empty sequences # Note that if a pseudocount is added, empty sequences become non-empty. has_empty = False if masked and not pseudocount: filled = (total > 0).ravel() if has_empty := not np.all(filled): mat, total = mat[filled], total[filled] # convert counts to proportions mat /= total # `np.logabsdet` is more stable than `det` -> `log`. sign, logabsdet = np.linalg.slogdet(mat) # The determinant should be positive (sign = 1). Otherwise result is NaN. logabsdet[sign != 1.0] = np.nan # LogDet distance uses a constant if not paralinear: c0 = part0 # Paralinear with complete deletion: use pre-calculated diagonals. elif not masked: c0 = k2_inv * (diags[i] + diags[i + 1 :]) # For pairwise deletion, calculate diagonals on the current sequence pair: # Take the frequency matrix, sum rows to get the character frequencies of # sequence 1; sum columns to get those of sequence 2. else: freq12 = np.concat((np.sum(mat, axis=1), np.sum(mat, axis=2)), axis=1) freq12[freq12 == 0] = np.nan c0 = k2_inv * np.sum(np.log(freq12), axis=1) # The formula (Eq. 2 of Gu & Li, 1996) res = c0 + c1 * logabsdet if has_empty: out[filled] = res out[~filled] = np.nan else: out[:] = res return _build_dm(func, seqs) @_metric_specs() def kmer_distance(seq1, seq2, k, overlap=True): r"""Compute the *k*-mer distance between a pair of sequences. The *k*-mer distance between two sequences is the fraction of *k*-mer that are unique to either sequence. Parameters ---------- seq1, seq2 : Sequence Sequences to compute *k*-mer distance between. k : int The *k*-mer length. overlap : bool, optional Defines whether the *k*-mers should be overlapping or not. Returns ------- float *k*-mer distance between the two sequences. Raises ------ ValueError If ``k`` is less than 1. TypeError If the sequences are not ``Sequence`` instances. TypeError If the sequences are not the same type. Notes ----- *k*-mers counts are not incorporated in this distance metric. ``np.nan`` will be returned if there are no kmers defined for the sequences. Examples -------- >>> from skbio.sequence import Sequence >>> seq1 = Sequence('ATCGGCGAT') >>> seq2 = Sequence('GCAGATGTG') >>> kmer_distance(seq1, seq2, 3) # doctest: +ELLIPSIS 0.9230769230... """ seq1_kmers = set(map(str, seq1.iter_kmers(k, overlap=overlap))) seq2_kmers = set(map(str, seq2.iter_kmers(k, overlap=overlap))) all_kmers = seq1_kmers | seq2_kmers if not all_kmers: return np.nan shared_kmers = seq1_kmers & seq2_kmers number_unique = len(all_kmers) - len(shared_kmers) fraction_unique = number_unique / len(all_kmers) return fraction_unique scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/000077500000000000000000000000001520735541300224345ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/__init__.py000066400000000000000000000005411520735541300245450ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/test_alphabet.py000066400000000000000000000254611520735541300256350ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt from skbio.sequence._alphabet import ( _encode_alphabet, _alphabet_to_hashes, _indices_in_alphabet, _indices_in_alphabet_ascii, _indices_in_observed) class TestAlphabet(TestCase): def test_encode_alphabet(self): # ascii characters alpha = 'ACGT' exp = np.array([65, 67, 71, 84], dtype=np.uint8) npt.assert_array_equal(_encode_alphabet(alpha), exp) npt.assert_array_equal(_encode_alphabet(list(alpha)), exp) npt.assert_array_equal(_encode_alphabet(tuple(alpha)), exp) npt.assert_array_equal(_encode_alphabet(np.array(list(alpha))), exp) npt.assert_array_equal(_encode_alphabet(np.char.encode(list(alpha))), exp) # ascii code points codes = list(map(ord, alpha)) npt.assert_array_equal(_encode_alphabet(codes), exp) npt.assert_array_equal(_encode_alphabet(np.array(codes)), exp) npt.assert_array_equal(_encode_alphabet(np.array(codes).astype(np.uint8)), exp) # 2d array alpha = np.array([[65, 67], [71, 84]], dtype=np.uint8) obs = _encode_alphabet(alpha) npt.assert_array_equal(obs, alpha) # wrong data types with self.assertRaises(TypeError): _encode_alphabet(123) with self.assertRaises(TypeError): _encode_alphabet(set(alpha)) with self.assertRaises(TypeError): _encode_alphabet([1.0, 1.5, 2.0]) # with self.assertRaises(TypeError): # _encode_alphabet([['a', 'b'], ['c', 'd']]) # not single characters with self.assertRaises(ValueError): _encode_alphabet(['this', 'is', 'not']) # exceed ascii range with self.assertRaises(ValueError): _encode_alphabet([100, 200, 300]) with self.assertRaises(UnicodeEncodeError): _encode_alphabet(chr(1234) + chr(5678)) with self.assertRaises(UnicodeEncodeError): _encode_alphabet([chr(1234), chr(5678)]) def test_alphabet_to_hashes(self): alpha = 'ATGCSWRYKMBVHDN' obs = _alphabet_to_hashes(alpha) exp = np.array([ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 10, 3, 13, -1, -1, 2, 12, -1, -1, 8, -1, 9, 14, -1, -1, -1, 6, 4, 1, -1, 11, 5, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], dtype=np.intp) npt.assert_array_equal(obs, exp) def test_indices_in_alphabet(self): seq = 'GAGCTCA' # DNA sequence without degenerate characters alpha = 'ACGTN' # DNA alphabet exp = np.array([2, 0, 2, 1, 3, 1, 0]) # indices of characters # either alphabet or sequence may be string, list/tuple, or iterator npt.assert_array_equal(_indices_in_alphabet(seq, alpha), exp) npt.assert_array_equal(_indices_in_alphabet(list(seq), list(alpha)), exp) npt.assert_array_equal(_indices_in_alphabet(iter(seq), iter(alpha)), exp) # alphabet is a dictionary of character : index (most performant) npt.assert_array_equal(_indices_in_alphabet(seq, dict(zip(alpha, range(len( alpha))))), exp) # one character is absent from alphabet seq = 'GAGRCTCA' msg = 'One or more characters in the sequence are absent from the alphabet.' with self.assertRaisesRegex(ValueError, msg): _indices_in_alphabet(seq, alpha) # replace absent character with wildcard obs = _indices_in_alphabet(seq, alpha, wildcard='N') exp = np.array([2, 0, 2, 4, 1, 3, 1, 0]) npt.assert_array_equal(obs, exp) # wildcard not in alphabet msg = 'Wildcard character "X" is not in the alphabet.' with self.assertRaisesRegex(ValueError, msg): _indices_in_alphabet(seq, alpha, wildcard='X') # amino acid seq = 'MEEPQSDPSV' alpha = 'ARNDCQEGHILKMFPSTWYVBZX' exp = np.array([12, 6, 6, 14, 5, 15, 3, 14, 15, 19]) npt.assert_array_equal(_indices_in_alphabet(seq, alpha), exp) # natural language seq = 'The quick brown fox jumps over the lazy dog'.split() alpha = ['dog', 'fox', 'jumps', 'the'] obs = _indices_in_alphabet(seq, alpha, wildcard='the') exp = np.array([3, 3, 3, 1, 2, 3, 3, 3, 0]) npt.assert_array_equal(obs, exp) # empty sequence self.assertEqual(_indices_in_alphabet('', alpha).size, 0) # sequence with gaps alpha = 'ACGTN' seq = 'GAG--TCA' gaps = [0, 0, 0, 1, 1, 0, 0, 0] obs = _indices_in_alphabet(seq, alpha, gaps=gaps) exp = np.array([2, 0, 2, -1, -1, 3, 1, 0]) npt.assert_array_equal(obs, exp) # sequence with gaps and degenerate code seq = 'GRG--YCA' gaps = [0, 0, 0, 1, 1, 0, 0, 0] obs = _indices_in_alphabet(seq, alpha, wildcard='N', gaps=gaps) exp = np.array([2, 4, 2, -1, -1, 4, 1, 0]) npt.assert_array_equal(obs, exp) def test_indices_in_alphabet_ascii(self): # convert a sequence into a vector of code points seq = 'GAGCTCA' seq = np.frombuffer(seq.encode('ascii'), dtype=np.uint8) # convert an alphabet into a vector of indices alpha = 'ACGTN' idx = np.frombuffer(alpha.encode('ascii'), dtype=np.uint8) alpha = np.full(128, -1, dtype=np.intp) alpha[idx] = np.arange(idx.size) # a typical case obs = _indices_in_alphabet_ascii(seq, alpha) exp = np.array([2, 0, 2, 1, 3, 1, 0]) npt.assert_array_equal(obs, exp) self.assertIs(obs.dtype.type, np.intp) # one character is absent seq = np.insert(seq, 3, ord('R')) msg = 'One or more characters in the sequence are absent from the alphabet.' with self.assertRaisesRegex(ValueError, msg): _indices_in_alphabet_ascii(seq, alpha) # replace absent character obs = _indices_in_alphabet_ascii(seq, alpha, wildcard=ord('N')) exp = np.array([2, 0, 2, 4, 1, 3, 1, 0]) npt.assert_array_equal(obs, exp) # wildcard not in alphabet msg = 'Wildcard character "&" is not in the alphabet.' with self.assertRaisesRegex(ValueError, msg): _indices_in_alphabet_ascii(seq, alpha, wildcard=38) # multiple sequences of the same length seqs = ('GAGCTCA', 'ACGGTAT', 'CCTTAGA') seqs = np.vstack([ np.frombuffer(x.encode('ascii'), dtype=np.uint8) for x in seqs]) obs = _indices_in_alphabet_ascii(seqs, alpha, wildcard=ord('N')) exp = np.array([[2, 0, 2, 1, 3, 1, 0], [0, 1, 2, 2, 3, 0, 3], [1, 1, 3, 3, 0, 2, 0]]) npt.assert_array_equal(obs, exp) # sequences with gaps (which become -1) seqs = ('GAG-TCA', 'A-G-TAT', 'CCTTA-A') seqs = np.vstack([ np.frombuffer(x.encode('ascii'), dtype=np.uint8) for x in seqs]) gaps = np.array([[0, 0, 0, 1, 0, 0, 1], [0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0]], dtype=bool) obs = _indices_in_alphabet_ascii(seqs, alpha, gaps=gaps) exp = np.array([[2, 0, 2, -1, 3, 1, 0], [0, -1, 2, -1, 3, 0, 3], [1, 1, 3, 3, 0, -1, 0]]) npt.assert_array_equal(obs, exp) # sequences with degenerate codes and gap positions (the former are casted into # 'N' but the later remain -1) seqs = ('RAG-TNA', 'A-G-TAT', 'CCYTA-A') seqs = np.vstack([ np.frombuffer(x.encode('ascii'), dtype=np.uint8) for x in seqs]) obs = _indices_in_alphabet_ascii(seqs, alpha, wildcard=ord('N'), gaps=gaps) exp = np.array([[4, 0, 2, -1, 3, 4, 0], [0, -1, 2, -1, 3, 0, 3], [1, 1, 4, 3, 0, -1, 0]]) npt.assert_array_equal(obs, exp) def test_indices_in_observed(self): # data from human TP53 protein (NP_000537.3) seqs = ('MEEPQSDPSVEPPLSQETFSDLWKLLPE', 'NNVLSPLPSQAMDDLMLSP', 'DDIEQWFTEDPGPDEAPRMPEAA') obs_idx, obs_alp = _indices_in_observed(seqs) exp_alp = np.array(tuple('ADEFGIKLMNPQRSTVW')) exp_idx = ( np.array([8, 2, 2, 10, 11, 13, 1, 10, 13, 15, 2, 10, 10, 7, 13, 11, 2, 14, 3, 13, 1, 7, 16, 6, 7, 7, 10, 2]), np.array([9, 9, 15, 7, 13, 10, 7, 10, 13, 11, 0, 8, 1, 1, 7, 8, 7, 13, 10]), np.array([1, 1, 5, 2, 11, 16, 3, 14, 2, 1, 10, 4, 10, 1, 2, 0, 10, 12, 8, 10, 2, 0, 0])) npt.assert_array_equal(obs_alp, exp_alp) for obs, exp in zip(obs_idx, exp_idx): npt.assert_array_equal(obs, exp) # reconstruct original sequences for idx, seq in zip(obs_idx, seqs): self.assertEqual(''.join(obs_alp[idx]), seq) # sequences are numbers seqs = ([1, 4, 6, 7, 8], [3, 3, 4, 1, 0], [5, 2, 5, 8, 0]) obs_idx, obs_alp = _indices_in_observed(seqs) npt.assert_array_equal(obs_alp, np.arange(9)) for idx, seq in zip(obs_idx, seqs): npt.assert_array_equal(obs_alp[idx], np.array(seq)) # sequences are natural language seqs = (['this', 'is', 'a', 'cat'], ['that', 'is', 'a', 'dog'], ['cat', 'is', 'not', 'dog']) obs_idx, obs_alp = _indices_in_observed(seqs) exp_alp = np.unique(np.concatenate(seqs)) npt.assert_array_equal(obs_alp, exp_alp) for idx, seq in zip(obs_idx, seqs): npt.assert_array_equal(obs_alp[idx], np.array(seq)) # sequences are individual characters obs_idx, obs_alp = _indices_in_observed(['hello']) npt.assert_array_equal(obs_alp, np.array(['e', 'h', 'l', 'o'])) self.assertEqual(''.join(obs_alp[np.concatenate(obs_idx)]), 'hello') # empty sequence obs_idx, obs_alp = _indices_in_observed([[]]) self.assertEqual(obs_alp.size, 0) self.assertEqual(len(obs_idx), 1) self.assertEqual(obs_idx[0].size, 0) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/test_distance.py000066400000000000000000001102101520735541300256320ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main from itertools import product import numpy as np import numpy.testing as npt from skbio.sequence import Sequence, GrammaredSequence, DNA, RNA, Protein from skbio.util import classproperty from skbio.util._decorator import overrides from skbio.sequence.distance import ( _metric_specs, _char_hash, _char_freqs, _check_freqs, hamming, pdist, kmer_distance, jc69, jc69_correct, f81, k2p, f84, tn93, logdet, paralin ) class TestMetricSpecs(TestCase): def test_is_metric(self): """Test if the wrapped function is marked as a metric.""" def metric1(seq1, seq2): return 1 self.assertFalse(hasattr(metric1, "_is_metric")) @_metric_specs() def metric2(seq1, seq2): return 1 self.assertTrue(hasattr(metric2, "_is_metric")) self.assertTrue(metric2._is_metric) def test_instance(self): """Test if input sequences are of matching Sequence objects.""" @_metric_specs() def metric1(seq1, seq2): return 1 seq1, seq2 = DNA("ACGT"), DNA("AGTC") self.assertEqual(metric1(seq1, seq2), 1) seq1, seq2 = Sequence("Hello"), Sequence("There") self.assertEqual(metric1(seq1, seq2), 1) seq1, seq2 = "Hello", "There" with self.assertRaises(TypeError) as cm: metric1(seq1, seq2) msg = "Sequences must be skbio.sequence.Sequence instances, not 'str'." self.assertEqual(str(cm.exception), msg) seq1, seq2 = DNA("ACGT"), Protein("MKVS") with self.assertRaises(TypeError) as cm: metric1(seq1, seq2) msg = "Sequences must have matching type. 'DNA' does not match 'Protein'." self.assertEqual(str(cm.exception), msg) def test_seqtype(self): """Test if input sequences are of expected sequence types.""" @_metric_specs(seqtype=Protein) def metric1(seq1, seq2): return 1 self.assertIs(metric1._seqtype, Protein) self.assertEqual(metric1(Protein("MVR"), Protein("TPD")), 1) with self.assertRaises(TypeError) as cm: metric1("GGC", "CAT") msg = "Sequences must be skbio.sequence.Sequence instances, not 'str'." self.assertEqual(str(cm.exception), msg) with self.assertRaises(TypeError) as cm: metric1(Protein("MVR"), DNA("CAT")) msg = "Sequences must have matching type. 'Protein' does not match 'DNA'." self.assertEqual(str(cm.exception), msg) with self.assertRaises(TypeError) as cm: metric1(DNA("GGC"), DNA("CAT")) msg = "'metric1' is compatible with 'Protein' sequences, not 'DNA'." self.assertEqual(str(cm.exception), msg) @_metric_specs(seqtype=(DNA, RNA)) def metric2(seq1, seq2): return 1 self.assertTupleEqual(metric2._seqtype, (DNA, RNA)) self.assertEqual(metric2(RNA("AUCG"), RNA("UAAC")), 1) with self.assertRaises(TypeError) as cm: metric2(Protein("MVR"), Protein("TPD")) msg = "'metric2' is compatible with ('DNA', 'RNA') sequences, not 'Protein'." self.assertEqual(str(cm.exception), msg) @_metric_specs(seqtype=GrammaredSequence) def metric3(seq1, seq2): return 1 class CustomSequence(GrammaredSequence): @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set('^$') @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return '^' @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set('WXYZ') @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return {} self.assertEqual(metric3(DNA("GGC"), DNA("CAT")), 1) self.assertEqual(metric3(RNA("AUCG"), RNA("UAAC")), 1) self.assertEqual(metric3(Protein("MVR"), Protein("TPD")), 1) self.assertEqual(metric3(CustomSequence("XXY"), CustomSequence("WWZ")), 1) with self.assertRaises(TypeError) as cm: metric3(Sequence("hello"), Sequence("there")) msg = ("'metric3' is compatible with 'GrammaredSequence' sequences, not " "'Sequence'.") self.assertEqual(str(cm.exception), msg) def test_char_hash(self): """Hash table of valid characters.""" # Note: A more intuitive test of this function is in skbio.alignment.distance. # DNA sequence obs = _char_hash(None, DNA) self.assertIsNone(obs) obs = _char_hash("ACGT", DNA) exp = np.zeros(128, dtype=bool) exp[[65, 67, 71, 84]] = True npt.assert_array_equal(obs, exp) obs = _char_hash("definite", DNA) npt.assert_array_equal(obs, exp) obs = _char_hash("canonical", DNA) npt.assert_array_equal(obs, exp) obs = _char_hash("ACGTN", DNA) exp[78] = True npt.assert_array_equal(obs, exp) obs = _char_hash("nongap", DNA) exp[sorted(map(ord, DNA.degenerate_chars))] = True npt.assert_array_equal(obs, exp) # RNA sequence obs = _char_hash("definite", RNA) exp = np.zeros(128, dtype=bool) exp[[65, 67, 71, 85]] = True npt.assert_array_equal(obs, exp) # protein sequence obs = _char_hash("definite", Protein) exp = np.zeros(128, dtype=bool) exp[sorted(map(ord, Protein.definite_chars))] = True npt.assert_array_equal(obs, exp) obs = _char_hash("canonical", Protein) exp[sorted(map(ord, Protein.noncanonical_chars))] = False npt.assert_array_equal(obs, exp) obs = _char_hash("ABCD", Protein) exp = np.zeros(128, dtype=bool) exp[65:69] = True npt.assert_array_equal(obs, exp) def test_char_freqs(self): # DNA characters valid = _char_hash("definite", DNA) # one 1D array seq1 = DNA("CGATCATCTA") obs = _char_freqs(seq1._bytes, valid) exp = np.array([.3, .3, .1, .3]) npt.assert_array_equal(obs, exp) # two 1D arrays seq2 = DNA("CTGGCACCGA") obs = _char_freqs((seq1._bytes, seq2._bytes), valid) exp = np.array([.25, .35, .2, .2]) npt.assert_array_equal(obs, exp) # 2D array seqs = np.vstack((seq1._bytes, seq2._bytes)) obs = _char_freqs(seqs, valid) exp = np.array([.25, .35, .2, .2]) npt.assert_array_equal(obs, exp) # all ASCII codes obs = _char_freqs(seqs) self.assertTupleEqual(obs.shape, (128,)) self.assertEqual(obs[65], .25) self.assertEqual(obs[67], .35) self.assertEqual(obs[71], .2) self.assertEqual(obs[84], .2) # with gaps seq3 = DNA("CGATC---ATCTA") obs = _char_freqs(seq3._bytes, valid) exp = np.array([.3, .3, .1, .3]) npt.assert_array_equal(obs, exp) # RNA characters valid = _char_hash("definite", RNA) seq4 = RNA("CGAUCAUCUA") obs = _char_freqs(seq4._bytes, valid) exp = np.array([.3, .3, .1, .3]) npt.assert_array_equal(obs, exp) # empty sequence seq5 = RNA("") obs = _char_freqs(seq5._bytes, valid) exp = np.full(4, np.nan) npt.assert_array_equal(obs, exp) def test_check_freqs(self): """Valudate character frequencies.""" obs = _check_freqs([0.1, 0.2, 0.3, 0.4]) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.array([0.1, 0.2, 0.3, 0.4])) with self.assertRaises(ValueError) as cm: _check_freqs([0.2, 0.3, 0.5, 0.8]) msg = "Character frequencies must sum to 1.0." self.assertEqual(str(cm.exception), msg) with self.assertRaises(ValueError) as cm: _check_freqs([-0.5, 0.3, 0.5, 0.7]) msg = "Character frequencies must all be non-negative." self.assertEqual(str(cm.exception), msg) obs = _check_freqs([0.0, 0.3, 0.7]) self.assertIsInstance(obs, np.ndarray) with self.assertRaises(ValueError) as cm: _check_freqs([0.0, 0.3, 0.7], nonzero=True) msg = "Character frequencies must all be positive." self.assertEqual(str(cm.exception), msg) def test_equal(self): """Test if input sequences are of equal length.""" seq1, seq2 = DNA("ACGT"), DNA("GATGC") @_metric_specs() def metric1(seq1, seq2): return 1.0 self.assertFalse(metric1._equal) self.assertEqual(metric1(seq1, seq2), 1) @_metric_specs(equal=True) def metric2(seq1, seq2): return 1.0 self.assertTrue(metric2._equal) with self.assertRaises(ValueError) as cm: metric2(seq1, seq2) msg = ("'metric2' can only be calculated between equal-length sequences. " "4 != 5.") self.assertEqual(str(cm.exception), msg) # empty sequences obs = metric2(DNA(""), DNA("")) self.assertTrue(np.isnan(obs)) @_metric_specs(equal=True, alphabet="nongap") def metric3(seq1, seq2): return 1.0 # empty sequences after trimming obs = metric3(DNA("AAA---"), DNA("---TTT")) self.assertTrue(np.isnan(obs)) def test_alphabet(self): """Filter input sequences by a given alphabet.""" seq1, seq2 = Sequence("X.,123Y"), Sequence("?'ZmYY0") @_metric_specs() def metric1(seq1, seq2): return len(seq1) * len(seq2) self.assertIsNone(metric1._alphabet) self.assertEqual(metric1(seq1, seq2), 49) @_metric_specs(alphabet="XYZ") def metric2(seq1, seq2): return len(seq1) * len(seq2) self.assertEqual(metric2._alphabet, "XYZ") self.assertEqual(metric2(seq1, seq2), 6) # DNA sequences with gaps and degenerate characters ("N" and "R") seq1, seq2 = DNA("ACCR--GT"), DNA("A-CGCANT") @_metric_specs(seqtype=(DNA, RNA), alphabet="nongap") def metric3(seq1, seq2): return len(seq1) * len(seq2) self.assertEqual(metric3(seq1, seq2), 42) @_metric_specs(seqtype=(DNA, RNA), equal=True, alphabet="nongap") def metric4(seq1, seq2): return len(seq1) * len(seq2) self.assertEqual(metric4(seq1, seq2), 25) @_metric_specs(seqtype=(DNA, RNA), equal=True, alphabet="definite") def metric5(seq1, seq2): return len(seq1) * len(seq2) self.assertEqual(metric5(seq1, seq2), 9) # protein sequences with degenerate ("X") and non-canonical characters ("O") seq1, seq2 = Protein("MNXSQ"), Protein("MKPWO") @_metric_specs(seqtype=Protein, equal=True, alphabet="definite") def metric6(seq1, seq2): return len(seq1) * len(seq2) self.assertEqual(metric6(seq1, seq2), 16) @_metric_specs(seqtype=Protein, equal=True, alphabet="canonical") def metric7(seq1, seq2): return len(seq1) * len(seq2) self.assertEqual(metric7(seq1, seq2), 9) # alphabet only works with grammared sequence @_metric_specs(alphabet="nongap") def metric8(seq1, seq2): return len(seq1) * len(seq2) self.assertRaises(AttributeError, metric8, Sequence("X"), Sequence("Y")) class TestHamming(TestCase): def test_length_mismatch(self): seq1 = Sequence('ABC') seq2 = Sequence('ABCD') with self.assertRaisesRegex(ValueError, "equal-length sequences. 3 != 4."): hamming(seq1, seq2) def test_return_type(self): seq1 = Sequence('ABC') seq2 = Sequence('ABC') obs = hamming(seq1, seq2) self.assertIsInstance(obs, float) self.assertEqual(obs, 0.0) def test_minimum_distance(self): seq1 = Sequence('ABC') seq2 = Sequence('ABC') obs = hamming(seq1, seq2) self.assertEqual(obs, 0.0) def test_mid_range_distance(self): seq1 = Sequence("abcdefgh") seq2 = Sequence("1b23ef45") obs = hamming(seq1, seq2) self.assertEqual(obs, 5.0/8.0) def test_maximum_distance(self): seq1 = Sequence('ABC') seq2 = Sequence('CAB') obs = hamming(seq1, seq2) self.assertEqual(obs, 1.0) def test_empty_sequences(self): seq1 = Sequence('') seq2 = Sequence('') obs = hamming(seq1, seq2) self.assertTrue(np.isnan(obs)) def test_single_characters(self): seq1 = Sequence('a') seq2 = Sequence('b') self.assertEqual(hamming(seq1, seq1), 0.0) self.assertEqual(hamming(seq1, seq2), 1.0) def test_sequence_subclass(self): seq1 = DNA('ACG-T') seq2 = DNA('ACCTT') obs = hamming(seq1, seq2) self.assertEqual(obs, 2.0/5.0) def test_sequences_with_metadata(self): # test for #1254 seqs1 = [ Sequence("ACGT"), Sequence("ACGT", metadata={'id': 'abc'}), Sequence("ACGT", positional_metadata={'qual': range(4)}) ] seqs2 = [ Sequence("AAAA"), Sequence("AAAA", metadata={'id': 'def'}), Sequence("AAAA", positional_metadata={'qual': range(4, 8)}) ] for seqs in seqs1, seqs2: for seq1, seq2 in product(seqs, repeat=2): obs = hamming(seq1, seq2) self.assertEqual(obs, 0.0) for seq1, seq2 in product(seqs1, seqs2): obs = hamming(seq1, seq2) self.assertEqual(obs, 0.75) def test_raw_count(self): seq1 = DNA("AAGTC") seq2 = DNA("ACGAC") obs = hamming(seq1, seq2) self.assertEqual(obs, 0.4) obs = hamming(seq1, seq2, proportion=False) self.assertIsInstance(obs, float) self.assertEqual(obs, 2.0) class TestPDist(TestCase): def test_pdist(self): # sequences of canonical characters seq1 = DNA("AGATC") seq2 = DNA("AGATG") self.assertEqual(pdist(seq1, seq2), 0.2) seq1 = RNA("AUCG") seq2 = RNA("UACG") self.assertEqual(pdist(seq1, seq2), 0.5) seq1 = Protein("RCKMAF") seq2 = Protein("SCPTAA") self.assertAlmostEqual(pdist(seq1, seq2), 2 / 3) # sequences with gaps seq1 = DNA("A--ACGG") seq2 = DNA("AGAAT-G") self.assertEqual(pdist(seq1, seq2), 0.25) seq1 = Protein("-PYCRNG") seq2 = Protein("MPYAKC-") self.assertEqual(pdist(seq1, seq2), 0.6) # sequences with degenerate characters seq1 = DNA("ANGCRT") seq2 = DNA("CCSMTT") self.assertEqual(pdist(seq1, seq2), 0.5) seq1 = Protein("NBMKK") seq2 = Protein("HEMYX") self.assertAlmostEqual(pdist(seq1, seq2), 2 / 3) # sequences with non-canonical characters seq1 = Protein("NKOC") seq2 = Protein("UKPA") self.assertAlmostEqual(pdist(seq1, seq2), 0.5) # identical sequences seq1 = DNA("ACGT") seq2 = DNA("ACGT") self.assertEqual(pdist(seq1, seq2), 0.0) # distinct sequences seq1 = DNA("ACGT") seq2 = DNA("TGCA") self.assertEqual(pdist(seq1, seq2), 1.0) # single-character sequences seq1 = RNA("U") seq2 = RNA("G") self.assertEqual(pdist(seq1, seq2), 1.0) seq1 = Protein("MGCPS") seq2 = Protein("XXXXX") self.assertTrue(np.isnan(pdist(seq1, seq2))) # non-grammared sequences seq1 = Sequence("AGCNT") seq2 = Sequence("CG-AT") with self.assertRaises(TypeError): pdist(seq1, seq2) class TestKmerDistance(TestCase): def test_default_kwargs(self): seq1 = Sequence('AACCTAGCAATGGAT') seq2 = Sequence('CAGGCAGTTCTCACC') obs = kmer_distance(seq1, seq2, 3) exp = 0.9130434782608695 self.assertAlmostEqual(obs, exp) def test_nondefault_k(self): seq1 = Sequence('GCTTATGGAGAGAGA') seq2 = Sequence('CTCGAACTCCAGCCA') obs = kmer_distance(seq1, seq2, 2) exp = 0.7333333333333333 self.assertAlmostEqual(obs, exp) seq1 = Sequence('EADDECAEECDEACD') seq2 = Sequence('DCBCBADADABCCDA') obs = kmer_distance(seq1, seq2, 1) exp = 0.4 self.assertAlmostEqual(obs, exp) def test_overlap_false(self): seq1 = Sequence('CGTTATGTCTGTGAT') seq2 = Sequence('CTGAATCGGTAGTGT') obs = kmer_distance(seq1, seq2, 3, overlap=False) exp = 0.8888888888888888 self.assertAlmostEqual(obs, exp) def test_entirely_different_sequences(self): seq1 = Sequence('CCGTGGTCGTATAAG') seq2 = Sequence('CGCCTTCCACATCAG') obs = kmer_distance(seq1, seq2, 3) exp = 1.0 self.assertEqual(obs, exp) def test_same_sequence(self): seq1 = Sequence('CTGCGACAGTTGGTA') seq2 = Sequence('CTGCGACAGTTGGTA') obs = kmer_distance(seq1, seq2, 3) exp = 0.0 self.assertEqual(obs, exp) def test_differing_length_seqs(self): seq1 = Sequence('AGAAATCTGAGCAAGGATCA') seq2 = Sequence('TTAGTGCGTAATCCG') obs = kmer_distance(seq1, seq2, 3) exp = 0.9285714285714286 self.assertAlmostEqual(obs, exp) def test_with_sequence_subclass(self): seq1 = DNA('GATGGTACTGTAGGT') seq2 = DNA('AGGGTGAAGGTATCA') obs = kmer_distance(seq1, seq2, 3) exp = 0.8421052631578947 self.assertAlmostEqual(obs, exp) def test_with_metadata_sanity(self): seq1 = Sequence('AACCTAGCAATGGAT', metadata={'Name': 'Kestrel Gorlick'}, positional_metadata={'seq': list('ACTCAAGCTACGAAG')}) seq2 = Sequence('CAGGCAGTTCTCACC') obs = kmer_distance(seq1, seq2, 3) exp = 0.9130434782608695 self.assertAlmostEqual(obs, exp) def test_return_type(self): seq1 = Sequence('ATCG') seq2 = Sequence('ATCG') obs = kmer_distance(seq1, seq2, 3) self.assertIsInstance(obs, float) self.assertEqual(obs, 0.0) def test_empty_sequences(self): seq1 = Sequence('') seq2 = Sequence('') obs = kmer_distance(seq1, seq2, 3) self.assertTrue(np.isnan(obs)) def test_one_empty_sequence(self): seq1 = Sequence('') seq2 = Sequence('CGGGCAGCTCCTACCTGCTA') obs = kmer_distance(seq1, seq2, 3) exp = 1.0 self.assertAlmostEqual(obs, exp) def test_no_kmers_found(self): seq1 = Sequence('ATCG') seq2 = Sequence('ACGT') obs = kmer_distance(seq1, seq2, 5) self.assertTrue(np.isnan(obs)) def test_k_less_than_one_error(self): seq1 = Sequence('ATCG') seq2 = Sequence('ACTG') with self.assertRaisesRegex(ValueError, r'k must be greater than 0.'): kmer_distance(seq1, seq2, 0) class TestJC69(TestCase): def test_jc69(self): # normal case seq1 = DNA("AGATC") seq2 = DNA("AGATG") obs = jc69(seq1, seq2) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.23262) obs = jc69(seq1, seq2, gamma=2.0) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.25162) # RNA sequences seq1, seq2 = RNA("AUCG"), RNA("UACG") self.assertEqual(round(jc69(seq1, seq2), 5), 0.82396) self.assertEqual(round(jc69(seq1, seq2, gamma=2.0), 5), 1.09808) # sequences with gaps seq1, seq2 = DNA("A--ACGG"), DNA("AGAAT-G") self.assertEqual(round(jc69(seq1, seq2), 5), 0.30410) self.assertEqual(round(jc69(seq1, seq2, gamma=2.0), 5), 0.33712) # sequences with degenerate characters seq1, seq2 = DNA("ANGCRT"), DNA("CCSMTT") self.assertEqual(round(jc69(seq1, seq2), 5), 0.82396) self.assertEqual(round(jc69(seq1, seq2, gamma=2.0), 5), 1.09808) # identical sequences seq1, seq2 = DNA("ACGT"), DNA("ACGT") self.assertEqual(jc69(seq1, seq2), 0.0) self.assertEqual(jc69(seq1, seq2, gamma=2.0), 0.0) # distinct sequences seq1, seq2 = DNA("ACGT"), DNA("TGCA") self.assertTrue(np.isnan(jc69(seq1, seq2))) self.assertTrue(np.isnan(jc69(seq1, seq2, gamma=2.0))) # highly divergent sequences (p = 0.7) seq1, seq2 = DNA("ACGAGCTCCT"), DNA("GCTTGAGTCA") self.assertEqual(round(jc69(seq1, seq2), 5), 2.03104) self.assertEqual(round(jc69(seq1, seq2, gamma=2.0), 5), 4.30948) # overly divergent sequences (p = 0.8) seq1, seq2 = DNA("GACTA"), DNA("CTCAG") self.assertTrue(np.isnan(jc69(seq1, seq2))) self.assertTrue(np.isnan(jc69(seq1, seq2, gamma=2.0))) # protein sequences seq1, seq2 = Protein("-PYCRNG"), Protein("MPYAKC-") with self.assertRaises(TypeError): jc69(seq1, seq2) # non-grammared sequences seq1, seq2 = Sequence("AGCNT"), Sequence("CG-AT") with self.assertRaises(TypeError): jc69(seq1, seq2) seq1, seq2 = DNA("A--ACGG"), DNA("AGAAT-G") with self.assertRaises(ValueError): jc69(seq1, seq2, gamma=-1.0) with self.assertRaises(ValueError): jc69(seq1, seq2, gamma=0.0) def test_jc69_correct(self): # scalar input obs = jc69_correct(0.1) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.10733) self.assertEqual(round(jc69_correct(0.2), 5), 0.23262) self.assertEqual(round(jc69_correct(0.5), 5), 0.82396) self.assertEqual(round(jc69_correct(0.7), 5), 2.03104) self.assertEqual(jc69_correct(0.0), 0.0) self.assertTrue(np.isnan(jc69_correct(0.8))) # list input lst = [0.0, 0.1, 0.2, 0.5, 0.7, 1.0] obs = jc69_correct(lst) self.assertIsInstance(obs, np.ndarray) self.assertTupleEqual(obs.shape, (6,)) exp = np.array([0.0, 0.107, 0.233, 0.824, 2.031, np.nan]) npt.assert_array_equal(obs.round(3), exp) # inplace has no effect on non-array obs = jc69_correct(lst, inplace=True) npt.assert_array_equal(obs.round(3), exp) self.assertIsNot(obs, lst) # 1D array input arr = np.array(lst) obs = jc69_correct(arr, inplace=False) npt.assert_array_equal(obs.round(3), exp) self.assertIsNot(obs, arr) # modify array in-place obs = jc69_correct(arr, inplace=True) npt.assert_array_equal(obs.round(3), exp) self.assertIs(obs, arr) npt.assert_array_equal(arr.round(3), exp) # 2D array input shape = (2, 3) arr = np.reshape(lst, shape) obs = jc69_correct(arr) self.assertTupleEqual(obs.shape, shape) exp = np.reshape(exp, shape) npt.assert_array_equal(obs.round(3), exp) # alternative character count self.assertEqual(round(jc69_correct(0.5, chars=5), 3), 0.785) self.assertEqual(round(jc69_correct(0.8, chars=9), 3), 2.047) with self.assertRaisesRegex(ValueError, r"`chars` must be at least 2."): jc69_correct(0.5, chars=1) class TestF81(TestCase): def test_f81(self): # normal case seq1 = DNA("AT-ACGGCGA-C") seq2 = DNA("AGAAT--CAACC") obs = f81(seq1, seq2) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.53708) obs = f81(seq1, seq2, gamma=2.0) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.65464) # even base frequencies (equivalent to JC69) obs = f81(seq1, seq2, freqs=(.25, .25, .25, .25)) self.assertEqual(round(obs, 5), 0.51986) exp = jc69(seq1, seq2) self.assertAlmostEqual(obs, exp) obs = f81(seq1, seq2, freqs=(.25, .25, .25, .25), gamma=2.0) self.assertEqual(round(obs, 5), 0.62132) exp = jc69(seq1, seq2, gamma=2.0) self.assertAlmostEqual(obs, exp) # identical sequences after trimming self.assertEqual(f81(DNA("AACGTY"), DNA("WACGTT")), 0.0) self.assertEqual(f81(DNA("AACGTY"), DNA("WACGTT"), gamma=2.0), 0.0) # highly divergent sequences seq1, seq2 = DNA("ACGAGCTCCT"), DNA("GCTTGAGTCA") self.assertEqual(round(f81(seq1, seq2), 5), 2.09101) self.assertEqual(round(f81(seq1, seq2, gamma=2.0), 5), 4.57259) # overly divergent sequences seq1, seq2 = DNA("GACTA"), DNA("CTCAG") self.assertTrue(np.isnan(f81(seq1, seq2))) self.assertTrue(np.isnan(f81(seq1, seq2, gamma=2.0))) # RNA sequences seq1, seq2 = RNA("AUCU-CGGU"), RNA("AGGUUCA--") self.assertEqual(round(f81(seq1, seq2), 5), 0.83539) self.assertEqual(round(f81(seq1, seq2, gamma=2.0), 5), 1.1236) # non-nucleotide sequences with self.assertRaises(TypeError): f81(Protein("-PYCRNG"), Protein("MPYAKC-")) with self.assertRaises(TypeError): f81(Sequence("AGCNT"), Sequence("CG-AT")) seq1, seq2 = RNA("AUCU-CGGU"), RNA("AGGUUCA--") with self.assertRaises(ValueError): f81(seq1, seq2, gamma=-1.0) with self.assertRaises(ValueError): f81(seq1, seq2, gamma=0.0) class TestK2P(TestCase): def test_k2p(self): # normal case (8 sites, 2 transitions, 1 transversion) seq1 = DNA("AT-ACGGCGA-C") seq2 = DNA("AGAAT--CAACC") obs = k2p(seq1, seq2) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.56234) obs = k2p(seq1, seq2, gamma=2.0) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.71034) # identical sequences after trimming self.assertEqual(k2p(DNA("AACGTY"), DNA("WACGTT")), 0.0) # too many transversions (2Q > 1) seq1 = DNA("ACGTACGT") seq2 = DNA("AGCATATT") self.assertTrue(np.isnan(k2p(seq1, seq2))) self.assertTrue(np.isnan(k2p(seq1, seq2, gamma=2.0))) # too many transitions (2P + Q > 1) seq1 = DNA("ACGTATGT") seq2 = DNA("GTCTACAT") self.assertTrue(np.isnan(k2p(seq1, seq2))) self.assertTrue(np.isnan(k2p(seq1, seq2, gamma=2.0))) # RNA sequences seq1, seq2 = RNA("AUCU-CGGU"), RNA("AGGUUCA--") self.assertEqual(round(k2p(seq1, seq2), 5), 0.82396) self.assertEqual(round(k2p(seq1, seq2, gamma=2.0), 5), 1.09808) # non-nucleotide sequences with self.assertRaises(TypeError): k2p(Protein("-PYCRNG"), Protein("MPYAKC-")) with self.assertRaises(TypeError): k2p(Sequence("AGCNT"), Sequence("CG-AT")) seq1, seq2 = RNA("AUCU-CGGU"), RNA("AGGUUCA--") with self.assertRaises(ValueError): k2p(seq1, seq2, gamma=-1.0) with self.assertRaises(ValueError): k2p(seq1, seq2, gamma=0.0) class TestF84(TestCase): def test_f84(self): # normal case seq1 = DNA("AT-ACGGCGA-C") seq2 = DNA("AGAAT--CAACC") obs = f84(seq1, seq2) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.62024) # even base frequencies (equivalent to K2P) obs = f84(seq1, seq2, freqs=(.25, .25, .25, .25)) self.assertEqual(round(obs, 5), 0.56234) exp = k2p(seq1, seq2) self.assertAlmostEqual(obs, exp) # one base has zero frequency (fine) obs = f84(seq1, seq2, freqs=(.0, .2, .3, .5)) self.assertEqual(round(obs, 5), 1.07015) # both purines have zero frequency (NaN) obs = f84(seq1, seq2, freqs=(.0, .4, .0, .6)) self.assertTrue(np.isnan(obs)) # identical sequences after trimming self.assertEqual(f84(DNA("AACGTY"), DNA("WACGTT")), 0.0) # too many transversions seq1 = DNA("ACGTACGT") seq2 = DNA("AGCATATT") self.assertTrue(np.isnan(f84(seq1, seq2))) # too many transitions seq1 = DNA("ACGTATGT") seq2 = DNA("GTCTACAT") self.assertTrue(np.isnan(f84(seq1, seq2))) # RNA sequences seq1, seq2 = RNA("AUCU-CGGU"), RNA("AGGUUCA--") self.assertEqual(round(f84(seq1, seq2), 5), 0.83551) # non-nucleotide sequences with self.assertRaises(TypeError): f84(Protein("-PYCRNG"), Protein("MPYAKC-")) with self.assertRaises(TypeError): f84(Sequence("AGCNT"), Sequence("CG-AT")) class TestTN93(TestCase): def test_tn93(self): # normal case: 8 sites, 1 purine transition, 1 pyrimidine transition, # 1 transversion; use observed base frequencies seq1 = DNA("AT-ACGGCGA-C") seq2 = DNA("AGAAT--CAACC") obs = tn93(seq1, seq2) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.99700) obs = tn93(seq1, seq2, gamma=2.0) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 3.01441) # specify base frequencies obs = tn93(seq1, seq2, freqs=(.2, .2, .3, .3)) self.assertEqual(round(obs, 5), 0.57303) obs = tn93(seq1, seq2, freqs=(.2, .2, .3, .3), gamma=2.0) self.assertEqual(round(obs, 5), 0.73357) # even base frequencies obs = tn93(seq1, seq2, freqs=(.25, .25, .25, .25)) self.assertEqual(round(obs, 5), 0.56234) obs = tn93(seq1, seq2, freqs=(.25, .25, .25, .25), gamma=2.0) self.assertEqual(round(obs, 5), 0.71034) # zero base frequency obs = tn93(seq1, seq2, freqs=(.0, .2, .3, .5)) self.assertTrue(np.isnan(obs)) obs = tn93(seq1, seq2, freqs=(.0, .2, .3, .5), gamma=2.0) self.assertTrue(np.isnan(obs)) # identical sequences after trimming self.assertEqual(tn93(DNA("AACGTY"), DNA("WACGTT")), 0.0) self.assertEqual(tn93(DNA("AACGTY"), DNA("WACGTT"), gamma=2.0), 0.0) # too many purine transitions (a1 < 0) seq1 = DNA("ACGTATGT") seq2 = DNA("GCATGCAT") self.assertTrue(np.isnan(tn93(seq1, seq2))) self.assertTrue(np.isnan(tn93(seq1, seq2, gamma=2.0))) # too many pyrimidine transitions (a2 < 0) seq1 = DNA("ACCTTGCC") seq2 = DNA("ATTTCGCT") self.assertTrue(np.isnan(tn93(seq1, seq2))) self.assertTrue(np.isnan(tn93(seq1, seq2, gamma=2.0))) # too many transversions (a3 < 0) seq1 = DNA("ACGTACGT") seq2 = DNA("AGCATATT") self.assertTrue(np.isnan(tn93(seq1, seq2))) self.assertTrue(np.isnan(tn93(seq1, seq2, gamma=2.0))) # RNA sequences seq1 = RNA("AUCU-CGCAGU") seq2 = RNA("AGGUUCAUA--") self.assertEqual(round(tn93(seq1, seq2), 5), 0.88543) self.assertEqual(round(tn93(seq1, seq2, gamma=2.0), 5), 1.25798) # non-nucleotide sequences with self.assertRaises(TypeError): tn93(Protein("-PYCRNG"), Protein("MPYAKC-")) with self.assertRaises(TypeError): tn93(Sequence("AGCNT"), Sequence("CG-AT")) seq1 = RNA("AUCU-CGCAGU") seq2 = RNA("AGGUUCAUA--") with self.assertRaises(ValueError): tn93(seq1, seq2, gamma=-1.0) with self.assertRaises(ValueError): tn93(seq1, seq2, gamma=0.0) class TestLogDet(TestCase): def test_logdet(self): # normal case (note that logdet) seq1 = DNA("CTGTGCCTGTGCCGCCCCAGTACCGAAGTCCATGTA") seq2 = DNA("CTGTGACCAGGCCACTTCACAAGTGGAGTTCAGGAT") obs = logdet(seq1, seq2) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.74220) seq1 = DNA("CTGTGC---CTGTGCCTTGCCCCAGTACCGAAG-TCCATGTAAA") seq2 = DNA("CTGTGAAGACCAGGCC--ACTTCACAAGTGGAGGTTCAGGAT--") obs = logdet(seq1, seq2) self.assertEqual(round(obs, 5), 0.74220) # LogDet is often NaN when sequences are short and frequency matrix is sparse. seq1 = DNA("AT-ACGGCGA-C") seq2 = DNA("AGAAT--CAACC") self.assertTrue(np.isnan(logdet(seq1, seq2))) # LogDet is often NaN when the alphabet is large (e.g., protein) seq1 = Protein("PGTRVRAMAIYKQSQHMTEVVRRCPHHERCSDSDGLAPPQHLIRVEGNLRVEYL" "DDRNTFRHSVVVPYEPPEVGSDCTT") seq2 = Protein("QGSVVRATAIYKKSEHVAEVVRRCPHHERTPDGDNLAPAGHLIRVEGNQRANYR" "EDNITLRHSVFVPYEAPQLGAEWTT") self.assertTrue(np.isnan(logdet(seq1, seq2))) # add a pseudocount can mitigate this scenario # NOTE: This test produces different results in different systems. # obs = logdet(seq1, seq2, pseudocount=0.5) # self.assertEqual(round(obs, 5), 3.87727) # Gen 1 Xeon # LogDet is zero when sequences are identical and character frequencies are # equal. seq1 = RNA("ACGUACGU") seq2 = RNA("ACGUACGU") self.assertAlmostEqual(logdet(seq1, seq2), 0.0) # custom sequence type with five characters class CustomSequence(GrammaredSequence): @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set('^$') @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return '^' @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set('aeiou') @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return {} seq1 = CustomSequence("euooeuauaueia^^ioaoaiaioae^eiaoeiaooeueuiua") seq2 = CustomSequence("eioaeiaeeoiiuaeioaeuiuueeeaaiaooiuoee^^uuua") obs = logdet(seq1, seq2) self.assertEqual(round(obs, 5), 0.84653) class TestParalin(TestCase): def test_paralin(self): # normal case (note that logdet) seq1 = DNA("CTGTGCCTGTGCCGCCCCAGTACCGAAGTCCATGTA") seq2 = DNA("CTGTGACCAGGCCACTTCACAAGTGGAGTTCAGGAT") obs = paralin(seq1, seq2) self.assertIsInstance(obs, float) self.assertEqual(round(obs, 5), 0.72121) seq1 = DNA("CTGTGC---CTGTGCCTTGCCCCAGTACCGAAG-TCCATGTAAA") seq2 = DNA("CTGTGAAGACCAGGCC--ACTTCACAAGTGGAGGTTCAGGAT--") obs = paralin(seq1, seq2) self.assertEqual(round(obs, 5), 0.72121) # Paralinear is often NaN when sequences are short and the matrix is sparse. seq1 = DNA("AT-ACGGCGA-C") seq2 = DNA("AGAAT--CAACC") self.assertTrue(np.isnan(paralin(seq1, seq2))) # Paralinear collapses to LogDet when character frequencies are equal. seq1 = DNA("ACCGGTAAGCTAAGGCCTTT") seq2 = DNA("CCAGGTAAACTAGGGTCCTT") obs = paralin(seq1, seq2) self.assertEqual(round(obs, 5), 0.44595) exp = logdet(seq1, seq2) self.assertAlmostEqual(obs, exp) # Paralinear is zero when sequences are identical, whether character # frequencies are equal or not. seq1 = RNA("ACGUACGU") seq2 = RNA("ACGUACGU") self.assertAlmostEqual(paralin(seq1, seq2), 0.0) seq1 = RNA("AAACCGGU") seq2 = RNA("AAACCGGU") self.assertAlmostEqual(paralin(seq1, seq2), 0.0) # custom sequence type with five characters class CustomSequence(GrammaredSequence): @classproperty @overrides(GrammaredSequence) def gap_chars(cls): return set('^$') @classproperty @overrides(GrammaredSequence) def default_gap_char(cls): return '^' @classproperty @overrides(GrammaredSequence) def definite_chars(cls): return set('aeiou') @classproperty @overrides(GrammaredSequence) def degenerate_map(cls): return {} seq1 = CustomSequence("euooeuauaueia^^ioaoaiaioae^eiaoeiaooeueuiua") seq2 = CustomSequence("eioaeiaeeoiiuaeioaeuiuueeeaaiaooiuoee^^uuua") obs = paralin(seq1, seq2) self.assertEqual(round(obs, 5), 0.82944) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/test_dna.py000066400000000000000000000034311520735541300246100ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from skbio import DNA, RNA from skbio.metadata import IntervalMetadata # tests specific to DNA go here. tests for functionality shared by DNA and RNA # go in test_nucleotide_sequences.py class TestDNA(unittest.TestCase): def test_transcribe(self): # without changes self.assertEqual(DNA('').transcribe(), RNA('')) self.assertEqual(DNA('A').transcribe(), RNA('A')) self.assertEqual(DNA('.ACGW-').transcribe(), RNA('.ACGW-')) # with changes self.assertEqual(DNA('T').transcribe(), RNA('U')) self.assertEqual(DNA('TT').transcribe(), RNA('UU')) self.assertEqual(DNA('ATCTG').transcribe(), RNA('AUCUG')) self.assertEqual(DNA('TTTG').transcribe(), RNA('UUUG')) def test_transcribe_preserves_all_metadata(self): im = IntervalMetadata(4) im.add([(0, 2)], metadata={'gene': 'p53'}) exp = RNA('AGUU', metadata={'foo': 'bar'}, positional_metadata={'foo': range(4)}, interval_metadata=im) seq = DNA('AGTT', metadata={'foo': 'bar'}, positional_metadata={'foo': range(4)}, interval_metadata=im) self.assertEqual(seq.transcribe(), exp) def test_transcribe_does_not_modify_input(self): seq = DNA('ATAT') self.assertEqual(seq.transcribe(), RNA('AUAU')) self.assertEqual(seq, DNA('ATAT')) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/test_genetic_code.py000066400000000000000000000463221520735541300264640ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import itertools import unittest import numpy as np import numpy.testing as npt from skbio import Sequence, DNA, RNA, Protein, GeneticCode from skbio.sequence._genetic_code import _ncbi_genetic_codes class TestGeneticCode(unittest.TestCase): def setUp(self): self.sgc = GeneticCode.from_ncbi(1) def test_from_ncbi_valid_table_ids(self): # spot check a few tables self.assertEqual(GeneticCode.from_ncbi().name, 'Standard') self.assertEqual(GeneticCode.from_ncbi(2).name, 'Vertebrate Mitochondrial') self.assertEqual(GeneticCode.from_ncbi(12).name, 'Alternative Yeast Nuclear') self.assertEqual(GeneticCode.from_ncbi(25).name, 'Candidate Division SR1 and Gracilibacteria') def test_from_ncbi_invalid_input(self): with self.assertRaisesRegex(ValueError, r'table_id.*7'): GeneticCode.from_ncbi(7) with self.assertRaisesRegex(ValueError, r'table_id.*42'): GeneticCode.from_ncbi(42) def test_reading_frames(self): exp = [1, 2, 3, -1, -2, -3] self.assertEqual(GeneticCode.reading_frames, exp) self.assertEqual(self.sgc.reading_frames, exp) GeneticCode.reading_frames.append(42) self.assertEqual(GeneticCode.reading_frames, exp) self.assertEqual(self.sgc.reading_frames, exp) with self.assertRaises(AttributeError): self.sgc.reading_frames = [1, 2, 42] def test_name(self): self.assertEqual(self.sgc.name, 'Standard') self.assertEqual(GeneticCode('M' * 64, '-' * 64).name, '') self.assertEqual(GeneticCode('M' * 64, '-' * 64, 'foo').name, 'foo') with self.assertRaises(AttributeError): self.sgc.name = 'foo' def test_init_varied_equivalent_input(self): for args in (('M' * 64, '-' * 64), (Protein('M' * 64), Protein('-' * 64)), (Sequence('M' * 64), Sequence('-' * 64))): gc = GeneticCode(*args) self.assertEqual(gc.name, '') self.assertEqual(gc._amino_acids, Protein('M' * 64)) self.assertEqual(gc._starts, Protein('-' * 64)) npt.assert_array_equal(gc._m_character_codon, np.asarray([0, 0, 0], dtype=np.uint8)) self.assertEqual(len(gc._start_codons), 0) def test_init_invalid_input(self): # `amino_acids` invalid protein with self.assertRaisesRegex(ValueError, r'Invalid character.*&'): GeneticCode('&' * 64, '-' * 64) # wrong number of amino acids with self.assertRaisesRegex(ValueError, r'amino_acids.*64.*42'): GeneticCode('M' * 42, '-' * 64) # `amino_acids` missing M with self.assertRaisesRegex(ValueError, r'amino_acids.*M.*character'): GeneticCode('A' * 64, '-' * 64) # `starts` invalid protein with self.assertRaisesRegex(ValueError, r'Invalid character.*&'): GeneticCode('M' * 64, '&' * 64) # wrong number of starts with self.assertRaisesRegex(ValueError, r'starts.*64.*42'): GeneticCode('M' * 64, '-' * 42) # invalid characters in `starts` with self.assertRaisesRegex(ValueError, r'starts.*M and - characters'): GeneticCode('M' * 64, '-M' * 30 + '*AQR') def test_str(self): # predefined exp = ( ' AAs = FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAA' 'DDEEGGGG\n' 'Starts = ---M---------------M---------------M--------------------' '--------\n' 'Base1 = UUUUUUUUUUUUUUUUCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGG' 'GGGGGGGG\n' 'Base2 = UUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCC' 'AAAAGGGG\n' 'Base3 = UCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAG' 'UCAGUCAG' ) self.assertEqual(str(self.sgc), exp) # custom, no name obs = str(GeneticCode('M' * 64, '-' * 64)) self.assertIn('M' * 64, obs) self.assertIn('-' * 64, obs) def test_repr(self): # predefined exp = ( 'GeneticCode (Standard)\n' '-----------------------------------------------------------------' '--------\n' ' AAs = FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAA' 'DDEEGGGG\n' 'Starts = ---M---------------M---------------M--------------------' '--------\n' 'Base1 = UUUUUUUUUUUUUUUUCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGG' 'GGGGGGGG\n' 'Base2 = UUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCCAAAAGGGGUUUUCCCC' 'AAAAGGGG\n' 'Base3 = UCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAGUCAG' 'UCAGUCAG' ) self.assertEqual(repr(self.sgc), exp) # custom, no name obs = repr(GeneticCode('M' * 64, '-' * 64)) self.assertTrue(obs.startswith('GeneticCode\n')) self.assertIn('M' * 64, obs) self.assertIn('-' * 64, obs) def test_eq(self): amino_acids = 'AMPM' * 16 starts = '--M-' * 16 equal_gcs = [ GeneticCode(amino_acids, starts), # name should be ignored GeneticCode(amino_acids, starts, 'foo'), # metadata/positional metadata should be ignored if Sequence # subclass is provided GeneticCode( Protein(amino_acids, metadata={'foo': 'bar'}), Protein(starts, positional_metadata={'foo': range(64)})) ] # every gc should be equal to itself for gc in equal_gcs: self.assertTrue(gc == gc) self.assertFalse(gc != gc) # every pair of gcs should be equal. use permutations instead of # combinations to test that comparing gc1 to gc2 and gc2 to gc1 are # both equal for gc1, gc2 in itertools.permutations(equal_gcs, 2): self.assertTrue(gc1 == gc2) self.assertFalse(gc1 != gc2) def test_ne(self): class GeneticCodeSubclass(GeneticCode): pass amino_acids = 'AMPM' * 16 starts = '--M-' * 16 unequal_gcs = [ GeneticCode(amino_acids, starts), # type must match GeneticCodeSubclass(amino_acids, starts), # completely different type 'foo' ] # none of the NCBI genetic codes should be equal to each other unequal_gcs.extend(_ncbi_genetic_codes.values()) for gc in unequal_gcs: self.assertTrue(gc == gc) self.assertFalse(gc != gc) for gc1, gc2 in itertools.permutations(unequal_gcs, 2): self.assertTrue(gc1 != gc2) self.assertFalse(gc1 == gc2) def test_translate_preserves_metadata(self): obs = self.sgc.translate( RNA('AUG', metadata={'foo': 'bar', 'baz': 42}, positional_metadata={'foo': range(3)})) # metadata retained, positional metadata dropped self.assertEqual(obs, Protein('M', metadata={'foo': 'bar', 'baz': 42})) def test_translate_default_behavior(self): # empty translation exp = Protein('') for seq in RNA(''), RNA('A'), RNA('AU'): obs = self.sgc.translate(seq) self.assertEqual(obs, exp) # no start or stop codons obs = self.sgc.translate(RNA('CCU')) self.assertEqual(obs, Protein('P')) # multiple alternative start codons, no stop codons, length is multiple # of 3 obs = self.sgc.translate(RNA('CAUUUGCUGAAA')) self.assertEqual(obs, Protein('HLLK')) # multiple stop codons, length isn't multiple of 3 obs = self.sgc.translate(RNA('UUUUUUUAAAGUUAAGGGAU')) self.assertEqual(obs, Protein('FF*S*G')) def test_translate_reading_frame_empty_translation(self): exp = Protein('') for seq in RNA(''), RNA('A'), RNA('AU'): for reading_frame in GeneticCode.reading_frames: obs = self.sgc.translate(seq, reading_frame=reading_frame) self.assertEqual(obs, exp) # reading frames that yield a partial codon for reading_frame in 2, 3, -2, -3: obs = self.sgc.translate(RNA('AUG'), reading_frame=reading_frame) self.assertEqual(obs, exp) def test_translate_reading_frame_non_empty_translation(self): seq = RNA('AUGGUGGAA') # rc = UUCCACCAU for reading_frame, exp_str in ((1, 'MVE'), (2, 'WW'), (3, 'GG'), (-1, 'FHH'), (-2, 'ST'), (-3, 'PP')): exp = Protein(exp_str) obs = self.sgc.translate(seq, reading_frame=reading_frame) self.assertEqual(obs, exp) def test_translate_start_empty_translation(self): exp = Protein('') for seq in RNA(''), RNA('A'), RNA('AU'): for start in {'optional', 'ignore'}: obs = self.sgc.translate(seq, start=start) self.assertEqual(obs, exp) with self.assertRaisesRegex(ValueError, r'reading_frame=1.*start=\'require\''): self.sgc.translate(seq, start='require') def test_translate_start_with_start_codon(self): # trim before start codon, replace with M. ensure alternative start # codons following the start codon aren't replaced with M. ensure # default behavior for handling stop codons is retained seq = RNA('CAUUUGCUGAAAUGA') exp = Protein('MLK*') for start in {'require', 'optional'}: obs = self.sgc.translate(seq, start=start) self.assertEqual(obs, exp) # ignore start codon replacement and trimming; just translate exp = Protein('HLLK*') obs = self.sgc.translate(seq, start='ignore') self.assertEqual(obs, exp) # just a start codon, no replacement necessary seq = RNA('AUG') exp = Protein('M') for start in {'require', 'optional', 'ignore'}: obs = self.sgc.translate(seq, start=start) self.assertEqual(obs, exp) # single alternative start codon seq = RNA('CUG') exp = Protein('M') for start in {'require', 'optional'}: obs = self.sgc.translate(seq, start=start) self.assertEqual(obs, exp) exp = Protein('L') obs = self.sgc.translate(seq, start='ignore') self.assertEqual(obs, exp) def test_translate_start_no_start_codon(self): seq = RNA('CAACAACAGCAA') exp = Protein('QQQQ') for start in {'ignore', 'optional'}: obs = self.sgc.translate(seq, start=start) self.assertEqual(obs, exp) with self.assertRaisesRegex(ValueError, r'reading_frame=1.*start=\'require\''): self.sgc.translate(seq, start='require') # non-start codon that translates to an AA that start codons also map # to. should catch bug if code attempts to search and trim *after* # translation -- this must happen *before* translation seq = RNA('UUACAA') exp = Protein('LQ') for start in {'ignore', 'optional'}: obs = self.sgc.translate(seq, start=start) self.assertEqual(obs, exp) with self.assertRaisesRegex(ValueError, r'reading_frame=1.*start=\'require\''): self.sgc.translate(seq, start='require') def test_translate_start_no_accidental_mutation(self): # `start` mutates a vector in-place that is derived from # GeneticCode._offset_table. the current code doesn't perform an # explicit copy because numpy's advanced indexing is used, which always # returns a copy. test this assumption here in case that behavior # changes in the future offset_table = self.sgc._offset_table.copy() seq = RNA('CAUUUGCUGAAAUGA') obs = self.sgc.translate(seq, start='require') self.assertEqual(obs, Protein('MLK*')) npt.assert_array_equal(self.sgc._offset_table, offset_table) def test_translate_stop_empty_translation(self): exp = Protein('') for seq in RNA(''), RNA('A'), RNA('AU'): for stop in {'optional', 'ignore'}: obs = self.sgc.translate(seq, stop=stop) self.assertEqual(obs, exp) with self.assertRaisesRegex(ValueError, r'reading_frame=1.*stop=\'require\''): self.sgc.translate(seq, stop='require') def test_translate_stop_with_stop_codon(self): # multiple stop codons with trailing codons seq = RNA('UGGACUUGAUAUCGUUAGGAU') exp = Protein('WT') for stop in {'require', 'optional'}: obs = self.sgc.translate(seq, stop=stop) self.assertEqual(obs, exp) # ignore stop codon trimming; just translate exp = Protein('WT*YR*D') obs = self.sgc.translate(seq, stop='ignore') self.assertEqual(obs, exp) # ends with single stop codon seq = RNA('UGUCUGUAA') exp = Protein('CL') for stop in {'require', 'optional'}: obs = self.sgc.translate(seq, stop=stop) self.assertEqual(obs, exp) exp = Protein('CL*') obs = self.sgc.translate(seq, stop='ignore') self.assertEqual(obs, exp) # just a stop codon seq = RNA('UAG') exp = Protein('') for stop in {'require', 'optional'}: obs = self.sgc.translate(seq, stop=stop) self.assertEqual(obs, exp) exp = Protein('*') obs = self.sgc.translate(seq, stop='ignore') self.assertEqual(obs, exp) def test_translate_stop_no_stop_codon(self): seq = RNA('GAAUCU') exp = Protein('ES') for stop in {'ignore', 'optional'}: obs = self.sgc.translate(seq, stop=stop) self.assertEqual(obs, exp) with self.assertRaisesRegex(ValueError, r'reading_frame=1.*stop=\'require\''): self.sgc.translate(seq, stop='require') def test_translate_trim_to_cds(self): seq = RNA('UAAUUGCCUCAUUAAUAACAAUGA') # find first start codon, trim all before it, convert alternative start # codon to M, finally trim to first stop codon following the start # codon exp = Protein('MPH') for param in {'require', 'optional'}: obs = self.sgc.translate(seq, start=param, stop=param) self.assertEqual(obs, exp) exp = Protein('*LPH**Q*') obs = self.sgc.translate(seq, start='ignore', stop='ignore') self.assertEqual(obs, exp) # alternative reading frame disrupts cds: # AAUUGCCUCAUUAAUAACAAUGA # NCLINNN with self.assertRaisesRegex(ValueError, r'reading_frame=2.*start=\'require\''): self.sgc.translate(seq, reading_frame=2, start='require') with self.assertRaisesRegex(ValueError, r'reading_frame=2.*stop=\'require\''): self.sgc.translate(seq, reading_frame=2, stop='require') exp = Protein('NCLINNN') for param in {'ignore', 'optional'}: obs = self.sgc.translate(seq, reading_frame=2, start=param, stop=param) self.assertEqual(obs, exp) def test_translate_invalid_input(self): # invalid sequence type with self.assertRaisesRegex(TypeError, r'RNA.*DNA'): self.sgc.translate(DNA('ACG')) with self.assertRaisesRegex(TypeError, r'RNA.*str'): self.sgc.translate('ACG') # invalid reading frame with self.assertRaisesRegex(ValueError, r'\[1, 2, 3, -1, -2, -3\].*0'): self.sgc.translate(RNA('AUG'), reading_frame=0) # invalid start with self.assertRaisesRegex(ValueError, r'start.*foo'): self.sgc.translate(RNA('AUG'), start='foo') # invalid stop with self.assertRaisesRegex(ValueError, r'stop.*foo'): self.sgc.translate(RNA('AUG'), stop='foo') # gapped sequence with self.assertRaisesRegex(ValueError, r'gapped'): self.sgc.translate(RNA('UU-G')) # degenerate sequence with self.assertRaisesRegex(NotImplementedError, r'degenerate'): self.sgc.translate(RNA('RUG')) def test_translate_varied_genetic_codes(self): # spot check using a few NCBI and custom genetic codes to translate seq = RNA('AAUGAUGUGACUAUCAGAAGG') # table_id=2 exp = Protein('NDVTI**') obs = GeneticCode.from_ncbi(2).translate(seq) self.assertEqual(obs, exp) exp = Protein('MTI') obs = GeneticCode.from_ncbi(2).translate(seq, start='require', stop='require') self.assertEqual(obs, exp) # table_id=22 exp = Protein('NDVTIRR') obs = GeneticCode.from_ncbi(22).translate(seq) self.assertEqual(obs, exp) with self.assertRaisesRegex(ValueError, r'reading_frame=1.*start=\'require\''): GeneticCode.from_ncbi(22).translate(seq, start='require', stop='require') # custom, no start codons gc = GeneticCode('MWN*' * 16, '-' * 64) exp = Protein('MM*MWN*') obs = gc.translate(seq) self.assertEqual(obs, exp) with self.assertRaisesRegex(ValueError, r'reading_frame=1.*start=\'require\''): gc.translate(seq, start='require', stop='require') def test_translate_six_frames(self): seq = RNA('AUGCUAACAUAAA') # rc = UUUAUGUUAGCAU # test default behavior exp = [Protein('MLT*'), Protein('C*HK'), Protein('ANI'), Protein('FMLA'), Protein('LC*H'), Protein('YVS')] obs = list(self.sgc.translate_six_frames(seq)) self.assertEqual(obs, exp) # test that start/stop are respected exp = [Protein('MLT'), Protein('C'), Protein('ANI'), Protein('MLA'), Protein('LC'), Protein('YVS')] obs = list(self.sgc.translate_six_frames(seq, start='optional', stop='optional')) self.assertEqual(obs, exp) def test_translate_six_frames_preserves_metadata(self): seq = RNA('AUG', metadata={'foo': 'bar', 'baz': 42}, positional_metadata={'foo': range(3)}) obs = list(self.sgc.translate_six_frames(seq))[:2] # metadata retained, positional metadata dropped self.assertEqual( obs, [Protein('M', metadata={'foo': 'bar', 'baz': 42}), Protein('', metadata={'foo': 'bar', 'baz': 42})]) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/test_grammared_sequence.py000066400000000000000000000732761520735541300277130ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt import pandas as pd from skbio.sequence import GrammaredSequence from skbio.util import classproperty from skbio.util import assert_data_frame_almost_equal from skbio.metadata import IntervalMetadata class ExampleGrammaredSequence(GrammaredSequence): @classproperty def degenerate_map(cls): return {"X": set("AB"), "Y": set("BC"), "Z": set("AC"), "W": set("ABCQ")} @classproperty def definite_chars(cls): return set("ABCQ") @classproperty def default_gap_char(cls): return '-' @classproperty def gap_chars(cls): return set('-.') @classproperty def noncanonical_chars(cls): return "Q" @classproperty def wildcard_char(cls): return "W" class ExampleMotifsTester(ExampleGrammaredSequence): @property def _motifs(self): # These aren't really motifs, just a way to excercise the code paths return { "name1": lambda x, _, __: str(x), "name2": lambda x, _, __: len(x) } class TestGrammaredSequence(TestCase): def test_default_gap_must_be_in_gap_chars(self): with self.assertRaisesRegex( TypeError, r"default_gap_char must be in gap_chars for class " "GrammaredSequenceInvalidDefaultGap"): class GrammaredSequenceInvalidDefaultGap(ExampleGrammaredSequence): @classproperty def default_gap_char(cls): return '*' def test_degenerates_must_expand_to_valid_definites(self): with self.assertRaisesRegex( TypeError, r"degenerate_map must expand only to characters included in " "definite_chars for class " "GrammaredSequenceInvalidDefaultGap"): class GrammaredSequenceInvalidDefaultGap(ExampleGrammaredSequence): @classproperty def degenerate_map(cls): return {"X": set("B")} @classproperty def definite_chars(cls): return set("A") def test_gap_chars_and_degenerates_share(self): with self.assertRaisesRegex( TypeError, r"gap_chars and degenerate_chars must not share any characters" " for class GrammaredSequenceGapInDegenerateMap"): class GrammaredSequenceGapInDegenerateMap( ExampleGrammaredSequence): @classproperty def degenerate_map(cls): return {"X": set("AB")} @classproperty def definite_chars(cls): return set("ABC") @classproperty def gap_chars(cls): return set(".-X") def test_gap_chars_and_definites_share(self): with self.assertRaisesRegex( TypeError, (r"gap_chars and definite_chars must not share any characters " "for class GrammaredSequenceGapInDefiniteMap")): class GrammaredSequenceGapInDefiniteMap( ExampleGrammaredSequence): @classproperty def degenerate_map(cls): return {"X": set("AB")} @classproperty def definite_chars(cls): return set("ABC") @classproperty def gap_chars(cls): return set(".-A") def test_degenerates_and_definites_share(self): with self.assertRaisesRegex( TypeError, (r"degenerate_chars and definite_chars must not share any " "characters for class GrammaredSequenceInvalid")): class GrammaredSequenceInvalid(ExampleGrammaredSequence): @classproperty def degenerate_map(cls): return {"X": set("AB")} @classproperty def definite_chars(cls): return set("ABCX") def test_instantiation_with_no_implementation(self): class GrammaredSequenceSubclassNoImplementation(GrammaredSequence): pass with self.assertRaises(TypeError) as cm: GrammaredSequenceSubclassNoImplementation() self.assertIn("abstract class", str(cm.exception)) self.assertIn("definite_chars", str(cm.exception)) self.assertIn("degenerate_map", str(cm.exception)) def test_init_default_parameters(self): seq = ExampleGrammaredSequence('.-ABCXYZ') npt.assert_equal(seq.values, np.array('.-ABCXYZ', dtype='c')) self.assertEqual(seq.metadata, {}) assert_data_frame_almost_equal(seq.positional_metadata, pd.DataFrame(index=range(8))) self.assertEqual(seq.interval_metadata, IntervalMetadata(8)) def test_init_nondefault_parameters(self): im = IntervalMetadata(8) im.add([(1, 8)], metadata={'gene': 'p53'}) seq = ExampleGrammaredSequence( '.-ABCXYZ', metadata={'id': 'foo'}, positional_metadata={'quality': range(8)}, interval_metadata=im) npt.assert_equal(seq.values, np.array('.-ABCXYZ', dtype='c')) self.assertEqual(seq.metadata, {'id': 'foo'}) assert_data_frame_almost_equal(seq.positional_metadata, pd.DataFrame({'quality': range(8)})) self.assertEqual(seq.interval_metadata, im) def test_init_valid_empty_sequence(self): # just make sure we can instantiate an empty sequence regardless of # `validate` and `lowercase` parameters. more extensive tests # are performed in Sequence base class unit tests for validate in (True, False): for lowercase in (True, False): seq = ExampleGrammaredSequence( '', validate=validate, lowercase=lowercase) self.assertEqual(seq, ExampleGrammaredSequence('')) def test_init_valid_single_character_sequence(self): for validate in (True, False): for lowercase in (True, False): seq = ExampleGrammaredSequence( 'C', validate=validate, lowercase=lowercase) self.assertEqual(seq, ExampleGrammaredSequence('C')) def test_init_valid_multiple_character_sequence(self): for validate in (True, False): for lowercase in (True, False): seq = ExampleGrammaredSequence( 'BAACB.XYY-AZ', validate=validate, lowercase=lowercase) self.assertEqual(seq, ExampleGrammaredSequence('BAACB.XYY-AZ')) def test_init_validate_parameter_single_character(self): seq = 'w' with self.assertRaisesRegex(ValueError, r"character.*'w'"): ExampleGrammaredSequence(seq) # test that we can instantiate an invalid sequence. we don't guarantee # anything working beyond instantiation ExampleGrammaredSequence(seq, validate=False) def test_init_validate_parameter_multiple_characters(self): # mix of valid and invalid characters with repeats and lowercased # alphabet characters seq = 'CBCBBbawCbbwBXYZ-.x' with self.assertRaisesRegex(ValueError, r"\['a', 'b', 'w', 'x'\]"): ExampleGrammaredSequence(seq) ExampleGrammaredSequence(seq, validate=False) def test_init_lowercase_all_lowercase(self): s = 'cbcbbbazcbbzbxyz-.x' with self.assertRaisesRegex(ValueError, r"\['a', 'b', 'c', 'x', 'y', 'z'\]"): ExampleGrammaredSequence(s) seq = ExampleGrammaredSequence(s, lowercase=True) self.assertEqual(seq, ExampleGrammaredSequence('CBCBBBAZCBBZBXYZ-.X')) def test_init_lowercase_mixed_case(self): s = 'CBCBBbazCbbzBXYZ-.x' with self.assertRaisesRegex(ValueError, r"\['a', 'b', 'x', 'z'\]"): ExampleGrammaredSequence(s) seq = ExampleGrammaredSequence(s, lowercase=True) self.assertEqual(seq, ExampleGrammaredSequence('CBCBBBAZCBBZBXYZ-.X')) def test_init_lowercase_no_validation(self): s = 'car' with self.assertRaisesRegex(ValueError, r"\['a', 'c', 'r'\]"): ExampleGrammaredSequence(s) with self.assertRaisesRegex(ValueError, r"character.*'R'"): ExampleGrammaredSequence(s, lowercase=True) ExampleGrammaredSequence(s, lowercase=True, validate=False) def test_init_lowercase_byte_ownership(self): bytes = np.array([97, 98, 97], dtype=np.uint8) with self.assertRaisesRegex(ValueError, r"\['a', 'b'\]"): ExampleGrammaredSequence(bytes) seq = ExampleGrammaredSequence(bytes, lowercase=True) self.assertEqual(seq, ExampleGrammaredSequence('ABA')) # should not share the same memory self.assertIsNot(seq._bytes, bytes) # we should have copied `bytes` before modifying in place to convert to # upper. make sure `bytes` hasn't been mutated npt.assert_equal(bytes, np.array([97, 98, 97], dtype=np.uint8)) def test_init_lowercase_invalid_keys(self): for invalid_key in ((), [], 2): invalid_type = type(invalid_key) with self.assertRaisesRegex(TypeError, r"lowercase keyword argument expected " "a bool or string, but got %s" % invalid_type): ExampleGrammaredSequence('ACGTacgt', lowercase=invalid_key) def test_definite_codes(self): definite_char_codes = set(ExampleGrammaredSequence._definite_codes) self.assertEqual(definite_char_codes, set([65, 66, 67, 81])) def test_gap_codes(self): gap_codes = set(ExampleGrammaredSequence._gap_codes) self.assertEqual(gap_codes, set([45, 46])) def test_noncanonical_codes(self): noncanonical_codes = set(ExampleGrammaredSequence._noncanonical_codes) self.assertEqual(noncanonical_codes, set([81])) def test_degenerate_chars(self): expected = set("WXYZ") self.assertIs(type(ExampleGrammaredSequence.degenerate_chars), set) self.assertEqual(ExampleGrammaredSequence.degenerate_chars, expected) ExampleGrammaredSequence.degenerate_chars.add("W") self.assertEqual(ExampleGrammaredSequence.degenerate_chars, expected) self.assertEqual(ExampleGrammaredSequence('').degenerate_chars, expected) with self.assertRaises(AttributeError): ExampleGrammaredSequence('').degenerate_chars = set("BAR") # TODO: duplicate of test_definite_chars, remove when nondegenerate_chars, # is removed def test_nondegenerate_chars(self): expected = set("ABCQ") self.assertEqual(ExampleGrammaredSequence.nondegenerate_chars, expected) ExampleGrammaredSequence.degenerate_chars.add("D") self.assertEqual(ExampleGrammaredSequence.nondegenerate_chars, expected) self.assertEqual(ExampleGrammaredSequence('').nondegenerate_chars, expected) with self.assertRaises(AttributeError): ExampleGrammaredSequence('').nondegenerate_chars = set("BAR") def test_definite_chars(self): expected = set("ABCQ") self.assertEqual(ExampleGrammaredSequence.definite_chars, expected) ExampleGrammaredSequence.degenerate_chars.add("D") self.assertEqual(ExampleGrammaredSequence.definite_chars, expected) self.assertEqual(ExampleGrammaredSequence('').definite_chars, expected) with self.assertRaises(AttributeError): ExampleGrammaredSequence('').definite_chars = set("BAR") def test_gap_chars(self): expected = set(".-") self.assertIs(type(ExampleGrammaredSequence.gap_chars), set) self.assertEqual(ExampleGrammaredSequence.gap_chars, expected) ExampleGrammaredSequence.gap_chars.add("_") self.assertEqual(ExampleGrammaredSequence.gap_chars, expected) self.assertEqual(ExampleGrammaredSequence('').gap_chars, expected) with self.assertRaises(AttributeError): ExampleGrammaredSequence('').gap_chars = set("_ =") def test_default_gap_char(self): self.assertIs(type(ExampleGrammaredSequence.default_gap_char), str) self.assertEqual(ExampleGrammaredSequence.default_gap_char, '-') self.assertEqual(ExampleGrammaredSequence('').default_gap_char, '-') with self.assertRaises(AttributeError): ExampleGrammaredSequence('').default_gap_char = '.' def test_alphabet(self): expected = set("ABC.-XYZQW") self.assertIs(type(ExampleGrammaredSequence.alphabet), set) self.assertEqual(ExampleGrammaredSequence.alphabet, expected) ExampleGrammaredSequence.alphabet.add("DEF") self.assertEqual(ExampleGrammaredSequence.alphabet, expected) self.assertEqual(ExampleGrammaredSequence('').alphabet, expected) with self.assertRaises(AttributeError): ExampleGrammaredSequence('').alphabet = set("ABCDEFG.-WXYZ") def test_degenerate_map(self): expected = {"X": set("AB"), "Y": set("BC"), "Z": set("AC"), "W": set("ABCQ")} self.assertEqual(ExampleGrammaredSequence.degenerate_map, expected) ExampleGrammaredSequence.degenerate_map['W'] = set("ABC") ExampleGrammaredSequence.degenerate_map['X'] = set("CA") self.assertEqual(ExampleGrammaredSequence.degenerate_map, expected) self.assertEqual(ExampleGrammaredSequence('').degenerate_map, expected) with self.assertRaises(AttributeError): ExampleGrammaredSequence('').degenerate_map = {'W': "ABC"} def test_gaps(self): self.assertIs(type(ExampleGrammaredSequence("").gaps()), np.ndarray) self.assertIs(ExampleGrammaredSequence("").gaps().dtype, np.dtype('bool')) npt.assert_equal(ExampleGrammaredSequence("ABCXBZYABC").gaps(), np.zeros(10).astype(bool)) npt.assert_equal(ExampleGrammaredSequence(".-.-.").gaps(), np.ones(5).astype(bool)) npt.assert_equal(ExampleGrammaredSequence("A.B-C.X-Y.").gaps(), np.array([0, 1] * 5, dtype=bool)) npt.assert_equal(ExampleGrammaredSequence("AB.AC.XY-").gaps(), np.array([0, 0, 1] * 3, dtype=bool)) npt.assert_equal(ExampleGrammaredSequence("A.BC.-").gaps(), np.array([0, 1, 0, 0, 1, 1], dtype=bool)) def test_has_gaps(self): self.assertIs(type(ExampleGrammaredSequence("").has_gaps()), bool) self.assertIs(type(ExampleGrammaredSequence("-").has_gaps()), bool) self.assertFalse(ExampleGrammaredSequence("").has_gaps()) self.assertFalse(ExampleGrammaredSequence("ABCXYZ").has_gaps()) self.assertTrue(ExampleGrammaredSequence("-").has_gaps()) self.assertTrue(ExampleGrammaredSequence("ABCXYZ-").has_gaps()) def test_degenerates(self): self.assertIs(type(ExampleGrammaredSequence("").degenerates()), np.ndarray) self.assertIs(ExampleGrammaredSequence("").degenerates().dtype, np.dtype('bool')) npt.assert_equal(ExampleGrammaredSequence("ABCBC-.AB.").degenerates(), np.zeros(10).astype(bool)) npt.assert_equal(ExampleGrammaredSequence("ZYZYZ").degenerates(), np.ones(5).astype(bool)) npt.assert_equal(ExampleGrammaredSequence("AX.Y-ZBXCZ").degenerates(), np.array([0, 1] * 5, dtype=bool)) npt.assert_equal(ExampleGrammaredSequence("ABXACY.-Z").degenerates(), np.array([0, 0, 1] * 3, dtype=bool)) npt.assert_equal(ExampleGrammaredSequence("AZBCXY").degenerates(), np.array([0, 1, 0, 0, 1, 1], dtype=bool)) def test_has_degenerates(self): self.assertIs(type(ExampleGrammaredSequence("").has_degenerates()), bool) self.assertIs(type(ExampleGrammaredSequence("X").has_degenerates()), bool) self.assertFalse(ExampleGrammaredSequence("").has_degenerates()) self.assertFalse(ExampleGrammaredSequence("A-.BC").has_degenerates()) self.assertTrue(ExampleGrammaredSequence("Z").has_degenerates()) self.assertTrue(ExampleGrammaredSequence("ABC.XYZ-").has_degenerates()) # TODO: duplicate of test_definites; remove when nondegenerates is removed def test_nondegenerates(self): self.assertIs(type(ExampleGrammaredSequence("").nondegenerates()), np.ndarray) self.assertIs(ExampleGrammaredSequence("").nondegenerates().dtype, np.dtype('bool')) npt.assert_equal( ExampleGrammaredSequence("XYZYZ-.XY.").nondegenerates(), np.zeros(10).astype(bool)) npt.assert_equal(ExampleGrammaredSequence("ABABA").nondegenerates(), np.ones(5).astype(bool)) npt.assert_equal( ExampleGrammaredSequence("XA.B-AZCXA").nondegenerates(), np.array([0, 1] * 5, dtype=bool)) npt.assert_equal( ExampleGrammaredSequence("XXAZZB.-C").nondegenerates(), np.array([0, 0, 1] * 3, dtype=bool)) npt.assert_equal(ExampleGrammaredSequence("YB.-AC").nondegenerates(), np.array([0, 1, 0, 0, 1, 1], dtype=bool)) def test_definites(self): self.assertIs(type(ExampleGrammaredSequence("").definites()), np.ndarray) self.assertIs(ExampleGrammaredSequence("").definites().dtype, np.dtype('bool')) npt.assert_equal( ExampleGrammaredSequence("XYZYZ-.XY.").definites(), np.zeros(10).astype(bool)) npt.assert_equal(ExampleGrammaredSequence("ABABA").definites(), np.ones(5).astype(bool)) npt.assert_equal( ExampleGrammaredSequence("XA.B-AZCXA").definites(), np.array([0, 1] * 5, dtype=bool)) npt.assert_equal( ExampleGrammaredSequence("XXAZZB.-C").definites(), np.array([0, 0, 1] * 3, dtype=bool)) npt.assert_equal(ExampleGrammaredSequence("YB.-AC").definites(), np.array([0, 1, 0, 0, 1, 1], dtype=bool)) # TODO: duplicate of test_has_definites; remove when has_nondegenerates is # removed. def test_has_nondegenerates(self): self.assertIs(type(ExampleGrammaredSequence("").has_nondegenerates()), bool) self.assertIs(type(ExampleGrammaredSequence("A").has_nondegenerates()), bool) self.assertFalse(ExampleGrammaredSequence("").has_nondegenerates()) self.assertFalse( ExampleGrammaredSequence("X-.YZ").has_nondegenerates()) self.assertTrue(ExampleGrammaredSequence("C").has_nondegenerates()) self.assertTrue( ExampleGrammaredSequence(".XYZ-ABC").has_nondegenerates()) def test_has_definites(self): self.assertIs(type(ExampleGrammaredSequence("").has_definites()), bool) self.assertIs(type(ExampleGrammaredSequence("A").has_definites()), bool) self.assertFalse(ExampleGrammaredSequence("").has_definites()) self.assertFalse( ExampleGrammaredSequence("X-.YZ").has_definites()) self.assertTrue(ExampleGrammaredSequence("C").has_definites()) self.assertTrue( ExampleGrammaredSequence(".XYZ-ABC").has_definites()) def test_degap(self): kw = { 'metadata': { 'id': 'some_id', 'description': 'some description', }, } self.assertEqual( ExampleGrammaredSequence( "", positional_metadata={'qual': []}, **kw).degap(), ExampleGrammaredSequence( "", positional_metadata={'qual': []}, **kw)) self.assertEqual( ExampleGrammaredSequence( "ABCXYZ", positional_metadata={'qual': np.arange(6)}, **kw).degap(), ExampleGrammaredSequence( "ABCXYZ", positional_metadata={'qual': np.arange(6)}, **kw)) self.assertEqual( ExampleGrammaredSequence( "ABC-XYZ", positional_metadata={'qual': np.arange(7, dtype=np.int64)}, **kw).degap(), ExampleGrammaredSequence( "ABCXYZ", positional_metadata={'qual': np.asarray([0, 1, 2, 4, 5, 6], dtype=np.int64)}, **kw)) self.assertEqual( ExampleGrammaredSequence( ".-ABC-XYZ.", positional_metadata={'qual': np.arange(10, dtype=np.int64)}, **kw).degap(), ExampleGrammaredSequence( "ABCXYZ", positional_metadata={'qual': np.asarray([2, 3, 4, 6, 7, 8], dtype=np.int64)}, **kw)) self.assertEqual( ExampleGrammaredSequence( "---.-.-.-.-.", positional_metadata={'quality': np.arange(12, dtype=np.int64)}, **kw).degap(), ExampleGrammaredSequence( "", positional_metadata={'quality': np.array([], dtype=np.int64)}, **kw)) def test_expand_degenerates_no_degens(self): seq = ExampleGrammaredSequence("ABCABCABC") self.assertEqual(list(seq.expand_degenerates()), [seq]) def test_expand_degenerates_all_degens(self): exp = [ ExampleGrammaredSequence('ABA'), ExampleGrammaredSequence('ABC'), ExampleGrammaredSequence('ACA'), ExampleGrammaredSequence('ACC'), ExampleGrammaredSequence('BBA'), ExampleGrammaredSequence('BBC'), ExampleGrammaredSequence('BCA'), ExampleGrammaredSequence('BCC') ] # Sort based on sequence string, as order is not guaranteed. obs = sorted(ExampleGrammaredSequence('XYZ').expand_degenerates(), key=str) self.assertEqual(obs, exp) def test_expand_degenerates_with_metadata(self): kw = { "metadata": { "id": "some_id", "description": "some description" }, "positional_metadata": { "quality": np.arange(3), }, } exp = [ExampleGrammaredSequence('ABA', **kw), ExampleGrammaredSequence('ABC', **kw), ExampleGrammaredSequence('BBA', **kw), ExampleGrammaredSequence('BBC', **kw)] obs = sorted( ExampleGrammaredSequence('XBZ', **kw).expand_degenerates(), key=str) self.assertEqual(obs, exp) def test_to_regex_no_degens(self): seq = ExampleGrammaredSequence('ABC') regex = seq.to_regex() self.assertEqual(regex.pattern, str(seq)) def test_to_regex_with_degens(self): seq = ExampleGrammaredSequence('AYZ') regex = seq.to_regex() self.assertFalse(any(regex.match(s) is None for s in 'ABA ABC ACA ACC'.split())) self.assertTrue(all(regex.match(s) is None for s in 'CBA BBA ABB AAA'.split())) def test_to_regex_within_capture(self): seq = ExampleGrammaredSequence('XYC') regex = seq.to_regex(within_capture=True) for ref in 'ABA BBB CCA'.split(): self.assertFalse(any(len(match.groups()) == 1 for match in regex.finditer(ref))) for ref in 'ABC BBC ACC'.split(): self.assertTrue(all(len(match.groups()) == 1 for match in regex.finditer(ref))) def test_find_motifs_no_motif(self): seq = ExampleMotifsTester("ABCABCABC") with self.assertRaises(ValueError) as cm: seq.find_motifs("doesn't-exist") self.assertIn("doesn't-exist", str(cm.exception)) seq = ExampleGrammaredSequence("ABCABCABC") with self.assertRaises(ValueError) as cm: seq.find_motifs("doesn't-exist") self.assertIn("doesn't-exist", str(cm.exception)) def test_find_motifs(self): seq = ExampleMotifsTester("ABC") self.assertEqual(seq.find_motifs("name1"), "ABC") self.assertEqual(seq.find_motifs("name2"), 3) def test_repr(self): # basic sanity checks for custom repr stats. more extensive testing is # performed on Sequence.__repr__ # minimal obs = repr(ExampleGrammaredSequence('')) self.assertEqual(obs.count('\n'), 7) self.assertTrue(obs.startswith('ExampleGrammaredSequence')) self.assertIn('length: 0', obs) self.assertIn('has gaps: False', obs) self.assertIn('has degenerates: False', obs) self.assertIn('has definites: False', obs) self.assertTrue(obs.endswith('-')) # no metadata, mix of gaps, degenerates, and definites obs = repr(ExampleGrammaredSequence('AY-B')) self.assertEqual(obs.count('\n'), 8) self.assertTrue(obs.startswith('ExampleGrammaredSequence')) self.assertIn('length: 4', obs) self.assertIn('has gaps: True', obs) self.assertIn('has degenerates: True', obs) self.assertIn('has definites: True', obs) self.assertTrue(obs.endswith('0 AY-B')) # metadata and positional metadata of mixed types obs = repr( ExampleGrammaredSequence( 'ABCA', metadata={'foo': 42, b'bar': 33.33, None: True, False: {}, (1, 2): 3, 'acb' * 100: "'"}, positional_metadata={'foo': range(4), 42: ['a', 'b', [], 'c']})) self.assertEqual(obs.count('\n'), 18) self.assertTrue(obs.startswith('ExampleGrammaredSequence')) self.assertIn('None: True', obs) self.assertIn('\'foo\': 42', obs) self.assertIn('42: ', obs) self.assertIn('\'foo\': ', obs) self.assertIn('length: 4', obs) self.assertIn('has gaps: False', obs) self.assertIn('has degenerates: False', obs) self.assertIn('has definites: True', obs) self.assertTrue(obs.endswith('0 ABCA')) # sequence spanning > 5 lines obs = repr(ExampleGrammaredSequence('A' * 301)) self.assertEqual(obs.count('\n'), 12) self.assertTrue(obs.startswith('ExampleGrammaredSequence')) self.assertIn('length: 301', obs) self.assertIn('has gaps: False', obs) self.assertIn('has degenerates: False', obs) self.assertIn('has definites: True', obs) self.assertIn('...', obs) self.assertTrue(obs.endswith('300 A')) def test_to_definites(self): seq = ExampleGrammaredSequence("ABCQXYZ") # default behavior, here I expect to see the sequence "ABCWWWW" returned obs = seq.to_definites() exp = ExampleGrammaredSequence("ABCWWWW") self.assertEqual(obs, exp) # noncanonical wildcard, expect to see "ABCQWWW" returned obs = seq.to_definites(noncanonical=False) exp = ExampleGrammaredSequence("ABCQWWW") # gap behavior, I expect to see the sequence "ABC----" returned obs = seq.to_definites(degenerate="gap") exp = ExampleGrammaredSequence("ABC----") self.assertEqual(obs, exp) # noncanonical gap obs = seq.to_definites(degenerate="gap", noncanonical=False) exp = ExampleGrammaredSequence("ABCQ---") self.assertEqual(obs, exp) # canonical trim obs = seq.to_definites(degenerate="del") exp = ExampleGrammaredSequence("ABC") self.assertEqual(obs, exp) # noncanonical trim obs = seq.to_definites(degenerate="del", noncanonical=False) exp = ExampleGrammaredSequence("ABCQ") self.assertEqual(obs, exp) # single char, acceptable input obs = seq.to_definites(degenerate="A") exp = ExampleGrammaredSequence("ABCAAAA") self.assertEqual(obs, exp) # noncanonical single char, acceptable input obs = seq.to_definites(degenerate="A", noncanonical=False) exp = ExampleGrammaredSequence("ABCQAAA") self.assertEqual(obs, exp) # test that single char outside of alphabet will throw error with self.assertRaises(ValueError): seq.to_definites("P") # test that an invalid wildcard (not a string) will throw an error ExampleGrammaredSequence.wildcard_char = 1 with self.assertRaises(ValueError): seq.to_definites() ExampleGrammaredSequence.wildcard_char = 'W' # test that nonsense input for 'to' will throw error with self.assertRaises(ValueError): seq.to_definites(degenerate='nonsense') def test_noncanonical_chars(self): self.assertTrue(isinstance(GrammaredSequence.noncanonical_chars, set)) self.assertEqual(len(GrammaredSequence.noncanonical_chars), 0) def test_wildcard_char(self): exp = None self.assertEqual(GrammaredSequence.wildcard_char, exp) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/test_nucleotide_sequences.py000066400000000000000000000513771520735541300302700ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy as np from skbio import DNA, RNA, Protein, GeneticCode from skbio.sequence._nucleotide_mixin import NucleotideMixin from skbio.sequence import GrammaredSequence from skbio.util import classproperty from skbio.metadata import IntervalMetadata # This file contains tests for functionality of sequence types which implement # NucleotideMixin. Currently this means DNA and RNA. These types are so # similar that the testing logic can be shared and parameterized across # different test data. class TestNucleotideSequence(unittest.TestCase): def setUp(self): self.sequence_kinds = frozenset([ str, lambda s: np.frombuffer(s.encode('ascii'), dtype='|S1'), lambda s: np.frombuffer(s.encode('ascii'), dtype=np.uint8)]) dna_str = 'ACGTMRWSYKVHDBN.-' dna_comp_str = 'TGCAKYWSRMBDHVN.-' dna_rev_comp_str = '-.NVHDBMRSWYKACGT' rna_str = 'ACGUMRWSYKVHDBN.-' rna_comp_str = 'UGCAKYWSRMBDHVN.-' rna_rev_comp_str = '-.NVHDBMRSWYKACGU' qual = tuple(range(len(dna_str))) self.dna = (DNA, dna_str) self.rna = (RNA, rna_str) dna_comp = self.dna + (dna_comp_str,) rna_comp = self.rna + (rna_comp_str,) dna_comp_qual = dna_comp + (qual,) rna_comp_qual = rna_comp + (qual,) self.all_combos_comp_qual = (dna_comp_qual, rna_comp_qual) dna_rev_comp = self.dna + (dna_rev_comp_str,) rna_rev_comp = self.rna + (rna_rev_comp_str,) self.all_combos_rev_comp = (dna_rev_comp, rna_rev_comp) dna_rev_comp_qual = dna_rev_comp + (qual,) rna_rev_comp_qual = rna_rev_comp + (qual,) self.all_combos_rev_comp_qual = \ (dna_rev_comp_qual, rna_rev_comp_qual) def test_instantiation_with_no_implementation(self): class NucleotideSequenceSubclassNoImplementation(NucleotideMixin): pass with self.assertRaises(TypeError) as cm: NucleotideSequenceSubclassNoImplementation() self.assertIn("abstract class", str(cm.exception)) self.assertIn("complement_map", str(cm.exception)) # TODO: remove when nondegenerate_chars is removed def test_nondegenerate_chars(self): dna = (DNA, "ACGT") rna = (RNA, "ACGU") for constructor, nondegenerate in (dna, rna): exp = set(nondegenerate) self.assertEqual(constructor('').nondegenerate_chars, exp) self.assertEqual(constructor.nondegenerate_chars, exp) def test_definite_chars(self): dna = (DNA, "ACGT") rna = (RNA, "ACGU") for constructor, definite_char in (dna, rna): exp = set(definite_char) self.assertEqual(constructor('').definite_chars, exp) self.assertEqual(constructor.definite_chars, exp) def test_degenerate_map(self): dna_exp = (DNA, { 'B': set(['C', 'T', 'G']), 'D': set(['A', 'T', 'G']), 'H': set(['A', 'C', 'T']), 'K': set(['T', 'G']), 'M': set(['A', 'C']), 'N': set(['A', 'C', 'T', 'G']), 'S': set(['C', 'G']), 'R': set(['A', 'G']), 'W': set(['A', 'T']), 'V': set(['A', 'C', 'G']), 'Y': set(['C', 'T']) }) rna_exp = (RNA, { 'B': set(['C', 'U', 'G']), 'D': set(['A', 'U', 'G']), 'H': set(['A', 'C', 'U']), 'K': set(['U', 'G']), 'M': set(['A', 'C']), 'N': set(['A', 'C', 'U', 'G']), 'S': set(['C', 'G']), 'R': set(['A', 'G']), 'W': set(['A', 'U']), 'V': set(['A', 'C', 'G']), 'Y': set(['C', 'U']) }) for constructor, degenerate in (dna_exp, rna_exp): self.assertEqual(constructor('').degenerate_map, degenerate) self.assertEqual(constructor.degenerate_map, degenerate) def test_complement_map(self): dna_exp = (DNA, { '-': '-', '.': '.', 'A': 'T', 'C': 'G', 'B': 'V', 'D': 'H', 'G': 'C', 'H': 'D', 'K': 'M', 'M': 'K', 'N': 'N', 'S': 'S', 'R': 'Y', 'T': 'A', 'W': 'W', 'V': 'B', 'Y': 'R' }) rna_exp = (RNA, { '-': '-', '.': '.', 'A': 'U', 'C': 'G', 'B': 'V', 'D': 'H', 'G': 'C', 'H': 'D', 'K': 'M', 'M': 'K', 'N': 'N', 'S': 'S', 'R': 'Y', 'U': 'A', 'W': 'W', 'V': 'B', 'Y': 'R' }) for constructor, comp_map in (dna_exp, rna_exp): self.assertEqual(constructor('').complement_map, comp_map) self.assertEqual(constructor.complement_map, comp_map) # immutable constructor.complement_map['A'] = 'X' constructor.complement_map['C'] = 'W' self.assertEqual(constructor.complement_map, comp_map) with self.assertRaises(AttributeError): constructor('').complement_map = {'W': 'X'} def test_translate_ncbi_table_id(self): for seq in RNA('AAAUUUAUGCAU'), DNA('AAATTTATGCAT'): # default obs = seq.translate() self.assertEqual(obs, Protein('KFMH')) obs = seq.translate(9) self.assertEqual(obs, Protein('NFMH')) def test_translate_genetic_code_object(self): gc = GeneticCode('M' * 64, '-' * 64) for seq in RNA('AAAUUUAUGCAU'), DNA('AAATTTATGCAT'): obs = seq.translate(gc) self.assertEqual(obs, Protein('MMMM')) def test_translate_passes_parameters_through(self): exp = Protein('MW') for seq in RNA('UAAAUUGUGGUAA'), DNA('TAAATTGTGGTAA'): # mix of args and kwargs obs = seq.translate(13, reading_frame=2, start='require', stop='require') self.assertEqual(obs, exp) # kwargs only obs = seq.translate(genetic_code=13, reading_frame=2, start='require', stop='require') self.assertEqual(obs, exp) # args only obs = seq.translate(13, 2, 'require', 'require') self.assertEqual(obs, exp) def test_translate_preserves_metadata(self): metadata = {'foo': 'bar', 'baz': 42} positional_metadata = {'foo': range(3)} for seq in (RNA('AUG', metadata=metadata, positional_metadata=positional_metadata), DNA('ATG', metadata=metadata, positional_metadata=positional_metadata)): obs = seq.translate() # metadata retained, positional metadata dropped self.assertEqual(obs, Protein('M', metadata={'foo': 'bar', 'baz': 42})) def test_translate_invalid_id(self): for seq in RNA('AUG'), DNA('ATG'): with self.assertRaisesRegex(ValueError, r'table_id.*42'): seq.translate(42) def test_translate_six_frames_ncbi_table_id(self): # rc = CAAUUU for seq in RNA('AAAUUG'), DNA('AAATTG'): # default obs = list(seq.translate_six_frames()) self.assertEqual(obs, [Protein('KL'), Protein('N'), Protein('I'), Protein('QF'), Protein('N'), Protein('I')]) obs = list(seq.translate_six_frames(9)) self.assertEqual(obs, [Protein('NL'), Protein('N'), Protein('I'), Protein('QF'), Protein('N'), Protein('I')]) def test_translate_six_frames_genetic_code_object(self): gc = GeneticCode('M' * 64, '-' * 64) for seq in RNA('AAAUUG'), DNA('AAATTG'): obs = list(seq.translate_six_frames(gc)) self.assertEqual(obs, [Protein('MM'), Protein('M'), Protein('M'), Protein('MM'), Protein('M'), Protein('M')]) def test_translate_six_frames_passes_parameters_through(self): for seq in RNA('UUUAUGUGGUGA'), DNA('TTTATGTGGTGA'): # mix of args and kwargs obs = next(seq.translate_six_frames(11, start='require', stop='require')) self.assertEqual(obs, Protein('MW')) # kwargs only obs = next(seq.translate_six_frames(genetic_code=11, start='require', stop='require')) self.assertEqual(obs, Protein('MW')) # args only obs = next(seq.translate_six_frames(11, 'require', 'require')) self.assertEqual(obs, Protein('MW')) def test_translate_six_frames_preserves_metadata(self): metadata = {'foo': 'bar', 'baz': 42} positional_metadata = {'foo': range(3)} for seq in (RNA('AUG', metadata=metadata, positional_metadata=positional_metadata), DNA('ATG', metadata=metadata, positional_metadata=positional_metadata)): obs = list(seq.translate_six_frames())[:2] # metadata retained, positional metadata dropped self.assertEqual( obs, [Protein('M', metadata={'foo': 'bar', 'baz': 42}), Protein('', metadata={'foo': 'bar', 'baz': 42})]) def test_translate_six_frames_invalid_id(self): for seq in RNA('AUG'), DNA('ATG'): with self.assertRaisesRegex(ValueError, r'table_id.*42'): seq.translate_six_frames(42) def test_repr(self): # basic sanity checks for custom repr stats. more extensive testing is # performed on Sequence.__repr__ for seq in DNA(''), RNA(''): obs = repr(seq) # obtained from super() self.assertIn('has gaps: False', obs) # custom to Protein self.assertIn('GC-content: 0.00%', obs) for seq in DNA('ACGT'), RNA('ACGU'): obs = repr(seq) self.assertIn('has gaps: False', obs) self.assertIn('GC-content: 50.00%', obs) for seq in DNA('CST'), RNA('CSU'): obs = repr(seq) self.assertIn('has gaps: False', obs) self.assertIn('GC-content: 66.67%', obs) for seq in DNA('GCSSCG'), RNA('GCSSCG'): obs = repr(seq) self.assertIn('has gaps: False', obs) self.assertIn('GC-content: 100.00%', obs) for seq in DNA('-GCSSCG.'), RNA('-GCSSCG.'): obs = repr(seq) self.assertIn('has gaps: True', obs) self.assertIn('GC-content: 100.00%', obs) def test_complement_without_reverse_empty(self): for constructor in (DNA, RNA): # without optional attributes comp = constructor('').complement() self.assertEqual(comp, constructor('')) # with optional attributes comp = constructor( '', metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': []}, interval_metadata=IntervalMetadata(0)).complement() self.assertEqual( comp, constructor( '', metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': []})) def test_complement_without_reverse_non_empty(self): for (constructor, seq_str, comp_str, qual) in self.all_combos_comp_qual: comp = constructor(seq_str).complement() self.assertEqual(comp, constructor(comp_str)) im = IntervalMetadata(len(seq_str)) im.add([(0, 1)], metadata={'gene': 'p53'}) comp = constructor( seq_str, metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': qual}, interval_metadata=im).complement() self.assertEqual( comp, constructor( comp_str, metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': qual}, interval_metadata=im)) def test_complement_with_reverse_empty(self): for constructor in (DNA, RNA): rc = constructor('').complement(reverse=True) self.assertEqual(rc, constructor('')) rc = constructor( '', metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': []}, interval_metadata=IntervalMetadata(0)).complement(reverse=True) self.assertEqual( rc, constructor( '', metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': []})) def test_complement_with_reverse_non_empty(self): for (constructor, seq_str, rev_comp_str, qual) in self.all_combos_rev_comp_qual: rc = constructor(seq_str).complement(reverse=True) self.assertEqual(rc, constructor(rev_comp_str)) length = len(seq_str) im = IntervalMetadata(length) im.add([(0, 1)], metadata={'gene': 'p53'}) im_rc = IntervalMetadata(length) im_rc.add([(length-1, length)], metadata={'gene': 'p53'}) original = constructor( seq_str, metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={ 'quality': qual}, interval_metadata=im) rc = original.complement(reverse=True) self.assertEqual( rc, constructor( rev_comp_str, metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': list(qual)[::-1]}, interval_metadata=im_rc)) # assert the original object is not changed self.assertIsNot(original.interval_metadata, im) self.assertEqual(original.interval_metadata, im) def test_reverse_complement(self): # light tests because this just calls # NucleotideSequence.complement(reverse=True), which is tested more # extensively for (constructor, seq_str, rev_comp_str, qual) in self.all_combos_rev_comp_qual: rc = constructor( seq_str, metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': qual}).reverse_complement() self.assertEqual( rc, constructor( rev_comp_str, metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': list(qual)[::-1]})) def test_is_reverse_complement_varied_types(self): tested = 0 for constructor, seq_str, rev_comp_str in self.all_combos_rev_comp: seq_kinds = self.sequence_kinds.union(frozenset([constructor])) for sequence in seq_kinds: tested += 1 seq1 = constructor(seq_str) seq2 = sequence(rev_comp_str) self.assertTrue(seq1.is_reverse_complement(seq2)) self.assertEqual(tested, 8) def test_is_reverse_complement_empty(self): for constructor in (DNA, RNA): seq1 = constructor('') self.assertTrue(seq1.is_reverse_complement(seq1)) # optional attributes are ignored, only the sequence is compared seq2 = constructor( '', metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': np.array([], dtype=np.int64)}) self.assertTrue(seq2.is_reverse_complement(seq2)) self.assertTrue(seq1.is_reverse_complement(seq2)) self.assertTrue(seq2.is_reverse_complement(seq1)) def test_is_reverse_complement_metadata_ignored(self): for (constructor, seq_str, rev_comp_str, qual) in self.all_combos_rev_comp_qual: seq1 = constructor(seq_str) seq2 = constructor( rev_comp_str, metadata={'id': 'foo', 'description': 'bar'}, positional_metadata={'quality': qual}) self.assertFalse(seq1.is_reverse_complement(seq1)) self.assertFalse(seq2.is_reverse_complement(seq2)) self.assertTrue(seq1.is_reverse_complement(seq2)) self.assertTrue(seq2.is_reverse_complement(seq1)) def test_is_reverse_complement_non_reverse_complements(self): for constructor in (DNA, RNA): # same length seq1 = constructor('ACAG') seq2 = constructor('AAAA') self.assertFalse(seq1.is_reverse_complement(seq1)) self.assertFalse(seq2.is_reverse_complement(seq2)) self.assertFalse(seq1.is_reverse_complement(seq2)) self.assertFalse(seq2.is_reverse_complement(seq1)) # different length seq1 = constructor('ACAG') seq2 = constructor('AAAAA') self.assertFalse(seq1.is_reverse_complement(seq1)) self.assertFalse(seq2.is_reverse_complement(seq2)) self.assertFalse(seq1.is_reverse_complement(seq2)) self.assertFalse(seq2.is_reverse_complement(seq1)) def test_is_reverse_complement_type_mismatch(self): for Class in (DNA, RNA): class DifferentSequenceClass(GrammaredSequence): @classproperty def degenerate_map(cls): return {"X": set("AB")} @classproperty def definite_chars(cls): return set("ABC") @classproperty def default_gap_char(cls): return '-' @classproperty def gap_chars(cls): return set('-.') seq1 = Class('ABC') seq2 = DifferentSequenceClass('ABC') with self.assertRaisesRegex(TypeError, r"Cannot use.*and " "DifferentSequenceClass together"): seq1.is_reverse_complement(seq2) def test_motif_purine_run(self): dna = (DNA, "AARC--TCRG", "AA-RC--TCR-G") rna = (RNA, "AARC--UCRG", "AA-RC--UCR-G") all_sets = (dna, rna) for constructor, run1, run2 in all_sets: seq = constructor("") self.assertEqual(list(seq.find_motifs("purine-run")), []) seq = constructor(run1) self.assertEqual(list(seq.find_motifs("purine-run")), [slice(0, 3), slice(8, 10)]) seq = constructor(run2) self.assertEqual(list(seq.find_motifs("purine-run", min_length=3, ignore=seq.gaps())), [slice(0, 4)]) def test_motif_pyrimidine_run(self): dna = (DNA, "AARC--TCRA", "AA-RC--TCR-A") rna = (RNA, "AARC--UCRG", "AA-RC--UCR-G") all_sets = (dna, rna) for constructor, run1, run2 in all_sets: seq = constructor("") self.assertEqual(list(seq.find_motifs("pyrimidine-run")), []) seq = constructor(run1) self.assertEqual(list(seq.find_motifs("pyrimidine-run")), [slice(3, 4), slice(6, 8)]) seq = constructor(run2) self.assertEqual(list(seq.find_motifs("pyrimidine-run", min_length=3, ignore=seq.gaps())), [slice(4, 9)]) def test_gc_frequency_and_gc_content(self): universal_sets = (('', 0, 0.0), ('ADDDH', 0, 0.0), ('ACGA', 2, 0.5), ('ACGS', 3, 0.75), ('AAAAAAAG', 1, 0.125), ('CCC', 3, 1.0), ('GGG', 3, 1.0), ('SSS', 3, 1.0), ('CGS', 3, 1.0), ('----....', 0, 0.0), ('G--..', 1, 1.0), ('ACGA', 2, 0.5)) dna = (DNA, universal_sets + (('ATMRWYKVHDBN.-', 0, 0.0),)) rna = (RNA, universal_sets + (('AUMRWYKVHDBN.-', 0, 0.0),)) for constructor, current_set in (dna, rna): for seq_str, count, ratio in current_set: seq = constructor(seq_str) self.assertEqual(count, seq.gc_frequency()) self.assertEqual(count, seq.gc_frequency(relative=False)) self.assertEqual(ratio, seq.gc_frequency(relative=True)) self.assertEqual(ratio, seq.gc_content()) if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/test_protein.py000066400000000000000000000117131520735541300255300ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy as np import numpy.testing as npt from skbio import Protein class TestProtein(unittest.TestCase): def test_alphabet(self): expected = set("ABCDEFGHIJKLMNOPQRSTUVWXYZ-.*") self.assertIs(type(Protein.alphabet), set) self.assertEqual(Protein.alphabet, expected) Protein.alphabet.add("&") self.assertEqual(Protein.alphabet, expected) self.assertEqual(Protein('').alphabet, expected) with self.assertRaises(AttributeError): Protein('').alphabet = set("ABCD") # TODO: duplicate of test_definite_chars, remove when nondegenerate_chars, # is removed def test_nondegenerate_chars(self): exp = set("ACDEFGHIKLMNOPQRSTUVWY") self.assertEqual(Protein("").nondegenerate_chars, exp) self.assertEqual(Protein.nondegenerate_chars, exp) def test_definite_chars(self): exp = set("ACDEFGHIKLMNOPQRSTUVWY") self.assertEqual(Protein("").definite_chars, exp) self.assertEqual(Protein.definite_chars, exp) def test_noncanonical_chars(self): exp = set("OU") self.assertEqual(Protein("").noncanonical_chars, exp) self.assertEqual(Protein.noncanonical_chars, exp) def test_wildcard_char(self): exp = "X" self.assertEqual(Protein("").wildcard_char, exp) self.assertEqual(Protein.wildcard_char, exp) def test_degenerate_map(self): exp = { 'B': set(['D', 'N']), 'Z': set(['E', 'Q']), 'J': set(['I', 'L']), 'X': set(['A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'Y']) } self.assertEqual(Protein("").degenerate_map, exp) self.assertEqual(Protein.degenerate_map, exp) def test_stop_chars(self): expected = set('*') self.assertIs(type(Protein.stop_chars), set) self.assertEqual(Protein.stop_chars, expected) Protein.stop_chars.add("JO") self.assertEqual(Protein.stop_chars, expected) self.assertEqual(Protein('').stop_chars, expected) with self.assertRaises(AttributeError): Protein('').stop_chars = set("^&") def test_stops(self): npt.assert_array_equal(Protein('').stops(), np.array([])) npt.assert_array_equal(Protein('P').stops(), np.array([False])) npt.assert_array_equal(Protein('PAW').stops(), np.array([False, False, False])) npt.assert_array_equal(Protein('PAW*').stops(), np.array([False, False, False, True])) npt.assert_array_equal(Protein('P*W*').stops(), np.array([False, True, False, True])) npt.assert_array_equal(Protein('****').stops(), np.array([True, True, True, True])) npt.assert_array_equal(Protein('XZB-.').stops(), np.array([False, False, False, False, False])) def test_has_stops(self): self.assertFalse(Protein('').has_stops()) self.assertFalse(Protein('P').has_stops()) self.assertFalse(Protein('PAW').has_stops()) self.assertTrue(Protein('PAW*').has_stops()) self.assertTrue(Protein('P*W*').has_stops()) self.assertTrue(Protein('****').has_stops()) self.assertFalse(Protein('XZB-.').has_stops()) def test_motif_n_glycosylation(self): seq = Protein("ACDFFACGNPSL") self.assertEqual(list(seq.find_motifs("N-glycosylation")), []) seq = Protein("ACDFNFTACGNPSL") self.assertEqual(list(seq.find_motifs("N-glycosylation")), [slice(4, 8)]) seq = Protein("AC-DFN-FTACGNPSL") self.assertEqual(list(seq.find_motifs("N-glycosylation", ignore=seq.gaps())), [slice(5, 10)]) def test_repr(self): # basic sanity checks for custom repr stats. more extensive testing is # performed on Sequence.__repr__ obs = repr(Protein('')) # obtained from super() self.assertIn('has gaps: False', obs) # custom to Protein self.assertIn('has stops: False', obs) obs = repr(Protein('PAW')) self.assertIn('has gaps: False', obs) self.assertIn('has stops: False', obs) obs = repr(Protein('PA*W-')) self.assertIn('has gaps: True', obs) self.assertIn('has stops: True', obs) obs = repr(Protein('*****')) self.assertIn('has gaps: False', obs) self.assertIn('has stops: True', obs) if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/test_rna.py000066400000000000000000000035711520735541300246330ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from skbio import DNA, RNA from skbio.metadata import IntervalMetadata # tests specific to RNA go here. tests for functionality shared by DNA and RNA # go in test_nucleotide_sequences.py class TestRNA(unittest.TestCase): def test_reverse_transcribe(self): # without changes self.assertEqual(RNA('').reverse_transcribe(), DNA('')) self.assertEqual(RNA('A').reverse_transcribe(), DNA('A')) self.assertEqual(RNA('.ACGW-').reverse_transcribe(), DNA('.ACGW-')) # with changes self.assertEqual(DNA('T'), RNA('U').reverse_transcribe()) self.assertEqual(DNA('TT'), RNA('UU').reverse_transcribe()) self.assertEqual(DNA('ATCTG'), RNA('AUCUG').reverse_transcribe()) self.assertEqual(DNA('TTTG'), RNA('UUUG').reverse_transcribe()) def test_reverse_transcribe_preserves_all_metadata(self): im = IntervalMetadata(4) im.add([(0, 2)], metadata={'gene': 'p53'}) seq = RNA('AGUU', metadata={'foo': 'bar'}, positional_metadata={'foo': range(4)}, interval_metadata=im) exp = DNA('AGTT', metadata={'foo': 'bar'}, positional_metadata={'foo': range(4)}, interval_metadata=im) self.assertEqual(seq.reverse_transcribe(), exp) def test_reverse_transcribe_does_not_modify_input(self): seq = RNA('AUAU') self.assertEqual(seq.reverse_transcribe(), DNA('ATAT')) self.assertEqual(seq, RNA('AUAU')) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/test_sequence.py000066400000000000000000003404771520735541300256740ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import copy import functools import itertools import re from types import GeneratorType from collections.abc import Hashable from unittest import TestCase, main import numpy as np import numpy.testing as npt import pandas as pd from scipy.spatial.distance import hamming as sp_hamming from skbio.sequence.distance import hamming as sk_hamming from skbio import Sequence, DNA, SubstitutionMatrix from skbio.util import assert_data_frame_almost_equal from skbio.sequence._sequence import (_single_index_to_slice, _is_single_index, _as_slice_if_single_index) from skbio.util._testing import ReallyEqualMixin from skbio.metadata._testing import (MetadataMixinTests, IntervalMetadataMixinTests, PositionalMetadataMixinTests) from skbio.metadata import IntervalMetadata class SequenceSubclass(Sequence): """Used for testing purposes.""" pass class SequenceSubclassTwo(Sequence): """Used for testing purposes.""" pass class TestSequenceMetadata(TestCase, ReallyEqualMixin, MetadataMixinTests): def setUp(self): self._metadata_constructor_ = functools.partial(Sequence, '') class TestSequencePositionalMetadata(TestCase, ReallyEqualMixin, PositionalMetadataMixinTests): def setUp(self): def factory(axis_len, positional_metadata=None): return Sequence('Z' * axis_len, positional_metadata=positional_metadata) self._positional_metadata_constructor_ = factory class TestSequenceIntervalMetadata(TestCase, ReallyEqualMixin, IntervalMetadataMixinTests): def setUp(self): super()._set_up() def factory(axis_len, interval_metadata=None): return Sequence('Z' * axis_len, interval_metadata=interval_metadata) self._interval_metadata_constructor_ = factory class TestSequenceBase(TestCase): def setUp(self): self.sequence_kinds = frozenset([ str, Sequence, lambda s: np.frombuffer(s.encode('ascii'), dtype='|S1'), lambda s: np.frombuffer(s.encode('ascii'), dtype=np.uint8)]) class TestSequence(TestSequenceBase, ReallyEqualMixin): def setUp(self): super(TestSequence, self).setUp() self.lowercase_seq = Sequence('AAAAaaaa', lowercase='key') def empty_generator(): yield from () self.getitem_empty_indices = [ [], (), {}, empty_generator(), # ndarray of implicit float dtype np.array([]), np.array([], dtype=int)] def test_concat_bad_how(self): seq1 = seq2 = Sequence("123") with self.assertRaises(ValueError): Sequence.concat([seq1, seq2], how='foo') def test_concat_on_subclass(self): seq1 = SequenceSubclass("123") seq2 = Sequence("123") result = SequenceSubclass.concat([seq1, seq2]) self.assertIs(type(result), SequenceSubclass) self.assertEqual(result, SequenceSubclass("123123")) def test_concat_on_empty_iterator(self): result = SequenceSubclass.concat((_ for _ in [])) self.assertIs(type(result), SequenceSubclass) self.assertEqual(result, SequenceSubclass("")) def test_concat_on_bad_subclass(self): seq1 = Sequence("123") seq2 = SequenceSubclassTwo("123") with self.assertRaises(TypeError): SequenceSubclass.concat([seq1, seq2]) def test_concat_interval_metadata(self): seq1 = Sequence("1234") seq1.interval_metadata.add( [(0, 2)], [(True, False)], {'gene': 'sagA'}) seq2 = Sequence("5678") seq2.interval_metadata.add( [(1, 3)], [(False, True)], {'gene': 'sagB'}) obs = Sequence.concat([seq1, seq2]) exp = Sequence('12345678') exp.interval_metadata.add( [(0, 2)], [(True, False)], {'gene': 'sagA'}) exp.interval_metadata.add( [(5, 7)], [(False, True)], {'gene': 'sagB'}) self.assertEqual(exp, obs) def test_concat_one_seq_has_none_interval_metadata(self): seq1 = Sequence("1234") seq1.interval_metadata.add( [(0, 2)], [(True, False)], {'gene': 'sagA'}) seq2 = Sequence("5678") seq3 = Sequence("910") seq3.interval_metadata.add( [(1, 3)], [(False, True)], {'gene': 'sagB'}) obs = Sequence.concat([seq1, seq2, seq3]) exp = Sequence('12345678910') exp.interval_metadata.add( [(0, 2)], [(True, False)], {'gene': 'sagA'}) exp.interval_metadata.add( [(9, 11)], [(False, True)], {'gene': 'sagB'}) self.assertEqual(exp, obs) def test_concat_default_how(self): seq1 = Sequence("1234", positional_metadata={'a': [1]*4}) seq2 = Sequence("5678", positional_metadata={'a': [2]*4}) seqbad = Sequence("9", positional_metadata={'b': [9]}) result1 = Sequence.concat([seq1, seq2]) result2 = Sequence.concat([seq1, seq2], how='strict') self.assertEqual(result1, result2) with self.assertRaisesRegex(ValueError, r'.*positional.*metadata.*inner.*outer.*'): Sequence.concat([seq1, seq2, seqbad]) def test_concat_strict_simple(self): expected = Sequence( "12345678", positional_metadata={'a': [1, 1, 1, 1, 2, 2, 2, 2]}) seq1 = Sequence("1234", positional_metadata={'a': [1]*4}) seq2 = Sequence("5678", positional_metadata={'a': [2]*4}) result = Sequence.concat([seq1, seq2], how='strict') self.assertEqual(result, expected) self.assertFalse(result.metadata) def test_concat_strict_many(self): odd_key = frozenset() expected = Sequence("13579", positional_metadata={odd_key: [1, 2, 3, 4, 5], 'a': list('skbio')}) result = Sequence.concat([ Sequence("1", positional_metadata={'a': ['s'], odd_key: [1]}), Sequence("3", positional_metadata={'a': ['k'], odd_key: [2]}), Sequence("5", positional_metadata={'a': ['b'], odd_key: [3]}), Sequence("7", positional_metadata={'a': ['i'], odd_key: [4]}), Sequence("9", positional_metadata={'a': ['o'], odd_key: [5]}) ], how='strict') self.assertEqual(result, expected) self.assertFalse(result.metadata) def test_concat_strict_fail(self): seq1 = Sequence("1", positional_metadata={'a': [1]}) seq2 = Sequence("2", positional_metadata={'b': [2]}) with self.assertRaisesRegex(ValueError, r'.*positional.*metadata.*inner.*outer.*'): Sequence.concat([seq1, seq2], how='strict') def test_concat_outer_simple(self): seq1 = Sequence("1234") seq2 = Sequence("5678") result = Sequence.concat([seq1, seq2], how='outer') self.assertEqual(result, Sequence("12345678")) self.assertFalse(result.metadata) def test_concat_outer_missing(self): a = {} b = {} seq1 = Sequence("12", positional_metadata={'a': ['1', '2']}) seq2 = Sequence("34", positional_metadata={'b': [3, 4], 'c': [a, b]}) seq3 = Sequence("56") seq4 = Sequence("78", positional_metadata={'a': [7, 8]}) seq5 = Sequence("90", positional_metadata={'b': [9, 0]}) result = Sequence.concat([seq1, seq2, seq3, seq4, seq5], how='outer') expected = Sequence("1234567890", positional_metadata={ 'a': ['1', '2', np.nan, np.nan, np.nan, np.nan, 7, 8, np.nan, np.nan], 'b': [np.nan, np.nan, 3, 4, np.nan, np.nan, np.nan, np.nan, 9, 0], 'c': [np.nan, np.nan, a, b, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan] }) self.assertEqual(result, expected) self.assertFalse(result.metadata) def test_concat_inner_simple(self): seq1 = Sequence("1234") seq2 = Sequence("5678", positional_metadata={'discarded': [1] * 4}) result = Sequence.concat([seq1, seq2], how='inner') self.assertEqual(result, Sequence("12345678")) self.assertFalse(result.metadata) def test_concat_inner_missing(self): seq1 = Sequence("12", positional_metadata={'a': ['1', '2'], 'c': [{}, {}]}) seq2 = Sequence("34", positional_metadata={'a': [3, 4], 'b': [3, 4]}) seq3 = Sequence("56", positional_metadata={'a': [5, 6], 'b': [5, 6]}) result = Sequence.concat([seq1, seq2, seq3], how='inner') expected = Sequence("123456", positional_metadata={'a': ['1', '2', 3, 4, 5, 6]}) self.assertEqual(result, expected) self.assertFalse(result.metadata) def test_init_default_parameters(self): seq = Sequence('.ABC123xyz-') npt.assert_equal(seq.values, np.array('.ABC123xyz-', dtype='c')) self.assertEqual('.ABC123xyz-', str(seq)) self.assertFalse(seq.metadata) self.assertEqual(seq.metadata, {}) assert_data_frame_almost_equal(seq.positional_metadata, pd.DataFrame(index=range(11))) self.assertEqual(seq.interval_metadata, IntervalMetadata(len(seq))) def test_init_nondefault_parameters(self): s = '.ABC123xyz-' im = IntervalMetadata(len(s)) im.add([(0, 1)], metadata={'gene': 'sagA'}) seq = Sequence(s, metadata={'id': 'foo', 'description': 'bar baz'}, positional_metadata={'quality': range(11)}, interval_metadata=im) self.assertEqual(seq.interval_metadata, im) npt.assert_equal(seq.values, np.array('.ABC123xyz-', dtype='c')) self.assertEqual(s, str(seq)) self.assertTrue(seq.metadata) self.assertEqual(seq.metadata, {'id': 'foo', 'description': 'bar baz'}) assert_data_frame_almost_equal( seq.positional_metadata, pd.DataFrame({'quality': range(11)}, index=range(11))) def test_init_empty_sequence(self): # Test constructing an empty sequence using each supported input type. for s in (b'', # bytes '', # unicode np.array('', dtype='c'), # char vector np.frombuffer(b'', dtype=np.uint8), # byte vec Sequence('')): # another Sequence object seq = Sequence(s) self.assertIsInstance(seq.values, np.ndarray) self.assertEqual(seq.values.dtype, '|S1') self.assertEqual(seq.values.shape, (0, )) npt.assert_equal(seq.values, np.array('', dtype='c')) self.assertEqual(str(seq), '') self.assertEqual(len(seq), 0) self.assertFalse(seq.metadata) self.assertEqual(seq.metadata, {}) self.assertEqual(seq.interval_metadata, IntervalMetadata(0)) assert_data_frame_almost_equal(seq.positional_metadata, pd.DataFrame(index=range(0))) def test_init_single_character_sequence(self): for s in (b'A', 'A', np.array('A', dtype='c'), np.frombuffer(b'A', dtype=np.uint8), Sequence('A')): seq = Sequence(s) self.assertIsInstance(seq.values, np.ndarray) self.assertEqual(seq.values.dtype, '|S1') self.assertEqual(seq.values.shape, (1,)) npt.assert_equal(seq.values, np.array('A', dtype='c')) self.assertEqual(str(seq), 'A') self.assertEqual(len(seq), 1) self.assertFalse(seq.metadata) self.assertEqual(seq.metadata, {}) self.assertEqual(seq.interval_metadata, IntervalMetadata(1)) assert_data_frame_almost_equal(seq.positional_metadata, pd.DataFrame(index=range(1))) def test_init_multiple_character_sequence(self): for s in (b'.ABC\t123 xyz-', '.ABC\t123 xyz-', np.array('.ABC\t123 xyz-', dtype='c'), np.frombuffer(b'.ABC\t123 xyz-', dtype=np.uint8), Sequence('.ABC\t123 xyz-')): seq = Sequence(s) self.assertIsInstance(seq.values, np.ndarray) self.assertEqual(seq.values.dtype, '|S1') self.assertEqual(seq.values.shape, (14,)) npt.assert_equal(seq.values, np.array('.ABC\t123 xyz-', dtype='c')) self.assertEqual(str(seq), '.ABC\t123 xyz-') self.assertEqual(len(seq), 14) self.assertFalse(seq.metadata) self.assertEqual(seq.metadata, {}) self.assertEqual(seq.interval_metadata, IntervalMetadata(14)) assert_data_frame_almost_equal(seq.positional_metadata, pd.DataFrame(index=range(14))) def test_init_from_sequence_object(self): # We're testing this in its simplest form in other tests. This test # exercises more complicated cases of building a sequence from another # sequence. # just the sequence, no other metadata seq = Sequence('ACGT') self.assertEqual(Sequence(seq), seq) # sequence with metadata should have everything propagated seq = Sequence('ACGT', metadata={'id': 'foo', 'description': 'bar baz'}, positional_metadata={'quality': range(4)}) seq.interval_metadata.add([(0, 1)], metadata={'gene': 'sagA'}) self.assertEqual(Sequence(seq), seq) # should be able to override metadata im = IntervalMetadata(4) im.add([(0, 2)], metadata={'gene': 'sagB'}) self.assertEqual( Sequence(seq, metadata={'id': 'abc', 'description': '123'}, positional_metadata={'quality': [42] * 4}, interval_metadata=im), Sequence('ACGT', metadata={'id': 'abc', 'description': '123'}, positional_metadata={'quality': [42] * 4}, interval_metadata=im)) # subclasses work too im = IntervalMetadata(4) im.add([(0, 2)], metadata={'gene': 'sagB'}) seq = SequenceSubclass('ACGT', metadata={'id': 'foo', 'description': 'bar baz'}, positional_metadata={'quality': range(4)}, interval_metadata=im) self.assertEqual( Sequence(seq), Sequence('ACGT', metadata={'id': 'foo', 'description': 'bar baz'}, positional_metadata={'quality': range(4)}, interval_metadata=im)) def test_init_from_non_descendant_sequence_object(self): seq = SequenceSubclass('ACGT') with self.assertRaises(TypeError) as cm: SequenceSubclassTwo(seq) error = str(cm.exception) self.assertIn("SequenceSubclass", error) self.assertIn("SequenceSubclassTwo", error) self.assertIn("cast", error) def test_init_from_contiguous_sequence_bytes_view(self): bytes = np.array([65, 42, 66, 42, 65], dtype=np.uint8) view = bytes[:3] seq = Sequence(view) # sequence should be what we'd expect self.assertEqual(seq, Sequence('A*B')) # we shouldn't own the memory because no copy should have been made self.assertFalse(seq._owns_bytes) # can't mutate view because it isn't writeable anymore with self.assertRaises(ValueError): view[1] = 100 # sequence shouldn't have changed self.assertEqual(seq, Sequence('A*B')) # mutate bytes (*not* the view) bytes[0] = 99 # Sequence changed because we are only able to make the view read-only, # not its source (bytes). This is somewhat inconsistent behavior that # is (to the best of our knowledge) outside our control. self.assertEqual(seq, Sequence('c*B')) def test_init_from_noncontiguous_sequence_bytes_view(self): bytes = np.array([65, 42, 66, 42, 65], dtype=np.uint8) view = bytes[::2] seq = Sequence(view) # sequence should be what we'd expect self.assertEqual(seq, Sequence('ABA')) # we should own the memory because a copy should have been made self.assertTrue(seq._owns_bytes) # mutate bytes and its view bytes[0] = 99 view[1] = 100 # sequence shouldn't have changed self.assertEqual(seq, Sequence('ABA')) def test_init_no_copy_of_sequence(self): bytes = np.array([65, 66, 65], dtype=np.uint8) seq = Sequence(bytes) # should share the same memory self.assertIs(seq._bytes, bytes) # shouldn't be able to mutate the Sequence object's internals by # mutating the shared memory with self.assertRaises(ValueError): bytes[1] = 42 def test_init_invalid_sequence(self): # invalid dtype (numpy.ndarray input) with self.assertRaises(TypeError): # int64 Sequence(np.array([1, 2, 3])) with self.assertRaises(TypeError): # |S21 Sequence(np.array([1, "23", 3])) with self.assertRaises(TypeError): # object Sequence(np.array([1, {}, ()], dtype=object)) # invalid input type (non-numpy.ndarray input) with self.assertRaisesRegex(TypeError, r'tuple'): Sequence(('a', 'b', 'c')) with self.assertRaisesRegex(TypeError, r'list'): Sequence(['a', 'b', 'c']) with self.assertRaisesRegex(TypeError, r'set'): Sequence({'a', 'b', 'c'}) with self.assertRaisesRegex(TypeError, r'dict'): Sequence({'a': 42, 'b': 43, 'c': 44}) with self.assertRaisesRegex(TypeError, r'int'): Sequence(42) with self.assertRaisesRegex(TypeError, r'float'): Sequence(4.2) with self.assertRaisesRegex(TypeError, r'int64'): Sequence(np.int64(50)) with self.assertRaisesRegex(TypeError, r'float64'): Sequence(np.float64(50)) with self.assertRaisesRegex(TypeError, r'Foo'): class Foo: pass Sequence(Foo()) # out of ASCII range with self.assertRaises(UnicodeEncodeError): Sequence('abc\u1F30') def test_values_property(self): # Property tests are only concerned with testing the interface # provided by the property: that it can be accessed, can't be # reassigned or mutated in place, and that the correct type is # returned. More extensive testing of border cases (e.g., different # sequence lengths or input types, odd characters, etc.) are performed # in Sequence.__init__ tests. seq = Sequence('ACGT') # should get back a numpy.ndarray of '|S1' dtype self.assertIsInstance(seq.values, np.ndarray) self.assertEqual(seq.values.dtype, '|S1') npt.assert_equal(seq.values, np.array('ACGT', dtype='c')) # test that we can't mutate the property with self.assertRaises(ValueError): seq.values[1] = 'A' # test that we can't set the property with self.assertRaises(AttributeError): seq.values = np.array("GGGG", dtype='c') def test_sequence_numpy_compatibility(self): seq = Sequence('abc123') array = np.asarray(seq) self.assertIsInstance(array, np.ndarray) self.assertEqual(array.dtype, '|S1') npt.assert_equal(array, np.array('abc123', dtype='c')) npt.assert_equal(array, seq.values) with self.assertRaises(ValueError): array[1] = 'B' def test_observed_chars_property(self): self.assertEqual(Sequence('').observed_chars, set()) self.assertEqual(Sequence('x').observed_chars, {'x'}) self.assertEqual(Sequence('xYz').observed_chars, {'x', 'Y', 'z'}) self.assertEqual(Sequence('zzz').observed_chars, {'z'}) self.assertEqual(Sequence('xYzxxZz').observed_chars, {'x', 'Y', 'z', 'Z'}) self.assertEqual(Sequence('\t ').observed_chars, {' ', '\t'}) im = IntervalMetadata(6) im.add([(0, 2)], metadata={'gene': 'sagB'}) self.assertEqual( Sequence('aabbcc', metadata={'foo': 'bar'}, positional_metadata={'foo': range(6)}, interval_metadata=im).observed_chars, {'a', 'b', 'c'}) with self.assertRaises(AttributeError): Sequence('ACGT').observed_chars = {'a', 'b', 'c'} def test_eq_and_ne(self): seq_a = Sequence("A") seq_b = Sequence("B") im = IntervalMetadata(1) im.add([(0, 1)], metadata={'gene': 'sagA'}) im2 = IntervalMetadata(1) im.add([(0, 1)], metadata={'gene': 'sagB'}) self.assertTrue(seq_a == seq_a) self.assertTrue(Sequence("a") == Sequence("a")) self.assertTrue(Sequence("a", metadata={'id': 'b'}) == Sequence("a", metadata={'id': 'b'})) self.assertTrue(Sequence("a", metadata={'id': 'b', 'description': 'c'}) == Sequence("a", metadata={'id': 'b', 'description': 'c'})) self.assertTrue(Sequence("a", metadata={'id': 'b', 'description': 'c'}, positional_metadata={'quality': [1]}, interval_metadata=im) == Sequence("a", metadata={'id': 'b', 'description': 'c'}, positional_metadata={'quality': [1]}, interval_metadata=im)) self.assertTrue(seq_a != seq_b) self.assertTrue(SequenceSubclass("a") != Sequence("a")) self.assertTrue(Sequence("a") != Sequence("b")) self.assertTrue(Sequence("a") != Sequence("a", metadata={'id': 'b'})) self.assertTrue(Sequence("a", metadata={'id': 'c'}) != Sequence("a", metadata={'id': 'c', 'description': 't'})) self.assertTrue(Sequence("a", positional_metadata={'quality': [1]}) != Sequence("a")) self.assertTrue(Sequence("a", interval_metadata=im) != Sequence("a")) self.assertTrue(Sequence("a", positional_metadata={'quality': [1]}) != Sequence("a", positional_metadata={'quality': [2]})) self.assertTrue(Sequence("a", interval_metadata=im) != Sequence("a", interval_metadata=im2)) self.assertTrue(Sequence("c", positional_metadata={'quality': [3]}) != Sequence("b", positional_metadata={'quality': [3]})) self.assertTrue(Sequence("c", interval_metadata=im) != Sequence("b", interval_metadata=im)) self.assertTrue(Sequence("a", metadata={'id': 'b'}) != Sequence("c", metadata={'id': 'b'})) def test_eq_sequences_without_metadata_compare_equal(self): self.assertTrue(Sequence('') == Sequence('')) self.assertTrue(Sequence('z') == Sequence('z')) self.assertTrue( Sequence('ACGT') == Sequence('ACGT')) def test_eq_sequences_with_metadata_compare_equal(self): seq1 = Sequence('ACGT', metadata={'id': 'foo', 'desc': 'abc'}, positional_metadata={'qual': [1, 2, 3, 4]}) seq2 = Sequence('ACGT', metadata={'id': 'foo', 'desc': 'abc'}, positional_metadata={'qual': [1, 2, 3, 4]}) self.assertTrue(seq1 == seq2) # order shouldn't matter self.assertTrue(seq2 == seq1) def test_eq_sequences_from_different_sources_compare_equal(self): # sequences that have the same data but are constructed from different # types of data should compare equal im = IntervalMetadata(4) im.add([(0, 2)], metadata={'gene': 'sagB'}) seq1 = Sequence('ACGT', metadata={'id': 'foo', 'desc': 'abc'}, positional_metadata={'quality': np.array((1, 2, 3, 4), dtype=np.int64)}, interval_metadata=im) seq2 = Sequence(np.array([65, 67, 71, 84], dtype=np.uint8), metadata={'id': 'foo', 'desc': 'abc'}, positional_metadata={'quality': np.array([1, 2, 3, 4], dtype=np.int64)}, interval_metadata=im) self.assertTrue(seq1 == seq2) def test_eq_type_mismatch(self): seq1 = Sequence('ACGT') seq2 = SequenceSubclass('ACGT') self.assertFalse(seq1 == seq2) def test_eq_positional_metadata_mismatch(self): # both provided seq1 = Sequence('ACGT', positional_metadata={'quality': [1, 2, 3, 4]}) seq2 = Sequence('ACGT', positional_metadata={'quality': [1, 2, 3, 5]}) self.assertFalse(seq1 == seq2) # one provided seq1 = Sequence('ACGT', positional_metadata={'quality': [1, 2, 3, 4]}) seq2 = Sequence('ACGT') self.assertFalse(seq1 == seq2) def test_eq_interval_metadata_mismatch(self): im1 = IntervalMetadata(4) im1.add([(0, 3)], metadata={'gene': 'sagA'}) im2 = IntervalMetadata(4) im2.add([(0, 2)], metadata={'gene': 'sagA'}) # both provided seq1 = Sequence('ACGT', interval_metadata=im1) seq2 = Sequence('ACGT', interval_metadata=im2) self.assertFalse(seq1 == seq2) # one provided seq1 = Sequence('ACGT', interval_metadata=im1) seq2 = Sequence('ACGT') self.assertFalse(seq1 == seq2) def test_eq_sequence_mismatch(self): seq1 = Sequence('ACGT') seq2 = Sequence('TGCA') self.assertFalse(seq1 == seq2) def test_getitem_gives_new_sequence(self): seq = Sequence("Sequence string !1@2#3?.,") self.assertFalse(seq is seq[:]) def test_getitem_drops_interval_metadata(self): s = "Sequence string !1@2#3?.," seq = Sequence(s, metadata={'id': 'id', 'description': 'dsc'}) seq.interval_metadata.add([(0, 3)], metadata={'gene': 'sagA'}) eseq = Sequence('Se', metadata={'id': 'id', 'description': 'dsc'}) self.assertEqual(seq[:2], eseq) def test_getitem_with_int_has_positional_metadata(self): s = "Sequence string !1@2#3?.," length = len(s) seq = Sequence(s, metadata={'id': 'id', 'description': 'dsc'}, positional_metadata={'quality': np.arange(length, dtype=np.int64)}) eseq = Sequence("S", {'id': 'id', 'description': 'dsc'}, positional_metadata={'quality': np.array([0], dtype=np.int64)}) self.assertEqual(seq[0], eseq) eseq = Sequence(",", metadata={'id': 'id', 'description': 'dsc'}, positional_metadata={'quality': np.array([len(seq) - 1], dtype=np.int64)}) self.assertEqual(seq[len(seq) - 1], eseq) eseq = Sequence("t", metadata={'id': 'id', 'description': 'dsc'}, positional_metadata={'quality': np.asarray([10], dtype=np.int64)}) self.assertEqual(seq[10], eseq) def test_single_index_to_slice(self): a = [1, 2, 3, 4] self.assertEqual(slice(0, 1), _single_index_to_slice(0)) self.assertEqual([1], a[_single_index_to_slice(0)]) self.assertEqual(slice(-1, None), _single_index_to_slice(-1)) self.assertEqual([4], a[_single_index_to_slice(-1)]) def test_is_single_index(self): self.assertTrue(_is_single_index(0)) self.assertFalse(_is_single_index(True)) self.assertFalse(_is_single_index(bool())) self.assertFalse(_is_single_index('a')) def test_as_slice_if_single_index(self): self.assertEqual(slice(0, 1), _as_slice_if_single_index(0)) slice_obj = slice(2, 3) self.assertIs(slice_obj, _as_slice_if_single_index(slice_obj)) def test_slice_positional_metadata(self): seq = Sequence('ABCDEFGHIJ', positional_metadata={'foo': np.arange(10, dtype=np.int64), 'bar': np.arange(100, 110, dtype=np.int64)}) self.assertTrue(pd.DataFrame({'foo': [0], 'bar': [100]}, dtype=np.int64).equals( seq._slice_positional_metadata(0))) self.assertTrue(pd.DataFrame({'foo': [0], 'bar': [100]}).equals( seq._slice_positional_metadata(slice(0, 1)))) self.assertTrue(pd.DataFrame({'foo': [0, 1], 'bar': [100, 101]}).equals( seq._slice_positional_metadata(slice(0, 2)))) self.assertTrue(pd.DataFrame( {'foo': [9], 'bar': [109]}, index=[9]).equals( seq._slice_positional_metadata(9))) def test_getitem_with_int_no_positional_metadata(self): seq = Sequence("Sequence string !1@2#3?.,", metadata={'id': 'id2', 'description': 'no_qual'}) eseq = Sequence("t", metadata={'id': 'id2', 'description': 'no_qual'}) self.assertEqual(seq[10], eseq) def test_getitem_with_slice_has_positional_metadata(self): s = "0123456789abcdef" length = len(s) seq = Sequence(s, metadata={'id': 'id3', 'description': 'dsc3'}, positional_metadata={'quality': np.arange(length, dtype=np.int64)}) eseq = Sequence("012", metadata={'id': 'id3', 'description': 'dsc3'}, positional_metadata={'quality': np.arange(3, dtype=np.int64)}) self.assertEqual(seq[0:3], eseq) self.assertEqual(seq[:3], eseq) self.assertEqual(seq[:3:1], eseq) eseq = Sequence("def", metadata={'id': 'id3', 'description': 'dsc3'}, positional_metadata={'quality': np.asarray([13, 14, 15], dtype=np.int64)}) self.assertEqual(seq[-3:], eseq) self.assertEqual(seq[-3::1], eseq) eseq = Sequence("02468ace", metadata={'id': 'id3', 'description': 'dsc3'}, positional_metadata={'quality': np.asarray([0, 2, 4, 6, 8, 10, 12, 14], dtype=np.int64)}) self.assertEqual(seq[0:length:2], eseq) self.assertEqual(seq[::2], eseq) eseq = Sequence(s[::-1], metadata={'id': 'id3', 'description': 'dsc3'}, positional_metadata={'quality': np.arange(length, dtype=np.int64)[::-1]}) self.assertEqual(seq[length::-1], eseq) self.assertEqual(seq[::-1], eseq) eseq = Sequence('fdb97531', metadata={'id': 'id3', 'description': 'dsc3'}, positional_metadata={'quality': np.asarray([15, 13, 11, 9, 7, 5, 3, 1], dtype=np.int64)}) self.assertEqual(seq[length::-2], eseq) self.assertEqual(seq[::-2], eseq) self.assertEqual(seq[0:500:], seq) eseq = Sequence('', metadata={'id': 'id3', 'description': 'dsc3'}, positional_metadata={'quality': np.array([], dtype=np.int64)}) self.assertEqual(seq[length:0], eseq) self.assertEqual(seq[-length:0], eseq) self.assertEqual(seq[1:0], eseq) eseq = Sequence("0", metadata={'id': 'id3', 'description': 'dsc3'}, positional_metadata={'quality': np.asarray([0], dtype=np.int64)}) self.assertEqual(seq[0:1], eseq) self.assertEqual(seq[0:1:1], eseq) self.assertEqual(seq[-length::-1], eseq) def test_getitem_with_slice_no_positional_metadata(self): s = "0123456789abcdef" length = len(s) seq = Sequence(s, metadata={'id': 'id4', 'description': 'no_qual4'}) eseq = Sequence("02468ace", metadata={'id': 'id4', 'description': 'no_qual4'}) self.assertEqual(seq[0:length:2], eseq) self.assertEqual(seq[::2], eseq) def test_getitem_with_tuple_of_mixed_with_positional_metadata(self): s = "0123456789abcdef" length = len(s) seq = Sequence(s, metadata={'id': 'id5', 'description': 'dsc5'}, positional_metadata={'quality': np.arange(length, dtype=np.int64)}) eseq = Sequence("00000", metadata={'id': 'id5', 'description': 'dsc5'}, positional_metadata={'quality': np.asarray([0, 0, 0, 0, 0], dtype=np.int64)}) self.assertEqual(seq[0, 0, 0, 0, 0], eseq) self.assertEqual(seq[0, 0:1, 0, 0, 0], eseq) self.assertEqual(seq[0, 0:1, 0, -length::-1, 0, 1:0], eseq) self.assertEqual(seq[0:1, 0:1, 0:1, 0:1, 0:1], eseq) self.assertEqual(seq[0:1, 0, 0, 0, 0], eseq) eseq = Sequence("0123fed9", metadata={'id': 'id5', 'description': 'dsc5'}, positional_metadata={'quality': [0, 1, 2, 3, 15, 14, 13, 9]}) self.assertEqual(seq[0, 1, 2, 3, 15, 14, 13, 9], eseq) self.assertEqual(seq[0, 1, 2, 3, :-4:-1, 9], eseq) self.assertEqual(seq[0:4, :-4:-1, 9, 1:0], eseq) self.assertEqual(seq[0:4, :-4:-1, 9:10], eseq) def test_getitem_with_tuple_of_mixed_no_positional_metadata(self): seq = Sequence("0123456789abcdef", metadata={'id': 'id6', 'description': 'no_qual6'}) eseq = Sequence("0123fed9", metadata={'id': 'id6', 'description': 'no_qual6'}) self.assertEqual(seq[0, 1, 2, 3, 15, 14, 13, 9], eseq) self.assertEqual(seq[0, 1, 2, 3, :-4:-1, 9], eseq) self.assertEqual(seq[0:4, :-4:-1, 9], eseq) self.assertEqual(seq[0:4, :-4:-1, 9:10], eseq) def test_getitem_with_tuple_of_mixed_no_metadata(self): seq = Sequence("0123456789abcdef") eseq = Sequence("0123fed9") self.assertEqual(seq[0, 1, 2, 3, 15, 14, 13, 9], eseq) self.assertEqual(seq[0, 1, 2, 3, :-4:-1, 9], eseq) self.assertEqual(seq[0:4, :-4:-1, 9], eseq) self.assertEqual(seq[0:4, :-4:-1, 9:10], eseq) def test_getitem_with_iterable_of_mixed_has_positional_metadata(self): s = "0123456789abcdef" length = len(s) seq = Sequence(s, metadata={'id': 'id7', 'description': 'dsc7'}, positional_metadata={'quality': np.arange(length, dtype=np.int64)}) def generator(): yield slice(0, 4) yield slice(200, 400) yield -1 yield slice(-2, -4, -1) yield 9 eseq = Sequence("0123fed9", metadata={'id': 'id7', 'description': 'dsc7'}, positional_metadata={'quality': np.asarray([0, 1, 2, 3, 15, 14, 13, 9], dtype=np.int64)}) self.assertEqual(seq[[0, 1, 2, 3, 15, 14, 13, 9]], eseq) self.assertEqual(seq[generator()], eseq) self.assertEqual(seq[[slice(0, 4), slice(None, -4, -1), 9]], eseq) self.assertEqual(seq[ [slice(0, 4), slice(None, -4, -1), slice(9, 10)]], eseq) def test_getitem_with_iterable_of_mixed_no_positional_metadata(self): s = "0123456789abcdef" seq = Sequence(s, metadata={'id': 'id7', 'description': 'dsc7'}) def generator(): yield slice(0, 4) yield slice(200, 400) yield slice(None, -4, -1) yield 9 eseq = Sequence("0123fed9", metadata={'id': 'id7', 'description': 'dsc7'}) self.assertEqual(seq[[0, 1, 2, 3, 15, 14, 13, 9]], eseq) self.assertEqual(seq[generator()], eseq) self.assertEqual(seq[[slice(0, 4), slice(None, -4, -1), 9]], eseq) self.assertEqual(seq[ [slice(0, 4), slice(None, -4, -1), slice(9, 10)]], eseq) def test_getitem_with_numpy_index_has_positional_metadata(self): s = "0123456789abcdef" length = len(s) seq = Sequence(s, metadata={'id': 'id9', 'description': 'dsc9'}, positional_metadata={'quality': np.arange(length, dtype=np.int64)}) eseq = Sequence("0123fed9", metadata={'id': 'id9', 'description': 'dsc9'}, positional_metadata={'quality': np.asarray([0, 1, 2, 3, 15, 14, 13, 9], dtype=np.int64)}) self.assertEqual(seq[np.array([0, 1, 2, 3, 15, 14, 13, 9])], eseq) def test_getitem_with_numpy_index_no_positional_metadata(self): s = "0123456789abcdef" seq = Sequence(s, metadata={'id': 'id10', 'description': 'dsc10'}) eseq = Sequence("0123fed9", metadata={'id': 'id10', 'description': 'dsc10'}) self.assertEqual(seq[np.array([0, 1, 2, 3, 15, 14, 13, 9])], eseq) def test_getitem_with_empty_indices_empty_seq_no_pos_metadata(self): s = "" seq = Sequence(s, metadata={'id': 'id10', 'description': 'dsc10'}) eseq = Sequence('', metadata={'id': 'id10', 'description': 'dsc10'}) tested = 0 for index in self.getitem_empty_indices: tested += 1 self.assertEqual(seq[index], eseq) self.assertEqual(tested, 6) def test_getitem_with_empty_indices_non_empty_seq_no_pos_metadata(self): s = "0123456789abcdef" seq = Sequence(s, metadata={'id': 'id10', 'description': 'dsc10'}) eseq = Sequence('', metadata={'id': 'id10', 'description': 'dsc10'}) tested = 0 for index in self.getitem_empty_indices: tested += 1 self.assertEqual(seq[index], eseq) self.assertEqual(tested, 6) def test_getitem_with_boolean_vector_has_qual(self): s = "0123456789abcdef" length = len(s) seq = Sequence(s, metadata={'id': 'id11', 'description': 'dsc11'}, positional_metadata={'quality': np.arange(length, dtype=np.int64)}) eseq = Sequence("13579bdf", metadata={'id': 'id11', 'description': 'dsc11'}, positional_metadata={'quality': np.asarray([1, 3, 5, 7, 9, 11, 13, 15], dtype=np.int64)}) self.assertEqual(seq[np.array([False, True] * 8)], eseq) self.assertEqual(seq[[False, True] * 8], eseq) def test_getitem_with_boolean_vector_no_positional_metadata(self): s = "0123456789abcdef" seq = Sequence(s, metadata={'id': 'id11', 'description': 'dsc11'}) eseq = Sequence("13579bdf", metadata={'id': 'id11', 'description': 'dsc11'}) self.assertEqual(seq[np.array([False, True] * 8)], eseq) def test_getitem_with_invalid(self): seq = Sequence("123456", metadata={'id': 'idm', 'description': 'description'}, positional_metadata={'quality': [1, 2, 3, 4, 5, 6]}) with self.assertRaises(IndexError): seq['not an index'] with self.assertRaises(IndexError): seq[['1', '2']] with self.assertRaises(IndexError): seq[[1, slice(1, 2), 'a']] with self.assertRaises(IndexError): seq[[1, slice(1, 2), True]] with self.assertRaises(IndexError): seq[True] with self.assertRaises(IndexError): seq[np.array([True, False])] with self.assertRaises(IndexError): seq[999] with self.assertRaises(IndexError): seq[0, 0, 999] # numpy 1.8.1 and 1.9.2 raise different error types # (ValueError, IndexError). with self.assertRaises(Exception): seq[100 * [True, False, True]] def test_getitem_empty_positional_metadata(self): seq = Sequence('ACGT') seq.positional_metadata # This will create empty positional_metadata self.assertEqual(Sequence('A'), seq[0]) def test_len(self): self.assertEqual(len(Sequence("")), 0) self.assertEqual(len(Sequence("a")), 1) self.assertEqual(len(Sequence("abcdef")), 6) def test_nonzero(self): # blank self.assertFalse(Sequence("")) self.assertFalse(Sequence("", metadata={'id': 'foo'}, positional_metadata={'quality': range(0)})) # single self.assertTrue(Sequence("A")) self.assertTrue(Sequence("A", metadata={'id': 'foo'}, positional_metadata={'quality': range(1)})) # multi self.assertTrue(Sequence("ACGT")) self.assertTrue(Sequence("ACGT", metadata={'id': 'foo'}, positional_metadata={'quality': range(4)})) def test_contains(self): seq = Sequence("#@ACGT,24.13**02") tested = 0 for c in self.sequence_kinds: tested += 1 self.assertTrue(c(',24') in seq) self.assertTrue(c('*') in seq) self.assertTrue(c('') in seq) self.assertFalse(c("$") in seq) self.assertFalse(c("AGT") in seq) self.assertEqual(tested, 4) def test_contains_sequence_subclass(self): with self.assertRaises(TypeError): SequenceSubclass("A") in Sequence("AAA") self.assertTrue(SequenceSubclass("A").values in Sequence("AAA")) def test_hash(self): with self.assertRaises(TypeError): hash(Sequence("ABCDEFG")) self.assertNotIsInstance(Sequence("ABCDEFG"), Hashable) def test_iter_has_positional_metadata(self): tested = False seq = Sequence("0123456789", metadata={'id': 'a', 'desc': 'b'}, positional_metadata={'qual': np.arange(10, dtype=np.int64)}) for i, s in enumerate(seq): tested = True self.assertEqual(s, Sequence(str(i), metadata={'id': 'a', 'desc': 'b'}, positional_metadata={'qual': np.asarray([i], dtype=np.int64)})) self.assertTrue(tested) def test_iter_no_positional_metadata(self): tested = False seq = Sequence("0123456789", metadata={'id': 'a', 'desc': 'b'}) for i, s in enumerate(seq): tested = True self.assertEqual(s, Sequence(str(i), metadata={'id': 'a', 'desc': 'b'})) self.assertTrue(tested) def test_reversed_has_positional_metadata(self): tested = False seq = Sequence("0123456789", metadata={'id': 'a', 'desc': 'b'}, positional_metadata={'qual': np.arange(10, dtype=np.int64)}) for i, s in enumerate(reversed(seq)): tested = True self.assertEqual(s, Sequence(str(9 - i), metadata={'id': 'a', 'desc': 'b'}, positional_metadata={'qual': np.asarray([9 - i], dtype=np.int64)})) self.assertTrue(tested) def test_reversed_no_positional_metadata(self): tested = False seq = Sequence("0123456789", metadata={'id': 'a', 'desc': 'b'}) for i, s in enumerate(reversed(seq)): tested = True self.assertEqual(s, Sequence(str(9 - i), metadata={'id': 'a', 'desc': 'b'})) self.assertTrue(tested) def test_repr(self): # basic sanity checks -- more extensive testing of formatting and # special cases is performed in SequenceReprDoctests below. here we # only test that pieces of the repr are present. these tests also # exercise coverage in case doctests stop counting towards coverage in # the future # minimal obs = repr(Sequence('')) self.assertEqual(obs.count('\n'), 4) self.assertTrue(obs.startswith('Sequence')) self.assertIn('length: 0', obs) self.assertTrue(obs.endswith('-')) # no metadata obs = repr(Sequence('ACGT')) self.assertEqual(obs.count('\n'), 5) self.assertTrue(obs.startswith('Sequence')) self.assertIn('length: 4', obs) self.assertTrue(obs.endswith('0 ACGT')) # metadata and positional metadata of mixed types obs = repr( Sequence( 'ACGT', metadata={'foo': 'bar', b'bar': 33.33, None: True, False: {}, (1, 2): 3, 'acb' * 100: "'", 10: 11}, positional_metadata={'foo': range(4), 42: ['a', 'b', [], 'c']})) self.assertEqual(obs.count('\n'), 16) self.assertTrue(obs.startswith('Sequence')) self.assertIn('None: True', obs) self.assertIn('\'foo\': \'bar\'', obs) self.assertIn('42: ', obs) self.assertIn('\'foo\': ', obs) self.assertIn('length: 4', obs) self.assertTrue(obs.endswith('0 ACGT')) # sequence spanning > 5 lines obs = repr(Sequence('A' * 301)) self.assertEqual(obs.count('\n'), 9) self.assertTrue(obs.startswith('Sequence')) self.assertIn('length: 301', obs) self.assertIn('...', obs) self.assertTrue(obs.endswith('300 A')) def test_str(self): self.assertEqual(str(Sequence("GATTACA")), "GATTACA") self.assertEqual(str(Sequence("ACCGGTACC")), "ACCGGTACC") self.assertEqual(str(Sequence("GREG")), "GREG") self.assertEqual( str(Sequence("ABC", positional_metadata={'quality': [1, 2, 3]})), "ABC") self.assertIs(type(str(Sequence("A"))), str) def test_count(self): def construct_char_array(s): return np.frombuffer(s.encode('ascii'), dtype='|S1') def construct_uint8_array(s): return np.frombuffer(s.encode('ascii'), dtype=np.uint8) seq = Sequence("1234567899876555") tested = 0 for c in self.sequence_kinds: tested += 1 self.assertEqual(seq.count(c('4')), 1) self.assertEqual(seq.count(c('8')), 2) self.assertEqual(seq.count(c('5')), 4) self.assertEqual(seq.count(c('555')), 1) self.assertEqual(seq.count(c('555'), 0, 4), 0) self.assertEqual(seq.count(c('555'), start=0, end=4), 0) self.assertEqual(seq.count(c('5'), start=10), 3) self.assertEqual(seq.count(c('5'), end=10), 1) with self.assertRaises(ValueError): seq.count(c('')) self.assertEqual(tested, 4) def test_count_on_subclass(self): with self.assertRaises(TypeError) as cm: Sequence("abcd").count(SequenceSubclass("a")) self.assertIn("Sequence", str(cm.exception)) self.assertIn("SequenceSubclass", str(cm.exception)) def test_replace_sanity(self): seq = Sequence('AAGCATGCCCTTTACATTTG') index = self._make_index('10011011001111110111') obs = seq.replace(index, '_') exp = Sequence('_AG__T__CC______T___') self.assertEqual(obs, exp) def test_replace_index_array(self): seq = Sequence('TCGGGTGTTGTGCAACCACC') for _type in list, tuple, np.array, pd.Series: index = _type([0, 2, 5, 8, 9]) obs = seq.replace(index, '-') exp = Sequence('-C-GG-GT--TGCAACCACC') self.assertEqual(obs, exp) def test_replace_iterable_slices(self): seq = Sequence('CATTATGGACCCAGCGTGCC') slices = (slice(0, 5), slice(8, 12), slice(15, 17)) mixed_slices = (0, 1, 2, 3, 4, slice(8, 12), 15, 16) for _type in (lambda x: x, list, tuple, lambda x: np.array(tuple(x)), lambda x: pd.Series(tuple(x))): index = (_type(slices), _type(mixed_slices)) obs_slices = seq.replace(index[0], '-') obs_mixed = seq.replace(index[1], '-') exp = Sequence('-----TGG----AGC--GCC') self.assertEqual(obs_slices, exp) self.assertEqual(obs_mixed, exp) def test_replace_index_in_positional_metadata(self): positional_metadata = {'where': self._make_index('001110110' '10001110000')} seq = Sequence('AAGATTGATACCACAGTTGT', positional_metadata=positional_metadata) obs = seq.replace('where', '-') exp = Sequence('AA---T--T-CCA---TTGT', positional_metadata=positional_metadata) self.assertEqual(obs, exp) def test_replace_does_not_mutate_original(self): seq = Sequence('ATCG') index = self._make_index('0011') seq.replace(index, '-') obs = seq exp = Sequence('ATCG') self.assertEqual(obs, exp) def test_replace_with_metadata(self): seq = Sequence('GCACGGCAAGAAGCGCCCCA', metadata={'NM': 'Kestrel Gorlick'}, positional_metadata={'diff': list('01100001110010001100')}) seq.interval_metadata.add([(0, 1)], metadata={'gene': 'sagA'}) index = self._make_index('01100001110010001100') obs = seq.replace(index, '-') exp = Sequence('G--CGGC---AA-CGC--CA', metadata={'NM': 'Kestrel Gorlick'}, positional_metadata={'diff': list('01100001110010001100')}) exp.interval_metadata.add([(0, 1)], metadata={'gene': 'sagA'}) self.assertEqual(obs, exp) def test_replace_with_subclass(self): seq = DNA('CGACAACCGATGTGCTGTAA') index = self._make_index('10101000111111110011') obs = seq.replace(index, '-') exp = DNA('-G-C-ACC--------GT--') self.assertEqual(obs, exp) def test_replace_with_bytes(self): seq = Sequence('ABC123') obs = seq.replace([1, 3, 5], b'*') self.assertEqual(obs, Sequence('A*C*2*')) def test_replace_invalid_char_for_type_error(self): seq = DNA('TAAACGGAACGCTACGTCTG') index = self._make_index('01000001101011001001') with self.assertRaisesRegex(ValueError, r"Invalid character.*'F'"): seq.replace(index, 'F') def test_replace_invalid_char_error(self): seq = Sequence('GGGAGCTAGA') index = self._make_index('1000101110') with self.assertRaisesRegex(UnicodeEncodeError, r"can't encode character.*not in " r"range\(128\)"): seq.replace(index, '\uFFFF') def test_replace_non_single_character_error(self): seq = Sequence('CCGAACTGTC') index = self._make_index('1100110011') with self.assertRaisesRegex(TypeError, r'string of length 2 found'): seq.replace(index, 'AB') def _make_index(self, bools): return [bool(int(char)) for char in bools] def test_lowercase_mungeable_key(self): # NOTE: This test relies on Sequence._munge_to_index_array working # properly. If the internal implementation of the lowercase method # changes to no longer use _munge_to_index_array, this test may need # to be updated to cover cases currently covered by # _munge_to_index_array self.assertEqual('AAAAaaaa', self.lowercase_seq.lowercase('key')) def test_lowercase_array_key(self): # NOTE: This test relies on Sequence._munge_to_index_array working # properly. If the internal implementation of the lowercase method # changes to no longer use _munge_to_index_array, this test may need # to be updated to cover cases currently covered by # _munge_to_index_array self.assertEqual('aaAAaaaa', self.lowercase_seq.lowercase( np.array([True, True, False, False, True, True, True, True]))) self.assertEqual('AaAAaAAA', self.lowercase_seq.lowercase([1, 4])) def test_matches(self): tested = 0 for constructor in self.sequence_kinds: tested += 1 seq1 = Sequence("AACCEEGG") seq2 = constructor("ABCDEFGH") expected = np.array([True, False] * 4) npt.assert_equal(seq1.matches(seq2), expected) self.assertEqual(tested, 4) def test_matches_on_subclass(self): seq1 = Sequence("AACCEEGG") seq2 = SequenceSubclass("ABCDEFGH") with self.assertRaises(TypeError): seq1.matches(seq2) def test_matches_unequal_length(self): seq1 = Sequence("AACCEEGG") seq2 = Sequence("TOOLONGTOCOMPARE") with self.assertRaises(ValueError): seq1.matches(seq2) def test_mismatches(self): tested = 0 for constructor in self.sequence_kinds: tested += 1 seq1 = Sequence("AACCEEGG") seq2 = constructor("ABCDEFGH") expected = np.array([False, True] * 4) npt.assert_equal(seq1.mismatches(seq2), expected) self.assertEqual(tested, 4) def test_mismatches_on_subclass(self): seq1 = Sequence("AACCEEGG") seq2 = SequenceSubclass("ABCDEFGH") with self.assertRaises(TypeError): seq1.mismatches(seq2) def test_mismatches_unequal_length(self): seq1 = Sequence("AACCEEGG") seq2 = Sequence("TOOLONGTOCOMPARE") with self.assertRaises(ValueError): seq1.mismatches(seq2) def test_mismatch_frequency(self): seq1 = Sequence("AACCEEGG") seq2 = Sequence("ABCDEFGH") seq3 = Sequence("TTTTTTTT") self.assertIs(type(seq1.mismatch_frequency(seq1)), int) self.assertEqual(seq1.mismatch_frequency(seq1), 0) self.assertEqual(seq1.mismatch_frequency(seq2), 4) self.assertEqual(seq1.mismatch_frequency(seq3), 8) def test_mismatch_frequency_relative(self): seq1 = Sequence("AACCEEGG") seq2 = Sequence("ABCDEFGH") seq3 = Sequence("TTTTTTTT") self.assertIs(type(seq1.mismatch_frequency(seq1, relative=True)), float) self.assertEqual(seq1.mismatch_frequency(seq1, relative=True), 0.0) self.assertEqual(seq1.mismatch_frequency(seq2, relative=True), 0.5) self.assertEqual(seq1.mismatch_frequency(seq3, relative=True), 1.0) def test_mismatch_frequency_unequal_length(self): seq1 = Sequence("AACCEEGG") seq2 = Sequence("TOOLONGTOCOMPARE") with self.assertRaises(ValueError): seq1.mismatch_frequency(seq2) def test_mismatch_frequence_on_subclass(self): seq1 = Sequence("AACCEEGG") seq2 = SequenceSubclass("ABCDEFGH") with self.assertRaises(TypeError): seq1.mismatch_frequency(seq2) def test_match_frequency(self): seq1 = Sequence("AACCEEGG") seq2 = Sequence("ABCDEFGH") seq3 = Sequence("TTTTTTTT") self.assertIs(type(seq1.match_frequency(seq1)), int) self.assertEqual(seq1.match_frequency(seq1), 8) self.assertEqual(seq1.match_frequency(seq2), 4) self.assertEqual(seq1.match_frequency(seq3), 0) def test_match_frequency_relative(self): seq1 = Sequence("AACCEEGG") seq2 = Sequence("ABCDEFGH") seq3 = Sequence("TTTTTTTT") self.assertIs(type(seq1.match_frequency(seq1, relative=True)), float) self.assertEqual(seq1.match_frequency(seq1, relative=True), 1.0) self.assertEqual(seq1.match_frequency(seq2, relative=True), 0.5) self.assertEqual(seq1.match_frequency(seq3, relative=True), 0.0) def test_match_frequency_unequal_length(self): seq1 = Sequence("AACCEEGG") seq2 = Sequence("TOOLONGTOCOMPARE") with self.assertRaises(ValueError): seq1.match_frequency(seq2) def test_match_frequency_on_subclass(self): seq1 = Sequence("AACCEEGG") seq2 = SequenceSubclass("ABCDEFGH") with self.assertRaises(TypeError): seq1.match_frequency(seq2) def test_index(self): tested = 0 for c in self.sequence_kinds: tested += 1 seq = Sequence("ABCDEFG@@ABCDFOO") self.assertEqual(seq.index(c("A")), 0) self.assertEqual(seq.index(c("@")), 7) self.assertEqual(seq.index(c("@@")), 7) with self.assertRaises(ValueError): seq.index("A", start=1, end=5) self.assertEqual(tested, 4) def test_index_on_subclass(self): with self.assertRaises(TypeError): Sequence("ABCDEFG").index(SequenceSubclass("A")) self.assertEqual( SequenceSubclass("ABCDEFG").index(SequenceSubclass("A")), 0) def test_frequencies_empty_sequence(self): seq = Sequence('') self.assertEqual(seq.frequencies(), {}) self.assertEqual(seq.frequencies(relative=True), {}) self.assertEqual(seq.frequencies(chars=set()), {}) self.assertEqual(seq.frequencies(chars=set(), relative=True), {}) self.assertEqual(seq.frequencies(chars={'a', 'b'}), {'a': 0, 'b': 0}) # use npt.assert_equal to explicitly handle nan comparisons npt.assert_equal(seq.frequencies(chars={'a', 'b'}, relative=True), {'a': np.nan, 'b': np.nan}) def test_frequencies_observed_chars(self): seq = Sequence('x') self.assertEqual(seq.frequencies(), {'x': 1}) self.assertEqual(seq.frequencies(relative=True), {'x': 1.0}) seq = Sequence('xYz') self.assertEqual(seq.frequencies(), {'x': 1, 'Y': 1, 'z': 1}) self.assertEqual(seq.frequencies(relative=True), {'x': 1/3, 'Y': 1/3, 'z': 1/3}) seq = Sequence('zzz') self.assertEqual(seq.frequencies(), {'z': 3}) self.assertEqual(seq.frequencies(relative=True), {'z': 1.0}) seq = Sequence('xYzxxZz') self.assertEqual(seq.frequencies(), {'x': 3, 'Y': 1, 'Z': 1, 'z': 2}) self.assertEqual(seq.frequencies(relative=True), {'x': 3/7, 'Y': 1/7, 'Z': 1/7, 'z': 2/7}) seq = Sequence('\t ') self.assertEqual(seq.frequencies(), {'\t': 1, ' ': 3}) self.assertEqual(seq.frequencies(relative=True), {'\t': 1/4, ' ': 3/4}) seq = Sequence('aabbcc', metadata={'foo': 'bar'}, positional_metadata={'foo': range(6)}) self.assertEqual(seq.frequencies(), {'a': 2, 'b': 2, 'c': 2}) self.assertEqual(seq.frequencies(relative=True), {'a': 2/6, 'b': 2/6, 'c': 2/6}) def test_frequencies_specified_chars(self): seq = Sequence('abcbca') self.assertEqual(seq.frequencies(chars=set()), {}) self.assertEqual(seq.frequencies(chars=set(), relative=True), {}) self.assertEqual(seq.frequencies(chars='a'), {'a': 2}) self.assertEqual(seq.frequencies(chars='a', relative=True), {'a': 2/6}) self.assertEqual(seq.frequencies(chars={'a'}), {'a': 2}) self.assertEqual(seq.frequencies(chars={'a'}, relative=True), {'a': 2/6}) self.assertEqual(seq.frequencies(chars={'a', 'b'}), {'a': 2, 'b': 2}) self.assertEqual(seq.frequencies(chars={'a', 'b'}, relative=True), {'a': 2/6, 'b': 2/6}) self.assertEqual(seq.frequencies(chars={'a', 'b', 'd'}), {'a': 2, 'b': 2, 'd': 0}) self.assertEqual(seq.frequencies(chars={'a', 'b', 'd'}, relative=True), {'a': 2/6, 'b': 2/6, 'd': 0.0}) self.assertEqual(seq.frequencies(chars={'x', 'y', 'z'}), {'x': 0, 'y': 0, 'z': 0}) self.assertEqual(seq.frequencies(chars={'x', 'y', 'z'}, relative=True), {'x': 0.0, 'y': 0.0, 'z': 0.0}) def test_frequencies_chars_varied_type(self): seq = Sequence('zabczzzabcz') # single character case (shortcut) chars = b'z' self.assertEqual(seq.frequencies(chars=chars), {b'z': 5}) self.assertEqual(seq.frequencies(chars=chars, relative=True), {b'z': 5/11}) chars = 'z' self.assertEqual(seq.frequencies(chars=chars), {'z': 5}) self.assertEqual(seq.frequencies(chars=chars, relative=True), {'z': 5/11}) chars = np.frombuffer('z'.encode('ascii'), dtype='|S1')[0] self.assertEqual(seq.frequencies(chars=chars), {b'z': 5}) self.assertEqual(seq.frequencies(chars=chars, relative=True), {b'z': 5/11}) # set of characters, some present, some not chars = {b'x', b'z'} self.assertEqual(seq.frequencies(chars=chars), {b'x': 0, b'z': 5}) self.assertEqual(seq.frequencies(chars=chars, relative=True), {b'x': 0.0, b'z': 5/11}) chars = {'x', 'z'} self.assertEqual(seq.frequencies(chars=chars), {'x': 0, 'z': 5}) self.assertEqual(seq.frequencies(chars=chars, relative=True), {'x': 0.0, 'z': 5/11}) chars = { np.frombuffer('x'.encode('ascii'), dtype='|S1')[0], np.frombuffer('z'.encode('ascii'), dtype='|S1')[0] } self.assertEqual(seq.frequencies(chars=chars), {b'x': 0, b'z': 5}) self.assertEqual(seq.frequencies(chars=chars, relative=True), {b'x': 0.0, b'z': 5/11}) def test_frequencies_equivalent_to_kmer_frequencies_k_of_1(self): seq = Sequence('abcabc') exp = {'a': 2, 'b': 2, 'c': 2} self.assertEqual(seq.frequencies(chars=None), exp) self.assertEqual(seq.kmer_frequencies(k=1), exp) exp = {'a': 2/6, 'b': 2/6, 'c': 2/6} self.assertEqual(seq.frequencies(chars=None, relative=True), exp) self.assertEqual(seq.kmer_frequencies(k=1, relative=True), exp) def test_frequencies_passing_observed_chars_equivalent_to_default(self): seq = Sequence('abcabc') exp = {'a': 2, 'b': 2, 'c': 2} self.assertEqual(seq.frequencies(chars=None), exp) self.assertEqual(seq.frequencies(chars=seq.observed_chars), exp) exp = {'a': 2/6, 'b': 2/6, 'c': 2/6} self.assertEqual(seq.frequencies(chars=None, relative=True), exp) self.assertEqual( seq.frequencies(chars=seq.observed_chars, relative=True), exp) def test_frequencies_invalid_chars(self): seq = Sequence('abcabc') with self.assertRaisesRegex(ValueError, r'0 characters'): seq.frequencies(chars='') with self.assertRaisesRegex(ValueError, r'0 characters'): seq.frequencies(chars={''}) with self.assertRaisesRegex(ValueError, r'2 characters'): seq.frequencies(chars='ab') with self.assertRaisesRegex(ValueError, r'2 characters'): seq.frequencies(chars={'b', 'ab'}) with self.assertRaisesRegex(TypeError, r'string.*NoneType'): seq.frequencies(chars={'a', None}) with self.assertRaisesRegex(ValueError, r'outside the range'): seq.frequencies(chars='\u1F30') with self.assertRaisesRegex(ValueError, r'outside the range'): seq.frequencies(chars={'c', '\u1F30'}) with self.assertRaisesRegex(TypeError, r'set.*int'): seq.frequencies(chars=42) def _compare_kmers_results(self, observed, expected): for obs, exp in itertools.zip_longest(observed, expected, fillvalue=None): self.assertEqual(obs, exp) def test_iter_kmers(self): seq = Sequence('GATTACA', positional_metadata={'quality': range(7)}) expected = [ Sequence('G', positional_metadata={'quality': [0]}), Sequence('A', positional_metadata={'quality': [1]}), Sequence('T', positional_metadata={'quality': [2]}), Sequence('T', positional_metadata={'quality': [3]}), Sequence('A', positional_metadata={'quality': [4]}), Sequence('C', positional_metadata={'quality': [5]}), Sequence('A', positional_metadata={'quality': [6]}) ] self._compare_kmers_results( seq.iter_kmers(1, overlap=False), expected) expected = [ Sequence('GA', positional_metadata={'quality': [0, 1]}), Sequence('TT', positional_metadata={'quality': [2, 3]}), Sequence('AC', positional_metadata={'quality': [4, 5]}) ] self._compare_kmers_results( seq.iter_kmers(2, overlap=False), expected) expected = [ Sequence('GAT', positional_metadata={'quality': [0, 1, 2]}), Sequence('TAC', positional_metadata={'quality': [3, 4, 5]}) ] self._compare_kmers_results( seq.iter_kmers(3, overlap=False), expected) expected = [ Sequence('GATTACA', positional_metadata={'quality': [0, 1, 2, 3, 4, 5, 6]}) ] self._compare_kmers_results( seq.iter_kmers(7, overlap=False), expected) expected = [] self._compare_kmers_results( seq.iter_kmers(8, overlap=False), expected) self.assertIs(type(seq.iter_kmers(1)), GeneratorType) def test_iter_kmers_no_positional_metadata(self): seq = Sequence('GATTACA') expected = [ Sequence('G'), Sequence('A'), Sequence('T'), Sequence('T'), Sequence('A'), Sequence('C'), Sequence('A') ] self._compare_kmers_results( seq.iter_kmers(1, overlap=False), expected) expected = [ Sequence('GA'), Sequence('TT'), Sequence('AC') ] self._compare_kmers_results( seq.iter_kmers(2, overlap=False), expected) expected = [ Sequence('GAT'), Sequence('TAC') ] self._compare_kmers_results( seq.iter_kmers(3, overlap=False), expected) expected = [ Sequence('GATTACA') ] self._compare_kmers_results( seq.iter_kmers(7, overlap=False), expected) expected = [] self._compare_kmers_results( seq.iter_kmers(8, overlap=False), expected) self.assertIs(type(seq.iter_kmers(1)), GeneratorType) def test_iter_kmers_with_overlap(self): seq = Sequence('GATTACA', positional_metadata={'quality': range(7)}) expected = [ Sequence('G', positional_metadata={'quality': [0]}), Sequence('A', positional_metadata={'quality': [1]}), Sequence('T', positional_metadata={'quality': [2]}), Sequence('T', positional_metadata={'quality': [3]}), Sequence('A', positional_metadata={'quality': [4]}), Sequence('C', positional_metadata={'quality': [5]}), Sequence('A', positional_metadata={'quality': [6]}) ] self._compare_kmers_results( seq.iter_kmers(1, overlap=True), expected) expected = [ Sequence('GA', positional_metadata={'quality': [0, 1]}), Sequence('AT', positional_metadata={'quality': [1, 2]}), Sequence('TT', positional_metadata={'quality': [2, 3]}), Sequence('TA', positional_metadata={'quality': [3, 4]}), Sequence('AC', positional_metadata={'quality': [4, 5]}), Sequence('CA', positional_metadata={'quality': [5, 6]}) ] self._compare_kmers_results( seq.iter_kmers(2, overlap=True), expected) expected = [ Sequence('GAT', positional_metadata={'quality': [0, 1, 2]}), Sequence('ATT', positional_metadata={'quality': [1, 2, 3]}), Sequence('TTA', positional_metadata={'quality': [2, 3, 4]}), Sequence('TAC', positional_metadata={'quality': [3, 4, 5]}), Sequence('ACA', positional_metadata={'quality': [4, 5, 6]}) ] self._compare_kmers_results( seq.iter_kmers(3, overlap=True), expected) expected = [ Sequence('GATTACA', positional_metadata={'quality': [0, 1, 2, 3, 4, 5, 6]}) ] self._compare_kmers_results( seq.iter_kmers(7, overlap=True), expected) expected = [] self._compare_kmers_results( seq.iter_kmers(8, overlap=True), expected) self.assertIs(type(seq.iter_kmers(1)), GeneratorType) def test_iter_kmers_with_overlap_no_positional_metadata(self): seq = Sequence('GATTACA') expected = [ Sequence('G'), Sequence('A'), Sequence('T'), Sequence('T'), Sequence('A'), Sequence('C'), Sequence('A') ] self._compare_kmers_results( seq.iter_kmers(1, overlap=True), expected) expected = [ Sequence('GA'), Sequence('AT'), Sequence('TT'), Sequence('TA'), Sequence('AC'), Sequence('CA') ] self._compare_kmers_results( seq.iter_kmers(2, overlap=True), expected) expected = [ Sequence('GAT'), Sequence('ATT'), Sequence('TTA'), Sequence('TAC'), Sequence('ACA') ] self._compare_kmers_results( seq.iter_kmers(3, overlap=True), expected) expected = [ Sequence('GATTACA') ] self._compare_kmers_results( seq.iter_kmers(7, overlap=True), expected) expected = [] self._compare_kmers_results( seq.iter_kmers(8, overlap=True), expected) self.assertIs(type(seq.iter_kmers(1)), GeneratorType) def test_iter_kmers_large_k(self): """Addressing issue 1723.""" # k larger than sequence length seq = Sequence('TATATA') expected = [] self._compare_kmers_results(seq.iter_kmers(10), expected) # k equal to sequence length expected = [Sequence('TATATA'), ] self._compare_kmers_results(seq.iter_kmers(6), expected) # with positional metadata seq = Sequence('GATTACA', positional_metadata={'quality': range(7)}) expected = [] self._compare_kmers_results(seq.iter_kmers(10), expected) def test_iter_kmers_invalid_k(self): seq = Sequence('GATTACA', positional_metadata={'quality': range(7)}) with self.assertRaises(ValueError): list(seq.iter_kmers(0)) with self.assertRaises(ValueError): list(seq.iter_kmers(-42)) def test_iter_kmers_invalid_k_no_positional_metadata(self): seq = Sequence('GATTACA') with self.assertRaises(ValueError): list(seq.iter_kmers(0)) with self.assertRaises(ValueError): list(seq.iter_kmers(-42)) def test_iter_kmers_different_sequences(self): seq = Sequence('HE..--..LLO', metadata={'id': 'hello', 'desc': 'gapped hello'}, positional_metadata={'quality': range(11)}) expected = [ Sequence('HE.', positional_metadata={'quality': [0, 1, 2]}, metadata={'id': 'hello', 'desc': 'gapped hello'}), Sequence('.--', positional_metadata={'quality': [3, 4, 5]}, metadata={'id': 'hello', 'desc': 'gapped hello'}), Sequence('..L', positional_metadata={'quality': [6, 7, 8]}, metadata={'id': 'hello', 'desc': 'gapped hello'}) ] self._compare_kmers_results(seq.iter_kmers(3, overlap=False), expected) def test_iter_kmers_different_sequences_no_positional_metadata(self): seq = Sequence('HE..--..LLO', metadata={'id': 'hello', 'desc': 'gapped hello'}) expected = [ Sequence('HE.', metadata={'id': 'hello', 'desc': 'gapped hello'}), Sequence('.--', metadata={'id': 'hello', 'desc': 'gapped hello'}), Sequence('..L', metadata={'id': 'hello', 'desc': 'gapped hello'}) ] self._compare_kmers_results(seq.iter_kmers(3, overlap=False), expected) def test_iter_kmers_empty_sequence(self): seq = Sequence('') expected = [] self._compare_kmers_results(seq.iter_kmers(3, overlap=False), expected) def test_iter_kmers_empty_sequence_with_positional_metadata(self): seq = Sequence('', positional_metadata={'quality': []}) expected = [] self._compare_kmers_results(seq.iter_kmers(3, overlap=False), expected) def test_kmer_frequencies_empty_sequence(self): seq = Sequence('') self.assertEqual(seq.kmer_frequencies(1), {}) self.assertEqual(seq.kmer_frequencies(1, overlap=False), {}) self.assertEqual(seq.kmer_frequencies(1, relative=True), {}) self.assertEqual(seq.kmer_frequencies(1, relative=True, overlap=False), {}) def test_kmer_frequencies(self): seq = Sequence('GATTACA', positional_metadata={'quality': range(7)}) # overlap = True expected = {'G': 1, 'A': 3, 'T': 2, 'C': 1} self.assertEqual(seq.kmer_frequencies(1, overlap=True), expected) expected = {'GAT': 1, 'ATT': 1, 'TTA': 1, 'TAC': 1, 'ACA': 1} self.assertEqual(seq.kmer_frequencies(3, overlap=True), expected) expected = {} self.assertEqual(seq.kmer_frequencies(8, overlap=True), expected) # overlap = False expected = {'GAT': 1, 'TAC': 1} self.assertEqual(seq.kmer_frequencies(3, overlap=False), expected) expected = {'GATTACA': 1} self.assertEqual(seq.kmer_frequencies(7, overlap=False), expected) expected = {} self.assertEqual(seq.kmer_frequencies(8, overlap=False), expected) def test_kmer_frequencies_relative(self): seq = Sequence('GATTACA', positional_metadata={'quality': range(7)}) # overlap = True expected = {'A': 3/7, 'C': 1/7, 'G': 1/7, 'T': 2/7} self.assertEqual(seq.kmer_frequencies(1, overlap=True, relative=True), expected) expected = {'GAT': 1/5, 'ATT': 1/5, 'TTA': 1/5, 'TAC': 1/5, 'ACA': 1/5} self.assertEqual(seq.kmer_frequencies(3, overlap=True, relative=True), expected) expected = {} self.assertEqual(seq.kmer_frequencies(8, overlap=True, relative=True), expected) # overlap = False expected = {'GAT': 1/2, 'TAC': 1/2} self.assertEqual(seq.kmer_frequencies(3, overlap=False, relative=True), expected) expected = {'GATTACA': 1.0} self.assertEqual(seq.kmer_frequencies(7, overlap=False, relative=True), expected) expected = {} self.assertEqual(seq.kmer_frequencies(8, overlap=False, relative=True), expected) def test_kmer_frequencies_floating_point_precision(self): # Test that a sequence having no variation in k-words yields a # frequency of exactly 1.0. Note that it is important to use # self.assertEqual here instead of self.assertAlmostEqual because we # want to test for exactly 1.0. A previous implementation of # Sequence.kmer_frequencies(relative=True) added (1 / num_words) for # each occurrence of a k-word to compute the frequencies (see # https://github.com/scikit-bio/scikit-bio/issues/801). In certain # cases, this yielded a frequency slightly less than 1.0 due to # roundoff error. The test case here uses a sequence with 10 characters # that are all identical and computes k-word frequencies with k=1. This # test case exposes the roundoff error present in the previous # implementation because there are 10 k-words (which are all # identical), so 1/10 added 10 times yields a number slightly less than # 1.0. This occurs because 1/10 cannot be represented exactly as a # floating point number. seq = Sequence('AAAAAAAAAA') self.assertEqual(seq.kmer_frequencies(1, relative=True), {'A': 1.0}) def test_find_with_regex(self): seq = Sequence('GATTACA', positional_metadata={'quality': range(7)}) pat = re.compile('(T+A)(CA)') obs = list(seq.find_with_regex(pat)) exp = [slice(2, 5), slice(5, 7)] self.assertEqual(obs, exp) self.assertIs(type(seq.find_with_regex(pat)), GeneratorType) def test_find_with_regex_string_as_input(self): seq = Sequence('GATTACA', positional_metadata={'quality': range(7)}) pat = '(T+A)(CA)' obs = list(seq.find_with_regex(pat)) exp = [slice(2, 5), slice(5, 7)] self.assertEqual(obs, exp) self.assertIs(type(seq.find_with_regex(pat)), GeneratorType) def test_find_with_regex_no_groups(self): seq = Sequence('GATTACA', positional_metadata={'quality': range(7)}) pat = re.compile('(FOO)') self.assertEqual(list(seq.find_with_regex(pat)), []) def test_find_with_regex_ignore_no_difference(self): seq = Sequence('..ABCDEFG..') pat = "([A-Z]+)" exp = [slice(2, 9)] self.assertEqual(list(seq.find_with_regex(pat)), exp) obs = seq.find_with_regex( pat, ignore=np.array([1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1], dtype=bool)) self.assertEqual(list(obs), exp) def test_find_with_regex_ignore(self): obs = Sequence('A..A..BBAAB.A..AB..A.').find_with_regex( "(A+)", ignore=np.array([0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1], dtype=bool)) self.assertEqual(list(obs), [slice(0, 4), slice(8, 10), slice(12, 16), slice(19, 20)]) def test_find_with_regex_ignore_index_array(self): obs = Sequence('A..A..BBAAB.A..AB..A.').find_with_regex( "(A+)", ignore=np.array([1, 2, 4, 5, 11, 13, 14, 17, 18, 20])) self.assertEqual(list(obs), [slice(0, 4), slice(8, 10), slice(12, 16), slice(19, 20)]) def test_iter_contiguous_index_array(self): s = Sequence("0123456789abcdef") for c in list, tuple, np.array, pd.Series: exp = [Sequence("0123"), Sequence("89ab")] obs = s.iter_contiguous(c([0, 1, 2, 3, 8, 9, 10, 11])) self.assertEqual(list(obs), exp) def test_iter_contiguous_boolean_vector(self): s = Sequence("0123456789abcdef") for c in list, tuple, np.array, pd.Series: exp = [Sequence("0123"), Sequence("89ab")] obs = s.iter_contiguous(c(([True] * 4 + [False] * 4) * 2)) self.assertEqual(list(obs), exp) def test_iter_contiguous_iterable_slices(self): def spaced_out(): yield slice(0, 4) yield slice(8, 12) def contiguous(): yield slice(0, 4) yield slice(4, 8) yield slice(12, 16) s = Sequence("0123456789abcdef") for c in (lambda x: x, list, tuple, lambda x: np.array(tuple(x)), lambda x: pd.Series(tuple(x))): exp = [Sequence("0123"), Sequence("89ab")] obs = s.iter_contiguous(c(spaced_out())) self.assertEqual(list(obs), exp) exp = [Sequence("01234567"), Sequence("cdef")] obs = s.iter_contiguous(c(contiguous())) self.assertEqual(list(obs), exp) def test_iter_contiguous_with_max_length(self): s = Sequence("0123456789abcdef") for c in list, tuple, np.array, pd.Series: exp = [Sequence("234"), Sequence("678"), Sequence("abc")] obs = s.iter_contiguous(c([True, False, True, True] * 4), min_length=3) self.assertEqual(list(obs), exp) exp = [Sequence("0"), Sequence("234"), Sequence("678"), Sequence("abc"), Sequence("ef")] obs1 = list(s.iter_contiguous(c([True, False, True, True] * 4), min_length=1)) obs2 = list(s.iter_contiguous(c([True, False, True, True] * 4))) self.assertEqual(obs1, obs2) self.assertEqual(obs1, exp) def test_iter_contiguous_with_invert(self): def spaced_out(): yield slice(0, 4) yield slice(8, 12) def contiguous(): yield slice(0, 4) yield slice(4, 8) yield slice(12, 16) s = Sequence("0123456789abcdef") for c in (lambda x: x, list, tuple, lambda x: np.array(tuple(x)), lambda x: pd.Series(tuple(x))): exp = [Sequence("4567"), Sequence("cdef")] obs = s.iter_contiguous(c(spaced_out()), invert=True) self.assertEqual(list(obs), exp) exp = [Sequence("89ab")] obs = s.iter_contiguous(c(contiguous()), invert=True) self.assertEqual(list(obs), exp) def test_to_indices_observed(self): # arbitrary sequence seq = Sequence('hello') obs_idx, obs_alp = seq.to_indices() exp_idx, exp_alp = np.array([1, 0, 2, 2, 3]), 'ehlo' npt.assert_equal(obs_idx, exp_idx) self.assertEqual(obs_alp, exp_alp) self.assertTrue(obs_idx.dtype.type is np.intp) # return ASCII code points obs_idx, obs_alp = seq.to_indices(return_codes=True) exp_alp = np.frombuffer('ehlo'.encode('ascii'), dtype=np.uint8) npt.assert_equal(obs_idx, exp_idx) npt.assert_equal(obs_alp, exp_alp) # grammared sequence obs_idx, obs_alp = DNA('GAGCTC').to_indices() npt.assert_equal(obs_idx, np.array([2, 0, 2, 1, 3, 1])) self.assertEqual(obs_alp, 'ACGT') def test_to_indices_alphabet(self): # arbitrary sequence seq = Sequence('hello') obs = seq.to_indices('oleh') exp = np.array([3, 2, 1, 1, 0]) npt.assert_equal(obs, exp) self.assertTrue(obs.dtype.type is np.intp) # grammared sequence seq = DNA('GAGCTC') obs = seq.to_indices('ACGT') exp = np.array([2, 0, 2, 1, 3, 1]) npt.assert_equal(obs, exp) # alphabet has duplicates msg = 'Alphabet contains duplicated characters.' with self.assertRaisesRegex(ValueError, msg): Sequence('hello').to_indices('there') # non-ASCII alphabet msg = 'Alphabet cannot be encoded as single ASCII characters.' with self.assertRaisesRegex(ValueError, msg): Sequence('hello').to_indices('how are you'.split()) def test_to_indices_submat(self): # basic nucleotides sm = SubstitutionMatrix.identity('ACGT', 1, -2) obs = DNA('GAGCTC').to_indices(sm) exp = np.array([2, 0, 2, 1, 3, 1]) npt.assert_equal(obs, exp) # extended nucleotides (and not sorted) # ATGCSWRYKMBVHDN sm = SubstitutionMatrix.by_name('NUC.4.4') obs = DNA('GAGRCTC').to_indices(sm) exp = np.array([2, 0, 2, 6, 3, 1, 3]) npt.assert_equal(obs, exp) # non-ASCII alphabet sm = SubstitutionMatrix.identity('how are you'.split(), 1, -2) msg = ('Alphabet in the substitution matrix are not single ASCII ' 'characters.') with self.assertRaisesRegex(ValueError, msg): Sequence('hello').to_indices(sm) def test_to_indices_wildcard(self): # default wildcard seq = DNA('GAGRCTC') obs = seq.to_indices('ACGTN') exp = np.array([2, 0, 2, 4, 1, 3, 1]) npt.assert_equal(obs, exp) # non-default wildcard obs = seq.to_indices('ACGTN', wildcard='A') exp = np.array([2, 0, 2, 0, 1, 3, 1]) npt.assert_equal(obs, exp) # invalid wildcard msg = 'Wildcard character "X" is not in the alphabet.' with self.assertRaisesRegex(ValueError, msg): seq.to_indices('ACGTN', wildcard='X') msg = 'Wildcard must be a single ASCII character.' with self.assertRaisesRegex(ValueError, msg): seq.to_indices('ACGTN', wildcard='hi') with self.assertRaisesRegex(ValueError, msg): seq.to_indices('ACGTN', wildcard=chr(200)) def test_to_indices_masked(self): # gaps are automatically identified and masked obs_idx, obs_alp = DNA('GAG-CTC').to_indices() self.assertTrue(isinstance(obs_idx, np.ma.MaskedArray)) npt.assert_equal(obs_idx.data, [2, 0, 2, -1, 1, 3, 1]) npt.assert_equal(obs_idx.mask, [0, 0, 0, 1, 0, 0, 0]) self.assertEqual(obs_alp, 'ACGT') # force masking regardless of gap presence obs_idx, obs_alp = DNA('GAGCTC').to_indices(mask_gaps=True) self.assertTrue(isinstance(obs_idx, np.ma.MaskedArray)) npt.assert_equal(obs_idx.data, [2, 0, 2, 1, 3, 1]) npt.assert_equal(obs_idx.mask, [0, 0, 0, 0, 0, 0]) self.assertEqual(obs_alp, 'ACGT') # force not masking regardless of gap presence obs_idx, obs_alp = DNA('GAG-CTC').to_indices(mask_gaps=False) self.assertFalse(isinstance(obs_idx, np.ma.MaskedArray)) npt.assert_equal(obs_idx, [3, 1, 3, 0, 2, 4, 2]) self.assertEqual(obs_alp, '-ACGT') # gap character(s) are not defined msg = r'Gap character\(s\) are not defined for the sequence.' with self.assertRaisesRegex(ValueError, msg): Sequence('hello').to_indices(mask_gaps=True) # with alphabet obs = DNA('GAG-CTC').to_indices('ACGT') self.assertTrue(isinstance(obs, np.ma.MaskedArray)) npt.assert_equal(obs.data, [2, 0, 2, -1, 1, 3, 1]) npt.assert_equal(obs.mask, [0, 0, 0, 1, 0, 0, 0]) def test_copy_without_metadata(self): # shallow vs deep copy with sequence only should be equivalent for copy_method in copy.copy, copy.deepcopy: seq = Sequence('ACGT') seq_copy = copy_method(seq) self.assertEqual(seq_copy, seq) self.assertIsNot(seq_copy, seq) self.assertIsNot(seq_copy._bytes, seq._bytes) def test_copy_with_metadata_shallow(self): seq = Sequence('ACGT', metadata={'foo': [1]}, positional_metadata={'bar': [[], [], [], []], 'baz': [42, 42, 42, 42]}) seq.interval_metadata.add([(0, 3)], metadata={'gene': ['sagA']}) seq_copy = copy.copy(seq) self.assertEqual(seq_copy, seq) self.assertIsNot(seq_copy, seq) self.assertIsNot(seq_copy._bytes, seq._bytes) self.assertIsNot(seq_copy._metadata, seq._metadata) self.assertIsNot(seq_copy._positional_metadata, seq._positional_metadata) self.assertIsNot(seq_copy._positional_metadata.values, seq._positional_metadata.values) self.assertIs(seq_copy._metadata['foo'], seq._metadata['foo']) self.assertIs(seq_copy._positional_metadata.loc[0, 'bar'], seq._positional_metadata.loc[0, 'bar']) self.assertIsNot(seq_copy.interval_metadata, seq.interval_metadata) self.assertIsNot(seq_copy.interval_metadata._intervals[0], seq.interval_metadata._intervals[0]) self.assertIsNot(seq_copy.interval_metadata._intervals[0].metadata, seq.interval_metadata._intervals[0].metadata) self.assertIs( seq_copy.interval_metadata._intervals[0].metadata['gene'], seq.interval_metadata._intervals[0].metadata['gene']) seq_copy.metadata['foo'].append(2) seq_copy.metadata['foo2'] = 42 self.assertEqual(seq_copy.metadata, {'foo': [1, 2], 'foo2': 42}) self.assertEqual(seq.metadata, {'foo': [1, 2]}) seq_copy.positional_metadata.loc[0, 'bar'].append(1) seq_copy.positional_metadata.loc[0, 'baz'] = 43 assert_data_frame_almost_equal( seq_copy.positional_metadata, pd.DataFrame({'bar': [[1], [], [], []], 'baz': [43, 42, 42, 42]})) assert_data_frame_almost_equal( seq.positional_metadata, pd.DataFrame({'bar': [[1], [], [], []], 'baz': [42, 42, 42, 42]})) def test_copy_with_metadata_deep(self): seq = Sequence('ACGT', metadata={'foo': [1]}, positional_metadata={'bar': [[], [], [], []], 'baz': [42, 42, 42, 42]}) seq.interval_metadata.add([(0, 3)], metadata={'gene': ['sagA']}) seq_copy = copy.deepcopy(seq) self.assertEqual(seq_copy, seq) self.assertIsNot(seq_copy, seq) self.assertIsNot(seq_copy._bytes, seq._bytes) self.assertIsNot(seq_copy._metadata, seq._metadata) self.assertIsNot(seq_copy._positional_metadata, seq._positional_metadata) self.assertIsNot(seq_copy._positional_metadata.values, seq._positional_metadata.values) self.assertIsNot(seq_copy._metadata['foo'], seq._metadata['foo']) self.assertIsNot(seq_copy._positional_metadata.loc[0, 'bar'], seq._positional_metadata.loc[0, 'bar']) self.assertIsNot(seq_copy.interval_metadata, seq.interval_metadata) self.assertIsNot(seq_copy.interval_metadata._intervals[0], seq.interval_metadata._intervals[0]) self.assertIsNot(seq_copy.interval_metadata._intervals[0].metadata, seq.interval_metadata._intervals[0].metadata) self.assertIsNot( seq_copy.interval_metadata._intervals[0].metadata['gene'], seq.interval_metadata._intervals[0].metadata['gene']) seq_copy.metadata['foo'].append(2) seq_copy.metadata['foo2'] = 42 self.assertEqual(seq_copy.metadata, {'foo': [1, 2], 'foo2': 42}) self.assertEqual(seq.metadata, {'foo': [1]}) seq_copy.positional_metadata.loc[0, 'bar'].append(1) seq_copy.positional_metadata.loc[0, 'baz'] = 43 assert_data_frame_almost_equal( seq_copy.positional_metadata, pd.DataFrame({'bar': [[1], [], [], []], 'baz': [43, 42, 42, 42]})) assert_data_frame_almost_equal( seq.positional_metadata, pd.DataFrame({'bar': [[], [], [], []], 'baz': [42, 42, 42, 42]})) def test_copy_preserves_read_only_flag_on_bytes(self): seq = Sequence('ACGT') seq_copy = copy.copy(seq) with self.assertRaises(ValueError): seq_copy._bytes[0] = 'B' def test_deepcopy_memo_is_respected(self): # basic test to ensure deepcopy's memo is passed through to recursive # deepcopy calls seq = Sequence('ACGT', metadata={'foo': 'bar'}) memo = {} copy.deepcopy(seq, memo) self.assertGreater(len(memo), 2) def test_munge_to_index_array_valid_index_array(self): s = Sequence('123456') for c in list, tuple, np.array, pd.Series: exp = np.array([1, 2, 3], dtype=int) obs = s._munge_to_index_array(c([1, 2, 3])) npt.assert_equal(obs, exp) exp = np.array([1, 3, 5], dtype=int) obs = s._munge_to_index_array(c([1, 3, 5])) npt.assert_equal(obs, exp) def test_munge_to_index_array_invalid_index_array(self): s = Sequence("12345678") for c in list, tuple, np.array, pd.Series: with self.assertRaises(ValueError): s._munge_to_index_array(c([3, 2, 1])) with self.assertRaises(ValueError): s._munge_to_index_array(c([5, 6, 7, 2])) with self.assertRaises(ValueError): s._munge_to_index_array(c([0, 1, 2, 1])) def test_munge_to_index_array_valid_bool_array(self): s = Sequence('123456') for c in list, tuple, np.array, pd.Series: exp = np.array([2, 3, 5], dtype=int) obs = s._munge_to_index_array( c([False, False, True, True, False, True])) npt.assert_equal(obs, exp) exp = np.array([], dtype=int) obs = s._munge_to_index_array( c([False] * 6)) npt.assert_equal(obs, exp) exp = np.arange(6) obs = s._munge_to_index_array( c([True] * 6)) npt.assert_equal(obs, exp) def test_munge_to_index_array_invalid_bool_array(self): s = Sequence('123456') for c in (list, tuple, lambda x: np.array(x, dtype=bool), lambda x: pd.Series(x, dtype=bool)): with self.assertRaises(ValueError): s._munge_to_index_array(c([])) with self.assertRaises(ValueError): s._munge_to_index_array(c([True])) with self.assertRaises(ValueError): s._munge_to_index_array(c([True] * 10)) def test_munge_to_index_array_valid_iterable(self): s = Sequence('') def slices_only(): return (slice(i, i+1) for i in range(0, 10, 2)) def mixed(): return (slice(i, i+1) if i % 2 == 0 else i for i in range(10)) for c in (lambda x: x, list, tuple, lambda x: np.array(tuple(x)), lambda x: pd.Series(tuple(x))): exp = np.arange(10, dtype=int) obs = s._munge_to_index_array(c(mixed())) npt.assert_equal(obs, exp) exp = np.arange(10, step=2, dtype=int) obs = s._munge_to_index_array(c(slices_only())) npt.assert_equal(obs, exp) def test_munge_to_index_array_invalid_iterable(self): s = Sequence('') def bad1(): yield "r" yield [1, 2, 3] def bad2(): yield 1 yield 'str' def bad3(): yield False yield True yield 2 def bad4(): yield np.array([False, True]) yield slice(2, 5) for c in (lambda x: x, list, tuple, lambda x: np.array(tuple(x)), lambda x: pd.Series(tuple(x))): with self.assertRaises(TypeError): s._munge_to_index_array(bad1()) with self.assertRaises(TypeError): s._munge_to_index_array(bad2()) with self.assertRaises(TypeError): s._munge_to_index_array(bad3()) with self.assertRaises(TypeError): s._munge_to_index_array(bad4()) def test_munge_to_index_array_valid_string(self): seq = Sequence('ACGTACGT', positional_metadata={'introns': [False, True, True, False, False, True, False, False]}) npt.assert_equal(np.array([1, 2, 5]), seq._munge_to_index_array('introns')) seq.positional_metadata['exons'] = ~seq.positional_metadata['introns'] npt.assert_equal(np.array([0, 3, 4, 6, 7]), seq._munge_to_index_array('exons')) def test_munge_to_index_array_invalid_string(self): seq_str = 'ACGT' seq = Sequence(seq_str, positional_metadata={'quality': range(len(seq_str))}) with self.assertRaisesRegex(ValueError, r"No positional metadata associated with " "key 'introns'"): seq._munge_to_index_array('introns') with self.assertRaisesRegex(TypeError, r"Column 'quality' in positional metadata " "does not correspond to a boolean " "vector"): seq._munge_to_index_array('quality') def test_munge_to_bytestring_return_bytes(self): seq = Sequence('') m = 'dummy_method' str_inputs = ('', 'a', 'acgt') unicode_inputs = ('', 'a', 'acgt') byte_inputs = (b'', b'a', b'acgt') seq_inputs = (Sequence(''), Sequence('a'), Sequence('acgt')) all_inputs = str_inputs + unicode_inputs + byte_inputs + seq_inputs all_expected = [b'', b'a', b'acgt'] * 4 for input_, expected in zip(all_inputs, all_expected): observed = seq._munge_to_bytestring(input_, m) self.assertEqual(observed, expected) self.assertIs(type(observed), bytes) def test_munge_to_bytestring_unicode_out_of_ascii_range(self): seq = Sequence('') all_inputs = ('\x80', 'abc\x80', '\x80abc') for input_ in all_inputs: with self.assertRaisesRegex(UnicodeEncodeError, r"'ascii' codec can't encode character" r".*in position.*: ordinal not in" r" range\(128\)"): seq._munge_to_bytestring(input_, 'dummy_method') class TestDistance(TestSequenceBase): def test_mungeable_inputs_to_sequence(self): def metric(a, b): self.assertEqual(a, Sequence("abcdef")) self.assertEqual(b, Sequence("12bcef")) return 42.0 for constructor in self.sequence_kinds: seq1 = Sequence("abcdef") seq2 = constructor("12bcef") distance = seq1.distance(seq2, metric=metric) self.assertEqual(distance, 42.0) def test_mungeable_inputs_to_sequence_subclass(self): def metric(a, b): self.assertEqual(a, SequenceSubclass("abcdef")) self.assertEqual(b, SequenceSubclass("12bcef")) return -42.0 sequence_kinds = frozenset([ str, SequenceSubclass, lambda s: np.frombuffer(s.encode('ascii'), dtype='|S1'), lambda s: np.frombuffer(s.encode('ascii'), dtype=np.uint8)]) for constructor in sequence_kinds: seq1 = SequenceSubclass("abcdef") seq2 = constructor("12bcef") distance = seq1.distance(seq2, metric=metric) self.assertEqual(distance, -42.0) def test_sequence_type_mismatch(self): seq1 = SequenceSubclass("abcdef") seq2 = Sequence("12bcef") with self.assertRaisesRegex(TypeError, r'SequenceSubclass.*Sequence.*`distance`'): seq1.distance(seq2) with self.assertRaisesRegex(TypeError, r'Sequence.*SequenceSubclass.*`distance`'): seq2.distance(seq1) def test_munging_invalid_characters_to_self_type(self): with self.assertRaisesRegex(ValueError, r'Invalid characters.*X'): DNA("ACGT").distance("WXYZ") def test_munging_invalid_type_to_self_type(self): with self.assertRaises(TypeError): Sequence("ACGT").distance(42) def test_return_type_coercion(self): def metric(a, b): return 42 distance = Sequence('abc').distance('cba', metric=metric) self.assertIsInstance(distance, float) def test_invalid_return_type(self): def metric(a, b): return 'too far' with self.assertRaisesRegex(ValueError, r'string.*float'): Sequence('abc').distance('cba', metric=metric) def test_arbitrary_metric(self): def metric(x, y): return len(x) ** 2 + len(y) ** 2 seq1 = Sequence("12345678") seq2 = Sequence("1234") distance = seq1.distance(seq2, metric=metric) self.assertEqual(distance, 80.0) def test_scipy_hamming_metric_with_metadata(self): # test for #1254 seqs1 = [ Sequence("ACGT"), Sequence("ACGT", metadata={'id': 'abc'}), Sequence("ACGT", positional_metadata={'qual': range(4)}) ] seqs2 = [ Sequence("AAAA"), Sequence("AAAA", metadata={'id': 'def'}), Sequence("AAAA", positional_metadata={'qual': range(4, 8)}) ] for seqs in seqs1, seqs2: for seq1, seq2 in itertools.product(seqs, repeat=2): distance = seq1.distance(seq2, metric=sp_hamming) self.assertEqual(distance, 0.0) for seq1, seq2 in itertools.product(seqs1, seqs2): distance = seq1.distance(seq2, metric=sp_hamming) self.assertEqual(distance, 0.75) def test_default_metric_with_metadata(self): # test for #1254 seqs1 = [ Sequence("ACGT"), Sequence("ACGT", metadata={'id': 'abc'}), Sequence("ACGT", positional_metadata={'qual': range(4)}) ] seqs2 = [ Sequence("AAAA"), Sequence("AAAA", metadata={'id': 'def'}), Sequence("AAAA", positional_metadata={'qual': range(4, 8)}) ] for seqs in seqs1, seqs2: for seq1, seq2 in itertools.product(seqs, repeat=2): distance = seq1.distance(seq2) self.assertEqual(distance, 0.0) for seq1, seq2 in itertools.product(seqs1, seqs2): distance = seq1.distance(seq2) self.assertEqual(distance, 0.75) def test_default_metric_matches_hamming(self): seq1 = Sequence("abcdef") seq2 = Sequence("12bcef") seq_wrong = Sequence("abcdefghijklmnop") distance1 = seq1.distance(seq2) distance2 = sk_hamming(seq1, seq2) self.assertEqual(distance1, distance2) with self.assertRaises(ValueError): seq1.distance(seq_wrong) with self.assertRaises(ValueError): seq_wrong.distance(seq1) # NOTE: this must be a *separate* class for doctests only (no unit tests). nose # will not run the unit tests otherwise # TODO: check if this is still the case since nose is no longer used # # these doctests exercise the correct formatting of Sequence's repr in a # variety of situations. they are more extensive than the unit tests above # (TestSequence.test_repr) but cannot be relied upon for coverage (the unit # tests take care of this) class SequenceReprDoctests: r""">>> import pandas as pd >>> from skbio import Sequence Empty (minimal) sequence: >>> Sequence('') Sequence ------------- Stats: length: 0 ------------- Single character sequence: >>> Sequence('G') Sequence ------------- Stats: length: 1 ------------- 0 G Multicharacter sequence: >>> Sequence('ACGT') Sequence ------------- Stats: length: 4 ------------- 0 ACGT Full single line: >>> Sequence('A' * 60) Sequence ------------------------------------------------------------------- Stats: length: 60 ------------------------------------------------------------------- 0 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA Full single line with 1 character overflow: >>> Sequence('A' * 61) Sequence -------------------------------------------------------------------- Stats: length: 61 -------------------------------------------------------------------- 0 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 60 A Two full lines: >>> Sequence('T' * 120) Sequence -------------------------------------------------------------------- Stats: length: 120 -------------------------------------------------------------------- 0 TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT 60 TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT Two full lines with 1 character overflow: >>> Sequence('T' * 121) Sequence --------------------------------------------------------------------- Stats: length: 121 --------------------------------------------------------------------- 0 TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT 60 TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT TTTTTTTTTT 120 T Five full lines (maximum amount of information): >>> Sequence('A' * 300) Sequence --------------------------------------------------------------------- Stats: length: 300 --------------------------------------------------------------------- 0 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 60 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 120 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 180 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 240 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA Six lines starts "summarized" output: >>> Sequence('A' * 301) Sequence --------------------------------------------------------------------- Stats: length: 301 --------------------------------------------------------------------- 0 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 60 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA ... 240 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 300 A A naive algorithm would assume the width of the first column (noting position) based on the sequence's length alone. This can be off by one if the last position (in the last line) has a shorter width than the width calculated from the sequence's length. This test case ensures that only a single space is inserted between position 99960 and the first sequence chunk: >>> Sequence('A' * 100000) Sequence ----------------------------------------------------------------------- Stats: length: 100000 ----------------------------------------------------------------------- 0 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 60 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA ... 99900 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 99960 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA The largest sequence that can be displayed using six chunks per line: >>> Sequence('A' * 100020) Sequence ----------------------------------------------------------------------- Stats: length: 100020 ----------------------------------------------------------------------- 0 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 60 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA ... 99900 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 99960 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA A single character longer than the previous sequence causes the optimal number of chunks per line to be 5: >>> Sequence('A' * 100021) Sequence ------------------------------------------------------------- Stats: length: 100021 ------------------------------------------------------------- 0 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 50 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA ... 99950 AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA AAAAAAAAAA 100000 AAAAAAAAAA AAAAAAAAAA A Wide range of characters (locale-independent): >>> import string >>> Sequence((string.ascii_letters + string.punctuation + string.digits + ... 'a space') * 567) Sequence ----------------------------------------------------------------------- Stats: length: 57267 ----------------------------------------------------------------------- 0 abcdefghij klmnopqrst uvwxyzABCD EFGHIJKLMN OPQRSTUVWX YZ!"#$%&'( 60 )*+,-./:;< =>?@[\]^_` {|}~012345 6789a spac eabcdefghi jklmnopqrs ... 57180 opqrstuvwx yzABCDEFGH IJKLMNOPQR STUVWXYZ!" #$%&'()*+, -./:;<=>?@ 57240 [\]^_`{|}~ 0123456789 a space Supply horrendous metadata, positional, and interval metadata to exercise a variety of metadata formatting cases and rules. Sorting should be by type, then by value within each type (Python 3 doesn't allow sorting of mixed types): >>> metadata = { ... # str key, str value ... 'abc': 'some description', ... # int value ... 'foo': 42, ... # unsupported type (dict) value ... 'bar': {}, ... # int key, wrapped str (single line) ... 42: 'some words to test text wrapping and such... yada yada yada ' ... 'yada yada yada yada yada.', ... # bool key, wrapped str (multi-line) ... True: 'abc ' * 34, ... # float key, truncated str (too long) ... 42.5: 'abc ' * 200, ... # unsupported type (tuple) key, unsupported type (list) value ... ('foo', 'bar'): [1, 2, 3], ... # bytes key, single long word that wraps ... b'long word': 'abc' * 30, ... # truncated key (too long), None value ... 'too long of a key name to display in repr': None, ... # wrapped bytes value (has b'' prefix) ... 'bytes wrapped value': b'abcd' * 25, ... # float value ... 0.1: 99.9999, ... # bool value ... 43: False, ... # None key, complex value ... None: complex(-1.0, 0.0), ... # nested quotes ... 10: '"\'' ... } >>> positional_metadata = pd.DataFrame({ ... # str key, int list value ... 'foo': [1, 2, 3, 4], ... # float key, float list value ... 42.5: [2.5, 3.0, 4.2, -0.00001], ... # int key, object list value ... 42: [[], 4, 5, {}], ... # truncated key (too long), bool list value ... 'abc' * 90: [True, False, False, True], ... # None key ... None: range(4)}) >>> positional_metadata = positional_metadata.reindex( ... columns=['foo', 42.5, 42, 'abc' * 90, None]) >>> interval_metadata = IntervalMetadata(4) >>> _ = interval_metadata.add([(0, 2), (1, 3)], ... [(False, True), (False, False)], ... {'gene': 'p53'}) >>> _ = interval_metadata.add([(1, 4)]) >>> Sequence('ACGT', metadata=metadata, ... positional_metadata=positional_metadata, ... interval_metadata=interval_metadata) Sequence ----------------------------------------------------------------------- Metadata: None: (-1+0j) True: 'abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc ' b'long word': 'abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabca bcabcabcabcabcabcabcabcabcabcabcabcabc' 0.1: 99.9999 42.5: 10: '"\'' 42: 'some words to test text wrapping and such... yada yada yada yada yada yada yada yada.' 43: False 'abc': 'some description' 'bar': 'bytes wrapped value': b'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdab cdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd abcdabcdabcdabcd' 'foo': 42 : None : Positional metadata: 'foo': 42.5: 42: : None: Interval metadata: 2 interval features Stats: length: 4 ----------------------------------------------------------------------- 0 ACGT """ pass if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/sequence/tests/test_substitution.py000066400000000000000000000202521520735541300266220ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np from numpy.testing import assert_array_equal from skbio import SubstitutionMatrix class TestSubstitutionMatrix(TestCase): def setUp(self): self.alphabet = 'ACGTN' self.scores = np.array([ [1, -2, -2, -2, 0], [-2, 1, -2, -2, 0], [-2, -2, 1, -2, 0], [-2, -2, -2, 1, 0], [0, 0, 0, 0, 0]]) def test_init(self): # typical usage # alphabet becomes tuple of characters alphabet = tuple(self.alphabet) obs = SubstitutionMatrix(self.alphabet, self.scores) self.assertTupleEqual(obs.alphabet, alphabet) # alphabet is an alias of ids self.assertTupleEqual(obs.alphabet, obs.ids) # matrix is ndarray (this is important for alignment efficiency) self.assertTrue(isinstance(obs.scores, np.ndarray)) self.assertTupleEqual(obs.shape, (5, 5)) assert_array_equal(obs.scores, self.scores) # data type becomes float32 self.assertEqual(obs.dtype, np.float32) # scores is an alias of data assert_array_equal(obs.scores, obs.data) # character to index mapping self.assertDictEqual(obs._char_map, dict(zip( alphabet, range(len(alphabet))))) # alphabet can be encoded as ASCII characters self.assertTrue(obs._is_ascii) # hash table of ASCII characters self.assertTrue(isinstance(obs._char_hash, np.ndarray)) self.assertTrue(obs._char_hash.dtype.type is np.intp) for i, char in enumerate(alphabet): self.assertEqual(i, obs._char_hash[ord(char)]) # matrix is guaranteed to be C-contiguous obs = SubstitutionMatrix(self.alphabet, np.asfortranarray(self.scores)) assert_array_equal(obs.scores, self.scores) self.assertTrue(obs.scores.flags.c_contiguous) def test_init_alt_alphabet(self): # alternative formats of alphabet: list, dictionary (only keys matter), # and iterator alphabet = tuple(self.alphabet) for alp in (list(alphabet), dict.fromkeys(alphabet), iter(alphabet)): obs = SubstitutionMatrix(alp, self.scores) self.assertTupleEqual(obs.alphabet, alphabet) def test_init_non_ascii(self): # non-ASCII characters in the alphabet obs = SubstitutionMatrix("äëïöü", self.scores) self.assertTupleEqual(obs.alphabet, ("ä", "ë", "ï", "ö", "ü")) self.assertEqual(obs["ï", "ë"], -2) self.assertFalse(obs.is_ascii) self.assertIsNone(obs._char_hash) def test_init_words(self): # words in the alphabet words = "lorem ipsum dolor sit amet".split() obs = SubstitutionMatrix(words, self.scores) self.assertTupleEqual(obs.alphabet, tuple(words)) self.assertEqual(obs["dolor", "ipsum"], -2) self.assertFalse(obs.is_ascii) self.assertIsNone(obs._char_hash) def test_init_alt_scores(self): # alternative format of scores: nested list obs = SubstitutionMatrix(self.alphabet, self.scores.tolist()) assert_array_equal(obs.scores, self.scores) # condensed matrix (less likely because diagonal is zero) obs = SubstitutionMatrix('ACGT', [-1] * 6) assert_array_equal(obs.scores, np.identity(4) - 1) def test_init_alt_float(self): # alternative floating-point precision (64-bit) obs = SubstitutionMatrix(self.alphabet, self.scores.astype(np.float32)) assert_array_equal(obs.scores, self.scores) self.assertEqual(obs.dtype, np.float32) obs = SubstitutionMatrix(self.alphabet, self.scores.astype(np.float64)) assert_array_equal(obs.scores, self.scores) self.assertEqual(obs.dtype, np.float64) obs = SubstitutionMatrix(self.alphabet, self.scores.astype(np.float16)) assert_array_equal(obs.scores, self.scores) self.assertEqual(obs.dtype, np.float32) obs = SubstitutionMatrix(self.alphabet, self.scores.astype(np.int16)) assert_array_equal(obs.scores, self.scores) self.assertEqual(obs.dtype, np.float32) def test_to_dict(self): mat = SubstitutionMatrix(self.alphabet, self.scores) obs = mat.to_dict() exp = {'A': {'A': 1., 'C': -2., 'G': -2., 'T': -2., 'N': 0.}, 'C': {'A': -2., 'C': 1., 'G': -2., 'T': -2., 'N': 0.}, 'G': {'A': -2., 'C': -2., 'G': 1., 'T': -2., 'N': 0.}, 'T': {'A': -2., 'C': -2., 'G': -2., 'T': 1., 'N': 0.}, 'N': {'A': 0., 'C': 0., 'G': 0., 'T': 0., 'N': 0.}} self.assertDictEqual(obs, exp) def test_from_dict(self): d = {'a': {'a': 1, 'b': 0, 'c': 0}, 'b': {'a': 0, 'b': 1, 'c': 0}, 'c': {'a': 0, 'b': 0, 'c': 1}} obs = SubstitutionMatrix.from_dict(d) self.assertTrue(isinstance(obs, SubstitutionMatrix)) self.assertTupleEqual(obs.alphabet, tuple('abc')) exp = np.array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) assert_array_equal(obs.data, exp) self.assertEqual(obs._data.dtype, np.float32) # data type obs = SubstitutionMatrix.from_dict(d, dtype="float32") self.assertEqual(obs._data.dtype, np.float32) obs = SubstitutionMatrix.from_dict(d, dtype="float64") self.assertEqual(obs._data.dtype, np.float64) # alphabet is inconsistent msg = ('The outer and inner layers of the dictionary must have the ' 'same set of keys.') d['d'] = {'a': 0, 'b': 0, 'c': 0} with self.assertRaisesRegex(ValueError, msg): SubstitutionMatrix.from_dict(d) del d['d'] d['a']['d'] = 2 with self.assertRaisesRegex(ValueError, msg): SubstitutionMatrix.from_dict(d) del d['a']['d'] # scores are not numbers d['a']['b'] = 'hello' with self.assertRaises(ValueError): SubstitutionMatrix.from_dict(d) def test_identity(self): obs = SubstitutionMatrix.identity('ACGT', 1, -2) self.assertTrue(isinstance(obs, SubstitutionMatrix)) self.assertTupleEqual(obs.alphabet, tuple('ACGT')) exp = np.array([[1., -2., -2., -2.], [-2., 1., -2., -2.], [-2., -2., 1., -2.], [-2., -2., -2., 1.]]) assert_array_equal(obs.scores, exp) self.assertEqual(obs._data.dtype, np.float32) obs = SubstitutionMatrix.identity('ACGT', 1, -2, dtype="float64") assert_array_equal(obs.scores, exp) self.assertEqual(obs._data.dtype, np.float64) obs = SubstitutionMatrix.identity('ACGT', 1, -2, dtype="int16") assert_array_equal(obs.scores, exp) self.assertEqual(obs._data.dtype, np.float32) with self.assertRaises(TypeError): _ = SubstitutionMatrix.identity('ACGT', 1, -2, dtype="hello") def test_by_name(self): obs = SubstitutionMatrix.by_name('NUC.4.4') self.assertEqual(len(obs.alphabet), 15) self.assertEqual(obs['A', 'T'], -4) self.assertEqual(obs._data.dtype, np.float32) obs = SubstitutionMatrix.by_name('BLOSUM50') self.assertEqual(len(obs.alphabet), 24) self.assertEqual(obs['M', 'K'], -2) obs = SubstitutionMatrix.by_name('blosum50') self.assertEqual(len(obs.alphabet), 24) self.assertEqual(obs['M', 'K'], -2) msg = 'Substitution matrix "hello" does not exist.' with self.assertRaisesRegex(ValueError, msg): SubstitutionMatrix.by_name('hello') def test_get_names(self): obs = SubstitutionMatrix.get_names() self.assertTrue('NUC.4.4' in obs) self.assertTrue('PAM250' in obs) self.assertTrue('BLOSUM62' in obs) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/000077500000000000000000000000001520735541300206205ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/__init__.py000066400000000000000000000026711520735541300227370ustar00rootroot00000000000000r"""Multivariate Statistics (:mod:`skbio.stats`) ============================================ .. currentmodule:: skbio.stats This module provides various statistical methods to support the analyses of high-dimensional biological data to uncover the relationships among samples, features and metadata. Examples include distance matrix-based statistics, ordination methods, composition statistics, and data subsampling techniques. Distance matrix statistics -------------------------- .. autosummary:: :toctree: generated/ distance Ordination methods ------------------ .. autosummary:: :toctree: generated/ ordination Composition statistics ---------------------- .. autosummary:: :toctree: generated/ composition Data subsampling ---------------- .. autosummary:: :toctree: generated/ subsample_counts isubsample Other statistical methods ------------------------- .. autosummary:: :toctree: generated/ evolve gradient power """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._subsample import subsample_counts, isubsample __all__ = ["subsample_counts", "isubsample"] scikit-bio-scikit-bio-a3beaa6/skbio/stats/_misc.py000066400000000000000000000015701520735541300222670ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- def _pprint_strs( strs, max_chars=80, delimiter=", ", suffix="...", ): """Pretty-print an iterable of strings, truncating if necessary.""" # Adapted from http://stackoverflow.com/a/250373 joined_str = delimiter.join(repr(s) for s in strs) if len(joined_str) > max_chars: truncated = joined_str[: max_chars + 1].split(delimiter)[0:-1] joined_str = delimiter.join(truncated) if joined_str: joined_str += delimiter joined_str += suffix return joined_str scikit-bio-scikit-bio-a3beaa6/skbio/stats/_subsample.py000066400000000000000000000174401520735541300233320ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import sys from heapq import heappush, heappop from collections import defaultdict from copy import copy import numpy as np import scipy.sparse as sparse from skbio.util import get_rng from biom import subsample as biom_subsample def isubsample(items, maximum, minimum=1, buf_size=1000, bin_f=None, seed=None): """Randomly subsample items from bins, without replacement. Randomly subsample items without replacement from an unknown number of input items, that may fall into an unknown number of bins. This method is intended for data that either a) cannot fit into memory or b) subsampling collections of arbitrary datatypes. Parameters ---------- items : Iterable The items to evaluate. maximum : unsigned int The maximum number of items per bin. minimum : unsigned int, optional The minimum number of items per bin. The default is 1. buf_size : unsigned int, optional The size of the random value buffer. This buffer holds the random values assigned to each item from items. In practice, it is unlikely that this value will need to change. Increasing it will require more resident memory, but potentially reduce the number of function calls made to the PRNG, whereas decreasing it will result in more function calls and lower memory overhead. The default is 1000. bin_f : function, optional Method to determine what bin an item is associated with. If None (the default), then all items are considered to be part of the same bin. This function will be provided with each entry in items, and must return a hashable value indicating the bin that that entry should be placed in. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- generator (bin, item) Raises ------ ValueError If ``minimum`` is > ``maximum``. ValueError If ``minimum`` < 1 or if ``maximum`` < 1. See Also -------- subsample_counts Notes ----- Randomly get up to ``maximum`` items for each bin. If the bin has less than ``maximum``, only those bins that have >= ``minimum`` items are returned. This method will at most hold ``maximum`` * N data, where N is the number of bins. All items associated to a bin have an equal probability of being retained. Examples -------- Randomly keep up to 2 sequences per sample from a set of demultiplexed sequences: >>> from skbio.stats import isubsample >>> seqs = [('sampleA', 'AATTGG'), ... ('sampleB', 'ATATATAT'), ... ('sampleC', 'ATGGCC'), ... ('sampleB', 'ATGGCT'), ... ('sampleB', 'ATGGCG'), ... ('sampleA', 'ATGGCA')] >>> bin_f = lambda item: item[0] >>> for bin_, item in sorted(isubsample(seqs, 2, bin_f=bin_f, seed=123)): ... print(bin_, item[1]) sampleA AATTGG sampleA ATGGCA sampleB ATGGCG sampleB ATGGCT sampleC ATGGCC Now, let's set the minimum to 2: >>> bin_f = lambda item: item[0] >>> for bin_, item in sorted(isubsample(seqs, 2, 2, bin_f=bin_f, seed=123)): ... print(bin_, item[1]) sampleA AATTGG sampleA ATGGCA sampleB ATGGCG sampleB ATGGCT """ if minimum > maximum: raise ValueError("minimum cannot be > maximum.") if minimum < 1 or maximum < 1: raise ValueError("minimum and maximum must be > 0.") if bin_f is None: def bin_f(x): return True rng = get_rng(seed) # buffer some random values random_values = rng.integers(0, sys.maxsize, buf_size, dtype=np.int64) random_idx = 0 result = defaultdict(list) for item in items: bin_ = bin_f(item) heap = result[bin_] # pull a random value, and recompute random values if we've consumed # our buffer random_value = random_values[random_idx] random_idx += 1 if random_idx >= buf_size: random_values = rng.integers(0, sys.maxsize, buf_size, dtype=np.int64) random_idx = 0 # push our item on to the heap and drop the smallest if necessary heappush(heap, (random_value, copy(item))) if len(heap) > maximum: heappop(heap) # yield items for bin_, heap in result.items(): if len(heap) < minimum: continue for _, item in heap: yield (bin_, item) def subsample_counts(counts, n, replace=False, seed=None): """Randomly subsample from a vector of counts, with or without replacement. Parameters ---------- counts : 1-D array_like Vector of counts (integers or floats) to randomly subsample from. n : int Number of items to subsample from `counts`. Must be less than or equal to the sum of `counts`. replace : bool, optional If ``True``, subsample with replacement. If ``False`` (the default), subsample without replacement. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. Returns ------- subsampled : ndarray Subsampled vector of counts where the sum of the elements equals `n` (i.e., ``subsampled.sum() == n``). Will have the same shape as `counts`. Raises ------ ValueError If `n` is less than zero or greater than the sum of `counts` when `replace=False`. See Also -------- isubsample skbio.diversity.alpha Notes ----- If subsampling is performed without replacement (``replace=False``), a copy of `counts` is returned if `n` is equal to the number of items in `counts`, as all items will be chosen from the original vector. If subsampling is performed with replacement (``replace=True``) and `n` is equal to the number of items in `counts`, the subsampled vector that is returned may not necessarily be the same vector as `counts`. Examples -------- Subsample 4 items (without replacement) from a vector of counts: >>> import numpy as np >>> from skbio.stats import subsample_counts >>> a = np.array([4, 5, 0, 2, 1]) >>> sub = subsample_counts(a, 4) >>> sub.sum() 4 >>> sub.shape (5,) Trying to subsample an equal number of items (without replacement) results in the same vector as our input: >>> subsample_counts([0, 3, 0, 1], 4) array([0, 3, 0, 1]) Subsample 5 items (with replacement): >>> sub = subsample_counts([1, 0, 1, 2, 2, 3, 0, 1], 5, replace=True) >>> sub.sum() 5 >>> sub.shape (8,) """ if n < 0: raise ValueError("n cannot be negative.") # cast to float as that's what the biom subsample method currently requires counts = np.asarray(counts, dtype=float) if counts.ndim != 1: raise ValueError("Only 1-D vectors are supported.") # csr_array will report ndim of 2 if vector counts = sparse.csr_array(counts) counts_sum = counts.sum() if n > counts_sum and not replace: raise ValueError( "Cannot subsample more items than exist in input " "counts vector when `replace=False`." ) rng = get_rng(seed) biom_subsample(counts, n, replace, rng) return np.atleast_1d(counts.astype(int).toarray().squeeze()) scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/000077500000000000000000000000001520735541300231635ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/__init__.py000066400000000000000000000120111520735541300252670ustar00rootroot00000000000000r"""Composition Statistics (:mod:`skbio.stats.composition`) ======================================================= .. currentmodule:: skbio.stats.composition This module provides functions for compositional data analysis. Many omics datasets are inherently compositional -- meaning that they are best interpreted as proportions or percentages rather than absolute counts. Formally, sample :math:`x` is a composition if :math:`\sum_{i=0}^D x_{i} = c` and :math:`x_{i} > 0`, :math:`1 \leq i \leq D` and :math:`c` is a real-valued constant and there are :math:`D` components (features) for this composition. In this module :math:`c=1`. Compositional data can be analyzed using **Aitchison geometry** [1]_. However, in this framework, standard real Euclidean operations such as addition and multiplication no longer apply. Only operations such as perturbation and power can be used to manipulate this data. This module allows two styles of manipulation of compositional data. Compositional data can be analyzed using perturbation and power operations, which can be useful for simulation studies. The alternative strategy is to transform compositional data into the real space. Right now, the centre log ratio transform (clr) and the isometric log ratio transform (ilr) [2]_ can be used to accomplish this. This transform can be useful for performing standard statistical methods such as parametric hypothesis testing, regression and more. The major caveat of using this framework is dealing with zeros. In Aitchison geometry, only compositions with non-zero components can be considered. The multiplicative replacement technique [3]_ can be used to substitute these zeros with small pseudocounts without introducing major distortions to the data. Differential abundance ---------------------- Statistical tests for the differential abundance (DA) of components among groups of compositions. .. autosummary:: :toctree: ancom ancombc dirmult_ttest dirmult_lme struc_zero .. note:: Differential abundance tests will be moved to a separate module ``differential`` in the next release of scikit-bio. The current location will be kept as an alias. Arithmetic operations --------------------- Manipulate compositional data within the Aitchison space. .. autosummary:: :toctree: centralize closure inner perturb perturb_inv power Log-ratio transformation ------------------------ Convert compositional data into log-ratio space to enable subsequent comparison and statistical analysis. .. autosummary:: :toctree: alr alr_inv clr clr_inv rclr ilr ilr_inv .. note:: Arithmetic operations and log-ratio transformations support array formats compliant with the `Python array API standard `_ without transition through NumPy. For example, they can directly consume and return GPU-resident PyTorch tensors. Correlation analysis -------------------- Measure the pairwise relationships of compositional data. .. autosummary:: :toctree: vlr pairwise_vlr Zero handling ------------- Replace zero values in compositional data with positive values, which is necessary prior to logarithmic operations. .. autosummary:: :toctree: multi_replace Basis construction ------------------ Generate basis vectors for compositional data via hierarchical partitioning, to allow for decomposition and transformation, such as ilr transform. .. autosummary:: :toctree: sbp_basis tree_basis References ---------- .. [1] V. Pawlowsky-Glahn, J. J. Egozcue, R. Tolosana-Delgado (2015), Modeling and Analysis of Compositional Data, Wiley, Chichester, UK .. [2] J. J. Egozcue., "Isometric Logratio Transformations for Compositional Data Analysis" Mathematical Geology, 35.3 (2003) .. [3] J. A. Martin-Fernandez, "Dealing With Zeros and Missing Values in Compositional Data Sets Using Nonparametric Imputation", Mathematical Geology, 35.3 (2003) """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._base import ( centralize, closure, inner, perturb, perturb_inv, power, alr, alr_inv, clr, clr_inv, rclr, ilr, ilr_inv, vlr, pairwise_vlr, multi_replace, sbp_basis, tree_basis, ) from ._ancom import ancom from ._ancombc import ancombc, struc_zero from ._dirmult import dirmult_ttest, dirmult_lme __all__ = [ "centralize", "closure", "inner", "perturb", "perturb_inv", "power", "alr", "alr_inv", "clr", "clr_inv", "rclr", "ilr", "ilr_inv", "vlr", "pairwise_vlr", "multi_replace", "sbp_basis", "tree_basis", "ancom", "ancombc", "struc_zero", "dirmult_ttest", "dirmult_lme", ] scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/_ancom.py000066400000000000000000000373211520735541300247770ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np import pandas as pd from skbio.util._decorator import params_aliased from skbio.table._tabular import _ingest_table from ._base import _check_composition from ._utils import _check_grouping, _check_sig_test, _check_p_adjust @params_aliased( [ ("p_adjust", "multiple_comparisons_correction", "0.6.0", True), ("sig_test", "significance_test", "0.7.0", True), ] ) def ancom( table, grouping, alpha=0.05, tau=0.02, theta=0.1, p_adjust="holm", sig_test="f_oneway", percentiles=None, ): r"""Perform differential abundance test using ANCOM. Analysis of composition of microbiomes (ANCOM) is done by calculating pairwise log ratios between all features and performing a significance test to determine if there is a significant difference in feature ratios with respect to the variable of interest. In an experiment with only two treatments, this tests the following hypothesis for feature :math:`i`: .. math:: H_{0i}: \mathbb{E}[\ln(u_i^{(1)})] = \mathbb{E}[\ln(u_i^{(2)})] where :math:`u_i^{(1)}` is the mean abundance for feature :math:`i` in the first group and :math:`u_i^{(2)}` is the mean abundance for feature :math:`i` in the second group. .. versionchanged:: 0.7.0 Computational efficiency significantly improved. Parameters ---------- table : table_like of shape (n_samples, n_features) Matrix of strictly positive values (i.e. counts or proportions). See :ref:`supported formats `. .. note:: If the table contains zero values, one should add a pseudocount or apply :func:`multi_replace` to convert all values into positive numbers. grouping : pd.Series or 1-D array_like Vector indicating the assignment of samples to groups. These could be strings or integers denoting which group a sample belongs to. If it is a pandas Series and the table contains sample IDs, its index will be filtered and reordered to match the sample IDs. Otherwise, it must be the same length as the samples in the table. alpha : float, optional Significance level for each of the statistical tests. This can can be anywhere between 0 and 1 exclusive. tau : float, optional A constant used to determine an appropriate cutoff. A value close to zero indicates a conservative cutoff. This can can be anywhere between 0 and 1 exclusive. theta : float, optional Lower bound for the proportion for the *W*-statistic. If all *W*- statistics are lower than theta, then no features will be detected to be significantly different. This can can be anywhere between 0 and 1 exclusive. p_adjust : str, optional Method to correct *p*-values for multiple comparisons. Options are Holm-Boniferroni ("holm" or "holm-bonferroni") (default), Benjamini-Hochberg ("bh", "fdr_bh" or "benjamini-hochberg"), or any method supported by statsmodels' :func:`~statsmodels.stats.multitest.multipletests` function. Case-insensitive. If None, no correction will be performed. sig_test : str or callable, optional A function to test for significance between classes. It must be able to accept at least two vectors of floats and returns a test statistic and a *p*-value. Functions under ``scipy.stats`` can be directly specified by name. The default is one-way ANOVA ("f_oneway"). .. versionchanged:: 0.7.0 Test function must accept 2-D arrays as input, perform batch testing, and return 1-D arrays. SciPy functions have this capability. Custom functions may need modification. .. versionchanged:: 0.6.0 Accepts test names in addition to functions. percentiles : iterable of floats, optional Percentile abundances to return for each feature in each group. By default, will return the minimum, 25th percentile, median, 75th percentile, and maximum abundances for each feature in each group. Returns ------- pd.DataFrame A table of features, their *W*-statistics and whether the null hypothesis is rejected. - ``W``: *W*-statistic, or the number of features that the current feature is tested to be significantly different against. - ``Signif``: Whether the feature is significantly differentially abundant across groups (``True``) or not (``False``). .. versionchanged:: 0.7.0 Renamed ``Reject null hypothesis`` as ``Signif``. pd.DataFrame A table of features and their percentile abundances in each group. If ``percentiles`` is empty, this will be an empty ``pd.DataFrame``. The rows in this object will be features, and the columns will be a multi-index where the first index is the percentile, and the second index is the group. See Also -------- ancombc multi_replace scipy.stats.ttest_ind scipy.stats.f_oneway scipy.stats.wilcoxon scipy.stats.kruskal Notes ----- The developers of ANCOM recommend the following significance tests ([1]_, Supplementary File 1, top of page 11): - If there are two groups, use the standard parametric *t*-test (``ttest_ind``) or the non-parametric Mann-Whitney rank test (``mannwhitneyu``). - For paired samples, use the parametric paired *t*-test (``ttest_rel``) or the non-parametric Wilcoxon signed-rank test (``wilcoxon``). - If there are more than two groups, use the parametric one-way ANOVA (``f_oneway``) or the non-parametric Kruskal-Wallis test (``kruskal``). - If there are multiple measurements obtained from the individuals, use a Friedman test (``friedmanchisquare``). Because one-way ANOVA is equivalent to the standard *t*-test when the number of groups is two, we default to ``f_oneway`` here, which can be used when there are two or more groups. Users should refer to the documentation of these tests in SciPy to understand the assumptions made by each test. This method cannot handle any zero counts as input, since the logarithm of zero cannot be computed. While this is an unsolved problem, many studies, including [1]_, have shown promising results by adding pseudocounts to all values in the matrix. In [1]_, a pseudocount of 0.001 was used, though the authors note that a pseudocount of 1.0 may also be useful. Zero counts can also be addressed using the ``multi_replace`` method. References ---------- .. [1] Mandal et al. "Analysis of composition of microbiomes: a novel method for studying microbial composition", Microbial Ecology in Health & Disease, (2015), 26. Examples -------- >>> from skbio.stats.composition import ancom >>> import pandas as pd Let's load in a DataFrame with six samples and seven features (e.g., these may be bacterial taxa): >>> table = pd.DataFrame([[12, 11, 10, 10, 10, 10, 10], ... [9, 11, 12, 10, 10, 10, 10], ... [1, 11, 10, 11, 10, 5, 9], ... [22, 21, 9, 10, 10, 10, 10], ... [20, 22, 10, 10, 13, 10, 10], ... [23, 21, 14, 10, 10, 10, 10]], ... index=['s1', 's2', 's3', 's4', 's5', 's6'], ... columns=['b1', 'b2', 'b3', 'b4', 'b5', 'b6', ... 'b7']) Then create a grouping vector. In this example, there is a treatment group and a placebo group. >>> grouping = pd.Series(['treatment', 'treatment', 'treatment', ... 'placebo', 'placebo', 'placebo'], ... index=['s1', 's2', 's3', 's4', 's5', 's6']) Now run ``ancom`` to determine if there are any features that are significantly different in abundance between the treatment and the placebo groups. The first DataFrame that is returned contains the ANCOM test results, and the second contains the percentile abundance data for each feature in each group. >>> ancom_df, percentile_df = ancom(table, grouping) >>> ancom_df['W'] # doctest: +ELLIPSIS b1 0 b2 4 b3 0 b4 1 b5 1 b6 0 b7 1 Name: W, dtype: ... The *W*-statistic is the number of features that a single feature is tested to be significantly different against. In this scenario, ``b2`` was detected to have significantly different abundances compared to four of the other features. To summarize the results from the *W*-statistic, let's take a look at the results from the hypothesis test. The ``Signif`` column in the table indicates whether the null hypothesis was rejected, and that a feature was therefore observed to be differentially abundant across the groups. >>> ancom_df['Signif'] b1 False b2 True b3 False b4 False b5 False b6 False b7 False Name: Signif, dtype: bool From this we can conclude that only ``b2`` was significantly different in abundance between the treatment and the placebo. We still don't know, for example, in which group ``b2`` was more abundant. We therefore may next be interested in comparing the abundance of ``b2`` across the two groups. We can do that using the second DataFrame that was returned. Here we compare the median (50th percentile) abundance of ``b2`` in the treatment and placebo groups: >>> percentile_df[50.0].loc['b2'] Group placebo 21.0 treatment 11.0 Name: b2, dtype: float64 We can also look at a full five-number summary for ``b2`` in the treatment and placebo groups: >>> percentile_df.loc['b2'] # doctest: +NORMALIZE_WHITESPACE Percentile Group 0.0 placebo 21.0 25.0 placebo 21.0 50.0 placebo 21.0 75.0 placebo 21.5 100.0 placebo 22.0 0.0 treatment 11.0 25.0 treatment 11.0 50.0 treatment 11.0 75.0 treatment 11.0 100.0 treatment 11.0 Name: b2, dtype: float64 Taken together, these data tell us that ``b2`` is present in significantly higher abundance in the placebo group samples than in the treatment group samples. """ matrix, samples, features = _ingest_table(table) groups, labels = _check_grouping(grouping, matrix, samples) _check_composition(np, matrix, nozero=True) # validate parameters if not 0 < alpha < 1: raise ValueError("`alpha`=%f is not within 0 and 1." % alpha) if not 0 < tau < 1: raise ValueError("`tau`=%f is not within 0 and 1." % tau) if not 0 < theta < 1: raise ValueError("`theta`=%f is not within 0 and 1." % theta) # validate percentiles if percentiles is None: percentiles = np.arange(0, 125, 25.0) else: if not isinstance(percentiles, np.ndarray): percentiles = np.fromiter(percentiles, dtype=float) if (percentiles < 0.0).any() or (percentiles > 100.0).any(): raise ValueError("Percentiles must be in the range [0, 100].") n_pcts = len(percentiles) percentiles = np.unique(percentiles) if percentiles.size != n_pcts: raise ValueError("Percentile values must be unique.") n_groups = len(groups) if n_groups == len(labels): raise ValueError( "All values in `grouping` are unique. This method cannot " "operate on a grouping vector with only unique values (e.g., " "there are no 'within' variance because each group of samples " "contains only a single sample)." ) elif n_groups == 1: raise ValueError( "All values the `grouping` are the same. This method cannot " "operate on a grouping vector with only a single group of samples" "(e.g., there are no 'between' variance because there is only a " "single group)." ) # validate significance test if sig_test is None: sig_test = "f_oneway" test_f = _check_sig_test(sig_test, n_groups) # compare log ratios pval_mat = _log_compare(matrix, labels, n_groups, test_f) # correct for multiple testing problem if p_adjust is not None: func = _check_p_adjust(p_adjust) pval_mat = np.apply_along_axis(func, 1, pval_mat) np.fill_diagonal(pval_mat, 1) # calculate W-statistics n_feats = matrix.shape[1] W = (pval_mat < alpha).sum(axis=1) c_start = W.max() / n_feats if c_start < theta: reject = np.zeros_like(W, dtype=bool) else: # Select appropriate cutoff cutoff = c_start - np.linspace(0.05, 0.25, 5) prop_cut = (W[:, None] > n_feats * cutoff).mean(axis=0) dels = np.abs(prop_cut - np.roll(prop_cut, -1)) dels[-1] = 0 if (dels[0] < tau) and (dels[1] < tau) and (dels[2] < tau): nu = cutoff[1] elif (dels[0] >= tau) and (dels[1] < tau) and (dels[2] < tau): nu = cutoff[2] elif (dels[1] >= tau) and (dels[2] < tau) and (dels[3] < tau): nu = cutoff[3] else: nu = cutoff[4] reject = W >= nu * n_feats ancom_df = pd.DataFrame( { "W": pd.Series(W, index=features), "Signif": pd.Series(reject, index=features), } ) # calculate percentiles if percentiles.size == 0: return ancom_df, pd.DataFrame() data = [] columns = [] for i, group in enumerate(groups): feat_dists = matrix[labels == i] for percentile in percentiles: columns.append((percentile, group)) data.append(np.percentile(feat_dists, percentile, axis=0)) columns = pd.MultiIndex.from_tuples(columns, names=["Percentile", "Group"]) percentile_df = pd.DataFrame(np.asarray(data).T, columns=columns, index=features) return ancom_df, percentile_df def _log_compare(matrix, labels, n, test): """Compare pairwise log ratios between sample groups. Calculate pairwise log ratios between all features and perform a statistical test to determine if there is a significant difference in feature ratios with respect to the variable of interest. Parameters ---------- matrix : ndarray of shape (n_samples, n_features) Data matrix. labels : ndarray of shape (n_samples,) Group indices (0-indexed, consecutive). n : int Number of groups. test : callable Statistical test to run. Returns ------- ndarray of shape (n_features, n_features) p-value matrix. """ # note: `n` can be simply computed with `labels.max()`. It is supplied instead to # save compute. # log-transform data log_mat = np.log(matrix) # divide data by sample group grouped = [log_mat[labels == i] for i in range(n)] # determine all pairs of feature indices m = matrix.shape[1] ii, jj = np.triu_indices(m, k=1) # calculate all log ratios (pairwise difference of log values) log_ratios = [x[:, ii] - x[:, jj] for x in grouped] # run statistical test on the 2-D arrays in a vectorized manner _, pvals = test(*log_ratios) # populate p-value matrix pval_mat = np.empty((m, m)) pval_mat[ii, jj] = pval_mat[jj, ii] = pvals np.fill_diagonal(pval_mat, 0) return pval_mat scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/_ancombc.py000066400000000000000000001331561520735541300253070ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- # This implementation of ANCOM-BC is based on an analysis of the source code # from the R package ANCOMBC: # - https://github.com/FrederickHuangLin/ANCOMBC # # Which is licensed under Artistic-2.0: # - https://www.bioconductor.org/packages/release/bioc/html/ANCOMBC.html # # We thank Dr. Huang Lin (@FrederickHuangLin) for his helpful advice. # ---------------------------------------------------------------------------- import numpy as np import pandas as pd from scipy.stats import norm, chi2 from scipy.optimize import minimize from patsy import dmatrix from skbio.table._tabular import _ingest_table from ._base import _check_composition from ._utils import _check_metadata, _check_p_adjust, _type_cast_to_float def ancombc( table, metadata, formula, grouping=None, max_iter=100, tol=1e-5, alpha=0.05, p_adjust="holm", ): r"""Perform differential abundance test using ANCOM-BC. Analysis of compositions of microbiomes with bias correction (ANCOM-BC) [1]_ is a differential abundance testing method featuring the estimation and correction for the bias of differential sampling fractions. .. versionadded:: 0.7.1 Parameters ---------- table : table_like of shape (n_samples, n_features) A matrix containing strictly positive count or proportional abundance data of the samples. See :ref:`supported formats `. .. note:: If the table contains zero values, one should add a pseudocount or apply :func:`multi_replace` to convert all values into positive numbers. metadata : pd.DataFrame or 2-D array_like Metadata of the samples. Rows correspond to samples and columns correspond to covariates (attributes). Must be a pandas DataFrame or convertible to a pandas DataFrame. formula : str or generic Formula object A formula defining the model using factors included in the metadata columns. Refer to `Patsy's documentation `_ on how to specify a formula. grouping : str, optional A metadata column name of interest for *global test*, which identifies features that are differentially abundant between at least two groups across three or more groups in that column. Must be one of the factors in ``formula``. Default is None, which skips global test. max_iter : int, optional Maximum number of iterations for the bias estimation process. Default is 100. tol : float, optional Absolute convergence tolerance for the bias estimation process. Default is 1e-5. alpha : float, optional Significance level for the statistical tests. Must be in the range of (0, 1). Default is 0.05. p_adjust : str, optional Method to correct *p*-values for multiple comparisons. Options are Holm-Boniferroni ("holm" or "holm-bonferroni") (default), Benjamini-Hochberg ("bh", "fdr_bh" or "benjamini-hochberg"), or any method supported by statsmodels' :func:`~statsmodels.stats.multitest.multipletests` function. Case-insensitive. If None, no correction will be performed. Returns ------- res_main : pd.DataFrame A table of features and covariates, their log-fold changes and other relevant statistics of the primary ANCOM-BC analysis. - ``FeatureID``: Feature identifier, i.e., dependent variable. - ``Covariate``: Covariate name, i.e., independent variable. - ``Log2(FC)``: Expected log2-fold change of abundance from the reference category to the covariate category defined in the formula. The value is expressed in the center log ratio (see :func:`clr`) transformed coordinates. - ``SE``: Standard error of the estimated Log2(FC). - ``W``: *W*-statistic, or the number of features that the current feature is tested to be significantly different against. - ``pvalue``: *p*-value of the ANCOM-BC test. - ``qvalue``: Corrected *p*-value of the ANCOM-BC test for multiple comparisons. - ``Signif``: Whether the covariate category is significantly differentially abundant from the reference category. A feature-covariate pair is marked as "True" if the *q*-value is less than or equal to the significance level (``alpha``). res_global : pd.DataFrame, optional A table of features and statistics from the global test (when ``grouping`` is set). - ``FeatureID``: Feature identifier, i.e., dependent variable. - ``W``: *W*-statistic of Chi-squared statistic that quantifies the overall evidence against null hypothesis (the mean abundance of the feature is the same across all groups). - ``pvalue``: *p*-value of the *W*-statistic in global test. - ``qvalue``: Corrected *p*-value in global test. - ``Signif``: Whether at least one group mean is different from other in grouping variable. See Also -------- ancom struc_zero multi_replace Notes ----- This function is a Python re-implementation of the ANCOM-BC method [1]_, which was originally implemented in the R package ``ANCOMBC``. This function provides an efficient and scalable algorithm, with a simple interface consistent with other scikit-bio components. The output of this function should match that of the R package. Comparing with the R command ``ancombc``, this function defers the flexibility of data preprocessing to the user. Most importantly, if the input table contains zero values (which is common), one needs to remove them by, e.g., adding a pseudocount of 1 (``pseudo=1`` in the R command's parameters) (assuming ``table`` is a pandas DataFrame): .. code-block:: python table += 1 See also :func:`multi_replace` for additional information on zero handling. Some other pre-processing options provided by the R command can be performed with: To aggregate data at a given taxonomic level (``tax_level="Family"``): .. code-block:: python table = table.T.groupby(feature_to_family_dict).sum().T To discard features with prevalence < 10% among samples (``prv_cut=0.1``): .. code-block:: python table = table.loc[:, (table > 0).mean() >= 0.1] To discard samples with a total abundance < 1 million (``lib_cut=1e6``): .. code-block:: python table = table.loc[table.sum(axis=1) >= 1e6] Categorical columns in metadata are sorted alphabetically, and the reference level for each column is automatically set to be the first category. If this behavior is not intended, you will need to change the order manually, like: .. code-block:: python metadata['bmi'] = pd.Categorical( metadata['bmi'], categories=['lean', 'overweight', 'obese'], ordered=True) References ---------- .. [1] Lin, H. and Peddada, S.D., 2020. Analysis of compositions of microbiomes with bias correction. Nature Communications, 11(1), p.3514. Examples -------- >>> from skbio.stats.composition import ancombc >>> import pandas as pd **A basic example** Let's create a data table with six samples and seven features (e.g., these may be microbial taxa): >>> samples = ['S1', 'S2', 'S3', 'S4', 'S5', 'S6'] >>> features = ['F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7'] >>> table = pd.DataFrame( ... [[ 2, 0, 4, 7, 0, 0, 1], ... [ 1, 1, 0, 6, 5, 1, 10], ... [ 3, 0, 2, 9, 6, 0, 1], ... [ 0, 12, 1, 2, 0, 3, 2], ... [ 2, 2, 37, 0, 0, 7, 3], ... [10, 1, 0, 0, 4, 4, 3]], ... index=samples, columns=features) Then create a sampling grouping vector. In this example, there is a "healthy" group and a "sick" group. >>> grouping = ['healthy', 'healthy', 'healthy', 'sick', 'sick', 'sick'] >>> metadata = pd.Series(grouping, index=samples, name='status').to_frame() Now run ``ancombc`` to determine if there are any features that are significantly different in abundance between the healthy and the sick groups. Note that a pseudocount of 1 is manually added to the table to remove zero values. >>> result = ancombc(table + 1, metadata, formula='status') >>> result.round(3) Log2(FC) SE W pvalue qvalue Signif FeatureID Covariate F1 Intercept -0.045 0.218 -0.207 0.836 1.000 False status[T.sick] 0.126 0.589 0.214 0.831 1.000 False F2 Intercept -0.873 0.137 -6.381 0.000 0.000 True status[T.sick] 1.241 0.538 2.307 0.021 0.105 False F3 Intercept -0.202 0.475 -0.425 0.671 1.000 False status[T.sick] 0.561 0.964 0.582 0.561 1.000 False F4 Intercept 1.005 0.136 7.399 0.000 0.000 True status[T.sick] -1.723 0.392 -4.399 0.000 0.000 True F5 Intercept 0.141 0.422 0.335 0.738 1.000 False status[T.sick] -0.690 0.625 -1.104 0.270 1.000 False F6 Intercept -0.873 0.137 -6.381 0.000 0.000 True status[T.sick] 1.480 0.160 9.255 0.000 0.000 True F7 Intercept 0.157 0.401 0.391 0.695 1.000 False status[T.sick] 0.049 0.405 0.121 0.904 1.000 False The covariate "status[T.sick]" stands for the effect of the "sick" group relative to the reference group, "healthy" (the first group in alphabetical order is automatically selected as the reference group). "Log2(FC)" represents the :func:`clr`-transformed fold change of abundance (positive/negative: more/less abundant in "sick" than in "healthy", respectively). A "True" in the "Signif" column indicates a significantly differentially abundant feature-covariate pair. This example shows that two features differ by healthy/sick status. >>> result.query('Covariate != "Intercept" & Signif == True').round(3) Log2(FC) SE W pvalue qvalue Signif FeatureID Covariate F4 status[T.sick] -1.723 0.392 -4.399 0.0 0.0 True F6 status[T.sick] 1.480 0.160 9.255 0.0 0.0 True **An advanced example** Now we will create a complex dataset with 15 samples grouped into three disease status: "mild", "moderate" and "severe", plus age as a confounder. Our goal is to identify features that are differentially abundant between disease status. >>> samples = [f'S{i}' for i in range(1, 16)] >>> features = [f'F{i}' for i in range(1, 9)] >>> data = [[ 2, 0, 7, 0, 0, 2, 3, 2], ... [ 0, 2, 0, 1, 1, 2, 0, 0], ... [ 3, 1, 0, 9, 0, 1, 1, 0], ... [ 2, 0, 1, 8, 1, 0, 11, 46], ... [ 1, 0, 1, 1, 0, 0, 2, 2], ... [ 0, 3, 22, 1, 1, 1, 3, 0], ... [ 1, 7, 16, 1, 0, 0, 2, 2], ... [ 0, 5, 6, 1, 2, 1, 0, 1], ... [ 1, 7, 0, 2, 1, 0, 3, 2], ... [ 0, 6, 4, 2, 0, 2, 2, 1], ... [ 3, 13, 7, 0, 0, 0, 3, 9], ... [ 1, 8, 5, 1, 0, 0, 0, 0], ... [ 0, 5, 14, 1, 0, 1, 0, 1], ... [ 5, 26, 3, 2, 0, 3, 1, 3], ... [ 0, 18, 7, 0, 0, 3, 1, 0]] >>> table = pd.DataFrame(data, index=samples, columns=features) >>> status = ['mild'] * 5 + ['moderate'] * 5 + ['severe'] * 5 >>> age = [39, 19, 20, 31, 15, 37, 27, 47, 26, 23, 39, 48, 46, 33, 36] >>> metadata = pd.DataFrame({'status': status, 'age': age}, index=samples) Run ``ancombc``. This time, we specify two factors: "status" and "age" in the formula, such that the function will test the individual effects of each factor while controlling for the other. Additionally, we instruct the function to perform a *global test* on "status", which identifies features that are differentially abundant between at least two status. >>> res_main, res_global = ancombc( ... table + 1, metadata, formula='status + age', grouping='status') >>> res_main.round(3) Log2(FC) SE W pvalue qvalue Signif FeatureID Covariate F1 Intercept -0.006 0.346 -0.016 0.987 1.000 False status[T.moderate] -0.337 0.245 -1.376 0.169 1.000 False status[T.severe] 0.278 0.350 0.792 0.428 1.000 False age 0.002 0.011 0.141 0.888 1.000 False F2 Intercept 0.072 0.446 0.160 0.873 1.000 False status[T.moderate] 1.906 0.259 7.371 0.000 0.000 True status[T.severe] 2.935 0.304 9.649 0.000 0.000 True age -0.022 0.013 -1.676 0.094 0.562 False F3 Intercept -1.690 0.570 -2.967 0.003 0.021 True status[T.moderate] 1.010 0.578 1.747 0.081 0.565 False status[T.severe] 0.717 0.517 1.388 0.165 1.000 False age 0.063 0.022 2.883 0.004 0.031 True F4 Intercept 0.439 0.483 0.910 0.363 1.000 False status[T.moderate] -0.046 0.405 -0.113 0.910 1.000 False status[T.severe] -0.244 0.536 -0.455 0.649 1.000 False age -0.003 0.019 -0.185 0.854 1.000 False F5 Intercept -1.227 0.393 -3.125 0.002 0.014 True status[T.moderate] 0.274 0.293 0.934 0.350 1.000 False status[T.severe] -0.323 0.320 -1.011 0.312 1.000 False age 0.027 0.014 2.021 0.043 0.303 False F6 Intercept -0.439 0.440 -0.999 0.318 1.000 False status[T.moderate] 0.114 0.432 0.264 0.792 1.000 False status[T.severe] 0.375 0.544 0.691 0.490 1.000 False age 0.008 0.016 0.480 0.631 1.000 False F7 Intercept 0.201 0.472 0.426 0.670 1.000 False status[T.moderate] 0.082 0.302 0.270 0.787 1.000 False status[T.severe] -0.264 0.401 -0.658 0.510 1.000 False age 0.004 0.016 0.272 0.785 1.000 False F8 Intercept -0.168 0.526 -0.319 0.750 1.000 False status[T.moderate] -0.402 0.584 -0.688 0.491 1.000 False status[T.severe] -0.299 0.728 -0.411 0.681 1.000 False age 0.022 0.018 1.237 0.216 1.000 False We found that feature "F2" is significantly differentially (more) abundant in "moderate" and "severe" groups compared with "mild", which serves as the reference group. Additionally, feature "F3" is separately correlated with age. >>> res_main.query('Covariate != "Intercept" & Signif == True').round(3) Log2(FC) SE W pvalue qvalue Signif FeatureID Covariate F2 status[T.moderate] 1.906 0.259 7.371 0.000 0.000 True status[T.severe] 2.935 0.304 9.649 0.000 0.000 True F3 age 0.063 0.022 2.883 0.004 0.031 True The global test result suggests that "F2" and "F4" are differentially abundant between two of the three groups (though it doesn't tell which groups). >>> res_global.round(3) W pvalue qvalue Signif FeatureID F1 1.855 0.791 1.000 False F2 80.771 0.000 0.000 True F3 2.925 0.463 1.000 False F4 -0.093 0.000 0.000 True F5 1.068 0.827 1.000 False F6 0.121 0.117 0.704 False F7 0.220 0.208 1.000 False F8 0.485 0.430 1.000 False **Structural zero test** The structural zero test identifies features that are systematically absent from certain sample groups. This test is an option of the R command ``ancombc``. In scikit-bio, :func:`struc_zero` is a standalone function, as it is generally useful with or without ANCOM-BC. >>> from skbio.stats.composition import struc_zero >>> res_zero = struc_zero(table, metadata, 'status') >>> res_zero mild moderate severe F1 False False False F2 False False False F3 False False False F4 False False False F5 False False True F6 False False False F7 False False False F8 False False False The result reveals that feature "F5" is a structural zero in the "severe" groups, as all or most of its values are zero. Although the ANCOM-BC test itself didn't identify "F5", we should consider it as differentially (less) abundant than in the other two groups. We can use this additional information to update the global test result. The rule is that a feature should be considered as globally differentially abundant if it is a structural zero in at least one but not all groups. >>> signif_global = res_global['Signif'] | ( ... ~res_zero.all(axis=1) & res_zero.any(axis=1)) >>> signif_global FeatureID F1 False F2 True F3 False F4 True F5 True F6 False F7 False F8 False dtype: bool The main ANCOM-BC result can also be updated with structural zeros. >>> signif_main = res_main.query( ... 'Covariate.str.startswith("status[T.")')['Signif'].unstack() >>> signif_main.columns = signif_main.columns.str.removeprefix( ... 'status[T.').str.removesuffix(']') >>> signif_zero = res_zero.loc[signif_main.index, signif_main.columns] >>> signif_main |= signif_zero >>> signif_main.columns.name = None >>> signif_main moderate severe FeatureID F1 False False F2 True True F3 False False F4 False False F5 False True F6 False False F7 False False F8 False False """ # Note: A pseudocount should have been added to the table by the user prior to # calling this function. matrix, samples, features = _ingest_table(table) _check_composition(np, matrix, nozero=True) n_feats = matrix.shape[1] if features is None: features = np.arange(n_feats) # Log-transform count matrix. matrix = np.log(matrix) # Validate metadata and cast to numbers where applicable. metadata = _check_metadata(metadata, matrix, samples) metadata = _type_cast_to_float(metadata) if grouping is not None and len(metadata[grouping].unique()) < 3: raise ValueError("Global test cannot be performed on less than three groups.") # Create a design matrix based on metadata and formula. dmat = dmatrix(formula, metadata) # Obtain a list of covariates by selecting the relevant columns. covars = dmat.design_info.column_names n_covars = len(covars) # validate parameters if not 0 < alpha < 1: raise ValueError("`alpha`=%f is not within 0 and 1." % alpha) # Estimate initial model parameters. var_hat, beta, _, vcov_hat = _estimate_params(matrix, dmat) # Estimate and correct for sampling bias via expectation-maximization (EM). bias = np.empty((n_covars, 3)) for i in range(n_covars): bias[i] = _estimate_bias_em(beta[i], var_hat[:, i], tol=tol, max_iter=max_iter) delta_em = bias[:, 0] # Correct coefficients (logFC) according to estimated bias. beta_hat = beta.T - delta_em # Calculate statistics while performing multiple testing correction. se_hat, W, pval, qval = _calc_statistics(beta_hat, var_hat, method=p_adjust) # Identify significantly differentially abundance feature-covariate pairs. reject = qval <= alpha # Output the primary results. res = pd.DataFrame.from_dict( { "FeatureID": [x for x in features for _ in range(n_covars)], "Covariate": list(covars) * n_feats, "Log2(FC)": beta_hat.ravel(), "SE": se_hat.ravel(), "W": W.ravel(), "pvalue": pval.ravel(), "qvalue": qval.ravel(), } ) # Pandas' nullable boolean type res["Signif"] = pd.Series(reject.ravel(), dtype="boolean") res.set_index(["FeatureID", "Covariate"], inplace=True) # Output global test results if grouping is not None: res_global = _global_test(dmat, grouping, beta_hat, vcov_hat, alpha, p_adjust) res_global_df = pd.DataFrame.from_dict( { "FeatureID": features, "W": res_global[0], "pvalue": res_global[1], "qvalue": res_global[2], "Signif": res_global[3], } ) res_global_df.set_index("FeatureID", inplace=True) return res, res_global_df return res # , None def _estimate_params(data, dmat): """Estimate initial model parameters. Perform initial estimation of model parameters (coefficients, variances and mean residuals) based on the observed data prior to bias correction. Parameters ---------- data : ndarray of shape (n_samples, n_features) Data table. Must be zero-handled and log-transformed. dmat : ndarray of shape (n_samples, n_covariates) Design matrix. Returns ------- var_hat : ndarray of shape (n_features, n_covariates) Estimated variances of regression coefficients. beta : ndarray of shape (n_features, n_covariates) Estimated coefficients (log-fold changes before correction). theta : ndarray of shape (n_samples,) Per-sample mean residuals of estimated data. beta_covmat : ndarray of shape (n_features, n_covariates, n_covariates) Estimated covariance matrices. """ # The original R code performs iterative maximum likelihood estimation to calculate # the coefficients, and calls MASS:ginv to calculate the pseudo inverse Gram matrix # using the Moore-Penrose method. We noticed that the former can be replaced with # ordinary least squares by NumPy's `lstsq`; and the latter matches the method by # NumPy's `pinv`. We further noticed that both functions perform singular value # decomposition (SVD). Therefore, the following code only performs SVD once, and # uses the intermediates to calculate coefficients and inverse Gram matrix. # Perform thin SVD and set small singular values to zero. The process and threshold # (1e-15) are consistent with the underlying algorithm of `pinv`. # Note: the Gram matrix may be singular, if there are colinear covariates in the # design matrix. In such cases, a direct `inv` will raise an error, and `pinv` is # the robust choice. U, S, Vh = np.linalg.svd(dmat, full_matrices=False) S_inv = np.where(S > 1e-15 * np.max(S), 1.0 / S, 0.0) # Regression coefficients V = Vh.T dmat_inv = (V * S_inv) @ U.T beta = dmat_inv @ data # Inverse Gram matrix gmat_inv = (V * S_inv**2) @ Vh # Per-sample mean residuals (theta) diff = data - dmat @ beta theta = np.mean(diff, axis=1, keepdims=True) # Centered residuals eps = diff - theta # Calculate the covariance matrix of the coefficients. The estimated variances are # the diagonal of the covariance matrix. # Note: The original R code uses nested `for` loops over samples and features. The # current implementation is fully vectorized. # Note: The original R code patches NaN with 0.1 when calculating covariances. This # is not needed in the current implementation, as the input data are guaranteed to # contain only finite real numbers. intm_mat = np.einsum("ji,jp,jq->ipq", eps**2, dmat, dmat) beta_covmat = (gmat_inv @ intm_mat) @ gmat_inv var_hat = np.diagonal(beta_covmat, axis1=1, axis2=2) # Note: Residuals are needed for ANCOM-BC2. return var_hat, beta, theta.reshape(-1), beta_covmat def _estimate_bias_em(beta, var_hat, tol=1e-5, max_iter=100): """Estimate sampling bias through an expectation-maximization (EM) algorithm. This function models the observed coefficients (log-fold changes) for a given covariate as a Gaussian mixture distribution with three components: 0) null, 1) negative, 2) positive. It aims to estimate a global bias term (delta) that affects all features. Parameters ---------- beta : ndarray of shape (n_features,) Estimated coefficients (log-fold change before correction). var_hat : ndarray of shape (n_features,) Estimated variances of regression coefficients. tol : float, optional Absolute tolerance of EM iteration. Default is 1e-5. max_iter : int Max number of iteration of EM iteration. Default is 100. Returns ------- delta_em : float EM estimator of bias. delta_wls : float WLS estimator of bias. var_delta : float Estimated variances of bias. """ # This function involves careful memory optimization to avoid creating temporary # arrays during iteration. Technically, the arrays could have been pre-allocated # in the outer function `ancombc` and re-used across covariates, which could # further enhance memory efficiency. It is left as-is for modularity. # The original R code has `na.rm = TRUE` in many commands. This is not necessary # in the current implementation, because the pre-correction coefficients (beta) # is guaranteed to not contain NaN values. # Mask NaN values (deemed unnecessary; left here for future examination). # beta = beta[~np.isnan(beta)] # There might be a chance that numeric optimization produces (near) zero weights # (pi) or variances (kappa), which can cause numerical stability issues in the # EM process. To safe-guard, one may use a small number `eps` as the floor of # those parameters. The original R code doesn't have this mechanism. Therefore, it # is currently disabled. # eps = 1e-12 # Initial model parameters pi0, pi1, pi2 = 0.75, 0.125, 0.125 # weights of components (pi) delta, l1, l2, kappa1, kappa2 = _init_bias_params(beta) params = np.array([pi0, pi1, pi2, delta, l1, l2, kappa1, kappa2]) updated = np.empty(8) # Pre-allocate memory for intermediates. Each array has three rows, representing # the three components (0, 1, 2), and columns representing individual features. # Let delta_i = mu_i1_hat - mu_i2_hat # The distribution of delta_i is modeled by Gaussian mixture: # f(delta_i) = pi0 * phi((delta_i - delta) / nu_i0) + # pi1 * phi((delta_i - (delta + l1)) / nu_i1) + # pi2 * phi((delta_i - (delta + l2)) / nu_i2) # where phi is the normal density function, # (delta + l1) and (delta + l2) are means for delta_i | C1 and delta_i | C2 # nu_i0, nu_i1, and nu_i2 are variances of delta_i | C0, delta_i | C1, and # delta_i | C2 respectively. # We assume nu_i1 = nu_i0 + kappa1 and nu_i2 = nu_i0 + kappa2 for computational # simplicity. n_feats = beta.shape[0] shape = (3, n_feats) nu_inv = np.empty(shape) # inverse of variances stdevs = np.empty(shape) # standard deviations ratios = np.empty(shape) # coefficients / variances # Mean coefficients means = np.empty(3) # Posterior probabilities of feature-component assignments (EM's responsibilities) resp = np.empty(shape) # Just a 2-row array to store random data intm = np.empty((2, n_feats)) # Initialize intermediates. The 1st row is constant, representing pre-correction # estimates, whereas the 2nd and 3rd rows are to be modified during iteration. np.reciprocal(var_hat, out=nu_inv[0]) np.sqrt(var_hat, out=stdevs[0]) np.divide(beta, var_hat, out=ratios[0]) # Objective function for numeric optimization of variance estimation # Note: `norm.logpdf` doesn't have an `out` parameter. To further optimize this, # one needs to manually implement the under-the-hood algorithm. def func(x, loc, resp): log_pdf = norm.logpdf(beta, loc=loc, scale=(var_hat + x) ** 0.5) return -np.dot(resp, log_pdf) # Optimizer arguments. The Nelder-Mead simplex algorithm is used, which is # consistent with the original R code. # Note: The Nelder–Mead method doesn't actually enforce bounds during optimization. # It merely clips at the bounds. For further consideration. args = dict(method="Nelder-Mead", bounds=[(0, None)]) # Expectation-maximization (E-M) iterations loss, epoch = np.inf, 0 while loss > tol and epoch < max_iter: # Update intermediates (2nd and 3rd rows only) np.add(var_hat, params[6:8, None], out=intm) # kappa1, kappa2 np.reciprocal(intm, out=nu_inv[1:]) np.sqrt(intm, out=stdevs[1:]) np.subtract(beta, params[4:6, None], out=ratios[1:]) # means (l) ratios[1:] *= nu_inv[1:] ### E-step ### # Mean coefficients delta = means[0] = params[3] # global bias (delta) np.add(params[4:6], delta, means[1:]) # Posterior probabilities = mean probability density functions weighted by # component fractions # Note: `norm.pdf` doesn't have an `out` parameter. To further optimize this, # one needs to manually implement the under-the-hood algorithm. # p_r,i = (pi_r * phi(delta_i - (delta + l_r) / nu_ir)) / # sum_r(pi_r * phi((delta_i - (dleta + l_r)) / nu_ir)), # where r = 0, 1, 2; i = 1, ..., n_features resp[:] = norm.pdf(beta, means[:, None], stdevs) resp *= params[:3, None] # weights (pi) resp /= np.sum(resp, axis=0, keepdims=True) ### M-step ### # Weights of components (pi) # pi_r_new = mean(pi_r * pdf_r / (pi0 * pdf0 + pi1 * pdf1 + pi2 * pdf2)), # where r = 0, 1, 2 np.mean(resp, axis=1, out=updated[:3]) # Avoid zero weights. # updated[:3] = np.maximum(updated[:3], eps) # updated[:3] /= updated[:3].sum() # Gaussian mixture modeling of global bias (delta) # The following code produces the same result as: # updated[3] = np.sum(resp * ratios) / np.sum(resp * nu_inv) # But it avoids creating intermediate arrays. # delta_new = sum(r_0i * beta / nu0 + # r_1i * (beta - l1) / (nu0 + kappa1) + # r_2i * (beta - l2) / (nu0 + kappa2)) / # sum(r0i / nu0 + r1i / (nu0 + kappa1) + r2i / (nu0 + kappa2)) updated[3] = np.vdot(resp, ratios) / np.vdot(resp, nu_inv) # Negative and positive components relative to delta (l) np.multiply(resp[1:], nu_inv[1:], out=intm) denom = np.sum(intm, axis=1) np.subtract(beta, delta, out=resp[0]) # reuse as intermediate intm *= resp[0] numer = np.sum(intm, axis=1) l1, l2 = numer / denom # l1_new = min(sum(r1i * (beta - delta) / (nu0 + kappa1)) / # sum(r1i / (nu0 + kappa1)), 0) updated[4] = np.minimum(l1, 0) # l2_new = min(sum(r2i * (beta - delta) / (nu0 + kappa2)) / # sum(r2i / (nu0 + kappa2)), 0) updated[5] = np.maximum(l2, 0) # Perform numeric optimization to minimize variances of negative and positive # components (kappa). # TODO: Consider scenarios where optimization doesn't converge. updated[6] = minimize(func, params[6], args=(means[1], resp[1]), **args).x[0] updated[7] = minimize(func, params[7], args=(means[2], resp[2]), **args).x[0] # Avoid zero variances. # updated[6] = max(updated[6], eps) # updated[7] = max(updated[7], eps) # Loss (epsilon) # epsilon = sqrt((pi0_new - pi0)^2 + (pi1_new - pi1)^2 + (pi2_new - pi2)^2 + # (delta_new - delta)^2 + (l1_new - l1)^2 + (l2_new - l2)^2 + # (kappa1_new - kappa1)^2 + (kappa2_new - kappa2)^2) loss = np.linalg.norm(updated - params) params[:] = updated epoch += 1 return _estimate_bias_var(beta, var_hat, params) def _init_bias_params(beta): """Initialize parameters for iterative bias estimation. Parameters ---------- beta : ndarray of shape (n_features,) Estimated coefficients before correction. Returns ------- delta : float Initial global bias term. l1, l2 : float Initial means of negative and positive components, respectively. kappa1, kappa2 : float Initial variances of negative and positive components, respectively. """ edges = np.quantile(beta, (0.125, 0.25, 0.75, 0.875)) # Estimate delta (mean of values between q1 and q3) if np.any(mask := (beta >= edges[1]) & (beta <= edges[2])): delta = np.mean(beta[mask]) else: delta = np.mean(beta) # Estimate l1 if np.any(mask := beta < edges[0]): l1 = np.mean(beta_ := beta[mask]) if beta_.size > 1: kappa1 = np.var(beta_, ddof=1, mean=l1) or 1.0 else: kappa1 = 1.0 else: l1 = np.min(beta) kappa1 = 1.0 # Estimate l2 if np.any(mask := beta > edges[3]): l2 = np.mean(beta_ := beta[mask]) if beta_.size > 1: kappa2 = np.var(beta_, ddof=1, mean=l2) or 1.0 else: kappa2 = 1.0 else: l2 = np.max(beta) kappa2 = 1.0 return delta, l1, l2, kappa1, kappa2 def _estimate_bias_var(beta, var_hat, params): """Estimate variance of sampling bias according to EM-optimized parameters. This function calculates the weighted least squares (WLS) estimator of bias. Parameters ---------- beta : ndarray of shape (n_features,) Estimated coefficients (log-fold change before correction). var_hat : ndarray of shape (n_features,) Estimated variances of regression coefficients. params : ndarray of shape (8,) Model parameters optimized by EM. Returns ------- delta_em : float EM estimator of bias. delta_wls : float WLS estimator of bias. var_delta : float Estimated variance of bias. """ pi0, pi1, pi2, delta, l1, l2, kappa1, kappa2 = params # The EM estimator of bias delta_em = delta # Assign features to Gaussian components (C) q1, q2 = np.quantile(beta, (pi1, 1.0 - pi2)) C1 = np.flatnonzero(beta < q1) C2 = np.flatnonzero(beta >= q2) # Numerator of the WLS estimator nu_inv = var_hat.copy() nu_inv[C1] += kappa1 nu_inv[C2] += kappa2 nu_inv[:] = 1.0 / nu_inv wls_denom = np.sum(nu_inv) # Denominator of the WLS estimator beta_ = beta.copy() beta_[C1] -= l1 beta_[C2] -= l2 nu_inv *= beta_ wls_numer = np.sum(nu_inv) # Estimate the variance of bias wls_denom_inv = 1.0 / wls_denom delta_wls = wls_numer * wls_denom_inv var_delta = np.nan_to_num(wls_denom_inv) # TODO: var_delta will be used if conserve=True to account for the variance of # delta_hat return delta_em, delta_wls, var_delta def _sample_fractions(data, dmat, beta_hat): """Estimate sampling fractions. Parameters ---------- data : ndarray of shape (n_samples, n_features) Data table. Zero-handled. Log-transformed. dmat : ndarray of shape (n_samples, n_covariates) Design matrix. beta_hat : ndarray of shape (n_features, n_covariates) Corrected coefficients. Returns ------- theta_hat : ndarray of shape (n_samples,) Sampling fractions. """ return np.mean(data - dmat @ beta_hat.T, axis=1) def _calc_statistics(beta_hat, var_hat, method="holm"): """Calculate statistical significance while correcting for multiple testing. Parameters ---------- beta_hat : ndarray of shape (n_features, n_covariates) Estimated coefficients post correction. var_hat : ndarray of shape (n_features, n_covariates) Estimated variances. Returns ------- se_hat : ndarray of shape (n_features, n_covariates) Estimated standard errors. W : ndarray of shape (n_features, n_covariates) Test statistics. p : ndarray of shape (n_features, n_covariates) p-values. q : ndarray of shape (n_features, n_covariates) Adjusted p-values. """ se_hat = var_hat**0.5 W = beta_hat / se_hat pval = 2.0 * norm.sf(abs(W), loc=0, scale=1) func = _check_p_adjust(method) qval = np.apply_along_axis(func, 0, pval) return se_hat, W, pval, qval def struc_zero(table, metadata, grouping, neg_lb=False): r"""Identify features with structural zeros. .. versionadded:: 0.7.1 Structural zeros refer to features that are systematically absent from certain sample groups. Consequently, the observed feature frequencies are all zeros, or mostly zeros, due to variability in technical factors. This function tests whether the proportion of observed zeros is close to zero, which suggests the absence of a feature in a given sample group. Parameters ---------- table : table_like of shape (n_samples, n_features) A matrix containing count or proportional abundance data of the samples. See :ref:`supported formats `. metadata : pd.DataFrame or 2-D array_like Metadata of the samples. Rows correspond to samples and columns correspond to covariates (attributes). Must be a pandas DataFrame or convertible to a pandas DataFrame. grouping : str A metadata column name indicating the assignment of samples to groups. neg_lb : bool, optional Determine whether to use negative lower bound when calculating sample proportions. Default is False. Generally, it is recommended to set it as True when the sample size per group is relatively large. Returns ------- pd.DataFrame of bool of shape (n_features, n_groups) A table indicating whether each feature (row) is a structural zero in each group (column) (True: structural zero, False: not structural zero). Notes ----- The structural zero test was initially proposed and implemented in the ANCOM-II method [1]_. It was adopted to the ANCOM-BC method [2]_ as a recommended method to complement test results. See :func:`ancombc` for how to use this function along with the ANCOM-BC test. Nevertheless, this function is generally useful with or without explicit statistical tests of feature abundances. A feature found to be a structural zero in a group should be automatically considered as differentially (less) abundant compared with other groups in which this feature is not a structural zero. Meanwhile, this feature should be excluded from subsequent analyses that involves this group. If a feature is identified as a structural zero in all groups, this feature should be removed entirely from downstream analyses. Note that the structural zero test should be applied to the original table before adding a pseudocount (see :func:`multi_replace`), which will otherwise mask all zeros and invalidate this test. References ---------- .. [1] Kaul, A., Mandal, S., Davidov, O., & Peddada, S. D. (2017). Analysis of microbiome data in the presence of excess zeros. Frontiers in Microbiology, 8, 2114. .. [2] Lin, H. and Peddada, S.D., 2020. Analysis of compositions of microbiomes with bias correction. Nature Communications, 11(1), p.3514. Examples -------- >>> from skbio.stats.composition import struc_zero >>> import pandas as pd Generate a DataFrame with 10 samples and 6 features with 0's in specific groups: >>> table = pd.DataFrame([[ 7, 1, 0, 11, 3, 1], ... [ 1, 1, 0, 13, 13, 0], ... [11, 5, 0, 1, 4, 1], ... [ 2, 2, 0, 16, 4, 0], ... [ 0, 1, 0, 0, 6, 0], ... [14, 8, 7, 9, 0, 5], ... [ 0, 7, 4, 1, 0, 26], ... [ 8, 1, 4, 28, 0, 10], ... [ 2, 2, 2, 4, 0, 5], ... [ 6, 4, 10, 1, 0, 9]], ... index=[f's{i}' for i in range(10)], ... columns=[f'f{i}' for i in range(6)]) Then create a grouping vector. In this example, there is a treatment group and a placebo group. >>> metadata = pd.DataFrame( ... {'grouping': ['treatment'] * 5 + ['placebo'] * 5}, ... index=[f's{i}' for i in range(10)]) The ``struc_zero`` function will identify features with structural zeros. Features that are identified as structural zeros in given groups should not be used in further analyses such as ``ancombc`` and ``dirmult_ttest``. Setting ``neg_lb=True`` declares that the true prevalence of a feature in a group is not significantly different from zero. >>> result = struc_zero(table, metadata, grouping='grouping', neg_lb=True) >>> result placebo treatment f0 False False f1 False False f2 False True f3 False False f4 True False f5 False True """ # Validate feature table and metadata matrix, samples, features = _ingest_table(table) metadata = _check_metadata(metadata, matrix, samples) metadata = _type_cast_to_float(metadata) unique_groups, group_indices, group_counts = np.unique( metadata[grouping], return_inverse=True, return_counts=True ) # Create a boolean matrix to indicate whether the value in table is 0 or not tmp = np.nan_to_num(matrix) != 0 n_groups = len(unique_groups) n_features = tmp.shape[1] # Initialize group sum matrix group_sums = np.zeros((n_groups, n_features)) np.add.at(group_sums, group_indices, tmp.astype(int)) # Calculate sample sizes of the groups for each feature sample_size = group_counts[:, np.newaxis] # Calculate sample proportions of the groups for each feature p_hat = group_sums / sample_size # Calculate the lower bound of a 95% confidence interval for sample proportion if neg_lb: p_hat = p_hat - 1.96 * (p_hat * (1 - p_hat) / sample_size) ** 0.5 zero_idx = p_hat <= 0 # Output structural zero as a DataFrame return pd.DataFrame(zero_idx.T, index=features, columns=unique_groups) def _global_test(dmat, grouping, beta_hat, vcov_hat, alpha=0.05, p_adjust="holm"): """Perform ANCOM-BC global test. The global test is to determine features that are differentially abundant between at least 2 sample groups across 3 or more groups. Parameters ---------- dmat : ndarray of shape (n_samples, n_covariates) Design matrix. grouping : str The group variable of interests in metadata. beta_hat : ndarray of shape (n_features, n_covariates) Corrected coefficients. vcov_hat : ndarray of shape (n_features, n_covariates, n_covariates) Estimated covariance matrices. alpha : float, optional Significance level for the statistical tests. Must be in the range of (0, 1). Default is 0.05. p_adjust : str, optional Method to correct *p*-values for multiple comparisons. Options are Holm- Boniferroni ("holm" or "holm-bonferroni") (default), Benjamini- Hochberg ("bh", "fdr_bh" or "benjamini-hochberg"), or any method supported by statsmodels' :func:`~statsmodels.stats.multitest.multipletests` function. Case-insensitive. If None, no correction will be performed. Returns ------- W_global : ndarray of float of shape (n_features,) W-statistics of global test. pval : ndarray of float of shape (n_features,) p-values of global test. qval : ndarray of float of shape (n_features,) Adjusted p-values of global test. reject : ndarray of bool of shape (n_features,) If the variable is differentially abundant. """ # Slices of columns in the dmat that the terms in the grouping is mapped to s = dmat.design_info.term_name_slices[grouping] # Get the index of the terms in the grouping group_ind = np.array(range(*s.indices(s.stop))) # Subset beta_hat and vcov_hat by grouping indices beta_hat_sub = beta_hat[:, group_ind] vcov_hat_sub = vcov_hat[:, group_ind][:, :, group_ind] # Inverse the subset of vcov_hat vcov_hat_sub_inv = np.linalg.pinv(vcov_hat_sub) dof = group_ind.size A = np.identity(dof) # for each feature, calculate test statistics W by the following formula: # W = (A @ beta_hat_sub).T @ inv(A @ vcov_hat_sub @ A.T) @ (A @ beta_hat_sub) term = np.einsum("ik,jk->ji", A, beta_hat_sub) W_global = np.einsum("ni,nij,ni->n", term, vcov_hat_sub_inv, term) # Derive p-values from W statistics p_lower = chi2.cdf(W_global, dof) p_upper = chi2.sf(W_global, dof) pval = 2 * np.minimum(p_lower, p_upper) # Correct p-values func = _check_p_adjust(p_adjust) qval = np.apply_along_axis(func, 0, pval) reject = qval <= alpha return W_global, pval, qval, reject scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/_base.py000066400000000000000000001457701520735541300246240ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from sys import modules from warnings import warn from typing import Any, TYPE_CHECKING import numpy as np from skbio.util._decorator import ( aliased, register_aliases, params_aliased, array_api_doc, ) from skbio.util._array import ingest_array if TYPE_CHECKING: # pragma: no cover from types import ModuleType from skbio.util._typing import ArrayLike, StdArray def _check_composition( xp: ModuleType, mat: StdArray, axis: int = -1, nozero: bool = False, maxdim: int | None = None, allnum: bool = True, ): r"""Check if the input matrix contain valid compositions. Parameters ---------- xp : namespace The array API compatible namespace corresponding ``mat``. mat : array of shape (..., n_components, ...) A matrix of proportions. axis : int, optional Axis that represents each composition. Default is the last axis (-1). nozero : bool, optional If True, matrix cannot have zero values. maxdim : int, optional Maximum number of dimensions allowed. Default is None. allnum : bool, optional If True, matrix cannot have NaN values. Raises ------ TypeError If the matrix is not numeric. ValueError If the matrix contains nan or infinite values. ValueError If any values in the matrix are negative. ValueError If there are compositions that have all zeros. ValueError If the matrix has more than maximum number of dimensions. """ if not xp.isdtype(mat.dtype, "numeric"): raise TypeError("Input matrix must have a numeric data type.") if allnum: # Don't allow infinite or NaN values. if not xp.all(xp.isfinite(mat)): raise ValueError("Input matrix cannot have infinite or NaN values.") else: # Allow NaN, but not infinite. if xp.any(xp.isinf(mat)): raise ValueError("Input matrix cannot have infinite values.") if nozero: if xp.any(mat <= 0): raise ValueError("Input matrix cannot have negative or zero components.") else: if xp.any(mat < 0): raise ValueError("Input matrix cannot have negative components.") if xp.any(~xp.any(mat, axis=axis)): raise ValueError("Input matrix cannot have compositions with all zeros.") if maxdim is not None and mat.ndim > maxdim: raise ValueError(f"Input matrix can only have {maxdim} dimensions or less.") @array_api_doc( backends=["numpy", "cupy", "torch", "jax", "dask"], devices=["cpu", "gpu"], ) def closure(mat: ArrayLike, axis: int = -1, validate: bool = True) -> StdArray: r"""Perform closure to ensure that all components of each composition sum to 1. .. versionchanged:: 0.7.0 The function now works on any dimension in arrays of any number of dimensions. Parameters ---------- mat : array_like of shape (..., n_components, ...) A matrix of compositions. axis : int, optional Axis along which closure will be performed. That is, each vector along this axis is considered as a composition. Default is the last axis (-1). .. versionadded:: 0.7.0 validate : bool, default True Check if the compositions are legitimate. .. versionadded:: 0.7.0 Returns ------- ndarray of shape (..., n_components, ...) The matrix where all components of each composition sum to 1. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import closure >>> X = np.array([[2, 2, 6], [4, 4, 2]]) >>> closure(X) array([[ 0.2, 0.2, 0.6], [ 0.4, 0.4, 0.2]]) """ xp, mat = ingest_array(mat) if validate: _check_composition(xp, mat, axis) return _closure(xp, mat, axis) def _closure(xp: ModuleType, mat: StdArray, axis: int = -1) -> StdArray: """Perform closure.""" row_sums = _nansum(xp, mat, axis=axis, keepdims=True) return mat / row_sums def _nansum( xp: ModuleType, arr: StdArray, axis: int, keepdims: bool = False ) -> StdArray: """Sum array elements along axis, ignoring NaN values.""" # Create mask of non-NaN values nan_mask = xp.isnan(arr) # Replace NaN with 0 for summation arr_no_nan = xp.where(nan_mask, xp.asarray(0.0, dtype=arr.dtype), arr) return xp.sum(arr_no_nan, axis=axis, keepdims=keepdims) @aliased("multiplicative_replacement", "0.6.0", True) def multi_replace(mat, delta=None): r"""Replace all zeros with small non-zero values. It uses the multiplicative replacement strategy [1]_, replacing zeros with a small positive :math:`\delta` and ensuring that the compositions still add up to 1. Parameters ---------- mat : array_like of shape (n_compositions, n_components) A matrix of proportions. delta : float, optional A small number to be used to replace zeros. If not specified, the default value is :math:`\delta = \frac{1}{N^2}` where :math:`N` is the number of components. Returns ------- ndarray of shape (n_compositions, n_components) The matrix where all of the values are non-zero and each composition (row) adds up to 1. Raises ------ ValueError If negative proportions are created due to a large ``delta``. Notes ----- This method will result in negative proportions if a large delta is chosen. References ---------- .. [1] J. A. Martin-Fernandez. "Dealing With Zeros and Missing Values in Compositional Data Sets Using Nonparametric Imputation" Examples -------- >>> import numpy as np >>> from skbio.stats.composition import multi_replace >>> X = np.array([[.2, .4, .4, 0], [0, .5, .5, 0]]) >>> multi_replace(X) array([[ 0.1875, 0.375 , 0.375 , 0.0625], [ 0.0625, 0.4375, 0.4375, 0.0625]]) """ mat = closure(mat) z_mat = mat == 0 num_feats = mat.shape[-1] tot = z_mat.sum(axis=-1, keepdims=True) if delta is None: delta = (1.0 / num_feats) ** 2 zcnts = 1 - tot * delta if (zcnts < 0).any(): raise ValueError( "Multiplicative replacement created negative proportions. Consider " "using a smaller `delta`." ) mat = np.where(z_mat, delta, zcnts * mat) return mat.squeeze() def _closure_two(x, y, validate): xp, x, y = ingest_array(x, y) if validate: _check_composition(xp, x) _check_composition(xp, y) return xp, _closure(xp, x), _closure(xp, y) def perturb(x: ArrayLike, y: ArrayLike, validate: bool = True) -> StdArray: r"""Perform the perturbation operation. This operation is defined as: .. math:: x \oplus y = C[x_1 y_1, \ldots, x_D y_D] :math:`C[x]` is the closure operation defined as: .. math:: C[x] = \left[\frac{x_1}{\sum_{i=1}^{D} x_i},\ldots, \frac{x_D}{\sum_{i=1}^{D} x_i} \right] for some :math:`D` dimensional real vector :math:`x` and :math:`D` is the number of components for every composition. Parameters ---------- x : array_like of shape (n_compositions, n_components) A matrix of proportions. y : array_like of shape (n_compositions, n_components) A matrix of proportions. validate : bool, default True Check if the compositions are legitimate. .. versionadded:: 0.7.0 Returns ------- ndarray of shape (n_compositions, n_components) A matrix of proportions where all of the values are non-zero and each composition (row) adds up to 1. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import perturb Consider a very simple environment with only three species. The species in the environment are evenly distributed and their proportions are equal: >>> before = np.array([1/3, 1/3, 1/3]) Suppose that an antibiotic kills off half of the population for the first two species, but doesn't harm the third species. Then the perturbation vector would be as follows: >>> after = np.array([1/2, 1/2, 1]) And the resulting perturbation would be: >>> perturb(before, after) array([ 0.25, 0.25, 0.5 ]) """ xp, cx, cy = _closure_two(x, y, validate) return _closure(xp, cx * cy) def perturb_inv(x: ArrayLike, y: ArrayLike, validate: bool = True) -> StdArray: r"""Perform the inverse perturbation operation. This operation is defined as: .. math:: x \ominus y = C[x_1 y_1^{-1}, \ldots, x_D y_D^{-1}] :math:`C[x]` is the closure operation defined as: .. math:: C[x] = \left[\frac{x_1}{\sum_{i=1}^{D} x_i},\ldots, \frac{x_D}{\sum_{i=1}^{D} x_i} \right] for some :math:`D` dimensional real vector :math:`x` and :math:`D` is the number of components for every composition. Parameters ---------- x : array_like of shape (n_compositions, n_components) A matrix of proportions. y : array_like of shape (n_compositions, n_components) A matrix of proportions. validate : bool, default True Check if the compositions are legitimate. .. versionadded:: 0.7.0 Returns ------- ndarray of shape (n_compositions, n_components) A matrix of proportions where all of the values are non-zero and each composition (row) adds up to 1. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import perturb_inv >>> x = np.array([.1, .3, .4, .2]) >>> y = np.array([1/6, 1/6, 1/3, 1/3]) >>> perturb_inv(x, y) array([ 0.14285714, 0.42857143, 0.28571429, 0.14285714]) """ xp, cx, cy = _closure_two(x, y, validate) return _closure(xp, cx / cy) def power(x: ArrayLike, a: float, validate: bool = True) -> StdArray: r"""Perform the power operation. This operation is defined as follows: .. math:: `x \odot a = C[x_1^a, \ldots, x_D^a] :math:`C[x]` is the closure operation defined as: .. math:: C[x] = \left[\frac{x_1}{\sum_{i=1}^{D} x_i},\ldots, \frac{x_D}{\sum_{i=1}^{D} x_i} \right] for some :math:`D` dimensional real vector :math:`x` and :math:`D` is the number of components for every composition. Parameters ---------- x : array_like of shape (n_compositions, n_components) A matrix of proportions. a : float A scalar exponent. validate : bool, default True Check if the compositions are legitimate. .. versionadded:: 0.7.0 Returns ------- ndarray of shape (n_compositions, n_components) The matrix where all of the values are non-zero and each composition (row) adds up to 1. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import power >>> x = np.array([.1, .3, .4, .2]) >>> power(x, .1) array([ 0.23059566, 0.25737316, 0.26488486, 0.24714631]) """ xp, x = ingest_array(x) if validate: _check_composition(xp, x) cx = _closure(xp, x) return _closure(xp, cx**a).squeeze() def inner(x: ArrayLike, y: ArrayLike, validate: bool = True) -> StdArray: r"""Calculate the Aitchson inner product. This inner product is defined as follows: .. math:: \langle x, y \rangle_a = \frac{1}{2D} \sum\limits_{i=1}^{D} \sum\limits_{j=1}^{D} \ln\left(\frac{x_i}{x_j}\right) \ln\left(\frac{y_i}{y_j}\right) Parameters ---------- x : array_like of shape (n_compositions, n_components) A matrix of proportions. y : array_like of shape (n_compositions, n_components) A matrix of proportions. validate : bool, default True Check if the compositions are legitimate. .. versionadded:: 0.7.0 Returns ------- ndarray or scalar of shape (n_compositions, n_compositions) Inner product result. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import inner >>> x = np.array([.1, .3, .4, .2]) >>> y = np.array([.2, .4, .2, .2]) >>> inner(x, y) # doctest: +ELLIPSIS 0.2107852473... """ xp, cx, cy = _closure_two(x, y, validate) clrx, clry = _clr(xp, cx, axis=-1), _clr(xp, cy, axis=-1) return xp.matmul(clrx, clry.T) @array_api_doc( backends=["numpy", "cupy", "torch", "jax", "dask"], devices=["cpu", "gpu"], ) def clr(mat: ArrayLike, axis: int = -1, validate: bool = True) -> StdArray: r"""Perform centre log ratio (CLR) transformation. This function transforms compositions from Aitchison geometry to the real space. The :math:`clr` transform is both an isometry and an isomorphism defined on the following spaces: .. math:: clr: S^D \rightarrow U where :math:`U= \{x :\sum\limits_{i=1}^D x = 0 \; \forall x \in \mathbb{R}^D\}` It is defined for a composition :math:`x` as follows: .. math:: clr(x) = \ln\left[\frac{x_1}{g_m(x)}, \ldots, \frac{x_D}{g_m(x)}\right] where :math:`g_m(x) = (\prod\limits_{i=1}^{D} x_i)^{1/D}` is the geometric mean of :math:`x`. .. versionchanged:: 0.7.0 The function now works on any dimension in arrays of any number of dimensions. Parameters ---------- mat : array_like of shape (..., n_components, ...) A matrix of positive proportions. axis : int, optional Axis along which CLR transformation will be performed. Each vector on this axis is considered as a composition. Default is the last axis (-1). .. versionadded:: 0.7.0 validate : bool, default True Check if the matrix consists of strictly positive values. .. versionadded:: 0.7.0 Returns ------- ndarray of shape (..., n_components, ...) CLR-transformed matrix. See Also -------- clr_inv Examples -------- >>> import numpy as np >>> from skbio.stats.composition import clr >>> x = np.array([.1, .3, .4, .2]) >>> clr(x) array([-0.79451346, 0.30409883, 0.5917809 , -0.10136628]) """ xp, mat = ingest_array(mat) if validate: _check_composition(xp, mat, nozero=True) return _clr(xp, mat, axis) def _clr(xp: ModuleType, mat: StdArray, axis: int) -> StdArray: """Perform CLR transform.""" return (lmat := xp.log(mat)) - xp.mean(lmat, axis=axis, keepdims=True) @array_api_doc( backends=["numpy", "cupy", "torch", "jax", "dask"], devices=["cpu", "gpu"], ) def clr_inv(mat: ArrayLike, axis: int = -1, validate: bool = True) -> StdArray: r"""Perform inverse centre log ratio (CLR) transformation. This function transforms compositions from the real space to Aitchison geometry. The :math:`clr^{-1}` transform is both an isometry, and an isomorphism defined on the following spaces: .. math:: clr^{-1}: U \rightarrow S^D where :math:`U= \{x :\sum\limits_{i=1}^D x = 0 \; \forall x \in \mathbb{R}^D\}` This transformation is defined as follows: .. math:: clr^{-1}(x) = C[\exp( x_1, \ldots, x_D)] .. versionchanged:: 0.7.0 The function now works on any dimension in arrays of any number of dimensions. Parameters ---------- mat : array_like of shape (..., n_components, ...) A matrix of CLR-transformed data. axis : int, optional Axis along which inverse CLR transformation will be performed. Each vector on this axis is considered as a CLR-transformed composition. Default is the last axis (-1). .. versionadded:: 0.7.0 validate: bool, optional Check if the matrix has been centered at 0. Violation will result in a warning rather than an error, for backward compatibility. Defaults to True. .. versionadded:: 0.7.0 Returns ------- ndarray of shape (..., n_components, ...) Inverse CLR-transformed matrix. See Also -------- clr Notes ----- The output of ``clr_inv`` is guaranteed to have each composition sum to 1. But this property isn't required for the input for ``clr``. Therefore, ``clr_inv`` does not completely invert ``clr``. Instead, ``clr_inv(clr(mat))`` and ``closure(mat)`` are equal. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import clr_inv >>> x = np.array([.1, .3, .4, .2]) >>> clr_inv(x) array([ 0.21383822, 0.26118259, 0.28865141, 0.23632778]) """ xp, mat = ingest_array(mat) # `1e-8` is taken from `np.allclose`. It's not guaranteed that `xp` has `allclose`, # therefore it is manually written here. if validate and xp.any(xp.abs(xp.sum(mat, axis=axis)) > 1e-08): warn( "The input matrix is not in the CLR range, which requires the sum of " "values per composition equals to 0.", UserWarning, ) return _clr_inv(xp, mat, axis) def _clr_inv(xp: ModuleType, mat: StdArray, axis: int) -> StdArray: """Perform inverse CLR transform.""" # for numerical stability, shift the values < 1 diff = xp.exp(mat - xp.max(mat, axis=axis, keepdims=True)) return _closure(xp, diff, axis) @array_api_doc( backends=["numpy", "cupy", "torch", "jax", "dask"], devices=["cpu", "gpu"], ) def rclr(mat: ArrayLike, axis: int = -1, validate: bool = True) -> StdArray: r"""Perform robust centre log ratio (rclr) transformation. The robust CLR transformation is similar to the standard CLR transformation, but it only operates on observed (non-zero) values [1]_. This makes it suitable for sparse compositional data. For each composition, the transformation computes: .. math:: rclr(x_i) = \ln(x_i) - \frac{1}{|S|} \sum_{j \in S} \ln(x_j) where :math:`S` is the set of indices with non-zero values, and :math:`|S|` is the number of non-zero values. Parameters ---------- mat : array_like of shape (..., n_components, ...) A matrix of non-negative values. Zeros are allowed and will become NaN in the output. NaN values in the input are preserved (representing missing entries). axis : int, optional Axis along which rclr transformation will be performed. Each vector on this axis is considered as a composition. Default is the last axis (-1). validate : bool, default True Check if the matrix consists of non-negative, finite values. NaN values are allowed as missing entries. Returns ------- ndarray of shape (..., n_components, ...) rclr-transformed matrix. Zero values in the input become NaN. See Also -------- clr Notes ----- The rclr transformation has several advantages for sparse compositional data: 1. It does not require pseudocount addition, which can bias results 2. It preserves the zero/non-zero structure of the data 3. It allows for matrix completion methods to be applied The geometric mean is computed only over non-zero values in each composition, making it "robust" to the presence of zeros. References ---------- .. [1] Martino, C., Morton, J. T., Marotz, C. A., Thompson, L. R., Tripathi, A., Knight, R., & Zengler, K. (2019). A novel sparse compositional technique reveals microbial perturbations. MSystems, 4(1), 10-1128. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import rclr >>> x = np.array([[1, 2, 0, 4], ... [0, 3, 3, 0], ... [2, 2, 2, 2]]) >>> result = rclr(x) >>> np.round(result, 3) array([[-0.693, 0. , nan, 0.693], [ nan, 0. , 0. , nan], [ 0. , 0. , 0. , 0. ]]) """ xp, mat = ingest_array(mat) if validate: _check_composition(xp, mat, allnum=False) return _rclr(xp, mat, axis) def _rclr(xp: ModuleType, mat: StdArray, axis: int) -> StdArray: """Perform rclr transform.""" # Track which values were observed in the original input observed_mask = (mat != 0) & ~xp.isnan(mat) # Take log (will give -inf for zeros, NaN for NaN) log_safe = xp.where(observed_mask, xp.log(mat), 0.0) # Count observed values from mask n_observed = xp.sum(observed_mask, axis=axis, keepdims=True) # Sum logs for observed values only log_sum = xp.sum(log_safe, axis=axis, keepdims=True) # Geometric mean geo_mean_log = log_sum / n_observed # Center by geometric mean result = log_safe - geo_mean_log # Replace non-observed with NaN result = xp.where(observed_mask, result, xp.nan) return result @params_aliased([("validate", "check", "0.7.0", True)]) @array_api_doc( backends=["numpy", "cupy", "torch", "jax", "dask"], devices=["cpu", "gpu"], ) def ilr( mat: ArrayLike, basis: ArrayLike | None = None, axis: int = -1, validate: bool = True, ) -> StdArray: r"""Perform isometric log ratio (ILR) transformation. This function transforms compositions from Aitchison simplex to the real space. The :math:`ilr` transform is both an isometry, and an isomorphism defined on the following spaces: .. math:: ilr: S^D \rightarrow \mathbb{R}^{D-1} The ilr transformation is defined as follows: .. math:: ilr(x) = [\langle x, e_1 \rangle_a, \ldots, \langle x, e_{D-1} \rangle_a] where :math:`[e_1,\ldots,e_{D-1}]` is an orthonormal basis in the simplex. If an orthornormal basis isn't specified, the J. J. Egozcue orthonormal basis derived from Gram-Schmidt orthogonalization [1]_ will be used by default. .. versionchanged:: 0.7.0 The function now works on any dimension in arrays of any number of dimensions. Parameters ---------- mat : array_like of shape (..., n_components, ...) A matrix of positive proportions. basis : ndarray or sparse matrix, optional Orthonormal basis for Aitchison simplex. Defaults to J. J. Egozcue orthonormal basis. axis : int, optional Axis along which ILR transformation will be performed. That is, each vector along this axis is considered as a composition. Default is the last axis (-1). .. versionadded:: 0.7.0 validate : bool, default True Check if i) the matrix is compositional, ii) the basis is orthonormal, 2-dimensional, and the dimensions are matched. Returns ------- ndarray of shape (..., n_components - 1,...) ILR-transformed matrix. See Also -------- ilr_inv Notes ----- If the ``basis`` parameter is specified, it is expected to be a basis in the Aitchison simplex. If there are :math:`D - 1` elements specified in ``mat``, then the dimensions of the basis needs be :math:`(D-1) \times D`, where rows represent basis vectors, and the columns represent proportions. References ---------- .. [1] Egozcue, J. J., Pawlowsky-Glahn, V., Mateu-Figueras, G., & Barcelo-Vidal, C. (2003). Isometric logratio transformations for compositional data analysis. Mathematical geology, 35(3), 279-300. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import ilr >>> x = np.array([.1, .3, .4, .2]) >>> ilr(x) array([-0.7768362 , -0.68339802, 0.11704769]) """ xp, mat = ingest_array(mat) if validate: _check_composition(xp, mat, nozero=True) N = mat.shape[axis] if basis is None: # NOTE: acc.device(mat) would be nicer basis = xp.asarray( _gram_schmidt_basis(N), device=mat.device, dtype=xp.float64 ) # dimension (N-1) x N else: xp_, basis = ingest_array(basis) if validate: # the following maybe redundant if basis.ndim != 2: raise ValueError( f"Basis needs to be a 2-D matrix, not a {basis.ndim}-D matrix." ) _check_basis(xp_, basis, orthonormal=True, subspace_dim=N - 1) basis = xp.asarray(basis, device=mat.device, dtype=xp.float64) axis %= mat.ndim return _ilr(xp, mat, basis, axis) def _swap_axis(ndim, axis): """Create a list of axis indices with one axis swapped with the last axis.""" res = list(range(ndim)) res[axis] = ndim - 1 res[ndim - 1] = axis return res def _ilr(xp: ModuleType, mat: StdArray, basis: StdArray, axis: int) -> StdArray: """Perform ILR transform.""" mat = _clr(xp, mat, axis) # tensordot return's shape consists of the non-contracted axes (dimensions) of # the first array x1, followed by the non-contracted axes (dimensions) of the # second array x2 prod = xp.tensordot(mat, basis, axes=([axis], [1])) return xp.permute_dims(prod, axes=_swap_axis(mat.ndim, axis)) @params_aliased([("validate", "check", "0.7.0", True)]) @array_api_doc( backends=["numpy", "cupy", "torch", "jax", "dask"], devices=["cpu", "gpu"], ) def ilr_inv( mat: ArrayLike, basis: ArrayLike | None = None, axis: int = -1, validate: bool = True, ) -> StdArray: r"""Perform inverse isometric log ratio (ILR) transformation. This function transforms compositions from the real space to Aitchison geometry. The :math:`ilr^{-1}` transform is both an isometry, and an isomorphism defined on the following spaces: .. math:: ilr^{-1}: \mathbb{R}^{D-1} \rightarrow S^D The inverse ilr transformation is defined as follows: .. math:: ilr^{-1}(x) = \bigoplus\limits_{i=1}^{D-1} x \odot e_i where :math:`[e_1,\ldots, e_{D-1}]` is an orthonormal basis in the simplex. If an orthonormal basis isn't specified, the J. J. Egozcue orthonormal basis derived from Gram-Schmidt orthogonalization [1]_ will be used by default. .. versionchanged:: 0.7.0 The function now works on any dimension in arrays of any number of dimensions. Parameters ---------- mat : array_like of shape (..., n_components - 1, ...) A matrix of ILR-transformed data. basis : ndarray or sparse matrix, optional Orthonormal basis for Aitchison simplex. Defaults to J. J. Egozcue orthonormal basis. axis : int, optional Axis along which ILR transformation will be performed. That is, each vector along this axis is considered as a ILR transformed composition data. Default is the last axis (-1). .. versionadded:: 0.7.0 validate : bool, default True Check to see if basis is orthonormal and dimension matches. Returns ------- ndarray of shape (..., n_components, ...) Inverse ILR-transformed matrix. See Also -------- ilr Notes ----- If the ``basis`` parameter is specified, it is expected to be a basis in the Aitchison simplex. If there are :math:`D - 1` elements specified in ``mat``, then the dimensions of the basis needs be :math:`(D-1) \times D`, where rows represent basis vectors, and the columns represent proportions. References ---------- .. [1] Egozcue, J. J., Pawlowsky-Glahn, V., Mateu-Figueras, G., & Barcelo-Vidal, C. (2003). Isometric logratio transformations for compositional data analysis. Mathematical geology, 35(3), 279-300. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import ilr >>> x = np.array([.1, .3, .6,]) >>> ilr_inv(x) array([ 0.34180297, 0.29672718, 0.22054469, 0.14092516]) """ xp, mat = ingest_array(mat) N = mat.shape[axis] + 1 if basis is None: basis = xp.asarray( _gram_schmidt_basis(N), device=mat.device, dtype=xp.float64 ) # dimension (N-1) x N elif validate: xp_, basis = ingest_array(basis) # the following maybe redundant as the orthonrmal implicitly check 2-d if basis.ndim != 2: raise ValueError( f"Basis needs to be a 2-D matrix, not a {basis.ndim}-D matrix." ) _check_basis(xp_, basis, orthonormal=True, subspace_dim=N - 1) basis = xp.asarray(basis, device=mat.device, dtype=xp.float64) axis %= mat.ndim return _ilr_inv(xp, mat, basis, axis) def _ilr_inv(xp: ModuleType, mat: StdArray, basis: StdArray, axis: int) -> StdArray: """Perform ILR transform.""" prod = xp.tensordot(mat, basis, axes=([axis], [0])) perm = xp.permute_dims(prod, axes=_swap_axis(mat.ndim, axis)) return _clr_inv(xp, perm, axis) @params_aliased([("ref_idx", "denominator_idx", "0.7.0", False)]) @array_api_doc( backends=["numpy", "cupy", "torch", "jax", "dask"], devices=["cpu", "gpu"], ) def alr( mat: ArrayLike, ref_idx: int = 0, axis: int = -1, validate: bool = True ) -> StdArray: r"""Perform additive log ratio (ALR) transformation. This function transforms compositions from a D-part Aitchison simplex to a non-isometric real space of D-1 dimensions. The argument ``ref_idx`` defines the index of the column used as the reference (a common denominator). The :math:`alr` transformed data are amenable to multivariate analysis as long as statistics don't involve distances. .. math:: alr: S^D \rightarrow \mathbb{R}^{D-1} The alr transformation is defined as follows .. math:: alr(x) = \left[ \ln \frac{x_1}{x_D}, \ldots, \ln \frac{x_{D-1}}{x_D} \right] where :math:`D` is the index of the part used as the reference. .. versionchanged:: 0.7.0 The function now works on any dimension in arrays of any number of dimensions. Parameters ---------- mat : array_like of shape (..., n_components, ...) A matrix of proportions. ref_idx : int, optional Index on the target axis which should be used as the reference composition (denominator). Default is 0 (the first position). axis : int, optional Axis along which ALR transformation will be performed. Each vector along this axis is considered as a composition. Default is the last axis (-1). .. versionadded:: 0.7.0 validate: bool, default True Check whether the input is positive, whether the mat is 2D. .. versionadded:: 0.7.0 Returns ------- ndarray of shape (..., n_components - 1, ...) ALR-transformed data projected in a non-isometric real space of :math:`D - 1` dimensions for a *D*-parts composition. See Also -------- alr_inv Examples -------- >>> import numpy as np >>> from skbio.stats.composition import alr >>> x = np.array([.1, .3, .4, .2]) >>> alr(x) array([ 1.09861229, 1.38629436, 0.69314718]) """ xp, mat = ingest_array(mat) if validate: _check_composition(xp, mat, nozero=True) # validate and normalize axis and index N = mat.shape[axis] if N < 2: raise ValueError(f"Dimension {axis} of the input matrix is singleton.") axis %= mat.ndim if ref_idx < -N or ref_idx >= N: raise IndexError(f"Invalid index {ref_idx} on dimension {axis}.") ref_idx %= N return _alr(xp, mat, ref_idx, axis) def _alr(xp: ModuleType, mat: StdArray, ref_idx: int, axis: int) -> StdArray: # Given that: log(numerator / denominator) = log(numerator) - log(denominator) # The following code will perform logarithm on the entire matrix, then subtract # denominator from numerator. This is also for numerical stability. lmat = xp.log(mat) # The following code can be replaced with a single NumPy function call: # numerator_matrix = xp.delete(lmat, ref_idx, axis=axis) # However, `delete` is not in the Python array API standard. For compatibility with # libraries that don't have `delete`, an arbitrary dimension slicing method is # is provided below. before: Any = [slice(None)] * mat.ndim before[axis] = slice(None, ref_idx) before = tuple(before) after: Any = [slice(None)] * mat.ndim after[axis] = slice(ref_idx + 1, None) after = tuple(after) numerator_matrix = xp.concat((lmat[before], lmat[after]), axis=axis) # The following code can be replaced with a single NumPy function call: # denominator_vector = xp.take(lmat, xp.asarray([ref_idx]), axis=axis) # `take` is in the Python array API standard. The following code is to keep the # style consistent with the code above. column: Any = [slice(None)] * mat.ndim column[axis] = slice(ref_idx, ref_idx + 1) column = tuple(column) denominator_vector = lmat[column] return numerator_matrix - denominator_vector @params_aliased([("ref_idx", "denominator_idx", "0.7.0", False)]) @array_api_doc( backends=["numpy", "cupy", "torch", "jax", "dask"], devices=["cpu", "gpu"], ) def alr_inv(mat: ArrayLike, ref_idx: int = 0, axis: int = -1) -> StdArray: r"""Perform inverse additive log ratio (ALR) transform. This function transforms compositions from the non-isometric real space of ALRs to Aitchison geometry. .. math:: alr^{-1}: \mathbb{R}^{D-1} \rightarrow S^D The inverse ALR transformation is defined as follows: .. math:: alr^{-1}(x) = C[exp([y_1, y_2, ..., y_{D-1}, 0])] where :math:`C[x]` is the closure operation defined as .. math:: C[x] = \left[\frac{x_1}{\sum_{i=1}^{D} x_i},\ldots, \frac{x_D}{\sum_{i=1}^{D} x_i} \right] for some :math:`D` dimensional real vector :math:`x` and :math:`D` is the number of components for every composition. .. versionchanged:: 0.7.0 The function now works on any dimension in arrays of any number of dimensions. Parameters ---------- mat : array_like of shape (..., n_components - 1, ...) A matrix of ALR-transformed data. ref_idx : int, optional Index on the target axis where the reference composition (denominator) will be inserted. Default is 0 (the first position). axis : int, optional Axis along which inverse ALR transformation will be performed. Each vector on this axis is considered as a CLR-transformed composition. Default is the last axis (-1). .. versionadded:: 0.7.0 Returns ------- ndarray of shape (..., n_components, ...) Inverse ALR-transformed matrix or vector where rows sum to 1. See Also -------- alr Notes ----- The output of ``alr_inv`` is guaranteed to have each composition sum to 1. But this property isn't required for the input for ``alr``. Therefore, ``alr_inv`` does not completely invert ``alr``. Instead, ``alr_inv(clr(mat))`` and ``closure(mat)`` are equal. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import alr, alr_inv >>> x = np.array([.1, .3, .4, .2]) >>> alr_inv(alr(x)) array([ 0.1, 0.3, 0.4, 0.2]) """ xp, mat = ingest_array(mat) # validate and normalize axis and index N = mat.shape[axis] + 1 if N < 2: raise ValueError(f"Dimension {axis} of the input matrix has zero length.") axis %= mat.ndim if ref_idx < -N or ref_idx >= N: raise IndexError(f"Invalid index {ref_idx} on dimension {axis}.") ref_idx %= N return _alr_inv(xp, mat, ref_idx, axis) def _alr_inv(xp: ModuleType, mat: StdArray, ref_idx: int, axis: int) -> StdArray: # The following code can be replaced with a single NumPy function call. # comp = xp.insert(emat, ref_idx, 1.0, axis=axis) # However, `insert` is not in the Python array API standard. For compatibility with # libraries that don't have `insert`, an arbitrary dimension slicing method is # is provided below. before: Any = [slice(None)] * mat.ndim before[axis] = slice(None, ref_idx) before = tuple(before) after: Any = [slice(None)] * mat.ndim after[axis] = slice(ref_idx, None) after = tuple(after) shape: Any = list(mat.shape) shape[axis] = 1 shape = tuple(shape) zeros = xp.zeros(shape, dtype=mat.dtype, device=mat.device) comp = xp.concat((mat[before], zeros, mat[after]), axis=axis) comp = xp.exp(comp - xp.max(comp, axis=axis, keepdims=True)) return _closure(xp, comp, axis) def centralize(mat: ArrayLike) -> StdArray: r"""Center data around its geometric average. Parameters ---------- mat : array_like of shape (n_compositions, n_components) A matrix of proportions. Returns ------- ndarray of shape (n_compositions, n_components) Centered composition matrix. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import centralize >>> X = np.array([[.1, .3, .4, .2], [.2, .2, .2, .4]]) >>> centralize(X) array([[ 0.17445763, 0.30216948, 0.34891526, 0.17445763], [ 0.32495488, 0.18761279, 0.16247744, 0.32495488]]) """ from scipy.stats import gmean mat = closure(mat) cen = gmean(mat, axis=0) return perturb_inv(mat, cen) def _vlr(x, y, ddof): r"""Calculate variance log ratio. Parameters ---------- x : array_like of shape (n_components,) A vector of proportions. y : array_like of shape (n_components,) A vector of proportions. ddof : int Degrees of freedom. Returns ------- float Variance log ratio value. """ # Log transformation x = np.log(x) y = np.log(y) # Variance log ratio return np.var(x - y, ddof=ddof) def _robust_vlr(x, y, ddof): r"""Calculate variance log ratio while masking zeros. Parameters ---------- x : array_like of shape (n_components,) A vector of proportions. y : array_like of shape (n_components,) A vector of proportions. ddof : int Degrees of freedom. Returns ------- float Variance log ratio value. """ # Mask zeros x = np.ma.masked_array(x, mask=x == 0) y = np.ma.masked_array(y, mask=y == 0) # Log transformation x = np.ma.log(x) y = np.ma.log(y) # Variance log ratio return np.ma.var(x - y, ddof=ddof) def vlr(x, y, ddof=1, robust=False): r"""Calculate variance log ratio. Parameters ---------- x : array_like of shape (n_components,) A vector of proportions. y : array_like of shape (n_components,) A vector of proportions. ddof : int Degrees of freedom. robust : bool Whether to mask zeros at the cost of performance. Returns ------- float Variance log ratio value. Notes ----- Variance log ratio was described in [1]_ and [2]_. References ---------- .. [1] V. Lovell D, Pawlowsky-Glahn V, Egozcue JJ, Marguerat S, Bähler J (2015) Proportionality: A Valid Alternative to Correlation for Relative Data. PLoS Comput Biol 11(3): e1004075. https://doi.org/10.1371/journal.pcbi.1004075 .. [2] Erb, I., Notredame, C. How should we measure proportionality on relative gene expression data?. Theory Biosci. 135, 21-36 (2016). https://doi.org/10.1007/s12064-015-0220-8 Examples -------- >>> import numpy as np >>> from skbio.stats.composition import vlr >>> x = np.exp([1, 2, 3]) >>> y = np.exp([2, 3, 4]) >>> vlr(x, y) # no zeros 0.0 """ # Convert array_like to numpy array x = closure(x) y = closure(y) # Set up input and parameters kwargs = { "x": x, "y": y, "ddof": ddof, } # Run backend function if robust: return _robust_vlr(**kwargs) else: return _vlr(**kwargs) def _pairwise_vlr(mat, ddof): r"""Perform pairwise variance log ratio transformation. Parameters ---------- mat : array_like of shape (n_compositions, n_components) A matrix of proportions. ddof : int Degrees of freedom. Returns ------- ndarray of shape (n_compositions, n_compositions) Distance matrix of variance log ratio values. """ # Log Transform X_log = np.log(mat) # Variance Log Ratio covariance = np.cov(X_log.T, ddof=ddof) diagonal = np.diagonal(covariance) vlr_data = -2 * covariance + diagonal[:, np.newaxis] + diagonal return vlr_data def pairwise_vlr(mat, ids=None, ddof=1, robust=False, validate=True): r"""Perform pairwise variance log ratio transformation. Parameters ---------- mat : array_like of shape (n_compositions, n_components) A matrix of proportions. ids : array_like of str of shape (n_components,) Component names. ddof : int Degrees of freedom. robust : bool Whether to mask zeros at the cost of performance. validate : bool Whether to validate the distance matrix after construction. Returns ------- skbio.DistanceMatrix if validate=True Distance matrix of variance log ratio values. skbio.DissimilarityMatrix if validate=False Dissimilarity matrix of variance log ratio values. Notes ----- Pairwise variance log ratio transformation was described in [1]_ and [2]_. References ---------- .. [1] V. Lovell D, Pawlowsky-Glahn V, Egozcue JJ, Marguerat S, Bähler J (2015) Proportionality: A Valid Alternative to Correlation for Relative Data. PLoS Comput Biol 11(3): e1004075. https://doi.org/10.1371/journal.pcbi.1004075 .. [2] Erb, I., Notredame, C. How should we measure proportionality on relative gene expression data?. Theory Biosci. 135, 21-36 (2016). https://doi.org/10.1007/s12064-015-0220-8 Examples -------- >>> import numpy as np >>> from skbio.stats.composition import pairwise_vlr >>> mat = np.array([np.exp([1, 2, 2]), ... np.exp([2, 3, 6]), ... np.exp([2, 3, 12])]).T >>> dism = pairwise_vlr(mat) >>> dism.redundant_form() array([[ 0., 3., 27.], [ 3., 0., 12.], [ 27., 12., 0.]]) """ from skbio.stats.distance import DistanceMatrix # Mask zeros mat = closure(mat.astype(np.float64)) # Set up input and parameters kwargs = { "mat": mat, "ddof": ddof, } # Variance log ratio if robust: raise NotImplementedError("Pairwise version of robust VLR is not implemented.") else: vlr_data = _pairwise_vlr(**kwargs) # Return distance matrix if validate: vlr_data = 0.5 * (vlr_data + vlr_data.T) return DistanceMatrix(vlr_data, ids=ids) # Return dissimilarity matrix else: return DistanceMatrix(vlr_data, ids=ids, validate=False) def tree_basis(tree): r"""Calculate the sparse representation of an ilr basis from a tree. This computes an orthonormal basis specified from a bifurcating tree. Parameters ---------- tree : skbio.TreeNode Input bifurcating tree. Must be strictly bifurcating (i.e. every internal node needs to have exactly two children). This is used to specify the ilr basis. Returns ------- scipy.sparse.coo_array The ilr basis required to perform the ilr_inv transform. This is also known as the sequential binary partition. Note that this matrix is represented in clr coordinates. list of str List of tree node names indicating the ordering in the basis. Raises ------ ValueError If the tree doesn't contain two branches. Examples -------- >>> from skbio import TreeNode >>> tree = u"((b,c)a, d)root;" >>> t = TreeNode.read([tree]) >>> basis, nodes = tree_basis(t) >>> basis.toarray() array([[-0.40824829, -0.40824829, 0.81649658], [-0.70710678, 0.70710678, 0. ]]) """ from scipy.sparse import coo_array # Specifies which child is numerator and denominator # within any given node in a tree. NUMERATOR = 1 DENOMINATOR = 0 # this is inspired by @wasade in # https://github.com/biocore/gneiss/pull/8 t = tree.copy() D = len(list(tree.tips())) # calculate number of tips under each node for n in t.postorder(include_self=True): if n.is_tip(): n._tip_count = 1 else: if len(n.children) == 2: left, right = ( n.children[NUMERATOR], n.children[DENOMINATOR], ) else: raise ValueError("Not a strictly bifurcating tree.") n._tip_count = left._tip_count + right._tip_count # calculate k, r, s, t coordinate for each node left, right = ( t.children[NUMERATOR], t.children[DENOMINATOR], ) t._k, t._r, t._s, t._t = 0, left._tip_count, right._tip_count, 0 for n in t.preorder(include_self=False): if n.is_tip(): n._k, n._r, n._s, n._t = 0, 0, 0, 0 elif n == n.parent.children[NUMERATOR]: n._k = n.parent._k n._r = n.children[NUMERATOR]._tip_count n._s = n.children[DENOMINATOR]._tip_count n._t = n.parent._s + n.parent._t elif n == n.parent.children[DENOMINATOR]: n._k = n.parent._r + n.parent._k n._r = n.children[NUMERATOR]._tip_count n._s = n.children[DENOMINATOR]._tip_count n._t = n.parent._t else: # pragma: no cover raise ValueError("Tree topology is not correct.") # navigate through tree to build the basis in a sparse matrix form value = [] row, col = [], [] nodes = [] i = 0 for n in t.levelorder(include_self=True): if n.is_tip(): continue for j in range(n._k, n._k + n._r): row.append(i) # consider tips in reverse order. May want to rethink # this orientation in the future. col.append(D - 1 - j) A = np.sqrt(n._s / (n._r * (n._s + n._r))) value.append(A) for j in range(n._k + n._r, n._k + n._r + n._s): row.append(i) col.append(D - 1 - j) B = -np.sqrt(n._r / (n._s * (n._s + n._r))) value.append(B) i += 1 nodes.append(n.name) basis = coo_array((value, (row, col)), shape=(D - 1, D)) return basis, nodes def _gram_schmidt_basis(n): """Build CLR-transformed basis derived from Gram-Schmidt orthogonalization. Parameters ---------- n : int Dimension of the Aitchison simplex. Returns ------- basis : array_like of shape (n - 1, n) Basis matrix. """ basis = np.zeros((n, n - 1)) for j in range(n - 1): i = j + 1 e = np.array([(1 / i)] * i + [-1] + [0] * (n - i - 1)) * np.sqrt(i / (i + 1)) basis[:, j] = e return basis.T def sbp_basis(sbp): r"""Build an orthonormal basis from a sequential binary partition (SBP). A SBP is a hierarchical collection of binary divisions of compositional parts ([1]_). The child groups are divided again until all groups contain a single part. The SBP can be encoded in a :math:`(D - 1) \times D` matrix where, for each row, parts can be grouped by -1 and +1 tags, and 0 for excluded parts. The *i*-th balance is computed as follows: .. math:: b_i = \sqrt{ \frac{r_i s_i}{r_i+s_i} } \ln \left( \frac{g(x_{r_i})}{g(x_{s_i})} \right) where :math:`b_i` is the *i*-th balance corresponding to the *i*-th row in the SBP, :math:`r_i` and :math:`s_i` and the number of respectively ``+1`` and ``-1`` labels in the *i*-th row of the SBP and where :math:`g(x) = (\prod\limits_{i=1}^{D} x_i)^{1/D}` is the geometric mean of :math:`x`. Parameters ---------- sbp : array_like of shape (n_partitions, n_features) A contrast matrix, also known as a sequential binary partition, where every row represents a partition between two groups of features. A part labelled ``+1`` would correspond to that feature being in the numerator of the given row partition, a part labelled ``-1`` would correspond to features being in the denominator of that given row partition, and ``0`` would correspond to features excluded in the row partition. Returns ------- ndarray of shape (n_partitions, n_features) An orthonormal basis in the Aitchison simplex. Notes ----- The ``sbp_basis`` method was derived from the ``gsi.buildilrBase()`` function implemented in the R package "compositions" [2]_. Examples -------- >>> import numpy as np >>> sbp = np.array([[1, 1,-1,-1,-1], ... [1,-1, 0, 0, 0], ... [0, 0, 1,-1,-1], ... [0, 0, 0, 1,-1]]) ... >>> sbp_basis(sbp) array([[ 0.54772256, 0.54772256, -0.36514837, -0.36514837, -0.36514837], [ 0.70710678, -0.70710678, 0. , 0. , 0. ], [ 0. , 0. , 0.81649658, -0.40824829, -0.40824829], [ 0. , 0. , 0. , 0.70710678, -0.70710678]]) References ---------- .. [1] Parent, S.É., Parent, L.E., Egozcue, J.J., Rozane, D.E., Hernandes, A., Lapointe, L., Hébert-Gentile, V., Naess, K., Marchand, S., Lafond, J., Mattos, D., Barlow, P., Natale, W., 2013. The plant ionome revisited by the nutrient balance concept. Front. Plant Sci. 4, 39. .. [2] van den Boogaart, K. Gerald, Tolosana-Delgado, Raimon and Bren, Matevz, 2014. `compositions`: Compositional Data Analysis. R package version 1.40-1. https://CRAN.R-project.org/package=compositions. """ n_pos = (sbp == 1).sum(axis=1) n_neg = (sbp == -1).sum(axis=1) psi = np.zeros(sbp.shape) for i in range(0, sbp.shape[0]): psi[i, :] = sbp[i, :] * np.sqrt( (n_neg[i] / n_pos[i]) ** sbp[i, :] / np.sum(np.abs(sbp[i, :])) ) return psi def _check_basis( xp: ModuleType, basis: StdArray, orthonormal: bool = False, subspace_dim: int | None = None, ): r"""Check if basis is a valid basis for transformation. Parameters ---------- xp : namespace The array API compatible namespace corresponding ``basis``. basis : array of shape (n_basis, n_components) A columns vectors for the basis. orthonormal : bool, optional If True, basis is required to be orthonormal. Default is False. subspace_dim : int, optional The dimensions of the subspace that the basis suppose to span, when None is give, the n_basis will be used. Default is None. Raises ------ ValueError If the basis is not matching to the subspace dimension. ValueError If the basis are not orthonormal. """ xp, basis = ingest_array(basis) if basis.ndim < 2: basis = basis.reshape(1, -1) if subspace_dim is None: subspace_dim = len(basis) elif len(basis) != subspace_dim: n_basis = len(basis) msg = f"Number of basis {n_basis} not match to the subspace dim {subspace_dim}." raise ValueError(msg) if orthonormal: eyes = xp.eye(subspace_dim, device=basis.device) if not xp.all(xp.abs(basis @ basis.T - eyes) < (1e-4 * eyes + 1e-6)): raise ValueError("Basis is not orthonormal.") register_aliases(modules[__name__]) scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/_dirmult.py000066400000000000000000000743251520735541300253670ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from warnings import warn, catch_warnings, simplefilter import numpy as np import pandas as pd from skbio.util import get_rng from skbio.table._tabular import _ingest_table from ._base import _check_composition, clr from ._utils import ( _check_metadata, _check_grouping, _check_trt_ref_groups, _check_p_adjust, _type_cast_to_float, ) def _dirmult_draw(matrix, rng): """Resample data from a Dirichlet-multinomial posterior distribution. See Also -------- numpy.random.Generator.gamma numpy.random.Generator.dirichlet Notes ----- This function uses a Gamma distribution to replace a Dirichlet distribution. The result is precisely identical to (and reproducible given the same seed): .. code-block:: python return clr(np.apply_along_axis(rng.dirichlet, axis=1, arr=matrix)) A Dirichlet distribution is essentially a standard Gamma distribution normalized by row sums. Meanwhile, CLR is independent of scale, therefore the normalization step can be omitted. `gamma` can vectorize to a 2-D array whereas `dirichlet` cannot. """ return clr(rng.gamma(shape=matrix, scale=1.0, size=matrix.shape), validate=False) def dirmult_ttest( table, grouping, treatment=None, reference=None, pseudocount=0.5, draws=128, p_adjust="holm", seed=None, ): r"""Perform *t*-test using Dirichlet-multinomial distribution. The Dirichlet-multinomial distribution is a compound distribution that combines a Dirichlet distribution over the probabilities of a multinomial distribution. This distribution models the distribution of species abundances in a community. Abundance data of each sample is first fit to a Dirichlet-multinomial distribution. The posteriors are then transformed to the center log ratio (CLR) coordinates (see :func:`clr`), based on which the fold changes (differences between the treatment/reference group means) are calculated and Welch's *t*-tests are performed to assess the significance. This process is repeated for multiple draws to provide robust estimates of the statistics. The fold changes, their confidence intervals, the *p*-values and multiple-comparison corrected *p*-values are reported. This process mirrors the approach performed by the R package "ALDEx2" [1]_. Additionally, this function excludes hits with a 95% confidence interval of fold-change crossing zero during any draw. This step further reduces false positive hits, especially among low-abundance features. .. versionchanged:: 0.7.0 Computational efficiency significantly improved. Parameters ---------- table : table_like of shape (n_samples, n_features) A matrix containing count or proportional abundance data of the samples. See :ref:`supported formats `. Counts are recommended over proportions for lower statistical uncertainty. See Notes for details. grouping : pd.Series or 1-D array_like Vector indicating the assignment of samples to groups. These could be strings or integers denoting which group a sample belongs to. If it is a pandas Series and the table contains sample IDs, its index will be filtered and reordered to match the sample IDs. Otherwise, it must be the same length as the samples in the table. treatment : str, optional Name of the treatment group. The *t*-test is computed between the ``treatment`` group and the ``reference`` group specified in the ``grouping`` vector. If omitted, the first group in the sorted order of all group names will be the treatment group. reference : str, optional Name of the reference group. See above. If omitted, all groups other than the treatment group will be combined as the reference group. .. versionchanged:: 0.7.0 ``treatment`` and ``reference`` are now optional. pseudocount : float, optional A non-zero value added to the input counts to ensure that all of the estimated abundances are strictly greater than zero. Default is 0.5. draws : int, optional The number of draws from the Dirichlet-multinomial posterior distribution. More draws provide more robust estimates of uncertainty for the log-fold changes and *p*-values. Default is 128. p_adjust : str, optional Method to correct *p*-values for multiple comparisons. Options are Holm-Boniferroni ("holm" or "holm-bonferroni") (default), Benjamini-Hochberg ("bh", "fdr_bh" or "benjamini-hochberg"), or any method supported by statsmodels' :func:`~statsmodels.stats.multitest.multipletests` function. Case-insensitive. If None, no correction will be performed. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance for drawing from the Dirichlet distribution. See :func:`details `. Returns ------- pd.DataFrame A table of features, their log-fold changes and other relevant statistics. - ``T-statistic``: *t*-statistic of Welch's *t*-test. The reported value is the average across all of the posterior draws. - ``Log2(FC)``: Expected log2-fold change of abundance from the reference group to the treatment group. The value is expressed in the CLR-transformed coordinates. The reported value is the average of all of the log2-fold changes computed from each of the posterior draws. - ``CI(2.5)``: 2.5% quantile of the log2-fold change. The reported value is the minimum of per-draw 2.5% quantiles across all posterior draws. - ``CI(97.5)``: 97.5% quantile of the log2-fold change. The reported value is the maximum of per-draw 97.5% quantiles across all posterior draws. - ``pvalue``: *p*-value of Welch's *t*-test. The reported value is the average of the per-draw *p*-values across all posterior draws. - ``qvalue``: Corrected *p*-value of Welch's *t*-test for multiple comparisons. The reported value is the average of the per-draw *q*-values across all posterior draws. - ``Signif``: Whether feature is significantly differentially abundant between the treatment and reference groups. A feature marked as "True" suffice: 1) The *q*-value must be less than or equal to the significance level (0.05). 2) The confidence interval (CI(2.5)..CI(97.5)) must not overlap with zero. .. versionchanged:: 0.7.0 ``df`` (degrees of freedom) was removed from the report, as this metric is inconsistent across draws. .. versionchanged:: 0.7.0 Renamed ``T statistic`` as ``T-statistic``. Renamed ``Reject null hypothesis`` as ``Signif``. See Also -------- dirmult_ttest scipy.stats.ttest_ind statsmodels.stats.weightstats.CompareMeans Notes ----- A benefit of using the Dirichlet-multinomial distribution is that the statistical uncertainty decreases as the magnitude of abundance increases. Larger counts per sample (e.g., resulting from higher sequencing depth) will reduce the uncertainty of the estimated statistics, resulting in lower *p*-values for true positives. This is in contrast to many other statistical tests. Therefore, it is generally recommended to provide raw counts instead of pre-normalized proportions, as the latter will remove the magnitude information, which can lead to higher uncertainty in the estimates and increased false negatives. The confidence intervals are computed by taking the minimum of all per-draw 2.5% bounds and the maximum of all per-draw 97.5% bounds across posterior draws. This produces a conservative (wider) interval that captures variability across draws. The reference frame in this analysis is the geometric mean. Extracting absolute log-fold changes from this test assumes that the average feature abundance between the treatment and reference groups are identical. If this assumption is violated, the log-fold changes will be biased, and the *p*-values will not be reliable. However, the bias is the same across each feature, as a result the ordering of the log-fold changes can still be useful. References ---------- .. [1] Fernandes, A. D., Reid, J. N., Macklaim, J. M., McMurrough, T. A., Edgell, D. R., & Gloor, G. B. (2014). Unifying the analysis of high-throughput sequencing datasets: characterizing RNA-seq, 16S rRNA gene sequencing and selective growth experiments by compositional data analysis. Microbiome, 2, 1-13. Examples -------- >>> import pandas as pd >>> from skbio.stats.composition import dirmult_ttest >>> table = pd.DataFrame([[20, 110, 100, 101, 100, 103, 104], ... [33, 110, 120, 100, 101, 100, 102], ... [12, 110, 100, 110, 100, 50, 90], ... [202, 201, 9, 10, 10, 11, 11], ... [200, 202, 10, 10, 13, 10, 10], ... [203, 201, 14, 10, 10, 13, 12]], ... index=['s1', 's2', 's3', 's4', 's5', 's6'], ... columns=['b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7']) >>> grouping = pd.Series(['treatment', 'treatment', 'treatment', ... 'placebo', 'placebo', 'placebo'], ... index=['s1', 's2', 's3', 's4', 's5', 's6']) >>> result = dirmult_ttest(table, grouping, 'treatment', 'placebo', seed=0) >>> result T-statistic Log2(FC) CI(2.5) CI(97.5) pvalue qvalue Signif b1 -17.178600 -4.991987 -7.884498 -2.293463 0.003355 0.020131 True b2 -16.873187 -2.533729 -3.594590 -1.462339 0.001064 0.007446 True b3 6.942727 1.627677 -1.048219 4.750792 0.021130 0.068310 False b4 6.522786 1.707221 -0.467481 4.164998 0.013123 0.065613 False b5 6.654142 1.528243 -1.036910 3.978387 0.019360 0.068310 False b6 3.839520 1.182343 -0.702656 3.556061 0.045376 0.068310 False b7 7.600734 1.480232 -0.601277 4.043888 0.017077 0.068310 False """ from statsmodels.stats.weightstats import CompareMeans rng = get_rng(seed) matrix, samples, features = _ingest_table(table) _check_composition(np, matrix) # handle zero values if pseudocount: matrix = matrix + pseudocount # get sample indices of treatment and reference groups groups, labels = _check_grouping(grouping, matrix, samples) trt_idx, ref_idx = _check_trt_ref_groups(treatment, reference, groups, labels) cm_params = dict(alternative="two-sided", usevar="unequal") # initiate results m = matrix.shape[1] delta = np.zeros(m) # inter-group difference tstat = np.zeros(m) # t-test statistic pval = np.zeros(m) # t-test p-value lower = np.full(m, np.inf) # 2.5% percentile of distribution upper = np.full(m, -np.inf) # 97.5% percentile of distribution for i in range(draws): # Resample data in a Dirichlet-multinomial distribution. dir_mat = _dirmult_draw(matrix, rng) # Stratify data by group (treatment vs. reference). trt_mat = dir_mat[trt_idx] ref_mat = dir_mat[ref_idx] # Calculate the difference between the two means. delta += trt_mat.mean(axis=0) - ref_mat.mean(axis=0) # Create a CompareMeans object for statistical testing. # Welch's t-test is also available in SciPy's `ttest_ind` (with `equal_var= # False`). The current code uses statsmodels' `CompareMeans` instead because # it additionally returns confidence intervals. cm = CompareMeans.from_data(trt_mat, ref_mat) # Perform Welch's t-test to assess the significance of difference. tstat_, pval_, _ = cm.ttest_ind(value=0, **cm_params) tstat += tstat_ pval += pval_ # Calculate confidence intervals. # The final lower and upper bounds are the minimum and maximum of all lower # and upper bounds seen during sampling, respectively. lower_, upper_ = cm.tconfint_diff(alpha=0.05, **cm_params) np.minimum(lower, lower_, out=lower) np.maximum(upper, upper_, out=upper) # Normalize metrics to averages over all replicates. delta /= draws tstat /= draws pval /= draws # Correct p-values for multiple comparison. if p_adjust is not None: qval = _check_p_adjust(p_adjust)(pval) else: qval = pval reject = qval <= 0.05 # Test if confidence interval includes 0. # A significant result (i.e., reject null hypothesis) must simultaneously suffice: # 1) q-value <= significance level. 2) confidence interval doesn't include 0. # This test is in addition to the original ALDEx2 method. It helps to reduce false # positive discoveries of low abundance. outer = ((lower > 0) & (upper > 0)) | ((lower < 0) & (upper < 0)) reject &= outer # Convert all log fold changes to base 2. log2_ = np.log(2) delta /= log2_ upper /= log2_ lower /= log2_ # construct report res = pd.DataFrame.from_dict( { "T-statistic": tstat, "Log2(FC)": delta, "CI(2.5)": lower, "CI(97.5)": upper, "pvalue": pval, "qvalue": qval, "Signif": reject, } ) if features is not None: res.index = features return res def dirmult_lme( table, metadata, formula, grouping, pseudocount=0.5, draws=128, p_adjust="holm", seed=None, re_formula=None, vc_formula=None, model_kwargs={}, fit_method=None, fit_converge=False, fit_warnings=False, fit_kwargs={}, ): r"""Fit a Dirichlet-multinomial linear mixed effects model. .. versionadded:: 0.7.0 The Dirichlet-multinomial distribution is a compound distribution that combines a Dirichlet distribution over the probabilities of a multinomial distribution. This distribution is used to model the distribution of species abundances in a community. To fit the linear mixed effects model we first fit a Dirichlet-multinomial distribution for each sample, and then we compute the fold change and *p*-value for each feature. The fold change is computed as the slopes from the resulting model. Statistical tests are then performed on the posterior samples, drawn from each Dirichlet-multinomial distribution. The log-fold changes as well as their credible intervals, the *p*-values and the multiple comparison corrected *p*-values are reported. This function uses the :class:`~statsmodels.regression.mixed_linear_model.MixedLM` class from statsmodels. .. note:: Because the analysis iteratively runs many numeric optimizations, it can take longer than usual to finish. Please allow extra time for completion. Parameters ---------- table : table_like of shape (n_samples, n_features) A matrix containing count or proportional abundance data of the samples. See :ref:`supported formats `. Counts are recommended over proportions for lower statistical uncertainty. See Notes of :func:`dirmult_ttest` for details. metadata : pd.DataFrame or 2-D array_like The metadata for the model. Rows correspond to samples and columns correspond to covariates in the model. Must be a pandas DataFrame or convertible to a pandas DataFrame. formula : str or generic Formula object The formula defining the model. Refer to `Patsy's documentation `_ on how to specify a formula. grouping : str, pd.Series or 1-D array_like A vector or a metadata column name indicating the assignment of samples to groups. Samples are independent between groups during model fitting. pseudocount : float, optional A non-zero value added to the input counts to ensure that all of the estimated abundances are strictly greater than zero. Default is 0.5. draws : int, optional Number of draws from the Dirichlet-multinomial posterior distribution. Default is 128. p_adjust : str, optional Method to correct *p*-values for multiple comparisons. Options are Holm-Boniferroni ("holm" or "holm-bonferroni") (default), Benjamini-Hochberg ("bh", "fdr_bh" or "benjamini-hochberg"), or any method supported by statsmodels' :func:`~statsmodels.stats.multitest.multipletests` function. Case-insensitive. If None, no correction will be performed. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance for drawing from the Dirichlet distribution. See :func:`details `. re_formula : str, optional Random coefficient formula. See :meth:`MixedLM.from_formula ` for details. vc_formula : str, optional Variance component formula. See ``MixedLM.from_formula`` for details. model_kwargs : dict, optional Additional keyword arguments to pass to ``MixedLM``. fit_method : str or list of str, optional Optimization method for model fitting. Can be a single method name, or a list of method names to be tried sequentially. See `statsmodels.optimization `_ for available methods. If None, a default list of methods will be tried. fit_converge : bool, optional If True, model fittings that were completed but did not converge will be excluded from the calculation of final statistics. Default is False. fit_warnings : bool, optional Issue warnings if any during the model fitting process. Default is False. Warnings are usually issued when the optimization methods do not converge, which is common in the analysis. Default is False. fit_kwargs : dict, optional Additional keyword arguments to pass to :meth:`MixedLM.fit `. Returns ------- pd.DataFrame A table of features and covariates, their log-fold changes and other relevant statistics. - ``FeatureID``: Feature identifier, i.e., dependent variable. - ``Covariate``: Covariate name, i.e., independent variable. - ``Reps``: Number of Dirichlet-multinomial posterior draws that supported the reported statistics, i.e., the number of successful model fittings on this feature. Max: ``draws`` (if none failed). Min: 0 (in which case all statistics are NaN). - ``Log2(FC)``: Expected log2-fold change of abundance from the reference category to the covariate category defined in the formula. The value is expressed in the center log ratio (see :func:`clr`) transformed coordinates. The reported value is the average of all of the log2-fold changes computed from each of the posterior draws. - ``CI(2.5)``: 2.5% quantile of the log2-fold change. The reported value is the minimum of all of the 2.5% quantiles computed from each of the posterior draws. - ``CI(97.5)``: 97.5% quantile of the log2-fold change. The reported value is the maximum of all of the 97.5% quantiles computed from each of the posterior draws. - ``pvalue``: *p*-value of the linear mixed effects model. The reported value is the average of all of the *p*-values computed from each of the posterior draws. - ``qvalue``: Corrected *p*-value of the linear mixed effects model for multiple comparisons. The reported value is the average of all of the *q*-values computed from each of the posterior draws. - ``Signif``: Whether the covariate category is significantly differentially abundant from the reference category. A feature-covariate pair marked as "True" suffice: 1) The *q*-value must be less than or equal to the significance level (0.05). 2) The confidence interval (CI(2.5)..CI(97.5)) must not overlap with zero. See Also -------- dirmult_ttest statsmodels.formula.api.mixedlm statsmodels.regression.mixed_linear_model.MixedLM Examples -------- >>> import pandas as pd >>> from skbio.stats.composition import dirmult_lme >>> table = pd.DataFrame( ... [[1.00000053, 6.09924644], ... [0.99999843, 7.0000045], ... [1.09999884, 8.08474053], ... [1.09999758, 1.10000349], ... [0.99999902, 2.00000027], ... [1.09999862, 2.99998318], ... [1.00000084, 2.10001257], ... [0.9999991, 3.09998418], ... [0.99999899, 3.9999742], ... [1.10000124, 5.0001796], ... [1.00000053, 6.09924644], ... [1.10000173, 6.99693644]], ... index=['u1', 'u2', 'u3', 'x1', 'x2', 'x3', 'y1', 'y2', 'y3', 'z1', ... 'z2', 'z3'], ... columns=['Y1', 'Y2']) >>> metadata = pd.DataFrame( ... {'patient': [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4], ... 'treatment': [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2], ... 'time': [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3],}, ... index=['x1', 'x2', 'x3', 'y1', 'y2', 'y3', 'z1', 'z2', 'z3', 'u1', ... 'u2', 'u3']) >>> result = dirmult_lme(table, metadata, formula='time + treatment', ... grouping='patient', seed=0, p_adjust='sidak') >>> result FeatureID Covariate Reps Log2(FC) CI(2.5) CI(97.5) pvalue \ 0 Y1 time 128 -0.210769 -1.532255 1.122148 0.403737 1 Y1 treatment 128 -0.744061 -3.401978 1.581917 0.252057 2 Y2 time 128 0.210769 -1.122148 1.532255 0.403737 3 Y2 treatment 128 0.744061 -1.581917 3.401978 0.252057 qvalue Signif 0 0.644470 False 1 0.440581 False 2 0.644470 False 3 0.440581 False """ from patsy import dmatrix from scipy.optimize import OptimizeWarning from statsmodels.regression.mixed_linear_model import MixedLM, VCSpec from statsmodels.tools.sm_exceptions import ConvergenceWarning rng = get_rng(seed) matrix, samples, features = _ingest_table(table) _check_composition(np, matrix) n_feats = matrix.shape[1] if n_feats < 2: raise ValueError("Table must have at least two features.") if features is None: features = np.arange(n_feats) # validate metadata metadata = _check_metadata(metadata, matrix, samples) # cast metadata to numbers where applicable metadata = _type_cast_to_float(metadata) # Instead of directly calling `MixedLM.from_formula` on merged table + metadata, # the following code converts metadata into a design matrix based on the formula # (as well as re_formula and vc_formula, if applicable), and calls `MixedLM`. # This is because the design matrix (independent variable) is always the same # whereas the table (dependent variable) is resampled in every replicate. Fixing # the design matrix can save conversion overheads. # Create a design matrix based on metadata and formula. dmat = dmatrix(formula, metadata, return_type="matrix") # Obtain the list of covariates by selecting the relevant columns covars = dmat.design_info.column_names # Remove intercept since it is not a covariate, and is included by default. # Then determine the range of rows to be extracted from the model fitting result. # (See also `result.model.k_fe`, number of fixed effects.) if covars[0] == "Intercept": covars = covars[1:] n_covars = len(covars) covar_range = slice(1, n_covars + 1) else: n_covars = len(covars) covar_range = slice(0, n_covars) exog_mat = np.asarray(dmat) # parse grouping if isinstance(grouping, str): try: grouping = metadata[grouping].to_numpy() except KeyError: raise ValueError("Grouping is not a column in the metadata.") uniq, grouping = np.unique(grouping, return_inverse=True) else: uniq, grouping = _check_grouping(grouping, matrix, samples) n_groups = len(uniq) # random effects matrix if re_formula is not None: exog_re = np.asarray(dmatrix(re_formula, metadata, return_type="matrix")) else: exog_re = None # variance component matrices # see: https://www.statsmodels.org/v0.12.2/examples/notebooks/generated/ # variance_components.html if vc_formula is not None: metas = [metadata.iloc[grouping == x] for x in range(n_groups)] names, cols, mats = [], [], [] for name, formula in vc_formula.items(): names.append(name) dmats = [dmatrix(formula, x, return_type="matrix") for x in metas] cols.append([x.design_info.column_names for x in dmats]) mats.append([np.asarray(x) for x in dmats]) exog_vc = VCSpec(names, cols, mats) else: exog_vc = None # handle zero values if pseudocount: matrix = matrix + pseudocount # initiate results shape = (n_feats, n_covars) coef = np.zeros(shape) # coefficient (fold change) pval = np.zeros(shape) # p-value lower = np.full(shape, np.inf) # 2.5% CI upper = np.full(shape, -np.inf) # 97.5% CI # number of replicates (draws) LME fitting is successful for each feature fitted = np.zeros(n_feats, dtype=int) fit_fail_msg = "LME fit failed for feature {} in replicate {}, outputting NaNs." with catch_warnings(): if not fit_warnings: simplefilter("ignore", UserWarning) simplefilter("ignore", ConvergenceWarning) simplefilter("ignore", OptimizeWarning) # This is temporary because statsmodels calls scipy in a deprecated way as # of v0.14.4. simplefilter("ignore", DeprecationWarning) for i in range(draws): # Resample data in a Dirichlet-multinomial distribution. dir_mat = _dirmult_draw(matrix, rng) # Fit a linear mixed effects (LME) model for each feature. for j in range(n_feats): model = MixedLM( dir_mat[:, j], exog_mat, grouping, exog_re=exog_re, exog_vc=exog_vc, **model_kwargs, ) # model fitting (computationally expensive) try: result = model.fit(method=fit_method, **fit_kwargs) # There are many ways model fitting may fail. Examples are LinAlgError, # RuntimeError, OverflowError, and ZeroDivisionError. If any error # occurs, the function will still proceed but the current run will be # discarded. except Exception: warn(fit_fail_msg.format(features[j], i), UserWarning) continue # It is common that model fitting successfully finished (no error) but # the optimizer did not converge, making the calculated statistics less # reliable. The `fit_converge` flag can discard these runs. if fit_converge and not result.converged: # pragma: no cover warn(fit_fail_msg.format(features[j], i), UserWarning) continue # update results coef[j] += result.params[covar_range] pval[j] += result.pvalues[covar_range] # calculate confidence interval and update results ci = result.conf_int() np.minimum(lower[j], ci[covar_range, 0], out=lower[j]) np.maximum(upper[j], ci[covar_range, 1], out=upper[j]) fitted[j] += 1 # deal with fitting failures all_fail_msg = "LME fit failed for {} features in all replicates, reporting NaNs." mask = fitted > 0 n_failed = n_feats - mask.sum() # all succeeded if n_failed == 0: mask = slice(None) # some failed elif n_failed < n_feats: # pragma: no cover warn(all_fail_msg.format(n_failed), UserWarning) for x in (coef, pval, lower, upper): x[~mask] = np.nan # all failed else: raise ValueError("LME fit failed for all features in all replicates.") # normalize metrics to averages over all successful replicates fitted_ = fitted.reshape(-1, 1)[mask] for x in (coef, pval): x[mask] /= fitted_ # convert all log fold changes to base 2 log2_ = np.log(2) for x in (coef, lower, upper): x[mask] /= log2_ # correct p-values for multiple comparison # (only valid replicates are included) if p_adjust is not None: func = _check_p_adjust(p_adjust) qval = np.full(shape, np.nan) qval[mask] = np.apply_along_axis(func, 1, pval[mask]) else: qval = pval # get significant results (q-value <= 0.05 and CI doesn't cross 0) # see `dirmult_ttest` reject = np.full(shape, np.nan) ii = np.where(mask)[0] if n_failed else np.arange(n_feats) for i in ii: outer = ((lower[i] > 0) & (upper[i] > 0)) | ((lower[i] < 0) & (upper[i] < 0)) reject[i] = (qval[i] <= 0.05) & outer # construct report res = pd.DataFrame.from_dict( { "FeatureID": [x for x in features for _ in range(n_covars)], "Covariate": list(covars) * n_feats, "Reps": np.repeat(fitted, n_covars), "Log2(FC)": coef.ravel(), "CI(2.5)": lower.ravel(), "CI(97.5)": upper.ravel(), "pvalue": pval.ravel(), "qvalue": qval.ravel(), } ) # pandas' nullable boolean type res["Signif"] = pd.Series(reject.ravel(), dtype="boolean") return res scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/_utils.py000066400000000000000000000215041520735541300250360ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import inspect import numpy as np import pandas as pd def _check_metadata(metadata, matrix, samples=None): """Format metadata for differential abundance analysis. Parameters ---------- metadata : dataframe_like Metadata table. matrix : ndarray of shape (n_samples, n_features) Data matrix. samples : array_like of shape (n_samples,), optional Sample IDs. Returns ------- pd.DataFrame Validated metadata table. Notes ----- This function resembles `_check_grouping`. """ if not isinstance(metadata, pd.DataFrame): try: metadata = pd.DataFrame(metadata) except Exception: raise TypeError( "Metadata must be a pandas DataFrame, or a data structure that can be " "converted into a pandas DataFrame, such as a NumPy structured or rec " "array, or a dictionary." ) # match lengths if samples is None or isinstance(metadata.index, pd.RangeIndex): if matrix.shape[0] != metadata.shape[0]: raise ValueError("Sample counts in table and metadata are not consistent.") # match sample IDs else: if not metadata.index.equals(pd.Index(samples)): try: metadata = metadata.loc[samples] except KeyError: raise ValueError( "Metadata contains sample IDs that are absent in the table." ) if metadata.isnull().values.any(): raise ValueError("Cannot handle missing values in metadata.") return metadata def _check_sig_test(test, n_groups=None): """Validate significance test. Parameters ---------- test : str or callable Statistical testing function or its name. n_groups : int, optional Number of sample groups. Returns ------- callable Statistical testing function. """ if isinstance(test, str): import scipy.stats try: func = getattr(scipy.stats, test) except AttributeError: raise ValueError(f'Function "{test}" does not exist under scipy.stats.') else: if not callable(test): raise TypeError("`sig_test` must be a function or a string.") func = test test = test.__name__ if n_groups is not None: sig = inspect.signature(func) param = next(iter(sig.parameters.values())) is_multi = param.kind is inspect.Parameter.VAR_POSITIONAL if n_groups > 2 and not is_multi: raise ValueError( f'"{test}" is a two-way statistical test whereas {n_groups} sample ' "groups were provided." ) return func def _check_p_adjust(name): r"""Construct a p-value correction function based on the method name. Parameters ---------- name : str The name of the p-value correction method. This should match one of the method names available in :func:`statsmodels.stats.multitest.multipletests`. Returns ------- callable, optional Function to correct p-values. """ if name is None: return from statsmodels.stats.multitest import multipletests as sm_multipletests name_ = name.lower() # Original options are kept for backwards compatibility if name_ in ("holm", "holm-bonferroni"): name_ = "holm" if name_ in ("bh", "fdr_bh", "benjamini-hochberg"): name_ = "fdr_bh" def func(pvals): r"""Correct p-values for multiple testing problems. Parameters ---------- pvals : ndarray of shape (n_tests,) Original p-values. Returns ------- qvals : ndarray of shape (n_tests,) Corrected p-values. """ try: res = sm_multipletests(pvals, alpha=0.05, method=name_) except ValueError as e: if "method not recognized" in str(e): raise ValueError(f'"{name}" is not an available FDR correction method.') else: # pragma: no cover raise ValueError( f"Cannot perform FDR correction using the {name} method." ) else: return res[1] return func def _check_grouping(grouping, matrix, samples=None): """Format grouping for differential abundance analysis. Parameters ---------- grouping : 1-D array_like Vector indicating the assignment of samples to groups. For example, these could be strings or integers denoting which group a sample belongs to. matrix : ndarray of shape (n_samples, n_features) Data matrix. samples : array_like of shape (n_samples,), optional Sample IDs. Returns ------- groups : ndarray of (n_groups,) Class names. labels : ndarray of (n_samples,) Class indices by sample. Notes ----- If `grouping` is indexed and `samples` is provided, `grouping` will be filtered and reordered to match `samples`. Otherwise, `grouping` and `matrix` must have the same length, with the assumption that samples are in the same order. """ # match sample IDs if samples is not None and isinstance(grouping, pd.Series): try: grouping = grouping.loc[samples] except KeyError: raise ValueError( "`table` contains sample IDs that are absent in `grouping`." ) else: grouping = grouping.to_numpy() # match lengths else: grouping = np.asarray(grouping) if grouping.ndim != 1: raise ValueError("`grouping` must be convertible to a 1-D vector.") if matrix.shape[0] != grouping.shape[0]: raise ValueError( "Sample counts in `table` and `grouping` are not consistent." ) # The following code achieves what `pd.isnull` does with NumPy. null_errmsg = "Cannot handle missing values in `grouping`." if np.isdtype(grouping.dtype, "numeric"): if np.isnan(grouping).any(): raise ValueError(null_errmsg) else: if (grouping != grouping).any() or np.equal(grouping, None).any(): raise ValueError(null_errmsg) return np.unique(grouping, return_inverse=True) def _check_trt_ref_groups(treatment, reference, groups, labels): """Extract treatment and reference group indices. Parameters ---------- treatment : str, int or None Treatment group label. reference : str, int or None Reference group label. groups : ndarray of (n_groups,) Class names. labels : ndarray of (n_samples,) Class indices by sample. Returns ------- trt_idx : ndarray of (n_samples_in_treatment,) Sample indices in the treatment group. ref_idx : ndarray of (n_samples_in_reference,) Sample indices in the reference group. Raises ------ ValueError If treatment or reference group is not found. ValueError If treatment and reference groups are the same. ValueError If there are less than two groups. """ if len(groups) < 2: raise ValueError("There must be at least two groups in grouping.") if treatment is not None: try: (trt_i,) = np.flatnonzero(groups == treatment) except ValueError: raise ValueError(f"Treatment group {treatment} is not found in grouping.") else: trt_i = 0 trt_idx = np.flatnonzero(labels == trt_i) if reference is not None: try: (ref_i,) = np.flatnonzero(groups == reference) except ValueError: raise ValueError(f"Reference group {reference} is not found in grouping.") if trt_i == ref_i: raise ValueError("Treatment and reference groups must not be identical.") ref_idx = np.flatnonzero(labels == ref_i) else: ref_idx = np.flatnonzero(labels != trt_i) return trt_idx, ref_idx def _type_cast_to_float(df): """Attempt to cast all of the values in dataframe to float. This will try to type cast all of the series within the dataframe into floats. If a column cannot be type casted, it will be kept as is. Parameters ---------- df : pd.DataFrame Returns ------- pd.DataFrame """ df = df.copy() for col in df.select_dtypes(exclude=["float64"]).columns: try: df[col] = df[col].astype("float64") except (ValueError, TypeError): continue return df scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/tests/000077500000000000000000000000001520735541300243255ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/tests/data/000077500000000000000000000000001520735541300252365ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/tests/data/pseq_feature_table_subset.csv.gz000066400000000000000000000620571520735541300336230ustar00rootroot00000000000000‹ ´ñhÿpseq_feature_table_subset.csvt�Û®.9rœïõz€ß@ñL^Ú Ì…‚ݶF¸�‘Z虹ðÛ»â‹d±þÝ=€Ý½×æªb‘yˆŒŒüü÷?þõçÿüåß~úã_ÿôëÏ?}þÿðËÏÿþ§¿þé/Ÿú?}ÿÙÏþóÏŸúó/ùë¯?ÿûÏû�üãŸÿö—ûOÿñ¿ÿ_ÿðwþû¿üþþ×ßýÏÿú‡¿óŸÿð÷þà_~úý?ø—¿óŸÿð÷þûßÿƒ?|þÏþñoþëß~ýÓ¿ÿãóC?ýùÞµ×ü¯_î ûãß´—ÿóo9[ù¿ýå¯:ÿúÏÿõó¯¿üñÿþĦÿËŸ~ýõoüå?~þ㯿üÛÏ?ýÃ?ÿôÿõç?ý·ôIk|f¯Ÿë3Ú'µO¾ÿïZùSƧÞÿö©9_ŸûÇÒýõSòçþËi¯’?©¬Oö2)ß¾´TIc~fýŒûÏ>yµ¥u²~Ó§öùéë^©ÍûßKß+•{¥û?ö¡ß–?­}ú§Þ�ð¹ÿ§T­ÓGÒ2KZïÿ_õsõ³ø£í…ô.÷Ï”ëþÏ÷ÛèÅÖ§”Ô?3}Ú¸×ý/÷JSÿ§|úýj¹½œ–*u¯ÔïÇ»_…•ú¥•Öý“ós¿ªž«ž…î­Ÿ©UºöâYåþÃqoôbƒÊ½wú�ûŸÒçÞ^ýêûÅ&+4ïöý'ÚéY¿vú~‡öE«Üo¥_?rš÷ëeÚ¥ÇéEûro[«·æ�š^kÌçËߦL÷>Þ/v¯2´ eL-¨ÿp/U¦¾™K{¿îÓ!hüþ¾ž¥šDÊ:÷»WI—¾Ïýì9VÊ©^¬tÝÿ{ÿZ½Za3®ëY¦û¥ÉÖÝp?R¾ÿçZ~:mø}6.NQÑcß;Évß{’y¦g¿ïŸ/ú•Wæí¼¯×ý ³Uþ¹w=ÖÐÑâ‰õZçÁ:¿?Ÿ­šf}_�ölõýÃU'‹ xÿ²¥�‘»öY'�®eèjqûuÊü@3qӞۯߓô92¥T.Ô½Eõ~Hí/‡²uH]¢{ƒ?eòý±y<+ݤŸÁ,èýîÖ´©÷�ßóÞÜ„a»l•ê,”Rù>I¹ë•û™ôHC—Z?_g$¥rùöóõ½z=ßÓò¬tï`— X%¾ºþúuÿ»Î¶¬Òì÷Ò­©[ÕîºÏ€Íê³Ì}²î3·Æš€©S¨�Ô|ÞY'é¿ß ÉBh›’– 3pßÃg­ûcÝǽ%ÎRg¿ï�ØÊâ#q&ïû¨ï�‘º7Ý_WÕ|Ë-3Õõ‹ô´tŸ¦ûÉ”uêvÕf®gÞ®ñ©Ï:÷ß/\ëb�8“² ²¸÷w¸í…Þµr5´œlÄýè‰GoúE÷Þï~ètU�4¾Å}mï[rßÊ9î•ïã|Ÿ�û$,®ð˜;(k?nç0pª�{ÒƒÜ& «’ª ½:2¸�ÎÚ~¡©<çáþúY÷ZÏqoi^÷¥Ñ®g>àÔBU‡ð^á60Ïe>ÇT–nèâÛWd½�®á�ÍÃùÈêÝÏt¯Ô° ú¼Ùž¸~÷×¼ÏÕ:wŒ Cp_ðÛžf¢€û`f,^CÇ /ï’£¤³Î½ˆöeÚ,8è¹÷àR6>ØáRx"‚Œõ™—½Àã¥n32jã]ú¥ Ÿ�îåï'M“`;H¬¨¹=sø;ŽL}ÌpÓSO‡=YVT†÷>ˆ�ÚtÆ'·Å�Aê6œÃË<«È½Þ?“>Ù+¬T½=£6ãÂÅÔ‹#Iè©3a35u¿Úd(ÂÓôwK5{§m²õ¥a©ÒË7 9Y‚­}Ž›¹¿d¾�R[ûʆ�+ž‚k  ú`HºŽ#÷„ãË{'¦ÍÎ¥_‘l¦/}ýä×.?ÙvGŒEæO¡ïýˆgÝÛ*£¯í«2†òzE~³ðV š|½Œ_Qpp;j_ÿîg©{å¨+{¾Ø†¢]RÔÞÜÁŠì9Wìþ÷¸(x¥rNç˜è hß²ºÃemu‘Q¾ásø½tü¿ÀҪ˦râvµý>œ2"D‰;r?öÒ[Eˆ‰¡|L›¢wÅØ·}+‡ßou?ùÂûV]õû­´íÞu½®öA÷ åô÷ƒ�LLU"½Ï’>úÀ�ߟ~áD†â9í‰þ!lä+¿PL{¯T‰ŸyF½@“¿ë|ÿû‡uªõ®ºµºç¿ÍœîWšŠT´È¸ýàu[æûµd÷¡¯¹°B°äK›¾¾¼¬è¥÷�˜~­œøLá¼\´ÃKEx®æ'Êç‰ÑiưݷñþcÜä˜ÞzŒm%@øxï¿\uJîßþ8Ëa(�SÒã‹&t[µÙ¸Ê�`u.?›½ïéëÍ¿ì~ÎÇÜf3MÝy¼Éý4z Ù®Û¤èp]<��¡xhè»n�سÔÄ‘'¾Õq¦b>¹·ä¿]ì*€ø*aIpeé¼âý±š,UýØeÌ«ë²ê•F甯HÆs%<ñÝu _N*uoß}ô¦ã�ûV¸û<´Ì +\päN7äSõ¦�ñ%ÛEÏà$Ëè*ô¿ÿGF¨+ˆUXMxW"’V! ö!�kO¾1tï¯;‹³€¥—˜r´òï9©Þ8aÓö@Q’N–7åY©�fx¯dUºîEk÷I«‹¬ãEì÷!ìº]�¬–ZXš×SÉjßg€ÿ®³ª€ò>‚Ê_îO€�º}X·IÐ!-Ú+åÁ˜Ìu6ý~N]5ÎrŸŽæd‡¹Ò@µ:–ëv.yÚd‚äóH ¼ïMÈ—;9Âíd„£t9´{Ë«<ש€¶è Ü{®',�? šP¸ƒw6¥œóº°¿¬t§_rØÖû÷6\ó6 �‘‚<î­fó.m=áö¸°îJ°�*ªàúi“.ǪÃßèYèŽ:x ìéýáº^¨)J@ãê^ £Pø‰È¦Ç³Ôýw‡"öaØ¡�6µNÄgËW«;+»·¹Žð½íË÷ê´*‘¸"ÍR(Gr¡ýÈ„ÏÙQ=™ñ£œèL;HÈ$f/DÖŽx’¾ïíˆè+V½*I„þ°âšÞö$‹ó?.Ò¬>"¨i‰ˆ‡€·dû«a¯ö´'B™@H÷[±º3:Áo:}K¿S8VŸ'mäÝŠRF2ÑtÞ­ÉpÔ¢g¿�zæùªà½Iå OaæAwCw–é€ #Ð ¦ÜGVÇH�÷ ¼áR|/C|Rm4žuì-&_$ =¸þOú ‹ÜÂñ‰üD’o!öšg‡”ÈØ€$;¼{Û ÊR¨£  †oIcŸîò}$—3Ñ;£ÌxÏ⬴a�µ£ÝŸ²„Ö/RH"8Љðñ-+R¹ „¡kRº|ß¹!›>³®}*» [-8±?ÏûݧÝ÷ `CGwä$¸#óáŒóù«žUšS°sŽä¿…µÎ „ì û<�;R¬³ÊReèZ"�,¬?g[¨„oôͲô ì’þ€ ³!~Ö1žBŸ‰¹ž§~_›Y8¿¿¯ÿ2ü6ùÇ x=&ÃO °B&\æONV Êí%ɤ.bV�“Â� žtì>Ý÷ú \ìüs@?/©òÊ£d¯î ,šH„ɧ…z¿pQÔ5êöRvø²¿Iñy-ÇúÄ[q•‘:‚ÂHå×;Êóç�‘ÚEj¯´THím©x¦;4.;N6 dx`ò½cþÚ" 09ÞuÝÏ«Û#ßu³©]KD} ÝŒ¤u;¤ûWŸ;¹mÊ×åsªÜ@ÎQÙ‚P�‹@£ŒH†?ÂmÁCv(Ü^[¦pIQßÚ!ÑÏ}�'JQ0Fvnåø.Þ”ðn�³Ö}�›n?y�$Êú]ݾdèÝ1•2>]“Ë¡âú(¿�nWîE„5�ðÝÏÑñZ¨…�èåð8òÞ�¤ €àƒÓ(‘o ›­¢’ò{mpEV\¡K�’ÌXÇï)j¨:8yƒ,» 6êrdÐe]äE¸äQʆ ôR\íˆ^OÄ=î'F™ûv{VLiƒšöÌ×»·Õ–Ïunµ jÅå Æä›s¶ƒèŠøÂ%_=ÊR˜öbÛýÚ$—Ë ›Ôx5VªÀFv¦™Â/ß´ûvZãƒt(÷Þ•,ŠY�)ó­L øvsfƒ~ºâìSò‰~=Öऄÿ°ÓÑÉY¹Ê&àf›ä¡ÛM’é<æ¸/™%ýo%<š|®)0X@8ÅÕq,QŸ@šaeÊë… \%ç›ñùzN™%9œ:åÉÕ Ç)…Èãú>›÷¯Âø¡rd;«`ª:Ó±îi9tF €É>þ %þ@P8@rä©\O‹Ëwê]‘eï IÖc¦c´SñÊTad�qÑŽÓeK]yÒÝv vG°×Îlç÷‘µ×÷H@I§'°eØÇ|Þéè>]‹˜‹Ð±|Á@ ¼1ã>â>‡Œ¥b€žÌ´Œ¡1þžØ)×ù} •JM> 6�¼OŽK`uŠ€v]£œÂ”ªœý¬tN„ ý<å~6�Kåi²#Ú£ÊÓQ­ïϼ’ün@㬵œ_¦¶ëF;¦^·NïÖíµ)ËeG‘¡¯ÿzC½‰‚ÒdÕô 6ž”�p´ÇÃ]¶@à±Y¯h ÏÌ ö¸™( \¦ƒ†z'\Ê+O°ûxΤ€WY õ½õSf§•ˆ$s&GV06|þ ÛˆId]•«ÄÉ긊)ßÑü‚­²M~† !O„Ì׿ÏH³ÑÒ#��Φ$ DöþSa@l¿Lo·@ÎçU@èDëåÒ ŽCul�¢�Ìr^Û>¨„é �Äôd€ºÏM[‹Oi5jK÷¨@{¸Z> •výC¿€äûO6 ò$cô®— þ,…ˆÝp×Hó àwÇv)óœy¹QÕA¾Šhë}ð!ŠÐuº*º‹D¹ø5û7|D®ËíÁ¾È “PæÀe\]p¦¨ðSmºÊëHÈ/Ñ0xäéŠ�.¥QPµÚ½šÒ°Kšý NWu é7C¢ò–·Ûv¸kÌk ×jIå§qWÂy¥I¯¥xÜDÒ}u•0/Cr?)jÈÎĪ3ÌHè1ô•D‘s7R‰rù§íòm]eÍÜRî!øõù€Â À0ýg¡é*u²&Q¦Ô†«Q"wø: ¡Î7—ÃÐ;ÜŸY_!êÆ�AìísnAßñ 8§T�b?J¤Þüú>+5?H^€+*ãy?Gð¯gÒyWŠ“ÁÛ“Ð9ƒÆ¤øÅÇê¾?׿îè•õ¹éòÎc´Öª°Bþتó¢Û*i«ìuízØžÓ~•KxΦžà>d³2  §†#�Ê3en |ƒ…+×#ÕΦ YK@¹/`ÞØžÈRM‡9%ŠíTú.׃¢¼úz,9m¥±„‰ArJ*-¹dì_Zì:wÔ;6LxèIIÁ½N–#œª CM ð–ÓÛž/Ã;ÕðÎY¨Ä�a¬4cãîƒQçýAO¢D¢\ìêÎr\ª}=Ôp:Ÿ—â¼S�E°ÆË5⢀úp<êmz­ƒŸ&¬Ðe(Icލ֧¶3qrQîõVòî÷†5gÝ”åg‘ßèË4‰ÊmtX5ÀDŸŒþœH}$y[ž„“ÒkjÏ$óR# ÌàŒ–/,]±uVÍì" U ©€M)ù´ÇGbmët¯™ÍïX®jœ£´=—D7N9£"W�P¸2fÜ~¶q³æ&"Ì׃à?î\í&m)`Q¤x¥(ANÛ‚ìDh†ˆŽïú÷î4jZ�ØXµ1"d ªJ˵Un]D/iç9�K�R�4¢«D(r‚U¶Ú Lr—*¬¿ñ¿É¡@ïuÛß »bZQbkÓ}�»ëÝd–_ù[7pžGkm¢Š Œ c ‚ìûþ*|k®a�ã¾€Ýâ9£;fÞUÕ�|…[-ùq1Æ ®ƒÌ½6kù¤dŠ+ÄÈÜã;•a#Ój@ë5¼Ì¸ð×A0Z/Fß¾•ŒAs�^V!ôåÚ 1èFeÊU��÷S�¡J6b¬ +M×¹3Ѹ…¸´Ïfnä/,›`nÈà`¬ûWç>J…b™ÙsÃx¿#9µs ^K¢ƒJB�GnYZ.µ¸rÐUGB„=ò‘S>ò¥b6]¡“›ûÒ±ÿÉNæ2[¢9 ‚`þb;ÙgfX%Nod:•¦R%¢�(gÔDn;91¥í¯wPZÕ/ááºplHGø¾E\æ{k:hFøª>¡¾‚íµ’ê·Ž^.yj Q¿*¤eнF̜ͥS5TO”¾#™|ý8 °~×})§~a (­;#Q–¢ªIç¨n´âa+c #ÊYŽ¡ä”ÁUq©DSMT�O0SmÞá‹«‡¸Ù4³Ò�‡Ødµ+öÐ54Ú5 &ŠÀ¨rÚI�#!�v?–à°Ný¥Yt‹Ú ¾‚JdÅ4à6“&©â¯–£ À”�NŠk'eo�Å�ÓF¢ÔÞy| †zìdžùeÓ¬¨› “£®”ܸÚý}.j=�Â8aâYLG½501ȱQ)¿ƒ,Ï JŽN(ô›B(ä}}GÈÓ†8MCÓ~5Ù-Óûâ¸X¾�õ—_Ì®y´¿ sÎM9D7Ç vϽ«SJ›ðQíh9¸‚—@F;I›Üòq÷~ Ǽ¨M¶¤ã·…áîÈï6Š\)®¦ÏùµëU_‡LPvTï½\œ±Q¡žˆ/ º…s&îåpõ»»�ÞN@º Šö4Ìl˜Ú#I1�rìù˜�hãà´:ò8o¸ì ¦+YØ?Áœm=tŸ;ì.ö@‚èjB›çórÂVùK.:8„¬+cIQÃ…m¦”‚�Oß^Qæø$ÒXÛ:gJ™y{Œ™nÎ0n—}ÆúŽ"a~"n¯Íheîš%èNí+‰jî]5ÏëØee�÷m9É:|“ŸÀƒ±°¹Æ~”W´.xö~ÕU|°S(Z‹Hˆ™¯ù„£: ÃÁÞ]c|x¾eƒ•«@�pmE?Ár@jŸ ß6ïÔí‘ÞC©c›ªJuTSiFٓံã>YÙbèÑÑL=ôæË¥ÉÞH”kùåu_¢zï‚sÝؤ�XŸzìA3}ºµ)hhÐÂïè>”ZÏÂˡѶîc"Ú{­Lôh>|uaOާ‘_tW¨æµIHcîRãA£•~*ȾÌÖR (–¹^!D¿ü•&¶¹iutÀ<þ°¾žIù8M¯ìM¨jü늌2SmÀVc¾×F¶_ AWƒéæ%sTi G¬p�u_ ~Tfe¿�G’:µ(ñâU®³Èµ%¬G$ŸÕ–¹NÀ@Ã/›ø÷!¥Ëá‚0êÛÇ�w½Ë©x÷qÈ€¬/D(0n³jËBˆ 9Р¤*O8¸¨¨ÞÖÕMT¸’˜P‡»g¡…¹[6ì9`t‡­”(3–Ê…ö.P³Ã†ŽïÓ� eUÛA—òT#ºÌà&4Jíz�ÛûÎð©LòxjîLµ®â]2)¢Ž}¥ ;ô;½ ]·CëŒ=ïBi甈iŠsr)G|Çßaogȵú�¦‚^nú¤X£Šyg ø¾ê@rb#Û6¹¯—4;ý>A»§C!RµDArw¹ø1ÆàeyÓÓ×Y§}Lè#øÉ. 6•¹jw*WÚH‡è|9$5�ðz½à qžjˆV>¹Àëq{A.ëä%Á�«ßäÔ¬5E52z™¬¢p^^ç¶Zý¼Y­‡ôQ_çIæV”Š 4JÅúíc)ï5ÿ¯tçóÕ�ÄuŸ‡I‡`‘w£ÆE‰H¶×I³ÒÚèÞÅ>á塨=äŸSøÌŠäî¯N±v*åøJò§½q�×í§CÅzˆ„‡4›s„”A™ gBÅ«ùú4A¦�Iwq›Âo›Î²YÀ­;øÄ¶aP‰Ì\4K�ÿ×Þí”îe{-S)�fª.¢¦­Y)jÍ¥^-²¥Óo6ßqBÎFâÆrbnMLÙë� ¤²™1T*fÌëd�Üf_D‰T'¡ Bß4¢™‰äÜŒ¸¥}¯6ÅïŽ÷V´q¦¶Hº«y#FüL#¬áªêëÅk\5ÃÄjÚÑùl”]®«> EÂ:=W%½^m‘;•PŽ‚}kÐnrw ˜„²:²û¸9veë ²*Ó€}6ÂÖE¤ _€šál¹,q'Î:ÀÜÓD Ÿ$åþœ]ßiM4“î Ìz.ÝÁßr´Óš)�L¥¡áóšä”ñvÍ­A%2ª8êž2²@ØÐÆC)D!·÷#Vi‡Þ( s¾Þk©ìß­åð$UE—åV¬Èyrq&Ü©¼h×/«¢ LÕäèovO—bèQ]+´«lŒ$ºûZþ>šbÐæÐ£·º¸?¬u—hè¹vi†èll†ó¡ËœÐûå¶ { jÍt¾RAÒÇLQwŸ4Ê=/÷2átC“Àø®ÝIÞ¢ƒrŸ”ˆŽÂhuñ�‚¹ڹƔã¦â¸1¢ ¹ÐA×”'©F€B¦§UŠK¡6»;–ÿÊ®³¬®^&Ù k-�š$ÜÔ§—¶ærBiJ1² Ð|ê«íW§â‚Mç¢y·gÈ�{#S`ñp†ôA^É£bøEïw ª£¨IÙºlç=›jÔ(s@×'!¢np–J~®V7�fºûW9nòJ-�y LëÇ¿n³¾´Â‚ÛÈÁ‰Á=.fÔPð0_­AÆý ŒÈÁ? qQÁ–éÃ5/ @\óÄ›Å4UïÇ9ïäaÐÀ)Ü*2q†0ÌRÅ‚fΘóÙ(FÙ±Ÿu*]öw¨l ­$�sxI¬á¾RŸˆ Õ§§`�N~Ø&·‡ =k6øÊwŒ�×6‰v,³t߈쳲vË_WŽ<á\G*?Šå¢³ÆUs•ØÊyû21¨kÖÁbúªJÂ÷”%îæ^.>ŽtµÑf‡mŽºuG± FÂ+ï$˜¢óÎM 7†I�õžÚd­º~8 bö§À²¨^ªëSÆBUe_š•²ÞœÆü˜ý/—$ï;ù¿YÅ:§—2¥—»\¯‡qùøúØï¥´Žò„H4>îC¦ô?Ýdѱƒ}®' j¯®�c¨@(«6¡�’„Jw‹^–[›�à C ã)Sbè^©Ã*ÀóÅ„;µß™lbè\†Ò¯¾z¯ ¦Ÿ#O‡¾¢Ä¶9ް‹‹,¢¢Y¢Â`CF#NV¦_¤Ôkƒ_[%û41jTæÊª¼â ~èæŽÌ€yƇé8ÏqW�°‡¿¢ñò†Ë5„ €“i%0¢0MmfU³YÎjƒ^ÓrÙn)îÕO wMÑ =›04wÙÞôkÛÅ�Á̆! XZu#Ê2�~ws¡ý}ŽéëÀ«£iaÿ@b[3!¯¸§˜#ÕêÏÊ_m§7� ŠZ¬§³¬i©úq<* ¤ëùÎÿËn(\$Hiw¥¼Ám�0¯åZ�V�þ§ÂI¯Á T1ÄþÇtUÝyÛ5Ã;ë,(w¨ñܸe¡¡óöÜÄoÅå-ôVvÚ5œvÙ2½^5úî:KiMÊIè€`—ïw´Ö©û@d"ï9¤Uf‰3®e6D¢ K¡�WÐý}ÇæÅ½rÖ}‹ÔЬ�CPæ½qâ—è8˜ÅGªKš[‡t£ýx‹"P²åò‡øNÂñC‹.cóY1OÒY1«%ÓFЮüäàÓ¥HÃ_¯çiSAߌH×ñuV`§pF:š ×'äN†‚17|³> E¶¡p5•0²Í”á¶íWI“«lÎûæ™^T‘Ä%U4–œ“ÉØcrôJ$àãÛûAï�þM,]ó^óá(.®–¶,†ÎÊX§¬§«ÐÛ-j®Í*ϵ�ÜôË�XÅ^ȶު*ù¬Ô¹z#¹¯ <Ül�B´ëîóºÖVô‚øJ¾4D„.éî …èàŒ:ý—š]�Í’Æáþs#g¯ÒÓª¦\¸�ÿÞ ¿"vkŒeV§¥'Z€Vß-}EŸ§!}¥Ûéø&�hNåÔ�[+ZèÌJ<�w‰ê¦áÏâ–N�DwdöGmI›.ã·Â®¯¬æº)ަGºó•ˆ›ªæ3¡Ù ]îõ¯ïó}Xì·‰»G5“]ÁÙ &•ôÃÅ'”{n—æ@Ë(=œUªœfšž¤§@óK.Uªe°ô⎠vÅ1 Ý¡9kqZOö[¶Ö–òV,UÐõï ŒÔÃ&v›U²Ùí¨v¹¬}¡å“0$eV °÷'3¬_Es¹qÕ îðÕ Ãtçû¶˜Xm‡ô§¡eBmÂÔ“ô­r¤°N�z %¬œ²ƒ‹„ÿ¹”ÛÕm‚«#,ƒ9¯�Ò鱃)Z�?@J2KœK âÝ5^¡Çûv”“¸EáG« *X‚V_!'<=‡Á öI?E–BŸÌ¢´sYÕ.ꓦ¯¸ÌBïíg›u•¤wºú2é…s­�±ÕÓÎ<8ž%¸+ó(Å]ßÌÙ×ç[––sMCP…ïX]AŒ] fpÀX¹Ö0¾°5‹ÈùmtËQÔ¨3×GF­¹9ºÄ^­iVFº¾Y0p­¡¨;%G@Å4‘*;ôÛ™ µ�¿ M™oYI‡*ÜÙ;ŸÌ7“çBõ-=’Pë…úÍå–'ÎÖû- Á>QÝ©¶ TÔ"QÄè^†à rorÐ9ïjP¥ tÄ*Þ^öîϪ!ê½?[§Dú|BðÔ qí]¤lÀç+Þ-ËæEóÀа­×R:î3G²8é$I”àA­ÊÆYˆ0{$_ï5 »vŒ�~¸^Òu* 4U.­“A±­I´ÁMëR0IÐÕÆÞ«‹;T]x¯äʧÇMœF4{z UQŒX"[H&TæU""\± ÜøÂ/KC¤²e ×Ô¦ˆ”�%[»âªùAÐD˜fòá˾˜ˆr�ÀÇÙÇ ÿ§ã¤þº¾ L³=¸j‚wIœ`çv.Ëýï°ž¾ê8úàéŠK×Ö¯�Ä¢1™ÐøúnPNÛŒÖMãUd)ù̵u6pœ~.èK´·9j9Ϥʚ swå9æJà°Ã™Ü[ö™âËë|wZS³â¥ c �&ÔLg©›7% eø9O.Úß— ïN Ë�ˆ>ôêîœâ¡‡Ë†¹ÅÚ}çÓõb5´jòݦt*ð¸#«éð³ŽÈÕÅ¿îÅE´+^¯W¹rÍmh»…|“9ŠÅt:­4ó_¸j¸çãÄ‚¨T5M98!”¯@asö–'h¦?ªðµ_¯+9u—ùh4§Ú7q6�î�—#Uhøóf\3›¹ðzAX]©ÐœPªÍxsÙ"9Êlº»ò ¦:¯S�^ë\º×@z6þ™ì&Ðy·Rn ³¢.·Msäﺑ¾–ÛêØgóacŸÛÎÌBˆåYiPW-9´Ð°îœ&uãøÆ«ÃÒ–oK;ˆ7FñE¦�ÃùmRZ›–÷ì­&•¸±õõ4!lêßû+Oµ†Ïž læÊgãZgþ¤%:ÿ¢pßNñ•9"~lÿmÞÎBÄýÍÊr­YÝ7˘XOA÷‹BQ e×ÖÛãÞq�e³—ѤˆPó„"Q牴V‰6³’^žvP›W4K<혵6¯šœÜ­»ÿÙU½þz°¡}mÓ‘. IQªŸªùZ$ªùOH]€,ŠM…IÚZas ÉK7i¸¤ý’eÌÓ˜ÇÁ {ÏTèWÞŠˆ ¸{sÐÿ©³6Jc> .ßübnì9 “àJß{Eq»Ñ^BÒ¸#Ê«•mD ÌÍ`˜}%u˜µûŽÀ }ª†µ«¡¨Ì|zת#ïbxúKø!$.‡að:Ìã½—v÷ßÞùõPúŽmËäPõõ\´³öTK‘îóÓå/âäölÕŒ­jƒ_uQÝrÑ\®ê²¡ï¾ aŒ=4Ø»r²ŽÑ>y–!/½ G·Z_@ScWmïPËS¢l>�ºùõéèQ›¾L©ºU𲍀uUîj´ŒVÿ�‰úë��ÑZ²iݾ»Wô+%A‚66,[| –9†×Jªø+Z6´ñ–€Õj}#Ò¦’Ìhî*"G=�÷†L�Q¼uEqÑ QâÚ#ùLã)AtÒL�=Ÿp¹ŠÎ©Yö—¥ïB³;™?wz´o†[»Æñ)_ëY½k¶q˜§ôfU8€+`³›2Ð Ëoq”˜ B9H/Y^ˆÈÔV�ð €ì²DÀVÞwìÆò³oª÷)à ζ{©dÔL#ƒÃ€Œ†º‚ÇŸææ’—I]Jh+ðmì_·+g4±ß_cYÝÑ9DwÎ+úkÚҬ_·Ü–Õ™V"çãÐê‹ôWŸÊ ]Ýú .Ò¥àNh㑤²nµÛ(åG²�‰zÿŸƒÆS-{2ý_µ¿9V”‰èÓ�ïŽG”y�뿟kZrîM´½Ã!¨¡ÀºMár�ÐZVz�~Ë:Æ¥ZºÀÍqEL¶+˜U÷I[AóRÎÖêfØ%rã“�Ü�0<[Ô pâ (îñ‚¶R•£ê®gš —y­ÕÀôK úBÔë>±�™ŸBȉ0ç "W$¦RÇÏôëŒóD˜Q�ž5Ùº{C”yJvùs8ºs²yþQ8_í×êe¡ã:í:L„`Æ [@tt °¤tM¦Zƒ€zÖkÌá°�ºv¥ºqR’oµxbH)ø‘V£ìœ¬«Û À¾‰Üúr¢rßlƒL=r¨ŸsX>^QÍsv,QŽÿAþü‚oØjß*žƒ{9,æØ–´=`ŽØüR¿á)±f€YVÃ"–�WËÕ(V ú´åxå{/›‚óå ó«3 :x�Œ SHF½R˜‡À’¶ÎÕŽMÎÎë8É-ÛWK¤UW¦É ô�ˆmäÀÔ3$`i< &Ûeà™ÍHc�\„¦kž¹í„îð(GyøÕ0\¡þß§ÖºšŸº�:òÁÞçá-XlØpŸ³šh‰©R  ÑËSÆ‚!:H;�wãBöYȘ�ú:ö©: ¦ÍÐZ‘Á•íoiÚÃÚcø¤s{Ö�w|ç"ˆ† nOsÂQø=å> €ˆ*ãsÍ«8K‘i¦•#|u¥þ|D8POÎ*›Ö@°¯�ö~¶å>Ë `£Uô"jWú°Ê�`tä‹‘èó~,Kµ˜G!C0ëQJÊý•Ì·ä�G…ùu<ÎÜÁ(5Ã&¶�$!8ôS«„ tG/?‚àÕÚZ°â éqXˆp!��xÈ}.„C{”u^v43ˆå¾Ì5ôöÈÑUÀÎæ… YÙZ…àóéÌ_3£{—’…ß:B0:Æ ELÌו½G–QÈZpjýŒUÈY4i3_-ûÌHOØ“2iVI&ú ÛjBoýz*a·Ý)¡mZ#êCK±RêõÁ˜€‘³çv¤—Öp�fƒ;Dª5šÔÛbr§±5¬ŠL¶:Dÿl«9aá'X‹yó½›Û–sý ¥­QBrVu9h–Zƒ�ÝÜÐJ f1Ý_ÃwÔ¶Ü!ðQ(Á~¼ôDu„Â%„­à¨>Å`i˜åt|Œ´dœ ½ŸÅÜõd5°í<90¢…[sö›�8+´Û„úbKÚöÆkrýÜ�‘äÁ4H{�dœÎÊ5:5"Îæè7üPɰŸ»#ÔÌÉÄg瞇q!œN@´„ïùªe&KY-³1G€·ÔÇLï«!ò{íL «†ÊgÝ™iºqïöP9šùmV†@έ×z\Ëe|�EžéhY±ì™˜�êÁ*Æ“ëf‰¿·‹Ðí>hü·ZH{¡]23ÉÆ›¥P ^âÆúãcÙ�æìZ×u¬eEq¶+-kY†‚h1Q?&'¼ü„#¬Ñ7—¯ 95UÆó}[¤-3`Y¦|tKÎ:ƒÏZàd|¬Õ›°‰b¤›IZ§˜jÝÔè¡o¯ÅtÔⱑ;ìg•Øü}”éäûì!”¶¼Uãµ’K=µY¡0íi­½ ¯ÇxZôNÖ0Uú. ,›Iƒßn1Ÿq¼¶‚ìJí‘wA ÍU‰ãd\•R¢¹L££^_Ô¸”<)A ÛF¯¹QÖÓþ²;ÀÏRböËS÷È„Ñt Éí —§ô¥×ÌeO‚š¯u@ê&•Jr=¨æÚ£Ù¶Å³,x„—¦*äÍÚg!úsîx¼?=±;·7÷ã?{ê¯Æ¼×v›xKÍ’xÖ¿(zÞlëhÄÍëíE |ívGÁ® 3j X9xÁhÚ˜]�b؆©ÓíÞEs‘°Ãz7PÓø¡Ž&Š CŸ±¿5ZeB ù\¹e‘ý|¹"lQÙ;e‹n+Apäˆ ±Ëµg{½-Ä/e„I«³ <äwdNÅã“êx±Žf±9§TvRغè¦åÖa1«¬¦©U£¯¬ÖÏdD];Y«èt4èð*u *‹Çâ*D„Ô™btD²“™›º:7P“_ch•Ókòܶ¾A©�Ö ÷dëFm~·*kh�›þr´ôø¨²T¯Íð…¤)+zÕ“I^)ÈõÌÆ˜„Õ.†¡zh‰$W�júÊ×®æˆR�ÏøõqEt[¯/S.u‹Œ¨­‡ÞEcÀHéhÑ^‹4U³)‚¾|béæ±*­½§·è,«ÂÐbŸÚ¼Û(Tu\/¯…ȱ³Ê^iÓz”][°ÞYŽ)Ò¦xï"¦ë¼¾Ýô,Üâñu9p¿ éþM«£…uªŒ·<Ãù^O´ÐZ6Y%|�º®à0€Gi’Å"ôAÖsKp¾&ÇÔRYA4›Ý<á�ŸÏàîž-ôëãjûy·(!¹ŠS£7¿ G”®my{}¿g~é@žAĆùš‘5S{ÑKìÖ6Î/é`{•ñnO|}5DÑŠL3+¦Ó‰}ýZ[ éºÎéV»¢Ùå›Pݬ2z«ÕШ ‘¹„нa‚¼Pú[(¡E[GÛ}Âľ°úcš0„ÕW�ʳÛ÷ìà˜çQº[^F<Áʘqïu}È�”)e¦c‘,é\}ˆÜè¢׆� ”µϯèüzDt_×Õ’¦Y!q�èdM1rN6d�g.®˜L¦Ô/³™™x›FSFbÄxNž"Eè< ¡7¥òF·Uû.½7K†§âÊÖÜíÇu=×µ]õ�+Õ<“Îññ„é4™ ë&åx8+|H�.ˆ›õº£Ül�çóf–÷¾Ã›¹µö§ï+³zöŒÉ¢gØK%&/�ßs9%UÌvêDõ�×g`qÉÑi{ mÍ! «øeüé¼Ð^¬Gçj‚NÎÜæßJ'<�G$ãl“õjvçšáÁ%“L³˜ ÛËkæBòp/¿Ýx­DÜP›µ ئiˆ·e”ºC EUüMiR~y­Ü…Âbt½I»a˜�$̰<Ãnt�gÍФøy=æñq¦†|.�ìݧêÞŸ-€Sã¬Å£¬·?“7ÆØ0˜¾gÎŽpÆ÷åo1ÿ´õþ¨öá)¾À5ç ‚[åÑË}?M¨¹œ•ˆ“ˬ5K|:¸™Áx 7òúm+›Õ&Äø´¾Á†ç2 çᩞáœTv&ÓÉhÖ š–qY»xω«án†uøœªä.Ls(_~¤YƒÚ8wÍA£^èrS±Óc‘RH§XzýµEí¶®­…É�uF¶À°Kty¢ñâ0'C çd7Bã9a"â€jÊ׌_å(Ò~â|Cð~æ³ß©Á³–?z‹Æ«éÆ÷;�Vq¹=ái�³íéEÏ̬ôZWØzߣ8'ý¢ö?"ÌýÕrØ’#ùù]/Rƒ²Ìm6G=&ŒgѰz‚SniyQh —ä4ð,TÜÅ×<—Gú%¨xÊ—. àåt™àëš0zIØÈå€ñRá,G×x*åôs*&ÌXo ú´Þ¥9ÓjŸŽ h|©˜Ò±Ô#Ú0�û,M.Èÿ=E´5…�…8ö~X0ÅQ´‘$&É×k)¾Í²þ»ûŤínû⯆8Ä®„]ó5¤âõшHfÇGîÙrãE¾t9+)A`P’ت§}Ùíî ¹Ýz7î8+ß"‘»ñü‘…TßL$�ó‡Pbo7žj{óÍ·™R$Ä#=³d ju÷ˆÎóTæ Šx¾…w™²³†;Jr¨Å… ﻟÇâËžxh}š–“©Éˆ……ÞçKkLפ"Q&PÑÛjù¯í²TqOb$ŨîÔÖƒ9P·PõÞ—(çé†kV*uާ¼.’pa®h áÄk– ¥zˆX ÍëõP`‚=�òèâBû1‹:B ËríÑñÁ)Ë?ÀCÞ¤dÊGó0¾#ä§L¨>#:û'¤ˆÍwÊ'Š‹T¾ëBše®¯¿<^‹M¹IÔã+{ì*Çm3yÆVr~Áòü:ª­„_Û•Tƒ¼Ûª[g£#Ï˽­_âå=Ê”ÓåÎé‚׳DVQRºÎ­íóTãßÝ=5þêãiÒWf≶ý£ï€YÅÃ18EG®Csiu�ªhšåy  ·úÎr~ž¨[¬p£�¯•ÿê°á4/RQ±á¨Ä4¬Ö§îæQ‰³ÀÒŠqÂÏZ)d?Aˆٹ÷z…‚Tqã“Û^º {þ] N{•ôzH/ô„Xã´^¯:Ÿ3t¤ÄèþŠð„Ê@ra+Zh^û•lȦ…l[hw:FZÝRRm‘Ì޾[û4ßh0™ZJ:æÞe]ÜCms¥‡ëM-ÚBmj ZÁ ½S„ï¼ÒC×Ö…Pì7ã©ÊR²§[³~ËÆÅJ½F;©¢4/›ÛgÆîÐ×°ñl'æ.‚㤚­¹YöÈj{4Ì…fWŠŽ§× Id–¢‰ }™4„BYôE™²•=/^ŒÂÆ,JØ=áƒêæ!§WªÒ"J1ŽR£f4† i¸^µgÔÀ®�Y¼¢9÷OW!0ðèÍünèj®­ ˆ&g¬”³›»¡ëbú²åæê³ûÔãÞw…E9ê 1”õ̇|‚ŒR›GpÇ!¨bF¸èy¥g¿ç]ßoU99ÎÌè@”(| ¥Â¯gË�ÆçÅP¤ÍAUÉT’G±O¯\Ìýó>|=%#É!H²¯ôÍIÌÍκ‚éN.mÀP(Û4ƒg7èÂØHáÃgã|[fm}�ƒé�HüŽ.Sܘú¡àµuRÚL'|žÕso)yáÝ[à,´ËIûjDS[ãzÑÿ››áBðÿýj†j/ï޳PŸùÈl\×ÄW„¼í;Ôè&ýå:vV‡f$fjÚ9t™›®KÂåÎ×þ=HSb<šdhEÿ¶û6îx 2òö@ííéUSß¾ñÛ=†à%;½ €}‰ LÔ®ÄfXmùjÔ‚™Ð4¿c |HdÌææè](M`‡»ˆ¥l\}­3çוÖq&$5Èãâ48¸WÅH.«E3ü€F¤bý¤x4À¼¬Ëˆyžž�èbŽÕ úÇLo¶•ÿ8~“ñZÊm@ëÙf GXÌê*ëÛè*ÏhìWë’J5ñ+NiǼ<è*Þ<,•«ÛL�Aïï¬Äå¿Oi½Nw2æÉ#j\‚¢Ï!‹/C#ÞÃÕœ;è:¤GcDŠ7”Ò»ÏB\×u¬ƒ¦†7Ö+M£F9Ô CS23+e¹¶q Lß$@ ß™/¥,F‰`lW °«9ž­@»NgI?[½óõÜÍ_Ú¡qåJ ã4® 8c¼Â9xÀÑá;k¼c�¹èf&PWXñiY²*ˆ 9å×Àõc‰gŒíË�<«ôb¢iÉ~­/¥¢� ÿˆýN#‡Åž©(& iÙU¶‘NcIЉmVUxm® çvD¬[D<Ì&¾Gïk¾¶µ,^oåa;—Ûˆ11:HŒ+Ù5èZOƒ 6”Ëñ]béŽR€ž­¹B*‡–X¾Â¦\s•~OLì•S¹¹UÆéO&Þ5¼ÍÝÊå-¾’_TL†/9x…žÂV.wžMâ 1Ívƒ °Ô�Í:/¯­2úeÅ»dÔ²ÎGOFÌ­yÏ5ÄgÝ›ö,¢ «0ÓÄZð5ä›3­MêÏ©M+Lup¦ß\q‘œt�¬S Ø �|ÏoÎ\â*ïA@)ÝØÅ`‚åL’wD# gT†`¥Ý´0(<²¾ÖÜ¥I2Vdú{4CfççúU‹:#Vu×3ý^}×·ÇÓ-š®=�ÆÖú:+%9ˆ¹xàQ¢Ru²º‹�ÍíF+Ô&{ ‰øö¬„©Ì8rø[3š^Ñ»@ƒ²‰€a²a†#(¥±8 첸ˆyaв—ç0‚¥F§g÷HI1TL›9[Ž:vsfð^ݲЊ¿vžÁZ´8ÉX­PŠž÷c0JÒ!ÞÚ4¥I­[7–ô‡¼ÉÂÎ(Z@2z¯Åcw`š=Fر]ûf╹FñßÀÜ=™àõ–ÒГÃÛ*„>X]”Ç>ˆ:ì:Ý/VZ“¥—<æëN¯ѺM‰¡áKº©4%x0Aè½$#T½!Óp=¨`Å`=§¹Ó÷oèù‹5×àc¼Ô± í²Ê¶… «èØ/øž=¨êa>!tà&wÃÀùdeCX(“«—Áéa–�&ÂÖÀÑèÜqâž„ž®mƒS¾ãqâÔ>ž›,ô‘ªr³.#sjÝäìmÊ×)lI¯sÖ³ÊT  j3˜(AŸŒcŸ±0ƒ1h¶RŒl§ªˆËð¤dÐ  “nþ_r¯ã£ÒëårH‚�$äY ~Îob“ˆÜq‹b¶T¿ºË2Tè Ýh…$4ms]žåFáó-F¶"mÅINCf Vd¬6ìz¢c‰öÛÁb:«©yG@ª;µC =ûâÒÞ˜<+89 lÃô1}Å“Ã\üròÆœ ]’fQ£´YG{ØÛ(¶Pu}qe†D.Õ$rˆ�óô=£%g<5Öäù·*&Gs°ÓæëœµAm ‡„u7R•›E ñ€)ÜX5¢åµA¸ÃþPÚ­ð£xÚóÁÙHâÉÝ—³{¨ò[ob®µÇq¾¯£ª8Hiws¤P}�bù\$P ÅÁ#m¤¿Ûû¿æ7iœý`kb ˆÏB¦Wª Ò]—¦„¼ ÜAÂé—½(±îC 4BàQplîúµ� yP(u¿ù-R¯Sc!ìéAPÅÌt+ <ª¾in$ÆèIú*¯Œ©½m<‹ðf‹Ð_îè³h±¸’Ý¡{L²®¡Äë© g)#È‹“íc œ®Íx¾ß#´?=~ôãG=Ýë�àJhß�9 7wý°Íiž~•æ�Ôv=&y, Bv„µFK Ê£îÖn¤°švCL÷-˜ªRª0°Ð1UNA)d¶Nƒ¼y&u»|ÜÊ¥< ÍÀšnâš$§Ý¥zØÝ•á©%®ïq5æ©É¦�Åt@©†.ç‰ä½¥yÉš^üº�pËgÔG^öø4…ð½~<@Eê9 �yù@ä´•(|kTvŒ"ž­§~¥«Oå§ �eˆä?Õ"çÙñx«z\†éàábª¬XŒF]hè¡ÚQ¬™"R¯Vv3ºoOîžb—bîØë5•‰Éz¥i¢ÊÁz³æÒ-�vìA‚³‚¬ pïðrEÇ»g]¸<¢¨×"xL©¯!Å„"?M“ 9Ô"�è(”£½(24ôæ×kí&bj¾‡ýJõàô…U€å5£$|»ª€ˆž«Ì´SØ£ªLvÕ^K �‰h†ôKTG˜{¹;ZKGb{ƒ!ßå|2 $±xé1 Õ'êœÝJ~ á‰Sc üXýýþRUSbœWhÁ”dªeh“särDª4ÌÍ]¡Ä„‘a’ìÎæ»…yo¯Õ¤Õ";2ëW�[‹w†D E‘F8ž,ØÃL›“Z!¶ç$Ï«ÇLdn%Nu}Kö±27‚q«t§Ø"ª…ìY~� Í<ÐÞOL½vYatÆ>aß{3ØáDOIK%rQæëmé¢ ~ìS2ö&”yF1§,×15}ðîþz¬Åœó(šB-aÊ@–åžQ%7ƒ)(îÃí7k„ YPÊfØc5GFê¶P÷XÊQíô!¥ÿØ«~ÍhQYB Í©ž üâŠêÐÁïal¢ZÞOÀU­Û2‚¼{ M“j¸‘ý†§Ô*<Ì„�¾σI!]³< }Ä¡mz2úÞ þÂ*µ˜©¸{y]õÈQDù­ŠdB„ªuwU.“ÝhÍäG62q\��Yw÷fÈÌä¡Å“Ëïž\–h¶§I¸=­˜ëCJÙ™,MܦGÛ^tº{F”ä..mWå°z<+îfùÛ³Ô0å¥GÏ…;ÕYÐ.g9^hw[ ¹˜Œµ¥nÓéÑ– ®ôK �è[ÈŽÌZm~¶6ÒÜ<„Cp‚‡”?“§�ä¼i\)¤†e4=¨²hª<«ÌE Í~¹Î!Þ ÇÀ\�*éÐÌõ) U)chÇž^ýÕ=Un¬ß ÝÿåùË¢©”ǹ!†x”dÒ‘M�ú…c×ï,½"{Ú=*ÜsÏ¢&”$Pº)ê=Á½xô*Ù¬³M\gí—I ¸�û•ŒíYUl9! ¥³t ÕÖ±<½­ÑS:’�JÖtň�.ïF�Ë7)J›‡æ2#\ž6ÖÙžÒ)Ùý˜X=^=‡F7å÷´[ˆ_n7Ó»"Äšƒ@LWPk9W\¹^ñZ.“Vuák¿à‚©Üà,)Å´±"ï2ݯ›}=PSòÑY»-¢¼kZá}6}ƒ'f©3²„u¡ºx¸™ºÞ~îQ}�ŠE‚�•�^<1®‰Õ“úd7f“™5 ÙuçþÕF4 õ&•»ûÇ�Jo£Í@ÿ–¾ g Öî×x]È.nJºDH\híºq²hjm¢|êcô@Ïä¨éÅ�Sf�,·µ'ªåŠî/7Í“eÌJQyõ5ÏÆ[VÙ8èœV¡v(4[aß.R¯Öjžy1|H�]‚ÛµŒ¥×“ULM^ÅøßžN´:b™÷›™¾¥N®Q•éÄÏ’ÇìÄ4Ìû¦W¦*%uc3¿@&r5#• ã£ñVèOÎo�{&JIÌÅgÚ“©�mDÿ)xsR S÷Ð }}I°ÞÎ .î_"i¡òZ\Ùv¦Lm)y¾¯q¬ü• Mf�Ĥˆ¹Ez+“aFÌyÍ—‡‘ÕhTs§õïÛ¨A“*²Zë:ñ[^~òÁ‹»khÜúxAÖxØ—ÅQÅ™ÏdØ5’¼Æ”oæ «Ðä) ×3&Á@ îç;‹%÷¹§G$€*cG1°9Eã0¹/·7Çù\ëÊñ(2˜W!«CÃU}~å]œi+Ç qÒ4��Óf¥li2_a´¾L¬O2}k¢ˆãþºˆ¶Ö–áNQjD*57×m2|fü Ɔƒ?v(–~ÿ™-ªVCõûªù�£Dn~ÙŸuã‡ÑO`�)†§÷m¦P/èdW%–êøü yxÌèÎ}ie«aUÁQO!„Û@@^ –¯‡˜i—§•Ùi@^¯O¸àÝa¶)à‚KËr—¼»7¼¤W¶2iþÒU�;hSưЦ¬2²%M( ��&¹dÉññtš¼tÛ$¥§Ì:DÞ<´¨"* ¦ùºEd…Ë–p'×�sœo©ž`:É–5±c\\Ñ-Q¹Ü˜zöaŠZÕt†;¾ZÆͨ¬Âš÷—Š %]L ’Üajä¶C ëž—Îôñc%T›ÑpPNq×umÍz#4m^÷v>Ú÷ß7�TœöH²c‹€á¼Ü$�ùòèl•Ûéý/¯w§¢Pž1&nŠ¢‰Äen´#ºIµ^Ù3G&_^Ï%ìï²&­3ù„ÐF¾Úc³ÅÚ£iȲ.çè¿NؤÂT8Ð8.ÅY4‰Sj6‚™R æÖ'‚~�!�Ìõ¬ÉÊɾ�d¯cÀÔM|HNÛ?l’eàCà·çÄŠS±ž@'-PGÚ¶xÕ,G`ÍÑêVÆ}eCCK«¸æÉh«ÆdÚ:™@ RÌñ ~F7(’_ÿ˜F¨é�L@1àH£x£.>(¶þô+.„-\ȥ樕¾.À˜9!æaäe¢}LÛÔ¼š2vóÛ)ã‹.N$õI³XG`¼Ï F4®>[ÀõZǃ¿2µÁÌ®œ=ì¢XÀ¤šàC§1 æ’‡¹w ƒWC}ï]í�ÌyÀ×›¥¤?VbnÍ£žÅJ…éÜ£Rø +öÎ%ÐS–•jv¼È4äϳvÆßà·ÖƒÄäׇÄ.˜¦Õ–ƒÀB» T([ý-ÌEm/�ùκó¤Jµ’W¥rI-}¹ë^A*žÝII,ñ7’GXóulj[—­œ¥d&KŠjÝí™(%Oª¿{šŠt�‰òZk˜¿ã¨Îrž÷^-Â;ø[îB›±ñÕ›0—çO3¨=+Fn3'“1ÔÜØOˆÞö¼‡LxÀß±ú¯‚6_­0-|NüoÃï–Žs*/NÛkړîì$ÝK‹z_W°T‰[G ùÂÏ‹¹Ä»ÎZ|¯™T„n¬{}GaÅn)˜Îªê®}ƒNªÆ(ZÄ|¨›¹ãPÖ–¡† C­º’!|¡Hm™læ‰óù”Àb…B6q$ò»ƒÓäŒo–gšØ}YWh~ý8A ¿žÀ>)UÃC: ôÁg ÑÚFG�°ú­D öL”ׂݛհ¼ Ê}!ã0(jRn¨fà­  ¹“~æ3·I;3â20MtNâ–Ï‹•7 S6ê¸tMS¤1ž8ÏZè ‰/»µßª”ɯ8k5Qì)=Fñx@Ot2�Ë´¨¦IÛ¢A¤£ïÆT#'¨? Šc…l‰nX{½"²» „±¹m„Z~÷¤OZMJ¿È+g°r/ó'ÜÞôz&×ò‰Û=õÒm|Ô³ÈL‹:‚‹s›ü�MUx=’k°Ù)“‡«XÁÒØ£yæòΘG’�ÖE9²ŸµÅ:�¿ŠîyÔlzLKxž÷¼!øÅRpîÃ?¬•¯D62f#ºß<{sÔ"‡1ÈË NW6°p°!ÉêS­èÃÐ-$B ¹ç õ6òã9,ø[ò+¬Æ4v(+Ü´œ¶æ¼ÕÑ-áK‡}Ì<¶öϹ:Å´ â©d‘60Öb/â»y9+¹¬ØCŸ£}¥ âS3†èŠ¡Á‰<0:ŸÁZëÓg—Úæö:é|½^á÷MgaÍh"¯;_ϰœˆ ­XðZF¿Tîǃ¥­9GoŒÊ.9GŒY—9°ÝAþ¦�ÿXnÕÀ?¦V_3Ä{3¡ C§cLŸ�Ò]þL·ã[Lwíå³1gCÒ˜8}ˆ…Ö3í|Ww 'ÏõCTÿG|O¥ýµ²o±ÿ»w±{ôa`,àzKL¡ôbÕÈÒW\¾áˆUjzüz ´ŽFær"y[ƒÅ!y=œsëê�µcÍC[#˜�*0U¸p!~,w9€·‚mþ"ç.šÍ€!îÍݵϬ±Ól_˜’ÅÕ0í9ÕvÎêtn ‡Ç q({cFC\a‰q}›,ø·#ž‡£I#Ñå]…q#óé²IíTø®§¸=¶# U¶×º¯Ëð8 X«ËRå)„™ï Éô`r Ì‘1�&M ^]†¯›çèìV±tøví+L²KÃ%ãõ˳O=ýòVèÛ4ØS¶å)Ÿ½?[pD)ÝÎ-†l”ÈøŒ7Ÿ5ÊøšD3ú.ž½IÐ/b9ä¼V(JŒåpLúÎf“5¡Ó–È›Ž;__oª2 v¸Û ikx=G»E? ˆè-Óª‰2^†]{{ß1ëîZ÷A‘Vu«ƒËÊ‚ªXBY0çÐißÄWãü5Ï‘ÝC]8Z!LWS9]Š-Ú¾ÕI±ÕÇhK§ãj™âïÊRa¬ÄæÁÐ)ƾŸÍf´¬B O´v®ÎÒ5ˆ˜MWR3«ó SÒòKvà@ý«ÑÃm±zk(dK[¸¯¸ÎöÙ"¾5Ä�ÜXúz³ »h:››+ÛüXt‘©ÔªÀ¥¨ûÀŒˆ„ñÝÚBO´ìyž–òöd|ñ4ñ³SV_Íô”gŠFAϤüð‚Bª—¤< P.Å#úSñ¬Jš%ºÙ9“#\M6á÷,Æ Ìü(ÝYZ+Ó™ ¢d&ÜŒI‚HÑGTu}ÇŸ ‘Ëè$ɱÛUÄ#+•·‰¢¥pœ¶ˆ“Ž/´»W¨ß=9–åZ‰ñ†·;&÷V·º|tN7J&)f#&‹"LªæC È̺%îœ<ãôÜtö¨›øëIJûÎ2ÅT¶ò«]ÛôªeØ¥?�D9F€ˆn2ùrÖàlƒÀOM ~µª4Ä÷D©Ÿ°Òó ‘¼; J B¶v=by„ŒfF Mû{6Gö4’½é¯¥t{Ä‹c†îKUœÕ–Mù�Ù¬S«ýµëç"w¢?y¹6.–t¯K X¬ôT›æ�‘AŽ9 –9± #,ê\¢E¸¸8ó¢7ÇàIô_Oc}ŒâéÈÓm êµ{ÇÈ>ÖP§" Bˆ1ÁØ­¯„X5q/ʺÎÃÀ˜`ÙY¬n†ºnÝŠv²«SB”˜¼ Üž3�Pj§@€ì™z]=ùsíÚ¹§»""ýb«©…øóB¬èV Ó ‰Èp¢Péèî�‰’Ý×åÓ®‹›1"ƒ$Çpl�cjPEDÑ¥M$C£Ò�¿:ºðF‹ÓTwægN©G6ZpWˆºÙ!Ó�ËöùW¼öK©?SG¨Ay´(6%ZŠkY´iv�>~:»¥.Í p6w‰,ÏÈÍ5ªÓ֮ΡZÝO»¾qÖå)Cã(�Üe‰ã))ƒ#�Ú÷8¤³­KkÆ÷’ƒÓ‡àDò×�Y¶k·¿Rª{;–ZK¸p4)»ÁÐí�ï•{zÌeŽF²°¯ÜZ ºjì«n¢¦–’S4¾¯ˆéÝÇn>CQ_QŠnºð‡rEQ­�1´9¿­^[ž%úqÎĉ£2¸dG¡»n7`ÂuÈðua å>_£Ì„B>Êå¯4�±@óéð�)|Yþêou—×xZ9‚v4Âü–×È?ÍXПÅõe�,n‚¨r•ôÇ}ïžGG4Ê•«ß †èócbÏ&Ù©fîTV…g]H"Ñ@o�(Bû—`øR£ª'uÍ`ìgU;�«+ãúHÕ˜Éè&¨#*Ï]YŽ¢Fwkm 7MEÏ�¤¦�FA::ãVÏeþçøÄÅû ¯dVù¬îÖl�­å9d`t{ô{ž´HŸè$NO#KÛÕ Œo0êáöG¡lV+�Ôo¥�ùæb¸`:̓ÐÑ ‘·@M]¢GKvÞƒ^ �øׯXsàW´ywßçTyNßÚù;8½4•ÜÆèWq4.G/kà° Šä€²c;d@ÎZQž¸ M<#ªÐ!O‡eÄVÿ„*I¹öHô^ù™ªkêX0È•¢‡¦”˜€ë!µ8j¥ÃšŸ€žÃ�çsîó¦ï¦×Í6ÊŽn&ÉNR¥ÍA®38/ýݤ/”ˆƒ›[­>N4@Âeÿ^¢™3êªô±ÐAؾúK’ÇÂ|hAJÌN<.·®VÚŒGè¤|‚871Zèm¼V+4-›pTÓ áÊRD/�þ÷ .*BƺY‹YŠï7Eé `Ô7Ñ ½ªžTX9xbt‡j—[«êC_] ISU»;£n_lì$¥TÐ\¨ŒàÌÎIô¡V¶øø‰ˆPœ0¢®V †e¢óÐlÞéwÔ» =¶J£nçÜ%´Ó\˜£_hJ]²í>Ùá?þ4öµfhËŸVL>~å#>}m‰ã\Áï`‹²�~ Iå½ï}eóÉöµÆýéë!ó’õh{QÑé}µ÷¢³nu™íìGù~—ˆíݬ¹è¾‡Óg7MÆœ±¸ü ÷ÿV~yLX ôeÚØ"̼ƒr5÷•²pþï {ãd Ë�qM ûâùÖR h-Ñ ÔÒ¡ÿµÈ!%£è»wtD¨Mèí+ŸèŠ`ûŽz\¶\¶Vj­¶ˆ¶ ½}åÕËÓ=QC ãòiOt¢î?½m²±ê1^-ÕhØ—Ö./øD%ÖÑFº’îè³îÓ-÷¾á ôB½ï§Å'´_ý‰JØ'kÝÛt­³Ý¸‰¶l .ºƒ~‹,OÎ5‘Њh£˜U�[è®3N.$Oš“ É]t+¹hÈwȆo“¦ÙG †ÆíªeÓòjY_ =›D��`á:­õž$úvòáwiV¨GN$Àì ûé+¥ååæv/™UŸjÉÃêä�D ²g ¤Ä¢éò¸Ýðœ-€N`xœ)Pk>‰y…x”…;5 èëœl'u–ËDè«Ó�–Ù`�g¸I…•Ð ¸çnœ Àªt y8€µ±Ðq;�ÜÚê4µëö0HÎ dçgÖ½ÒžÒæ>ô¬µõ6͉B6�DA2znÐ7rú68µB³ØŠ‚“nŶޯ9¡È¾¢9¡È­¡HcÞœPˆe´ÂbhN(rjN(6ÖÎ+º¼bì3ç>1Ã5z™áC’á:Ã$ÃV›a ž�áë!ÃóÚ·¿Á¯íÿîÜË8XÙÎM:ôÒÉ iÒÏ]s†•51†ÎŽ�ªÂÀ:9±¾± C}rŽBÆ"<¡ARê® F˜«hµ 70®A{X»ÌËêžèº :+ãšH:¾iq2a#{¤Ù¥Øß<–€¿™Û¤­@›щ:,sÍc ø�%ue´Ïj û»Í¬Ã¾yli GzOr¹P²à¡¤gôv®Ùz�ÓÁIw"T–‚H÷@‘©x�@‘%Ôz›~Ö/œ}2ÅîÎþ³ÆÕkGrŒN÷zÄ€™šÀBz½¹ÉÛ1j‰³n5´a`쪱ì ZFõfüOñ¶%ÝÃ�nµ�¬í"ÆÞã¬yC�z¯[bÕ=4À�{p€3Ù[×°Þ'— ÿ¼†HòYžÇ‡ºÕW˜‡‡šµÿŒIMÇÚn°ãŒ³%6rÖÕÆ£†Ó;è·‘‚ ¸ËcúÊ5„L0.ÇòPt¶ÔÑúä÷Èi-N…À•z%m{UkN}h ÅÑPË‚ô2‡'j´é2áÅé¶o c#·§….CMÑÇZ°íäêÍ‘‘¥Ž«m²é¸:ô&h²’‹†Ð µjxEd^’4ÎC0Τa7],\q› Öcn/Ö�ïÂl†+Æ�Ñh¬âÕɲ ¸ Û™þ0°à?Ð*%…Ú ¬;›ü,ÈÙu~òtN6Û) ã|NÃáä'sU›øŒÍ…žlqO$³[�Z\ÈïlíóMÌÙ ¬ÌÄõº]ì ç?6wo *\Ö�rljôHhH5äº ¤wÍ©Æé�65Î,›Í· · £¬í-è¨nÙFÜ™å~8gÊwo£öíÝÛ¨Bwo£ŸÛH|à9¼]k»o§×áorÔ¾=q�2ÒóÖñ™i¸ôz}ú¬"{�E¯¶ßªØ7ªœ>7©{ 3¨üÀoæîˇ ­”Ö:´A^ïø|C‘PAT#‹o£ŠEÖKªqf&ô|`ðŽºÉÙÈ#ž$6Æ�-úDï¼Ø'z^»'Tï¼bxTøJ…oãÎj…ožðޱ(-wÌr šu¯\¤W䩉ì @’[G¤‰BYÛfÚŽ*yç‚$Ù± ªÛÔÙ±èåóX�l;. ìy}»‘~>rß|�9âùÁnÅÅ Å4³0ÇYê�Ÿœ_i~¾SL5ΔńÊ5vOT5ÊFŸeÀʘŸÏºH‰È²˜­·mç.zÄè §_>ä‰Ê~¨ª‚AÍj—“{¢ƒ&¢žo¶z¿Cx ­ÐHÅUBÏhƒwü³‘áÎøó‚Ü‹¦¤Y30òjrçµlŸèÚ:�êÜf¯Û¿+˜±ŸÎ£Ú_©ùS‹­tîhWÖn4€}Ð`Gb¨½¶^kJÙ§TšŽÏ ‹M ¹|̳N à~^l¤ŸùÜ©Æ"TË…‚œx> 5îÐO5:ã Ï—R䘟�(z¾˜NèB0�÷´<¶ñpr§u<ŸÌÒ­!Úƒf'T.Û#éd7Õ°K:ÕÛ(3mñšñž2›ï)óH8 ‚¥�ï)g¼§ 7¡£8møý/†QçtþÓ7[µéü'?³ŸkÏ´æ2rkÐR_¯'H g�#Y…s•®h•~Ñì'*W›OT±¬�ÛZmÿddµoõVëˆ ¥Ï®¦Xظð`x^'¬Oô˜yõr[EîN¯X£]oæŸhß¾¤_ñTä(¢÷?Û<Ñq¥7?щè"T ¢ц(¾ÃXCÖëyÆS†]…Ÿè@tÞ‚óˆÆÃµ\ãõï=O´"Úí¤µ ¢ØC5DüÂÒ‰èþíöò²ÿV¿ñ­QKF7°L.”ä( 0), axis=1, arr=sbp) s = np.apply_along_axis(func1d=lambda x: np.sum(x < 0), axis=1, arr=sbp) psi = np.zeros(sbp.shape) for i in range(0, sbp.shape[0]): for j in range(0, sbp.shape[1]): if sbp[i, j] == 1: psi[i, j] = np.sqrt(s[i]/(r[i]*(r[i]+s[i]))) elif sbp[i, j] == -1: psi[i, j] = -np.sqrt(r[i]/(s[i]*(r[i]+s[i]))) npt.assert_allclose(psi, sbpbasis) class TestTreeBasis(TestCase): def test_tree_basis_base_case(self): tree = TreeNode.read(["(a,b);"]) exp_basis = coo_array( np.array([[-np.sqrt(1. / 2), np.sqrt(1. / 2)]])) exp_keys = [tree.name] res_basis, res_keys = tree_basis(tree) assert_coo_allclose(exp_basis, res_basis) self.assertListEqual(exp_keys, res_keys) def test_tree_basis_invalid(self): tree = TreeNode.read(["(a,b,c);"]) with self.assertRaises(ValueError): tree_basis(tree) tree = TreeNode.read(["(a,(b,c,d));"]) with self.assertRaises(ValueError): tree_basis(tree) tree = TreeNode.read(["(a,b,(c,d));"]) with self.assertRaises(ValueError): tree_basis(tree) def test_tree_basis_unbalanced(self): tree = TreeNode.read(["((a,b)c, d);"]) exp_basis = coo_array(np.array( [[-np.sqrt(1. / 6), -np.sqrt(1. / 6), np.sqrt(2. / 3)], [-np.sqrt(1. / 2), np.sqrt(1. / 2), 0]] )) exp_keys = [tree.name, tree[0].name] res_basis, res_keys = tree_basis(tree) assert_coo_allclose(exp_basis, res_basis) self.assertListEqual(exp_keys, res_keys) def test_tree_basis_unbalanced2(self): tree = TreeNode.read(["(d,(a,b)c);"]) exp_basis = coo_array(np.array( [ [-np.sqrt(2. / 3), np.sqrt(1. / 6), np.sqrt(1. / 6)], [0, -np.sqrt(1. / 2), np.sqrt(1. / 2)] ] )) exp_keys = [tree.name, tree[1].name] res_basis, res_keys = tree_basis(tree) assert_coo_allclose(exp_basis, res_basis, atol=1e-7, rtol=1e-7) self.assertListEqual(exp_keys, res_keys) class VLRTests(TestCase): def setUp(self): self.mat = np.array([[1, 1, 2], [3, 5, 8], [13, 21, 55]]) self.mat_neg = np.array([[-1, 1, 2], [3, -5, 8], [13, 21, -55]]) self.mat_with_zero = np.array([[0, 1, 2], [3, 5, 8], [13, 21, 55]]) def test_vlr(self): # No zeros output = vlr( x=self.mat[0], y=self.mat[1], ddof=1, robust=False, ) self.assertAlmostEqual(output, 0.0655828061998637) # With zeros output = vlr( x=self.mat_with_zero[0], y=self.mat_with_zero[1], ddof=1, robust=False, ) assert np.isnan(output) # assert raises error with self.assertRaises(ValueError): vlr( x=self.mat_neg[0], y=self.mat_neg[1], ddof=1, robust=False, ) def test_robust_vlr(self): # No zeros output = vlr( x=self.mat[0], y=self.mat[1], ddof=1, robust=True, ) self.assertAlmostEqual(output, 0.0655828061998637) # With zeros output = vlr( x=self.mat_with_zero[0], y=self.mat_with_zero[1], ddof=1, robust=True, ) self.assertAlmostEqual(output, 0.024896522246558722) def test_pairwise_vlr(self): # No zeros dism = pairwise_vlr(self.mat, ids=None, ddof=1, robust=False) output = dism.condensed_form().sum() self.assertAlmostEqual(output, 0.2857382286903922) # With zeros with self.assertRaises(DistanceMatrixError): pairwise_vlr(self.mat_with_zero, ids=None, ddof=1, robust=False) # no validation dism = pairwise_vlr(self.mat, ids=None, ddof=1, robust=False, validate=False) output = dism.data.sum() / 2 self.assertAlmostEqual(output, 0.2857382286903922) class TestRclr(TestCase, ArrayAPITestMixin): """Tests for the robust centered log-ratio transformation.""" def test_basic_rclr(self): """Test basic rclr transformation.""" # Simple matrix with no zeros mat = np.array([[1, 2, 3], [4, 5, 6]]) result = rclr(mat) # For each row, the mean of transformed values should be ~0 # (only over observed values) for i in range(mat.shape[0]): observed = ~np.isnan(result[i]) npt.assert_almost_equal(result[i, observed].mean(), 0.0) @array_backends("numpy", "jax", "torch", "cupy") def test_rclr_backends(self, xp, device): # Dense data (no zeros) — should match clr data = rand(4, 6, 3) + 1e-4 lmat = np.log(data) expected = lmat - np.mean(lmat, axis=-1, keepdims=True) arr = self.make_array(xp, device, data) result = rclr(arr) self.assert_type_preserved(result, xp, device) self.assertEqual(result.shape, arr.shape) self.assert_close(result, expected, rtol=_RELAXED_RTOL) # Sparse data (with zeros) — zeros become NaN, observed values centered data_sparse = np.array([[3.0, 3.0, 0.0], [0.0, 4.0, 2.0]]) expected_sparse = np.array([[0.0, 0.0, np.nan], [np.nan, 0.34657359, -0.34657359]]) arr_sparse = self.make_array(xp, device, data_sparse) result_sparse = rclr(arr_sparse) self.assert_type_preserved(result_sparse, xp, device) self.assertEqual(result_sparse.shape, arr_sparse.shape) # Convert to numpy for NaN-aware comparison result_np = _to_numpy(result_sparse) npt.assert_array_equal(np.isnan(result_np), np.isnan(expected_sparse)) npt.assert_allclose(result_np[~np.isnan(result_np)], expected_sparse[~np.isnan(expected_sparse)], rtol=_RELAXED_RTOL) def test_rclr_with_zeros(self): """Test rclr handles zeros by producing NaN.""" mat = np.array([[1, 0, 3], [4, 5, 0]]) result = rclr(mat) # Zeros should become NaN self.assertTrue(np.isnan(result[0, 1])) self.assertTrue(np.isnan(result[1, 2])) # Non-zero positions should not be NaN self.assertFalse(np.isnan(result[0, 0])) self.assertFalse(np.isnan(result[0, 2])) def test_rclr_centering(self): """Test that rclr centers each row correctly.""" mat = np.array([[1, 2, 0, 4], [0, 3, 3, 0], [2, 2, 2, 2]]) result = rclr(mat) # For rows with observed values, mean should be 0 for i in range(mat.shape[0]): observed = ~np.isnan(result[i]) if np.any(observed): npt.assert_almost_equal(result[i, observed].mean(), 0.0) def test_rclr_negative_values_error(self): """Test that negative values raise an error.""" mat = np.array([[1, -2, 3], [4, 5, 6]]) with self.assertRaises(ValueError) as context: rclr(mat) self.assertIn("negative", str(context.exception)) def test_rclr_inf_error(self): """Test that infinite values raise an error.""" mat = np.array([[1, np.inf, 3], [4, 5, 6]]) with self.assertRaises(ValueError) as context: rclr(mat) self.assertIn("infinite", str(context.exception)) def test_rclr_nan_preserved(self): """Test that NaN values (missing entries) are preserved.""" mat = np.array([[1, np.nan, 3], [4, 5, 6]]) result = rclr(mat) # NaN should remain NaN self.assertTrue(np.isnan(result[0, 1])) # Non-NaN values should be transformed self.assertFalse(np.isnan(result[0, 0])) self.assertFalse(np.isnan(result[0, 2])) def test_rclr_1d_input(self): """Test that 1D input works correctly.""" vec = np.array([1, 2, 3]) result = rclr(vec) # Should handle 1D gracefully self.assertEqual(result.shape, vec.shape) npt.assert_almost_equal(np.nanmean(result), 0.0) def test_rclr_uniform_row(self): """Test rclr on uniform row (all same values).""" mat = np.array([[2, 2, 2, 2]]) result = rclr(mat) # Uniform row should have all zeros (log-ratio of equal values) npt.assert_almost_equal(result[0], [0.0, 0.0, 0.0, 0.0]) def test_rclr_preserves_ratios(self): """Test that rclr preserves log-ratios between features.""" mat = np.array([[1, 2, 4]]) result = rclr(mat) # log(2) - log(1) = log(2) expected_ratio = np.log(2) observed_ratio = result[0, 1] - result[0, 0] npt.assert_almost_equal(observed_ratio, expected_ratio) def test_rclr_3d_tensor(self): """Test rclr on 3D tensor.""" tensor = np.array([ [[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]] ]) result = rclr(tensor) # Shape should be preserved self.assertEqual(result.shape, tensor.shape) # Each sample's mean should be approximately 0 result_2d = result.reshape(-1, tensor.shape[-1]) for i in range(result_2d.shape[0]): observed = ~np.isnan(result_2d[i]) if np.any(observed): npt.assert_almost_equal(result_2d[i, observed].mean(), 0.0, decimal=5) def test_rclr_3d_with_zeros(self): """Test rclr handles zeros in 3D tensor.""" tensor = np.array([ [[1, 0, 3], [0, 5, 6]], [[7, 8, 0], [10, 0, 12]] ]) result = rclr(tensor) # Zeros should become NaN self.assertTrue(np.isnan(result[0, 0, 1])) self.assertTrue(np.isnan(result[0, 1, 0])) self.assertTrue(np.isnan(result[1, 0, 2])) self.assertTrue(np.isnan(result[1, 1, 1])) def test_rclr_various_shapes(self): """Test that various tensor shapes work correctly.""" shapes = [(2, 3, 4), (5, 2, 6), (3, 3, 3)] for shape in shapes: tensor = np.random.rand(*shape) + 0.1 # Avoid zeros result = rclr(tensor) self.assertEqual(result.shape, shape) def test_rclr_dense_equals_clr(self): """Test that rclr equals clr on dense data without zeros.""" # Dense count data with no zeros count_data = np.array([[2, 2, 6], [4, 4, 2]]) # Apply rclr rclr_result = rclr(count_data) # Apply closure then clr closed_data = closure(count_data) clr_result = clr(closed_data) # Results should be identical for dense data npt.assert_allclose(rclr_result, clr_result, rtol=1e-10) def test_rclr_sparse_expected_values(self): """Test rclr on sparse data with known expected values.""" # Sparse count data with zeros count_data = np.array([[3, 3, 0], [0, 4, 2]]) # Expected values (zeros become NaN, observed values centered) expected = np.array([[0.0, 0.0, np.nan], [np.nan, 0.34657359, -0.34657359]]) result = rclr(count_data) # Check non-NaN values match expected npt.assert_allclose(result[~np.isnan(result)], expected[~np.isnan(expected)], rtol=1e-5) # Check NaN positions match npt.assert_array_equal(np.isnan(result), np.isnan(expected)) def test_rclr_axis_parameter(self): """Test rclr with different axis values.""" mat = np.array([[1, 2, 3], [4, 5, 6]]) # Default axis=-1 (features on last axis) result_default = rclr(mat) result_last = rclr(mat, axis=-1) npt.assert_array_equal(result_default, result_last) # axis=0 (features on first axis) result_axis0 = rclr(mat, axis=0) self.assertEqual(result_axis0.shape, mat.shape) # Each column should be centered for j in range(mat.shape[1]): observed = ~np.isnan(result_axis0[:, j]) if np.any(observed): npt.assert_almost_equal(result_axis0[observed, j].mean(), 0.0) def test_rclr_log_ratio_preservation(self): """Test that log-ratios are preserved exactly.""" # Data where we can compute expected values analytically data = np.array([[1, 2, 4, 8]]) result = rclr(data) # Log-ratio between adjacent pairs should be log(2) expected_ratio = np.log(2) for i in range(3): observed_ratio = result[0, i + 1] - result[0, i] npt.assert_almost_equal(observed_ratio, expected_ratio) def test_rclr_geometric_mean_centering(self): """Test that each row is centered at geometric mean.""" np.random.seed(42) data = np.random.rand(5, 10) * 100 + 1 # No zeros result = rclr(data) # Each row should have mean of 0 (centered at geometric mean) for i in range(data.shape[0]): row_mean = np.nanmean(result[i]) npt.assert_almost_equal(row_mean, 0.0, decimal=10) def test_rclr_validate_false(self): """Test that validation can be disabled.""" # This should work with validate=False even with potential edge cases mat = np.array([[1, 2, 3], [4, 5, 6]]) result = rclr(mat, validate=False) self.assertEqual(result.shape, mat.shape) if __name__ == "__main__": main()scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/tests/test_dirmult.py000066400000000000000000000564121520735541300274260ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt import pandas as pd import pandas.testing as pdt from skbio.stats.composition._dirmult import ( dirmult_ttest, dirmult_lme, ) class DirMultTTestTests(TestCase): def setUp(self): np.random.seed(0) # Create sample data for testing self.data = { 'feature1': [5, 8, 12, 15, 20], 'feature2': [3, 6, 9, 12, 15], 'feature3': [10, 15, 20, 25, 30], } self.table = pd.DataFrame(self.data) self.grouping = pd.Series(['Group1', 'Group1', 'Group2', 'Group2', 'Group2']) self.treatment = 'Group2' self.reference = 'Group1' d = 50 n = 200 self.depth = depth = 1000 p1 = np.random.lognormal(0, 1, size=d) * 10 p2 = np.random.lognormal(0.01, 1, size=d) * 10 self.p1, self.p2 = p1 / p1.sum(), p2 / p2.sum() self.data2 = np.vstack(( np.random.multinomial(depth, self.p1, size=n), np.random.multinomial(depth, self.p2, size=n))) self.table2 = pd.DataFrame(self.data2) self.grouping2 = pd.Series(['Group1'] * n + ['Group2'] * n) def test_dirmult_ttest_demo(self): # The same example as in doctest data = np.array([ [ 20, 110, 100, 101, 100, 103, 104], [ 33, 110, 120, 100, 101, 100, 102], [ 12, 110, 100, 110, 100, 50, 90], [202, 201, 9, 10, 10, 11, 11], [200, 202, 10, 10, 13, 10, 10], [203, 201, 14, 10, 10, 13, 12], ]) samples = ["s1", "s2", "s3", "s4", "s5", "s6"] features = ["b1", "b2", "b3", "b4", "b5", "b6", "b7"] table = pd.DataFrame(data, index=samples, columns=features) labels = ["treatment", "treatment", "treatment", "placebo", "placebo", "placebo"] grouping = pd.Series(labels, index=samples) obs = dirmult_ttest(table, grouping, 'treatment', 'placebo', seed=0) self.assertTupleEqual(obs.shape, (7, 7)) self.assertListEqual(obs.index.to_list(), features) exp = { "T-statistic": [-17.179, -16.873, 6.943, 6.523, 6.654, 3.84, 7.601], "Log2(FC)": [ -4.992, -2.534, 1.628, 1.707, 1.528, 1.182, 1.48 ], "CI(2.5)": [ -7.884, -3.595, -1.048, -0.467, -1.037, -0.703, -0.601], "CI(97.5)": [ -2.293, -1.462, 4.751, 4.165, 3.978, 3.556, 4.044], "pvalue": [ 0.003, 0.001, 0.021, 0.013, 0.019, 0.045, 0.017], "qvalue": [ 0.02 , 0.007, 0.068, 0.066, 0.068, 0.068, 0.068], } for key, value in exp.items(): npt.assert_array_equal(obs[key].to_numpy().round(3), np.array(value)) exp = np.array([True, True, False, False, False, False, False]) npt.assert_array_equal(obs["Signif"].to_numpy(), exp) def test_dirmult_ttest_toy(self): p1 = np.array([5, 6, 7]) p2 = np.array([4, 7, 7]) p1, p2 = p1 / p1.sum(), p2 / p2.sum() depth = 1000 n = 100 data = np.vstack(( np.random.multinomial(depth, p1, size=n), np.random.multinomial(depth, p2, size=n))) table = pd.DataFrame(data) grouping = pd.Series(['Group1'] * n + ['Group2'] * n) exp_lfc = np.log2([4/5, 7/6, 7/7]) exp_lfc = (exp_lfc - exp_lfc.mean()) # convert to CLR coordinates res = dirmult_ttest(table, grouping, self.treatment, self.reference) npt.assert_array_less(exp_lfc, res['CI(97.5)']) npt.assert_array_less(res['CI(2.5)'], exp_lfc) def test_dirmult_ttest_toy_depth(self): p1 = np.array([5, 6, 7, 8, 9, 4]) p2 = np.array([4, 7, 7, 6, 5, 7]) p1, p2 = p1 / p1.sum(), p2 / p2.sum() depth = 100 n = 100 data = np.vstack(( np.random.multinomial(depth, p1, size=n), np.random.multinomial(depth, p2, size=n))) table = pd.DataFrame(data) grouping = pd.Series(['Group1'] * n + ['Group2'] * n) exp_lfc = np.log2([4/5, 7/6, 7/7, 6/8, 5/9, 7/4]) exp_lfc = (exp_lfc - exp_lfc.mean()) # convert to CLR coordinates res_100 = dirmult_ttest(table, grouping, self.treatment, self.reference) # increase sequencing depth by 100 fold depth = 10000 data = np.vstack(( np.random.multinomial(depth, p1, size=n), np.random.multinomial(depth, p2, size=n))) table = pd.DataFrame(data) res_10000 = dirmult_ttest(table, grouping, self.treatment, self.reference) # when the sequencing depth increases, the confidence intervals # should also shrink npt.assert_array_less(res_100['CI(2.5)'], res_10000['CI(2.5)']) npt.assert_array_less(res_10000['CI(97.5)'], res_100['CI(97.5)']) def test_dirmult_ttest_output(self): exp_lfc = np.log2(self.p2 / self.p1) exp_lfc = exp_lfc - exp_lfc.mean() res = dirmult_ttest(self.table2, self.grouping2, self.treatment, self.reference) npt.assert_array_less(res['Log2(FC)'], res['CI(97.5)']) npt.assert_array_less(res['CI(2.5)'], res['Log2(FC)']) # a couple of things that complicate the tests # first, there is going to be a little bit of a fudge factor due # to the pseudocount, so we will define it via log2(0.5) eps = np.abs(np.log2(0.5)) # second, the confidence interval is expected to be inaccurate # for (1/20) of the tests. So we should double check to # see if the confidence intervals were able to capture # 95% of the log-fold changes correctly self.assertGreater(np.mean(res['CI(2.5)'] - eps < exp_lfc), 0.95) self.assertGreater(np.mean(res['CI(97.5)'] + eps > exp_lfc), 0.95) def test_dirmult_ttest_valid_input(self): result = dirmult_ttest(self.table, self.grouping, self.treatment, self.reference) self.assertIsInstance(result, pd.DataFrame) self.assertEqual(result.shape[1], 7) # Expected number of columns pdt.assert_index_equal(result.index, pd.Index(['feature1', 'feature2', 'feature3'])) def test_dirmult_ttest_array_input(self): result = dirmult_ttest(self.table.to_numpy(), self.grouping, self.treatment, self.reference) self.assertIsInstance(result, pd.DataFrame) self.assertIsInstance(result.index, pd.RangeIndex) def test_dirmult_ttest_no_group(self): result = dirmult_ttest(self.table, self.grouping) self.assertIsInstance(result, pd.DataFrame) result = dirmult_ttest(self.table, self.grouping, treatment=self.treatment) self.assertIsInstance(result, pd.DataFrame) result = dirmult_ttest(self.table, self.grouping, reference=self.treatment) self.assertIsInstance(result, pd.DataFrame) def test_dirmult_ttest_no_pseudocount(self): result = dirmult_ttest(self.table, self.grouping, self.treatment, self.reference, pseudocount=None) self.assertIsInstance(result, pd.DataFrame) def test_dirmult_ttest_no_p_adjust(self): result = dirmult_ttest(self.table, self.grouping, self.treatment, self.reference, p_adjust=None) pdt.assert_series_equal(result['pvalue'], result['qvalue'], check_names=False) def test_dirmult_ttest_invalid_table_type(self): with self.assertRaises(TypeError): dirmult_ttest("invalid_table", self.grouping, self.treatment, self.reference) def test_dirmult_ttest_negative_values_in_table(self): self.table.iloc[0, 0] = -5 # Modify a value to be negative with self.assertRaises(ValueError): dirmult_ttest(self.table, self.grouping, self.treatment, self.reference) def test_dirmult_ttest_missing_values_in_grouping(self): self.grouping[1] = np.nan # Introduce a missing value in grouping with self.assertRaises(ValueError): dirmult_ttest(self.table, self.grouping, self.treatment, self.reference) def test_dirmult_ttest_missing_values_in_table(self): self.table.iloc[2, 1] = np.nan # Introduce a missing value in the table with self.assertRaises(ValueError): dirmult_ttest(self.table, self.grouping, self.treatment, self.reference) def test_dirmult_ttest_inconsistent_indexes(self): self.table.index = ['a', 'b', 'c', 'd', 'e'] # Change table index with self.assertRaises(ValueError): dirmult_ttest(self.table, self.grouping, self.treatment, self.reference) class DirMultLMETests(TestCase): # NOTE: `dirmult_lme` performs numerical optimization, which might (though rarely) # generate slightly different results on different platforms. The following tests # have specific numbers commented out, just to be safe in the CI workflow. But one # may check the accuracy of results locally by restoring the commented code. def setUp(self): np.random.seed(0) index = ["subject1", "subject2", "subject3", "subject4", "subject5", "subject6"] columns = ["feature1", "feature2", "feature3", "feature4"] # create sample data for testing self.table = pd.DataFrame( [[20, 110, 100, 101], [33, 110, 120, 100], [12, 110, 100, 110], [202, 201, 9, 10], [200, 202, 10, 10], [203, 201, 14, 10]], index=index, columns=columns) self.metadata = pd.DataFrame( {"Covar1": [1,1,2,2,3,3], "Covar2": [1,1,1,1,2,2], "Covar3": [1,2,1,2,1,2]}, index=index) def test_dirmult_lme_demo(self): # a regular analysis res = dirmult_lme( table=self.table, metadata=self.metadata, formula="Covar2 + Covar3", grouping="Covar1", draws=1, seed=0, p_adjust="sidak") exp = """ FeatureID Covariate Reps Log2(FC) CI(2.5) CI(97.5) pvalue qvalue Signif 0 feature1 Covar2 1 2.708376 -0.818699 6.235451 0.132319 0.247129 False 1 feature1 Covar3 1 1.696770 -1.224053 4.617594 0.254876 0.444790 False 2 feature2 Covar2 1 0.956017 -0.736692 2.648726 0.268312 0.464632 False 3 feature2 Covar3 1 0.325451 -0.657935 1.308836 0.516565 0.766291 False 4 feature3 Covar2 1 -1.990268 -4.362246 0.381711 0.100061 0.190110 False 5 feature3 Covar3 1 -0.812892 -2.910615 1.284830 0.447548 0.694797 False 6 feature4 Covar2 1 -1.674125 -3.885791 0.537540 0.137915 0.256810 False 7 feature4 Covar3 1 -1.209329 -3.204871 0.786213 0.234925 0.414660 False """.strip("\n") # self.assertEqual(str(res), exp) self.assertIsInstance(res, pd.DataFrame) self.assertTupleEqual(res.shape, (8, 9)) pdt.assert_index_equal(res.columns, pd.Index([ "FeatureID", "Covariate", "Reps", "Log2(FC)", "CI(2.5)", "CI(97.5)", "pvalue", "qvalue", "Signif"])) self.assertListEqual(res["FeatureID"].tolist(), [ "feature1", "feature1", "feature2", "feature2", "feature3", "feature3", "feature4", "feature4"]) self.assertListEqual(res["Covariate"].tolist(), [ "Covar2", "Covar3", "Covar2", "Covar3", "Covar2", "Covar3", "Covar2", "Covar3"]) self.assertTrue((res["Reps"] == 1).all()) # npt.assert_array_equal(res["Log2(FC)"].round(5), np.array([ # 2.70838, 1.69677, 0.95602, 0.32545, -1.99027, -0.81289, -1.67413, # -1.20933])) # npt.assert_array_equal(res["CI(2.5)"].round(5), np.array([ # -0.8187, -1.22405, -0.73669, -0.65793, -4.36225, -2.91061, -3.88579, # -3.20487])) # npt.assert_array_equal(res["CI(97.5)"].round(5), np.array([ # 6.23545, 4.61759, 2.64873, 1.30884, 0.38171, 1.28483, 0.53754, 0.78621])) # npt.assert_array_equal(res["pvalue"].round(5), np.array([ # 0.13232, 0.25488, 0.26831, 0.51657, 0.10006, 0.44755, 0.13792, 0.23492])) # npt.assert_array_equal(res["qvalue"].round(5), np.array([ # 0.24713, 0.44479, 0.46463, 0.76629, 0.19011, 0.6948 , 0.25681, 0.41466])) self.assertTrue((res["Signif"] == False).all()) # confirm that 2.5% < fold-change < 97.5% npt.assert_array_less(res["Log2(FC)"], res["CI(97.5)"]) npt.assert_array_less(res["CI(2.5)"], res["Log2(FC)"]) def test_dirmult_lme_array_input(self): res = dirmult_lme( table=self.table.to_numpy(), metadata=self.metadata, formula="Covar2 + Covar3", grouping="Covar1", draws=1, seed=0, p_adjust="sidak") self.assertIsInstance(res, pd.DataFrame) # npt.assert_array_equal(res["qvalue"].round(3), np.array([ # 0.247, 0.445, 0.465, 0.766, 0.190, 0.695, 0.257, 0.415])) def test_dirmult_lme_alt_grouping(self): res = dirmult_lme( table=self.table, metadata=self.metadata, formula="Covar2 + Covar3", grouping=self.metadata["Covar1"].to_numpy(), draws=1, seed=0, p_adjust="sidak") self.assertIsInstance(res, pd.DataFrame) # npt.assert_array_equal(res["qvalue"].round(3), np.array([ # 0.247, 0.445, 0.465, 0.766, 0.190, 0.695, 0.257, 0.415])) def test_dirmult_lme_no_pseudocount(self): res = dirmult_lme( table=self.table + 0.5, metadata=self.metadata, formula="Covar2 + Covar3", grouping="Covar1", draws=1, seed=0, p_adjust="sidak", pseudocount=None) self.assertIsInstance(res, pd.DataFrame) # npt.assert_array_equal(res["qvalue"].round(3), np.array([ # 0.247, 0.445, 0.465, 0.766, 0.190, 0.695, 0.257, 0.415])) def test_dirmult_lme_no_intercept(self): # "-1" at the end of formula suppresses intercept res = dirmult_lme( table=self.table, metadata=self.metadata, formula="Covar2 + Covar3 - 1", grouping="Covar1", draws=1, seed=0, p_adjust="sidak") self.assertIsInstance(res, pd.DataFrame) # npt.assert_array_equal(res["qvalue"].round(3), np.array([ # 0.988, 0.998, 0.129, 0.761, 0.766, 0.988, 0.971, 0.965])) def test_dirmult_lme_re_formula(self): # "1": random effect only in intercept (the default scenario) res = dirmult_lme( table=self.table, metadata=self.metadata, formula="Covar2 + Covar3", grouping="Covar1", draws=1, seed=0, p_adjust="sidak", re_formula="1") self.assertIsInstance(res, pd.DataFrame) # npt.assert_array_equal(res["qvalue"].round(3), np.array([ # 0.247, 0.445, 0.465, 0.766, 0.190, 0.695, 0.257, 0.415])) # add a random slope for Covar2 res = dirmult_lme( table=self.table, metadata=self.metadata, formula="Covar2 + Covar3", grouping="Covar1", draws=1, seed=0, p_adjust="sidak", re_formula="1 + Covar2", fit_method="bfgs") self.assertIsInstance(res, pd.DataFrame) # NOTE: This test function is prone to generate different results on different # platforms. If the following test is to be executed, be prepared that lower # precision is needed to get the test pass. # npt.assert_array_equal(res["qvalue"].round(3), np.array([ # 0.274, 0.463, 0.645, 0.766, 0.251, 0.703, 0.400, 0.415])) def test_dirmult_lme_vc_formula(self): res = dirmult_lme( table=self.table, metadata=self.metadata, formula="Covar2 + Covar3", grouping="Covar1", draws=1, seed=0, p_adjust="sidak", vc_formula={"Covar2": "0 + C(Covar2)"}) self.assertIsInstance(res, pd.DataFrame) # npt.assert_array_equal(res["qvalue"].round(3), np.array([ # 0.247, 0.445, 0.465, 0.766, 0.190, 0.695, 0.257, 0.415])) def test_dirmult_lme_no_p_adjust_and_reml(self): result = dirmult_lme( self.table, self.metadata, "Covar2 + Covar3", "Covar1", draws=1, seed=0, p_adjust=None) pdt.assert_series_equal(result['pvalue'], result['qvalue'], check_names=False) fit_kwargs = {"reml": False} res_ml = dirmult_lme( self.table, self.metadata, "Covar2 + Covar3", "Covar1", draws=1, seed=0, p_adjust=None, fit_kwargs=fit_kwargs) with self.assertRaises(AssertionError): npt.assert_allclose(result['CI(97.5)'], res_ml['CI(97.5)']) npt.assert_allclose(result['CI(2.5)'], res_ml['CI(2.5)']) npt.assert_allclose(result['pvalue'], res_ml['pvalue']) def test_dirmult_lme_fit_warnings(self): # Convergence warnings are frequently raised during model fitting. from statsmodels.tools.sm_exceptions import ConvergenceWarning with self.assertWarns(ConvergenceWarning): dirmult_lme(table=self.table, metadata=self.metadata, formula="Covar2 + Covar3", grouping="Covar1", draws=1, seed=0, p_adjust="sidak", fit_warnings=True) def test_dirmult_lme_fail_all(self): # Supply a non-existent optimization method to make it fail. msg = "LME fit failed for all features in all replicates." with self.assertRaises(ValueError) as cm: dirmult_lme(table=self.table, metadata=self.metadata, formula="Covar2 + Covar3", grouping="Covar1", draws=1, seed=0, p_adjust="sidak", fit_method="not_a_method") self.assertEqual(str(cm.exception), msg) # def test_dirmult_lme_fail_some(self): # # With the BFGS method, LME model fitting will not converge on two features. # # Output will be NaN. # msg = "LME fit failed for 2 features in all replicates, reporting NaNs." # with self.assertWarns(UserWarning) as cm: # res = dirmult_lme(table=self.table, metadata=self.metadata, # formula="Covar2 + Covar3", grouping="Covar1", # draws=1, seed=0, p_adjust="sidak", # fit_method="bfgs", fit_converge=True) # self.assertEqual(str(cm.warning), msg) # self.assertTrue(res.query( # "FeatureID == ['feature1', 'feature3']")["Log2(FC)"].isnull().all()) # self.assertTrue(res.query( # "FeatureID == ['feature2', 'feature4']")["Log2(FC)"].notnull().all()) def test_dirmult_lme_invalid_table_type(self): with self.assertRaises(TypeError): dirmult_lme("not a table", self.metadata, "Covar2 + Covar3", "Covar1") def test_dirmult_lme_invalid_metadata_type(self): with self.assertRaises(TypeError): dirmult_lme(self.table, "not metadata", "Covar2 + Covar3", "Covar1") def test_dirmult_lme_invalid_grouping(self): with self.assertRaises(ValueError): dirmult_lme(self.table, self.metadata, "Covar2 + Covar3", "hello") def test_dirmult_lme_inconsistent_indexes(self): # change table index self.table.index = ["a", "b", "c", "d", "e", "f"] with self.assertRaises(ValueError): dirmult_lme(self.table, self.metadata, "Covar2 + Covar3", "Covar1") def test_dirmult_lme_single_feature(self): # only keep the first column of the table self.table = self.table.iloc[:, :1] with self.assertRaises(ValueError): dirmult_lme(self.table, self.metadata, "Covar1", "Covar1") def test_dirmult_lme_toy_data(self): # simulate a dataset of 20 samples by 3 features, with 10 repeated measurements # (covar1) and 2 sample groups (covar2) p1 = np.array([5, 6, 7]) p2 = np.array([4, 7, 7]) p1, p2 = p1 / p1.sum(), p2 / p2.sum() depth = 1000 n = 10 index_range = range(1, n * 2 + 1) data = np.vstack(( np.random.multinomial(depth, p1, size=n), np.random.multinomial(depth, p2, size=n))) table = pd.DataFrame(data) table.columns = ["feature1", "feature2", "feature3"] table.index = [f"subject{i}" for i in index_range] exp_lfc = np.log2([4/5, 7/6, 7/7]) exp_lfc = (exp_lfc - exp_lfc.mean()) # convert to CLR coordinates metadata = pd.DataFrame({ "covar1": [1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10], "covar2": [1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2]}, index=[f"subject{i}" for i in index_range]) res = dirmult_lme( table=table, metadata=metadata, formula="covar2", grouping="covar1", draws=8, seed=0, p_adjust="sidak") npt.assert_array_equal(res["Log2(FC)"].round(5), [-0.28051, 0.32118, -0.04067]) npt.assert_array_equal(res["CI(2.5)"].round(5), [-0.41639, 0.18745, -0.16542]) npt.assert_array_equal(res["CI(97.5)"].round(5), [-0.14359, 0.46473, 0.07706]) # confirm expected fold change is within confidence interval npt.assert_array_less(exp_lfc, res['CI(97.5)']) npt.assert_array_less(res['CI(2.5)'], exp_lfc) def test_dirmult_lme_toy_data_depth(self): p1 = np.array([5, 6, 7, 8, 9, 4]) p2 = np.array([4, 7, 7, 6, 5, 7]) p1, p2 = p1 / p1.sum(), p2 / p2.sum() depth = 100 n = 10 index_range = range(1, n * 2 + 1) data = np.vstack(( np.random.multinomial(depth, p1, size=n), np.random.multinomial(depth, p2, size=n))) table = pd.DataFrame(data) table.columns = [ "feature1", "feature2", "feature3", "feature4", "feature5", "feature6"] table.index = [f"subject{i}" for i in index_range] metadata = pd.DataFrame({ "covar1": [1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10], "covar2": [1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2]}, index=[f"subject{i}" for i in index_range]) exp_lfc = np.log2([4/5, 7/6, 7/7, 6/8, 5/9, 7/4]) exp_lfc = (exp_lfc - exp_lfc.mean()) # convert to CLR coordinates res_100 = dirmult_lme( table=table, metadata=metadata, formula="covar2", grouping="covar1", draws=8, seed=0, p_adjust="sidak") # increase sequencing depth by 100 fold depth = 10000 data = np.vstack(( np.random.multinomial(depth, p1, size=n), np.random.multinomial(depth, p2, size=n))) table = pd.DataFrame(data) table.columns = [ "feature1", "feature2", "feature3", "feature4", "feature5", "feature6"] table.index = [f"subject{i}" for i in index_range] metadata.index = [f"subject{i}" for i in index_range] res_10000 = dirmult_lme( table=table, metadata=metadata, formula="covar2", grouping="covar1", draws=8, seed=0, p_adjust="sidak") # when the sequencing depth increases, the confidence intervals # should also shrink npt.assert_array_less(res_100['CI(2.5)'], res_10000['CI(2.5)']) npt.assert_array_less(res_10000['CI(97.5)'], res_100['CI(97.5)']) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/composition/tests/test_utils.py000066400000000000000000000300721520735541300271000ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt import pandas as pd import pandas.testing as pdt from skbio.stats.composition._utils import ( _check_grouping, _check_trt_ref_groups, _check_metadata, _type_cast_to_float, _check_sig_test, _check_p_adjust, ) class UtilsTests(TestCase): def test_check_grouping(self): matrix = np.array([[1, 2], [3, 4], [5, 6]]) grouping = [0, 0, 1] obs = _check_grouping(grouping, matrix) npt.assert_array_equal(obs[0], [0, 1]) npt.assert_array_equal(obs[1], grouping) grouping = [5, 2, 5] obs = _check_grouping(grouping, matrix) npt.assert_array_equal(obs[0], [2, 5]) npt.assert_array_equal(obs[1], [1, 0, 1]) grouping = ["b", "b", "a"] obs = _check_grouping(grouping, matrix) npt.assert_array_equal(obs[0], ["a", "b"]) npt.assert_array_equal(obs[1], [1, 1, 0]) grouping = pd.Series(grouping) obs = _check_grouping(grouping, matrix) npt.assert_array_equal(obs[0], ["a", "b"]) npt.assert_array_equal(obs[1], [1, 1, 0]) msg = "`table` contains sample IDs that are absent in `grouping`." samples = ["x", "y", "z"] with self.assertRaises(ValueError) as cm: _check_grouping(grouping, matrix, samples=samples) self.assertEqual(str(cm.exception), msg) grouping.index = ["x", "y", "z"] obs = _check_grouping(grouping, matrix, samples=samples) npt.assert_array_equal(obs[0], ["a", "b"]) npt.assert_array_equal(obs[1], [1, 1, 0]) msg = "Sample counts in `table` and `grouping` are not consistent." grouping = ["b", "c", "a", "b"] with self.assertRaises(ValueError) as cm: _check_grouping(grouping, matrix) self.assertEqual(str(cm.exception), msg) grouping = pd.Series(grouping) with self.assertRaises(ValueError) as cm: _check_grouping(grouping, matrix) self.assertEqual(str(cm.exception), msg) grouping.index = ["y", "z", "x", "w"] samples = ["x", "y", "z"] obs = _check_grouping(grouping, matrix, samples=samples) npt.assert_array_equal(obs[0], ["a", "b", "c"]) npt.assert_array_equal(obs[1], [0, 1, 2]) msg = "Cannot handle missing values in `grouping`." grouping = np.array([1., np.nan, 3.]) with self.assertRaises(ValueError) as cm: _check_grouping(grouping, matrix) self.assertEqual(str(cm.exception), msg) grouping = [1, None, 3] with self.assertRaises(ValueError) as cm: _check_grouping(grouping, matrix) self.assertEqual(str(cm.exception), msg) msg = "`grouping` must be convertible to a 1-D vector." grouping = np.array([["a", "b"], ["c", "g"], ["e", "d"]]) with self.assertRaises(ValueError) as cm: _check_grouping(grouping, matrix) self.assertEqual(str(cm.exception), msg) grouping = 123 with self.assertRaises(ValueError) as cm: _check_grouping(grouping, matrix) self.assertEqual(str(cm.exception), msg) def test_check_trt_ref_groups(self): # two groups grouping = ["B", "A", "B", "B", "A", "A", "A", "B"] groups, labels = _check_grouping(grouping, np.empty((8, 1))) obs = _check_trt_ref_groups("A", "B", groups, labels) npt.assert_array_equal(obs[0], [1, 4, 5, 6]) npt.assert_array_equal(obs[1], [0, 2, 3, 7]) obs = _check_trt_ref_groups("B", "A", groups, labels) npt.assert_array_equal(obs[0], [0, 2, 3, 7]) npt.assert_array_equal(obs[1], [1, 4, 5, 6]) # default groups obs = _check_trt_ref_groups(None, None, groups, labels) npt.assert_array_equal(obs[0], [1, 4, 5, 6]) npt.assert_array_equal(obs[1], [0, 2, 3, 7]) obs = _check_trt_ref_groups("A", None, groups, labels) npt.assert_array_equal(obs[0], [1, 4, 5, 6]) npt.assert_array_equal(obs[1], [0, 2, 3, 7]) obs = _check_trt_ref_groups("B", None, groups, labels) npt.assert_array_equal(obs[0], [0, 2, 3, 7]) npt.assert_array_equal(obs[1], [1, 4, 5, 6]) msg = "Treatment group C is not found in grouping." with self.assertRaises(ValueError) as cm: _check_trt_ref_groups("C", None, groups, labels) self.assertEqual(str(cm.exception), msg) msg = "Reference group D is not found in grouping." with self.assertRaises(ValueError) as cm: _check_trt_ref_groups("A", "D", groups, labels) self.assertEqual(str(cm.exception), msg) msg = "Treatment and reference groups must not be identical." with self.assertRaises(ValueError) as cm: _check_trt_ref_groups("A", "A", groups, labels) self.assertEqual(str(cm.exception), msg) with self.assertRaises(ValueError) as cm: _check_trt_ref_groups(None, "A", groups, labels) self.assertEqual(str(cm.exception), msg) # one group grouping = ["A", "A", "A", "A"] groups, labels = _check_grouping(grouping, np.empty((4, 1))) msg = "There must be at least two groups in grouping." with self.assertRaises(ValueError) as cm: _check_trt_ref_groups(None, None, groups, labels) self.assertEqual(str(cm.exception), msg) # three groups grouping = ["A", "C", "B", "B", "C", "A", "A", "C"] groups, labels = _check_grouping(grouping, np.empty((8, 1))) obs = _check_trt_ref_groups("A", "B", groups, labels) npt.assert_array_equal(obs[0], [0, 5, 6]) npt.assert_array_equal(obs[1], [2, 3]) obs = _check_trt_ref_groups("C", "A", groups, labels) npt.assert_array_equal(obs[0], [1, 4, 7]) npt.assert_array_equal(obs[1], [0, 5, 6]) obs = _check_trt_ref_groups("B", None, groups, labels) npt.assert_array_equal(obs[0], [2, 3]) npt.assert_array_equal(obs[1], [0, 1, 4, 5, 6, 7]) obs = _check_trt_ref_groups(None, "C", groups, labels) npt.assert_array_equal(obs[0], [0, 5, 6]) npt.assert_array_equal(obs[1], [1, 4, 7]) obs = _check_trt_ref_groups(None, None, groups, labels) npt.assert_array_equal(obs[0], [0, 5, 6]) npt.assert_array_equal(obs[1], [1, 2, 3, 4, 7]) def test_check_metadata(self): mat = np.empty(12).reshape(3, 4) df = pd.DataFrame([("Alice", 20, 28.0), ("Bob", 32, 33.0), ("Carol", 25, 26.5)], columns=["name", "age", "bmi"]) obs = _check_metadata(df, mat) self.assertIs(obs, df) lst = [("Alice", 20, 28.0), ("Bob", 32, 33.0), ("Carol", 25, 26.5)] obs = _check_metadata(lst, mat) self.assertIsInstance(obs, pd.DataFrame) dic = {"name": ["Alice", "Bob", "Carol"], "age": [20, 32, 25], "bmi": [28.0, 33.0, 26.5]} obs = _check_metadata(dic, mat) self.assertIsInstance(obs, pd.DataFrame) arr = np.array([("Alice", 20, 28.0), ("Bob", 32, 33.0), ("Carol", 25, 26.5)], dtype=[("name", "U10"), ("age", "i4"), ("bmi", "f4")]) obs = _check_metadata(arr, mat) self.assertIsInstance(obs, pd.DataFrame) msg = "Metadata must be a pandas DataFrame" with self.assertRaisesRegex(TypeError, msg): _check_metadata(42, mat) with self.assertRaisesRegex(TypeError, msg): _check_metadata("hello", mat) msg = "Sample counts in table and metadata are not consistent." with self.assertRaises(ValueError) as cm: _check_metadata(df, mat.reshape(4, 3)) self.assertEqual(str(cm.exception), msg) df.index = ["a", "b", "c"] obs = _check_metadata(df, mat) self.assertIs(obs, df) # check sample IDs samples = ["a", "b", "c"] obs = _check_metadata(df, mat, samples=samples) self.assertIs(obs, df) # reorder samples samples = ["b", "c", "a"] obs = _check_metadata(df, mat, samples=samples) self.assertIsNot(obs, df) pdt.assert_index_equal(obs.index, pd.Index(samples)) # filter and reorder samples samples = ["c", "b"] obs = _check_metadata(df, mat, samples=samples) self.assertIsNot(obs, df) pdt.assert_index_equal(obs.index, pd.Index(samples)) msg = "Metadata contains sample IDs that are absent in the table." samples = ["a", "b", "x"] with self.assertRaises(ValueError) as cm: _check_metadata(df, mat, samples=samples) self.assertEqual(str(cm.exception), msg) msg = "Cannot handle missing values in metadata." df = pd.DataFrame(np.array([1.0, np.nan, 2.0]).reshape(3, -1)) with self.assertRaises(ValueError) as cm: _check_metadata(df, mat) self.assertEqual(str(cm.exception), msg) df = pd.DataFrame(np.array([1.0, None, 2.0]).reshape(3, -1)) with self.assertRaises(ValueError) as cm: _check_metadata(df, mat) self.assertEqual(str(cm.exception), msg) def test_type_cast_to_float(self): df = pd.DataFrame([("Alice", 20, 28.0), ("Bob", 32, 33.0), ("Carol", 25, 26.5)], columns=["name", "age", "bmi"]) obs = _type_cast_to_float(df) self.assertIsInstance(obs, pd.DataFrame) self.assertIsNot(obs, df) self.assertTrue(pd.api.types.is_string_dtype(obs["name"])) self.assertEqual(obs["age"].dtype, np.float64) self.assertEqual(obs["bmi"].dtype, np.float64) def test_check_sig_test(self): from scipy.stats import ttest_ind, mannwhitneyu, f_oneway, kruskal obs = _check_sig_test(ttest_ind) self.assertIs(obs, ttest_ind) obs = _check_sig_test("ttest_ind") self.assertIs(obs, ttest_ind) obs = _check_sig_test(f_oneway) self.assertIs(obs, f_oneway) obs = _check_sig_test("f_oneway") self.assertIs(obs, f_oneway) msg = 'Function "not_a_test" does not exist under scipy.stats.' with self.assertRaises(ValueError) as cm: _check_sig_test("not_a_test") self.assertEqual(str(cm.exception), msg) msg = "`sig_test` must be a function or a string." with self.assertRaises(TypeError) as cm: _check_sig_test(123) self.assertEqual(str(cm.exception), msg) msg = ('"mannwhitneyu" is a two-way statistical test whereas 3 sample ' "groups were provided.") with self.assertRaises(ValueError) as cm: _check_sig_test(mannwhitneyu, n_groups=3) self.assertEqual(str(cm.exception), msg) obs = _check_sig_test(mannwhitneyu, n_groups=2) obs = _check_sig_test(kruskal, n_groups=5) def test_check_p_adjust(self): self.assertIsNone(_check_p_adjust(None)) p = [0.005, 0.011, 0.02, 0.04, 0.13] obs = _check_p_adjust("holm-bonferroni")(p) exp = p * np.arange(1, 6)[::-1] for a, b in zip(obs, exp): self.assertAlmostEqual(a, b) p = [0.005, 0.011, 0.02, 0.04, 0.13] obs = _check_p_adjust("benjamini-hochberg")(p) exp = [0.025, 0.0275, 0.03333333, 0.05, 0.13] for a, b in zip(obs, exp): self.assertAlmostEqual(a, b) msg = '"hello" is not an available FDR correction method.' with self.assertRaises(ValueError) as cm: _check_p_adjust("hello")(p) self.assertEqual(str(cm.exception), msg) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/000077500000000000000000000000001520735541300224125ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/__init__.py000066400000000000000000000123071520735541300245260ustar00rootroot00000000000000r"""Distance matrix-based statistics (:mod:`skbio.stats.distance`) ============================================================== .. currentmodule:: skbio.stats.distance This module provides functionality for storing, manipulating, and analyzing pairwise relationships, especially distances, between biological objects. It contains various statistical methods that operate on distance matrices, often relating distances to categorical and/or numeric variables of interest (e.g., gender and/or age). Methods are also provided for comparing distance matrices (e.g., computing the correlation between two or more distance matrices using the Mantel test). Data structures --------------- This package provides three hierarchical matrix classes: ``PairwiseMatrix`` > ``SymmetricMatrix`` > ``DistanceMatrix``, to store measures of pairwise relationships between objects. A matrix object stores a 2-D float array of pairwise measures and a tuple of unique string labels identifying each object in the matrix. ``PairwiseMatrix`` can be used to store any measures of pairwise relationships. Its subclass ``SymmetricMatrix`` requires that the relationships are **symmetric** (i.e., :math:`D(i, j) = D(j, i)`). ``DistanceMatrix``, the most specific class of the three, further requires that the matrix is **hollow** (i.e., :math:`D(i, i) = 0`), usually representing the difference/distinction between objects (e.g., Euclidean or Hamming distances). However, ``DistanceMatrix`` does not enforce non-negativity or triangle inequality, two properties of a metric distance, therefore it is suitable for more general measures (e.g., Bray-Curtis dissimilarity). Classes ^^^^^^^ .. autosummary:: :toctree: PairwiseMatrix SymmetricMatrix DistanceMatrix Functions ^^^^^^^^^ .. autosummary:: :toctree: randdm Exceptions ^^^^^^^^^^ .. autosummary:: PairwiseMatrixError SymmetricMatrixError DistanceMatrixError MissingIDError Distance-based statistics ------------------------- Categorical Variable Stats ^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autosummary:: :toctree: anosim permanova permdisp Continuous Variable Stats ^^^^^^^^^^^^^^^^^^^^^^^^^ .. autosummary:: :toctree: bioenv Distance Matrix Comparisons ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autosummary:: :toctree: mantel pwmantel Examples -------- Assume we have the following delimited text file storing distances between three objects with IDs ``a``, ``b``, and ``c``:: \ta\tb\tc a\t0.0\t0.5\t1.0 b\t0.5\t0.0\t0.75 c\t1.0\t0.75\t0.0 Load a distance matrix from the file: >>> from io import StringIO >>> from skbio import DistanceMatrix >>> dm_fh = StringIO("\ta\tb\tc\n" ... "a\t0.0\t0.5\t1.0\n" ... "b\t0.5\t0.0\t0.75\n" ... "c\t1.0\t0.75\t0.0\n") >>> dm = DistanceMatrix.read(dm_fh) >>> print(dm) 3x3 distance matrix IDs: 'a', 'b', 'c' Data: [[ 0. 0.5 1. ] [ 0.5 0. 0.75] [ 1. 0.75 0. ]] Access the distance (scalar) between objects ``'a'`` and ``'c'``: >>> dm['a', 'c'] 1.0 Get a row vector of distances between object ``'b'`` and all other objects: >>> dm['b'] array([ 0.5 , 0. , 0.75]) numpy indexing/slicing also works as expected. Extract the third column: >>> dm[:, 2] array([ 1. , 0.75, 0. ]) Serialize the distance matrix to delimited text file: >>> out_fh = StringIO() >>> _ = dm.write(out_fh) >>> out_fh.getvalue() == dm_fh.getvalue() True A distance matrix object can also be created from an existing ``numpy.array`` (or an array-like object, such as a nested Python list): >>> import numpy as np >>> data = np.array([[0.0, 0.5, 1.0], ... [0.5, 0.0, 0.75], ... [1.0, 0.75, 0.0]]) >>> ids = ["a", "b", "c"] >>> dm_from_np = DistanceMatrix(data, ids) >>> print(dm_from_np) 3x3 distance matrix IDs: 'a', 'b', 'c' Data: [[ 0. 0.5 1. ] [ 0.5 0. 0.75] [ 1. 0.75 0. ]] >>> dm_from_np == dm True IDs may be omitted when constructing a pairwise/symmetric/distance matrix. Monotonically-increasing integers (cast as strings) will be automatically used: >>> dm = DistanceMatrix(data) >>> dm.ids ('0', '1', '2') """ # noqa: D407, D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._base import ( PairwiseMatrixError, DissimilarityMatrixError, SymmetricMatrixError, DistanceMatrixError, MissingIDError, PairwiseMatrix, DissimilarityMatrix, SymmetricMatrix, DistanceMatrix, randdm, ) from ._bioenv import bioenv from ._anosim import anosim from ._permanova import permanova from ._mantel import mantel, pwmantel from ._permdisp import permdisp __all__ = [ "PairwiseMatrixError", "DissimilarityMatrixError", "SymmetricMatrixError", "DistanceMatrixError", "MissingIDError", "PairwiseMatrix", "DissimilarityMatrix", "SymmetricMatrix", "DistanceMatrix", "randdm", "anosim", "permanova", "bioenv", "mantel", "pwmantel", "permdisp", ] scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/_anosim.py000066400000000000000000000220001520735541300244030ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from functools import partial from typing import Any, TYPE_CHECKING import numpy as np from scipy.stats import rankdata from ._base import _preprocess_input, _run_monte_carlo_stats, _build_results from skbio.util._decorator import params_aliased if TYPE_CHECKING: # pragma: no cover from ._base import DistanceMatrix from numpy.typing import ArrayLike, NDArray import pandas as pd from skbio.util._typing import SeedLike @params_aliased([("distmat", "distance_matrix", "0.7.0", False)]) def anosim( distmat: DistanceMatrix, grouping: pd.DataFrame | ArrayLike, column: str | None = None, permutations: int = 999, seed: SeedLike | None = None, ) -> pd.Series: r"""Test for significant differences between groups using ANOSIM. Analysis of Similarities (ANOSIM) is a non-parametric method that tests whether two or more groups of objects (e.g., samples) are significantly different based on a categorical factor. The ranks of the distances in the distance matrix are used to calculate an R statistic, which ranges between -1 (anti-grouping) to +1 (strong grouping), with an R value of 0 indicating random grouping. Statistical significance is assessed via a permutation test. The assignment of objects to groups (`grouping`) is randomly permuted a number of times (controlled via `permutations`). An R statistic is computed for each permutation and the p-value is the proportion of permuted R statistics that are equal to or greater than the original (unpermuted) R statistic. Parameters ---------- distmat : DistanceMatrix Distance matrix containing distances between objects (e.g., distances between samples of microbial communities). grouping : 1-D array_like or pandas.DataFrame Vector indicating the assignment of objects to groups. For example, these could be strings or integers denoting which group an object belongs to. If `grouping` is 1-D ``array_like``, it must be the same length and in the same order as the objects in `distmat`. If `grouping` is a ``DataFrame``, the column specified by `column` will be used as the grouping vector. The ``DataFrame`` must be indexed by the IDs in `distmat` (i.e., the row labels must be distance matrix IDs), but the order of IDs between `distmat` and the ``DataFrame`` need not be the same. All IDs in the distance matrix must be present in the ``DataFrame``. Extra IDs in the ``DataFrame`` are allowed (they are ignored in the calculations). column : str, optional Column name to use as the grouping vector if `grouping` is a ``DataFrame``. Must be provided if `grouping` is a ``DataFrame``. Cannot be provided if `grouping` is 1-D ``array_like``. permutations : int, optional Number of permutations to use when assessing statistical significance. Must be greater than or equal to zero. If zero, statistical significance calculations will be skipped and the p-value will be ``np.nan``. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- pandas.Series Results of the statistical test, including ``test statistic`` and ``p-value``. See Also -------- permanova Notes ----- See [1]_ for the original method reference. The general algorithm and interface are similar to ``vegan::anosim``, available in R's vegan package [2]_. The p-value will be ``np.nan`` if `permutations` is zero. References ---------- .. [1] Clarke, KR. "Non-parametric multivariate analyses of changes in community structure." Australian journal of ecology 18.1 (1993): 117-143. .. [2] http://cran.r-project.org/web/packages/vegan/index.html Examples -------- Load a 4x4 distance matrix and grouping vector denoting 2 groups of objects: >>> from skbio import DistanceMatrix >>> dm = DistanceMatrix([[0, 1, 1, 4], ... [1, 0, 3, 2], ... [1, 3, 0, 3], ... [4, 2, 3, 0]], ... ['s1', 's2', 's3', 's4']) >>> grouping = ['Group1', 'Group1', 'Group2', 'Group2'] Run ANOSIM using 99 permutations to calculate the p-value. The seed is to make the output deterministic. You may skip it if that's not necessary. >>> from skbio.stats.distance import anosim >>> anosim(dm, grouping, permutations=99, seed=42) method name ANOSIM test statistic name R sample size 4 number of groups 2 test statistic 0.25 p-value 0.66 number of permutations 99 Name: ANOSIM results, dtype: object The return value is a ``pandas.Series`` object containing the results of the statistical test. To suppress calculation of the p-value and only obtain the R statistic, specify zero permutations: >>> anosim(dm, grouping, permutations=0) method name ANOSIM test statistic name R sample size 4 number of groups 2 test statistic 0.25 p-value NaN number of permutations 0 Name: ANOSIM results, dtype: object You can also provide a ``pandas.DataFrame`` and a column denoting the grouping instead of a grouping vector. The following ``DataFrame``'s ``Group`` column specifies the same grouping as the vector we used in the previous examples: >>> # make output deterministic; not necessary for normal use >>> import pandas as pd >>> df = pd.DataFrame.from_dict( ... {'Group': {'s2': 'Group1', 's3': 'Group2', 's4': 'Group2', ... 's5': 'Group3', 's1': 'Group1'}}) >>> anosim(dm, df, column='Group', permutations=99, seed=42) method name ANOSIM test statistic name R sample size 4 number of groups 2 test statistic 0.25 p-value 0.66 number of permutations 99 Name: ANOSIM results, dtype: object The results match the first example above. Note that when providing a ``DataFrame``, the ordering of rows and/or columns does not affect the grouping vector that is extracted. The ``DataFrame`` must be indexed by the distance matrix IDs (i.e., the row labels must be distance matrix IDs). If IDs (rows) are present in the ``DataFrame`` but not in the distance matrix, they are ignored. The previous example's ``s5`` ID illustrates this behavior: note that even though the ``DataFrame`` had 5 objects, only 4 were used in the test (see the "Sample size" row in the results above to confirm this). Thus, the ``DataFrame`` can be a superset of the distance matrix IDs. Note that the reverse is not true: IDs in the distance matrix *must* be present in the ``DataFrame`` or an error will be raised. """ sample_size, num_groups, grouping, tri_idxs, distances = _preprocess_input( distmat, grouping, column ) divisor = sample_size * ((sample_size - 1) / 4) ranked_dists = rankdata(distances, method="average") test_stat_function = partial(_compute_r_stat, tri_idxs, ranked_dists, divisor) stat, p_value = _run_monte_carlo_stats( test_stat_function, grouping, permutations, seed ) return _build_results( "ANOSIM", "R", sample_size, num_groups, stat, p_value, permutations ) def _compute_r_stat( tri_idxs: tuple[NDArray[np.int_], NDArray[np.int_]], ranked_dists: NDArray[np.float64], divisor: float, grouping: NDArray[np.number], ) -> np.floating[Any]: """Compute ANOSIM R statistic (between -1 and +1).""" # Create a matrix where True means that the two objects are in the same # group. This ufunc requires that grouping is a numeric vector (e.g., it # won't work with a grouping vector of strings). grouping_matrix = np.equal.outer(grouping, grouping) # Extract upper triangle from the grouping matrix. It is important to # extract the values in the same order that the distances are extracted # from the distance matrix (see ranked_dists). Extracting the upper # triangle (excluding the diagonal) preserves this order. grouping_tri = grouping_matrix[tri_idxs] # within r_W = np.mean(ranked_dists[grouping_tri]) # between r_B = np.mean(ranked_dists[np.invert(grouping_tri)]) return (r_B - r_W) / divisor scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/_base.py000066400000000000000000002543011520735541300240420ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from copy import deepcopy from itertools import combinations from typing import Any, ClassVar, Type, TYPE_CHECKING import numpy as np import pandas as pd from scipy.spatial.distance import squareform from skbio._base import SkbioObject from skbio.stats._misc import _pprint_strs from skbio.util import find_duplicates, get_rng from skbio.util._decorator import classonlymethod from skbio.util._misc import resolve_key from skbio.util._plotting import PlottableMixin from skbio.io.descriptors import Read, Write from ._utils import is_symmetric_and_hollow, is_symmetric from ._utils import distmat_reorder, distmat_reorder_condensed if TYPE_CHECKING: # pragma: no cover from collections.abc import Sequence, Iterable, Callable, Collection from numpy.typing import NDArray, ArrayLike from numpy.random import Generator import matplotlib.figure from matplotlib.colors import Colormap from skbio.util._typing import SeedLike from typing import Self class PairwiseMatrixError(Exception): r"""General error for pairwise matrix validation failures. .. versionchanged:: 0.7.1 Renamed from ``DissimilarityMatrixError``. The old name is kept as an alias. """ pass class SymmetricMatrixError(PairwiseMatrixError): r"""General error for symmetric matrix validation failures.""" pass class DistanceMatrixError(SymmetricMatrixError): r"""General error for distance matrix validation failures.""" pass class MissingIDError(PairwiseMatrixError): r"""Error for ID lookup that doesn't exist in the pairwise matrix.""" def __init__(self, missing_id): super(MissingIDError, self).__init__() self.args = ("The ID '%s' is not in the matrix." % missing_id,) class PairwiseMatrix(SkbioObject, PlottableMixin): r"""Store pairwise relationships between objects. A ``PairwiseMatrix`` object stores a square, two-dimensional matrix of relationships between objects. Objects could be, for example, biological samples or DNA sequences. A sequence of IDs accompanies the data. Methods are provided to load and save pairwise matrices from/to disk, as well as perform common operations such as extracting values based on object ID. Additionally, the :meth:`plot` method provides convenient built-in plotting functionality. .. versionchanged:: 0.7.1 Renamed from ``DissimilarityMatrix`` to better reflect the nature of the matrix data. The old name ``DissimilarityMatrix`` is kept as an alias. Parameters ---------- data : 1-D or 2-D array_like, or PairwiseMatrix A square 2-D array of pairwise relationships between objects, or a 1-D array representing its condensed form, with the diagonal defaulting to zero. Can instead be an instance of ``PairwiseMatrix`` or its subclass, in which case its data and IDs will be directly used. ids : sequence of str, optional IDs of the objects. Must match the number of rows/columns in ``data``. If None (default) and ``data`` does not contain IDs, IDs will be monotonically-increasing integers cast as strings, starting from zero (i.e., '0', '1', '2', '3', ...). validate : bool, optional If True (default) and ``data`` is not a ``PairwiseMatrix`` object, the input data will be validated. See Also -------- SymmetricMatrix DistanceMatrix scipy.spatial.distance.squareform Notes ----- The matrix data are stored in redundant (square-form) format. If the input ``data`` is already a square NumPy array of float32 or float64 type, it will be directly used without making a copy. If ``data`` is in condensed (vector-form) format, the diagonal will be set as zero. The definitions of redundant/condensed formats follow SciPy's :func:`~scipy.spatial.distance.squareform`. The data are not checked for symmetry or hollowness, nor guaranteed/assumed to be symmetric or hollow. Refer to ``SymmetricMatrix`` or ``DistanceMatrix`` instead if such checks are expected. """ default_write_format: ClassVar[str] = "lsmat" """Default write format for this object: ``lsmat``.""" # Used in __str__ # TODO: decide on what to call a matrix element here _matrix_element_name: ClassVar[str] = "relationship" read = Read() write = Write() def __init__( self, data: NDArray | Sequence[float] | Sequence[Sequence[float]] | PairwiseMatrix, ids: Sequence[str] | None = None, validate: bool = True, ): data, ids, validate_shape, validate_ids = self._normalize_input(data, ids) # convert data to redundant if 1D input. # should do this for PairwiseMatrix only. if data.ndim == 1: data = squareform(data, force="tomatrix", checks=False) if ids is None: ids = self._generate_ids(data) else: ids = tuple(ids) if validate: if validate_shape: self._validate_shape(data) if validate_ids: self._validate_ids(data, ids) self._ids = ids self._id_index = self._index_list(self._ids) self._data = self._init_data(data) self._flags = self._init_flags() def _normalize_input(self, data, ids): """Get input into standard numpy array format.""" validate_shape = True validate_ids = True if isinstance(data, PairwiseMatrix): validate_shape = False if ids is None: validate_ids = False ids = data.ids data = data.data # It is necessary to standardize the representation of the .data # attribute of this object. The input types might be list, tuple, # np.array, or possibly some other object type. Generally, this # normalization of type will require a copy of data. For example, # moving from a Python type representation (e.g., [[0, 1], [1, 0]]) # requires casting all of the values to numpy types, which is handled # as an implicit copy via np.asarray. However, these copies are # unnecessary if the data object is already a numpy array. np.asarray # is smart enough to not copy the data, however if a dtype change is # requested it will. The following block of code limits the use of # np.asarray to situations where the data are (a) not already a numpy # array or (b) the data are not a single or double precision numpy # data type. _issue_copy = True if isinstance(data, np.ndarray): if data.dtype in (np.float32, np.float64): _issue_copy = False if _issue_copy: data = np.asarray(data, dtype="float") # Make data_ explicitly an ndarray to help with type checking. # At this point in the code we can be certain that data is an # ndarray. assert isinstance(data, np.ndarray) data_: NDArray = data return (data_, ids, validate_shape, validate_ids) def _generate_ids(self, data: NDArray) -> tuple[str, ...]: """Generate ids if none provided.""" if data.ndim != 1: return tuple(str(i) for i in range(data.shape[0])) else: return tuple(str(i) for i in range(_vec_to_shape(data))) def _init_flags(self, condensed: bool = False) -> dict: """Initialize boolean flags for matrix forms.""" # This is the default value. PairwiseMatrix doesn't really need flags. return {"CONDENSED": False} def _init_data(self, data: NDArray, condensed: bool = False) -> NDArray: """Initialize underlying data structure.""" return data @classonlymethod def from_iterable( cls, iterable: Iterable[Any], metric: Callable, key: Any | None = None, keys: Iterable[Any] | None = None, ) -> Self: r"""Create a pairwise matrix from an iterable of objects given a metric. Parameters ---------- iterable : iterable Objects to compute pairwise relationships on. metric : callable A function that takes two arguments and returns a float representing the relationship between the two objects. key : callable or str, optional A function that takes one argument and returns a string representing the ID of the object. Alternatively, a key to the ``metadata`` property if exists for each object in the ``iterable``. If None, the default IDs will be used. keys : iterable of str, optional IDs of the objects. Must be the same length as ``iterable``. Returns ------- PairwiseMatrix The ``metric`` applied to all pairwise elements in the ``iterable``. Raises ------ ValueError If ``key`` and ``keys`` are both provided. """ iterable = list(iterable) keys_ = _get_keys(iterable, key, keys) dm = np.empty((len(iterable),) * 2) for i, a in enumerate(iterable): for j, b in enumerate(iterable): dm[i, j] = metric(a, b) return cls(dm, keys_) # type: ignore[operator] @property def data(self) -> NDArray: r"""Array of pairwise relationships. A square, two-dimensional ``numpy.ndarray`` of values (floats). A copy is *not* returned. Notes ----- This property is not writeable. """ return self._data @property def ids(self) -> tuple: r"""Tuple of object IDs. A tuple of strings, one for each object in the pairwise matrix. Notes ----- This property is writeable, but the number of new IDs must match the number of objects in ``data``. """ return self._ids @ids.setter def ids(self, ids_: Sequence[str]) -> None: ids_ = tuple(ids_) self._validate_ids(self._data, ids_) self._ids = ids_ self._id_index = self._index_list(self._ids) @property def dtype(self) -> np.dtype: r"""Data type of the matrix values.""" return self._data.dtype @property def shape(self) -> tuple: r"""Two-element tuple containing the redundant form matrix dimensions. Notes ----- As the matrix is guaranteed to be square, both tuple entries will always be equal. The shape of the redundant form matrix is returned. """ if self._flags["CONDENSED"]: m = _vec_to_shape(self._data) return (m, m) return self._data.shape @property def size(self) -> int: r"""Total number of elements in the underlying data structure. Notes ----- If the matrix is stored in redundant form, size is equivalent to ``self.shape[0] * self.shape[1]``. If the matrix is stored in condensed form, size is equal to the number of elements in the condensed array. """ return self._data.size @property def T(self) -> PairwiseMatrix: r"""Transpose of the matrix. See Also -------- transpose """ return self.transpose() def transpose(self) -> PairwiseMatrix: r"""Return the transpose of the matrix. Notes ----- A deep copy is returned. Returns ------- PairwiseMatrix Transpose of the matrix. Will be the same type as ``self``. """ # Note: Skip validation, since we assume self was already validated return self._copy(transpose=True) def index(self, lookup_id: str) -> int: r"""Return the index of the specified ID. Parameters ---------- lookup_id : str ID whose index will be returned. Returns ------- int Row/column index of ``lookup_id``. Raises ------ MissingIDError If ``lookup_id`` is not in the matrix. """ if lookup_id in self: return self._id_index[lookup_id] else: raise MissingIDError(lookup_id) def redundant_form(self) -> NDArray: r"""Return an array of values in redundant form. Returns ------- ndarray Two-dimensional `numpy.ndarray` of values in redundant form. Notes ----- Redundant form is described in [1]_. Does *not* return a copy of the data. References ---------- .. [1] http://docs.scipy.org/doc/scipy/reference/spatial.distance.html """ return self._data def copy(self) -> PairwiseMatrix: r"""Return a deep copy of the matrix. Returns ------- PairwiseMatrix Deep copy of the matrix. Will be the same type as ``self``. """ # We deepcopy IDs in case the tuple contains mutable objects at some # point in the future. # Note: Skip validation, since we assume self was already validated # We deepcopy IDs in case the tuple contains mutable objects at some # point in the future. # Note: Skip validation, since we assume self was already validated return self._copy() def _copy(self, transpose: bool = False, condensed: bool = False) -> PairwiseMatrix: r"""Copy support. Parameters ---------- transpose : bool Whether transpose the data on copy. condensed : bool Placeholder. Always False. Returns ------- PairwiseMatrix Deep copy of the matrix. Will be the same type as ``self``. """ data = self._data.copy() if transpose: data = data.T return self.__class__(data, deepcopy(self.ids), validate=False) def rename(self, mapper: dict | Callable, strict: bool = True) -> None: r"""Rename IDs in the matrix. Parameters ---------- mapper : dict or callable A dictionary or function that maps current IDs to new IDs. strict : bool, optional If True (default), every ID in the matrix must be included in ``mapper``. If False, only the specified IDs will be renamed. Raises ------ ValueError If ``mapper`` does not contain all of the same IDs in the matrix whereas in strict mode. Examples -------- >>> from skbio.stats.distance import PairwiseMatrix >>> dm = PairwiseMatrix([[0, 1], [2, 3]], ids=['a', 'b']) >>> dm.rename({'a': 'x', 'b': 'y'}) >>> print(dm.ids) ('x', 'y') """ if isinstance(mapper, dict): if strict and not set(self.ids).issubset(mapper): raise ValueError( "The IDs in mapper do not include all IDs in the matrix." ) new_ids = tuple(mapper.get(x, x) for x in self.ids) else: new_ids = tuple(mapper(x) for x in self.ids) self.ids = new_ids def filter( self, ids: Sequence[str], strict: bool = True, # , preserve_condensed=True ) -> PairwiseMatrix: r"""Filter the matrix by IDs. Parameters ---------- ids : sequence of str IDs to retain. May not contain duplicates or be empty. Each ID must be present in the matrix. strict : bool, optional If True (default) and an ID that is not found in the distance matrix but is found in ``ids``, a ``MissingIDError`` exception will be raised, otherwise the ID will be ignored. Returns ------- PairwiseMatrix Filtered matrix containing only the IDs specified in ``ids``. IDs will be in the same order as they appear in ``ids``. Raises ------ MissingIDError If an ID in ``ids`` is not in the object's list of IDs. Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. """ if tuple(self._ids) == tuple(ids): if self._flags["CONDENSED"]: return self.__class__(self._data, self._ids, condensed=True) else: return self.__class__(self._data, self._ids) if strict: idxs = [self.index(id_) for id_ in ids] else: # get the indices to slice the inner numpy array idxs = [] # save the IDs that were found in the distance matrix found_ids = [] for id_ in ids: try: idxs.append(self.index(id_)) found_ids.append(id_) except MissingIDError: pass ids = found_ids # Note: Skip validation, since we assume self was already validated # But ids are new, so validate them explicitly if self._flags["CONDENSED"]: filtered_data = distmat_reorder_condensed_py(self.condensed_form(), idxs) self._validate_ids(filtered_data, ids) return self.__class__(filtered_data, ids, validate=False, condensed=True) else: filtered_data = distmat_reorder(self.redundant_form(), idxs) self._validate_ids(filtered_data, ids) return self.__class__(filtered_data, ids, validate=False) def _stable_order(self, ids: Iterable[str]) -> NDArray: """Obtain a stable ID order with respect to self. Parameters ---------- ids : Iterable of ids The IDs to establish a stable ordering for. Returns ------- np.array, dtype=int The corresponding index values. """ id_order = sorted(self._id_index[i] for i in ids) return np.array(id_order, dtype=int) def within(self, ids: Iterable[str]) -> pd.DataFrame: r"""Obtain all the pairwise values among the set of IDs. Parameters ---------- ids : iterable of str The IDs to obtain distances for. All pairs of distances are returned such that, if provided ['a', 'b', 'c'], the distances for [('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'b'), ('b', 'c'), ('c', 'a'), ('c', 'b'), ('c', 'c')] are gathered. Returns ------- pd.DataFrame (i, j, value) representing the source ID ("i"), the target ID ("j") and the distance ("value"). Raises ------ MissingIDError If an ID(s) specified is not in the matrix. Notes ----- Order of the return items is stable, meaning that requesting IDs ['a', 'b'] is equivalent to ['b', 'a']. The order is with respect to the order of the .ids attribute of self. Examples -------- >>> from skbio.stats.distance import PairwiseMatrix >>> dm = PairwiseMatrix([[0, 1, 2, 3, 4], [1, 0, 1, 2, 3], ... [2, 1, 0, 1, 2], [3, 2, 1, 0, 1], ... [4, 3, 2, 1, 0]], ... ['A', 'B', 'C', 'D', 'E']) >>> dm.within(['A', 'B', 'C']) i j value 0 A A 0.0 1 A B 1.0 2 A C 2.0 3 B A 1.0 4 B B 0.0 5 B C 1.0 6 C A 2.0 7 C B 1.0 8 C C 0.0 """ ids = set(ids) not_present = ids - set(self._id_index) if not_present: raise MissingIDError( "At least one ID (e.g., '%s') was not found." % not_present.pop() ) return self._subset_to_dataframe(ids, ids) def between( self, from_: Iterable[str], to_: Iterable[str], allow_overlap: bool = False ) -> pd.DataFrame: r"""Obtain the pairwise values between the two groups of IDs. Parameters ---------- from_ : Iterable of str The IDs to obtain values from. to_ : Iterable of str The IDs to obtain values to. allow_overlap : bool, optional If True, allow overlap in the IDs of from and to (which would in effect be collecting the within distances). Default is False. Returns ------- pd.DataFrame (i, j, value) representing the source ID ("i"), the target ID ("j") and the value between them ("value"). Raises ------ MissingIDError If an ID(s) specified is not in the matrix. Notes ----- Order of the return items is stable, meaning that requesting IDs ['a', 'b'] is equivalent to ['b', 'a']. The order is with respect to the .ids attribute of self. Examples -------- >>> from skbio.stats.distance import PairwiseMatrix >>> dm = PairwiseMatrix([[0, 1, 2, 3, 4], [1, 0, 1, 2, 3], ... [2, 1, 0, 1, 2], [3, 2, 1, 0, 1], ... [4, 3, 2, 1, 0]], ... ['A', 'B', 'C', 'D', 'E']) >>> dm.between(['A', 'B'], ['C', 'D', 'E']) i j value 0 A C 2.0 1 A D 3.0 2 A E 4.0 3 B C 1.0 4 B D 2.0 5 B E 3.0 """ from_ = set(from_) to_ = set(to_) all_ids = from_ | to_ not_present = all_ids - set(self._id_index) if not_present: raise MissingIDError( "At least one ID (e.g., '%s') was not found." % not_present.pop() ) overlapping = from_ & to_ if not allow_overlap and overlapping: raise KeyError( "At least one ID overlaps in from_ and to_ " "(e.g., '%s'). This constraint can removed with " "allow_overlap=True." % overlapping.pop() ) return self._subset_to_dataframe(from_, to_) def _subset_to_dataframe( self, i_ids: Iterable[str], j_ids: Iterable[str] ) -> pd.DataFrame: """Extract a subset of self and express as a DataFrame. Parameters ---------- i_ids : Iterable of str The "from" IDs. j_ids : Iterable of str The "to" IDs. Notes ----- ID membership is not tested by this private method, and it is assumed the caller has asserted the IDs are present. Returns ------- pd.DataFrame (i, j, value) representing the source ID ("i"), the target ID ("j") and the distance ("value"). """ i_indices = self._stable_order(i_ids) j_indices = self._stable_order(j_ids) j_length = len(j_indices) j_labels = tuple(self.ids[j] for j in j_indices) i: list[str] = [] j: list[str] = [] # np.hstack([]) throws a ValueError. However, np.hstack([np.array([])]) # is valid and returns an empty array. Accordingly, an empty array is # included here so that np.hstack works in the event that either i_ids # or j_ids is empty. values = [np.array([])] for i_idx in i_indices: i.extend([self.ids[i_idx]] * j_length) j.extend(j_labels) subset = self._data[i_idx, j_indices] values.append(subset) i = pd.Series(i, name="i", dtype=str) j = pd.Series(j, name="j", dtype=str) values = pd.Series(np.hstack(values), name="value") return pd.concat([i, j, values], axis=1) def plot( self, cmap: str | Colormap | None = None, title: str = "" ) -> matplotlib.figure.Figure: r"""Create a heatmap of the matrix. Parameters ---------- cmap: str or matplotlib.colors.Colormap, optional Sets the color scheme of the heatmap. If None, defaults to the colormap specified in the matplotlib rc file. title: str, optional Sets the title label of the heatmap. Default is blank. Returns ------- matplotlib.figure.Figure Figure containing the heatmap and colorbar of the plotted matrix. Examples -------- .. plot:: Define a matrix with five objects labeled A-E: >>> from skbio.stats.distance import PairwiseMatrix >>> dm = PairwiseMatrix([[0, 1, 2, 3, 4], [1, 0, 1, 2, 3], ... [2, 1, 0, 1, 2], [3, 2, 1, 0, 1], ... [4, 3, 2, 1, 0]], ... ['A', 'B', 'C', 'D', 'E']) Plot the matrix as a heatmap: >>> fig = dm.plot(cmap='Reds', title='Example heatmap') # doctest: +SKIP """ self._get_mpl_plt() # based on http://stackoverflow.com/q/14391959/3776794 fig, ax = self.plt.subplots() # use pcolormesh instead of pcolor for performance heatmap = ax.pcolormesh(self.redundant_form(), cmap=cmap) fig.colorbar(heatmap) # center labels within each cell ticks = np.arange(0.5, self.shape[0]) ax.set_xticks(ticks, minor=False) ax.set_yticks(ticks, minor=False) # Ensure there is no white border around the heatmap by manually # setting the limits ax.set_ylim(0, len(self.ids)) ax.set_xlim(0, len(self.ids)) # display data as it is stored in the pairwise matrix # (default is to have y-axis inverted) ax.invert_yaxis() ax.set_xticklabels(self.ids, rotation=90, minor=False) ax.set_yticklabels(self.ids, minor=False) ax.set_title(title) return fig def to_data_frame(self) -> pd.DataFrame: r"""Create a pandas DataFrame from this matrix. Returns ------- pd.DataFrame DataFrame with IDs on index and columns. Examples -------- >>> from skbio import DistanceMatrix >>> dm = DistanceMatrix([[0, 1, 2], ... [1, 0, 3], ... [2, 3, 0]], ids=['a', 'b', 'c']) >>> df = dm.to_data_frame() >>> df a b c a 0.0 1.0 2.0 b 1.0 0.0 3.0 c 2.0 3.0 0.0 """ return pd.DataFrame( data=self.redundant_form(), index=self.ids, columns=self.ids ) def __str__(self) -> str: r"""Return a string representation of the matrix. Summary includes matrix dimensions, a (truncated) list of IDs, and (truncated) array of values. Returns ------- str String representation of the matrix. """ return "%dx%d %s matrix\nIDs:\n%s\nData:\n" % ( self.shape[0], self.shape[1], self._matrix_element_name, _pprint_strs(self.ids), ) + str(self._data) def __eq__(self, other: object) -> bool: r"""Compare this matrix to another for equality. Two matrices are equal if they have the same shape and IDs (in the same order!), and have data arrays that are equal. Checks are *not* performed to ensure that ``other`` is a ``PairwiseMatrix`` instance. Parameters ---------- other : PairwiseMatrix Matrix to compare to for equality. Returns ------- bool True if ``self`` is equal to ``other``, False otherwise. """ if not isinstance(other, PairwiseMatrix): return NotImplemented equal = True # The order these checks are performed in is important to be as # efficient as possible. The check for shape equality is not strictly # necessary as it should be taken care of in np.array_equal, but I'd # rather explicitly bail before comparing IDs or data. Use array_equal # instead of (a == b).all() because of this issue: # http://stackoverflow.com/a/10582030 try: if self.shape != other.shape: equal = False elif self.ids != other.ids: equal = False elif not np.array_equal(self._data, other.data): equal = False except AttributeError: equal = False return equal def __ne__(self, other: object) -> bool: r"""Determine whether two matrices are not equal. Parameters ---------- other : PairwiseMatrix Matrix to compare to. Returns ------- bool True if ``self`` is not equal to ``other``, False otherwise. See Also -------- __eq__ """ return not self == other def __contains__(self, lookup_id: str) -> bool: r"""Check if the specified ID is in the matrix. Parameters ---------- lookup_id : str ID to search for. Returns ------- bool True if ``lookup_id`` is in the matrix, False otherwise. See Also -------- index """ return lookup_id in self._id_index def __getitem__(self, index: str | tuple[str, str] | Any) -> NDArray | float: r"""Slice into data by object ID or numpy indexing. Extracts data from the matrix by object ID, a pair of IDs, or NumPy indexing/slicing. Parameters ---------- index : str, two-tuple of str, or numpy index Can be one of the following: - A string: Returns the row vector of this ID. - A tuple of two strings: Returns the value between the first ID (row) and the second ID (column). - Otherwise, ``index`` will be passed through to ``.data.__getitem__``, allowing for standard indexing of a NumPy array (e.g., slicing). .. note:: The first ID is the row and the second ID (if provided) is the column. This order matters when the matrix is asymmetric (i.e., ``mat['a', 'b']`` may not be the same as ``mat['b', 'a']``). Returns ------- 1-D ndarray or scalar Indexed data, where return type depends on the form of `index` (see description of `index` for more details). Raises ------ MissingIDError If the ID(s) specified in `index` are not in the matrix. Notes ----- The lookup based on ID(s) is quick. NumPy indexing (slicing) on condensed form matrices will convert them to redundant, roughly doubling their memory requirement. """ if isinstance(index, str): row_idx = self.index(index) return self._data[row_idx] elif isinstance(index, tuple) and self._is_id_pair(index): i, j = self.index(index[0]), self.index(index[1]) return self._data[i, j] else: # NumPy index types are numerous and complex, easier to just # ignore them in type checking. return self._data.__getitem__(index) # type: ignore[index] def _validate_ids(self, data: NDArray, ids: Collection[str]) -> None: """Validate the IDs. Checks that IDs are unique and that the number of IDs matches the number of rows/cols in the data array. Subclasses can override this method to perform different/more specific validation. Notes ----- Accepts arguments instead of inspecting instance attributes to avoid creating an invalid matrix before raising an error. Otherwise, the invalid matrix could be used after the exception is caught and handled. """ duplicates = find_duplicates(ids) if duplicates: formatted_duplicates = ", ".join(repr(e) for e in duplicates) raise PairwiseMatrixError( "IDs must be unique. Found the " "following duplicate IDs: %s" % formatted_duplicates ) if 0 == len(ids): raise PairwiseMatrixError("IDs must be at least 1 in size.") # handle condensed form data if data.ndim == 1: n = _vec_to_shape(data) if len(ids) != n: raise PairwiseMatrixError( "The number of IDs (%d) must match " "the number of rows/columns in the " "data (%d)." % (len(ids), n) ) # handle redundant form data else: if len(ids) != data.shape[0]: raise PairwiseMatrixError( "The number of IDs (%d) must match " "the number of rows/columns in the " "data (%d)." % (len(ids), data.shape[0]) ) def _validate_shape(self, data: NDArray) -> None: """Validate the data array shape. Checks that the data is at least 1x1 in size, 2D, square, and contains only floats. Notes ----- Accepts arguments instead of inspecting instance attributes to avoid creating an invalid matrix before raising an error. Otherwise, the invalid matrix could be used after the exception is caught and handled. """ if 0 in data.shape: raise PairwiseMatrixError("Data must be at least 1x1 in size.") if len(data.shape) != 2: raise PairwiseMatrixError("Data must have exactly two dimensions.") if data.shape[0] != data.shape[1]: raise PairwiseMatrixError( "Data must be square (i.e., have the same number of rows and columns)." ) if data.dtype not in (np.float32, np.float64): raise PairwiseMatrixError("Data must contain only floating point values.") def _index_list(self, list_: Sequence[str]) -> dict: return {id_: idx for idx, id_ in enumerate(list_)} def _is_id_pair(self, index: tuple) -> bool: return len(index) == 2 and all(map(lambda e: isinstance(e, str), index)) class SymmetricMatrix(PairwiseMatrix): r"""Store symmetric pairwise relationships between objects. A ``SymmetricMatrix`` is a ``PairwiseMatrix`` with the additional requirement that the matrix data is symmetric (i.e., upper and lower triangles mirror each other). There are additional methods made available that take advantage of this symmetry. .. versionadded:: 0.7.1 Parameters ---------- data : 1-D or 2-D array_like, or PairwiseMatrix A square 2-D array of pairwise relationships between objects, or a 1-D array representing its condensed form. Can instead be an instance of ``PairwiseMatrix`` or its subclass, in which case its data and IDs will be directly used. ids : sequence of str, optional IDs of the objects. Must match the number of objects in ``data``. If None (default) and ``data`` does not contain IDs, IDs will be monotonically-increasing integers cast as strings, starting from zero (i.e., '0', '1', '2', '3', ...). validate : bool, optional If True (default) and ``data`` is not a ``SymmetricMatrix`` object, the input data will be validated. condensed : bool, optional Store the data in a 2-D redundant form (False, default) or a 1-D condensed form (True). diagonal : 1-D array_like or float, optional Values along the diagonal of the matrix. Can be a vector matching the number of objects in ``data``, or a single number representing a uniform diagonal. Default is zero. Can be provided when ``data`` is in condensed form. Otherwise, an error will be raised. See Also -------- PairwiseMatrix SymmetricMatrix scipy.spatial.distance.squareform """ def __init__( self, data: NDArray | Sequence[float] | Sequence[Sequence[float]] | PairwiseMatrix, ids: Sequence[str] | None = None, validate: bool = True, condensed: bool = False, diagonal: float | NDArray = None, ): ( data, ids, diagonal, validate_data, validate_ids, validate_shape, validate_diagonal, ) = self._normalize_input(data, ids, diagonal) if ids is None: ids = self._generate_ids(data) else: ids = tuple(ids) if validate: if validate_shape: self._validate_shape(data) if validate_ids: self._validate_ids(data, ids) if validate_diagonal: self._validate_diagonal(data, diagonal) if validate_data: self._validate_data(data) self._ids = ids self._id_index = self._index_list(self._ids) self._diagonal = self._init_diagonal(diagonal, data, condensed) self._data = self._init_data(data, condensed) self._flags = self._init_flags(condensed) def _normalize_input(self, data, ids, diagonal): """Get input into standard numpy array format.""" validate_data = True validate_ids = True validate_shape = True validate_diagonal = True if isinstance(data, DistanceMatrix): validate_data = False validate_shape = False # if no new ids then no validation if ids is None: validate_ids = False ids = data.ids # if no new diagonal then no validation if diagonal is None: validate_diagonal = False data = data.data # if it is a symmetric matrix then data doesn't need validation elif isinstance(data, SymmetricMatrix): validate_data = False validate_shape = False # if no new ids then no validation if ids is None: validate_ids = False ids = data.ids # if no new diagonal then no validation if diagonal is None: validate_diagonal = False diagonal = data.diagonal data = data.data elif isinstance(data, PairwiseMatrix): validate_shape = False # PairwiseMatrix will always be 2D, meaning that passing a diagonal will # raise an error, so we can skip validation # validate_diagonal = False if ids is None: validate_ids = False ids = data.ids if diagonal is None: validate_diagonal = False data = data.data # It is necessary to standardize the representation of the .data # attribute of this object. The input types might be list, tuple, # np.array, or possibly some other object type. Generally, this # normalization of type will require a copy of data. For example, # moving from a Python type representation (e.g., [[0, 1], [1, 0]]) # requires casting all of the values to numpy types, which is handled # as an implicit copy via np.asarray. However, these copies are # unnecessary if the data object is already a numpy array. np.asarray # is smart enough to not copy the data, however if a dtype change is # requested it will. The following block of code limits the use of # np.asarray to situations where the data are (a) not already a numpy # array or (b) the data are not a single or double precision numpy # data type. _issue_copy = True if isinstance(data, np.ndarray): if data.dtype in (np.float32, np.float64): _issue_copy = False if _issue_copy: data = np.asarray(data, dtype="float") # Make data_ explicitly an ndarray to help with type checking. # At this point in the code we can be certain that data is an # ndarray. assert isinstance(data, np.ndarray) data_: NDArray = data return ( data_, ids, diagonal, validate_data, validate_ids, validate_shape, validate_diagonal, ) def _init_diagonal( self, diagonal: float | NDArray | None, data: NDArray, condensed: bool ) -> float | NDArray | None: """Initialize the diagonal attribute. Parameters ---------- diagonal : float or np.ndarray The value or values defined along the diagonal of the matrix. data : np.ndarray 1 or 2-dimensional array of the data of the matrix. condensed : bool Whether the matrix is in condensed form. Returns ------- float, np.ndarray, or None The diagonal values of the matrix. """ if diagonal is not None: if np.isscalar(diagonal): if isinstance(diagonal, (float, np.floating)): return diagonal else: return float(diagonal) else: return np.asarray(diagonal) elif condensed: if data.ndim == 1: return 0.0 elif data.ndim == 2: return np.diagonal(data) return None def _init_flags(self, condensed: bool = False) -> dict: """Initialize flags for symmetric matrix. Parameters ---------- condensed : bool Whether the matrix is in condensed form. Returns ------- dict Dictionary containing information on the form of the matrix. """ if condensed: return {"CONDENSED": True} else: return {"CONDENSED": False} def _init_data(self, data: NDArray, condensed: bool = False) -> NDArray: """Initialize data for symmetric matrix. Parameters ---------- data : np.ndarray 1-D or 2-D array representing the data of the matrix. condensed : bool Whether or not to store the data in condensed form. Returns ------- np.ndarray 1-D or 2-D array containing the values of the matrix. """ if condensed: # case where input is 1d and stays 1d if data.ndim == 1: return data # case where input is 2d and is converted to 1d else: return squareform(data, force="tovector", checks=False) else: # case where input is 1d and is converted to 2d. if data.ndim == 1: mat = squareform(data, force="tomatrix", checks=False) if self._diagonal is not None: np.fill_diagonal(mat, self._diagonal) else: np.fill_diagonal(mat, 0.0) return mat # case where input is 2d and stays 2d else: return data def _validate_data(self, data: NDArray) -> None: """Validate the data array. Performs a check for symmetry if data is 2D. If data is 1D it is assumed to be symmetric. """ if (data.ndim != 1) and (not is_symmetric(data)): raise DistanceMatrixError("Data must be symmetric and cannot contain NaNs.") def _validate_diagonal( self, data: NDArray, diagonal: NDArray | None = None ) -> None: """Validate the diagonal of the matrix. Checks that the length of the diagonal matches the shape of the matrix, and that the diagonal is 1D if passed as an array. """ if diagonal is not None: # if data is 2D and diagonal is provided, raise error because unsure # which diagonal to use if data.ndim == 2: raise SymmetricMatrixError( "Cannot provide diagonal when data matrix is 2D. Information " "contained along diagonal is ambiguous." ) # if it's a single value, it doesn't need to be validated if not np.isscalar(diagonal): diagonal = np.array(diagonal) # if it's a nd.array it needs to be 1d if diagonal.ndim != 1: raise SymmetricMatrixError( f"Diagonal must be 1 dimensional if it is an array. Found " f"{diagonal.ndim} dimensions." ) # it also needs to match the size of the matrix length = diagonal.size shape = _vec_to_shape(data) if length != shape: raise SymmetricMatrixError( f"Length of diagonal ({length}) does not match the shape " f"of the matrix {(shape, shape)}." ) def _validate_shape(self, data: NDArray): """Validate the shape of the input data. If the input is 2D, it checks that it is at least 1x1, and that it is square. If the input is 1D, it checks that it is a correct length to represent a symmetric matrix. If input is not 1D or 2D, it raises an error. """ if data.ndim == 2: if 0 in data.shape: raise SymmetricMatrixError("Data must be at least 1x1 in size.") if data.shape[0] != data.shape[1]: raise SymmetricMatrixError( "Data must be square (i.e., have the same number of rows and " "columns)." ) # check that the length of the array is a valid length if 1D elif data.ndim == 1: # pulled from scipy squareform s = data.shape # Grab the closest value to the square root of the number # of elements times 2 to see if the number of elements # is indeed a binomial coefficient. d = int(np.ceil(np.sqrt(s[0] * 2))) # Check that v is of valid dimensions. if d * (d - 1) != s[0] * 2: raise SymmetricMatrixError( "Incompatible vector size. It must be a binomial " "coefficient n choose 2 for some integer n >= 2." ) else: raise SymmetricMatrixError( f"Data must be have either 1 or 2 dimensions. " f"Found {data.ndim} dimensions." ) if data.dtype not in (np.float32, np.float64): raise PairwiseMatrixError("Data must contain only floating point values.") @property def T(self) -> SymmetricMatrix: r"""Transpose of the matrix. If the matrix is in condensed form, a redundant form matrix will be returned. See Also -------- transpose """ return self.transpose() def transpose(self) -> SymmetricMatrix: r"""Return the transpose of the matrix. If the matrix is in condensed form, a redundant form matrix will be returned. Notes ----- A deep copy is returned. Returns ------- SymmetricMatrix Transpose of the matrix. Will be the same type as `self`. """ # Note: Skip validation, since we assume self was already validated return self._copy(transpose=True) @property def diagonal(self) -> float | NDArray: """Diagonal value(s) of the matrix. If diagonal is a float, this value is repeated along the diagonal of the matrix. If diagonal is an array, it represents the full diagonal of the matrix. """ return self._diagonal @classonlymethod def from_iterable( cls, iterable: Iterable[Any], metric: Callable, key: Any | None = None, keys: Iterable[Any] | None = None, validate: bool = True, condensed: bool = False, diagonal: float | ArrayLike = 0.0, ) -> Self: r"""Create a symmetric matrix from an iterable given a metric. Parameters ---------- iterable : iterable Objects to compute pairwise relationships on. metric : callable A function that takes two arguments and returns a float representing the relationship between the two objects. key : callable or str, optional A function that takes one argument and returns a string representing the ID of the object. Alternatively, a key to the ``metadata`` property if exists for each object in the ``iterable``. If None, the default IDs will be used. keys : iterable of str, optional IDs of the objects. Must be the same length as ``iterable``. validate : boolean, optional If True, all pairwise relationships are computed, including upper and lower triangles and the diagonal. If False, ``metric`` is assumed to be symmetric and only the lower triangle (excluding the diagonal) is computed, thereby saving compute. condensed : bool, optional Store the data in a 2-D redundant form (False, default) or a 1-D condensed form (True). diagonal : float or array_like, optional Value(s) with which to fill the diagonal of the matrix. Relevant only when ``validate`` is False. Returns ------- PairwiseMatrix The ``metric`` applied to all pairwise elements in the ``iterable``. Raises ------ ValueError If ``key`` and ``keys`` are both provided. """ iterable = list(iterable) keys_ = _get_keys(iterable, key, keys) dm = np.empty((len(iterable),) * 2) if validate: for i, a in enumerate(iterable): for j, b in enumerate(iterable): dm[i, j] = metric(a, b) else: # This assumes that metric will return a symmetric matrix. That is, that # metric(a, b) is the same as metric(b, a) for i, a in enumerate(iterable): for j, b in enumerate(iterable[:i]): dm[i, j] = dm[j, i] = metric(a, b) np.fill_diagonal(dm, diagonal) return cls(dm, keys_, condensed=condensed) # type: ignore[operator] def __getitem__(self, index: str | tuple[str, str] | Any) -> NDArray | float: r"""Slice into data by object ID or NumPy indexing. Extracts data from the matrix by object ID, a pair of IDs, or NumPy indexing/slicing. Parameters ---------- index : str, two-tuple of str, or NumPy index Can be one of the following: - A string: Returns the row vector of this ID. - A tuple of two strings: Returns the value between the first ID (row) and the second ID (column). - Otherwise, ``index`` will be passed through to ``.data.__getitem__``, allowing for standard indexing of a NumPy array (e.g., slicing). Returns ------- ndarray or scalar Indexed data, where return type depends on the form of ``index`` (see description of ``index`` for more details). Raises ------ MissingIDError If the ID(s) specified in ``index`` are not in the matrix. Notes ----- The lookup based on ID(s) is quick. NumPy indexing (slicing) on condensed form matrices will convert them to redundant, roughly doubling their memory requirement. """ if isinstance(index, str): row_idx = self.index(index) if self._flags["CONDENSED"]: return _get_row_from_condensed( self._data, row_idx, self.shape[0], self._diagonal ) else: return self._data[row_idx] elif isinstance(index, tuple) and self._is_id_pair(index): i, j = self.index(index[0]), self.index(index[1]) if self._flags["CONDENSED"]: return _get_element_from_condensed( self._data, i, j, self.shape[0], self._diagonal ) else: return self._data[i, j] else: # NumPy index types are numerous and complex, easier to just # ignore them in type checking. # revert to redundant form to handle numpy style indexing if self._flags["CONDENSED"]: return self.redundant_form().__getitem__(index) else: return self._data.__getitem__(index) # type: ignore[index] def as_redundant(self) -> SymmetricMatrix: """Return a redundant form deep copy of the matrix. Returns ------- SymmetricMatrix A new matrix object with the same data stored in redundant form. See Also -------- redundant_form condensed_form as_condensed Notes ----- This method always returns a new matrix object, even if the matrix is already in redundant form. The new matrix object is a deep copy of the original matrix. Examples -------- Convert from condensed form to redundant form: >>> from skbio.stats.distance import SymmetricMatrix >>> sm_condensed = SymmetricMatrix([1, 2, 3], ... ids=['a', 'b', 'c'], ... condensed=True) >>> sm_condensed.data array([ 1., 2., 3.]) >>> sm_square = sm_condensed.as_redundant() >>> sm_square.data array([[ 0., 1., 2.], [ 1., 0., 3.], [ 2., 3., 0.]]) """ return self._copy(condensed=False) def redundant_form(self) -> NDArray: r"""Return an array of values in redundant format. Returns ------- ndarray Two-dimensional array of values in redundant format. See Also -------- as_redundant condensed_form as_condensed Examples -------- Create a symmetric matrix in condensed form and expand to square form: >>> from skbio.stats.distance import SymmetricMatrix >>> sm = SymmetricMatrix([1, 2, 3], ids=['a', 'b', 'c'], condensed=True) >>> sm.data array([ 1., 2., 3.]) >>> sm.redundant_form() array([[ 0., 1., 2.], [ 1., 0., 3.], [ 2., 3., 0.]]) """ if self._flags["CONDENSED"]: mat = squareform(self._data, force="tomatrix", checks=False) np.fill_diagonal(mat, self._diagonal) return mat else: return self._data def as_condensed(self) -> SymmetricMatrix: """Return a condensed form deep copy of the matrix. Returns ------- SymmetricMatrix A new matrix object with the same data stored in condensed form. See Also -------- condensed_form redundant_form as_redundant Notes ----- This method always returns a new matrix object, even if the matrix is already in condensed form. The new matrix object is a deep copy of the original matrix. This format is compatible with SciPy’s :func:`scipy.spatial.distance.squareform`. Examples -------- >>> from skbio.stats.distance import SymmetricMatrix >>> sm = SymmetricMatrix([[0, 1, 2], ... [1, 0, 3], ... [2, 3, 0]], ids=['a', 'b', 'c']) >>> sm_condensed = sm.as_condensed() >>> sm_condensed.data array([ 1., 2., 3.]) """ return self._copy(condensed=True) def condensed_form(self) -> NDArray: r"""Return an array of distances in condensed format. Returns ------- data : ndarray One-dimensional `numpy.ndarray` of values in condensed format. See Also -------- as_condensed redundant_form as_redundant Notes ----- Condensed format is described in [1]_. The conversion is not a constant-time operation, though it should be relatively quick to perform. Examples -------- >>> from skbio.stats.distance import SymmetricMatrix >>> sm = SymmetricMatrix([[0, 1, 2], ... [1, 0, 3], ... [2, 3, 0]], ids=['a', 'b', 'c']) >>> sm.condensed_form() array([ 1., 2., 3.]) References ---------- .. [1] http://docs.scipy.org/doc/scipy/reference/spatial.distance.html """ if self._flags["CONDENSED"]: return self._data else: return squareform(self._data, force="tovector", checks=False) def permute( self, condensed: bool = False, seed: SeedLike | None = None, ) -> SymmetricMatrix | NDArray: r"""Randomly permute both rows and columns in the matrix. Randomly permutes the ordering of rows and columns in the matrix. The same permutation is applied to both rows and columns in order to maintain symmetry and, if applicable, hollowness. Only the rows/columns in the matrix are permuted; the IDs are *not* permuted. Parameters ---------- condensed : bool, optional If ``True``, return the permuted distance matrix in condensed format. Otherwise, return the permuted distance matrix as a new ``SymmetricMatrix`` instance. Can only be ``True`` if operating on a ``DistanceMatrix``. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- SymmetricMatrix or ndarray Permuted values as a new ``DistanceMatrix`` or as a ``ndarray`` in condensed format. See Also -------- condensed_form Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. This method does not modify the distance matrix that it is called on. It is more efficient to pass ``condensed=True`` than permuting the distance matrix and then converting to condensed format. """ rng = get_rng(seed) order = rng.permutation(self.shape[0]) if condensed: # if self.__class__ != DistanceMatrix: # raise TypeError("Only distance matrices can return condensed.") if self._flags["CONDENSED"]: permuted_condensed = distmat_reorder_condensed_py(self._data, order) else: permuted_condensed = distmat_reorder_condensed(self._data, order) return permuted_condensed else: # Note: Skip validation, since we assume self was already validated if self._flags["CONDENSED"]: permuted = distmat_reorder_condensed_py(self._data, order) return self.__class__( permuted, self.ids, validate=False, condensed=True ) else: permuted = distmat_reorder(self._data, order) return self.__class__(permuted, self.ids, validate=False) def copy(self) -> SymmetricMatrix: r"""Return a deep copy of the symmetric matrix. Returns ------- SymmetricMatrix Deep copy of the matrix. Will be the same type as ``self``. """ if self._flags["CONDENSED"]: return self._copy(condensed=True) else: return self._copy() def _copy( self, transpose: bool = False, condensed: bool = False ) -> SymmetricMatrix: """Copy support. Parameters ---------- transpose : bool Placeholder. Always False. condensed : bool Whether the matrix is in condensed form. Returns ------- SymmetricMatrix """ # adding for backward compatibility data = self._data.copy() # We deepcopy IDs in case the tuple contains mutable objects at some # point in the future. # Note: Skip validation, since we assume self was already validated return self.__class__( data, deepcopy(self.ids), diagonal=deepcopy(self._diagonal), validate=False, condensed=condensed, ) def _subset_to_dataframe( self, i_ids: Iterable[str], j_ids: Iterable[str] ) -> pd.DataFrame: """Extract a subset of self and express as a DataFrame. Parameters ---------- i_ids : Iterable of str The "from" IDs. j_ids : Iterable of str The "to" IDs. Notes ----- ID membership is not tested by this private method, and it is assumed the caller has asserted the IDs are present. Returns ------- pd.DataFrame (i, j, value) representing the source ID ("i"), the target ID ("j") and the distance ("value"). """ i_indices = self._stable_order(i_ids) j_indices = self._stable_order(j_ids) j_length = len(j_indices) j_labels = tuple(self.ids[j] for j in j_indices) i: list[str] = [] j: list[str] = [] # np.hstack([]) throws a ValueError. However, np.hstack([np.array([])]) # is valid and returns an empty array. Accordingly, an empty array is # included here so that np.hstack works in the event that either i_ids # or j_ids is empty. values = [np.array([])] if self._flags["CONDENSED"]: diagonal = getattr(self, "_diagonal", 0.0) if diag_is_array := isinstance(diagonal, np.ndarray): diag_arr = diagonal n = self.shape[0] # precompute to avoid repeated calculations condensed_indices = {} for i_idx in i_indices: for j_idx in j_indices: if i_idx == j_idx: continue key = (min(i_idx, j_idx), max(i_idx, j_idx)) if key not in condensed_indices: condensed_indices[key] = _condensed_index(key[0], key[1], n) for i_idx in i_indices: diag_ = diag_arr[i_idx] if diag_is_array else diagonal i.extend([self.ids[i_idx]] * j_length) j.extend(j_labels) subset_values = np.zeros(j_length, dtype=self._data.dtype) for idx, j_idx in enumerate(j_indices): if i_idx == j_idx: subset_values[idx] = diag_ else: key = (min(i_idx, j_idx), max(i_idx, j_idx)) subset_values[idx] = self._data[condensed_indices[key]] values.append(subset_values) # redundant form else: for i_idx in i_indices: i.extend([self.ids[i_idx]] * j_length) j.extend(j_labels) subset = self._data[i_idx, j_indices] values.append(subset) i = pd.Series(i, name="i", dtype=str) j = pd.Series(j, name="j", dtype=str) values = pd.Series(np.hstack(values), name="value") return pd.concat([i, j, values], axis=1) class DistanceMatrix(SymmetricMatrix): r"""Store distances between objects. A ``DistanceMatrix`` is a ``SymmetricMatrix`` with the additional requirement that the matrix data is hollow (i.e., diagonal is zero). There are additional methods made available that take advantage of this hollowness. Parameters ---------- data : 1-D or 2-D array_like, or PairwiseMatrix A square 2-D array of pairwise distances between objects, or a 1-D array representing its condensed form. Can instead be an instance of ``PairwiseMatrix`` or its subclass, in which case its data and IDs will be directly used. ids : sequence of str, optional IDs of the objects. Must match the number of rows/columns in ``data``. If None (default) and ``data`` does not contain IDs, IDs will be monotonically-increasing integers cast as strings, starting from zero (i.e., '0', '1', '2', '3', ...). validate : bool, optional If True (default) and ``data`` is not a ``DistanceMatrix`` object, the input data will be validated. condensed : bool, optional Store the data in a 2-D redundant form (False, default) or a 1-D condensed form (True). diagonal : 1-D array_like or float, optional Values along the diagonal of the matrix. Must be zero. This parameter is a placeholder for interface compatibility with ``SymmetricMatrix``. See Also -------- PairwiseMatrix SymmetricMatrix scipy.spatial.distance.pdist scipy.spatial.distance.squareform Notes ----- The distances are stored in redundant (square-form) format [1]_. To facilitate use with other scientific Python routines (e.g., scipy), the distances can be retrieved in condensed (vector-form) format using ``condensed_form``. ``DistanceMatrix`` only requires that the distances it stores are symmetric and hollow. Checks are *not* performed to ensure the other three metric properties hold (non-negativity, identity of indiscernibles, and triangle inequality) [2]_. Thus, a ``DistanceMatrix`` instance can store distances that are not metric. References ---------- .. [1] http://docs.scipy.org/doc/scipy/reference/spatial.distance.html .. [2] http://planetmath.org/metricspace """ # Override here, used in superclass __str__ _matrix_element_name: ClassVar[str] = "distance" read = Read() write = Write() def __init__( self, data: NDArray | Sequence[float] | Sequence[Sequence[float]] | PairwiseMatrix, ids: Sequence[str] | None = None, validate: bool = True, condensed: bool = False, ): data, ids, validate_data, validate_ids, validate_shape = self._normalize_input( data, ids ) if ids is None: ids = self._generate_ids(data) else: ids = tuple(ids) if validate: if validate_shape: self._validate_shape(data) if validate_ids: self._validate_ids(data, ids) if validate_data: self._validate_data(data) self._ids = ids self._id_index = self._index_list(self._ids) self._diagonal = 0.0 self._data = self._init_data(data, condensed) self._flags = self._init_flags(condensed) def _normalize_input(self, data, ids): """Get input into standard numpy array format.""" validate_data = True validate_ids = True validate_shape = True # ids = data.ids if ids is None else ids # if it's a distance matrix we can assume it's already been checked for symmetry # and hollowness if isinstance(data, DistanceMatrix): validate_data = False validate_shape = False # but if new ids are provided then we need to validate them if ids is None: validate_ids = False ids = data.ids data = data.data # need to validate data if it's coming from a SymmetricMatrix or PairwiseMatrix elif isinstance(data, PairwiseMatrix): validate_shape = False # validate new ids if they are provided if ids is None: validate_ids = False ids = data.ids data = data.data # It is necessary to standardize the representation of the .data # attribute of this object. The input types might be list, tuple, # np.array, or possibly some other object type. Generally, this # normalization of type will require a copy of data. For example, # moving from a Python type representation (e.g., [[0, 1], [1, 0]]) # requires casting all of the values to numpy types, which is handled # as an implicit copy via np.asarray. However, these copies are # unnecessary if the data object is already a numpy array. np.asarray # is smart enough to not copy the data, however if a dtype change is # requested it will. The following block of code limits the use of # np.asarray to situations where the data are (a) not already a numpy # array or (b) the data are not a single or double precision numpy # data type. _issue_copy = True if isinstance(data, np.ndarray): if data.dtype in (np.float32, np.float64): _issue_copy = False if _issue_copy: data = np.asarray(data, dtype="float") # Make data_ explicitly an ndarray to help with type checking. # At this point in the code we can be certain that data is an # ndarray. assert isinstance(data, np.ndarray) data_: NDArray = data return data_, ids, validate_data, validate_ids, validate_shape def _validate_data(self, data: NDArray) -> None: """Validate the data array. Performs a check for symmetry and hollowness. """ # if the input data is 1D, we don't need to check for hollowness or symmetry if data.ndim == 2: data_sym, data_hol = is_symmetric_and_hollow(data) if not data_sym: raise DistanceMatrixError( "Data must be symmetric and cannot contain NaNs." ) if not data_hol: raise DistanceMatrixError( "Data must be hollow (i.e., the diagonal can only contain zeros)." ) def _copy(self, transpose: bool = False, condensed: bool = False) -> DistanceMatrix: """Copy support. Parameters ---------- transpose : bool Placeholder. Always False. condensed : bool Whether the matrix is in condensed form. Returns ------- DistanceMatrix """ # adding for backward compatibility data = self._data.copy() if transpose: data = data.T # We deepcopy IDs in case the tuple contains mutable objects at some # point in the future. # Note: Skip validation, since we assume self was already validated return self.__class__( data, deepcopy(self.ids), validate=False, condensed=condensed, ) def to_series(self) -> pd.Series: """Create a pandas Series from this ``DistanceMatrix``. The series will contain distances in condensed form: only distances from one matrix triangle are included, and the diagonal is excluded. The series' index will be a :class:`pandas.MultiIndex` relating pairs of IDs to distances. The pairs of IDs will be in row-major order with respect to the upper matrix triangle. To obtain all distances (i.e. both upper and lower matrix triangles and the diagonal), use :meth:`to_data_frame`. To obtain *only* the distances in condensed form (e.g. for use with SciPy), use :meth:`condensed_form`. Returns ------- pd.Series Series with pairs of IDs on the index. See Also -------- to_data_frame condensed_form scipy.spatial.distance.squareform Examples -------- >>> from skbio import DistanceMatrix >>> dm = DistanceMatrix([[0, 1, 2, 3], ... [1, 0, 4, 5], ... [2, 4, 0, 6], ... [3, 5, 6, 0]], ids=['a', 'b', 'c', 'd']) >>> dm.to_series() a b 1.0 c 2.0 d 3.0 b c 4.0 d 5.0 c d 6.0 dtype: float64 """ distances = self.condensed_form() # `id_pairs` will not be interpreted as a `pd.MultiIndex` if it is an # iterable returned by `combinations`. id_pairs = list(combinations(self.ids, 2)) index = pd.Index(id_pairs, tupleize_cols=True) return pd.Series(data=distances, index=index, dtype=float) def randdm( num_objects: int, ids: Sequence[str] | None = None, constructor: Type[PairwiseMatrix | DistanceMatrix] | None = None, random_fn: int | Generator | Callable | None = None, ) -> PairwiseMatrix: r"""Generate a distance matrix populated with random distances. Using the default ``random_fn``, distances are randomly drawn from a uniform distribution over ``[0, 1)``. Regardless of ``random_fn``, the resulting distance matrix is guaranteed to be symmetric and hollow. Parameters ---------- num_objects : int The number of objects in the resulting distance matrix. For example, if ``num_objects`` is 3, a 3x3 distance matrix will be returned. ids : sequence of str or None, optional A sequence of strings to be used as IDs. ``len(ids)`` must be equal to ``num_objects``. If not provided, IDs will be monotonically-increasing integers cast as strings (numbering starts at 1). For example, ``('1', '2', '3')``. constructor : type, optional ``PairwiseMatrix`` or its subclass to use when creating the random distance matrix. The returned matrix will be of this type. By default, a ``DistanceMatrix`` instance will be returned. random_fn : int, np.random.Generator or callable, optional Function for generating random values. It must accept (n_rows, n_columns) and return a 2D array of float-like. Default is the :meth:`~numpy.random.Generator.random` method of a NumPy random generator. If an integer is provided, a random generator will be constructed using this number as the seed. .. versionchanged:: 0.6.3 Switched to NumPy's new random generator. Can accept a random seed or random generator instance. The function takes one tuple parameter instead of two separate parameters. Returns ------- PairwiseMatrix ``PairwiseMatrix`` (or subclass) instance of random distances. Type depends on ``constructor``. See Also -------- numpy.random.Generator.random """ if constructor is None: constructor = DistanceMatrix if not callable(random_fn): random_fn = get_rng(random_fn).random assert callable(random_fn) data = np.tril(random_fn((num_objects, num_objects)), -1) data += data.T if not ids: ids = tuple(map(str, range(1, num_objects + 1))) return constructor(data, ids) # helper functions for anosim and permanova def _preprocess_input_sng( ids: Sequence, sample_size: int, grouping: pd.DataFrame | Sequence, column: str | None, ) -> tuple: """Compute intermediate results not affected by permutations. These intermediate results can be computed a single time for efficiency, regardless of grouping vector permutations (i.e., when calculating the p-value). These intermediate results are used by both ANOSIM and PERMANOVA. Also validates and normalizes input (e.g., converting ``DataFrame`` column into grouping vector). """ if isinstance(grouping, pd.DataFrame): if column is None: raise ValueError("Must provide a column name if supplying a DataFrame.") else: grouping = _df_to_vector(ids, grouping, column) elif isinstance(grouping, pd.Series): if (column is not None) and (column != grouping.name): raise ValueError( "Column name does not match your Series name. Try not" " providing column at all." ) else: grouping = _df_to_vector(ids, grouping.to_frame(), column=grouping.name) elif column is not None: raise ValueError("Must provide a DataFrame if supplying a column name.") if len(grouping) != sample_size: raise ValueError( "Grouping vector size must match the number of IDs in the distance matrix." ) # Find the group labels and convert grouping to an integer vector # (factor). groups, grouping = np.unique(grouping, return_inverse=True) num_groups = len(groups) if num_groups == len(grouping): raise ValueError( "All values in the grouping vector are unique. This method cannot " "operate on a grouping vector with only unique values (e.g., " "there are no 'within' distances because each group of objects " "contains only a single object)." ) if num_groups == 1: raise ValueError( "All values in the grouping vector are the same. This method " "cannot operate on a grouping vector with only a single group of " "objects (e.g., there are no 'between' distances because there is " "only a single group)." ) return num_groups, grouping def _preprocess_input( distance_matrix: DistanceMatrix, grouping: pd.DataFrame | Sequence, column: str | None, ) -> tuple: """Compute intermediate results not affected by permutations. These intermediate results can be computed a single time for efficiency, regardless of grouping vector permutations (i.e., when calculating the p-value). These intermediate results are used by both ANOSIM and PERMANOVA. Also validates and normalizes input (e.g., converting ``DataFrame`` column into grouping vector). """ if not isinstance(distance_matrix, DistanceMatrix): raise TypeError("Input must be a DistanceMatrix.") # The if statements are redundant here if I keep the modifications I've made to # self.shape, which take advantage of the self._flags dictionary # handle redundant form # if distance_matrix.data.ndim == 2: sample_size = distance_matrix.shape[0] # handle condensed form # if distance_matrix.data.ndim == 1: # sample_size = _vec_to_shape(distance_matrix.data) num_groups, grouping = _preprocess_input_sng( distance_matrix.ids, sample_size, grouping, column ) tri_idxs = np.triu_indices(sample_size, k=1) distances = distance_matrix.condensed_form() return sample_size, num_groups, grouping, tri_idxs, distances def _df_to_vector(ids: Sequence, df: pd.DataFrame, column: str) -> list: """Return a grouping vector from a ``DataFrame`` column. Parameters ---------- ids : Sequence IDs that will be mapped to group labels. df : pandas.DataFrame DataFrame (indexed by distance matrix ID). column : str Column name in `df` containing group labels. Returns ------- list Grouping vector (vector of labels) based on the IDs in `ids`. Each ID's label is looked up in the ``DataFrame`` under the column specified by `column`. Raises ------ ValueError If `column` is not in the ``DataFrame``, or a distance matrix ID is not in the ``DataFrame``. """ if column not in df: raise ValueError("Column '%s' not in DataFrame." % column) grouping = df.reindex(ids, axis=0).loc[:, column] if grouping.isnull().any(): raise ValueError( "One or more IDs in the distance matrix are not in the data frame." ) return grouping.tolist() def _run_monte_carlo_stats( test_stat_function: Callable, grouping: pd.DataFrame | Sequence, permutations: int, seed: SeedLike | None = None, ) -> tuple: """Run stat test and compute significance with Monte Carlo permutations.""" if permutations < 0: raise ValueError( "Number of permutations must be greater than or equal to zero." ) stat = test_stat_function(grouping) rng = get_rng(seed) p_value = np.nan if permutations > 0: perm_stats: NDArray = np.empty(permutations, dtype=np.float64) for i in range(permutations): perm_grouping = rng.permutation(grouping) perm_stats[i] = test_stat_function(perm_grouping) p_value = ((perm_stats >= stat).sum() + 1) / (permutations + 1) return stat, p_value def _build_results( method_name: str, test_stat_name: str, sample_size: int, num_groups: int, stat: float, p_value: float, permutations: int, ) -> pd.Series: """Return ``pandas.Series`` containing results of statistical test.""" return pd.Series( data=[ method_name, test_stat_name, sample_size, num_groups, stat, p_value, permutations, ], index=[ "method name", "test statistic name", "sample size", "number of groups", "test statistic", "p-value", "number of permutations", ], name="%s results" % method_name, ) def _vec_to_shape(vec: NDArray) -> int: r"""Calculate the redundant shape of a matrix given its condensed vector. For an :math:`n \times n` symmetric matrix stored in condensed form (upper triangular, excluding diagonal), this function recovers the dimension :math:`n` from the number of elements :math:`k` in the condensed vector. The mathematical relationship is: .. math:: k = \frac{n(n-1)}{2} Solving for :math:`n` using the quadratic formula: .. math:: n = \frac{1 + \sqrt{1 + 8k}}{2} """ return int((1 + np.sqrt(1 + 8 * len(vec))) / 2) def _condensed_index(i: int | NDArray, j: int | NDArray, n: int) -> int | NDArray: """Get indices for condensed form from redundant form indices. Parameters ---------- i, j : int or np.ndarray Matrix coordinates. Can be scalars or arrays. n : int Sample size of the square matrix. Returns ------- int or np.ndarray Index/indices in the condensed form vector. """ is_scalar = np.isscalar(i) and np.isscalar(j) i_arr = np.asarray(i) j_arr = np.asarray(j) swap_mask = i_arr > j_arr if np.any(swap_mask): i_min = np.where(swap_mask, j_arr, i_arr) j_max = np.where(swap_mask, i_arr, j_arr) else: i_min = i_arr j_max = j_arr result = i_min * n + j_max - ((i_min + 2) * (i_min + 1)) // 2 if is_scalar: return int(result) return result def distmat_reorder_condensed_py(in_mat, reorder_vec): """Pure Python implementation of distmat_reorder for condensed matrices. Parameters ---------- in_mat : np.ndarray 1D condensed form of the matrix. reorder_vec : np.ndarray 1D list of permutation indexes. Returns ------- np.ndarray Condensed matrix. """ reorder_vec = np.asarray(reorder_vec) in_mat = np.asarray(in_mat) n_original = _vec_to_shape(in_mat) n_filtered = len(reorder_vec) # -1 here to exclude the diagonal out_size = n_filtered * (n_filtered - 1) // 2 if out_size == 0: return np.array([], dtype=in_mat.dtype) i_indices, j_indices = np.triu_indices(n_filtered, k=1) old_i = reorder_vec[i_indices] old_j = reorder_vec[j_indices] old_indices = _condensed_index(old_i, old_j, n_original) return in_mat[old_indices] def _get_keys(iterable, key, keys): """Get IDs in the matrix.""" if key is not None and keys is not None: raise ValueError("Cannot use both `key` and `keys` at the same time.") keys_ = None if key is not None: keys_ = [resolve_key(e, key) for e in iterable] elif keys is not None: keys_ = list(keys) return keys_ def _get_element_from_condensed( condensed_data: NDArray, i: int, j: int, n: int, diagonal: float | NDArray ) -> float | np.floating: """Get a single element from condensed storage. Parameters ---------- condensed_data : np.ndarray 1-dimensional vector form of the matrix. i : int Row index. j : int Column index. n : int Sample size of the square matrix. diagonal : float or np.ndarray If float, this value is repeated along the diagonal of the matrix. If array, this array represents the diagonal of the matrix. Returns ------- float The value at position (i, j). """ if i == j: if isinstance(diagonal, (float, np.floating)): return diagonal else: return diagonal[i] condensed_idx = _condensed_index(i, j, n) return condensed_data[condensed_idx] def _get_row_from_condensed( condensed_data: NDArray, row_idx: int, n: int, diagonal: float | NDArray ) -> NDArray: """Extract a full row from condensed storage. Parameters ---------- condensed_data : np.ndarray Condensed vector form of the matrix. row_idx : int Row index of the desired row. n : int Sample size of the square matrix. diagonal : np.ndarray Array of values found on the diagonal of the matrix. Returns ------- np.ndarray The row data for the desired index. """ row = np.empty(n, dtype=condensed_data.dtype) # fill in diagonal value if isinstance(diagonal, (float, np.floating)): row[row_idx] = diagonal else: row[row_idx] = diagonal[row_idx] # elements before diagonal: j < row_idx j_before = np.arange(row_idx) if len(j_before) > 0: row[j_before] = condensed_data[_condensed_index(j_before, row_idx, n)] # elements after diagonal: j > row_idx j_after = np.arange(row_idx + 1, n) if len(j_after) > 0: row[j_after] = condensed_data[_condensed_index(row_idx, j_after, n)] return row # Alias `DissimilarityMatrix` for backward compatibility # test whether documentation gets built twice with this DissimilarityMatrix = PairwiseMatrix DissimilarityMatrixError = PairwiseMatrixError scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/_bioenv.py000066400000000000000000000222361520735541300244120ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from itertools import combinations import numpy as np import pandas as pd from scipy.spatial.distance import pdist from scipy.stats import spearmanr from skbio.stats.distance import DistanceMatrix from skbio.util._decorator import params_aliased @params_aliased([("distmat", "distance_matrix", "0.7.0", False)]) def bioenv(distmat, data_frame, columns=None): r"""Find subset of variables maximally correlated with distances. Finds subsets of variables whose Euclidean distances (after scaling the variables; see Notes section below for details) are maximally rank-correlated with the distance matrix. For example, the distance matrix might contain distances between communities, and the variables might be numeric environmental variables (e.g., pH). Correlation between the community distance matrix and Euclidean environmental distance matrix is computed using Spearman's rank correlation coefficient (:math:`\\rho`). Subsets of environmental variables range in size from 1 to the total number of variables (inclusive). For example, if there are 3 variables, the "best" variable subsets will be computed for subset sizes 1, 2, and 3. The "best" subset is chosen by computing the correlation between the community distance matrix and all possible Euclidean environmental distance matrices at the given subset size. The combination of environmental variables with maximum correlation is chosen as the "best" subset. Parameters ---------- distmat : DistanceMatrix Distance matrix containing distances between objects (e.g., distances between samples of microbial communities). data_frame : pandas.DataFrame Contains columns of variables (e.g., numeric environmental variables such as pH) associated with the objects in `distmat`. Must be indexed by the IDs in `distmat` (i.e., the row labels must be distance matrix IDs), but the order of IDs between `distmat` and `data_frame` need not be the same. All IDs in the distance matrix must be present in `data_frame`. Extra IDs in `data_frame` are allowed (they are ignored in the calculations). columns : iterable of strs, optional Column names in `data_frame` to include as variables in the calculations. If not provided, defaults to all columns in `data_frame`. The values in each column must be numeric or convertible to a numeric type. Returns ------- pandas.DataFrame Data frame containing the "best" subset of variables at each subset size, as well as the correlation coefficient of each. Raises ------ TypeError If invalid input types are provided, or if one or more specified columns in `data_frame` are not numeric. ValueError If column name(s) or `distmat` IDs cannot be found in `data_frame`, if there is missing data (``NaN``) in the environmental variables, or if the environmental variables cannot be scaled (e.g., due to zero variance). See Also -------- scipy.stats.spearmanr Notes ----- See [1]_ for the original method reference (originally called BIO-ENV). The general algorithm and interface are similar to ``vegan::bioenv``, available in R's vegan package [2]_. This method can also be found in PRIMER-E [3]_ (originally called BIO-ENV, but is now called BEST). .. warning:: This method can take a *long* time to run if a large number of variables are specified, as all possible subsets are evaluated at each subset size. The variables are scaled before computing the Euclidean distance: each column is centered and then scaled by its standard deviation. References ---------- .. [1] Clarke, K. R & Ainsworth, M. 1993. "A method of linking multivariate community structure to environmental variables". Marine Ecology Progress Series, 92, 205-219. .. [2] http://cran.r-project.org/web/packages/vegan/index.html .. [3] http://www.primer-e.com/primer.htm Examples -------- Import the functionality we'll use in the following examples: >>> import pandas as pd >>> from skbio import DistanceMatrix >>> from skbio.stats.distance import bioenv Load a 4x4 community distance matrix: >>> dm = DistanceMatrix([[0.0, 0.5, 0.25, 0.75], ... [0.5, 0.0, 0.1, 0.42], ... [0.25, 0.1, 0.0, 0.33], ... [0.75, 0.42, 0.33, 0.0]], ... ['A', 'B', 'C', 'D']) Load a ``pandas.DataFrame`` with two environmental variables, pH and elevation: >>> df = pd.DataFrame([[7.0, 400], ... [8.0, 530], ... [7.5, 450], ... [8.5, 810]], ... index=['A','B','C','D'], ... columns=['pH', 'Elevation']) Note that the data frame is indexed with the same IDs (``'A'``, ``'B'``, ``'C'``, and ``'D'``) that are in the distance matrix. This is necessary in order to link the environmental variables (metadata) to each of the objects in the distance matrix. In this example, the IDs appear in the same order in both the distance matrix and data frame, but this is not necessary. Find the best subsets of environmental variables that are correlated with community distances: >>> bioenv(dm, df) # doctest: +NORMALIZE_WHITESPACE size correlation vars pH 1 0.771517 pH, Elevation 2 0.714286 We see that in this simple example, pH alone is maximally rank-correlated with the community distances (:math:`\rho=0.771517`). """ if not isinstance(distmat, DistanceMatrix): raise TypeError("Must provide a DistanceMatrix as input.") if not isinstance(data_frame, pd.DataFrame): raise TypeError("Must provide a pandas.DataFrame as input.") if columns is None: columns = data_frame.columns.values.tolist() if len(set(columns)) != len(columns): raise ValueError("Duplicate column names are not supported.") if len(columns) < 1: raise ValueError("Must provide at least one column.") for column in columns: if column not in data_frame: raise ValueError("Column '%s' not in data frame." % column) # Subset and order the vars data frame to match the IDs in the distance # matrix, only keeping the specified columns. vars_df = data_frame.reindex(distmat.ids, axis=0).loc[:, columns] if vars_df.isnull().any().any(): raise ValueError( "One or more IDs in the distance matrix are not " "in the data frame, or there is missing data in the " "data frame." ) try: vars_df = vars_df.astype(float) except ValueError: raise TypeError("All specified columns in the data frame must be numeric.") # Scale the vars and extract the underlying numpy array from the data # frame. We mainly do this for performance as we'll be taking subsets of # columns within a tight loop and using a numpy array ends up being ~2x # faster. vars_array = _scale(vars_df).values dm_flat = distmat.condensed_form() num_vars = len(columns) var_idxs = np.arange(num_vars) # For each subset size, store the best combination of variables: # (string identifying best vars, subset size, rho) max_rhos = np.empty( num_vars, dtype=[("vars", object), ("size", int), ("correlation", float)] ) for subset_size in range(1, num_vars + 1): max_rho = None for subset_idxs in combinations(var_idxs, subset_size): # Compute Euclidean distances using the current subset of # variables. pdist returns the distances in condensed form. vars_dm_flat = pdist(vars_array[:, subset_idxs], metric="euclidean") rho = spearmanr(dm_flat, vars_dm_flat)[0] # If there are ties for the best rho at a given subset size, choose # the first one in order to match vegan::bioenv's behavior. if max_rho is None or rho > max_rho[0]: max_rho = (rho, subset_idxs) vars_label = ", ".join([columns[i] for i in max_rho[1]]) max_rhos[subset_size - 1] = (vars_label, subset_size, max_rho[0]) return pd.DataFrame.from_records(max_rhos, index="vars") def _scale(df): """Center and scale each column in a data frame. Each column is centered (by subtracting the mean) and then scaled by its standard deviation. """ # Modified from http://stackoverflow.com/a/18005745 df = df.copy() df -= df.mean() df /= df.std() if df.isnull().any().any(): raise ValueError( "Column(s) in the data frame could not be scaled, " "likely because the column(s) had no variance." ) return df scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/_cutils.pyx000066400000000000000000000422641520735541300246260ustar00rootroot00000000000000# ----------------------------------------------------------------------------- # Copyright (c) 2021-2021, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ----------------------------------------------------------------------------- import numpy as np cimport numpy as cnp cnp.import_array() cimport cython from cython.parallel import prange from libc.math cimport sqrt, fabs ctypedef cnp.npy_intp intp_t ctypedef fused TReal: float double ctypedef fused floating: cnp.float64_t cnp.float32_t ctypedef cnp.float64_t float64_t ctypedef cnp.float32_t float32_t @cython.boundscheck(False) @cython.wraparound(False) cdef inline Py_ssize_t condensed_index(Py_ssize_t i, Py_ssize_t j, Py_ssize_t n) nogil: """ Get index for condensed form from redundant form indices. This is a Cython implementation of the _condensed_index function that can be used in nogil context. Parameters ---------- i, j : Py_ssize_t Matrix coordinates (row, col). Assumes i < j for upper triangular access. n : Py_ssize_t Sample size of the square matrix. Returns ------- Py_ssize_t Index in the condensed form vector. """ cdef Py_ssize_t i_min, j_max # Ensure i < j (swap if necessary) if i > j: i_min = j j_max = i else: i_min = i j_max = j # Formula: i_min * n + j_max - ((i_min + 2) * (i_min + 1)) // 2 return i_min * n + j_max - ((i_min + 2) * (i_min + 1)) // 2 @cython.boundscheck(False) @cython.wraparound(False) def is_symmetric_and_hollow_cy(TReal[:, ::1] mat): """ Check if mat is symmetric and hollow. Equivalent to [not (mat.T != mat).any(), np.trace(mat) == 0] Parameters ---------- mat : 2D array_like Distance matrix. Result: ------- is_symmetric: Boolean not (mat.T != mat).any() is_hollow: Boolean np.trace(mat) == 0 """ cdef Py_ssize_t in_n = mat.shape[0] cdef Py_ssize_t in2 = mat.shape[1] assert in_n == in2 cdef Py_ssize_t trow,tcol cdef Py_ssize_t trow_max,tcol_max cdef Py_ssize_t row,col cdef TReal testval # use int instead of bool for portability cdef int is_sym = True cdef int is_hollow = True # use a tiled approach to maximize memory locality for trow in prange(0, in_n, 24, nogil=True): trow_max = min(trow+24, in_n) for tcol in range(0, in_n, 24): tcol_max = min(tcol+24, in_n) for row in range(trow, trow_max, 1): for col in range(tcol, tcol_max, 1): is_sym &= (mat[row,col]==mat[col,row]) if (trow==tcol): # diagonal block, only ones that can have col==row for col in range(tcol, tcol_max, 1): is_hollow &= (mat[col,col]==0) return [(is_sym==True), (is_hollow==True)] @cython.boundscheck(False) @cython.wraparound(False) def distmat_reorder_cy(TReal[:, ::1] in_mat, intp_t[::1] reorder_vec, TReal[:, ::1] out_mat): """ Reorder the rows and columns of a distance matrix given a reorder vector. Not all of the columns need to be used. For example: [ [0, 1, 2, 3] , [1, 0, 4, 5] , [2, 4, 0, 6] , [3, 5, 6, 0] ] with [1,0,3,2] will result in [ [0, 1, 5, 4] , [1, 0, 3, 2] , [5, 3, 0, 6] , [4, 2, 6, 0] ] Note: No error checking is performed. The caller must ensure that all values in reorder_vec are valid Parameters ---------- in_mat : 2D array_like Distance matrix. reorder_vec : 1D_array_like List of permutation indexes out_mat : 2D array_like Output, Distance matrix, must be same size as reorder_vec """ cdef Py_ssize_t in_n = in_mat.shape[0] cdef Py_ssize_t in2 = in_mat.shape[1] cdef Py_ssize_t out_n = reorder_vec.shape[0] cdef Py_ssize_t on2 = out_mat.shape[0] cdef Py_ssize_t on3 = out_mat.shape[1] assert in_n == in2 assert out_n == on2 assert out_n == on3 cdef Py_ssize_t row,col cdef Py_ssize_t vrow for row in prange(out_n, nogil=True): vrow = reorder_vec[row] for col in range(out_n): out_mat[row,col] = in_mat[vrow, reorder_vec[col]] @cython.boundscheck(False) @cython.wraparound(False) def distmat_reorder_condensed_cy(TReal[:, ::1] in_mat, intp_t[::1] reorder_vec, TReal[::1] out_mat_condensed): """ Reorder the rows and columns of a distance matrix given a reorder vector. Not all of the columns need to be used. For example: [ [0, 1, 2, 3] , [1, 0, 4, 5] , [2, 4, 0, 6] , [3, 5, 6, 0] ] with [1,0,3,2] will result in [ 1, 5, 4, 3, 2, 6 ] Note: No error checking is performed. The caller must ensure that all values in reorder_vec are valid Parameters ---------- in_mat : 2D array_like Distance matrix. reorder_vec : 1D_array_like List of permutation indexes out_mat_condensed : 1D array_like Output, condensed distance matrix """ cdef Py_ssize_t in_n = in_mat.shape[0] cdef Py_ssize_t in2 = in_mat.shape[1] cdef Py_ssize_t out_n = reorder_vec.shape[0] cdef Py_ssize_t on2 = out_mat_condensed.shape[0] assert in_n == in2 assert on2 == ((out_n-1)*out_n)/2 cdef Py_ssize_t row,col cdef Py_ssize_t vrow cdef Py_ssize_t idx for row in prange(out_n-1, nogil=True): vrow = reorder_vec[row] idx = row*(out_n-1) - ((row-1)*row)//2 for col in range(out_n-row-1): out_mat_condensed[idx+col] = in_mat[vrow, reorder_vec[col+row+1]] @cython.boundscheck(False) @cython.wraparound(False) def mantel_perm_pearsonr_cy(TReal[:, ::1] x_data, intp_t[:, ::1] perm_order, TReal xmean, TReal normxm, TReal[::1] ym_normalized, TReal[::1] permuted_stats): """ Fused permute, fma, pearsonr for mantel. Replaces the following python code: def _mantel_perm_pearsonr_one(x_flat, xmean, normxm, ym_normalized): # inline pearsonr, condensed from scipy.stats.pearsonr # and reusing some of the known values xm_normalized = (x_flat - xmean)/normxm one_stat = np.dot(xm_normalized, ym_normalized) one_stat = max(min(one_stat, 1.0), -1.0) return one_stat perm_gen = (_mantel_perm_pearsonr_one(distmat_reorder_condensed(x._data, perm_order[p,:]), xmean, normxm, ym_normalized) for p in range(permutations)) permuted_stats = np.fromiter(perm_gen, np.float, count=permutations) Parameters ---------- x_data : 2D array_like Distance matrix. perm_order : 2D array_like List of permutation orders. xmean: real Mean value of condensed x_data normxm: real Norm of pre-processed xm ym_normalized : 1D_array_like Normalized condensed y_data permuted_stats : 1D array_like Output, Pearson stats """ cdef Py_ssize_t in_n = x_data.shape[0] cdef Py_ssize_t in2 = x_data.shape[1] cdef Py_ssize_t perms_n = perm_order.shape[0] cdef Py_ssize_t out_n = perm_order.shape[1] cdef Py_ssize_t y_n = ym_normalized.shape[0] cdef Py_ssize_t on2 = permuted_stats.shape[0] assert in_n == in2 assert y_n == ((out_n-1)*out_n)/2 assert perms_n == on2 cdef Py_ssize_t p cdef Py_ssize_t row,col,icol cdef Py_ssize_t vrow cdef Py_ssize_t idx cdef TReal mul = 1.0/normxm cdef TReal add = -xmean/normxm cdef TReal my_ps cdef TReal yval cdef TReal xval for p in prange(perms_n, nogil=True): my_ps = 0.0 for row in range(out_n-1): vrow = perm_order[p, row] idx = row*(out_n-1) - ((row-1)*row)//2 for icol in range(out_n-row-1): col = icol+row+1 yval = ym_normalized[idx+icol] xval = x_data[vrow, perm_order[p, col]]*mul + add # do not use += to avoid having prange consider it for reduction my_ps = yval*xval + my_ps # Presumably, if abs(one_stat) > 1, then it is only some small artifact of # floating point arithmetic. if my_ps>1.0: my_ps = 1.0 elif my_ps<-1.0: my_ps = -1.0 permuted_stats[p] = my_ps @cython.boundscheck(False) @cython.wraparound(False) def mantel_perm_pearsonr_condensed_cy(TReal[::1] x_data_condensed, intp_t[:, ::1] perm_order, TReal xmean, TReal normxm, TReal[::1] ym_normalized, TReal[::1] permuted_stats): """ Fused permute, fma, pearsonr for mantel using condensed distance matrix format. This is similar to mantel_perm_pearsonr_cy but accepts x_data in condensed form (1D array) instead of the full 2D distance matrix. Parameters ---------- x_data_condensed : 1D array_like Condensed distance matrix (lower triangle only). perm_order : 2D array_like List of permutation orders. xmean: real Mean value of condensed x_data normxm: real Norm of pre-processed xm ym_normalized : 1D_array_like Normalized condensed y_data permuted_stats : 1D array_like Output, Pearson stats """ cdef Py_ssize_t x_n = x_data_condensed.shape[0] cdef Py_ssize_t perms_n = perm_order.shape[0] cdef Py_ssize_t out_n = perm_order.shape[1] cdef Py_ssize_t y_n = ym_normalized.shape[0] cdef Py_ssize_t on2 = permuted_stats.shape[0] assert x_n == ((out_n-1)*out_n)/2 assert y_n == ((out_n-1)*out_n)/2 assert perms_n == on2 cdef Py_ssize_t p cdef Py_ssize_t row, col, icol cdef Py_ssize_t vrow, vcol cdef Py_ssize_t idx, x_idx cdef TReal mul = 1.0/normxm cdef TReal add = -xmean/normxm cdef TReal my_ps cdef TReal yval cdef TReal xval for p in prange(perms_n, nogil=True): my_ps = 0.0 for row in range(out_n-1): vrow = perm_order[p, row] idx = row*(out_n-1) - ((row-1)*row)//2 for icol in range(out_n-row-1): col = icol+row+1 vcol = perm_order[p, col] x_idx = condensed_index(vrow, vcol, out_n) yval = ym_normalized[idx+icol] xval = x_data_condensed[x_idx]*mul + add my_ps = yval*xval + my_ps if my_ps>1.0: my_ps = 1.0 elif my_ps<-1.0: my_ps = -1.0 permuted_stats[p] = my_ps @cython.boundscheck(False) @cython.wraparound(False) def permanova_f_stat_sW_cy(TReal[:, ::1] distance_matrix, Py_ssize_t[::1] group_sizes, Py_ssize_t[::1] grouping): """Compute PERMANOVA pseudo-F partial statistic.""" cdef Py_ssize_t in_n = distance_matrix.shape[0] cdef Py_ssize_t in2 = distance_matrix.shape[1] cdef Py_ssize_t in3 = grouping.shape[0] assert in_n == in2 assert in_n == in3 cdef double s_W = 0.0 cdef Py_ssize_t group_idx cdef double local_s_W cdef double val cdef Py_ssize_t row, col, rowi, coli cdef Py_ssize_t in_n_2 = in_n//2 for rowi in prange(in_n_2, nogil=True): # since columns get shorter, combine first and last row=rowi local_s_W = 0.0 group_idx = grouping[row] for coli in range(in_n-row-1): col = coli+row+1 if grouping[col] == group_idx: val = distance_matrix[row,col] local_s_W = local_s_W + val * val s_W += local_s_W/group_sizes[group_idx] row = in_n-rowi-2 if row!=rowi: # don't double count local_s_W = 0.0 group_idx = grouping[row] for coli in range(in_n-row-1): col = coli+row+1 if grouping[col] == group_idx: val = distance_matrix[row,col] local_s_W = local_s_W + val * val s_W += local_s_W/group_sizes[group_idx] return s_W @cython.boundscheck(False) @cython.wraparound(False) def permanova_f_stat_sW_condensed_cy(TReal[::1] distance_matrix, Py_ssize_t[::1] group_sizes, Py_ssize_t[::1] grouping): """Compute PERMANOVA pseudo-F partial statistic.""" cdef Py_ssize_t condensed_size = distance_matrix.shape[0] cdef Py_ssize_t grouping_size = grouping.shape[0] # Calculate the redundant form dimension from condensed vector length # Formula: n = (1 + sqrt(1 + 8*k)) / 2, where k is the condensed vector length cdef Py_ssize_t n = ((1 + sqrt(1.0 + 8.0 * condensed_size)) / 2.0) assert n == grouping_size assert condensed_size == ((n - 1) * n) // 2 cdef double s_W = 0.0 cdef Py_ssize_t group_idx cdef double local_s_W cdef double val cdef Py_ssize_t row, col, rowi, coli, row1 cdef Py_ssize_t in_n_2 = n//2 for rowi in prange(in_n_2, nogil=True): # since columns get shorter, combine first and last row=rowi local_s_W = 0.0 group_idx = grouping[row] row1 = row + 1 for coli in range(n-row-1): col = coli + row1 if grouping[col] == group_idx: idx_ = condensed_index(row, col, n) val = distance_matrix[idx_] local_s_W += val * val s_W += local_s_W / group_sizes[group_idx] row = n-rowi-2 if row!=rowi: # don't double count local_s_W = 0.0 group_idx = grouping[row] row1 = row + 1 for coli in range(n-row-1): col = coli + row1 if grouping[col] == group_idx: idx_ = condensed_index(row, col, n) val = distance_matrix[idx_] local_s_W += val * val s_W += local_s_W / group_sizes[group_idx] return s_W @cython.boundscheck(False) @cython.wraparound(False) def geomedian_axis_one(floating[:, :] X, floating eps=1e-7, size_t maxiters=500): """Compute high dimensional median. This function, its helpers (dist_euclidean, norm_euclidean, sum), and necessary type definitions (floating) were ported from hdmedians v0.14.2. The only change was changing "cdef" to "def" on the line defining the function. See https://github.com/daleroberts/hdmedians for more information. """ cdef size_t p = X.shape[0] cdef size_t n = X.shape[1] cdef floating[:] y = np.mean(X, axis=1) if n == 1: return y if floating is cnp.float32_t: dtype = np.float32 else: dtype = np.float64 cdef floating[:] D = np.empty(n, dtype=dtype) cdef floating[:] Dinv = np.empty(n, dtype=dtype) cdef floating[:] W = np.empty(n, dtype=dtype) cdef floating[:] T = np.empty(p, dtype=dtype) cdef floating[:] y1 = np.empty(p, dtype=dtype) cdef floating[:] R = np.empty(p, dtype=dtype) cdef floating dist, Dinvs, total, r, rinv, tmp, Di cdef size_t nzeros = n cdef size_t iteration with nogil: iteration = 0 while iteration < maxiters: for i in range(n): Di = _dist_euclidean(X[:, i], y) D[i] = Di if fabs(Di) > eps: Dinv[i] = 1. / Di else: Dinv[i] = 0. Dinvs = _sum(Dinv) for i in range(n): W[i] = Dinv[i] / Dinvs for j in range(p): total = 0. for i in range(n): if fabs(D[i]) > eps: total += W[i] * X[j, i] T[j] = total nzeros = n for i in range(n): if fabs(D[i]) > eps: nzeros -= 1 if nzeros == 0: y1 = T elif nzeros == n: break else: for j in range(p): R[j] = (T[j] - y[j]) * Dinvs r = _norm_euclidean(R) if r > eps: rinv = nzeros/r else: rinv = 0. for j in range(p): y1[j] = max(0, 1-rinv)*T[j] + min(1, rinv)*y[j] dist = _dist_euclidean(y, y1) if dist < eps: break y[:] = y1 iteration = iteration + 1 return y cdef floating _dist_euclidean(floating[:] x, floating[:] y) nogil: cdef size_t n = x.shape[0] cdef float64_t d = 0. cdef float64_t tmp for i in range(n): tmp = x[i] - y[i] d += tmp * tmp return sqrt(d) cdef floating _norm_euclidean(floating[:] x) nogil: cdef size_t n = x.shape[0] cdef float64_t d = 0. for i in range(n): d += x[i] * x[i] return sqrt(d) cdef floating _sum(floating[:] x) nogil: cdef size_t n = x.shape[0] cdef float64_t total = 0. for i in range(n): total += x[i] return total scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/_mantel.py000066400000000000000000000663701520735541300244170ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from itertools import combinations from warnings import warn from typing import TYPE_CHECKING import numpy as np import pandas as pd import scipy.special from scipy.stats import kendalltau, ConstantInputWarning, NearConstantInputWarning from ._cutils import mantel_perm_pearsonr_cy, mantel_perm_pearsonr_condensed_cy from skbio.stats.distance import DistanceMatrix from skbio.util import get_rng if TYPE_CHECKING: # pragma: no cover from collections.abc import Sequence from ._base import DistanceMatrix from numpy.typing import ArrayLike from skbio.util._typing import SeedLike def mantel( x: DistanceMatrix | ArrayLike, y: DistanceMatrix | ArrayLike, method: str = "pearson", permutations: int = 999, alternative: str = "two-sided", strict: bool = True, lookup: dict[str, str] | None = None, seed: SeedLike | None = None, ) -> tuple[float, float, int]: r"""Compute correlation between distance matrices using the Mantel test. The Mantel test compares two distance matrices by computing the correlation between the distances in the lower (or upper) triangular portions of the symmetric distance matrices. Correlation can be computed using Pearson's product-moment correlation coefficient or Spearman's rank correlation coefficient. As defined in [1]_, the Mantel test computes a test statistic :math:`r_M` given two symmetric distance matrices :math:`D_X` and :math:`D_Y`. :math:`r_M` is defined as .. math:: r_M=\frac{1}{d-1}\sum_{i=1}^{n-1}\sum_{j=i+1}^{n} stand(D_X)_{ij}stand(D_Y)_{ij} where .. math:: d=\frac{n(n-1)}{2} and :math:`n` is the number of rows/columns in each of the distance matrices. :math:`stand(D_X)` and :math:`stand(D_Y)` are distance matrices with their upper triangles containing standardized distances. Note that since :math:`D_X` and :math:`D_Y` are symmetric, the lower triangular portions of the matrices could equivalently have been used instead of the upper triangular portions (the current function behaves in this manner). If ``method='spearman'``, the above equation operates on ranked distances instead of the original distances. Statistical significance is assessed via a permutation test. The rows and columns of the first distance matrix (`x`) are randomly permuted a number of times (controlled via `permutations`). A correlation coefficient is computed for each permutation and the p-value is the proportion of permuted correlation coefficients that are equal to or more extreme than the original (unpermuted) correlation coefficient. Whether a permuted correlation coefficient is "more extreme" than the original correlation coefficient depends on the alternative hypothesis (controlled via `alternative`). Parameters ---------- x, y : DistanceMatrix or array_like Input distance matrices to compare. If `x` and `y` are both ``DistanceMatrix`` instances, they will be reordered based on matching IDs (see `strict` and `lookup` below for handling matching/mismatching IDs); thus they are not required to be in the same ID order. If `x` and `y` are ``array_like``, no reordering is applied and both matrices must have the same shape. In either case, `x` and `y` must be at least 3x3 in size *after* reordering and matching of IDs. method : {'pearson', 'spearman','kendalltau'} Method used to compute the correlation between distance matrices. permutations : int, optional Number of times to randomly permute `x` when assessing statistical significance. Must be greater than or equal to zero. If zero, statistical significance calculations will be skipped and the p-value will be ``np.nan``. alternative : {'two-sided', 'greater', 'less'} Alternative hypothesis to use when calculating statistical significance. The default ``'two-sided'`` alternative hypothesis calculates the proportion of permuted correlation coefficients whose magnitude (i.e. after taking the absolute value) is greater than or equal to the absolute value of the original correlation coefficient. ``'greater'`` calculates the proportion of permuted coefficients that are greater than or equal to the original coefficient. ``'less'`` calculates the proportion of permuted coefficients that are less than or equal to the original coefficient. strict : bool, optional If ``True``, raises a ``ValueError`` if IDs are found that do not exist in both distance matrices. If ``False``, any nonmatching IDs are discarded before running the test. See `n` (in Returns section below) for the number of matching IDs that were used in the test. This parameter is ignored if `x` and `y` are ``array_like``. lookup : dict, optional Maps each ID in the distance matrices to a new ID. Used to match up IDs across distance matrices prior to running the Mantel test. If the IDs already match between the distance matrices, this parameter is not necessary. This parameter is disallowed if `x` and `y` are ``array_like``. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- corr_coeff : float Correlation coefficient of the test (depends on `method`). p_value : float p-value of the test. n : int Number of rows/columns in each of the distance matrices, after any reordering/matching of IDs. If ``strict=False``, nonmatching IDs may have been discarded from one or both of the distance matrices prior to running the Mantel test, so this value may be important as it indicates the *actual* size of the matrices that were compared. Raises ------ ValueError If `x` and `y` are not at least 3x3 in size after reordering/matching of IDs, or an invalid `method`, number of `permutations`, or `alternative` are provided. TypeError If `x` and `y` are not both ``DistanceMatrix`` instances or ``array_like``. See Also -------- DistanceMatrix scipy.stats.pearsonr scipy.stats.spearmanr pwmantel Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. The Mantel test was first described in [2]_. The general algorithm and interface are similar to ``vegan::mantel``, available in R's vegan package [3]_. ``np.nan`` will be returned for the p-value if `permutations` is zero or if the correlation coefficient is ``np.nan``. The correlation coefficient will be ``np.nan`` if one or both of the inputs does not have any variation (i.e. the distances are all constant) and ``method='spearman'``. References ---------- .. [1] Legendre, P. and Legendre, L. (2012) Numerical Ecology. 3rd English Edition. Elsevier. .. [2] Mantel, N. (1967). "The detection of disease clustering and a generalized regression approach". Cancer Research 27 (2): 209-220. PMID 6018555. .. [3] http://cran.r-project.org/web/packages/vegan/index.html Examples -------- Import the functionality we'll use in the following examples: >>> from skbio import DistanceMatrix >>> from skbio.stats.distance import mantel Define two 3x3 distance matrices: >>> x = DistanceMatrix([[0, 1, 2], ... [1, 0, 3], ... [2, 3, 0]]) >>> y = DistanceMatrix([[0, 2, 7], ... [2, 0, 6], ... [7, 6, 0]]) Compute the Pearson correlation between them and assess significance using a two-sided test with 999 permutations: >>> coeff, p_value, n = mantel(x, y) >>> print(round(coeff, 4)) 0.7559 Thus, we see a moderate-to-strong positive correlation (:math:`r_M=0.7559`) between the two matrices. In the previous example, the distance matrices (``x`` and ``y``) have the same IDs, in the same order: >>> x.ids ('0', '1', '2') >>> y.ids ('0', '1', '2') If necessary, ``mantel`` will reorder the distance matrices prior to running the test. The function also supports a ``lookup`` dictionary that maps distance matrix IDs to new IDs, providing a way to match IDs between distance matrices prior to running the Mantel test. For example, let's reassign the distance matrices' IDs so that there are no matching IDs between them: >>> x.ids = ('a', 'b', 'c') >>> y.ids = ('d', 'e', 'f') If we rerun ``mantel``, we get the following error notifying us that there are nonmatching IDs (this is the default behavior with ``strict=True``): >>> mantel(x, y) Traceback (most recent call last): ... ValueError: IDs exist that are not in both distance matrices. If we pass ``strict=False`` to ignore/discard nonmatching IDs, we see that no matches exist between `x` and `y`, so the Mantel test still cannot be run: >>> mantel(x, y, strict=False) Traceback (most recent call last): ... ValueError: No matching IDs exist between the distance matrices. To work around this, we can define a ``lookup`` dictionary to specify how the IDs should be matched between distance matrices: >>> lookup = {'a': 'A', 'b': 'B', 'c': 'C', ... 'd': 'A', 'e': 'B', 'f': 'C'} ``lookup`` maps each ID to ``'A'``, ``'B'``, or ``'C'``. If we rerun ``mantel`` with ``lookup``, we get the same results as the original example where all distance matrix IDs matched: >>> coeff, p_value, n = mantel(x, y, lookup=lookup) >>> print(round(coeff, 4)) 0.7559 ``mantel`` also accepts input that is ``array_like``. For example, if we redefine `x` and `y` as nested Python lists instead of ``DistanceMatrix`` instances, we obtain the same result: >>> x = [[0, 1, 2], ... [1, 0, 3], ... [2, 3, 0]] >>> y = [[0, 2, 7], ... [2, 0, 6], ... [7, 6, 0]] >>> coeff, p_value, n = mantel(x, y) >>> print(round(coeff, 4)) 0.7559 It is import to note that reordering/matching of IDs (and hence the ``strict`` and ``lookup`` parameters) do not apply when input is ``array_like`` because there is no notion of IDs. """ rng = get_rng(seed) if method in ("pearson", "spearman"): special = True elif method == "kendalltau": corr_func = kendalltau special = False # set to true, if we have a dedicated implementation else: raise ValueError("Invalid correlation method '%s'." % method) if permutations < 0: raise ValueError( "Number of permutations must be greater than or equal to zero." ) if alternative not in ("two-sided", "greater", "less"): raise ValueError("Invalid alternative hypothesis '%s'." % alternative) x, y = _order_dms(x, y, strict=strict, lookup=lookup) n = x.shape[0] if n < 3: raise ValueError( "Distance matrices must have at least 3 matching IDs " "between them (i.e., minimum 3x3 in size)." ) if special: if method == "pearson": orig_stat, comp_stat, permuted_stats = _mantel_stats_pearson( x, y, permutations, rng ) else: orig_stat, comp_stat, permuted_stats = _mantel_stats_spearman( x, y, permutations, rng ) else: x_flat = x.condensed_form() y_flat = y.condensed_form() orig_stat = comp_stat = corr_func(x_flat, y_flat)[0] del x_flat permuted_stats = [] if not (permutations == 0 or np.isnan(orig_stat)): perm_gen = ( corr_func(x.permute(condensed=True, seed=rng), y_flat)[0] for _ in range(permutations) ) permuted_stats = np.fromiter(perm_gen, float, count=permutations) del y_flat if permutations == 0 or np.isnan(orig_stat): p_value = np.nan else: if alternative == "two-sided": count_better = (np.absolute(permuted_stats) >= np.absolute(comp_stat)).sum() elif alternative == "greater": count_better = (permuted_stats >= comp_stat).sum() else: count_better = (permuted_stats <= comp_stat).sum() p_value = (count_better + 1) / (permutations + 1) return orig_stat, p_value, n def _mantel_stats_pearson_flat(x, y_flat, permutations, seed=None): """Compute original and permuted stats using pearsonr. Parameters ---------- x : DistanceMatrix Input distance matrix. y_flat: 1D array Compact representation of a distance matrix. permutations : int Number of times to randomly permute `x` when assessing statistical significance. Must be greater than or equal to zero. If zero, statistical significance calculations will be skipped and permuted_stats will be an empty array. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. Returns ------- orig_stat : 1D array_like Correlation coefficient of the test. comp_stat : 1D array_like Correlation coefficient to compare against permuted_stats, usually the same as orig_stat, but on certain architectures it will differ. This should be used for any p-value calculation as it will match the values for any "self-permutations" in the permuted_stats. permuted_stats : 1D array_like Permuted correlation coefficients of the test. """ rng = get_rng(seed) x_flat = x.condensed_form() # If an input is constant, the correlation coefficient is not defined. if (x_flat == x_flat[0]).all() or (y_flat == y_flat[0]).all(): warn(ConstantInputWarning()) return np.nan, np.nan, [] # inline pearsonr, condensed from scipy.stats.pearsonr xmean = x_flat.mean() xm = x_flat - xmean normxm = np.linalg.norm(xm) xm_normalized = xm / normxm del xm del x_flat ymean = y_flat.mean() ym = y_flat - ymean normym = np.linalg.norm(ym) ym_normalized = ym / normym del ym threshold = 1e-13 if (normxm < threshold * abs(xmean)) or (normym < threshold * abs(ymean)): # If all the values in x (likewise y) are very close to the mean, # the loss of precision that occurs in the subtraction xm = x - xmean # might result in large errors in r. warn(NearConstantInputWarning()) orig_stat = np.dot(xm_normalized, ym_normalized) # Presumably, if abs(orig_stat) > 1, then it is only some small artifact of # floating point arithmetic. orig_stat = max(min(orig_stat, 1.0), -1.0) mat_n = x.shape[0] # note: xmean and normxm do not change with permutations permuted_stats = [] comp_stat = orig_stat if not (permutations == 0 or np.isnan(orig_stat)): # inline DistanceMatrix.permute, grouping them together x_data = x._data if not x_data.flags.c_contiguous: x_data = np.asarray(x_data, order="C") # compute all pearsonr permutations at once # create first the list of permutations perm_order = np.empty((permutations + 1, mat_n), dtype=np.intp) # first row/statistic will be comp_stat perm_order[0, :] = np.arange(mat_n) for row in range(1, permutations + 1): perm_order[row, :] = rng.permutation(mat_n) permuted_stats = np.empty(permutations + 1, dtype=x_data.dtype) if x._flags["CONDENSED"]: mantel_perm_pearsonr_condensed_cy( x_data, perm_order, xmean, normxm, ym_normalized, permuted_stats ) else: mantel_perm_pearsonr_cy( x_data, perm_order, xmean, normxm, ym_normalized, permuted_stats ) comp_stat = permuted_stats[0] permuted_stats = permuted_stats[1:] return orig_stat, comp_stat, permuted_stats def _mantel_stats_pearson(x, y, permutations, seed=None): """Compute original and permuted stats using pearsonr. Parameters ---------- x, y : DistanceMatrix Input distance matrices to compare. permutations : int Number of times to randomly permute `x` when assessing statistical significance. Must be greater than or equal to zero. If zero, statistical significance calculations will be skipped and permuted_stats will be an empty array. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. Returns ------- orig_stat : 1D array_like Correlation coefficient of the test. comp_stat : 1D array_like Correlation coefficient to compare against permuted_stats, usually the same as orig_stat, but on certain architectures it will differ. This should be used for any p-value calculation as it will match the values for any "self-permutations" in the permuted_stats. permuted_stats : 1D array_like Permuted correlation coefficients of the test. """ y_flat = y.condensed_form() return _mantel_stats_pearson_flat(x, y_flat, permutations, seed) def _mantel_stats_spearman(x, y, permutations, seed=None): """Compute original and permuted stats using spearmanr. Parameters ---------- x, y : DistanceMatrix Input distance matrices to compare. permutations : int Number of times to randomly permute `x` when assessing statistical significance. Must be greater than or equal to zero. If zero, statistical significance calculations will be skipped and permuted_stats will be an empty array. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. Returns ------- orig_stat : 1D array_like Correlation coefficient of the test. comp_stat : 1D array_like Correlation coefficient to compare against permuted_stats, usually the same as orig_stat, but on certain architectures it will differ. This should be used for any p-value calculation as it will match the values for any "self-permutations" in the permuted_stats. permuted_stats : 1D array_like Permuted correlation coefficients of the test. """ x_flat = x.condensed_form() y_flat = y.condensed_form() # If an input is constant, the correlation coefficient is not defined. if (x_flat == x_flat[0]).all() or (y_flat == y_flat[0]).all(): warn(ConstantInputWarning()) return np.nan, np.nan, [] y_rank = scipy.stats.rankdata(y_flat) del y_flat x_rank = scipy.stats.rankdata(x_flat) del x_flat x_rank_matrix = DistanceMatrix(x_rank, x.ids) del x_rank # for our purposes, spearman is just pearson on rankdata return _mantel_stats_pearson_flat(x_rank_matrix, y_rank, permutations, seed) def pwmantel( dms: Sequence[DistanceMatrix | ArrayLike], labels: Sequence[str | int] | None = None, method: str = "pearson", permutations: int = 999, alternative: str = "two-sided", strict: bool = True, lookup: dict[str, str] | None = None, seed: SeedLike | None = None, ) -> pd.DataFrame: """Run Mantel tests for every pair of given distance matrices. Runs a Mantel test for each pair of distance matrices and collates the results in a ``DataFrame``. Distance matrices do not need to be in the same ID order if they are ``DistanceMatrix`` instances. Distance matrices will be re-ordered prior to running each pairwise test, and if ``strict=False``, IDs that don't match between a pair of distance matrices will be dropped prior to running the test (otherwise a ``ValueError`` will be raised if there are nonmatching IDs between any pair of distance matrices). Parameters ---------- dms : iterable of DistanceMatrix objects, array_like objects, or filepaths to distance matrices. If they are ``array_like``, no reordering or matching of IDs will be performed. labels : iterable of str or int, optional Labels for each distance matrix in `dms`. These are used in the results ``DataFrame`` to identify the pair of distance matrices used in a pairwise Mantel test. If ``None``, defaults to monotonically-increasing integers starting at zero. method : {'pearson', 'spearman'} Correlation method. See ``mantel`` function for more details. permutations : int, optional Number of permutations. See ``mantel`` function for more details. alternative : {'two-sided', 'greater', 'less'} Alternative hypothesis. See ``mantel`` function for more details. strict : bool, optional Handling of nonmatching IDs. See ``mantel`` function for more details. lookup : dict, optional Map existing IDs to new IDs. See ``mantel`` function for more details. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- pandas.DataFrame ``DataFrame`` containing the results of each pairwise test (one per row). Includes the number of objects considered in each test as column ``n`` (after applying `lookup` and filtering nonmatching IDs if ``strict=False``). Column ``p-value`` will display p-values as ``NaN`` if p-values could not be computed (they are stored as ``np.nan`` within the ``DataFrame``; see ``mantel`` for more details). See Also -------- mantel DistanceMatrix.read Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. Passing a list of filepaths can be useful as it allows for a smaller amount of memory consumption as it only loads two matrices at a time as opposed to loading all distance matrices into memory. Examples -------- Import the functionality we'll use in the following examples: >>> from skbio import DistanceMatrix >>> from skbio.stats.distance import pwmantel Define three 3x3 distance matrices: >>> x = DistanceMatrix([[0, 1, 2], ... [1, 0, 3], ... [2, 3, 0]]) >>> y = DistanceMatrix([[0, 2, 7], ... [2, 0, 6], ... [7, 6, 0]]) >>> z = DistanceMatrix([[0, 5, 6], ... [5, 0, 1], ... [6, 1, 0]]) Run Mantel tests for each pair of distance matrices (there are 3 possible pairs): >>> pwmantel((x, y, z), labels=('x', 'y', 'z'), ... permutations=0) # doctest: +NORMALIZE_WHITESPACE statistic p-value n method permutations alternative dm1 dm2 x y 0.755929 NaN 3 pearson 0 two-sided z -0.755929 NaN 3 pearson 0 two-sided y z -0.142857 NaN 3 pearson 0 two-sided Note that we passed ``permutations=0`` to suppress significance tests; the p-values in the output are labelled ``NaN``. """ rng = get_rng(seed) num_dms = len(dms) if num_dms < 2: raise ValueError("Must provide at least two distance matrices.") if labels is None: labels = range(num_dms) else: if num_dms != len(labels): raise ValueError( "Number of labels must match the number of distance matrices." ) if len(set(labels)) != len(labels): raise ValueError("Labels must be unique.") num_combs = scipy.special.comb(num_dms, 2, exact=True) results_dtype = [ ("dm1", object), ("dm2", object), ("statistic", float), ("p-value", float), ("n", int), ("method", object), ("permutations", int), ("alternative", object), ] results = np.empty(num_combs, dtype=results_dtype) for i, pair in enumerate(combinations(zip(labels, dms), 2)): (xlabel, x), (ylabel, y) = pair if isinstance(x, str): x = DistanceMatrix.read(x) if isinstance(y, str): y = DistanceMatrix.read(y) stat, p_val, n = mantel( x, y, method=method, permutations=permutations, alternative=alternative, strict=strict, lookup=lookup, seed=rng, ) results[i] = (xlabel, ylabel, stat, p_val, n, method, permutations, alternative) return pd.DataFrame.from_records(results, index=("dm1", "dm2")) def _order_dms(x, y, strict=True, lookup=None): """Intersect distance matrices and put them in the same order.""" x_is_dm = isinstance(x, DistanceMatrix) y_is_dm = isinstance(y, DistanceMatrix) if (x_is_dm and not y_is_dm) or (y_is_dm and not x_is_dm): raise TypeError( "Mixing DistanceMatrix and array_like input types is not " "supported. Both x and y must either be DistanceMatrix instances " "or array_like, but not mixed." ) elif x_is_dm and y_is_dm: if lookup is not None: x = _remap_ids(x, lookup, "x", "first") y = _remap_ids(y, lookup, "y", "second") if tuple(x.ids) == tuple(y.ids): return x, y id_order = [id_ for id_ in x.ids if id_ in y] num_matches = len(id_order) if strict and ((num_matches != len(x.ids)) or (num_matches != len(y.ids))): raise ValueError("IDs exist that are not in both distance matrices.") if num_matches < 1: raise ValueError("No matching IDs exist between the distance matrices.") return x.filter(id_order), y.filter(id_order) else: # Both x and y aren't DistanceMatrix instances. if lookup is not None: raise ValueError( "ID lookup can only be provided if inputs are DistanceMatrix instances." ) x = DistanceMatrix(x) y = DistanceMatrix(y) if x.shape != y.shape: raise ValueError("Distance matrices must have the same shape.") return x, y def _remap_ids(dm, lookup, label, order): """Return a copy of `dm` with its IDs remapped based on `lookup`.""" try: remapped_ids = [lookup[id_] for id_ in dm.ids] except KeyError as e: raise KeyError( "All IDs in the %s distance matrix (%s) must be in " "the lookup. Missing ID: %s" % (order, label, str(e)) ) # Create a copy as we'll be modifying the IDs in place. dm_copy = dm.copy() dm_copy.ids = remapped_ids return dm_copy scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/_permanova.py000066400000000000000000000231221520735541300251130ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from functools import partial from warnings import warn from typing import TYPE_CHECKING import numpy as np from ._base import ( _preprocess_input_sng, _run_monte_carlo_stats, _build_results, DistanceMatrix, ) from ._cutils import permanova_f_stat_sW_cy, permanova_f_stat_sW_condensed_cy from skbio.binaries import ( permanova_available as _skbb_permanova_available, permanova as _skbb_permanova, ) from skbio.util._decorator import params_aliased if TYPE_CHECKING: # pragma: no cover from numpy.typing import ArrayLike import pandas as pd from skbio.util._typing import SeedLike @params_aliased([("distmat", "distance_matrix", "0.7.0", False)]) def permanova( distmat: DistanceMatrix, grouping: pd.DataFrame | ArrayLike, column: str | None = None, permutations: int = 999, seed: SeedLike | None = None, ) -> pd.Series: r"""Test for significant differences between groups using PERMANOVA. Permutational Multivariate Analysis of Variance (PERMANOVA) is a non-parametric method that tests whether two or more groups of objects (e.g., samples) are significantly different based on a categorical factor. It is conceptually similar to ANOVA except that it operates on distances between objects via a distance matrix, which allows for multivariate analysis. Unlike classical Multivariate Analysis of Variance (MANOVA), PERMANOVA makes no assumptions about the distribution of the underlying data. As such, rather than computing a true `F` statistic based in known distributions of variables, it computes a pseudo-`F` statistic whose significance can be assessed by a permutation test. The pseudo-`F` statistic is the ratio of between-group variance to within-group variance, defined in [1]_ analogously to the `F` statistic in ANOVA: .. math:: F = \frac{{SS}_{between}/(g - 1)}{{SS}_{within}/(n - g)} It is computed from the sums of squares :math:`{SS}_{between}` and :math:`{SS}_{within}` divided by their corresponding degrees of freedom, where :math:`n` is the number of distinct objects and :math:`g` is the number of groups. Statistical significance is assessed via a permutation test. Objects in the distance matrix are assigned to groups (`grouping`) based on a categorical factor. This assignment of groups is permuted a number of times (controlled via `permutations`), and a pseudo-`F` statistic is computed for each permutation. Under the null hypothesis that the groupings of objects have no effect on the distribution of the underlying data, the pseudo-`F` statistics of these permutations should be identically distributed for a given distance matrix. The probability of a given pseudo-`F` statistic being at least as extreme as an observed one is then the proportion of permuted pseudo-`F` statistics (:math:`F^{\pi}`) that are greater than or equal to the observed (unpermuted) one (:math:`F`): .. math:: p = \frac{1 + \text{no. of } F^{\pi} \geq F}{1 + \text{no. of permutations}} Parameters ---------- distmat : DistanceMatrix Distance matrix containing distances between objects (e.g., distances between samples of microbial communities). grouping : 1-D array_like or pandas.DataFrame Vector indicating the assignment of objects to groups. For example, these could be strings or integers denoting which group an object belongs to. If `grouping` is 1-D ``array_like``, it must be the same length and in the same order as the objects in `distmat`. If `grouping` is a ``DataFrame``, the column specified by `column` will be used as the grouping vector. The ``DataFrame`` must be indexed by the IDs in `distmat` (i.e., the row labels must be distance matrix IDs), but the order of IDs between `distmat` and the ``DataFrame`` need not be the same. All IDs in the distance matrix must be present in the ``DataFrame``. Extra IDs in the ``DataFrame`` are allowed (they are ignored in the calculations). column : str, optional Column name to use as the grouping vector if `grouping` is a ``DataFrame``. Must be provided if `grouping` is a ``DataFrame``. Cannot be provided if `grouping` is 1-D ``array_like``. permutations : int, optional Number of permutations to use when assessing statistical significance. Must be greater than or equal to zero. If zero, statistical significance calculations will be skipped and the `p`-value will be ``np.nan``. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- pandas.Series Results of the statistical test, including ``test statistic`` and ``p-value``. See Also -------- anosim statsmodels.multivariate.manova.MANOVA scipy.stats.permutation_test Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. Low-level acceleration is available for this function. See :install:`scikit-bio-binaries <#acceleration>` for more information. See [1]_ for the original method reference, as well as ``vegan::adonis``, available in R's vegan package [2]_. The precision of the `p`-value is dependent on the number of permutations. The default precision is :math:`0.001=1/(1+999)` from the default value ``permutations=999``. The unpermuted grouping always contributes the first permutation to the numerator and denominator of the `p`-value, so 1 is added to both. This circumvents the risk of the probability being zero by chance even when it is nonzero. It is suggested in [1]_ that at least 1000 permutations should be performed for a confidence level of 0.05, and 5000 permutations should be performed for a confidence level of 0.01. The `p`-value will be ``np.nan`` if ``permutations`` is zero. A related statistic reported by some implementations (such as ``vegan::adonis``) is the :math:`R^2` value, which describes the proportion of variance in the data explained by the grouping: .. math:: R^2 = \frac{{SS}_{between}}{{SS}_{total}} This is not currently computed by this function, but it may be derived from the outputs using the following formula: .. math:: R^2 = \frac{1}{1 + \frac{n - g}{(g - 1)F}} where :math:`F` is the pseudo-`F` statistic, :math:`n` is the number of objects, and :math:`g` is the number of groups. References ---------- .. [1] Anderson, Marti J. "A new method for non-parametric multivariate analysis of variance." Austral Ecology 26.1 (2001): 32-46. .. [2] http://cran.r-project.org/web/packages/vegan/index.html Examples -------- See :mod:`skbio.stats.distance.anosim` for usage examples (both functions provide similar interfaces). """ if not isinstance(distmat, DistanceMatrix): raise TypeError("Input must be a DistanceMatrix.") sample_size = distmat.shape[0] num_groups, grouping = _preprocess_input_sng( distmat.ids, sample_size, grouping, column ) if _skbb_permanova_available( distmat, grouping, permutations, seed ): # pragma: no cover # unlikely to throw here, but just in case try: stat, p_value = _skbb_permanova(distmat, grouping, permutations, seed) return _build_results( "PERMANOVA", "pseudo-F", sample_size, num_groups, stat, p_value, permutations, ) except Exception as e: warn( "Attempted to use binaries.permanova but failed, " "using regular logic instead.", RuntimeWarning, ) # if we got here, we could not use skbb # Calculate number of objects in each group. group_sizes = np.bincount(grouping) s_T = (distmat.data**2).sum() / sample_size if not distmat._flags["CONDENSED"]: # we are going over the whole matrix, instead of just upper triangle # so cut in half s_T /= 2.0 test_stat_function = partial( _compute_f_stat, sample_size, num_groups, distmat, group_sizes, s_T ) stat, p_value = _run_monte_carlo_stats( test_stat_function, grouping, permutations, seed ) return _build_results( "PERMANOVA", "pseudo-F", sample_size, num_groups, stat, p_value, permutations ) def _compute_f_stat( sample_size, num_groups, distance_matrix, group_sizes, s_T, grouping ): """Compute PERMANOVA pseudo-F statistic.""" # Calculate s_W for each group, accounting for different group sizes. if distance_matrix._flags["CONDENSED"]: s_W = permanova_f_stat_sW_condensed_cy( distance_matrix.data, group_sizes, grouping ) else: s_W = permanova_f_stat_sW_cy(distance_matrix.data, group_sizes, grouping) s_A = s_T - s_W return (s_A / (num_groups - 1)) / (s_W / (sample_size - num_groups)) scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/_permdisp.py000066400000000000000000000323571520735541300247600ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from functools import partial from typing import TYPE_CHECKING import numpy as np from scipy.stats import f_oneway from ._cutils import geomedian_axis_one from ._base import ( _preprocess_input_sng, _run_monte_carlo_stats, _build_results, DistanceMatrix, ) from skbio.stats.ordination import pcoa, OrdinationResults from skbio.util._decorator import params_aliased if TYPE_CHECKING: # pragma: no cover from numpy.typing import ArrayLike import pandas as pd from skbio.util._typing import SeedLike @params_aliased( [ ("dimensions", "number_of_dimensions", "0.7.0", False), ("distmat", "distance_matrix", "0.7.0", False), ] ) def permdisp( distmat: DistanceMatrix | OrdinationResults, grouping: pd.DataFrame | ArrayLike, column: str | None = None, test: str = "median", permutations: int = 999, method: str = "eigh", dimensions: int = 10, seed: SeedLike | None = None, warn_neg_eigval: bool | float = 0.01, ) -> pd.Series: r"""Test for Homogeneity of Multivariate Groups Disperisons. PERMDISP is a multivariate analog of Levene's test for homogeneity of multivariate variances. Distances are handled by reducing the original distances to principal coordinates. PERMDISP calculates an F-statistic to assess whether the dispersions between groups is significant. Parameters ---------- distmat : DistanceMatrix or OrdinationResults Distance matrix containing distances between objects (e.g., distances between samples of microbial communities) or result of pcoa on such a matrix. grouping : 1-D array_like or pandas.DataFrame Vector indicating the assignment of objects to groups. For example, these could be strings or integers denoting which group an object belongs to. If `grouping` is 1-D ``array_like``, it must be the same length and in the same order as the objects in `distmat`. If `grouping` is a ``DataFrame``, the column specified by `column` will be used as the grouping vector. The ``DataFrame`` must be indexed by the IDs in `distmat` (i.e., the row labels must be distance matrix IDs), but the order of IDs between `distmat` and the ``DataFrame`` need not be the same. All IDs in the distance matrix must be present in the ``DataFrame``. Extra IDs in the ``DataFrame`` are allowed (they are ignored in the calculations). column : str, optional Column name to use as the grouping vector if `grouping` is a ``DataFrame``. Must be provided if `grouping` is a ``DataFrame``. Cannot be provided if `grouping` is 1-D ``array_like``. test : {'centroid', 'median'}, optional Determines whether the analysis is done using centroid or spatial median (default). permutations : int, optional Number of permutations to use when assessing statistical significance. Must be greater than or equal to zero. If zero, statistical significance calculations will be skipped and the p-value will be ``np.nan``. method : {'eigh', 'fsvd'}, optional Matrix decomposition method to use. Options are "eigh" (eigendecomposition, default) and "fsvd" (fast singular value decomposition). See :func:`~skbio.stats.ordination.pcoa ` for details. Not used if distmat is a OrdinationResults object. dimensions : int, optional Dimensions to reduce the distance matrix to if using the `fsvd` method. Not used if the `eigh` method is being selected. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 warn_neg_eigval : bool or float, optional Raise a warning if any negative eigenvalue of large magnitude is generated during PCoA. See :func:`skbio.stats.ordination.pcoa ` for details. .. versionadded:: 0.6.3 Returns ------- pandas.Series Results of the statistical test, including ``test statistic`` and ``p-value``. Raises ------ TypeError If, when using the spatial median test, the pcoa ordination is not of type np.float32 or np.float64, the spatial median function will fail and the centroid test should be used instead ValueError If the test is not centroid or median, or if method is not eigh or fsvd. TypeError If the distance matrix is not an instance of ``DistanceMatrix``. ValueError If there is only one group. ValueError If a list and a column name are both provided. ValueError If a list is provided for `grouping` and it's length does not match. the number of ids in distmat. ValueError If all of the values in the grouping vector are unique. KeyError If there are ids in grouping that are not in distmat. See Also -------- permanova anosim Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. This function uses Marti Anderson's PERMDISP2 procedure. The significance of the results from this function will be the same as the results found in vegan's betadisper, however due to floating point variability the F-statistic results may vary slightly. See [1]_ for the original method reference, as well as ``vegan::betadisper``, available in R's vegan package [2]_. References ---------- .. [1] Anderson, M. J. (2006). Distance-based tests for homogeneity of multivariate dispersions. Biometrics, 62(1), 245-253. .. [2] http://cran.r-project.org/web/packages/vegan/index.html Examples -------- Load a 6x6 distance matrix and grouping vector denoting 2 groups of objects: >>> from skbio import DistanceMatrix >>> dm = DistanceMatrix([[0, 0.5, 0.75, 1, 0.66, 0.33], ... [0.5, 0, 0.25, 0.33, 0.77, 0.61], ... [0.75, 0.25, 0, 0.1, 0.44, 0.55], ... [1, 0.33, 0.1, 0, 0.75, 0.88], ... [0.66, 0.77, 0.44, 0.75, 0, 0.77], ... [0.33, 0.61, 0.55, 0.88, 0.77, 0]], ... ['s1', 's2', 's3', 's4', 's5', 's6']) >>> grouping = ['G1', 'G1', 'G1', 'G2', 'G2', 'G2'] Run PERMDISP using 99 permutations to calculate the p-value. The seed is to make the output deterministic. You may skip it if that's not necessary. >>> from skbio.stats.distance import permdisp >>> permdisp(dm, grouping, permutations=99, seed=42, ... dimensions=dm.shape[0]) # doctest: +ELLIPSIS method name PERMDISP test statistic name F-value sample size 6 number of groups 2 test statistic 1.03296 p-value ... number of permutations 99 Name: PERMDISP results, dtype: object The return value is a ``pandas.Series`` object containing the results of the statistical test. To suppress calculation of the p-value and only obtain the F statistic, specify zero permutations: >>> permdisp(dm, grouping, permutations=0, dimensions=dm.shape[0]) method name PERMDISP test statistic name F-value sample size 6 number of groups 2 test statistic 1.03296 p-value NaN number of permutations 0 Name: PERMDISP results, dtype: object PERMDISP computes variances based on two types of tests, using either centroids or spatial medians, also commonly referred to as a geometric median. The spatial median is thought to yield a more robust test statistic, and this test is used by default. Spatial medians are computed using an iterative algorithm to find the optimally minimum point from all other points in a group while centroids are computed using a deterministic formula. As such the two different tests yield slightly different F statistics. >>> permdisp(dm, grouping, test='centroid', permutations=6, seed=42, ... dimensions=dm.shape[0]) method name PERMDISP test statistic name F-value sample size 6 number of groups 2 test statistic 3.670816 p-value 0.285714 number of permutations 6 Name: PERMDISP results, dtype: object You can also provide a ``pandas.DataFrame`` and a column denoting the grouping instead of a grouping vector. The following DataFrame's Grouping column specifies the same grouping as the vector we used in the previous examples.: >>> import pandas as pd >>> df = pd.DataFrame.from_dict( ... {'Grouping': {'s1': 'G1', 's2': 'G1', 's3': 'G1', 's4': 'G2', ... 's5': 'G2', 's6': 'G2'}}) >>> permdisp(dm, df, 'Grouping', permutations=6, test='centroid', seed=42, ... dimensions=dm.shape[0]) method name PERMDISP test statistic name F-value sample size 6 number of groups 2 test statistic 3.670816 p-value 0.285714 number of permutations 6 Name: PERMDISP results, dtype: object Note that when providing a ``DataFrame``, the ordering of rows and/or columns does not affect the grouping vector that is extracted. The ``DataFrame`` must be indexed by the distance matrix IDs (i.e., the row labels must be distance matrix IDs). If IDs (rows) are present in the ``DataFrame`` but not in the distance matrix, they are ignored. The previous example's ``s7`` ID illustrates this behavior: note that even though the ``DataFrame`` had 7 objects, only 6 were used in the test (see the "Sample size" row in the results above to confirm this). Thus, the ``DataFrame`` can be a superset of the distance matrix IDs. Note that the reverse is not true: IDs in the distance matrix *must* be present in the ``DataFrame`` or an error will be raised. PERMDISP should be used to determine whether the dispersions between the groups in your distance matrix are significantly separated. A non-significant test result indicates that group dispersions are similar to each other. PERMANOVA or ANOSIM should then be used in conjunction to determine whether clustering within groups is significant. """ if test not in ("centroid", "median"): raise ValueError("Test must be centroid or median.") if isinstance(distmat, OrdinationResults): ordination = distmat ids = ordination.samples.axes[0].to_list() sample_size = len(ids) elif isinstance(distmat, DistanceMatrix): if method not in ("eigh", "fsvd"): raise ValueError("Method must be eigh or fsvd.") # The `dimensions` argument is passed through to pcoa unchanged. # Since #2285 the eigh path in pcoa honors `dimensions` and can # yield substantial speedups on large distance matrices; the # previous code here forced `dimensions=0`, which both discarded # that speedup and tripped pcoa's "EIGH: since no value for # dimensions..." RuntimeWarning on every call (#2430). Users who # deliberately pass `dimensions=0` will still see that warning, # as intended. ids = distmat.ids sample_size = distmat.shape[0] ordination = pcoa( distmat, method=method, dimensions=dimensions, warn_neg_eigval=warn_neg_eigval, ) else: raise TypeError("Input must be a DistanceMatrix or OrdinationResults.") sample_data = ordination.samples.to_numpy(copy=False) num_groups, grouping = _preprocess_input_sng(ids, sample_size, grouping, column) test_stat_function = partial(_compute_groups, sample_data, test) stat, p_value = _run_monte_carlo_stats( test_stat_function, grouping, permutations, seed ) return _build_results( "PERMDISP", "F-value", sample_size, num_groups, stat, p_value, permutations ) def _compute_groups(samples, test_type, grouping): data = np.asarray(samples) groups = [] grouping_array = np.asarray(grouping) for group_id in np.unique(grouping_array): group_data = data[grouping_array == group_id] if test_type == "centroid": center = group_data.mean(axis=0) else: # median center = np.asarray(geomedian_axis_one(group_data.T)) # Distances from each sample in this group to the group center. groups.append(np.linalg.norm(group_data - center, axis=1)) stat, _ = f_oneway(*groups) return float(np.ravel(stat)[0]) scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/_utils.py000066400000000000000000000121711520735541300242650ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from ._cutils import is_symmetric_and_hollow_cy from ._cutils import distmat_reorder_cy, distmat_reorder_condensed_cy def is_symmetric_and_hollow(mat): """Check if a Distance Matrix is symmetric and hollow. Equivalent to [not (mat.T != mat).any(), np.trace(mat) == 0] Parameters ---------- mat : 2D array_like Distance matrix. Result: ------- is_symmetric: Boolean not (mat.T != mat).any() is_hollow: Boolean np.trace(mat) == 0 Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. """ # is_symmetric_and_hollow_cy is optimized # for the common cas of c_contiguous. # For all other cases, make a copy. if not mat.flags.c_contiguous: mat = np.asarray(mat, order="C") return is_symmetric_and_hollow_cy(mat) def is_symmetric(mat): """Check if a Distance Matrix is symmetric. Equivalent to not (mat.T != mat).any() Parameters ---------- mat : 2D array_like Distance matrix. Result: ------- is_symmetric: Boolean not (mat.T != mat).any() Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. """ # the is_hollow check is really cheap, # so can reuse is_symmetric_and_hollow return is_symmetric_and_hollow(mat)[0] def is_hollow(mat): """Check if a Distance Matrix is hollow. Equivalent to np.trace(mat) == 0 Parameters ---------- mat : 2D array_like Distance matrix. Result: ------- is_hollow: Boolean np.trace(mat) == 0 """ # is_symmetric_and_hollow_cy spends most # of its time in symmetry check, just use numpy return np.trace(mat) == 0 def _validate_order(order, mat): if np.any((order < 0) | (order >= mat.shape[0])): raise ValueError("Invalid reorder_vec") def distmat_reorder(in_mat, reorder_vec, validate=False): """Reorder the rows and columns of a distance matrix given a reorder vector. Not all of the columns need to be used. For example: [ [0, 1, 2, 3] , [1, 0, 4, 5] , [2, 4, 0, 6] , [3, 5, 6, 0] ] with [1,0,3,2] will result in [ [0, 1, 5, 4] , [1, 0, 3, 2] , [5, 3, 0, 6] , [4, 2, 6, 0] ] Parameters ---------- in_mat : 2D array_like Distance matrix, must be in c_order reorder_vec : 1D_array_like List of permutation indexes validate: boolean Optional, if True, validate reorder_vec content, defaults to False Returns ------- out_mat : 2D array_like Distance matrix Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. """ np_reorder = np.asarray(reorder_vec, dtype=np.intp) if validate: _validate_order(np_reorder, in_mat) if not in_mat.flags.c_contiguous: in_mat = np.asarray(in_mat, order="C") out_mat = np.empty([np_reorder.size, np_reorder.size], in_mat.dtype) distmat_reorder_cy(in_mat, np_reorder, out_mat) return out_mat def distmat_reorder_condensed(in_mat, reorder_vec, validate=False): """Reorder the rows and columns of a distance matrix given a reorder vector. Not all of the columns need to be used. For example: [ [0, 1, 2, 3] , [1, 0, 4, 5] , [2, 4, 0, 6] , [3, 5, 6, 0] ] with [1,0,3,2] will result in [ 1, 5, 4 , 3, 2, 6 ] Parameters ---------- in_mat : 2D array_like Distance matrix, must be in c_order reorder_vec : 1D_array_like List of permutation indexes validate: boolean Optional, if True, validate reorder_vec content, defaults to False Returns ------- out_mat_condensed : 1D array_like Condensed distance matrix Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. """ np_reorder = np.asarray(reorder_vec, dtype=np.intp) if validate: _validate_order(np_reorder, in_mat) if not in_mat.flags.c_contiguous: in_mat = np.asarray(in_mat, order="C") csize = ((np_reorder.size - 1) * np_reorder.size) // 2 out_mat_condensed = np.empty([csize], in_mat.dtype) distmat_reorder_condensed_cy(in_mat, np_reorder, out_mat_condensed) return out_mat_condensed scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/000077500000000000000000000000001520735541300235545ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/__init__.py000066400000000000000000000005411520735541300256650ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/000077500000000000000000000000001520735541300244655ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/bioenv_df_vegan.txt000066400000000000000000000021241520735541300303400ustar00rootroot00000000000000#SampleID log(N) P K Ca pH Al 18 2.98568193770049 42.1 139.9 519.4 2.7 39 15 2.59525470695687 39.1 167.3 356.7 2.8 88.1 24 3.00568260440716 67.7 207.1 973.3 3 138 27 3.02529107579554 60.8 233.7 834 2.8 15.4 23 3.16968558067743 54.5 180.6 777 2.7 24.2 19 3.1267605359604 40.9 171.4 691.8 2.7 104.8 22 3.28091121578765 36.7 171.4 738.6 2.8 20.7 16 3.18635263316264 31 138.2 394.6 2.8 74.2 28 3.39450839351136 73.5 260 748.6 2.8 17.9 13 3.3357695763397 40.5 313.8 540.7 2.8 329.7 14 3.08190996979504 38.1 146.8 512.2 2.7 92.3 20 3.26575941076705 61.9 202.2 741.2 2.9 124.3 25 3.1267605359604 50.6 151.7 648 2.9 12.1 7 3.41772668361337 24.6 78.7 188.5 3.1 294.9 5 3.49953328238302 22.7 43.6 240.3 3.1 39 6 2.94968833505258 26.4 61.1 259.1 3 155.1 3 3.43720781918519 32.3 73.7 219 3.3 304.6 4 2.89037175789616 64.9 224.5 517.6 2.9 435.1 2 3.10458667846607 47.4 165.9 436.1 2.9 316.5 9 2.70805020110221 48.4 127.4 499.6 3 227.1 12 2.77258872223978 32.7 126.4 471.4 2.9 108.8 10 2.66025953726586 62.8 215.2 709.7 3.2 168.2 11 2.81540871942271 55.8 205.3 1169.7 3.6 253.6 21 3.04452243772342 26.5 104.4 484.8 3 35.8 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/bioenv_dm_vegan.txt000066400000000000000000000234471520735541300303620ustar00rootroot00000000000000 18 15 24 27 23 19 22 16 28 13 14 20 25 7 5 6 3 4 2 9 12 10 11 21 18 0 0.452897212693772 0.715360803826621 0.624766305873718 0.493154219155204 0.43865006075341 0.432340187193151 0.440822999771334 0.698420319937299 0.46351050707088 0.523211654445006 0.408294556891784 0.604911324328014 0.434178076197442 0.545291972003212 0.393272103797605 0.330797959207167 0.563648430837013 0.66523173799306 0.511183841155759 0.46804467412999 0.515485401604058 0.580143332456965 0.668700755517761 15 0.452897212693772 0 0.611610336420561 0.655733483106344 0.410315012072556 0.453712867932398 0.424523404131089 0.377720269664141 0.654941298927269 0.417480326012996 0.35798188425419 0.360483800701559 0.589951055270385 0.532758773890324 0.584210632971972 0.37822819560664 0.53024185913761 0.584066987502168 0.778451630131581 0.543847849995263 0.527747948281903 0.582043972050997 0.591017841508146 0.753206717859593 24 0.715360803826621 0.611610336420561 0 0.749908842875888 0.624415191219002 0.598837193048421 0.660837272556231 0.638184679569268 0.724777756165372 0.708236862111778 0.645430446977294 0.535631415741837 0.693070808707219 0.71138410637102 0.810870811602888 0.638724301482429 0.721802013418365 0.751900340516049 0.812623821498287 0.596958779537393 0.58038306362995 0.631041437421227 0.634765906326142 0.634430266921848 27 0.624766305873718 0.655733483106344 0.749908842875888 0 0.595583136283997 0.480812012211359 0.509183154263298 0.68272679039539 0.503151848497109 0.745346748197303 0.742254576600809 0.581672470591416 0.574612957968774 0.720436148000664 0.836899929519594 0.712346970098655 0.722493161303423 0.81059478353512 0.67179686908506 0.741190787334003 0.632934861831476 0.743347684665419 0.787761710107256 0.545259963579148 23 0.493154219155204 0.410315012072556 0.624415191219002 0.595583136283997 0 0.39798190453075 0.551027253590122 0.530245080842824 0.688639670633179 0.558293400969046 0.499126157677784 0.374655747006781 0.560198031134205 0.575636505169288 0.709011461350035 0.555007697254655 0.569632137079713 0.700292123849093 0.686164552961924 0.610923773488132 0.522084519099983 0.614601499571679 0.573249035174906 0.619889410480321 19 0.43865006075341 0.453712867932398 0.598837193048421 0.480812012211359 0.39798190453075 0 0.447090470008913 0.462780164587808 0.62210941999066 0.517037833858162 0.547198044950618 0.436336586468505 0.466295105039809 0.533153195372235 0.649768050102464 0.468877587536534 0.489021376289978 0.59989451354897 0.600155810641532 0.482373873247893 0.455971043613941 0.485136325934296 0.561030342274039 0.514596020968001 22 0.432340187193151 0.424523404131089 0.660837272556231 0.509183154263298 0.551027253590122 0.447090470008913 0 0.318721801577202 0.560878982326328 0.493770323127832 0.484678838434732 0.466044129553462 0.540556449240843 0.537716889466216 0.700184066308371 0.472868628510347 0.525506721244604 0.632959267911546 0.74368261302233 0.514539804165303 0.555492307675902 0.545820329626384 0.605832461377114 0.55345791449267 16 0.440822999771334 0.377720269664141 0.638184679569268 0.68272679039539 0.530245080842824 0.462780164587808 0.318721801577202 0 0.664347219281937 0.418561808219052 0.408452070724878 0.358924933851484 0.5815245364665 0.515594594372192 0.532206785163483 0.4397020901552 0.529224758564709 0.566927472518065 0.753903949731256 0.515921987762518 0.494683547387077 0.495896853216952 0.583525904687767 0.658433720786117 28 0.698420319937299 0.654941298927269 0.724777756165372 0.503151848497109 0.688639670633179 0.62210941999066 0.560878982326328 0.664347219281937 0 0.733169240464629 0.745486578838407 0.618846839169478 0.713792541454381 0.74890906664669 0.853976950339078 0.756087305765939 0.762966538206308 0.791917677364091 0.81258384801323 0.69092466328736 0.711493718852431 0.72961696443748 0.777088600232844 0.628275585712577 13 0.46351050707088 0.417480326012996 0.708236862111778 0.745346748197303 0.558293400969046 0.517037833858162 0.493770323127832 0.418561808219052 0.733169240464629 0 0.434107073238778 0.495251428454508 0.659888526193112 0.482068398983308 0.561095050557647 0.335593085096115 0.482301178660398 0.475008544079799 0.738041440415793 0.50014768619111 0.58859107425281 0.560373485926146 0.58991583345561 0.703705376166457 14 0.523211654445006 0.35798188425419 0.645430446977294 0.742254576600809 0.499126157677784 0.547198044950618 0.484678838434732 0.408452070724878 0.745486578838407 0.434107073238778 0 0.460778501195483 0.598177860722774 0.566437502573166 0.60997028881234 0.437494609608184 0.560278994397196 0.564565884853771 0.814568858546278 0.563078236117464 0.634425207383389 0.539163427744901 0.64719734947765 0.746247657025891 20 0.408294556891784 0.360483800701559 0.535631415741837 0.581672470591416 0.374655747006781 0.436336586468505 0.466044129553462 0.358924933851484 0.618846839169478 0.495251428454508 0.460778501195483 0 0.614834763166026 0.527001028768971 0.636029763289345 0.402589693145724 0.520623812716001 0.635315798842479 0.669112826680887 0.536517399269416 0.410136150776988 0.536831397119922 0.57987764447421 0.650019383574573 25 0.604911324328014 0.589951055270385 0.693070808707219 0.574612957968774 0.560198031134205 0.466295105039809 0.540556449240843 0.5815245364665 0.713792541454381 0.659888526193112 0.598177860722774 0.614834763166026 0 0.635642388269005 0.743838694259872 0.621437815990208 0.63532741224439 0.661420102186089 0.725910634940022 0.669519591989177 0.689034754247501 0.693127422615701 0.709588799419957 0.678749793333 7 0.434178076197442 0.532758773890324 0.71138410637102 0.720436148000664 0.575636505169288 0.533153195372235 0.537716889466216 0.515594594372192 0.74890906664669 0.482068398983308 0.566437502573166 0.527001028768971 0.635642388269005 0 0.510261674576661 0.323081424973504 0.332861861510004 0.588465187037358 0.640307330403348 0.582254042755471 0.59221097693992 0.57611902810367 0.682931566080637 0.694784212730897 5 0.545291972003212 0.584210632971972 0.810870811602888 0.836899929519594 0.709011461350035 0.649768050102464 0.700184066308371 0.532206785163483 0.853976950339078 0.561095050557647 0.60997028881234 0.636029763289345 0.743838694259872 0.510261674576661 0 0.476300258746816 0.526916663583772 0.593846530768998 0.758314271175518 0.691571027310973 0.761795894022086 0.702775696818748 0.581204902584864 0.85891984357451 6 0.393272103797605 0.37822819560664 0.638724301482429 0.712346970098655 0.555007697254655 0.468877587536534 0.472868628510347 0.4397020901552 0.756087305765939 0.335593085096115 0.437494609608184 0.402589693145724 0.621437815990208 0.323081424973504 0.476300258746816 0 0.382921704843115 0.495001919452646 0.623361805111518 0.50370863979105 0.494400467755648 0.488742161380673 0.573395486170862 0.701044642267538 3 0.330797959207167 0.53024185913761 0.721802013418365 0.722493161303423 0.569632137079713 0.489021376289978 0.525506721244604 0.529224758564709 0.762966538206308 0.482301178660398 0.560278994397196 0.520623812716001 0.63532741224439 0.332861861510004 0.526916663583772 0.382921704843115 0 0.541116521910622 0.538929257690873 0.50363315957546 0.477667500339432 0.485484212285837 0.642536439557206 0.731616786185991 4 0.563648430837013 0.584066987502168 0.751900340516049 0.81059478353512 0.700292123849093 0.59989451354897 0.632959267911546 0.566927472518065 0.791917677364091 0.475008544079799 0.564565884853771 0.635315798842479 0.661420102186089 0.588465187037358 0.593846530768998 0.495001919452646 0.541116521910622 0 0.569041488360324 0.555333827555126 0.650999789659056 0.618391387774669 0.620122895019617 0.79004091039811 2 0.66523173799306 0.778451630131581 0.812623821498287 0.67179686908506 0.686164552961924 0.600155810641532 0.74368261302233 0.753903949731256 0.81258384801323 0.738041440415793 0.814568858546278 0.669112826680887 0.725910634940022 0.640307330403348 0.758314271175518 0.623361805111518 0.538929257690873 0.569041488360324 0 0.6473786039708 0.537771707661098 0.605751675531862 0.787300504670568 0.71419000634693 9 0.511183841155759 0.543847849995263 0.596958779537393 0.741190787334003 0.610923773488132 0.482373873247893 0.514539804165303 0.515921987762518 0.69092466328736 0.50014768619111 0.563078236117464 0.536517399269416 0.669519591989177 0.582254042755471 0.691571027310973 0.50370863979105 0.50363315957546 0.555333827555126 0.6473786039708 0 0.458910772686871 0.197543573969677 0.453468643433417 0.589071475907458 12 0.46804467412999 0.527747948281903 0.58038306362995 0.632934861831476 0.522084519099983 0.455971043613941 0.555492307675902 0.494683547387077 0.711493718852431 0.58859107425281 0.634425207383389 0.410136150776988 0.689034754247501 0.59221097693992 0.761795894022086 0.494400467755648 0.477667500339432 0.650999789659056 0.537771707661098 0.458910772686871 0 0.405413621307249 0.521219574609625 0.6041813253885 10 0.515485401604058 0.582043972050997 0.631041437421227 0.743347684665419 0.614601499571679 0.485136325934296 0.545820329626384 0.495896853216952 0.72961696443748 0.560373485926146 0.539163427744901 0.536831397119922 0.693127422615701 0.57611902810367 0.702775696818748 0.488742161380673 0.485484212285837 0.618391387774669 0.605751675531862 0.197543573969677 0.405413621307249 0 0.438888571031113 0.584480238627684 11 0.580143332456965 0.591017841508146 0.634765906326142 0.787761710107256 0.573249035174906 0.561030342274039 0.605832461377114 0.583525904687767 0.777088600232844 0.58991583345561 0.64719734947765 0.57987764447421 0.709588799419957 0.682931566080637 0.581204902584864 0.573395486170862 0.642536439557206 0.620122895019617 0.787300504670568 0.453468643433417 0.521219574609625 0.438888571031113 0 0.747120312482333 21 0.668700755517761 0.753206717859593 0.634430266921848 0.545259963579148 0.619889410480321 0.514596020968001 0.55345791449267 0.658433720786117 0.628275585712577 0.703705376166457 0.746247657025891 0.650019383574573 0.678749793333 0.694784212730897 0.85891984357451 0.701044642267538 0.731616786185991 0.79004091039811 0.71419000634693 0.589071475907458 0.6041813253885 0.584480238627684 0.747120312482333 0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/bioenv_exp_results_vegan.txt000066400000000000000000000003441520735541300323260ustar00rootroot00000000000000vars size correlation P 1 0.25163022609618835 P, Al 2 0.4003778484896049 P, Ca, Al 3 0.4004805867496183 P, Ca, pH, Al 4 0.3618749732452448 log(N), P, Ca, pH, Al 5 0.3215524892624249 log(N), P, K, Ca, pH, Al 6 0.2821814757209515 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/df.txt000066400000000000000000000012041520735541300256140ustar00rootroot00000000000000#SampleID TOT_ORG_CARB SILT_CLAY ELEVATION SOIL_MOISTURE_DEFICIT CARB_NITRO_RATIO ANNUAL_SEASON_TEMP ANNUAL_SEASON_PRECPT PH CMIN_RATE LONGITUDE LATITUDE CA1.141704 16.7 73 2003 198 13 10.3 400 7.27 2.276 -111.7666667 36.05 MT2.141698 39.1 35 1000 70 23.087 7 450 6.66 19.7 -114 46.8 CO2.141657 18.1 24 2400 104 31.8 6.1 350 5.68 9.223 -105.3333333 40.58333333 TL3.141709 53.9 52 894 -212 24.6 -9.3 400 4.23 16.456 -149.5833333 68.63333333 SN3.141650 16.6 20 3000 -252 13.9 3.6 600 5.74 6.289 -118.1666667 36.45 ExtraSample 42.0 42 -42 breh 3.6 602 1.74 0.289 -122.7 36.45 BB2.141659 52.2 44 400 -680 21.4 6.1 1200 4.6 2.223 -68.1 44.86666667 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/df_extra_column.txt000066400000000000000000000012701520735541300303770ustar00rootroot00000000000000#SampleID SILT_CLAY ELEVATION ExtraColumn SOIL_MOISTURE_DEFICIT ANNUAL_SEASON_TEMP CARB_NITRO_RATIO ANNUAL_SEASON_PRECPT PH CMIN_RATE LONGITUDE LATITUDE TOT_ORG_CARB TL3.141709 52 894 42 -212 -9.3 24.6 400 4.23 16.456 -149.5833333 68.63333333 53.9 MT2.141698 35 1000 column 70 7 23.087 450 6.66 19.7 -114 46.8 39.1 CO2.141657 24 2400 with 104 6.1 31.8 350 5.68 9.223 -105.3333333 40.58333333 18.1 ExtraSample 42 some -42 3.6 breh 602 1.74 0.289 -122.7 36.45 42.0 SN3.141650 20 3000 really -252 3.6 13.9 600 5.74 6.289 -118.1666667 36.45 16.6 BB2.141659 44 400 invalid -680 6.1 21.4 1200 4.6 2.223 -68.1 44.86666667 52.2 CA1.141704 73 2003 data 198 10.3 13 400 7.27 2.276 -111.7666667 36.05 16.7 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/dm.txt000066400000000000000000000011371520735541300256300ustar00rootroot00000000000000 MT2.141698 CA1.141704 BB2.141659 CO2.141657 TL3.141709 SN3.141650 MT2.141698 0.0 0.623818643706 0.750015427505 0.585201193913 0.729023583672 0.622135587669 CA1.141704 0.623818643706 0.0 0.774881224555 0.649822398416 0.777203137034 0.629507320436 BB2.141659 0.750015427505 0.774881224555 0.0 0.688845424001 0.567470311282 0.721707516043 CO2.141657 0.585201193913 0.649822398416 0.688845424001 0.0 0.658853575764 0.661223617505 TL3.141709 0.729023583672 0.777203137034 0.567470311282 0.658853575764 0.0 0.711173405838 SN3.141650 0.622135587669 0.629507320436 0.721707516043 0.661223617505 0.711173405838 0.0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/dm2.txt000066400000000000000000000011371520735541300257120ustar00rootroot00000000000000 MT2.141698 CA1.141704 BB2.141659 CO2.141657 TL3.141709 SN3.141650 MT2.141698 0.0 0.623818643706 0.750015427505 0.585201193913 0.729023583672 0.822135587669 CA1.141704 0.623818643706 0.0 0.974881224555 0.649822398416 0.737203137034 0.629507320436 BB2.141659 0.750015427505 0.974881224555 0.0 0.688845424001 0.567470311282 0.721707516043 CO2.141657 0.585201193913 0.649822398416 0.688845424001 0.0 0.658853575764 0.661223617505 TL3.141709 0.729023583672 0.737203137034 0.567470311282 0.658853575764 0.0 0.711173405838 SN3.141650 0.822135587669 0.629507320436 0.721707516043 0.661223617505 0.711173405838 0.0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/dm3.txt000066400000000000000000000011371520735541300257130ustar00rootroot00000000000000 MT2.141698 CA1.141704 BB2.141659 CO2.141657 TL3.141709 SN3.141650 MT2.141698 0.0 0.523818643706 0.750015427505 0.585201193913 0.729023583672 0.622135587669 CA1.141704 0.523818643706 0.0 0.774881224555 0.649822398416 0.777203137034 0.629507320436 BB2.141659 0.750015427505 0.774881224555 0.0 0.687745424001 0.567470311282 0.721707516043 CO2.141657 0.585201193913 0.649822398416 0.687745424001 0.0 0.658853575764 0.661223617505 TL3.141709 0.729023583672 0.777203137034 0.567470311282 0.658853575764 0.0 0.781173405838 SN3.141650 0.622135587669 0.629507320436 0.721707516043 0.661223617505 0.781173405838 0.0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/dm4.txt000066400000000000000000000011371520735541300257140ustar00rootroot00000000000000 MT2.141698 CA1.141704 BB2.141659 CO2.141657 TL3.141709 SN3.141650 MT2.141698 0.0 0.623818643706 0.750015427505 0.585201193913 0.729023583672 0.652135587669 CA1.141704 0.623818643706 0.0 0.974881224555 0.649822398416 0.737203137034 0.629507320436 BB2.141659 0.750015427505 0.974881224555 0.0 0.688845424001 0.657470311282 0.721707516043 CO2.141657 0.585201193913 0.649822398416 0.688845424001 0.0 0.658853575764 0.661223617505 TL3.141709 0.729023583672 0.737203137034 0.657470311282 0.658853575764 0.0 0.711173405838 SN3.141650 0.652135587669 0.629507320436 0.721707516043 0.661223617505 0.711173405838 0.0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/dm_reordered.txt000066400000000000000000000011371520735541300276630ustar00rootroot00000000000000 MT2.141698 CO2.141657 BB2.141659 CA1.141704 TL3.141709 SN3.141650 MT2.141698 0.0 0.585201193913 0.750015427505 0.623818643706 0.729023583672 0.622135587669 CO2.141657 0.585201193913 0.0 0.688845424001 0.649822398416 0.658853575764 0.661223617505 BB2.141659 0.750015427505 0.688845424001 0.0 0.774881224555 0.567470311282 0.721707516043 CA1.141704 0.623818643706 0.649822398416 0.774881224555 0.0 0.777203137034 0.629507320436 TL3.141709 0.729023583672 0.658853575764 0.567470311282 0.777203137034 0.0 0.711173405838 SN3.141650 0.622135587669 0.661223617505 0.721707516043 0.629507320436 0.711173405838 0.0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/exp_results.txt000066400000000000000000000022251520735541300276040ustar00rootroot00000000000000vars size correlation PH 1 0.75 SOIL_MOISTURE_DEFICIT, PH 2 0.7464285714285714 SOIL_MOISTURE_DEFICIT, CARB_NITRO_RATIO, PH 3 0.8107142857142857 TOT_ORG_CARB, SOIL_MOISTURE_DEFICIT, CARB_NITRO_RATIO, PH 4 0.8107142857142857 ELEVATION, SOIL_MOISTURE_DEFICIT, CARB_NITRO_RATIO, ANNUAL_SEASON_TEMP, PH 5 0.7892857142857144 TOT_ORG_CARB, ELEVATION, SOIL_MOISTURE_DEFICIT, CARB_NITRO_RATIO, ANNUAL_SEASON_TEMP, PH 6 0.775 TOT_ORG_CARB, ELEVATION, SOIL_MOISTURE_DEFICIT, CARB_NITRO_RATIO, ANNUAL_SEASON_TEMP, ANNUAL_SEASON_PRECPT, PH 7 0.7285714285714285 TOT_ORG_CARB, ELEVATION, SOIL_MOISTURE_DEFICIT, CARB_NITRO_RATIO, ANNUAL_SEASON_TEMP, ANNUAL_SEASON_PRECPT, PH, CMIN_RATE 8 0.675 TOT_ORG_CARB, SILT_CLAY, ELEVATION, SOIL_MOISTURE_DEFICIT, CARB_NITRO_RATIO, ANNUAL_SEASON_TEMP, ANNUAL_SEASON_PRECPT, PH, CMIN_RATE 9 0.6392857142857143 TOT_ORG_CARB, SILT_CLAY, ELEVATION, SOIL_MOISTURE_DEFICIT, CARB_NITRO_RATIO, ANNUAL_SEASON_TEMP, ANNUAL_SEASON_PRECPT, PH, CMIN_RATE, LATITUDE 10 0.6071428571428571 TOT_ORG_CARB, SILT_CLAY, ELEVATION, SOIL_MOISTURE_DEFICIT, CARB_NITRO_RATIO, ANNUAL_SEASON_TEMP, ANNUAL_SEASON_PRECPT, PH, CMIN_RATE, LONGITUDE, LATITUDE 11 0.5392857142857144 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/exp_results_different_column_order.txt000066400000000000000000000022251520735541300344020ustar00rootroot00000000000000vars size correlation PH 1 0.75 PH, SOIL_MOISTURE_DEFICIT 2 0.7464285714285714 PH, CARB_NITRO_RATIO, SOIL_MOISTURE_DEFICIT 3 0.8107142857142857 PH, CARB_NITRO_RATIO, SOIL_MOISTURE_DEFICIT, TOT_ORG_CARB 4 0.8107142857142857 PH, ANNUAL_SEASON_TEMP, CARB_NITRO_RATIO, SOIL_MOISTURE_DEFICIT, ELEVATION 5 0.7892857142857144 PH, ANNUAL_SEASON_TEMP, CARB_NITRO_RATIO, SOIL_MOISTURE_DEFICIT, ELEVATION, TOT_ORG_CARB 6 0.775 PH, ANNUAL_SEASON_PRECPT, ANNUAL_SEASON_TEMP, CARB_NITRO_RATIO, SOIL_MOISTURE_DEFICIT, ELEVATION, TOT_ORG_CARB 7 0.7285714285714285 CMIN_RATE, PH, ANNUAL_SEASON_PRECPT, ANNUAL_SEASON_TEMP, CARB_NITRO_RATIO, SOIL_MOISTURE_DEFICIT, ELEVATION, TOT_ORG_CARB 8 0.675 CMIN_RATE, PH, ANNUAL_SEASON_PRECPT, ANNUAL_SEASON_TEMP, CARB_NITRO_RATIO, SOIL_MOISTURE_DEFICIT, ELEVATION, SILT_CLAY, TOT_ORG_CARB 9 0.6392857142857143 LATITUDE, CMIN_RATE, PH, ANNUAL_SEASON_PRECPT, ANNUAL_SEASON_TEMP, CARB_NITRO_RATIO, SOIL_MOISTURE_DEFICIT, ELEVATION, SILT_CLAY, TOT_ORG_CARB 10 0.6071428571428571 LATITUDE, LONGITUDE, CMIN_RATE, PH, ANNUAL_SEASON_PRECPT, ANNUAL_SEASON_TEMP, CARB_NITRO_RATIO, SOIL_MOISTURE_DEFICIT, ELEVATION, SILT_CLAY, TOT_ORG_CARB 11 0.5392857142857144 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/exp_results_single_column.txt000066400000000000000000000000401520735541300325130ustar00rootroot00000000000000vars size correlation PH 1 0.75 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/frameSeries_dm.tsv000066400000000000000000001035771520735541300301650ustar00rootroot00000000000000 zr5156_10V3V4_R1 zr5156_11V3V4_R1 zr5156_12V3V4_R1 zr5156_13V3V4_R1 zr5156_14V3V4_R1 zr5156_15V3V4_R1 zr5156_16V3V4_R1 zr5156_17V3V4_R1 zr5156_18V3V4_R1 zr5156_19V3V4_R1 zr5156_1V3V4_R1 zr5156_20V3V4_R1 zr5156_21V3V4_R1 zr5156_22V3V4_R1 zr5156_23V3V4_R1 zr5156_24V3V4_R1 zr5156_25V3V4_R1 zr5156_26V3V4_R1 zr5156_27V3V4_R1 zr5156_28V3V4_R1 zr5156_29V3V4_R1 zr5156_2V3V4_R1 zr5156_30V3V4_R1 zr5156_31V3V4_R1 zr5156_32V3V4_R1 zr5156_33V3V4_R1 zr5156_34V3V4_R1 zr5156_35V3V4_R1 zr5156_36V3V4_R1 zr5156_37V3V4_R1 zr5156_38V3V4_R1 zr5156_39V3V4_R1 zr5156_3V3V4_R1 zr5156_40V3V4_R1 zr5156_41V3V4_R1 zr5156_42V3V4_R1 zr5156_4V3V4_R1 zr5156_5V3V4_R1 zr5156_6V3V4_R1 zr5156_7V3V4_R1 zr5156_8V3V4_R1 zr5156_9V3V4_R1 zr5156_10V3V4_R1 0.0 0.1262357062761839 0.1193865365457798 0.08369713736578445 0.1659985845782383 0.2413835508626568 0.09222586294019872 0.1332458611895229 0.1530725883054793 0.1030425072609837 0.1507649170302824 0.1787555671808348 0.1597616025172856 0.1898693942662075 0.1360359317680881 0.1049860511593583 0.1746896194906567 0.161129211588336 0.165837544051112 0.1752147914800797 0.1480519516874988 0.1112465247679185 0.1692371646842593 0.1252088150316864 0.08268117179980342 0.1742274829101774 0.1496018871532361 0.1500606848826225 0.0912813927832417 0.144559101309172 0.05810838197701153 0.1171949649446682 0.1380765955687044 0.1182590284387932 0.1356949184522072 0.1492389709105595 0.1719400665956264 0.1291549435784331 0.1468766374442677 0.1091956031010886 0.1143689310080433 0.09455770835222979 zr5156_11V3V4_R1 0.1262357062761839 0.0 0.1051514077284487 0.1436161968850221 0.2326146299642306 0.3219897477207319 0.1306845763682954 0.1726909080063596 0.2094546841590949 0.1785200181052513 0.1752774412896001 0.2154764037924464 0.1105956384726629 0.2579305923909834 0.159789071992378 0.1401926653555514 0.253467238411307 0.1946535754346474 0.1888771836724367 0.2275422217301586 0.2115565064058448 0.1783473469005498 0.2007589770499096 0.2181750700928601 0.1577708345699125 0.2414698314172274 0.1670926567844305 0.1808713654953637 0.1546989219851927 0.1088772819983929 0.1167616325358589 0.1891301816506275 0.1775778470758768 0.1349910326716275 0.1588695258762032 0.1882842047156271 0.1991533541817128 0.1721427946534862 0.2244956129113895 0.1670845888464353 0.2052035117066867 0.1903787489339654 zr5156_12V3V4_R1 0.1193865365457798 0.1051514077284487 0.0 0.1093122761611469 0.1987041345338616 0.2777605474410032 0.09575160285950673 0.1403344910533776 0.1770438457407355 0.1400693448388553 0.1364153324857176 0.1870373808998719 0.09101061477732886 0.2260548001840255 0.1172769090821173 0.1072421916820582 0.2087469669032011 0.1733522824178857 0.1696871005126365 0.187931858353296 0.162882215924352 0.1553874410694003 0.1764760473412724 0.167489650486269 0.1519273675868082 0.1973084855519143 0.1480477158740635 0.1431819486645803 0.1069299038720177 0.1332297613857648 0.1091566636633538 0.1492424223061563 0.152491287745897 0.1083567819591257 0.1427214101618832 0.1611511306235009 0.1595761509757549 0.1500966809337344 0.1781044627881863 0.1159089070519137 0.1687749540518114 0.1445521299410403 zr5156_13V3V4_R1 0.08369713736578445 0.1436161968850221 0.1093122761611469 0.0 0.2099081302071139 0.2547902145261156 0.1183371783778977 0.1595841200777173 0.1877367852297378 0.1389454310660076 0.1728683959814479 0.2188698322004292 0.1554574052267208 0.2346773645328648 0.1586484644018412 0.1308941061459895 0.2012966580779219 0.1917774480379034 0.1982756055583835 0.1921503882730374 0.1557335645633633 0.1629089780904155 0.2032389001242923 0.131159826282788 0.1012771564034674 0.1973138613804784 0.1758042169438702 0.1815975767536929 0.1326513138992096 0.1166921858969914 0.100028511360236 0.1468560396558712 0.1715386724734005 0.1460793979744434 0.1844397746403332 0.1851404905894722 0.2035008838651794 0.1756409562316918 0.1844940306823346 0.1310043927080653 0.1274660625319308 0.1210815382689097 zr5156_14V3V4_R1 0.1659985845782383 0.2326146299642306 0.1987041345338616 0.2099081302071139 0.0 0.1368761603689816 0.1549363528889497 0.1026266319009563 0.06375393548141987 0.1061964577740717 0.1213465082848441 0.07231770914919781 0.2107012493298301 0.057900260661145 0.1424163593326227 0.1471611534836962 0.04812334702685623 0.09078969190065313 0.1086189565288966 0.05872593113570378 0.09151669454001352 0.07821269786940772 0.06996212339862032 0.1368410645527744 0.1756972879054398 0.04427944492288369 0.1206901971025525 0.1140531027519637 0.1152803819279663 0.2484366499552812 0.1479235418939771 0.09430963935200642 0.1121609301391732 0.1397797338573526 0.102358713414537 0.08604434738251315 0.09680238766551985 0.07981215038454734 0.05161595501220772 0.1309676378366985 0.1736693926661831 0.1278738876176231 zr5156_15V3V4_R1 0.2413835508626568 0.3219897477207319 0.2777605474410032 0.2547902145261156 0.1368761603689816 0.0 0.2420450180602975 0.1907140876094187 0.1640753724994711 0.195309117326092 0.2109650211311947 0.1624040520528475 0.2960016006630153 0.1332445557925075 0.2191940344010214 0.2278414102839472 0.1372424420935046 0.1841649631042498 0.2074798245699567 0.1418995799966432 0.1590265675013176 0.1841790746735276 0.1650967973752359 0.1607704526607447 0.2343947977674807 0.1448627995068159 0.2077583468932165 0.202723110815676 0.2119801976204397 0.328921866244096 0.2413729053962549 0.1932601053934642 0.2116749344567443 0.2343824623829839 0.2084371690181891 0.190025213701608 0.184979573702458 0.1814099370308643 0.147337106494635 0.2100482721957215 0.2008409170468961 0.1876003493219673 zr5156_16V3V4_R1 0.09222586294019872 0.1306845763682954 0.09575160285950673 0.1183371783778977 0.1549363528889497 0.2420450180602975 0.0 0.08263613637407852 0.1249797932713108 0.09870148787969783 0.102176599081265 0.1365276515293163 0.116439510078064 0.1898848340513761 0.07786822802993801 0.05401145288005917 0.1608441923525799 0.12045107182917 0.1213421821687465 0.148512405859414 0.1289832913735298 0.1095169693535252 0.1245630108816215 0.1327209909999326 0.1116237507126911 0.1555075513525551 0.1044792964275772 0.1096892560630082 0.07831354584298185 0.1573140686222914 0.08551518076451084 0.1061046095352267 0.09936325979161925 0.07361150317912567 0.1107051637876943 0.1058724170650332 0.1228288320488214 0.1037345909087888 0.1342508169187087 0.07394194432267176 0.1357310753392193 0.09874232058267786 zr5156_17V3V4_R1 0.1332458611895229 0.1726909080063596 0.1403344910533776 0.1595841200777173 0.1026266319009563 0.1907140876094187 0.08263613637407852 0.0 0.08303520928891407 0.06985979390369568 0.07174115638796125 0.08057183456765618 0.1429028601943221 0.1329634637216814 0.0740927879837481 0.07418478958392143 0.1100300707087181 0.07008865816197911 0.07929519403596762 0.09201463976355255 0.08314086994757977 0.07587333147399185 0.06920007949144595 0.112561577121862 0.1351865948955731 0.1001349594748285 0.05998740222523407 0.06601518804953017 0.07115231158863734 0.2064501976046656 0.1229157997755125 0.07753559725691035 0.06881803748322107 0.0820846987106403 0.06395163415235482 0.07172432182235257 0.07559215505254606 0.06027907145870632 0.07871286915773762 0.07430033371847444 0.1330161099409772 0.08857449130841386 zr5156_18V3V4_R1 0.1530725883054793 0.2094546841590949 0.1770438457407355 0.1877367852297378 0.06375393548141987 0.1640753724994711 0.1249797932713108 0.08303520928891407 0.0 0.0832255363968509 0.09796527139450667 0.05608936279497666 0.1755865429819896 0.08740310762140162 0.1193713860376948 0.1145587407339521 0.07865635506232996 0.07683918177728462 0.08384703972285515 0.0654764926759044 0.08287220015736114 0.06969073853841316 0.06692467160975255 0.1238846903158282 0.167732914442687 0.07224645743270168 0.1030843783407304 0.08225899574587957 0.09645584208844683 0.222334873242736 0.1466127868580658 0.07222266017834206 0.09172516908628203 0.1162768066095267 0.07905265996221633 0.0567104313060754 0.07543050314656505 0.0660325232357851 0.05072631112103963 0.09949584542379035 0.1522582519137235 0.1107092109216859 zr5156_19V3V4_R1 0.1030425072609837 0.1785200181052513 0.1400693448388553 0.1389454310660076 0.1061964577740717 0.195309117326092 0.09870148787969783 0.06985979390369568 0.0832255363968509 0.0 0.09753610290549938 0.1017346420142612 0.1644783872622975 0.1251234274252112 0.1115062704977202 0.08954636025289847 0.1098613401946223 0.09871639363275223 0.1028380618525378 0.1084763047550623 0.08667891705872721 0.0609989726364468 0.1037837460743364 0.09207793857497111 0.1192469688205176 0.1093112721543453 0.08860707657380694 0.09312238939191526 0.06703878855206988 0.1785201686029534 0.1013136603848457 0.05611783879110421 0.07991271618393228 0.1016673356245131 0.07696853985358303 0.08080498078476354 0.1052781884103818 0.07799275478850214 0.08496026819850905 0.0787607762755338 0.1123099056561567 0.070619182570014 zr5156_1V3V4_R1 0.1507649170302824 0.1752774412896001 0.1364153324857176 0.1728683959814479 0.1213465082848441 0.2109650211311947 0.102176599081265 0.07174115638796125 0.09796527139450667 0.09753610290549938 0.0 0.1058795883794136 0.1265643434969865 0.155743644118801 0.06725291003387059 0.09267213929408216 0.1381552217190008 0.09799732995730347 0.09099430012236363 0.1143484501154464 0.1103350912367392 0.09941983080123719 0.086317365683536 0.1389912666262949 0.1561556350671514 0.1248455745183124 0.06899021103431674 0.04491924818433251 0.08853138818432028 0.2150451203669508 0.141020216879513 0.09776379105212425 0.08602353922419155 0.07643882594134431 0.06559889924995091 0.08577151478557646 0.06141240424591926 0.08088966140739555 0.1147481134136431 0.08839165726498709 0.1473847349914805 0.1081185183786368 zr5156_20V3V4_R1 0.1787555671808348 0.2154764037924464 0.1870373808998719 0.2188698322004292 0.07231770914919781 0.1624040520528475 0.1365276515293163 0.08057183456765618 0.05608936279497666 0.1017346420142612 0.1058795883794136 0.0 0.1856215824235532 0.08124894543727004 0.1203346033797456 0.1210423617877242 0.08678691470162736 0.07878321710685555 0.08251367293404212 0.07431170062957689 0.1012643196396393 0.09394507079725747 0.05876448547475446 0.1413412612940679 0.1841899618245461 0.07403227741159515 0.1010815612105938 0.08596708777539988 0.1196311645508068 0.2561636268431229 0.1686669900374906 0.1038716112494349 0.104780687821961 0.121413112290244 0.08363180629625183 0.0738963402814959 0.06333925762127142 0.08108268378100926 0.06524006389939632 0.1262928005887744 0.1813701927393017 0.1383471986853116 zr5156_21V3V4_R1 0.1597616025172856 0.1105956384726629 0.09101061477732886 0.1554574052267208 0.2107012493298301 0.2960016006630153 0.116439510078064 0.1429028601943221 0.1755865429819896 0.1644783872622975 0.1265643434969865 0.1856215824235532 0.0 0.2422305212056287 0.1191151038625533 0.1169683527831099 0.2226713215858389 0.1725616625016525 0.1674819007527343 0.2000242854405594 0.1893928451337126 0.1651755734154186 0.1696921049902433 0.2038597221154419 0.1761684912419932 0.2128256620069059 0.1444194353155745 0.1334576325902176 0.1363377877720563 0.1545135185562693 0.1363237846992682 0.1673044393176452 0.1526877722173743 0.105266118247574 0.1397791086721317 0.1602177138243876 0.146685116887321 0.1591529090740322 0.1936066013830202 0.1364861137771962 0.2008336857804045 0.1725630164924993 zr5156_22V3V4_R1 0.1898693942662075 0.2579305923909834 0.2260548001840255 0.2346773645328648 0.057900260661145 0.1332445557925075 0.1898848340513761 0.1329634637216814 0.08740310762140162 0.1251234274252112 0.155743644118801 0.08124894543727004 0.2422305212056287 0.0 0.1755267816641163 0.1756754639634829 0.073606405409486 0.1180374369948224 0.1235755058514064 0.08494248874020731 0.1174110944530593 0.1123675569281386 0.1074794677126668 0.1595554892825317 0.1984663371830582 0.06210691037205323 0.1481196194399604 0.1388728467906852 0.1418026627986534 0.2768515563562317 0.1825557453516704 0.1196410278389074 0.1409395006935493 0.1669410671259341 0.1214607606546082 0.110851678484599 0.1206105207768592 0.1122631081988461 0.08220976258824157 0.1646064624803332 0.2042014882530901 0.1646434831272248 zr5156_23V3V4_R1 0.1360359317680881 0.159789071992378 0.1172769090821173 0.1586484644018412 0.1424163593326227 0.2191940344010214 0.07786822802993801 0.0740927879837481 0.1193713860376948 0.1115062704977202 0.06725291003387059 0.1203346033797456 0.1191151038625533 0.1755267816641163 0.0 0.06531911833602928 0.1447300758373689 0.1045145823019871 0.1027061087038626 0.1327128900376398 0.1255703871944387 0.1152778230783219 0.1060029076129174 0.1370131392756702 0.137458916857107 0.1438363335802246 0.07624260366493245 0.07524276786752448 0.08764847433444532 0.1967450721390073 0.1191018090830029 0.1151892353153167 0.09909052502969176 0.05931195788646768 0.08339582346188876 0.09811943883304841 0.08949239010667165 0.09259485726203597 0.1209557771688734 0.08013308923594474 0.1365335693351368 0.110998504901641 zr5156_24V3V4_R1 0.1049860511593583 0.1401926653555514 0.1072421916820582 0.1308941061459895 0.1471611534836962 0.2278414102839472 0.05401145288005917 0.07418478958392143 0.1145587407339521 0.08954636025289847 0.09267213929408216 0.1210423617877242 0.1169683527831099 0.1756754639634829 0.06531911833602928 0.0 0.1502832416013179 0.1067710181941987 0.1061290633013017 0.1379781501203592 0.12515638131281 0.09913849387830026 0.1164588445229939 0.1317057656664396 0.1169260600375063 0.1462928674062135 0.09185636105489747 0.08804859487181674 0.07108646529012899 0.1679802590670332 0.09921407494202536 0.09812719761369507 0.08820298476069452 0.06010303997262437 0.09020751232207111 0.09837968550510195 0.1104348923324209 0.09720692343733198 0.1229139652860976 0.07079867089860219 0.1327854232072213 0.09746813415503264 zr5156_25V3V4_R1 0.1746896194906567 0.253467238411307 0.2087469669032011 0.2012966580779219 0.04812334702685623 0.1372424420935046 0.1608441923525799 0.1100300707087181 0.07865635506232996 0.1098613401946223 0.1381552217190008 0.08678691470162736 0.2226713215858389 0.073606405409486 0.1447300758373689 0.1502832416013179 0.0 0.1043792539148186 0.1236315321827428 0.0709620550790759 0.08794307691682986 0.09904525329564624 0.0946654938685631 0.1302099875593525 0.1760172303189602 0.05135724925564918 0.1329067510430049 0.1281675140352214 0.1339038795483324 0.2533810718223353 0.1661064734830484 0.1052777804781497 0.1313728749046526 0.1615327641223157 0.1288630226916564 0.1074080498446083 0.1119841331692077 0.1029044559270918 0.05698861093521006 0.1373696060893588 0.1707707847040014 0.133037686536992 zr5156_26V3V4_R1 0.161129211588336 0.1946535754346474 0.1733522824178857 0.1917774480379034 0.09078969190065313 0.1841649631042498 0.12045107182917 0.07008865816197911 0.07683918177728462 0.09871639363275223 0.09799732995730347 0.07878321710685555 0.1725616625016525 0.1180374369948224 0.1045145823019871 0.1067710181941987 0.1043792539148186 0.0 0.04443749532122632 0.07526343284271764 0.08130402562282243 0.07338911020025321 0.06687342391905679 0.1234011810329324 0.125784220632367 0.09212529243856292 0.05543553476911059 0.08517475025845339 0.1005496762930421 0.2344744444268831 0.1436209415497395 0.08525782962378581 0.06135349734319131 0.09851630396881918 0.07490410326865986 0.06042391936866871 0.0709047818626396 0.0567232774169169 0.08118965111940799 0.1105407079365012 0.1642047146947 0.1225829219859804 zr5156_27V3V4_R1 0.165837544051112 0.1888771836724367 0.1696871005126365 0.1982756055583835 0.1086189565288966 0.2074798245699567 0.1213421821687465 0.07929519403596762 0.08384703972285515 0.1028380618525378 0.09099430012236363 0.08251367293404212 0.1674819007527343 0.1235755058514064 0.1027061087038626 0.1061290633013017 0.1236315321827428 0.04443749532122632 0.0 0.09843983697412532 0.1041635308603416 0.08500801186774593 0.0790653247825966 0.1420473050122881 0.1370681319561848 0.1092685826269802 0.04868840896146547 0.08040003540536432 0.104127688547458 0.2377777064433007 0.1572225496111248 0.08756271162253361 0.05713884128694471 0.09426314487323312 0.06132904768143902 0.0632648239213944 0.07590344590544494 0.07088252545912956 0.1043985706380321 0.116331928374334 0.1773828114798063 0.1316397181630972 zr5156_28V3V4_R1 0.1752147914800797 0.2275422217301586 0.187931858353296 0.1921503882730374 0.05872593113570378 0.1418995799966432 0.148512405859414 0.09201463976355255 0.0654764926759044 0.1084763047550623 0.1143484501154464 0.07431170062957689 0.2000242854405594 0.08494248874020731 0.1327128900376398 0.1379781501203592 0.0709620550790759 0.07526343284271764 0.09843983697412532 0.0 0.05864280757027062 0.09013980716622781 0.06596833655200689 0.1162127451167597 0.1607511973768047 0.05341404063172048 0.101482891446088 0.1117912976759633 0.1127973840937417 0.2399144610940579 0.1602139154980649 0.08871939095328259 0.1051599736026621 0.1264384414435232 0.1034236138857928 0.08663455480160505 0.09383929438294789 0.08360393754612507 0.05782839463975919 0.124745846611633 0.1693508749517296 0.1323556664653223 zr5156_29V3V4_R1 0.1480519516874988 0.2115565064058448 0.162882215924352 0.1557335645633633 0.09151669454001352 0.1590265675013176 0.1289832913735298 0.08314086994757977 0.08287220015736114 0.08667891705872721 0.1103350912367392 0.1012643196396393 0.1893928451337126 0.1174110944530593 0.1255703871944387 0.12515638131281 0.08794307691682986 0.08130402562282243 0.1041635308603416 0.05864280757027062 0.0 0.07630875662648294 0.07919833370291939 0.08696090717071786 0.1376305771883671 0.0808309425513034 0.09510023724624679 0.1132338807012602 0.09791462900397319 0.2131426008999406 0.1367106274269204 0.06827977668864908 0.1034362939298921 0.1202407917718846 0.1096511231485762 0.08790458984672868 0.1023554591348991 0.08145892335326672 0.06929952689801679 0.1040491012469253 0.1377790116599498 0.1084175346524984 zr5156_2V3V4_R1 0.1112465247679185 0.1783473469005498 0.1553874410694003 0.1629089780904155 0.07821269786940772 0.1841790746735276 0.1095169693535252 0.07587333147399185 0.06969073853841316 0.0609989726364468 0.09941983080123719 0.09394507079725747 0.1651755734154186 0.1123675569281386 0.1152778230783219 0.09913849387830026 0.09904525329564624 0.07338911020025321 0.08500801186774593 0.09013980716622781 0.07630875662648294 0.0 0.08687578609232423 0.1009315579237222 0.1326620868190357 0.1012494507527034 0.08844108777355007 0.09186086909218714 0.07272671088484615 0.2040286684103269 0.1013769576742951 0.05531367056656115 0.07350886607183753 0.1034727958228171 0.07613494436349319 0.0674369517807583 0.0789257782507407 0.0420327233925696 0.0698463677619778 0.08622211236971568 0.1277098088342294 0.08309564574942276 zr5156_30V3V4_R1 0.1692371646842593 0.2007589770499096 0.1764760473412724 0.2032389001242923 0.06996212339862032 0.1650967973752359 0.1245630108816215 0.06920007949144595 0.06692467160975255 0.1037837460743364 0.086317365683536 0.05876448547475446 0.1696921049902433 0.1074794677126668 0.1060029076129174 0.1164588445229939 0.0946654938685631 0.06687342391905679 0.0790653247825966 0.06596833655200689 0.07919833370291939 0.08687578609232423 0.0 0.1238984522112872 0.1644876473395898 0.08307955480904008 0.08343015904621844 0.08490608946949572 0.1068360768335047 0.235647394116081 0.1486211714669667 0.09084471310296907 0.09160424651084875 0.1027820712620189 0.07592115588638786 0.06792796390297036 0.06625077353928581 0.0644417469616961 0.0714730621416056 0.1156778361865623 0.165536508403527 0.1245190784169049 zr5156_31V3V4_R1 0.1252088150316864 0.2181750700928601 0.167489650486269 0.131159826282788 0.1368410645527744 0.1607704526607447 0.1327209909999326 0.112561577121862 0.1238846903158282 0.09207793857497111 0.1389912666262949 0.1413412612940679 0.2038597221154419 0.1595554892825317 0.1370131392756702 0.1317057656664396 0.1302099875593525 0.1234011810329324 0.1420473050122881 0.1162127451167597 0.08696090717071786 0.1009315579237222 0.1238984522112872 0.0 0.1240010381044835 0.1373375601400495 0.1299328250599692 0.1388719144556062 0.1146529538980112 0.2028384589348753 0.1337494407386485 0.0979591241135474 0.134027827423915 0.1413658681223808 0.1360229809862496 0.116912696834271 0.1406802119790954 0.1094172671246521 0.1082413342006877 0.1060190194170001 0.08482542432750666 0.07455250371809519 zr5156_32V3V4_R1 0.08268117179980342 0.1577708345699125 0.1519273675868082 0.1012771564034674 0.1756972879054398 0.2343947977674807 0.1116237507126911 0.1351865948955731 0.167732914442687 0.1192469688205176 0.1561556350671514 0.1841899618245461 0.1761684912419932 0.1984663371830582 0.137458916857107 0.1169260600375063 0.1760172303189602 0.125784220632367 0.1370681319561848 0.1607511973768047 0.1376305771883671 0.1326620868190357 0.1644876473395898 0.1240010381044835 0.0 0.1774916894187259 0.1138407775271362 0.1686100181194675 0.1178957857066783 0.1690434364297126 0.08383457056928388 0.1333717746469479 0.1189228624913752 0.1206213225244056 0.1521659068500048 0.1549336344833185 0.1788617068567274 0.1471852797083001 0.1564186804877641 0.1280145613178406 0.1222913335609594 0.1108203144145568 zr5156_33V3V4_R1 0.1742274829101774 0.2414698314172274 0.1973084855519143 0.1973138613804784 0.04427944492288369 0.1448627995068159 0.1555075513525551 0.1001349594748285 0.07224645743270168 0.1093112721543453 0.1248455745183124 0.07403227741159515 0.2128256620069059 0.06210691037205323 0.1438363335802246 0.1462928674062135 0.05135724925564918 0.09212529243856292 0.1092685826269802 0.05341404063172048 0.0808309425513034 0.1012494507527034 0.08307955480904008 0.1373375601400495 0.1774916894187259 0.0 0.1187013834079619 0.1131705830938557 0.1192823377168671 0.2433961939289964 0.1675122668634584 0.0912750400418213 0.1174453107218831 0.1461492540159815 0.1157637817868849 0.09502672361548307 0.09987904226520145 0.09505323762032163 0.06074165405775561 0.1332955653137387 0.1790707952239549 0.138269372102398 zr5156_34V3V4_R1 0.1496018871532361 0.1670926567844305 0.1480477158740635 0.1758042169438702 0.1206901971025525 0.2077583468932165 0.1044792964275772 0.05998740222523407 0.1030843783407304 0.08860707657380694 0.06899021103431674 0.1010815612105938 0.1444194353155745 0.1481196194399604 0.07624260366493245 0.09185636105489747 0.1329067510430049 0.05543553476911059 0.04868840896146547 0.101482891446088 0.09510023724624679 0.08844108777355007 0.08343015904621844 0.1299328250599692 0.1138407775271362 0.1187013834079619 0.0 0.07253031963137985 0.08955207791470898 0.2209310967325532 0.1338806374398232 0.09196437930107422 0.05556145297834826 0.07373480062868552 0.0569631231348962 0.08129464309027375 0.08027885251518388 0.07336079523131014 0.1078632904903195 0.09944659213735112 0.1529778505728458 0.1133863079229603 zr5156_35V3V4_R1 0.1500606848826225 0.1808713654953637 0.1431819486645803 0.1815975767536929 0.1140531027519637 0.202723110815676 0.1096892560630082 0.06601518804953017 0.08225899574587957 0.09312238939191526 0.04491924818433251 0.08596708777539988 0.1334576325902176 0.1388728467906852 0.07524276786752448 0.08804859487181674 0.1281675140352214 0.08517475025845339 0.08040003540536432 0.1117912976759633 0.1132338807012602 0.09186086909218714 0.08490608946949572 0.1388719144556062 0.1686100181194675 0.1131705830938557 0.07253031963137985 0.0 0.08929317958961092 0.2205530923235972 0.148931361561393 0.08952210500788307 0.08116302034006075 0.0796186162812691 0.05635847656736118 0.0741297127837791 0.0559730905798909 0.07726305230758866 0.1035251812645182 0.09140527550336644 0.1547068425897874 0.1100166471315029 zr5156_36V3V4_R1 0.0912813927832417 0.1546989219851927 0.1069299038720177 0.1326513138992096 0.1152803819279663 0.2119801976204397 0.07831354584298185 0.07115231158863734 0.09645584208844683 0.06703878855206988 0.08853138818432028 0.1196311645508068 0.1363377877720563 0.1418026627986534 0.08764847433444532 0.07108646529012899 0.1339038795483324 0.1005496762930421 0.104127688547458 0.1127973840937417 0.09791462900397319 0.07272671088484615 0.1068360768335047 0.1146529538980112 0.1178957857066783 0.1192823377168671 0.08955207791470898 0.08929317958961092 0.0 0.1688428724669093 0.08794329654551179 0.06931938640236024 0.07379289887134234 0.07116679305509278 0.0728436935296748 0.08522666507916347 0.1044775375989856 0.0731090544920879 0.1010511511905997 0.05019906030334988 0.1157586709622803 0.0794395863043969 zr5156_37V3V4_R1 0.144559101309172 0.1088772819983929 0.1332297613857648 0.1166921858969914 0.2484366499552812 0.328921866244096 0.1573140686222914 0.2064501976046656 0.222334873242736 0.1785201686029534 0.2150451203669508 0.2561636268431229 0.1545135185562693 0.2768515563562317 0.1967450721390073 0.1679802590670332 0.2533810718223353 0.2344744444268831 0.2377777064433007 0.2399144610940579 0.2131426008999406 0.2040286684103269 0.235647394116081 0.2028384589348753 0.1690434364297126 0.2433961939289964 0.2209310967325532 0.2205530923235972 0.1688428724669093 0.0 0.1352007578348229 0.180999355245605 0.2115009040682549 0.1835499498731898 0.2132309477093111 0.2128737552097922 0.2468673382678022 0.2132182939304277 0.22535850721593 0.1682463117714778 0.1874393102781126 0.18003132611175 zr5156_38V3V4_R1 0.05810838197701153 0.1167616325358589 0.1091566636633538 0.100028511360236 0.1479235418939771 0.2413729053962549 0.08551518076451084 0.1229157997755125 0.1466127868580658 0.1013136603848457 0.141020216879513 0.1686669900374906 0.1363237846992682 0.1825557453516704 0.1191018090830029 0.09921407494202536 0.1661064734830484 0.1436209415497395 0.1572225496111248 0.1602139154980649 0.1367106274269204 0.1013769576742951 0.1486211714669667 0.1337494407386485 0.08383457056928388 0.1675122668634584 0.1338806374398232 0.148931361561393 0.08794329654551179 0.1352007578348229 0.0 0.1139162857600752 0.1258731045422016 0.1002566675964894 0.1233097624859415 0.1353396237386873 0.158419444876432 0.113078898847648 0.1318772629319251 0.1025817862547318 0.1188094866787605 0.1040218736336048 zr5156_39V3V4_R1 0.1171949649446682 0.1891301816506275 0.1492424223061563 0.1468560396558712 0.09430963935200642 0.1932601053934642 0.1061046095352267 0.07753559725691035 0.07222266017834206 0.05611783879110421 0.09776379105212425 0.1038716112494349 0.1673044393176452 0.1196410278389074 0.1151892353153167 0.09812719761369507 0.1052777804781497 0.08525782962378581 0.08756271162253361 0.08871939095328259 0.06827977668864908 0.05531367056656115 0.09084471310296907 0.0979591241135474 0.1333717746469479 0.0912750400418213 0.09196437930107422 0.08952210500788307 0.06931938640236024 0.180999355245605 0.1139162857600752 0.0 0.0793363748306886 0.09667707293725775 0.07500183477834294 0.05998668523430459 0.09603735891837441 0.06407993221728969 0.07364087102953018 0.0841988972355663 0.1253477686721348 0.08425718423704588 zr5156_3V3V4_R1 0.1380765955687044 0.1775778470758768 0.152491287745897 0.1715386724734005 0.1121609301391732 0.2116749344567443 0.09936325979161925 0.06881803748322107 0.09172516908628203 0.07991271618393228 0.08602353922419155 0.104780687821961 0.1526877722173743 0.1409395006935493 0.09909052502969176 0.08820298476069452 0.1313728749046526 0.06135349734319131 0.05713884128694471 0.1051599736026621 0.1034362939298921 0.07350886607183753 0.09160424651084875 0.134027827423915 0.1189228624913752 0.1174453107218831 0.05556145297834826 0.08116302034006075 0.07379289887134234 0.2115009040682549 0.1258731045422016 0.0793363748306886 0.0 0.08373480193011155 0.06327159323423624 0.07347913747915685 0.08887165680412651 0.0638807158669014 0.104625081999776 0.0867735093246497 0.1510897179571402 0.1039641165049727 zr5156_40V3V4_R1 0.1182590284387932 0.1349910326716275 0.1083567819591257 0.1460793979744434 0.1397797338573526 0.2343824623829839 0.07361150317912567 0.0820846987106403 0.1162768066095267 0.1016673356245131 0.07643882594134431 0.121413112290244 0.105266118247574 0.1669410671259341 0.05931195788646768 0.06010303997262437 0.1615327641223157 0.09851630396881918 0.09426314487323312 0.1264384414435232 0.1202407917718846 0.1034727958228171 0.1027820712620189 0.1413658681223808 0.1206213225244056 0.1461492540159815 0.07373480062868552 0.0796186162812691 0.07116679305509278 0.1835499498731898 0.1002566675964894 0.09667707293725775 0.08373480193011155 0.0 0.0646901863579918 0.0841188930266444 0.09307281344584185 0.08932489766976665 0.1277825808297082 0.07926549125591863 0.149082220904614 0.1114119040038509 zr5156_41V3V4_R1 0.1356949184522072 0.1588695258762032 0.1427214101618832 0.1844397746403332 0.102358713414537 0.2084371690181891 0.1107051637876943 0.06395163415235482 0.07905265996221633 0.07696853985358303 0.06559889924995091 0.08363180629625183 0.1397791086721317 0.1214607606546082 0.08339582346188876 0.09020751232207111 0.1288630226916564 0.07490410326865986 0.06132904768143902 0.1034236138857928 0.1096511231485762 0.07613494436349319 0.07592115588638786 0.1360229809862496 0.1521659068500048 0.1157637817868849 0.0569631231348962 0.05635847656736118 0.0728436935296748 0.2132309477093111 0.1233097624859415 0.07500183477834294 0.06327159323423624 0.0646901863579918 0.0 0.05346196830622852 0.06874532295201652 0.05704439051065374 0.09660602733837584 0.09668633348787234 0.1544663798090666 0.1111660506442167 zr5156_42V3V4_R1 0.1492389709105595 0.1882842047156271 0.1611511306235009 0.1851404905894722 0.08604434738251315 0.190025213701608 0.1058724170650332 0.07172432182235257 0.0567104313060754 0.08080498078476354 0.08577151478557646 0.0738963402814959 0.1602177138243876 0.110851678484599 0.09811943883304841 0.09837968550510195 0.1074080498446083 0.06042391936866871 0.0632648239213944 0.08663455480160505 0.08790458984672868 0.0674369517807583 0.06792796390297036 0.116912696834271 0.1549336344833185 0.09502672361548307 0.08129464309027375 0.0741297127837791 0.08522666507916347 0.2128737552097922 0.1353396237386873 0.05998668523430459 0.07347913747915685 0.0841188930266444 0.05346196830622852 0.0 0.07072936610639428 0.05044240463618335 0.0746529662660631 0.09413368674655981 0.148989690647545 0.104263380286519 zr5156_4V3V4_R1 0.1719400665956264 0.1991533541817128 0.1595761509757549 0.2035008838651794 0.09680238766551985 0.184979573702458 0.1228288320488214 0.07559215505254606 0.07543050314656505 0.1052781884103818 0.06141240424591926 0.06333925762127142 0.146685116887321 0.1206105207768592 0.08949239010667165 0.1104348923324209 0.1119841331692077 0.0709047818626396 0.07590344590544494 0.09383929438294789 0.1023554591348991 0.0789257782507407 0.06625077353928581 0.1406802119790954 0.1788617068567274 0.09987904226520145 0.08027885251518388 0.0559730905798909 0.1044775375989856 0.2468673382678022 0.158419444876432 0.09603735891837441 0.08887165680412651 0.09307281344584185 0.06874532295201652 0.07072936610639428 0.0 0.06182863394483688 0.08518471960424352 0.1128638042424907 0.1703999656298808 0.1262217229766436 zr5156_5V3V4_R1 0.1291549435784331 0.1721427946534862 0.1500966809337344 0.1756409562316918 0.07981215038454734 0.1814099370308643 0.1037345909087888 0.06027907145870632 0.0660325232357851 0.07799275478850214 0.08088966140739555 0.08108268378100926 0.1591529090740322 0.1122631081988461 0.09259485726203597 0.09720692343733198 0.1029044559270918 0.0567232774169169 0.07088252545912956 0.08360393754612507 0.08145892335326672 0.0420327233925696 0.0644417469616961 0.1094172671246521 0.1471852797083001 0.09505323762032163 0.07336079523131014 0.07726305230758866 0.0731090544920879 0.2132182939304277 0.113078898847648 0.06407993221728969 0.0638807158669014 0.08932489766976665 0.05704439051065374 0.05044240463618335 0.06182863394483688 0.0 0.07205782034366952 0.08667352924759916 0.1403661231953189 0.09708488328178215 zr5156_6V3V4_R1 0.1468766374442677 0.2244956129113895 0.1781044627881863 0.1844940306823346 0.05161595501220772 0.147337106494635 0.1342508169187087 0.07871286915773762 0.05072631112103963 0.08496026819850905 0.1147481134136431 0.06524006389939632 0.1936066013830202 0.08220976258824157 0.1209557771688734 0.1229139652860976 0.05698861093521006 0.08118965111940799 0.1043985706380321 0.05782839463975919 0.06929952689801679 0.0698463677619778 0.0714730621416056 0.1082413342006877 0.1564186804877641 0.06074165405775561 0.1078632904903195 0.1035251812645182 0.1010511511905997 0.22535850721593 0.1318772629319251 0.07364087102953018 0.104625081999776 0.1277825808297082 0.09660602733837584 0.0746529662660631 0.08518471960424352 0.07205782034366952 0.0 0.102948784071646 0.1398437820759513 0.1022986047425159 zr5156_7V3V4_R1 0.1091956031010886 0.1670845888464353 0.1159089070519137 0.1310043927080653 0.1309676378366985 0.2100482721957215 0.07394194432267176 0.07430033371847444 0.09949584542379035 0.0787607762755338 0.08839165726498709 0.1262928005887744 0.1364861137771962 0.1646064624803332 0.08013308923594474 0.07079867089860219 0.1373696060893588 0.1105407079365012 0.116331928374334 0.124745846611633 0.1040491012469253 0.08622211236971568 0.1156778361865623 0.1060190194170001 0.1280145613178406 0.1332955653137387 0.09944659213735112 0.09140527550336644 0.05019906030334988 0.1682463117714778 0.1025817862547318 0.0841988972355663 0.0867735093246497 0.07926549125591863 0.09668633348787234 0.09413368674655981 0.1128638042424907 0.08667352924759916 0.102948784071646 0.0 0.09303708683358188 0.06804559561595384 zr5156_8V3V4_R1 0.1143689310080433 0.2052035117066867 0.1687749540518114 0.1274660625319308 0.1736693926661831 0.2008409170468961 0.1357310753392193 0.1330161099409772 0.1522582519137235 0.1123099056561567 0.1473847349914805 0.1813701927393017 0.2008336857804045 0.2042014882530901 0.1365335693351368 0.1327854232072213 0.1707707847040014 0.1642047146947 0.1773828114798063 0.1693508749517296 0.1377790116599498 0.1277098088342294 0.165536508403527 0.08482542432750666 0.1222913335609594 0.1790707952239549 0.1529778505728458 0.1547068425897874 0.1157586709622803 0.1874393102781126 0.1188094866787605 0.1253477686721348 0.1510897179571402 0.149082220904614 0.1544663798090666 0.148989690647545 0.1703999656298808 0.1403661231953189 0.1398437820759513 0.09303708683358188 0.0 0.07605080457182967 zr5156_9V3V4_R1 0.09455770835222979 0.1903787489339654 0.1445521299410403 0.1210815382689097 0.1278738876176231 0.1876003493219673 0.09874232058267786 0.08857449130841386 0.1107092109216859 0.070619182570014 0.1081185183786368 0.1383471986853116 0.1725630164924993 0.1646434831272248 0.110998504901641 0.09746813415503264 0.133037686536992 0.1225829219859804 0.1316397181630972 0.1323556664653223 0.1084175346524984 0.08309564574942276 0.1245190784169049 0.07455250371809519 0.1108203144145568 0.138269372102398 0.1133863079229603 0.1100166471315029 0.0794395863043969 0.18003132611175 0.1040218736336048 0.08425718423704588 0.1039641165049727 0.1114119040038509 0.1111660506442167 0.104263380286519 0.1262217229766436 0.09708488328178215 0.1022986047425159 0.06804559561595384 0.07605080457182967 0.0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/frameSeries_grouping.tsv000066400000000000000000000027301520735541300314040ustar00rootroot00000000000000sample_name tumor zr5156_1V3V4_R1 no-tumor mice zr5156_2V3V4_R1 no-tumor mice zr5156_3V3V4_R1 no-tumor mice zr5156_4V3V4_R1 no-tumor mice zr5156_5V3V4_R1 no-tumor mice zr5156_6V3V4_R1 tumor-bearing mice zr5156_7V3V4_R1 tumor-bearing mice zr5156_8V3V4_R1 tumor-bearing mice zr5156_33V3V4_R1 tumor-bearing mice zr5156_10V3V4_R1 tumor-bearing mice zr5156_11V3V4_R1 tumor-bearing mice zr5156_12V3V4_R1 tumor-bearing mice zr5156_13V3V4_R1 tumor-bearing mice zr5156_14V3V4_R1 tumor-bearing mice zr5156_15V3V4_R1 tumor-bearing mice zr5156_16V3V4_R1 tumor-bearing mice zr5156_17V3V4_R1 tumor-bearing mice zr5156_18V3V4_R1 tumor-bearing mice zr5156_19V3V4_R1 tumor-bearing mice zr5156_20V3V4_R1 tumor-bearing mice zr5156_21V3V4_R1 tumor-bearing mice zr5156_22V3V4_R1 tumor-bearing mice zr5156_23V3V4_R1 tumor-bearing mice zr5156_24V3V4_R1 tumor-bearing mice zr5156_25V3V4_R1 tumor-bearing mice zr5156_26V3V4_R1 tumor-bearing mice zr5156_27V3V4_R1 tumor-bearing mice zr5156_28V3V4_R1 tumor-bearing mice zr5156_29V3V4_R1 tumor-bearing mice zr5156_30V3V4_R1 tumor-bearing mice zr5156_31V3V4_R1 tumor-bearing mice zr5156_32V3V4_R1 tumor-bearing mice zr5156_9V3V4_R1 tumor-bearing mice zr5156_34V3V4_R1 tumor-bearing mice zr5156_35V3V4_R1 tumor-bearing mice zr5156_36V3V4_R1 tumor-bearing mice zr5156_37V3V4_R1 tumor-bearing mice zr5156_38V3V4_R1 tumor-bearing mice zr5156_39V3V4_R1 tumor-bearing mice zr5156_40V3V4_R1 tumor-bearing mice zr5156_41V3V4_R1 tumor-bearing mice zr5156_42V3V4_R1 tumor-bearing mice scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/mantel_env_dm_vegan.txt000066400000000000000000000222401520735541300312160ustar00rootroot000000000000000 2.07679533239178 6.88145502389971 4.47292990349355 2.50815747366843 3.58036212296744 2.6591292750976 2.29553760953804 4.71171667874897 5.16305059040855 2.21426134242764 3.92961213866286 3.13399015473536 4.90270725079791 5.49476199174931 4.24083600731234 6.11441501785041 6.05615282291975 4.95222984315722 4.21090492925648 2.85939902504818 4.97193013540636 6.55517500441812 2.54101803759533 2.07679533239178 0 6.90291144667953 4.64003084174476 3.72544116897342 4.23057909059422 3.32236571813861 2.52327233791657 5.13562550988481 5.1437583829781 2.50862666200143 4.72257599677909 3.43881324942989 4.85150831682718 5.50342943536056 3.52222099128756 5.87491943777315 5.49066317297654 4.27208092800677 3.15270231033824 1.74819033890028 4.12374288054719 6.15931692104792 3.35050234347791 6.88145502389971 6.90291144667953 0 5.48014130249836 5.71422767011491 5.44458516207639 6.21128694887343 7.57897769844682 5.72787031540342 5.50347777475312 6.05215034685817 5.13756253132332 6.81750519634229 8.76568212120474 9.04444618731187 8.33992506606364 9.11412838063313 5.67503738892289 6.94693258686523 5.30131540387761 6.85740763239976 5.5325902108287 6.30781548936649 7.84284307315349 4.47292990349355 4.64003084174476 5.48014130249836 0 3.48549610587919 3.96397362332123 3.14459815680532 5.59791469171996 2.25198909783448 5.18311849821211 4.54741248463763 3.71058624754798 2.69797588499755 7.82504504220559 7.61406607135237 7.13381545095109 8.44384430044265 6.71088081591996 6.35910146136893 5.18001442223706 5.2381960545819 4.7094220651569 6.46329094926891 5.88708881996361 2.50815747366843 3.72544116897342 5.71422767011491 3.48549610587919 0 2.09064557523382 2.35007842477788 3.84437623072582 3.37982049066074 4.82948860655148 2.61344414995761 3.08212085298007 3.39826001248126 6.34083256759322 6.78044024394629 5.9882682085243 7.368182657586 6.29229240618139 5.93365009305124 4.74001147278235 4.16875045563175 5.19193126631916 6.60549692940372 3.75170839493609 3.58036212296744 4.23057909059422 5.44458516207639 3.96397362332123 2.09064557523382 0 2.91550590841545 4.53693024483879 4.16796766816088 4.70318440048524 2.79541837375649 3.79457424274492 4.23335312544269 6.52562476479155 7.28216604836819 6.15919058556992 7.48332275942444 6.29601002300864 6.13547796850531 4.6792323698443 4.45343001677936 5.90808732531762 7.12563061433389 4.29741620103145 2.6591292750976 3.32236571813861 6.21128694887343 3.14459815680532 2.35007842477788 2.91550590841545 0 3.03537232143609 3.19717141237262 4.78031309163852 2.41753325811849 3.59607995374352 2.12854912039549 5.46704031619679 5.33701156479808 4.96043060818422 6.44826304723108 6.36381765874823 5.33050747387333 4.28625407689455 3.30334570818273 4.94667231796753 6.31277712868333 3.58610710419189 2.29553760953804 2.52327233791657 7.57897769844682 5.59791469171996 3.84437623072582 4.53693024483879 3.03537232143609 0 5.42581905199784 5.5382425777602 2.21628461900339 4.91569734557852 3.76898373844346 3.66958270784948 3.7596809535214 3.09087676998529 5.16423793264611 6.19348191138961 4.67007617153741 4.11204634372634 2.12921147954829 5.20716627366845 6.64769970583513 2.40407490833653 4.71171667874897 5.13562550988481 5.72787031540342 2.25198909783448 3.37982049066074 4.16796766816088 3.19717141237262 5.42581905199784 0 4.78731905692567 4.50479586376459 3.38670838656427 3.20693742829686 7.42683056394166 7.34570046678601 7.17015799953149 7.98002716787638 6.41561622183692 6.2124182195955 5.39657010741707 5.54110800674231 5.15776751659351 6.8516874226519 6.10574081766257 5.16305059040855 5.1437583829781 5.50347777475312 5.18311849821211 4.82948860655148 4.70318440048524 4.78031309163852 5.5382425777602 4.78731905692567 0 4.67746569480341 4.08051856974203 5.63341628143736 6.13993687315028 7.7127998868603 6.72017341542958 6.71492819699427 4.33113554849634 4.44684649984502 4.82408553908334 5.61768442520245 5.26230208160398 6.54992709860496 6.42845550946653 2.21426134242764 2.50862666200143 6.05215034685817 4.54741248463763 2.61344414995761 2.79541837375649 2.41753325811849 2.21628461900339 4.50479586376459 4.67746569480341 0 3.67536647198733 3.50853972062287 4.8908007524505 5.29902826407876 4.05541661524461 6.11473384050956 5.23487714375643 4.87089053925741 3.21806378630338 2.37451207574614 5.0909474774308 6.73970215554685 3.03452592937357 3.92961213866286 4.72257599677909 5.13756253132332 3.71058624754798 3.08212085298007 3.79457424274492 3.59607995374352 4.91569734557852 3.38670838656427 4.08051856974203 3.67536647198733 0 3.67506523963379 6.73163254348659 7.18535849292866 6.60015854488732 7.50539564845393 4.98323825896227 5.96071394777962 4.63371782472599 5.21021128432828 5.3351470840398 6.70375146848393 5.02891238126826 3.13399015473536 3.43881324942989 6.81750519634229 2.69797588499755 3.39826001248126 4.23335312544269 2.12854912039549 3.76898373844346 3.20693742829686 5.63341628143736 3.50853972062287 3.67506523963379 0 6.07359964931452 5.55282592144639 5.28753056505203 6.86459352948227 6.60873730627615 5.6314567316324 4.5625504604801 3.80862359775727 4.74234966729958 6.39367296383052 4.14114063107224 4.90270725079791 4.85150831682718 8.76568212120474 7.82504504220559 6.34083256759322 6.52562476479155 5.46704031619679 3.66958270784948 7.42683056394166 6.13993687315028 4.8908007524505 6.73163254348659 6.07359964931452 0 3.95581421039689 2.89070054815662 2.00584491640009 6.4169416509523 3.98054063154574 5.12176871169235 4.25495681827209 6.42605641292207 6.84353264931 4.64487610678987 5.49476199174931 5.50342943536056 9.04444618731187 7.61406607135237 6.78044024394629 7.28216604836819 5.33701156479808 3.7596809535214 7.34570046678601 7.7127998868603 5.29902826407876 7.18535849292866 5.55282592144639 3.95581421039689 0 4.04435991796256 5.01228422881506 8.11947221764963 5.86295047339197 5.99126094814824 4.58960572590818 6.61131730349409 7.40381675001318 4.84021195384958 4.24083600731234 3.52222099128756 8.33992506606364 7.13381545095109 5.9882682085243 6.15919058556992 4.96043060818422 3.09087676998529 7.17015799953149 6.72017341542958 4.05541661524461 6.60015854488732 5.28753056505203 2.89070054815662 4.04435991796256 0 3.64256798987379 6.01870458325898 4.26211882754801 3.82653767294834 2.5630508080946 5.89444500689165 6.82255468001791 4.23311465341886 6.11441501785041 5.87491943777315 9.11412838063313 8.44384430044265 7.368182657586 7.48332275942444 6.44826304723108 5.16423793264611 7.98002716787638 6.71492819699427 6.11473384050956 7.50539564845393 6.86459352948227 2.00584491640009 5.01228422881506 3.64256798987379 0 6.60501226761683 3.94055918447939 5.63216883653706 5.30106624617202 6.83112869949915 6.80321310613232 6.05396442753773 6.05615282291975 5.49066317297654 5.67503738892289 6.71088081591996 6.29229240618139 6.29601002300864 6.36381765874823 6.19348191138961 6.41561622183692 4.33113554849634 5.23487714375643 4.98323825896227 6.60873730627615 6.4169416509523 8.11947221764963 6.01870458325898 6.60501226761683 0 4.58594627180039 3.55328319122345 5.54504004833869 5.61499654775589 6.828621895957 7.2430575511398 4.95222984315722 4.27208092800677 6.94693258686523 6.35910146136893 5.93365009305124 6.13547796850531 5.33050747387333 4.67007617153741 6.2124182195955 4.44684649984502 4.87089053925741 5.96071394777962 5.6314567316324 3.98054063154574 5.86295047339197 4.26211882754801 3.94055918447939 4.58594627180039 0 3.90515299381786 4.28027849695426 4.38635292373633 5.39036567068314 6.01887662312089 4.21090492925648 3.15270231033824 5.30131540387761 5.18001442223706 4.74001147278235 4.6792323698443 4.28625407689455 4.11204634372634 5.39657010741707 4.82408553908334 3.21806378630338 4.63371782472599 4.5625504604801 5.12176871169235 5.99126094814824 3.82653767294834 5.63216883653706 3.55328319122345 3.90515299381786 0 2.65742337348713 3.85104238688071 5.57317463010724 5.08393769559955 2.85939902504818 1.74819033890028 6.85740763239976 5.2381960545819 4.16875045563175 4.45343001677936 3.30334570818273 2.12921147954829 5.54110800674231 5.61768442520245 2.37451207574614 5.21021128432828 3.80862359775727 4.25495681827209 4.58960572590818 2.5630508080946 5.30106624617202 5.54504004833869 4.28027849695426 2.65742337348713 0 4.28103353313767 5.86614162833534 3.27887996130286 4.97193013540636 4.12374288054719 5.5325902108287 4.7094220651569 5.19193126631916 5.90808732531762 4.94667231796753 5.20716627366845 5.15776751659351 5.26230208160398 5.0909474774308 5.3351470840398 4.74234966729958 6.42605641292207 6.61131730349409 5.89444500689165 6.83112869949915 5.61499654775589 4.38635292373633 3.85104238688071 4.28103353313767 0 3.33721452854301 5.88678552682047 6.55517500441812 6.15931692104792 6.30781548936649 6.46329094926891 6.60549692940372 7.12563061433389 6.31277712868333 6.64769970583513 6.8516874226519 6.54992709860496 6.73970215554685 6.70375146848393 6.39367296383052 6.84353264931 7.40381675001318 6.82255468001791 6.80321310613232 6.828621895957 5.39036567068314 5.57317463010724 5.86614162833534 3.33721452854301 0 6.7434003020233 2.54101803759533 3.35050234347791 7.84284307315349 5.88708881996361 3.75170839493609 4.29741620103145 3.58610710419189 2.40407490833653 6.10574081766257 6.42845550946653 3.03452592937357 5.02891238126826 4.14114063107224 4.64487610678987 4.84021195384958 4.23311465341886 6.05396442753773 7.2430575511398 6.01887662312089 5.08393769559955 3.27887996130286 5.88678552682047 6.7434003020233 0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/mantel_veg_dm_vegan.txt000066400000000000000000000233161520735541300312140ustar00rootroot000000000000000 0.531002122667858 0.668066081456845 0.562124668311531 0.3747077813648 0.509473807708101 0.623441897868918 0.533760972316003 0.841820910455228 0.345334659061175 0.544980977465613 0.387906855391038 0.631889119284077 0.360369716481462 0.495569929879871 0.338230884557721 0.527747996119875 0.46940182727116 0.572409158546537 0.658356940509915 0.468803827751196 0.624899560429172 0.445852306473965 0.556086425651643 0.531002122667858 0 0.359778297016791 0.405560971081094 0.365209673840692 0.456075749605471 0.35795169856699 0.397667376920489 0.522541392379812 0.60638464347191 0.48037557590249 0.378418761774833 0.337611485751577 0.671739130434783 0.717861205915813 0.635512156237545 0.757850272278487 0.684397366160893 0.820626944245034 0.776103945014594 0.679419902681042 0.764456383429945 0.471627356163032 0.760728080850839 0.668066081456845 0.359778297016791 0 0.493494677463379 0.502030649266258 0.509231821290175 0.50100504976222 0.590762326930444 0.573666487726319 0.757674655787863 0.653360627772091 0.434689236988378 0.336909757263505 0.793106938610254 0.856175256640914 0.744137292184681 0.83821186778176 0.830987488829312 0.837255085778569 0.759051704257184 0.689453763842811 0.78428294394681 0.567737261531031 0.727272727272727 0.562124668311531 0.405560971081094 0.493494677463379 0 0.428611098255195 0.487819025522041 0.465522369035986 0.568393032270116 0.302780246286657 0.754373626373627 0.746791469651645 0.495783259540375 0.500159329903947 0.77929167212542 0.873218985388874 0.749693459050357 0.809023592216291 0.841379965785972 0.758192367410313 0.741589782845171 0.625361639704983 0.70965400435519 0.632291885091214 0.54560014236142 0.3747077813648 0.365209673840692 0.502030649266258 0.428611098255195 0 0.360624235718861 0.481270602337428 0.409431221365516 0.697951879101213 0.622147127631921 0.564580791354366 0.287701365077311 0.425861695209191 0.639083780437474 0.729525454839929 0.625248311481923 0.712879825495866 0.711791887728906 0.724986879144997 0.669388904533934 0.538476172358033 0.662547573180473 0.471028037383178 0.495122079839688 0.509473807708101 0.456075749605471 0.509231821290175 0.487819025522041 0.360624235718861 0 0.47264827514003 0.449673125625773 0.643173412512372 0.573924437650142 0.633194205745151 0.395377631035906 0.431129869389152 0.695857026807473 0.789820495341968 0.568402976531196 0.530275619878684 0.517760385310054 0.538922155688623 0.539314268896846 0.428855622420053 0.505990964447063 0.329349338004224 0.531589448015961 0.623441897868918 0.35795169856699 0.50100504976222 0.465522369035986 0.481270602337428 0.47264827514003 0 0.267803106717773 0.598566633402885 0.694873612095441 0.535760932030719 0.46270201874964 0.382298106172113 0.745988552125364 0.861145064293746 0.724916160609081 0.802615164256341 0.801531425047536 0.832146445891039 0.772508176966776 0.70517511761631 0.787532847973119 0.581221922731357 0.677116737663332 0.533760972316003 0.397667376920489 0.590762326930444 0.568393032270116 0.409431221365516 0.449673125625773 0.267803106717773 0 0.701535990362414 0.551494144215115 0.482635012046777 0.373779728755815 0.430605761857816 0.659614382490881 0.718478913197665 0.650987864807943 0.683795276397356 0.646264782232478 0.735420178184445 0.818586585827965 0.634216589861751 0.765659822656361 0.517282479141836 0.747455911343173 0.841820910455228 0.522541392379812 0.573666487726319 0.302780246286657 0.697951879101213 0.643173412512372 0.598566633402885 0.701535990362414 0 0.860012230114305 0.823966727319989 0.696356043704593 0.608614963860129 0.896020179372198 0.953959215457244 0.9014440433213 0.923448497952799 0.938116913005677 0.905321324457207 0.868666952421774 0.854316702819956 0.901660445359763 0.754406370224568 0.724877304998332 0.345334659061175 0.60638464347191 0.757674655787863 0.754373626373627 0.622147127631921 0.573924437650142 0.694873612095441 0.551494144215115 0.860012230114305 0 0.554756456358287 0.57855421686747 0.741260525644297 0.453305402640425 0.514898810129157 0.351567272898162 0.496547756041427 0.388174807197943 0.596869061623382 0.729252973406388 0.590238621498489 0.716043877642022 0.427280771201043 0.72127723067741 0.544980977465613 0.48037557590249 0.653360627772091 0.746791469651645 0.564580791354366 0.633194205745151 0.535760932030719 0.482635012046777 0.823966727319989 0.554756456358287 0 0.511525795828759 0.554151727277901 0.655082959520078 0.725768053508672 0.622747338353674 0.783666100254885 0.673474291206151 0.859248929176213 0.828249694002448 0.750707371556218 0.830408783452603 0.674327728932078 0.809644950779781 0.387906855391038 0.378418761774833 0.434689236988378 0.495783259540375 0.287701365077311 0.395377631035906 0.46270201874964 0.373779728755815 0.696356043704593 0.57855421686747 0.511525795828759 0 0.451855598406777 0.595916174099946 0.715382678751259 0.543911776469916 0.669047897880314 0.677185443802873 0.695153896529142 0.698248620855873 0.518242618672176 0.67063492063492 0.446171234812094 0.632043116119549 0.631889119284077 0.337611485751577 0.336909757263505 0.500159329903947 0.425861695209191 0.431129869389152 0.382298106172113 0.430605761857816 0.608614963860129 0.741260525644297 0.554151727277901 0.451855598406777 0 0.755672609400324 0.860085791452629 0.734387197501951 0.816868430229662 0.840013416065739 0.817908907547258 0.788424259207976 0.70625642943982 0.784595481217946 0.617593040115998 0.746623195156032 0.360369716481462 0.671739130434783 0.793106938610254 0.77929167212542 0.639083780437474 0.695857026807473 0.745988552125364 0.659614382490881 0.896020179372198 0.453305402640425 0.655082959520078 0.595916174099946 0.755672609400324 0 0.32374463790058 0.175471345902557 0.515448702689836 0.560172148132405 0.646577681901937 0.83184352597575 0.699166591988529 0.769745293466224 0.526223291092406 0.793334979017526 0.495569929879871 0.717861205915813 0.856175256640914 0.873218985388874 0.729525454839929 0.789820495341968 0.861145064293746 0.718478913197665 0.953959215457244 0.514898810129157 0.725768053508672 0.715382678751259 0.860085791452629 0.32374463790058 0 0.398453833811446 0.563443208895949 0.537750556792873 0.725759700794764 0.901458342917606 0.780864053688773 0.850419084461638 0.556379750493714 0.888831597401258 0.338230884557721 0.635512156237545 0.744137292184681 0.749693459050357 0.625248311481923 0.568402976531196 0.724916160609081 0.650987864807943 0.9014440433213 0.351567272898162 0.622747338353674 0.543911776469916 0.734387197501951 0.175471345902557 0.398453833811446 0 0.451762651100795 0.466509988249118 0.555275398861018 0.722312633832977 0.576246207195492 0.656792557980023 0.407794761777063 0.672014090541248 0.527747996119875 0.757850272278487 0.83821186778176 0.809023592216291 0.712879825495866 0.530275619878684 0.802615164256341 0.683795276397356 0.923448497952799 0.496547756041427 0.783666100254885 0.669047897880314 0.816868430229662 0.515448702689836 0.563443208895949 0.451762651100795 0 0.359268929503916 0.20992028343667 0.388581148863785 0.264185101779485 0.341337757596926 0.300259669263359 0.750777302759425 0.46940182727116 0.684397366160893 0.830987488829312 0.841379965785972 0.711791887728906 0.517760385310054 0.801531425047536 0.646264782232478 0.938116913005677 0.388174807197943 0.673474291206151 0.677185443802873 0.840013416065739 0.560172148132405 0.537750556792873 0.466509988249118 0.359268929503916 0 0.484114532261228 0.622234006652847 0.487074231539852 0.577606177606177 0.321596600394597 0.764130434782609 0.572409158546537 0.820626944245034 0.837255085778569 0.758192367410313 0.724986879144997 0.538922155688623 0.832146445891039 0.735420178184445 0.905321324457207 0.596869061623382 0.859248929176213 0.695153896529142 0.817908907547258 0.646577681901937 0.725759700794764 0.555275398861018 0.20992028343667 0.484114532261228 0 0.233028585612046 0.184614740719039 0.145672877846791 0.420959606845713 0.677966101694915 0.658356940509915 0.776103945014594 0.759051704257184 0.741589782845171 0.669388904533934 0.539314268896846 0.772508176966776 0.818586585827965 0.868666952421774 0.729252973406388 0.828249694002448 0.698248620855873 0.788424259207976 0.83184352597575 0.901458342917606 0.722312633832977 0.388581148863785 0.622234006652847 0.233028585612046 0 0.227722772277228 0.111727966689799 0.514525993883792 0.595256346665464 0.468803827751196 0.679419902681042 0.689453763842811 0.625361639704983 0.538476172358033 0.428855622420053 0.70517511761631 0.634216589861751 0.854316702819956 0.590238621498489 0.750707371556218 0.518242618672176 0.70625642943982 0.699166591988529 0.780864053688773 0.576246207195492 0.264185101779485 0.487074231539852 0.184614740719039 0.227722772277228 0 0.179336829499938 0.368810178817056 0.560213727907933 0.624899560429172 0.764456383429945 0.78428294394681 0.70965400435519 0.662547573180473 0.505990964447063 0.787532847973119 0.765659822656361 0.901660445359763 0.716043877642022 0.830408783452603 0.67063492063492 0.784595481217946 0.769745293466224 0.850419084461638 0.656792557980023 0.341337757596926 0.577606177606177 0.145672877846791 0.111727966689799 0.179336829499938 0 0.50435780791633 0.614787397309741 0.445852306473965 0.471627356163032 0.567737261531031 0.632291885091214 0.471028037383178 0.329349338004224 0.581221922731357 0.517282479141836 0.754406370224568 0.427280771201043 0.674327728932078 0.446171234812094 0.617593040115998 0.526223291092406 0.556379750493714 0.407794761777063 0.300259669263359 0.321596600394597 0.420959606845713 0.514525993883792 0.368810178817056 0.50435780791633 0 0.671336257723692 0.556086425651643 0.760728080850839 0.727272727272727 0.54560014236142 0.495122079839688 0.531589448015961 0.677116737663332 0.747455911343173 0.724877304998332 0.72127723067741 0.809644950779781 0.632043116119549 0.746623195156032 0.793334979017526 0.888831597401258 0.672014090541248 0.750777302759425 0.764130434782609 0.677966101694915 0.595256346665464 0.560213727907933 0.614787397309741 0.671336257723692 0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/moving_pictures_dm.tsv000066400000000000000000000502311520735541300311210ustar00rootroot00000000000000 L1S105 L1S140 L1S208 L1S257 L1S281 L1S57 L1S76 L1S8 L2S155 L2S175 L2S204 L2S222 L2S240 L2S309 L2S357 L2S382 L3S294 L3S313 L3S341 L3S360 L3S378 L4S112 L4S137 L4S63 L5S104 L5S155 L5S174 L5S203 L5S222 L5S240 L6S20 L6S68 L6S93 L1S105 0.0 0.5390370298457626 0.5958380256061412 0.5768343811669847 0.5923046539353664 0.44786237128294343 0.39489596582130626 0.5545584734774127 0.8628589351714164 0.8434498336351259 0.8592370856547886 0.8506877032999233 0.7889826076831608 0.8359411856255106 0.8200856211804968 0.8426252468809847 0.8588300792888636 0.7569476110839489 0.7737531468949157 0.8944159171736104 0.6033584308249973 0.8470795512030315 0.821242904747876 0.8652874911410461 0.7549182333398126 0.7223305078861331 0.7614916771466183 0.7384823167933402 0.7685949288454377 0.7217074962665071 0.7245343115615573 0.7830441925323288 0.7712136041691006 L1S140 0.5390370298457626 0.0 0.5799280564700269 0.5498337267462643 0.5487499420209432 0.5617578336407074 0.5274803712970444 0.5842935186320399 0.8425845430236847 0.7832827608957819 0.832335123190656 0.83707961792672 0.7311087382394217 0.7969572429804197 0.74931933992796 0.791784337383268 0.7891927506641839 0.6721331780898249 0.7493321619468443 0.8773425730913526 0.3943371737754427 0.8380071824429106 0.7797415033649835 0.8604626784828243 0.7389385379102201 0.713927118153038 0.7409814677579339 0.6893827188871452 0.739005471405395 0.7134211109446568 0.7210216228178491 0.7548606893628177 0.75650714031249 L1S208 0.5958380256061412 0.5799280564700269 0.0 0.3514478448812178 0.3099429863936709 0.4908395118886828 0.5060147104062029 0.5921114631534051 0.8899108348691316 0.871025922389371 0.882455510304791 0.8798738374168472 0.8153291321982421 0.8616764262370401 0.8215036618481708 0.8762874977082885 0.8826136551026731 0.8218942402038897 0.8270103157643566 0.8918833194204532 0.5595063305032598 0.8896853519676307 0.8701383470494592 0.9064920956741176 0.8245445313262268 0.7952347925702751 0.8252913142216206 0.7959214036381839 0.8153225533087411 0.7836084181624914 0.791415482862234 0.8107398191951546 0.8044123679011221 L1S257 0.5768343811669847 0.5498337267462643 0.3514478448812178 0.0 0.25929060246530955 0.47255177559300116 0.43222880359346527 0.5884066995223238 0.8795468292082718 0.8633179655119932 0.8688146996880899 0.8629186587174017 0.8190468684000036 0.8492352934610714 0.8120267566814204 0.8666693265827448 0.8777562843225813 0.802227485419459 0.8160964503323095 0.8817724113978568 0.5576854601824073 0.8747926182003918 0.858838497674028 0.8925129391873841 0.828703636427477 0.8010491792499632 0.8063815782189153 0.8092051698995067 0.806495056831578 0.8032210970007331 0.7958200880953574 0.8161661389998109 0.8303929119421523 L1S281 0.5923046539353664 0.5487499420209432 0.3099429863936709 0.25929060246530955 0.0 0.4609450181065116 0.4768241494226335 0.6336173247999576 0.8985838283907426 0.8902364311520621 0.8972881153423283 0.8878063096662511 0.842173339458122 0.8796280371215733 0.8476576569873849 0.8898292712501708 0.9039077039484619 0.8485533231569067 0.852633569868443 0.9096947429872373 0.5498250250306412 0.9022662022069642 0.8832755726058907 0.9169203743757105 0.8572110146660553 0.833803405339537 0.8394041604332061 0.8290963638641423 0.8384368165385457 0.8247152739488143 0.832089497492543 0.8365271234666928 0.8483699050146564 L1S57 0.44786237128294343 0.5617578336407074 0.4908395118886828 0.47255177559300116 0.4609450181065116 0.0 0.31082469034707255 0.5024096303529431 0.9113813328862811 0.9014185555334876 0.9014865706960162 0.8945638042848107 0.8714620677099987 0.8806337056845028 0.8481649374200068 0.9084204945482022 0.913489362275528 0.852617211132442 0.8535720478866394 0.9122868711391121 0.5758415360633006 0.9020100495580599 0.9027332494336695 0.9186219021297435 0.853072903040757 0.8327332298901452 0.8629325424179554 0.838123751985925 0.8659733546560768 0.8346642658091125 0.8289313199906942 0.8703637908123152 0.8629123642673379 L1S76 0.39489596582130626 0.5274803712970444 0.5060147104062029 0.43222880359346527 0.4768241494226335 0.31082469034707255 0.0 0.4003824579445799 0.894830907945713 0.8782305450289447 0.8768848673183877 0.8694496317335333 0.834400640278251 0.8645838229241534 0.8020621529524625 0.8821339436331491 0.8821873080715426 0.8108074314407202 0.8071422086314133 0.8931657453933083 0.5741407822604754 0.8800714967479438 0.8737823256177506 0.8981103792379882 0.8193019560519106 0.7921706586389919 0.8200532532128909 0.8020963162128805 0.8249980087726344 0.7949183972892307 0.7923436575946494 0.8310029142646927 0.8322683023877507 L1S8 0.5545584734774127 0.5842935186320399 0.5921114631534051 0.5884066995223238 0.6336173247999576 0.5024096303529431 0.4003824579445799 0.0 0.8984532053428095 0.8752689122693623 0.892740827989152 0.8922691853549297 0.8314474877203453 0.8600974905243383 0.8016996748131581 0.8870353495912263 0.8805255216909961 0.7980602019240324 0.829887986255906 0.8798293357284456 0.5576624158659516 0.8948846831679798 0.8816102418936791 0.9112039786090779 0.8148374423400107 0.7791385980867408 0.8123406708143702 0.8036845403456274 0.8182429195392156 0.786233773105675 0.785902469716853 0.8323093879065956 0.8268942255033314 L2S155 0.8628589351714164 0.8425845430236847 0.8899108348691316 0.8795468292082718 0.8985838283907426 0.9113813328862811 0.894830907945713 0.8984532053428095 0.0 0.46760603559570263 0.4249569948218847 0.43461957349574365 0.7136184283615585 0.3913207521607729 0.6347075539715223 0.7018474049205657 0.48529937944992957 0.6445967049513042 0.6384694268897185 0.4614095269789821 0.8793414820335794 0.49283220104466596 0.6490593420832039 0.47563246735903575 0.7320469060900457 0.8046481081885503 0.7992253539435805 0.7608659584888517 0.761349180972591 0.8017496796623877 0.7844856344015433 0.7648448360194874 0.7728251640763542 L2S175 0.8434498336351259 0.7832827608957819 0.871025922389371 0.8633179655119932 0.8902364311520621 0.9014185555334876 0.8782305450289447 0.8752689122693623 0.46760603559570263 0.0 0.4521351118370733 0.47450759266616915 0.6496968752812166 0.4163459132801876 0.5642253392315422 0.6035203651725982 0.4127343227632307 0.5009839698168453 0.5720541940600513 0.5238301647807445 0.8519601477875526 0.45057960516670714 0.6012619962408408 0.5452699437274425 0.7004211741288418 0.7254489332170817 0.7241658196524235 0.6728749977683892 0.7120770444662118 0.7067601324302817 0.7154192599371452 0.6790044090495644 0.6670904831025087 L2S204 0.8592370856547886 0.832335123190656 0.882455510304791 0.8688146996880899 0.8972881153423283 0.9014865706960162 0.8768848673183877 0.892740827989152 0.4249569948218847 0.4521351118370733 0.0 0.34707557932356076 0.7317461021420034 0.32542423370295653 0.5940997497062588 0.7202722055635978 0.46284470929748595 0.6399875240134363 0.5427529698531464 0.41546588368326215 0.8806954039760829 0.3819763193450203 0.6864606389600179 0.4541251117472289 0.7433650255074369 0.8140552153241122 0.8171702240197111 0.7787482342908187 0.7789238492726243 0.8145023991202386 0.797521853405542 0.7823436739920101 0.7825923091798144 L2S222 0.8506877032999233 0.83707961792672 0.8798738374168472 0.8629186587174017 0.8878063096662511 0.8945638042848107 0.8694496317335333 0.8922691853549297 0.43461957349574365 0.47450759266616915 0.34707557932356076 0.0 0.7373605415524003 0.38933892308526385 0.6131841736075622 0.7071347655059155 0.5297960404918108 0.6776613871707217 0.614146849517274 0.41910689292075193 0.8807526952301693 0.43694693261646017 0.6992608535946145 0.4512186030792239 0.7657709194380475 0.8264506476297601 0.8235579667989716 0.7929926795664424 0.7900065630791773 0.8272758828816869 0.8177374352486667 0.7787324503994212 0.7937870099703493 L2S240 0.7889826076831608 0.7311087382394217 0.8153291321982421 0.8190468684000036 0.842173339458122 0.8714620677099987 0.834400640278251 0.8314474877203453 0.7136184283615585 0.6496968752812166 0.7317461021420034 0.7373605415524003 0.0 0.7032990730427625 0.5742088858732407 0.5358811200052477 0.6113293724148627 0.5506881270264428 0.5515051266923414 0.7398454298135383 0.7579742017535656 0.7115018729258218 0.48083389190461734 0.7661067183222632 0.36560695464990867 0.4412731503394013 0.41030162605879844 0.38926922412434417 0.3758838249617733 0.43476390441875573 0.4013288162093646 0.29292532554452677 0.35832282922330977 L2S309 0.8359411856255106 0.7969572429804197 0.8616764262370401 0.8492352934610714 0.8796280371215733 0.8806337056845028 0.8645838229241534 0.8600974905243383 0.3913207521607729 0.4163459132801876 0.32542423370295653 0.38933892308526385 0.7032990730427625 0.0 0.5284516343093534 0.7093129471508985 0.41393505549147774 0.6241411216254367 0.5766719921218544 0.36061963338100667 0.8395112062787546 0.4200940359303599 0.6691543813483889 0.43557544512779306 0.7065436739270591 0.7784024482700062 0.7846395088210678 0.7393917740028452 0.7397915081982174 0.7798934785055419 0.7729246906860544 0.763695527435426 0.7629847033876873 L2S357 0.8200856211804968 0.74931933992796 0.8215036618481708 0.8120267566814204 0.8476576569873849 0.8481649374200068 0.8020621529524625 0.8016996748131581 0.6347075539715223 0.5642253392315422 0.5940997497062588 0.6131841736075622 0.5742088858732407 0.5284516343093534 0.0 0.6247944934502809 0.5283785180280727 0.44838682641972477 0.375128958725295 0.6121711834124891 0.8188660070261687 0.5950936496526126 0.542689027968325 0.6689211737896941 0.5421787179552776 0.6601284562072681 0.6793754491062178 0.5918194682678256 0.6055221091296257 0.6631138650570884 0.6559008959245738 0.6414849884779625 0.6348752854444591 L2S382 0.8426252468809847 0.791784337383268 0.8762874977082885 0.8666693265827448 0.8898292712501708 0.9084204945482022 0.8821339436331491 0.8870353495912263 0.7018474049205657 0.6035203651725982 0.7202722055635978 0.7071347655059155 0.5358811200052477 0.7093129471508985 0.6247944934502809 0.0 0.680488155634992 0.5879411676849041 0.6300513986721148 0.7798117418893309 0.8451713307652351 0.7053126728281367 0.29452174278276233 0.7387926847081081 0.6760422527308095 0.6989286770361658 0.6126816214335168 0.6413026519516322 0.6319640587005974 0.6916898221776602 0.6638186733377722 0.5262410574638753 0.5609030584455355 L3S294 0.8588300792888636 0.7891927506641839 0.8826136551026731 0.8777562843225813 0.9039077039484619 0.913489362275528 0.8821873080715426 0.8805255216909961 0.48529937944992957 0.4127343227632307 0.46284470929748595 0.5297960404918108 0.6113293724148627 0.41393505549147774 0.5283785180280727 0.680488155634992 0.0 0.5793151362285137 0.532519942057993 0.4417588676636619 0.8329083701065813 0.5166391190254049 0.6344485180123575 0.5880518426822319 0.6166977936514635 0.6976139122442497 0.6965206807593246 0.6533170380479183 0.6465722615751633 0.7007111257543401 0.697083374921763 0.7001623873009802 0.7062166839383266 L3S313 0.7569476110839489 0.6721331780898249 0.8218942402038897 0.802227485419459 0.8485533231569067 0.852617211132442 0.8108074314407202 0.7980602019240324 0.6445967049513042 0.5009839698168453 0.6399875240134363 0.6776613871707217 0.5506881270264428 0.6241411216254367 0.44838682641972477 0.5879411676849041 0.5793151362285137 0.0 0.45248307788083786 0.7165487737423945 0.76582414397238 0.6574105445715698 0.560831971453598 0.7171733441832148 0.5902731094836756 0.5532059333861852 0.5853434250505234 0.5025483834097694 0.561609978051379 0.5582681387584417 0.5694158492427435 0.6032070350377756 0.5911945286328084 L3S341 0.7737531468949157 0.7493321619468443 0.8270103157643566 0.8160964503323095 0.852633569868443 0.8535720478866394 0.8071422086314133 0.829887986255906 0.6384694268897185 0.5720541940600513 0.5427529698531464 0.614146849517274 0.5515051266923414 0.5766719921218544 0.375128958725295 0.6300513986721148 0.532519942057993 0.45248307788083786 0.0 0.6196019964860159 0.783720015310488 0.5829777947168483 0.5534737998316789 0.6520900532121093 0.5493281969319693 0.6308837007391367 0.652197593637747 0.6025364874432444 0.6084801413450426 0.6341899420458715 0.6354966927534835 0.6495259871270996 0.6352447858014029 L3S360 0.8944159171736104 0.8773425730913526 0.8918833194204532 0.8817724113978568 0.9096947429872373 0.9122868711391121 0.8931657453933083 0.8798293357284456 0.4614095269789821 0.5238301647807445 0.41546588368326215 0.41910689292075193 0.7398454298135383 0.36061963338100667 0.6121711834124891 0.7798117418893309 0.4417588676636619 0.7165487737423945 0.6196019964860159 0.0 0.886859306656774 0.5343546555847905 0.7414678143333879 0.5400460290177217 0.7495782488980336 0.8108767861286648 0.8149762338575348 0.7802652073770237 0.7846158292767554 0.81147352370555 0.8005244117641637 0.8006143679532055 0.8014989491687546 L3S378 0.6033584308249973 0.3943371737754427 0.5595063305032598 0.5576854601824073 0.5498250250306412 0.5758415360633006 0.5741407822604754 0.5576624158659516 0.8793414820335794 0.8519601477875526 0.8806954039760829 0.8807526952301693 0.7579742017535656 0.8395112062787546 0.8188660070261687 0.8451713307652351 0.8329083701065813 0.76582414397238 0.783720015310488 0.886859306656774 0.0 0.8878531310256906 0.8359164049140062 0.8993931924960518 0.7252856380797102 0.6746582064114732 0.7140756986649465 0.7000095154033142 0.7254146177064372 0.6747284675539041 0.694536665024702 0.750964397649065 0.7478762997708954 L4S112 0.8470795512030315 0.8380071824429106 0.8896853519676307 0.8747926182003918 0.9022662022069642 0.9020100495580599 0.8800714967479438 0.8948846831679798 0.49283220104466596 0.45057960516670714 0.3819763193450203 0.43694693261646017 0.7115018729258218 0.4200940359303599 0.5950936496526126 0.7053126728281367 0.5166391190254049 0.6574105445715698 0.5829777947168483 0.5343546555847905 0.8878531310256906 0.0 0.6481421375149321 0.3575409039402891 0.7357714051501275 0.809583225542944 0.8029186032245896 0.7654724305797693 0.7692411532770428 0.8100058186769521 0.7895581361870725 0.7651442703099545 0.7646440275794989 L4S137 0.821242904747876 0.7797415033649835 0.8701383470494592 0.858838497674028 0.8832755726058907 0.9027332494336695 0.8737823256177506 0.8816102418936791 0.6490593420832039 0.6012619962408408 0.6864606389600179 0.6992608535946145 0.48083389190461734 0.6691543813483889 0.542689027968325 0.29452174278276233 0.6344485180123575 0.560831971453598 0.5534737998316789 0.7414678143333879 0.8359164049140062 0.6481421375149321 0.0 0.6908078779515394 0.6039667084060777 0.680281107717286 0.5936509777076375 0.6119432909211573 0.6028821638318781 0.6703353838958876 0.6453016109359295 0.5078212308619812 0.5169165993321925 L4S63 0.8652874911410461 0.8604626784828243 0.9064920956741176 0.8925129391873841 0.9169203743757105 0.9186219021297435 0.8981103792379882 0.9112039786090779 0.47563246735903575 0.5452699437274425 0.4541251117472289 0.4512186030792239 0.7661067183222632 0.43557544512779306 0.6689211737896941 0.7387926847081081 0.5880518426822319 0.7171733441832148 0.6520900532121093 0.5400460290177217 0.8993931924960518 0.3575409039402891 0.6908078779515394 0.0 0.7771055341254081 0.8401318632573123 0.8278791663557197 0.8033319145222341 0.8021181534933208 0.8397629806795364 0.8174036603850671 0.8034029168891261 0.8047837943956528 L5S104 0.7549182333398126 0.7389385379102201 0.8245445313262268 0.828703636427477 0.8572110146660553 0.853072903040757 0.8193019560519106 0.8148374423400107 0.7320469060900457 0.7004211741288418 0.7433650255074369 0.7657709194380475 0.36560695464990867 0.7065436739270591 0.5421787179552776 0.6760422527308095 0.6166977936514635 0.5902731094836756 0.5493281969319693 0.7495782488980336 0.7252856380797102 0.7357714051501275 0.6039667084060777 0.7771055341254081 0.0 0.299746565246475 0.3717459070188454 0.30611431267503736 0.2687293485232606 0.29488133279702533 0.35282575882032935 0.4059272692757093 0.3546188970208585 L5S155 0.7223305078861331 0.713927118153038 0.7952347925702751 0.8010491792499632 0.833803405339537 0.8327332298901452 0.7921706586389919 0.7791385980867408 0.8046481081885503 0.7254489332170817 0.8140552153241122 0.8264506476297601 0.4412731503394013 0.7784024482700062 0.6601284562072681 0.6989286770361658 0.6976139122442497 0.5532059333861852 0.6308837007391367 0.8108767861286648 0.6746582064114732 0.809583225542944 0.680281107717286 0.8401318632573123 0.299746565246475 0.0 0.24482970831325948 0.21540954545570457 0.28453959248410193 0.08866970541518727 0.2086655812403446 0.42817224711244256 0.35580061290923976 L5S174 0.7614916771466183 0.7409814677579339 0.8252913142216206 0.8063815782189153 0.8394041604332061 0.8629325424179554 0.8200532532128909 0.8123406708143702 0.7992253539435805 0.7241658196524235 0.8171702240197111 0.8235579667989716 0.41030162605879844 0.7846395088210678 0.6793754491062178 0.6126816214335168 0.6965206807593246 0.5853434250505234 0.652197593637747 0.8149762338575348 0.7140756986649465 0.8029186032245896 0.5936509777076375 0.8278791663557197 0.3717459070188454 0.24482970831325948 0.0 0.2877214934590952 0.25347139824912546 0.2605730633285677 0.2559815010487754 0.27892381163313434 0.3053187587048309 L5S203 0.7384823167933402 0.6893827188871452 0.7959214036381839 0.8092051698995067 0.8290963638641423 0.838123751985925 0.8020963162128805 0.8036845403456274 0.7608659584888517 0.6728749977683892 0.7787482342908187 0.7929926795664424 0.38926922412434417 0.7393917740028452 0.5918194682678256 0.6413026519516322 0.6533170380479183 0.5025483834097694 0.6025364874432444 0.7802652073770237 0.7000095154033142 0.7654724305797693 0.6119432909211573 0.8033319145222341 0.30611431267503736 0.21540954545570457 0.2877214934590952 0.0 0.24311981207597314 0.2201431600708006 0.2346438472041132 0.333150002145841 0.2850632669863039 L5S222 0.7685949288454377 0.739005471405395 0.8153225533087411 0.806495056831578 0.8384368165385457 0.8659733546560768 0.8249980087726344 0.8182429195392156 0.761349180972591 0.7120770444662118 0.7789238492726243 0.7900065630791773 0.3758838249617733 0.7397915081982174 0.6055221091296257 0.6319640587005974 0.6465722615751633 0.561609978051379 0.6084801413450426 0.7846158292767554 0.7254146177064372 0.7692411532770428 0.6028821638318781 0.8021181534933208 0.2687293485232606 0.28453959248410193 0.25347139824912546 0.24311981207597314 0.0 0.31116489519567736 0.30117438587754664 0.29331724421227606 0.2904033216874486 L5S240 0.7217074962665071 0.7134211109446568 0.7836084181624914 0.8032210970007331 0.8247152739488143 0.8346642658091125 0.7949183972892307 0.786233773105675 0.8017496796623877 0.7067601324302817 0.8145023991202386 0.8272758828816869 0.43476390441875573 0.7798934785055419 0.6631138650570884 0.6916898221776602 0.7007111257543401 0.5582681387584417 0.6341899420458715 0.81147352370555 0.6747284675539041 0.8100058186769521 0.6703353838958876 0.8397629806795364 0.29488133279702533 0.08866970541518727 0.2605730633285677 0.2201431600708006 0.31116489519567736 0.0 0.21735399370958108 0.3819989872862365 0.3241682922704345 L6S20 0.7245343115615573 0.7210216228178491 0.791415482862234 0.7958200880953574 0.832089497492543 0.8289313199906942 0.7923436575946494 0.785902469716853 0.7844856344015433 0.7154192599371452 0.797521853405542 0.8177374352486667 0.4013288162093646 0.7729246906860544 0.6559008959245738 0.6638186733377722 0.697083374921763 0.5694158492427435 0.6354966927534835 0.8005244117641637 0.694536665024702 0.7895581361870725 0.6453016109359295 0.8174036603850671 0.35282575882032935 0.2086655812403446 0.2559815010487754 0.2346438472041132 0.30117438587754664 0.21735399370958108 0.0 0.36633132081192926 0.3477206555495855 L6S68 0.7830441925323288 0.7548606893628177 0.8107398191951546 0.8161661389998109 0.8365271234666928 0.8703637908123152 0.8310029142646927 0.8323093879065956 0.7648448360194874 0.6790044090495644 0.7823436739920101 0.7787324503994212 0.29292532554452677 0.763695527435426 0.6414849884779625 0.5262410574638753 0.7001623873009802 0.6032070350377756 0.6495259871270996 0.8006143679532055 0.750964397649065 0.7651442703099545 0.5078212308619812 0.8034029168891261 0.4059272692757093 0.42817224711244256 0.27892381163313434 0.333150002145841 0.29331724421227606 0.3819989872862365 0.36633132081192926 0.0 0.19042209104190255 L6S93 0.7712136041691006 0.75650714031249 0.8044123679011221 0.8303929119421523 0.8483699050146564 0.8629123642673379 0.8322683023877507 0.8268942255033314 0.7728251640763542 0.6670904831025087 0.7825923091798144 0.7937870099703493 0.35832282922330977 0.7629847033876873 0.6348752854444591 0.5609030584455355 0.7062166839383266 0.5911945286328084 0.6352447858014029 0.8014989491687546 0.7478762997708954 0.7646440275794989 0.5169165993321925 0.8047837943956528 0.3546188970208585 0.35580061290923976 0.3053187587048309 0.2850632669863039 0.2904033216874486 0.3241682922704345 0.3477206555495855 0.19042209104190255 0.0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/moving_pictures_mf.tsv000066400000000000000000000071261520735541300311300ustar00rootroot00000000000000#SampleID BarcodeSequence LinkerPrimerSequence BodySite Year Month Day Subject ReportedAntibioticUsage DaysSinceExperimentStart Description L1S8 AGCTGACTAGTC GTGCCAGCMGCCGCGGTAA gut 2008 10 28 subject-1 Yes 0 subject-1.gut.2008-10-28 L1S57 ACACACTATGGC GTGCCAGCMGCCGCGGTAA gut 2009 1 20 subject-1 No 84 subject-1.gut.2009-1-20 L1S76 ACTACGTGTGGT GTGCCAGCMGCCGCGGTAA gut 2009 2 17 subject-1 No 112 subject-1.gut.2009-2-17 L1S105 AGTGCGATGCGT GTGCCAGCMGCCGCGGTAA gut 2009 3 17 subject-1 No 140 subject-1.gut.2009-3-17 L2S155 ACGATGCGACCA GTGCCAGCMGCCGCGGTAA left palm 2009 1 20 subject-1 No 84 subject-1.left-palm.2009-1-20 L2S175 AGCTATCCACGA GTGCCAGCMGCCGCGGTAA left palm 2009 2 17 subject-1 No 112 subject-1.left-palm.2009-2-17 L2S204 ATGCAGCTCAGT GTGCCAGCMGCCGCGGTAA left palm 2009 3 17 subject-1 No 140 subject-1.left-palm.2009-3-17 L2S222 CACGTGACATGT GTGCCAGCMGCCGCGGTAA left palm 2009 4 14 subject-1 No 168 subject-1.left-palm.2009-4-14 L3S242 ACAGTTGCGCGA GTGCCAGCMGCCGCGGTAA right palm 2008 10 28 subject-1 Yes 0 subject-1.right-palm.2008-10-28 L3S294 CACGACAGGCTA GTGCCAGCMGCCGCGGTAA right palm 2009 1 20 subject-1 No 84 subject-1.right-palm.2009-1-20 L3S313 AGTGTCACGGTG GTGCCAGCMGCCGCGGTAA right palm 2009 2 17 subject-1 No 112 subject-1.right-palm.2009-2-17 L3S341 CAAGTGAGAGAG GTGCCAGCMGCCGCGGTAA right palm 2009 3 17 subject-1 No 140 subject-1.right-palm.2009-3-17 L3S360 CATCGTATCAAC GTGCCAGCMGCCGCGGTAA right palm 2009 4 14 subject-1 No 168 subject-1.right-palm.2009-4-14 L5S104 CAGTGTCAGGAC GTGCCAGCMGCCGCGGTAA tongue 2008 10 28 subject-1 Yes 0 subject-1.tongue.2008-10-28 L5S155 ATCTTAGACTGC GTGCCAGCMGCCGCGGTAA tongue 2009 1 20 subject-1 No 84 subject-1.tongue.2009-1-20 L5S174 CAGACATTGCGT GTGCCAGCMGCCGCGGTAA tongue 2009 2 17 subject-1 No 112 subject-1.tongue.2009-2-17 L5S203 CGATGCACCAGA GTGCCAGCMGCCGCGGTAA tongue 2009 3 17 subject-1 No 140 subject-1.tongue.2009-3-17 L5S222 CTAGAGACTCTT GTGCCAGCMGCCGCGGTAA tongue 2009 4 14 subject-1 No 168 subject-1.tongue.2009-4-14 L1S140 ATGGCAGCTCTA GTGCCAGCMGCCGCGGTAA gut 2008 10 28 subject-2 Yes 0 subject-2.gut.2008-10-28 L1S208 CTGAGATACGCG GTGCCAGCMGCCGCGGTAA gut 2009 1 20 subject-2 No 84 subject-2.gut.2009-1-20 L1S257 CCGACTGAGATG GTGCCAGCMGCCGCGGTAA gut 2009 3 17 subject-2 No 140 subject-2.gut.2009-3-17 L1S281 CCTCTCGTGATC GTGCCAGCMGCCGCGGTAA gut 2009 4 14 subject-2 No 168 subject-2.gut.2009-4-14 L2S240 CATATCGCAGTT GTGCCAGCMGCCGCGGTAA left palm 2008 10 28 subject-2 Yes 0 subject-2.left-palm.2008-10-28 L2S309 CGTGCATTATCA GTGCCAGCMGCCGCGGTAA left palm 2009 1 20 subject-2 No 84 subject-2.left-palm.2009-1-20 L2S357 CTAACGCAGTCA GTGCCAGCMGCCGCGGTAA left palm 2009 3 17 subject-2 No 140 subject-2.left-palm.2009-3-17 L2S382 CTCAATGACTCA GTGCCAGCMGCCGCGGTAA left palm 2009 4 14 subject-2 No 168 subject-2.left-palm.2009-4-14 L3S378 ATCGATCTGTGG GTGCCAGCMGCCGCGGTAA right palm 2008 10 28 subject-2 Yes 0 subject-2.right-palm.2008-10-28 L4S63 CTCGTGGAGTAG GTGCCAGCMGCCGCGGTAA right palm 2009 1 20 subject-2 No 84 subject-2.right-palm.2009-1-20 L4S112 GCGTTACACACA GTGCCAGCMGCCGCGGTAA right palm 2009 3 17 subject-2 No 140 subject-2.right-palm.2009-3-17 L4S137 GAACTGTATCTC GTGCCAGCMGCCGCGGTAA right palm 2009 4 14 subject-2 No 168 subject-2.right-palm.2009-4-14 L5S240 CTGGACTCATAG GTGCCAGCMGCCGCGGTAA tongue 2008 10 28 subject-2 Yes 0 subject-2.tongue.2008-10-28 L6S20 GAGGCTCATCAT GTGCCAGCMGCCGCGGTAA tongue 2009 1 20 subject-2 No 84 subject-2.tongue.2009-1-20 L6S68 GATACGTCCTGA GTGCCAGCMGCCGCGGTAA tongue 2009 3 17 subject-2 No 140 subject-2.tongue.2009-3-17 L6S93 GATTAGCACTCT GTGCCAGCMGCCGCGGTAA tongue 2009 4 14 subject-2 No 168 subject-2.tongue.2009-4-14scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/pwmantel_exp_results_all_dms.txt000066400000000000000000000005721520735541300332110ustar00rootroot00000000000000dm1 dm2 statistic p-value n method permutations alternative 0 1 0.7020310705446676 0.001 6 pearson 999 two-sided 0 2 0.8633966325233801 0.002 6 pearson 999 two-sided 0 3 0.6476901774685102 0.006 6 pearson 999 two-sided 1 2 0.7784836464659731 0.003 6 pearson 999 two-sided 1 3 0.9206880242368882 0.004 6 pearson 999 two-sided 2 3 0.7172972179393844 0.003 6 pearson 999 two-sided scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/pwmantel_exp_results_dm_dm2.txt000066400000000000000000000001471520735541300327360ustar00rootroot00000000000000dm1 dm2 statistic p-value n method permutations alternative 0 1 0.702031 0.001 6 pearson 999 two-sided scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/pwmantel_exp_results_duplicate_dms.txt000066400000000000000000000002371520735541300344110ustar00rootroot00000000000000dm1 dm2 statistic p-value n method permutations alternative 0 1 1.0 1.000 3 pearson 999 less 0 2 1.0 1.000 3 pearson 999 less 1 2 1.0 1.000 3 pearson 999 less scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/pwmantel_exp_results_minimal.txt000066400000000000000000000003231520735541300332160ustar00rootroot00000000000000dm1 dm2 statistic p-value n method permutations alternative 0 1 0.7559289460184544 0.34 3 pearson 999 greater 0 2 -0.989743318610787 1.0 3 pearson 999 greater 1 2 -0.8416975766245423 0.842 3 pearson 999 greater pwmantel_exp_results_minimal_with_labels.txt000066400000000000000000000003451520735541300355200ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/datadm1 dm2 statistic p-value n method permutations alternative minx miny 0.7559289460184544 0.34 3 pearson 999 greater minx minz -0.989743318610787 1.0 3 pearson 999 greater miny minz -0.8416975766245423 0.842 3 pearson 999 greater scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/data/pwmantel_exp_results_na_p_value.txt000066400000000000000000000001371520735541300337040ustar00rootroot00000000000000dm1 dm2 statistic p-value n method permutations alternative 0 1 0.5 NaN 3 spearman 0 two-sided pwmantel_exp_results_reordered_distance_matrices.txt000066400000000000000000000003241520735541300372260ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/datadm1 dm2 statistic p-value n method permutations alternative 0 1 0.7559289460184544 0.34 3 pearson 999 greater 0 2 -0.9897433186107871 1.0 3 pearson 999 greater 1 2 -0.8416975766245423 0.835 3 pearson 999 greater scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/test_anosim.py000066400000000000000000000130111520735541300264470ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from functools import partial from unittest import TestCase, main import numpy as np import pandas as pd from pandas.testing import assert_series_equal from skbio import DistanceMatrix from skbio.stats.distance import anosim class TestANOSIM(TestCase): """All results were verified with R (vegan::anosim).""" def setUp(self): # Distance matrices with and without ties in the ranks, with 2 groups # of equal size. dm_ids = ['s1', 's2', 's3', 's4'] self.grouping_equal = ['Control', 'Control', 'Fast', 'Fast'] self.df = pd.read_csv( io.StringIO('ID,Group\ns2,Control\ns3,Fast\ns4,Fast\ns5,Control\n' 's1,Control'), index_col=0) self.dm_ties = DistanceMatrix([[0, 1, 1, 4], [1, 0, 3, 2], [1, 3, 0, 3], [4, 2, 3, 0]], dm_ids) self.dm_no_ties = DistanceMatrix([[0, 1, 5, 4], [1, 0, 3, 2], [5, 3, 0, 3], [4, 2, 3, 0]], dm_ids) self.dm_condensed = DistanceMatrix([[0, 1, 5, 4], [1, 0, 3, 2], [5, 3, 0, 3], [4, 2, 3, 0]], dm_ids, condensed=True) # Test with 3 groups of unequal size. This data also generates a # negative R statistic. self.grouping_unequal = ['Control', 'Treatment1', 'Treatment2', 'Treatment1', 'Control', 'Control'] # Equivalent grouping but with different labels -- groups should be # assigned different integer labels but results should be the same. self.grouping_unequal_relabeled = ['z', 42, 'abc', 42, 'z', 'z'] self.dm_unequal = DistanceMatrix( [[0.0, 1.0, 0.1, 0.5678, 1.0, 1.0], [1.0, 0.0, 0.002, 0.42, 0.998, 0.0], [0.1, 0.002, 0.0, 1.0, 0.123, 1.0], [0.5678, 0.42, 1.0, 0.0, 0.123, 0.43], [1.0, 0.998, 0.123, 0.123, 0.0, 0.5], [1.0, 0.0, 1.0, 0.43, 0.5, 0.0]], ['s1', 's2', 's3', 's4', 's5', 's6']) # Expected series index is the same across all tests. self.exp_index = ['method name', 'test statistic name', 'sample size', 'number of groups', 'test statistic', 'p-value', 'number of permutations'] # Stricter series equality testing than the default. self.assert_series_equal = partial(assert_series_equal, check_index_type=True, check_series_type=True) def test_ties(self): # Ensure we get the same results if we rerun the method using the same # inputs. Also ensure we get the same results if we run the method # using a grouping vector or a data frame with equivalent groupings. exp = pd.Series(index=self.exp_index, data=['ANOSIM', 'R', 4, 2, 0.25, 0.68, 999], name='ANOSIM results') for _ in range(2): obs = anosim(self.dm_ties, self.grouping_equal, seed=42) self.assert_series_equal(obs, exp) for _ in range(2): obs = anosim(self.dm_ties, self.df, column='Group', seed=42) self.assert_series_equal(obs, exp) def test_no_ties(self): exp = pd.Series(index=self.exp_index, data=['ANOSIM', 'R', 4, 2, 0.625, 0.345, 999], name='ANOSIM results') obs = anosim(self.dm_no_ties, self.grouping_equal, seed=42) self.assert_series_equal(obs, exp) def test_no_ties_condensed(self): exp = pd.Series(index=self.exp_index, data=['ANOSIM', 'R', 4, 2, 0.625, 0.345, 999], name='ANOSIM results') obs = anosim(self.dm_condensed, self.grouping_equal, seed=42) self.assert_series_equal(obs, exp) def test_no_permutations(self): exp = pd.Series(index=self.exp_index, data=['ANOSIM', 'R', 4, 2, 0.625, np.nan, 0], name='ANOSIM results') obs = anosim(self.dm_no_ties, self.grouping_equal, permutations=0) self.assert_series_equal(obs, exp) def test_no_permutations_condensed(self): exp = pd.Series(index=self.exp_index, data=['ANOSIM', 'R', 4, 2, 0.625, np.nan, 0], name='ANOSIM results') obs = anosim(self.dm_condensed, self.grouping_equal, permutations=0) self.assert_series_equal(obs, exp) def test_unequal_group_sizes(self): exp = pd.Series(index=self.exp_index, data=['ANOSIM', 'R', 6, 3, -0.363636, 0.87, 999], name='ANOSIM results') obs = anosim(self.dm_unequal, self.grouping_unequal, seed=42) self.assert_series_equal(obs, exp) obs = anosim(self.dm_unequal, self.grouping_unequal_relabeled, seed=42) self.assert_series_equal(obs, exp) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/test_base.py000066400000000000000000002346221520735541300261100ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from unittest import TestCase, main, skipUnless import numpy as np import numpy.testing as npt import pandas as pd import pandas.testing as pdt import scipy.spatial.distance try: import matplotlib as mpl except ImportError: has_matplotlib = False else: has_matplotlib = True import skbio.sequence.distance from skbio import DistanceMatrix, Sequence from skbio.stats.distance import ( PairwiseMatrixError, DistanceMatrixError, SymmetricMatrixError, MissingIDError, PairwiseMatrix, SymmetricMatrix, randdm, ) from skbio.stats.distance._base import _preprocess_input, _run_monte_carlo_stats from skbio.stats.distance._utils import is_symmetric_and_hollow from skbio.util import assert_data_frame_almost_equal from skbio.util._testing import assert_series_almost_equal class PairwiseMatrixTestData: def setUp(self): self.dm_1x1_data = [[0.0]] self.dm_2x2_data = [[0.0, 0.123], [0.123, 0.0]] self.dm_2x2_asym_data = [[0.0, 1.0], [-2.0, 0.0]] self.dm_3x3_data = [[0.0, 0.01, 4.2], [0.01, 0.0, 12.0], [4.2, 12.0, 0.0]] self.dm_5x5_data = [ [0, 1, 2, 3, 4], [5, 0, 6, 7, 8], [9, 1, 0, 2, 3], [4, 5, 6, 0, 7], [8, 9, 1, 2, 0], ] class PairwiseMatrixTestBase(PairwiseMatrixTestData): @classmethod def get_matrix_class(cls): return None def setUp(self): super(PairwiseMatrixTestBase, self).setUp() self.matobj = self.get_matrix_class() self.dm_1x1 = self.matobj(self.dm_1x1_data, ["a"]) self.dm_2x2 = self.matobj(self.dm_2x2_data, ["a", "b"]) self.dm_2x2_asym = self.matobj(self.dm_2x2_asym_data, ["a", "b"]) self.dm_3x3 = self.matobj(self.dm_3x3_data, ["a", "b", "c"]) self.dm_5x5 = self.matobj(self.dm_5x5_data, list("abcde")) self.dms = [self.dm_1x1, self.dm_2x2, self.dm_2x2_asym, self.dm_3x3] self.dm_shapes = [(1, 1), (2, 2), (2, 2), (3, 3)] self.dm_sizes = [1, 4, 4, 9] self.dm_transposes = [ self.dm_1x1, self.dm_2x2, self.matobj([[0, -2], [1, 0]], ["a", "b"]), self.dm_3x3, ] self.dm_redundant_forms = [ np.array(self.dm_1x1_data), np.array(self.dm_2x2_data), np.array(self.dm_2x2_asym_data), np.array(self.dm_3x3_data), ] def test_avoid_copy_on_construction(self): # ((data, expect_copy)) tests = ( ([[0, 1], [1, 0]], True), ([(0, 1), (1, 0)], True), (((0, 1), (1, 0)), True), (np.array([[0, 1], [1, 0]], dtype="int"), True), (np.array([[0, 1], [1, 0]], dtype="float"), False), (np.array([[0, 1], [1, 0]], dtype=np.float32), False), (np.array([[0, 1], [1, 0]], dtype=np.float64), False), (np.array([[0, 1], [1, 0]], dtype="double"), False), ) for data, expect in tests: obj = PairwiseMatrix(data) self.assertEqual(id(obj.data) != id(data), expect) def test_within(self): exp = pd.DataFrame( [["a", "a", 0.0], ["a", "c", 4.2], ["c", "a", 4.2], ["c", "c", 0.0]], columns=["i", "j", "value"], ) obs = self.dm_3x3.within(["a", "c"]) pdt.assert_frame_equal(obs, exp) def test_within_order_stability(self): exp = pd.DataFrame( [["a", "a", 0.0], ["a", "c", 4.2], ["c", "a", 4.2], ["c", "c", 0.0]], columns=["i", "j", "value"], ) # NOTE: order was changed from ['a', 'c'] to ['c', 'a'] # but the output order in exp is consistent with # test_within obs = self.dm_3x3.within(["c", "a"]) pdt.assert_frame_equal(obs, exp) obs = self.dm_3x3.within(["a", "c"]) pdt.assert_frame_equal(obs, exp) def test_within_missing_id(self): with self.assertRaisesRegex(MissingIDError, "not found."): self.dm_3x3.within(["x", "a"]) def test_between(self): exp = pd.DataFrame( [ ["b", "a", 5.0], ["b", "c", 6.0], ["b", "e", 8.0], ["d", "a", 4.0], ["d", "c", 6.0], ["d", "e", 7.0], ], columns=["i", "j", "value"], ) obs = self.dm_5x5.between(["b", "d"], ["a", "c", "e"]) pdt.assert_frame_equal(obs, exp) def test_between_order_stability(self): exp = pd.DataFrame( [ ["b", "a", 5.0], ["b", "c", 6.0], ["b", "e", 8.0], ["d", "a", 4.0], ["d", "c", 6.0], ["d", "e", 7.0], ], columns=["i", "j", "value"], ) # varying the order of the "i" values, result remains consistent # with the test_between result obs = self.dm_5x5.between(["d", "b"], ["a", "c", "e"]) pdt.assert_frame_equal(obs, exp) # varying the order of the "j" values, result remains consistent # with the test_between result obs = self.dm_5x5.between(["b", "d"], ["a", "e", "c"]) pdt.assert_frame_equal(obs, exp) # varying the order of the "i" and "j" values, result remains # consistent with the test_between result obs = self.dm_5x5.between(["d", "b"], ["a", "e", "c"]) pdt.assert_frame_equal(obs, exp) def test_between_overlap(self): exp = pd.DataFrame( [ ["b", "a", 5.0], ["b", "d", 7.0], ["b", "e", 8.0], ["d", "a", 4.0], ["d", "d", 0.0], ["d", "e", 7.0], ], columns=["i", "j", "value"], ) # 'd' in i and j overlap with self.assertRaisesRegex( KeyError, ("This constraint can removed with allow_overlap=True.") ): self.dm_5x5.between(["b", "d"], ["a", "d", "e"]) obs = self.dm_5x5.between(["b", "d"], ["a", "d", "e"], allow_overlap=True) pdt.assert_frame_equal(obs, exp) def test_between_missing_id(self): with self.assertRaisesRegex(MissingIDError, "not found."): self.dm_3x3.between(["x", "a"], ["a", "b", "c"]) with self.assertRaisesRegex(MissingIDError, "not found."): self.dm_3x3.between(["a", "b"], ["a", "x", "c"]) with self.assertRaisesRegex(MissingIDError, "not found."): self.dm_3x3.between(["a", "y"], ["a", "x", "c"]) def test_stable_order(self): exp = np.array([1, 3, 4], dtype=int) obs = self.dm_5x5._stable_order(["d", "e", "b"]) npt.assert_equal(obs, exp) def test_matrix_from_matrix(self): # pairwise from pairwise dm = self.matobj(self.dm_5x5) npt.assert_equal(dm.data, self.dm_5x5.data) self.assertEqual(dm.ids, self.dm_5x5.ids) # pairwise from symmetric sm = SymmetricMatrix(self.dm_3x3) dm = self.matobj(sm) npt.assert_equal(dm.data, self.dm_3x3.data) self.assertEqual(dm.ids, self.dm_3x3.ids) # pairwise from distance dm = DistanceMatrix(self.dm_3x3) dm = self.matobj(dm) npt.assert_equal(dm.data, self.dm_3x3.data) self.assertEqual(dm.ids, self.dm_3x3.ids) def test_subset_to_dataframe(self): exp = pd.DataFrame( [ ["b", "a", 5.0], ["b", "d", 7.0], ["b", "e", 8.0], ["d", "a", 4.0], ["d", "d", 0.0], ["d", "e", 7.0], ], columns=["i", "j", "value"], ) obs = self.dm_5x5._subset_to_dataframe(["b", "d"], ["a", "d", "e"]) pdt.assert_frame_equal(obs, exp) # and the empty edge cases exp = pd.DataFrame( [], columns=["i", "j", "value"], index=pd.RangeIndex(start=0, stop=0) ) obs = self.dm_5x5._subset_to_dataframe([], ["a", "d", "e"]) pdt.assert_frame_equal(obs, exp, check_dtype=False) obs = self.dm_5x5._subset_to_dataframe(["b", "d"], []) pdt.assert_frame_equal(obs, exp, check_dtype=False) obs = self.dm_5x5._subset_to_dataframe([], []) pdt.assert_frame_equal(obs, exp, check_dtype=False) def test_init_from_dm(self): ids = ["foo", "bar", "baz"] # PairwiseMatrix -> PairwiseMatrix exp = self.matobj(self.dm_3x3_data, ids) obs = self.matobj(self.dm_3x3, ids) self.assertEqual(obs, exp) # Test that copy of data is not made. self.assertTrue(obs.data is self.dm_3x3.data) obs.data[0, 1] = 424242 self.assertTrue(np.array_equal(obs.data, self.dm_3x3.data)) # DistanceMatrix -> PairwiseMatrix exp = self.matobj(self.dm_3x3_data, ids) obs = self.matobj(self.matobj(self.dm_3x3_data, ("a", "b", "c")), ids) self.assertEqual(obs, exp) # PairwiseMatrix -> DistanceMatrix with self.assertRaises(DistanceMatrixError): DistanceMatrix(self.dm_2x2_asym, ["foo", "bar"]) def test_init_non_hollow_dm(self): data = [[1, 1], [1, 1]] obs = self.matobj(data, ["a", "b"]) self.assertTrue(np.array_equal(obs.data, data)) data_hollow = skbio.stats.distance._utils.is_hollow(obs.data) self.assertEqual(data_hollow, False) def test_init_no_ids(self): exp = self.matobj(self.dm_3x3_data, ("0", "1", "2")) obs = self.matobj(self.dm_3x3_data) self.assertEqual(obs, exp) self.assertEqual(obs["1", "2"], 12.0) def test_init_invalid_input(self): # Empty data. with self.assertRaises(PairwiseMatrixError): self.matobj([], []) # Another type of empty data. with self.assertRaises(PairwiseMatrixError): self.matobj(np.empty((0, 0)), []) # Invalid number of dimensions. with self.assertRaises(PairwiseMatrixError): self.matobj([1, 2, 3], ["a"]) # Dimensions don't match. with self.assertRaises(PairwiseMatrixError): self.matobj([[1, 2, 3]], ["a"]) data = [[0, 1], [1, 0]] # Duplicate IDs. with self.assertRaises(PairwiseMatrixError): self.matobj(data, ["a", "a"]) # Number of IDs don't match dimensions. with self.assertRaises(PairwiseMatrixError): self.matobj(data, ["a", "b", "c"]) with self.assertRaises(PairwiseMatrixError): self.matobj(data, []) def test_from_iterable_non_hollow_data(self): iterable = (x for x in range(4)) exp = self.matobj([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]) res = self.matobj.from_iterable(iterable, lambda a, b: 1) self.assertEqual(res, exp) def test_from_iterable_asymmetric_data(self): iterable = (x for x in range(4)) exp = self.matobj( [[0, 1, 2, 3], [-1, 0, 1, 2], [-2, -1, 0, 1], [-3, -2, -1, 0]] ) res = self.matobj.from_iterable(iterable, lambda a, b: b - a) self.assertEqual(res, exp) def test_from_iterable_no_key(self): iterable = (x for x in range(4)) exp = self.matobj([[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]]) res = self.matobj.from_iterable(iterable, lambda a, b: abs(b - a)) self.assertEqual(res, exp) def test_from_iterable_with_key(self): iterable = (x for x in range(4)) exp = self.matobj( [[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]], ["0", "1", "4", "9"], ) res = self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), key=lambda x: str(x**2) ) self.assertEqual(res, exp) def test_from_iterable_empty(self): with self.assertRaises(PairwiseMatrixError): self.matobj.from_iterable([], lambda x: x) def test_from_iterable_single(self): exp = self.matobj([[100]]) res = self.matobj.from_iterable(["boo"], lambda a, b: 100) self.assertEqual(res, exp) def test_from_iterable_with_keys(self): iterable = (x for x in range(4)) exp = self.matobj( [[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]], ["0", "1", "4", "9"], ) res = self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), keys=iter(["0", "1", "4", "9"]) ) self.assertEqual(res, exp) def test_from_iterable_with_key_and_keys(self): iterable = (x for x in range(4)) with self.assertRaises(ValueError): self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), key=str, keys=["1", "2", "3", "4"] ) def test_from_iterable_scipy_hamming_metric_with_metadata(self): # test for #1254 seqs = [ Sequence("ACGT"), Sequence("ACGA", metadata={"id": "seq1"}), Sequence("AAAA", metadata={"id": "seq2"}), Sequence("AAAA", positional_metadata={"qual": range(4)}), ] exp = self.matobj( [ [0, 0.25, 0.75, 0.75], [0.25, 0.0, 0.5, 0.5], [0.75, 0.5, 0.0, 0.0], [0.75, 0.5, 0.0, 0.0], ], ["a", "b", "c", "d"], ) dm = self.matobj.from_iterable( seqs, metric=scipy.spatial.distance.hamming, keys=["a", "b", "c", "d"] ) self.assertEqual(dm, exp) def test_from_iterable_skbio_hamming_metric_with_metadata(self): # test for #1254 seqs = [ Sequence("ACGT"), Sequence("ACGA", metadata={"id": "seq1"}), Sequence("AAAA", metadata={"id": "seq2"}), Sequence("AAAA", positional_metadata={"qual": range(4)}), ] exp = self.matobj( [ [0, 0.25, 0.75, 0.75], [0.25, 0.0, 0.5, 0.5], [0.75, 0.5, 0.0, 0.0], [0.75, 0.5, 0.0, 0.0], ], ["a", "b", "c", "d"], ) dm = self.matobj.from_iterable( seqs, metric=skbio.sequence.distance.hamming, keys=["a", "b", "c", "d"] ) self.assertEqual(dm, exp) def test_data(self): for dm, exp in zip(self.dms, self.dm_redundant_forms): obs = dm.data self.assertTrue(np.array_equal(obs, exp)) with self.assertRaises(AttributeError): self.dm_3x3.data = "foo" def test_ids(self): obs = self.dm_3x3.ids self.assertEqual(obs, ("a", "b", "c")) # Test that we overwrite the existing IDs and that the ID index is # correctly rebuilt. new_ids = ["foo", "bar", "baz"] self.dm_3x3.ids = new_ids obs = self.dm_3x3.ids self.assertEqual(obs, tuple(new_ids)) self.assertTrue(np.array_equal(self.dm_3x3["bar"], np.array([0.01, 0.0, 12.0]))) with self.assertRaises(MissingIDError): self.dm_3x3["b"] def test_ids_invalid_input(self): with self.assertRaises(PairwiseMatrixError): self.dm_3x3.ids = ["foo", "bar"] # Make sure that we can still use the dissimilarity matrix after trying # to be evil. obs = self.dm_3x3.ids self.assertEqual(obs, ("a", "b", "c")) def test_ids_wrong_size(self): with self.assertRaises(PairwiseMatrixError): PairwiseMatrix([1, 2, 3], ["a"]) def test_dtype(self): for dm in self.dms: self.assertEqual(dm.dtype, np.float64) def test_shape(self): for dm, shape in zip(self.dms, self.dm_shapes): self.assertEqual(dm.shape, shape) def test_size(self): for dm, size in zip(self.dms, self.dm_sizes): self.assertEqual(dm.size, size) def test_transpose(self): for dm, transpose in zip(self.dms, self.dm_transposes): self.assertEqual(dm.T, transpose) self.assertEqual(dm.transpose(), transpose) # We should get a reference to a different object back, even if the # transpose is the same as the original. self.assertTrue(dm.transpose() is not dm) def test_index(self): self.assertEqual(self.dm_3x3.index("a"), 0) self.assertEqual(self.dm_3x3.index("b"), 1) self.assertEqual(self.dm_3x3.index("c"), 2) with self.assertRaises(MissingIDError): self.dm_3x3.index("d") with self.assertRaises(MissingIDError): self.dm_3x3.index(1) def test_redundant_form(self): for dm, redundant in zip(self.dms, self.dm_redundant_forms): obs = dm.redundant_form() self.assertTrue(np.array_equal(obs, redundant)) def test_copy(self): copy = self.dm_2x2.copy() self.assertEqual(copy, self.dm_2x2) self.assertFalse(copy.data is self.dm_2x2.data) # deepcopy doesn't actually create a copy of the IDs because it is a # tuple of strings, which is fully immutable. self.assertTrue(copy.ids is self.dm_2x2.ids) new_ids = ["hello", "world"] copy.ids = new_ids self.assertNotEqual(copy.ids, self.dm_2x2.ids) copy = self.dm_2x2.copy() copy.data[0, 1] = 0.0001 self.assertFalse(np.array_equal(copy.data, self.dm_2x2.data)) def test_filter_no_filtering(self): # Don't actually filter anything -- ensure we get back a different # object. obs = self.dm_3x3.filter(["a", "b", "c"]) self.assertEqual(obs, self.dm_3x3) self.assertFalse(obs is self.dm_3x3) def test_filter_reorder(self): # Don't filter anything, but reorder the distance matrix. order = ["c", "a", "b"] exp = self.matobj([[0, 4.2, 12], [4.2, 0, 0.01], [12, 0.01, 0]], order) obs = self.dm_3x3.filter(order) self.assertEqual(obs, exp) def test_filter_single_id(self): ids = ["b"] exp = self.matobj([[0]], ids) obs = self.dm_2x2_asym.filter(ids) self.assertEqual(obs, exp) def test_filter_asymmetric(self): # 2x2 ids = ["b", "a"] exp = self.matobj([[0, -2], [1, 0]], ids) obs = self.dm_2x2_asym.filter(ids) self.assertEqual(obs, exp) # 3x3 dm = self.matobj( [[0, 10, 53], [42, 0, 22.5], [53, 1, 0]], ("bro", "brah", "breh") ) ids = ["breh", "brah"] exp = self.matobj([[0, 1], [22.5, 0]], ids) obs = dm.filter(ids) self.assertEqual(obs, exp) def test_filter_subset(self): ids = ("c", "a") exp = self.matobj([[0, 4.2], [4.2, 0]], ids) obs = self.dm_3x3.filter(ids) self.assertEqual(obs, exp) ids = ("b", "a") exp = self.matobj([[0, 0.01], [0.01, 0]], ids) obs = self.dm_3x3.filter(ids) self.assertEqual(obs, exp) # 4x4 dm = self.matobj([[0, 1, 55, 7], [1, 0, 16, 1], [55, 16, 0, 23], [7, 1, 23, 0]]) ids = np.asarray(["3", "0", "1"]) exp = self.matobj([[0, 7, 1], [7, 0, 1], [1, 1, 0]], ids) obs = dm.filter(ids) self.assertEqual(obs, exp) def test_filter_duplicate_ids(self): with self.assertRaises(PairwiseMatrixError): self.dm_3x3.filter(["c", "a", "c"]) def test_filter_missing_ids(self): with self.assertRaises(MissingIDError): self.dm_3x3.filter(["c", "bro"]) def test_filter_missing_ids_strict_false(self): # no exception should be raised ids = ("c", "a") exp = self.matobj([[0, 4.2], [4.2, 0]], ids) obs = self.dm_3x3.filter(["c", "a", "not found"], strict=False) self.assertEqual(obs, exp) def test_filter_empty_ids(self): with self.assertRaises(PairwiseMatrixError): self.dm_3x3.filter([]) @skipUnless(has_matplotlib, "Matplotlib not available.") def test_plot_default(self): fig = self.dm_1x1.plot() self.assertIsInstance(fig, mpl.figure.Figure) axes = fig.get_axes() self.assertEqual(len(axes), 2) ax = axes[0] self.assertEqual(ax.get_title(), "") xticks = [] for tick in ax.get_xticklabels(): xticks.append(tick.get_text()) self.assertEqual(xticks, ["a"]) yticks = [] for tick in ax.get_yticklabels(): yticks.append(tick.get_text()) self.assertEqual(yticks, ["a"]) @skipUnless(has_matplotlib, "Matplotlib not available.") def test_plot_no_default(self): ids = ["0", "one", "2", "three", "4.000"] data = ( [0, 1, 2, 3, 4], [1, 0, 1, 2, 3], [2, 1, 0, 1, 2], [3, 2, 1, 0, 1], [4, 3, 2, 1, 0], ) dm = self.matobj(data, ids) fig = dm.plot(cmap="Reds", title="Testplot") self.assertIsInstance(fig, mpl.figure.Figure) axes = fig.get_axes() self.assertEqual(len(axes), 2) ax = axes[0] self.assertEqual(ax.get_title(), "Testplot") xticks = [] for tick in ax.get_xticklabels(): xticks.append(tick.get_text()) self.assertEqual(xticks, ["0", "one", "2", "three", "4.000"]) yticks = [] for tick in ax.get_yticklabels(): yticks.append(tick.get_text()) self.assertEqual(yticks, ["0", "one", "2", "three", "4.000"]) def test_to_data_frame_1x1(self): df = self.dm_1x1.to_data_frame() exp = pd.DataFrame([[0.0]], index=["a"], columns=["a"]) assert_data_frame_almost_equal(df, exp) def test_to_data_frame_3x3(self): df = self.dm_3x3.to_data_frame() exp = pd.DataFrame( [[0.0, 0.01, 4.2], [0.01, 0.0, 12.0], [4.2, 12.0, 0.0]], index=["a", "b", "c"], columns=["a", "b", "c"], ) assert_data_frame_almost_equal(df, exp) def test_to_data_frame_default_ids(self): df = self.matobj(self.dm_2x2_data).to_data_frame() exp = pd.DataFrame( [[0.0, 0.123], [0.123, 0.0]], index=["0", "1"], columns=["0", "1"] ) assert_data_frame_almost_equal(df, exp) def test_str(self): for dm in self.dms: obs = str(dm) # Do some very light testing here to make sure we're getting a # non-empty string back. We don't want to test the exact # formatting. self.assertTrue(obs) def test_eq(self): for dm in self.dms: copy = dm.copy() self.assertTrue(dm == dm) self.assertTrue(copy == copy) self.assertTrue(dm == copy) self.assertTrue(copy == dm) self.assertFalse(self.dm_1x1 == self.dm_3x3) def test_ne(self): # Wrong class. self.assertTrue(self.dm_3x3 != "foo") # Wrong shape. self.assertTrue(self.dm_3x3 != self.dm_1x1) # Wrong IDs. other = self.dm_3x3.copy() other.ids = ["foo", "bar", "baz"] self.assertTrue(self.dm_3x3 != other) # Wrong data. other = self.dm_3x3.copy() other.data[1, 0] = 42.42 self.assertTrue(self.dm_3x3 != other) self.assertFalse(self.dm_2x2 != self.dm_2x2) def test_contains(self): self.assertTrue("a" in self.dm_3x3) self.assertTrue("b" in self.dm_3x3) self.assertTrue("c" in self.dm_3x3) self.assertFalse("d" in self.dm_3x3) def test_getslice(self): # Slice of first dimension only. Test that __getslice__ defers to # __getitem__. obs = self.dm_2x2[1:] self.assertTrue(np.array_equal(obs, np.array([[0.123, 0.0]]))) self.assertEqual(type(obs), np.ndarray) def test_getitem_by_id(self): obs = self.dm_1x1["a"] self.assertTrue(np.array_equal(obs, np.array([0.0]))) obs = self.dm_2x2_asym["b"] self.assertTrue(np.array_equal(obs, np.array([-2.0, 0.0]))) obs = self.dm_3x3["c"] self.assertTrue(np.array_equal(obs, np.array([4.2, 12.0, 0.0]))) with self.assertRaises(MissingIDError): self.dm_2x2["c"] def test_getitem_by_id_pair(self): # Same object. self.assertEqual(self.dm_1x1["a", "a"], 0.0) # Different objects (symmetric). self.assertEqual(self.dm_3x3["b", "c"], 12.0) self.assertEqual(self.dm_3x3["c", "b"], 12.0) # Different objects (asymmetric). self.assertEqual(self.dm_2x2_asym["a", "b"], 1.0) self.assertEqual(self.dm_2x2_asym["b", "a"], -2.0) with self.assertRaises(MissingIDError): self.dm_2x2["a", "c"] def test_getitem_ndarray_indexing(self): # Single element access. obs = self.dm_3x3[0, 1] self.assertEqual(obs, 0.01) # Single element access (via two __getitem__ calls). obs = self.dm_3x3[0][1] self.assertEqual(obs, 0.01) # Row access. obs = self.dm_3x3[1] self.assertTrue(np.array_equal(obs, np.array([0.01, 0.0, 12.0]))) self.assertEqual(type(obs), np.ndarray) # Grab all data. obs = self.dm_3x3[:, :] self.assertTrue(np.array_equal(obs, self.dm_3x3.data)) self.assertEqual(type(obs), np.ndarray) with self.assertRaises(IndexError): self.dm_3x3[:, 3] def test_validate_invalid_dtype(self): with self.assertRaises(PairwiseMatrixError): self.dm_3x3._validate_shape(np.array([[0, 42], [42, 0]])) def test_validate_invalid_shape(self): # first check it actually likes good matrices self.dm_3x3._validate_shape(np.array([[0.0, 42.0], [42.0, 0.0]])) # it checks just the shape, not the content self.dm_3x3._validate_shape(np.array([[1.0, 2.0], [3.0, 4.0]])) # empty array with self.assertRaises(PairwiseMatrixError): self.dm_3x3._validate_shape(np.array([])) # invalid shape with self.assertRaises(PairwiseMatrixError): self.dm_3x3._validate_shape( np.array([[0.0, 42.0], [42.0, 0.0], [22.0, 22.0]]) ) with self.assertRaises(PairwiseMatrixError): self.dm_3x3._validate_shape( np.array([[[0.0, 42.0], [42.0, 0.0]], [[0.0, 24.0], [24.0, 0.0]]]) ) def test_validate_invalid_ids(self): # repeated ids with self.assertRaises(PairwiseMatrixError): self.dm_3x3._validate_ids(self.dm_3x3.data, ["a", "a"]) # empty ids with self.assertRaises(PairwiseMatrixError): self.dm_3x3._validate_ids(self.dm_3x3.data, []) # invalid shape with self.assertRaises(PairwiseMatrixError): self.dm_3x3._validate_ids(self.dm_3x3.data, ["a", "b", "c", "d"]) class SymmetricMatrixTestBase(PairwiseMatrixTestData): @classmethod def get_matrix_class(cls): return None def setUp(self): super(SymmetricMatrixTestBase, self).setUp() self.matobj = self.get_matrix_class() self.dm_1x1 = self.matobj(self.dm_1x1_data, ["a"]) self.dm_2x2 = self.matobj(self.dm_2x2_data, ["a", "b"]) self.dm_3x3 = self.matobj(self.dm_3x3_data, ["a", "b", "c"]) self.dm_1x1_cond = self.matobj(self.dm_1x1_data, ["a"], condensed=True) self.dm_2x2_cond = self.matobj(self.dm_2x2_data, ["a", "b"], condensed=True) self.dm_3x3_cond = self.matobj( self.dm_3x3_data, ["a", "b", "c"], condensed=True ) self.dm_5x5 = self.matobj([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], list("abcde")) self.dm_5x5_cond = self.matobj( [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], list("abcde"), condensed=True ) self.dm_5x5_cond_diag = self.matobj( [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], list("abcde"), condensed=True, diagonal=[90, 80, 70, 60, 50], ) self.dms = [ self.dm_1x1, self.dm_2x2, self.dm_3x3, self.dm_1x1_cond, self.dm_2x2_cond, self.dm_3x3_cond, ] self.dm_condensed_forms = [ np.array([]), np.array([0.123]), np.array([0.01, 4.2, 12.0]), ] * 2 def test_get_element_from_condensed(self): # check that it gets diagonal values correct exp = 70 obs = self.dm_5x5_cond_diag["c", "c"] self.assertEqual(obs, exp) # check non diagonal values exp = 1 obs = self.dm_5x5_cond_diag["a", "b"] def test_get_row_from_condensed(self): exp = np.array([90, 1, 2, 3, 4]) obs = self.dm_5x5_cond_diag["a"] npt.assert_equal(obs, exp) exp = np.array([1, 80, 5, 6, 7]) obs = self.dm_5x5_cond_diag["b"] npt.assert_equal(obs, exp) exp = np.array([4, 7, 9, 10, 50]) obs = self.dm_5x5_cond_diag["e"] npt.assert_equal(obs, exp) def test_matrix_from_matrix(self): # symmetric from symmetric sm = SymmetricMatrix(self.dm_5x5) npt.assert_equal(sm.data, self.dm_5x5.data) self.assertEqual(sm.ids, self.dm_5x5.ids) npt.assert_equal(sm.diagonal, self.dm_5x5.diagonal) # symmetric from pairwise pm = PairwiseMatrix(self.dm_3x3) sm = self.matobj(pm) npt.assert_equal(sm.data, self.dm_3x3.data) self.assertEqual(sm.ids, self.dm_3x3.ids) npt.assert_equal(sm.diagonal, self.dm_3x3.diagonal) # symmetric from distance dm = DistanceMatrix(self.dm_3x3) sm = self.matobj(dm) npt.assert_equal(sm.data, self.dm_3x3.data) self.assertEqual(sm.ids, self.dm_3x3.ids) npt.assert_equal(sm.diagonal, self.dm_3x3.diagonal) def test_matrix_from_matrix_condensed(self): # symmetric from symmetric sm = SymmetricMatrix(self.dm_5x5_cond, condensed=True) npt.assert_equal(sm.data, self.dm_5x5_cond.data) self.assertEqual(sm.ids, self.dm_5x5_cond.ids) npt.assert_equal(sm.diagonal, self.dm_5x5_cond.diagonal) # symmetric from symmetric, change ids sm = SymmetricMatrix(self.dm_5x5_cond, ids = ['aa', 'bb', 'cc', 'dd', 'ee'], condensed=True) npt.assert_equal(sm.data, self.dm_5x5_cond.data) self.assertEqual(sm.ids, ('aa', 'bb', 'cc', 'dd', 'ee')) npt.assert_equal(sm.diagonal, self.dm_5x5_cond.diagonal) # symmetric from pairwise pm = PairwiseMatrix(self.dm_3x3_cond) sm = self.matobj(pm, condensed=True) npt.assert_equal(sm.data, self.dm_3x3_cond.data) self.assertEqual(sm.ids, self.dm_3x3_cond.ids) npt.assert_equal(sm.diagonal, self.dm_3x3_cond.diagonal) # symmetric from pairwise, change ids pm = PairwiseMatrix(self.dm_3x3_cond) sm = self.matobj(pm, ids=['aa', 'bb', 'cc'], condensed=True) npt.assert_equal(sm.data, self.dm_3x3_cond.data) self.assertEqual(sm.ids, ('aa', 'bb', 'cc')) npt.assert_equal(sm.diagonal, self.dm_3x3_cond.diagonal) # symmetric from distance dm = DistanceMatrix(self.dm_3x3_cond) sm = self.matobj(dm, condensed=True) npt.assert_equal(sm.data, self.dm_3x3_cond.data) self.assertEqual(sm.ids, self.dm_3x3_cond.ids) npt.assert_equal(sm.diagonal, self.dm_3x3_cond.diagonal) # symmetric from distance, change ids dm = DistanceMatrix(self.dm_3x3_cond) sm = self.matobj(dm, ids=['aa', 'bb', 'cc'], condensed=True) npt.assert_equal(sm.data, self.dm_3x3_cond.data) self.assertEqual(sm.ids, ('aa', 'bb', 'cc')) npt.assert_equal(sm.diagonal, self.dm_3x3_cond.diagonal) # symmetric from distance, change diagonal, only possible when the # original matrix is condensed, because we can't provide diagonal with a 2D # matrix as input dm = DistanceMatrix(self.dm_3x3_cond, condensed=True) sm = self.matobj(dm, dm.ids, diagonal=[11, 22, 33], condensed=True) npt.assert_equal(sm.data, self.dm_3x3_cond.data) self.assertEqual(sm.ids, self.dm_3x3_cond.ids) npt.assert_equal(sm.diagonal, np.array([11, 22, 33])) # dm = SymmetricMatrix(self.dm_3x3_cond, condensed=True) sm = self.matobj(dm, dm.ids, diagonal=[11, 22, 33], condensed=True) npt.assert_equal(sm.data, self.dm_3x3_cond.data) self.assertEqual(sm.ids, self.dm_3x3_cond.ids) npt.assert_equal(sm.diagonal, np.array([11, 22, 33])) # this should raise error because can't pass diagonal with 2D input with self.assertRaises(SymmetricMatrixError) as e: pm = PairwiseMatrix(self.dm_3x3_cond) sm = self.matobj(pm, pm.ids, diagonal=[11, 22, 33], condensed=True) self.assertEqual(str(e.exception), "Cannot provide diagonal when data matrix is 2D. Information contained along diagonal is ambiguous.") def test_as_condensed(self): sm = self.dm_3x3.as_condensed() # data should be the same, but copied self.assertEqual(sm, self.dm_3x3_cond) self.assertFalse(sm.data is self.dm_3x3.data) # ids aren't copied because they are immutable self.assertTrue(sm.ids is self.dm_3x3.ids) self.assertFalse(sm.diagonal is self.dm_3x3.diagonal) def test_as_redundant(self): sm_ = self.dm_3x3_cond.as_redundant() self.assertEqual(sm_, self.dm_3x3) self.assertFalse(sm_.data is self.dm_3x3_cond.data) # ids aren't copied because they are immutable self.assertTrue(sm_.ids is self.dm_3x3_cond.ids) self.assertFalse(sm_.diagonal is self.dm_3x3_cond.diagonal) def test_validate_ids_1d(self): with self.assertRaises(PairwiseMatrixError) as e: SymmetricMatrix([1, 2, 3], ["a"], condensed=True) self.assertEqual( str(e.exception), "The number of IDs (1) must match the number of rows/columns in the data (3).", ) def test_init_diagonal_1d_none(self): # diagonal=None and 1d input should return None, because the underlying data structure is redundant sm = SymmetricMatrix([1, 2, 3]) obs = sm.diagonal exp = None self.assertEqual(obs, exp) def test_init_diagonal_2d_zero_trace(self): # diagonal=None and 2d input should return None because it is redundant sm = SymmetricMatrix([[0, 1, 2], [1, 0, 3], [2, 3, 0]]) obs = sm.diagonal exp = None self.assertEqual(obs, exp) def test_init_diagonal_2d_nonzero_trace(self): # diagonal=None and 2d input should return None if it contains non-zeros, because the underlying data structure is redundant sm = SymmetricMatrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) obs = sm.diagonal exp = None self.assertEqual(obs, exp) def test_init_diagonal_condensed(self): sm = SymmetricMatrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]], condensed=True) exp = np.array([1, 3, 5]) obs = sm.diagonal npt.assert_equal(obs, exp) def test_init_diagonal_given_scalar(self): sm = SymmetricMatrix([1, 2, 3], diagonal=1.5) obs = sm.diagonal exp = 1.5 self.assertEqual(obs, exp) def test_init_diagonal_given_arraylike(self): sm = SymmetricMatrix([1, 2, 3], diagonal=[2, 4, 5]) obs = sm.diagonal exp = np.array([2, 4, 5]) npt.assert_equal(obs, exp) def test_validate_data(self): with self.assertRaises(SymmetricMatrixError) as e: SymmetricMatrix([[1, 2], [4, 1]]) self.assertEqual( str(e.exception), "Data must be symmetric and cannot contain NaNs." ) def test_validate_diagonal_multidim(self): with self.assertRaises(SymmetricMatrixError) as e: SymmetricMatrix([1, 2, 3], diagonal=[[1, 2]]) self.assertEqual( str(e.exception), "Diagonal must be 1 dimensional if it is an array. Found 2 dimensions.", ) # def test_validate_diagonal_mismatch_2D(self): # with self.assertRaises(SymmetricMatrixError) as e: # SymmetricMatrix([[0, 1], [1, 0]], diagonal=[1, 2, 3]) # self.assertEqual( # str(e.exception), # "Length of diagonal (3) does not match the shape of the matrix (2, 2).", # ) def test_validate_diagonal_mismatch_1D(self): with self.assertRaises(SymmetricMatrixError) as e: SymmetricMatrix([1], diagonal=[1, 2, 3]) self.assertEqual( str(e.exception), "Length of diagonal (3) does not match the shape of the matrix (2, 2).", ) def test_validate_diagonal_providing_redundant(self): with self.assertRaises(SymmetricMatrixError) as e: sm = SymmetricMatrix([[0, 1], [1, 0]], diagonal=[2, 3]) self.assertEqual( str(e.exception), "Cannot provide diagonal when data matrix is 2D. Information contained along diagonal is ambiguous.", ) def test_validate_shape_invalid_1D_size(self): with self.assertRaises(SymmetricMatrixError) as e: SymmetricMatrix([1, 2, 3, 4]) self.assertEqual( str(e.exception), "Incompatible vector size. It must be a binomial coefficient n choose 2 for some integer n >= 2.", ) def test_validate_shape_3D(self): with self.assertRaises(SymmetricMatrixError) as e: SymmetricMatrix([[[1]]]) self.assertEqual( str(e.exception), "Data must be have either 1 or 2 dimensions. Found 3 dimensions.", ) def test_condensed_form_condensed(self): obs = SymmetricMatrix([1, 2, 3], condensed=True).condensed_form() exp = np.array([1, 2, 3]) npt.assert_equal(obs, exp) def test_condensed_form_redundant(self): obs = SymmetricMatrix([1, 2, 3], condensed=False).condensed_form() exp = np.array([1, 2, 3]) npt.assert_equal(obs, exp) def test_subset_to_dataframe(self): exp = pd.DataFrame( [ ["b", "a", 1.0], ["b", "d", 6.0], ["b", "e", 7.0], ["d", "a", 3.0], ["d", "d", 0.0], ["d", "e", 10.0], ], columns=["i", "j", "value"], ) obs = self.dm_5x5._subset_to_dataframe(["b", "d"], ["a", "d", "e"]) pdt.assert_frame_equal(obs, exp) # and the empty edge cases exp = pd.DataFrame( [], columns=["i", "j", "value"], index=pd.RangeIndex(start=0, stop=0) ) obs = self.dm_5x5._subset_to_dataframe([], ["a", "d", "e"]) pdt.assert_frame_equal(obs, exp, check_dtype=False) obs = self.dm_5x5._subset_to_dataframe(["b", "d"], []) pdt.assert_frame_equal(obs, exp, check_dtype=False) obs = self.dm_5x5._subset_to_dataframe([], []) pdt.assert_frame_equal(obs, exp, check_dtype=False) def test_subset_to_dataframe_condensed(self): exp = pd.DataFrame( [ ["b", "a", 1.0], ["b", "d", 6.0], ["b", "e", 7.0], ["d", "a", 3.0], ["d", "d", 0.0], ["d", "e", 10.0], ], columns=["i", "j", "value"], ) obs = self.dm_5x5_cond._subset_to_dataframe(["b", "d"], ["a", "d", "e"]) pdt.assert_frame_equal(obs, exp) # and the empty edge cases exp = pd.DataFrame( [], columns=["i", "j", "value"], index=pd.RangeIndex(start=0, stop=0) ) obs = self.dm_5x5_cond._subset_to_dataframe([], ["a", "d", "e"]) pdt.assert_frame_equal(obs, exp, check_dtype=False) obs = self.dm_5x5_cond._subset_to_dataframe(["b", "d"], []) pdt.assert_frame_equal(obs, exp, check_dtype=False) obs = self.dm_5x5_cond._subset_to_dataframe([], []) pdt.assert_frame_equal(obs, exp, check_dtype=False) def test_subset_to_dataframe_condensed_diagonal(self): exp = pd.DataFrame( [ ["b", "a", 1.0], ["b", "d", 6.0], ["b", "e", 7.0], ["d", "a", 3.0], ["d", "d", 60.0], ["d", "e", 10.0], ], columns=["i", "j", "value"], ) obs = self.dm_5x5_cond_diag._subset_to_dataframe(["b", "d"], ["a", "d", "e"]) pdt.assert_frame_equal(obs, exp) # and the empty edge cases exp = pd.DataFrame( [], columns=["i", "j", "value"], index=pd.RangeIndex(start=0, stop=0) ) obs = self.dm_5x5_cond_diag._subset_to_dataframe([], ["a", "d", "e"]) pdt.assert_frame_equal(obs, exp, check_dtype=False) obs = self.dm_5x5_cond_diag._subset_to_dataframe(["b", "d"], []) pdt.assert_frame_equal(obs, exp, check_dtype=False) obs = self.dm_5x5_cond_diag._subset_to_dataframe([], []) pdt.assert_frame_equal(obs, exp, check_dtype=False) # test filtering on condensed forms def test_filter_no_filtering(self): # Don't actually filter anything -- ensure we get back a different # object. obs = self.dm_3x3_cond.filter(["a", "b", "c"]) self.assertEqual(obs, self.dm_3x3_cond) self.assertFalse(obs is self.dm_3x3_cond) def test_filter_reorder(self): # Don't filter anything, but reorder the distance matrix. order = ["c", "a", "b"] exp = self.matobj( [[0, 4.2, 12], [4.2, 0, 0.01], [12, 0.01, 0]], order, condensed=True ) obs = self.dm_3x3_cond.filter(order) self.assertEqual(obs, exp) def test_filter_single_id(self): ids = ["b"] exp = self.matobj([[0]], ids, condensed=True) obs = self.dm_2x2_cond.filter(ids) self.assertEqual(obs, exp) def test_filter_subset(self): ids = ("c", "a") exp = self.matobj([[0, 4.2], [4.2, 0]], ids, condensed=True) obs = self.dm_3x3_cond.filter(ids) self.assertEqual(obs, exp) ids = ("b", "a") exp = self.matobj([[0, 0.01], [0.01, 0]], ids, condensed=True) obs = self.dm_3x3_cond.filter(ids) self.assertEqual(obs, exp) # 4x4 dm = self.matobj( [[0, 1, 55, 7], [1, 0, 16, 1], [55, 16, 0, 23], [7, 1, 23, 0]], condensed=True, ) ids = np.asarray(["3", "0", "1"]) exp = self.matobj([[0, 7, 1], [7, 0, 1], [1, 1, 0]], ids, condensed=True) obs = dm.filter(ids) self.assertEqual(obs, exp) def test_filter_duplicate_ids(self): with self.assertRaises(PairwiseMatrixError) as e: self.dm_3x3_cond.filter(["c", "a", "c"]) self.assertEqual( str(e.exception), "IDs must be unique. Found the following duplicate IDs: 'c'", ) def test_filter_missing_ids(self): with self.assertRaises(MissingIDError) as e: self.dm_3x3_cond.filter(["c", "bro"]) self.assertEqual(str(e.exception), "The ID 'bro' is not in the matrix.") def test_filter_missing_ids_strict_false(self): # no exception should be raised ids = ("c", "a") exp = self.matobj([[0, 4.2], [4.2, 0]], ids, condensed=True) obs = self.dm_3x3_cond.filter(["c", "a", "not found"], strict=False) self.assertEqual(obs, exp) def test_filter_empty_ids(self): with self.assertRaises(PairwiseMatrixError) as e: self.dm_3x3_cond.filter([]) self.assertEqual(str(e.exception), "IDs must be at least 1 in size.") def test_getslice(self): # Slice of first dimension only. Test that __getslice__ defers to # __getitem__. obs = self.dm_2x2_cond[1:] self.assertTrue(np.array_equal(obs, np.array([[0.123, 0.0]]))) self.assertEqual(type(obs), np.ndarray) def test_getitem_by_id(self): obs = self.dm_1x1_cond["a"] self.assertTrue(np.array_equal(obs, np.array([0.0]))) obs = self.dm_2x2_cond["b"] self.assertTrue(np.array_equal(obs, np.array([0.123, 0.0]))) obs = self.dm_3x3_cond["c"] self.assertTrue(np.array_equal(obs, np.array([4.2, 12.0, 0.0]))) with self.assertRaises(MissingIDError) as e: self.dm_2x2_cond["c"] self.assertEqual(str(e.exception), "The ID 'c' is not in the matrix.") def test_getitem_by_id_with_scalar_diag(self): # get row sm = self.matobj([1, 2, 3], ['a', 'b', 'c'], diagonal=8, condensed=True) obs = sm["a"] exp = np.array([8, 1, 2]) npt.assert_equal(obs, exp) # get single value obs = sm["a", "a"] exp = 8.0 npt.assert_equal(obs, exp) def test_getitem_by_id_pair(self): # Same object. self.assertEqual(self.dm_1x1_cond["a", "a"], 0.0) # Different objects (symmetric). self.assertEqual(self.dm_3x3_cond["b", "c"], 12.0) self.assertEqual(self.dm_3x3_cond["c", "b"], 12.0) # Different objects. self.assertEqual(self.dm_2x2_cond["a", "b"], 0.123) self.assertEqual(self.dm_2x2_cond["b", "a"], 0.123) with self.assertRaises(MissingIDError) as e: self.dm_2x2_cond["a", "c"] self.assertEqual(str(e.exception), "The ID 'c' is not in the matrix.") def test_getitem_ndarray_indexing(self): # Single element access. obs = self.dm_3x3_cond[0, 1] self.assertEqual(obs, 0.01) # Single element access (via two __getitem__ calls). obs = self.dm_3x3_cond[0][1] self.assertEqual(obs, 0.01) # Row access. obs = self.dm_3x3_cond[1] self.assertTrue(np.array_equal(obs, np.array([0.01, 0.0, 12.0]))) self.assertEqual(type(obs), np.ndarray) # Grab all data. obs = self.dm_3x3_cond[:, :] self.assertTrue(np.array_equal(obs, self.dm_3x3.data)) self.assertEqual(type(obs), np.ndarray) with self.assertRaises(IndexError) as e: self.dm_3x3_cond[:, 3] self.assertEqual( str(e.exception), "index 3 is out of bounds for axis 1 with size 3" ) class DistanceMatrixTestBase(PairwiseMatrixTestData): @classmethod def get_matrix_class(cls): return None def setUp(self): super(DistanceMatrixTestBase, self).setUp() self.matobj = self.get_matrix_class() self.dm_1x1 = self.matobj(self.dm_1x1_data, ["a"]) self.dm_2x2 = self.matobj(self.dm_2x2_data, ["a", "b"]) self.dm_3x3 = self.matobj(self.dm_3x3_data, ["a", "b", "c"]) self.dm_1x1_cond = self.matobj(self.dm_1x1_data, ["a"], condensed=True) self.dm_2x2_cond = self.matobj(self.dm_2x2_data, ["a", "b"], condensed=True) self.dm_3x3_cond = self.matobj( self.dm_3x3_data, ["a", "b", "c"], condensed=True ) self.dms = [ self.dm_1x1, self.dm_2x2, self.dm_3x3, self.dm_1x1_cond, self.dm_2x2_cond, self.dm_3x3_cond, ] self.dm_condensed_forms = [ np.array([]), np.array([0.123]), np.array([0.01, 4.2, 12.0]), ] * 2 def test_matrix_from_matrix(self): # distance from distance sm = DistanceMatrix(self.dm_3x3) npt.assert_equal(sm.data, self.dm_3x3.data) self.assertEqual(sm.ids, self.dm_3x3.ids) npt.assert_equal(sm.diagonal, self.dm_3x3.diagonal) # distance from pairwise pm = PairwiseMatrix(self.dm_3x3) sm = self.matobj(pm) npt.assert_equal(sm.data, self.dm_3x3.data) self.assertEqual(sm.ids, self.dm_3x3.ids) npt.assert_equal(sm.diagonal, self.dm_3x3.diagonal) # distance from symmetric dm = SymmetricMatrix(self.dm_3x3) sm = self.matobj(dm) npt.assert_equal(sm.data, self.dm_3x3.data) self.assertEqual(sm.ids, self.dm_3x3.ids) npt.assert_equal(sm.diagonal, self.dm_3x3.diagonal) def test_matrix_from_matrix_condensed(self): # distance from distance sm = DistanceMatrix(self.dm_3x3_cond, condensed=True) npt.assert_equal(sm.data, self.dm_3x3_cond.data) self.assertEqual(sm.ids, self.dm_3x3_cond.ids) npt.assert_equal(sm.diagonal, self.dm_3x3_cond.diagonal) # distance from pairwise pm = PairwiseMatrix(self.dm_3x3_cond) sm = self.matobj(pm, condensed=True) npt.assert_equal(sm.data, self.dm_3x3_cond.data) self.assertEqual(sm.ids, self.dm_3x3_cond.ids) npt.assert_equal(sm.diagonal, self.dm_3x3_cond.diagonal) # distance from symmetric dm = SymmetricMatrix(self.dm_3x3_cond) sm = self.matobj(dm, condensed=True) npt.assert_equal(sm.data, self.dm_3x3_cond.data) self.assertEqual(sm.ids, self.dm_3x3_cond.ids) npt.assert_equal(sm.diagonal, self.dm_3x3_cond.diagonal) def test_init_from_condensed_form(self): data = [1, 2, 3] exp = self.matobj([[0, 1, 2], [1, 0, 3], [2, 3, 0]], ["0", "1", "2"]) res = self.matobj(data) self.assertEqual(exp, res) def test_init_from_condensed_to_condensed(self): data = [1, 2, 3] exp = self.matobj( [[0, 1, 2], [1, 0, 3], [2, 3, 0]], ["0", "1", "2"], condensed=True ) res = self.matobj(data, condensed=True) self.assertEqual(exp, res) def test_init_invalid_input(self): # Asymmetric. data = [[0.0, 2.0], [1.0, 0.0]] with self.assertRaises(DistanceMatrixError) as e: self.matobj(data, ["a", "b"]) self.assertEqual( str(e.exception), "Data must be symmetric and cannot contain NaNs." ) # Non-hollow data = [[1.0, 2.0], [2.0, 1.0]] with self.assertRaises(DistanceMatrixError) as e: self.matobj(data, ["a", "b"]) self.assertEqual( str(e.exception), "Data must be hollow (i.e., the diagonal can only contain zeros).", ) # Ensure that the superclass validation is still being performed. with self.assertRaises(PairwiseMatrixError) as e: self.matobj([[1, 2, 3]], ["a"]) self.assertEqual( str(e.exception), "Data must be square (i.e., have the same number of rows and columns).", ) def test_init_invalid_input_condensed(self): # Asymmetric. data = [[0.0, 2.0], [1.0, 0.0]] with self.assertRaises(DistanceMatrixError) as e: self.matobj(data, ["a", "b"], condensed=True) self.assertEqual( str(e.exception), "Data must be symmetric and cannot contain NaNs." ) # Non-hollow data = [[1.0, 2.0], [2.0, 1.0]] with self.assertRaises(DistanceMatrixError) as e: self.matobj(data, ["a", "b"], condensed=True) self.assertEqual( str(e.exception), "Data must be hollow (i.e., the diagonal can only contain zeros).", ) # Ensure that the superclass validation is still being performed. with self.assertRaises(PairwiseMatrixError) as e: self.matobj([[1, 2, 3]], ["a"], condensed=True) self.assertEqual( str(e.exception), "Data must be square (i.e., have the same number of rows and columns).", ) def test_init_nans(self): with self.assertRaisesRegex(DistanceMatrixError, r"NaNs"): self.matobj([[0.0, np.nan], [np.nan, 0.0]], ["a", "b"]) def test_init_nans_condensed(self): with self.assertRaisesRegex(DistanceMatrixError, r"NaNs"): self.matobj([[0.0, np.nan], [np.nan, 0.0]], ["a", "b"], condensed=True) def test_from_iterable_no_key(self): iterable = (x for x in range(4)) exp = self.matobj([[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]]) res = self.matobj.from_iterable(iterable, lambda a, b: abs(b - a)) self.assertEqual(res, exp) def test_from_iterable_no_key_condensed(self): iterable = (x for x in range(4)) exp = self.matobj( [[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]], condensed=True ) res = self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), condensed=True ) self.assertEqual(res, exp) def test_from_iterable_validate_equal_valid_data(self): validate_true = self.matobj.from_iterable( (x for x in range(4)), lambda a, b: abs(b - a), validate=True ) validate_false = self.matobj.from_iterable( (x for x in range(4)), lambda a, b: abs(b - a), validate=False ) self.assertEqual(validate_true, validate_false) def test_from_iterable_validate_equal_valid_data_condensed(self): validate_true = self.matobj.from_iterable( (x for x in range(4)), lambda a, b: abs(b - a), validate=True, condensed=True, ) validate_false = self.matobj.from_iterable( (x for x in range(4)), lambda a, b: abs(b - a), validate=False, condensed=True, ) self.assertEqual(validate_true, validate_false) def test_from_iterable_validate_false(self): iterable = (x for x in range(4)) exp = self.matobj([[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]]) res = self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), validate=False ) self.assertEqual(res, exp) def test_from_iterable_validate_false_condensed(self): iterable = (x for x in range(4)) exp = self.matobj( [[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]], condensed=True ) res = self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), validate=False, condensed=True ) self.assertEqual(res, exp) def test_from_iterable_with_invalid_diagonal(self): iterable = (x for x in range(4)) with self.assertRaises(DistanceMatrixError) as e: self.matobj.from_iterable(iterable, lambda a, b: a * b, diagonal=1, validate=False) self.assertEqual( str(e.exception), "Data must be hollow (i.e., the diagonal can only contain zeros)." ) def test_from_iterable_with_valid_diagonal(self): iterable = (x for x in range(4)) exp = self.matobj( [[0, 1, 2, 3], [1, 0, 2, 3], [2, 2, 0, 3], [3, 3, 3, 0]] ) res = self.matobj.from_iterable(iterable, lambda a, b: a, diagonal=0, validate=False) self.assertTrue((res.data == exp.data).all()) def test_from_iterable_validate_non_hollow(self): iterable = (x for x in range(4)) with self.assertRaises(DistanceMatrixError) as e: self.matobj.from_iterable(iterable, lambda a, b: 1) self.assertEqual( str(e.exception), "Data must be hollow (i.e., the diagonal can only contain zeros).", ) def test_from_iterable_validate_non_hollow_condensed(self): iterable = (x for x in range(4)) with self.assertRaises(DistanceMatrixError) as e: self.matobj.from_iterable(iterable, lambda a, b: 1, condensed=True) self.assertEqual( str(e.exception), "Data must be hollow (i.e., the diagonal can only contain zeros).", ) def test_from_iterable_validate_false_non_symmetric(self): exp = self.matobj([[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]]) res = self.matobj.from_iterable( (x for x in range(4)), lambda a, b: a - b, validate=False ) self.assertEqual(res, exp) def test_from_iterable_validate_false_non_symmetric_condensed(self): exp = self.matobj( [[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]], condensed=True ) res = self.matobj.from_iterable( (x for x in range(4)), lambda a, b: a - b, validate=False, condensed=True ) self.assertEqual(res, exp) def test_from_iterable_validate_asym(self): iterable = (x for x in range(4)) with self.assertRaises(DistanceMatrixError): self.matobj.from_iterable(iterable, lambda a, b: b - a) def test_from_iterable_validate_asym_condensed(self): iterable = (x for x in range(4)) with self.assertRaises(DistanceMatrixError): self.matobj.from_iterable(iterable, lambda a, b: b - a, condensed=True) def test_from_iterable_with_key(self): iterable = (x for x in range(4)) exp = self.matobj( [[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]], ["0", "1", "4", "9"], ) res = self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), key=lambda x: str(x**2) ) self.assertEqual(res, exp) def test_from_iterable_with_key_condensed(self): iterable = (x for x in range(4)) exp = self.matobj( [[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]], ["0", "1", "4", "9"], condensed=True, ) res = self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), key=lambda x: str(x**2), condensed=True ) self.assertEqual(res, exp) def test_from_iterable_empty(self): with self.assertRaises(PairwiseMatrixError): self.matobj.from_iterable([], lambda x: x) def test_from_iterable_empty_condensed(self): with self.assertRaises(PairwiseMatrixError): self.matobj.from_iterable([], lambda x: x, condensed=True) def test_from_iterable_single(self): exp = self.matobj([[0]]) res = self.matobj.from_iterable(["boo"], lambda a, b: 0) self.assertEqual(res, exp) def test_from_iterable_single_condensed(self): exp = self.matobj([[0]], condensed=True) res = self.matobj.from_iterable(["boo"], lambda a, b: 0, condensed=True) self.assertEqual(res, exp) def test_from_iterable_with_keys(self): iterable = (x for x in range(4)) exp = self.matobj( [[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]], ["0", "1", "4", "9"], ) res = self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), keys=iter(["0", "1", "4", "9"]) ) self.assertEqual(res, exp) def test_from_iterable_with_keys_condensed(self): iterable = (x for x in range(4)) exp = self.matobj( [[0, 1, 2, 3], [1, 0, 1, 2], [2, 1, 0, 1], [3, 2, 1, 0]], ["0", "1", "4", "9"], condensed=True, ) res = self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), keys=iter(["0", "1", "4", "9"]), condensed=True, ) self.assertEqual(res, exp) def test_from_iterable_with_key_and_keys(self): iterable = (x for x in range(4)) with self.assertRaises(ValueError): self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), key=str, keys=["1", "2", "3", "4"] ) iterable = (x for x in range(4)) with self.assertRaises(ValueError): self.matobj.from_iterable( iterable, lambda a, b: abs(b - a), key=str, keys=["1", "2", "3", "4"], condensed=True, ) def test_from_iterable_scipy_hamming_metric_with_metadata(self): # test for #1254 seqs = [ Sequence("ACGT"), Sequence("ACGA", metadata={"id": "seq1"}), Sequence("AAAA", metadata={"id": "seq2"}), Sequence("AAAA", positional_metadata={"qual": range(4)}), ] exp = self.matobj( [ [0, 0.25, 0.75, 0.75], [0.25, 0.0, 0.5, 0.5], [0.75, 0.5, 0.0, 0.0], [0.75, 0.5, 0.0, 0.0], ], ["a", "b", "c", "d"], ) dm = self.matobj.from_iterable( seqs, metric=scipy.spatial.distance.hamming, keys=["a", "b", "c", "d"] ) self.assertEqual(dm, exp) def test_from_iterable_scipy_hamming_metric_with_metadata_condensed(self): # test for #1254 seqs = [ Sequence("ACGT"), Sequence("ACGA", metadata={"id": "seq1"}), Sequence("AAAA", metadata={"id": "seq2"}), Sequence("AAAA", positional_metadata={"qual": range(4)}), ] exp = self.matobj( [ [0, 0.25, 0.75, 0.75], [0.25, 0.0, 0.5, 0.5], [0.75, 0.5, 0.0, 0.0], [0.75, 0.5, 0.0, 0.0], ], ["a", "b", "c", "d"], condensed=True, ) dm = self.matobj.from_iterable( seqs, metric=scipy.spatial.distance.hamming, keys=["a", "b", "c", "d"], condensed=True, ) self.assertEqual(dm, exp) def test_from_iterable_skbio_hamming_metric_with_metadata(self): # test for #1254 seqs = [ Sequence("ACGT"), Sequence("ACGA", metadata={"id": "seq1"}), Sequence("AAAA", metadata={"id": "seq2"}), Sequence("AAAA", positional_metadata={"qual": range(4)}), ] exp = self.matobj( [ [0, 0.25, 0.75, 0.75], [0.25, 0.0, 0.5, 0.5], [0.75, 0.5, 0.0, 0.0], [0.75, 0.5, 0.0, 0.0], ], ["a", "b", "c", "d"], ) dm = self.matobj.from_iterable( seqs, metric=skbio.sequence.distance.hamming, keys=["a", "b", "c", "d"] ) self.assertEqual(dm, exp) def test_from_iterable_skbio_hamming_metric_with_metadata_condensed(self): # test for #1254 seqs = [ Sequence("ACGT"), Sequence("ACGA", metadata={"id": "seq1"}), Sequence("AAAA", metadata={"id": "seq2"}), Sequence("AAAA", positional_metadata={"qual": range(4)}), ] exp = self.matobj( [ [0, 0.25, 0.75, 0.75], [0.25, 0.0, 0.5, 0.5], [0.75, 0.5, 0.0, 0.0], [0.75, 0.5, 0.0, 0.0], ], ["a", "b", "c", "d"], condensed=True, ) dm = self.matobj.from_iterable( seqs, metric=skbio.sequence.distance.hamming, keys=["a", "b", "c", "d"], condensed=True, ) self.assertEqual(dm, exp) def test_condensed_form(self): for dm, condensed in zip(self.dms, self.dm_condensed_forms): obs = dm.condensed_form() self.assertTrue(np.array_equal(obs, condensed)) def test_permute_condensed(self): # Can't really permute a 1x1 or 2x2... for _ in range(2): obs = self.dm_1x1.permute(condensed=True) npt.assert_equal(obs, np.array([])) for _ in range(2): obs = self.dm_2x2.permute(condensed=True) npt.assert_equal(obs, np.array([0.123])) dm_copy = self.dm_3x3.copy() obs = self.dm_3x3.permute(condensed=True, seed=3) npt.assert_equal(obs, np.array([12.0, 4.2, 0.01])) obs = self.dm_3x3.permute(condensed=True, seed=2) npt.assert_equal(obs, np.array([4.2, 12.0, 0.01])) # Ensure dm hasn't changed after calling permute() on it a couple of # times. self.assertEqual(self.dm_3x3, dm_copy) def test_permute_condensed_on_condensed(self): # Can't really permute a 1x1 or 2x2... for _ in range(2): obs = self.dm_1x1_cond.permute(condensed=True) npt.assert_equal(obs, np.array([])) for _ in range(2): obs = self.dm_2x2_cond.permute(condensed=True) npt.assert_equal(obs, np.array([0.123])) dm_copy = self.dm_3x3_cond.copy() obs = self.dm_3x3_cond.permute(condensed=True, seed=3) npt.assert_equal(obs, np.array([12.0, 4.2, 0.01])) obs = self.dm_3x3_cond.permute(condensed=True, seed=2) npt.assert_equal(obs, np.array([4.2, 12.0, 0.01])) # Ensure dm hasn't changed after calling permute() on it a couple of # times. self.assertEqual(self.dm_3x3_cond, dm_copy) def test_permute_not_condensed(self): obs = self.dm_1x1.permute() self.assertEqual(obs, self.dm_1x1) self.assertFalse(obs is self.dm_1x1) obs = self.dm_2x2.permute() self.assertEqual(obs, self.dm_2x2) self.assertFalse(obs is self.dm_2x2) exp = self.matobj( [[0, 12, 4.2], [12, 0, 0.01], [4.2, 0.01, 0]], self.dm_3x3.ids ) obs = self.dm_3x3.permute(seed=3) self.assertEqual(obs, exp) exp = self.matobj( [[0, 4.2, 12], [4.2, 0, 0.01], [12, 0.01, 0]], self.dm_3x3.ids ) obs = self.dm_3x3.permute(seed=2) self.assertEqual(obs, exp) def test_permute_not_condensed_on_condensed(self): obs = self.dm_1x1_cond.permute() self.assertEqual(obs, self.dm_1x1_cond) self.assertFalse(obs is self.dm_1x1_cond) obs = self.dm_2x2_cond.permute() self.assertEqual(obs, self.dm_2x2_cond) self.assertFalse(obs is self.dm_2x2_cond) exp = self.matobj( [[0, 12, 4.2], [12, 0, 0.01], [4.2, 0.01, 0]], self.dm_3x3_cond.ids, condensed=True, ) obs = self.dm_3x3_cond.permute(seed=3) self.assertEqual(obs, exp) exp = self.matobj( [[0, 4.2, 12], [4.2, 0, 0.01], [12, 0.01, 0]], self.dm_3x3_cond.ids, condensed=True, ) obs = self.dm_3x3_cond.permute(seed=2) self.assertEqual(obs, exp) # TODO: need to test this with SymmetricMatrix vs DistanceMatrix for condensed form def test_eq(self): # Compare DistanceMatrix to PairwiseMatrix, where both have the # same data and IDs. eq_dm = PairwiseMatrix(self.dm_3x3_data, ["a", "b", "c"]) self.assertTrue(self.dm_3x3 == eq_dm) self.assertTrue(eq_dm == self.dm_3x3) def test_to_series_1x1(self): series = self.dm_1x1.to_series() exp = pd.Series([], index=[], dtype="float64") assert_series_almost_equal(series, exp) def test_to_series_1x1_condensed(self): series = self.dm_1x1_cond.to_series() exp = pd.Series([], index=[], dtype="float64") assert_series_almost_equal(series, exp) def test_to_series_2x2(self): series = self.dm_2x2.to_series() exp = pd.Series([0.123], index=pd.Index([("a", "b")])) assert_series_almost_equal(series, exp) def test_to_series_2x2_condensed(self): series = self.dm_2x2_cond.to_series() exp = pd.Series([0.123], index=pd.Index([("a", "b")])) assert_series_almost_equal(series, exp) def test_to_series_4x4(self): dm = self.matobj( [ [0.0, 0.2, 0.3, 0.4], [0.2, 0.0, 0.5, 0.6], [0.3, 0.5, 0.0, 0.7], [0.4, 0.6, 0.7, 0.0], ], ["a", "b", "c", "d"], ) series = dm.to_series() exp = pd.Series( [0.2, 0.3, 0.4, 0.5, 0.6, 0.7], index=pd.Index( [("a", "b"), ("a", "c"), ("a", "d"), ("b", "c"), ("b", "d"), ("c", "d")] ), ) assert_series_almost_equal(series, exp) def test_to_series_4x4_condensed(self): dm = self.matobj( [ [0.0, 0.2, 0.3, 0.4], [0.2, 0.0, 0.5, 0.6], [0.3, 0.5, 0.0, 0.7], [0.4, 0.6, 0.7, 0.0], ], ["a", "b", "c", "d"], condensed=True, ) series = dm.to_series() exp = pd.Series( [0.2, 0.3, 0.4, 0.5, 0.6, 0.7], index=pd.Index( [("a", "b"), ("a", "c"), ("a", "d"), ("b", "c"), ("b", "d"), ("c", "d")] ), ) assert_series_almost_equal(series, exp) def test_to_series_default_ids(self): series = self.matobj(self.dm_2x2_data).to_series() exp = pd.Series([0.123], index=pd.Index([("0", "1")])) assert_series_almost_equal(series, exp) def test_to_series_default_ids_condensed(self): series = self.matobj(self.dm_2x2_data, condensed=True).to_series() exp = pd.Series([0.123], index=pd.Index([("0", "1")])) assert_series_almost_equal(series, exp) def test_validate_asym_shape(self): # first check it actually likes good matrices data_good = np.array([[0.0, 42.0], [42.0, 0.0]]) data_sym, data_hollow = is_symmetric_and_hollow(data_good) self.assertEqual(data_sym, True) del data_sym self.assertEqual(data_hollow, True) del data_hollow data_sym = skbio.stats.distance._utils.is_symmetric(data_good) self.assertEqual(data_sym, True) del data_sym data_hollow = skbio.stats.distance._utils.is_hollow(data_good) self.assertEqual(data_hollow, True) del data_hollow self.dm_3x3._validate_shape(data_good) self.dm_3x3_cond._validate_shape(data_good) del data_good # _validate_shap checks just the shape, not the content bad_data = np.array([[1.0, 2.0], [3.0, 4.0]]) data_sym, data_hollow = is_symmetric_and_hollow(bad_data) self.assertEqual(data_sym, False) del data_sym self.assertEqual(data_hollow, False) del data_hollow data_sym = skbio.stats.distance._utils.is_symmetric(bad_data) self.assertEqual(data_sym, False) del data_sym data_hollow = skbio.stats.distance._utils.is_hollow(bad_data) self.assertEqual(data_hollow, False) del data_hollow self.dm_3x3._validate_shape(bad_data) self.dm_3x3_cond._validate_shape(bad_data) del bad_data # re-try with partially bad data bad_data = np.array([[0.0, 2.0], [3.0, 0.0]]) data_sym, data_hollow = is_symmetric_and_hollow(bad_data) self.assertEqual(data_sym, False) del data_sym self.assertEqual(data_hollow, True) del data_hollow data_sym = skbio.stats.distance._utils.is_symmetric(bad_data) self.assertEqual(data_sym, False) del data_sym data_hollow = skbio.stats.distance._utils.is_hollow(bad_data) self.assertEqual(data_hollow, True) del data_hollow self.dm_3x3._validate_shape(bad_data) self.dm_3x3_cond._validate_shape(bad_data) del bad_data def test_rename(self): # Test successful renaming with a dictionary in strict mode (default) dm = DistanceMatrix([[0, 1], [1, 0]], ids=["a", "b"]) rename_dict = {"a": "x", "b": "y"} dm.rename(rename_dict) exp = ("x", "y") self.assertEqual(dm.ids, exp) # Test successful renaming with a function in strict mode (default) dm = DistanceMatrix([[0, 1], [1, 0]], ids=["a", "b"]) rename_func = lambda x: x + "_1" dm.rename(rename_func) exp = ("a_1", "b_1") self.assertEqual(dm.ids, exp) # Test renaming in non-strict mode where one ID is not included in the dictionary dm = DistanceMatrix([[0, 1], [1, 0]], ids=["a", "b"]) rename_dict = {"a": "x"} # 'b' will retain its original ID dm.rename(rename_dict, strict=False) exp = ("x", "b") self.assertEqual(dm.ids, exp) # Test that renaming with strict=True raises an error if not all IDs are included dm = DistanceMatrix([[0, 1], [1, 0]], ids=["a", "b"]) rename_dict = {"a": "x"} # Missing 'b' with self.assertRaises(ValueError): dm.rename(rename_dict, strict=True) def test_rename_condensed(self): # Test successful renaming with a dictionary in strict mode (default) dm = DistanceMatrix([[0, 1], [1, 0]], ids=["a", "b"], condensed=True) rename_dict = {"a": "x", "b": "y"} dm.rename(rename_dict) exp = ("x", "y") self.assertEqual(dm.ids, exp) # Test successful renaming with a function in strict mode (default) dm = DistanceMatrix([[0, 1], [1, 0]], ids=["a", "b"], condensed=True) rename_func = lambda x: x + "_1" dm.rename(rename_func) exp = ("a_1", "b_1") self.assertEqual(dm.ids, exp) # Test renaming in non-strict mode where one ID is not included in the dictionary dm = DistanceMatrix([[0, 1], [1, 0]], ids=["a", "b"], condensed=True) rename_dict = {"a": "x"} # 'b' will retain its original ID dm.rename(rename_dict, strict=False) exp = ("x", "b") self.assertEqual(dm.ids, exp) # Test that renaming with strict=True raises an error if not all IDs are included dm = DistanceMatrix([[0, 1], [1, 0]], ids=["a", "b"], condensed=True) rename_dict = {"a": "x"} # Missing 'b' with self.assertRaises(ValueError): dm.rename(rename_dict, strict=True) class RandomDistanceMatrixTests(TestCase): def test_default_usage(self): exp = DistanceMatrix(np.asarray([[0.0]]), ["1"]) obs = randdm(1) self.assertEqual(obs, exp) obs = randdm(2) self.assertEqual(obs.shape, (2, 2)) self.assertEqual(obs.ids, ("1", "2")) obs1 = randdm(5) num_trials = 10 found_diff = False for _ in range(num_trials): obs2 = randdm(5) if obs1 != obs2: found_diff = True break self.assertTrue(found_diff) def test_large_matrix_for_symmetry(self): obs3 = randdm(100) self.assertEqual(obs3, obs3.T) def test_ids(self): ids = ["foo", "bar", "baz"] obs = randdm(3, ids=ids) self.assertEqual(obs.shape, (3, 3)) self.assertEqual(obs.ids, tuple(ids)) def test_constructor(self): exp = PairwiseMatrix(np.asarray([[0.0]]), ["1"]) obs = randdm(1, constructor=PairwiseMatrix) self.assertEqual(obs, exp) self.assertEqual(type(obs), PairwiseMatrix) def test_random_fn(self): def myrand(size): # One dm to rule them all... data = np.empty(size) data.fill(42) return data exp = DistanceMatrix( np.asarray([[0, 42, 42], [42, 0, 42], [42, 42, 0]]), ["1", "2", "3"] ) obs = randdm(3, random_fn=myrand) self.assertEqual(obs, exp) def test_random_seed(self): obs = randdm(5, random_fn=42).data exp = np.array( [ [0.0, 0.97562235, 0.37079802, 0.22723872, 0.75808774], [0.97562235, 0.0, 0.92676499, 0.55458479, 0.35452597], [0.37079802, 0.92676499, 0.0, 0.06381726, 0.97069802], [0.22723872, 0.55458479, 0.06381726, 0.0, 0.89312112], [0.75808774, 0.35452597, 0.97069802, 0.89312112, 0.0], ] ) npt.assert_almost_equal(obs, exp) def test_invalid_input(self): # Invalid dimensions. with self.assertRaises(PairwiseMatrixError): randdm(0) # Invalid dimensions. with self.assertRaises(ValueError): randdm(-1) # Invalid number of IDs. with self.assertRaises(PairwiseMatrixError): randdm(2, ids=["foo"]) class CategoricalStatsHelperFunctionTests(TestCase): def setUp(self): self.dm = DistanceMatrix( [[0.0, 1.0, 2.0], [1.0, 0.0, 3.0], [2.0, 3.0, 0.0]], ["a", "b", "c"] ) self.grouping = [1, 2, 1] # Ordering of IDs shouldn't matter, nor should extra IDs. self.df = pd.read_csv( io.StringIO("ID,Group\nb,Group2\na,Group1\nc,Group1\nd,Group3"), index_col=0 ) self.df_missing_id = pd.read_csv( io.StringIO("ID,Group\nb,Group2\nc,Group1"), index_col=0 ) def test_preprocess_input_with_valid_input(self): # Should obtain same result using grouping vector or data frame. exp = ( 3, 2, np.array([0, 1, 0]), (np.array([0, 0, 1]), np.array([1, 2, 2])), np.array([1.0, 2.0, 3.0]), ) obs = _preprocess_input(self.dm, self.grouping, None) npt.assert_equal(obs, exp) obs = _preprocess_input(self.dm, self.df, "Group") npt.assert_equal(obs, exp) def test_preprocess_input_raises_error(self): # Requires a DistanceMatrix. with self.assertRaises(TypeError): _preprocess_input( PairwiseMatrix([[0, 2], [3, 0]], ["a", "b"]), [1, 2], None ) # Requires column if DataFrame. with self.assertRaises(ValueError): _preprocess_input(self.dm, self.df, None) # Cannot provide column if not data frame. with self.assertRaises(ValueError): _preprocess_input(self.dm, self.grouping, "Group") # Column must exist in data frame. with self.assertRaises(ValueError): _preprocess_input(self.dm, self.df, "foo") # All distance matrix IDs must be in data frame. with self.assertRaises(ValueError): _preprocess_input(self.dm, self.df_missing_id, "Group") # Grouping vector length must match number of objects in dm. with self.assertRaises(ValueError): _preprocess_input(self.dm, [1, 2], None) # Grouping vector cannot have only unique values. with self.assertRaises(ValueError): _preprocess_input(self.dm, [1, 2, 3], None) # Grouping vector cannot have only a single group. with self.assertRaises(ValueError): _preprocess_input(self.dm, [1, 1, 1], None) def test_run_monte_carlo_stats_with_permutations(self): obs = _run_monte_carlo_stats(lambda e: 42, self.grouping, 50) npt.assert_equal(obs, (42, 1.0)) def test_run_monte_carlo_stats_no_permutations(self): obs = _run_monte_carlo_stats(lambda e: 42, self.grouping, 0) npt.assert_equal(obs, (42, np.nan)) def test_run_monte_carlo_stats_invalid_permutations(self): with self.assertRaises(ValueError): _run_monte_carlo_stats(lambda e: 42, self.grouping, -1) class PairwiseMatrixTests(PairwiseMatrixTestBase, TestCase): @classmethod def get_matrix_class(cls): return PairwiseMatrix def setUp(self): super(PairwiseMatrixTests, self).setUp() class SymmetricMatrixTests(SymmetricMatrixTestBase, TestCase): @classmethod def get_matrix_class(cls): return SymmetricMatrix def setUp(self): super(SymmetricMatrixTests, self).setUp() class DistanceMatrixTests(DistanceMatrixTestBase, TestCase): @classmethod def get_matrix_class(cls): return DistanceMatrix def setUp(self): super(DistanceMatrixTests, self).setUp() if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/test_bioenv.py000066400000000000000000000266231520735541300264600ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import pandas as pd from skbio import DistanceMatrix from skbio.stats.distance import bioenv from skbio.stats.distance._bioenv import _scale from skbio.util import get_data_path, assert_data_frame_almost_equal from skbio.util._testing import _data_frame_to_default_int_type class BIOENVTests(TestCase): """Results were verified with R 3.0.2 and vegan 2.0-10 (vegan::bioenv).""" def setUp(self): # The test dataset used here is a subset of the Lauber et al. 2009 # "88 Soils" dataset. It has been altered to exercise various aspects # of the code, including (but not limited to): # # - order of distance matrix IDs and IDs in data frame (metadata) are # not exactly the same # - data frame has an extra sample that is not in the distance matrix # - this extra sample has non-numeric and missing values in some of its # cells # # Additional variations of the distance matrix and data frame are used # to test different orderings of rows/columns, extra non-numeric data # frame columns, etc. # # This dataset is also useful because it is non-trivial in size (6 # samples, 11 environment variables) and it includes positive/negative # floats and integers in the data frame. self.dm = DistanceMatrix.read(get_data_path('dm.txt')) # add condensed for testing self.dm_condensed = DistanceMatrix(self.dm, condensed=True) # Reordered rows and columns (i.e., different ID order). Still # conceptually the same distance matrix. self.dm_reordered = DistanceMatrix.read( get_data_path('dm_reordered.txt')) self.dm_reordered_condensed = DistanceMatrix(self.dm_reordered, condensed=True) self.df = pd.read_csv(get_data_path('df.txt'), sep='\t', index_col=0) # Similar to the above data frame, except that it has an extra # non-numeric column, and some of the other rows and columns have been # reordered. self.df_extra_column = pd.read_csv( get_data_path('df_extra_column.txt'), sep='\t', index_col=0) # All columns in the original data frame (these are all numeric # columns). self.cols = self.df.columns.tolist() # This second dataset is derived from vegan::bioenv's example dataset # (varespec and varechem). The original dataset includes a site x # species table (e.g., OTU table) and a data frame of environmental # variables. Since the bioenv function defined here accepts a distance # matrix, we use a Bray-Curtis distance matrix that is derived from the # site x species table (this matches what is done by vegan::bioenv when # provided an OTU table, using their default distance measure). The # data frame only includes the numeric environmental variables we're # interested in for these tests: log(N), P, K, Ca, pH, Al self.dm_vegan = DistanceMatrix.read( get_data_path('bioenv_dm_vegan.txt')) self.df_vegan = pd.read_csv( get_data_path('bioenv_df_vegan.txt'), sep='\t', converters={0: str}) self.df_vegan.set_index('#SampleID', inplace=True) # Load expected results. self.exp_results = pd.read_csv(get_data_path('exp_results.txt'), sep='\t', index_col=0) _data_frame_to_default_int_type(self.exp_results) self.exp_results_single_column = pd.read_csv( get_data_path('exp_results_single_column.txt'), sep='\t', index_col=0 ) _data_frame_to_default_int_type(self.exp_results_single_column) self.exp_results_different_column_order = pd.read_csv( get_data_path('exp_results_different_column_order.txt'), sep='\t', index_col=0 ) _data_frame_to_default_int_type(self.exp_results_different_column_order) self.exp_results_vegan = pd.read_csv( get_data_path('bioenv_exp_results_vegan.txt'), sep='\t', index_col=0 ) _data_frame_to_default_int_type(self.exp_results_vegan) def test_bioenv_all_columns_implicit(self): # Test with all columns in data frame (implicitly). obs = bioenv(self.dm, self.df) assert_data_frame_almost_equal(obs, self.exp_results) # Should get the same results if order of rows/cols in distance matrix # is changed. obs = bioenv(self.dm_reordered, self.df) assert_data_frame_almost_equal(obs, self.exp_results) def test_bioenv_all_columns_implicit_condensed(self): # Test with all columns in data frame (implicitly). obs = bioenv(self.dm_condensed, self.df) assert_data_frame_almost_equal(obs, self.exp_results) # Should get the same results if order of rows/cols in distance matrix # is changed. obs = bioenv(self.dm_reordered_condensed, self.df) assert_data_frame_almost_equal(obs, self.exp_results) def test_bioenv_all_columns_explicit(self): # Test with all columns being specified. obs = bioenv(self.dm, self.df, columns=self.cols) assert_data_frame_almost_equal(obs, self.exp_results) # Test against a data frame that has an extra non-numeric column and # some of the rows and columns reordered (we should get the same # result since we're specifying the same columns in the same order). obs = bioenv(self.dm, self.df_extra_column, columns=self.cols) assert_data_frame_almost_equal(obs, self.exp_results) def test_bioenv_all_columns_explicit_condensed(self): # Test with all columns being specified. obs = bioenv(self.dm_condensed, self.df, columns=self.cols) assert_data_frame_almost_equal(obs, self.exp_results) # Test against a data frame that has an extra non-numeric column and # some of the rows and columns reordered (we should get the same # result since we're specifying the same columns in the same order). obs = bioenv(self.dm_condensed, self.df_extra_column, columns=self.cols) assert_data_frame_almost_equal(obs, self.exp_results) def test_bioenv_single_column(self): obs = bioenv(self.dm, self.df, columns=['PH']) assert_data_frame_almost_equal(obs, self.exp_results_single_column) def test_bioenv_different_column_order(self): # Specifying columns in a different order will change the row labels in # the results data frame as the column subsets will be reordered, but # the actual results (e.g., correlation coefficients) shouldn't change. obs = bioenv(self.dm, self.df, columns=self.cols[::-1]) assert_data_frame_almost_equal( obs, self.exp_results_different_column_order) def test_bioenv_no_side_effects(self): # Deep copies of both primary inputs. dm_copy = self.dm.copy() df_copy = self.df.copy(deep=True) bioenv(self.dm, self.df) # Make sure we haven't modified the primary input in some way (e.g., # with scaling, type conversions, etc.). self.assertEqual(self.dm, dm_copy) assert_data_frame_almost_equal(self.df, df_copy) def test_bioenv_vegan_example(self): # The correlation coefficient in the first row of the # results (rho=0.2516) is different from the correlation coefficient # computed by vegan (rho=0.2513). This seems to occur due to # differences in numerical precision when calculating the Euclidean # distances, which affects the rank calculations in Spearman # (specifically, dealing with ties). The ranked distances end up being # slightly different between vegan and our implementation because some # distances are treated as ties in vegan but treated as distinct values # in our implementation. This explains the difference in rho values. I # verified that using Pearson correlation instead of Spearman on the # same distances yields *very* similar results. Thus, the discrepancy # seems to stem from differences when computing ranks/ties. obs = bioenv(self.dm_vegan, self.df_vegan) assert_data_frame_almost_equal( obs, self.exp_results_vegan, rtol=1e-3 ) def test_bioenv_no_distance_matrix(self): with self.assertRaises(TypeError): bioenv('breh', self.df) def test_bioenv_no_data_frame(self): with self.assertRaises(TypeError): bioenv(self.dm, None) def test_bioenv_duplicate_columns(self): with self.assertRaises(ValueError): bioenv(self.dm, self.df, columns=self.cols + ['PH']) def test_bioenv_no_columns(self): with self.assertRaises(ValueError): bioenv(self.dm, self.df, columns=[]) def test_bioenv_missing_columns(self): with self.assertRaises(ValueError): bioenv(self.dm, self.df, columns=self.cols + ['brofist']) def test_bioenv_missing_distance_matrix_ids(self): df = self.df[1:] with self.assertRaises(ValueError): bioenv(self.dm, df) def test_bioenv_nans(self): df = self.df.replace(53.9, np.nan) with self.assertRaises(ValueError): bioenv(self.dm, df) def test_bioenv_nonnumeric_columns(self): df = self.df.replace(2400, 'no cog yay') with self.assertRaises(TypeError): bioenv(self.dm, df) with self.assertRaises(TypeError): bioenv(self.dm, self.df_extra_column) def test_scale_single_column(self): df = pd.DataFrame([[1], [0], [2]], index=['A', 'B', 'C'], columns=['foo']) exp = pd.DataFrame([[0.0], [-1.0], [1.0]], index=['A', 'B', 'C'], columns=['foo']) obs = _scale(df) assert_data_frame_almost_equal(obs, exp) def test_scale_multiple_columns(self): # Floats and ints, including positives and negatives. df = pd.DataFrame([[7.0, 400, -1], [8.0, 530, -5], [7.5, 450, 1], [8.5, 810, -4]], index=['A', 'B', 'C', 'D'], columns=['pH', 'Elevation', 'negatives']) exp = pd.DataFrame([[-1.161895, -0.805979, 0.453921], [0.387298, -0.095625, -0.998625], [-0.387298, -0.532766, 1.180194], [1.161895, 1.434369, -0.635489]], index=['A', 'B', 'C', 'D'], columns=['pH', 'Elevation', 'negatives']) obs = _scale(df) assert_data_frame_almost_equal(obs, exp) def test_scale_no_variance(self): df = pd.DataFrame([[-7.0, -1.2], [6.2, -1.2], [2.9, -1.2]], index=['A', 'B', 'C'], columns=['foo', 'bar']) with self.assertRaises(ValueError): _scale(df) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/test_mantel.py000066400000000000000000001314071520735541300264530ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt import pandas as pd import scipy from scipy.spatial.distance import squareform from scipy.stats import pearsonr, spearmanr, ConstantInputWarning, NearConstantInputWarning from skbio import DistanceMatrix from skbio.stats.distance import (PairwiseMatrixError, DistanceMatrixError, mantel, pwmantel) from skbio.stats.distance._mantel import _order_dms from skbio.stats.distance._mantel import _mantel_stats_pearson from skbio.stats.distance._mantel import _mantel_stats_spearman from skbio.stats.distance._cutils import mantel_perm_pearsonr_cy from skbio.stats.distance._utils import distmat_reorder_condensed from skbio.util import get_data_path, assert_data_frame_almost_equal from skbio.util._testing import _data_frame_to_default_int_type class MantelTestData(TestCase): def setUp(self): # Small dataset of minimal size (3x3). Mix of floats and ints in a # native Python nested list structure. self.minx = [[0, 1, 2], [1, 0, 3], [2, 3, 0]] self.miny = [[0, 2, 7], [2, 0, 6], [7, 6, 0]] self.minz = [[0, 0.5, 0.25], [0.5, 0, 0.1], [0.25, 0.1, 0]] # Version of the above dataset stored as DistanceMatrix instances. self.minx_dm = DistanceMatrix(self.minx) self.miny_dm = DistanceMatrix(self.miny) self.minz_dm = DistanceMatrix(self.minz) # Condensed data self.minx_cond = DistanceMatrix(self.minx, condensed=True) self.miny_cond = DistanceMatrix(self.miny, condensed=True) self.minz_cond = DistanceMatrix(self.minz, condensed=True) # Versions of self.minx_dm and self.minz_dm that each have an extra ID # on the end. self.minx_dm_extra = DistanceMatrix([[0, 1, 2, 7], [1, 0, 3, 2], [2, 3, 0, 4], [7, 2, 4, 0]], ['0', '1', '2', 'foo']) self.minz_dm_extra = DistanceMatrix([[0, 0.5, 0.25, 3], [0.5, 0, 0.1, 24], [0.25, 0.1, 0, 5], [3, 24, 5, 0]], ['0', '1', '2', 'bar']) class InternalMantelTests(MantelTestData): def setUp(self): super(InternalMantelTests, self).setUp() def _compute_perf_one(self, x_data, order, xmean, normxm, ym_normalized): x_flat = distmat_reorder_condensed(x_data, order) xm_normalized = (x_flat - xmean)/normxm one_stat = np.dot(xm_normalized, ym_normalized) one_stat = max(min(one_stat, 1.0), -1.0) return one_stat def test_perm_pearsonr3(self): # data pre-computed using released code x_data = np.asarray([[0., 1., 3.], [1., 0., 2.], [3., 2., 0.]]) perm_order = np.asarray([[2, 1, 0], [2, 0, 1], [0, 2, 1], [2, 0, 1]], dtype=np.intp) xmean = 2.0 normxm = 1.4142135623730951 ym_normalized = np.asarray([-0.80178373, 0.26726124, 0.53452248]) permuted_stats = np.empty(len(perm_order), dtype=x_data.dtype) mantel_perm_pearsonr_cy(x_data, perm_order, xmean, normxm, ym_normalized, permuted_stats) for i in range(len(perm_order)): exp_res = self._compute_perf_one(x_data, perm_order[i, :], xmean, normxm, ym_normalized) self.assertAlmostEqual(permuted_stats[i], exp_res) def test_perm_pearsonr6(self): # data pre-computed using released code x_data = np.asarray([[0., 0.62381864, 0.75001543, 0.58520119, 0.72902358, 0.65213559], [0.62381864, 0., 0.97488122, 0.6498224, 0.73720314, 0.62950732], [0.75001543, 0.97488122, 0., 0.68884542, 0.65747031, 0.72170752], [0.58520119, 0.6498224, 0.68884542, 0., 0.65885358, 0.66122362], [0.72902358, 0.73720314, 0.65747031, 0.65885358, 0., 0.71117341], [0.65213559, 0.62950732, 0.72170752, 0.66122362, 0.71117341, 0.]]) perm_order = np.asarray([[0, 2, 3, 4, 1, 5], [4, 3, 2, 5, 0, 1], [2, 5, 3, 1, 0, 4], [3, 5, 4, 1, 2, 0], [4, 3, 5, 2, 0, 1]], dtype=np.intp) xmean = 0.6953921578226 normxm = 0.3383126690576294 ym_normalized = np.asarray([-0.4999711, 0.24980825, -0.29650504, 0.18022614, -0.17407781, 0.33223145, -0.08230374, 0.33992794, -0.14964257, 0.04340053, -0.35527798, 0.15597541, -0.0523679, -0.04451187, 0.35308828]) permuted_stats = np.empty(len(perm_order), dtype=x_data.dtype) mantel_perm_pearsonr_cy(x_data, perm_order, xmean, normxm, ym_normalized, permuted_stats) for i in range(len(perm_order)): exp_res = self._compute_perf_one(x_data, perm_order[i, :], xmean, normxm, ym_normalized) self.assertAlmostEqual(permuted_stats[i], exp_res) def test_perm_pearsonr_full(self): x = DistanceMatrix.read(get_data_path('dm2.txt')) y = DistanceMatrix.read(get_data_path('dm3.txt')) x_data = x._data y_data = y._data x_flat = squareform(x_data, force='tovector', checks=False) y_flat = squareform(y_data, force='tovector', checks=False) xmean = x_flat.mean() ymean = y_flat.mean() xm = x_flat - xmean ym = y_flat - ymean normxm_la = scipy.linalg.norm(xm) normym_la = scipy.linalg.norm(ym) normxm = np.linalg.norm(xm) normym = np.linalg.norm(ym) self.assertAlmostEqual(normxm, normxm_la) self.assertAlmostEqual(normym, normym_la) perm_order = np.asarray([[0, 2, 3, 4, 1, 5], [4, 3, 2, 5, 0, 1], [2, 5, 3, 1, 0, 4], [3, 5, 4, 1, 2, 0], [4, 3, 5, 2, 0, 1], [4, 5, 1, 2, 0, 3], [3, 5, 1, 0, 4, 2], [4, 5, 3, 1, 2, 0], [2, 1, 5, 4, 0, 3], [4, 1, 0, 5, 2, 3], [1, 2, 5, 4, 0, 3], [5, 4, 0, 1, 3, 2], [3, 0, 1, 5, 4, 2], [5, 0, 2, 3, 1, 4]], dtype=np.intp) ym_normalized = ym/normym permuted_stats = np.empty(len(perm_order), dtype=x_data.dtype) mantel_perm_pearsonr_cy(x_data, perm_order, xmean, normxm, ym_normalized, permuted_stats) for i in range(len(perm_order)): exp_res = self._compute_perf_one(x_data, perm_order[i, :], xmean, normxm, ym_normalized) self.assertAlmostEqual(permuted_stats[i], exp_res) def test_pearsonr_full(self): """ Compare the optimized version of pearson mantel with the naive loop implementation """ x = DistanceMatrix.read(get_data_path('dm2.txt')) y = DistanceMatrix.read(get_data_path('dm3.txt')) num_perms = 12 rng = np.random.default_rng(0) orig_stat_fast, comp_stat, permuted_stats_fast = \ _mantel_stats_pearson(x, y, num_perms, seed=rng) # compute the traditional way rng = np.random.default_rng(0) x_flat = x.condensed_form() y_flat = y.condensed_form() orig_stat = pearsonr(x_flat, y_flat)[0] perm_gen = (pearsonr(x.permute(condensed=True, seed=rng), y_flat)[0] for _ in range(num_perms)) permuted_stats = np.fromiter(perm_gen, float, count=num_perms) self.assertAlmostEqual(orig_stat_fast, orig_stat) for i in range(num_perms): self.assertAlmostEqual(permuted_stats_fast[i], permuted_stats[i]) def test_spearmanr_full(self): """ Compare the optimized version of spearman mantel with the naive loop implementation """ x = DistanceMatrix.read(get_data_path('dm2.txt')) y = DistanceMatrix.read(get_data_path('dm3.txt')) num_perms = 12 rng = np.random.default_rng(0) orig_stat_fast, comp_stat, permuted_stats_fast = \ _mantel_stats_spearman(x, y, num_perms, seed=rng) # compute the traditional way rng = np.random.default_rng(0) x_flat = x.condensed_form() y_flat = y.condensed_form() orig_stat = spearmanr(x_flat, y_flat)[0] perm_gen = (spearmanr(x.permute(condensed=True, seed=rng), y_flat)[0] for _ in range(num_perms)) permuted_stats = np.fromiter(perm_gen, float, count=num_perms) self.assertAlmostEqual(orig_stat_fast, orig_stat) for i in range(num_perms): self.assertAlmostEqual(permuted_stats_fast[i], permuted_stats[i]) class MantelTests(MantelTestData): """Results were verified with R 3.1.0 and vegan 2.0-10 (vegan::mantel). vegan::mantel performs a one-sided (greater) test and does not have the option to specify different alternative hypotheses. In order to test the other alternative hypotheses, I modified vegan::mantel to perform the appropriate test, source()'d the file and verified the output. """ def setUp(self): super(MantelTests, self).setUp() self.methods = ('pearson', 'spearman', 'kendalltau') self.alternatives = ('two-sided', 'greater', 'less') # No variation in distances. Taken from Figure 10.20(b), pg. 603 in L&L # 3rd edition. Their example is 4x4 but using 3x3 here for easy # comparison to the minimal dataset above. self.no_variation = [[0, 0.667, 0.667], [0.667, 0, 0.667], [0.667, 0.667, 0]] # This second dataset is derived from vegan::mantel's example dataset. # The "veg" distance matrix contains Bray-Curtis distances derived from # the varespec data (named "veg.dist" in the example). The "env" # distance matrix contains Euclidean distances derived from scaled # varechem data (named "env.dist" in the example). self.veg_dm_vegan = np.loadtxt( get_data_path('mantel_veg_dm_vegan.txt')) self.env_dm_vegan = np.loadtxt( get_data_path('mantel_env_dm_vegan.txt')) # Expected test statistic when comparing x and y with method='pearson'. self.exp_x_vs_y = 0.7559289 # Expected test statistic when comparing x and z with method='pearson'. self.exp_x_vs_z = -0.9897433 def assert_mantel_almost_equal(self, left, right): # p-value is a count based on comparing two real value # it is thus very sensitive to minor rounding errors # When counts are rare, that may make huge proportional error # se we have to keep that number high for proper "almost" comparison self.assertAlmostEqual(left[0], right[0]) npt.assert_almost_equal(left[1] + 0.5, right[1] + 0.5, decimal=2) self.assertEqual(left[2], right[2]) def test_statistic_same_across_alternatives_and_permutations(self): # Varying permutations and alternative hypotheses shouldn't affect the # computed test statistics. for n in (0, 99, 999): for alt in self.alternatives: for method, exp in (('pearson', self.exp_x_vs_y), ('spearman', 0.5), ('kendalltau', 0.33333333333333337)): obs = mantel(self.minx, self.miny, method=method, permutations=n, alternative=alt)[0] self.assertAlmostEqual(obs, exp) def test_comparing_same_matrices(self): for method in self.methods: obs = mantel(self.minx, self.minx, method=method)[0] self.assertAlmostEqual(obs, 1) obs = mantel(self.miny, self.miny, method=method)[0] self.assertAlmostEqual(obs, 1) def test_negative_correlation(self): for method, exp in (('pearson', self.exp_x_vs_z), ('spearman', -1)): obs = mantel(self.minx, self.minz, method=method)[0] self.assertAlmostEqual(obs, exp) def test_zero_permutations(self): for alt in self.alternatives: for method, exp in (('pearson', self.exp_x_vs_y), ('spearman', 0.5), ('kendalltau', 0.33333333333333337)): obs = mantel(self.minx, self.miny, permutations=0, method=method, alternative=alt) self.assertAlmostEqual(obs[0], exp) npt.assert_equal(obs[1], np.nan) self.assertEqual(obs[2], 3) # swapping order of matrices should give same result obs = mantel(self.miny, self.minx, permutations=0, method=method, alternative=alt) self.assertAlmostEqual(obs[0], exp) npt.assert_equal(obs[1], np.nan) self.assertEqual(obs[2], 3) def test_distance_matrix_instances_as_input(self): # Matrices with all matching IDs in the same order. obs = mantel(self.minx_dm, self.miny_dm, alternative='less', seed=0) self.assert_mantel_almost_equal(obs, [self.exp_x_vs_y, 0.843, 3]) def test_distance_matrix_instances_with_reordering_and_nonmatching(self): x = self.minx_dm_extra.filter(['1', '0', 'foo', '2']) y = self.miny_dm.filter(['0', '2', '1']) # strict=True should disallow IDs that aren't found in both matrices with self.assertRaises(ValueError): mantel(x, y, alternative='less', strict=True) # strict=False should ignore IDs that aren't found in both matrices obs = mantel(x, y, alternative='less', strict=False, seed=0) self.assert_mantel_almost_equal(obs, [self.exp_x_vs_y, 0.843, 3]) def test_distance_matrix_instances_with_lookup(self): self.minx_dm.ids = ('a', 'b', 'c') self.miny_dm.ids = ('d', 'e', 'f') lookup = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'A', 'e': 'B', 'f': 'C'} obs = mantel(self.minx_dm, self.miny_dm, alternative='less', lookup=lookup, seed=0) self.assert_mantel_almost_equal(obs, [self.exp_x_vs_y, 0.843, 3]) def test_one_sided_greater(self): obs = mantel(self.minx, self.miny, alternative='greater', seed=0) self.assertAlmostEqual(obs[0], self.exp_x_vs_y) self.assertAlmostEqual(obs[1], 0.319) self.assertEqual(obs[2], 3) obs = mantel(self.minx, self.minx, alternative='greater', seed=0) self.assert_mantel_almost_equal(obs, [1, 0.172, 3]) def test_one_sided_less(self): # no need to seed here as permuted test statistics will all be less # than or equal to the observed test statistic (1.0) for method in self.methods: obs = mantel(self.minx, self.minx, method=method, alternative='less') npt.assert_almost_equal(obs, (1, 1, 3)) obs = mantel(self.minx, self.miny, alternative='less', seed=0) self.assert_mantel_almost_equal(obs, [self.exp_x_vs_y, 0.843, 3]) obs = mantel(self.minx, self.minz, alternative='less', seed=0) self.assert_mantel_almost_equal(obs, [self.exp_x_vs_z, 0.172, 3]) def test_two_sided(self): obs = mantel(self.minx, self.minx, method='spearman', alternative='two-sided', seed=0) self.assert_mantel_almost_equal(obs, [1.0, 0.347, 3]) obs = mantel(self.minx, self.miny, method='spearman', alternative='two-sided', seed=0) self.assert_mantel_almost_equal(obs, [0.5, 1.0, 3]) obs = mantel(self.minx, self.minz, method='spearman', alternative='two-sided', seed=0) self.assert_mantel_almost_equal(obs, [-1, 0.347, 3]) def test_vegan_example(self): # pearson obs = mantel(self.veg_dm_vegan, self.env_dm_vegan, alternative='greater', seed=0) self.assert_mantel_almost_equal(obs, [0.3047454, 0.002, 24]) # spearman obs = mantel(self.veg_dm_vegan, self.env_dm_vegan, alternative='greater', method='spearman', seed=0) self.assert_mantel_almost_equal(obs, [0.283791, 0.003, 24]) def test_no_variation_pearson(self): exp = (np.nan, np.nan, 3) for alt in self.alternatives: # test one or both inputs having no variation in their # distances for x, y in ( (self.miny, self.no_variation), (self.no_variation, self.miny), (self.no_variation, self.no_variation), ): with self.assertWarns(ConstantInputWarning): obs = mantel(x, y, method='pearson', alternative=alt) npt.assert_equal(obs, exp) def test_no_variation_spearman(self): exp = (np.nan, np.nan, 3) for alt in self.alternatives: for x, y in ( (self.miny, self.no_variation), (self.no_variation, self.miny), (self.no_variation, self.no_variation), ): with self.assertWarns(ConstantInputWarning): obs = mantel(x, y, method='spearman', alternative=alt) npt.assert_equal(obs, exp) def test_no_side_effects(self): minx = np.asarray(self.minx, dtype='float') miny = np.asarray(self.miny, dtype='float') minx_copy = np.copy(minx) miny_copy = np.copy(miny) mantel(minx, miny) # Make sure we haven't modified the input. npt.assert_equal(minx, minx_copy) npt.assert_equal(miny, miny_copy) def test_near_constant(self): noise = 1e-15 mat = np.array(self.no_variation) mat[0, 1] += noise mat[1, 0] += noise with self.assertWarns(NearConstantInputWarning) as context: mantel(mat, mat, method="pearson") def test_fortran_matrix(self): mat = np.asfortranarray(self.minx) obs = mantel(mat, mat, method="pearson")[0] self.assertAlmostEqual(obs, 1) def test_invalid_distance_matrix(self): # Single asymmetric, non-hollow distance matrix. with self.assertRaises(PairwiseMatrixError): mantel([[1, 2], [3, 4]], [[0, 0], [0, 0]]) # Two asymmetric distance matrices. with self.assertRaises(DistanceMatrixError): mantel([[0, 2], [3, 0]], [[0, 1], [0, 0]]) def test_invalid_input(self): # invalid correlation method with self.assertRaises(ValueError): mantel([[1]], [[1]], method='brofist') # invalid permutations with self.assertRaises(ValueError): mantel([[1]], [[1]], permutations=-1) # invalid alternative with self.assertRaises(ValueError): mantel([[1]], [[1]], alternative='no cog yay') # too small dms with self.assertRaises(ValueError): mantel([[0, 3], [3, 0]], [[0, 2], [2, 0]]) class PairwiseMantelTests(MantelTestData): def setUp(self): super(PairwiseMantelTests, self).setUp() self.min_dms = (self.minx_dm, self.miny_dm, self.minz_dm) self.exp_results_minimal = pd.read_csv( get_data_path('pwmantel_exp_results_minimal.txt'), sep='\t', index_col=(0, 1) ) _data_frame_to_default_int_type(self.exp_results_minimal) self.exp_results_minimal_with_labels = pd.read_csv( get_data_path('pwmantel_exp_results_minimal_with_labels.txt'), sep='\t', index_col=(0, 1) ) _data_frame_to_default_int_type(self.exp_results_minimal_with_labels) self.exp_results_duplicate_dms = pd.read_csv( get_data_path('pwmantel_exp_results_duplicate_dms.txt'), sep='\t', index_col=(0, 1) ) _data_frame_to_default_int_type(self.exp_results_duplicate_dms) self.exp_results_na_p_value = pd.read_csv( get_data_path('pwmantel_exp_results_na_p_value.txt'), sep='\t', index_col=(0, 1) ) _data_frame_to_default_int_type(self.exp_results_na_p_value) self.exp_results_reordered_distance_matrices = pd.read_csv( get_data_path('pwmantel_exp_results_reordered_distance_matrices.txt'), sep='\t', index_col=(0, 1) ) _data_frame_to_default_int_type(self.exp_results_reordered_distance_matrices) self.exp_results_dm_dm2 = pd.read_csv( get_data_path('pwmantel_exp_results_dm_dm2.txt'), sep='\t', index_col=(0, 1)) self.exp_results_all_dms = pd.read_csv( get_data_path('pwmantel_exp_results_all_dms.txt'), sep='\t', index_col=(0, 1)) def assert_pwmantel_almost_equal(self, left, right): # p-value is a count based on comparing two real value # it is thus very sensitive to minor rounding errors # When counts are rare, that may make huge proportional error # se we have to keep that number high for proper "almost" comparison # stats use the normal precision npt.assert_almost_equal(left.values[:, 0], right.values[:, 0]) # p-values use modified check npt.assert_almost_equal(left.values[:, 1] + 0.5, right.values[:, 1] + 0.5, decimal=2) def test_minimal_compatible_input(self): # Matrices are already in the correct order and have matching IDs. # input as DistanceMatrix instances obs = pwmantel(self.min_dms, alternative='greater', seed=42) assert_data_frame_almost_equal(obs, self.exp_results_minimal) # input as array_like obs = pwmantel((self.minx, self.miny, self.minz), alternative='greater', seed=42) assert_data_frame_almost_equal(obs, self.exp_results_minimal) def test_minimal_compatible_input_with_labels(self): obs = pwmantel(self.min_dms, alternative='greater', labels=('minx', 'miny', 'minz'), seed=42) assert_data_frame_almost_equal( obs, self.exp_results_minimal_with_labels) def test_duplicate_dms(self): obs = pwmantel((self.minx_dm, self.minx_dm, self.minx_dm), alternative='less', seed=42) assert_data_frame_almost_equal(obs, self.exp_results_duplicate_dms) def test_na_p_value(self): obs = pwmantel((self.miny_dm, self.minx_dm), method='spearman', permutations=0, seed=42) assert_data_frame_almost_equal(obs, self.exp_results_na_p_value) def test_reordered_distance_matrices(self): # Matrices have matching IDs but they all have different ordering. x = self.minx_dm.filter(['1', '0', '2']) y = self.miny_dm.filter(['0', '2', '1']) z = self.minz_dm.filter(['1', '2', '0']) obs = pwmantel((x, y, z), alternative='greater', seed=42) assert_data_frame_almost_equal( obs, self.exp_results_reordered_distance_matrices) def test_strict(self): # Matrices have some matching and nonmatching IDs, with different # ordering. x = self.minx_dm_extra.filter(['1', '0', 'foo', '2']) y = self.miny_dm.filter(['0', '2', '1']) z = self.minz_dm_extra.filter(['bar', '1', '2', '0']) # strict=False should discard IDs that aren't found in both matrices obs = pwmantel((x, y, z), alternative='greater', strict=False, seed=42) assert_data_frame_almost_equal( obs, self.exp_results_reordered_distance_matrices) def test_id_lookup(self): # Matrices have mismatched IDs but a lookup is provided. self.minx_dm_extra.ids = ['a', 'b', 'c', 'foo'] self.minz_dm_extra.ids = ['d', 'e', 'f', 'bar'] lookup = {'a': '0', 'b': '1', 'c': '2', 'foo': 'foo', 'd': '0', 'e': '1', 'f': '2', 'bar': 'bar', '0': '0', '1': '1', '2': '2'} x = self.minx_dm_extra.filter(['b', 'a', 'foo', 'c']) y = self.miny_dm.filter(['0', '2', '1']) z = self.minz_dm_extra.filter(['bar', 'e', 'f', 'd']) x_copy = x.copy() y_copy = y.copy() z_copy = z.copy() obs = pwmantel((x, y, z), alternative='greater', strict=False, lookup=lookup, seed=42) assert_data_frame_almost_equal( obs, self.exp_results_reordered_distance_matrices) # Make sure the inputs aren't modified. self.assertEqual(x, x_copy) self.assertEqual(y, y_copy) self.assertEqual(z, z_copy) def test_too_few_dms(self): with self.assertRaises(ValueError): pwmantel([self.miny_dm]) def test_wrong_number_of_labels(self): with self.assertRaises(ValueError): pwmantel(self.min_dms, labels=['foo', 'bar']) def test_duplicate_labels(self): with self.assertRaises(ValueError): pwmantel(self.min_dms, labels=['foo', 'bar', 'foo']) def test_mixed_input_types(self): # DistanceMatrix, DistanceMatrix, array_like with self.assertRaises(TypeError): pwmantel((self.miny_dm, self.minx_dm, self.minz)) def test_filepaths_as_input(self): dms = [ get_data_path('dm.txt'), get_data_path('dm2.txt'), ] obs = pwmantel(dms, seed=42) self.assert_pwmantel_almost_equal(obs, self.exp_results_dm_dm2) def test_many_filepaths_as_input(self): dms = [ get_data_path('dm2.txt'), get_data_path('dm.txt'), get_data_path('dm4.txt'), get_data_path('dm3.txt') ] obs = pwmantel(dms, seed=42) self.assert_pwmantel_almost_equal(obs, self.exp_results_all_dms) class OrderDistanceMatricesTests(MantelTestData): def setUp(self): super(OrderDistanceMatricesTests, self).setUp() def test_array_like_input(self): obs = _order_dms(self.minx, self.miny) self.assertEqual(obs, (self.minx_dm, self.miny_dm)) def test_reordered_distance_matrices(self): # All matching IDs but with different orderings. x = self.minx_dm.filter(['1', '0', '2']) y = self.miny_dm.filter(['0', '2', '1']) exp = (x, y.filter(['1', '0', '2'])) obs = _order_dms(x, y) self.assertEqual(obs, exp) def test_reordered_and_nonmatching_distance_matrices(self): # Some matching and nonmatching IDs, with different ordering. x = self.minx_dm_extra.filter(['1', '0', 'foo', '2']) z = self.minz_dm_extra.filter(['bar', '0', '2', '1']) exp = (x.filter(['1', '0', '2']), z.filter(['1', '0', '2'])) obs = _order_dms(x, z, strict=False) self.assertEqual(obs, exp) def test_id_lookup(self): # Matrices have mismatched IDs but a lookup is provided. self.minx_dm_extra.ids = ['a', 'b', 'c', 'foo'] self.minz_dm_extra.ids = ['d', 'e', 'f', 'bar'] lookup = {'a': '0', 'b': '1', 'c': '2', 'foo': 'foo', 'd': '0', 'e': '1', 'f': '2', 'bar': 'bar'} x = self.minx_dm_extra.filter(['b', 'a', 'foo', 'c']) z = self.minz_dm_extra.filter(['bar', 'e', 'f', 'd']) x_copy = x.copy() z_copy = z.copy() exp = (self.minx_dm.filter(['1', '0', '2']), self.minz_dm.filter(['1', '0', '2'])) obs = _order_dms(x, z, strict=False, lookup=lookup) self.assertEqual(obs, exp) # Make sure the inputs aren't modified. self.assertEqual(x, x_copy) self.assertEqual(z, z_copy) def test_lookup_with_array_like(self): lookup = {'0': 'a', '1': 'b', '2': 'c'} with self.assertRaises(ValueError): _order_dms(self.minx, self.miny, lookup=lookup) def test_shape_mismatch(self): with self.assertRaises(ValueError): _order_dms(self.minx, [[0, 2], [2, 0]]) def test_missing_ids_in_lookup(self): # Mapping for '1' is missing. Should get an error while remapping IDs # for the first distance matrix. lookup = {'0': 'a', '2': 'c'} with self.assertRaisesRegex(KeyError, r"first.*(x).*'1'\"$"): _order_dms(self.minx_dm, self.miny_dm, lookup=lookup) # Mapping for 'bar' is missing. Should get an error while remapping IDs # for the second distance matrix. lookup = {'0': 'a', '1': 'b', '2': 'c', 'foo': 'a', 'baz': 'c'} self.miny_dm.ids = ('foo', 'bar', 'baz') with self.assertRaisesRegex(KeyError, r"second.*(y).*'bar'\"$"): _order_dms(self.minx_dm, self.miny_dm, lookup=lookup) def test_nonmatching_ids_strict_true(self): with self.assertRaises(ValueError): _order_dms(self.minx_dm, self.minz_dm_extra, strict=True) def test_no_matching_ids(self): self.minx_dm.ids = ['foo', 'bar', 'baz'] self.miny_dm.ids = ['a', 'b', 'c'] with self.assertRaises(ValueError): _order_dms(self.minx_dm, self.miny_dm, strict=False) def test_mixed_input_types(self): with self.assertRaises(TypeError): _order_dms(self.minx, self.minz_dm) with self.assertRaises(TypeError): _order_dms(self.minz_dm, self.minx) class MantelCondensedTests(TestCase): """Test that mantel works identically with condensed and full matrices.""" def setUp(self): """Set up test data in both full and condensed forms.""" # Small 3x3 matrices self.small_x = [[0, 1, 2], [1, 0, 3], [2, 3, 0]] self.small_y = [[0, 2, 7], [2, 0, 6], [7, 6, 0]] # Medium 5x5 matrices self.medium_x = [[0, 1, 2, 3, 4], [1, 0, 5, 6, 7], [2, 5, 0, 8, 9], [3, 6, 8, 0, 10], [4, 7, 9, 10, 0]] self.medium_y = [[0, 2, 4, 6, 8], [2, 0, 3, 5, 7], [4, 3, 0, 9, 11], [6, 5, 9, 0, 13], [8, 7, 11, 13, 0]] # Floating point matrices self.float_x = [[0.0, 0.5, 0.75], [0.5, 0.0, 0.25], [0.75, 0.25, 0.0]] self.float_y = [[0.0, 1.5, 2.25], [1.5, 0.0, 1.75], [2.25, 1.75, 0.0]] # Fixed seed for reproducible tests self.seed = 42 self.n_perms = 99 def test_small_matrices_pearson(self): """Test small 3x3 matrices with Pearson correlation.""" # Full form x_full = DistanceMatrix(self.small_x) y_full = DistanceMatrix(self.small_y) stat_full, p_full, n_full = mantel( x_full, y_full, method='pearson', permutations=self.n_perms, seed=self.seed ) # Condensed form x_cond = DistanceMatrix(self.small_x, condensed=True) y_cond = DistanceMatrix(self.small_y, condensed=True) stat_cond, p_cond, n_cond = mantel( x_cond, y_cond, method='pearson', permutations=self.n_perms, seed=self.seed ) # Results should be identical self.assertAlmostEqual(stat_full, stat_cond, places=10, msg="Correlation coefficients differ") self.assertAlmostEqual(p_full, p_cond, places=10, msg="P-values differ") self.assertEqual(n_full, n_cond, msg="Sample sizes differ") def test_medium_matrices_pearson(self): """Test medium 5x5 matrices with Pearson correlation.""" # Full form x_full = DistanceMatrix(self.medium_x) y_full = DistanceMatrix(self.medium_y) stat_full, p_full, n_full = mantel( x_full, y_full, method='pearson', permutations=self.n_perms, seed=self.seed ) # Condensed form x_cond = DistanceMatrix(self.medium_x, condensed=True) y_cond = DistanceMatrix(self.medium_y, condensed=True) stat_cond, p_cond, n_cond = mantel( x_cond, y_cond, method='pearson', permutations=self.n_perms, seed=self.seed ) # Results should be identical self.assertAlmostEqual(stat_full, stat_cond, places=10) self.assertAlmostEqual(p_full, p_cond, places=10) self.assertEqual(n_full, n_cond) def test_floating_point_matrices_pearson(self): """Test floating point matrices with Pearson correlation.""" # Full form x_full = DistanceMatrix(self.float_x) y_full = DistanceMatrix(self.float_y) stat_full, p_full, n_full = mantel( x_full, y_full, method='pearson', permutations=self.n_perms, seed=self.seed ) # Condensed form x_cond = DistanceMatrix(self.float_x, condensed=True) y_cond = DistanceMatrix(self.float_y, condensed=True) stat_cond, p_cond, n_cond = mantel( x_cond, y_cond, method='pearson', permutations=self.n_perms, seed=self.seed ) # Results should be identical self.assertAlmostEqual(stat_full, stat_cond, places=10) self.assertAlmostEqual(p_full, p_cond, places=10) self.assertEqual(n_full, n_cond) def test_small_matrices_spearman(self): """Test small 3x3 matrices with Spearman correlation.""" # Full form x_full = DistanceMatrix(self.small_x) y_full = DistanceMatrix(self.small_y) stat_full, p_full, n_full = mantel( x_full, y_full, method='spearman', permutations=self.n_perms, seed=self.seed ) # Condensed form x_cond = DistanceMatrix(self.small_x, condensed=True) y_cond = DistanceMatrix(self.small_y, condensed=True) stat_cond, p_cond, n_cond = mantel( x_cond, y_cond, method='spearman', permutations=self.n_perms, seed=self.seed ) # Results should be identical self.assertAlmostEqual(stat_full, stat_cond, places=10) self.assertAlmostEqual(p_full, p_cond, places=10) self.assertEqual(n_full, n_cond) def test_mixed_formats_x_condensed_y_full(self): """Test with x condensed and y full.""" x_cond = DistanceMatrix(self.small_x, condensed=True) y_full = DistanceMatrix(self.small_y) stat_mixed, p_mixed, n_mixed = mantel( x_cond, y_full, method='pearson', permutations=self.n_perms, seed=self.seed ) # Compare to both condensed x_cond2 = DistanceMatrix(self.small_x, condensed=True) y_cond = DistanceMatrix(self.small_y, condensed=True) stat_cond, p_cond, n_cond = mantel( x_cond2, y_cond, method='pearson', permutations=self.n_perms, seed=self.seed ) self.assertAlmostEqual(stat_mixed, stat_cond, places=10) self.assertAlmostEqual(p_mixed, p_cond, places=10) self.assertEqual(n_mixed, n_cond) def test_mixed_formats_x_full_y_condensed(self): """Test with x full and y condensed.""" x_full = DistanceMatrix(self.small_x) y_cond = DistanceMatrix(self.small_y, condensed=True) stat_mixed, p_mixed, n_mixed = mantel( x_full, y_cond, method='pearson', permutations=self.n_perms, seed=self.seed ) # Compare to both full x_full2 = DistanceMatrix(self.small_x) y_full = DistanceMatrix(self.small_y) stat_full, p_full, n_full = mantel( x_full2, y_full, method='pearson', permutations=self.n_perms, seed=self.seed ) self.assertAlmostEqual(stat_mixed, stat_full, places=10) self.assertAlmostEqual(p_mixed, p_full, places=10) self.assertEqual(n_mixed, n_full) def test_alternative_hypotheses_two_sided(self): """Test two-sided alternative with condensed matrices.""" x_full = DistanceMatrix(self.small_x) y_full = DistanceMatrix(self.small_y) stat_full, p_full, _ = mantel( x_full, y_full, alternative='two-sided', permutations=self.n_perms, seed=self.seed ) x_cond = DistanceMatrix(self.small_x, condensed=True) y_cond = DistanceMatrix(self.small_y, condensed=True) stat_cond, p_cond, _ = mantel( x_cond, y_cond, alternative='two-sided', permutations=self.n_perms, seed=self.seed ) self.assertAlmostEqual(stat_full, stat_cond, places=10) self.assertAlmostEqual(p_full, p_cond, places=10) def test_alternative_hypotheses_greater(self): """Test greater alternative with condensed matrices.""" x_full = DistanceMatrix(self.small_x) y_full = DistanceMatrix(self.small_y) stat_full, p_full, _ = mantel( x_full, y_full, alternative='greater', permutations=self.n_perms, seed=self.seed ) x_cond = DistanceMatrix(self.small_x, condensed=True) y_cond = DistanceMatrix(self.small_y, condensed=True) stat_cond, p_cond, _ = mantel( x_cond, y_cond, alternative='greater', permutations=self.n_perms, seed=self.seed ) self.assertAlmostEqual(stat_full, stat_cond, places=10) self.assertAlmostEqual(p_full, p_cond, places=10) def test_alternative_hypotheses_less(self): """Test less alternative with condensed matrices.""" x_full = DistanceMatrix(self.small_x) y_full = DistanceMatrix(self.small_y) stat_full, p_full, _ = mantel( x_full, y_full, alternative='less', permutations=self.n_perms, seed=self.seed ) x_cond = DistanceMatrix(self.small_x, condensed=True) y_cond = DistanceMatrix(self.small_y, condensed=True) stat_cond, p_cond, _ = mantel( x_cond, y_cond, alternative='less', permutations=self.n_perms, seed=self.seed ) self.assertAlmostEqual(stat_full, stat_cond, places=10) self.assertAlmostEqual(p_full, p_cond, places=10) def test_zero_permutations(self): """Test with zero permutations (no significance testing).""" x_full = DistanceMatrix(self.small_x) y_full = DistanceMatrix(self.small_y) stat_full, p_full, _ = mantel( x_full, y_full, permutations=0 ) x_cond = DistanceMatrix(self.small_x, condensed=True) y_cond = DistanceMatrix(self.small_y, condensed=True) stat_cond, p_cond, _ = mantel( x_cond, y_cond, permutations=0 ) # Correlation should be identical self.assertAlmostEqual(stat_full, stat_cond, places=10) # P-values should both be NaN self.assertTrue(np.isnan(p_full)) self.assertTrue(np.isnan(p_cond)) def test_many_permutations(self): """Test with many permutations to ensure statistical stability.""" x_full = DistanceMatrix(self.medium_x) y_full = DistanceMatrix(self.medium_y) stat_full, p_full, _ = mantel( x_full, y_full, permutations=999, seed=self.seed ) x_cond = DistanceMatrix(self.medium_x, condensed=True) y_cond = DistanceMatrix(self.medium_y, condensed=True) stat_cond, p_cond, _ = mantel( x_cond, y_cond, permutations=999, seed=self.seed ) self.assertAlmostEqual(stat_full, stat_cond, places=10) self.assertAlmostEqual(p_full, p_cond, places=10) def test_negative_correlation(self): """Test matrices with negative correlation.""" # Create matrices with negative correlation x_data = [[0, 1, 5], [1, 0, 4], [5, 4, 0]] y_data = [[0, 5, 1], [5, 0, 2], [1, 2, 0]] x_full = DistanceMatrix(x_data) y_full = DistanceMatrix(y_data) stat_full, p_full, _ = mantel( x_full, y_full, permutations=self.n_perms, seed=self.seed ) x_cond = DistanceMatrix(x_data, condensed=True) y_cond = DistanceMatrix(y_data, condensed=True) stat_cond, p_cond, _ = mantel( x_cond, y_cond, permutations=self.n_perms, seed=self.seed ) # Verify negative correlation self.assertLess(stat_full, 0) self.assertLess(stat_cond, 0) # Verify they match self.assertAlmostEqual(stat_full, stat_cond, places=10) self.assertAlmostEqual(p_full, p_cond, places=10) def test_perfect_correlation(self): """Test identical matrices (perfect correlation).""" x_full = DistanceMatrix(self.small_x) y_full = DistanceMatrix(self.small_x) # Same as x stat_full, p_full, _ = mantel( x_full, y_full, permutations=self.n_perms, seed=self.seed ) x_cond = DistanceMatrix(self.small_x, condensed=True) y_cond = DistanceMatrix(self.small_x, condensed=True) # Same as x stat_cond, p_cond, _ = mantel( x_cond, y_cond, permutations=self.n_perms, seed=self.seed ) # Should be perfect correlation self.assertAlmostEqual(stat_full, 1.0, places=10) self.assertAlmostEqual(stat_cond, 1.0, places=10) # Results should match self.assertAlmostEqual(stat_full, stat_cond, places=10) self.assertAlmostEqual(p_full, p_cond, places=10) def test_large_matrix(self): """Test with a larger matrix to ensure scalability.""" # Create a 10x10 matrix np.random.seed(42) n = 10 x_data = np.random.rand(n, n) x_data = (x_data + x_data.T) / 2 # Make symmetric np.fill_diagonal(x_data, 0) # Make hollow y_data = np.random.rand(n, n) y_data = (y_data + y_data.T) / 2 np.fill_diagonal(y_data, 0) x_full = DistanceMatrix(x_data) y_full = DistanceMatrix(y_data) stat_full, p_full, _ = mantel( x_full, y_full, permutations=99, seed=self.seed ) x_cond = DistanceMatrix(x_data, condensed=True) y_cond = DistanceMatrix(y_data, condensed=True) stat_cond, p_cond, _ = mantel( x_cond, y_cond, permutations=99, seed=self.seed ) self.assertAlmostEqual(stat_full, stat_cond, places=10) self.assertAlmostEqual(p_full, p_cond, places=10) def test_condensed_form_memory_advantage(self): """Verify that condensed form actually uses less memory.""" n = 100 np.random.seed(42) data = np.random.rand(n, n) data = (data + data.T) / 2 np.fill_diagonal(data, 0) dm_full = DistanceMatrix(data) dm_cond = DistanceMatrix(data, condensed=True) # Full form should be n x n self.assertEqual(dm_full._data.shape, (n, n)) # Condensed form should be n*(n-1)/2 expected_cond_size = n * (n - 1) // 2 self.assertEqual(dm_cond._data.shape, (expected_cond_size,)) # Memory usage: condensed should be approximately half full_size = dm_full._data.nbytes cond_size = dm_cond._data.nbytes self.assertLess(cond_size, full_size / 2 + 1) # +1 for rounding if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/test_permanova.py000066400000000000000000000456401520735541300271660ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from functools import partial from unittest import TestCase, main import numpy as np import pandas as pd from pandas.testing import assert_series_equal from scipy.spatial.distance import squareform from skbio import DistanceMatrix from skbio.stats.distance import permanova from skbio.util import get_data_path from skbio.stats.distance._base import _preprocess_input_sng class PERMANOVATests(TestCase): """All results were verified with R (vegan::adonis).""" def setUp(self): # Distance matrices with and without ties in the ranks, with 2 groups # of equal size. dm_ids = ['s1', 's2', 's3', 's4'] self.grouping_equal = ['Control', 'Control', 'Fast', 'Fast'] self.df = pd.read_csv( io.StringIO('ID,Group\ns2,Control\ns3,Fast\ns4,Fast\ns5,Control\n' 's1,Control'), index_col=0) self.dm_ties = DistanceMatrix([[0, 1, 1, 4], [1, 0, 3, 2], [1, 3, 0, 3], [4, 2, 3, 0]], dm_ids) self.dm_no_ties = DistanceMatrix([[0, 1, 5, 4], [1, 0, 3, 2], [5, 3, 0, 3], [4, 2, 3, 0]], dm_ids) # Test with 3 groups of unequal size. self.grouping_unequal = ['Control', 'Treatment1', 'Treatment2', 'Treatment1', 'Control', 'Control'] # Equivalent grouping but with different labels -- groups should be # assigned different integer labels but results should be the same. self.grouping_unequal_relabeled = ['z', 42, 'abc', 42, 'z', 'z'] self.dm_unequal = DistanceMatrix( [[0.0, 1.0, 0.1, 0.5678, 1.0, 1.0], [1.0, 0.0, 0.002, 0.42, 0.998, 0.0], [0.1, 0.002, 0.0, 1.0, 0.123, 1.0], [0.5678, 0.42, 1.0, 0.0, 0.123, 0.43], [1.0, 0.998, 0.123, 0.123, 0.0, 0.5], [1.0, 0.0, 1.0, 0.43, 0.5, 0.0]], ['s1', 's2', 's3', 's4', 's5', 's6']) # Expected series index is the same across all tests. self.exp_index = ['method name', 'test statistic name', 'sample size', 'number of groups', 'test statistic', 'p-value', 'number of permutations'] # Stricter series equality testing than the default. self.assert_series_equal = partial(assert_series_equal, check_index_type=True, check_series_type=True) def test_call_ties(self): # Ensure we get the same results if we rerun the method using the same # inputs. Also ensure we get the same results if we run the method # using a grouping vector or a data frame with equivalent groupings. exp = pd.Series(index=self.exp_index, data=['PERMANOVA', 'pseudo-F', 4, 2, 2.0, 0.68, 999], name='PERMANOVA results') obs = permanova(self.dm_ties, self.grouping_equal, seed=42) # pstat can change slightly, depending on random source used self.assertAlmostEqual(obs.array[5],exp.array[5],delta=0.05) # update exp accordingly for further tests exp.array[5] = obs.array[5] for _ in range(2): obs = permanova(self.dm_ties, self.grouping_equal, seed=42) self.assert_series_equal(obs, exp) for _ in range(2): obs = permanova(self.dm_ties, self.df, column='Group', seed=42) self.assert_series_equal(obs, exp) def test_call_no_ties(self): exp = pd.Series(index=self.exp_index, data=['PERMANOVA', 'pseudo-F', 4, 2, 4.4, 0.345, 999], name='PERMANOVA results') obs = permanova(self.dm_no_ties, self.grouping_equal, seed=42) # pstat can change slightly, depending on random source used self.assertAlmostEqual(obs.array[5],exp.array[5],delta=0.05) # update exp accordingly for further tests exp.array[5] = obs.array[5] self.assert_series_equal(obs, exp) def test_call_no_permutations(self): exp = pd.Series(index=self.exp_index, data=['PERMANOVA', 'pseudo-F', 4, 2, 4.4, np.nan, 0], name='PERMANOVA results') obs = permanova(self.dm_no_ties, self.grouping_equal, permutations=0) self.assert_series_equal(obs, exp) def test_call_unequal_group_sizes(self): exp = pd.Series( index=self.exp_index, data=['PERMANOVA', 'pseudo-F', 6, 3, 0.578848, 0.655, 999], name='PERMANOVA results') obs = permanova(self.dm_unequal, self.grouping_unequal, seed=42) # pstat can change slightly, depending on random source used self.assertAlmostEqual(obs.array[5],exp.array[5],delta=0.05) # update exp accordingly for further tests exp.array[5] = obs.array[5] self.assert_series_equal(obs, exp) obs = permanova(self.dm_unequal, self.grouping_unequal_relabeled, seed=42) # pstat can change slightly, depending on random source used self.assertAlmostEqual(obs.array[5],exp.array[5],delta=0.05) # update exp accordingly for further tests exp.array[5] = obs.array[5] self.assert_series_equal(obs, exp) def test_call_via_series(self): # test https://github.com/scikit-bio/scikit-bio/issues/1877 # permanova gives different results if grouping is either # a pd.DataFrame or a pd.Series dm = DistanceMatrix.read(get_data_path('frameSeries_dm.tsv')) grouping = pd.read_csv(get_data_path("frameSeries_grouping.tsv"), sep="\t", index_col=0) obs_frame = permanova(dm, grouping, column='tumor', seed=42) obs_series = permanova(dm, grouping['tumor'], seed=42) # in principle, both tests - if seed is the same - should return the # exact same results. However, they don't for the current example ... self.assert_series_equal(obs_frame, obs_series) # ... which is due to different result in computing "unique" values for # the grouping, which is illustrated with the following test grp_frame = _preprocess_input_sng( dm.ids, dm.shape[0], grouping, 'tumor' # grouping as a pd.DataFrame )[-1] grp_series = _preprocess_input_sng( dm.ids, dm.shape[0], grouping['tumor'], column=None # grouping as a pd.Series, note # that user of permanova do not # have to explicitly set # column=None )[-1] # convert np.array to tuple to ease comparison for equality self.assertEqual(tuple(grp_frame), tuple(grp_series)) # to better illustrate what is going wrong, we compare the computed # grouping labels (0 or 1) with the original user provided data, here # "no-tumor mice" and "tumor-bearing mice". We expect a one-to-one # correspondens, i.e. if we group on both columns at the same time, we # expect exactly two groups, like # tumor series # no-tumor mice 0 5 # tumor-bearing mice 1 37 # dtype: int64 # which is not the case of the pd.Series case g = pd.DataFrame(data={'series': list(grp_series), 'dataframe': list(grp_frame), 'tumor': grouping.loc[list(dm.ids), 'tumor']}, index=dm.ids) self.assertEqual(g.groupby(['tumor', 'dataframe']).size().shape[0], 2) self.assertEqual(g.groupby(['tumor', 'series']).size().shape[0], 2) # test that ValueError is raised, if use provided column does not match # the provided pd.Series name for grouping with self.assertRaises(ValueError): _preprocess_input_sng(dm.ids, dm.shape[0], grouping['tumor'], 'foo') def test_invalid_input(self): with self.assertRaises(TypeError): permanova(self.dm_ties.data, self.grouping_equal, seed=42) class PERMANOVACondensedTests(TestCase): """Tests for PERMANOVA with condensed distance matrices. These tests verify that condensed and redundant forms of the same distance matrix produce identical results. """ def setUp(self): # Distance matrices with and without ties in the ranks, with 2 groups # of equal size. dm_ids = ['s1', 's2', 's3', 's4'] self.grouping_equal = ['Control', 'Control', 'Fast', 'Fast'] self.df = pd.read_csv( io.StringIO('ID,Group\ns2,Control\ns3,Fast\ns4,Fast\ns5,Control\n' 's1,Control'), index_col=0) # Create both redundant and condensed versions self.dm_ties_redundant = DistanceMatrix([[0, 1, 1, 4], [1, 0, 3, 2], [1, 3, 0, 3], [4, 2, 3, 0]], dm_ids) self.dm_ties_condensed = DistanceMatrix( squareform(self.dm_ties_redundant.data), #, checks=False), dm_ids, condensed=True ) self.dm_no_ties_redundant = DistanceMatrix([[0, 1, 5, 4], [1, 0, 3, 2], [5, 3, 0, 3], [4, 2, 3, 0]], dm_ids) self.dm_no_ties_condensed = DistanceMatrix( squareform(self.dm_no_ties_redundant.data), #, checks=False), dm_ids, condensed=True ) # Test with 3 groups of unequal size. self.grouping_unequal = ['Control', 'Treatment1', 'Treatment2', 'Treatment1', 'Control', 'Control'] self.dm_unequal_redundant = DistanceMatrix( [[0.0, 1.0, 0.1, 0.5678, 1.0, 1.0], [1.0, 0.0, 0.002, 0.42, 0.998, 0.0], [0.1, 0.002, 0.0, 1.0, 0.123, 1.0], [0.5678, 0.42, 1.0, 0.0, 0.123, 0.43], [1.0, 0.998, 0.123, 0.123, 0.0, 0.5], [1.0, 0.0, 1.0, 0.43, 0.5, 0.0]], ['s1', 's2', 's3', 's4', 's5', 's6']) self.dm_unequal_condensed = DistanceMatrix( squareform(self.dm_unequal_redundant.data), #, checks=False), ['s1', 's2', 's3', 's4', 's5', 's6'], condensed=True ) # Expected series index is the same across all tests. self.exp_index = ['method name', 'test statistic name', 'sample size', 'number of groups', 'test statistic', 'p-value', 'number of permutations'] # Stricter series equality testing than the default. self.assert_series_equal = partial(assert_series_equal, check_index_type=True, check_series_type=True) def test_condensed_vs_redundant_ties(self): """Test that condensed and redundant forms give identical results with ties.""" # Run with same seed for both obs_redundant = permanova(self.dm_ties_redundant, self.grouping_equal, seed=42) obs_condensed = permanova(self.dm_ties_condensed, self.grouping_equal, seed=42) self.assert_series_equal(obs_redundant, obs_condensed) def test_condensed_vs_redundant_no_ties(self): """Test that condensed and redundant forms give identical results without ties.""" obs_redundant = permanova(self.dm_no_ties_redundant, self.grouping_equal, seed=42) obs_condensed = permanova(self.dm_no_ties_condensed, self.grouping_equal, seed=42) self.assert_series_equal(obs_redundant, obs_condensed) def test_condensed_vs_redundant_unequal_groups(self): """Test that condensed and redundant forms give identical results with unequal groups.""" obs_redundant = permanova(self.dm_unequal_redundant, self.grouping_unequal, seed=42) obs_condensed = permanova(self.dm_unequal_condensed, self.grouping_unequal, seed=42) self.assert_series_equal(obs_redundant, obs_condensed) def test_condensed_with_dataframe_grouping(self): """Test that condensed form works with DataFrame grouping.""" obs_redundant = permanova(self.dm_ties_redundant, self.df, column='Group', seed=42) obs_condensed = permanova(self.dm_ties_condensed, self.df, column='Group', seed=42) self.assert_series_equal(obs_redundant, obs_condensed) def test_condensed_no_permutations(self): """Test that condensed form works with no permutations.""" obs_redundant = permanova(self.dm_no_ties_redundant, self.grouping_equal, permutations=0) obs_condensed = permanova(self.dm_no_ties_condensed, self.grouping_equal, permutations=0) self.assert_series_equal(obs_redundant, obs_condensed) def test_condensed_different_permutation_counts(self): """Test that condensed form gives consistent results across different permutation counts.""" # Test with various permutation counts for n_perms in [99, 199, 999]: obs_redundant = permanova(self.dm_ties_redundant, self.grouping_equal, permutations=n_perms, seed=42) obs_condensed = permanova(self.dm_ties_condensed, self.grouping_equal, permutations=n_perms, seed=42) self.assert_series_equal(obs_redundant, obs_condensed) def test_condensed_multiple_runs_same_seed(self): """Test that condensed form gives identical results across multiple runs with same seed.""" obs1 = permanova(self.dm_ties_condensed, self.grouping_equal, seed=42) obs2 = permanova(self.dm_ties_condensed, self.grouping_equal, seed=42) obs3 = permanova(self.dm_ties_condensed, self.grouping_equal, seed=42) self.assert_series_equal(obs1, obs2) self.assert_series_equal(obs2, obs3) def test_condensed_test_statistic_positive(self): """Test that condensed form produces positive F-statistics.""" # This is a regression test for the bug where condensed matrices # produced negative F-statistics due to incorrect s_T calculation obs = permanova(self.dm_ties_condensed, self.grouping_equal, seed=42) # F-statistic should always be non-negative self.assertGreaterEqual(obs['test statistic'], 0.0) def test_condensed_test_statistic_matches_expected(self): """Test that condensed form produces expected F-statistic values.""" # These expected values come from the redundant form tests obs_ties = permanova(self.dm_ties_condensed, self.grouping_equal, permutations=0) self.assertAlmostEqual(obs_ties['test statistic'], 2.0, places=5) obs_no_ties = permanova(self.dm_no_ties_condensed, self.grouping_equal, permutations=0) self.assertAlmostEqual(obs_no_ties['test statistic'], 4.4, places=5) def test_condensed_large_matrix(self): """Test condensed form with a larger matrix.""" # Create a 10x10 distance matrix np.random.seed(42) n = 10 redundant_data = np.random.rand(n, n) redundant_data = (redundant_data + redundant_data.T) / 2 # Make symmetric np.fill_diagonal(redundant_data, 0) # Zero diagonal ids = [f's{i}' for i in range(n)] dm_redundant = DistanceMatrix(redundant_data, ids) dm_condensed = DistanceMatrix(squareform(redundant_data, checks=False), ids) grouping = ['A'] * 5 + ['B'] * 5 obs_redundant = permanova(dm_redundant, grouping, seed=42, permutations=99) obs_condensed = permanova(dm_condensed, grouping, seed=42, permutations=99) self.assert_series_equal(obs_redundant, obs_condensed) def test_condensed_3x3_matrix(self): """Test condensed form with 3x3 matrix.""" dm_redundant = DistanceMatrix([[0, 1, 2], [1, 0, 3], [2, 3, 0]], ['s1', 's2', 's3']) dm_condensed = DistanceMatrix([1, 2, 3], ['s1', 's2', 's3']) grouping = ['A', 'A', 'B'] obs_redundant = permanova(dm_redundant, grouping, seed=42, permutations=99) obs_condensed = permanova(dm_condensed, grouping, seed=42, permutations=99) self.assert_series_equal(obs_redundant, obs_condensed) def test_condensed_via_series(self): """Test condensed form with pd.Series grouping (regression test for #1877).""" dm_redundant = DistanceMatrix.read(get_data_path('frameSeries_dm.tsv')) dm_condensed = DistanceMatrix( squareform(dm_redundant.data, checks=False), dm_redundant.ids ) grouping = pd.read_csv(get_data_path("frameSeries_grouping.tsv"), sep="\t", index_col=0) # Test with DataFrame obs_redundant_frame = permanova(dm_redundant, grouping, column='tumor', seed=42) obs_condensed_frame = permanova(dm_condensed, grouping, column='tumor', seed=42) self.assert_series_equal(obs_redundant_frame, obs_condensed_frame) # Test with Series obs_redundant_series = permanova(dm_redundant, grouping['tumor'], seed=42) obs_condensed_series = permanova(dm_condensed, grouping['tumor'], seed=42) self.assert_series_equal(obs_redundant_series, obs_condensed_series) # Verify both grouping types give same results for condensed self.assert_series_equal(obs_condensed_frame, obs_condensed_series) def test_condensed_flags_set_correctly(self): """Test that condensed matrices have correct flags set.""" self.assertTrue(self.dm_ties_condensed._flags["CONDENSED"]) self.assertFalse(self.dm_ties_redundant._flags["CONDENSED"]) def test_condensed_data_shape(self): """Test that condensed matrix data has correct shape.""" n = 4 # 4x4 matrix expected_condensed_length = n * (n - 1) // 2 self.assertEqual(len(self.dm_ties_condensed.data), expected_condensed_length) self.assertEqual(self.dm_ties_redundant.data.shape, (n, n)) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/test_permdisp.py000066400000000000000000000436431520735541300270220ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from functools import partial from unittest import TestCase, main, skipIf import platform import numpy as np import numpy.testing as npt import pandas as pd from pandas.testing import assert_series_equal from scipy.stats import f_oneway, ConstantInputWarning from skbio import DistanceMatrix from skbio.stats.ordination import pcoa from skbio.stats.distance import permdisp from skbio.stats.distance._permdisp import _compute_groups from skbio.stats.distance._cutils import geomedian_axis_one from skbio.util import get_data_path IS_INTEL_MAC = platform.system() == "Darwin" and platform.machine() == "x86_64" class PERMDISPTests(TestCase): def setUp(self): # test with 2 groups of equal size # when assigned different labels, results should be the same self.grouping_eq = ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] self.grouping_eq_relab = ['pyt', 'pyt', 'pyt', 'hon', 'hon', 'hon'] self.exp_index = ['method name', 'test statistic name', 'sample size', 'number of groups', 'test statistic', 'p-value', 'number of permutations'] # test with 3 groups of different sizes # when assigned different labels results should be the same self.grouping_uneq = ['foo', 'foo', 'bar', 'bar', 'bar', 'qw', 'qw', 'qw', 'qw'] self.grouping_uneq_relab = [12, 12, 7, 7, 7, 23, 23, 23, 23] self.grouping_un_mixed = ['a', 'a', 7, 7, 7, 'b', 'b', 'b', 'b'] eq_ids = ['s1', 's2', 's3', 's4', 's5', 's6'] uneq_ids = ['s1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9'] # matrix for equal grouping self.eq_mat = DistanceMatrix([[0, 4, 0, 0, 4, 2], [4, 0, 2, 0, 3, 1], [0, 2, 0, 5, 2, 5], [0, 0, 5, 0, 0, 2], [4, 3, 2, 0, 0, 2], [2, 1, 5, 2, 2, 0]], eq_ids) # matrix for unequal grouping self.uneq_mat = DistanceMatrix([[0, 0, 4, 0, 0, 3, 5, 3, 0], [0, 0, 0, 3, 4, 5, 3, 0, 3], [4, 0, 0, 4, 3, 1, 0, 5, 2], [0, 3, 4, 0, 0, 2, 1, 3, 5], [0, 4, 3, 0, 0, 1, 1, 5, 0], [3, 5, 1, 2, 1, 0, 2, 0, 5], [5, 3, 0, 1, 1, 2, 0, 4, 3], [3, 0, 5, 3, 5, 0, 4, 0, 4], [0, 3, 2, 5, 0, 5, 3, 4, 0]], uneq_ids) # null matrix for equal grouping self.null_mat = DistanceMatrix([[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], eq_ids) unif_ids = ['PC.354', 'PC.355', 'PC.356', 'PC.481', 'PC.593', 'PC.607', 'PC.634', 'PC.635', 'PC.636'] self.unifrac_dm = DistanceMatrix( [[0.0, 0.595483768391, 0.618074717633, 0.582763100909, 0.566949022108, 0.714717232268, 0.772001731764, 0.690237118413, 0.740681707488], [0.595483768391, 0.0, 0.581427669668, 0.613726772383, 0.65945132763, 0.745176523638, 0.733836123821, 0.720305073505, 0.680785600439], [0.618074717633, 0.581427669668, 0.0, 0.672149021573, 0.699416863323, 0.71405573754, 0.759178215168, 0.689701276341, 0.725100672826], [0.582763100909, 0.613726772383, 0.672149021573, 0.0, 0.64756120797, 0.666018240373, 0.66532968784, 0.650464714994, 0.632524644216], [0.566949022108, 0.65945132763, 0.699416863323, 0.64756120797, 0.0, 0.703720200713, 0.748240937349, 0.73416971958, 0.727154987937], [0.714717232268, 0.745176523638, 0.71405573754, 0.666018240373, 0.703720200713, 0.0, 0.707316869557, 0.636288883818, 0.699880573956], [0.772001731764, 0.733836123821, 0.759178215168, 0.66532968784, 0.748240937349, 0.707316869557, 0.0, 0.565875193399, 0.560605525642], [0.690237118413, 0.720305073505, 0.689701276341, 0.650464714994, 0.73416971958, 0.636288883818, 0.565875193399, 0.0, 0.575788039321], [0.740681707488, 0.680785600439, 0.725100672826, 0.632524644216, 0.727154987937, 0.699880573956, 0.560605525642, 0.575788039321, 0.0]], unif_ids) # condensed form self.unifrac_dm_condensed = DistanceMatrix(self.unifrac_dm) self.unif_grouping = ['Control', 'Control', 'Control', 'Control', 'Control', 'Fast', 'Fast', 'Fast', 'Fast'] self.assert_series_equal = partial(assert_series_equal, check_index_type=True, check_series_type=True) def test_centroids_eq_groups(self): exp = [[1.2886811963240687, 1.890538910062923, 1.490527658097728], [2.17349240061718, 2.3192679626679946, 2.028338553903792]] exp_stat, _ = f_oneway(*exp) dm = pcoa(self.eq_mat, warn_neg_eigval=False) dm = dm.samples obs = _compute_groups(dm, 'centroid', self.grouping_eq) self.assertAlmostEqual(obs, exp_stat, places=6) obs_relab = _compute_groups(dm, 'centroid', self.grouping_eq_relab) self.assertAlmostEqual(obs_relab, obs, places=6) def test_centroids_uneq_groups(self): """ the expected result here was calculated by hand """ exp = [[2.5847022428144935, 2.285624595858895, 1.7022431146340287], [1.724817266046108, 1.724817266046108], [2.4333280644972795, 2.389000390879655, 2.8547180589306036, 3.218568759338847]] exp_stat, _ = f_oneway(*exp) dm = pcoa(self.uneq_mat, warn_neg_eigval=False) dm = dm.samples obs = _compute_groups(dm, 'centroid', self.grouping_uneq) self.assertAlmostEqual(obs, exp_stat, places=6) obs_relab = _compute_groups(dm, 'centroid', self.grouping_uneq_relab) self.assertAlmostEqual(obs, obs_relab, places=6) def test_centroids_mixedgroups(self): exp = [[2.5847022428144935, 2.285624595858895, 1.7022431146340287], [1.724817266046108, 1.724817266046108], [2.4333280644972795, 2.389000390879655, 2.8547180589306036, 3.218568759338847]] dm = pcoa(self.uneq_mat, warn_neg_eigval=False) dm = dm.samples exp_stat, _ = f_oneway(*exp) obs_mixed = _compute_groups(dm, 'centroid', self.grouping_un_mixed) self.assertAlmostEqual(exp_stat, obs_mixed, places=6) def test_centroids_null(self): dm = pcoa(self.null_mat) dm = dm.samples # TODO: SciPy 1.17+ changed the behavior of f_oneway so that a # ConstantInputWarning may no longer be emitted for this case. # Once the expected behavior is clarified, consider reintroducing # an explicit warning assertion here. obs_null = _compute_groups(dm, 'centroid', self.grouping_eq) np.isnan(obs_null) def test_centroid_normal(self): exp = pd.Series(index=self.exp_index, data=['PERMDISP', 'F-value', 9, 2, 0.244501519876, 0.53, 99], name='PERMDISP results') grouping = ['Control', 'Control', 'Control', 'Control', 'Control', 'Fast', 'Fast', 'Fast', 'Fast'] obs = permdisp(self.unifrac_dm, grouping, test='centroid', permutations=99, seed=42, dimensions=self.unifrac_dm.shape[0]) self.assert_series_equal(obs, exp) def test_centroid_normal_condensed(self): exp = pd.Series(index=self.exp_index, data=['PERMDISP', 'F-value', 9, 2, 0.244501519876, 0.53, 99], name='PERMDISP results') grouping = ['Control', 'Control', 'Control', 'Control', 'Control', 'Fast', 'Fast', 'Fast', 'Fast'] obs = permdisp(self.unifrac_dm_condensed, grouping, test='centroid', permutations=99, seed=42, dimensions=self.unifrac_dm_condensed.shape[0]) self.assert_series_equal(obs, exp) @skipIf(IS_INTEL_MAC, "See issue #2382.") def test_median_normal(self): exp = pd.Series(index=self.exp_index, data=['PERMDISP', 'F-value', 9, 2, 0.139475441876, 0.51, 99], name='PERMDISP results') obs = permdisp(self.unifrac_dm, self.unif_grouping, test='median', permutations=99, seed=42, dimensions=self.unifrac_dm.shape[0]) self.assert_series_equal(obs, exp) po = pcoa(self.unifrac_dm) obs2 = permdisp(po, self.unif_grouping, test='median', permutations=99, seed=42) self.assert_series_equal(obs2, exp) @skipIf(IS_INTEL_MAC, "See issue #2382.") def test_median_normal_condensed(self): exp = pd.Series(index=self.exp_index, data=['PERMDISP', 'F-value', 9, 2, 0.139475441876, 0.51, 99], name='PERMDISP results') obs = permdisp(self.unifrac_dm_condensed, self.unif_grouping, test='median', permutations=99, seed=42, dimensions=self.unifrac_dm_condensed.shape[0]) self.assert_series_equal(obs, exp) po = pcoa(self.unifrac_dm_condensed) obs2 = permdisp(po, self.unif_grouping, test='median', permutations=99, seed=42) self.assert_series_equal(obs2, exp) @skipIf(IS_INTEL_MAC, "See issue #2382.") def test_median_fsvd(self): exp = pd.Series(index=self.exp_index, data=['PERMDISP', 'F-value', 9, 2, 0.04078077215673714, 0.79, 99], name='PERMDISP results') obs = permdisp(self.unifrac_dm, self.unif_grouping, test='median', permutations=99, method='fsvd', dimensions=3, seed=42) self.assert_series_equal(obs, exp) po = pcoa(self.unifrac_dm, method='fsvd', dimensions=3) obs = permdisp(po, self.unif_grouping, test='median', permutations=99, seed=42) self.assert_series_equal(obs, exp) @skipIf(IS_INTEL_MAC, "See issue #2382.") def test_median_fsvd_condensed(self): exp = pd.Series(index=self.exp_index, data=['PERMDISP', 'F-value', 9, 2, 0.04078077215673714, 0.79, 99], name='PERMDISP results') obs = permdisp(self.unifrac_dm_condensed, self.unif_grouping, test='median', permutations=99, method='fsvd', dimensions=3, seed=42) self.assert_series_equal(obs, exp) po = pcoa(self.unifrac_dm_condensed, method='fsvd', dimensions=3) obs = permdisp(po, self.unif_grouping, test='median', permutations=99, seed=42) self.assert_series_equal(obs, exp) def test_not_distance_matrix(self): dm = [] grouping = ['Control', 'Control', 'Control', 'Control', 'Control', 'Fast', 'Fast', 'Fast', 'Fast'] npt.assert_raises(TypeError, permdisp, dm, grouping, permutations=0) def test_mismatched_group(self): gr = ['foo', 'bar'] npt.assert_raises(ValueError, permdisp, self.unifrac_dm, gr) def test_single_group(self): gr = ['f', 'f', 'f', 'f', 'f', 'f', 'f', 'f', 'f'] npt.assert_raises(ValueError, permdisp, self.unifrac_dm, gr) def test_no_permuations(self): obs = permdisp(self.eq_mat, self.grouping_eq, permutations=0, dimensions=self.eq_mat.shape[0], warn_neg_eigval=False) pval = obs['p-value'] np.isnan(pval) def test_geomedian(self): exp = np.array([2.01956244, 1.53164546, 2.60571752, 0.91424179, 1.76214416, 1.69943057]) obs = np.array(geomedian_axis_one(self.eq_mat.data)) npt.assert_almost_equal(obs, exp, decimal=6) def test_confirm_betadispr_results(self): mp_dm = DistanceMatrix.read(get_data_path('moving_pictures_dm.tsv')) mp_mf = pd.read_csv(get_data_path('moving_pictures_mf.tsv'), sep='\t') mp_mf.set_index('#SampleID', inplace=True) obs_med_mp = permdisp(mp_dm, mp_mf, column='BodySite', seed=42, dimensions=mp_dm.shape[0]) obs_cen_mp = permdisp(mp_dm, mp_mf, column='BodySite', test='centroid', seed=42, dimensions=mp_dm.shape[0]) exp_data_m = ['PERMDISP', 'F-value', 33, 4, 10.1956, 0.001, 999] exp_data_c = ['PERMDISP', 'F-value', 33, 4, 17.4242, 0.001, 999] exp_ind = ['method name', 'test statistic name', 'sample size', 'number of groups', 'test statistic', 'p-value', 'number of permutations'] exp_med_mp = pd.Series(data=exp_data_m, index=exp_ind, dtype='object', name='PERMDISP results') exp_cen_mp = pd.Series(data=exp_data_c, index=exp_ind, dtype='object', name='PERMDISP results') self.assert_series_equal(exp_med_mp, obs_med_mp) self.assert_series_equal(exp_cen_mp, obs_cen_mp) def test_call_via_series(self): # test https://github.com/scikit-bio/scikit-bio/issues/1877 # actual issue is with _base._preprocess_input_sng but permdisp is # indirectly affected dm = DistanceMatrix.read(get_data_path('frameSeries_dm.tsv')) grouping = pd.read_csv(get_data_path("frameSeries_grouping.tsv"), sep="\t", index_col=0) obs_frame = permdisp(dm, grouping, column='tumor', seed=42, warn_neg_eigval=False) obs_series = permdisp(dm, grouping['tumor'], seed=42, warn_neg_eigval=False) # in principle, both tests - if seed is the same - should return the # exact same results. However, they don't for the current example ... self.assert_series_equal(obs_frame, obs_series) def test_invalid_test(self): with self.assertRaises(ValueError) as cm: permdisp(self.unifrac_dm, [], test='invalid') self.assertEqual(str(cm.exception), "Test must be centroid or median.") def test_invalid_method(self): with self.assertRaises(ValueError) as cm: permdisp(self.unifrac_dm, [], method='invalid') self.assertEqual(str(cm.exception), "Method must be eigh or fsvd.") def test_no_mutation_of_ordination_results(self): po = pcoa(self.unifrac_dm, warn_neg_eigval=False) original_columns = po.samples.columns.tolist() permdisp(po, self.unif_grouping, permutations=0, warn_neg_eigval=False) self.assertEqual(po.samples.columns.tolist(), original_columns) self.assertNotIn("grouping", po.samples.columns.tolist()) def test_permdisp_passes_dimensions_through(self): # Regression test for issue #2430. Previously `permdisp` silently # overrode `dimensions = 0` before calling pcoa, which tripped # pcoa's "EIGH: since no value for dimensions..." warning on every # call for distance matrices larger than 10 samples. `permdisp` # now passes `dimensions` through unchanged: normal usage (an # explicit positive value, or the default of 10) no longer leaks # the warning, while users who explicitly opt in with # `dimensions=0` still receive it (per #2456 review). import warnings from scipy.spatial.distance import pdist, squareform rng = np.random.default_rng(0) n = 12 # exceed pcoa's 10-sample warning threshold coords = rng.random((n, 5)) big_dm = DistanceMatrix( squareform(pdist(coords)), ids=[f"s{i}" for i in range(n)], ) grouping = ["A"] * 6 + ["B"] * 6 # Case 1: default permdisp call (dimensions=10) — no warning. with warnings.catch_warnings(record=True) as caught: warnings.simplefilter("always") permdisp(big_dm, grouping, permutations=9, warn_neg_eigval=False) self.assertFalse( any("EIGH" in str(w.message) for w in caught), "permdisp with a positive dimensions value must not emit " "pcoa's 'EIGH: since no value for dimensions...' warning", ) # Case 2: user explicitly passes dimensions=0 — warning preserved. with warnings.catch_warnings(record=True) as caught: warnings.simplefilter("always") permdisp(big_dm, grouping, permutations=9, dimensions=0, warn_neg_eigval=False) self.assertTrue( any(issubclass(w.category, RuntimeWarning) and "EIGH" in str(w.message) for w in caught), "permdisp must surface pcoa's EIGH warning when the caller " "explicitly passes dimensions=0 on a large matrix", ) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/distance/tests/test_util.py000066400000000000000000000104711520735541300261450ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt from skbio.stats.distance._utils import ( is_symmetric_and_hollow, is_symmetric, is_hollow, distmat_reorder, distmat_reorder_condensed, ) class UtilsTests(TestCase): def test_is_symmetric_and_hollow(self): # a symmetric and hollow matrix data = np.array([ [0, 1, 2, 3], [1, 0, 4, 5], [2, 4, 0, 6], [3, 5, 6, 0], ]).astype(float) obs = is_symmetric_and_hollow(data) exp = [True, True] self.assertListEqual(obs, exp) # convert matrix to F-contiguous order self.assertListEqual(is_symmetric_and_hollow(np.asfortranarray(data)), exp) # a symmetric but non-hollow matrix self.assertListEqual(is_symmetric_and_hollow(np.array([ [1, 2, 3], [2, 4, 5], [3, 5, 6], ]).astype(float)), [True, False]) # a hollow but asymmetric matrix self.assertListEqual(is_symmetric_and_hollow(np.array([ [0, 1, 3], [2, 0, 5], [4, 6, 0], ]).astype(float)), [False, True]) # an asymmetric and non-hollow matrix self.assertListEqual(is_symmetric_and_hollow(np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]).astype(float)), [False, False]) def test_is_symmetric(self): self.assertTrue(is_symmetric(np.array([ [1, 2, 3], [2, 4, 5], [3, 5, 6], ]).astype(float))) self.assertFalse(is_symmetric(np.array([ [0, 1, 3], [2, 0, 5], [4, 6, 0], ]).astype(float))) def test_is_hollow(self): self.assertTrue(is_hollow(np.array([ [0, 1, 3], [2, 0, 5], [4, 6, 0], ]).astype(float))) self.assertFalse(is_hollow(np.array([ [1, 2, 3], [2, 4, 5], [3, 5, 6], ]).astype(float))) def test_distmat_reorder(self): mat = np.array([ [0, 1, 2, 3], [1, 0, 4, 5], [2, 4, 0, 6], [3, 5, 6, 0], ]).astype(float) vec = np.array([1, 0, 3, 2]) obs = distmat_reorder(mat, vec) exp = np.array([ [0, 1, 5, 4], [1, 0, 3, 2], [5, 3, 0, 6], [4, 2, 6, 0], ]).astype(float) npt.assert_array_equal(obs, exp) # validation obs = distmat_reorder(mat, vec, validate=True) npt.assert_array_equal(obs, exp) # F-contiguous order obs = distmat_reorder(np.asfortranarray(mat), vec) npt.assert_array_equal(obs, exp) # partial and repeated elements obs = distmat_reorder(mat, [2, 1, 2]) exp = np.array([ [0, 4, 0], [4, 0, 4], [0, 4, 0], ]).astype(float) npt.assert_array_equal(obs, exp) # invalid order vectors with self.assertRaises(ValueError): distmat_reorder(mat, np.array([1, 100]), validate=True) with self.assertRaises(ValueError): distmat_reorder(mat, np.array([-1, 2, 3]), validate=True) def test_distmat_reorder_condensed(self): mat = np.array([ [0, 1, 2, 3], [1, 0, 4, 5], [2, 4, 0, 6], [3, 5, 6, 0], ]).astype(float) vec = np.array([1, 0, 3, 2]) obs = distmat_reorder_condensed(mat, vec) exp = np.array([1, 5, 4, 3, 2, 6]).astype(float) npt.assert_array_equal(obs, exp) # validation obs = distmat_reorder_condensed(mat, vec, validate=True) npt.assert_array_equal(obs, exp) # F-contiguous order obs = distmat_reorder_condensed(np.asfortranarray(mat), vec) npt.assert_array_equal(obs, exp) # partial and repeated elements obs = distmat_reorder_condensed(mat, [2, 1, 2]) exp = np.array([4, 0, 4]).astype(float) npt.assert_array_equal(obs, exp) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/evolve/000077500000000000000000000000001520735541300221205ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/evolve/__init__.py000066400000000000000000000016641520735541300242400ustar00rootroot00000000000000"""Evolutionary statistics (:mod:`skbio.stats.evolve`) =================================================== .. currentmodule:: skbio.stats.evolve This package contains statistics pertaining to phylogenies and evolution. Cophylogenetic methods ---------------------- These functions test for correlation between phylogenies or representations of evolutionary distance (for example, genetic distance matrices). Functions ^^^^^^^^^ .. autosummary:: :toctree: hommola_cospeciation """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._hommola import hommola_cospeciation __all__ = ["hommola_cospeciation"] scikit-bio-scikit-bio-a3beaa6/skbio/stats/evolve/_hommola.py000066400000000000000000000257331520735541300242770ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from scipy.stats import pearsonr from skbio import DistanceMatrix from skbio.util import get_rng def hommola_cospeciation(host_dist, par_dist, interaction, permutations=999, seed=None): """Perform Hommola et al (2009) host/parasite cospeciation test. This test for host/parasite cospeciation is as described in [1]_. This test is a modification of a Mantel test, expanded to accept the case where multiple hosts map to a single parasite (and vice versa). For a basic Mantel test, the distance matrices being compared must have the same number of values. To determine the significance of the correlations between distances in the two matrices, the correlation coefficient of those distances is calculated and compared to the correlation coefficients calculated from a set of matrices in which rows and columns have been permuted. In this test, rather than comparing host-host to parasite-parasite distances directly (requiring one host per parasite), the distances are compared for each interaction edge between host and parasite. Thus, a host interacting with two different parasites will be represented in two different edges, with the host-host distance for the comparison between those edges equal to zero, and the parasite-parasite distance equal to the distance between those two parasites. Like in the Mantel test, significance of the interaction is assessed by permutation, in this case permutation of the host-symbiont interaction links. Note that the null hypothesis being tested here is that the hosts and parasites have evolved independently of one another. The alternative to this is a somewhat weaker case than what is often implied with the term 'cospeciation,' which is that each incidence of host speciation is recapitulated in an incidence of symbiont speciation (strict co-cladogenesis). Although there may be many factors that could contribute to non-independence of host and symbiont phylogenies, this loss of explanatory specificity comes with increased robustness to phylogenetic uncertainty. Thus, this test may be especially useful for cases where host and/or symbiont phylogenies are poorly resolved, or when simple correlation between host and symbiont evolution is of more interest than strict co-cladogenesis. This test requires pairwise distance matrices for hosts and symbionts, as well as an interaction matrix specifying links between hosts (in columns) and symbionts (in rows). This interaction matrix should have the same number of columns as the host distance matrix, and the same number of rows as the symbiont distance matrix. Interactions between hosts and symbionts should be indicated by values of ``1`` or ``True``, with non-interactions indicated by values of ``0`` or ``False``. Parameters ---------- host_dist : 2-D array_like or DistanceMatrix Symmetric matrix of m x m pairwise distances between hosts. par_dist : 2-D array_like or DistanceMatrix Symmetric matrix of n x n pairwise distances between parasites. interaction : 2-D array_like, bool n x m binary matrix of parasite x host interactions. Order of hosts (columns) should be identical to order of hosts in `host_dist`, as should order of parasites (rows) be identical to order of parasites in `par_dist`. permutations : int, optional Number of permutations used to compute p-value. Must be greater than or equal to zero. If zero, statistical significance calculations will be skipped and the p-value will be ``np.nan``. seed : int or np.random.Generator, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- corr_coeff : float Pearson correlation coefficient of host : parasite association. p_value : float Significance of host : parasite association computed using `permutations` and a one-sided (greater) alternative hypothesis. perm_stats : 1-D numpy.ndarray, float Correlation coefficients observed using permuted host : parasite interactions. Length will be equal to the number of permutations used to compute p-value (see `permutations` parameter above). See Also -------- skbio.stats.distance.mantel scipy.stats.pearsonr Notes ----- It is assumed that the ordering of parasites in `par_dist` and hosts in `host_dist` are identical to their ordering in the rows and columns, respectively, of the interaction matrix. This code is loosely based on the original R code from [1]_. References ---------- .. [1] Hommola K, Smith JE, Qiu Y, Gilks WR (2009) A Permutation Test of Host-Parasite Cospeciation. Molecular Biology and Evolution, 26, 1457-1468. Examples -------- >>> from skbio.stats.evolve import hommola_cospeciation Create arrays for host distances, parasite distances, and their interactions (data taken from example in [1]_): >>> hdist = [[0,3,8,8,9], [3,0,7,7,8], [8,7,0,6,7], [8,7,6,0,3], ... [9,8,7,3,0]] >>> pdist = [[0,5,8,8,8], [5,0,7,7,7], [8,7,0,4,4], [8,7,4,0,2], ... [8,7,4,2,0]] >>> interaction = [[1,0,0,0,0], [0,1,0,0,0], [0,0,1,0,0], [0,0,0,1,0], ... [0,0,0,1,1]] Run the cospeciation test with 99 permutations. Note that the correlation coefficient for the observed values counts against the final reported p-value: >>> corr_coeff, p_value, perm_stats = hommola_cospeciation( ... hdist, pdist, interaction, permutations=99, seed=42) >>> print("%.3f" % corr_coeff) 0.832 In this case, the host distances have a fairly strong positive correlation with the symbiont distances. However, this may also reflect structure inherent in the phylogeny, and is not itself indicative of significance. >>> p_value <= 0.05 True After permuting host : parasite interactions, we find that the observed correlation is indeed greater than we would expect by chance. """ host_dist = DistanceMatrix(host_dist) par_dist = DistanceMatrix(par_dist) interaction = np.asarray(interaction, dtype=bool) num_hosts = host_dist.shape[0] num_pars = par_dist.shape[0] if num_hosts < 3 or num_pars < 3: raise ValueError("Distance matrices must be a minimum of 3x3 in size.") if num_hosts != interaction.shape[1]: raise ValueError( "Number of interaction matrix columns must match " "number of hosts in `host_dist`." ) if num_pars != interaction.shape[0]: raise ValueError( "Number of interaction matrix rows must match " "number of parasites in `par_dist`." ) if permutations < 0: raise ValueError( "Number of permutations must be greater than or " "equal to zero." ) if interaction.sum() < 3: raise ValueError( "Must have at least 3 host-parasite interactions in " "`interaction`." ) # shortcut to eliminate nested for-loops specifying pairwise interaction # partners as randomizeable indices pars, hosts = np.nonzero(interaction) pars_k_labels, pars_t_labels = _gen_lists(pars) hosts_k_labels, hosts_t_labels = _gen_lists(hosts) # get a vector of pairwise distances for each interaction edge x = _get_dist(hosts_k_labels, hosts_t_labels, host_dist.data, np.arange(num_hosts)) y = _get_dist(pars_k_labels, pars_t_labels, par_dist.data, np.arange(num_pars)) # calculate the observed correlation coefficient for these hosts/symbionts corr_coeff = pearsonr(x, y)[0] # now do permutatitons. initialize index lists of the appropriate size mp = np.arange(num_pars) mh = np.arange(num_hosts) # initialize list of shuffled correlation vals perm_stats = np.empty(permutations) if permutations == 0 or np.isnan(corr_coeff): p_value = np.nan perm_stats.fill(np.nan) else: rng = get_rng(seed) for i in range(permutations): # generate a shuffled list of indexes for each permutation. this # effectively randomizes which host is associated with which # symbiont, but maintains the distribution of genetic distances rng.shuffle(mp) rng.shuffle(mh) # get pairwise distances in shuffled order y_p = _get_dist(pars_k_labels, pars_t_labels, par_dist.data, mp) x_p = _get_dist(hosts_k_labels, hosts_t_labels, host_dist.data, mh) # calculate shuffled correlation coefficient perm_stats[i] = pearsonr(x_p, y_p)[0] p_value = ((perm_stats >= corr_coeff).sum() + 1) / (permutations + 1) return corr_coeff, p_value, perm_stats def _get_dist(k_labels, t_labels, dists, index): """Subset a distance matrix using a set of (randomizable) index labels. Parameters ---------- k_labels : numpy.array index labels specifying row-wise member of pairwise interaction t_labels : numpy.array index labels specifying column-wise member of pairwise interaction dists : numpy.array pairwise distance matrix index : numpy.array of int permutable indices for changing order in pairwise distance matrix Returns ------- vec : list of float List of distances associated with host:parasite edges. """ return dists[index[k_labels], index[t_labels]] def _gen_lists(labels): """Generate matched lists of row and column index labels. Shortcut function for generating matched lists of row and col index labels for the set of pairwise comparisons specified by the list of those indices recovered using ``np.nonzero(interaction)``. Reproduces values of iterated indices from the nested for-loops contained in ``get_dist`` function in original code from [1]_. Parameters ---------- labels : numpy.array array containing the indices of nonzero elements in one dimension of an interaction matrix Returns ------- k_labels : numpy.array index labels specifying row-wise member of pairwise interaction t_labels : numpy.array index labels specifying column-wise member of pairwise interaction References ---------- .. [1] Hommola K, Smith JE, Qiu Y, Gilks WR (2009) A Permutation Test of Host-Parasite Cospeciation. Molecular Biology and Evolution, 26, 1457-1468. """ i_array, j_array = np.transpose(np.tri(len(labels) - 1)).nonzero() j_array += 1 return labels[i_array], labels[j_array] scikit-bio-scikit-bio-a3beaa6/skbio/stats/evolve/tests/000077500000000000000000000000001520735541300232625ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/evolve/tests/__init__.py000066400000000000000000000005411520735541300253730ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/stats/evolve/tests/test_hommola.py000066400000000000000000000172461520735541300263410ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy as np import numpy.testing as npt from skbio.stats.distance import mantel from skbio.stats.evolve import hommola_cospeciation from skbio.stats.evolve._hommola import _get_dist, _gen_lists class HommolaCospeciationTests(unittest.TestCase): def setUp(self): # Test matrices, as presented in original paper by Hommola et al. self.hdist = np.array([[0, 3, 8, 8, 9], [3, 0, 7, 7, 8], [ 8, 7, 0, 6, 7], [8, 7, 6, 0, 3], [9, 8, 7, 3, 0]]) self.pdist = np.array([[0, 5, 8, 8, 8], [5, 0, 7, 7, 7], [ 8, 7, 0, 4, 4], [8, 7, 4, 0, 2], [8, 7, 4, 2, 0]]) self.interact = np.array([[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [ 0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 1, 1]]) # Reduced-size host matrix for testing asymmetric interaction matrix self.hdist_4x4 = np.array([[0, 3, 8, 8], [3, 0, 7, 7], [8, 7, 0, 6], [8, 7, 6, 0]]) self.interact_5x4 = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [0, 0, 0, 1]]) # One to one interaction matrix for comparing against Mantel output self.interact_1to1 = np.array([[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [ 0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]]) # interaction matrix yielding non-significant results. # this matrix was picked because it will generate an r value that's # less than a standard deviation away from the mean of the normal # distribution of r vals self.interact_ns = np.array( [[0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [0, 0, 0, 0, 1]]) # minimal size matrices for sanity checks of inputs self.h_dist_3x3 = np.array([[0, 1, 2], [1, 0, 1], [2, 1, 0]]) self.h_dist_2x2 = np.array([[0, 3], [3, 0]]) self.p_dist_3x3 = np.array([[0, 3, 2], [3, 0, 1], [2, 1, 0]]) self.interact_3x3 = np.array([[0, 1, 1], [1, 0, 1], [0, 0, 1]]) self.interact_3x2 = np.array([[0, 1], [1, 0], [1, 1]]) self.interact_2x3 = np.array([[0, 1, 1], [1, 0, 1]]) self.interact_zero = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) def test_hommola_cospeciation_sig(self): obs_r, obs_p, obs_perm_stats = hommola_cospeciation( self.hdist, self.pdist, self.interact, 9, seed=123) exp_p = 0.1 exp_r = 0.8317096546324791 exp_perm_stats = np.array([-0.234008859, 0.490495437, -0.116936751, -0.175562859, 0.189925198, 0.824737151, 0.509368992, 0.016431258, -0.260609898]) self.assertAlmostEqual(obs_p, exp_p) self.assertAlmostEqual(obs_r, exp_r) npt.assert_allclose(obs_perm_stats, exp_perm_stats) def test_hommola_cospeciation_asymmetric(self): obs_r, obs_p, obs_perm_stats = hommola_cospeciation( self.hdist_4x4, self.pdist, self.interact_5x4, 9, seed=123) exp_p = 0.1 exp_r = 0.8573214099741122 exp_perm_stats = np.array([-0.0985138, 0.05605763, -0.38783588, 0.09342939, -0.28028816, -0.13080114, 0.05910828, 0.4286607, 0.04082483]) self.assertAlmostEqual(obs_p, exp_p) self.assertAlmostEqual(obs_r, exp_r) npt.assert_allclose(obs_perm_stats, exp_perm_stats) def test_hommola_cospeciation_no_sig(self): obs_r, obs_p, obs_perm_stats = hommola_cospeciation( self.hdist, self.pdist, self.interact_ns, 9, seed=123) exp_p = 0.5 exp_r = -0.01367939137911453 exp_perm_stats = np.array([0.49493401, -0.15686395, -0.40824829, -0.17739372, 0.23529593, -0.13187609, 0.23529593, -0.03137279, 0.07664242]) self.assertAlmostEqual(obs_p, exp_p) self.assertAlmostEqual(obs_r, exp_r) npt.assert_allclose(obs_perm_stats, exp_perm_stats) def test_hommola_vs_mantel(self): # we don't compare p-values because the two methods use different # permutation strategies r_mantel, p_mantel, _ = mantel( self.hdist, self.pdist, method='pearson', permutations=0, alternative='greater' ) r_hommola, p_hommola, _ = hommola_cospeciation( self.hdist, self.pdist, self.interact_1to1, permutations=0 ) self.assertAlmostEqual(r_hommola, r_mantel) npt.assert_equal(p_hommola, p_mantel) def test_zero_permutations(self): obs_r, obs_p, obs_perm_stats = hommola_cospeciation( self.hdist, self.pdist, self.interact, 0) exp_p = np.nan exp_r = 0.83170965463247915 exp_perm_stats = np.array([]) npt.assert_equal(obs_p, exp_p) self.assertAlmostEqual(obs_r, exp_r) npt.assert_equal(obs_perm_stats, exp_perm_stats) def test_get_dist(self): labels = np.array([0, 1, 1, 2, 3]) k_labels, t_labels = _gen_lists(labels) dists = np.array([[0, 2, 6, 3], [2, 0, 5, 4], [6, 5, 0, 7], [3, 4, 7, 0]]) index = np.array([2, 3, 1, 0]) expected_vec = np.array([7, 7, 5, 6, 0, 4, 3, 4, 3, 2]) actual_vec = _get_dist(k_labels, t_labels, dists, index) npt.assert_allclose(actual_vec, expected_vec) def test_gen_lists(self): exp_pars_k_labels = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]) exp_pars_t_labels = np.array([1, 2, 3, 4, 4, 2, 3, 4, 4, 3, 4, 4, 4, 4, 4]) exp_host_k_labels = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3]) exp_host_t_labels = np.array([1, 2, 3, 3, 4, 2, 3, 3, 4, 3, 3, 4, 3, 4, 4]) pars, hosts = np.nonzero(self.interact) obs_pars_k_labels, obs_pars_t_labels = _gen_lists(pars) obs_hosts_k_labels, obs_hosts_t_labels = _gen_lists(hosts) npt.assert_allclose(exp_pars_k_labels, obs_pars_k_labels) npt.assert_allclose(exp_pars_t_labels, obs_pars_t_labels) npt.assert_allclose(exp_host_k_labels, obs_hosts_k_labels) npt.assert_allclose(exp_host_t_labels, obs_hosts_t_labels) def test_dm_too_small(self): with self.assertRaises(ValueError): hommola_cospeciation(self.h_dist_2x2, self.p_dist_3x3, self.interact_3x3) def test_host_interaction_not_equal(self): with self.assertRaises(ValueError): hommola_cospeciation(self.h_dist_3x3, self.p_dist_3x3, self.interact_2x3) def test_par_interaction_not_equal(self): with self.assertRaises(ValueError): hommola_cospeciation(self.h_dist_3x3, self.p_dist_3x3, self.interact_3x2) def test_interaction_too_few(self): with self.assertRaises(ValueError): hommola_cospeciation(self.h_dist_3x3, self.p_dist_3x3, self.interact_zero) def test_permutations_too_few(self): with self.assertRaises(ValueError): hommola_cospeciation(self.h_dist_3x3, self.p_dist_3x3, self.interact_3x3, -1) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/gradient.py000066400000000000000000000770671520735541300230100ustar00rootroot00000000000000r"""Gradient analyses (:mod:`skbio.stats.gradient`) =============================================== .. currentmodule:: skbio.stats.gradient This module provides functionality for performing gradient analyses. The algorithms included in this module mainly allows performing analysis of volatility on time series data, but they can be applied to any data that contains a gradient. Classes ------- .. autosummary:: :toctree: GradientANOVA AverageGradientANOVA TrajectoryGradientANOVA FirstDifferenceGradientANOVA WindowDifferenceGradientANOVA GroupResults CategoryResults GradientANOVAResults Examples -------- Assume we have the following coordinates: >>> import numpy as np >>> import pandas as pd >>> from skbio.stats.gradient import AverageGradientANOVA >>> coord_data = {'PC.354': np.array([0.2761, -0.0341, 0.0633, 0.1004]), ... 'PC.355': np.array([0.2364, 0.2186, -0.0301, -0.0225]), ... 'PC.356': np.array([0.2208, 0.0874, -0.3519, -0.0031]), ... 'PC.607': np.array([-0.1055, -0.4140, -0.15, -0.116]), ... 'PC.634': np.array([-0.3716, 0.1154, 0.0721, 0.0898])} >>> coords = pd.DataFrame.from_dict(coord_data, orient='index') the following metadata map: >>> metadata_map = {'PC.354': {'Treatment': 'Control', 'Weight': '60'}, ... 'PC.355': {'Treatment': 'Control', 'Weight': '55'}, ... 'PC.356': {'Treatment': 'Control', 'Weight': '50'}, ... 'PC.607': {'Treatment': 'Fast', 'Weight': '65'}, ... 'PC.634': {'Treatment': 'Fast', 'Weight': '68'}} >>> metadata_map = pd.DataFrame.from_dict(metadata_map, orient='index') and the following array with the proportion explained of each coord: >>> prop_expl = np.array([25.6216, 15.7715, 14.1215, 11.6913, 9.8304]) Then to compute the average trajectory of this data: >>> av = AverageGradientANOVA(coords, prop_expl, metadata_map, ... trajectory_categories=['Treatment'], ... sort_category='Weight') >>> trajectory_results = av.get_trajectories() Check the algorithm used to compute the trajectory_results: >>> print(trajectory_results.algorithm) avg Check if we weighted the data or not: >>> print(trajectory_results.weighted) False Check the results of one of the categories: >>> print(trajectory_results.categories[0].category) Treatment >>> print(trajectory_results.categories[0].probability) 0.0118478282382 Check the results of one group of one of the categories: >>> print(trajectory_results.categories[0].groups[0].name) Control >>> print(trajectory_results.categories[0].groups[0].trajectory) [ 3.52199973 2.29597001 3.20309816] >>> print(trajectory_results.categories[0].groups[0].info) {'avg': 3.007022633956606} """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from copy import deepcopy from collections import defaultdict from numbers import Integral import numpy as np from natsort import realsorted from scipy.stats import f_oneway def _weight_by_vector(trajectories, w_vector): r"""Weight the values of `trajectories` given a weighting vector `w_vector`. Each value in `trajectories` will be weighted by the 'rate of change' to 'optimal rate of change' ratio. The 'rate of change' of a vector measures how each point in the vector changes with respect to its predecessor point. The 'optimal rate of change' is the rate of change in which each point in the vector performs the same change than its predecessor, meaning that when calling this function over evenly spaced `w_vector` values, no change will be reflected on the output. Parameters ---------- trajectories: pandas.DataFrame Values to weight w_vector: pandas.Series Values used to weight `trajectories` Returns ------- pandas.DataFrame A weighted version of `trajectories`. Raises ------ ValueError If `trajectories` and `w_vector` don't have equal lengths If `w_vector` is not a gradient TypeError If `trajectories` and `w_vector` are not iterables """ try: if len(trajectories) != len(w_vector): raise ValueError( "trajectories (%d) & w_vector (%d) must be equal " "lengths" % (len(trajectories), len(w_vector)) ) except TypeError: raise TypeError("trajectories and w_vector must be iterables") # check no repeated values are passed in the weighting vector if len(set(w_vector)) != len(w_vector): raise ValueError("The weighting vector must be a gradient") # no need to weight in case of a one element vector if len(w_vector) == 1: return trajectories # Cast to float so divisions have a floating point resolution total_length = float(max(w_vector) - min(w_vector)) # Reflects the expected gradient between subsequent values in w_vector # the first value isn't weighted so subtract one from the number of # elements optimal_gradient = total_length / (len(w_vector) - 1) # Convert to float64 before performing calculations to avoid type errors trajectories = trajectories.astype("float64") # for all elements apply the weighting function for i, idx in enumerate(trajectories.index): # Skipping the first element is it doesn't need to be weighted if i != 0: trajectories.loc[idx] = ( trajectories.loc[idx] * optimal_gradient / np.abs((w_vector.iloc[i] - w_vector.iloc[i - 1])) ) return trajectories def _ANOVA_trajectories(category, res_by_group): r"""Run ANOVA over `res_by_group`. If ANOVA cannot be run in the current category (because either there is only one group in category or there is a group with only one member) the result CategoryResults instance has `probability` and `groups` set to None and message is set to a string explaining why ANOVA was not run Returns ------- CategoryResults An instance of CategoryResults holding the results of the trajectory analysis applied on `category` """ # If there is only one group under category we cannot run ANOVA if len(res_by_group) == 1: return CategoryResults(category, None, None, "Only one value in the group.") # Check if groups can be tested using ANOVA. ANOVA testing requires # all elements to have at least size greater to one. values = [res.trajectory.astype(float) for res in res_by_group] if any([len(value) == 1 for value in values]): return CategoryResults( category, None, None, "This group can not be used. All groups should have more than 1 element.", ) # We are ok to run ANOVA _, p_val = f_oneway(*values) return CategoryResults(category, p_val, res_by_group, None) class GroupResults: """Store the trajectory results of a group of a metadata category. Attributes ---------- name : str The name of the group within the metadata category trajectory : array like The result trajectory in an 1-D numpy array mean : float The mean of the trajectory info : dict Any extra information computed by the trajectory algorithm. Depends on the algorithm message : str A message with information of the execution of the algorithm """ def __init__(self, name, trajectory, mean, info, message): """Construct all the necessary attributes for the GroupResults object.""" self.name = name self.trajectory = trajectory self.mean = mean self.info = info self.message = message def to_files(self, out_f, raw_f): r"""Save trajectory analysis results for a category group to text format files. Parameters ---------- out_f : file-like object File-like object to write trajectory analysis data to. Must have a `write` method. It is the caller's responsibility to close `out_f` when done (if necessary) raw_f : file-like object File-like object to write trajectories trajectory values. Must have a `write` method. It is the caller's responsibility to close `out_f` when done (if necessary) """ out_f.write('For group "%s", the group means is: %f\n' % (self.name, self.mean)) raw_f.write('For group "%s":\n' % self.name) if self.message: out_f.write("%s\n" % self.message) raw_f.write("%s\n" % self.message) out_f.write( "The info is: %s\n" % sorted(((k, v) for k, v in self.info.items())) ) raw_f.write("The trajectory is:\n[%s]\n" % ", ".join(map(str, self.trajectory))) class CategoryResults: """Store the trajectory results of a metadata category. Attributes ---------- category : str The name of the category probability : float The ANOVA probability that the category groups are independent groups : list of GroupResults The trajectory results for each group in the category message : str A message with information of the execution of the algorithm """ def __init__(self, category, probability, groups, message): """Construct all the necessary attributes for the CategoryResults object.""" self.category = category self.probability = probability self.groups = groups self.message = message def to_files(self, out_f, raw_f): r"""Save trajectory analysis results for a category to files in text format. Parameters ---------- out_f : file-like object File-like object to write trajectory analysis data to. Must have a `write` method. It is the caller's responsibility to close `out_f` when done (if necessary) raw_f : file-like object File-like object to write trajectory raw values. Must have a `write` method. It is the caller's responsibility to close `out_f` when done (if necessary) """ if self.probability is None: out_f.write('Grouped by "%s": %s\n' % (self.category, self.message)) else: out_f.write( 'Grouped by "%s", probability: %f\n' % (self.category, self.probability) ) raw_f.write('Grouped by "%s"\n' % self.category) for group in self.groups: group.to_files(out_f, raw_f) class GradientANOVAResults: """Store the trajectory results. Attributes ---------- algorithm : str The algorithm used to compute trajectories weighted : bool If true, a weighting vector was used categories : list of CategoryResults The trajectory results for each metadata category """ def __init__(self, algorithm, weighted, categories): """Construct all the attributes for the GradientANOVAResults object.""" self.algorithm = algorithm self.weighted = weighted self.categories = categories def to_files(self, out_f, raw_f): r"""Save the trajectory analysis results to files in text format. Parameters ---------- out_f : file-like object File-like object to write trajectories analysis data to. Must have a `write` method. It is the caller's responsibility to close `out_f` when done (if necessary) raw_f : file-like object File-like object to write trajectories raw values. Must have a `write` method. It is the caller's responsibility to close `out_f` when done (if necessary) """ out_f.write("Trajectory algorithm: %s\n" % self.algorithm) raw_f.write("Trajectory algorithm: %s\n" % self.algorithm) if self.weighted: out_f.write("** This output is weighted **\n") raw_f.write("** This output is weighted **\n") out_f.write("\n") raw_f.write("\n") for cat_results in self.categories: cat_results.to_files(out_f, raw_f) out_f.write("\n") raw_f.write("\n") class GradientANOVA: r"""Base class for the Trajectory algorithms. Parameters ---------- coords : pandas.DataFrame The coordinates for each sample id prop_expl : array like The numpy 1-D array with the proportion explained by each axis in coords metadata_map : pandas.DataFrame The metadata map, indexed by sample ids and columns are metadata categories trajectory_categories : list of str, optional A list of metadata categories to use to create the trajectories. If None is passed, the trajectories for all metadata categories are computed. Default: None, compute all of them sort_category : str, optional The metadata category to use to sort the trajectories. Default: None axes : int, optional The number of axes to account while doing the trajectory specific calculations. Pass 0 to compute all of them. Default: 3 weighted : bool, optional If true, the output is weighted by the space between samples in the `sort_category` column Raises ------ ValueError If any category of `trajectory_categories` is not present in `metadata_map` If `sort_category` is not present in `metadata_map` If `axes` is not between 0 and the maximum number of axes available If `weighted` is True and no `sort_category` is provided If `weighted` is True and the values under `sort_category` are not numerical If `coords` and `metadata_map` does not have samples in common """ # Should be defined by the derived classes _alg_name: str | None = None def __init__( self, coords, prop_expl, metadata_map, trajectory_categories=None, sort_category=None, axes=3, weighted=False, ): """Construct all the necessary attributes for the GradientANOVA object.""" if not trajectory_categories: # If trajectory_categories is not provided, use all the categories # present in the metadata map trajectory_categories = metadata_map.keys() else: # Check that trajectory_categories are in metadata_map for category in trajectory_categories: if category not in metadata_map: raise ValueError("Category %s not present in metadata." % category) # Check that sort_categories is in metadata_map if sort_category and sort_category not in metadata_map: raise ValueError( "Sort category %s not present in metadata." % sort_category ) if axes == 0: # If axes == 0, we should compute the trajectories for all axes axes = len(prop_expl) elif axes > len(prop_expl) or axes < 0: # Axes should be 0 <= axes <= len(prop_expl) raise ValueError( "axes should be between 0 and the max number of " "axes available (%d), found: %d " % (len(prop_expl), axes) ) # Restrict coordinates to those axes that we actually need to compute self._coords = coords.loc[:, : axes - 1] self._prop_expl = prop_expl[:axes] self._metadata_map = metadata_map self._weighted = weighted # Remove any samples from coords not present in mapping file # and remove any samples from metadata_map not present in coords self._normalize_samples() # Create groups self._make_groups(trajectory_categories, sort_category) # Compute the weighting_vector self._weighting_vector = None if weighted: if not sort_category: raise ValueError( "You should provide a sort category if you " "want to weight the trajectories" ) try: self._weighting_vector = self._metadata_map[sort_category].astype( np.float64 ) except ValueError: raise ValueError("The sorting category must be numeric") # Initialize the message buffer self._message_buffer = [] def get_trajectories(self): r"""Compute the trajectories for each group and category and run ANOVA. More specifically, compute the trajectories for each group in each category and run ANOVA over the results to test group independence. Returns ------- GradientANOVAResults An instance of GradientANOVAResults holding the results. """ result = GradientANOVAResults(self._alg_name, self._weighted, []) # Loop through all the categories that we should compute # the trajectories for cat, cat_groups in self._groups.items(): # Loop through all the category values present in the current # category and compute the trajectory for each of them res_by_group = [] for group in sorted(cat_groups, key=lambda k: str(k)): res_by_group.append( self._get_group_trajectories(group, cat_groups[group]) ) result.categories.append(_ANOVA_trajectories(cat, res_by_group)) return result def _normalize_samples(self): r"""Ensure `self._coords` and `self._metadata_map` have the same sample ids. Raises ------ ValueError If `coords` and `metadata_map` does not have samples in common """ # Figure out the sample ids in common coords_sample_ids = set(self._coords.index) mm_sample_ids = set(self._metadata_map.index) sample_ids = coords_sample_ids.intersection(mm_sample_ids) # Check if they actually have sample ids in common if not sample_ids: raise ValueError("Coordinates and metadata map had no samples in common") # pandas no longer allows use of set with .loc sample_ids = list(sample_ids) # Need to take a subset of coords if coords_sample_ids != sample_ids: self._coords = self._coords.loc[sample_ids] # Need to take a subset of metadata_map if mm_sample_ids != sample_ids: self._metadata_map = self._metadata_map.loc[sample_ids] def _make_groups(self, trajectory_categories, sort_category): r"""Group sample ids in `self._metadata_map` by `trajectory_categories` values. Creates `self._groups`, a dictionary keyed by category and values are dictionaries in which the keys represent the group name within the category and values are ordered lists of sample ids If `sort_category` is not None, the sample ids are sorted based on the values under this category in the metadata map. Otherwise, they are sorted using the sample id. Parameters ---------- trajectory_categories : list of str A list of metadata categories to use to create the groups. Default: None, compute all of them sort_category : str or None The category from self._metadata_map to use to sort groups """ # If sort_category is provided, we used the value of such category to # sort. Otherwise, we use the sample id. if sort_category: def sort_val(sid): return self._metadata_map[sort_category][sid] else: def sort_val(sid): return sid self._groups = defaultdict(dict) for cat in trajectory_categories: # Group samples by category gb = self._metadata_map.groupby(cat) for g, df in gb: self._groups[cat][g] = realsorted(df.index, key=sort_val) def _get_group_trajectories(self, group_name, sids): r"""Compute trajectory results for `group_name` containing the samples `sids`. Weights the data if `self._weighted` is True and ``len(sids) > 1`` Parameters ---------- group_name : str The name of the group sids : list of str The sample ids in the group Returns ------- GroupResults The trajectory results for the given group Raises ------ RuntimeError If sids is an empty list """ # We multiply the coord values with the prop_expl trajectories = self._coords.loc[sids] * self._prop_expl if trajectories.empty: # Raising a RuntimeError since in a usual execution this should # never happen. The only way this can happen is if the user # directly calls this method, which shouldn't be done # (that's why the method is private) raise RuntimeError( "No samples to process, an empty list cannot be processed" ) # The weighting can only be done over trajectories with a length # greater than 1 if self._weighted and len(sids) > 1: trajectories_copy = deepcopy(trajectories) try: trajectories = _weight_by_vector( trajectories_copy, self._weighting_vector[sids] ) except (FloatingPointError, ValueError): self._message_buffer.append( "Could not weight group, no gradient in the the weighting vector.\n" ) trajectories = trajectories_copy return self._compute_trajectories_results(group_name, trajectories.loc[sids]) def _compute_trajectories_results(self, group_name, trajectories): r"""Do the actual trajectories computation over trajectories. Parameters ---------- group_name : str The name of the group trajectories : pandas.DataFrame The sorted trajectories for each sample in the group Raises ------ NotImplementedError This is the base class """ raise NotImplementedError("No algorithm is implemented on the base class.") class AverageGradientANOVA(GradientANOVA): r"""Perform trajectory analysis using the RMS average algorithm. For each group in a category, it computes the average point among the samples in such group and then computes the norm of each sample from the averaged one. See Also -------- GradientANOVA """ _alg_name = "avg" def _compute_trajectories_results(self, group_name, trajectories): r"""Do the actual trajectory computation over trajectories. Parameters ---------- group_name : str The name of the group trajectories : pandas.DataFrame The sorted trajectories for each sample in the group Returns ------- GroupResults The trajectory results for `group_name` using the average trajectories method """ center = np.average(trajectories, axis=0) if len(trajectories) == 1: trajectory = np.array([np.linalg.norm(center)]) calc = {"avg": trajectory[0]} else: trajectory = np.array( [ np.linalg.norm(row[1].to_numpy() - center) for row in trajectories.iterrows() ] ) calc = {"avg": np.average(trajectory)} msg = "".join(self._message_buffer) if self._message_buffer else None # Reset the message buffer self._message_buffer = [] return GroupResults(group_name, trajectory, np.mean(trajectory), calc, msg) class TrajectoryGradientANOVA(GradientANOVA): r"""Perform trajectory analysis using the RMS trajectory algorithm. For each group in a category, each component of the result trajectory is computed as taking the sorted list of samples in the group and taking the norm of the coordinates of the 2nd sample minus 1st sample, 3rd sample minus 2nd sample and so on. See Also -------- GradientANOVA """ _alg_name = "trajectory" def _compute_trajectories_results(self, group_name, trajectories): r"""Do the actual trajectory computation over trajectories. Parameters ---------- group_name : str The name of the group trajectories : pandas.DataFrame The sorted trajectories for each sample in the group Returns ------- GroupResults The trajectory results for `group_name` using the trajectory method """ if len(trajectories) == 1: trajectory = np.array([np.linalg.norm(trajectories)]) calc = {"2-norm": trajectory[0]} else: # Loop through all the rows in trajectories and create '2-norm' # by taking the norm of the 2nd row - 1st row, 3rd row - 2nd row... trajectory = np.array( [ np.linalg.norm( trajectories.iloc[i + 1].to_numpy() - trajectories.iloc[i].to_numpy() ) for i in range(len(trajectories) - 1) ] ) calc = {"2-norm": np.linalg.norm(trajectory)} msg = "".join(self._message_buffer) if self._message_buffer else None # Reset the message buffer self._message_buffer = [] return GroupResults(group_name, trajectory, np.mean(trajectory), calc, msg) class FirstDifferenceGradientANOVA(GradientANOVA): r"""Perform trajectory analysis using the first difference algorithm. It calculates the norm for all the time-points and then calculates the first difference for each resulting point See Also -------- GradientANOVA """ _alg_name = "diff" def _compute_trajectories_results(self, group_name, trajectories): r"""Do the actual trajectory computation over trajectories. Parameters ---------- group_name : str The name of the group trajectories : pandas.DataFrame The sorted trajectories for each sample in the group Returns ------- GroupResults The trajectory results for `group_name` using the first difference method """ if len(trajectories) == 1: trajectory = np.array([np.linalg.norm(trajectories)]) calc = {"mean": trajectory[0], "std": 0} elif len(trajectories) == 2: trajectory = np.array([np.linalg.norm(trajectories[1] - trajectories[0])]) calc = {"mean": trajectory[0], "std": 0} else: vec_norm = np.array( [ np.linalg.norm( trajectories.iloc[i + 1].to_numpy() - trajectories.iloc[i].to_numpy() ) for i in range(len(trajectories) - 1) ] ) trajectory = np.diff(vec_norm) calc = {"mean": np.mean(trajectory), "std": np.std(trajectory)} msg = "".join(self._message_buffer) if self._message_buffer else None # Reset the message buffer self._message_buffer = [] return GroupResults(group_name, trajectory, np.mean(trajectory), calc, msg) class WindowDifferenceGradientANOVA(GradientANOVA): r"""Perform trajectory analysis using the modified first difference algorithm. It calculates the norm for all the time-points and subtracts the mean of the next number of elements specified in `window_size` and the current element. Parameters ---------- coords : pandas.DataFrame The coordinates for each sample id prop_expl : array like The numpy 1-D array with the proportion explained by each axis in coords metadata_map : pandas.DataFrame The metadata map, indexed by sample ids and columns are metadata categories window_size : int or long The window size to use while computing the differences Raises ------ ValueError If the window_size is not a positive integer See Also -------- GradientANOVA """ _alg_name = "wdiff" def __init__(self, coords, prop_expl, metadata_map, window_size, **kwargs): """Build all the attributes for the WindowDifferenceGradientANOVA object.""" super(WindowDifferenceGradientANOVA, self).__init__( coords, prop_expl, metadata_map, **kwargs ) if not isinstance(window_size, Integral) or window_size < 1: raise ValueError("The window_size must be a positive integer") self._window_size = window_size def _compute_trajectories_results(self, group_name, trajectories): r"""Do the actual trajectory computation over trajectories. If the first difference cannot be calculated of the provided window size, no difference is applied and a message is added to the results. Parameters ---------- group_name : str The name of the group trajectories : pandas.DataFrame The sorted trajectories for each sample in the group Returns ------- GroupResults The trajectory results for `group_name` using the windowed difference method """ if len(trajectories) == 1: trajectory = np.array([np.linalg.norm(trajectories)]) calc = {"mean": trajectory, "std": 0} elif len(trajectories) == 2: trajectory = np.array([np.linalg.norm(trajectories[1] - trajectories[0])]) calc = {"mean": trajectory, "std": 0} else: vec_norm = np.array( [ np.linalg.norm( trajectories.iloc[i + 1].to_numpy() - trajectories.iloc[i].to_numpy() ) for i in range(len(trajectories) - 1) ] ) # windowed first differences won't be able on every group, # specially given the variation of size that a trajectory tends # to have if len(vec_norm) <= self._window_size: trajectory = vec_norm self._message_buffer.append( "Cannot calculate the first " "difference with a window of size " "(%d)." % self._window_size ) else: # Replicate the last element as many times as required for idx in range(0, self._window_size): vec_norm = np.append(vec_norm, vec_norm[-1:], axis=0) trajectory = [] for idx in range(0, len(vec_norm) - self._window_size): # Meas has to be over axis 0 so it handles arrays of arrays element = np.mean( vec_norm[(idx + 1) : (idx + 1 + self._window_size)], axis=0 ) trajectory.append(element - vec_norm[idx]) trajectory = np.array(trajectory) calc = {"mean": np.mean(trajectory), "std": np.std(trajectory)} msg = "".join(self._message_buffer) if self._message_buffer else None # Reset the message buffer self._message_buffer = [] return GroupResults(group_name, trajectory, np.mean(trajectory), calc, msg) scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/000077500000000000000000000000001520735541300227665ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/__init__.py000066400000000000000000000124521520735541300251030ustar00rootroot00000000000000r"""Ordination methods (:mod:`skbio.stats.ordination`) ================================================== .. currentmodule:: skbio.stats.ordination This module provides functions for ordination -- a category of methods that aim at arranging data so that similar data points are proximate to each other. Ordination can preserve and represent the structure of high-dimensional data within a low-dimensional space, thereby facilitating visual exploration and statistical analysis. Mathematically, ordination shares similarities with, and is in multiple respects equivalent to, embedding and dimensionality reduction. While all three aim to represent high-dimensional data in a lower-dimensional space, the term "ordination" is mainly used in the field of ecology to reveal patterns such as groups or gradients underlying community data. However, the ordination methods implemented in scikit-bio are versatile, serving not only ecological studies but also broader applications in scientific computing. Multidimensional scaling ------------------------ .. autosummary:: :toctree: pcoa pcoa_biplot .. TODO: re-add "Dimensionality reduction" (PCA) section when RCLR and RPCA are finished. Correspondence analysis ----------------------- .. autosummary:: :toctree: ca Canonical analysis ------------------ .. autosummary:: :toctree: cca rda Multimodal embedding -------------------- .. autosummary:: :toctree: mmvec MMvecResult Ordination results ------------------ .. autosummary:: :toctree: OrdinationResults Utility functions ----------------- .. autosummary:: :toctree: mean_and_std corr scale svd_rank e_matrix f_matrix Examples -------- This is an artificial dataset (table 11.3 in [1]_) that represents fish abundance in different sites (`Y`, the response variables) and environmental variables (`X`, the explanatory variables). >>> import numpy as np >>> import pandas as pd First we need to construct our explanatory variable dataset `X`. >>> X = np.array([[1.0, 0.0, 1.0, 0.0], ... [2.0, 0.0, 1.0, 0.0], ... [3.0, 0.0, 1.0, 0.0], ... [4.0, 0.0, 0.0, 1.0], ... [5.0, 1.0, 0.0, 0.0], ... [6.0, 0.0, 0.0, 1.0], ... [7.0, 1.0, 0.0, 0.0], ... [8.0, 0.0, 0.0, 1.0], ... [9.0, 1.0, 0.0, 0.0], ... [10.0, 0.0, 0.0, 1.0]]) >>> transects = ['depth', 'substrate_coral', 'substrate_sand', ... 'substrate_other'] >>> sites = ['site1', 'site2', 'site3', 'site4', 'site5', 'site6', 'site7', ... 'site8', 'site9', 'site10'] >>> X = pd.DataFrame(X, sites, transects) Then we need to create a dataframe with the information about the species observed at different sites. >>> species = ['specie1', 'specie2', 'specie3', 'specie4', 'specie5', ... 'specie6', 'specie7', 'specie8', 'specie9'] >>> Y = np.array([[1, 0, 0, 0, 0, 0, 2, 4, 4], ... [0, 0, 0, 0, 0, 0, 5, 6, 1], ... [0, 1, 0, 0, 0, 0, 0, 2, 3], ... [11, 4, 0, 0, 8, 1, 6, 2, 0], ... [11, 5, 17, 7, 0, 0, 6, 6, 2], ... [9, 6, 0, 0, 6, 2, 10, 1, 4], ... [9, 7, 13, 10, 0, 0, 4, 5, 4], ... [7, 8, 0, 0, 4, 3, 6, 6, 4], ... [7, 9, 10, 13, 0, 0, 6, 2, 0], ... [5, 10, 0, 0, 2, 4, 0, 1, 3]]) >>> Y = pd.DataFrame(Y, sites, species) We can now perform canonical correspondence analysis. Matrix `X` contains a continuous variable (depth) and a categorical one (substrate type) encoded using a one-hot encoding. >>> from skbio.stats.ordination import cca We explicitly need to avoid perfect collinearity, so we'll drop one of the substrate types (the last column of `X`). >>> del X['substrate_other'] >>> ordination_result = cca(Y, X, scaling=2) Exploring the results we see that the first three axes explain about 80% of all the variance. >>> ordination_result.proportion_explained CCA1 0.466911 CCA2 0.238327 CCA3 0.100548 CCA4 0.104937 CCA5 0.044805 CCA6 0.029747 CCA7 0.012631 CCA8 0.001562 CCA9 0.000532 dtype: float64 References ---------- .. [1] Legendre P. and Legendre L. 1998. Numerical Ecology. Elsevier, Amsterdam. """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._redundancy_analysis import rda from ._correspondence_analysis import ca from ._canonical_correspondence_analysis import cca from ._principal_coordinate_analysis import pcoa, pcoa_biplot from ._principal_component_analysis import pca from ._ordination_results import OrdinationResults from ._mmvec import mmvec, MMvec, MMvecResult from ._utils import ( mean_and_std, scale, svd_rank, corr, e_matrix, f_matrix, center_distance_matrix, ) __all__ = [ "ca", "rda", "cca", # "pca", "pcoa", "pcoa_biplot", "mmvec", "MMvec", "MMvecResult", "OrdinationResults", "mean_and_std", "scale", "svd_rank", "corr", "e_matrix", "f_matrix", "center_distance_matrix", ] scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/_canonical_correspondence_analysis.py000066400000000000000000000217271520735541300324330ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np import pandas as pd from scipy.linalg import svd, lstsq from ._ordination_results import OrdinationResults from ._utils import corr, svd_rank, scale from skbio.table._tabular import _create_table, _create_table_1d, _ingest_table def cca( y, x, scaling=1, sample_ids=None, feature_ids=None, constraint_ids=None, output_format=None, ): r"""Compute canonical (also known as constrained) correspondence analysis. Canonical (or constrained) correspondence analysis is a multivariate ordination technique. It appeared in community ecology [1]_ and relates community composition to the variation in the environment (or in other factors). It works from data on abundances or counts of samples and constraints variables, and outputs ordination axes that maximize sample separation among species. It is better suited to extract the niches of taxa than linear multivariate methods because it assumes unimodal response curves (habitat preferences are often unimodal functions of habitat variables [2]_). As more environmental variables are added, the result gets more similar to unconstrained ordination, so only the variables that are deemed explanatory should be included in the analysis. Parameters ---------- y : table_like Samples by features table (n, m). See :ref:`supported formats `. x : table_like Samples by constraints table (n, q). See above. scaling : int, {1, 2}, optional Scaling type 1 maintains :math:`\chi^2` distances between rows. Scaling type 2 preserves :math:`\chi^2` distances between columns. For a more detailed explanation of the interpretation, check Legendre & Legendre 1998, section 9.4.3. constraint_ids : list of str, optional List of identifiers for metadata variables or constraints. If not provided implicitly by the input data structure or explicitly by the user, defaults to integers starting at zero. sample_ids, feature_ids, output_format : optional Standard table parameters. See :ref:`table_params` for details. Returns ------- OrdinationResults Object that stores the cca results. Raises ------ ValueError If `x` and `y` have different number of rows If `y` contains negative values If `y` contains a row of only 0's. NotImplementedError If scaling is not 1 or 2. See Also -------- ca rda OrdinationResults Notes ----- The algorithm is based on [3]_, \S 11.2, and is expected to give the same results as ``cca(y, x)`` in R's package vegan, except that this implementation won't drop constraining variables due to perfect collinearity: the user needs to choose which ones to input. Canonical *correspondence* analysis shouldn't be confused with canonical *correlation* analysis (CCorA, but sometimes called CCA), a different technique to search for multivariate relationships between two datasets. Canonical correlation analysis is a statistical tool that, given two vectors of random variables, finds linear combinations that have maximum correlation with each other. In some sense, it assumes linear responses of "species" to "environmental variables" and is not well suited to analyze ecological data. References ---------- .. [1] Cajo J. F. Ter Braak, "Canonical Correspondence Analysis: A New Eigenvector Technique for Multivariate Direct Gradient Analysis", Ecology 67.5 (1986), pp. 1167-1179. .. [2] Cajo J.F. Braak and Piet F.M. Verdonschot, "Canonical correspondence analysis and related multivariate methods in aquatic ecology", Aquatic Sciences 57.3 (1995), pp. 255-289. .. [3] Legendre P. and Legendre L. 1998. Numerical Ecology. Elsevier, Amsterdam. """ Y, y_sample_ids, feature_ids = _ingest_table( y, sample_ids=sample_ids, feature_ids=feature_ids ) X, x_sample_ids, constraint_ids = _ingest_table( x, sample_ids=sample_ids, feature_ids=constraint_ids ) # Perform parameter sanity checks if X.shape[0] != Y.shape[0]: raise ValueError( "The samples by features table 'y' and the samples by" " constraints table 'x' must have the same number of " " rows. 'y': {0} 'x': {1}".format(X.shape[0], Y.shape[0]) ) if Y.min() < 0: raise ValueError("The samples by features table 'y' must be nonnegative") row_max = Y.max(axis=1) if np.any(row_max <= 0): # Or else the lstsq call to compute Y_hat breaks raise ValueError( "The samples by features table 'y' cannot contain a row with only 0's" ) if scaling not in {1, 2}: raise NotImplementedError("Scaling {0} not implemented.".format(scaling)) # Step 1 (similar to Pearson chi-square statistic) grand_total = Y.sum() Q = Y / grand_total # Relative frequencies of Y (contingency table) # Features and sample weights (marginal totals) column_marginals = Q.sum(axis=0) row_marginals = Q.sum(axis=1) # Formula 9.32 in Lagrange & Lagrange (1998). Notice that it's an # scaled version of the contribution of each cell towards Pearson # chi-square statistic. expected = np.outer(row_marginals, column_marginals) Q_bar = (Q - expected) / np.sqrt(expected) # Step 2. Standardize columns of X with respect to sample weights, # using the maximum likelihood variance estimator (Legendre & # Legendre 1998, p. 595) X = scale(X, weights=row_marginals, ddof=0) # Step 3. Weighted multiple regression. X_weighted = row_marginals[:, None] ** 0.5 * X B, _, rank_lstsq, _ = lstsq(X_weighted, Q_bar) Y_hat = X_weighted.dot(B) Y_res = Q_bar - Y_hat # Step 4. Eigenvalue decomposition u, s, vt = svd(Y_hat, full_matrices=False) rank = svd_rank(Y_hat.shape, s) s = s[:rank] u = u[:, :rank] vt = vt[:rank] U = vt.T # Step 5. Eq. 9.38 U_hat = Q_bar.dot(U) * s**-1 # Residuals analysis u_res, s_res, vt_res = svd(Y_res, full_matrices=False) rank = svd_rank(Y_res.shape, s_res) s_res = s_res[:rank] u_res = u_res[:, :rank] vt_res = vt_res[:rank] U_res = vt_res.T U_hat_res = Y_res.dot(U_res) * s_res**-1 eigenvalues = np.r_[s, s_res] ** 2 # Scalings (p. 596 L&L 1998): # feature scores, scaling 1 V = (column_marginals**-0.5)[:, None] * U # sample scores, scaling 2 V_hat = (row_marginals**-0.5)[:, None] * U_hat # sample scores, scaling 1 F = V_hat * s # feature scores, scaling 2 F_hat = V * s # Sample scores which are linear combinations of constraint # variables Z_scaling1 = (row_marginals**-0.5)[:, None] * Y_hat.dot(U) Z_scaling2 = Z_scaling1 * s**-1 # Feature residual scores, scaling 1 V_res = (column_marginals**-0.5)[:, None] * U_res # Sample residual scores, scaling 2 V_hat_res = (row_marginals**-0.5)[:, None] * U_hat_res # Sample residual scores, scaling 1 F_res = V_hat_res * s_res # Feature residual scores, scaling 2 F_hat_res = V_res * s_res eigvals = eigenvalues if scaling == 1: features_scores = np.hstack((V, V_res)) sample_scores = np.hstack((F, F_res)) sample_constraints = np.hstack((Z_scaling1, F_res)) elif scaling == 2: features_scores = np.hstack((F_hat, F_hat_res)) sample_scores = np.hstack((V_hat, V_hat_res)) sample_constraints = np.hstack((Z_scaling2, V_hat_res)) biplot_scores = corr(X_weighted, u) pc_ids = ["CCA%d" % (i + 1) for i in range(len(eigenvalues))] eigvals = _create_table_1d(eigenvalues, index=pc_ids, backend=output_format) samples = _create_table( sample_scores, columns=pc_ids, index=y_sample_ids, backend=output_format ) features = _create_table( features_scores, columns=pc_ids, index=feature_ids, backend=output_format ) biplot_scores = _create_table( biplot_scores, index=constraint_ids, columns=pc_ids[: biplot_scores.shape[1]], backend=output_format, ) sample_constraints = _create_table( sample_constraints, index=y_sample_ids, columns=pc_ids, backend=output_format ) return OrdinationResults( "CCA", "Canonical Correspondence Analysis", eigvals, samples, sample_ids=y_sample_ids, features=features, feature_ids=feature_ids, biplot_scores=biplot_scores, sample_constraints=sample_constraints, constraint_ids=constraint_ids, proportion_explained=eigvals / eigvals.sum(), ) scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/_correspondence_analysis.py000066400000000000000000000170471520735541300304240ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from scipy.linalg import svd from ._ordination_results import OrdinationResults from ._utils import svd_rank from skbio.table._tabular import _create_table, _create_table_1d, _ingest_table def ca(X, scaling=1, sample_ids=None, feature_ids=None, output_format=None): r"""Compute correspondence analysis. Correspondence analysis is a multivariate statistical technique for ordination. In general, rows in the data table will correspond to samples and columns to features, but the method is symmetric. In order to measure the correspondence between rows and columns, the :math:`\chi^2` distance is used, and those distances are preserved in the transformed space. The :math:`\chi^2` distance doesn't take double zeros into account, and so it is expected to produce better ordination that PCA when the data has lots of zero values. It is related to Principal Component Analysis (PCA) but it should be preferred in the case of steep or long gradients, that is, when there are many zeros in the input data matrix. Parameters ---------- X : table_like of shape (n_samples, n_features) Input data table. See :ref:`supported formats `. Data must be non-negative and dimensionally homogeneous (numeric or binary). scaling : {1, 2} Scaling type 1 maintains :math:`\chi^2` distances between rows. Scaling type 2 preserves :math:`\chi^2` distances between columns. For a more detailed explanation of the interpretation, check notes below and Legendre & Legendre 1998, section 9.4.3. sample_ids, feature_ids, output_format : optional Standard table parameters. See :ref:`table_params` for details. Returns ------- OrdinationResults Object that stores the computed eigenvalues, the transformed sample coordinates, the transformed features coordinates and the proportion explained. Raises ------ NotImplementedError If the scaling value is not either `1` or `2`. ValueError If any of the input matrix elements are negative. See Also -------- cca rda OrdinationResults Notes ----- The algorithm is based on [1]_, \S 9.4.1., and is expected to give the same results as ``cca(X)`` in R's package vegan. In Scaling type 1, the euclidean distances between rows in the transformed space equal their :math:`\chi^2` distances in the original space. Rows (samples) near a column (features) indicate high contributions from that feature. In Scaling type 2, the euclidean distances between columns in the transformed space equal their :math:`\chi^2` distances in the original space. Columns (features) near a row (sample) indicate higher abundance in that sample. Other types of scalings are currently not implemented, as they are less used by ecologists (Legendre & Legendre 1998, p. 456). Features far from the center of the biplot and far from its edges often exhibit better relationships than features either in the center (may represent multimodal features, not related to the shown ordination axes) or the edges (sparse features). References ---------- .. [1] Legendre P. and Legendre L. 1998. Numerical Ecology. Elsevier, Amsterdam. """ if scaling not in {1, 2}: raise NotImplementedError("Scaling {0} not implemented.".format(scaling)) short_method_name = "CA" long_method_name = "Correspondence Analysis" # we deconstruct the dataframe to avoid duplicating the data and be able # to perform operations on the matrix X, row_ids, column_ids = _ingest_table( X, sample_ids=sample_ids, feature_ids=feature_ids ) # Correspondence Analysis r, c = X.shape if X.min() < 0: raise ValueError("Input matrix elements must be non-negative.") # Step 1 (similar to Pearson chi-square statistic) grand_total = X.sum() Q = X / grand_total column_marginals = Q.sum(axis=0) row_marginals = Q.sum(axis=1) # Formula 9.32 in Lagrange & Lagrange (1998). Notice that it's # an scaled version of the contribution of each cell towards # Pearson chi-square statistic. expected = np.outer(row_marginals, column_marginals) Q_bar = (Q - expected) / np.sqrt(expected) # Eq. 9.32 # Step 2 (Singular Value Decomposition) U_hat, W, Ut = svd(Q_bar, full_matrices=False) # Due to the centering, there are at most min(r, c) - 1 non-zero # eigenvalues (which are all positive) rank = svd_rank(Q_bar.shape, W) assert rank <= min(r, c) - 1 U_hat = U_hat[:, :rank] W = W[:rank] U = Ut[:rank].T # Both scalings are a bit intertwined, so we'll compute both and # then choose V = column_marginals[:, None] ** -0.5 * U V_hat = row_marginals[:, None] ** -0.5 * U_hat F = V_hat * W # According to Formula 9.43, this should hold # assert np.allclose(F, (row_marginals**-1)[:, None] * Q.dot(V)) # but it doesn't (notice that W**2==Lambda): # (9.43a) F = V_hat W = D(p_i+)^{-1/2} U_hat W # = D(p_i+)^{-1/2} Q_bar U W^{-1} W (substituting 9.38) # = D(p_i+)^{-1/2} Q_bar U # (9.43b) F = D(p_i+)^{-1} Q V # = D(p_i+)^{-1} Q D(p_+j)^{-1/2} U (substituting 9.41) # = D(p_i+)^{-1/2} D(p_i+)^{-1/2} Q D(p_+j)^{-1/2} U # = D(p_i+)^{-1/2} Q_tilde U (using 9.40) # It holds if we replace Q in 9.43b with Q after centering, ie # assert np.allclose( # F, # (row_marginals**-1)[:, None] * (Q - expected).dot(V)) # Comparing results with vegan and the examples in the book, 9.43a # is the right one. The same issue happens in 9.44, where also # 9.44a is the one that matches vegan's output. # (9.44a) F_hat = V W = D(p_+j)^{-1/2} U W # = D(p_+j)^{-1/2} Q_bar' U_hat W^{-1} W (using 9.39) # = D(p_+j)^{-1/2} Q_bar' U_hat # (9.44b) F_hat = D(p_+j)^{-1} Q' V_hat # = D(p_+j)^{-1/2} Q_tilde' U_hat (using 9.40 and 9.42) F_hat = V * W # Eigenvalues eigvals = W**2 # features scores features_scores = [V, F_hat][scaling - 1] # sample scores (weighted averages of features scores) sample_scores = [F, V_hat][scaling - 1] # build the OrdinationResults object sample_columns = [ "%s%d" % (short_method_name, i + 1) for i in range(sample_scores.shape[1]) ] feature_columns = [ "%s%d" % (short_method_name, i + 1) for i in range(features_scores.shape[1]) ] eigvals = _create_table_1d( eigvals, index=["%s%d" % (short_method_name, i + 1) for i in range(eigvals.shape[0])], backend=output_format, ) samples = _create_table( sample_scores, index=row_ids, columns=sample_columns, backend=output_format ) features = _create_table( features_scores, index=column_ids, columns=feature_columns, backend=output_format, ) return OrdinationResults( short_method_name, long_method_name, eigvals, samples=samples, sample_ids=row_ids, features=features, feature_ids=column_ids, proportion_explained=eigvals / eigvals.sum(), ) scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/_cutils.pyx000066400000000000000000000121021520735541300251660ustar00rootroot00000000000000# ----------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ----------------------------------------------------------------------------- import numpy as np cimport cython from cython.parallel import prange from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free ctypedef fused TReal: float double @cython.boundscheck(False) @cython.wraparound(False) def e_matrix_means_cy(TReal[:, ::1] mat, TReal[:, ::1] centered, TReal[::1] row_means): """ Compute E matrix from a distance matrix, and also compute the means in the process. Squares and divides by -2 the input elementwise. Eq. 9.20 in Legendre & Legendre 1998. Parameters ---------- mat : 2D array_like Distance matrix. centered : 2D array_like Output, E matrix. Must be pre-allocated and same shape as mat. Can point to mat (i.e. in-place) row_means : 1D_array_like Output, Mean values of each row in `centered` Returns ------- global_mean : real Global mean value """ cdef Py_ssize_t n_samples = mat.shape[0] cdef Py_ssize_t d2 = mat.shape[1] cdef Py_ssize_t d3 = centered.shape[1] cdef Py_ssize_t d4 = centered.shape[1] cdef Py_ssize_t d5 = row_means.shape[0] assert n_samples == d2 assert n_samples == d3 assert n_samples == d4 assert n_samples == d5 cdef Py_ssize_t row,col cdef long double row_sum cdef TReal el0 cdef long double global_sum = 0.0 for row in prange(n_samples, nogil=True): row_sum = 0.0 for col in range(n_samples): el0 = mat[row,col] el0 = -0.5*el0*el0 centered[row,col] = el0 # Note: do not use +=, so it is not flagged as a global reduction row_sum = row_sum + el0 global_sum += row_sum row_means[row] = row_sum/n_samples cdef TReal global_mean = (global_sum/n_samples)/n_samples return global_mean @cython.boundscheck(False) @cython.wraparound(False) def f_matrix_inplace_cy(TReal[::1] row_means, TReal global_mean, TReal[:, ::1] centered): """ Compute F matrix from E matrix inplace. Centering step: for each element, the mean of the corresponding row and column are subtracted, and the mean of the whole matrix is added. Eq. 9.21 in Legendre & Legendre 1998. Modified from :func:`skbio.stats.ordination.f_matrix_inplace` function, Parameters ---------- row_means : 1D_array_like Mean values of each row in `centered` global_mean : real Global mean value in `centered` centered : 2D array_like, must be symmetric In, a matrix representing the "E matrix" as described above. Out, the centered matrix """ cdef Py_ssize_t n_samples = centered.shape[0] cdef Py_ssize_t d2 = centered.shape[1] cdef Py_ssize_t d3 = row_means.shape[0] assert n_samples == d2 assert n_samples == d3 cdef Py_ssize_t trow,tcol,row,col cdef Py_ssize_t trow_max,tcol_max cdef TReal gr_mean # use a tiled pattern to maximize locality of row_means for trow in prange(0, n_samples, 24, nogil=True): trow_max = min(trow+24, n_samples) for tcol in range(0, n_samples, 24): tcol_max = min(tcol+24, n_samples) for row in range(trow, trow_max, 1): gr_mean = global_mean - row_means[row] for col in range(tcol, tcol_max, 1): # Note: do not use +=, so it is not flagged as a global reduction centered[row,col] = centered[row,col] + (gr_mean - row_means[col]) @cython.boundscheck(False) @cython.wraparound(False) def center_distance_matrix_cy(TReal[:, ::1] mat, TReal[:, ::1] centered): """ Centers a distance matrix. Note: If the used distance was euclidean, pairwise distances needn't be computed from the data table Y because F_matrix = Y.dot(Y.T) (if Y has been centered). But since we're expecting distance_matrix to be non-euclidian, we do the following computation as per Numerical Ecology (Legendre & Legendre 1998). Parameters ---------- mat : 2D array_like Distance matrix. centered : 2D array_like Output centered matrix. Must be pre-allocated and same shape as mat. Can point to mat (i.e. in-place) """ cdef Py_ssize_t n_samples = mat.shape[0] cdef Py_ssize_t d2 = mat.shape[1] cdef Py_ssize_t d3 = centered.shape[1] cdef Py_ssize_t d4 = centered.shape[1] assert n_samples == d2 assert n_samples == d3 assert n_samples == d4 cdef TReal global_mean if TReal is float: dtype_real = np.float32 else: dtype_real = np.float64 row_means_np = np.zeros((n_samples,), dtype=dtype_real) cdef TReal[::1] row_means = row_means_np global_mean = e_matrix_means_cy(mat, centered, row_means) f_matrix_inplace_cy(row_means, global_mean, centered) scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/_mmvec.py000066400000000000000000001703621520735541300246170ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """MMvec - Microbe-Metabolite Vectors. This module implements MMvec for learning joint embeddings of two omics modalities from their co-occurrence patterns. This implementation was adopted, modified and improved from the original mmvec package, licensed under BSD-3-Clause: - https://github.com/biocore/mmvec """ from __future__ import annotations from typing import TYPE_CHECKING import numpy as np import pandas as pd from scipy.sparse import coo_array from skbio._base import SkbioObject from skbio.stats.composition import clr_inv as softmax from skbio.stats.composition import ilr_inv from skbio.util import get_rng from skbio.table._tabular import _ingest_table, _create_table, _create_table_1d if TYPE_CHECKING: # pragma: no cover from skbio.util._typing import SeedLike, TableLike Grad4Tuple = tuple[ np.ndarray, # dx_main np.ndarray, # dx_bias np.ndarray, # dy_main np.ndarray, # dy_bias ] def mmvec( X: TableLike, Y: TableLike, dimensions: int = 3, optimizer: str = "lbfgs", max_iter: int = 1000, x_prior_mean: float = 0.0, x_prior_scale: float = 1.0, y_prior_mean: float = 0.0, y_prior_scale: float = 1.0, learning_rate: float = 1e-3, batch_size: int = 50, beta_1: float = 0.9, beta_2: float = 0.95, clipnorm: float = 10.0, batch_norm: str = "unbiased", seed: SeedLike | None = None, verbose: bool = False, output_format: str | None = None, ) -> MMvecResult: r"""Perform multiomics Microbe-Metabolite Vectors (MMvec) analysis. MMvec learns joint embeddings of two feature sets from their co-occurrence patterns using a multinomial likelihood model [1]_. The model learns: .. math:: P(Y_j | X_i) = \text{softmax}(\hat{X}_i \cdot \hat{Y}_j + b_{\hat{X}_i} + b_{\hat{Y}_j}) where :math:`\hat{X}_i` is the learned embedding vector of feature :math:`i` in the X modality (e.g., microbiome), :math:`\hat{Y}_j` is the learned embedding vector of feature :math:`j` in the Y modality (e.g., metabolome), and :math:`b_{\hat{X}_i}`, :math:`b_{\hat{Y}_j}` are learned bias terms. While MMvec was originally developed to analyze microbe-metabolite co-occurrence, this method is **generic** and can be applied to any two modalities that can be represented as compositional (count-based) data and share the same samples. .. versionadded:: 0.7.3 Parameters ---------- X : table_like of shape (n_samples, n_features_x) Abundance counts for the first modality (e.g., microbes). This modality is treated as the "conditioning" variable. See :ref:`supported formats `. Y : table_like of shape (n_samples, n_features_y) Abundance counts for the second modality (e.g., metabolites). This modality is treated as the "conditioned" variable. See above. Must have the same samples as ``X``. dimensions : int, optional Number of latent dimensions for embeddings. Default is 3. optimizer : {'lbfgs', 'adam'}, optional Optimization algorithm to use. Default is 'lbfgs'. - 'lbfgs': L-BFGS-B quasi-Newton method. Recommended for most cases. Typically converges in 50-200 iterations. Deterministic. - 'adam': Stochastic gradient descent with Adam. Use for very large datasets or when stochastic behavior is desired. max_iter : int, optional Maximum number of iterations. Default is 1000. For 'lbfgs', this is the max number of L-BFGS iterations. For 'adam', this is the number of epochs. x_prior_mean : float, optional Mean of Gaussian prior on first modality embeddings. Default is 0.0. x_prior_scale : float, optional Scale (std) of Gaussian prior on first modality embeddings. Default is 1.0. Smaller values increase regularization. y_prior_mean : float, optional Mean of Gaussian prior on second modality embeddings. Default is 0.0. y_prior_scale : float, optional Scale (std) of Gaussian prior on second modality embeddings. Default is 1.0. Smaller values increase regularization. learning_rate : float, optional Adam learning rate. Ignored for 'lbfgs'. Default is 1e-3. batch_size : int, optional Adam mini-batch size. Ignored for 'lbfgs'. Default is 50. beta_1 : float, optional Adam exponential decay rate for first moment. Ignored for 'lbfgs'. Default is 0.9. beta_2 : float, optional Adam exponential decay rate for second moment. Ignored for 'lbfgs'. Default is 0.95. clipnorm : float, optional Adam gradient clipping threshold (global L2 norm). Ignored for 'lbfgs'. Default is 10.0. batch_norm : {'unbiased', 'legacy'}, optional Method for scaling mini-batch likelihood in Adam. Ignored for 'lbfgs'. - 'unbiased' (default): Uses norm = sum(n_features_x) / batch_size. - 'legacy': Uses norm = n_samples / batch_size. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. verbose : bool, optional Print training progress. Default is False. output_format : str, optional Output table format. See :ref:`table_params` for details. Returns ------- :class:`MMvecResult` Result of MMvec model fitting, including learned embeddings, conditional probabilities, and convergence history. It also provides methods for predicting target distributions, and scoring predictive performance. See Also -------- MMvecResult References ---------- .. [1] Morton, J. T., Aksenov, A. A., Nothias, L. F., Foulds, J. R., Quinn, R. A., Badri, M. H., ... & Knight, R. (2019). Learning representations of microbe-metabolite interactions. Nature Methods, 16(12), 1306-1314. Examples -------- >>> from skbio.stats.ordination import mmvec Create a toy example of paired microbiome and metabolome datasets. >>> import pandas as pd >>> samples = ['S1', 'S2', 'S3', 'S4', 'S5'] >>> microbes = ['O1', 'O2', 'O3', 'O4', 'O5', 'O6', 'O7', 'O8'] >>> microbiome = pd.DataFrame([ ... [1, 0, 0, 7, 0, 2, 1, 0], ... [0, 1, 2, 9, 1, 1, 0, 1], ... [2, 0, 1, 6, 0, 0, 2, 0], ... [1, 2, 1, 8, 3, 1, 0, 2], ... [0, 1, 3, 3, 1, 4, 1, 0], ... ], index=samples, columns=microbes) >>> metabolites = ['C1', 'C2', 'C3', 'C4', 'C5', 'C6'] >>> metabolome = pd.DataFrame([ ... [0, 1, 0, 1, 1, 2], ... [1, 0, 2, 1, 5, 0], ... [0, 3, 1, 0, 1, 1], ... [3, 1, 0, 2, 2, 0], ... [0, 0, 4, 1, 7, 3], ... ], index=samples, columns=metabolites) Fit the MMvec model to the data. This will perform numerical optimization for up to 100 iterations to learn the embeddings and co-occurrence patterns. >>> res = mmvec(microbiome, metabolome, max_iter=100, seed=42) Features of the two datasets (i.e., microbes and metabolites) are projected to the same latent space. Their coordinates (i.e., embeddings) are stored in two matrices: ``x_embeddings`` and ``y_embeddings``, respectively. The last column of each matrix is the bias term. >>> res.x_embeddings.round(3) PC1 PC2 PC3 bias O1 -0.442 -0.358 0.701 0.036 O2 0.136 0.378 -0.280 -0.304 O3 0.226 -0.206 -0.668 0.376 O4 0.036 -0.015 0.088 0.055 O5 0.137 0.490 -0.068 -0.423 O6 -0.268 -0.047 -0.899 0.622 O7 0.009 -0.924 0.025 1.099 O8 0.575 0.823 0.398 -0.593 >>> res.y_embeddings.round(3) PC1 PC2 PC3 bias C1 0.000 0.000 0.000 0.000 C2 -0.153 -0.861 0.936 -0.149 C3 0.186 -0.475 -0.742 0.102 C4 -0.079 0.429 -0.001 0.020 C5 0.266 -0.074 -0.541 1.028 C6 -0.743 -0.965 -0.525 -0.132 One can generate a biplot visualizing the co-occurrence patterns of microbes and metabolites. The distance and angle between features indicate their association strength. Note that the origin of the plot alway lies on the first metabolite in the dataset, which serves as a reference. >>> import matplotlib.pyplot as plt >>> plt.scatter('PC1', 'PC2', data=res.x_embeddings) # doctest: +SKIP >>> plt.scatter('PC1', 'PC2', data=res.y_embeddings) # doctest: +SKIP >>> plt.grid() # doctest: +SKIP The ``ranks`` matrix stores the log conditional probabilities of microbe-metabolite co-occurrences. Larger positive values indicate a stronger likelihood of co-occurrence. Low and negative values indicate no relationship, not necessarily a negative correlation. Values are row-centered. One can sort each row to reveal which metabolites are most strongly associated with each microbe. >>> res.ranks.round(3) C1 C2 C3 C4 C5 C6 O1 -0.228 0.691 -0.522 -0.291 0.366 -0.017 O2 0.202 -0.859 0.054 0.070 1.086 -0.553 O3 -0.602 -0.858 0.511 -0.313 1.239 0.023 O4 -0.180 -0.184 -0.074 -0.114 0.866 -0.314 O5 0.368 -0.710 -0.109 0.165 1.011 -0.725 O6 -0.833 -1.119 0.531 -0.189 1.236 0.373 O7 -1.355 0.411 0.266 -0.634 0.829 0.483 O8 0.725 -0.441 -0.347 0.459 1.036 -1.431 The actual conditional probabilities are provided by ``probs``. >>> res.probs.round(3) C1 C2 C3 C4 C5 C6 O1 0.121 0.304 0.090 0.114 0.220 0.150 O2 0.167 0.058 0.144 0.147 0.405 0.079 O3 0.070 0.054 0.212 0.093 0.440 0.130 O4 0.127 0.126 0.141 0.135 0.361 0.111 O5 0.200 0.068 0.124 0.163 0.379 0.067 O6 0.053 0.040 0.208 0.101 0.421 0.177 O7 0.034 0.201 0.174 0.071 0.305 0.216 O8 0.256 0.080 0.088 0.197 0.350 0.030 The ``convergence`` vector stores the loss curve over iterations during model training. If the model has converged, the curve should decrease and stabilize. >>> plt.plot(res.convergence) # doctest: +SKIP A fitted MMvec model can be used to predict metabolite abundances given new microbiome data using the ``predict`` method. >>> samples_test = ['S6', 'S7', 'S8'] >>> microbiome_test = pd.DataFrame([ ... [3, 0, 2, 6, 1, 4, 4, 0], ... [2, 1, 5, 0, 0, 3, 6, 1], ... [8, 4, 1, 1, 5, 0, 5, 1], ... ], index=samples_test, columns=microbes) >>> metabolome_pred = res.predict(microbiome_test) >>> metabolome_pred.round(3) C1 C2 C3 C4 C5 C6 S6 0.091 0.140 0.160 0.109 0.349 0.151 S7 0.077 0.130 0.175 0.098 0.360 0.160 S8 0.131 0.171 0.129 0.124 0.318 0.128 To evaluate the model's generalizability, one can compute the :math:`Q^2` statistic on held-out test data using the ``score`` method. A positive :math:`Q^2` indicates better-than-mean predictive performance (with 1.0 indicating perfect prediction). A negative or close-to-zero :math:`Q^2` is a sign of model overfitting or poor generalization. >>> metabolome_test = pd.DataFrame([ ... [0, 5, 1, 1, 8, 0], ... [1, 0, 5, 3, 2, 3], ... [4, 1, 0, 1, 6, 3], ... ], index=samples_test, columns=metabolites) >>> q2 = res.score(microbiome_test, metabolome_test) >>> float(q2.round(5)) 0.02291 """ estimator = MMvec( n_components=dimensions, optimizer=optimizer, max_iter=max_iter, x_prior_mean=x_prior_mean, x_prior_scale=x_prior_scale, y_prior_mean=y_prior_mean, y_prior_scale=y_prior_scale, learning_rate=learning_rate, batch_size=batch_size, beta_1=beta_1, beta_2=beta_2, clipnorm=clipnorm, batch_norm=batch_norm, seed=seed, verbose=verbose, output_format=output_format, ) fitted = estimator.fit(X, Y) return MMvecResult(fitted) class MMvecResult: r"""Result of an MMvec analysis. This class contains the learned embeddings and co-occurrence patterns from fitting an MMvec model. It enables both interpretation (which conditioning (X) and conditioned (Y) features co-occur with each other) and prediction (expected Y composition given X composition). Attributes ---------- x_embeddings : table_like of shape (n_features_x, n_dimensions + 1) y_embeddings : table_like of shape (n_features_y, n_dimensions + 1) ranks : table_like of shape (n_features_x, n_features_y) probs : table_like of shape (n_features_x, n_features_y) convergence : table_like of shape (n_iterations,) See Also -------- mmvec Notes ----- **Detecting overfitting with Q-squared** Overfitting occurs when the model memorizes training data rather than learning generalizable patterns. To detect overfitting: 1. Split your data into training and test sets before fitting. 2. Fit the model on training data only. 3. Use :meth:`score` to compute :math:`Q^2` on held-out test data. Interpretation of :math:`Q^2` values: - **Close to 1**: Excellent predictive performance. - **Close to 0**: Model predicts no better than the mean. - **Negative**: Model performs worse than predicting the mean, indicating overfitting or model misspecification. If :math:`Q^2` is much lower than expected, try: - Reducing ``dimensions`` (fewer latent dimensions). - Increasing regularization via smaller ``x_prior_scale`` and ``y_prior_scale`` values. - Collecting more training samples. **Embedding Interpretation** The embeddings place X and Y features in the same latent space. The inner product between an X embedding vector and a Y embedding vector (plus their bias terms) gives the log-odds of their co-occurrence: .. math:: \log \frac{P(m_j | \mu_i)}{P(m_{\text{ref}} | \mu_i)} = X_i \cdot Y_j + b_{X_i} + b_{Y_j} This means that X and Y features pointing in similar directions associate with each other, and the angle between a pair of X and Y vectors indicates their association strength. """ def __init__(self, estimator: MMvec): self._estimator = estimator def __str__(self) -> str: n_features_x = self.x_embeddings.shape[0] n_features_y = self.y_embeddings.shape[0] n_dimensions = self.x_embeddings.shape[1] - 1 return ( f"MMvecResult\n" f" Features: {n_features_x}\n" f" Targets: {n_features_y}\n" f" Components: {n_dimensions}\n" f" Iterations: {len(self.convergence)}" ) @property def x_embeddings(self) -> TableLike: r"""Learned coordinates of conditioning features (X) in latent space. Each row is a vector representation of an X feature. Features with similar embeddings tend to co-occur with similar sets of Y features. The Euclidean distance or cosine similarity between embeddings can be used to identify feature relatedness. The last column (+1; "bias") captures the baseline tendency of each X feature to associate with Y features overall. """ return self._estimator.x_embeddings_ @property def y_embeddings(self) -> TableLike: r"""Learned coordinates of conditioned features (Y) in latent space. See ``x_embeddings``. The first row is all zeros and represents the reference Y feature used for identifiability. The last column (+1; "bias") captures the baseline abundance of each Y feature. """ return self._estimator.y_embeddings_ @property def ranks(self) -> TableLike: r"""Row-centered log conditional probability matrix. Entry (i, j) represents the log-odds of observing :math:`Y_j` given :math:`X_i`, relative to the row mean. Higher values indicate stronger positive associations. This matrix is row-centered (each row sums to 0) for identifiability. The actual conditional probabilities (see :attr:`probs`) can be obtained by transforming this matrix with :func:`~skbio.stats.composition.clr_inv` (a.k.a. softmax). """ return self._estimator.ranks_ @property def probs(self) -> TableLike: r"""Conditional probability matrix of co-occurrence of X and Y features. Entry (i, j) represents the probability of observing :math:`Y_j` given :math:`X_i`. Each row sums to 1. This matrix is derived from the softmax transformation of the ``ranks`` matrix and is cached lazily. """ return self._estimator.probs_ @property def convergence(self) -> TableLike: r"""Loss (negative log-posterior) over iterations during training. Use this to diagnose training issues. The loss should generally decrease and stabilize. If the loss is still decreasing at the final iteration, consider increasing ``max_iter``. If the loss oscillates (Adam optimizer), try reducing ``learning_rate``. """ return self._estimator.loss_curve_ def predict(self, X: TableLike) -> TableLike: r"""Predict conditioned feature compositions given conditioning features. The expected conditioned (Y) feature distribution for each sample is computed by marginalizing over the given conditioning (X) feature composition and the learned conditional probabilities: .. math:: P(Y) = \sum_i P(X_i)\,P(Y \mid X_i) Parameters ---------- X : table_like of shape (n_samples, n_features_x) Feature abundance table of the conditioning (X) modality. Columns must match the features used during training. Returns ------- table_like of shape (n_samples, n_features_y) Predicted feature proportions of the conditioned (Y) modality for each sample. Each row sums to 1. """ return self._estimator.predict(X) def score(self, X: TableLike, Y: TableLike) -> float: r"""Compute Q-squared (coefficient of prediction) on held-out data. :math:`Q^2` measures predictive performance on test data, analogous to :math:`R^2` but for cross-validation. Values range from -inf to 1, where 1 indicates perfect prediction and 0 indicates prediction no better than the mean. .. math:: Q^2 = 1 - \frac{SS_{res}}{SS_{tot}} = 1 - \frac{\sum(y - \hat{y})^2}{\sum(y - \bar{y}_j)^2} where :math:`\bar{y}_j` is the per-target mean across samples. Parameters ---------- X : table_like of shape (n_samples, n_features_x) Feature abundance table of the conditioning (X) modality. Columns must match the features used during training. Y : table_like of shape (n_samples, n_features_y) Feature abundance table of the conditioned (Y) modality. Returns ------- q2 : float Q-squared score. Higher is better, with 1.0 being perfect prediction. """ return self._estimator.score(X, Y) class MMvec(SkbioObject): r"""MMvec estimator with scikit-learn-style interface. MMvec models conditional target distributions given feature compositions. In sklearn terms, the first modality (``X``) are "features" and the second modality (``y``, vector or matrix) are "targets". In the original MMvec work, features typically correspond to microbes and targets to metabolites. .. versionadded:: 0.7.3 Attributes ---------- x_embeddings_ : table_like of shape (n_features, n_components + 1) Learned feature embeddings (+1 is the bias term). y_embeddings_ : table_like of shape (n_outputs, n_components + 1) Learned target embeddings (+1 is the bias term). ranks_ : table_like of shape (n_features, n_outputs) Row-centered log conditional probabilities (lazy, cached on first access). probs_ : table_like of shape (n_features, n_outputs) Conditional probability matrix P(Y | X) (lazy, cached on first access). loss_curve_ : table_like of shape (n_iterations,) Optimization losses over training updates. n_iter_ : int Number of optimization iterations completed. n_features_in_ : int Number of features in `X` seen during :meth:`fit`. n_outputs_ : int Number of features in `y` seen during :meth:`fit`. x_feature_ids_ : tuple or None Feature IDs of `X`, if available. y_feature_ids_ : tuple or None Feature IDs of `y`, if available. """ def __init__( self, n_components: int = 3, optimizer: str = "lbfgs", max_iter: int = 1000, x_prior_mean: float = 0.0, x_prior_scale: float = 1.0, y_prior_mean: float = 0.0, y_prior_scale: float = 1.0, learning_rate: float = 1e-3, batch_size: int = 50, beta_1: float = 0.9, beta_2: float = 0.95, clipnorm: float = 10.0, batch_norm: str = "unbiased", seed: SeedLike | None = None, verbose: bool = False, output_format: str | None = None, ) -> None: self.n_components = n_components self.optimizer = optimizer self.max_iter = max_iter self.x_prior_mean = x_prior_mean self.x_prior_scale = x_prior_scale self.y_prior_mean = y_prior_mean self.y_prior_scale = y_prior_scale self.learning_rate = learning_rate self.batch_size = batch_size self.beta_1 = beta_1 self.beta_2 = beta_2 self.clipnorm = clipnorm self.batch_norm = batch_norm self.seed = seed self.verbose = verbose self.output_format = output_format def fit(self, X: TableLike, y: TableLike) -> MMvec: """Fit MMvec model. Parameters ---------- X : table_like of shape (n_samples, n_features) Conditioning feature matrix (e.g., microbes). y : table_like of shape (n_samples,) or (n_samples, n_outputs) Conditioned feature matrix or vector (e.g., metabolites). Returns ------- MMvec Fitted estimator. """ # Parse tabular inputs X_arr, _, x_feature_ids = _ingest_table(X) y_arr, _, y_feature_ids = _ingest_table(y) # Check for sample count consistency if X_arr.shape[0] != y_arr.shape[0]: raise ValueError( f"X and y must have the same number of samples. " f"Got {X_arr.shape[0]} and {y_arr.shape[0]}." ) # Check for all-zero columns / rows for mod, name in (X_arr, "X"), (y_arr, "y"): for i, axis in enumerate(("columns", "rows")): if np.any(mod.sum(axis=i) == 0): raise ValueError( f"{name} contains all-zero {axis}. Remove them before calling." ) # Check for positive prior scales if self.x_prior_scale <= 0: raise ValueError("x_prior_scale must be positive.") if self.y_prior_scale <= 0: raise ValueError("y_prior_scale must be positive.") # Validate optimizer optimizer = self.optimizer.lower() if optimizer not in ("lbfgs", "adam"): raise ValueError("Optimizer must be 'lbfgs' or 'adam'.") # Create RNG rng = get_rng(self.seed) n_features_x = X_arr.shape[1] n_features_y = y_arr.shape[1] # Initialize model model = _MMvecModel( n_features_x=n_features_x, n_features_y=n_features_y, n_components=self.n_components, x_prior_mean=self.x_prior_mean, x_prior_scale=self.x_prior_scale, y_prior_mean=self.y_prior_mean, y_prior_scale=self.y_prior_scale, rng=rng, ) # Convert X to sparse COO format X_coo = coo_array(X_arr) # Train model using choice of L-BFGS-B or Adam optimizer if optimizer == "lbfgs": losses = _train_lbfgs(model, X_coo, y_arr, self.max_iter, self.verbose) else: losses = _train_adam( model=model, X_coo=X_coo, Y=y_arr, rng=rng, max_iter=self.max_iter, learning_rate=self.learning_rate, batch_size=self.batch_size, beta_1=self.beta_1, beta_2=self.beta_2, clipnorm=self.clipnorm, batch_norm=self.batch_norm, verbose=self.verbose, ) pc_cols = [f"PC{i + 1}" for i in range(model.n_components)] + ["bias"] x_embed = np.hstack([model.x_main, model.x_bias]) y_embed = np.vstack( [ np.zeros((1, model.n_components + 1)), np.hstack([model.y_main.T, model.y_bias.T]), ] ) self.x_embeddings_ = _create_table( x_embed, columns=pc_cols, index=x_feature_ids, backend=self.output_format ) # (n_features_x, n_components + 1) self.y_embeddings_ = _create_table( y_embed, columns=pc_cols, index=y_feature_ids, backend=self.output_format ) # (n_features_x, n_components + 1) # Loss curve for diagnosis self.loss_curve_ = _create_table_1d(losses) # (n_iterations,) # Keep the learned low-rank parameters available for post-fit analysis. self._x_main = model.x_main # (n_features_x, n_components) self._x_bias = model.x_bias # (n_features_x, 1) self._y_main = model.y_main # (n_components, n_features_y - 1) self._y_bias = model.y_bias # (n_features_y - 1, 1) # `ranks_` and `probs` are both dense (n_features_x, n_features_y) matrices, # so we avoid materializing either one until a user actually needs it. self._ranks = None self._probs = None self.x_feature_ids_ = ( tuple(x_feature_ids) if x_feature_ids is not None else None ) self.y_feature_ids_ = ( tuple(y_feature_ids) if y_feature_ids is not None else None ) self.n_features_in_ = X_arr.shape[1] self.n_outputs_ = y_arr.shape[1] self.n_iter_ = len(losses) self.is_fitted_ = True return self def _check_is_fitted(self) -> None: if not getattr(self, "is_fitted_", False): raise ValueError("MMvec estimator is not fitted. Call fit(X, y) first.") def __str__(self) -> str: """Return string representation of MMvec.""" self._check_is_fitted() n_features_x = self.x_embeddings_.shape[0] n_features_y = self.y_embeddings_.shape[0] n_components = self.x_embeddings_.shape[1] - 1 # exclude bias n_iterations = len(self.loss_curve_) return ( f"MMvec\n" f" Features: {n_features_x}\n" f" Targets: {n_features_y}\n" f" Components: {n_components}\n" f" Iterations: {n_iterations}" ) def get_params(self, deep: bool = True) -> dict[str, object]: """Get estimator parameters for sklearn compatibility.""" return { "n_components": self.n_components, "optimizer": self.optimizer, "max_iter": self.max_iter, "learning_rate": self.learning_rate, "batch_size": self.batch_size, "x_prior_mean": self.x_prior_mean, "x_prior_scale": self.x_prior_scale, "y_prior_mean": self.y_prior_mean, "y_prior_scale": self.y_prior_scale, "beta_1": self.beta_1, "beta_2": self.beta_2, "clipnorm": self.clipnorm, "batch_norm": self.batch_norm, "seed": self.seed, "verbose": self.verbose, "output_format": self.output_format, } def set_params(self, **params: object) -> MMvec: """Set estimator parameters for sklearn compatibility.""" for key, value in params.items(): if not hasattr(self, key): raise ValueError(f"Invalid parameter '{key}' for MMvec estimator.") setattr(self, key, value) return self @property def ranks_(self) -> TableLike: """Row-centered log conditional probabilities. This dense matrix is cached lazily because it can be very large for high-dimensional multiomics data and is primarily used for inspection. """ self._check_is_fitted() if self._ranks is None: ranks = self._compute_logits() ranks -= np.mean(ranks, axis=1, keepdims=True) self._ranks = _create_table( ranks, columns=self.y_feature_ids_, index=self.x_feature_ids_, backend=self.output_format, ) return self._ranks @property def probs_(self) -> TableLike: """Conditional probability matrix P(Y | X). Entry (i, j) is the probability of observing target j given feature i. Each row sums to 1. This dense matrix is cached lazily because it can be very large for high-dimensional multiomics data. """ self._check_is_fitted() if self._probs is None: probs_array = self._get_probs() self._probs = _create_table( probs_array, columns=self.y_feature_ids_, index=self.x_feature_ids_, backend=self.output_format, ) return self._probs def _compute_logits(self) -> np.ndarray: """Construct full Y logits from the learned low-rank parameters. The first Y feature is the reference category and is fixed at zero logits. Remaining columns are computed directly from the fitted X/Y embeddings and bias terms. """ logits = np.empty((self.n_features_in_, self.n_outputs_)) logits[:, 0] = 0.0 logits_nr = logits[:, 1:] np.matmul(self._x_main, self._y_main, out=logits_nr) logits_nr += self._x_bias logits_nr += self._y_bias return logits def _get_probs(self) -> np.ndarray: """Compute conditional probability matrix P(Y | X) as numpy array. This computes the raw probability array without table wrapping. Used internally by probs_ and predict. """ return softmax(self._compute_logits(), validate=False) def _predict(self, X: np.ndarray) -> np.ndarray: """Predict Y proportions given X data.""" # Normalize abundances to proportions before applying P(Y | X). row_sums = np.sum(X, axis=1, keepdims=True) if np.any(row_sums == 0): raise ValueError( "X contains samples with all-zero counts. Remove these samples before " "calling predict." ) X_props = X / row_sums return X_props @ self._get_probs() def predict(self, X: TableLike) -> TableLike: """Predict target distributions given feature compositions. Parameters ---------- X : table_like of shape (n_samples, n_features) Feature abundance/count table. Columns must match the features used during training. Returns ------- y_pred : table_like of shape (n_samples, n_outputs) Predicted target (y) proportions for each sample. Each row sums to 1. """ self._check_is_fitted() X, sample_ids, _ = _ingest_table(X) y_pred = self._predict(X) return _create_table( y_pred, columns=self.y_feature_ids_, index=sample_ids, backend=self.output_format, ) def score(self, X: TableLike, y: TableLike) -> float: r"""Compute Q-squared (coefficient of prediction) on held-out data. Parameters ---------- X : table_like of shape (n_samples, n_features) Test feature table. y : table_like of shape (n_samples,) or (n_samples, n_outputs) Test target table (or vector). Returns ------- q2 : float Q-squared score. Higher is better, with 1.0 being perfect prediction. """ self._check_is_fitted() X, _, _ = _ingest_table(X) Y, _, _ = _ingest_table(y) # Predict directly into an array to avoid a table round-trip. Y_pred = self._predict(X) # Normalize abundances to proportions row_sums = np.sum(Y, axis=1, keepdims=True) if np.any(row_sums == 0): raise ValueError( "y contains samples with all-zero counts. " "Remove these samples before calling score." ) Y_true = Y / row_sums # Q^2 = 1 - SS_res / SS_tot ss_res = np.sum((Y_true - Y_pred) ** 2) ss_tot = np.sum((Y_true - Y_true.mean(axis=0)) ** 2) # All true values are the same - return 0 to avoid division by zero # NOTE: Mathematically, this should happen when every feature has a uniform # value across samples. But due to floating-point arithmetic issues, this # won't happen. if ss_tot == 0: # pragma: no cover return 0.0 return 1.0 - ss_res / ss_tot class _MMvecModel: """Internal model class for MMvec optimization.""" def __init__( self, n_features_x: int, n_features_y: int, n_components: int, x_prior_mean: float, x_prior_scale: float, y_prior_mean: float, y_prior_scale: float, rng: np.random.Generator, ) -> None: """Initialize MMvec model parameters. Parameters ---------- n_features_x : int Number of features in the conditioning modality (X). n_features_y : int Number of features in the conditioned modality (Y). n_components : int Latent dimensionality (p). x_prior_mean : float Mean of Gaussian prior on X-side embeddings and biases. x_prior_scale : float Scale of Gaussian prior on X-side embeddings and biases. y_prior_mean : float Mean of Gaussian prior on Y-side embeddings and biases. y_prior_scale : float Scale of Gaussian prior on Y-side embeddings and biases. rng : numpy.random.Generator Random number generator. """ self.n_features_x = n_features_x self.n_features_y = n_features_y self.n_components = n_components self.x_prior_mean = x_prior_mean self.x_prior_scale = x_prior_scale self.y_prior_mean = y_prior_mean self.y_prior_scale = y_prior_scale # Cache squared scales self._x_prior_scale_sq = x_prior_scale**2 self._y_prior_scale_sq = y_prior_scale**2 # Initialize parameters with random normal distribution self.x_main = rng.standard_normal((n_features_x, n_components)) self.x_bias = rng.standard_normal((n_features_x, 1)) self.y_main = rng.standard_normal((n_components, n_features_y - 1)) self.y_bias = rng.standard_normal((1, n_features_y - 1)) def loss_and_grad( self, X_coo: coo_array, Y: np.ndarray, size: int, norm: float, weights: np.ndarray, rng: np.random.Generator, ) -> tuple[float, Grad4Tuple]: """Compute loss and gradients for a mini-batch. Parameters ---------- X_coo : coo_array of shape (n_samples, n_features_x) Conditioning (X) feature counts in COO format. Y : np.ndarray of shape (n_samples, n_features_y) Conditioned (Y) feature counts. size : int Mini-batch size. norm : float Batch normalization factor. weights : np.ndarray of shape (n_samples,) Sample weights for weighted batch sampling. rng : numpy.random.Generator Random number generator for batch sampling. Returns ------- loss : float Negative log posterior. grads : tuple of np.ndarray Gradients in the order of (dx_main, dx_bias, dy_main, dy_bias). """ batch_idx = rng.choice(len(X_coo.data), size=size, replace=True, p=weights) sample_ids = X_coo.row[batch_idx] X_ids = X_coo.col[batch_idx] # Build the non-reference logits directly for the sampled X features. Y_batch = Y[sample_ids, :] # (B, d2) x_main_batch = self.x_main[X_ids, :] # (B, p) x_bias_batch = self.x_bias[X_ids, :] # (B, 1) logits_nr = x_main_batch @ self.y_main # (B, d2-1) logits_nr += x_bias_batch logits_nr += self.y_bias # Stable log(1 + sum(exp(logits_nr))) with the reference Y category # kept implicit as a zero logit. row_max = np.max(logits_nr, axis=1, keepdims=True) np.maximum(row_max, 0.0, out=row_max) exp_shifted = np.exp(logits_nr - row_max) log_norm = row_max + np.log( np.exp(-row_max) + exp_shifted.sum(axis=1, keepdims=True) ) # Non-reference probabilities and grouped residuals for the sampled batch. probs_nr = exp_shifted / np.exp(log_norm - row_max) totals = np.sum(Y_batch, axis=1, keepdims=True) delta = Y_batch[:, 1:] - totals * probs_nr # The reference category has logit 0, so only non-reference logits appear in # the inner-product term. loglik = np.sum(Y_batch[:, 1:] * logits_nr) - np.sum(totals * log_norm) # Gradient w.r.t. Y-side embedding parameters dy_main = -norm * (x_main_batch.T @ delta) dy_main += (self.y_main - self.y_prior_mean) / (self.y_prior_scale**2) # Y-side bias gradient is the row-wise sum over non-reference residuals. dy_bias = -norm * delta.sum(axis=0, keepdims=True) dy_bias += (self.y_bias - self.y_prior_mean) / (self.y_prior_scale**2) # Project residuals back through the Y embeddings for the X-side gradients. dx_main_batch = delta @ self.y_main.T # (B, p) dx_bias_batch = delta.sum(axis=1) # (B,) dx_main = np.zeros_like(self.x_main) dx_bias = np.zeros_like(self.x_bias) # Scatter-add the sampled X-side contributions back to full parameter arrays. np.add.at(dx_main, X_ids, -norm * dx_main_batch) np.add.at(dx_bias[:, 0], X_ids, -norm * dx_bias_batch) # Add prior gradients dx_main += (self.x_main - self.x_prior_mean) / (self.x_prior_scale**2) dx_bias += (self.x_bias - self.x_prior_mean) / (self.x_prior_scale**2) # Compute total loss (negative log posterior) prior_loss = 0.0 prior_loss += ( 0.5 * np.sum((self.x_main - self.x_prior_mean) ** 2) / self._x_prior_scale_sq ) prior_loss += ( 0.5 * np.sum((self.x_bias - self.x_prior_mean) ** 2) / self._x_prior_scale_sq ) prior_loss += ( 0.5 * np.sum((self.y_main - self.y_prior_mean) ** 2) / self._y_prior_scale_sq ) prior_loss += ( 0.5 * np.sum((self.y_bias - self.y_prior_mean) ** 2) / self._y_prior_scale_sq ) loss = -norm * loglik + prior_loss grads = (dx_main, dx_bias, dy_main, dy_bias) return loss, grads def pack_params(self) -> np.ndarray: """Flatten all parameters into a single vector. Returns ------- theta : np.ndarray Flattened parameters [x_main, x_bias, y_main, y_bias]. """ return np.concatenate( [ self.x_main.ravel(), self.x_bias.ravel(), self.y_main.ravel(), self.y_bias.ravel(), ] ) def unpack_params(self, theta: np.ndarray) -> None: """Restore parameter matrices from flat vector. Parameters ---------- theta : np.ndarray Flattened parameters. """ d1 = self.n_features_x d2 = self.n_features_y p = self.n_components idx = 0 self.x_main = theta[idx : idx + d1 * p].reshape(d1, p) idx += d1 * p self.x_bias = theta[idx : idx + d1].reshape(d1, 1) idx += d1 self.y_main = theta[idx : idx + p * (d2 - 1)].reshape(p, d2 - 1) idx += p * (d2 - 1) self.y_bias = theta[idx : idx + (d2 - 1)].reshape(1, d2 - 1) def loss_and_grad_fb( self, y_sums: np.ndarray, n_sums: np.ndarray, logits: np.ndarray, resids: np.ndarray, row_max: np.ndarray, log_norm: np.ndarray, row_scale: np.ndarray, ) -> tuple[float, np.ndarray]: """Compute full-batch loss and gradient for L-BFGS. Parameters ---------- y_sums : np.ndarray of shape (n_features_x, n_features_y) Weighted Y counts aggregated by X feature index. Each row stores the total Y counts contributed by all nonzero X entries for one X feature. n_sums : np.ndarray of shape (n_features_x,) Weighted Y sample totals aggregated by X feature index. Each entry stores the total Y count paired with one X feature. logits : np.ndarray of shape (n_features_x, n_features_y - 1) Reusable workspace for non-reference logits. resids : np.ndarray of shape (n_features_x, n_features_y - 1) Reusable workspace for grouped residuals and non-reference probabilities. row_max : np.ndarray of shape (n_features_x,) Reusable workspace for row-wise maxima. log_norm : np.ndarray of shape (n_features_x,) Reusable workspace for row-wise log normalizers. row_scale : np.ndarray of shape (n_features_x,) Reusable workspace for row-wise normalizing factors. Returns ------- loss : float Negative log-posterior. grad : np.ndarray Flattened gradient vector. Notes ----- This routine evaluates the full negative log-posterior for the L-BFGS solver. It first groups the data by X feature using two sufficient statistics: - y_sums: grouped Y counts - n_sums: grouped Y totals With those grouped arrays in hand, the dense part of the objective is computed from the non-reference logits: x_main @ y_main + x_bias + y_bias without materializing the reference Y column. The data term is then: sum(n_sums * log_norm) - sum(y_sums[:, 1:] * logits) followed by the Gaussian prior terms for the X-side and Y-side parameters. The same grouped quantities are reused to form the gradient. """ # Symbols used in comments below: # d1 : number of X features # d2 : number of Y features # p : number of latent dimensions # nnz : number of non-zero entries in X # Compute the non-reference logits directly: # logits = x_main @ y_main + x_bias + y_bias # This is algebraically the same as the old augmented-matrix product, but # avoids the reference column (1). np.matmul(self.x_main, self.y_main, out=logits) logits += self.x_bias logits += self.y_bias # Stable softmax for all X features (rows). # Compute log_norm = log(1 + \sum exp(logits)) in a numerically stable way that # resembles SciPy's logsumexp, but without allocating the reference column (0): # log_norm = m + log(exp(-m) + \sum exp(logits - m)) # In which m = max(0, max(logits)) # And exp(logits - m) is stored in resids for reuse. np.max(logits, axis=1, out=row_max) np.maximum(row_max, 0.0, out=row_max) np.subtract(logits, row_max[:, None], out=resids) np.exp(resids, out=resids) np.sum(resids, axis=1, out=log_norm) np.negative(row_max, out=row_scale) np.exp(row_scale, out=row_scale) log_norm += row_scale np.log(log_norm, out=log_norm) log_norm += row_max # Compute the grouped negative log-likelihood (part of the loss). # For each X feature, we combine: # - the weighted observed Y totals (`y_sums`) # - the weighted Y sample totals (`n_sums`) # - the corresponding log-normalizer (`log_norm`) # In compact form: # loss_data = sum(n_sums * log_norm) - sum(y_sums[:, 1:] * logits) # The reference category has logit 0, so only non-reference logits appear # in the inner-product term. loss = np.dot(n_sums, log_norm) - np.einsum("ij,ij->", y_sums[:, 1:], logits) # Recover non-reference probabilities from the shifted exponentials. # At this point resids holds exp(logits - row_max). Divide by # exp(log_norm - row_max) to recover the non-reference probabilities. np.subtract(log_norm, row_max, out=row_scale) np.exp(row_scale, out=row_scale) resids /= row_scale[:, None] # Turn probabilities into grouped residuals: observed weighted totals # minus expected weighted totals for each non-reference category. resids *= n_sums[:, None] resids *= -1.0 resids += y_sums[:, 1:] # Gradient for the Y-side embedding matrix. dy_main = -self.x_main.T @ resids # (p, d2-1) # Gradient for Y-side biases: sum residuals across X features. dy_bias = -resids.sum(axis=0, keepdims=True) # (1, d2-1) # Gradient for the X-side embedding matrix. dx_main = -(resids @ self.y_main.T) # (d1, p) # Gradient for X-side biases: sum residuals across Y categories. dx_bias = -resids.sum(axis=1, keepdims=True) # (d1, 1) # Add prior terms (L2 regularization) # These are exactly the Gaussian-prior contributions to the negative # log-posterior and its gradient. x_main_diff = self.x_main - self.x_prior_mean x_bias_diff = self.x_bias - self.x_prior_mean y_main_diff = self.y_main - self.y_prior_mean y_bias_diff = self.y_bias - self.y_prior_mean loss += 0.5 * np.sum(x_main_diff**2) / self._x_prior_scale_sq loss += 0.5 * np.sum(x_bias_diff**2) / self._x_prior_scale_sq loss += 0.5 * np.sum(y_main_diff**2) / self._y_prior_scale_sq loss += 0.5 * np.sum(y_bias_diff**2) / self._y_prior_scale_sq dx_main += x_main_diff / self._x_prior_scale_sq dx_bias += x_bias_diff / self._x_prior_scale_sq dy_main += y_main_diff / self._y_prior_scale_sq dy_bias += y_bias_diff / self._y_prior_scale_sq # Pack gradients grad = np.concatenate( [ dx_main.ravel(), dx_bias.ravel(), dy_main.ravel(), dy_bias.ravel(), ] ) return loss, grad def _train_lbfgs( model: _MMvecModel, X_coo: coo_array, Y: np.ndarray, max_iter: int, verbose: bool, ) -> list[float]: """Train MMvec model using L-BFGS-B optimization. Parameters ---------- model : _MMvecModel Initialized model to train. X_coo : coo_array of shape (n_samples, n_features_x) X feature counts in sparse COO format. Y : np.ndarray of shape (n_samples, n_features_y) Y feature counts. max_iter : int Maximum number of L-BFGS iterations. verbose : bool Print training progress. Returns ------- losses : list of float Loss per iteration. """ from scipy.optimize import minimize rows, cols, data = X_coo.row, X_coo.col, X_coo.data d1 = model.n_features_x d2 = model.n_features_y # Infer the data type for computation. Currently it promotes to at least float64. # But we should consider float32 support in the future. dtype = np.result_type(Y.dtype, data.dtype, np.float64) # Precompute X feature-grouped sufficient statistics reused by every iteration. # y_sums groups Y counts by X feature. Each row is the total Y abundance associated # with one X feature across all nonzero X entries. prods_ = data[:, None] * Y[rows, :] # (nnz, d2) y_sums = np.empty((d1, d2), dtype=dtype) for j in range(d2): y_sums[:, j] = np.bincount(cols, weights=prods_[:, j], minlength=d1) # n_sums stores the corresponding grouped Y totals. It is the row sum partner to # y_sums and tells us how much total Y abundance is attached to each X feature. sums_ = Y.sum(axis=1)[rows] # (nnz,) n_sums = np.bincount(cols, weights=data * sums_, minlength=d1).astype( dtype, copy=False ) # Reusable array workspaces for each iteration. # Logits for each X feature, excluding the reference (first column, all zeros). logits = np.empty((d1, d2 - 1), dtype=dtype) # Exponential-shifted logits reused later as grouped residuals. resids = np.empty((d1, d2 - 1), dtype=dtype) # Row-wise maximum over logits for numerically stable normalization. row_max = np.empty(d1, dtype=dtype) # Row-wise log normalizer, i.e., log(1 + sum(exp(logits))). log_norm = np.empty(d1, dtype=dtype) # Row-wise scaling factors derived from row_max/log_norm. row_scale = np.empty(d1, dtype=dtype) losses = [] it = 0 def func(theta: np.ndarray) -> tuple[float, np.ndarray]: nonlocal it model.unpack_params(theta) loss, grad = model.loss_and_grad_fb( y_sums, n_sums, logits, resids, row_max, log_norm, row_scale ) it += 1 losses.append(loss) if verbose and it % 10 == 0: print(f"Iteration {it}, Loss: {loss:.4f}") return loss, grad # Initial parameters theta0 = model.pack_params() # Run L-BFGS-B result = minimize( func, theta0, method="L-BFGS-B", jac=True, options={ "maxiter": max_iter, "ftol": 1e-9, "gtol": 1e-5, }, ) # Unpack final parameters model.unpack_params(result.x) if verbose: print( f"L-BFGS-B converged: {result.success}, " f"iterations: {result.nit}, message: {result.message}" ) return losses def _train_adam( model: _MMvecModel, X_coo: coo_array, Y: np.ndarray, rng: np.random.Generator, max_iter: int, learning_rate: float, batch_size: int, beta_1: float, beta_2: float, clipnorm: float, batch_norm: str, verbose: bool, ) -> list[float]: """Train MMvec model using Adam optimization. Parameters ---------- model : _MMvecModel Initialized model to train. X_coo : coo_array of shape (n_samples, n_features_x) Conditioning (X) feature counts in sparse COO format. Y : np.ndarray of shape (n_samples, n_features_y) Conditioned (Y) feature counts. rng : np.random.Generator Random number generator. max_iter : int Number of epochs. learning_rate : float Adam learning rate. batch_size : int Mini-batch size. beta_1 : float Adam exponential decay rate for first moment. beta_2 : float Adam exponential decay rate for second moment. clipnorm : float Gradient clipping threshold. batch_norm : {'legacy', 'unbiased'} Batch normalization mode. verbose : bool Print training progress. Returns ------- losses : list of dict Training metrics per iteration. """ losses = [] # Initialize Adam moments x_main_m = np.zeros_like(model.x_main) x_main_v = np.zeros_like(model.x_main) x_bias_m = np.zeros_like(model.x_bias) x_bias_v = np.zeros_like(model.x_bias) y_main_m = np.zeros_like(model.y_main) y_main_v = np.zeros_like(model.y_main) y_bias_m = np.zeros_like(model.y_bias) y_bias_v = np.zeros_like(model.y_bias) # Compute number of iterations per epoch data = X_coo.data nnz = len(data) iter_per_epoch = max(1, nnz // batch_size) # Compute normalization factor if batch_norm == "legacy": norm = X_coo.shape[0] / batch_size else: # unbiased norm = data.sum() / batch_size # Sample batch weighted by abundance weights = data / data.sum() it = 0 for epoch in range(max_iter): for _ in range(iter_per_epoch): it += 1 # Compute loss and gradients loss, grads = model.loss_and_grad(X_coo, Y, batch_size, norm, weights, rng) # Gradient clipping dx_main, dx_bias, dy_main, dy_bias = _clip_gradients(grads, clipnorm) # Adam updates bc1 = 1 - beta_1**it bc2 = 1 - beta_2**it params = (bc1, bc2, learning_rate, beta_1, beta_2) model.x_main, x_main_m, x_main_v = _adam_update( model.x_main, dx_main, x_main_m, x_main_v, *params ) model.x_bias, x_bias_m, x_bias_v = _adam_update( model.x_bias, dx_bias, x_bias_m, x_bias_v, *params ) model.y_main, y_main_m, y_main_v = _adam_update( model.y_main, dy_main, y_main_m, y_main_v, *params ) model.y_bias, y_bias_m, y_bias_v = _adam_update( model.y_bias, dy_bias, y_bias_m, y_bias_v, *params ) losses.append(loss) if verbose: print(f"Epoch {epoch + 1}/{max_iter}, Loss: {loss:.4f}") return losses def _clip_gradients(grads: Grad4Tuple, clipnorm: float) -> Grad4Tuple: """Apply global norm gradient clipping. Parameters ---------- grads : tuple of np.ndarray Gradients in the order of (dx_main, dx_bias, dy_main, dy_bias). clipnorm : float Maximum gradient norm. Returns ------- grads : tuple of np.ndarray Clipped gradients in the same fixed order. """ global_norm = np.sqrt(sum(np.sum(g**2) for g in grads)) if global_norm > clipnorm: scale = clipnorm / global_norm grads = tuple(g * scale for g in grads) return grads def _adam_update( param: np.ndarray, grad: np.ndarray, m: np.ndarray, v: np.ndarray, bc1: float, bc2: float, lr: float, beta_1: float, beta_2: float, eps: float = 1e-8, ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: """Perform single Adam update step. Parameters ---------- param : np.ndarray Current parameter values. grad : np.ndarray Gradient. m : np.ndarray First moment estimate. v : np.ndarray Second moment estimate. bc1 : float First-moment bias-correction denominator. bc2 : float Second-moment bias-correction denominator. lr : float Learning rate. beta_1 : float Exponential decay rate for first moment. beta_2 : float Exponential decay rate for second moment. eps : float Small constant for numerical stability. Returns ------- param : np.ndarray Updated parameter values. m : np.ndarray Updated first moment. v : np.ndarray Updated second moment. """ m = beta_1 * m + (1 - beta_1) * grad v = beta_2 * v + (1 - beta_2) * grad**2 # Bias correction m_hat = m / bc1 v_hat = v / bc2 param = param - lr * m_hat / (np.sqrt(v_hat) + eps) return param, m, v def random_multimodal( n_features_x: int = 20, n_features_y: int = 100, n_samples: int = 100, n_components: int = 3, grad_low: float = -1, grad_high: float = 1, x_total: int = 10, y_total: int = 100, coef_mean: float = 0, coef_std: float = 2, x_noise_std: float = 0.1, x_mean: float = 0, x_std: float = 1, y_mean: float = 0, y_std: float = 1, seed: SeedLike | None = 0, ) -> tuple[ pd.DataFrame, pd.DataFrame, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, ]: """Generate synthetic co-occurrence data of two modalities. This helper function is currently kept private because it is specific to MMvec tests. In the future, it may be promoted to a public and generalized simulation utility if broader use cases emerge. Parameters ---------- n_features_x : int Number of conditioning (X) features to simulate. n_features_y : int Number of conditioned (Y) features to simulate. n_samples : int Number of samples to generate. n_components : int Number of latent dimensions for the embeddings. grad_low : float Lower bound of the sample gradient. grad_high : float Upper bound of the sample gradient. x_total : int Total counts for X features per sample. y_total : int Total counts for Y features per sample. coef_mean : float Mean of regression coefficient distribution. coef_std : float Standard deviation of regression coefficient distribution. x_noise_std : float Standard deviation of noise in X composition. x_mean : float Mean of X embedding distribution. x_std : float Standard deviation of X embedding distribution. y_mean : float Mean of Y embedding distribution. y_std : float Standard deviation of Y embedding distribution. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. Returns ------- x_counts : pd.DataFrame of shape (n_samples, n_features_x) Count table of X abundances. y_counts : pd.DataFrame of shape (n_samples, n_features_y) Count table of Y abundances. design : np.ndarray of shape (n_samples, 2) Design matrix with intercept and gradient. coefs : np.ndarray of shape (2, n_features_x) Regression coefficients. x_main : np.ndarray of shape (n_features_x, n_dimensions) True X embedding matrix. x_bias : np.ndarray of shape (n_features_x, 1) True X bias vector. y_main : np.ndarray of shape (n_dimensions, n_features_y - 1) True Y embedding matrix. y_bias : np.ndarray of shape (1, n_features_y - 1) True Y bias vector. """ rng = get_rng(seed) # Regression coefficients for gradient model coefs = rng.normal(coef_mean, coef_std, size=(2, n_features_x)) # Design matrix: intercept + gradient design = np.vstack( (np.ones(n_samples), np.linspace(grad_low, grad_high, n_samples)) ).T # Generate X compositions from ILR with noise X = ilr_inv( rng.multivariate_normal( mean=np.zeros(n_features_x - 1), cov=np.diag([x_noise_std] * (n_features_x - 1)), size=n_samples, ) ) # Generate latent embeddings x_main = rng.normal(x_mean, x_std, size=(n_features_x, n_components)) y_main = rng.normal(y_mean, y_std, size=(n_components, n_features_y - 1)) x_bias = rng.normal(x_mean, x_std, size=(n_features_x, 1)) y_bias = rng.normal(y_mean, y_std, size=(1, n_features_y - 1)) # Augmented matrices for computing probabilities X_ = np.hstack((np.ones((n_features_x, 1)), x_bias, x_main)) Y_ = np.vstack((y_bias, np.ones((1, n_features_y - 1)), y_main)) # Compute conditional probabilities P(Y|X) phi = np.hstack((np.zeros((n_features_x, 1)), X_ @ Y_)) probs = softmax(phi, validate=False) # Generate count data x_counts = np.zeros((n_samples, n_features_x)) y_counts = np.zeros((n_samples, n_features_y)) n1 = x_total n2 = y_total // x_total for n in range(n_samples): # Draw X counts x = rng.multinomial(n1, X[n, :]) # For each x, draw Y conditional on that x for i in range(n_features_x): y = rng.multinomial(x[i] * n2, probs[i, :]) y_counts[n, :] += y x_counts[n, :] += x # Create DataFrames with meaningful IDs feature_ids_x = [f"x_feature_{d}" for d in range(x_counts.shape[1])] feature_ids_y = [f"y_feature_{d}" for d in range(y_counts.shape[1])] sample_ids = [f"sample_{d}" for d in range(y_counts.shape[0])] x_counts = pd.DataFrame(x_counts, index=sample_ids, columns=feature_ids_x) y_counts = pd.DataFrame(y_counts, index=sample_ids, columns=feature_ids_y) return x_counts, y_counts, design, coefs, x_main, x_bias, y_main, y_bias scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/_ordination_results.py000066400000000000000000000623541520735541300274400ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import functools from warnings import warn import numpy as np import pandas as pd from skbio._base import SkbioObject from skbio.stats._misc import _pprint_strs from skbio.util._plotting import PlottableMixin from skbio.io.descriptors import Read, Write from skbio.table._tabular import _extract_row_ids class OrdinationResults(SkbioObject, PlottableMixin): """Store ordination results, providing serialization and plotting support. Stores various components of ordination results. Provides methods for serializing/deserializing results, as well as generation of basic matplotlib 3-D scatterplots using the :meth:`plot` method. Attributes ---------- short_method_name : str Abbreviated ordination method name. long_method_name : str Ordination method name. eigvals : table_like The resulting eigenvalues. The index corresponds to the ordination axis labels. See :ref:`table_output` for details. samples : table_like The position of the samples in the ordination space, row-indexed by the sample id. See :ref:`table_output` for details. features : table_like The position of the features in the ordination space, row-indexed by the feature id. See :ref:`table_output` for details. biplot_scores : table_like Correlation coefficients of the samples with respect to the features. See :ref:`table_output` for details. sample_constraints : table_like Site constraints (linear combinations of constraining variables): coordinates of the sites in the space of the explanatory variables X. These are the fitted site scores. See :ref:`table_output` for details. proportion_explained : table_like Proportion explained by each of the dimensions in the ordination space. The index corresponds to the ordination axis labels. See :ref:`table_output` for details. sample_ids, feature_ids, constraint_ids, output_format : optional Standard table parameters. See :ref:`table_params` for details. See Also -------- ca cca pcoa rda """ default_write_format = "ordination" """Default write format for this object: ``ordination``.""" read = Read() write = Write() def __init__( self, short_method_name, long_method_name, eigvals, samples, sample_ids=None, features=None, feature_ids=None, biplot_scores=None, sample_constraints=None, constraint_ids=None, proportion_explained=None, ): self.short_method_name = short_method_name self.long_method_name = long_method_name self.eigvals = eigvals self.samples = samples if sample_ids is None: no_samp_ids = True self.sample_ids = _extract_row_ids(samples) else: no_samp_ids = False self.sample_ids = sample_ids self.features = features if feature_ids is None and features is not None: self.feature_ids = _extract_row_ids(features, warn_ids=no_samp_ids) else: self.feature_ids = feature_ids self.biplot_scores = biplot_scores self.sample_constraints = sample_constraints self.constraint_ids = constraint_ids self.proportion_explained = proportion_explained def __str__(self): """Return a string representation of the ordination results. String representation lists ordination results attributes and indicates whether or not they are present. If an attribute is present, its dimensions are listed. A truncated list of features and sample IDs are included (if they are present). Returns ------- str String representation of the ordination results. """ lines = ["Ordination results:"] method = "%s (%s)" % (self.long_method_name, self.short_method_name) lines.append(self._format_attribute(method, "Method", str)) attrs = [ (self.eigvals, "Eigvals"), (self.proportion_explained, "Proportion explained"), (self.features, "Features"), (self.samples, "Samples"), (self.biplot_scores, "Biplot Scores"), (self.sample_constraints, "Sample constraints"), ] for attr, attr_label in attrs: def formatter(e): return "x".join(["%d" % s for s in e.shape]) lines.append(self._format_attribute(attr, attr_label, formatter)) lines.append( self._add_id_line( attr_name="Feature IDs", ids=self.feature_ids, data=self.features ) ) lines.append( self._add_id_line( attr_name="Sample IDs", ids=self.sample_ids, data=self.samples ) ) return "\n".join(lines) def _add_id_line(self, attr_name, ids, data): """Helper to append ids to str.""" if ids is not None: return "\t%s: %s" % (attr_name, _pprint_strs(ids)) elif data is not None: return self._format_attribute( data, attr_name, _pprint_strs(_extract_row_ids) ) else: return "\t%s: N/A" % attr_name def _format_attribute(self, attr, attr_label, formatter): if attr is None: formatted_attr = "N/A" else: formatted_attr = formatter(attr) return "\t%s: %s" % (attr_label, formatted_attr) def plot( self, df=None, column=None, axes=None, axis_labels=None, title="", cmap=None, s=20, centroids=False, confidence_ellipses=False, ): """Create a scatterplot of ordination results colored by metadata. Creates a scatterplot of the ordination results, where each point represents a sample. Optionally, these points can be colored by metadata (see `df` and `column` below). Parameters ---------- df : pd.DataFrame, optional ``DataFrame`` containing sample metadata. Must be indexed by sample ID, and all sample IDs in the ordination results must exist in the ``DataFrame``. If ``None``, samples (i.e., points) will not be colored by metadata. column : str, optional Column name in `df` to color samples (i.e., points in the plot) by. Cannot have missing data (i.e., ``np.nan``). `column` can be numeric or categorical. If numeric, all values in the column will be cast to ``float`` and mapped to colors using `cmap`. A colorbar will be included to serve as a legend. If categorical (i.e., not all values in `column` could be cast to ``float``), colors will be chosen for each category using evenly-spaced points along `cmap`. A legend will be included. If ``None``, samples (i.e., points) will not be colored by metadata. axes : iterable of int, optional Indices of sample coordinates to plot. Must contain exactly two or three elements, for 2D or 3D plots, respectively. For example, ``axes=(0, 1, 2)`` (default if there are three or more dimensions) will create a 3D plot with PC1 on the x-axis, PC2 on the y-axis, and PC3 on the z-axis. ``axes=(0, 1)`` (default if there are only two dimensions) will create a 2D plot with PC1 on the x-axis and PC2 on the y-axis. axis_labels : iterable of str, optional Labels for the x-, y-, and z-axes. If ``None``, labels will be the values of `axes` cast as strings. title : str, optional Plot title. cmap : str or matplotlib.colors.Colormap, optional Name or instance of matplotlib colormap to use for mapping `column` values to colors. If ``None``, defaults to the colormap specified in the matplotlib rc file. Qualitative colormaps (e.g., ``Set1``) are recommended for categorical data, while sequential colormaps (e.g., ``Greys``) are recommended for numeric data. See [1]_ for these colormap classifications. s : scalar or iterable of scalars, optional Size of points. See matplotlib's ``Axes3D.scatter`` documentation for more details. centroids : bool, optional If True, plot the centroids of each category in `column`. confidence_ellipses : bool, optional If True, plot confidence ellipses for each category in `column`. Ellipses are calculated using to fit an interval of 2 standard deviations using the covariance of the points. Only supported for 2D plots. Returns ------- matplotlib.figure.Figure Figure containing the scatterplot and legend/colorbar if metadata were provided. Raises ------ ValueError Raised on invalid input, including the following situations: - there are not at least two dimensions to plot - there are not exactly two or three values in `axes`, they are not unique, or are out of range - there are not exactly two or three values in `axis_labels` - either `df` or `column` is provided without the other - `column` is not in the ``DataFrame`` - sample IDs in the ordination results are not in `df` or have missing data in `column` - confidence ellipses are requested for 3D plots Notes ----- This method creates basic plots of ordination results, and is intended to provide a quick look at the results in the context of metadata (e.g., from within the Jupyter Lab). For more customization and to generate publication-quality figures, we recommend EMPeror [2]_. References ---------- .. [1] http://matplotlib.org/examples/color/colormaps_reference.html .. [2] EMPeror: a tool for visualizing high-throughput microbial community data. Vazquez-Baeza Y, Pirrung M, Gonzalez A, Knight R. Gigascience. 2013 Nov 26;2(1):16. http://biocore.github.io/emperor/ Examples -------- .. plot:: Define a distance matrix with four samples labelled A-D: >>> from skbio import DistanceMatrix >>> dm = DistanceMatrix([[0., 0.21712454, 0.5007512, 0.91769271], ... [0.21712454, 0., 0.45995501, 0.80332382], ... [0.5007512, 0.45995501, 0., 0.65463348], ... [0.91769271, 0.80332382, 0.65463348, 0.]], ... ['A', 'B', 'C', 'D']) Define metadata for each sample in a ``pandas.DataFrame``: >>> import pandas as pd >>> metadata = { ... 'A': {'body_site': 'skin'}, ... 'B': {'body_site': 'gut'}, ... 'C': {'body_site': 'gut'}, ... 'D': {'body_site': 'skin'}} >>> df = pd.DataFrame.from_dict(metadata, orient='index') Run principal coordinate analysis (PCoA) on the distance matrix: >>> from skbio.stats.ordination import pcoa >>> pcoa_results = pcoa(dm) Plot the ordination results, where each sample is colored by body site (a categorical variable): >>> fig = pcoa_results.plot( ... df=df, column='body_site', ... title='Samples colored by body site', ... cmap='Set1', s=50 ... ) # doctest: +SKIP """ # Note: New features should not be added to this method and should # instead be added to EMPeror (http://biocore.github.io/emperor/). # Only bug fixes and minor updates should be made to this method. self._get_mpl_plt() # This handles any input, numpy/pandas/polars coord_matrix = np.atleast_2d(self.samples).T # Determine default axes based on available dimensions if axes is None: num_dims = coord_matrix.shape[0] if num_dims >= 3: axes = [0, 1, 2] elif num_dims == 2: axes = [0, 1] else: raise ValueError( "At least two dimensions are required to plot " "ordination results. There is only %d dimension." % num_dims ) self._validate_plot_axes(coord_matrix, axes) point_colors, category_to_color = self._get_plot_point_colors( df, column, self.sample_ids, cmap ) # Validate metadata requirements for centroids and ellipses if category_to_color is None and centroids is True: raise ValueError("Metadata must be provided to plot centroids.") if category_to_color is None and confidence_ellipses is True: raise ValueError("Metadata must be provided to plot confidence ellipses.") # Check if confidence ellipses are requested for 3D plot if len(axes) == 3 and confidence_ellipses is True: raise ValueError("Confidence ellipses can only be plotted in 2D.") # Create figure and axes is_3d = len(axes) == 3 if is_3d: fig = self.plt.figure() ax = fig.add_subplot(projection="3d") xs, ys, zs = ( coord_matrix[axes[0]], coord_matrix[axes[1]], coord_matrix[axes[2]], ) else: fig, ax = self.plt.subplots() xs, ys = coord_matrix[axes[0]], coord_matrix[axes[1]] zs = None # Create scatter plot if zs is None: scatter_fn = functools.partial(ax.scatter, xs, ys, s=s) else: scatter_fn = functools.partial(ax.scatter, xs, ys, zs, s=s) if point_colors is None: plot = scatter_fn() else: plot = scatter_fn(c=point_colors) # Add centroids if requested if centroids and category_to_color: self._plot_centroids(ax, df, column, category_to_color, axes, is_3d) # Add confidence ellipses if requested (2D only) if confidence_ellipses and not is_3d and category_to_color: self._plot_confidence_ellipses(ax, df, column, category_to_color, axes) # Set axis labels if axis_labels is None: axis_labels = ["%d" % axis for axis in axes] elif len(axis_labels) != len(axes): raise ValueError( f"axis_labels ({len(axis_labels)} elements) " f"must contain the same number of elements as " f"axes ({len(axes)} elements)." ) ax.set_xlabel(axis_labels[0]) ax.set_ylabel(axis_labels[1]) ax.set_xticklabels([]) ax.set_yticklabels([]) if is_3d: ax.set_zlabel(axis_labels[2]) ax.set_zticklabels([]) ax.set_title(title) # Create legend/colorbar if point_colors is not None: if category_to_color is None: fig.colorbar(plot) else: self._plot_categorical_legend( ax, category_to_color, centroids=centroids, confidence_ellipses=confidence_ellipses, ) return fig def _plot_centroids(self, ax, df, column, category_to_color, axes, is_3d): """Plot centroids for each category. Parameters ---------- ax : matplotlib.axes.Axes The axes object to plot on. df : pd.DataFrame DataFrame containing sample metadata. column : str Column name in df for grouping. category_to_color : dict Mapping of category labels to colors. axes : list of int Indices of axes to plot. is_3d : bool Whether the plot is 3D. """ current_centroids = self.samples.groupby(df[column]).mean() for label, color in category_to_color.items(): if label not in current_centroids.index: continue centroid = current_centroids.loc[label] if is_3d: ax.scatter( centroid.iloc[axes[0]], centroid.iloc[axes[1]], centroid.iloc[axes[2]], color=color, marker="x", s=30, label=f"'{label}' centroid", ) else: ax.scatter( centroid.iloc[axes[0]], centroid.iloc[axes[1]], color=color, marker="x", s=30, label=f"'{label}' centroid", ) def _plot_confidence_ellipses(self, ax, df, column, category_to_color, axes): """Plot confidence ellipses for each category in 2D. Ellipses are calculated to fit an interval of 2 standard deviations using the covariance of the points. Parameters ---------- ax : matplotlib.axes.Axes The axes object to plot on. df : pd.DataFrame DataFrame containing sample metadata. column : str Column name in df for grouping. category_to_color : dict Mapping of category labels to colors. axes : list of int Indices of axes to plot (must be length 2). Notes ----- Derived from: https://matplotlib.org/stable/gallery/statistics/confidence_ellipse.html """ for label, color in category_to_color.items(): group = self.samples[df[column] == label] if len(group) < 3: continue # can't draw ellipse with less than 3 points x_vals = group.iloc[:, axes[0]] y_vals = group.iloc[:, axes[1]] # Covariance matrix cov = np.cov(x_vals, y_vals) # Pearson correlation coefficient pearson = cov[0, 1] / np.sqrt(cov[0, 0] * cov[1, 1]) # Ellipse radii ell_radius_x = np.sqrt(1 + pearson) ell_radius_y = np.sqrt(1 - pearson) # Means mean_x = x_vals.mean() mean_y = y_vals.mean() # 2 standard deviations for confidence interval scale_x = np.sqrt(cov[0, 0]) * 2 scale_y = np.sqrt(cov[1, 1]) * 2 # Rotation angle angle = 0.5 * np.degrees(np.arctan2(2 * cov[0, 1], cov[0, 0] - cov[1, 1])) # Create and transform ellipse ellipse = self.mpl.patches.Ellipse( (0, 0), width=ell_radius_x * 2, height=ell_radius_y * 2, facecolor="none", edgecolor=color, lw=2, label=f"'{label}' ellipse", ) transf = ( self.mpl.transforms.Affine2D() .rotate_deg(angle) .scale(scale_x, scale_y) .translate(mean_x, mean_y) ) ellipse.set_transform(transf + ax.transData) ax.add_patch(ellipse) def _validate_plot_axes(self, coord_matrix, axes): """Validate `axes` against coordinates matrix.""" num_dims = coord_matrix.shape[0] if num_dims < 2: raise ValueError( "At least two dimensions are required to plot " "ordination results. There are only %d " "dimension(s)." % num_dims ) if len(axes) not in [2, 3]: raise ValueError( "`axes` must contain exactly two or three elements " "(found %d elements)." % len(axes) ) if len(set(axes)) != len(axes): raise ValueError("The values provided for `axes` must be unique.") for idx, axis in enumerate(axes): if axis < 0 or axis >= num_dims: raise ValueError("`axes[%d]` must be >= 0 and < %d." % (idx, num_dims)) def _get_plot_point_colors(self, df, column, ids, cmap): """Return a list of colors for each plot point given a metadata column. If `column` is categorical, additionally returns a dictionary mapping each category (str) to color (used for legend creation). """ if (df is None and column is not None) or (df is not None and column is None): raise ValueError( "Both df and column must be provided, or both must be None." ) elif df is None and column is None: point_colors, category_to_color = None, None else: if column not in df: raise ValueError("Column '%s' not in data frame." % column) col_vals = df.reindex(ids, axis=0).loc[:, column] if col_vals.isnull().any(): raise ValueError( "One or more IDs in the ordination results " "are not in the data frame, or there is " "missing data in the data frame's '%s' " "column." % column ) category_to_color = None try: point_colors = col_vals.astype(float) except ValueError: # we have categorical data, so choose a color for each # category, where colors are evenly spaced across the # colormap. # derived from http://stackoverflow.com/a/14887119 categories = col_vals.unique() cmap = self.plt.get_cmap(cmap) category_colors = cmap(np.linspace(0, 1, len(categories))) category_to_color = dict(zip(categories, category_colors)) point_colors = col_vals.apply(lambda x: category_to_color[x]) point_colors = point_colors.tolist() return point_colors, category_to_color def _plot_categorical_legend( self, ax, color_dict, centroids=False, confidence_ellipses=False ): """Add legend to plot using specified mapping of category to color.""" # derived from http://stackoverflow.com/a/20505720 proxies = [] labels = [] for category in color_dict: proxy = self.mpl.lines.Line2D( [0], [0], linestyle="none", c=color_dict[category], marker="o" ) proxies.append(proxy) labels.append(category) # Add centroid markers if enabled if centroids: proxy = self.mpl.lines.Line2D( [0], [0], linestyle="none", c=color_dict[category], marker="x", markersize=np.sqrt(30), ) proxies.append(proxy) labels.append(f"'{category}' centroid") # Add confidence ellipse lines if enabled if confidence_ellipses: proxy = self.mpl.lines.Line2D([0], [0], c=color_dict[category], lw=2) proxies.append(proxy) labels.append(f"'{category}' ellipse") # place legend outside of the axes (centered) # derived from http://matplotlib.org/users/legend_guide.html ax.legend( proxies, labels, numpoints=1, loc=6, bbox_to_anchor=(1.05, 0.5), borderaxespad=0.0, ) def rename(self, mapper, matrix="samples", strict=True): r"""Rename sample or feature IDs in the data matrix. Parameters ---------- mapper : dict or callable A dictionary or function that maps current IDs to new IDs. matrix : str, optional Specifies which matrix contains the IDs to be renamed. Either "samples" (default) or "features". strict : bool, optional If ``True`` (default), every ID in the matrix must be included in ``mapper``. If ``False``, only the specified IDs will be renamed. Raises ------ ValueError If ``mapper`` does not contain all of the same IDs in the matrix whereas in strict mode. ValueError If renaming features but self does not contain features. ValueError If ``matrix`` is neither "samples" nor "features". """ if matrix not in ("samples", "features"): raise ValueError('Matrix must be either "samples" or "features".') df = getattr(self, matrix) if matrix == "features" and df is None: raise ValueError( "`features` were not provided on the construction of this object." ) if strict and isinstance(mapper, dict) and not set(df.index).issubset(mapper): raise ValueError( "The IDs in mapper do not include all IDs in the %s matrix." % matrix ) df.rename(index=mapper, inplace=True) scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/_principal_component_analysis.py000066400000000000000000000243061520735541300314520ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from scipy.linalg import eigh, svd from scipy.sparse.linalg import eigsh, svds from ._ordination_results import OrdinationResults from skbio.table._tabular import _create_table, _create_table_1d, _ingest_table def pca( X, method="eigh", iterative=False, dimensions=None, sample_ids=None, feature_ids=None, output_format=None, ): r"""Perform Principal Component Analysis (PCA). Principal component analysis (PCA) is a dimensionality reduction technique that finds linear combinations of features which maximize the variance among samples. The vectors of feature weights resulting from this are the principal components of the data. The original samples are projected onto the principal components to obtain a lower-dimensional representation of the data that captures as much variance as possible. PCA operates on a set of `n` samples that are each associated with a set of `p` features. Each sample is then a row of the `n` :math:`\times` `p` data matrix :math:`\mathbf{X}`, whose columns are the features of the data. The goal of PCA is to find vectors :math:`\mathbf{w}_i` in feature space along which the variance of the samples is maximized, the principal components of the data matrix: .. math:: \mathbf{w}_i^\ast = \arg\max_{\mathbf{w}_i} \operatorname{Var}(\mathbf{X_c} \mathbf{w}_i) where :math:`\mathbf{X_c}` is the mean-centered data matrix, centered by columns (features). The principal components of :math:`\mathbf{X}` are the unit eigenvectors of the covariance matrix :math:`\mathbf{\Sigma}`: .. math:: \mathbf{\Sigma} = \frac{1}{n-1} \mathbf{X_c}^T \mathbf{X_c} Each entry :math:`\mathbf{\Sigma}_{ij}` is the covariance between features `i` and `j`: .. math:: \mathbf{\Sigma}_{ij} = \operatorname{Cov}(\mathbf{X}_{\cdot i}, \mathbf{X}_{\cdot j}) The eigenvalue associated with each principal direction is the variance of the data along that direction: .. math:: \sigma_i^2 = \operatorname{Var}(\mathbf{X_c} \mathbf{w}_i) Parameters ---------- X : table_like Samples by features table (n, p). See :ref:`supported formats `. method : str, optional Matrix decomposition method to use. Default is "eigh" (eigendecomposition), which computes exact eigenvectors and eigenvalues of the covariance matrix. The alternative is "svd" (singular value decomposition), which bypasses computing the full covariance matrix and instead computes the singular values of the input matrix. iterative : bool, optional Whether to use iterative algorithms via ARPACK to compute only the specified number of eigenvalues. Default is False, which uses dense algorithms via LAPACK to compute all eigenvalues. Only applied if ``dimensions`` is specified; otherwise, dense algorithms are used regardless. dimensions : int, optional Number of principal components to compute. Must be a positive integer less than or equal to min(n, p). If not provided, all principal components will be computed. sample_ids, feature_ids, output_format : optional Standard table parameters. See :ref:`table_params` for details. Returns ------- OrdinationResults Object that stores the PCA results, including eigenvalues, the proportion of variance explained by each of them, and transformed sample coordinates. Raises ------ ValueError If ``dimensions`` is not a positive integer less than or equal to min(n_samples, n_features) ValueError If ``method`` is not one of "eigh" or "svd" See Also -------- OrdinationResults Notes ----- Principal Component Analysis (PCA) was first described in [1]_ and [2]_. Two methods are provided for performing the matrix decomposition: The default method, ``eigh``, constructs the covariance matrix first and then performs eigenvalue decomposition to obtain the principal components. The alternative method, ``svd``, performs singular value decomposition (SVD) on the centered data matrix to obtain the same result. Because SVD avoids explicitly computing the covariance matrix, it may be more accurate than eigenvalue decomposition for very small eigenvalues. The ``iterative`` parameter determines whether the methods are performed by dense algorithms, which compute all eigenvalues to full accuracy via LAPACK, or sparse algorithms, which compute only the specified number of eigenvalues iteratively by ARPACK. Dense algorithms are used by default, while iterative algorithms are preferred for very large data matrices when the desired number of principal components is much less than the size of the data matrix. The number of principal components kept is determined by ``dimensions``, and if no dimension is specified, the default is to compute all eigenvalues. The iterative parameter is incompatible with computing all eigenvalues; therefore, if no dimension is specified, dense algorithms are used regardless. If ``iterative`` is specified as False, ``svd`` is computed by SciPy's dense "svd" function, and ``eigh`` is computed by SciPy's dense "eigh" function. If ``iterative`` is specified as True, the methods are computed by SciPy's sparse "svds" and "eigsh" functions respectively. References ---------- .. [1] Pearson, K. (1901). On lines and planes of closest fit to systems of points in space. Philosophical Magazine, 2(11), 559–572. .. [2] Hotelling, H. (1933). Analysis of a complex of statistical variables into principal components. Journal of Educational Psychology, 24(6), 417–441, 498–520. """ # Ingestion of input data matrix X, row_ids, column_ids = _ingest_table(X, sample_ids, feature_ids) # Center the data matrix X_centered = X - np.mean(X, axis=0) n = X.shape[0] # Handle dimensions parameter if dimensions is None: sub_idx = None elif dimensions <= 0 or dimensions > min(X.shape): raise ValueError( "Dimensions must be a positive integer less than or equal to " "min(n_samples, n_features)" ) elif type(dimensions) is not int: raise ValueError("Dimensions must be a positive integer") else: sub_idx = [n - dimensions, n - 1] # Perform eigendecomposition if method == "eigh": # Compute the covariance matrix covariance_matrix = np.cov(X_centered, rowvar=False) # Perform iterative sparse eigendecomposition only if "iterative" # is selected and a valid dimension is specified if not iterative or dimensions is None: # Perform full dense eigendecomposition variances, components = eigh(covariance_matrix, subset_by_index=sub_idx) # Sort output of eigh in descending order (it is ascending by default) components = components.T[::-1] variances = variances[::-1] else: # Perform iterative sparse eigendecomposition variances, components = eigsh(covariance_matrix, k=dimensions) components = components.T # Compute total variance using the fact that the trace # of a matrix is the sum of its eigenvalues -- # We want to avoid this for SVD # because it involves computing the covariance matrix total_variance = np.trace(covariance_matrix) # Perform singular value decomposition elif method == "svd": # The eigenvalues of the covariance matrix are the right singular values # of the centered data matrix, scaled by the total degrees of freedom # (number of samples - 1) # Perform iterative sparse SVD only if "iterative" is selected and # a valid dimension is specified if not iterative or dimensions is None: # Perform full dense SVD _, singular_values, components = svd(X_centered) # Collect only the specified number of components if applicable if dimensions: singular_values = singular_values[:dimensions] components = components[:dimensions] else: # Perform iterative sparse SVD _, singular_values, components = svds(X_centered, k=dimensions) # Compute explained variances variances = np.square(singular_values) / (n - 1) # The total variance, the trace of the covariance matrix, is equal to # the squared Frobenius norm of the centered data matrix scaled by # the total degrees of freedom total_variance = np.sum(np.square(X_centered)) / (n - 1) # Handle method parameter else: raise ValueError("Method must be 'eigh' or 'svd'") # Iterative algorithms may return an unsorted output, # so they should be sorted if iterative: idx = variances.argsort()[::-1] variances = variances[idx] components = components[idx, :] # Project samples onto principal components projected_samples = np.dot(X_centered, components.T) # Build the OrdinationResults object pc_ids = ["%s%d" % ("PC", i + 1) for i in range(variances.shape[0])] eigvals = _create_table_1d(variances, index=pc_ids, backend=output_format) samples = _create_table( projected_samples, index=row_ids, columns=pc_ids, backend=output_format ) features = _create_table( components, index=pc_ids, columns=column_ids, backend=output_format ) return OrdinationResults( short_method_name="PCA", long_method_name="Principal Component Analysis", eigvals=eigvals, samples=samples, sample_ids=row_ids, features=features, feature_ids=pc_ids, proportion_explained=eigvals / total_variance, ) scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/_principal_coordinate_analysis.py000066400000000000000000000704311520735541300315770ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from numbers import Integral from warnings import warn import numpy as np import pandas as pd from scipy.linalg import eigh as scipy_eigh from skbio.util import get_rng from skbio.stats.distance import DistanceMatrix from skbio.table._tabular import _create_table, _create_table_1d from ._ordination_results import OrdinationResults from ._utils import center_distance_matrix as center_distance_matrix_np, scale from skbio.binaries import ( pcoa_fsvd_available as _skbb_pcoa_fsvd_available, pcoa_fsvd as _skbb_pcoa_fsvd, ) from skbio.util._decorator import params_aliased from skbio.util._array import ingest_array, _to_numpy # Double centering (Gower centering) of distance matrix for PCoA # Transforms squared distances to centered inner product matrix via: # E_matrix: E = -D^2 / 2 # F_matrix: Double-centers E by removing row/column/grand means # This is required for eigendecomposition. # # Based on implementation by Igor Sfiligoi def e_matrix(distance_matrix): return distance_matrix * distance_matrix / -2 def f_matrix(E_matrix): row_means = E_matrix.mean(axis=1, keepdims=True) col_means = E_matrix.mean(axis=0, keepdims=True) matrix_mean = E_matrix.mean() return E_matrix - row_means - col_means + matrix_mean def center_distance_matrix(distance_matrix, inplace=False): """Center a distance matrix. Note: For JAX arrays (immutable) and CuPy arrays (GPU), the ``inplace`` argument is accepted for API compatibility but ignored — the function always returns a centered array. """ # For true NumPy arrays, use the Cython-accelerated implementation, # which also supports in-place modification. if isinstance(distance_matrix, np.ndarray): return center_distance_matrix_np(distance_matrix, inplace=inplace) # For JAX/CuPy and other array-API backends, use the generic # double-centering path; `inplace` is ignored for these backends. xp, distance_matrix = ingest_array(distance_matrix) return f_matrix(e_matrix(distance_matrix)) # Compute partial eigendecomposition on host via SciPy LAPACK for JAX/CuPy. # Transfers to NumPy (JAX doesn't support subset_by_index), computes, returns to device. def _host_partial_eigh(matrix_any, subidx): xp, matrix_any = ingest_array(matrix_any) device = getattr(matrix_any, "device", None) mat_np = _to_numpy(matrix_any) if mat_np.dtype != np.float64: mat_np = mat_np.astype(np.float64, copy=False) mat_np = np.ascontiguousarray(mat_np) eigvals_np, eigvecs_np = scipy_eigh(mat_np, subset_by_index=subidx) if device is not None: return ( xp.asarray(eigvals_np, device=device), xp.asarray(eigvecs_np, device=device), ) return xp.asarray(eigvals_np), xp.asarray(eigvecs_np) @params_aliased( [ ("dimensions", "number_of_dimensions", "0.7.0", False), ("distmat", "distance_matrix", "0.7.0", False), ] ) def pcoa( distmat, method="eigh", dimensions=0, inplace=False, seed=None, warn_neg_eigval=0.01, output_format=None, ): r"""Perform Principal Coordinate Analysis (PCoA). PCoA is an ordination method similar to Principal Components Analysis (PCA), with the difference that it operates on distance matrices, calculated using meaningful and typically non-Euclidian methods. Parameters ---------- distmat : DistanceMatrix The input distance matrix. method : str, optional Matrix decomposition method to use. Default is "eigh" (eigendecomposition), which computes exact eigenvectors and eigenvalues for all dimensions. The alternate is "fsvd" (fast singular value decomposition), a heuristic that can compute only a given number of dimensions. dimensions : int or float, optional Dimensions to reduce the distance matrix to. This number determines how many eigenvectors and eigenvalues will be returned. If an integer is provided, the exact number of dimensions will be retained. If a float between 0 and 1, it represents the fractional cumulative variance to be retained. Default is 0, which will retain the same number of dimensions as the distance matrix. inplace : bool, optional If True, the input distance matrix will be centered in-place to reduce memory consumption, at the cost of losing the original distances. Default is False. seed : int or np.random.Generator, optional A user-provided random seed or random generator instance for method "fsvd". See :func:`details `. .. versionadded:: 0.6.3 warn_neg_eigval : bool or float, optional Raise a warning if any negative eigenvalue is obtained and its magnitude exceeds the specified fraction threshold compared to the largest positive eigenvalue, which suggests potential inaccuracy in the PCoA result. Default is 0.01. Set True to warn regardless of the magnitude. Set False to disable warning completely. .. versionadded:: 0.6.3 output_format : optional Standard table parameters. See :ref:`table_params` for details. Returns ------- OrdinationResults Object that stores the PCoA results, including eigenvalues, the proportion explained by each of them, and transformed sample coordinates. See Also -------- OrdinationResults Notes ----- This function uses parallel computation for improved performance. See the :install:`parallelization guide <#parallelization>` for information on controlling the number of threads used. Low-level acceleration is available for this function. See :install:`scikit-bio-binaries <#acceleration>` for more information. Principal Coordinate Analysis (PCoA) was first described in [1]_. This function uses a choice of two methods for matrix decomposition: The default method, ``eigh``, performs eigendecomposition, an exact method that computes all eigenvectors and eigenvalues. The alternative method, ``fsvd``, performs fast singular value decomposition (FSVD) [2]_, an efficient heuristic method that allows a custom number of dimensions to be specified to reduce calculation at the cost of losing accuracy. The degree of accuracy lost is dependent on dataset. Note that the default method ``eigh`` does not natively support a given number of dimensions to reduce a matrix to. Therefore, if this parameter is specified, all eigenvectors and eigenvalues will be simply be computed with no speed gain, and only the specified number of dimensions will be returned. Eigenvalues represent the magnitude of individual principal coordinates, and they are usually positive. However, negative eigenvalues can occur when the distances were calculated using a non-Euclidean metric that does not satisfy triangle inequality. If the negative eigenvalues are small in magnitude compared to the largest positive eigenvalue, it is usually safe to ignore them. However, large negative eigenvalues may indicate result inaccuracy, in which case a warning message will be displayed. The parameter ``warn_neg_eigval`` controls the threshold for the warning. PCoA on Euclidean distances is equivalent to Principal Component Analysis (PCA). However, in ecology, the Euclidean distance preserved by PCA is often not a good choice because it deals poorly with double zeros. For example, species have unimodal distributions along environmental gradients. If a species is absent from two sites simultaneously, it can't be known if an environmental variable is too high in one of them and too low in the other, or too low in both, etc. On the other hand, if a species is present in two sites, that means that the sites are similar. Note that the returned eigenvectors are not normalized to unit length. References ---------- .. [1] Gower, J. C. (1966). Some distance properties of latent root and vector methods used in multivariate analysis. Biometrika, 53(3-4), 325-338. .. [2] Halko, N., Martinsson, P. G., Shkolnisky, Y., & Tygert, M. (2011). An algorithm for the principal component analysis of large data sets. SIAM Journal on Scientific computing, 33(5), 2580-2594. """ # this converts to redundant form, regardless of input type distmat = DistanceMatrix(distmat) # If no dimension specified, by default will compute all eigenvectors # and eigenvalues if dimensions == 0: if method == "fsvd" and distmat.data.shape[0] > 10: warn( "FSVD: since no value for dimensions is specified, " "PCoA for all dimensions will be computed, which may " "result in long computation time if the original " "distance matrix is large.", RuntimeWarning, ) elif method == "eigh" and distmat.data.shape[0] > 10: warn( "EIGH: since no value for dimensions is specified, " "PCoA for all dimensions will be computed, which may " "result in long computation time if the original " "distance matrix is large.", RuntimeWarning, ) # distmat is guaranteed to be square dimensions = distmat.data.shape[0] elif dimensions < 0: raise ValueError( "Invalid operation: cannot reduce distance matrix " "to negative dimensions using PCoA. Did you intend " 'to specify the default value "0", which sets ' "the dimensions equal to the " "dimensionality of the given distance matrix?" ) elif dimensions > distmat.data.shape[0]: raise ValueError("Invalid operation: cannot extend distance matrix size.") elif not isinstance(dimensions, Integral) and dimensions > 1: raise ValueError( "Invalid operation: A floating-point number greater than 1 cannot be " "supplied as the number of dimensions." ) if warn_neg_eigval and not 0 <= warn_neg_eigval <= 1: raise ValueError( "warn_neg_eigval must be Boolean or a floating-point number between 0 " "and 1." ) # new parameter for ndim = number of dimensions (accounting for # non-int values) ndim = dimensions # Perform eigendecomposition if method == "eigh": long_method_name = "Principal Coordinate Analysis" # Center distance matrix, a requirement for PCoA here matrix_data = center_distance_matrix(distmat.data, inplace=inplace) if 0 < dimensions < 1: if matrix_data.shape[0] > 10: warn( "EIGH: since value for dimensions is specified as float," " PCoA for all dimensions will be computed, which may" " result in long computation time if the original" " distance matrix is large." " Consider specifying an integer value to optimize performance.", RuntimeWarning, ) ndim = matrix_data.shape[0] subidx = [matrix_data.shape[0] - ndim, matrix_data.shape[0] - 1] xp, matrix_data = ingest_array(matrix_data) # For JAX/CuPy, we compute the partial eigendecomposition on host via SciPy # LAPACK, since they don't support subset_by_index. if ndim < matrix_data.shape[0]: eigvals, eigvecs = _host_partial_eigh(matrix_data, subidx) else: eigvals, eigvecs = xp.linalg.eigh(matrix_data) elif method == "fsvd": long_method_name = "Approximate Principal Coordinate Analysis using FSVD" if 0 < dimensions < 1: if distmat.data.shape[0] > 10: warn( "FSVD: since value for dimensions is specified as float," " PCoA for all dimensions will be computed, which may" " result in long computation time if the original" " distance matrix is large." " Consider specifying an integer value to optimize performance.", RuntimeWarning, ) ndim = distmat.data.shape[0] if _skbb_pcoa_fsvd_available( distmat.data, dimensions, inplace, seed ): # pragma: no cover # unlikely to throw here, but just in case try: eigvals, coordinates, proportion_explained = _skbb_pcoa_fsvd( distmat.data, dimensions, inplace, seed ) xp_eigvals, eigvals = ingest_array(eigvals) xp_coordinates, coordinates = ingest_array(coordinates) xp_proportion_explained, proportion_explained = ingest_array( proportion_explained ) eigvals, coordinates, proportion_explained = ( xp_eigvals.asarray(eigvals), xp_coordinates.asarray(coordinates), xp_proportion_explained.asarray(proportion_explained), ) return _encapsulate_pcoa_result( long_method_name, eigvals, coordinates, proportion_explained, distmat.ids, output_format, ) except Exception as e: warn( "Attempted to use binaries.pcoa_fsvd but failed, " "using regular logic instead.", RuntimeWarning, ) # if we got here, we could not use skbb # Center distance matrix, a requirement for PCoA here matrix_data = center_distance_matrix(distmat.data, inplace=inplace) eigvals, eigvecs = _fsvd(matrix_data, ndim, seed=seed) else: raise ValueError( "PCoA eigendecomposition method {} not supported.".format(method) ) # Ensure dimensions does not exceed available dimensions # dimensions = min(dimensions, eigvals.shape[0]) # cogent makes eigenvalues positive by taking the # abs value, but that doesn't seem to be an approach accepted # by L&L to deal with negative eigenvalues. We raise a warning # in that case. First, we make values close to 0 equal to 0. xp, eigvals = ingest_array(eigvals) negative_close_to_zero = xp.isclose(eigvals, 0) eigvals = xp.where(negative_close_to_zero, 0, eigvals) # eigvals might not be ordered, so we first sort them, then analogously # sort the eigenvectors by the ordering of the eigenvalues too idxs_descending = eigvals.argsort()[::-1] eigvals = eigvals[idxs_descending] eigvecs = eigvecs[:, idxs_descending] # large negative eigenvalues suggest result inaccuracy # see: https://github.com/scikit-bio/scikit-bio/issues/1410 # convert to float because JAX may return a DeviceArray, # which cannot be directly compared to a float if warn_neg_eigval and float(eigvals[-1]) < 0: if warn_neg_eigval is True or -eigvals[-1] > eigvals[0] * warn_neg_eigval: warn( "The result contains negative eigenvalues that are large in magnitude," " which may suggest result inaccuracy. See Notes for details. The" " negative-most eigenvalue is {0} whereas the largest positive one is" " {1}.".format(eigvals[-1], eigvals[0]), RuntimeWarning, ) # If we return only the coordinates that make sense (i.e., that have a # corresponding positive eigenvalue), then Jackknifed Beta Diversity # won't work as it expects all the OrdinationResults to have the same # number of coordinates. In order to solve this issue, we return the # coordinates that have a negative eigenvalue as 0 xp, eigvecs = ingest_array(eigvecs) # assume same backend for eigvals and eigvecs num_positive = (eigvals >= 0).sum() # Create a mask to set negative eigenvalues to 0 and their corresponding # eigenvectors to 0 because JAX does not have in-place operations. idx = xp.arange(eigvals.shape[0]) mask = idx < num_positive eigvals = xp.where(mask, eigvals, 0) eigvecs = eigvecs * mask if ndim != distmat.data.shape[0]: # Since the dimension parameter, hereafter referred to as 'd', # restricts the number of eigenvalues and eigenvectors that FSVD # computes, we need to use an alternative method to compute the sum # of all eigenvalues, used to compute the array of proportions # explained. Otherwise, the proportions calculated will only be # relative to d number of dimensions computed; whereas we want # it to be relative to the entire dimensionality of the # centered distance matrix. # An alternative method of calculating th sum of eigenvalues is by # computing the trace of the centered distance matrix. # See proof outlined here: https://goo.gl/VAYiXx xp_mat, matrix_data = ingest_array(matrix_data) sum_eigenvalues = xp_mat.trace(matrix_data) else: # Calculate proportions the usual way sum_eigenvalues = xp.sum(eigvals) proportion_explained = eigvals / sum_eigenvalues if 0 < dimensions < 1: xp_prop, proportion_explained = ingest_array(proportion_explained) cumulative_variance = xp_prop.cumsum(proportion_explained) ndim = xp_prop.searchsorted(cumulative_variance, dimensions, side="left") + 1 # gives the number of dimensions needed to reach specified variance # updates number of dimensions to reach the requirement of variance. dimensions = ndim # In case eigh is used, eigh computes all eigenvectors and -values. # So if dimensions was specified, we manually need to ensure # only the requested number of dimensions # (number of eigenvectors and eigenvalues, respectively) are returned. eigvecs = eigvecs[:, :dimensions] eigvals = eigvals[:dimensions] proportion_explained = proportion_explained[:dimensions] # Scale eigenvalues to have length = sqrt(eigenvalue). This # works because np.linalg.eigh returns normalized # eigenvectors. Each row contains the coordinates of the # objects in the space of principal coordinates. Note that at # least one eigenvalue is zero because only n-1 axes are # needed to represent n points in a euclidean space. coordinates = eigvecs * xp.sqrt(eigvals) return _encapsulate_pcoa_result( long_method_name, eigvals, coordinates, proportion_explained, distmat.ids, output_format, ) def _encapsulate_pcoa_result( long_method_name, eigvals, coordinates, proportion_explained, ids, output_format ): r"""Format PCoA results Helper function for converting raw buffers of the pcoa function into proper OrdinationResult object. Parameters ---------- long_method_name: str The verbose name of the method used. eigvals: ndarray Eigenvalues coordinates: ndarray Sample coordinates proportion_explained: ndarray Proportions explained ids: array Distance matrix ids output_format : optional Standard table parameters. See :ref:`table_params` for details. Returns ------- OrdinationResults Object that stores the PCoA results, including eigenvalues, the proportion explained by each of them, and transformed sample coordinates. See Also -------- OrdinationResults """ dimensions = eigvals.shape[0] axis_labels = ["PC%d" % i for i in range(1, dimensions + 1)] return OrdinationResults( short_method_name="PCoA", long_method_name=long_method_name, eigvals=_create_table_1d(eigvals, index=axis_labels, backend=output_format), samples=_create_table( coordinates, index=ids, columns=axis_labels, backend=output_format, ), proportion_explained=_create_table_1d( proportion_explained, index=axis_labels, backend=output_format ), ) @params_aliased([("dimensions", "number_of_dimensions", "0.7.0", False)]) def _fsvd(centered_distance_matrix, dimensions=10, seed=None): """Perform singular value decomposition. More specifically in this case eigendecomposition, using fast heuristic algorithm nicknamed "FSVD" (FastSVD), adapted and optimized from the algorithm described by Halko et al (2011). Parameters ---------- centered_distance_matrix : np.array Numpy matrix representing the distance matrix for which the eigenvectors and eigenvalues shall be computed dimensions : int Number of dimensions to keep. Must be lower than or equal to the rank of the given distance_matrix. seed : int or np.random.Generator, optional A user-provided random seed or random generator instance. Returns ------- np.array Array of eigenvectors, each with dimensions length. np.array Array of eigenvalues, a total number of dimensions. Notes ----- The algorithm is based on [1]_. Ported from MATLAB implementation described in [2]_. References ---------- .. [1] Halko, N., Martinsson, P. G., Shkolnisky, Y., & Tygert, M. (2011). An algorithm for the principal component analysis of large data sets. SIAM Journal on Scientific computing, 33(5), 2580-2594. .. [2] https://stats.stackexchange.com/a/11934/211065 """ m, n = centered_distance_matrix.shape # Number of levels of the Krylov method to use. # For most applications, num_levels=1 or num_levels=2 is sufficient. num_levels = 1 # Changes the power of the spectral norm, thus minimizing the error). use_power_method = False # Note: a (conjugate) transpose is removed for performance, since we # only expect square matrices. if m != n: raise ValueError("FSVD expects square distance matrix") if dimensions > m or dimensions > n: raise ValueError( "FSVD: dimensions cannot be larger than" " the dimensionality of the given distance matrix." ) if dimensions < 0: raise ValueError( "Invalid operation: cannot reduce distance matrix " "to negative dimensions using PCoA. Did you intend " 'to specify the default value "0", which sets ' "the dimensions equal to the " "dimensionality of the given distance matrix?" ) k = dimensions + 2 # Form a real nxl matrix G whose entries are independent, identically # distributed Gaussian random variables of zero mean and unit variance xp, centered_distance_matrix = ingest_array(centered_distance_matrix) rng = get_rng(seed) G = xp.asarray( rng.standard_normal(size=(n, k)), device=centered_distance_matrix.device ) # `use_power_method` is constantly False, so `if` won't start. if use_power_method: # pragma: no cover # use only the given exponent H = xp.matmul(centered_distance_matrix, G) for x in range(2, num_levels + 2): # enhance decay of singular values # note: distance_matrix is no longer transposed, saves work # since we're expecting symmetric, square matrices anyway # (Daniel McDonald's changes) H = xp.matmul( centered_distance_matrix, xp.matmul(centered_distance_matrix, H) ) else: # compute the m x l matrices H^{(0)}, ..., H^{(i)} # Note that this is done implicitly in each iteration below. H = xp.matmul(centered_distance_matrix, G) # to enhance performance H = xp.hstack( ( H, xp.matmul( centered_distance_matrix, xp.matmul(centered_distance_matrix, H) ), ) ) # `num_levels` is constantly 1, so `for` loop won't start for x in range(3, num_levels + 2): # pragma: no cover tmp = xp.matmul( centered_distance_matrix, xp.matmul(centered_distance_matrix, H) ) H = xp.hstack( ( H, xp.matmul( centered_distance_matrix, xp.matmul(centered_distance_matrix, tmp), ), ) ) # Using the pivoted QR-decomposition, form a real m * ((i+1)l) matrix Q # whose columns are orthonormal, s.t. there exists a real # ((i+1)l) * ((i+1)l) matrix R for which H = QR # Q and center_distance_matrix share same bacnkend, so we can use the same xp Q, R = xp.linalg.qr(H) # Compute the n * ((i+1)l) product matrix T = A^T Q T = xp.matmul(centered_distance_matrix, Q) # step 3 # Form an SVD of T # T is same backend as Q, so we can use the same xp for both Vt, St, W = xp.linalg.svd(T, full_matrices=False) W = W.T # Compute the m * ((i+1)l) product matrix Ut = xp.matmul(Q, W) U_fsvd = Ut[:, :dimensions] S = St[:dimensions] # drop imaginary component, if we got one # Note: # In cogent, after computing eigenvalues/vectors, the imaginary part # is dropped, if any. We know for a fact that the eigenvalues are # real, so that's not necessary, but eigenvectors can in principle # be complex (see for example # http://math.stackexchange.com/a/47807/109129 for details) eigenvalues = S.real eigenvectors = U_fsvd.real return eigenvalues, eigenvectors def pcoa_biplot(ordination, y): """Compute the projection of descriptors into a PCoA matrix. Parameters ---------- ordination : OrdinationResults The computed principal coordinates analysis of dimensions (n, c) where the matrix ``y`` will be projected onto. y : DataFrame Samples by features table of dimensions (n, m). These can be environmental features or abundance counts. This table should be normalized in cases of dimensionally heterogeneous physical variables. Returns ------- OrdinationResults The modified input object that includes projected features onto the ordination space in the ``features`` attribute. Notes ----- This implementation is as described in Chapter 9 of [1]_. References ---------- .. [1] Legendre P. and Legendre L. 1998. Numerical Ecology. Elsevier, Amsterdam. """ # acknowledge that most saved ordinations lack a name, however if they have # a name, it should be PCoA if ordination.short_method_name != "" and ordination.short_method_name != "PCoA": raise ValueError( "This biplot computation can only be performed in a PCoA matrix." ) if set(y.index) != set(ordination.samples.index): raise ValueError( "The eigenvectors and the descriptors must describe the same samples." ) eigvals = ordination.eigvals.values coordinates = ordination.samples N = coordinates.shape[0] # align the descriptors and eigenvectors in a sample-wise fashion y = y.reindex(coordinates.index) # Preserve original column names before converting to array coord_columns = coordinates.columns.copy() # S_pc from equation 9.44 # Represents the covariance matrix between the features matrix and the # column-centered eigenvectors of the pcoa. xp, coordinates = ingest_array(coordinates) spc = (1 / (N - 1)) * xp.matmul(y.values.T, scale(coordinates, ddof=1)) # U_proj from equation 9.55, is the matrix of descriptors to be projected. # # Only get the power of non-zero values, otherwise this will raise a # divide by zero warning. There shouldn't be negative eigenvalues(?) Uproj = xp.sqrt(N - 1) * xp.matmul( spc, xp.diag( xp.where(eigvals > 0, xp.power(xp.where(eigvals > 0, eigvals, 1), -0.5), 0) ), ) ordination.features = pd.DataFrame( data=Uproj, index=y.columns.copy(), columns=coord_columns ) ordination.features.fillna(0.0, inplace=True) return ordination scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/_redundancy_analysis.py000066400000000000000000000243241520735541300275430ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np import pandas as pd from scipy.linalg import svd, lstsq from ._ordination_results import OrdinationResults from ._utils import corr, svd_rank, scale from skbio.table._tabular import _ingest_table, _create_table, _create_table_1d def rda( y, x, scale_Y=False, scaling=1, sample_ids=None, feature_ids=None, constraint_ids=None, output_format=None, ): r"""Compute redundancy analysis, a type of canonical analysis. It is related to PCA and multiple regression because the explained variables `y` are fitted to the explanatory variables `x` and PCA is then performed on the fitted values. A similar process is performed on the residuals. RDA should be chosen if the studied gradient is small, and CCA when it's large, so that the contingency table is sparse. Parameters ---------- y : table_like :math:`n \times p` response matrix, where :math:`n` is the number of samples and :math:`p` is the number of features. Its columns need be dimensionally homogeneous (or you can set `scale_Y=True`). This matrix is also referred to as the community matrix that commonly stores information about species abundances. See :ref:`supported formats `. x : table_like :math:`n \times m, n \geq m` matrix of explanatory variables, where :math:`n` is the number of samples and :math:`m` is the number of metadata variables. Its columns need not be standardized, but doing so turns regression coefficients into standard regression coefficients. See above. scale_Y : bool, optional Controls whether the response matrix columns are scaled to have unit standard deviation. Defaults to `False`. scaling : int Scaling type 1 produces a distance biplot. It focuses on the ordination of rows (samples) because their transformed distances approximate their original euclidean distances. Especially interesting when most explanatory variables are binary. Scaling type 2 produces a correlation biplot. It focuses on the relationships among explained variables (`y`). It is interpreted like scaling type 1, but taking into account that distances between objects don't approximate their euclidean distances. See more details about distance and correlation biplots in [1]_, \S 9.1.4. constraint_ids : list of str, optional List of identifiers for metadata variables or constraints (applicable in constrained ordination methods). If not provided implicitly by the input data structure or explicitly by the user, defaults to integers starting at zero. sample_ids, feature_ids, output_format : optional Standard table parameters. See :ref:`table_params` for details. Returns ------- OrdinationResults Object that stores the computed eigenvalues, the proportion explained by each of them (per unit), transformed coordinates for feature and samples, biplot scores, sample constraints, etc. Raises ------ ValueError If the data matrices have different numbers of rows. ValueError If explanatory variables have less rows than columns. See Also -------- ca cca OrdinationResults Notes ----- The algorithm is based on [1]_, \S 11.1, and is expected to give the same results as ``rda(y, x)`` in R's package vegan. The eigenvalues reported in vegan are re-normalized to :math:`\sqrt{\frac{s}{n-1}}` `n` is the number of samples, and `s` is the original eigenvalues. Here we will only return the original eigenvalues, as recommended in [1]_. References ---------- .. [1] Legendre P. and Legendre L. 1998. Numerical Ecology. Elsevier, Amsterdam. """ Y, y_rows, y_cols = _ingest_table(y) X, x_rows, x_cols = _ingest_table(x) n, p = Y.shape n_, m = X.shape if n != n_: raise ValueError("Both data matrices must have the same number of rows.") if n < m: # Mmm actually vegan is able to do this case, too raise ValueError("Explanatory variables cannot have less rows than columns.") sample_ids = y_rows feature_ids = y_cols # Centre response variables (they must be dimensionally # homogeneous) Y = scale(Y, with_std=scale_Y) # Centre explanatory variables X = scale(X, with_std=False) # Distribution of variables should be examined and transformed # if necessary (see paragraph 4 in p. 580 L&L 1998) # Compute Y_hat (fitted values by multivariate linear # regression, that is, linear least squares). Formula 11.6 in # L&L 1998 involves solving the normal equations, but that fails # when cond(X) ~ eps**(-0.5). A more expensive but much more # stable solution (fails when cond(X) ~ eps**-1) is computed # using the QR decomposition of X = QR: # (11.6) Y_hat = X [X' X]^{-1} X' Y # = QR [R'Q' QR]^{-1} R'Q' Y # = QR [R' R]^{-1} R'Q' Y # = QR R^{-1} R'^{-1} R' Q' Y # = Q Q' Y # and B (matrix of regression coefficients) # (11.4) B = [X' X]^{-1} X' Y # = R^{-1} R'^{-1} R' Q' Y # = R^{-1} Q' # Q, R = np.linalg.qr(X) # Y_hat = Q.dot(Q.T).dot(Y) # B = scipy.linalg.solve_triangular(R, Q.T.dot(Y)) # This works provided X has full rank. When not, you can still # fix it using R's pseudoinverse or partitioning R. To avoid any # issues, like the numerical instability when trying to # reproduce an example in L&L where X was rank-deficient, we'll # just use `np.linalg.lstsq`, which uses the SVD decomposition # under the hood and so it's also more expensive. B, _, rank_X, _ = lstsq(X, Y) Y_hat = X.dot(B) # Now let's perform PCA on the fitted values from the multiple # regression u, s, vt = svd(Y_hat, full_matrices=False) # vt are the right eigenvectors, which is what we need to # perform PCA. That is, we're changing points in Y_hat from the # canonical basis to the orthonormal basis given by the right # eigenvectors of Y_hat (or equivalently, the eigenvectors of # the covariance matrix Y_hat.T.dot(Y_hat)) # See 3) in p. 583 in L&L 1998 rank = svd_rank(Y_hat.shape, s) # Theoretically, there're at most min(p, m, n - 1) non-zero eigenvalues U = vt[:rank].T # U as in Fig. 11.2 # Ordination in the space of response variables. Its columns are # sample scores. (Eq. 11.12) F = Y.dot(U) # Ordination in the space of explanatory variables. Its columns # are fitted sample scores. (Eq. 11.13) Z = Y_hat.dot(U) # Canonical coefficients (formula 11.14) # C = B.dot(U) # Not used Y_res = Y - Y_hat # PCA on the residuals u_res, s_res, vt_res = svd(Y_res, full_matrices=False) # See 9) in p. 587 in L&L 1998 rank_res = svd_rank(Y_res.shape, s_res) # Theoretically, there're at most min(p, n - 1) non-zero eigenvalues as U_res = vt_res[:rank_res].T F_res = Y_res.dot(U_res) # Ordination in the space of residuals eigenvalues = np.r_[s[:rank], s_res[:rank_res]] # Compute scores if scaling not in {1, 2}: raise NotImplementedError("Only scalings 1, 2 available for RDA.") # According to the vegan-FAQ.pdf, the scaling factor for scores # is (notice that L&L 1998 says in p. 586 that such scaling # doesn't affect the interpretation of a biplot): eigvals = _create_table_1d( eigenvalues, index=["RDA%d" % (i + 1) for i in range(len(eigenvalues))], backend=output_format, ) const = np.sum(eigenvalues**2) ** 0.25 if scaling == 1: scaling_factor = const elif scaling == 2: scaling_factor = eigenvalues / const feature_scores = np.hstack((U, U_res)) * scaling_factor sample_scores = np.hstack((F, F_res)) / scaling_factor feature_scores = _create_table( feature_scores, index=feature_ids, columns=["RDA%d" % (i + 1) for i in range(feature_scores.shape[1])], backend=output_format, ) sample_scores = _create_table( sample_scores, index=sample_ids, columns=["RDA%d" % (i + 1) for i in range(sample_scores.shape[1])], backend=output_format, ) # TODO not yet used/displayed sample_constraints = np.hstack((Z, F_res)) / scaling_factor sample_constraints = _create_table( sample_constraints, index=sample_ids, columns=["RDA%d" % (i + 1) for i in range(sample_constraints.shape[1])], backend=output_format, ) # Vegan seems to compute them as corr(X[:, :rank_X], # u) but I don't think that's a good idea. In fact, if # you take the example shown in Figure 11.3 in L&L 1998 you # can see that there's an arrow for each of the 4 # environmental variables (depth, coral, sand, other) even if # other = not(coral or sand) biplot_scores = corr(X, u) biplot_scores = _create_table( biplot_scores, index=x_cols, columns=["RDA%d" % (i + 1) for i in range(biplot_scores.shape[1])], backend=output_format, ) # The "Correlations of environmental variables with sample # scores" from table 11.4 are quite similar to vegan's biplot # scores, but they're computed like this: # corr(X, F)) p_explained = _create_table_1d( eigenvalues / eigenvalues.sum(), index=["RDA%d" % (i + 1) for i in range(len(eigenvalues))], backend=output_format, ) return OrdinationResults( "RDA", "Redundancy Analysis", eigvals=eigvals, proportion_explained=p_explained, features=feature_scores, feature_ids=feature_ids, samples=sample_scores, sample_ids=sample_ids, biplot_scores=biplot_scores, sample_constraints=sample_constraints, constraint_ids=x_cols, ) scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/_utils.py000066400000000000000000000233611520735541300246440ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from ._cutils import center_distance_matrix_cy def mean_and_std(a, axis=None, weights=None, with_mean=True, with_std=True, ddof=0): """Compute the weighted average and standard deviation along the specified axis. Parameters ---------- a : array_like Calculate average and standard deviation of these values. axis : int, optional Axis along which the statistics are computed. The default is to compute them on the flattened array. weights : array_like, optional An array of weights associated with the values in `a`. Each value in `a` contributes to the average according to its associated weight. The weights array can either be 1-D (in which case its length must be the size of `a` along the given axis) or of the same shape as `a`. If `weights=None`, then all data in `a` are assumed to have a weight equal to one. with_mean : bool, optional, defaults to True Compute average if True. with_std : bool, optional, defaults to True Compute standard deviation if True. ddof : int, optional, defaults to 0 It means delta degrees of freedom. Variance is calculated by dividing by `n - ddof` (where `n` is the number of elements). By default it computes the maximum likelihood estimator. Returns ------- average, std Return the average and standard deviation along the specified axis. If any of them was not required, returns `None` instead """ if not (with_mean or with_std): raise ValueError("Either the mean or standard deviation need to be computed.") a = np.asarray(a) if weights is None: avg = a.mean(axis=axis) if with_mean else None std = a.std(axis=axis, ddof=ddof) if with_std else None else: avg = np.average(a, axis=axis, weights=weights) if with_std: if axis is None: variance = np.average((a - avg) ** 2, weights=weights) else: # Make sure that the subtraction to compute variance works for # multidimensional arrays a_rolled = np.rollaxis(a, axis) # Numpy doesn't have a weighted std implementation, but this is # stable and fast variance = np.average((a_rolled - avg) ** 2, axis=0, weights=weights) if ddof != 0: # Don't waste time if variance doesn't need scaling if axis is None: variance *= a.size / (a.size - ddof) else: variance *= a.shape[axis] / (a.shape[axis] - ddof) std = np.sqrt(variance) else: std = None avg = avg if with_mean else None return avg, std def scale(a, weights=None, with_mean=True, with_std=True, ddof=0, copy=True): """Scale array by columns to have weighted average 0 and standard deviation 1. Parameters ---------- a : array_like 2D array whose columns are standardized according to the weights. weights : array_like, optional Array of weights associated with the columns of `a`. By default, the scaling is unweighted. with_mean : bool, optional, defaults to True Center columns to have 0 weighted mean. with_std : bool, optional, defaults to True Scale columns to have unit weighted std. ddof : int, optional, defaults to 0 If with_std is True, variance is calculated by dividing by `n - ddof` (where `n` is the number of elements). By default it computes the maximum likelihood stimator. copy : bool, optional, defaults to True Whether to perform the standardization in place, or return a new copy of `a`. Returns ------- 2D ndarray Scaled array. Notes ----- Wherever std equals 0, it is replaced by 1 in order to avoid division by zero. """ a = np.asarray(a, dtype=np.float64) # Pandas 3.0+ returns read-only objects if copy or (not a.flags.writeable): a = a.copy() avg, std = mean_and_std( a, axis=0, weights=weights, with_mean=with_mean, with_std=with_std, ddof=ddof ) if with_mean: a -= avg if with_std: std[std == 0] = 1.0 a /= std return a def svd_rank(M_shape, S, tol=None): """Matrix rank of `M` given its singular values `S`. See `np.linalg.matrix_rank` for a rationale on the tolerance (we're not using that function because it doesn't let us reuse a precomputed SVD). """ if tol is None: tol = S.max() * max(M_shape) * np.finfo(S.dtype).eps return np.sum(S > tol) def corr(x, y=None): """Compute correlation between columns of `x`, or `x` and `y`. Correlation is covariance of (columnwise) standardized matrices, so each matrix is first centered and scaled to have variance one, and then their covariance is computed. Parameters ---------- x : 2D array_like Matrix of shape (n, p). Correlation between its columns will be computed. y : 2D array_like, optional Matrix of shape (n, q). If provided, the correlation is computed between the columns of `x` and the columns of `y`. Else, it's computed between the columns of `x`. Returns ------- correlation Matrix of computed correlations. Has shape (p, p) if `y` is not provided, else has shape (p, q). """ x = np.asarray(x) if y is not None: y = np.asarray(y) if y.shape[0] != x.shape[0]: raise ValueError("Both matrices must have the same number of rows") x, y = scale(x), scale(y) else: x = scale(x) y = x # Notice that scaling was performed with ddof=0 (dividing by n, # the default), so now we need to remove it by also using ddof=0 # (dividing by n) return x.T.dot(y) / x.shape[0] def e_matrix(distance_matrix): """Compute E matrix from a distance matrix. Squares and divides by -2 the input elementwise. Eq. 9.20 in Legendre & Legendre 1998. """ return distance_matrix * distance_matrix / -2 def f_matrix(E_matrix): """Compute F matrix from E matrix. Centring step: for each element, the mean of the corresponding row and column are subtracted, and the mean of the whole matrix is added. Eq. 9.21 in Legendre & Legendre 1998. """ row_means = E_matrix.mean(axis=1, keepdims=True) col_means = E_matrix.mean(axis=0, keepdims=True) matrix_mean = E_matrix.mean() return E_matrix - row_means - col_means + matrix_mean def center_distance_matrix(distance_matrix, inplace=False): """Centers a distance matrix. Note: If the used distance was euclidean, pairwise distances needn't be computed from the data table Y because F_matrix = Y.dot(Y.T) (if Y has been centered). But since we're expecting distance_matrix to be non-euclidian, we do the following computation as per Numerical Ecology (Legendre & Legendre 1998). Parameters ---------- distance_matrix : 2D array_like Distance matrix. inplace : bool, optional Whether or not to center the given distance matrix in-place, which is more efficient in terms of memory and computation. """ if not distance_matrix.flags.c_contiguous: # center_distance_matrix_cy requires c_contiguous, so make a copy distance_matrix = np.asarray(distance_matrix, order="C") if inplace: center_distance_matrix_cy(distance_matrix, distance_matrix) return distance_matrix else: centered = np.empty(distance_matrix.shape, distance_matrix.dtype) center_distance_matrix_cy(distance_matrix, centered) return centered def _e_matrix_inplace(distance_matrix): """Compute E matrix from a distance matrix inplace. Squares and divides by -2 the input element-wise. Eq. 9.20 in Legendre & Legendre 1998. Modified from :func:`skbio.stats.ordination.e_matrix` function, performing row-wise operations to avoid excessive memory allocations. Parameters ---------- distance_matrix : 2D array_like Distance matrix. """ distance_matrix = distance_matrix.astype(float) for i in np.arange(len(distance_matrix)): distance_matrix[i] = (distance_matrix[i] * distance_matrix[i]) / -2 return distance_matrix def _f_matrix_inplace(e_matrix): """Compute F matrix from E matrix inplace. Centering step: for each element, the mean of the corresponding row and column are subtracted, and the mean of the whole matrix is added. Eq. 9.21 in Legendre & Legendre 1998. Modified from :func:`skbio.stats.ordination.f_matrix` function, performing row-wise operations to avoid excessive memory allocations. Parameters ---------- e_matrix : 2D array_like A matrix representing the "E matrix" as described above. """ e_matrix = e_matrix.astype(float) row_means = np.zeros(len(e_matrix), dtype=float) col_means = np.zeros(len(e_matrix), dtype=float) matrix_mean = 0.0 for i in np.arange(len(e_matrix)): row_means[i] = e_matrix[i].mean() matrix_mean += e_matrix[i].sum() col_means += e_matrix[i] matrix_mean /= len(e_matrix) ** 2 col_means /= len(e_matrix) for i in np.arange(len(e_matrix)): v = e_matrix[i] v -= row_means[i] v -= col_means v += matrix_mean e_matrix[i] = v return e_matrix scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/000077500000000000000000000000001520735541300241305ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/__init__.py000066400000000000000000000005411520735541300262410ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/000077500000000000000000000000001520735541300250415ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/L&L_CA_data000066400000000000000000000000301520735541300266660ustar00rootroot0000000000000010 10 20 10 15 10 15 5 5scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/PCoA_biplot_descriptors000066400000000000000000000021751520735541300315450ustar00rootroot00000000000000Taxon PC.636 PC.635 PC.356 PC.481 PC.354 PC.593 PC.355 PC.607 PC.634 Root;k__Bacteria;Other 0.0202702702703 0.0469798657718 0.0266666666667 0.027397260274 0.0134228187919 0.0134228187919 0.0136054421769 0.0469798657718 0.02 Root;k__Bacteria;p__Actinobacteria 0.00675675675676 0.00671140939597 0.0 0.00684931506849 0.0 0.0 0.0 0.0201342281879 0.02 Root;k__Bacteria;p__Bacteroidetes 0.695945945946 0.523489932886 0.193333333333 0.143835616438 0.0738255033557 0.389261744966 0.285714285714 0.275167785235 0.653333333333 Root;k__Bacteria;p__Deferribacteres 0.0472972972973 0.0134228187919 0.0 0.0 0.0 0.0 0.0 0.0201342281879 0.0333333333333 Root;k__Bacteria;p__Firmicutes 0.209459459459 0.395973154362 0.773333333333 0.787671232877 0.89932885906 0.41610738255 0.700680272109 0.456375838926 0.22 Root;k__Bacteria;p__Proteobacteria 0.00675675675676 0.00671140939597 0.0 0.0 0.0 0.0335570469799 0.0 0.0201342281879 0.0133333333333 Root;k__Bacteria;p__TM7 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0133333333333 Root;k__Bacteria;p__ 0.0135135135135 0.00671140939597 0.00666666666667 0.0342465753425 0.0134228187919 0.147651006711 0.0 0.161073825503 0.0266666666667 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/PCoA_biplot_projected_descriptors000066400000000000000000000030511520735541300335760ustar00rootroot00000000000000"","Axis.1","Axis.2","Axis.3","Axis.4","Axis.5","Axis.6","Axis.7","Axis.8" "Root;k__Bacteria;Other",-0.0251703458354009,-0.0387419997798285,0.0370307944752097,-0.0182485866183309,-0.00129741030252842,0.000814106793625313,-0.0173701207829898,0.0361211055519348 "Root;k__Bacteria;p__Actinobacteria",-0.0243896442435075,-0.0173750855733946,0.00412122918478027,-0.00122921164491863,-0.0133154056835269,-0.0154481346200809,0.0110025326657988,-0.0193889181281414 "Root;k__Bacteria;p__Bacteroidetes",-0.715120229604841,0.317840715450945,-0.183247320427738,0.616597812375811,0.261720590975174,-0.0233954969961052,0.0235684811385711,0.108576064612194 "Root;k__Bacteria;p__Deferribacteres",-0.0581057801759818,0.0109676872979955,0.000973434160884227,0.0403394413149601,-0.0126657203131676,0.0312522995897358,0.00445295277091873,-0.0391828157435708 "Root;k__Bacteria;p__Firmicutes",0.826514889978526,0.0338669291769973,0.258683679610306,-0.820041925817023,-0.236331008329088,0.0820371240664409,-0.146993916645359,-0.114613637622136 "Root;k__Bacteria;p__Proteobacteria",-0.00665357958782869,-0.0351957821869525,-0.0269691957766513,0.0384070851104123,0.019915981256556,-0.0152225877254676,0.019285238587548,0.0101464789573946 "Root;k__Bacteria;p__TM7",-0.00936607225354557,0.00504668520861811,-0.00329562583232389,-0.00189853964818609,0.00398022745872819,-0.0160400884328152,0.0128760393792986,-0.0162949930598132 "Root;k__Bacteria;p__",0.0122907617222583,-0.276409149593715,-0.0872969953941216,0.146073924926225,-0.022007255063595,-0.0439972226754927,0.0931787928855206,0.0346367154320729 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/PCoA_sample_data000066400000000000000000000021131520735541300300750ustar00rootroot000000000000000 0.099 0.033 0.183 0.148 0.198 0.462 0.628 0.113 0.173 0.434 0.762 0.53 0.586 0.099 0 0.022 0.114 0.224 0.039 0.266 0.442 0.07 0.119 0.419 0.633 0.389 0.435 0.033 0.022 0 0.042 0.059 0.053 0.322 0.444 0.046 0.162 0.339 0.781 0.482 0.55 0.183 0.114 0.042 0 0.068 0.085 0.435 0.406 0.047 0.331 0.505 0.7 0.579 0.53 0.148 0.224 0.059 0.068 0 0.051 0.268 0.24 0.034 0.177 0.469 0.758 0.597 0.552 0.198 0.039 0.053 0.085 0.051 0 0.025 0.129 0.002 0.039 0.39 0.625 0.498 0.509 0.462 0.266 0.322 0.435 0.268 0.025 0 0.014 0.106 0.089 0.315 0.469 0.374 0.369 0.628 0.442 0.444 0.406 0.24 0.129 0.014 0 0.129 0.237 0.349 0.618 0.562 0.471 0.113 0.07 0.046 0.047 0.034 0.002 0.106 0.129 0 0.071 0.151 0.44 0.247 0.234 0.173 0.119 0.162 0.331 0.177 0.039 0.089 0.237 0.071 0 0.43 0.538 0.383 0.346 0.434 0.419 0.339 0.505 0.469 0.39 0.315 0.349 0.151 0.43 0 0.607 0.387 0.456 0.762 0.633 0.781 0.7 0.758 0.625 0.469 0.618 0.44 0.538 0.607 0 0.084 0.09 0.53 0.389 0.482 0.579 0.597 0.498 0.374 0.562 0.247 0.383 0.387 0.084 0 0.038 0.586 0.435 0.55 0.53 0.552 0.509 0.369 0.471 0.234 0.346 0.456 0.09 0.038 0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/PCoA_sample_data_12dim000066400000000000000000000051271520735541300311010ustar00rootroot00000000000000 1 2 3 4 5 6 7 8 9 10 11 12 1 0.0 0.909636950834479 0.9869428157422727 0.7190893636533138 0.6960053958431593 0.6477238596907942 0.30557161358653495 0.8946966124829346 0.12780699944110363 0.39915339691165386 0.7641239434153432 0.6248070796484706 2 0.909636950834479 0.0 0.3871354292850083 0.6881160960373599 0.5550593584027527 0.5855786600007656 0.4843215561734061 0.20448304199758327 0.4067028703340123 0.2754701840044086 0.6269219445617967 0.05629366991581264 3 0.9869428157422727 0.3871354292850083 0.0 0.6088130886750466 0.8611896463567201 0.2815827949525225 0.6500535832888426 0.8196046614443331 0.356410088497226 0.05164123821334954 0.7110953188954077 0.32855281988632934 4 0.7190893636533138 0.6881160960373599 0.6088130886750466 0.0 0.7453215102240474 0.9916540031629704 0.14394284428694282 0.8388378539413649 0.15115603934799038 0.13871462268568635 0.1934605692727246 0.9804118301943398 5 0.6960053958431593 0.5550593584027527 0.8611896463567201 0.7453215102240474 0.0 0.7996611932937304 0.30579824243478326 0.5227960305398314 0.8564730629853469 0.7786384040043949 0.06843106040159719 0.7715973816221341 6 0.6477238596907942 0.5855786600007656 0.2815827949525225 0.9916540031629704 0.7996611932937304 0.0 0.8869204659721949 0.1619378942802252 0.10200764546980268 0.17805335055828198 0.8796559972720953 0.20933243431218862 7 0.30557161358653495 0.4843215561734061 0.6500535832888426 0.14394284428694282 0.30579824243478326 0.8869204659721949 0.0 0.9489770186788868 0.9531210051205121 0.5834385348164726 0.31984891724102216 0.5852822100268925 8 0.8946966124829346 0.20448304199758327 0.8196046614443331 0.8388378539413649 0.5227960305398314 0.1619378942802252 0.9489770186788868 0.0 0.16681381452925792 0.9281238242741929 0.604480007052297 0.43978806925866687 9 0.12780699944110363 0.4067028703340123 0.356410088497226 0.15115603934799038 0.8564730629853469 0.10200764546980268 0.9531210051205121 0.16681381452925792 0.0 0.10766387594368387 0.9552101788877516 0.6135541732435132 10 0.39915339691165386 0.2754701840044086 0.05164123821334954 0.13871462268568635 0.7786384040043949 0.17805335055828198 0.5834385348164726 0.9281238242741929 0.10766387594368387 0.0 0.4157921207508062 0.31997143485314194 11 0.7641239434153432 0.6269219445617967 0.7110953188954077 0.1934605692727246 0.06843106040159719 0.8796559972720953 0.31984891724102216 0.604480007052297 0.9552101788877516 0.4157921207508062 0.0 0.11189976154475101 12 0.6248070796484706 0.05629366991581264 0.32855281988632934 0.9804118301943398 0.7715973816221341 0.20933243431218862 0.5852822100268925 0.43978806925866687 0.6135541732435132 0.31997143485314194 0.11189976154475101 0.0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/PCoA_sample_data_2000066400000000000000000000016041520735541300303220ustar00rootroot000000000000000.000000000000000000e+00 7.123610999999999693e-01 7.684919799999999634e-01 8.001856299999999811e-01 6.824852399999999930e-01 7.463462899999999678e-01 7.123610999999999693e-01 0.000000000000000000e+00 8.664569100000000246e-01 8.048528200000000243e-01 8.338130099999999656e-01 7.388172600000000312e-01 7.684919799999999634e-01 8.664569100000000246e-01 0.000000000000000000e+00 8.230839599999999479e-01 7.745174599999999909e-01 7.649887199999999554e-01 8.001856299999999811e-01 8.048528200000000243e-01 8.230839599999999479e-01 0.000000000000000000e+00 8.416736500000000509e-01 7.761436600000000130e-01 6.824852399999999930e-01 8.338130099999999656e-01 7.745174599999999909e-01 8.416736500000000509e-01 0.000000000000000000e+00 7.266116299999999528e-01 7.463462899999999678e-01 7.388172600000000312e-01 7.649887199999999554e-01 7.761436600000000130e-01 7.266116299999999528e-01 0.000000000000000000e+00 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/PCoA_sample_data_3000066400000000000000000000023141520735541300303220ustar00rootroot00000000000000 PC.636 PC.635 PC.356 PC.481 PC.354 PC.593 PC.355 PC.607 PC.634 PC.636 0.0 0.60737953696 0.748276547061 0.669767446745 0.747947798007 0.7377413135 0.70062016649 0.722772498498 0.581124366673 PC.635 0.60737953696 0.0 0.72197480583 0.655979250216 0.70672669146 0.745154628257 0.745509981365 0.659269044234 0.558850879936 PC.356 0.748276547061 0.72197480583 0.0 0.697796152694 0.610208881707 0.718770654329 0.615310834175 0.735768463546 0.788355481145 PC.481 0.669767446745 0.655979250216 0.697796152694 0.0 0.595087696488 0.657351659549 0.647258584304 0.686601452856 0.663208945591 PC.354 0.747947798007 0.70672669146 0.610208881707 0.595087696488 0.0 0.585097582096 0.599541095803 0.726258935536 0.781832289452 PC.593 0.7377413135 0.745154628257 0.718770654329 0.657351659549 0.585097582096 0.0 0.660981656067 0.713741192899 0.763317384716 PC.355 0.70062016649 0.745509981365 0.615310834175 0.647258584304 0.599541095803 0.660981656067 0.0 0.77062394744 0.753575681654 PC.607 0.722772498498 0.659269044234 0.735768463546 0.686601452856 0.726258935536 0.713741192899 0.77062394744 0.0 0.726387392797 PC.634 0.581124366673 0.558850879936 0.788355481145 0.663208945591 0.781832289452 0.763317384716 0.753575681654 0.726387392797 0.0scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/PCoA_sample_data_3_eigh_ref_3dim000066400000000000000000000014761520735541300330760ustar00rootroot00000000000000Eigvals 3 0.5123672604605051 0.30071909442702155 0.26791206600414047 Proportion explained 3 0.26757383277657976 0.15704469604990076 0.13991186377402365 Species 0 0 Site 9 3 PC.636 -0.2584654611828421 0.17399954688273872 -0.03828757925519412 PC.635 -0.27100113539100934 -0.018595131906339258 0.08648419263485663 PC.356 0.23507789817473093 0.09625192544887005 0.34579272671386985 PC.481 0.026140766432533755 -0.011145967653319655 -0.14766060301460787 PC.354 0.2850075522831216 -0.019254988848331687 -0.062326337538532166 PC.593 0.20463632624145514 -0.13936115093164073 -0.29151381962286704 PC.355 0.23348240321199026 0.22525797406849954 0.018862309626814944 PC.607 -0.09496319113225934 -0.4209748024953033 0.15486945486941445 PC.634 -0.35991515863772167 0.11382259543482587 -0.06622034441375392 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/PCoA_sample_data_3_fsvd_ref_3dim000066400000000000000000000014651520735541300331220ustar00rootroot00000000000000Eigvals 3 0.5123672604605054 0.3007190944270222 0.2679120660041405 Proportion explained 3 0.2675738327765797 0.15704469604990098 0.13991186377402356 Species 0 0 Site 9 3 PC.636 -0.2584654611828421 0.17399954688273822 -0.03828757925519378 PC.635 -0.2710011353910087 -0.018595131906339074 0.08648419263485721 PC.356 0.23507789817473107 0.0962519254488692 0.3457927267138707 PC.481 0.026140766432533644 -0.011145967653318808 -0.14766060301460796 PC.354 0.28500755228312136 -0.019254988848331694 -0.06232633753853236 PC.593 0.20463632624145525 -0.13936115093164014 -0.2915138196228672 PC.355 0.23348240321199093 0.22525797406849954 0.018862309626815132 PC.607 -0.09496319113225955 -0.4209748024953044 0.1548694548694131 PC.634 -0.35991515863772144 0.1138225954348267 -0.06622034441375402 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/PCoA_skbio000066400000000000000000000037101520735541300267360ustar00rootroot00000000000000Eigvals 9 0.5123672604605048 0.30071909442702155 0.2679120660041405 0.20898868107836532 0.19169895326008157 0.16054234528018121 0.1501769571197782 0.12245774816668883 0.0 Proportion explained 9 0.2675738327765797 0.1570446960499008 0.1399118637740237 0.109140272453788 0.10011104850250738 0.08384011619116792 0.07842699390110737 0.06395117635092507 0.0 Species 0 0 Site 9 9 PC.636 -0.25846546118284214 0.17399954688273864 -0.03828757925519388 0.1944775056196811 -0.08311760208440848 0.2624303332005185 -0.023163639223487725 0.018479403958060633 -0.0 PC.635 -0.27100113539100923 -0.01859513190633933 0.08648419263485602 -0.11806424531525102 0.19880835843691802 -0.021172359953453967 -0.19102402756537798 -0.1556465923768283 -0.0 PC.356 0.2350778981747308 0.0962519254488697 0.3457927267138699 0.003208625776186833 0.09637776755188007 0.04570253869527276 0.1854728132858981 -0.04040939717932225 -0.0 PC.481 0.026140766432533637 -0.011145967653319279 -0.14766060301460832 -0.29087660852960373 -0.20394547280060757 0.06197123847575147 0.10164132870879576 -0.1056909987185146 -0.0 PC.354 0.2850075522831214 -0.019254988848331458 -0.062326337538532166 -0.13812679985198154 0.10479860242276298 0.09517207306283292 -0.12963609754202599 0.22068717037162142 -0.0 PC.593 0.20463632624145503 -0.13936115093164061 -0.2915138196228669 0.18156678682059035 0.1595801327151684 -0.024641213016179383 0.08662524044412884 -0.09962214768709698 -0.0 PC.355 0.23348240321199026 0.22525797406849948 0.018862309626814986 0.10772998183109622 -0.1771089995718839 -0.19290583515124646 -0.14981947140833857 -0.03835490374645002 -0.0 PC.607 -0.09496319113225948 -0.42097480249530345 0.1548694548694144 0.08984275092805967 -0.15261819448811528 -0.0334232691500879 -0.02512247773026579 0.05089885364091516 -0.0 PC.634 -0.35991515863772167 0.11382259543482588 -0.06622034441375366 -0.029757997278778266 0.05722540781828547 -0.1931335061634077 0.14502633103067314 0.14965861173761527 -0.0 Biplot 0 0 Site constraints 0 0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/cf/000077500000000000000000000000001520735541300254315ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/cf/README.md000066400000000000000000000022251520735541300267110ustar00rootroot00000000000000# Cystic Fibrosis Dataset This dataset contains paired microbiome and metabolome data derived from lung mucus samples of patients with cystic fibrosis (CF). Adapted from: - https://github.com/biocore/mmvec/tree/master/examples/cf The dataset was used as a demonstration in the MMvec paper: - Morton, J. T., Aksenov, A. A., Nothias, L. F., Foulds, J. R., Quinn, R. A., Badri, M. H., ... & Knight, R. (2019). Learning representations of microbe–metabolite interactions. Nature Methods, 16(12), 1306-1314. The original dataset was published in: - Quinn, R. A., Comstock, W., Zhang, T., Morton, J. T., da Silva, R., Tran, A., ... & Dorrestein, P. C. (2018). Niche partitioning of a pathogenic microbiome driven by chemical gradients. Science Advances, 4(9), eaau1908. This dataset contains 172 samples, 2720 microbes (16S rRNA V4 ASVs), and 462 metabolites (LC-MS/MS) The MMvec analysis revealed a strong association between _Pseudomonas aeruginosa_, a major pathogen responsible for lung infections in CF, and rhamnolipids, which are key virulence factors produced by this organism. *** Note: The actual data files are not kept in the codebase due to their sizes. scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/cf/metabolite_meta.tsv.sha256000066400000000000000000000001261520735541300323300ustar00rootroot000000000000006b442d52cac6723e50531248c03016677fcc70a5a2c282857f546725879dae28 metabolite_meta.tsv scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/cf/metabolites.tsv.sha256000066400000000000000000000001221520735541300315010ustar00rootroot0000000000000046bdbc714953c37f72992b91b07ef1051bcf829e0c333ee9cab75b5ce8248863 metabolites.tsv scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/cf/microbe_meta.tsv.sha256000066400000000000000000000001231520735541300316200ustar00rootroot000000000000000030cdd28f7689b49bc218237ac483002d6d93335a92aa19281604eb6b68dc57 microbe_meta.tsv scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/cf/microbes.tsv.sha256000066400000000000000000000001171520735541300310000ustar00rootroot000000000000007e4ba6663fa0680fbd46394b5ed7a0c2206994fcad5afd58c79bfec7c1a743e5 microbes.tsv scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example2_X000066400000000000000000000017501520735541300267730ustar00rootroot000000000000001.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 2.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 3.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 4.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 5.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 6.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 7.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 8.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 9.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+01 0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example2_Y000066400000000000000000000002001520735541300267610ustar00rootroot000000000000001 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 11 4 0 0 8 1 11 5 17 7 0 0 9 6 0 0 6 2 9 7 13 10 0 0 7 8 0 0 4 3 7 9 10 13 0 0 5 10 0 0 2 4 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example2_biplot_scaling1000066400000000000000000000004221520735541300316310ustar00rootroot000000000000000.422650 -0.559143 -0.713251 1.165734e-16 1.471046e-16 1.831868e-16 0.988496 0.150787 -0.011785 6.106227e-17 6.661338e-17 8.326673e-17 -0.556517 0.817600 0.147714 -4.996004e-17 4.440892e-17 -7.216450e-17 -0.404080 -0.905843 -0.127150 2.775558e-18 -2.220446e-17 0.000000e+00 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example2_biplot_scaling2000066400000000000000000000004231520735541300316330ustar00rootroot00000000000000 0.422650 -0.559143 -0.713251 1.165734e-16 1.471046e-16 1.831868e-16 0.988496 0.150787 -0.011785 6.106227e-17 6.661338e-17 8.326673e-17 -0.556517 0.817600 0.147714 -4.996004e-17 4.440892e-17 -7.216450e-17 -0.404080 -0.905843 -0.127150 2.775558e-18 -2.220446e-17 0.000000e+00scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example2_sample_constraints_scaling1000066400000000000000000000015021520735541300342500ustar00rootroot00000000000000-1.203552 0.973291 0.398346 -4.377164e-02 -2.025459e-01 -4.174845e-02 2.251712e-03 -1.233129 1.048075 0.112959 1.946350e-16 -3.553872e-16 8.349689e-02 -1.554395e-16 -1.262706 1.122859 -0.172429 4.377164e-02 2.025459e-01 -4.174845e-02 -2.251712e-03 -0.629153 -1.155379 0.778203 -3.794874e-01 5.000171e-02 3.937851e-16 2.503876e-04 2.249463 0.043725 0.561763 6.747053e-01 2.580938e-02 6.726139e-16 1.835041e-02 -0.688307 -1.005810 0.207427 -1.264958e-01 1.666724e-02 -6.333665e-17 8.346252e-05 2.190309 0.193293 -0.009012 -4.068089e-02 -1.574523e-02 -6.651371e-18 -3.978716e-02 -0.747462 -0.856242 -0.363348 1.264958e-01 -1.666724e-02 -4.098446e-16 -8.346252e-05 2.131154 0.342861 -0.579787 -6.340244e-01 -1.006415e-02 -4.849801e-16 2.143675e-02 -0.806617 -0.706674 -0.934123 3.794874e-01 -5.000171e-02 -7.280846e-16 -2.503876e-04 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example2_sample_constraints_scaling2000066400000000000000000000014751520735541300342620ustar00rootroot00000000000000-1.481311 2.070632 1.420611 -2.272346e-01 -3.841304e+00 -2.304877e+00 2.600617e-01 -1.517714 2.229732 0.402842 1.010421e-15 -6.739956e-15 4.609755e+00 -1.795250e-14 -1.554117 2.388832 -0.614928 2.272346e-01 3.841304e+00 -2.304877e+00 -2.600617e-01 -0.774350 -2.458015 2.775281 -1.970058e+00 9.482876e-01 2.174036e-14 2.891853e-02 2.768601 0.093023 2.003399 3.502642e+00 4.894777e-01 3.713413e-14 2.119383e+00 -0.847157 -2.139816 0.739742 -6.566859e-01 3.160959e-01 -3.496734e-15 9.639511e-03 2.695794 0.411223 -0.032139 -2.111894e-01 -2.986100e-01 -3.672135e-16 -4.595222e+00 -0.919963 -1.821616 -1.295796 6.566859e-01 -3.160959e-01 -2.262699e-14 -9.639511e-03 2.622988 0.729422 -2.067677 -3.291452e+00 -1.908677e-01 -2.677512e-14 2.475840e+00 -0.992770 -1.503417 -3.331334 1.970058e+00 -9.482876e-01 -4.019660e-14 -2.891853e-02 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example2_site_scaling1_from_vegan000066400000000000000000000014231520735541300335110ustar00rootroot00000000000000-1.209385 0.9996717 0.2040803 -0.04377164 -0.2025459 -0.04174845 0.002251712 -1.262748 1.114136 0.1333392 -5.659699e-17 2.478790e-16 0.0834969 -1.146481e-16 -1.227255 1.030418 0.001456920 0.04377164 0.2025459 -0.04174845 -0.002251712 -0.7091313 -1.234889 0.7539303 -0.3794874 0.05000171 6.953961e-17 0.0002503876 2.414956 0.1515006 0.7018385 0.6747053 0.02580938 2.771828e-16 0.01835041 -0.7149669 -1.032314 0.1993367 -0.1264958 0.01666724 5.423912e-17 8.346252e-05 2.146560 0.1833668 -0.02417943 -0.04068089 -0.01574523 -3.100586e-16 -0.03978716 -0.7208024 -0.8297385 -0.3552569 0.1264958 -0.01666724 7.539371e-18 -8.346252e-05 2.009409 0.2450122 -0.7046952 -0.6340244 -0.01006415 2.966077e-16 0.02143675 -0.726638 -0.6271632 -0.9098504 0.3794874 -0.05000171 9.260122e-17 -0.0002503876 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example2_site_scaling2_from_vegan000066400000000000000000000013461520735541300335160ustar00rootroot00000000000000-1.488490 2.126756 0.7278053 -0.2272346 -3.841304 -2.304877 0.2600617 -1.554168 2.370273 0.4755236 -2.938157e-16 4.701051e-15 4.609755 -1.324129e-14 -1.510485 2.192167 0.005195769 0.2272346 3.841304 -2.304877 -0.2600617 -0.8727866 -2.627171 2.688719 -1.970058 0.9482876 3.839191e-15 0.02891853 2.972287 0.3223107 2.502946 3.502642 0.4894777 1.53029e-14 2.119383 -0.8799689 -2.196201 0.7108885 -0.6566859 0.3160959 2.994471e-15 0.009639511 2.641949 0.3901046 -0.08623036 -0.2111894 -0.2986100 -1.711793e-14 -4.595222 -0.8871512 -1.765231 -1.266942 0.6566859 -0.3160959 4.162388e-16 -0.009639511 2.473146 0.5212524 -2.513133 -3.291452 -0.1908677 1.637533e-14 2.475840 -0.8943335 -1.334261 -3.244772 1.970058 -0.9482876 5.112392e-15 -0.02891853 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example2_species_scaling1_from_vegan000066400000000000000000000006501520735541300342010ustar00rootroot000000000000001.700926 -3.648509 2.254854 0.03700915 2.285531 -3.992165 -0.9423084 1.131309 -2.668483 -4.203715 -0.03700915 -2.285531 -3.992165 0.9423084 4.183397 0.9492028 1.450372 3.89008 1.505626 2.78929e-14 3.804618 3.105920 0.9508293 -1.474339 -3.319613 -1.214393 3.792181e-14 3.87476 -0.6542268 -2.856405 1.655304 -2.139057 3.761467 -1.190933e-14 0.6985568 -0.3552263 -1.215823 -1.449786 1.069529 -1.880733 -6.738172e-15 -0.3492784 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example2_species_scaling2_from_vegan000066400000000000000000000007131520735541300342020ustar00rootroot000000000000001.381987 -1.714964 0.6322725 0.007128982 0.1205124 -0.07231043 -0.00815886 0.9191784 -1.254308 -1.178743 -0.007128982 -0.1205124 -0.07231043 0.00815886 3.398972 0.4461683 0.4066916 0.7493367 0.07938928 5.052266e-16 0.03294182 2.523533 0.4469328 -0.4134120 -0.639449 -0.064033 6.868811e-16 0.03354913 -0.5315534 -1.342640 0.4641556 -0.4120414 0.1983362 -2.157147e-16 0.006048367 -0.2886182 -0.5714919 -0.4065273 0.2060207 -0.0991681 -1.220491e-16 -0.003024184 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example3_X000066400000000000000000000017501520735541300267740ustar00rootroot000000000000001.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 2.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 3.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 4.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 5.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 6.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 7.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 8.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 9.000000000000000000e+00 1.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+01 0.000000000000000000e+00 0.000000000000000000e+00 1.000000000000000000e+00 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example3_Y000066400000000000000000000003041520735541300267670ustar00rootroot000000000000001 0 0 0 0 0 2 4 4 0 0 0 0 0 0 5 6 1 0 1 0 0 0 0 0 2 3 11 4 0 0 8 1 6 2 0 11 5 17 7 0 0 6 6 2 9 6 0 0 6 2 10 1 4 9 7 13 10 0 0 4 5 4 7 8 0 0 4 3 6 6 4 7 9 10 13 0 0 6 2 0 5 10 0 0 2 4 0 1 3 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example3_biplot_scaling1000066400000000000000000000001261520735541300316330ustar00rootroot00000000000000-0.169747 0.630691 0.760769 -0.994017 0.060953 -0.044937 0.184353 -0.974868 0.030987 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example3_biplot_scaling2000066400000000000000000000001261520735541300316340ustar00rootroot00000000000000-0.169747 0.630691 0.760769 -0.994017 0.060953 -0.044937 0.184353 -0.974868 0.030987 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example3_sample_constraints_scaling1000066400000000000000000000015401520735541300342530ustar00rootroot00000000000000 0.418807 -1.331731 -0.092311 -0.357222 -0.201114 -0.077319 0.024296 -0.127088 0.023765 0.402119 -1.323781 0.064653 0.774418 0.400533 0.124249 0.046928 0.031790 -0.027526 0.385431 -1.315831 0.221617 -0.893930 -0.432358 -0.106748 -0.138400 0.169415 0.011485 0.670971 0.216324 -0.436938 0.191154 -0.206474 0.219195 -0.110093 0.000480 -0.000760 -0.586949 0.028310 -0.314662 -0.175743 0.184258 0.048211 0.057137 0.011500 0.017735 0.637595 0.232225 -0.123010 0.082373 -0.107580 -0.221430 0.169356 0.010714 -0.009033 -0.620325 0.044211 -0.000734 -0.120892 -0.020910 -0.060213 -0.067075 -0.013264 -0.035699 0.604219 0.248126 0.190919 -0.001622 0.236689 -0.162758 -0.145629 -0.005405 0.015899 -0.653701 0.060112 0.313195 0.335670 -0.188566 0.011227 0.008564 0.001462 0.019120 0.570843 0.264027 0.504847 -0.367420 0.068042 0.303396 0.104854 -0.008683 -0.009463 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example3_sample_constraints_scaling2000066400000000000000000000015431520735541300342570ustar00rootroot00000000000000 0.692139 -3.080537 -0.328747 -1.245288 -1.072935 -0.506242 0.244127 -3.631648 1.163119 0.664560 -3.062146 0.230249 2.699651 2.136829 0.813520 0.471530 0.908423 -1.347244 0.636980 -3.043755 0.789246 -3.116275 -2.306609 -0.698930 -1.390626 4.841176 0.562103 1.108876 0.500397 -1.556068 0.666370 -1.101532 1.435176 -1.106200 0.013703 -0.037180 -0.970016 0.065487 -1.120607 -0.612647 0.983007 0.315662 0.574110 0.328630 0.868028 1.053717 0.537179 -0.438075 0.287157 -0.573935 -1.449806 1.701670 0.306164 -0.442116 -1.025175 0.102269 -0.002614 -0.421433 -0.111552 -0.394242 -0.673964 -0.379019 -1.747250 0.998559 0.573961 0.679918 -0.005653 1.262724 -1.065657 -1.463266 -0.154459 0.778140 -1.080333 0.139050 1.115379 1.170159 -1.005992 0.073507 0.086046 0.041765 0.935820 0.943400 0.610742 1.797911 -1.280840 0.363003 1.986480 1.053561 -0.248131 -0.463165 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example3_site_scaling1_from_vegan000066400000000000000000000017301520735541300335130ustar00rootroot000000000000000.4299704 -1.332221 0.06167733 -0.3572215 -0.2011142 -0.07731854 0.02429630 -0.1270878 0.02376451 0.3538402 -1.299809 -0.2660402 0.7744182 0.4005334 0.1242493 0.04692828 0.03178983 -0.02752649 0.4615241 -1.362879 0.6006922 -0.8939302 -0.4323576 -0.1067479 -0.1383998 0.1694146 0.01148472 0.6730478 0.4632174 -0.5265713 0.191154 -0.2064744 0.2191950 -0.1100927 0.0004795276 -0.000759659 -0.5924553 -0.02607423 -0.1955122 -0.1757430 0.1842576 0.04821126 0.05713738 0.01150025 0.01773529 0.631247 0.1986126 -0.1796544 0.08237334 -0.1075801 -0.2214295 0.1693559 0.01071407 -0.009033185 -0.5775539 -0.03661717 0.03720809 -0.1208918 -0.02090970 -0.06021282 -0.06707516 -0.01326357 -0.03569931 0.5731844 -0.04684914 0.1477290 -0.001621561 0.2366887 -0.1627582 -0.1456291 -0.005405227 0.01589872 -0.6946946 0.2120237 0.1343200 0.3356701 -0.1885661 0.01122678 0.008563613 0.001461538 0.01912039 0.6250085 0.4474569 0.7713248 -0.3674199 0.06804227 0.3033959 0.1048540 -0.008683241 -0.009463257 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example3_site_scaling2_from_vegan000066400000000000000000000016131520735541300335140ustar00rootroot000000000000000.7105873 -3.081668 0.2196514 -1.245288 -1.072935 -0.5062419 0.2441267 -3.631648 1.163119 0.5847714 -3.006693 -0.9474487 2.699651 2.136829 0.81352 0.4715303 0.908423 -1.347244 0.7627343 -3.152586 2.139244 -3.116275 -2.306609 -0.6989299 -1.390626 4.841176 0.562103 1.112307 1.071506 -1.875277 0.6663702 -1.101532 1.435176 -1.106200 0.01370293 -0.03718039 -0.9791168 -0.06031443 -0.6962774 -0.6126467 0.9830066 0.3156624 0.5741102 0.3286300 0.8680277 1.043226 0.459427 -0.6398028 0.2871566 -0.5739354 -1.449806 1.70167 0.3061643 -0.442116 -0.9544901 -0.08470217 0.1325091 -0.4214334 -0.1115523 -0.3942425 -0.673964 -0.3790186 -1.747250 0.9472688 -0.1083706 0.5261072 -0.005652824 1.262724 -1.065657 -1.463266 -0.1544592 0.7781397 -1.148082 0.4904493 0.4783537 1.170159 -1.005992 0.07350714 0.08604627 0.04176476 0.9358196 1.032916 1.035049 2.746918 -1.280840 0.3630026 1.986480 1.053561 -0.2481314 -0.4631652 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example3_species_scaling1_from_vegan000066400000000000000000000014641520735541300342060ustar00rootroot000000000000000.1823706 0.6532424 -0.7230468 -0.006709309 -0.4387088 0.5613251 -0.1226234 -1.215044 0.2284292 0.2336159 0.7020405 1.408284 -0.4924596 -0.1434352 0.937947 0.4323209 1.361292 -0.1116756 -1.678295 0.2216763 -0.7060727 -0.3653404 0.6936791 0.1597882 0.4669268 0.7694895 1.713529 -1.712479 0.2535825 0.7869925 0.7796179 -1.300374 -0.1696223 -0.5366468 -0.9018874 1.255149 1.741418 1.242592 -1.560116 0.7790618 -1.728251 0.8161103 -1.198472 1.189485 -1.869424 1.650260 1.327675 2.421391 -1.359427 1.595568 2.150528 2.131749 -2.371434 -2.151822 0.4218299 -0.4121355 -0.7269577 1.510841 0.3772344 -1.23206 1.275166 0.1284123 -0.5996156 0.2422044 -1.983235 -0.05430946 0.1839251 1.891113 -0.2729081 -1.999644 -0.06107332 -0.3832015 0.6837066 -1.637614 0.7681627 -2.406462 -0.7918731 -2.188509 -0.06317185 -0.1040515 -0.6006456 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/example3_species_scaling2_from_vegan000066400000000000000000000015611520735541300342050ustar00rootroot000000000000000.1103509 0.2824 -0.2030290 -0.001924623 -0.08223286 0.08573143 -0.01220389 -0.04251988 0.004667199 0.1413590 0.3034956 0.3954412 -0.1412663 -0.02688592 0.1432531 0.04302603 0.04763777 -0.002281724 -1.015522 0.09583179 -0.1982627 -0.1048010 0.1300252 0.02440453 0.04647012 0.02692792 0.03501032 -1.036207 0.1096250 0.2209847 0.2236401 -0.2437459 -0.02590649 -0.05340889 -0.03156112 0.02564484 1.053717 0.5371787 -0.4380751 0.2234806 -0.3239485 0.1246449 -0.1192759 0.04162547 -0.03819552 0.9985587 0.5739606 0.6799181 -0.3899634 0.2990779 0.328451 0.2121588 -0.08298719 -0.0439654 0.2552457 -0.1781683 -0.2041272 0.4333976 0.07070992 -0.1881731 0.1269088 0.004493729 -0.01225117 0.1465559 -0.8573625 -0.01524991 0.0527605 0.3544758 -0.04168137 -0.1990112 -0.002137232 -0.007829461 0.4137051 -0.707949 0.2156974 -0.6903142 -0.148431 -0.3342519 -0.006287074 -0.003641234 -0.01227222 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/exp_PCoAEigenResults_site000066400000000000000000000040161520735541300320010ustar00rootroot00000000000000-2.584654599999999802e-01 1.739995500000000028e-01 3.828758000000000161e-02 -1.944775099999999923e-01 8.311759999999999982e-02 2.624303299999999894e-01 -2.316363999999999923e-02 -1.847939999999999999e-02 0.000000000000000000e+00 -2.710011399999999737e-01 -1.859513000000000138e-02 -8.648419000000000245e-02 1.180642499999999956e-01 -1.988083599999999895e-01 -2.117236000000000118e-02 -1.910240300000000113e-01 1.556465900000000013e-01 0.000000000000000000e+00 2.350779000000000063e-01 9.625192999999999943e-02 -3.457927299999999926e-01 -3.208630000000000076e-03 -9.637777000000000149e-02 4.570253999999999983e-02 1.854728099999999880e-01 4.040939999999999810e-02 0.000000000000000000e+00 2.614077000000000067e-02 -1.114596999999999984e-02 1.476606000000000030e-01 2.908766099999999799e-01 2.039454699999999898e-01 6.197123999999999688e-02 1.016413300000000020e-01 1.056909999999999933e-01 0.000000000000000000e+00 2.850075499999999984e-01 -1.925498999999999961e-02 6.232634000000000091e-02 1.381267999999999940e-01 -1.047986000000000056e-01 9.517206999999999750e-02 -1.296361000000000041e-01 -2.206871699999999881e-01 0.000000000000000000e+00 2.046363300000000052e-01 -1.393611499999999892e-01 2.915138199999999791e-01 -1.815667900000000057e-01 -1.595801299999999867e-01 -2.464121000000000020e-02 8.662524000000000612e-02 9.962215000000000653e-02 0.000000000000000000e+00 2.334824000000000066e-01 2.252579700000000018e-01 -1.886231000000000019e-02 -1.077299800000000030e-01 1.771089999999999887e-01 -1.929058399999999951e-01 -1.498194700000000101e-01 3.835489999999999733e-02 0.000000000000000000e+00 -9.496319000000000288e-02 -4.209747999999999823e-01 -1.548694499999999918e-01 -8.984274999999999900e-02 1.526181899999999869e-01 -3.342326999999999798e-02 -2.512247999999999912e-02 -5.089885000000000242e-02 0.000000000000000000e+00 -3.599151600000000117e-01 1.138225999999999960e-01 6.622034000000000253e-02 2.975799999999999973e-02 -5.722540999999999739e-02 -1.931335100000000082e-01 1.450263300000000088e-01 -1.496586099999999975e-01 0.000000000000000000e+00 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/exp_PCoAzeros_site000066400000000000000000000114441520735541300305350ustar00rootroot000000000000002.407881329999999875e-01 2.336771619999999938e-01 2.142755920000000147e-02 2.933648560000000002e-02 2.323964740000000057e-02 7.204402660000000513e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.136560330000000035e-01 1.167860260000000011e-01 4.047749600000000170e-02 4.171719389999999777e-02 5.458618300000000340e-02 5.687754019999999994e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 2.393598090000000067e-01 7.600313170000000396e-02 8.108063910000000429e-02 2.004822419999999911e-02 4.581686060000000373e-03 6.111682289999999934e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 2.129341230000000029e-01 6.047901669999999896e-02 1.108399510000000060e-01 1.568068159999999878e-01 4.018964929999999797e-02 1.244166470000000052e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 2.494895480000000054e-01 6.933176589999999473e-02 6.654290229999999806e-02 1.767019729999999914e-02 6.618815479999999585e-02 1.519420850000000045e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.487285489999999877e-01 7.783569120000000119e-02 5.321890979999999854e-02 3.189647279999999890e-02 8.112682020000000493e-02 2.872780789999999917e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 5.139397400000000199e-02 1.623059860000000132e-01 2.992259149999999986e-03 1.115089660000000010e-01 3.296634109999999757e-02 2.308574460000000091e-04 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 1.153621120000000028e-02 3.446314899999999848e-01 1.169549180000000084e-02 3.466400010000000170e-02 1.169378239999999992e-02 1.366916789999999930e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 3.932616380000000106e-03 5.908732849999999946e-03 2.629546940000000027e-02 7.368117420000000473e-02 1.939265150000000007e-02 2.257115020000000083e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 3.856929369999999996e-02 8.874156730000000784e-03 8.037018469999999970e-02 1.252655340000000117e-01 6.270869140000000230e-02 9.891935890000000051e-03 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 4.211582109999999907e-02 5.655546539999999761e-02 3.122599229999999948e-01 4.320305709999999744e-02 3.457770230000000149e-03 2.089115019999999989e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 5.158303490000000213e-01 2.909775239999999943e-02 9.484347120000000131e-02 2.340326009999999998e-02 3.819325810000000210e-02 4.608673130000000284e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 3.180272690000000013e-01 1.500964499999999924e-01 6.675638650000000063e-02 3.818534149999999738e-02 1.598195930000000098e-02 3.005567279999999883e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 3.237616709999999731e-01 4.748628319999999986e-02 5.282383000000000217e-02 4.852971259999999676e-02 7.869736770000000659e-02 4.101528460000000015e-02 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/soils/000077500000000000000000000000001520735541300261725ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/soils/README.md000066400000000000000000000022271520735541300274540ustar00rootroot00000000000000# Desert Soil Biocrust Wetting Dataset This dataset contains paired microbiome and metabolome data derived from biocrust samples after a laboratory wetting event. Adapted from: - https://github.com/biocore/mmvec/tree/master/examples/soils The dataset was used as a demonstration in the MMvec paper: - Morton, J. T., Aksenov, A. A., Nothias, L. F., Foulds, J. R., Quinn, R. A., Badri, M. H., ... & Knight, R. (2019). Learning representations of microbe–metabolite interactions. Nature Methods, 16(12), 1306-1314. The original dataset was published in: - Swenson, T. L., Karaoz, U., Swenson, J. M., Bowen, B. P., & Northen, T. R. (2018). Linking soil biology and chemistry in biological soil crust using isolate exometabolomics. Nature Communications, 9(1), 19. The dataset contains 19 samples: - 4 time points: 3 min (immediately after wetting), 9 hours, 18 hours, 42 hours, and 49.5 hours. - 4 biocrust successional stages: early, early-mid, late-mid, and late. The dataset contains two omics layers: - Microbes (n=466), generated using ribosomal protein L15 (rplO) genotyping. - Metabolites (n=85), generated using liquid chromatography-mass spectrometry (LC/MS). scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/soils/metabolites.tsv000066400000000000000000000341251520735541300312450ustar00rootroot00000000000000 42hr_latemid 9hr_latemid 3min_late 9hr_earlymid 18hr_early 42hr_earlymid 49p5hr_early 9hr_early 18hr_latemid 18hr_late 42hr_late 49p5hr_latemid 18hr_earlymid 49p5hr_earlymid 3min_early 42hr_early 49p5hr_late 3min_latemid 3min_earlymid (2,3-dihydroxy-3-methylbutanoate) 737409 106211 293 98720 18559 57261 57205 68 416443 434578 540666 376365 70304 167448 1 9310 821189 137 460 (2,5-diaminohexanoate) 6139353 1858817 4039221 1757143 2818005 2649203 5842490 1217995 3649969 4246048 6305377 6938167 2765782 3627547 2782242 3086052 12080544 2531813 1883228 (3-hydroxypyridine) 11794395 7913218 4395256 6778304 8118056 23994691 17578552 5701840 8778404 6567773 81892669 31031506 17206076 13553115 2764132 5199015 59605488 3817224 3014543 (3-methyladenine) 25456433 74817388 14376340 54461337 31575138 23158721 4164767 36544924 35652469 44634519 33010090 16850683 59127978 36506855 3151923 9924625 9417872 10516080 4224009 (4-oxoproline) 15256443 395621642 335056264 287291443 31982087 12458802 4504692 144491739 36425721 70138710 18842555 8708761 163220696 13284054 145094920 7295747 9333631 261704693 150345346 (5,6-dihydrothymine) 15669063 37060000 22825471 22711707 13566340 8567759 4497692 11836450 27575224 16898679 26592268 32835804 31458363 10543409 10668504 9029176 9932010 37658588 9343810 (alanyl-leucine) 6258151 97609236 32410061 79808008 7395746 5357354 5940200 45004310 10018532 11965228 20789234 8726617 37733556 15113537 8863774 5980736 14130386 24760371 10341774 (dehydroalanine) 577650 7109939 18298870 8193841 730914 581461 397799 2712926 495780 576641 788643 631683 6587122 806953 9415865 306593 980376 9830850 9637489 (glycero-3-phosphoethanolamine) 628261 2073130 1154312 3242565 7026060 645602 3564947 3399507 989588 1372290 375167 2064355 4990136 6111718 833840 1002609 1317931 739865 764415 (indoleacrylate) 817105 132124874 38240052 83266097 2332408 198811 282478 28984593 28123772 24191297 913139 269400 38179521 3176995 7863318 132691 439062 27996851 9504608 (leucyl-leucine) 2647016 218872552 75228906 191332692 7972129 2751590 5325812 113891101 15635617 20594535 24658886 7029230 100420639 33802151 19748375 736288 10391784 61208638 26736608 (lipoate) 94367 205238 9470 403263 73089 37369 12814 40641 572487 753258 108435 68589 414555 30202 3486 14785 99836 91649 32281 (N6-acetyl-lysine) 1197165952 1844444160 1028776432 1466164813 242598172 663145994 133906340 510852150 961183257 920299200 1795786138 688954249 2032003008 1591878091 405487712 588510912 2476219085 540606152 505415832 (queuine) 2748984 4408161 9235185 5296515 5629947 4361372 6272654 6919534 2744760 3674797 2326836 3403967 4569287 4294627 10691936 5659594 3030533 9129995 11260668 2-aminobutanoate 291148 308073 176840 191926 221783 148471 82952 124447 307561 454781 490045 313301 268899 119817 51210 112709 258516 102263 92254 2-oxoglutarate 3913232 15394846 705553 10823315 7299423 2520273 59114 1761341 7476113 3288865 970613 174181 4147330 1274978 81265 267252 166422 1091990 224126 2'-deoxyguanosine 98892 702910 246917 313829 185513 186573 49135 153822 398434 279264 290135 148749 306095 148642 23852 47843 156568 275762 138376 2'-deoxyuridine 54786 11778486 2839069 240960 327 3849 2877 31312 240899 423220 30238 34258 8026180 25703 102968 18239 43236 1642790 997470 3',5'-cyclic-AMP 5496461 9942466 2178946 7329605 6639374 1866650 2840627 2635200 7654377 6753384 6741683 4172578 10101674 13211677 214748 2182376 11212094 769361 226908 4-guanidinobutanoate 2621115648 1403908651 431654148 916157708 389706794 495317648 286759812 596974873 1025601075 840220224 1457286668 659587529 841861112 217076142 98487329 235339220 1049231992 209832368 132031650 4-hydroxy-proline 11760801 32287804 11527947 23085869 13899458 12957918 3133998 8300092 36179311 29942923 23202794 16160553 54761625 14025298 2484050 9045210 4991468 4956742 3102781 7-methyladenine 44516428 14517512 6876107 10689007 8553436 19309283 39709349 7344856 14922971 27820146 63232151 47103368 11832180 55340664 4396582 15667698 123016548 3395601 2482292 adenine 596877056 2401511339 1916438336 2081569306 2192243016 942871722 354176616 1499301414 794554176 1475108368 980309350 960578908 2548913792 1688277248 997245344 416083068 1133779213 1136206976 905052896 adenosine 42926748 247140986 3744201536 187903944 99317744 27398727 110504272 201649020 100911625 204000230 53350097 159168132 160070688 201040892 2774461216 22421635 268654126 1963006312 2345038144 alanine 52877 5007883 1545993 445938 27863 32185 16596 133118 406996 7106755 514487 61608 2674305 42376 86579 19711 48542 1334698 478440 aminoadipic acid 2273757 1341712 47213 829896 1757051 636985 3516 79836 3586957 2756173 2258140 1204262 729292 151376 2601 423630 222798 44282 14347 arginine 22507358 343531073 141800658 154154096 28905911 20968938 18788196 75037374 135604434 126065128 32697324 24465035 67377589 35852352 42559571 18556520 26728138 65737369 45932231 asparagine 1664496 36248618 33357831 31723213 3830204 2490297 1714421 13446810 3927657 7397544 3013992 2558912 14923614 3745788 16073191 1328083 2972201 50617540 13354026 aspartate 5205050 83110649 222749632 101241203 7941530 3226390 2907963 32572437 3587950 5229990 8534007 5286022 82056004 7867873 117564375 2136025 10282667 128782939 113339072 betaine 271070800 452385701 286049996 306537628 95580754 217839154 175993320 143929358 216894284 194678492 402810348 423683924 458732282 2226002640 110978622 96551260 795200339 117601236 132449380 biotin 4950 217893 134479 5327 14035 7332 10125 8022 8081 9691 6213 6268 49457 11409 39815 10324 4262 168475 77424 carnitine 40629628 131755773 184504906 147735513 45589429 64635958 39668420 36525704 112987106 94556014 121681113 121490810 155049890 171268888 35366457 32262403 207014891 49562486 61009785 citrulline 9926 516149 440848 176570 19694 6621 1905 48268 185089 771792 181701 22093 274096 28873 115627 5620 11913 399737 208083 creatinine 4064970 6181552 4716394 4793239 4410336 3209061 5097349 4878258 4429884 4929570 5303368 4690286 5394190 5947984 5535494 4008912 10026626 4678385 4754222 cytidine 21655 1736700 1196651 50263 31313 25587 46743 33453 51104 76644 40575 36557 659914 41331 267369 27539 47163 1397725 573464 cytosine 451627176 654741216 354040608 344414270 134887559 37688826 35434568 297503100 91623096 612431412 202285802 33994144 221016226 120707958 119763811 11549772 86568579 176843136 134906600 decanoate 1604490 1802250 3608851 1851148 2486213 2655067 3422286 2312795 1452663 1612188 1341579 1903420 1961456 3298481 3868516 2724992 2175803 3808527 4137790 disaccharide (maltose) 147815 59821243 32828104 20066267 8806877 78079 43008 4269318 54544938 4457996 180737 227974 3917755 86616 2256335 69826 108100 152033845 29550821 ergothioneine 491552 4216411 54111216 2866153 1056430 160687 297093 1660487 1763023 8028399 852212 579949 2758473 1014485 16401153 449740 1865153 19061208 29053500 fumarate 6352431 5045514 256567 3851180 4218530 3970526 41203 947433 6374136 3226515 1480204 390611 3176848 1321063 70533 859982 168571 1679539 203855 glutamate 343365 28993459 18677732 11987699 4282154 486152 172290 2627682 1382038 11821100 864455 353060 10537527 405923 3071507 215373 417673 16625141 12098670 glutamine 4032758 184958828 207680292 147458620 57124464 4876707 3485976 79768640 63279340 184404484 8425430 6779326 100944544 12081397 75076050 4406568 7940763 240790108 78783764 guanine 56624460 544936277 169699330 407494656 378470748 121371136 32363846 279728611 206344294 303479716 204068803 96346440 523492336 62799250 33866250 37056230 155070930 98608990 51937843 guanosine 12209 774431 1006066 30555 7297 7511 10031 15392 55946 68216 26712 27340 306752 18828 165673 6972 41477 953345 566776 hypoxanthine 26464027 54003068 3481677 33625446 19839239 32529544 237780 9413357 46553479 75561948 59315225 17422999 34264734 5959963 508596 13799874 22139444 3003448 1425797 inosine 91856 3069826 1013621 83155 30408 36291 3227 16614 255289 156555 67203 133644 1747710 19947 200248 10804 39657 1959570 850923 isoleucine 84359414 548548594 500740408 48477950 2050012471 11767760 11655481 98049806 14488509 15534967 72402204 12513549 822035295 17726428 117028996 8350104 11507010 182074969 126609055 lactate 61842170 17544868 8294927 15047578 6024068 7340255 1212756 3316645 80427064 94411608 52910415 62894057 52304795 1546482 1785392 2562389 45522173 2535693 3828330 laurate 1763783 1747736 3099909 1839203 2017409 2436237 2292949 2212798 1406168 1473190 1376635 1938180 1902214 2399695 3305807 2178413 1940271 3062284 3335792 leucine 60415054 839918669 790635912 85771348 51443384 10740714 18477168 96326154 13750782 23479040 113386045 21141109 1158762678 27675668 161249644 11077086 28023388 110312472 164162652 lysine 6881551 36411724 29501812 24914458 9118182 6684833 5656130 23055133 17657790 17359110 20712616 11542567 15975689 15045355 28451429 7295822 9748115 21557172 70277678 methionine 6779332 150633349 68423166 59164455 8027285 2351197 1557079 27710241 5198241 12530324 107723090 3307465 158186167 5388610 10777251 2686989 6285485 26299422 15083033 monosaccharide (glucose) 4450982 2945922 1095402 1652581 1172856 2121546 17608 342865 2474715 1305138 2783827 2050478 1844807 1246409 29666 795967 2885309 895530 291250 myristate 7914818 8117998 16314038 8628407 10257583 8822154 9401871 10390105 6107868 7320690 6267574 5896386 9182365 7317717 18190995 9612301 6826818 16601130 17479787 N-acetyl-glutamate 5356787 12662878 3638355 4796224 3614005 4195229 278185 719227 18968965 9700563 2095227 2572965 5760105 1132850 239744 2323361 1306870 3991431 2578862 N-acetylornithine 6810677 84910544 40686370 75763200 14085511 8115450 5220645 17476517 51544530 67171681 65879258 17369349 89543424 26407061 11890565 7136365 27156904 15363869 18551710 nicotinamide 19016967 113992920 56479025 92853769 41119884 10423805 14652899 59407242 26327273 41337546 11380280 16152650 28573149 15189956 39446091 10939044 31903552 28450524 28213174 nicotinate 2221019 297114 465291 225320 374179 964259 485402 60121 847138 655011 1250840 1969857 485247 976617 72665 482190 2887183 332667 208131 oleate 1167045 1648760 894387 1603995 955734 710419 841422 1170349 1791113 1382145 1693944 970468 1441727 955284 1141759 521124 1284746 1015091 1013554 palmitate 88584843 89734473 150731254 91830809 105837897 93859100 100718424 106499568 73167218 84141017 78906683 73000140 95013348 83117273 165160553 97703182 80788993 155626153 158510246 palmitoleate 2567826 10442504 4098812 15880692 2248348 383457 488527 4601510 7956119 7940981 2497579 1276231 12509965 1350388 1224232 385087 1425838 1953223 2386563 pantothenate 327843160 75441706 18908850 57806096 89544601 175746066 45856197 28359610 165509352 132037220 392289092 263407734 175977818 357115672 3147826 95070136 617403910 8971354 5473330 phenylalanine 69260 32292174 2052885 8934382 24721 45545 11316 1487169 3913328 5666559 5960786 45906 12364542 133679 152193 13687 55747 2220847 690372 proline 27904022 104062021 134924838 31341144 20992032 23272185 14821475 24779432 94218990 96292878 25299077 17939760 95099881 24446361 48863741 11239098 31106550 68649658 48254394 pyridoxine 91308260 4347935 2810577 3922711 4920505 15272777 26644529 2856004 5194241 6183107 12335872 24282651 5424110 33227682 1459842 11304249 48708015 2103452 1575729 pyroglutamate 875866 4393822 1846369 1928640 1126649 933577 71755 290141 4811027 3840933 874825 470478 1534802 193343 394517 195509 138306 2359035 880774 raffinose 362589 16694923 4312293 5171451 2925671 202101 44485 2082748 22396411 10208114 712383 173599 3287045 102734 566846 84760 110978 16630428 2474203 salicylate 17233740 5269926 4555815 5014989 9958679 14421406 13354007 8070221 8854859 6653538 13771505 16103773 7806770 11925727 4618607 14684210 21530172 3844936 5054321 serine 6005327 81456627 63828011 36973595 10161350 4433442 3413385 17673774 11693715 11149152 5262850 4106207 72226296 7189765 19001918 3362835 5003366 29048626 21124178 stachyose 1266809 7001224 5518530 3538248 1635820 114749 15847 1444160 9307545 9424552 659678 136146 3463877 46295 608514 34596 56534 4899066 3406955 stearate 160302696 174059523 261015126 168262745 191262444 165539187 173924176 192738240 139654593 157269664 141472452 130949436 176060444 148949619 281944908 172214278 144985691 271517766 273308364 succinate 36848062 68021032 12786345 54410146 31991306 24273109 472562 15116361 59877529 35890640 14996591 7773205 37193581 6908511 3077373 4118413 4213415 23294365 6859918 taurine 72673016 4171559 5367164 4949182 5158336 9876442 21706884 3277158 5306108 7158805 13572616 14372983 4981971 54934466 3370099 8713591 68640535 3444688 2778817 threonine 32111 2012064 772584 396532 35261 29181 12577 158238 106428 645364 179484 34237 1484473 28395 90339 17703 34821 873383 283678 thymidine 0 5089669 1503310 1509582 1552496 0 0 7348 120363 481150 4117462 0 1933544 8664553 34397 0 0 1031304 819120 thymine 9213899 11331274 448543 11438349 4882161 8317165 233091 5123419 19530305 20865250 19599532 1452559 15169666 8715251 109349 3989909 8598488 253399 246399 tryptophan 1648272 220618952 65047095 141850663 3880187 495290 574471 49754577 49654224 39651101 1894473 576164 67037417 6172212 13088307 300802 1101640 46597109 16385973 tyrosine 58414 25505184 1710039 13680010 21327 55166 27657 1965698 10089340 16368842 4303875 81706 5562167 91775 194658 36097 90577 1737798 743442 uracil 69221727 108816756 35204637 120308734 86759694 88900175 1030888 65034268 133451476 125305379 120499462 499514 132533950 86402320 4125935 50935301 34207943 17512613 13107718 urate 584184 146691 3069240 94195 62559 210863 91435 40786 256581 278540 620930 584321 71557 370205 29208 148125 1374207 231523 93451 uridine 149123 23769767 21964584 301903 155481 92155 152577 106934 478292 1060865 198400 398349 7533056 237257 3439209 103822 496181 22551330 15350040 urocanate 5701000 4817844 200348 3911638 6364446 3584922 3054061 2216264 10524465 8808024 9503982 9910207 6862071 5807147 181869 2285158 13003412 222793 243979 valine 110522 16928788 4489668 224102 83965 84272 58987 93602 126388 21012560 1109175 110781 13818424 93203 201910 60014 178001 2571421 1135240 xanthine 104235988 37008337 1769415 26843470 13328309 36761261 3369387 3693085 65239143 64820107 101180416 66325417 23180892 44224468 142192 18055989 111962712 437041 454639 xylitol 2812511 2434361 445519 1515462 1263282 1486881 181878 717907 3069008 1546167 1976039 1606142 1071575 2256694 56899 738026 1777920 1480906 118361 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/soils/metabolites.tsv.sha256000066400000000000000000000001221520735541300322420ustar00rootroot00000000000000802e9076be6e14073e2b3730964a1a20c0c18c27214e40617d9feff7e052c0ae metabolites.tsv scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/soils/microbes.tsv000066400000000000000000001040301520735541300305310ustar00rootroot00000000000000 42hr_latemid 9hr_latemid 3min_late 9hr_earlymid 18hr_early 42hr_earlymid 49p5hr_early 9hr_early 18hr_latemid 18hr_late 42hr_late 49p5hr_latemid 18hr_earlymid 49p5hr_earlymid 3min_early 42hr_early 49p5hr_late 3min_latemid 3min_earlymid rplo 1 (Cyanobacteria) 113 2157 5313 1551 3771 1417 301 2077 1538 976 765 70 1016 677 4121 2117 49 2032 4489 rplo 2 (Firmicutes) 1641 4843 0 3523 2592 2435 195 3832 6867 0 152 731 19 302 0 1781 241 0 25 rplo 60 (Firmicutes) 628 0 0 0 0 47 49 0 128 174 51 63 231 569 0 0 0 0 0 rplo 7 (Actinobacteria) 233 326 337 345 457 310 363 488 330 170 252 248 285 328 196 508 22 171 122 rplo 10 (Firmicutes) 871 0 0 0 775 0 341 0 666 0 152 0 0 2289 0 720 0 0 0 rplo 100 (Proteobacteria) 25 18 91 44 55 35 36 33 19 0 171 31 0 45 132 29 130 16 56 rplo 101 (Proteobacteria) 0 24 0 20 74 16 917 0 26 25 26 0 0 92 0 21 0 66 0 rplo 102 (Actinobacteria) 0 21 0 53 130 128 0 81 46 23 92 0 138 27 80 56 40 20 21 rplo 103 (Actinobacteria) 0 55 0 28 267 110 19 70 0 0 0 66 197 71 0 240 0 0 20 rplo 104 (Bacteroidetes) 0 0 119 0 119 230 24 0 0 49 25 0 0 0 108 0 386 0 24 rplo 105 (Proteobacteria) 0 62 129 17 43 14 43 79 0 66 112 18 51 80 0 0 0 38 0 rplo 106 (Acidobacteria) 0 0 45 36 0 852 22 0 24 0 0 0 0 28 0 38 0 40 23 rplo 107 (Actinobacteria) 87 61 0 67 63 41 19 156 45 0 66 18 34 0 19 72 19 75 22 rplo 108 (Actinobacteria) 27 111 96 46 77 50 0 18 0 99 40 33 92 24 53 65 0 34 20 rplo 109 (Proteobacteria) 81 19 0 31 0 50 20 0 0 0 0 0 1014 0 0 17 0 0 20 rplo 11 (Proteobacteria) 355 105 669 309 0 28 0 100 936 153 181 56 152 0 0 0 712 154 155 rplo 110 (Proteobacteria) 0 0 155 18 0 0 88 41 0 0 23 38 0 82 80 19 40 38 22 rplo 111 (Actinobacteria) 64 22 23 34 0 0 45 63 24 71 24 0 18 29 124 39 0 103 71 rplo 112 (Actinobacteria) 54 56 78 124 76 75 0 36 61 0 0 50 31 0 0 49 17 35 119 rplo 113 (unknown) 142 20 182 16 0 40 21 0 22 0 0 18 81 0 19 0 0 91 42 rplo 114 (Deinococcus-Thermus) 0 48 23 159 75 32 25 89 76 26 26 0 20 0 0 21 0 0 26 rplo 115 (Acidobacteria) 0 348 42 0 42 27 0 0 0 0 0 73 17 105 38 36 19 38 130 rplo 116 (unknown) 60 0 0 34 0 0 0 0 136 0 0 0 416 0 0 0 0 0 90 rplo 117 (Deferribacteres) 136 146 48 156 50 160 0 46 0 0 53 0 40 0 0 0 0 0 0 rplo 118 (Acidobacteria) 31 0 23 0 45 15 68 0 119 0 47 19 0 28 41 35 0 40 0 rplo 119 (Actinobacteria) 29 61 63 67 0 14 21 39 44 21 22 0 17 26 57 36 19 37 22 rplo 12 (Gemmatimonadetes) 88 418 216 345 193 42 130 259 205 308 181 19 69 106 176 110 97 77 422 rplo 120 (Actinobacteria) 0 85 44 18 22 57 0 61 46 45 46 38 70 27 40 75 20 116 0 rplo 121 (Actinobacteria) 0 21 22 69 0 70 61 100 46 22 23 19 69 27 20 18 20 39 45 rplo 122 (Cyanobacteria) 67 47 0 38 0 0 0 22 51 0 25 21 0 0 0 0 22 43 25 rplo 123 (Cyanobacteria) 0 158 0 19 0 0 0 0 25 122 126 41 0 0 0 0 43 148 25 rplo 124 (Chloroflexi) 75 140 0 115 36 12 0 83 57 0 73 108 72 22 33 61 32 0 18 rplo 125 (Actinobacteria) 0 24 49 39 48 0 49 45 76 50 75 21 19 0 66 103 0 0 0 rplo 126 (Gemmatimonadetes) 0 0 44 17 22 28 22 119 46 22 46 55 17 0 179 0 0 58 0 rplo 127 (Acidobacteria) 0 0 62 49 61 100 31 113 32 0 0 0 122 38 56 26 0 55 63 rplo 128 (Acidobacteria) 32 21 23 125 0 0 23 124 24 23 120 20 18 0 38 58 41 81 23 rplo 129 (Proteobacteria) 28 0 0 16 0 0 0 19 21 0 42 0 32 0 0 0 0 71 0 rplo 13 (Proteobacteria) 0 0 0 0 22 335 586 21 0 0 71 369 18 2628 21 593 651 0 0 rplo 130 (Verrucomicrobia) 25 35 18 0 0 0 0 83 0 0 19 0 0 0 33 0 16 112 147 rplo 131 (Proteobacteria) 0 23 0 75 23 46 0 22 0 72 98 0 19 29 64 99 21 21 48 rplo 132 (Proteobacteria) 88 0 21 68 0 0 21 39 22 65 309 73 67 53 0 0 19 19 22 rplo 133 (Proteobacteria) 31 21 0 35 111 14 200 39 70 0 46 37 35 0 20 38 80 59 23 rplo 134 (Bacteroidetes) 0 0 0 0 0 0 1014 0 0 0 0 20 0 0 0 20 0 0 0 rplo 135 (Actinobacteria) 75 54 0 22 54 71 28 0 115 0 0 0 88 34 25 70 0 0 0 rplo 136 (Cyanobacteria) 0 0 24 37 0 15 0 0 0 24 0 0 0 0 0 0 0 0 73 rplo 137 (Proteobacteria) 29 0 22 70 0 14 0 20 69 67 223 38 35 0 0 37 20 97 112 rplo 138 (Bacteroidetes) 0 0 0 0 0 33 847 0 0 0 0 93 0 67 0 0 0 0 0 rplo 139 (Actinobacteria) 0 0 34 27 0 195 0 0 0 68 0 0 27 42 0 29 0 0 105 rplo 14 (Proteobacteria) 30 0 0 52 2136 0 174 20 23 0 0 0 51 27 411 1521 0 94 0 rplo 140 (Chloroflexi) 39 53 28 78 85 55 0 39 30 0 0 37 101 70 39 82 0 49 15 rplo 141 (Firmicutes) 47 16 0 54 68 11 101 78 36 0 0 15 27 42 62 29 0 45 17 rplo 142 (Actinobacteria) 0 38 40 63 0 51 35 0 0 81 124 0 31 144 0 0 36 0 0 rplo 143 (Actinobacteria) 131 47 45 19 24 0 49 0 0 25 102 0 39 30 22 21 108 86 0 rplo 144 (Cyanobacteria) 0 176 0 18 23 0 0 21 24 47 0 0 0 0 62 0 0 61 0 rplo 145 (Actinobacteria) 68 71 0 0 123 96 25 45 26 0 0 63 117 0 0 103 44 22 0 rplo 146 (Chloroflexi) 0 77 0 64 31 93 48 118 34 0 33 14 51 119 15 27 43 0 16 rplo 147 (Actinobacteria) 64 0 23 18 90 89 0 0 0 47 120 60 0 115 0 56 61 0 0 rplo 148 (Chloroflexi) 0 84 0 14 16 67 35 81 73 0 0 15 180 87 0 104 0 0 18 rplo 149 (Actinobacteria) 0 47 24 58 24 0 195 67 0 50 51 21 19 0 43 62 44 22 25 rplo 15 (Firmicutes) 206 81 277 151 41 111 42 195 156 129 157 92 51 105 273 55 115 306 243 rplo 150 (Actinobacteria) 32 157 0 18 113 59 0 21 24 0 0 40 18 86 21 59 0 62 0 rplo 151 (Actinobacteria) 0 126 22 0 43 84 0 0 91 66 45 56 52 54 0 37 0 0 0 rplo 152 (Bacteroidetes) 125 44 23 0 45 15 42 21 167 0 24 19 36 0 79 95 20 121 23 rplo 153 (Bacteroidetes) 0 23 71 38 0 15 0 0 0 0 0 0 0 0 21 0 0 63 24 rplo 154 (Proteobacteria) 61 64 66 35 0 29 66 0 0 113 69 111 70 0 0 0 0 39 0 rplo 155 (Proteobacteria) 97 45 0 37 70 0 0 0 94 24 98 0 75 0 0 0 42 0 24 rplo 156 (Proteobacteria) 0 0 21 0 20 13 21 38 0 0 0 35 49 25 0 0 0 18 0 rplo 157 (Bacteroidetes) 0 24 100 20 0 0 0 69 0 26 52 43 20 0 23 21 0 0 75 rplo 158 (Chloroflexi) 96 69 0 86 0 80 18 33 57 18 19 31 57 22 16 136 16 32 37 rplo 159 (Actinobacteria) 64 0 0 19 191 126 24 0 77 0 0 0 19 30 44 41 0 43 50 rplo 16 (Proteobacteria) 60 253 305 226 130 99 197 422 69 134 68 94 69 54 119 166 78 95 290 rplo 160 (Actinobacteria) 91 21 22 123 22 29 0 61 93 0 46 19 103 0 0 0 0 0 0 rplo 161 (Proteobacteria) 83 0 0 110 20 26 20 19 0 21 63 17 0 100 36 0 36 18 142 rplo 162 (Actinobacteria) 67 24 24 97 0 16 24 67 0 0 25 0 77 0 44 41 0 22 0 rplo 163 (Actinobacteria) 0 111 0 0 98 234 0 15 52 17 0 57 117 20 0 70 0 0 0 rplo 164 (Cyanobacteria) 0 45 45 19 0 0 70 105 0 48 0 0 0 0 0 0 42 0 0 rplo 165 (Proteobacteria) 0 0 0 88 44 14 88 20 0 45 23 19 17 109 20 19 0 20 0 rplo 166 (Actinobacteria) 60 63 0 86 65 70 0 40 91 22 0 19 17 27 20 55 0 19 22 rplo 167 (Chloroflexi) 0 140 0 0 54 70 36 17 19 0 19 62 115 90 33 46 0 32 0 rplo 168 (Proteobacteria) 27 58 20 0 0 13 20 0 21 0 311 17 47 0 54 0 18 18 0 rplo 169 (Proteobacteria) 29 21 21 0 0 14 0 20 68 44 89 73 33 0 19 18 38 38 152 rplo 17 (Actinobacteria) 131 327 195 288 97 125 122 379 179 221 102 0 193 30 264 21 44 151 149 rplo 170 (Proteobacteria) 118 21 22 52 0 14 0 0 23 22 46 75 52 0 0 0 20 19 290 rplo 171 (Actinobacteria) 34 47 0 97 24 63 0 90 77 0 25 0 39 0 0 103 0 22 0 rplo 172 (Firmicutes) 0 55 75 15 38 25 0 193 81 0 0 33 15 24 87 30 0 34 20 rplo 173 (Proteobacteria) 0 21 22 17 0 14 0 0 23 89 23 19 17 54 0 18 19 0 67 rplo 174 (Bacteroidetes) 33 0 72 38 0 31 96 0 47 0 0 41 38 0 65 0 85 42 24 rplo 175 (Proteobacteria) 28 20 21 16 20 40 41 76 22 21 0 0 49 0 56 17 0 18 21 rplo 176 (Proteobacteria) 161 113 23 19 0 29 0 22 0 24 49 40 74 0 21 40 21 42 24 rplo 177 (Proteobacteria) 0 109 23 36 68 44 45 21 0 0 24 39 36 84 0 38 0 0 44 rplo 178 (Acidobacteria) 0 44 91 90 23 29 66 42 0 22 68 58 36 0 60 0 41 40 0 rplo 179 (Actinobacteria) 63 88 0 0 137 131 46 21 0 0 0 20 109 28 42 0 0 0 0 rplo 18 (Gemmatimonadetes) 123 129 157 248 356 29 134 309 234 137 186 192 35 305 202 113 279 79 430 rplo 180 (Actinobacteria) 91 42 22 105 44 99 22 0 23 22 69 0 17 54 0 19 39 0 0 rplo 181 (Actinobacteria) 0 39 22 17 0 99 0 0 0 0 0 19 35 54 20 0 20 0 67 rplo 182 (Bacteroidetes) 0 88 72 35 47 15 24 39 25 24 0 0 0 30 43 20 0 21 0 rplo 183 (Actinobacteria) 0 35 37 29 36 47 0 34 0 0 38 0 29 45 132 31 0 0 37 rplo 184 (Proteobacteria) 0 0 0 16 0 0 0 0 42 634 0 17 0 0 0 0 36 0 0 rplo 185 (Acidobacteria) 0 0 51 20 25 0 25 23 107 0 0 0 40 0 23 0 0 68 0 rplo 186 (Proteobacteria) 33 23 121 0 24 45 24 44 25 0 0 0 19 60 22 81 87 0 25 rplo 187 (Thermotogae) 63 0 0 0 91 43 0 0 73 0 0 0 147 58 21 38 0 0 24 rplo 188 (Chloroflexi) 0 35 18 29 72 126 18 33 76 0 0 46 85 22 16 31 0 16 0 rplo 189 (Chloroflexi) 0 35 36 28 0 0 0 16 19 73 37 31 0 0 31 0 0 64 37 rplo 19 (Firmicutes) 0 0 0 0 0 14 0 22 0 4488 0 0 0 0 0 0 0 0 0 rplo 190 (Planctomycetes) 0 19 39 0 0 0 0 0 0 20 0 33 0 24 35 0 0 17 40 rplo 191 (Bacteroidetes) 32 0 24 38 0 0 0 0 50 24 122 20 38 30 41 20 21 0 0 rplo 192 (Actinobacteria) 0 71 0 0 145 140 0 22 51 0 0 42 38 0 0 82 0 0 0 rplo 193 (Proteobacteria) 74 0 53 0 53 34 53 146 0 53 0 46 0 66 48 0 0 0 0 rplo 194 (Proteobacteria) 122 20 0 69 0 0 0 0 116 23 23 38 50 0 0 0 0 58 0 rplo 195 (Gemmatimonadetes) 60 21 0 34 21 0 22 40 0 22 152 0 17 0 0 18 58 19 22 rplo 196 (Thermotogae) 0 0 0 0 19 25 0 0 0 20 20 0 0 0 50 33 0 17 40 rplo 197 (Actinobacteria) 51 71 18 73 0 0 0 33 39 19 57 0 29 0 17 0 16 33 0 rplo 198 (Acidobacteria) 0 104 65 34 0 56 22 0 23 0 0 18 34 52 39 73 19 77 20 rplo 199 (Thermobaculum) 83 40 0 50 21 27 42 0 0 0 0 18 66 26 0 53 0 0 0 rplo 20 (Actinobacteria) 200 233 97 310 46 109 71 90 101 174 152 167 96 30 110 103 87 22 124 rplo 200 (Actinobacteria) 0 39 0 0 61 105 0 0 64 42 21 52 32 0 0 34 18 18 62 rplo 201 (Acidobacteria) 31 0 66 36 0 14 45 62 24 0 23 38 18 0 40 75 0 20 46 rplo 202 (Firmicutes) 0 0 155 0 22 0 22 0 0 0 23 19 89 0 20 0 0 20 203 rplo 203 (Chloroflexi) 49 0 0 0 72 234 18 17 19 0 0 16 43 112 0 15 0 0 19 rplo 204 (Bacteroidetes) 33 0 24 38 24 15 0 22 25 25 25 0 38 0 44 0 0 21 0 rplo 205 (Deinococcus-Thermus) 0 0 0 0 0 0 696 0 0 0 0 0 0 0 0 20 21 0 0 rplo 206 (Actinobacteria) 0 43 0 0 0 57 0 40 0 0 0 0 105 0 79 37 40 39 90 rplo 207 (Proteobacteria) 0 0 0 231 0 0 0 0 24 68 0 0 18 0 0 0 0 0 156 rplo 208 (Acidobacteria) 0 78 80 0 0 0 0 37 0 0 0 0 0 0 0 0 0 0 0 rplo 209 (Proteobacteria) 0 63 22 87 22 0 0 60 0 0 23 0 0 27 79 0 20 19 22 rplo 21 (Actinobacteria) 232 142 147 184 105 190 169 155 199 0 154 198 283 26 114 213 19 165 108 rplo 210 (Proteobacteria) 0 0 0 31 39 76 0 36 41 0 123 0 62 49 36 33 0 35 0 rplo 211 (Actinobacteria) 33 70 73 0 24 93 0 22 102 0 0 21 76 0 0 41 0 0 0 rplo 212 (unknown) 21 60 0 12 0 80 0 0 33 0 32 13 37 212 0 26 14 0 0 rplo 213 (Bacteroidetes) 30 69 119 0 0 0 0 44 0 49 0 41 0 0 0 0 43 42 0 rplo 214 (Bacteroidetes) 0 0 48 38 0 0 0 22 0 24 0 0 0 30 64 20 0 0 73 rplo 215 (Verrucomicrobia) 0 0 0 15 111 36 56 34 0 0 0 0 0 0 117 47 0 0 0 rplo 216 (Actinobacteria) 60 0 43 0 0 14 43 20 46 44 68 17 17 0 20 0 0 19 22 rplo 217 (Proteobacteria) 30 42 65 52 0 14 0 40 23 41 45 74 17 81 0 0 39 0 22 rplo 218 (Firmicutes) 74 0 0 0 0 0 0 0 38 0 0 0 0 0 0 0 0 32 0 rplo 219 (Thermotogae) 0 0 54 0 0 0 0 16 0 0 0 0 0 0 177 0 0 32 55 rplo 22 (Actinobacteria) 145 202 105 50 145 217 105 78 222 129 197 144 200 155 114 178 0 112 43 rplo 220 (Chloroflexi) 32 160 0 35 24 0 0 0 0 24 99 0 0 0 21 0 0 0 194 rplo 221 (Proteobacteria) 0 21 0 35 44 14 0 40 0 0 68 0 17 27 0 0 39 19 22 rplo 222 (Proteobacteria) 0 21 21 52 43 0 43 100 0 22 0 0 17 0 79 54 38 0 22 rplo 223 (Chloroflexi) 27 19 20 47 20 0 40 127 0 0 0 34 47 0 0 50 36 0 41 rplo 224 (Chloroflexi) 42 58 0 12 30 49 30 14 32 0 32 13 72 0 14 0 68 13 16 rplo 225 (Firmicutes) 0 0 0 28 0 11 18 98 56 0 0 0 56 110 48 15 0 47 52 rplo 226 (Actinobacteria) 52 37 37 46 0 49 0 35 39 0 0 16 61 0 17 32 34 17 0 rplo 227 (Actinobacteria) 23 16 0 13 50 107 17 13 18 0 0 14 79 0 0 84 0 30 0 rplo 228 (Proteobacteria) 0 0 70 37 23 0 23 21 0 0 24 0 0 58 42 0 39 0 47 rplo 229 (Proteobacteria) 0 0 45 18 0 29 0 0 24 23 91 136 0 0 38 19 81 20 0 rplo 23 (Proteobacteria) 132 92 172 91 38 49 0 35 20 955 239 82 45 24 87 48 361 34 117 rplo 230 (Proteobacteria) 0 0 23 37 69 30 0 21 0 47 0 20 0 0 63 0 0 21 24 rplo 231 (Bacteroidetes) 33 23 24 56 24 44 0 22 126 0 0 0 0 0 0 20 0 43 0 rplo 232 (Bacteroidetes) 120 0 0 35 43 14 44 20 69 0 91 0 17 54 0 0 20 0 0 rplo 233 (Bacteroidetes) 0 0 0 38 166 0 0 85 25 0 0 0 0 0 43 60 0 0 0 rplo 234 (Gemmatimonadetes) 32 45 0 0 138 0 0 43 24 0 0 0 37 0 166 0 0 0 0 rplo 235 (Bacteroidetes) 65 0 24 38 47 15 0 44 23 0 0 0 19 0 129 0 21 21 94 rplo 236 (Proteobacteria) 0 20 41 32 20 13 0 0 0 42 42 119 0 0 18 17 18 18 0 rplo 237 (Firmicutes) 0 21 43 0 0 14 0 20 0 0 23 0 17 0 20 37 0 19 43 rplo 238 (Acidobacteria) 0 27 55 22 0 0 83 126 0 0 0 24 0 0 25 23 0 24 0 rplo 239 (Proteobacteria) 103 0 25 20 0 16 49 23 52 0 52 21 20 31 23 0 67 22 0 rplo 24 (Actinobacteria) 134 259 316 155 73 94 49 200 128 50 102 230 77 0 396 144 87 130 25 rplo 240 (Actinobacteria) 54 0 20 30 19 0 0 36 41 0 20 0 31 0 89 0 18 0 0 rplo 241 (Gemmatimonadetes) 49 67 143 28 0 0 0 0 38 0 75 31 0 0 0 0 60 29 0 rplo 242 (Acidobacteria) 0 23 0 38 48 31 24 0 0 25 50 21 38 89 22 61 0 0 0 rplo 243 (Cyanobacteria) 0 20 22 0 22 0 0 0 0 0 0 0 0 0 0 0 0 39 114 rplo 244 (Bacteroidetes) 64 23 24 57 95 15 0 0 25 0 0 20 19 30 22 40 0 0 98 rplo 245 (Firmicutes) 0 0 65 17 0 14 0 20 23 45 91 0 0 27 59 0 0 0 22 rplo 246 (Aquificae) 60 0 0 0 0 0 0 40 68 22 66 0 0 0 39 0 0 0 43 rplo 247 (Firmicutes) 31 0 42 0 20 58 0 0 0 0 94 0 36 28 0 0 20 0 0 rplo 248 (Cyanobacteria) 0 0 72 0 0 0 48 22 0 0 0 0 0 0 22 0 0 0 0 rplo 249 (Proteobacteria) 68 24 0 0 49 32 0 46 26 0 26 0 20 0 23 21 0 0 0 rplo 25 (Acidobacteria) 30 107 243 70 22 199 88 18 93 0 0 19 51 82 714 37 20 566 90 rplo 250 (Actinobacteria) 0 0 0 0 48 16 73 45 0 0 0 21 135 60 22 41 0 22 0 rplo 251 (Proteobacteria) 0 0 85 31 0 0 44 81 0 45 0 0 0 0 0 37 40 39 0 rplo 252 (Thermotogae) 0 21 70 37 0 15 24 22 50 24 0 0 18 0 43 99 0 21 0 rplo 253 (Actinobacteria) 0 93 0 0 0 47 0 0 76 25 51 0 0 0 0 41 44 22 25 rplo 254 (Proteobacteria) 0 24 25 20 0 16 75 183 0 0 0 0 0 0 135 0 0 0 0 rplo 255 (Proteobacteria) 60 21 0 17 0 14 22 0 23 19 0 37 137 0 20 0 0 39 22 rplo 256 (Acidobacteria) 28 0 0 36 89 0 67 0 0 0 0 19 18 0 0 38 0 0 0 rplo 257 (Chloroflexi) 59 41 21 51 0 14 21 20 0 22 22 18 34 0 19 0 19 0 22 rplo 258 (Actinobacteria) 0 49 0 14 51 110 0 0 36 0 0 29 94 0 0 57 0 15 0 rplo 259 (Proteobacteria) 0 0 0 0 159 0 115 42 48 23 0 0 0 0 21 78 0 0 0 rplo 26 (Actinobacteria) 62 141 24 251 242 173 73 134 178 0 25 230 586 0 175 141 0 230 0 rplo 260 (Acidobacteria) 0 0 0 0 0 0 0 0 0 21 116 0 0 57 42 19 124 0 23 rplo 261 (Bacteroidetes) 0 0 33 54 0 65 0 62 0 0 0 0 27 0 31 0 0 0 69 rplo 262 (Actinobacteria) 41 44 30 12 45 49 0 69 48 0 0 13 96 0 0 25 0 0 0 rplo 263 (Cyanobacteria) 0 21 24 19 0 0 0 67 0 25 0 0 0 0 44 0 0 21 0 rplo 264 (Actinobacteria) 101 24 49 58 0 0 0 0 0 25 51 21 0 0 22 0 22 65 0 rplo 265 (Verrucomicrobia) 0 0 46 0 22 13 23 21 24 24 48 0 0 0 42 0 0 59 24 rplo 266 (Proteobacteria) 62 22 22 18 0 0 45 0 0 43 0 0 53 0 0 0 0 0 46 rplo 267 (Proteobacteria) 27 43 0 0 0 14 0 0 23 23 69 38 0 0 0 0 0 20 68 rplo 268 (Chloroflexi) 0 35 37 15 0 24 18 0 0 75 93 16 0 0 17 0 82 0 18 rplo 269 (Actinobacteria) 0 22 23 0 43 119 0 0 24 0 0 0 18 58 0 20 42 0 0 rplo 27 (Proteobacteria) 29 248 64 68 213 207 64 177 68 0 22 110 119 159 233 106 38 132 152 rplo 270 (Actinobacteria) 0 41 21 34 0 0 0 0 23 44 67 55 17 0 0 0 38 38 0 rplo 271 (Proteobacteria) 59 0 0 0 0 0 0 0 90 153 0 18 17 27 0 0 0 0 22 rplo 272 (Thermotogae) 0 23 0 56 0 0 24 22 0 0 0 20 37 0 0 40 0 42 0 rplo 273 (Acidobacteria) 0 0 0 0 45 14 66 21 47 0 0 0 0 0 61 19 0 0 0 rplo 274 (Bacteroidetes) 190 0 0 0 24 31 0 0 50 0 0 41 0 0 0 0 0 42 24 rplo 275 (Chloroflexi) 29 0 21 17 21 14 21 39 0 43 44 0 17 0 19 0 19 37 0 rplo 276 (Bacteroidetes) 0 0 0 0 0 0 398 22 0 0 0 0 0 0 22 0 0 21 0 rplo 277 (Chloroflexi) 41 57 15 0 72 10 15 69 0 0 0 37 0 0 14 50 0 0 0 rplo 278 (unknown) 0 0 0 0 81 79 0 0 85 0 0 35 32 0 0 34 0 36 0 rplo 279 (Chloroflexi) 0 0 0 98 18 45 18 0 0 0 0 15 42 22 16 15 0 47 0 rplo 28 (Proteobacteria) 107 94 78 47 19 63 20 108 82 40 408 100 46 145 106 50 263 139 80 rplo 280 (Acidobacteria) 0 0 0 0 21 15 0 21 0 0 23 0 36 56 41 38 0 0 92 rplo 281 (Chloroflexi) 50 53 0 14 0 23 0 0 19 19 114 16 14 23 0 0 0 16 37 rplo 282 (Acidobacteria) 31 22 0 18 23 0 0 0 48 0 0 19 0 0 0 0 0 80 0 rplo 283 (Verrucomicrobia) 0 23 0 19 96 62 0 22 23 0 0 0 19 0 65 61 0 0 25 rplo 284 (Acidobacteria) 0 22 22 36 22 0 67 0 47 0 23 0 0 0 61 0 0 40 69 rplo 285 (Proteobacteria) 0 21 22 0 0 0 86 0 23 91 46 57 0 0 0 19 20 20 0 rplo 286 (unknown) 62 22 0 70 0 0 0 0 71 0 0 0 0 0 20 19 0 40 0 rplo 287 (Chloroflexi) 25 52 0 14 18 70 0 0 19 0 19 73 0 90 0 0 0 0 18 rplo 288 (Deinococcus-Thermus) 0 0 21 33 0 0 0 39 0 0 0 0 0 26 0 0 0 19 21 rplo 289 (Proteobacteria) 29 0 21 33 21 14 0 39 0 0 22 18 67 0 0 0 0 37 0 rplo 29 (Gemmatimonadetes) 128 67 23 184 0 75 0 0 98 0 170 0 55 29 21 0 21 330 1131 rplo 290 (Acidobacteria) 31 0 91 0 0 0 0 42 0 0 0 19 0 0 0 0 0 0 46 rplo 291 (Nitrospirae) 33 0 0 0 0 31 24 0 50 0 25 0 19 59 22 20 0 0 0 rplo 292 (Actinobacteria) 80 38 19 0 0 13 0 18 0 0 20 17 46 0 0 0 0 52 0 rplo 293 (Acidobacteria) 31 0 0 18 0 0 22 21 0 0 23 0 18 0 0 19 0 79 46 rplo 294 (Verrucomicrobia) 0 24 24 0 24 0 0 0 72 25 0 20 0 30 0 0 0 22 0 rplo 295 (Actinobacteria) 0 0 0 59 110 48 0 0 0 0 38 0 58 0 0 31 33 0 0 rplo 296 (Gemmatimonadetes) 0 0 19 0 0 0 0 0 0 0 23 0 35 0 20 38 20 59 45 rplo 297 (Proteobacteria) 0 22 46 0 0 0 0 0 24 0 24 20 0 0 21 0 0 20 0 rplo 298 (Chloroflexi) 25 35 0 14 18 23 0 0 38 0 38 16 72 0 0 107 0 0 0 rplo 299 (unknown) 0 0 22 18 22 29 22 21 0 0 23 19 35 28 0 0 0 0 23 rplo 3 (Proteobacteria) 85 79 206 194 164 1279 3465 188 43 83 750 2145 147 1373 130 1960 3582 110 147 rplo 30 (Proteobacteria) 218 152 45 36 203 307 113 167 72 69 47 155 89 140 82 210 81 59 46 rplo 300 (Proteobacteria) 87 0 21 34 0 27 0 19 0 0 44 18 0 0 0 18 19 19 22 rplo 301 (Chloroflexi) 24 17 53 0 50 23 0 0 19 18 110 0 28 0 0 0 16 0 36 rplo 302 (unknown) 0 22 0 18 0 0 0 0 0 0 0 0 0 0 41 0 0 0 46 rplo 303 (Actinobacteria) 0 24 0 58 24 0 0 22 0 25 0 42 19 0 44 0 0 22 0 rplo 304 (Chloroflexi) 0 67 0 0 23 135 0 0 0 0 0 80 18 0 0 79 0 0 0 rplo 305 (Firmicutes) 0 0 0 14 0 13 0 0 0 0 42 0 16 0 18 34 0 36 21 rplo 306 (Thermotogae) 0 0 60 0 0 0 0 0 0 0 0 0 0 0 0 17 0 35 142 rplo 307 (Acidobacteria) 24 0 0 27 17 21 17 0 36 0 0 15 54 0 16 14 0 15 35 rplo 308 (unknown) 30 22 67 18 0 0 22 41 0 0 0 38 35 0 20 36 0 0 0 rplo 309 (unknown) 0 43 0 0 89 14 0 0 0 0 0 0 35 28 20 35 20 20 22 rplo 31 (Firmicutes) 132 0 0 0 0 0 1082 22 0 74 0 663 0 30 0 797 0 0 0 rplo 310 (Chloroflexi) 0 0 0 13 72 70 0 0 0 0 19 15 43 90 0 31 0 0 37 rplo 311 (Acidobacteria) 122 86 0 18 0 0 0 0 23 0 0 38 0 0 0 0 0 20 68 rplo 312 (Gemmatimonadetes) 0 67 46 18 23 0 47 0 0 0 0 0 0 0 146 0 0 0 0 rplo 313 (Firmicutes) 56 79 0 0 0 13 0 0 65 0 0 18 64 0 0 0 18 18 0 rplo 314 (Acidobacteria) 0 22 0 18 45 15 0 41 47 0 0 0 0 0 82 0 0 40 23 rplo 315 (Proteobacteria) 31 21 0 0 0 0 45 82 0 0 23 0 0 0 0 54 40 0 0 rplo 316 (Bacteroidetes) 33 21 0 19 96 0 0 22 0 0 25 0 0 0 0 0 0 0 0 rplo 317 (Gemmatimonadetes) 32 23 23 19 0 0 20 0 72 0 0 0 0 0 63 0 21 42 24 rplo 318 (Acidobacteria) 0 37 0 0 0 0 0 35 121 39 0 0 0 0 70 0 0 0 39 rplo 319 (Cyanobacteria) 0 22 0 0 0 0 0 0 0 96 0 62 0 0 22 0 20 0 25 rplo 32 (Firmicutes) 181 0 0 0 0 0 1177 30 0 0 0 704 0 163 0 499 0 0 0 rplo 320 (Actinobacteria) 0 0 0 58 0 16 0 22 0 0 25 0 0 0 0 0 0 43 75 rplo 321 (Firmicutes) 0 42 23 51 45 0 0 21 24 0 47 0 0 0 41 0 0 0 0 rplo 322 (Actinobacteria) 30 42 0 33 21 0 21 40 23 22 0 18 51 0 20 18 0 0 0 rplo 323 (Acidobacteria) 0 0 0 0 22 0 0 41 0 0 0 0 0 84 20 19 0 20 44 rplo 324 (Proteobacteria) 34 24 0 40 0 64 25 46 26 0 26 0 19 0 23 21 0 0 0 rplo 325 (Planctomycetes) 28 0 66 0 0 0 0 0 44 0 0 18 52 0 0 0 20 0 0 rplo 326 (Actinobacteria) 0 23 0 0 24 0 0 0 0 0 0 0 58 0 22 20 0 65 25 rplo 327 (Proteobacteria) 0 0 0 20 0 0 0 23 52 0 0 0 0 0 45 0 0 66 100 rplo 328 (Chloroflexi) 0 36 0 77 19 0 19 0 0 40 20 0 15 0 0 16 0 17 20 rplo 329 (Bacteroidetes) 0 23 0 38 71 0 0 0 0 0 0 0 0 0 43 0 0 0 71 rplo 33 (Bacteroidetes) 0 46 143 19 214 0 594 88 0 24 174 143 38 30 86 141 450 0 24 rplo 330 (Chloroflexi) 0 0 0 14 0 23 0 17 57 0 57 31 29 22 16 15 16 16 0 rplo 331 (Bacteroidetes) 0 139 24 19 0 0 0 0 25 25 50 0 0 0 0 0 0 0 47 rplo 332 (Cyanobacteria) 0 0 24 0 0 0 0 0 0 49 25 0 0 0 0 0 0 21 49 rplo 333 (Firmicutes) 0 20 0 34 0 0 0 39 22 22 22 0 0 26 0 0 19 19 0 rplo 334 (Actinobacteria) 0 47 25 0 24 0 0 0 0 48 0 21 0 0 0 41 0 0 0 rplo 335 (Actinobacteria) 0 42 22 52 0 0 0 0 0 0 23 38 87 27 0 0 0 39 0 rplo 336 (Proteobacteria) 28 0 40 0 0 0 0 0 0 20 42 0 0 0 0 0 18 36 0 rplo 337 (unknown) 0 42 44 0 0 0 0 0 23 67 0 19 17 0 0 19 0 0 0 rplo 338 (Actinobacteria) 0 23 0 19 0 0 24 0 0 0 0 0 19 0 44 0 0 43 25 rplo 339 (Bacteroidetes) 0 0 72 57 0 0 0 0 0 0 0 0 0 0 22 0 0 0 0 rplo 34 (Actinobacteria) 0 161 48 56 312 125 24 65 102 49 25 187 303 150 44 163 0 43 49 rplo 340 (unknown) 0 58 0 0 0 0 0 40 23 0 0 0 0 0 0 0 0 19 45 rplo 341 (Actinobacteria) 0 23 0 0 93 75 0 0 0 0 0 20 56 0 0 0 0 21 0 rplo 342 (Chloroflexi) 72 0 0 0 0 51 0 0 27 0 0 22 41 64 0 22 0 0 0 rplo 343 (Acidobacteria) 0 0 22 0 0 0 0 0 0 0 0 0 0 0 40 37 0 0 0 rplo 344 (Proteobacteria) 0 0 22 0 0 29 0 0 0 0 47 0 0 0 0 0 38 40 0 rplo 345 (Actinobacteria) 0 0 41 0 0 14 22 0 0 44 0 19 0 0 20 0 0 0 43 rplo 346 (Chloroflexi) 0 24 0 0 0 62 25 23 0 0 0 21 19 30 44 21 0 0 0 rplo 347 (Firmicutes) 0 0 22 0 0 0 0 0 0 0 0 19 0 0 0 0 0 250 0 rplo 348 (Cyanobacteria) 0 0 0 16 0 0 0 0 22 22 111 0 0 0 0 0 0 0 0 rplo 349 (Acidobacteria) 0 0 23 18 45 15 23 0 0 0 24 0 0 28 41 19 61 0 0 rplo 35 (Proteobacteria) 84 141 82 116 21 0 42 116 154 0 44 18 50 78 95 35 0 130 64 rplo 350 (Proteobacteria) 92 0 0 0 22 14 0 21 24 0 23 17 17 27 0 19 20 20 0 rplo 351 (Acidobacteria) 31 0 0 54 0 0 0 0 47 0 0 0 0 0 0 0 20 101 0 rplo 352 (Bacteroidetes) 66 19 48 38 24 0 24 22 0 0 0 20 0 0 22 0 0 0 0 rplo 353 (Firmicutes) 0 0 0 35 0 0 0 64 0 0 24 0 0 0 146 0 0 0 0 rplo 354 (Cyanobacteria) 0 0 23 0 0 0 0 0 0 24 0 0 0 0 0 0 0 0 24 rplo 355 (Verrucomicrobia) 0 0 37 15 125 0 0 51 0 0 0 0 0 0 16 16 0 0 19 rplo 356 (Proteobacteria) 0 0 26 0 0 0 26 24 55 0 0 22 20 0 0 0 0 0 53 rplo 357 (Cyanobacteria) 0 0 23 0 23 0 23 42 0 0 0 0 0 0 0 0 0 0 0 rplo 358 (Firmicutes) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 349 0 0 0 rplo 359 (Actinobacteria) 0 17 0 0 34 69 0 16 19 0 0 0 70 0 16 30 0 0 0 rplo 36 (Actinobacteria) 327 63 22 155 194 125 87 40 114 44 45 112 119 106 59 73 0 115 89 rplo 360 (Firmicutes) 0 0 0 0 32 31 0 0 0 0 0 28 38 40 0 0 0 72 33 rplo 361 (Firmicutes) 33 0 0 0 24 0 0 0 50 0 0 20 0 111 22 20 0 0 0 rplo 362 (unknown) 0 15 0 0 93 20 0 0 0 0 16 0 49 19 0 77 0 0 0 rplo 363 (Proteobacteria) 0 0 41 0 20 0 0 0 0 62 61 0 0 25 0 0 18 18 0 rplo 364 (Firmicutes) 0 23 24 57 0 31 0 0 25 0 23 18 19 0 0 0 0 0 0 rplo 365 (Armatimonadetes) 29 0 0 17 86 0 0 20 0 0 0 0 17 0 39 0 0 19 0 rplo 366 (Firmicutes) 0 0 0 0 23 30 0 0 0 0 0 40 92 58 0 0 0 0 0 rplo 367 (unknown) 0 0 0 0 44 28 0 0 0 0 22 19 17 0 0 0 0 0 22 rplo 368 (Verrucomicrobia) 0 0 0 17 0 28 0 0 0 22 91 19 17 0 0 0 0 55 89 rplo 369 (Chloroflexi) 17 35 0 9 12 16 0 11 0 0 13 0 78 15 0 10 22 11 0 rplo 37 (Proteobacteria) 212 127 66 175 44 28 66 101 162 198 229 56 87 27 0 19 0 194 135 rplo 370 (Chloroflexi) 49 15 0 0 18 12 0 33 0 0 0 0 85 22 0 45 0 0 0 rplo 371 (Proteobacteria) 29 21 22 70 22 0 0 0 0 22 0 38 35 0 0 0 0 0 0 rplo 372 (Bacteroidetes) 0 0 24 38 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 rplo 373 (Proteobacteria) 0 0 22 18 44 28 0 0 23 0 0 0 0 27 0 0 20 20 45 rplo 374 (Proteobacteria) 0 0 0 0 0 0 0 0 0 0 0 0 0 333 0 0 0 0 0 rplo 375 (Actinobacteria) 0 0 22 0 43 84 0 0 23 0 0 19 34 107 0 0 0 0 0 rplo 376 (Proteobacteria) 0 0 28 23 0 0 0 0 0 0 29 0 0 0 26 0 0 0 0 rplo 377 (Chloroflexi) 0 23 0 0 23 44 0 0 49 0 0 20 75 29 0 0 0 0 0 rplo 378 (unknown) 0 29 0 47 0 0 27 0 0 91 0 0 0 0 0 0 0 0 60 rplo 379 (Cyanobacteria) 0 0 23 0 0 0 0 0 98 0 0 0 0 0 0 0 0 0 0 rplo 38 (Actinobacteria) 145 122 125 33 63 109 21 58 111 0 88 72 117 78 38 53 19 56 108 rplo 380 (Actinobacteria) 0 0 0 0 46 45 0 21 49 24 0 20 18 0 0 20 0 0 0 rplo 381 (Bacteroidetes) 33 0 24 0 24 0 0 0 25 0 50 0 0 0 0 0 0 21 24 rplo 382 (Cyanobacteria) 0 0 73 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 rplo 383 (Actinobacteria) 0 0 23 17 46 30 23 0 0 24 0 0 18 0 0 0 0 0 24 rplo 384 (Bacteroidetes) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 0 0 0 28 rplo 385 (Chlorobi) 32 0 0 0 0 0 0 21 70 0 48 0 34 0 0 0 0 19 0 rplo 386 (Actinobacteria) 0 0 0 0 47 62 0 0 0 0 0 0 19 30 0 40 0 0 0 rplo 387 (Bacteroidetes) 33 0 0 0 0 15 0 22 0 46 50 0 19 0 22 41 0 0 0 rplo 388 (Verrucomicrobia) 67 0 0 19 0 16 0 0 0 0 25 21 19 0 22 20 0 0 25 rplo 389 (Armatimonadetes) 0 0 21 19 0 0 0 0 0 0 25 0 0 0 44 21 0 0 25 rplo 39 (Actinobacteria) 59 167 0 0 300 163 86 40 91 176 0 111 68 107 78 73 77 38 44 rplo 390 (Actinobacteria) 0 40 21 17 21 27 0 38 22 21 0 0 16 0 0 18 0 0 0 rplo 391 (Thermotogae) 0 0 18 0 0 0 0 0 0 0 0 0 0 0 16 0 0 16 37 rplo 392 (Firmicutes) 0 0 0 0 23 0 0 0 0 23 0 0 0 0 21 19 0 20 23 rplo 393 (Actinobacteria) 0 20 0 16 82 53 0 0 0 0 0 0 15 0 0 69 0 0 0 rplo 394 (Bacteroidetes) 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 241 0 0 0 rplo 395 (Bacteroidetes) 0 0 24 19 0 0 0 0 0 72 22 0 19 0 0 0 21 0 0 rplo 396 (Chloroflexi) 0 18 0 0 36 12 18 0 19 0 19 47 13 45 0 15 0 0 0 rplo 397 (Proteobacteria) 0 0 0 75 0 0 0 0 0 0 49 0 0 0 0 0 0 83 0 rplo 398 (Chloroflexi) 0 0 0 0 45 14 45 21 47 0 0 38 35 0 0 0 0 20 0 rplo 399 (Proteobacteria) 0 0 0 0 68 0 50 46 0 0 0 0 0 0 0 42 0 0 0 rplo 4 (Firmicutes) 1808 0 0 0 1307 16 658 0 1305 25 1092 3161 0 2260 0 1151 831 0 0 rplo 40 (Acidobacteria) 32 44 92 91 23 0 65 84 121 23 164 39 55 85 187 58 121 61 231 rplo 400 (Proteobacteria) 0 22 0 0 0 0 23 63 0 0 0 0 0 0 62 0 0 0 0 rplo 401 (Aquificae) 0 23 24 0 0 0 48 0 0 24 25 20 0 0 0 0 0 21 0 rplo 402 (Proteobacteria) 60 0 0 0 0 0 0 0 0 0 0 0 18 0 0 0 20 79 0 rplo 403 (Bacteroidetes) 66 0 0 0 0 0 0 0 0 0 0 0 19 0 22 0 0 21 47 rplo 404 (Cyanobacteria) 0 0 0 36 0 0 0 0 0 0 0 0 0 0 20 0 0 42 0 rplo 405 (Actinobacteria) 0 0 0 19 48 47 0 22 26 0 0 21 39 0 0 0 0 0 0 rplo 406 (Proteobacteria) 0 0 0 0 0 0 0 0 62 0 0 0 93 73 0 0 0 0 0 rplo 407 (Acidobacteria) 74 0 53 0 0 34 53 0 0 0 0 0 0 0 0 0 0 0 55 rplo 408 (Deinococcus-Thermus) 30 0 44 35 0 0 0 0 0 0 0 19 17 0 20 17 0 0 22 rplo 409 (Gemmatimonadetes) 0 0 0 0 0 0 0 0 0 0 0 0 0 46 0 28 0 0 0 rplo 41 (Proteobacteria) 60 62 110 70 109 14 66 221 139 0 69 56 52 54 119 260 217 78 67 rplo 410 (Actinobacteria) 0 17 0 0 17 23 0 32 0 0 0 31 57 0 0 15 16 0 18 rplo 411 (Firmicutes) 0 43 44 18 0 0 0 0 23 0 23 19 18 0 0 0 20 0 0 rplo 412 (Acidobacteria) 31 0 0 18 0 0 0 21 0 0 0 19 0 28 41 19 0 20 21 rplo 413 (Bacteroidetes) 0 23 0 0 0 15 0 0 0 0 25 20 19 0 0 0 0 21 0 rplo 414 (Chloroflexi) 24 18 0 0 18 0 0 17 19 0 19 44 14 0 0 0 0 32 0 rplo 415 (Verrucomicrobia) 0 0 48 0 0 0 0 0 0 0 0 0 19 0 0 0 0 43 0 rplo 416 (Firmicutes) 0 0 0 0 0 0 0 0 0 0 249 0 0 0 0 0 0 0 0 rplo 417 (Acidobacteria) 31 0 0 36 0 0 0 0 24 0 0 0 0 112 0 0 0 0 0 rplo 418 (Bacteroidetes) 0 23 0 57 0 0 24 0 0 0 25 20 0 0 22 20 0 0 0 rplo 419 (Bacteroidetes) 0 0 117 0 0 0 0 0 0 0 0 0 0 0 18 0 0 0 0 rplo 42 (Acidobacteria) 122 64 111 35 44 0 132 184 23 68 23 38 18 54 141 131 80 79 68 rplo 420 (unknown) 0 0 0 0 22 43 0 0 24 0 0 0 0 0 0 0 0 20 46 rplo 421 (Chloroflexi) 0 0 0 0 0 0 0 21 0 0 0 19 18 28 0 57 0 0 46 rplo 422 (Chloroflexi) 0 0 0 0 0 0 0 16 0 0 0 15 28 0 16 15 0 0 0 rplo 423 (Chloroflexi) 0 56 0 0 0 0 0 27 0 0 0 0 46 0 0 0 0 0 0 rplo 424 (Acidobacteria) 0 0 0 20 0 16 0 0 0 0 0 0 59 0 0 0 0 44 0 rplo 425 (Chloroflexi) 41 0 30 0 30 0 0 0 0 0 0 0 0 0 0 25 0 0 0 rplo 426 (Firmicutes) 0 0 0 16 0 0 0 0 25 98 0 21 0 0 0 0 43 0 0 rplo 427 (unknown) 0 21 0 0 22 0 44 40 0 0 0 0 0 0 40 19 0 0 0 rplo 428 (Acidobacteria) 0 0 0 35 0 0 0 0 0 0 0 0 17 0 0 18 0 0 45 rplo 429 (Bacteroidetes) 0 0 0 0 0 0 24 0 0 0 23 0 19 0 0 0 21 63 0 rplo 43 (Proteobacteria) 0 157 41 81 40 13 20 74 64 21 85 35 32 101 129 0 109 108 21 rplo 430 (Proteobacteria) 0 0 0 0 0 14 0 0 23 22 0 0 35 0 40 0 0 0 0 rplo 431 (Thermobaculum) 0 20 0 17 21 27 0 0 0 0 0 0 33 0 0 35 19 0 0 rplo 432 (Actinobacteria) 0 0 0 0 0 0 51 0 0 0 0 0 43 0 0 39 0 0 0 rplo 433 (Proteobacteria) 0 0 0 0 0 0 223 0 0 0 0 0 0 0 0 0 0 0 0 rplo 434 (Firmicutes) 0 19 0 0 0 0 20 0 0 0 0 34 0 0 18 0 0 71 41 rplo 435 (Actinobacteria) 32 22 0 0 21 0 0 0 0 0 0 0 18 0 0 79 0 0 0 rplo 436 (Proteobacteria) 0 0 0 0 0 0 0 0 0 82 110 0 0 0 0 0 24 0 0 rplo 437 (Bacteroidetes) 0 0 0 37 47 0 0 0 0 21 0 0 0 0 21 20 21 0 0 rplo 438 (Proteobacteria) 0 24 75 0 25 0 0 0 26 0 0 0 0 0 0 0 45 0 0 rplo 439 (Actinobacteria) 0 0 0 0 24 47 0 0 26 0 0 0 58 30 0 0 0 0 0 rplo 44 (Actinobacteria) 33 137 142 113 140 46 24 65 125 24 25 0 130 29 43 140 85 167 48 rplo 440 (Candidatus Roizmanbacteria) 0 0 0 0 0 0 0 0 0 0 0 0 210 0 0 0 0 0 0 rplo 441 (Proteobacteria) 22 0 0 0 0 24 0 0 58 0 0 0 15 45 0 15 0 0 0 rplo 442 (Actinobacteria) 0 0 0 0 40 39 0 0 0 0 0 0 16 0 0 0 0 0 0 rplo 443 (Firmicutes) 0 0 0 34 0 0 0 0 0 0 0 0 0 27 0 0 0 0 0 rplo 444 (Chloroflexi) 0 0 0 18 22 0 0 0 0 0 0 19 35 55 0 19 20 0 0 rplo 445 (Verrucomicrobia) 33 23 0 19 0 0 0 0 0 0 0 62 0 0 0 0 0 0 0 rplo 446 (Acidobacteria) 0 0 0 0 23 0 0 21 0 0 0 0 34 0 0 0 0 0 0 rplo 447 (Chloroflexi) 0 0 22 0 0 28 0 40 22 22 0 0 0 0 0 0 0 0 0 rplo 448 (Bacteroidetes) 0 27 28 0 0 0 0 0 30 0 0 0 0 0 0 0 77 0 0 rplo 449 (Proteobacteria) 0 21 0 0 0 0 22 0 23 22 23 0 0 0 0 0 0 19 0 rplo 45 (Proteobacteria) 60 127 66 35 87 57 44 121 69 22 46 91 68 162 59 184 20 0 112 rplo 450 (unknown) 0 0 0 0 22 71 0 0 22 0 0 19 17 0 0 18 0 19 0 rplo 451 (Acidobacteria) 0 0 0 19 0 15 0 22 25 0 0 0 19 0 0 0 0 0 0 rplo 452 (Bacteroidetes) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 rplo 453 (Actinobacteria) 0 0 0 0 0 43 0 0 23 0 0 0 52 0 0 0 0 19 0 rplo 454 (unknown) 0 0 0 0 22 14 0 0 0 0 0 0 0 0 0 54 0 40 0 rplo 455 (Gemmatimonadetes) 0 0 22 17 0 0 0 0 0 0 68 0 0 0 0 0 0 0 22 rplo 456 (Gemmatimonadetes) 0 0 0 17 0 0 0 0 0 0 24 19 0 0 0 0 20 0 23 rplo 457 (Proteobacteria) 0 0 0 0 0 0 0 0 50 0 0 0 0 0 0 0 0 42 0 rplo 458 (Chloroflexi) 0 0 0 15 0 0 0 0 20 0 0 17 31 24 35 0 0 0 0 rplo 459 (Proteobacteria) 0 0 0 0 0 21 0 0 0 0 0 28 26 0 0 27 58 0 0 rplo 46 (Proteobacteria) 84 20 81 259 40 13 41 37 64 62 170 87 161 50 111 0 55 144 83 rplo 460 (Bacteroidetes) 0 0 0 0 24 31 0 0 0 0 0 0 38 0 0 20 0 21 24 rplo 461 (Bacteroidetes) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 124 0 rplo 462 (Chloroflexi) 0 0 0 0 18 59 0 0 0 0 0 16 0 0 0 0 0 0 0 rplo 463 (Chloroflexi) 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 rplo 464 (Proteobacteria) 90 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 0 rplo 465 (Cyanobacteria) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 106 0 rplo 466 (Proteobacteria) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 0 rplo 47 (Proteobacteria) 111 78 60 96 20 0 20 0 63 41 331 121 48 50 18 17 180 51 102 rplo 48 (Actinobacteria) 117 21 63 183 42 27 21 78 90 87 111 73 151 132 96 54 19 131 65 rplo 49 (Gemmatimonadetes) 147 103 43 34 64 41 62 78 157 22 200 91 84 79 76 90 77 57 86 rplo 5 (Firmicutes) 2916 0 0 0 751 0 317 0 948 0 584 60 0 1538 0 740 0 0 0 rplo 50 (Actinobacteria) 60 42 0 103 0 14 0 0 251 88 518 112 51 0 39 18 19 58 22 rplo 51 (Proteobacteria) 0 40 42 0 41 27 1421 38 0 42 43 0 33 0 151 0 37 37 43 rplo 52 (Cyanobacteria) 0 44 68 36 0 0 0 21 72 0 71 0 0 0 0 0 0 400 46 rplo 53 (Proteobacteria) 66 136 95 76 95 154 191 0 50 49 149 41 38 59 0 81 0 85 0 rplo 54 (Proteobacteria) 120 21 44 52 43 70 66 80 67 0 68 37 50 27 99 111 59 39 109 rplo 55 (Proteobacteria) 170 0 98 59 48 47 49 134 104 101 103 42 0 61 67 42 133 66 49 rplo 56 (Proteobacteria) 29 102 63 17 42 41 64 78 67 170 44 0 17 0 0 36 133 38 130 rplo 57 (Proteobacteria) 111 117 101 113 20 0 20 37 106 41 127 17 64 75 18 17 127 36 165 rplo 58 (Proteobacteria) 90 105 22 208 65 14 22 80 67 175 45 19 17 54 59 37 78 39 45 rplo 59 (Actinobacteria) 87 20 21 152 21 41 63 136 89 64 175 18 84 26 19 35 0 132 65 rplo 6 (Actinobacteria) 165 77 40 286 80 674 160 110 85 1382 0 583 2113 198 108 203 36 106 82 rplo 61 (Proteobacteria) 97 34 18 84 17 11 18 16 92 124 128 45 358 65 32 0 95 78 54 rplo 62 (Proteobacteria) 150 106 45 89 0 116 68 83 166 46 94 116 71 56 20 76 101 60 92 rplo 63 (Actinobacteria) 195 23 0 0 0 0 0 0 200 0 0 0 38 0 21 20 0 751 0 rplo 64 (Cyanobacteria) 0 25 78 18 26 17 52 119 0 0 0 0 0 0 253 0 0 0 0 rplo 65 (Actinobacteria) 64 135 70 18 185 132 46 43 49 22 118 58 129 86 20 59 63 0 143 rplo 66 (Bacteroidetes) 70 0 26 122 51 66 0 71 215 415 0 41 39 0 46 22 0 0 157 rplo 67 (Proteobacteria) 99 24 48 157 0 0 0 272 208 76 51 127 20 61 112 42 67 64 0 rplo 68 (Firmicutes) 0 0 0 0 0 0 165 0 0 0 0 1444 0 68 0 93 0 0 0 rplo 69 (Proteobacteria) 31 44 68 18 45 58 45 104 95 0 71 58 90 28 102 303 41 20 0 rplo 70 (Proteobacteria) 61 21 44 141 0 14 66 61 93 90 46 208 0 55 20 19 19 137 90 rplo 71 (Actinobacteria) 50 87 18 129 107 46 36 149 19 18 38 77 100 0 65 136 0 16 37 rplo 72 (Firmicutes) 0 0 0 0 0 0 72 0 0 0 0 83 39 0 0 429 1062 0 0 rplo 73 (Bacteroidetes) 0 24 0 0 0 0 0 0 0 604 26 0 0 0 0 0 200 63 0 rplo 74 (Proteobacteria) 56 0 61 32 0 509 0 130 21 21 85 35 0 48 18 17 73 90 21 rplo 75 (Acidobacteria) 31 22 0 0 0 0 225 352 0 0 0 0 36 56 691 38 0 0 23 rplo 76 (Firmicutes) 0 0 0 0 0 0 0 0 0 50 0 0 0 147 0 0 1461 0 0 rplo 77 (Proteobacteria) 26 110 76 45 0 24 0 17 80 19 355 97 0 47 17 48 153 50 77 rplo 78 (Actinobacteria) 60 84 88 17 44 28 0 20 23 22 46 38 103 0 79 19 0 117 132 rplo 79 (Actinobacteria) 64 202 0 0 116 180 0 43 98 0 0 120 55 230 21 98 0 62 0 rplo 8 (Acidobacteria) 125 117 1081 72 60 294 61 84 383 0 32 206 168 38 275 126 0 2338 93 rplo 80 (Actinobacteria) 0 102 63 67 42 162 63 19 111 21 22 108 150 0 19 159 19 19 43 rplo 81 (unknown) 28 59 41 16 20 13 0 19 86 0 42 0 32 50 37 119 37 718 20 rplo 82 (Actinobacteria) 235 47 49 39 0 63 0 90 0 0 125 63 19 0 44 0 22 22 0 rplo 83 (Acidobacteria) 0 64 178 53 0 0 0 41 0 68 23 0 0 0 60 19 20 138 68 rplo 84 (Proteobacteria) 58 41 83 83 84 68 21 58 89 43 42 54 34 52 19 72 73 0 83 rplo 85 (Cyanobacteria) 0 0 70 0 0 0 0 0 0 0 0 0 0 0 21 0 0 617 0 rplo 86 (Proteobacteria) 28 20 20 64 20 13 20 19 106 268 63 17 48 50 55 0 18 18 41 rplo 87 (Proteobacteria) 0 41 63 34 42 40 63 58 109 43 44 18 83 79 96 36 76 113 65 rplo 88 (Firmicutes) 0 0 0 0 0 0 0 0 0 0 0 1500 0 0 0 0 0 0 0 rplo 89 (Bacteroidetes) 33 0 24 226 167 0 0 0 76 0 50 0 0 0 196 0 0 64 197 rplo 9 (Proteobacteria) 86 320 206 181 186 27 83 440 109 106 87 71 99 438 415 280 37 275 170 rplo 90 (Proteobacteria) 0 128 155 67 43 29 0 59 46 0 23 19 0 27 98 36 20 59 23 rplo 91 (Actinobacteria) 34 118 73 96 73 16 73 45 51 50 0 42 19 0 22 82 0 22 125 rplo 92 (Proteobacteria) 120 0 65 52 43 56 22 100 23 0 46 0 35 54 78 37 98 39 45 rplo 93 (Proteobacteria) 30 63 44 17 43 14 0 20 229 66 228 94 17 27 40 0 0 58 134 rplo 94 (unknown) 30 106 22 70 42 56 131 141 69 0 0 75 35 0 59 74 20 18 45 rplo 95 (Proteobacteria) 34 0 75 20 49 32 672 23 52 25 52 0 20 0 113 41 22 22 25 rplo 96 (unknown) 62 65 0 71 267 216 0 41 141 23 23 19 53 28 61 38 20 20 69 rplo 97 (Firmicutes) 152 0 0 0 0 0 435 0 0 112 0 235 0 132 0 362 0 0 0 rplo 98 (Actinobacteria) 24 50 0 25 170 220 51 29 72 0 18 59 203 21 0 129 15 15 0 rplo 99 (Cyanobacteria) 66 68 48 38 0 0 24 0 51 98 200 62 0 0 0 0 65 43 25 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/soils/microbes.tsv.sha256000066400000000000000000000001171520735541300315410ustar00rootroot0000000000000069f018c4a907d8548d21bdca9f73f7392bd54ccf0c8d1e738ff13185912a025f microbes.tsv scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/vare_rda_biplot_from_vegan.csv000066400000000000000000000033071520735541300331200ustar00rootroot00000000000000"RDA1","RDA2","RDA3","RDA4","RDA5","RDA6" "N",-0.374511707101879,0.279141775958977,-0.113262015862774,0.0291604466058106,-0.00381582755421537,0.0424863529236013 "P",-0.0788656563464819,-0.472632677542489,-0.0651887823463463,-0.0513067111958969,-0.0626909273376982,-0.00110889996021487 "K",-0.201461843066864,-0.381022612236819,-0.0251340010064783,0.0598912302377648,-0.0959494580327501,-0.0171435160344495 "Ca",-0.235421762881426,-0.415332965840277,0.0156842418693768,-0.0304645964200932,-0.0193425068993681,0.0307301502356508 "Mg",-0.258006129373729,-0.351149186002239,0.0198906297437563,-0.0603137013913655,-0.062802597760679,-0.0064268580320466 "S",0.110423012128282,-0.327827092711384,0.0273964647390279,0.0128822505351356,-0.131322241122595,-0.0161293619330301 "Al",0.622794612442927,0.223726801861401,-0.0774758868765043,0.0133921880598012,-0.0975006207689577,-0.0375948643932326 "Fe",0.538546175590668,0.252910024481109,-0.128206469586592,-0.00122698444588682,-0.0370755089903238,-0.0301862362243074 "Mn",-0.53181428311314,-0.387983018850023,-0.0369812755533416,0.028195676589086,0.0139082147231988,-0.010802072964436 "Zn",-0.189256949293269,-0.321619350980509,-0.0296694989201669,-0.0516020128947528,-0.100811021654885,0.0631043516762351 "Mo",0.0825455222136991,0.105558125042181,0.0444498655868074,-0.013149221839644,-0.129692423248781,-0.0279316900201847 "Baresoil",-0.584523854747717,0.0175764195098462,0.249347810472773,-0.0433132869859633,-0.0219797931388049,-0.0115874538804695 "Humdepth",-0.528249123722545,-0.348123615804582,0.139315047829644,0.0255225451725187,-0.00106320905614231,-0.0391497797327695 "pH",0.485293188422395,0.145941294383608,-0.144156426452744,-0.0680477191104673,0.017879488382429,0.028893908227529 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/vare_rda_constraints_from_vegan.csv000066400000000000000000000053541520735541300342020ustar00rootroot00000000000000"RDA1","RDA2","RDA3","RDA4","RDA5","RDA6" "18",-1.94540324526486,1.35619693843417,0.703939871143434,-0.273017904915305,0.430167111988789,-0.48660737084197 "15",0.141838231206451,-0.829758087643046,0.173141397491083,-0.0156875043824831,0.0136619216795438,-0.408528269058105 "24",-1.43248927964489,-0.54425653333442,-0.306236786536847,-0.979876701440387,-0.731804914672737,0.321212796309646 "27",-2.80798626244276,-1.82787096826377,-0.915538594054524,-0.10113999881667,0.165371808326588,-0.272482540524553 "23",-1.32166553682556,-0.588228004227234,0.79516884314486,-0.100577754862558,0.312457897704011,-0.162743742127975 "19",-0.525042043686618,-1.34621680872358,0.603541116383373,-0.350740907365001,-0.10559130781142,-0.222556236954221 "22",-1.6970783295333,-0.00841159288220255,0.350604237250266,1.06598318305367,0.329079144655896,0.216254552790676 "16",-1.02617620074073,1.16222063659566,0.276350890008082,0.508682734424414,0.110047918087361,0.229152398042771 "28",-2.81539141691889,-2.87330917539132,-1.4254501909053,0.278788463109637,-0.0715764088962425,0.0383464804901234 "13",-0.56793332760884,0.978469150560303,-0.0102101554071479,1.15471089199982,-0.893165637481288,-0.179567246057747 "14",0.123702948593575,-0.279611839517576,0.857490241180555,0.288565237262797,-0.0962678825382923,0.386913110717701 "20",-0.889372681662648,-0.172942499513205,1.20564982758643,-0.384640065668512,-0.329123722655264,0.40082339960546 "25",-1.25287864077043,-0.862513780744027,-0.209243578856711,-0.147987569283365,0.455041774670079,0.00853808793906775 "7",0.836595155865492,3.14264733462783,-0.552874592253968,-0.309850905157291,0.156192445586091,-0.608122966237938 "5",-1.03320113118202,2.71896020759242,-1.00737497595167,-0.217427871913452,0.20643732081764,0.836448050498042 "6",0.261185057560469,1.0060253513401,-0.216278932347733,0.191968910927705,0.205015879586198,-0.202134531184565 "3",2.0251525928349,0.838200337107143,-0.890575565259071,-0.221678715814349,0.0510468211613041,-0.177568585625492 "4",0.304232766529097,1.06258912371904,-0.346193660344245,-0.0766334378573768,-0.817513397231726,-0.386397972418401 "2",3.8927613225141,-0.214065093420055,-0.421802196571513,0.0641876476814947,0.0763106413897994,0.455052488664798 "9",4.49140913947389,-1.24888267627012,0.716772000188893,0.0761750818231677,-0.0738996910301799,-0.0631749857609068 "12",1.22495554555309,-0.302280829527584,0.345679740337339,0.568930336840597,0.189701343000118,-0.0324863384828909 "10",3.8583881810421,-1.69957275456566,-0.30263129042612,-0.244748829936061,0.13487999114786,-0.0898553381384633 "11",1.48652810795229,-0.077774982953761,-0.500871495640448,-0.0865802555774825,0.246429358792296,0.261018343487596 "21",-1.33213095284393,0.610386547000902,1.07694384984097,-0.687404064133014,0.0371015837235694,0.138466414867343 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/vare_rda_eigvals_from_vegan.csv000066400000000000000000000010501520735541300332520ustar00rootroot00000000000000"x" "RDA1",820.104210710977 "RDA2",399.28474306136 "RDA3",102.561678139934 "RDA4",47.6316939665912 "RDA5",26.8382218045756 "RDA6",24.0480874768085 "RDA7",19.0643755874934 "RDA8",10.1669953619382 "RDA9",4.42878597644952 "RDA10",2.27203567668609 "RDA11",1.5353256650454 "RDA12",0.925527669731662 "RDA13",0.715510164471211 "RDA14",0.311861227346199 "PC1",186.191732488638 "PC2",88.4641941356934 "PC3",38.1882774045901 "PC4",18.4020745527723 "PC5",12.8394334391492 "PC6",10.551972429882 "PC7",5.51940479440112 "PC8",4.52105681330178 "PC9",1.09220616230999 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/vare_rda_propexpl_from_vegan.csv000066400000000000000000000005261520735541300335000ustar00rootroot00000000000000"x" "RDA1",0.44921 "RDA2",0.21871 "RDA3",0.05618 "RDA4",0.02609 "RDA5",0.0147 "RDA6",0.01317 "RDA7",0.01044 "RDA8",0.00557 "RDA9",0.00243 "RDA10",0.00124 "RDA11",0.00084 "RDA12",0.00051 "RDA13",0.00039 "RDA14",0.00017 "PC1",0.10199 "PC2",0.04846 "PC3",0.02092 "PC4",0.01008 "PC5",0.00703 "PC6",0.00578 "PC7",0.00302 "PC8",0.00248 "PC9",6e-04 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/vare_rda_sites_from_vegan.csv000066400000000000000000000053561520735541300327640ustar00rootroot00000000000000"RDA1","RDA2","RDA3","RDA4","RDA5","RDA6" "18",-0.725180341740889,1.32304743578072,0.536735571384135,-0.39768741234737,0.233754657058704,-0.561316258413971 "15",-1.93529754271851,-0.766164733988552,-0.273348455556674,0.390736768713259,0.0177606558885408,-0.169349974419623 "24",-1.81353741848749,-0.970245493575222,-0.0374209701843787,-0.872025399986459,-0.789699995023076,0.493449832483016 "27",-2.33510121426858,-2.13826666457436,-0.985623024073038,-0.145132098331367,0.583205282290284,-0.313874765445323 "23",-1.41317135065566,-0.1177033753694,0.766850507492372,-0.501223786646214,0.401907289450705,-0.278342018223195 "19",-0.0575697569183517,-0.821681038610851,0.206606955195771,-0.182752763015451,-0.130617003087652,-0.244482299124097 "22",-1.84743663448918,-0.634524208599755,0.802635258758064,1.66371301803693,0.685511124204389,0.639715037447257 "16",-1.50266104356433,0.202771968994942,0.343618483724244,1.10930062109802,0.325281324139236,0.681725828414122 "28",-2.88734608017533,-2.8973024244037,-1.64121631383754,0.0549907838317931,-0.142301693170976,-0.220948911082786 "13",-0.216157151714584,1.4060194258153,-0.0466575925757337,0.799855819301344,-1.0946823960693,-0.416466375199514 "14",-1.20534703154947,0.418683116827144,1.3597696084289,0.513403260974061,-0.776146451075579,0.28265707897677 "20",-1.22313804827702,0.22033914415852,0.616483727488239,-0.430533982693562,-0.160467249867719,0.177868834807142 "25",-1.77661950967122,-0.825044182048943,0.361003390009536,-0.107164123598687,-0.148676491945586,0.237023999173496 "7",-0.678511723219697,2.89559652272012,-0.547824463296798,-0.235728554420752,0.165597328353004,-0.710828270319712 "5",-0.487596122987802,3.18852947968577,-1.41737309023615,-0.422865480680066,0.253132238647981,0.727755243784674 "6",-0.0243012352784496,2.50490917263305,-0.360296245554514,-0.0702120962654929,0.0909124415194519,-0.936567113418783 "3",2.80827785868984,0.455143313772751,-0.613132585731335,0.00451399728070384,0.0225377341796233,0.258222116793284 "4",0.963314315837764,0.84576412181764,-0.066781701948557,0.0887932875301872,-0.700374853742517,-0.116961021287795 "2",3.99917033463046,-0.482115663123818,-0.454217823172445,-0.0665100409733586,0.266626884554847,0.381471681881249 "9",4.36400742802721,-1.736534702518,0.405907326952517,-0.0368661340355564,0.0832432640777509,-0.136409557861582 "12",3.03564636652536,-0.827580749873411,0.102186438399489,-0.171696624931404,0.288862751499394,-0.0309441831749462 "10",4.48325878385124,-1.33798990585379,0.229165601207832,0.0330101538089084,0.11942053442103,-0.0256496604321859 "11",0.817850354912684,0.213402853934839,-0.88018842594682,-0.127740767588512,0.086264341451757,0.125072918411801 "21",-0.342553236757974,-0.119053413601001,1.59311782307288,-0.890178445060962,0.318948282245704,0.157177836230702 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/vare_rda_species_from_vegan.csv000066400000000000000000000126071520735541300332650ustar00rootroot00000000000000"RDA1","RDA2","RDA3","RDA4","RDA5","RDA6" "Callvulg",-0.226273730144909,0.693800038650831,0.338218922488515,6.67088802095297,-7.21896322666435,-0.779857240089175 "Empenigr",-0.238899164401276,-0.631301245805765,2.60480743178841,-1.55330692069587,5.61834172767659,-2.20332774370264 "Rhodtome",-0.17142303305129,-0.0654248519425288,0.185549293155117,-0.217665325317797,0.322372965190883,0.0853972606062568 "Vaccmyrt",-1.09428970452297,-1.23571473681342,-0.940502994941989,0.218545935413684,0.657932487096486,0.837134528181776 "Vaccviti",-0.162201143615588,-1.38843399510951,4.76670106297968,-3.77408048235071,5.43168646890937,-2.79074856413388 "Pinusylv",0.0369862347468032,-0.0238456401875,0.0478650516626519,0.0763337150565842,0.0639052442139435,0.0825651654004402 "Descflex",-0.147574817002457,-0.167722789057799,-0.27793799775637,0.0344024518701595,0.288412456210204,-0.299444024885208 "Betupube",-0.00425890842744653,0.00301626626963975,0.023633639469157,-0.0287099967609287,0.008285119424158,0.0144904045944417 "Vacculig",-0.00617517925092514,0.586329345378346,-0.424343136945186,-0.267181701965188,0.899708457788426,-2.10623236401806 "Diphcomp",-0.0193891282832212,0.0848409769290093,0.0886832373456673,-0.125925466951118,0.302273874297346,-0.479439541135259 "Dicrsp",-0.584662822766602,-0.554381688683121,-0.76501102421792,-4.62706081016606,-3.61916960506924,3.01061244828378 "Dicrfusc",-1.28109719764106,0.103470480549643,2.67976193286694,10.2747384364546,6.22585244770623,4.2615539016749 "Dicrpoly",-0.0527337929905133,-0.00090081484981692,0.221880786125258,-0.683724436531866,-0.345681664095091,0.394727452877124 "Hylosple",-0.522637153726359,-0.918065056916316,-1.62638166301937,0.295469951213255,-0.0135580694056817,-0.334186893959993 "Pleuschr",-5.50878076569324,-8.8886978183423,-8.37459165372512,1.41924983472743,1.57437830231155,-2.29995876920357 "Polypili",0.000632590233791712,0.0102615110484168,-0.0159075161955889,-0.018096445320708,0.031500746301268,0.0786160198924179 "Polyjuni",-0.12340157237603,-0.171463376700033,0.0728402465477063,-0.446428512892154,1.22564488464636,-0.0622820830373054 "Polycomm",-0.0103528544039597,-0.00993084811579174,0.0216129382454449,-0.0489313397543105,0.0229047076022281,-0.011862059575897 "Pohlnuta",0.00970583089927341,-0.018349828466775,0.0527104964420516,-0.0571342448078905,-0.020164288017587,0.0418920415970837 "Ptilcili",-0.159464075362797,0.10006784787628,1.05136092046601,-1.2908733474554,0.33545113524691,0.404450545385935 "Barbhatc",-0.0466890634925938,0.0382613228575175,0.276662021782069,-0.373812730583367,0.0219595583756616,0.138309628865647 "Cladarbu",-0.416846189233898,5.31641622718912,-0.930205800774416,2.81811168990724,-0.554814634260353,-10.4595841461921 "Cladrang",1.29592368856734,8.36409911724857,-8.96098432978265,-0.969135607167511,4.09265280992759,3.38742710658704 "Cladstel",12.9993162839447,-4.60357024457592,-2.45511784152944,1.63313879335609,0.811266886992104,-1.04082533645468 "Cladunci",-0.139665650154971,-0.200952644353237,2.01080043905276,0.112942947894908,-2.80683515519727,4.71782772042145 "Cladcocc",0.0140440451319673,0.0120659834096241,0.00879969627655237,0.0504748534035485,0.0439656404180021,0.0166991824468257 "Cladcorn",-0.0171421483490833,-0.0318891939249154,0.0851353096044147,-0.0712924559399341,0.247868762857871,-0.0985092679795218 "Cladgrac",-0.014291516155796,0.0207918228721213,0.0478283724736316,-0.0599532273483947,-0.0244356304170684,-0.0119910291097221 "Cladfimb",0.00461344583647884,0.00630264328769572,0.0615207799865213,0.0490653816228835,0.0599873314053227,-0.0755759161054924 "Cladcris",-0.00958758815249997,-0.0295565794036219,0.243789050898361,0.130760954099805,0.0658965803482975,-0.231256073310349 "Cladchlo",0.0187488915228099,-0.00928114626307454,0.0285623673752264,-0.0587116824010891,-0.00900681474395845,-0.0135004250016505 "Cladbotr",-0.00660812579632819,0.00125815962588916,0.0253237320949088,-0.0237179502029999,-0.0196117567973272,0.00711937194787014 "Cladamau",-0.00136745162702629,0.00480205186223178,-5.41472575201337e-05,-0.00654936924677102,0.0139883033489021,-0.00709922460632658 "Cladsp",0.00992686294206172,-0.00373711675547203,0.0158895402267187,0.0215400183589053,-0.0307100869494753,-0.0192034215304599 "Cetreric",0.00737025600460116,0.00496065101699207,0.0252933788488033,-0.0709698476248171,-0.295480904895558,0.15202504773877 "Cetrisla",0.0168171538461378,-0.00955018178379953,0.064611315838899,-0.0807719773413275,0.00582196133393798,0.0526210231757201 "Flavniva",0.0758578271997996,0.25014312602853,-0.305377423821448,-0.181549650656412,-2.66963212661746,-1.46522484606432 "Nepharct",-0.061783073424573,-0.0763675615694388,-0.106412306793283,-0.155075628433089,0.7492348600785,-0.0401582665032977 "Stersp",-0.110643408686953,0.675909058528055,-0.847389185822014,-0.584961498181175,0.824411871660421,2.59432085604071 "Peltapht",-0.00433509537730518,-0.00792550879085397,0.00628297623647816,-0.0102203772879107,0.0660236532497632,-0.00750239908018623 "Icmaeric",-0.001603267524481,0.00986109695445918,-0.00702150205760372,0.0019342085956161,0.010326600170813,0.0330394729689556 "Cladcerv",0.00116172819790058,0.000657287114342154,-0.00296642933466362,-0.000910130438819726,-0.00978815736822817,-0.00203673989458803 "Claddefo",-0.0471902500908342,-0.0319259473091497,0.429430035290953,0.0132849661625517,-0.0669419782195097,0.146247353879757 "Cladphyl",0.0267818636482677,-0.0171932277857551,0.00184089496193447,-0.00923266735869818,0.0239144294161575,0.0171690545470201 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/varechem.csv000066400000000000000000000033521520735541300273530ustar00rootroot00000000000000"ID","N","P","K","Ca","Mg","S","Al","Fe","Mn","Zn","Mo","Baresoil","Humdepth","pH" "18",19.8,42.1,139.9,519.4,90,32.3,39,40.9,58.1,4.5,0.3,43.9,2.2,2.7 "15",13.4,39.1,167.3,356.7,70.7,35.2,88.1,39,52.4,5.4,0.3,23.6,2.2,2.8 "24",20.2,67.7,207.1,973.3,209.1,58.1,138,35.4,32.1,16.8,0.8,21.2,2,3 "27",20.6,60.8,233.7,834,127.2,40.7,15.4,4.4,132,10.7,0.2,18.7,2.9,2.8 "23",23.8,54.5,180.6,777,125.8,39.5,24.2,3,50.1,6.6,0.3,46,3,2.7 "19",22.8,40.9,171.4,691.8,151.4,40.8,104.8,17.6,43.6,9.1,0.4,40.5,3.8,2.7 "22",26.6,36.7,171.4,738.6,94.9,33.8,20.7,2.5,77.6,7.4,0.3,23,2.8,2.8 "16",24.2,31,138.2,394.6,45.3,27.1,74.2,9.8,24.4,5.2,0.3,29.8,2,2.8 "28",29.8,73.5,260,748.6,105.3,42.5,17.9,2.4,106.6,9.3,0.3,17.6,3,2.8 "13",28.1,40.5,313.8,540.7,118.9,60.2,329.7,109.9,61.7,9.1,0.5,29.9,2.2,2.8 "14",21.8,38.1,146.8,512.2,75,36.6,92.3,4.6,29,8.1,0.5,33.3,2.7,2.7 "20",26.2,61.9,202.2,741.2,86.3,48.6,124.3,23.6,94.5,10.2,0.6,56.9,2.5,2.9 "25",22.8,50.6,151.7,648,64.8,30.2,12.1,2.3,122.9,8.1,0.2,23.7,2.6,2.9 "7",30.5,24.6,78.7,188.5,55.5,25.3,294.9,123.8,10.1,3,0.4,18.6,1.7,3.1 "5",33.1,22.7,43.6,240.3,25.7,14.9,39,8.4,26.8,8.4,0.2,8.1,1,3.1 "6",19.1,26.4,61.1,259.1,37,21.4,155.1,81.4,20.6,4,0.6,5.8,1.9,3 "3",31.1,32.3,73.7,219,52.5,25.5,304.6,204.4,14.2,2.6,0.5,3.6,1.8,3.3 "4",18,64.9,224.5,517.6,59.7,52.9,435.1,101.2,38,9.5,1.1,21.3,1.8,2.9 "2",22.3,47.4,165.9,436.1,64.3,42.3,316.5,200.1,28.2,7.2,0.3,0.01,1.5,2.9 "9",15,48.4,127.4,499.6,75.1,46.9,227.1,32.2,35.1,8.9,0.7,6.07,2.2,3 "12",16,32.7,126.4,471.4,61.3,31.1,108.8,9.5,26.4,6,0.4,11.2,2.2,2.9 "10",14.3,62.8,215.2,709.7,102.5,48.6,168.2,32,46.9,8.7,0.05,4.4,1.2,3.2 "11",16.7,55.8,205.3,1169.7,126.3,35.9,253.6,96.4,25.1,8.2,0.05,7.6,1.1,3.6 "21",21,26.5,104.4,484.8,74.4,22.2,35.8,5.9,27.5,5.3,0.2,56,2.5,3 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/data/varespec.csv000066400000000000000000000105731520735541300273740ustar00rootroot00000000000000"ID","Callvulg","Empenigr","Rhodtome","Vaccmyrt","Vaccviti","Pinusylv","Descflex","Betupube","Vacculig","Diphcomp","Dicrsp","Dicrfusc","Dicrpoly","Hylosple","Pleuschr","Polypili","Polyjuni","Polycomm","Pohlnuta","Ptilcili","Barbhatc","Cladarbu","Cladrang","Cladstel","Cladunci","Cladcocc","Cladcorn","Cladgrac","Cladfimb","Cladcris","Cladchlo","Cladbotr","Cladamau","Cladsp","Cetreric","Cetrisla","Flavniva","Nepharct","Stersp","Peltapht","Icmaeric","Cladcerv","Claddefo","Cladphyl" "18",0.55,11.13,0,0,17.8,0.07,0,0,1.6,2.07,0,1.62,0,0,4.67,0.02,0.13,0,0.13,0.12,0,21.73,21.47,3.5,0.3,0.18,0.23,0.25,0.25,0.23,0,0,0.08,0.02,0.02,0,0.12,0.02,0.62,0.02,0,0,0.25,0 "15",0.67,0.17,0,0.35,12.13,0.12,0,0,0,0,0.33,10.92,0.02,0,37.75,0.02,0.23,0,0.03,0.02,0,12.05,8.13,0.18,2.65,0.13,0.18,0.23,0.25,1.23,0,0,0,0,0.15,0.03,0,0,0.85,0,0,0,1,0 "24",0.1,1.55,0,0,13.47,0.25,0,0,0,0,23.43,0,1.68,0,32.92,0,0.23,0,0.32,0.03,0,3.58,5.52,0.07,8.93,0,0.2,0.48,0,0.07,0.1,0.02,0,0,0.78,0.12,0,0,0.03,0,0,0,0.33,0 "27",0,15.13,2.42,5.92,15.97,0,3.7,0,1.12,0,0,3.63,0,6.7,58.07,0,0,0.13,0.02,0.08,0.08,1.42,7.63,2.55,0.15,0,0.38,0.12,0.1,0.03,0,0.02,0,0.02,0,0,0,0,0,0.07,0,0,0.15,0 "23",0,12.68,0,0,23.73,0.03,0,0,0,0,0,3.42,0.02,0,19.42,0.02,2.12,0,0.17,1.8,0.02,9.08,9.22,0.05,0.73,0.08,1.42,0.5,0.17,1.78,0.05,0.05,0,0,0,0,0.02,0,1.58,0.33,0,0,1.97,0 "19",0,8.92,0,2.42,10.28,0.12,0.02,0,0,0,0,0.32,0.02,0,21.03,0.02,1.58,0.18,0.07,0.27,0.02,7.23,4.95,22.08,0.25,0.1,0.25,0.18,0.1,0.12,0.05,0.02,0,0,0,0,0.02,0,0.28,0,0,0,0.37,0 "22",4.73,5.12,1.55,6.05,12.4,0.1,0.78,0.02,2,0,0.03,37.07,0,0,26.38,0,0,0,0.1,0.03,0,6.1,3.6,0.23,2.38,0.17,0.13,0.18,0.2,0.2,0.02,0,0,0.02,0.02,0,0,0,0,0,0,0,0.15,0 "16",4.47,7.33,0,2.15,4.33,0.1,0,0,0,0,1.02,25.8,0.23,0,18.98,0,0.02,0,0.13,0.1,0,7.13,14.03,0.02,0.82,0.15,0.05,0.22,0.22,0.17,0,0,0,0.02,0.18,0.08,0,0,0.03,0,0.07,0,0.67,0 "28",0,1.63,0.35,18.27,7.13,0.05,0.4,0,0.2,0,0.3,0.52,0.2,9.97,70.03,0,0.08,0,0.07,0.03,0,0.17,0.87,0,0.05,0.02,0.03,0.07,0.1,0.02,0,0.02,0,0,0,0.02,0,0,0.02,0,0,0,0.08,0 "13",24.13,1.9,0.07,0.22,5.3,0.12,0,0,0,0.07,0.02,2.5,0,0,5.52,0,0.02,0,0.03,0.25,0.07,23.07,23.67,11.9,0.95,0.17,0.05,0.23,0.18,0.57,0.02,0.07,0,0.07,0.18,0.02,0,0,0.03,0.02,0,0,0.47,0 "14",3.75,5.65,0,0.08,5.3,0.1,0,0,0,0,0,11.32,0,0,7.75,0,0.3,0.02,0.07,0,0,17.45,1.32,0.12,23.68,0.22,0.5,0.15,0.23,0.97,0,0,0,0,0.68,0.02,0,0,0.33,0,0.02,0,1.57,0.05 "20",0.02,6.45,0,0,14.13,0.07,0,0,0.47,0,0.85,1.87,0.08,1.35,13.73,0.07,0.05,0,0.12,0,0,6.8,11.22,0.05,4.75,0.03,0.12,0.22,0.18,0.07,0,0.02,0,0.02,0.15,0,0,0.02,0,0,0,0,1.2,0 "25",0,6.93,0,0,10.6,0.02,0.1,0.02,0.05,0.07,14.02,10.82,0,0.02,28.77,0,6.98,0.13,0,0.22,0,6,2.25,0,0.8,0.12,0.57,0.17,0.15,0.07,0,0,0,0.02,0.03,0.02,0,4.87,0.1,0.07,0,0.02,0.05,0 "7",0,5.3,0,0,8.2,0,0.05,0,8.1,0.28,0,0.45,0.03,0,0.1,0,0.25,0,0.03,0,0,35,42.5,0.28,0.35,0.08,0.2,0.25,0.18,0.13,0.08,0,0,0,0.05,0,0.23,0.2,0.93,0,0.03,0,0.1,0 "5",0,0.13,0,0,2.75,0.03,0,0,0,0,0,0.25,0.03,0,0.03,0.18,0.65,0,0,0,0,18.5,59,0.98,0.28,0.23,0.23,0.23,0.1,0.05,0,0,0.03,0,0.18,0,0.28,0,10.28,0,0.1,0,0.25,0 "6",0.3,5.75,0,0,10.5,0.1,0,0,0,0,0,0.85,0,0,0.05,0.03,0.08,0,0,0.08,0,39,37.5,11.3,3.45,0.18,0.2,0.25,0.25,0.23,0.03,0,0,0.03,0.35,0,0.08,0,0.03,0,0,0,0.28,0 "3",0.03,3.65,0,0,4.43,0,0,0,1.65,0.5,0,0.55,0,0,0.05,0,0,0,0.03,0.03,0,8.8,29.5,55.6,0.25,0.08,0.25,0.25,0.15,0.1,0.03,0,0.03,0,0.05,0,0.15,0.15,0.28,0,0,0,0.08,0 "4",3.4,0.63,0,0,1.98,0.05,0.05,0,0.03,0,0,0.2,0,0,1.53,0,0.1,0,0.05,0,0,15.73,20.03,28.2,0.73,0.1,0.15,0.13,0.1,0.15,0,0,0,0.05,0.28,0.05,10.03,0,0.95,0,0,0.05,0.08,0 "2",0.05,9.3,0,0,8.5,0.03,0,0,0,0,0,0.03,0,0,0.75,0,0.03,0,0,0.03,0,0.48,24.5,75,0.2,0,0.03,0.03,0.05,0.03,0.03,0,0,0,0,0,0,0,0,0,0,0.03,0.03,0 "9",0,3.47,0,0.25,20.5,0.25,0,0,0,0.25,0,0.38,0.25,0,4.07,0,0.25,0,0.25,0.25,0,0.46,4,84.3,0.25,0.25,0.25,0.25,0.25,0.25,0.25,0,0,0.25,0.25,0.25,0.67,0,0,0,0,0,0.25,0.25 "12",0.25,11.5,0,0,15.8,1.2,0,0,0,0,0.25,0.25,0,0,6,0,0,0,0.25,0,0,3.6,14.6,63.3,1.3,0,0.25,0.25,0.25,0.25,0,0,0,0,0,0.25,0,0,0,0,0,0,0.25,0 "10",0.25,11,0,0,11.9,0.25,0,0,0,0,0,0.25,0.25,0,0.67,0,0.25,0,0.25,0,0,1.3,8.7,84.3,0.25,0.25,0.25,0,0.25,0.25,0.25,0,0,0,0.25,0.25,0.25,0,0.25,0,0,0,0.25,0.25 "11",2.37,0.67,0,0,12.9,0.8,0,0,0,0,0,0.25,0.25,0,17.7,0.25,0.25,0,0.25,0.67,0,9.67,29.8,31.8,2.53,0.25,0.25,0.25,0,0.25,0,0,0,0,0,0.25,0,0,0.93,0.25,0,0,0,0.25 "21",0,16,4,15,25,0.25,0.5,0.25,0,0,0.25,0.25,3,0,2,0,0.25,0.25,0.25,10,3,0.7,4.7,10.9,0.25,0,0.05,0.25,0.25,0.25,0.25,0.25,0,0,0,0.67,0,0,0,0,0,0,0.4,0 scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/test_canonical_correspondence_analysis.py000066400000000000000000000151041520735541300344650ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np import numpy.testing as npt import pandas as pd from unittest import TestCase, main from skbio import OrdinationResults from skbio.stats.ordination import cca from skbio.util import get_data_path, assert_ordination_results_equal from skbio._config import set_config class TestCCAErrors(TestCase): def setUp(self): """Data from table 11.3 in Legendre & Legendre 1998.""" self.Y = pd.DataFrame(np.loadtxt(get_data_path('example3_Y'))) self.X = pd.DataFrame(np.loadtxt(get_data_path('example3_X'))) def test_shape(self): X, Y = self.X, self.Y with npt.assert_raises(ValueError): cca(Y, X[:-1]) def test_Y_values(self): X, Y = self.X, self.Y Y.iloc[0, 0] = -1 with npt.assert_raises(ValueError): cca(Y, X) Y.iloc[0] = 0 with npt.assert_raises(ValueError): cca(Y, X) def test_scaling(self): X, Y = self.X, self.Y with npt.assert_raises(NotImplementedError): cca(Y, X, 3) def test_all_zero_row(self): X, Y = pd.DataFrame(np.zeros((3, 3))), pd.DataFrame(np.zeros((3, 3))) with npt.assert_raises(ValueError): cca(X, Y) class TestCCAResults1(TestCase): def setUp(self): """Data from table 11.3 in Legendre & Legendre 1998 (p. 590). Loaded results as computed with vegan 2.0-8 and compared with table 11.5 if also there.""" self.feature_ids = ['Feature0', 'Feature1', 'Feature2', 'Feature3', 'Feature4', 'Feature5', 'Feature6', 'Feature7', 'Feature8'] self.sample_ids = ['Sample0', 'Sample1', 'Sample2', 'Sample3', 'Sample4', 'Sample5', 'Sample6', 'Sample7', 'Sample8', 'Sample9'] self.env_ids = ['Constraint0', 'Constraint1', 'Constraint2'] self.pc_ids = ['CCA1', 'CCA2', 'CCA3', 'CCA4', 'CCA5', 'CCA6', 'CCA7', 'CCA8', 'CCA9'] self.Y = pd.DataFrame( np.loadtxt(get_data_path('example3_Y')), columns=self.feature_ids, index=self.sample_ids) self.X = pd.DataFrame( np.loadtxt(get_data_path('example3_X'))[:, :-1], columns=self.env_ids, index=self.sample_ids ) set_config("table_output", "pandas") def test_scaling1(self): scores = cca(self.Y, self.X, scaling=1) # Load data as computed with vegan 2.0-8 vegan_features = pd.DataFrame( np.loadtxt(get_data_path( 'example3_species_scaling1_from_vegan')), index=self.feature_ids, columns=self.pc_ids) vegan_samples = pd.DataFrame( np.loadtxt(get_data_path( 'example3_site_scaling1_from_vegan')), index=self.sample_ids, columns=self.pc_ids) sample_constraints = pd.DataFrame( np.loadtxt(get_data_path( 'example3_sample_constraints_scaling1')), index=self.sample_ids, columns=self.pc_ids) mat = np.loadtxt(get_data_path( 'example3_biplot_scaling1')) cropped_pcs = self.pc_ids[:mat.shape[1]] biplot_scores = pd.DataFrame(mat, index=self.env_ids, columns=cropped_pcs) proportion_explained = pd.Series([0.466911, 0.238327, 0.100548, 0.104937, 0.044805, 0.029747, 0.012631, 0.001562, 0.000532], index=self.pc_ids) eigvals = pd.Series([0.366136, 0.186888, 0.078847, 0.082288, 0.035135, 0.023327, 0.009905, 0.001225, 0.000417], index=self.pc_ids) exp = OrdinationResults( 'CCA', 'Canonical Correspondence Analysis', samples=vegan_samples, features=vegan_features, sample_constraints=sample_constraints, biplot_scores=biplot_scores, proportion_explained=proportion_explained, eigvals=eigvals) assert_ordination_results_equal(scores, exp, decimal=6) def test_scaling2(self): scores = cca(self.Y, self.X, scaling=2) # Load data as computed with vegan 2.0-8 vegan_features = pd.DataFrame( np.loadtxt(get_data_path( 'example3_species_scaling2_from_vegan')), index=self.feature_ids, columns=self.pc_ids) vegan_samples = pd.DataFrame( np.loadtxt(get_data_path( 'example3_site_scaling2_from_vegan')), index=self.sample_ids, columns=self.pc_ids) sample_constraints = pd.DataFrame( np.loadtxt(get_data_path( 'example3_sample_constraints_scaling2')), index=self.sample_ids, columns=self.pc_ids) mat = np.loadtxt(get_data_path( 'example3_biplot_scaling2')) cropped_pc_ids = self.pc_ids[:mat.shape[1]] biplot_scores = pd.DataFrame(mat, index=self.env_ids, columns=cropped_pc_ids) proportion_explained = pd.Series([0.466911, 0.238327, 0.100548, 0.104937, 0.044805, 0.029747, 0.012631, 0.001562, 0.000532], index=self.pc_ids) eigvals = pd.Series([0.366136, 0.186888, 0.078847, 0.082288, 0.035135, 0.023327, 0.009905, 0.001225, 0.000417], index=self.pc_ids) exp = OrdinationResults( 'CCA', 'Canonical Correspondence Analysis', samples=vegan_samples, features=vegan_features, sample_constraints=sample_constraints, biplot_scores=biplot_scores, proportion_explained=proportion_explained, eigvals=eigvals) assert_ordination_results_equal(scores, exp, decimal=6) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/test_correspondence_analysis.py000066400000000000000000000371231520735541300324630ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main, skipIf import numpy as np import numpy.testing as npt import pandas as pd from scipy.spatial.distance import pdist from skbio._config import set_config from skbio import OrdinationResults from skbio.stats.ordination import ca from skbio.util import ( get_package, get_data_path, assert_ordination_results_equal, assert_ordination_results_equal_np, ) pl = get_package("polars", raise_error=False) def chi_square_distance(data_table, between_rows=True): """Computes the chi-square distance between two rows or columns of input. It is a measure that has no upper limit, and it excludes double-zeros. Parameters ---------- data_table : 2D array_like An array_like object of shape (n, p). The input must be a frequency table (so that the sum of all cells equals 1, and all values are non-negative). between_rows : bool (defaults to True) Indicates whether distance is computed between rows (default) or columns. Returns ------- Y : ndarray Returns a condensed distance matrix. For each i and j (where i= 0).all()) # Column names should match Y features self.assertListEqual(list(Y_pred.columns), list(self.Y.columns)) def test_predict_match(self): """Check if results match the old ranks path.""" model = MMvec(n_components=2, max_iter=50, seed=42).fit(self.X, self.Y) X_test = self.X.iloc[:5].to_numpy() obs = model._predict(X_test) X_props = X_test / X_test.sum(axis=1, keepdims=True) probs = softmax(model.ranks_.to_numpy(), validate=False) exp = X_props @ probs npt.assert_allclose(obs, exp) def test_score(self): """Test score method returns valid Q-squared value.""" # Split data into train and test sets X_train, X_test = self.X.iloc[:40], self.X.iloc[40:] Y_train, Y_test = self.Y.iloc[:40], self.Y.iloc[40:] model = MMvec(n_components=2, max_iter=100, seed=42).fit(X_train, Y_train) q2 = model.score(X_test, Y_test) self.assertIsInstance(q2, float) # Q^2 should be <= 1.0 (perfect prediction) self.assertLessEqual(q2, 1.0) def test_predict_zero_sample_raises(self): """Predict with zero-count sample should raise ValueError.""" model = MMvec( n_components=2, max_iter=10, seed=42 ).fit(self.X, self.Y) # Create X with a zero row X_ = self.X.iloc[:3].copy() X_.iloc[0, :] = 0 with self.assertRaises(ValueError) as ctx: model.predict(X_) self.assertIn("all-zero counts", str(ctx.exception)) def test_mmvec_result_str(self): """Test string representation of MMvecResult.""" result = mmvec(self.X, self.Y, dimensions=2, max_iter=10, seed=42) obs = str(result) self.assertIn("MMvecResult", obs) self.assertIn("Features", obs) self.assertIn("Targets", obs) self.assertIn("Components", obs) self.assertIn("Iterations", obs) def test_predict_numpy_array(self): """Test predict with numpy array input (not DataFrame).""" model = MMvec(n_components=2, max_iter=50, seed=42).fit(self.X, self.Y) predictions = model.predict(self.X.to_numpy()[:5]) self.assertEqual(predictions.shape[0], 5) npt.assert_allclose(predictions.sum(axis=1), 1.0, rtol=1e-6) def test_score_numpy_array(self): """Test score with numpy array inputs (not DataFrames).""" X_train, X_test = self.X.iloc[:40], self.X.iloc[40:] Y_train, Y_test = self.Y.iloc[:40], self.Y.iloc[40:] model = MMvec(n_components=2, max_iter=100, seed=42).fit(X_train, Y_train) q2 = model.score(X_test.to_numpy(), Y_test.to_numpy()) self.assertIsInstance(q2, float) self.assertLessEqual(q2, 1.0) def test_score_zero_raises(self): """Score with zero-count Y sample should raise ValueError.""" model = MMvec(n_components=2, max_iter=100, seed=42).fit(self.X, self.Y) Y_ = self.Y.iloc[:5].copy() Y_.iloc[0, :] = 0 with self.assertRaises(ValueError) as ctx: model.score(self.X.iloc[:5], Y_) self.assertIn("all-zero counts", str(ctx.exception)) def test_check_is_fitted(self): """Should raise if fit has not been called.""" model = MMvec(n_components=2, max_iter=10, seed=42) with self.assertRaises(ValueError) as ctx: model._check_is_fitted() self.assertIn("not fitted", str(ctx.exception)) def test_str(self): """String representation of estimator should require fitted state.""" model = MMvec(n_components=2, max_iter=10, seed=42) model.fit(self.X, self.Y) obs = str(model) self.assertIn("MMvec", obs) self.assertIn("Features", obs) self.assertIn("Targets", obs) self.assertIn("Components", obs) self.assertIn("Iterations", obs) def test_get_params(self): """Estimator parameters should be returned as a dict.""" model = MMvec( n_components=4, optimizer="adam", max_iter=123, learning_rate=0.02, batch_size=11, x_prior_mean=1.5, x_prior_scale=0.8, y_prior_mean=-2.5, y_prior_scale=1.2, beta_1=0.8, beta_2=0.85, clipnorm=3.0, batch_norm="legacy", seed=7, verbose=True, output_format="numpy", ) obs = model.get_params() exp = { "n_components": 4, "optimizer": "adam", "max_iter": 123, "learning_rate": 0.02, "batch_size": 11, "x_prior_mean": 1.5, "x_prior_scale": 0.8, "y_prior_mean": -2.5, "y_prior_scale": 1.2, "beta_1": 0.8, "beta_2": 0.85, "clipnorm": 3.0, "batch_norm": "legacy", "seed": 7, "verbose": True, "output_format": "numpy", } self.assertDictEqual(obs, exp) def test_set_params(self): """set_params should update known parameters and reject unknown ones.""" model = MMvec(n_components=2, max_iter=10, seed=42) result = model.set_params(n_components=5, optimizer="adam", max_iter=20) self.assertIs(result, model) self.assertEqual(model.n_components, 5) self.assertEqual(model.optimizer, "adam") self.assertEqual(model.max_iter, 20) with self.assertRaises(ValueError) as ctx: model.set_params(not_a_real_param=1) self.assertIn("Invalid parameter", str(ctx.exception)) class TestMMvecValidation(unittest.TestCase): """Test input validation for MMvec.""" def setUp(self): """Create valid test data.""" self.X, self.Y, *_ = random_multimodal(8, 10, 50, seed=42) def test_mismatched_sample_counts(self): """Mismatched sample counts should raise.""" X = self.X.iloc[:40] # 40 samples Y = self.Y.iloc[:50] # 50 samples with self.assertRaises(ValueError) as ctx: mmvec(X, Y, max_iter=1) self.assertIn("same number of samples", str(ctx.exception)) def test_all_zero_columns(self): """Columns (features) with all zero counts should raise.""" X = self.X.copy() for i in (1, 2, 3): X.iloc[:, i] = 0 with self.assertRaises(ValueError) as ctx: mmvec(X, self.Y, max_iter=1) self.assertIn("X contains all-zero columns", str(ctx.exception)) Y = self.Y.copy() for i in (4, 5, 6): Y.iloc[:, i] = 0 with self.assertRaises(ValueError) as ctx: mmvec(self.X, Y, max_iter=1) self.assertIn("y contains all-zero columns", str(ctx.exception)) def test_all_zero_rows(self): """Rows (samples) with all zero counts should raise.""" X = self.X.copy() for i in (1, 2, 3): X.iloc[i, :] = 0 with self.assertRaises(ValueError) as ctx: mmvec(X, self.Y, max_iter=1) self.assertIn("X contains all-zero rows", str(ctx.exception)) Y = self.Y.copy() for i in (4, 5, 6): Y.iloc[i, :] = 0 with self.assertRaises(ValueError) as ctx: mmvec(self.X, Y, max_iter=1) self.assertIn("y contains all-zero rows", str(ctx.exception)) def test_prior_scales(self): """x_prior_scale and y_prior_scale must be positive.""" msg = "x_prior_scale must be positive" with self.assertRaises(ValueError) as ctx: mmvec(self.X, self.Y, x_prior_scale=0, max_iter=1) self.assertIn(msg, str(ctx.exception)) with self.assertRaises(ValueError) as ctx: mmvec(self.X, self.Y, x_prior_scale=-0.5, max_iter=1) self.assertIn(msg, str(ctx.exception)) msg = "y_prior_scale must be positive" with self.assertRaises(ValueError) as ctx: mmvec(self.X, self.Y, y_prior_scale=0, max_iter=1) self.assertIn(msg, str(ctx.exception)) with self.assertRaises(ValueError) as ctx: mmvec(self.X, self.Y, y_prior_scale=-0.5, max_iter=1) self.assertIn(msg, str(ctx.exception)) class TestMMvecInputTypes(unittest.TestCase): """Test different input types for MMvec.""" def test_sparse_pandas_input(self): """Test with sparse pandas DataFrame.""" X_dense, Y_dense, *_ = random_multimodal(8, 10, 50, seed=42) # Convert to sparse pandas DataFrame X_sparse = X_dense.astype(pd.SparseDtype("float64", 0)) Y_sparse = Y_dense.astype(pd.SparseDtype("float64", 0)) result = mmvec(X_sparse, Y_sparse, dimensions=2, max_iter=10, seed=42) # Should produce valid results self.assertEqual(result.ranks.shape, (8, 10)) npt.assert_allclose( result.ranks.to_numpy().mean(axis=1), 0, atol=1e-10 ) class TestMMvecParameterBehavior(unittest.TestCase): """Test parameter behavior for MMvec.""" def setUp(self): """Create test data.""" self.X, self.Y, *_ = random_multimodal(8, 10, 50, seed=42) def test_nonzero_prior_mean_affects_results(self): """Non-zero prior means should affect results.""" params = dict(dimensions=2, max_iter=50, seed=42) result_default = mmvec( self.X, self.Y, **params, x_prior_mean=0.0, y_prior_mean=0.0 ) result_nonzero = mmvec( self.X, self.Y, **params, x_prior_mean=5.0, y_prior_mean=5.0 ) # Results should differ self.assertFalse( np.allclose( result_default.x_embeddings.to_numpy(), result_nonzero.x_embeddings.to_numpy(), ) ) def test_verbose_output(self): """Verbose mode should produce output.""" # Capture stdout captured = io.StringIO() sys.stdout = captured try: mmvec( self.X, self.Y, dimensions=2, optimizer="adam", max_iter=5, verbose=True, seed=42, ) finally: sys.stdout = sys.__stdout__ output = captured.getvalue() self.assertIn("Epoch", output) self.assertIn("Loss", output) class TestMMvecResultVerification(unittest.TestCase): """Test output structure and properties.""" def setUp(self): """Create test data.""" self.X, self.Y, *_ = random_multimodal(8, 10, 50, seed=42) def test_index_columns_preserved(self): """Index and column names should be preserved from input.""" result = mmvec(self.X, self.Y, dimensions=2, max_iter=10, seed=42) # X IDs preserved pdt.assert_index_equal(result.x_embeddings.index, self.X.columns) pdt.assert_index_equal(result.ranks.index, self.X.columns) # Y IDs preserved pdt.assert_index_equal(result.y_embeddings.index, self.Y.columns) pdt.assert_index_equal(result.ranks.columns, self.Y.columns) def test_convergence_structure(self): """Convergence DataFrame should have correct structure.""" result = mmvec(self.X, self.Y, dimensions=2, max_iter=10, seed=42) self.assertTupleEqual(result.convergence.shape, (11,)) def test_loss_decreases(self): """Loss should generally decrease during training.""" result = mmvec( self.X, self.Y, dimensions=2, optimizer="adam", max_iter=100, seed=42 ) losses = result.convergence.to_numpy() # Compare first 10% average to last 10% average n = len(losses) early_loss = losses[: n // 10].mean() late_loss = losses[-n // 10 :].mean() self.assertLess(late_loss, early_loss) class TestMMvecLBFGS(unittest.TestCase): """Test L-BFGS optimizer for MMvec.""" def setUp(self): """Create test data.""" res = random_multimodal(8, 10, 50, 2, seed=42) self.X, self.Y = res[0], res[1] self.x_embed_true, self.y_embed_true = res[4], res[6] def test_lbfgs_produces_valid_results(self): """L-BFGS optimizer should produce valid results.""" result = mmvec(self.X, self.Y, 2, optimizer="lbfgs", max_iter=100, seed=42) # Check result type self.assertIsInstance(result, MMvecResult) # Check shapes self.assertEqual(result.x_embeddings.shape, (8, 3)) self.assertEqual(result.y_embeddings.shape, (10, 3)) self.assertEqual(result.ranks.shape, (8, 10)) # Ranks should be row-centered row_means = result.ranks.to_numpy().mean(axis=1) npt.assert_allclose(row_means, 0, atol=1e-10) def test_lbfgs_reproducibility(self): """L-BFGS should be deterministic with same seed.""" args = dict(dimensions=2, optimizer="lbfgs", max_iter=50, seed=123) res1 = mmvec(self.X, self.Y, **args) res2 = mmvec(self.X, self.Y, **args) pdt.assert_frame_equal(res1.ranks, res2.ranks, rtol=1e-10) def test_lbfgs_recovers_structure(self): """L-BFGS should recover embedding structure from synthetic data.""" # Use more data for better recovery res = random_multimodal( 8, 8, 150, 2, x_noise_std=2, x_total=1000, y_total=10000, seed=1 ) X, Y = res[0], res[1] x_embed_true = res[4] result = mmvec(X, Y, dimensions=2, optimizer="lbfgs", max_iter=500, seed=42) # Check correlation of pairwise distances x_r, _ = spearmanr( pdist(result.x_embeddings.to_numpy()[:, :-1]), pdist(x_embed_true) ) self.assertGreater(x_r, 0.3, f"X embedding correlation too low: {x_r}") def test_lbfgs_score_on_test_data(self): """L-BFGS model should produce reasonable Q-squared score on test data.""" # Split data X_train = self.X.iloc[:40] X_test = self.X.iloc[40:] Y_train = self.Y.iloc[:40] Y_test = self.Y.iloc[40:] model = MMvec( n_components=2, optimizer="lbfgs", max_iter=100, seed=42 ).fit(X_train, Y_train) # Compute Q^2 score on test data q2 = model.score(X_test, Y_test) # Q^2 should be a valid float self.assertIsInstance(q2, float) def test_lbfgs_verbose_output(self): """L-BFGS verbose mode should produce output.""" captured = io.StringIO() sys.stdout = captured try: mmvec( self.X, self.Y, dimensions=2, optimizer="lbfgs", max_iter=50, verbose=True, seed=42, ) finally: sys.stdout = sys.__stdout__ output = captured.getvalue() self.assertIn("Iteration", output) self.assertIn("Loss", output) def test_seed_generator(self): """seed as np.random.Generator should work.""" rng = np.random.default_rng(42) result = mmvec( self.X, self.Y, dimensions=2, optimizer="lbfgs", max_iter=50, seed=rng, ) self.assertIsInstance(result, MMvecResult) self.assertEqual(result.ranks.shape, (8, 10)) def test_numpy_array_inputs(self): """mmvec should accept numpy arrays (not just DataFrames).""" result = mmvec( self.X.to_numpy(), self.Y.to_numpy(), dimensions=2, optimizer="lbfgs", max_iter=50, seed=42, ) self.assertIsInstance(result, MMvecResult) self.assertEqual(result.ranks.shape, (8, 10)) def test_invalid_optimizer_raises(self): """Invalid optimizer should raise ValueError.""" with self.assertRaises(ValueError) as ctx: mmvec( self.X, self.Y, optimizer="invalid", max_iter=1, ) self.assertIn("Optimizer must be", str(ctx.exception)) class TestMMvecCaseStudies(unittest.TestCase): """Test MMvec on real-world case study datasets. These tests verify that the MMvec implementation can reproduce the biological findings from the original MMvec publication and example notebooks. """ def test_biocrust_wetting(self): """Co-occurrence of Cyanobacteria and known metabolites in wetup biocrust. This test reproduces the finding from the soils example notebook: the model should learn that Cyanobacteria (specifically rplo 1) co-occur with a known set of 13 metabolites associated with Microcoleus vaginatus, a desert crust cyanobacterium. """ # Load the biocrust wetting dataset subdir = os.path.join("data", "soils") microbes = pd.read_table( get_data_path("microbes.tsv", subdir), index_col=0 ).T metabolites = pd.read_table( get_data_path("metabolites.tsv", subdir), index_col=0 ).T # Fit the model with low latent dimension for faster testing result = MMvec( n_components=1, optimizer="lbfgs", max_iter=500, x_prior_scale=1.0, y_prior_scale=1.0, seed=42, ).fit(microbes, metabolites) # Define expected Cyanobacteria-associated metabolites expected_metabolites = [ "(3-methyladenine)", "7-methyladenine", "4-guanidinobutanoate", "uracil", "xanthine", "hypoxanthine", "(N6-acetyl-lysine)", "cytosine", "N-acetylornithine", "succinate", "adenosine", "guanine", "adenine", ] # Define Cyanobacteria taxon cyanobacteria_id = "rplo 1 (Cyanobacteria)" # Count how many of the expected metabolites have positive rank for # Cyanobacteria. ranks_cyanobacteria = result.ranks_.loc[cyanobacteria_id] positive_count = (ranks_cyanobacteria.loc[expected_metabolites] > 0).sum() # The original notebook expects all 13 metabolites to have positive ranks for # Cyanobacteria. We use a more lenient threshold (11) to account for # optimization variability. # self.assertEqual(positive_count, 13) self.assertGreaterEqual(positive_count, 11) # Check numerical values against expected outputs for reproducibility. # NOTE: Due to optimization variability and floating-point accumulation order # changes from computational optimizations, these values may not match exactly, # but should be close. # obs = result.score(microbes, metabolites) # exp = 0.217611 # (Linux) # self.assertAlmostEqual(obs, exp, places=4) @unittest.skip("Skipping a test that requires long runtime.") def test_cystic_fibrosis(self): """Co-occurrence of Pseudomonas and rhamnolipids in cystic fibrosis sputum. This test reproduces the finding from the example notebook: the model should learn that Pseudomonas microbes co-occur with rhamnolipids and other Pseudomonas-associated metabolites. Note: The actual data files are not kept in the codebase due to their sizes. To run this test, place the local data files in the expected directory. It is anticipated that the test will cost several to dozens of seconds. """ # Load the cystic fibrosis dataset subdir = os.path.join("data", "cf") microbes = pd.read_table( get_data_path("microbes.tsv", subdir), index_col=0 ).T metabolites = pd.read_table( get_data_path("metabolites.tsv", subdir), index_col=0 ).T microbe_meta = pd.read_table( get_data_path("microbe_meta.tsv", subdir), index_col=0 ) metabolite_meta = pd.read_table( get_data_path("metabolite_meta.tsv", subdir), index_col=0 ) # Find Pseudomonas microbes in the metadata (n=39) pseudomonas = microbe_meta[ microbe_meta["Taxon"].str.contains("Pseudomonas") ].index.tolist() # Find expert-annotated metabolites in the metadata (n=20) expert_metabolites = metabolite_meta[ metabolite_meta["expert_annotation"].notnull() ].index.tolist() # Fit the model with parameters similar to the original result = mmvec( microbes, metabolites, dimensions=3, optimizer="lbfgs", max_iter=500, x_prior_scale=1.0, y_prior_scale=1.0, seed=42, ) # For the first Pseudomonas taxon in the ranks table, count expert-annotated # metabolites with positive ranks. ranks_pseudomonas = result.ranks[result.ranks.index.isin(pseudomonas)] first_pseudomonas = ranks_pseudomonas.iloc[0] # The original analysis expects 19 out of 20 metabolites with positive ranks. # A slightly lower threshold (15) is used here for reproducibility. positive_count = (first_pseudomonas.loc[expert_metabolites] > 0).sum() self.assertEqual(positive_count, 19) self.assertGreaterEqual(positive_count, 15) if __name__ == "__main__": unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/test_ordination_results.py000066400000000000000000000730541520735541300315010ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import numpy as np import numpy.testing as npt import pandas as pd try: import matplotlib as mpl import matplotlib.pyplot as plt except ImportError: has_matplotlib = False else: has_matplotlib = True from skbio import OrdinationResults class TestOrdinationResults(unittest.TestCase): def setUp(self): # Define in-memory CA results to serialize and deserialize. eigvals = pd.Series([0.0961330159181, 0.0409418140138], ['CA1', 'CA2']) features = np.array([[0.408869425742, 0.0695518116298], [-0.1153860437, -0.299767683538], [-0.309967102571, 0.187391917117]]) samples = np.array([[-0.848956053187, 0.882764759014], [-0.220458650578, -1.34482000302], [1.66697179591, 0.470324389808]]) features_ids = ['Species1', 'Species2', 'Species3'] sample_ids = ['Site1', 'Site2', 'Site3'] samples_df = pd.DataFrame(samples, index=sample_ids, columns=['CA1', 'CA2']) features_df = pd.DataFrame(features, index=features_ids, columns=['CA1', 'CA2']) self.ordination_results = OrdinationResults( 'CA', 'Correspondence Analysis', eigvals=eigvals, samples=samples_df, features=features_df, feature_ids=features_ids, sample_ids=sample_ids) def test_str(self): exp = ("Ordination results:\n" "\tMethod: Correspondence Analysis (CA)\n" "\tEigvals: 2\n" "\tProportion explained: N/A\n" "\tFeatures: 3x2\n" "\tSamples: 3x2\n" "\tBiplot Scores: N/A\n" "\tSample constraints: N/A\n" "\tFeature IDs: 'Species1', 'Species2', 'Species3'\n" "\tSample IDs: 'Site1', 'Site2', 'Site3'") obs = str(self.ordination_results) self.assertEqual(obs, exp) # all optional attributes missing exp = ("Ordination results:\n" "\tMethod: Principal Coordinate Analysis (PCoA)\n" "\tEigvals: 1\n" "\tProportion explained: N/A\n" "\tFeatures: N/A\n" "\tSamples: 2x1\n" "\tBiplot Scores: N/A\n" "\tSample constraints: N/A\n" "\tFeature IDs: N/A\n" "\tSample IDs: 0, 1") samples_df = pd.DataFrame(np.array([[1], [2]])) obs = str(OrdinationResults('PCoA', 'Principal Coordinate Analysis', pd.Series(np.array([4.2])), samples_df)) self.assertEqual(obs.split('\n'), exp.split('\n')) def test_rename(self): ordi = self.ordination_results # Testing rename function when passing in a dictionary to mapper # `strict` is True # Should rename current elements to their corresponding new value rename_dict_samp = {'Site2': 'B', 'Site1': 'A', 'Site3': 'C'} rename_dict_feat = {'Species2': 'Y', 'Species1': 'X', 'Species3': 'Z'} ordi.rename(rename_dict_samp) self.assertListEqual(list(ordi.samples.index), ['A', 'B', 'C']) ordi.rename(rename_dict_feat, matrix='features') self.assertListEqual(list(ordi.features.index), ['X', 'Y', 'Z']) # Same test as above, except `strict` is False rename_dict_samp = {'A': '001', 'B': '010'} rename_dict_feat = {'X': 'abc', 'Y': 'def'} ordi.rename(rename_dict_samp, strict=False) self.assertEqual(list(ordi.samples.index), ['001', '010', 'C']) ordi.rename(rename_dict_feat, matrix='features', strict=False) self.assertEqual(list(ordi.features.index), ['abc', 'def', 'Z']) # Testing rename when `strict` is True and there are extra keys # Should throw a ValueError rename_dict_samp = {'001': 'he', '010': 'llo', 'D': 'hello'} rename_dict_feat = {'abc': 'go', 'def': 'od', 'W': 'bye'} errmsg = "The IDs in mapper do not include all IDs in the %s matrix." with self.assertRaisesRegex(ValueError, errmsg % "samples"): ordi.rename(rename_dict_samp) with self.assertRaisesRegex(ValueError, errmsg % "features"): ordi.rename(rename_dict_feat, matrix='features') # Testing rename when passing a lambda function into mapper # Should append '_0' to the previous elements in ordination_results lam = lambda x: x + '_0' ordi.rename(lam) self.assertEqual(list(ordi.samples.index), ['001_0', '010_0', 'C_0']) ordi.rename(lam, matrix='features') self.assertEqual(list(ordi.features.index), ['abc_0', 'def_0', 'Z_0']) # Testing rename when features is None errmsg = "`features` were not provided on the construction of this object." ordi.features = None with self.assertRaisesRegex(ValueError, errmsg): ordi.rename(rename_dict_feat, matrix='features') @unittest.skipUnless(has_matplotlib, "Matplotlib not available.") class TestOrdinationResultsPlotting(unittest.TestCase): def setUp(self): # DataFrame for testing plot method. Has a categorical column with a # mix of numbers and strings. Has a numeric column with a mix of ints, # floats, and strings that can be converted to floats. Has a numeric # column with missing data (np.nan). self.df = pd.DataFrame([['foo', '42', 10], [22, 0, 8], [22, -4.2, np.nan], ['foo', '42.19', 11]], index=['A', 'B', 'C', 'D'], columns=['categorical', 'numeric', 'nancolumn']) # Minimal ordination results for easier testing of plotting method. # Paired with df above. eigvals = np.array([0.50, 0.25, 0.25]) samples = np.array([[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6]]) samples_df = pd.DataFrame(samples, ['A', 'B', 'C', 'D'], ['PC1', 'PC2', 'PC3']) self.min_ord_results = OrdinationResults( 'PCoA', 'Principal Coordinate Analysis', eigvals, samples_df) self.min_ord_results._get_mpl_plt() def check_basic_figure_sanity(self, fig, exp_num_subplots, exp_title, exp_legend_exists, exp_xlabel, exp_ylabel, exp_zlabel): # check type self.assertIsInstance(fig, mpl.figure.Figure) # check number of subplots axes = fig.get_axes() npt.assert_equal(len(axes), exp_num_subplots) # check title ax = axes[0] npt.assert_equal(ax.get_title(), exp_title) # shouldn't have tick labels for tick_label in (ax.get_xticklabels() + ax.get_yticklabels() + ax.get_zticklabels()): npt.assert_equal(tick_label.get_text(), '') # check if legend is present legend = ax.get_legend() if exp_legend_exists: self.assertTrue(legend is not None) else: self.assertTrue(legend is None) # check axis labels npt.assert_equal(ax.get_xlabel(), exp_xlabel) npt.assert_equal(ax.get_ylabel(), exp_ylabel) npt.assert_equal(ax.get_zlabel(), exp_zlabel) def test_plot_no_metadata(self): fig = self.min_ord_results.plot() self.check_basic_figure_sanity(fig, 1, '', False, '0', '1', '2') def test_plot_with_numeric_metadata_and_plot_options(self): fig = self.min_ord_results.plot( self.df, 'numeric', axes=(1, 0, 2), axis_labels=['PC 2', 'PC 1', 'PC 3'], title='a title', cmap='Reds') self.check_basic_figure_sanity( fig, 2, 'a title', False, 'PC 2', 'PC 1', 'PC 3') def test_plot_with_categorical_metadata_and_plot_options(self): fig = self.min_ord_results.plot( self.df, 'categorical', axes=[2, 0, 1], title='a title', cmap='Accent') self.check_basic_figure_sanity(fig, 1, 'a title', True, '2', '0', '1') def test_plot_with_centroids(self): fig = self.min_ord_results.plot( self.df, 'categorical', centroids=True, cmap='Set1') ax = fig.get_axes()[0] labels = [t.get_text() for t in ax.get_legend().get_texts()] self.assertTrue("'foo' centroid" in labels) self.assertTrue("'22' centroid" in labels) def test_plot_without_centroids(self): fig = self.min_ord_results.plot( self.df, 'categorical', centroids=False, cmap='Set1') ax = fig.get_axes()[0] legend = ax.get_legend() if legend: labels = [t.get_text() for t in legend.get_texts()] self.assertTrue("'foo' centroid" not in labels) self.assertTrue("'22' centroid" not in labels) def test_plot_with_invalid_axis_labels(self): with self.assertRaisesRegex(ValueError, r'axis_labels.*4'): self.min_ord_results.plot(axes=[2, 0, 1], axis_labels=('a', 'b', 'c', 'd')) def test_validate_plot_axes_valid_input(self): # shouldn't raise an error on valid input. nothing is returned, so # nothing to check here samples = self.min_ord_results.samples.values.T self.min_ord_results._validate_plot_axes(samples, (1, 2, 0)) def test_validate_plot_axes_invalid_input(self): # not enough dimensions with self.assertRaisesRegex(ValueError, r'1 dimension\(s\)'): self.min_ord_results._validate_plot_axes( np.asarray([[0.1, 0.2, 0.3]]), (0, 1, 2)) coord_matrix = self.min_ord_results.samples.values.T # wrong number of axes with self.assertRaisesRegex(ValueError, r'exactly two.*found 0'): self.min_ord_results._validate_plot_axes(coord_matrix, []) with self.assertRaisesRegex(ValueError, r'exactly two.*found 4'): self.min_ord_results._validate_plot_axes(coord_matrix, (0, 1, 2, 3)) # duplicate axes with self.assertRaisesRegex(ValueError, r'must be unique'): self.min_ord_results._validate_plot_axes(coord_matrix, (0, 1, 0)) # out of range axes with self.assertRaisesRegex(ValueError, r'axes\[1\].*3'): self.min_ord_results._validate_plot_axes(coord_matrix, (0, -1, 2)) with self.assertRaisesRegex(ValueError, r'axes\[2\].*3'): self.min_ord_results._validate_plot_axes(coord_matrix, (0, 2, 3)) def test_get_plot_point_colors_invalid_input(self): # column provided without df with npt.assert_raises(ValueError): self.min_ord_results._get_plot_point_colors(None, 'numeric', ['B', 'C'], 'jet') # df provided without column with npt.assert_raises(ValueError): self.min_ord_results._get_plot_point_colors(self.df, None, ['B', 'C'], 'jet') # column not in df with self.assertRaisesRegex(ValueError, r'missingcol'): self.min_ord_results._get_plot_point_colors(self.df, 'missingcol', ['B', 'C'], 'jet') # id not in df with self.assertRaisesRegex(ValueError, r'numeric'): self.min_ord_results._get_plot_point_colors( self.df, 'numeric', ['B', 'C', 'missingid', 'A'], 'jet') # missing data in df with self.assertRaisesRegex(ValueError, r'nancolumn'): self.min_ord_results._get_plot_point_colors(self.df, 'nancolumn', ['B', 'C', 'A'], 'jet') def test_get_plot_point_colors_no_df_or_column(self): obs = self.min_ord_results._get_plot_point_colors(None, None, ['B', 'C'], 'jet') npt.assert_equal(obs, (None, None)) def test_get_plot_point_colors_numeric_column(self): # subset of the ids in df exp = [0.0, -4.2, 42.0] obs = self.min_ord_results._get_plot_point_colors( self.df, 'numeric', ['B', 'C', 'A'], 'jet') npt.assert_almost_equal(obs[0], exp) self.assertTrue(obs[1] is None) # all ids in df exp = [0.0, 42.0, 42.19, -4.2] obs = self.min_ord_results._get_plot_point_colors( self.df, 'numeric', ['B', 'A', 'D', 'C'], 'jet') npt.assert_almost_equal(obs[0], exp) self.assertTrue(obs[1] is None) def test_get_plot_point_colors_categorical_column(self): # subset of the ids in df exp_colors = [[0., 0., 0.5, 1.], [0., 0., 0.5, 1.], [0.5, 0., 0., 1.]] exp_color_dict = { 'foo': [0.5, 0., 0., 1.], 22: [0., 0., 0.5, 1.] } obs = self.min_ord_results._get_plot_point_colors( self.df, 'categorical', ['B', 'C', 'A'], 'jet') npt.assert_almost_equal(obs[0], exp_colors) npt.assert_equal(obs[1], exp_color_dict) # all ids in df exp_colors = [[0., 0., 0.5, 1.], [0.5, 0., 0., 1.], [0.5, 0., 0., 1.], [0., 0., 0.5, 1.]] obs = self.min_ord_results._get_plot_point_colors( self.df, 'categorical', ['B', 'A', 'D', 'C'], 'jet') npt.assert_almost_equal(obs[0], exp_colors) # should get same color dict as before npt.assert_equal(obs[1], exp_color_dict) def test_plot_categorical_legend(self): fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # we shouldn't have a legend yet self.assertTrue(ax.get_legend() is None) self.min_ord_results._plot_categorical_legend( ax, {'foo': 'red', 'bar': 'green'}) # make sure we have a legend now legend = ax.get_legend() self.assertTrue(legend is not None) # do some light sanity checking to make sure our input labels and # colors are present labels = [t.get_text() for t in legend.get_texts()] npt.assert_equal(sorted(labels), ['bar', 'foo']) colors = [line.get_color() for line in legend.get_lines()] npt.assert_equal(sorted(colors), ['green', 'red']) @unittest.skipUnless(has_matplotlib, "Matplotlib not available.") class TestOrdinationResults2DPlotting(unittest.TestCase): def setUp(self): # DataFrame for testing plot method. Has a categorical column with a # mix of numbers and strings. Has a numeric column with a mix of ints, # floats, and strings that can be converted to floats. Has a numeric # column with missing data (np.nan). self.df = pd.DataFrame([['foo', '42'], [22, 0], [22, -4.2], ['foo', '42.19']], index=['A', 'B', 'C', 'D'], columns=['categorical', 'numeric']) # Minimal ordination results for easier testing of plotting method. # Paired with df above. eigvals = np.array([0.50, 0.25]) samples = np.array([[0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]) samples_df = pd.DataFrame(samples, ['A', 'B', 'C', 'D'], ['PC1', 'PC2']) self.min_ord_results = OrdinationResults( 'PCoA', 'Principal Coordinate Analysis', eigvals, samples_df) self.min_ord_results._get_mpl_plt() def check_basic_figure_sanity(self, fig, exp_num_subplots, exp_title, exp_legend_exists, exp_xlabel, exp_ylabel): # check type self.assertIsInstance(fig, mpl.figure.Figure) # check number of subplots axes = fig.get_axes() npt.assert_equal(len(axes), exp_num_subplots) # check title ax = axes[0] npt.assert_equal(ax.get_title(), exp_title) # shouldn't have tick labels for tick_label in (ax.get_xticklabels() + ax.get_yticklabels()): npt.assert_equal(tick_label.get_text(), '') # check if legend is present legend = ax.get_legend() if exp_legend_exists: self.assertTrue(legend is not None) else: self.assertTrue(legend is None) # check axis labels npt.assert_equal(ax.get_xlabel(), exp_xlabel) npt.assert_equal(ax.get_ylabel(), exp_ylabel) def test_plot_no_metadata(self): # Test 2D plot without metadata - axes should default to [0, 1] fig = self.min_ord_results.plot() self.check_basic_figure_sanity(fig, 1, '', False, '0', '1') def test_plot_explicit_2d_axes(self): # Test explicitly passing 2D axes fig = self.min_ord_results.plot(axes=[0, 1]) self.check_basic_figure_sanity(fig, 1, '', False, '0', '1') def test_plot_with_numeric_metadata_and_plot_options(self): fig = self.min_ord_results.plot( self.df, 'numeric', axes=(1, 0), axis_labels=['PC 2', 'PC 1'], title='a title', cmap='Reds') self.check_basic_figure_sanity( fig, 2, 'a title', False, 'PC 2', 'PC 1') def test_plot_with_categorical_metadata_and_plot_options(self): fig = self.min_ord_results.plot( self.df, 'categorical', axes=[0, 1], title='a title', cmap='Accent') self.check_basic_figure_sanity(fig, 1, 'a title', True, '0', '1') def test_plot_with_centroids(self): fig = self.min_ord_results.plot( self.df, 'categorical', centroids=True, cmap='Set1', axes=[0, 1]) ax = fig.get_axes()[0] labels = [t.get_text() for t in ax.get_legend().get_texts()] self.assertTrue("'foo' centroid" in labels) self.assertTrue("'22' centroid" in labels) def test_plot_without_centroids(self): fig = self.min_ord_results.plot( self.df, 'categorical', centroids=False, cmap='Set1', axes=[0, 1]) ax = fig.get_axes()[0] legend = ax.get_legend() if legend: labels = [t.get_text() for t in legend.get_texts()] self.assertTrue("'foo' centroid" not in labels) self.assertTrue("'22' centroid" not in labels) def test_plot_centroids_without_metadata(self): # Test that plotting centroids without metadata raises ValueError. with self.assertRaisesRegex(ValueError, r'Metadata must be provided to plot centroids.'): self.min_ord_results.plot(centroids=True) def test_plot_with_confidence_ellipses(self): fig = self.min_ord_results.plot( self.df, 'categorical', confidence_ellipses=True, cmap='Set1', axes=[0, 1]) ax = fig.get_axes()[0] labels = [t.get_text() for t in ax.get_legend().get_texts()] self.assertTrue("'foo' ellipse" in labels) self.assertTrue("'22' ellipse" in labels) def test_plot_without_confidence_ellipse(self): fig = self.min_ord_results.plot( self.df, 'categorical', confidence_ellipses=False, cmap='Set1', axes=[0, 1]) ax = fig.get_axes()[0] legend = ax.get_legend() if legend: labels = [t.get_text() for t in legend.get_texts()] self.assertTrue("'foo' ellipse" not in labels) self.assertTrue("'22' ellipse" not in labels) def test_plot_confidence_ellipses_without_metadata(self): # Test that plotting confidence ellipses without metadata raises ValueError. with self.assertRaisesRegex(ValueError, r'Metadata must be provided to plot confidence ellipses.'): self.min_ord_results.plot(confidence_ellipses=True, axes=[0, 1]) def test_plot_confidence_ellipses_in_3d(self): # Test that plotting confidence ellipses in 3D raises ValueError. # Need to create a 3D ordination result first eigvals_3d = np.array([0.50, 0.25, 0.10]) samples_3d = np.array([[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6]]) samples_df_3d = pd.DataFrame(samples_3d, ['A', 'B', 'C', 'D'], ['PC1', 'PC2', 'PC3']) ord_results_3d = OrdinationResults( 'PCoA', 'Principal Coordinate Analysis', eigvals_3d, samples_df_3d) ord_results_3d._get_mpl_plt() with self.assertRaisesRegex(ValueError, r'Confidence ellipses can only be plotted in 2D.'): ord_results_3d.plot( self.df, 'categorical', confidence_ellipses=True, axes=[0, 1, 2] ) def test_plot_with_invalid_axis_labels(self): with self.assertRaisesRegex(ValueError, r'axis_labels.*3'): self.min_ord_results.plot(axes=[0, 1], axis_labels=('a', 'b', 'c')) def test_validate_plot_axes_valid_input(self): # shouldn't raise an error on valid input. nothing is returned, so # nothing to check here samples = self.min_ord_results.samples.values.T self.min_ord_results._validate_plot_axes(samples, (0, 1)) def test_validate_plot_axes_invalid_input(self): # not enough dimensions with self.assertRaisesRegex(ValueError, r'`axes\[2\]` must be >= 0 and < 2.'): self.min_ord_results._validate_plot_axes( np.asarray([[0.1, 0.2], [0.2, 0.3]]), (0, 1, 2)) coord_matrix = self.min_ord_results.samples.values.T # wrong number of axes with self.assertRaisesRegex(ValueError, r'exactly two.*found 0'): self.min_ord_results._validate_plot_axes(coord_matrix, []) with self.assertRaisesRegex(ValueError, r'exactly two.*found 4'): self.min_ord_results._validate_plot_axes(coord_matrix, (0, 1, 2, 3)) # duplicate axes with self.assertRaisesRegex(ValueError, r'must be unique'): self.min_ord_results._validate_plot_axes(coord_matrix, (0, 0)) # out of range axes with self.assertRaisesRegex(ValueError, r'axes\[1\].*2'): self.min_ord_results._validate_plot_axes(coord_matrix, (0, -1)) with self.assertRaisesRegex(ValueError, r'axes\[1\].*2'): self.min_ord_results._validate_plot_axes(coord_matrix, (0, 3)) def test_get_plot_point_colors_invalid_input(self): # column provided without df with npt.assert_raises(ValueError): self.min_ord_results._get_plot_point_colors(None, 'numeric', ['B', 'C'], 'jet') # df provided without column with npt.assert_raises(ValueError): self.min_ord_results._get_plot_point_colors(self.df, None, ['B', 'C'], 'jet') # column not in df with self.assertRaisesRegex(ValueError, r'missingcol'): self.min_ord_results._get_plot_point_colors(self.df, 'missingcol', ['B', 'C'], 'jet') # id not in df with self.assertRaisesRegex(ValueError, r'numeric'): self.min_ord_results._get_plot_point_colors( self.df, 'numeric', ['B', 'missingid'], 'jet') # missing data in df with self.assertRaisesRegex(ValueError, r'nancolumn'): self.min_ord_results._get_plot_point_colors(self.df, 'nancolumn', ['B', 'C'], 'jet') def test_get_plot_point_colors_no_df_or_column(self): obs = self.min_ord_results._get_plot_point_colors(None, None, ['B', 'C'], 'jet') npt.assert_equal(obs, (None, None)) def test_get_plot_point_colors_numeric_column(self): # subset of the ids in df exp = [0.0, -4.2] obs = self.min_ord_results._get_plot_point_colors( self.df, 'numeric', ['B', 'C'], 'jet') npt.assert_almost_equal(obs[0], exp) self.assertTrue(obs[1] is None) # all ids in df exp = [0.0, 42.0] obs = self.min_ord_results._get_plot_point_colors( self.df, 'numeric', ['B', 'A'], 'jet') npt.assert_almost_equal(obs[0], exp) self.assertTrue(obs[1] is None) def test_get_plot_point_colors_categorical_column(self): # subset of the ids in df exp_colors = [[0., 0., 0.5, 1.], [0.5, 0., 0., 1.]] exp_color_dict = { 'foo': [0.5, 0., 0., 1.], 22: [0., 0., 0.5, 1.] } obs = self.min_ord_results._get_plot_point_colors( self.df, 'categorical', ['B', 'A'], 'jet') npt.assert_almost_equal(obs[0], exp_colors) npt.assert_equal(obs[1], exp_color_dict) # all ids in df exp_colors = [[0., 0., 0.5, 1.], [0.5, 0., 0., 1.], [0.5, 0., 0., 1.], [0., 0., 0.5, 1.]] obs = self.min_ord_results._get_plot_point_colors( self.df, 'categorical', ['B', 'A', 'D', 'C'], 'jet') npt.assert_almost_equal(obs[0], exp_colors) # should get same color dict as before npt.assert_equal(obs[1], exp_color_dict) def test_plot_categorical_legend(self): fig = plt.figure() ax = fig.add_subplot(111) # we shouldn't have a legend yet self.assertTrue(ax.get_legend() is None) self.min_ord_results._plot_categorical_legend( ax, {'foo': 'red', 'bar': 'green'}) # make sure we have a legend now legend = ax.get_legend() self.assertTrue(legend is not None) # do some light sanity checking to make sure our input labels and # colors are present labels = [t.get_text() for t in legend.get_texts()] npt.assert_equal(sorted(labels), ['bar', 'foo']) colors = [line.get_color() for line in legend.get_lines()] npt.assert_equal(sorted(colors), ['green', 'red']) def test_plot_confidence_ellipses_helper(self): # Test the _plot_confidence_ellipses helper function directly # Create a simple dataframe with enough points per category df_sufficient = pd.DataFrame([['foo', '42'], ['foo', '43'], ['foo', '44'], [22, 0], [22, -4.2], [22, 5.1]], index=['A', 'B', 'C', 'D', 'E', 'F'], columns=['categorical', 'numeric']) # Create samples with good spread samples_sufficient = np.array([[0.1, 0.3], [0.3, 0.15], [0.2, 0.4], [0.5, 0.6], [0.4, 0.45], [0.6, 0.7]]) samples_df_sufficient = pd.DataFrame(samples_sufficient, ['A', 'B', 'C', 'D', 'E', 'F'], ['PC1', 'PC2']) ord_results = OrdinationResults( 'PCoA', 'Principal Coordinate Analysis', np.array([0.50, 0.25]), samples_df_sufficient) ord_results._get_mpl_plt() fig, ax = plt.subplots() category_to_color = { 'foo': [0.5, 0., 0., 1.], 22: [0., 0., 0.5, 1.] } # Call the helper function ord_results._plot_confidence_ellipses( ax, df_sufficient, 'categorical', category_to_color, [0, 1]) # Check that ellipses were added as patches patches = ax.patches self.assertEqual(len(patches), 2) # Check that all patches are Ellipse objects for patch in patches: self.assertIsInstance(patch, mpl.patches.Ellipse) plt.close(fig) def test_plot_confidence_ellipses_insufficient_points(self): # Test that ellipses are not plotted for categories with < 3 points df_sparse = pd.DataFrame([['foo', '42'], [22, 0]], index=['A', 'B'], columns=['categorical', 'numeric']) samples_sparse = np.array([[0.1, 0.2], [0.2, 0.3]]) samples_df_sparse = pd.DataFrame(samples_sparse, ['A', 'B'], ['PC1', 'PC2']) ord_results = OrdinationResults( 'PCoA', 'Principal Coordinate Analysis', np.array([0.50, 0.25]), samples_df_sparse) ord_results._get_mpl_plt() fig, ax = plt.subplots() category_to_color = { 'foo': [0.5, 0., 0., 1.], 22: [0., 0., 0.5, 1.] } ord_results._plot_confidence_ellipses( ax, df_sparse, 'categorical', category_to_color, [0, 1]) # Should have 0 ellipses since no category has 3+ points patches = ax.patches self.assertEqual(len(patches), 0) plt.close(fig) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/test_principal_component_analysis.py000066400000000000000000000221731520735541300335140ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np from skbio import OrdinationResults from skbio.stats.ordination import pca from skbio.util import assert_ordination_results_equal from skbio.table._tabular import _create_table, _create_table_1d class TestPCA(TestCase): def setUp(self): # Simple dataset with 4 samples and 4 features self.X = np.array([ [1, 4, 2, 6], [2, 5, 1, 7], [1, 5, 2, 4], [3, 4, 3, 6] ]) # Full dimensionality expected results components = np.array([ [0.48260815, -0.12451597, -0.06637759, 0.86439526], [0.51789148, -0.33553222, 0.73499837, -0.28104082], [0.63156772, 0.6869599, -0.23531131, -0.27172945], [-0.31622777, 0.63245553, 0.63245553, 0.31622777] ]) variances = np.array([1.95862455, 1.18116419, 0.36021126, 0]) variance_proportion = np.array([0.55960701, 0.33747548, 0.1029175, 0]) projected_samples = np.array([ [-0.08359932, -0.29091271, -0.8850881, 0], [1.20526571, -1.12459263, 0.39702138, 0], [-1.9369058, -0.06436329, 0.3453307, 0], [0.8152394, 1.47986863, 0.14273602, 0] ]) row_ids = ["Sample 1", "Sample 2", "Sample 3", "Sample 4"] column_ids = ["Feature 1", "Feature 2", "Feature 3", "Feature 4"] pc_ids = ["PC1", "PC2", "PC3", "PC4"] eigvals = _create_table_1d( variances, index=pc_ids, backend=None ) samples = _create_table( projected_samples, index=row_ids, columns=pc_ids, backend=None ) features = _create_table( components, index=pc_ids, columns=column_ids, backend=None ) proportion_explained = _create_table_1d( variance_proportion, index=pc_ids, backend=None ) self.full_dim_expected_results = OrdinationResults( short_method_name="PCA", long_method_name="Principal Component Analysis", eigvals=eigvals, samples=samples, sample_ids=row_ids, features=features, feature_ids=pc_ids, proportion_explained=proportion_explained, ) # Reduced dimensionality expected results (2D) components = np.array([ [0.48260815, -0.12451597, -0.06637759, 0.86439526], [0.51789148, -0.33553222, 0.73499837, -0.28104082] ]) variances = np.array([1.95862455, 1.18116419]) variance_proportion = np.array([0.55960701, 0.33747548]) projected_samples = np.array([ [-0.08359932, -0.29091271], [1.20526571, -1.12459263], [-1.9369058, -0.06436329], [0.8152394, 1.47986863] ]) row_ids = ["Sample 1", "Sample 2", "Sample 3", "Sample 4"] column_ids = ["Feature 1", "Feature 2", "Feature 3", "Feature 4"] pc_ids = ["PC1", "PC2"] eigvals = _create_table_1d( variances, index=pc_ids, backend=None ) samples = _create_table( projected_samples, index=row_ids, columns=pc_ids, backend=None ) features = _create_table( components, index=pc_ids, columns=column_ids, backend=None ) proportion_explained = _create_table_1d( variance_proportion, index=pc_ids, backend=None ) self.reduced_dim_expected_results = OrdinationResults( short_method_name="PCA", long_method_name="Principal Component Analysis", eigvals=eigvals, samples=samples, sample_ids=row_ids, features=features, feature_ids=pc_ids, proportion_explained=proportion_explained, ) def test_simple(self): results = pca(self.X, sample_ids=["Sample 1", "Sample 2", "Sample 3", "Sample 4"], feature_ids=["Feature 1", "Feature 2", "Feature 3", "Feature 4"]) assert_ordination_results_equal(results, self.full_dim_expected_results, ignore_directionality=True) def test_dimensionality_reduction(self): results = pca(self.X, dimensions=2, sample_ids=["Sample 1", "Sample 2", "Sample 3", "Sample 4"], feature_ids=["Feature 1", "Feature 2", "Feature 3", "Feature 4"]) assert_ordination_results_equal(results, self.reduced_dim_expected_results, ignore_directionality=True) def test_svd_full_dim(self): results = pca(self.X, method="svd", sample_ids=["Sample 1", "Sample 2", "Sample 3", "Sample 4"], feature_ids=["Feature 1", "Feature 2", "Feature 3", "Feature 4"]) assert_ordination_results_equal(results, self.full_dim_expected_results, ignore_directionality=True) def test_svd_reduced_dim(self): results = pca(self.X, method="svd", dimensions=2, sample_ids=["Sample 1", "Sample 2", "Sample 3", "Sample 4"], feature_ids=["Feature 1", "Feature 2", "Feature 3", "Feature 4"]) assert_ordination_results_equal(results, self.reduced_dim_expected_results, ignore_directionality=True) def test_svd_full_dim_iterative(self): results = pca(self.X, method="svd", iterative=True, sample_ids=["Sample 1", "Sample 2", "Sample 3", "Sample 4"], feature_ids=["Feature 1", "Feature 2", "Feature 3", "Feature 4"]) assert_ordination_results_equal(results, self.full_dim_expected_results, ignore_directionality=True) def test_svd_reduced_dim_iterative(self): results = pca(self.X, method="svd", dimensions=2, iterative=True, sample_ids=["Sample 1", "Sample 2", "Sample 3", "Sample 4"], feature_ids=["Feature 1", "Feature 2", "Feature 3", "Feature 4"]) assert_ordination_results_equal(results, self.reduced_dim_expected_results, ignore_directionality=True) def test_eigh_full_dim(self): results = pca(self.X, method="eigh", sample_ids=["Sample 1", "Sample 2", "Sample 3", "Sample 4"], feature_ids=["Feature 1", "Feature 2", "Feature 3", "Feature 4"]) assert_ordination_results_equal(results, self.full_dim_expected_results, ignore_directionality=True) def test_eigh_reduced_dim(self): results = pca(self.X, method="eigh", dimensions=2, sample_ids=["Sample 1", "Sample 2", "Sample 3", "Sample 4"], feature_ids=["Feature 1", "Feature 2", "Feature 3", "Feature 4"]) assert_ordination_results_equal(results, self.reduced_dim_expected_results, ignore_directionality=True) def test_eigh_full_dim(self): results = pca(self.X, method="eigh", iterative=True, sample_ids=["Sample 1", "Sample 2", "Sample 3", "Sample 4"], feature_ids=["Feature 1", "Feature 2", "Feature 3", "Feature 4"]) assert_ordination_results_equal(results, self.full_dim_expected_results, ignore_directionality=True) def test_eigh_reduced_dim(self): results = pca(self.X, method="eigh", dimensions=2, iterative=True, sample_ids=["Sample 1", "Sample 2", "Sample 3", "Sample 4"], feature_ids=["Feature 1", "Feature 2", "Feature 3", "Feature 4"]) assert_ordination_results_equal(results, self.reduced_dim_expected_results, ignore_directionality=True) def test_invalid_method(self): with self.assertRaises(ValueError): pca(self.X, method="invalid_method") def test_invalid_dimensions(self): with self.assertRaises(ValueError): pca(self.X, dimensions=0) with self.assertRaises(ValueError): pca(self.X, dimensions=0.1) with self.assertRaises(ValueError): pca(self.X, dimensions=5) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/test_principal_coordinate_analysis.py000066400000000000000000000550311520735541300336400ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np import numpy.testing as npt import pandas as pd from copy import deepcopy from warnings import catch_warnings from unittest import TestCase, main from skbio import DistanceMatrix, OrdinationResults from skbio.stats.distance import PairwiseMatrixError from skbio.stats.ordination import pcoa, pcoa_biplot from skbio.util import (get_data_path, assert_ordination_results_equal, assert_data_frame_almost_equal, ArrayAPITestMixin, array_backends) from skbio.stats.ordination._principal_coordinate_analysis import ( e_matrix, f_matrix, center_distance_matrix, _host_partial_eigh, _fsvd, ) class TestPCoA(TestCase): def setUp(self): # Sample data set from page 111 of W.J Krzanowski. Principles # of multivariate analysis, 2000, Oxford University Press. self.dm = DistanceMatrix(np.loadtxt(get_data_path('PCoA_sample_data'))) self.dm3 = DistanceMatrix.read(get_data_path('PCoA_sample_data_3')) self.dm_invalid = np.array([[1, 2], [3, 4], [5, 6]]) def test_simple(self): eigvals = [0.51236726, 0.30071909, 0.26791207, 0.20898868, 0.19169895, 0.16054235, 0.15017696, 0.12245775, 0.0] proportion_explained = [0.2675738328, 0.157044696, 0.1399118638, 0.1091402725, 0.1001110485, 0.0838401162, 0.0784269939, 0.0639511764, 0.0] sample_ids = ['PC.636', 'PC.635', 'PC.356', 'PC.481', 'PC.354', 'PC.593', 'PC.355', 'PC.607', 'PC.634'] axis_labels = ['PC%d' % i for i in range(1, 10)] expected_results = OrdinationResults( short_method_name='PCoA', long_method_name='Principal Coordinate Analysis', eigvals=pd.Series(eigvals, index=axis_labels), samples=pd.DataFrame( np.loadtxt(get_data_path('exp_PCoAEigenResults_site')), index=sample_ids, columns=axis_labels), proportion_explained=pd.Series(proportion_explained, index=axis_labels)) results = pcoa(self.dm3) assert_ordination_results_equal(results, expected_results, ignore_directionality=True) def test_fsvd_inplace(self): expected_results = pcoa( self.dm3.copy(), method="eigh", dimensions=3, inplace=True) results = pcoa(self.dm3.copy(), method="fsvd", dimensions=3, inplace=True) assert_ordination_results_equal(results, expected_results, ignore_directionality=True, ignore_method_names=True) def test_fsvd(self): # Test eigh vs. fsvd pcoa and inplace parameter expected_results = pcoa(self.dm3, method="eigh", dimensions=3, inplace=False) results = pcoa(self.dm3, method="fsvd", dimensions=3, inplace=False) results_inplace = pcoa(self.dm3.copy(), method="fsvd", dimensions=3, inplace=True) assert_ordination_results_equal(results, expected_results, ignore_directionality=True, ignore_method_names=True) assert_ordination_results_equal(results, results_inplace, ignore_directionality=True, ignore_method_names=True) # Test dimensions edge cases results2 = pcoa(self.dm3, method="fsvd", dimensions=0, inplace=False) expected_results2 = pcoa(self.dm3, method="fsvd", dimensions=self.dm3.shape[0], inplace=False) assert_ordination_results_equal(results2, expected_results2, ignore_directionality=True, ignore_method_names=True) with self.assertRaises(ValueError): dim_too_large = self.dm3.shape[0] + 10 pcoa(self.dm3, method="fsvd", dimensions=dim_too_large) with self.assertRaises(ValueError): pcoa(self.dm3, method="fsvd", dimensions=-1) with self.assertRaises(ValueError): dim_too_large = self.dm3.shape[0] + 10 pcoa(self.dm3, method="eigh", dimensions=dim_too_large) with self.assertRaises(ValueError): pcoa(self.dm3, method="eigh", dimensions=-1) dm_big = DistanceMatrix.read(get_data_path('PCoA_sample_data_12dim')) with self.assertWarnsRegex(RuntimeWarning, r"no value for dimensions"): pcoa(dm_big, method="fsvd", dimensions=0) def test_permutted(self): # this should not throw pcoa(self.dm3, method="fsvd", dimensions=3, inplace=False) # some operations, like permute, will change memory structure # we want to test that this does not break pcoa permutted = self.dm3.permute() # we just want to assure it does not throw pcoa(permutted, method="fsvd", dimensions=3, inplace=False) def test_extensive(self): eigvals = [0.3984635, 0.36405689, 0.28804535, 0.27479983, 0.19165361, 0.0] proportion_explained = [0.2626621381, 0.2399817314, 0.1898758748, 0.1811445992, 0.1263356565, 0.0] sample_ids = [str(i) for i in range(6)] axis_labels = ['PC%d' % i for i in range(1, 7)] samples = [[-0.028597, 0.22903853, 0.07055272, 0.26163576, 0.28398669, 0.0], [0.37494056, 0.22334055, -0.20892914, 0.05057395, -0.18710366, 0.0], [-0.33517593, -0.23855979, -0.3099887, 0.11521787, -0.05021553, 0.0], [0.25412394, -0.4123464, 0.23343642, 0.06403168, -0.00482608, 0.0], [-0.28256844, 0.18606911, 0.28875631, -0.06455635, -0.21141632, 0.0], [0.01727687, 0.012458, -0.07382761, -0.42690292, 0.1695749, 0.0]] expected_results = OrdinationResults( short_method_name='PCoA', long_method_name='Principal Coordinate Analysis', eigvals=pd.Series(eigvals, index=axis_labels), samples=pd.DataFrame(samples, index=sample_ids, columns=axis_labels), proportion_explained=pd.Series(proportion_explained, index=axis_labels)) data = np.loadtxt(get_data_path('PCoA_sample_data_2')) # test passing a numpy.ndarray and a DistanceMatrix to pcoa # gives same results for dm in (data, DistanceMatrix(data)): results = pcoa(dm) assert_ordination_results_equal(results, expected_results, ignore_directionality=True) def test_book_example_dataset(self): # Adapted from PyCogent's `test_principal_coordinate_analysis`: # "I took the example in the book (see intro info), and did # the principal coordinates analysis, plotted the data and it # looked right". eigvals = [0.73599103, 0.26260032, 0.14926222, 0.06990457, 0.02956972, 0.01931184, 0., 0., 0., 0., 0., 0., 0., 0.] proportion_explained = [0.58105792, 0.20732046, 0.1178411, 0.05518899, 0.02334502, 0.01524651, 0., 0., 0., 0., 0., 0., 0., 0.] sample_ids = [str(i) for i in range(14)] axis_labels = ['PC%d' % i for i in range(1, 15)] expected_results = OrdinationResults( short_method_name='PCoA', long_method_name='Principal Coordinate Analysis', eigvals=pd.Series(eigvals, index=axis_labels), samples=pd.DataFrame( np.loadtxt(get_data_path('exp_PCoAzeros_site')), index=sample_ids, columns=axis_labels), proportion_explained=pd.Series(proportion_explained, index=axis_labels)) with self.assertWarns(RuntimeWarning): results = pcoa(self.dm) # Note the absolute value because column can have signs swapped results.samples = np.abs(results.samples) assert_ordination_results_equal(results, expected_results, ignore_directionality=True) def test_invalid_input(self): with self.assertRaises(PairwiseMatrixError): pcoa([[1, 2], [3, 4]]) def test_warn_neg_eigval(self): """Test warnings of negative eigenvalues.""" # In this example, negative-most: -0.109, positive-most: 0.736, ratio: 0.148, # which is above the threshold, therefore a warning is raised by default. # Note: Explicitly pass the dimensions, to avoid spurious "large DM" warning with self.assertWarns(RuntimeWarning): results = pcoa(self.dm, dimensions=self.dm.data.shape[0]) # warn regardless of magnitude with self.assertWarns(RuntimeWarning): results = pcoa(self.dm, dimensions=self.dm.data.shape[0], warn_neg_eigval=True) # disable warning with catch_warnings(record=True) as obs: results = pcoa(self.dm, dimensions=self.dm.data.shape[0], warn_neg_eigval=False) self.assertEqual(obs, []) # larger (more stringent) threshold with catch_warnings(record=True) as obs: results = pcoa(self.dm, dimensions=self.dm.data.shape[0], warn_neg_eigval=0.2) self.assertEqual(obs, []) # In this example, all eigenvalues are zero or positive, therefore no warning # will be raised. with catch_warnings(record=True) as obs: results = pcoa(self.dm3) self.assertEqual(obs, []) with catch_warnings(record=True) as obs: results = pcoa(self.dm3, warn_neg_eigval=True) self.assertEqual(obs, []) # invalid parameter msg = ("warn_neg_eigval must be Boolean or a floating-point number between 0 " "and 1.") with self.assertRaisesRegex(ValueError, msg): pcoa(self.dm3, warn_neg_eigval=5.0) with self.assertRaisesRegex(ValueError, msg): pcoa(self.dm3, warn_neg_eigval=-2.5) def test_integer_dimensions(self): """Test with an integer dimensions.""" results = pcoa(self.dm3, dimensions=3) self.assertEqual(results.samples.shape[1], 3) def test_large_float(self): """Test with a float dimensions > 1.""" msg = "A floating-point number greater than 1 cannot be" with self.assertRaisesRegex(ValueError, msg): pcoa(self.dm3, dimensions=2.5) def test_eigh_method_with_float(self): """Test with a float dimensions with eigh method to retain 80% variance.""" results = pcoa(self.dm3, method="eigh", dimensions=0.8, inplace=False, seed=None) cumulative_variance = np.cumsum(results.proportion_explained.values) self.assertGreaterEqual(cumulative_variance[-1], 0.8) def test_edge_case_for_all_variance(self): """Test with a dimensions close to 1 to retain nearly all variance. """ results = pcoa(self.dm3, dimensions=0.9999) cumulative_variance = np.cumsum(results.proportion_explained.values) self.assertGreaterEqual(cumulative_variance[-1], 0.9999) def test_fsvd_method_with_float(self): """Test FSVD with float dimensions for variance threshold.""" results = pcoa(self.dm3, method="fsvd", dimensions=0.7, inplace=False, seed=None) cumulative_variance = np.cumsum(results.proportion_explained.values) self.assertGreaterEqual(cumulative_variance[-1], 0.7) def test_invalid_method(self): """Test that correct error is raised when method is invalid.""" with self.assertRaisesRegex( ValueError, "PCoA eigendecomposition method asdf not supported." ): results = pcoa(self.dm3, method="asdf") def test_fsvd_non_square_input(self): with self.assertRaisesRegex(ValueError, "FSVD expects square distance matrix"): results = _fsvd(self.dm_invalid) def test_fsvd_invalid_dimensions(self): with self.assertRaisesRegex( ValueError, ("Invalid operation: cannot reduce distance matrix " "to negative dimensions using PCoA. Did you intend " 'to specify the default value "0", which sets ' "the dimensions equal to the " "dimensionality of the given distance matrix?") ): results = _fsvd(self.dm_invalid[1:4], dimensions=-1) class TestPCoABiplot(TestCase): def setUp(self): # Crawford dataset for unweighted UniFrac fp = get_data_path('PCoA_sample_data_3') self.ordination = pcoa(DistanceMatrix.read(fp)) fp = get_data_path('PCoA_biplot_descriptors') self.descriptors = pd.read_table(fp, index_col='Taxon').T def test_pcoa_biplot_from_ape(self): """Test against a reference implementation from R's ape package The test data was generated with the R script below and using a modified version of pcoa.biplot that returns the U matrix. library(ape) # files can be found in the test data folder of the ordination module y = t(read.table('PCoA_biplot_descriptors', row.names = 1, header = 1)) dm = read.table('PCoA_sample_data_3', row.names = 1, header = 1) h = pcoa(dm) # biplot.pcoa will only calculate the biplot for two axes at a time acc = NULL for (axes in c(1, 3, 5, 7)) { new = biplot.pcoa(h, y, plot.axes=c(axes, axes+1), rn = rep('.', length(colnames(dm))) ) if(is.null(acc)) { acc = new } else { b = acc acc <- cbind(acc, new) } } write.csv(acc, file='PCoA_biplot_projected_descriptors') """ obs = pcoa_biplot(self.ordination, self.descriptors) # we'll build a dummy ordination results object based on the expected # the main thing we'll compare and modify is the features dataframe exp = deepcopy(obs) fp = get_data_path('PCoA_biplot_projected_descriptors') # R won't calculate the last dimension, so pad with zeros to make the # arrays comparable exp.features = pd.read_table(fp, sep=',', index_col=0) exp.features['Axis.9'] = np.zeros_like(exp.features['Axis.8']) # make the order comparable exp.features = exp.features.reindex(obs.features.index) assert_ordination_results_equal(obs, exp, ignore_directionality=True, ignore_axis_labels=True) def test_pcoa_biplot_subset_input(self): # create a 2D copy of the full ordination two_dims = deepcopy(self.ordination) two_dims.eigvals = two_dims.eigvals[:2] two_dims.samples = two_dims.samples.iloc[:, :2] two_dims.proportion_explained = two_dims.proportion_explained[:2] # only look at the features subset = pcoa_biplot(two_dims, self.descriptors).features full = pcoa_biplot(self.ordination, self.descriptors).features # the biplot should be identical regardless of the number of axes used assert_data_frame_almost_equal(subset, full.iloc[:, :2]) def test_mismatching_samples(self): new_index = self.descriptors.index.tolist() new_index[3] = 'Not.an.id' self.descriptors.index = pd.Index(new_index) with self.assertRaisesRegex(ValueError, r'The eigenvectors and the ' 'descriptors must describe ' 'the same ' 'samples.'): pcoa_biplot(self.ordination, self.descriptors) def test_not_a_pcoa(self): self.ordination.short_method_name = 'RDA' self.ordination.long_method_name = 'Redundancy Analysis' with self.assertRaisesRegex(ValueError, r'This biplot computation can' ' only be performed in a ' 'PCoA matrix.'): pcoa_biplot(self.ordination, self.descriptors) def test_from_seralized_results(self): # the current implementation of ordination results loses some # information, test that pcoa_biplot works fine regardless results = OrdinationResults.read(get_data_path('PCoA_skbio')) serialized = pcoa_biplot(results, self.descriptors) in_memory = pcoa_biplot(self.ordination, self.descriptors) assert_ordination_results_equal(serialized, in_memory, ignore_directionality=True, ignore_axis_labels=True, ignore_method_names=True) # A small symmetric distance matrix used by most helpers. _DM = [ [0.0, 0.7, 0.6, 0.5], [0.7, 0.0, 0.4, 0.3], [0.6, 0.4, 0.0, 0.2], [0.5, 0.3, 0.2, 0.0], ] class TestEMatrixBackends(TestCase, ArrayAPITestMixin): @array_backends("numpy", "jax", "torch", "cupy") def test_e_matrix_backends(self, xp, device): data = self.make_array(xp, device, _DM) result = e_matrix(data) # Reference computed in numpy. data_np = np.asarray(_DM, dtype=np.float64) expected = -(data_np * data_np) / 2 self.assert_type_preserved(result, xp, device) self.assert_close(result, expected) class TestFMatrixBackends(TestCase, ArrayAPITestMixin): @array_backends("numpy", "jax", "torch", "cupy") def test_f_matrix_backends(self, xp, device): data_np = np.asarray(_DM, dtype=np.float64) e_np = -(data_np * data_np) / 2 e = self.make_array(xp, device, e_np.tolist()) result = f_matrix(e) # Reference: manual double-centering in numpy. row = e_np.mean(axis=1, keepdims=True) col = e_np.mean(axis=0, keepdims=True) expected = e_np - row - col + e_np.mean() self.assert_type_preserved(result, xp, device) self.assert_close(result, expected) @array_backends("numpy", "jax", "torch", "cupy") def test_f_matrix_is_symmetric(self, xp, device): data = self.make_array(xp, device, _DM) result = f_matrix(e_matrix(data)) # Double-centered matrix of a symmetric input should be symmetric. # Using .T instead of xp.matrix_transpose (not available in torch). self.assert_close(result, result.T) class TestCenterDistanceMatrixBackends(TestCase, ArrayAPITestMixin): @array_backends("numpy", "jax", "torch", "cupy") def test_center_distance_matrix_backends(self, xp, device): data = self.make_array(xp, device, _DM) result = center_distance_matrix(data) # Reference: run the numpy path. data_np = np.asarray(_DM, dtype=np.float64) expected = center_distance_matrix(data_np) self.assert_type_preserved(result, xp, device) self.assert_close(result, expected) @array_backends("numpy", "jax", "torch", "cupy") def test_center_distance_matrix_inplace_ignored_for_non_numpy(self, xp, device): # `inplace=True` is documented to be ignored for non-numpy arrays; # the call should still succeed and produce the centered matrix. data = self.make_array(xp, device, _DM) result = center_distance_matrix(data, inplace=True) data_np = np.asarray(_DM, dtype=np.float64) expected = center_distance_matrix(data_np) self.assert_close(result, expected) class TestHostPartialEighBackends(TestCase, ArrayAPITestMixin): @array_backends("numpy", "jax", "torch", "cupy") def test_host_partial_eigh_returns_to_device(self, xp, device): # Build a symmetric positive-ish matrix on the backend. centered_np = center_distance_matrix(np.asarray(_DM, dtype=np.float64)) centered = self.make_array(xp, device, centered_np.tolist()) n = centered_np.shape[0] subidx = [n - 2, n - 1] # top two eigenpairs eigvals, eigvecs = _host_partial_eigh(centered, subidx) # Results should live on the original backend/device. self.assert_type_preserved(eigvals, xp, device) self.assert_type_preserved(eigvecs, xp, device) # And match a direct scipy call on the numpy reference. from scipy.linalg import eigh as scipy_eigh exp_vals, exp_vecs = scipy_eigh(centered_np, subset_by_index=subidx) self.assert_close(eigvals, exp_vals) # Eigenvectors can differ by sign; compare |vecs|. self.assert_close(xp.abs(eigvecs), np.abs(exp_vecs)) class TestFSVDBackends(TestCase, ArrayAPITestMixin): @array_backends("numpy", "jax", "torch", "cupy") def test_fsvd_shape_and_backend(self, xp, device): centered_np = center_distance_matrix(np.asarray(_DM, dtype=np.float64)) centered = self.make_array(xp, device, centered_np.tolist()) dims = 2 eigvals, eigvecs = _fsvd(centered, dimensions=dims, seed=42) self.assert_type_preserved(eigvals, xp, device) self.assert_type_preserved(eigvecs, xp, device) self.assertEqual(tuple(eigvals.shape), (dims,)) self.assertEqual(tuple(eigvecs.shape), (centered_np.shape[0], dims)) @array_backends("numpy", "jax", "torch", "cupy") def test_fsvd_matches_numpy(self, xp, device): # Same seed on both paths → same (up to sign) subspace. centered_np = center_distance_matrix(np.asarray(_DM, dtype=np.float64)) dims = 2 ref_vals, ref_vecs = _fsvd(centered_np, dimensions=dims, seed=0) centered = self.make_array(xp, device, centered_np.tolist()) res_vals, res_vecs = _fsvd(centered, dimensions=dims, seed=0) # Eigenvalues are unique; eigenvectors can flip sign per column. self.assert_close(res_vals, ref_vals, rtol=1e-5, atol=1e-5) self.assert_close(xp.abs(res_vecs), np.abs(ref_vecs), rtol=1e-5, atol=1e-5) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/test_redundancy_analysis.py000066400000000000000000000243161520735541300316060ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np import numpy.testing as npt import pandas as pd from unittest import TestCase, main from skbio import OrdinationResults from skbio.stats.ordination import rda from skbio.util import get_data_path, assert_ordination_results_equal class TestRDAErrors(TestCase): def setUp(self): pass def test_shape(self): for n, p, n_, m in [(3, 4, 2, 1), (3, 4, 3, 10)]: Y = pd.DataFrame(np.random.randn(n, p)) X = pd.DataFrame(np.random.randn(n_, m)) with self.assertRaises(ValueError): rda(Y, X, None, None) class TestRDAResults(TestCase): # STATUS: L&L only shows results with scaling 1, and they agree # with vegan's (module multiplying by a constant). I can also # compute scaling 2, agreeing with vegan, but there are no written # results in L&L. def setUp(self): """Data from table 11.3 in Legendre & Legendre 1998.""" self.sample_ids = ['Site0', 'Site1', 'Site2', 'Site3', 'Site4', 'Site5', 'Site6', 'Site7', 'Site8', 'Site9'] self.feature_ids = ['Species0', 'Species1', 'Species2', 'Species3', 'Species4', 'Species5'] self.env_ids = list(map(str, range(4))) self.pc_ids = ['RDA1', 'RDA2', 'RDA3', 'RDA4', 'RDA5', 'RDA6', 'RDA7'] self.Y = pd.DataFrame( np.loadtxt(get_data_path('example2_Y')), index=self.sample_ids, columns=self.feature_ids) self.X = pd.DataFrame( np.loadtxt(get_data_path('example2_X')), index=self.sample_ids, columns=self.env_ids) def test_scaling1(self): scores = rda(self.Y, self.X, scaling=1) sample_constraints = pd.DataFrame(np.loadtxt( get_data_path('example2_sample_constraints_scaling1'))) # Load data as computed with vegan 2.0-8 vegan_features = pd.DataFrame( np.loadtxt(get_data_path( 'example2_species_scaling1_from_vegan')), index=self.feature_ids, columns=self.pc_ids) vegan_samples = pd.DataFrame( np.loadtxt(get_data_path( 'example2_site_scaling1_from_vegan')), index=self.sample_ids, columns=self.pc_ids) sample_constraints = pd.DataFrame( np.loadtxt(get_data_path( 'example2_sample_constraints_scaling1')), index=self.sample_ids, columns=self.pc_ids) mat = np.loadtxt(get_data_path( 'example2_biplot_scaling1')) cropped_pc_ids = self.pc_ids[:mat.shape[1]] biplot_scores = pd.DataFrame(mat, index=self.env_ids, columns=cropped_pc_ids) proportion_explained = pd.Series([0.44275783, 0.25614586, 0.15280354, 0.10497021, 0.02873375, 0.00987052, 0.00471828], index=self.pc_ids) eigvals = pd.Series([25.897954, 14.982578, 8.937841, 6.139956, 1.680705, 0.577350, 0.275984], index=self.pc_ids) exp = OrdinationResults( 'RDA', 'Redundancy Analysis', samples=vegan_samples, features=vegan_features, sample_constraints=sample_constraints, biplot_scores=biplot_scores, proportion_explained=proportion_explained, eigvals=eigvals) assert_ordination_results_equal(scores, exp, ignore_directionality=True, decimal=6) def test_scaling2(self): scores = rda(self.Y, self.X, scaling=2) mat = np.loadtxt(get_data_path('example2_biplot_scaling2')) cropped_pc_ids = self.pc_ids[:mat.shape[1]] biplot_scores = pd.DataFrame(mat, index=self.env_ids, columns=cropped_pc_ids) sample_constraints = pd.DataFrame(np.loadtxt( get_data_path('example2_sample_constraints_scaling2'))) # Load data as computed with vegan 2.0-8 vegan_features = pd.DataFrame( np.loadtxt(get_data_path( 'example2_species_scaling2_from_vegan')), index=self.feature_ids, columns=self.pc_ids) vegan_samples = pd.DataFrame( np.loadtxt(get_data_path( 'example2_site_scaling2_from_vegan')), index=self.sample_ids, columns=self.pc_ids) sample_constraints = pd.DataFrame( np.loadtxt(get_data_path( 'example2_sample_constraints_scaling2')), index=self.sample_ids, columns=self.pc_ids) mat = np.loadtxt(get_data_path( 'example2_biplot_scaling2')) cropped_pc_ids = self.pc_ids[:mat.shape[1]] biplot_scores = pd.DataFrame(mat, index=self.env_ids, columns=cropped_pc_ids) proportion_explained = pd.Series([0.44275783, 0.25614586, 0.15280354, 0.10497021, 0.02873375, 0.00987052, 0.00471828], index=self.pc_ids) eigvals = pd.Series([25.897954, 14.982578, 8.937841, 6.139956, 1.680705, 0.577350, 0.275984], index=self.pc_ids) exp = OrdinationResults( 'RDA', 'Redundancy Analysis', samples=vegan_samples, features=vegan_features, sample_constraints=sample_constraints, biplot_scores=biplot_scores, proportion_explained=proportion_explained, eigvals=eigvals) assert_ordination_results_equal(scores, exp, ignore_directionality=True, decimal=6) class TestRDAResults_biplot_score(TestCase): # STATUS: L&L only shows results with scaling 1, and they agree # with vegan's (module multiplying by a constant). I can also # compute scaling 2, agreeing with vegan, but there are no written # results in L&L. def setUp(self): """varespec and varechem from Väre etal. 1995 DOI: 10.2307/3236351""" self.Y = pd.read_csv(get_data_path('varespec.csv'), index_col=0) self.X = pd.read_csv(get_data_path('varechem.csv'), index_col=0) self.Y.index.name = None self.X.index.name = None def test_biplot_score(self): rda_ = rda(y=self.Y, x=self.X, scale_Y=False, scaling=1) # Load data as computed with vegan 2.4-3: # library(vegan) # data(varechem) # data(varespec) # rda_ = rda(X=varespec, Y=varechem, scale=FALSE) # write.table(summary(rda_, scaling=1)$biplot, # 'vare_rda_biplot_from_vegan.csv', sep=',') # write.table(summary(rda_, scaling=1)$sites, # 'vare_rda_sites_from_vegan.csv', sep=',') # write.table(summary(rda_, scaling=1)$species, # 'vare_rda_species_from_vegan.csv', sep=',') # write.table(summary(rda_, scaling=1)$constraints, # # 'vare_rda_constraints_from_vegan.csv', sep=',') # write.table(summary(rda_, scaling=1)$cont$importance[2, ], # 'vare_rda_propexpl_from_vegan.csv', sep=',') # write.table(summary(rda_, scaling=1)$cont$importance[1, ], # 'vare_rda_eigvals_from_vegan.csv', sep=',') vegan_features = pd.read_csv( get_data_path('vare_rda_species_from_vegan.csv')) vegan_samples = pd.read_csv( get_data_path('vare_rda_sites_from_vegan.csv')) vegan_biplot = pd.read_csv( get_data_path('vare_rda_biplot_from_vegan.csv')) vegan_constraints = pd.read_csv( get_data_path('vare_rda_constraints_from_vegan.csv')) vegan_propexpl = pd.read_csv( get_data_path('vare_rda_propexpl_from_vegan.csv')) vegan_propexpl = pd.Series( vegan_propexpl.x.values, index=rda_.eigvals.index) vegan_eigvals = pd.read_csv( get_data_path('vare_rda_eigvals_from_vegan.csv')) vegan_eigvals = pd.Series( vegan_eigvals.x.values, index=rda_.eigvals.index) # scikit-bio returns singular values, whereas vegan returns eigenvalues vegan_eigvals = np.sqrt(vegan_eigvals*vegan_eigvals.shape[0]) vegan_propexpl = vegan_eigvals/vegan_eigvals.sum() # transform the output of rda_ to match column selection of vegan res_samples = rda_.samples.iloc[:, 0:6] res_features = rda_.features.iloc[:, 0:6] rda_ = OrdinationResults( 'RDA', 'Redundancy Analysis', samples=res_samples, features=res_features, sample_constraints=rda_.sample_constraints.iloc[:, 0:6], biplot_scores=rda_.biplot_scores.iloc[:, 0:6], proportion_explained=rda_.proportion_explained, eigvals=rda_.eigvals) exp = OrdinationResults( 'RDA', 'Redundancy Analysis', samples=vegan_samples, features=vegan_features, sample_constraints=vegan_constraints, biplot_scores=vegan_biplot, proportion_explained=vegan_propexpl, eigvals=vegan_eigvals) # This scaling constant is required to make skbio comparable to vegan. scaling = (rda_.eigvals.iloc[0] / rda_.eigvals.iloc[:6]) exp.biplot_scores *= scaling assert_ordination_results_equal( rda_, exp, ignore_directionality=True, decimal=6) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/ordination/tests/test_util.py000066400000000000000000000113551520735541300265230ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import copy import numpy as np import numpy.testing as npt from skbio.stats.ordination import corr, mean_and_std, e_matrix, f_matrix, \ center_distance_matrix from skbio.stats.ordination._utils import _e_matrix_inplace, _f_matrix_inplace class TestUtils(TestCase): def setUp(self): self.x = np.array([[1, 2, 3], [4, 5, 6]]) self.y = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) self.matrix = np.arange(1, 7).reshape(2, 3) self.matrix2 = np.arange(1, 10).reshape(3, 3) self.small_mat = np.array([[7, 5, 5], [4, 4, 9], [7, 5, 3]]) self.dist_mat = np.asarray([[0., 7., 5., 5.], [7., 0., 4., 9.], [5., 4., 0., 3.], [5., 9., 3., 0.]], dtype=np.float64) self.dist_mat_fp32 = np.asarray([[0., 7., 5., 5.], [7., 0., 4., 9.], [5., 4., 0., 3.], [5., 9., 3., 0.]], dtype=np.float32) def test_mean_and_std(self): obs = mean_and_std(self.x) npt.assert_almost_equal((3.5, 1.707825127), obs) obs = mean_and_std(self.x, with_std=False) self.assertEqual((3.5, None), obs) obs = mean_and_std(self.x, ddof=2) npt.assert_almost_equal((3.5, 2.091650066), obs) def test_mean_and_std_no_mean_no_std(self): with npt.assert_raises(ValueError): mean_and_std(self.x, with_mean=False, with_std=False) def test_corr(self): obs = corr(self.small_mat) npt.assert_almost_equal(np.array([[1, 1, -0.94491118], [1, 1, -0.94491118], [-0.94491118, -0.94491118, 1]]), obs) def test_corr_shape_mismatch(self): with npt.assert_raises(ValueError): corr(self.x, self.y) def test_e_matrix(self): E = e_matrix(self.matrix) expected_E = np.array([[-0.5, -2., -4.5], [-8., -12.5, -18.]]) npt.assert_almost_equal(E, expected_E) def test_f_matrix(self): F = f_matrix(self.matrix2) expected_F = np.zeros((3, 3)) # Note that `test_make_F_matrix` in cogent is wrong npt.assert_almost_equal(F, expected_F) def test_e_matrix_inplace(self): E = _e_matrix_inplace(self.matrix) expected_E = np.array([[-0.5, -2., -4.5], [-8., -12.5, -18.]]) npt.assert_almost_equal(E, expected_E) def test_f_matrix_inplace(self): F = _f_matrix_inplace(self.matrix2) expected_F = np.zeros((3, 3)) npt.assert_almost_equal(F, expected_F) def test_center_distance_matrix_inplace(self): dm_expected = f_matrix(e_matrix(self.dist_mat)) # make copy of matrix to test inplace centering matrix_copy = copy.deepcopy(self.dist_mat) dm_centered = center_distance_matrix(matrix_copy, inplace=False) # ensure that matrix_copy was NOT modified inplace self.assertTrue(np.array_equal(matrix_copy, self.dist_mat)) # and ensure that the result of centering was correct npt.assert_almost_equal(dm_expected, dm_centered) # next, sort same matrix inplace matrix_copy2 = copy.deepcopy(self.dist_mat) dm_centered_inp = center_distance_matrix(matrix_copy2, inplace=True) # and ensure that the result of inplace centering was correct npt.assert_almost_equal(dm_expected, dm_centered_inp) def test_center_distance_matrix_single(self): dm_expected = f_matrix(e_matrix(self.dist_mat_fp32)) # make copy of matrix to test inplace centering matrix_copy = copy.deepcopy(self.dist_mat_fp32) dm_centered = center_distance_matrix(matrix_copy, inplace=False) # ensure that matrix_copy was NOT modified inplace self.assertTrue(np.array_equal(matrix_copy, self.dist_mat_fp32)) # and ensure that the result of centering was correct npt.assert_almost_equal(dm_expected, dm_centered) # next, sort same matrix inplace matrix_copy2 = copy.deepcopy(self.dist_mat_fp32) dm_centered_inp = center_distance_matrix(matrix_copy2, inplace=True) # and ensure that the result of inplace centering was correct npt.assert_almost_equal(dm_expected, dm_centered_inp) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/power.py000066400000000000000000001346741520735541300223450ustar00rootroot00000000000000r"""Empirical Power Estimation (:mod:`skbio.stats.power`) ===================================================== .. currentmodule:: skbio.stats.power The purpose of this module is to provide empirical, post-hoc power estimation of normally and non-normally distributed data. It also provides support to subsample data to facilitate this analysis. The underlying principle is based on subsampling and Monte Carlo simulation. Assume that there is some set of populations, :math:`K_{1}, K_{2}, ... K_{n}` which have some property, :math:`\mu` such that :math:`\mu_{1} \neq \mu_{2} \neq ... \neq \mu_{n}`. For each of the populations, a sample, :math:`S` can be drawn, with a parameter, :math:`x` where :math:`x \approx \mu` and for the samples, we can use a test, :math:`f`, to show that :math:`x_{1} \neq x_{2} \neq ... \neq x_{n}`. Since we know that :math:`\mu_{1} \neq \mu_{2} \neq ... \neq \mu_{n}`, we know we should reject the null hypothesis. If we fail to reject the null hypothesis, we have committed a Type II error and our result is a false negative. We can estimate the frequency of Type II errors at various sampling depths by repeatedly subsampling the populations and observing how often we see a false negative. If we repeat this several times for each subsampling depth, and vary the depths we use, we can start to approximate a relationship between the number of samples we use and the rate of false negatives, also called the statistical power of the test. To generate complete power curves from data which appears underpowered, the :mod:`statsmodels.stats.power` module can be used to solve for an effect size. The effect size can be used to extrapolate a power curve for the data. Most functions in this module accept a statistical test function which takes a list of samples and returns a p value. The test is then evaluated over a series of subsamples. Sampling may be handled in two ways. For any set of samples, we may simply choose to draw :math:`n` observations at random for each sample. Alternatively, if metadata is available, samples can be matched based on a set of control categories so that paired samples are drawn at random from the set of available matches. Functions --------- .. autosummary:: :toctree: subsample_power subsample_paired_power confidence_bound paired_subsamples Examples -------- Suppose we wanted to test that there's a relationship between two random variables, ``ind`` and ``dep``. Let's use random subsampling to estimate the statistical power of our test with an alpha of 0.1, 0.01, and 0.001. We will use a random seed to ensure the reproducibility of results. >>> import numpy as np >>> rng = np.random.default_rng(42) >>> ind = rng.integers(0, 20, 15) >>> ind # doctest: +ELLIPSIS array([ 1, 15, 13, 8, 8, 17, 1, 13, 4, 1, 10, 19, 14, 15, 14]... >>> dep = (3 * ind + 5 + rng.standard_normal(15) * 5).round(3) >>> dep array([ 7.916, 45.735, 48.397, 32.889, 29.33 , 61.636, 10.338, 39.704, 18.844, 3.206, 39.392, 61.75 , 46.076, 46.595, 53.113]) Let's define a test that will draw a list of sample pairs and determine if they're correlated. We'll use :func:`scipy.stats.pearsonr` which takes two arrays and returns a correlation coefficient and a p-value representing the probability the two distributions are correlated. >>> from scipy.stats import pearsonr >>> f = lambda x: pearsonr(*x).pvalue Now, let's use random sampling to estimate the power of our test on the first distribution. >>> samples = [ind, dep] >>> print('{:.3e}'.format(f(samples))) 1.606e-10 In :func:`subsample_power`, we can maintain a paired relationship between samples by setting ``draw_mode`` to "matched". We can also set our critical value, so that we estimate power for a critical value of :math:`\alpha = 0.05`, an estimate for the critical value of 0.01, and a critical value of 0.001. >>> from skbio.stats.power import subsample_power >>> pwr_100, counts_100 = subsample_power( ... test=f, samples=samples, max_counts=10, min_counts=3, counts_interval=1, ... draw_mode='matched', alpha_pwr=0.1, num_iter=25, seed=rng) >>> counts_100 array([3, 4, 5, 6, 7, 8, 9]) >>> pwr_100.mean(0) array([ 0.512, 0.936, 0.984, 1. , 1. , 1. , 1. ]) >>> pwr_010, counts_010 = subsample_power( ... test=f, samples=samples, max_counts=10, min_counts=3, counts_interval=1, ... draw_mode='matched', alpha_pwr=0.01, num_iter=25, seed=rng) >>> pwr_010.mean(0) array([ 0.072, 0.416, 0.888, 0.964, 1. , 0.996, 1. ]) >>> pwr_001, counts_001 = subsample_power( ... test=f, samples=samples, max_counts=10, min_counts=3, counts_interval=1, ... draw_mode='matched', alpha_pwr=0.001, num_iter=25, seed=rng) >>> pwr_001.mean(0) array([ 0. , 0.044, 0.204, 0.796, 0.948, 0.996, 1. ]) Based on this power estimate, as we increase our confidence that we have not committed a type I error and identified a false positive, the number of samples we need to be confident that we have not committed a type II error increases. """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import collections import copy import numpy as np import pandas as pd import scipy.stats from skbio.util import get_rng def subsample_power( test, samples, draw_mode="ind", alpha_pwr=0.05, ratio=None, max_counts=50, counts_interval=10, min_counts=None, num_iter=500, num_runs=10, seed=None, ): r"""Subsample data to iteratively calculate power. Parameters ---------- test : function The statistical test which accepts a list of arrays of values (sample ids or numeric values) and returns a p value or one-dimensional array of p values. samples : array_like `samples` can be a list of lists or a list of arrays where each sublist or row in the array corresponds to a sampled group. draw_mode : {"ind", "matched"}, optional "matched" samples should be used when observations in samples have corresponding observations in other groups. For instance, this may be useful when working with regression data where :math:`x_{1}, x_{2}, ..., x_{n}` maps to :math:`y_{1}, y_{2}, ..., y_{n}`. Sample vectors must be the same length in "matched" mode. If there is no reciprocal relationship between samples, then "ind" mode should be used. alpha_pwr : float, optional The critical value used to calculate the power. ratio : 1-D array, optional The fraction of the sample counts which should be assigned to each group. If this is a 1-D array, it must be the same length as `samples`. If no value is supplied (`ratio` is None), then an equal number of observations will be drawn for each sample. In `matched` mode, this will be set to one. max_counts : positive int, optional The maximum number of samples per group to draw for effect size calculation. counts_interval : positive int, optional The difference between each subsampling count. min_counts : positive int, optional How many samples should be drawn for the smallest subsample. If this is None, the `counts_interval` will be used. num_iter : positive int, optional The number of p-values to generate for each point on the curve. num_runs : positive int, optional The number of times to calculate each curve. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- power : array The power calculated for each subsample at each count. The array has `num_runs` rows, a length with the same number of elements as `sample_counts` and a depth equal to the number of p values returned by `test`. If `test` returns a float, the returned array will be two-dimensional instead of three. sample_counts : array The number of samples drawn at each power calculation. Raises ------ ValueError If the `mode` is "matched", an error will occur if the arrays in `samples` are not the same length. ValueError There is a ValueError if there are fewer samples than the minimum count. ValueError If the `counts_interval` is greater than the difference between the sample start and the max value, the function raises a ValueError. ValueError There are not an equal number of groups in `samples` and in `ratios`. TypeError `test` does not return a float or a 1-dimensional numpy array. Examples -------- Let's say we wanted to look at the relationship between the presence of a specific bacteria, *Gardnerella vaginalis* in the vaginal community, and the probability of a pre or post menopausal woman experiencing a urinary tract infection (UTI). Healthy women were enrolled in the study either before or after menopause, and followed for eight weeks. Participants submitted fecal samples at the beginning of the study, and were then followed for clinical symptoms of a UTI. A confirmed UTI was an endpoint in the study. Using available literature and 16S sequencing, a set of candidate taxa were identified as correlated with UTIs, including *G. vaginalis*. In the 100 women (50 premenopausal and 50 postmenopausal samples) who had UTIs, the presence or absence of *G. vaginalis* was confirmed with quantitative PCR. We can model the probability that detectable *G. vaginalis* was found in these samples using a binomial model. (*Note that this is a simulation.*) >>> import numpy as np >>> rng = np.random.default_rng(123) >>> pre_rate = rng.binomial(1, 0.85, size=50) >>> print(pre_rate.sum()) 42 >>> pos_rate = rng.binomial(1, 0.40, size=50) >>> print(pos_rate.sum()) 16 Let's set up a test function, so we can test the probability of finding a difference in frequency between the two groups. We'll use :func:`scipy.stats.chisquare` to look for the difference in frequency between groups. >>> from scipy.stats import chisquare >>> test = lambda x: chisquare(np.array([x[i].sum() for i in ... range(len(x))])).pvalue Let's make sure that our two distributions are different. >>> print('{:.5f}'.format(test([pre_rate, pos_rate]))) 0.00064 Since there are an even number of samples, and we don't have enough information to try controlling the data, we'll use :func:`subsample_power` to compare the two groups. If we had metadata about other risk factors, like a reproductive history, BMI, tobacco use, we might want to use :func:`subsample_paired_power`. We'll also use "ind" ``draw_mode``, since there is no linkage between the two groups of samples. >>> from skbio.stats.power import subsample_power >>> pwr_est, counts = subsample_power( ... test=test, samples=[pre_rate, pos_rate], num_iter=100, num_runs=5, ... counts_interval=5, seed=rng) >>> counts array([ 5, 10, 15, 20, 25, 30, 35, 40, 45]) >>> np.nanmean(pwr_est, axis=0) # doctest: +NORMALIZE_WHITESPACE array([ 0.11 , 0.19 , 0.45 , 0.684, 0.874, 0.964, 1. , 1. , 1. ]) >>> counts[np.nanmean(pwr_est, axis=0) > 0.8].min() 25 So, we can estimate that we will see a significant difference in the presence of *G. vaginalis* in the stool of pre and post women with UTIs if we have at least 25 samples per group. If we wanted to test the relationship of a second candidate taxa which is more rare in the population, but may have a similar effect, based on available literature, we might also start by trying to identify 25 samples per group where the second candidate taxa is present. Suppose, now, that we want to test that a secondary metabolite seen only in the presence of *G vaginalis* to see if it is also correlated with UTIs. We can model the abundance of the metabolite as a normal distribution. >>> met_pos = (rng.standard_normal(pre_rate.sum() + pos_rate.sum()) * ... 2000 + 2500) >>> met_pos[met_pos < 0] = 0 >>> met_neg = met_neg = (rng.standard_normal(100 - (pre_rate.sum() + ... pos_rate.sum())) * 2000 + 500) >>> met_neg[met_neg < 0] = 0 Let's compare the populations with a kruskal-wallis test. Physically, there cannot be a negative concentration of a chemical, so we've set the lower bound at 0. This means that we can no longer assume our distribution is normal. >>> from scipy.stats import kruskal >>> test2 = lambda x: kruskal(*x).pvalue >>> print('{:.3e}'.format(test2([met_pos, met_neg]))) 9.783e-06 When we go to perform the statistical test on all the data, you might notice that there are twice as many samples from women with *G. vaginalis* than those without. It might make sense to account for this difference when we're testing power. So, we're going to set the ``ratio`` parameter, which lets us draw twice as many samples from women with *G. vaginalis*. >>> pwr_est2, counts2 = subsample_power( ... test=test2, samples=[met_pos, met_neg], counts_interval=5, ... num_iter=100, num_runs=5, ratio=[2, 1], seed=rng) >>> counts2 array([ 5., 10., 15., 20., 25.]) >>> np.nanmean(pwr_est2, axis=0) array([ 0.388, 0.688, 0.898, 0.986, 1. ]) >>> counts2[np.nanmean(pwr_est2, axis=0) > 0.8].min() 15.0 When we consider the number of samples per group needed in the power analysis, we need to look at the ratio. The analysis says that we need 25 samples in the smallest group, in this case, the group of women without *G. vaginalis* and 50 samples from women with *G. vaginalis* to see a significant difference in the abundance of our secondary metabolite at 80% power. """ # Checks the inputs ratio, num_p, sample_counts = _check_subsample_power_inputs( test=test, samples=samples, draw_mode=draw_mode, ratio=ratio, min_counts=min_counts, max_counts=max_counts, counts_interval=counts_interval, ) # Preallocates the power array power = np.zeros((num_runs, len(sample_counts), num_p)) rng = get_rng(seed) # Calculates the power instances for id2, c in enumerate(sample_counts): count = np.round(c * ratio, 0).astype(int) for id1 in range(num_runs): ps = _compare_distributions( test=test, samples=samples, num_p=num_p, counts=count, num_iter=num_iter, mode=draw_mode, seed=rng, ) power[id1, id2, :] = _calculate_power(ps, alpha_pwr) power = power.squeeze() return power, sample_counts def subsample_paired_power( test, meta, cat, control_cats, order=None, strict_match=True, alpha_pwr=0.05, max_counts=50, counts_interval=10, min_counts=None, num_iter=500, num_runs=10, seed=None, ): r"""Estimate power iteratively using samples with matching metadata. Parameters ---------- test : function The statistical test which accepts a list of arrays sample ids and returns a p-value. meta : pandas.DataFrame The metadata associated with the samples. cat : str The metadata category being varied between samples. control_cats : list The metadata categories to be used as controls. For example, if you wanted to vary age (`cat` = "AGE"), you might want to control for gender and health status (i.e. `control_cats` = ["SEX", "HEALTHY"]). order : list, optional The order of groups in the category. This can be used to limit the groups selected. For example, if there's a category with groups 'A', 'B' and 'C', and you only want to look at A vs B, `order` would be set to ['A', 'B']. strict_match : bool, optional This determines how data is grouped using `control_cats`. If a sample within `meta` has an undefined value (NaN) for any of the columns in `control_cats`, the sample will not be considered as having a match and will be ignored when `strict_match` is True. If `strict_match` is False, missing values (NaN) in the `control_cats` can be considered matches. alpha_pwr : float, optional The critical value used to calculate the power. max_counts : positive int, optional The maximum number of observations per sample to draw for effect size calculation. counts_interval : positive int, optional The difference between each subsampling count. min_counts : positive int, optional How many samples should be drawn for the smallest subsample. If this is None, the `counts_interval` will be used. num_iter : positive int, optional The number of p-values to generate for each point on the curve. num_runs : positive int, optional The number of times to calculate each curve. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- power : array The power calculated for each subsample at each count. The array is `num_runs` rows, a length with the same number of elements as `sample_counts` and a depth equal to the number of p values returned by `test`. If `test` returns a float, the returned array will be two-dimensional instead of three. sample_counts : array The number of samples drawn at each power calculation. Raises ------ ValueError There is a ValueError if there are fewer samples than the minimum count. ValueError If the `counts_interval` is greater than the difference between the sample start and the max value, the function raises a ValueError. TypeError `test` does not return a float or a 1-dimensional numpy array. Examples -------- Assume you are interested in the role of a specific cytokine of protein translocation in myeloid-lineage cells. You are able to culture two macrophage lineages (bone marrow derived phagocytes and peritoneally-derived macrophages). Due to unfortunate circumstances, your growth media must be acquired from multiple sources (lab, company A, company B). Also unfortunate, you must use labor-intensive low throughput assays. You have some preliminary measurements, and you'd like to predict how many (more) cells you need to analyze for 80% power. You have information about 60 cells, which we'll simulate below. Note that we are setting a random seed value for consistency. >>> import numpy as np >>> import pandas as pd >>> rng = np.random.default_rng(123) >>> data = pd.DataFrame.from_dict({ ... 'CELL_LINE': rng.binomial(1, 0.5, size=(60,)), ... 'SOURCE': rng.binomial(2, 0.33, size=(60,)), ... 'TREATMENT': np.hstack((np.zeros((30)), np.ones((30)))), ... 'INCUBATOR': rng.binomial(1, 0.2, size=(60,))}) >>> data['OUTCOME'] = (0.25 + data.TREATMENT * 0.25) + \ ... rng.standard_normal(60) * (0.1 + data.SOURCE/10 + data.CELL_LINE/5) >>> data.loc[data.OUTCOME < 0, 'OUTCOME'] = 0 >>> data.loc[data.OUTCOME > 1, 'OUTCOME'] = 1 We will approach this by assuming that the distribution of our outcome is not normally distributed, and apply a kruskal-wallis test to compare between the cytokine treated and untreated cells. >>> from scipy.stats import kruskal >>> f = lambda x: kruskal(*[data.loc[i, 'OUTCOME'] for i in x]).pvalue Let's check that cytokine treatment has a significant effect across all the cells. >>> treatment_stat = [g for g in data.groupby('TREATMENT').groups.values()] >>> print('{:.5f}'.format(f(treatment_stat))) 0.00176 Now, let's pick the control categories. It seems reasonable to assume there may be an effect of cell line on the treatment outcome, which may be attributed to differences in receptor expression. It may also be possible that there are differences due cytokine source. Incubators were maintained under the same conditions throughout the experiment, within one degree of temperature difference at any given time, and the same level of CO2. So, at least initially, let's ignore differences due to the incubator. It's recommended that as a first pass analysis, control variables be selected based on an idea of what may be biologically relevant to the system, although further iteration might encourage the consideration of variable with effect sizes similar, or larger than the variable of interest. >>> control_cats = ['SOURCE', 'CELL_LINE'] >>> from skbio.stats.power import subsample_paired_power >>> pwr, cnt = subsample_paired_power( ... test=f, meta=data, cat='TREATMENT', control_cats=control_cats, ... counts_interval=5, num_iter=25, num_runs=5, seed=rng) >>> cnt array([ 5., 10., 15., 20.]) >>> pwr.mean(0) array([ 0.272, 0.52 , 0.712, 0.952]) >>> pwr.std(0).round(3) array([ 0.069, 0.057, 0.053, 0.039]) Estimating off the power curve, it looks like 20 cells per group may provide adequate power for this experiment, although the large variance in power might suggest extending the curves or increasing the number of samples per group. """ # Handles the order argument if order is None: order = sorted(meta.groupby(cat).groups.keys()) order = np.array(order) rng = get_rng(seed) # Checks for the number of sampling pairs available meta_pairs, index = _identify_sample_groups( meta, cat, control_cats, order, strict_match ) min_obs = min( [ _get_min_size(meta, cat, control_cats, order, strict_match), np.floor(len(index) * 0.9), ] ) sub_ids = _draw_paired_samples(meta_pairs, index, min_obs, rng) ratio, num_p, sample_counts = _check_subsample_power_inputs( test=test, samples=sub_ids, draw_mode="matched", min_counts=min_counts, max_counts=max_counts, counts_interval=counts_interval, ) # Preallocates the power array power = np.zeros((num_runs, len(sample_counts), num_p)) # Calculates power instances for id2, c in enumerate(sample_counts): for id1 in range(num_runs): ps = np.zeros((num_p, num_iter)) for id3 in range(num_iter): subs = _draw_paired_samples(meta_pairs, index, c, rng) ps[:, id3] = test(subs) power[id1, id2, :] = _calculate_power(ps, alpha_pwr) power = power.squeeze() return power, sample_counts def confidence_bound(vec, alpha=0.05, df=None, axis=None): r"""Calculate a confidence bound assuming a normal distribution. Parameters ---------- vec : array_like The array of values to use in the bound calculation. alpha : float, optional The critical value, used for the confidence bound calculation. df : float, optional The degrees of freedom associated with the distribution. If None is given, df is assumed to be the number of elements in specified axis. axis : positive int, optional The axis over which to take the deviation. When axis is None, a single value will be calculated for the whole matrix. Returns ------- bound : float The confidence bound around the mean. The confidence interval is [mean - bound, mean + bound]. """ # Determines the number of non-nan counts vec = np.asarray(vec) vec_shape = vec.shape if axis is None and len(vec_shape) == 1: num_counts = vec_shape[0] - np.isnan(vec).sum() elif axis is None: num_counts = vec_shape[0] * vec_shape[1] - np.isnan(vec).sum() else: num_counts = vec_shape[axis] - np.isnan(vec).sum() / ( vec_shape[0] * vec_shape[1] ) # Gets the df if not supplied if df is None: df = num_counts - 1 # Calculates the bound # In the conversion from scipy.stats.nanstd -> np.nanstd `ddof=1` had to be # added to match the scipy default of `bias=False`. bound = ( np.nanstd(vec, axis=axis, ddof=1) / np.sqrt(num_counts - 1) * scipy.stats.t.ppf(1 - alpha / 2, df) ) return bound def paired_subsamples( meta, cat, control_cats, order=None, strict_match=True, seed=None ): r"""Draw a list of samples varied by `cat` and matched for `control_cats`. This function is designed to provide controlled samples, based on a metadata category. For example, one could control for age, sex, education level, and diet type while measuring exercise frequency. Parameters ---------- meta : pandas.DataFrame The metadata associated with the samples. cat : str, list The metadata category (or a list of categories) for comparison. control_cats : list The metadata categories to be used as controls. For example, if you wanted to vary age (`cat` = "AGE"), you might want to control for gender and health status (i.e. `control_cats` = ["SEX", "HEALTHY"]) order : list, optional The order of groups in the category. This can be used to limit the groups selected. For example, if there's a category with groups 'A', 'B' and 'C', and you only want to look at A vs B, `order` would be set to ['A', 'B']. strict_match: bool, optional This determines how data is grouped using `control_cats`. If a sample within `meta` has an undefined value (`NaN`) for any of the columns in `control_cats`, the sample will not be considered as having a match and will be ignored when `strict_match` is True. If `strict_match` is False, missing values (NaN) in the `control_cats` can be considered matches. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. versionadded:: 0.6.3 Returns ------- ids : array a set of ids which satisfy the criteria. These are not grouped by `cat`. An empty array indicates there are no sample ids which satisfy the requirements. Examples -------- If we have a mapping file for a set of random individuals looking at housing, sex, age and antibiotic use. >>> import pandas as pd >>> import numpy as np >>> meta = {'SW': {'HOUSING': '2', 'SEX': 'M', 'AGE': np.nan, 'ABX': 'Y'}, ... 'TS': {'HOUSING': '2', 'SEX': 'M', 'AGE': '40s', 'ABX': 'Y'}, ... 'CB': {'HOUSING': '3', 'SEX': 'M', 'AGE': '40s', 'ABX': 'Y'}, ... 'BB': {'HOUSING': '1', 'SEX': 'M', 'AGE': '40s', 'ABX': 'Y'}} >>> meta = pd.DataFrame.from_dict(meta, orient="index") >>> meta #doctest: +SKIP ABX HOUSING AGE SEX BB Y 1 40s M CB Y 3 40s M SW Y 2 NaN M TS Y 2 40s M We may want to vary an individual's housing situation, while holding constant their age, sex and antibiotic use so we can estimate the effect size for housing, and later compare it to the effects of other variables. >>> from skbio.stats.power import paired_subsamples >>> ids = paired_subsamples(meta, 'HOUSING', ['SEX', 'AGE', 'ABX']) >>> np.hstack(ids) #doctest: +ELLIPSIS array(['BB', 'TS', 'CB']...) So, for this set of data, we can match TS, CB, and BB based on their age, sex, and antibiotic use. SW cannot be matched in either group because `strict_match` was true, and there is missing AGE data for this sample. """ # Handles the order argument if order is None: order = sorted(meta.groupby(cat).groups.keys()) order = np.array(order) # Checks the groups in the category min_obs = _get_min_size(meta, cat, control_cats, order, strict_match) # Identifies all possible subsamples meta_pairs, index = _identify_sample_groups( meta=meta, cat=cat, control_cats=control_cats, order=order, strict_match=strict_match, ) # Draws paired ids ids = _draw_paired_samples( meta_pairs=meta_pairs, index=index, num_samps=min_obs, seed=seed ) return ids def _get_min_size(meta, cat, control_cats, order, strict_match): """Determine the smallest group represented.""" if strict_match: all_cats = copy.deepcopy(control_cats) all_cats.append(cat) meta = meta[all_cats].dropna() return meta.groupby(cat).count().loc[order, control_cats[0]].min() def _check_nans(x, switch=False): r"""Return False if x is a nan and True is x is a string or number.""" if isinstance(x, str): return True elif isinstance(x, (float, int)): return not np.isnan(x) elif switch and isinstance(x, (list, tuple)) and np.nan in x: return False elif switch and isinstance(x, (list, tuple)): return True else: raise TypeError("input must be a string, float or a nan") def _calculate_power(p_values, alpha=0.05): r"""Calculate statistical power empirically. Parameters ---------- p_values : 1-D array A 1-D numpy array with the test results. alpha : float The critical value for the power calculation. Returns ------- power : float The empirical power, or the fraction of observed p values below the critical value. """ p_values = np.atleast_2d(p_values) w = (p_values < alpha).sum(axis=1) / p_values.shape[1] return w def _compare_distributions( test, samples, num_p, counts=5, mode="ind", num_iter=100, seed=None ): r"""Compare two distribution arrays iteratively. Parameters ---------- test : function The statistical test which accepts an array_like of sample ids (list of lists) and returns a p-value. This can be a one-dimensional array, or a float. samples : list of arrays A list where each 1-d array represents a sample. If `mode` is "matched", there must be an equal number of observations in each sample. num_p : positive int, optional The number of p-values returned by the test. counts : positive int or 1-D array, optional The number of samples to draw from each distribution. If this is a 1-D array, the length must correspond to the number of samples. The function will not draw more observations than are in a sample. In "matched" `mode`, the same number of observations will be drawn from each group. mode : {"ind", "matched", "paired"}, optional "matched" samples should be used when observations in samples have corresponding observations in other groups. For instance, this may be useful when working with regression data where :math:`x_{1}, x_{2}, ..., x_{n}` maps to :math:`y_{1}, y_{2}, ... , y_{n}`. num_iter : positive int, optional Default 1000. The number of p-values to generate for each point on the curve. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. Returns ------- p_values : array The p-values for the subsampled tests. If `test` returned a single p value, p_values is a one-dimensional array. If `test` returned an array, `p_values` has dimensions `num_iter` x `num_p`. Raises ------ ValueError If mode is not "ind" or "matched". ValueError If the arrays in samples are not the same length in "matched" mode. ValueError If counts is a 1-D array and counts and samples are different lengths. """ # Preallocates the pvalue matrix p_values = np.zeros((num_p, num_iter)) # Determines the number of samples per group num_groups = len(samples) samp_lens = [len(sample) for sample in samples] if isinstance(counts, int): counts = np.array([counts] * num_groups) rng = get_rng(seed) for idx in range(num_iter): if mode == "matched": pos = rng.choice(np.arange(0, samp_lens[0]), counts[0], replace=False) subs = [sample[pos] for sample in samples] else: subs = [ rng.choice(np.array(pop), counts[i], replace=False) for i, pop in enumerate(samples) ] p_values[:, idx] = test(subs) if num_p == 1: p_values = p_values.squeeze() return p_values def _check_subsample_power_inputs( test, samples, draw_mode="ind", ratio=None, max_counts=50, counts_interval=10, min_counts=None, ): r"""Make sure that everything is sane before power calculations. Parameters ---------- test : function The statistical test which accepts a list of arrays of values (sample ids or numeric values) and returns a p value or one-dimensional array of p values. samples : array_like `samples` can be a list of lists or a list of arrays where each sublist or row in the array corresponds to a sampled group. draw_mode : {"ind", "matched"}, optional "matched" samples should be used when observations in samples have corresponding observations in other groups. For instance, this may be useful when working with regression data where :math:`x_{1}, x_{2}, ..., x_{n}` maps to :math:`y_{1}, y_{2}, ..., y_{n}`. Sample vectors must be the same length in "matched" mode. If there is no reciprocal relationship between samples, then "ind" mode should be used. ratio : 1-D array, optional The fraction of the sample counts which should be assigned to each group. If this is a 1-D array, it must be the same length as `samples`. If no value is supplied (`ratio` is None), then an equal number of observations will be drawn for each sample. In `matched` mode, this will be set to one. max_counts : positive int, optional The maximum number of samples per group to draw for effect size calculation. counts_interval : positive int, optional The difference between each subsampling count. min_counts : positive int, optional How many samples should be drawn for the smallest subsample. If this is None, the `counts_interval` will be used. Returns ------- ratio : 1-D array The fraction of the sample counts which should be assigned to each group. num_p : positive integer The number of p values returned by `test`. sample_counts : array The number of samples drawn at each power calculation. Raises ------ ValueError If the `mode` is "matched", an error will occur if the arrays in `samples` are not the same length. ValueError There is a ValueError if there are fewer samples than the minimum count. ValueError If the `counts_interval` is greater than the difference between the sample start and the max value, the function raises a ValueError. ValueError There are not an equal number of groups in `samples` and in `ratios`. TypeError `test` does not return a float or a 1-dimensional numpy array. """ if draw_mode not in {"ind", "matched"}: raise ValueError('mode must be "matched" or "ind".') # Determines the minimum number of ids in a category id_counts = np.array([len(id_) for id_ in samples]) num_ids = id_counts.min() # Determines the number of groups num_groups = len(samples) # Checks that "matched" mode is handled appropriately if draw_mode == "matched": for id_ in samples: if not len(id_) == num_ids: raise ValueError( "Each vector in samples must be the same " 'length in "matched" draw_mode.' ) # Checks the number of counts is appropriate if min_counts is None: min_counts = counts_interval if (max_counts - min_counts) < counts_interval: raise ValueError("No subsamples of the specified size can be drawn.") # Checks the ratio argument is sane if ratio is None or draw_mode == "matched": ratio = np.ones((num_groups)) else: ratio = np.asarray(ratio) if not ratio.shape == (num_groups,): raise ValueError("There must be a ratio for each group.") ratio_counts = np.array([id_counts[i] / ratio[i] for i in range(num_groups)]) largest = ratio_counts.min() # Determines the number of p values returned by the test p_return = test(samples) if isinstance(p_return, float): num_p = 1 elif isinstance(p_return, np.ndarray) and len(p_return.shape) == 1: num_p = p_return.shape[0] else: raise TypeError("test must return a float or one-dimensional array.") # Calculates the same counts sample_counts = np.arange(min_counts, min(max_counts, largest), counts_interval) return ratio, num_p, sample_counts def _identify_sample_groups(meta, cat, control_cats, order, strict_match): """Aggregate samples matches for `control_cats` that vary by `cat`. Parameters ---------- meta : pandas.DataFrame The metadata associated with the samples. cat : str, list The metadata category (or a list of categories) for comparison. control_cats : list The metadata categories to be used as controls. For example, if you wanted to vary age (`cat` = "AGE"), you might want to control for gender and health status (i.e. `control_cats` = ["SEX", "HEALTHY"]) order : list The order of groups in the category. This can be used to limit the groups selected. For example, if there's a category with groups 'A', 'B' and 'C', and you only want to look at A vs B, `order` would be set to ['A', 'B']. ctrl_pos : int The location of the smallest group in `order`. strict_match: bool, optional This determines how data is grouped using `control_cats`. If a sample within `meta` has an undefined value (`NaN`) for any of the columns in `control_cats`, the sample will not be considered as having a match and will be ignored when `strict_match` is True. If `strict_match` is False, missing values (NaN) in the `control_cats` can be considered matches. Returns ------- meta_pairs : dict Describes the categories matched for metadata. The `control_cat`-grouped samples are numbered, corresponding to the second list in `index`. The group is keyed to the list of sample arrays with the same length of `order`. index : list A list of numpy arrays describing the positions of samples to be drawn. The first array is an index array. The second gives an integer corresponding to the `control_cat`-group, and the third lists the position of the reference group sample in the list of samples. """ # Sets up variables to be filled meta_pairs = {} index = [] i1 = 0 # Groups the data by the control groups. # Avoid pandas 4 warning about single-element list keys. group_by = control_cats[0] if len(control_cats) == 1 else control_cats # TODO: pandas 3.0 changed NaN normalization. The strict_match=False # tests are skipped for pandas 3.0 until this is properly resolved. # See: test_power.py::test__identify_sample_groups_not_strict # test_power.py::test_paired_subsamples_not_strict ctrl_groups = meta.groupby(group_by).groups # Identifies the samples that satisfy the control pairs. Keys are iterated # in sorted order so that results don't change with different dictionary # ordering. for g in sorted(ctrl_groups, key=lambda k: str(k)): ids = ctrl_groups[g] # If strict_match, Skips over data that has nans if not _check_nans(g, switch=True) and strict_match: continue # Draws the samples that are matched for control cats m_ids = meta.loc[ids].groupby(cat).groups # Checks if samples from the cat groups are represented in those # Samples id_vecs = [sorted(m_ids[o]) for o in order if o in m_ids] # If all groups are represented, the index and results are retained if len(id_vecs) == len(order): min_vec = np.array([len(v) for v in id_vecs]) loc_vec = np.arange(0, min_vec.min()) meta_pairs[i1] = id_vecs index.append(np.zeros(loc_vec.shape) + i1) i1 += 1 # If the groups are not represented, an empty array gets passed else: index.append(np.array([])) # Converts index to a 1d array index = np.hstack(index) # If index is empty, sets up meta_paris with a no key. if not meta_pairs: meta_pairs["no"] = order return meta_pairs, index def _draw_paired_samples(meta_pairs, index, num_samps, seed=None): """Draw a random set of ids from a matched list. Parameters ---------- meta_pairs : dict Describes the categories matched for metadata. The `control_cat`-grouped samples are numbered, corresponding to the second list in `index`. The group is keyed to the list of sample arrays with the same length of `order`. index : list A list of numpy arrays describing the positions of samples to be drawn. The first array is an index array. The second gives an integer corresponding to the `control_cat`-group, and the third lists the position of the reference group sample in the list of samples. num_samps : int The number of samples. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. Returns ------- ids : list A set of randomly selected ids groups from each group. """ # Handles an empty paired vector if "no" in meta_pairs: return [np.array([]) for o in meta_pairs["no"]] rng = get_rng(seed) # Identifies the absolute positions of the control group being drawn set_pos = rng.choice(index, int(num_samps), replace=False).astype(int) subs = [] # Draws the other groups. Get a collection.Counter object for simplicity counter = collections.Counter(set_pos) # counter.items() order isn't guaranteed in python 3.6 and then the random # choice isn't reproducible between python version, even specifying seed; # so we access such values through sets. set_list = set(set_pos) # then, as stated by @RNAer, since we can't assure that items in sets are # ordered, we choose to order set_list before accessing values set_list = sorted(set_list) # now set_list is ordered and we can iterate over it to get counter obj for set_ in set_list: num_ = counter[set_] r2 = [rng.choice(col, num_, replace=False) for col in meta_pairs[set_]] subs.append(r2) ids = [np.hstack(ids) for ids in zip(*subs)] return ids def _calculate_power_curve( test, samples, sample_counts, ratio=None, mode="ind", num_iter=1000, alpha=0.05, seed=None, ): r"""Generate an empirical power curve for the samples. Parameters ---------- test : function The statistical test which accepts a list of arrays of values and returns a p value. samples : array_like `samples` can be a list of lists or an array where each sublist or row in the array corresponds to a sampled group. sample_counts : 1-D array A vector of the number of samples which should be sampled in each curve. mode : {"ind", "matched"}, optional "matched" samples should be used when observations in samples have corresponding observations in other groups. For instance, this may be useful when working with regression data where :math:`x_{1}, x_{2}, ..., x_{n}` maps to :math:`y_{1}, y_{2}, ... , y_{n}`. ratio : 1-D array, optional The fraction of the sample counts which should be assigned to each group. If this is a 1-D array, it must be the same length as `samples`. If no value is supplied (`ratio` is None), then an equal number of observations will be drawn for each sample. num_iter : int The default is 1000. The number of p-values to generate for each point on the curve. alpha : float, optional The significance level for the statistical test. Defaults to 0.05. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. Returns ------- p_values : array The p-values associated with the input sample counts. Raises ------ ValueError If ratio is an array and ratio is not the same length as samples """ # Casts array-likes to arrays sample_counts = np.asarray(sample_counts) # Determines the number of groups num_groups = len(samples) num_samps = len(sample_counts) if isinstance(alpha, float): vec = True pwr = np.zeros((num_samps)) alpha = np.array([alpha]) else: vec = False num_crit = alpha.shape[0] pwr = np.zeros((num_crit, num_samps)) # Checks the ratio argument if ratio is None: ratio = np.ones((num_groups)) ratio = np.asarray(ratio) if not ratio.shape == (num_groups,): raise ValueError("There must be a ratio for each group.") # Loops through the sample sizes rng = get_rng(seed) for id2, s in enumerate(sample_counts): count = np.round(s * ratio, 0).astype(int) for id1, a in enumerate(alpha): ps = _compare_distributions( test=test, samples=samples, counts=count, num_p=1, num_iter=num_iter, mode=mode, seed=rng, ) if vec: pwr[id2] = (_calculate_power(ps, a)).item() else: pwr[id1, id2] = _calculate_power(ps, a) return pwr scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/000077500000000000000000000000001520735541300217625ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/__init__.py000066400000000000000000000005411520735541300240730ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/000077500000000000000000000000001520735541300226735ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/cr_data_out000066400000000000000000000004511520735541300251020ustar00rootroot00000000000000Grouped by "bar", probability: 0.011000 For group "Foo", the group means is: -1.439800 The info is: [('mean', -1.4398), ('std', 1.3184)] For group "Bar", the group means is: 5.958900 Cannot calculate the first difference with a window of size (3). The info is: [('mean', 5.9589), ('std', 2.7942)] scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/cr_data_raw000066400000000000000000000003221520735541300250610ustar00rootroot00000000000000Grouped by "bar" For group "Foo": The trajectory is: [-2.675, -0.251, -2.8322, 0.0] For group "Bar": Cannot calculate the first difference with a window of size (3). The trajectory is: [9.6823, 2.9511, 5.2434] scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/cr_no_data_out000066400000000000000000000001321520735541300255720ustar00rootroot00000000000000Grouped by "foo": This group can not be used. All groups should have more than 1 element. scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/cr_no_data_raw000066400000000000000000000000001520735541300255460ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/gr_w_msg_out000066400000000000000000000002401520735541300253050ustar00rootroot00000000000000For group "Bar", the group means is: 5.958900 Cannot calculate the first difference with a window of size (3). The info is: [('mean', 5.9589), ('std', 2.7942)] scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/gr_w_msg_raw000066400000000000000000000001761520735541300252770ustar00rootroot00000000000000For group "Bar": Cannot calculate the first difference with a window of size (3). The trajectory is: [9.6823, 2.9511, 5.2434] scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/gr_wo_msg_out000066400000000000000000000001411520735541300254640ustar00rootroot00000000000000For group "Foo", the group means is: -1.439800 The info is: [('mean', -1.4398), ('std', 1.3184)] scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/gr_wo_msg_raw000066400000000000000000000001031520735541300254440ustar00rootroot00000000000000For group "Foo": The trajectory is: [-2.675, -0.251, -2.8322, 0.0] scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/vr_out000066400000000000000000000007001520735541300241310ustar00rootroot00000000000000Trajectory algorithm: wdiff ** This output is weighted ** Grouped by "foo": This group can not be used. All groups should have more than 1 element. Grouped by "bar", probability: 0.011000 For group "Foo", the group means is: -1.439800 The info is: [('mean', -1.4398), ('std', 1.3184)] For group "Bar", the group means is: 5.958900 Cannot calculate the first difference with a window of size (3). The info is: [('mean', 5.9589), ('std', 2.7942)] scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/vr_raw000066400000000000000000000004171520735541300241200ustar00rootroot00000000000000Trajectory algorithm: wdiff ** This output is weighted ** Grouped by "bar" For group "Foo": The trajectory is: [-2.675, -0.251, -2.8322, 0.0] For group "Bar": Cannot calculate the first difference with a window of size (3). The trajectory is: [9.6823, 2.9511, 5.2434] scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/vr_real_out000066400000000000000000000010051520735541300251330ustar00rootroot00000000000000Trajectory algorithm: avg Grouped by "Description": This group can not be used. All groups should have more than 1 element. Grouped by "DOB": This group can not be used. All groups should have more than 1 element. Grouped by "Weight": This group can not be used. All groups should have more than 1 element. Grouped by "Treatment", probability: 0.933100 For group "Control", the group means is: 4.050800 The info is: [('avg', 4.0508)] For group "Fast", the group means is: 4.159600 The info is: [('avg', 4.1596)] scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/data/vr_real_raw000066400000000000000000000003151520735541300251200ustar00rootroot00000000000000Trajectory algorithm: avg Grouped by "Treatment" For group "Control": The trajectory is: [2.3694, 3.3716, 5.4452, 4.5704, 4.4972] For group "Fast": The trajectory is: [7.2220, 4.2726, 1.1169, 4.0271] scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/test_gradient.py000066400000000000000000001542321520735541300251770ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from operator import attrgetter from unittest import TestCase, main import numpy as np import pandas as pd import numpy.testing as npt import pandas.testing as pdt from skbio.util import get_data_path, assert_data_frame_almost_equal from skbio.stats.gradient import (GradientANOVA, AverageGradientANOVA, TrajectoryGradientANOVA, FirstDifferenceGradientANOVA, WindowDifferenceGradientANOVA, GroupResults, CategoryResults, GradientANOVAResults, _weight_by_vector, _ANOVA_trajectories) class BaseTests(TestCase): def setUp(self): """Initializes some data for testing""" coord_data = { 'PC.636': np.array([-0.212230626531, 0.216034194368, 0.03532727349, -0.254450494129, -0.0687468542543, 0.231895596562, 0.00496549154314, -0.0026246871695, 9.73837390723e-10]), 'PC.635': np.array([-0.277487312135, -0.0295483215975, -0.0744173437992, 0.0957182357964, 0.204714844022, -0.0055407341857, -0.190287966833, 0.16307126638, 9.73837390723e-10]), 'PC.356': np.array([0.220886492631, 0.0874848360559, -0.351990132198, -0.00316535032886, 0.114635191853, -0.00019194106125, 0.188557853937, 0.030002427212, 9.73837390723e-10]), 'PC.481': np.array([0.0308923744062, -0.0446295973489, 0.133996451689, 0.29318228566, -0.167812539312, 0.130996149793, 0.113551017379, 0.109987942454, 9.73837390723e-10]), 'PC.354': np.array([0.27616778138, -0.0341866951102, 0.0633000238256, 0.100446653327, 0.123802521199, 0.1285839664, -0.132852841046, -0.217514322505, 9.73837390723e-10]), 'PC.593': np.array([0.202458130052, -0.115216120518, 0.301820871723, -0.18300251046, 0.136208248567, -0.0989435556722, 0.0927738484879, 0.0909429797672, 9.73837390723e-10]), 'PC.355': np.array([0.236467470907, 0.21863434374, -0.0301637746424, -0.0225473129718, -0.205287183891, -0.180224615141, -0.165277751908, 0.0411933458557, 9.73837390723e-10]), 'PC.607': np.array([-0.105517545144, -0.41405687433, -0.150073017617, -0.116066751485, -0.158763393475, -0.0223918378516, -0.0263068046112, -0.0501209518091, 9.73837390723e-10]), 'PC.634': np.array([-0.371636765565, 0.115484234741, 0.0721996475289, 0.0898852445906, 0.0212491652909, -0.184183028843, 0.114877153051, -0.164938000185, 9.73837390723e-10]) } self.coords = pd.DataFrame.from_dict(coord_data, orient='index') coord_data = { 'PC.636': np.array([-0.212230626531, 0.216034194368, 0.03532727349]), 'PC.635': np.array([-0.277487312135, -0.0295483215975, -0.0744173437992]), 'PC.356': np.array([0.220886492631, 0.0874848360559, -0.351990132198]), 'PC.481': np.array([0.0308923744062, -0.0446295973489, 0.133996451689]), 'PC.354': np.array([0.27616778138, -0.0341866951102, 0.0633000238256]), 'PC.593': np.array([0.202458130052, -0.115216120518, 0.301820871723]), 'PC.355': np.array([0.236467470907, 0.21863434374, -0.0301637746424]), 'PC.607': np.array([-0.105517545144, -0.41405687433, -0.150073017617]), 'PC.634': np.array([-0.371636765565, 0.115484234741, 0.0721996475289]) } self.coords_3axes = pd.DataFrame.from_dict(coord_data, orient='index') metadata_map = {'PC.354': {'Treatment': 'Control', 'DOB': '20061218', 'Weight': '60', 'Description': 'Control_mouse_I.D._354'}, 'PC.355': {'Treatment': 'Control', 'DOB': '20061218', 'Weight': '55', 'Description': 'Control_mouse_I.D._355'}, 'PC.356': {'Treatment': 'Control', 'DOB': '20061126', 'Weight': '50', 'Description': 'Control_mouse_I.D._356'}, 'PC.481': {'Treatment': 'Control', 'DOB': '20070314', 'Weight': '52', 'Description': 'Control_mouse_I.D._481'}, 'PC.593': {'Treatment': 'Control', 'DOB': '20071210', 'Weight': '57', 'Description': 'Control_mouse_I.D._593'}, 'PC.607': {'Treatment': 'Fast', 'DOB': '20071112', 'Weight': '65', 'Description': 'Fasting_mouse_I.D._607'}, 'PC.634': {'Treatment': 'Fast', 'DOB': '20080116', 'Weight': '68', 'Description': 'Fasting_mouse_I.D._634'}, 'PC.635': {'Treatment': 'Fast', 'DOB': '20080116', 'Weight': '70', 'Description': 'Fasting_mouse_I.D._635'}, 'PC.636': {'Treatment': 'Fast', 'DOB': '20080116', 'Weight': '72', 'Description': 'Fasting_mouse_I.D._636'}} self.metadata_map = pd.DataFrame.from_dict(metadata_map, orient='index') self.prop_expl = np.array([25.6216900347, 15.7715955926, 14.1215046787, 11.6913885817, 9.83044890697, 8.51253468595, 7.88775505332, 6.56308246609, 4.42499350906e-16]) gr_wo_msg = GroupResults('Foo', np.array([-2.6750, -0.2510, -2.8322, 0.]), -1.4398, {'mean': -1.4398, 'std': 1.3184}, None) gr_w_msg = GroupResults('Bar', np.array([9.6823, 2.9511, 5.2434]), 5.9589, {'mean': 5.9589, 'std': 2.7942}, "Cannot calculate the first difference " "with a window of size (3).") self.groups = [gr_wo_msg, gr_w_msg] cr_no_data = CategoryResults('foo', None, None, 'This group can not be used. All groups ' 'should have more than 1 element.') cr_data = CategoryResults('bar', 0.0110, self.groups, None) self.categories = [cr_no_data, cr_data] vr = GradientANOVAResults('wdiff', True, self.categories) description = CategoryResults('Description', None, None, 'This group can not be used. All groups ' 'should have more than 1 element.') weight = CategoryResults('Weight', None, None, 'This group can not be used. All groups ' 'should have more than 1 element.') dob = CategoryResults('DOB', None, None, 'This group can not be used. All groups ' 'should have more than 1 element.') control_group = GroupResults('Control', np.array([2.3694, 3.3716, 5.4452, 4.5704, 4.4972]), 4.0508, {'avg': 4.0508}, None) fast_group = GroupResults('Fast', np.array([7.2220, 4.2726, 1.1169, 4.0271]), 4.1596, {'avg': 4.1596}, None) treatment = CategoryResults('Treatment', 0.9331, [control_group, fast_group], None) vr_real = GradientANOVAResults('avg', False, [description, weight, dob, treatment]) self.vec_results = [vr, vr_real] # This function makes the comparisons between the results classes easier def assert_group_results_almost_equal(self, obs, exp): """Tests that obs and exp are almost equal""" self.assertEqual(obs.name, exp.name) npt.assert_almost_equal(obs.trajectory, exp.trajectory) npt.assert_almost_equal(obs.mean, exp.mean) self.assertEqual(obs.info.keys(), exp.info.keys()) for key in obs.info: npt.assert_almost_equal(obs.info[key], exp.info[key]) self.assertEqual(obs.message, exp.message) def assert_category_results_almost_equal(self, obs, exp): """Tests that obs and exp are almost equal""" self.assertEqual(obs.category, exp.category) if exp.probability is None: self.assertTrue(obs.probability is None) self.assertTrue(obs.groups is None) else: npt.assert_almost_equal(obs.probability, exp.probability) for o, e in zip(sorted(obs.groups, key=attrgetter('name')), sorted(exp.groups, key=attrgetter('name'))): self.assert_group_results_almost_equal(o, e) def assert_gradientANOVA_results_almost_equal(self, obs, exp): """Tests that obs and exp are almost equal""" self.assertEqual(obs.algorithm, exp.algorithm) self.assertEqual(obs.weighted, exp.weighted) for o, e in zip(sorted(obs.categories, key=attrgetter('category')), sorted(exp.categories, key=attrgetter('category'))): self.assert_category_results_almost_equal(o, e) class GradientTests(BaseTests): def test_weight_by_vector(self): """Correctly weights the vectors""" trajectory = pd.DataFrame.from_dict({'s1': np.array([1]), 's2': np.array([2]), 's3': np.array([3]), 's4': np.array([4]), 's5': np.array([5]), 's6': np.array([6]), 's7': np.array([7]), 's8': np.array([8])}, orient='index') trajectory.sort_values(by=0, inplace=True) w_vector = pd.Series(np.array([1, 5, 8, 12, 45, 80, 85, 90]), ['s1', 's2', 's3', 's4', 's5', 's6', 's7', 's8']).astype(np.float64) exp = pd.DataFrame.from_dict({'s1': np.array([1]), 's2': np.array([6.3571428571]), 's3': np.array([12.7142857142]), 's4': np.array([12.7142857142]), 's5': np.array([1.9264069264]), 's6': np.array([2.1795918367]), 's7': np.array([17.8]), 's8': np.array([20.3428571428])}, orient='index').astype(np.float64) obs = _weight_by_vector(trajectory, w_vector) assert_data_frame_almost_equal(obs.sort_index(), exp.sort_index()) trajectory = pd.DataFrame.from_dict({'s1': np.array([1]), 's2': np.array([2]), 's3': np.array([3]), 's4': np.array([4]), 's5': np.array([5]), 's6': np.array([6]), 's7': np.array([7]), 's8': np.array([8])}, orient='index') trajectory.sort_values(by=0, inplace=True) w_vector = pd.Series(np.array([1, 2, 3, 4, 5, 6, 7, 8]), ['s1', 's2', 's3', 's4', 's5', 's6', 's7', 's8']).astype(np.float64) exp = pd.DataFrame.from_dict({'s1': np.array([1]), 's2': np.array([2]), 's3': np.array([3]), 's4': np.array([4]), 's5': np.array([5]), 's6': np.array([6]), 's7': np.array([7]), 's8': np.array([8]) }, orient='index').astype(np.float64) obs = _weight_by_vector(trajectory, w_vector) assert_data_frame_almost_equal(obs.sort_index(), exp.sort_index()) trajectory = pd.DataFrame.from_dict({'s2': np.array([2]), 's3': np.array([3]), 's4': np.array([4]), 's5': np.array([5]), 's6': np.array([6])}, orient='index') trajectory.sort_values(by=0, inplace=True) w_vector = pd.Series(np.array([25, 30, 35, 40, 45]), ['s2', 's3', 's4', 's5', 's6']).astype(np.float64) exp = pd.DataFrame.from_dict({'s2': np.array([2]), 's3': np.array([3]), 's4': np.array([4]), 's5': np.array([5]), 's6': np.array([6])}, orient='index').astype(np.float64) obs = _weight_by_vector(trajectory, w_vector) assert_data_frame_almost_equal(obs.sort_index(), exp.sort_index()) trajectory = pd.DataFrame.from_dict({'s1': np.array([1, 2, 3]), 's2': np.array([2, 3, 4]), 's3': np.array([5, 6, 7]), 's4': np.array([8, 9, 10])}, orient='index') trajectory.sort_values(by=0, inplace=True) w_vector = pd.Series(np.array([1, 2, 3, 4]), ['s1', 's2', 's3', 's4']).astype(np.float64) exp = pd.DataFrame.from_dict({'s1': np.array([1, 2, 3]), 's2': np.array([2, 3, 4]), 's3': np.array([5, 6, 7]), 's4': np.array([8, 9, 10])}, orient='index').astype(np.float64) obs = _weight_by_vector(trajectory, w_vector) assert_data_frame_almost_equal(obs.sort_index(), exp.sort_index()) sample_ids = ['PC.356', 'PC.481', 'PC.355', 'PC.593', 'PC.354'] trajectory = pd.DataFrame.from_dict({'PC.356': np.array([5.65948525, 1.37977545, -4.9706303]), 'PC.481': np.array([0.79151484, -0.70387996, 1.89223152]), 'PC.355': np.array([6.05869624, 3.44821245, -0.42595788]), 'PC.593': np.array([5.18731945, -1.81714206, 4.26216485]), 'PC.354': np.array([7.07588529, -0.53917873, 0.89389158]) }, orient='index') w_vector = pd.Series(np.array([50, 52, 55, 57, 60]), sample_ids).astype(np.float64) exp = pd.DataFrame.from_dict({'PC.356': np.array([5.65948525, 1.37977545, -4.9706303]), 'PC.481': np.array([0.98939355, -0.87984995, 2.3652894]), 'PC.355': np.array([5.04891353, 2.87351038, -0.3549649]), 'PC.593': np.array([6.48414931, -2.27142757, 5.32770606]), 'PC.354': np.array([5.89657108, -0.44931561, 0.74490965]) }, orient='index') obs = _weight_by_vector(trajectory.loc[sample_ids], w_vector[sample_ids]) assert_data_frame_almost_equal(obs.sort_index(), exp.sort_index()) def test_weight_by_vector_single_element(self): trajectory = pd.DataFrame.from_dict({'s1': np.array([42])}, orient='index') w_vector = pd.Series(np.array([5]), ['s1']).astype(np.float64) obs = _weight_by_vector(trajectory, w_vector) assert_data_frame_almost_equal(obs, trajectory) def test_weight_by_vector_error(self): """Raises an error with erroneous inputs""" # Different vector lengths with self.assertRaises(ValueError): _weight_by_vector([1, 2, 3, 4], [1, 2, 3]) # Inputs are not iterables with self.assertRaises(TypeError): _weight_by_vector(9, 1) # Weighting vector is not a gradient with self.assertRaises(ValueError): _weight_by_vector([1, 2, 3, 4], [1, 2, 3, 3]) def test_ANOVA_trajectories(self): """Correctly performs the check before running ANOVA""" # Only one group in a given category group = GroupResults('Bar', np.array([2.3694943596755276, 3.3716388181385781, 5.4452089176253367, 4.5704258453173559, 4.4972603724478377]), 4.05080566264, {'avg': 4.0508056626409275}, None) obs = _ANOVA_trajectories('Foo', [group]) exp = CategoryResults('Foo', None, None, 'Only one value in the group.') self.assert_category_results_almost_equal(obs, exp) # One element have only one element group2 = GroupResults('FooBar', np.array([4.05080566264]), 4.05080566264, {'avg': 4.05080566264}, None) obs = _ANOVA_trajectories('Foo', [group, group2]) exp = CategoryResults('Foo', None, None, 'This group can not be used. All groups ' 'should have more than 1 element.') self.assert_category_results_almost_equal(obs, exp) gr1 = GroupResults('Foo', np.array([-0.219044992, 0.079674486, 0.09233683]), -0.015677892, {'avg': -0.015677892}, None) gr2 = GroupResults('Bar', np.array([-0.042258081, 0.000204041, 0.024837603]), -0.0732878716, {'avg': -0.0732878716}, None) gr3 = GroupResults('FBF', np.array([0.080504323, -0.212014503, -0.088353435]), -0.0057388123, {'avg': -0.0057388123}, None) obs = _ANOVA_trajectories('Cat', [gr1, gr2, gr3]) exp = CategoryResults('Cat', 0.8067456876, [gr1, gr2, gr3], None) self.assert_category_results_almost_equal(obs, exp) class GroupResultsTests(BaseTests): def test_to_file(self): out_paths = ['gr_wo_msg_out', 'gr_w_msg_out'] raw_paths = ['gr_wo_msg_raw', 'gr_w_msg_raw'] for gr, out_fp, raw_fp in zip(self.groups, out_paths, raw_paths): obs_out_f = io.StringIO() obs_raw_f = io.StringIO() gr.to_files(obs_out_f, obs_raw_f) obs_out = obs_out_f.getvalue() obs_raw = obs_raw_f.getvalue() obs_out_f.close() obs_raw_f.close() with open(get_data_path(out_fp)) as f: exp_out = f.read() with open(get_data_path(raw_fp)) as f: exp_raw = f.read() self.assertEqual(obs_out, exp_out) self.assertEqual(obs_raw, exp_raw) class CategoryResultsTests(BaseTests): def test_to_file(self): out_paths = ['cr_no_data_out', 'cr_data_out'] raw_paths = ['cr_no_data_raw', 'cr_data_raw'] for cat, out_fp, raw_fp in zip(self.categories, out_paths, raw_paths): obs_out_f = io.StringIO() obs_raw_f = io.StringIO() cat.to_files(obs_out_f, obs_raw_f) obs_out = obs_out_f.getvalue() obs_raw = obs_raw_f.getvalue() obs_out_f.close() obs_raw_f.close() with open(get_data_path(out_fp)) as f: exp_out = f.read() with open(get_data_path(raw_fp)) as f: exp_raw = f.read() self.assertEqual(obs_out, exp_out) self.assertEqual(obs_raw, exp_raw) class GradientANOVAResultsTests(BaseTests): def test_to_file(self): out_paths = ['vr_out'] raw_paths = ['vr_raw'] for vr, out_fp, raw_fp in zip(self.vec_results, out_paths, raw_paths): obs_out_f = io.StringIO() obs_raw_f = io.StringIO() vr.to_files(obs_out_f, obs_raw_f) obs_out = obs_out_f.getvalue() obs_raw = obs_raw_f.getvalue() obs_out_f.close() obs_raw_f.close() with open(get_data_path(out_fp)) as f: exp_out = f.read() with open(get_data_path(raw_fp)) as f: exp_raw = f.read() self.assertEqual(obs_out, exp_out) self.assertEqual(obs_raw, exp_raw) class GradientANOVATests(BaseTests): def test_init(self): """Correctly initializes the class attributes""" # Note self._groups is tested on test_make_groups # so we are not testing it here # Test with weighted = False bv = GradientANOVA(self.coords, self.prop_expl, self.metadata_map) assert_data_frame_almost_equal(bv._coords.loc[self.coords_3axes.index], self.coords_3axes) exp_prop_expl = np.array([25.6216900347, 15.7715955926, 14.1215046787]) npt.assert_equal(bv._prop_expl, exp_prop_expl) assert_data_frame_almost_equal(bv._metadata_map.loc[self.metadata_map.index], # noqa self.metadata_map) self.assertTrue(bv._weighting_vector is None) self.assertFalse(bv._weighted) # Test with weighted = True bv = GradientANOVA(self.coords, self.prop_expl, self.metadata_map, sort_category='Weight', weighted=True) assert_data_frame_almost_equal(bv._coords.loc[self.coords_3axes.index], self.coords_3axes) npt.assert_equal(bv._prop_expl, exp_prop_expl) assert_data_frame_almost_equal(bv._metadata_map.loc[self.metadata_map.index], # noqa self.metadata_map) exp_weighting_vector = pd.Series( np.array([60, 55, 50, 52, 57, 65, 68, 70, 72]), ['PC.354', 'PC.355', 'PC.356', 'PC.481', 'PC.593', 'PC.607', 'PC.634', 'PC.635', 'PC.636'], name='Weight' ).astype(np.float64) pdt.assert_series_equal(bv._weighting_vector.loc[exp_weighting_vector.index], # noqa exp_weighting_vector) self.assertTrue(bv._weighted) def test_init_error(self): """Raises an error with erroneous inputs""" # Raises ValueError if any category in trajectory_categories is not # present in metadata_map with self.assertRaises(ValueError): GradientANOVA(self.coords, self.prop_expl, self.metadata_map, trajectory_categories=['foo']) with self.assertRaises(ValueError): GradientANOVA(self.coords, self.prop_expl, self.metadata_map, trajectory_categories=['Weight', 'Treatment', 'foo']) # Raises ValueError if sort_category is not present in metadata_map with self.assertRaises(ValueError): GradientANOVA(self.coords, self.prop_expl, self.metadata_map, sort_category='foo') # Raises ValueError if weighted == True and sort_category == None with self.assertRaises(ValueError): GradientANOVA(self.coords, self.prop_expl, self.metadata_map, weighted=True) # Raises ValueError if weighted == True and the values under # sort_category are not numerical with self.assertRaises(ValueError): GradientANOVA(self.coords, self.prop_expl, self.metadata_map, sort_category='Treatment', weighted=True) # Raises ValueError if axes > len(prop_expl) with self.assertRaises(ValueError): GradientANOVA(self.coords, self.prop_expl, self.metadata_map, axes=10) # Raises ValueError if axes < 0 with self.assertRaises(ValueError): GradientANOVA(self.coords, self.prop_expl, self.metadata_map, axes=-1) def test_normalize_samples(self): """Correctly normalizes the samples between coords and metadata_map""" coord_data = { 'PC.636': np.array([-0.212230626531, 0.216034194368, 0.03532727349]), 'PC.635': np.array([-0.277487312135, -0.0295483215975, -0.0744173437992]), 'PC.355': np.array([0.236467470907, 0.21863434374, -0.0301637746424]), 'PC.607': np.array([-0.105517545144, -0.41405687433, -0.150073017617]), 'PC.634': np.array([-0.371636765565, 0.115484234741, 0.0721996475289]) } subset_coords = pd.DataFrame.from_dict(coord_data, orient='index') metadata_map = {'PC.355': {'Treatment': 'Control', 'DOB': '20061218', 'Weight': '55', 'Description': 'Control_mouse_I.D._355'}, 'PC.607': {'Treatment': 'Fast', 'DOB': '20071112', 'Weight': '65', 'Description': 'Fasting_mouse_I.D._607'}, 'PC.634': {'Treatment': 'Fast', 'DOB': '20080116', 'Weight': '68', 'Description': 'Fasting_mouse_I.D._634'}, 'PC.635': {'Treatment': 'Fast', 'DOB': '20080116', 'Weight': '70', 'Description': 'Fasting_mouse_I.D._635'}, 'PC.636': {'Treatment': 'Fast', 'DOB': '20080116', 'Weight': '72', 'Description': 'Fasting_mouse_I.D._636'}} subset_metadata_map = pd.DataFrame.from_dict(metadata_map, orient='index') # Takes a subset from metadata_map bv = GradientANOVA(subset_coords, self.prop_expl, self.metadata_map) assert_data_frame_almost_equal( bv._coords.sort_index(), subset_coords.sort_index()) assert_data_frame_almost_equal( bv._metadata_map.sort_index(), subset_metadata_map.sort_index()) # Takes a subset from coords bv = GradientANOVA(self.coords, self.prop_expl, subset_metadata_map) assert_data_frame_almost_equal( bv._coords.sort_index(), subset_coords.sort_index()) assert_data_frame_almost_equal( bv._metadata_map.sort_index(), subset_metadata_map.sort_index()) # Takes a subset from metadata_map and coords at the same time coord_data = { 'PC.636': np.array([-0.212230626531, 0.216034194368, 0.03532727349]), 'PC.635': np.array([-0.277487312135, -0.0295483215975, -0.0744173437992]), 'PC.355': np.array([0.236467470907, 0.21863434374, -0.0301637746424]) } subset_coords = pd.DataFrame.from_dict(coord_data, orient='index') metadata_map = {'PC.355': {'Treatment': 'Control', 'DOB': '20061218', 'Weight': '55', 'Description': 'Control_mouse_I.D._355'}, 'PC.607': {'Treatment': 'Fast', 'DOB': '20071112', 'Weight': '65', 'Description': 'Fasting_mouse_I.D._607'}, 'PC.634': {'Treatment': 'Fast', 'DOB': '20080116', 'Weight': '68', 'Description': 'Fasting_mouse_I.D._634'}} subset_metadata_map = pd.DataFrame.from_dict(metadata_map, orient='index') bv = GradientANOVA(subset_coords, self.prop_expl, subset_metadata_map) exp_coords = pd.DataFrame.from_dict( {'PC.355': np.array([0.236467470907, 0.21863434374, -0.0301637746424])}, orient='index') assert_data_frame_almost_equal( bv._coords.sort_index(), exp_coords.sort_index()) exp_metadata_map = pd.DataFrame.from_dict( {'PC.355': {'Treatment': 'Control', 'DOB': '20061218', 'Weight': '55', 'Description': 'Control_mouse_I.D._355'}}, orient='index') assert_data_frame_almost_equal( bv._metadata_map.sort_index(), exp_metadata_map.sort_index()) def test_normalize_samples_error(self): """Raises an error if coords and metadata_map does not have samples in common""" error_metadata_map = pd.DataFrame.from_dict( {'Foo': {'Treatment': 'Control', 'DOB': '20061218', 'Weight': '55', 'Description': 'Control_mouse_I.D._355'}, 'Bar': {'Treatment': 'Fast', 'DOB': '20071112', 'Weight': '65', 'Description': 'Fasting_mouse_I.D._607'}}, orient='index') with self.assertRaises(ValueError): GradientANOVA(self.coords, self.prop_expl, error_metadata_map) def test_make_groups(self): """Correctly generates the groups for trajectory_categories""" # Test with all categories bv = GradientANOVA(self.coords, self.prop_expl, self.metadata_map) exp_groups = {'Treatment': {'Control': ['PC.354', 'PC.355', 'PC.356', 'PC.481', 'PC.593'], 'Fast': ['PC.607', 'PC.634', 'PC.635', 'PC.636']}, 'DOB': {'20061218': ['PC.354', 'PC.355'], '20061126': ['PC.356'], '20070314': ['PC.481'], '20071210': ['PC.593'], '20071112': ['PC.607'], '20080116': ['PC.634', 'PC.635', 'PC.636']}, 'Weight': {'60': ['PC.354'], '55': ['PC.355'], '50': ['PC.356'], '52': ['PC.481'], '57': ['PC.593'], '65': ['PC.607'], '68': ['PC.634'], '70': ['PC.635'], '72': ['PC.636']}, 'Description': {'Control_mouse_I.D._354': ['PC.354'], 'Control_mouse_I.D._355': ['PC.355'], 'Control_mouse_I.D._356': ['PC.356'], 'Control_mouse_I.D._481': ['PC.481'], 'Control_mouse_I.D._593': ['PC.593'], 'Fasting_mouse_I.D._607': ['PC.607'], 'Fasting_mouse_I.D._634': ['PC.634'], 'Fasting_mouse_I.D._635': ['PC.635'], 'Fasting_mouse_I.D._636': ['PC.636']}} self.assertEqual(bv._groups, exp_groups) # Test with user-defined categories bv = GradientANOVA(self.coords, self.prop_expl, self.metadata_map, trajectory_categories=['Treatment', 'DOB']) exp_groups = {'Treatment': {'Control': ['PC.354', 'PC.355', 'PC.356', 'PC.481', 'PC.593'], 'Fast': ['PC.607', 'PC.634', 'PC.635', 'PC.636']}, 'DOB': {'20061218': ['PC.354', 'PC.355'], '20061126': ['PC.356'], '20070314': ['PC.481'], '20071210': ['PC.593'], '20071112': ['PC.607'], '20080116': ['PC.634', 'PC.635', 'PC.636']}} self.assertEqual(bv._groups, exp_groups) def test_make_groups_natural_sorting(self): # Ensure sample IDs are sorted using a natural sorting algorithm. df = pd.DataFrame.from_dict({ 'a2': {'Col1': 'foo', 'Col2': '1.0'}, 'a1': {'Col1': 'bar', 'Col2': '-42.0'}, 'a11.0': {'Col1': 'foo', 'Col2': '2e-5'}, 'a-10': {'Col1': 'foo', 'Col2': '5'}, 'a10': {'Col1': 'bar', 'Col2': '5'}}, orient='index') coords = pd.DataFrame.from_dict({ 'a10': np.array([-0.212230626531, 0.216034194368, 0.03532727349]), 'a11.0': np.array([-0.277487312135, -0.0295483215975, -0.0744173437992]), 'a1': np.array([0.220886492631, 0.0874848360559, -0.351990132198]), 'a2': np.array([0.0308923744062, -0.0446295973489, 0.133996451689]), 'a-10': np.array([0.27616778138, -0.0341866951102, 0.0633000238256])}, orient='index') prop_expl = np.array([25.6216900347, 15.7715955926, 14.1215046787, 11.6913885817, 9.83044890697]) # Sort by sample IDs. ga = GradientANOVA(coords, prop_expl, df) exp_groups = { 'Col1': { 'foo': ['a-10', 'a2', 'a11.0'], 'bar': ['a1', 'a10'] }, 'Col2': { '1.0': ['a2'], '-42.0': ['a1'], '2e-5': ['a11.0'], '5': ['a-10', 'a10'] } } self.assertEqual(ga._groups, exp_groups) # Sort sample IDs by Col2. ga = GradientANOVA(coords, prop_expl, df, trajectory_categories=['Col1'], sort_category='Col2') exp_groups = { 'Col1': { 'foo': ['a11.0', 'a2', 'a-10'], 'bar': ['a1', 'a10'] } } self.assertEqual(ga._groups, exp_groups) def test_get_trajectories(self): """Should raise a NotImplementedError as this is a base class""" bv = GradientANOVA(self.coords, self.prop_expl, self.metadata_map) with self.assertRaises(NotImplementedError): bv.get_trajectories() def test_get_group_trajectories(self): """Should raise a NotImplementedError in usual execution as this is a base class""" bv = GradientANOVA(self.coords, self.prop_expl, self.metadata_map) with self.assertRaises(NotImplementedError): bv.get_trajectories() def test_get_group_trajectories_error(self): """Should raise a RuntimeError if the user call _get_group_trajectories with erroneous inputs""" bv = GradientANOVA(self.coords, self.prop_expl, self.metadata_map) with self.assertRaises(KeyError): bv._get_group_trajectories("foo", ['foo']) with self.assertRaises(RuntimeError): bv._get_group_trajectories("bar", []) def test_compute_trajectories_results(self): """Should raise a NotImplementedError as this is a base class""" bv = GradientANOVA(self.coords, self.prop_expl, self.metadata_map) with self.assertRaises(NotImplementedError): bv._compute_trajectories_results("foo", []) class AverageGradientANOVATests(BaseTests): def test_get_trajectories_all(self): """get_trajectories returns the results of all categories""" av = AverageGradientANOVA(self.coords, self.prop_expl, self.metadata_map) obs = av.get_trajectories() exp_description = CategoryResults('Description', None, None, 'This group can not be used. All ' 'groups should have more than 1 ' 'element.') exp_weight = CategoryResults('Weight', None, None, 'This group can not be used. All groups ' 'should have more than 1 element.') exp_dob = CategoryResults('DOB', None, None, 'This group can not be used. All groups ' 'should have more than 1 element.') exp_control_group = GroupResults('Control', np.array([2.3694943596755276, 3.3716388181385781, 5.4452089176253367, 4.5704258453173559, 4.4972603724478377]), 4.05080566264, {'avg': 4.0508056626409275}, None) exp_fast_group = GroupResults('Fast', np.array([7.2220488239279126, 4.2726021564374372, 1.1169097274372082, 4.02717600030876]), 4.15968417703, {'avg': 4.1596841770278292}, None) exp_treatment = CategoryResults('Treatment', 0.93311555, [exp_control_group, exp_fast_group], None) exp = GradientANOVAResults('avg', False, [exp_description, exp_weight, exp_dob, exp_treatment]) self.assert_gradientANOVA_results_almost_equal(obs, exp) def test_get_trajectories_single(self): """get_trajectories returns the results of the provided category""" av = AverageGradientANOVA(self.coords, self.prop_expl, self.metadata_map, trajectory_categories=['Treatment']) obs = av.get_trajectories() exp_control_group = GroupResults('Control', np.array([2.3694943596755276, 3.3716388181385781, 5.4452089176253367, 4.5704258453173559, 4.4972603724478377]), 4.05080566264, {'avg': 4.0508056626409275}, None) exp_fast_group = GroupResults('Fast', np.array([7.2220488239279126, 4.2726021564374372, 1.1169097274372082, 4.02717600030876]), 4.15968417703, {'avg': 4.1596841770278292}, None) exp_treatment = CategoryResults('Treatment', 0.93311555, [exp_control_group, exp_fast_group], None) exp = GradientANOVAResults('avg', False, [exp_treatment]) self.assert_gradientANOVA_results_almost_equal(obs, exp) def test_get_trajectories_weighted(self): """get_trajectories returns the correct weighted results""" av = AverageGradientANOVA(self.coords, self.prop_expl, self.metadata_map, trajectory_categories=['Treatment'], sort_category='Weight', weighted=True) obs = av.get_trajectories() exp_control_group = GroupResults('Control', np.array([5.7926887872, 4.3242308936, 2.9212403501, 5.5400792151, 1.2326804315]), 3.9621839355, {'avg': 3.9621839355}, None) exp_fast_group = GroupResults('Fast', np.array([7.2187223286, 2.5522161282, 2.2349795861, 4.5278215248]), 4.1334348919, {'avg': 4.1334348919}, None) exp_treatment = CategoryResults('Treatment', 0.9057666800, [exp_control_group, exp_fast_group], None) exp = GradientANOVAResults('avg', True, [exp_treatment]) self.assert_gradientANOVA_results_almost_equal(obs, exp) class TrajectoryGradientANOVATests(BaseTests): def test_get_trajectories(self): tv = TrajectoryGradientANOVA(self.coords, self.prop_expl, self.metadata_map, trajectory_categories=['Treatment'], sort_category='Weight') obs = tv.get_trajectories() exp_control_group = GroupResults('Control', np.array([8.6681963576, 7.0962717982, 7.1036434615, 4.0675712674]), 6.73392072123, {'2-norm': 13.874494152}, None) exp_fast_group = GroupResults('Fast', np.array([11.2291654905, 3.9163741156, 4.4943507388]), 6.5466301150, {'2-norm': 12.713431181}, None) exp_treatment = CategoryResults('Treatment', 0.9374500147, [exp_control_group, exp_fast_group], None) exp = GradientANOVAResults('trajectory', False, [exp_treatment]) self.assert_gradientANOVA_results_almost_equal(obs, exp) def test_get_trajectories_weighted(self): tv = TrajectoryGradientANOVA(self.coords, self.prop_expl, self.metadata_map, trajectory_categories=['Treatment'], sort_category='Weight', weighted=True) obs = tv.get_trajectories() exp_control_group = GroupResults('Control', np.array([8.9850643421, 6.1617529749, 7.7989125908, 4.9666249268]), 6.9780887086, {'2-norm': 14.2894710091}, None) exp_fast_group = GroupResults('Fast', np.array([9.6823682852, 2.9511115209, 5.2434091953]), 5.9589630005, {'2-norm': 11.3995901159}, None) exp_treatment = CategoryResults('Treatment', 0.6248157720, [exp_control_group, exp_fast_group], None) exp = GradientANOVAResults('trajectory', True, [exp_treatment]) self.assert_gradientANOVA_results_almost_equal(obs, exp) class FirstDifferenceGradientANOVATests(BaseTests): def test_get_trajectories(self): dv = FirstDifferenceGradientANOVA(self.coords, self.prop_expl, self.metadata_map, trajectory_categories=['Treatment'], sort_category='Weight') obs = dv.get_trajectories() exp_control_group = GroupResults('Control', np.array([-1.5719245594, 0.0073716633, -3.0360721941]), -1.5335416967, {'mean': -1.5335416967, 'std': 1.2427771485}, None) exp_fast_group = GroupResults('Fast', np.array([-7.3127913749, 0.5779766231]), -3.3674073758, {'mean': -3.3674073758, 'std': 3.9453839990}, None) exp_treatment = CategoryResults('Treatment', 0.6015260608, [exp_control_group, exp_fast_group], None) exp = GradientANOVAResults('diff', False, [exp_treatment]) self.assert_gradientANOVA_results_almost_equal(obs, exp) def test_get_trajectories_weighted(self): dv = FirstDifferenceGradientANOVA(self.coords, self.prop_expl, self.metadata_map, trajectory_categories=['Treatment'], sort_category='Weight', weighted=True) obs = dv.get_trajectories() exp_control_group = GroupResults('Control', np.array([-2.8233113671, 1.6371596158, -2.8322876639]), -1.3394798050, {'mean': -1.3394798050, 'std': 2.1048051097}, None) exp_fast_group = GroupResults('Fast', np.array([-6.7312567642, 2.2922976743]), -2.2194795449, {'mean': -2.2194795449, 'std': 4.5117772193}, None) exp_treatment = CategoryResults('Treatment', 0.8348644420, [exp_control_group, exp_fast_group], None) exp = GradientANOVAResults('diff', True, [exp_treatment]) self.assert_gradientANOVA_results_almost_equal(obs, exp) class WindowDifferenceGradientANOVATests(BaseTests): def test_get_trajectories(self): wdv = WindowDifferenceGradientANOVA( self.coords, self.prop_expl, self.metadata_map, 3, trajectory_categories=['Treatment'], sort_category='Weight') obs = wdv.get_trajectories() exp_control_group = GroupResults('Control', np.array([-2.5790341819, -2.0166764661, -3.0360721941, 0.]), -1.9079457105, {'mean': -1.9079457105, 'std': 1.1592139913}, None) exp_fast_group = GroupResults('Fast', np.array([11.2291654905, 3.9163741156, 4.4943507388]), 6.5466301150, {'mean': 6.5466301150, 'std': 3.3194494926}, "Cannot calculate the first difference " "with a window of size (3).") exp_treatment = CategoryResults('Treatment', 0.0103976830, [exp_control_group, exp_fast_group], None) exp = GradientANOVAResults('wdiff', False, [exp_treatment]) self.assert_gradientANOVA_results_almost_equal(obs, exp) def test_get_trajectories_weighted(self): wdv = WindowDifferenceGradientANOVA( self.coords, self.prop_expl, self.metadata_map, 3, trajectory_categories=['Treatment'], sort_category='Weight', weighted=True) obs = wdv.get_trajectories() exp_control_group = GroupResults('Control', np.array([-2.6759675112, -0.2510321601, -2.8322876639, 0.]), -1.4398218338, {'mean': -1.4398218338, 'std': 1.31845790844}, None) exp_fast_group = GroupResults('Fast', np.array([9.6823682852, 2.9511115209, 5.2434091953]), 5.9589630005, {'mean': 5.9589630005, 'std': 2.7942163293}, "Cannot calculate the first difference " "with a window of size (3).") exp_treatment = CategoryResults('Treatment', 0.0110675605, [exp_control_group, exp_fast_group], None) exp = GradientANOVAResults('wdiff', True, [exp_treatment]) self.assert_gradientANOVA_results_almost_equal(obs, exp) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/test_misc.py000066400000000000000000000033701520735541300243310ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main from skbio.stats._misc import _pprint_strs class PPrintStrsTests(TestCase): def test_truncation(self): # truncation between items (on comma) exp = "'a', ..." obs = _pprint_strs(['a', 'b', 'c'], max_chars=4) self.assertEqual(obs, exp) # truncation between items (on space) exp = "'a', ..." obs = _pprint_strs(['a', 'b', 'c'], max_chars=5) self.assertEqual(obs, exp) # truncation on item exp = "'a', ..." obs = _pprint_strs(['a', 'b', 'c'], max_chars=6) self.assertEqual(obs, exp) # truncation (no items) exp = "..." obs = _pprint_strs(['a', 'b', 'c'], max_chars=2) self.assertEqual(obs, exp) def test_no_truncation(self): exp = "'a'" obs = _pprint_strs(['a'], max_chars=3) self.assertEqual(obs, exp) exp = "'a', 'b', 'c'" obs = _pprint_strs(['a', 'b', 'c']) self.assertEqual(obs, exp) exp = "'a', 'b', 'c'" obs = _pprint_strs(['a', 'b', 'c'], max_chars=13) self.assertEqual(obs, exp) def test_non_default_delimiter_and_suffix(self): exp = "'abc','defg',...." obs = _pprint_strs(['abc', 'defg', 'hi', 'jklmno'], max_chars=14, delimiter=',', suffix='....') self.assertEqual(obs, exp) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/test_power.py000066400000000000000000000531611520735541300245350ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main, skipIf from packaging.version import Version import numpy as np import numpy.testing as npt import pandas as pd from scipy.stats import kruskal from skbio.stats.power import (subsample_power, subsample_paired_power, _check_nans, confidence_bound, _calculate_power, _compare_distributions, _calculate_power_curve, _check_subsample_power_inputs, _identify_sample_groups, _draw_paired_samples, _get_min_size, paired_subsamples ) PANDAS_3 = Version(pd.__version__) >= Version("3.0.0") class PowerAnalysisTest(TestCase): def setUp(self): # Defines a testing functions def test_meta(ids, meta, cat, div): """Checks thhe div metric with a kruskal wallis""" out = [meta.loc[id_, div] for id_ in ids] return kruskal(*out)[1] def meta_f(x): """Applies `test_meta` to a result""" return test_meta(x, self.meta, 'INT', 'DIV') def f(x): """returns the p value of a kruskal wallis test""" return kruskal(*x)[1] self.test_meta = test_meta self.f = f self.meta_f = meta_f self.num_p = 1 # Sets up the distributions of data for use self.s1 = np.arange(0, 10, 1) # Sets up two distributions which will never be equal by a rank-sum # test. self.samps = [np.ones((10))/10., np.ones((10))] self.pop = [np.arange(0, 10, 0.1), np.arange(0, 20, 0.2)] # Sets up a vector of alpha values self.alpha = np.power(10, np.array([-1, -1.301, -2, -3])).round(3) # Sets up a vector of samples self.num_samps = np.arange(10, 100, 10) # Sets up a mapping file meta = {'GW': {'INT': 'N', 'ABX': np.nan, 'DIV': 19.5, 'AGE': '30s', 'SEX': 'M'}, 'CB': {'INT': 'Y', 'ABX': np.nan, 'DIV': 42.7, 'AGE': '30s', 'SEX': 'M'}, 'WM': {'INT': 'N', 'ABX': 'N', 'DIV': 27.5, 'AGE': '20s', 'SEX': 'F'}, 'MH': {'INT': 'Y', 'ABX': 'N', 'DIV': 62.3, 'AGE': '30s', 'SEX': 'F'}, 'CD': {'INT': 'Y', 'ABX': 'Y', 'DIV': 36.4, 'AGE': '40s', 'SEX': 'F'}, 'LF': {'INT': 'Y', 'ABX': 'N', 'DIV': 50.2, 'AGE': '20s', 'SEX': 'M'}, 'PP': {'INT': 'N', 'ABX': 'Y', 'DIV': 10.8, 'AGE': '30s', 'SEX': 'F'}, 'MM': {'INT': 'N', 'ABX': 'N', 'DIV': 55.6, 'AGE': '40s', 'SEX': 'F'}, 'SR': {'INT': 'N', 'ABX': 'Y', 'DIV': 2.2, 'AGE': '20s', 'SEX': 'M'}, 'TS': {'INT': 'N', 'ABX': 'Y', 'DIV': 16.1, 'AGE': '40s', 'SEX': 'M'}, 'PC': {'INT': 'Y', 'ABX': 'N', 'DIV': 82.6, 'AGE': '40s', 'SEX': 'M'}, 'NR': {'INT': 'Y', 'ABX': 'Y', 'DIV': 15.7, 'AGE': '20s', 'SEX': 'F'}} self.meta = pd.DataFrame.from_dict(meta, orient='index') self.meta_pairs = {0: [['GW', 'SR', 'TS'], ['CB', 'LF', 'PC']], 1: [['MM', 'PP', 'WM'], ['CD', 'MH', 'NR']]} self.pair_index = np.array([0, 0, 0, 1, 1, 1]) self.counts = np.array([5, 15, 25, 35, 45]) self.powers = [np.array([[0.105, 0.137, 0.174, 0.208, 0.280], [0.115, 0.135, 0.196, 0.204, 0.281], [0.096, 0.170, 0.165, 0.232, 0.256], [0.122, 0.157, 0.202, 0.250, 0.279], [0.132, 0.135, 0.173, 0.203, 0.279]]), np.array([[0.157, 0.345, 0.522, 0.639, 0.739], [0.159, 0.374, 0.519, 0.646, 0.757], [0.161, 0.339, 0.532, 0.634, 0.745], [0.169, 0.372, 0.541, 0.646, 0.762], [0.163, 0.371, 0.522, 0.648, 0.746]]), np.array([[0.276, 0.626, 0.865, 0.927, 0.992], [0.267, 0.667, 0.848, 0.937, 0.978], [0.236, 0.642, 0.850, 0.935, 0.977], [0.249, 0.633, 0.828, 0.955, 0.986], [0.249, 0.663, 0.869, 0.951, 0.985]])] self.power_alpha = 0.1 self.effects = np.array([0.15245, 0.34877, 0.55830]) self.bounds = np.array([0.01049, 0.00299, 0.007492]) self.labels = np.array(['Age', 'Intervenption', 'Antibiotics']) self.cats = np.array(['AGE', 'INT', 'ABX']) self.cat = "AGE" self.control_cats = ['INT', 'ABX'] def test_subsample_power_defaults(self): test_p, test_c = subsample_power(self.f, self.pop, num_iter=10, num_runs=5) self.assertEqual(test_p.shape, (5, 4)) npt.assert_array_equal(np.array([10, 20, 30, 40]), test_c) def test_subsample_power_counts(self): test_p, test_c = subsample_power(self.f, samples=self.pop, num_iter=10, num_runs=2, min_counts=5) self.assertEqual(test_p.shape, (2, 5)) npt.assert_array_equal(np.arange(5, 50, 10), test_c) def test_subsample_power_matches(self): test_p, test_c = subsample_power(self.f, samples=self.pop, num_iter=10, num_runs=5, draw_mode="matched") self.assertEqual(test_p.shape, (5, 4)) npt.assert_array_equal(np.array([10, 20, 30, 40]), test_c) def test_subsample_power_multi_p(self): test_p, test_c = subsample_power(lambda x: np.array([0.5, 0.5]), samples=self.pop, num_iter=10, num_runs=5) self.assertEqual(test_p.shape, (5, 4, 2)) npt.assert_array_equal(np.array([10, 20, 30, 40]), test_c) def test_subsample_paired_power(self): known_c = np.array([1, 2, 3, 4]) # Sets up the handling values cat = 'INT' control_cats = ['SEX'] # Tests for the control cats test_p, test_c = subsample_paired_power(self.meta_f, meta=self.meta, cat=cat, control_cats=control_cats, counts_interval=1, num_iter=10, num_runs=2) # Test the output shapes are sane self.assertEqual(test_p.shape, (2, 4)) npt.assert_array_equal(known_c, test_c) def test_subsample_paired_power_multi_p(self): def f(x): return np.array([0.5, 0.5, 0.005]) cat = 'INT' control_cats = ['SEX'] # Tests for the control cats test_p, test_c = subsample_paired_power(f, meta=self.meta, cat=cat, control_cats=control_cats, counts_interval=1, num_iter=10, num_runs=2) self.assertEqual(test_p.shape, (2, 4, 3)) def test_check_nans_str(self): self.assertTrue(_check_nans('string')) def test_check_nans_num(self): self.assertTrue(_check_nans(4.2)) def test__check_nans_nan(self): self.assertFalse(_check_nans(np.nan)) def test__check_nans_clean_list(self): self.assertTrue(_check_nans(['foo', 'bar'], switch=True)) def test__check_nans_list_nan(self): self.assertFalse(_check_nans(['foo', np.nan], switch=True)) def test__check_str_error(self): with self.assertRaises(TypeError): _check_nans(self.f) def test__get_min_size_strict(self): known = 5 test = _get_min_size(self.meta, 'INT', ['ABX', 'SEX'], ['Y', 'N'], True) self.assertEqual(test, known) def test__get_min_size_relaxed(self): known = 5 test = _get_min_size(self.meta, 'INT', ['ABX', 'SEX'], ['Y', 'N'], False) self.assertEqual(known, test) def test_confidence_bound_default(self): # Sets the know confidence bound known = 2.2830070 test = confidence_bound(self.s1) npt.assert_almost_equal(test, known, 3) def test_confidence_bound_df(self): known = 2.15109 test = confidence_bound(self.s1, df=15) npt.assert_almost_equal(known, test, 3) def test_confidence_bound_alpha(self): known = 3.2797886 test = confidence_bound(self.s1, alpha=0.01) npt.assert_almost_equal(known, test, 3) def test_confidence_bound_nan(self): # Sets the value to test samples = np.array([[4, 3.2, 3.05], [2, 2.8, 2.95], [5, 2.9, 3.07], [1, 3.1, 2.93], [3, np.nan, 3.00]]) # Sets the know value known = np.array([2.2284, 0.2573, 0.08573]) # Tests the function test = confidence_bound(samples, axis=0) npt.assert_almost_equal(known, test, 3) def test_confidence_bound_axis_none(self): # Sets the value to test samples = np.array([[4, 3.2, 3.05], [2, 2.8, 2.95], [5, 2.9, 3.07], [1, 3.1, 2.93], [3, np.nan, 3.00]]) # Sest the known value known = 0.52852 # Tests the output test = confidence_bound(samples, axis=None) npt.assert_almost_equal(known, test, 3) def test__calculate_power(self): # Sets up the values to test crit = 0.025 # Sets the known value known = 0.5 # Calculates the test value test = _calculate_power(self.alpha, crit) # Checks the test value npt.assert_almost_equal(known, test) def test__calculate_power_n(self): crit = 0.025 known = np.array([0.5, 0.5]) alpha = np.vstack((self.alpha, self.alpha)) test = _calculate_power(alpha, crit) npt.assert_almost_equal(known, test) def test__compare_distributions_sample_counts_error(self): with self.assertRaises(ValueError): _compare_distributions(self.f, [self.pop[0][:5], self.pop[1]], 1, counts=25) def test__compare_distributions_all_mode(self): known = np.ones((100))*0.0026998 test = _compare_distributions(self.f, self.samps, 1, num_iter=100) npt.assert_allclose(known, test, 5) def test__compare_distributions_matched_mode(self): # Sets the known value known_mean = 0.162195 known_std = 0.121887 known_shape = (100,) # Tests the sample value test = _compare_distributions(self.f, self.pop, self.num_p, mode='matched', num_iter=100) # This test is temporarily masked because it fails on CI with cp310-macosx_x86_64. # npt.assert_allclose(known_mean, test.mean(), rtol=0.1, atol=0.02) # npt.assert_allclose(known_std, test.std(), rtol=0.1, atol=0.02) self.assertEqual(known_shape, test.shape) def test__compare_distributions_draw_mode(self): draw_mode = 'Ultron' with self.assertRaises(ValueError): _check_subsample_power_inputs(self.f, self.pop, draw_mode, self.num_p) def test__compare_distributions_multiple_returns(self): known = np.array([[1, 1, 1], [2, 2, 2], [3, 3, 3]]) def f(x): return np.array([1, 2, 3]) test = _compare_distributions(f, self.pop, 3, mode='matched', num_iter=3) npt.assert_array_equal(known, test) def test_check_subsample_power_inputs_matched_mode(self): with self.assertRaises(ValueError): _check_subsample_power_inputs(self.f, samples=[np.ones((2)), np.ones((5))], draw_mode="matched") def test_check_subsample_power_inputs_counts(self): with self.assertRaises(ValueError): _check_subsample_power_inputs(self.f, samples=[np.ones((3)), np.ones((5))], min_counts=5, counts_interval=1000, max_counts=7) def test_check_subsample_power_inputs_ratio(self): with self.assertRaises(ValueError): _check_subsample_power_inputs(self.f, self.samps, ratio=np.array([1, 2, 3])) def test_check_subsample_power_inputs_test(self): # Defines a test function def test(x): return 'Hello World!' with self.assertRaises(TypeError): _check_subsample_power_inputs(test, self.samps) def test_check_sample_power_inputs(self): # Defines the know returns known_num_p = 1 known_ratio = np.ones((2)) known_counts = np.arange(2, 10, 2) # Runs the code for the returns test_ratio, test_num_p, test_counts = \ _check_subsample_power_inputs(self.f, self.samps, counts_interval=2, max_counts=10) # Checks the returns are sane self.assertEqual(known_num_p, test_num_p) npt.assert_array_equal(known_ratio, test_ratio) npt.assert_array_equal(known_counts, test_counts) def test__calculate_power_curve_ratio_error(self): with self.assertRaises(ValueError): _calculate_power_curve(self.f, self.pop, self.num_samps, ratio=np.array([0.1, 0.2, 0.3]), num_iter=100) def test__calculate_power_curve_default(self): # Sets the known output known = np.array([0.49, 0.83, 0.97, 1., 1., 1., 1., 1., 1.]) # Generates the test values test = _calculate_power_curve(self.f, self.pop, self.num_samps, num_iter=100, seed=42) # Checks the samples returned sanely npt.assert_allclose(test, known, rtol=0.1, atol=0.01) def test__calculate_power_curve_alpha(self): # Sets the know output known = np.array([0.22, 0.62, 0.83, 0.94, 1., 1., 1., 1., 1.]) # Generates the test values test = _calculate_power_curve(self.f, self.pop, self.num_samps, alpha=0.01, num_iter=100, seed=42) # Checks the samples returned sanely npt.assert_allclose(test, known, rtol=0.1, atol=0.1) def test__calculate_power_curve_ratio(self): # Sets the know output known = np.array([0.08, 0.31, 0.59, 0.69, 0.77, 0.91, 0.99, 0.99, 1.]) # Generates the test values test = _calculate_power_curve(self.f, self.pop, self.num_samps, ratio=np.array([0.25, 0.75]), num_iter=100, seed=42) # Checks the samples returned sanely npt.assert_allclose(test, known, rtol=0.1, atol=0.1) def test_paired_subsamples_default(self): # Sets the known np.array set known_array = [{'MM', 'SR', 'TS', 'GW', 'PP', 'WM'}, {'CD', 'LF', 'PC', 'CB', 'MH', 'NR'}] # Gets the test value cat = 'INT' control_cats = ['SEX', 'AGE'] test_array = paired_subsamples(self.meta, cat, control_cats) self.assertEqual(known_array[0], set(test_array[0])) self.assertEqual(known_array[1], set(test_array[1])) def test_paired_subsamples_break(self): # Sets known np.array set known_array = [np.array([]), np.array([])] # Gets the test value cat = 'ABX' control_cats = ['SEX', 'AGE', 'INT'] test_array = paired_subsamples(self.meta, cat, control_cats) npt.assert_array_equal(known_array, test_array) def test_paired_subsample_undefined(self): known_array = np.zeros((2, 0)) cat = 'INT' order = ['Y', 'N'] control_cats = ['AGE', 'ABX', 'SEX'] test_array = paired_subsamples(self.meta, cat, control_cats, order=order) npt.assert_array_equal(test_array, known_array) def test_paired_subsample_fewer(self): # Set known value known_array = {'PP', 'MH', 'CD', 'PC', 'TS', 'MM'} # Sets up test values cat = 'AGE' order = ['30s', '40s'] control_cats = ['ABX'] test_array = paired_subsamples(self.meta, cat, control_cats, order=order) for v in test_array[0]: self.assertTrue(v in known_array) for v in test_array[1]: self.assertTrue(v in known_array) @skipIf(PANDAS_3, reason="TODO: NaN behavior changed in pandas 3.0") def test_paired_subsamples_not_strict(self): known_array = [{'WM', 'MM', 'GW', 'SR', 'TS'}, {'LF', 'PC', 'CB', 'NR', 'CD'}] # Gets the test values cat = 'INT' control_cats = ['ABX', 'AGE'] test_array = paired_subsamples(self.meta, cat, control_cats, strict_match=False) self.assertEqual(set(test_array[0]), known_array[0]) self.assertEqual(set(test_array[1]), known_array[1]) def test__identify_sample_groups(self): # Defines the know values known_pairs = {0: [['MM'], ['CD']], 1: [['SR'], ['LF']], 2: [['TS'], ['PC']], 3: [['GW'], ['CB']], 4: [['PP'], ['MH']], 5: [['WM'], ['NR']]} known_index = np.array([0, 1, 2, 3, 4, 5]) test_pairs, test_index = _identify_sample_groups(self.meta, 'INT', ['SEX', 'AGE'], order=['N', 'Y'], strict_match=True) self.assertEqual(known_pairs.keys(), test_pairs.keys()) self.assertEqual(sorted(known_pairs.values()), sorted(test_pairs.values())) npt.assert_array_equal(known_index, test_index) @skipIf(PANDAS_3, reason="TODO: NaN behavior changed in pandas 3.0") def test__identify_sample_groups_not_strict(self): # Defines the know values known_pairs = {1: [np.array(['PP'], dtype=object), np.array(['CD', 'NR'], dtype=object)], 0: [np.array(['MM', 'WM'], dtype=object), np.array(['MH'], dtype=object)], 2: [np.array(['GW'], dtype=object), np.array(['CB'], dtype=object)]} known_index = np.array([0, 1, 2]) test_pairs, test_index = _identify_sample_groups(self.meta, 'INT', ['SEX', 'ABX'], order=['N', 'Y'], strict_match=False) self.assertEqual(known_pairs.keys(), test_pairs.keys()) for k in known_pairs: for i in range(2): npt.assert_array_equal(known_pairs[k][i], test_pairs[k][i]) npt.assert_array_equal(known_index, test_index) def test__draw_paired_samples(self): num_samps = 3 known_sets = [{'GW', 'SR', 'TS', 'MM', 'PP', 'WM'}, {'CB', 'LF', 'PC', 'CD', 'MH', 'NR'}] test_samps = _draw_paired_samples(self.meta_pairs, self.pair_index, num_samps) for i, t in enumerate(test_samps): self.assertTrue(set(t).issubset(known_sets[i])) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/stats/tests/test_subsample.py000066400000000000000000000213541520735541300253730ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest import warnings import numpy as np import numpy.testing as npt from skbio.stats import subsample_counts, isubsample def setup(): """Ignore warnings during tests.""" warnings.simplefilter("ignore") def teardown(): """Clear the list of warning filters, so that no filters are active.""" warnings.resetwarnings() class SubsampleCountsTests(unittest.TestCase): def test_subsample_counts_nonrandom(self): a = np.array([0, 5, 0]) # Subsample same number of items that are in input (without # replacement). npt.assert_equal(subsample_counts(a, 5), a) # Can only choose from one bin. exp = np.array([0, 2, 0]) npt.assert_equal(subsample_counts(a, 2), exp) npt.assert_equal( subsample_counts(a, 2, replace=True), exp) # Subsample zero items. a = [3, 0, 1] exp = np.array([0, 0, 0]) npt.assert_equal(subsample_counts(a, 0), exp) npt.assert_equal(subsample_counts(a, 0, replace=True), exp) def test_subsample_counts_without_replacement(self): # Selecting 2 counts from the vector 1000 times yields each of the two # possible results at least once each. a = np.array([2, 0, 1]) actual = set() for i in range(1000): obs = subsample_counts(a, 2) actual.add(tuple(obs)) self.assertEqual(actual, {(1, 0, 1), (2, 0, 0)}) obs = subsample_counts(a, 2) self.assertTrue(np.array_equal(obs, np.array([1, 0, 1])) or np.array_equal(obs, np.array([2, 0, 0]))) def test_subsample_counts_with_replacement(self): # Can choose from all in first bin, all in last bin (since we're # sampling with replacement), or split across bins. a = np.array([2, 0, 1]) actual = set() for i in range(1000): obs = subsample_counts(a, 2, replace=True) actual.add(tuple(obs)) self.assertEqual(actual, {(1, 0, 1), (2, 0, 0), (0, 0, 2)}) # Test that selecting 35 counts from a 36-count vector 1000 times # yields more than 10 different subsamples. If we were subsampling # *without* replacement, there would be only 10 possible subsamples # because there are 10 nonzero bins in array a. However, there are more # than 10 possibilities when sampling *with* replacement. a = np.array([2, 0, 1, 2, 1, 8, 6, 0, 3, 3, 5, 0, 0, 0, 5]) actual = set() for i in range(1000): obs = subsample_counts(a, 35, replace=True) self.assertEqual(obs.sum(), 35) actual.add(tuple(obs)) self.assertTrue(len(actual) > 10) def test_subsample_counts_with_replacement_equal_n(self): # test when n == counts.sum() a = np.array([0, 0, 3, 4, 2, 1]) actual = set() for i in range(1000): obs = subsample_counts(a, 10, replace=True) self.assertEqual(obs.sum(), 10) actual.add(tuple(obs)) self.assertTrue(len(actual) > 1) def test_subsample_counts_invalid_input(self): # Negative n. with self.assertRaises(ValueError): subsample_counts([1, 2, 3], -1) # Wrong number of dimensions. with self.assertRaises(ValueError): subsample_counts([[1, 2, 3], [4, 5, 6]], 2) # Input has too few counts. with self.assertRaises(ValueError): subsample_counts([0, 5, 0], 6, replace=False) # Input has too counts, but should work with bootstrap subsample_counts([0, 5, 0], 6, replace=True) class ISubsampleTests(unittest.TestCase): def setUp(self): # comment indicates the expected random value self.sequences = [ ('a_1', 'AATTGGCC-a1'), # 2, 3624216819017203053 ('a_2', 'AATTGGCC-a2'), # 5, 5278339153051796802 ('b_1', 'AATTGGCC-b1'), # 4, 4184670734919783522 ('b_2', 'AATTGGCC-b2'), # 0, 946590342492863505 ('a_4', 'AATTGGCC-a4'), # 3, 4048487933969823850 ('a_3', 'AATTGGCC-a3'), # 7, 7804936597957240377 ('c_1', 'AATTGGCC-c1'), # 8, 8868534167180302049 ('a_5', 'AATTGGCC-a5'), # 1, 3409506807702804593 ('c_2', 'AATTGGCC-c2'), # 9, 8871627813779918895 ('c_3', 'AATTGGCC-c3') # 6, 7233291490207274528 ] def mock_sequence_iter(self, items): return ({'SequenceID': sid, 'Sequence': seq} for sid, seq in items) def test_isubsample_simple(self): maximum = 10 def bin_f(x): return x['SequenceID'].rsplit('_', 1)[0] # note, the result here is sorted by sequence_id but is in heap order # by the random values associated to each sequence exp = sorted([('a', {'SequenceID': 'a_2', 'Sequence': 'AATTGGCC-a2'}), ('a', {'SequenceID': 'a_5', 'Sequence': 'AATTGGCC-a5'}), ('a', {'SequenceID': 'a_4', 'Sequence': 'AATTGGCC-a4'}), ('a', {'SequenceID': 'a_3', 'Sequence': 'AATTGGCC-a3'}), ('a', {'SequenceID': 'a_1', 'Sequence': 'AATTGGCC-a1'}), ('b', {'SequenceID': 'b_2', 'Sequence': 'AATTGGCC-b2'}), ('b', {'SequenceID': 'b_1', 'Sequence': 'AATTGGCC-b1'}), ('c', {'SequenceID': 'c_2', 'Sequence': 'AATTGGCC-c2'}), ('c', {'SequenceID': 'c_1', 'Sequence': 'AATTGGCC-c1'}), ('c', {'SequenceID': 'c_3', 'Sequence': 'AATTGGCC-c3'})], key=lambda x: x[0]) obs = isubsample(self.mock_sequence_iter(self.sequences), maximum, bin_f=bin_f, seed=123) self.assertEqual(sorted(obs, key=lambda x: x[0]), exp) def test_per_sample_sequences_min_seqs(self): maximum = 10 minimum = 3 def bin_f(x): return x['SequenceID'].rsplit('_', 1)[0] # note, the result here is sorted by sequence_id but is in heap order # by the random values associated to each sequence exp = sorted([('a', {'SequenceID': 'a_2', 'Sequence': 'AATTGGCC-a2'}), ('a', {'SequenceID': 'a_5', 'Sequence': 'AATTGGCC-a5'}), ('a', {'SequenceID': 'a_4', 'Sequence': 'AATTGGCC-a4'}), ('a', {'SequenceID': 'a_3', 'Sequence': 'AATTGGCC-a3'}), ('a', {'SequenceID': 'a_1', 'Sequence': 'AATTGGCC-a1'}), ('c', {'SequenceID': 'c_2', 'Sequence': 'AATTGGCC-c2'}), ('c', {'SequenceID': 'c_1', 'Sequence': 'AATTGGCC-c1'}), ('c', {'SequenceID': 'c_3', 'Sequence': 'AATTGGCC-c3'})], key=lambda x: x[0]) obs = isubsample(self.mock_sequence_iter(self.sequences), maximum, minimum, bin_f=bin_f, seed=123) self.assertEqual(sorted(obs, key=lambda x: x[0]), exp) def test_per_sample_sequences_complex(self): maximum = 2 def bin_f(x): return x['SequenceID'].rsplit('_', 1)[0] exp = sorted([('a', {'SequenceID': 'a_1', 'Sequence': 'AATTGGCC-a1'}), ('a', {'SequenceID': 'a_3', 'Sequence': 'AATTGGCC-a3'}), ('b', {'SequenceID': 'b_2', 'Sequence': 'AATTGGCC-b2'}), ('b', {'SequenceID': 'b_1', 'Sequence': 'AATTGGCC-b1'}), ('c', {'SequenceID': 'c_3', 'Sequence': 'AATTGGCC-c3'}), ('c', {'SequenceID': 'c_1', 'Sequence': 'AATTGGCC-c1'})], key=lambda x: x[0]) obs = isubsample(self.mock_sequence_iter(self.sequences), maximum, bin_f=bin_f, buf_size=1, seed=123) self.assertEqual(sorted(obs, key=lambda x: x[0]), exp) def test_min_gt_max(self): gen = isubsample([1, 2, 3], maximum=2, minimum=10) with self.assertRaises(ValueError): next(gen) def test_min_lt_zero(self): gen = isubsample([1, 2, 3], maximum=0, minimum=-10) with self.assertRaises(ValueError): next(gen) def test_max_lt_zero(self): gen = isubsample([1, 2, 3], maximum=-10) with self.assertRaises(ValueError): next(gen) def test_binf_is_none(self): maximum = 2 items = [1, 2] exp = [(True, 2), (True, 1)] obs = isubsample(items, maximum, seed=123) self.assertEqual(list(obs), exp) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/table/000077500000000000000000000000001520735541300205515ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/table/__init__.py000066400000000000000000000224641520735541300226720ustar00rootroot00000000000000r"""Data Table (:mod:`skbio.table`) ================================== .. currentmodule:: skbio.table Tabular data are among the most common data structures in bioinformatics and many other fields. scikit-bio provides a powerful table class for biological data (:class:`Table`), a flexible system that accepts multiple input formats and returns results in the user's preferred format, and algorithms for manipulating tabular data in biological research. See an |table_intro|_ to the specifics, nomenclature and usage of data tables in scikit-bio. BIOM table ---------- `Biological Observation Matrix (BIOM) `_ is an efficient and versatile sparse table format designed for biological "omic" data types. It is the native table format in scikit-bio. .. autosummary:: :toctree: generated/ Table example_table Table-like formats ------------------ scikit-bio functions directly operate on various "table-like" formats, such as BIOM table, Pandas and Polars dataframes, NumPy array and AnnData objects, without the need for explicit format conversion. - :ref:`table_like` - :ref:`array_like` Data augmentation ----------------- Techniques for creating synthetic samples based on the current data and biological properties. Helpful for improving the accuracy and robustness of machine learning models. .. autosummary:: :toctree: generated/ phylomix compos_cutmix aitchison_mixup mixup .. |table_intro| replace:: **Introduction** .. _table_intro: Introduction ------------ In scikit-bio, a table is an **ID-labeled data matrix**. Data are stored in a two-dimensional structure with **rows = samples** and **columns = features**. Cell values represent counts, abundances, or other numeric measurements of a given feature within a given sample. The entire table must be in a homogeneous data type. Internally, a table is decomposed into a 2-D data matrix, and lists of sample IDs and feature IDs (:ref:`explained below `). IDs are optional. When they are absent, scikit-bio uses integer indices to refer to samples and features. When IDs are present, however, scikit-bio uses them to bridge structured biological knowledge with numeric data, enabling convenient ID-based in addition to index-based operations (e.g., :func:`~skbio.diversity.alpha_diversity` and :class:`~skbio.stats.distance.DistanceMatrix`). .. _table_like: Supported table-like formats ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Scikit-bio supports a variety of table-like formats used in bioinformatics, scientific computing and data science in general. When a function parameter is annotated as ``table_like``, it accepts any of the following formats: +--------------------------------------+---------------------+------------------------+ | Format | Sample IDs | Feature IDs | +======================================+=====================+========================+ | skbio :class:`~skbio.table.Table`\ | "sample" | "observation" | | (i.e., BIOM table) | | | +--------------------------------------+---------------------+------------------------+ | anndata :class:`~anndata.AnnData` | "obs" (observation) | "var" (variable) | +--------------------------------------+---------------------+------------------------+ | Pandas :class:`~pandas.DataFrame` | "index" (rows) | "columns" | +--------------------------------------+---------------------+------------------------+ | Polars |pl_df|_ | N/A (rows) | "schema" | +--------------------------------------+---------------------+------------------------+ | array-like objects \ | N/A | N/A | | (:ref:`detailed below `) | | | +--------------------------------------+---------------------+------------------------+ Input handling of supported types is automatic. No manual conversion is required. If provided, sample and feature IDs will be preserved and propagated to downstream results. Otherwise, integer indices starting at 0 will be used. .. _array_like: Supported array-like formats ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Scikit-bio supports a wide range of array libraries in the Python ecosystem. A parameter annotated as ``array_like`` accepts any of the following formats: - Numpy :class:`~numpy.ndarray`, the "native" format which most of scikit-bio's functions are optimized for (e.g., utilizing vectorization if possible). - Any array object compliant with the `Python array API standard `_. Examples are PyTorch ``Tensor``, CuPy ``ndarray``, JAX ``Array``, Dask ``Array``, and sparse ``SparseArray``. - Any object convertible to a ≥1-dimensional NumPy array via :func:`~numpy.asarray`. Examples are plain Python lists and tuples. .. note:: A proportion of scikit-bio functions offer *native* support for alternative array libraries. For instance, log-ratio transformations like :func:`~skbio.stats.composition.clr` can consume and return GPU-resident tensors with arbitrary dimensions, eliminating the overhead of round-tripping through NumPy and significantly accelerating computation. .. _samples_and_features: Samples and features ^^^^^^^^^^^^^^^^^^^^ Typically, the two table dimensions represent: - **Sample IDs** (row labels): biological samples, or any other experimental units (specimens, subjects, sites, time points, cells, etc.). - **Feature IDs** (column labels): variables or characteristics measured in each sample (taxa, genes, molecules, environmental factors, etc.). Terminology varies across disciplines and can sometimes be confusing. Scikit-bio standardizes on "sample" and "feature" -- the most common terms in data science. But you may encounter aliases: * In the BIOM format (wrapped by :mod:`skbio.table`), features are called "observations" and samples stay "samples". (Beware: in anndata, "observations" instead refer to samples.) * Some other scikit-bio sub-modules adopt field-specific terms, documented on their index pages, such as: - :mod:`skbio.diversity`: sample → "community", feature → "taxon" - :mod:`skbio.stats.composition`: sample → "composition", feature → "component" Depending on the research task, you are free to transpose a table to swap samples and features. .. _table_params: Common parameters ^^^^^^^^^^^^^^^^^ Many functions involving tabular data share a set of common parameters that control how IDs are handled and specify output format preferences: ``sample_ids`` : *list of str, optional* Identifiers for samples (rows). If not provided implicitly by the input table or explicitly by the user, defaults to ``range(n_samples)``. This parameter is useful when the input format doesn't support row labels (e.g., NumPy arrays) or when you want to override existing labels. ``feature_ids`` : *list of str, optional* Identifiers for features (columns). Analogous to ``sample_ids``. Default: ``range(n_features)``. ``output_format`` : *{"pandas", "numpy", "polars"}*, optional Preferred output format **for this call only** (default: ``"pandas"``). This setting overrides the global configuration (see below). .. _table_output: Output formats ^^^^^^^^^^^^^^ Some functions that *produce* tables can return the result in one of three formats: - Pandas :class:`~pandas.DataFrame` and :class:`~pandas.Series` (default) - Polars |pl_df|_ and |pl_s|_ - NumPy :class:`~numpy.ndarray` (2-D and 1-D) There are two ways to control the output format: 1. Set the desired output format on a per-function basis, using the ``output_format`` parameter. .. code-block:: python from skbio.stats.ordination import cca # This specific call will return an `OrdinationResults` object whose attributes are # NumPy arrays. res = cca(Y, X, output_format="numpy") 2. Set the ``table_output`` configuration option using :func:`skbio.set_config`. It will change the global behavior of all scikit-bio functions. .. code-block:: python # `set_config` is available as a top level import from skbio from skbio import set_config # Set output format to NumPy arrays, or set_config("table_output", "numpy") # Return to default Pandas output set_config("table_output", "pandas") .. Polars DataFrame and Series cannot be cross-linked therefore the following workaround is used. See: https://github.com/pola-rs/polars/issues/7027 .. |pl_df| replace:: ``DataFrame`` .. _pl_df: https://docs.pola.rs/api/python/stable/reference/dataframe/index.html .. |pl_s| replace:: ``Series`` .. _pl_s: https://docs.pola.rs/api/python/stable/reference/series/index.html """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from skbio.table._base import Table, example_table from skbio.table._augment import phylomix, compos_cutmix, aitchison_mixup, mixup __all__ = [ "Table", "example_table", "phylomix", "compos_cutmix", "aitchison_mixup", "mixup", ] scikit-bio-scikit-bio-a3beaa6/skbio/table/_augment.py000066400000000000000000001026651520735541300227340ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from typing import TYPE_CHECKING import numpy as np from skbio.util import get_rng from skbio.stats.composition import closure from skbio.table._tabular import _ingest_table if TYPE_CHECKING: # pragma: no cover from collections.abc import Sequence from numpy.typing import ArrayLike, NDArray from skbio.tree import TreeNode from skbio.util._typing import TableLike, SeedLike def _validate_labels(labels: NDArray, n: int) -> tuple[NDArray, NDArray]: r"""Ensure that the provided label is appropriate for the provided matrix. Parameters ---------- labels : array_like of shape (n_samples,) or (n_samples, n_classes) Class labels for the data. n : int Number of samples. Returns ------- labels_index : ndarray of shape (n_samples,) The class labels in 1-D format. Contains indices from 0 to n_classes - 1. If the input was already 1-D, this is the same as the input. If the input was one-hot encoded, this is the argmax reconstruction. labels_one_hot : ndarray of shape (n_samples, n_classes) The class labels in one-hot encoded format. Each row contains exactly one 1 and the rest 0s, indicating the class membership for that sample. Raises ------ ValueError If labels are not 1-D or 2-D. ValueError If labels' sample count is not ``n``. ValueError If index labels contain non-integer values. ValueError If index labels do not start from zero. ValueError If index labels are not consecutive integers. ValueError If one-hot encoded labels are not valid. """ labels = np.asarray(labels) if labels.ndim not in (1, 2): raise ValueError( f"Labels should be 1-D or 2-D, but got {labels.ndim} dimensions instead." ) if labels.shape[0] != n: raise ValueError( f"Number of labels ({labels.shape[0]}) does not match number of samples " f"in the data ({n})." ) # input as indexed labels if labels.ndim == 1: # if labels is not integer-type, make sure it contains only whole numbers, # then convert to int if not np.issubdtype(labels.dtype, np.integer): if not (np.mod(labels, 1) == 0).all(): raise ValueError(f"Labels must only contain integer values.") labels = labels.astype(int) # check that labels are 0-indexed unique_labels = np.unique(labels) if unique_labels.min() != 0: raise ValueError("Labels must be zero-indexed. Minimum value must be 0.") n_classes = len(unique_labels) exp_labels = np.arange(n_classes) # check that label is consecutive integers starting at 0 if not np.array_equal(unique_labels, exp_labels): raise ValueError( "Labels must be consecutive integers from 0 to n_classes - 1." ) # perform one-hot encoding labels_one_hot = np.eye(n_classes, dtype=int)[labels] return labels, labels_one_hot # input as one-hot encoded labels else: # all rows should sum to 1 if not np.allclose(labels.sum(axis=1), 1): raise ValueError("Labels are not properly one-hot encoded.") # generated label indices labels_index = labels.argmax(axis=1) return labels_index, labels def _normalize_matrix(matrix: NDArray) -> NDArray: r"""Normalize a data matrix if needed such that each row sums to 1. Parameters ---------- matrix : ndarray of shape (n_samples, n_features) Original matrix. Returns ------- ndarray of shape (n_samples, n_features) Normalized matrix. """ if np.allclose(matrix.sum(axis=1), 1): return matrix return closure(matrix) def _all_pairs(n: int) -> NDArray: r"""Get all pairs of sample indices. Parameters ---------- n : int Number of samples. Returns ------- ndarray of shape (n_pairs, 2), dtype=int Pairs of sample indices. """ return np.column_stack(np.triu_indices(n, k=1)) def _intra_class_pairs(labels: ArrayLike) -> NDArray: r"""Get pairs of sample indices within each class. Parameters ---------- labels : array_like of shape (n_samples,), dtype=int Class labels of samples. Returns ------- ndarray of shape (n_pairs, 2), dtype=int Pairs of sample indices. """ pairs = [] for label in np.unique(labels): idx = np.where(labels == label)[0] if idx.size > 1: i, j = np.triu_indices(idx.size, k=1) pairs.append(np.column_stack((idx[i], idx[j]))) if pairs: return np.vstack(pairs) else: return np.empty((0, 2), dtype=np.intp) def _format_input( table: TableLike, labels: Sequence | NDArray, intra_class: bool | None = False, normalize: bool | None = False, taxa: Sequence | NDArray | None = None, ) -> tuple[ NDArray, NDArray | None, NDArray, Sequence | NDArray | None, ]: """Format input data for augmentation. Parameters ---------- table : table_like of shape (n_samples, n_features) Input data table. labels : array_like of shape (n_samples,) or (n_samples, n_classes), optional Class labels for the data. intra_class : bool, optional If True, pair samples within each class. normalize : bool, optional If True, normalize the data. taxa : array_like of shape (n_features,), optional Feature IDs corresponding to tip names in a tree. Returns ------- matrix : ndarray of shape (n_samples, n_features) Data matrix (X). labels : ndarray of shape (n_samples, n_classes), optional Class labels (one-hot encoded) (Y). pairs : ndarray of shape (n_pairs, 2) Pairs of sample indices to be mixed up. taxa : array_like of shape (n_features,), optional Feature IDs corresponding to tip names in a tree. """ matrix, _, taxa = _ingest_table(table, feature_ids=taxa) if normalize: matrix = _normalize_matrix(matrix) n_samples = matrix.shape[0] if labels is None: pairs = _all_pairs(n_samples) labels_2d = None else: labels_1d, labels_2d = _validate_labels(labels, n_samples) if intra_class: pairs = _intra_class_pairs(labels_1d) else: pairs = _all_pairs(n_samples) if len(pairs) == 0: raise ValueError("Cannot find a pair of samples to mix.") return matrix, labels_2d, pairs, taxa def _make_aug_labels( labels: NDArray | None, pairs: NDArray, lams: NDArray, intra_class: bool, ) -> NDArray | None: r"""Generate class labels for synthetic samples. Parameters ---------- labels : ndarray of shape (n, n_classes), or None Original class labels in one-hot encoded format. pairs : ndarray of shape (n_pairs, 2) Pairs of sample indices that were mixed up to create synthetic samples. lams : ndarray of shape (n, 1) Lambda parameters (probabilities) used during mixing-up. intra_class : bool If True, samples were paired within each class. Returns ------- aug_labels : ndarray of shape (n, n_classes), or None Synthetic class labels in one-hot encoded format. """ if labels is None: return None elif intra_class: return labels[pairs[:, 0]] else: return lams * labels[pairs[:, 0]] + (1.0 - lams) * labels[pairs[:, 1]] def _format_output( aug_matrix: NDArray, aug_labels: NDArray | None, matrix: NDArray, labels: NDArray | None, append: bool = False, ) -> tuple[NDArray, NDArray]: """Format output data of augmentation. Parameters ---------- aug_matrix : array_like of shape (n, n_features) Augmented data matrix. aug_labels : array_like of shape (n, n_classes), optional Augmented class labels in one-hot encoded format. matrix : ndarray of shape (n_samples, n_features), optional Original data matrix. labels : ndarray of shape (n_samples, n_classes), optional Original class labels in one-hot encoded format. Returns ------- aug_matrix : ndarray of shape ([n_samples + ]n, n_features) Augmented data matrix. aug_labels : ndarray of shape ([n_samples + ]n, n_classes), optional Augmented class labels in one-hot encoded format. """ # concatenate original and synthetic data if append: aug_matrix = np.concatenate([matrix, aug_matrix]) if aug_labels is not None: aug_labels = np.concatenate([labels, aug_labels]) # not necessary because upstream code already enforced it; but for safety else: aug_matrix = np.asarray(aug_matrix) if aug_labels is not None: aug_labels = np.asarray(aug_labels) return aug_matrix, aug_labels def mixup( table: TableLike, n: int, labels: NDArray | None = None, intra_class: bool = False, alpha: float = 2.0, append: bool = False, seed: SeedLike | None = None, ) -> tuple[NDArray, NDArray | None]: r"""Data augmentation by vanilla mixup. Parameters ---------- table : table_like of shape (n_samples, n_features) Input data table to be augmented. See :ref:`supported formats `. n : int Number of synthetic samples to generate. labels : array_like of shape (n_samples,) or (n_samples, n_classes), optional Class labels for the data. Accepts either indices (1-D) or one-hot encoded labels (2-D). intra_class : bool, optional If True, synthetic samples will be created by mixing samples within each class. If False (default), any samples regardless of class can be mixed. alpha : float, optional Shape parameter of the beta distribution. append : bool, optional If True, the returned data include both the original and synthetic samples. If False (default), only the synthetic samples are returned. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. See Also -------- phylomix aitchison_mixup compos_cutmix Returns ------- aug_matrix : ndarray of shape (n, n_features) Augmented data matrix. aug_labels : ndarray of shape (n, n_classes), optional Augmented class labels in one-hot encoded format. Available if ``labels`` are provided. One can call ``aug_labels.argmax(axis=1)`` to get class indices. Notes ----- The mixup method is based on [1]_. It randomly selects two samples :math:`s_1` and :math:`s_2` from the data table, and generates a new sample :math:`s` by a linear combination of them, as follows: .. math:: s = \lambda \cdot s_1 + (1 - \lambda) \cdot s_2 where :math:`\lambda` is a mixing coefficient drawn from a beta distribution: .. math:: \lambda \sim \mathrm{Beta}(\alpha, \alpha) The label :math:`y` is computed as the linear combination of the labels of the two samples (:math:`y_1` and :math:`y_2`): .. math:: y = \lambda \cdot y_1 + (1 - \lambda) \cdot y_2 This function shares the same core concept as PyTorch's `MixUp `_ class. There are some key differences: 1. This implementation returns synthetic samples and class labels from a dataset, while PyTorch's MixUp is applied on-the-fly during training to batches of data. 2. This implementation randomly selects pairs of samples from the entire dataset, while PyTorch's implementation typically mixes consecutive samples in a batch (requiring prior shuffling). 3. This implementation is tailored for biological omic data, while PyTorch's is primarily for image data. Examples -------- >>> import numpy as np >>> from skbio.table import mixup >>> matrix = np.arange(40).reshape(4, 10) >>> labels = np.array([0, 1, 0, 1]) >>> aug_matrix, aug_labels = mixup(matrix, n=5, labels=labels) >>> print(aug_matrix.shape) (5, 10) >>> print(aug_labels.shape) (5, 2) References ---------- .. [1] Zhang, H., Cisse, M., Dauphin, Y. N., & Lopez-Paz, D. (2017). mixup: Beyond Empirical Risk Minimization. arXiv preprint arXiv:1710.09412. """ rng = get_rng(seed) matrix, labels, pairs, _ = _format_input(table, labels, intra_class) # Draw pairs of samples to mix. pairs_sel = pairs[rng.integers(0, len(pairs), size=n)] # Draw mixing coefficients (lambda) from a beta distribution. lams = rng.beta(alpha, alpha, size=(n, 1)) # Collect paired sample data. x1 = matrix[pairs_sel[:, 0]] x2 = matrix[pairs_sel[:, 1]] # Mix paired sample data. aug_matrix = lams * x1 + (1.0 - lams) * x2 # Generate synthetic class labels. aug_labels = _make_aug_labels(labels, pairs_sel, lams, intra_class) return _format_output(aug_matrix, aug_labels, matrix, labels, append) def _aitchison_add(x: NDArray, y: NDArray) -> NDArray: r"""Perform Aitchison addition on two samples or sample groups. Parameters ---------- x : ndarray of shape (..., n_features) The first sample(s). y : ndarray of shape (..., n_features) The second sample(s). Returns ------- ndarray of shape (..., n_features) The result of Aitchison addition. """ return (prod := x * y) / prod.sum(axis=-1, keepdims=True) def _aitchison_multiply(x: NDArray, p: float) -> NDArray: r"""Perform Aitchison multiplication on a sample (group) with a scalar. Parameters ---------- x : ndarray of shape (..., n_features) The sample to multiply. p : float or ndarray of shape (...,) The scalar to multiply the sample by. Returns ------- ndarray of shape (..., n_features) The result of Aitchison multiplication. """ return (exp := x**p) / exp.sum(axis=-1, keepdims=True) def aitchison_mixup( table: TableLike, n: int, labels: NDArray | None = None, intra_class: bool = False, alpha: float = 2.0, normalize: bool = True, append: bool = False, seed: SeedLike | None = None, ) -> tuple[NDArray, NDArray | None]: r"""Data augmentation by Aitchison mixup. This function requires the data to be compositional (values per sample sum to one). If not, the function will automatically normalize them prior to augmentation. Parameters ---------- table : table_like of shape (n_samples, n_features) Input data table to be augmented. See :ref:`supported formats `. n : int Number of synthetic samples to generate. labels : array_like of shape (n_samples,) or (n_samples, n_classes), optional Class labels for the data. Accepts either indices (1-D) or one-hot encoded labels (2-D). intra_class : bool, optional If ``True``, synthetic samples will be created by mixing samples within each class. If ``False`` (Default), any samples regardless of class can be mixed. alpha : float, optional Shape parameter of the beta distribution. normalize : bool, optional If True (default), and the input is not already compositional, scikit-bio's :func:`~skbio.stats.composition.closure` function will be called, ensuring values for each sample add up to 1. append : bool, optional If True, the returned data include both the original and synthetic samples. If False (default), only the synthetic samples are returned. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. Returns ------- aug_matrix : ndarray of shape (n, n_features) Augmented data matrix. aug_labels : ndarray of shape (n, n_classes), optional Augmented class labels in one-hot encoded format. Available if ``labels`` are provided. One can call ``aug_labels.argmax(axis=1)`` to get class indices. See Also -------- mixup compos_cutmix Notes ----- The algorithm is based on [1]_, and leverages the Aitchison geometry to guide the augmentation of compositional data. It is essentially the vanilla mixup method in the Aitchison space. This method only works on compositional data, where a set of data points live in the simplex: :math:`x_i > 0`, and :math:`\sum_{i=1}^{p} x_i = 1`. An augmented sample :math:`s` is computed as the linear combination of two samples :math:`s_1` and :math:`s_2` in the Aitchison space: .. math:: s = (\lambda \otimes s_1) \oplus ((1 - \lambda) \otimes s_2) where :math:`\otimes` is the Aitchison scalar multiplication, defined as: .. math:: \lambda \otimes s = \frac{1}{\sum_{i=1}^{n} s_i^{\lambda}} (s_1^{\lambda}, s_2^{\lambda}, ..., s_n^{\lambda}) :math:`\oplus` is the Aitchison addition, defined as: .. math:: s \oplus t = \frac{1}{\sum_{i=1}^{n} s_i t_i} (s_1 t_1, s_2 t_2, ..., s_n t_n) :math:`\lambda` is a mixing coefficient drawn from a beta distribution: .. math:: \lambda \sim \mathrm{Beta}(\alpha, \alpha) The label :math:`y` is computed as the linear combination of the labels of the two samples (:math:`y_1` and :math:`y_2`): .. math:: y = \lambda \cdot y_1 + (1 - \lambda) \cdot y_2 By mixing the counts of two samples, Aitchison mixup preserves the compositional nature of the data, and the sum-to-one property. Examples -------- >>> import numpy as np >>> from skbio.table import aitchison_mixup >>> matrix = np.arange(40).reshape(4, 10) >>> labels = np.array([0, 1, 0, 1]) >>> aug_matrix, aug_labels = aitchison_mixup(matrix, n=5, labels=labels) >>> print(aug_matrix.shape) (5, 10) >>> print(aug_labels.shape) (5, 2) References ---------- .. [1] Gordon-Rodriguez, E., Quinn, T., & Cunningham, J. P. (2022). Data augmentation for compositional data: Advancing predictive models of the microbiome. Advances in Neural Information Processing Systems, 35, 20551-20565. """ rng = get_rng(seed) matrix, labels, pairs, _ = _format_input(table, labels, intra_class, normalize) pairs_sel = pairs[rng.integers(0, len(pairs), size=n)] # Draw mixing coefficients (lambda) from a beta distribution. lams = rng.beta(alpha, alpha, size=(n, 1)) # Collect paired sample data to mix. x1 = matrix[pairs_sel[:, 0]] x2 = matrix[pairs_sel[:, 1]] # Perform Aitchison scalar multiplication on each side of mixture. s1 = _aitchison_multiply(x1, lams) s2 = _aitchison_multiply(x2, 1.0 - lams) # Perform Aitchison addition to mix the two sides. aug_matrix = _aitchison_add(s1, s2) aug_labels = _make_aug_labels(labels, pairs_sel, lams, intra_class) return _format_output(aug_matrix, aug_labels, matrix, labels, append) def compos_cutmix( table: TableLike, n: int, labels: NDArray | None = None, normalize: bool = True, append: bool = False, seed: SeedLike | None = None, ) -> tuple[NDArray, NDArray | None]: r"""Data augmentation by compositional cutmix. This function requires the data to be compositional (values per sample sum to one). If not, the function will automatically normalize them prior to augmentation. Parameters ---------- table : table_like of shape (n_samples, n_features) Input data table to be augmented. See :ref:`supported formats `. n : int Number of synthetic samples to generate. labels : array_like of shape (n_samples,) or (n_samples, n_classes), optional Class labels for the data. Accepts either indices (1-D) or one-hot encoded labels (2-D). normalize : bool, optional If True (default), and the input is not already compositional, scikit-bio's :func:`~skbio.stats.composition.closure` function will be called, ensuring values for each sample add up to 1. append : bool, optional If True, the returned data include both the original and synthetic samples. If False (default), only the synthetic samples are returned. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. .. note:: This function does not have the ``intra_class`` parameter, as it always operates in intra-class mode in order to preserve the compositional structure within classes. See Also -------- mixup aitchison_mixup Returns ------- aug_matrix : ndarray of shape (n, n_features) Augmented data matrix. aug_labels : ndarray of shape (n, n_classes), optional Augmented class labels in one-hot encoded format. Available if ``labels`` are provided. One can call ``aug_labels.argmax(axis=1)`` to get class indices. Notes ----- The compositional cutmix method was described in [1]_. This method randomly selects values from one of a pair of samples to generate a new sample. It has four steps: 1. Draw a mixing coefficient :math:`\lambda` from a uniform distribution: .. math:: \lambda \sim U(0, 1) 2. Draw a binary selector :math:`I` for each feature from a Bernoulli distribution: .. math:: I \sim \mathrm{Bernoulli}(\lambda) 3. For the :math:`i`-th feature, set the augmented value :math:`x_i` as from sample 1 if :math:`I_i = 0` or from sample 2 if :math:`I_i = 1`. 4. Normalize the augment sample such that it is compositional (sum-to-one). .. math:: s = \frac{1}{\sum_{i=1}^{n} x_i} (x_1, x_2, ..., x_n) This method is applied separately to samples of each class. If ``labels`` is None, all samples will be considered as the same class, and ``aug_labels`` will be returned as None. Examples -------- >>> import numpy as np >>> from skbio.table import compos_cutmix >>> matrix = np.arange(40).reshape(4, 10) >>> labels = np.array([0, 1, 0, 1]) >>> aug_matrix, aug_labels = compos_cutmix(matrix, n=5, labels=labels) >>> print(aug_matrix.shape) (5, 10) >>> print(aug_labels.shape) (5, 2) References ---------- .. [1] Gordon-Rodriguez, E., Quinn, T., & Cunningham, J. P. (2022). Data augmentation for compositional data: Advancing predictive models of the microbiome. Advances in Neural Information Processing Systems, 35, 20551-20565. """ rng = get_rng(seed) matrix, labels, pairs, _ = _format_input(table, labels, True, normalize) pairs_sel = pairs[rng.integers(0, len(pairs), size=n)] # Draw binary gates to control the choice between samples 1 and 2 per feature. probs = rng.uniform(0, 1, size=(n, 1)) gates = rng.binomial(1, probs, size=(n, matrix.shape[1])).astype(bool) # Mix sample pairs based on binary gates. samples_sel = matrix[pairs_sel] aug_matrix = np.where(gates, samples_sel[:, 0], samples_sel[:, 1]) # Normalize synthetic samples (although original samples are compositional, # synthetic one at this point are not, so they need to be normalized) aug_matrix = closure(aug_matrix) aug_labels = labels[pairs_sel[:, 0]] if labels is not None else None return _format_output(aug_matrix, aug_labels, matrix, labels, append) def _indices_under_nodes( tree: TreeNode, taxa: Sequence | NDArray ) -> list[dict[int, None]]: """Pre-compute feature indices descending from each node. Parameters ---------- tree : TreeNode Reference tree. taxa : sequence of str Taxa (tip names) corresponding to feature indices. Returns ------- list of dict of {int: None} Feature indices descending from each node. Raises ------ ValueError If there are duplicate taxa. ValueError If some taxa are not present as tip names in the tree. See Also -------- skbio.tree._utils._validate_taxa_and_tree Notes ----- Only internal nodes with at least one descending feature are included. This function does not ensure all tip names in the tree are unique. The output is a list of dicts instead of just list of lists. The reason is explained in the inline comments of `phylomix`. """ n_taxa = len(taxa) taxon_map = {taxon: i for i, taxon in enumerate(taxa)} if len(taxon_map) < n_taxa: raise ValueError("All taxa must be unique.") seen: set[str] = set() seen_add = seen.add res: list[dict[int, None]] = [] res_append = res.append dict_fromkeys = dict.fromkeys for node in tree.postorder(include_self=True): if node.children: lst = [] for child in node.children: lst.extend(child._taxa) del child._taxa node._taxa = lst if lst: res_append(dict_fromkeys(lst)) else: if (taxon := node.name) in taxon_map: node._taxa = [taxon_map[taxon]] seen_add(taxon) else: node._taxa = [] del tree._taxa if missing := n_taxa - len(seen): raise ValueError(f"{missing} taxa are not present as tip names in the tree.") return res def phylomix( table: TableLike, n: int, tree: TreeNode, taxa: ArrayLike | None = None, labels: NDArray | None = None, intra_class: bool = False, alpha: float = 2.0, append: bool = False, seed: SeedLike | None = None, ) -> tuple[NDArray, NDArray | None]: r"""Data augmentation by PhyloMix. Parameters ---------- table : table_like of shape (n_samples, n_features) Input data table to be augmented. See :ref:`supported formats `. n : int Number of synthetic samples to generate. tree : :class:`~skbio.tree.TreeNode` Tree structure modeling the relationships between features. taxa : array_like of shape (n_features,), optional Taxa (tip names) in ``tree`` corresponding to individual features. Can be omitted if ``table`` already contains feature IDs that are taxa. Otherwise they need to be explicitly provided. Should be a subset of taxa in the tree. labels : array_like of shape (n_samples,) or (n_samples, n_classes), optional Class labels for the data. Accepts either indices (1-D) or one-hot encoded labels (2-D). intra_class : bool, optional If ``True``, synthetic samples will be created by mixing samples within each class. If ``False`` (Default), any samples regardless of class can be mixed. alpha : float, optional Shape parameter of the beta distribution. append : bool, optional If True, the returned data include both the original and synthetic samples. If False (default), only the synthetic samples are returned. seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. See :func:`details `. Returns ------- aug_matrix : ndarray of shape (n, n_features) Augmented data matrix. aug_labels : ndarray of shape (n, n_classes), optional Augmented class labels in one-hot encoded format. Available if ``labels`` are provided. One can call ``aug_labels.argmax(axis=1)`` to get class indices. Raises ------ ValueError If taxa are unavailable. See Also -------- mixup Notes ----- The Phylomix method was described in [1]_. This method leverages phylogenetic relationships to guide data augmentation in microbiome and other omic data. By mixing the abundances of evolutionarily related taxa (tips of a selected node), Phylomix preserves the biological structure while introducing new synthetic samples. The selection of nodes follows a random sampling approach, where a subset of taxa is chosen based on a Beta-distributed mixing coefficient. This ensures that the augmented data maintains biologically meaningful compositional relationships. In the original paper, the authors assumed a bifurcated phylogenetic tree, but this implementation works with any tree structure. If desired, the user can bifurcate the tree using :meth:`~skbio.tree.TreeNode.bifurcate` before augmentation. Phylomix is particularly valuable for microbiome-trait association studies, where preserving phylogenetic similarity between related taxa is crucial for accurate downstream predictions. This approach helps address the common challenge of limited sample sizes in omic data studies. Examples -------- >>> import numpy as np >>> from skbio.table import phylomix >>> from skbio.tree import TreeNode >>> matrix = np.arange(20).reshape(4, 5) >>> labels = np.array([0, 1, 0, 1]) >>> tree = TreeNode.read(['(((a,b),c),(d,e));']) >>> taxa = ['a', 'b', 'c', 'd', 'e'] >>> aug_matrix, aug_labels = phylomix( ... matrix, n=5, tree=tree, taxa=taxa, labels=labels) >>> print(aug_matrix.shape) (5, 5) >>> print(aug_labels.shape) (5, 2) References ---------- .. [1] Jiang, Y., Liao, D., Zhu, Q., & Lu, Y. Y. (2025). PhyloMix: Enhancing microbiome-trait association prediction through phylogeny-mixing augmentation. Bioinformatics, btaf014. """ rng = get_rng(seed) matrix, labels, pairs, taxa = _format_input(table, labels, intra_class, taxa=taxa) if taxa is None: raise ValueError("Taxa must be included in table or explicitly provided.") n_taxa = len(taxa) pairs_sel = pairs[rng.integers(0, len(pairs), size=n)] # Pre-calculate feature indices descending from each node. node_indices = _indices_under_nodes(tree, taxa) n_nodes = len(node_indices) # Draw mixing coefficients (lambda) from a beta distribution. lams = rng.beta(alpha, alpha, size=n) # Randomly shuffle about half of the pairs. This is because each pair of samples # are not treated symmetrically in the algorithm. Meanwhile, pairs were generated # with the smaller index on the left. If shuffling isn't performed, the algorithm # will bias toward one side of the list of samples. gates = rng.random(n) < 0.5 pairs_sel[gates] = pairs_sel[gates][:, ::-1] aug_matrix = [] for (idx1, idx2), lam in zip(pairs_sel, lams): x1, x2 = matrix[idx1], matrix[idx2] # Number of features to select (ratio: 1 - lambda). n_selected = int(np.ceil((1.0 - lam) * n_taxa)) # Shuffle nodes. it = iter(rng.permutation(n_nodes)) # Randomly sample nodes and add their descending feature indices to selection, # until it reaches a given size. # Note 1: Nodes may overlap each other, thus descending feature indices may be # redundant. # Note 2: Dictionary is used instead of set because the order of elements in a # dictionary is stable (unlike set, which is unstable). # See `_indices_under_nodes` for how it was done. # Note 3: One cannot predict how many nodes need to be sampled in order to get # n_selected features. Otherwise one can do the following: # # nodes_sel = rng.choice(n_nodes, size=num_nodes_to_sample) # selected = np.unique(np.fromiter(itertools.chain.from_iterable( # node_indices[i].keys() for i in nodes_self), dtype=np.intp)) # # Note 4: It it guaranteed that n_selected <= n_taxa <= n_taxa_in_tree, # therefore the `while` loop won't last infinitely. selected: dict[str, None] = {} while len(selected) < n_selected: selected.update(node_indices[next(it)]) # Drop out extra indices. # Permutation is used instead of sorting because we just want stable selection # of indices whereas order doesn't matter. `matrix[selected]` should always be # the same regardless of order. selected = np.fromiter(selected.keys(), dtype=np.intp) selected = rng.permutation(selected)[:n_selected] # Take selected features from sample 2, scale them to match sample 1, then # replace those in sample 1. # Note that samples 1 and 2 are not treated equally. The synthetic sample will # will have the same scale as sample 1. x1_sel, x2_sel = x1[selected], x2[selected] total1, total2 = x1_sel.sum(), x2_sel.sum() if total1 > 0 and total2 > 0: # removed astype(int) so phylomix could handle compositional input # (total1 / total2) is guaranteed to be float, therefore # leaf_counts2 * (total1 / total2) is also guaranteed to be float x_mix = x1.copy() x_mix[selected] = x2_sel * (total1 / total2) aug_matrix.append(x_mix) # If either is zero, just use sample 1. else: aug_matrix.append(x1) aug_matrix = np.vstack(aug_matrix) aug_labels = _make_aug_labels(labels, pairs_sel, lams.reshape(-1, 1), intra_class) return _format_output(aug_matrix, aug_labels, matrix, labels, append) scikit-bio-scikit-bio-a3beaa6/skbio/table/_base.py000066400000000000000000000022541520735541300221770ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """BIOM table specifications and utilities.""" import numpy as np from biom import Table, example_table from skbio.io.descriptors import Read, Write Table.default_write_format = "biom" """Default write format for this object: ``biom``.""" # Define read and write methods for the Table class. Table.read = Read() Table.write = Write() def _table_to_numpy(table): """Convert a Table to a dense representation. This is a stop-gap solution to allow current Table objects to interoperate with existing driver methods, until they transition to be "sparse" aware. """ sample_ids = list(table.ids()) obs_ids = list(table.ids(axis="observation")) if table.is_empty(): counts = np.array([[]] * len(sample_ids)) else: counts = table.matrix_data.T.toarray() return counts, sample_ids, obs_ids scikit-bio-scikit-bio-a3beaa6/skbio/table/_tabular.py000066400000000000000000000165761520735541300227330ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from warnings import warn from collections.abc import Sequence import numpy as np import pandas as pd from ._base import _table_to_numpy from skbio._config import get_config from skbio.util import get_package def _create_table(data, columns=None, index=None, backend=None): """Create a table object using the specified backend. Parameters ---------- data : table_like Input data. columns : array_like Column labels to use if data does not have them. index : array_like Index labels to use if data does not have them. backend : str The desired data structure to be used within scikit-bio functions. Returns ------- pd.DataFrame or np.array Representation of the data in the appropriate format depending on the underlying configuration option. """ if backend is None: backend = get_config("table_output") if backend == "pandas": return pd.DataFrame(data, index=index, columns=columns) elif backend == "numpy": return np.array(data) elif backend == "polars": pl = get_package(backend) # Polars doesn't support Pandas Index or Series as schema. Convertion needed. if columns is not None and not isinstance(columns, Sequence): columns = list(columns) return pl.DataFrame(data, schema=columns) else: raise ValueError(f"Unsupported backend: '{backend}'") def _create_table_1d(data, index=None, backend=None): """Create a 1d array using the specified backend. Parameters ---------- data : table_like Input data. columns : array_like Column labels to use if data does not have them. index : array_like Index labels to use if data does not have them. backend : str The desired data structure to be used within scikit-bio functions. Returns ------- pd.Series or 1-D ndarray Representation of the data in the appropriate format depending on the underlying configuration option. """ if backend is None: backend = get_config("table_output") if backend in ("pandas"): # , "biom"): return pd.Series(data, index=index) elif backend == "numpy": return np.array(data) elif backend == "polars": pl = get_package(backend) return pl.Series(values=data) else: raise ValueError(f"Unsupported backend: '{backend}'") def _extract_row_ids(input_data, warn_ids=False): """Extract row ids from a dataframe or table.""" if isinstance(input_data, pd.DataFrame): return list(input_data.index) # for right now, just going to worry about pandas/polars/numpy, # which is to say that if it's not pandas, then it doesn't have ids else: # Raise warning if sample_ids and feature_ids are both None, as this means # that both will have arbitrary integer IDs starting at 0. if warn_ids: warn( ( "sample_ids and feature_ids were both None. As a " "result, both have been set to integer IDs " "starting at 0. Namespaces for sample_ids and " "feature_ids are no longer mutually exclusive." ) ) return list(range(input_data.shape[0])) def _ingest_table(table, sample_ids=None, feature_ids=None, expand=True): """Process an input data table into individual components. Parameters ---------- table : table_like The input data table. May be any of the supported formats. sample_ids : sequence of str, optional IDs corresponding to samples (rows). If ``None``, extraction from input data will be attempted. In the case that IDs may not be extracted, they will be assigned integer values starting at 0. feature_ids : sequence of str, optional IDs corresponding to features (columns). If ``None``, extraction from input data will be attempted. In the case that IDs may not be extracted, they will be assigned integer values starting at 0. expand : bool, optional If table has only one dimension and this parameter is True, expand the data to two dimensions (i.e., a single-row matrix). Otherwise, raise an error. Returns ------- data : ndarray of shape (n_samples, n_features) The raw numeric values from the input data. sample_ids : list of str The extracted or provided sample IDs. feature_ids : list of str The extracted or provided feature IDs. Raises ------ TypeError If input table format is not supported. ValueError If number of provided sample/feature IDs doesn't match table dimensions. """ data, samples, features = None, None, None # Python (nested) list, tuple, etc. if isinstance(table, Sequence) and not isinstance(table, (str, bytes)): data = np.asarray(table) # NumPy array # to be replaced with `aac.is_array_api_obj(table)` elif isinstance(table, np.ndarray): data = table # pandas DataFrame elif isinstance(table, pd.DataFrame): data = table.to_numpy() samples = table.index features = table.columns # BIOM (skbio) Table # Check the BIOM-specific attribute "generated_by" before lazy-loading BIOM. elif hasattr(table, "generated_by"): from skbio.table import Table if isinstance(table, Table): data, samples, features = _table_to_numpy(table) # Polars DataFrame # Can't do an explicit check until polars is imported, so check for schema first. elif hasattr(table, "schema"): pl = get_package("polars") if isinstance(table, pl.DataFrame): data = table.to_numpy() features = table.schema # AnnData object elif hasattr(table, "X"): adt = get_package("anndata") if isinstance(table, adt.AnnData): data = np.asarray(table.X) samples = table.obs.index features = table.var.index # array-like object # this will generate a NumPy array, regardless of input type if data is None: data = np.asarray(table) # zero-dimensional arrays are considered as invalid (such as scalars, non- # convertible objects) if data.ndim == 0: raise TypeError( f"'{table.__class__.__name__}' is not a supported table format." ) # convert a 1-D vector into a 2-D array if data.ndim == 1 and expand: data = data.reshape(1, -1) if data.ndim < 2: raise ValueError("Input table has less than 2 dimensions.") lenerr = "Input table has {0} {1}s whereas {2} {1} IDs were provided." if sample_ids is None: sample_ids = samples elif len(sample_ids) != data.shape[0]: raise ValueError(lenerr.format(data.shape[0], "sample", len(sample_ids))) if feature_ids is None: feature_ids = features elif len(feature_ids) != data.shape[1]: raise ValueError(lenerr.format(data.shape[1], "feature", len(feature_ids))) return data, sample_ids, feature_ids scikit-bio-scikit-bio-a3beaa6/skbio/table/tests/000077500000000000000000000000001520735541300217135ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/table/tests/__init__.py000066400000000000000000000005411520735541300240240ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/table/tests/test_augment.py000066400000000000000000001105201520735541300247630ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt import pandas as pd from skbio.tree import TreeNode from skbio.stats.composition import closure from skbio.table._augment import ( mixup, aitchison_mixup, compos_cutmix, phylomix, _validate_labels, _normalize_matrix, _all_pairs, _intra_class_pairs, _aitchison_add, _aitchison_multiply, _indices_under_nodes, ) class AugmentationTests(TestCase): def setUp(self): # a normal example (10 x 10) self.matrix = np.array([ [ 2, 0, 3, 0, 9, 31, 3, 1, 3, 7], [ 9, 0, 8, 4, 1, 24, 0, 0, 3, 6], [ 0, 0, 1, 0, 0, 1, 2, 1, 0, 1], [ 0, 5, 0, 1, 7, 0, 5, 2, 4, 0], [ 0, 0, 5, 22, 1, 10, 4, 16, 19, 0], [ 0, 0, 2, 0, 1, 2, 3, 2, 0, 1], [ 0, 0, 0, 2, 0, 3, 0, 3, 1, 0], [ 5, 2, 0, 14, 0, 3, 3, 5, 9, 51], [15, 3, 0, 8, 17, 0, 0, 5, 0, 0], [ 0, 3, 5, 0, 2, 2, 2, 0, 4, 1], ]) self.labels_1 = np.zeros(10, dtype=int) # one class self.labels_2 = np.array([0, 0, 0, 1, 0, 1, 1, 1, 0, 0]) # two classes self.labels_3 = np.array([1, 1, 0, 2, 0, 0, 0, 2, 1, 2]) # three classes self.taxa = [f"O{i}" for i in range(10)] self.tree = TreeNode.read([ "((O6,((O1,O4),O7),((O5,O2),(O3,O8))),(O0,O9));" ]) def test_validate_labels(self): # Create a simple matrix for testing matrix = np.array([[1, 2, 3], [4, 5, 6]]) n = matrix.shape[0] # Test with valid 1D labels labels = np.array([0, 1]) obs_idx, obs_1hot = _validate_labels(labels, n) npt.assert_array_equal(obs_idx, labels) npt.assert_array_equal(obs_1hot, np.array([[1, 0], [0, 1]])) # Test with a plain list obs_idx, obs_1hot = _validate_labels(labels.tolist(), n) npt.assert_array_equal(obs_idx, labels) npt.assert_array_equal(obs_1hot, np.array([[1, 0], [0, 1]])) # Test with integer-equivalent floats obs_idx, obs_1hot = _validate_labels(labels.astype(float), n) npt.assert_array_equal(obs_idx, labels) npt.assert_array_equal(obs_1hot, np.array([[1, 0], [0, 1]])) self.assertTrue(np.issubdtype(obs_idx.dtype, np.integer)) # Test with valid 2D one-hot encoded labels (discrete) one_hot = np.array([[1, 0], [0, 1]]) obs_idx, obs_1hot = _validate_labels(one_hot, n) npt.assert_array_equal(obs_idx, np.array([0, 1])) npt.assert_array_equal(obs_1hot, one_hot) # Test with non-integer but still valid one-hot labels one_hot = np.array([[0.6, 0.4], [0.2, 0.8]]) obs_idx, obs_1hot = _validate_labels(one_hot, n) npt.assert_array_equal(obs_idx, np.array([0, 1])) npt.assert_array_equal(obs_1hot, one_hot) def test_validate_labels_errors(self): matrix = np.array([[1, 2, 3], [4, 5, 6]]) n = matrix.shape[0] # Test with wrong dimensions msg = "Labels should be 1-D or 2-D, but got 3 dimensions instead." wrong_dim_labels = np.array([[[0], [1]]]) with self.assertRaises(ValueError) as cm: _validate_labels(wrong_dim_labels, n) self.assertEqual(str(cm.exception), msg) # Test with wrong number of samples msg = "Number of labels (3) does not match number of samples in the data (2)." wrong_len_labels = np.array([0, 1, 2]) with self.assertRaises(ValueError) as cm: _validate_labels(wrong_len_labels, n) self.assertEqual(str(cm.exception), msg) # Test with non-whole numbers msg = "Labels must only contain integer values." non_int_labels = np.array([1.5, 2.0]) with self.assertRaises(ValueError) as cm: _validate_labels(non_int_labels, n) self.assertEqual(str(cm.exception), msg) # Test with non-zero indexed label msg = "Labels must be zero-indexed. Minimum value must be 0." non_zero_labels = np.array([1, 2]) with self.assertRaises(ValueError) as cm: _validate_labels(non_zero_labels, n) self.assertEqual(str(cm.exception), msg) # Test with non-consecutive label msg = "Labels must be consecutive integers from 0 to n_classes - 1." non_consecutive = np.array([0, 2]) with self.assertRaises(ValueError) as cm: _validate_labels(non_consecutive, n) self.assertEqual(str(cm.exception), msg) # Test with invalid one-hot encoding msg = "Labels are not properly one-hot encoded." invalid_one_hot = np.array([[1, 1], [0, 1]]) with self.assertRaises(ValueError) as cm: _validate_labels(invalid_one_hot, n) self.assertEqual(str(cm.exception), msg) def test_normalize_matrix(self): matrix = np.array([[0.2, 0.5, 0.3], [0.3, 0.6, 0.1]]) obs = _normalize_matrix(matrix) self.assertIs(obs, matrix) matrix = np.array([[2, 5, 3], [3, 6, 1]], dtype=float) obs = _normalize_matrix(matrix) exp = np.array([[0.2, 0.5, 0.3], [0.3, 0.6, 0.1]]) npt.assert_allclose(obs, exp) def test_aitchison_add(self): """Test Aitchison addition.""" # vector addition x1 = np.array([0.2, 0.3, 0.5]) x2 = np.array([0.1, 0.4, 0.5]) obs = _aitchison_add(x1, x2) exp = np.array([0.05128, 0.30769, 0.64103]) npt.assert_array_equal(obs.round(5), exp) self.assertAlmostEqual(obs.sum(), 1.0) # matrix addition x1 = np.array([[0.2, 0.3, 0.5], [0.1, 0.4, 0.5]]) x2 = np.array([[0.3, 0.3, 0.4], [0.5, 0.2, 0.3]]) obs = _aitchison_add(x1, x2) exp = np. array([[0.17143, 0.25714, 0.57143], [0.17857, 0.28571, 0.53571]]) npt.assert_array_equal(obs.round(5), exp) self.assertTrue(np.allclose(obs.sum(axis=1), 1)) def test_aitchison_multiply(self): """Test Aitchison scalar multiplication.""" p = 2.0 # vector multiplication x = np.array([0.2, 0.3, 0.5]) obs = _aitchison_multiply(x, p) exp = np.array([0.10526, 0.23684, 0.65789]) npt.assert_array_equal(obs.round(5), exp) self.assertAlmostEqual(obs.sum(), 1.0) # matrix multiplication x = np.array([[0.2, 0.3, 0.5], [0.1, 0.4, 0.5]]) obs = _aitchison_multiply(x, p) exp = np.array([[0.10526, 0.23684, 0.65789], [0.02381, 0.38095, 0.59524]]) npt.assert_array_equal(obs.round(5), exp) self.assertTrue(np.allclose(obs.sum(axis=1), 1)) def test_all_pairs(self): obs = _all_pairs(2) exp = np.array([[0, 1]]) npt.assert_array_equal(obs, exp) obs = _all_pairs(3) exp = np.array([[0, 1], [0, 2], [1, 2]]) npt.assert_array_equal(obs, exp) obs = _all_pairs(5) exp = np.array([[0, 0, 0, 0, 1, 1, 1, 2, 2, 3], [1, 2, 3, 4, 2, 3, 4, 3, 4, 4]]).T npt.assert_array_equal(obs, exp) # edge case: one sample -> no pair obs = _all_pairs(1) exp = np.empty((0, 2), dtype=int) npt.assert_array_equal(obs, exp) def test_intra_class_pairs(self): # one class only obs = _intra_class_pairs([0, 0, 0]) exp = np.array([[0, 1], [0, 2], [1, 2]]) npt.assert_array_equal(obs, exp) # two classes, one pair each obs = _intra_class_pairs([0, 0, 1, 1]) exp = np.array([[0, 1], [2, 3]]) npt.assert_array_equal(obs, exp) # two classes, interleaved obs = _intra_class_pairs([0, 1, 0, 1]) exp = np.array([[0, 2], [1, 3]]) npt.assert_array_equal(obs, exp) # two classes, three pairs each obs = _intra_class_pairs([0, 0, 1, 1, 1, 0]) exp = np.array([[0, 0, 1, 2, 2, 3], [1, 5, 5, 3, 4, 4]]).T npt.assert_array_equal(obs, exp) # three classes, mixed pair numbers obs = _intra_class_pairs([0, 0, 1, 1, 2, 0, 2, 1, 1, 1]) exp = np.array([[0, 0, 1, 2, 2, 2, 2, 3, 3, 3, 7, 7, 8, 4], [1, 5, 5, 3, 7, 8, 9, 7, 8, 9, 8, 9, 9, 6]]).T npt.assert_array_equal(obs, exp) # edge case: no pair obs = _intra_class_pairs([0, 1, 2]) exp = np.empty((0, 2), dtype=int) npt.assert_array_equal(obs, exp) # edge case: no sample obs = _intra_class_pairs([]) exp = np.empty((0, 2), dtype=int) npt.assert_array_equal(obs, exp) def test_indices_under_nodes(self): # a tree with 10 taxa tree = self.tree taxa = self.taxa obs = _indices_under_nodes(tree, taxa) # naive method (not optimized) taxon_map = {taxon: i for i, taxon in enumerate(taxa)} nodes = tree.non_tips(include_self=True) exp = [[taxon_map[tip.name] for tip in node.tips()] for node in nodes] self.assertEqual(len(obs), len(exp)) for o, e in zip(obs, exp): self.assertListEqual(list(o.keys()), e) # taxon map doesn't cover entire tree (a common scenario) taxa = ["O3", "O7", "O1", "O4", "O9"] obs = _indices_under_nodes(tree, taxa) # manually constructed exp = [[2, 3], [2, 3, 1], [0], [0], [2, 3, 1, 0], [4], [2, 3, 1, 0, 4]] self.assertEqual(len(obs), len(exp)) for o, e in zip(obs, exp): self.assertListEqual(list(o.keys()), e) # check if temporary attributes have been cleaned up for node in tree.traverse(include_self=True): self.assertFalse(hasattr(node, "_taxa")) # taxa contain duplicates msg = "All taxa must be unique." taxa = ["O1", "O2", "O1"] with self.assertRaises(ValueError) as cm: _indices_under_nodes(tree, taxa) self.assertEqual(str(cm.exception), msg) # taxa not found in the tree msg = "2 taxa are not present as tip names in the tree." taxa = ["O1", "X2", "O3", "X4", "O5"] with self.assertRaises(ValueError) as cm: _indices_under_nodes(tree, taxa) self.assertEqual(str(cm.exception), msg) def test_mixup(self): matrix, labels_2, labels_3 = self.matrix, self.labels_2, self.labels_3 # no labels obs_mat, obs_lab = mixup(matrix, n=10, seed=42) exp_mat = np.array([ [ 0.55, 0. , 2.27, 0. , 3.19, 9.95, 3. , 1.73, 0.82, 2.64], [ 0. , 2.36, 5. , 4.73, 1.79, 3.72, 2.43, 3.44, 7.22, 0.79], [ 0. , 4.64, 0.9 , 0.82, 6.1 , 0.36, 4.46, 1.64, 4. , 0.18], [ 0. , 0. , 1.69, 0. , 0.69, 1.69, 2.69, 1.69, 0. , 1. ], [ 0. , 0. , 1.61, 0. , 0.61, 1.61, 2.61, 1.61, 0. , 1. ], [ 0. , 1.91, 3.91, 0. , 1.64, 2. , 2.36, 0.73, 2.54, 1. ], [ 1.31, 0. , 3.69, 7.55, 6.25, 23.79, 3.34, 6.15, 8.49, 4.6 ], [ 0. , 0. , 0.93, 5.72, 0.19, 4.3 , 0.74, 5.42, 4.35, 0. ], [ 2.08, 0. , 2.62, 0.93, 0.23, 6.33, 1.54, 0.77, 0.69, 2.16], [ 1.11, 0. , 2.55, 0. , 5.44, 18.08, 3. , 1.45, 1.66, 4.33], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) self.assertIsNone(obs_lab) # append mode obs_mat, obs_lab = mixup(matrix, n=10, seed=42, append=True) self.assertTupleEqual(obs_mat.shape, (20, 10)) npt.assert_array_equal(obs_mat[:10], matrix) npt.assert_array_equal(obs_mat.round(2)[10:], exp_mat) self.assertIsNone(obs_lab) # two-class labels obs_mat, obs_lab = mixup(matrix, n=10, labels=labels_2, seed=42) npt.assert_array_equal(obs_mat.round(2), exp_mat) exp_lab = np.array([ [0.27, 0.73], [1. , 0. ], [0.18, 0.82], [0.31, 0.69], [0.39, 0.61], [0.64, 0.36], [1. , 0. ], [0.19, 0.81], [1. , 0. ], [0.55, 0.45], ]) npt.assert_array_equal(obs_lab.round(2), exp_lab) # append mode obs_mat, obs_lab = mixup(matrix, n=10, labels=labels_2, seed=42, append=True) self.assertTupleEqual(obs_mat.shape, (20, 10)) npt.assert_array_equal(obs_mat[:10], matrix) npt.assert_array_equal(obs_mat.round(2)[10:], exp_mat) self.assertTupleEqual(obs_lab.shape, (20, 2)) npt.assert_array_equal(obs_lab[:10], np.eye(2, dtype=int)[labels_2]) npt.assert_array_equal(obs_lab.round(2)[10:], exp_lab) # alpha parameter obs_mat, obs_lab = mixup(matrix, n=10, alpha=1, seed=42) exp_mat = np.array([ [ 1.72, 0. , 2.86, 0. , 7.88, 26.94, 3. , 1.14, 2.58, 6.16], [ 0. , 1.35, 5. , 12.07, 1.45, 6.39, 3.1 , 8.78, 12.23, 0.45], [ 0. , 3.58, 3.55, 0.29, 3.45, 1.42, 2.87, 0.58, 4. , 0.71], [ 0. , 0. , 1.93, 0. , 0.93, 1.93, 2.93, 1.93, 0. , 1. ], [ 0. , 0. , 1.71, 0. , 0.71, 1.71, 2.71, 1.71, 0. , 1. ], [ 0. , 2.34, 4.34, 0. , 1.78, 2. , 2.22, 0.44, 3.12, 1. ], [ 0.88, 0. , 4.12, 12.3 , 4.53, 19.26, 3.56, 9.38, 11.94, 3.09], [ 0. , 0. , 2.97, 13.86, 0.59, 7.15, 2.37, 10.71, 11.68, 0. ], [ 6.09, 0. , 5.74, 2.71, 0.68, 16.57, 0.65, 0.32, 2.03, 4.39], [ 0.59, 0. , 2.3 , 0. , 3.38, 10.61, 3. , 1.7 , 0.89, 2.78], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) # two-class labels, intra-class mixing obs_mat, obs_lab = mixup( matrix, n=10, labels=labels_2, intra_class=True, seed=42 ) exp_mat = np.array([ [ 0.55, 0. , 1.55, 0. , 2.47, 9.22, 2.27, 1. , 0.82, 2.64], [ 0. , 1.07, 0. , 1.79, 1.5 , 2.36, 1.07, 2.79, 1.64, 0. ], [ 0. , 0.54, 5. , 18.05, 1.18, 8.56, 3.64, 13.13, 16.31, 0.18], [ 0. , 0. , 3.77, 15.25, 0.69, 7.24, 3.39, 11.4 , 13.17, 0.31], [ 0. , 0. , 3.45, 13.48, 0.61, 6.51, 3.23, 10.19, 11.64, 0.39], [ 0. , 0. , 0.73, 1.27, 0.36, 2.64, 1.09, 2.64, 0.64, 0.36], [ 1.31, 0. , 2.31, 0. , 5.91, 20.7 , 2.66, 1. , 1.97, 4.94], [ 2.79, 3. , 4.07, 1.49, 4.79, 1.63, 1.63, 0.93, 3.26, 0.81], [ 0.46, 2.31, 4.54, 0. , 3.62, 8.72, 2.23, 0.23, 3.77, 2.39], [ 1.11, 0. , 2.11, 0. , 4.99, 17.64, 2.55, 1. , 1.66, 4.33], ]) exp_lab = np.array([ [1, 0], [0, 1], [1, 0], [1, 0], [1, 0], [0, 1], [1, 0], [1, 0], [1, 0], [1, 0], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) npt.assert_array_equal(obs_lab, exp_lab) # three-class labels obs_mat, obs_lab = mixup(matrix, n=10, labels=labels_3, seed=42) exp_mat = np.array([ [ 0.55, 0. , 2.27, 0. , 3.19, 9.95, 3. , 1.73, 0.82, 2.64], [ 0. , 2.36, 5. , 4.73, 1.79, 3.72, 2.43, 3.44, 7.22, 0.79], [ 0. , 4.64, 0.9 , 0.82, 6.1 , 0.36, 4.46, 1.64, 4. , 0.18], [ 0. , 0. , 1.69, 0. , 0.69, 1.69, 2.69, 1.69, 0. , 1. ], [ 0. , 0. , 1.61, 0. , 0.61, 1.61, 2.61, 1.61, 0. , 1. ], [ 0. , 1.91, 3.91, 0. , 1.64, 2. , 2.36, 0.73, 2.54, 1. ], [ 1.31, 0. , 3.69, 7.55, 6.25, 23.79, 3.34, 6.15, 8.49, 4.6 ], [ 0. , 0. , 0.93, 5.72, 0.19, 4.3 , 0.74, 5.42, 4.35, 0. ], [ 2.08, 0. , 2.62, 0.93, 0.23, 6.33, 1.54, 0.77, 0.69, 2.16], [ 1.11, 0. , 2.55, 0. , 5.44, 18.08, 3. , 1.45, 1.66, 4.33], ]) exp_lab = np.array([ [0.73, 0.27, 0. ], [0.21, 0. , 0.79], [0. , 0. , 1. ], [1. , 0. , 0. ], [1. , 0. , 0. ], [0.36, 0. , 0.64], [0.34, 0.66, 0. ], [1. , 0. , 0. ], [0.77, 0.23, 0. ], [0.45, 0.55, 0. ], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) npt.assert_array_equal(obs_lab.round(2), exp_lab) def test_mixup_errors(self): msg = "Cannot find a pair of samples to mix." # Each class has only one sample. In intra-class mode there is no pair to mix. labels = np.arange(10) with self.assertRaises(ValueError) as cm: mixup(self.matrix, n=10, labels=labels, intra_class=True, seed=42) self.assertEqual(str(cm.exception), msg) # Entire dataset has only one sample => no pair to mix. with self.assertRaises(ValueError) as cm: mixup(self.matrix[:1], n=10, seed=42) self.assertEqual(str(cm.exception), msg) def test_aitchison_mixup(self): matrix, labels_2, labels_3 = self.matrix, self.labels_2, self.labels_3 # no labels obs_mat, obs_lab = aitchison_mixup(matrix, n=10, seed=42) exp_mat = np.array([ [0. , 0. , 0.15, 0. , 0.12, 0.29, 0.2 , 0.11, 0. , 0.12], [0. , 0. , 0.29, 0. , 0.1 , 0.16, 0.13, 0. , 0.32, 0. ], [0. , 0.25, 0. , 0. , 0.3 , 0. , 0.23, 0. , 0.22, 0. ], [0. , 0. , 0.19, 0. , 0. , 0.19, 0.31, 0.19, 0. , 0.12], [0. , 0. , 0.19, 0. , 0. , 0.19, 0.31, 0.19, 0. , 0.12], [0. , 0. , 0.34, 0. , 0.15, 0.19, 0.22, 0. , 0. , 0.1 ], [0. , 0. , 0.09, 0. , 0.1 , 0.52, 0.08, 0.06, 0.14, 0. ], [0. , 0. , 0. , 0.25, 0. , 0.3 , 0. , 0.32, 0.14, 0. ], [0. , 0. , 0.31, 0. , 0. , 0.4 , 0. , 0. , 0. , 0.29], [0. , 0. , 0.11, 0. , 0.15, 0.41, 0.13, 0.06, 0. , 0.13], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) self.assertIsNone(obs_lab) # check if the synthetic samples are also compositional self.assertTrue(np.allclose(obs_mat.sum(axis=1), 1)) # append mode obs_mat, obs_lab = aitchison_mixup(matrix, n=10, seed=42, append=True) self.assertTupleEqual(obs_mat.shape, (20, 10)) npt.assert_array_equal(obs_mat.round(2)[10:], exp_mat) # check if the original samples have been normalized npt.assert_array_equal(obs_mat[:10].round(2), closure(matrix).round(2)) # feed pre-normalized data normed = closure(matrix) obs_mat, obs_lab = aitchison_mixup(normed, n=10, seed=42, normalize=False) npt.assert_array_equal(obs_mat.round(2), exp_mat) # skip normalization obs_mat, obs_lab = aitchison_mixup(matrix, n=10, seed=42, normalize=False) exp_mat = np.array([ [0. , 0. , 0.15, 0. , 0.12, 0.29, 0.2 , 0.11, 0. , 0.12], [0. , 0. , 0.29, 0. , 0.1 , 0.16, 0.13, 0. , 0.32, 0. ], [0. , 0.25, 0. , 0. , 0.3 , 0. , 0.23, 0. , 0.22, 0. ], [0. , 0. , 0.19, 0. , 0. , 0.19, 0.31, 0.19, 0. , 0.12], [0. , 0. , 0.19, 0. , 0. , 0.19, 0.31, 0.19, 0. , 0.12], [0. , 0. , 0.34, 0. , 0.15, 0.19, 0.22, 0. , 0. , 0.1 ], [0. , 0. , 0.09, 0. , 0.1 , 0.52, 0.08, 0.06, 0.14, 0. ], [0. , 0. , 0. , 0.25, 0. , 0.3 , 0. , 0.32, 0.14, 0. ], [0. , 0. , 0.31, 0. , 0. , 0.4 , 0. , 0. , 0. , 0.29], [0. , 0. , 0.11, 0. , 0.15, 0.41, 0.13, 0.06, 0. , 0.13], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) # two-class labels obs_mat, obs_lab = aitchison_mixup(matrix, n=10, labels=labels_2, seed=42) npt.assert_array_equal(obs_mat.round(2), exp_mat) # Note that the synthetic labels are identical to those of `mixup`. This is # because they are determined by sampling from beta distribution, which is # independent from the subsequent calculation. exp_lab = np.array([ [0.27, 0.73], [1. , 0. ], [0.18, 0.82], [0.31, 0.69], [0.39, 0.61], [0.64, 0.36], [1. , 0. ], [0.19, 0.81], [1. , 0. ], [0.55, 0.45], ]) npt.assert_array_equal(obs_lab.round(2), exp_lab) # alpha parameter obs_mat, obs_lab = aitchison_mixup(matrix, n=10, alpha=1, seed=42) exp_mat = np.array([ [0. , 0. , 0.07, 0. , 0.17, 0.53, 0.08, 0.03, 0. , 0.13], [0. , 0. , 0.21, 0. , 0.06, 0.21, 0.12, 0. , 0.4 , 0. ], [0. , 0.27, 0. , 0. , 0.22, 0. , 0.2 , 0. , 0.31, 0. ], [0. , 0. , 0.2 , 0. , 0. , 0.2 , 0.3 , 0.2 , 0. , 0.1 ], [0. , 0. , 0.19, 0. , 0. , 0.19, 0.31, 0.19, 0. , 0.12], [0. , 0. , 0.37, 0. , 0.16, 0.18, 0.2 , 0. , 0. , 0.09], [0. , 0. , 0.1 , 0. , 0.07, 0.41, 0.09, 0.12, 0.21, 0. ], [0. , 0. , 0. , 0.29, 0. , 0.22, 0. , 0.29, 0.2 , 0. ], [0. , 0. , 0.25, 0. , 0. , 0.54, 0. , 0. , 0. , 0.21], [0. , 0. , 0.15, 0. , 0.13, 0.3 , 0.2 , 0.11, 0. , 0.12], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) self.assertTrue(np.allclose(obs_mat.sum(axis=1), 1)) # two-class labels, intra-class mixing obs_mat, obs_lab = aitchison_mixup( matrix, n=10, labels=labels_2, intra_class=True, seed=42 ) exp_mat = np.array([ [0. , 0. , 0.15, 0. , 0. , 0.29, 0.25, 0.11, 0. , 0.19], [0. , 0. , 0. , 0.3 , 0. , 0. , 0. , 0.47, 0.23, 0. ], [0. , 0. , 0.16, 0. , 0.04, 0.24, 0.11, 0. , 0.46, 0. ], [0. , 0. , 0.17, 0. , 0. , 0.27, 0.18, 0.38, 0. , 0. ], [0. , 0. , 0.18, 0. , 0. , 0.27, 0.2 , 0.36, 0. , 0. ], [0. , 0. , 0. , 0. , 0. , 0.5 , 0. , 0.5 , 0. , 0. ], [0. , 0. , 0.11, 0. , 0. , 0.51, 0.14, 0.05, 0. , 0.19], [0. , 0.5 , 0. , 0. , 0.5 , 0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0.24, 0. , 0.15, 0.2 , 0.12, 0. , 0.2 , 0.08], [0. , 0. , 0.12, 0. , 0. , 0.45, 0.17, 0.07, 0. , 0.2 ], ]) exp_lab = np.array([ [1, 0], [0, 1], [1, 0], [1, 0], [1, 0], [0, 1], [1, 0], [1, 0], [1, 0], [1, 0], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) npt.assert_array_equal(obs_lab, exp_lab) self.assertTrue(np.allclose(obs_mat.sum(axis=1), 1)) # three-class labels obs_mat, obs_lab = aitchison_mixup(matrix, n=10, labels=labels_3, seed=42) exp_mat = np.array([ [0. , 0. , 0.15, 0. , 0.12, 0.29, 0.2 , 0.11, 0. , 0.12], [0. , 0. , 0.29, 0. , 0.1 , 0.16, 0.13, 0. , 0.32, 0. ], [0. , 0.25, 0. , 0. , 0.3 , 0. , 0.23, 0. , 0.22, 0. ], [0. , 0. , 0.19, 0. , 0. , 0.19, 0.31, 0.19, 0. , 0.12], [0. , 0. , 0.19, 0. , 0. , 0.19, 0.31, 0.19, 0. , 0.12], [0. , 0. , 0.34, 0. , 0.15, 0.19, 0.22, 0. , 0. , 0.1 ], [0. , 0. , 0.09, 0. , 0.1 , 0.52, 0.08, 0.06, 0.14, 0. ], [0. , 0. , 0. , 0.25, 0. , 0.3 , 0. , 0.32, 0.14, 0. ], [0. , 0. , 0.31, 0. , 0. , 0.4 , 0. , 0. , 0. , 0.29], [0. , 0. , 0.11, 0. , 0.15, 0.41, 0.13, 0.06, 0. , 0.13], ]) exp_lab = np.array([ [0.73, 0.27, 0. ], [0.21, 0. , 0.79], [0. , 0. , 1. ], [1. , 0. , 0. ], [1. , 0. , 0. ], [0.36, 0. , 0.64], [0.34, 0.66, 0. ], [1. , 0. , 0. ], [0.77, 0.23, 0. ], [0.45, 0.55, 0. ], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) npt.assert_array_equal(obs_lab.round(2), exp_lab) self.assertTrue(np.allclose(obs_mat.sum(axis=1), 1)) def test_compos_cutmix(self): matrix, labels_2, labels_3 = self.matrix, self.labels_2, self.labels_3 # no labels obs_mat, obs_lab = compos_cutmix(matrix, n=10, seed=42) exp_mat = np.array([ [0.03, 0. , 0.05, 0. , 0.15, 0.53, 0.05, 0.02, 0.05, 0.12], [0. , 0. , 0.06, 0.27, 0.01, 0.12, 0.1 , 0.2 , 0.23, 0. ], [0. , 0.22, 0. , 0.04, 0.31, 0. , 0.11, 0.09, 0.18, 0.06], [0. , 0. , 0.18, 0. , 0.09, 0.18, 0.27, 0.18, 0. , 0.09], [0. , 0. , 0.16, 0. , 0.09, 0.16, 0.26, 0.16, 0. , 0.16], [0. , 0.13, 0.22, 0. , 0.09, 0.09, 0.09, 0.15, 0.18, 0.04], [0.03, 0. , 0.05, 0. , 0.15, 0.53, 0.05, 0.02, 0.05, 0.12], [0. , 0. , 0.07, 0.3 , 0.01, 0.14, 0. , 0.22, 0.26, 0. ], [0.25, 0. , 0.22, 0.11, 0. , 0.25, 0. , 0. , 0. , 0.17], [0.03, 0. , 0.16, 0. , 0.13, 0.16, 0.24, 0.16, 0.04, 0.08], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) self.assertIsNone(obs_lab) # check if the synthetic samples are also compositional self.assertTrue(np.allclose(obs_mat.sum(axis=1), 1)) # append mode obs_mat, obs_lab = compos_cutmix(matrix, n=10, seed=42, append=True) self.assertTupleEqual(obs_mat.shape, (20, 10)) npt.assert_array_equal(obs_mat.round(2)[10:], exp_mat) # check if the original samples have been normalized npt.assert_array_equal(obs_mat[:10].round(2), closure(matrix).round(2)) # feed pre-normalized data normed = closure(matrix) obs_mat, obs_lab = compos_cutmix(normed, n=10, seed=42, normalize=False) npt.assert_array_equal(obs_mat.round(2), exp_mat) # skip normalization obs_mat, obs_lab = compos_cutmix(matrix, n=10, seed=42, normalize=False) exp_mat = np.array([ [0.03, 0. , 0.05, 0. , 0.15, 0.53, 0.05, 0.02, 0.05, 0.12], [0. , 0. , 0.07, 0.29, 0.01, 0.13, 0.03, 0.21, 0.25, 0. ], [0. , 0.23, 0. , 0.05, 0.32, 0. , 0.09, 0.09, 0.18, 0.05], [0. , 0. , 0.18, 0. , 0.09, 0.18, 0.27, 0.18, 0. , 0.09], [0. , 0. , 0.12, 0. , 0.12, 0.12, 0.38, 0.12, 0. , 0.12], [0. , 0.14, 0.24, 0. , 0.1 , 0.1 , 0.1 , 0.1 , 0.19, 0.05], [0.03, 0. , 0.05, 0. , 0.15, 0.53, 0.05, 0.02, 0.05, 0.12], [0. , 0. , 0.07, 0.3 , 0.01, 0.14, 0. , 0.22, 0.26, 0. ], [0.32, 0. , 0.29, 0.14, 0. , 0.04, 0. , 0. , 0. , 0.21], [0.08, 0. , 0.08, 0. , 0.38, 0.08, 0.12, 0.08, 0.12, 0.04], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) # although original samples are not compositional, synthetic samples are still # compositional. self.assertTrue(np.allclose(obs_mat.sum(axis=1), 1)) # two-class labels # Note that compos_cutmix is always intra-class. obs_mat, obs_lab = compos_cutmix(matrix, n=10, labels=labels_2, seed=42) exp_mat = np.array([ [0.03, 0. , 0.05, 0. , 0.15, 0.53, 0.05, 0.02, 0.05, 0.12], [0. , 0.26, 0. , 0.05, 0.37, 0. , 0. , 0.11, 0.21, 0. ], [0. , 0. , 0.06, 0.26, 0.01, 0.12, 0.1 , 0.19, 0.22, 0.05], [0. , 0. , 0.06, 0.29, 0.01, 0.13, 0.05, 0.21, 0.25, 0. ], [0. , 0. , 0.16, 0.28, 0.01, 0.16, 0.05, 0.16, 0. , 0.16], [0. , 0. , 0. , 0.26, 0. , 0.39, 0. , 0.21, 0.13, 0. ], [0.03, 0. , 0.05, 0. , 0.15, 0.53, 0.05, 0.02, 0.05, 0.12], [0.26, 0.13, 0. , 0.14, 0.29, 0. , 0.09, 0.09, 0. , 0. ], [0.05, 0. , 0.07, 0. , 0.15, 0.15, 0.07, 0.02, 0.3 , 0.17], [0.03, 0. , 0.13, 0. , 0.12, 0.13, 0.27, 0.13, 0.04, 0.13], ]) exp_lab = np.array([ [1, 0], [0, 1], [1, 0], [1, 0], [1, 0], [0, 1], [1, 0], [1, 0], [1, 0], [1, 0], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) npt.assert_array_equal(obs_lab, exp_lab) self.assertTrue(np.allclose(obs_mat.sum(axis=1), 1)) # three-class labels obs_mat, obs_lab = compos_cutmix(matrix, n=10, labels=labels_3, seed=42) exp_mat = np.array([ [0. , 0. , 0.17, 0. , 0. , 0.17, 0.33, 0.17, 0. , 0.17], [0. , 0.25, 0. , 0.05, 0.35, 0. , 0.04, 0.1 , 0.2 , 0. ], [0.04, 0. , 0.06, 0. , 0.18, 0.63, 0. , 0.02, 0.06, 0. ], [0. , 0. , 0. , 0.22, 0. , 0.33, 0. , 0.33, 0.11, 0. ], [0. , 0. , 0.21, 0.26, 0. , 0.21, 0. , 0.21, 0. , 0.11], [0. , 0.15, 0.24, 0. , 0.1 , 0.1 , 0.1 , 0.08, 0.19, 0.05], [0. , 0. , 0.17, 0. , 0. , 0.17, 0.33, 0.17, 0. , 0.17], [0.15, 0.06, 0.14, 0.07, 0.02, 0.41, 0. , 0. , 0.05, 0.1 ], [0. , 0. , 0.13, 0. , 0. , 0.26, 0.26, 0.13, 0.09, 0.13], [0. , 0. , 0.2 , 0. , 0. , 0.2 , 0.3 , 0.2 , 0. , 0.1 ], ]) exp_lab = np.array([ [1, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 0, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0], [1, 0, 0], [1, 0, 0], ]) npt.assert_array_equal(obs_mat.round(2), exp_mat) npt.assert_array_equal(obs_lab, exp_lab) self.assertTrue(np.allclose(obs_mat.sum(axis=1), 1)) def test_phylomix(self): matrix, tree, taxa, = self.matrix, self.tree, self.taxa labels_2, labels_3 = self.labels_2, self.labels_3 # no labels obs_mat, obs_lab = phylomix(matrix, n=10, tree=tree, taxa=taxa, seed=42) exp_mat = np.array([ [ 0, 0, 0, 0, 1, 4, 3, 0, 0, 1], [ 0, 12, 21, 0, 8, 8, 8, 0, 17, 0], [ 0, 3, 5, 0, 2, 2, 2, 0, 4, 1], [ 0, 0, 2, 0, 0, 2, 3, 2, 0, 1], [ 0, 0, 2, 0, 0, 2, 3, 2, 0, 2], [ 0, 1, 2, 0, 1, 1, 1, 2, 2, 0], [ 2, 0, 3, 0, 9, 7, 3, 12, 14, 7], [ 0, 0, 0, 17, 0, 25, 0, 25, 8, 0], [ 0, 0, 13, 0, 0, 13, 0, 13, 0, 13], [ 0, 0, 0, 0, 1, 3, 3, 2, 0, 0], ]) npt.assert_array_equal(obs_mat, exp_mat) self.assertIsNone(obs_lab) # append mode obs_mat, obs_lab = phylomix( matrix, n=10, tree=tree, taxa=taxa, seed=42, append=True ) self.assertTupleEqual(obs_mat.shape, (20, 10)) npt.assert_array_equal(obs_mat[:10], matrix) npt.assert_array_equal(obs_mat[10:], exp_mat) # two-class labels obs_mat, obs_lab = phylomix( matrix, n=10, tree=tree, taxa=taxa, labels=labels_2, seed=42 ) npt.assert_array_equal(obs_mat, exp_mat) # Note that the synthetic labels won't be the same as those of `mixup`. This is # because `phylomix` shuffles pairs of sample indices to ensure randomness. exp_lab = np.array([ [0.73, 0.27], [1. , 0. ], [0.82, 0.18], [0.69, 0.31], [0.61, 0.39], [0.64, 0.36], [1. , 0. ], [0.19, 0.81], [1. , 0. ], [0.45, 0.55], ]) npt.assert_array_equal(obs_lab.round(2), exp_lab) # alpha parameter obs_mat, obs_lab = phylomix( matrix, n=10, tree=tree, taxa=taxa, alpha=1, seed=42 ) exp_mat = np.array([ [ 0, 0, 2, 0, 1, 2, 3, 2, 0, 1], [ 0, 0, 1, 5, 2, 2, 2, 0, 4, 1], [ 0, 4, 0, 0, 5, 0, 2, 1, 3, 1], [ 0, 0, 1, 0, 0, 1, 1, 1, 0, 0], [ 0, 0, 1, 0, 0, 1, 1, 1, 0, 0], [ 0, 2, 2, 0, 1, 1, 1, 0, 2, 0], [ 2, 0, 4, 17, 0, 8, 3, 1, 15, 7], [ 0, 0, 0, 1, 0, 3, 0, 3, 1, 0], [ 9, 0, 16, 0, 0, 24, 0, 0, 0, 6], [ 0, 0, 2, 0, 1, 5, 0, 0, 0, 1], ]) npt.assert_array_equal(obs_mat, exp_mat) # two-class labels, intra-class mixing obs_mat, obs_lab = phylomix( matrix, n=10, tree=tree, taxa=taxa, labels=labels_2, intra_class=True, seed=42 ) exp_mat = np.array([ [ 0, 0, 0, 0, 0, 2, 2, 0, 0, 0], [ 0, 0, 0, 5, 0, 8, 0, 8, 2, 0], [ 0, 3, 5, 0, 2, 2, 2, 0, 4, 1], [ 0, 0, 24, 0, 0, 24, 4, 24, 0, 0], [ 0, 0, 5, 0, 0, 22, 4, 22, 0, 22], [ 0, 0, 2, 2, 0, 3, 0, 2, 1, 0], [ 2, 0, 3, 0, 9, 17, 3, 17, 0, 7], [ 0, 8, 13, 0, 5, 5, 5, 0, 10, 0], [ 0, 0, 20, 0, 8, 8, 3, 0, 16, 4], [ 0, 0, 0, 0, 0, 2, 2, 1, 0, 0], ]) exp_lab = np.array([ [1, 0], [0, 1], [1, 0], [1, 0], [1, 0], [0, 1], [1, 0], [1, 0], [1, 0], [1, 0], ]) npt.assert_array_equal(obs_mat, exp_mat) npt.assert_array_equal(obs_lab, exp_lab) # three-class labels obs_mat, obs_lab = phylomix( matrix, n=10, tree=tree, taxa=taxa, labels=labels_3, seed=42 ) exp_mat = np.array([ [ 0, 0, 0, 0, 1, 4, 3, 0, 0, 1], [ 0, 12, 21, 0, 8, 8, 8, 0, 17, 0], [ 0, 3, 5, 0, 2, 2, 2, 0, 4, 1], [ 0, 0, 2, 0, 0, 2, 3, 2, 0, 1], [ 0, 0, 2, 0, 0, 2, 3, 2, 0, 2], [ 0, 1, 2, 0, 1, 1, 1, 2, 2, 0], [ 2, 0, 3, 0, 9, 7, 3, 12, 14, 7], [ 0, 0, 0, 17, 0, 25, 0, 25, 8, 0], [ 0, 0, 13, 0, 0, 13, 0, 13, 0, 13], [ 0, 0, 0, 0, 1, 3, 3, 2, 0, 0], ]) exp_lab = np.array([ [0.27, 0.73, 0. ], [0.21, 0. , 0.79], [0. , 0. , 1. ], [1. , 0. , 0. ], [1. , 0. , 0. ], [0.36, 0. , 0.64], [0.34, 0.66, 0. ], [1. , 0. , 0. ], [0.77, 0.23, 0. ], [0.55, 0.45, 0. ], ]) npt.assert_array_equal(obs_mat, exp_mat) npt.assert_array_equal(obs_lab.round(2), exp_lab) def test_phylomix_errors(self): # a simple example (2 x 5) matrix = np.arange(10).reshape(2, 5) labels = np.array([0, 1]) taxa = list("abcde") tree = TreeNode.read(["(((a,b),c),(d,e));"]) # normal situation obs_mat, obs_lab = phylomix( matrix, n=5, tree=tree, taxa=taxa, labels=labels, seed=42 ) exp_mat = np.array([ [ 0, 2, 2, 2, 3], [ 0, 1, 1, 3, 4], [ 0, 1, 2, 3, 3], [ 0, 6, 8, 12, 9], [ 5, 6, 6, 9, 9], ]) exp_lab = np.array([ [0.42, 0.58], [0.53, 0.47], [0.64, 0.36], [0.48, 0.52], [0.32, 0.68], ]) npt.assert_array_equal(obs_mat, exp_mat) npt.assert_array_equal(obs_lab.round(2), exp_lab) # taxa not provided msg = "Taxa must be included in table or explicitly provided." with self.assertRaises(ValueError) as cm: phylomix(matrix, n=5, tree=tree, taxa=None) self.assertEqual(str(cm.exception), msg) # taxa included in table df = pd.DataFrame(matrix, columns=taxa) obs_mat, obs_lab = phylomix(df, n=5, tree=tree, seed=42) npt.assert_array_equal(obs_mat, exp_mat) # explicitly provided taxa override feature IDs in table df = pd.DataFrame(matrix, columns=list("uvwxy")) obs_mat, obs_lab = phylomix(df, n=5, tree=tree, taxa=taxa, seed=42) npt.assert_array_equal(obs_mat, exp_mat) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/table/tests/test_base.py000066400000000000000000000047471520735541300242520ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt from skbio.table import Table, example_table from skbio.table._base import _table_to_numpy class TableTests(TestCase): def test_table(self): data = np.arange(40).reshape(10, 4) sample_ids = ['S%d' % i for i in range(4)] observ_ids = ['O%d' % i for i in range(10)] sample_metadata = [{'environment': 'A'}, {'environment': 'B'}, {'environment': 'A'}, {'environment': 'B'}] observ_metadata = [{'taxonomy': ['Bacteria', 'Firmicutes']}, {'taxonomy': ['Bacteria', 'Firmicutes']}, {'taxonomy': ['Bacteria', 'Proteobacteria']}, {'taxonomy': ['Bacteria', 'Proteobacteria']}, {'taxonomy': ['Bacteria', 'Proteobacteria']}, {'taxonomy': ['Bacteria', 'Bacteroidetes']}, {'taxonomy': ['Bacteria', 'Bacteroidetes']}, {'taxonomy': ['Bacteria', 'Firmicutes']}, {'taxonomy': ['Bacteria', 'Firmicutes']}, {'taxonomy': ['Bacteria', 'Firmicutes']}] table = Table(data, observ_ids, sample_ids, observ_metadata, sample_metadata, table_id='Example Table') self.assertEqual(list(table.ids()), ['S0', 'S1', 'S2', 'S3']) self.assertEqual(list(table.ids(axis='observation')), ['O0', 'O1', 'O2', 'O3', 'O4', 'O5', 'O6', 'O7', 'O8', 'O9']) self.assertEqual(int(table.nnz), 39) class TableUtilTests(TestCase): def test_table_to_numpy(self): exp_data = np.array([[0, 1, 2], [3, 4, 5]]).T exp_ids = ['S1', 'S2', 'S3'] exp_feat_ids = ['O1', 'O2'] obs_data, obs_ids, obs_feat_ids = _table_to_numpy(example_table) npt.assert_equal(obs_data, exp_data) self.assertEqual(obs_ids, exp_ids) self.assertEqual(obs_feat_ids, exp_feat_ids) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/table/tests/test_tabular.py000066400000000000000000000412371520735541300247650ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main, skipIf import numpy as np import numpy.testing as npt import pandas as pd import pandas.testing as pdt from skbio._config import set_config from skbio.table import Table from skbio.util import get_package from skbio.util._testing import assert_data_frame_almost_equal from skbio.table._tabular import _create_table, _create_table_1d, _ingest_table # import optional dependencies pl = get_package("polars", raise_error=False) # polars.testing isn't imported along with polars. Therefore one needs to import it # separately. if pl is not None: plt = get_package("polars.testing") adt = get_package("anndata", raise_error=False) torch = get_package("torch", raise_error=False) jnp = get_package("jax.numpy", raise_error=False) class TestIngest(TestCase): def setUp(self): self.data = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) self.data_1d = self.data[0] self.samples = ["A", "B", "C"] self.features = ["f1", "f2", "f3"] def test_ingest_numpy(self): table = self.data obs = _ingest_table(table) self.assertIs(obs[0], table) self.assertIsNone(obs[1]) self.assertIsNone(obs[2]) obs = _ingest_table(table, self.samples, self.features) self.assertIs(obs[0], table) self.assertIs(obs[1], self.samples) self.assertIs(obs[2], self.features) def test_ingest_pandas(self): table = pd.DataFrame(self.data, index=self.samples, columns=self.features) obs = _ingest_table(table) self.assertIsInstance(obs[0], np.ndarray) npt.assert_array_equal(obs[0], self.data) self.assertListEqual(obs[1].tolist(), self.samples) self.assertListEqual(obs[2].tolist(), self.features) # no samples / features table = pd.DataFrame(self.data) obs = _ingest_table(table) npt.assert_array_equal(obs[0], self.data) self.assertListEqual(obs[1].tolist(), list(range(obs[0].shape[0]))) self.assertListEqual(obs[2].tolist(), list(range(obs[0].shape[1]))) # override samples / features obs = _ingest_table(table, self.samples, self.features) npt.assert_array_equal(obs[0], self.data) self.assertListEqual(obs[1], self.samples) self.assertListEqual(obs[2], self.features) @skipIf(pl is None, "Polars is not available for unit tests.") def test_ingest_polars(self): table = pl.DataFrame(self.data, schema=self.features) obs = _ingest_table(table, sample_ids=self.samples) self.assertIsInstance(obs[0], np.ndarray) npt.assert_array_equal(obs[0], self.data) self.assertListEqual(obs[1], self.samples) self.assertListEqual(obs[2].names(), self.features) # no samples, override features table = pl.DataFrame(self.data) obs = _ingest_table(table, feature_ids=self.features) npt.assert_array_equal(obs[0], self.data) self.assertIsNone(obs[1]) self.assertListEqual(obs[2], self.features) def test_ingest_biom(self): table = Table( self.data.T, observation_ids=self.features, sample_ids=self.samples ) obs = _ingest_table(table) self.assertIsInstance(obs[0], np.ndarray) npt.assert_array_equal(obs[0], self.data) self.assertListEqual(obs[1], self.samples) self.assertListEqual(obs[2], self.features) @skipIf(adt is None, "Anndata is not available for unit tests.") def test_ingest_anndata(self): table = adt.AnnData( self.data, obs=pd.DataFrame(index=self.samples), var=pd.DataFrame(index=self.features), ) obs = _ingest_table(table) self.assertIsInstance(obs[0], np.ndarray) npt.assert_array_equal(obs[0], self.data) self.assertListEqual(list(obs[1]), self.samples) self.assertListEqual(list(obs[2]), self.features) def test_ingest_sequence(self): table = self.data.tolist() obs = _ingest_table(table) npt.assert_array_equal(obs[0], self.data) self.assertIsNone(obs[1]) self.assertIsNone(obs[2]) obs = _ingest_table(tuple(table)) npt.assert_array_equal(obs[0], self.data) obs = _ingest_table(tuple(tuple(x) for x in table)) npt.assert_array_equal(obs[0], self.data) @skipIf(torch is None, "PyTorch is not available for unit tests.") def test_ingest_torch(self): table = torch.tensor(self.data) obs = _ingest_table(table) npt.assert_array_equal(obs[0], self.data) self.assertIsNone(obs[1]) self.assertIsNone(obs[2]) @skipIf(jnp is None, "JAX is not available for unit tests.") def test_ingest_jax(self): table = jnp.asarray(self.data) obs = _ingest_table(table) npt.assert_array_equal(obs[0], self.data) self.assertIsNone(obs[1]) self.assertIsNone(obs[2]) def test_ingest_error(self): msg = "'int' is not a supported table format." with self.assertRaises(TypeError) as cm: _ingest_table(123) self.assertEqual(str(cm.exception), msg) msg = "'str' is not a supported table format." with self.assertRaises(TypeError) as cm: _ingest_table("hello") self.assertEqual(str(cm.exception), msg) msg = "'type' is not a supported table format." with self.assertRaises(TypeError) as cm: _ingest_table(TypeError) self.assertEqual(str(cm.exception), msg) msg = "Input table has less than 2 dimensions." with self.assertRaises(ValueError) as cm: _ingest_table(np.array([1, 2, 3]), expand=False) self.assertEqual(str(cm.exception), msg) with self.assertRaises(ValueError) as cm: _ingest_table([1, 2, 3], expand=False) self.assertEqual(str(cm.exception), msg) msg = "Input table has 3 samples whereas 2 sample IDs were provided." with self.assertRaises(ValueError) as cm: _ingest_table(self.data, sample_ids=["A", "B"]) self.assertEqual(str(cm.exception), msg) msg = "Input table has 3 features whereas 2 feature IDs were provided." with self.assertRaises(ValueError) as cm: _ingest_table(self.data, feature_ids=["f2", "f3"]) self.assertEqual(str(cm.exception), msg) class TestPandas(TestCase): def setUp(self): set_config("table_output", "pandas") self.data = [[0, 1, 2], [3, 4, 5], [6, 7, 8]] self.data_1d = self.data[0] self.index = ["A", "B", "C"] self.columns = ["f1", "f2", "f3"] def test_create_table_no_backend(self): obs = _create_table(data=self.data, columns=self.columns, index=self.index) exp = pd.DataFrame(self.data, columns=self.columns, index=self.index) assert_data_frame_almost_equal(obs, exp) def test_create_table_no_optionals(self): obs = _create_table(self.data) exp = pd.DataFrame(self.data) assert_data_frame_almost_equal(obs, exp) def test_create_table_same_backend(self): obs = _create_table( data=self.data, columns=self.columns, index=self.index, backend="pandas" ) exp = pd.DataFrame(self.data, columns=self.columns, index=self.index) assert_data_frame_almost_equal(obs, exp) def test_create_table_numpy_backend(self): obs = _create_table( data=self.data, columns=self.columns, index=self.index, backend="numpy" ) exp = np.array(self.data) npt.assert_array_equal(obs, exp) def test_create_table_bad_backend(self): with self.assertRaisesRegex(ValueError, "Unsupported backend: 'nonsense'"): _create_table(self.data, backend="nonsense") def test_create_table_1d_no_backend(self): obs = _create_table_1d(self.data_1d, index=self.index) exp = pd.Series(self.data_1d, index=self.index) pdt.assert_series_equal(obs, exp) def test_create_table_1d_no_optionals(self): obs = _create_table_1d(self.data_1d) exp = pd.Series(self.data_1d) pdt.assert_series_equal(obs, exp) def test_create_table_1d_same_backend(self): obs = _create_table_1d(self.data_1d, index=self.index, backend="pandas") exp = pd.Series(self.data_1d, index=self.index) pdt.assert_series_equal(obs, exp) def test_create_table_1d_numpy_backend(self): obs = _create_table_1d(self.data_1d, index=self.index, backend="numpy") exp = np.array(self.data_1d) npt.assert_array_equal(obs, exp) def test_create_table_1d_bad_backend(self): with self.assertRaisesRegex(ValueError, "Unsupported backend: 'nonsense'"): _create_table_1d(self.data, backend="nonsense") class TestNumpy(TestCase): def setUp(self): set_config("table_output", "numpy") self.data = [[0, 1, 2], [3, 4, 5], [6, 7, 8]] self.data_1d = self.data[0] self.index = ["A", "B", "C"] self.columns = ["f1", "f2", "f3"] def tearDown(self): set_config("table_output", "pandas") def test_create_table_no_backend(self): obs = _create_table(data=self.data, columns=self.columns, index=self.index) exp = np.array(self.data) npt.assert_array_equal(obs, exp) def test_create_table_no_optionals(self): obs = _create_table(self.data) exp = np.array(self.data) npt.assert_array_equal(obs, exp) def test_create_table_same_backend(self): obs = _create_table( data=self.data, columns=self.columns, index=self.index, backend="numpy" ) exp = np.array(self.data) npt.assert_array_equal(obs, exp) def test_create_table_pandas_backend(self): obs = _create_table( data=self.data, columns=self.columns, index=self.index, backend="pandas" ) exp = pd.DataFrame(self.data, columns=self.columns, index=self.index) assert_data_frame_almost_equal(obs, exp) def test_create_table_bad_backend(self): with self.assertRaisesRegex(ValueError, "Unsupported backend: 'nonsense'"): _create_table(self.data, backend="nonsense") def test_create_table_1d_no_backend(self): obs = _create_table_1d(self.data_1d, index=self.index) exp = np.array(self.data_1d) npt.assert_array_equal(obs, exp) def test_create_table_1d_no_optionals(self): obs = _create_table_1d(self.data_1d) exp = np.array(self.data_1d) npt.assert_array_equal(obs, exp) def test_create_table_1d_same_backend(self): obs = _create_table_1d(self.data_1d, index=self.index, backend="numpy") exp = np.array(self.data_1d) npt.assert_array_equal(obs, exp) def test_create_table_1d_pandas_backend(self): obs = _create_table_1d(self.data_1d, index=self.index, backend="pandas") exp = pd.Series(self.data_1d, index=self.index) pdt.assert_series_equal(obs, exp) def test_create_table_1d_bad_backend(self): with self.assertRaisesRegex(ValueError, "Unsupported backend: 'nonsense'"): _create_table_1d(self.data, backend="nonsense") @skipIf(pl is None, "Polars is not available for unit tests.") class TestPolars(TestCase): def setUp(self): set_config("table_output", "polars") self.data = [[0, 1, 2], [3, 4, 5], [6, 7, 8]] self.data_1d = self.data[0] self.index = ["A", "B", "C"] self.columns = ["f1", "f2", "f3"] def tearDown(self): set_config("table_output", "pandas") def test_create_table_no_backend(self): obs = _create_table(data=self.data, columns=self.columns, index=self.index) exp = pl.DataFrame(self.data, schema=self.columns) plt.assert_frame_equal(obs, exp) def test_create_table_no_optionals(self): obs = _create_table(self.data) exp = pl.DataFrame(self.data) plt.assert_frame_equal(obs, exp) def test_create_table_pandas_columns(self): columns = pd.Series(self.columns) obs = _create_table(data=self.data, columns=columns, index=self.index) exp = pl.DataFrame(self.data, schema=self.columns) plt.assert_frame_equal(obs, exp) def test_create_table_same_backend(self): obs = _create_table( data=self.data, columns=self.columns, index=self.index, backend="polars" ) exp = pl.DataFrame(self.data, schema=self.columns) plt.assert_frame_equal(obs, exp) def test_create_table_numpy_backend(self): obs = _create_table( data=self.data, columns=self.columns, index=self.index, backend="numpy" ) exp = np.array(self.data) npt.assert_array_equal(obs, exp) def test_create_table_pandas_backend(self): obs = _create_table( data=self.data, columns=self.columns, index=self.index, backend="pandas" ) exp = pd.DataFrame(self.data, columns=self.columns, index=self.index) assert_data_frame_almost_equal(obs, exp) def test_create_table_bad_backend(self): with self.assertRaisesRegex(ValueError, "Unsupported backend: 'nonsense'"): _create_table(self.data, backend="nonsense") def test_create_table_1d_no_backend(self): obs = _create_table_1d(self.data_1d, index=self.index) exp = pl.Series(self.data_1d) plt.assert_series_equal(obs, exp) def test_create_table_1d_no_optionals(self): obs = _create_table_1d(self.data_1d) exp = pl.Series(self.data_1d) plt.assert_series_equal(obs, exp) def test_create_table_1d_same_backend(self): obs = _create_table_1d(self.data_1d, index=self.index, backend="polars") exp = pl.Series(self.data_1d) plt.assert_series_equal(obs, exp) def test_create_table_1d_pandas_backend(self): obs = _create_table_1d(self.data_1d, index=self.index, backend="pandas") exp = pd.Series(self.data_1d, index=self.index) pdt.assert_series_equal(obs, exp) def test_create_table_1d_numpy_backend(self): obs = _create_table( data=self.data, columns=self.columns, index=self.index, backend="numpy" ) exp = np.array(self.data) npt.assert_array_equal(obs, exp) def test_create_table_1d_bad_backend(self): with self.assertRaisesRegex(ValueError, "Unsupported backend: 'nonsense'"): _create_table_1d(self.data, backend="nonsense") class TestBIOM(TestCase): def setUp(self): self.data = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) self.samples = ["A", "B", "C"] self.features = ["f1", "f2", "f3"] def test_biom_input(self): tbl = Table( self.data.T, observation_ids=self.features, sample_ids=self.samples ) data, row_ids, col_ids = _ingest_table(tbl) npt.assert_array_equal(data, self.data) self.assertEqual(row_ids, self.samples) self.assertEqual(col_ids, self.features) def test_biom_input_pass_ids(self): tbl = Table( self.data.T, observation_ids=self.features, sample_ids=self.samples ) data, row_ids, col_ids = _ingest_table( tbl, sample_ids=self.samples, feature_ids=self.features ) npt.assert_array_equal(data, self.data) self.assertEqual(row_ids, self.samples) self.assertEqual(col_ids, self.features) @skipIf(adt is None, "Anndata is not available for unit tests.") class TestAnndata(TestCase): def setUp(self): self.data = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) self.samples = pd.DataFrame(index=["A", "B", "C"]) self.features = pd.DataFrame(index=["f1", "f2", "f3"]) def test_anndata_input(self): tbl = adt.AnnData(self.data, obs=self.samples, var=self.features) data, row_ids, col_ids = _ingest_table(tbl) npt.assert_array_equal(data, self.data) self.assertListEqual(list(row_ids), list(self.samples.index)) self.assertListEqual(list(col_ids), list(self.features.index)) def test_anndata_input_pass_ids(self): tbl = adt.AnnData(self.data, obs=self.samples, var=self.features) data, row_ids, col_ids = _ingest_table( tbl, sample_ids=list(self.samples.index), feature_ids=list(self.features.index) ) npt.assert_array_equal(data, self.data) self.assertListEqual(list(row_ids), list(self.samples.index)) self.assertListEqual(list(col_ids), list(self.features.index)) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/test.py000066400000000000000000000007321520735541300210150ustar00rootroot00000000000000"""Run pytest in scikit-bio configuration. ---------------------------------------------------------------------------- Copyright (c) 2013--, scikit-bio development team. Distributed under the terms of the Modified BSD License. The full license is in the file LICENSE.txt, distributed with this software. ---------------------------------------------------------------------------- """ from skbio.util import pytestrunner if __name__ == "__main__": pytestrunner() scikit-bio-scikit-bio-a3beaa6/skbio/tests/000077500000000000000000000000001520735541300206245ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/tests/__init__.py000066400000000000000000000005411520735541300227350ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/tests/test_base.py000066400000000000000000000030211520735541300231430ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from skbio._base import SkbioObject, ElasticLines class TestSkbioObject(unittest.TestCase): def test_no_instantiation(self): class Foo(SkbioObject): pass with self.assertRaises(TypeError): Foo() class TestElasticLines(unittest.TestCase): def setUp(self): self.el = ElasticLines() def test_empty(self): self.assertEqual(self.el.to_str(), '') def test_add_line(self): self.el.add_line('foo') self.assertEqual(self.el.to_str(), 'foo') def test_add_lines(self): self.el = ElasticLines() self.el.add_lines(['alice', 'bob', 'carol']) self.assertEqual(self.el.to_str(), 'alice\nbob\ncarol') def test_add_separator(self): self.el.add_separator() self.assertEqual(self.el.to_str(), '') self.el.add_line('foo') self.assertEqual(self.el.to_str(), '---\nfoo') self.el.add_separator() self.el.add_lines(['bar', 'bazzzz']) self.el.add_separator() self.assertEqual(self.el.to_str(), '------\nfoo\n------\nbar\nbazzzz\n------') if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/tests/test_config.py000066400000000000000000000020161520735541300235010ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main from skbio._config import get_config, set_config class TestOptions(TestCase): def test_set_config_bad_option(self): with self.assertRaisesRegex(KeyError, "Unknown option: 'nonsense'."): set_config("nonsense", "asdf") def test_set_config_bad_value(self): with self.assertRaisesRegex( ValueError, "Unsupported value 'asdf' for 'table_output'." ): set_config("table_output", "asdf") def test_get_config_bad_option(self): with self.assertRaisesRegex(KeyError, "Unknown option: 'frontend'."): get_config("frontend") if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/tests/test_workflow.py000066400000000000000000000315571520735541300241220ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from collections import defaultdict from skbio.workflow import (Exists, NotExecuted, NotNone, Workflow, not_none, requires, method) from unittest import TestCase, main def construct_iterator(**kwargs): """make an iterator for testing purposes""" to_gen = [] for k in sorted(kwargs): if k.startswith('iter'): to_gen.append(kwargs[k]) if len(to_gen) == 1: return (x for x in to_gen[0]) else: return zip(*to_gen) class MockWorkflow(Workflow): def initialize_state(self, item): self.state[0] = None self.state[1] = item @method(priority=90) @requires(option='A', values=True) def wf_groupA(self): self.methodA1() self.methodA2() @method() @requires(option='B', values=True) def wf_groupB(self): self.methodB1() self.methodB2() @method(priority=10) @requires(option='C', values=True) def wf_groupC(self): self.methodC1() self.methodC2() def methodA1(self): name = 'A1' self.stats[name] += 1 if self.state[-1] == 'fail %s' % name: self.failed = True self.state = [name, self.state[-1]] def methodA2(self): name = 'A2' self.stats[name] += 1 if self.state[-1] == 'fail %s' % name: self.failed = True self.state = [name, self.state[-1]] def methodB1(self): name = 'B1' self.stats[name] += 1 if self.state[-1] == 'fail %s' % name: self.failed = True self.state = 'failed' else: self.state = [name, self.state[-1]] @requires(option='foo', values=[1, 2, 3]) def methodB2(self): name = 'B2' self.stats[name] += 1 if self.state[-1] == 'fail %s' % name: self.failed = True self.state = 'failed' else: self.state = [name, self.state[-1]] def methodC1(self): name = 'C1' self.stats[name] += 1 if self.state[-1] == 'fail %s' % name: self.failed = True self.state = [name, self.state[-1]] @requires(option='C2', values=[1, 2, 3]) def methodC2(self): name = 'C2' self.stats[name] += 1 if self.state[-1] == 'fail %s' % name: self.failed = True self.state = [name, self.state[-1]] class WorkflowTests(TestCase): def setUp(self): opts = {'A': True, 'C': True} self.obj_short = MockWorkflow([None, None], options=opts, stats=defaultdict(int)) self.obj_debug = MockWorkflow([None, None], debug=True, options=opts, stats=defaultdict(int)) self.obj_noshort = MockWorkflow([None, None], short_circuit=False, options=opts, stats=defaultdict(int)) def test_debug_trace(self): gen = construct_iterator(**{'iter_x': [1, 2, 3, 4, 5]}) obj = self.obj_debug(gen) exp = ['C1', 1] obs = next(obj) self.assertEqual(obs, exp) exp_trace = set([('wf_groupA', 0), ('methodA1', 1), ('methodA2', 2), ('wf_groupC', 3), ('methodC1', 4)]) exp_pre_state = {('wf_groupA', 0): [None, 1], ('methodA1', 1): [None, 1], ('methodA2', 2): ['A1', 1], ('wf_groupC', 3): ['A2', 1], ('methodC1', 4): ['A2', 1]} exp_post_state = {('wf_groupA', 0): ['A2', 1], ('methodA1', 1): ['A1', 1], ('methodA2', 2): ['A2', 1], ('wf_groupC', 3): ['C1', 1], ('methodC1', 4): ['C1', 1]} obs_trace = self.obj_debug.debug_trace obs_pre_state = self.obj_debug.debug_pre_state obs_post_state = self.obj_debug.debug_post_state self.assertEqual(obs_trace, exp_trace) self.assertEqual(obs_pre_state, exp_pre_state) self.assertEqual(obs_post_state, exp_post_state) def test_init(self): self.assertEqual(self.obj_short.options, {'A': True, 'C': True}) self.assertEqual(self.obj_short.stats, {}) self.assertTrue(self.obj_short.short_circuit) self.assertEqual(self.obj_noshort.options, {'A': True, 'C': True}) self.assertEqual(self.obj_noshort.stats, {}) self.assertFalse(self.obj_noshort.short_circuit) def test_init_reserved_attributes(self): with self.assertRaises(AttributeError): Workflow('foo', failed=True) def test_all_wf_methods(self): # note on priority: groupA:90, groupC:10, groupB:0 (default) exp = [self.obj_short.wf_groupA, self.obj_short.wf_groupC, self.obj_short.wf_groupB] obs = self.obj_short._all_wf_methods() self.assertEqual(obs, exp) def test_call_AC_no_fail(self): iter_ = construct_iterator(**{'iter_x': [1, 2, 3, 4, 5]}) # success function def sf(x): return x.state[:] exp_stats = {'A1': 5, 'A2': 5, 'C1': 5} # C2 isn't executed as its requirements aren't met in the options exp_result = [['C1', 1], ['C1', 2], ['C1', 3], ['C1', 4], ['C1', 5]] obs_result = list(self.obj_short(iter_, sf, None)) self.assertEqual(obs_result, exp_result) self.assertEqual(self.obj_short.stats, exp_stats) def test_call_AC_fail(self): iter_ = construct_iterator(**{'iter_x': [1, 2, 'fail A2', 4, 5]}) # success function def sf(x): return x.state[:] ff = sf # failed function exp_stats = {'A1': 5, 'A2': 5, 'C1': 4, 'C2': 4} self.obj_short.options['C2'] = 1 # pass in a failed callback to capture the result, and pause execution gen = self.obj_short(iter_, sf, ff) r1 = next(gen) self.assertEqual(r1, ['C2', 1]) self.assertFalse(self.obj_short.failed) r2 = next(gen) self.assertEqual(r2, ['C2', 2]) self.assertFalse(self.obj_short.failed) r3 = next(gen) self.assertEqual(self.obj_short.state, ['A2', 'fail A2']) self.assertTrue(self.obj_short.failed) self.assertEqual(r3, ['A2', 'fail A2']) r4 = next(gen) self.assertEqual(r4, ['C2', 4]) self.assertFalse(self.obj_short.failed) r5 = next(gen) self.assertEqual(r5, ['C2', 5]) self.assertFalse(self.obj_short.failed) self.assertEqual(self.obj_short.stats, exp_stats) def test_call_AC_fail_noshort(self): iter_ = construct_iterator(**{'iter_x': [1, 2, 'fail A2', 4, 5]}) # success function def sf(x): return x.state[:] ff = sf # failed function exp_stats = {'A1': 5, 'A2': 5, 'C1': 5} # pass in a failed callback to capture the result, and pause execution gen = self.obj_noshort(iter_, sf, ff) r1 = next(gen) self.assertEqual(r1, ['C1', 1]) self.assertFalse(self.obj_noshort.failed) r2 = next(gen) self.assertEqual(r2, ['C1', 2]) self.assertFalse(self.obj_noshort.failed) next(gen) self.assertEqual(self.obj_noshort.state, ['C1', 'fail A2']) self.assertTrue(self.obj_noshort.failed) r4 = next(gen) self.assertEqual(r4, ['C1', 4]) self.assertFalse(self.obj_noshort.failed) r5 = next(gen) self.assertEqual(r5, ['C1', 5]) self.assertFalse(self.obj_noshort.failed) self.assertEqual(self.obj_noshort.stats, exp_stats) class MockWorkflowReqTest(Workflow): def _allocate_state(self): self.state = None def initialize_state(self, item): self.state = [None, item] @method(priority=5) @requires(state=lambda x: x[-1] < 3) def wf_needs_data(self): name = 'needs_data' self.stats[name] += 1 if self.state[-1] == 'fail %s' % name: self.failed = True self.state = [name, self.state[-1]] @method(priority=10) def wf_always_run(self): name = 'always_run' self.stats[name] += 1 if self.state[-1] == 'fail %s' % name: self.failed = True self.state = [name, self.state[-1]] @method(priority=20) @requires(option='cannot_be_none', values=not_none) def wf_run_if_not_none(self): name = 'run_if_not_none' self.stats[name] += 1 if self.state[-1] == 'fail %s' % name: self.failed = True self.state = [name, self.state[-1]] class RequiresTests(TestCase): def test_validdata(self): obj = MockWorkflowReqTest([None, None], stats=defaultdict(int)) single_iter = construct_iterator(**{'iter_x': [1, 2, 3, 4, 5]}) exp_stats = {'needs_data': 2, 'always_run': 5} exp_result = [['needs_data', 1], ['needs_data', 2], ['always_run', 3], ['always_run', 4], ['always_run', 5]] obs_result = list(obj(single_iter)) self.assertEqual(obs_result, exp_result) self.assertEqual(obj.stats, exp_stats) def test_not_none_avoid(self): obj = MockWorkflowReqTest([None, None], {'cannot_be_none': None}, stats=defaultdict(int)) single_iter = construct_iterator(**{'iter_x': [1, 2, 3, 4, 5]}) exp_stats = {'needs_data': 2, 'always_run': 5} exp_result = [['needs_data', 1], ['needs_data', 2], ['always_run', 3], ['always_run', 4], ['always_run', 5]] obs_result = list(obj(single_iter)) self.assertEqual(obs_result, exp_result) self.assertEqual(obj.stats, exp_stats) def test_not_none_execute(self): obj = MockWorkflowReqTest([None, None], options={'cannot_be_none': True}, debug=True, stats=defaultdict(int)) single_iter = construct_iterator(**{'iter_x': [1, 2, 3, 4, 5]}) exp_stats = {'needs_data': 2, 'always_run': 5, 'run_if_not_none': 5} exp_result = [['needs_data', 1], ['needs_data', 2], ['always_run', 3], ['always_run', 4], ['always_run', 5]] obs_result = list(obj(single_iter)) self.assertEqual(obs_result, exp_result) self.assertEqual(obj.stats, exp_stats) def test_methodb1(self): obj = MockWorkflow([None, None], stats=defaultdict(int)) obj.initialize_state('test') obj.methodB1() self.assertEqual(obj.state, ['B1', 'test']) self.assertFalse(obj.failed) # methodb1 executes regardless of if self.failed obj.failed = True obj.initialize_state('test 2') obj.methodB1() self.assertEqual(obj.state, ['B1', 'test 2']) obj.failed = False obj.state = [None, 'fail B1'] obj.methodB1() self.assertEqual(obj.state, 'failed') self.assertEqual(obj.stats, {'B1': 3}) def test_methodb2_accept(self): # methodb2 is setup to be valid when foo is in [1,2,3], make sure we # can execute obj = MockWorkflow([None, None], options={'foo': 1}, stats=defaultdict(int)) obj.initialize_state('test') obj.methodB2() self.assertEqual(obj.state, ['B2', 'test']) self.assertEqual(obj.stats, {'B2': 1}) def test_methodb2_ignore(self): # methodb2 is setup to be valid when foo is in [1, 2, 3], make sure # we do not execute obj = MockWorkflow([None, None], options={'foo': 'bar'}, stats=defaultdict(int)) obj.methodB2() self.assertEqual(obj.state, [None, None]) self.assertEqual(obj.stats, {}) class PriorityTests(TestCase): def test_dec(self): @method(priority=10) def foo(x, y, z): """doc check""" return x + y + z self.assertEqual(foo.priority, 10) self.assertEqual(foo.__name__, 'foo') self.assertEqual(foo.__doc__, 'doc check') class NotExecutedTests(TestCase): def test_call(self): ne = NotExecuted() obs = ne('foo') self.assertTrue(obs is ne) self.assertEqual(obs.msg, 'foo') class ExistsTests(TestCase): def test_contains(self): e = Exists() self.assertTrue('foo' in e) self.assertTrue(None in e) class NotNoneTests(TestCase): def test_contains(self): nn = NotNone() self.assertTrue('foo' in nn) self.assertFalse(None in nn) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/tree/000077500000000000000000000000001520735541300204215ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/tree/__init__.py000066400000000000000000000463071520735541300225440ustar00rootroot00000000000000r"""Trees and Phylogenetics (:mod:`skbio.tree`) =========================================== .. currentmodule:: skbio.tree This module provides functionality for working with trees, including phylogenetic trees and various types of hierarchies with relevance in biology or beyond. It supports trees that are multifurcating and nodes that have single descendants. Functionality is provided for constructing trees, for traversing in multiple ways, comparisons, fetching subtrees, and more. See the |tree_tutorial|_ section for working with trees using scikit-bio. Tree structure and operations ----------------------------- ``TreeNode`` is the data structure for tree representation. A tree consists of an arbitrary number of interconnected ``TreeNode`` objects representing individual nodes. Each node has pointers to its parent and children. The class provides a large number of methods to achieve various tasks for tree analysis and manipulation. .. autosummary:: :toctree: generated/ :template: TreeNode.rst TreeNode Tree Construction ----------------- Algorithms for phylogenetic reconstruction based on distance matrices. .. autosummary:: :toctree: generated/ upgma nj gme bme Tree Rearrangement ------------------ Algorithms for improving an existing phylogenetic tree via rearrangement. .. autosummary:: :toctree: generated/ nni Tree Comparison --------------- Metrics for assessing the topological or length dissimilarity among trees. .. autosummary:: :toctree: generated/ rf_dists wrf_dists path_dists Tree utilities -------------- .. autosummary:: :toctree: generated/ majority_rule Exceptions ^^^^^^^^^^ .. autosummary:: TreeError NoLengthError DuplicateNodeError MissingNodeError NoParentError .. |tree_tutorial| replace:: **Tutorial** .. _tree_tutorial: Tutorial -------- In scikit-bio, the :class:`TreeNode` class is the main and only data structure for tree representation. It is simple, flexible and powerful. >>> from skbio import TreeNode Loading a tree ^^^^^^^^^^^^^^ A tree can be constructed from a Newick string. :wiki:`Newick ` is a common file format used to represent tree structure based on nesting with parentheses. For instance, the following string describes a 3-taxon tree, with one internal node: ((A,B)C,D)root; Where A, B, and D are tips of the tree, and C is an internal node that unites tips A and B. C and D are in turn united by the root of the tree. If this string is stored in a file ``input.nwk``, we can read it into scikit-bio with: .. code-block:: python tree = TreeNode.read("input.nwk") Alternatively, we can directly convert a Newick string into a tree with: >>> tree = TreeNode.read(["((A,B)C,D)root;"]) >>> tree Let's display an ASCII representation of the tree: >>> print(tree.ascii_art()) /-A /C-------| -root----| \-B | \-D Optionally, we can attach branch lengths to the nodes in a Newick string. In phylogenetics, the branch length usually represents the amount of evolution accumulated from one node to another. For example: >>> tree = TreeNode.read(["((A:2,B:3)C:1,D:4)root;"]) To save a tree to a Newick file: .. code-block:: python tree.write("output.nwk") Navigating in a tree ^^^^^^^^^^^^^^^^^^^^ The variable ``tree`` is a :class:`TreeNode` object. It is merely the **root** node of the tree, but one can refer to the entire tree with just the root. >>> tree.name 'root' >>> tree.is_root() True Starting from the root node one can navigate to its child nodes. >>> len(tree.children) 2 The first child of root has the name "C". It is an **internal node** of the tree. >>> node = tree.children[0] >>> node.name 'C' >>> node.is_tip() False The branch length can be accessed via attribute ``length``. Note, that it is the length of the branch connecting the current node and its parent. >>> node.length 1.0 scikit-bio's ``TreeNode`` is highly flexible that we can refer to a subtree (a.k.a., a clade) within a larger tree using its root node (here "C"). There is no need to detach the subtree and we can just work with it in-place. Most tree analyses implemented in scikit-bio also apply to subtrees. The second child "D" is a **tip** (a.k.a., leaf). In a phylogenetic tree, a tip often represents a **taxon**, i.e. an organism or a group of organisms being studied. >>> node = tree.children[1] >>> node.name 'D' >>> node.is_tip() True Each node has exactly one parent node, with the exception of the root node, whose parent is None. >>> node.parent.name 'root' The ``parent`` and ``children`` attributes connect multiple nodes into a tree structure. Additionally, one can use methods like :meth:`~TreeNode.siblings`, :meth:`~TreeNode.neighbors`, :meth:`~TreeNode.ancestors` and :meth:`~TreeNode.root` to navigate to node with certain relationships to the current node. For example: >>> node.siblings()[0].name 'C' One can quickly find a node by name using :meth:`~TreeNode.find`: >>> node = tree.find("A") >>> node.name 'A' If the tree is giant, the first call of ``find`` may take a while, but all subsequent calls will complete in a flash. That's because ``find`` will cache and reuse a lookup table under the hood. Traversing a tree ^^^^^^^^^^^^^^^^^ The process of visiting each and every node within a tree is called :wiki:`tree traversal `. There are a few common ways to traverse a tree, and depending on your use, some methods are more appropriate than others. The wiki page linked above will go into further depth on this topic. Here, we're only going to cover two of the commonly used traversal methods: :meth:`~TreeNode.preorder` and :meth:`~TreeNode.postorder`. A preorder traversal moves from root to tips, looking at the left most child first. For instance: >>> for node in tree.preorder(): ... print(node.name) root C A B D A postorder traversal moves from tips to root, accessing the left subtree tips first before walking back up the tree: >>> for node in tree.postorder(): ... print(node.name) A B C D root If you are not certain (or don't mind) what method should be used to traverse the tree, simply use :meth:`~TreeNode.traverse`. Note, by default, those traversal methods will include self, i.e., the root node from which traversal starts. One can pass the ``include_self=False`` flag to the method call if you wish to exclude it. ``TreeNode`` provides multiple methods for iterating over certain nodes. For examples, :meth:`~TreeNode.tips` and :meth:`~TreeNode.non_tips` iterate over tips and internal nodes, respectively: >>> for node in tree.tips(): ... print(node.name) A B D >>> for node in tree.non_tips(): ... print(node.name) C If we just want to know the total number of nodes (or just tips) in a tree, we can do: >>> tree.count() 5 >>> tree.count(tips=True) 3 Instead, if we want to obtain a set of taxa (tip names) from a tree, we can use the :meth:`~TreeNode.subset` method (it is called the "subset" because one can call it at any node and get a subset of taxa descending from it). >>> taxa = tree.subset() >>> sorted(taxa) ['A', 'B', 'D'] Editing a tree ^^^^^^^^^^^^^^ As discussed above, a tree consists of multiple ``TreeNode`` objects connected to each other. To manipulate a tree, one just needs to change the connections between nodes. ``TreeNode`` provides several standard methods that let you work with nodes like Python lists. Create a new tip "E" and attach it to the internal node "C" as a child of it: >>> node = TreeNode("E") >>> tree.find("C").append(node) >>> print(tree.ascii_art()) /-A | /C-------|--B | | -root----| \-E | \-D Create two tips "F" and "G" and attach both of them to tip "D". Now "D" becomes an internal node because it has children: >>> D = tree.find("D") >>> D.extend([TreeNode("F"), TreeNode("G")]) >>> print(tree.ascii_art()) /-A | /C-------|--B | | -root----| \-E | | /-F \D-------| \-G Prune clade "D" and graft it to node "B". Once a node is attached to a new parent, the connection to its old parent is automatically removed. >>> B = tree.find("B") >>> B.append(D) >>> print(tree.ascii_art()) /-A | | /-F -root---- /C-------|-B------- /D-------| | \-G | \-E Remove clade "D" from node "B". This operation detaches the two nodes, but the removed node still exists in the memory and once can still use it. >>> B.remove(D) True >>> print(tree.ascii_art()) /-A | -root---- /C-------|--B | \-E >>> print(D.ascii_art()) /-F -D-------| \-G These methods automatically clear lookup tables and other caches because they may be obsolete for the modified tree. This safety measure could impact performance when working with very large trees. If caches are not present or relevant, we can add ``uncache=False`` to these methods to skip this check. See :meth:`~TreeNode.has_caches` for details. ``TreeNode`` provides several advanced methods for editing a tree as a batch. For examples, :meth:`~TreeNode.bifurcate` converts an arbitrary tree into a bifurcating tree (binary tree), :meth:`~TreeNode.shear` refines a tree to a given set of taxa, :meth:`~TreeNode.unpack_by_func` unpacks (contracts) branches that suffice certain criteria (e.g., bootstrap support below a threshold). Building a tree ^^^^^^^^^^^^^^^ scikit-bio provides several common algorithms for building a tree structure based on a distance matrix (:class:`~skbio.stats.distance.DistanceMatrix`) that stores pairwise distances between taxa. In the field of :wiki:`phylogenetics `, the evolutionary relationships among organisms are inferred using genetic data. :wiki:`Distance-based methods ` are a common category of methods for such purpose. The distances are usually computed from sequence alignment (see :mod:`skbio.alignment`), but they can also be inferred using alternative methods such as *k*-mer frequency (see :func:`~skbio.sequence.Sequence.kmer_frequencies`) and community diversity (see :mod:`skbio.diversity.beta`), and the applications of distance-based tree building are not limited to evolutionary biology, but can be extended to other fields (e.g., :wiki:`hierarchical clustering ` in data science). To begin with, let's create a distance matrix of seven taxa. >>> from skbio import DistanceMatrix >>> dm = DistanceMatrix([ ... [0. , 0.005, 0.033, 0.387, 0.626, 0.635, 0.665], ... [0.005, 0. , 0.028, 0.387, 0.626, 0.635, 0.665], ... [0.033, 0.028, 0. , 0.396, 0.635, 0.64 , 0.679], ... [0.387, 0.387, 0.396, 0. , 0.611, 0.611, 0.66 ], ... [0.626, 0.626, 0.635, 0.611, 0. , 0.147, 0.758], ... [0.635, 0.635, 0.64 , 0.611, 0.147, 0. , 0.754], ... [0.665, 0.665, 0.679, 0.66 , 0.758, 0.754, 0. ], ... ], ids=[ ... 'human', 'chimp', 'monkey', 'pig', 'mouse', 'rat', 'chicken' ... ]) The following code applies :wiki:`neighbor joining ` (:func:`nj`), a classic distance-based tree-building algorithm: >>> from skbio.tree import nj >>> tree = nj(dm) Display the reconstructed phylogenetic tree: >>> print(tree.ascii_art()) /-human | |--chimp ---------| | /-monkey | | \--------| /-pig | | \--------| /-mouse | /--------| \--------| \-rat | \-chicken Other methods include :func:`upgma` (simplest), :func:`gme` (highly scalable) and :func:`bme`. All of them can be applied in the same way. These four methods create a tree from scratch through a fixed set of procedures. Additionally, starting from an existing tree, :wiki:`tree rearrangement ` methods will explore the tree space further in order to improve it. Nearest neighbor interchange (:func:`nni`) is one such method. >>> from skbio.tree import nni >>> tree = nni(tree, dm) Rooting a tree ^^^^^^^^^^^^^^ The phylogenetic tree created above seems to properly reflect the relatedness among the seven organisms. However, the "root" of the tree doesn't appear to be aligned with our knowledge of evolution. This is because the tree is in fact **unrooted**. That is, the placement of branches does not inform the direction of evolution. In scikit-bio, the distinguishment between rooted and unrooted trees is implicit: Every tree has a root node. A tree is considered as "rooted" if its root node has exactly two children. In contrast, an "unrooted" tree may have three (the most common case), one, or more than three children attached to its root node. There are several approaches to root an unrooted tree to reflect the correct direction of evolution. Midpoint rooting (:meth:`~TreeNode.root_at_midpoint`) is a simple method that places the root at the midpoint between the two most distant tips in the tree. >>> rooted = tree.root_at_midpoint() >>> print(rooted.ascii_art()) /-chicken | ---------| /-mouse | /--------| | | \-rat \--------| | /-pig \--------| | /-monkey \--------| | /-chimp \--------| \-human If we already know which taxon or taxa (called an "outgroup") were separated from all other taxa in evolution, we can perform outgroup rooting (:meth:`~TreeNode.root_by_outgroup`): >>> rooted = tree.root_by_outgroup(["chicken"]) Or we can directly root a tree at a given taxon, node or branch: >>> rooted = tree.root_at("chicken") To convert a rooted tree into unrooted, we can apply the :meth:`~TreeNode.unroot` method. Analyzing topology ^^^^^^^^^^^^^^^^^^ The topology of a tree describes the grouping pattern among taxa. For example, in the rooted tree displayed above, human, chimp and monkey form a clade (a monophyletic group), while mouse and rat form another clade. A clade can be referred to by its root node, which is the lowest common ancestor (:wiki:`LCA `) of all descending taxa: >>> primate = rooted.lca(["human", "chimp", "monkey"]) >>> rodent = rooted.lca(["mouse", "rat"]) Note that one doesn't need to list all descending taxa in order to find the LCA. Two or more taxa that join at the LCA node on their paths to the root are sufficient for locating the LCA. >>> primate = rooted.lca(["human", "monkey"]) A clade regardless of its internal structure can be simply defined by the :meth:`~TreeNode.subset` of taxa descending from it (see above). All :meth:`~TreeNode.subsets` within a rooted tree describes all possible taxon groups. Assume we have another rooted tree ``tree2`` of the same taxa. To assess whether that tree also support human, chimp and monkey grouped together, we can simply do: .. code-block:: python primate.subset() in tree2.subsets() When working with unrooted trees, we should replace the notion of subset with bipartition (:meth:`~TreeNode.bipart`), which defines the separation of all taxa into two parts by a given branch, regardless of the direction of evolution. For example, both the rooted and unrooted trees support the separation of primates from other taxa: >>> primate.bipart() in tree.biparts() True The topology of two trees with shared taxa can be compared using the Robinson-Foulds (RF) distance, which is the number of bipartitions (unrooted trees) or subsets (rooted trees) that are distinct between the two trees. For example, let's define three trees, the first two of which have the same topology despite different orders of clades. >>> tree1 = TreeNode.read(["((A,B),(C,D),(E,F));"]) >>> tree2 = TreeNode.read(["((F,E),(C,D),(B,A));"]) >>> tree3 = TreeNode.read(["((C,B),(A,D),(E,F));"]) Calculate RF distances using (:meth:`~TreeNode.compare_rfd`): >>> tree1.compare_rfd(tree1) # identity case 0.0 >>> tree1.compare_rfd(tree2) # same tree but different clade order 0.0 >>> tree1.compare_rfd(tree3) # only 1 of 3 common clade 4.0 We can calculate pairwise RF distances between any number of trees using a single call of :func:`rf_dists`, which returns a distance matrix: >>> from skbio.tree import rf_dists >>> dm = rf_dists([tree1, tree2, tree3]) >>> print(dm) 3x3 distance matrix IDs: '0', '1', '2' Data: [[ 0. 0. 4.] [ 0. 0. 4.] [ 4. 4. 0.]] Analyzing distances ^^^^^^^^^^^^^^^^^^^ With branch lengths annotated, a phylogenetic tree describes the evolutionary distances among taxa. This important property is the basis for multiple downstream analyses, such as community diversity (see :mod:`skbio.diversity`). The :meth:`~TreeNode.distance` between two nodes in a tree (a.k.a., patristic distance) is the total length of branches constituting the path connecting them. For example: >>> human, mouse = tree.find("human"), tree.find("mouse") >>> human.distance(mouse).round(3) 0.628 The maximum distance between any pair of taxa (:meth:`~TreeNode.maxdist`) and the total branch length connecting all taxa (:meth:`~TreeNode.total_length`) can be used to measure the biodiversity of groups of organisms. The distances between all pairs of tips (taxa) in a tree can be efficiently calculated using :meth:`~TreeNode.cophenet`, which returns a distance matrix. .. code-block:: python dm = tree.cophenet() The evolutionary distances reflected by two trees can be compared. First, let's create two trees with the same taxa but different branch lengths. >>> tree1 = TreeNode.read(["((A:0.1,B:0.3):0.3,C:0.4,D:0.5);"]) >>> tree2 = TreeNode.read(["((A:0.4,B:0.7):0.3,C:0.1,D:0.5);"]) Calculate the distance between the cophenetic distance matrices using (:meth:`~TreeNode.compare_cophenet`): >>> tree1.compare_cophenet(tree2).round(3) 0.376 Likewise, we can calculate this metric between multiple trees using :func:`path_dists`. """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._tree import TreeNode from ._upgma import upgma from ._nj import nj from ._me import gme, bme, nni from ._majority_rule import majority_rule from ._compare import rf_dists, wrf_dists, path_dists from ._exception import ( TreeError, NoLengthError, DuplicateNodeError, MissingNodeError, NoParentError, ) __all__ = [ "TreeNode", "upgma", "nj", "gme", "bme", "nni", "rf_dists", "wrf_dists", "path_dists", "majority_rule", "TreeError", "NoLengthError", "DuplicateNodeError", "MissingNodeError", "NoParentError", ] scikit-bio-scikit-bio-a3beaa6/skbio/tree/_c_me.pyx000066400000000000000000003067071520735541300222420ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # cython: language_level=3, boundscheck=False, wraparound=False, cdivision=True from cython cimport floating from cython.parallel cimport prange # from openmp cimport omp_get_max_threads from libc.string cimport memmove # from libc.math cimport ldexp, ldexpf from heapq import heappush # This script hosts components of the greedy algorithms for phylogenetic reconstruction # using the minimum evolution (ME) principle. Specifically, it supports GME and BME for # de novo tree building, and FastNNI and BNNI for tree arrangement. # Most functions don't create any intermediate arrays, but repeatedly use pre-allocated # arrays for all operations. This improves computational efficiency. cdef extern from *: """ #ifdef _OPENMP #include int _get_max_threads() { return omp_get_max_threads(); } #else int _get_max_threads() { return 1; } #endif """ int _get_max_threads() def _get_num_threads(): """Determine the number of threads that will be used by OpenMP. If OpenMP is not installed in the system, it will return 1. """ return _get_max_threads() # cdef inline floating xldexp(floating x, int exp) noexcept nogil: # """Calculate power of 2. # This function is not used because tests found it is slower than pre-calculating # all possible powers of 2 (`npots`) and lookup. # Additionally, there is a bit hacking method to make this calculation even faster. # """ # if floating is float: # return ldexpf(x, exp) # else: # return ldexp(x, exp) def _preorder( Py_ssize_t[::1] order, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] stack, Py_ssize_t start = 0, ): r"""Perform preorder traversal. This function and :func:`_postorder` use stacks to avoid recursion. The stack array is pre-allocated. The output (ordered nodes) is also written into a pre-allocated array. This function and :func:`_postorder` are not actually used in the greedy algorithms in this module, which incrementally grow the tree as well as the orders. The two functions are implemented for reference and test purpose. """ cdef Py_ssize_t curr, left cdef Py_ssize_t order_i = 0 # next index of order cdef Py_ssize_t stack_i = 1 # next index of stack stack[0] = start while stack_i: # pop a node from stack into order stack_i -= 1 curr = stack[stack_i] order[order_i] = curr # index[curr] = order_i # preorder index order_i += 1 # append children to stack, right first such that left is processed first left = tree[curr, 0] if left: stack[stack_i] = tree[curr, 1] stack[stack_i + 1] = left stack_i += 2 def _postorder( Py_ssize_t[::1] order, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] stack, Py_ssize_t start = 0, ): """Perform postorder traversal. See also :func:`_preorder`. """ cdef Py_ssize_t curr, last, left, right cdef Py_ssize_t order_i = 0 cdef Py_ssize_t stack_i = 1 cdef Py_ssize_t prev = 0 # last visited node stack[0] = start curr = tree[start, 0] while stack_i: if curr: stack[stack_i] = curr stack_i += 1 curr = tree[curr, 0] # go to left child else: last = stack[stack_i - 1] left, right = tree[last, 0], tree[last, 1] if left and prev != right: curr = right # go to right child else: order[order_i] = last # index[last] = order_i # postorder index order_i += 1 prev = last stack_i -= 1 def _avgdist_matrix( floating[:, ::1] adm, floating[:, ::1] dm, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] tacts, ): r"""Calculate a matrix of average distances between all pairs of subtrees. This function will update adm, a float array of (n, n) representing pairwise distances between all nodes (tips, internal nodes and the root) in the tree. Implemented according to Appendix 4 of Desper and Gascuel (2002). Basically, this algorithm traverses the tree and calculates the average distance between each pair of subtrees. Here, a "subtree" is identified by a node, but it can be one of the two scenarios: 0. Lower subtree (L): the subtree descending from a node (including the node). 1. Upper subtree (U): the subtree branching from the node upward. The root of this subtree is the node's parent (NOT the node itself). Its immediate children are the parent's parent and the node's sibling. Then it iteratively applies Eq. 2 to calculate the average distance between two subtrees based on the average distances from the children (1 and 2) of one of the subtrees (B) to the other (A): d(A, B) = (|B_1| * d(A, B_1) + |B_2| * d(A, B_2)) / |B| NOTE: Although tracing ancestry of a given node can be done without preorder index, as in (`_bal`)`_avgdist_insert`, index is provided here to save compute since this operation needs to be done for every node in the tree. TODO: It might be possible to only fill half of the matrix (upper or lower triangle). Same for other functions, especially those in BME. """ cdef Py_ssize_t i, j, icur, isib cdef Py_ssize_t cur, par, sib, lft, p_size, s_size cdef Py_ssize_t a, a_size, a_taxon cdef Py_ssize_t a1 = 0, a2 = 0, a1_size = 0, a2_size = 0 cdef Py_ssize_t b, b_size, b1, b2 # pointers to matrix rows to facilitate lookup of cells cdef floating* dm_0 = &dm[0, 0] cdef floating* dm_a cdef floating* adm_0 = &adm[0, 0] cdef floating* adm_a # total numbers of taxa and nodes in the tree cdef Py_ssize_t m = tacts[0] + 1 cdef Py_ssize_t n = 2 * m - 3 # Calculate the average distance between each pair of subtrees defined by nodes # a and b (A4.1 of the paper). # Step 1: Calculate non-nested subtree-to-subtree distances (i.e., one is not an # ancestor of another. Therefore each subtree is the lower (descending) tree of # the node. (A4.1 (a)) # The paper suggests outer and inner postorder traverals for all nodes. Since # distances are symmetric, one can save half of the calculations, as done by the # following code. # Loop over nodes in reversed preorder (outcome matches postorder). # Skip the root, which is always the first node in the preorder traversal. for i in range(n - 1, 0, -1): a = order[i] a_size = tacts[a] # check if a is a tip if a_size == 1: a_taxon = tree[a, 1] else: a_taxon = 0 # a can never be root (taxon 0), therefore 0 means none a1, a2 = tree[a, 0], tree[a, 1] a1_size, a2_size = tacts[a1], tacts[a2] dm_a = &dm[a_taxon, 0] adm_a = &adm[a, 0] # Iterate over the ancestors of a, and find the other subtree on the right. # We can skip the left subtree because it must have been calculated already. # If the right subtree contains a's ancestry, just skip. icur = i while icur: cur = order[icur] par = tree[cur, 2] if (lft := tree[par, 0]) == cur: isib = icur + tacts[cur] * 2 - 1 # Loop over nodes within the right subtree in reversed preorder. # This preorder doesn't need to be re-calculated. Because all nodes within # a clade are contiguous in preorder, one can take a slice of the full # preorder that represents the descending nodes of the current node. The # size of the slice is 2 x taxon count - 2. for j in range(isib + tacts[tree[cur, 3]] * 2 - 2, isib - 1, -1): b = order[j] b_size = tacts[b] # If both a and b are tips, take the original taxon-to-taxon distance # (A4.1 (a) i). if b_size == 1 and a_taxon != 0: adm_a[b] = adm[b, a] = dm_a[tree[b, 1]] # If a is an internal node, and b is either (a tip or an internal node), # calculate the average distance based on the two child subtrees of a # (A4.1 (a) ii). elif a_taxon == 0: adm_a[b] = adm[b, a] = ( a1_size * adm[a1, b] + a2_size * adm[a2, b] ) / a_size # If a is a tip, and b is an internal node, calculate the average # distance based on the two child subtrees of b (A4.1 (a) iii). else: b1, b2 = tree[b, 0], tree[b, 1] adm_a[b] = adm[b, a] = ( tacts[b1] * adm_a[b1] + tacts[b2] * adm_a[b2] ) / b_size icur -= 1 else: icur -= tacts[lft] * 2 # Step 2: Calculate subtree to root (taxon 0) distances (A4.1 (b)). # This is done through a reversed preorder traversal. for i in range(n - 1, 0, -1): a = order[i] a_size = tacts[a] if a_size == 1: adm[a, 0] = adm_0[a] = dm_0[tree[a, 1]] else: a1, a2 = tree[a, 0], tree[a, 1] adm[a, 0] = adm_0[a] = ( tacts[a1] * adm_0[a1] + tacts[a2] * adm_0[a2] ) / a_size # Step 3: Calculate nested subtree to subtree distances, in which the first node # (a) is a descendant of the second node (b), therefore the first subtree (A) is # the lower (descending) tree of node a, whereas the second subtree (B) is the # upper (ancestral) tree of node b (A4.1 (c)). # This is done through a preorder traversal. for i in range(1, n): a = order[i] par, sib = tree[a, 2], tree[a, 3] # The size of (upper) subtree b is the complement of its descendants. Same for # the parent subtree. a_size = m - tacts[a] p_size = m - tacts[par] s_size = tacts[sib] # Iterate over all subtrees below b. # The paper says this traversal can be done in any manner. Here, we use the # preorder. See * above. adm_a = &adm[a, 0] for j in range(i + 1, i + tacts[a] * 2 - 1): b = order[j] adm_a[b] = adm[b, a] = ( s_size * adm[b, sib] + p_size * adm[b, par] ) / a_size def _bal_avgdist_matrix( floating[:, ::1] adm, floating[:, ::1] dm, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] sizes, ): r"""Calculate a matrix of balanced average distances between all pairs of subtrees. This function resembles :func:`_avgdist_matrix`, but it weighs subtrees equally regardless of their sizes. Specifically, it replaces Eq. 2 with Eq. 6. of Desper and Gascuel (2002): d(A, B) = (d(A, B_1) + d(A, B_2)) / 2 Same for all functions starting with `bal_`. """ cdef Py_ssize_t cur, par, sib, lft cdef Py_ssize_t i, j, icur, isib cdef Py_ssize_t a, b, a_taxon cdef Py_ssize_t a1 = 0, a2 = 0 cdef floating* dm_0 = &dm[0, 0] cdef floating* dm_a cdef floating* adm_0 = &adm[0, 0] cdef floating* adm_a cdef Py_ssize_t n = sizes[0] # Step 1: Calculate non-nested subtree to subtree distances. for i in range(n - 1, 0, -1): a = order[i] if tree[a, 0] == 0: a_taxon = tree[a, 1] else: a_taxon = 0 a1, a2 = tree[a, 0], tree[a, 1] dm_a = &dm[a_taxon, 0] adm_a = &adm[a, 0] icur = i while icur: cur = order[icur] par = tree[cur, 2] if (lft := tree[par, 0]) == cur: isib = icur + sizes[cur] for j in range(isib + sizes[tree[cur, 3]] - 1, isib - 1, -1): b = order[j] if tree[b, 0] == 0 and a_taxon != 0: adm_a[b] = adm[b, a] = dm_a[tree[b, 1]] elif a_taxon == 0: adm_a[b] = adm[b, a] = 0.5 * (adm[a1, b] + adm[a2, b]) else: adm_a[b] = adm[b, a] = 0.5 * ( adm_a[tree[b, 0]] + adm_a[tree[b, 1]] ) icur -= 1 else: icur -= sizes[lft] + 1 # Step 2: Calculate subtree to root distances. for i in range(n - 1, 0, -1): a = order[i] if tree[a, 0] == 0: adm[a, 0] = adm_0[a] = dm_0[tree[a, 1]] else: adm[a, 0] = adm_0[a] = 0.5 * (adm_0[tree[a, 0]] + adm_0[tree[a, 1]]) # Step 3: Calculate nested subtree to subtree distances. for i in range(1, n): a = order[i] adm_a = &adm[a, 0] par, sib = tree[a, 2], tree[a, 3] for j in range(i + 1, i + sizes[a]): b = order[j] adm_a[b] = adm[b, a] = 0.5 * (adm[b, sib] + adm[b, par]) def _avgdist_taxon( floating[:, ::1] adk, Py_ssize_t taxon, floating[:, :] dm, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] tacts, ): """Calculate average distances between a new taxon (k) and existing subtrees. This function will update adk, a float array of (2, n) in which the two rows represent the average distances from the taxon to the lower and upper subtrees of each existing node, respectively. Implemented according to Appendix 3 of Desper and Gascuel (2002). Basically, this algorithm calculates all lower subtree distances via a reversed preorder traversal (paper says postorder traversal), then calculates all upper subtree distances via a preorder traversal. """ cdef Py_ssize_t i cdef Py_ssize_t node, left, right, parent, sibling # total numbers of taxa and nodes in the tree cdef Py_ssize_t m = tacts[0] + 1 cdef Py_ssize_t n = 2 * m - 3 cdef floating* adkl = &adk[0, 0] cdef floating* adku = &adk[1, 0] # Calculate the distance between taxon and the lower subtree of each node. for i in range(n - 1, -1, -1): node = order[i] left, right = tree[node, 0], tree[node, 1] if left == 0: adkl[node] = dm[taxon, right] else: adkl[node] = ( tacts[left] * adkl[left] + tacts[right] * adkl[right] ) / tacts[node] # Assign upper distance of root. adku[0] = dm[taxon, 0] # Calculate the distance between taxon k and the upper subtree of each node. for i in range(1, n): node = order[i] parent, sibling = tree[node, 2], tree[node, 3] adku[node] = ( (m - tacts[parent]) * adku[parent] + tacts[sibling] * adkl[sibling] ) / (m - tacts[node]) def _avgdist_taxon_c( floating[:, ::1] adk, Py_ssize_t taxon, floating[:, ::1] dm, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] tacts, ): """Calculate average distances between a new taxon (k) and existing subtrees. This function is identical to `_avgdist_taxon` except that it assumes `dm` is C-contiguous, which makes lookup more efficient. """ cdef Py_ssize_t i cdef Py_ssize_t node, left, right, parent, sibling # total numbers of taxa and nodes in the tree cdef Py_ssize_t m = tacts[0] + 1 cdef Py_ssize_t n = 2 * m - 3 # pointer to taxon row in the distance matrix cdef floating* dm_k = &dm[taxon, 0] cdef floating* adkl = &adk[0, 0] cdef floating* adku = &adk[1, 0] # Calculate the distance between taxon and the lower subtree of each node. for i in range(n - 1, -1, -1): node = order[i] left, right = tree[node, 0], tree[node, 1] if left == 0: adkl[node] = dm_k[right] else: adkl[node] = ( tacts[left] * adkl[left] + tacts[right] * adkl[right] ) / tacts[node] # Assign upper distance of root. adku[0] = dm_k[0] # Calculate the distance between taxon k and the upper subtree of each node. for i in range(1, n): node = order[i] parent, sibling = tree[node, 2], tree[node, 3] adku[node] = ( (m - tacts[parent]) * adku[parent] + tacts[sibling] * adkl[sibling] ) / (m - tacts[node]) def _bal_avgdist_taxon( Py_ssize_t n, Py_ssize_t k, floating[:, :] dm, floating[:, ::1] adk, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, ): r"""Calculate balanced average distances between a new taxon and existing subtrees. This function resembles :func:`_avgdist_taxon` but uses the balanced framework. TODO: The 2nd half of this function (preorder traversal) can be merged into `_bal_min_branch`, a move that will potentially save time. TODO: This function can be parallelized too -- using a similar but more complex strategy as `_bal_min_branch_p` does. This strategy will involve incrementally maintaining a chunking scheme across outer iterations, instead of re-calculating it each time (current code does it because it is natural for preorder traversal, but this function starts with a reversed preorder traversal). """ cdef Py_ssize_t i cdef Py_ssize_t node, left, right cdef floating* adkl = &adk[0, 0] cdef floating* adku = &adk[1, 0] # Calculate distances to lower subtrees in reversed preorder (bottom-up). # This modifies the original algorithm, which is postorder. Both postorder and # reversed preorder guarantee that a node is visited after both of its children # have been visited. for i in range(n - 1, -1, -1): node = order[i] left, right = tree[node, 0], tree[node, 1] if left == 0: adkl[node] = dm[k, right] # tip: adopt from `dm` else: adkl[node] = 0.5 * (adkl[left] + adkl[right]) # internal: mean of children # distance to root (upper subtree of taxon 0) adku[0] = dm[k, 0] # Calculate distances to upper subtrees in preorder (top-down). for i in range(1, n): node = order[i] adku[node] = 0.5 * (adku[tree[node, 2]] + adkl[tree[node, 3]]) def _bal_avgdist_taxon_c( Py_ssize_t n, Py_ssize_t k, floating[:, ::1] dm, floating[:, ::1] adk, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, ): r"""Calculate balanced average distances between a new taxon and existing subtrees. Identical to `_bal_avgdist_taxon` but assumes a C-contiguous `dm`. """ cdef Py_ssize_t i cdef Py_ssize_t node, left, right cdef floating* dm_k = &dm[k, 0] cdef floating* adkl = &adk[0, 0] cdef floating* adku = &adk[1, 0] for i in range(n - 1, -1, -1): node = order[i] left, right = tree[node, 0], tree[node, 1] if left == 0: adkl[node] = dm_k[right] else: adkl[node] = 0.5 * (adkl[left] + adkl[right]) adku[0] = dm_k[0] for i in range(1, n): node = order[i] adku[node] = 0.5 * (adku[tree[node, 2]] + adkl[tree[node, 3]]) def _ols_lengths( floating[::1] lens, floating[:, ::1] adm, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] tacts, ): r"""Calculate branch lengths of a tree based on the OLS framework. Using an average distance matrix between all pairs of subtrees. Implemented according to Eqs. 3 & 4 of Desper and Gascuel (2002). TODO: Can be parallelized. Although this isn't a bottlenecking step. """ cdef Py_ssize_t node, left, right, parent, sibling cdef Py_ssize_t l_size, r_size, p_size, s_size cdef floating lambda_ cdef Py_ssize_t m = tacts[0] + 1 for node in range(1, 2 * m - 3): left = tree[node, 0] parent = tree[node, 2] sibling = tree[node, 3] # External (terminal) branch: based on the triplet (iAB) of self (i), parent # (A), and sibling (B) (Eq. 4). if left == 0: lens[node] = 0.5 * ( adm[parent, node] + adm[sibling, node] - adm[parent, sibling] ) # Internal branch: based on the quartet (AB|CD) of parent (A, upper), sibling # (B), and children (C and D) (Eq. 3). else: right = tree[node, 1] l_size = tacts[left] r_size = tacts[right] p_size = m - tacts[parent] s_size = tacts[sibling] lambda_ = (p_size * r_size + s_size * l_size) / ( (p_size + s_size) * (l_size + r_size) ) lens[node] = 0.5 * ( lambda_ * (adm[parent, left] + adm[sibling, right]) + (1 - lambda_) * (adm[parent, right] + adm[sibling, left]) - (adm[parent, sibling] + adm[left, right]) ) # root branch left, right = tree[0, 0], tree[0, 1] lens[0] = 0.5 * (adm[left, 0] + adm[right, 0] - adm[left, right]) def _ols_lengths_d2( floating[::1] lens, floating[:, ::1] ad2, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] tacts, ): r"""Calculate branch lengths of a tree based on an OLS framework. Using only average distances between pairs of distant-2 subtrees. This function produces the same result as `_ols_lengths`. The latter relies on Eq. 3 of Desper and Gascuel (2002), which involves distances between distant-3 subtrees. Therefore, we need to modify the equation such that it only takes distances between distant-2 subtrees as input. Specifically, with the following local structure: | parent / \ node sibling / \ left right We will need to calculate the distances between left / right (lower) and parent (upper) / sibling (lower). This can be achieved by (according to Fig. 2a): d(left(L), parent(U)) = d(left(L), node(U)) + d(node(L), parent(U)) - d(node(L), node(U)) Do the same for d(right(L), parent(U)), d(left(L), sibling(L)), and d(right(L), sibling(L)). Plug results into Eq. 3, we will get: l(node) = 0.5 * ( d(left(L), parent(U)) + d(right(L), parent(U)) + d(node(L), parent(U)) + d(node(L), sibling(U)) - d(sibling(L), parent(U)) - d(left(L), right(L)) ) - d(node(L), node(U)) Note that this equation is free of the lambda factor. Here, d(node(L), node(U)) is the distance between the lower and upper subtrees of the same node. This can be calculated using the equation in A4.1(c): d(node(L), node(U)) = (|sibling(L)| * d(node(L), sibling(L)) + |parent(U)| * d(node(L), parent(U))) / |node(U)| Therefore, we will get l(node). """ cdef Py_ssize_t node, left, sibling cdef Py_ssize_t m = tacts[0] + 1 cdef Py_ssize_t n = 2 * m - 3 cdef floating* ad2l = &ad2[0, 0] cdef floating* ad2u = &ad2[1, 0] for node in range(1, n): left = tree[node, 0] # External (terminal) branch: based on Eq. 4 of the paper. if left == 0: lens[node] = 0.5 * (ad2l[node] + ad2u[node] - ad2u[tree[node, 3]]) # Internal branch: based on the equation discussed above. else: sibling = tree[node, 3] lens[node] = 0.5 * ( ad2u[left] + ad2u[tree[node, 1]] + ad2u[node] + ad2l[node] - ad2u[sibling] - ad2l[left] ) - ( tacts[sibling] * ad2l[node] + (m - tacts[tree[node, 2]]) * ad2u[node] ) / (m - tacts[node]) # root branch left = tree[0, 0] lens[0] = 0.5 * (ad2u[left] + ad2u[tree[0, 1]] - ad2l[left]) def _bal_lengths( floating[::1] lens, floating[:, ::1] adm, Py_ssize_t[:, ::1] tree, ): r"""Calculate branch lengths of a tree based on the balanced framework. Using a balanced average distance matrix between all pairs of subtrees. This function resembles :func:`_ols_lengths` but it uses the balanced framework. Implemented according to Eqs. 3 & 4 and the description on top of pg. 691 of Desper and Gascuel (2002). """ cdef Py_ssize_t n = tree.shape[0] cdef Py_ssize_t node, left, right, parent, sibling for node in range(1, n): left, parent, sibling = tree[node, 0], tree[node, 2], tree[node, 3] # node is tip if left == 0: if tree[parent, 0] != node: lens[node] = 0.5 * ( adm[parent, node] + adm[sibling, node] - adm[parent, sibling] ) else: lens[node] = 0.5 * ( adm[parent, node] + adm[node, sibling] - adm[parent, sibling] ) # node is internal else: right = tree[node, 1] # node is left, sibling is right if tree[parent, 0] != node: right = tree[node, 1] lens[node] = 0.25 * ( adm[parent, left] + adm[sibling, right] + adm[parent, right] + adm[sibling, left] ) - 0.5 * (adm[parent, sibling] + adm[left, right]) # sibling is left, node is right else: lens[node] = 0.25 * ( adm[parent, left] + adm[right, sibling] + adm[parent, right] + adm[left, sibling] ) - 0.5 * (adm[parent, sibling] + adm[left, right]) left, right = tree[0, 0], tree[0, 1] lens[0] = 0.5 * (adm[0, left] + adm[0, right] - adm[left, right]) def _ols_min_branch_d2( floating[::1] lens, floating[:, ::1] ad2, floating[:, ::1] adk, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] tacts, ): r"""Find the branch with the minimum length change after inserting a new taxon. It returns the node at the lower end of the branch. Implemented according to Eq. 7 of Desper and Gascuel (2002). IMPORTANT NOTE: Should there are ties (which are common), this function returns the first minimum branch seen during preorder traversal. This behavior resembles FastME. Alternatively, one can return the first minimum branch by the order of addition using `return lens[:n].argmin()`, which could produce different results at the presence of ties. It must be noted that all candidates in a tie are equally optimal in the current iteration of the greedy algorithm. """ cdef Py_ssize_t i cdef Py_ssize_t node, parent, sibling, size, p_size, s_size cdef floating L, numerator, lambda_0, lambda_1 cdef Py_ssize_t min_i = 0 cdef floating min_len = 0 cdef Py_ssize_t m = tacts[0] + 1 cdef Py_ssize_t n = 2 * m - 3 cdef floating* ad2l = &ad2[0, 0] cdef floating* ad2u = &ad2[1, 0] cdef floating* adkl = &adk[0, 0] cdef floating* adku = &adk[1, 0] # Traverse tree in preorder and calculate the length change of each branch from its # previous branch. for i in range(1, n): node = order[i] parent = tree[node, 2] sibling = tree[node, 3] size = tacts[node] p_size = m - tacts[parent] s_size = tacts[sibling] numerator = s_size + size * p_size lambda_0 = numerator / ((s_size + size) * (p_size + 1)) lambda_1 = numerator / ((s_size + p_size) * (size + 1)) # factor 0.5 is omitted lens[node] = L = lens[parent] + ( (lambda_0 - lambda_1) * (adkl[sibling] + ad2u[node]) + (lambda_1 - 1) * (ad2l[sibling] + adku[parent]) + (1 - lambda_0) * (ad2u[sibling] + adkl[node]) ) if L < min_len: min_len, min_i = L, i return min_i def _bal_min_branch( Py_ssize_t n, floating[::1] lens, floating[:, ::1] adm, floating[:, ::1] adk, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, ): """Find the branch with the minimum length change after inserting a new taxon. This function resembles :func:`_ols_min_branch_d2` but it 1) uses the balanced framework and 2) calculates based on the entire matrix. See also the note of the latter. Implemented according to Eq. 10 of Desper and Gascuel (2002). """ cdef Py_ssize_t i cdef Py_ssize_t node, parent cdef floating length cdef floating* adkl = &adk[0, 0] cdef floating* adku = &adk[1, 0] cdef Py_ssize_t min_i = 0 cdef floating min_len = 0 # Identify the smallest branch length change through a preorder traversal. # NOTE: Length change of root (`lens[0]`) has been set to zero. for i in range(1, n): node = order[i] parent = tree[node, 2] lens[node] = length = lens[parent] + ( adm[parent, tree[node, 3]] # parent-sibling + adkl[node] - adm[tree[parent, 0], tree[parent, 1]] # node-sibling - adku[parent] ) # NOTE: In the above code, `node` and `sibling` are looked up again to # make the calculation branchless. if length < min_len: min_len, min_i = length, i return min_i # def _bal_min_branch2( # Py_ssize_t n, # floating[::1] lens, # floating[:, ::1] adm, # floating[:, ::1] adk, # Py_ssize_t[:, ::1] tree, # Py_ssize_t[::1] order, # Py_ssize_t[::1] sizes, # ): # """Find the branch with the minimum length change after inserting a new taxon. # This is an alternative version that is faster, but it doesn't maintain strict # preorder. Result may be different. # """ # cdef Py_ssize_t i, node, left, right # cdef floating L_intm, L_left, L_right # cdef floating* adkl = &adk[0, 0] # cdef floating* adku = &adk[1, 0] # cdef Py_ssize_t min_i = 0 # cdef floating min_len = 0 # for i in range(n): # node = order[i] # if left := tree[node, 0]: # right = tree[node, 1] # L_intm = lens[node] - adm[left, right] - adku[node] # lens[left] = L_left = L_intm + adm[node, right] + adkl[left] # lens[right] = L_right = L_intm + adm[node, left] + adkl[right] # if L_left <= L_right: # if L_left < min_len: # min_len, min_i = L_left, i + 1 # elif L_right < min_len: # min_len, min_i = L_right, i + sizes[left] + 1 # return min_i def _bal_min_branch_p( Py_ssize_t n, floating[::1] lens, floating[:, ::1] adm, floating[:, ::1] adk, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] sizes, Py_ssize_t enc, Py_ssize_t[::1] clades, Py_ssize_t[::1] chunks, Py_ssize_t[::1] roots, floating[::1] rlens, ): r"""Find the branch with the minimum length change after inserting a new taxon. This is the parallel version of `_bal_min_branch`. It divides the tree into chunks of clades that are roughly even in size, and calculates the minimum length change within each clade through parallelization. Specifically, this function performs a preorder traversal of the tree, calculating the length change of every node it visits, while determining whether the clade descending from this node (excluding the node) can be placed into a chunk for subsequent parallelization. If the clade can fit into a chunk, it will not be traversed, and the node index will jump to the next clade. If the clade is too large to fit, it will be decomposed into subclades by moving the node index forward in the traversal. This process generates a list of "roots" representing nodes that are already visited and calculated, and a list of "clades" left to be calculated. The clades are placed into chunks (one chunk can have one or multiple clades). Parallelization then starts over the chunks of clades. Within each clade, all nodes are traversed and the node with the minimum length change is determined. Finally, the minimum length changes under all roots are compared and the global minimum is determined. Because roots are in preorder, it is guaranteed that the result is the first minimum in preorder. In the following example, x and + are nodes visited and calculated during the serial phase. o are nodes within clades (there are two) that are calculated during the parallel phase. At the end of the serial phase, "roots" are x and +. In the parallel phase, the two clades are traversed and each root can move from a + to an o if the latter has a smaller length change. But roots at x don't need to be updated, since they are either tips or ancestors of clades. Finally, x and the combo of either + or o are compared to determine the global minimum. x / \ x \ / \ \ + x + / \ / \ o o o o / \ o o """ cdef Py_ssize_t node, min_node, parent cdef Py_ssize_t size, size_1 cdef Py_ssize_t min_i = 0 cdef floating length cdef floating min_len = 0 cdef floating* adkl = &adk[0, 0] cdef floating* adku = &adk[1, 0] # chunk capacity cdef Py_ssize_t capacity = max(1, (sizes[0] + enc - 1) // enc) # remaining space of current chunk cdef Py_ssize_t space = capacity cdef Py_ssize_t i = 1 # current node index cdef Py_ssize_t iroo = 1 # current root index cdef Py_ssize_t icla = 0 # current clade index cdef Py_ssize_t nchu = 1 # current number of chunks cdef Py_ssize_t ichu # current chunk index # Serial phase: Traverse the tree from root and identify clades to parallelize on, # while doing calculations for nodes outside those clades. while i < n: node = order[i] size = sizes[node] size_1 = size - 1 # add current node to roots roots[iroo] = i # calculate length change of the current node parent = tree[node, 2] rlens[iroo] = lens[node] = lens[parent] + ( adm[parent, tree[node, 3]] + adkl[node] - adm[tree[parent, 0], tree[parent, 1]] - adku[parent] ) # current node is tip: already calculated, move on if size == 1: i += 1 # put in current chunk elif size_1 <= space: clades[icla] = iroo icla += 1 space -= size_1 i += size # put in next chunk elif size_1 <= capacity: chunks[nchu] = icla nchu += 1 clades[icla] = iroo icla += 1 space = capacity - size_1 i += size # mark for decomposition else: i += 1 iroo += 1 chunks[nchu] = icla # Parallel phase: Do calculations within chunks of clades. for ichu in prange(nchu, nogil=True, schedule="dynamic"): for icla in range(chunks[ichu], chunks[ichu + 1]): i = clades[icla] min_i = roots[i] min_node = order[min_i] min_len = lens[min_node] for j in range(min_i + 1, min_i + sizes[min_node]): node = order[j] parent = tree[node, 2] lens[node] = length = lens[parent] + ( adm[parent, tree[node, 3]] + adkl[node] - adm[tree[parent, 0], tree[parent, 1]] - adku[parent] ) if length < min_len: min_len, min_i = length, j roots[i] = min_i rlens[i] = min_len # Finally, identify the global minimum length change by comparing the roots. # Note that "roots" are no longer roots of clades, but can be replaced with # nodes descending from them. min_len, min_i = 0.0, 0 for i in range(iroo): length = rlens[i] if length < min_len: min_len, min_i = length, roots[i] return min_i def _avgdist_d2_insert( floating[:, ::1] ad2, Py_ssize_t itag, floating[:, ::1] adk, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] tacts, ): r"""Update average distances between distant-2 subtrees after taxon insertion. This function will update `ad2`, a float array of (2, n) representing pairwise distances between all distant-2 subtrees in the tree. Here, `distant-2 subtrees` refer to subtrees that are two branches away from each other. Specifically, there are two scenarios: - Row 0: Distance between the lower subtree of the current node and the lower subtree of its parent. - Row 1: Distance between the lower subtree of the current node and the upper subtree of its sibling. This function assumes that the taxon will be inserted into the branch connecting the target node and its parent. After insertion, the taxon will become the sibling of the target. parent parent / \ / \ => link sibling target sibling / \ target taxon (k) This function should be executed *before* calling :func:`_insert_taxon`, which will mutate the tree. Implemented according to Eq. 8 of Desper and Gascuel (2002). """ # total taxon count (all tips plus root) cdef Py_ssize_t m = tacts[0] + 1 # total node count cdef Py_ssize_t n = 2 * m - 3 # node indices as in tree cdef Py_ssize_t tag = order[itag] # target node cdef Py_ssize_t lnk = n # link node cdef Py_ssize_t kay = n + 1 # new taxon (k) cdef Py_ssize_t node, curr # any node and current node cdef Py_ssize_t par, sib, lft, rgt # parent, sibling, left and right children # node indices as in order cdef Py_ssize_t i cdef Py_ssize_t ipar, isib # taxon counts cdef Py_ssize_t tact = tacts[tag] cdef Py_ssize_t tact_1 = tact + 1 cdef Py_ssize_t cpar # row pointers cdef floating* ad2l = &ad2[0, 0] cdef floating* ad2u = &ad2[1, 0] cdef floating* adkl = &adk[0, 0] cdef floating* adku = &adk[1, 0] ###### Special case: insert into the root branch. ###### if tag == 0: # Assign taxon counts of special ndes. tacts[kay] = 1 tacts[lnk] = tact # k (lower) to root (parent, upper): pre-calculated ad2u[kay] = adku[0] # k (lower) to link (sibling, lower): equals to k to root (lower). ad2l[lnk] = ad2l[kay] = adkl[0] # Link (lower) to root (parent, upper): de novo calculation according to the # equation in A4.1(b). It is basically the distance between the upper and lower # subtrees of the root itself. lft, rgt = tree[0, 0], tree[0, 1] ad2u[lnk] = (tacts[lft] * ad2u[lft] + tacts[rgt] * ad2u[rgt]) / tact # Calculate all node (lower) to parent (upper, containing k) distances. These # parents include the new link. for node in range(1, n): cpar = m - tacts[tree[node, 2]] ad2u[node] = (adkl[node] + ad2u[node] * cpar) / (cpar + 1) # Finally, update the taxon count of root. tacts[0] = tact_1 return ###### Regular case: insert into any other branch. ###### # Assign taxon counts of special ndes. tacts[kay] = 1 tacts[lnk] = tact_1 # Temporarily copy the distances of target to link (will edit later). ad2u[lnk] = ad2u[tag] ad2l[lnk] = ad2l[tag] # Distance between k (lower) and link (parent, upper) equals to that between k and # the upper subtree of target. ad2u[kay] = adku[tag] # Distance between target (lower) and link (parent, upper) needs to be calculated # using the equation in A4.1(c). Basically, it is the distance between the lower # and upper subtrees of the same target. par, sib = tree[tag, 2], tree[tag, 3] ad2u[tag] = (tacts[sib] * ad2l[tag] + (m - tacts[par]) * ad2u[tag]) / (m - tact) # Transfer the pre-calculated distance between target (lower) and k (sibling, # lower). ad2l[tag] = ad2l[kay] = adkl[tag] # Within the clade below target, calculate the distance between each node (lower) # and its parent (upper, containing k). for i in range(itag + 1, itag + tact * 2 - 1): node = order[i] cpar = m - tacts[tree[node, 2]] ad2u[node] = (adkl[node] + ad2u[node] * cpar) / (cpar + 1) # Locate the preorder indices of parent and sibling. # NOTE: The same logic is also included in the `while` loop below, which is awkward # but necessary because the loop starts with link instead of target. Unless we # update tree topology before this function call, we can't let the loop handle the # special case without adding unnecessary checks. if tree[par, 0] == tag: # target/link is left child ipar = itag - 1 isib = itag + tact * 2 - 1 else: # right child ipar = itag - tacts[sib] * 2 isib = ipar + 1 # Iterate over the ancestors of target, starting from link and ending at root. curr = lnk while curr: # Calculate the distance between each pair of lower (containing k) and upper # ancestors. ad2u[curr] = (adku[par] + ad2u[curr] * tact) / tact_1 # Calculate the distance between each ancestor (lower, containing k) and its # sibling (lower). ad2l[curr] = ad2l[sib] = (adkl[sib] + ad2l[curr] * tact) / tact_1 # Within the clade below each sibling, calculate the distance between each node # (lower) and its parent (upper, containing k). for i in range(isib + 1, isib + tacts[sib] * 2 - 1): node = order[i] cpar = m - tacts[tree[node, 2]] ad2u[node] = (adkl[node] + ad2u[node] * cpar) / (cpar + 1) # Up one level. curr = par par, sib, tact = tree[curr, 2], tree[curr, 3], tacts[curr] tact_1 = tact + 1 # Locate parent and sibling of the current node. if tree[par, 0] == curr: # left child isib = ipar + tact * 2 - 1 ipar -= 1 else: # right child ipar -= tacts[sib] * 2 isib = ipar + 1 # Add k to taxon count. tacts[curr] += 1 def _bal_avgdist_insert( Py_ssize_t n, Py_ssize_t itag, floating[:, ::1] adm, floating[:, ::1] adk, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] sizes, Py_ssize_t[::1] deeps, floating[::1] diffs, floating[::1] npots, Py_ssize_t[::1] ancs, Py_ssize_t[::1] ancx, ): r"""Update balanced average distance matrix after taxon insertion. This function resembles :func:`_avgdist_d2_insert` but it 1) uses the balanced framework and, 2) updates the entire matrix (`adm`), which makes it the dominant term of the entire algorithm. This function is the serial version. A parallel version can be found in :func:`_bal_avgdist_insert_p`. *** This function assumes that the taxon will be inserted into the branch connecting the target node and its parent. After insertion, the taxon will become the right sibling of the target. parent parent / \ / \ => link sibling target sibling / \ target taxon (k) This function only updates distance [i, j] but not [j, i], saving half of the assignment operations, which are expensive given the size of the matrix. i and j suffice i < j in a preorder traversal (parent - left - right), where 1) ancestors are always earlier than their descendants, and 2) left children (and their descendants) are always earlier than right children (and their descendants). Therefore, the order of i, j can be easily determined during tree traversal. anc3 (root) / \ anc2 x / \ + anc1 / / \ + link x / \ target taxon (k) / o / \ o o The tree can be partitioned into two parts: 1) the clade descending from target (o) and 2) the clades that are cousins to the target, which in turn are divided into left cousins (+) and right cousins (x). These clades can be identified by navigating all ancestors of target up to root. 0. For a tree with N taxa, the number of ancestors (i.e., depth) of any node is between O(logN) (balanced tree, best case) and O(N) (skewed tree, worst case). The distances to be updated can be divided into two compute-intensive categories: 1. Within each clade (o, + and x), the distance between the upper subtree of each ancestor and the lower subtree of each of its descendants needs to be updated. The total number of ancestor-descendant pairs (i.e., sum of depths) is between O(nlogn) (balanced tree, best case) and O(n^2) (skewed tree, worst case). 2. Within each cousin clade (+ and x), the distance between the lower subtree of each node and the lower subtree of each ancestor of target needs to be updated. *** Several additional arrays are involved: - `sizes` stores the number of nodes (including self) within the clade descending from each node. It facilitates the determination of range of node constituting the clade. - `deeps` stores the number of branches from each node to root (i.e., depth). It facilitates the calculation of path distance between two arbitrary nodes. - `npots` is a pre-calculated array of 2^(-l) powers (l is the depth difference between two nodes). - `ancs` is an integer array storing ancestral nodes of target. - `ancx` is an integer array storing (index * stride) of ancestral nodes of target. It facilitates locating individual cells in `adm`. """ # node indices as in tree cdef Py_ssize_t a cdef Py_ssize_t tag = order[itag] # target node cdef Py_ssize_t lnk = n # link node cdef Py_ssize_t kay = n + 1 # new taxon (k) cdef Py_ssize_t par = tree[tag, 2] # parent cdef Py_ssize_t sib = tree[tag, 3] # sibling cdef Py_ssize_t cur # current cdef Py_ssize_t anc # ancestor cdef Py_ssize_t lft # left child # node indices as in order cdef Py_ssize_t i, j cdef Py_ssize_t icur, ianc, icuz # current, ancestor, cousin # sizes (number of nodes in clade) cdef Py_ssize_t size = sizes[tag] cdef Py_ssize_t s_cur, s_cuz # depths (number of branches to root) cdef Py_ssize_t deep = deeps[tag] # intermediate variables cdef floating cell # specific value in `adm` (a matrix) cdef floating diff # difference of distance; usually from `adk` cdef floating npot # negative power of 2; from `npots` cdef floating* adkl = &adk[0, 0] cdef floating* adku = &adk[1, 0] # pointers to specific rows in `adm` cdef floating* adm_0 = &adm[0, 0] cdef floating* adm_t = &adm[tag, 0] cdef floating* adm_l = &adm[lnk, 0] cdef floating* adm_k = &adm[kay, 0] cdef floating* adm_r # ancestor cdef floating* adm_a # arbitrary node cdef Py_ssize_t deg # number of branches between two nodes cdef Py_ssize_t lvl # number of branches above target's parent cdef Py_ssize_t stride = adm.shape[1] # width of `adm` cdef floating* npots_2 = &npots[2] # power array offset sizes[kay] = 1 # k is a tip with size = 1 ##### Special case: insert into the root branch. ##### # root (target) root # / \ / \ # left right => link taxon (k) # / \ # left right if itag == 0: # Update sizes and deeps (see illustration above). sizes[0] = n + 2 sizes[lnk] = n deeps[lnk] = deeps[kay] = 1 # Transfer distance between k and root (upper). adm_t[kay] = adku[0] # k to link: equals to k to root (lower). adm_l[kay] = adkl[0] # Root to link: de novo calculation according to the equation in A4.1(b). It is # basically the distance between the upper and lower subtrees of the root. adm_t[lnk] = 0.5 * (adm_t[tree[0, 0]] + adm_t[tree[0, 1]]) # Iterate over all nodes but root (first in preorder). It is important to do # this in reverse preorder, such that the intermediates (see below) of all # descendants of a node are already calculated when they are used. for i in range(n - 1, 0, -1): a = order[i] adm_a = &adm[a, 0] # Transfer distances between the node (lower) and k. adm_a[kay] = diff = adkl[a] cell = adm_t[a] # Calculate the distance between the node (lower) and link (upper, with two # taxa (0 and k) added) using Eq. 8. adm_l[a] = 0.5 * (diff + cell) # Calculate this intermediate and store in `adkl`, such that it won't need # to be repeatedly calculated in the loop below. `adkl` will be completely # re-calculated by `_bal_avgdist_taxon`, so it is fine to use it to store # intermediates. diffs[i] = diff - cell # Update depth (entire tree +1 deeper). # NOTE: Although depth is unnecessary for tips, having an `if` check here # may not benefit performance because interleaved internal/tips are bad for # branch prediction. deeps[a] = deg = deeps[a] + 1 # Calculate the distances between the node (upper, containing k) and each # of its descendants (lower). We can now reuse the intermediate calculated # above. The order of iteration is not important. npot = npots[deg] for j in range(i + 1, i + sizes[a]): adm_a[order[j]] += npot * diffs[j] # NOTE: `npots[deg] * num` can be replaced with `xldexp(num, -deg)`, but # tests found the current method is faster. return ##### Regular case: insert into any other branch. ##### # parent parent # / \ / \ # target sibling => link sibling # / \ # target taxon (k) ### Step 1: Distances around the insertion point. ### # Update sizes and deeps. sizes[lnk] = size + 2 deeps[lnk] = deep = deeps[tag] deeps[kay] = deeps[tag] = deep + 1 # Distance between k (lower) and link (upper) equals to that between k and the # upper subtree of target. adm_l[kay] = adku[tag] # Distance between target (lower) and link (upper) needs to be calculated using the # equation in A4.1(c). Basically, it is the distance between the lower and upper # subtrees of the same target. cell = adm[tag, sib] if tree[par, 0] == tag else adm[sib, tag] adm_l[tag] = 0.5 * (cell + adm[par, tag]) # Transfer pre-calculated distance between target (lower) and k (lower). adm_t[kay] = adkl[tag] ### Step 2: Distances within the clade below target. ### # Locate the clade below target (excluding target). for i in range(itag + size - 1, itag, -1): a = order[i] adm_a = &adm[a, 0] # Transfer pre-calculated distance between k (lower) and any node within # the clade (lower). adm_a[kay] = diff = adkl[a] # Distance between any descendant (lower) and link (upper) equals to that to # target. adm_l[a] = cell = adm_t[a] # Calculate the distance between each descendant (lower) and target (upper). adm_t[a] = 0.5 * (diff + cell) diffs[i] = diff - cell deeps[a] = deg = deeps[a] + 1 # Within the clade, find all ancestor (a) - descendant (b) pairs, and calculate # the distance between a (upper, with k) and b (lower). npot = npots[deg - deep] for j in range(i + 1, i + sizes[a]): adm_a[order[j]] += npot * diffs[j] ### Step 3: Distances among nodes outside the clade. ### # Iterate over ancestors of target in ascending order till root. lvl = 0 deg = 2 - deep icur = itag s_cur = size while icur: cur = order[icur] # Determine ancestor node and its pointer in `adm`. ancs[lvl] = anc = tree[cur, 2] ancx[lvl] = stride * anc adm_r = &adm[anc, 0] # Transfer the pre-calculated distance between k and ancestor (upper). adm_r[kay] = diff = adku[anc] # Calculate the distance between link (lower, with k) and ancestor (upper). cell = adm_r[tag] adm_r[lnk] = 0.5 * (diff + cell) # Calculate the distance between each previous ancestor (lower, with k) # and the current ancestor (upper). diff -= cell for i in range(lvl): adm_r[ancs[i]] += npots_2[i] * diff # Determine whether cousin is the right or left child of the shared ancestor. # This helps to determine the order of coordinates of each distance to be # updated. Basically, if the left child of parent is current, then current is # left and cousin is right. In this case, coordinates are [current, cousin]. if (lft := tree[anc, 0]) == cur: # Determine the indices of ancestor and cousin in preorder. The current # solution is awkward as it is separate from the determination process in # tree, due to the lack of mapping from tree indices to preorder indices. # Since current is left, parent is -1 from current, and right cousin is # current + its size. ianc = icur - 1 icuz = icur + s_cur s_cuz = sizes[order[icuz]] # Locate the cousin clade descending from the ancestor (including cousin). for i in range(icuz + s_cuz - 1, icuz - 1, -1): a = order[i] adm_a = &adm[a, 0] # Transfer the pre-calculated distances between k and each descendant # (lower). adm_k[a] = diff = adkl[a] # Calculate the distance between link (lower, with k) and each # descendant (lower). cell = adm_t[a] adm_l[a] = 0.5 * (diff + cell) diffs[i] = diff = diff - cell # intermediate # Calculate the distance between each previous ancestor (lower, with k # and each descendant (lower). for j in range(lvl): # This is equivalent to: adm[ancs[j], a] += ... but faster (maybe). adm_0[ancx[j] + a] += npots_2[j] * diff # Calculate the distance between a (upper, with k) and each of its # descendants (lower). npot = npots[deeps[a] + deg] for j in range(i + 1, i + sizes[a]): adm_a[order[j]] += npot * diffs[j] # Cousin is left, and coordinates are [cousin, current]. Otherwise the same. else: # ancestor index = current index - cousin size - 1 s_cuz = sizes[lft] ianc = icur - s_cuz - 1 # This is equivalent to range(icuz + s_cuz - 1, icuz - 1, -1), in which # icuz = ianc + 1. for i in range(ianc + s_cuz, ianc, -1): a = order[i] adm_a = &adm[a, 0] diff, cell = adkl[a], adm_a[tag] adm_a[kay] = diff adm_a[lnk] = 0.5 * (diff + cell) diffs[i] = diff = diff - cell for j in range(lvl): adm_a[ancs[j]] += npots_2[j] * diff npot = npots[deeps[a] + deg] for j in range(i + 1, i + sizes[a]): adm_a[order[j]] += npot * diffs[j] # level up icur = ianc s_cur = sizes[anc] sizes[anc] += 2 # every ancestor size +2 (link and k added) lvl += 1 deg += 2 def _calc_tacts( Py_ssize_t n, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] tacts, ): """Calculate the number of taxa (tips) descending from each node.""" cdef Py_ssize_t i, node, lft for i in range(n - 1, -1, -1): node = order[i] if lft := tree[node, 0]: tacts[node] = tacts[lft] + tacts[tree[node, 1]] else: tacts[node] = 1 def _calc_sizes( Py_ssize_t n, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] sizes, ): """Calculate the number of nodes within each clade (including root). NOTE: size = tact * 2 - 1 """ cdef Py_ssize_t i, node, lft for i in range(n - 1, -1, -1): node = order[i] if lft := tree[node, 0]: sizes[node] = sizes[lft] + sizes[tree[node, 1]] + 1 else: sizes[node] = 1 def _calc_deeps( Py_ssize_t n, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] deeps, ): """Calculate the number of branches from root to each node (i.e., depth).""" cdef Py_ssize_t i, node deeps[0] = 0 # root for i in range(1, n): node = order[i] deeps[node] = deeps[tree[node, 2]] + 1 def _calc_pairs( Py_ssize_t n, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] sizes, Py_ssize_t[::1] pairs, ): """Calculate the number of ancestor-descendant pairs within each clade. This function is executed after completing the serial phase and before entering the parallel phase. The `pairs` array is useful in the distribution of workloads across threads. It can be updated accumulatively as the tree grows. This function merely creates the initial status. Additionally, this function is useful for test purpose. The total number of ancestor-descendant pairs equals to the sum of depths of nodes within a clade. """ cdef Py_ssize_t i, a, lft, rgt for i in range(n - 1, -1, -1): # traverse tree in reverse preorder a = order[i] if lft := tree[a, 0]: rgt = tree[a, 1] pairs[a] = pairs[lft] + pairs[rgt] + sizes[lft] + sizes[rgt] else: pairs[a] = 0 def _bal_insert_plan( Py_ssize_t n, Py_ssize_t itag, floating[:, ::1] adm, floating[:, ::1] adk, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] sizes, Py_ssize_t[::1] deeps, Py_ssize_t[::1] pairs, floating[::1] diffs, Py_ssize_t[::1] ancs, Py_ssize_t[::1] ancx, Py_ssize_t[::1] segs, Py_ssize_t[::1] lvls, Py_ssize_t[::1] oops, bint flat=True, ): r"""Update balanced average distance matrix after taxon insertion. This function resembles `_bal_avgdist_insert` but it doesn't involve the nested for loops to calculate the distances between subtree pairs, which is the dominant part of the algorithm (between O(nlogn) and O(n^2)). Instead, it merely identifies these pairs for subsequent parallel calculation. To do so, it navigates from the target node upward to the root, marking ancestor and cousin nodes, which indicate "segments" of the preorder with the same degree from the insertion site, thus defining the behavior of the nested calculations in each segment. Optionally, it calculates the distance between each node and the special nodes (new taxon, link, target), which is O(n). In phase 2 (see `_bme`), this is enabled, but in phase 3 this is disabled and deferred to a separate parallel function. *** It is easy to know that there can be no more than n segments (when every node is its own segment). The actual bounds are: - min. = deep - 1 When all ancestors are right children of their parents, such that their left cousins do not need to be marked. - max. = deep * 2 - 1 When all ancestors are left children, and their right cousins are marked. When the tree is extremely skewed and all ancestors are left children, there will be n - 2 segments, because target's parent always has 3 children and they are the same segment. Therefore, filling index n_segs to mark the end of the segment array is safe. *** An example of the scheme: description : root anc3 anc2 anc1 anc0 target rcuz1 rcuz3 n depth : 0 1 2 3 4 5 4 2 segment : 0 5 12 19 31 42 65 73 100 level : 4 3 2 1 0 -1 1 3 ancestor : 4 3 2 1 0 """ cdef Py_ssize_t a cdef Py_ssize_t tag = order[itag] cdef Py_ssize_t lnk = n cdef Py_ssize_t kay = n + 1 cdef Py_ssize_t par = tree[tag, 2] cdef Py_ssize_t sib = tree[tag, 3] cdef Py_ssize_t cur cdef Py_ssize_t anc cdef Py_ssize_t cuz cdef Py_ssize_t lft cdef Py_ssize_t i cdef Py_ssize_t icur, ianc, icuz cdef Py_ssize_t lvl cdef Py_ssize_t size = sizes[tag] cdef Py_ssize_t s_cuz cdef Py_ssize_t deep = deeps[tag] cdef Py_ssize_t pair = pairs[tag] cdef floating cell, diff cdef floating* adkl = &adk[0, 0] cdef floating* adku = &adk[1, 0] cdef floating* adm_t = &adm[tag, 0] cdef floating* adm_l = &adm[lnk, 0] cdef floating* adm_k = &adm[kay, 0] cdef floating* adm_r cdef floating* adm_a cdef Py_ssize_t stride = adm.shape[1] # Accumulative number of horizontal operations to be assigned to each node in the # spine. This number += (cousin size + 1) * (level - 1) at each node. cdef Py_ssize_t achori # Accumulative number of vertical operations to be subtracted from each node in the # spine. This number += (size - 1) at each node. cdef Py_ssize_t acvert # Left and right indices in the segment array. Ancestors are appended to the left # side of the array. Right cousins are appended to the right side. cdef Py_ssize_t li, ri sizes[kay] = 1 pairs[kay] = 0 ###### Special case: insert into the root branch. ###### if itag == 0: sizes[0] = n + 2 sizes[lnk] = n deeps[lnk] = deeps[kay] = 1 # update pairs pairs[lnk] = pair pairs[0] += size + 1 # There is only one segment, which is the entire tree. segs[0] = 0 segs[1] = n lvls[0] = 0 # workload of entire tree (see below). oops[0] = pair - size + 1 adm_t[kay] = adku[0] adm_l[kay] = adkl[0] adm_t[lnk] = 0.5 * (adm_t[tree[0, 0]] + adm_t[tree[0, 1]]) # Unlike the serial version, order is not important here. if flat: for i in range(1, n): a = order[i] diff, cell = adkl[a], adm_t[a] adm[a, kay] = diff adm_l[a] = 0.5 * (diff + cell) diffs[i] = diff - cell deeps[a] += 1 # this +1 here is important; it cannot be postponed to `_insert_taxon` # TODO: double-check the maths return ###### Regular case: insert into any other branch. ###### sizes[lnk] = size + 2 deeps[lnk] = deep deeps[kay] = deeps[tag] = deep + 1 # Pairs of link = pairs of target clade + size of clade (vs. each node) + 1 (k) pairs[lnk] = pair + size + 1 # Initiate accumulative horizontal and vertical operations. achori = 0 acvert = size - 1 # Depth equals to the number of ancestors of target. Therefore, target is placed at # index = deep in the list of segment. segs[deep] = itag lvls[deep] = 0 li = deep - 1 ri = deep + 1 # Target clade workload = number of pairs - (number of nodes - 1). This is because # target node itself is not involved in calculation. oops[deep] = pair - acvert ### Step 1: Distances around the insertion point. ### adm_l[kay] = adku[tag] cell = adm_t[sib] if tree[par, 0] == tag else adm[sib, tag] adm_l[tag] = 0.5 * (cell + adm[par, tag]) adm_t[kay] = adkl[tag] ### Step 2: Distances within the clade below target. ### if flat: for i in range(itag + 1, itag + size): a = order[i] diff, cell = adkl[a], adm_t[a] adm[a, kay] = diff adm_l[a] = cell adm_t[a] = 0.5 * (diff + cell) diffs[i] = diff - cell deeps[a] += 1 ### Step 3: Distances among nodes outside the clade. ### lvl = 0 icur = itag while icur: cur = order[icur] ancs[lvl] = anc = tree[cur, 2] ancx[lvl] = stride * anc # Current is left, cousin is right if (lft := tree[anc, 0]) == cur: ianc = icur - 1 icuz = icur + sizes[cur] cuz = order[icuz] s_cuz = sizes[cuz] # Add right cousin to segments, on the right side of target. segs[ri] = icuz lvls[ri] = lvl oops[ri] = s_cuz * lvl + pairs[cuz] ri += 1 # TODO: ops of right cousins is the same as that of regular nodes. Can this # be skipped? if flat: for i in range(icuz, icuz + s_cuz): a = order[i] adm_a = &adm[a, 0] diff, cell = adkl[a], adm_t[a] adm_k[a] = diff adm_l[a] = 0.5 * (diff + cell) diffs[i] = diff - cell # Cousin is left, current is right. else: icuz = icur - sizes[lft] ianc = icuz - 1 cuz = order[icuz] s_cuz = sizes[cuz] if flat: for i in range(icuz, icuz + s_cuz): a = order[i] adm_a = &adm[a, 0] diff, cell = adkl[a], adm_a[tag] adm_a[kay] = diff adm_a[lnk] = 0.5 * (diff + cell) diffs[i] = diff - cell # Update ancestor node in the end (because we need `anc_i`). if flat: adm_r = &adm[anc, 0] diff, cell = adku[anc], adm_r[tag] adm_r[kay] = diff adm_r[lnk] = 0.5 * (diff + cell) diffs[ianc] = diff - cell # Transfer upper distance to lower distance, which will be utilized later. else: adkl[anc] = adku[anc] # Update accumulative size and pair. # +1 because the ancestor itself is added to the clade. achori += (s_cuz + 1) * lvl # -1 because only descendants but not the clade root are counted. acvert += sizes[anc] - 1 # Add ancestor to segments, on the left side of target. segs[li] = ianc lvls[li] = lvl oops[li] = achori + pairs[anc] - acvert li -= 1 icur = ianc lvl += 1 # Seal the segment array. # NOTE: Otherwise, since `segs` is reused across iterations, a later iteration may # have fewer segments than a previous one, and the remnant indices in the previous # `segs` could confuse. `n` is a value that indices will never reach, thus safe. segs[ri] = n def _bal_avgdist_chunk( Py_ssize_t n, Py_ssize_t itag, Py_ssize_t[::1] order, Py_ssize_t[::1] sizes, Py_ssize_t[::1] pairs, Py_ssize_t[::1] segs, Py_ssize_t[::1] lvls, Py_ssize_t[::1] oops, Py_ssize_t enc, Py_ssize_t[::1] chunks, Py_ssize_t[::1] chusegs, ): """Partition tree into chunks of nodes with roughly even workloads. This function traverses the tree in preorder and iteratively puts single nodes or the entire clade under each node into chunks with a fixed upper limit of workload (number of operations). Specifically, it puts a clade into a chunk when there is sufficient space left to hold it. Otherwise, it decomposes the clade into smaller clades or nodes and tries to put them in subsequent iterations. There are two types of workloads: 1. "Vertical": Ancestor (upper) - descendant (lower) pairs. Applies to all nodes except for target and it ancestors. For each node, the workload is the number of nodes descending from it, i.e., n - 1. For each clade, the workload is the total number of ancestor-descendant pairs, which is equal to the sum of depths of all nodes. This number varies between O(nlogn) (balanced tree) and O(n^2) (skewed tree). An incrementally updated array, `pairs`, stores these numbers. 2. "Horizontal": direct relative (lower) - cousin (lower) pairs. Applies to all nodes outside the clade descending from target's parent. For each node, the workload is the number of more recent ancestors descending from the ancestor shared with target. This value is stored in `lvls`. For each clade, the workload is the number of nodes times `gen`. Workloads of segment clades are special and cannot be calculated using the above rules. The array `oops` stores the correct values. *** Because the workload of a clade can be calculated without traversing it, the code can "leap" to the next clade when it determines that the current clade can fit into a chunk without further decomposing it. Therefore, this function is between O(1) (entire tree is a chunk) and O(n) (each node is a chunk). *** Although each chunk has a fixed capacity. The actual workload per chunk can vary below or above this capacity. Specifically: 1. When the current chunk still has room but the current node cannot fit into it, the chunk will be closed and the remaining room won't be utilized. This is the most common scenario. 2. When a single node has a large workload that exceeds the chunk capacity, it will be forced to occupy one chunk. This is because each node is the minimum unit of parallelization, and cannot further break down. This scenario is rare but could happen in theory. """ cdef Py_ssize_t node cdef Py_ssize_t size # number of nodes within each clade # workload (number of operations) per node and per clade (subtree) cdef Py_ssize_t node_ops, tree_ops # Calculate chunk capacity. Total workload of the tree is `oops[0]`. A ceiling # division is performed to divide it into `enc` number of chunks. cdef Py_ssize_t capacity = max(1, (oops[0] + enc - 1) // enc) ### Initialization: Create the first chunk, and put the first node (root) in it. # chunks[0] = 0 # current chunk index (done already) # chusegs[0] = 0 # segment index when current chunk starts (done) cdef Py_ssize_t i = 1 # current node index cdef Py_ssize_t nchu = 1 # current number of chunks cdef Py_ssize_t iseg = 1 # next segment index cdef Py_ssize_t seg = segs[1] # next segment start (node) cdef Py_ssize_t lvl = lvls[0] # current segment's level cdef Py_ssize_t space = capacity - lvl # remaining space of current chunk while i < n: node = order[i] size = sizes[node] ### Calculate workload per node & clade. ### # entering a new segment if i == seg: lvl = lvls[iseg] # when segment start is target or an ancestor of it if i <= itag: node_ops = lvl tree_ops = oops[iseg] # when segment start is a right cousin else: node_ops = size + lvl - 1 tree_ops = pairs[node] + size * lvl # regular scenario (same as right cousin) else: node_ops = size + lvl - 1 tree_ops = pairs[node] + size * lvl ### Put workload into a chunk. ### # put whole clade (and leap to next clade) if tree_ops <= space: space -= tree_ops i += size # put node only, and decompose elif node_ops <= space: space -= node_ops i += 1 # not enough space; has to create a new chunk else: chunks[nchu] = i chusegs[nchu] = iseg nchu += 1 # put whole clade to next chunk if tree_ops <= capacity: space = capacity - tree_ops i += size # put node to next chunk and decompose else: space = capacity - node_ops i += 1 ### Locate next segment start. ### # This loop is necessary only when: 1) current node is an ancestor of target, # otherwise the entire clade should not cross segments. 2) the whole clade was # leaped over, otherwise node index only +1, and one doesn't need a loop to # find the next segment. However, having another `if` switch here may not # increase performance. # This task can be more efficiently achieved with a binary tree search, through # the `bisect` module or code from scratch. However, it is anticipated that the # next segment is relatively close to the current node. So this optimization # may not be necessary. # TODO: Revisit later. while seg < i: iseg += 1 seg = segs[iseg] lvl = lvls[iseg - 1] chunks[nchu] = n # upper bound of last chunk return nchu def _bal_update_spine( Py_ssize_t tag, Py_ssize_t deep, Py_ssize_t[::1] sizes, Py_ssize_t[::1] pairs, Py_ssize_t[::1] ancs, ): """Update size and pair of ancestors of target. Each ancestor's size +2 because link and kay are added. Its pair += size of target clade (link to target clade) + 1 (link to kay) + 2 * (level + 1) (this and each previous ancestor to link). This trivial function has to be executed after chunking and before filling. """ cdef Py_ssize_t i cdef Py_ssize_t size_3 = sizes[tag] + 3 for i in range(deep): anc = ancs[i] sizes[anc] += 2 pairs[anc] += size_3 + 2 * i def _bal_avgdist_flat( Py_ssize_t n, Py_ssize_t itag, Py_ssize_t size, Py_ssize_t[::1] order, floating[:, ::1] adm, floating[:, ::1] adk, floating[::1] diffs, Py_ssize_t[::1] deeps, ): r"""Update balanced average distances through a flat loop. This function traverses the tree once and updates the distances between each node and several special nodes (target, link, and new taxon). It also calculates an intermediate variable, which must be completed before entering the nexted loop. This function is O(n), therefore less costly than `_bal_avgdist_nest`. It is only beneficial when the tree is sufficiently large (e.g., over 10k taxa). """ cdef Py_ssize_t i, a cdef Py_ssize_t tag = order[itag] cdef Py_ssize_t lnk = n cdef Py_ssize_t kay = n + 1 cdef Py_ssize_t iaft = itag + size cdef floating* adkl = &adk[0, 0] cdef floating diff, cell cdef floating* adm_t = &adm[tag, 0] cdef floating* adm_l = &adm[lnk, 0] cdef floating* adm_k = &adm[kay, 0] cdef floating* adm_a # special case if itag == 0: for i in prange(1, n, nogil=True): a = order[i] diff = adkl[a] cell = adm_t[a] adm[a, kay] = diff adm_l[a] = 0.5 * (diff + cell) diffs[i] = diff - cell deeps[a] += 1 # regular case else: for i in prange(n, nogil=True): a = order[i] diff = adkl[a] # before target clade (ancestors and left cousins) if i < itag: adm_a = &adm[a, 0] cell = adm_a[tag] adm_a[kay] = diff adm_a[lnk] = 0.5 * (diff + cell) diffs[i] = diff - cell # skip target elif i > itag: cell = adm_t[a] # within target clade if i < iaft: adm[a, kay] = diff adm_l[a] = cell adm_t[a] = 0.5 * (diff + cell) deeps[a] += 1 # after target clade (right cousins) else: adm_k[a] = diff adm_l[a] = 0.5 * (diff + cell) diffs[i] = diff - cell def _bal_avgdist_nest( Py_ssize_t itag, Py_ssize_t deep, floating[:, ::1] adm, Py_ssize_t[::1] order, Py_ssize_t[::1] sizes, Py_ssize_t[::1] deeps, floating[::1] diffs, floating[::1] npots, Py_ssize_t[::1] ancs, Py_ssize_t[::1] ancx, Py_ssize_t[::1] segs, Py_ssize_t[::1] lvls, Py_ssize_t nchu, Py_ssize_t[::1] chunks, Py_ssize_t[::1] chusegs, ): r"""Update balanced average distances through nested loops. This function is the dominant part of the entire BME algorithm, It is between O(nlogn) and O(n^2). Therefore parallelization is desired. """ cdef Py_ssize_t a # nodes as in tree cdef Py_ssize_t i, j # nodes as in order cdef Py_ssize_t size cdef Py_ssize_t dep2 = deep - 2 # intermediate cdef Py_ssize_t ichu # chunk index cdef Py_ssize_t iseg # segment index cdef Py_ssize_t seg # segment bound cdef floating diff cdef floating* adm_0 = &adm[0, 0] cdef floating* adm_a cdef floating* npots_2 = &npots[2] # number of branches from insertion point to shared ancestor cdef Py_ssize_t lvl # number of branches from insertion point to any node cdef Py_ssize_t deg for ichu in prange(nchu, nogil=True, schedule="dynamic"): iseg = chusegs[ichu] # next segment index seg = segs[iseg] lvl = lvls[iseg - 1] if iseg else -1 # current segment's level deg = 2 * lvl - dep2 for i in range(chunks[ichu], chunks[ichu + 1]): a = order[i] adm_a = &adm[a, 0] diff = diffs[i] # Current node is at or before target in preorder. This means two things: # 1) It is before any ancestor lower than the ancestor shared between it # and target. Therefore, the horizontally filled cell coordinates must # be [a, anc]. # 2) Every segment start it encounters is target or an ancestor, which are # skipped during vertical filling. # This `if` would cost little compute due to branch prediction. if i <= itag: if i == seg: lvl = lvls[iseg] # NOTE: This cannot be written as `iseg += 1`, otherwise Cython # will complain: "Cannot read reduction variable in loop body." iseg = iseg + 1 seg = segs[iseg] deg = 2 * lvl - dep2 # If not in spine, trigger vertical fill. # NOTE: This `if` isn't good for branch prediction because tips (size # = 1) are frequent. But removing `if` will add two array reads. Test # suggests keeping the current code is fine. elif (size := sizes[a]) > 1: npot = npots[deeps[a] + deg] for j in range(i + 1, i + size): adm_a[order[j]] += npot * diffs[j] # horizontal fill is guaranteed for j in range(lvl): adm_a[ancs[j]] += npots_2[j] * diff # adm_a[ancs[j]] += ldexp(diff, -2 - j) # Current node is after target. This means: 1) Horizontal Cell coordinates # are [anc, a]. 2) Segment starts are right cousins. else: if i == seg: lvl = lvls[iseg] iseg = iseg + 1 seg = segs[iseg] deg = 2 * lvl - dep2 # both fills are guaranteed if (size := sizes[a]) > 1: npot = npots[deeps[a] + deg] for j in range(i + 1, i + size): adm_a[order[j]] += npot * diffs[j] for j in range(lvl): adm_0[ancx[j] + a] += npots_2[j] * diff # adm_0[ancx[j] + a] += ldexp(diff, -2 - j) def _insert_taxon( Py_ssize_t taxon, Py_ssize_t itag, Py_ssize_t size, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] preodr, ): r"""Insert a taxon between a target node and its parent. For example, with the following local structure of the original tree: A / \ B C With target=B, this function inserts a taxon into the branch A-B. The structure becomes: A / \ link C / \ B taxon The link and taxon will be appended to the end of the tree array, but the pre- and postorders need to be muted such that new nodes can be inserted. Specifically: Preorder: A - B - C => A - link - B - taxon - C Postorder: B - C - A => B - taxon - link - C - A A special case is that the taxon is inserted into the root branch (node=0). The tree becomes: A / \ link taxon / \ B C The inserted taxon always becomes the right child. *** This function only maintains preorder in addition to tree topology, as this is sufficient for algorithms in this module. Comments are included on maintaining preorder index, postorder, and postorder index. """ cdef Py_ssize_t lft, rgt, par, sib cdef Py_ssize_t side # determine tree dimensions cdef Py_ssize_t m = taxon - 1 cdef Py_ssize_t n = m * 2 - 1 cdef Py_ssize_t lnk = n cdef Py_ssize_t kay = n + 1 # target node as in tree cdef Py_ssize_t tag = preodr[itag] # preorder index immediately after target clade cdef Py_ssize_t iaft = itag + size cdef Py_ssize_t* node cdef size_t intsize = sizeof(Py_ssize_t) # Special case (root branch): taxon k becomes the sibling of all existing taxa # except for the root (taxon 0). if tag == 0: node = &tree[0, 0] # children lft, rgt = node[0], node[1] tree[lft, 2] = tree[rgt, 2] = lnk # root node[0] = lnk node[1] = kay # link node = &tree[lnk, 0] node[0] = lft node[1] = rgt node[2] = 0 node[3] = kay # taxon node = &tree[kay, 0] node[0] = 0 node[1] = taxon node[2] = 0 node[3] = lnk # preorder memmove(&preodr[2], &preodr[1], ((n - 1) * intsize)) # the above line can be replaced with (but slower): # for i in range(1, n): # preodr[i + 1] = preodr[i] # if both preodr and preidx are involved: # for i in range(n - 1, 0, -1): # preidx[i] += 1 # preodr[i + 1] = preodr[i] preodr[1] = lnk preodr[n + 1] = kay # preidx[lnk] = 1 # preidx[kay] = n + 1 # postorder # posodr[n - 1] = link # posodr[n] = kay # posodr[n + 1] = 0 # posidx[lnk] = n - 1 # posidx[kay] = n # Regular case (any other branch): The link becomes the parent of the target node, # and child of its original parent. Taxon k becomes the sibling else: node = &tree[tag, 0] lft = node[0] rgt = node[1] par = node[2] sib = node[3] side = int(tree[par, 0] != tag) tree[par, side] = lnk tree[sib, 3] = lnk node[2] = lnk node[3] = kay # link node = &tree[lnk, 0] node[0] = tag node[1] = kay node[2] = par node[3] = sib # taxon node = &tree[kay, 0] node[0] = 0 node[1] = taxon node[2] = lnk node[3] = tag # preorder shift: nodes after clade +2, tip inserted after clade, nodes within # clade +1, link inserted before clade memmove(&preodr[iaft + 2], &preodr[iaft], ( (n - iaft) * intsize )) # or: # for i in range(iaft, n): # preodr[i + 2] = preodr[i] # or: # for i in range(n - 1, iaft - 1, -1): # k = preodr[i] # preidx[k] += 2 # preodr[i + 2] = k preodr[iaft + 1] = kay # preidx[kay] = iaft + 1 memmove(&preodr[itag + 1], &preodr[itag], ( (iaft - itag) * intsize )) # or: # for i in range(itag, iaft): # preodr[i + 1] = preodr[i] # or: # for i in range(iaft - 1, itag - 1, -1): # k = order[i] # preidx[k] += 1 # preodr[i + 1] = k preodr[itag] = lnk # preidx[lnk] = itag # postorder shift: all nodes after clade +2, tip and link inserted after clade # post_i = posidx[tag] # posidx[lnk] = post_i + 2 # posidx[kay] = post_i + 1 # for i in range(n - 1, post_i, -1): # k = posodr[i] # posidx[k] += 2 # posodr[i + 2] = k # posodr[post_i + 2] = lnk # posodr[post_i + 1] = kay def _avgdist_swap( Py_ssize_t itag, Py_ssize_t side, floating[:, ::1] adm, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] tacts, ): r"""Update average distance matrix after branch swapping. This function will update adm, a float array of (n, n) representing pairwise distances between all subtrees in the tree. It assumes that one child of the target node on a certain side (left: 0, right: 1) exchanges position with the sibling of the target: | | parent parent / \ / \ target sibling => target child / \ / \ other child other sibling Two categories of average distances will be updated: 1. From target (upper) to any node within other and sibling. 2. From target (lower) to any node within parent and child. Only target to itself doesn't need to be updated. All other nodes in the tree do. This function should be executed *after* calling :func:`_swap_branches`. Implemented according to A4.3(b) of Desper and Gascuel (2002). """ cdef Py_ssize_t i, node # total numbers of taxa and nodes in the tree cdef Py_ssize_t m = tacts[0] + 1 cdef Py_ssize_t n = 2 * m - 3 # target node cdef Py_ssize_t target = order[itag] # the two branches that were swapped cdef Py_ssize_t child = tree[target, 3] # former child, now sibling cdef Py_ssize_t sibling = tree[target, side] # former sibling, now child # the two branches that stay still cdef Py_ssize_t other = tree[target, 1 - side] # the other child cdef Py_ssize_t parent = tree[target, 2] # the parent cdef Py_ssize_t c_size = tacts[child] cdef Py_ssize_t o_size = tacts[other] cdef Py_ssize_t s_size = tacts[sibling] cdef Py_ssize_t p_size = m - tacts[parent] cdef Py_ssize_t so_size = s_size + o_size cdef Py_ssize_t cp_size = c_size + p_size # Loop over all nodes except for target. These nodes can be divided into ones # within the clade below target (former sibling and other), and ones that are # outside the clade (former child and parent). Their distances to the target will # be updated separately. cdef Py_ssize_t iaft = itag + tacts[target] * 2 - 1 # 1) subtrees within (parent, child) vs sibling (lower) + other (lower) for i in range(itag): node = order[i] adm[node, target] = adm[target, node] = ( s_size * adm[node, sibling] + o_size * adm[node, other] ) / so_size # 2) # subtrees within (sibling, other) vs parent (upper) + child (lower) for i in range(itag + 1, iaft): node = order[i] adm[node, target] = adm[target, node] = ( p_size * adm[node, parent] + c_size * adm[node, child] ) / cp_size # 3) same as 1) for i in range(iaft, n): node = order[i] adm[node, target] = adm[target, node] = ( s_size * adm[node, sibling] + o_size * adm[node, other] ) / so_size # cdef floating temp_val = adm[target, target] # for i in range(n): # node = order[i] # # subtrees within (sibling, other) vs parent (upper) + child (lower) # if itag < i < iaft: # adm[node, target] = adm[target, node] = ( # p_size * adm[node, parent] + c_size * adm[node, child] # ) / (c_size + p_size) # # subtrees within (parent, child) vs sibling (lower) + other (lower) # else: # adm[node, target] = adm[target, node] = ( # s_size * adm[node, sibling] + o_size * adm[node, other] # ) / (s_size + o_size) # # this cell doesn't need to be filled and let's reset it # adm[target, target] = temp_val def _bal_avgdist_swap( floating[:, ::1] adm, Py_ssize_t target, Py_ssize_t side, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] order, Py_ssize_t[::1] index, Py_ssize_t[::1] sizes, Py_ssize_t[::1] deeps, floating[::1] npots, Py_ssize_t[::1] stack, ): r"""Update balanced average distance matrix after branch swapping. This function resembles :func:`_avgdist_swap`, but it uses a balanced framework. Specifically, it follows Eq. 18 and Appendix 5.3 of Desper and Gascuel (2002). This function is the dominant term of the entire BNNI algorithm. """ cdef Py_ssize_t node, curr, before, after, cousin, a, b cdef Py_ssize_t i, j, ii, anc_i, start, end cdef Py_ssize_t deep, dep2, depd cdef floating npot, diff cdef Py_ssize_t n = sizes[0] cdef Py_ssize_t child = tree[target, 3] cdef Py_ssize_t sibling = tree[target, side] cdef Py_ssize_t other = tree[target, 1 - side] cdef Py_ssize_t parent = tree[target, 2] cdef floating* adm_a # Step 1: Update distances between subtrees within each of the four clades (Eq. 18 # and A5.3(a)). # 1.1: Work on the three downward clades rooted at sibling, child, and other. For # each of them, identify their neighbor (i.e., the other clade on the same side of # the target branch) before and after swapping. cdef Py_ssize_t[9] arr arr[0], arr[1], arr[2] = sibling, parent, other arr[3], arr[4], arr[5] = child, other, parent arr[6], arr[7], arr[8] = other, child, sibling for i in range(0, 9, 3): curr, before, after = arr[i], arr[i + 1], arr[i + 2] deep = deeps[curr] dep2 = deep - 2 ii = index[curr] for i in range(ii, ii + sizes[curr]): a = order[i] npot = npots[deeps[a] - dep2] adm_a = &adm[a, 0] for j in range(i + 1, i + sizes[a]): b = order[j] adm_a[b] = adm[b, a] = adm_a[b] - npot * ( adm[b, before] - adm[b, after] ) # 1.2: Work on the upward clade rooted at the parent node. The process is similar # to that in `_bal_avgdist_insert`. Basically, we will consider three categories of # distances: # - previous ancestor vs. current ancestor # - previous & current ancestor vs. cousin or its descendant # - cousin or its descendant vs. descendant of the former before, after = sibling, child deep = deeps[parent] dep2 = deep + 2 # iterate over ancestors of the target node, starting from its parent anc_i = 0 curr = parent while True: stack[anc_i] = curr depd = dep2 - 2 * deeps[curr] + 1 # each previous ancestor vs. current ancestor diff = adm[curr, before] - adm[curr, after] for i in range(anc_i): a = stack[i] adm[curr, a] = adm[a, curr] = adm[curr, a] - npots[i + 2] * diff if not curr: break anc_i += 1 # iterate over nodes within each cousin clade (cousin and its descendants) cousin = tree[curr, 3] ii = index[cousin] for i in range(ii, ii + sizes[cousin]): a = order[i] adm_a = &adm[a, 0] # each previous & current ancestor vs. current node diff = adm[a, before] - adm[a, after] for j in range(anc_i): b = stack[j] adm_a[b] = adm[b, a] = adm_a[b] - npots[j + 2] * diff # current node vs. each descendant npot = npots[depd + deeps[a]] #### trick for j in range(i + 1, i + sizes[a]): b = order[j] adm_a[b] = adm[b, a] = adm_a[b] - npot * ( adm[b, before] - adm[b, after] ) curr = tree[curr, 2] # Step 2: Update distances between subtrees within each side of the target branch # and the other end of the branch (A5.3(b)). start = index[target] end = start + sizes[target] for i in range(start): node = order[i] adm[node, target] = adm[target, node] = 0.5 * ( adm[node, sibling] + adm[node, other] ) for i in range(start + 1, end): node = order[i] adm[node, target] = adm[target, node] = 0.5 * ( adm[node, parent] + adm[node, child] ) for i in range(end, n): node = order[i] adm[node, target] = adm[target, node] = 0.5 * ( adm[node, sibling] + adm[node, other] ) # Step 3: Update the distance between the lower and upper subtrees of the target # node itself (A5.3(c)). # This step is omitted as we will not fill the diagonal of the matrix (i.e., the # distance between the lower and upper subtree of the same node). See `_avgdist_ # matrix`. # adm[target, target] = 0.25 * ( # adm[parent, sibling] # + adm[parent, other] # + adm[child, sibling] # + adm[child, other] # ) cdef void _ols_swap( floating* L, Py_ssize_t* side, Py_ssize_t p_size, Py_ssize_t s_size, Py_ssize_t l_size, Py_ssize_t r_size, floating ad_before, floating ad_left, floating ad_right, ) noexcept nogil: r"""Calculate the change in overall tree length after a given swap. In a given quartet AB|CD, the swap takes place between subtrees B and C. The decrease of overall branch length, delta L (larger is better), can be calculated according to Eq. 9 of Desper and Gascuel (2002): delta L = ((lambda - 1)(d(A, C) + d(B, D)) - (lambda' - 1)(d(A, B) + d(C, D)) - (lambda - lambda')(d(A, D) + d(B, C))) / 2 Where: lambda = (|A||D| + |B||C|) / ((|A| + |B|)(|C| + |D|)) lambda' = (|A||D| + |B||C|) / ((|A| + |C|)(|B| + |D|)) This function calculates delta L for two scenarios: 1) swap between left child and sibling, and 2) swap between right child and sibling. These two calculations share some steps, which are exploited by the following code. Factor 0.5 (/2) is omitted. The output value is negated, in order to match Python's minheap data structure (smallest popped first). Then the smaller change if negative is retained, according to A4.2. """ cdef Py_ssize_t size_0 = p_size * s_size + l_size * r_size cdef Py_ssize_t size_1 = p_size * r_size + s_size * l_size cdef Py_ssize_t size_2 = p_size * l_size + s_size * r_size cdef floating ad_bl = ad_before - ad_left cdef floating ad_br = ad_before - ad_right cdef floating ad_lr_size = (ad_left - ad_right) / (size_1 + size_2) cdef floating L1 = size_1 * (ad_br / (size_0 + size_1) - ad_lr_size) - ad_bl cdef floating L2 = size_2 * (ad_bl / (size_0 + size_2) + ad_lr_size) - ad_br if L1 >= 0 and L2 >= 0: L[0] = 0 elif L1 <= L2: L[0] = L1 side[0] = 0 else: L[0] = L2 side[0] = 1 def _ols_all_swaps( floating[::1] lens, floating[:, ::1] adm, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] tacts, Py_ssize_t[::1] sides, ): r"""Evaluate all possible swaps at all internal branches of a tree. Using an OLS framework. The results (length change, smaller is better) are saved to `lens`. The child side of each node that achieves this length change is saved to column 7 of the tree. Implemented according to A4.2(a) of Desper and Gascuel (2002). """ cdef Py_ssize_t m = tacts[0] + 1 cdef Py_ssize_t node, left, right, parent, sibling # root is zero lens[0] = 0 # calculate on internal branches (nodes with children) for node in range(1, tree.shape[0]): if tree[node, 0]: left = tree[node, 0] right = tree[node, 1] parent = tree[node, 2] sibling = tree[node, 3] # calculate length change _ols_swap( &lens[node], &sides[node], m - tacts[parent], tacts[sibling], tacts[left], tacts[right], adm[parent, sibling] + adm[left, right], adm[parent, left] + adm[sibling, right], adm[parent, right] + adm[sibling, left], ) # tips are zero else: lens[node] = 0 def _ols_corner_swaps( Py_ssize_t target, list heap, floating[::1] lens, floating[:, ::1] adm, Py_ssize_t[:, ::1] tree, Py_ssize_t[::1] tacts, Py_ssize_t[::1] sides, ): r"""Update swaps of the four corner branches of a swapped branch. Using an OLS framework. Specifically, the four corner branches concern all nodes illustrated below. | x / \ parent x / \ target sibling / \ / \ left right x x / \ / \ x x x x Implemented according to A4.2(c) of Desper and Gascuel (2002). """ cdef Py_ssize_t m = tacts[0] + 1 cdef Py_ssize_t i, left, right, parent, sibling # update four corner branches if they are internal # 0: left, 1: right, 2: parent, 3: sibling # for 0, 1, 3, check left child; for 2, check parent for i in range(4): node = tree[target, i] if (node if i == 2 else tree[node, 0]): left = tree[node, 0] right = tree[node, 1] parent = tree[node, 2] sibling = tree[node, 3] # calculate length change _ols_swap( &lens[node], &sides[node], m - tacts[parent], tacts[sibling], tacts[left], tacts[right], adm[parent, sibling] + adm[left, right], adm[parent, left] + adm[sibling, right], adm[parent, right] + adm[sibling, left], ) # if length is reduced, push the swap into heap # TODO: arithmetic error can cause increase? if lens[node]: heappush(heap, (lens[node], node, sides[node])) def _bal_all_swaps( floating[::1] gains, Py_ssize_t[::1] sides, Py_ssize_t[::1] nodes, floating[:, ::1] adm, Py_ssize_t[:, ::1] tree, ): r"""Evaluate possible swaps at all internal branches of a tree. Using a balanced framework. Implemented according to Eq. 12 and A4.2(a) of Desper and Gascuel (2002). \delta L = ((d(A, B) + d(C, D)) - (d(A, C) + d(B, D))) / 4 Larger and positive \delta L is favored. Factor 0.25 (/4) is omitted in the calculation. `lens` should be initiated with zeros, because root and tips are assigned zeros automatically and are skipped during the iteration. """ cdef Py_ssize_t branch, node, left, right, parent, sibling cdef floating L1, L2, Lcomm for branch in range(nodes.shape[0]): node = nodes[branch] left = tree[node, 0] if not left: continue right, parent, sibling = tree[node, 1], tree[node, 2], tree[node, 3] Lcomm = adm[parent, sibling] + adm[left, right] L1 = adm[parent, left] + adm[sibling, right] L2 = adm[parent, right] + adm[sibling, left] if L1 >= Lcomm and L2 >= Lcomm: gains[branch] = 0 elif L1 <= L2: gains[branch], sides[branch] = Lcomm - L1, 0 else: gains[branch], sides[branch] = Lcomm - L2, 1 scikit-bio-scikit-bio-a3beaa6/skbio/tree/_c_nj.pyx000066400000000000000000000040321520735541300222320ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # cython: language_level=3, boundscheck=False, wraparound=False, cdivision=True from cython cimport floating from libc.math cimport INFINITY def nj_minq_cy(floating[:, :] dm, floating[::1] sums): r"""Find the minimum value in a Q-matrix during the NJ algorithm. Parameters ---------- dm : (N, N) ndarray Distance matrix. sums : (N,) ndarray Distance sum vector. Returns ------- (int, int) Row and column indices of the minimum value. See Also -------- skbio.tree.nj Notes ----- The agglomerative clustering algorithm neighbor joining (NJ) involves converting the original distance matrix into a "Q-matrix" and finding the location of the minimum _q_ value in the matrix. .. math:: Q(i, j) = (n - 2) d(i, j) - \sum d(i) - \sum d(j) This function calculates _q_ values and finds the minimum as the calculation goes, and avoids creating the entire Q-matrix, thereby saving compute. """ cdef Py_ssize_t n = dm.shape[0] cdef Py_ssize_t i, j cdef floating n_2 = n - 2.0 # current minimum q value and its location cdef Py_ssize_t min_i, min_j cdef floating min_q = INFINITY # current q value and minimum q value plus \sum d(i) cdef floating q_plus, min_q_plus # loop the upper-right triangle of the distance matrix # i < j is guaranteed for i in range(n): min_q_plus = min_q + sums[i] for j in range(i + 1, n): q_plus = dm[i, j] * n_2 - sums[j] if q_plus < min_q_plus: min_q_plus = q_plus min_q = q_plus - sums[i] min_i, min_j = i, j return min_i, min_j scikit-bio-scikit-bio-a3beaa6/skbio/tree/_compare.py000066400000000000000000000432541520735541300225700ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from itertools import combinations import numpy as np import scipy.spatial.distance as spdist from scipy.spatial.distance import squareform from skbio.stats.distance import DistanceMatrix from skbio.util import get_rng def unitcorr(a, b): """Calculate unit correlation distance. d = (1 - r) / 2, in which r is the Pearson's correlation coefficient. """ return spdist.correlation(a, b) * 0.5 def _check_input(trees, ids): """Validate input trees and IDs.""" if not (n := len(trees)): raise ValueError(f"No tree is provided.") if ids is None: return if (m := len(ids)) != n: raise ValueError(f"Numbers of IDs and trees don't match.") if m > len(set(ids)): raise ValueError(f"IDs contain duplicates.") def _check_dist_metric(metric): """Validate distance metric.""" if isinstance(metric, str): if metric == "unitcorr": metric = unitcorr else: metric = getattr(spdist, metric) elif not callable(metric): raise ValueError("`metric` must be a string or callable.") return metric def _check_shuffler(shuffler): """Validate sample shuffler.""" if not callable(shuffler): shuffler = get_rng(shuffler).shuffle return shuffler def _calc_dists(trees, ids, func, kwargs, shared_by_all): """Calculate paiwise distances among trees.""" if shared_by_all: result = func(trees, **kwargs) result = squareform(np.array(result, dtype=float), checks=False) return DistanceMatrix(result, ids, validate=False) else: return DistanceMatrix.from_iterable( trees, metric=lambda x, y: func((x, y), **kwargs)[0], keys=ids, validate=False, ) def _setdiff(a, b, proportion): r"""Quantify the difference between two sets. For Robinson-Foulds (RF) distance calculation. """ # calculate symmetric difference result = len(a ^ b) # normalize result to unit range [0, 1] # if total is 0, return 1 (dist = 1 means saturation) if proportion: total = len(a) + len(b) result = result / total if total else 1.0 # cast result to float else: result = float(result) return result def _mapdiff(a, b, metric): r"""Quantify the difference between two mappings. For weighted Robinson-Foulds (wRF) distance calculation. """ # unique keys are assigned value 0 union = frozenset(a).union(b) La = [a.get(x, 0.0) for x in union] Lb = [b.get(x, 0.0) for x in union] return metric(La, Lb) def _topo_dists( trees, rooted=False, shared_only=True, proportion=False, include_tips=False, weighted=False, metric=None, ): r"""Calculate the topological distances among multiple trees. This function calculates the Robinson-Foulds (RF) distance or its variants. These metrics rely on the compatibility of branches between two trees. See :meth:`TreeNode.compare_rfd` and :meth:`~TreeNode.compare_wrfd` for details of the metrics and parameters. Parameters ---------- trees : list of TreeNode The trees to compare. rooted : bool, optional Rooted or unrooted. shared_only : bool, optional Refine to shared taxa. proportion : bool, optional Normalize to proportion. include_tips : bool, optional Include singletons. weighted : bool, optional Weight by branch length. metric : callable, optional Distance metric (must provide if weighted). Returns ------- list of float Pairwise path-length distances or variants in condensed form. See Also -------- rf_dists wrfd_dists TreeNode.compare_rfd TreeNode.compare_wrfd TreeNode.compare_subsets TreeNode.compare_biparts """ kwargs = dict(include_tips=include_tips, map_to_length=weighted) # get topological units reflecting shared taxa if shared_only: taxon_sets = [t.subset() for t in trees] shared = frozenset.intersection(*taxon_sets) n_shared = len(shared) # Decide the "within" parameter (None or shared taxa) for each method call, # which is more efficient when within=None. withins = [shared if len(s) > n_shared else None for s in taxon_sets] # get topological units from all trees if rooted: sets = [t.subsets(within=w, **kwargs) for t, w in zip(trees, withins)] else: sets = [ t.biparts(within=w, full=s, **kwargs) for t, w, s in zip(trees, withins, taxon_sets) ] # get all topological units else: sets = [(t.subsets if rooted else t.biparts)(**kwargs) for t in trees] # unweighted (symmetric difference between sets) if not weighted: result = [_setdiff(a, b, proportion) for a, b in combinations(sets, 2)] # branch length weighted (vector distance) else: result = [_mapdiff(a, b, metric) for a, b in combinations(sets, 2)] return result def rf_dists(trees, ids=None, shared_by_all=True, proportion=False, rooted=False): r"""Calculate Robinson-Foulds (RF) distances among trees. .. versionadded:: 0.6.3 Parameters ---------- trees : list of TreeNode Input trees. ids : list of str, optional Unique identifiers of input trees. If omitted, will use incremental integers "0", "1", "2",... shared_by_all : bool, optional Calculate the distance between each pair of trees based on taxa shared across all trees (True, default), or shared between the current pair of trees (False). proportion : bool, optional Whether to return the RF distance as count (False, default) or proportion (True). rooted : bool, optional Whether to consider the trees as unrooted (False, default) or rooted (True). Returns ------- DistanceMatrix Matrix of the Robinson-Foulds distances. See Also -------- TreeNode.compare_rfd Notes ----- The Robinson-Foulds (RF) distance [1]_, a.k.a. symmetric difference, is the number of bipartitions differing between two trees. This function is equivalent to :meth:`TreeNode.compare_rfd` for two trees. Refer to the latter for details about the metric and its parameters. However, the current function extends the operation to an arbitrary number of trees and returns a distance matrix for them. This function is optimized for calculation based on taxa shared across all trees. One can instead set ``shared_by_all`` to False to calculate based on taxa shared between each pair of trees, which is however less efficient since bipartitions need to be re-inferred during each comparison. References ---------- .. [1] Robinson, D. F., & Foulds, L. R. (1981). Comparison of phylogenetic trees. Mathematical biosciences, 53(1-2), 131-147. Examples -------- >>> from skbio import TreeNode >>> trees = [TreeNode.read([x]) for x in ( ... "(((a,b),c),d,e);", ... "((a,(b,c)),d,e);", ... "((a,b),(c,d),e);", ... "(a,b,(c,(d,e)));", ... )] >>> dm = rf_dists(trees, ids=list("ABCD")) >>> print(dm) 4x4 distance matrix IDs: 'A', 'B', 'C', 'D' Data: [[ 0. 2. 2. 0.] [ 2. 0. 4. 2.] [ 2. 4. 0. 2.] [ 0. 2. 2. 0.]] """ _check_input(trees, ids) kwargs = dict( rooted=rooted, shared_only=True, proportion=proportion, include_tips=False, weighted=False, metric=None, ) return _calc_dists(trees, ids, _topo_dists, kwargs, shared_by_all) def wrf_dists( trees, ids=None, shared_by_all=True, metric="cityblock", rooted=False, include_tips=True, ): r"""Calculate weighted Robinson-Foulds (wRF) distances or variants among trees. .. versionadded:: 0.6.3 Parameters ---------- trees : list of TreeNode Input trees. ids : list of str, optional Unique identifiers of input trees. If omitted, will use incremental integers "0", "1", "2",... shared_by_all : bool, optional Calculate the distance between each pair of trees based on taxa shared across all trees (True, default), or shared between the current pair of trees (False). metric : str or callable, optional The distance metric to use. Can be a preset, a distance function name under :mod:`scipy.spatial.distance`, or a custom function that takes two vectors and returns a number. See :meth:`~TreeNode.compare_wrfd` for details. rooted : bool, optional Whether to consider the trees as unrooted (False, default) or rooted (True). include_tips : bool, optional Whether to include single-taxon biparitions (terminal branches) in the calculation. Default is True. Returns ------- DistanceMatrix Matrix of weighted Robinson-Foulds distances or variants. See Also -------- TreeNode.compare_wrfd Notes ----- The weighted Robinson-Foulds (wRF) distance [1]_ is the sum of differences of branch lengths of matching bipartitions between a pair of trees. This function is equivalent to :meth:`TreeNode.compare_wrfd` for two trees. Refer to the latter for details about the metric and its variants, and the parameter settings for calculating them. However, the current function extends the operation to an arbitrary number of trees and returns a distance matrix for them. A restriction of the current function compared to ``compare_wrfd`` is that ``metric`` must be symmetric (i.e., :math:`d(x, y) = d(y, x)`), and equals zero from a vector to itself (i.e., :math:`d(x, x) = 0`). It does not have to suffice non-negativity or triangle inequality though. This function is optimized for calculation based on taxa shared across all trees. One can instead set ``shared_by_all`` to False to calculate based on taxa shared between each pair of trees, which is however less efficient as bipartitions need to be re-inferred during each comparison. References ---------- .. [1] Robinson, D. F., & Foulds, L. R. (1979) Comparison of weighted labelled trees. In Combinatorial Mathematics VI: Proceedings of the Sixth Australian Conference on Combinatorial Mathematics, Armidale, Australia (pp. 119-126). Examples -------- >>> from skbio import TreeNode >>> trees = [TreeNode.read([x]) for x in ( ... "((a:1,b:2):1,c:4,((d:4,e:5):2,f:6):1);", ... "((a:3,(b:2,c:2):1):3,d:8,(e:5,f:6):2);", ... "((a:1,c:6):2,(b:3,(d:2,e:3):1):2,f:7);", ... )] >>> dm = wrf_dists(trees, ids=list("ABC")) >>> print(dm) 3x3 distance matrix IDs: 'A', 'B', 'C' Data: [[ 0. 16. 15.] [ 16. 0. 27.] [ 15. 27. 0.]] """ _check_input(trees, ids) metric = _check_dist_metric(metric) kwargs = dict( rooted=rooted, shared_only=True, include_tips=include_tips, weighted=True, metric=metric, ) return _calc_dists(trees, ids, _topo_dists, kwargs, shared_by_all) def _path_dists(trees, sample, metric, shuffler, use_length, ignore_self): r"""Calculate path-length distances or variants among multiple trees. This function calculates several tree distance metrics based on the lengths of paths connecting pairs of taxa, a.k.a., cophenetic distances. See :meth:`TreeNode.compare_cophenet` for details of the metrics and parameters. Parameters ---------- trees : list of TreeNode The trees to compare. sample : int, optional Number of taxa to sample. metric : callable, optional Distance function. shuffler : callable, optional Shuffling function. use_length : bool, optional Use branch lengths. ignore_self : bool, optional Ignore taxon to itself. Returns ------- list of float Pairwise path-length distances or variants in condensed form. See Also -------- path_dists TreeNode.compare_cophenet """ # Get shared taxa among trees. shared = frozenset.intersection(*(t.subset() for t in trees)) # Sort shared taxa. This is for the stability of sampling and distance calculation # as Python set is unordered. shared = sorted(shared) # Randomly sample a subset of taxa. if sample is not None: if (n_shared := len(shared)) < sample: raise ValueError( f"Sample size ({sample}) is greater than the number of shared taxa " f"({n_shared})." ) shuffler(shared) shared = shared[:sample] # Generate cophenetic (tip-to-tip) distance matrices. paths = [x.cophenet(endpoints=shared, use_length=use_length) for x in trees] # Convert square matrices into condensed 1-D arrays, such that diagonal (d(x, x) = # 0) and symmetric (d(x, y) = d(y, x)) comparisons are omitted. if ignore_self: paths = [x.condensed_form() for x in paths] # Otherwise, create 1-D views of the entire square matrices. `ravel` copies the # data only when necessary, and in this case doesn't. else: paths = [x.data.ravel() for x in paths] # Calculate pairwise distances among matrices. return [metric(a, b) for a, b in combinations(paths, 2)] def path_dists( trees, ids=None, shared_by_all=True, metric="euclidean", use_length=True, sample=None, shuffler=None, ): r"""Calculate path-length distances or variants among trees. .. versionadded:: 0.6.3 Parameters ---------- trees : list of TreeNode Input trees. ids : list of str, optional Unique identifiers of input trees. If omitted, will use incremental integers "0", "1", "2",... shared_by_all : bool, optional Calculate the distance between each pair of trees based on taxa shared across all trees (True, default), or shared between the current pair of trees (False). metric : str or callable, optional The distance metric to use. Can be a preset, a distance function name under :mod:`scipy.spatial.distance`, or a custom function that takes two vectors and returns a number. See :meth:`~TreeNode.compare_cophenet` for details. use_length : bool, optional Whether to calculate the sum of branch lengths (True, default) or the number of branches (False) connecting each pair of tips. sample : int, optional Randomly subsample this number of shared taxa for calculation. This is useful when comparing very large trees. shuffler : int, np.random.Generator or callable, optional The shuffling function to use if ``sample`` is specified. Default is :meth:`~numpy.random.Generator.shuffle`. If an integer is provided, a random generator will be constructed using this number as the seed. Returns ------- DistanceMatrix Matrix of the path-length distances or variants. See Also -------- TreeNode.compare_cophenet Notes ----- The path-length distance [1]_ is the square root of the sum of squared differences of path lengths among all pairs of taxa between two trees. This function is equivalent to :meth:`TreeNode.compare_cophenet` for two trees. Refer to the latter for details about the metric and its variants, and parameter settings for calculating them. However, the current function extends the operation to an arbitrary number of trees and returns a distance matrix for them. It is named so because the term "cophenetic distance" refers to the distance between two taxa in a tree instead. A restriction of the current function compared to ``compare_cophenet`` is that ``metric`` must be symmetric (i.e., :math:`d(x, y) = d(y, x)`), and equals zero from a vector to itself (i.e., :math:`d(x, x) = 0`). It does not have to suffice non-negativity or triangle inequality though. This function is optimized for calculation based on taxa shared across all trees. One can instead set ``shared_by_all`` to False to calculate based on taxa shared between each pair of trees, which is however less efficient as the path lengths need to be re-calculated during each comparison. References ---------- .. [1] Lapointe, F. J., & Cucumel, G. (1997). The average consensus procedure: combination of weighted trees containing identical or overlapping sets of taxa. Systematic Biology, 46(2), 306-312. Examples -------- >>> from skbio import TreeNode >>> trees = [TreeNode.read([x]) for x in ( ... "((a:1,b:2):1,c:4,((d:4,e:5):2,f:6):1);", ... "((a:3,(b:2,c:2):1):3,d:8,(e:5,f:6):2);", ... "((a:1,c:6):2,(b:3,(d:2,e:3):1):2,f:7);", ... )] >>> dm = path_dists(trees, ids=list("ABC")) >>> print(dm) 3x3 distance matrix IDs: 'A', 'B', 'C' Data: [[ 0. 13.7113092 11.87434209] [ 13.7113092 0. 19.5192213 ] [ 11.87434209 19.5192213 0. ]] """ _check_input(trees, ids) metric = _check_dist_metric(metric) if sample is not None: shuffler = _check_shuffler(shuffler) kwargs = dict( sample=sample, metric=metric, shuffler=shuffler, use_length=use_length, ignore_self=True, ) return _calc_dists(trees, ids, _path_dists, kwargs, shared_by_all) scikit-bio-scikit-bio-a3beaa6/skbio/tree/_exception.py000066400000000000000000000013661520735541300231360ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- class TreeError(Exception): """General tree error.""" pass class NoLengthError(TreeError): """Missing length when expected.""" pass class DuplicateNodeError(TreeError): """Duplicate nodes with identical names.""" pass class MissingNodeError(TreeError): """Expecting a node.""" pass class NoParentError(MissingNodeError): """Missing a parent.""" pass scikit-bio-scikit-bio-a3beaa6/skbio/tree/_majority_rule.py000066400000000000000000000242011520735541300240160ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from collections import defaultdict import numpy as np from skbio.tree import TreeNode def _walk_clades(trees, weights): """Walk all the clades of all the trees. Parameters ---------- trees : list of TreeNode The trees to walk. weights : np.array Tree weights. Returns ------- list of tuple The clades and support values sorted by support value such that the most supported clade is index 0. The tuples are of the form: (frozenset, float). defaultdict(float) The edge lengths, keyed by frozenset of the clade, and valued by the weighted average length of the clade by the trees the clade was observed in. """ clade_counts = defaultdict(float) edge_lengths = defaultdict(float) total = weights.sum() # get clade counts def tipnames_f(n): return [n.name] if n.is_tip() else [] for tree, weight in zip(trees, weights): tree.cache_attr(tipnames_f, "tip_names", frozenset) for node in tree.postorder(): tip_names = node.tip_names # if node.length is not None, fetch it and weight it length = node.length * weight if node.length is not None else None clade_counts[tip_names] += weight if length is None: edge_lengths[tip_names] = None else: edge_lengths[tip_names] += length / total # sort clades by number times observed clade_counts = sorted(clade_counts.items(), key=lambda x: len(x[0]), reverse=True) return clade_counts, edge_lengths def _filter_clades(clade_counts, cutoff_threshold): """Filter clades that not well supported or are contradicted. Parameters ---------- clade_counts : list of tuple Where the first element in each tuple is the frozenset of the clade, and the second element is the support value. It is expected that this list is sorted by descending order by support. cutoff_threshold : float The minimum weighted observation count that a clade must have to be considered supported. Returns ------- dict A dict of the accepted clades, keyed by the frozenset of the clade and valued by the support value. """ accepted_clades = {} for clade, count in clade_counts: conflict = False if count <= cutoff_threshold: continue if len(clade) > 1: # check the current clade against all the accepted clades to see if # it conflicts. A conflict is defined as: # 1. the clades are not disjoint # 2. neither clade is a subset of the other for accepted_clade in accepted_clades: intersect = clade.intersection(accepted_clade) subset = clade.issubset(accepted_clade) superset = clade.issuperset(accepted_clade) if intersect and not (subset or superset): conflict = True if conflict is False: accepted_clades[clade] = count return accepted_clades def _build_trees(clade_counts, edge_lengths, support_attr, tree_node_class): """Construct the trees with support. Parameters ---------- clade_counts : dict Keyed by the frozenset of the clade and valued by the support edge_lengths : dict Keyed by the frozenset of the clade and valued by the weighted length support_attr : str The name of the attribute to hold the support value tree_node_class : type Specifies type of consensus trees that are returned. Either ``TreeNode`` or a type that implements the same interface (most usefully, a subclass of ``TreeNode``). Returns ------- list of tree_node_class instances A list of the constructed trees """ nodes = {} queue = [(len(clade), clade) for clade in clade_counts] while queue: # The values within the queue are updated on each iteration, so it # doesn't look like an insertion sort will make sense unfortunately queue.sort() (clade_size, clade) = queue.pop(0) new_queue = [] # search for ancestors of clade for _, ancestor in queue: if clade.issubset(ancestor): # update ancestor such that, in the following example: # ancestor == {1, 2, 3, 4} # clade == {2, 3} # new_ancestor == {1, {2, 3}, 4} new_ancestor = (ancestor - clade) | frozenset([clade]) # update references for counts and lengths clade_counts[new_ancestor] = clade_counts.pop(ancestor) edge_lengths[new_ancestor] = edge_lengths.pop(ancestor) ancestor = new_ancestor new_queue.append((len(ancestor), ancestor)) # if the clade is a tip, then we have a name if clade_size == 1: name = list(clade)[0] else: name = None # the clade will not be in nodes if it is a tip children = [nodes.pop(c) for c in clade if c in nodes] length = edge_lengths[clade] node = tree_node_class(children=children, length=length, name=name) setattr(node, support_attr, clade_counts[clade]) nodes[clade] = node queue = new_queue return list(nodes.values()) def majority_rule( trees, weights=None, cutoff=0.5, support_attr="support", tree_node_class=TreeNode ): r"""Determine consensus trees from a list of rooted trees. Parameters ---------- trees : list of TreeNode The trees to operate on weights : list or np.array of {int, float}, optional If provided, the list must be in index order with `trees`. Each tree will receive the corresponding weight. If omitted, all trees will be equally weighted. cutoff : float, 0.0 <= cutoff <= 1.0, optional Any clade that has <= cutoff support will be dropped. If cutoff is < 0.5, then it is possible that ties will result. If so, ties are broken arbitrarily depending on list sort order. support_attr : str, optional The attribute to be decorated onto the resulting trees that contain the consensus support. tree_node_class : type, optional Specifies type of consensus trees that are returned. Either ``TreeNode`` (the default) or a type that implements the same interface (most usefully, a subclass of ``TreeNode``). Returns ------- list of tree_node_class instances Each tree will be of type `tree_node_class`. Multiple trees can be returned in the case of two or more disjoint sets of tips represented on input. Notes ----- This code was adapted from PyCogent's majority consensus code originally written by Matthew Wakefield. The method is based off the original description of consensus trees in [1]_. An additional description can be found in the Phylip manual [2]_. This method does not support majority rule extended. Support is computed as a weighted average of the tree weights in which the clade was observed in. For instance, if {A, B, C} was observed in 5 trees all with a weight of 1, its support would then be 5. References ---------- .. [1] Margush T, McMorris FR. (1981) "Consensus n-trees." Bulletin for Mathematical Biology 43(2) 239-44. .. [2] http://evolution.genetics.washington.edu/phylip/doc/consense.html Examples -------- Computing the majority consensus, using the example from the Phylip manual with the exception that we are computing majority rule and not majority rule extended. >>> from skbio.tree import TreeNode >>> trees = [ ... TreeNode.read(["(A,(B,(H,(D,(J,(((G,E),(F,I)),C))))));"]), ... TreeNode.read(["(A,(B,(D,((J,H),(((G,E),(F,I)),C)))));"]), ... TreeNode.read(["(A,(B,(D,(H,(J,(((G,E),(F,I)),C))))));"]), ... TreeNode.read(["(A,(B,(E,(G,((F,I),((J,(H,D)),C))))));"]), ... TreeNode.read(["(A,(B,(E,(G,((F,I),(((J,H),D),C))))));"]), ... TreeNode.read(["(A,(B,(E,((F,I),(G,((J,(H,D)),C))))));"]), ... TreeNode.read(["(A,(B,(E,((F,I),(G,(((J,H),D),C))))));"]), ... TreeNode.read(["(A,(B,(E,((G,(F,I)),((J,(H,D)),C)))));"]), ... TreeNode.read(["(A,(B,(E,((G,(F,I)),(((J,H),D),C)))));"])] >>> consensus = majority_rule(trees, cutoff=0.5)[0] >>> for node in sorted(consensus.non_tips(), key=lambda k: k.count(tips=True)): ... support_value = node.support ... names = ' '.join(sorted(n.name for n in node.tips())) ... print(f"Tips: {names}, support: {support_value}") Tips: F I, support: 9.0 Tips: D H J, support: 6.0 Tips: C D H J, support: 6.0 Tips: C D F G H I J, support: 6.0 Tips: C D E F G H I J, support: 9.0 Tips: B C D E F G H I J, support: 9.0 In the next example, multiple trees will be returned which can happen if clades are not well supported across the trees. In addition, this can arise if not all tips are present across all trees. >>> trees = [ ... TreeNode.read(["((a,b),(c,d),(e,f));"]), ... TreeNode.read(["(a,(c,d),b,(e,f));"]), ... TreeNode.read(["((c,d),(e,f),b);"]), ... TreeNode.read(["(a,(c,d),(e,f));"])] >>> consensus_trees = majority_rule(trees) >>> len(consensus_trees) 4 """ if weights is None: weights = np.ones(len(trees), dtype=float) else: weights = np.asarray(weights) if len(weights) != len(trees): raise ValueError("Number of weights and trees differ.") cutoff_threshold = cutoff * weights.sum() clade_counts, edge_lengths = _walk_clades(trees, weights) clade_counts = _filter_clades(clade_counts, cutoff_threshold) trees = _build_trees(clade_counts, edge_lengths, support_attr, tree_node_class) return trees scikit-bio-scikit-bio-a3beaa6/skbio/tree/_me.py000066400000000000000000001706301520735541300215420ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- r"""Minimum evolution phylogenetic methods. This submodule implements four algorithms for distance-based phylogenetic inference and refinement under the minimum evolution (ME) criterion. They were originally introduced in: Desper, R., & Gascuel, O. (2002). Fast and accurate phylogeny reconstruction algorithms based on the minimum-evolution principle. J Comput Biol, 9(5), 687-705. The four algorithms are (named following the original publication): De novo reconstruction of phylogenetic trees using an agglomerative clustering strategy that iteratively inserts new taxa into a growing tree: 1. GME: Greedy minimum evolution (using an OLS framework). 2. BME: Balanced minimum evolution (using a balanced framework). Rearrangement of existing phylogenetic trees using the nearest neighbor interchange (NNI) strategy that iteratively swaps branches to improve optimality: 3. FastNNI: using an OLS framework. 4. BNNI: using a balanced framework. *** These four algorithms share the same mathematical foundations with the algorithms provided by the FastME package: 1. GME: `-m O -w O` 2. BME: `-m B -w B` 3. GME with FastNNI: `-m O -w O -n O` 4. BME with BNNI: `-m B -w B -n B` The algorithms implemented here were designed from scratch based on the original paper. Multiple optimization strategies were incorporated to make them efficient. *** Specifically, these algorithms use a flattened, incrementally maintained array data structure to represent the tree topology. In this 2-D array, rows represent nodes in the order of insertion into the tree, with the root placed at row 0. There are four columns: 0. Left child index, or 0 if a tip. 1. Right child index, or taxon index if a tip. 2. Parent index, or 0 if root. 3. Sibling index, or 0 if root. For example, a tree with four taxa: a, b, c and d is like: a / \ b x / \ c d This tree can be represented by the following 2-D array: [[1, 2, 0, 0], # a (root) [0, 1, 0, 2], # b (tip) [3, 4, 0, 1], # x (internal) [0, 2, 2, 4], # c (tip) [0, 3, 2, 3]] # d (tip) In the agglomerative clustering methods, newly inserted taxa are appended to the end of the tree array, therefore existing nodes except for the connection do not need to be updated. In the rearrangement methods, all nodes stay still and only connections are updated. The average distances between nodes are stored in a matrix with the same order of node indices as in the tree array. Locating distances is via indexing and is efficient. *** A separate 1-D array stores node indices visited through a preorder traversal: [0, 1, 2, 3, 4] In this example, the preorder is identical to the insertion order. But they can be different in real calculation. When a new taxon is inserted into the tree, or two existing branches are swapped, the preorder array needs to be updated to reflect the change, and this operation is O(n). The preorder array permits convenient location of all nodes within a clade, without the need to traverse it. Therefore, it enables parallelization of per-node calculations in addition to enhanced memory locality. With the preorder array, one can easily look up the original node given its index. However, the opposite is not possible. The tree building algorithms were designed not to rely on the reverse lookup, whereas the tree rearrangement algorithms separately maintains a reverse lookup table. Meanwhile, postorder traversal is not involved in these algorithms. The original paper used postorder in multiple situations. This is replaced with reverse preorder in the algorithms here, as both orders suffice the parent-after-children pattern, which is all the algorithms need. Therefore, maintaining a single preorder array is sufficient for both top-down and bottom-up traversal. """ from heapq import heapify, heappop import numpy as np from skbio.tree import TreeNode from ._c_me import ( _insert_taxon, _avgdist_taxon, _avgdist_taxon_c, _bal_avgdist_taxon, _bal_avgdist_taxon_c, _avgdist_d2_insert, _bal_avgdist_insert, _ols_lengths, _ols_lengths_d2, _bal_lengths, _ols_min_branch_d2, _bal_min_branch, _bal_min_branch_p, _avgdist_matrix, _bal_avgdist_matrix, _avgdist_swap, _bal_avgdist_swap, _ols_all_swaps, _ols_corner_swaps, _bal_all_swaps, _get_num_threads, _bal_avgdist_chunk, _bal_update_spine, _bal_insert_plan, _bal_avgdist_flat, _bal_avgdist_nest, _calc_tacts, _calc_sizes, _calc_pairs, _calc_deeps, ) from ._utils import _validate_dm, _validate_dm_and_tree from skbio.stats.distance import DistanceMatrix def gme(dm, neg_as_zero=True): r"""Perform greedy minimum evolution (GME) for phylogenetic reconstruction. .. versionadded:: 0.6.2 .. versionchanged:: 0.6.3 Computational efficiency significantly improved. Parameters ---------- dm : skbio.DistanceMatrix Input distance matrix containing distances between taxa. neg_as_zero : bool, optional If True (default), convert negative branch lengths into zeros. Returns ------- TreeNode Reconstructed phylogenetic tree. See Also -------- bme nni nj Notes ----- Greedy Minimum Evolution (GME) [1]_ is a distance-based algorithm for phylogenetic reconstruction. It utilizes the minimum evolution (ME) principle [2]_ for selecting a tree topology with the smallest sum of branch lengths, as calculated using an ordinary least squares (OLS) framework [3]_. GME is *O*\(*n*:sup:`2`) in time and *O*\(*n*) in space, making it a more scalable method than multiple alternatives (e.g., :func:`nj` and :func:`bme`). Therefore it is suitable for reconstructing very large phylogenetic trees. GME generates an unrooted tree with variable tip heights and potentially some negative branch lengths. The first taxon in the distance matrix is always placed as a child of the root node. See the notes of :func:`nj` for how to deal with unrooted trees and negative branch lengths. A GME-generated tree may be further improved by executing the FastNNI algorithm implemented in :func:`nni` (with ``balanced=False``). This algorithm is mathematically equivalent to the "TaxAdd_OLSME" method provided by the FastME program [4]_. .. note:: This function was implemented following the original paper [1]_. It is not guaranteed that it will precisely mirror FastME's output. Although in practices it usually generates identical or equally optimal phylogenetic trees as FastME does. A similar but less scalable algorithm using the balanced instead of OLS framework is provided in :func:`bme`. References ---------- .. [1] Desper, R., & Gascuel, O. (2002). Fast and accurate phylogeny reconstruction algorithms based on the minimum-evolution principle. J Comput Biol, 9(5), 687-705. .. [2] Rzhetsky, A., & Nei, M. (1993). Theoretical foundation of the minimum-evolution method of phylogenetic inference. Mol Biol Evol, 10(5), 1073-1095. .. [3] Cavalli-Sforza, L. L., & Edwards, A. W. (1967). Phylogenetic analysis. Models and estimation procedures. American journal of human genetics, 19(3 Pt 1), 233. .. [4] Lefort, V., Desper, R., & Gascuel, O. (2015). FastME 2.0: a comprehensive, accurate, and fast distance-based phylogeny inference program. Mol Biol Evol, 32(10), 2798-2800. Examples -------- Define a new distance matrix object describing the distances between five taxa: human, monkey, pig, rat, and chicken. >>> from skbio import DistanceMatrix >>> from skbio.tree import gme >>> dm = DistanceMatrix([[0, 0.02, 0.18, 0.34, 0.55], ... [0.02, 0, 0.19, 0.35, 0.55], ... [0.18, 0.19, 0, 0.34, 0.54], ... [0.34, 0.35, 0.34, 0, 0.62], ... [0.55, 0.55, 0.54, 0.62, 0]], ... ['human','monkey','pig','rat','chicken']) Perform Greedy Minimum Evoltuion (GME) and construct the minimum evolution tree representing the relationship between those taxa. This is returned as a TreeNode object. >>> tree = gme(dm) >>> print(tree.ascii_art()) /-monkey | | /-pig |---------| ---------| | /-rat | \--------| | \-chicken | \-human """ _validate_dm(dm) # convert to redundant form for now if dm._flags["CONDENSED"]: dm = DistanceMatrix(dm) # reconstruct tree topology and branch lengths using GME tree, lens = _gme(dm.data) if neg_as_zero: lens[lens < 0] = 0 return _to_treenode(tree, dm.ids, lens, unroot=True) def bme(dm, neg_as_zero=True, **kwargs): r"""Perform balanced minimum evolution (BME) for phylogenetic reconstruction. .. versionadded:: 0.6.3 .. versionchanged:: 0.7.3 Computational efficiency significantly improved. Parallelization is enabled by default. Parameters ---------- dm : skbio.DistanceMatrix Input distance matrix containing distances between taxa. neg_as_zero : bool, optional If True (default), convert negative branch lengths into zeros. Returns ------- TreeNode Reconstructed phylogenetic tree. See Also -------- gme nni nj Notes ----- Balanced Minimum Evolution (BME) [1]_ is a refinement of the distance-based minimum evolution problem where the average distances between subtrees are independent of the sizes of the subtrees. This is referred to as a balanced (or simply BME) framework [2]_, as in contrast to the OLS framework used by GME (:func:`gme`). The BME problem aims to find a tree topology that minimizes the balanced tree length: .. math:: L(T) = \sum 2^{1-p_{i,j}(T)} d_{i,j} In which :math:`d_{i,j}` is the distance between each pair of taxa :math:`i` and :math:`j` in the input distance matrix. :math:`p_{i,j}(T)` is the number of branches along the path connecting the two taxa in the output tree :math:`T`. This function is an improved implementation of the original BME algorithm described in [1]_. It is an additive heuristic algorithm that iteratively grows a tree by inserting taxa while minimizing the balanced tree length at each step. This process is similar to GME, but uses the balanced framework. It is mathematically equivalent to the "TaxAdd_BalME" method provided by FastME [3]_. It has an average case time complexity of *O*\(*n*:sup:`2` log(*n*)) and a worst case of *O*\(*n*:sup:`3`), and its space complexity is *O*\(*n*:sup:`2`). .. note:: This function was implemented following the original paper [1]_. It is not guaranteed that it will precisely mirror FastME's output. Although in practices it usually generates identical or equally optimal phylogenetic trees as FastME does. BME generates an unrooted tree with variable tip heights and potentially some negative branch lengths. The first taxon in the distance matrix is always placed as a child of the root node. See the notes of :func:`nj` for how to deal with unrooted trees and negative branch lengths.. A BME-generated tree may be further improved by executing the BNNI algorithm implemented in :func:`nni` (with ``balanced=True``). **Parallelization** This function utilizes parallelization to improve efficiency. By default, it starts to parallelize when the tree has grown to 500 taxa, an empirically determined threshold that can be modified by setting the hidden parameter ``parallel`` (e.g., ``parallel=100``). Setting it to ``True`` always enables parallelization regardless of tree size. Setting it to ``False`` disables parallelization completely. See also `this section `_ on how to specify the number of threads to use for parallelization. **Floating-point precision** This algorithm natively supports float32 and float64 calculations without casting. The former has half memory cost and moderately faster runtime compared to the latter, at the cost of reduced precision. To control the floating-point precision, simply supply a distance matrix of the desired type (e.g., ``bme(DistanceMatrix.read(file, dtype='float32'))``). References ---------- .. [1] Desper, R., & Gascuel, O. (2002). Fast and accurate phylogeny reconstruction algorithms based on the minimum-evolution principle. J Comput Biol, 9(5), 687-705. .. [2] Pauplin, Y. (2000). Direct calculation of a tree length using a distance matrix. J Mol Evol, 51, 41-47. .. [3] Lefort, V., Desper, R., & Gascuel, O. (2015). FastME 2.0: a comprehensive, accurate, and fast distance-based phylogeny inference program. Mol Biol Evol, 32(10), 2798-2800. Examples -------- Define a new distance matrix object describing the distances between five taxa: human, monkey, pig, rat, and chicken. >>> from skbio import DistanceMatrix >>> from skbio.tree import bme >>> dm = DistanceMatrix([[0, 0.02, 0.18, 0.34, 0.55], ... [0.02, 0, 0.19, 0.35, 0.55], ... [0.18, 0.19, 0, 0.34, 0.54], ... [0.34, 0.35, 0.34, 0, 0.62], ... [0.55, 0.55, 0.54, 0.62, 0]], ... ['human','monkey','pig','rat','chicken']) Perform Balanced Minimum Evoltuion (BME) and construct the minimum evolution tree representing the relationship between those taxa. This is returned as a TreeNode object. >>> tree = bme(dm) >>> print(tree.ascii_art()) /-monkey | | /-pig |---------| ---------| | /-rat | \--------| | \-chicken | \-human """ _validate_dm(dm) # convert to redundant form for now if dm._flags["CONDENSED"]: dm = DistanceMatrix(dm) # reconstruct tree topology and branch lengths using BME tree, lens = _bme(dm.data, **kwargs) if neg_as_zero: lens[lens < 0] = 0 return _to_treenode(tree, dm.ids, lens, unroot=True) def nni(tree, dm, balanced=True, neg_as_zero=True): r"""Perform nearest neighbor interchange (NNI) to improve a phylogenetic tree. .. versionadded:: 0.6.2 .. versionchanged:: 0.6.3 Computational efficiency significantly improved. Parameters ---------- tree : skbio.TreeNode Input phylogenetic tree to be rearranged. dm : skbio.DistanceMatrix Input distance matrix containing distances between taxa. balanced : bool, optional Use the OLS framework (False) or the balanced framework (True, default). neg_as_zero : bool, optional If True (default), convert negative branch lengths into zeros. Returns ------- TreeNode Rearranged phylogenetic tree. Notes ----- Nearest neighbor interchange (NNI) is a method for tree rearrangement aiming at optimizing a given tree topology according to certain criteria. It iteratively swaps neighboring branches that could result in a better tree, until no such swaps remain in the optimized tree. This function performs NNI for the minimum evolution (ME) problem on phylogenetic trees. The implementation is based on [1]_. Two versions of the method are provided: the FastNNI algorithm (``balanced=False``) based on an ordinary least squares (OLS) framework (see also :func:`gme`) and the BNNI algorithm (``balanced=True``) based on a balanced framework (see also :func:`bme`). The former is more scalable than the latter. .. note:: The FastNNI and BNNI algorithms are mathematically equivalent to the "NNI_OLS" and "NNI_BalME" methods provided by the FastME program [2]_, respectively. This function was implemented following the original paper [1]_, and there is no guarantee that it will precisely mirror FastME's output. Although in practices it usually generates identical or equally optimal trees as FastME does. The set of taxa in the tree (accessible via :meth:`~TreeNode.subset`) must match those in the distance matrix. The tree may be rooted or unrooted, but it must be strictly bifurcating. One can apply :meth:`~TreeNode.is_bifurcating` to check if the tree is strictly bifurcating: .. code-block:: python tree.is_bifurcating(strict=True, include_self=False) If not, one can apply :meth:`~TreeNode.bifurcate` and :meth:`~TreeNode.prune` to convert the tree into a bifurcating one. A special case is when the root node itself is a taxon (and it is connected to only one child), a format that can be generated by some phylogenetic analyses (e.g., by calling :meth:`~TreeNode.root_at` on a tip). This format is currently unsupported by this function. One needs to reroot the tree in such a case. The output tree is unrooted, with the first taxon in the distance matrix placed as a child of the root node. Branch lengths are assigned according to the framework of choice. See also :func:`nj` regarding rooting an unrooted tree and dealing with potential negative branch lengths. References ---------- .. [1] Desper, R., & Gascuel, O. (2002). Fast and accurate phylogeny reconstruction algorithms based on the minimum-evolution principle. J Comput Biol, 9(5), 687-705. .. [2] Lefort, V., Desper, R., & Gascuel, O. (2015). FastME 2.0: a comprehensive, accurate, and fast distance-based phylogeny inference program. Mol Biol Evol, 32(10), 2798-2800. Examples -------- >>> from skbio import DistanceMatrix, TreeNode >>> from skbio.tree import nni Define a distance matrix describing the distances between five taxa. >>> dm = DistanceMatrix([[0, 0.02, 0.18, 0.34, 0.55], ... [0.02, 0, 0.19, 0.35, 0.55], ... [0.18, 0.19, 0, 0.34, 0.54], ... [0.34, 0.35, 0.34, 0, 0.62], ... [0.55, 0.55, 0.54, 0.62, 0]], ... ['human','monkey','pig','rat','chicken']) Provide a tree to be rearranged. The tree must be bifurcating. Branches lengths are not required. >>> tree = TreeNode.read(["((human,chicken),(rat,monkey),pig);"]) >>> print(tree.ascii_art()) /-human /--------| | \-chicken | ---------| /-rat |---------| | \-monkey | \-pig Perform nearest neighbor interchange (NNI). This will rearrange tree topolgy to better approach the minimum evolution criterion. >>> tree = nni(tree, dm) >>> print(tree.ascii_art()) /-pig /--------| | | /-chicken | \--------| ---------| \-rat | |--monkey | \-human Besides rearranging tree topology, estimated branch lengths are assigned to the tree. >>> rat = tree.find('rat') >>> print(rat.length) 0.20875 """ _validate_dm_and_tree(dm, tree) # convert to redundant form for now if dm._flags["CONDENSED"]: dm = DistanceMatrix(dm) # generate tree array taxa = dm.ids tree = _root_from_treenode(tree, taxa) order = np.arange(tree.shape[0], dtype=int) # allocate lengths lens = np.empty(len(tree), dtype=dm.dtype) # matrix data # NOTE: current code assumes matrix is C-contiguous for efficient access (unlike # `gme` and `bme`, which don't). This can be patch later to increase flexibility. data = np.ascontiguousarray(dm.data) # perform BNNI or FastNNI func = _bnni if balanced else _fastnni func(data, tree, order, lens) if neg_as_zero: lens[lens < 0] = 0 # generate TreeNode object return _to_treenode(tree, taxa, lens, unroot=True) def _gme(dm): r"""Perform greedy minimum evolution (GME) for phylogenetic reconstruction. Parameters ---------- dm : ndarray of float of shape (m, m) Input distance matrix containing distances between taxa. Returns ------- tree : ndarray of int of shape (2m - 3, 4) Reconstructed tree topology by GME. lens : ndarray of float of shape (2m - 3,) Estimated branch lengths by OLS. Notes ----- The GME algorithm involves growing an unrooted tree by iteratively inserting taxa. In the beginning it initializes a triplet tree with the first three taxa: 0 | x / \ 1 2 Taxon 0 is placed at the root position, with its unique descendant x serving as connector for taxa 1 and 2 as its left and right children. Next, taxon 3 will be inserted into a branch that suffices the minimum evolution criterion. Let's say the branch connecting x and 2. The tree becomes: 0 | x / \ 1 y / \ 2 3 So on so forth until all taxa are included in the tree. Finally, branch lengths are estimated using an ordinary least squares (OLS) framework. --- This implementation uses an array-based tree structure to improve efficiency. See top of this file for details of this structure. Basically, the root node (taxon 0) is omitted, making the tree strictly binary. Instead, the unique descendant (x) is now treated as the root and marked with taxon 0: 0 / \ 1 y / \ 2 3 The root is always the first row in the tree array. Other nodes are appended to the tree array in the same order as they are added to the tree. --- For an input distance matrix with m taxa, the output tree will have 2m - 3 nodes. This memory space is pre-allocated to improve efficiency. The algorithm doesn't remake arrays during iteration, but repeatedly uses the already allocated space. During an iteration involving x nodes, the first x positions of each array are occupied, while the remaining positions are disregarded. There is no need to reset array values after each iteration. Since they are created de novo, all arrays are C-contiguous. This permits further optimization in the Cython code. """ dtype = dm.dtype # faster processing for C-contiguous data adk_func = _avgdist_taxon_c if dm.flags["C_CONTIGUOUS"] else _avgdist_taxon # number of taxa in the input distance matrix m = dm.shape[0] # number of nodes in the final tree (note: taxon 0 is at root) n = 2 * m - 3 # tree topology tree = np.empty((n, 4), dtype=int) tree[:3] = [ [1, 2, 0, 0], # 0: root [0, 1, 0, 2], # 1: left child [0, 2, 0, 1], # 2: right child ] # node indices in preorder order = np.empty(n, dtype=int) order[:3] = [0, 1, 2] # number of taxa (i.e., tips) descending from each node (=1 if a tip). # NOTE: "tact" is an abbr for "taxon count". tacts = np.full(n, -1, dtype=int) tacts[:3] = [2, 1, 1] # average distances between distant-2 subtrees ad2 = np.empty((2, n), dtype=dtype) ad2[1, 1] = dm[0, 1] ad2[1, 2] = dm[0, 2] ad2[0, 1] = ad2[0, 2] = dm[1, 2] ad2[1, 0] = ad2[0, 0] = 0 # average distances from a taxon to each subtree adk = np.empty((2, n), dtype=dtype) # branch lengths or length changes lens = np.empty((n,), dtype=dtype) lens[0] = 0 # Iteratively add taxa to the tree. for k in range(3, m): # Calculate average distances from new taxon to existing subtrees. adk_func(adk, k, dm, tree, order, tacts) # Find a branch with minimum length change. itag = _ols_min_branch_d2(lens, ad2, adk, tree, order, tacts) size = tacts[order[itag]] * 2 - 1 # Update average distances between distant-2 subtrees. _avgdist_d2_insert(ad2, itag, adk, tree, order, tacts) # Insert new taxon into tree. _insert_taxon(k, itag, size, tree, order) # Calculate branch lengths using an OLS framework. _ols_lengths_d2(lens, ad2, tree, tacts) return tree, lens def _bme(dm, parallel=500, factor=10): r"""Perform balanced minimum evolution (BME) for phylogenetic reconstruction. Parameters ---------- dm : ndarray of float of shape (m, m) Input distance matrix containing distances between taxa. parallel : bool or int Whether to parallelize (bool) and since how many taxa in the tree to start parallelization (int, default: 500). factor : int During parallelization, the program will try to partition the tree into chunks of available thread count multiplied by this number. Default is 10, a number empirically determined. Returns ------- tree : ndarray of int of shape (2m - 3, 4) Reconstructed tree topology by BME. lens : ndarray of float of shape (2m - 3,) Estimated branch lengths by a balanced framework. Notes ----- The BME algorithm resembles GME but uses a balanced instead of OLS framework. See :func:`_gme` for details of the latter. The main differences are: 1) BME requires a full matrix stored and iteratively updated, which is less efficient than GME in time and space. 2) BME doesn't rely on subtree sizes, which is simpler and more efficient than GME in individual calculations (but this cannot compensate for the former). *** This function utilizes parallelization. It is only worth to parallelize when the tree has grown beyond certain size. Therefore, this function implements a three- phase process: 1. Serial processing for small trees. 2. Parallelize the update of average distances between pairs of subtrees, which involve nested iterations and is the dominant part of the algorithm. 3. Also parallelize flat iterations (e.g., calculating branch lengths). """ dtype = dm.dtype # faster processing for C-contiguous data adk_func = _bal_avgdist_taxon_c if dm.flags["C_CONTIGUOUS"] else _bal_avgdist_taxon # numbers of taxa and nodes in the tree m = dm.shape[0] N = 2 * m - 3 ### Determine parallelization plan. ### # To disable parallelization, set parallel=False or 0 # To always enable parallelization, set parallel=True or 3 # The iteration is divided into three phases: # - Phase 1: Serial. # - Phase 2: Parallelize the update of average distance between pairs of subtrees, # which requires nested iterations. These calculations are between O(nlog(n)) # and O(n^2), and therefore the dominant part of the algorith. # * If we assume a Yule process, the expected number of ancestor-descendant pairs # is approximately 4n * ln(n), which is close to the number of calculations. # - Phase 3: Also parallelize flat iterations over all nodes (O(n)). These steps # are not dominant but still cost non-negligible time. # The parameter `parallel` defines the threshold of current number of taxa (i.e., # tips) in the tree that triggers parallelization (entering phase 2). The threshold # of entering phase 3 is 2n * ln(n) (derived from above). # The default setting parallel=500 translates into: Enter phase 2 when the tree # has grown to 500 taxa (999 nodes). Enter phase 3 when tree has 6,215 taxa. # Number of threads available to OpenMP. threads = _get_num_threads() # Crossover point between serial and parallel phases. When the tree has grown to # this number of taxa, parallelization becomes worth and is performed afterwards. # never parallelize if threads <= 1 or not parallel: nest_th = flat_th = m # parallelize beyond this taxon count else: nest_th = max(3, parallel) # algorithm starts with 3 taxa flat_th = 2 * nest_th * int(np.log(nest_th)) # calculate 2nd threshold nest_th = min(nest_th, m) # cap by target tree size flat_th = min(flat_th, m) ### Allocate array space and initiate a 3-taxon tree. ### # tree topology (left, right, parent, sibling) tree = np.empty((N, 4), dtype=int) tree[:3] = [ [1, 2, 0, 0], # 0: root [0, 1, 0, 2], # 1: left child [0, 2, 0, 1], # 2: right child ] # node indices in preorder order = np.empty(N, dtype=int) order[:3] = [0, 1, 2] # number of nodes (tips and internal, incl. root) within each clade (i.e., size) sizes = np.empty(N, dtype=int) sizes[:3] = [3, 1, 1] # number of branches from each node to root (i.e., depth) (named as `deeps` to be # equal to other attributes in length) deeps = np.empty(N, dtype=int) deeps[:3] = [0, 1, 1] # average distances between all subtrees # (This is the dominant factor in BME, and what makes it more expensive than GME.) adm = np.empty((N, N), dtype=dtype) adm[0, 1] = adm[1, 0] = dm[0, 1] adm[0, 2] = adm[2, 0] = dm[0, 2] adm[1, 2] = adm[2, 1] = dm[1, 2] # average distances from an added taxon (k) to each subtree (lower and upper). adk = np.empty((2, N), dtype=dtype) # Branch lengths or length changes. The latter is relative to the root (i.e., start # of preorder traversal). Therefore the first element is always zero. lens = np.empty(N, dtype=dtype) lens[0] = 0.0 # intermediate diffs = np.empty(N, dtype=dtype) # ancestors of target (nodes from its parent to root in ascending order) ancs = np.empty(N, dtype=int) # pointers to rows in `adm` representing individual ancestors ancx = np.empty(N, dtype=int) # Pre-calculate negative powers of 2 for quick lookup. # NOTE: The maximum number of branches connecting any two nodes (i.e., diameter) is # m (when tree is extremely skewed). Therefore m powers are sufficient. # NOTE: This method appears to be faster than calling the C function `ldexp` each # time. When m is large, the array may exceed cache size. However, the range of # powers that are actually used is often closer to log2(m) (balanced tree) than to # m (skewed tree). So lookup is often efficient. # NOTE: When l >= certain threshold, 2^(-l) effectively becomes 0 in floating-point # arithmetics. This threshold is 150 for float32 and 1075 for float64. So the array # has a large proportion of zeros at the right end. # NOTE: A potential optimization is to skip all calculations when path length goes # beyond the above thresholds. However, in a binary tree the max. path length is at # the logarithmic scale (more precisely, height ~= 4.31107 ln(n), according to # Devroye et al. Bull Math Biol. 2025). So path lengths in a tree of 100k taxa are # usually below 100, making this optimization unnecessary. npots = np.ldexp(dtype.type(1.0), -np.arange(m)) ### Phase 1: Serial ### # group arguments to make it easier to write args1 = (adm, adk, tree) args2 = (order, sizes, deeps) # current number of nodes in the tree (n = 2 * k - 3) n = 3 for k in range(3, nest_th): # Calculate balanced average distances from new taxon to existing subtrees. adk_func(n, k, dm, adk, tree, order) # Find the branch with minimum length change, into which the new taxon will be # inserted. Return value is the preorder index of the node under this branch. itag = _bal_min_branch(n, lens, *args1, order) # Update balanced average distance matrix between all subtrees. _bal_avgdist_insert(n, itag, *args1, *args2, diffs, npots, ancs, ancx) # Update tree topology with the inserted taxon. _insert_taxon(k, itag, sizes[order[itag]], tree, order) n += 2 ### Phase 2: Parallel (nested only) ### # Expected number of chunks into which tree nodes will be evenly divided. Per-chunk # capacity = total number of nodes / this number. The actual chunk count usually # exceeds this number. enc = threads * factor # number of ancestor-descendant pairs (i.e., sum of depths) within each clade pairs = np.empty(N, dtype=int) _calc_pairs(n, tree, order, sizes, pairs) # segment bounds (nodes within each segment has the same level) segs = np.empty(N + 1, dtype=int) # level (number of branches ascending from target's parent) of each segment lvls = np.empty(N, dtype=int) # workload of clade under each segment start oops = np.empty(N, dtype=int) # chunk bounds in preorder # NOTE: The maximum number of chunks is n (i.e., one node per chunk), therefore # n + 1 boundaries are needed. The first bound must be 0. chunks = np.empty(N + 1, dtype=int) chunks[0] = 0 # segment index at the beginning of each chunk chusegs = np.empty(N, dtype=int) chusegs[0] = 0 args3 = (ancs, ancx, segs, lvls) for k in range(nest_th, flat_th): adk_func(n, k, dm, adk, tree, order) itag = _bal_min_branch(n, lens, *args1, order) tag = order[itag] size = sizes[tag] # Get the depth of target, which equals to the number of ancestors of it. deep = deeps[tag] # Navigate the tree from target upward to root to identify the "spine", to # calculate special values and intermediates _bal_insert_plan(n, itag, *args1, *args2, pairs, diffs, *args3, oops, True) # Distribute nodes into chunks such that they have roughly even workloads. nc = _bal_avgdist_chunk( n, itag, order, sizes, pairs, segs, lvls, oops, enc, chunks, chusegs ) _bal_update_spine(tag, deep, sizes, pairs, ancs) lvls[deep] = -1 # do this for target clade # Update balanced average distance matrix through parallelization. _bal_avgdist_nest( itag, deep, adm, *args2, diffs, npots, *args3, nc, chunks, chusegs ) _insert_taxon(k, itag, size, tree, order) n += 2 ### Phase 3: Parallel (nested and flat) ### # index of node with minimum length change within each clade roots = np.empty(N, dtype=int) roots[0] = 0 # minimum length change within each clade. rlens = np.empty(N, dtype=dtype) rlens[0] = 0 # index of root that marks each clade clades = np.empty(N, dtype=int) for k in range(flat_th, m): adk_func(n, k, dm, adk, tree, order) # Find the branch with minimum length change (parallel). itag = _bal_min_branch_p( n, lens, *args1, order, sizes, enc, clades, chunks, roots, rlens ) tag = order[itag] size = sizes[tag] deep = deeps[tag] # Navigate the tree from target upward to root to identify the "spine", to # calculate special values and intermediates _bal_insert_plan(n, itag, *args1, *args2, pairs, diffs, *args3, oops, False) # Distribute nodes into chunks such that they have roughly even workloads. nc = _bal_avgdist_chunk( n, itag, order, sizes, pairs, segs, lvls, oops, enc, chunks, chusegs ) _bal_update_spine(tag, deep, sizes, pairs, ancs) lvls[deep] = -1 # Update balanced average distance matrix through parallelization (both flat # and nested). _bal_avgdist_flat(n, itag, size, order, adm, adk, diffs, deeps) _bal_avgdist_nest( itag, deep, adm, *args2, diffs, npots, *args3, nc, chunks, chusegs ) _insert_taxon(k, itag, size, tree, order) n += 2 ### Calculate branch lengths. ### _bal_lengths(lens, adm, tree) return tree, lens def _fastnni(dm, tree, order, lens): r"""Perform fast nearest neighbor interchange (FastNNI) on a tree. To improve the tree under the minimum evolution (ME) criterion using an OLS framework on a distance matrix between taxa. This algorithm was implemented following Section 2.2 and Appendix 4 of Desper and Gascuel (2002). Basically, it creates a full average distance matrix between all pairs of subtrees, evaluates all possible swaps, then iteratively performs swaps that lead to the maximum reduction of overall branch lengths. During this process, it needs to update the evaluation of the four corner branches after one branch is swapped. --- The swaps that can reduce overall branch length are stored in a heap. The paper suggests using a maxheap, but the following code uses Python's heapq which is a minheap. Therefore the length changes are negated (in contrast to `_bnni`). Each item in the heap is a tuple consisting of: 0. Length change (negative; smaller is better) 1. Corresponding node index 2. Corresponding side (0: left, 1: right) of child to swap with sibling For example, (-0.15, 7, 1) means that swapping the right child and the sibling of node 7 will reduce the overall branch length by 0.15. Meanwhile, the length change of each node is stored in `lens`. For root and tips, this value is 0. For internal nodes, this value is negative or 0. Only negative values are stored in the heap. 0 means this node is not useful. Additionally, the side information is stored in `sides`. When a swap is updated, the new length change (if negative) is pushed into the heap, but the old length change won't be deleted from the heap (which would be inefficient as O(n)). Instead, a "lazy deletion" mechanism is adopted: When the negative-most swap is popped out of the heap, it is checked against the stored length change (in `lens`) and side (in `sides`). If they don't match, then it means that it is outdated and should be skipped. Otherwise, it is considered relevant and the swap will be performed. TODO: heapq is a Python module and may not be efficient. Tests showed that the code isn't significantly faster than a naive `np.argmax` on then entire `lens`. Consider optimization. TODO: It should be feasible to rely on `order` alone without `index`, which will save multiple O(n) operations (see `_swap_branches` for details). Implementation will be less straightforward compared with `_gme` and `_bme`. This is because branch length changes are associated with original nodes, not preorder. Updating preorder will change this association. A workaround is to track the preorder of a node via an O(n) search during each iteration, which should be cheaper than the current method (updating `index` via memory reads / writes). """ dtype = dm.dtype n = tree.shape[0] # preorder index index = np.empty(n, dtype=int) index[order] = np.arange(n) # taxon counts tacts = np.empty(n, dtype=int) _calc_tacts(n, tree, order, tacts) # child side (left: 0, right: 1) of each node to swap sides = np.empty(n, dtype=int) # intermediate array stack = np.empty(n, dtype=int) # Calculate average distances between all pairs of subtrees. adm = np.empty((n, n), dtype=dtype) _avgdist_matrix(adm, dm, tree, order, tacts) # Calculate length changes of all possible swaps. _ols_all_swaps(lens, adm, tree, tacts, sides) # Create a heap that stores negative length changes and their nodes and sides. heap = [(lens[i], i, sides[i]) for i in np.flatnonzero(lens)] heapify(heap) # Iteratively swap branches until there is no more beneficial swap. while heap: # Pop the swap that reduces the most length. L, target, side = heappop(heap) # Skip if this swap is outdated. if L != lens[target] or side != sides[target]: continue # Reset this swap. lens[target] = 0 # Swap the branches in the tree. _swap_branches(target, side, tree, order, index, stack, tacts=tacts) # Update average distances after swapping. _avgdist_swap(index[target], side, adm, tree, order, tacts) # Update length reductions of swaps of the four corner branches. _ols_corner_swaps(target, heap, lens, adm, tree, tacts, sides) # Calculate branch lengths using an OLS framework. _ols_lengths(lens, adm, tree, tacts) def _bnni(dm, tree, order, lens): r"""Perform balanced nearest neighbor interchange (BNNI) on a tree. To improve the tree under the balanced minimum evolution (BME) criterion given a distance matrix between taxa. Implemented according to Section 3.2 and Appendix 5 of Desper and Gascuel (2002). Basically, BNNI is similar to FastNNI (see `_fastnni`), but it needs to update more than the four corner branches after each swap, as balanced average distances are dependent on the topology of the tree. --- The original paper doesn't explain how to store and update positive swaps. Because a large proportion of swaps need to be re-evaluated during every iteration, one would expect that a heap structure as suggested for the FastNNI algorithm may not be efficient. The current code simply stores all swaps (positive or not) and runs `np.argmax` on all of them during each iteration. """ dtype = dm.dtype m = dm.shape[0] n = tree.shape[0] # preorder index index = np.empty(n, dtype=int) index[order] = np.arange(n) # node counts sizes = np.empty(n, dtype=int) _calc_sizes(n, tree, order, sizes) # node depths deeps = np.empty(n, dtype=int) _calc_deeps(n, tree, order, deeps) # Identify all internal branches (those above nodes that are not tips or root). # The association between nodes and internal branches are fixed, no matter how tree # is swapped. # For a tree with m taxa (including root), there should be m - 3 internal branches. nodes = np.flatnonzero(tree[1:, 0]) + 1 nb = nodes.shape[0] # overall tree length reduction (larger is better) gains = np.zeros(nb, dtype=dtype) # child side (left: 0, right: 1) of each node to swap sides = np.empty(nb, dtype=int) # Calculate balanced average distances between all pairs of subtrees. adm = np.empty((n, n), dtype=dtype) _bal_avgdist_matrix(adm, dm, tree, order, sizes) # Pre-calculate negative powers of 2. npots = np.ldexp(dtype.type(1.0), -np.arange(m)) stack = np.empty(n, dtype=int) # Iteratively swap branches until there is no more beneficial swap. while True: # Calculate length reductions of all possible swaps. _bal_all_swaps(gains, sides, nodes, adm, tree) # Find the swap with the maximum length reduction, and stop if non-positive. branch = gains.argmax() if gains[branch] <= 0: break target, side = nodes[branch], sides[branch] # Swap the branches in the tree. _swap_branches( target, side, tree, order, index, stack, sizes=sizes, deeps=deeps ) # Update balanced average distances after swapping. _bal_avgdist_swap( adm, target, side, tree, order, index, sizes, deeps, npots, stack ) # Calculate branch lengths using a balanced framework. _bal_lengths(lens, adm, tree) def _to_treenode(tree, taxa, lens=None, unroot=False): r"""Convert an array-based tree structure into a TreeNode object. Parameters ---------- tree : (n, 2+) array_like of int Tree structure. taxa : list of str Taxon names in order. lens : (n,) array_like of float, optional Branch lengths. unroot : bool, optional If True, generate an unrooted tree in which the root node has three children, the last of which is the first taxon. Otherwise leave the first taxon at the root node. Returns ------- TreeNode Converted TreeNode object. See Also -------- TreeNode Notes ----- This function only needs the first two columns (left child, right child / taxon name) of a tree array to generate a TreeNode object. """ nodes = [TreeNode(taxa[0])] + [ TreeNode(None if a else taxa[b]) for a, b in tree[1:, :2] ] if lens is not None: for node, L in zip(nodes, lens): node.length = L for node, (left, right, *_) in zip(nodes, tree): if left: node.extend([nodes[left], nodes[right]], uncache=False) tree = nodes[0] if unroot: tree.append(TreeNode(taxa[0], length=tree.length), uncache=False) tree.name = None tree.length = None return tree def _from_treenode(obj, taxmap, tree, pos=0): r"""Convert a TreeNode object into an array-based tree structure. Parameters ---------- tree : TreeNode Input tree. It must be strictly bifurcating. taxmap : dict of str : int Mapping of taxon names to indices. tree : (n, 4) ndarray of int Tree structure. pos : int, optional Position (axis 0) in the tree array for new data. Returns ------- int Number of nodes in the tree. Raises ------ ValueError If tree is not strictly bifurcating. See Also -------- _root_from_treenode Notes ----- This function fills in a pre-allocated tree array. It doesn't return any value. Nodes in the tree array follows preorder. This may not agree with the order they were added to the original tree, if that ever happened. Therefore, one shouldn't directly compare the original and generated tree arrays. However, the topologies represented by the two tree arrays should be identical. The function doesn't fill branch lengths, which aren't required by the downstream algorithms. Adding this functionality should be straightforward. Parameter ``pos`` is typically set by :func:`_root_from_treenode`. One doesn't need to specify it if working with this function alone. """ # create root node tree[pos, 2] = 0 tree[pos, 3] = 0 # if root node is a tip, just wrap up and return if not obj.children: tree[pos, 0] = 0 tree[pos, 1] = taxmap[obj.name] return 1 # Perform preorder traversal, index nodes, fill parent (2) and taxon (1). obj._i = pos pos_1 = pos + 1 for i, node in enumerate(obj.preorder(include_self=False)): node._i = ni = pos_1 + i tree[ni, 2] = node.parent._i if not node.children: tree[ni, 0] = 0 tree[ni, 1] = taxmap[node.name] size = ni - pos + 1 # Perform postorder traversal, fill children (0 and 1) and sibling (3). for i, node in enumerate(obj.postorder()): ni = node._i if node.children: try: left, right = node.children except ValueError: raise ValueError("Tree is not strictly bifurcating.") li, ri = left._i, right._i tree[ni, 0] = tree[ri, 3] = li tree[ni, 1] = tree[li, 3] = ri del left._i del right._i del obj._i return size def _root_from_treenode(obj, taxa): r"""Convert a TreeNode object into a tree array rooted at the first taxon. Parameters ---------- tree : TreeNode Input tree. It must be strictly bifurcating. taxa : list of str Taxon names in order (usually as in a distance matrix). Returns ------- (n, 4) ndarray of int Tree structure. Raises ------ ValueError If tree is not strictly bifurcating. See Also -------- _from_treenode TreeNode.unrooted_move Notes ----- This function locates the first taxon in the tree, walks from it to the root, and rotate nodes along the path such that the first taxon becomes the new root in the generated tree array. For example (p: parent, c: clade): root taxon / | \ / \ c3 p2 c4 c1 p2 / \ => / \ c2 p1 c2 root / \ / \ taxon c1 c3 c4 Note that the original parent node always becomes the right child of the current node. The first parent (p1) is gone and replaced by the taxon. The output array is always preordered. """ errmsg = "Tree is not strictly bifurcating." taxmap = {taxon: i for i, taxon in enumerate(taxa)} m = len(taxa) # number of taxa n = m * 2 - 3 # number of nodes # single-child root node is not supported if len(obj.children) == 1: raise ValueError(errmsg) # allocate tree array tree = np.empty((n, 4), dtype=int) # position of the current node pos = 0 # position of the previous node prev_pos = 0 # position of the other child of the previous node in the path; # it will become the sibling of the current node sib_pos = 0 # helper to add the current node to the array def _add_current(): tree[pos, 2] = prev_pos tree[prev_pos, 1] = pos tree[sib_pos, 3] = pos tree[pos, 3] = sib_pos # iterate over ancestors of the first taxon curr = obj.find(taxa[0]) parent = None while True: prev = curr curr = curr.parent parent = curr.parent siblings = [x for x in curr.children if x is not prev] if not siblings: # singleton branch raise ValueError(errmsg) n_sibs = len(siblings) if n_sibs == 1: other = siblings[0] # Current node is a regular internal node of the tree (the typical case): # Add the current node, then add the other child of it. # parent prev # | | # curr => curr # / \ / \ # other prev other parent if parent is not None: _add_current() prev_pos = pos pos += 1 # add the other child clade size = _from_treenode(other, taxmap, tree, pos) tree[pos - 1, 0] = pos # curr's left child tree[pos, 2] = pos - 1 # parent (now missing sibling) sib_pos = pos pos += size # Current node is the root of a rooted tree (i.e., it has two children): # Don't add the current node, instead add the other child. # curr prev # / \ => / # other prev other else: _from_treenode(other, taxmap, tree, pos) tree[pos, 2] = prev_pos tree[prev_pos, 1] = pos tree[sib_pos, 3] = pos tree[pos, 3] = sib_pos break elif n_sibs == 2: # Current node is the root of an unrooted tree (i.e., it has three # children): Add the current node, then add the other two children of it. # prev # curr | # / | \ => curr # left right prev / \ # left right if parent is None: _add_current() curr_pos = pos pos += 1 left, right = siblings size = _from_treenode(left, taxmap, tree, pos) tree[pos, 2] = curr_pos left_pos = pos tree[curr_pos, 0] = pos pos += size _from_treenode(right, taxmap, tree, pos) tree[pos, 2] = curr_pos tree[curr_pos, 1] = pos tree[left_pos, 3] = pos tree[pos, 3] = left_pos break else: raise ValueError(errmsg) else: raise ValueError(errmsg) return tree def _insert_taxon_treenode(taxon, target, tree): r"""Insert a taxon between a target node and its parent. This function resembles :func:`_insert_taxon` but operates on a TreeNode object. It is for test purpose. It is not used in the actual algorithms. """ link = TreeNode() tip = TreeNode(taxon) parent = target.parent if parent is None: # root branch link.extend(tree.children) tree.append(link) tree.append(tip) else: # other branch is_left = target is parent.children[0] link.append(target) link.append(tip) parent.append(link) if is_left: parent.children = parent.children[::-1] def _avgdist_matrix_naive(adm, dm, tree, order, tacts): r"""Calculate a matrix of average distances between all pairs of subtrees. This function produces the same result as :func:`_avgdist_matrix`. However, it calculates all subtree-to-subtree distances based on the original taxon-to-taxon distances, as discussed in Eq. 1 of Desper and Gascuel (2002). instead of adopting a recursive strategy (Eq. 2). Therefore, it is significantly slower. d(A, B) = \frac{1}{|A||B|} \sum_{i \in A, j \in B} d(i, j) This algorithm is implemented as a reference and for comparison purpose. It is not used in the actual GME algorithm. """ n = tacts[0] * 2 - 1 taxas = {} # iterate over nodes in reversed preorder (same outcome as postorder) for node in order[n - 1 :: -1]: left, right = tree[node, 0], tree[node, 1] if not left: taxas[node] = frozenset([right]) else: taxas[node] = taxas[left] | taxas[right] full = taxas[0] | frozenset([0]) for a in range(n): a_taxa = taxas[a] a_taxa_r = full - a_taxa # adm[a, a] = dm[list(a_taxa)][:, list(a_taxa_r)].mean() # self distance for b in range(a + 1, n): # If a is an ancestor (proper superset) of b, flip a's taxon set as the # the upper subtree of a will be considered. a_taxa_ = a_taxa_r if a_taxa > (b_taxa := taxas[b]) else a_taxa adm[a, b] = adm[b, a] = dm[list(a_taxa_)][:, list(b_taxa)].mean() # Because this is postorder traversal, a cannot be a descendant (proper # subset) of b. def _avgdist_taxon_naive(adk, taxon, dm, tree, order, tacts): """Calculate average distances between a new taxon and existing subtrees. This function produces the same result as :func:`_avgdist_taxon`, but it calculates all taxon-to-subtree distances based on the original taxon-to-taxon distances, as discussed in Eq. 1 of Desper and Gascuel (2002), instead of adopting a recursive strategy (Eq. 2). Therefore, it is significantly slower. This algorithm is implemented as a reference and for comparison purpose, but not used in the actual GME algorithm. """ n = tacts[0] * 2 - 1 taxas = {} # iterate over nodes in reversed preorder (same outcome as postorder) for node in order[n - 1 :: -1]: left, right = tree[node, :2] if not left: taxas[node] = frozenset([right]) else: taxas[node] = taxas[left] | taxas[right] full = taxas[0] | frozenset([0]) adkl, adku = adk[0], adk[1] dk = dm[taxon] for node in range(n): taxa_lower = taxas[node] adkl[node] = dk[list(taxa_lower)].mean() taxa_upper = full - taxa_lower adku[node] = dk[list(taxa_upper)].mean() def _swap_branches_treenode(node1, node2): """Swap two nodes in a TreeNode object. This function is for testing purpose. """ parent1, parent2 = node1.parent, node2.parent parent1.append(node2, False) parent2.append(node1, False) def _swap_branches( target, side, tree, order, index, stack, tacts=None, sizes=None, deeps=None ): r"""Swap one child of the target node with its sibling. | | parent parent / \ / \ target sibling => target child / \ / \ other child other sibling Target must be an internal node. Root and tips are not allowed. This function is specifically designed for nearest neighbor interchange (NNI). It may be generalized to swapping non-neighbor branches, but that is not currently implemented. For FastNNI (OLS framework), provide `tacts`. For BNNI (balanced framework), provide `sizes` and `deeps`. TODO: This function may be Cythonized to improve efficiency. TODO: This function updates both preorder (`order`) and preorder index (`index`), both of which are O(n). It is technically feasible to update `order` only, which can be more efficiently done via `memmove`. Refer to `_insert_taxon`. """ # This function can potentially be optimized using Cython. See `_insert_taxon`. if tacts is None and sizes is None: raise ValueError("Must provide either tacts or sizes.") if tacts is not None and sizes is not None: raise ValueError("Cannot provide tacts and sizes simultaneously.") child = tree[target, side] other = tree[target, 1 - side] # other child parent = tree[target, 2] sibling = tree[target, 3] # update connections tree[target, side] = sibling tree[target, 3] = child # update taxon count if tacts is not None: c_tact = tacts[child] o_tact = tacts[other] s_tact = tacts[sibling] tacts[target] += s_tact - c_tact c_size = c_tact * 2 - 1 o_size = o_tact * 2 - 1 s_size = s_tact * 2 - 1 # update node count if sizes is not None: c_size = sizes[child] o_size = sizes[other] s_size = sizes[sibling] sizes[target] += s_size - c_size p_side = int(tree[parent, 0] == target) # sibling side of parent tree[parent, p_side] = child tree[sibling, 2] = target tree[sibling, 3] = other tree[child, 2] = parent tree[child, 3] = target tree[other, 3] = sibling # locate the clades under the relevant nodes c_start = index[child] c_end = c_start + c_size c_clade = order[c_start:c_end] s_start = index[sibling] s_end = s_start + s_size s_clade = order[s_start:s_end] o_start = index[other] o_end = o_start + o_size o_clade = order[o_start:o_end] # update depths if deeps is not None: deeps[c_clade] -= 1 deeps[s_clade] += 1 # update preorder (naive) # _preorder(order, tree, stack) # index[order[:n]] = np.arange(n) # update preorder # sibling is the left child of parent if p_side == 0: index[target] += c_size - s_size stack[:c_size] = c_clade stack[c_size] = target c1_width = c_size + 1 # sibling_clade, target, child_clade, other_clade => # child_clade, target, sibling_clade, other_clade if side == 0: index[s_clade] += c_size + 1 index[c_clade] -= s_size + 1 order[(sc1_start := s_start + c1_width) : c_end] = s_clade order[s_start:sc1_start] = stack[:c1_width] # sibling_clade, target, other_clade, child_clade => # child_clade, target, other_clade, sibling_clade else: index[s_clade] += c_size + o_size + 1 index[c_clade] -= s_size + o_size + 1 index[o_clade] += c_size - s_size stack[c1_width : (c1o_width := c1_width + o_size)] = o_clade order[(sc1o_start := s_start + c1o_width) : c_end] = s_clade order[s_start:sc1o_start] = stack[:c1o_width] # sibling is the right child of parent else: stack[:s_size] = s_clade # target, child_clade, other_clade, sibling_clade => # target, sibling_clade, other_clade, child_clade if side == 0: index[c_clade] += (so_width := s_size + o_size) index[s_clade] -= c_size + o_size index[o_clade] += s_size - c_size stack[s_size:so_width] = o_clade order[(cso_start := c_start + so_width) : s_end] = c_clade order[c_start:cso_start] = stack[:so_width] # target, other_clade, child_clade, sibling_clade => # target, other_clade, sibling_clade, child_clade else: index[c_clade] += s_size index[s_clade] -= c_size order[(cs_start := c_start + s_size) : s_end] = c_clade order[c_start:cs_start] = stack[:s_size] scikit-bio-scikit-bio-a3beaa6/skbio/tree/_nj.py000066400000000000000000000303031520735541300215400ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np from skbio.tree import TreeNode from skbio.util._decorator import params_aliased from skbio.util._warning import _warn_deprecated from skbio.stats.distance import DistanceMatrix from ._c_nj import nj_minq_cy from ._utils import _validate_dm @params_aliased([("neg_as_zero", "disallow_negative_branch_length", "0.6.3", True)]) def nj( dm, neg_as_zero=True, result_constructor=None, inplace=False, ): r"""Perform neighbor joining (NJ) for phylogenetic reconstruction. Parameters ---------- dm : skbio.DistanceMatrix Input distance matrix containing pairwise distances among taxa. neg_as_zero : bool, optional If True (default), convert negative branch lengths into zeros. result_constructor : function, optional Function to apply to construct the result object. This must take a newick-formatted string as input. Deprecated and to be removed in a future release. .. deprecated:: 0.6.3 inplace : bool, optional If True, the input distance matrix will be manipulated in-place to reduce memory consumption, at the cost of losing the original data. Default is False. .. versionadded:: 0.6.3 Returns ------- TreeNode Reconstructed phylogenetic tree. .. versionchanged:: 0.6.3 The NJ algorithm has been optimized. The output may be slightly different from the previous version in root placement, node ordering, and the numeric precision of branch lengths. However, the overall tree topology and branch lengths should remain the same. See Also -------- bme upgma TreeNode.root_at_midpoint Notes ----- Neighbor joining (NJ) was initially described by Saitou and Nei (1987) [1]_. It is a simple and efficient agglomerative clustering method that builds a phylogenetic tree based on a distance matrix. This function implements the canonical NJ method. The algorithm has been optimized to improve efficiency, but no heuristic was involved to further accelerate it at the cost of accuracy. Therefore, one is guaranteed to obtain an optimal tree. The algorithm is *O*\(*n*:sup:`3`) in time and *O*\(*n*:sup:`2`) in space. NJ generates an **unrooted** tree with varying tip heights. This contrasts UPGMA (:func:`upgma`), which always produces ultrametric trees. One may subsequently use choice of strategies such as midpoint rooting (:meth:`~TreeNode.root_at_midpoint`) or outgroup rooting (:meth:`~TreeNode.root_by_outgroup`) to convert the result into a rooted tree. NJ is most accurate when distances are **additive** -- the distance between two taxa in the matrix equals to the sum of branch lengths connecting them in the tree. When this assumption is violated, which is common in real studies, negative branch lengths may be produced, challenging interpretation and subsequent analyses. To address this issue, this function converts negative branch lengths into zeros by default, but this behavior can be disabled by setting ``neg_as_zero`` to False. Gascuel and Steel (2006) provide a detailed overview of neighbor joining in terms of its biological relevance and limitations [2]_. They proved that NJ is a greedy heuristic to the balanced minimum evolution (BME) problem. An alternative heuristic solution to this problem is provided by :func:`bme`. The example presented here is derived from the Wikipedia page on neighbor joining [3]_. References ---------- .. [1] Saitou, N., & Nei, M. (1987). The neighbor-joining method: a new method for reconstructing phylogenetic trees. Mol Biol Evol, 4(4), 406-425. .. [2] Gascuel, O., & Steel, M. (2006). Neighbor-joining revealed. Mol Biol Evol, 23(11), 1997-2000. .. [3] http://en.wikipedia.org/wiki/Neighbour_joining Examples -------- Define a new distance matrix object describing the distances between five taxa: a, b, c, d, and e. >>> from skbio import DistanceMatrix >>> from skbio.tree import nj >>> data = [[0, 5, 9, 9, 8], ... [5, 0, 10, 10, 9], ... [9, 10, 0, 8, 7], ... [9, 10, 8, 0, 3], ... [8, 9, 7, 3, 0]] >>> ids = list('abcde') >>> dm = DistanceMatrix(data, ids) Construct the neighbor joining tree representing the relationship between those taxa. This is returned as a TreeNode object. >>> tree = nj(dm) >>> print(tree.ascii_art()) /-a /--------| /--------| \-b | | | \-c ---------| |--e | \-d """ if result_constructor is not None: msg = ( "`result_constructor` is deprecated and will be removed in a future " "release." ) _warn_deprecated(nj, "0.6.3", msg) _validate_dm(dm) taxa = list(dm.ids) # convert to redundant form for now if dm._flags["CONDENSED"]: dm = DistanceMatrix(dm) dm_ = dm.data if not inplace: dm_ = dm_.copy() lm = _nj(dm_) tree = _tree_from_linkmat(lm, taxa, rooted=False, neg_as_zero=neg_as_zero) if result_constructor is not None: tree = result_constructor(str(tree)) return tree def _nj(dm): r"""Perform neighbor joining (NJ) for phylogenetic reconstruction. Parameters ---------- dm : (N, N) ndarray Input distance matrix. Returns ------- ndarray of shape (N - 1, 4) Linkage matrix representing the tree. Notes ----- This function manipulates the distance matrix in-place. Therefore, one should make a copy prior to running the function if the original distance matrix needs to be preserved. """ # This function re-uses the original array space during iteration, without creating # additional intermediate arrays. Therefore, it is memory-efficient, and avoids the # time overhead of allocating new memory space. # This function only operates on arrays of numbers, therefore it can be further # Cythonized. However, Cythonization did not bring significant performance gain in # tests, likely because all operations already utilize NumPy APIs. That being said, # further optimization and testing should be convenient. N = n = dm.shape[0] # dimension sums = dm.sum(axis=0) # distance sums idxs = np.arange(N) # cluster indices lm = np.empty((N - 1, 4), dtype=dm.dtype) # linkage matrix # Iteratively merge taxa until there are three left. while n > 3: # Create memory views of currently relevant array areas. dm_ = dm[:n, :n] sums_ = sums[:n] idxs_ = idxs[:n] # Find the minimum value of the Q-matrix and return its position (i, j). # Q(i, j) = (n - 2) d(i, j) - \sum d(i) - \sum d(j) # The function call avoids constructing the entire Q-matrix, but instead # computes values and finds the minimum as the computation goes. i, j = nj_minq_cy(dm_, sums_) # Get half of the original distance at (i, j). d_ij_ = dm[i, j] / 2 # Taxa i and j will be merged into a cluster {i, j}. The updated distance from # cluster to any other taxon k is: # d({i, j}, k) = (d(i, k) + d(j, k) - d(i, j)) / 2 # We first compute (d(i, k) + d(j, k)) / 2 and save the results in row i. dm_[i] += dm_[j] dm_[i] /= 2 # Compute branch lengths of taxa i and j. # \delta = (\sum d(i) - \sum d(j)) / (2(n - 2)) # L(i) = d(i, j) / 2 + \delta # L(j) = d(i, j) / 2 - \delta delta_ = (sums_[i] - sums_[j]) / (2 * n - 4) L_i = d_ij_ + delta_ L_j = d_ij_ - delta_ # The previously calculated sums can be updated for re-use. Specifically, for # taxon k, there is: # new sum = old sum - d(i, k) - d(j, k) + d({i,j}, k) # = old sum - d(i, k) - d(j, k) + (d(i, k) + d(j, k) - d(i, j)) / 2 # = old sum - (d(i, k) + d(j, k)) / 2 - d(i, j) / 2 # We already have (d(i, k) + d(j, k)) / 2 stored in row i, therefore: sums_[:] -= dm_[i] sums_[:] -= d_ij_ # Now complete the calculation of the updated distances d({i, j}, k). dm_[i] -= d_ij_ # Update column i to match row i. dm_[:, i] = dm_[i] # Because two taxa have been merged into one cluster, we will shrink the # distance matrix from (n, n) to (n - 1, n - 1). Specifically, we will move # the last row/column (index: n - 1) to row/column j. n_1 = n - 1 dm_[j] = dm_[n_1] dm_[:, j] = dm_[:, n_1] # Also move the last sum to j. sums_[j] = sums_[n_1] # Then calculate the updated sum at i (now cluster {i, j}), which is the sum # of the updated distances. sums_[i] = dm_[i, :n_1].sum() # Store the taxa and branch lengths to the linkage matrix. lm[N - n] = idxs_[i], idxs_[j], L_i, L_j # Update cluster indices. Specifically, position i will have the new cluster # index. Meanwhile, position j will be replaced with the last cluster. idxs_[i] = 2 * N - n idxs_[j] = idxs_[n_1] n -= 1 # Perform final calculation on the three remaining taxa. They will become children # of the root node, and the entire tree is unrooted. L_0 = (dm[0, 1] + dm[0, 2] - dm[1, 2]) / 2 lm[N - 3] = idxs[1], idxs[2], dm[0, 1] - L_0, dm[0, 2] - L_0 lm[N - 2] = idxs[0], 2 * N - 3, L_0, 0 return lm def _tree_from_linkmat(lm, taxa, rooted=True, neg_as_zero=True): r"""Convert a linkage matrix into a tree structure. Parameters ---------- lm : (N, 4) array_like Linkage matrix. taxa : list of str Taxon names. rooted : bool, optional If True (default), will generate a rooted binary tree, with two children attached to the root node. If False, will generate an unrooted tree with three children attached to the root node. neg_as_zero : bool, optional Convert negative branch lengths to zero. Returns ------- TreeNode Converted phylogenetic tree. See Also -------- TreeNode.from_linkage_matrix Notes ----- The linkage matrix data structure resembles that used in SciPy's hierarchical clustering, but also stores the branch lengths of both children, which could be unequal in a phylogenetic tree. In SciPy's linkage matrix, the four elements per row are (see: https://stackoverflow.com/questions/9838861/): cluster1, cluster2, length1+2, # original taxa In the current data structure, they are: cluster1, cluster2, length1, length2 """ # allocate node list nodes = [TreeNode(name=x) for x in taxa] + [TreeNode() for _ in range(len(lm))] # build tree incrementally idx = len(taxa) for c1, c2, L1, L2 in lm if rooted else lm[:-2]: c1, c2 = nodes[int(c1)], nodes[int(c2)] if neg_as_zero: c1.length = L1 if L1 >= 0 else 0.0 c2.length = L2 if L2 >= 0 else 0.0 else: c1.length, c2.length = L1, L2 nodes[idx].extend([c1, c2], uncache=False) idx += 1 # final treatment of an unroot tree (root is trifurcating) if not rooted: # this code assumes that the first element of the last row is the node # see the end of _nj (c0, _, L0, _), (c1, c2, L1, L2) = lm[-1], lm[-2] c0, c1, c2 = nodes[int(c0)], nodes[int(c1)], nodes[int(c2)] if neg_as_zero: c0.length = L0 if L0 >= 0 else 0.0 c1.length = L1 if L1 >= 0 else 0.0 c2.length = L2 if L2 >= 0 else 0.0 else: c0.length, c1.length, c2.length = L0, L1, L2 nodes[-1].extend([c0, c1, c2], uncache=False) return nodes[-1] scikit-bio-scikit-bio-a3beaa6/skbio/tree/_tree.py000066400000000000000000006500551520735541300221040ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from operator import ne, gt, itemgetter from copy import copy, deepcopy from itertools import chain, combinations from collections import defaultdict, deque from typing import Any, TYPE_CHECKING import numpy as np import pandas as pd from skbio._base import SkbioObject from skbio.stats.distance import DistanceMatrix from skbio.tree._exception import ( NoLengthError, DuplicateNodeError, NoParentError, MissingNodeError, TreeError, ) from skbio.util._decorator import ( classonlymethod, register_aliases, aliased, params_aliased, ) from skbio.io.descriptors import Read, Write from ._compare import ( _check_dist_metric, _check_shuffler, _topo_dists, _path_dists, ) if TYPE_CHECKING: # pragma: no cover from collections.abc import Sequence, Iterable, Callable, Iterator from numpy.typing import ArrayLike from typing import Self # ---------------------------------------------------------------------------- # Important note: The TreeNode class has a large number of methods. They are # organized under several categories, which are defined in this script as well # as in `doc/source/_templates/TreeNode.rst`, which is a template file for the # documentation. When methods are added, removed or re-organized, one needs to # edit the template file to reflect the changes. # ---------------------------------------------------------------------------- @register_aliases class TreeNode(SkbioObject): r"""Represent a node within a tree. A ``TreeNode`` instance stores links from a node to its parent node and optionally child nodes. In addition, it can represent the length of the branch connecting itself and its parent, and the support of this branch. Parameters ---------- name : str or None Name of the node. It is common for tips in particular to have names, for instance, in a phylogenetic tree where the tips correspond to taxa. Internal nodes and the root may also have names. length : float, int, or None Length of the branch connecting this node to its parent. Can represent elapsed time, amount of mutations, or other measures of evolutionary distance. support : float, int, or None Support value of the branch connecting this node to its parent. Can be bootstrap value, posterior probability, or other measures of the confidence or frequency of this branch. parent : TreeNode or None Parent node to which this node is connected. A node without a parent is the root of the tree. children : list of TreeNode or None Child nodes to which this node is connected. A node without any children is a tip (leaf) of the tree. Notes ----- A tree is a graph in which any two nodes (vertices) are connected by exactly one path. The ``TreeNode`` class is capable of representing various tree structures, including binary trees, phylogenetic trees, and other hierarchical systems such as taxonomies and ontologies. While the class is versatile, many of its terms and methods are specifically designed for phylogenetic analysis. In scikit-bio, trees are modeled as a collection of interconnected ``TreeNode`` objects, each representing a single node in the tree. There is no explicit class for the entire tree, a clade, or a branch (edge). Instead, a tree is implicitly defined by its root node, from which the entire tree can be traversed. Starting from any node, one can navigate up to its parent and ancestors, down to its children and descendants, or sideways to its siblings. The underlying data structure of a tree composed of ``TreeNode`` objects is an ordered, rooted tree. However, the ``TreeNode`` class has the flexibility to handle unrooted and unordered trees as well, which are common in phylogenetics. """ default_write_format = "newick" """Default write format for this object: ``newick``.""" read = Read() write = Write() # Methods of TreeNode involves various temporary attributes added to or removed # from instances of this class. The following code informs mypy that this class # may have arbitrary attributes. if TYPE_CHECKING: # pragma: no cover def __getattr__(self, name: str) -> Any: raise AttributeError(name) def __setattr__(self, name: str, value: Any) -> None: object.__setattr__(self, name, value) def __delattr__(self, name: str) -> None: object.__delattr__(self, name) def __init__( self, name: str | None = None, length: float | int | None = None, support: float | int | None = None, parent: TreeNode | None = None, children: list[TreeNode] | None = None, ): self.name = name self.length = length # TODO: `support` doesn't need to be a default attribute. self.support = support self.parent = parent self.children: list[TreeNode] = [] # TODO: `id` doesn't need to be a default attribute. self.id = None # TODO: This could skip cache clearing. if children is not None: self.extend(children) def __repr__(self): r"""Return summary of the tree. Returns ------- str A summary of this node and all descendants Notes ----- This method returns the name of the node and a count of tips and the number of internal nodes in the tree. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c, d)root;"]) >>> repr(tree) '' """ nodes = [n for n in self.traverse(include_self=False)] n_tips = sum([n.is_tip() for n in nodes]) n_nontips = len(nodes) - n_tips classname = self.__class__.__name__ name = self.name if self.name is not None else "unnamed" return "<%s, name: %s, internal node count: %d, tips count: %d>" % ( classname, name, n_nontips, n_tips, ) def __str__(self): r"""Return a Newick string of self, with names and distances.""" return str("".join(self.write([]))) def __iter__(self): r"""Iterate over the children of self.""" return iter(self.children) def __len__(self): """Return the number of children of self.""" return len(self.children) def __getitem__(self, i): r"""Slice the children of self.""" return self.children[i] # ------------------------------------------------ # Tree copying # ------------------------------------------------ # node attributes that should not be copied _exclude_from_copy = { "name", "length", "support", "parent", "children", "id", "_tip_cache", "_non_tip_cache", "_registered_caches", } def _copy(self, deep, memo): """Return a copy of self.""" # decide deep or shallow copy _copy = deepcopy if deep else copy _args = [memo] if deep else [] # node attributes to exclude during copying # add any custom attributes that were registered as caches exclude_attrs = self._exclude_from_copy if hasattr((root := self.root()), "_registered_caches"): exclude_attrs = exclude_attrs | root._registered_caches # exclude dynamically generated methods exclude_attrs = exclude_attrs | {"_write_method"} # tree node class (default is TreeNode) # this is _possibly_ dangerous, we're assuming the node to copy is # of the same class as self, and has the same exclusion criteria. # however, it is potentially dangerous to mix TreeNode subclasses # within a tree, so... treenode = self.__class__ def __copy_node(node, parent=None): """Copy a node.""" # create a new instance by transferring built-in attributes, which can be # directly assigned res = treenode( name=node.name, length=node.length, support=node.support, parent=parent, children=None, ) res.id = node.id # copy custom attributes, which may be compound objects therefore need to # be copied # this method of iteration is slightly faster than # `for key in node.__dict__.keys() - exclude_attrs:` for key in node.__dict__: if key not in exclude_attrs: res.__dict__[key] = _copy(node.__dict__[key], *_args) return res # start with a copy of self, which will become the root (no parent) root = __copy_node(self) stack = [[root, self, len(self.children)]] stack_append = stack.append while stack: # check the top node, any children left unvisited? top = stack[-1] new_top_node, old_top_node, unvisited_children = top if unvisited_children: top[2] -= 1 old_child = old_top_node.children[-unvisited_children] new_child = __copy_node(old_child, new_top_node) new_top_node.children.append(new_child) stack_append([new_child, old_child, len(old_child.children)]) else: del stack[-1] return root def __copy__(self): """Return a shallow copy.""" return self._copy(False, {}) def __deepcopy__(self, memo): """Return a deep copy.""" return self._copy(True, memo) def copy(self, deep: bool = False) -> TreeNode: r"""Return a copy of self using an iterative approach. Parameters ---------- deep : bool, optional Whether to perform a deep (True) or shallow (False, default) copy of node attributes. .. versionadded:: 0.6.2 .. versionchanged:: 0.7.0 The default value has been changed to False. Returns ------- TreeNode A new copy of self. .. versionchanged:: 0.6.3 Node attribute caches will not be copied. See Also -------- unrooted_copy Notes ----- This method iteratively copies the current node and its descendants. That is, if the current node is not the root of the tree, only the subtree below the node, instead of the entire tree, will be copied. All nodes and their attributes except for caches will be copied. The copies are new objects rather than references to the original objects. The distinction between deep and shallow copies only applies to each node attribute. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)root;"]) >>> tree_copy = tree.copy() >>> tree_nodes = set([id(n) for n in tree.traverse()]) >>> tree_copy_nodes = set([id(n) for n in tree_copy.traverse()]) >>> print(len(tree_nodes.intersection(tree_copy_nodes))) 0 """ return self._copy(deep, {}) # ------------------------------------------------ # Tree navigation # ------------------------------------------------ def is_tip(self) -> bool: r"""Check if the current node is a tip of a tree. Returns ------- bool Whether the node is a tip. See Also -------- is_root has_children Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c);"]) >>> print(tree.is_tip()) False >>> print(tree.find('a').is_tip()) True """ return not self.children def _is_rooted(self): r"""Check if the current tree is rooted. Returns ------- bool Whether the tree is rooted. Notes ----- This method tests whether the root node of a tree has two children (rooted) or not (unrooted). The latter scenario usually involves three children (a typical unrooted tree), but could also have one (tip at root position) or more than three children (polytomy). """ return len(self.root().children) == 2 def is_root(self) -> bool: r"""Check if the current node is the root of a tree. Returns ------- bool Whether the node is the root. See Also -------- is_tip has_children Notes ----- A root is defined as a node that has no ``parent``. A tree has exactly one root. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c);"]) >>> print(tree.is_root()) True >>> print(tree.find('a').is_root()) False """ return self.parent is None def has_children(self) -> bool: r"""Check if the current node has any children. Returns ------- bool Whether the node has at least one child. See Also -------- is_tip is_root Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c);"]) >>> print(tree.has_children()) True >>> print(tree.find('a').has_children()) False """ return not self.is_tip() def root(self) -> TreeNode: r"""Return root of the tree which contains `self`. Returns ------- TreeNode The root of the tree Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)root;"]) >>> tip_a = tree.find('a') >>> root = tip_a.root() >>> root == tree True """ curr = self while (parent := curr.parent) is not None: curr = parent return curr def ancestors(self, include_self: bool = False) -> list[TreeNode]: r"""Return all ancestral nodes from self back to the root. Parameters ---------- include_self : bool, optional Whether to include the initial node in the path (default: False). Returns ------- list of TreeNode The path from self toward the root. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)g;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b -g-------| | /-d \f-------| \-e >>> tip = tree.find('a') >>> [node.name for node in tip.ancestors()] ['c', 'g'] >>> [node.name for node in tip.ancestors(include_self=True)] ['a', 'c', 'g'] """ result = [self] if include_self else [] result_append = result.append curr = self.parent while curr is not None: result_append(curr) curr = curr.parent return result def siblings(self) -> list[TreeNode]: r"""Return all nodes that are siblings of the current node. Siblings are nodes that are children of the current node's parent, except for the current node itself. Returns ------- list of TreeNode The list of sibling nodes relative to self. See Also -------- neighbors Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e,f)g)root;"]) >>> tip_e = tree.find('e') >>> [n.name for n in tip_e.siblings()] ['d', 'f'] """ if (parent := self.parent) is not None: return [x for x in parent.children if x is not self] else: return [] def neighbors(self, ignore: TreeNode | None = None) -> list[TreeNode]: r"""Return all nodes that are neighbors of the current node. Neighbors are nodes that are directly connected to the current node by one branch. They usually include parent and children of the current node, if present. One may optionally ignore one node from the result. Parameters ---------- ignore : TreeNode, optional A node to ignore. Returns ------- list of TreeNode The list of all nodes that are connected to self. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)root;"]) >>> node_c = tree.find('c') >>> [n.name for n in node_c.neighbors()] ['a', 'b', 'root'] """ if (parent := self.parent) is not None: nodes = self.children + [parent] else: nodes = self.children[:] if ignore is None: return nodes else: return [n for n in nodes if n is not ignore] @aliased("lowest_common_ancestor") @params_aliased([("nodes", "tipnames", "0.6.3", True)]) def lca(self, nodes: Iterable[TreeNode | str] | None = None) -> TreeNode: r"""Find the lowest common ancestor of a list of nodes. Parameters ---------- nodes : iterable of TreeNode or str Instances or names of the nodes of interest. Returns ------- TreeNode The lowest common ancestor of the nodes. Raises ------ MissingNodeError If some nodes cannot be found in the tree. Notes ----- Both tips and internal nodes may be provided in ``nodes``. If internal node names are provided, it is the user's responsibility to ensure that they are unique in the tree. This method considers the entire tree rather than the subtree below self. Therefore, if some nodes are not descendants of self, the LCA of nodes will be ancestral to self. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)root;"]) >>> nodes = [tree.find('a'), tree.find('b')] >>> lca = tree.lca(nodes) >>> print(lca.name) c >>> nodes = [tree.find('a'), tree.find('e')] >>> lca = tree.lca(nodes) # lca is an alias for convenience >>> print(lca.name) root """ if not nodes: raise ValueError("No node is specified.") # Keep a record of visited nodes, such that the temporary attribute assigned # to each node can be cleared after getting LCA. visited: list[TreeNode] = [] visited_append = visited.append # Path of the first node to root. LCA must be in this path. # A temporary attribute "prev" will be assigned to visited nodes. It represents # the previous node in the upward path. it = map(self.find, nodes) curr = next(it) prev = None while curr is not None: visited_append(curr) curr._prev = prev prev = curr curr = curr.parent # type: ignore[assignment] # Paths of other nodes to root. # The prev attribute no longer needs to record the previous node. It is # uniformly set as None. When the path hits a previously visited node, it will # stop. If the node is in the first path, its prev becomes None, indicating # that it has been visited more than once. for curr in it: while not hasattr(curr, "_prev"): visited_append(curr) curr._prev = None curr = curr.parent curr._prev = None # walk down from root until a node with prev as None curr = prev while (prev := curr._prev) is not None: curr = prev # clear temporary attribute for node in visited: del node._prev return curr def _path(self, other): r"""Return the path from self to other. Parameters ---------- other : TreeNode Target node. Returns ------- TreeNode LCA of self and other. list of TreeNode self (inclusive) to LCA (exclusive). list of TreeNode other (inclusive) to LCA (exclusive). Notes ----- This algorithm is optimized for finding the LCA of two nodes. Instead, :meth:`lca` is optimized for finding the LCA of multiple nodes. """ anc1 = self.ancestors(include_self=True) anc2 = other.ancestors(include_self=True) # find lowest common ancestor of the two by iterating down from root and # stopping at divergence # pos is lca's index from root + 1 lca, pos = None, None for i, (n1, n2) in enumerate(zip(reversed(anc1), reversed(anc2))): if n1 is n2: lca = n1 else: pos = i break if lca is None: raise TreeError("Could not find a path between self and other.") if pos is None: pos = i + 1 return lca, anc1[: len(anc1) - pos], anc2[: len(anc2) - pos] def path(self, other: TreeNode, include_ends: bool = False) -> list[TreeNode]: r"""Return the list of nodes in the path from self to another node. .. versionadded:: 0.6.3 Parameters ---------- other : TreeNode Final node of path. include_ends: bool, optional Whether to include the initial (self) and final (other) nodes in the list. Default is False. Returns ------- list List of TreeNode objects. See Also -------- distance Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)root;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b -root----| | /-d \f-------| \-e >>> node_1, node_2 = tree.find('a'), tree.find('d') >>> path = node_1.path(node_2) >>> print(len(path)) 3 >>> print('-'.join(x.name for x in path)) c-root-f >>> path_2 = node_1.path(node_2, include_ends=True) >>> print(len(path_2)) 5 >>> print('-'.join(x.name for x in path_2)) a-c-root-f-d """ lca, self_path, other_path = self._path(other) path = self_path + [lca] + other_path[::-1] # remove initial and final nodes if desired if include_ends is False: path = path[1:-1] return path # ------------------------------------------------ # Tree traversal # ------------------------------------------------ def traverse( self, self_before: bool = True, self_after: bool = False, include_self: bool = True, ) -> Iterator[TreeNode]: r"""Traverse over tree. Parameters ---------- self_before : bool, optional Whether to include each node before its descendants (default: True). self_after : bool, optional Whether to include each node after its descendants (default: False). include_self : bool, optional Include the initial node if True (default). Yields ------ TreeNode Visited node. See Also -------- preorder postorder pre_and_postorder levelorder tips non_tips Notes ----- This is a depth-first search (DFS). ``self_before`` and ``self_after`` determine whether a node should be visited before and after traversing its children. They are independent. If both True, each internal node (and root) will be visited twice. If neither is True, only tips will be returned. This method is a generalization of :meth:`preorder`, :meth:`postorder`, :meth:`pre_and_postorder` and :meth:`tips`. The default mode (``self_before=True, self_after=False``) is equivalent to preorder traversal. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)g;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b -g-------| | /-d \f-------| \-e >>> for node in tree.traverse(): ... print(node.name) g c a b f d e """ if self_before: if self_after: return self.pre_and_postorder(include_self=include_self) else: return self.preorder(include_self=include_self) else: if self_after: return self.postorder(include_self=include_self) else: return self.tips(include_self=include_self) def preorder(self, include_self: bool = True) -> Iterator[TreeNode]: r"""Perform preorder traversal over tree. Parameters ---------- include_self : bool, optional Include the initial node if True (default). Yields ------ TreeNode Visited node. See Also -------- traverse postorder pre_and_postorder levelorder Notes ----- Preorder traversal visits each node followed by traversing each of its children in order. It is also known as NLR (node - left - right). It is a depth-first search (DFS). The overall direction of traversal is from root to tips. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)g;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b -g-------| | /-d \f-------| \-e >>> for node in tree.preorder(): ... print(node.name) g c a b f d e """ stack = [self] if include_self else self.children[::-1] stack_pop = stack.pop stack_extend = stack.extend while stack: yield (curr := stack_pop()) if curr.children: stack_extend(curr.children[::-1]) def postorder(self, include_self: bool = True) -> Iterator[TreeNode]: r"""Perform postorder traversal over tree. Parameters ---------- include_self : bool, optional Include the initial node if True (default). Yields ------ TreeNode Visited node. See Also -------- traverse preorder pre_and_postorder levelorder Notes ----- Postorder traversal traverses all children of a node in order before visiting the parent node. It is also known as LRN (left - right - node). It is a depth-first search (DFS). The overall direction of traversal is from tips to root. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)g;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b -g-------| | /-d \f-------| \-e >>> for node in tree.postorder(): ... print(node.name) a b c d e f g """ # This is somewhat inelegant compared to saving the node and its index # on the stack, but is 30% faster in the average case and 3x faster in # the worst case (for a comb tree). child_index_stack = [0] child_index_stack_append = child_index_stack.append child_index_stack_pop = child_index_stack.pop curr = self curr_children = self.children curr_children_len = len(curr_children) while True: curr_index = child_index_stack[-1] # if there are children left, process them if curr_index < curr_children_len: curr_child = curr_children[curr_index] # if the current child has children, go there if curr_child.children: child_index_stack_append(0) curr = curr_child curr_children = curr.children curr_children_len = len(curr_children) curr_index = 0 # otherwise, yield that child else: yield curr_child child_index_stack[-1] += 1 # if there are no children left, return self, and move to # self's parent else: if include_self or (curr is not self): yield curr if curr is self: break curr = curr.parent # type: ignore[assignment] curr_children = curr.children curr_children_len = len(curr_children) child_index_stack_pop() child_index_stack[-1] += 1 def pre_and_postorder(self, include_self: bool = True) -> Iterator[TreeNode]: r"""Perform traversal over tree, visiting nodes before and after. Parameters ---------- include_self : bool, optional Include the initial node if True (default). Yields ------ TreeNode Visited node. See Also -------- traverse postorder preorder levelorder Notes ----- Pre- and post-order traversal visits each node before and after traversing all children of the node. Therefore, each internal node (and root) is visited twice. It is a depth-first search (DFS). The overall direction of traversal is from root to tips then back to root. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)g;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b -g-------| | /-d \f-------| \-e >>> for node in tree.pre_and_postorder(): ... print(node.name) g c a b c f d e f g """ # handle simple case first if not self.children: if include_self: yield self return child_index_stack = [0] child_index_stack_append = child_index_stack.append child_index_stack_pop = child_index_stack.pop curr = self curr_children = self.children while True: curr_index = child_index_stack[-1] if not curr_index: if include_self or (curr is not self): yield curr # if there are children left, process them if curr_index < len(curr_children): curr_child = curr_children[curr_index] # if the current child has children, go there if curr_child.children: child_index_stack_append(0) curr = curr_child curr_children = curr.children curr_index = 0 # otherwise, yield that child else: yield curr_child child_index_stack[-1] += 1 # if there are no children left, return self, and move to # self's parent else: if include_self or (curr is not self): yield curr if curr is self: break curr = curr.parent # type: ignore[assignment] curr_children = curr.children child_index_stack_pop() child_index_stack[-1] += 1 def levelorder(self, include_self: bool = True) -> Iterator[TreeNode]: r"""Perform level order traversal over tree. Parameters ---------- include_self : bool, optional Include the initial node if True (default). Yields ------ TreeNode Visited node. See Also -------- postorder preorder pre_and_postorder traverse Notes ----- Level order traversal visits all nodes at each depth from the root before visiting nodes at the next depth. It is a breadth-first search (BFS). The overall direction of traversal is from root to tips. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)g;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b -g-------| | /-d \f-------| \-e >>> for node in tree.levelorder(): ... print(node.name) g c f a b d e """ queue = deque([self]) if include_self else deque(self.children) queue_popleft = queue.popleft queue_extend = queue.extend while queue: yield (curr := queue_popleft()) if curr.children: queue_extend(curr.children) def tips(self, include_self: bool = False) -> Iterator[TreeNode]: r"""Iterate over tips descended from the current node. Parameters ---------- include_self : bool, optional Whether to include the initial node if it is a tip (default: False). Yields ------ TreeNode Visited tip. See Also -------- non_tips postorder Notes ----- Nodes are ordered by a postorder traversal of the tree. The order is consistent between calls. If self is a tip, it won't be yieled unless `include_self` is True. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f);"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b ---------| | /-d \f-------| \-e >>> for node in tree.tips(): ... print(node.name) a b d e """ for node in self.postorder(include_self=include_self): if not node.children: yield node def non_tips(self, include_self: bool = False) -> Iterator[TreeNode]: r"""Iterate over non-tip nodes descended from the current node. Parameters ---------- include_self : bool, optional Whether to include the initial node if it is not a tip (default: False). Yields ------ TreeNode Visited non-tip node. See Also -------- tips postorder Notes ----- Nodes are ordered by a postorder traversal of the tree. The order is consistent between calls. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f);"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b ---------| | /-d \f-------| \-e >>> for node in tree.non_tips(): ... print(node.name) c f """ for node in self.postorder(include_self): if node.children: yield node # ------------------------------------------------ # Tree manipulation # ------------------------------------------------ def append(self, node: TreeNode, uncache: bool = True): r"""Add a node to self's children. Parameters ---------- node : TreeNode Node to add as a child. uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 See Also -------- extend Notes ----- This method will add the node to the end of self's children. If the incoming node is within another tree, it will be disconnected from its original parent, if any, but its children will be preserved. Therefore, this method is able to move an entire clade. The ``uncache`` parameter applies to both donor and recipient trees. Examples -------- >>> from skbio import TreeNode >>> root = TreeNode(name="root") >>> child1 = TreeNode(name="child1") >>> child2 = TreeNode(name="child2") >>> root.append(child1) >>> root.append(child2) >>> print(root) (child1,child2)root; """ if uncache: self.clear_caches() node.clear_caches() # reconnect the node from its original parent to self # this code is similar to `remove`, but it does not return a value if node.parent is not None: for i, curr_node in enumerate((children := node.parent.children)): if curr_node is node: del children[i] break node.parent = self self.children.append(node) def extend(self, nodes: Iterable[TreeNode], uncache: bool = True): r"""Add a list of nodes to self's children. Parameters ---------- nodes : iterable of TreeNode Nodes to add as children. .. versionchanged:: 0.6.2 Can accept any iterable type in addition to list as input. uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 See Also -------- append Notes ----- This method will remove existing parents of the nodes if they have any, set their parents to self, and add the nodes to the end of self's children. The ``uncache`` parameter applies to both donor and recipient trees. Examples -------- >>> from skbio import TreeNode >>> root = TreeNode(name="root") >>> root.extend([TreeNode(name="child1"), TreeNode(name="child2")]) >>> print(root) (child1,child2)root; """ # make a shallow copy of nodes, which is necessary for working with iterators # and containers that are mutable during reconnection (like `children`) nodes = list(nodes) if uncache: self.clear_caches() for node in nodes: node.clear_caches() # reconnect each node from original parent to self; see `append` for node in nodes: if node.parent is not None: for i, curr_node in enumerate((children := node.parent.children)): if curr_node is node: del children[i] break node.parent = self self.children.extend(nodes) def insert( self, node: TreeNode, distance: float | int | None = None, branch_attrs: Iterable[str] = [], uncache: bool = True, ): r"""Insert a node into the branch connecting self and its parent. .. versionadded:: 0.6.2 Parameters ---------- node : TreeNode Node to insert. distance : float, int or None, optional Distance between self and the insertion point. Must not exceed ``length`` of self. If None whereas ``length`` is not None, will insert at the midpoint of the branch. branch_attrs : iterable of str, optional Attributes of self that should be transferred to the inserted node as they are considered as attributes of the branch. ``support`` will be automatically included as it is always a branch attribute. uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 Raises ------ NoParentError If self has no parent. ValueError If distance is specified but branch has no length. ValueError If distance exceeds branch length. See Also -------- append Notes ----- This method will remove the existing parent of the node if any, set its parent as self's parent, and set self's parent as the incoming node. The node's index position in the parent's children is consistent with that of self prior to insertion. The ``uncache`` parameter applies to both donor and recipient trees. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a:1,b:2)c:4,d:5)e;"]) >>> print(tree.ascii_art()) /-a /c-------| -e-------| \-b | \-d >>> tree.find("c").insert(TreeNode("x")) >>> print(tree.ascii_art()) /-a /x------- /c-------| -e-------| \-b | \-d >>> tree.find("c").length 2.0 >>> tree.find("x").length 2.0 """ if (parent := self.parent) is None: raise NoParentError("Self has no parent.") if uncache: self.clear_caches() # detach node from original tree if applicable if node.parent is not None: node.parent.remove(node, uncache) # replace self with node in the parent's list of children node.parent = parent for i, curr_node in enumerate(parent.children): if curr_node is self: parent.children[i] = node # add self to the beginning of the node's list of children self.parent = node node.children.insert(0, self) # transfer branch attributes to new node branch_attrs = set(branch_attrs) branch_attrs.add("support") branch_attrs.discard("length") for attr in branch_attrs: setattr(node, attr, getattr(self, attr, None)) # determine insertion point if distance is None: if self.length is None: node.length = None else: self.length *= 0.5 node.length = self.length else: if self.length is None: raise ValueError("Distance is provided but branch has no length.") elif distance > self.length: raise ValueError("Distance cannot exceed branch length.") node.length = self.length - distance self.length = distance def pop(self, index: int = -1, uncache: bool = True) -> TreeNode: r"""Remove and return a child node by index position from self. Parameters ---------- index : int, optional The index position in ``children`` to pop. uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 Returns ------- TreeNode The popped child node. Raises ------ IndexError If the index position does not exist. See Also -------- remove remove_by_func Notes ----- The parent of the popped node will be set to ``None``. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["(a,b)c;"]) >>> print(tree.pop(0)) a; """ if uncache: self.clear_caches() node = self.children.pop(index) node.parent = None return node def remove(self, node: TreeNode, uncache: bool = True) -> bool: r"""Remove a child node by identity from self. Parameters ---------- node : TreeNode The node to remove from self's children. uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 Returns ------- bool True if the node was removed. False if the node is not a child of self. See Also -------- pop remove_by_func Notes ----- The parent of the removed node will be set to None. The removed node and its children (if any) still exist, but are disconnected from the tree. Therefore, this method is useful for detaching a clade from a tree. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["(a,b)c;"]) >>> tree.remove(tree.children[0]) True """ if uncache: self.clear_caches() # it is necessary to perform removal by identity (`is`), instead of removal by # equality (e.g., `self.children.remove(node)`), therefore: for i, curr_node in enumerate(self.children): if curr_node is node: curr_node.parent = None del self.children[i] return True return False @aliased("remove_deleted", "0.6.3", True) def remove_by_func(self, func: Callable[[TreeNode], bool], uncache: bool = True): r"""Remove nodes of a tree that meet certain criteria. Parameters ---------- func : callable A function that accepts a ``TreeNode`` and returns True or False, where True indicates the node is to be deleted. uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 See Also -------- pop remove Notes ----- This method has the potential to drop entire clades. That is, if an internal node is removed, all its descendants are no longer connected to the tree, even if they are not explicitly removed. This method has the potential to leave single-child internal nodes in the tree, which can be further collapsed by :meth:`prune`. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["(a,b)c;"]) >>> tree.remove_by_func(lambda x: x.name == 'b') >>> print(tree) (a)c; """ if uncache: self.clear_caches() for node in self.traverse(include_self=False): if func(node): node.parent.remove(node, uncache=False) # type: ignore[union-attr] def prune(self, uncache: bool = True): r"""Collapse single-child nodes in the tree. Internal nodes with only one child will be removed, and direct connections will be made from the parent to the child. The branch length of the node will be added to the child. The name and properties of the child will override those of the parent following the operation. Parameters ---------- uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 See Also -------- shear pop remove remove_by_func Notes ----- This method is useful for cleaning up single-child nodes after some nodes were removed from a tree. If called from an internal node of the tree, only the clade below the node will be pruned. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["(((a,b)c,(d)e)g,((h,i)j)k)root;"]) >>> print(tree.ascii_art()) /-a /c-------| /g-------| \-b | | -root----| \e------- /-d | | /-h \k------- /j-------| \-i >>> tree.prune() >>> print(tree.ascii_art()) /-a /c-------| /g-------| \-b | | -root----| \-d | | /-h \j-------| \-i """ if uncache: self.clear_caches() # build up the list of nodes to remove so the topology is not altered # while traversing nodes_to_remove: list[TreeNode] = [] nodes_to_remove_append = nodes_to_remove.append for node in self.traverse(include_self=False): if len(node.children) == 1: nodes_to_remove_append(node) # clean up the single children nodes for node in nodes_to_remove: child = node.children[0] if child.length is None or node.length is None: child.length = child.length or node.length else: child.length += node.length if (parent := node.parent) is not None: # TODO: replace the original node's index position, rather than append # to the end. parent.append(child, uncache=False) parent.remove(node, uncache=False) # If there is a single descendent from the root, the root will adopt the # child's properties. We can't "delete" the root as that would be deleting # self. if len(self.children) == 1: child = self.children[0] if child.length is None or self.length is None: self.length = self.length or child.length else: self.length += child.length for key, value in child.__dict__.items(): if key not in ("length", "parent", "children"): self.__dict__[key] = value self.remove(child, uncache=False) self.extend(child.children, uncache=False) def shear( self, names: Iterable[str], strict: bool = True, prune: bool = True, inplace: bool = False, uncache: bool = True, ) -> TreeNode: r"""Refine a tree such that it just has the desired tip names. Parameters ---------- names : iterable of str The tip names on the tree to keep. strict : bool, optional In case some names are not found in the tree, whether to raise an error (True, default) or to refine the tree to the found names only (False). .. versionadded:: 0.6.3 prune : bool, optional Whether to collapse single-child nodes after shearing by calling :meth:`prune` (default: True). .. versionadded:: 0.6.3 inplace : bool, optional Whether to modify the tree in place (True) or to create a modified copy of the tree (False, default). .. versionadded:: 0.6.3 uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. Only applicable when ``inplace`` is True. .. versionadded:: 0.6.3 Returns ------- TreeNode The resulting tree. .. versionchanged:: 0.7.2 The sheared tree is returned regardless of ``inplace``. Raises ------ ValueError If one or more names do not exist in the tree and ``strict`` is True. See Also -------- prune remove remove_by_func Notes ----- This method is useful for reducing a large tree to a relevant subset of taxa. If called from an internal node of the tree, only the clade below the node will be refined, and the copy of the tree (when ``inplace`` is False) will only include the clade. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["(((a,b)c,(d,e)f)g,(h,i)j)root;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b /g-------| | | /-d | \f-------| -root----| \-e | | /-h \j-------| \-i >>> sheared = tree.shear(['a', 'd', 'h']) >>> print(sheared.ascii_art()) /-a /g-------| -root----| \-d | \-h """ names = set(names) if strict and not names.issubset(self.subset()): raise ValueError("Names are not a subset of the tree.") # modify (sub)tree in place if inplace: tree = self if uncache: tree.clear_caches() # temporarily disconnect subtree from parent curr_parent = tree.parent tree.parent = None # make a copy of (sub)tree else: tree = self.copy() # mark desired tips and their ancestors marked: set[TreeNode] = set() marked_add = marked.add for tip in tree.tips(): if tip.name in names: marked_add(tip) # see also `tip.ancestors`, but the following code stops early if it # doesn't need to reach root anc = tip.parent while anc is not None: if anc in marked: break marked_add(anc) anc = anc.parent # TODO: This `list` can potentially be removed to save unnecessary removals # within clades that are already removed for node in list(tree.traverse()): if node not in marked: node.parent.remove(node, uncache=False) # type: ignore[union-attr] # remove single-child nodes if prune: tree.prune(uncache=False) # reconnect subtree to parent if inplace: tree.parent = curr_parent return tree def unpack(self, uncache: bool = True): """Unpack an internal node in place. Parameters ---------- uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 Notes ----- This method sequentially: 1) elongates child nodes by branch length of self (omit if there is no branch length), 2) removes self from parent node, and 3) grafts child nodes to parent node. Raises ------ ValueError If input node is root or tip. See Also -------- unpack_by_func prune Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(['((c:2.0,d:3.0)a:1.0,(e:2.0,f:1.0)b:2.0);']) >>> tree.find('b').unpack() >>> print(tree) ((c:2.0,d:3.0)a:1.0,e:4.0,f:3.0); """ if self.is_root(): raise TreeError("Cannot unpack root.") if self.is_tip(): raise TreeError("Cannot unpack tip.") if uncache: self.clear_caches() parent = self.parent blen = self.length or 0.0 for child in self.children: clen = child.length or 0.0 child.length = clen + blen or None parent.remove(self, uncache=False) # type: ignore[union-attr] parent.extend(self.children, uncache=False) # type: ignore[union-attr] def unpack_by_func(self, func: Callable[[TreeNode], bool], uncache: bool = True): """Unpack internal nodes of a tree that meet certain criteria. Parameters ---------- func : callable A function that accepts a ``TreeNode`` and returns True or False, where True indicates the node is to be unpacked. uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 See Also -------- unpack prune Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(['((c:2,d:3)a:1,(e:1,f:2)b:2);']) >>> tree.unpack_by_func(lambda x: x.length <= 1) >>> print(tree) ((e:1.0,f:2.0)b:2.0,c:3.0,d:4.0); >>> tree = TreeNode.read(['(((a,b)85,(c,d)78)75,(e,(f,g)64)80);']) >>> tree.assign_supports() >>> tree.unpack_by_func(lambda x: x.support < 75) >>> print(tree) (((a,b)85,(c,d)78)75,(e,f,g)80); """ if uncache: self.clear_caches() nodes_to_unpack: list[TreeNode] = [] nodes_to_unpack_append = nodes_to_unpack.append for node in self.non_tips(include_self=False): if func(node): nodes_to_unpack_append(node) for node in nodes_to_unpack: node.unpack(uncache=False) def bifurcate( self, insert_length: int | None = None, include_self: bool = True, uncache: bool = True, ): r"""Convert the tree into a bifurcating tree. All nodes that have more than two children will have additional intermediate nodes inserted to ensure that every node has only two children. Parameters ---------- insert_length : int, optional The branch length assigned to all inserted nodes. include_self : bool, optional If False, will not convert the current node. This is useful for keeping an unrooted tree unrooted. Default is True. .. versionadded:: 0.6.3 uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 See Also -------- prune is_bifurcating Notes ----- This method does not modify single-child nodes. These nodes can be collapsed using :meth:`prune` prior to this method to create a strictly bifurcating tree. This method modifies the subtree under the current node. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b,g,h)c,(d,e)f)root;"]) >>> print(tree.ascii_art()) /-a | |--b /c-------| | |--g | | -root----| \-h | | /-d \f-------| \-e >>> tree.bifurcate() >>> print(tree.ascii_art()) /-h /c-------| | | /-g | \--------| | | /-a -root----| \--------| | \-b | | /-d \f-------| \-e """ if uncache: self.clear_caches() treenode = self.__class__ for node in self.traverse(include_self=include_self): if len(node.children) > 2: stack = node.children while len(stack) > 2: ind = stack.pop() interm = treenode(length=insert_length, children=stack[:]) node.append(interm, uncache=False) for child in stack: node.remove(child, uncache=False) node.extend([ind, interm], uncache=False) @params_aliased([("shuffler", "shuffle_f", "0.6.3", True)]) def shuffle( self, k: int | None = None, names: list | None = None, shuffler: int | np.random.Generator | Callable[[list], None] | None = None, n: int = 1, ) -> Iterator[TreeNode]: r"""Randomly shuffle tip names of the tree. Parameters ---------- k : int, optional The number of tips to shuffle. If provided, this number of tips will be randomly selected by ``shuffle_f``, and only those names will be shuffled. Conflicts with ``names``. names : list, optional The specific tip names to shuffle. Conflicts with ``k``. shuffler : int, np.random.Generator or callable, optional Shuffling function, which must accept a list and modify in place. Default is the :meth:`shuffle ` method of a NumPy random generator. If an integer is provided, a random generator will be constructed using this number as the seed. .. versionchanged:: 0.6.3 Switched to NumPy's new random generator. Can accept a random seed or random generator instance. n : int, optional The number of iterations to perform. Must be a positive integer. Default is 1. If None or ``np.inf``, iterations will be infinite. .. versionchanged:: 0.6.3 Can accept None. Yields ------ TreeNode Tree with shuffled tip names. Raises ------ ValueError If ``k`` < 2 or ``n`` < 1. ValueError If both ``k`` and ``names`` are specified. MissingNodeError If ``names`` is specified but one of the names cannot be found. See Also -------- numpy.random.Generator.shuffle Notes ----- This method does not create copies of the tree. Instead, tip names are shuffled in place in the original tree and the tree is yielded prior to the next round of shuffling. Tree caches will be cleared prior to shuffling. ``k`` and ``names`` cannot be specified at the same time. If neither ``k`` nor ``names`` are provided, all tips will be shuffled. Examples -------- Shuffle the names of a 4-tip tree for 5 times: >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b),(c,d));"]) >>> for shuffled in tree.shuffle(shuffler=42, n=5): ... print(shuffled) ((d,c),(b,a)); ((a,b),(d,c)); ((a,c),(d,b)); ((d,b),(a,c)); ((a,c),(d,b)); """ if k is not None: if k < 2: raise ValueError("k must be None or >= 2.") if names is not None: raise ValueError("k and names cannot be specified at the same time.") if n is None: n = np.inf elif n < 1: raise ValueError("n must be > 0.") # determine shuffling function func = _check_shuffler(shuffler) # determine tip names to shuffle if names is not None: tips = [self.find(x) for x in names] else: tips = list(self.tips()) if k is not None: func(tips) tips = tips[:k] names = [x.name for x in tips] # since the names are being shuffled, the caches are no longer reliable self.clear_caches() # iteratively shuffle tip names and yield tree counter = 0 while counter < n: func(names) for tip, name in zip(tips, names): tip.name = name yield self counter += 1 # ------------------------------------------------ # Tree rerooting # ------------------------------------------------ def unroot(self, side: int | None = None, uncache: bool = True): r"""Convert a rooted tree into unrooted. .. versionadded:: 0.6.2 Parameters ---------- side : int, optional Which basal node (i.e., children of root) will be elevated to root. Must be 0 or 1. If not provided, will elevate the first basal node that is not a tip. The choice won't impact tree topology. uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 See Also -------- root root_at Notes ----- In scikit-bio, every tree has a root node. A tree is considered as "rooted" if its root node has exactly two children. In contrast, an "unrooted" tree may have three (the most common case), one, or more than three children attached to its root node. This method will not modify the tree if it is already unrooted. This method unroots a tree by trifucating its root. Specifically, it removes one of the two basal nodes of the tree (i.e., children of the root), transfers the name of the removed node to the root, and re-attaches the removed node's children to the root. Additionally, the removed node's branch length, if available, will be added to the other basal node's branch. The outcome appears as if the root is removed and the two basal nodes are directly connected. The choice of the basal node to be elevated affects the positioning of the resulting tree, but does not affect its topology from a phylogenetic perspective, as it is considered as unrooted. This method manipulates the tree in place. There is no return value. .. note:: In the case where the basal node has just one child, the resulting tree will still appear rooted as it has two basal nodes. To avoid this scenario, call :meth:`prune` to remove all one-child internal nodes. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(['(((a,b)c,(d,e)f)g,(h,i)j)k;']) >>> print(tree.ascii_art()) /-a /c-------| | \-b /g-------| | | /-d | \f-------| -k-------| \-e | | /-h \j-------| \-i >>> tree.unroot() >>> print(tree.ascii_art()) /-a /c-------| | \-b | | /-d -g-------|-f-------| | \-e | | /-h \j-------| \-i """ # return original tree if already unrooted root = self.root() if len(bases := root.children) != 2: return root if uncache: root.clear_caches() # choose a basal node to elevate if side is None: side = 1 if (bases[0].is_tip() and not bases[1].is_tip()) else 0 chosen, other = bases[side], bases[1 - side] # remove chosen node and re-attach its children to root chosen.parent = None for child in chosen.children: child.parent = root if side: root.children = [other] + chosen.children else: root.children = chosen.children + [other] # transfer basal node's attributes to root for key, value in chosen.__dict__.items(): if key not in ("length", "support", "parent", "children"): root.__dict__[key] = value # add branch length to the other basal node if (L := chosen.length) is not None: if other.length is not None: other.length += L else: other.length = L def unrooted_copy( self, parent: TreeNode | None = None, branch_attrs: set[str] = {"length", "support"}, root_name: str | None = None, deep: bool = False, exclude_attrs: set[str] | None = None, ) -> TreeNode: r"""Walk the tree unrooted-style and return a copy. Parameters ---------- parent : TreeNode or None Direction of walking (from parent to self). If specified, walking to the parent will be prohibited. branch_attrs : set of str, optional Attributes of ``TreeNode`` objects that should be considered as branch attributes during the operation. .. versionadded:: 0.6.2 .. versionchanged:: 0.7.0 Removed ``name`` from the default values. root_name : str or None, optional Name for the new root node, if it doesn't have one. .. versionadded:: 0.6.2 .. versionchanged:: 0.7.0 Set the default value to None. deep : bool, optional Whether to perform a shallow (False, default) or deep (True) copy of node attributes. .. versionadded:: 0.6.2 exclude_attrs : set, optional Node attributes that should not be copied. If None (default), the caches will be excluded. This parameter keeps a memo during recursive copying for efficiency. It should not be customized by the user unless absolutely needed. .. versionadded:: 0.6.3 Returns ------- TreeNode A new copy of the tree rooted at the given node. .. versionchanged:: 0.6.2 Node attributes other than name and length will also be copied. See Also -------- copy unrooted_move Notes ----- This method recursively walks a tree from a given node in an unrooted style (i.e., directions of branches are not assumed), and copies each node it visits, such that the copy of the given node becomes the root node of a new tree and the copies of all other nodes are re-positioned accordingly, whereas the topology of the new tree will be identical to the existing one. Nodes attributes except for caches will be copied to the new tree. Attributes in ``branch_attrs`` will be transferred to the node at the other end of a branch if the branch is flipped in the new tree. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,(b,c)d)e,(f,g)h)i;"]) >>> new_tree = tree.find('d').unrooted_copy() >>> print(new_tree) (b,c,(a,((f,g)h)i)e)d; """ # determine copy mode _copy = deepcopy if deep else copy # determine node attributes to exclude if exclude_attrs is None: exclude_attrs = self._exclude_from_copy if hasattr((root := self.root()), "_registered_caches"): exclude_attrs = exclude_attrs | root._registered_caches # identify neighbors (adjacent nodes) of self, excluding the incoming node neighbors = self.neighbors(ignore=parent) # recursively copy each neighbor; they will become outgoing nodes (children) children = [ c.unrooted_copy( parent=self, branch_attrs=branch_attrs, root_name=root_name, deep=deep, exclude_attrs=exclude_attrs, ) for c in neighbors ] # identify node from which branch attributes should be transferred # 1. starting point (becomes root) if parent is None: other = None # 2. walk up (parent becomes child) elif parent.parent is self: other = parent # 3. walk down (retain the same order) else: other = self # create a new node and attach children to it, see also `copy` attrs = { x: ( (None if other is None else getattr(other, x)) if x in branch_attrs else getattr(self, x) ) for x in ("name", "length", "support") } result = self.__class__(**attrs, children=children) # transfer attributes to the new node, see also `copy` for key in self.__dict__: if key not in exclude_attrs: source = other if key in branch_attrs else self if source is not None and key in source.__dict__: result.__dict__[key] = _copy(source.__dict__[key]) # name the new root if root_name and parent is None and result.name is None: result.name = root_name return result def unrooted_move( self, branch_attrs: set[str] = {"length", "support"}, uncache: bool = True, ): r"""Walk the tree unrooted-style and rearrange it. .. versionadded:: 0.6.2 .. versionchanged:: 0.6.3 The underlying algorithm is now iterative instead of recursive, therefore won't be constrained by Python's maximum recursion limit when working with large trees. Parameter ``parent`` was removed as it is no longer needed. Parameters ---------- parent : TreeNode or None Direction of walking (from parent to self). If specified, walking to the parent will be prohibited. branch_attrs : set of str, optional Attributes of ``TreeNode`` objects that should be considered as branch attributes during the operation. uncache : bool, optional Whether to clear caches of the tree if present (default: True). See :meth:`details `. .. versionadded:: 0.6.3 See Also -------- root_at unrooted_copy Notes ----- This method walks a tree from a given node in an unrooted style (i.e., directions of branches are not assumed). It rerranges the tree such that the given node becomes the root node and all other nodes are re-positioned accordingly, whereas the topology remains the same. This method manipulates the tree in place. There is no return value. The new tree should be referred to by the node where the operation started, as it has become the new root node. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,(b,c)d)e,(f,g)h)i;"]) >>> new_root = tree.find('d') >>> new_root.unrooted_move() >>> print(new_root) (b,c,(a,((f,g)h)i)e)d; """ if uncache: self.clear_caches() # This algorithm uses an iterative approach to avoid the maximum recursion # limit imposed by Python. Two rounds of iterations are involved to 1) flip # the tree and to 2) reconstruct the upward branches. self.old_child = None curr = self parent = None # move up in the original tree and move parent to children while (old_parent := curr.parent) is not None: for i, child in enumerate(old_parent.children): if child is curr: old_parent.children.pop(i) break curr.children.append(old_parent) old_parent.old_child = curr curr.parent = parent parent = curr curr = old_parent # move up in the new tree and rebuild parent connection while curr.old_child is not None: child = curr.old_child curr.parent = child for attr in branch_attrs: setattr(curr, attr, getattr(child, attr, None)) del curr.old_child curr = child del self.old_child for attr in branch_attrs: setattr(self, attr, None) def root_at( self, node: TreeNode | str | None = None, above: bool | float | int | None = False, reset: bool = True, branch_attrs: Iterable[str] = [], root_name: str | None = None, inplace: bool = False, ) -> TreeNode: r"""Reroot the tree at the provided node. This is useful for positioning a tree with an orientation that reflects knowledge of the true root location. Parameters ---------- node : TreeNode or str, optional The node to root at. Can either be a node object or the name of the node. If not provided, will root at self. If a root node provided, will return the original tree. .. versionchanged:: 0.6.2 Becomes optional. above : bool, float, or int, optional Whether and where to insert a new root node. If False (default), the target node will serve as the root node. If True, a new root node will be created and inserted at the midpoint of the branch connecting the target node and its parent. If a number, the new root will be inserted at this distance from the target node. The number ranges between 0 and branch length. .. versionadded:: 0.6.2 reset : bool, optional Whether to remove the original root of a rooted tree before performing the rerooting operation. Default is True. .. versionadded:: 0.6.2 .. versionchanged:: 0.7.0 Set the default value to True. branch_attrs : iterable of str, optional Attributes of each node that should be considered as attributes of the branch connecting the node to its parent. This is important for the correct rerooting operation. "length" and "support" will be automatically included as they are always branch attributes. .. versionadded:: 0.6.2 .. versionchanged:: 0.7.0 Removed ``name`` from the default values. root_name : str or None, optional Name for the root node, if it doesn't already have one. .. versionadded:: 0.6.2 .. versionchanged:: 0.7.0 Set the default value to None. inplace : bool, optional Whether to reroot the tree in place (True) or to create a rerooted copy of the tree (False, default). .. versionadded:: 0.6.3 Returns ------- TreeNode A tree rooted at the give node. See Also -------- unrooted_copy unrooted_move unroot Notes ----- The specified node will be come the root of the new tree. Tree caches (see :meth:`details `) will not be retained in the returned tree. In in-place mode, they will be cleared prior to rerooting. In copying mode, they will not be copied to the new tree. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["(((a,b)c,(d,e)f)g,h)i;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b /g-------| | | /-d -i-------| \f-------| | \-e | \-h Use the given node as the root node. This will typically create an unrooted tree (i.e., root node has three children). >>> t1 = tree.root_at("c") >>> print(t1) (a,b,((d,e)f,h)g)c; >>> print(t1.ascii_art()) /-a | |--b -c-------| | /-d | /f-------| \g-------| \-e | \-h Insert a new root node into the branch above the given node. This will create a rooted tree (i.e., root node has two children). >>> t2 = tree.root_at("c", above=True) >>> print(t2) ((a,b)c,((d,e)f,h)g); >>> print(t2.ascii_art()) /-a /c-------| | \-b ---------| | /-d | /f-------| \g-------| \-e | \-h """ # locate to-be root node tree = self.root() if node is None: node = self elif isinstance(node, str): node = tree.find(node) # return if already rooted if node.is_root(): return node.copy() # check if tree is rooted if reset and len(tree.children) != 2: reset = False # Prior to rerooting, the tree may need to be manipulated to remove the # original root and/or to insert a new root node # For optimal performance (copying the tree only once), the following code # considers three scenarios: # 1. In-place mode: Just manipulate the tree if needed, then call # `unrooted_move`. # 2. Copying mode, tree doesn't need to be manipulated: directly call # `unrooted_copy` # 3. Copying mode, tree needs to be manipulated: Make a copy of the # tree, manipulate, then call `unrooted_move`. to_copy = False if not inplace: if reset or above is not False: tree.assign_ids() # every node will have an integer ID new_tree = tree.copy() new_tree.assign_ids() node = new_tree.find_by_id(node.id) # type: ignore[arg-type] tree = new_tree else: to_copy = True # Clear caches, since root node will be different and caches are going to be # useless regardless. else: tree.clear_caches() # Remove original root. We need to make sure the node itself is not the basal # node that gets removed. if reset: side = None for i, base in enumerate(tree.children): if node is base: side = 1 - i break tree.unroot(side) # insert a new root node into the branch above if above is not False: to_insert = node.__class__() distance = None if above is True else above node.insert(to_insert, distance, branch_attrs, uncache=False) node = to_insert branch_attrs = set(branch_attrs) branch_attrs.update(["length", "support"]) # rotate the tree to position the new root if to_copy: return node.unrooted_copy(branch_attrs=branch_attrs, root_name=root_name) else: node.unrooted_move(branch_attrs=branch_attrs, uncache=False) if root_name and node.name is None: node.name = root_name return node def root_at_midpoint( self, reset: bool = True, branch_attrs: Iterable[str] = [], root_name: str | None = None, inplace: bool = False, ) -> TreeNode: r"""Reroot the tree at the midpoint of the two tips farthest apart. Parameters ---------- reset : bool, optional Whether to remove the original root of a rooted tree before performing the rerooting operation. Default is True. .. versionadded:: 0.6.2 .. versionchanged:: 0.7.0 Set the default value to True. branch_attrs : iterable of str, optional Attributes of each node that should be considered as attributes of the branch connecting the node to its parent. This is important for the correct rerooting operation. "length" and "support" will be automatically included as they are always branch attributes. .. versionadded:: 0.6.2 .. versionchanged:: 0.7.0 Removed ``name`` from the default values. root_name : str or None, optional Name for the new root node, if it doesn't have one. .. versionadded:: 0.6.2 .. versionchanged:: 0.7.0 Set the default value to None. inplace : bool, optional Whether to reroot the tree in place (True) or to create a rerooted copy of the tree (False, default). .. versionadded:: 0.6.3 Returns ------- TreeNode A tree rooted at its midpoint. Raises ------ TreeError If a tip ends up being the mid point. LengthError Midpoint rooting requires `length` and will raise (indirectly) if evaluated nodes don't have length. See Also -------- root_at unrooted_copy Notes ----- The midpoint rooting (MPR) method was originally described in [1]_. Tree caches (see :meth:`details `) will not be retained in the returned tree. In in-place mode, they will be cleared prior to rerooting. In copying mode, they will not be copied to the new tree. References ---------- .. [1] Farris, J. S. (1972). Estimating phylogenetic trees from distance matrices. The American Naturalist, 106(951), 645-668. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a:1,b:1)c:2,(d:3,e:4)f:5,g:1)h;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b | -h-------| /-d |-f-------| | \-e | \-g >>> t = tree.root_at_midpoint() >>> print(t) ((d:3.0,e:4.0)f:2.0,((a:1.0,b:1.0)c:2.0,g:1.0)h:3.0); >>> print(t.ascii_art()) /-d /f-------| | \-e ---------| | /-a | /c-------| \h-------| \-b | \-g """ tree = self.root() if inplace: tree.clear_caches() else: tree = tree.copy() if reset: tree.unroot(uncache=False) max_dist, (tip1, tip2) = tree.maxdist() if max_dist == 0.0: return tree half_max_dist = max_dist / 2.0 lca = tree.lca([tip1, tip2]) if tip1.depth(lca, missing_as_zero=True) > half_max_dist: climb_node = tip1 else: climb_node = tip2 dist_climbed = 0.0 while (dist_ := dist_climbed + climb_node.length or 0.0) < half_max_dist: dist_climbed = dist_ climb_node = climb_node.parent # case 1: midpoint is at the climb node's parent # make the parent node as the new root if (dist_climbed + climb_node.length or 0.0) == half_max_dist: new_root = climb_node.parent # case 2: midpoint is on the climb node's branch to its parent # insert a new root node into the branch else: new_root = tree.__class__() climb_node.insert( new_root, half_max_dist - dist_climbed, branch_attrs, uncache=False ) branch_attrs = set(branch_attrs) branch_attrs.update(["length", "support"]) new_root.unrooted_move(branch_attrs=branch_attrs, uncache=False) if root_name and new_root.name is None: new_root.name = root_name return new_root def root_by_outgroup( self, outgroup: Iterable[str], above: bool | float | int = True, reset: bool = True, branch_attrs: Iterable[str] = [], root_name: str | None = None, inplace: bool = False, ) -> TreeNode: r"""Reroot the tree with a given set of taxa as outgroup. .. versionadded:: 0.6.2 Parameters ---------- outgroup : iterable of str Taxon set to serve as outgroup. Must be a proper subset of taxa in the tree. The tree will be rooted at the lowest common ancestor (LCA) of the outgroup. above : bool, float, or int, optional Whether and where to insert a new root node. If False, the LCA will serve as the root node. If True (default), a new root node will be created and inserted at the midpoint of the branch connecting the LCA and its parent (i.e., the midpoint between outgroup and ingroup). If a number between 0 and branch length, the new root will be inserted at this distance from the LCA. reset : bool, optional Whether to remove the original root of a rooted tree before performing the rerooting operation. Default is True. branch_attrs : iterable of str, optional Attributes of each node that should be considered as attributes of the branch connecting the node to its parent. This is important for the correct rerooting operation. "length" and "support" will be automatically included as they are always branch attributes. root_name : str or None, optional Name for the root node, if it doesn't already have one. inplace : bool, optional Whether to reroot the tree in place (True) or to create a rerooted copy of the tree (False, default). .. versionadded:: 0.6.3 Returns ------- TreeNode A tree rooted by the outgroup. Raises ------ TreeError Outgroup is not a proper subset of taxa in the tree. TreeError Outgroup is not monophyletic in the tree. Notes ----- An outgroup is a subset of taxa that are usually distantly related from the remaining taxa (ingroup). The outgroup helps with locating the root of the ingroup, which are of interest in the study. This method reroots the tree at the lowest common ancestor (LCA) of the outgroup. By default, a new root will be placed at the midpoint between the LCA of outgroup and that of ingroup. But this behavior can be customized. This method requires the outgroup to be monophyletic, i.e., it forms a single clade in the tree. If the outgroup spans across the root of the tree, the method will reroot the tree within the ingroup such that the outgroup can form a clade in the rerooted tree, prior to rooting by outgroup. Tree caches (see :meth:`details `) will not be retained in the returned tree. In in-place mode, they will be cleared prior to rerooting. In copying mode, they will not be copied to the new tree. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(['((((a,b),(c,d)),(e,f)),g);']) >>> print(tree.ascii_art()) /-a /--------| | \-b /--------| | | /-c | \--------| /--------| \-d | | | | /-e ---------| \--------| | \-f | \-g >>> rooted = tree.root_by_outgroup(['a', 'b']) >>> print(rooted.ascii_art()) /-a /--------| | \-b | ---------| /-c | /--------| | | \-d \--------| | /-e | /--------| \--------| \-f | \-g >>> rooted = tree.root_by_outgroup(['e', 'f', 'g']) >>> print(rooted.ascii_art()) /-e /--------| /--------| \-f | | | \-g ---------| | /-c | /--------| | | \-d \--------| | /-b \--------| \-a """ outgroup = set(outgroup) if not outgroup < self.subset(): raise TreeError("Outgroup is not a proper subset of taxa in the tree.") # locate the lowest common ancestor (LCA) of outgroup in the tree lca = self.lca(outgroup) # if LCA is root (i.e., outgroup is split across basal clades), root # the tree at a tip within the ingroup and locate LCA again if lca is self: for tip in self.tips(): if tip.name not in outgroup: tree = self.root_at( tip, reset=reset, branch_attrs=branch_attrs, inplace=inplace ) inplace = False # no need to make copy again break lca = tree.lca(outgroup) else: tree = self # test if outgroup is monophyletic if lca.count(tips=True) > len(outgroup): raise TreeError("Outgroup is not monophyletic in the tree.") # reroot the tree at LCA return tree.root_at( lca, above=above, reset=reset, branch_attrs=branch_attrs, root_name=root_name, inplace=inplace, ) # ------------------------------------------------ # Tree metrics # ------------------------------------------------ def count(self, tips: bool = False) -> int: r"""Get the count of nodes in the tree. Parameters ---------- tips : bool, optional If True, only return the count of tips (default: False). Returns ------- int The number of nodes. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,(b,c)d)e,(f,g)h)i;"]) >>> print(tree.count()) 9 >>> print(tree.count(tips=True)) 5 """ if tips: return len(list(self.tips())) else: return len(list(self.traverse(include_self=True))) def subset(self, include_self: bool = False) -> frozenset[str]: r"""Return a subset of taxa descending from self. A subset can be considered as taxa (tip names) within a clade defined by the current node (branch), selected from all taxa within the tree. Parameters ---------- include_self : bool, optional Whether to include the current node if it is a tip (default: False). .. versionadded:: 0.6.3 Returns ------- frozenset of str The set of names at the tips of the clade that descends from self. See Also -------- tips subsets bipart Notes ----- This is a convenient method to return all taxa (tip names) rather than the tip nodes themselves. Internal node names will not be included. The returned value (a frozenset) is unordered and hashable, therefore can be used to define clades, lineages and taxon groups for efficient lookup. For example, one can check whether a taxon exists in the current tree or clade. By default, if this method is applied to a tip, an empty set will be returned, because a tip does not have descendants. With ``include_self=True``, a single- element set containing the name of the tip will be returned. This behavior can be considered as returning taxa descending from the branch connecting self and its parent. Applying this method to the root node of a tree will return all taxa in the tree. Duplicate tip names are tolerated and merged. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,(b,c)d)e,(f,g)h)i;"]) >>> print(tree.ascii_art()) /-a /e-------| | | /-b | \d-------| -i-------| \-c | | /-f \h-------| \-g >>> sorted(tree.subset()) ['a', 'b', 'c', 'f', 'g'] >>> subset = tree.find('e').subset() >>> sorted(subset) ['a', 'b', 'c'] >>> 'a' in subset True >>> 'f' in subset False """ return frozenset( x.name for x in self.tips(include_self=include_self) if x.name is not None ) def subsets( self, within: Iterable[str] | None = None, include_full: bool = False, include_tips: bool = False, map_to_length: bool = False, ) -> frozenset[frozenset[str]] | dict[frozenset[str], float]: r"""Return all subsets of taxa defined by nodes descending from self. Parameters ---------- within : iterable of str, optional A custom set of taxa to refine the result. Only taxa within it will be considered. If None (default), all taxa in the tree will be considered. .. versionadded:: 0.6.3 include_full : bool, optional Whether to include a set of all taxa in the result. Default is False, as such a set provides no topological information. .. versionadded:: 0.6.3 include_tips : bool, optional Whether to include subsets with only one taxon in the result. Default is False, as such sets provide no topological information. .. versionadded:: 0.6.3 map_to_length : bool, optional If True, return a mapping of subsets to their branch lengths. Missing branch lengths will be replaced with 0. Default is False. .. versionadded:: 0.6.3 Returns ------- frozenset of frozenset of str, or All subsets of taxa defined by nodes descending from self. Returned if ``map_to_length`` is False. dict of {frozenset of str: float} Mapping of all subsets of taxa to their branch lengths. Returned if ``map_to_length`` is True. See Also -------- subset compare_subsets biparts Notes ----- The returned value represents the tree as a set of nested sets, each of which representing a clade in the tree. It is useful for assessing topological patterns of a tree. The returned value itself and each of its components (frozensets) are unordered and hashable, making it efficient for lookup and comparison. For example, one can check whether a group of taxa form a clade in the tree, regardless of its internal structure. This method can be applied to both rooted and unrooted trees. However, the underlying assumption is that the direction of descendance is from the current node to the tips below. That is, the root of the tree, even if not explicitly defined, should be at or above the current node. This should be considered when applying this method to an unrooted tree. If such an assumption is not present, one should consider using :meth:`biparts` instead. Duplicate tip names are tolerated and merged. This method operates on the subtree below the current node. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,(b,c)d)e,(f,g)h)i;"]) >>> print(tree.ascii_art()) /-a /e-------| | | /-b | \d-------| -i-------| \-c | | /-f \h-------| \-g >>> subsets = tree.subsets() >>> for s in sorted(subsets, key=sorted): ... print(sorted(s)) ['a', 'b', 'c'] ['b', 'c'] ['f', 'g'] >>> {'a', 'b', 'c'} in subsets True >>> {'a', 'b'} in subsets False """ lookup: Iterable[str] if not (getall := within is None): # get a hash table for efficient lookup if isinstance(within, (set, frozenset, dict)): lookup = within else: lookup = frozenset(within) # initiate result subsets: list[frozenset[str]] = [] subsets_append = subsets.append if map_to_length: lengths: list[float] = [] lengths_append = lengths.append # If the current subset has been encountered during postorder traversal, it # must be the immediately previous subset. This happens when a single-child # node is encountered after refining taxa to the "within" set. last = None for node in self.postorder(include_self=True): # tip: create a one-taxon set if not node.children: if (name := node.name) is not None and (getall or name in lookup): subset = frozenset([name]) else: subset = frozenset() # internal node: merge sets of children else: subset = frozenset() for child in node.children: subset |= child._subset del child._subset # add to result if subset and (include_tips or len(subset) > 1): if subset != last: subsets_append(last := subset) if map_to_length: lengths_append(node.length or 0.0) elif map_to_length: lengths[-1] += node.length or 0.0 node._subset = subset # final clean up del self._subset # remove the full set if not include_full: subsets = subsets[:-1] if map_to_length: lengths = lengths[:-1] if map_to_length: return dict(zip(subsets, lengths)) else: return frozenset(subsets) def bipart(self) -> frozenset[str]: r"""Return a bipartition of the tree at the current branch. .. versionadded:: 0.6.3 A bipartition, partition or split of a tree is the division of all taxa (tip names) into two complementary subsets, separated at a given branch. In this context, it is the branch connecting self and its parent. One subset consists of all taxa descending from self and the other consists of all remaining taxa. The smaller subset of the two is returned. Returns ------- frozenset of str The set of names at the tips on the smaller side of the current branch. See Also -------- subset biparts Notes ----- A bipartition describes the topological placement of a branch regardless of other branches and the root of the tree. The returned value is a set of tip names on the smaller side of the branch, as determined by the number of tips. If a tie is observed, the tip names on both sides are sorted lexicographically and the first set is returned. The returned value (a frozenset) is unordered and hashable, making it efficient for lookup and comparison. For example, one can check whether two branches in two unrooted trees with the same taxa agree with each other. Rerooting a tree will not change the bipartition of a branch. However, one should be cautious because this method applies to a node, and rerooting may change the branch above the current node. Applying this method to a root node will return an empty set. Applying this method to a tip will return a single-element set containing the tip name. These two situations produce outputs independent of the topology of the tree. Duplicate tip names, if separated by the target branch, can cause an unexpected result. This function does not validate the uniqueness of tip names though. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["(((a,(b,c)X)Y,d)Z,(e,f),g);"]) >>> print(tree.ascii_art()) /-a /Y-------| | | /-b /Z-------| \X-------| | | \-c | | | \-d ---------| | /-e |---------| | \-f | \-g Clade has less than half taxa, return them. >>> sorted(tree.find('X').bipart()) ['b', 'c'] Clade has more than half taxa, return remaining taxa. >>> sorted(tree.find('Z').bipart()) ['e', 'f', 'g'] Clade has exactly half taxa, return the lexicographically smaller side. >>> sorted(tree.find('Y').bipart()) ['a', 'b', 'c'] A second tree with the same topology but different root position. >>> tree2 = TreeNode.read(["((c,b)X2,a,(((f,e),g)Y2,d));"]) >>> print(tree2.ascii_art()) /-c /X2------| | \-b | |--a ---------| | /-f | /--------| | /Y2------| \-e | | | \--------| \-g | \-d Although the tree has been re-positioned, the corresponding branches have the same bipartitions, whereas non-corresponding branches don't. >>> tree.find('X').bipart() == tree2.find('X2').bipart() True >>> tree.find('Y').bipart() == tree2.find('Y2').bipart() False """ bipart = self.subset(include_self=True) full = self.root().subset(include_self=True) if (size := len(bipart)) > (th := len(full) * 0.5): bipart = full - bipart elif size == th: # sort the elements of each part by lexicographic order, then order the two # parts and pick the smaller part bipart, _ = sorted([bipart, full - bipart], key=sorted) return bipart def biparts( self, within: Iterable[str] | None = None, include_tips: bool = False, map_to_length: bool = False, full: frozenset[str] | None = None, ) -> frozenset[frozenset[str]] | dict[frozenset[str], float]: r"""Return all bipartitions within the tree under self. .. versionadded:: 0.6.3 Parameters ---------- within : iterable of str, optional A custom set of taxa to refine the result. Only taxa within it will be considered. If None (default), all taxa in the tree will be considered. include_tips : bool, optional Whether to include bipartitions with only one taxon at either side. Default is False, as such bipartitions provide no topological information. map_to_length : bool, optional If True, return a mapping of subsets to their branch lengths. Missing branch lengths will be replaced with 0. Default is False. full : frozenset of str, optional Pre-computed full set of taxa of the current tree. Providing this parameter can save one tree traversal from computing. Returns ------- frozenset of frozenset of str, or All sets of names at the tips on the smaller side of each branch. Returned if `map_to_length` is False. dict of {frozenset of str: float} Mapping of All sets of smaller-side tip names to branch lengths. Returned if `map_to_length` is True. .. versionchanged:: 0.7.2 Nameless tips are excluded from the results. See Also -------- bipart subsets Notes ----- The returned value represents the tree as a set of nested sets, each of which representing the position of a branch in the tree. It is useful for assessing topological patterns of a tree. The returned value itself and each of its components (frozensets) are unordered and hashable, making it efficient for lookup and comparison. For example, one can check whether the topologies of two trees are consistent, regardless of their root positions. This method can be applied to both rooted and unrooted trees. However, a rooted tree implies the direction of descendance, which may violate the purpose of bipartitioning a tree on arbitrary branches. If this is a concern, one should consider using :meth:`subsets` instead. Duplicate tip names, if separated by the target branch, can cause unexpected results. This function does not validate the uniqueness of tip names though. This method operates on the subtree below the current node. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,(b,c)),(d,e),f);"]) >>> print(tree.ascii_art()) /-a /--------| | | /-b | \--------| | \-c ---------| | /-d |---------| | \-e | \-f Return all bipartitions of an unrooted tree. >>> biparts = tree.biparts() >>> for s in sorted(biparts, key=sorted): ... print(sorted(s)) ['a', 'b', 'c'] ['b', 'c'] ['d', 'e'] A second tree with the same topology but different root position. >>> tree2 = TreeNode.read(["(a,((b,c),((d,e),f)));"]) >>> print(tree2.ascii_art()) /-a | ---------| /-b | /--------| | | \-c \--------| | /-d | /--------| \--------| \-e | \-f Although the tree has been re-positioned, the bipartitions remain the same. >>> biparts == tree2.biparts() True """ # identify full set (universe) if full is None: full = self.subset() if not (getall := within is None): if not isinstance(within, (set, frozenset)): within = frozenset(within) full &= within th = len(full) * 0.5 # initiate result if map_to_length: bipartz: dict[frozenset[str], float] = {} bipartz_get = bipartz.get else: biparts: list[frozenset[str]] = [] biparts_append = biparts.append for node in self.postorder(include_self=False): # tip: create a one-taxon set if not node.children: if (name := node.name) is not None and (getall or name in full): bipart = frozenset([name]) else: bipart = frozenset() flip = False # internal node: merge sets of children # `_bipart` of a node is either the taxa below it, or, if the former has # reached half of the full set, it "flips" to the other half that is above # the node, and `_flip` will be set to True. # Taxa below should be united, whereas taxa above should be intersected. # If at least one child is already flipped, the current node should also be # flipped. Otherwise, the set will be compared to the half to determine the # flipping status. else: aboves, belows = [], [] for child in node.children: if child._flip: aboves.append(child._bipart) else: belows.append(child._bipart) del child._bipart del child._flip if aboves: bipart = frozenset.intersection(*aboves).difference(*belows) flip = True else: bipart = frozenset().union(*belows) flip = False if (size := len(bipart)) >= th: other = full - bipart if size > th or sorted(bipart) > sorted(other): bipart = other flip = True # add to result if bipart and (include_tips or len(bipart) > 1): if map_to_length: bipartz[bipart] = bipartz_get(bipart, 0.0) + (node.length or 0.0) else: biparts_append(bipart) node._bipart = bipart node._flip = flip # final clean up for child in self.children: del child._bipart del child._flip return bipartz if map_to_length else frozenset(biparts) def _extract_support(self): """Extract the support value from a node label, if available. Returns ------- tuple of int, float or None The support value extracted from the node label. str or None The node label with the support value stripped. """ support, label = None, None if self.name: # separate support value from node name by the first colon left, _, right = self.name.partition(":") try: support = int(left) except ValueError: try: support = float(left) except ValueError: pass # strip support value from node name label = right or None if support is not None else self.name return support, label def _node_label(self): """Generate a node label. The label will be in the format of "support:name" if both exist, or "support" or "name" if either exists. Returns ------- str Generated node label. """ lblst = [] if self.support is not None: # prevents support of NoneType lblst.append(str(self.support)) if self.name: # prevents name of NoneType lblst.append(self.name) return ":".join(lblst) def assign_supports(self): """Extract support values from internal node labels of a tree. Notes ----- A "support value" measures the confidence or frequency of the incoming branch (the branch from parent to self) of an internal node in a tree. Roots and tips do not have support values. To extract a support value from a node label, this method reads from left and stops at the first ":" (if any), and attempts to convert it to a number. For examples: "(a,b)1.0", "(a,b)1.0:2.5", and "(a,b)'1.0:species_A'". In these cases the support values are all 1.0. For examples: "(a,b):1.0" and "(a,b)species_A". In these cases there are no support values. If a support value is successfully extracted, it will be stripped from the node label and assigned to the `support` property. .. note:: Mathematically, "support value" is a property of a branch, not a node, although they are usually attached to nodes in tree file formats [1]_. References ---------- .. [1] Czech, Lucas, Jaime Huerta-Cepas, and Alexandros Stamatakis. "A Critical Review on the Use of Support Values in Tree Viewers and Bioinformatics Toolkits." Molecular biology and evolution 34.6 (2017): 1535-1542. Examples -------- >>> from skbio import TreeNode >>> newick = "((a,b)95,(c,d):1.1,(e,f)'80:speciesA':1.0);" >>> tree = TreeNode.read([newick]) >>> tree.assign_supports() >>> tree.lca(['a', 'b']).support 95 >>> tree.lca(['c', 'd']).support is None True >>> tree.lca(['e', 'f']).support 80 >>> tree.lca(['e', 'f']).name 'speciesA' """ for node in self.traverse(): if node.is_root() or node.is_tip(): node.support = None else: node.support, node.name = node._extract_support() def is_bifurcating(self, strict: bool = False, include_self: bool = True): r"""Check if the tree is bifurcating. .. versionadded:: 0.6.3 Parameters ---------- strict : bool, optional Whether to consider single-child nodes as violations of bifurcation. Default is False. include_self : bool, optional If False, will not check the current node. This is useful for checking an unrooted tree, whose root node may have three children. Default is True. See Also -------- bifurcate prune Notes ----- In a bifurcating tree (a.k.a. binary tree), every node has at most two children. The property of bifurcation is necessary for a wide range of tree analyses. In contrast, if a node has three or more children, it is considered as multifurcating, or polytomy in phylogenetics. In strict mode, every internal node (including root) has to have exactly two children in order for the tree to be bifurcating. Single-child nodes are considered as violations. These nodes can be collapsed by :meth:`prune`. This method operates on the subtree below the current node. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b,c),(d,e))root;"]) >>> tree.is_bifurcating() False """ test = ne if strict else gt for node in self.traverse(include_self=include_self): if (children := node.children) and test(len(children), 2): return False return True def observed_node_counts(self, tip_counts: dict[str, int]) -> dict[str, int]: """Return counts of node observations from counts of tip observations. Parameters ---------- tip_counts : dict of ints Counts of observations of tips. Keys correspond to tip names in ``self``, and counts are unsigned ints. Returns ------- dict Counts of observations of nodes. Keys correspond to node names (internal nodes or tips), and counts are unsigned ints. Raises ------ ValueError If a count less than one is observed. MissingNodeError If a count is provided for a tip not in the tree, or for an internal node. """ result: dict[str, int] = defaultdict(int) for tip_name, count in tip_counts.items(): if count < 1: raise ValueError("All tip counts must be greater than zero.") else: t = self.find(tip_name) if not t.is_tip(): raise MissingNodeError( "Counts can only be for tips in the tree. %s is an " "internal node." % t.name ) result[t] += count for internal_node in t.ancestors(): result[internal_node] += count return result @aliased("accumulate_to_ancestor", "0.6.3") def depth( self, ancestor: TreeNode | None = None, include_root: bool = False, use_length: bool = True, missing_as_zero: bool = False, ) -> float: r"""Calculate the depth of the current node. The **depth** of a node is the sum of branch lengths from it to the root of the tree. Parameters ---------- ancestor : TreeNode, optional An ancestral node of self. If provided, the distance from self to this node instead of the root node will be calculated. .. versionchanged:: 0.6.3 Becomes optional. include_root : bool, optional If True, the distance will include the length of the root node, or the given ancestral node if ``ancestor`` is provided. Default is False. .. versionadded:: 0.6.3 use_length : bool, optional Whether to return the sum of branch lengths (True, default) or the number of branches (False) from self to root. .. versionadded:: 0.6.3 missing_as_zero : bool, optional When a node without an associated branch length is encountered, raise an error (False, default) or use 0 (True). Applicable when ``use_length`` is True. .. versionadded:: 0.6.3 Returns ------- float The depth of self. Raises ------ NoParentError If the given ancestral node is not an ancestor of self. NoLengthError If nodes without branch length are encountered, but ``missing_as_zero`` is False. See Also -------- height distance Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a:1,b:2)c:3,(d:4,e:5)f:6)root;"]) >>> tree.find('a').depth() 4.0 >>> tree.find('a').depth(tree.find('c')) 1.0 """ path: list[TreeNode] = [self] path_append = path.append if ancestor is None: curr = self.parent while curr is not None: path_append(curr) curr = curr.parent else: try: curr = self while curr is not ancestor: path_append(curr := curr.parent) # type: ignore except AttributeError: # reached root but didn't encounter ancestor raise NoParentError("Provided ancestor is not ancestral to self.") if not include_root: path = path[:-1] if not use_length: return float(len(path)) if missing_as_zero: return sum(x.length or 0.0 for x in path) try: return sum(x.length for x in path) # type: ignore[misc] except TypeError: raise NoLengthError("Nodes without branch length are encountered.") def height( self, include_self: bool = False, use_length: bool = True, missing_as_zero: bool = False, ) -> tuple[float, TreeNode]: r"""Calculate the height of the current node. .. versionadded:: 0.6.3 The **height** of a node is the maximum sum of branch lengths from it to any of its descending tips. Parameters ---------- include_self : bool, optional If True, the height will include the length of the current node. Default is False. use_length : bool, optional Whether to return the sum of branch lengths (True, default) or the number of branches (False) from self to the most distant tip. missing_as_zero : bool, optional When a node without an associated branch length is encountered, raise an error (False, default) or use 0 (True). Applicable when ``use_length`` is True. Returns ------- float The height of self. TreeNode The most distant descending tip from self. Raises ------ NoLengthError If nodes without branch length are encountered, but ``missing_as_zero`` is False. See Also -------- depth distance Notes ----- When a tie is observed among multiple tips, only one of them will be returned. The choice is stable. This often happens when ``use_length=False``. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a:1,b:2)c:3,(d:4,e:5)f:6)root;"]) >>> dist, tip = tree.find('c').height() >>> dist 2.0 >>> tip.name 'b' """ errmsg = "Nodes without branch length are encountered." maxkey = itemgetter(0) for node in self.postorder(include_self=True): if not node.children: node._height = (0.0, node) else: heights = [] for child in node.children: H, tip = child._height del child._height if not use_length: H += 1.0 elif (L := child.length) is not None: H += L elif not missing_as_zero: raise NoLengthError(errmsg) heights.append((H, tip)) node._height = max(heights, key=maxkey) H, tip = self._height del self._height if include_self: if not use_length: H += 1.0 elif (L := self.length) is not None: H += L elif not missing_as_zero: raise NoLengthError(errmsg) return H, tip @aliased("descending_branch_length", "0.6.3") @params_aliased([("nodes", "tip_subset", "0.6.3", True)]) def total_length( self, nodes: Iterable[TreeNode | str] | None = None, include_stem: bool = False, include_self: bool = False, ) -> float: r"""Calculate the total length of branches descending from self. Parameters ---------- nodes : iterable of TreeNode or str, optional Instances or names of a subset of descending nodes to refine the result. If provided, the total length of branches connecting these nodes will be returned. Otherwise, the total branch length of the tree will be returned. .. versionchanged:: 0.6.3 Can accept TreeNode instances in addition to names. Can accept internal nodes in addition to tips. include_stem : bool, optional Whether to include the path from the lowest common ancestor (LCA) of the subset of nodes to self. Applicable when ``nodes`` is specified. Default is False. .. versionadded:: 0.6.3 include_self : bool, optional Whether to include the length of self. When ``nodes`` is provided and ``include_stem`` is False, it is instead the LCA of the subset of nodes. Default is False. .. versionadded:: 0.6.3 Returns ------- float The total descending branch length. Raises ------ MissingNodeError If some nodes are not found in the tree or are not descendants of self. Notes ----- The metric can be considered as the total amount of evolutionary change across all lineages in the tree. This metric is closely related to phylogenetic diversity (PD) in community ecology. When ``include_stem`` is True, it is equivalent to Faith's PD (see :func:`~skbio.diversity.alpha.faith_pd`). However, this method is optimized to handle a single set of nodes, whereas the referred function is optimized to simultaneously calculate for multiple taxon sets (i.e., communities). Missing branch lengths will be replaced with 0. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read([ ... "(((A:.1,B:1.2)C:.6,(D:.9,E:.6)F:.9)G:2.4,(H:.4,I:.5)J:1.3)K;"]) >>> print(tree.ascii_art()) /-A /C-------| | \-B /G-------| | | /-D | \F-------| -K-------| \-E | | /-H \J-------| \-I Calculate the total branch length of the tree. >>> L = tree.total_length() >>> print(round(L, 1)) 8.9 Calculate the total branch length connecting three taxa. >>> L = tree.total_length(['A', 'E', 'H']) >>> print(round(L, 1)) 6.3 """ # shortcut for the entire subtree if not nodes: return sum( n.length or 0.0 for n in self.postorder(include_self=include_self) ) # Identify all nodes that need to be visited during the navigation from all # tips to the root. This algorithm resembles that of `lca`. However, we will # separate the visited nodes of the first path and all other paths. Also, we # don't need to record the previous node. All we need is whether each node is # unique in all paths. first_path: list[TreeNode] = [] first_path_append = first_path.append it = map(self.find, nodes) curr = next(it) while curr is not None: first_path_append(curr) curr._unique = True curr = curr.parent # type: ignore[assignment] other_paths = [] other_paths_append = other_paths.append for curr in it: while not hasattr(curr, "_unique"): other_paths_append(curr) curr._unique = True curr = curr.parent curr._unique = False # Iterate the first path in reverse order (from root to starting node) and find # the indices of self and LCA. i_self, i_lca = None, 0 for i in reversed(range(len(first_path))): if (node := first_path[i]) is self: i_self = i if node._unique is False: i_lca = i break # clear temporary attribute for node in first_path: del node._unique for node in other_paths: del node._unique # If all nodes are descendants of self, LCA must also be self or one of its # descendants, and self must be identified when iterating the first path. if i_self is None: raise MissingNodeError("Some nodes are not descendants of self.") # Identify the range of nodes to be included in calculation depending on the # parameter setting stop = (i_self if include_stem else i_lca) + include_self # sum up branch lengths return ( sum(n.length or 0.0 for n in chain(first_path[:stop], other_paths)) or 0.0 ) def distance( self, other: TreeNode, use_length: bool = True, missing_as_zero: bool = False ) -> float: r"""Calculate the distance between self and another node. Parameters ---------- other : TreeNode The node to compute a distance to. use_length : bool, optional Whether to return the sum of branch lengths (True, default) or the number of branches (False) connecting self and other. .. versionadded:: 0.6.3 missing_as_zero : bool, optional When a node without an associated branch length is encountered, raise an error (False, default) or use 0 (True). Applicable when ``use_length`` is True. .. versionadded:: 0.6.3 Returns ------- float The distance between two nodes. Raises ------ NoLengthError If nodes without branch length are encountered, but ``missing_as_zero`` is False. See Also -------- path cophenet compare_cophenet maxdist Notes ----- The distance between two nodes is the length of the path (branches) connecting them. It is also known as the patristic distance [1]_. When ``use_length=False``, it is the number of branches in the path. This method can be used to compute the distance between two given nodes. However, it is not optimized for computing all pairwise tip distances. Use :meth:`cophenet` instead for that purpose. References ---------- .. [1] Fourment, M., & Gibbs, M. J. (2006). PATRISTIC: a program for calculating patristic distances and graphically comparing the components of genetic change. BMC evolutionary biology, 6, 1-5. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a:1,b:2)c:3,(d:4,e:5)f:6)root;"]) >>> tip_a = tree.find('a') >>> tip_d = tree.find('d') >>> tip_a.distance(tip_d) 14.0 >>> tip_a.distance(tip_d, use_length=False) 4.0 """ _, self_path, other_path = self._path(other) if not use_length: return float(len(self_path) + len(other_path)) if missing_as_zero: return sum(x.length or 0.0 for x in chain(self_path, other_path)) try: return sum(x.length for x in chain(self_path, other_path)) except TypeError: raise NoLengthError("Nodes without branch length are encountered.") @aliased("get_max_distance", "0.6.3") def maxdist( self, use_length: bool = True ) -> tuple[float, tuple[TreeNode, TreeNode]]: r"""Return the maximum distance between any pair of tips in the tree. This measure is also referred to as the **diameter** of a tree. Parameters ---------- use_length : bool, optional Whether to return the sum of branch lengths (True, default) or the number of branches (False) connecting each pair of tips. .. versionadded:: 0.6.3 Returns ------- float The distance between the two most distant tips in the tree. tuple of (TreeNode, TreeNode) The two most distant tips in the tree. See Also -------- distance cophenet scipy.cluster.hierarchy.maxdists Notes ----- This method identifies the two furthest apart tips in a tree, as measured by the sum of branch lengths (i.e., patristic distance) connecting them. Missing branch lengths will be replaced with 0. When ``use_length=False``, the number of branches connecting two tips will be considered instead. When a tie is observed among more than one pair of tips, only one pair will be returned. The choice is stable. This often happens when ``use_length=False``. This method operates on the subtree below the current node. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a:1,b:2)c:3,(d:4,e:5)f:6)root;"]) >>> dist, tips = tree.maxdist() >>> dist 16.0 >>> [n.name for n in tips] ['e', 'b'] """ # The code performs a post-order traversal and appends two pieces of # information to each node: # a: The maximum distance from the node to any descending tip. # b: The maximum distance between any two descending tips. # The information is updated at each internal node: # a becomes the maximum of any child's (a + length). # b becomes the larger of the maximum of any b and the sum of the two # largest (a + length). The latter represents the new plausible maximum # distance that crosses the node. maxkey = itemgetter(0) for node in self.postorder(): # initialize maximum at tip: (up_dist, up_tip, in_dist, in_tip1, in_tip2) if not node.children: node._maxdist = (0, node, 0, None, None) # internal node: update the maximum elif len(children := node.children) > 1: ups, ins = [], [] for child in children: up_dist, up_tip, in_dist, in_tip1, in_tip2 = child._maxdist del child._maxdist ups.append( (up_dist + (child.length or 0.0 if use_length else 1), up_tip) ) ins.append((in_dist, in_tip1, in_tip2)) # compare the previous maximum with the distance between the two # longest descendants from any two child clades ups.sort(key=maxkey, reverse=True) (up_dist, up_tip), (up_dist2, up_tip2) = ups[:2] in_dist, in_tip1, in_tip2 = max(ins, key=maxkey) if (x_dist := up_dist + up_dist2) > in_dist: node._maxdist = (up_dist, up_tip, x_dist, up_tip, up_tip2) else: node._maxdist = (up_dist, up_tip, in_dist, in_tip1, in_tip2) # internal node with only one child: inherit the maximum else: (child,) = children up_dist, up_tip, in_dist, in_tip1, in_tip2 = child._maxdist del child._maxdist up_dist += child.length or 0.0 if use_length else 1 node._maxdist = (up_dist, up_tip, in_dist, in_tip1, in_tip2) max_dist, max_tip1, max_tip2 = self._maxdist[2:] del self._maxdist if not use_length: max_dist = float(max_dist) return max_dist, (max_tip1, max_tip2) @aliased("tip_tip_distances", "0.6.3") def cophenet( self, endpoints: Iterable[TreeNode | str] | None = None, use_length: bool = True, ) -> DistanceMatrix: r"""Return a distance matrix between each pair of tips in the tree. Parameters ---------- endpoints : iterable of TreeNode or str, optional Tips or their names (i.e., taxa) to be included in the calculation. The returned distance matrix will use this order. If not specified, all tips will be included. use_length : bool, optional Whether to return the sum of branch lengths (True, default) or the number of branches (False) connecting each pair of tips. .. versionadded:: 0.6.3 Returns ------- DistanceMatrix The cophenetic distance matrix. Raises ------ MissingNodeError If any of the specified ``endpoints`` are not found in the tree. DuplicateNodeError If the specified ``endpoints`` have duplicates. ValueError If any of the specified ``endpoints`` are not tips. See Also -------- distance compare_cophenet scipy.cluster.hierarchy.cophenet Notes ----- The cophenetic distance [1]_ between a pair of tips is essentially the sum of branch lengths connecting them (i.e., patristic distance [2]_, see :meth:`distance`). It measures the divergence between two taxa in evolution. This method calculates the cophenetic distances between all pairs of tips in a tree and returns a distance matrix. Missing branch lengths will be replaced with 0's. If ``use_length`` is False, the method instead calculates the number of branches connecting each pair of tips. This method operates on the subtree below the current node. In hierarchical clustering, the cophenetic distance is commonly used to measure the dissimilarity between two objects before they are joined in a dendrogram. In that context, it is also defined as the height of the lowest common ancestor (LCA) from the surface of the tree. However, phylogenetic trees are usually non-ultrametric (e.g., :func:`~skbio.tree.nj`), and the two child clades of a node may have different heights. Therefore, the cophenetic distance is instead defined as the patristic distance between the two tips. For ultrametric trees (e.g., :func:`~skbio.tree.upgma`), this method's result should match SciPy's :func:`~scipy.cluster.hierarchy.cophenet`. One should also distinguish cophenetic distance from a related metric: cophenetic value [1]_, which is the patristic distance between the LCA of two tips and the root of the tree. It quantifies the shared evolutionary history between two taxa, as in contrast to the cophenetic distance. References ---------- .. [1] Sokal, R. R., & Rohlf, F. J. (1962). The comparison of dendrograms by objective methods. Taxon, 33-40. .. [2] Fourment, M., & Gibbs, M. J. (2006). PATRISTIC: a program for calculating patristic distances and graphically comparing the components of genetic change. BMC evolutionary biology, 6, 1-5. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a:1,b:2)c:3,(d:4,e:5)f:6)root;"]) Calculate cophenetic distances as the sum of branch lengths (i.e., patristic distance). >>> mat = tree.cophenet() >>> print(mat) 4x4 distance matrix IDs: 'a', 'b', 'd', 'e' Data: [[ 0. 3. 14. 15.] [ 3. 0. 15. 16.] [ 14. 15. 0. 9.] [ 15. 16. 9. 0.]] Calculate cophenetic distances as the number of branches. >>> mat = tree.cophenet(use_length=False) >>> print(mat) 4x4 distance matrix IDs: 'a', 'b', 'd', 'e' Data: [[ 0. 2. 4. 4.] [ 2. 0. 4. 4.] [ 4. 4. 0. 2.] [ 4. 4. 2. 0.]] """ taxa: list[str] = [] taxa_append = taxa.append # Include all tips. # `tips()` performs a postorder traversal, which guarantees the continuity # of tip indices within each node. A `_range` attribute is assigned to each # node, representing the range of tip indices. if not endpoints: i = 0 for tip in self.tips(): if (name := tip.name) is not None: taxa_append(name) tip._range = (i, i + 1) i += 1 num_tips = len(taxa) # A tree could have duplicate taxa so this check is desired. if len(set(taxa)) < num_tips: raise DuplicateNodeError(f"Tree contains duplicate tip names.") # Include only selected tips in order. # Only selected tips are indexed, but the continuity of tip indices (see above) # is still ensured. else: idxmap = {} for i, endpoint in enumerate(endpoints): tip = self.find(endpoint) if (name := tip.name) in idxmap: raise DuplicateNodeError(f"Duplicate tip name '{name}' found.") if tip.children: raise ValueError(f"Node with name '{name}' is not a tip.") # The `find` call above guarantees `name` cannot be None. taxa_append(name) # type: ignore[arg-type] idxmap[name] = i num_tips = len(taxa) # Create an index array to store the order of indices of original tips. order: np.ndarray = np.empty(num_tips, dtype=int) i = 0 for tip in self.tips(): if (name := tip.name) in idxmap: tip._range = (i, i + 1) order[idxmap[name]] = i i += 1 # Initiate the resulting distance matrix. result = np.zeros((num_tips, num_tips)) # An intermediate vector storing the accumulative distance from each tip to # the current node. depths = np.zeros(num_tips) # Traverse internal nodes. # This method involves two postorder traversals. Theoretically, one can perform # only one traversal, and store tip and internal node references into two lists # for use. However, this method isn't more efficient according to benchmarks. for node in self.postorder(): if not node.children: continue # Record tip ranges of each child clade, and increment the tip depths. ranges = [] for child in node.children: if not hasattr(child, "_range"): continue ranges.append(range_ := slice(*child._range)) depths[range_] += (child.length or 0.0) if use_length else 1 del child._range # Calculate tip-to-tip distances between each pair of child clades, and # save the results to both upper and lower triangles of the resulting # distance matrix. # This is significantly faster than saving to only one triangle and doing # doing `result += result.T` after the iteration. for range1, range2 in combinations(ranges, 2): dists = depths[range1][:, None] + depths[range2] result[range1, range2] = dists result[range2, range1] = dists.T # Due to the continuity of tip indices (see above), it is guaranteed that # the first child is the smallest and the last child is the largest. if ranges: node._range = (ranges[0].start, ranges[-1].stop) if hasattr(self, "_range"): del self._range # Reorder the distance matrix to reflect the given order of endpoints. if endpoints: result = result[np.ix_(order, order)] # Skip validation as all items to validate are guaranteed. return DistanceMatrix(result, taxa, validate=False) @params_aliased([("shared_only", "exclude_absent_taxa", "0.6.3", True)]) def compare_subsets( self, other: TreeNode, shared_only: bool = False, proportion: bool = True ) -> float: r"""Calculate the difference of subsets between two trees. Parameters ---------- other : TreeNode The other tree to compare with. shared_only : bool, optional Only consider taxa shared with the other tree. Default is False. proportion : bool, optional Whether to return count (False) or proportion (True, default) of different subsets. .. versionadded:: 0.6.3 Returns ------- float The count or proportion of subsets that differ between the trees. See Also -------- subsets compare_rfd compare_biparts Notes ----- This metric is equivalent to the Robinson-Foulds distance on rooted trees. Examples -------- >>> from skbio import TreeNode >>> tree1 = TreeNode.read(["((a,b),(c,d));"]) >>> tree2 = TreeNode.read(["(((a,b),c),d);"]) >>> tree1.compare_subsets(tree2) 0.5 """ return _topo_dists((self, other), True, shared_only, proportion)[0] def compare_biparts(self, other: TreeNode, proportion: bool = True) -> float: r"""Calculate the difference of bipartitions between two trees. .. versionadded:: 0.6.3 Parameters ---------- other : TreeNode The other tree to compare with. proportion : bool, optional Whether to return count (False) or proportion (True, default) of different bipartitions. Returns ------- float The count or proportion of bipartitions that differ between the trees. See Also -------- biparts compare_rfd compare_subsets Notes ----- This metric is equivalent to the Robinson-Foulds distance on unrooted trees. Only taxa shared between the two trees are considered. Examples -------- >>> from skbio import TreeNode >>> tree1 = TreeNode.read(["((a,b),(c,d));"]) >>> tree2 = TreeNode.read(["(((a,b),c),d);"]) >>> tree1.compare_biparts(tree2) 0.0 """ return _topo_dists((self, other), False, True, proportion)[0] def compare_rfd( self, other: TreeNode, proportion: bool = False, rooted: bool | None = None ) -> float: r"""Calculate Robinson-Foulds distance between two trees. Parameters ---------- other : TreeNode The other tree to compare with. proportion : bool, optional Whether to return the RF distance as count (False, default) or proportion (True). rooted : bool, optional Whether to consider the trees as rooted or unrooted. If None (default), this will be determined based on whether self is rooted. However, one can override it by explicitly specifying True (rooted) or False (unrooted). .. versionadded:: 0.6.3 Returns ------- float The Robinson-Foulds distance as count or proportion between the trees. .. versionchanged:: 0.6.3 When the tree is unrooted, the calculation is based on bipartitions instead of subsets. Notes ----- The Robinson-Foulds (RF) distance, a.k.a. symmetric difference, is a measure of topological dissimilarity between two trees. It was originally described in [1]_. It is calculated as the number of bipartitions that differ between two unrooted trees. It is equivalent to :meth:`compare_biparts`. .. math:: \text{RF}(T_1, T_2) = |S_1 \triangle S_2| = |(S_1 \setminus S_2) \cup (S_2 \setminus S_1)| where :math:`S_1` and :math:`S_2` are the sets of bipartitions of trees :math:`T_1` and :math:`T_2`, respectively. For rooted trees, the RF distance is calculated as the number of unshared clades (subsets of taxa) [2]_. It is equivalent to :meth:`compare_subsets`. This method automatically determines whether to use the unrooted or rooted RF distance based on whether self is rooted or not. Specifically, if self has two children (see :meth:`details `), or has a parent (i.e., it is a subtree within a larger tree), it will be considered as rooted. Otherwise it will be considered as unrooted. One can override this automatic decision by setting the ``rooted`` parameter, which is recommended for explicitness. By specifying ``proportion=True``, a unit distance will be returned, ranging from 0 (identical) to 1 (completely different). This method operates on the subtrees below the given nodes. Only taxa shared between the two trees are considered. Taxa unique to either tree are excluded from the calculation. See Also -------- compare_wrfd compare_subsets compare_biparts skbio.tree.rf_dists References ---------- .. [1] Robinson, D. F., & Foulds, L. R. (1981). Comparison of phylogenetic trees. Mathematical biosciences, 53(1-2), 131-147. .. [2] Bogdanowicz, D., & Giaro, K. (2013). On a matching distance between rooted phylogenetic trees. International Journal of Applied Mathematics and Computer Science, 23(3), 669-684. Examples -------- Calculate the RF distance between two unrooted trees with the same taxa but different topologies. Each tree has three non-trivial bipartitions, as defined by individual internal branches, among which one pair (abc|def) is shared whereas the other two of each tree are unique (ab|cdef, abcf|de, bc|adef, abcd|ef). Therefore the RF distance is 2 + 2 = 4. >>> from skbio import TreeNode >>> tree1 = TreeNode.read(["((a,b),c,((d,e),f));"]) >>> print(tree1.ascii_art()) /-a /--------| | \-b | ---------|--c | | /-d | /--------| \--------| \-e | \-f >>> tree2 = TreeNode.read(["((a,(b,c)),d,(e,f));"]) >>> print(tree2.ascii_art()) /-a /--------| | | /-b | \--------| | \-c ---------| |--d | | /-e \--------| \-f >>> tree1.compare_rfd(tree2) 4.0 """ if rooted is None: rooted = self.parent is not None or len(self.children) == 2 return _topo_dists((self, other), rooted, proportion=proportion)[0] def compare_wrfd( self, other: TreeNode, metric: str | Callable[[Sequence, Sequence], float] = "cityblock", rooted: bool | None = None, include_tips: bool = True, ) -> float: r"""Calculate weighted Robinson-Foulds distance or variants between two trees. .. versionadded:: 0.6.3 Parameters ---------- other : TreeNode The other tree to compare with. metric : str or callable, optional The distance metric to use. Can be a preset, a distance function name under :mod:`scipy.spatial.distance`, or a custom function that takes two vectors and returns a number. Some notable options are: - "cityblock" (default): City block (Manhattan) distance. The result matches the original weighted Robinson-Foulds distance [1]_. - "euclidean": Euclidean distance. The result matches the Kuhner-Felsenstein (KF) distance, a.k.a. branch score (Bs) distance [2]_. - "correlation": 1 - Pearson's correlation coefficient (:math:`r`). Ranges between 0 (maximum similarity) and 2 (maximum dissimilarity). Independent of tree scale. - "unitcorr": :math:`(1 - r) / 2`, which returns a unit correlation distance (range: [0, 1]). rooted : bool, optional Whether to consider the trees as rooted or unrooted. If None (default), this will be determined based on whether self is rooted. However, one can override it by explicitly setting True (rooted) or False (unrooted). See :meth:`compare_rfd` for details. include_tips : bool, optional Whether to include single-taxon biparitions (terminal branches) in the calculation. Default is True, such that all branches in the trees are considered. Set this as False if terminal branch lengths are absent or irrelevant. Returns ------- float The weighted Robinson-Foulds distance or variants between the trees. Notes ----- The Robinson-Foulds (RF) distance may be weighted by the branch lengths of bipartitions to account for evolutionary distances in addition to branching patterns. The default behavior of this method calculates the original weighted RF (wRF) distance [1]_, which is the sum of differences of branch lengths of matching bipartitions. Bipartitions unique to one tree are given a length of 0 in the other tree during calculation. .. math:: \text{wRF}(T_1, T_2) = \sum_{s \in S_1 \cup S_2} |l_1(s) - l_2(s)| where :math:`S_1` and :math:`S_2` are the sets of bipartitions of trees :math:`T_1` and :math:`T_2`, respectively. :math:`l_1` and :math:`l_2` are the branch lengths of bipartition :math:`s` in :math:`T_1` and :math:`T_2`, respectively (or 0 if :math:`s` is unique to the other tree). When ``metric="euclidean"``, it calculates the Kuhner-Felsenstein (KF) distance, a.k.a., branch score (Bs) distance [2]_, which replaces absolute difference with squared difference in the equation. .. math:: \text{KF}(T_1, T_2) = \sqrt{\sum_{s \in S_1 \cup S_2} (l_1(s) - l_2(s))^2} This method operates on the subtrees below the given nodes. Only taxa shared between the two trees are considered. Taxa unique to either tree are excluded from the calculation. See Also -------- compare_rfd compare_cophenet skbio.tree.wrf_dists References ---------- .. [1] Robinson, D. F., & Foulds, L. R. (1979) Comparison of weighted labelled trees. In Combinatorial Mathematics VI: Proceedings of the Sixth Australian Conference on Combinatorial Mathematics, Armidale, Australia (pp. 119-126). .. [2] Kuhner, M. K., & Felsenstein, J. (1994). A simulation comparison of phylogeny algorithms under equal and unequal evolutionary rates. Molecular biology and evolution, 11(3), 459-468. Examples -------- >>> from skbio import TreeNode >>> tree1 = TreeNode.read(["((a:1,b:2):1,c:4,((d:4,e:5):2,f:6):1);"]) >>> print(tree1.ascii_art()) /-a /--------| | \-b | ---------|--c | | /-d | /--------| \--------| \-e | \-f >>> tree2 = TreeNode.read(["((a:3,(b:2,c:2):1):3,d:8,(e:5,f:6):2);"]) >>> print(tree2.ascii_art()) /-a /--------| | | /-b | \--------| | \-c ---------| |--d | | /-e \--------| \-f Calculate the weighted RF (wRF) distance between two unrooted trees with branch lengths. >>> tree1.compare_wrfd(tree2) 16.0 Calculated the wRF distance while considering trees as rooted (therefore based on subsets instead of bipartitions). >>> tree1.compare_wrfd(tree2, rooted=True) 18.0 Calculate the Kuhner-Felsenstein (KF) distance. >>> d = tree1.compare_wrfd(tree2, metric="euclidean") >>> print(round(d, 5)) 6.16441 Calculate the KF distance without considering terminal branches. >>> d = tree1.compare_wrfd(tree2, metric="euclidean", include_tips=False) >>> print(round(d, 5)) 3.74166 """ if rooted is None: rooted = self.parent is not None or len(self.children) == 2 metric = _check_dist_metric(metric) return _topo_dists( (self, other), rooted=rooted, include_tips=include_tips, weighted=True, metric=metric, )[0] @aliased("compare_tip_distances", "0.6.3") @params_aliased( [ ("shuffler", "shuffle_f", "0.6.3", True), ("metric", "dist_f", "0.6.3", True), ] ) def compare_cophenet( self, other: TreeNode, sample: int | None = None, metric: str | Callable[[Sequence, Sequence], float] = "unitcorr", shuffler: int | np.random.Generator | Callable | None = None, use_length: bool = True, ignore_self: bool = True, ) -> float: r"""Calculate the distance between two trees based on cophenetic distances. Parameters ---------- other : TreeNode The other tree to compare with. sample : int, optional Randomly subsample this number of tips in common between the trees to compare. This is useful when comparing very large trees. metric : str or callable, optional The distance metric to use. Can be a preset, a distance function name under :mod:`scipy.spatial.distance`, or a custom function that takes two vectors and returns a number. Some notable options are: - "cityblock": City block (Manhattan) distance. - "euclidean": Euclidean distance. The result matches the path-length distance [1]_, or the path distance [2]_ if ``use_length`` is False. - "correlation": 1 - Pearson's correlation coefficient (:math:`r`). Ranges between 0 (maximum similarity) and 2 (maximum dissimilarity). Independent of tree scale. - "unitcorr" (default): :math:`(1 - r) / 2`, which returns a unit correlation distance (range: [0, 1]). .. versionchanged:: 0.6.3 Accepts a function on two vectors instead of two `DistanceMatrix` instances. The default value "unitcorr" is consistent with the previous default behavior. shuffler : int, np.random.Generator or callable, optional The shuffling function to use if ``sample`` is specified. Default is :meth:`~numpy.random.Generator.shuffle`. If an integer is provided, a random generator will be constructed using this number as the seed. .. versionchanged:: 0.6.3 Switched to NumPy's new random generator. Can accept a random seed or random generator instance. use_length : bool, optional Whether to calculate the sum of branch lengths (True, default) or the number of branches (False) connecting each pair of tips. .. versionadded:: 0.6.3 ignore_self : bool, optional Whether to ignore the distance between each tip and itself (which must be 0). Default is True. .. versionadded:: 0.6.3 .. versionchanged:: 0.7.0 The default value has been changed to True. Returns ------- float The distance between the trees. .. versionchanged:: 0.6.3 Improved customizability to allow calculation of published metrics, such as path distance and path-length distance, while preserving the previous default behavior. Edge cases are now handled by the specified distance metric rather than being treated separately. Raises ------ ValueError If there are no common tips between the trees. See Also -------- cophenet compare_rfd compare_wrfd skbio.tree.path_dists Notes ----- This method calculates the dissimilarity between the cophenetic distance [1]_ (i.e., tip-to-tip distance) matrices of two trees. Tips are identified by their names (i.e., taxa). Only tips shared between the trees are considered. Tips unique to either tree are excluded from the calculation. The default behavior returns a unit correlation distance (range: [0, 1]), measuring the dissimilarity between the relative evolutionary distances among taxa, regardless of the tree scale (i.e., multiply all branch lengths in one tree by a factor and the result remains the same). This measure is closely related to **cophenetic correlation**, which measures the similarity (instead of dissimilarity) between two cophenetic distance matrices, or between a cophenetic distance matrix and the original distance matrix among taxa on which hierarchical clustering was performed. When the metric is Euclidean and lengths are used, it returns the **path-length distance** [2]_, which is the square root of the sum of squared differences of path lengths among all pairs of taxa. .. math:: d(T_1, T_2) = \sqrt{\sum (d_1(i,j) - d_2(i,j))^2} where :math:`d_1` and :math:`d_2` are the sums of branch lengths connecting a pair of tips :math:`i` and :math:`j` in trees :math:`T_1` and :math:`T_2`, respectively. When the metric is Euclidean and lengths are not used, it returns the **path distance** [3]_, which insteads considers the number of edges in the path. References ---------- .. [1] Sokal, R. R., & Rohlf, F. J. (1962). The comparison of dendrograms by objective methods. Taxon, 33-40. .. [2] Lapointe, F. J., & Cucumel, G. (1997). The average consensus procedure: combination of weighted trees containing identical or overlapping sets of taxa. Systematic Biology, 46(2), 306-312. .. [3] Steel, M. A., & Penny, D. (1993). Distributions of tree comparison metrics—some new results. Systematic Biology, 42(2), 126-141. Examples -------- >>> from skbio import TreeNode >>> tree1 = TreeNode.read(["((a:1,b:2):1,c:4,((d:4,e:5):2,f:6):1);"]) >>> print(tree1.ascii_art()) /-a /--------| | \-b | ---------|--c | | /-d | /--------| \--------| \-e | \-f >>> tree2 = TreeNode.read(["((a:3,(b:2,c:2):1):3,d:8,(e:5,f:6):2);"]) >>> print(tree2.ascii_art()) /-a /--------| | | /-b | \--------| | \-c ---------| |--d | | /-e \--------| \-f Calculate the unit correlation distance between the two trees. >>> d = tree1.compare_cophenet(tree2) >>> print(round(d, 5)) 0.14131 Calculate the path-length distance between the two trees. >>> d = tree1.compare_cophenet(tree2, metric="euclidean") >>> print(round(d, 5)) 13.71131 Calculate the path distance between the two trees. >>> tree1.compare_cophenet(tree2, metric="euclidean", use_length=False) 4.0 """ metric = _check_dist_metric(metric) if sample is not None: shuffler = _check_shuffler(shuffler) return _path_dists( trees=(self, other), sample=sample, metric=metric, shuffler=shuffler, use_length=use_length, ignore_self=ignore_self, )[0] # ------------------------------------------------ # Tree indexing and searching # ------------------------------------------------ def has_caches(self) -> tuple[set[str] | None, bool]: r"""Check if the current tree has caches. .. versionadded:: 0.6.3 Returns ------- set or None Names of present node attribute caches, or None if none is present. bool Presence (True) or absence (False) of node lookup caches. See Also -------- clear_caches cache_attr find Notes ----- Caches are optional but can significantly accelerate certain analyses of the tree. Two types of caches may be created: 1. **Node attributes**, which may be created by calling :meth:`cache_attr` and assigned to individual nodes within the tree. The names of these attributes are optionally registered at the root. 2. **Node lookup table**, which is automatically created during the first node search (e.g., by calling :meth:`find`) and reused in subsequent searches. This table is attached to the root of the tree. This method checks if a node lookup table and any registered node attributes are present at the root node of the tree. The returned set of node attribute names is a reference instead of a copy. One may edit the set in place to explicitly enable/disable names. Use this feature with caution. When the tree is manipulated, caches typically become obsolete and are automatically cleared. If the caches are not present or not relevant to the analysis, you may set ``uncache=False`` when performing individual operations to suppress clearing. This can improve the performance of these operations. You may explicitly call :meth:`clear_caches` to clear caches of a tree. """ tree = self.root() attrs = getattr(tree, "_registered_caches", None) lookup = hasattr(tree, "_tip_cache") and hasattr(tree, "_non_tip_cache") return attrs, lookup @aliased("invalidate_caches", "0.6.3", True) def clear_caches(self, attr: bool | str = True, lookup: bool = True): r"""Delete node attribute and lookup caches of a tree. Parameters ---------- attr : bool or str, optional Whether to delete attribute caches created by ``cache_attr`` (default: True). One may instead provide an attribute name such that only this attribute will be deleted. .. versionchanged:: 0.6.3 Can provide a specific attribute name. lookup : bool, optional Whether to delete lookup caches created during name searching (default: True). .. versionadded:: 0.6.3 See Also -------- has_caches cache_attr find Notes ----- This method may be called from any node within a tree. The caches, which were attached to the root node of the tree, will be deleted. This method will silently skip if the specified caches do not exist. """ tree = self.root() # delete attribute caches if attr and hasattr(tree, "_registered_caches"): attrs = tree._registered_caches # delete a single attribute if isinstance(attr, str): if attr not in attrs: return for node in tree.traverse(): if hasattr(node, attr): delattr(node, attr) if len(attrs) == 1: del tree._registered_caches else: attrs.remove(attr) # delete all attributes else: for node in tree.traverse(): for attr_ in attrs: if hasattr(node, attr_): delattr(node, attr_) del tree._registered_caches # delete lookup caches if lookup: for key in ("_tip_cache", "_non_tip_cache"): if hasattr(tree, key): delattr(tree, key) def cache_attr( self, func: Callable, cache_attrname: str, cache_type: type | Callable | None = list, register: bool = True, ): r"""Cache attributes on nodes of the tree through a postorder traversal. Parameters ---------- func : callable Function to calculate the attribute of the current node. The result will be combined with the attributes of the previous nodes, if applicable. cache_attrname : str Name of the attribute to be attached to each node. cache_type : {list, tuple, set, frozenset}, callable, or None The type of the cache. Can be any of the four iterable types: list (default), tuple, set, or frozenset. In these cases, combination of attributes of the node's children and itself will be automated. Or a custom function that takes two arguments: list of attributes of its children, and attribute calculated from itself by ``func``, and returns the combined attribute of the node. Or None, in which case combination of attributes of children and self will not take place, unless explicitly customized within ``func``. .. versionchanged:: 0.6.3 Tuple, custom function and None were added to the options. register : bool, optional Whether to register the attribute name as a cache of the tree, such that the attributes will be deleted from all nodes when the tree is manipulated or the ``clear_caches`` method is explicitly invoked. Default is True. .. versionadded:: 0.6.3 Raises ------ TypeError If ``cache_type`` is invalid. See Also -------- has_caches clear_caches Notes ----- This method provides an efficient interface to assign a custom attribute to every node of a tree through one postorder traversal. It is particularly useful if one needs to frequently look up attributes that would normally require one traversal of the tree per lookup. The assigned attributes may be automatically deleted when the tree is manipulated. Examples -------- This method facilitates evaluation for various useful node properties. Some representative examples are provided below. >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a:1.2,b:1.6)c:0.3,(d:0.8,e:1.0)f:0.6)g;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b -g-------| | /-d \f-------| \-e Cache a list of all descending tip names on each node. This facilitates the assignment of taxon set under each clade in the tree. It resembles but is more efficient than calling :meth:`subset` multiple times. >>> f = lambda n: [n.name] if n.is_tip() else [] >>> tree.cache_attr(f, 'tip_names') >>> for node in tree.traverse(include_self=True): ... print(f"Node: {node.name}, tips: {node.tip_names}") Node: g, tips: ['a', 'b', 'd', 'e'] Node: c, tips: ['a', 'b'] Node: a, tips: ['a'] Node: b, tips: ['b'] Node: f, tips: ['d', 'e'] Node: d, tips: ['d'] Node: e, tips: ['e'] Cache the number of nodes per clade. The function ``sum`` is used in place of cache type such that the count will be accumulated. This resembles but is more efficient than calling :meth:`count` multiple times. >>> f = lambda n: 1 >>> tree.cache_attr(f, 'node_count', sum) >>> tree.node_count 7 Cache the sum of branch lengths per clade. This resembles but is more efficient than calling :meth:`total_length` multiple times. >>> f = lambda n: n.length or 0.0 >>> tree.cache_attr(f, 'clade_size', sum) >>> tree.clade_size 5.5 Cache the accumulative distances from all tips to the common ancestor of each clade. This is more efficient than calling :meth:`depth` multiple times. One can further apply calculations like mean and standard deviation to the results. >>> import numpy as np >>> dist_f = lambda n: np.array(n.length or 0.0, ndmin=1) >>> comb_f = lambda prev, curr: np.concatenate(prev) + curr if prev else curr >>> tree.cache_attr(dist_f, 'accu_dists', comb_f) >>> tree.accu_dists array([ 1.5, 1.9, 1.4, 1.6]) """ combine_f: Callable | None if cache_type in (set, frozenset): def combine_f(prev, curr): return cache_type().union(*prev + [curr]) elif cache_type in (list, tuple): def combine_f(prev, curr): return cache_type(chain.from_iterable(prev + [curr])) elif callable(cache_type) or cache_type is None: combine_f = cache_type else: raise TypeError("Cache type is invalid.") # register attribute name as a cache if register: tree = self.root() if not hasattr(tree, "_registered_caches"): tree._registered_caches = set() tree._registered_caches.add(cache_attrname) # traverse tree and assign attributes if combine_f is not None: for node in self.postorder(include_self=True): prev_attrs = [getattr(c, cache_attrname) for c in node.children] curr_attr = func(node) setattr(node, cache_attrname, combine_f(prev_attrs, curr_attr)) else: for node in self.postorder(include_self=True): setattr(node, cache_attrname, func(node)) def assign_ids(self): """Assign topologically stable unique IDs to all nodes of the tree. See Also -------- find_by_id postorder Notes ----- This method assigns unique IDs to all nodes of the tree via a postorder traversal. The IDs are incremental integers starting from 0. The order is topologically stable. Following the call, all nodes in the tree will have their ``id`` attribute set. """ curr_index = 0 for n in self.postorder(): for c in n.children: c.id = curr_index curr_index += 1 self.id = curr_index def index_tree(self): r"""Index a tree for rapid lookups within a tree array. Indexes nodes in-place as ``n._leaf_index``. Returns ------- dict A mapping {node_id: TreeNode} ndarray of int This arrays describes the IDs of every internal node, and the ID range of the immediate descendents. The first column in the array corresponds to node_id. The second column is the left most descendent's ID. The third column is the right most descendent's ID. """ self.assign_ids() id_index = {} child_index = [] for n in self.postorder(): for c in n.children: id_index[c.id] = c if c: # c has children itself, so need to add to result child_index.append((c.id, c.children[0].id, c.children[-1].id)) # handle root, which should be t itself id_index[self.id] = self # only want to add to the child_index if self has children... if self.children: child_index.append((self.id, self.children[0].id, self.children[-1].id)) child_index = np.asarray(child_index, dtype=np.int64) child_index = np.atleast_2d(child_index) return id_index, child_index def create_caches(self): r"""Construct an internal lookup table to facilitate searching by name. Raises ------ DuplicateNodeError If there are duplicate tip names. See Also -------- has_caches clear_caches find Notes ----- This method is automatically called during the first search in a tree (methods :meth:`find` and :meth:`find_all`). After that, subsequent searches will utilize the constructed lookup table, until it is deleted. This method may be called from any node within a tree. The lookup table will be attached to the root node of the tree. This method will not cache nodes whose name is ``None``. This method will raise an error if a name conflict in the tips is discovered, but will not raise if on internal nodes. This is because, in practice, the tips of a tree are required to be unique while no such requirement holds for internal nodes. """ tree = self.root() if hasattr(tree, "_tip_cache") and hasattr(tree, "_non_tip_cache"): return tip_cache, non_tip_cache = {}, {} non_tip_cache_setdefault = non_tip_cache.setdefault for node in tree.postorder(): if (name := node.name) is None: continue if node.is_tip(): if name in tip_cache: raise DuplicateNodeError(f"Duplicate tip name '{name}' found.") tip_cache[name] = node else: non_tip_cache_setdefault(name, []).append(node) tree._tip_cache = tip_cache tree._non_tip_cache = non_tip_cache def find(self, name: TreeNode | str) -> TreeNode: r"""Find a node by name. Parameters ---------- name : TreeNode or str The name of the node to find. If a ``TreeNode`` object is provided, will find this particular node in the tree. Returns ------- TreeNode The found node. Raises ------ MissingNodeError If the node to be searched for is not found in the current tree. See Also -------- find_all find_by_id find_by_func Notes ----- This method will first attempt to find the node in the tips. If it cannot find a corresponding tip, it will then search through the internal nodes of the tree. In practice, phylogenetic trees and other common trees in biology do not have unique internal node names. As a result, this find method will only return the first occurrence of an internal node encountered on a postorder traversal of the tree. The first call of ``find`` will cache a node lookup table in the tree on the assumption that additional calls to ``find`` will be made. See :meth:`details `. This method searches within the entire tree where self is located, regardless if self is the root node. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f);"]) >>> node = tree.find('c') >>> node.name 'c' """ tree = self.root() # create lookup table if not already tree.create_caches() # if input is a node, get its name if name_is_node := isinstance(name, tree.__class__): name_ = name.name else: name_ = name if name_ is None: raise MissingNodeError(f"Cannot find a node without a name.") # look up name in tips node = tree._tip_cache.get(name_, None) if node is not None: if not name_is_node or node is name: return node # look up name in non-tips nodes = tree._non_tip_cache.get(name_, None) if nodes is not None: if name_is_node: for node in nodes: if node is name: return node else: return nodes[0] raise MissingNodeError(f"Node '{name_}' is not found in the tree.") def find_all(self, name: TreeNode | str) -> list[TreeNode]: r"""Find all nodes that match a given name. Parameters ---------- name : TreeNode or str The name or node to find. If a ``TreeNode`` object is provided, all nodes with the same name will be returned. Returns ------- list of TreeNode The found nodes. Raises ------ MissingNodeError If the node to be searched for is not found. See Also -------- find find_by_id find_by_func Notes ----- All internal nodes (including root) and tips with the given name will be returned, with the former placed before the latter in the returned list. The first call to ``find_all`` will cache a node lookup table in the tree on the assumption that additional calls to ``find_all`` will be made. See :meth:`details `. This method searches within the entire tree where self is located, regardless if self is the root node. Examples -------- >>> from skbio.tree import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)d,(f,g)c);"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b | | /-d ---------|-d-------| | \-e | | /-f \c-------| \-g >>> for node in tree.find_all('c'): ... print(node.name, node.children[0].name, node.children[1].name) c a b c f g >>> for node in tree.find_all('d'): ... print(node.name, str(node)) d (d,e)d; d d; """ tree = self.root() # if input is a node, get its name if isinstance(name, tree.__class__): name_ = name.name else: name_ = name if name_ is None: raise MissingNodeError(f"Cannot find nodes without a name.") tree.create_caches() tip = tree._tip_cache.get(name_, None) nodes = tree._non_tip_cache.get(name_, []) if tip is not None: nodes.append(tip) if not nodes: raise MissingNodeError(f"Node '{name_}' is not found.") else: return nodes def find_by_id(self, node_id: int) -> TreeNode: r"""Find a node by ID. Parameters ---------- node_id : int The ID of a node in the tree. Returns ------- TreeNode The node with the matching ID. Raises ------ MissingNodeError If the ID cannot be found. See Also -------- assign_ids find Notes ----- This method searches within the subtree under the current node. But the IDs are assigned from the root of the entire tree. This method does not cache ID associations. A full traversal of the tree is performed to find a node by an ID on every call. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f);"]) >>> print(tree.find_by_id(2).name) d """ self.root().assign_ids() for node in self.traverse(include_self=True): if node.id == node_id: return node raise MissingNodeError(f"ID {node_id} is not in self.") def find_by_func(self, func: Callable[[TreeNode], bool]) -> Iterator[TreeNode]: r"""Find all nodes in a tree that meet certain criteria. Parameters ---------- func : callable A function that accepts a ``TreeNode`` and returns True or False, where True indicates the node is to be yielded. Yields ------ TreeNode The found node. See Also -------- find find_all find_by_id Notes ----- This search method is based on the current subtree, not the root. This method does not cache search results. Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f);"]) >>> func = lambda x: x.parent == tree.find('c') >>> [n.name for n in tree.find_by_func(func)] ['a', 'b'] """ for node in self.traverse(include_self=True): if func(node): yield node # ------------------------------------------------ # Tree visualization # ------------------------------------------------ def _ascii_art(self, char1="-", show_internal=True, compact=False): LEN = 10 PAD = " " * LEN PA = " " * (LEN - 1) namestr = self._node_label() if self.children: mids = [] result = [] for c in self.children: if c is self.children[0]: char2 = "/" elif c is self.children[-1]: char2 = "\\" else: char2 = "-" (clines, mid) = c._ascii_art(char2, show_internal, compact) mids.append(mid + len(result)) result.extend(clines) if not compact: result.append("") if not compact: result.pop() (lo, hi, end) = (mids[0], mids[-1], len(result)) prefixes = ( [PAD] * (lo + 1) + [PA + "|"] * (hi - lo - 1) + [PAD] * (end - hi) ) mid = int(np.trunc((lo + hi) / 2)) prefixes[mid] = char1 + "-" * (LEN - 2) + prefixes[mid][-1] result = [p + L for (p, L) in zip(prefixes, result)] if show_internal: stem = result[mid] result[mid] = stem[0] + namestr + stem[len(namestr) + 1 :] return (result, mid) else: return ([char1 + "-" + namestr], 0) def ascii_art(self, show_internal: bool = True, compact: bool = False) -> str: r"""Return a string containing an ascii drawing of the tree. Note, this method calls a private recursive function and is not safe for large trees. Parameters ---------- show_internal : bool includes internal edge names compact : bool use exactly one line per tip Returns ------- str an ASCII formatted version of the tree Examples -------- >>> from skbio import TreeNode >>> tree = TreeNode.read(["((a,b)c,(d,e)f)root;"]) >>> print(tree.ascii_art()) /-a /c-------| | \-b -root----| | /-d \f-------| \-e """ (lines, mid) = self._ascii_art(show_internal=show_internal, compact=compact) return "\n".join(lines) # ------------------------------------------------ # Format conversion # ------------------------------------------------ @classonlymethod @params_aliased( [ ("lnkmat", "linkage_matrix", "0.7.2", False), ("names", "id_list", "0.7.2", False), ] ) def from_linkage_matrix(cls, lnkmat: ArrayLike, names: Iterable[str]) -> Self: r"""Construct tree from a SciPy linkage matrix. Parameters ---------- lnkmat : array_like of shape (n_tips - 1, 3+) A SciPy linkage matrix. names : iterable of str of shape (n_tips,) Corresponding tip names of the indices in the linkage matrix. Returns ------- TreeNode A rooted, bifurcating, and ultrametric tree. See Also -------- scipy.cluster.hierarchy.linkage scipy.cluster.hierarchy.dendrogram Notes ----- A linkage matrix is typically generated by SciPy's hierarchical clustering (:func:`~scipy.cluster.hierarchy.linkage`). It can be plotted as a dendrogram (:func:`~scipy.cluster.hierarchy.dendrogram`). The underlying data structure is an array of *n* - 1 rows representing clusters (i.e., internal nodes) (*n* is the number of taxa) and four columns: 1. Index of left child cluster 2. Index of right child cluster 3. Distance between two child clusters 4. Number of descending taxa (not used in this function) Due to the mathematical nature of hierarchical clustering, the tree converted from a linkage matrix must be a perfect binary tree, where every internal node or root has two children, and all tips have the same depth from root. Examples -------- The following code demonstrates how to call SciPy to perform hierarchical clustering on a scikit-bio ``DistanceMatrix`` and return a scikit-bio ``TreeNode`` object. The same process is wrapped by :func:`skbio.tree.upgma`. >>> from skbio.tree import TreeNode >>> from skbio.stats.distance import DistanceMatrix >>> from scipy.cluster.hierarchy import linkage >>> data = [[0, 5, 9, 9, 8], ... [5, 0, 12, 10, 9], ... [9, 12, 0, 8, 7], ... [9, 10, 8, 0, 3], ... [8, 9, 7, 3, 0]] >>> ids = list('abcde') >>> dm = DistanceMatrix(data, ids) >>> lm = linkage(dm.condensed_form(), method='average') >>> lm array([[ 3. , 4. , 3. , 2. ], [ 0. , 1. , 5. , 2. ], [ 2. , 5. , 7.5, 3. ], [ 6. , 7. , 9.5, 5. ]]) >>> tree = TreeNode.from_linkage_matrix(lm, ids) >>> print(tree.ascii_art()) /-a /--------| | \-b ---------| | /-c \--------| | /-d \--------| \-e """ # see also: skbio.tree._nj._tree_from_linkmat lnkmat = np.asarray(lnkmat) if not isinstance(names, list): names = list(names) n_tips = len(names) n_clusters = lnkmat.shape[0] if n_tips != n_clusters + 1: raise ValueError( "Number of names must be number of rows in the linkage matrix plus one." ) # allocate node list nodes = [cls(x) for x in names + [None] * n_clusters] heights = np.empty(n_clusters + n_tips) heights[:n_tips] = 0.0 left_idx = lnkmat[:, 0].astype(int).tolist() right_idx = lnkmat[:, 1].astype(int).tolist() half_dist = lnkmat[:, 2] * 0.5 # build tree incrementally idx = n_tips for a, b, height in zip(left_idx, right_idx, half_dist): heights[idx] = height child_a = nodes[a] child_b = nodes[b] child_a.length = height - heights[a] child_b.length = height - heights[b] parent = nodes[idx] parent.append(child_a, uncache=False) parent.append(child_b, uncache=False) idx += 1 return nodes[-1] @classonlymethod def from_taxonomy( cls, lineage_map: dict | Iterable[tuple] | pd.DataFrame, extract_rank: bool = False ) -> Self: r"""Construct a tree from a taxonomy. Parameters ---------- lineage_map : dict, iterable of tuples, or pd.DataFrame Mapping of taxon IDs to lineages (iterables of taxonomic units from high to low in ranking). extract_rank : bool, optional Whether to extract rank information from taxon names (default: False). If True, taxon names are expected to have rank prefixes (e.g., "d__Bacteria"). The prefixes will be removed from the names and stored in the ``rank`` attribute of the created nodes. Returns ------- TreeNode The constructed taxonomy. See Also -------- from_taxdump Examples -------- >>> from skbio.tree import TreeNode >>> lineages = [ ... ('1', ['Bacteria', 'Firmicutes', 'Clostridia']), ... ('2', ['Bacteria', 'Firmicutes', 'Bacilli']), ... ('3', ['Bacteria', 'Bacteroidetes', 'Sphingobacteria']), ... ('4', ['Archaea', 'Euryarchaeota', 'Thermoplasmata']), ... ('5', ['Archaea', 'Euryarchaeota', 'Thermoplasmata']), ... ('6', ['Archaea', 'Euryarchaeota', 'Halobacteria']), ... ('7', ['Archaea', 'Euryarchaeota', 'Halobacteria']), ... ('8', ['Bacteria', 'Bacteroidetes', 'Sphingobacteria']), ... ('9', ['Bacteria', 'Bacteroidetes', 'Cytophagia'])] >>> tree = TreeNode.from_taxonomy(lineages) >>> print(tree.ascii_art()) /Clostridia-1 /Firmicutes | \Bacilli- /-2 /Bacteria| | | /-3 | | /Sphingobacteria | \Bacteroidetes \-8 | | ---------| \Cytophagia-9 | | /-4 | /Thermoplasmata | | \-5 \Archaea- /Euryarchaeota | /-6 \Halobacteria \-7 """ root = cls(name=None) root._lookup = {} if isinstance(lineage_map, dict): lineage_map = lineage_map.items() elif isinstance(lineage_map, pd.DataFrame): lineage_map = ((idx, row.tolist()) for idx, row in lineage_map.iterrows()) import re p_rank = re.compile(r"^([a-z])__") has_rank = None for id_, lineage in lineage_map: cur_node = root if isinstance(lineage, str): parsed_lineage = [] for taxon in lineage.split(";"): taxon = taxon.strip() if not taxon: continue parsed_lineage.append(taxon) lineage = parsed_lineage # for each name, see if we've seen it, if not, add that puppy on for name in lineage: rank = None m = p_rank.match(name) if isinstance(name, str) else None if m: rank = m.group(1) if extract_rank: name = name[len(m.group(0)) :] if has_rank is False: raise ValueError( "All taxa must either have a rank or not have a rank. " "A mixture is erroneous." ) has_rank = True else: if has_rank is True: raise ValueError( "All taxa must either have a rank or not have a rank. " "A mixture is erroneous." ) has_rank = False if name in cur_node._lookup: cur_node = cur_node._lookup[name] else: new_node = cls(name=name) if rank is not None: new_node.rank = rank new_node._lookup = {} cur_node._lookup[name] = new_node cur_node.append(new_node, uncache=False) cur_node = new_node cur_node.append(cls(name=id_), uncache=False) # scrub the lookups for node in root.non_tips(include_self=True): del node._lookup return root def to_taxonomy(self, allow_empty: bool = False, filter_f=None) -> Iterator[tuple]: """Return a taxonomy representation of self. Parameters ---------- allow_empty : bool, optional Allow gaps the taxonomy (e.g., internal nodes without names). filter_f : function, optional Specify a filtering function that returns True if the lineage is to be returned. This function must accept a ``TreeNode`` as its first parameter, and a ``list`` that represents the lineage as the second parameter. Yields ------ tuple ``(tip, [lineage])`` where ``tip`` corresponds to a tip in the tree and ``[lineage]`` is the expanded names from root to tip. ``None`` and empty strings are omitted from the lineage. Notes ----- If ``allow_empty`` is True and the root node does not have a name, that name will not be included. This is because it is common to have multiple domains represented in the taxonomy, which would result in a root node that does not have a name and does not make sense to represent in the output. Examples -------- >>> from skbio.tree import TreeNode >>> lineages = {'1': ['Bacteria', 'Firmicutes', 'Clostridia'], ... '2': ['Bacteria', 'Firmicutes', 'Bacilli'], ... '3': ['Bacteria', 'Bacteroidetes', 'Sphingobacteria'], ... '4': ['Archaea', 'Euryarchaeota', 'Thermoplasmata'], ... '5': ['Archaea', 'Euryarchaeota', 'Thermoplasmata'], ... '6': ['Archaea', 'Euryarchaeota', 'Halobacteria'], ... '7': ['Archaea', 'Euryarchaeota', 'Halobacteria'], ... '8': ['Bacteria', 'Bacteroidetes', 'Sphingobacteria'], ... '9': ['Bacteria', 'Bacteroidetes', 'Cytophagia']} >>> tree = TreeNode.from_taxonomy(lineages.items()) >>> lineages = sorted([(n.name, l) for n, l in tree.to_taxonomy()]) >>> for name, lineage in lineages: ... print(name, '; '.join(lineage)) 1 Bacteria; Firmicutes; Clostridia 2 Bacteria; Firmicutes; Bacilli 3 Bacteria; Bacteroidetes; Sphingobacteria 4 Archaea; Euryarchaeota; Thermoplasmata 5 Archaea; Euryarchaeota; Thermoplasmata 6 Archaea; Euryarchaeota; Halobacteria 7 Archaea; Euryarchaeota; Halobacteria 8 Bacteria; Bacteroidetes; Sphingobacteria 9 Bacteria; Bacteroidetes; Cytophagia """ if filter_f is None: def filter_f(a, b): return True self.assign_ids() seen: set = set() seen_add = seen.add lineage: list = [] lineage_pop = lineage.pop lineage_append = lineage.append # visit internal nodes while traversing out to the tips, and on the # way back up for node in self.traverse(self_before=True, self_after=True): if node.is_tip(): if filter_f(node, lineage): yield (node, lineage[:]) else: if allow_empty: if node.is_root() and not node.name: continue else: if not node.name: continue if node.id in seen: lineage_pop() else: lineage_append(node.name) seen_add(node.id) @classonlymethod def from_taxdump( cls, nodes: pd.DataFrame, names: pd.DataFrame | dict | None = None ) -> Self: r"""Construct a tree from the NCBI taxonomy database. Parameters ---------- nodes : pd.DataFrame Taxon hierarchy. names : pd.DataFrame or dict, optional Taxon names. Returns ------- TreeNode The constructed tree. Notes ----- ``nodes`` and ``names`` correspond to "nodes.dmp" and "names.dmp" of the NCBI taxonomy database. The should be read into data frames using ``skbio.io.read`` prior to this operation. Alternatively, ``names`` may be provided as a dictionary. If ``names`` is omitted, taxonomy IDs be used as taxon names. Raises ------ ValueError If there is no top-level node. ValueError If there are more than one top-level node. See Also -------- from_taxonomy skbio.io.format.taxdump Examples -------- >>> import pandas as pd >>> from skbio.tree import TreeNode >>> nodes = pd.DataFrame([ ... [1, 1, 'no rank'], ... [2, 1, 'domain'], ... [3, 1, 'domain'], ... [4, 2, 'phylum'], ... [5, 2, 'phylum']], columns=[ ... 'tax_id', 'parent_tax_id', 'rank']).set_index('tax_id') >>> names = {1: 'root', 2: 'Bacteria', 3: 'Archaea', ... 4: 'Firmicutes', 5: 'Bacteroidetes'} >>> tree = TreeNode.from_taxdump(nodes, names) >>> print(tree.ascii_art()) /-Firmicutes /Bacteria| -root----| \-Bacteroidetes | \-Archaea """ # identify top level of hierarchy tops = nodes[nodes["parent_tax_id"] == nodes.index] # validate root uniqueness n_top = tops.shape[0] if n_top == 0: raise ValueError("There is no top-level node.") elif n_top > 1: raise ValueError("There are more than one top-level node.") # get root taxid root_id = tops.index[0] # get parent-to-child(ren) map to_children = { p: g.index.tolist() for p, g in nodes[nodes.index != root_id].groupby("parent_tax_id") } # get rank map ranks = nodes["rank"].to_dict() # get taxon-to-name map # if not provided, use tax_id as name if names is None: names = {x: str(x) for x in nodes.index} # use "scientific name" as name elif isinstance(names, pd.DataFrame): names = names[names["name_class"] == "scientific name"][ "name_txt" ].to_dict() # initiate tree tree = cls(names[root_id]) tree.id = root_id tree.rank = ranks[root_id] # helper for extending tree def _extend_tree(node): self_id = node.id if self_id not in to_children: return children = [] for id_ in to_children[self_id]: child = TreeNode(names[id_]) child.id = id_ child.rank = ranks[id_] _extend_tree(child) children.append(child) node.extend(children, uncache=False) # extend tree _extend_tree(tree) return tree def to_array( self, attrs: list[tuple] | None = None, nan_length_value: float | None = None, ) -> dict: """Return an array representation of self. Parameters ---------- attrs : list of tuple or None The attributes and types to return. The expected form is [(attribute_name, type)]. If `None`, then `name`, `length`, and `id` are returned. nan_length_value : float, optional If provided, replaces any `nan` in the branch length vector (i.e., ``result['length']``) with this value. `nan` branch lengths can arise from an edge not having a length (common for the root node parent edge), which can making summing problematic. Returns ------- dict of array {id_index: {id: TreeNode}, child_index: ((node_id, left_child_id, right_child_id)), attr_1: array(...), ... attr_N: array(...)} Notes ----- Attribute arrays are in index order such that TreeNode.id can be used as a lookup into the array. Examples -------- >>> from skbio import TreeNode >>> t = TreeNode.read(['(((a:1,b:2,c:3)x:4,(d:5)y:6)z:7);']) >>> res = t.to_array() >>> sorted(res.keys()) ['child_index', 'id', 'id_index', 'length', 'name'] >>> res['child_index'] # doctest: +ELLIPSIS array([[4, 0, 2], [5, 3, 3], [6, 4, 5], [7, 6, 6]]... >>> for k, v in res['id_index'].items(): ... print(k, v) ... 0 a:1.0; 1 b:2.0; 2 c:3.0; 3 d:5.0; 4 (a:1.0,b:2.0,c:3.0)x:4.0; 5 (d:5.0)y:6.0; 6 ((a:1.0,b:2.0,c:3.0)x:4.0,(d:5.0)y:6.0)z:7.0; 7 (((a:1.0,b:2.0,c:3.0)x:4.0,(d:5.0)y:6.0)z:7.0); >>> res['id'] array([0, 1, 2, 3, 4, 5, 6, 7]) >>> res['name'] array(['a', 'b', 'c', 'd', 'x', 'y', 'z', None], dtype=object) """ if attrs is None: attrs = [("name", object), ("length", float), ("id", int)] else: for attr, dtype in attrs: if not hasattr(self, attr): raise AttributeError("Invalid attribute '%s'." % attr) # `index_tree` calls `assign_ids`, which assigns integer IDs to `id` of each # node, starting from 0. id_index, child_index = self.index_tree() n = self.id + 1 # type: ignore[operator] tmp = [np.zeros(n, dtype=dtype) for attr, dtype in attrs] for node in self.traverse(include_self=True): n_id = node.id for idx, (attr, dtype) in enumerate(attrs): tmp[idx][n_id] = getattr(node, attr) results = {"id_index": id_index, "child_index": child_index} results.update({attr: arr for (attr, dtype), arr in zip(attrs, tmp)}) if nan_length_value is not None: length_v = results["length"] length_v[np.isnan(length_v)] = nan_length_value return results scikit-bio-scikit-bio-a3beaa6/skbio/tree/_upgma.py000066400000000000000000000060111520735541300222410ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from scipy.cluster.hierarchy import linkage from skbio.tree import TreeNode from ._utils import _validate_dm def upgma(dm, weighted=False): r"""Perform unweighted pair group method with arithmetic mean (UPGMA) or its weighted variant (WPGMA) for phylogenetic reconstruction. Parameters ---------- dm : skbio.DistanceMatrix The input distance matrix. weighted : bool, optional If True, WPGMA is performed instead of UPGMA. WPGMA is a variant of UPGMA which is unbiased towards the size of subtrees computed. Returns ------- TreeNode A TreeNode object with estimated edge values. See Also -------- nj Notes ----- UPGMA (unweighted pair group method with arithmetic mean) is a simple hierarchical clustering method that iteratively groups proximal taxa or taxon groups to form a tree structure. A weighted variant is known as WPGMA, and both variants are due to Sokal and Michener [1]_. This function wraps SciPy's :func:`~scipy.cluster.hierarchy.linkage` function, with the ``method`` parameter set as "average" (UPGMA) or "weighted" (WPGMA). It takes a scikit-bio DistanceMatrix object and returns a scikit-bio TreeNode object. UPGMA creates a rooted and ultrametric tree -- all tips will have the same height (distance from the root node). References ---------- .. [1] Sokal, R.R., & Michener, C.D. (1958). A statistical method for evaluating systematic relationships. University of Kansas science bulletin, 38, 1409-1438. Examples -------- Define a distance matrix object for the taxa a, b, and c. >>> from skbio import DistanceMatrix >>> data = [[0, 1, 2], ... [1, 0, 3], ... [2, 3, 0]] >>> ids = list('abc') >>> dm = DistanceMatrix(data, ids) Construct a tree using UPGMA. >>> tree = upgma(dm) >>> print(tree.ascii_art()) /-c ---------| | /-a \--------| \-b The tree also has estimated edge values assigned to each edge. >>> print(tree) (c:1.25,(a:0.5,b:0.5):0.75); """ _validate_dm(dm) # If weighted is set to 'False', UPGMA is performed if weighted is False: linkage_matrix = linkage( dm.condensed_form(), method="average", metric="euclidean" ) # Otherwise, WPGMA is performed else: linkage_matrix = linkage( dm.condensed_form(), method="weighted", metric="euclidean" ) # Construct the TreeNode from the linkage matrix tree = TreeNode.from_linkage_matrix(linkage_matrix, dm.ids) return tree scikit-bio-scikit-bio-a3beaa6/skbio/tree/_utils.py000066400000000000000000000056641520735541300223050ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._exception import ( NoLengthError, DuplicateNodeError, MissingNodeError, TreeError, ) def _validate_dm(dm): if dm.shape[0] < 3: raise ValueError("Distance matrix must be at least 3x3 to generate a tree.") def _validate_dm_and_tree(dm, tree): _validate_dm(dm) if frozenset(dm.ids) != tree.subset(): raise ValueError("Inconsistent taxa between tree and distance matrix.") def _validate_taxa_and_tree(taxa, tree, unique=True, rooted=False, lengths=False): """Validate taxa and tree prior to phylogenetic analyses. Parameters ---------- taxa : sequence of str Input taxa. tree : TreeNode Input tree. unique : bool, optional If True, check if all taxa and tip names are unique. rooted : bool, optional If True, check if the tree is rooted. lengths : bool, optional If True, check if all non-root nodes in the tree have a branch length. Raises ------ ValueError If there are duplicate taxa. TreeError If the tree is not rooted. NoLengthError If there are non-root nodes without a branch length. DuplicateNodeError If there are duplicate tip names. MissingNodeError If some taxa are not present as tip names in the tree. """ # This function was moved from skbio.diversity._util and modified. taxon_set = set(taxa) if unique and len(taxa) != len(taxon_set): raise ValueError("All taxa must be unique.") # The following code checks if the tree is rooted. # There was a comment in the original code: "this is an imperfect check for " # "whether the tree is rooted or not. can this be improved?" # This check could be simplified as `not tree._is_rooted()`. It is kept as the # original form for compatibility. if rooted and len(tree.root().children) > 2: raise ValueError("The tree must be rooted.") tip_names = [] tip_names_append = tip_names.append for node in tree.postorder(include_self=False): if lengths and node.length is None: raise ValueError( # NoLengthError "All non-root nodes in the tree must have a branch length." ) if not node.children: tip_names_append(node.name) tip_name_set = set(tip_names) if unique and len(tip_names) != len(tip_name_set): raise DuplicateNodeError("All tip names in the tree must be unique.") if missing := taxon_set - tip_name_set: raise MissingNodeError( f"{len(missing)} taxa are not present as tip names in the tree." ) scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/000077500000000000000000000000001520735541300215635ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/__init__.py000066400000000000000000000005411520735541300236740ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/data/000077500000000000000000000000001520735541300224745ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/data/mp100.bme.nni.nwk000066400000000000000000000055711520735541300254070ustar00rootroot00000000000000(((((Seq42:0.01895284,(Seq04:0.01150651,(((Seq51:0.03633104,Seq69:0.05200896):0.01606791,(Seq50:0.11552877,((((Seq54:0.00215354,Seq84:0.00622646):0.06607393,(((Seq09:0.02006961,Seq58:0.00536039):0.00904547,Seq96:0.02565453):0.0980303,Seq95:0.0667522):0.01846919):0.09256681,Seq29:0.10924913):0.03079662,((((((Seq11:0.01883888,Seq12:0.01526112):0.13763244,((Seq85:0.06994169,Seq89:0.05686831):0.0086471,Seq87:0.1057979):0.01608256):0.01767736,((((Seq59:0.0627708,Seq81:0.0739692):0.00642256,Seq73:0.06201744):0.00798909,(((Seq21:0.0275697,Seq49:0.0607703):0.01728508,(Seq36:0.00294157,Seq63:0.00543843):0.02752992):0.02848776,Seq78:0.04728974):0.00363935):0.01690471,(((((Seq30:0.00691882,Seq38:0.00146118):0.00207517,Seq75:0.00634983):0.0281657,Seq34:0.0240093):0.01511709,Seq86:0.03590041):0.03610659,Seq71:0.08465529):0.01548439):0.01678411):0.03435569,(((Seq43:0.03088568,(Seq07:0.02801501,Seq44:0.06032499):0.00419432):0.03375483,Seq79:0.06853017):0.05490913,(((((((Seq15:0.03479356,Seq45:0.04422644):0.02570969,(((((Seq18:0.00010311,Seq57:0.00827689):0.00805663,Seq56:0.00036837):0.00626195,(Seq92:0.03231781,(Seq41:0.00127289,Seq39:0.00710711):0.00197719):0.00248118):0.01217683,(Seq70:0.01823993,Seq97:0.01586007):0.03330223):0.01701438,Seq20:0.22200155):0.03341703):0.0135444,Seq64:0.13547834):0.07127722,Seq83:0.51734785):0.05109795,Seq66:0.1422001):0.02191566,(((Seq23:0.039631,(Seq55:0.02180201,Seq65:0.02993799):0.018179):0.06151285,(((((Seq05:0.0281689,Seq24:0.0147011):0.01152767,Seq88:0.05071733):0.02022999,Seq61:0.03349251):0.0474074,Seq48:0.04440385):0.0090941,(((((Seq01:0.00141002,Seq60:0.00696998):0.00613617,Seq13:0.00228883):0.09624842,(Seq10:0.01699661,Seq77:0.03474339):0.03404658):0.00852329,Seq90:0.05604921):0.00906047,(Seq27:-0.00077967,Seq91:0.01762967):0.08679515):0.00739981):0.00647309):0.02918109,(Seq32:0.16944536,Seq68:0.09806464):0.02628137):0.02429296):0.01220912,((Seq35:0.00150513,Seq74:0.01534487):0.00475777,Seq72:0.00372223):0.19793985):0.01158362):0.01706302):0.01699378,(Seq40:0.11999962,Seq82:0.09023038):0.1015656):0.01254545,(((((((Seq02:0.00030742,Seq16:0.00807258):0.00340959,Seq80:0.00501541):0.01932538,Seq19:0.02388962):0.03887842,Seq46:0.06691158):0.04536908,(((((Seq22:0.0008025,Seq53:0.0075775):0.01353017,Seq31:0.02076483):0.02060344,Seq98:0.06031406):0.0746301,Seq99:0.1921499):0.03276875,((Seq14:0.09416334,Seq28:0.10511666):0.01739778,((Seq08:0.01429593,Seq33:0.01113407):0.05301119,Seq62:0.00869381):0.11011347):0.01154063):0.04916885):0.00521523,(Seq26:0.13046132,((Seq37:0.04870558,Seq76:0.03963442):0.0234984,Seq94:0.0444966):0.06352118):0.07701097):0.05923655,((Seq47:0.03655191,Seq67:0.08044809):0.03938343,Seq52:0.07063657):0.04846876):0.07336109):0.04763061):0.01151396):0.02571711):0.0541108,Seq17:0.02708208):0.01364589):0.00777567):0.00700779,Seq25:0.00782794):0.00479706,Seq93:0.02175696):0.00414304,Seq06:0.01761905):0.02549595,Seq03:-9.753e-05,Seq00:0.00847753); scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/data/mp100.bme.nwk000066400000000000000000000055771520735541300246320ustar00rootroot00000000000000((((((((((((((((((((Seq01:0.00140733,Seq60:0.00697267):0.00700767,Seq13:0.00141733):0.09415052,(Seq10:0.01622578,Seq77:0.03551422):0.03614448):0.00581147,Seq90:0.05876103):0.01598249,((Seq23:0.03642084,(Seq55:0.02180991,Seq65:0.02993009):0.02138916):0.06878154,Seq48:0.04908596):0.00372657):-0.00620004,((((Seq05:0.02870101,Seq24:0.01416899):0.01167897,Seq88:0.05056603):0.01392333,Seq61:0.03979917):0.05086763,(Seq27:0.00193665,Seq91:0.01491335):0.09099487):0.00563188):0.0319567,(Seq32:0.16619272,Seq68:0.10131728):0.03890465):0.02727093,Seq66:0.15192251):0.01032096,((((Seq15:0.03508388,Seq45:0.04393612):0.02941215,(((((Seq18:9.725e-05,Seq57:0.00828275):0.0080436,Seq56:0.0003814):0.005857,(Seq39:0.00744107,(Seq41:0.0015606,Seq92:0.0325394):0.00113393):0.00275488):0.01235578,(Seq70:0.01745347,Seq97:0.01664653):0.03465704):0.01770642,Seq20:0.22067108):0.02923472):0.0178019,Seq64:0.13092982):0.06445927,Seq83:0.52444534):0.0358311):0.0281302,((((((((Seq02:0.0002231,Seq16:0.0081569):0.00325325,Seq80:0.00517175):0.01896913,Seq19:0.02424587):0.03571625,Seq46:0.07007375):0.0458047,(Seq26:0.13116383,((Seq37:0.04917549,Seq76:0.03916451):0.02188328,Seq94:0.04611172):0.06281867):0.07689139):0.0108798,((Seq47:0.03488153,Seq67:0.08211847):0.03700064,Seq52:0.07301936):0.0913177):0.02779319,(((Seq08:0.01258305,Seq33:0.01284695):0.04991028,Seq62:0.01179472):0.11309414,((Seq14:0.09284155,Seq28:0.10643845):0.02223469,((((Seq22:0.0008025,Seq53:0.0075775):0.01345321,Seq31:0.02084179):0.02279555,Seq98:0.05812195):0.0656497,Seq99:0.2011303):0.03491281):0.00157898):0.04394256):0.08172509,(((Seq07:0.02913741,(Seq43:0.03268133,Seq44:0.06508867):-0.00348741):0.02139443,Seq79:0.09079807):0.04704607,((Seq35:-0.00103275,Seq74:0.01788275):0.00689489,Seq72:0.00158511):0.19892081):0.0073323):0.00726736):0.01104245,((((Seq11:0.02009417,Seq12:0.01400583):0.13606233,((Seq85:0.06884068,Seq89:0.05796932):0.01718332,Seq87:0.09726168):0.01765267):0.02856294,(Seq40:0.12055298,Seq82:0.08967702):0.11918394):-0.00875817,((((Seq21:0.02934531,Seq49:0.05899469):0.01466544,(Seq36:0.00352222,Seq63:0.00485778):0.03014956):0.02686645,(((Seq59:0.06290206,Seq81:0.07383794):0.00770469,Seq73:0.06073531):0.01026194,Seq78:0.04572056):0.00455699):0.02222519,(((((Seq30:0.00691449,Seq38:0.00146551):0.00195027,Seq75:0.00647473):0.02814512,Seq34:0.02402988):0.01357832,Seq86:0.03743918):0.03158905,Seq71:0.08917283):0.00806311):0.04089696):0.01486746):0.05981647,Seq29:0.11277839):0.02974607,(Seq50:0.10985635,(Seq51:0.03633255,Seq69:0.05200745):0.03453865):0.01887096):0.00861715,(((Seq09:0.01987458,Seq58:0.00555542):0.0073985,Seq96:0.0273015):0.08300418,((Seq54:0.00561288,Seq84:0.00276712):0.08288276,Seq95:0.05470224):0.02873644):0.09679483):0.05245877,Seq17:0.01904856):0.02431347,(Seq04:0.01421186,Seq42:0.01988814):0.00163353):0.00950929,Seq25:0.00782121):0.00480379,Seq93:0.02491604):0.00098396,Seq06:0.0176491):0.0254659,Seq03:0.00014862,Seq00:0.00823138); scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/data/mp100.gme.nni.nwk000066400000000000000000000056031520735541300254100ustar00rootroot00000000000000(((((((((((((((((((Seq01:0.0014027,Seq60:0.0069773):0.00349168,Seq13:0.00493332):0.0945405,(Seq10:0.02073934,Seq77:0.03100066):0.03702227):0.01868182,(Seq23:0.03856979,(Seq55:0.02181786,Seq65:0.02992214):0.01924021):0.0562789):0.00314752,((Seq27:0.00718332,Seq91:0.00966668):0.08309558,((Seq90:0.06933357,Seq48:0.04766643):0.00223331,(((Seq05:0.02865551,Seq24:0.01421449):0.0188518,Seq88:0.0433932):0.0148557,Seq61:0.03546203):0.0484077):0.01080719):-0.00080551):0.03333285,(Seq32:0.15312337,Seq68:0.11438663):0.03422856):0.02527798,Seq66:0.1527784):0.01738556,((((Seq15:0.02156546,Seq45:0.05745454):0.01054086,((((Seq18:0.00218321,Seq57:0.00619679):0.0075654,(((Seq56:0.00351444,Seq41:0.00486556):0.00279023,Seq39:0.00563477):0.0130069,Seq92:0.02040802):-0.00157264):0.009491,(Seq70:0.00835209,Seq97:0.02574791):0.0372833):0.06199375,Seq20:0.18035415):-0.00642486):0.05650885,Seq64:0.10174488):0.03866116,Seq83:0.53002874):0.05151312):0.02427687,((((Seq11:0.02153046,Seq12:0.01256954):0.10938894,Seq81:0.07831606):0.02043584,((Seq85:0.05832449,Seq89:0.06848551):0.01755505,Seq87:0.09688995):0.01699838):0.02369043,((((Seq21:0.04077286,Seq49:0.04756714):0.00328503,(Seq36:0.00030903,Seq63:0.00807097):0.04152997):0.01938621,((Seq59:0.05984607,Seq73:0.06696393):0.00788673,Seq78:0.05557827):0.00945822):0.00914077,(((((Seq30:0.00410515,Seq38:0.00427485):0.00245054,Seq75:0.00597446):0.02120638,Seq34:0.03010844):0.01569753,Seq86:0.04212418):0.04627324,Seq71:0.07336727):0.01507986):0.00994474):0.04465232):0.00163945,(((Seq35:-0.00025388,Seq74:0.01710388):0.00532284,Seq72:0.00315716):0.1985214,((((Seq07:0.02054607,Seq43:0.04018393):0.00870941,Seq44:0.05398059):0.03378396,Seq79:0.06911623):0.03912866,((((((((Seq02:0.00386082,Seq80:0.00451918):0.00486845,Seq16:0.00355655):0.01580779,Seq19:0.02575106):0.05087325,Seq46:0.05970728):0.0435493,(Seq26:0.11919734,((Seq37:0.05202051,Seq76:0.03631949):0.03048242,Seq94:0.03751258):0.07441018):0.04442674):0.04749951,((Seq47:0.06249929,Seq67:0.05450071):0.03393345,Seq52:0.07608655):0.06533487):0.01156965,((((Seq08:0.0153701,Seq33:0.0100599):0.04625778,Seq62:0.01544722):0.10545249,(Seq14:0.11609724,Seq28:0.08318276):0.02720825):0.01038713,((((Seq22:0.00409648,Seq53:0.00428352):0.01908678,Seq31:0.01520822):0.03534175,Seq98:0.04502766):0.08300026,Seq99:0.17120107):0.01694776):0.0451095):0.09228773,(Seq40:0.12640985,Seq82:0.08382015):0.09582616):0.00713792):0.01163787):0.01199347):0.06314672,Seq29:0.12026353):0.01150843,Seq50:0.11747489):0.00915725,((Seq09:0.0148134,(Seq58:0.01142612,Seq96:0.02267388):0.0112166):0.08539122,((Seq54:0.00457383,Seq84:0.00380617):0.06682492,Seq95:0.07076008):0.03155883):0.09167327):0.04173809,(Seq51:0.03864158,Seq69:0.04969842):0.02232358):0.03367438,Seq17:0.02499061):0.01058798,Seq04:0.01231004):0.01213663,((Seq25:0.01256138,Seq93:0.02153862):0.00751219,Seq42:0.01392281):0.00391016):0.00527673,Seq06:0.02067784):0.02243716,Seq03:0.00441255,Seq00:0.00396745); scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/data/mp100.gme.nwk000066400000000000000000000056021520735541300246240ustar00rootroot00000000000000(((((((((((((((((((Seq01:0.0014027,Seq60:0.0069773):0.00349168,Seq13:0.00493332):0.0945405,(Seq10:0.02073934,Seq77:0.03100066):0.03702227):0.01868182,(Seq23:0.03856979,(Seq55:0.02181786,Seq65:0.02992214):0.01924021):0.0562789):0.00314752,(((((Seq05:0.02865551,Seq24:0.01421449):0.0188518,Seq88:0.0433932):0.0148557,Seq61:0.03546203):0.04858006,Seq48:0.05001596):0.00787616,((Seq27:0.00718332,Seq91:0.00966668):0.0751842,Seq90:0.0734758):0.00567202):0.00188881):0.03333285,(Seq32:0.15312337,Seq68:0.11438663):0.03422856):0.02527798,Seq66:0.1527784):0.01738556,((((Seq15:0.02156546,Seq45:0.05745454):0.01054086,((((Seq18:0.00218321,Seq57:0.00619679):0.0075654,(((Seq39:0.00320796,Seq41:0.00517204):0.00232577,Seq56:0.00609923):0.01316172,Seq92:0.02040802):-0.00157264):0.009491,(Seq70:0.00835209,Seq97:0.02574791):0.0372833):0.06199375,Seq20:0.18035415):-0.00642486):0.05650885,Seq64:0.10174488):0.03866116,Seq83:0.53002874):0.05151312):0.02427687,((((Seq11:0.02153046,Seq12:0.01256954):0.10938894,Seq81:0.07831606):0.02043584,((Seq85:0.05832449,Seq89:0.06848551):0.01755505,Seq87:0.09688995):0.01699838):0.02369043,((((Seq21:0.03870054,(Seq36:0.00030903,Seq63:0.00807097):0.03612946):0.00802648,Seq49:0.0531937):0.01682055,((Seq59:0.05984607,Seq73:0.06696393):0.00788673,Seq78:0.05557827):0.00945822):0.00914077,(((((Seq30:0.00410515,Seq38:0.00427485):0.00245054,Seq75:0.00597446):0.02120638,Seq34:0.03010844):0.01569753,Seq86:0.04212418):0.04627324,Seq71:0.07336727):0.01507986):0.00994474):0.04465232):0.00163945,(((((((((Seq02:0.00386082,Seq80:0.00451918):0.00486845,Seq16:0.00355655):0.01580779,Seq19:0.02575106):0.05087325,Seq46:0.05970728):0.0435493,(Seq26:0.11919734,((Seq37:0.05202051,Seq76:0.03631949):0.03048242,Seq94:0.03751258):0.07441018):0.04442674):0.04749951,((Seq47:0.06249929,Seq67:0.05450071):0.03393345,Seq52:0.07608655):0.06533487):0.01156965,((((Seq08:0.0153701,Seq33:0.0100599):0.04625778,Seq62:0.01544722):0.10545249,(Seq14:0.11609724,Seq28:0.08318276):0.02720825):0.01038713,((((Seq22:0.00409648,Seq53:0.00428352):0.01908678,Seq31:0.01520822):0.03534175,Seq98:0.04502766):0.08300026,Seq99:0.17120107):0.01694776):0.0451095):0.09228773,(Seq40:0.12640985,Seq82:0.08382015):0.09582616):0.01225304,((((Seq07:0.02054607,Seq43:0.04018393):0.00870941,Seq44:0.05398059):0.03378396,Seq79:0.06911623):0.04448799,((Seq35:-0.00025388,Seq74:0.01710388):0.00532284,Seq72:0.00315716):0.19831918):-0.00264036):0.01846925):0.06314672,Seq29:0.12026353):0.01150843,Seq50:0.11747489):0.00915725,((Seq09:0.0148134,(Seq58:0.01142612,Seq96:0.02267388):0.0112166):0.08539122,((Seq54:0.00457383,Seq84:0.00380617):0.06682492,Seq95:0.07076008):0.03155883):0.09167327):0.04173809,(Seq51:0.03864158,Seq69:0.04969842):0.02232358):0.03367438,Seq17:0.02499061):0.0228658,Seq06:0.02586297):-0.01110166,Seq04:0.01150447):0.0096176,((Seq25:0.01256138,Seq93:0.02153862):0.00751219,Seq42:0.01392281):0.00522392):0.02889035,Seq03:0.00441255,Seq00:0.00396745); scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/data/mp100.nj.nwk000066400000000000000000000055611520735541300244670ustar00rootroot00000000000000((((((((((((Seq00:0.00467178,Seq03:0.00370822):0.02321315,(Seq06:0.01712763,(Seq93:0.01937427,Seq25:0.01472573):0.00430737):0.00289185):0.01228761,(Seq04:0.01063712,Seq42:0.02346288):0.00504552):0.00909501,Seq17:0.0289578):0.0411903,(Seq69:0.05348314,Seq51:0.03485686):0.02709783):0.03252254,Seq50:0.10963777):0.01022409,((Seq09:0.01482722,(Seq96:0.02250702,Seq58:0.01159298):0.01120278):0.08401807,((Seq54:0.005099,Seq84:0.003281):0.07071382,Seq95:0.06687118):0.02989005):0.0995392):0.01860607,Seq29:0.11469053):0.06344744,(((((((((Seq01:0.00124939,Seq60:0.00713061):0.00456505,Seq13:0.00385995):0.08989606,(Seq90:0.06283711,(Seq10:0.01950782,Seq77:0.03223218):0.03810289):0.00403144):0.01290163,(((((Seq05:0.02755715,Seq24:0.01531285):0.01826032,Seq88:0.04398468):0.0149659,Seq61:0.0387566):0.0493825,Seq48:0.04242875):0.01251282,(Seq91:0.0104965,Seq27:0.0063535):0.0920153):0.00261227):0.01491012,((Seq65:0.02682307,Seq55:0.02491693):0.01229396,Seq23:0.04551604):0.04899398):0.01789305,(Seq68:0.11050759,Seq32:0.15700241):0.0399974):0.01621201,((Seq35:0.00065881,Seq74:0.01619119):0.00561485,Seq72:0.00286515):0.20828006):0.00947508,Seq66:0.16075942):0.02024225,(((((((((Seq02:0.0036404,Seq80:0.0047396):0.00532129,Seq16:0.00310371):0.01697761,Seq19:0.02623739):0.04905292,Seq46:0.05923708):0.06390133,(Seq26:0.118983,((Seq37:0.05205987,Seq76:0.03628013):0.0303467,Seq94:0.0376483):0.0749995):0.05830742):0.02778696,((Seq47:0.06451126,Seq67:0.05248874):0.03543869,Seq52:0.07458131):0.0738289):0.02455459,((((Seq08:0.0153701,Seq33:0.0100599):0.04691902,Seq62:0.01478598):0.09965719,(Seq14:0.1167896,Seq28:0.0824904):0.02785406):0.02293368,((((Seq22:0.00409453,Seq53:0.00428547):0.01930189,Seq31:0.01499311):0.03729231,Seq98:0.04362519):0.08639283,Seq99:0.18038717):0.0213757):0.04312047):0.06691435,(Seq83:0.53849106,(((Seq15:0.03067681,(((((Seq18:0.00170377,Seq57:0.00667623):0.00498393,(Seq39:0.00509153,(Seq41:0.00462913,Seq56:0.00375087):0.00333347):0.00783982):0.00778084,Seq92:0.02901478):0.00490851,(Seq97:0.02645474,Seq70:0.00764526):0.03583274):0.0354076,Seq45:0.04555959):0.02580304):0.03689734,Seq20:0.23204243):0.02705687,Seq64:0.12051204):0.03548513):0.04138715):0.02540897,(Seq40:0.13528221,Seq82:0.07494779):0.10850021):0.00326669):0.00967434):0.0165427,(((Seq07:0.01974424,Seq43:0.04098576):0.01253449,Seq44:0.05015551):0.0443509,Seq79:0.0585816):0.06100333):0.0288987,((Seq81:0.05430915,(Seq11:0.02143746,Seq12:0.01266254):0.13339585):0.01670203,((Seq89:0.0600733,Seq85:0.0667367):0.01562965,Seq87:0.09881535):0.03190547):0.00903377):0.01325424,(Seq73:0.06088583,Seq59:0.06592417):0.00771373,((Seq78:0.04529075,(Seq71:0.0838696,(Seq86:0.03876356,((Seq30:0.00541757,(Seq75:0.00646917,Seq38:0.00191083):0.00300743):0.02447122,Seq34:0.02770378):0.01225394):0.03753915):0.01921925):0.01075767,((Seq21:0.03325344,Seq49:0.05508656):0.00890323,(Seq36:0.00095826,Seq63:0.00742174):0.03591177):0.02564038):0.00841104); scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/data/mp100.phy000066400000000000000000001155001520735541300240550ustar00rootroot00000000000000100 Seq00 Seq01 0.44084 Seq02 0.51986 0.51986 Seq03 0.00838 0.42599 0.53672 Seq04 0.06073 0.44084 0.47146 0.05174 Seq05 0.38312 0.19928 0.58968 0.38312 0.39714 Seq06 0.05174 0.41142 0.51986 0.04287 0.06073 0.32952 Seq07 0.3167 0.3167 0.38312 0.32952 0.3041 0.35584 0.34257 Seq08 0.57161 0.6082 0.32952 0.58968 0.57161 0.66667 0.62719 0.35584 Seq09 0.27951 0.50338 0.6082 0.27951 0.3041 0.42599 0.25569 0.45599 0.64667 Seq10 0.42599 0.14681 0.55396 0.41142 0.35584 0.22134 0.42599 0.26751 0.50338 0.45599 Seq11 0.44084 0.35584 0.42599 0.44084 0.41142 0.45599 0.41142 0.42599 0.55396 0.41142 0.34257 Seq12 0.45599 0.34257 0.42599 0.45599 0.45599 0.44084 0.42599 0.39714 0.57161 0.38312 0.32952 0.0341 Seq13 0.45599 0.00838 0.53672 0.44084 0.45599 0.21023 0.42599 0.3041 0.58968 0.48725 0.13674 0.34257 0.32952 Seq14 0.62719 0.57161 0.35584 0.6082 0.57161 0.58968 0.6082 0.38312 0.27951 0.70835 0.51986 0.53672 0.51986 0.58968 Seq15 0.41142 0.32952 0.51986 0.39714 0.36936 0.34257 0.38312 0.2917 0.58968 0.50338 0.27951 0.41142 0.39714 0.34257 0.42599 Seq16 0.50338 0.50338 0.00838 0.51986 0.45599 0.57161 0.50338 0.36936 0.3167 0.58968 0.53672 0.44084 0.44084 0.51986 0.36936 0.53672 Seq17 0.06982 0.45599 0.45599 0.07902 0.05174 0.36936 0.06982 0.3041 0.55396 0.25569 0.39714 0.41142 0.45599 0.47146 0.55396 0.35584 0.44084 Seq18 0.47146 0.44084 0.58968 0.47146 0.41142 0.42599 0.48725 0.38312 0.58968 0.53672 0.35584 0.50338 0.48725 0.45599 0.47146 0.117 0.6082 0.42599 Seq19 0.50338 0.53672 0.04287 0.51986 0.45599 0.64667 0.51986 0.34257 0.32952 0.62719 0.53672 0.47146 0.45599 0.55396 0.3167 0.51986 0.05174 0.44084 0.58968 Seq20 0.62719 0.58968 0.55396 0.64667 0.58968 0.53672 0.6082 0.44084 0.51986 0.70835 0.6082 0.68722 0.68722 0.6082 0.44084 0.34257 0.57161 0.55396 0.26751 0.53672 Seq21 0.39714 0.2917 0.41142 0.39714 0.34257 0.3167 0.36936 0.27951 0.47146 0.38312 0.26751 0.2917 0.27951 0.27951 0.51986 0.34257 0.39714 0.32952 0.35584 0.42599 0.51986 Seq22 0.58968 0.58968 0.3167 0.58968 0.53672 0.55396 0.55396 0.39714 0.3167 0.6082 0.55396 0.51986 0.51986 0.57161 0.26751 0.55396 0.32952 0.55396 0.47146 0.35584 0.48725 0.41142 Seq23 0.44084 0.17785 0.50338 0.42599 0.41142 0.24407 0.44084 0.2917 0.57161 0.57161 0.21023 0.42599 0.39714 0.18849 0.50338 0.36936 0.48725 0.42599 0.45599 0.45599 0.53672 0.3041 0.53672 Seq24 0.35584 0.18849 0.55396 0.36936 0.38312 0.04287 0.35584 0.3041 0.6082 0.44084 0.19928 0.45599 0.44084 0.19928 0.57161 0.32952 0.53672 0.35584 0.41142 0.6082 0.50338 0.3167 0.53672 0.22134 Seq25 0.05174 0.44084 0.50338 0.04287 0.0341 0.35584 0.0341 0.35584 0.58968 0.27951 0.38312 0.39714 0.45599 0.45599 0.62719 0.36936 0.48725 0.06073 0.44084 0.51986 0.62719 0.35584 0.58968 0.45599 0.36936 Seq26 0.68722 0.6082 0.2917 0.68722 0.64667 0.53672 0.66667 0.48725 0.45599 0.6082 0.6082 0.47146 0.45599 0.6082 0.47146 0.57161 0.3041 0.66667 0.51986 0.34257 0.55396 0.42599 0.35584 0.51986 0.51986 0.66667 Seq27 0.36936 0.21023 0.55396 0.38312 0.36936 0.19928 0.36936 0.2917 0.55396 0.42599 0.16736 0.48725 0.45599 0.22134 0.58968 0.3167 0.53672 0.34257 0.35584 0.57161 0.48725 0.34257 0.57161 0.19928 0.18849 0.39714 0.53672 Seq28 0.57161 0.50338 0.26751 0.58968 0.53672 0.51986 0.58968 0.38312 0.34257 0.62719 0.50338 0.47146 0.47146 0.51986 0.19928 0.47146 0.27951 0.51986 0.47146 0.25569 0.48725 0.39714 0.27951 0.44084 0.48725 0.6082 0.3167 0.51986 Seq29 0.27951 0.44084 0.48725 0.2917 0.26751 0.39714 0.27951 0.35584 0.45599 0.36936 0.32952 0.32952 0.36936 0.42599 0.44084 0.41142 0.47146 0.22134 0.45599 0.48725 0.57161 0.3167 0.53672 0.34257 0.39714 0.27951 0.68722 0.35584 0.44084 Seq30 0.36936 0.34257 0.48725 0.35584 0.32952 0.36936 0.34257 0.35584 0.41142 0.47146 0.32952 0.3167 0.3041 0.32952 0.45599 0.44084 0.47146 0.38312 0.42599 0.51986 0.53672 0.17785 0.50338 0.2917 0.36936 0.32952 0.47146 0.32952 0.44084 0.3167 Seq31 0.57161 0.6082 0.3167 0.57161 0.50338 0.57161 0.57161 0.36936 0.3167 0.62719 0.51986 0.51986 0.55396 0.58968 0.26751 0.51986 0.32952 0.51986 0.44084 0.3041 0.47146 0.42599 0.0341 0.48725 0.55396 0.57161 0.35584 0.57161 0.27951 0.51986 0.53672 Seq32 0.50338 0.36936 0.51986 0.48725 0.45599 0.35584 0.44084 0.35584 0.62719 0.55396 0.2917 0.48725 0.45599 0.35584 0.55396 0.38312 0.53672 0.45599 0.44084 0.48725 0.58968 0.39714 0.51986 0.32952 0.35584 0.48725 0.58968 0.3167 0.53672 0.44084 0.42599 0.50338 Seq33 0.55396 0.58968 0.2917 0.57161 0.53672 0.64667 0.6082 0.35584 0.02543 0.66667 0.51986 0.57161 0.58968 0.6082 0.26751 0.57161 0.27951 0.55396 0.55396 0.2917 0.50338 0.50338 0.32952 0.53672 0.58968 0.57161 0.45599 0.51986 0.3167 0.48725 0.41142 0.32952 0.62719 Seq34 0.38312 0.35584 0.48725 0.36936 0.34257 0.36936 0.36936 0.35584 0.45599 0.48725 0.3167 0.3167 0.3167 0.34257 0.48725 0.42599 0.47146 0.36936 0.42599 0.47146 0.50338 0.14681 0.53672 0.2917 0.38312 0.32952 0.48725 0.36936 0.45599 0.32952 0.06073 0.48725 0.41142 0.48725 Seq35 0.42599 0.44084 0.55396 0.44084 0.38312 0.45599 0.47146 0.26751 0.45599 0.57161 0.3167 0.55396 0.51986 0.42599 0.45599 0.36936 0.53672 0.41142 0.44084 0.50338 0.57161 0.42599 0.51986 0.34257 0.42599 0.44084 0.58968 0.3167 0.45599 0.36936 0.36936 0.48725 0.41142 0.45599 0.38312 Seq36 0.32952 0.25569 0.42599 0.3167 0.32952 0.34257 0.32952 0.25569 0.44084 0.35584 0.24407 0.2917 0.26751 0.24407 0.48725 0.3167 0.41142 0.34257 0.38312 0.45599 0.50338 0.07902 0.45599 0.3041 0.3167 0.34257 0.47146 0.32952 0.38312 0.3041 0.14681 0.45599 0.36936 0.45599 0.13674 0.42599 Seq37 0.62719 0.64667 0.23262 0.6082 0.53672 0.62719 0.58968 0.51986 0.50338 0.66667 0.6082 0.51986 0.51986 0.66667 0.44084 0.58968 0.24407 0.55396 0.66667 0.26751 0.62719 0.57161 0.55396 0.58968 0.6082 0.57161 0.26751 0.6082 0.34257 0.57161 0.50338 0.55396 0.58968 0.45599 0.50338 0.53672 0.51986 Seq38 0.35584 0.35584 0.48725 0.34257 0.32952 0.38312 0.35584 0.34257 0.41142 0.47146 0.32952 0.3167 0.3041 0.34257 0.44084 0.44084 0.47146 0.38312 0.42599 0.50338 0.55396 0.17785 0.51986 0.27951 0.38312 0.32952 0.47146 0.34257 0.42599 0.3167 0.00838 0.51986 0.44084 0.41142 0.05174 0.36936 0.14681 0.50338 Seq39 0.50338 0.41142 0.58968 0.50338 0.44084 0.41142 0.51986 0.36936 0.62719 0.53672 0.32952 0.51986 0.50338 0.42599 0.48725 0.10733 0.6082 0.45599 0.02543 0.58968 0.26751 0.36936 0.50338 0.42599 0.39714 0.47146 0.53672 0.32952 0.50338 0.50338 0.47146 0.47146 0.45599 0.58968 0.44084 0.44084 0.39714 0.68722 0.47146 Seq40 0.47146 0.50338 0.44084 0.47146 0.45599 0.48725 0.45599 0.41142 0.53672 0.50338 0.45599 0.39714 0.34257 0.51986 0.39714 0.45599 0.42599 0.47146 0.50338 0.42599 0.6082 0.39714 0.58968 0.47146 0.50338 0.48725 0.53672 0.48725 0.45599 0.36936 0.35584 0.6082 0.53672 0.50338 0.38312 0.50338 0.41142 0.44084 0.34257 0.51986 Seq41 0.48725 0.42599 0.58968 0.48725 0.42599 0.42599 0.50338 0.38312 0.6082 0.53672 0.34257 0.53672 0.51986 0.44084 0.47146 0.117 0.6082 0.44084 0.01685 0.58968 0.26751 0.38312 0.48725 0.44084 0.41142 0.45599 0.53672 0.34257 0.50338 0.48725 0.45599 0.45599 0.45599 0.57161 0.45599 0.45599 0.41142 0.68722 0.45599 0.00838 0.51986 Seq42 0.07902 0.50338 0.48725 0.06982 0.0341 0.41142 0.06073 0.35584 0.58968 0.3167 0.39714 0.41142 0.45599 0.51986 0.58968 0.39714 0.47146 0.06982 0.44084 0.48725 0.64667 0.32952 0.53672 0.41142 0.42599 0.0341 0.64667 0.39714 0.55396 0.25569 0.3041 0.51986 0.44084 0.55396 0.32952 0.42599 0.32952 0.55396 0.3041 0.47146 0.45599 0.45599 Seq43 0.38312 0.35584 0.32952 0.39714 0.34257 0.39714 0.41142 0.06073 0.36936 0.50338 0.2917 0.36936 0.32952 0.34257 0.36936 0.32952 0.34257 0.36936 0.39714 0.32952 0.48725 0.27951 0.35584 0.32952 0.35584 0.39714 0.47146 0.36936 0.34257 0.35584 0.36936 0.36936 0.36936 0.36936 0.38312 0.3041 0.26751 0.48725 0.36936 0.38312 0.42599 0.39714 0.35584 Seq44 0.35584 0.26751 0.35584 0.36936 0.34257 0.32952 0.32952 0.08834 0.41142 0.45599 0.3041 0.39714 0.36936 0.25569 0.42599 0.35584 0.36936 0.3167 0.44084 0.34257 0.47146 0.23262 0.38312 0.32952 0.3041 0.36936 0.50338 0.3041 0.41142 0.38312 0.36936 0.41142 0.34257 0.44084 0.35584 0.36936 0.25569 0.58968 0.38312 0.42599 0.51986 0.44084 0.39714 0.09777 Seq45 0.42599 0.41142 0.6082 0.41142 0.38312 0.42599 0.42599 0.3041 0.57161 0.51986 0.3041 0.50338 0.48725 0.39714 0.50338 0.07902 0.62719 0.39714 0.10733 0.6082 0.34257 0.39714 0.57161 0.45599 0.41142 0.38312 0.55396 0.34257 0.57161 0.45599 0.45599 0.53672 0.42599 0.58968 0.44084 0.41142 0.38312 0.6082 0.45599 0.10733 0.53672 0.09777 0.41142 0.3167 0.36936 Seq46 0.44084 0.51986 0.13674 0.45599 0.42599 0.55396 0.48725 0.34257 0.3041 0.50338 0.50338 0.48725 0.44084 0.53672 0.3167 0.51986 0.14681 0.41142 0.55396 0.12681 0.53672 0.41142 0.3167 0.50338 0.51986 0.47146 0.3041 0.53672 0.25569 0.50338 0.51986 0.3167 0.48725 0.3041 0.48725 0.50338 0.45599 0.36936 0.50338 0.55396 0.45599 0.55396 0.45599 0.3041 0.3167 0.55396 Seq47 0.35584 0.58968 0.3041 0.35584 0.2917 0.57161 0.32952 0.42599 0.42599 0.38312 0.51986 0.55396 0.57161 0.57161 0.44084 0.57161 0.2917 0.3041 0.62719 0.25569 0.66667 0.44084 0.44084 0.53672 0.55396 0.34257 0.42599 0.53672 0.39714 0.38312 0.47146 0.41142 0.58968 0.42599 0.47146 0.45599 0.44084 0.38312 0.48725 0.64667 0.47146 0.64667 0.32952 0.48725 0.45599 0.64667 0.3167 Seq48 0.36936 0.19928 0.50338 0.38312 0.32952 0.15701 0.36936 0.23262 0.55396 0.41142 0.13674 0.39714 0.38312 0.18849 0.53672 0.26751 0.48725 0.3041 0.32952 0.48725 0.47146 0.26751 0.51986 0.14681 0.15701 0.35584 0.57161 0.15701 0.44084 0.2917 0.32952 0.48725 0.3041 0.55396 0.32952 0.3167 0.2917 0.62719 0.32952 0.3041 0.48725 0.3167 0.35584 0.26751 0.25569 0.3167 0.50338 0.51986 Seq49 0.3167 0.2917 0.39714 0.32952 0.3041 0.3167 0.3041 0.26751 0.47146 0.32952 0.2917 0.2917 0.26751 0.27951 0.53672 0.38312 0.38312 0.3167 0.41142 0.41142 0.50338 0.08834 0.44084 0.3167 0.3041 0.3167 0.42599 0.3041 0.39714 0.3167 0.21023 0.42599 0.42599 0.48725 0.17785 0.41142 0.10733 0.57161 0.21023 0.42599 0.41142 0.44084 0.32952 0.27951 0.24407 0.44084 0.42599 0.42599 0.25569 Seq50 0.26751 0.44084 0.47146 0.25569 0.23262 0.39714 0.24407 0.32952 0.68722 0.3041 0.41142 0.48725 0.44084 0.45599 0.55396 0.35584 0.48725 0.23262 0.39714 0.47146 0.48725 0.36936 0.6082 0.34257 0.38312 0.25569 0.50338 0.34257 0.50338 0.27951 0.38312 0.6082 0.38312 0.64667 0.38312 0.45599 0.34257 0.47146 0.38312 0.41142 0.42599 0.41142 0.25569 0.34257 0.35584 0.38312 0.42599 0.38312 0.34257 0.35584 Seq51 0.16736 0.42599 0.45599 0.15701 0.13674 0.35584 0.12681 0.32952 0.58968 0.34257 0.41142 0.47146 0.44084 0.44084 0.51986 0.38312 0.44084 0.13674 0.47146 0.44084 0.53672 0.35584 0.6082 0.32952 0.35584 0.14681 0.57161 0.3167 0.57161 0.24407 0.27951 0.6082 0.44084 0.58968 0.3041 0.34257 0.35584 0.47146 0.2917 0.50338 0.34257 0.48725 0.15701 0.41142 0.35584 0.45599 0.41142 0.27951 0.35584 0.34257 0.17785 Seq52 0.35584 0.58968 0.32952 0.35584 0.32952 0.55396 0.35584 0.38312 0.44084 0.35584 0.48725 0.55396 0.50338 0.57161 0.39714 0.57161 0.3167 0.3167 0.6082 0.2917 0.68722 0.35584 0.42599 0.51986 0.53672 0.36936 0.39714 0.53672 0.36936 0.36936 0.45599 0.42599 0.55396 0.47146 0.42599 0.48725 0.39714 0.38312 0.44084 0.62719 0.44084 0.62719 0.35584 0.42599 0.41142 0.6082 0.25569 0.12681 0.50338 0.36936 0.3041 0.3041 Seq53 0.58968 0.58968 0.3167 0.58968 0.53672 0.55396 0.55396 0.39714 0.3167 0.6082 0.55396 0.51986 0.51986 0.57161 0.26751 0.55396 0.32952 0.55396 0.47146 0.35584 0.48725 0.41142 0.00838 0.53672 0.53672 0.58968 0.35584 0.57161 0.27951 0.53672 0.50338 0.04287 0.51986 0.32952 0.53672 0.51986 0.45599 0.55396 0.51986 0.50338 0.58968 0.48725 0.53672 0.35584 0.38312 0.57161 0.3167 0.44084 0.51986 0.44084 0.6082 0.6082 0.42599 Seq54 0.36936 0.48725 0.53672 0.38312 0.32952 0.53672 0.36936 0.41142 0.62719 0.22134 0.44084 0.44084 0.48725 0.47146 0.62719 0.47146 0.51986 0.3041 0.50338 0.53672 0.64667 0.34257 0.66667 0.51986 0.48725 0.36936 0.68722 0.50338 0.53672 0.24407 0.50338 0.64667 0.55396 0.66667 0.48725 0.50338 0.35584 0.62719 0.50338 0.50338 0.51986 0.50338 0.34257 0.41142 0.42599 0.50338 0.48725 0.39714 0.42599 0.35584 0.34257 0.34257 0.34257 0.66667 Seq55 0.48725 0.19928 0.53672 0.47146 0.45599 0.24407 0.48725 0.27951 0.58968 0.53672 0.19928 0.41142 0.38312 0.18849 0.55396 0.3167 0.51986 0.47146 0.41142 0.51986 0.51986 0.24407 0.51986 0.07902 0.22134 0.50338 0.48725 0.18849 0.47146 0.39714 0.2917 0.47146 0.32952 0.58968 0.2917 0.35584 0.24407 0.66667 0.27951 0.36936 0.50338 0.38312 0.45599 0.3167 0.3167 0.36936 0.55396 0.58968 0.16736 0.27951 0.44084 0.42599 0.55396 0.51986 0.48725 Seq56 0.48725 0.44084 0.58968 0.48725 0.42599 0.44084 0.50338 0.38312 0.58968 0.55396 0.35584 0.51986 0.50338 0.45599 0.45599 0.10733 0.6082 0.44084 0.00838 0.58968 0.25569 0.36936 0.47146 0.45599 0.42599 0.45599 0.53672 0.35584 0.48725 0.47146 0.44084 0.44084 0.44084 0.55396 0.44084 0.44084 0.39714 0.68722 0.44084 0.01685 0.51986 0.00838 0.45599 0.39714 0.44084 0.09777 0.55396 0.64667 0.32952 0.42599 0.41142 0.48725 0.62719 0.47146 0.51986 0.39714 Seq57 0.45599 0.45599 0.57161 0.45599 0.39714 0.44084 0.47146 0.39714 0.6082 0.53672 0.36936 0.50338 0.48725 0.47146 0.48725 0.10733 0.58968 0.41142 0.00838 0.57161 0.27951 0.36936 0.48725 0.47146 0.42599 0.42599 0.51986 0.36936 0.48725 0.47146 0.44084 0.45599 0.44084 0.57161 0.44084 0.45599 0.39714 0.64667 0.44084 0.0341 0.48725 0.02543 0.42599 0.41142 0.45599 0.117 0.55396 0.6082 0.34257 0.42599 0.39714 0.45599 0.6082 0.48725 0.50338 0.42599 0.01685 Seq58 0.27951 0.50338 0.6082 0.27951 0.3041 0.42599 0.25569 0.47146 0.66667 0.02543 0.48725 0.44084 0.41142 0.51986 0.68722 0.47146 0.58968 0.25569 0.50338 0.6082 0.68722 0.41142 0.64667 0.57161 0.44084 0.27951 0.62719 0.42599 0.62719 0.36936 0.50338 0.66667 0.6082 0.64667 0.51986 0.57161 0.38312 0.66667 0.50338 0.50338 0.47146 0.50338 0.3167 0.51986 0.47146 0.51986 0.50338 0.39714 0.44084 0.35584 0.3041 0.34257 0.36936 0.64667 0.21023 0.57161 0.51986 0.50338 Seq59 0.36936 0.3167 0.42599 0.36936 0.3167 0.36936 0.36936 0.25569 0.55396 0.35584 0.27951 0.27951 0.26751 0.3041 0.57161 0.35584 0.41142 0.32952 0.36936 0.42599 0.51986 0.12681 0.47146 0.3167 0.36936 0.35584 0.41142 0.34257 0.48725 0.38312 0.24407 0.45599 0.34257 0.55396 0.23262 0.45599 0.13674 0.55396 0.24407 0.36936 0.42599 0.36936 0.3041 0.27951 0.26751 0.38312 0.41142 0.42599 0.26751 0.21023 0.32952 0.35584 0.39714 0.47146 0.34257 0.26751 0.38312 0.36936 0.38312 Seq60 0.45599 0.00838 0.53672 0.44084 0.45599 0.19928 0.42599 0.3167 0.6082 0.51986 0.14681 0.36936 0.35584 0.01685 0.57161 0.32952 0.51986 0.47146 0.44084 0.55396 0.58968 0.3041 0.58968 0.17785 0.18849 0.45599 0.6082 0.21023 0.50338 0.44084 0.35584 0.6082 0.36936 0.58968 0.36936 0.44084 0.26751 0.64667 0.36936 0.41142 0.50338 0.42599 0.51986 0.35584 0.27951 0.41142 0.53672 0.6082 0.19928 0.3041 0.44084 0.42599 0.6082 0.58968 0.48725 0.19928 0.44084 0.45599 0.51986 0.32952 Seq61 0.35584 0.23262 0.53672 0.36936 0.3041 0.09777 0.35584 0.3041 0.64667 0.45599 0.18849 0.44084 0.42599 0.24407 0.57161 0.32952 0.51986 0.3167 0.38312 0.55396 0.50338 0.3041 0.51986 0.21023 0.06982 0.34257 0.50338 0.17785 0.45599 0.36936 0.38312 0.48725 0.38312 0.6082 0.36936 0.38312 0.32952 0.57161 0.38312 0.36936 0.47146 0.38312 0.34257 0.34257 0.32952 0.41142 0.53672 0.50338 0.117 0.25569 0.38312 0.36936 0.50338 0.51986 0.48725 0.21023 0.39714 0.39714 0.45599 0.32952 0.23262 Seq62 0.57161 0.57161 0.2917 0.58968 0.53672 0.62719 0.58968 0.3167 0.06982 0.58968 0.48725 0.53672 0.53672 0.55396 0.21023 0.55396 0.27951 0.51986 0.53672 0.27951 0.45599 0.39714 0.23262 0.48725 0.57161 0.6082 0.42599 0.50338 0.24407 0.41142 0.35584 0.23262 0.55396 0.07902 0.44084 0.44084 0.35584 0.51986 0.35584 0.57161 0.45599 0.55396 0.53672 0.34257 0.38312 0.6082 0.2917 0.36936 0.47146 0.39714 0.6082 0.55396 0.39714 0.23262 0.53672 0.50338 0.53672 0.55396 0.6082 0.45599 0.57161 0.55396 Seq63 0.34257 0.26751 0.44084 0.32952 0.34257 0.34257 0.3167 0.26751 0.45599 0.35584 0.25569 0.2917 0.26751 0.25569 0.50338 0.32952 0.42599 0.35584 0.39714 0.47146 0.51986 0.07902 0.47146 0.3167 0.32952 0.32952 0.47146 0.34257 0.39714 0.3167 0.13674 0.47146 0.38312 0.47146 0.12681 0.44084 0.00838 0.53672 0.13674 0.41142 0.41142 0.42599 0.3167 0.27951 0.26751 0.39714 0.47146 0.45599 0.3041 0.10733 0.35584 0.34257 0.41142 0.47146 0.36936 0.25569 0.41142 0.41142 0.38312 0.13674 0.27951 0.34257 0.36936 Seq64 0.35584 0.39714 0.48725 0.34257 0.36936 0.42599 0.35584 0.36936 0.55396 0.48725 0.36936 0.36936 0.36936 0.41142 0.48725 0.17785 0.50338 0.38312 0.21023 0.51986 0.41142 0.38312 0.51986 0.44084 0.41142 0.35584 0.57161 0.38312 0.47146 0.35584 0.38312 0.53672 0.53672 0.53672 0.35584 0.47146 0.32952 0.58968 0.38312 0.22134 0.44084 0.23262 0.39714 0.35584 0.38312 0.23262 0.50338 0.57161 0.39714 0.38312 0.32952 0.42599 0.55396 0.51986 0.48725 0.42599 0.22134 0.19928 0.45599 0.41142 0.39714 0.44084 0.53672 0.34257 Seq65 0.42599 0.21023 0.58968 0.41142 0.44084 0.22134 0.42599 0.32952 0.62719 0.51986 0.22134 0.39714 0.35584 0.19928 0.58968 0.35584 0.57161 0.44084 0.44084 0.58968 0.53672 0.25569 0.55396 0.08834 0.19928 0.45599 0.48725 0.19928 0.51986 0.38312 0.25569 0.51986 0.35584 0.64667 0.24407 0.39714 0.24407 0.62719 0.24407 0.42599 0.47146 0.44084 0.44084 0.36936 0.34257 0.41142 0.6082 0.6082 0.17785 0.25569 0.44084 0.38312 0.55396 0.55396 0.51986 0.05174 0.45599 0.45599 0.55396 0.3041 0.21023 0.19928 0.57161 0.25569 0.41142 Seq66 0.39714 0.36936 0.44084 0.41142 0.35584 0.34257 0.39714 0.3041 0.55396 0.45599 0.27951 0.42599 0.38312 0.35584 0.58968 0.3167 0.42599 0.38312 0.42599 0.47146 0.58968 0.34257 0.53672 0.35584 0.3167 0.41142 0.45599 0.3041 0.51986 0.42599 0.38312 0.53672 0.39714 0.55396 0.39714 0.38312 0.3167 0.53672 0.38312 0.42599 0.41142 0.44084 0.39714 0.32952 0.41142 0.38312 0.47146 0.45599 0.26751 0.3041 0.36936 0.36936 0.44084 0.53672 0.47146 0.27951 0.44084 0.41142 0.48725 0.34257 0.36936 0.26751 0.51986 0.32952 0.41142 0.3041 Seq67 0.32952 0.55396 0.35584 0.32952 0.27951 0.57161 0.32952 0.36936 0.45599 0.44084 0.50338 0.51986 0.53672 0.57161 0.41142 0.51986 0.34257 0.26751 0.57161 0.3041 0.70835 0.44084 0.45599 0.47146 0.55396 0.32952 0.47146 0.50338 0.39714 0.36936 0.50338 0.39714 0.64667 0.42599 0.45599 0.41142 0.45599 0.44084 0.48725 0.57161 0.45599 0.58968 0.3167 0.44084 0.42599 0.58968 0.32952 0.117 0.50338 0.44084 0.38312 0.3167 0.21023 0.45599 0.45599 0.55396 0.58968 0.55396 0.42599 0.45599 0.57161 0.50338 0.38312 0.47146 0.50338 0.57161 0.48725 Seq68 0.36936 0.3041 0.58968 0.35584 0.38312 0.24407 0.36936 0.25569 0.57161 0.51986 0.25569 0.50338 0.48725 0.2917 0.53672 0.35584 0.57161 0.36936 0.48725 0.57161 0.58968 0.34257 0.6082 0.19928 0.22134 0.36936 0.57161 0.3167 0.57161 0.38312 0.34257 0.57161 0.26751 0.58968 0.3167 0.35584 0.3167 0.53672 0.32952 0.47146 0.50338 0.48725 0.36936 0.3167 0.35584 0.36936 0.57161 0.53672 0.21023 0.35584 0.32952 0.34257 0.50338 0.6082 0.55396 0.26751 0.48725 0.50338 0.57161 0.38312 0.3041 0.27951 0.57161 0.32952 0.45599 0.24407 0.3167 0.50338 Seq69 0.13674 0.41142 0.48725 0.13674 0.13674 0.34257 0.13674 0.34257 0.55396 0.34257 0.39714 0.41142 0.45599 0.42599 0.58968 0.39714 0.47146 0.15701 0.44084 0.50338 0.57161 0.34257 0.57161 0.38312 0.32952 0.12681 0.57161 0.38312 0.55396 0.25569 0.3167 0.58968 0.48725 0.53672 0.35584 0.38312 0.35584 0.55396 0.32952 0.47146 0.38312 0.45599 0.16736 0.39714 0.36936 0.44084 0.45599 0.3041 0.39714 0.36936 0.19928 0.08834 0.36936 0.57161 0.34257 0.48725 0.45599 0.42599 0.34257 0.34257 0.41142 0.41142 0.55396 0.35584 0.34257 0.45599 0.41142 0.3167 0.34257 Seq70 0.45599 0.45599 0.57161 0.45599 0.39714 0.44084 0.47146 0.36936 0.68722 0.55396 0.36936 0.55396 0.53672 0.47146 0.55396 0.17785 0.58968 0.41142 0.08834 0.58968 0.27951 0.36936 0.50338 0.47146 0.42599 0.42599 0.50338 0.35584 0.51986 0.6082 0.48725 0.47146 0.45599 0.64667 0.44084 0.53672 0.39714 0.64667 0.48725 0.06982 0.57161 0.07902 0.42599 0.38312 0.42599 0.12681 0.55396 0.68722 0.34257 0.42599 0.39714 0.51986 0.62719 0.50338 0.62719 0.41142 0.07902 0.09777 0.55396 0.38312 0.45599 0.39714 0.62719 0.41142 0.26751 0.47146 0.42599 0.6082 0.42599 0.48725 Seq71 0.44084 0.35584 0.45599 0.42599 0.34257 0.36936 0.42599 0.27951 0.45599 0.53672 0.26751 0.3041 0.2917 0.34257 0.50338 0.3041 0.44084 0.39714 0.3167 0.48725 0.48725 0.19928 0.47146 0.25569 0.35584 0.38312 0.39714 0.32952 0.45599 0.32952 0.16736 0.45599 0.36936 0.45599 0.16736 0.34257 0.19928 0.44084 0.16736 0.32952 0.42599 0.34257 0.32952 0.27951 0.36936 0.2917 0.50338 0.50338 0.27951 0.25569 0.32952 0.35584 0.47146 0.47146 0.48725 0.25569 0.32952 0.32952 0.57161 0.18849 0.35584 0.3167 0.45599 0.19928 0.3167 0.25569 0.3167 0.48725 0.3041 0.35584 0.34257 Seq72 0.41142 0.44084 0.57161 0.42599 0.36936 0.45599 0.45599 0.25569 0.47146 0.55396 0.3167 0.53672 0.50338 0.42599 0.47146 0.35584 0.55396 0.39714 0.42599 0.51986 0.55396 0.42599 0.53672 0.35584 0.42599 0.42599 0.6082 0.3167 0.47146 0.36936 0.36936 0.50338 0.41142 0.47146 0.38312 0.00838 0.42599 0.55396 0.36936 0.42599 0.50338 0.44084 0.41142 0.2917 0.35584 0.39714 0.51986 0.47146 0.3041 0.41142 0.44084 0.32952 0.50338 0.53672 0.48725 0.35584 0.42599 0.44084 0.55396 0.44084 0.44084 0.38312 0.45599 0.44084 0.45599 0.39714 0.38312 0.42599 0.35584 0.36936 0.51986 0.35584 Seq73 0.38312 0.27951 0.44084 0.38312 0.35584 0.36936 0.38312 0.3041 0.48725 0.38312 0.26751 0.24407 0.23262 0.26751 0.50338 0.39714 0.42599 0.36936 0.44084 0.45599 0.58968 0.15701 0.48725 0.27951 0.36936 0.38312 0.44084 0.3041 0.47146 0.3041 0.18849 0.47146 0.42599 0.51986 0.18849 0.42599 0.13674 0.55396 0.18849 0.44084 0.42599 0.44084 0.34257 0.3167 0.27951 0.44084 0.47146 0.44084 0.27951 0.16736 0.38312 0.35584 0.38312 0.48725 0.38312 0.24407 0.45599 0.45599 0.41142 0.12681 0.2917 0.3041 0.42599 0.13674 0.39714 0.25569 0.27951 0.45599 0.38312 0.39714 0.48725 0.18849 0.42599 Seq74 0.45599 0.47146 0.58968 0.47146 0.41142 0.48725 0.50338 0.2917 0.48725 0.6082 0.34257 0.53672 0.50338 0.45599 0.48725 0.36936 0.57161 0.44084 0.44084 0.53672 0.57161 0.42599 0.55396 0.36936 0.45599 0.47146 0.58968 0.34257 0.48725 0.39714 0.36936 0.51986 0.44084 0.48725 0.38312 0.01685 0.42599 0.55396 0.36936 0.44084 0.50338 0.45599 0.45599 0.32952 0.39714 0.41142 0.53672 0.48725 0.34257 0.44084 0.48725 0.36936 0.51986 0.55396 0.53672 0.35584 0.44084 0.45599 0.6082 0.45599 0.47146 0.41142 0.47146 0.44084 0.47146 0.39714 0.38312 0.44084 0.38312 0.41142 0.53672 0.34257 0.02543 0.42599 Seq75 0.35584 0.36936 0.47146 0.34257 0.32952 0.39714 0.35584 0.34257 0.39714 0.47146 0.34257 0.3167 0.3041 0.35584 0.42599 0.44084 0.45599 0.38312 0.42599 0.48725 0.55396 0.18849 0.50338 0.26751 0.39714 0.32952 0.45599 0.35584 0.41142 0.32952 0.01685 0.50338 0.45599 0.39714 0.06073 0.35584 0.15701 0.48725 0.00838 0.47146 0.35584 0.45599 0.3041 0.36936 0.38312 0.45599 0.48725 0.47146 0.32952 0.22134 0.38312 0.2917 0.42599 0.50338 0.50338 0.2917 0.44084 0.44084 0.50338 0.24407 0.38312 0.39714 0.34257 0.14681 0.38312 0.25569 0.39714 0.47146 0.32952 0.32952 0.48725 0.15701 0.36936 0.19928 0.35584 Seq76 0.57161 0.6082 0.27951 0.57161 0.51986 0.55396 0.53672 0.47146 0.48725 0.58968 0.57161 0.57161 0.51986 0.62719 0.47146 0.57161 0.2917 0.50338 0.62719 0.27951 0.58968 0.57161 0.48725 0.57161 0.55396 0.57161 0.26751 0.55396 0.32952 0.6082 0.53672 0.53672 0.55396 0.45599 0.55396 0.51986 0.57161 0.08834 0.55396 0.64667 0.45599 0.64667 0.57161 0.48725 0.50338 0.58968 0.3167 0.32952 0.58968 0.57161 0.44084 0.44084 0.32952 0.48725 0.66667 0.66667 0.64667 0.6082 0.58968 0.57161 0.6082 0.53672 0.51986 0.58968 0.55396 0.64667 0.48725 0.38312 0.53672 0.50338 0.6082 0.47146 0.53672 0.58968 0.55396 0.53672 Seq77 0.44084 0.18849 0.53672 0.45599 0.36936 0.23262 0.47146 0.26751 0.51986 0.45599 0.05174 0.38312 0.36936 0.17785 0.51986 0.3041 0.51986 0.39714 0.34257 0.51986 0.57161 0.3041 0.55396 0.22134 0.22134 0.42599 0.64667 0.14681 0.45599 0.3041 0.34257 0.51986 0.3041 0.51986 0.34257 0.3041 0.3041 0.64667 0.34257 0.3167 0.41142 0.32952 0.42599 0.3041 0.3167 0.32952 0.50338 0.53672 0.09777 0.2917 0.44084 0.42599 0.51986 0.55396 0.44084 0.21023 0.34257 0.35584 0.48725 0.3041 0.18849 0.17785 0.47146 0.3167 0.42599 0.24407 0.26751 0.51986 0.3041 0.44084 0.35584 0.3041 0.3041 0.2917 0.32952 0.35584 0.6082 Seq78 0.35584 0.3041 0.38312 0.36936 0.38312 0.36936 0.41142 0.23262 0.45599 0.45599 0.3041 0.3167 0.2917 0.2917 0.45599 0.35584 0.36936 0.35584 0.36936 0.39714 0.45599 0.117 0.41142 0.2917 0.3167 0.42599 0.42599 0.3041 0.39714 0.3041 0.16736 0.39714 0.38312 0.48725 0.13674 0.39714 0.09777 0.57161 0.15701 0.38312 0.44084 0.39714 0.38312 0.27951 0.25569 0.39714 0.39714 0.47146 0.3167 0.16736 0.35584 0.34257 0.38312 0.41142 0.38312 0.23262 0.38312 0.38312 0.48725 0.13674 0.3167 0.32952 0.36936 0.10733 0.3167 0.25569 0.2917 0.45599 0.3167 0.36936 0.38312 0.14681 0.39714 0.117 0.39714 0.16736 0.57161 0.32952 Seq79 0.34257 0.34257 0.3167 0.34257 0.26751 0.39714 0.3167 0.15701 0.45599 0.39714 0.3041 0.27951 0.26751 0.32952 0.44084 0.34257 0.32952 0.3041 0.42599 0.3167 0.53672 0.19928 0.35584 0.3167 0.39714 0.3041 0.45599 0.34257 0.39714 0.34257 0.3167 0.34257 0.38312 0.45599 0.3167 0.35584 0.23262 0.51986 0.3167 0.41142 0.39714 0.42599 0.26751 0.12681 0.15701 0.35584 0.34257 0.44084 0.23262 0.18849 0.36936 0.35584 0.41142 0.35584 0.41142 0.3041 0.42599 0.44084 0.42599 0.19928 0.35584 0.3041 0.39714 0.23262 0.44084 0.34257 0.3167 0.42599 0.32952 0.38312 0.36936 0.25569 0.34257 0.19928 0.38312 0.3167 0.53672 0.2917 0.25569 Seq80 0.50338 0.53672 0.00838 0.51986 0.45599 0.57161 0.50338 0.38312 0.3167 0.58968 0.57161 0.44084 0.44084 0.55396 0.35584 0.51986 0.01685 0.44084 0.58968 0.05174 0.55396 0.42599 0.3041 0.51986 0.53672 0.48725 0.2917 0.53672 0.26751 0.48725 0.50338 0.3041 0.53672 0.27951 0.50338 0.55396 0.44084 0.23262 0.50338 0.58968 0.42599 0.58968 0.47146 0.32952 0.35584 0.6082 0.12681 0.2917 0.51986 0.41142 0.47146 0.44084 0.32952 0.3041 0.53672 0.55396 0.58968 0.57161 0.58968 0.44084 0.55396 0.51986 0.27951 0.45599 0.48725 0.6082 0.45599 0.34257 0.6082 0.47146 0.58968 0.47146 0.57161 0.45599 0.58968 0.48725 0.27951 0.55396 0.39714 0.32952 Seq81 0.34257 0.32952 0.39714 0.35584 0.39714 0.38312 0.38312 0.2917 0.50338 0.39714 0.38312 0.21023 0.19928 0.3167 0.53672 0.42599 0.38312 0.38312 0.51986 0.41142 0.57161 0.18849 0.50338 0.3167 0.36936 0.38312 0.39714 0.36936 0.45599 0.38312 0.17785 0.50338 0.44084 0.51986 0.18849 0.42599 0.16736 0.53672 0.16736 0.55396 0.41142 0.55396 0.38312 0.3167 0.2917 0.50338 0.41142 0.48725 0.32952 0.19928 0.38312 0.32952 0.42599 0.50338 0.45599 0.2917 0.53672 0.51986 0.42599 0.13674 0.34257 0.39714 0.45599 0.16736 0.41142 0.27951 0.35584 0.51986 0.36936 0.35584 0.55396 0.23262 0.41142 0.14681 0.42599 0.16736 0.57161 0.39714 0.12681 0.24407 0.41142 Seq82 0.39714 0.47146 0.50338 0.38312 0.34257 0.41142 0.35584 0.3167 0.50338 0.55396 0.42599 0.45599 0.42599 0.48725 0.41142 0.41142 0.48725 0.36936 0.45599 0.48725 0.48725 0.36936 0.58968 0.32952 0.41142 0.36936 0.51986 0.44084 0.51986 0.41142 0.25569 0.57161 0.47146 0.47146 0.26751 0.38312 0.34257 0.50338 0.25569 0.45599 0.21023 0.47146 0.35584 0.36936 0.41142 0.45599 0.51986 0.48725 0.36936 0.36936 0.35584 0.26751 0.48725 0.58968 0.53672 0.41142 0.47146 0.44084 0.51986 0.38312 0.47146 0.41142 0.41142 0.32952 0.39714 0.38312 0.36936 0.39714 0.34257 0.35584 0.45599 0.3167 0.39714 0.39714 0.38312 0.24407 0.50338 0.45599 0.35584 0.36936 0.51986 0.39714 Seq83 0.99132 0.82396 0.82396 0.99132 0.90298 0.64667 0.93128 0.70835 0.84939 1.05658 0.66667 0.73009 0.73009 0.79937 0.66667 0.70835 0.82396 0.93128 0.66667 0.84939 0.75248 0.77556 0.79937 0.8757 0.68722 0.90298 0.75248 0.75248 0.68722 0.77556 0.75248 0.84939 0.75248 0.82396 0.82396 0.90298 0.79937 0.66667 0.75248 0.73009 0.79937 0.70835 0.90298 0.73009 0.75248 0.68722 0.93128 0.93128 0.68722 0.8757 0.82396 0.99132 0.84939 0.79937 1.12806 0.79937 0.68722 0.66667 1.09147 0.75248 0.82396 0.62719 0.77556 0.79937 0.73009 0.82396 0.68722 0.99132 0.73009 0.90298 0.70835 0.70835 0.90298 0.70835 0.84939 0.77556 0.68722 0.62719 0.73009 0.79937 0.82396 0.75248 0.9607 Seq84 0.36936 0.48725 0.55396 0.38312 0.3167 0.53672 0.36936 0.41142 0.64667 0.23262 0.42599 0.45599 0.50338 0.47146 0.62719 0.45599 0.53672 0.2917 0.48725 0.53672 0.64667 0.32952 0.66667 0.51986 0.48725 0.35584 0.70835 0.50338 0.53672 0.25569 0.50338 0.64667 0.55396 0.68722 0.48725 0.48725 0.36936 0.64667 0.50338 0.48725 0.51986 0.48725 0.32952 0.42599 0.42599 0.48725 0.48725 0.39714 0.41142 0.36936 0.35584 0.34257 0.34257 0.66667 0.00838 0.48725 0.50338 0.48725 0.22134 0.32952 0.48725 0.47146 0.55396 0.38312 0.50338 0.51986 0.48725 0.45599 0.55396 0.34257 0.6082 0.47146 0.47146 0.39714 0.51986 0.50338 0.66667 0.42599 0.38312 0.39714 0.55396 0.45599 0.55396 1.09147 Seq85 0.32952 0.41142 0.55396 0.34257 0.32952 0.42599 0.35584 0.3041 0.51986 0.44084 0.35584 0.24407 0.26751 0.39714 0.50338 0.34257 0.57161 0.3041 0.39714 0.48725 0.50338 0.24407 0.51986 0.27951 0.39714 0.36936 0.47146 0.3167 0.44084 0.26751 0.23262 0.47146 0.36936 0.55396 0.18849 0.36936 0.23262 0.57161 0.22134 0.41142 0.45599 0.42599 0.34257 0.34257 0.3167 0.39714 0.47146 0.48725 0.2917 0.26751 0.34257 0.3167 0.44084 0.51986 0.32952 0.26751 0.41142 0.39714 0.44084 0.19928 0.41142 0.38312 0.47146 0.24407 0.3167 0.23262 0.36936 0.44084 0.36936 0.34257 0.47146 0.24407 0.35584 0.25569 0.36936 0.22134 0.57161 0.35584 0.19928 0.3167 0.57161 0.18849 0.32952 0.90298 0.32952 Seq86 0.38312 0.36936 0.45599 0.39714 0.35584 0.36936 0.36936 0.34257 0.45599 0.47146 0.34257 0.3041 0.27951 0.35584 0.45599 0.44084 0.44084 0.35584 0.42599 0.45599 0.47146 0.16736 0.50338 0.3167 0.38312 0.38312 0.48725 0.34257 0.39714 0.3041 0.08834 0.51986 0.42599 0.48725 0.06982 0.35584 0.16736 0.50338 0.09777 0.44084 0.36936 0.45599 0.35584 0.32952 0.3167 0.45599 0.44084 0.45599 0.3167 0.17785 0.38312 0.3041 0.39714 0.50338 0.44084 0.34257 0.44084 0.44084 0.50338 0.23262 0.38312 0.36936 0.39714 0.16736 0.36936 0.3041 0.38312 0.47146 0.38312 0.35584 0.44084 0.15701 0.36936 0.18849 0.35584 0.08834 0.51986 0.34257 0.13674 0.27951 0.47146 0.18849 0.26751 0.84939 0.44084 0.19928 Seq87 0.35584 0.42599 0.57161 0.35584 0.3167 0.41142 0.3041 0.3167 0.51986 0.39714 0.38312 0.27951 0.3041 0.41142 0.47146 0.42599 0.55396 0.3041 0.44084 0.55396 0.53672 0.23262 0.47146 0.38312 0.42599 0.34257 0.50338 0.41142 0.55396 0.32952 0.23262 0.48725 0.39714 0.55396 0.23262 0.48725 0.25569 0.68722 0.24407 0.42599 0.36936 0.44084 0.3041 0.34257 0.3167 0.45599 0.53672 0.48725 0.34257 0.26751 0.39714 0.34257 0.41142 0.47146 0.36936 0.36936 0.45599 0.44084 0.39714 0.21023 0.42599 0.39714 0.42599 0.25569 0.38312 0.34257 0.39714 0.45599 0.42599 0.32952 0.47146 0.24407 0.47146 0.22134 0.48725 0.24407 0.64667 0.41142 0.23262 0.26751 0.58968 0.26751 0.27951 0.84939 0.36936 0.17785 0.18849 Seq88 0.39714 0.23262 0.58968 0.38312 0.38312 0.08834 0.36936 0.35584 0.64667 0.39714 0.22134 0.42599 0.36936 0.24407 0.53672 0.32952 0.57161 0.38312 0.41142 0.64667 0.51986 0.34257 0.55396 0.22134 0.07902 0.39714 0.55396 0.22134 0.50338 0.36936 0.38312 0.57161 0.41142 0.62719 0.38312 0.42599 0.3167 0.6082 0.38312 0.39714 0.45599 0.41142 0.42599 0.36936 0.38312 0.41142 0.53672 0.58968 0.16736 0.2917 0.36936 0.36936 0.53672 0.55396 0.48725 0.22134 0.42599 0.42599 0.39714 0.39714 0.23262 0.10733 0.58968 0.32952 0.36936 0.17785 0.2917 0.53672 0.24407 0.41142 0.45599 0.35584 0.42599 0.36936 0.45599 0.39714 0.57161 0.23262 0.36936 0.41142 0.57161 0.39714 0.38312 0.75248 0.50338 0.36936 0.41142 0.44084 Seq89 0.34257 0.36936 0.48725 0.35584 0.36936 0.39714 0.38312 0.27951 0.48725 0.45599 0.35584 0.21023 0.18849 0.35584 0.47146 0.36936 0.50338 0.34257 0.45599 0.48725 0.55396 0.21023 0.47146 0.3041 0.35584 0.39714 0.45599 0.36936 0.48725 0.35584 0.23262 0.48725 0.41142 0.51986 0.23262 0.42599 0.22134 0.62719 0.22134 0.47146 0.44084 0.48725 0.36936 0.27951 0.25569 0.45599 0.42599 0.57161 0.27951 0.24407 0.38312 0.35584 0.47146 0.47146 0.44084 0.2917 0.47146 0.45599 0.48725 0.19928 0.36936 0.34257 0.44084 0.23262 0.41142 0.25569 0.35584 0.50338 0.36936 0.39714 0.50338 0.26751 0.41142 0.22134 0.42599 0.22134 0.58968 0.36936 0.19928 0.24407 0.50338 0.15701 0.35584 0.8757 0.44084 0.12681 0.23262 0.17785 0.34257 Seq90 0.32952 0.16736 0.50338 0.34257 0.35584 0.14681 0.32952 0.26751 0.53672 0.42599 0.12681 0.44084 0.42599 0.15701 0.62719 0.3167 0.48725 0.34257 0.38312 0.55396 0.51986 0.27951 0.53672 0.22134 0.13674 0.32952 0.58968 0.14681 0.53672 0.34257 0.2917 0.55396 0.25569 0.55396 0.2917 0.35584 0.25569 0.68722 0.3041 0.35584 0.57161 0.36936 0.38312 0.3041 0.24407 0.34257 0.50338 0.53672 0.117 0.26751 0.36936 0.38312 0.50338 0.53672 0.48725 0.21023 0.38312 0.39714 0.45599 0.3041 0.17785 0.17785 0.53672 0.26751 0.38312 0.19928 0.2917 0.57161 0.22134 0.32952 0.36936 0.27951 0.35584 0.3041 0.38312 0.3167 0.62719 0.12681 0.26751 0.3041 0.51986 0.34257 0.47146 0.73009 0.48725 0.35584 0.27951 0.36936 0.22134 0.35584 Seq91 0.36936 0.23262 0.55396 0.38312 0.36936 0.22134 0.36936 0.2917 0.55396 0.42599 0.18849 0.45599 0.42599 0.24407 0.58968 0.3167 0.53672 0.34257 0.35584 0.57161 0.48725 0.34257 0.57161 0.22134 0.21023 0.39714 0.53672 0.01685 0.51986 0.35584 0.32952 0.57161 0.34257 0.51986 0.36936 0.3167 0.32952 0.6082 0.34257 0.32952 0.48725 0.34257 0.39714 0.36936 0.32952 0.34257 0.53672 0.53672 0.17785 0.3041 0.34257 0.3167 0.53672 0.57161 0.50338 0.21023 0.35584 0.36936 0.42599 0.34257 0.23262 0.19928 0.50338 0.34257 0.38312 0.22134 0.3041 0.50338 0.3167 0.38312 0.35584 0.32952 0.3167 0.32952 0.34257 0.35584 0.55396 0.16736 0.3041 0.34257 0.53672 0.34257 0.44084 0.79937 0.50338 0.2917 0.34257 0.41142 0.19928 0.34257 0.16736 Seq92 0.47146 0.42599 0.55396 0.47146 0.41142 0.41142 0.48725 0.35584 0.55396 0.51986 0.34257 0.57161 0.55396 0.44084 0.45599 0.15701 0.57161 0.42599 0.05174 0.55396 0.2917 0.41142 0.44084 0.44084 0.39714 0.44084 0.53672 0.32952 0.47146 0.51986 0.48725 0.41142 0.42599 0.51986 0.48725 0.44084 0.44084 0.66667 0.48725 0.04287 0.55396 0.0341 0.44084 0.36936 0.41142 0.13674 0.50338 0.58968 0.3167 0.44084 0.42599 0.47146 0.58968 0.44084 0.53672 0.41142 0.04287 0.06073 0.50338 0.39714 0.42599 0.36936 0.50338 0.45599 0.27951 0.47146 0.47146 0.51986 0.48725 0.44084 0.09777 0.36936 0.42599 0.47146 0.47146 0.48725 0.6082 0.32952 0.42599 0.42599 0.53672 0.58968 0.51986 0.75248 0.51986 0.47146 0.48725 0.48725 0.39714 0.51986 0.36936 0.32952 Seq93 0.06073 0.45599 0.51986 0.05174 0.06982 0.36936 0.04287 0.36936 0.55396 0.3041 0.42599 0.41142 0.45599 0.47146 0.62719 0.42599 0.50338 0.09777 0.50338 0.51986 0.66667 0.36936 0.55396 0.41142 0.36936 0.0341 0.62719 0.39714 0.6082 0.2917 0.2917 0.55396 0.44084 0.53672 0.3167 0.44084 0.34257 0.58968 0.3041 0.53672 0.48725 0.51986 0.04287 0.39714 0.38312 0.44084 0.48725 0.34257 0.41142 0.34257 0.27951 0.14681 0.38312 0.55396 0.38312 0.45599 0.51986 0.48725 0.3041 0.36936 0.47146 0.39714 0.57161 0.32952 0.38312 0.41142 0.42599 0.34257 0.32952 0.12681 0.48725 0.39714 0.42599 0.38312 0.47146 0.3041 0.57161 0.48725 0.39714 0.32952 0.50338 0.35584 0.36936 0.9607 0.38312 0.32952 0.36936 0.3167 0.42599 0.36936 0.34257 0.39714 0.50338 Seq94 0.6082 0.57161 0.27951 0.6082 0.53672 0.57161 0.58968 0.48725 0.44084 0.58968 0.53672 0.45599 0.42599 0.58968 0.44084 0.50338 0.2917 0.51986 0.55396 0.3041 0.64667 0.47146 0.47146 0.50338 0.55396 0.57161 0.23262 0.53672 0.34257 0.55396 0.48725 0.50338 0.62719 0.42599 0.50338 0.50338 0.51986 0.117 0.48725 0.55396 0.41142 0.57161 0.53672 0.47146 0.55396 0.53672 0.35584 0.36936 0.53672 0.55396 0.47146 0.48725 0.3167 0.47146 0.62719 0.55396 0.57161 0.53672 0.58968 0.50338 0.57161 0.51986 0.45599 0.53672 0.48725 0.53672 0.44084 0.35584 0.51986 0.51986 0.55396 0.38312 0.51986 0.48725 0.50338 0.47146 0.10733 0.55396 0.50338 0.48725 0.27951 0.51986 0.48725 0.66667 0.6082 0.50338 0.50338 0.55396 0.53672 0.50338 0.62719 0.53672 0.57161 0.57161 Seq95 0.3167 0.44084 0.66667 0.3041 0.24407 0.48725 0.26751 0.42599 0.57161 0.18849 0.41142 0.47146 0.51986 0.42599 0.64667 0.44084 0.64667 0.24407 0.50338 0.62719 0.62719 0.36936 0.68722 0.53672 0.47146 0.25569 0.79937 0.47146 0.66667 0.3041 0.44084 0.64667 0.6082 0.6082 0.44084 0.48725 0.38312 0.73009 0.44084 0.51986 0.55396 0.50338 0.26751 0.50338 0.44084 0.45599 0.53672 0.39714 0.41142 0.39714 0.35584 0.3041 0.38312 0.68722 0.14681 0.50338 0.51986 0.50338 0.18849 0.34257 0.45599 0.45599 0.55396 0.36936 0.48725 0.53672 0.50338 0.45599 0.57161 0.32952 0.58968 0.47146 0.47146 0.41142 0.51986 0.44084 0.70835 0.42599 0.44084 0.41142 0.64667 0.47146 0.51986 1.05658 0.13674 0.38312 0.47146 0.39714 0.45599 0.45599 0.47146 0.47146 0.50338 0.3041 0.68722 Seq96 0.2917 0.50338 0.62719 0.2917 0.3167 0.39714 0.26751 0.48725 0.66667 0.06073 0.48725 0.47146 0.44084 0.51986 0.68722 0.47146 0.6082 0.26751 0.51986 0.62719 0.68722 0.41142 0.66667 0.57161 0.44084 0.2917 0.68722 0.42599 0.62719 0.36936 0.50338 0.68722 0.6082 0.64667 0.51986 0.57161 0.38312 0.68722 0.50338 0.51986 0.51986 0.51986 0.32952 0.53672 0.48725 0.53672 0.51986 0.42599 0.44084 0.36936 0.3167 0.35584 0.39714 0.66667 0.22134 0.57161 0.53672 0.51986 0.0341 0.38312 0.51986 0.45599 0.6082 0.38312 0.45599 0.55396 0.50338 0.45599 0.58968 0.35584 0.58968 0.58968 0.55396 0.44084 0.6082 0.50338 0.58968 0.48725 0.48725 0.47146 0.6082 0.44084 0.53672 1.02324 0.23262 0.44084 0.51986 0.45599 0.39714 0.48725 0.45599 0.42599 0.51986 0.3167 0.62719 0.18849 Seq97 0.47146 0.48725 0.62719 0.47146 0.41142 0.47146 0.48725 0.38312 0.66667 0.53672 0.39714 0.58968 0.57161 0.50338 0.55396 0.17785 0.64667 0.42599 0.07902 0.62719 0.2917 0.42599 0.51986 0.50338 0.45599 0.44084 0.53672 0.35584 0.53672 0.58968 0.51986 0.48725 0.50338 0.62719 0.50338 0.53672 0.45599 0.68722 0.51986 0.06982 0.55396 0.06982 0.44084 0.39714 0.44084 0.117 0.57161 0.68722 0.36936 0.48725 0.41142 0.53672 0.62719 0.51986 0.58968 0.44084 0.06982 0.08834 0.51986 0.42599 0.48725 0.42599 0.6082 0.47146 0.26751 0.50338 0.45599 0.57161 0.48725 0.50338 0.0341 0.38312 0.51986 0.48725 0.53672 0.51986 0.64667 0.38312 0.44084 0.42599 0.6082 0.6082 0.48725 0.73009 0.57161 0.48725 0.50338 0.50338 0.45599 0.53672 0.42599 0.35584 0.06982 0.50338 0.57161 0.55396 0.55396 Seq98 0.57161 0.57161 0.38312 0.55396 0.51986 0.57161 0.51986 0.36936 0.35584 0.58968 0.50338 0.48725 0.48725 0.55396 0.23262 0.51986 0.39714 0.50338 0.48725 0.36936 0.47146 0.39714 0.09777 0.51986 0.57161 0.53672 0.44084 0.58968 0.2917 0.50338 0.45599 0.09777 0.53672 0.38312 0.42599 0.50338 0.42599 0.51986 0.44084 0.51986 0.53672 0.50338 0.51986 0.35584 0.38312 0.53672 0.27951 0.48725 0.50338 0.44084 0.57161 0.50338 0.41142 0.10733 0.62719 0.50338 0.48725 0.50338 0.62719 0.45599 0.57161 0.55396 0.27951 0.41142 0.50338 0.51986 0.53672 0.45599 0.58968 0.57161 0.51986 0.45599 0.51986 0.45599 0.50338 0.42599 0.53672 0.53672 0.38312 0.36936 0.36936 0.44084 0.47146 0.75248 0.62719 0.44084 0.42599 0.44084 0.55396 0.44084 0.57161 0.58968 0.48725 0.55396 0.53672 0.57161 0.62719 0.53672 Seq99 0.64667 0.58968 0.35584 0.62719 0.58968 0.57161 0.58968 0.42599 0.44084 0.58968 0.58968 0.6082 0.6082 0.6082 0.35584 0.57161 0.34257 0.6082 0.51986 0.38312 0.48725 0.47146 0.2917 0.51986 0.55396 0.62719 0.34257 0.50338 0.36936 0.62719 0.51986 0.3167 0.66667 0.39714 0.55396 0.57161 0.51986 0.44084 0.53672 0.48725 0.53672 0.48725 0.6082 0.44084 0.44084 0.55396 0.42599 0.53672 0.58968 0.47146 0.57161 0.55396 0.45599 0.2917 0.66667 0.50338 0.50338 0.53672 0.58968 0.53672 0.57161 0.57161 0.39714 0.51986 0.58968 0.53672 0.58968 0.51986 0.64667 0.58968 0.45599 0.48725 0.58968 0.51986 0.58968 0.51986 0.45599 0.62719 0.48725 0.42599 0.35584 0.51986 0.48725 0.79937 0.66667 0.62719 0.50338 0.50338 0.58968 0.57161 0.58968 0.50338 0.47146 0.58968 0.48725 0.68722 0.64667 0.47146 0.32952 scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/data/mp100.upgma.nwk000066400000000000000000000052161520735541300251660ustar00rootroot00000000000000(Seq83:0.40417551,((((Seq52:0.08426,(Seq47:0.0585,Seq67:0.0585):0.02576):0.08691315,((Seq46:0.06714625,(Seq19:0.02439167,(Seq80:0.0063075,(Seq02:0.00419,Seq16:0.00419):0.0021175):0.01808417):0.04275458):0.07880225,(Seq26:0.12794,(Seq94:0.0560825,(Seq37:0.04417,Seq76:0.04417):0.0119125):0.0718575):0.0180085):0.02522465):0.02527335,(Seq99:0.17721889,((Seq62:0.03721,(Seq08:0.012715,Seq33:0.012715):0.024495):0.110445,((Seq98:0.05047833,(Seq31:0.0192425,(Seq22:0.00419,Seq53:0.00419):0.0150525):0.03123583):0.08485792,(Seq14:0.09964,Seq28:0.09964):0.03569625):0.01231875):0.02956389):0.01922761):0.06386254,((Seq20:0.14987273,(Seq64:0.1154905,((Seq15:0.03951,Seq45:0.03951):0.02225406,((Seq70:0.01705,Seq97:0.01705):0.0228825,(Seq92:0.023231,((Seq39:0.00419,Seq41:0.00419):0.00639667,(Seq57:0.0063075,(Seq18:0.00419,Seq56:0.00419):0.0021175):0.00427917):0.01264433):0.0167015):0.02183156):0.05372644):0.03438223):0.07228804,((Seq40:0.105115,Seq82:0.105115):0.10516444,((((Seq96:0.0237075,(Seq09:0.012715,Seq58:0.012715):0.0109925):0.08212361,(Seq95:0.0708875,(Seq54:0.00419,Seq84:0.00419):0.0666975):0.03494361):0.05217299,(Seq29:0.13389727,(Seq50:0.1200265,((Seq17:0.03562286,((Seq04:0.01705,Seq42:0.01705):0.011133,((Seq00:0.00419,Seq03:0.00419):0.02095083,(Seq93:0.0192425,(Seq06:0.01705,Seq25:0.01705):0.0021925):0.00589833):0.00304217):0.00743986):0.03625964,(Seq51:0.04417,Seq69:0.04417):0.0277125):0.048144):0.01387077):0.02410682):0.04585843,((Seq74:0.01057,(Seq35:0.00419,Seq72:0.00419):0.00638):0.18650853,(Seq32:0.18737732,(((Seq79:0.07347167,(Seq44:0.0465275,(Seq07:0.030365,Seq43:0.030365):0.0161625):0.02694417):0.07662643,((Seq11:0.01705,Seq12:0.01705):0.12206147,((Seq87:0.088925,(Seq85:0.063405,Seq89:0.063405):0.02552):0.02489071,(((Seq49:0.0505,(Seq21:0.03951,(Seq36:0.00419,Seq63:0.00419):0.03532):0.01099):0.025135,(Seq81:0.06839333,(Seq59:0.0658875,(Seq73:0.0585,Seq78:0.0585):0.0073875):0.00250583):0.00724167):0.01541125,(Seq71:0.08161,(Seq86:0.04303375,(Seq34:0.02886667,(Seq75:0.0063075,(Seq30:0.00419,Seq38:0.00419):0.0021175):0.02255917):0.01416708):0.03857625):0.00943625):0.02276946):0.02529576):0.01098662):0.0171324,(Seq66:0.15540059,(Seq68:0.13201594,((Seq23:0.04184,(Seq55:0.02587,Seq65:0.02587):0.01597):0.06087808,((Seq61:0.04582,(Seq88:0.04184,(Seq05:0.021435,Seq24:0.021435):0.020405):0.00398):0.054135,((Seq60:0.0063075,(Seq01:0.00419,Seq13:0.00419):0.0021175):0.08884722,((Seq27:0.008425,Seq91:0.008425):0.07401562,((Seq10:0.02587,Seq77:0.02587):0.03514625,(Seq48:0.0585,Seq90:0.0585):0.00251625):0.02142438):0.0127141):0.00480028):0.00276308):0.02929786):0.02338465):0.01182991):0.02014682):0.00970121):0.006784):0.00641691):0.01188132):0.03814827):0.14386647); scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/test_compare.py000066400000000000000000000173011520735541300246240ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt from skbio import TreeNode from skbio.tree._compare import rf_dists, wrf_dists, path_dists class CompareTests(TestCase): def test_rf_dists(self): """Calculate Robinson-Foulds distances among trees.""" # all trees have identical taxa nwks = ["(((a,b),c),d,e);", "((a,(b,c)),d,e);", "((a,b),(c,d),e);", "(a,b,(c,(d,e)));"] trees = [TreeNode.read([x]) for x in nwks] obs = rf_dists(trees) self.assertSequenceEqual(obs.ids, list("0123")) exp = np.array([[0, 2, 2, 0], [2, 0, 4, 2], [2, 4, 0, 2], [0, 2, 2, 0]], dtype=float) npt.assert_allclose(obs.data, exp) # with IDs ids = list("ABCD") obs = rf_dists(trees, ids) self.assertSequenceEqual(obs.ids, ids) npt.assert_allclose(obs.data, exp) # rooted obs = rf_dists(trees, rooted=True).data exp = np.array([[0, 2, 2, 4], [2, 0, 4, 4], [2, 4, 0, 4], [4, 4, 4, 0]], dtype=float) npt.assert_allclose(obs, exp) # proportion obs = rf_dists(trees, proportion=True).data exp = np.array([[0, .5, .5, 0], [.5, 0, 1, .5], [.5, 1, 0, .5], [0, .5, .5, 0]], dtype=float) npt.assert_allclose(obs, exp) # with unique taxa nwks = ["(((a,b),c),((d,e),f),g);", "((a,(b,c)),(d,(e,f)),h);", "(((a,b),(c,e)),(f,h),i);", "((a,((b,c),f)),g,(h,e));"] trees = [TreeNode.read([x]) for x in nwks] obs = rf_dists(trees).data exp = np.array([[0, 2, 2, 4], [2, 0, 4, 2], [2, 4, 0, 4], [4, 2, 4, 0]], dtype=float) npt.assert_allclose(obs, exp) # pairwise sharing obs = rf_dists(trees, shared_by_all=False).data exp = np.array([[0, 4, 2, 6], [4, 0, 6, 4], [2, 6, 0, 6], [6, 4, 6, 0]], dtype=float) npt.assert_allclose(obs, exp) # duplicate IDs with self.assertRaises(ValueError): rf_dists(trees, list("xxxx")) # ID number doesn't match with self.assertRaises(ValueError): rf_dists(trees, list("abc")) # no shared taxon nwks = ["((a,b),(c,d));", "((e,f),(g,h));"] trees = [TreeNode.read([x]) for x in nwks] obs = rf_dists(trees).data self.assertFalse(np.any(obs)) # only one tree obs = rf_dists([TreeNode.read(["((a,b),(c,d));"])]).data npt.assert_array_equal(obs, np.zeros((1, 1))) # no tree with self.assertRaises(ValueError): rf_dists([]) def test_wrf_dists(self): """Calculate weighted Robinson-Foulds distances among trees.""" # all trees have identical taxa nwks = ["((a:1,b:2):1,c:4,((d:4,e:5):2,f:6):1);", "((a:3,(b:2,c:2):1):3,d:8,(e:5,f:6):2);", "((a:1,c:6):2,(b:3,(d:2,e:3):1):2,f:7);"] trees = [TreeNode.read([x]) for x in nwks] obs = wrf_dists(trees) self.assertSequenceEqual(obs.ids, list("012")) exp = np.array([[0, 16, 15], [16, 0, 27], [15, 27, 0]], dtype=float) npt.assert_allclose(obs.data, exp) # with IDs ids = list("ABC") obs = wrf_dists(trees, ids) self.assertSequenceEqual(obs.ids, ids) npt.assert_allclose(obs.data, exp) # rooted obs = wrf_dists(trees, rooted=True).data exp = np.array([[0, 18, 15], [18, 0, 27], [15, 27, 0]], dtype=float) npt.assert_allclose(obs, exp) # Euclidean distances obs = wrf_dists(trees, metric="euclidean").data exp = np.array([[0, 6.164414, 5], [6.164414, 0, 9.21954446], [5, 9.21954446, 0]]) npt.assert_allclose(obs, exp) # unit correlation distances obs = wrf_dists(trees, metric="unitcorr").data exp = np.array([[0, 0.15822237, 0.13211014], [0.15822237, 0, 0.32552865], [0.13211014, 0.32552865, 0]]) npt.assert_allclose(obs, exp) # invalide distance metric with self.assertRaises(ValueError): wrf_dists(trees, metric=100) with self.assertRaises(AttributeError): wrf_dists(trees, metric="hello") # with unique taxa nwks = ["((a:1,b:2):1,(c:3,d:4):2);", "((a:1,(b:2,d:4):1):2,e:5);", "(b:2,((c:3,d:4):1,e:5):2);"] trees = [TreeNode.read([x]) for x in nwks] obs = wrf_dists(trees).data exp = np.array([[0, 3, 0], [3, 0, 3], [0, 3, 0]], dtype=float) npt.assert_allclose(obs, exp) # pairwise sharing obs = wrf_dists(trees, shared_by_all=False).data exp = np.array([[0, 4, 0], [4, 0, 6], [0, 6, 0]], dtype=float) npt.assert_allclose(obs, exp) def test_path_dists(self): """Calculate path-length distances among trees.""" # all trees have identical taxa nwks = ["((a:1,b:2):1,c:4,((d:4,e:5):2,f:6):1);", "((a:3,(b:2,c:2):1):3,d:8,(e:5,f:6):2);", "((a:1,c:6):2,(b:3,(d:2,e:3):1):2,f:7);"] trees = [TreeNode.read([x]) for x in nwks] obs = path_dists(trees) self.assertSequenceEqual(obs.ids, list("012")) exp = np.array([13.7113092, 11.87434209, 19.5192213]) npt.assert_allclose(obs.condensed_form(), exp) # with IDs ids = list("ABC") obs = path_dists(trees, ids) self.assertSequenceEqual(obs.ids, ids) npt.assert_allclose(obs.condensed_form(), exp) # city block distances obs = path_dists(trees, metric="cityblock").condensed_form() exp = np.array([48, 37, 61]) npt.assert_allclose(obs, exp) # unit correlation distances obs = path_dists(trees, metric="unitcorr").condensed_form() exp = np.array([0.14130903, 0.2805951, 0.48826796]) npt.assert_allclose(obs, exp) # random sampling obs = path_dists(trees, sample=3, shuffler=list.sort).condensed_form() exp = np.array([4.24264069, 7.87400787, 9.2736185]) npt.assert_allclose(obs, exp) # too many samples with self.assertRaises(ValueError): path_dists(trees, sample=10) # with unique taxa nwks = ["((a:1,b:2):1,(c:3,d:4):2,e:5);", "((a:1,(b:2,d:4):1):2,e:5,f:6);", "(a:1,b:2,((c:3,d:4):1,e:5):2);"] trees = [TreeNode.read([x]) for x in nwks] obs = path_dists(trees).condensed_form() exp = np.array([4.47213595, 1.73205081, 4.35889894]) npt.assert_allclose(obs, exp) # pairwise sharing obs = path_dists(trees, shared_by_all=False).condensed_form() exp = np.array([4.47213595, 2.0, 4.35889894]) npt.assert_allclose(obs, exp) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/test_majority_rule.py000066400000000000000000000163421520735541300260670ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np from skbio import TreeNode from skbio.tree import majority_rule from skbio.tree._majority_rule import ( _walk_clades, _filter_clades, _build_trees) class MajorityRuleTests(TestCase): def test_majority_rule(self): trees = [ TreeNode.read(["(A,(B,(H,(D,(J,(((G,E),(F,I)),C))))));"]), TreeNode.read(["(A,(B,(D,((J,H),(((G,E),(F,I)),C)))));"]), TreeNode.read(["(A,(B,(D,(H,(J,(((G,E),(F,I)),C))))));"]), TreeNode.read(["(A,(B,(E,(G,((F,I),((J,(H,D)),C))))));"]), TreeNode.read(["(A,(B,(E,(G,((F,I),(((J,H),D),C))))));"]), TreeNode.read(["(A,(B,(E,((F,I),(G,((J,(H,D)),C))))));"]), TreeNode.read(["(A,(B,(E,((F,I),(G,(((J,H),D),C))))));"]), TreeNode.read(["(A,(B,(E,((G,(F,I)),((J,(H,D)),C)))));"]), TreeNode.read(["(A,(B,(E,((G,(F,I)),(((J,H),D),C)))));"])] exp = TreeNode.read(["(((E,(G,(F,I),(C,(D,J,H)))),B),A);"]) obs = majority_rule(trees) self.assertEqual(exp.compare_subsets(obs[0]), 0.0) self.assertEqual(len(obs), 1) tree = obs[0] exp_supports = sorted([9.0, 9.0, 9.0, 6.0, 6.0, 6.0]) obs_supports = sorted([n.support for n in tree.non_tips()]) self.assertEqual(obs_supports, exp_supports) obs = majority_rule(trees, weights=np.ones(len(trees)) * 2) self.assertEqual(exp.compare_subsets(obs[0]), 0.0) self.assertEqual(len(obs), 1) tree = obs[0] exp_supports = sorted([18.0, 18.0, 12.0, 18.0, 12.0, 12.0]) obs_supports = sorted([n.support for n in tree.non_tips()]) with self.assertRaises(ValueError): majority_rule(trees, weights=[1, 2]) def test_majority_rule_multiple_trees(self): trees = [ TreeNode.read(["((a,b),(c,d),(e,f));"]), TreeNode.read(["(a,(c,d),b,(e,f));"]), TreeNode.read(["((c,d),(e,f),b);"]), TreeNode.read(["(a,(c,d),(e,f));"])] trees = majority_rule(trees) self.assertEqual(len(trees), 4) for tree in trees: self.assertIs(type(tree), TreeNode) exp = set([ frozenset(['a']), frozenset(['b']), frozenset([None, 'c', 'd']), frozenset([None, 'e', 'f'])]) obs = set([frozenset([n.name for n in t.traverse()]) for t in trees]) self.assertEqual(obs, exp) def test_majority_rule_tree_node_class(self): class TreeNodeSubclass(TreeNode): pass trees = [ TreeNode.read(["((a,b),(c,d),(e,f));"]), TreeNode.read(["(a,(c,d),b,(e,f));"]), TreeNode.read(["((c,d),(e,f),b);"]), TreeNode.read(["(a,(c,d),(e,f));"])] trees = majority_rule(trees, tree_node_class=TreeNodeSubclass) self.assertEqual(len(trees), 4) for tree in trees: self.assertIs(type(tree), TreeNodeSubclass) exp = set([ frozenset(['a']), frozenset(['b']), frozenset([None, 'c', 'd']), frozenset([None, 'e', 'f'])]) obs = set([frozenset([n.name for n in t.traverse()]) for t in trees]) self.assertEqual(obs, exp) def test_walk_clades(self): trees = [ TreeNode.read(["((A,B),(D,E));"]), TreeNode.read(["((A,B),(D,(E,X)));"])] exp_clades = [ (frozenset(['A']), 2.0), (frozenset(['B']), 2.0), (frozenset(['A', 'B']), 2.0), (frozenset(['D', 'E']), 1.0), (frozenset(['D', 'E', 'A', 'B']), 1.0), (frozenset(['D']), 2.0), (frozenset(['E']), 2.0), (frozenset(['X']), 1.0), (frozenset(['E', 'X']), 1.0), (frozenset(['D', 'E', 'X']), 1.0), (frozenset(['A', 'B', 'D', 'E', 'X']), 1.0)] exp_lengths_nolength = { frozenset(['A']): None, frozenset(['B']): None, frozenset(['A', 'B']): None, frozenset(['D', 'E']): None, frozenset(['D', 'E', 'A', 'B']): None, frozenset(['D']): None, frozenset(['E']): None, frozenset(['X']): None, frozenset(['E', 'X']): None, frozenset(['D', 'E', 'X']): None, frozenset(['A', 'B', 'D', 'E', 'X']): None} exp_lengths = { frozenset(['A']): 2.0, frozenset(['B']): 2.0, frozenset(['A', 'B']): 2.0, frozenset(['D', 'E']): 1.0, frozenset(['D', 'E', 'A', 'B']): 1.0, frozenset(['D']): 2.0, frozenset(['E']): 2.0, frozenset(['X']): 1.0, frozenset(['E', 'X']): 1.0, frozenset(['D', 'E', 'X']): 1.0, frozenset(['A', 'B', 'D', 'E', 'X']): 1.0} obs_clades, obs_lengths = _walk_clades(trees, np.ones(len(trees))) self.assertEqual(set(obs_clades), set(exp_clades)) self.assertEqual(obs_lengths, exp_lengths_nolength) for t in trees: for n in t.traverse(include_self=True): n.length = 2.0 obs_clades, obs_lengths = _walk_clades(trees, np.ones(len(trees))) self.assertEqual(set(obs_clades), set(exp_clades)) self.assertEqual(obs_lengths, exp_lengths) def test_filter_clades(self): clade_counts = [(frozenset(['A', 'B']), 8), (frozenset(['A', 'C']), 7), (frozenset(['A']), 6), (frozenset(['B']), 5)] obs = _filter_clades(clade_counts, 2) exp = {frozenset(['A', 'B']): 8, frozenset(['A']): 6, frozenset(['B']): 5} self.assertEqual(obs, exp) clade_counts = [(frozenset(['A']), 8), (frozenset(['B']), 7), (frozenset(['C']), 7), (frozenset(['A', 'B']), 6), (frozenset(['A', 'B', 'C']), 5), (frozenset(['D']), 2)] obs = _filter_clades(clade_counts, 4) exp = {frozenset(['A']): 8, frozenset(['B']): 7, frozenset(['C']): 7, frozenset(['A', 'B']): 6, frozenset(['A', 'B', 'C']): 5} self.assertEqual(obs, exp) def test_build_trees(self): clade_counts = {frozenset(['A', 'B']): 6, frozenset(['A']): 7, frozenset(['B']): 8} edge_lengths = {frozenset(['A', 'B']): 1, frozenset(['A']): 2, frozenset(['B']): 3} tree = _build_trees(clade_counts, edge_lengths, 'foo', TreeNode)[0] self.assertEqual(tree.foo, 6) tree_foos = set([c.foo for c in tree.children]) tree_lens = set([c.length for c in tree.children]) self.assertEqual(tree_foos, set([7, 8])) self.assertEqual(tree_lens, set([2, 3])) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/test_me.py000066400000000000000000002515401520735541300236040ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main from heapq import heapify import numpy as np import numpy.testing as npt from skbio import DistanceMatrix, TreeNode from skbio.util import get_data_path from skbio.tree._me import ( gme, bme, nni, _to_treenode, _from_treenode, _root_from_treenode, _insert_taxon_treenode, _avgdist_matrix_naive, _avgdist_taxon_naive, _swap_branches_treenode, _swap_branches, ) from skbio.tree._c_me import ( _preorder, _postorder, _calc_tacts, _calc_sizes, _calc_deeps, _calc_pairs, _insert_taxon, _avgdist_matrix, _bal_avgdist_matrix, _avgdist_taxon, _avgdist_taxon_c, _bal_avgdist_taxon, _bal_avgdist_taxon_c, _avgdist_d2_insert, _bal_avgdist_insert, _ols_lengths, _ols_lengths_d2, _bal_lengths, _ols_min_branch_d2, _bal_min_branch, _bal_min_branch_p, _avgdist_swap, _bal_avgdist_swap, _ols_all_swaps, _ols_corner_swaps, _bal_all_swaps, _bal_insert_plan, _bal_avgdist_chunk, _bal_update_spine, _bal_avgdist_nest, _bal_avgdist_flat, ) def _check_tree(tree, n=None): """Check the integrity of an array-based tree structure. A tree is represented by a 2D integer array of four columns: 0. Left child index, or 0 if a tip. 1. Right child index, or taxon index if a tip. 2. Parent index, or 0 if root. 3. Sibling index, or 0 if root. """ if n is None: n = tree.shape[0] for i in range(n): left, right = tree[i, 0], tree[i, 1] if left == 0: assert i == 0 or right != 0 else: assert tree[left, 2] == tree[right, 2] == i assert tree[left, 3] == right assert tree[right, 3] == left def _half_adm(adm, order, n=None): """Replace the invalid half of an average distance matrix with zero. A cell [i, j] is filled only when i < j in preorder traversal. """ if n is None: n = adm.shape[0] for i in range(n): for j in range(i + 1, n): adm[order[j], order[i]] = 0 def _halve_adm(adm, tree, n=None): """Replace the invalid half of an average distance matrix with zero. This helper function is useful in the tests of `_bal_avgdist_insert_p`, which inserts a new taxon into an existing tree under the balanced framework. This algorithm has been improved to fill only half of the matrix. Specifically, only ancestor-descendant pairs and right-left pairs are filled. In other words, only late-early pairs in postorder are filled. This function replaces early-late pairs with zero, just to mimic the output of `_bal_avgdist_insert_p`. """ shape = adm.shape if n is None else (n, n) for i, j in np.ndindex(*shape): if tree[i, 7] < tree[j, 7]: adm[i, j] = 0 class MeTests(TestCase): def setUp(self): # Example 1 # This newick string was confirmed against http://www.trex.uqam.ca/ which # generated the following (isomorphic) newick string: # (d:2.0000,e:1.0000,(c:4.0000,(a:2.0000,b:3.0000):3.0000):2.0000); # /-b # -a-------| # | /-c # \--------| # | /-e # \--------| # \-d self.dm1 = np.array([ [0, 5, 9, 9, 8], [5, 0, 10, 10, 9], [9, 10, 0, 8, 7], [9, 10, 8, 0, 3], [8, 9, 7, 3, 0], ], dtype=float) self.taxa1 = list("abcde") self.nwk1 = "(b:3.0,(c:4.0,(e:1.0,d:2.0):2.0):3.0)a:2.0;" self.tree1 = np.array([ [1, 2, 0, 0], # 0: a (root) [0, 1, 0, 2], # 1: b [3, 4, 0, 1], # 2: (c,(e,d)) [0, 2, 2, 4], # 3: c [5, 6, 2, 3], # 4: (e,d) [0, 4, 4, 6], # 5: e [0, 3, 4, 5], # 6: d ]) self.lens1 = np.array([2, 3, 3, 4, 2, 1, 2], dtype=float) # preorder and postorder and indices for reverse mapping self.preodr1 = np.array([0, 1, 2, 3, 4, 5, 6]) self.preidx1 = np.array([0, 1, 2, 3, 4, 5, 6]) self.posodr1 = np.array([1, 3, 5, 6, 4, 2, 0]) self.posidx1 = np.array([6, 0, 5, 1, 4, 2, 3]) # per-node information # number of descending tips (i.e., taxa) (incl. self) self.tacts1 = np.array([4, 1, 3, 1, 2, 1, 1]) # number of descending nodes (incl. self) self.sizes1 = np.array([7, 1, 5, 1, 3, 1, 1]) # number of branches to root (i.e., depth) self.deeps1 = np.array([0, 1, 1, 2, 2, 3, 3]) # number of ancestor-descendant pairs self.pairs1 = np.array([12, 0, 6, 0, 2, 0, 0]) # An unfinished tree for example 1 (missing e) # /-b # -a-------| # | /-c # \--------| # \-d self.nwk1m1 = "(b:3.0,(c:4.0,d:4.0):3.0)a:2.0;" self.tree1m1 = np.array([ [1, 2, 0, 0], # 0: a (root) [0, 1, 0, 2], # 1: b [3, 4, 0, 1], # 2: (c,d) [0, 2, 2, 4], # 3: c [0, 3, 2, 3], # 4: d [0, 0, 0, 0], # 5: empty [0, 0, 0, 0], # 6: empty ]) self.preodr1m1 = np.array([0, 1, 2, 3, 4, 0, 0]) self.preidx1m1 = np.array([0, 1, 2, 3, 4, 0, 0]) self.posodr1m1 = np.array([1, 3, 4, 2, 0, 0, 0]) self.posidx1m1 = np.array([4, 0, 3, 1, 2, 0, 0]) self.tacts1m1 = np.array([3, 1, 2, 1, 1, 0, 0]) self.sizes1m1 = np.array([5, 1, 3, 1, 1, 0, 0]) self.deeps1m1 = np.array([0, 1, 1, 2, 2, 0, 0]) self.pairs1m1 = np.array([6, 0, 2, 0, 0, 0, 0]) # An alternative tree for example 1 (less ladder-like) # /-b # /--------| # | \-d # -a-------| # | /-e # \--------| # \-c self.nwk1v2 = "((b,d),(e,c))a;" self.tree1v2 = np.array([ [1, 2, 0, 0], # 0: a (root) [3, 4, 0, 2], # 1: (b,d) [5, 6, 0, 1], # 2: (e,c) [0, 1, 1, 4], # 3: b [0, 3, 1, 3], # 4: d [0, 4, 2, 6], # 5: e [0, 2, 2, 5], # 6: c ]) self.preodr1v2 = np.array([0, 1, 3, 4, 2, 5, 6]) self.preidx1v2 = np.array([0, 1, 4, 2, 3, 5, 6]) self.posodr1v2 = np.array([3, 4, 1, 5, 6, 2, 0]) self.posidx1v2 = np.array([6, 2, 5, 0, 1, 3, 4]) self.tacts1v2 = np.array([4, 2, 2, 1, 1, 1, 1]) self.sizes1v2 = np.array([7, 3, 3, 1, 1, 1, 1]) self.deeps1v2 = np.array([0, 1, 1, 2, 2, 2, 2]) self.pairs1v2 = np.array([10, 2, 2, 0, 0, 0, 0]) # Example 2 # This example was adopted from the Phylip manual: # https://phylipweb.github.io/phylip/doc/neighbor.html # /-Mouse # -Bovine--| # | /-Gibbon # \--------| # | /-Orang # \--------| # | /-Gorilla # \--------| # | /-Human # \--------| # \-Chimp self.dm2 = np.array([ [0.0000, 1.6866, 1.7198, 1.6606, 1.5243, 1.6043, 1.5905], [1.6866, 0.0000, 1.5232, 1.4841, 1.4465, 1.4389, 1.4629], [1.7198, 1.5232, 0.0000, 0.7115, 0.5958, 0.6179, 0.5583], [1.6606, 1.4841, 0.7115, 0.0000, 0.4631, 0.5061, 0.4710], [1.5243, 1.4465, 0.5958, 0.4631, 0.0000, 0.3484, 0.3083], [1.6043, 1.4389, 0.6179, 0.5061, 0.3484, 0.0000, 0.2692], [1.5905, 1.4629, 0.5583, 0.4710, 0.3083, 0.2692, 0.0000] ]) self.taxa2 = [ "Bovine", "Mouse", "Gibbon", "Orang", "Gorilla", "Chimp", "Human" ] self.nwk2 = ( "(Mouse:0.76891,(Gibbon:0.372875,(Orang:0.2705917,(Gorilla:0.1525417," "(Human:0.1240375,Chimp:0.1451625):0.0412083):0.03939583):0.0326305)" ":0.42026875)Bovine:0.91769;" ) self.tree2 = np.array([ [ 1, 2, 0, 0], [ 0, 1, 0, 2], [ 3, 4, 0, 1], [ 0, 2, 2, 4], [ 5, 6, 2, 3], [ 0, 3, 4, 6], [ 7, 8, 4, 5], [ 0, 4, 6, 8], [ 9, 10, 6, 7], [ 0, 6, 8, 10], [ 0, 5, 8, 9], ]) self.lens2 = np.array([ 0.91769, 0.76891, 0.42026875, 0.372875, 0.0326305, 0.2705917, 0.03939583, 0.1525417, 0.0412083, 0.1240375, 0.1451625, ]) self.preodr2 = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) self.preidx2 = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) self.posodr2 = np.array([1, 3, 5, 7, 9, 10, 8, 6, 4, 2, 0]) self.posidx2 = np.array([10, 0, 9, 1, 8, 2, 7, 3, 6, 4, 5]) self.tacts2 = np.array([6, 1, 5, 1, 4, 1, 3, 1, 2, 1, 1]) self.sizes2 = np.array([11, 1, 9, 1, 7, 1, 5, 1, 3, 1, 1]) self.deeps2 = np.array([0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5]) self.pairs2 = np.array([30, 0, 20, 0, 12, 0, 6, 0, 2, 0, 0]) # Example 3 # This example uses the same distance matrix as example 2, but with simplified # taxon names and different (less ladder-like) tree topology. # /-d # /--------| # /--------| \-c # | | # -a-------| \-e # | # | /-b # \--------| # \-f self.dm3 = self.dm2.copy() self.taxa3 = list("abcdefg") self.nwk3 = "(((d,c),e),(b,f))a;" self.tree3 = np.array([ [1, 2, 0, 0], # 0, root (a) [3, 4, 0, 2], # 1, ((d,c),e) [5, 6, 0, 1], # 2, (b,f) [7, 8, 1, 4], # 3, (d,c) [0, 4, 1, 3], # 4, e [0, 1, 2, 6], # 5, b [0, 5, 2, 5], # 6, f [0, 3, 3, 8], # 7, d [0, 2, 3, 7], # 8, c [0, 0, 0, 0], # reserved for g's link [0, 0, 0, 0], # reserved for g ]) self.preodr3 = np.array([0, 1, 3, 7, 8, 4, 2, 5, 6, 0, 0]) self.preidx3 = np.array([0, 1, 6, 2, 5, 7, 8, 3, 4, 0, 0]) self.posodr3 = np.array([7, 8, 3, 4, 1, 5, 6, 2, 0, 0, 0]) self.posidx3 = np.array([8, 4, 7, 2, 3, 5, 6, 0, 1, 0, 0]) self.tacts3 = np.array([5, 3, 2, 2, 1, 1, 1, 1, 1, 0, 0]) self.sizes3 = np.array([9, 5, 3, 3, 1, 1, 1, 1, 1, 0, 0]) self.deeps3 = np.array([0, 1, 1, 2, 2, 2, 2, 3, 3, 0, 0]) self.pairs3 = np.array([16, 6, 2, 2, 0, 0, 0, 0, 0, 0, 0]) # Example 4 # This example is based on example 3, with the last taxon g inserted as the # sibling of e. # /-d # /--------| # | \-c # /--------| # | | /-e # | \--------| # -a-------| \-g # | # | /-b # \--------| # \-f self.dm4 = self.dm3.copy() self.taxa4 = self.taxa3.copy() self.nwk4 = "(((d,c),(e,g)),(b,f))a;" self.tree4 = np.array([ [ 1, 2, 0, 0], # 0, root (a) [ 3, 9, 0, 2], # 1, ((d,c),(e,g)) [ 5, 6, 0, 1], # 2, (b,f) [ 7, 8, 1, 9], # 3, (d,c) [ 0, 4, 9, 10], # 4, e [ 0, 1, 2, 6], # 5, b [ 0, 5, 2, 5], # 6, f [ 0, 3, 3, 8], # 7, d [ 0, 2, 3, 7], # 8, c [ 4, 10, 1, 3], # 9, (e,g) [ 0, 6, 9, 4], # 10, g ]) self.preodr4 = np.array([0, 1, 3, 7, 8, 9, 4, 10, 2, 5, 6]) self.preidx4 = np.array([0, 1, 8, 2, 6, 9, 10, 3, 4, 5, 7]) self.posodr4 = np.array([7, 8, 3, 4, 10, 9, 1, 5, 6, 2, 0]) self.posidx4 = np.array([10, 6, 9, 2, 3, 7, 8, 0, 1, 5, 4]) self.tacts4 = np.array([6, 4, 2, 2, 1, 1, 1, 1, 1, 2, 1]) self.sizes4 = np.array([11, 7, 3, 3, 1, 1, 1, 1, 1, 3, 1]) self.deeps4 = np.array([0, 1, 1, 2, 3, 2, 2, 3, 3, 2, 3]) self.pairs4 = np.array([22, 10, 2, 2, 0, 0, 0, 0, 0, 2, 0]) # Example 5 # This dm can yield negative branch lengths. self.dm5 = np.array([ [0, 5, 9, 9, 800], [5, 0, 10, 10, 9], [9, 10, 0, 8, 7], [9, 10, 8, 0, 3], [800, 9, 7, 3, 0], ], dtype=float) self.taxa5 = list("abcde") self.nwk5 = "(b:-129,(c:-95,(d:-130,e:133):101):102,a:134);" # Example 6 # This is a relatively large example, used to demonstrate the parallelizaton # planning process in BME. self.nwk6 = "(((3,(5,6)4)2,(((10,11)9,(13,14)12)8,(16,17)15)7)1,18)0;" # /-3 # /2-------| # | | /-5 # | \4-------| # | \-6 # | # /1-------| /-10 # | | /9-------| # | | | \-11 # | | /8-------| # | | | | /-13 # | | | \12------| # -0-------| \7-------| \-14 # | | # | | /-16 # | \15------| # | \-17 # | # \-18 def test_gme(self): """The entire tree building workflow.""" obs = gme(DistanceMatrix(self.dm1, self.taxa1)) exp = TreeNode.read([self.nwk1]) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) obs = gme(DistanceMatrix(self.dm2, self.taxa2)) exp = TreeNode.read([self.nwk2]) self.assertEqual(obs.compare_rfd(exp), 0) # float32 obs = gme(DistanceMatrix(self.dm2.astype("float32"), self.taxa2)) exp = TreeNode.read([self.nwk2]) self.assertEqual(obs.compare_rfd(exp), 0) # non-contiguous data obs = gme(DistanceMatrix(np.asfortranarray(self.dm2), self.taxa2)) exp = TreeNode.read([self.nwk2]) self.assertEqual(obs.compare_rfd(exp), 0) # clip to zero dm = DistanceMatrix(self.dm5, self.taxa5) obs = gme(dm, neg_as_zero=False) exp = TreeNode.read([self.nwk5]) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) for taxon in ("b", "c", "d"): self.assertTrue(obs.find(taxon).length < 0) obs = gme(dm, neg_as_zero=True) for taxon in ("b", "c", "d"): self.assertEqual(obs.find(taxon).length, 0) def test_gme_condensed(self): """The entire tree building workflow.""" obs = gme(DistanceMatrix(self.dm1, self.taxa1, condensed=True)) exp = TreeNode.read([self.nwk1]) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) obs = gme(DistanceMatrix(self.dm2, self.taxa2, condensed=True)) exp = TreeNode.read([self.nwk2]) self.assertEqual(obs.compare_rfd(exp), 0) # clip to zero dm = DistanceMatrix(self.dm5, self.taxa5, condensed=True) obs = gme(dm, neg_as_zero=False) exp = TreeNode.read([self.nwk5]) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) for taxon in ("b", "c", "d"): self.assertTrue(obs.find(taxon).length < 0) obs = gme(dm, neg_as_zero=True) for taxon in ("b", "c", "d"): self.assertEqual(obs.find(taxon).length, 0) def test_gme_real(self): """Test on a real dataset with 100 taxa.""" dm = DistanceMatrix.read(get_data_path("mp100.phy")) obs = gme(dm, neg_as_zero=False) exp = TreeNode.read(get_data_path("mp100.gme.nwk")) self.assertEqual(obs.compare_rfd(exp), 0.0) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) def test_bme(self): """The entire tree building workflow.""" # simple integer example obs = bme(DistanceMatrix(self.dm1, self.taxa1)) exp = TreeNode.read([self.nwk1]) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) # simple float example obs = bme(DistanceMatrix(self.dm2, self.taxa2)) exp = TreeNode.read([self.nwk2]) self.assertEqual(obs.compare_rfd(exp), 0) # float32 obs = bme(DistanceMatrix(self.dm2.astype("float32"), self.taxa2)) exp = TreeNode.read([self.nwk2]) self.assertEqual(obs.compare_rfd(exp), 0) # non-contiguous data obs = bme(DistanceMatrix(np.asfortranarray(self.dm2), self.taxa2)) exp = TreeNode.read([self.nwk2]) self.assertEqual(obs.compare_rfd(exp), 0) # parallelization obs = bme(DistanceMatrix(self.dm2, self.taxa2), parallel=True) exp = TreeNode.read([self.nwk2]) self.assertEqual(obs.compare_rfd(exp), 0) # clip to zero dm = DistanceMatrix(self.dm5, self.taxa5) obs = bme(dm, neg_as_zero=False) for taxon in ("b", "c", "d"): self.assertTrue(obs.find(taxon).length < 0) obs = bme(dm, neg_as_zero=True) for taxon in ("b", "c", "d"): self.assertEqual(obs.find(taxon).length, 0) def test_bme_condensed(self): """The entire tree building workflow.""" obs = bme(DistanceMatrix(self.dm1, self.taxa1, condensed=True)) exp = TreeNode.read([self.nwk1]) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) obs = bme(DistanceMatrix(self.dm2, self.taxa2, condensed=True)) exp = TreeNode.read([self.nwk2]) self.assertEqual(obs.compare_rfd(exp), 0) # clip to zero dm = DistanceMatrix(self.dm5, self.taxa5, condensed=True) obs = bme(dm, neg_as_zero=False) for taxon in ("b", "c", "d"): self.assertTrue(obs.find(taxon).length < 0) obs = bme(dm, neg_as_zero=True) for taxon in ("b", "c", "d"): self.assertEqual(obs.find(taxon).length, 0) def test_bme_real(self): """Test on a real dataset with 100 taxa.""" dm = DistanceMatrix.read(get_data_path("mp100.phy")) obs = bme(dm, neg_as_zero=False) exp = TreeNode.read(get_data_path("mp100.bme.nwk")) self.assertEqual(obs.compare_rfd(exp), 0.0) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) # disable parallelization (no effect, since tree is small) obs = bme(dm, neg_as_zero=False, parallel=False) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) # always enable parallelization obs = bme(dm, neg_as_zero=False, parallel=True) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) # specify a threshold for parallelization # (50 will not enter phase 3) obs = bme(dm, neg_as_zero=False, parallel=50) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) # (15 will enter phase 3) obs = bme(dm, neg_as_zero=False, parallel=15) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) def test_nni(self): """The entire tree rearrangement workflow.""" # Test if NNI can convert an incorrect tree into the groud truth tree. # Example 1: In this simple example, FastNNI and BNNI should produce the same # topology and branch lengths. tree = TreeNode.read([self.nwk1v2]) tree.append(TreeNode(tree.name, tree.length)) tree.name, tree.length = None, None dm = DistanceMatrix(self.dm1, self.taxa1) exp = TreeNode.read([self.nwk1]) exp.append(TreeNode(exp.name, exp.length)) exp.name, exp.length = None, None obs = nni(tree, dm, balanced=False) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) obs = nni(tree, dm, balanced=True) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) dm = DistanceMatrix(self.dm1.astype("float32"), self.taxa1) for balanced in True, False: obs = nni(tree, dm, balanced=balanced) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) # Example 4: The same, except for branch lengths. tree = TreeNode.read([self.nwk4]) tree.append(TreeNode(tree.name, tree.length)) tree.name, tree.length = None, None dm = DistanceMatrix(self.dm4, self.taxa4) exp = TreeNode.read([self.nwk2]) exp.append(TreeNode(exp.name, exp.length)) exp.name, exp.length = None, None taxonmap = dict(zip(self.taxa2, self.taxa4)) for tip in exp.tips(): tip.name = taxonmap[tip.name] obs = nni(tree, dm, balanced=False) self.assertEqual(obs.compare_rfd(exp), 0) obs = nni(tree, dm, balanced=True) self.assertEqual(obs.compare_rfd(exp), 0) # clip to zero dm = DistanceMatrix(self.dm5, self.taxa5) tree = TreeNode.read(["(((a,b),d),(c,e));"]) obs = nni(tree, dm, balanced=False, neg_as_zero=False) exp = TreeNode.read([self.nwk5]) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) for taxon in ("b", "c", "d"): self.assertTrue(obs.find(taxon).length < 0) obs = nni(tree, dm, balanced=False, neg_as_zero=True) for taxon in ("b", "c", "d"): self.assertEqual(obs.find(taxon).length, 0) def test_nni_condensed(self): """The entire tree rearrangement workflow.""" # Test if NNI can convert an incorrect tree into the groud truth tree. # Example 1: In this simple example, FastNNI and BNNI should produce the same # topology and branch lengths. tree = TreeNode.read([self.nwk1v2]) tree.append(TreeNode(tree.name, tree.length)) tree.name, tree.length = None, None dm = DistanceMatrix(self.dm1, self.taxa1, condensed=True) exp = TreeNode.read([self.nwk1]) exp.append(TreeNode(exp.name, exp.length)) exp.name, exp.length = None, None obs = nni(tree, dm, balanced=False) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) obs = nni(tree, dm, balanced=True) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) # Example 4: The same, except for branch lengths. tree = TreeNode.read([self.nwk4]) tree.append(TreeNode(tree.name, tree.length)) tree.name, tree.length = None, None dm = DistanceMatrix(self.dm4, self.taxa4, condensed=True) exp = TreeNode.read([self.nwk2]) exp.append(TreeNode(exp.name, exp.length)) exp.name, exp.length = None, None taxonmap = dict(zip(self.taxa2, self.taxa4)) for tip in exp.tips(): tip.name = taxonmap[tip.name] obs = nni(tree, dm, balanced=False) self.assertEqual(obs.compare_rfd(exp), 0) obs = nni(tree, dm, balanced=True) self.assertEqual(obs.compare_rfd(exp), 0) # clip to zero dm = DistanceMatrix(self.dm5, self.taxa5, condensed=True) tree = TreeNode.read(["(((a,b),d),(c,e));"]) obs = nni(tree, dm, balanced=False, neg_as_zero=False) exp = TreeNode.read([self.nwk5]) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) for taxon in ("b", "c", "d"): self.assertTrue(obs.find(taxon).length < 0) obs = nni(tree, dm, balanced=False, neg_as_zero=True) for taxon in ("b", "c", "d"): self.assertEqual(obs.find(taxon).length, 0) def test_nni_real(self): """Test on a real dataset with 100 taxa.""" # FastNNI tree = TreeNode.read(get_data_path("mp100.gme.nwk")) dm = DistanceMatrix.read(get_data_path("mp100.phy")) obs = nni(tree, dm, balanced=False, neg_as_zero=False) exp = TreeNode.read(get_data_path("mp100.gme.nni.nwk")) self.assertNotEqual(obs.compare_rfd(tree), 0.0) self.assertEqual(obs.compare_rfd(exp), 0.0) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) # BNNI tree = TreeNode.read(get_data_path("mp100.bme.nwk")) dm = DistanceMatrix.read(get_data_path("mp100.phy")) obs = nni(tree, dm, balanced=True, neg_as_zero=False) exp = TreeNode.read(get_data_path("mp100.bme.nni.nwk")) self.assertNotEqual(obs.compare_rfd(tree), 0.0) self.assertEqual(obs.compare_rfd(exp), 0.0) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) def test_to_treenode(self): """Convert an array-based tree structure into a TreeNode object.""" # entire tree obs = _to_treenode(self.tree1, self.taxa1) exp = TreeNode.read([self.nwk1]) self.assertEqual(obs.compare_rfd(exp), 0) # with branch lengths obs = _to_treenode(self.tree1, self.taxa1, self.lens1) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) # unroot obs = _to_treenode(self.tree1, self.taxa1, self.lens1, unroot=True) exp = TreeNode.read(["(b:3.0,(c:4.0,(e:1.0,d:2.0):2.0):3.0,a:2.0);"]) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) # incomplete tree obs = _to_treenode(self.tree1m1, self.taxa1) exp = TreeNode.read([self.nwk1m1]) self.assertEqual(obs.compare_rfd(exp), 0) # another example obs = _to_treenode(self.tree2, self.taxa2, self.lens2) exp = TreeNode.read([self.nwk2]) self.assertEqual(obs.compare_rfd(exp), 0) self.assertAlmostEqual(obs.compare_cophenet(exp, ignore_self=True), 0) def test_from_treenode(self): """Convert a TreeNode object into an array-based tree structure.""" # a complete tree obj = TreeNode.read([self.nwk1]) taxmap = {x: i for i, x in enumerate(self.taxa1)} n = len(taxmap) * 2 - 3 obs = np.empty((n, 4), dtype=int) num = _from_treenode(obj, taxmap, obs) self.assertEqual(num, n) # check if tree topology is correct _check_tree(obs) # check if nodes are in preorder stack = np.empty(n, dtype=int) _preorder(order := np.empty(n, dtype=int), obs, stack) npt.assert_array_equal(order, np.arange(n)) # check if tree topology matches expectation npt.assert_array_equal(obs, self.tree1) # an incomplete tree obj = TreeNode.read([self.nwk1m1]) num = _from_treenode(obj, taxmap, obs) self.assertEqual(num, n - 2) _check_tree(obs, n - 2) obs[-2:] = 0 # fill unused cells before comparison npt.assert_array_equal(obs, self.tree1m1) # start from index 2 _from_treenode(obj, taxmap, obs, pos=2) exp = np.array([[3, 4, 0, 0], [0, 1, 2, 4], [5, 6, 2, 3], [0, 2, 4, 6], [0, 3, 4, 5]]) npt.assert_array_equal(obs[2:], exp) # non-binary tree obj = TreeNode.read(["((b,c,d),e)a;"]) with self.assertRaises(ValueError) as cm: _from_treenode(obj, taxmap, obs) self.assertEqual(str(cm.exception), "Tree is not strictly bifurcating.") # another example obj = TreeNode.read([self.nwk3]) taxmap = {x: i for i, x in enumerate(self.taxa3)} n = len(taxmap) * 2 - 3 obs = np.empty((n, 4), dtype=int) _from_treenode(obj, taxmap, obs) _check_tree(obs, n - 2) # note: self.tree3 is not in preorder so we can't directly compare def test_root_from_treenode(self): """Convert TreeNode into tree array rooted at 1st taxon.""" # Example 1: first move the root taxon ("a") to the child place, making the # tree trifurcating. This is the typical output of tree-building methods. obj = TreeNode.read([self.nwk1]) obj.append(TreeNode(obj.name)) obj.name = None # Now convert to array to see if it matches the reference. obs = _root_from_treenode(obj, self.taxa1) _check_tree(obs) npt.assert_array_equal(obs, self.tree1) # Test a different order of taxa. This time, taxon "c" will become the root. taxa = list("cadeb") obs = _root_from_treenode(obj, taxa) exp = np.array([ [1, 4, 0, 0], # c [2, 3, 0, 4], # (e,d) [0, 3, 1, 3], # e [0, 2, 1, 2], # d [5, 6, 0, 1], # (b,a) [0, 4, 4, 6], # b [0, 1, 4, 5], # a ]) _check_tree(obs) npt.assert_array_equal(obs, exp) # Root the tree at an internal branch and test to recover the same result. obj = obj.find("e").parent obj = obj.root_at(above=True) self.assertEqual(len(obj.children), 2) obs = _root_from_treenode(obj, self.taxa1) _check_tree(obs) npt.assert_array_equal(obs, self.tree1) # Example 4: Test all possible roots (taxa). obj = TreeNode.read([self.nwk4]) obj.append(TreeNode(obj.name)) obj.name = None taxa = self.taxa4 m = len(taxa) n = m * 2 - 3 for i in range(m): # move target taxon to the first place taxon_ = taxa[i] taxa_ = [taxon_] + taxa[:i] + taxa[i + 1:] # use the algorithm to generate the array obs = _root_from_treenode(obj, taxa_) _check_tree(obs) # root the TreeNode object instead (slower) and generate the array obj_ = obj.root_at(taxon_) obj_.prune() taxmap = {x: i for i, x in enumerate(taxa_)} _from_treenode(obj_, taxmap, exp := np.empty((n, 4), dtype=int)) npt.assert_array_equal(obs, exp) # non-binary trees taxa = list("abcde") nwks = [ "((a,b,c),(d,e));", # internal node has 3 children "((a),b,(c,(d,e)));", # internal node has 1 child "(((b,c),((d,e),a)));", # root has 1 child "((a,b),c,d,e);", # root has 4 children ] for nwk in nwks: obj = TreeNode.read([nwk]) self.assertRaises(ValueError, _root_from_treenode, obj, taxa) def test_preorder(self): """Perform preorder traversal.""" n = self.tree1.shape[0] stack = np.full(n, 0) # entire tree _preorder(obs := np.full(n, 0), self.tree1, stack) npt.assert_array_equal(obs, self.preodr1) # given clade _preorder(obs := np.full(n, 0), self.tree1, stack, start=2) exp = np.array([2, 3, 4, 5, 6, 0, 0]) npt.assert_array_equal(obs, exp) # alternative tree _preorder(obs := np.full(n, 0), self.tree1v2, stack) npt.assert_array_equal(obs, self.preodr1v2) # another example stack = np.full(n := self.tree3.shape[0], 0) _preorder(obs := np.full(n, 0), self.tree3, stack) npt.assert_array_equal(obs, self.preodr3) def test_postorder(self): """Perform postorder traversal.""" n = self.tree1.shape[0] stack = np.full(n, 0) # entire tree _postorder(obs := np.full(n, 0), self.tree1, stack) npt.assert_array_equal(obs, self.posodr1) # given clade _postorder(obs := np.full(n, 0), self.tree1, stack, start=2) exp = np.array([3, 5, 6, 4, 2, 0, 0]) npt.assert_array_equal(obs, exp) # alternative tree _postorder(obs := np.full(n, 0), self.tree1v2, stack) npt.assert_array_equal(obs, self.posodr1v2) # another example stack = np.full(n := self.tree3.shape[0], 0) _postorder(obs := np.full(n, 0), self.tree3, stack) npt.assert_array_equal(obs, self.posodr3) def test_insert_taxon_treenode(self): """Insert a taxon between a target node and its parent.""" # insert into a regular branch obs = TreeNode.read([self.nwk1m1]) _insert_taxon_treenode("e", obs.find("d"), obs) exp = TreeNode.read([self.nwk1]) self.assertEqual(obs.compare_rfd(exp), 0) # insert into the root branch obs = TreeNode.read([self.nwk1m1]) _insert_taxon_treenode("e", obs, obs) exp = TreeNode.read(["((b,(c,d)),e)a;"]) self.assertEqual(obs.compare_rfd(exp), 0) def test_insert_taxon(self): """Insert a taxon between a target node and its parent.""" # insert taxon e (4) above d (order=4, size=1) obs = self.tree1m1.copy(), self.preodr1m1.copy() _insert_taxon(4, 4, 1, *obs) exp = np.array([ [1, 2, 0, 0], [0, 1, 0, 2], [3, 5, 0, 1], [0, 2, 2, 5], [0, 3, 5, 6], [4, 6, 2, 3], [0, 4, 5, 4], ]), np.array([ 0, 1, 2, 3, 5, 4, 6 ]) for o, e in zip(obs, exp): npt.assert_array_equal(o, e) # insert taxon e (4) above b (order=1, size=1) obs = self.tree1m1.copy(), self.preodr1m1.copy() _insert_taxon(4, 1, 1, *obs) exp = np.array([ [5, 2, 0, 0], [0, 1, 5, 6], [3, 4, 0, 5], [0, 2, 2, 4], [0, 3, 2, 3], [1, 6, 0, 2], [0, 4, 5, 1], ]), np.array([ 0, 5, 1, 6, 2, 3, 4 ]) for o, e in zip(obs, exp): npt.assert_array_equal(o, e) # insert taxon e (4) above (c,d) (order=2, size=3) obs = self.tree1m1.copy(), self.preodr1m1.copy() _insert_taxon(4, 2, 3, *obs) exp = np.array([ [1, 5, 0, 0], [0, 1, 0, 5], [3, 4, 5, 6], [0, 2, 2, 4], [0, 3, 2, 3], [2, 6, 0, 1], [0, 4, 5, 2], ]), np.array([ 0, 1, 5, 2, 3, 4, 6 ]) for o, e in zip(obs, exp): npt.assert_array_equal(o, e) # insert taxon e (4) into the root branch (idx=0, size=5) obs = self.tree1m1.copy(), self.preodr1m1.copy() _insert_taxon(4, 0, 5, *obs) exp = np.array([ [5, 6, 0, 0], [0, 1, 5, 2], [3, 4, 5, 1], [0, 2, 2, 4], [0, 3, 2, 3], [1, 2, 0, 6], [0, 4, 0, 5], ]), np.array([ 0, 5, 1, 2, 3, 4, 6 ]) for o, e in zip(obs, exp): npt.assert_array_equal(o, e) # another example: all possible insertions taxa, tree, order, sizes = self.taxa3, self.tree3, self.preodr3, self.sizes3 n = tree.shape[0] - 2 k = len(taxa) - 1 taxamap = {} for node in self.preodr3[:-2][::-1]: if tree[node, 0] == 0: taxamap[node] = [taxa[tree[node, 1]]] else: taxamap[node] = taxamap[tree[node, 0]] + taxamap[tree[node, 1]] obj = TreeNode.read([self.nwk3]) for i in range(n): tag = order[i] _insert_taxon(k, i, sizes[tag], tree_ := tree.copy(), order.copy()) obs = _to_treenode(tree_, taxa) exp = obj.copy() _insert_taxon_treenode("g", exp.lca(taxamap[tag]), exp) self.assertEqual(obs.compare_rfd(exp), 0) def test_avgdist_matrix_naive(self): """Calculate an average distance matrix using a naive method.""" # Test if the algorithm reproduces the manually calculated result. n = self.tree1.shape[0] obs = np.zeros((n, n), dtype=float) _avgdist_matrix_naive(obs, self.dm1, self.tree1, self.preodr1, self.tacts1) exp = np.array([ [ 0. , 5. , 8.667, 9. , 8.5 , 8. , 9. ], [ 5. , 0. , 9.667, 10. , 9.5 , 9. , 10. ], [ 8.667, 9.667, 0. , 9.5 , 9. , 8.5 , 9.5 ], [ 9. , 10. , 9.5 , 0. , 7.5 , 7. , 8. ], [ 8.5 , 9.5 , 9. , 7.5 , 0. , 8. , 9. ], [ 8. , 9. , 8.5 , 7. , 8. , 0. , 3. ], [ 9. , 10. , 9.5 , 8. , 9. , 3. , 0. ], ]) npt.assert_array_equal(obs.round(3), exp) # incomplete tree obs = np.zeros((n, n), dtype=float) _avgdist_matrix_naive( obs, self.dm1, self.tree1m1, self.preodr1m1, self.tacts1m1 ) exp = np.array([ [ 0. , 5. , 9. , 9. , 9. , 0. , 0. ], [ 5. , 0. , 10. , 10. , 10. , 0. , 0. ], [ 9. , 10. , 0. , 9.5, 9.5, 0. , 0. ], [ 9. , 10. , 9.5, 0. , 8. , 0. , 0. ], [ 9. , 10. , 9.5, 8. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], ]) npt.assert_allclose(obs, exp) # alternative tree obs = np.zeros((n, n), dtype=float) _avgdist_matrix_naive( obs, self.dm1, self.tree1v2, self.preodr1v2, self.tacts1v2 ) exp = np.array([ [ 0. , 7. , 8.5 , 5. , 9. , 8. , 9. ], [ 7. , 0. , 7.5 , 8. , 6.67, 6. , 9. ], [ 8.5 , 7.5 , 0. , 9.5 , 5.5 , 6.67, 9. ], [ 5. , 8. , 9.5 , 0. , 10. , 9. , 10. ], [ 9. , 6.67, 5.5 , 10. , 0. , 3. , 8. ], [ 8. , 6. , 6.67, 9. , 3. , 0. , 7. ], [ 9. , 9. , 9. , 10. , 8. , 7. , 0. ], ]) npt.assert_array_equal(obs.round(2), exp) def test_avgdist_matrix(self): """Calculate an average distance matrix.""" # Test if the algorithm produces the same result as the native method does. dm, tree, order, tacts = self.dm1, self.tree1, self.preodr1, self.tacts1 n = tree.shape[0] obs = np.zeros((n, n), dtype=float) _avgdist_matrix(obs, dm, tree, order, tacts) exp = np.zeros((n, n), dtype=float) _avgdist_matrix_naive(exp, dm, tree, order, tacts) npt.assert_allclose(obs, exp) # make sure all cells are populated _avgdist_matrix(obs := np.full((n, n), np.nan), dm, tree, order, tacts) np.fill_diagonal(obs, 0) _avgdist_matrix_naive(exp := np.zeros((n, n)), dm, tree, order, tacts) npt.assert_allclose(obs, exp) # incomplete tree tree, order, tacts = self.tree1m1, self.preodr1m1, self.tacts1m1 _avgdist_matrix(obs := np.zeros((n, n)), dm, tree, order, tacts) _avgdist_matrix_naive(exp := np.zeros((n, n)), dm, tree, order, tacts) npt.assert_allclose(obs, exp) # example 1 v2 tree, order, tacts = self.tree1v2, self.preodr1v2, self.tacts1v2 _avgdist_matrix(obs := np.zeros((n, n)), dm, tree, order, tacts) _avgdist_matrix_naive(exp := np.zeros((n, n)), dm, tree, order, tacts) npt.assert_allclose(obs, exp) # example 2 (complete) dm, tree, order, tacts = self.dm2, self.tree2, self.preodr2, self.tacts2 n = tree.shape[0] _avgdist_matrix(obs := np.zeros((n, n)), dm, tree, order, tacts) _avgdist_matrix_naive(exp := np.zeros((n, n)), dm, tree, order, tacts) npt.assert_allclose(obs, exp) # example 3 (incomplete) dm, tree, order, tacts = self.dm3, self.tree3, self.preodr3, self.tacts3 n = tree.shape[0] _avgdist_matrix(obs := np.zeros((n, n)), dm, tree, order, tacts) _avgdist_matrix_naive(exp := np.zeros((n, n)), dm, tree, order, tacts) npt.assert_allclose(obs, exp) def test_bal_avgdist_matrix(self): """Calculate a balanced average distance matrix.""" dm, tree, order, sizes = self.dm1, self.tree1, self.preodr1, self.sizes1 n = sizes[0] _bal_avgdist_matrix(obs := np.zeros((n, n)), dm, tree, order, sizes) exp = np.array([ [ 0. , 5. , 8.75, 9. , 8.5 , 8. , 9. ], [ 5. , 0. , 9.75, 10. , 9.5 , 9. , 10. ], [ 8.75, 9.75, 0. , 9.5 , 9. , 8.5 , 9.5 ], [ 9. , 10. , 9.5 , 0. , 7.5 , 7. , 8. ], [ 8.5 , 9.5 , 9. , 7.5 , 0. , 7.75, 8.75], [ 8. , 9. , 8.5 , 7. , 7.75, 0. , 3. ], [ 9. , 10. , 9.5 , 8. , 8.75, 3. , 0. ], ]) npt.assert_allclose(obs, exp) _bal_avgdist_matrix(obs := np.full((n, n), np.nan), dm, tree, order, sizes) np.fill_diagonal(obs, 0) npt.assert_allclose(obs, exp) dm, tree, order, sizes = self.dm3, self.tree3, self.preodr3, self.sizes3 n = sizes[0] _bal_avgdist_matrix(obs := np.zeros((n, n)), dm, tree, order, sizes) exp = np.array([ [0. , 1.607, 1.645, 1.69 , 1.524, 1.687, 1.604, 1.661, 1.72 ], [1.607, 0. , 0.965, 1.362, 1.211, 1.475, 0.455, 1.328, 1.395], [1.645, 0.965, 0. , 1.033, 0.897, 1.581, 1.03 , 0.995, 1.071], [1.69 , 1.362, 1.033, 0. , 0.529, 1.504, 0.562, 0.895, 0.995], [1.524, 1.211, 0.897, 0.529, 0. , 1.446, 0.348, 0.463, 0.596], [1.687, 1.475, 1.581, 1.504, 1.446, 0. , 1.439, 1.484, 1.523], [1.604, 0.455, 1.03 , 0.562, 0.348, 1.439, 0. , 0.506, 0.618], [1.661, 1.328, 0.995, 0.895, 0.463, 1.484, 0.506, 0. , 0.712], [1.72 , 1.395, 1.071, 0.995, 0.596, 1.523, 0.618, 0.712, 0. ], ]) npt.assert_array_equal(obs.round(3), exp) def test_avgdist_taxon_naive(self): """Calculate taxon-to-subtree average distances using a naive method.""" # Test if the algorithm reproduces the manually calculated result. n = self.tree1.shape[0] taxon = self.dm1.shape[0] - 1 obs = np.zeros((2, n), dtype=float) _avgdist_taxon_naive( obs, taxon, self.dm1, self.tree1m1, self.preodr1m1, self.tacts1m1 ) exp = np.array([[6.333, 9. , 5. , 7. , 3. , 0. , 0. ], [8. , 6. , 8.5 , 6.667, 8. , 0. , 0. ]]) npt.assert_array_equal(obs.round(3), exp) def test_avgdist_taxon(self): """Calculate taxon-to-subtree average distances.""" # Test if the algorithm produces the same result as the naive method does. dm = self.dm1 taxon = dm.shape[0] - 1 tree, order, tacts = self.tree1m1, self.preodr1m1, self.tacts1m1 n = tree.shape[0] _avgdist_taxon(obs := np.zeros((2, n)), taxon, dm, tree, order, tacts) _avgdist_taxon_naive(exp := np.zeros((2, n)), taxon, dm, tree, order, tacts) npt.assert_allclose(obs, exp) # non-contiguous data dmf = np.asfortranarray(dm) _avgdist_taxon(obs := np.zeros((2, n)), taxon, dmf, tree, order, tacts) npt.assert_allclose(obs, exp) # contiguous function _avgdist_taxon_c(obs := np.zeros((2, n)), taxon, dm, tree, order, tacts) npt.assert_allclose(obs, exp) def test_bal_avgdist_taxon(self): """Calculate taxon-to-subtree balanced average distances.""" dm = self.dm1 tree, order = self.tree1m1, self.preodr1m1 k = dm.shape[0] - 1 n = tree.shape[0] obs = np.zeros((2, n)) _bal_avgdist_taxon(n - 2, k, dm, obs, tree, order) exp = np.array([[7. , 9. , 5. , 7. , 3. , 0. , 0. ], [8. , 6.5 , 8.5 , 5.75, 7.75, 0. , 0. ]]) npt.assert_allclose(obs, exp) # non-contiguous data _bal_avgdist_taxon(n - 2, k, np.asfortranarray(dm), obs, tree, order) npt.assert_allclose(obs, exp) # contiguous function _bal_avgdist_taxon_c(n - 2, k, dm, obs, tree, order) npt.assert_allclose(obs, exp) dm = self.dm3 tree, order = self.tree3, self.preodr3 k = dm.shape[0] - 1 n = tree.shape[0] obs = np.zeros((2, n)) _bal_avgdist_taxon(n - 2, k, dm, obs, tree, order) exp = np.array([[0.639, 0.411, 0.866, 0.515, 0.308, 1.463, 0.269, 0.471, 0.558, 0. , 0. ], [1.59 , 1.228, 1.001, 0.768, 0.871, 0.635, 1.232, 0.663, 0.62 , 0. , 0. ]]) npt.assert_array_equal(obs.round(3), exp) def test_avgdist_d2_insert(self): """Update distant-2 subtree average distances after taxon insertion.""" n = self.tree1.shape[0] taxon = self.dm1.shape[0] - 1 # The following values were taken from the full-scale distance matrix. ad2 = np.array([ [ 0. , 0. ], # 0: a (root) [10. , 5. ], # 1: b [10. , 9. ], # 2: (c,d) [ 8. , 9.5], # 3: c [ 8. , 9.5], # 4: d [ 0. , 0. ], # 5: empty [ 0. , 0. ], # 6: empty ]).T # Insert e as a sibling of d. This should recover tree1. target = 4 _avgdist_taxon( adk := np.zeros((2, n), dtype=float), taxon, self.dm1, self.tree1m1, self.preodr1m1, self.tacts1m1 ) _avgdist_d2_insert( obs := ad2.copy(), target, adk, self.tree1m1, self.preodr1m1, self.tacts1m1 ) # The following values were taken from the full-scale distance matrix. exp = np.array([ [0. , 0. ], # 0: a (root) [9.667, 5. ], # 1: b [9.667, 8.667], # 2: (c,(e,d)) [7.5 , 9.5 ], # 3: c [3. , 9. ], # 4: d [7.5 , 9. ], # 5: (e,d) [3. , 8. ], # 6: e ]).T npt.assert_array_equal(obs.round(3), exp) # another example: all possible insertions dm, tree, order, tacts = self.dm3, self.tree3, self.preodr3, self.tacts3 n = tree.shape[0] k = tacts[0] + 1 ran_ = np.arange(n) # get distant-2 values from the full matrix _avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, tacts) ad2 = np.ascontiguousarray( np.vstack([adm[ran_, tree[ran_, 3]], adm[ran_, tree[ran_, 2]]]) ) _avgdist_taxon(adk := np.zeros((2, n)), k, dm, tree, order, tacts) for i in range(n - 2): tree_, order_, tacts_ = tree.copy(), order.copy(), tacts.copy() # calculate distant-2 values using the algorithm _avgdist_d2_insert(obs := ad2.copy(), i, adk, tree_, order_, tacts_) # insert taxon and calculate full matrix _insert_taxon(k, i, tacts_[order_[i]] * 2 - 1, tree_, order_) _avgdist_matrix(adm := np.zeros((n, n)), dm, tree_, order_, tacts_) exp = np.ascontiguousarray( np.vstack([adm[ran_, tree_[ran_, 3]], adm[ran_, tree_[ran_, 2]]]) ) npt.assert_allclose(obs, exp) def test_bal_avgdist_insert_1(self): """Update balanced average distance matrix after taxon insertion. Phase 1 (serial). """ # Test if the algorithm produces the same result as calculated from the full # matrix after taxon insertion. tree, order, sizes, deeps = ( self.tree1m1, self.preodr1m1, self.sizes1m1, self.deeps1m1 ) n = tree.shape[0] npots = 2.0 ** -np.arange((n + 1) // 2) diffs = np.zeros(n) ancs = np.zeros(n, dtype=int) ancx = np.zeros(n, dtype=int) adm = np.array([ [ 0. , 5. , 9. , 9. , 9. , 0. , 0. ], [ 0. , 0. , 10. , 10. , 10. , 0. , 0. ], [ 0. , 0. , 0. , 9.5, 9.5, 0. , 0. ], [ 0. , 0. , 0. , 0. , 8. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], ]) adk = np.array([ [7. , 9. , 5. , 7. , 3. , 0. , 0. ], [8. , 6.5 , 8.5 , 5.75, 7.75, 0. , 0. ], ]) # Insert e as a sibling of d. This should recover tree1. itag = 4 _bal_avgdist_insert( n - 2, itag, obs := adm, adk, tree, order, sizes, deeps, diffs, npots, ancs, ancx ) exp = np.array([ [ 0. , 5. , 8.75, 9. , 9. , 8.5 , 8. ], [ 0. , 0. , 9.75, 10. , 10. , 9.5 , 9. ], [ 0. , 0. , 0. , 9.5 , 9.5 , 9. , 8.5 ], [ 0. , 0. , 0. , 0. , 8. , 7.5 , 7. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 3. ], [ 0. , 0. , 0. , 0. , 8.75, 0. , 7.75], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], ]) npt.assert_allclose(obs, exp) # another example: all possible insertions dm, tree, order, sizes, deeps = ( self.dm3, self.tree3, self.preodr3, self.sizes3, self.deeps3 ) n = tree.shape[0] m = dm.shape[0] - 1 _bal_avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, sizes) _half_adm(adm, order, n - 2) _bal_avgdist_taxon(n - 2, m, dm, adk := np.zeros((2, n)), tree, order) npots = 2.0 ** -np.arange(m) diffs = np.zeros(n) ancs = np.zeros(n, dtype=int) ancx = np.zeros(n, dtype=int) for i in range(n - 2): # update matrix using the algorithm tree_, order_, sizes_ = tree.copy(), order.copy(), sizes.copy() _bal_avgdist_insert( n - 2, i, obs := adm.copy(), adk.copy(), tree_, order_, sizes_, deeps.copy(), diffs, npots, ancs, ancx ) # insert taxon and calculate full matrix _insert_taxon(m, i, sizes_[order_[i]], tree_, order_) _bal_avgdist_matrix(exp := np.zeros((n, n)), dm, tree_, order_, sizes_) _half_adm(exp, order_, n) npt.assert_allclose(obs, exp) def test_bal_avgdist_insert_2(self): """Update balanced average distance matrix after taxon insertion. Phase 2 (flat serial, nested parallel). """ # Test if the algorithm produces the same result as calculated from the full # matrix after taxon insertion. tree, order, sizes, deeps, pairs = ( self.tree1m1, self.preodr1m1, self.sizes1m1, self.deeps1m1, self.pairs1m1 ) n = tree.shape[0] npots = 2.0 ** -np.arange((n + 1) // 2) diffs = np.zeros(n) ancs = np.zeros(n, dtype=int) ancx = np.zeros(n, dtype=int) segs = np.empty(n + 1, dtype=int) lvls = np.empty(n, dtype=int) oops = np.empty(n, dtype=int) chunks = np.empty(n + 1, dtype=int) chunks[0] = 0 chusegs = np.empty(n, dtype=int) chusegs[0] = 0 adm = np.array([ [ 0. , 5. , 9. , 9. , 9. , 0. , 0. ], [ 0. , 0. , 10. , 10. , 10. , 0. , 0. ], [ 0. , 0. , 0. , 9.5, 9.5, 0. , 0. ], [ 0. , 0. , 0. , 0. , 8. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], ]) adk = np.array([ [7. , 9. , 5. , 7. , 3. , 0. , 0. ], [8. , 6.5 , 8.5 , 5.75, 7.75, 0. , 0. ], ]) # Insert e as a sibling of d. This should recover tree1. itag = 4 tag = order[itag] deep = deeps[tag] _bal_insert_plan( n - 2, itag, adm, adk, tree, order, sizes, deeps, pairs, diffs, ancs, ancx, segs, lvls, oops, True) # The target node has a depth of 2. Therefore it has two ancestors (parent and # root). obs = (segs == n - 2).argmax() self.assertEqual(obs, 3) npt.assert_array_equal(segs[:obs + 1], [0, 2, 4, 5]) npt.assert_array_equal(lvls[:obs], [1, 0, 0]) npt.assert_array_equal(oops[:obs], [2, 0, 0]) # This is an extremely simple case. Only the root node has 2 operations, while # all other nodes have 0. Therefore, regardless how many chunks are desired, # there will always be one chunk generated, which includes just the root. enc = 3 # aim for 3 chunks (get 2) nc = _bal_avgdist_chunk( n - 2, itag, order, sizes, pairs, segs, lvls, oops, enc, chunks, chusegs) self.assertEqual(nc, 2) _bal_update_spine(tag, deep, sizes, pairs, ancs) _bal_avgdist_nest( itag, deep, obs := adm, order, sizes, deeps, diffs, npots, ancs, ancx, segs, lvls, nc, chunks, chusegs) exp = np.array([ [ 0. , 5. , 8.75, 9. , 9. , 8.5 , 8. ], [ 0. , 0. , 9.75, 10. , 10. , 9.5 , 9. ], [ 0. , 0 , 0. , 9.5 , 9.5 , 9. , 8.5 ], [ 0. , 0. , 0. , 0. , 8. , 7.5 , 7. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 3. ], [ 0. , 0. , 0. , 0. , 8.75, 0. , 7.75], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], ]) npt.assert_allclose(obs, exp) def test_bal_avgdist_insert_3(self): """Update balanced average distance matrix after taxon insertion. Phase 3 (flat and nested both parallel). """ # Test if the algorithm produces the same result as calculated from the full # matrix after taxon insertion. tree, order, sizes, deeps, pairs = ( self.tree1m1, self.preodr1m1, self.sizes1m1, self.deeps1m1, self.pairs1m1 ) n = tree.shape[0] npots = 2.0 ** -np.arange((n + 1) // 2) diffs = np.zeros(n) ancs = np.zeros(n, dtype=int) ancx = np.zeros(n, dtype=int) segs = np.empty(n + 1, dtype=int) lvls = np.empty(n, dtype=int) oops = np.empty(n, dtype=int) chunks = np.empty(n + 1, dtype=int) chunks[0] = 0 chusegs = np.empty(n, dtype=int) chusegs[0] = 0 adm = np.array([ [ 0. , 5. , 9. , 9. , 9. , 0. , 0. ], [ 0. , 0. , 10. , 10. , 10. , 0. , 0. ], [ 0. , 0. , 0. , 9.5, 9.5, 0. , 0. ], [ 0. , 0. , 0. , 0. , 8. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], ]) adk = np.array([ [7. , 9. , 5. , 7. , 3. , 0. , 0. ], [8. , 6.5 , 8.5 , 5.75, 7.75, 0. , 0. ], ]) # Insert e as a sibling of d. This should recover tree1. itag = 4 tag = order[itag] size = sizes[tag] deep = deeps[tag] _bal_insert_plan( n - 2, itag, adm, adk, tree, order, sizes, deeps, pairs, diffs, ancs, ancx, segs, lvls, oops, False) enc = 3 nc = _bal_avgdist_chunk( n - 2, itag, order, sizes, pairs, segs, lvls, oops, enc, chunks, chusegs) _bal_update_spine(tag, deep, sizes, pairs, ancs) _bal_avgdist_flat(n - 2, itag, size, order, adm, adk, diffs, deeps) _bal_avgdist_nest( itag, deep, obs := adm, order, sizes, deeps, diffs, npots, ancs, ancx, segs, lvls, nc, chunks, chusegs) exp = np.array([ [ 0. , 5. , 8.75, 9. , 9. , 8.5 , 8. ], [ 0. , 0. , 9.75, 10. , 10. , 9.5 , 9. ], [ 0. , 0 , 0. , 9.5 , 9.5 , 9. , 8.5 ], [ 0. , 0. , 0. , 0. , 8. , 7.5 , 7. ], [ 0. , 0. , 0. , 0. , 0. , 0. , 3. ], [ 0. , 0. , 0. , 0. , 8.75, 0. , 7.75], [ 0. , 0. , 0. , 0. , 0. , 0. , 0. ], ]) npt.assert_allclose(obs, exp) def test_bal_insert_plan(self): """Navigate a tree and plan on subsequent parallelization.""" # This is a relatively large tree with 19 nodes and 10 tips. obj = TreeNode.read([self.nwk6]) n = obj.count() m = obj.count(tips=True) # Generate tree topology array. tree = np.empty((n + 2, 4), dtype=int) taxmap = {x.name: int(x.name) for x in obj.tips()} _from_treenode(obj, taxmap, tree) # Generate tree properties based on the topology. order = np.empty(n + 2, dtype=int) order[:n] = np.arange(n) sizes = np.empty(n + 2, dtype=int) _calc_sizes(n, tree, order, sizes) deeps = np.empty(n + 2, dtype=int) _calc_deeps(n, tree, order, deeps) pairs = np.empty(n + 2, dtype=int) _calc_pairs(n, tree, order, sizes, pairs) # Fill the matrices with zeros, as this test primarily concerns parallelization # planning, whereas numeric accuracy was assessed in `test_bal_avgdist_insert_ # 2`. adm = np.zeros((n + 2, n + 2), dtype=float) adk = np.zeros((2, n + 2), dtype=float) # Allocate arrays that will be filled. diffs = np.empty(n + 2, dtype=float) ancs = np.empty(n + 2, dtype=int) ancx = np.empty(n + 2, dtype=int) segs = np.empty(n + 3, dtype=int) lvls = np.empty(n + 2, dtype=int) oops = np.empty(n + 2, dtype=int) # We will insert a taxon into the branch above node 8. This node has a depth of # 3, meaning it has three ancestors: 7 (parent), 1 (grandparent) and 0 (root). # Meanwhile, 8 itself is the left child of its parent (7), therefore it has a # right sibling: 15. Moving up, it has a left cousin 2 and a right cousin 18. itag = 8 tag = order[itag] size = sizes[tag] deep = deeps[tag] # do the job _bal_insert_plan(n, itag, adm, adk, tree, order, sizes, deeps, pairs, diffs, ancs, ancx, segs, lvls, oops, True) # ancestors npt.assert_array_equal(ancs[:deep], [7, 1, 0]) npt.assert_array_equal(ancx[:deep], [147, 21, 0]) # == ancs * adm.shape[0] # segments (ancestors high-to-low, self, right cousins low-to-high) n_segs = (segs == n).argmax() self.assertEqual(n_segs, 6) npt.assert_array_equal(segs[:n_segs + 1], [0, 1, 7, 8, 15, 18, 19]) # levels up from parent npt.assert_array_equal(lvls[:n_segs], [2, 1, 0, 0, 0, 2]) # numbers of operations npt.assert_array_equal(oops[:n_segs], [22, 18, 6, 4, 2, 2]) # update sizes and pairs _bal_update_spine(tag, deep, sizes, pairs, ancs) # Update tree topoloy, then calculate sizes, deeps and pairs from scratch, and # compare them with the incrementally updated results. _insert_taxon(m + 1, itag, size, tree, order) exp = np.empty(n + 2, dtype=int) _calc_sizes(n + 2, tree, order, exp) npt.assert_array_equal(sizes, exp) exp = np.empty(n + 2, dtype=int) _calc_deeps(n + 2, tree, order, exp) npt.assert_array_equal(deeps, exp) exp = np.empty(n + 2, dtype=int) _calc_pairs(n + 2, tree, order, sizes, exp) npt.assert_array_equal(pairs, exp) def test_bal_avgdist_chunk(self): """Partition nodes into chunks with roughly even workloads.""" # Use the same example as above. # preparation (which is long...) obj = TreeNode.read([self.nwk6]) n = obj.count() tree = np.empty((n + 2, 4), dtype=int) taxmap = {x.name: int(x.name) for x in obj.tips()} _from_treenode(obj, taxmap, tree) order = np.empty(n + 2, dtype=int) order[:n] = np.arange(n) sizes = np.empty(n + 2, dtype=int) _calc_sizes(n, tree, order, sizes) deeps = np.empty(n + 2, dtype=int) _calc_deeps(n, tree, order, deeps) pairs = np.empty(n + 2, dtype=int) _calc_pairs(n, tree, order, sizes, pairs) adm = np.zeros((n + 2, n + 2), dtype=float) adk = np.zeros((2, n + 2), dtype=float) diffs = np.empty(n + 2, dtype=float) ancs = np.empty(n + 2, dtype=int) ancx = np.empty(n + 2, dtype=int) segs = np.empty(n + 3, dtype=int) lvls = np.empty(n + 2, dtype=int) oops = np.empty(n + 2, dtype=int) itag = 8 _bal_insert_plan(n, itag, adm, adk, tree, order, sizes, deeps, pairs, diffs, ancs, ancx, segs, lvls, oops, True) n_segs = (segs == n).argmax() self.assertEqual(n_segs, 6) npt.assert_array_equal(segs[:n_segs + 1], [0, 1, 7, 8, 15, 18, 19]) # chunk boundaries and segment status per chunk chunks = np.zeros(n + 1, dtype=int) chunks[0] = 0 chusegs = np.zeros(n, dtype=int) chusegs[0] = 1 # We aim at dividing the tree into 4 chunks (capacity per chunk: 6). Eventually # we get 5. enc = 4 obs = _bal_avgdist_chunk( n, itag, order, sizes, pairs, segs, lvls, oops, enc, chunks, chusegs) self.assertEqual(obs, 5) # chunk 0: nodes 0, 1: ops = 2 + 1 = 3 (next node has ops = 5 which exceeds # remaining space, so move to new chunk) # chunk 1: nodes 2, 3: ops = 5 + 1 = 6 # chunk 2: nodes 4..8: ops = 3 + 1 + 1 + 0 + 0 = 5 # chunk 3: nodes 9..17: ops = 2 + 0 + 0 + 2 + 0 + 0 + 2 + 0 + 0 = 6 # chunk 4: node 18: ops = 2 (remaining nodes; chunk not filled) npt.assert_array_equal(chunks[:obs + 1], [0, 2, 4, 9, 18, 19]) npt.assert_array_equal(chusegs[:obs], [1, 2, 2, 4, 5]) def test_ols_lengths(self): """Calculate tree branch lengths using an OLS framework.""" # Example 1: This should recover the same branch lengths as in the original # tree. dm, tree, order, tacts = self.dm1, self.tree1, self.preodr1, self.tacts1 n = tree.shape[0] _avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, tacts) _ols_lengths(obs := np.zeros(n), adm, tree, tacts) npt.assert_allclose(obs, self.lens1) # Example 2: The output is close but not precisely identical to those in the # original tree. dm, tree, order, tacts = self.dm2, self.tree2, self.preodr2, self.tacts2 n = tree.shape[0] _avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, tacts) _ols_lengths(obs := np.zeros(n), adm, tree, tacts) exp = np.array([ 0.91769, 0.76891, 0.42026875, 0.35793125, 0.04316597, 0.28054444, 0.03137847, 0.15226875, 0.04148125, 0.12214, 0.14706]) npt.assert_allclose(obs, exp) def test_ols_lengths_d2(self): """Calculate tree branch lengths using an OLS framework.""" # Test if result matches that calculated from the full matrix. # example 1 dm, tree, order, tacts = self.dm1, self.tree1, self.preodr1, self.tacts1 n = tree.shape[0] ran_ = np.arange(n) _avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, tacts) ad2 = np.ascontiguousarray( np.vstack([adm[ran_, tree[ran_, 3]], adm[ran_, tree[ran_, 2]]])) _ols_lengths_d2(obs := np.zeros(n), ad2, tree, tacts) _ols_lengths(exp := np.zeros(n), adm, tree, tacts) npt.assert_allclose(obs, exp) # example 2 dm, tree, order, tacts = self.dm2, self.tree2, self.preodr2, self.tacts2 n = tree.shape[0] ran_ = np.arange(n) _avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, tacts) ad2 = np.ascontiguousarray( np.vstack([adm[ran_, tree[ran_, 3]], adm[ran_, tree[ran_, 2]]])) _ols_lengths_d2(obs := np.zeros(n), ad2, tree, tacts) _ols_lengths(exp := np.zeros(n), adm, tree, tacts) npt.assert_allclose(obs, exp) def test_bal_lengths(self): """Calculate tree branch lengths using a balanced framework.""" # Example 1: In this simple example, OLS and balanced frameworks produce the # same branch lengths. dm, tree, order, sizes = self.dm1, self.tree1, self.preodr1, self.sizes1 n = sizes[0] _bal_avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, sizes) _bal_lengths(obs := np.zeros(n), adm, tree) npt.assert_allclose(obs, self.lens1) # Example 2: Also slightly different from the original branch lengths. dm, tree, order, sizes = self.dm2, self.tree2, self.preodr2, self.sizes2 n = sizes[0] _bal_avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, sizes) _bal_lengths(obs := np.zeros(n), adm, tree) exp = np.array([ 0.92853125, 0.75806875, 0.41086875, 0.36733125, 0.04648125, 0.28469375, 0.02695625, 0.15393125, 0.03981875, 0.11678125, 0.15241875]) npt.assert_allclose(obs, exp) def test_ols_min_branch_d2(self): """Find the branch with minimum length change using an OLS framework.""" # Test if result matches ground truth. dm, tree, order, tacts = self.dm1, self.tree1m1, self.preodr1m1, self.tacts1m1 n = tree.shape[0] k = dm.shape[0] - 1 ran_ = np.arange(n) _avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, tacts) ad2 = np.ascontiguousarray(np.vstack([ adm[ran_, tree[ran_, 3]], adm[ran_, tree[ran_, 2]]])) _avgdist_taxon(adk := np.zeros((2, n)), k, dm, tree, order, tacts) res = _ols_min_branch_d2(obs := np.zeros(n), ad2, adk, tree, order, tacts) self.assertEqual(res, 4) exp = np.array([0, 0, -2, -2, -3, 0, 0], dtype=float) # The algorithm omits factor 0.5, therefore we need to x2 here. npt.assert_allclose(obs, 2 * exp) # Test if result matches that calculated from the entire tree. dm, tree, order, tacts = self.dm3, self.tree3, self.preodr3, self.tacts3 n = tree.shape[0] k = dm.shape[0] - 1 ran_ = np.arange(n) _avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, tacts) ad2 = np.ascontiguousarray( np.vstack([adm[ran_, tree[ran_, 3]], adm[ran_, tree[ran_, 2]]]) ) _avgdist_taxon(adk := np.zeros((2, n)), k, dm, tree, order, tacts) res = _ols_min_branch_d2(obs := np.zeros(n), ad2, adk, tree, order, tacts) # For each branch, insert taxon, calculate full matrix, then calculate and sum # all branch lengths. The difference between each sum and the sum by the root # branch is the length change value calculated by the algorithm. exp = np.zeros(n) for i in range(n - 2): size = tacts[order[i]] * 2 - 1 _insert_taxon(k, i, size, tree_ := tree.copy(), order_ := order.copy()) _calc_tacts(n, tree_, order_, tacts_ := np.empty(n, dtype=int)) _avgdist_matrix(adm := np.zeros((n, n)), dm, tree_, order_, tacts_) _ols_lengths(lens := np.zeros(n), adm, tree_, tacts_) exp[order[i]] = lens.sum() exp[:n - 2] -= exp[0] npt.assert_allclose(obs, exp * 2) self.assertEqual(order[res], exp[:n - 2].argmin()) def test_bal_min_branch(self): """Find the branch with minimum length change using a balacned framework.""" # Test if result matches ground truth. dm = self.dm1 tree, order, sizes = self.tree1m1, self.preodr1m1, self.sizes1m1 n = tree.shape[0] k = dm.shape[0] - 1 _bal_avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, sizes) _bal_avgdist_taxon(n - 2, k, dm, adk := np.zeros((2, n)), tree, order) res = _bal_min_branch(n - 2, obs := np.zeros(n), adm, adk, tree, order) self.assertEqual(res, 4) exp = np.array([0, 0, -2, -2, -3, 0, 0], dtype=float) # The algorithm omits factor 0.25, therefore we need to x4 here. npt.assert_allclose(obs, 4 * exp) # Test if result matches that calculated from the entire tree. dm, tree, order, sizes = self.dm3, self.tree3, self.preodr3, self.sizes3 n = tree.shape[0] k = dm.shape[0] - 1 _bal_avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, sizes) _bal_avgdist_taxon(n - 2, k, dm, adk := np.zeros((2, n)), tree, order) res = _bal_min_branch(n - 2, obs := np.zeros(n), adm, adk, tree, order) exp = np.zeros(n) for i in range(n - 2): size = sizes[order[i]] _insert_taxon(k, i, size, tree_ := tree.copy(), order_ := order.copy()) _calc_sizes(n, tree_, order_, sizes_ := np.empty(n, dtype=int)) _bal_avgdist_matrix(adm := np.zeros((n, n)), dm, tree_, order_, sizes_) _bal_lengths(lens := np.zeros(n), adm, tree_) exp[order[i]] = lens.sum() exp[:n - 2] -= exp[0] npt.assert_allclose(obs, 4 * exp) self.assertEqual(order[res], exp[:n - 2].argmin()) def test_bal_min_branch_p(self): """Find the branch with minimum length change (parallel version).""" # Test if the parallel code can recover the output of the serial code. dm = self.dm1 tree, order, sizes = self.tree1m1, self.preodr1m1, self.sizes1m1 n = tree.shape[0] k = dm.shape[0] - 1 _bal_avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, sizes) _bal_avgdist_taxon(n - 2, k, dm, adk := np.zeros((2, n)), tree, order) # additional preparations roots = np.empty(n, dtype=int) roots[0] = 0 rlens = np.empty(n, dtype=float) rlens[0] = 0 clades = np.empty(n, dtype=int) chunks = np.empty(n + 1, dtype=int) chunks[0] = 0 enc = 2 res = _bal_min_branch_p( n - 2, obs := np.zeros(n), adm, adk, tree, order, sizes, enc, clades, chunks, roots, rlens) self.assertEqual(res, 4) exp = np.array([0, 0, -2, -2, -3, 0, 0], dtype=float) npt.assert_allclose(obs, 4 * exp) # A large, complex example: obj = TreeNode.read([self.nwk6]) n = obj.count() m = obj.count(tips=True) tree = np.empty((n + 2, 4), dtype=int) taxmap = {x.name: i for i, x in enumerate(obj.tips())} _from_treenode(obj, taxmap, tree) order = np.empty(n + 2, dtype=int) order[:n] = np.arange(n) sizes = np.empty(n + 2, dtype=int) _calc_sizes(n, tree, order, sizes) # Fill it with random data. rng = np.random.default_rng(42) adm = np.zeros((n + 2, n + 2), dtype=float) adm[np.triu_indices(n, 1)] = rng.random(n * (n - 1) // 2) adm += adm.T dm = rng.random(m).reshape(1, -1) # we just need one row adk = np.zeros((2, n + 2), dtype=float) _bal_avgdist_taxon(n, 0, dm, adk, tree, order) lens = np.zeros(n + 2, dtype=float) roots = np.zeros(n, dtype=int) roots[0] = 0 rlens = np.zeros(n, dtype=float) rlens[0] = 0 clades = np.zeros(n, dtype=int) chunks = np.zeros(n + 1, dtype=int) chunks[0] = 0 # Trying to divide the tree into two chunks. enc = 2 obs = _bal_min_branch_p( n, lens, adm, adk, tree, order, sizes, enc, clades, chunks, roots, rlens) # This will find node 5. self.assertEqual(obs, 5) exp = np.array([ 0. , -0.336, -0.26 , -0.281, -0.14 , -0.832 , 0.104, -0.266, -0.265, -0.361, -0.793, -0.728, 0.38 , 1.015, 1.502, 0.557, 1.442, 0.84 , 0.68 ]) npt.assert_array_equal(lens[:n].round(3), exp) # Check if serial and parallel results are the same. exp = _bal_min_branch(n, lens, adm, adk, tree, order) self.assertEqual(obs, exp) # This function doesn't return chunk count (unlike `_bal_avgdist_chunk`), so # we will have to find it in an indirect way. nr = (roots[1:] == 0).argmax() + 1 # number of roots self.assertEqual(nr, 5) # The initial roots after the serial phase should be: [0, 1, 2, 7, 18]. # During the parallel phase, nodes 2 and 7 were mutated into 5 and 10. npt.assert_array_equal(roots[:nr], [0, 1, 5, 10, 18]) # There are three clades: 2 and 3 (corresponding to root nodes 2 and 7, later # becoming 5 and 10). npt.assert_array_equal(clades[:2], [2, 3]) # There are two chunks. Clade 2 belongs to the first chunk. Clade 3 belongs to # the second chunk. npt.assert_array_equal(chunks[:3], [0, 1, 2]) def test_swap_branches(self): # example 1: swap (e,d) with b # swap with tacts (for OLS framework) tree, order, index, tacts = ( self.tree1.copy(), self.preodr1.copy(), self.preidx1.copy(), self.tacts1.copy()) n = tree.shape[0] stack = np.full(n, 0) _swap_branches(2, 1, tree, order, index, stack, tacts=tacts) # make sure tree topology, node order and attributes are valid _check_tree(tree) _preorder(order_ := np.empty(n, dtype=int), tree, stack) npt.assert_array_equal(order, order_) index_ = np.empty(n, dtype=int) index_[order] = np.arange(n) npt.assert_array_equal(index, index_) _calc_tacts(n, tree, order, tacts_ := np.empty(n, dtype=int)) npt.assert_array_equal(tacts, tacts_) # check new parent mapping self.assertEqual(tree[4, 2], 0) self.assertEqual(tree[1, 2], 2) # swap with sizes and deeps (for balanced framework) tree, order, index, sizes, deeps = ( self.tree1.copy(), self.preodr1.copy(), self.preidx1.copy(), self.sizes1.copy(), self.deeps1.copy()) _swap_branches(2, 1, tree, order, index, stack, sizes=sizes, deeps=deeps) _check_tree(tree) _preorder(order_ := np.empty(n, dtype=int), tree, stack) npt.assert_array_equal(order, order_) index_ = np.empty(n, dtype=int) index_[order] = np.arange(n) npt.assert_array_equal(index, index_) _calc_sizes(n, tree, order, sizes_ := np.empty(n, dtype=int)) npt.assert_array_equal(sizes, sizes_) _calc_deeps(n, tree, order, deeps_ := np.empty(n, dtype=int)) npt.assert_array_equal(deeps, deeps_) self.assertEqual(tree[4, 2], 0) self.assertEqual(tree[1, 2], 2) # neither tacts nor sizes provided with self.assertRaises(ValueError) as cm: _swap_branches(2, 1, tree, order, index, stack) msg = "Must provide either tacts or sizes." self.assertEqual(str(cm.exception), msg) # both tacts and sizes provided with self.assertRaises(ValueError) as cm: _swap_branches(2, 1, tree, order, index, stack, tacts=tacts, sizes=sizes) msg = "Cannot provide tacts and sizes simultaneously." self.assertEqual(str(cm.exception), msg) # example 4: all possible swaps taxa, tree, order, index, tacts = ( self.taxa4, self.tree4, self.preodr4, self.preidx4, self.tacts4) n = tree.shape[0] stack = np.full(n, 0) taxamap = {} for node in order[::-1]: if tree[node, 0] == 0: taxamap[node] = [taxa[tree[node, 1]]] else: taxamap[node] = taxamap[tree[node, 0]] + taxamap[tree[node, 1]] for node in range(1, n): if tree[node, 0] == 0: continue node1 = taxamap[tree[node, 3]] for side in range(2): tree_, order_, index_, tacts_ = ( tree.copy(), order.copy(), index.copy(), tacts.copy()) node2 = taxamap[tree[node, side]] exp = _to_treenode(tree_, taxa) _swap_branches_treenode(exp.lca(node1), exp.lca(node2)) _swap_branches(node, side, tree_, order_, index_, stack, tacts=tacts_) _check_tree(tree_) obs = _to_treenode(tree_, taxa) self.assertEqual(obs.compare_rfd(exp), 0) def test_avgdist_swap(self): """Update average distance matrix after branch swapping.""" # Test if the algorithm produces the same result as calculated from the full # matrix after branch swapping. # example 1: swap (e,d) with b dm, tree, order, index, tacts = ( self.dm1, self.tree1, self.preodr1, self.preidx1, self.tacts1) n = tree.shape[0] stack = np.full(n, 0) _avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, tacts) _swap_branches(2, 1, tree, order, index, stack, tacts=tacts) _avgdist_swap(index[2], 1, obs := adm.copy(), tree, order, tacts) _avgdist_matrix(exp := np.zeros((n, n)), dm, tree, order, tacts) npt.assert_allclose(obs, exp) # example 4: all possible swaps dm, tree, order, index, tacts = ( self.dm4, self.tree4, self.preodr4, self.preidx4, self.tacts4) n = tree.shape[0] stack = np.full(n, 0) _avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, tacts) for node in range(1, n): if tree[node, 0] == 0: # omit tips continue for side in range(2): # left and right tree_, order_, index_, tacts_ = ( tree.copy(), order.copy(), index.copy(), tacts.copy()) _swap_branches( node, side, tree_, order_, index_, stack, tacts=tacts_) _avgdist_swap( index_[node], side, obs := adm.copy(), tree_, order_, tacts_) _avgdist_matrix( exp := np.zeros((n, n)), dm, tree_, order_, tacts_) npt.assert_allclose(obs, exp) def test_bal_avgdist_swap(self): """Update balanced average distance matrix after branch swapping.""" # Test if the algorithm produces the same result as calculated from the full # matrix after branch swapping. # example 1: swap (e,d) with b dm, tree, order, index, sizes, deeps = ( self.dm1, self.tree1, self.preodr1, self.preidx1, self.sizes1, self.deeps1 ) n = tree.shape[0] stack = np.full(n, 0) npots = np.ldexp(1.0, -np.arange((n + 1) // 2)) _bal_avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, sizes) _swap_branches(2, 1, tree, order, index, stack, sizes=sizes, deeps=deeps) _bal_avgdist_swap( obs := adm.copy(), 2, 1, tree, order, index, sizes, deeps, npots, stack) _bal_avgdist_matrix(exp := np.zeros((n, n)), dm, tree, order, sizes) npt.assert_allclose(obs, exp) # example 4: all possible swaps dm, tree, order, index, sizes, deeps = ( self.dm4, self.tree4, self.preodr4, self.preidx4, self.sizes4, self.deeps4 ) n = tree.shape[0] stack = np.full(n, 0) npots = np.ldexp(1.0, -np.arange((n + 1) // 2)) _bal_avgdist_matrix(adm := np.zeros((n, n)), dm, tree, order, sizes) for node in range(1, n): if tree[node, 0] == 0: continue for side in range(2): tree_, order_, index_, sizes_, deeps_ = ( tree.copy(), order.copy(), index.copy(), sizes.copy(), deeps.copy()) _swap_branches( node, side, tree_, order_, index_, stack, sizes=sizes_, deeps=deeps_) _bal_avgdist_swap( obs := adm.copy(), node, side, tree_, order_, index_, sizes_, deeps_, npots, stack) _bal_avgdist_matrix(exp := np.zeros((n, n)), dm, tree_, order_, sizes_) npt.assert_allclose(obs, exp) def test_ols_all_swaps(self): """Evaluate possible swaps at all branches of a tree.""" dm, tree, order, index, tacts = ( self.dm4, self.tree4, self.preodr4, self.preidx4, self.tacts4) n = tree.shape[0] _avgdist_matrix(adm := np.empty((n, n)), dm, tree, order, tacts) _ols_lengths(lens := np.empty(n), adm, tree, tacts) lensum = lens.sum() # Nodes 2 and 3 will have length reduction. sides = np.empty(n, dtype=int) _ols_all_swaps(lens, adm, tree, tacts, sides) exp = np.array([0, 0, -0.47035, -0.03426528, 0, 0, 0, 0, 0, 0, 0]) npt.assert_allclose(lens, exp) # For each of those two branches, perform branch swapping, update average # distance matrix, calculate total tree length, and check if the actual # tree length gain equals to the algorithm-calculated value. stack = np.full(n, 0) for node in np.flatnonzero(lens): side = sides[node] tree_, order_, index_, tacts_ = ( tree.copy(), order.copy(), index.copy(), tacts.copy()) _swap_branches(node, side, tree_, order_, index_, stack, tacts=tacts_) _avgdist_swap( index_[node], side, adm_ := adm.copy(), tree_, order_, tacts_) _ols_lengths(lens_ := np.empty(n), adm_, tree_, tacts_) # The algorithm omits factor 0.5, therefore we need to x2 here. self.assertAlmostEqual(lens[node], 2 * (lens_.sum() - lensum)) def test_ols_corner_swaps(self): """Update swaps of the four corner branches of a swapped branch.""" dm, tree, order, index, tacts = ( self.dm4, self.tree4, self.preodr4, self.preidx4, self.tacts4) n = tree.shape[0] _avgdist_matrix(adm := np.empty((n, n)), dm, tree, order, tacts) sides = np.empty(n, dtype=int) _ols_all_swaps(lens := np.empty(n), adm, tree, tacts, sides) heap = [(lens[i], i, sides[i]) for i in np.flatnonzero(lens)] heapify(heap) # Perform swaps at the two branches that are known to produce gains (see # `test_ols_all_swaps`), and check if the updated result matches the result # re-calculated from the entire tree. stack = np.full(n, 0) for node in np.flatnonzero(lens): side = sides[node] tree_, order_, index_, tacts_ = ( tree.copy(), order.copy(), index.copy(), tacts.copy()) _swap_branches(node, side, tree_, order_, index_, stack, tacts=tacts_) _avgdist_swap( index_[node], side, adm_ := adm.copy(), tree_, order_, tacts_) _ols_all_swaps(exp := np.empty(n), adm_, tree_, tacts_, sides) _ols_corner_swaps( node, heap, obs := lens.copy(), adm_, tree_, tacts_, sides) obs[node] = 0 npt.assert_allclose(obs, exp) def test_bal_all_swaps(self): """Evaluate possible swaps at all branches of a tree.""" # Using the same strategy as `test_ols_all_swaps`. dm, tree, order, index, sizes, deeps = ( self.dm4, self.tree4, self.preodr4, self.preidx4, self.sizes4, self.deeps4 ) n = tree.shape[0] npots = np.ldexp(1.0, -np.arange((n + 1) // 2)) _bal_avgdist_matrix(adm := np.empty((n, n)), dm, tree, order, sizes) _bal_lengths(lens := np.empty(n), adm, tree) lensum = lens.sum() nodes = np.flatnonzero(tree[1:, 0]) + 1 nb = nodes.size gains = np.zeros(nb, dtype=float) sides = np.empty(nb, dtype=int) _bal_all_swaps(gains, sides, nodes, adm, tree) exp = np.array([0, 0.9407, 0.06885, 0]) npt.assert_allclose(gains, exp) stack = np.full(n, 0) for branch in range(nb): if gains[branch] == 0: continue node, side = nodes[branch], sides[branch] tree_, order_, index_, sizes_, deeps_ = ( tree.copy(), order.copy(), index.copy(), sizes.copy(), deeps.copy()) _swap_branches( node, side, tree_, order_, index_, stack, sizes=sizes_, deeps=deeps_) _bal_avgdist_swap( adm_ := adm.copy(), node, side, tree_, order_, index_, sizes_, deeps_, npots, stack) _bal_lengths(lens_ := np.empty(n), adm_, tree_) # The algorithm omits factor 0.25, therefore we need to x4 here. self.assertAlmostEqual(gains[branch], 4 * (lensum - lens_.sum())) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/test_nj.py000066400000000000000000000201041520735541300236000ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from unittest import TestCase, main import numpy.testing as npt from skbio import DistanceMatrix, TreeNode from skbio.util import get_data_path from skbio.tree._nj import nj, _tree_from_linkmat class NjTests(TestCase): def setUp(self): data1 = [[0, 5, 9, 9, 8], [5, 0, 10, 10, 9], [9, 10, 0, 8, 7], [9, 10, 8, 0, 3], [8, 9, 7, 3, 0]] ids1 = list('abcde') self.dm1 = DistanceMatrix(data1, ids1) self.dm1_condensed = DistanceMatrix(self.dm1, condensed=True) # this newick string was confirmed against http://www.trex.uqam.ca/ # which generated the following (isomorphic) newick string: # (d:2.0000,e:1.0000,(c:4.0000,(a:2.0000,b:3.0000):3.0000):2.0000); self.expected1_str = ("(d:2.000000, (c:4.000000, (b:3.000000," " a:2.000000):3.000000):2.000000, e:1.000000);") self.expected1_TreeNode = TreeNode.read( io.StringIO(self.expected1_str)) # this example was pulled from the Phylip manual # https://phylipweb.github.io/phylip/doc/neighbor.html data2 = [[0.0000, 1.6866, 1.7198, 1.6606, 1.5243, 1.6043, 1.5905], [1.6866, 0.0000, 1.5232, 1.4841, 1.4465, 1.4389, 1.4629], [1.7198, 1.5232, 0.0000, 0.7115, 0.5958, 0.6179, 0.5583], [1.6606, 1.4841, 0.7115, 0.0000, 0.4631, 0.5061, 0.4710], [1.5243, 1.4465, 0.5958, 0.4631, 0.0000, 0.3484, 0.3083], [1.6043, 1.4389, 0.6179, 0.5061, 0.3484, 0.0000, 0.2692], [1.5905, 1.4629, 0.5583, 0.4710, 0.3083, 0.2692, 0.0000]] ids2 = ["Bovine", "Mouse", "Gibbon", "Orang", "Gorilla", "Chimp", "Human"] self.dm2 = DistanceMatrix(data2, ids2) self.expected2_str = ("(Mouse:0.76891, (Gibbon:0.35793, (Orang:0.28469" ", (Gorilla:0.15393, (Chimp:0.15167, Human:0.117" "53):0.03982):0.02696):0.04648):0.42027, Bovine:" "0.91769);") self.expected2_TreeNode = TreeNode.read( io.StringIO(self.expected2_str)) data3 = [[0, 5, 4, 7, 6, 8], [5, 0, 7, 10, 9, 11], [4, 7, 0, 7, 6, 8], [7, 10, 7, 0, 5, 8], [6, 9, 6, 5, 0, 8], [8, 11, 8, 8, 8, 0]] ids3 = map(str, range(6)) self.dm3 = DistanceMatrix(data3, ids3) self.expected3_str = ("((((0:1.000000,1:4.000000):1.000000,2:2.000000" "):1.250000,5:4.750000):0.750000,3:2.750000,4:2." "250000);") self.expected3_TreeNode = TreeNode.read( io.StringIO(self.expected3_str)) # this dm can yield negative branch lengths for nj data4 = [[0, 5, 9, 9, 800], [5, 0, 10, 10, 9], [9, 10, 0, 8, 7], [9, 10, 8, 0, 3], [800, 9, 7, 3, 0]] ids4 = list('abcde') self.dm4 = DistanceMatrix(data4, ids4) def test_nj_dm1(self): actual_TreeNode = nj(self.dm1) self.assertAlmostEqual(actual_TreeNode.compare_cophenet( self.expected1_TreeNode), 0.0) def test_nj_dm1_condensed(self): actual_TreeNode = nj(self.dm1_condensed) self.assertAlmostEqual(actual_TreeNode.compare_cophenet( self.expected1_TreeNode), 0.0) def test_nj_dm2(self): actual_TreeNode = nj(self.dm2) self.assertAlmostEqual(actual_TreeNode.compare_cophenet( self.expected2_TreeNode), 0.0) def test_nj_dm3(self): actual_TreeNode = nj(self.dm3) self.assertAlmostEqual(actual_TreeNode.compare_cophenet( self.expected3_TreeNode), 0.0) def test_nj_real(self): dm = DistanceMatrix.read(get_data_path("mp100.phy")) obs = nj(dm, neg_as_zero=False) exp = TreeNode.read(get_data_path("mp100.nj.nwk")) self.assertEqual(obs.compare_rfd(exp), 0.0) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) def test_nj_inplace(self): dm = self.dm3.copy() obs = nj(dm) exp = self.expected3_TreeNode self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) npt.assert_almost_equal(dm.data, self.dm3.data) obs = nj(dm, inplace=True) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) with self.assertRaises(AssertionError): npt.assert_almost_equal(dm.data, self.dm3.data) def test_nj_floating(self): dm = self.dm3.copy() exp = nj(dm) dm._data = dm._data.astype("float64") obs = nj(dm) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) dm._data = dm._data.astype("float32") obs = nj(dm) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) dm._data = dm._data.astype("int32") with self.assertRaises(TypeError): _ = nj(dm) def test_nj_zero_branch_length(self): # no nodes have negative branch length when we disallow negative # branch length. self is excluded as branch length is None tree = nj(self.dm4) for n in tree.postorder(include_self=False): self.assertTrue(n.length >= 0) # only tips associated with the large distance in the input # have positive branch lengths when we allow negative branch # length tree = nj(self.dm4, neg_as_zero=False) self.assertTrue(tree.find('a').length > 0) self.assertTrue(tree.find('b').length < 0) self.assertTrue(tree.find('c').length < 0) self.assertTrue(tree.find('d').length < 0) self.assertTrue(tree.find('e').length > 0) # deprecated functionality with self.assertWarns(DeprecationWarning): t2 = nj(self.dm4, disallow_negative_branch_length=False) self.assertAlmostEqual(tree.compare_cophenet(t2), 0.0) def test_nj_trivial(self): data = [[0, 3, 2], [3, 0, 3], [2, 3, 0]] dm = DistanceMatrix(data, list('abc')) exp = TreeNode.read(["(b:2.000000, a:1.000000, c:1.000000);"]) self.assertAlmostEqual(nj(dm).compare_cophenet(exp), 0.0) # deprecated functionality with self.assertWarns(DeprecationWarning): self.assertEqual(nj(dm, result_constructor=str), "(a:1.0,b:2.0,c:1.0);\n") def test_nj_error(self): data = [[0, 3], [3, 0]] dm = DistanceMatrix(data, list('ab')) self.assertRaises(ValueError, nj, dm) def test_tree_from_linkmat(self): taxa = ['human', 'chimp', 'monkey', 'pig', 'mouse', 'rat', 'chicken'] lm = [ [5, 4, 0.065041, 0.060976], # rat, mouse [6, 7, 0.457317, 0.229675], # chicken, rat-mouse [3, 8, 0.161924, 0.050474], # pig, chicken-rat-mouse [2, 9, 0.018293, 0.162602], # monkey, pig-...-mouse [10, 1, 0.006098, 0.001016], # chimp, monkey-...-mouse [0, 11, 0.003049, 0.0], # human, chimp-...-mouse ] obs = str(_tree_from_linkmat(lm, taxa, rooted=True)) exp = ("(human:0.003049,((monkey:0.018293,(pig:0.161924,(chicken:0.457317," "(rat:0.065041,mouse:0.060976):0.229675):0.050474):0.162602):0.006098," "chimp:0.001016):0.0);\n") self.assertEqual(str(obs), exp) obs = str(_tree_from_linkmat(lm, taxa, rooted=False)) exp = ("(human:0.003049,(monkey:0.018293,(pig:0.161924,(chicken:0.457317," "(rat:0.065041,mouse:0.060976):0.229675):0.050474):0.162602):0.006098," "chimp:0.001016);\n") self.assertEqual(str(obs), exp) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/test_tree.py000066400000000000000000003640011520735541300241370ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main from collections import defaultdict from warnings import catch_warnings, simplefilter import numpy as np import numpy.testing as npt import pandas as pd from scipy.stats import pearsonr from scipy.spatial.distance import euclidean from skbio import DistanceMatrix, TreeNode from skbio.tree import (DuplicateNodeError, NoLengthError, TreeError, MissingNodeError, NoParentError) class TreeNodeSubclass(TreeNode): pass class TreeTests(TestCase): def setUp(self): """Prep the self""" # a simple tree self.simple_t = TreeNode.read(["((a,b)i1,(c,d)i2)root;"]) # /-a # /i1------| # | \-b # -root----| # | /-c # \i2------| # \-d # another test tree nodes = dict([(x, TreeNode(x)) for x in "abcdefgh"]) nodes["a"].append(nodes["b"]) nodes["b"].append(nodes["c"]) nodes["c"].append(nodes["d"]) nodes["c"].append(nodes["e"]) nodes["c"].append(nodes["f"]) nodes["f"].append(nodes["g"]) nodes["a"].append(nodes["h"]) self.TreeRoot = nodes["a"] # (((d,e,(g)f)c)b,h)a; # /-d # | # /b------- /c-------|--e # | | # -a-------| \f------- /-g # | # \-h self.complex_tree = TreeNode.read([ "(((a,b)int1,(x,y,(w,z)int2,(c,d)int3)int4),(e,f)int5);"]) # /-a # /int1----| # | \-b # | # /--------| /-x # | | | # | | |--y # | | | # | \int4----| /-w # | |-int2----| # ---------| | \-z # | | # | | /-c # | \int3----| # | \-d # | # | /-e # \int5----| # \-f def test_gops(self): """Basic TreeNode operations should work as expected.""" p = TreeNode() self.assertEqual(str(p), ";\n") p.name = "abc" self.assertEqual(str(p), "abc;\n") p.length = 3 self.assertEqual(str(p), "abc:3;\n") # don"t suppress branch from root q = TreeNode() p.append(q) self.assertEqual(str(p), "()abc:3;\n") r = TreeNode() q.append(r) self.assertEqual(str(p), "(())abc:3;\n") r.name = "xyz" self.assertEqual(str(p), "((xyz))abc:3;\n") q.length = 2 self.assertEqual(str(p), "((xyz):2)abc:3;\n") def test_iter(self): """iter wraps children.""" exp = ["i1", "i2"] obs = [n.name for n in self.simple_t] self.assertEqual(obs, exp) # ------------------------------------------------ # Tree copying # ------------------------------------------------ def test_copy(self): """Copy a tree.""" t = self.simple_t t.children[0].length = 1.2 t.children[1].children[0].length = 0.5 cp = t.copy() for obs, exp in zip(cp.traverse(), t.traverse()): self.assertIsNot(obs, exp) self.assertEqual(obs.name, exp.name) self.assertEqual(obs.length, exp.length) # deep vs shallow copy t.dummy = [1, [2, 3], 4] cp = t.copy(deep=True) cp.dummy[1].append(0) self.assertListEqual(t.dummy[1], [2, 3]) cp = t.copy(deep=False) cp.dummy[1].append(0) self.assertListEqual(t.dummy[1], [2, 3, 0]) # with attribute cache t.cache_attr(lambda n: 1, "node_count", sum) cp = t.copy() self.assertFalse(hasattr(cp, "node_count")) def test__copy__(self): t = self.simple_t t.dummy = [1, [2, 3], 4] cp = self.simple_t.__copy__() for obs, exp in zip(cp.traverse(), t.traverse()): self.assertIsNot(obs, exp) self.assertEqual(obs.name, exp.name) self.assertEqual(obs.length, exp.length) cp.dummy[1].append(0) self.assertListEqual(t.dummy[1], [2, 3, 0]) def test__deepcopy__(self): t = self.simple_t t.dummy = [1, [2, 3], 4] cp = self.simple_t.__deepcopy__({}) for obs, exp in zip(cp.traverse(), t.traverse()): self.assertIsNot(obs, exp) self.assertEqual(obs.name, exp.name) self.assertEqual(obs.length, exp.length) cp.dummy[1].append(0) self.assertListEqual(t.dummy[1], [2, 3]) # ------------------------------------------------ # Tree navigation # ------------------------------------------------ def test_is_tip(self): """see if we're a tip or not""" self.assertFalse(self.simple_t.is_tip()) self.assertFalse(self.simple_t.children[0].is_tip()) self.assertTrue(self.simple_t.children[0].children[0].is_tip()) def test_is_root(self): """see if we're at the root or not""" self.assertTrue(self.simple_t.is_root()) self.assertFalse(self.simple_t.children[0].is_root()) self.assertFalse(self.simple_t.children[0].children[0].is_root()) def test_has_children(self): """Test if has children""" t = TreeNode.read(["((a,b)c,(d,e)f);"]) self.assertTrue(t.has_children()) self.assertTrue(t.children[0].has_children()) self.assertTrue(t.children[1].has_children()) self.assertFalse(t.children[0].children[0].has_children()) self.assertFalse(t.children[0].children[1].has_children()) self.assertFalse(t.children[1].children[0].has_children()) self.assertFalse(t.children[1].children[1].has_children()) def test_root(self): """Get the root!""" t = self.simple_t self.assertIs(t, self.simple_t.root()) self.assertIs(t, self.simple_t.children[0].root()) self.assertIs(t, self.simple_t.children[1].children[1].root()) def test_ancestors(self): """Get all the ancestors""" exp = ["i1", "root"] obs = self.simple_t.children[0].children[0].ancestors() self.assertEqual([o.name for o in obs], exp) exp = ["a", "i1", "root"] obs = self.simple_t.children[0].children[0].ancestors(include_self=True) self.assertEqual([o.name for o in obs], exp) exp = ["root"] obs = self.simple_t.children[0].ancestors() self.assertEqual([o.name for o in obs], exp) exp = [] obs = self.simple_t.ancestors() self.assertEqual([o.name for o in obs], exp) def test_siblings(self): """Get siblings of a node.""" exp = [] obs = self.simple_t.siblings() self.assertEqual(obs, exp) exp = ["i2"] obs = self.simple_t.children[0].siblings() self.assertEqual([o.name for o in obs], exp) exp = ["c"] obs = self.simple_t.children[1].children[1].siblings() self.assertEqual([o.name for o in obs], exp) self.simple_t.append(TreeNode(name="foo")) self.simple_t.append(TreeNode(name="bar")) exp = ["i1", "foo", "bar"] obs = self.simple_t.children[1].siblings() self.assertEqual([o.name for o in obs], exp) def test_neighbors(self): """Get neighbors of a node""" t = TreeNode.read(["((a,b)c,(d,e)f);"]) exp = t.children obs = t.neighbors() self.assertEqual(obs, exp) exp = t.children[0].children + [t] obs = t.children[0].neighbors() self.assertEqual(obs, exp) exp = [t.children[0].children[0]] + [t] obs = t.children[0].neighbors(ignore=t.children[0].children[1]) self.assertEqual(obs, exp) exp = [t.children[0]] obs = t.children[0].children[0].neighbors() self.assertEqual(obs, exp) def test_lca(self): """Return LCA for set of nodes.""" t1 = TreeNode.read(["((a,(b,c)d)e,f,(g,h)i)j;"]) t2 = t1.copy() t3 = t1.copy() t4 = t1.copy() t5 = t1.copy() input1 = ["a"] # return self input2 = ["a", "b"] # return e input3 = ["b", "c"] # return d input4 = ["a", "h", "g"] # return j input5 = ["g", "i"] # return i (nested) exp1 = t1.find("a") exp2 = t2.find("e") exp3 = t3.find("d") exp4 = t4 exp5 = t5.find("i") obs1 = t1.lca(input1) obs2 = t2.lca(input2) obs3 = t3.lca(input3) obs4 = t4.lca(input4) obs5 = t5.lca(input5) self.assertEqual(obs1, exp1) self.assertEqual(obs2, exp2) self.assertEqual(obs3, exp3) self.assertEqual(obs4, exp4) self.assertEqual(obs5, exp5) # parameter alias self.assertEqual(t1.lca(nodes=input1), exp1) with self.assertWarns(DeprecationWarning): obsx = t1.lca(tipnames=input1) self.assertEqual(obsx, exp1) # verify multiple calls work t_mul = t1.copy() exp_1 = t_mul.find("d") exp_2 = t_mul.find("i") obs_1 = t_mul.lca(["b", "c"]) obs_2 = t_mul.lca(["g", "h"]) self.assertEqual(obs_1, exp_1) self.assertEqual(obs_2, exp_2) # verify subtree call t_sub = t1.copy() obs = t_sub.find("e").lca(["b", "c"]) exp = t_sub.find("d") self.assertEqual(obs, exp) # lca outside subtree obs = t_sub.find("e").lca(["b", "g"]) exp = t_sub self.assertEqual(obs, exp) # root included t_root = TreeNode.read(["(a,b)c;"]) obs = t_root.lca(["a", "c"]) self.assertIs(obs, t_root) # nested nodes t_sub = t1.copy() obs = t_sub.lca(["b", "d", "g", "i"]) self.assertIs(obs, t_sub) obs = t_sub.lca(["e", "b", "d", "h"]) self.assertIs(obs, t_sub) # empty case self.assertRaises(ValueError, t1.lca, []) self.assertRaises(ValueError, t1.lca) def test_path(self): """List of TreeNode objects in path between nodes.""" t1 = TreeNode.read(["((a,(b,c)d)e,f,(g,h)i)j;"]) t2 = t1.copy() t3 = t1.copy() init1 = t1.find("a") # tip init2 = t2.find("j") # root node init3 = t3.find("e") # internal node fin1 = t1.find("g") # tip fin2 = t2.find("c") # tip fin3 = t3.find("i") # internal node exp1 = [t1.find("e"), t1.find("j"), t1.find("i")] exp2 = [t2.find("e"), t2.find("d")] exp3 = [t3.find("j")] obs1 = init1.path(fin1) # tip-to-tip obs2 = init2.path(fin2) # root-to-tip obs3 = init3.path(fin3) # internal-to-internal self.assertEqual(obs1, exp1) self.assertEqual(obs2, exp2) self.assertEqual(obs3, exp3) # include ends t = TreeNode.read(["((a,b)c,(d,e)f)root;"]) init = t.find("a") fin = t.find("e") exp = [t.find("a"), t.find("c"), t.find("root"), t.find("f"), t.find("e")] obs = init.path(fin, include_ends=True) self.assertEqual(obs, exp) # flag for no existing path t1 = TreeNode.read(["((a,b)c,(d,e)f);"]) t2 = TreeNode.read(["((g,h)i,(j,k)l);"]) node1 = t1.find("a") node2 = t2.find("g") msg = "Could not find a path between self and other." with self.assertRaises(TreeError) as cm: node1.path(node2) self.assertEqual(str(cm.exception), msg) # ------------------------------------------------ # Tree traversal # ------------------------------------------------ def test_preorder(self): """Preorder traversal of the tree""" exp = ["root", "i1", "a", "b", "i2", "c", "d"] obs = [n.name for n in self.simple_t.preorder()] self.assertEqual(obs, exp) exp = ["i1", "a", "b", "i2", "c", "d"] obs = [n.name for n in self.simple_t.preorder(include_self=False)] self.assertEqual(obs, exp) def test_postorder(self): """Postorder traversal of the tree""" exp = ["a", "b", "i1", "c", "d", "i2", "root"] obs = [n.name for n in self.simple_t.postorder()] self.assertEqual(obs, exp) exp = ["a", "b", "i1", "c", "d", "i2"] obs = [n.name for n in self.simple_t.postorder(include_self=False)] self.assertEqual(obs, exp) def test_pre_and_postorder(self): """Pre and post order traversal of the tree""" exp = ["root", "i1", "a", "b", "i1", "i2", "c", "d", "i2", "root"] obs = [n.name for n in self.simple_t.pre_and_postorder()] self.assertEqual(obs, exp) obs2 = [n.name for n in self.simple_t.traverse(True, True)] self.assertEqual(obs2, exp) def test_pre_and_postorder_no_children(self): t = TreeNode("brofist") # include self exp = ["brofist"] obs = [n.name for n in t.pre_and_postorder()] self.assertEqual(obs, exp) # do not include self obs = list(t.pre_and_postorder(include_self=False)) self.assertEqual(obs, []) def test_levelorder(self): """Level order traversal of the tree""" exp = ["root", "i1", "i2", "a", "b", "c", "d"] obs = [n.name for n in self.simple_t.levelorder()] self.assertEqual(obs, exp) exp = ["i1", "i2", "a", "b", "c", "d"] obs = [n.name for n in self.simple_t.levelorder(include_self=False)] self.assertEqual(obs, exp) def test_tips(self): """Tip traversal of tree""" exp = ["a", "b", "c", "d"] obs = [n.name for n in self.simple_t.tips()] self.assertEqual(obs, exp) obs2 = [n.name for n in self.simple_t.traverse(False, False)] self.assertEqual(obs2, exp) def test_tips_self(self): """ See issue #1509 """ tree = TreeNode.read(["(c,(b,a)x)y;"]) ts = list(tree.find("c").tips(include_self=True)) self.assertEqual(len(ts), 1) t = ts[0] self.assertEqual(t.name, "c") self.assertTrue(t.is_tip()) # ------------------------------------------------ # Tree manipulation # ------------------------------------------------ def test_append(self): """Add a node to children.""" t = self.simple_t # append a single tip t.create_caches() t.append(TreeNode(name="n1")) self.assertEqual(len((c := t.children)), 3) self.assertEqual(c[-1].name, "n1") self.assertIs(c[-1].parent, t) self.assertFalse(hasattr(t, "_tip_cache")) # append an entire tree t2 = TreeNode.read(["(x,y)z;"]) t.append(t2) self.assertEqual(len((c := t.children)), 4) self.assertEqual(c[0].name, "i1") self.assertEqual(c[1].name, "i2") self.assertEqual(c[2].name, "n1") self.assertEqual(c[3].name, "z") self.assertEqual(c[3].children[0].name, "x") self.assertEqual(c[3].children[1].name, "y") self.assertEqual(t2.parent, t) # move a clade from another tree, keep cache t3 = TreeNode.read(["((x2,x3)o,(x4,x5)p)q;"]) n3 = t3.find("o") t2.create_caches() t2.append(n3, uncache=False) self.assertEqual(len((c2 := t2.children)), 3) self.assertEqual(c2[0].name, "x") self.assertEqual(c2[1].name, "y") self.assertEqual(c2[2].name, "o") self.assertEqual(c2[2].children[0].name, "x2") self.assertEqual(c2[2].children[1].name, "x3") self.assertIs(c2[2].parent, t2) self.assertEqual(len(t3.children), 1) self.assertEqual(t3.children[0].name, "p") self.assertTrue(hasattr(t, "_tip_cache")) self.assertTrue(hasattr(t3, "_tip_cache")) def test_extend(self): """Add arbitrary number of nodes to children.""" # add two clades t = self.simple_t t.create_caches() t2 = TreeNode.read(["(x1,y1)z1;"]) t3 = TreeNode.read(["(x2,y2)z2;"]) t.extend([t2, t3]) self.assertIs(t2.parent, t) self.assertIs(t3.parent, t) self.assertEqual(len(c := t.children), 4) self.assertEqual(c[0].name, "i1") self.assertEqual(c[1].name, "i2") self.assertEqual(c[2].name, "z1") self.assertEqual(c[3].name, "z2") self.assertEqual(c[2].children[0].name, "x1") self.assertEqual(c[2].children[1].name, "y1") self.assertEqual(c[3].children[0].name, "x2") self.assertEqual(c[3].children[1].name, "y2") self.assertFalse(hasattr(t, "_tip_cache")) # move all children, keep cache t1 = TreeNode.read(["(x1,y1)z1;"]) t4 = TreeNode.read(["(x2,y2)z2;"]) t1.create_caches() t4.create_caches() t1.extend(t4.children, uncache=False) self.assertEqual(len(t4.children), 0) self.assertEqual(len(c := t1.children), 4) self.assertEqual(c[0].name, "x1") self.assertEqual(c[1].name, "y1") self.assertEqual(c[2].name, "x2") self.assertEqual(c[3].name, "y2") self.assertIs(c[2].parent, t1) self.assertIs(c[3].parent, t1) self.assertTrue(hasattr(t1, "_tip_cache")) self.assertTrue(hasattr(t4, "_tip_cache")) # empty input t.extend([]) self.assertEqual(len(t.children), 4) def test_insert(self): "Insert a node into the branch connecting self and its parent." # insert a new node into a branch with no length t = self.simple_t node = t.find("i1") node.insert(TreeNode("x")) obs = t.find("x") self.assertTrue(obs.parent is t) self.assertTrue(node.parent is obs) self.assertIn(obs, t.children) self.assertIn(node, obs.children) self.assertIsNone(obs.length) self.assertIsNone(node.length) msg = "Distance is provided but branch has no length." with self.assertRaisesRegex(ValueError, msg): node.insert(TreeNode("x"), distance=1.0) msg = "Self has no parent." with self.assertRaisesRegex(NoParentError, msg): t.insert(TreeNode("x")) # insert an existing clade into a branch with length t = TreeNode.read(["((a:1,b:1)c:2,(d:3,e:4)f:5,g:1)h;"]) donor_t = TreeNode.read(["((x:1,y:1)m:1.5,(z:1,w:1)n:0.5,l:2.5);"]) t.find("c").insert(donor_t.find("m")) obs = t.find("m") self.assertTrue(obs.parent is t) self.assertTrue(t.find("c").parent is obs) self.assertNotIn(obs, donor_t.children) self.assertEqual(obs.length, 1) self.assertEqual(t.find("c").length, 1) t.find("d").insert(donor_t.find("n"), 2) obs = t.find("n") self.assertTrue(obs.parent is t.find("f")) self.assertTrue(t.find("d").parent is obs) self.assertEqual(obs.length, 1) self.assertEqual(t.find("d").length, 2) msg = "Distance cannot exceed branch length." with self.assertRaisesRegex(ValueError, msg): t.find("c").insert(TreeNode("x"), 20) # with branch support, keep cache t = TreeNode.read(["(((a,b)90)d);"]) t.assign_supports() t.create_caches() n = t.lca(["a", "b"]) t.lca(["a", "b"]).insert(TreeNode("x"), uncache=False) self.assertTrue(hasattr(t, "_tip_cache")) self.assertEqual(n.parent.name, "x") self.assertEqual(n.parent.parent.name, "d") self.assertIs(n.parent.support, 90) # with custom branch attribute t = TreeNode.read(["(((a,b)c)d);"]) n = t.find("c") n.battr = 1 # branch attribute n.nattr = 2 # node attribute n.insert(TreeNode("x"), branch_attrs=["battr"]) self.assertEqual(t.find("x").battr, 1) self.assertFalse(hasattr(t.find("x"), "nattr")) def test_pop(self): """Pop off a node by index.""" t = self.simple_t t.extend([ TreeNode.read(["(x1,y1)z1;"]), TreeNode.read(["(x2,y2)z2;"]) ]) # pop last child (default) t.create_caches() z2 = t.pop() self.assertEqual(z2.name, "z2") self.assertIsNone(z2.parent) self.assertEqual(len(t.children), 3) self.assertNotIn(z2, t.children) self.assertEqual(z2.children[0].name, "x2") self.assertEqual(z2.children[1].name, "y2") self.assertFalse(hasattr(t, "_tip_cache")) # pop first child, keep cache t.create_caches() i1 = t.pop(0, uncache=False) self.assertEqual(i1.name, "i1") self.assertIsNone(i1.parent) self.assertEqual(len(t.children), 2) self.assertNotIn(i1, t.children) self.assertEqual(i1.children[0].name, "a") self.assertEqual(i1.children[1].name, "b") self.assertTrue(hasattr(t, "_tip_cache")) # check remaining tree structure self.assertEqual(t.children[0].name, "i2") self.assertEqual(t.children[1].name, "z1") def test_remove(self): """Remove a node.""" t = self.simple_t # a node that can be removed parent = t.find("i1") child = t.find("a") self.assertTrue(parent.remove(child)) self.assertIsNone(child.parent) self.assertEqual(len(parent.children), 1) self.assertNotIn(child, parent.children) self.assertEqual(parent.children[0].name, "b") self.assertFalse(hasattr(t, "_tip_cache")) # nodes that cannot be removed self.assertFalse(t.remove(child)) self.assertFalse(t.remove(t.find("c"))) self.assertFalse(t.remove(TreeNode())) # keep cache t.create_caches() self.assertTrue(t.remove(parent, uncache=False)) self.assertTrue(hasattr(t, "_tip_cache")) def test_remove_by_func(self): """Remove nodes by function.""" t = self.simple_t def f(node): return node.name in ("b", "d") # def function t.remove_by_func(f) self.assertEqual(str(t), "((a)i1,(c)i2)root;\n") # lambda function, keep cache t.create_caches() t.remove_by_func(lambda x: x.name == "a", uncache=False) self.assertEqual(str(t), "(i1,(c)i2)root;\n") self.assertTrue(hasattr(t, "_tip_cache")) def test_prune(self): """Collapse single-child nodes.""" t = self.simple_t.copy() # nothing to collapse because tree is bifurcating cp = t.copy() t.prune() for obs, exp in zip(t.traverse(), cp.traverse()): self.assertEqual(obs.name, exp.name) self.assertEqual(obs.length, exp.length) # create a single child by removing tip "a" n = t.children[0] n.remove(n.children[0]) t.prune() self.assertEqual(len(t.children), 2) self.assertEqual(t.children[0].name, "i2") self.assertEqual(t.children[1].name, "b") self.assertIsNone(t.children[1].length) # tree with branch lengths t = self.simple_t.copy() for n in t.traverse(): n.length = 1 n = t.children[0] n.remove(n.children[0]) t.prune() self.assertEqual(len(t.children), 2) self.assertEqual(t.children[0].name, "i2") self.assertEqual(t.children[1].name, "b") self.assertAlmostEqual(t.children[1].length, 2) # root has single child t = TreeNode.read(["((a,b)c)extra;"]) t.prune() self.assertEqual(str(t), "(a,b)c;\n") # nested single-child nodes t = TreeNode.read(["(((a,b)));"]) t.prune() self.assertEqual(str(t), "(a,b);\n") # single-child root and branch lengths t = TreeNode.read(["((((a:1)b:2)c:3)d:4)e:5;"]) t.prune() self.assertEqual(t.name, "a") self.assertAlmostEqual(t.length, 15) # keep cache t = TreeNode.read(["((((a)b)c)d)e;"]) t.create_caches() t.prune(uncache=False) self.assertEqual(t.name, "a") self.assertTrue(hasattr(t, "_tip_cache")) # prune from internal node t = TreeNode.read(["((((a:1)b:2)c:3)d:4)e:5;"]) n = t.children[0].children[0] n.prune() self.assertEqual(t.name, "e") self.assertEqual(len(t.children), 1) c = t.children[0] self.assertEqual(c.name, "d") self.assertAlmostEqual(c.length, 4) self.assertEqual(len(c.children), 1) self.assertIs(c.children[0], n) self.assertIs(n.parent, c) self.assertAlmostEqual(n.length, 6) def test_shear(self): """Shear tree to keep given tips.""" # LCA is root, and root is retained t = TreeNode.read(["((H:1,G:1):2,(R:0.5,M:0.7):3);"]) obs = str(t.shear(["G", "M"])) exp = "(G:3.0,M:3.7);\n" self.assertEqual(obs, exp) # in place obs = t.shear(["G", "M"], inplace=True) self.assertEqual(str(t), exp) self.assertIs(obs, t) # keep cache t = TreeNode.read(["((H:1,G:1):2,(R:0.5,M:0.7):3);"]) t.create_caches() obs = t.shear(["G", "M"], inplace=True, uncache=False) self.assertEqual(str(t), exp) self.assertTrue(hasattr(t, "_tip_cache")) # LCA is internal, and root is dropped t = TreeNode.read(["((a,b),((c,d),(e,f)));"]) obs = str(t.shear(["c", "d"])) exp = "(c,d);\n" self.assertEqual(obs, exp) # don't prune obs = str(t.shear(["c", "d"], prune=False)) exp = "(((c,d)));\n" self.assertEqual(obs, exp) # in place exp = "(c,d);\n" t.shear(["c", "d"], inplace=True) self.assertEqual(str(t), exp) # polytomy (issue 1416) t = TreeNode.read(["(((a,b,f,g),c),d);"]) obs = str(t.shear(["a", "b", "c", "f"])) exp = "((a,b,f),c);\n" self.assertEqual(obs, exp) # in place t.shear(["a", "b", "c", "f"], inplace=True) self.assertEqual(str(obs), exp) # complex example; shear from internal node t = TreeNode.read(["((((((a,b),(c,d)),(e,f)):1,(g,(h,i))):2,((j,k),l)),m);"]) n = t.children[0].children[0] # LCA is root of subtree names = {"a", "b", "e", "h"} obs = n.shear(names) self.assertAlmostEqual(obs.length, 2) self.assertSetEqual(obs.subset(), names) # LCA is internal node of subtree (check branch length) names = {"a", "b", "e"} obs = n.shear(names) self.assertAlmostEqual(obs.length, 3) self.assertSetEqual(obs.subset(), names) # in place (check branch length and connection) n.shear(names, inplace=True) self.assertAlmostEqual(n.length, 3) self.assertIs(n.parent, t.children[0]) self.assertSetEqual(n.subset(), names) # name not found msg = "Names are not a subset of the tree." with self.assertRaisesRegex(ValueError, msg): TreeNode.read(["(a,b)c;"]).shear(["a", "c"]) # non-strict mode obs = str(TreeNode.read(["(a,b)c;"]).shear(["a", "c"], strict=False)) exp = "a;\n" self.assertEqual(obs, exp) def test_unpack(self): """Unpack an internal node.""" # test unpacking a node without branch length tree = TreeNode.read(["((c,d)a,(e,f)b);"]) tree.find("b").unpack() exp = "((c,d)a,e,f);\n" self.assertEqual(str(tree), exp) self.assertFalse(hasattr(tree, "_tip_cache")) # keep cache tree = TreeNode.read(["((c,d)a,(e,f)b);"]) tree.find("b").unpack(uncache=False) self.assertEqual(str(tree), exp) self.assertTrue(hasattr(tree, "_tip_cache")) # test unpacking a node with branch length tree = TreeNode.read(["((c:2.0,d:3.0)a:1.0,(e:2.0,f:1.0)b:2.0);"]) tree.find("b").unpack() exp = "((c:2.0,d:3.0)a:1.0,e:4.0,f:3.0);" self.assertEqual(str(tree).rstrip(), exp) # test attempting to unpack root tree = TreeNode.read(["((d,e)b,(f,g)c)a;"]) msg = "Cannot unpack root." with self.assertRaisesRegex(TreeError, msg): tree.find("a").unpack() # test attempting to unpack tip msg = "Cannot unpack tip." with self.assertRaisesRegex(TreeError, msg): tree.find("d").unpack() def test_unpack_by_func(self): """Unpack internal nodes of a tree by a function.""" # unpack internal nodes with branch length <= 1.0 def func(x): return x.length <= 1.0 # will unpack node "a", but not tip "e" # will add the branch length of "a" to its child nodes "c" and "d" tree = TreeNode.read(["((c:2,d:3)a:1,(e:1,f:2)b:2);"]) tree.unpack_by_func(func) exp = "((e:1.0,f:2.0)b:2.0,c:3.0,d:4.0);" self.assertEqual(str(tree).rstrip(), exp) # keep cache tree = TreeNode.read(["((c:2,d:3)a:1,(e:1,f:2)b:2);"]) tree.create_caches() tree.unpack_by_func(func, uncache=False) self.assertEqual(str(tree).rstrip(), exp) self.assertTrue(hasattr(tree, "_tip_cache")) # unpack internal nodes with branch length < 2.01 # will unpack both "a" and "b" tree = TreeNode.read(["((c:2,d:3)a:1,(e:1,f:2)b:2);"]) tree.unpack_by_func(lambda x: x.length <= 2.0) exp = "(c:3.0,d:4.0,e:3.0,f:4.0);" self.assertEqual(str(tree).rstrip(), exp) # unpack two nested nodes "a" and "c" simultaneously tree = TreeNode.read(["(((e:3,f:2)c:1,d:3)a:1,b:4);"]) tree.unpack_by_func(lambda x: x.length <= 2.0) exp = "(b:4.0,d:4.0,e:5.0,f:4.0);" self.assertEqual(str(tree).rstrip(), exp) # test a complicated scenario (unpacking nodes "g", "h" and "m") def func(x): return x.length < 2.0 tree = TreeNode.read(["(((a:1.04,b:2.32,c:1.44)d:3.20," "(e:3.91,f:2.47)g:1.21)h:1.75," "(i:4.14,(j:2.06,k:1.58)l:3.32)m:0.77);"]) tree.unpack_by_func(func) exp = ("((a:1.04,b:2.32,c:1.44)d:4.95,e:6.87,f:5.43,i:4.91," "(j:2.06,k:1.58)l:4.09);") self.assertEqual(str(tree).rstrip(), exp) # unpack nodes with support < 75 def func(x): return x.support < 75 tree = TreeNode.read(["(((a,b)85,(c,d)78)75,(e,(f,g)64)80);"]) tree.assign_supports() tree.unpack_by_func(func) exp = "(((a,b)85,(c,d)78)75,(e,f,g)80);" self.assertEqual(str(tree).rstrip(), exp) # unpack nodes with support < 85 tree = TreeNode.read(["(((a,b)85,(c,d)78)75,(e,(f,g)64)80);"]) tree.assign_supports() tree.unpack_by_func(lambda x: x.support < 85) exp = "((a,b)85,c,d,e,f,g);" self.assertEqual(str(tree).rstrip(), exp) # unpack nodes with support < 0.95 tree = TreeNode.read(["(((a,b)0.97,(c,d)0.98)1.0,(e,(f,g)0.88)0.96);"]) tree.assign_supports() tree.unpack_by_func(lambda x: x.support < 0.95) exp = "(((a,b)0.97,(c,d)0.98)1.0,(e,f,g)0.96);" self.assertEqual(str(tree).rstrip(), exp) # test a case where there are branch lengths, none support values and # node labels tree = TreeNode.read(["(((a:1.02,b:0.33)85:0.12,(c:0.86,d:2.23)" "70:3.02)75:0.95,(e:1.43,(f:1.69,g:1.92)64:0.20)" "node:0.35)root;"]) tree.assign_supports() tree.unpack_by_func(lambda x: x.support is not None and x.support < 75) exp = ("(((a:1.02,b:0.33)85:0.12,c:3.88,d:5.25)75:0.95," "(e:1.43,f:1.89,g:2.12)node:0.35)root;") self.assertEqual(str(tree).rstrip(), exp) def test_bifurcate(self): t1 = TreeNode.read(["(((a,b),c),(d,e));"]) t1.create_caches() t1.bifurcate() self.assertEqual(str(t1), "(((a,b),c),(d,e));\n") self.assertFalse(hasattr(t1, "_tip_cache")) # keep cache t1 = TreeNode.read(["(((a,b),c),(d,e));"]) t1.create_caches() t1.bifurcate(uncache=False) self.assertEqual(str(t1), "(((a,b),c),(d,e));\n") self.assertTrue(hasattr(t1, "_tip_cache")) # with and without insert length t2 = TreeNode.read(["((a,b,c));"]) t3 = t2.copy() t2.bifurcate() self.assertEqual(str(t2), "((c,(a,b)));\n") t3.bifurcate(insert_length=0) self.assertEqual(str(t3), "((c,(a,b):0));\n") # rooted and unrooted tree t4 = TreeNode.read(["((a,b),(c,d),e);"]) t4.bifurcate(include_self=False) self.assertEqual(str(t4), "((a,b),(c,d),e);\n") t4.bifurcate(include_self=True) self.assertEqual(str(t4), "(e,((a,b),(c,d)));\n") # bifurcate with subclass tree = TreeNodeSubclass() tree.append(TreeNodeSubclass()) tree.append(TreeNodeSubclass()) tree.append(TreeNodeSubclass()) tree.append(TreeNodeSubclass()) tree.bifurcate() for node in tree.traverse(): self.assertIs(type(node), TreeNodeSubclass) def test_shuffle(self): # default behavior: all tips are shuffled, only one tree is yielded # shuffling method is stochastic and so is the result t = self.simple_t.copy() obs = list(t.shuffle()) self.assertEqual(len(obs), 1) self.assertSetEqual(obs[0].subset(), set('abcd')) # specify a random generator to make results deterministic rng = np.random.default_rng(42) t = self.simple_t.copy() obs = str(next(t.shuffle(shuffler=rng))) exp = "((d,c)i1,(b,a)i2)root;\n" self.assertEqual(obs, exp) # can also specify a random seed; result is the same t = self.simple_t.copy() obs = str(next(t.shuffle(shuffler=42))) self.assertEqual(obs, exp) # can also supply a function; result is the same t = self.simple_t.copy() f = np.random.default_rng(42).shuffle obs = str(next(t.shuffle(shuffler=f))) self.assertEqual(obs, exp) # renamed parameter t = self.simple_t.copy() with self.assertWarns(DeprecationWarning): obs = str(next(t.shuffle(shuffle_f=42))) self.assertEqual(obs, exp) # yield a row of 5 trees rng = np.random.default_rng(42) t = self.simple_t.copy() obs = list(map(str, t.shuffle(shuffler=rng, n=5))) self.assertEqual(len(obs), 5) exp = ["((d,c)i1,(b,a)i2)root;\n", "((a,b)i1,(d,c)i2)root;\n", "((a,c)i1,(d,b)i2)root;\n", "((d,b)i1,(a,c)i2)root;\n", "((a,c)i1,(d,b)i2)root;\n"] self.assertListEqual(obs, exp) # yield infinitely rng = np.random.default_rng(42) t = self.simple_t.copy() gen = t.shuffle(shuffler=rng, n=None) obs = [str(next(gen)) for i in range(100)] self.assertListEqual(obs[:5], exp) # define two simple, non-stochastic shuffling functions def rev_f(items): items.reverse() def rotate_f(items): tmp = items[-1] items[1:] = items[:-1] items[0] = tmp # apply a simple function t = self.simple_t.copy() obs = str(next(t.shuffle(shuffler=rev_f))) exp = "((d,c)i1,(b,a)i2)root;\n" self.assertEqual(obs, exp) # specify names to shuffle t = self.simple_t.copy() obs = list(map(str, t.shuffle(names=list("abc"), shuffler=rotate_f, n=4))) exp = ["((c,a)i1,(b,d)i2)root;\n", "((b,c)i1,(a,d)i2)root;\n", "((a,b)i1,(c,d)i2)root;\n", "((c,a)i1,(b,d)i2)root;\n"] self.assertListEqual(obs, exp) # specify number of names to shuffle t = self.simple_t.copy() obs = list(map(str, t.shuffle(k=2, shuffler=rev_f, n=5))) exp = ["((a,b)i1,(d,c)i2)root;\n", "((a,b)i1,(c,d)i2)root;\n", "((a,b)i1,(d,c)i2)root;\n", "((a,b)i1,(c,d)i2)root;\n", "((a,b)i1,(d,c)i2)root;\n"] self.assertListEqual(obs, exp) # a complex example obs = list(map(str, self.complex_tree.shuffle( shuffler=rev_f, names=["c", "d", "e", "f"], n=4))) exp = ["(((a,b)int1,(x,y,(w,z)int2,(f,e)int3)int4),(d,c)int5);\n", "(((a,b)int1,(x,y,(w,z)int2,(c,d)int3)int4),(e,f)int5);\n", "(((a,b)int1,(x,y,(w,z)int2,(f,e)int3)int4),(d,c)int5);\n", "(((a,b)int1,(x,y,(w,z)int2,(c,d)int3)int4),(e,f)int5);\n"] self.assertListEqual(obs, exp) # invalid number of iterations t = self.simple_t.copy() with self.assertRaises(ValueError): next(t.shuffle(n=-1)) # invalid number of names to shuffle with self.assertRaises(ValueError): next(t.shuffle(k=1)) # k and names conflict with self.assertRaises(ValueError): next(t.shuffle(k=5, names=["a", "b"])) # tip names not found with self.assertRaises(MissingNodeError): next(t.shuffle(names=["x", "y"])) # ------------------------------------------------ # Tree rerooting # ------------------------------------------------ def test_unroot(self): """Convert a rooted tree into unrooted.""" # default behavior t = TreeNode.read(["((a,b)c,(d,e)f)g;"]) t.unroot() exp = "(a,b,(d,e)f)c;\n" self.assertEqual(str(t), exp) # choose the other side t = TreeNode.read(["((a,b)c,(d,e)f)g;"]) t.unroot(side=1) exp = "((a,b)c,d,e)f;\n" self.assertEqual(str(t), exp) # start from internal node t = TreeNode.read(["((a,b)c,(d,e)f)g;"]) t.find("c").unroot() exp = "(a,b,(d,e)f)c;\n" self.assertEqual(str(t), exp) self.assertFalse(hasattr(t, "_tip_cache")) # keep caches t = TreeNode.read(["((a,b)c,(d,e)f)g;"]) t.find("c").unroot(uncache=False) exp = "(a,b,(d,e)f)c;\n" self.assertEqual(str(t), exp) self.assertTrue(hasattr(t, "_tip_cache")) # with branch lengths t = TreeNode.read(["((a:2.0,b:1.5)c:0.5,(d:1.0,e:1.2)f:0.3)g;"]) t.unroot() exp = "(a:2.0,b:1.5,(d:1.0,e:1.2)f:0.8)c;\n" self.assertEqual(str(t), exp) # other child has no branch length t = TreeNode.read(["((a,b)c:1.0,(d,e)f)g;"]) t.unroot() exp = "(a,b,(d,e)f:1.0)c;\n" self.assertEqual(str(t), exp) # first child is a tip t = TreeNode.read(["(a,(b,c)d)e;"]) t.unroot() exp = "(a,b,c)d;\n" self.assertEqual(str(t), exp) # both children are tips t = TreeNode.read(["(a,b)c;"]) t.unroot() exp = "(b)a;\n" self.assertEqual(str(t), exp) # tree is already unrooted t = TreeNode.read(["(a,b,(d,e)f)c;"]) t.unroot() exp = "(a,b,(d,e)f)c;\n" self.assertEqual(str(t), exp) def test_unrooted_copy(self): tree = TreeNode.read(["((a,(b,c)d)e,(f,g)h)i;"]) node = tree.find("d") # default behavior obs = node.unrooted_copy() exp = "(b,c,(a,((f,g)h)i)e)d;\n" self.assertEqual(str(obs), exp) # name as branch label, root name as "root" (old default behavior; changed in # 0.7.0) obs = node.unrooted_copy(branch_attrs={"name", "length", "support"}, root_name="root") exp = "(b,c,(a,((f,g)h)e)d)root;\n" self.assertEqual(str(obs), exp) # name as node label obs = node.unrooted_copy(branch_attrs={"length"}) exp = "(b,c,(a,((f,g)h)i)e)d;\n" self.assertEqual(str(obs), exp) # name the new root node (only when it doesn't have one) obs = node.unrooted_copy(branch_attrs={"name", "length"}, root_name="hello") exp = "(b,c,(a,((f,g)h)e)d)hello;\n" self.assertEqual(str(obs), exp) obs = node.unrooted_copy(branch_attrs={"length"}, root_name="hello") exp = "(b,c,(a,((f,g)h)i)e)d;\n" self.assertEqual(str(obs), exp) # tree caches are cleaned tree.cache_attr(lambda n: 1, "node_count", sum) self.assertTrue(hasattr(node, "node_count")) obs = node.unrooted_copy() self.assertFalse(hasattr(obs, "node_count")) # transfer branch support to opposite node tree = TreeNode.read(["((a,b)90,(c,d)90);"]) node = tree.find("a") obs = node.unrooted_copy(branch_attrs={"support", "length"}) exp = "((b,((c,d)90))90)a;\n" self.assertEqual(str(obs), exp) tree.assign_supports() obs = node.unrooted_copy(branch_attrs={"support", "length"}) exp = "((b,((c,d)90)90))a;\n" self.assertEqual(str(obs), exp) # retain custom attributes tree = TreeNode.read(["(((a,b)c,d)e,f)g;"]) tree.find("c").dummy = "this" tree.find("e").dummy = "that" obs = tree.find("c").unrooted_copy(branch_attrs={"length"}) exp = "(a,b,(d,(f)g)e)c;\n" self.assertEqual(str(obs), exp) self.assertEqual(obs.dummy, "this") self.assertEqual(obs.find("e").dummy, "that") self.assertIsNone(getattr(obs.find("d"), "dummy", None)) # deep vs shallow copy tree = TreeNode.read(["(((a,b)c,d)e,f)g;"]) tree.find("c").dummy = [1, [2, 3], 4] tcopy = tree.unrooted_copy(deep=True) tcopy.find("c").dummy[1].append(0) self.assertListEqual(tree.find("c").dummy[1], [2, 3]) tcopy = tree.unrooted_copy() tcopy.find("c").dummy[1].append(0) self.assertListEqual(tree.find("c").dummy[1], [2, 3, 0]) def test_unrooted_move(self): t = TreeNode.read(["(((a:1,b:1)c:1,(d:1,e:1)f:2)g:0.5,(h:1,i:1)j:0.5)k;"]) tcopy = t.copy() obs = tcopy.find("c") obs.unrooted_move() self.assertFalse(hasattr(tcopy, "_tip_cache")) self.assertTrue(obs.is_root()) for node in obs.traverse(): self.assertFalse(hasattr(node, 'old_child')) for child in node.children: self.assertIs(child.parent, node) exp = TreeNode.read(["(a:1,b:1,((d:1,e:1)f:2,((h:1,i:1)j:0.5)k:0.5)g:1)c;"]) for o, e in zip(obs.traverse(), exp.traverse()): self.assertEqual(o.name, e.name) self.assertEqual(o.length, e.length) # keep caches tcopy = t.copy() obs = tcopy.find("c") obs.unrooted_move(uncache=False) self.assertTrue(hasattr(tcopy, "_tip_cache")) def test_root_at(self): """Root tree at a given node.""" t = TreeNode.read(["(((a,b)c,(d,e)f)g,h)i;"]) # root at an internal node obs = str(t.root_at("c")) exp = "(a,b,((d,e)f,h)g)c;\n" self.assertEqual(obs, exp) # root at self obs = str(t.find("c").root_at()) self.assertEqual(obs, exp) # root at a basal node (which will be avoided during unrooting) obs = str(t.root_at("g")) exp = "((a,b)c,(d,e)f,h)g;\n" self.assertEqual(obs, exp) # in-place rooting n = t.copy().find("g") obs = n.root_at(inplace=True) self.assertIs(n, obs) self.assertEqual(str(obs), exp) # root at tip (and input node instead of name) obs = str(t.root_at(t.find("h"))) exp = "(((a,b)c,(d,e)f)g)h;\n" self.assertEqual(obs, exp) # root at root (no change) obs = str(t.root_at("i")) self.assertEqual(obs, str(t)) # tree is already unrooted t = TreeNode.read(["((a,b)c,d,e)f;"]) obs = str(t.root_at("c")) exp = str(t.root_at("c", reset=False)) self.assertEqual(obs, exp) def test_root_at_keep(self): """Root tree while keeping original root.""" t = TreeNode.read(["(((a,b)c,(d,e)f)g,h)i;"]) # old default behavior (changed since 0.7.0) obs = str(t.root_at("c", reset=False, branch_attrs=["name"], root_name="root")) exp = "(a,b,((d,e)f,(h)g)c)root;\n" self.assertEqual(obs, exp) # root at an internal node obs = str(t.root_at("c", reset=False)) exp = "(a,b,((d,e)f,(h)i)g)c;\n" self.assertEqual(obs, exp) # root at a tip obs = str(t.root_at(t.find("h"), reset=False)) exp = "((((a,b)c,(d,e)f)g)i)h;\n" self.assertEqual(obs, exp) # root at root (no change) obs = str(t.root_at("i", reset=False)) self.assertEqual(obs, str(t)) def test_root_at_above(self): """Root tree at the branch above a given node.""" # no branch length t = TreeNode.read(["(((a,b)c,(d,e)f)g,h)i;"]) obs = str(t.root_at("c", above=True)) exp = "((a,b)c,((d,e)f,h)g);\n" self.assertEqual(obs, exp) # in-place rooting n = t.find("c") obs = t.root_at(n, above=True, inplace=True) self.assertIs(n.parent, obs) self.assertEqual(str(obs), exp) # root at midpoint of branch t = TreeNode.read(["(((a,b)c:1.0,(d,e)f)g,h)i;"]) obs = str(t.root_at("c", above=True)) exp = "((a,b)c:0.5,((d,e)f,h)g:0.5);\n" self.assertEqual(obs, exp) # root at specific position t = TreeNode.read(["(((a,b)c:1.0,(d,e)f)g,h)i;"]) obs = str(t.root_at("c", above=0.4)) exp = "((a,b)c:0.4,((d,e)f,h)g:0.6);\n" self.assertEqual(obs, exp) # with branch support t = TreeNode.read(["(((a,b)'90:c',(d,e)'80:f')g,h)i;"]) t.assign_supports() obs = str(t.root_at("c", above=True)) exp = "((a,b)'90:c',((d,e)'80:f',h)'90:g');\n" self.assertEqual(obs, exp) def test_root_at_midpoint(self): """Root tree at the midpoint""" t = self.TreeRoot for n in t.traverse(): n.length = 1 # g and h are farthest apart, by 5, therefore root should be # 2.5 away from h, i.e., midpoint between b and c result = t.root_at_midpoint() self.assertEqual(result.distance(result.find("e")), 1.5) self.assertEqual(result.distance(result.find("g")), 2.5) exp_dist = t.cophenet() obs_dist = result.cophenet() self.assertEqual(obs_dist, exp_dist) # in-place rerooting b = t.find("b") result = t.root_at_midpoint(inplace=True, reset=False) self.assertIs(b.parent, result) self.assertEqual(result.cophenet(), exp_dist) def test_root_at_midpoint_no_lengths(self): # should get same tree back (a copy) nwk = "(a,b)c;\n" t = TreeNode.read([nwk]) obs = t.root_at_midpoint(reset=False) self.assertEqual(str(obs), nwk) def test_root_at_midpoint_missing_length(self): # Internal node c has no length. It will be treated as 0. # b and e are farthest apart, by 11, therefore root should be # 5.5 above b, and 1.5 below c. nwk = "((a:2,b:7)c,(d:1,e:3)f:1,g:2)h;\n" t = TreeNode.read([nwk]) obs = t.root_at_midpoint(reset=False) exp = TreeNode.read(["(b:5.5,(a:2,((d:1,e:3)f:1,g:2)h)c:1.5);"]) for o, e in zip(obs.traverse(), exp.traverse()): self.assertEqual(o.name, e.name) self.assertEqual(o.length, e.length) def test_root_at_midpoint_tie(self): t = TreeNode.read(["(((a:1,b:1)c:2,(d:3,e:4)f:5),g:1);"]) obs = t.root_at_midpoint() exp = TreeNode.read(["((d:3,e:4)f:2,((a:1,b:1)c:2,g:1):3);"]) for o, e in zip(obs.traverse(), exp.traverse()): self.assertEqual(o.name, e.name) self.assertEqual(o.length, e.length) t = TreeNode.read(["((a:1,b:1)c:2,(d:3,e:4)f:5,g:1)h;"]) # farthest tip-to-tip distance is 12 (a or b to e) # therefore new root should be 2 above f obs = t.root_at_midpoint() exp = TreeNode.read(["((d:3,e:4)f:2,((a:1,b:1)c:2,g:1)h:3);"]) for o, e in zip(obs.traverse(), exp.traverse()): self.assertEqual(o.name, e.name) self.assertEqual(o.length, e.length) # with root name obs = t.root_at_midpoint(root_name="root") self.assertEqual(obs.name, "root") # with branch support t = TreeNode.read(["((a:1,b:1)c:2,(d:3,e:4)'80:f':5,g:1)h;"]) t.assign_supports() obs = t.root_at_midpoint() exp = TreeNode.read(["((d:3,e:4)'80:f':2,((a:1,b:1)c:2,g:1)'80:h':3);"]) exp.assign_supports() for o, e in zip(obs.traverse(), exp.traverse()): self.assertEqual(o.name, e.name) self.assertEqual(o.length, e.length) self.assertEqual(o.support, e.support) def test_root_at_midpoint_node(self): t = TreeNode.read(["(((a:2,b:3)c:1,d:1)e:1,f:3)g;"]) # farthest tip-to-tip distance is 8 (b - c - e - f) # therefore new root should be at e obs = t.root_at_midpoint(reset=False) exp = TreeNode.read(["((a:2.0,b:3.0)c:1.0,d:1.0,(f:3.0)g:1.0)e;"]) for o, e in zip(obs.traverse(), exp.traverse()): self.assertEqual(o.name, e.name) self.assertEqual(o.length, e.length) # remove original root obs = t.root_at_midpoint() exp = TreeNode.read(["((a:2.0,b:3.0)c:1.0,d:1.0,f:4.0)e;"]) for o, e in zip(obs.traverse(), exp.traverse()): self.assertEqual(o.name, e.name) self.assertEqual(o.length, e.length) def test_root_by_outgroup(self): tree = TreeNode.read(["((((a,b),(c,d)),(e,f)),g);"]) # outgroup is monophyletic obs = str(tree.root_by_outgroup(["a", "b"])) exp = "((a,b),((c,d),((e,f),g)));\n" self.assertEqual(obs, exp) # outgroup is monophyletic after rotating obs = str(tree.root_by_outgroup(["e", "f", "g"])) exp = "(((e,f),g),((c,d),(b,a)));\n" self.assertEqual(obs, exp) # outgroup is a single taxon obs = str(tree.root_by_outgroup(["a"])) exp = "(a,(b,((c,d),((e,f),g))));\n" self.assertEqual(obs, exp) # outgroup is not monophyletic msg = "Outgroup is not monophyletic in the tree." with self.assertRaisesRegex(TreeError, msg): tree.root_by_outgroup(["a", "c"]) # outgroup has extra taxa msg = "Outgroup is not a proper subset of taxa in the tree." with self.assertRaisesRegex(TreeError, msg): tree.root_by_outgroup(["a", "b", "x"]) # outgroup is not in tree with self.assertRaisesRegex(TreeError, msg): tree.root_by_outgroup(["x", "y"]) # outgroup is the whole tree with self.assertRaisesRegex(TreeError, msg): tree.root_by_outgroup("abcdefg") # generate unrooted tree obs = str(tree.root_by_outgroup(["a", "b"], above=False)) exp = "(a,b,((c,d),((e,f),g)));\n" self.assertEqual(obs, exp) # keep old root node obs = str(tree.root_by_outgroup(["a", "b"], reset=False)) exp = "((a,b),((c,d),((e,f),(g))));\n" self.assertEqual(obs, exp) # specify root name obs = str(tree.root_by_outgroup(["a", "b"], root_name="root")) exp = "((a,b),((c,d),((e,f),g)))root;\n" self.assertEqual(obs, exp) # in-place rooting lca = tree.lca(["a", "b"]) self.assertIsNot(obs, lca.parent) obs = tree.root_by_outgroup(["a", "b"], root_name="root", inplace=True) self.assertEqual(str(obs), exp) self.assertIs(obs, lca.parent) # transfer branch support tree = TreeNode.read(["((((a,b)80,(c,d)),(e,f)),g);"]) tree.assign_supports() obs = str(tree.root_by_outgroup(["a", "b"])) exp = "((a,b)80,((c,d),((e,f),g))80);\n" self.assertEqual(obs, exp) # transfer custom branch attribute tree = TreeNode.read(["((((a,b),(c,d))x,(e,f)),g);"]) obs = str(tree.root_by_outgroup(["a", "b"], branch_attrs=["name"])) exp = "((a,b),((c,d),((e,f),g)x));\n" self.assertEqual(obs, exp) # ------------------------------------------------ # Tree metrics # ------------------------------------------------ def test_count(self): """Get node counts""" exp = 7 obs = self.simple_t.count() self.assertEqual(obs, exp) exp = 4 obs = self.simple_t.count(tips=True) self.assertEqual(obs, exp) def test_subset(self): """Return a set of tip names descending from a node.""" # entire tree t = self.simple_t self.assertEqual(t.subset(), frozenset("abcd")) # subtree c = t.children[0] self.assertEqual(c.subset(), frozenset("ab")) # tip tip = c.children[1] self.assertEqual(tip.subset(), frozenset()) self.assertEqual(tip.subset(include_self=True), frozenset("b")) # single-child internal node t = TreeNode.read(["((a,b),(c)d);"]) self.assertEqual(t.subset(), frozenset("abc")) # nameless tips t = TreeNode.read(["((a,b),(c,));"]) self.assertEqual(t.subset(), frozenset("abc")) # duplicate names t = TreeNode.read(["((a,b),(c,a));"]) self.assertEqual(t.subset(), frozenset("abc")) def test_subsets(self): """Return all subsets descending from a node.""" t = self.simple_t # default case self.assertSetEqual(t.subsets(), frozenset( [frozenset("ab"), frozenset("cd")])) # make sure intermediates are cleaned for node in t.traverse(include_self=False): self.assertFalse(hasattr(node, "_subset")) # custom range self.assertSetEqual(t.subsets(within={"a", "b", "c"}), frozenset( [frozenset("ab")])) self.assertSetEqual(t.subsets(within="abc"), frozenset( [frozenset("ab")])) # include all self.assertSetEqual(t.subsets(include_full=True), frozenset( [frozenset("ab"), frozenset("cd"), frozenset("abcd")])) for node in t.traverse(include_self=False): self.assertFalse(hasattr(node, "_subset")) # include singles self.assertSetEqual(t.subsets(include_tips=True), frozenset( [frozenset("ab"), frozenset("cd"), frozenset("a"), frozenset("b"), frozenset("c"), frozenset("d")])) # map to length t = TreeNode.read(["((a:1,b:2):1,c:4,((d:4,e:5):2,f:6):1);"]) self.assertDictEqual(t.subsets(map_to_length=True), { frozenset("ab"): 1, frozenset("de"): 2, frozenset("def"): 1}) # merged lengths self.assertDictEqual(t.subsets(within="abde", map_to_length=True), { frozenset("ab"): 1, frozenset("de"): 3}) # missing length t.children[0].length = None self.assertDictEqual(t.subsets(map_to_length=True), { frozenset("ab"): 0, frozenset("de"): 2, frozenset("def"): 1}) # when a basal taxon is excluded t = TreeNode.read(['(((a,b),(c,d)),e);']) self.assertSetEqual(t.subsets(within="abcd"), frozenset( [frozenset("ab"), frozenset("cd")])) # nothing to include self.assertFalse(t.subsets(within=set())) self.assertFalse(t.subsets(within="")) self.assertFalse(t.subsets(within="xyz")) # single-child internal node t = TreeNode.read(["((a,b),(c)d);"]) self.assertSetEqual(t.subsets(), frozenset( [frozenset("ab")])) self.assertSetEqual(t.subsets(within="abc"), frozenset( [frozenset("ab")])) self.assertSetEqual(t.subsets(include_full=True), frozenset( [frozenset("ab"), frozenset("abc")])) self.assertSetEqual(t.subsets(include_tips=True), frozenset( [frozenset("ab"), frozenset("a"), frozenset("b"), frozenset("c")])) # nameless tips t = TreeNode.read(["((a,b),(c,));"]) self.assertSetEqual(t.subsets(), frozenset( [frozenset("ab")])) self.assertSetEqual(t.subsets(within="abc"), frozenset( [frozenset("ab")])) self.assertSetEqual(t.subsets(include_full=True), frozenset( [frozenset("ab"), frozenset("abc")])) self.assertSetEqual(t.subsets(include_tips=True), frozenset( [frozenset("ab"), frozenset("a"), frozenset("b"), frozenset("c")])) # duplicate names t = TreeNode.read(["((a,b),(c,a));"]) self.assertSetEqual(t.subsets(), frozenset( [frozenset("ab"), frozenset("ca")])) self.assertSetEqual(t.subsets(include_full=True), frozenset( [frozenset("abc"), frozenset("ab"), frozenset("ca")])) self.assertSetEqual(t.subsets(include_tips=True), frozenset( [frozenset("ab"), frozenset("ca"), frozenset("a"), frozenset("b"), frozenset("c")])) def test_bipart(self): """Return a set of tip names on the smaller side of the branch.""" t = self.complex_tree # typical cases (internal node): get smaller side # taxa below node (same as subset) self.assertSetEqual(t.find("int1").bipart(), frozenset("ab")) self.assertSetEqual(t.find("int3").bipart(), frozenset("cd")) self.assertSetEqual(t.find("int5").bipart(), frozenset("ef")) # when clade is larger than half of tree, get remaining taxa self.assertSetEqual(t.find("int4").bipart(), frozenset("abef")) # at root: empty set self.assertSetEqual(t.bipart(), frozenset()) # at tip: singleton self.assertSetEqual(t.find("a").bipart(), frozenset("a")) # when size is equal, get lexicographically smaller side t = self.simple_t self.assertSetEqual(t.find("i1").bipart(), frozenset("ab")) self.assertSetEqual(t.find("i2").bipart(), frozenset("ab")) # an unrooted tree t = TreeNode.read(["((a,(b,c))X,(d,e)Y,f);"]) self.assertSetEqual(t.find("X").bipart(), frozenset("abc")) self.assertSetEqual(t.find("Y").bipart(), frozenset("de")) # single-child internal node t = TreeNode.read(["((a,b),(c)d);"]) self.assertSetEqual(t.find("c").bipart(), frozenset("c")) self.assertSetEqual(t.find("d").bipart(), frozenset("c")) # nameless tips t = TreeNode.read(["((a,b),(c,)d);"]) self.assertSetEqual(t.find("d").bipart(), frozenset("c")) def test_biparts(self): """Return all sets of tip names on the smaller side of each branch.""" # an unrooted, bifurcating tree (typical case) t = TreeNode.read(["(((a,(b,c)),d),(e,f),g);"]) self.assertSetEqual(t.biparts(), frozenset({ frozenset({"e", "f"}), frozenset({"e", "f", "g"}), frozenset({"b", "c"}), frozenset({"a", "b", "c"})})) # a rooted tree with polytomy t = self.complex_tree self.assertSetEqual(t.biparts(), frozenset({ frozenset({"e", "f"}), frozenset({"c", "d"}), frozenset({"a", "b"}), frozenset({"w", "z"}), frozenset({"a", "b", "e", "f"})})) # within given taxa self.assertSetEqual(t.biparts(within="abcdef"), frozenset({ frozenset({"c", "d"}), frozenset({"a", "b"}), frozenset({"e", "f"})})) self.assertSetEqual( t.biparts(within="cbda"), t.biparts(within={"a", "b", "c", "d"})) # within a subtree self.assertSetEqual(t.children[0].biparts(), frozenset({ frozenset({"c", "d"}), frozenset({"a", "b"}), frozenset({"w", "z"})})) # a simple tree with only one bipartition t = self.simple_t self.assertSetEqual(t.biparts(), frozenset({ frozenset({"a", "b"})})) # include singletons (tips) self.assertSetEqual(t.biparts(include_tips=True), frozenset({ frozenset({"a", "b"}), frozenset({"a"}), frozenset({"b"}), frozenset({"c"}), frozenset({"d"})})) # full set pre-computed self.assertSetEqual(t.biparts(full=t.subset()), frozenset({ frozenset({"a", "b"})})) # map to length ("abc" crosses the root) t = TreeNode.read(["(((a:1,b:2):1,c:3):2,((d:4,e:5):2,f:6):2);"]) self.assertDictEqual(t.biparts(map_to_length=True), { frozenset("ab"): 1, frozenset("de"): 2, frozenset("abc"): 4}) # merged lengths self.assertDictEqual(t.biparts(within="abde", map_to_length=True), { frozenset("ab"): 7}) # missing length t.children[0].length = None self.assertDictEqual(t.biparts(map_to_length=True), { frozenset("ab"): 1, frozenset("de"): 2, frozenset("abc"): 2}) # when a basal taxon is excluded t = TreeNode.read(['(((a,b),(c,d)),e);']) self.assertSetEqual(t.biparts(within="abcd"), frozenset( [frozenset("ab")])) # nothing to include self.assertFalse(t.biparts(within=set())) self.assertFalse(t.biparts(within="")) self.assertFalse(t.biparts(within="xyz")) # nameless tips t = TreeNode.read(["(((a,),b),(c,d));"]) self.assertSetEqual(t.biparts(), frozenset({ frozenset({"a", "b"})})) def test_assign_supports(self): """Extract support values of internal nodes.""" # test nodes with support values alone as labels tree = TreeNode.read(["((a,b)75,(c,d)90);"]) tree.assign_supports() node1, node2 = tree.children # check if internal nodes are assigned correct support values self.assertEqual(node1.support, 75) self.assertEqual(node2.support, 90) # check if original node names are cleared self.assertIsNone(node1.name) self.assertIsNone(node2.name) # check if support values are not assigned to root and tips self.assertIsNone(tree.support) for taxon in ("a", "b", "c", "d"): self.assertIsNone(tree.find(taxon).support) # test nodes with support values and branch lengths tree = TreeNode.read(["((a,b)0.85:1.23,(c,d)0.95:4.56);"]) tree.assign_supports() node1, node2 = tree.children self.assertEqual(node1.support, 0.85) self.assertEqual(node2.support, 0.95) # test whether integer or float support values can be correctly parsed tree = TreeNode.read(["((a,b)75,(c,d)80.0,(e,f)97.5,(g,h)0.95);"]) tree.assign_supports() node1, node2, node3, node4 = tree.children self.assertTrue(isinstance(node1.support, int)) self.assertEqual(node1.support, 75) self.assertTrue(isinstance(node2.support, float)) self.assertEqual(node2.support, 80.0) self.assertTrue(isinstance(node3.support, float)) self.assertEqual(node3.support, 97.5) self.assertTrue(isinstance(node4.support, float)) self.assertEqual(node4.support, 0.95) # test support values that are negative or scientific notation (not a # common scenario but can happen) tree = TreeNode.read(["((a,b)-1.23,(c,d)1.23e-4);"]) tree.assign_supports() node1, node2 = tree.children self.assertEqual(node1.support, -1.23) self.assertEqual(node2.support, 0.000123) # test nodes with support and extra label tree = TreeNode.read(["((a,b)'80:X',(c,d)'60:Y');"]) tree.assign_supports() node1, node2 = tree.children self.assertEqual(node1.support, 80) self.assertEqual(node1.name, "X") self.assertEqual(node2.support, 60) self.assertEqual(node2.name, "Y") # test nodes without label, with non-numeric label, and with branch # length only tree = TreeNode.read(["((a,b),(c,d)x,(e,f):1.0);"]) tree.assign_supports() for node in tree.children: self.assertIsNone(node.support) def test_is_bifurcating(self): """Check if tree is bifurcating.""" t = self.simple_t self.assertTrue(t.is_bifurcating()) t = TreeNode.read(["((a,b,c),(d,e))root;"]) self.assertFalse(t.is_bifurcating()) t = TreeNode.read(["((((a,b)c)d)e,f)root;"]) self.assertTrue(t.is_bifurcating()) self.assertFalse(t.is_bifurcating(strict=True)) t = TreeNode.read(["((a,b),(c,d),e)root;"]) self.assertFalse(t.is_bifurcating()) self.assertTrue(t.is_bifurcating(include_self=False)) def test_observed_node_counts(self): """returns observed nodes counts given vector of observed taxon counts """ t = self.simple_t # no taxon observed taxon_counts = {} exp = defaultdict(int) self.assertEqual(t.observed_node_counts(taxon_counts), exp) # error on zero count(s) taxon_counts = {"a": 0} self.assertRaises(ValueError, t.observed_node_counts, taxon_counts) taxon_counts = {"a": 0, "b": 0, "c": 0, "d": 0} self.assertRaises(ValueError, t.observed_node_counts, taxon_counts) # all taxa observed once taxon_counts = {"a": 1, "b": 1, "c": 1, "d": 1} exp = defaultdict(int) exp[t.find("root")] = 4 exp[t.find("i1")] = 2 exp[t.find("i2")] = 2 exp[t.find("a")] = 1 exp[t.find("b")] = 1 exp[t.find("c")] = 1 exp[t.find("d")] = 1 self.assertEqual(t.observed_node_counts(taxon_counts), exp) # some taxa observed twice taxon_counts = {"a": 2, "b": 1, "c": 1, "d": 1} exp = defaultdict(int) exp[t.find("root")] = 5 exp[t.find("i1")] = 3 exp[t.find("i2")] = 2 exp[t.find("a")] = 2 exp[t.find("b")] = 1 exp[t.find("c")] = 1 exp[t.find("d")] = 1 self.assertEqual(t.observed_node_counts(taxon_counts), exp) taxon_counts = {"a": 2, "b": 1, "c": 1, "d": 2} exp = defaultdict(int) exp[t.find("root")] = 6 exp[t.find("i1")] = 3 exp[t.find("i2")] = 3 exp[t.find("a")] = 2 exp[t.find("b")] = 1 exp[t.find("c")] = 1 exp[t.find("d")] = 2 self.assertEqual(t.observed_node_counts(taxon_counts), exp) # some taxa observed, others not observed taxon_counts = {"a": 2, "b": 1} exp = defaultdict(int) exp[t.find("root")] = 3 exp[t.find("i1")] = 3 exp[t.find("a")] = 2 exp[t.find("b")] = 1 self.assertEqual(t.observed_node_counts(taxon_counts), exp) taxon_counts = {"d": 1} exp = defaultdict(int) exp[t.find("root")] = 1 exp[t.find("i2")] = 1 exp[t.find("d")] = 1 self.assertEqual(t.observed_node_counts(taxon_counts), exp) # error on non-tips taxon_counts = {"a": 2, "e": 1} self.assertRaises(MissingNodeError, t.observed_node_counts, taxon_counts) taxon_counts = {"a": 2, "i1": 1} self.assertRaises(MissingNodeError, t.observed_node_counts, taxon_counts) # test with another tree t2 = self.complex_tree taxon_counts = {} exp = defaultdict(int) self.assertEqual(t2.observed_node_counts(taxon_counts), exp) taxon_counts = {"e": 42, "f": 1} exp[t2.root()] = 43 exp[t2.find("int5")] = 43 exp[t2.find("e")] = 42 exp[t2.find("f")] = 1 self.assertEqual(t2.observed_node_counts(taxon_counts), exp) def test_depth(self): """Calculate the distance from a node to root or an ancestor.""" t = TreeNode.read(["((a:0.1,b:0.2)c:0.3,(d:0.4,e)f:0.5)root;"]) a = t.find("a") self.assertAlmostEqual(a.depth(), 0.4) self.assertAlmostEqual(a.depth(t), 0.4) self.assertAlmostEqual(a.depth(include_root=True, missing_as_zero=True), 0.4) self.assertRaises(NoLengthError, a.depth, include_root=True) self.assertAlmostEqual(a.depth(t.find("c")), 0.1) self.assertAlmostEqual(a.depth(t.find("c"), include_root=True), 0.4) self.assertRaises(NoParentError, a.depth, t.find("b")) self.assertAlmostEqual(a.depth(use_length=False), 2.0) self.assertAlmostEqual(a.depth(include_root=True, use_length=False), 3.0) def test_height(self): """Calculate the distance from a node to the farthese tip.""" t = TreeNode.read(["((a:0.1,b:0.2)c:0.3,(d:0.4,e:0.0)f:0.5)root;"]) H, tip = t.height() self.assertAlmostEqual(H, 0.9) self.assertIs(tip, t.find("d")) a = t.find("a") H, tip = a.height() self.assertAlmostEqual(H, 0.0) self.assertIs(tip, a) self.assertAlmostEqual(a.height(include_self=True)[0], 0.1) self.assertAlmostEqual(a.height(include_self=True, use_length=False)[0], 1.0) b = t.find("b") c = t.find("c") H, tip = c.height() self.assertAlmostEqual(H, 0.2) self.assertIs(tip, b) H, tip = c.height(use_length=False) self.assertAlmostEqual(H, 1.0) self.assertIs(tip, a) self.assertAlmostEqual(c.height(include_self=True)[0], 0.5) self.assertAlmostEqual(c.height(include_self=True, use_length=False)[0], 2.0) self.assertRaises(NoLengthError, t.height, include_self=True) H = t.height(include_self=True, missing_as_zero=True)[0] self.assertAlmostEqual(H, 0.9) t.find("e").length = None f = t.find("f") self.assertRaises(NoLengthError, f.height) H = f.height(missing_as_zero=True)[0] self.assertAlmostEqual(H, 0.4) def test_total_length(self): """Calculate total branch length descending from self.""" tr = TreeNode.read([ "(((A:.1,B:1.2)C:.6,(D:.9,E:.6)F:.9)G:2.4,(H:.4,I:.5)J:1.3)K;"]) tdbl = tr.total_length() self.assertAlmostEqual(tdbl, 8.9) # specify nodes sdbl = tr.total_length(["A", "E"]) self.assertAlmostEqual(sdbl, 2.2) sdbl = tr.total_length("AE") self.assertAlmostEqual(sdbl, 2.2) sdbl = tr.total_length([tr.find("A"), tr.find("E")]) self.assertAlmostEqual(sdbl, 2.2) # parameter alias with self.assertWarns(DeprecationWarning): sdbl = tr.total_length(tip_subset="AE") self.assertAlmostEqual(sdbl, 2.2) # missing node self.assertRaises(MissingNodeError, tr.total_length, ["A", "DNE"]) tr = TreeNode.read([ "(((A,B:1.2)C:.6,(D:.9,E:.6)F:.9)G:2.4,(H:.4,I:.5)J:1.3)K;"]) tdbl = tr.total_length() self.assertAlmostEqual(tdbl, 8.8) tr = TreeNode.read([ "(((A,B:1.2)C:.6,(D:.9,E:.6)F)G:2.4,(H:.4,I:.5)J:1.3)K;"]) tdbl = tr.total_length() self.assertAlmostEqual(tdbl, 7.9) # nodes whose LCA is not root tr = TreeNode.read([ "(((A,B:1.2)C:.6,(D:.9,E:.6)F)G:2.4,(H:.4,I:.5)J:1.3)K;"]) tdbl = tr.total_length(["A", "D", "E"]) self.assertAlmostEqual(tdbl, 2.1) # include stem length tdbl = tr.total_length(["A", "D", "E"], include_stem=True) self.assertAlmostEqual(tdbl, 4.5) # nodes whose LCA is root tr = TreeNode.read([ "(((A,B:1.2)C:.6,(D:.9,E:.6)F:.9)G:2.4,(H:.4,I:.5)J:1.3)K;"]) tdbl = tr.total_length(["I", "D", "E"]) self.assertAlmostEqual(tdbl, 6.6) # there is no stem to add tdbl = tr.total_length(["I", "D", "E"], include_stem=True) self.assertAlmostEqual(tdbl, 6.6) # test with a situation where we have unnamed internal nodes tr = TreeNode.read([ "(((A,B:1.2):.6,(D:.9,E:.6)F):2.4,(H:.4,I:.5)J:1.3);"]) tdbl = tr.total_length() self.assertAlmostEqual(tdbl, 7.9) # issue 1847 (ignoring root length) tr = TreeNode.read([ "(((A:.1,B:1.2)C:.6,(D:.9,E:.6)F:.9)G:2.4,(H:.4,I:.5)J:1.3)K;"]) tr.length = 1 tdbl = tr.total_length() self.assertAlmostEqual(tdbl, 8.9) # include root length tdbl = tr.total_length(include_self=True) self.assertAlmostEqual(tdbl, 9.9) # internal nodes tdbl = tr.total_length(["C", "F", "J"]) self.assertAlmostEqual(tdbl, 5.2) # only one node tdbl = tr.total_length("B") self.assertEqual(tdbl, 0.0) self.assertIsInstance(tdbl, float) tdbl = tr.total_length("B", include_self=True) self.assertAlmostEqual(tdbl, 1.2) def test_total_length_subtree(self): """Calculate total branch length of a subtree.""" tr = TreeNode.read([ "(((A,B:1.2)C:.6,(D:.9,E:.6)F:.9)G:2.4,(H:.4,I:.5)J:1.3)K;"]) tsub = tr.children[0] obs = tsub.total_length() self.assertAlmostEqual(obs, 4.2) obs = tsub.total_length(include_self=True) self.assertAlmostEqual(obs, 6.6) obs = tsub.total_length(["D", "E"]) self.assertAlmostEqual(obs, 1.5) obs = tsub.total_length(["D", "E"], include_stem=True) self.assertAlmostEqual(obs, 2.4) obs = tsub.total_length(["D", "E"], include_self=True) self.assertAlmostEqual(obs, 2.4) obs = tsub.total_length(["D", "E"], include_stem=True, include_self=True) self.assertAlmostEqual(obs, 4.8) # node outside subtree self.assertRaises(MissingNodeError, tsub.total_length, ["A", "I"]) def test_distance_nontip(self): # example derived from issue #807, credit @wwood tstr = "((A:1.0,B:2.0)'g__genus1':3.0)root;" tree = TreeNode.read([tstr]) self.assertEqual(tree.find("A").distance(tree.find("g__genus1")), 1.0) def test_distance(self): """Get the path length (patristic) distance between two nodes.""" t = TreeNode.read(["((a:0.1,b:0.2)c:0.3,(d:0.4,e)f:0.5)root;"]) tips = sorted([n for n in t.tips()], key=lambda x: x.name) self.assertAlmostEqual(tips[0].distance(tips[0]), 0.0) self.assertAlmostEqual(tips[0].distance(tips[1]), 0.3) self.assertAlmostEqual(tips[0].distance(tips[2]), 1.3) with self.assertRaises(NoLengthError): tips[0].distance(tips[3]) self.assertAlmostEqual( tips[0].distance(tips[3], missing_as_zero=True), 0.9) self.assertAlmostEqual(tips[1].distance(tips[0]), 0.3) self.assertAlmostEqual(tips[1].distance(tips[1]), 0.0) self.assertAlmostEqual(tips[1].distance(tips[2]), 1.4) with self.assertRaises(NoLengthError): tips[1].distance(tips[3]) self.assertAlmostEqual(tips[2].distance(tips[0]), 1.3) self.assertAlmostEqual(tips[2].distance(tips[1]), 1.4) self.assertAlmostEqual(tips[2].distance(tips[2]), 0.0) with self.assertRaises(NoLengthError): tips[2].distance(tips[3]) def test_distance_count(self): """Get the path distance (edge count) between two nodes.""" t = TreeNode.read(["((a:0.1,b:0.2)c:0.3,(d:0.4,e)f:0.5)root;"]) tips = sorted([n for n in t.tips()], key=lambda x: x.name) self.assertEqual(tips[0].distance(tips[0], False), 0) self.assertEqual(tips[0].distance(tips[1], False), 2) self.assertEqual(tips[0].distance(tips[2], False), 4) self.assertEqual(tips[0].distance(tips[3], False), 4) self.assertEqual(tips[1].distance(tips[0], False), 2) self.assertEqual(tips[1].distance(tips[1], False), 0) self.assertEqual(tips[1].distance(tips[2], False), 4) self.assertEqual(tips[1].distance(tips[3], False), 4) self.assertEqual(tips[2].distance(tips[0], False), 4) self.assertEqual(tips[2].distance(tips[1], False), 4) self.assertEqual(tips[2].distance(tips[2], False), 0) self.assertEqual(tips[2].distance(tips[3], False), 2) def test_maxdist(self): """Get maximum tip-to-tip distance across tree. """ # regular case tree = TreeNode.read([ "((a:0.1,b:0.2)c:0.3,(d:0.4,e:0.5)f:0.6)root;"]) dist, nodes = tree.maxdist() self.assertAlmostEqual(dist, 1.6) self.assertListEqual([n.name for n in nodes], ["e", "b"]) # number of branches dist, nodes = tree.maxdist(use_length=False) self.assertEqual(dist, 4) self.assertListEqual([n.name for n in nodes], ["a", "d"]) # tree with a single-child node and missing lengths tree = TreeNode.read(["((a:1,b:2),c:4,(((d:4,e:5):2):3,f:6));"]) dist, nodes = tree.maxdist() self.assertAlmostEqual(dist, 16) self.assertListEqual([n.name for n in nodes], ["e", "f"]) dist, nodes = tree.maxdist(use_length=False) self.assertEqual(dist, 6) self.assertListEqual([n.name for n in nodes], ["d", "a"]) def test_cophenet_all(self): """Get a tip-to-tip distance matrix of all taxa.""" t = TreeNode.read(["((H:1,G:1):2,(R:0.5,M:0.7):3);"]) exp = DistanceMatrix(np.array([[0. , 2.0, 6.5, 6.7], [2.0, 0. , 6.5, 6.7], [6.5, 6.5, 0. , 1.2], [6.7, 6.7, 1.2, 0. ]]), ["H", "G", "R", "M"]) obs = t.cophenet() self.assertEqual(obs, exp) # makes sure intermediate attributes are clear for node in t.traverse(include_self=True): self.assertFalse(hasattr(node, '_start')) self.assertFalse(hasattr(node, '_stop')) def test_cophenet_endpoints(self): """Get a tip-to-tip distance matrix of selected taxa.""" t = TreeNode.read(["((H:1,G:1):2,(R:0.5,M:0.7):3);"]) names = ["H", "G", "M"] nodes = [t.find(x) for x in names] exp = DistanceMatrix(np.array([[0. , 2.0, 6.7], [2.0, 0. , 6.7], [6.7, 6.7, 0. ]]), names) # specify endpoints by node instance obs = t.cophenet(endpoints=nodes) self.assertEqual(obs, exp) # specify endpoints by name (taxon) obs = t.cophenet(endpoints=names) self.assertEqual(obs, exp) # endpoints can be any iterable (tuple, str, iter, dict...) # but unordered iterable like set is not recommended obs = t.cophenet(endpoints=tuple(names)) self.assertEqual(obs, exp) obs = t.cophenet(endpoints="".join(names)) self.assertEqual(obs, exp) obs = t.cophenet(endpoints=iter(names)) self.assertEqual(obs, exp) obs = t.cophenet(endpoints={x: 0 for x in names}) self.assertEqual(obs, exp) for node in t.traverse(include_self=True): self.assertFalse(hasattr(node, '_start')) self.assertFalse(hasattr(node, '_stop')) # different order names = ["M", "H", "G"] exp = DistanceMatrix(np.array([[0. , 6.7, 6.7], [6.7, 0. , 2.0], [6.7, 2.0, 0. ]]), names) obs = t.cophenet(endpoints=names) self.assertEqual(obs, exp) # only 2 taxa obs = t.cophenet(endpoints="HR") exp = DistanceMatrix(np.array([[0. , 6.5], [6.5, 0. ]]), "HR") self.assertEqual(obs, exp) # only 1 taxon obs = t.cophenet(endpoints="H") exp = DistanceMatrix(np.array([[0. ]]), "H") self.assertEqual(obs, exp) def test_cophenet_counts(self): """Get a tip-to-tip distance matrix in counts.""" t = TreeNode.read(["((H:1,G:1):2,(R:0.5,M:0.7):3);"]) nodes = [t.find("H"), t.find("G"), t.find("M")] names = ["H", "G", "M"] exp = DistanceMatrix(np.array([[0, 2, 4], [2, 0, 4], [4, 4, 0]]), names) obs = t.cophenet(endpoints=names, use_length=False) self.assertEqual(obs, exp) obs = t.cophenet(endpoints=nodes, use_length=False) self.assertEqual(obs, exp) for node in t.traverse(include_self=True): self.assertFalse(hasattr(node, '_start')) self.assertFalse(hasattr(node, '_stop')) def test_cophenet_bad_endpoints(self): t = TreeNode.read(["((H:1,G:1)foo:2,(R:0.5,M:0.7):3);"]) msg = "Node with name 'foo' is not a tip." with self.assertRaises(ValueError) as e: t.cophenet(endpoints=["foo"]) self.assertEqual(str(e.exception), msg) with self.assertRaises(MissingNodeError): t.cophenet(endpoints=["bar"]) with self.assertRaises(DuplicateNodeError): t.cophenet(endpoints=["H", "R", "H"]) def test_cophenet_duplicate_tips(self): t = TreeNode.read(["((H:1,G:1):2,(R:0.5,H:0.7):3);"]) msg = "Tree contains duplicate tip names." with self.assertRaises(DuplicateNodeError) as e: t.cophenet() self.assertEqual(str(e.exception), msg) t = TreeNode.read(["((H:1,G:1):2,(R:0.5,M:0.7):3);"]) msg = "Duplicate tip name 'H' found." with self.assertRaises(DuplicateNodeError) as e: t.cophenet(endpoints="HRH") self.assertEqual(str(e.exception), msg) def test_cophenet_no_name(self): t = TreeNode.read(["((H:1,G:1):2,(R:0.5,M:0.7):3);"]) t.find("R").name = None t.clear_caches() names = ["H", "G", "M"] nodes = [t.find(x) for x in names] exp = DistanceMatrix(np.array([[0. , 2.0, 6.7], [2.0, 0. , 6.7], [6.7, 6.7, 0. ]]), names) # tip without name is ignored obs = t.cophenet() self.assertEqual(obs, exp) # endpoints without nameless tip is not affected obs = t.cophenet(endpoints=names) self.assertEqual(obs, exp) obs = t.cophenet(endpoints=nodes) self.assertEqual(obs, exp) # endpoints with nameless tip raises nodes = [t.children[0].children[0], t.children[1].children[0]] msg = "Cannot find a node without a name." with self.assertRaises(MissingNodeError) as e: t.cophenet(endpoints=nodes) self.assertEqual(str(e.exception), msg) def test_cophenet_no_length(self): t = TreeNode.read(["((a,b)c,(d,e)f);"]) exp_t = TreeNode.read(["((a:0,b:0)c:0,(d:0,e:0)f:0);"]) exp_t_dm = exp_t.cophenet() t_dm = t.cophenet() self.assertEqual(t_dm, exp_t_dm) def test_cophenet_missing_length(self): t = TreeNode.read(["((a,b:6)c:4,(d,e:0)f);"]) exp_t = TreeNode.read(["((a:0,b:6)c:4,(d:0,e:0)f:0);"]) t_dm = t.cophenet() exp_t_dm = exp_t.cophenet() self.assertEqual(t_dm, exp_t_dm) def test_compare_rfd(self): """Return Robinson-Foulds distance.""" # original example t1 = TreeNode.read(["((H,G),(R,M));"]) t2 = TreeNode.read(["(((H,G),R),M);"]) self.assertEqual(t1.compare_rfd(t2), 2) # zero distance to self self.assertEqual(t1.compare_rfd(t2), t2.compare_rfd(t1)) # return proportion self.assertEqual(t1.compare_rfd(t2, proportion=True), 0.5) # two conflicting quartets t1 = TreeNode.read(["((a,b),(c,d));"]) t2 = TreeNode.read(["((a,c),(b,d));"]) self.assertEqual(t1.compare_rfd(t2), 4) self.assertEqual(t1.compare_rfd(t2, proportion=True), 1.0) self.assertEqual(t1.compare_rfd(t2, rooted=False), 2) # same topology but different rooting t1 = TreeNode.read(["(((a,b),c),(d,e));"]) t2 = TreeNode.read(["((a,b),(c,(d,e)));"]) self.assertEqual(t1.compare_rfd(t2), 2) self.assertAlmostEqual(t1.compare_rfd(t2, proportion=True), 1 / 3) self.assertEqual(t1.compare_rfd(t2, rooted=False), 0) # different topologies t1 = TreeNode.read(["(((a,b),c),((d,e),f));"]) t2 = TreeNode.read(["(((a,(b,c)),d),(e,f));"]) self.assertEqual(t1.compare_rfd(t2), 6) self.assertEqual(t1.compare_rfd(t2, proportion=True), 0.75) self.assertEqual(t1.compare_rfd(t2, rooted=False), 4) # unrooted trees t1.unroot() t2.unroot() self.assertEqual(t1.compare_rfd(t2), 4) self.assertEqual(t1.compare_rfd(t2, rooted=True), 6) # make self a subtree (therefore rooted) t1.parent = TreeNode("x") self.assertEqual(t1.compare_rfd(t2), 6) self.assertEqual(t1.compare_rfd(t2, rooted=False), 4) t1.parent = None # with polytomy t1 = TreeNode.read(["((a,b,(c,d)),((e,f),(g,h),i));"]) t2 = TreeNode.read(["((((a,b),c,d),e),((f,g,h),i));"]) self.assertEqual(t1.compare_rfd(t2), 8) self.assertEqual(t1.compare_rfd(t2, rooted=False), 6) c1, c2 = t1.children[0], t2.children[0] self.assertEqual(c1.compare_rfd(c2), 2) self.assertEqual(c1.compare_rfd(c2, rooted=False), 0) def test_compare_wrfd(self): """Return weighted Robinson-Foulds distance or variants.""" t1 = TreeNode.read(["((a:1,b:2):1,c:4,((d:4,e:5):2,f:6):1);"]) t2 = TreeNode.read(["((a:3,(b:2,c:2):1):3,d:8,(e:5,f:6):2);"]) # weighted RF distance (matches phangorn::wRF.dist and dendropy's # weighted_robinson_foulds_distance) self.assertAlmostEqual(t1.compare_wrfd(t2), 16) self.assertAlmostEqual(t1.compare_wrfd(t2, metric="cityblock"), 16) # KF branch score distance (matches phangorn::KF.dist and dendropy's # euclidean_distance) self.assertAlmostEqual(t1.compare_wrfd(t2, metric="euclidean"), 6.1644140) # no terminal branches (matches ape::dist.topo with method="score") self.assertAlmostEqual(t1.compare_wrfd( t2, metric="euclidean", include_tips=False), 3.7416574) # force rooted (considers subsets not bipartitions) self.assertAlmostEqual(t1.compare_wrfd(t2, rooted=True), 18) self.assertAlmostEqual( t1.compare_wrfd(t2, metric="euclidean", rooted=True), 6.6332496) # make self a subtree, therefore it is considered as rooted t1.parent = TreeNode("x") self.assertAlmostEqual(t1.compare_wrfd(t2), 18) t1.parent = None # correlation distance self.assertAlmostEqual(t1.compare_wrfd(t2, metric="correlation"), 0.3164447) # unit correlation distance self.assertAlmostEqual(t1.compare_wrfd(t2, metric="unitcorr"), 0.1582224) # correlation distance is independent of scale for node in t2.traverse(include_self=False): node.length *= 10 self.assertAlmostEqual(t1.compare_wrfd(t2, metric="correlation"), 0.3164447) def test_compare_subsets(self): """Return the amount of unshared subsets.""" t = TreeNode.read(["((H,G),(R,M));"]) t2 = TreeNode.read(["(((H,G),R),M);"]) t4 = TreeNode.read(["(((H,G),(O,R)),X);"]) result = t.compare_subsets(t) self.assertEqual(result, 0) result = t.compare_subsets(t2) self.assertEqual(result, 0.5) result = t.compare_subsets(t4) self.assertEqual(result, 0.6) result = t.compare_subsets(t4, proportion=False) self.assertEqual(result, 3) result = t.compare_subsets(t4, shared_only=True) self.assertEqual(result, 0) with self.assertWarns(DeprecationWarning): result = t.compare_subsets(self.TreeRoot, exclude_absent_taxa=True) self.assertEqual(result, 1) result = t.compare_subsets(self.TreeRoot) self.assertEqual(result, 1) result = TreeNode('x').compare_subsets(TreeNode('y')) self.assertEqual(result, 1) def test_compare_biparts(self): """Return the amount of unshared bipartitions.""" t = TreeNode.read(["((H,G),(R,M));"]) t2 = TreeNode.read(["(((H,G),R),M);"]) t3 = TreeNode.read(["(((H,R),G),M);"]) result = t.compare_biparts(t) self.assertEqual(result, 0) result = t.compare_biparts(t2) self.assertEqual(result, 0) result = t.compare_biparts(t3) self.assertEqual(result, 1) result = t.compare_biparts(t3, proportion=False) self.assertEqual(result, 2) result = t.compare_biparts(self.TreeRoot) self.assertEqual(result, 1) result = TreeNode('x').compare_biparts(TreeNode('y')) self.assertEqual(result, 1) def test_compare_cophenet_old(self): """Return distance between two trees based on tip distances.""" t = TreeNode.read(["((H:1,G:1):2,(R:0.5,M:0.7):3);"]) t2 = TreeNode.read(["(((H:1,G:1,O:1):2,R:3):1,X:4);"]) # default behavior (half correlation, use length, include self) # note: common taxa are H, G, R (only) # note: version 0.7.0 will ignore self by default (see below) obs = t.compare_cophenet(t2, ignore_self=False) m1 = np.array([[0, 2, 6.5], [2, 0, 6.5], [6.5, 6.5, 0]]) m2 = np.array([[0, 2, 6], [2, 0, 6], [6, 6, 0]]) r = pearsonr(m1.flat, m2.flat)[0] exp = (1 - r) / 2 self.assertAlmostEqual(obs, exp) # sample a subset of taxa # note: all common taxa are selected, despite that the default # shuffler function is stochastic. obs = t.compare_cophenet(t2, sample=3, ignore_self=False) self.assertAlmostEqual(obs, exp) # 4 common taxa, custom shuffler, still picking H, G, R tx = TreeNode.read(["((H:1,G:1):2,(R:0.5,M:0.7,U:5):3);"]) t2x = TreeNode.read(["(((H:1,G:1,O:1):2,R:3,U:10):1,X:4);"]) obs = tx.compare_cophenet(t2x, sample=3, shuffler=list.sort, ignore_self=False) self.assertAlmostEqual(obs, exp) with self.assertWarns(DeprecationWarning): obs = tx.compare_cophenet(t2x, sample=3, shuffle_f=list.sort, ignore_self=False) self.assertAlmostEqual(obs, exp) # sample too large with self.assertRaises(ValueError): tx.compare_cophenet(t2x, sample=10, ignore_self=False) # no common taxa t3 = TreeNode.read(["(((Z:1,Y:1,X:1):2,W:3):1,V:4);"]) with self.assertRaises(ValueError): t.compare_cophenet(t3, ignore_self=False) # single common taxon t4 = TreeNode.read(["(((R:1,Y:1,X:1):2,W:3):1,V:4);"]) with catch_warnings(): simplefilter("ignore", category=RuntimeWarning) self.assertTrue(np.isnan(t.compare_cophenet(t4, ignore_self=False))) # two common taxa t5 = TreeNode.read(["(((R:1,Y:1,X:1):2,M:3):1,V:4);"]) self.assertAlmostEqual(t.compare_cophenet(t5, ignore_self=False), 0) with catch_warnings(): simplefilter("ignore", category=RuntimeWarning) self.assertTrue(np.isnan(t.compare_cophenet(t5, ignore_self=True))) def test_compare_cophenet_new(self): """Return distance between two trees based on tip distances.""" # This test case is more comprehensive and reflects the new behavior # and options of the method. t1 = TreeNode.read(["((a:1,b:2):1,c:4,((d:4,e:5):2,f:6):1);"]) t2 = TreeNode.read(["((a:3,(b:2,c:2):1):3,d:8,(e:5,f:6):2);"]) # default behavior (old, changed in version 0.7.0) obs = t1.compare_cophenet(t2, ignore_self=False) self.assertAlmostEqual(obs, 0.0453512) # new default behavior obs = t1.compare_cophenet(t2) self.assertAlmostEqual(obs, 0.1413090) # path length distance (matches phangorn::path.dist(use.weight=TRUE)) obs = t1.compare_cophenet(t2, metric="euclidean") self.assertAlmostEqual(obs, 13.7113092) obs = t1.compare_cophenet(t2, metric=euclidean) self.assertAlmostEqual(obs, 13.7113092) with self.assertWarns(DeprecationWarning): obs = t1.compare_cophenet(t2, dist_f=euclidean) self.assertAlmostEqual(obs, 13.7113092) # path distance (matches phangorn::path.dist) obs = t1.compare_cophenet( t2, metric="euclidean", use_length=False) self.assertAlmostEqual(obs, 4.0) # unit correlation distance is independent of tree scale for node in t2.traverse(include_self=False): node.length *= 3 obs = t1.compare_cophenet(t2) self.assertAlmostEqual(obs, 0.1413090) # ------------------------------------------------ # Tree indexing and searching # ------------------------------------------------ def test_has_caches(self): """Check if tree has caches.""" t = self.simple_t self.assertTupleEqual(t.has_caches(), (None, False)) t.find("a") self.assertTupleEqual(t.has_caches(), (None, True)) t.cache_attr(lambda n: 1, "node_count", sum) self.assertTupleEqual(t.has_caches(), ({"node_count"}, True)) t.clear_caches() self.assertTupleEqual(t.has_caches(), (None, False)) def test_clear_caches(self): # delete lookup caches t = TreeNode.read(["((a:1.2,b:1.6)c:0.3,(d:0.8,e:1.0)f:0.6)g;"]) t.create_caches() keys = ("_tip_cache", "_non_tip_cache") for key in keys: self.assertTrue(hasattr(t, key)) t.clear_caches(attr=False) for key in keys: self.assertFalse(hasattr(t, key)) # delete all attribute caches t.cache_attr(lambda n: [n.name] if n.is_tip() else [], "tip_names") delattr(t.children[0], "tip_names") t.clear_caches(lookup=False) self.assertFalse(hasattr(t, "_registered_caches")) for node in t.traverse(include_self=True): self.assertFalse(hasattr(node, "tip_names")) # delete individual attribute caches t.cache_attr(lambda n: 1, "node_count", sum) t.cache_attr(lambda n: n.length or 0.0, "length_sum", sum) t.clear_caches(attr="node_count") self.assertTrue(hasattr(t, "_registered_caches")) self.assertNotIn("node_count", t._registered_caches) self.assertIn("length_sum", t._registered_caches) for node in t.traverse(include_self=True): self.assertFalse(hasattr(node, "node_count")) self.assertTrue(hasattr(node, "length_sum")) delattr(t.children[1], "length_sum") t.clear_caches(attr="length_sum") self.assertFalse(hasattr(t, "_registered_caches")) for node in t.traverse(include_self=True): self.assertFalse(hasattr(node, "length_sum")) def test_cache_attr(self): # cache names of all descending tips t = TreeNode.read(["((a,b)c,(d,e)f)g;"]) f = lambda n: [n.name] if n.is_tip() else [] t.cache_attr(f, "tip_names") self.assertIn("tip_names", t._registered_caches) self.assertListEqual(t.tip_names, list("abde")) self.assertListEqual(t.children[0].tip_names, list("ab")) self.assertListEqual(t.children[1].tip_names, list("de")) # don't register as cache t.clear_caches() t.cache_attr(f, "tip_names", register=False) self.assertFalse(hasattr(t, "_registered_caches")) self.assertListEqual(t.tip_names, list("abde")) # tuple instead of list t.cache_attr(f, "tip_names", tuple) self.assertTupleEqual(t.tip_names, tuple("abde")) # set and frozenset t.cache_attr(f, "tip_names", set) self.assertIs(type(t.tip_names), set) self.assertSetEqual(t.tip_names, set("abde")) t.cache_attr(f, "tip_names", frozenset) self.assertIs(type(t.tip_names), frozenset) self.assertSetEqual(t.tip_names, set("abde")) # cache number of nodes per clade t = TreeNode.read(["((a:1.2,b:1.6)c:0.3,(d:0.8,e:1.0)f:0.6)g;"]) f = lambda n: 1 t.cache_attr(f, "node_count", sum) self.assertEqual(t.node_count, 7) self.assertEqual(t.children[0].node_count, 3) self.assertEqual(t.children[1].node_count, 3) # cache total branch length per clade t.clear_caches() f = lambda n: n.length or 0.0 t.cache_attr(f, "total_length", sum) self.assertAlmostEqual(t.total_length, 5.5) self.assertAlmostEqual(t.children[0].total_length, 3.1) self.assertAlmostEqual(t.children[1].total_length, 2.4) # cache accumulative distance from tips using a custom function t.clear_caches() dist_f = lambda x: np.array(x.length or 0.0, ndmin=1) comb_f = lambda prev, curr: np.concatenate(prev) + curr if prev else curr t.cache_attr(dist_f, "accu_dist", comb_f) npt.assert_almost_equal(t.accu_dist, np.array([1.5, 1.9, 1.4, 1.6])) npt.assert_almost_equal(t.children[0].accu_dist, np.array([1.5, 1.9])) # cache and combine accumulative distance using a custom function t.clear_caches() def depths_f(node): if node.is_tip(): return [0.0] else: return [y + (x.length or 0.0) for x in node.children for y in x.depths] t.cache_attr(depths_f, "depths", None) for obs, exp in zip(t.depths, [1.5, 1.9, 1.4, 1.6]): self.assertAlmostEqual(obs, exp) for obs, exp in zip(t.children[0].depths, [1.2, 1.6]): self.assertAlmostEqual(obs, exp) # invalid cache type msg = "Cache type is invalid." with self.assertRaisesRegex(TypeError, msg): t.cache_attr(sum, "missing", "invalid") def test_assign_ids(self): """Assign IDs to the tree""" t1 = TreeNode.read(["(((a,b),c),(e,f),(g));"]) t2 = TreeNode.read(["(((a,b),c),(e,f),(g));"]) t3 = TreeNode.read(["((g),(e,f),(c,(a,b)));"]) t1_copy = t1.copy() t1.assign_ids() t2.assign_ids() t3.assign_ids() t1_copy.assign_ids() self.assertEqual([(n.name, n.id) for n in t1.traverse()], [(n.name, n.id) for n in t2.traverse()]) self.assertEqual([(n.name, n.id) for n in t1.traverse()], [(n.name, n.id) for n in t1_copy.traverse()]) self.assertNotEqual([(n.name, n.id) for n in t1.traverse()], [(n.name, n.id) for n in t3.traverse()]) def test_assign_ids_index_tree(self): """assign_ids and index_tree should assign the same IDs""" t1 = TreeNode.read(["(((a,b),c),(d,e));"]) t2 = TreeNode.read(["(((a,b),(c,d)),(e,f));"]) t3 = TreeNode.read(["(((a,b,c),(d)),(e,f));"]) t1_copy = t1.copy() t2_copy = t2.copy() t3_copy = t3.copy() t1.assign_ids() t1_copy.index_tree() t2.assign_ids() t2_copy.index_tree() t3.assign_ids() t3_copy.index_tree() self.assertEqual([n.id for n in t1.traverse()], [n.id for n in t1_copy.traverse()]) self.assertEqual([n.id for n in t2.traverse()], [n.id for n in t2_copy.traverse()]) self.assertEqual([n.id for n in t3.traverse()], [n.id for n in t3_copy.traverse()]) def test_index_tree(self): """index_tree should produce correct index and node map""" # test for first tree: contains singleton outgroup t1 = TreeNode.read(["(((a,b),c),(d,e));"]) t2 = TreeNode.read(["(((a,b),(c,d)),(e,f));"]) t3 = TreeNode.read(["(((a,b,c),(d)),(e,f));"]) id_1, child_1 = t1.index_tree() nodes_1 = [n.id for n in t1.traverse(self_before=False, self_after=True)] self.assertEqual(nodes_1, [0, 1, 2, 3, 6, 4, 5, 7, 8]) npt.assert_equal(child_1, np.array([[2, 0, 1], [6, 2, 3], [7, 4, 5], [8, 6, 7]])) # test for second tree: strictly bifurcating id_2, child_2 = t2.index_tree() nodes_2 = [n.id for n in t2.traverse(self_before=False, self_after=True)] self.assertEqual(nodes_2, [0, 1, 4, 2, 3, 5, 8, 6, 7, 9, 10]) npt.assert_equal(child_2, np.array([[4, 0, 1], [5, 2, 3], [8, 4, 5], [9, 6, 7], [10, 8, 9]])) # test for third tree: contains trifurcation and single-child parent id_3, child_3 = t3.index_tree() nodes_3 = [n.id for n in t3.traverse(self_before=False, self_after=True)] self.assertEqual(nodes_3, [0, 1, 2, 4, 3, 5, 8, 6, 7, 9, 10]) npt.assert_equal(child_3, np.array([[4, 0, 2], [5, 3, 3], [8, 4, 5], [9, 6, 7], [10, 8, 9]])) # test for single-node tree t1 = TreeNode.read(["root;"]) id_index, child_index = t1.index_tree() self.assertEqual(id_index[0], t1) npt.assert_equal(child_index, np.array([[]])) def test_create_caches(self): t = TreeNode.read(["(((a,b)x,(c,d)x,e),(f,g)y)root;"]) # create a lookup table for a fresh tree t.create_caches() self.assertEqual(t._tip_cache["a"].name, "a") self.assertEqual(len(t._non_tip_cache["x"]), 2) self.assertEqual(len(t._non_tip_cache["y"][0].children), 2) # skip re-creating a lookup table if the tree already has it t._tip_cache["a"] = None t.create_caches() self.assertIsNone(t._tip_cache["a"]) # can create a lookup table for the entire tree from any node node = t.find("b") t.clear_caches(attr=False) node.create_caches() self.assertEqual(t._tip_cache["c"].name, "c") self.assertListEqual([ x.name for x in t._non_tip_cache["y"][0].children], ["f", "g"]) # raise if duplicate tip names found msg = "Duplicate tip name 'a' found." with self.assertRaisesRegex(DuplicateNodeError, msg): TreeNode.read(["(a,a);"]).create_caches() def test_find(self): t = TreeNode.read(["((a,b)c,(d,e)f);"]) # find an internal node exp = t.children[0] obs = t.find("c") self.assertEqual(obs, exp) # input is node object obs = t.find(exp) self.assertIs(obs, exp) # find a tip exp = t.children[0].children[1] obs = t.find("b") self.assertEqual(obs, exp) # input is tip object obs = t.find(exp) self.assertEqual(obs, exp) # name not found msg = "Node 'missing' is not found in the tree." with self.assertRaisesRegex(MissingNodeError, msg): t.find("missing") # input is a node but not in current tree with self.assertRaisesRegex(MissingNodeError, msg): t.find(TreeNode("missing")) # name is None msg = "Cannot find a node without a name." with self.assertRaisesRegex(MissingNodeError, msg): t.find(None) with self.assertRaisesRegex(MissingNodeError, msg): t.find(TreeNode()) # input node name matches a tip but it's not in the current tree msg = "Node 'a' is not found in the tree." with self.assertRaisesRegex(MissingNodeError, msg): t.find(TreeNode("a")) # input node name matches a non-tip but it's not in the current tree msg = "Node 'c' is not found in the tree." with self.assertRaisesRegex(MissingNodeError, msg): t.find(TreeNode("c")) def test_find_all(self): t = TreeNode.read(["((a,b)c,((d,e)c)c,(f,(g,h)c)a)root;"]) # find all nodes with a given name exp = [t.children[2], t.children[0].children[0]] obs = t.find_all("a") self.assertEqual(obs, exp) exp = [t.children[0], t.children[1].children[0], t.children[1], t.children[2].children[1]] obs = t.find_all("c") self.assertEqual(obs, exp) # input is TreeNode obs = t.find_all(t.children[0]) self.assertEqual(obs, exp) # find root itself obs = t.find_all("root") self.assertEqual(len(obs), 1) self.assertIs(obs[0], t) # node not found msg = "Node 'missing' is not found." with self.assertRaisesRegex(MissingNodeError, msg): t.find_all("missing") # node has no name msg = "Cannot find nodes without a name." with self.assertRaisesRegex(MissingNodeError, msg): t.find_all(None) with self.assertRaisesRegex(MissingNodeError, msg): t.find_all(TreeNode()) def test_find_by_id(self): """Find a node by id""" t1 = TreeNode.read(["((,),(,,));"]) t2 = TreeNode.read(["((,),(,,));"]) exp = t1.children[1] obs = t1.find_by_id(6) # right inner node with 3 children self.assertEqual(obs, exp) exp = t2.children[1] obs = t2.find_by_id(6) # right inner node with 3 children self.assertEqual(obs, exp) with self.assertRaises(MissingNodeError): t1.find_by_id(100) def test_find_by_func(self): """Find nodes by a function""" t = TreeNode.read(["((a,b)c,(d,e)f);"]) def func(x): return x.parent == t.find("c") exp = ["a", "b"] obs = [n.name for n in t.find_by_func(func)] self.assertEqual(obs, exp) # ------------------------------------------------ # Tree visualization # ------------------------------------------------ def test_ascii_art(self): """Make some ascii trees""" # unlabeled internal node tr = TreeNode.read(["(B:0.2,(C:0.3,D:0.4):0.6)F;"]) obs = tr.ascii_art(show_internal=True, compact=False) exp = (" /-B\n" "-F-------|\n" " | /-C\n" " \\--------|\n" " \\-D") self.assertEqual(obs, exp) obs = tr.ascii_art(show_internal=True, compact=True) exp = ("-F------- /-B\n" " \\-------- /-C\n" " \\-D") self.assertEqual(obs, exp) obs = tr.ascii_art(show_internal=False, compact=False) exp = (" /-B\n" "---------|\n" " | /-C\n" " \\--------|\n" " \\-D") self.assertEqual(obs, exp) def test_ascii_art_with_support(self): """Make some ascii trees with support values""" tr = TreeNode.read(["(B:0.2,(C:0.3,D:0.4)90:0.6)F;"]) exp = " /-B\n-F-------|\n | /-C\n "\ " \\90------|\n \\-D" obs = tr.ascii_art(show_internal=True, compact=False) self.assertEqual(obs, exp) tr.assign_supports() obs = tr.ascii_art(show_internal=True, compact=False) self.assertEqual(obs, exp) tr = TreeNode.read(["((A,B)75,(C,D)'80:spA');"]) exp = " /-A\n /75------|\n | "\ " \\-B\n---------|\n | /-C\n \\"\ "80:spA--|\n \\-D" obs = tr.ascii_art(show_internal=True, compact=False) self.assertEqual(obs, exp) tr.assign_supports() obs = tr.ascii_art(show_internal=True, compact=False) self.assertEqual(obs, exp) def test_ascii_art_three_children(self): obs = TreeNode.read(["(a,(b,c,d));"]).ascii_art() self.assertEqual(obs, exp_ascii_art_three_children) # ------------------------------------------------ # Format conversion # ------------------------------------------------ def test_from_linkage_matrix(self): # Ensure matches: http://www.southampton.ac.uk/~re1u06/teaching/upgma/ lnkmat = np.asarray([[1.0, 5.0, 1.0, 2.0], [0.0, 3.0, 8.0, 2.0], [6.0, 7.0, 12.5, 3.0], [8.0, 9.0, 16.5, 5.0], [2.0, 10.0, 29.0, 6.0], [4.0, 11.0, 34.0, 7.0]]) names = ["A", "B", "C", "D", "E", "F", "G"] obs = TreeNode.from_linkage_matrix(lnkmat, names) self.assertIsInstance(obs, TreeNode) exp = ("(E:17.0,(C:14.5,((A:4.0,D:4.0):4.25,(G:6.25,(B:0.5,F:0.5)" ":5.75):2.0):6.25):2.5);\n") self.assertEqual(str(obs), exp) obs = TreeNodeSubclass.from_linkage_matrix(lnkmat, names) self.assertIsInstance(obs, TreeNodeSubclass) obs = TreeNode.from_linkage_matrix(lnkmat.tolist(), names) self.assertEqual(str(obs), exp) obs = TreeNode.from_linkage_matrix(lnkmat, tuple(names)) self.assertEqual(str(obs), exp) obs = TreeNode.from_linkage_matrix(lnkmat, np.array(names)) self.assertEqual(str(obs), exp) msg = "Number of names must be number of rows in the linkage matrix plus one." with self.assertRaises(ValueError) as e: TreeNode.from_linkage_matrix(lnkmat, names[:-1]) self.assertEqual(str(e.exception), msg) def test_from_taxonomy(self): lineages = [("1", ["a", "b", "c", "d", "e", "f", "g"]), ("2", ["a", "b", "c", None, None, "x", "y"]), ("3", ["h", "i", "j", "k", "l", "m", "n"]), ("4", ["h", "i", "j", "k", "l", "m", "q"]), ("5", ["h", "i", "j", "k", "l", "m", "n"])] exp = TreeNode.read([ "((((((((1)g)f)e)d,((((2)y)x)))c)b)a," "(((((((3,5)n,(4)q)m)l)k)j)i)h);"]) # input as 2-element tuples obs = TreeNode.from_taxonomy(lineages) self.assertIs(type(obs), TreeNode) self.assertEqual(obs.compare_subsets(exp), 0.0) obs = TreeNodeSubclass.from_taxonomy(lineages) self.assertIs(type(obs), TreeNodeSubclass) # input as dictionary dict_ = dict(lineages) obs = TreeNode.from_taxonomy(dict_) self.assertEqual(obs.compare_subsets(exp), 0.0) # input as data frame df_ = pd.DataFrame([x[1] for x in lineages], [x[0] for x in lineages]) obs = TreeNode.from_taxonomy(df_) self.assertEqual(obs.compare_subsets(exp), 0.0) # input as strings with Greengenes2/GTDB style ranks and unassigned taxa str_lineages = [ ("1", "d__Bacteria; p__Bacillota; c__Clostridia"), ("2", "d__Bacteria; p__Bacillota; c__Bacilli"), ("3", "d__Bacteria; p__Bacteroidota; c__Sphingobacteriia"), ("4", "d__Archaea; p__Halobacteriota; c__Thermoplasmata; s__"), ("5", "d__Archaea; p__Halobacteriota; c__Thermoplasmata"), ("6", "d__Archaea; p__Halobacteriota; c__Halobacteria"), ("7", "d__Archaea; p__Halobacteriota; c__Halobacteria; s__"), ("8", "d__Bacteria; p__Bacteroidota; c__Sphingobacteriia"), ("9", "d__Bacteria; p__Bacteroidota; c__Cytophagia; s__")] # By default extract_rank is False, so the node names include the rank str_exp_no_extract = TreeNode.read([ "((((1)c__Clostridia,(2)c__Bacilli)p__Bacillota," "((3,8)c__Sphingobacteriia,(9)c__Cytophagia)p__Bacteroidota)d__Bacteria," "(((4,5)c__Thermoplasmata,(6,7)c__Halobacteria)p__Halobacteriota)d__Archaea);" ]) obs_str_no_extract = TreeNode.from_taxonomy(str_lineages) self.assertEqual(obs_str_no_extract.compare_subsets(str_exp_no_extract), 0.0) # verify rank attributes even when not extracted self.assertEqual(obs_str_no_extract.find("d__Bacteria").rank, "d") self.assertEqual(obs_str_no_extract.find("p__Bacillota").rank, "p") self.assertEqual(obs_str_no_extract.find("c__Thermoplasmata").rank, "c") self.assertFalse(hasattr(obs_str_no_extract.find("1"), "rank")) # when extract_rank is True str_exp_extract = TreeNode.read([ "((((1)Clostridia,(2)Bacilli)Bacillota," "((3,8)Sphingobacteriia,(9)Cytophagia)Bacteroidota)Bacteria," "(((4,5)Thermoplasmata,(6,7)Halobacteria)Halobacteriota)Archaea);" ]) obs_str_extract = TreeNode.from_taxonomy(str_lineages, extract_rank=True) self.assertEqual(obs_str_extract.compare_subsets(str_exp_extract), 0.0) # verify rank attributes self.assertEqual(obs_str_extract.find("Bacteria").rank, "d") self.assertEqual(obs_str_extract.find("Bacillota").rank, "p") self.assertEqual(obs_str_extract.find("Thermoplasmata").rank, "c") self.assertFalse(hasattr(obs_str_extract.find("1"), "rank")) # verify mixture of ranked and unranked taxa raises ValueError mixed_lineages = [ ("1", "d__Bacteria; p__Bacillota"), ("2", "Archaea; Halobacteriota") ] with self.assertRaisesRegex(ValueError, "mixture is erroneous"): TreeNode.from_taxonomy(mixed_lineages) def test_to_taxonomy(self): input_lineages = {"1": ["a", "b", "c", "d", "e", "f", "g"], "2": ["a", "b", "c", None, None, "x", "y"], "3": ["h", "i", "j", "k", "l", "m", "n"], "4": ["h", "i", "j", "k", "l", "m", "q"], "5": ["h", "i", "j", "k", "l", "m", "n"]} tree = TreeNode.from_taxonomy(input_lineages.items()) exp = sorted(input_lineages.items()) obs = [(n.name, lin) for n, lin in tree.to_taxonomy(allow_empty=True)] self.assertEqual(sorted(obs), exp) def test_to_taxonomy_filter(self): input_lineages = {"1": ["a", "b", "c", "d", "e", "f", "g"], "2": ["a", "b", "c", None, None, "x", "y"], "3": ["h", "i", "j", "k", "l"], # test jagged "4": ["h", "i", "j", "k", "l", "m", "q"], "5": ["h", "i", "j", "k", "l", "m", "n"]} tree = TreeNode.from_taxonomy(input_lineages.items()) def f(node, lin): return "k" in lin or "x" in lin exp = [("2", ["a", "b", "c", "x", "y"]), ("3", ["h", "i", "j", "k", "l"]), ("4", ["h", "i", "j", "k", "l", "m", "q"]), ("5", ["h", "i", "j", "k", "l", "m", "n"])] obs = [(n.name, lin) for n, lin in tree.to_taxonomy(filter_f=f)] self.assertEqual(sorted(obs), exp) def test_from_taxdump(self): # same example as in skbio.io.format.taxdump nodes = pd.DataFrame([ [1, 1, "no rank"], [2, 131567, "superkingdom"], [543, 91347, "family"], [548, 570, "species"], [561, 543, "genus"], [562, 561, "species"], [570, 543, "genus"], [620, 543, "genus"], [622, 620, "species"], [766, 28211, "order"], [1224, 2, "phylum"], [1236, 1224, "class"], [28211, 1224, "class"], [91347, 1236, "order"], [118884, 1236, "no rank"], [126792, 36549, "species"], [131567, 1, "no rank"], [585056, 562, "no rank"], [1038927, 562, "no rank"], [2580236, 488338, "species"]], columns=["tax_id", "parent_tax_id", "rank"]).set_index("tax_id") names = pd.DataFrame([ [1, "root", np.nan, "scientific name"], [2, "Bacteria", "Bacteria ", "scientific name"], [2, "eubacteria", np.nan, "genbank common name"], [543, "Enterobacteriaceae", np.nan, "scientific name"], [548, "Klebsiella aerogenes", np.nan, "scientific name"], [561, "Escherichia", np.nan, "scientific name"], [562, "\"Bacillus coli\" Migula 1895", np.nan, "authority"], [562, "Escherichia coli", np.nan, "scientific name"], [562, "Escherichia/Shigella coli", np.nan, "equivalent name"], [570, "Donovania", np.nan, "synonym"], [570, "Klebsiella", np.nan, "scientific name"], [620, "Shigella", np.nan, "scientific name"], [622, "Shigella dysenteriae", np.nan, "scientific name"], [766, "Rickettsiales", np.nan, "scientific name"], [1224, "Proteobacteria", np.nan, "scientific name"], [1236, "Gammaproteobacteria", np.nan, "scientific name"], [28211, "Alphaproteobacteria", np.nan, "scientific name"], [91347, "Enterobacterales", np.nan, "scientific name"], [118884, "unclassified Gammaproteobacteria", np.nan, "scientific name"], [126792, "Plasmid pPY113", np.nan, "scientific name"], [131567, "cellular organisms", np.nan, "scientific name"], [585056, "Escherichia coli UMN026", np.nan, "scientific name"], [1038927, "Escherichia coli O104:H4", np.nan, "scientific name"], [2580236, "synthetic Escherichia coli Syn61", np.nan, "scientific name"]], columns=["tax_id", "name_txt", "unique_name", "name_class"]).set_index("tax_id") # nodes without names (use tax_id as name) obs = TreeNode.from_taxdump(nodes) exp = ("(((((((((585056,1038927)562)561,(548)570,(622)620)543)91347," "118884)1236,(766)28211)1224)2)131567)1;") self.assertEqual(str(obs).rstrip(), exp) self.assertEqual(obs.count(), 18) self.assertEqual(obs.count(tips=True), 6) # default scenario (nodes and names) obs = TreeNode.from_taxdump(nodes, names) # check tree is in same size self.assertEqual(obs.count(), 18) self.assertEqual(obs.count(tips=True), 6) # check id, name and rank are correctly set at root self.assertEqual(obs.id, 1) self.assertEqual(obs.name, "root") self.assertEqual(obs.rank, "no rank") # check an internal node node = obs.find("Enterobacteriaceae") self.assertEqual(node.id, 543) self.assertEqual(node.rank, "family") # check its children (which should preserve input order) self.assertEqual(len(node.children), 3) self.assertListEqual([x.name for x in node.children], [ "Escherichia", "Klebsiella", "Shigella"]) # check that non-scientific name isn"t used with self.assertRaises(MissingNodeError): obs.find("Donovania") # name as a dictionary names = names[names["name_class"] == "scientific name"][ "name_txt"].to_dict() obs = TreeNode.from_taxdump(nodes, names) self.assertEqual(obs.count(), 18) self.assertEqual(obs.name, "root") self.assertEqual(obs.find("Enterobacteriaceae").id, 543) # nodes has no top level nodes = pd.DataFrame([ [2, 1, "A"], [3, 2, "B"], [1, 3, "C"]], columns=["tax_id", "parent_tax_id", "rank"]).set_index("tax_id") with self.assertRaises(ValueError) as ctx: TreeNode.from_taxdump(nodes) self.assertEqual(str(ctx.exception), "There is no top-level node.") # nodes has more than one top level nodes = pd.DataFrame([ [1, 1, "A"], [2, 2, "B"], [3, 3, "C"]], columns=["tax_id", "parent_tax_id", "rank"]).set_index("tax_id") with self.assertRaises(ValueError) as ctx: TreeNode.from_taxdump(nodes) self.assertEqual(str( ctx.exception), "There are more than one top-level node.") def test_to_array(self): """Convert a tree to arrays""" t = TreeNode.read([ "(((a:1,b:2,c:3)x:4,(d:5)y:6)z:7,(e:8,f:9)z:10);"]) id_index, child_index = t.index_tree() arrayed = t.to_array() self.assertEqual(id_index, arrayed["id_index"]) npt.assert_equal(child_index, arrayed["child_index"]) exp = np.array([1, 2, 3, 5, 4, 6, 8, 9, 7, 10, np.nan]) obs = arrayed["length"] npt.assert_equal(obs, exp) exp = np.array(["a", "b", "c", "d", "x", "y", "e", "f", "z", "z", None]) obs = arrayed["name"] npt.assert_equal(obs, exp) exp = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) obs = arrayed["id"] npt.assert_equal(obs, exp) def test_to_array_attrs(self): t = TreeNode.read([ "(((a:1,b:2,c:3)x:4,(d:5)y:6)z:7,(e:8,f:9)z:10);"]) id_index, child_index = t.index_tree() arrayed = t.to_array(attrs=[("name", object)]) # should only have id_index, child_index, and name since we specified # attrs self.assertEqual(len(arrayed), 3) self.assertEqual(id_index, arrayed["id_index"]) npt.assert_equal(child_index, arrayed["child_index"]) exp = np.array(["a", "b", "c", "d", "x", "y", "e", "f", "z", "z", None]) obs = arrayed["name"] npt.assert_equal(obs, exp) # invalid attrs with self.assertRaises(AttributeError): t.to_array(attrs=[("name", object), ("brofist", int)]) def test_to_array_nan_length_value(self): t = TreeNode.read(["((a:1, b:2)c:3)root;"]) indexed = t.to_array(nan_length_value=None) npt.assert_equal(indexed["length"], np.array([1, 2, 3, np.nan], dtype=float)) indexed = t.to_array(nan_length_value=0.0) npt.assert_equal(indexed["length"], np.array([1, 2, 3, 0.0], dtype=float)) indexed = t.to_array(nan_length_value=42.0) npt.assert_equal(indexed["length"], np.array([1, 2, 3, 42.0], dtype=float)) t = TreeNode.read(["((a:1, b:2)c:3)root:4;"]) indexed = t.to_array(nan_length_value=42.0) npt.assert_equal(indexed["length"], np.array([1, 2, 3, 4], dtype=float)) t = TreeNode.read(["((a:1, b:2)c)root;"]) indexed = t.to_array(nan_length_value=42.0) npt.assert_equal(indexed["length"], np.array([1, 2, 42.0, 42.0], dtype=float)) sample = """ ( ( xyz:0.28124, ( def:0.24498, mno:0.03627) :0.17710) :0.04870, abc:0.05925, ( ghi:0.06914, jkl:0.13776) :0.09853); """ node_data_sample = """ ( ( xyz:0.28124, ( def:0.24498, mno:0.03627) 'A':0.17710) B:0.04870, abc:0.05925, ( ghi:0.06914, jkl:0.13776) C:0.09853); """ minimal = "();" no_names = "((,),(,));" missing_tip_name = "((a,b),(c,));" empty = "();" single = "(abc:3);" double = "(abc:3, def:4);" onenest = "(abc:3, (def:4, ghi:5):6 );" nodedata = "(abc:3, (def:4, ghi:5)jkl:6 );" exp_ascii_art_three_children = r""" /-a | ---------| /-b | | \--------|--c | \-d""" if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/test_upgma.py000066400000000000000000000040631520735541300243100ustar00rootroot00000000000000import io from unittest import TestCase, main from skbio import DistanceMatrix, TreeNode from skbio.util import get_data_path from skbio.tree._upgma import upgma class UpgmaTests(TestCase): def setUp(self): data = [[0, 5, 9, 9, 8], [5, 0, 10, 10, 9], [9, 10, 0, 8, 7], [9, 10, 8, 0, 3], [8, 9, 7, 3, 0]] ids = list('abcde') self.dm = DistanceMatrix(data, ids) self.dm_condensed = DistanceMatrix(self.dm, condensed=True) # Note that upgma and wpgma have different edge # estimations, even with small examples. self.expected_str_upgma = ( "((a:2.5,b:2.5):2.083333333333333,(c:3.75,(d:1.5,e:1.5):2.25):0.833333333333333);") self.expected_str_wpgma = ( "((a:2.5,b:2.5):2.125,(c:3.75,(d:1.5,e:1.5):2.25):0.875);") self.expected_TreeNode_upgma = TreeNode.read( io.StringIO(self.expected_str_upgma)) self.expected_TreeNode_wpgma = TreeNode.read( io.StringIO(self.expected_str_wpgma)) def test_upgma_dm(self): actual_TreeNode = upgma(self.dm) self.assertAlmostEqual(actual_TreeNode.compare_cophenet( self.expected_TreeNode_upgma), 0.0, places=10) def test_upgma_dm_condensed(self): actual_TreeNode = upgma(self.dm_condensed) self.assertAlmostEqual(actual_TreeNode.compare_cophenet( self.expected_TreeNode_upgma), 0.0, places=10) def test_wpgma_dm(self): actual_TreeNode = upgma(self.dm, weighted=True) self.assertAlmostEqual(actual_TreeNode.compare_cophenet( self.expected_TreeNode_wpgma), 0.0, places=10) def test_upgma_real(self): """Test on a real dataset with 100 taxa.""" dm = DistanceMatrix.read(get_data_path("mp100.phy")) obs = upgma(dm) exp = TreeNode.read(get_data_path("mp100.upgma.nwk")) self.assertEqual(obs.compare_rfd(exp), 0.0) self.assertAlmostEqual(obs.compare_cophenet(exp), 0.0) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/tree/tests/test_utils.py000066400000000000000000000063771520735541300243510ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import io from unittest import TestCase, main import numpy.testing as npt from skbio import TreeNode from skbio.tree._exception import DuplicateNodeError, MissingNodeError from skbio.tree._utils import _validate_taxa_and_tree class UtilsTests(TestCase): def test_validate_taxa_and_tree(self): # basic valid input tree = TreeNode.read([ "(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:0.75,OTU5:0.75)" ":1.25):0.0)root;"]) taxa = ["OTU1", "OTU2", "OTU3"] self.assertIsNone(_validate_taxa_and_tree(taxa, tree)) # all tips observed taxa = ["OTU1", "OTU2", "OTU3", "OTU4", "OTU5"] self.assertIsNone(_validate_taxa_and_tree(taxa, tree)) # no tips observed taxa = [] self.assertIsNone(_validate_taxa_and_tree(taxa, tree)) def test_validate_taxa_and_tree_invalid_input(self): # tree has duplicated tip ids tree = TreeNode.read([ "(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:0.75,OTU2:0.75)" ":1.25):0.0)root;"]) taxa = ["OTU1", "OTU2", "OTU3"] self.assertRaises(DuplicateNodeError, _validate_taxa_and_tree, taxa, tree) self.assertIsNone(_validate_taxa_and_tree(taxa, tree, unique=False)) # unrooted tree as input tree = TreeNode.read(["((OTU1:0.1,OTU2:0.2):0.3,OTU3:0.5,OTU4:0.7);"]) taxa = ["OTU1", "OTU2", "OTU3"] self.assertIsNone(_validate_taxa_and_tree(taxa, tree)) self.assertRaises(ValueError, _validate_taxa_and_tree, taxa, tree, rooted=True) # taxa has duplicated ids tree = TreeNode.read([ "(((((OTU1:0.5,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:0.75,OTU5:0.75)" ":1.25):0.0)root;"]) taxa = ["OTU1", "OTU2", "OTU2"] self.assertRaises(ValueError, _validate_taxa_and_tree, taxa, tree) self.assertIsNone(_validate_taxa_and_tree(taxa, tree, unique=False)) # tree with no branch lengths tree = TreeNode.read(["((((OTU1,OTU2),OTU3)),(OTU4,OTU5));"]) taxa = ["OTU1", "OTU2", "OTU3"] self.assertIsNone(_validate_taxa_and_tree(taxa, tree)) self.assertRaises(ValueError, _validate_taxa_and_tree, taxa, tree, lengths=True) # tree missing some branch lengths tree = TreeNode.read([ "(((((OTU1,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:0.75,OTU5:0.75)" ":1.25):0.0)root;"]) taxa = ["OTU1", "OTU2", "OTU3"] self.assertRaises(ValueError, _validate_taxa_and_tree, taxa, tree, lengths=True) # taxa not present in tree tree = TreeNode.read([ "(((((OTU1:0.25,OTU2:0.5):0.5,OTU3:1.0):1.0):0.0,(OTU4:0.75,OTU5:0.75)" ":1.25):0.0)root;"]) taxa = ["OTU1", "OTU2", "OTU32"] self.assertRaises(MissingNodeError, _validate_taxa_and_tree, taxa, tree) if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/util/000077500000000000000000000000001520735541300204375ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/util/__init__.py000066400000000000000000000054261520735541300225570ustar00rootroot00000000000000r"""Utilities for Developers (:mod:`skbio.util`) ============================================ .. currentmodule:: skbio.util This package provides general exception/warning definitions used throughout scikit-bio, as well as various utility functionality, including I/O and unit-testing convenience functions. Testing utilities ----------------- Common functionality to support testing in skbio. .. autosummary:: :toctree: generated/ get_data_path assert_ordination_results_equal assert_ordination_results_equal_np assert_data_frame_almost_equal xp_assert_close xp_assert_equal Plotting utilities ------------------ .. autosummary:: :toctree: generated/ PlottableMixin Randomization ------------- .. autosummary:: :toctree: generated/ get_rng Decorators ---------- .. autosummary:: :toctree: generated/ overrides classproperty classonlymethod deprecated aliased register_aliases params_aliased array_api_doc Miscellaneous utilities ----------------------- Generally useful functionality that doesn't fit in more specific locations. .. autosummary:: :toctree: generated/ cardinal_to_ordinal find_duplicates safe_md5 """ # noqa: D412, D416, D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from ._misc import cardinal_to_ordinal, find_duplicates, safe_md5 from ._random import get_rng from ._testing import ( get_data_path, assert_ordination_results_equal, assert_ordination_results_equal_np, assert_data_frame_almost_equal, xp_assert_close, xp_assert_equal, array_backends, ArrayAPITestMixin, pytestrunner, ) from ._decorator import ( overrides, classproperty, classonlymethod, deprecated, aliased, register_aliases, params_aliased, array_api_doc, ) from ._optionals import get_package, _is_usable from ._plotting import PlottableMixin from ._array import ingest_array __all__ = [ "cardinal_to_ordinal", "find_duplicates", "safe_md5", "get_rng", "get_data_path", "assert_ordination_results_equal", "assert_ordination_results_equal_np", "assert_data_frame_almost_equal", "pytestrunner", "get_package", "_is_usable", "ingest_array", "PlottableMixin", "overrides", "classproperty", "classonlymethod", "deprecated", "aliased", "register_aliases", "params_aliased", "array_api_doc", "xp_assert_close", "xp_assert_equal", "array_backends", "ArrayAPITestMixin", ] scikit-bio-scikit-bio-a3beaa6/skbio/util/_array.py000066400000000000000000000206311520735541300222700ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """Array-like objects and namespaces.""" from __future__ import annotations from typing import TYPE_CHECKING import numpy as np import array_api_compat as aac if TYPE_CHECKING: # pragma: no cover from types import ModuleType from ._typing import ArrayLike, StdArray # ------------------------------------------------------------------------------------- # Important note: This script provides support for array-like objects. Two notions are # currently used interchangeably in scikit-bio: # # 1. `np.typing.ArrayLike`: Used in most legacy code. It is usually converted into a # NumPy array via `np.asarray`. # # 2. `skbio.util._array.StdArray`: Used in some new code that focuses on GPU support. # It is essentially a union of NumPy array-like and array objects compliant with the # Python array API standard. It is parsed using the `_get_array` function below. # # The two types and the two functions can be used interchangeably, but with certain # considerations, as detailed below. # ------------------------------------------------------------------------------------- def _get_array(arr: ArrayLike, /, *, to_numpy: bool = False) -> StdArray: r"""Convert an array-like variable into an array object. Parameters ---------- arr : array_like An array-like variable. to_numpy : bool, optional If True, make sure the returned array is a NumPy array. Returns ------- arr : ndarray An array object. Notes ----- When `to_numpy=True`, this function's behavior is very similar to `np.asarray`. Therefore, in most legacy code, a simple `np.asarray` call can replace the current function. However, there is a subtle difference that makes the current function more suitable for GPU-oriented code: `np.asarray` forces a device-to- host copy, whereas `np.from_dlpack` attempts to share the buffer without making a copy, thereby improving performance. """ # Cast a non-array object into a NumPy array. if not aac.is_array_api_obj(arr): arr = np.asarray(arr) # Cast a non-NumPy array into a NumPy array. elif to_numpy and not aac.is_numpy_array(arr): # The Python array API standard requires any compliant array objects have a # `__dlpack__` protocol, which guarantees that they can be converted into a # NumPy array via `np.from_dlpack`. # See: https://numpy.org/devdocs//user/basics.interoperability.html try: arr = np.from_dlpack(arr) # For array objects that doesn't have the `__dlpack__` protocol (e.g., Dask, # at the time of coding), or array objects that are not on the same device # (e.g., cuda), `np.asarray` is called as a fallback, which should work for # objects that have an `__array__` protocol. except (AttributeError, TypeError, RuntimeError): arr = _to_numpy(arr) return arr # ------------------------------------------------------------------------------------- # Array API backend helpers # ------------------------------------------------------------------------------------- _BACKEND_CHECKERS = { "numpy": aac.is_numpy_namespace, "cupy": aac.is_cupy_namespace, "torch": aac.is_torch_namespace, "jax": aac.is_jax_namespace, "dask": aac.is_dask_namespace, } # ------------------------------------------------------------------------------------- # Conversion and device helpers (used primarily in testing) # ------------------------------------------------------------------------------------- def _to_numpy(arr): r"""Convert any array-API-compatible array to a NumPy array on CPU. Unlike `_get_array(arr, to_numpy=True)`, this handles GPU arrays explicitly without relying on `__dlpack__` or `__array__`, which can fail for device arrays (e.g., `np.asarray` raises `RuntimeError` on a PyTorch CUDA tensor). Parameters ---------- arr : array Any array-API-compatible array object, or a NumPy array. Returns ------- numpy.ndarray The data as a NumPy array on CPU. Notes ----- This is intended for use in **test assertions**, not in library functions. Library functions should stay on the input device and use the `xp` namespace throughout. """ if isinstance(arr, np.ndarray): return arr # PyTorch: must detach from computation graph and move to CPU first. # Without .detach().cpu(), np.asarray raises RuntimeError for CUDA tensors # and tensors that require grad. if hasattr(arr, "detach"): return arr.detach().cpu().numpy() # CuPy: .get() transfers GPU → CPU and returns a NumPy array. if hasattr(arr, "get"): return arr.get() # JAX, Dask, and others: np.asarray works (JAX arrays are on-host by # default; Dask triggers compute). return np.asarray(arr) def _move_to_device(arr, xp, device): r"""Move an array to the specified device. Parameters ---------- arr : array An array-API-compatible array. xp : module The array namespace (e.g. `numpy`, `torch`, `jax.numpy`). device : str or None Target device string (`'cpu'`, `'cuda'`, `'gpu'`, etc.). If `None` or `'cpu'`, the array is returned unchanged. Returns ------- array The array on the requested device. Notes ----- This is intended for use in **test setup**, to place test data on the correct device before calling the function under test. """ if device is None or device == "cpu": return arr xp_name = xp.__name__.split(".")[0] if xp_name == "torch": return arr.to(device) if xp_name == "jax": import jax dev = jax.devices(device)[0] return jax.device_put(arr, dev) # CuPy arrays are always on GPU; numpy arrays are always on CPU. return arr def _get_backend_name(xp): r"""Return a short backend name string for an array namespace. Parameters ---------- xp : module An array namespace. Returns ------- str One of `'numpy'`, `'torch'`, `'jax'`, `'cupy'`, `'dask'`, or the raw module name if unrecognized. """ for name, checker in _BACKEND_CHECKERS.items(): if checker(xp): return name return getattr(xp, "__name__", str(xp)) # ------------------------------------------------------------------------------------- # Main public helper # ------------------------------------------------------------------------------------- def ingest_array( *arrays: ArrayLike, to_numpy: bool = False ) -> tuple[ModuleType, StdArray | ArrayLike]: r"""Convert array-like variables into array objects and their shared namespace. Parameters ---------- *arrays : array_like One or more array-like variables. to_numpy : bool, optional If True, make sure the returned arrays are NumPy arrays. Returns ------- xp : namespace The array API compatible namespace corresponding `arrays`. *arrays : object One or more array objects that are consistent with `xp`. See Also -------- _get_array skbio.util._typing.ArrayLike array_api_compat.array_namespace numpy.typing.ArrayLike numpy.from_dlpack Notes ----- A compatible array-like object must be either: 1. An array object that is compatible with the Python array API standard [1]_. * Examples are numpy.ndarray, cupy.ndarray, torch.Tensor, jax.Array, dask.array.Array, and sparse.SparseArray. 2. An object that can be casted into a NumPy array [2]_. * Examples are numpy.ndarray, Python list, tuple, array, and scalar. `xp` is the namespace wrapper for different array libraries. If the input `arr` is already a compatible object, it will be returned as-is. Otherwise, it will be converted into a NumPy array. References ---------- .. [1] https://data-apis.org/array-api/latest/ .. [2] https://numpy.org/devdocs/glossary.html#term-array_like """ arrays = tuple(_get_array(x, to_numpy=to_numpy) for x in arrays) return aac.array_namespace(*arrays), *arrays scikit-bio-scikit-bio-a3beaa6/skbio/util/_decorator.py000066400000000000000000000213211520735541300231310ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """Decorators.""" from functools import wraps from collections import namedtuple from typing import Any from ._exception import OverrideError from ._docstring import ( _note_into_doc, _note_into_doc_param, _deprecation_note, _renaming_note, _array_api_compat_section, _insert_into_notes_section, ) from ._warning import _warn_deprecated, _warn_renamed, _warn_param_renamed def array_api_doc(backends, devices=None): r"""Add an array API compatibility table to a function's documentation. An array API compatibility table is inserted into the Notes section of the function's docstring. If the docstring has no Notes section, the table is inserted at the end of the docstring. Parameters ---------- backends : list of str Supported backends: `'numpy'`, `'cupy'`, `'torch'`, `'jax'`, `'dask'`. devices : list of str, optional Supported devices: `'cpu'`, `'gpu'`. Defaults to per-backend defaults. """ def decorator(func): section = _array_api_compat_section(backends, devices) func.__doc__ = _insert_into_notes_section(section, func.__doc__ or "") return func return decorator def overrides(interface_class): """Indicate that a member is being overridden from a specific parent class. Decorator for class-level members. Used to indicate that a member is being overridden from a specific parent class. If the member does not have a docstring, it will pull one from the parent class. When chaining decorators, this should be first as it is relatively nondestructive. Parameters ---------- interface_class : class The class which has a member overridden by the decorated member. Returns ------- function The function is not changed or replaced. Raises ------ OverrideError If the `interface_class` does not possess a member of the same name as the decorated member. """ # Adapted from http://stackoverflow.com/a/8313042/579416 def overrider(method): if method.__name__ not in dir(interface_class): raise OverrideError( f"{method.__name__} is not present in parent " f"class: {interface_class.__name__}." ) backup = classproperty.__get__ classproperty.__get__ = lambda x, y, z: x if method.__doc__ is None: method.__doc__ = getattr(interface_class, method.__name__).__doc__ classproperty.__get__ = backup return method return overrider class classproperty(property): """Decorator for class-level properties. Supports read access only. The property will be read-only within an instance. However, the property can always be redefined on the class, since Python classes are mutable. Parameters ---------- func : function Method to make a class property. Returns ------- property Decorated method. Raises ------ AttributeError If the property is set on an instance. """ def __init__(self, func): name = func.__name__ doc = func.__doc__ # Keep fget as a plain function so introspection tools (e.g. Sphinx) # can inspect its signature without tripping on a classmethod object. super(classproperty, self).__init__(func) self.__name__ = name self.__doc__ = doc def __get__(self, obj, owner=None): if getattr(self.fget, "__isabstractmethod__", False): return self if owner is None: owner = type(obj) return self.fget(owner) def __set__(self, obj, value): raise AttributeError("can't set attribute") class classonlymethod(classmethod): """Just like `classmethod`, but it can't be called on an instance.""" def __init__(self, func): # Need to inform mypy that function's first argument is a type if hasattr(func, "__annotations__") and "cls" in func.__annotations__: # Remove the specific class type annotation func.__annotations__["cls"] = Any super().__init__(func) def __get__(self, obj, cls=None): if obj is not None: raise TypeError( f"Class-only method called on an instance. Use " f"{cls.__name__}.{self.__func__.__name__} " "instead." ) return super().__get__(obj, cls) def deprecated(ver, msg=None, append=True): """Mark a function or a method as deprecated. Parameters ---------- ver : str Version when deprecation became effective. msg : str, optional A custom warning message. append : bool, optional Append the custom message to the end of the default message (True, default), or replace the entire default message with the custom message (False). Notes ----- This decorator has two effects: 1) A note will be added to the docstring of the function below the title line to indicate the deprecated status. 2) When the function is called at the first time, a deprecation warning will be displayed. """ def decorator(func): note = _deprecation_note(ver, msg) func.__doc__ = _note_into_doc(note, func.__doc__) @wraps(func) def wrapper(*args, **kwargs): _warn_deprecated(func, ver, msg, append) return func(*args, **kwargs) return wrapper return decorator def aliased(name, ver=None, warn=False): """Create an alias for a function or method. Parameters ---------- name : str Alias name of the function or method. ver : str, optional Version when alias was created. warn : bool, optional If True, raise a deprecation warning when alias is called. See Also -------- deprecated register_aliases params_aliased Notes ----- This is a decorator that can be applied to a function or method to indicate its alias status. To make it effective, :func:`register_aliases` must be applied to the parent module or class. """ def decorator(func): msg = _renaming_note(name, ver, warn) func.__doc__ = _note_into_doc(msg, func.__doc__) @wraps(func) def wrapper(*args, **kwargs): if warn: _warn_renamed(func, name, ver) return func(*args, **kwargs) wrapper._skipdoc = True func._alias = (name, wrapper) return func return decorator def register_aliases(cls): """Register aliases of members of a module or class. See Also -------- aliased Notes ----- This function may serve as a decorator applied to a class to register aliases for its member methods: .. code-block:: python @register_aliases class MyClass(): Alternatively, this function may be called at the end of a module to register aliases for its member functions. .. code-block:: python register_aliases(sys.modules[__name__]) """ aliases = [] for func in cls.__dict__.values(): if hasattr(func, "_alias"): aliases.append(func._alias) for name, wrapper in aliases: setattr(cls, name, wrapper) return cls def params_aliased(params=[]): r"""Create aliases for parameters of a function or method. Parameters ---------- params : list of tuple Aliases of parameters. Each tuple has four elements: param, alias, ver, and warn. Refer to :func:`aliased` for definitions. See Also -------- aliased Notes ----- This is a decorator that can be applied to a function or method to create aliases for its parameters. Unlike :func:`aliased`, this decorator does not require :func:`register_aliases` added to the module or class. """ def decorator(func): for param, alias, ver, warn in params: msg = _renaming_note(alias, ver, warn) if doc := func.__doc__: func.__doc__ = _note_into_doc_param(msg, doc, param) @wraps(func) def wrapper(*args, **kwargs): for param, alias, ver, warn in params: if alias in kwargs: kwargs[param] = kwargs.pop(alias) if warn: _warn_param_renamed(func, param, alias, ver) return func(*args, **kwargs) return wrapper return decorator scikit-bio-scikit-bio-a3beaa6/skbio/util/_docstring.py000066400000000000000000000205701520735541300231500ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """Docstring utilities.""" import re def _note_into_doc(note, doc): """Insert a note into a docstring under the head line. Parameters ---------- note : str Note to insert. doc : str Docstring to modify. Returns ------- str Modified docstring. Notes ----- The note will be placed below the first paragraph (usually a single line) of the docstring, like a subtitle. """ # Make sure note has one line end. note = note.rstrip() + "\n" # No docstring: note becomes the entire docstring. if not doc: return note # Determine the indentation of the second non-empty line. # Correct indentation is important for docstring rendering. if match := re.search(r"\n+(\s*)\S*", doc): indent = match.group(1) # If such a line doesn't exist, i.e., the docstring is a single line, then # indentation is empty. else: indent = "" # Find the first paragraph break (an empty line) and insert the note after the # first paragraph. if pos := doc.find("\n\n") + 1: return f"{doc[:pos].rstrip()}\n\n{indent}{note}{doc[pos:]}" # If not found, i.e., the docstring is a single paragraph, then append the note to # the end of docstring. else: return f"{doc.rstrip()}\n\n{indent}{note}{indent}" def _note_into_doc_param(note, doc, param): """Insert a note into a docstring under the description of a parameter. Parameters ---------- note : str Note to insert. doc : str Docstring to modify. param : str Target parameter. Returns ------- str Modified docstring. Raises ------ ValueError Parameter is missing or its format is invalid. Notes ----- The note will be placed below the description of the parameter, and above the next parameter or the next section. """ note = note.rstrip() + "\n" # Find the header line of the parameter. if not (match := re.search(rf"(^\s*){param}\s*:.*?\n", doc, re.MULTILINE)): raise ValueError( f'Parameter "{param}" is missing from the docstring or its format is ' "invalid." ) # Determine the indentation of the header line. indent = match.group(1) # Find the next line with the same or less indentation, which indicates the next # parameter or the end of the "Parameters" section. after = doc[(end := match.end()) :] match = re.search(rf"^{indent}(\S|$)", after, re.MULTILINE) # Determine the insertion point. pos = end + (match.start() if match else len(after)) # Insert the message. It should have 1+ indentation level (i.e., 4 spaces) than # the header line. return f"{doc[:pos].rstrip()}\n\n{indent} {note}\n{doc[pos:]}" _BACKEND_DEVICES = { "numpy": ["cpu"], "cupy": ["gpu"], "torch": ["cpu", "gpu"], "jax": ["cpu", "gpu"], "dask": ["cpu"], } _BACKEND_DISPLAY = { "numpy": "NumPy", "cupy": "CuPy", "torch": "PyTorch", "jax": "JAX", "dask": "Dask", } def _array_api_compat_section(backends, devices=None): """Generate an RST compatibility table for the Array API notes section. Parameters ---------- backends : list of str Supported backends. devices : list of str, optional Supported devices. Defaults to per-backend defaults. Returns ------- str RST-formatted compatibility table paragraph. """ # Collect the set of all devices to display as columns if devices is not None: all_devices = list(dict.fromkeys(devices)) else: all_devices = [] for b in backends: for d in _BACKEND_DEVICES.get(b, ["cpu"]): if d not in all_devices: all_devices.append(d) col_headers = [d.upper() for d in all_devices] # Build rows rows = [] for b in backends: display = _BACKEND_DISPLAY.get(b, b.capitalize()) supported = _BACKEND_DEVICES.get(b, ["cpu"]) if devices is not None: supported = [d for d in devices if d in supported] cells = ["\u2713" if d in supported else "n/a" for d in all_devices] rows.append((display, cells)) # Compute column widths backend_col_w = max(len("Backend"), max(len(r[0]) for r in rows)) device_col_ws = [ max(len(h), max(len(r[1][i]) for r in rows)) for i, h in enumerate(col_headers) ] def hline(left, mid, right, fill="-"): parts = [fill * (backend_col_w + 2)] for w in device_col_ws: parts.append(fill * (w + 2)) return "+" + "+".join(parts) + "+" def row_line(backend, cells, fill=" "): parts = [f" {backend:<{backend_col_w}} "] for val, w in zip(cells, device_col_ws): parts.append(f" {val:<{w}} ") return "|" + "|".join(parts) + "|" header_sep = hline("+", "+", "+", "=") normal_sep = hline("+", "+", "+", "-") header_row = row_line("Backend", col_headers) lines = [normal_sep, header_row, header_sep] for display, cells in rows: lines.append(row_line(display, cells)) lines.append(normal_sep) intro_text = ( "This function supports the `Python array API standard" " `_." " Compatible array backends:" ) # Build a self-contained ``.. note::`` admonition. Every body line (the # intro sentence and all table rows) is indented three spaces relative to # the directive; blank lines are left empty. note_body_lines = [intro_text, ""] + lines indented_body = "\n".join( " " + ln if ln.strip() else ln for ln in note_body_lines ) return ".. note::\n\n" + indented_body + "\n" def _insert_into_notes_section(note, doc): """Insert a note into the Notes section of a docstring. Parameters ---------- note : str Text to insert. doc : str Docstring to modify. Returns ------- str Modified docstring with note prepended inside Notes section. Notes ----- If a Notes section is found, the note is prepended inside it. Otherwise, a new Notes section is appended at the end of the docstring. """ note = note.rstrip() + "\n" # Determine indentation from the second non-empty line (same as _note_into_doc) if match := re.search(r"\n+(\s*)\S*", doc): indent = match.group(1) else: indent = "" # Re-indent the entire note block (directive line AND body together) by the # section indent, preserving the relative nesting inside the directive. # Blank lines are left empty so the directive body parses correctly. indented_note = "".join( indent + line if line.strip() else line for line in note.splitlines(keepends=True) ) # Look for an existing Notes section "Notes\n-----" notes_match = re.search(r"^(\s*)Notes\s*\n\s*-{3,}", doc, re.MULTILINE) if notes_match: # Insert after the section header (and any blank lines following it) header_end = notes_match.end() # Skip any leading blank lines inside the section rest = doc[header_end:] skip = re.match(r"\n*", rest) insert_pos = header_end + (skip.end() if skip else 0) return doc[:insert_pos] + "\n" + indented_note + "\n" + doc[insert_pos:] # No Notes section: append one at the end doc_stripped = doc.rstrip() notes_section = ( f"\n\n{indent}Notes\n{indent}-----\n\n" + indented_note.rstrip() + "\n" ) return doc_stripped + notes_section def _deprecation_note(ver=None, msg=None): """Create a note indicating deprecation.""" note = f".. deprecated:: {ver}" if msg: note += " " + msg return note def _renaming_note(name, ver=None, warn=False): """Create a message indicating renaming.""" if not ver: return f"Alias: ``{name}``" note = ( f".. versionchanged:: {ver} " f"Renamed from ``{name}``. The old name is kept as an alias" ) if warn: note += " but is deprecated" note += "." return note scikit-bio-scikit-bio-a3beaa6/skbio/util/_exception.py000066400000000000000000000012241520735541300231450ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """Exceptions.""" class TestingUtilError(Exception): """Raised when an exception is needed to test exception handling.""" __test__ = False # prevent py-test from collecting it class OverrideError(AssertionError): """Raised when a property does not exist in the parent class.""" pass scikit-bio-scikit-bio-a3beaa6/skbio/util/_gpu.py000066400000000000000000000014431520735541300217450ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """GPU-related utilities.""" import subprocess def cuda_avail(): # pragma: no cover r"""Check if CUDA is available. Returns ------- bool Whether CUDA is available. """ try: result = subprocess.run( ["nvidia-smi"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) return result.returncode == 0 except FileNotFoundError: return False scikit-bio-scikit-bio-a3beaa6/skbio/util/_misc.py000066400000000000000000000125631520735541300221120ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """Miscellaneous utilities.""" import inspect from types import FunctionType def resolve_key(obj, key): """Resolve key given an object and key.""" if callable(key): return key(obj) elif hasattr(obj, "metadata"): return obj.metadata[key] raise TypeError( "Could not resolve key %r. Key must be callable or %s must" " have `metadata` attribute." % (key, obj.__class__.__name__) ) def make_sentinel(name): return type( name, (), {"__repr__": lambda s: name, "__str__": lambda s: name, "__class__": None}, )() def find_sentinels(function, sentinel): params = inspect.signature(function).parameters return [name for name, param in params.items() if param.default is sentinel] class MiniRegistry(dict): def __call__(self, name): """Act as a decorator to register functions with self.""" def decorator(func): self[name] = func return func return decorator def copy(self): """Use for inheritance.""" return self.__class__(super(MiniRegistry, self).copy()) def formatted_listing(self): """Produce an RST list with descriptions.""" if len(self) == 0: return "\tNone" else: return "\n".join( [ "\t%r\n\t %s" % (name, self[name].__doc__.split("\n")[0]) for name in sorted(self) ] ) def interpolate(self, obj, name): """Inject the formatted listing in the second blank line of `name`.""" f = getattr(obj, name) f2 = FunctionType( f.__code__, f.__globals__, name=f.__name__, argdefs=f.__defaults__, closure=f.__closure__, ) # Conveniently the original docstring is on f2, not the new ones if # inheritance is happening. I have no idea why. t = f2.__doc__.split("\n\n") t.insert(2, self.formatted_listing()) f2.__doc__ = "\n\n".join(t) setattr(obj, name, f2) def chunk_str(s, n, char): """Insert `char` character every `n` characters in string `s`. Canonically pronounced "chunkster". """ # Modified from http://stackoverflow.com/a/312464/3776794 if n < 1: raise ValueError( "Cannot split string into chunks with n=%d. n must be >= 1." % n ) return char.join((s[i : i + n] for i in range(0, len(s), n))) def cardinal_to_ordinal(n): """Return ordinal string version of cardinal int `n`. Parameters ---------- n : int Cardinal to convert to ordinal. Must be >= 0. Returns ------- str Ordinal version of cardinal `n`. Raises ------ ValueError If `n` is less than 0. Notes ----- This function can be useful when writing human-readable error messages. Examples -------- >>> from skbio.util import cardinal_to_ordinal >>> cardinal_to_ordinal(0) '0th' >>> cardinal_to_ordinal(1) '1st' >>> cardinal_to_ordinal(2) '2nd' >>> cardinal_to_ordinal(3) '3rd' """ # Taken and modified from http://stackoverflow.com/a/20007730/3776794 # Originally from http://codegolf.stackexchange.com/a/4712 by Gareth if n < 0: raise ValueError("Cannot convert negative integer %d to ordinal string." % n) return "%d%s" % (n, "tsnrhtdd"[(n // 10 % 10 != 1) * (n % 10 < 4) * n % 10 :: 4]) def safe_md5(open_file, block_size=2**20): """Compute an md5 sum without loading the file into memory. Parameters ---------- open_file : file object open file handle to the archive to compute the checksum. It must be open as a binary file block_size : int, optional size of the block taken per iteration Returns ------- md5 : md5 object from the hashlib module object with the loaded file Notes ----- This method is based on the answers given in: http://stackoverflow.com/a/1131255/379593 Examples -------- >>> from io import BytesIO >>> from skbio.util import safe_md5 >>> fd = BytesIO(b"foo bar baz") # open file like object >>> x = safe_md5(fd) >>> x.hexdigest() 'ab07acbb1e496801937adfa772424bf7' >>> fd.close() """ import hashlib md5 = hashlib.md5() data = True while data: data = open_file.read(block_size) if data: md5.update(data) return md5 def find_duplicates(iterable): """Find duplicate elements in an iterable. Parameters ---------- iterable : iterable Iterable to be searched for duplicates (i.e., elements that are repeated). Returns ------- set Repeated elements in `iterable`. """ # modified from qiita.qiita_db.util.find_repeated # https://github.com/biocore/qiita # see licenses/qiita.txt seen, repeated = set(), set() for e in iterable: if e in seen: repeated.add(e) else: seen.add(e) return repeated scikit-bio-scikit-bio-a3beaa6/skbio/util/_optionals.py000066400000000000000000000026551520735541300231700ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """Optional dependencies.""" import importlib def get_package(name, raise_error=True): r"""Attempt to import a package for functions that require the said package. Parameters ---------- name : str Name of the package. raise_error : bool, optional If the package cannot be imported, raise an ``ImportError`` if True (default), otherwise return None. Returns ------- module Imported package (None if not available). Raises ------ ImportError If the package cannot be imported. """ msg = ( f'Optional dependency "{name}" is not found. ' "Install it to use relevant functionalities." ) try: return importlib.import_module(name) except (ImportError, ModuleNotFoundError): if raise_error: raise ImportError(msg) def _is_usable(mod, probe): """Return True if `mod` is importable AND `probe()` runs without error.""" if mod is None: return False try: probe() return True except Exception: return False scikit-bio-scikit-bio-a3beaa6/skbio/util/_plotting.py000066400000000000000000000037421520735541300230160ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """Plotting utilities.""" import importlib from io import StringIO, BytesIO class PlottableMixin: """A plottable object.""" def _get_mpl_plt(self): """Import Matplotlib and its plotting interface.""" msg = "Plotting requires Matplotlib installed in the system." if hasattr(self, "mpl"): if self.mpl is None: raise ImportError(msg) return try: self.mpl = importlib.import_module("matplotlib") except ImportError: self.mpl = None raise ImportError(msg) else: self.plt = importlib.import_module("matplotlib.pyplot") def _figure_data(self, format="png"): """Get figure data of a plottable object. Parameters ---------- format : str, optional Image format supported by the plotting backend. Examples include 'png' (default), 'svg', 'pdf', and 'eps'. Returns ------- str or bytes or None Figure data, or None if the plotting backend is not available. """ try: self._get_mpl_plt() except ImportError: return # call default plotting method fig = self.plot() fig.tight_layout() # get figure data # formats such as SVG are string try: fig.savefig(f := StringIO(), format=format) # formats such as PNG are bytes except TypeError: fig.savefig(f := BytesIO(), format=format) # close figure to avoid double display in IPython self.plt.close(fig) return f.getvalue() scikit-bio-scikit-bio-a3beaa6/skbio/util/_random.py000066400000000000000000000077111520735541300224360ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """Randomization.""" import numpy as np def get_rng(seed=None): r"""Get a random generator. .. versionchanged:: 0.6.3 Added legacy random generator support. Parameters ---------- seed : int, Generator or RandomState, optional A user-provided random seed or random generator instance. Returns ------- np.random.Generator Random generator instance. See Also -------- numpy.random.Generator numpy.random.RandomState Notes ----- A random generator ensures reproducibility of outputs. scikit-bio utilizes NumPy's new random generator (``Generator``) [1]_, which was introduced in version 1.17. See NEP 19 [2]_ for an introduction to this change. The following code demonstrates the recommended usage of the random generator with various scikit-bio functions that are stochastic. With a random generator created in advance, you can plug it into multiple function calls. The results of the entire code will be reproducible. (42 is an arbitrarily chosen random seed. It can be any non-negative integer.) .. code-block:: python rng = np.random.default_rng(42) skbio_func1(..., seed=rng) skbio_func2(..., seed=rng) ... Alternatively, you may specify an integer seed to make the result of each function call reproducible, such as: .. code-block:: python skbio_func1(..., seed=42) skbio_func2(..., seed=42) ... Meanwhile, scikit-bio respects the legacy random generator (``RandomState``) [3]_. If ``np.random.seed`` has been called, or a ``RandomState`` instance is provided, scikit-bio will create a new random generator from a seed selected by the legacy random generator. This ensures reproducibility of legacy code and compatibility with packages that use the legacy mechanism. For example: .. code-block:: python np.random.seed(42) skbio_func1(...) skbio_func2(...) ... It should be noted that the legacy random generator will not be directly used by scikit-bio functions for random number generation. Only the new random generator will be exposed to the functions. References ---------- .. [1] https://numpy.org/devdocs/reference/random/generator.html .. [2] https://numpy.org/neps/nep-0019-rng-policy.html .. [3] https://numpy.org/doc/stable/reference/random/legacy.html """ # seed is new Generator: directly return it try: if isinstance(seed, np.random.Generator): return seed except AttributeError: raise ValueError( "The installed NumPy version does not support random.Generator. " "Please use NumPy >= 1.17." ) # no seed: create a generator from a seed selected by the legacy random state # this ensures reproducibility of legacy code starting with `np.random.seed(x)` if seed is None: # the result of `np.iinfo(np.int32).max + 1` is usually 2,147,483,648, or # 1 << 31, # which is also the result of `np.random.get_state()[1][0]` if # `np.random` hasn't been called seed = np.random.randint(np.iinfo(np.int32).max + 1) # seed is legacy RandomState: create a generator from a seed selected by it elif isinstance(seed, np.random.RandomState): seed = seed.randint(np.iinfo(np.int32).max + 1) # seed is integer: create a generator from this random state elif not np.issubdtype(type(seed), np.integer): raise ValueError( "Invalid seed. It must be an integer or a random generator instance." ) return np.random.default_rng(seed) scikit-bio-scikit-bio-a3beaa6/skbio/util/_testing.py000066400000000000000000000606511520735541300226350ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """Testing utilities.""" import inspect import os import sys import functools import unittest import numpy as np import numpy.testing as npt import pandas.testing as pdt from scipy.spatial.distance import pdist from skbio.util._array import _to_numpy, _move_to_device, _get_backend_name class ReallyEqualMixin: """Use this for testing __eq__/__ne__. Taken and modified from the following public domain code: https://ludios.org/testing-your-eq-ne-cmp/ """ def assertReallyEqual(self, a, b): # assertEqual first, because it will have a good message if the # assertion fails. self.assertEqual(a, b) self.assertEqual(b, a) self.assertTrue(a == b) self.assertTrue(b == a) self.assertFalse(a != b) self.assertFalse(b != a) def assertReallyNotEqual(self, a, b): # assertNotEqual first, because it will have a good message if the # assertion fails. self.assertNotEqual(a, b) self.assertNotEqual(b, a) self.assertFalse(a == b) self.assertFalse(b == a) self.assertTrue(a != b) self.assertTrue(b != a) def get_data_path(fn, subfolder="data"): """Return path to filename ``fn`` in the data folder. During testing it is often necessary to load data files. This function returns the full path to files in the ``data`` subfolder by default. Parameters ---------- fn : str File name. subfolder : str, defaults to ``data`` Name of the subfolder that contains the data. Returns ------- str Inferred absolute path to the test data for the module where ``get_data_path(fn)`` is called. Notes ----- The requested path may not point to an existing file, as its existence is not checked. """ # getouterframes returns a list of tuples: the second tuple # contains info about the caller, and the second element is its # filename callers_filename = inspect.getouterframes(inspect.currentframe())[1][1] path = os.path.dirname(os.path.abspath(callers_filename)) data_path = os.path.join(path, subfolder, fn) return data_path def assert_ordination_results_equal( left, right, ignore_method_names=False, ignore_axis_labels=False, ignore_directionality=False, decimal=7, ): """Assert that ordination results objects are equal. This is a helper function intended to be used in unit tests that need to compare ``OrdinationResults`` objects. Parameters ---------- left, right : OrdinationResults Ordination results to be compared for equality. ignore_method_names : bool, optional Ignore differences in `short_method_name` and `long_method_name`. ignore_axis_labels : bool, optional Ignore differences in axis labels (i.e., column labels). ignore_directionality : bool, optional Ignore differences in directionality (i.e., differences in signs) for attributes `samples`, `features` and `biplot_scores`. decimal : int, optional Number of decimal places to compare when checking numerical values. Defaults to 7. Raises ------ AssertionError If the two objects are not equal. """ npt.assert_equal(type(left) is type(right), True) if not ignore_method_names: npt.assert_equal(left.short_method_name, right.short_method_name) npt.assert_equal(left.long_method_name, right.long_method_name) _assert_frame_dists_equal( left.samples, right.samples, ignore_columns=ignore_axis_labels, ignore_directionality=ignore_directionality, decimal=decimal, ) _assert_frame_dists_equal( left.features, right.features, ignore_columns=ignore_axis_labels, ignore_directionality=ignore_directionality, decimal=decimal, ) _assert_frame_dists_equal( left.biplot_scores, right.biplot_scores, ignore_columns=ignore_axis_labels, ignore_directionality=ignore_directionality, decimal=decimal, ) _assert_frame_dists_equal( left.sample_constraints, right.sample_constraints, ignore_columns=ignore_axis_labels, ignore_directionality=ignore_directionality, decimal=decimal, ) _assert_series_equal( left.eigvals, right.eigvals, ignore_axis_labels, decimal=decimal ) _assert_series_equal( left.proportion_explained, right.proportion_explained, ignore_axis_labels, decimal=decimal, ) def assert_ordination_results_equal_np(obs, exp, ignore_method_names=False, decimal=7): """NumPy version of testing ordination results.""" if not ignore_method_names: npt.assert_equal(obs.short_method_name, exp.short_method_name) npt.assert_equal(obs.long_method_name, exp.long_method_name) # do this for samples, features, biplot_scores, sample_constraints obs_dists_samp = pdist(obs.samples) exp_dists_samp = pdist(exp.samples) npt.assert_almost_equal(obs_dists_samp, exp_dists_samp, decimal=decimal) # test features if exp.features is None: assert obs.features is None else: obs_dists_feat = pdist(obs.features) exp_dists_feat = pdist(exp.features) npt.assert_almost_equal(obs_dists_feat, exp_dists_feat, decimal=decimal) # test biplot_scores if exp.biplot_scores is None: assert obs.biplot_scores is None else: obs_dists_biplot = pdist(obs.biplot_scores) exp_dists_biplot = pdist(exp.biplot_scores) npt.assert_almost_equal(obs_dists_biplot, exp_dists_biplot, decimal=decimal) # test sample_constraints if exp.sample_constraints is None: assert obs.sample_constraints is None else: obs_dists_cons = pdist(obs.sample_constraints) exp_dists_cons = pdist(exp.sample_constraints) npt.assert_almost_equal(obs_dists_cons, exp_dists_cons, decimal=decimal) # test eigvals npt.assert_almost_equal(obs.eigvals, exp.eigvals, decimal=decimal) # test proportion_explained if exp.proportion_explained is None: assert obs.proportion_explained is None else: npt.assert_almost_equal( obs.proportion_explained, exp.proportion_explained, decimal=decimal ) def _assert_series_equal(left_s, right_s, ignore_index=False, decimal=7): # assert_series_equal doesn't like None... if left_s is None or right_s is None: assert left_s is None and right_s is None else: npt.assert_almost_equal(left_s.values, right_s.values, decimal=decimal) if not ignore_index: pdt.assert_index_equal(left_s.index, right_s.index) def _assert_frame_dists_equal( left_df, right_df, ignore_index=False, ignore_columns=False, ignore_directionality=False, decimal=7, ): if left_df is None or right_df is None: assert left_df is None and right_df is None else: left_values = left_df.values right_values = right_df.values left_dists = pdist(left_values) right_dists = pdist(right_values) npt.assert_almost_equal(left_dists, right_dists, decimal=decimal) if not ignore_index: pdt.assert_index_equal(left_df.index, right_df.index) if not ignore_columns: pdt.assert_index_equal(left_df.columns, right_df.columns) def _normalize_signs(arr1, arr2): """Change column signs so that "column" and "-column" compare equal. This is needed because results of eigenproblmes can have signs flipped, but they're still right. Notes ----- This function tries hard to make sure that, if you find "column" and "-column" almost equal, calling a function like np.allclose to compare them after calling `normalize_signs` succeeds. To do so, it distinguishes two cases for every column: - It can be all almost equal to 0 (this includes a column of zeros). - Otherwise, it has a value that isn't close to 0. In the first case, no sign needs to be flipped. I.e., for |epsilon| small, np.allclose(-epsilon, 0) is true if and only if np.allclose(epsilon, 0) is. In the second case, the function finds the number in the column whose absolute value is largest. Then, it compares its sign with the number found in the same index, but in the other array, and flips the sign of the column as needed. """ # Let's convert everything to floating point numbers (it's # reasonable to assume that eigenvectors will already be floating # point numbers). This is necessary because np.array(1) / # np.array(0) != np.array(1.) / np.array(0.) arr1 = np.asarray(arr1, dtype=np.float64) arr2 = np.asarray(arr2, dtype=np.float64) if arr1.shape != arr2.shape: raise ValueError( "Arrays must have the same shape ({0} vs {1}).".format( arr1.shape, arr2.shape ) ) # To avoid issues around zero, we'll compare signs of the values # with highest absolute value max_idx = np.abs(arr1).argmax(axis=0) max_arr1 = arr1[max_idx, range(arr1.shape[1])] max_arr2 = arr2[max_idx, range(arr2.shape[1])] sign_arr1 = np.sign(max_arr1) sign_arr2 = np.sign(max_arr2) # Store current warnings, and ignore division by zero (like 1. / # 0.) and invalid operations (like 0. / 0.) wrn = np.seterr(invalid="ignore", divide="ignore") differences = sign_arr1 / sign_arr2 # The values in `differences` can be: # 1 -> equal signs # -1 -> diff signs # Or nan (0/0), inf (nonzero/0), 0 (0/nonzero) np.seterr(**wrn) # Now let's deal with cases where `differences != \pm 1` special_cases = (~np.isfinite(differences)) | (differences == 0) # In any of these cases, the sign of the column doesn't matter, so # let's just keep it differences[special_cases] = 1 return arr1 * differences, arr2 def assert_data_frame_almost_equal(left, right, rtol=1e-5): """Raise AssertionError if ``pd.DataFrame`` objects are not "almost equal". Wrapper of ``pd.util.testing.assert_frame_equal``. Floating point values are considered "almost equal" if they are within a threshold defined by ``assert_frame_equal``. This wrapper uses a number of checks that are turned off by default in ``assert_frame_equal`` in order to perform stricter comparisons (for example, ensuring the index and column types are the same). It also does not consider empty ``pd.DataFrame`` objects equal if they have a different index. Other notes: * Index (row) and column ordering must be the same for objects to be equal. * NaNs (``np.nan``) in the same locations are considered equal. This is a helper function intended to be used in unit tests that need to compare ``pd.DataFrame`` objects. Parameters ---------- left, right : pd.DataFrame ``pd.DataFrame`` objects to compare. rtol : float, optional The relative tolerance parameter used for comparison. Defaults to 1e-5. Raises ------ AssertionError If `left` and `right` are not "almost equal". See Also -------- pandas.util.testing.assert_frame_equal """ # pass all kwargs to ensure this function has consistent behavior even if # `assert_frame_equal`'s defaults change pdt.assert_frame_equal( left, right, check_dtype=True, check_index_type=True, check_column_type=True, check_frame_type=True, check_names=True, by_blocks=False, check_exact=False, rtol=rtol, ) # this check ensures that empty DataFrames with different indices do not # compare equal. exact=True specifies that the type of the indices must be # exactly the same assert_index_equal(left.index, right.index) def _data_frame_to_default_int_type(df): """Convert integer columns in a data frame into the platform-default integer type. Pandas DataFrame defaults to int64 when reading integers, rather than respecting the platform default (Linux and MacOS: int64, Windows: int32). This causes issues in comparing observed and expected data frames in Windows. This function repairs the issue by converting int64 columns of a data frame into int32 in Windows. See: https://github.com/unionai-oss/pandera/issues/726 """ for col in df.select_dtypes("int").columns: df[col] = df[col].astype(int) def assert_series_almost_equal(left, right): # pass all kwargs to ensure this function has consistent behavior even if # `assert_series_equal`'s defaults change pdt.assert_series_equal( left, right, check_dtype=True, check_index_type=True, check_series_type=True, check_names=True, check_exact=False, check_datetimelike_compat=False, obj="Series", ) # this check ensures that empty Series with different indices do not # compare equal. assert_index_equal(left.index, right.index) def assert_index_equal(a, b): pdt.assert_index_equal(a, b, exact=True, check_names=True, check_exact=True) def pytestrunner(): try: import numpy try: # NumPy 1.14 changed repr output breaking our doctests, # request the legacy 1.13 style numpy.set_printoptions(legacy="1.13") except TypeError: # Old Numpy, output should be fine as it is :) # TypeError: set_printoptions() got an unexpected # keyword argument 'legacy' pass except ImportError: numpy = None try: import pandas # Max columns is automatically set by pandas based on terminal # width, so set columns to unlimited to prevent the test suite # from passing/failing based on terminal size. pandas.options.display.max_columns = None except ImportError: pandas = None try: import matplotlib except ImportError: matplotlib = None else: # Set a non-interactive backend for Matplotlib, such that it can work on # systems without graphics matplotlib.use("agg") # import here, cause outside the eggs aren't loaded import pytest errno = pytest.main(args=["--pyargs", "skbio"] + sys.argv[1:]) sys.exit(errno) # ------------------------------------------------------------------------------------- # Array API test infrastructure # # Write one test method, run it against every supported array backend # (numpy, jax, torch, cupy). Uses ``unittest.subTest()`` for per-backend # reporting — no pytest required. # # Env vars: # SKBIO_ARRAY_BACKEND — "numpy" (default), "jax", "torch", "cupy", or "all" # SKBIO_DEVICE — "cpu" (default), "cuda", "gpu" # # Note: ``"gpu"`` (JAX's native string) and ``"cuda"`` (Torch/CuPy's native # string) refer to the same hardware and are treated as equivalent. # # Usage: # class TestClosure(TestCase, ArrayAPITestMixin): # @array_backends("numpy", "jax", "torch", "cupy") # def test_basic(self, xp, device): # data = self.make_array(xp, device, [[2.0, 2.0, 6.0]]) # result = closure(data) # self.assert_type_preserved(result, xp, device) # self.assert_close(result, self.make_array(xp, device, [[0.2, 0.2, 0.6]])) # ------------------------------------------------------------------------------------- # Two device-name spellings that refer to the same hardware. Used only to # decide whether a requested ``SKBIO_DEVICE`` matches a backend's advertised # device — never to inspect a real array (see ``_on_device`` for that). _GPU_ALIASES = frozenset({"cuda", "gpu"}) def _device_specs_match(a, b): """True if two device-spec strings refer to the same hardware. Both inputs are expected to be the per-backend strings stored in ``_BACKENDS`` or read from ``SKBIO_DEVICE`` — short labels like ``"cpu"``, ``"cuda"``, or ``"gpu"``. This is *not* for inspecting a real array's device; use ``_on_device`` for that. """ if a is None or b is None: return a == b a, b = a.lower(), b.lower() if a == b: return True return a in _GPU_ALIASES and b in _GPU_ALIASES def _on_device(arr, xp, device): """Return whether ``arr`` lives on ``device`` according to its backend. Asks each backend a structured question rather than parsing the ``__repr__`` of a device object, so it doesn't break when a backend changes how it prints devices. Parameters ---------- arr : array An array produced by ``xp``. xp : module The array namespace that produced ``arr`` (e.g. ``numpy``, ``jax.numpy``, ``torch``, ``cupy``). device : str or None The expected device: ``"cpu"``, ``"cuda"``, ``"gpu"``, or ``None`` (treated as ``"cpu"``). Returns ------- bool Raises ------ NotImplementedError If ``xp`` is not a recognized backend. """ backend = _get_backend_name(xp) want_gpu = device is not None and device.lower() in _GPU_ALIASES want_cpu = device is None or device.lower() == "cpu" if backend == "numpy": # NumPy is CPU-only; "cuda"/"gpu" never matches. return want_cpu if backend == "cupy": # CuPy arrays are always on CUDA. return want_gpu if backend == "torch": # arr.device.type is "cpu" or "cuda" (or "mps", etc.) kind = arr.device.type if want_cpu: return kind == "cpu" if want_gpu: return kind == "cuda" return False if backend == "jax": # JAX device objects expose .platform: "cpu", "gpu", or "tpu". platform = arr.device.platform if want_cpu: return platform == "cpu" if want_gpu: return platform == "gpu" return False raise NotImplementedError(f"_on_device: unknown backend {backend!r}") def _read_env(): """Read backend/device environment variables.""" backend = os.environ.get("SKBIO_ARRAY_BACKEND", "").strip() device = os.environ.get("SKBIO_DEVICE", "").strip() or None return backend, device def _get_array_backends(): """Return dict of {name: (namespace, [devices])} for installed backends. The device strings stored here are each backend's *native* form — JAX uses ``"gpu"``, Torch and CuPy use ``"cuda"`` — because they get passed back to the backend (e.g. via ``_move_to_device``). """ _backends = {"numpy": (np, ["cpu"])} try: import jax import jax.numpy as jnp jax.config.update("jax_enable_x64", True) devices = ["cpu"] try: if jax.devices("gpu"): devices.append("gpu") except RuntimeError: pass _backends["jax"] = (jnp, devices) except ImportError: pass try: import torch devices = ["cpu"] if torch.cuda.is_available(): devices.append("cuda") _backends["torch"] = (torch, devices) except ImportError: pass try: import cupy _backends["cupy"] = (cupy, ["cuda"]) except ImportError: pass return _backends _BACKENDS = _get_array_backends() def _should_run(backend_name, device): """Check whether a backend/device combo should execute.""" env_backend, env_device = _read_env() if not env_backend: return backend_name == "numpy" and device == "cpu" if env_backend == "all": if env_device and not _device_specs_match(env_device, device): return False return True if env_backend != backend_name: return False if env_device and not _device_specs_match(env_device, device): return False return True def xp_assert_close(actual, desired, rtol=1e-7, atol=0): """Assert two arrays are element-wise equal within a tolerance. Converts both arrays to NumPy (handles GPU arrays), then delegates to ``numpy.testing.assert_allclose``. """ npt.assert_allclose(_to_numpy(actual), _to_numpy(desired), rtol=rtol, atol=atol) def xp_assert_equal(actual, desired): """Assert two arrays are element-wise exactly equal. Converts both arrays to NumPy (handles GPU arrays), then delegates to ``numpy.testing.assert_array_equal``. """ npt.assert_array_equal(_to_numpy(actual), _to_numpy(desired)) def array_backends(*backend_names, cpu_only=False): """Decorator: run a test method once per supported backend/device. Uses ``unittest.subTest()`` for per-backend reporting. Parameters ---------- *backend_names : str Backends to run on. Defaults to all if empty. cpu_only : bool, optional If True, skip GPU devices. Raises ------ RuntimeError If ``SKBIO_ARRAY_BACKEND`` names a backend that is not installed. """ if not backend_names: backend_names = ("numpy", "jax", "torch", "cupy") def decorator(test_func): @functools.wraps(test_func) def wrapper(self): env_backend, env_device = _read_env() # Hard error when a specific backend was requested but is missing. if env_backend and env_backend != "all" and env_backend not in _BACKENDS: raise RuntimeError( f"SKBIO_ARRAY_BACKEND={env_backend!r} but " f"{env_backend!r} is not installed. " f"Installed backends: {sorted(_BACKENDS.keys())}" ) ran_any = False for name in backend_names: if name not in _BACKENDS: continue xp, devices = _BACKENDS[name] for device in devices: if cpu_only and device != "cpu": continue if not _should_run(name, device): continue ran_any = True with self.subTest(backend=name, device=device): test_func(self, xp, device) if not ran_any: if env_device: raise RuntimeError( f"SKBIO_DEVICE={env_device!r} was requested but no " f"backend has that device available." ) raise unittest.SkipTest(f"No matching backends for {backend_names}") # Tag with a pytest marker so we can filter for CI with # `pytest -m array_api`. Falls back silently if pytest not installed. try: import pytest wrapper = pytest.mark.array_api(wrapper) except ImportError: pass return wrapper return decorator class ArrayAPITestMixin: """Mixin providing array-API test helpers for ``unittest.TestCase``. Mix into your test class alongside ``TestCase``:: class TestMyFunc(unittest.TestCase, ArrayAPITestMixin): ... """ def make_array(self, xp, device, data, dtype=None): """Create an array on the given backend and device.""" if dtype is None: dtype = xp.float64 arr = xp.asarray(data, dtype=dtype) return _move_to_device(arr, xp, device) def assert_close(self, actual, expected, rtol=1e-7, atol=1e-7): """Assert two arrays are numerically close (converts to numpy).""" xp_assert_close(actual, expected, rtol=rtol, atol=atol) def assert_type_preserved(self, result, xp, device): """Assert result is from the correct backend and on the right device.""" import array_api_compat as aac result_name = _get_backend_name(aac.array_namespace(result)) expected_name = _get_backend_name(xp) self.assertEqual( result_name, expected_name, f"Backend not preserved: result is {result_name}, expected {expected_name}", ) # Skip the device check on CPU: not every backend exposes a useful # device attribute for CPU arrays, and CPU/CPU is the trivial case. if device in (None, "cpu"): return self.assertTrue( _on_device(result, xp, device), f"Device not preserved: result on " f"{getattr(result, 'device', '')}, expected {device}", ) scikit-bio-scikit-bio-a3beaa6/skbio/util/_typing.py000066400000000000000000000202721520735541300224650ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from __future__ import annotations from typing import TypeAlias, Protocol, runtime_checkable, Any, overload import pandas as pd import numpy as np from numpy.typing import ArrayLike as NPArrayLike from skbio.table import Table from skbio.util import get_package # ------------------------------------------------ # ArrayLike (see: skbio.util._array) # ------------------------------------------------ @runtime_checkable class StdArray(Protocol): # pragma: no cover r"""Any object compliant with the Python array API standard [1]_. Examples are numpy.ndarray, cupy.ndarray, torch.Tensor, jax.Array, dask.array.Array, and sparse.SparseArray. See Also -------- ._array._get_array References ---------- .. [1] https://data-apis.org/array-api/latest/ Notes ----- This is a Protocol class (PEP 544) which defines the methods and properties that an object must implement to be considered compliant with the Python array API standards. Python array API standards and array-api-compat do not provide an official typing. A third-party library array-api-typing exists (https://pypi.org/project/array-api-typing/) but is not widely adopted. Typing for the array API is therefore manually defined here based on the standard [1]_. """ def __array_namespace__(self, api_version: str | None = None): ... # Attributes @property def dtype(self) -> Any: ... @property def device(self) -> Any: ... @property def T(self) -> StdArray: ... @property def mT(self) -> StdArray: ... @property def ndim(self) -> int: ... @property def shape(self) -> tuple[int, ...]: ... @property def size(self) -> int: ... # Comparison operators @overload def __eq__(self, other: int | float | bool | StdArray) -> StdArray: ... @overload def __eq__(self, other: Any) -> bool: ... @overload def __ne__(self, other: int | float | bool | StdArray) -> StdArray: ... @overload def __ne__(self, other: Any) -> bool: ... @overload def __lt__(self, other: int | float | bool | StdArray) -> StdArray: ... @overload def __lt__(self, other: Any) -> bool: ... @overload def __le__(self, other: int | float | bool | StdArray) -> StdArray: ... @overload def __le__(self, other: Any) -> bool: ... @overload def __gt__(self, other: int | float | bool | StdArray) -> StdArray: ... @overload def __gt__(self, other: Any) -> bool: ... @overload def __ge__(self, other: int | float | bool | StdArray) -> StdArray: ... @overload def __ge__(self, other: Any) -> bool: ... # Arithmetic operators def __pos__(self) -> StdArray: ... def __neg__(self) -> StdArray: ... def __add__(self, other: int | float | StdArray) -> StdArray: ... def __radd__(self, other: int | float | StdArray) -> StdArray: ... def __iadd__(self, other: int | float | StdArray) -> StdArray: ... def __sub__(self, other: int | float | StdArray) -> StdArray: ... def __rsub__(self, other: int | float | StdArray) -> StdArray: ... def __isub__(self, other: int | float | StdArray) -> StdArray: ... def __mul__(self, other: int | float | StdArray) -> StdArray: ... def __rmul__(self, other: int | float | StdArray) -> StdArray: ... def __imul__(self, other: int | float | StdArray) -> StdArray: ... def __truediv__(self, other: int | float | StdArray) -> StdArray: ... def __rtruediv__(self, other: int | float | StdArray) -> StdArray: ... def __itruediv__(self, other: int | float | StdArray) -> StdArray: ... def __floordiv__(self, other: int | float | StdArray) -> StdArray: ... def __rfloordiv__(self, other: int | float | StdArray) -> StdArray: ... def __ifloordiv__(self, other: int | float | StdArray) -> StdArray: ... def __mod__(self, other: int | float | StdArray) -> StdArray: ... def __rmod__(self, other: int | float | StdArray) -> StdArray: ... def __imod__(self, other: int | float | StdArray) -> StdArray: ... def __pow__(self, other: int | float | StdArray) -> StdArray: ... def __rpow__(self, other: int | float | StdArray) -> StdArray: ... def __ipow__(self, other: int | float | StdArray) -> StdArray: ... def __abs__(self) -> StdArray: ... # Array operators def __matmul__(self, other: int | float | StdArray) -> StdArray: ... def __rmatmul__(self, other: int | float | StdArray) -> StdArray: ... def __imatmul__(self, other: int | float | StdArray) -> StdArray: ... # Bitwise operators def __invert__(self) -> StdArray: ... def __and__(self, other: int | bool | StdArray) -> StdArray: ... def __rand__(self, other: int | bool | StdArray) -> StdArray: ... def __iand__(self, other: int | bool | StdArray) -> StdArray: ... def __or__(self, other: int | bool | StdArray) -> StdArray: ... def __ror__(self, other: int | bool | StdArray) -> StdArray: ... def __ior__(self, other: int | bool | StdArray) -> StdArray: ... def __xor__(self, other: int | bool | StdArray) -> StdArray: ... def __rxor__(self, other: int | bool | StdArray) -> StdArray: ... def __ixor__(self, other: int | bool | StdArray) -> StdArray: ... def __lshift__(self, other: int | StdArray) -> StdArray: ... def __rlshift__(self, other: int | StdArray) -> StdArray: ... def __ilshift__(self, other: int | StdArray) -> StdArray: ... def __rshift__(self, other: int | StdArray) -> StdArray: ... def __rrshift__(self, other: int | StdArray) -> StdArray: ... def __irshift__(self, other: int | StdArray) -> StdArray: ... # Indexing, slicing, and manipulation def __getitem__(self, key: Any) -> Any: ... def __setitem__(self, key: Any, value: Any) -> None: ... def __len__(self) -> int: ... def reshape(self, *shape: int, order: str = "C") -> StdArray: ... def squeeze(self, axis: int | tuple[int, ...] | None = None) -> StdArray: ... def astype(self, dtype: Any, copy: bool = True) -> StdArray: ... def all( self, axis: int | tuple[int, ...] | None = None, keepdims: bool = False ) -> StdArray: ... def any( self, axis: int | tuple[int, ...] | None = None, keepdims: bool = False ) -> StdArray: ... # Statistical functions def min( self, axis: int | tuple[int, ...] | None = None, keepdims: bool = False ) -> StdArray: ... def max( self, axis: int | tuple[int, ...] | None = None, keepdims: bool = False ) -> StdArray: ... def argmin(self, axis: int | tuple[int, ...] | None = None) -> StdArray: ... def argmax(self, axis: int | tuple[int, ...] | None = None) -> StdArray: ... def sum( self, axis: int | tuple[int, ...] | None = None, keepdims: bool = False ) -> StdArray: ... def mean( self, axis: int | tuple[int, ...] | None = None, keepdims: bool = False ) -> StdArray: ... def std( self, axis: int | tuple[int, ...] | None = None, keepdims: bool = False ) -> StdArray: ... def var( self, axis: int | tuple[int, ...] | None = None, keepdims: bool = False ) -> StdArray: ... ArrayLike: TypeAlias = NPArrayLike | StdArray # ------------------------------------------------ # TableLike (see: skbio.table._tabular) # ------------------------------------------------ # Base types which are always available TableLike: TypeAlias = pd.DataFrame | np.ndarray | Table # add other types depending on availability pl = get_package("polars", raise_error=False) if pl is not None: # pragma: no cover TableLike = TableLike | pl.DataFrame # type: ignore[misc] adt = get_package("anndata", raise_error=False) if adt is not None: # pragma: no cover TableLike = TableLike | adt.AnnData # type: ignore[misc] # ------------------------------------------------ # SeedLike (see: skbio.util.get_rng) # ------------------------------------------------ SeedLike: TypeAlias = int | np.random.Generator | np.random.RandomState scikit-bio-scikit-bio-a3beaa6/skbio/util/_warning.py000066400000000000000000000101421520735541300226130ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- """Warning utilities.""" from warnings import warn, simplefilter def _warn_once(func, warning, message, param=None): r"""Warn once Parameters ---------- func : callable Function that triggers the warning. warning : class Warning type. message : str Warning message. param : str, optional Parameter of the function that triggers the warning. Notes ----- The warning is raised only at the first call of the function. Meanwhile, a "_warned" attribute is added to the function, which prevents subsequent warnings. If a parameter is given, the warning is raised at the first use of the particular parameter, while not affect the host function or other parameters. Meanwhile, a "_warned_params" attribute of the function will contain the parameter to prevent subsequent warnings. """ if not param: if not hasattr(func, "_warned"): simplefilter("once", warning) warn(message, warning) func._warned = True else: if not hasattr(func, "_warned_params"): func._warned_params = set() if param not in func._warned_params: simplefilter("once", warning) warn(message, warning) func._warned_params.add(param) def _deprecation_message(name, ver=None, msg=None, append=True): """Create a message indicating deprecation.""" if msg and not append: return msg if ver: message = f"{name} has been deprecated since {ver}." else: message = f"{name} is deprecated." if msg: message += " " + msg return message def _warn_deprecated(func, ver=None, msg=None, append=True): r"""Warn of deprecated status of a function. Parameters ---------- func : callable Function that triggers the warning. ver : str, optional Version when deprecation became effective. msg : str, optional A custom warning message. append : bool, optional Append the custom message to the end of the default message (True, default), or replace the entire default message with the custom message (False). See Also -------- _warn_param_deprecated """ msg = _deprecation_message(f"`{func.__name__}`", ver, msg, append) _warn_once(func, DeprecationWarning, msg) def _warn_param_deprecated(func, param, ver=None, msg=None, append=True): r"""Warn of deprecated status of a parameter of a function. Parameters ---------- func : callable Function that hosts the parameter. param : str Parameter that triggers the warning. ver : str, optional msg : str, optional append : bool, optional Refer to :func:`_warn_deprecated`. See Also -------- _warn_deprecated """ msg = _deprecation_message( f"`{func.__name__}`'s parameter `{param}`", ver, msg, append ) _warn_once(func, DeprecationWarning, msg, param) def _renaming_message(oldname, newname, ver=None): """Create a message indicating renaming.""" if ver: message = f"{oldname} was renamed to {newname} in {ver}." else: message = f"{oldname} has been renamed to {newname}." message += " The old name is kept as an alias but is deprecated." return message def _warn_renamed(func, oldname, ver=None): """Warn of renaming status of a function.""" msg = _renaming_message(f"`{oldname}`", f"`{func.__name__}`", ver) _warn_once(func, DeprecationWarning, msg) def _warn_param_renamed(func, param, oldname, ver=None): """Warn of renaming status of a parameter of a function.""" msg = _renaming_message( f"`{func.__name__}`'s parameter `{oldname}`", f"`{param}`", ver ) _warn_once(func, DeprecationWarning, msg, param) scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/000077500000000000000000000000001520735541300216015ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/__init__.py000066400000000000000000000005411520735541300237120ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/test_array.py000066400000000000000000000410241520735541300243310ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main, skipIf from unittest.mock import MagicMock, patch import numpy as np import pandas as pd import numpy.testing as npt import array_api_compat as aac from skbio.util import get_package, _is_usable from skbio.util._array import ( ingest_array, _get_array, _to_numpy, _move_to_device, _get_backend_name, ) # import optional dependencies cp = get_package("cupy", raise_error=False) jax = get_package("jax", raise_error=False) torch = get_package("torch", raise_error=False) xr = get_package("xarray", raise_error=False) da = get_package("dask.array", raise_error=False) CUPY_OK = _is_usable(cp, lambda: cp.arange(1)) TORCH_OK = _is_usable(torch, lambda: torch.arange(1)) JAX_OK = _is_usable(jax, lambda: jax.numpy.arange(1)) DASK_OK = _is_usable(da, lambda: da.arange(1, chunks=1).compute()) XARRAY_OK = _is_usable(xr, lambda: xr.DataArray([1])) # Get the numpy namespace via array_api_compat (aac has no .numpy attribute). np_xp = aac.array_namespace(np.empty(0)) # ===================================================================== # Tests for _get_array # ===================================================================== class TestGetArray(TestCase): def test_non_array_converted_to_numpy(self): # A plain list is not an array API object; should become ndarray. obs = _get_array([1, 2, 3]) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.array([1, 2, 3])) def test_numpy_array_returned_as_is(self): arr = np.arange(5) obs = _get_array(arr) self.assertIs(obs, arr) def test_numpy_array_to_numpy_noop(self): arr = np.arange(5) obs = _get_array(arr, to_numpy=True) self.assertIs(obs, arr) @skipIf(not TORCH_OK, "PyTorch is not usable.") def test_torch_kept_when_to_numpy_false(self): ten = torch.arange(5) obs = _get_array(ten) self.assertIsInstance(obs, torch.Tensor) self.assertIs(obs, ten) @skipIf(not TORCH_OK, "PyTorch is not usable.") def test_torch_to_numpy_via_dlpack(self): ten = torch.arange(5) obs = _get_array(ten, to_numpy=True) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) @skipIf(not CUPY_OK, "CuPy is not usable.") def test_cupy_to_numpy(self): arr = cp.arange(5) obs = _get_array(arr, to_numpy=True) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) @skipIf(not JAX_OK, "JAX is not usable.") def test_jax_to_numpy(self): arr = jax.numpy.arange(5) obs = _get_array(arr, to_numpy=True) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) @skipIf(not DASK_OK, "Dask is not usable.") def test_dask_to_numpy_fallback(self): # Dask doesn't support __dlpack__, so _get_array should fall back # to np.asarray. arr = da.arange(5, chunks=5) obs = _get_array(arr, to_numpy=True) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) def test_to_numpy_dlpack_fallback(self): class FakeArr: def __array__(self, dtype=None, copy=None): return np.array([10, 20, 30]) for exc in (AttributeError, TypeError, RuntimeError): with self.subTest(exception=exc.__name__): with patch.object(aac, "is_array_api_obj", return_value=True), \ patch.object(aac, "is_numpy_array", return_value=False), \ patch("skbio.util._array.np.from_dlpack", side_effect=exc): obs = _get_array(FakeArr(), to_numpy=True) self.assertIsInstance(obs, np.ndarray) # ===================================================================== # Tests for _to_numpy # ===================================================================== class TestToNumpy(TestCase): def test_numpy_passthrough(self): arr = np.arange(5) obs = _to_numpy(arr) self.assertIs(obs, arr) @skipIf(not TORCH_OK, "PyTorch is not usable.") def test_torch_cpu(self): ten = torch.arange(5) obs = _to_numpy(ten) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) @skipIf(not TORCH_OK, "PyTorch is not usable.") def test_torch_requires_grad(self): ten = torch.arange(5, dtype=torch.float32).requires_grad_(True) obs = _to_numpy(ten) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5, dtype=np.float32)) @skipIf(not CUPY_OK, "CuPy is not usable.") def test_cupy(self): arr = cp.arange(5) obs = _to_numpy(arr) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) @skipIf(not JAX_OK, "JAX is not usable.") def test_jax(self): arr = jax.numpy.arange(5) obs = _to_numpy(arr) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) @skipIf(not DASK_OK, "Dask is not usable.") def test_dask(self): arr = da.arange(5, chunks=5) obs = _to_numpy(arr) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) def test_generic_array_via_np_asarray(self): # An object with no .detach and no .get falls through to np.asarray. mock_arr = MagicMock(spec=[]) mock_arr.__array__ = lambda dtype=None, copy=None: np.array([7, 8, 9]) # Ensure it's not ndarray and has no detach/get. self.assertNotIsInstance(mock_arr, np.ndarray) obs = _to_numpy(mock_arr) self.assertIsInstance(obs, np.ndarray) # ===================================================================== # Tests for _move_to_device # ===================================================================== class TestMoveToDevice(TestCase): def test_none_device_returns_same(self): arr = np.arange(5) obs = _move_to_device(arr, np, None) self.assertIs(obs, arr) def test_cpu_device_returns_same(self): arr = np.arange(5) obs = _move_to_device(arr, np, "cpu") self.assertIs(obs, arr) @skipIf(not TORCH_OK, "PyTorch is not usable.") def test_torch_cpu_noop(self): ten = torch.arange(5) obs = _move_to_device(ten, torch, "cpu") self.assertIs(obs, ten) @skipIf(not TORCH_OK or not torch.cuda.is_available(), "PyTorch CUDA is not usable.") def test_torch_cuda(self): ten = torch.arange(5) obs = _move_to_device(ten, torch, "cuda") self.assertTrue(obs.is_cuda) npt.assert_array_equal(obs.cpu().numpy(), np.arange(5)) def test_numpy_non_cpu_passthrough(self): # NumPy arrays are always on CPU; non-cpu device returns unchanged. arr = np.arange(5) obs = _move_to_device(arr, np, "gpu") self.assertIs(obs, arr) @skipIf(not CUPY_OK, "CuPy is not usable.") def test_cupy_non_cpu_passthrough(self): import cupy arr = cupy.arange(5) obs = _move_to_device(arr, cupy, "gpu") self.assertIs(obs, arr) @skipIf(not TORCH_OK, "PyTorch is not usable.") def test_torch_to_device(self): # torch.to("cpu") should work and return a CPU tensor. ten = torch.arange(5) # Use a module whose __name__ starts with "torch". obs = _move_to_device(ten, torch, "cpu") # device=cpu means early return, so test with a mock device name # that triggers the torch branch but stays on cpu. self.assertIs(obs, ten) # ===================================================================== # Tests for _get_backend_name # ===================================================================== class TestGetBackendName(TestCase): def test_numpy(self): self.assertEqual(_get_backend_name(np_xp), "numpy") @skipIf(not TORCH_OK, "PyTorch is not usable.") def test_torch(self): xp = aac.array_namespace(torch.arange(1)) self.assertEqual(_get_backend_name(xp), "torch") @skipIf(not CUPY_OK, "CuPy is not usable.") def test_cupy(self): xp = aac.array_namespace(cp.arange(1)) self.assertEqual(_get_backend_name(xp), "cupy") @skipIf(not JAX_OK, "JAX is not usable.") def test_jax(self): xp = aac.array_namespace(jax.numpy.arange(1)) self.assertEqual(_get_backend_name(xp), "jax") @skipIf(not DASK_OK, "Dask is not usable.") def test_dask(self): xp = aac.array_namespace(da.arange(1, chunks=1)) self.assertEqual(_get_backend_name(xp), "dask") def test_unknown_namespace_with_name(self): mock_ns = MagicMock() mock_ns.__name__ = "mystery_lib" with patch.dict( "skbio.util._array._BACKEND_CHECKERS", {k: (lambda ns: False) for k in ["numpy", "cupy", "torch", "jax", "dask"]}, ): self.assertEqual(_get_backend_name(mock_ns), "mystery_lib") def test_unknown_namespace_without_name(self): mock_ns = object() with patch.dict( "skbio.util._array._BACKEND_CHECKERS", {k: (lambda ns: False) for k in ["numpy", "cupy", "torch", "jax", "dask"]}, ): result = _get_backend_name(mock_ns) # Falls back to str(xp) since object has no __name__. self.assertIsInstance(result, str) # ===================================================================== # Tests for ingest_array (original tests preserved + additions) # ===================================================================== class TestIngestArray(TestCase): def test_ingest_array_numpy(self): # NumPy arrays are kept as-is. arr = np.arange(5) xp, obs = ingest_array(arr) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) self.assertIs(obs, arr) npt.assert_array_equal(obs, np.arange(5)) xp, obs = ingest_array(arr, to_numpy=True) self.assertIs(xp, np_xp) self.assertIs(obs, arr) # 2-D array arr = np.arange(9).reshape(3, 3) xp, obs = ingest_array(arr) self.assertIs(xp, np_xp) self.assertIs(obs, arr) npt.assert_array_equal(obs, np.arange(9).reshape(3, 3)) def test_ingest_array_sequence(self): # Plain Python lists are converted into NumPy arrays. lst = list(range(5)) xp, obs = ingest_array(lst) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.asarray(lst)) tup = tuple(range(5)) xp, obs = ingest_array(tup) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.asarray(tup)) ran = range(5) xp, obs = ingest_array(ran) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.asarray(ran)) def test_ingest_array_pyarray(self): # Python's built-in array is not an API-compatible array library. import array as pyarray arr = pyarray.array('i', range(5)) xp, obs = ingest_array(arr) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.asarray(arr)) @skipIf(not CUPY_OK, "CuPy is not usable.") def test_ingest_array_cupy(self): # CuPy arrays are kept as-is in default mode. arr = cp.arange(5) xp, obs = ingest_array(arr) self.assertTrue(aac.is_cupy_namespace(xp)) self.assertIsInstance(obs, cp.ndarray) self.assertIs(obs, arr) npt.assert_array_equal(cp.asnumpy(obs), np.arange(5)) # Convert CuPy arrays into NumPy arrays. xp, obs = ingest_array(arr, to_numpy=True) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) @skipIf(not TORCH_OK, "PyTorch is not usable.") def test_ingest_array_torch(self): # PyTorch tensors are kept as-is in default mode. ten = torch.arange(5) xp, obs = ingest_array(ten) self.assertTrue(aac.is_torch_namespace(xp)) self.assertIsInstance(obs, torch.Tensor) self.assertIs(obs, ten) npt.assert_array_equal(obs.numpy(), np.arange(5)) # Convert PyTorch tensors into NumPy arrays. xp, obs = ingest_array(ten, to_numpy=True) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) @skipIf(not JAX_OK, "JAX is not usable.") def test_ingest_array_jax(self): # JAX arrays are kept as-is in default mode. arr = jax.numpy.arange(5) xp, obs = ingest_array(arr) self.assertTrue(aac.is_jax_namespace(xp)) self.assertIsInstance(obs, jax.Array) self.assertIs(obs, arr) npt.assert_array_equal(np.asarray(obs), np.arange(5)) # Convert JAX arrays into NumPy arrays. xp, obs = ingest_array(arr, to_numpy=True) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(5)) @skipIf(not DASK_OK, "Dask is not usable.") def test_ingest_array_dask(self): # Dask arrays are kept as-is in default mode. arr = da.arange(20, chunks=4) xp, obs = ingest_array(arr) self.assertTrue(aac.is_dask_namespace(xp)) self.assertIsInstance(obs, da.Array) self.assertIs(obs, arr) npt.assert_array_equal(obs.compute(), np.arange(20)) # Convert Dask arrays into NumPy arrays. xp, obs = ingest_array(arr, to_numpy=True) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.arange(20)) def test_ingest_array_scalar(self): # Scalars are converted into 0-D NumPy arrays. xp, obs = ingest_array(42) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.array(42)) self.assertEqual(obs.ndim, 0) # Strings are also scalars (not treated as sequences of characters). xp, obs = ingest_array("hello") self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.array("hello")) self.assertEqual(obs.ndim, 0) xp, obs = ingest_array(None) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(obs, np.array(None)) self.assertEqual(obs.ndim, 0) def test_ingest_array_pandas(self): # Pandas Series' are not API-compatible arrays, but they can be casted into # NumPy arrays. s = pd.Series(range(5), index=list("abcde")) xp, obs = ingest_array(s) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(s.to_numpy(), np.arange(5)) # So are Pandas DataFrames. df = s.to_frame() xp, obs = ingest_array(df) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(df.to_numpy(), np.arange(5).reshape(-1, 1)) @skipIf(not XARRAY_OK, "Xarray is not usable.") def test_ingest_array_xarray(self): # Xarray DataArrays are not API-compatible arrays, but they can be casted into # Numpy arrays. xarr = xr.DataArray(range(5)) xp, obs = ingest_array(xarr) self.assertIs(xp, np_xp) self.assertIsInstance(obs, np.ndarray) npt.assert_array_equal(xarr.to_numpy(), np.arange(5)) def test_ingest_array_multiple(self): # Multiple arrays should all be returned with shared namespace. a = np.arange(3) b = np.ones(4) xp, oa, ob = ingest_array(a, b) self.assertIs(xp, np_xp) self.assertIs(oa, a) self.assertIs(ob, b) def test_ingest_array_multiple_mixed(self): # Mix of list and ndarray; both should come back as ndarray. a = [1, 2, 3] b = np.ones(3) xp, oa, ob = ingest_array(a, b) self.assertIs(xp, np_xp) self.assertIsInstance(oa, np.ndarray) self.assertIs(ob, b) if __name__ == "__main__": main()scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/test_decorator.py000066400000000000000000000160551520735541300252030ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import sys import unittest import inspect import warnings from skbio.util import classproperty from skbio.util._decorator import ( overrides, classproperty, classonlymethod, deprecated, aliased, register_aliases, params_aliased, ) from skbio.util._exception import OverrideError class TestClassOnlyMethod(unittest.TestCase): def test_works_on_class(self): class A: @classonlymethod def example(cls): return cls self.assertEqual(A.example(), A) def test_fails_on_instance(self): class A: @classonlymethod def example(cls): pass with self.assertRaises(TypeError) as e: A().example() self.assertIn('A.example', str(e.exception)) self.assertIn('instance', str(e.exception)) def test_matches_classmethod(self): class A: pass def example(cls, thing): """doc""" A.example1 = classmethod(example) A.example2 = classonlymethod(example) self.assertEqual(A.__dict__['example1'].__func__, example) self.assertEqual(A.__dict__['example2'].__func__, example) self.assertEqual(A.example1.__doc__, example.__doc__) self.assertEqual(A.example2.__doc__, example.__doc__) self.assertEqual(A.example1.__name__, example.__name__) self.assertEqual(A.example2.__name__, example.__name__) def test_passes_args_kwargs(self): self.ran_test = False class A: @classonlymethod def example(cls, arg1, arg2, kwarg1=None, kwarg2=None, default=5): self.assertEqual(arg1, 1) self.assertEqual(arg2, 2) self.assertEqual(kwarg1, '1') self.assertEqual(kwarg2, '2') self.assertEqual(default, 5) self.ran_test = True A.example(1, *[2], kwarg2='2', **{'kwarg1': '1'}) self.assertTrue(self.ran_test) class TestOverrides(unittest.TestCase): def test_raises_when_missing(self): class A: pass with self.assertRaises(OverrideError): class B(A): @overrides(A) def test(self): pass def test_doc_inherited(self): class A: def test(self): """Docstring""" pass class B(A): @overrides(A) def test(self): pass self.assertEqual(B.test.__doc__, "Docstring") def test_doc_not_inherited(self): class A: def test(self): """Docstring""" pass class B(A): @overrides(A) def test(self): """Different""" pass self.assertEqual(B.test.__doc__, "Different") class TestClassProperty(unittest.TestCase): def test_getter_only(self): class Foo: _foo = 42 @classproperty def foo(cls): return cls._foo # class-level getter self.assertEqual(Foo.foo, 42) # instance-level getter f = Foo() self.assertEqual(f.foo, 42) with self.assertRaises(AttributeError): f.foo = 4242 def test_no_owner(self): class Foo: _foo = 42 @classproperty def foo(cls): return cls._foo class Bar(Foo): _foo = 84 descriptor = Foo.__dict__["foo"] # Exercise classproperty.__get__(obj, owner=None) explicitly. self.assertEqual(descriptor.__get__(Foo(), None), 42) self.assertEqual(descriptor.__get__(Bar(), None), 84) class TestDeprecated(unittest.TestCase): def test_deprecated(self): @deprecated("1.0", msg="It will be removed soon.") def foo(param): """I am a function. Parameters ---------- param : str I am a parameter. """ pass msg = ".. deprecated:: 1.0 It will be removed soon." self.assertIn(msg, foo.__doc__) with self.assertWarns(DeprecationWarning) as ctx: foo("bar") msg = "`foo` has been deprecated since 1.0. It will be removed soon." self.assertEqual(str(ctx.warning), msg) class TestAliases(unittest.TestCase): def test_aliased(self): # apply to a function @aliased("bar") def foo(param): return param self.assertEqual(foo._alias[0], "bar") self.assertTrue(callable(foo._alias[1])) self.assertTrue(foo._alias[1]._skipdoc) self.assertEqual(foo.__doc__, f"Alias: ``bar``\n") self.assertEqual(foo(42), 42) self.assertEqual(foo._alias[1](42), 42) # apply to a class method class Foo: @aliased("bar") def foo(cls, param): return param self.assertEqual(Foo.foo._alias[0], "bar") def test_register_aliases(self): @register_aliases class Foo: @aliased("bar", ver="1.0", warn=True) def foo(self, param): return param # class level self.assertTrue(hasattr(Foo, "bar")) self.assertTrue(Foo.bar._skipdoc) # instance level f = Foo() self.assertTrue(hasattr(f, "bar")) # check warning self.assertFalse(hasattr(f.foo, "_warned")) msg = "`bar` was renamed to `foo` in 1.0." with self.assertWarnsRegex(DeprecationWarning, msg): f.bar(42) self.assertTrue(hasattr(f.foo, "_warned")) def test_params_aliased(self): @params_aliased([ ("param1", "alias1", None, False), ("param2", "alias2", "1.0", True), ]) def foo(param1, param2): """I am a function. Parameters ---------- param1 : int The first parameter. param2 : int The second parameter. Returns ------- int Sum of the two parameters. """ return param1 + param2 self.assertIn("Renamed from ``alias2``.", foo.__doc__) self.assertEqual(foo(1, 2), 3) self.assertEqual(foo(param1=1, param2=2), 3) self.assertEqual(foo(alias1=1, param2=2), 3) msg = "`foo`'s parameter `alias2` was renamed to `param2` in 1.0." with self.assertWarnsRegex(DeprecationWarning, msg): obs = foo(param1=1, alias2=2) self.assertEqual(obs, 3) with self.assertRaises(TypeError): foo(1, 2, alias1=2) if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/test_docstring.py000066400000000000000000000277411520735541300252210ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from skbio.util._docstring import ( _note_into_doc, _note_into_doc_param, _array_api_compat_section, _insert_into_notes_section, _deprecation_note, _renaming_note, ) class TestNoteIntoDoc(unittest.TestCase): def setUp(self): self.docstring = """An example function. Here is an example function with a typical docstring. Parameters ---------- param1 : int The first parameter. param2 : str, optional The second parameter. Returns ------- float The return value. """ def test_normal_case(self): note = ".. note:: This is a note.\n" obs = _note_into_doc(note, self.docstring) exp = """An example function. .. note:: This is a note. Here is an example function with a typical docstring. """ self.assertIn(exp, obs) def test_no_docstring(self): note = ".. note:: This is a note.\n" obs = _note_into_doc(note, "") self.assertEqual(obs, note) def test_single_line_docstring(self): note = ".. note:: This is a note.\n" obs = _note_into_doc(note, "Hello!") self.assertEqual(obs, f"Hello!\n\n{note}") def test_single_line_with_trailing_newline(self): note = ".. note:: This is a note.\n" obs = _note_into_doc(note, "Hello!\n") self.assertEqual(obs, f"Hello!\n\n{note}") def test_single_paragraph(self): note = ".. note:: This is a note.\n" obs = _note_into_doc(note, "Hello!\nHello!\nHello!\n") self.assertEqual(obs, f"Hello!\nHello!\nHello!\n\n{note}") def test_single_paragraph_with_indentation(self): note = ".. note:: This is a note.\n" doc = """Hello! I am the header paragraph. """ obs = _note_into_doc(note, doc) exp = """Hello! I am the header paragraph. .. note:: This is a note. """ self.assertEqual(obs, exp) def test_note_trailing_whitespace_stripped(self): """Note with extra trailing whitespace should be normalized.""" note = ".. note:: Trailing. \n\n" obs = _note_into_doc(note, "") self.assertEqual(obs, ".. note:: Trailing.\n") class TestNoteIntoDocParam(unittest.TestCase): def setUp(self): self.docstring = """An example function. Here is an example function with a typical docstring. Parameters ---------- param1 : int The first parameter. param2 : str, optional The second parameter. Returns ------- float The return value. """ def test_first_parameter(self): note = ".. note:: This is a note." obs = _note_into_doc_param(note, self.docstring, "param1") exp = """ param1 : int The first parameter. .. note:: This is a note. param2 : str, optional """ self.assertIn(exp, obs) def test_last_parameter(self): note = ".. note:: This is a note." obs = _note_into_doc_param(note, self.docstring, "param2") exp = """ param2 : str, optional The second parameter. .. note:: This is a note. Returns """ self.assertIn(exp, obs) def test_missing_parameter(self): note = ".. note:: This is a note." with self.assertRaises(ValueError): _note_into_doc_param(note, self.docstring, "param3") def test_no_section_after_param(self): note = ".. note:: This is a note." doc = self.docstring[:self.docstring.find("Returns")] obs = _note_into_doc_param(note, doc, "param2") exp = """ param2 : str, optional The second parameter. .. note:: This is a note. """ self.assertTrue(obs.endswith(exp)) class TestArrayApiCompatSection(unittest.TestCase): def test_single_backend_default_devices(self): result = _array_api_compat_section(["numpy"]) self.assertIn("array API standard", result) self.assertIn("NumPy", result) self.assertIn("CPU", result) self.assertIn("\u2713", result) def test_multiple_backends_default_devices(self): result = _array_api_compat_section(["numpy", "torch", "jax"]) self.assertIn("NumPy", result) self.assertIn("PyTorch", result) self.assertIn("JAX", result) self.assertIn("CPU", result) self.assertIn("GPU", result) # NumPy doesn't support GPU self.assertIn("n/a", result) def test_explicit_devices(self): result = _array_api_compat_section(["numpy", "torch"], devices=["cpu"]) self.assertIn("CPU", result) # GPU column should not appear self.assertNotIn("GPU", result) def test_unknown_backend_fallback(self): """Unknown backend should capitalize its name and default to cpu.""" result = _array_api_compat_section(["mylib"]) self.assertIn("Mylib", result) self.assertIn("CPU", result) self.assertIn("\u2713", result) def test_cupy_backend(self): result = _array_api_compat_section(["cupy"]) self.assertIn("CuPy", result) self.assertIn("GPU", result) self.assertIn("\u2713", result) def test_dask_backend(self): result = _array_api_compat_section(["dask"]) self.assertIn("Dask", result) self.assertIn("CPU", result) def test_all_known_backends(self): result = _array_api_compat_section( ["numpy", "cupy", "torch", "jax", "dask"]) for name in ("NumPy", "CuPy", "PyTorch", "JAX", "Dask"): self.assertIn(name, result) def test_table_structure(self): """Table should have proper RST grid table delimiters.""" result = _array_api_compat_section(["numpy"]) lines = result.strip().splitlines() # Table lines start with + or | table_lines = [l for l in lines if l.lstrip().startswith(("+", "|"))] self.assertTrue(len(table_lines) >= 5) # Header separator uses = header_seps = [l for l in table_lines if "=" in l] self.assertTrue(len(header_seps) >= 1) def test_explicit_devices_filters_supported(self): """When devices are explicit, only those devices the backend supports appear.""" result = _array_api_compat_section(["numpy"], devices=["cpu", "gpu"]) # NumPy only supports cpu, so gpu should show n/a self.assertIn("n/a", result) def test_note_directive(self): """Output should be wrapped in a note admonition with an indented body.""" result = _array_api_compat_section(["numpy"]) self.assertTrue(result.startswith(".. note::")) # Table rows must be indented (inside the note body), not flush-left table_lines = [l for l in result.splitlines() if l.lstrip().startswith(("+", "|"))] self.assertTrue(len(table_lines) >= 5) self.assertTrue(all(l.startswith(" ") for l in table_lines)) class TestInsertIntoNotesSection(unittest.TestCase): def test_existing_notes_section(self): doc = """My function. Parameters ---------- x : int A value. Notes ----- Some existing notes. """ note = "This is new.\n" result = _insert_into_notes_section(note, doc) # The new note should appear inside the Notes section self.assertIn("This is new.", result) # The existing notes should still be there self.assertIn("Some existing notes.", result) # The new note should come before the existing notes new_pos = result.index("This is new.") old_pos = result.index("Some existing notes.") self.assertLess(new_pos, old_pos) def test_no_notes_section(self): doc = """My function. Parameters ---------- x : int A value. """ note = "This is new.\n" result = _insert_into_notes_section(note, doc) # A Notes section should be created self.assertIn("Notes", result) self.assertIn("-----", result) self.assertIn("This is new.", result) def test_single_line_doc_no_notes(self): doc = "Short docstring." note = "Added note." result = _insert_into_notes_section(note, doc) self.assertIn("Notes", result) self.assertIn("-----", result) self.assertIn("Added note.", result) def test_note_trailing_whitespace_stripped(self): doc = """My function. Notes ----- Existing. """ note = "New note. \n\n" result = _insert_into_notes_section(note, doc) self.assertIn("New note.", result) # Trailing whitespace from note should not appear self.assertNotIn("New note. ", result) def test_multiline_note(self): doc = """My function. Notes ----- Existing. """ note = "Line one.\nLine two.\n" result = _insert_into_notes_section(note, doc) self.assertIn("Line one.", result) self.assertIn("Line two.", result) def test_notes_with_blank_lines_after_header(self): """Blank lines between Notes header and content should be handled.""" doc = """My function. Notes ----- Existing content here. """ note = "Inserted." result = _insert_into_notes_section(note, doc) inserted_pos = result.index("Inserted.") existing_pos = result.index("Existing content here.") self.assertLess(inserted_pos, existing_pos) class TestDeprecationNote(unittest.TestCase): def test_version_only(self): result = _deprecation_note(ver="0.5.0") self.assertEqual(result, ".. deprecated:: 0.5.0") def test_version_and_message(self): result = _deprecation_note(ver="0.5.0", msg="Use bar instead.") self.assertEqual(result, ".. deprecated:: 0.5.0 Use bar instead.") def test_no_version(self): result = _deprecation_note() self.assertEqual(result, ".. deprecated:: None") def test_no_message(self): result = _deprecation_note(ver="1.0", msg=None) self.assertEqual(result, ".. deprecated:: 1.0") def test_empty_message(self): result = _deprecation_note(ver="1.0", msg="") self.assertEqual(result, ".. deprecated:: 1.0") class TestRenamingNote(unittest.TestCase): def test_no_version(self): result = _renaming_note("old_func") self.assertEqual(result, "Alias: ``old_func``") def test_with_version(self): result = _renaming_note("old_func", ver="0.6.0") self.assertIn("versionchanged:: 0.6.0", result) self.assertIn("Renamed from ``old_func``", result) self.assertIn("kept as an alias", result) self.assertNotIn("deprecated", result) self.assertTrue(result.endswith(".")) def test_with_version_and_warn(self): result = _renaming_note("old_func", ver="0.6.0", warn=True) self.assertIn("versionchanged:: 0.6.0", result) self.assertIn("Renamed from ``old_func``", result) self.assertIn("but is deprecated", result) self.assertTrue(result.endswith(".")) def test_warn_without_version(self): """warn is irrelevant without ver — should return alias form.""" result = _renaming_note("old_func", warn=True) self.assertEqual(result, "Alias: ``old_func``") def test_empty_version_string(self): result = _renaming_note("old_func", ver="") self.assertEqual(result, "Alias: ``old_func``") if __name__ == '__main__': unittest.main()scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/test_misc.py000066400000000000000000000172561520735541300241600ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main from io import BytesIO import re from skbio.util._misc import ( cardinal_to_ordinal, safe_md5, find_duplicates, MiniRegistry, chunk_str, resolve_key, ) class TestMiniRegistry(TestCase): def setUp(self): self.registry = MiniRegistry() def test_decoration(self): self.assertNotIn("name1", self.registry) self.assertNotIn("name2", self.registry) self.n1_called = False self.n2_called = False @self.registry("name1") def some_registration1(): self.n1_called = True @self.registry("name2") def some_registration2(): self.n2_called = True self.assertIn("name1", self.registry) self.assertEqual(some_registration1, self.registry["name1"]) self.assertIn("name2", self.registry) self.assertEqual(some_registration2, self.registry["name2"]) self.registry["name1"]() self.assertTrue(self.n1_called) self.registry["name2"]() self.assertTrue(self.n2_called) def test_copy(self): @self.registry("name") def some_registration(): pass new = self.registry.copy() self.assertIsNot(new, self.registry) @new("other") def other_registration(): pass self.assertIn("name", self.registry) self.assertNotIn("other", self.registry) self.assertIn("other", new) self.assertIn("name", new) def test_everything(self): class SomethingToInterpolate: def interpolate_me(): """First line Some description of things, also this: Other things are happening now. """ def dont_interpolate_me(): """First line Some description of things, also this: Other things are happening now. """ class Subclass(SomethingToInterpolate): pass @self.registry("a") def a(): """x""" @self.registry("b") def b(): """y""" @self.registry("c") def c(): """z""" subclass_registry = self.registry.copy() @subclass_registry("o") def o(): """p""" self.registry.interpolate(SomethingToInterpolate, "interpolate_me") subclass_registry.interpolate(Subclass, "interpolate_me") # Python 3.13+ removes leading whitespaces from a docstring, therefore it is # necessary to make this edit. def _strip_spaces(s): return re.sub(r'^\s+', '', s, flags=re.MULTILINE) obs = _strip_spaces(SomethingToInterpolate.interpolate_me.__doc__) exp = ("First line\nSome description of things, also this:\n'a'\nx" "\n'b'\ny\n'c'\nz\nOther things are happening now.\n") self.assertEqual(obs, exp) obs = _strip_spaces(SomethingToInterpolate.dont_interpolate_me.__doc__) exp = ("First line\nSome description of things, also this:\nOther things " "are happening now.\n") self.assertEqual(obs, exp) obs = _strip_spaces(Subclass.interpolate_me.__doc__) exp = ("First line\nSome description of things, also this:\n'a'\nx\n'b'\ny\n" "'c'\nz\n'o'\np\nOther things are happening now.\n") self.assertEqual(obs, exp) obs = _strip_spaces(Subclass.dont_interpolate_me.__doc__) exp = ("First line\nSome description of things, also this:\nOther things " "are happening now.\n") self.assertEqual(obs, exp) class ResolveKeyTests(TestCase): def test_callable(self): def func(x): return str(x) self.assertEqual(resolve_key(1, func), "1") self.assertEqual(resolve_key(4, func), "4") def test_index(self): class MetadataHaver(dict): @property def metadata(self): return self obj = MetadataHaver({'foo': 123}) self.assertEqual(resolve_key(obj, 'foo'), 123) obj = MetadataHaver({'foo': 123, 'bar': 'baz'}) self.assertEqual(resolve_key(obj, 'bar'), 'baz') def test_wrong_type(self): with self.assertRaises(TypeError): resolve_key({'foo': 1}, 'foo') class ChunkStrTests(TestCase): def test_even_split(self): self.assertEqual(chunk_str('abcdef', 6, ' '), 'abcdef') self.assertEqual(chunk_str('abcdef', 3, ' '), 'abc def') self.assertEqual(chunk_str('abcdef', 2, ' '), 'ab cd ef') self.assertEqual(chunk_str('abcdef', 1, ' '), 'a b c d e f') self.assertEqual(chunk_str('a', 1, ' '), 'a') self.assertEqual(chunk_str('abcdef', 2, ''), 'abcdef') def test_no_split(self): self.assertEqual(chunk_str('', 2, '\n'), '') self.assertEqual(chunk_str('a', 100, '\n'), 'a') self.assertEqual(chunk_str('abcdef', 42, '|'), 'abcdef') def test_uneven_split(self): self.assertEqual(chunk_str('abcdef', 5, '|'), 'abcde|f') self.assertEqual(chunk_str('abcdef', 4, '|'), 'abcd|ef') self.assertEqual(chunk_str('abcdefg', 3, ' - '), 'abc - def - g') def test_invalid_n(self): with self.assertRaisesRegex(ValueError, r'n=0'): chunk_str('abcdef', 0, ' ') with self.assertRaisesRegex(ValueError, r'n=-42'): chunk_str('abcdef', -42, ' ') class SafeMD5Tests(TestCase): def test_safe_md5(self): exp = 'ab07acbb1e496801937adfa772424bf7' fd = BytesIO(b'foo bar baz') obs = safe_md5(fd) self.assertEqual(obs.hexdigest(), exp) fd.close() class CardinalToOrdinalTests(TestCase): def test_valid_range(self): # taken and modified from http://stackoverflow.com/a/20007730/3776794 exp = ['0th', '1st', '2nd', '3rd', '4th', '5th', '6th', '7th', '8th', '9th', '10th', '11th', '12th', '13th', '14th', '15th', '16th', '17th', '18th', '19th', '20th', '21st', '22nd', '23rd', '24th', '25th', '26th', '27th', '28th', '29th', '30th', '31st', '32nd', '100th', '101st', '42042nd'] obs = [cardinal_to_ordinal(n) for n in list(range(0, 33)) + [100, 101, 42042]] self.assertEqual(obs, exp) def test_invalid_n(self): with self.assertRaisesRegex(ValueError, r'-1'): cardinal_to_ordinal(-1) class TestFindDuplicates(TestCase): def test_empty_input(self): def empty_gen(): yield from () for empty in [], (), '', set(), {}, empty_gen(): self.assertEqual(find_duplicates(empty), set()) def test_no_duplicates(self): self.assertEqual(find_duplicates(['a', 'bc', 'def', 'A']), set()) def test_one_duplicate(self): self.assertEqual(find_duplicates(['a', 'bc', 'def', 'a']), set(['a'])) def test_many_duplicates(self): self.assertEqual(find_duplicates(['a', 'bc', 'bc', 'def', 'a']), set(['a', 'bc'])) def test_all_duplicates(self): self.assertEqual( find_duplicates(('a', 'bc', 'bc', 'def', 'a', 'def', 'def')), set(['a', 'bc', 'def'])) def test_mixed_types(self): def gen(): yield from ('a', 1, 'bc', 2, 'a', 2, 2, 3.0) self.assertEqual(find_duplicates(gen()), set(['a', 2])) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/test_optionals.py000066400000000000000000000037221520735541300252260ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import importlib from unittest import mock from skbio.util import get_package, _is_usable class TestGetPackage(TestCase): def test_get_numpy(self): """Import NumPy, a mandatory dependency.""" obs = get_package("numpy") self.assertIsNotNone(obs) self.assertIsInstance(obs.ndarray, type) def test_get_numpy_testing(self): """Import NumPy's testing module.""" obs = get_package("numpy.testing") self.assertIsNotNone(obs) self.assertTrue(callable(obs.assert_array_equal)) def test_get_polars_import_error(self): """Import Polars, pretending it doesn't exist.""" msg = ( 'Optional dependency "polars" is not found. ' "Install it to use relevant functionalities." ) with mock.patch.object(importlib, "import_module", side_effect=ImportError): with self.assertRaises(ImportError) as cm: get_package("polars") self.assertEqual(str(cm.exception), msg) class TestIsUsable(TestCase): def test_returns_false_when_mod_is_none(self): assert _is_usable(None, lambda: "anything") is False def test_returns_true_when_probe_succeeds(self): mod = mock.MagicMock() probe = mock.MagicMock(return_value="ok") assert _is_usable(mod, probe) is True probe.assert_called_once() def test_returns_false_when_probe_raises(self): mod = mock.MagicMock() def probe(): raise RuntimeError("boom") assert _is_usable(mod, probe) is False if __name__ == "__main__": main() scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/test_plotting.py000066400000000000000000000043541520735541300250600ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import sys import unittest try: import matplotlib except ImportError: has_matplotlib = False else: has_matplotlib = True from skbio.util._plotting import PlottableMixin @unittest.skipUnless(has_matplotlib, "Matplotlib not available.") class TestPlottableMixin(unittest.TestCase): def setUp(self): def _plot(self): fig, ax = self.plt.subplots() ax.plot(1, 1, color='k', marker='o') return fig PlottableMixin.plot = _plot def test_get_mpl_plt(self): obj = PlottableMixin() # hasn't imported yet self.assertFalse(hasattr(obj, 'mpl')) # import Matplotlib if available obj._get_mpl_plt() self.assertEqual(obj.mpl.__name__, 'matplotlib') self.assertEqual(obj.plt.__name__, 'matplotlib.pyplot') # make Matplotlib unimportable delattr(obj, 'mpl') backup = sys.modules['matplotlib'] sys.modules['matplotlib'] = None with self.assertRaises(ImportError): obj._get_mpl_plt() # won't try again if already failed sys.modules['matplotlib'] = backup self.assertIsNone(obj.mpl) with self.assertRaises(ImportError): obj._get_mpl_plt() def test_figure_data(self): obj = PlottableMixin() obj._get_mpl_plt() # PNG data are bytes obs = obj._figure_data('png') self.assertIsInstance(obs, bytes) self.assertTrue(len(obs) > 0) # SVG data are string obs = obj._figure_data('svg') self.assertIsInstance(obs, str) self.assertTrue(len(obs) > 0) # plotting backend not available delattr(obj, 'mpl') backup = sys.modules['matplotlib'] sys.modules['matplotlib'] = None self.assertIsNone(obj._figure_data()) sys.modules['matplotlib'] = backup if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/test_random.py000066400000000000000000000063311520735541300244750ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from unittest import TestCase, main import numpy as np import numpy.testing as npt from skbio.util._random import get_rng class RandomTests(TestCase): def test_get_rng(self): # returns random generator res = get_rng() self.assertIsInstance(res, np.random.Generator) # seed is Python integer res = get_rng(42) obs = np.array([res.integers(100) for _ in range(5)]) exp = np.array([8, 77, 65, 43, 43]) npt.assert_array_equal(obs, exp) # seed is NumPy integer res = get_rng(np.uint8(42)) obs = np.array([res.integers(100) for _ in range(5)]) npt.assert_array_equal(obs, exp) # seed is new Generator res = get_rng(res) obs = np.array([res.integers(100) for _ in range(5)]) exp = np.array([85, 8, 69, 20, 9]) npt.assert_array_equal(obs, exp) # test if integer seeds are disjoint obs = [get_rng(i).integers(1e6) for i in range(10)] exp = [850624, 473188, 837575, 811504, 726442, 670790, 445045, 944904, 719549, 421547] self.assertListEqual(obs, exp) # no seed: use current random state np.random.seed(42) res = get_rng() obs = np.array([res.integers(100) for _ in range(5)]) exp = np.array([90, 11, 93, 94, 34]) npt.assert_array_equal(obs, exp) # reset random state to reproduce output np.random.seed(42) res = get_rng() obs = np.array([res.integers(100) for _ in range(5)]) npt.assert_array_equal(obs, exp) # call also advances current random state np.random.seed(42) self.assertEqual(np.random.randint(100), 51) res = get_rng() self.assertEqual(np.random.randint(100), 14) # seed is legacy RandomState res = get_rng(np.random.RandomState(42)) obs = np.array([res.integers(100) for _ in range(5)]) npt.assert_array_equal(obs, exp) # test if legacy random states are disjoint obs = [get_rng(np.random.RandomState(i)).integers(1e6) for i in range(5)] exp = [368454, 346004, 189187, 324799, 924851] self.assertListEqual(obs, exp) # invalid seed msg = 'Invalid seed. It must be an integer or a random generator instance.' with self.assertRaises(ValueError) as cm: get_rng('hello') self.assertEqual(str(cm.exception), msg) # mimic legacy NumPy delattr(np.random, 'Generator') msg = ('The installed NumPy version does not support random.Generator. ' 'Please use NumPy >= 1.17.') with self.assertRaises(ValueError) as cm: get_rng() self.assertEqual(str(cm.exception), msg) with self.assertRaises(ValueError) as cm: get_rng('hello') self.assertEqual(str(cm.exception), msg) if __name__ == '__main__': main() scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/test_testing.py000066400000000000000000001066461520735541300247040ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import os import itertools import unittest from unittest.mock import patch from types import SimpleNamespace import pandas as pd import numpy as np import numpy.testing as npt import array_api_compat as aac from skbio import OrdinationResults from skbio.util import (get_data_path, assert_ordination_results_equal, assert_data_frame_almost_equal, get_package, _is_usable) from skbio.util._testing import ( _normalize_signs, assert_series_almost_equal, assert_index_equal, assert_ordination_results_equal_np, _assert_series_equal, _assert_frame_dists_equal, _data_frame_to_default_int_type, ReallyEqualMixin, _read_env, _get_array_backends, _should_run, xp_assert_close, xp_assert_equal, array_backends, ArrayAPITestMixin, _device_specs_match, _on_device ) np_xp = aac.array_namespace(np.empty(0)) class TestGetDataPath(unittest.TestCase): def test_get_data_path(self): fn = 'parrot' path = os.path.dirname(os.path.abspath(__file__)) data_path = os.path.join(path, 'data', fn) data_path_2 = get_data_path(fn) self.assertEqual(data_path_2, data_path) def test_get_data_path_subfolder(self): fn = 'parrot' path = os.path.dirname(os.path.abspath(__file__)) data_path = os.path.join(path, 'custom_subfolder', fn) data_path_2 = get_data_path(fn, subfolder='custom_subfolder') self.assertEqual(data_path_2, data_path) class TestReallyEqualMixin(unittest.TestCase, ReallyEqualMixin): def test_assert_really_equal(self): self.assertReallyEqual(1, 1) self.assertReallyEqual('a', 'a') self.assertReallyEqual([1, 2], [1, 2]) def test_assert_really_not_equal(self): self.assertReallyNotEqual(1, 2) self.assertReallyNotEqual('a', 'b') self.assertReallyNotEqual(1, '1') def test_assert_really_equal_fails_on_unequal(self): with self.assertRaises(AssertionError): self.assertReallyEqual(1, 2) def test_assert_really_not_equal_fails_on_equal(self): with self.assertRaises(AssertionError): self.assertReallyNotEqual(1, 1) class TestAssertOrdinationResultsEqual(unittest.TestCase): def setUp(self): self.minimal1 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) self.minimal2 = OrdinationResults( 'foo', 'bar', pd.Series([1.0000001, 1.9999999]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) def test_equal_to_itself(self): assert_ordination_results_equal(self.minimal1, self.minimal1) def test_type_mismatch(self): with npt.assert_raises(AssertionError): assert_ordination_results_equal(self.minimal1, 'foo') def test_almost_equal_numeric(self): assert_ordination_results_equal(self.minimal1, self.minimal2) def test_optional_numeric_attributes(self): for attr in ('features', 'samples', 'biplot_scores', 'sample_constraints'): m1 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) m2 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) # missing in one, present in other setattr(m2, attr, pd.DataFrame([[1.0, 2.0], [3.0, 4.0]])) with npt.assert_raises(AssertionError): assert_ordination_results_equal(m1, m2) setattr(m2, attr, None) # both present, not almost equal (different pairwise distances) setattr(m1, attr, pd.DataFrame([[1.0, 2.0], [3.0, 4.0]])) setattr(m2, attr, pd.DataFrame([[1.0, 2.0], [3.5, 4.0]])) with npt.assert_raises(AssertionError): assert_ordination_results_equal(m1, m2) setattr(m1, attr, None) setattr(m2, attr, None) # both present, almost equal setattr(m1, attr, pd.DataFrame([[1.0, 2.0], [3.0, 4.0]])) setattr(m2, attr, pd.DataFrame([[1.0, 2.0], [3.00000002, 4.0]])) assert_ordination_results_equal(m1, m2) setattr(m1, attr, None) setattr(m2, attr, None) def test_proportion_explained_mismatch(self): m2 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) m2.proportion_explained = pd.Series([1.0, 2.0, 3.0]) with npt.assert_raises(AssertionError): assert_ordination_results_equal(self.minimal1, m2) def test_proportion_explained_almost_equal(self): m1 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) m2 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) m1.proportion_explained = pd.Series([1.0, 2.0, 3.0]) m2.proportion_explained = pd.Series([1.0, 2.0, 3.00000002]) assert_ordination_results_equal(m1, m2) def test_ignore_method_names(self): m1 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) m2 = OrdinationResults( 'baz', 'qux', pd.Series([1.0, 2.0]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) # Should fail without ignore with npt.assert_raises(AssertionError): assert_ordination_results_equal(m1, m2) # Should pass with ignore assert_ordination_results_equal(m1, m2, ignore_method_names=True) def test_ignore_axis_labels(self): m1 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0], index=['a', 'b']), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], columns=['x', 'y', 'z'])) m2 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0], index=['c', 'd']), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], columns=['p', 'q', 'r'])) assert_ordination_results_equal(m1, m2, ignore_axis_labels=True) def test_ignore_directionality(self): m1 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0]), pd.DataFrame([[1.0, 2.0], [3.0, 4.0]])) m2 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0]), pd.DataFrame([[-1.0, 2.0], [-3.0, 4.0]])) # Pairwise distances should be the same even with sign flip assert_ordination_results_equal(m1, m2, ignore_directionality=True) def test_decimal_parameter(self): m1 = OrdinationResults( 'foo', 'bar', pd.Series([1.0, 2.0]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) m2 = OrdinationResults( 'foo', 'bar', pd.Series([1.001, 2.0]), pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])) # Should fail with high precision with npt.assert_raises(AssertionError): assert_ordination_results_equal(m1, m2, decimal=7) # Should pass with low precision assert_ordination_results_equal(m1, m2, decimal=2) class TestAssertOrdinationResultsEqualNp(unittest.TestCase): """Tests for the NumPy version of ordination results comparison. ``assert_ordination_results_equal_np`` uses ``npt.assert_almost_equal`` directly on ``eigvals`` and ``proportion_explained``, which requires NumPy arrays (not pd.Series) to avoid ambiguous truth-value errors in newer NumPy/Pandas. We therefore convert these attributes to raw arrays after constructing OrdinationResults. """ @staticmethod def _make_ord(short='foo', long='bar', eigvals=None, samples=None, **overrides): """Create an OrdinationResults with NumPy-array eigvals/prop_expl.""" if eigvals is None: eigvals = pd.Series([1.0, 2.0]) if samples is None: samples = pd.DataFrame([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) obj = OrdinationResults(short, long, eigvals, samples) # Convert to numpy arrays so npt.assert_almost_equal works obj.eigvals = obj.eigvals.values obj.samples = obj.samples.values for attr, val in overrides.items(): if isinstance(val, pd.Series): setattr(obj, attr, val.values) elif isinstance(val, pd.DataFrame): setattr(obj, attr, val.values) else: setattr(obj, attr, val) return obj def test_basic_equal(self): m1 = self._make_ord() assert_ordination_results_equal_np(m1, m1) def test_ignore_method_names(self): m1 = self._make_ord('foo', 'bar') m2 = self._make_ord('baz', 'qux') with npt.assert_raises(AssertionError): assert_ordination_results_equal_np(m1, m2) assert_ordination_results_equal_np(m1, m2, ignore_method_names=True) def test_features_none(self): m1 = self._make_ord(features=None) m2 = self._make_ord(features=None) assert_ordination_results_equal_np(m1, m2) def test_features_present(self): feat = np.array([[1.0, 2.0], [3.0, 4.0]]) m1 = self._make_ord(features=feat) m2 = self._make_ord(features=feat.copy()) assert_ordination_results_equal_np(m1, m2) def test_biplot_scores_none(self): m1 = self._make_ord(biplot_scores=None) m2 = self._make_ord(biplot_scores=None) assert_ordination_results_equal_np(m1, m2) def test_biplot_scores_present(self): bp = np.array([[0.1, 0.2], [0.3, 0.4]]) m1 = self._make_ord(biplot_scores=bp) m2 = self._make_ord(biplot_scores=bp.copy()) assert_ordination_results_equal_np(m1, m2) def test_sample_constraints_none(self): m1 = self._make_ord(sample_constraints=None) m2 = self._make_ord(sample_constraints=None) assert_ordination_results_equal_np(m1, m2) def test_sample_constraints_present(self): sc = np.array([[1.0, 2.0], [3.0, 4.0]]) m1 = self._make_ord(sample_constraints=sc) m2 = self._make_ord(sample_constraints=sc.copy()) assert_ordination_results_equal_np(m1, m2) def test_proportion_explained_none(self): m1 = self._make_ord(proportion_explained=None) m2 = self._make_ord(proportion_explained=None) assert_ordination_results_equal_np(m1, m2) def test_proportion_explained_present(self): pe = np.array([0.5, 0.3]) m1 = self._make_ord(proportion_explained=pe) m2 = self._make_ord(proportion_explained=pe.copy()) assert_ordination_results_equal_np(m1, m2) class TestAssertSeriesEqual(unittest.TestCase): """Tests for the private _assert_series_equal helper.""" def test_both_none(self): _assert_series_equal(None, None, ignore_index=False) def test_one_none(self): with self.assertRaises(AssertionError): _assert_series_equal(pd.Series([1.0]), None, ignore_index=False) with self.assertRaises(AssertionError): _assert_series_equal(None, pd.Series([1.0]), ignore_index=False) def test_almost_equal(self): s1 = pd.Series([1.0, 2.0, 3.0]) s2 = pd.Series([1.0, 2.00000001, 3.0]) _assert_series_equal(s1, s2, ignore_index=False) def test_not_almost_equal(self): s1 = pd.Series([1.0, 2.0, 3.0]) s2 = pd.Series([1.0, 2.1, 3.0]) with self.assertRaises(AssertionError): _assert_series_equal(s1, s2, ignore_index=False) def test_ignore_index(self): s1 = pd.Series([1.0, 2.0], index=['a', 'b']) s2 = pd.Series([1.0, 2.0], index=['x', 'y']) _assert_series_equal(s1, s2, ignore_index=True) def test_different_index_fails(self): s1 = pd.Series([1.0, 2.0], index=['a', 'b']) s2 = pd.Series([1.0, 2.0], index=['x', 'y']) with self.assertRaises(AssertionError): _assert_series_equal(s1, s2, ignore_index=False) class TestAssertFrameDistsEqual(unittest.TestCase): """Tests for the private _assert_frame_dists_equal helper.""" def test_both_none(self): _assert_frame_dists_equal(None, None) def test_one_none(self): df = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]]) with self.assertRaises(AssertionError): _assert_frame_dists_equal(df, None) with self.assertRaises(AssertionError): _assert_frame_dists_equal(None, df) def test_equal_dists(self): df = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]]) _assert_frame_dists_equal(df, df) def test_different_dists(self): df1 = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]]) df2 = pd.DataFrame([[1.0, 2.0], [10.0, 4.0]]) with self.assertRaises(AssertionError): _assert_frame_dists_equal(df1, df2) def test_ignore_index(self): df1 = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], index=['a', 'b']) df2 = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], index=['x', 'y']) _assert_frame_dists_equal(df1, df2, ignore_index=True) with self.assertRaises(AssertionError): _assert_frame_dists_equal(df1, df2, ignore_index=False) def test_ignore_columns(self): df1 = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], columns=['a', 'b']) df2 = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], columns=['x', 'y']) _assert_frame_dists_equal(df1, df2, ignore_columns=True) with self.assertRaises(AssertionError): _assert_frame_dists_equal(df1, df2, ignore_columns=False) def test_ignore_directionality(self): df1 = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]]) df2 = pd.DataFrame([[-1.0, 2.0], [-3.0, 4.0]]) # pairwise dists are the same regardless of column sign flips _assert_frame_dists_equal(df1, df2, ignore_directionality=True) class TestNormalizeSigns(unittest.TestCase): def test_shapes_and_nonarray_input(self): with self.assertRaises(ValueError): _normalize_signs([[1, 2], [3, 5]], [[1, 2]]) def test_works_when_different(self): """Taking abs value of everything would lead to false positives.""" a = np.array([[1, -1], [2, 2]]) b = np.array([[-1, -1], [2, 2]]) with self.assertRaises(AssertionError): npt.assert_equal(*_normalize_signs(a, b)) def test_easy_different(self): a = np.array([[1, 2], [3, -1]]) b = np.array([[-1, 2], [-3, -1]]) npt.assert_equal(*_normalize_signs(a, b)) def test_easy_already_equal(self): a = np.array([[1, -2], [3, 1]]) b = a.copy() npt.assert_equal(*_normalize_signs(a, b)) def test_zeros(self): a = np.array([[0, 3], [0, -1]]) b = np.array([[0, -3], [0, 1]]) npt.assert_equal(*_normalize_signs(a, b)) def test_hard(self): a = np.array([[0, 1], [1, 2]]) b = np.array([[0, 1], [-1, 2]]) npt.assert_equal(*_normalize_signs(a, b)) def test_harder(self): """We don't want a value that might be negative due to floating point inaccuracies to make a call to allclose in the result to be off.""" a = np.array([[-1e-15, 1], [5, 2]]) b = np.array([[1e-15, 1], [5, 2]]) npt.assert_almost_equal(*_normalize_signs(a, b)) def test_column_zeros(self): a = np.array([[0, 1], [0, 2]]) b = np.array([[0, -1], [0, -2]]) npt.assert_equal(*_normalize_signs(a, b)) def test_column_almost_zero(self): a = np.array([[1e-15, 3], [-2e-14, -6]]) b = np.array([[0, 3], [-1e-15, -6]]) npt.assert_almost_equal(*_normalize_signs(a, b)) class TestAssertDataFrameAlmostEqual(unittest.TestCase): def setUp(self): self.df = pd.DataFrame({'bar': ['a', 'b', 'cd', 'e'], 'foo': [42, 42.0, np.nan, 0]}) def test_not_equal(self): unequal_dfs = [ self.df, # floating point error too large to be "almost equal" pd.DataFrame({'bar': ['a', 'b', 'cd', 'e'], 'foo': [42, 42.001, np.nan, 0]}), # extra NaN pd.DataFrame({'bar': ['a', 'b', 'cd', 'e'], 'foo': [42, np.nan, np.nan, 0]}), # different column order pd.DataFrame(self.df, columns=['foo', 'bar']), # different index order pd.DataFrame(self.df, index=np.arange(4)[::-1]), # different index type pd.DataFrame(self.df, index=np.arange(4).astype(float)), # various forms of "empty" DataFrames that are not equivalent pd.DataFrame(), pd.DataFrame(index=np.arange(10)), pd.DataFrame(columns=np.arange(10)), pd.DataFrame(index=np.arange(10), columns=np.arange(10)), pd.DataFrame(index=np.arange(9)), pd.DataFrame(columns=np.arange(9)), pd.DataFrame(index=np.arange(9), columns=np.arange(9)) ] # each df should compare equal to itself and a copy of itself for df in unequal_dfs: assert_data_frame_almost_equal(df, df) assert_data_frame_almost_equal(df, pd.DataFrame(df).copy()) # every pair of dfs should not compare equal for df1, df2 in itertools.permutations(unequal_dfs, 2): with self.assertRaises(AssertionError): assert_data_frame_almost_equal(df1, df2) def test_equal(self): equal_dfs = [ self.df, # floating point error small enough to be "almost equal" pd.DataFrame({'bar': ['a', 'b', 'cd', 'e'], 'foo': [42, 42.00001, np.nan, 0]}) ] for df in equal_dfs: assert_data_frame_almost_equal(df, df) for df1, df2 in itertools.permutations(equal_dfs, 2): assert_data_frame_almost_equal(df1, df2) def test_rtol_parameter(self): df1 = pd.DataFrame({'a': [1.0, 2.0]}) df2 = pd.DataFrame({'a': [1.01, 2.0]}) with self.assertRaises(AssertionError): assert_data_frame_almost_equal(df1, df2, rtol=1e-5) assert_data_frame_almost_equal(df1, df2, rtol=0.1) class TestDataFrameToDefaultIntType(unittest.TestCase): def test_converts_int_columns(self): df = pd.DataFrame({'a': np.array([1, 2, 3], dtype=np.int64), 'b': [1.0, 2.0, 3.0], 'c': ['x', 'y', 'z']}) expected_c = df['c'].copy() _data_frame_to_default_int_type(df) # After conversion, int columns should have platform default int type self.assertEqual(df['a'].dtype, np.dtype(int)) # Non-int columns should be unchanged self.assertEqual(df['b'].dtype, np.float64) pd.testing.assert_series_equal(df['c'], expected_c) def test_no_int_columns(self): df = pd.DataFrame({'a': [1.0, 2.0], 'b': ['x', 'y']}) _data_frame_to_default_int_type(df) self.assertEqual(df['a'].dtype, np.float64) class TestAssertSeriesAlmostEqual(unittest.TestCase): def setUp(self): self.series = [ pd.Series(dtype='float64'), pd.Series(dtype=object), pd.Series(dtype='int64'), pd.Series([1, 2, 3]), pd.Series([3, 2, 1]), pd.Series([1, 2, 3, 4]), pd.Series([1., 2., 3.]), pd.Series([1, 2, 3], [1.0, 2.0, 3.0]), pd.Series([1, 2, 3], [1, 2, 3]), pd.Series([1, 2, 3], ['c', 'b', 'a']), pd.Series([3, 2, 1], ['c', 'b', 'a']), ] def test_not_equal(self): # no pair of series should compare equal for s1, s2 in itertools.permutations(self.series, 2): with self.assertRaises(AssertionError): assert_series_almost_equal(s1, s2) def test_equal(self): s1 = pd.Series([1., 2., 3.]) s2 = pd.Series([1.000001, 2., 3.]) assert_series_almost_equal(s1, s2) # all series should be equal to themselves and copies of themselves for s in self.series: assert_series_almost_equal(s, s) assert_series_almost_equal(s, pd.Series(s).copy()) class TestAssertIndexEqual(unittest.TestCase): def test_equal_indices(self): idx1 = pd.Index([1, 2, 3]) idx2 = pd.Index([1, 2, 3]) assert_index_equal(idx1, idx2) def test_different_values(self): idx1 = pd.Index([1, 2, 3]) idx2 = pd.Index([1, 2, 4]) with self.assertRaises(AssertionError): assert_index_equal(idx1, idx2) def test_different_types(self): idx1 = pd.Index([1, 2, 3]) idx2 = pd.Index([1.0, 2.0, 3.0]) with self.assertRaises(AssertionError): assert_index_equal(idx1, idx2) def test_different_names(self): idx1 = pd.Index([1, 2, 3], name='a') idx2 = pd.Index([1, 2, 3], name='b') with self.assertRaises(AssertionError): assert_index_equal(idx1, idx2) class TestReadEnv(unittest.TestCase): def test_default_empty(self): with patch.dict(os.environ, {}, clear=True): os.environ.pop('SKBIO_ARRAY_BACKEND', None) os.environ.pop('SKBIO_DEVICE', None) backend, device = _read_env() self.assertEqual(backend, '') self.assertIsNone(device) def test_custom_values(self): with patch.dict(os.environ, {'SKBIO_ARRAY_BACKEND': ' jax ', 'SKBIO_DEVICE': ' cuda '}): backend, device = _read_env() self.assertEqual(backend, 'jax') self.assertEqual(device, 'cuda') def test_backend_only(self): with patch.dict(os.environ, {'SKBIO_ARRAY_BACKEND': 'torch'}, clear=False): os.environ.pop('SKBIO_DEVICE', None) backend, device = _read_env() self.assertEqual(backend, 'torch') self.assertIsNone(device) class TestGetAvailableBackends(unittest.TestCase): def test_numpy_always_present(self): backends_dict = _get_array_backends() self.assertIn('numpy', backends_dict) xp, devices = backends_dict['numpy'] self.assertIs(xp, np) self.assertIn('cpu', devices) class TestShouldRun(unittest.TestCase): def test_default_numpy_cpu(self): """With no env vars, only numpy/cpu should run.""" with patch('skbio.util._testing._read_env', return_value=('', None)): self.assertTrue(_should_run('numpy', 'cpu')) self.assertFalse(_should_run('jax', 'cpu')) self.assertFalse(_should_run('numpy', 'gpu')) def test_all_backends(self): with patch('skbio.util._testing._read_env', return_value=('all', None)): self.assertTrue(_should_run('numpy', 'cpu')) self.assertTrue(_should_run('jax', 'cpu')) self.assertTrue(_should_run('torch', 'cuda')) def test_all_with_device_filter(self): with patch('skbio.util._testing._read_env', return_value=('all', 'cpu')): self.assertTrue(_should_run('numpy', 'cpu')) self.assertFalse(_should_run('torch', 'cuda')) def test_specific_backend(self): with patch('skbio.util._testing._read_env', return_value=('torch', None)): self.assertFalse(_should_run('numpy', 'cpu')) self.assertTrue(_should_run('torch', 'cpu')) self.assertTrue(_should_run('torch', 'cuda')) def test_specific_backend_and_device(self): with patch('skbio.util._testing._read_env', return_value=('torch', 'cuda')): self.assertFalse(_should_run('torch', 'cpu')) self.assertTrue(_should_run('torch', 'cuda')) class TestXpAssertClose(unittest.TestCase): def test_close_arrays(self): a = np.array([1.0, 2.0, 3.0]) b = np.array([1.0, 2.0000001, 3.0]) xp_assert_close(a, b) def test_not_close_arrays(self): a = np.array([1.0, 2.0, 3.0]) b = np.array([1.0, 3.0, 3.0]) with self.assertRaises(AssertionError): xp_assert_close(a, b) def test_custom_tolerances(self): a = np.array([1.0]) b = np.array([1.1]) with self.assertRaises(AssertionError): xp_assert_close(a, b, rtol=1e-7, atol=0) xp_assert_close(a, b, rtol=0.2, atol=0) class TestXpAssertEqual(unittest.TestCase): def test_equal_arrays(self): a = np.array([1, 2, 3]) b = np.array([1, 2, 3]) xp_assert_equal(a, b) def test_not_equal_arrays(self): a = np.array([1, 2, 3]) b = np.array([1, 2, 4]) with self.assertRaises(AssertionError): xp_assert_equal(a, b) class TestBackendsDecorator(unittest.TestCase): def test_runs_numpy_by_default(self): """With default env, the decorator should run the test on numpy/cpu.""" ran = [] class FakeTest(unittest.TestCase): @array_backends('numpy') def test_it(self, xp, device): ran.append((xp, device)) with patch('skbio.util._testing._read_env', return_value=('', None)): t = FakeTest() t.test_it() self.assertEqual(len(ran), 1) self.assertIs(ran[0][0], np) self.assertEqual(ran[0][1], 'cpu') def test_missing_backend_raises(self): """Requesting a non-installed backend should raise RuntimeError.""" class FakeTest(unittest.TestCase): @array_backends('numpy') def test_it(self, xp, device): pass with patch('skbio.util._testing._read_env', return_value=('nonexistent', None)): with patch('skbio.util._testing._BACKENDS', {'numpy': (np, ['cpu'])}): t = FakeTest() with self.assertRaises(RuntimeError): t.test_it() def test_no_matching_backends_skips(self): """If no backends match, should raise SkipTest.""" class FakeTest(unittest.TestCase): @array_backends('jax') # jax likely not installed in test env def test_it(self, xp, device): pass with patch('skbio.util._testing._read_env', return_value=('', None)): with patch('skbio.util._testing._BACKENDS', {'numpy': (np, ['cpu'])}): t = FakeTest() with self.assertRaises(unittest.SkipTest): t.test_it() def test_cpu_only(self): """cpu_only=True should skip non-cpu devices.""" ran = [] class FakeTest(unittest.TestCase): @array_backends('numpy', cpu_only=True) def test_it(self, xp, device): ran.append(device) with patch('skbio.util._testing._read_env', return_value=('all', None)): with patch('skbio.util._testing._BACKENDS', {'numpy': (np, ['cpu', 'cuda'])}): t = FakeTest() t.test_it() self.assertEqual(ran, ['cpu']) def test_default_all_backends(self): """No backend_names argument should default to all four.""" ran = [] class FakeTest(unittest.TestCase): @array_backends() def test_it(self, xp, device): ran.append('ok') with patch('skbio.util._testing._read_env', return_value=('all', None)): with patch('skbio.util._testing._BACKENDS', {'numpy': (np, ['cpu'])}): with patch('skbio.util._testing._should_run', return_value=True): t = FakeTest() t.test_it() self.assertTrue(len(ran) >= 1) def test_no_matching_device_raises(self): """If SKBIO_DEVICE is set but no backend has it, RuntimeError.""" class FakeTest(unittest.TestCase): @array_backends('numpy') def test_it(self, xp, device): pass with patch('skbio.util._testing._read_env', return_value=('all', 'nonexistent')): with patch('skbio.util._testing._BACKENDS', {'numpy': (np, ['cpu'])}): t = FakeTest() with self.assertRaises(RuntimeError): t.test_it() class TestArrayAPITestMixin(unittest.TestCase, ArrayAPITestMixin): def test_make_array(self): arr = self.make_array(np, 'cpu', [[1.0, 2.0], [3.0, 4.0]]) npt.assert_array_equal(arr, np.array([[1.0, 2.0], [3.0, 4.0]])) def test_make_array_with_dtype(self): arr = self.make_array(np, 'cpu', [1, 2, 3], dtype=np.float32) self.assertEqual(arr.dtype, np.float32) def test_assert_close(self): a = np.array([1.0, 2.0]) b = np.array([1.0, 2.0000001]) self.assert_close(a, b) def test_assert_close_fails(self): a = np.array([1.0, 2.0]) b = np.array([1.0, 3.0]) with self.assertRaises(AssertionError): self.assert_close(a, b) def test_device_specs_match(self): # Same string matches itself. self.assertTrue(_device_specs_match('cuda', 'cuda')) self.assertTrue(_device_specs_match('cpu', 'cpu')) # GPU aliases match each other. self.assertTrue(_device_specs_match('gpu', 'cuda')) self.assertTrue(_device_specs_match('cuda', 'gpu')) # Case-insensitive. self.assertTrue(_device_specs_match('CUDA', 'cuda')) self.assertTrue(_device_specs_match('GPU', 'CUDA')) # Different hardware doesn't match. self.assertFalse(_device_specs_match('cpu', 'cuda')) self.assertFalse(_device_specs_match('cpu', 'gpu')) # None handling: matches only None. self.assertTrue(_device_specs_match(None, None)) self.assertFalse(_device_specs_match(None, 'cpu')) self.assertFalse(_device_specs_match('cuda', None)) class TestOnDevice(unittest.TestCase): """Tests for ``_on_device``. Uses mocking so it runs without optional backends installed.""" # ---- NumPy: no mocking needed, numpy is always available ---- def test_numpy_cpu_matches(self): arr = np.arange(5) self.assertTrue(_on_device(arr, np_xp, "cpu")) def test_numpy_none_matches(self): arr = np.arange(5) self.assertTrue(_on_device(arr, np_xp, None)) def test_numpy_cuda_does_not_match(self): arr = np.arange(5) self.assertFalse(_on_device(arr, np_xp, "cuda")) def test_numpy_gpu_does_not_match(self): arr = np.arange(5) self.assertFalse(_on_device(arr, np_xp, "gpu")) # ---- CuPy: always GPU. Mock the backend name. ---- def test_cupy_cuda_matches(self): fake_xp = object() fake_arr = object() with patch("skbio.util._testing._get_backend_name", return_value="cupy"): self.assertTrue(_on_device(fake_arr, fake_xp, "cuda")) def test_cupy_gpu_matches(self): fake_xp = object() fake_arr = object() with patch("skbio.util._testing._get_backend_name", return_value="cupy"): self.assertTrue(_on_device(fake_arr, fake_xp, "gpu")) def test_cupy_cpu_does_not_match(self): fake_xp = object() fake_arr = object() with patch("skbio.util._testing._get_backend_name", return_value="cupy"): self.assertFalse(_on_device(fake_arr, fake_xp, "cpu")) def test_cupy_none_does_not_match(self): fake_xp = object() fake_arr = object() with patch("skbio.util._testing._get_backend_name", return_value="cupy"): self.assertFalse(_on_device(fake_arr, fake_xp, None)) # ---- PyTorch: inspects arr.device.type ---- def test_torch_cpu_matches(self): fake_arr = SimpleNamespace(device=SimpleNamespace(type="cpu")) with patch("skbio.util._testing._get_backend_name", return_value="torch"): self.assertTrue(_on_device(fake_arr, object(), "cpu")) def test_torch_cpu_none_matches(self): fake_arr = SimpleNamespace(device=SimpleNamespace(type="cpu")) with patch("skbio.util._testing._get_backend_name", return_value="torch"): self.assertTrue(_on_device(fake_arr, object(), None)) def test_torch_cpu_does_not_match_cuda(self): fake_arr = SimpleNamespace(device=SimpleNamespace(type="cpu")) with patch("skbio.util._testing._get_backend_name", return_value="torch"): self.assertFalse(_on_device(fake_arr, object(), "cuda")) def test_torch_cuda_matches(self): fake_arr = SimpleNamespace(device=SimpleNamespace(type="cuda")) with patch("skbio.util._testing._get_backend_name", return_value="torch"): self.assertTrue(_on_device(fake_arr, object(), "cuda")) def test_torch_cuda_matches_gpu_alias(self): fake_arr = SimpleNamespace(device=SimpleNamespace(type="cuda")) with patch("skbio.util._testing._get_backend_name", return_value="torch"): self.assertTrue(_on_device(fake_arr, object(), "gpu")) def test_torch_cuda_does_not_match_cpu(self): fake_arr = SimpleNamespace(device=SimpleNamespace(type="cuda")) with patch("skbio.util._testing._get_backend_name", return_value="torch"): self.assertFalse(_on_device(fake_arr, object(), "cpu")) # ---- JAX: inspects arr.device.platform ---- def test_jax_cpu_matches(self): fake_arr = SimpleNamespace(device=SimpleNamespace(platform="cpu")) with patch("skbio.util._testing._get_backend_name", return_value="jax"): self.assertTrue(_on_device(fake_arr, object(), "cpu")) def test_jax_none_matches_cpu(self): fake_arr = SimpleNamespace(device=SimpleNamespace(platform="cpu")) with patch("skbio.util._testing._get_backend_name", return_value="jax"): self.assertTrue(_on_device(fake_arr, object(), None)) def test_jax_gpu_matches(self): fake_arr = SimpleNamespace(device=SimpleNamespace(platform="gpu")) with patch("skbio.util._testing._get_backend_name", return_value="jax"): self.assertTrue(_on_device(fake_arr, object(), "gpu")) def test_jax_gpu_matches_cuda_alias(self): fake_arr = SimpleNamespace(device=SimpleNamespace(platform="gpu")) with patch("skbio.util._testing._get_backend_name", return_value="jax"): self.assertTrue(_on_device(fake_arr, object(), "cuda")) def test_jax_cpu_does_not_match_gpu(self): fake_arr = SimpleNamespace(device=SimpleNamespace(platform="cpu")) with patch("skbio.util._testing._get_backend_name", return_value="jax"): self.assertFalse(_on_device(fake_arr, object(), "gpu")) # ---- Unknown backend raises ---- def test_unknown_backend_raises(self): with patch("skbio.util._testing._get_backend_name", return_value="weird_lib"): with self.assertRaises(NotImplementedError): _on_device(object(), object(), "cpu") if __name__ == '__main__': unittest.main()scikit-bio-scikit-bio-a3beaa6/skbio/util/tests/test_warning.py000066400000000000000000000073751520735541300246730ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import unittest from skbio.util._warning import _warn_once, _warn_deprecated, _warn_param_deprecated class TestWarning(unittest.TestCase): def test_warn_once(self): def foo(param): pass # function warning self.assertFalse(hasattr(foo, "_warned")) wtype = FutureWarning msg = "`foo` will become `bar` in 2.0." with self.assertWarns(wtype) as ctx: _warn_once(foo, wtype, msg) self.assertEqual(str(ctx.warning), msg) self.assertTrue(hasattr(foo, "_warned")) with self.assertRaises(AssertionError): self.assertWarns(wtype, _warn_once, foo, wtype, msg) # parameter warning self.assertFalse(hasattr(foo, "_warned_params")) wtype = DeprecationWarning msg = "`param` is deprecated as of 3.0." with self.assertWarns(wtype) as ctx: _warn_once(foo, wtype, msg, "param") self.assertEqual(str(ctx.warning), msg) self.assertIn("param", foo._warned_params) with self.assertRaises(AssertionError): self.assertWarns(wtype, _warn_once, foo, wtype, msg, "param") def test_warn_deprecated(self): def foo(): pass self.assertFalse(hasattr(foo, "_warned")) with self.assertWarns(DeprecationWarning) as ctx: _warn_deprecated(foo) exp = "`foo` is deprecated." self.assertEqual(str(ctx.warning), exp) self.assertTrue(hasattr(foo, "_warned")) with self.assertRaises(AssertionError): self.assertWarns(DeprecationWarning, _warn_deprecated, foo) def foo(): pass with self.assertWarns(DeprecationWarning) as ctx: _warn_deprecated(foo, ver="1.0") exp = "`foo` has been deprecated since 1.0." self.assertEqual(str(ctx.warning), exp) def foo(): pass with self.assertWarns(DeprecationWarning) as ctx: _warn_deprecated(foo, ver="1.0", msg="Use `bar` instead.") exp = "`foo` has been deprecated since 1.0. Use `bar` instead." self.assertEqual(str(ctx.warning), exp) def foo(): pass msg="Use `bar` instead of `foo`." with self.assertWarns(DeprecationWarning) as ctx: _warn_deprecated(foo, ver="1.0", msg=msg, append=False) self.assertEqual(str(ctx.warning), msg) def test_warn_param_deprecated(self): def foo(param1, param2): pass self.assertFalse(hasattr(foo, "_warned_params")) # parameter 1 with self.assertWarns(DeprecationWarning) as ctx: _warn_param_deprecated(foo, "param1") exp = "`foo`'s parameter `param1` is deprecated." self.assertEqual(str(ctx.warning), exp) self.assertIn("param1", foo._warned_params) with self.assertRaises(AssertionError): self.assertWarns(DeprecationWarning, _warn_param_deprecated, foo, "param1") # parameter 2 with self.assertWarns(DeprecationWarning) as ctx: _warn_param_deprecated(foo, "param2", ver="1.0") exp = "`foo`'s parameter `param2` has been deprecated since 1.0." self.assertEqual(str(ctx.warning), exp) self.assertIn("param2", foo._warned_params) with self.assertRaises(AssertionError): self.assertWarns(DeprecationWarning, _warn_param_deprecated, foo, "param2") if __name__ == '__main__': unittest.main() scikit-bio-scikit-bio-a3beaa6/skbio/workflow.py000066400000000000000000000451041520735541300217120ustar00rootroot00000000000000r"""Workflow Construction (:mod:`skbio.workflow`) ============================================= .. currentmodule:: skbio.workflow Construct arbitrarily complex workflows in which the specific methods run are determined at runtime. This module supports short circuiting a workflow if an item fails, supports ordering methods, callbacks for processed items, and deciding what methods are executed based on state or runtime options. Classes ------- .. autosummary:: :toctree: generated/ Workflow Decorators ---------- .. autosummary:: :toctree: generated/ requires method Tutorial -------- >>> from skbio.workflow import Workflow As an example of the :class:`Workflow` object, let's construct a sequence processor that will filter sequences that are < 10 nucleotides, reverse the sequence if the runtime options indicate to, and truncate if a specific nucleotide pattern is observed. The :class:`Workflow` object will only short circuit, and evaluate requirements on methods decorated by ``method``. Developers are free to define as many methods as they'd like within the object definition, and which can be called from workflow methods, but they will not be subjected directly to workflow checks. >>> nuc_pattern = 'AATTG' >>> has_nuc_pattern = lambda s: s[:len(nuc_pattern)] == nuc_pattern >>> class SequenceProcessor(Workflow): ... def initialize_state(self, item): ... # Setup the state for a new item (e.g., a new sequence) ... self.state = item ... @method(priority=100) ... def check_length(self): ... # Always make sure the sequence is at least 10 nucleotides ... if len(self.state) < 10: ... self.failed = True ... @method(priority=90) ... @requires(state=has_nuc_pattern) ... def truncate(self): ... # Truncate if a specific starting nucleotide pattern is observed ... self.state = self.state[len(nuc_pattern):] ... @method(priority=80) ... @requires(option='reverse', values=True) ... def reverse(self): ... # Reverse the sequence if indicatd at runtime ... self.state = self.state[::-1] An instance of a ``Workflow`` must be passed a ``state`` object and any runtime options. There are a few other useful parameters that can be specified but are out of scope for the purposes of this example. We also do not need to provide a state object as our ``initialize_state`` method overrides ``self.state``. Now, let's create the instance. >>> wf = SequenceProcessor(state=None, options={'reverse=': False}) To run items through the ``SequenceProcessor``, we need to pass in an iterable. So, lets create a ``list`` of sequences. >>> seqs = ['AAAAAAATTTTTTT', 'ATAGACC', 'AATTGCCGGAC', 'ATATGAACAAA'] Before we run these sequences through, we're going to also define callbacks that are applied to the result of an single pass through the ``Workflow``. Callbacks are optional -- by default, a success will simply yield the state member variable while failures are ignored -- but, depending on your workflow, it can be useful to handle failures or potentially do something fun and exciting on success. >>> def success_f(obj): ... return "SUCCESS: %s" % obj.state >>> def fail_f(obj): ... return "FAIL: %s" % obj.state Now, lets process some data! >>> for result in wf(seqs, success_callback=success_f, fail_callback=fail_f): ... print(result) SUCCESS: AAAAAAATTTTTTT FAIL: ATAGACC SUCCESS: CCGGAC SUCCESS: ATATGAACAAA A few things of note just happened. First off, none of the sequences were reversed as the ``SequenceProcessor`` did not have option "reverse" set to ``True``. Second, you'll notice that the 3rd sequence was truncated, which is expected as it matched our nucleotide pattern of interest. Finally, of the sequences we processed, only a single sequence failed. To assist in constructing workflows, debug information is available but it must be turned on at instantiation. Let's do that, and while we're at it, let's go ahead and enable the reversal method. This time through though, were going to walk through an item at a time so we can examine the debug information. >>> wf = SequenceProcessor(state=None, options={'reverse':True}, debug=True) >>> gen = wf(seqs, fail_callback=lambda x: x.state) >>> next(gen) 'TTTTTTTAAAAAAA' >>> wf.failed False >>> sorted(wf.debug_trace) [('check_length', 0), ('reverse', 2)] The ``debug_trace`` specifies the methods executed, and the order of their execution where closer to zero indicates earlier in the execution order. Gaps indicate there was a method evaluated but not executed. Each of the items in the ``debug_trace`` is a key into a few other ``dict`` of debug information which we'll discuss in a moment. Did you see that the sequence was reversed this time through the workflow? Now, let's take a look at the next item, which on our prior run through the workflow was a failed item. >>> next(gen) 'ATAGACC' >>> wf.failed True >>> sorted(wf.debug_trace) [('check_length', 0)] What we can see is that the failed sequence only executed the check_length method. Since the sequence didn't pass our length filter of 10 nucleotides, it was marked as failed within the ``check_length`` method. As a result, none of the other methods were evaluated (note: this short circuiting behavior can be disabled if desired). This third item previously matched our nucleotide pattern of interest for truncation. Let's see what that looks like in the debug output. >>> next(gen) 'CAGGCC' >>> wf.failed False >>> sorted(wf.debug_trace) [('check_length', 0), ('reverse', 2), ('truncate', 1)] In this last example, we can see that the ``truncate`` method was executed prior to the ``reverse`` method and following the ``check_length`` method. This is as anticipated given the priorities we specified for these methods. Since the ``truncate`` method is doing something interesting, let's take a closer look at how the ``state`` is changing. First, we're going to dump out the state of the workflow prior to the call to ``truncate`` and then we're going to dump out the ``state`` following the call to ``truncate``, which will allow us to rapidly what is going on. >>> wf.debug_pre_state[('truncate', 1)] 'AATTGCCGGAC' >>> wf.debug_post_state[('truncate', 1)] 'CCGGAC' As we expect, we have our original sequence going into ``truncate``, and following the application of ``truncate``, our sequence is missing our nucleotide pattern of interest. Awesome, right? There is one final piece of debug output, ``wf.debug_runtime``, which can be useful when diagnosing the amount of time required for individual methods on a particular piece of state (as opposed to the aggregate as provided by cProfile). Three final components of the workflow that are quite handy are objects that allow you to indicate ``anything`` as an option value, anything that is ``not_none``, and a mechanism to define a range of valid values. >>> from skbio.workflow import not_none, anything >>> class Ex(Workflow): ... @method() ... @requires(option='foo', values=not_none) ... def do_something(self): ... pass ... @method() ... @requires(option='bar', values=anything) ... def do_something_else(self): ... pass ... @method() ... @requires(option='foobar', values=[1,2,3]) ... def do_something_awesome(self): ... pass ... """ # noqa: D205, D415 # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import sys from copy import deepcopy from time import time from functools import update_wrapper from collections.abc import Iterable from types import MethodType class NotExecuted: """Helper object to track if a method was executed.""" def __init__(self): """Construct all the necessary attributes for the NotExecuted object.""" self.msg = None def __call__(self, msg): """Update message and return self.""" self.msg = msg return self _not_executed = NotExecuted() class Exists: """Stub object to assist with ``requires`` when a value exists.""" def __contains__(self, item): """Check if a value exists.""" return True anything = Exists() # external, for when a value can be anything class NotNone: """Check for non-None values.""" def __contains__(self, item): """Check if item is not None.""" if item is None: return False else: return True not_none = NotNone() class Workflow: """Arbitrary workflow support structure. Methods that are considered to be directly part of the workflow must be decorated with ``method``. The workflow methods offer a mechanism to logically group functionality together, and are free to make subsequent calls to other methods. All methods of a subclass of Workflow (those with and without the ``method`` decoration) can take advantage of the ``requires`` decorator to specify any option or state requirements for the decorated function. Parameters ---------- state : object State can be anything or nothing. This is dependent on the workflow as in some cases, it is useful to preallocate state while in other workflows state may be ignored. short_circuit : bool if True, enables ignoring function methods when a given item has failed debug : bool Enable debug mode options : dict runtime options, {'option':values}, that the ``requires`` decorator can interrogate. kwargs : dict Additional arguments will be added as member variables to self. This is handy if additional contextual information is needed by a workflow method (e.g., a lookup table). """ def __init__(self, state, short_circuit=True, debug=False, options=None, **kwargs): r"""Build thy workflow of self.""" if options is None: self.options = {} else: self.options = options self.short_circuit = short_circuit self.failed = False self.debug = debug self.state = state self.iter_ = None for k, v in kwargs.items(): if hasattr(self, k): raise AttributeError("'%s' already exists in self." % k) setattr(self, k, v) if self.debug: self._setup_debug() def initialize_state(self, item): """Initialize state. This method is called first prior to any other defined workflow method with the exception of _setup_debug_trace if self.debug is True Parameters ---------- item : anything Workflow dependent """ raise NotImplementedError("Must implement this method") def _setup_debug(self): """Wrap all methods with debug trace support.""" # ignore all members of the baseclass ignore = set(dir(Workflow)) for attrname in dir(self): if attrname in ignore: continue attr = getattr(self, attrname) if isinstance(attr, MethodType): setattr(self, attrname, self._debug_trace_wrapper(attr)) def _all_wf_methods(self): """Get all workflow methods. Methods are sorted by priority """ methods = [] for item in dir(self): obj = getattr(self, item) if hasattr(obj, "priority"): methods.append(obj) def key(x): return getattr(x, "priority") methods_sorted = sorted(methods, key=key, reverse=True) if self.debug: methods_sorted.insert(0, self._setup_debug_trace) return methods_sorted def _setup_debug_trace(self): """Set up a trace. The trace is per item iterated over by the workflow. Information about each method executed is tracked and keyed by:: (function name, order of execution) Order of execution starts from zero. Multiple calls to the same function are independent in the trace. The following information is tracked:: debug_trace : set([key]) debug_runtime : {key: runtime} debug_pre_state : {key: deepcopy(Workflow.state)}, state prior to method execution debug_post_state : {key: deepcopy(Workflow.state)}, state following method execution """ self.debug_counter = 0 self.debug_trace = set() self.debug_runtime = {} self.debug_pre_state = {} self.debug_post_state = {} def __call__(self, iter_, success_callback=None, fail_callback=None): """Operate on all the data. This is the processing engine of the workflow. Callbacks are executed following applying all workflow methods to an item from ``iter_`` (unless ``short_cicruit=True`` in which case method execution for an item is stopped if ``failed=True``). Callbacks are provided ``self`` which allows them to examine any aspect of the workflow. Parameters ---------- iter_ : iterator The iterator containing the data to be processed. success_callback : method, optional Method to call on a successful item prior to yielding. By default, ``self.state`` is yielded. fail_callback : method, optional Method to call on a failed item prior to yielding. By default, failures are ignored. """ if success_callback is None: def success_callback(x): return x.state self.iter_ = iter_ workflow = self._all_wf_methods() for item in self.iter_: self.failed = False self.initialize_state(item) for func in workflow: if self.short_circuit and self.failed: break else: func() if self.failed: if fail_callback is not None: yield fail_callback(self) else: yield success_callback(self) self.iter_ = None def _debug_trace_wrapper(self, func): """Trace a function call.""" def wrapped(): """Track debug information about a method execution.""" if not hasattr(self, "debug_trace"): raise AttributeError("%s doesn't have debug_trace." % self.__class__) exec_order = self.debug_counter name = func.__name__ key = (name, exec_order) pre_state = deepcopy(self.state) self.debug_trace.add(key) self.debug_counter += 1 start_time = time() if func() is _not_executed: self.debug_trace.remove(key) else: self.debug_runtime[key] = time() - start_time self.debug_pre_state[key] = pre_state self.debug_post_state[key] = deepcopy(self.state) return update_wrapper(wrapped, func) class method: """Decorate a function to indicate it is a workflow method. Parameters ---------- priority : int Specify a priority for the method, the higher the value the higher the priority. Priorities are relative to a given workflow """ highest_priority = sys.maxsize def __init__(self, priority=0): """Construct all the necessary attributes for the method object.""" self.priority = priority def __call__(self, func): """Decorate function with specified priority.""" func.priority = self.priority return func class requires: """Decorator that executes a function if requirements are met. Parameters ---------- option : any Hashable object An option that is required for the decorated method to execute. This option will be looked up within the containing ``Workflow``s' ``options``. values : object A required value. This defaults to ``anything`` indicating that the only requirement is that the ``option`` exists. It can be useful to specify ``not_none`` which indicates that the requirement is satisfied if the ``option`` exists and it holds a value that is not ``None``. Values also supports iterables or singular values. state : Function A requirement on workflow state. This must be a function that accepts a single argument, and returns ``True`` to indicate the requirement is satisfied, or ``False`` to indicate the requirement is not satisfied. This method will be passed the containing ``Workflow``s' ``state`` member variable. """ def __init__(self, option=None, values=anything, state=None): """Construct all the necessary attributes for the requires object.""" # self here is the requires object self.option = option self.required_state = state if values is anything: self.values = anything elif values is not_none: self.values = not_none elif isinstance(values, set): self.values = values else: if isinstance(values, str): self.values = values elif isinstance(values, Iterable): self.values = set(values) else: self.values = set([values]) def __call__(self, func): """Wrap a function. func : the function to wrap """ def decorated(dec_self): """Execute a decorated function that has requirements. dec_self : this is "self" for the decorated function """ if self.required_state is not None: if not self.required_state(dec_self.state): return _not_executed s_opt = self.option ds_opts = dec_self.options # if this is a function that doesn't have an option to validate if s_opt is None: func(dec_self) # if the option exists in the Workflow elif s_opt in ds_opts: val = ds_opts[s_opt] # if the value just needs to be not None if self.values is not_none and val is not None: func(dec_self) # otherwise make sure the value is acceptable elif val in self.values: func(dec_self) else: return _not_executed else: return _not_executed return update_wrapper(decorated, func) scikit-bio-scikit-bio-a3beaa6/web/000077500000000000000000000000001520735541300171305ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/web/.exclude000066400000000000000000000000671520735541300205650ustar00rootroot00000000000000.git .nojekyll docs robots.txt CNAME LICENSE README.md scikit-bio-scikit-bio-a3beaa6/web/Makefile000066400000000000000000000011721520735541300205710ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) scikit-bio-scikit-bio-a3beaa6/web/README.md000066400000000000000000000004561520735541300204140ustar00rootroot00000000000000scikit-bio website ================== The scikit-bio website can be visited at: https://scikit.bio Previous domain names [scikit-bio.org](scikit-bio.org) and [skbio.org](skbio.org) redirect to the current website. Guidelines for contributing to the website: https://scikit.bio/devdoc/web_guide.html scikit-bio-scikit-bio-a3beaa6/web/_static/000077500000000000000000000000001520735541300205565ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/web/_static/css/000077500000000000000000000000001520735541300213465ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/web/_static/css/style.css000066400000000000000000000027651520735541300232320ustar00rootroot00000000000000/* ---------------------------------------------------------------------------- Copyright (c) 2013--, scikit-bio development team. Distributed under the terms of the Modified BSD License. The full license is in the file LICENSE.txt, distributed with this software. ---------------------------------------------------------------------------- */ /* Custom stylesheet for the Sphinx website with the PyData theme. Instructions: https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/styling.html */ /* Refer to doc/source/_static/style.css for comments. */ html { --pst-icon-external-link: unset; } code { border: none !important; background-color: transparent !important; } html[data-theme="light"] { --pst-color-primary: #239552; --pst-color-target: #F5FDC6; --pst-color-secondary: var(--pst-color-primary); --pst-color-inline-code: var(--pst-color-accent); --pst-color-inline-code-links: var(--pst-color-primary); --pst-color-table-row-hover-bg: var(--pst-color-target); } html[data-theme="dark"] { --pst-color-primary: #72C093; --pst-color-target: #2C1E7F; --pst-color-secondary: var(--pst-color-primary); --pst-color-inline-code: var(--pst-color-accent); --pst-color-inline-code-links: var(--pst-color-primary); --pst-color-table-row-hover-bg: var(--pst-color-target); } html[data-theme="light"] div.bd-header-announcement { background-color: var(--pst-color-target); } html[data-theme="dark"] div.bd-header-announcement { background-color: var(--pst-color-target); } scikit-bio-scikit-bio-a3beaa6/web/_static/favicon.ico000066400000000000000000000013761520735541300227060ustar00rootroot00000000000000 è( @�¶ ‡·(‹¼/”¿?ŸÆR«Íf´Ó}ÃÛ“ÅÛœÊà¥Õç·áìÆìôÞóøîûÿý!!PNì!îÄ !nì0ë"îqÎç !!º0\îQîVîÓ!Þ¾ë1îîaîéîî¡íné&íîRì1žá!!!ì! ì! ë!î`ê®Á!ê>ç è–ç!æ!!æ!!!æ!!!ææÕ! !!!scikit-bio-scikit-bio-a3beaa6/web/_static/img/000077500000000000000000000000001520735541300213325ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/web/_static/img/doe_logo_green.png000066400000000000000000000373521520735541300250210ustar00rootroot00000000000000‰PNG  IHDR^<.`Òÿ>±IDATxÚí]TG~¢bC‘Þ{ï½Qì{ÇÞÅ.vEìJQDé" ¢¨Ø ö®±¦KŠIŒi¦™üúý³z_Ül^£h4ysÎ=ðfïÌîÌî~{綉^c9°ÙÄ´4M×aWš–Óöµ�ý®ì4Ÿs{·EÖ­rÓ¬[»L³oî²\¿7­Ù�Ã9º.zŽ¥uíæ™k‹”EY”¥VÊ“3v~Œ"é(gã_\ŽZzUdô½Tj½êb±ÁÛe†ÏÏn3ÄÎ,c¤%ê"q•×è qµ6’×h`ó#ìÝlŒË%F¸^fðÇÕ£ %ÉMÇìÉ2웟 ®¯œQeQ–ïF` œ�a9šo6~_¶aöéb“Oo3À’%šèeŒNQ6i Õv¦PicQKkˆXAÊ~‡™Á´—9:O¶FÄdKŒŒÖGq¦1®–™à`¶Î{e©š+Ë6êµVΰ²(Kµ€7‘Ñ/Œ|•³ñ/)9«›ÔݳI{ʾL�sò ±.NÁÃŒái �Pïd‰àAFðl‚â �²F¿é6ÈN6Ƕ,GlNwÃŽÍžè5™�°Ÿ-b'4êⓞV°îg‰¾ÓŒQžg†£ùz¿TnÖÛ³/Ë ƒrÖ•EY”ÀûŸ-»3 ÚŸÛª¡,C)k�a×φ]-Ñ µ%†˜âÌV=”lÒCy††Í4Å£#ÖxpØ•…Vؘ`ˆ’L+àzö¹câsxDùáî¹>(/iƒE«¼¡ÒÁ= ÛÃA#L±%Ã' ´;µE·°dƒž¥ò(‹²(�÷?Så™ëVæÆݬ�u‰ú°éËÔ®µ¶Å�m¬Y®óÁ¶øj¿!No·FúzsØŒqER¼ >Øí\ Bôr{ØM n#h^D=Q¸£Þ?Ñ Ú[aÛ®ž(ÜäŠû[aÙOx v†¨‹#"çØ¢4×׊4åÇ5‰TÞ eQ–7¼ê£}Õ5«f[UF %Ô×cÔäß|/hŒ�ª£Z<’gðÞþø¶+® €h nî ÅÌŒ.¬­7®�é‡ce­ðÅ¥>(ͰÇÕR¨ò`ª7¨ôqÅÂ$kÜ,ÓGÅ&í­¥õõjaBš3šÆ(JPß•ÑFNrÚÛ_£dF£¸I®â5˜2šÃh�¦0rðiQýbï2Fýx|ÝÅ0ZÀã!å¡ïE×.á˜ÍM,¯ŸùŒ†3Òäñõd´œŽÏ%ZH×Õ�x\¨ž;W(¯­ÕqüÁ¼ú¼zñ¹¹sL¿¤ì¯ñt¼Ü£�aT—‘ £IÄ·€æyõ·‚‘£÷—»î4F)Œ&�‡ýv&ž‚k�ª.H½MÀËÆ`Cã+btšÑyF{­eÔI�öÜ}ÚÄè(£ãŒÖQ½1ÍéAF§¥2 ¡{Å=ãªÿÀµ£qbt‚Q®Â�+ Ìú•mlþcJ¢̺YA³³9óJÐÁõ¢¦À9-|vÀGòŒñÝq[ô�焈e!x|ÜévØžm�µIöðžé ó!‰ €û‚tKj » x‡ ÕÂdeù!½ %Ζ‡â½ÃíñŹnÈXk… I.uöA«yÈ`<¢Þž�çŽ#…º8œ¥}}C¬ª}-îEÑ'¾2|Ä3žWw„w޵¼ú^ý-s">ïl^½ Õ5cô=�«�ï—2®¯ŸŒûÒ�Î'ls�‘7�oŒ”¾¹gÃô]^šã‡2æOü\ÙKioÍè�€Ÿ_ î9Ôs÷|$ï·Ú;º:Œ® Æø¥B��ä ;U¨÷lFŒ!D!6pígНö5ÃÇ¥M>Î ©ëLpk—5îí±Àƒ½6Øœíˆ>Ó­˜Të‹Èõ-0i£;NìwĵÞØW„%!Ø·+å;½pù¨’‹<à¶,=ã8?=æzâøÞöHHt€×4oˆº¡á`_Ü>Þ¿\ÂÎ\{Œô‚n”* qaKó;)1õÜj09Œ~ä.A}MÔ`m7Ï4úÝ”*„=ªp -©Ÿ}ŒL蚆ðÝ”÷õäêÞgTŸG�ø@ÏþßI|Hªp )…«ëÀã‹¢ºÿÑßN‚ërgô£‹$m7§æñ�%>MFfÄ�æÓƒÆ¡A<œÄýŒÚýÀ«¿Â{(cxç>Ku΂±6äÀ”x&ðÚ:4?òΡOó0ˆx�12¢O#)÷Ä’8èR?±Tw‘w‘T—J÷‚»ÆÆ4_ußUà¥ñˆç÷­$`t²ZKó· xûЧU"÷²–ÛðüëȳÏÇÌ1€(ÈÁ£,q,§)J7i⓽æè0Çn3üð°Ì3–YaüRGô‹óGÚn/<:ã†�yáØ™Ó…i!˜=³%:õ韽Ъ{FŒi‹ +oi‰Ý9íp¹"'+�1,3mxCu ;“†[ÃyF R Zw™R7œØj� ‹˜ç3ÈÙÍôÁ‰R=\Èo~w}L=Û/÷P|.¨Ï§I$£í<â¹@KvG­ª<4Œ7ŒúÙ*¨ß*8;¯» –ô ÛðudìÿRjçë+¤ºþô».�÷PL§cÛ%ïï4¾†Tׄ'©Œð7¦—æ[¡´B/íwŒnRÛ š'ñKû˜[žóøOÓ±Ö4N+z9uy<=¥——ãíKõ7è:´×Âi9÷d0ñfH8&–bÂÀ›N&=¢ºÿä‹_àåž9¨.“ÁׂÑgÄÇݳ‚ãKÅR±”UÞ…±^W,œW¸Ñ¾l£®,øácçé3[+ œjˆëÅêÌcA‡-ý]1~µ;S3Xcê' \ìŠakQXˆ/Žù"+¡ºEv‚Èb £hˆlçAd2"›ÅÙ/‚Èz6DK òŒ…Èn.; ý��XÛûòÃñøŠ;b·†@}|¼gø2ˆP\ßíŠ ÉÖ°ŒòˆUžx~ÊæLêÕŽ ù�z¨ÌÖ¸Ÿ¶´¡U €÷3)À+KâÕâIÆb:+·jïþrŸt†\}x¿–²Ü›Ãk·M¬~àÚòT šO+ª[Í“<Ÿˆ—ì<àýžÀþ>õbðK”<~]ÑïÄêðr ¹…úJ¢““Ž7S›<þÃRÆy†Ç3•V)$iEòyºNM)/û^îÉ|I:&–ôFÑïA¼ë{Îûâ»¼ìº }AcHT€Ÿ“^%þñ‚c |¡‚§ŸïGõ•¼•IžP "ã|œ:ɇ¤cí8Þ¤:3¨@5¢¾<9é]Âqñ8¢Å+,±ýAfÇÅÉZAé¿Î[Â@×Ï̘†“j8�­ÍÐK“��¸Î iÉè±Ä ëvµÄç•^ˆ™×ƃ!ÒgÀê¶Œy;¬dqÐî³Ùå;±¥d2‹³Q°ÿ<œ²cŒ:®ƒ¨}Sc¬�ÈŠµ±ž‚^ý rK ||ͽã8Û»7; ?Í#—9ãl©îtb^&h?Û s}p‰�oÅ&­3…ë4µ«8‰–ôò?ÔoáKˆrúà€qŒŠy/]x5€W(q.¡ú•<àý�$ŒH¢ÁôâÛI�”#0ý’ê|y<9ijŽQFåô{©xŸÐ’;‡úÅRÆ!x¹¶3in$]i%¿ž €÷$ñGóÆ9�SË€´„íÀ“ºn’¾°&À;—x'I8&žß¡àåV3ȰƑÿ; ¼£h<�8É]Á6éÔæ*O}v‘÷Ìpý3ôQ.×ÂŽäæ«ª8™Ú$ÕýÊÿ"‘´±U^B»º$õ´«Õ‚ªA,õõèx¯Êé�¯ãÕ”@æ< åÊoé÷ñ�§ã=E¿mé8÷B¨&ðö!Ïñjçå@ÿó�÷œÐà)á|bà�@¿+xzÃK5Þ® ¶“x‚£yF+3—1—f°îa Ÿ±vhÖ�ó,ÀÊMnøîˆ%ZÍrÚâÜaj…ñcÚ1 œ‘7S´�{ ¸œÛ�i»õˆ]Ó Okãû£&xöÑ$üòäs<{ö\©ØSÕp¼màvXûªmgÖ¶%`·è�Á•’ œ:â�á~è4Ù'·ÛáÓ£.è2ÛWÚáZ©!šŽ ĸdwÜ+ÓĦ¥ ÚV|OÑm¡IË3:‰'³!}=gó–EÄÇy@Ћ}E–úôE-ãüá<«î(2¬‰¥ª+b½ÉÄÆ©Dbשîx9<Àô«"È@zCüòøÅïÀ5êð Áå<i=ÆfA’µØcI›÷‘ò ÐÇUxcŸÉ}ñ¸ëüí{3 [žg:ÜžÓ�™Ö[R´˜ŠAw˜`Ô/tgRe·n((cw,vAý™ŽvI&åvZ÷89åþï’Ìh#šöŒcÑlÓÐoæhœß;xú%Äå£÷߃NÆ×6ée›Žb^KàÍ(€IÅÎÓPȤê÷Oz¡á@oÌXn‹‚Lk,c*�ŸŽ[âd¾ò6è1ðõGI‘.oÑøˆ©ªâÎå+–°xtŸ–ä±ð?ºÉ xº°]‚vÜu5Ïå,Ï CßSA??‘äÊÿŠÛòÜׄt“§?+z0ðúP£¯/÷EvkO’ðYÐ?¡—CU‚Þn¿@*Ñ¡ëøJ¸D%À}NzÝúôõJªž’RùƵý2Ü—Ú�XE1YÂ2ù¬tº‡åUÐÿ— Îý#ùk7åñ ¤cñÿàÕâ¹òM¬B;N"ýX¨çåVT—/àïÎÓñ6”°úûxIzýƒ¨ƒi›ã?)0¢þ,É‹€Æ(öXé¡ÀØ¢yïX# ÇÝy�0^½xewX¶ÃVݳë™^×ß-‡[`K’>*7Àùbsú‹ßúßÊ�ƒ‘Ç·hª¯%<û˜ãÆu\Ún€²M†(Î0a æ€©iÞ̈æ]ßLÒ]ðÒ(öB7˲ûÛ-õznB³ÞÐë—Ó�¹°¸ÖƒóѤs&³ËðìOÿÞgO„kd*êvLA£^›P§Gë#…k2Oúƒ/ûë0 ‡7·ÀÁ=î0‹t¾L}lKÖ„ÿL´œë†³y�a3Ý 79ã\¾ÖÜUMìDÊ¢,ÿÑRMàmÆÓ�ήB;gžÔ׫–�w¹P• çZ¶ò|‡?"õŸ> ½+ÄR²Œ¾4xóÑEßJ~À�BÀ{j‡móEF§WÇ¢n¨%N4ÇI–”d޶Óíp´Ðá1~¸|Âý‡vdîa³^ÐÄÒ)ŒLbmÔ+:}àÈ…Íà-pR—áE0é�‹ ‘i¸÷Ù׈û\ ½ÏáÓw9Ôº¤C¿_6š2À®Ûcã  ¾ë^I¿�Ùÿ¡ñPõ�‚�´@l²+˜ãÊ6}$¥XààVc|RÒÓÀ~¦nU˜bóµXåë§,Jà­ðªð\)‹ªÐ®½0а�7Q’/°Æå'¾? è'RÙqzžœ¾ty:äV2øÏ6…�·r«åÐ3EºXö5ƒj{k,�7Ãݽ&xpÈ ]6Շޢh](S/D1o‡¯t²è2ÕBSº†ýs`5(ŽC àÆ×gÔvØ Ú·È\ÿ.‰¹¢î‹’�· Úm—Ãbp ˜”ܼOÆ ©ù…ê�S[tè}}VòÃ|uÂÍ"\0{‰)~=ªƒ{»4™ÊA§²êÃz†7–¤;ãÄf­kç×5R¾‚Ê¢Þ*©VF`<«†h“Â3j6¬eà�‘§+å-ñ‚…Rx*³¿PæB�õÙS_¢£«là=Qh–’ºN:–X¸Ì.#ì¡7ȇŠíq¡Ô³S¼pmŸ?xŽ`~½±¯$QN½‘Š&½ÓaÌ@׆�®Ý &åÛïQ;á1¼ !öàø¥_!íógøî›/ñð³;$ú>Çìå¡Ù5 †}ó Õ+ êøþ)ù t¾íÙo·EH‰ïŽ«G\aÜà ũڸ´C—Ø4gÑ 6pZŒÇG��¶¬aoå+¨,Jà­ðêð¢Ñ6*ÀïËËù1Ip¬6€wÏ£¡‰„ó7&¿ï3À³…Á6Ú´¥pfV…ü`#):æcÄ3W!à=T`å|½ÔàË–# aÖË󛢌ùÇÎ]m‡ô V¼À'N z*‹D³âT ñ¯ i 2ݬ!SX3Ðu¾ }æ–bØü š·ã–¿%%%Û‘˜’�‡cYÜFŒŸŸ…µ9û�š]ŠiKr]ˆÈùùŸ�ÃúËbzâL¨ˆu¾�xàËIÚÁI¨ï7_³H¹ÖÓ1j: .ÔDyFslcAs–™Âtªv˜cÿ¦æù›ã›5V¾†ÊBÆ5Z÷ jM†™F öQï¸îºÕ ?®aÈ0?YÍR|Áä$ iü€W‡TÒ" ‡ðëPèþÿ„úf¿%ÏŸwŽs1”")P£/bÑS!à=^dÝãÔV=Ø °ÄÈú¸¸M÷ö™3w-+¬]o‡! Þxp0Í<‡°eþÊWÒn×äúX­>™Ìx– £¾%°x•çâöû�Qqø®Þ|ˆc•·Ùÿ7páê§(«¸†½‡¯áø¹Ø[ùöŸ|€cŒ¿x÷-\¼þ}òÞÿà1&¯>•YhÐ+ã•Ê�olã€Øz–,ï…£¥60ëc‰ÊÍ8�Ù ƒæ˜bNŒ6ºN7Ãà/<Ü­ól[ŠôäéäVDîdGj‘N“[ÙeEổø¹åLúº“ÒG€€ßŽÍOÖòø.‹—r¼sy’ßqUû:J�(%”x(š<&tk´Ä)Ï� Ñ�dX»'ýBŽîŸ‘¿îp¡—„ ¿XZN•2–Sâo¯Ï‘œñÏHéïõió&�—®-‰h§)zЉ€«%¥Ê|Îs¿ô’ÐG��W CåîWÒ½êPÄâ %^äéœú$ »ðü”ï)’=Ž Žçx�Áx¥Gs"ñM‚v’�÷æAo•ë»lƯҀZ DÍÖÃ-Œpï€-¾<æ†ü {äïóDÊÊöÌù«´Ë©˜^ׄI»ŠÐeZ f'Æãâé|ܹV‚'_ÁW÷÷âÓ÷à«pçV9¾ýì¾ÿâ>º¶_~¼÷omǃÛ%øêÎ.<¼S†³•Ùøò“ýØR¼j�YàÆæé°Q‚ÔËy9$Á$l ®í BØDk¬Yª�5+µÐcž &ÎÓÇ YÆh½*_ìÕCòB7“jÅ‹¢©múŽŸ,†\œdñ?:ýK¸Þ®rúè&aøü5�ï=Á¹ÚÕrÿ÷)®Z5@Ö¢âžUã¼ÜK?KJþâV öÑNÁëÌV ¯B÷¼7¼t}3eøŽƒ—ÄEJûLIúYž”ú?ß�ÀHÇwUlÈ Kù›ÿÈû�ÃOÐC »ƒwüÁ{ι̵¨Â<ð%Ä¿ñ~oæmà},nÿ¥³ý¹f·Ëô6`� vذÎ?5ÄÇìpx«-&Ç;ãëS^ðèÔ "Ï¥¯$NQ·çFh3Î]L½Û>T”Ž~s¾ €¯8ògÿû_²¿ŸùŸ0ž;,„ø–9ðž!p‘iœQÃøåh}|±Kļ*4Pšï�Ð1³™Nw3Dør|#çå`³ e[:aÒ ôœh€ß«boZ#¦Æ0ļ¥zpšæ�Ò"k”'5Zš«ZGÊ„ZHÈZ[ô¹àáqåeÒ’Fkå<�ä´ï,à÷æ}‘k›Î ÎÕú5�‡“Ö�«ð’ô%ð¬éy�H2.ñ¢±dÑy`I¾ÉOåôóuusúÖb"t úQ`ÊEZ¡¬“R/X†s«˜VGI*l(ჹJRR’0ó($ü=º¦¡2Î?„’0]$àÜGÓLª1”É�[™]¥>¹k"…?œÆ8å/J6è8ÜÞe€“¬6Ä;Òtá3Î]c}‘›åˆ.kP˜Ù"CæÉÐ–Ô êv_z1ØDæC»ÞÝÑÀ=7 _àŠnÓÝÐyŠ "¦»¢ÏLŽ\^PÏ™nè>ÛÝçz"b�z.òdä�ž ]Ñc�3ZGÛcà"[<Üß8/ÂàI½YT\Tz¦¿”zùÁûÆaÙ’N¸PáË~?G‘ÑF(Éѵ¼º°n�¹›ÜñÁ�ë%iz ßàýCÒ’í?¼âH4u^Ž9µ-Õ AŸtÅ+Ðv‚½í~ú˜ö¦�kræ·)�ÿ�ëº%]GøÕ$Õàüê|I•Jæ²z¶KLà9Ü«–éâó}Æ8´ÝeEžØ_à€Ò=®(Ìh ‘Å, –X÷ü˜Þ•ó¹åüu"  ßëöíšÜ´�¨#_[ÆÇ¨¥=‹‚s`þ·ŒZ93Àtc’«'“`}!êÑÀD-YsUÞÛ[ãÛ#úxtH„~Q,:®uê÷Jÿ»‡wm¡2e[Cá1Ä û³›âôV5\Ü¢ŠùKt`>ÖsÓ=pg§ö�Ý™†jïðÊtÿ¯Üܼ¤9µM{$œ«Ÿí>‘¦§æ…Ìʢ˲Ò#þÀ«,µP¶Æ7ð)Ë1†N73´i‚‘³Í°6ÉwŽx"g£îžtFÜÒˆœ½Zâ3¯‚:ÌoWƒ¹|™35ƒã�Bôæ€w:žß´E�Îvh7+?Ô%ÛÝá>Þ*½Øöô�E”7Æ®sì�®‘ä…zà ÎÜ¿Ba53 ×®®yãã­"|ºOý'fàZÕÞddë,P7°¿uüçbg~ ˜ö5Gì-ŒšgÇQÎØ¯Ž.³-1&Å·whßÛ¾^£Ñ;¼uUïßèaÖ3Á²ýç×xîQ\ˆ*Ðn¡i÷’mÛÿîdÊòšË¥í¦Ó6®ÕEÓNæ…9£Qw{è2ÿ]Ý1�p�é‰ ûüоW'žï.¼ÉPéþÒ›�Óï:±` ÃÞ±¯|~¹b íþ¶¨ØÓøa9pß e;ŒQ¿¿öAçX¬°Ç‡§¬±:ß6s‚^€nà¢`|sgžÞn‰£Dˆ_©ŽŸN6DߨA/€·‘$à¥üõBâlY(Ú�7eÒ1“¨»Âl´;�„Þ(_Œ^ï‹+ź_$ÏéüÀû‡À¸Và½.%!ÇÛ¼½aàý[¢mÞ2òâk>ï áÒ’æVØ?&j¤Å”F9ÿ”¯²¼ær{·ez"óhPikÅ<q(£ò׫AÔ‡I¢SÛàpiô|˜ÔÙ‚¼ üTz¼^GÞ½»¦áÉ%‹9Žˆ` ÛøÐ™ùÖõõA£a>˜–âŠ]»ì‘]ì„Â�Np™ï‹È¤xr~½ŠK™"„ŒÐ�ñPOà’&úNìÿ x»KˆdãRO¶XŒ÷ö„aþR ¦ÎpEàs|T¨‚¡ Í êߣ’|p©Xÿ›´‘o5�÷ …P&�Ò_QÚHéTx%ê÷^ðrRdJª2¾ aÒ€÷!EøðûI¥¾ yɱeQ± ?Kyô)%—ïO­º’zⲂíûJ8÷ZÚeóøõx~¯²æÉX ¼ÿÒr³Ì$+q�. fàæ„þÓô1zŽ��[úWlEc·áìØ’Wþ» üTº§A“¯^.ƒÓñV”Oųkæ,êÌ æƒ=Ðg�5¦ÄÛÂd¬D˜Nw@Z-ò„TŒJö`ºWg$´>ˆçWp-K„>QzyÃm<ó~¸aˆ{1)v+I¼©’�74ïU„a}’%a4ìë†é‹ô<Ój£C04Ñg·~»i±(´šÀ{¿6^‚jïwâ­z^#ð^©ÊŽÈrÆ'x+å´7#ÿX™Þ‚6�x»UÈ¢,i÷‘r´nP �T m›“?¨¼¶�Ä¿DÞ¨Ú¸Jà}Û�7Ì–œYÀ„3ÎîtÅçZ s|²ó8àAÀ+Nˆ“üBÇËåT0˜ {¼: xw—Dáù{&ÌèæÈ¤TfHëÌ-û} êÍ@7Ò¢¡h0&Æ“a=ËJZ�†àÉyoœËaàºm½Y[7øM>²Ä ¨î/€·�DUƒXâ]òBâMH°B“öv°å‚¶ÑÖØ�«ƒÍô1l¥ *‹Mk ¼&ÿðþm³Å×¼joðRÃåôqMÀï«ÀîTà¼õð»’æŠ—Û@QºNynnkëC¨Þ·´|¸×:3aEs&5Zag®#.îõFNA(Aëå�ØZÊT _€ÛŸ �^z5¨10|‘ŸaðhõÜÏüeÇà�KúhÖ‡o7ºÌ Á€w £¡þ c^ Ø¡nH(–å·¾ˆŸ¯†àƒ-"¤­Te Ëº—ëŸï,ÊœÅü‡Ã Q¿wºtà ‹ÅU¼™+Z§±zó†¸R¨Š³yMÐa¾+ú­öÆùí5Q5Ü­¶ÛHíïïâ¼µ¯ xkm—W€÷„}Èó¸,àŸ§€AÎTÁë&ãã{”6m.ÅXvXÎuüÈÛaY=W4ðB ¼ïp9–£=1#YŸI•HK´„}f  @G¶Lo냣,*¬K¿Žd\Kz®Ë|jöÜý~YLÝ�õî{Qœ? ¿�ÓD³¾NŒÏ>Sݰ*Ã#ð€h3¤ Fð²VÀ÷£X ÅÜ-WG%3¦Žej‚&íöfj‰.îðŸÏs†FuyáÇ[WìÇÛ)éïÆµ‹pš×BF™C³›=&Î×Gq ¤HUƒÝ4_ `¾ÈWkf\{Làm0)�†“þPµ€WVYï5ïÚ¨s`Æ7Rx�÷˜à·GN<^oc>FøpŽ· 2Ie¥@[OÞ>vÕ¥üÚ|¿•Àû––Üåu<ÊsM¡ÑÕ ý&Y {£â’ªn„šxß±’µ\ÕîòN´ž`�æíå†.sü0)! <±®ÐÛ³Û@d9—]ÏÀ–üÂË@�6ôËF¼›3z㧪/�·•'&Æ9âÊQ¨�ô})ñ‚æ„`\¾ \ÁùtF[±ãX•é„…iNX¼Ñ =—8Â?¦ Þ:©3SƒˆC†×ÿ51:÷۵Р�Â>ftd†¬ªðÉ8º†#g­ú-ó¤w|Rª}gO–Ñ› øXÂf‹5ÞÛ¯îÿ–ïíj/j!o„ï|6 ¸s9H1ˆyI ÊÝaMÉT<%ð4‘¼ú x,H£éµý~+�÷--Å©:÷÷é?ëÆ¤Î1óó}ðÝYôì‘×ÊW¾¼b©—Ûî‡St,GZr{|Ï [Z=˜Äî…qkq³Ò -çr3?D¥µ~‰ÇǬ°w}CøG³úÈVh8>ù̧wuž+3Â1µFW?.é<Cÿ™}™Ž·�6Á\ûWÃÄ6+QžßÃX —¥7ÄõüzøzwS¬N¶ƒó /”o³AI¼êb7ý]ÞG”5ëÉx¿êZé|Oå$˜Ñ—p�=kpþr@D…Ò~V%Ȧõëx¿k!-äšCi×¾K¸Su5Ïs«ªÛɿ۪†•j*»74›µ)Õ˜I´V˜´ŒË"6 Eؼуæ;#«Âéq,zÍh?žº�’åˆz0i´}1欄¯÷« p¨ ó4ðd¯Þ?nÅT P»ú"lQK<º??ÐÇ–µ�`?…© FµA“I-›ëޱ©,º-*u‡‡àÄ :|/í£0é¹@ Û%i·E ì:ŽÃ�Ãþ°d‹áS4qv³*Nç5ņ¹Ü!Ë‚ðå>=¤ÄÔuG€·’¤4yôÇ xò=;xçkK^ÒÚ}+ÞyöM/õï#HøZ#Ô^ð²ëšÏ÷F!u·™÷ Þ¯©¤ÊÛ½aÆFÝ�±¬aÄ� 3´à„©Ký1s™Œ†Ú£åÒpD'…¢K|¾<â M?nÛŸ¸—;@ð¥ÎYÃr4u!>Þ¥�…Ë ™îÕ“pî 5Æ%8¡~¤¢3:§Í�™Ð¢1Ì­lX;fpk ³YÁ(ÛíˆØwhNe¸‰mY¸ñxÜÜ× Ú�&1PÏù«n÷…ªƒIÛöqˆK胣;­Q§�5â—6ÃÄ…°ã„S…f˜ŸèŒþqžø|—öÿ “t,þà}P ï$AÎÑêЛÞ;ox¿ ­µ�¤Ü»`9÷‡¤ ‰× ¼tŽÇgõ¶/©Ä@ŒÐw™ý®Cy‰Åùm³j¼\BsãÚrÛ|'ÊžS—k;ô>�˜gË<á7‰�oZ|w©>:ÑþS]qü´?ÏfvLêm¿ö•º�Ä. |»2É·[6Îm·ÆžÍê x]á6É]ºÂdŒ+º-a.dwœ°5µ 'û¡Ýª@„,a¾½#ÂaÌ|†ýІ‘ œ¨7žy=ü8 ¹ë™nÙeÍ˾ÿºÜÖ?©h�¯*ÐfŠ=<ûéb߆†8˜­†H&é®ß芳]QºÍ »S›æ¦-iаÀûŒ\Ê>'iSzDR‚F�wEoýü�÷ºÞ‡Uß7’¶3y À»ZÎ k£À Áã^C9 Ä9#cÌë|·k¼=yÝÆ2øVðÆÓL_SÚ1¢Q ÀY•v}hZÅvõ¨]“*´á"µ«À¯!o‰å@¶Áº<æV¦=š¹^íÅ7úaúºPä&Y!z�7Z.öÁ�#>Pó ‘ÿ �wÁËm€Dír�™†Ï+êÁm˜=«g>¹�XE¯\:„Ê�zhÆ\Ë"âü�¹ÍWŽÙ¡í Ñ6²Õ ÉW4šÑ€P¬Ú:ˆéw#0)«Èü»´Ûž�ËgòÓ{âl3Ð[b[JÏnˆ+ÛÔq§Ì‹“ܘÛS32Bê’½äLš<à}H.\¶déV„܉¿n�w*ñÍ}ƒÀûIŽUŸ‡”½§ä/÷+'_YEÆòXV@mrø…"nxÿðrºÞRý<­iö±×¼}yÁCª2ø\({�$ ¢í�’é~ß%t¬-|“h¡Vú°¤6GÈñõ"å]ÞH›c6%µÈAÒ!§ö¶2ÆIyYn’;h)][})ü£(ÇÈ úHm£:ÅrWd¾ºC÷÷¶1Îð�îŸI,ä·kf'7»Â+:åþ¨ØÄÀÑi“hãIɹ¿i°±OŽ©£ M‡ñ¼Œ^+-öÀýÓnhÐÃ}0c£;úÄûàë‹–ØZêˆÈuž¨7!ŒÖZ h~(ðÓܯl Ͱi¬ß�—váÒ{¾?ïÝG´¢�¢u�Q’¡Ž‡ py‡5 &øbsQ«ÌѼ‘8OŨ†ÀËÅáëÔ’õVðF—àý7¼—ª³‘¢”ñÉÞãTõ$´; |h×ë§‚Œm’€wµx7){¯‰Á²B¼bM—ñ‘®ä�>à%¥ý-Þ÷�Ç/–¸ƒ¥¬ž’dî­ÐDŸÉÕ8QQd ýI~ðÏô³ýƒa1ÁGŽuÁãs-Ða�'löŧ`ì;œ…/})ùþ ¾LB Í„UŸ¥¸¿¯9¾9P!S�F¼L”3„ùéej…qa0‹�Ã,VˆÄ’— {ºØ�üX”\«4è2v^Œýmqõ°“¬mÑa¸æ,Òa Mñp¯6vçXaCšæ{ál©É³¢„F± >\Š$Éiòo@5vÉ}§’ä�dqG�qÝ•¢Gl¬ Î8U–î�¤¢86ŸüÏ/ïý˜ÍåA–²(ç§.%éïznÃ¥ôÙ•¤IMIÀKs÷)Õ…Ê0š=£gÛQ¼¿I–x;_';âÓÜ’ôžÓÖî\ò$_ú=›øÓdÌY:ßf#·­× ½¿S 6Ø2 µf¦ãñ%æÞu§=6[\-u†É¬*òÅ—Ç8·È<AÔ&áøvdà’Ë~KðÑ=ü~¼†Ä2�q.I£1¡�eàÉhx8òp ;G¶» ±÷¼À-ê$Öë2CZÈ:ÔaõG‹[1µ“ ƒì ÓÓß–×Á Ù&h8Ä %ö¸wÈÚL·»½ØršÝ^3[T¿–€÷;Z.M E»¢4…–DÁÕ^j³þ5ïçô0M¬Æø8ßNך/µë ÇWj>\j?® ɆƑñ“KˆcNKÅd¸Qêxe�‰St¡Ü瑪O+žzÂLÁ~…ÀkÆûî¡¥½�òxço'ÞO¤øo‡ñv€_¯Ø_™ë¯Ž׺•·RÌ”p]™¼màNÐ$*ˆS‹ùh·üzbnJ NV„"3× «Ö»"!Ù÷÷» ˜é€gdúàÁI_ÌŸÙ"·Yù®y©çå‚8àdªÝk9s/sÂÿNÔņLK4×âE´šhp+t\Ž{ï¾ï„�ynhì?ÿ%èrîi\á,ZÍw%ÌÛMÅZáúAGh†[ã·1ZO0ljœúx¼_ cV3Àç æ7ž…?(×BêâzmªøE][ÿp”\CàÕ—ã–ôOnýþÖÕ5I I¬"yB¤H%7«pÍß�ÑæSŸOÿo}y®_äB5›7ž¡½ýÇŠª°$/÷aüI�¼uï‡R"[HÞÂ÷TεVT!"q³Â“Îܯš�ÈÓ;wt›,¦ù`f¼'Nos€ë4O1I÷ñ oeÙÂ;Ú^sñþyOÊ ‡{øˆb˜«Ý8ðl™ •I˜�LJšàÚ>M¸Í À”�Ïðìj0,GÝ0Ö®U3À±6­ຬ…Šï"Lš×ŸóCY!“ÀýaaŽ�‹ëâf1‹PËo†¥øñ¨ ú,ò@x¬7îí5DÎ ÕØ*>d¯xk¼Ônâ[ ¼“j x –äªJͽÞÀ~o�A÷o^2`í¢{¡H”Þ þÒ› •â•”A5�מ7Gœ‘Ù‘òrðÉ“‚.lÅ<àýX‰·)Õ-’´á€Œk-#þÂ_Áuù’˜“Ú�ªtÃrãÔÎmÑü-‹šG ï,\ØéŒ;ǘΗ…oñÅ´¦·í½q~HÉõÅ�¼�×ö#!2a@ê‘ð"{˜¨=ÓφæÂT4vç:âùYUàRœÚæ ×nã^z/td:ÝP¦V°em(Ólj-&ˆ\ÀEÙùáò.c”¦4;¹nAÍ· xãjx›Va3Ç7 ¼jx©ýતȔÐ~ÍkÝ‹Š¾Lï0ð6#‰ŠxHÿ©âŸ~绌 ÚDÓ²¼µàU'‰²òXÈÙò eU^uªïrZ’¿.]Kùsvˉ“!«ZFëŒe ÚÝÚ¡ý{gžGÀ@^ý{T·@B›F´w|œ ¯†²Ó �™d;~©#>ÛeŽÉqîhÂÜÌnpÅýR}ÜÜa€ÅËLà:ÄíY¨ðœõ6L:vd³V(Ïi‡ƒÛÚ#c}{L˜� ¾#ÐzÐP,_Ù{ ÛcoA{ìÉm‹¯Nø`× Dα�n[˜uÒÇŠÅͰ6®9|ÇZ#}µ®«á×ãF(Øì‚±Ëœá¶ ÇK�p6§é'I Ulj`µ}ë�W Øÿ7¯5ÏwRÅËèc^5¼AdåS˜RÕ “wxõ)¢$y®'ý¨6I€œKر´Ø@‚:h=yõ\Øo¶0Y ð†ðæj%_çÌy:�Ñ-¦Zà­KÑj £˜�ß�ܱœçã|š—ÎÓ] ¦)àù�»Tûæ¥/mÐÿV‰öy[Ìa:#à¹hpk¸OóÀÖ †(Ë·ÃÉ;Ĭ4ÅÑ\]<Øk†ü$¸4�÷P{Œ±Aèx3Ì_mŠý%Î8RÆÀµØ{vøâô.WæZ¡g´9\GZÃ>ÒÚè5¼)æÍi†[Eõ±)±9W4‡Æ(Ì‹³ÄšTÌ[熱KãƒseF8™¥ö1]×Xj­x_à×A©¼syÈá] çZxK0iÔ]ÐÆÿ5/¿§ ¤rY¼ï)xOf(xî0}„’ÃÓjŽëszá «ù\5P`G�Þo«W-ã?\ï¯òˆœ‘>ž,ÈÔÇùö~ÉK×Ù’Ç{EÒóO)PŸñ$Ìi àëIë$©„(›�ØëA‹WoJ *î÷=;â߇ùA#düã»@r[Eâ 8¿ðWÕ.Ëö<Ÿ¯ùÉíúp›õ �Ø›©��iø Ü�†ú"*Á ¿ÔÆŠÕ&ØŸ¥‡+Ûõ·R#£ >Îá£Íà=ÌacÌÐ%Êfý,aÚÇÝ&Ámˆ9tµEn|cÄ.ÖÄÑÌx¯H··ÕÃrnäa¡¼Æù›˜êaxú'xãý cìImv%ya]ۺȘР|@Ë–Ú¢{Ôç\Þ¹ìék|O?Ç;Z�ë�Oí¥õ.Áwø&Yñk{|Ü’?’w® 2ÊÜ•rmÅU­2êÿž”þ¾ }ÑTäôÕ…$šr’=¥à‰RJ¨YÃ犓îr¤¾TÔúèL ø%�ÿgºO\à�®€×…ú)‘âóíEzú\a²ÒË®#ýö/ô‘¹C[RiHq­Ë þŸèÚ¸`“}µš_9{µšÿ±�Ëw*ô1y½̧ø`2[îG,tA«®ød¿F,q€Ëg¼_¢�O˜oiº.Nèàý]ú(ÝÐ _•7ÆÅBul_¯Žó…j8“ß7 ê3õ‚)Â&Ûà^¡õ†ø¢ÿK\ØR—·jbÃF[ÔÕ Ú#Ðb¾²¶Úãîn]ä®l˜ž½ªI�#®ÈÛˆ$_³Z$sJð¡!pÓò[ÉÊð$¸fs}4–b¦¤R©íñÙð`ÚšÈF ¿•$½¬Œ1ªQ_æRú³ ãuìO�¤à¡œ”NécIªAjíÚz_H߬+å¹² {Òøm^ÁxŒiÅæSÕü»$pp´‰,69}pºÊÚ�Þ±:rÞwYÇ‘Dë¡H&4âw!•žÁk¹‘IÚšùq�—~V®‰²"+´Œa‘g: ÷"|ZÒ3VZbÓzC¦êâÉ�¦ðœâ‚ôd]¬O5Fó^þ(ÎÐa:âÆHZ£…Y‹ô(7{á»Zîcìq³°>†Æ0Ï…E.رI ËVšcÂ4œŠYëÝp²Ô 7·6{˜So€HY”EYÞð*Ë[PŠ’uZTf4;q­DGvZ¡× wxL À„Åæ˜k†À©ŽxvP½;àæ¶ÆØ–ÉÔ�X†~ß_ÅLú4Í“ê#9^WsTàåÿ™.Ø’Ü KÖÁ'Úö31-Õ•;Íp»T÷—ò¤Æ™ëc*(‹xÿ“…ù˪&4{$³ù± Å8Qf…©ëœûh?ô�k�îÑVXžhˆÁ±–,d¸%TISÅæ¸Æ˜°ÐýçšaFŒ.ÚO·†hPÛ9yƒ™Ýa©Öd:âj…Nè<>˜Þ¼¬8Y#L9ëÊ¢,JàU*…ëÔ‡–¤j&�Ý¢ùÅ p¦ÌÖ¹`@œº¬öGØòx/ @È4[O²Fød xÌt‡év+Ñ'Þ£=�œãˆÛûÌqŸé‘f4?·c½æªôeªAÊVeQ¯²H)¹qÍ\Š’µûÄ5šy«Xûƒ/*´Ÿßߥóüön#aŽâ";dº ‡QE±5.”™ãv¹!>Û£óüóÝÚO�g¨È^ÑhضÝÞëcêi+gTY”¥FÀ»�(gã?RŠ’µ ËÒ�œŠS´�6۸坬;|G¼jLùZÕ¥e‰ªË¶ÅÕŸ�³L¥Oyš–[yº�ÓŽ4}ûõ‹êª)gNY”¥Ö€×�Q$#ål¼=åÿ…(G%UY1IEND®B`‚scikit-bio-scikit-bio-a3beaa6/web/_static/img/doe_logo_white.png000066400000000000000000000230661520735541300250360ustar00rootroot00000000000000‰PNG  IHDR^<.`Òÿ%ýIDATxÚí� ¸WÓúÇ5ª¨¤9šKRQ©„&•›P¨L·�)CÉxI¢’!¹®ÜH‘!S7\É�"ã­‹KRW…•R©ýßïÿ|–ó¶ìaíßù�Ó9µ×ó¬çœßÞk­½ö¾ë}¿ï»ÖÞm·| žç5õãŸü8À�—úqŒÿÊßëü8Ê�#ýx5ñ"?žìÇn~l¸[Ò�†lÌÃCüxº«¦­±óvrc?^âÇñ~¼ �êÇ~Üß�•ýx¾Ïõã9~Fú¾~âDZ~¼Á�×úñv?žçÇji˦! ÏÉ{¼œphÚ;_çáÇ)Ä;üØÇ�gùñ2¤Ø³ýx·'xÁaå”Aú½Ñ�gPÖd?þÍ�-Ò–NCÏM™CüØ.m��§SÛøqºòãi~åÇï¸~«»øñ?¾ïÇŠ~¼†{Gùña?®ðãë~üÌ��ú±=, ?<å¬Ò�†xw¥Žê`<­Â&úq *áqÒ½ÎïÕ~ü˜ÿßàïh lþMú[ù-<ðB@{ƒ’š_'Ý1ðÀ"%wJ{$ i(XàõËÚÓ�2Ì[Z(Å€ë%ý¸ÇNÞòŽe3Éx3*?^hñ´[ÔÿB;|¨~ �^îÇÁ~ì'^ HÍbX@Ù“ö9þnTù…¶(o¸÷óãóR�,4È^ðÑY×{c l“¿ é„�¾‹E©dÂ:Ô�ß©¢´OS+]e®_o¥^ü•î8F/šxÀo—êúŸÕuólyÆÅf’2n$ͱÖä„q¶„‹£‘�¡=®FÉA÷‡þ•zÿ[Å`xüßÍIs­U׋2©Â¼ÎåýóãÂ¥3lœú~\+å[×1|DÞI¤¹ŒßåygyßV êp„2DÖ¦Ng¨¶«£VO Ÿú±”Še5Ðûÿ?Mº?#U4UÆÌž*ÝE\û�¿ÇXõj‰6³i{/&ŒéóóI·7ZŒ¤ÿŠölÅ{T"ÍÙʸú³ºþ�êÓQêÙó¹ÖÜzWñ~)AšÁzüp­íó_õŒ´ÃÒ¾æÇ}XxʆôI5æ ªQÎh¥É™zœÎµ‰ô…Ô±íU¢¨¯²<¨Aôkc„°ÉêþçAÚ!šÑ\û’W„¹Ã”¶<—Óø†}¨lÞ“”ÃÀY,B�â2íøˆš¢ÿ÷:CT;ÕØ³‰çó€y¬pãxPµˆg”`ÒÖ\eB/ñãb€»é–ªþY©=ëàš@&äxeP¬°®Oçy"ò^£�~¨ÓM©² êÐ…rfX×gX×ðZ 04` 7Ö ˜„¶êÚ£\;UµýBúÌhOïfÞ¯ŒFR9ÇJ_ŽI³Æ–V˜´?Ò·§�Ì8;ÁM*ý<îuç=29«©4¢!mRT×É\_D=*[uè¨A:¦ON#íä€{FŠéfï},LÕ‰%vðÄÏx™Ï&Ü‘Næíפ“>Ûݺƒ‘ŠC´¼wwb^×ï¸f(Žt{]€5�Id f}�p7Àû´(OcOx› ê.Ï¿BIË×°Z¼Æï/�œÍd{“²Å@7&ÀûuðFI¼••dlÂ|nïL­îCÙH¸Mïw!êÞÕ*ßã†~�¼Šz@¬Kš®\»EIžë´Ï4Àû`¿  þLi(•¬÷¨ˆþhè x7AQ-CKŒt<�D êèPá¡4ò*Œ8Ç+:c¦­®F”s3RQD|™\à6õ-/8µgz7¨ã©ÑAñ[¿©Æ,Ã@¦T‰ÇH'`(û ,k°"Šx~7eÕ=Ú‘ª>0¼F2ÃsŸM4®S'(cÏ‹¤;2äyc ÉØ™v›e©Ð­l Ç[Å´M›cì×H5­{*C•ž\g£6n§Ö"-™]Žgòžƒ �jYªÜ0~ï¯&ú¢Ž×€Ã‡1QAqÙÿ �ŽVüîƒ*íYƸ¶ïj>\Ÿ _3Õö'à»ãÉä1WJ*#éÉ @+s¯˜B¾µ¼© 0Û*©Ñ¨g«ôf|ŒÀPL‚ŸSÒ’ïVÉÚx,UQ‹T+@×Ç‹«wÿ‹}óÞÅ‚p;~›e”;• «˜à‹©DmÇ)�Ñ¥ µË}1v´�� sGQ—ã¨mÆið… Êm§$x–i°d1ú�NÞ]qa³¬|²¢Þ¢ŒQÍã :H|›¬rÖ#¹êU|?å¾f‡ÅŠ?{Âö`PeìÉê++rsëÞQHÂóЯcr”àíf[RIUêñ­­¢¸ÛàuK±úo‚êéÈBª�k³#Ü—þ¤uYŒ/P“çpÐGÒ‡Ï%àÿŸ³ž½×Êò*]îݾoeåÊ7$A¾}°¿lÇó*:rz€fm8Þ2ÚßïÀ‹ôº…Ø3DÚ–ôoZFÔ_‚¼xGã±ÒÇáÝ®Ts¬lÀý–jÑ颮Íî_Q…·Â¿¶”Bp�ɱ„¸ˆ ×Ìp ôBúm¤xÔ–axÏž¨FÅj´"ý~³2%Xé»Ãgs@, íiäâÖòLXú;†ù9’¦"VþNH܇ٛ'HW>¹3éMìÆÖíâ 0�Ò&ÞnAjRG{e­/K]´Œ~¥(ÿ xKá,/u,e•]ƒIµ¿Ek9\qwÒFõTúæ¥~ÏÎhIc¼ajh-mi†çtŽÛ4²0÷¡›…p‰=2á !ðV… ˆôaÈWœ°�×ìJ}ÔJßOQ9åc€w�¾â!ã¶™Á%Ÿ8aÇHÐ÷żW)eãº2"ÝL›nBˆÝÎo=(ãC¨UF™) ùƒJeh›á ¨€$&®_‡píTÙÑ’AYY ‰½‘‰1YQ×dâå�†4ì,!Cà­ ¸Ña ò5WR_¿,ïM6•S—Êwøs„1?ã<#%G”UIµG¯*ô÷ CNÀ‹41 UVo>uwêéUy7rÖB3%õ웄À·Ê[UZÀSÆ¢­×CÙ‰„þPLYÕ‡Ü5"Ýõú¼Wà�Œ�`_ü>_¥‚?Àa®tåÅBÊŸ€Ú .è:x“c¡&ØŽ×ev0«´‚§v‰¬%�l ¸6�‚iH�7Q¾³™K?!É!ÏÝʨY&ËÀ;*Ž+Õ›–Ôf¡»e¶]LÐծϾ1mm]Ã�ÂCì~ZŽÇ¸ãx�ã›’œb¯,ˆ¥±ÐoÀÿí#Œ·ãŽñ.îXK£8Јçë|}Ë8õÒzWVïRé4LC ¼ÎùªªÝh“Ò·Sg~ µîex(�†=ž_¿ï·àaöf›€<b;s+ àQ½Ù( MIµÁk¸+ð^„ÁêLå§£ÙŽ·ˆ©ä^øVNe« 9uÈXI¿Æt:éžÂ�7 éôaN1jµsE=¯1ÒøUWFÐñ½Ói˜Æg[Ôâ>ÄîÐ_eË(¹ê]"“íÇyÜ2¬«¹!Fó\¦6�”Ëà­ª>®´“ð }°[÷³ùf•¾�òç½Ú¡-ªM A5ú(«Ö±À ROÀÒ;Ãòd0›Þtú ®àÁ|ªgRô*| '³pEZÂiXwC~?Çf�Oâ¡ žù¼n}eùý0 WŸ¨�SÃP,ÙŠó0&jµ«!Ûwç¤uæ$‡÷mÏêúZH‡Zé›àýñf–ßï}£Ê©gµÆï8iYsO1V®D몖Ð2G6¾Íx\‹aŸ'mÀÑýkÆêY¶—„UÞhÔé9!ïò–ÙâíX¿ÐþÞ)ï5Êl\�ÀKþ¿*L˜‡«f3€ëŽÊܦÜ/(#ÏÀkq¨0ÊW�{ª� #Uú‡•­j ^5•eã§ü•Ëéq¨�ØxU�61 ~¯•/xÁï–²xRãx,/ùž µÀJs F´—Ï þ…$;'ãGäÏò÷ Þ(ŽÙ¸íèpüG©÷C|Œ`R}Ê`þükuçZùª]4Ù?êÃbpqŠ Ëm§ÿ€úöŽ)ã¸5p[>½ßGÖ³zd¹üeœŸ»g ±»â¶fðÜo9A/èü⮎eôp¬çeÍÌ„.ËÒ±�‰ð÷Ô™ -BòßÄÏ*)õs}Þ�e¤Ó®ŠeÔ¶dO¦µê÷Tm'dgZÎzž‹Ë\çíÐÊr³ýIyFxò+†Ü> â9neõùÉèSµÝT$Ñ *U1üç,L¶ ªQWDIêù?ÒÈ=ᑟW'ÝÇäm’·~Ày¡Ù +¬Ás ·ý¡ñAaBÌ»“ÿX+}µ"g;Ì·žÕ=ŸžófïµË2¯áÕ ã’r­Œ ïÆ�%ÞD›bÊùÎËðL_/{¡×g=†�f!ÂÕ�a[ê-5|’½Q íh’Ù°°`Ž :T ó!´�¨ÓÀˆçŸ�æ»àü'4hí Ú¡”èS{ ©Ë!é»ñŽ—Ø7°=v yŒZ¡æáïVÓ¡Bõ¬Áz?4Å$¨€ÇYGÚ}� ?ªxÝ›¡ÎSÛó~s™p€îKtÚ­¼‡™x}ð<ºˆï– •m^³­¢ÃX¸:ÛR½=኿pÈ;8†·�íPÆem\‹)³<ï_à\wP=¤ßÓõx‚Þå3Í| |Åh«³QdòÞåÔ5>´ü.ÅfŒª ëSÕÛþ°õ ŽÀ{¾{' Ü^òN)"Àé(¾ oìÙ^î¡9ÙÏ<ë‡|_†ñÔjËlTxßÅÈ\�À›†ì öX8À†pW]èì¿#…¾ábMUÀ»À�Ç9B¹—uBÒ�ÍþêÚªŒ½?~ebƒçvÞfMÜYŽVjJg¸ÝïÙBØ¿¯扱‹¯ôe�µý—||ö¹†é—ò]"í¾ç�÷¨áN–†üÞ‰6)�Qºà:Çrê*‹ßÔŽÊìT{ZMŽ/�Ït‡¤_áx7º8pc]4^š`/—tf˜ÛH>ï˸–xÿíÈQ˜€÷ó^ †¨‘ óù¹‹lÕ’¶�{1ø6²ò]ìð¼©Y˜ß)ðRà�b$Jø\OÝ“Õ|@BàýW0}æË^î¡&7# ¿ ÜÆËý&“ ŸÁÓ#Ÿ ÕP…´S”ESÂj‚Ü‘!ð®Ãïx<Ò´kœ„F±{†ÀÈïåð~Ï8¸3áû‰7Ì• �w` Ë™HY怣¸ðD„Ÿe\ÛÁܑޯCäRk¼F…“ž=Á!ß–�°Ì¡�öM�wç^1rUQœÓ0/÷t,¡ú%Þ5x8Ô›@,ˆ­•zu<4À‹¬ú·2êyÛ6í"ñîMZ½]ï*h�3�xGd¼Ë¼,�÷�ð US7Ÿ�WünËeéýâ€w®Ã8šç-`å)ëå~­"*L ëGÆÏ=eL È+†¦¯òš¯e�qH{Q–ú#Þ ¼ü@ ðþÇ;9àý>Ÿ¯ƳâãÖ`“�•@ý˜ðNVF–Ë•Û�ðÊçäxkï àýý�òx÷, ÀKgÅ”ñ±•¾�C>íðÜR¾4¨­¼Ü³ ¢‚¸=5ups[˜Å…0ÞB ¼7 vý¦:~3êÿø ¨Þæé¯ pG«ûͼ\ggª¡iG`¤Óa=êìà �wiÆn#Ù^é�ÃóxßÍâxŠÞ7ʈóxßJ�ƒA®ŽcýÏŒX|ç ¡í"Tü+¦b³X“F6ºôÈb¤À[H�÷¥b��Wà ~áü®Éxqã�V|uíÝDk4`{9;êVsÏeK_ Ò^êmÿÅוøõŽ S߀÷ÚD6”œîÏ‚?,�à•ðºñ›Ìà•w¿€~q}¿sìç8ïk}ù|L/¨´ÅoR‚ù 'çÉÆÙj¾‚,;©:ämíå~Ç.Ó0=Ëó;ÞB ¼¢ŽËéÎßÄÄçšÄ�LÔ¨¦\ÃÒ³iû ¸Wáà hwörwô¸¸“UG2IÙ|Ûë«üã2ÞLý?~l1Sà•p&e]H¼g¼ŸÃ¹ŸË„1ö @Â…«­ž·g€ ¢ú$œ»ça>Ý–‡ö\íe¸C-Þ¢ ¼bTÛ�‰Ð�º×ËÝÁV9ðŠZß’krXÎ[|PÉž¶$Ý‘^îžë¯‘´ïPª—‹ÄÛޏ1‹Å8®‹qoœõ± ¼_xüØb^€÷ÜüÚàý$à5}š—pˆz^cw®¦!±ƒb+|ÚEãj�k§Ù#FóZ–á{]žó;ÞB ¼pÝêÄ&ƒÛÔÀ™‰„R3ðJèÀ51ÎÉ¶ãƒø]ÆËýj«á¼ZÆKðÝ�„44.!ð À¾àå~wÀ/ôÈd9è£Wïâ,K¼ÔP;‹“ßQÀûa†À›—ðœõ¼CbÔ{�Zõ<)u8,f,ž—A™ïGúŽ^/çËͧƒ2?ïbvÏb=ÇÀßhW^9$GNÐÎ0‡Ü¼€§€œ&v©C9õm#™—{™‘€Ùþ±*ÿ$#Ñ©Áƒ v^©÷T¤AØnÅèÖr'ÞÕ&×í‚Àû­Íµò¼¨CfdóN�€zöÍC=ÚÇŒÅâŒ{×°%› –Màõrv~~Q÷Y.Æt‡ç˜óº¯ßU€·þ¶•-‹î:¸8‘$¿t(§ª—{°M?®MÄP±Ÿb­fNGÚ-‰gÅhT²<ÔÈ}cžÝ?ÊýÕò;8ºQÇB&à�ËD‰ -»ð®Òž–à°9"ßš �-?�—òÛzÛ¦æãüÎËAè#´7 Þ#b€¿�r‹òøh”Çzš¯7\±«oI8Uù´ös¬n7 �þ€JñoG±»ŒÄ  ®ÖÎà^Α�Æ›án•¯Æ•©Fºõr¾Åf:¼\ÌsŸ‚¶Ø›:¯FÊý‘24j%ÍGà]žÇ;ÔÛþÌÑLBAï’^ñJ‘3››…ô]‡€Û´pç7ðòŒñŽï×°°/BŒFÙ¾Ë^ÎùÛ]•Ëç”<ÖS·}³å¶YTÀ÷"ø›.p¼b`3Ÿ*¾‚Iû”C9§(~u/@D<#úÀ™p~·ÕÉwÏ»I¡4‹�„cž)@¶‚g™O•|Âñ3Vrù°fï<ïV}Ò¦K\Í¢Q)!ðž _þKïê»*ÁûÉ„{µ€÷–˜þoì !´ÚAÀ[Ë‹>@\´¿Qù<·3޾ʠ[."ÝXõ>"Ò•gΗÍû.TI ΗU’pèqU¤¯äâ„<��ùk`,˜E�ëâ‚&4±îý—ëW¡>(ŒKP<+°õ'æ�qX »*@š˜ˆGC©<ï*¤øý°t»Ä–¤/‘x/%ÝðÞÏ�›&x?1b6Îx@³z×ñ]$}�ˆ¾+G?Ǻáíà®÷™ˆr„›>ª�¯9^u©p¹J×7Ð[ƒ€ÊËù<Ð]ô·”õ:`ÝÀJ7”yÚ5 Œäycÿ»”Ù1d.OÂFTZäe8dyöí†ú yŸÓ¡@ƒYÏP·R!éÅ@ÎYÄ"õ8×Jº6´ð¯âÿú1„yI¥òŽ¢à—bÊ(¥\ÅQ×naâ_€T,`x%ôÀ“\+­Ê­VÛ*Ï;’t=‰v˜ŽÇƇ…' x…?®š¥‰¼W’NÎø´€€÷=/ƒ)†¼_ð¾N:Y`Oôܾ!”Ñþàw4ãÃÀ’ŸÀ+‚Ä‹åˆ0s\!ÞÖŠ;ŸìepV x¢½o–ªÿåd¶*í"ƒ5s|™UÆ6µp]l¥ïÌ=Á±9V[k ð€‰ü1•F>ëóµú=SKôØÄô¢ú½5–Ÿw /çPœ'‘Î`²šÓñÁ¹JÁ×Å”ÓC‹vÓ�ÿ�W ú&ÄzÔø¿)o†Ã”•ú‚˜gÉŠô6ÒòR i+ H86ùØä>yÞåÙâá€÷/*mÿÞ=‡Ãî³¼s­ô½ßiVŒåÝ‹1°Õ³òTc¬©b®-M�÷ÿ´ñ–AWðà2´�Š1ù»©¼£¡ÏöƘÿªÂ3ïÍîÃË,ÿù²ð~KupýÃx÷r}Ü à_Æü®� ¡±;M°ê;N®‚5Ñ¢�UyƨôSÔB ;I«3¦º*�)®�ý ÞšnxHI�æð’n1å<¡$Eiôþª3…jXÕðWÔΪь¡d~ ·4‘�«Wž…pÒ¢&܃´;Æ‘j)tÀKú¹;ð¾�çvÇ÷:5ÂÀžLðŸîêÀkRÐÎÀÿ¡÷R«½œÏp‚�—óÕëMÚ':xoáÚl/øÛkã”ëk x%\±HÏU ¯>èØOãû¦Jo$î!ÚÂ&$ó6.�|H>@KœÊÅ©÷×F¹�°º-QjbM¼uá…ª² udµh�lx½F1ƒÁÃ�ì�0ðñr>_% À»ÔË’s{À{¨—ü+¹Eê�$‹%ïµ4„G,çÈOŒâÞ�·yñŸÜe€WÍ�aTAÚ€OuUúêŒñ­aBšÎ±Ê}t;à¥íŒ{j§£ÙVÆöðþ$,y¹_0!m/®™Í4ÿ šçhÔgš6¤-$ü=¢ÍîÓ6—F–�B^oÜw ÍW+#S7Hê5Q.fâŸ+/ƒ¶iör�€\ãEì RÞÝYyÖ¡NüSy \Ç:/ÁÀZÃ1Šä>¢Ý5^‚JÔ!Sà%ÏßòxW0˜†dð~âÛy`^€W¹nvÏ�ü8¶Íë¤ãç>ÐaÇ`¼ù<åxcË«‹&šå;ê]æ—3ÔmCOÔu,×Þºj|�ÏŽ©ç÷°€÷Ëÿí.FØPõ¡´ûbu�¡4Åûêu¿—ûøIIV·YH!“”»Ñoj’JÃÏ šä®>Fm“Îï ÿª$ÝÎ!e•`ØfžéånÍœ�d8Büj\Å,o^Ã]yÞ1nI;Ê�ׄKò ¼ä½ßáYÛB¬Ù¼ø#=˲ ©jsÂ÷=tàxKŹ~á5L½Ï@‹·ÿ• ޖhÀqçzl!ö¶€Wì?A;;ïX{žÆÔõÇq"õš–¤ÑOÀÂw&ƒc ¾¹z'K_T /Êà†ú¦Ïg®ÔÃQêºíGXXçGÓ¸3•+™Ç¤»Œ�ðŒ«TR@À{G^€—|C 1ðÍðÖ´,ÉI¥æ~^Á„ÃwfàÅ€5‹¾pÙ¥÷†V½•·Ñ Ï᜗àÝ_µ‘™€VÔQpa_Ü6+XÀû…ƒÄ[žk#�÷†c]Ÿ%ýÝ`G;«^íÐÆëzq° ¿‘•àD€b¾¾ð8WÕËÝf, ×+¢¼‹”d;Ã2 R)$ß0%Ö÷åÚG!y$¢þÀ 8¬üÞÛ²¼å=÷�94ðÎð’ÿ4Çgž’ÿÖ|Ý…®“©o/×ï~”CúYšRƧÍa#î¤2W»‡oEeóéñìvo™ €×|Ò|=D´øRy*R׿c›º‰ô÷Æ'6Zc{uþ85X®‚þT¥=\¹ž‰5óÈ�2å¬\ýâO¼€eÐ b@û€tC¸Ö^éjÅõš c\¼Š"ð&äA‹,ðZETŠ z@ÞbÑò#×X+Á¸*ÊTÃõÔquýGºæÊ# ¿ºn„£kò”õr��½ «af”GŠÒpÄà× à­ÄµV…2/[Gäñð¢:TQ£MB„$c/87“NÛ7²Xþ~Q–Æi%VÀ±Ž…Ûùp\Iš& ÿïÈ¿mÛÖSý(;³ªòœ½ðÍë/¡Ü ¬hÍyáÁ<{-R·LÐ�HÝBö�σնЯEìïÌÀ«¿>n�(ãš ¼AÂÂJ ‰%Ž«¢ ¼bWøŒz®ÇÀÛÛOEæõÕ€�‘õ×´û+êzi殼ÊEoGÕV7kÎÙË9ÆÖä7îfo pÎÃ(ÖL¥oêånî¸I ¥ÆÆ%Çy¶´hšG”£@‹L;®:•’sıx–áã½?~ öcÀ·'’í,Õy†‡�„¥ÿFx䟽>x“¯R¯ пªÎ|OqHƒQ/o÷2ür€—sðõÚ|¦‰êY­bÒ^SצJ 'XyÚ{ù.·¤ò¨ð‘cŸ\áøì.etb¬nÊð½V0áke8®x㾨qbaõj@èù̪ïFï�çˆÈ&¦ íãwYsÿ%<œ$Èa\G¨´�4ì­JÂ|IÍøÕÀúç JÈË9®Àx=TV×ë¢&¼ÅØñ•ZQ¥oémï)¸øŠp6h ÓΫˆ«Å}êšqù�‡ç, ¤€tÅ¡Œ@}K¼Àƒtri…D¿ØË=õÈS¼rk^h:õ�ß”Ç÷«M.GmÉVüŠ2‡«gíÏjüU@zI;È¡¾#ÈVF·ßáÅXñ³ý~¢�nÑN_‡¤—º=‘´ž¥ü¯BÊ[É‚\<¦¬^Œ™E^ôáC›ðÂãìù^7• ÝM WËPG�,Ìîd^În,³Ût¥RÉlÄ®õEŽ!ÚÏPß!�µµÒMPÿPƱ€à7<ÿúI„­jVÚ”#´ª„¸®Š€÷ g¶ƒf~'üö™%´a¥׺ɤ_OÝÄåöŸ^6ÏWörŽ‹|‰—IåÖ#µî΃ßò¶wf¿•äUöoÐã�b/çZ9ãÏðËÈïGÚ3ªEþÉÂ{•ħ³!�™­(>¢ t§á¦cîÙéz'÷K$ D Ș¨\…pÐÝKp"•ÃóŠ\ Cê^ÇËÒgÜ Â�ÑØäÁF óî�];Ê…-¦Œ}Σ´[æX±˜ùu¿,m+Ïá$4Ò·€Ò«™_)’ì?¼'tád;àB1P<ÉÛþsÛë¨v� +°tx’‰(¦ß�Òi·4¤! ¼iØñ�Y1ÿ^P¾¢ÿ–ûW€élÔ“)^a‘r3ëŒ ù.åÚ ¦à;<³ªiO¤! )ðîŠ�ÚuÿqŒ\÷ ­Þíåît3ßkzCÝ[P¡^QVþS‘¢_ÁÈ&<Ìɨ�Ͼ Ò–OCRàM;7ç°ãÉ:†cÙ ±>R~\W˜[Ó¾n÷o»e¤! )ð¦À»“wrcŒfã1¾]‹Tû´DGe`»˜{@ܦ‰ÇÚëIW-mÙ4¤!ã9yO’ó%ÒPô;\<ŽÂkáTö$aäë×k @+ˆe¹aÚ‚iHCV桾OOm"…+üíK²¶þÞ IEND®B`‚scikit-bio-scikit-bio-a3beaa6/web/_static/img/hmp1_pcoa.png000066400000000000000000002177131520735541300237220ustar00rootroot00000000000000‰PNG  IHDRý…÷½*$9tEXtSoftwareMatplotlib version3.8.2, https://matplotlib.org/ ûþÄ pHYsaa¨?§iIDATxœìýwœ#ù]ç�?«J±¥nuŽÓarÞ��MœÖöbƒ1^0ÁgÆp6�¯9 ˜xØ,þð=c~†ïÁ}�� æðr¶q\‡õæ]ÏtžN3�¦sKê ¬ªú|ÿPW�¤V«%µzºg¦ž�‡¶§ÕU¥j©^ŸÏ;¼Þ’B`aaaaaaq×#ïõXXXXXXXÜ,Ñ·°°°°°¸G°DßÂÂÂÂÂâÁ} ‹{Kô-,,,,,î,Ñ·°°°°°¸G°DßÂÂÂÂÂâÁ} ‹{Kô-,,,,,î,Ñ·°°°°°¸G°DßÂÂÂÂÂâÁ} ‹{Kô-,,,,,î,Ñ·°°°°°¸G°DßÂÂÂÂÂâÁ} ‹{Kô-,,,,,î,Ñ·°°°°°¸G°DßÂÂÂÂÂâÁ} ‹{Kô-,,,,,î,Ñ·°°°°°¸G°DßÂÂÂÂÂâÁ} ‹{Kô-,,,,,î,Ñ·°°°°°¸G°DßÂÂÂÂÂâÁ} ‹{Kô-,,,,,î,Ñ·°°°°°¸G°DßÂÂÂÂÂâÁ} ‹{Kô-,,,,,î,Ñ·°°°°°¸G°DßÂÂÂÂÂâÁ} ‹{Û^_€Å½‡®ë$“IdYFQ$IB’¤½¾, ‹»Kô-nB4M#™L�FM±W»ÝŽ¢((Š‚,[( ‹Ý@Bˆ½¾‹»!ÉdMÓÌÿ-IBt]Ga-,,,,vk§o±«¢žL&Ma70DÞu!BTUexx¯×Kss36› ›Íf-,,,,vˆ%ú»†!પ·DÞÿ|‹€D"�¦iH’D2™$‘H˜?·¥a‰¾Å®`ìîu]Ø$ÌÙ‚¿²,gDŒã&“I€M‹›ÍfZXXXl�%úe%]˜u]G–å’D8×ïùþ\çÊ 0Ö"ÀÂÂÂ"…%úeÃ(Ðëïï§²²’ööö îv5¦…,Œ¶ÀôÂ@k`aaq¯b‰¾EY0ÄÖhÉ3òñ¥bäü‹ý�BÙ5Ö"ÀÂÂâ^Á}‹‘Þ{/„0Ãù;í-‡§/ŒëÑu�D"A<·÷–è[”Lzï=` þv¢_¨¨–ÓBÂ8çV‹€k×®QWWGmm­µ°°°¸k±Dߢ$ŒÝ}®b½BvúÛ én mö"  QUU…‚xø µµµ%]�Ãá ±±‘ÆÆFâñ8Á`�`0Èðð0ñxœªª*sPUUµ¯Æð p8ÌÚÚMMM¨ªjþ<»&ÀZXXX”Kô-L4Mcff—ËEUUUÉb�Ç™ŸŸ§¶¶–Ë—/—”“7¢Ù8�Nš››inn �š‹€ÙÙYTUÅçó™‹€ÊÊÊ};z×·"ªª’L&·\ì×÷baaqg`‰¾EFïýää$---f¡]±Ç™˜˜`vv–ÊÊJΟ?¿«wÜn7n·›ÖÖV„D"s0==�®ëTWW›‹¯×»/wÎÙ‘€|‹€ôáAÖ"À¢,Ñ¿ÇÑuUU3Âù¥ôÇ' z{{ ‡Ã8p ,wJù�ǃÇãáÀ�!‡Ãæ"`||I’2�Ç<×íôBlÛö˜o¹Ý­E€……E>,Ñ¿GIï½7È™bÅÏï÷ÓÛÛKuu5—.]bzzšõõõ¼¿SˆùN9†öx½^¼^/íííèºN(" â÷û¹~ý:Š¢PSScZïn'Æ{ÅV‹€ô ‚FºÀZXXXl…%ú÷ ÙÅzéÅb[åÒ·:ÎØØ?~œööö‚îÂn8òɲLUUUUUtvv¢ë:kkkæ"àÆ�ܼy3Ã(Èår•õ vº¸Èµ0qF$ {`tXXXÜ»X¢�±]ï}¡b‹Åèéé!‘Hðè£�RUUUô1òq;ÄI–eª««©®®& ÒÔÔ„Ûí& 233ÃÐÐ.—+c°�‚ sŒ0d.ŒH@(Âívãõz3º,,,î,Ñ¿G(´÷¾�ðþÒÒ½½½444ðàƒn2˹SîȲLmm­Ù^¨ªªé099ÉÀÀ�'Ã#Àn·—|¾ÝÜ\‹€7nÐÐÐ`þíeYÞTh-,,în,Ñ¿(¦÷>_x_×uFFF˜žžæÔ©S´µµmyŒ;a§¿6›�úúzêëë�[n�Á`�7n‡Kv Ü‹ ‚�zOv»=g$À#laq÷c‰þ]Ž®ë$‰‚�õ¶ìH$BOOº®sñâE¼^oÑÇ(–½œ²— Ã-°¡¡Hù‹€ÑÑQb±X†[ ÏçÛWFAéué‘ã>Ÿ•ô1ÂÖ"ÀÂâîÂý»#œoTç꬗+¼???O?­­­?~|[!Û¯…|Û�¯XœN'MMM455©:£=ðÚµk$‰ £ ªªªŒÂ»Û- [�3}f€ñ:°w#–èß…ìÄJ7=¼¯iCCCÌÍÍqæÌÓ¯�cÜ áýbq¹\´´´ÐÒÒ‚"Ã-ðæÍ›hšfBz»)äœùFk#äö ¸ÿn÷–èßElÕ{_ †è‡B!zzz�e™K—.QQQQÔ1îÆð~1H’DEE´µµe­¬¬à÷ûÍÅ™a´Ûn�¥FÒé…›éì ‚ûKôïÒ­taó”·B‘e™µµ5^xá:::8zôhÑ/…Š~>ºÛÄ"Û(Ȩðù|¦[ ÑBh¤***ÊzÊ•RØjŒ°‚X,f¾ÆXXc„-,ö–èßèºÎÊÊ œ]Ò±ÖÖÖÌêüô õRØN°C¡ƒƒƒ8jkkwÕùn¿’}dYÆçóáóùèêêBÓ4Ó-pnnŽááaœNgÆ"Àét}ÎÛ!²é‹UU‘eÙ,M�äš h-,,vKôïP²‹õŒV)Ç™žžfxx˜ƒšÎm;!ŸèÏÌÌ088Hkk+’$133õkר¨¨È´½Øéßnò œ1 ¦¦HUí�ÓÓÓ fܳêêêmÝ÷ªcÀ}ÈŒ…�±XÌ|�µ°°Ø],Ñ¿Ée¥«(JÁžùÉd’þþ~VVV8þ>N?N§I’ðûýTWWï«~÷rP¬+ŠB]]uuu@¦[àÄÄ¡Ph[·À½XDãt²ëMŒE€¦ihš¶e‹ µ°°Ø9–èßAäë½/fPÀÊÊ ===x<._¾lîw# …èîîÆf³qéÒ%\.—9r›Þܸq¿ßÏÐÐPÞ~÷{•l·ÀD"a.®_¿N$Ùdd|fn'…œs« ‚†m´ñóìt@©Åª÷2–èß!l×{oäL·ÛA !˜˜˜`tt”£G�ÒÕÕ•ó8;!]ôgggÈèØîøN§ŸÏG,ãܹs›úÝu]ϨrßíV·Ý¢œ×ìp8hll¤±±H-œŒ{6<º£m!×aÚTWWsðàÁœUîén555OÂÛMö¢¨.Ý¥Ñãñàñx8pà@†[ =‘$)#…âñxJZÜŽŽ�ìE€ªªŒŒŒPWW—‘˶ ¶÷"{ÿô³È ½÷¾ÐÉx�Þ7ˆÅbôöö�ÇyôÑG©ªªÚö8¥†÷5Mcxx˜ÙÙYŽ9b†ÝK¥T¡È®rO&“¦˜���íûIx»I¾�;én�† s0Äï÷sýúõŒÂbR(»±Óßã;àp82Z“ɤ �$ÉZXÜ“X¢¿�Øé ¸µÓ_ZZ¢··—††Ο?_ðî¶”ð~$¡»»€K—.¡ª*7nÜ(ê帎\ØíöŒ7c^ `ppÐÌmÇb1¢ÑèmëeßOSö²‘e™ªª*ªªªèììÌ™Bq8‹€­Ì•ö¢c =:füwv:ÀXXoµ°Ùlû¾.Ä¢,Ñß'äê½/ãÁ¦ª*ÃÃÃLMMqêÔ)ÚÚÚŠ:N±áýô±»'Nœ@–eÖ××÷íÀ�ìIxFn{||œééifff̰vmmmÙýï÷’R¹R(«««ƒAfffÂåre¤Œ:ŠRª÷wЦi"Ÿ�Qôg�¾H$æïfÞ-Ÿ‹{Kô÷˜ô~äbÂù¹�$‰ÞÞ^.^¼ˆ×ë-é…„÷u]gxx˜™™™Mcw Ù¥—ZÈWNÒsÛËËËÔ××SUUE `yy™ëׯgøß×ÖÖ–Í.øvïô�¿G9Ω( µµµÔÖÖ·Œ‚Œ¢Àt·@UUÍÈÕí¢ØèB¡‹kŒ°ÅÝ€%ú{ˆÑ~vãÆ Ž;¶#ÁŸŸŸG×u<gÏž-9O]ÈN?‰ÐÓÓƒ"çØÝBD¿Ð)|·I’̰vºÿ} `vv–ááa\.—¹(Äúv¿PNÑÏ&Û((ÝaÑp}ôz½n�»YL¹Ó:‚ôE€qßt]'‘Hléh-,î,Ñß#ŒÞûx<Îää$'Nœ(ù8CCCÌÍÍa³ÙèêêÚQaÚv‚½°°@__­­­?~<ç¹Êåê·×dûß§[ߎ��‡M1«­­Åçó%fwêN;Ò9yò$ªª ͑»YLYÎâAã~Y‹‹»Kôo3é½÷BˆŒêâb¡PˆžždYæÒ¥K¼üòËeÛ\á}#œóæMΜ9CKKKÞcÜi£u ¹÷¹¬o�¢@Ãõ®ªªÊ\ä³ Þ«±Á·[ˆt]ÇápPWWGSSp«˜2 ríÚµ²Û,u1»A¾E@4¥··—³gÏâp8¬E€Å¾ÄýÛˆ®ë9NcwÅçx�iuéö¶²,ïØM/Wx?�ÒÝÝ�®ë\ºt �Ç“÷ÆûØ‹ õÛ‰Ãá ©©É³h4J 0 Üt]Ççó™ãƒ÷Ò.x¯D?×g »˜2ÛfYÓ´¹ÞÎ6ÁôE€®ë¬¯¯› ùxMkkkQÇ€�‡°ï4ÑO'ÝðÆ° ^__'°°°ÀÊÊ kkkD"3Pˆ]p9®ëvQJÚ*—[`ö¬I’2<²Û*÷Jôsuߤß­E€Å~Àý]¤�Þû­ìsÓB0==Íðð0]]]9r$ç±ÊµÓ×u�—_~UUKjý+Dô÷CËÞíD–e|>>Ÿ�ƒÒ××g>äÓÛÜŒ@uuõ–óJa/vúÆ9wZIŸ=ka}}�`0ÈÒÒcccm•555»šÓχ¦iÛF ]dO´åÂý] ˜Þ{c•¿•X-O+++œ?Þ´—ÍE9Dee!�‡S§N•TU]ˆèÇãqTUÝ4Œ'�;y§_ttt·ÚÜ�ׯ_'‰PYYi.vZážíRw;(‡èg“¾xêêêB×uÓ(hnnŽááa³pnnn.¯[`¹)%°Õ"@×uâñ8±X Y–ùØÇ>Æ÷ÿ÷óøã�ïÆ¥[ÜCX¢_fJ±ÒÝJ¬WVVèééÁãñpùòåm{ÂKõ͇ÔkllŒ‰‰ Μ9³£|SØìv»¹¸]Õîû‘t»`c ^v^Ûétš÷©¦¦fODß¶³ŸÚGÆB3�›�ÙK†QP¡ßƒÝ, ‡Ã›ì®-,JÁýÉ×{_,’$qóæM9~ü8ííí%«Ðð~<§§§‡x<Î… 2véãGw‚±ebb¢è‰Æâ©³³“ÎÎÎŒÉnFµûVõwåŒ*dçµs…´Ýn7º®³¼¼|ÛîÕ^LØ3Î[¨ø:�Nš››Í�QéFA³³³¨ªšá²˜¯–¢9ý­‡ÃÖNߢ,Ü9OÉ}„nSU‡Ã±#Á�ÅbÄb1TUåÑG¥ªªªäë*$¼ï÷ûééé¡®®ŽóçÏozøÒBX(}}}$‰M ¸U ”�ôŸ§Ov;|ø0ÉdÒ|8g×l÷pÎÅ^ˆÓn�3WH{vv–‰‰‰Œ{•ÒÞ�j±ÓîÊ…®ë%çéÓ£M¹Ü —Åt·ÀôïÌnˆ¾ªªÄãñ’¦fZXdc‰~‘»ûÑÑQ„œ:uªäcaoY–9zôèŽò‡÷…\¿~�ññqNœ8Á�òúìd' ͹—.]*iW¹� Úíö-댇súHÜÝ®(–ÛY?àp8¨©©aff†‹/æÜͦW·§ ÙN¸vúùÈå‡Í{799 `Þ»h4º+ï7 X¢oQ,Ñ/�ôp¾±¢7|µ‹%ÝíîÔ©SÌÌÌ”å·ÚéÇãqz{{‰F£ÛFŒ¨E)¢$„`rr’ÑÑQdYæøñã; #s Ù;´P(D È(t3¢û¥`/zæaó½J²‰‰‰mïŠ9ç^‰þnì¸Ó]ÛÛÛ7TƒAsá�^P¹Ó{‡Kô-ʃ%ú�«XϰQ,Æ,z]×M·»¹¹¹²„Ósåô�âÀššxà�‚D¸”~UUéïï' òÐCqåÊ•¢~?×5ìäw ·|õF ˜‰r±Sö¶Šì¤ YºãÝââ"cccf¥q¿ ]0íµîn“]P944„¦iTTT°°°Àèè¨yïŒh@>3ª­‡Ã¸Ýî]«°¸·°D¶²Òݪ=óóóô÷÷ÓÒÒ‰'Ì/q9œôŒãÕ÷BnܸÁ�7Š.,v§oÌp¹\f;ÞNÍuÊiÎSH=€á†f,öB¬v“BóëÙŽwé ¦›7ošf7é‘€­òç{™Óß«óVTTpðàA<˜qïÒ»*Òï]! (£G?¥§,î\,Ñß‚ízï‹jMÓ6MiŒJáRŽ•c‡žÞëÿÈ#�àóùŠ:N1&?³³³ lš °ŸõrÕE‡½½½·¥àv‡¾Ký[äZ0�ãããô÷÷gô¹WWW›‹Ù;=§_ÊyÓwãé÷RѰìˆS! ¨P(dµëY” KôsPHï½,ËíôC¡===Ȳ̥K—r~y˹Ó�Åb<÷Üs%÷úCa‚­ë:×®]c~~~ÓˆßB�±Ók(n·—ËEmm-mmmwD=@±”k‘‘Ë.؈š ‘H$Ìêö½Ú™îåhÝ|çµÙlÔÕÕ™ó3r- ¼^oÆÊf³‡·'laQ(–ègaìî·³Ò-$§?33Ãàà ííí;vlËB©õé!Ìêõ'NÐÑѱ#߀|׉DèîîàÒ¥K9ó”Û‰v!×¶‘‚RêJ-V¼Ý;ýÝ8_zŸ{v‹›ßïGÓ4³¦¤¶¶ö¶„©÷Rô‹É»g/ ‰DFÚ) ò±�}Œ††’É$‘HÄÚñ[ìKô7B ª*ªªÛ;ëåÛ�«ªÊàà KKK9wÁÅ«‰}}}¬®®R]]MgggÉÇ2®g+Á]\\¤¯¯�ææfNž<¹åõ;ýÛM®ëÝ-€ýRÈWN²[Üæææ˜žž¦¦¦ÆÜͦ ÕÖÖ–Tضû%¼_,‡ƒ¦¦&ššš€TîOýÔOñw÷wLMMQ]]Í… xãßÈ?øAóuÅ`‰>·ŠõÒ§‚m÷€Üª�Ï(js8\¾|¹ ±ž…¦ r±²²Bww7UUU:tˆ@ PÒqÒɵÓB0::Êää$§OŸ¦µµuÛc”Ë¿?…5Ëép7ìô·;§Ýn§££ƒŽŽt]gmm�`0Èüü<###…mÆ ¥�²›v¸·ó¼µµµ|ðƒDÁ3Ï<Ã'?ùI¾ùÍoò­o}«,é@‹{“{Zô³{ï‹�Œ—.ÔB¦§§ÞTÔVȱŒªûb®Ý˜ÄwôèQ:;;™™™Ù•Ö¿|¶½[QŽð>ì?ÑϦT€»q§Ÿëœé"(Ë2ÕÕÕTWWsðàÁŒÂ¶©©©²¥NîÔ�þV¼‡âСC¼ÿýï/û9,îîYÑßé œô<|2™¤¿¿Ÿ••Ο?oêJ±áýd2I__kkk“øÊÙ`ˆR0¤»»›šššœ¶½…£Ôk¸Ó(¦ =²t;ØË�;[‘«°-;ubtÔÖÖl¼_ ùJÅ(ä³°(÷¤èoÕ{_ †À®¬¬ÐÓÓƒÇã1{ÔK=V!áüÊÊJ.]º”-ÅT'’$¡iãããŒ��qìØ±¢  ýýTÌ·‚˜¯ ‹qíÚ5fggKžP {µÓ/æœÙ©“X,f¦NPUÕì 0îW®ãß�;}�ÇSöãZÜ›ÜS¢oôÞ«ªZt8?Y–QU•—_~™£G�ÒÕÕµ£cm'Öé·GŽÉy¾búë·cbb‚x<žI(†{q§¿颶¶¶FKK ²,ß–y{µÓ߉øº\.ZZZhii1‡\‹€©©) å{o¤NŒÊö½2Ú­){ápØìõ·°Ø)÷Œè-m‘H„ººº ~"‘```€‡~ØiZ*Û‰~zúࡇÚò|åﯯ¯›f Ù‘„bÈ'úº®322B04®ªª*ãA]ŽÁ?û§ÓICCÃm™p'ìôó!I��ÇÃ�Lßû@ ÀÒÒcccØl6ó»‘L& *¢-º®ïÚbà ï[”“{Bô�Þû¥¥%–——·m¡Ë‡áeo ­)ÇŒë|b½ººJww7�‡Ë—/çá�†÷ _‡ÃAggçŽ*©·ýxÿv»�úúzêëë�TJ. &�›‹¦šššMé¥bÑ4 I’vMô­�¾E¹¸ëD?½÷Þxèìd2ÞÒÒ}}}Ô××g´¬_ðríô�㬭­ÑÝÝ�Ûí.º Øðþââ"½½½´¶¶râÄ ó�UŽ.CôUUe``€@ �Q��OôE1۸Ο?�‚@ `VqkšfpíÖ@œýN¡þÆ"`/†ßìV5ûvçÌU¯ãp8L»`H-šŒE€±h2ÆßÖÔÔíu¿›ï5 YÕûeã®ýl+Ýlg½bœït]gtt”©©)N�:E[[ۦהSôUUejjŠááa<ÈáÇ‹~HÞOogΜ¡¥¥%ãçåv#I±XŒ_|»Ý^ÒRS§Ó™QŇ3În·g¼•Z‹p»ëÊYä¶U=€1×n·c·ÛY^^ÞѼ€bÐuý¶§e ­#p»Ý´µµÑÖÖ–ñ™Êe\SSƒÛíÎû÷Ú­}£kÁ*ä³(w�èÒ{_èN?‰ÐÓÓƒ®ë\¼xqË/\)‘ƒ\!H$Œ��•dîcPÈ"Ä(¤K$[¾·r´þ% ÆÇÇéèèÈ;lh;r¼y½^¼^/¦À&'' ²²2#w»S»¹ÀÈU0<_Ù®!‘H�L&-Ñ·(w¬èëºN"‘(ÊYOQ„›Fáp˜îîndYæÒ¥K·Ç”šÓ7Fï.//óÀPQQÁÍ›7‹>N®ë�Ì_ºOÿ#�<‚ÏçÛö8¥ˆíêê*W¯^ÅçóqñâEÊ"l;uõ3¶íííèºn¦Œ›ÑÆu»½ð�ë»]l%À…Ô”ê°Îx·#º�Ë.x||¿ßϵk×H&“¦]pMMÍŽÒ'ápÀ ï[”�;Nô�p¾Q�_Œ³ž!„é¡8Ã�¦½½½èÜs)9ýôÑ»—.]Âår‹År.FŠ%[ô�N€bÝõŠ ïâpøða|˜D"aFÖÖÖL±3¢ÅVpÃ~�²WN€½ê¸Ý —ËEee%‰D‚ûî»Ï´ 6¦�Ť˜B¡`‰¾Eù¸£D§“ñŒ‡�ÑS;88ÈÒÒ÷ß¿¹j/†bwúÆ£³³“#GŽ˜×“k‡^ éï†jì“}œBD)ÝÔ'»±¢»+އƒ¦¦&šššPU·Û�Óé$011�,Ë©€�¦_ö’RwÝ;ñ¸Ssú¥žWQ”-킃Á`Fú$»3`+Œ"¾ýXŒjqgrGˆ~¾Þûb0 kkk ãp8¸|ùrÉÝ…òišÆàà ‹‹‹œ;wn“ p¹Dß8Îàà �@€xÀ4')ö8Û½¯h4ÊÕ«W3L}ÒÙ�;ýíÎåp8hooÏHƒA³öÂãñ˜ €�:ºÝî|w¹OÅÔ‹ëÛÉ~«›nÜÙÙ™ñ¹š››cxx—Ë•±H�Èn|û¥øÔâÎgß‹þv½÷ÅK’$º»»Í^ø�< )ä …Btwwc³Ù¶\`¤‹þNˆD"橃RØ.¼¿¼¼LOOÍÍ͜Μ9³£ c[ ¶‚7npãÆ Nž<É�Š>F±×±_Hs !LG7ÃÀx˜‘€Bîÿ~(ä+'Ùõ/½ôuuuhšvÛüv³u.¥Fél6Û&»`# ðË¿üË,,,àt:yòÉ'yÓ›ÞÄ… ö¬ãÄâî`_Š~z8¿¿¿Ÿ®®®M®qŰ²²BOO�·Û]¶ö—­vúé¹îBêvbékŒ©½yó&gΜ¡¿¿Ç÷\-{FÀúúº9 åýý8eO’$***¨¨¨àÀ�¦™‹ßï7C¶n·;#�½Ãݯ…|åÆˆ„@ñóJa/wúåˆb¤×™ ógögü�ÿñ?å/ÿò/ …B<óÌ3<øàƒe¸j‹{‘}'úÙÅz;�Œ711Áèè(G�¥««‹çŸ¾,.z�{§o´ÿ)Š’3×�ïXÅŠ~,£§§‡d2ÉÅ‹ñx< –Å7?ýëëë\½z•ŠŠ .^¼XÐNãN ï—z®t3H…l q3v¸>Ÿ/c‡ wßN?›ìêýÛá°×…|妲²’®®.þþïÿ!ýýý9r¤ì籸wØW¢ŸËJWQ3Ÿ_ ‰DÂÜ™>òÈ#TWWå³Î5Ž•L&Íÿ?77GIíÅŠ¾ßï§§§‡úúú w½rÌHßé)Š®®.Ž9R°p”khÏ�ˆÍf£¡¡Á,ØLO-\𦱴´„Ýn/xa¸ö›%înùì…7žÓ/–p8lZeK’ÄÙ³gË~‹{‹}!úùzïKiÃn¶ººšË—/g ý(§è«iCCCÌÍÍqß}÷ÑÔÔTò±¶#=¯~âÄ 8�ñ0/—ØêºÎµkט™™)©¥ñNÜéïÙÃ]ÖÖÖ¸zõ*~¿Ÿ©©)\.WÆÀ Ý(vÛï£uËå ëúm&”ÍnÕ¤‹¾…E9ØsÑß®÷¾˜ð¾‚ëׯ3>>¾¥Ýl9üò E!�óÒK/™­k…ºùeSÈu%“Iz{{ …B[ºë•cXŽžŽÅb%¿§íDee…ééiªªª¨««ËYøv§îôó!I’iÓzòäIÜn7+++ÓÒu7ŠÝöJôK½öRý4MÛ“B·Ý ï[ö,ÊÍžŠ¾±»Ïg¥[èÎ<‹ÑÛÛK,Ë[h¶¿ülB¡~¿ŸŽŽŽ?¾£‡óv;ýÕÕUº»»ñz½\ºtiË‘¥; ï§�½páBɲ|ÓÓÓ ÑÔÔÄüü<###TTTlê�¿�…|{!ˆ°¹z;‹™©€ééiSØjjjJ^TþN(´ ÒníôC¡�Õ²gQVöDô³{ï·›Œ�Çóoii‰¾¾>êëë9þ|Þð^9Âûº®›á|�ÇÃÉ“'wt<ØZ¬ w½¡¡¡‚ÜõJ ï !˜œœdtt”¦¦&"‘ȎݳÛ0)ZZZâÁ4íHÓ ß†‡‡I$ø|>TU%‰àóùîÚ]6.—‹ÖÖVSܲG¼:�ÎŒT@¡óêï´�~>òÕ,//399ÉòòrIóJe·vúáp¸$·P ‹­ØÑO¦íÌvòòéºÎèè(SSSœ:uж¶¶mϽSÑ�D"twwpôèQK>Vöue‹µ¦i °¼¼¼Éæv+J 﫪ÊÀÀ�@€‡zˆh4jœ•J¶èÇb1®^½ `ÎH$@îx¿ßÏêê*###ܸqc_LÆ+'…ü�ÒÝܺºº2Œ\ÆÇÇ ²²Ò¼/UUU[Šì^8Þ.ïýôz€õõuÓ'!W=@MMMÞûT*·£�Ï¢ìYx¿Ð/ÈV9ýH$BOOš¦qñâÅ‚¿;}çµµ•'N°¸¸Xö¢@ƒp8ÌÕ«W±ÛíE¹ëÞÏ>�Óé$�—µÇ>ÐÝÝMcc#§N�Ê{�é=ð3339rEQÌ¢·ÁÁÁ ¡óù|w¬/y±‚˜� ˆÇãf* ¯¯ÏÌs÷ÆívgÌcØ Ûß½ðÞßɼ€RÙ­ð¾•Ó·(7{^È·¹Dz~~žþþ~ZZZ8qâDQ+lY–Íf¡èºÎðð0333œ>}Ú4 *g}@ºïïÀ�E·þÞ71Ùç)—±Ž®ëLNN222‰'hoo/é8é¶¥‰DÂÌåö÷÷oºRsÞ·›rÔ*8�NZZZhiiÉÈs/--166†Ýn7ïËíöÁ7Þß~h¼]þ»µÓ·rúåäŽ}MÓfvv–3gÎÐÜܼ£ãB4¥»»]×MƒrôħËpò›™™áìÙ³%·þm'(BFGG™œœäìÙ³›îc9Úþt]7ÇÕ>ôÐC¦h§Ÿc;r½ÆápÐÜÜLsssÆ|qq‘ÑÑѵ¿ÝÉí�¹òÜFWÀÄÄáp˜7n‡oK„d/wúùΙë>­­­™Q€RüŒT†Õ²gq'°g¢_Lÿ®¦i¦Ó�,Ë;j�+Fôéë룹¹9gD¡œ=ÿF!�Ýnß´¸(†í"‰D‚žžb±Ø–i‘�¶ý5ªªòš×¼fËÔD!Ÿ�|בý7rÞéíoÙNxû© p7¯EQêêêÌ:�—_~ŸÏG<g``MÓ¨®®Îˆ�”ózÒkvn'ÅŠ¯¢(f$i;€­êŒ÷Zî�¾ ï[”�}¿Ó·ÙlÄãqžþù’œî²)$$Ÿ^ xúôiZ[[s¾®\;ýååe–——ñx<;j“ƒü»ôÕÕU®^½ŠÏçãâÅ‹[î`vÞ÷ûýfk¡,Ë;üS Ù9ïl'Ÿ�ššš?8¶Ú¥½ñGŽ¡«««ìmÆœƒ±±1³…qnn®¸‹ß⸥’î„g¤�333f·®®ŽÚÚÚ= íï•÷¾$Ix½^¼^/fË›±8ÄëõfKû¹4*÷÷ûN;rÕƒÁŒzÃ$+‘Hìh‘› +§oQnömx}}Ý\#IRÙzUó‰þÒÒ½½½455qòäÉmtFÔ ”ÊèD"Aoo/áp˜G}”™™™²D ²£F�Àââ⮵ýišF?�@€‡~˜êêjffföÕh]Y–©®®¦ººšC‡‘L&Í(Àµk׈Ç㬯¯›í_åwg³Ÿ¦ì¥·¼Á­bIãÞ$“ÉŒT€á¯Pêùv“ݸ“žN2Kkkk,,,ðüóÏ—4/`+ŒˆL¹¦‚ZXÀ>ÜéŽmÃÃÃtuuÑÖÖÆ3Ïø JM?V9Âû’$™ãI‹‰Zd#Ÿ0 !çúõë[ž£\;ý½ ;Üm˜àøý~3m‘m‚S ûu§ŸY–7U»Q€¡¡!’É$>Ÿ�ŠŠ „·5Ìo|Þv£ .[-ú ©È1 …B¦Y•…E¹Øó�~zØáÇ9xðà¦Q±åžŒ—L&ebb‚“'OràÀ�’ŽeÌ ØN¬C¡ÝÝÝ8ŽŒMö±vú“É$‹‹‹Äãñ¼C‡¶#ß{RU•þþ~VVV¶œôgãNÙéoG¶ Žá‡o r»ÝÞÛ‰Î�´Óߎì4I$! 2??�ªª<ûì³·­cÂøÌîÅN»snU°•?€Çã1ÛõöS›©Å�ÏžŠ~"‘ ¯¯�õõu³,ùü÷‹Å8Îüü<.\Øq‘Ìvb=77G?=ztˇÃNwúëë릷}CCCÉ‚[ ¶aÙk,^òµuí÷œ~©äòÃ7B¸###ÄãñŒ¢·ýòо;îôT@EECCCœ:ujSÇ„±8*G·J:{%ú¥¸ñåóæÝï~·é¤øüóÏóè£�îJ]‰Å½Çž‰~,ã¹çž£ººšË—/çý@—ËÇï÷ÓÓÓÀÃ?\–öš­úþ�I|³³³ÜÿýÛvìDôggg «« Y– …B%'ýZ S(–––èéé)ØøNïƒÍf£¡¡�††€Œ¢·‰‰‰ŒTAvÿû�Þ/æ|Š¢lê˜È^ •ÓGazz`SÛän‰ïvìæX]«GߢÜì©èº“+&§oØÛF"‘-CÒ垎722Bmm-/^,¹Âv;±6Zå‚Á`ÎQµ…'éÑ €C‡•,¹þ¶é‹–“'Ošé!kkkøý~3÷]YY‰ªªTTTìÙîv’=/‹™©CäÒ ‹Íwï÷�þv¤ÏQ0Ú&ý~? ŒŒŒàr¹ÌÏŠªªe�’lG¹ŸÏ|X¤ûâ¹o¿ßÏ�7˜��enn.#÷]î¡&·›Bî«Ë墵µ•ÖÖÖŒ|÷ìì,ÃÃÃTTTlrÁÛî|wÒN?ém“F*`ee…™™’É$ßýîw©ªª2?3;uPÜMÓvå3¹Ÿ‡í!˜ŸŸgeee¯/Ũ®®¦¹¹¹ ïø#úùrúéqÇŽ£££#ï›ß©è§ïº�B­�>P·ý……úúú n•+e§ …¸rå æbi§�颋ÅL�‹/âr¹ò ŸÃá ¥¥…ååe|>ÕÕÕøý~³À˼ºº:ª««Ëò@ß‹¢ÁBÏ™�ïNo}KwÁ3EÙqöBôo§÷¾1RÙØuž9sÆLƒ¬êjÝÔׂ¯ºWÅ�²^Ûn†÷÷kµ¾!ø���»>œÊbk C¬ÅÅEZZZ¶ý�;Bôm6ñx<çÏ ƒŸP(”×!.��òÓÿœN'—.]bhh¨ìƒr õÇerr’³gÏÒÜÜ\Òq¶ÃXTæAé³Ê±Ó7¢/ œ:uª$�NßÕ‚ç÷ûÍ péQ€;Á²t§u é­oùâ÷ĸç·[ô÷Â$G–åŒ(‰Ð5¡CJü+B[&Ð -Tãq'¨ª˜@±%�VÊ{η‚Tü5ïV-A$)ÉF{·1êO šÚi±»6à‹‹‹466n»Ýóœ~!lµ3ƒôôôàóùÌiu;9Þv¤›à9rI’ÊV˜.Ö‰D‚žžb±XÑC€ Ý¡ !cbb"ç¢b§•ó’$¡i¯¾újAÑ—­Ž‘M¶à…Ãa�€Yïr¹2*ào·{1”C„s ÄYYY!099ÉÀÀ€YXº¶¶–±ØMöb´n®…†Mý&.åÁ­¢#QŲK]# é ÄNí#ÄâÿŠîýoÈJqùùÝÜéïÇ𾑖»Ø÷ Æß"™LîoÑ/”l‘N÷ë?zô(���E=`Š}Ã]onnŽsçΙÅP¾A9ÆÎzee…îîn|>/^,iÐvb�L&ééé!‰l¹¨ØIx_×u®_¿Žœ–X …ôñ{½^¼^/fn×ï÷gXânöÞ+v³#Áè‚H´´´Äúú:×®]3'½ £R‡mÇ^LÙË}±‚’x»úH,q²¯Æø$H¨:¸¤WéüaýÌ{XHèz·úô÷«èì‡ï’EŠbþwœè'“IúúúX[[Ëë׿Ýñ ´tw½‹/nZÝ–« ½7þèÑ£cw‹=N¾÷fxô{<ž¼ÅŽ¥†÷‰W¯^%‘Hl+øÛ틹#·[__Ür|3Šív{Fà^ð2w:�455122ÂÅ‹‰F£øý~3"#†~¹ªÞogN?ýœ²,#é£(Éo¡¨ßAbÆü¹ÐA�Ôedtœi:m“!©Â±®>Æïfyy™ëׯ›Ÿãþäò«Ø­TÆ�P½_,sssƒAb±²,ãõz9pàÀ_œ{'qG„÷m6›¹‹ëî²rÛ�/ù(T¨—––èííÍ;“^–å·¬hšÆÐÐ÷ß?MMM%+ŸèÏÏÏÓ××—‘žØŠRÂûkkk\¹r…êêjN�:ÅsÏ=WÔï纆��îø¦i«««øý~ÆÇÇÈèƒ7Zo'·{ä¬,Ëæ¤7cX�#‹•Í ovú*nÇ"JrI�X1¦i 2à�7Òh:8Ò.Ñn]òÓÙÙ™á�`Ø©ãþø|>³>ÈêÓ/Œõõuñx<!˜™™addd“ÉØÝÆ“O>ÉSO=Eww÷^_Ê�±Ó—e™h4Ê+¯¼Â‘#GJÞl'úéùîíüæwêî‰Dèîî6ßÏN«u·ê�azzº á?ÆqŠ ïÓ:Ä¡C‡ÌÂË�ævË%Äéƒo ³~jj !n·Ûì (uAY{a‰ ›Ù‘ÃÇï÷›^ø¥ŽÅÝ­<÷VHúM*Ïàr� h+áBbuãZ@ìR*¤oÜ9ÇÇRÓoEò²½âñ¸Ù5100€ªªÔÔÔ�H$ˆÇãe­c0 4ï6Ñ?vìXÆÿooïàÿ|æKÜüÞm[9óÚ»ú¹Y\\ä#ù_þò—YXX ¦¦†û￟'Ÿ|’‹/"IŸÿüçyâ‰'víöš}/úÉd’ññq’É$�<òÈ–¦4Å (JÞn£ˆ®w½�ò‘„––Nœ8Á×¾öµ×dïô³ßO¡‘BwúF—ÁÔÔTÎÅN„»iÛÝß×ׇªªæ@F ªªjWv­·k§_èô¹t]×7Í{÷z½»Ü|g]×o[úDÒæP´¯á�ç8A²�˜¢©Ÿ“üM¿—ë`Êá-Ïãt:inn¦¹¹9£ˆÔè$Ýr¢b)„B¡»NôÓùğÿâÿ‹&`þ[ý�:~îO~š×þÈ£»rÎw¾ó�$“I>ó™ÏpèÐ!xúé§ Ûÿò]¾ﯮ®šíqÆüér°ÕîÜh/Ëöê/åXùH· N÷é/G'€‘‹7\Ë®^½JeeeÑE�…†>Ù Šôñ¼¥r»DQ–e•••:t(c0N__Bˆ²ší…µp±÷2Ý0É‹k´š»Ü­ ÞnKõ¾Hâ:¶ä�õk¸m*’$!é$Í—uò‘‚^f‘z<ÆÆÆxøá‡‰Çã›&*ºHÊÅÝÞ7øî¿¼ÄÇ~쩊4–gü|ìÇ>ÁG?÷«eþ••ž}öY¾ýíoóú׿€ÎÎNy人ºøáþaógüÅ_üŸøÄ'˜žžæàÁƒüöoÿ6?ù“?i{jjŠ}èC<ýôÓȲÌ[ßúV>ùÉOî(U»[ìË�¾áv722ÂáÇihhà…^(Ûñ³Å5ݶØn€b…ÚÊP(´É&¸�ÆuÏÎÎ288h†ÛKi—Ëw-†¡ÏV�ÙãyKe/ÒŒcìè Ë×\æ@¥<Ìáö»ãíô|v»�¦¦&ššš6írÓ ÞŒ"ÉÛ‘Ó—Ä6õ$}Ä*%‚¬ „Äzñ”A—k‹úã;b·Ûñxüi.½ã¡²†ú�NŸ§žzŠ .lJW½òÊ+466òéOš·¾õ­æ¹?ÿùÏó‹¿ø‹üÉŸü o~ó›ùâ¿ÈOÿôOsàÀ{ì1„<ñÄx<¾ó�ï ª*?÷s?ÇOüÄOðío»l×_.ö�è'“Iƒ<øàƒÔÖÖ‹ÅÌIvåxX¦çôUU¥¯¯�ÕÕÕ¼žö[QÌN?½r>—¯@¹Úÿ®]»¶©½°òíôéííÝdè“N9D?´e[¾–Ãh/rúå¼—Ù­’FÁ[ 0‹$E!‘HP]]]>\±‚¬�"‰› t$}�I’‘Dœ¤V�]Šl´è�yi’\Ü÷Åø¾f‹SöÂ1Ý@i||ÜŒ\nU/�FÑuý®ýþï±|Ó¿õ ,Mûéÿî÷¿átÙÎk³Ùø›¿ù>ð�ð—ù—œ?ž×¿þõ¼ë]ïâ¾ûî3Ÿ•†¥­Á'>ñ Þ÷¾÷ñs?÷süò/ÿ2/¾ø"ŸøÄ'xì±ÇøÆ7¾Aoo/ããã´··ð·û·œ>}šW^y…‡~¸lï¡ì«ðþÚÚÝÝݸÝn._¾læÄŒ/”¦iei)2Dßa·Û]r7@¡;}ÃØçàÁƒ>|8çCx§¢oäïzè¡’Ú ¶*4ÒgΜÉkùX.Ñ¿]Y¨(c”oü�¶ÓÏG®aA½½½¨ªj~Ó½JJ�ˆlɧS‚¯­ ‹9`AмŽMYÝ42©J¾\¤­E5hòñ¢.ËXðç[Ôä2PZ]]ͨ—0¢ÆØàp8 p׉¾‚‘¾Ñ‚^ëŸ –ýüï|ç;yÛÛÞÆw¿û]^xá¾ò•¯ðñ�œ¿þë¿æ}ï{_Îß¹ví?û³?›ño—/_æOÿôOÍŸ···›‚pêÔ)ª««¹víš%ú¹B0==ÍððpÎp´!úåšž¥( Ñh”_|± öµ|l·ÓÏgì“ëX¥Šþêê*W¯^5«ÿwšwÎïóVVV¶œ^˜ýû°µèK’TÐ=ßÏ£usíx³gÀ!ݺº:3¤{§ïô·Ãåráp8hhh µµÕL�ÌÏÏ322‚ÛíÎè}/$„+k£Hú’XD€@"†Ìu2àÆ®D�%•T?ëšl|¤ÓËø� M~ ”­;urazqeY6gv>|8#z444ć>ô!\.’$qíÚ5Ο?×L™œššB*ðÑT×Rž®l\.�?þ8�?þ8ýèGyÿûßÏïüÎïl)ú°y‘žþ�Úêûµ®”…°ç¢¯ª*�-ÝÛŒ/U9Lp4MczzšX,ƃ>XrøÛ ßN?‹ÑÝÝ�¦i9�}²)UôgffäðáÃtuuñµ¯}mÇÂ’Þ�D"\½z›ÍVpDän ([š���c³ÙLñ¿�¿#§Ÿk"ž±0JwM4^¯7wºHLƒð#‹‘T…>I$T 8‘ˆ I*:dóßs°…vê¼�¤ãç‹~ŸåèÑÏŽýÏÿù?ù›¿ù†††xã߈ËåâÍo~3¿þë¿Î¹sçvt®½fii‰ŽûZñ5V²º¸EÝ… ê8óÚ·åšN�:ÅSO=¤þÙ:sòäIž}öYÞûÞ÷šÿöüóÏsòäIó÷§¦¦˜žž6wûƒƒƒ¬®®š¯ÙOì©è' žþy3¼ž¯Øf³íXô�žxMÓp:�;|ØZ¨�ÝÝÝÔ××l�´¿—Ð�¤8©í|ŽÝþV×J'ªëß�’?zµÕû,ç.\’$Μ9Ã�þè�ò…/|�‰‰ ^yå¾öµ¯•Í-q/y衇øÅO‰Tõ>dþ™6>2üãŸ.{¿¾ßïçÇ~ìÇø™Ÿùî»ï>*++yõÕWùøÇ?Î;Þñ UÁÿôÓOsùòeœN'555üÚ¯ý?þã?ÎùóçyÓ›Þľðþå_þ…o|ã¼ùÍoæ¾ûîã=ïyò'bò½þõ¯7ßï~bO?E‡ƒ#GŽÐÒÒ²íCi§v·FñYkk+---\¹r¥äcå»®ôN€ãÇ�ÓÞÞ^ÔÕBÅ:�ÓÝÝ�ªª›¢;‹kà÷ûæÄ‰ùªB0Â÷[‰öúú:===H’D}}}NáÛ‹Pøn‘ntÓÜÜÌ«¯¾JKK ~¿Ÿééi$I2^WWWVs ½Üéoþ�YA³ìx�G¨h;j.ŒŒ\÷ÔÔT†_BK�‡G P@$ *!ÕI,âq7©>ýížRêub­¤÷¹Û¾ûv»�Ë—/sùò岟c/yí�<ÊG?÷«|ê—>�QÔ×p Žþñîôé{½^}ôQþø�ÿ˜ëׯ“L&iooçøÿù?ÿgþè�þˆ_þå_æ¯þê¯hkkcbb‚'žx‚?ýÓ?åÿðù…_ø<ȧ?ýiÞð†7©çÔSO=Ň>ô!^÷º×e´ìíGö¼�¯­­­ »¢(¨ªZô9t]gllŒÉÉI³ø, •­J>]¨�¼w0,i.@¡¢oäïkjj8}úô¦ÀNÇâêºN("™L–ÔÑ�N®ëX\\¤§§‡öövœN'Á`0CøÒ‹Ânwüv!Ër†9P¶N9Í�öbá”s§/ØÔo# ?BªBQ$íYtåÒ­\wµÌÑÎ z2Èzx‰å Ÿ�¡‡›]T{Ö±;Ö±ÙâH88R‹\ù,‰ä«x]ËHèÂo"RvqŸ‰‚LI/²âƒÝ«kˆþ�–â*†×þÈ£\zÇCôwÿ\�º–š]uäs:�üÁüð°åkÞþö·óö·¿}Ó¿ðƒäƒüà–¿×ÑÑÁ¿þë¿nùó'Ÿ|’'Ÿ|²¨ëÝ-î˜xQ);ýx±NïØn\m©áý••®^½j K9f†ÀišfFAyä|>_Æ ¢tá;|ø0ñxœ¡¡!Âá°9›Àè…¯««»ã'äå[Àä2 fõ{±æ@E/n…Ь½Œ¬_Ã,sׇòQ4årAŸk§Ÿ éW¥I¬ è×ÐÅ*BnAÑ®!4åu {6®E\ÃYñ²Ë†¬O#´jrŠxBc=b#葉2‚:B—‘e ‰(á�÷P�ÊGÞøß6À‰  ÐScø¤â¾»Ö„=‹;�=ýBó¶…îô…LLL066¶eN=½ï'ÂfÌ�JÊ{g³•èÇãq®^½Š®ë\ºtiÛ襄÷�Ѱ¿¿¿l±XŒ«W¯"I/^,( ât:©¬¬ÄáppüøñMQ€ÊÊJ3 p7E²I¯~ïêêÚÒÈX¸ÝîœíEE�SÌ"ëC©¤�Ïšˆ#écHr;BÚÚŸ>ýœÙb(p#‘–;qdý!·#äf„>…,’Èb��á,R%èËHÄÑloAó`� ¹<8°Q_E�¾€½Š BtMC–udIÛ˜¬cGP�Ä©y{*©‚?7Br!¤ê¢vo§ …î‰�¾ÅígÏE¿P ýd2I?«««ysêÆÃh'…�éƒl³r~'äêù7æÔÕÕíJÀVå(¢“$‰õõuFFF¨««ãÌ™3EíŠ ñÊðûýEp;�ä\4ˆ$±„$T„T½!‚å‹~¤£ �ÑÐ<:‚£žfìrîóle´¼¼ÌØØN§Ó\ æ@Åîô%}Ðo >€ä!#ésy{ÑOíô³Ì�äCHÚM!�¼HbÄ"Є�Œ4’n÷ƒP7†çŸe$!µeW¬ã–_EST$[%2 $=Š.R‹N-)£j ²F–=Ø”5@FP… ?BøÑ„Vôßw·¦ Þ­¼{Ï#ú6›-o!ŸáæWQQ±m/¹$I;‰»²²Bww7>Ÿ�‹/òÍo~³,Ùb===ÍÐÐPÑó }cábÔ<”»@×u8zôhÉã�s ¤ÓéÜTWî(€¤ß@Ñ®‚oü‹ ]>„®"ˆ,F�ÔY †®I-*!7#is 6R?B ‰„äC—s;@Êú $"¨š…j$V@N o\¯Mq‘”ºÐôy„¶Ž$t4½�{-²Ü"€$¦RW÷ç»]ÈgaQnö\ô‹l³•°ÅmÅ —)¥0PÁÍ›7Ê(¤+Çt<¸%Öº®388Èââ¢9  Ù¥¯¯¯såʪªªrNÜI€1nWUUŽ?ÎÁƒK:N!ïcW¢b Eë$„ܵño1d}!×#¤Â&±myø�÷ôwÓÏñééïæ|Í—zù·¥^¾øè¯â´¶ÈØÊhnnŽH$ÂsÏ=g.†jjj¶¼BnÝfîÈSÿ!UЗ߱NÒPÔ/Sí¹Ž$EÒ(ú7�äe4Ûcèò}HjIZ!ƒdG³Q’„ ð€¤ ‹i!ùÐlRaþ\ç~4šÑ´I$b\@ °£K�86$Ý ÄQé$=L$ª ëH²B�o‰¤2B…¯­¨HÑníôC¡PÞº ‹RÙsÑ/EQ2 ¿ µÊ¾ví ¡éB�WŒPkšÆàà KKK› éÊ5(G–eb±/½ô/^4ó÷ÑP”ÈZŒ Ÿ·'õöv×3??O___Þ9¥îôUU5§:Ó¸JÙ¡gGÒû¾ �Hb ÄzªZÝüG'²>‰VàøÕ|¬H1þçô÷ò¾F~à¥Oð{ÇŒ õÅŸÓ0²Ùlܼy“C‡e Å©ªªÊi$¤Vtù4²>b‰ÔÎ_F—O!¤üu+²Ö�,– E›h�ê²DY¿†®ŸDCÈb!5lÜS²vIŠ£KÍHBES.¡+Ç7÷lèr+H[Ž^$*„:ðz'6ê’¤úø½Ñ‚Y ØQ$oU^_5 ºN4AO™› 0Ûû]ó3bøàçÛÉ—kH6áp˜ÎÎÎí_haQ$w”èùs¸e «( —/_.º�©˜�¾áä'I—.]Út®�ÄãqhiiáÔ©S(ŠÂôÐ ÿð{Ÿç¹/¼‚¿uŽÖc-¼û·~˜GàÜÞ̾­D_ÁØØÜwß}·f= Ä §®ÛëlE$áÊ•+8�N.\¸À‹/¾¸§Ž|ÙçéQ€©©)dY6™÷kãoZ(¤ Àvη˜DÛr L&¿5ü9_>Í:ñC%�Ë(ª3ÚþŽ9B,Í /§9�ý!„ܶ‘ß¹!µæÏy IF PäÈ­—¼ �Å d} !5™!�BÇB Ë'@i@—;7Ú÷ |R;ºHâu/“ª hB"DªuOCbŒÔßΆÀŽ,æA{M¹„$¹ñ¸üà>ĉú·q0á0ï‹Ñ.™>E1»ˆVÓ´²)D"‘‚&6ZXË%úFNaa�¾¾>ÚÚÚ8~üxI9µB…zii‰ÞÞÞ¼6´;Ýé‡æææ¨¬¬äÌ™3H’ÄÍ‘Yþðg>Å�«“™¯nŽÌññ÷ d�œ|øÿéo�º–ڜד¾¿pá••¡Rm)ù ˆy@¹a´èð~ àêÕ«›îS¾cl·“/wEþVQ€ÉÉIB¡N§Y–i¨S¨v9Rù|i#¯*4 „0*Êw€‚ë¬õ;_÷ðôsœ­êà߸Ìùš®¢Î—}/].Wƽ0†âd›ÕÖÄçómÿqíE}Ä*u•vIŽƒH‰¢ DAÊÌͧQtÛ·Ò Û¿)$1�¤]GÑž1†×µHH8Ðñ"!#‘’êR#ëèžjÔ® ä6„T�jû>�*q:¡¥¥…–––ŒvÉ……FFF6MQÜ­ð¾Õ²g±[ì¹èú`7 ù†‡‡™ššâìÙ³3�‹e;ÑO#{êÔ)ÚÚÚ¶|íNŠÓÓíííÄãq3´þÌ?¿˜SðMÝÈvèÀÀsc¼÷Ð/¤Ê¬¸ø#çùÙßÿ)Ô‡¹rå .—‹ .ÜÚ™èKH‰¯"‰u„ÜèHÚ5«(Ò}èza¢of·-îÔp7mx³£ƒƒƒ$ B¡SS~ê*£´4ÌPQQ…ÛS‰MŽ#ät¥¸ú„@"LLKÐäò¡l´„iºN¼„ˆ�ô¬MÑ38ÅO·¿†w·¿†ÑÐw…>w…úŽ:ŽÕpþMgxë»ßœ‘”Ô$Lµ`ù\¹IÇi«c]ä®–6H7 ÚªàðN¸£( ^¯—#GŽl|ÖÎ^½Fp~„DbÙÞ†Û{€šZ�ÊÊí«àçc+|òÆ×¹º:�êì^Þ×ñZÞÜxY’¨ÁÍá¼ÇÈǧ§Ÿå;ËÃ,&ÖÑÑqÉvÞÖtŽŸìx�¹¸0(¶e/Û( m�k„»«««Qä²>²ÑëîC EîGBE×<‚f{=BêD×;‘õaM€XÂèòC…uEˆ¶ä—Q´¯ƒLµÛáHE”ä†èÃvR²/H-,`�T ˉ$)hòItåTÁ÷Å´1¨+‰˜m»W®\ÉH¡ÔÖÖ–äÊip¯´ìiºÎÕ±–WÃÔû<#Q-ÁøGæã«ÈHÈ’ÄRb�?ºþeÜŠƒSr—¤|�1TQz-ÈDtŸ½Y²×UþeîUªÎTà¹À-Á1o3õÒ=Ü%I¢²²’ÊÊJs·kD†††H&“4ÔÙ8ؼ„³¢‡Ã†Æ1–×£T74 H˨¶7›]ší5 ÊÈbð#ð )Е3Û_ŒÐQÔo#k/oôðË¡ ±†„†lìŸ9AªCâ –�J�*’§°sæ¡¢¢»ÝNGGõõõfºÈH‘x½^sP]]]pÒð_¸ÛEÿé«£üá?}›Å•�ùo�Õ^~íÇßÀ›8º+ç¼qã/^䨱cüÃ?üd``€_ûµ_ãË_þ2/¾øbÎÍK"‘Ø•Ú�½`ÏE?ßÃ(Ý«ýÀ�,,,”­R6×î|vv–���¼Uí…k+Ò§ðå ‡Çq¸´ib~|±Àw„é,ª»@މÍ�Õk‹!þâßá…/¼ÌGÿþQ\öXfô@褪ž+¶ìP(Ä•+Wðz½Û.Âî”�~>rÕøý~&''ÜTÿŒˆùø*6IA6 †�H �ÏμÈïøAÎÓLCG+ÿëæsD´-f¿oƒŽ ˜ #vI!)4þüÆ×SIA‘d¾"I°Uóïí÷—å^Øl¶ s H$‚ß?ÏZH� ¢ê TTT�T=èƒ${rZNªD³}$CHU[¶âe#‰yd}!Õ"‰Õ�ϵ}#o/ÒÖ®ÆgFF `¬‚%ÖR5ºÜŽf{3B.­•4£O?;]”H$LçÄÁÁATU5�kkk©¨¨Èû|¹ÛEÿé«£üúÿâ¦ÈåÒJˆ_ÿï_äã?ûƒ»"üÿñ?þG_ûÚ×̢̎Žxà>ÌoýÖoññtuuñþ÷¿Ÿ±±1>ÿùÏóÄOð™Ï|†ßø�ßàóŸÿ<7oÞ¤¹¹™÷¼ç=|ô£½£lÁ÷\ô·"™LÒ××Çúú:�<òssse;~úN?=L}îÜ93|W(…òišÆÀÀ~¿?çôºìãüÐÏ¿•+_ï+üB rZgãVv*Ýß¼Æ87Í[Þ룮i…X¤‚¦>¦ãòÖ“Ô ëñM¿·´´DOO�9g ߃k§9ùýh­›þp6u(ŠÂ«®Y$06F ‰¡E&¢ËÄ%�Ÿ8p‰·5ŸãÇ^þ3;Øñ 0_lŒ¶?Y–·œÂ—-ú§.§±«ŽÅ‰[ó¦�leN¶¨ Ó•Ô/Izæ 8â³!ÛÁáY‘©¬vð†w_âô›5„3sBž1ÓÀQ¼Û…÷…Û. n×N«†‚ç£|y¡›…ø+ø¡–óœ­JEhrEú¦VÑイšD–dóØI‘úýæäçQ„ĵqÞßõl’²#Ñß ˆŠ$2¯$oQã8d+É›·’;\9^æ÷GÿS‘et6I¡Ë]Ï/y+Ǽ¹‹guùØeÜr6{€É°ƒúÖ·³l&Xefz€–º~ê}k¸Ý2NWØÎ¢Ù^[°Ã¡d}H ¤Ê�ݾJîo„á­oO ù‘+Ñ¥&„íTÙ säË圸²²’á™`x$“I:;;‰D"w­#ßÕ±™Œ�~6X†¸:6ÃCÇv6Ï$�ÑÑQ„œÏ?ͼ„]V�‘€[±³šˆb“Jê{& ‰¸®2 г:Ååº<^’ ]xAºE�ÄŠ˜Fv¢Îí¦®TõñÈ$Z¤ŸÞžJö[•ï5.ܶd}I_@f Ð@èÉ’I,§"†ÀAR«±‚]ÖR¯Å† � IŠ"¤tåRj€O9ïm¦ì¥{&|ýë_ç _ø?õS?Åç>÷9~í×~�£G�ò‰O|‚·½-ÿ,†;…z_aŒB_W(GŽA’$yâ‰'6ý|hhˆššÓÙ5;Òòâ‹/ò®w½‹ßýÝßå-oy >Ÿ�Ï~ö³üÑýQY¯s·Ù¢oÌL·Ùl9ïSèw*úªªÒßßÏÊÊ 555ttt”|,ƒ\ÁéçÉØç!]ôW—×Y¾égi&ÀüÄRþß#‡ð»di©då ›’:èõ+Ø] •=ó\ûÆuZÕpü�?ðSUT75’zDáx«98Å<×¢/„0#7‰DÂ,†Ú4Žuwúk7‰jI<Ê­÷$I.ÙÎr|�©ˆŸƒžÜ;ÇGkó¿ü /¯Ó³:Å—æ»±I2 ¡¦þPÈ{,ø�V8‚T j�^„H&Ñpq+ä.!¡ ¡êkjtÛã¦&ì¥_l‰8"mjŸÍfÃVوץ¦õAÖC©ˆXdå+4Úþ »sYRA"•ÿ§ ™%@ ÚÞŽ.u¤Ú÷´¯!t„H¹î��Z„Ò�  I,¡Ù.m;7 XŒ!Få¸c³Ù¸ÿþû±Ûí<û쳬­­ñÍo~“Ç·Ÿlx§ðÀ‘6«½,­„¶ j5ÖxyàHq5ÛQWWÇã�?Χ>õ)>üágäõçççù»¿û;ÞûÞ÷n¹Ùxî¹çèììä·~ë·Ì›œœÌùÚýÌž‹~<ç…^àÀ�;v,oè[’¤åõC¡W¯^ÅétrèÐ!‚Áàö¿T¹,‚¯\¹‚Ýn/x~<¤Þ£ÿf�ÿõ±fôÕëÌO-1;¶€Ð¶…M¹þ„~k%°CÝLÆ4s+°°Ââä×^€+߬὿]�Í!˜WpØz8p¶™úα;læûÉ%Ú†àCêÞ¹}Ãqј‚¸×ØdI2ŠãÒÒP¤RL[�¿5p+ÞP’f§�//ô  =÷Ÿ"#g“KÝEÖ Ë‹ŠF\KâVf€&4ìBƈ$7Òë‰%¢Z‚Õd§lÏi´Y«T€XéV4H«©YöàóÙ¨öFqÅþ7°†®Û5eíKMK¢IìJ›ú¿R Bò¦Âõ"õÝ“d=Õu"µ�äDÈ�©¿°A™Ãú€¹@/·#_(2«û«««ù‘ù‘²¯Qd™_ûñ7ðëÿý‹›ž[Æ'üWì »Ò¯ÿßþÛãÒ¥K¼å-oá¿ü—ÿ’Ѳ×ÖÖÆïýÞïmù»GŽajjŠÏ~ö³<üðÃ|éK_âóŸÿ|Ù¯q·ÙsÑw¹\<ú裷laó°�ûùùyúûûiooçèÑ£ÌÍÍ•­00}‡nØö¶¶¶d¼º¼Îxß$KS~V«|ý¸D"ždÍÊ)ø¹dÁù:/EÄÖRKE5™ª½êçw~âÛ(6]Øì:µ-KÜÿ†!}ûyêZk¹90‡Ö.hkmC±Ýwc’ ¢(fÔÆø7ã?š¦‘H$ÐuUUsF¶BÁâä2Á…UœkÁî´§vÔ† ‘ÄÂqԤʫ_îáê3=(v…#§'hêj ù`gµá³U°šŒàQœ)§D!ˆëIŽx›isÕls%)Ž{[8ìid8´¹ûdsaæí|ãØq]Å­8p*v¢zA\‹#I߸Áçf¿Ç?Ï Pe÷à�mœ©<À�µ=Bƒó–˜gïô…Ü€.Ÿ@Ñ¿‡ �À�$V]yÀ ¹+Ú¿!±‚  YN !  EŽKT`CVIêveYv¢K�Nj ÏRe‹¥Ž+µ"„Œ,fЕÓ©t÷έ0žå^ †B¡»¶ˆÏàMåã?ûƒ›ûôk¼üê�í^ŸþÑ£GyõÕWyòÉ'ù‰Ÿø ü~?ÍÍÍ<ñÄüÎïüNÞ‰¦ïxÇ;øð‡?ÌÏÿüÏ�ÇyÛÛÞÆG>òž|òÉ]¹ÖÝB{])EÊø �ËøÖ·¾Å¹sç6µºåC×uFGG7Y÷ÎÏÏ3>>ÎÅ‹K¾nƒÉÉI–––¨­­åúõëœ>}šÖÖ­C‰Ë3–¦– .®2veœx4Bð—®°|s‡Ó’„–PI&Ô U0D=ó1“Ü—oýK…„° ¤µÌóg×ì)¥£’”ÒT›ÓŽ«ÂIUM%ö*w…‹Îãí¼é'_Ç‘ó]·~mc¨O.t]gaa�ÁÁA>l:ÿgD}r=l±$ßùÇyõ:ñpY4wʼù]^š;œÌNÕðò×"Œ]�# 3=4K,CGGMh(6…ú¶ZÚO¶qòÂQ¼?ÔÊŸM}�¸žD ŸÝÍïœøaŽy·ï`0Xˆ­ò�îÿAX»Õ)#á”SÆ:f `Ó×À(äØ=Ñ—‘p)v|¶ ÖÕNÙF…‹ñ�)ø^Y¢Áá`6Gµ/õŽJVÕ(‡=�ü§£oÇ¥¤R~¿Ÿ±±1}ôÑ´·GÑ^Ù˜ÜOõË+ Ë)ƒI,cOü16íÛ©D‰UÒ“W‚* †®;ʼnÚ�¥0’\ËÂÚcØ”U·G‘$?2º|Íö¦ŒC¹ˆD"¼ôÒK<öØce=î׿þu~ó7“¡¡¡=¯kÉE,c||œƒ=è,›½pä»)æo²ç;ýb°ÙlEíΉÝÝݦk\zßk¹&㬭­ …¶Íß¾0Lïw®Y‹23:ÇÊâ*M˜ìŸayÚ�® bÉÍýñp«õNNÓxYQºœÊ}ê`< edô„@;éD é(ÉTQŸ¾;{F}ãV&£I´„J,G’¡º±ŠÕù³cóüÀÿõ8�üÀ93šL¨ÌŒÌ Ũ¬õÒr¸ Y–˜œœd||œûî»�††sçoD ÒÿnÙµÝO÷ÓûíAêÛjiê¬E‹�176Ç7ÿ¡’ƒgªxú³Ï1>�@ÓD×ã$bIœnš®#+2’¡•TÕpÿ3×x¬½Ž?~Ã{xzi€åxˆvw-oj8M½³ð¶¯¸–Ä!ÛøÅCo῎~!uÝHØd}#U`æõsõdnYÕNYþ˜:‚„®H†pÈ6~²ý2ßW§ñ¿gžás *µv;^›Â|Þ×ñº¢oMH�ñ?§žåÿ0ªÐhtTqªê×ÖfRçÜÈñŸ÷u1¼>GX‹§Æíf<ëó<øseJÔ Mh dTÔò†ú“¸¤,%t"º O ÅA›I] ‘dh}Ž*{’,ÄWo]F¾â6ÉMÊs:6õÈں܌&_FÖÆ‘XOu<àDÚhfL ÎÑT¦ û¤ŠT7„¢ãpû¨©iÁ婦¡¡¿ßÏÐX€htŸoÁ4Á)ç@(¬G¿B¡Ð]kÌc±÷ì Ñ/´»Ñ7ÆÔsäȺººr~ÑK’“Îââ"½½½ÔÖÖ�F·õfž™£û[,L,²º¼†S ždgb¼}Ü5‡ï‹2ð’‡èš‚b ÝÚuÃF(?’u޼?Å“}(]ÓÑ5 I–X†ýÞ „&Xž ]�òÄ/ý}SL]›¡±³§ËÎZ<·¿û2Çí¼÷WÞµ©øqui�o}ö9žýß/˜[ArI?\O¼Ë†Ëé@’à;�!8›ä‘ _,�ÃA»ÓÁz05�MÎ ºßÈKMG º@vÈèB k:v§�D4�Ћ¯�ЄÎï�üú×nb“dIæf,€‚ÌÛkîcnu™Ú†:¼615ÁB|•p4¶ý�ó‘þ1/²@!- Íñ³Ýÿ/ç}­¼²¢oÔA°QÏ�žßO}×ÉPÊ}0íD9wú¹.WÌ!éèr[j1 @Rz»ú¥ á·!ð ¨G—N ‰)di!¥öq$±€®<@\­ÁfËì�F£øý~�(ŠbÚ%çš™P,»9V÷nÏé[ìûBô EQ³Â;écj·šú–~¬RwúécwÏœ9ƒÍfcxxxÛß|q„Ù±y’±Dêü6 …«¯Í&#|2úºv�Ü2vt‹qcÐM2‘Ú¶JÈŠ@Û¸U’’,#)²,!t�¦ê] ÉÒÆ"@l¤J¹!›ÿI�ߺ·Z"õ¿Õ¤ÊäÀ4Ÿû¿ÿ·Ùncþ•kÌÝ/X9*��*,ê~-ŒðÆö3¦pÄÂq¾ð_ç™Ï½@(F’%"§�¬Ö&±-&ñÔØQ™dX%äPyÕ=ÃÚ3~ZÚiíÒYİÙ%l6M$£:Ž v§ 5©¢ =5�M$âIl65-Õ¬ù×9ûÚ(¶â콫S\[ŸÁ­ØMûZ—bg5e :Ë¿WNóÕÄM¾³ZðN_H•©)�ú:²¸�¢�H�²Ùõ ‰ºÜ‰�º€Ðlß�¬§FBK5èòq�èúbÞ…F®™ �@¿ßÏôô4@F �6[]×w%¼7[ðZì=ûBô‹™f—K\�6¹íln³�e†úÅ5úü].—9 ¸ DZ»ìx«\DV#`–Â…y³Å^® '²œ*ÚK¨‚©ë.Žœ SQ©SÝ•äìÅш›…±˜‡ËŽÓí W‘$ 5©as)TUx±Évœ4MGM¨„WRùÓ“Ž0øÂñH,Õê†D"–@Vdd%5ºTè©kO¥'$´¤Ñw/£iú–¯%4¢áh‚Õ†ëm6œa ‡f#¾žÀgw!xzi€Gj£H2+‹kD×£hª†«Ê�ªÜO¤L…u’®ƒ,cw؈Û¶Ô4øX ¬Zuð£ï­çô™§ÿ!Lïswe%k�ñh_]%Î ²#UÄW×\GóÁÚO¶qî�gh=ÜTÐg#·l'¡'Y4‹ßlx'ªÐqI6¾§Í’$Ÿà—Ù‹7ë0k³�ZM¤Ò6IE“ªÐÑ4?56Õözæck¬ª¸jqÈ6dI§R^a6Ã'¯aKÞ@HõØ¥G�åíwªBjF—� hßDц8Håû� UbÓþ ¡AWÒ¼Ò%ºrvÓ±Ò¿Ç’>ƒ¬ a„Ü”š �å·ït:iii¡¥¥%ásffÆ‹k,|>_ÎgÄníô­ð¾Ån²/D¿P²E_Áõë×çÔ©S´µîà”në[ˆè/,,Ð××G{{;ÇŽËX¨5ðø*¨o­¥ùP3+Ëëhía’€D"¹õn_‡Óªªðúþ8~¾ïý ÚN¯1re‰àü*¾Æ*Ž=|ˆŽS­ \£¶±š#G�6›Rò..©kfØÞ¨­‹j bZ§lçM¾c|%8¤ÜîĦ?þV†\6&¥‘q†�CéÓ"ægY"¢ƒ]^')@Cß°ì•©²¹‘ÄÁd—ìàÑšF„dCSxíÏ Ë�o’„¦¼[ò‹À:vÀ�.·"¤NdqYëÎý-0D_Öº±©_N¡ iºtÕþ£¹~‹Ë�ðù|ø|>:D2™4£hšFMM�¹0œÜv«�/=éÓ¢Pî8Ñ7rúÉd’ÞÞ^B¡�f/ã˪iZÞ‚!cccLLLdôùgk»�¾Ûëâ胇XœZ&0dab‰d"‰¦k9ãT±˜–ÐÍ�—¬È¸ž7s“‹´>Îüô›‰„bô|{g…o�—èZo,IE¥w¥‹õàÑp‡ÓŽË㢢ª‚ÐZE–qWºX[áô8¨ðV ë:+Kk¨ •DTÝ(�Ëu37R’ÀáµcÓøUUÓ°I .·�Š*7«‘uœºÌ`O-�Í4ª§óÔÆ—¯DR•ù#IÜ_Lý�*¨µ¡’€Ú ™Ú«­C'IÐr°»«!Õa÷À¹7§þc�TUúû±¹e:»:Í¢Rãs¶•=p>^ Ž1šÁcsUãè².ÔØ+x›ï O‡ˆæœWh^|y7Ð7Žë•¨‚EM`“ÂràLu'/¯3"‰ÅÆ;½œöØA’´a“¯QáÈom h¯ ±¸S¾úhHb¤Rå�‘¼¿o^³®c“£(êÓ T„œJ ¡!‰(Ús¨ò; :–ÝnÏ‹ …ðûý,,,022‚Ûí¦®®Î4�*7áp˜C‡•ý¸°OD¿Ðð¾Íf#�gŒÞ½téRIU¸…Øú ‹p8Ì… ¶t 4D» €©¢0™ºÖžby6º ‰ ªÇÛ ›p0=8Gd-Be�‡cæ‡á8öÐa^óÃ�0Ñ?Í�Þ ®|£�¯‚cçâªt\X¥åP#~ä<³Á›\ºp�ú¶Zžûò‹àüàxœ‡Þüu­5èºNcG=ýÓD×£èšÎX÷]§ É3cóÔuT£†uœ'žJ7í'[A¤ òdE¦¹«‡ÛI"– ¼!‰£©©ªý-‘ ¦Å‡Cq �ëø¢.ÂúBÊüF©qáph|Ý}´ÈÍ,-- i~¨–Ι6®¿:Åêò²,áûªBåuAã�d=Aê�аh'ÓÐ’*Bμî䦿‰&t¾<ßÃWç{™[÷Ó({xϱ×SUU…®ëÄÔÿ6ßÃ3þ!¢Z‚û*Ûy[ãý´ºk6%t•çü#ô¯ßÄ.)<\sˆžÕ)„€ Å�Ëa'¡§®EŠ$ã’íœRxI»¹ÃÒ½Ò…ßFª4ç°&RÍ >‡��ªf6äÇ®†ˆÎ4 ­Ë­>‹¿2D�ëEÎT:ir¥‡¢úÆ´»í.?€¬÷"ä6$m£7_’A„�´y�íèòÁ‚Þ�®ë8móH"°Q°�¤µHúˆèFË`áH’Dee%•••tuu¡ª*Á`¿ßÏââ"š¦ÑÝÝmFÊÑ_oôé[XìûBô EQB¡/½ôäðáÃ;ú‚åkÛ …B\¹r�ÇÃÅ‹ó.,ŒTÁv-<ŠMáìkOrì¡Ã|ÿx#±xŒîïu^‰°:%UY�¯PWSGÛá|õU\zâ!Ú�·™䕵^ξî$g_w’c¦û[,Þôà­öðà[î§åP7_™Ys‡8÷Ž“<ðÀY–é:ÝN×é”1ÆsO½ŒÓíÀî´£i:Š"áô8¨k¬¢²ÆÃ¡³TTU0?±„ÛëRVÁ‘µ(jRC¶É· ü ëà´?�$§z÷½µ^NþÈYnÎ, ­i4|9�úF…D£�¤M"–HðúÖÓü`ûC8e¨ªJ àЙ.úž¤ïkìͅ±Ûí$W’$þú&‡Ž6YÓ,¬à­® ©³‘‡Þz?'=²éïð™ÉgøâÜU’É”iΜáÏÆ¿NR¼¶þ8Ÿ¸þe^ ^OÝ'$¾ºÜÇË«7ø�£OdXïÆ„Ê½þE×g7ÜúàKý4:}¤Âäq HNÅŽ¦ê8;B³bH °¦FIwäWh»j¹ • € ) ¦HØ‘‘% ±Qg  ˆëPé°óº&!%Ñù&V×R»^û²J£7�Cš&=‚§ÂƒÃé@fM¯$)·½I�DM: ò²îGࡦªø¥ hÊý']Ocn9ãg¢Œ=ª6›�††P…x<ŽÏçÃï÷sýúu‡¹¨©©)i8˜U½¿wH’Äç?ÿùœSøºººø¥_ú%~é—~é¶^W9¹cD_×uY__çüùóeÉym•‹ŸŸŸ§¯¯�®®.sc>ÒS…ö8Ý"±0ƒý´jáÔ©Søo|a˜—Ÿù’"ñð÷?À©‹Ç¨¨Üzgròâ1Z�¶°4µ @C{¾†*B¡š¦ñ /PSSÙ3g¶½.›Ã–Ê©“*Æk8PÏÌÔšCÇW_…¯¾Š¹ ÔµÖpì¡CVpy\$щÌ=G‰8© :‰Ž­Y‹"tINþ)vg³‡æ�b´.J踃 ›ƒÊE™7ÍzÑ$;ó‹~.=rŠìxmÆ=·Ùl466ÒØØH¥âcæå%*«*±{mDÖÂ,ßXaæÆg^s‚7ÿÔë8x¶ƒ¶#Í8+6W`ÏÇVøê\/zB¥ÆáÁét"Ëñuþyæ%œ²�Wƒ7p)œ•÷úÆô¹/,wó ‡Þ‚¦ièz*Z0°>ƒGv¦ªô¥Tî~*ê'¦ß ÝKHÈ$°É ¯«;‘*q^SwŒo-_#¬Å7\æeŸ¯hs p8\Ð,’»Mèt&XޝSï¬ä\mWÎqÕåbqq‘�|ä#|ùË_faa�ššî¿ÿ~ž|òÉ‚,Ù_yå•;¾Èr_ˆþv_„X,Fww7±X ¯×[¶"—\…�£££LNNrß}÷ÑÔTXåvúN¿n޼ɵk×8zô(��©Cï·™˜F×u|M•<òØÃt�:€«ÂIÛÑœº®óúw]fö”ŠQ3ªá”lÄ"qÖÝI–²qh­ Uר9PÅý_o¥þl _b�Í�ܦž]'¾ÁYkç¦m ûD˜ŽƒÍ¼¯sË÷°¶Âáº%ÖŠ¢PUYEuu5‡:sÿýgX^^f||œþþ~ª««©¯¯§¾¾ž……–nΧÂÐöÌȇ&tI­8R6ƺNH‹Ó“©QÀBGGðR`ŒG7<擺†,¥Ò†Âǵ”I�WqRí¨`5%)´ÔpÉÆ3�!ž ¥>Ú~+°oóÜïYæ¼w™ˆ®ðöÚ :ëüÖäE’BFCÚUoÆ-ièÀ‹kÍh"å�'K>%Ž ˪Ýü} B"µ\¹år¯#�e.ÿ®ý š$#¤Æ-ýë…Ü‚&§9�ÐV ¡ø0B*++M3œtA¬©©I ž¤ Údž†¤O# � MyMy4çù¶Â¨Þו‡IJõÈÚµ”«ŸÔ†¦œ©ð!]Åœ3_ÍívÓÖÖF[[[Áæ@Bˆ{b§ÿ­ù~~£ûï7ýûb|�ßèþ{þë¹w—]øWVVxöÙgùö·¿Íë_ÿz:;;yä‘G¶ü��}ìcüùŸÿ9_ýêW9wîܦð¾$IüÕ_ý_úÒ—øêW¿J[[ôGÄýЕõÚËɾ}!Œ��qüøqÚÛÛ 2Á)Ã}}�+W®PYYÉ… J* Ü®mÏþ“L&¹xñâ–+ùRg¨ªJ__kkkœ?žW^yeÛÂÂt$Iâü›ï£ýx “KèšÎÐä ß÷ã¯ÃåreŒ½•eMèÜô„hw5‹W°4 ºÑ‡²bÅ�঴J]“—÷ÿ—Ïé‹'˜Œ,“œTq+^ì5 ‡Ïu232ÏZ(L¼BçÀ]<þÖKTTe†`C+az¾5ÀЋ£èB ©ëÁ�� ȃj25”¥®µÖ ?=z”h4Êòò2KKKŒŽŽp®±‹âKø“ajI&©k„µ8k�òXÃ)¾²Ð˪!®©Ød!¥öÉ^›‹ÏÝ|‰ƒ 4º|<\sˆ™}ecÁ�Zu£M/)4fbA4¡ctÅG´OÍ~�†¾ñ³LŽ»ƒØ$�5ÕHt­ós­}ü?sgˆ ]�3ço—uBš�„�©¶%7vñ‚°nÇ-I¬k6ÄFñ^ê÷e Ë­H&YQS‘ »¤p¨¢’ßèXÀ«¾$xÑ” ¨öŸH ÉÙ!‡#CðVVVŒ��300@UUÕ­(€çÇ‘•$ÝðÕo.zHNzŸ¾�¢X¸ŠéÓ/Ĩ··H ﺛsúšÐù£k_ÌûšÿÿЗx]Ó©²†ú½^/^¯—§žzŠ .ä5`BðK¿ôK<õÔS<ûì³=ºõ¨ßßýÝßåãÿ8ø‡È'?ùIÞóž÷099™×v/Ù—¢¯ª*ýýý¬¬¬ððÃS]] ”2žÍf#Ðßß¿ãÂÀ|m{F·AUUUÎá?…g+¢Ñ(W®\Áf³eä¥J™šÜÐ^GC{Bf¿:µi²�Ùõ DªÝP’Sýþë1B+›Œ�õ‡jù¿øCœ¾x€Z»�ÍÉš¥Î᥺ÑGU}7W–q)v~äÔ÷QaËüÆÂq¾ðç_ãzÏžªTUt`.ÈúJ˜½“4¶×¡k:Á…UÚO¶qìÁÌ6'·ÛMss3‹‹‹x½^:;;Y]]å±ÕVþUaQ]E–R†C=�ütçëhtùø‘Ö‡ù۩ª¸¨´¹9éme>¶BßÚ4orùx{Ëy^ Œ1 ¢H)Ï~U¤$9ª'Ò²ë·ý3±À† Nn¾8ÈÕ‹v¥BžB’¸\5Ç#Þyþ~é8³ ý¡¢8Ìc¬i)1¶¡#¦E€KR évà”S¯�ê·ŠÛ4‘@ 2nY¡Ãíã?4>GƒE—N$V°iO#ä:4Û÷oûÊvä“e™ÚÚZjkk9rä±X ¿ßŸ' Püwp·Üñò±“>ý\æ@ßûÞ÷øìg?K0ä§~ê§xâ‰'xë[ßÊ¥K—¶�ëq'јÈéçb!¶Jw`‚ëÊ׺h³Ùø›¿ù>ð�ð—ù—œ?ž×¿þõ¼ë]ïâ¾ûî3_§ª*ï}ï{yõÕWyî¹ç8p ªõ}ï{ÿîßý;~ÿ÷ŸO~ò“¼üò˼õ­o-Ûµ—“}!úéÃõÎétnú°oç½_ º®‰Dƒœ;wŽÆÆí«�ó±ÕÝ( � hB2ç ó 4dfv4!áµ9¸¯ªƒû½~šAÆcÕ³Ùp*‚1õY4åq�ò?6¶óÞw¹\GÜ,®„I¨5^7>On{í½ýr Ü1Ì�>üáó¡}ˆÚÚZþãü�|ï{ßã]ïz?ÿó?Ïoÿöo—áŠ÷Ëñõ²¾®ÞùÎwò¶·½�ï~÷»¼ð |å+_áãÿ8ý×ÍûÞ÷>>üáãt:yñÅ©¯Ïmè”Nú‚ÁãñPYYÉââbÙ¯½\ì Ñ7˜ŸŸ§¿¿ŸöövŽ=ºéKlxï¶ÎE"‘ §§‡D"AggçŽ6‹µQ855Åý÷ß_ð9ŠÙé�ÇŽ£££Ã¼'Æ}ÛÉAãÁ½´´DkkkΔÇkëSaû‘E¤„ÆŠc�Ú# ¼¥í~Î6Þôú×ÕŸÀ%Û¹º:AXMPisó††Cl^0ÜjIÓ‘ªNœ²†[V‰é :: é©E€SÖ©³W°ª)¸å�. Åź#˜a÷ÈDu‰�é¤ÂÌBr#âl÷Ø(Ô{6GŒâ·ååe¾öò½³!⺄Çí¢«¹ŽGNàÑãí(iO!R–Ö»a‰›�Ýpä ‡Ã¼ûÝïæCúº®“H$Êz޽¦ÞYX½B¡¯+—ËÅã�?Îã�?ÎG?úQÞÿþ÷ó;¿ó;¦è?þøãüÃ?ü_ýêWyÏ{Þ³íñ²Ÿ�…Ôwí%ûBôu]gxx˜ééiΜ9“Óõ ï‡ÏGz¨½±±±lŠì¢ÀtSŸbòs…ˆ¾‚ááafffrÜR?xB4M£««‹™™FGG©©©1 ⌖•îZÞÛþZ¾8ôß O`ó8qþìýy|dwyå�¿ï½µo*•öµ[­^Ôûnw 6‹WìnCbbˆ ‰“ðË $f¾a†$$™� �� Y †�°Ûƒ·ØãÛ-uK­îÖÖjíK•Tûz·ß¥[.í»Zm×y½0-©T÷ÞRÕ=ŸÏóœç«•±T„ŽØ»\UÓGïD‰JwrÔ·�¤’Æa²Î ¤É‡Ía™•î *6§—wîѿߟ«®ÓùH(i~8r†—'»Éh ¥7·U䆽{‡Ã˜F/Óíç‚¿—dC2K()n`�{n»gi*B7£)X%3²¢!Néæ5]GÑ4L3·•ïåɱ6bj˜™Q$�ÐÍü$´%«»O”òT¨žŒ¶¹¼þ,:�Ò$RÚô÷¶>u.>“�¤ne—«Œ¸’¢?9Á8Ùr땸J(³…wû§9+ z]l$ë�¿0–š²7ìv;6w1/�äé®0É´‚Õ$M¤™ …é% rr_cn"ÀxŸ_«;ý|¤oÜ3DQ\4<ìZÃ!ßVÊ­žKü¶"ù¶nÈùìÙ³‡Gy$÷õÝwßÍ]wÝÅ>ð$IâW~åW6ä<6 ›‚ôE!‰,J�ù~ù+ù° ÓÞÞž+µ_¼xqÍ4Yí »Ý¾¨©ÏBÏ3ò§ Nœ81ç̨Q†_IO?_°·mÛ6I&“øý~�]]]ØívJKK)..fd`9‘¢Ø[ŒÅlÆ.YèŠ�ÒŸšàžêc(ªŸu Ó1ʲJ‰Å�8Ï®pÛ�-œy²�É‘ Å•^Â�(’Ybûѹ{}tuu±wïÞY#—ãé�T„GG›i� â2Ù°ˆ&†RA¾Ö÷3à†’�x½^Þê=B]}=OŸ£-زJ}ÒÁ®¤‰ÎL¥¥¥”””L{ZD'};xjü<𦢣£æý ’ª‚=aâ]Exk±‹ÿyáY”Y"�õ)kf=ÿ'ú¼êýÙÏ17432»œ%¼¿æzþ¢ë?�5·É†€€¢«¼ñQo�pØŸšsfÓ»` ªåìôg"‘–ùñk¼|iUÓ)õ8P4‹EBÖÎ_Üa6™())¡¨¨ØxÒ_�À�D"�ÅbY‘˜øZ�$ˆü÷Ýï™S½oà÷šî\óyý‰‰ ~ù—™ßø�ßàÀ�¸Ýn^{í5þò/ÿ’S§¦[4ßsÏ=|ãßàþûïÇd2ñK¿ôKkz.W›‚ô­V+×]wÝ¢$e|¨EY–°Å¨$ qèСܬåZ EQ$ ÑÞÞ>g(Ïržg>Ò�Çã477ãp8�2X® Ð(‘ÎìAv÷U__?Íott4[Í@¦×Á¡Ù¨²!J>‹‹�Ä?t°ÇS;eø’EOlŒgýI…�:»�w–ï£Ö>[éZ·»†·Üsœ—t†¾ ƒ€€Ýmãú÷¡ñÐôÑ>£�2<<Ì‘#GrâOÈæ|èΆúf⌤CxL6<&;&QÂe²1œ òÄX+×û¶çn6[¥|dû;Qõ©»® fÛ���¤Óéi‡ÃÁ¯Ö½…gýˆèéYuøm–Ç£!:¿Ê{^æêâ|~h7²&N)þÅ©n¿ñ¾1þ?ûDnQFA$=U²ŸûÓ²´÷œ?åù‰DÜ&ÛëíTÝÎ+ñ&> Ž‚žDjQMïF—掷š�~ßxˆÞÑ ¢$b5™0›%ÌHÄS¬˜ÐE6·—“'“ˆÇrb@ g‡;Ÿ/ÀZc=Êû±X §Ó¹îç~µqså>þï¡ÌšÓ¯°ñ{Mw®Ëœ¾Ëåâúë¯ç _ø===ȲL]]ùÈGøÔ§>5ëñ¿ôK¿„¦iÜÿýˆ¢È{ßûÞ5?§«�MAúK… ¹¾þR‘N§sýûn¸a–íZôËt]'�N Ù¿?ÕÕK7™ Q‘eyÖ÷�gÏž]ò‚b9¤o(ô�Çç öfÂd2a±X˜œœ¤¦¦†X‘Hf`G,Ã@h«ÕŠÝnÇmµÈD Ë J,ÙêÍH*ÄCïÎ$(·zÐÑ鈎’üZý�x-Ó«‚ LüV. ¡i:µ;«¨ØZ6íüTUåüùóD£Q®»îºYã��Ÿáç�ŠÍœ&+¤t¢rŠ¡T�z{IÖ_ÝlÇŸŽSR™§ÿ¾±!G*»ví"�34>JûX/™ÎvÊE¤‹Ì˜q V™ :fMç�úóÜ^Ú‡M›*Á+·ûL49’<*#¤HØE�ïúëHéùd’-Ý'5 §¤b5©¤U)×ã}u±t¢Hi2Íá+HTÛ}DÕUAD]EÁMÚú±ÜÝRFõ ¬f§Kf[fIDAQ5L’ˆII+J6þØíÀj1c³fµµµµ¼ôÒKTVVÎ9àóùVd‡»Ö£¼o�þ›7Wîãm{6Ì‘ÏjµòÙÏ~–Ï~ö³ó>fæÆóÞ{ïåÞ{ïÍ}}åÊ•Y?€ÍŒkŠôay»óp8LKK ^¯wÎQ¹µØé«ªJ[[Éd’úúúU>Ì&k]×éë룫«kYñÁK-ï»{ãF½ØÎedd„ .°sçNêê긧(è¦ÔêÁ¤ $ É$�PIé×{¡¢šââbÚÂLfb4:Ês¤à�¬ô&ü\ˆqCÉÎ9¯Ã#œ †ÿ� \wÝu³*@¡Lœ3¡^ŠLvŠÌ”©™z �¨!cÉ`¤U§ÉŽMZZIÓuž‹tò“ð9‚zÍ­±ÓRNCºˆ´œFTDÄ ˜%�w—ösWY/M$’6#hK�i°�óÁò z’v¢Š™'ƒŒËvf‡éÈH„Ôü÷ðÊ£v-¢™¸’Æ&šQÐðš`ξ†S!šÜ5 ¸Ð…åϋϹÓ×HêY} ](B•Ïi˜ã°ZpXÍx�6â© ©ŒŒÅ$‘–4*½.Ží¬™¶¨0ÈwæDÀÄÄ—/_¦½½�¢¢¢œÞZTŒ…òzù6¢J±Y ⚎å°8Þ°¤?44Ä… ؾ};[·n�óC´Üñ¸™H&“´´´ Ieeek2K›Oúš¦qáÂÆÇǧù,÷yæC>áç—óç{lOON�£·ÇƒÙi#šÐ9d«Æ¦šhooGQÎ9'ÐM ªMÃ4µC�‰tlÉ×f �çD™{÷î�s×V’¤TŸ9»{òšØ%�¸’FÐ!-g˜Ð„37”ìF›Ã0g.<5ÞÆ¿÷¿@HNäfòGÒa^ÌNÉ#šMäÝ¥ý@B5#¨"fQC²„ÝŸrð—èM¹Hj².͘ï_]¾§ÐñYÜl±—r!:„U2! "q%�Ïââ–ò•—WgîômsæËˆzïÔÉ蘔#›@“vçI¤˜Œ&ÆRDV3ñT†p"Û*ÙZQ̽oÛOc•oÖñòÉ7"À0i2Œpúúú0™LÓìpWR0>[ëÑÓ3Xðpõ°iH©;ÓÅfõó­n>¼àœåjvú“““´´´PYYÉîÝ»¹pᚌid�ÉdhiiAUUn¸á†e+x#ý循ª´··‡9~üø4±¥I¹»ê½ÂprIÙWTËÝÕÇq›í455‹Å¸ò2—Ã=ôGú°Zl8ìv^ËÂ7:ESéKHi2•Ö"Ą¹s稩©Y0Égvb—,ÄÔ4VÉŒ$¤ØeÏЈ«Ð™Ì޳Y•ׂÝ|êüwøÄŽÛÙâ˜ÿ}£h*?=K ›5�/£½N°6(2§PtÔl ¡j‚ ÙŠ[ÊÐws!^D&aICµS¿?W2Ü|ß›«hBD˜²žý›�5ëyGÉnn¯8Èãã­¼ì&­)œômçΊà ^ÿb˜¹Ó7)!jÝhb}¶M kˆz?&ùßé ÿ.—Â\�äòhMÓ±YLd•DZÆë´³£º„}[*¹åèv<ŽÙŸƒÅvÜ3ípç«“)KÙe÷�õ(ï¿‘Ýø ¸úØ4¤¿T,ÔÓO§Óœ={EQ´º5°Ò×u���:::hjj¢®®nÅÏ5 �Á‹/¾ˆ×ëeÿþý+º±Ì7+jöò-uºÉ¯© \ýõsV3ªíÅüfÃ;èŽ�W³;ÅgyNÀgd’ß´í0.ME0iqÌÉ8ép†"ц¤Çñë~|>߬ëLNòƒá×LL ë*fE ,,òKÛßÂÖºÙÓùp›íœ,ÙÁã£Ùù{§'£«”š-8$ˆ©:¥f—¤ è*CÉ ÿÔû ºç—ç�*è‰�љӀ'ï•Î’­Içщ>ZÕŽ¤ê6 U‚„&RÜ<4´ƒÄ¨=*AF@Ü‘QÓ|?Ÿ€ÏÐý XEsÖ-QñIbdHjrvA†€Ëlå¤wï)?„‰ÓåG8]~D“(­ºd=m§¯µvt±äu]€ ¢QE&ÝÏ«ž¡k¬ŠñpŒÁ@�Ê-cÂf1I¤ Eñ¹íXÍ&&£É9I9‚ºµªŸõµ.ÃÇãñ7MO¿€«ƒkŽôç#×P(DKK >ŸoIQ² =×|È/·;v,ç£ +÷ÌŸ‰X,F0dÇŽË Ì™ QgUNf ö#üh4ÊÙ³g)..f÷îÝ ¾¦6É̾¢ºy®ë:磃ÄÕ415�¬« 蔹=œ*»_ÂBGGét:·ë*++³Ä÷_f 9IµÕK*–`$:AÒcgÈ‘bë^‹;*ðòD7!%ƒ8áµó\0E™EÄ)e3îL‚@±ÅA_"@O|Œ®¹ý"žoCÖòÿÖóëèuÕóáŠKø\Ibš +ЙôòŽàO; DA(Q@]dAÌæÃ[ª®¡’� 0 &ÔÜ( ˆ@©ÅÅx&2U8϶.D9kùô�_âµÐeüé)U¡ÒVÄNwÛœå9{eã}¡k:Š–]Ȉ¢˜ûßr‘¿Óô è*º`›ñ‰D:EFIQ_îeÀÆa53:#£ª”¸ìèšNFV¹2BGgh"»7²½zº¾c5½õ¥T A`~ÀЬ5é'‰ÂN¿€uŦ!ý¥~xæ"ê¹¢jWú\ó!�NÓÒÒ‚¦iœB©ËøôGË(<3©cD@˲­P„I�Pu�¤š!˜‰óÂD'W~ŠÍNÞRl¥„:Â}xM"%_Ñ>Óbçõ/㺙?½t˜ûëºØâŽ!ë"5x˜@ÚŽž¦Âet0ë  hè !§1� “ a ­ÉhèLÈÓõš®Qo+åO½‡ÉÊ;çéÏ瓺¦iÓZ>s-—"ô4žËx¿èB)ºPƒ¨÷ áÌéhj€HÒâVdEʼnKfHË ª¦32E…)퇎¬h¤e™æža¶Vc’ÄiÇ[ AÝ\U€‰‰‰œE°ÙlÎUL&Óºø¼™Ôû\lÒ_*ò{úš¦qñâEFGGç�ª]KÝ�‡Ãaš››)))™W0¶Q 1 …رc###+zž|ä—÷—+Øëïï§§§‡={öÌ뎸\ô%$Õ •Ö¢¬×¸9»hÊh í‘n©Ø� ¹$¬­[·"Ë2Oö5£Œ]!˜Ànw + 6ÉDTI!ëÙXߥÀm²ávíA”Ç1 ÏSdÒ‰*2%Ð.¢r ‡dáþ.>9üMÒ¼^ÂÿzŸÆ!gˆ”j¢Ú’!ªzIëÆ{Áhžë¹/sýt]çl¦œÖ‹%8Ü$bºT,:Ù˜[TDЂ&$ŸŠY4á숪ΨCAÃ"ˆ8D�D]–Hë*Š®aBÄ*š°«¢ÅDHKÒå�wî¨â™0,ßõÒxÏ• Gü -¦õô‰¤p¤þ Aïщݬ"��cÄÒNBñ8šöú‚IÓu4MGœzždFa<cgM “‘$±d¯ëõE÷zùîÛívjkk©­­�UH$‚@__߬*ÀjP(ï°Þ¸æHßèé§R)Ξ=‹¦iÜpà ³vÞKÁRˆz)S°òò~*•¢¹¹I’8yò$ápxÍ�ù†;Æ�x¡“!‚ôûý=z4çt¶Ú¬XX_.ÌóS³ÙÌ–âJ„Ý,RZä#“N…U£lµ–0:0DYYٲϚéíXÅZîªx‰a,#a“œ¤´8º®£¨ ÿ>üÒŒßÒÉègbEI2IQä€ÃO{¢„„>{†]Ï»hKFA“DDQ`R�Ç…Ÿ>=›u+€èU‘$§dÅcuðÑ­ïàßúŸçbt§˜FÔutD$DD¢»`EÃf·! i9ÁùÈÀ’I&ªä¿Ïó—ÿxãýâÇy⌠M¹™¦²6JÝãbUw�Ê DÆð‡Ñt�Œ¬’ÌdY ’ ‰)Y!–Êà²Y1›¦/º7"lgf`dd„žžÂáð¬*Àj|âñ8UUUk|öð:6 é/§$ŸH$x饗Üy/õ¹æ#jMÓèììdhhhÑ)ã¹–KÖ†¡¬¬Œ={öän kAú‚  ªê¢;üàXˆá®QÒé �˜W©�ë®»»ÝNÿxˆs—G™ŒâqXÙ»¥‚=[ʧ…�, Îr&+A9Žoʬ'£)ÄÔ4o÷ìžów¢Ñ(ýí]ˆ&‰KLbŠ…ñš¸=vÊ…RÞbÛ‘³v8”••QZZJQQÑÂ$ èÒvn«iÄa½ÄãcçOG¨µû°/LvÍû«*âT¦½È¸â¢Î'¬ZÉh"uV“ÙÅ€ êxb)tŠb)Üá�[*Ql"Y¡ŸSjQÐ¥¬_¥=…ÇV„`r2‘NðÏWžå“��üßÎ^†Ó¦Ü¯¹$—&ÑÒºŒ.dn³ 0/�k°äW’i™–ËÜ¿2Ь(4Vú8ÐPA±ËžÛý LUÓxöÜeêËöp%º�ŽI…Á@„ÃÛË9±«ŽŽÁ zGƒ$Ò2ªš×ŽšúOZQ3^§�ñP‚ƒ‡«pÚ¦‹I¯Fž$IX­V8°,-ÀbH$…�~ëŠMCúK�®ëÄb1�MMMÓ’åVƒ¨gîd�¾t:=¯¿ýL,w§oTfêVë¯ïÌC¡>Ÿ›Í6çëtáÅN^ùq Áñl´©Íaå†;¯Ç|�™Ë£“<öÊ%bÉ ‡•¡‰}ã!‰oÝ»uÙçTc+æÆ’&~¸ÀåøøT 4¹«¹®dû¬ÇšÛÎò �Ÿ”®ãÖl$Ô ãé0 5Ãon½‰w”ïCEabb¿ßŸKÉ+))¡¬¬Œ’’’yíŠAàíe»y[iŠ®¡é÷¿ú÷‹^‹IÔ©·&Ùåq9å`·9Ì[‹\ïÝJ_Jæ¯û‹AbBC0ë”D“nƶ"œÕü á©¶� ºŽMRÉè"n)ƒÏ*# ДXë˜ÈÄŽ_âËMq~®¦/¥Rb¹ÑkâS—Æð§Í¹¹ÿ„š!©epvP¼¦þð²¢òØ+—8ß7ŽÓfA^ê¤?áô‰Ýxâñ8š¦eÿ&�0ƒ�0U>W®o6I”xtNP첊¥�Ĭva.9¤ªj(ª†¢i4Tx9¾sv¶ùÕŽÕ]Ž`±*€aÎSÀµ‹­[·ò‰O|‚O|âköœþð‡ …BÓ‚�VŠk†ôUUåâÅ‹LNNâõzÙ²eeeË|äøÄh4Jss3n·›'N,¹L·T²Öu�ÎÎNæ¬ ¬v§o”a«««éëëã…^ÀívSVVFYYYÎíkbx’_üÇR©šCfkU-«‹ /tR¹µœ¶tŠDJf[åëF(“Ñg{FØ»%»³3I¤‰§2¸í\vëœç%ï*ßËVg)ÑRšÌ{ {‹êpÌpÁ¤³³­¾ˆ‘ÈjlÅXDŠ®¡h*£©�L,·�1™LTTTPQQ�®ë„Ãa�½½½œ?¯×››p8³@‚ `$ªJ\I/ú[•rKŠ�UwL}GCÇŠ&Ô³Å}Œÿ³ï6^»ÄÓž%ؤlB&¬m!•ôpüèNêJm<9y}Ѝ=¦ {“t&¼ØD Q°’&‘ƒn&®¦±K&n);¾ª¦qvpŒAÙ‚D6H'{1ú”�¿Ê7/?Ï+�m÷n£|ª ²’6˜�Ë£“\ P[Z„Í’ý\”xôŽNÒ9<ÉÁ-%´µµQSSƒÝnÇ “‘]gÐb,GQ²ïíP<ÅðD„+cAb© š6·�Õœ�]ÜYSʯÜt—}öÈèÕ ý…SùZUU ‡ÃK®¼Ùæôu]…Ìk ùA,Ë1a}"’ïºë.’É$O?ýô¬Ÿ½ôÒKÜpà œ9s†#Gެê8¯¾úꦮÖlÒ_hÇžJ¥hii`Û¶mƒÁ59æLÒ£µµ•­[·.hø2–²ÓW”¬¡L"‘àäÉ“s¾1VCúù#yåååTTT�Édøý~®\¹‚Ùl¦´´g�±!?æb‘²²2нÙñð?ÊÅæ^Æj\øÜÓûäÅ.;½£Aá8Å.;iYáÅ }\è÷“ÊÈØ­föÖWprO=Óì® ìpUÎ; §ë:ÝÝݹ–ʳ‰n´°ž‹ß5 "&IÄa²Ò›[ì(^¯¯×›Ëgzzz°Z­¹6@qqñ4²°‹fŠÍNâic cîQ<�”á¸{tê^ìh¦(–_± ‡ ðöº*ŽÝ=-O·qñÙvÁîëwpè�ûø³Á! &Á„IùÝšf8Æø“�c ¤=S•šìy¥Ô&ÑÇVG-è½ +(šÀÈÈ�²ˆŠ@‰ÅFFI©2²¦ ª 3i×8C³ÙÏÁ±lèÔ²Ú 30Š£ªZŽð!+(tX-\ìA \¡¶¶–ÆÆFA ª¼.íý~‰TÖO_¸2DDvÔø0OHhšž`ÈÕu £ªˆºH¥Ï…{žåÕÚé/嘒$ÍY˜˜˜˜V¨¨¨ ‘Hàv¯OŽüfƒžz=ò@}ý›b%xþ‚íÖ5?Þ<À{ßû^úúúfmÿå_þ…C‡­šð�\ ÛfÅÆ~RV€ÉÉI^|ñE\.W®×¼VÉxÆ’¢(tuuÑÚÚÊþýûÙ±cDzÛ‹íôãñ8/½ôº®/Ø2X)é;|èÄ8‹ÅBuu5äío;»wgûçÝ�=„Â!lV¢(¢¨Ùr³É,¡¦dÌ¢ˆ¬L�eUC’„œ�ê…ö+¼|q“(Páu! ðâÅ>^¾Ø¿ìó7&ÆÆÆ8~ü8ÅÅÅØ¥¬sÜL¿�lìÒv¬v»�ºº:>ÌM7ÝÄÎ�;s=?ýéOimmexx˜L&ƒ œª96õ›sÿ ¼&�^‰‹%tq+ºT�j~Šõ�Ês#iÎ"o}ßõüæÿý ïü£[o*¦›é(¥–ì�=£)¤4Aй©h»¤3&KDU‘IÙDX8XTÏ.ïÛФ4¥‹IÿyÜŽ0¥yjWdÉŽóM•È²ÖÆ5öbœfmÚ8õûwòö·¿�ÆÆÆ\ÕÌë_ fÓÜ·‹x"‰ldÖbÙí°±£¦”ñHUÓQT$�®ƒÛf%–È`5em‡EaÚKLíôM.«™±`Œ+cs/ö7ÛN!U€ƒrã�7²{÷nL&ÿðÿ@cc#ííí<þøã´µµ­(ûZ�žz=ôߦ>€6†úoè©'Öü˜ïyÏ{(//çk_ûÚ´ï' ¾ó�ïpúôiî»ï>jkkq8ìß¿Ÿo}ë[Ó�Fùà?ˆÓ餪ªŠ/|á ÜtÓMÓJù[·nå‹_übîkAøÊW¾Â=÷܃Ãá`ÇŽ<ú裹Ÿ«ªÊ<@CCv»�]»vñ7ó7k~ý6ÍN&ŒÑ±ÎÎNvíÚE]]‚ ¬i®Aúííí¹|ú•®²"뉉 Ξ=KMM ;wî\ðe<ÏróùsÕ )ô%I¢¸¸˜¡¡!¼•ÊÊË�Á`�ÑÑQ¬f+‘±8M74RR[ÆKûqÚÌØ,fTUc(¡ºÄCM‰‡p<ÅÅ�%{n|Êgv ëÐÞ7ÎÑ5³WóÁÐPèº>-4ç@Q=O޵1–ŽPnõ Q%…\W¼ü�I’(//§¼¼]׉F£øý~¸pá�‡#¥¥ÜãÛFB}†ŸG*Ièt@vØ3üΖbšJ>‰Äe=ˆ.øÐÅí0ÏØ`TNò¥ž'9î'­Êˆ‚ˆ¬ÉxÍN¶9Ë Ë .¦¶pÒ3ÆqÏ$åÖQ”ÑŸ’p›Uî,ÙÊ©ú[% áø= ö~Ÿê² EÅeÓ÷à:OHŽg5 y{d³`F¼fƒÉI®Äý”û§µA"‘�@€þþþÜõ1Án·{Öû¨¡Â‡Ûae,¥Ü›m�M™˜˜àž·ìcëÖ­³®¿¦ÔCy‘‹ÑÉ(�d]×PUYU %ÒT—º „Iʳ?Ó¢N›•ê‚ Ð=<ÁÖŠÙ!=W‹ôW{Ìü*ÀßüÍßð[¿õ[ÜrË-tttpâÄ |>ðÀÇ>ö±5:ëÍ]W³;ü9+iÙe«ùs°¾kMKý&“‰}èC|ík_ãÿðsïïï}ï{d2~ó7“o}ë[üÏÿù?ñx<<öØcÜÿýlÛ¶�믿€ßû½ßã…^àÑG¥¢¢‚?üÃ?¤¹¹™C‡-xìÏ|æ3üå_þ%ŸûÜçøÒ—¾Ä?øAúúúðù|hšFmm-ßýîw)--åÅ_ä£ý(UUUÓþÖìuXóg\!fF¥¶··3111Ëùn1ïýå ‘HävÈ'Ož\U`Î\åýü…ËîÝ»©­�-BšëyŒß]ŒôóGòŒß]Š¥®(ŠÜþ¾[xA•‹/was8°ZìLŒMâ*sÒ'°Óø¬:ýc“H&¢ PQìæ�‡1›$b¡É´Œ×7½ÿè²[ð‡Ä’™%‘~"‘ ¥¥—Ë5ËI±Æîã—k¯ç¡¡WLN`—,¼½´‰%;}îù�Re™(n»�ÆÆÆÜîw2p³ò ¿SþVs˜€ìâåØ6‚zG‹ “ VÈš‚]²"k*�L �2«‡]î…oLV«ušm0Ì�C&“IŠ‹‹)++cWU)[ÊÓ|±‡Ë½W8ñÖëÙ¿snÇFMÓ9wy˜Éh‚dZFÓutýõW/%«ôû#󞓤d³$I¤©(r ªê,c «µÓ_�…†aÃk³Ùx÷»ß½æÏ¿) ù×öqË@SS7Üpÿò/ÿÂÍ7ßLOOÏ?ÿù$ªªòñ|ç;ßahhˆt:M:�εb/_¾Œ,Ë\wÝu¹ç+**b×®]‹÷À�¹;�NÜn7ããã¹ïýÃ?ü_ùÊWèëë#™L’Éd­¬›Šô�2¸‘\7×y¡À�¥@×u®\¹Bww7{öì¡··wÍÌp –e™–––\ðÏrÓù¤¿Ð5,50`||œóçÏÓÐÐ0Í`Èb³°ÿm»Ùÿ¶ÙsòF|ÿ¾½D"ü~?cÃ\îêÀëõRVVƶr-½cè:8mb©4¡xŠ·ìÙ²è.llŒöövvìØ‘ -š%7–6-ø˜¥àG#gøjïOIi2‚�Íòö�F§ºùd}‚ò*²lB’¼ˆ¢(ˆ¢B™/L$Y‹*÷Шa0ÔCYY”²²²9Ëà‚r‚´¬ÓÐ2¤b Ñ‘õÐWt¹ÓŽê�ü?·ª ¨²ŽÕœU¹Gà¶[@9eŒÿù/�óËïßN\JÒ:1H2£àV-øLbR‚Œž J¨i¶™Ëù•Ú“³&$‚(Š9uù®]»H$91hggg–ìd™w_·oAÛë‘ɽ£AL¢ˆ>U}˜3EhHbÖ”'™Qèžä`C%;kJæ4Z˱ĥBUÕe'_.EQH¥Ro|õ¾¸D¡ÛR·L<ðÀüÎïüÿïÿý?|ðA¶lÙÂ;ßùN>÷¹Ïñ…/|�/~ñ‹ìß¿§ÓÉ'>ñ‰œÞÅØ`Í|¿/E{1s�˜ï˜úÝï~—ßýÝßå¯ÿú¯9yò$n·›Ï}îsüâ¿X‹Ë�…MCúÉd’æææiÉusÁØé¯Ä%.¿m`äÓ÷÷÷¯IåÀ¸éD"Ξ=‹ÇãáèÑ£ËvæZŒô—k©Û××ÇåË—Ù»w/Ë:˜^6Ôð~¿¿ß¡ |¢Š"ńɌ×íâ†Ý[8±{þä»üsÚ¿ÿ†)]ÓªÂ×û~N\Mc%DA@Õ5bJ‚WÂaÆcTX4ÌfAˆ¢ v=èHŒãuxÐÄÌÞ� z¼¹^¸(Š95|IIÉ4ò™MxŠš´‚ŠÒ–4â¾: ô™t¦²fß8ÒFŸ[‹ÙœÕ ˆ0Žòà‹¿ÀÜ “�3¨‚ ª€”6a’,øÜv"B‚cÞmüÿßE‰uujp‡ÃA}}=õõõôôôpåÊJJJ ··—’’’\+Àjµ¢¨£Á(�ƒ¢‰4¢$ €˜­s(úRÙÙÞ®$ìª-ã}7îÇçv̲VY–sß_j>Àj±åýX,›¡ð†Wï[ŽeUúÚs¯…ìÏ-ÇæøÙêqï½÷òñ�œo~ó›|ýë_ç#ù‚ ðüóÏsêÔ)~õWÈþ�»ººrâçÆÆFÌf3¯¼òJŽ£"‘]]]¼ýío_ñù<ÿüóÜpà Ӵ===«¸Â…±iHßápð¶·½ «uî±’$åzÙË!}ÃîvfÛ`­ÒñŒÍ+¯¼BCCCnli¹0Ä…s‘þR{Æcç²Ô]-ìv{Ž Sœ+ƒ# ��c7Ç)ã'¹P’™çÔÑÑ‘K)ôxõ©O‡ùð‡? ÀöíÛy衇xñÅ)..æóŸÿ<£££9Òw»ÝüÚ¯ýŸüä'ñù|”——óGôGKª¶.„íÛ·ó¯ÿú¯<ñÄ444ð�o|ƒW_}•†††µ¸ÜYØ4¤`³Ù-•D¢(Ê’ûðÁ`�––ÊËËsýlk¡0v¯À¢•Š¥`®„¼åödYæÜ¹s(ŠÂõ×_¿æeHù¦8š¦‡ñûýtwwÓÖÖ†ÏçË™™L&ÚÚÚH&“¹ÑËu�®)@áõ÷GPŽÏñ`  EQm;’€AWÐI �AÇ ‚µÌ©ÿÈü‡¼Øi¡kh›ÅÄÁmu©.&šdllŒ§Z_!’HeG -g(¯õÚaKf˜Ýõ‡â)QC×D+(š†ÅdBÔ¤„4.ÍŽ†€'êâ·ö¿›rëòU“ÑO·tÓ;DQ5Šœ6N4Õqd{5���ôô3¤8 ôŒâ´Y�•îá Ží¬áÇ�ŠÆyðñW DpJ*fAÄ„F"�Á, ¤TmZ°ÎÂÐ)óºxÛ¾*gëaŒTÊááaŽ;†Ãá˜Öö2ª°´� åb=vúñx›Í¶á­Š«Áv+xÿvÎ9}Áó©u™ÓÏÇ<ÀW¿úUn¹åê볕ÉOúÓôöörë­·âp8øèG?ÊéÓ§ ‡Ã¹ßûüç?ÏoýÖoñž÷¼�ÇÃÿøÿƒ���UÝcë·~‹³gÏòþ÷¿A¸ï¾ûøØÇ>ÆO~ò“U_ç\ØT¤¿ä¯ò—‚��.]ºÄÎ�;ç´í]­í­1óm-7éo.äWf öŒJÀ|ˆÇãœ={§ÓÉ¡C‡Vü±’s...¦¸¸˜�;w�dz:€±1.]º„(ŠX,öìÙ³n‹A½Œ¨<‡ ]LhÒa4óM ¸)³º±IfÒªŒ  ˆˆ(ªŠŒ€SØ[TŒ&GT^#Kü è:`aKn$OÇŽ¦s¥ÿßùYÛÍxVÂñ�¾t�¡5¼ï­ÙѵWFd¤ŽÉ옩&d{ÚÂT¢^ZÄ4äBV„%´·_„¬¼þ>•ã û%Ìå šLºÄae¦˜•tF!Ó¹,ORYìÆa]\p&+*?zù=£“Tz�XL“±$�¿ÖÉð`?>‹†¹¸÷�U¾)ÍDiZ{Giª+g"’ ®À¡][!ÛŸvGùÙ…¢uÆÕ,ŒÕ%ü—;®çÀ¶Ê©xݼWdÊÕÒÉæ{^ÌL 4k]X�«»i}×Û­`}׆9òåãäÉ“³6˜>ŸoQ›[·ÛÍ¿ÿû¿ç¾ŽÇã|æ3Ÿá£ýhî{W®\™ö;smdC¡PîßV«•|�|pÚc>ûÙÏæþ=Ó[`5¸æH©³úFy{dddÁØÝÕìôg¶ ~ö³Ÿ­™(0?Òt©‚½ÉÉIZ[[TÃoœN'N§“ÒÒRš››±ÛíX,Z[[s}ð²²2|>ß²ožM¡9t…¶ðiMf§«’ë<Jù‚6‰.”$ùq}Õò,ÚÂ6G9Ýñ1TM%£Ë€€Yy_y ›hEêQMNDõš´=ûJ ä×iYÀc`[åëäOehíãÈö¶W—ÐPéCÓ@�’ä ºˆ>•·k± xú=¤„ÔT+g>*œùý×çð£Wè·�°êئp–Zp)v:Ç'øÎÏÚÐ4�b·ƒ·ïoàÈöêßWÆ‚ô�©/-ÂbÎþ=*¼.Îu^¡5%ñ;¿ü.¾úd iYfd2ŠÅ,Qì²ãvXÇ ÆHË Y—¾Œ¢Ò7ãòp�”&`³˜qZÍŒ†‹þ}�V‡k8¾köˆ«®ëtttà÷ûs;ü¹0_J Q5[m`=& Ò3A¤5Ë[O´´´péÒ%®»î:Âá0ò'À©S§®ò™-›ŠôAX’r±Y}c]Q”EcwWJúFB^ii){÷î]Ó„<ãy–*؃l€Ï¥K—hjj¢¦¦fÕç°˜˜˜ µµ•-[¶ÐÐÐ�Ó*ƒAü~?¤Óé\8Ž![ª®ñðЫ¼ìÅ,ŠH‚ÄåØ8ƒA~£2H±u{ÎÚM×=ˆêE4í6i?ÿmû­|©ëqz£ã˜ —ÅÎ[Kjù`u‚ÞºXQ-·¢Z~)ómPÏf[‚º$…86s1Å?áT9‰´Ìx(Fÿxˆ¼ØÎ=7ìå†=õX-‰´7}Ép.k¾¬È‰$ " {凕5¥ÈŠJ{ß=#ÙÅÁÎÚ2vוI¤Ñt=Gøš®3:2‚EÔ‰cãëO·òÂ…>’i›Ù„Çi£Ôã`w]Vˆ)‰Ù$ÿ L�#¥¿� GÑ…­SÛ]“ÞG�ïgTTU‘Ñ£ŸFÒ.ŽzP5 É¢à2µòáŠ+„:ç>º">ŠL)¬B*KÎú8~ŠÐÅRFÜttµ¯È@3ßLF:Ž9ùßÑ´(ÞßÈÙ˜ŸYFW5TQ&âI£Õ)«èó !¸âýzÂÄÈd “$âóXPU�ቺ®c³‰R14Qˆšˆ–s™]ÜÁFÀbQT YÕøEÇÿñJÉ´ŒÅ,!‰¡x’—.ö³­ÊÇ�†*.ô�# äÈöä#qzÇ‚¼ûPcÃL "ÙݘMRÖ6WV²º!;^h5K˜%—ÝB,™á¥‹ý4wÓ=L&‚ äÒ×b$0‘H\¤oÜÿ‰Äú�Þ°,KÙüm*Ò_*Œž~,£¹¹§Óɉ'V´Û]¬oXWWW³k×®Eò–»Ó_ŠÃžÕj¥¶¶–ÚÚZFFF¸páN§“H$ÂóÏ?ŸSÂÏt„Û(y ‡ƒÃ‡/zÂÔäúìdg Èduz4ûol€€ÙdÆjŽã6Éèº€Š„ª hºÆA—Ÿ@f€ýö­¨’‘º6ÌÐx }Ã.Ž?¼ä›©¢ªüäµN𻆉¥ÒH¢HM‰‡_{ëN"êkÈš‹)K�fIGÓ$’ºˆ*ª˜53]"£ªh&•Hõ$ž`BL 35ng3›ˆ¤RÙÑ=M`áaý¹~¦çý+ûsQ˜Š¦%»†R5YÕ0‰"“„ªéÔ–±«®Œs½£¤e«9ûÑO¤3 k¤Cã”îÞÊ®]»rïÁçZ/Sãs3Œ’HËd•dF&™–§Ž�=cñ ¦åånðó®Jçmû8}r&QàìٳȲÌÑ£GsŸmãs0— ´¸¸8§Y2E‘þþþ\ëÊf³å4k1�ǯ‰ò¾$Ix½Þœw¼Ãá(ˆ¯t]'‘H0>>Ž×ë]Òýÿš$}I’‡ÃtwwS__¿ªñ´…H¿¿¿ŸŽŽŽ%î,w§¿\KÝ+W®ÐÛÛËþýû)//ÏâŒ��çáŒ�Ï|:€µF8æìÙ³TTTL# ãœÏ_ãÅ } OF©,vqÞ-زI(}„2ãÁúš´º¨LíÚà duN)‰$¨”›“Ù]3:šoóŒžp&kòdU’)8~üø²zÀ¿èäù¶+x]v*|ȪF¿?Ì÷_)ãŽëJpˆbª€Ç” Þ‘LÅdDt]†¤ £›4DI@FF­‰s\݃¦é´_fd2:U ˜ïo½�mÝ\#|ªª1Ã?õ�ÃB"£Pêq"ŠG·×pþÊ8úÇ0‰"ÙÒ}©Eåú=»Ùµsúç(t“"–Ì0ͦäiºŽªgŸ®³ZiÁW\6 [ʽ˜D�––t]Ÿ×Ê:_jÜøòóG® àõz×Dt×××Goo/G��æ&9s¼v¥#�×RO¿²²`ZhLW^¯7÷7Y ›Šô—Bܺ®�ljD"8p€ªªªUs.ÒÏŸñ?zôè’ñKÝé/×aÏHì3¢†�Î|†8†%êLÀBPT�ŽA?ü$RêÊŠØ·µ’²¢ùÏòÙ¾}{ÎÕ*/_à;?m%-+8¬ZC£\ôóËoÝÏÛw¾1ó½)#�@|¨–{²ÛU¡Õô6$ùÇèš ‚§˜BDCÕ%d=» ÑQ° ªqDo-©d’p¨Eñ‡J˜8>·Zl÷§i:¯ub5›(vÙÑt�dFÆj’xµ;Í¡mïå­¾Wx2 £ X%' ÕŒ(…1é&ÌV�¤ flBöïõF¸88ˆ;l%“I£èÆî~¹ô¸ÐhŸ0ëQ�H¦È¨{+í RZZʯ½ë0Í=Ãt øI§S˜R!n:z€�Û¦½ÍÝC¼xq€ö¾1T5ÛÇwYmÄÒTdumû¹³H™×…¢ª477#‡^’¹” 9_ˆ-[¶äì¡�mmY¿‚ü|€•,†�¼ˆ™„k7˜H$6ÍôÍb�ªª*ÊËË‘å¹#� Ø˜ÍæeUx7é/EQ8þ<±XŒŠŠŠU>Ì&êL&“++žß¨’ ¸\.\.ל:›ÍFYYåååÍ:æ í}¼Ú5ˆYÊ–„_é¤w4È×í¢²x¶{?ÝÝÝìÛ·oNádZVxâµN4MgK¹a£êdd2Âk—^ædƒ«tô1@Bw¢™ß�.½N>ªå~ QyA�!‰E ÅÈè&Ô©ÐI²£dB Y¾H:Ãépàðžfoéí&‚¹ÝŸaTVV6çk hñT›Å„ªi\ 2M k:‘Dš¾2Áûo¾‡¢º~žõ_ ®¦©²»¨²Ó!£fÇÚLBv¬MDlš…þ±0™1PçœË_É"`a(8lnÜ_Ë]Ƕ022Â¥K—p¹\T”–RÛTFww7»Ž¢¶vº Î úøösçð‡sÙiEEÕ²Ue� _Ì’„Íl"0<€·²ˆC‡­¸U•o­ë:‘H„@ ÀÀÀ.\ÀívçÞ ¥$0ÿÈ‘#KÊ‹XÈh¡‘ÀkMÈÙ…Îfаt\3¤ŸH$hiiÁl6SWW·f«Ëü™ÿX,Æ™3gp»Ý9rdÙ¶‹éfZê.Vî‹Çã´´´àv»Ù·oß²>\ù:cçã÷û9{ö,À4ÀD4IÛ•Q|.;EÎ좢¬ÈÉåÑ ç.�PyôuÒ7ÑÆÆÆÇ OD™Œ&sA)Nlëçhýs ÁlB@D“šP-¿¢wú“fTëûP-w�C”Š9ýyìR6›ÝèaƒE÷Ò9Ѐ×[Nié[Ð¥Ý8‘z§›úúzdYν---ˆ¢˜»ñZ³$Råópipœ´¢âÇqÙ-hSð¢ òó¶>î»é wU!¡¦qšl %'ùŸmß"¦¤�‘up‹6¢/ÛHG²¦3©tþ{#Ÿèó÷竇 @cU1¸ù7îÛÊ¥ÁŠËD]e=nIåRw/çûü ŠHŽQ, >Ÿ“ÉD8žâ{Ï·1Ê&¾I¢@FÑQU EÕ0Kâ/O²Wo5›(6+l-÷¬Šðg"?%²±±‘t:�{)‰F`®�¨|Â_IhÕbU€üÅÿäää5Gú\{ØT¤?ߊÛÓUUUÑÔÔD__©TjMŽiìÎÇÇÇsîqÛ·o_‘F`¡žþrú÷ðº›]mmíŠÏÇÀ\Á8ù:€°jÁ?cÏÖ×+'‚�uXð‡QTÓÔ‚¦­­�D"1-4ÇŽÓ=4A(ž%ù5%XÌ¢$ ¨¯¿NK”ë¶¾€$(È4b‘¬èzQmG’‚j½oî ,Ù>¿i?z¦H! i²táEU£ ùk°ý¥µsk/Ìf3•••TVVæÒñ�]]]¹p ÒÒRŽ6VÒ7¤k8€$Ф2*©ŒLM‰‡�u¥ô�…ð‡ÙS_N‘˜]Ðlq”ò_ÞɺLFS1 ">‹ ¥&" ™]˜CÕ¾$?ý9V3þH‚ŸjæßŸ=‡¢¨¹c h„¢qDÉŒ(¼x%Âþ‹ƒ¯sRZRÂå Ìx0†×a§?$•Qò<t4mõæS³®@€Õ.Þ±·†ãG�¬k4®Õj¥ººšêêêižÚÚÚrbÀÒÒR�Àª.ÌWॗ^bÇŽkrœ ˜›ŠôgB×uúûûéììd÷îݹ2äZ9ßÁëîwçÎ�cß¾}«jÌWÞ_.áÒÑÑ1ËÍn-0—àÕöÝctvwã°Ûq»\¸ÜnUÃi± bÎÚX’$Ž?žSS÷Žyª¹‹P<…Å$’‘UÎ÷�qË‘í4TÓÞ7ŽÍâÅ$‰T¸û°JaJ NC\'XТú*Ñä)'ȪJ‰ÇA…wú¶.6¢šß†¤ü'àBÇ‚*‡ˆ&¬X½¤²li醢(âóùðù|Ó´£££„ÃašŠúF!­ªØ,fvÖ–²½ª“(Kfxùb?ñd†C�U˜MÙÜ[Kwñôxƒ© •æ""‘0þ˜‚Ž$Š$«­L-<—ÿ•¬h(JšP,dMzt¢É4ª–­�9%ê˼ÄÓ2mc)v6neh$Ƴ­½ŒŒêëWã $ÖªÊo–lV ×=¼®„?3߆ÐX êºNEEŠ¢¬‹×¾ñ|ãããÜsÏ=üʯü û·»¦Ç( €™Ø´¤¯iíííŽ;Fqñëñš‹yï/ªªÒÝÝ�®ë?~¯×»ªçE‘L&“ûÚì-54Ç02B‚ò¯y=`è®;¸›Þ�L(šÀeHÄã �ŽÎèܸ§ŽÑѺ»»ñù|Ó¢‰eEåÅ Wˆ§34Vùr×pe,È/:xï ûˆ&› „ÑŸ5‚Å$QVâ›ÆW:ÉT’‡[ÚgÉÑf1±§¾œ·îÝòzÊš  Z?‚.5 Ê?%a|²‰¢ŠRì=²¢× "'9ŸbÜÁ½ÅÁ.ûVöDeb²Nóå1ª�:^‹N2癳£\òò¥~¾'µQâqpçuMÔ•qh[¨ ÿÐý4=áa$QB¶[Ñ5‘t|õy S/ µ![MÈ(ÓÄÁØìªX4™ah"J}¹—á‰0�¼ÜAm©‡pZGÑW,9!wHSŽ}v‹™@ '"l«¼zB6‡Ã‘¤†B!¶mÛF"‘ ½½EQrÕ ÒÒÒ5KŠåŽ;îà†nà«_ýj¡?^ÀºcS‘¾Aˆ©TŠ–– �8ó¶;}ãFÝíž-V[.òËûó‰v惢(ÓJçéÁí´Y¸éÀ6ž9×Ãd4‰`rà.u²Óc¥Ú-ÐÞÞž#ú@ �ë�" üáÞ×ÇŒA Üëbt2†Ãfæwïy ­½££Iª¼T–ô"Šq`j§¯kèÚ$—FvŒil-/F¢É4-=Ô¸ìoÈEÌ(Ò­\ì¬grr’ǯxÌi4â›/2” "  ¡ñ¢ÙÉ;‹ö£Y=„ä ü£I*�ðÃáf“ˆËf!™Qé ñ÷ÿñ26³«Yâ]x»·‚ ¯S‘ƒgš‡™P#+ý³Ìƒ9v÷ˆ ¦õÍ�`,‰¢j¤22‚˜&šHŒ'—Ô³_-çgÓø²½|—Æ¢jDK³Ã^Oô÷÷ÓÓÓ3M¯¢ë:±XŒ@ ÀððpNi,æ….~¿Ÿ»îº‹Ã‡ó/ÿò/Â/`C°©H^O¯+))aïÞ½s~ ÜY Âá0ÍÍÍ”””ÐÔÔÄ3Ï<³&©YÆ$Àr{ÆÄb±\5KÝmU>J‹œô�É(*>·IŽÓ9Õfp:�9|:�Æçó¡[œS×9ÿó:mNîžçÓu„ÌDåIt- ˜ô‘t ͨ)ñä¢jÝv+ÑDšŽAÿ4ÒW…ÖÖVÒé4Ç�_ñŽK×už?Ï`r’­Ž2$!ë‹ßíðgÿ-™ýZÕt&£IÀj1á´šIgdâ)Ÿ¤¬aMFæû/^Äj’¸¾©–׺ºI¤W_�Z ’$b5™Hd2K&b�¬�� @Z–IOUR™õ?_’V‹—͆Ù$Qä°Q쾺înáÏìá ‚0Í!3“ÉäF[ZZašp)Ÿß‰‰ îºë.víÚÅ7¾ñ�e‹† (`¥ØTï´x<Ϋ¯¾:+½n&V³Ó7By¶oßÎÖ­[sß_ �€±Ó_NÿÞ0·)++£©©iC{š3áqXÙ·µ]×¹|ù2½ýý:t(›ˆ³cÇŽ×{àcãÄ&ÇhõûÙVU‚ÛíÆl63гµ²˜b׌›¸  ZîE—¶ */ƒFwÑØÃD6éKêÏšL¦e ùŒ’p,›3”g¥A9ùÐ4 ·Û�ÉdâÅ_ÄåråÜðf¦�éºNoo/W®\YQòÛzA–eZ[[‘eyÉ¥óu|øv7=#LF˜4—¨0ÖßÃXÏ’rª}vÖ–ÒÒ=Œ(XÌÙ¿oI‘“½[*‡Ã<ÿò«”–•Ó´{Ϫ_VT^l¿À™ÎW±N·+lw‚Çá$”,'3Õ–1Ib.FY ÕZë1¶·ò£o >·š%jK‹Ø¿­’Üt»ÕŒÇ±vQ¹ËÅÀÀ@ŽðW+ä°ÛíÔÕÕQWW‡ªªƒA�ò'ÂÓO?�Íf£²²’o|ãk&, €å`Ó‘¾ ‹ÆJ’”Ê-FÆÑb±pâĉ9WÖ«iä öÇŽCQ”œ^oo/V«5·ðx<\¼x1?»µ€šc·Û9vìØ²zŒ%%žéÂC]× …Bøýþi³ðeee¸<^FÃIÒ²B‰ÇAU±ŸÛެj úCè@}¹—ëwÕ ùξBJ°â˜œ uì oÛ×@S]©ŒLçÐÁh‡Í®ÚR<Ž…o¤Ïœíá§ç^Åe‰Ð 9iÏ$9—ÉPšš)‰Pä†qº¨ƒ”u\;Ìõ¾^[cžÍ qJl(ñXŒR“Œ’cu”^µs »»{Í&$IÊõú|ðAn¿ýv&&&(//gïÞ½455ñgögœ:ujÍ�]@óaÓ‘þR`ìUU]�ô'''iiiÉ™úÌ÷Ø•’þ|‚=³Ùœ3QU•ÉÉIÆÇÇ9w`2™Ø¹sç†*ôB$¡¥¥…òòòE“bÉlªšÛ¾@|® L+{:€³—.óR×)UÄf³áv9©ðy˜Œ&)vÚØVÙ@FQÅxúÕvGÆQL6ê*Š1‰Ã��¼t�Ûå�¼Ú9È•± ºž Þ©ðº¸ûÄ*çu Å’œéê"™ŽÓ=â Ew!Z"u)n>Cp×ÑçO�–UU›Ç6w%¸ú½€«Ñ»7 hYâ÷yìÜvl;'¶—æ2"–k‹»XoÂÏG2™äøV«•ÖÖV<¡Pˆ'Ÿ|’-[¶¬ë± (`&®iÒWe^ÌÀÀ—.]b×®]s†ÁÌ|¾•h–2/IR.ìerr2׿|ù2—.]¢¤¤„òòrJKK¯Š Çï÷ÓÖÖÆ¶mÛOÂq^é ßŸ�»¯--âøÎš9½ùóaèA¢£eÝVÄ�9�"œ µ{�b·�c»êèÑ7$‘JK¤°ÛmT—š Å“”zœÔ—{é�äáÎ#+[ʽ˜Mš¦ÓïñÄ™N¸õXÎ4'“Ñ$Ý#!†&’™©°;PL;]„Ì�.7Q�Ž,kèèdæ˜q¿V±”*ÚúÜv ¿öî#Üy¼iªßH&“ÉõÀ�œzcàóùÖeŒm# ?�Nó«¿ú«D"ž|òÉœw¿×ëåÞ{ï]×cPÀ\Øt¤¿”“ óõJò–Kú+µÔ­««£±±1w�±X ¿ßO__íííçBq6¢ß700@WW{÷¢bÁÇF“i~òZ'#“QJ=.ö�3IpêäîœR_Q5‘8ÚTHÍ€?”ÕɉÍ]Cœ»<‚Ón!™VØZécoUCÍ�cI~ôR;�˜‚ ¼NÈRRF2I ODÙZQŒ Ã•±*1›$© ‰´L‘ÃÆèd”�@x–ÉKÏÈ$ÿøØËtÇÐtQ²ùó:h<ßáF$Óòš˜ÏäÃn–IÊ -êŠÔ]\-‡,áï¬-¥Òëž&سX,Ólq�xGGGn4ÔX¬Ågb# ?“Éð¡}ˆ±±1ž~úéu?^,›Žô—йˆÚH¤K§ÓËJÈ[J:žcw¿TÂÈÙç[êæÏþnÛ¶�d2‰ßïÏyâBÀòòò9Ç~Vc’axx˜#GŽ,éfÔ3<ÁÈd”†ŠâÜMÛe·ry4H×P€ëvÕÑ32Á³ç.3<e8!žÊàsÛE‘Ñ`«YÂn1ásÙ‰&Ót �/Ñ¡X2G´&!;Ò¥è:ŠªO¤(ñ¸ FžŒb³Éz±T†Ë£“ "(ª†$‰8¬fbÉ×M^i™§š»øòc¿ ‘2È\@GÏͪëS�:ÉŒ¬OL¨¬.¶c]ÿ’öÕl0˜% ³I½€hOEJJJ())ÉÙâúý~ÆÆÆèèèÀétæFáVbˆc,r—úž_ dYæ� ¯¯�gžy暉Ì-à��7 éÇb1š››q¹\œ8qbYB´¥ìô K]ãqkm©k·Û©¯¯§¾¾>WòœKèõzWµPU5O¼翉h"K¶y»4Q�³=#Ä’i~ÞÞ‡ªéH¢@(žBÓ5i™Ò"'"²¢¡KE¥Èic4åÙÖËÄ’™i;kEÐsþîãá$“Ñd.éÎã°¢ /^ìGlf3«™DZf2šà¹s—9ÐPE$‘æ±W.ñ­gÏKf¦_ÐT‡ûõÍïú’®¢]=ÿ…« IÌVQÌ’È–òâœ]ób§Ó‰ÓédëÖ­³RAÈ-æJÇ›‰ÁÁÁ #|EQø/ÿå¿pñâEž}öYJK¯žX±€fbÓ‘þR -ßßï÷sîÜ9êëëÙ±cDzIq¹‘¸Fö|0,u“ÉäŠ,uóKžªªænvçÎ�ËÝìVÒóÌd2œ={A8~üø²f„]6ë¬yð±PŒó}£¸6Zz† Dì¬)!™Î†º»ìDiDQ@’â© Š¦Œ¥pÚL$R ±d³$¢Î‘Þf,t@ž:´€†¦ÊYÌ£2fIÄf1“VTL’H‘ÓJë•1Æ‚1:‡œë&KÎsU©˜_HF÷ÆUîk:˜$‘£;jøå÷Í©µX f¦$†8ùéxÆ"`æçmpp�ÎÎÎ !|UUù�ßùš››yî¹çm›PÀFCЯf£o(в¤þúK/½Ä–-[H§Ótww³wïÞ'Ò�?«Õ:g¬¥!Ø3&[P$“IΞ=‹ÅbáÀ�k*ÎË�ÅG–å% ãñ8---x<žyí�‚?ç៷“’e*‹Ý$Ó2?;ß‹ªêßUË•± £“Q$QDQU‚±’IDQTŠ6b© ©ŒŒ( è:Sóï¢ ` ½@d›Àëa2f“ˆ×na2žÆj°™$,f^—›ÕÊðD„]5%t�NЧHn€îò�­oLÂ7KN»§ÕÂñ�5|âô[1™Ö§Úa¤ãùý~‚Á ‡#§ˆÅbtuuqøðáu°Ò4��üã<÷Üs<û쳋 ˆ (àjàš%ýW^yMÓH&“«Î»¾xñ"‚ ÐÔÔ4íûËì…B!Î�;·äÑ·ÕÀŽ��ã÷û‰ÅbçÚù¢§`0ȹs稩©aûöí+nt Oðâ…>á8ãá8#Qm«¤¼ØMç`€+c“$22±Dz*éMÈóRÐÑt°š$$Q ™‘QT}ªdOö±ó¼ÍRÖ$G$1û¸b—�`,…Ëf¡Ìã žJ“ÊÈD’2ª~uÇÓÞìðºlì¬)£©®Œ{nØ;ËÇa½ (JÎll UUñù|TWW¯ë„Œ¦i|ò“Ÿä'?ù Ï>û, ërœ X-®IÒO§Ó<ÿüó˜L&Nœ8±jUoGGŠ¢°wïÞÜ÷–+ØåÂ… lß¾�ººº ·Ô͆B!Ün7eee‚@OOMMMÔÖÖ®ú8iYat2JKÏ-ÝÃì¨Íö+Ãñgº D²¯›ª¦! iYr·˜$Ì’ˆ¬hH¢€,+ÈKx÷¤/ŠYÕ�ª¿žçnTt]/�ü&€ÛnÆj6sÇñ]ÜztueÞ«b¯;88HGG;wî$�NˆÅb9_ü²²2Çš|N5MãSŸú?ü0Ï=÷Û·o_ƒ+( €õÁ5×Ó�D"477c2™¨©©Y“1I’H§³Šï•ö._¾LÿUµÔ�)4Fãñ8V«•D"A(Zq ¨«Ù„Ù$‘Qü‘8æQ‘êR‡•Ò"gÎ,Ça5#Y•}4™FQ5ÐuDQÄf�eD“®/js+«L3ÊQóúý›lÝú¦„Ù$â¶[9´­Š‰H‚c;kÙR±¾åôù�ßÃ7JúÛ·o'•Já÷ûsZ«ÕšÓ¯¨2§ë:ŸùÌgøÞ÷¾W ü® l:Ò_£££´µµÑØØH<_³›½á½¿\Ážªª\¸p�P(ıcÇ6�¥®Éd" ¡( Ç�Ï- ßJ…€­½£44Dggçœ=|›Í6Írr¿ßO{{{6롤$·XŠÈU×u>ûÙÏòõ¯�gŸ}–]»v­×ePÀšáš }]×éîîæÊ•+Eáܹsd2®»îº\%¤¼¼MÓr~ø—.]B–åœài)ýÎH"Íó篠k:;jJØRá¥o4ÈkÝCÀÎÚ2á8þñT†x*CJVЧvèqËS_‹B6ÚUžã¥.ôä7'Ê<B‰ªªa’DìV3ªš (ðºìüÒ�ûqÚ6>=nhhˆŽŽŽ%‰ö §Ì²²2t]'�àÂ… x<žÜçbf`dïIý×Í—¿üežyæ™i­Á ØÌØt¤?óÃeŒ¿E"Nœ8‘ÛMç—äW QI¥Rd2,Ë¢„‹ÅhiiÉż®‡UèJ�J¥hiiÁjµrüøñY³Ë¢(âóùðù|ìܹ3'ÌwœKh`x"B8ždKyö†j1IT–¸ñŽØ±š%ön© –LN¤ˆÄS¤eI@�‹I %¿Þ{—„lOÔèј©o_èëò�_ýZc]‰$XM".³È¶­¤d•·ïoÀj6a³˜ð8lìÛRA±Û¾¦Ç] Â?tèвUú‚ àñxðxÉÁƒ×éª (`í±éH?Éd’ææfÌf3'OžœVrËŸÓ_ 4MÃãñ ë:Ï?ÿ<>Ÿ/G|síÞ�mmmÔ×׳mÛ¶ ì͇h4JKK ¥¥¥ † ÈwlllÌ  ÷3·Û�{ G@MŸ2³É»dYÑÐt “htŠœ6Þ¶¯�/ô1Œ"I"šªa1‹H’ AÎä gU]Ã$ŠX-fdEA�glo&ÉÌlw_¯Ù{T'–LQ]ê¥ØåÞs}ӢɆë�|Â_ ç;«ÕJMM 5559k`¿ßÏ×¾ö5>ÿùÏS[[ËÈÈßþö·9vìØ\Al6-éƒAZZZ¨¨¨`÷îݳHl5q¸0]°g·Û9qâÉd’ññqFFF¸téEEE9+\»ÝN?]]]ìÙ³‡ªªªÕ^âš!ÐÚÚJCC[·n]ÑBd.GÀññq._¾ŒÍfËF⺊ð8¬Âqʽ.¬fMÓ±[ÍHS£�ƒ†Êb’é ª¢ "‚ ’Q´ì®Q”Pµl‰XU³j‹$’QgÛ!/Í ùMŽ 3Z$¨.²aR“ Œ¦yËîz,WÙhp­ &ò­�?õ©O!Ë2_úҗصkï}ï{9xð üàù½ßû½5?v¬6é ‚Ààà /^\0!Ïd2­˜ôóòŒc ‚€Ãá`ëÖ­lݺ•t:��ëêêÂd2¡i»w零²rÅ×·Ö0F“öîÝ»fç5—#àøø8Ã�q) z‚ �P—ÝNFÕØ^]‚¢iŒ£8m¢‰4Š¢PdÁá`,œ$#«˜L"‚“ Q��Œ¢¢¨Y?uÖ~æ×›£ªrÍaY>¢>—�t&CU‰—Ë�Å$²¥Äή3?ÿùÏq¹\9mˆÇãÙ°ê×ðððº~>t]çßÿýßùÇüGžxâ nºé&��?þ8ápx]�]@k‰M7§‡yá…8tè%%%ó>ntt”ÞÞ^Nž<¹¬çÏ7ÜaÑ2¸,Ëœ;wŽD"�Ëå" bµZ©¨¨ ¬¬lÕ#p+…!nâàÁƒëî6ä„€­]W8y˜xJfkU ûë˜Lé´õû‰%ÓŒøƒL†ÂHÑ´B(–ÊÎìšž ºÉµ æ¿Â¼ 3¾W ÿYXìc¼Œ÷¨ € ƒÉ$Qåµ£ª*¶Õð¾÷£éPì¶SáÍŠÛdYιáMLL Šâª¦C–Šááa.]º´a„ÿío›�üãüà?àÝï~÷º¯€Ö›Žôu]'�/ª$÷ûýtttðÖ·¾uYϽ…~2™¤¥¥›ÍÆ�rÕcçë÷ûs*àòòòÏú.ªªÒÞÞN$áðáÃ8�Îu?æLä;Ž���Çq{Šh óRÇ5•¥T”áÅiîFœJÆ“�D*ƒ¬j ÷æ}ÆF?¿³_ ý91ßGy‰„oŒZn)÷¢k:#“aêŠmÜzý>n>´¯ka�^~4®ßï'�NOƒ[« —�$|€‡zˆßþíßæ»ßý.wÜqǺ¯€Ö›Žô�%©ò'''imm妛nZÒs®ÄR÷ìÙ³TVV²sçÎ9ÉܸÉħiZnPRR².»#4àСCË ÍYO$ ZÛÎóÝ—{HÈ*ENN'‡ƒ�@„ ýþœÂ»wtUÓ¦éÌfûóÌUÚ/�þ‚˜ë£¼Ì*T•ÏÅþ­•t ŒQâ�ø?Ü…Ó¹| ]cñî÷ûñûýD"‘œKdV2{ n)ØhÂôÑGyà�øæ7¿É©S§Öýx°ÞØt=ý¥b©=}C°·KÝ‘‘.\¸ÀÎ�;©««›÷qù"Ÿ¦¦&Âá0~¿ŸÎÎNÒé4¥¥¥K ÃY*ŒÐ·Û;}û6ͨ ¦iôôô‰'q—Paµ ¡æ\M¢ˆ®©¤3:£S»|�,ukd¹já1¼É/ ‚°â‘=ÃÎØaµÐÑ7‚Í$ð¡ÛnXá3õ\.— —ËECCCΠʃ³X,¹ÀR+dáf>ÁÞB�ïééa``€ýû÷¯8ÛØåŒ��åÂp\ F塺ºzEñÁëà H–eö8ÈWŸja"§ºÄd}÷'B.ô�“ÉÈDR Iy‘Ò~o¾(Ú«Q°[²I…M•.JfÞ÷Îì¨-_—㩪šƒóûýKrÃË'ü…´>k…§Ÿ~š|àüó?ÿ3÷Ýwߺ¯€6 ×,é§R)ž{î9n¹å–9w 3-uÛI}òp8ÌáÇq¹\+¿€0FÇÇÇ ‡Ã¹Ð�òòòYÙßsÁóÙ±cÇ‚•‡�F¾�¡yøÅ¥~øÒ¬‰"§�TFa"œ ¦´ˆ¶ÞQúÆ'ÉÈÚœcx.«Qˆ$33~R(ë¯'Ü63E.;Çë‹xëöŽ9²nit3a¸á €™¡8N§“‘‘.^¼¸a„ÿÓŸþ”{ï½—¿û»¿ãCúЦY`PÀZàš.﹜û|,·ŸN§s¾ô×_ýš÷Éív;[¶laË–-ÓF»»»q:�9/€™}N]×éëëãòåËW5Ìg.Äãqš››)..fÏž=¹¿Áñ�µÈªÊËû™Œ$±˜MœÜ³…wÞÎ_|ï§\�œsÿ.f Š\6\v ‘$ÅâÛÌ7Ýk{¬Ðn‘ØZQL¹CàØï†>LwÃkll$•Jå„€===˜L&dYfûöí2¡ò /ðþ÷¿ŸÏþóÂ/à ‰M¹Ó—e9W’Ÿº®çæeó-cówø‹•ó!ëdwöìYŠ‹‹Ù½{÷†öÉ�q§ññq�V«5·p»Ýtvv2>>ÎáÇñx<v^‹Áh5ÔÖÖÒØØ8çkœLËcIVsNõýÐÏÛøêgˆ§2ˆ‚€IÑuEÕ‘D«Y¤¡Ô‰¦(\ ¦ˆ§•9~›‹�Ôæ# A`ÊýPB–54]gÏ–rn=²9 ÆkçØÑ#³¬›¯&†††¸téÅÅÅD£Q4MËù”””¬ùâä¿ø§OŸæÏÿüÏùØÇ>V üÞ�Ø<Ÿðe˜±7Ä|+ìùý~ÚÚÚØºu+ þ!7›ÍTUUQUU5m°¥¥UU‘$‰¦¦¦5m5¬ãããœ?~ÑVƒÝjÆn�~SÞUWN±ËN<™F³¶¾&“ˆEÑ€Úªr3Zß(=#AdUcwÞæ�!ŠI0‰"ueEÔ–a6IøÃqDQà¼ï­ ^îD*uqèСM# …¬˜Ö0Þ)))A×õœP¶··—óçÏS\\œkØí«óû?sæ ï}ï{ùÌg>S üÞиfI^÷ߟ)Ø[Œðu]§¿¿ŸžžöìÙ³)ö$I¢¼¼�ÇC4ÍyãwuuqéÒ¥u\ èêêbß¾}”—/_äµ³¦”Ã�UŒ‡bhºŽ$dÃxL¢€ÃfAâI·ÝF}E ‘”‚¬¨Âñ©E]Á’w1;mSH×7Õñ¶ý <ÝÜÃh(Æx8ެ¨XÍ&î8¼ƒ�žÌf3Üt„?³‡/^¯¯×ËŽ;rYÆ´ŒÓéÌU–k˜uîÜ9N�:ÅüÁðñ�¼@ø¼¡±)I©ºüHÜ¥ ö4MãÒ¥Køý~Ž=JQQѪÏw­`„æ”””äòt]'‰0>>¾n£€‹Á˜jäÈ‘#x½Þ=�Å$ñÁwfp"BßXYѰš%JÜlV3Õ>7�H‚ñP §Í‚I‰'3Ô—{ ÇSÄS2r¶²#ÌHå{³Á$‚NÖðH�Zìºlf+‹$*ùÀ͇°šMh¨âÅ }ôŽNRä´s°¡œt`«ÍÎ�6ÄPj©Xªh/?+B–e&&&´´´ Šâ´6ÀB šöövîºë.~÷w—O~ò“Â/à �MÙÓWeI3øÏ?ÿ<;wîÌÍù.ö�•e™ÖÖV2™ ‡ZuIp-111Akk+[¶l™·Õ`Œ“Æ( QX+dz|hšÆÅ‹™œœ\³©†×:yª¥›x*ƒ$ŠhºNM‰‡S'wÓÞ7Î+Ä’ttdEÃf1OÉ„cI6 ‡·U2ólk/êUiú_½ž~¹ÇŽd’ÅRx]vjKÜD“© ån+n3T¸$Žn¯¦¶ºrVLr&“áÌ™38öïßMþBÐ4-×ðûý¤R)|>_n�ÿZ\ºt‰Ûo¿��|ä#üéŸþi�ð xSàš%}]×yõÕW‘e™ªªª\Þ|H$œ={»ÝÎþýû7¥`i¹é}3G=ON¸”QÀÅ ( ­­­¤Ói><톹Z\�¤cÀO4™¡¦ÔÞúl¿ ‘ÊN¤qÙ-˜%‘ÞÑ ‰´ŒÏí ¾¼Iyù|7Ÿþ·gI+ÚUû]Ò·[Lì¬-E4À,‰è:øÜvÞq¨‘·ìÙ‚ ÓœðÂápÎ ¯¨¨ˆK—.áñxØ»wï¦"|c,õÀ�+öǘ 3_‹®®.º»»9vìÿûÿoî¿ÿ~þâ/þbS½°žØ”¤¯ª*Š¢Ìûs£oŒ÷Œ�� sðÓH/ rîÜ9ªªªØ¹sç¦YÑç›­Öe,prrrÁQÀ¥ “ÉÐÒÒ‚ÉdâÀ�:Ƶ�gZÎòdOŒžñ(Ñx:o¼o£±1#{“HS]9¸ù >·ƒÕ%d•DZÆë´a6Í]Â6b’GGG™˜˜@’$ª««)//Çëõn ²[/Ÿ‰L&ÓO>É¿øE^~ùeüà¹ûî»yÇ;Þ±©*°^¸¦H!‡=Ãæs||œ‰‰‰é ‚ÀåË—ijj¢¶¶vC¯c!hšF{{;¡PhÍÍ€\ŠÈ)‘HÐÜÜLQQѦÛÉ{÷îåòdš‡~~žDZf<g,»Ú§·.h¬ôQâqð¿ï{Åîå‘S2™äÌ™39µ»1oŒÀÑ«Qý¥½½�ƒ®+áèïïçÖ[oåÖ[oå}ï{�=ö�>ú(»wïæ'?ùɺ¿€®6®Ò_ŽÃžAz—/_&‘H`µZ©ªª¢¢¢·Û}Õwú²,söìY4MãСCëÒ‹7�? !·˜Ëó<ÓÒÒ²éì~!{ÃîîîÎõ|u]çµÎ!~Þ~…¡‰]ÃÒ•x*s•vý C² UM×M_¼5! à´YÙVUŒÃjáÓxÇÒß/‰D‚3gÎPVVÆ®]»rÏü8¿ßO"‘ÈéCfö¾× µÃ70<<Ì­·ÞÊÍ7ßÌ?ýÓ?åÞûÆk±R�j\KØ”¤¯i²,ç¾6vø†ûÞbD¤ª*çÏŸ'�ràÀ�\ïÛï÷c6›s-€åŽö¬‰---8�Nöïß¿¡£RF* QQUuÚ(àää$mmm466²eË– ;¯Å�?=pøðáYš¦K¥ùúS-t�LÅ ÆPT5—?³Þän»•Š"')EEÓµÜû:–’‘E�¾0‰Yçɲ"«…÷måÃï>ºäãÅãqΜ9Ceeå¢ ¸ùt«IÄ[cccœ?~Ãvø£££Ü~ûí\ýõ<øàƒ›jD±€6›žôWj©+Š"œf©«iZn×ë÷ûs»ÞŠŠŠ éoNv›A[�? 8>>N2™D×ujkkÙ¾}û¦éáëºÎÅ‹ 9rdÁ6H×P€ïü¬�‰Hœ´¬0Mb³˜ØVéãÅ }ÄRò¼¿»d�„åõÀ “( ŠeaI‹ÉÄMû8º³†Ÿ¶]!šÈFH—¸íìk¨ÄŽóóóW˜Œ&IË2¢(â°Z(/r²½¦„ß¼í8eEÎ%�k,ãÌ™3ÔÔÔÌëš8 €‘Šg±XraQkñ9£½½}ì¥ÇÇǹãŽ;8xð ßøÆ76•ˆ·€6›šô�þýR ߘs÷ù|Óüàç;F0Ì‘ž®ëÓv½k½0ntÛ·o§¾¾~MŸ{50vÑýýýTTT�F‰ÅbçÚëÙ~Xš¦ÑÖÖF,ãÈ‘#KZ�LFiéf<£Äíà`cŠ¢ñ¥G_¤c0@dŠh—�D“$a6‹¤Òò”up¶Í$Š"©Œ2ëw [a0‰EN6‹™ß½ç-œØ]ÏD$Á•± ’(°½º—=ûëºÎðD„ΡÃQV3•>7*qØ–– �F9sæ õõõlÛ¶mÙ×›UU™œœÌUV«0vøØŸ˜˜àÎ;ïdÇŽ|ûÛßÞ4‹Ù ¸ZØ”¤¯ª*™L&7¶·}ö¡¡�­[·.kg£ë:¡P(·P…ÒÒR***V퀗ïþ·R'»õ‚aT8|ø0n·XÿQÀ¥ÀˆìU…ǯ*)‘–ù»G_b<£o,Äh0ºh¹_@ÓÁf1Qçsq¸ÞË•± ‰ŒF‰ÇÉÙ>?iUGÓ³æ8†_€E�$i9ë)Š»ëʰ˜MXÍ&þ÷}7Sä\¿~y8¦¹¹9g-½–X­`£ ? ñž÷¼‡ÚÚZ¾ÿýï¯y�V\‹Ø”¤ÿñøý~î¾ûnŽ9² éæ'ÑíÝ»—ŠŠŠU;¿ì=666ͯ¬¬lY;]×éèè`llŒC‡m*÷?UUimm%™LräÈ‘yoØk= ¸ä� ø ?ùÉOðù|Ü}÷Ýœ>}šãÇ�O[ä[ꮩêºN,Ëíz��MEEeee – óIõðáÛj8“É䢄:´ä’gþ(àÄÄD®×»ÔQÀ¥ ™LÒÜÜŒÛífß¾}kÖfÑu�ŽÁÍÝÃLDâH¢ÈóíW˜Œ$Ðt�UEÕ1›D\v+ •ÅÜ}b77îkÀb’r}òªª**kêyìåó4w K$u]4Íh¤ ³$QáuSésQæurÝ®:öÖ—¯›Ž# ÒÒÒ²hÒz!_011�ÙlεË2™ íííFø±XŒÓ§Oãp8øÑ�~´©>{pµ±)Iß@"‘àÉ'Ÿä¡‡â?þã?p:�Üu×]œ>}šÆÆF~í×~�ßø�ßàž{îÙ�•|¾n4�·ï�N§§íT7SÑ U—Ëž}ûVܺ0F�Rïb£€KA,£¹¹™²²2šššÖUè¨ë:�¿ÚÉÃ/¶3Š¡¨fIäPc¿yÛqŠÝ3¢˜=c”±¾¾~šMr4™&‘’±¡à—® ˜ S[^LC]5eee8�Kß­œ;wŽ�;wn /Š|ÀØØŠ¢P\\Lmm-¥¥¥ë*¤‹Çã¼ï}ïC{ì±M•PY@››šôó‘J¥øÏÿüOzè!~ðƒ�F)++ã‹_ü"·ÝvÛ†ë̾wQQ8�N.\¸@qFÿ,IDATqñ¢bÂ�F$¡¥¥…ŠŠŠi3Û«…¦iÓ4Æ(`YY¥¥¥KZX“ uuulÛ¶mC&t]§<ÄÅ?‰´Ì®Ú2vוåˆÞÀää$gÏž]²Óh‰øý~&''±Ûí¹]¯ÇãYÓk ´¶¶ÒÔÔDuuõš=ïZ`||œÖÖV¶oߎ,Ëëî�L&¹÷Þ{I¥Rüä'?Áãñ¬ÙsPÀ× éxî¹çxßûÞÇ;ßùN<ÿñÿ�¢(¼ç=ïáôéÓÜtÓM.ØI§ÓŒ��344D4ÅjµRWW7ËøjÂØ ýÞõ"Õ™£€©TŠ’’’\¯w®Å™A\›m²Àï÷ÓÖÖÆ®]»¨©©Yöï+Š2ÍI’¤Ü`¥‘üskmmeïÞ½›":ããã´µµ±ÿþiâÕD"‘Óˆ:ãõX�F$�Nsß}÷199É“O>Y0Ú) €ypM‘þøø8;wîä¯ÿú¯yà�€ìMõç?ÿ9ßÿþ÷yä‘GˆÅbÜyç�œ:uŠw½ë]&àæâÅ‹ìØ±I’fÙU€«1›oX×.7Ðgµ˜+pfKäj�ÛR`XÄ®©ÎeŽ´Òñ7C·oß¾U‹W×óþĻ(++[Ö‚(“Épÿý÷344ÄÓO?½ª ‹ x£ãš"}ÈÞP滑¨ªÊK/½”kLNNrÛm·qêÔ)n¹å–ué­êºÎåË—éïïçÀ�Ó"AgzàÛl6***(//ß;`c²¡··wÖ¹] Ìl‰X­VÒé4»wï^Ñ.z=144DGGǺÈc�H$())É‘ÞBÞFíF™Û,K%ü™˜ÏÀhÍ· ’e™_ÿõ_§»»›gžyfCÜý (àZÆ5GúK…¦i¼öÚk|ÿûßç?øÃÃÃÜrË-œ:uŠÛo¿=7“¾Úc\¸p�`0¸hhŽªª¹ÀFØç� >|xSõ7u]§««‹ÁÁA\.‘HdCF—о¾>zzz8tèІígÚàÞ3…€ÃÃÃ\ºtiU™óë…•þL̵ šK ( ùÈGhkkãÙgŸÝt� ØŒxÃ’~>4Mãܹs¹@oo/ïz×»¸ûóÎ;WDº²,O3�YŽk�±«1v½’$åo-lN�ì�å8Ùmt]Ï�Y¶ºFEd¦íëZŽ.õÜ._¾ÌÀÀÀœÿ…|!àÄćƒòòòœÑÓáÇ7] {­.:¿ßO(â¯þê¯Ø»w/½½½ôôôð³ŸýlÓµ† (`³âMAúùÐu�öööÜàÒ¥KÜtÓMœ>}š÷¼ç=ø|¾EI&™LÒÒÒ‚Ýngÿþý«AšÏ¸¢¢ŸÏ·ì€‘à§ë:‡ÚT.dš¦å‚�æ[Œä/ˆŒQ@ãõX­ðm!Õ‡‘‘Ž=ºiF½ !à•+WˆD"˜Íæ\‹h=_�å`= &R©_ùÊWøâ¿Èèè(555ÜsÏ=œ:uŠ·½ím›j<¶€6#Þt¤Ÿ]×éìì䡇âá‡æÜ¹sÜxã�œ>}š»îº‹òòÙf*áp˜³gÏ®ùØ›q>3í€óó}K¥R477ãp86<Áo1¬ÄVw®Q@Cø¶ÔQÀ¥Àõ™˜˜àèÑ£›fâ€á8yðàAt]Ï-ˆV#\+Aø�}Oüþïÿ>�?þ8O<ñ===<úè£<úè£|ík_ã–[nY÷s( €kojÒχ®ëôöö毽ö'OžäÔ©SÜ}÷ÝTWWóÍo~“@ ÀéÓ§©¯¯_wó˜¹ì€+**æ6aC¥¥¥455mŠ �µ°Õ]É(àR�_}8zô観kííí¥¯¯�#GŽLÓeÌì{'“Éi}ï�I2£&4Mãþàxä‘GxöÙgÙ¾}û´Ÿ›ê}_@›ÒŸº®300ÀÃ?ÌÃ?ÌK/½Duu5ÃÃÃ|æ3Ÿáãÿø† Íòí€ÇÆÆr7xÃ8�rîÜ9¶lÙ2Í-n3Àh…8�Nöïß¿&7å…F—cøbX%§R)Ž=º©Z!ùú‚£G�.*<5„€ãããD"ŠŠŠrU¢õ¨\\ Âÿã?þc¾ùÍoòì³Ï²k×®u?f¼Q ýE ( ¿ýÛ¿Í·¿ýmvìØA[[äÔ©Sœ:ujÙYåkƒðÆÆÆˆÅbèºNUU;vì¸j1¸sa£lu“ÉdÎòu©©€F»AUU>¼©zÁº®ÓÝÝÍðððŠôó ËÊÊÖÄp£ _×uþüÏÿœ¯|å+<óÌ3ìÝ»wÝ�Y@oTHÜÿý¼òÊ+üøÇ?fÛ¶m~ðƒððÃóÌ3ϰ{÷nN�:Åéӧ׼ǿúúúèî²’x<žÛáB¯«Yª6¼êkkk7ta”Édr=ï|s¤üQ@Y–iiiA’¤5Kñ[+:“±±1Ž=ºjo EQ¦MF“"Ë5À1p5ÿ¯þê¯øÒ—¾ÄþçrðàÁu?f¼‘Q ýEðÓŸþ”ýû÷Ï‘Òu�`0ÈøC~øažzê)¶mÛÆ©S§¸çž{ÖÕwßPšO-K¥R¹o0\ÒŽw=`Xþ^m[]ƒð s$‹Å‚ÏçËE8p`S‰�qÆ@ °.‚ÂüI‘•¯áÿíßþ-ŸûÜçxê©§8zô躳€Þè(�þ!ó£ýˆ‡~˜'žx‚êêê\àСCk¶Ð4�öövÂá0GŽ™—2™L®äm�œQXÏq4úv³ÙꪪÊèè(hš6-úu%£‘k c‚`rr’£G�®»·B¾0Òï÷çt"F`¦¾ÁÈ Ø»wï†þ—¿üeþìÏþŒ'žx‚믿~Ý�Y@oH‹Åøñ�ÌC=Ä�ücJKK¹ûî»9}ú4Ç�_1ÁȲLkk+Š¢pèС%÷ïgÚÛíö\`-í€èêêâÀ�›Î5�ÓÜÜLII »ví"¯û(àRaxG„Ãá«6A°�0�oøÿ«_ý*Ÿþô§yì±Çxë[ߺîÇ, €7 ¤¿ÎH$<ñÄ<ôÐC¹|ï»îº‹Ó§OsòäÉ%L*•¢¥¥«ÕÊ�V܇6ì€ÇÆÆÖÌý.?àðáÛ.á,�ÒÜÜœ;æ_ãz�.ÆÈ`,ãèÑ£›BˆiÇÇÇ™œœÌFmÛ¶mÝ3#t]çßøŸüä'ùÑ�~ÄM7Ý´nÇ* €7# ¤¿�H¥R<ýôÓ<üðÃüð‡?Äb±ðž÷¼‡{·¼å-óL,£¥¥ŸÏÇîݻ׬½vÀ†ÇÿøøxÎVw3!ÓÜܼäqFc4r5£€K…¦i´µµ‘H$6ÝÈ d#�Ï�;GMMM®Z´Z!àBÐu�o}ë[|âŸà‘Gá]ïzך=w�E�ô¯dYæÙgŸå¡‡â‘GAÓ4î¼óNî¹çÞþö·ç ¥¥…`0H}}ýºªà ‘רØ~¿]×s €ùzÞK±Õ½š˜œœäìÙ³+£€ããã„B¡yCpVÃ# �NsäÈ‘MIø­­­ìÙ³'+¬iZ. o||MÓrf@káøýïŸ�}ìc|÷»ßåŽ;îX‹Ë( €f @ú›Š¢ðüóÏóýïŸGy„D"Á�wÞ‰×ëå«_ý*ÿöoÿÆí·ß¾açcØ���åzÞ3í€E¡µµ•L&³)IËžíÚµkMb{ aäøøxnÐÈXn* ªªÓ,‰7“GÌMø3±\!àbøáÈoþæoò­o}‹»ï¾{-.£€ ˜ÒßdPU•_|‘?ú£?â¹çžÃjµr÷ÝwsêÔ)n¹å– ÷…ŸiœÉdðù|Äb1l6‡ÚTsîðúÁz ÏfŽ1ÉF[d¡€ªª´´´ ë:‡Þt¯ÝR.†Q~¿?'4‹½g{ì1>üáó¯ÿú¯¼ï}ï[í%P@  @ú› º®óéOš/ùËüð‡?Äl6çGGGy÷»ßÍéÓ§¹í¶Ûµf]�s›˜˜àüùóhš†®ë*z[ éììܰ ‚ùRçj‹(ŠBKK ‚ lÊŒᯰ{÷îU�[ÎU‘¹¦Ežzê)>øÁòÏÿüÏÜwß}kqPÀ(�þ&C4åÞ{ïå _øMMM¹ïkšÆÙ³gs €+W®ð®w½‹S§NqÇwlHî|þØÛîÝ»I$Óì€�ònyyùU)÷it‡¢¸¸xÃ�¿P* Çã¡­­-:´™L�`í&dYfbbbZUäå—_f×®]Øl6~õW•¿ÿû¿çþûïßT™ðFE�ô¯AèºÎùóçs €ŽŽn¾ùfNŸ>Í�wÞ‰Ïç[óèb¶ºÉd2§ˆD"x½ÞÜ`½çÎóÃiò ¯&fŽ& , ���TTTlŠªˆ�õ"ü™0„€Ÿþô§ùÁ~@4åĉü÷ÿþß¹í¶Û6ÝäG¼Q ýkÆÈœ ÜÖÖÆ�7ÞÈéÓ§¹ë®»(++[õ`¹¶º†ðØØØ4ÕûzØ^õ£££+ §Yod2Μ9ƒÅb¡¸¸¿ßO4]×QÀå`£?/¿ü2§OŸæ#ù&“‰Gy„¾¾>¾üå/óë¿þërðfE�ôß@0v¼ÆàÌ™3œ}šS§N±mÛ¶YÖ´ëm««( +²ÞìÆ6Éd’3gÎP\\Ìž={–Ln«\®áŸ?ž;O|âü¯ÿõ¿ „_@W Ò“A×uÆÇÇyä‘Gxøá‡yöÙgÙ½{wn°}ûv~çw~‡#GŽpß}÷mÈX 1öf¸æÛO#EQ8{ö,š¦mJc›D"Á™3g(--¥©©iÅä¶œQÀåÀp)ljj¢ººzEϱ\\¼x‘;�~ô£üÉŸüI�ð (à*¢@úobèºN0ä‡?ü!=ôO=õT.ðå+_ù wÜqdžGÎ.dìv»9{ö,&“‰C‡mº±·x<Ι3g¨¨¨`çÎ�kFnù£€~¿EQr£€Ë±¿½„ßÕÕÅm·ÝƇ>ô!>ûÙÏ^õã x³£@úYÂ:uê===ìÚµ‹ŸýìgÔÖÖrêÔ)NŸ>ÍÁƒ7ü†�ol¸Z­VvîÜIYYÙ¦"ýX,Æ™3g¨®®fûöíë¶›5F €a[QQAiié¼­Ž«Aø—/_æöÛoç}ï{Ÿÿüç „_@›Ò/]×¹ùæ›E‘Gy�ÇC4åÇ?þ1=ô?ùÉO(--åî»ïæž{îáØ±czO&“¼öÚk8\.~¿ŸL&“Ûí–––^Uw»h4Ê™3g¨««›¥�Xoö·ããã¹Q@£ `ˆ¯á÷õõqÛm·qç�wòw÷wÂ/ €M‚éÀÏþsŽ;6§ >‘Hðøã�óÐCñØc�áñx¸ë®»8}ú4'NœX×·á˜ß#×u�X,–3J&“WÍ8‰L‹î½š˜9 èv»q»ÝŒŒŒ°{÷î #ü¡¡!n½õVÞùÎwò�ÿø�Â/ €M„é°,¤R)žzê)~øa~øÃbµZ¹ë®»¸çž{xË[Þ²¦;îh4Jssó¢%óxüÿßÞ½ÅDuµoF­Aj)¸Û*‚@0J…1%j«ˆJE™ÐÄ›’VKÒzÑÆS{HMk,5±1Ú´ôôAˆí…mgC)A;RK+ÐD$m9†âÊI$göwñÏìAð™Ã†y~—ÛÈzñÂg­½×z× <pe;àþþ~ÔÖÖ"$$ÁÁÁNçAŒŽŽ¢µµmmmP©T.; xóæMìÚµ 7nDNNŽ¢>ÁCŸfattf³¢(Âd2A’$$%%A¯×cëÖ­³ ܾ¾>ÔÕÕ!88xF+hû}ÎnÜÛÛ‹ß~û ¡¡¡Šl(c¥A\r°³³»wïÆO<�¯¾úJq CŸd||0 0™LBRRt:âããg¸öÀºß¶¿Ó–'ÿn,–,YòÀ?×^_xx8V­ZõÀ?ÇYþø+W®œðg“��'³9 ØÝÝ�={ö ,, gÏžUÜQJ"ú? }r8«ÕŠªª*ˆ¢ˆ¼¼<ô÷÷#11:�;wî¼g»Ü®®.\½zÕá›ÎÕØÞØÆ•›âf¢··uuuSþdö£€ö}cccò&À™ìíí…F£ÁªU«`0×,‰ˆþCŸœÊf³á—_~‘o¼uë ×ëïºY­±±‹k×®… N«illlBë[{;`A°téÒi_wÛ'$®ìd73 üÉ$IÂÀÀ€<1²´oŽœ.Èûûû¡Õjáïï“É$÷y "ebè“ËØl6ÔÕÕÁ`0Àh4¢½½Û·o‡^¯GKK rrrPYYéÒôäÖ·ÓµîììÄÕ«W�>!yP³ ü©L> 8ÕÞˆ��$''ÃÛÛ³údBD®ÁÐ'·�$ õõõøî»ïðå—_ÊW㦧§#))é®ö»®`µZÑÝÝ-ï¶·^´hZ[[…+V¸´¦ûa|gí1ø÷ÞˆŽŽ;v qqqøù矱téR¹ôv@"zp }rI’ðî»ïâ“O>ÁçŸކ†äå塾¾[¶l�N§ƒF£A@@€Ë'6› ===hmmEoo/-ZAf½áÍÑœøS�—““ƒ“'O¢¿¿HMMEJJ ¢££ÙWŸHá”ñ?y¤ššdgg£¢¢©©©xç�wPSSƒ††ìܹ_ý5°{÷n|öÙg¸~ý:\5G]°`FFFpûömDGGËmˆpñâEÔ××£³³V«Õ%õLÅÕ�K–,Á¥K—‹Å‚£G�¢¹¹qqq¨­­uI JTQQ�FƒÇ*• &“ÉÝ%M‰+}r«ÁÁÁi_ K’‹ÅQa4Q]]�'Ÿ|Z­:����N[Y¶··£±±ëׯ‡ŸŸß„šúûûå×ÝövÀ‚ ÌhÇûlõõõ¡¶¶Ö¥�?::Šçž{7nÜ@YYÙ„—‘‘,^¼ØcWúÅÅŨªªBLL RSS‘——½^ïîÂЧ9A’$\¿~F£F£—.]Âúõëå+�CBB8‹ÍÍÍˆŽŽ†¯¯ï=krG;`wþØØ^xá´´´àÂ… ð÷÷wɸs‘J¥bè“b1ôiΑ$ ·nÝ‚Éd‚ÑhDyy9Ö¬Y#Ofs­mkk+þúë/ÄÄÄÀÇÇgF÷Î�;ògµ¶w* sYà���#==×®]ƒÙlVäfF%aè“’1ôiN“$ ===ÈÏχ(Š8þ<ÂÂÂä+�###ï{Ó]KK , bbb°lÙ²YÕåŒvÀöÀ_½z5gUßý²Z­8pà~ýõW”——+²?�Ò0ôIÉú4oØ¿·ÿý÷0�(--E`` |%pTTÔ”I’ÐÜÜŒŽŽ¨Õêu軎hìŽÀ·Ùlxå•WPYY ³Ùì²qç:†>)CŸæ­��BEcÅŠò@­VcÁ‚°ÙlòuÁ6lpúyóéÚ ‚0íØî üŒŒ ”––Âl6+îA%cè“’1ôÉ# ¢¤¤¢(¢°°>>>Ðh4øã�?P__�+W®LØ�î ÷ÓØ]�ÿæ›oÂd2¡¼¼¡¡¡.w¾`è“’1ôÉã áܹs8|ø0ñÈ#� %%ÉÉÉØ´i“[®„�ª°��ºººf}ÛàLØl69rgÏž…ÙlFDD„KÆ�ëîܹƒ¦¦&@tt4Nž<‰mÛ¶ÁÏÏO‘W/“çbè“DZZ­HOOGee%JJJÐÔÔQa2™ R©�””½^�-[¶¸åÆ8«ÕŠööv455A¥Rᡇ’ßøúú:í,¼$I8vìrrr`6›±fͧŒ3•——cÛ¶mw=þùç‘››ëú‚ˆ¦ÁÐ'�ÓÔÔ„´´4ˆ¢8árŸññq\¼xƒ&“ ###HJJ‚N§C||¼Ën�ëïïGmm-V¯^�•+W¢§§GÞ R©A°|ùr‡µ–$ 'NœÀÇŒüQQQù¹D¤, }òH’$ÝsÅlµZQUU%_ <00€]»vA¯×cÇŽðöövJ]öÀ ½ëµ°ÍfC__Ÿ<°Z­òÀÏÏ .| 1%IÂéÓ§ñᇢ¬¬ jµÚ¿ )CŸè°Ùl¨®®–']]]HHH€^¯Ç3Ï<ã°#~÷ üÉîÕØßßÿ¾'’$!++ ™™™())All¬#~"R(†>Ñ Øl6ÔÖÖÂ`0Àh4âï¿ÿÆŽ; ×둘˜ˆeË–=Ð7÷™þd’$a``@žØÛÛ'Óµ–$ ÿùÏpäÈaóæÍ3®›ˆæ†>ѲÙl¨¯¯—'MMMˆ��‡N§Ãž={°|ùòûšÌ&ð§2U;`A oL”$ gΜÁë¯¿Ž‚‚ÄÅÅÍz\"R>†>‘H’„ßÿ]ž\»v [·n…N§ƒF£�¿¿ÿ”Gþd“Ûûí· �··7Þÿ}äççcûöí—ˆ”‰¡Oä`’$ÉÇ�F#êêê°yófèt:hµZ<úè£P©T¸|ù2º»»±nÝ:9½®ááa|ôÑGÈÍÍE[["##ñâ‹/"%%!!!NŸˆÜÏ1ç}ˆH¦R©†7ÞxÕÕÕhll„F£�Á`@DD�‘‘­V‹¶¶6—>xyy!<<]]]ÈÍÍÅÁƒQZZŠððpdffº¤"r/®ô‰\D’$tttàôéÓ8uêl6Ôjµ|%ppp°ÓïÀ?ü€}ûöáÌ™3HMM•Ÿ÷ôô`xxxBÏ"šŸ¸Ò'r•J…ÎÎNdggãøñãèèèÀ¾}û`6›�§žz 'NœÀŸþ GÏÅÏ�;‡ýû÷#;;{Bà€ŸŸŸÈCp¥OäB‡Âc�=†ŒŒ ù™$IèîîF~~>DQÄ… �N½^�ÈÈÈY½0›ÍØ»w/²²²�––æÔ· D¤l }"ú_�%IB__ Š"JKK$_ ¼nݺµÞ­¬¬Ä³Ï>‹S§Naÿþý |"ÇÐ'R°Û·o£°°¢(¢¤¤‚ È€˜˜˜{N._¾Œääd?~`àCŸh®Dqq1DQDQQ|}}¡Õj¡Óé;¡õî•+W ÕjñÞ{ïáÕW_eà†>Ñœ444„ÒÒR�FÀËË Z­z½?ü0´Z-Þzë-:tˆ�OD2†>Ñ7::ŠóçÏÃh4"//½½½8|ø0233øD4CŸhCvv6^zé%>Ý…¡ODDä!Øœ‡ˆˆÈC0ô‰ˆˆ<CŸˆˆÈC0ô‰ˆˆ<CŸˆˆÈC0ô‰ˆˆ<CÉÊÊBHH¼¼¼ V«QYYéî’ˆˆHAúóÄ7ß|ƒƒâí·ßF]]ž~úi$&&Âb±¸»4""R6ç™'bccƒO?ýT~ ½^�>øÀ�•‘Rp¥?ŒŽŽ¢¦¦ ž'$$à§Ÿ~rSUDD¤4 ýyàŸþ�Õj… ž ‚€›7oº©*""R†þ<2ù‚I’xé Éú󀿿?.\xת¾³³ó®Õ?y.†þ<°xñb¨Õj”••Mx^VV†M›6¹©*""RšEî.€ãµ×^CZZ6lØ€�7â‹/¾€ÅbÁË/¿ìîÒˆˆH!úóÄÞ½{ÑÝÝ�£G�âÆ�X»v-ŠŠŠäîÒˆˆH!xNŸˆˆÈCð›>‘‡`èy†>‘‡`èy†>‘‡`èy†>‘‡`èy†>‘‡`èy†>‘‡`èy†>‘‡`èyˆÿ¾ûZsÁ •IEND®B`‚scikit-bio-scikit-bio-a3beaa6/web/_static/img/logo.svg000066400000000000000000000144751520735541300230260ustar00rootroot00000000000000 image/svg+xmlscikit-bio-scikit-bio-a3beaa6/web/_static/img/logo_inv.svg000066400000000000000000000144751520735541300237020ustar00rootroot00000000000000 image/svg+xmlscikit-bio-scikit-bio-a3beaa6/web/about.rst000066400000000000000000000122131520735541300207730ustar00rootroot00000000000000:html_theme.sidebar_secondary.remove: About scikit-bio ================ scikit-bio (canonically pronounced *sigh-kit-buy-oh*) is a library for working with biological data in Python. scikit-bio is open source BSD-licensed software that is currently under active development. Adoption -------- Some of the projects that we know of that are using scikit-bio are: - `QIIME 2 `_, `Qiita `_, `Emperor `_, `tax2tree `_, `ghost-tree `_, `Platypus-Conquistador `_, `An Introduction to Applied Bioinformatics `_. License ------- scikit-bio is available under the new BSD license. See :repo:`LICENSE.txt ` for scikit-bio's license, and the :repo:`licenses directory ` for the licenses of third-party software that is (either partially or entirely) distributed with scikit-bio. Team ---- Our core development team consists of three lead developers: **Dr. Qiyun Zhu** at Arizona State University (ASU) (@qiyunzhu), **Dr. James Morton** at Gutz Analytics (@mortonjt), and **Dr. Daniel McDonald** at the University of California San Diego (UCSD) (@wasade), and one dedicated software engineer: **Matthew Aton** at ASU (@mataton). **Dr. Rob Knight** at UCSD (@rob-knight) provides guidance on the development and research. **Dr. Greg Caporaso** (@gregcaporaso) at Northern Arizona University (NAU), the former leader of the scikit-bio project, serves as an advisor on the current project. Credits ------- We thank the many contributors to scikit-bio. A complete :repo:`list of contributors ` to the scikit-bio codebase is available at GitHub. This however may miss the larger community who contributed by testing the software and providing valuable comments, who we hold equal appreciation to. Wanna contribute? We enthusiastically welcome community contributors! Whether it's adding new features, improving code, or enhancing documentation, your contributions drive scikit-bio and open-source bioinformatics forward. Start your journey by reading the :doc:`Contributor's guidelines `. Funding ------- The development of scikit-bio is currently supported by the U.S. Department of Energy, Office of Science under award number `DE-SC0024320 `_, awarded to Dr. Qiyun Zhu at ASU (lead PI), Dr. James Morton at Gutz Analytics, and Dr. Rob Knight at UCSD. .. image:: _static/img/doe_logo_green.png :class: only-light :alt: DOE SC logo .. image:: _static/img/doe_logo_white.png :class: only-dark :alt: DOE SC logo .. The DOE SC logo was downloaded from: https://science.osti.gov/About/Resources/Logos .. The webpage stats the following usage policy: "The DOE SC co-Branded logos should only be obtained directly from the download links on this page. Only unaltered usage is permitted. Usage does not require explicit permission. The logos shall not be used in any manner that falsely implies employment by, or affiliation with, the U.S. Department of Energy Office of Science. Additionally, the DOE SC co-Branded logo may not be used for commercial purposes, including but not limited to endorsement of products or services." Citation -------- If you use scikit-bio for any published research, please cite: Aton, M., McDonald, D., Cañardo Alastuey, J. et al. Scikit-bio: a fundamental Python library for biological omic data analysis. *Nat Methods* (2025). https://doi.org/10.1038/s41592-025-02981-z The full text of this article is available at: https://rdcu.be/eUcOO. Collaboration ------------- For collaboration inquiries and other formal communications, please reach out to **Dr. Qiyun Zhu** at qiyun.zhu@asu.edu. We welcome academic and industrial partnerships to advance our mission. Branding -------- The logo of scikit-bio was created by `Alina Prassas `_. Vector and bitmap image files are available at the :repo:`logos ` directory. Pre-history ----------- scikit-bio began from code derived from `PyCogent `_ and `QIIME `_, and the contributors and/or copyright holders have agreed to make the code they wrote for PyCogent and/or QIIME available under the BSD license. The contributors to PyCogent and/or QIIME modules that have been ported to scikit-bio are listed below: .. dropdown:: Rob Knight (@rob-knight), Gavin Huttley (@gavinhuttley), Daniel McDonald (@wasade), Micah Hamady, Antonio Gonzalez (@antgonza), Sandra Smit, Greg Caporaso (@gregcaporaso), Jai Ram Rideout (@jairideout), Cathy Lozupone (@clozupone), Mike Robeson (@mikerobeson), Marcin Cieslik, Peter Maxwell, Jeremy Widmann, Zongzhi Liu, Michael Dwan, Logan Knecht (@loganknecht), Andrew Cochran, Jose Carlos Clemente (@cleme), Damien Coy, Levi McCracken, Andrew Butterfield, Will Van Treuren (@wdwvt1), Justin Kuczynski (@justin212k), Jose Antonio Navas Molina (@josenavas), Matthew Wakefield (@genomematt) and Jens Reeder (@jensreeder). scikit-bio-scikit-bio-a3beaa6/web/conf.py000066400000000000000000000061421520735541300204320ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # Configuration file for the Sphinx documentation builder. from datetime import datetime # -- Project information ----------------------------------------------------- project = 'scikit-bio' author = f'{project} development team' copyright = f'2014-{datetime.now().year}, {author}' # -- General configuration --------------------------------------------------- extensions = [ 'sphinx.ext.extlinks', 'sphinx.ext.autosectionlabel', 'sphinx_design', 'sphinx_copybutton', 'sphinxcontrib.youtube', 'sphinx_sitemap', ] root_doc = 'index' templates_path = ['_templates'] exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # -- Options for HTML output ------------------------------------------------- html_title = project html_short_title = project html_baseurl = 'https://scikit.bio' sitemap_url_scheme = '/{link}' html_logo = '_static/img/logo.svg' html_favicon = '_static/favicon.ico' # static files html_static_path = ['_static'] html_css_files = ['css/style.css'] # do not show side bar with section navigation html_sidebars = {"**": []} # do not show source links html_show_sourcelink = False # link to document:section autosectionlabel_prefix_document = True # -- External links ---------------------------------------------------------- github_url = f'https://github.com/{project}/{project}' twitter_url = 'https://twitter.com/scikitbio' extlinks = { 'home': (f'{html_baseurl}/%s', None), 'repo': (f'{github_url}/%s', None), 'docs': (f'{html_baseurl}/docs/dev/generated/skbio.%s.html', None), } # -- PyData Theme configuration ---------------------------------------------- # References: # https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/layout.html# # references html_theme = 'pydata_sphinx_theme' html_theme_options = { # logo image for light/dark modes # image files must be placed under _static/ 'logo': { 'alt_text': html_title, 'image_light': '_static/img/logo.svg', 'image_dark': '_static/img/logo_inv.svg', }, # announcement banner on top of the screen 'announcement': ( "scikit-bio is participating in Google Summer of Code 2026. Join us" "!" ), # social media links displayed as icons 'github_url': github_url, 'twitter_url': twitter_url, # disable prev & next buttons 'show_prev_next': False, # disable search button 'navbar_persistent': [], # display all header links 'header_links_before_dropdown': 8, # footer layout 'footer_start': ['copyright'], 'footer_center': ['sphinx-version'], 'footer_end': ['theme-version'], # google analytics 'analytics': { 'google_analytics_id': 'UA-6636235-9', } } scikit-bio-scikit-bio-a3beaa6/web/contribute.rst000066400000000000000000001072731520735541300220520ustar00rootroot00000000000000Contribute to scikit-bio ======================== :bdg-info:`New` :doc:`Roadmap of scikit-bio ` **Scikit-bio** is a community-driven open-source software project, and we warmly welcome your contributions! We are interested in many types of contributions, including feature additions, bug fixes, continuous integration improvements, and documentation/website updates, additions, and fixes. Whether you are a researcher, educator, or developer; whether your interest lies in biology, mathematics, statistics, or computer science; your input is invaluable. You can help making scikit-bio a better software package for our entire community. This document covers the information you may need to get started with contributing to scikit-bio. In addition, for a broader perspective, we recommend the inspiring guide: `How to Contribute to Open Source `_. Visit our GitHub repository: :repo:`scikit-bio/scikit-bio <>` for the source code of scikit-bio. You will need a GitHub account to interact with the scikit-bio codebase and community. Valuable contributions can be made without or with minimum amount of coding. We detail various ways you can contribute below: - `Ask a question`_ | `Report an error`_ | `Suggest a new feature`_ | `Fix a typo`_ Contributing code to scikit-bio is a rigorous and rewarding process. We have prepared the following step-by-step guidelines: - `Before coding`_ | `Set up a workspace`_ | `Write code`_ | `Test code`_ | `Document code`_ | `Style code`_ | `Submit code`_ | `Review code`_ .. .. contents:: .. :depth: 1 .. :local: .. :backlinks: none In addition, there are separate documents covering advanced topics: .. toctree:: :maxdepth: 1 devdoc/code_guide devdoc/doc_guide devdoc/new_module devdoc/review devdoc/release devdoc/array_api Ask a question -------------- Your inquiry matters! By asking questions in the scikit-bio :repo:`issue tracker ` or :repo:`discussion board `, you are not only giving us (and the community) the chance to help, but also let us assess the needs of users like you. Before asking a question, take a moment to search existing threads to see if there are any relevant ones. We also keep an eye on broader community forums such as Stack Overflow and BioStars for questions related to our scope. Report an error --------------- The scikit-bio team is proud of our high-quality, well-tested codebase. That being said, no software is immune to errors, which may arise from bugs, overlooked edge cases, or confusions in documentation. In any situation, we would appreciate it if you can report the error you encountered to us. You may :repo:`open an issue ` to report the error. Please provide a detailed description of the error such that the developers can reproduce it. Specifically, you may include the following information in the report: 1. The exact **command(s)** necessary to reproduce the error. 2. The input **file(s)** necessary for reproducing the error. You may either attach the file in the issue (by dragging & dropping) if it is small, or provide a link to it otherwise. The file should only be as large as necessary to reproduce the error. .. note:: For example, if you have a FASTA file with 10,000 sequences but the error only arises due to one of the sequences, create a new FASTA file with only that sequence, run the command that was giving you problems, and verify that you still get an error. Then post that command and link to the trimmed FASTA file. This is *extremely* useful to the developers, and it is likely that if you don't provide this information you'll get a response asking for it. Often this process helps you to better understand the error as well. We take error reports very seriously. Once confirmed that they should be fixed, we will update the code to fix them as soon as we can, and ship the update in the next scheduled release of scikit-bio. If the error could result in incorrect results or inability to access certain functionality, we may release a bug-fix version of scikit-bio ahead of the schedule. Suggest a new feature --------------------- We are always looking for new ideas to enhance scikit-bio's capabilities, especially from users with unique research interests. If you believe there is an analysis or feature that could extend scikit-bio's current offerings, we warmly invite you to share your suggestions with us. Please describe why the functionality that you are suggesting is relevant. For it to be relevant, it should be demonstrably useful to scikit-bio users and it should also fit within the biology/bioinformatics domain. This typically means that a new analytic method is implemented (you should describe why it's useful, ideally including a link to a paper that uses this method), or an existing method is enhanced (e.g., improved performance). If the scope of the suggested method overlaps with any pre-existing methods in scikit-bio, we may request benchmark results comparing your method to the pre-existing ones (which would also be required for publication of your method) so pointing to a paper or other document containing benchmark results, or including benchmark results in your issue, will help. Before suggesting a new feature, it is also a good idea to check whether the functionality exists in other Python packages, or if the feature would fit better in another Python package. For example, low-level statistical methods/tests may fit better in a project that is focused on statistics (e.g., `SciPy `_ or `statsmodels `_). If your proposal represents a significant research direction or requires a substantial suite of methods, we encourage you to consider establishing a formal academic or industrial collaboration with the scikit-bio team. For more details on this process, please refer to the :ref:`about:Collaboration` section. Fix a typo ---------- If you spot small errors such as typos, redundant spaces, broken links, missing citations etc. in the scikit-bio code or documentation, and want to give it a quick fix, you may follow the procedures detailed below. All procedures will take place in the web browser, and don't involve creating anything in your local computer. .. warning:: This approach should not be applied to anything larger than small errors. For the latter, please read `Before coding`_. 1. Locate the specific code file that needs to be fixed in the GitHub repository. If you are reading the documentation, you can click the `[source] `__ link next to the header to locate the corresponding code file. 2. In the top-right corner of the code viewer there is an Edit (:octicon:`pencil`) button, with a prompt "Fork this repository and edit the file". Click it. Then click the button :bdg-success:`Fork this repository`. This will open GitHub's `online file editor `_. 3. **Edit the code**. 4. When done, click :bdg-success:`Commit changes...`. Then enter a commit message to describe what you did, like "Fixed a typo in the documentation of skbio.module.function". Then click :bdg-success:`Propose changes`. 5. You will be able to review the changes you made and compare with the original code :octicon:`git-compare`. If everything looks good to you, click :bdg-success:`Create pull request`. Then enter a title and description that you think are informative to the scikit-bio maintainers. The **title** may or may not be the same as the commit message. In the **description**, you will need to answer a few questions by typing an ``x`` in the relevant checkboxes. You may also explain why the original code should be replaced by yours. Finally, click :bdg-success:`Create pull request`. 6. This will create a `pull request `__ :octicon:`git-pull-request`, i.e., the changes you made to the scikit-bio repository. A scikit-bio maintainer will review your pull request, and run necessary tests to make sure it is sound. You may be asked to clarify or to make modifications to your code. Please work with the maintainer by replying in the pull request. 7. If the maintainer believes that your code is good to go, they will `merge `_ it into the scikit-bio codebase. Once merged, the pull request webpage will have a purple notice :octicon:`git-merge`, saying: "Pull request successfully merged and closed". 8. At this point, your contribution is completed 🎉. You may optionally click :bdg-light:`Delete branch` to clean up your workspace. Then, you can move on, and enjoy the improved scikit-bio! Before coding ------------- We sincerely value your willingness to contribute code to scikit-bio (beyond reporting issues or correcting typos). This process can be intensive, particularly for those new to software engineering. The following sections detail the steps for contributing code to scikit-bio. Please review them carefully. Discuss your plan ^^^^^^^^^^^^^^^^^ When considering contributing code to scikit-bio, you should begin by posting an issue to the :repo:`scikit-bio issue tracker `. The information that you include in that post will differ based on the type of contribution. The two types of issues discussed in `Report an error`_ and `Suggest a new feature`_ can be a good start of the discussion. The scikit-bio developers will respond to let you know if we agree with the addition or change. It's very important that you go through this step to avoid spending time working on a feature that we are not interested in including in scikit-bio. Take existing tasks ^^^^^^^^^^^^^^^^^^^ Alternatively, if you're looking to contribute where help is needed, you can explore the following types of issues: - **Quick fix**: Some of our issues are labeled as ``quick fix``. Working on :repo:`these issues ` is a good way to get started with contributing to scikit-bio. These are usually small bugs or documentation errors that will only require one or a few lines of code to fix. Getting started by working on one of these issues will allow you to familiarize yourself with our development process before committing to a large amount of work (e.g., adding a new feature to scikit-bio). Please post a comment on the issue if you're interested in working on one of these "quick fixes". - **On deck**: Once you are more comfortable with our development process, you can check out the ``on deck`` :repo:`label ` on our issue tracker. These issues represent what our current focus is in the project. As such, they are probably the best place to start if you are looking to join the conversation and contribute code. Set up a workspace ------------------ To start contributing code to scikit-bio, you'll need to prepare a local development environment. This section guides you through the process step-by-step. 1. `Fork `_ the scikit-bio repository on the GitHub website. This will create a copy of the repository under your account, and you can access it using the URL: ``https://github.com/urname/scikit-bio/`` (``urname`` is your GitHub account). 2. `Clone `_ the forked repository to your local computer. Specifically, in your forked repository, you may click the :bdg-success:`<> Code` button, make sure that you are under the "Local" - "SSH" tab, and copy the URL to the clipboard. It should typically be: ``git@github.com:urname/scikit-bio.git``. .. note:: If the "SSH" tab is not available, it could mean that you have not set up an SSH key for your GitHub account. You may follow the instructions on `Connecting to GitHub with SSH `_ to set it up. Then, open "Terminal" :octicon:`terminal` (or anything similar) in your local computer and navigate to a directory where you want to place the workspace, and execute:: git clone git@github.com:urname/scikit-bio.git .. note:: If this is the first time you use ``git``, you may follow the `Set up Git `_ guidelines to install Git and set your user name and email address. This tutorial assumes that you will use the classical ``git`` to create a local development environment. If you prefer other methods such as `GitHub CLI `_ or `Codespace `_, please follow corresponding instructions. This will create a directory ``scikit-bio`` containing all files in the repository. Enter the directory:: cd scikit-bio Add the official scikit-bio repo as the **upstream** of your fork:: git remote add upstream https://github.com/scikit-bio/scikit-bio.git 3. Create a development environment with necessary dependencies. This is typically done using `Conda `_ (or `Mamba `_, in which case the command ``conda`` in the following code should be replaced with ``mamba``). .. note:: If you do not have Conda (or Mamba) in your computer, you may install one of the distributions such as `Miniconda `_, `Miniforge `_ or `Anaconda `_. Execute the following command (``skbio-dev`` can be any name you like):: conda create -n skbio-dev -c conda-forge --file ci/requirements.txt --file ci/requirements.test.txt --file ci/requirements.lint.txt --file ci/requirements.doc.txt When done, activate the environment:: conda activate skbio-dev .. note:: This may be slightly different depending on the operating system. Refer to the `Conda documentation `_ to find instructions for your OS. .. note:: If you prefer to use ``pip`` instead of Conda, you can create a Python virtual environment:: python -m venv .venv source .venv/bin/activate ``.venv`` will become a hidden directory in the project directory, and it will be ignored by Git. Alternatively, you may replace ``.venv`` with a location outside the project directory, such as ``~/.virtualenvs/skbio-dev``. Then install dependencies in the environment:: pip install -r ci/requirements.txt -r ci/requirements.test.txt -r ci/requirements.lint.txt -r ci/requirements.doc.txt 4. Install scikit-bio from source code:: pip install --no-deps -e . This will install scikit-bio to the current conda environment. After this, you can use scikit-bio like a normal user (e.g., you can do ``import skbio`` in Python code). When you edit the code in the this directory, the changes will be immediately reflected as you use the software. .. note:: If you run into OpenMP compile issues (or have other reasons to avoid OpenMP), you can avoid it by setting ``DISABLE_OPENMP=1`` in the build environment. 5. Test the installation:: make test This will run all unit tests implemented in the scikit-bio codebase to check if the corresponding functionality works correctly. The output should only indicate passes and warnings, but no failures. 6. Activate pre-commit hooks:: pre-commit install This will enable a set of tools that will automatically execute every time you commit changes to ensure code quality. Write code ---------- Before you start writing code, you may discuss with the scikit-bio team to make sure that your intended contribution is relevant (see `Before coding`_ above). Next, you may work through the following steps to start coding. 1. Update your main branch such that it has the latest version of all files. This is especially important if you cloned a long time ago:: git checkout main git pull upstream main Optionally, you may do the following to keep your forked repository's main branch up-to-date as well:: git push origin main 2. Create a new `branch `__ that you will make changes in:: git checkout -b mywork ``mywork`` is the name of the branch. What you name the branch is up to you, though we recommend including the issue number, if there is a relevant one (see above). For example, if you were addressing issue #42, you might name your branch ``issue-42``. .. warning:: It is not recommended that you directly code in your ``main`` branch. 3. Run ``make test`` to confirm that the tests pass before you make any changes. 4. **Edit the code** using any code editor of your favor. Now it is the time to bring your creativity to scikit-bio! Scikit-bio's :doc:`coding guidelines ` provide more details on how to write high-quality code. It is recommended that you read this document carefully and apply the guidelines in your code. Test code --------- Testing your code is an essential step to ensure its quality and functionality. For scikit-bio, we emphasize the importance of comprehensive testing to guarantee that your contribution works as expected. You might find testing tedious (it often costs more time than implementing the algorithm!), but it is a valuable step that will significantly enhance the robustness of your code, and will help fostering a culture of reliability and trust within our community. This section is to guide you through the testing process, providing you with the tools and knowledge to perform effective tests for scikit-bio. Functional test ^^^^^^^^^^^^^^^ You will want to test your code like a *user* would do: import the function, execute it on some input data, and examine whether the results are correct. You may install additional software such as `Jupyter `_ in the same conda environment to make the testing process convenient and pleasant. There is no need to reinstall the modified scikit-bio package in a separate environment in order to test. As soon as you edit the code, the changes will immediately reflect when you use the code. For example, you wrote a function ``gc_content``, which calculates the fraction of ``G`` and ``C`` in a nucleotide sequence:: def gc_content(seq): return sum(1 for x in seq if x in "GC") / len(seq) You added this function to the code file ``skbio/sequence/nucl.py``. It will be available for use in any Python code launched in the same conda environment:: >>> from skbio.sequence.nucl import gc_content Now test the function on some data. For example, you would expect that ``gc_content("ACGT")`` and ``gc_content("GGATCCGC")`` return 0.5 and 0.75, respectively. Is that the case? We highly recommend that you use real-world biological data in addition to small, dummy data for testing. This will let you evaluate the robustness and scalability of your code in real-world applications. For example, DNA sequences retrieved from public databases may contain lowercase letters, and you will find that the ``gc_content`` function cannot handle them properly. For another instance, a FASTQ file with ten million sequences (which is common) may cost a function forever to process, in which case you should consider optimization. Unit test ^^^^^^^^^ `Unit testing `_ involves testing the smallest units of your code, such as classes, functions, and methods, to ensure they function correctly in isolation. It is a fundamental best practice in software engineering, but is often overlooked by beginners. Unit testing is made easier by writing test code alongside the algorithm code. Both types of code are integrated into the scikit-bio codebase. This test code is then regularly executed whenever changes are made to ensure that the intended behavior remains consistent over time. For example, the test code for the ``gc_content`` may live in ``skbio/sequence/tests/test_nucl.py``, under class ``TestNucl``, as a method ``test_gc_content``. It may read like:: def test_gc_content(self): self.assertEqual(gc_content("ACGT"), 0.5) self.assertEqual(gc_content("GGATCCGC"), 0.75) ... You can run this test with:: python skbio/sequence/tests/test_nucl.py TestNucl.test_gc_content The screen output will tell you whether the test passed, and if not, what went wrong. This information will help you debug your code. Ideally, every line of the code should be covered by unit test(s). For example, if your function has an ``if`` statement, both ``True`` and ``False`` situations should be tested. It is a good practice to test all types of cases you can think of, including normal cases and `edge cases `_. For example, an empty sequence (``""``) will cause the ``gc_content`` function to crash, because zero cannot serve as a denominator in an equation. Having edge cases like this will help you to identify limitations of your code and think whether you should implement special handling to avoid problems. You should also test whether the changed code fits into scikit-bio without causing problems in the other parts of the codebase. There is a convenient command to run all unit tests implemented in scikit-bio:: make test Alternatively, you may run all unit tests in a Python session (including Jupyter):: >>> from skbio.test import pytestrunner >>> pytestrunner() GPU Tests ......... If you are incorporating Python Array API support or GPU support into scikit-bio, please review the :doc:`devdoc/array_api` page for specific information. Code coverage ^^^^^^^^^^^^^ `Code coverage `_ refers to the percentage of source code lines covered by unit tests. It is an assessment of the quality of a software project. In scikit-bio, code coverage can be calculated using the following command:: coverage run -m skbio.test && coverage report This will report the coverage of each code file and the entire codebase. If the coverage decreased for the file you edited, you may have missed some anticipated unit tests. You can create a detailed HTML report with:: coverage html Then open ``htmlcov/index.html`` in a web browser, navigate to the page for the relevant code file, and check which lines of your code are not covered by unit tests. Work on them to bring back coverage. Please read the :ref:`devdoc/code_guide:How should I test my code?` section of the coding guidelines to learn more about unit testing. Document code ------------- `Documentation `_ is a vital part of software engineering, especially for projects like scikit-bio, which involve many contributors and are designed to endure over time. Documentation helps everyone -- users and developers -- get on the same page. It also helps you, as even seasoned developers can lose track of their own coding logic over time. Also remember that scikit-bio brings together people from various fields, and nobody is expected to have the same level of understanding across all disciplines. Therefore, documenting your code with the broader audience in mind is important. This section will cover the basics of documenting your code in a manner that benefits the scikit-bio community at large. Scikit-bio's :doc:`documentation guidelines ` provide more details on how to write effective documentation. Comments ^^^^^^^^ `Comments `_ in the source code explain the rationale to fellow developers. Please make comments frequently in your code, especially where the code itself is not that intuitive. For example:: # Perform eigendecomposition on the covariance matrix of data. # w and v are eigenvalues and eigenvectors, respectively. # eigh is used in favor of eig to avoid returning complex numbers due to # matrix asymmetry caused by floating point errors. # Discussed in: https://stackoverflow.com/questions/12345678/ w, v = np.linalg.eig(np.cov(X)) Please read the :ref:`devdoc/code_guide:How should I write comments?` section of the coding guidelines to learn more about writing comments. Docstrings ^^^^^^^^^^ `Docstrings `_ are structured text blocks associated with each unit of the code that detail the usage of the code. Docstrings will be rendered to the software documentation. That is, *users* (not just developers) will read them. Therefore, docstrings are critical if you want your code to be used, and in the correct way. Below is a very simple example for the ``gc_content``. The lines between the triple double quotes (``"""``) are the docstring:: def gc_content(seq): """Calculate the GC content of a nucleotide sequence. Parameters ---------- seq : str Input sequence. Returns ------- float Fraction of G and C. """ return sum(1 for x in seq if x in "GC") / len(seq) As shown, the docstring explains the purpose, the parameter(s), and the return value(s) of the function. In more complicated cases, the docstring should also include example usage, potential errors, related functions, mathematics behind the algorithm, references to webpages or literature, etc. Every public-facing component should have a docstring. Please read the :ref:`devdoc/doc_guide:Docstring style` section of the documentation guidelines to learn more about writing docstrings. Doctests ^^^^^^^^ You may consider adding **example usages** of your code to its docstring. For example:: def gc_content(seq): """Calculate the GC content of a nucleotide sequence. ... Examples -------- >>> from skbio.sequence.nucl import gc_content >>> gc_content("ACGT") 0.5 """ ... The example code and its output must match. This is ensured by `doctest `_. When you run ``make test`` (see above), doctests are automatically executed as part of the test suite. You may fix any issues according to the screen output. HTML rendering ^^^^^^^^^^^^^^ After completing docstrings, you will want to check how they look like when rendered to the documentation webpages. You may build the entire HTML documentation package locally with:: make doc The built documentation will be at ``doc/build/html/index.html``, and can be examined using your web browser. If errors arise during the building process, or the rendered webpages don't look as anticipated, you should address the issues accordingly. Changelog ^^^^^^^^^ Please mention your changes in :repo:`CHANGELOG.md `. This file informs scikit-bio *users* of changes made in each release, so be sure to describe your changes with this audience in mind. It is especially important to note API additions and changes, particularly if they are backward-incompatible, as well as bug fixes. Be sure to make your updates under the section designated for the latest development version of scikit-bio (this will be at the top of the file). Describe your changes in detail under the most appropriate section heading(s). For example, if your pull request fixes a bug, describe the bug fix under the "Bug fixes" section of the changelog. Please also include a link to the issue(s) addressed by your changes. Style code ---------- `Code style `_ is a set of rules for formatting and structuring code in a particular software project. Although violating these rules won't cause errors in executing the code, adhering to them ensures that the codebase remains uniform and professional, and facilitates team collaboration. Scikit-bio utilizes the `Ruff `_ program for autoformatting and linting to ensure code consistency and quality. The rules are specified in :repo:`pyproject.toml `. Basically, we largely adopted the `Black `_ code style. When you `set up the development environment <#set-up-a-workspace>`_, Ruff was already installed and integrated into a `pre-commit hook `__. This means that Ruff will automatically format and lint your code every time you commit changes (see `Submit code`_ below). Therefore *you are not required to take any explicit action*. However, you can still manually run Ruff to check and fix issues in specific code files you have worked on:: ruff check --fix mycode.py If Ruff identifies any errors that cannot be automatically fixed, you will need to manually fix them based on Ruff's feedback. When done, let Ruff reformat your code:: ruff format mycode.py You will notice the improvement in your code's appearance before and after using Ruff. While it is always beneficial to strive for professional-looking code from the start, the necessity for perfection has lessened with the advent of tools like Ruff. Submit code ----------- Having completed, tested, and documented your code, you may now believe it deserves a place in scikit-bio to benefit the community. This section outlines the steps to submit your code to the official scikit-bio repository. 1. Add any new code file(s) you created to the git repository:: git add path/to/mycode.py Alternatively, if you have multiple new files, you can add them all at once:: git add . 2. `Commit `__ the changes (this is like "saving" your code in the current branch):: git commit -am "describe what I did" Here, "describe what I did" is the placeholder of a *commit message*. You should write a meaningful commit message to describe what you did. We recommend following `NumPy's commit message guidelines `_, including the usage of commit tags (i.e., starting commit messages with acronyms such ``ENH``, ``BUG``, etc.). The `commit` command will trigger the `pre-commit hook `__, which automatically runs Ruff to check and fix any code style problems (see `Style code`_ above). If there are any errors flagged by Ruff, you will need to resolve them and commit again. 3. Merge the latest code from the official scikit-bio repository to your local branch:: git fetch upstream git merge upstream/main This step is important as it ensures that your code doesn't conflict with any recent updates in the official repository. This could happen as there are other developers simultaneously working on the project. If there are conflicts, you will need to `resolve the conflicts `__ by editing the affected files. When done, run ``git add`` on those files, then run ``git commit`` with a relevant commit message (such as "resolved merge conflicts"). 4. Run ``make test`` for the last time to ensure that your changes don't cause anything to break. 5. Once the tests pass, you should push your changes to your forked repository on GitHub using:: git push origin mywork 6. Navigate to the GitHub website, and create a `pull request `__ from your ``mywork`` branch to the ``main`` branch of the official scikit-bio repository. Usually, GitHub will prompt you to do so, and you may click the :bdg-success:`Compare & pull request` button to initiate this process. If not, you can invoke a :bdg-success:`New pull request` under the ":octicon:`git-pull-request` pull request" tab. 7. Enter a meaningful title and a description of your code in the pull request. You may mention the issue you attempt to address in the description, such as "Resolves #42". This will `link your pull request to the issue `__. You will also need to answer a few questions by either typing an ``x`` in the checkboxes that apply to your code or leaving them empty otherwise. These questions can be found in :repo:`PULL_REQUEST_TEMPLATE.md `. When done, click :bdg-success:`Create pull request`. Review code ----------- Your `pull request will be reviewed `__ by one or more maintainers of scikit-bio. These reviews are intended to confirm a few points: - Your code provides relevant changes or additions to scikit-bio. - Your code adheres to our coding guidelines. - Your code is sufficiently well-tested. - Your code is sufficiently well-documented. This process is designed to ensure the quality of scikit-bio and can be a very useful experience for new developers. Typically, the reviewer will launch some automatic checks on your code. These checks are defined in :repo:`ci.yml `. They involve: - Full unit test suite and doctests execute without errors in all supported software and hardware environments. - C code can be correctly compiled. - Cython code is correctly generated. - Documentation can be built. - Code coverage is maintained or improved. - Code passes linting. The checks may take several to a few dozen minutes. If some check(s) fail, you may click "Details" in these checks to view the error messages, and fix the issues accordingly. Meanwhile, the reviewer will comment on your code inline and/or below. They may request changes (which is very common). Please work with the reviewer to improve your code. You should revise your code in your local branch. When completed, commit and push your code again (steps 1-5 of `Submit code`_). This will automatically update your pull request and restart the checks. *Don't issue a new pull request*. .. note:: Particularly for big changes, if you'd like feedback on your code in the form of a code review as you work, you should request help in the issue that you created and one of the scikit-bio maintainers will work with you to perform regular code reviews. This can greatly reduce development time. We highly recommend that new developers take advantage of this rather than submitting a pull request with a massive amount of code. That can lead to frustration when the developer thinks they are done but the reviewer requests large amounts of changes, and it also makes it harder to review. Please read :doc:`devdoc/review` for more details on how pull requests should be reviewed in the scikit-bio project. After your code has been improved and the reviewer has approved it, they will `merge your pull request `__ into the ``main`` branch of the official scikit-bio repository. This will be indicated by a note: :octicon:`git-merge` "Pull request successfully merged and closed". Congratulations! Your code is now an integral part of scikit-bio, and will benefit the broader community. You have successfully completed your contribution, and we extend our appreciation to you! 🎉🎉🎉" Benchmarks ---------- Scikit-bio utilizes `ASV `_ to run benchmarks on a selection of its functions. Benchmarks help the development team prevent performance regression, the unintentional loss of performance which may come from modified code. Scikit-bio's benchmarks are run against every release of scikit-bio, starting with version ``0.6.1``. We welcome the addition of new benchmarks or the expansion of existing benchmarks to further protect against performance regression. If you are interested in contributing to our benchmarking system please see our `benchmark repository `_. scikit-bio-scikit-bio-a3beaa6/web/devdoc/000077500000000000000000000000001520735541300203745ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/web/devdoc/array_api.rst000066400000000000000000000160151520735541300231000ustar00rootroot00000000000000Array API and GPU support ========================= Scikit-bio is gradually adopting the `Python array API standard `_ to allow functions to work across multiple array libraries (NumPy, PyTorch, JAX, CuPy, Dask) and run on GPUs where supported. This page covers what contributors need to know to write, test, and run array-API-compatible code. Overview -------- The array API standard defines a common interface that several array libraries implement. Functions written against this standard accept arrays from any compliant library and dispatch to that library's implementation — meaning the same function can run on CPU via NumPy, on GPU via PyTorch or CuPy, or on TPU via JAX. Currently supported backends: - **NumPy** (CPU only) — the default, always available - **Torch** — CPU or CUDA - **Jax** — CPU or GPU - **CuPy** — CUDA only Only a small fraction of scikit-bio currently has array-API support. Most functions still operate on NumPy arrays exclusively. This is being expanded over time. Writing array API compatible code ----------------------------------------- Use ``ingest_array`` at function entry points to obtain the array namespace (``xp``) and a converted array: .. code-block:: python from skbio.util._array import ingest_array def my_function(arr): xp, arr = ingest_array(arr) result = xp.sum(arr, axis=0) return result The returned ``xp`` is the namespace corresponding to the input array's backend. Use ``xp.func()`` for all array operations rather than ``np.func()`` — this is what makes the function backend-agnostic. .. code-block:: python def my_function(arr): xp, arr = ingest_array(arr) return xp.sum(arr) ... **Things to avoid:** - Hardcoded ``np.func()`` calls (use ``xp.func()`` instead). - Backend-specific methods like ``torch.numpy()`` or ``cupy.get()`` (both return a NumPy array). - In-place modification when supporting JAX arrays. They are immutable. - Assuming ``float64`` is the default dtype (PyTorch defaults to ``float32``). Writing tests for array API code -------------------------------- Tests that exercise array-API code paths use the ``ArrayAPITestMixin`` and the ``@array_backends`` decorator. Write the test once; the decorator runs it across every supported backend: .. code-block:: python from unittest import TestCase from skbio.util._testing import ArrayAPITestMixin, array_backends class TestMyFunction(TestCase, ArrayAPITestMixin): @array_backends("numpy", "torch", "jax", "cupy") def test_my_function(self, xp, device): data = [[1.0, 2.0], [3.0, 4.0]] arr = self.make_array(xp, device, data) result = my_function(arr) expected = self.make_array(xp, device, [[4.0, 6.0]]) self.assert_close(result, expected) self.assert_type_preserved(result, xp, device) The decorator injects ``xp`` (the array namespace) and ``device`` (the target device) into the test method. ``ArrayAPITestMixin`` provides: - ``make_array(xp, device, data)`` — create a test array on the right backend and device - ``assert_close(actual, expected)`` — numerical comparison that works across backends - ``assert_type_preserved(result, xp, device)`` — verify the result came back on the expected backend and device **When to use ``@array_backends``:** decorate tests that exercise the array computation itself. Tests for input validation, error handling, or pure-Python logic don't need it — those should remain standard ``TestCase`` methods. Running tests locally --------------------- Two environment variables control which backend and device tests use: - ``SKBIO_ARRAY_BACKEND``: ``numpy`` (default), ``torch``, ``jax``, ``cupy``, or ``all`` - ``SKBIO_DEVICE``: ``cpu`` (default), ``cuda``, or ``gpu`` Common invocations: .. code-block:: bash # Default: numpy on CPU pytest skbio/stats/composition/tests/test_base.py # Single backend on CPU (no GPU needed) SKBIO_ARRAY_BACKEND=torch pytest skbio/stats/composition/tests/test_base.py # All available backends on CPU and GPU (if available) SKBIO_ARRAY_BACKEND=all pytest skbio/stats/composition/tests/test_base.py # Run only array-API tests across the package pytest -m array_api skbio/ # GPU run (requires CUDA-capable hardware) SKBIO_ARRAY_BACKEND=torch SKBIO_DEVICE=cuda pytest -m array_api skbio/ Tests for unavailable backends skip cleanly — you don't need every backend installed. CuPy is GPU-only and will skip on machines without CUDA. The ``-m array_api`` marker filters to tests decorated with ``@array_backends``. Without it, pytest runs the full suite. Continuous integration ---------------------- GPU testing happens in the ``Array API Compatibility`` workflow (``.github/workflows/array-api.yml``), which runs on a T4 GPU runner against the ``torch``, ``jax``, and ``cupy`` backends with CUDA. **Triggers:** - **Weekly cron**: every Monday at 06:00 UTC, catching regressions from upstream changes in array libraries - **Manual dispatch**: via the Actions tab on GitHub - **`gpu-ci` label on a PR**: applies the label to a PR to trigger the workflow; pushes to the labeled PR will re-trigger it Reviewers should apply the ``gpu-ci`` label to any PR that modifies array-API code paths. Most PRs do not need GPU validation and the workflow has a non-trivial cost, so it is not run on every PR automatically. **What the workflow verifies:** - Each backend installs successfully with CUDA support - The GPU is visible to each backend at import time - Decorated tests pass with arrays placed on CUDA, and results remain on CUDA after computation **What it does not verify:** - Code paths not covered by ``@array_backends``-decorated tests - Subtle silent CPU fallback within individual operations - Correctness on GPU architectures other than T4 Backend-specific gotchas ------------------------ A few cross-backend differences come up often enough to call out: **PyTorch** - Defaults to ``float32``, not ``float64``. Specify dtypes explicitly if precision matters. - Tensors with ``requires_grad=True`` cannot be converted directly to NumPy; ``_to_numpy`` handles this by calling ``.detach()``. **JAX** - Arrays are immutable. In-place updates (``arr[i] = x``) raise an error; use ``arr.at[i].set(x)`` instead. - Silently falls back to CPU if no GPU is detected at import time. Always check ``jax.devices("gpu")`` before assuming GPU execution. - Uses ``"gpu"`` as its device string where Torch and CuPy use ``"cuda"``. These are treated as equivalent by ``_device_specs_match``. **CuPy** - GPU-only — there is no CPU mode. ``cupy.ndarray`` is always on a CUDA device. - Requires a CUDA driver matching the installed CuPy build (e.g. ``cupy-cuda12x`` requires a CUDA 12-capable driver). **General** - Integer division and dtype promotion rules differ subtly across backends. When in doubt, cast explicitly. - Some array API standard functions are unimplemented in certain backends. Check the library's documentation if you hit ``AttributeError`` on ``xp``. scikit-bio-scikit-bio-a3beaa6/web/devdoc/assets/000077500000000000000000000000001520735541300216765ustar00rootroot00000000000000scikit-bio-scikit-bio-a3beaa6/web/devdoc/assets/api-lifecycle.png000066400000000000000000001165061520735541300251230ustar00rootroot00000000000000‰PNG  IHDR¶mò)� AiCCPICC ProfileH �–wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?�#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…<�X�.d „Õá6'~�khu_}…9P¸IÈo=C#$n?z}ë[1 Ⱦ¼h­‘¯s�2zþçú \ŠnáLA"Sæö �dr%¢,£ß„lÁ�t  4�.0,` €3pÞ „€H–.Hi@²A>Ø A1ØvƒjpÔ�zÐN‚6p\WÀ p €G@ †ÁK0Þ�i‚ð¢Aª�¤™BÖZyCAP8ÅC‰�’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDB�X$!k‘"¤©Eš�¤¹�H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3�ù‚¥bÕ±¦X'¬?v 6›�-ÄV`�`[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ß�Æ¿'� Zk‚!– $l$Tçý„Â4Q�¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´�TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜º�ZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS�£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’�’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œ�ó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••�ªLUoÕÕ�ªmªOÔ0j&jajÙjûÕ.«�ϧÏwžÏ�_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰�I’I�ÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹�Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ß�YÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×�çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>�>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»H�ÈÒÈG‹�KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®�_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+ç�ñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_ò�ä©”�”£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ë�m mHÙðËFË�eßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`i�d�´2¨²½J¯jGÕ§ê¤ê��šæ½ê{·í�ÚÇÛ׿ßmÓ�Å>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂ�uÕ;Ô×7¨7”6Â�’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€Ó�Î-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ�®°®ÞË�—¯^ñ¹r©Û½ûüU—«g®9];}�}½í†ý�Ö»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ�‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg�†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?ö�ý¡ûcôÇ‘éìOøO•Ÿ�?w| üòx&mfæß÷„óû2:Y~ pHYs  šœÕiTXtXML:com.adobe.xmp 5 2 1 °ã2Ý@IDATxì� üTã÷ÇBe¯"K$K¡�²o¡$ÊÙ•­²”%‘})»"þ¶Ò"%K*¢²…"K‹ìD–ç>çç¹îÌw¾³}ïÌÜ{çs^¯ùÎ�ç>÷YÞÏ|gΜ{žsV±"†B$@$@$@$@'°jÄÇÏá“ � � � �€ bË7 � � � �@,P±�Å2r$@$@$@$@Tlù    ˆ*¶±XFN‚H€H€H€H€Š-ß$@$@$@$@± @Å6ËÈI� � � � P±å{€H€H€H€H ¨ØÆb9     *¶|� � � � Ä‚ÛX,#'A$@ÁX¶l™éÞ½»Ùi§�Ìk¬aVYe>"Æë†õÃ:b=)$wTlã¾Âœ � äA`Μ9¦Y³fú>|¸Y±b…±Öò1X7¬_Ó¦MM½zõ Ö•Bq&°Š|PÙ8O�s# È�,{P‚Æ�o:tè�ÛŬZ&L0ݺu3óæÍ3uëÖ í890¨ *¶U¡ÇkI€H †pÛºI“&fÀ€1œ]yOéÚk¯UÅväÈ‘å ‚³�-º"Ävi91 È�,z;vÌïb^jmÛ¶5sçÎ õ98¨ Zl«B�×’ �@ `Ã|3«U«ÃÙ•÷”þþûoS³fM³råÊòÁÙÇ–ÛØ.-'F$@ù@ôn¿È�]®âúFa•8Æ| Ð!_r¼ŽH€H€H€H T¨Ø†j98    �| P±Í—¯#   *¶¡Z†H€H€H€H _Tló%ÇëH€H€H€H€BE€Šm¨–ƒƒ!   È—Û|Éñ:    �P bªåà`H€H€H€H€ò%@Å6_r¼.ö–-[fºwïnvÚi'ƒLLjÎG´`ݰ~XG¬'…H€H Þ¨ØÆ{}9»< Ì™3Ç4kÖLÇ×ô¢ÈÄÄG´ -,Ö¯iÓ¦¦^½zëJ! ˆ/¦Ô�ïÚrfy€eJÐøñãM‡òl…—…�À„ L·nÝ̼yóLݺuÃ6¼P�‡)WCµ�†ë8R6"TlC´J8à¶u“&MÌ€Â1 Ž"0×^{­*¶#GŽ ¬Í86DÅ'Ž«úßœ¸¾ÿ±àQüÐ!~kÊU‘,z;v¬b+¼<ŒÚ¶mkæÎ�Æ¡qL$��þùÇüúë¯æï¿ÿΪ>+‘@¹ b[n+Îùf$Åg—]vÉX�¢G E‹j±�ÞÈ£1â .¸ ÂËjÕª™­·ÞÚ{ì±æõ×_�ÆDå'Ÿ|b¾ýöÛÀZ„ŸøÚk¯mÆŒX›lˆâD`µ8M†s!� üùçŸ_Æ”øÀºb})…%pÞyç™Í6ÛL;ùí·ß̇~hÆ�gžzê)3tèPsöÙgv!iïµÆ�›>}ú˜[o½5$£â0H Þ¨ØÆ{}9; (:�cŽ9Æìºë® ý.Y²Äzè¡æÜsÏ5{ï½·ÙqÇÎó � A€®APd$@$@i l¸á†j­Eȼ+¯¼2¡.nÕ÷îÝÛì°Ãf»í¶S çÂ… ê ¢Å½÷Þk&Mšdºtéb4h`Úµkg¦L™’PדּÎ2—]v™� ÀÉ'Ÿl<ð@ï|6ý òŒ3Ì~ûígj×®m6ÞxcÓµkW“<žÉ“'›3Ï2Ǽ*ÚÛþûïï)•p«hß¾½yì±ÇT9Ým·ÝÔÍcq~ÄÕ«W7õë××¾×Zk-=^uÕÿ}åöïßß}ôÑJ:â-÷êÕËœ~úéÞ<°9ì ƒÒH4…ÿÁ4=zôðêð€H ùõL!ð�ß+Æ�×7óŠæËH¬–׊µ²ÒNÄò¨uÄò¨uŽ<òH+¾ÏvþüùÞ5Ÿ}ö™­S§Žíܹ³WV³fM½nÔ¨Q^Ù_|akÕªe·Ùf+Š –‹õTë‰Âh?ýôS¯n6ý  IÌb7Úh#ûÍ7ßx×Þ~ûíÚ¦øk™Xp­ÄB¶¿ÿþ»WsÆÜ/¹ä¯L,®Z&>¶^Ù{ï½gEÁµ¢ ze8¿d­ë؉Ҭ¯ìÕûñÇu|èG,¾^y®ù®o®ý°> ”‚-¶òN! (� 6Ø@#'üõ×_fñâÅj�…5t«­¶ò°Å[èíyXOøá¯äà¿ëÖßO<Ñ|ðÁæóÏ?wÅÚþõ×_o5j¤eÙö3}út�š�XÖ¢ÜzíÁJ ßà5×\SËàv«0¬²NܼDùtE)Ÿï¸ãƒ�]ØPæ¸5@`†Œ1B‰ôíÛW_ãϺë®kúõëç½æ �@EÜû˜ñãÇûOWz,á‡L§N�ÔeâÀÔÝë•Væ   (*¶€Ê&I (.Ðgœa$p}B³ØÙ,ì5#NÀGvíµ×Ö:+äÂ%!«,»Pz¡x"£”WøëJìÍ„6Ÿ}öYÓµkWUNZ Y–öß­ŸP1éRŒ}ôÑfÅŠªTãYb�šÓO?=©&_’ � �@ Ž-…Hà?òïöß‹!ÓÑÎ;ïì¤G¶"�¿ÿþû­l«0:dzÂø¿ýö[ïœ(ª¶nݺ�ç�HüM­‡úN_”e ïʾþúkͨ„,KpAÐxôñâ‹/êkÝG ü=zèk÷GÒ§j=ô& Óú†‰‹,dä§¿c®oüÖ”3ú�-¶òN!�°€VUQd�¤%5ˆzpï½÷IYªá¾N:é$ üžnüˆt€¼ô’îÓ«ë.,¾Bï—ýöÛO£.¸2I%j}‘.\芞áò€( }úôI(‡ëäñÇO(ç   (n+Y¶K€B*):õÑ ,>ôÐCªä"£‘ó­MÕ¥X|uÚСCͬY³4ÓÑܹsSfWÛf›m*4?Û1cƨb‹ø¹É‰ÕW_ÝÜ~ûíɧ´J1…H€H€ŠA€ÛbPf$��?þøÃ V,Òn:‘[þFòÖ›k®¹FË×YgU:Q·2AÝ ˜«¯¾Z}`a�}úé§+«^¡¼F�Z†¾SɲeËT�ýé§ŸLòã ƒ2جF!  �b Å¶”Ù äAŠ$ÜÚ´ic&NœX¡(µ|°A|ÛåË—›�7Þ¸Bñ‘5ØØK+¬´.«˜øîj]¸#øåã�?ö¿Ôc·ÁlóÍ7¯p(ÿý÷͈#L�:uê@á®V­ZB_� � „Ÿ€ìËÐÏoÜ‘‹’¤6ÁDi+ Ä”>LaÚ´iê>�Y!RL�í³-£É�† 9Tl#·dp9@â…?ÿüÓ´lÙÒÜyç�fúôéfΜ9êc‹4»pS@,['›nº©B™„oëÖ[o­›ÆFŽi^{í53þ|së­·šSN9EËaÑýá‡ÜåêJpøá‡¤Í}ûí·MÏž=µ�‹/¾ØT技þgW",¨eyñâÅF"&˜îÝ»›Í6ÛÌtëÖÍkŸ$@$�K/½T³0ÑÛHMw{÷î�úd˜Kÿ �À# �ÿ×P�xî¹ç,Âma\þÇ&›lb%ŽmÂX%r�mÞ¼¹Ö“Ø·zN”Z‹0aîÚF�Yq/°’ÐAËdcšÖC¸¯¾}ûÚŽ;jØ/Ô_mµÕìõ×_ŸÐGr¸/œ|÷Ýwm³fͼ>p­¤¶óæÍK¸6 /06Jzd”žOÔÏF}}�=öX+wƒ¬¸XÙÁƒ[ù‘oå¿.‹ü°Ö×£F�ò– ¡e¬¾–;Rö¨£Ž²â6e6lhhW®\éÕM>˜2eŠ•5zQö=xUÎ>ûl+ÊŸ½è¢‹¬$ÌñÊÝÂ.bl/¿ü²·1+éε¿¯¾úÊJ+{ì‘GiÖÑI®ý!Œ#B+¢í�vÚÉÊ&a×T…gI¢c%’ŽÅwB‹-ì{ì¡añ™Ž×øžñ_�ù=üðÃÚ®•H7\‚ìÁΉÜ´W]u•¶Q«V-{Øa‡YI ¯§1?p�;‚öÐCµbv—䙟ðÁÊF£L ŒúbµU%ñ™gž±²ñËJt‹²ÊdÑ¢EV’$x§ñ¡ƒ• xe8W+þ¹ ex�/±ðÚ_ýµÂ¹Ê çVüx-qĶ «„q}ÃÆŠŒÂ¶"ÁŽ'êë+™­¸_©¢…Ïø±~Ë-·($I>£?°%ÁŒ¾–¨1úŸMøÜa‡¬$ªÑÏ7(»ÒÐöë×/%`(Ëâ¦ÊóŒ3Tq“;WVîœi}üx‡rÜ´iS+wÔ*´ñÍ7ßèX Þpà vÀ€ó[ÜÇì\ J#Ž�‚˜Or‡Mûà�Té”ä œÂÒí’û@YÇ{J-ó@2g¥MVl×\sÍ„ä?¸;…Vc(½òÑ C�"øQK¯SlÅ¥Í;_ÈúØÊªRH€H€H€¢I@L/=86»ŠK•n‚ýüóÏÍÔ©Suf6{ölÝ+Ê›7Q¹oÄ!å]ÔåΫ‹„/ô‡`Ddšäè2 È qðŠDéÔç®`ýõ×÷ö9äÚßÌ™3uƒ.6‹ÅT؇�D>Øë�JÄÂlÄU@O¹g¤W‡`HÅîßw¡'þýƒ8þÈ7Ø´¼dÉe‡P�~V¢ÄE÷³B”ŸbÛbPf$@$@$@! þ­a‘,a «{·ÝvÓˆ.â³jä–»ö+–C�éí„X)ý/Ž¡ е7¡,¹>²Cf’ä:²Ÿ!å%¹ö‡úሠ’PFñ�}F¬Ö Qpü�%�ç „f#Éãv =¸B/Ý/ÿý7¼¼"„¨,†P±-eöA$@$@$P°z"ì ¢ÈÈíqUÔäv¿Fi�U³}ûöÚ/¬•o½õ–A¨D'r;^•AœKX(]owõÅ'Õ½ ô9×þdS°ALrD­—}ˆï®÷ƒ´éÅÇ‘wœÈþ óÁŒ•ë'Õ3ÛTTXF$@$@$Z°úo·Ã*+¨LëÖ­uÌâgkd¿Þw®²S_Ã'"ü! dî¹ç#ÍL²5çQ>nÜ8ÏMÖàW^yEà â|Ð’kûí·ŸºHd Õ(Q4”#büVž1è1£=¸$ ‘�ø<{?Äo×àG±Üüó¢bë§Ác   �Ð��]æŠ+®0矾Ž~¶È” ";ÿõ6¸sC@âjCùêÓ§�&œqþ¢°v¦ÄûÞÿýÕ/Ù‘Î\B` Õ•ªz•Ëríþ°�>ú¨>à Ñ!Ô-Êz±ÅÅN‡¥îHì0zôh³ÖZk{(fìL+z¯ì�BL~Cü·ñUqh\ßÌÉ(3£(׈ËúbÃRõêÕõ‘ËzH0M.¡¾ŒKj“îzøïJEµþÊîÿtU9—k°efå\ß(¯Çž‰]2ây    �H b‰eâ I€H 3ìà– í™+² � Ä”]bº°œVþx›.vQ¸2Î당a74üÏ8ã Ó£G#);s^–83ÊF /àúÆpQ9%�[Hàø¡ïwBœ×áu¬‚ðEØÄ�Ýágžy¦9è ƒ* Úž¼âqf”<×r|Íõ-ÇU/Ÿ9S±-ŸµæL³$Àý,AE´Zœ×ׯØú—°súÐC5�?þ¸ÿTÊã83J9á2+ŒÛúâ½�;«¯¾z$V "ð¨Q£F•NjȘwª8¼ù6ŽÃK—.­�I,ßöŠ}}l‹Mœý‘ „š¾ô£úpÖÚT€1'Jð;õÚk¯5‡~¸Æ7}øá‡ƒï$-^wÝuæ¾ûî ÁH*w#®ºêªŠ'BZ‚äHù›� �î½÷Þ«‰&pý`n¹å–|šJy ÚF¼ß믿>åyaòXüçJyLŶ”ôÙ7 �@è †qTØîä‘GjQdd‚e'k­»žÏÙ:t¨yê©§Ìé§Ÿnúöí«Aü³»2Zµzöìi† fºvíªi\£5úp�¶{÷îæÿþïÿòâéžtÒIæ·ß~ËëúLA±EûHOœI =–LýWvžŠmedXN$@#‹-non.9òJ *?yòdµ&BÉ¥O`ÆŒ¦[·n¦}ûöi\·Ûn»à; A‹È(5sæLƒ;ì°ƒ™5kVAF…ä {챇™>}ºA \XŠ!Ÿ|ò‰ú‰cc$²�M™2¥ÒþÓÕ… À AƒÔbºÕV[™^½ziÛ®1¤ÌíÒ¥‹nºtãpçàò€LgMš41;ï¼s«fºk]xF½«¯¾Z‹–/_®ó}ç�wL§N�ôöÿÁlPž,Ÿ}ö™nE92ªÍ™3G«¬X±ÂôîÝ[³©íºë®Ú¾ÿÚÇ{Ì´jÕÊl±ÅæÄOLÙ6êŸvÚišè?€aGV3ü ñ x=ñÄ&ÕX ûïX|óÍ7:77—sÎ9GÛ¼øâ‹M»ví´ÙLLý}g{LÅ6[R¬G$@!'ðÚk¯<,X`.¸à‚¼""„|Š:<(XP:jÕªe�i)Õ­X(Dø’‡ßñN;í¤_ê¿þúkÖÓC]|ãGÚÀ1”'sçÎU…ö­·Þ2O>ù¤Z2�;î83þ|W%vÏøÑt×]wX©¡\Þ|óÍ�ÏŠço¼aŽ9æõCmݺµY¶l™*¢Èd…Ô­PÒÐ?Ø'K¦ºHŸ‹”³Pâ`�D–¯K.¹D›ùóÏ?ͱÇköÚk/µÂãG nõcLX«_xás饗š~ýú´Õ¿ÿ¬®ÕJÿþ�¥Š;}b¾pe9ä�Ct,Ó¦MóÆôï%úT·n]UÄñâ¼óÎó|`±hu¤°Eºa'PjO>ùd}ÿbí/^¬i‡Ýœ\=<ãÚ†nhÚ¶m«JöW_}eÞ{ï=} …5ÕXP×8�›æŸ]Èû￯ózúé§½1¦cêÚÉùYn¹QH€|äŸÈ÷Їq#Àõͼ¢ag$V!+_ÒV¬Fv„ V¬ˆVobï¾û®mܸ±]²d‰•/|{Ûm·YÙ\dEéñêd:…ÆŠUÎŽ3ÆJºR+áÓ¬¸wX±ê¥hûÖ[oµb½´bá³¢\k?b�ÊÔtÉϱ¾òãÉÊ Nß~ûm`súþûï-Æ'V=¯M7lØÐþóÏ?^™l„´b=Ô×:t°—]v™gª+þ­V+¯�‰'ê{mKh+ʳÅÜ UÄ2ÄÊF*+ñ¡u\o¾ù¦žÃŸGyÄÖ®][ßcé®õ.ø÷@~ØæÍ›ë+QµÝ|Ы&e+>¸ÞkÿÁìÙ³µþ?ü Å¢„ÛÎ�;{UDyÔó¢CµM6ÙD£d¸Ä; ·'o¼±Ê/³öÚk›O?ýT-Þp¿p‚;°žî·ß~®¨hÏp³pYqçw*cÚ Aƒ¼ÆEÅ6/l¼ˆH€H p{þ…øâ†B‰/o„&òG„€’ÿÌ#�p묡èCÑEè­ª BÔ9+®*Cb¥tEêç‹!É’©.Úk®¹F] à¢w•SO=U›ÁúÃwwÔ¨Q·ËáŸÞ>ø@Xø©ûßgp�€KÊÓ]›M²ª„ëÂÿ@²ˆ‘Ó€n~vøa˜¯/¸¿�ä>“_ûY¹sþ±âGA:¦îš\Ÿ©ØæJŒõI€H€JFÖ¹U¬Êçšk®©ãÀf!¿à<øšöñÇ«ï$,m°RµlÙRýbý×àÖ£jÕª©Å סl¸q e¾V$×FŸáï +7üSñ£Ša*¥3ß¹c  ÁZî~¨©|¦ÓÕ…‚‡Ýþظ…(q5qMª5Ö>©xÀ"Û¬Y3õ·E»?ÿü³ÁÆ'gù‡¯)¢à5ü¯+» r)ïU¼ŸaI‡O±q{0�5r/+}†Ò‰’NÜ]÷:ù ¼¿>þïÒI&¦é®Mw®ê?«ÒµÎs$@$@$ ��6ÚH7£@ÑÁnëo¼Q• X¨œÀÚë* Ô‡,E°°A° ·š“Ø(�â …JÌ_|¡É-zè!óòË/{/zÜÆ†k6ȤÚ�ƒzå à ¥Ñ!àš0vìØÀ¦ #ÙgŸ}VCñ½òo丣$Kºº°ªBÑs›™ ˜"1kˆõ;á„TIweˆ8€(øAT§Nu‡@è<¼/N9åý� uºkµƒ€þ8Ë.ÞÛ™ŠæÑG­›ä>üðCƒ¹àÇÜ1\;éÚÀÆL(§PÞ¡°b“89qm¸± >\6ðCe°Œ§“LLÓ]›ö\Ž>¹¬N±' ÿ0±Ÿc9O�ë›yõÃÎH,ƒ¶zõêV¾¸uó’øAê&±Ðêän¿ývÝP†Me¢dY 8o{ôè‘yâ¾ò…nÛ´icE²â“hÅ*gï¿ÿ~¯†(¹V%í¼ðÀ˜¾üòK¯NX ½¾¯¾úªk¡•ÈV”Èœ0¸Ícذ痋.ºH7ya-°îXsQ²´Šó ÒÕŦC¼/0>ñ“¶ºÊŠO«•¨Ú–${е”P`Vvþ[±ìj9þˆÅ_ËÄMBßb µbÕ÷Χ»Ö«$©6�a£•I„aÅšé^&Ã:_AÜÖ—8H1Öuù1¡¾Ðˆ‹ŠÛÎUXèaAD[°§“tua¹„›ÉÖ[o­þÀˆ¥Š÷B]A² nð±†ÕÓ/¨+J·º­ÀB™,é®M®[•×kˆlÞ“ø>Ã&2¬ÉöÛoŸ•µÖ?6X¶F 1ŒS‰,¸ƒ�M››o¾yÖ¾Ö™˜¦ê3]Ûttx®, ãC¿,Á†dÒ\ßÌ AF™E¹F1×±n±#ÿÎ;ïôb—F™Ç~TlÿFa‘ óC¿ÈScwB€ë›ùm@F™E¹F±×«5þ·Ø¼å|3£Ì�c/n ïÚpd$@$@$y«…¨ H—‹ðZˆ¡J!�B b[(²!j©á'Vj�O¦ð¥#û' ž¢RH¦.#Y°4¥+ÒÙRH ¨Ø‚jˆÚDÜEÙÕ¨›,J=,8•#7ÂŽPH€H€Ê�À‰'ž¨¡»à’€¸·ˆ K!� P± ’fÈÚ®`™¾ð uGc©‡‡œHmÙ³gO/…a)Ç¿/ljÀNO OSʡĢoÄ–DìPÄÿDV0õXL�“(KØQžK¶¥²„”ã¤�©oOx‡v0³fÍʱV'�Ê póXål"¿ˆ¯¼òJ#q�ËÐSêI!ÅÂæÜzë­ªàs<èY‹$†Ÿæ•Gß3K2‚ICñ†{c…vñ?÷‚<Çwœ¦¡DF ‰g¨þta›×7óŠ” #„ñ’Øži� 1Cß¾}5l•¿"ò#m/BG!ì˜ÄCÍØ–ÿúR‡i}ñyŒ¬Xþî¹ç– ûŽ �\‚Þ²ntȇ®J–ÜÝÞ §OŸn%õ¡•<èöž{î±âÐod"1ÿ4è2ÎKnl{øá‡kiùà÷®ÇÁ™gžih%VŸ=餓48º« ± µ}C— >V|¨Ü©„gÉ„bå{BY!_Ì™3GûCPo™–ÿ]ï! ¿}ôÑGºÇyJnd|Å—;· KP›ë›z90Âg¤Äæ´2ŸN$þg¥ŸeK–,ÑÏB¾ÿꫯÒ5ªsa[_$9�lo¶sçÎVâdžŠ=tE�ÿð8 nó,]ºTƒ1»ùÁª6nÜ8sÅWQJÕJ‰æò¶5|°9çœs4m\àÆpöÙg«”»Ïo¼ñ†™0a‚úíJv½•„òþýûkê>X/ºté¢VŒ^½zyù¸QÇ ‚ZÃ϶XÉ�·Á¸´ÝïÏ…€í­Zµª0G7Î0=â k(Ø!P6Ö k™,'N4’F­¥’5Ç´mÛÖl¹å–y¥ú/XüáV€�¸e(™�ÜHÀïÉ0£ð%Ó�9õÔSÕådÑ¢EÉÃãk Ü©Á�|Ö¥“F�Uzw w%$CU(ö0¤›CØÏ!˜?öƒà³¦yóæfêÔ©a2ÇfÑÓÅ9âlˆï¨Z%E õª?ÿüóZëÂc�=fEqÑsH)ïQ+>‘^]ÀêŠt’H«çD2±h]Q^-,�÷Þ{OÓõ%§¬<ï¼ó´î[o½å.×gXHÑÒ^C`‘‘\ñjQD¿îkmªô—86yñÅ5•á-·ÜbEyµò£ÁÖ®]Û[CŒW~¸Ø5jXQF­(•šnq·ÝvÓù&[Þ³™Öéa݇µë%>q¶{÷îÞå°ÐŠ"k;vì¨ýàòãÈJw¯^˜¸¾a⃱„™Þû¢Y—¦SòÍÛm¶ÙÆ>üðÃF¼w‘Jwøðáš.Ç’ÃÞ;�÷3þ—0OqÙ²·Ýv›•X'¿ýö›ÞÕBÛø¼K'ø_¤Å6¡ìω»˜• `öòË/÷Ræf5k’€|~B< àÃÚþüÓN±… �_$ —º$$+?'œp‚¶…É [ñϲ_|ñ…+²â¥õ\njw·—0 ïâŠôyæÌ™Z·†bò‰CiG~pŒ܂ė^*Áù0 nÕIb]I(Ÿ2eŠþ¸I( é‹°¯o°…™~´ÉÝ+±P•¤7µøQ=`À�û±Þºuk+›íu×]§ ®s;À�5¹¢ïånݺÙã�?Þâóεéš={¶•;SV¢”ÏTlSbÉ»PR¸Z¹ÛdÛ´i© yO˜J`5ù£Ä�Ü�ãZü]+ÌNü˜ÊjÕªeöÝw_#þ¶æÉ'Ÿ4¢ «›nß§äš?\ï”øìj_bÑóÊÜÆðÉ'Ÿ¸—úܤI}†«D¡9®qk¾iÓ¦F”4sà�ªKnéŸrÊ)…î>°öå VSRbó›(®¦zõêêBöX;nãÁíùÍq;®¸Å'Ô„q\tÑEFüŽÊÜ‹~ýú™½÷ÞÛ¼þúëï ±|¹SúŒìAˆl�ó{ì±GÂ9¾ �bÀæS¸P9Áÿò&›lâ^ê3Ü ؤ ¼§¥1½ñù7)Qf�Xy â©âÿ)•àZ¸äPŠK`£�6R—·k®¹Æ ¹Ã<`:uêTÜA°·È �md—.ýÀå6šú<®ºjÅ%–ÛÕ ÃöíÚµSZ|I`w*vª¦’äë��$É�ƒ:H-;¸ã’ŸhþâÀ�1/|(ÂÏyÊ1?±±à¹-x…j~€r»ÕÈ­Wý"ÆÚâÇBÆ ºWqû0wÜq‡‘Û§F,»ú…°çž{&ø‹ëˆÆ‘œ6mZ…g\AŸÅãW PŽèð·Åy „�”^'ø\CJ4à;âÒK/UƒÂVŸ?2¢±v¥%-¶¥^�õk6r‰ß—†×J×ÍUW]¥–Œûï¿ßÈí8¯*2Ä@&�À*ˆ‰#FŒ0uêÔI¨ŠpZ…ãX±qÃ…×òŸ òxòäÉfôèÑFnGzÍÊ-IƒG”DnµêF@XÄ�›Vüá0ñyÖÌ>µBó²£ üaáŸj�iŒ2ñ×ÅSZ�¥êæ›oÖ:âŸìÕ…ÅÊ/,Â(XX¾Ï ~ôùï"¹òtÏîG?þG*³Ø¦»žçŠC?Ìq‡IÜM >‹VÍYä‹3ö5ÍyQ›Ç›’,•�l"Àúk²À8AŒÆI“&éËL–Uäþ†¢Šh ~AÒ´ …×/PÀ o¼±¿8�c¿%QŠ%(µ�tP‚F`M‡õT|‚5ºƒl¾S+4"%À�?` à*.4鬺>‡�)V§VöýÁ{.#øqãÞCørA¬É-ZhTWý:·(áxÀ�…B…" ¾—ú#î÷ß×ä*Pv2}Na,þ:øÁ�×øÜÂç—øþ¸éø3#¢ˆÿX äÚKwÞÕãsÕÀPóì³Ïªr+bU¹­Z‹¼:Öä“C¢TêÆìôuâ6a‡½_\ô¹í£›Â“ñlÝf+lr°y ñý‚�ñØÅ*ú-¢0Àñÿ…^°r«Ü"¦­díñW·r«\Ç&!]Ê«úB¬³�ªŠüÃWµ‰À¯Ç®mñ;SnˆÅ+¾gºÙcETˆ¸h ¬¢YÈ—¶òÇæ=ùòÍyLØü‡÷6¤‰K‚nC|cÿîoìLk—Ž cq”á}F ãú†�SØáóM2Üéûð¾ÄûÔmvtÑ[ä΂¢íÝ»·¾7±áÒÿ¾”P€ÛºfÍšÑb$Ý«ÅfZˆ¤"÷ÞÏî}�gDS€ : úôŸÃ±?jˆV áŒ3ªòöÛo[ÙK`Å=Á"r…’ D÷Ý�<¾N – Ýù/¾²^yeŠ->È=ôP/”|`G°S¦.\¨í¤RlqâÝwßÕ/ÿ‡<¾°c9Y$^®~‰8e9ù|®¯åV¢*wr{ÊûRʵ ý°~è#º¢\à¹2 ®žBØ"(¦AˆXÁ­X±¾Ñn©Úëú–ŠGª~£ÂBª*øÑ‡ÿ›tÿWUí#l×Ge}+ã&nXÑ,­"ÕwLe×±¼<0¥®ü‡ÇU°QJ¬¯zk-“Ÿ,Àw»ìq«.ÜêÉ ·w¦6°) ·ñP›p =YP©Wq«{È�!ɧóz��û¸ÕŽ[õbÍÌ« ÿE˜§üûû‹x#\ßÌ‹IF™E¹F\ÖÑà.…ï$¢�P±�ñûQ°;a®$€~(fúôÓOë5øõ"U‚\ãGqDMiqùÐ HÌâúf^P2ÊÌ(Ê5â´¾0ÆuÔQú]w÷Ýwq¡‹òÒpìàæ± †µ ìv›‰Â2ÆÁƒë榪(µþ b˜W�JmX8q$@$@™ F9Âb# d˜ÓM€™¯b�8 bçÕ•¹!-Üb«Ô+-¢5 À¾"Ì>ûì“ï弎H€H fà:‡pˆ×_½‘ ¯fذat'‹Ùç2º"äB‹uKJqU do‰ %qºMW(FQn—ë›yõÈ(3£(׈óúJºwÓ¥K#iŽÍC=TðxéQ~Äuì´ØÆuec6¯3fhÜJÄš,¤R3lœ � ”$±AVE$™ÁcÊ”)e5NÖ*¶|D‚¢H<]ƒ,g  ¨ŒÀj«­f$Ö·¦G¢ì5ADÈ…^¨~�­ŽOtEˆçºF~VÈæóú믛½öÚ«ès‰ómº¢Ã a‡\ßÌ‹BF™E¹F9­¯Äô6]»v5Ȧ‰Ð`Pt%†ºî÷À�@JüÐb¿5�üŒ$3�i×®](6¼E&'@eF€1¨ËlÁ3LW21ÉgöÜsOõ½ElvXo?øà�}žáržŽ *¶\´8¿ 9¡mÛ¶F2ËÄyªœ �@§É^$u®ùôÓO5ãÆ�Í&›lb$ã¡¶°bÅ sÁhvÈC‰™5kVBë7Þx£¶±ÖZk™Î�;«¦¿ÔHJ]#éZuãQ«V­ÔÒç¯óÈ#�¨ß¦¤æÕ¶7Õ‰¤½6’ ËÜtÓM×B¡’4åwŸ(¥'0yòdÏ£AØHI'o$ExéÇJ€Šm 8ÙXU Üpà fôèÑfÀ€UmŠ×“ Ä€ÀV[me~øaÍ‚xúé§kÌÒ[n¹Åœzê©^†Dc“Od>lݺµÞõA’'’6Wý.¡(·lÙR•NwÏhsÍ5×4ï¿ÿ¾™?¾Ùxã� î9yðÁMŸ>}ÌqÇgæÎ�kN9åÓ¿ƒh-”C™E¬n„4D}dÆzóÍ7]|.�^½z™wÞyGÝüCX¹r¥9þøãýE<ŽúØÆ`£>Ü:„ÏDr€’·*LÊÉÿ¬*œ¢z-×7óÊ…‘¬¶»ï¾»Þ>vŸ˜ ,nHF3uêT½Ûƒ2XIwÞygµÀ^rÉ%(Ò2DU�¢Y³fM%VZ¤ã†Àz‡×_|±*µ°ÊΛ7Ï4oÞ\Ï7iÒÄzè¡æºë®Ó×øƒ Jˆ™ºlÙ2-C²Ä ¿êª«ô5Òš¯¿þú¦P Bò'Œë[H4XG„ÃXôñ=ãü#FT°Î»ó|ŽZl£·f±ñ“O>©–7)D? � �@*½{÷ö~»óü±|ðÁªàBÉmذ¡ùñÇMõêÕõÜêׯoúõëg¾üòK3}út àÿË/¿¸fÔ•V]XskÕªevÙeµò¡|2áqÈ!‡xõq€×P†¿ûî;¯¼Y³fÞqƒ t^JBkåÉà>‚¼ø®Á�Xmáö†u¤ÄƒÀjñ˜g5pà?çœsÌ„ ˜7j‹Çñ’@ˆàö?,�ÈJXY8@ø×ÂÚ:|øp9,vpoðËÂ… Í‹/¾¨–]㳩oß¾æ˜cŽQy£�6ÒH-ðßu‚È-p_€U–~øÁ‚¨x@fÏžmžþy3tèPÝLJô Ðbý5ŒÜ þøãµ†üôÓOúÁâ¿­†É¬¾úê › Â0&Ž!°¼a})Ñ"à6`á䃦M›êæ²�šÅ‹ëÄ`�ƒŸþÈ‘#õ5”R|Þ`“|h{ôèað9äo¡ °mÕUW5ðë…å¶Zµj¨ž={š»îºË øÿÆoèF±N8A¯AE{©^{�ñ vÜqGõ“†uŸJm(–$˜AÈ?"…ŠJ@¾Xì½÷Þ[Ô>séL¢2XñÃËåÖ�¹måË,"£-Ý0åÛ¥t�'õ,Ö4‹ñø�5J¨%¬D"°¢ˆÚºuëZñ¡µbiµâ> õÄ]ÁН¬•5V,¬öŠ+®°ø?K+~—Zgï½÷¶l°�­S§Ž¾G$ò‚• `^?¢[¹Ë¤m ž$°'Ÿ|²w­3dÈ£¸?X‰Ö`Ç�¯ã‘î¡û¼ Óúz€y@àæ1ù§ž¬#ÎßÍ\øžsï¡{÷î¶›H(ñ"€ëØï,yñš]p³‰êæ¢ï¿ÿ^-³†ìSÉ‚(õêÕK°Äº:°Ú­»îºº±® h#• ¸?ütq~�5ÖHU%ôeQ]ßЃåCA€Šm(–!Þƒ€ïÛ˜1c4 NfŠÎØl€ÐA:tˆÂ�9Æ,Àg²cÇŽ„Ī—Åå[…ŠO¼×žëïõ-÷ÙÑǶÜßž?baY‰ÂŒƒë[®l5芎uˆÔ(¦M›æ�WÒSR©õhð€H€H€H ”¨Ø–’~Äú†eö´ÓN3÷Ýw_ÄFÎá¦" 9î ,7_ýuªÓ,#  �È b¹%+Í€¿ýö[³Ë.»höÛo¿½4ƒ`¯�xâ‰'LÍš5 iPH€H€H èc‡U,®»î:�OÛ³gÏ"ôÆ.ŠA eË–fÆŒf½õÖ3Ë—/7ÕªU+F·ì#ÖXc ³bÅ ¾'"°V¹i¦ñƒvåÊ•¹^Êú$ ´ØFb™J?È~ýú*µ¥_‡ F€¸Ãï½÷ž6‡Ä/¼ðBPM³�@b¤Â¦Ä�À¬Y³4ÅtüfÆ‘Àÿ䥨~ôÑG¦ÿþ¦}ûöæŠ+®P?=øêá�×~áùpóy衇 Ü (åEàÑG5«®ú¿ÿŸþÙÜpà 倳MK Y³fæå—_N[‡'£I`üøñ?\¢,ÔAþ[½¨ëX…ÐArvEX´h‘iÕª•éÚµ«Zð¶Ùf›ÿó(rÆŽk:wîlð+~ç�wŽÜø9àü4mÚÔ|üñÇÞÅÕ«W7Ÿ|ò‰iР�Wƃò%°lÙ2µê=òÈ#¦C‡å "f3Ÿ0a‚騱£Yºt©©[·n$gG$’ËVé  ¡ƒä¬Ø^rÉ%fß}÷å‡]¥Ë½/¾ø¢þPY°`�©U«Vô&ÀçD íŽ;î¨>”îB(¶}ûö5ƒ rE|.ssæÌ1Í›77W^y¥*CØáÕW_]]à^‚ÿû¨ZjÝ2Pq$âõ¤’³b/”œ ”�N�:™‰'Xiÿúë/S£F ƒ]ðØ)ýæ›ošúõë—ΘH€H ¨ØÆb9 È�@›6mÌàÁƒ ž)$@$@$u9EE¸ð £>_ŽŸHÀG·)á‚B! �° ö ÇørRláA‰/ÿ.ùøÎ’3ó bë§Ác �0 æÕ©úØ‚ÒArRl«>l¶fE)/TlËk½9[ +� t*¶a]aŽ‹Š@`µÕVÓ dEèŠ]� � �@Á 䤨ò6@Á׃�@Q Ðb[TÜìŒH  ¨ƒT^]š“b‹î”øØzë­ã;9Î,%*¶)±°�H „¨ƒ„pQRP:HNŠm€ãgS!$ðÁ„pTR! P±-$]¶M$@$�-� t*¶Ùg=ˆ!*¶1\TN‰H€ʘ@NŠ-cÈ•ñ;…S�%n‹å²rR$KÔAb¹¬�O*'Å–ŽÛ�óUƒAÅ� Õ¤8˜´h±M‹‡'I€BD€:Hˆ£C JÉI±-À<ØdˆC.DSâP2 b›O“ � …@P:Û¢,;!�p bÎuá¨H€H€ò#�“bËÛùAæU$VTlú2 �@2ê ÉDø:�œ[Æ�K…0>eAÅ�‹‘øÏ„Šmüט3$�¸ —•L=� t�œÛÔCai\C..<ÊaŒŠP«Ì9’ �@ø ¥ƒP± ÿZs„$P0´Ø -& (�œ[Æ�+Á ±K( *¶„˦I€%@$Pœ±m,'Å–ŽÛ±}èÄ‚Š!oJñšÛx­'gCq&@$ΫkLP:HNŠm¼‘rvAÅ�#Éè b�µâHI€H ΂ÒA¨ØÆù]¹‘@Ü<–O“ � DŠ@NŠ-oDjm9XÈH€ÛŒˆX�H $¨ƒ(M«�@IDAT„d!B>Œœ[Æ� ùjVqxAÅ�«â0xy P±-"lvE$P%ÔAª„/ô¥ƒä¤Ø†ž X%AÅ�«Ò xqQ P±-*nvF$@$P � t*¶•f1 ”*¶å°Êœ# � ”�œ[Æ�+Ÿ7gZ¸y¬<Ö™³$�8 ‡U,ürRl£â¸½páB³Ê*«èã•W^II±_¿~zþ‹/¾Hy¾ ƒŠ!WŽì¢:gZl£ºr7 ”�¨è å·2ÁÌ8($'Å6˜¡·•Þ½{›•+W·ÓˆöT ¹ˆN¿,‡MŶ,—�“& �ÐJ‰µbÛ¤Ióᇚ!C†„n9 *¶aXŽ�H€H (9)¶Q» pÈ!‡˜ý÷ßß\}õÕfþüùY1{â‰'L§N�LÆ Í�hî»ï¾„ë.ºè"ƒv­µ^ùÝw߭׌;Ö+ûóÏ?õúáÇ{e< �° b¶áxH€*#5¤²y°¼°rRl£CîöÛoW‚§Ÿ~zF’ýû÷7G}´Y±b…éÒ¥‹>÷êÕËø¯­Q£†yöÙgÍܹs½ö~øa3nÜ83f̯læÌ™æ…^0uëÖõÊÂ~T ¹°Ï“ãû�ÛÿXðˆH Ü¢¨ƒ„›h¸F”’“b.Ù�¦Q£F ëĉÍ#�¢#¼ù曦Aƒ‘ Pl±ø³fÍŠœBÂäø¢lÐb[6K͉’@ä J�‘ †¨ä>›5kfŽ9æóöÛoGž_U&£ÝÚk¯�Ö´*íòÚœ\âCoÜ»îºKݰÉËÉ:ë¬cÆ�oºvíª›Ã\96ŠÝtÓM¢À" ×ø×:Ùh£�4ú6¢uìØÑGæ9¨r‘™0ª~åþÿ"! �°(´‚Mà;7}X'?ýôSóØc�iüz$aòç{y� t�œÛ@F^„Fà/›ÎW¿À6Yš7onÞ}÷]Mû`ÁÍ>¶ýöÛ'WÓ×íÛ·OÙüt£*AÅ�‹êüËqÜ´Ø–ãªsÎ$@©pÀæÈ#�¬p wl÷ÜsOua¤b[O`Aé 9¹"6ú7„MbP|‘N·2¥6ÄÃçÐH '…G‹mNÈX™H Ì´lÙRÝ.\˜0óo¿ýÖôîÝÛì°Ãºïqð“ëœrÊ)æÒK/Õý7p…lܸ±�eF´_~ùE3›ÂR‰}>¸ œ,ï½÷žê#¸#¼ñÆ›#Ž8¸𣨋$R�;wÖHLþk™ ŠúàÁƒ½âlÆ‹Ê0ü]vÙeê¶ …þòË/¯Ð¾×hrRlC.„+È!‘@ ¬ºêª‘ØPÅiòr �ˆ(•2wî\½C»Ç{xqWwç�w6HÞ„r$dzòÉ'õJ«$szâ‰'Ì>ûì£Ê,Bƒ>øàƒª¬"3)2¢¢$�‚«Î9yùå—M«V­Ìüùó ”⣎:ÊLŸ>]éwÞyG«ao\$^zé%w™>c�¸ƒ Év¼p¿@ˆÓ+¯¼ÒÀð��ò²²FFä–}Ö"“ʺ.+F�€øGoÐq• T¯^Ý®X±¢Êí° ($�Bé ’˜É¢í«¯¾Úʦpï!Q’ì€ì[lae¹[ozâ²`寥Ó+ûì³Ï¬„ µbAõÊ$ë©¶=|øp¯ìüóÏײÝvÛÍJ¤-ÿæ›o´½ãŽ;N_‹‚iå®±mذ¡•ÍîÞµèC"úh+›½¬X…µ<ÛñŠ?±ŽM,½^{ýÉÊ�l-%Ý+ú ($'MµPoª á°½üp}óãõ«ðá'II¢> ŽŸH æ õå[´_Ùãÿþïÿ<ºPBQOnõ{eî@,›VÂ(Z±Àj[±ªZ‰˜äªX±Òêõ~e'¡<¶hÑBë½ñÆZçôÓO÷®s²É]ωk�‰ß¯­U«–}-nv­µÖ²Ç¼¾Îe¼mÛ¶µuëÖµ¿ßu§ÏbµÕ> ©Øµ¾±Ü<&p($@Yà²,A± �@¬ \tÑEêWê&)w²t39|_á0{öl�|ä2d-]ºÔœx≮º>cù_ý¥¾¶.ÂÜ‘ÉIÍš5õ1ñý‚=>Hq~´­[·öWÑc$zôÑG ÆlnC¨W^yE£:Á51gE±Õú¹ŒQ�¶Ýv[uCðwŒ½GQ‘œÛBÅ�‹ ,Ž“âH€ŠmW•s"�ø(´"ÖRÝp•L›¶zõê¥!AÅk–-[¦U·^îv%T‡-b1õÊýÇ^¡`Ceâúpqòýõ 8Cœ²ŒHظöôÓO«b;zôh�±�Øú×V6ãÅ3Ì1Yœ2ž\Æ×9)¶…Ž!F@å4¦ bÈ•³8Ì•ŠmV‘s �ø(•‚¨gEu²�ì qîý‚ÍWP""8�;Â×_­Ñ F YS�ä2^ÙÐf~þùgÍ ê®Çó¨Q£ü/ r”RpÅVvÓ™]vÙEã¯áD©ä»ï¾Ó_[þ7üHð‹«Ôò /è-øÅ@·&Nœè ¿q‹€BA Å6h¢l�H N ÄB–,Y¢Ïp-èß¿¿�?j¿~ý4;üXÏ:ë,3iÒ$-Kçf �døk,Bl=÷ÜsæÚk¯5°˜Î›7Oýfa(Dl\¿ ö>pøC)öûÄæ2^‰a`ì@ßðÛ…AýÃIØö–á…,`†O‹¯‡î¤;çœs¬8UW¬P¤’K.¹$a!ºÅnÃ|æô�å¶�ŽMbÎiÓ¯¾úª•8rVÕõ5v:ÊÊŠMÐ]³=°Øµ+˜$A$@¡&P¨ïkúJ*ƒ˜]sÍ5­Äuµ~ø¡VË©8p †èÂ÷3ˆL ~À ðùŠH~3fLÂw¾;'VX+qcÝK+–S‹ð_®}<רQÃÞsÏ=^ÿ�økÝo¼Ñ_¬ÇÙŽ•¡“¬¿þú^¿²ÉÍÊÆ4}]Ȩ�gÁ*¸N`e%°"æP]ÛÀš¿4`!-•à×�ĨS«§Ä™+Õ0Rö ‹-~m!˜r§N�*ÔAf(J†sø­·ÞZá|PøÅÙ¤I“ šc;!€¬9=ô�ýŽÈ�9L �2$��RhL¸Œd 6Ÿ9·… ûýꫯ4s™„áRK¬(·y7Ÿíx‘¹lÆŒfÝu×U·¿¿mÞ�g¸0(¤ ®HÉöÀèT�ö ælÒÉ!¬F²Àô�ÔmN�Šîšk®Q‚c�=Ö`w Ò»ÝqÇ®Š÷Œ€oKíÚµÕíAâ¼y©íp{@‚kÝ.]ºx׋Yo'x�ÈA¦ôu¨;uêTU@a¢‡ã8Æ´å–[ ˆl¾üòKso¢›o¾YëÃéðn¹å– ;)ýÁY»18‰Cé…<ûì³Ú²š@¾í¶Ûü—éñ�wÞé�­ÂÉ M›6ÍPƒ§ãH€®q\UΉH  s ƒ˜Xe ¢Ôb ¶ÿþû«â\¥me;^±P‰�kZ¬J-Æ”RPÅ`Ü"@ëwá"à·E4YƒmÖ¬Y^1RÑ!Vâ´Á¿ ßøê:E•Ç�oë þ.ˆÛ†pHs‡úøÕ!Y:Œ¡×v‘oÙý¢ÂuèÓI6éëPwñâÅê4ýª«®2’D­]ð�íСƒkN­Û|°�ýûï¿kJ<ä`>ûì³ õÊÊñSO=e#;+ëׯ¯Uá'ƒc(ø°€Ãž,P´‘~Ïí¨L>Ï×$�L€›Ç’‰ð5 � �@d äâÂß‘\eذaê—�´oNdÇ`ŸœCÊ:±Nºjêû'`í 7Üà•‰I^}Z$o²–!í²uˆÂj‘]Éó™Q‹RùØÂ÷E¬­^;Ù¤¯CeQšuNrÛ>¡ÏÓN;MËÅ’«mŠY]_ûÇ�ÈV"¿€¼4¦É>¶®}¤óƒ¤ò±•°'Ú¶XoµþH>k-§v¯,—°¦”Ù@iå.DùMœ3&ˆ�|t�HM°Ì”’“Ŷ1ä`‚‡ÅÓ %oµÕVÙ= Ó§OWë%B[Àën çž{®�Õ8Á-ÿ9sæh,8˜ê�`gbÇŽ5¼†äkvÅú,ùžú„ÙâÆK1¬À'�t’–»?ð“AŒ8„äÈWœÅWœÐ½&Üñ1Çã•årT ¹\údÝÒ +Bé×€# ÈL :HæQ±FP‚ÒArRlƒ|.íà–zrØ (ž.ÛǧŸ~ªÍÁýÀ/¸m/ÖbuGð—Wvì/W–¾×Á±Ù/byö¿T߸±!h22Ìœ9ÓH ÜœßqÂÅ9¾€ß üQ�iÄ [¸EøÃ|¸sÙ<C.›¾X'<¨Ø†g-8 (WAé ¡Rløá‡ ëéür+œø·~¨� ü[’ß“K9—Mú:×C¦±!îM8–¿ñÆê+²¸,¸&ªô «-6˜A¹_°`�æ±Î×Z[¥�ðâH béåãàI€H€|rRl/¼ðBߥU;ô'J@KPP�¥3—–‘þ «¨_°IKülÕ…À_^Ù±Ûl…ˆÉ’œ¾.ù|e¯±±Lü^Íý÷߯á@î½÷^sæ™gzîRqî°Ú:7WV•vymyàæ±òZoΖ¢J H$ª 8îÌrRlÅq;s‹YÔ€é\\uÄpÍGvÝuWÍ’�H ~9r¤Æ}Eü·l$×ôuÙ´ ÷D…ð+›H‡‡Ì$ñϦ™Jë æ,Æí[D�p¹£+½(͉dW‹4Uy*Fh±�Ñbr*$cAé 1Fé©¥ƒä¤ØE )vq›±l±ù ñX±AÌ…áÊ¥(É’mà -,¤Ø¸K-ÒÂAÉCl[Ȧ›nªÏ#FŒÐ¸¸úÂ÷'×ôu¾K+=Dà{„ù4h�ÎW¢É(¦n¸‹E7“@ñ@NhlDƒRŒ„ N 4ÃÍÉPâŠóz*†\^�ó¢’ b[2ôì˜H€Hà_Aé %Ql‘cÖÅ!C†˜V­ZiÂlôÊwRH€ á¿T™ÅÆ)dè‚"K¦‹_‹„’®ÎHØ/Mª�ê�„Ä Ýºu3_|±Æ�ņ4´!éë ;ä*˜ç¡‡jð+ 8-@�F‚Dp@b‡l-ʘ“„L3íÛ·7?þø£7çS _Œ�B¹ b›+1Ö' +�œRê:Ônã믿V¿Ú B<@áƒÅJ-ÈT>¬H~€0\.qDª… 2}ÚGr $�@º=×/,¹Øð…¹§gªq!<þ°f°ÞÖ«WOhøòVE0ŽªºGT¥^[G‡˜ÉaéJ3öJ$@© ­ƒ¤î…¥¥"”’“b[ªÉ²ßÊ ÜàÒѲeËÊ+fqFV˜ ÂmdÑ«„„@ïÞ½õnž)$@$@$P Aé «•bðì³êž{î9óÒK/¤ñEêàª*µ•Úª¯K[`T„(®ÇL$@ñ"”RÛx-Eifƒ˜¿¯¼òŠÆÈ½ï¾ûJ3ö ô±�Å2r$@$@B 'Å–1äÂóžA aÄÈ5j”©_¿~xÆ‘DŽÛÈ-LeI€:HY.{ΓÎI±e ¹œùFê‚ bÈEjÒ¬¡bË7 �@P‰Â*å?Æ t�œÛü‡Ë+£@ ßpkQ˜ÇX9*¶•³á  �âJ¡b[œõb/$ZÜ<Ú¥áÀH€H€r$�“bËÛ9ÒeuˆZl#°H" �€&;"ÈD 'Å6Èä ™ÆóÅ'T¢Œâ�œ=V…ÛªÐãµ$@Å"@¤X¤KÓOP:HNŠmi¦Ê^‹E ¨rÅ/û †Û`8²  �ü ¥ƒP±Í x% Ä‚ÛX,#'A$@$ rRlCŽïˆn‹ßšrF$GÔA⸪ÁÏ)'Å–›Ç‚_€0µT ¹0͉cÉL€ÛÌŒXƒH ô¨ƒ”~ 9‚ t�œÛBNˆm—ž@P1äJ?Ž Tls¡Åº$@$@… ”BŶ«Ã6I B¨ØFh±8T  �´rRly -Kž$�H bÉeã I ìP)»%ÏkÂ9)¶Œ!—ãÈ\T ¹ÈL˜UTlùF ˆê QX¥üÇ”’“b›ÿpyeC. såÿ#À¨ÿ±à � �@i¥ƒP±-Íú±W ZlC³ � �@ 䤨2†\iór!*¶!\‰H ê �° �œ[:n§ £¢ bÈÅIYL…ŠmY,3'I‘'@$òK˜vAé 9)¶iGÄ“‘'T ¹Èƒ(³ P±-³çtI€H „‚ÒA¨Ø†pq9$(&n+&möE$@$PH9)¶¼ PÈ¥(mÛÿüó�©V­ZiÁÞKB€Û’`g§$@9 ’#°URÉI±e ¹½KrêW_}eÚµk—ãU¬Tlã°Šœ ÄŸu�ø®q�:È*V$¾¨83 �L>ÿüsÓ¦Mƒg � � D™@N[7Ñ9sæ¸C>“ Dœ-¶_@ŸÊŒu�2[ð§›—b{ä‘G𫝾ÚÌœ9Óüý÷ß9vÉê¥&#=°ÐÝu×]¥û/1n+ñ°{ �œPÉ Wè*ZÉK±}ýõ×͇~hN:é$Ó¨Q£h³gÏ6«¬²Š÷hÑ¢Ïû„�Ϫ«®jªW¯nZ·nm–,YâË‘-¶å¸êœ3 D—u�hëX…ÖAècÝÿí¢Ž»Q7Ø`Ó³gÏ¢öËÎ Oà—_~1m´‘Á3…ü–-[fÎ;ï<3wî\3oÞ<óçŸúOó8ðõY³ff»í¶3Æ 3uëÖ�À¨9DÈŸ@^Ûü»ã•Q%…Š]»v5?ÿüsT§Áq§ @‹m (,2ðc„B„ÇðáÃÍŠ+Ô…ÉÝFäóÿ\ºÂÎë†õCðûzõêéºòíMq&@‹mœW7à¹ýþûïæœsÎ1ãÇ�7£G�6Én&wÇæŠD`àÀ�~¶x¦�ÀR %ÿë:t ”˜˜0a‚éÖ­›Zßi¹�É¢rP±­€„™<õÔSæ´ÓN3ýû÷7gŸ}v¦êáX‡B�‚ë[(²l7 芆U(³1l½õÖfÆŒfýõ×7;ì°ƒ™5kV¨@ñ騱c¨ÆÄÁC mÛ¶ê3Lkl…H€H lh± ÛŠ”Ùxžzê)sÚi§™K.¹Äœ{˜ýk¬¡>µÕªU Åx8ˆàüý÷ߺyqåÊ•Á5ÖhÑ‹á¢ú¦ÄõõÁàaìP±�Ý’FoB .4G}´Ù`ƒ ÌC=dêÔ©SÒIðC¿¤ø Þ9×73b2ÊÌ(Ê5¸¾Q^=Ž=º"d"Äó'°ùæ››×^{M}n›7on¦N�Zð>Ù � D‘À?ÿüc~ýõWƒ»”ª@(ÊAƒ™u×]×¼úê«UkŒW‡†ÛÐ,EydµÕVÓH ˆšÐ¥KsÅW|€SH€¢Cà‚ .0°úpé�_ý±Çk^ýõèL& ‘~òÉ'æÛo¿ ¨5c²níµ×6cÆŒ ¬Írièûï¿7�=ö˜n^Ʀå6mÚ¨bûÛo¿™m¶Ù¦\0Ä~ž«Å~†œ`¤`ÓÖìÙ³5,Ó¾ûîkF�e6ÞxãHÍ�ƒ%�r'€Ä&›m¶™b€Ò€H(ãÆ�3ð©:t¨9ûì³Ë’º4nÜØôéÓÇÜzë­e1ç0NrîܹªÌ~ú駦F�æçŸö†¹æškš{î¹G]á¼BDšÛH/_<¿ÑFĽæšk ’;<ðÀ¦S§Nñœ,gE1$pÌ1Çh2ÿÔ–,Yb=ôPÝ$º÷Þ{›wÜÑšÇ$P00�,X°@³Gú3HâNa«V­ônBÁ:gÃE'@W„¢#g‡ÙXuÕUÍ¥—^ª·ÛN>ùdƒ[œþ¤lÚ` �ðØpà ÕZ‹ yW^yeÂÀp«¾wïÞþé�aáĦR¿tëÖÍÜ{ï½fÒ¤Iê®Ô AÓ®];3eÊ5sÖYg™Ë.»ÌÀŸx w>›~Pá÷Ûo?S»vm½cÔµk× ã™«?Îúé'o,O<ñ„–5lØPëÝwß}Þ9w€è˜Ë^{íeöÜsOsùå—XÀ)¹þøc³ûî»›Ï>û,vsä„H \@AÛtÓMÍo¼áM–4(�?þ¸Ùc�=ôÿüÉ'ŸÔçwß}׫÷ôÓO››nºÉ~øáºq +\ ÜŽ;Ö«‡¶qÇY¡,"^6$Û~�q°uëÖæ£�>2ǼnjÅØößO©„[EûöíÕ_w“vÛm7u³ÀXœqõêÕMýúõµïµÖZK�ñƒÒ¿�ƒ”ÏØS€gdb<ýôÓõ<þ`sØA¤? €AáðÁM�=¼:<ÈŽ~LÁŸÖÂkrã�7šM6Ù$»FX+:dÁ)$ ·Ür‹•�`V¾d :^ùï-hûl¼´¸¾™ùçËH¬–׊µ²ÒNäǪÖË£Ö9òÈ#­(vþüùÞ5òÖJØ?Û¹sg¯¬fÍšz�ÜVöʾøâ [«V-+¬(‚Z.ÖS­' £ŸJ¯n6ý �fÍšYq‡²ß|ó�wíí·ß®mŠ�°–‰×JZfûûï¿{u0gÌ]br{ebqÕ2±@{eï½÷ž׊‚ê•á@ü’µ®c'›œôµX½z?þø£ŽýˆÅ×+Ïõ ßõ͵Ÿ0Ôÿúë¯í>ûìcÅýÅŠåÜŠ�­¾ßvÝu×0 �c(Zlå?œ ¸ík ’9œrÊ)jåˆÆÈ9J Gñª5᯿þ2‹/6°ÎºÕV[¹*f‹-¶ÐÛóøÿᇼò¦M›øï:�õ÷ÄO4|ð�ùüóÏ]±¶ýõ×›F�iY¶ýLŸ>]S.#­6|ý�ÀJŠ2Øh�۬°Ê:qóåÓ¥|¾ãŽ;4â Ü-ü‚Ï7¬Ã¤åÙôíÛW_ãÂRõë×Ï{̓ô`YÇ> d|ùå—Õΰ†?óÌ3é/æÙÈHt8‰ì48ðr!€)DM@¶2øµ�=Úl»í¶å2}Γ"O~®Mš41·„8¢�¥K—ª‚êŸÜû￯Ê/|mÝF3\—,îÿnJPˆ!Ûo¿½º<¸ºpe‚dê»æ!¸íïܶ6l˜W׉åË—«Ï0R‚ÃÍ;ïÅøäÕ©ì.«¯¾º+p…*(‡o0õ07¸!øE,Êþ—ÀÙÆ‚±úçêŽáS‹ìüðÏɵ-.î�Ï)à‡|¹ñÃF¿R›¢:‹bH€Û.j¹Lé„NÐ &Gu”Þ¼ûî»õV]¹ÌŸó$�¨€õì�?þð”7d„@ÁÆ0¿àv1Üü·ûSm?[½,•5×µ—m?ˆP�ò�Û×N�Ÿ/PÈŸ›¿¶ÜrKµÒ:‹ª‹� 7‹t‚±@é‚«Arúp°qœ0¸F€ƒ+C»‹-J×|YŸƒ[ îæa}Î9眲fQΓ§Å¶œW?s‡ÏÂêÀ¿ ·+ñ…D!�çž{Î q|iñ£‚Œd°¸Â2Yn J ?!nû÷Ýw UyäõEõûÄ&T�Ùö#Š4$Tr±‘#Gj²¯¾úJ#³`LÇw\‚›ÀK/½¤ÝfrG@¸>º~AJWXš¡ðBiÊ2æìÜ^§$�M|.î /Ô}Tjù”Ý«lHc“$PرŒ�Ô7Üpƒ•/Ž¼Ç y_Ë ÃO€ë›y�òeä¢"Ȇ.�€(;ä�C¬X2­l~²b­LÀ�!Ct÷¿l’²â_jÅ·ÔÊ-¿V¯®‹Š –TûÊ+¯ØyóæidŒUÂ`yõ¡eË–Þkw�m?§žzªŽÑÐÇm·Ýf%l—ÿ]+ЦW+Vd+ º�6mšÿ]‹ˆ-ˆÎ€òÃ;ÌJêV×­•ø½V|eíĉ-¢$ˆÛ�–¡=Qn5ú /¼`ÅBkÅle³œ^‹v%\ç+›ã¬¸@X _¦láˆñ~B$ ÙT¨l=ð<([ü/Û¥�çÄñá/–+±%õ (ŸYæû¥žO_¼¦ø¸¾™™çËÈ)¶¸Þ=ÊKbPÛX„ºJq7°ÔLî(‰²Á'á*[q;²’vÛka³$!CB“•)¶Ùöƒ^SV•[7¹dÅ_ÓëG,¸ªèºó}ÁJüZ ÊÄ"íÕ4h�?a3”bˆÄçõÂv¹6$î®*ÒÞ…rðüóÏ{Š,êIÌUUrqLÅÖZ‰S¬Æ IÜáÇÆã2'° æ/ÿ$ˆ øåÉ—¨f”yôÑG Òwæ"ð‘K÷o�µ¸å•N°ÁÍùÜ¥«WìsØe�lJbi*v×Yõ‡á¨×’\D,^êÅ_̘~9ÓúæÒo\ë–‚\ %}×u½õÖKÀ‹P[õ…¤ cVýTáb�k€ýLý¸N±Ñ ¾°È˜†h —_ð7(œß\\&œ BÆŽÿ3'¿üò‹ÁÃï.ßY$˜@}øÓ"’C*A¦1dBC¨¯æÍ›'øÛ¦ªŸMY)Ö7›qe[Ÿ­bY7Hà¿Z‰cœí¥¬W¸y¬ ¹Ü¦ˆ´‰ØµŒÍG}´n&€¢‹ PH¡˜ÂW.Õë\X!¶%¾�R‰ÛP’ê\)˰{Jw!z7n¬¾Œ·Þzk‡È1�AdîÊF�ÑËeõʦ¾¿N¶ý@9E¶ÃÊÊ!ü`“Å…ó—ã.ùÿŸGÝ•)|ú\œûûŽÛñÛo¿m°a™åàœ#nóå|r'@Å6wf¼""ðÁ‡_ôÈó%AÕÅN\ñùS+HU¦Ò³gOMÓX•6Š}mªØ™Åû# �|Ü|óÍF\;Ì]wÝe$“\>Mðš2 À¨e°Èå|xÁÑ`Ç6rÉãö©_Ð÷Ál¦N�ªÅݺu3â'f&Mš¤ãDŒLX¯’wg£2â[öîÝÛì°ÃHŒ»Ñ/¸EŠ~˜í" üäÉ“5Bá8A72Ÿ3gŽ�¢‹©øêÜ:EîzÜîÅNndrJ–lÆ‚9b,Ë„�NX „J‚5ýË/¿Ô&1ÞöØcVüWµ~*ÅýŠÙkÏíl‡âý믿j¹lÖÑ~%v§W/Û±8ÅVèkh#×sô�yB ¯Åíªh(%”!„›_8àÏŠ+´˜Š­ŸNÕ�Áœ_QX_|æ!¢Â¥�;6¾‹Á™N€>¶òN‰7øÖ"ƒ�(ƒºÑÀE+@ô”#rüpsl\¨l“|x�À×÷ä“OÖÌE¸…&18�(jn«â6+v};AJQQÊ5G½„13H¥‰À¢Ôi�{W›Up·é$¦Fpç°É·üÓ Ü50>'p[€À5W ØÍ —¸p@/^œóX°þ]áØ_9ì<Ç\S ¢#¼üòË^ VW§nݺêRw nqTøLñ €¨øL�G#eä»Q048‹\ P±Í•ëGŽvK u#AÓ5+�$rÐLGøÐD Kø·JlÌœCL!7|›6m²âÿTdW3fŒ¦M•'UJP„ç‚ •¨Ë�|öPxýåŠ:|m‘�͉XqÝa¥ÏUäe’F »¸Á ß]H.cñ‡Dµ.R:_Y‰gjÉÊ-”zp@ß‘D!ˆ|NÂÏÿŒ3ÎPÿ‰U¿IrF%@Ŷ xÙx˜@I‚õÒY0ůÓÈ-l3tèPµDbsJ¡!ÈœuVÐTÖ©Â�!Ý(J­w×cqg0ÉÊ ,žxH x­ãþdcÍL¾Æ]›jŒî\>cq ³k#›çE‹(çsçÎU…ÖdX¬¡ÈÃÚK!ˆ„ûÃFVÜA=z´)äçq<ˆq• b[–Çž,›xø£jÒ_|±ùôÓO�ø×ªÕøž{î1²ñ+¡;X#“‘ °æ:t¯½öÒèþºˆô‹­øû‹ v쬯…ËUW]¥Jíý÷߯V7!¸5@ü–fwŽÏ$@Ñ"€;M08ÀÅH²Óyws¢5 Ž6,hãËJp±%€pWH8Ð¥Kƒ Y’~ScêÂéøì"¬�_à7‹{çã .nÕ%Ë~ûíg lš[ �¿m1Æ‚Ld°:KdoZPà w �@t ÀÅHÒ ëÿ8î 9¥èΈ#/5ZlK½ì?² ¬Âg¶2¨u`±…uÙÓúõë§)%a©½í¶ÛTÑ6lXJ¯ƒ 1¸[`#üi¡¸Â±zqŒ ìH¡‰¤˜§ó±…¿-RðRH€¢E1ÅÏ=÷\½ƒ%‘c4Öv´fÀц•Û°® Çz°4¤ø‹A¹… ÂwÜá¥Eâ(»HÚàwI€R‹üôpW€ÀÇõ¬³Î2Ǽ¾ÆÜ‚—\·èá �ï0”àTÒ´B�þb,H6qíµ×ªâ?^(òpÑÀü0gø)÷êÕKëì¿ÿþšì·1)$@Ñ!€è*ø¼Û~ûíõÇ»ÛK�p¤a&° ˆ…y€ ›ü6‹ýoK.B}AÙE¨lŽÂíþäÈŽ¬»ï¼óŽú˜¶hÑ ¯}©$è± „þÐ`ÈpöÑGiØ/·!XnÁ)_ÛR¬o©Ö&ß~É(_rѸ®”ë‹Ï8ÜqÂ�UüÀ§�@ШØM”íEž@)>ôýŠmä†|¥Xß�#©0<2ª€$V¥X_ć;6‡!ê�$‹‰SN&<¸y,è ƒ4[#¢«L™2Å�ªðŒ�ÄW_}µiܸ±ÆØ=üðÃ�?9¢Ñ [’ð âM²ÀŸøä“O6?ü°ÆëÝsÏ=ÍØ±c5¦9â÷¢]¤\w’OHuŽ(5HäƒìŒþö\»î9×ñ ¼¢‹�Þ»woõ�Æœ�½eË–fâĉ®i“n]°!ë2}útsØa‡éæAï "…HàÿÛ; +ª+ ßDÔˆ”Æ]QÅÜ₈b%*&j ÔˆŒ¨àŠŠ¸€H”—¨€K„ åR&hÊ��ˆ�,*ZF-7„*1j©QIç~§¼]=�7¯ß¼™7Óýæ?Uoz»}ûöwß›>}î¹ç$øßXbK«µF@ý›Þ£b”Î(Ï%ªÕ¿>®v4zôèÈÇ£Ž¼òVD> Mäã[G^i�¼ÒùXâÑN;íùH v=U†HOQ§N�¢‰'Fwß}wäC"FC† ±ãkÖ¬‰|ˆ¨_¿~ÑÌ™3#¯GÞ="ò WÑöúÚv?3f̈¼Âù”Þ‘W #¯LZy?TuìØ1ò®dv½ÂJ¼+FÔ®]»¨gϞѴiÓ¢>}úØv—.]"25j”µwùòåvj%×óʶ]Ê”)ÑÃ?ùˆ2‘7YØÛnh{|vɈ6!¬û¸áÑСC£'žx"òyŒ-ÇÒúeݺuq¿œp ÑÂ… 9­*¢'xU°ªÒ<¨Ö?ý<3©¥¶«Ó{SŒÒå¹D5ú÷ƒ>ˆ| nû°^-ùóŸÿl  jŸ¡1ò1®#?Ñ) Š­Ol›bÖ£GÛö–USDQÄ‚ äúøØa3^RŸŸðfÊqØéãˆG>™LäÝ+lŠ­·ºšbÊ$—(’(ÎÞ5Ãv?ÿüóÖ~”Z„vøì’‘·èZûz=?1Ïê[´h‘ÕÇx ¼ûI_ñ¾°Ò�öpN¡b‹bÄ'̱k{w…(­_‚b ÿj‹4ø_¸DD@D@D 2 U8Ð 6Ì‘˜†ä2Õ²12äNªñ Äòþúë¯-®uÈDÈ0â�{EØ6½bi. $Ï B(²Õ«W‡ÍxIœìO?ýÔyå.ÞGhFB•‘1®ø-×'Þ¢k‰t8NB$¸-pqÈ?ùäkC¯G” &ä‘Å’ n.ø8sO¸bJ¹í)<�íB®ìƒmZ¿„¸ä}ûö唪ŠÛªâUå" " "P›…"‹�)¾›Dw©¶xËßÊš·znpÙÍ6Ûlƒ}ìà|”IÉ ¤îöî a3^R)TIeî­Žq9ïj¯[)v¹P*¹ ,ÉZ¤M›6nøðá¶?ìK.ËmOòœ°^Œ+,Êí—æÈ2'Å6ô––" "P#°haºêª«l’ >‰4%RYÿâ¿0Ë)IüÐwSV_o]Xï»ï>÷í·ß:8+,ëK*xÅ*Ùm·ÝÌšùÛßþ6>¼`ÁKUïøn…ú&À1Ù !¥9)�½�¬m7åŸJ®Çý`qfò“é²W>ùä“ñvS¶±¾ºÒú… nÍ%Õ/h®;ÐuD@D@ê ÄC”ƒ 2…ƒYÙÉ—ˆ@SxüñÇmHzÀ€î©§žj6¥–¶3£K±Ÿˆe·‚Âtÿý÷[JòbÖÄÂû=ýôÓЬ÷ 5«ë3ÏíäÉ“]søJ–ê⢾òÊ+æÛ¡C‡RE‹#®í믿îÊ›Šô;ñ©]µj•-™8\ ê+ߨý•\ËõÊ•+m"ÙÞ{ïÝØ&T|~cû¥â 'N”b›€¡U€@%ÿôE.?ZCÿ2Tšô5Üh£�ì�ÇLrf®ã¢,]Åz®50*vß­e_%ý{ë­·šÕrðàÁ­“î3§¤Øæ´ãÔìê¨äŸ~õZ£š›š@kè_¬iXNX2cü´ÓN³!d²•#­�Q9jµŒú·V{V÷EEÐ÷@D@jŒ¡‹ø\|ñÅÎgù©7ìO�ݶnGD@œ,¶úˆ@Y3 €Ôئú7½CÅ(�Q(Á„ªÛo¿Ý-Y²Ä’œzê©îŒ3·3¹Tÿf²[Ô¨&" ‹m�T5" " ­�Q&5nÜ8çS­–ô]n}ttÇ"Ðü¤Ø6?s]QD@D F�€Ø¨G}t�ÜQþnƒˆÄlåÅ"Br >¤Âm¬»–û.'†o¹×"=1ir 3®•{~K—SÛ–î]_D@D AH>qØa‡¹­¶ÚÊÚèÎ;ïÜà|fñ|ðÁLÿ€°°N„9+W(KœVbÿe⨣Žr/½ôR|úŠ+L¡Å�`øLÐÃá�7ÞˆËh¥y�lìØ±Ís±&¸ IzôèQQM¤Ð}à�,IüñE¿ÿUîO¢nbÒþæ7¿I­¢°-©'4S)¶ÍZ—hÄ=묳,›Jí¨Q£,�h¨�¯¨ÿË_þ∿Jð}22}ùå—¡Hê’t±óçÏw·Ýv›[¸p¡#~i¯^½Ü›o¾içn¿ýö®gÏž•Àý¬ó)F-õ¢*Ð*üò—¿´”·•Üì»ï¾kßç/¾ø¢’ÓSÏA±å÷‚ßxšT»-iׯï¸ÛúÈh¿ˆ€ˆ@& 0ôÿÓŸþÔÍ�;×Í=öØÃýío‹ÛÊCŸ´«o¿ý¶[»v­ÅîÅe€ìQðQt ?~ø¡ùå—M)&ª° ßu×]n¯½ör!Ê-Ù¯ºtéâ~üã» /¼Ð®³õÖ[[úSÂÔa�_¼x±±ÇòŽ�ý Ë,ÉèûyóæÕ{�Req3fŒYL黳Ï>Ûê•…»ôohG8†ËÃe—]æöÜsOGè¼B«f©sC,)wóÍ7Û.EpF~ö³ŸÙðÿ‰'žX4;à¿ÿýo{¡ãD2¦-_¾Üêà…íüóÏ·LlŒRPRyäw衇ڨ1¬¹f1!«I}ôQ³€“ͬ0n1¼{ì1W¬-(Ä=ôP\5¿'î-\�ê¼úê«m„‚iLãʰ"Ŷ°TTD@D e … wïÞö`GYeèÀdB â(¤'�t’kß¾½¥B�8qbœmmΜ9¦tìØ±ÎËkÈúD¸´ƒ:¨ÎÍöíÛ×2PÕÙ©�&%€âùÜsÏ9¢K°~ÄGØË C÷dü"å,ý‹r‹H¡ð"Sª,/&XóQâ°N~ðÁîšk®±jx0`€;üðÃÝÿøG×½{wê§î&Œ\{íµnĈö’3räȲεBßýÁÒ‰âŽpMî÷ç?ÿ¹ãûE[,X·é»SlA‚Kdøðá±,©g„ –ê—ÁAPjÏ9çS$'MšäV¯^m¿ŸpO¡K^wØa÷“ŸüÄ”ì÷ßß1ú‘¶QX‹µ…cœ„ß*÷†Ï.B¦8îoÆŒ–Ƙ}¥˜r¼Ñä±J¨é�!ðôÓO»·ÞzË̶mÛZ°Ð%…ã<øyÐó 'u* ˬY³Ü±Çë9äó‹MžÃ:“yÈÒ†‚ËyÔCÊÕ ÿüç?ce"ìÓ²:è¯`ÕD"ÙÈŸþô'Ë ‰e«:J.}™\GJ•Ýb‹-ÜwÜáúõëg§¡àaý$Å4¾Û¸®`1ŷ׬ºëÖ­sï½÷ž]Ñ¢E±,ÉO°Ôßpà %ÏE L“o¼Ñ�yæ™V ßÕ§žzjƒS¸/^êû-·ÜÒÖIuŒ²Ž0ºÀ‡ö2ù ÅûÜsÏ�}�QÚUàåŽßBRx‰ÀŸ…‹4eê“úÚR_ù°“M6q¯¾úªõ#Vjú´>¦•¦.–bhk)" "�y;Y€xø3û‡?üÁü�<òȸíX„¦OŸnÖ5Êã÷Ú®];³øQˆ‡wÿþýãò…+(Kݺu³!S†Â±b1<‹ëÃßÿþ÷¸8V2”¬¼X¥˜™_éÃ8®T+Fëe�àFrÓM7…]î³Ï>³—�xÇw+ie²gý–[n1^vèCKð¾ûîk–z¾(�]t‘½ð<ñĶäÅŠs”`¾‡¼•:× §üIŽðbÅ(D¹’Ì(ÈòÑGÙwŸp¬Ø¸_aÒ%ÖÓBÅ6¯æ’—â(#¼Hð2YÓJ£2H±­fªn�&%À03 °¤¡�`mCùÀB‹\zé¥ö°ÄŠÛµkW×¹sgS>ðƒå¼r„ðIX’ðä|¬|Xr±ŠaCþñ�X}XúP¤ñ·ÝtÓMÍçÅDÒ8Xƒ`1Eúä“OÂ.·ß~ûYv½xÇw+ieQh‰9L4¢eà“ŠEáøî>üðÃÖ§¸CàÓ‹…kcÒå…—¾wì/un9aÈ®‹—¶Bá{ «t’.Xe+‘d=iç'Y…²É¶¦1 ç4t)Ŷ¡ÄT^D@D E 0…,ÊfP€^‚O!QP8ð¡DÑl¨%• i(9Ä å�õ(Xš¸Šr°ô…ëjY¸ƒ …‰{\?ÔbáÛJ•EÁc¶?.C‡µÆò„¡q¬¯|ø`‘År�¿-õb%fâS˜„ˆ¯é“O>iÛ¥ÎEAn á;Ëo|ŠƒL�:Õ^ØÂv}K~?øÉa„‚ ™õ |²<.@¥$�i©sKÓä±RttLD@D “p'JmayÀn¾ù渞 b '“e¯²IDATUj“õa­Åj—Tj“ǵ^}XQdÉð†%ò?ëÿ”SNqï¼óÎ/U–>DÑ “™PLýë_[¸“ ø8ÐüwÙÉ>Ü]ˆ‚À°=.-¸Cð²CD�!C†˜¯6.(¥ÎÝ ‘�Ø,»(àiÂuL’{íµ×ì^x9À#ÔSª|uQNQÞQXñu†I�PGh åqÙ`´„}XÆKIÓRç–:&ŶhQLôbÈŸH(—¸Ÿ0óW‘B)U¥–˜Ç×_½½¬ì¿ÿþîŠ+®0‹>þ´¸%àêÂ~,öûì³�#æ,>¬LÔb¤€–P\T°ä‡I[¥Î-lcc¶i×"®2Ò„ ”( Xž‰ôÁ6!¹‚/n©ó±ôâzSŸ1úÁv�¶0‘Ž2´íÀ´( ¡l±eÓb申ï{þí'*§ Êˆ@k!À[½~ ïm¬(ÌHæm†ÄK$æcÖDý›Þ#b”Î(Ï%òÚ¿ÄCÅ‚È6“KI©²Xa‰xA\b¬­ÄRŵ…I‚!äpC`BW¡,e‰õʤ',”…Rêܲ�ÙfB.ôešðû¬µ# &>˜±•¬÷opµF|W™•ͨ÷[Ÿ�¥Š‰‘ƒÞ Ù¡ýÄ$#29•3Ó|ƒJZ`GkèßÀªKf„€|l3Òj†”"€ëĉ-õ ±Ép„EtÕªU±bK&ÜxÈ’Wf¦®&)W]u•[¾|yrW¼>bÄGjÒ… :Ò.’�')'�t’ÃÍ€ãIÅ6YFë"�¸ÔðâGLS~Oõ a�øFNøFJ""� rEÈF?¨"P/¾²Æ�øƒ¸R‹ÀóIÁŠ»dÉwÏ=÷˜;® S¦Lq½zõ2«T(»lÙ2 vNÀóÂç \“ødžIJÛ¶m-ÿ8Ç%"Ј]JÈ"B!ÄÅ÷|úôéqsm ]ê½÷Þk1GY'È|~'“&M²M–¸Ü°Ä·â—R7Aî%" ù Å6ý¤V¶bÄLä�ËÃ÷ð÷„X‰BM q ÷»ß9¬ª,gÏžmn X£y䑸èÌ™3-°8>�…Ÿþýû[9&Šç±0øÓO?mñ±KD %Üpà î£�>Š't1¡F/‚O™Q^Qx™PÉHCðûfÄåyþùçm}ñâÅ7Ÿ Äú|ðÁ-€ÿŠ+Ân-E@2N@ŠmÆ;HͬSXO'OžlÊ&™oˆv@¤^,KŠ-}&x…ÉbK—.uëÖ­3_†�0`€¥‘$ÁBÈ÷�2@JE2Ê•!×E FPÂùà—(�j ëSr$‹êÎ;ï\çRÁu€<\kÈ.Åd¯  ž}öÙq„t£S§N5%–‰—Iá�ߟDD ?¤Øæ§¯ÔÒVJËùÉyóÀ>ï¼ólbÑ H y饗€‘éË.bð±EA½ä’K,ýdCðáÖ€u–É5dçÁêKšÉ.]ºØ„µàSÈp0©i >‹øùòAÙùÃr]•�¦$À÷0ʯ"ZŠ@íÐä±Úí[ÝY `•P_L÷6¤*d¨4¾´(š(´Xr±Ú2y¬RáÜ¿þõ¯V1i¹. oRÈ=Nh/‰4'^´‰‚ÿy‡ÂfYËð"\]©ÉceU¦B" ™! ‹mfºB �Òx“¶6<�‹•F©EðÁmŒR›¬› c]»vÝ@©M–Ѻ4'�Þ½{›ï,/UóçÏw�=öXì?[ªÁÇ–2Œ:l»í¶æ‹ÎháòˆòÚk¯ÅU°Ÿ’\¨¯ÔñPNK�æ# ŶùXëJ" " M@Ùy󿙫ÌСC-2ÂØ±cÝŒ3¬öC=Ô–„¾C(CÒ’ãŽ;®Ž‹ >¸ƒ ²H$Z`¤c‡v°súôécÊo�=,F-Š0ÎAæÌ™cÛìûøã�ÍbÌú™gžiÇõGD e(ACËp×U3L@ÁË3Ü9MÐ4õo:ļ0"ŠÁ6Ûl“~C%J`u%Ìõ” )QEîå¥sV Î)¶™è5"KôO?K½ÑômQÿ¦3£tFy.¡þÍsï©íiäŠ�FHÇE@D@D@D@rA@Šm.ºI�H# Å6��Ž‹€ˆ€ˆ€ˆ€ä‚€Û\t“)" " " "�F@Šm!È)¶¹è&5RD@D@D@D �€Û4B:." " " "� RlsÑMj¤ˆ€ˆ@9’isË)¯2" µE@Šmmõ§îFD@jŠÀªU«Ü>ûìãºwïîÞ|óMwË-·¸=öØÃí¼óÎîå—_¶{ýòË/Ýå—_nû~ðƒ¸^½z¹¥K—ÖápÛm·Y›o¾¹¥Ö]°`A�ãd#½îî»ïî¶ÞzkGZÞÓN;­N™éÓ§»ýöÛÏRðÒžûî»/>~×]w¹½÷ÞÛÝ~ûív.©y¯½öZ÷¿ÿý/.£�ê�b[}ƺ‚ˆ€ˆ@…ºtéâzè!÷ÕW_¹¡C‡º%K–¸;ï¼Ó�{î¹%a}Þ¼yÅó­·ÞrGq„;ꨣܻï¾_uÍš5nܸqEù�C1¥3>èW¨³mÛ¶î•W^qo¼ñ†kß¾½ûðÃã"S§Nu\p�;ãŒ3ÜŠ+Ü�!CÜÈ‘#ÝwÜaeØ�2{ÓM7¹aÆ9ÊO™2Å-Z´(®C+" Õ' ”ºÕg¬+äŒÀ&›lâ°m´ÑF9k¹š›F`ýúõn³Í6s_ýuZÑV}<‹)W±ÚöìÙÓMž<ÙѾ ï¿ÿ¾ëСƒ{öÙgÝ`»±’þèG?2 ì5×\ï{á…LÑä;€’Œ•vË-·´ãÇ·í«¯¾Ú”ÚvíÚ¹•+Wº}÷Ý׎ï¹çž®_¿~îÖ[oµmþ (O˜0Á­]»Ööõïßßíµ×^nìØ±¶}á…ºþð‡n̘1¶�•?Yì߬°Q;òO@Ûü÷¡î ‰ 0ÄÈPR{žîÖ­[íÝX+¹£óÏ?¿ŽRËm¿þúëv÷'žx¢)¸(¹;vtÿùÏܦ›njÇè÷�vÚÉ�1½÷Þ{nñâÅ_ÜÏ?ÿÜŽóW¬ºXs·Új+wÐA¹—^zÉŽóB„Dß¾}ãò¬°�rüñÇÇû“߯]vÙÅÚÔŠˆ@Õ ´©útÈLsçÎu=zôÈYËÕÜ4³fÍ2?Ë´r:ž ÿc�|ñÅ]§N�Š6ÿZ¬­X{‘Ï>ûÌÜ’…ß~ûm7sæLó‰e}öìÙîŠ+®p§žzª)È;[¸p¡ùï†óØÆ}«¬DD d±ÍF?¨"ÀÐ"Bl’Ú!@Ž5ʆŽkç®ZÇ�„ X,ù$#tíÚÕ&—]wÝunõêÕúzÚ´i¶�Rúé§Ÿš‹>´g�u–ûïÿ[§žË.»Ì¬¶ßÿþ÷~½Xn“îHƒv“&M2_^*}î¹çl¢ØÀ�ç ÉvÛ¶Bú#"P]þ‡(( °lÙ²Èÿò¢Ñ£GG~òGôí·ß”ÐfÐoôßÍ7ßm·Ývý*I'Àw?+2~üxû-Ò¦ðéܹs�æù a‘�byEÔúÙûÐFÞÒy÷+çÝ"ï+m¼ñÆ‘·°F7Þxcäýq#?ù,òŬ̑Gm»í¶Ñ6Ûlí¿ÿþ‘�¼ù `ñu¼"]rÉ%VåÚ´i�sÎ9‘wg°2>ZƒµÏ»?D>ZCäG¬=Þš=ðÀq=YXÉRÿf�‡ÚP[4yÌÿÂ%"PŒB˜P‚õ‡YÐß|óM±bÚ—a^‘1×ÜK°Ä{å6íÍNÓò:¹hݺuf™%˜W<7J”ƒí·ß¾Ž%6Â'w‹-¶07\¨£˜ð?]Ž3Ñ4�’×þÍ#kµ¹ù H±m~溢ˆ€dš€ŸLwO£§þm4BU�aò±Ípç¨i" " " " å�b[>+•È0)¶î5MD@D@D@D |RlËg¥’" " " " & Å6Ã�£¦‰€ˆ€ˆ€ˆ€”O@Šmù¬TRD@D@D@D äØf¸sÔ4�ò H±-Ÿ•JŠ€ˆ€ˆ€ˆ€d˜€Û wŽš&" " " "P>)¶å³RI� �b›áÎQÓD@D@D@D@Ê' Ŷ|V*)" ­‚ÀÆoìÖ¯_ß*îµµÝ$ýJÿJD V H±­ÕžÕ}‰€ˆ@…ºwïî^xá… ÏÖiY&°téR×­[·,7Qm�F�bÛ(|:YD@j�ŠÏܹskïÆtGnÖ¬YމÔ*�ïE^jõæt_" "  '°víZ³êMŸ>ÝsÌ1 ¯@gd’ÀìÙ³]Ÿ>}Üš5kÜvÛm—É6ªQ"ÐX²Ø6– Î�#€Ò3gÎS‚ÆŒã/^,ŸÛœö1>µô߸qãÜé§Ÿî–-[&¥6§}©f—G@Ûò8©”ˆ€´:Xn‡îV®\éV¬Xá¾ùæ›VÇ ï7ÌD1\p/™0a‚”Ú¼w¨ÚŸJ@Šm*"ȹ"ä¡—ÔF�TRlS©€ˆ€ˆ€ˆ€ˆ@H±ÍC/©�" " " " ©¤Ø¦"R�<�b›‡^RE@D@D@D@R H±ME¤" " " " y Å6½¤6Š€ˆ€ˆ€ˆ€¤�b›ŠHD@D@D@D@ò@@ŠmzImH%ð³¢~ŽÂIEND®B`‚scikit-bio-scikit-bio-a3beaa6/web/devdoc/code_guide.rst000066400000000000000000000567031520735541300232300ustar00rootroot00000000000000Coding guidelines ================= As project size increases, consistency of the code base and documentation becomes more important. We therefore provide guidelines for code and documentation that is contributed to scikit-bio. Our goal is to create a consistent code base where: * It is easy to find relevant functionality (and to determine when functionality that you're looking for doesn't exist), * You can trust that the code that you're working with is sufficiently tested, and * Names and interfaces are intuitive. .. note:: As scikit-bio is in beta, our coding guidelines are presented here as a working draft. These guidelines are requirements for all code submitted to scikit-bio, but at this stage the guidelines themselves are malleable. If you disagree with something, or have a suggestion for something new to include, you should :repo:`create an issue ` to initiate a discussion. What are the naming conventions? and How should I format my code? ----------------------------------------------------------------- We adhere to the `PEP 8 `_ python coding guidelines for code and documentation standards. Before submitting any code to scikit-bio, you should read these carefully and apply the guidelines in your code. What should I call my variables? -------------------------------- - *Choose the name that people will most likely guess.* Make it descriptive, but not too long: ``curr_record`` is better than ``c``, or ``curr``, or ``current_genbank_record_from_database``. - *Good names are hard to find.* Don't be afraid to change names except when they are part of interfaces that other people are also using. It may take some time working with the code to come up with reasonable names for everything: if you have unit tests, it's easy to change them, especially with global search and replace. - *Use singular names for individual things, plural names for collections.* For example, you'd expect ``self.name`` to hold something like a single string, but ``self.names`` to hold something that you could loop through like a list or dictionary. Sometimes the decision can be tricky: is ``self.index`` an integer holding a positon, or a dictionary holding records keyed by name for easy lookup? If you find yourself wondering these things, the name should probably be changed to avoid the problem: try ``self.position`` or ``self.look_up``. - *Don't make the type part of the name.* You might want to change the implementation later. Use ``Records`` rather than ``RecordDict`` or ``RecordList``, etc. Don't use Hungarian Notation either (i.e. where you prefix the name with the type). - *Make the name as precise as possible.* If the variable is the path of the input file, call it ``input_fp``, not ``input`` or ``file`` (which you shouldn't use anyway, since they're keywords), and not ``infile`` (because that looks like it should be a file object, not just its name). - *Use* ``result`` *to store the value that will be returned from a method or function.* Use ``data`` for input in cases where the function or method acts on arbitrary data (e.g. sequence data, or a list of numbers, etc.) unless a more descriptive name is appropriate. - *One-letter variable names should only occur in math functions or as loop iterators with limited scope.* Limited scope covers things like ``for k in keys: print k``, where ``k`` survives only a line or two. Loop iterators should refer to the variable that they're looping through: ``for k in keys, i in items``, or ``for key in keys, item in items``. If the loop is long or there are several 1-letter variables active in the same scope, rename them. - *Limit your use of abbreviations.* A few well-known abbreviations are OK, but you don't want to come back to your code in 6 months and have to figure out what ``sptxck2`` is. It's worth it to spend the extra time typing ``species_taxon_check_2``, but that's still a horrible name: what's check number 1? Far better to go with something like ``taxon_is_species_rank`` that needs no explanation, especially if the variable is only used once or twice. Acceptable abbreviations ^^^^^^^^^^^^^^^^^^^^^^^^ The following list of abbreviations can be considered well-known and used with impunity within mixed name variables, but some should not be used by themselves as they would conflict with common functions, python built-in's, or raise an exception. Do not use the following by themselves as variable names: ``dir``, ``exp`` (a common ``math`` module function), ``in``, ``max``, and ``min``. They can, however, be used as part of a name, e.g. ``matrix_exp``. .. dropdown:: :open: +--------------------+--------------+ | Full | Abbreviated | +====================+==============+ | alignment | aln | +--------------------+--------------+ | archaeal | arch | +--------------------+--------------+ | auxiliary | aux | +--------------------+--------------+ | bacterial | bact | +--------------------+--------------+ | citation | cite | +--------------------+--------------+ | current | curr | +--------------------+--------------+ | database | db | +--------------------+--------------+ | dictionary | dict | +--------------------+--------------+ | directory | dir | +--------------------+--------------+ | distance matrix | dm | +--------------------+--------------+ | end of file | eof | +--------------------+--------------+ | eukaryotic | euk | +--------------------+--------------+ | filepath | fp | +--------------------+--------------+ | frequency | freq | +--------------------+--------------+ | expected | exp | +--------------------+--------------+ | index | idx | +--------------------+--------------+ | input | in | +--------------------+--------------+ | maximum | max | +--------------------+--------------+ | minimum | min | +--------------------+--------------+ | mitochondrial | mt | +--------------------+--------------+ | number | num | +--------------------+--------------+ | observation | obs | +--------------------+--------------+ | observed | obs | +--------------------+--------------+ | original | orig | +--------------------+--------------+ | output | out | +--------------------+--------------+ | parameter | param | +--------------------+--------------+ | phylogeny | phylo | +--------------------+--------------+ | previous | prev | +--------------------+--------------+ | probability | prob | +--------------------+--------------+ | protein | prot | +--------------------+--------------+ | record | rec | +--------------------+--------------+ | reference | ref | +--------------------+--------------+ | sequence | seq | +--------------------+--------------+ | standard deviation | stdev | +--------------------+--------------+ | statistics | stats | +--------------------+--------------+ | string | str | +--------------------+--------------+ | structure | struct | +--------------------+--------------+ | temporary | temp | +--------------------+--------------+ | taxa | tax | +--------------------+--------------+ | taxon | tax | +--------------------+--------------+ | taxonomic | tax | +--------------------+--------------+ | taxonomy | tax | +--------------------+--------------+ | variance | var | +--------------------+--------------+ How do I organize my modules (source files)? -------------------------------------------- - *Have a docstring with a description of the module's functions*. If the description is long, the first line should be a short summary that makes sense on its own, separated from the rest by a newline. - *All code, including import statements, should follow the docstring.* Otherwise, the docstring will not be recognized by the interpreter, and you will not have access to it in interactive sessions (i.e. through ``obj.__doc__``) or when generating documentation with automated tools. - *Import built-in modules first, followed by third-party modules, followed by any changes to the path and your own modules.* Especially, additions to the path and names of your modules are likely to change rapidly: keeping them in one place makes them easier to find. - *Don't use* ``from module import *``, *instead use* ``from module import Name, Name2, Name3...`` *or possibly* ``import module``. This makes it *much* easier to see name collisions and to replace implementations. - If you are importing `NumPy `_, `Matplotlib `_, or another package that encourages a standard style for their import statements use them as needed for example: :: import numpy as np import numpy.testing as npt import pandas as pd from matplotlib import pyplot as plt Example of module structure ^^^^^^^^^^^^^^^^^^^^^^^^^^^ The structure of your module should be similar to the example below. scikit-bio follows the `numpydoc style guide `_ for documentation. Our :doc:`doc_guide` explains how to write your docstrings using the numpydoc standards for scikit-bio: .. code-block:: python r""" Numbers (:mod:`skbio.numbers`) ============================== .. currentmodule:: skbio.numbers Numbers holds a sequence of numbers, and defines several statistical operations (mean, stdev, etc.) FrequencyDistribution holds a mapping from items (not necessarily numbers) to counts, and defines operations such as Shannon entropy and frequency normalization. Classes ------- .. autosummary:: :toctree: generated/ Numbers """ # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from random import choice, random import numpy as np from utils import indices class Numbers(list): pass class FrequencyDistribution(dict): pass How should I write comments? ---------------------------- - *Always update the comments when the code changes.* Incorrect comments are far worse than no comments, since they are actively misleading. - *Comments should say more than the code itself.* Examine your comments carefully: they may indicate that you'd be better off rewriting your code (especially if *renaming your variables* would allow you to get rid of the comment.) In particular, don't scatter magic numbers and other constants that have to be explained through your code. It's far better to use variables whose names are self-documenting, especially if you use the same constant more than once. Also, think about making constants into class or instance data, since it's all too common for 'constants' to need to change or to be needed in several methods. .. tab-set:: .. tab-item:: Wrong .. code-block:: python win_size -= 20 # decrement win_size b .. tab-item:: OK .. code-block:: python win_size -= 20 # leave space for the scroll bar .. tab-item:: Right .. code-block:: python self._scroll_bar_size = 20 win_size -= self._scroll_bar_size - *Use comments starting with #, not strings, inside blocks of code.* - *Start each method, class and function with a docstring using triple double quotes (""").* Make sure the docstring follows the `numpydoc style guide `_. - *Always update the docstring when the code changes.* Like outdated comments, outdated docstrings can waste a lot of time. "Correct examples are priceless, but incorrect examples are worse than worthless." `Jim Fulton `_. How should I test my code? -------------------------- There are several different approaches for testing code in python: ``unittest`` and ``numpy.testing``. Their purpose is the same, to check that execution of code given some input produces a specified output. The cases to which the approaches lend themselves are different. Whatever approach is employed, the general principle is every line of code should be tested. It is critical that your code be fully tested before you draw conclusions from results it produces. For scientific work, bugs don't just mean unhappy users who you'll never actually meet: **they may mean retracted publications**. Tests are an opportunity to invent the interface(s) you want. Write the test for a method before you write the method: often, this helps you figure out what you would want to call it and what parameters it should take. It's OK to write the tests a few methods at a time, and to change them as your ideas about the interface change. However, you shouldn't change them once you've told other people what the interface is. In the spirit of this, your tests should also import the functionality that they test from the shortest alias possible. This way any change to the API will cause your tests to break, and rightly so! Never treat prototypes as production code. It's fine to write prototype code without tests to try things out, but when you've figured out the algorithm and interfaces you must rewrite it *with tests* to consider it finished. Often, this helps you decide what interfaces and functionality you actually need and what you can get rid of. "Code a little test a little". For production code, write a couple of tests, then a couple of methods, then a couple more tests, then a couple more methods, then maybe change some of the names or generalize some of the functionality. If you have a huge amount of code where all you have to do is write the tests', you're probably closer to 30% done than 90%. Testing vastly reduces the time spent debugging, since whatever went wrong has to be in the code you wrote since the last test suite. And remember to use python's interactive interpreter for quick checks of syntax and ideas. Run the test suite when you change `anything`. Even if a change seems trivial, it will only take a couple of seconds to run the tests and then you'll be sure. This can eliminate long and frustrating debugging sessions where the change turned out to have been made long ago, but didn't seem significant at the time. **Note that tests are executed using GitHub Actions**, see :doc:`../contribute` for further discussion. Some pointers ^^^^^^^^^^^^^ - *Use the* ``unittest`` *framework with tests in a separate file for each module.* Name the test file ``test_module_name.py`` and include it inside the tests folder of the module. Keeping the tests separate from the code reduces the temptation to change the tests when the code doesn't work, and makes it easy to verify that a completely new implementation presents the same interface (behaves the same) as the old. - *Always include an* ``__init__.py`` *file in your tests directory*. This is required for the module to be included when the package is built and installed via ``setup.py``. - *Always import from a minimally deep API target*. That means you would use ``from skbio import DistanceMatrix`` instead of ``from skbio.stats.distance import DistanceMatrix``. This allows us prevent most cases of accidental regression in our API. - *Use* ``numpy.testing`` *if you are doing anything with floating point numbers, arrays or permutations* (use ``numpy.testing.assert_almost_equal``). Do *not* try to compare floating point numbers using ``assertEqual`` if you value your sanity. - *Test the interface of each class in your code by defining at least one* ``TestCase`` *with the name* ``ClassNameTests``. This should contain tests for everything in the public interface. - *If the class is complicated, you may want to define additional tests with names* ``ClassNameTests_test_type``. These might subclass ``ClassNameTests`` in order to share ``setUp`` methods, etc. - *Tests of private methods should be in a separate* ``TestCase`` *called* ``ClassNameTests_private``. Private methods may change if you change the implementation. It is not required that test cases for private methods pass when you change things (that's why they're private, after all), though it is often useful to have these tests for debugging. - *Test `all` the methods in your class.* You should assume that any method you haven't tested has bugs. The convention for naming tests is ``test_method_name``. Any leading and trailing underscores on the method name can be ignored for the purposes of the test; however, *all tests must start with the literal substring* ``test`` *for* ``unittest`` *to find them.* If the method is particularly complex, or has several discretely different cases you need to check, use ``test_method_name_suffix``, e.g. ``test_init_empty``, ``test_init_single``, ``test_init_wrong_type``, etc. for testing ``__init__``. - *Docstrings for testing methods should be considered optional*, instead the description of what the method does should be included in the name itself, therefore the name should be descriptive enough such that when running the tests in verbose mode you can immediately see the file and test method that's failing. .. code-block:: none $ python -c "import skbio; skbio.test(verbose=True)" skbio.maths.diversity.alpha.tests.test_ace.test_ace ... ok test_berger_parker_d (skbio.maths.diversity.alpha.tests.test_base.BaseTests) ... ok ---------------------------------------------------------------------- Ran 2 tests in 0.1234s OK - *Module-level functions should be tested in their own* ``TestCase``\ *, called* ``modulenameTests``. Even if these functions are simple, it's important to check that they work as advertised. - *It is much more important to test several small cases that you can check by hand than a single large case that requires a calculator.* Don't trust spreadsheets for numerical calculations -- use R instead! - *Make sure you test all the edge cases: what happens when the input is None, or '', or 0, or negative?* What happens at values that cause a conditional to go one way or the other? Does incorrect input raise the right exceptions? Can your code accept subclasses or superclasses of the types it expects? What happens with very large input? - *To test permutations, check that the original and shuffled version are different, but that the sorted original and sorted shuffled version are the same.* Make sure that you get *different* permutations on repeated runs and when starting from different points. - *To test random choices, figure out how many of each choice you expect in a large sample (say, 1000 or a million) using the binomial distribution or its normal approximation.* Run the test several times and check that you're within, say, 3 standard deviations of the mean. - All tests that depend on a random value should be seeded, for example if using NumPy, `numpy.random.seed(0)` should be used, in any other case the appropriate API should be used to create consistent outputs between runs. It is preferable that you do this for each test case instead of doing it in the `setUp` function/method (if any exists). - Stochastic failures should occur less than 1/10,1000 times, otherwise you risk adding a significant amount of time to the total running time of the test suite. Example test module ^^^^^^^^^^^^^^^^^^^ Here is an example of a unit-test module structure: .. code-block:: python # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- import numpy as np import unittest from skbio.math.diversity.alpha.ace import ace class AceTests(unittest.TestCase): def test_ace(self): self.assertAlmostEqual(ace(np.array([2, 0])), 1.0) self.assertAlmostEqual(ace(np.array([12, 0, 9])), 2.0) self.assertAlmostEqual(ace(np.array([12, 2, 8])), 3.0) self.assertAlmostEqual(ace(np.array([12, 2, 1])), 4.0) self.assertAlmostEqual(ace(np.array([12, 1, 2, 1])), 7.0) self.assertAlmostEqual(ace(np.array([12, 3, 2, 1])), 4.6) self.assertAlmostEqual(ace(np.array([12, 3, 6, 1, 10])), 5.62749672) # Just returns the number of taxa when all are abundant. assert_almost_equal(ace(np.array([12, 12, 13, 14])), 4.0) # Border case: only singletons and 10-tons, no abundant taxa. assert_almost_equal(ace([0, 1, 1, 0, 0, 10, 10, 1, 0, 0]), 9.35681818182) def test_ace_only_rare_singletons(self): with self.assertRaises(ValueError): ace([0, 0, 43, 0, 1, 0, 1, 42, 1, 43]) if __name__ == '__main__': unittest.main() Git pointers ------------ Commit messages are a useful way to document the changes being made to a project, it additionally documents who is making these changes and when are these changes being made, all of which are relevant when tracing back problems. Authoring a commit message ^^^^^^^^^^^^^^^^^^^^^^^^^^ The most important metadata in a commit message is (arguably) the author's name and the author's e-mail. GitHub uses this information to attribute your contributions to a project, see for example the :repo:`list of scikit-bio contributors `. Follow `this guide `_ to set up your system and **make sure the e-mail you use in this step is the same e-mail associated to your GitHub account**. After doing this you should see your name and e-mail when you run the following commands:: $ git config --global user.name Yoshiki Vázquez Baeza $ git config --global user.email yoshiki89@gmail.com Writing a commit message ^^^^^^^^^^^^^^^^^^^^^^^^ In general the writing of a commit message should adhere to `NumPy's guidelines `_ which if followed correctly will help you structure your changes better i. e. bug fixes will be in a commit followed by a commit updating the test suite and with one last commit that update the documentation as needed. GitHub provides a set of handy features that will link together a commit message to a ticket in the issue tracker, this is specially helpful because you can `close an issue automatically `_ when the change is merged into the main repository, this reduces the amount of work that has to be done making sure outdated issues are not open. scikit-bio-scikit-bio-a3beaa6/web/devdoc/doc_guide.rst000066400000000000000000000203721520735541300230540ustar00rootroot00000000000000Documentation guidelines ======================== This guide contains instructions for building the scikit-bio documentation, as well as guidelines for contributing to the documentation. If you would like to contribute to the documentation, whether by adding something entirely new or by modifying existing documentation, please first review :doc:`../contribute`. .. note:: If you're only interested in viewing the scikit-bio documentation, please visit the `documentation site `_. Build the documentation ----------------------- To build the documentation, you'll need a scikit-bio development environment set up. See :doc:`../contribute` for instructions. In addition, you will also need to install `Sphinx `_ and relevant extensions within the same environment for the documentation, you can do that with:: conda install -c conda-forge --file ci/requirements.doc.txt .. warning:: The documentation will be built for whatever version of scikit-bio is *currently installed* on your system (i.e., the version imported by ``import skbio``). This may not match the code located in this repository. You will need to either install this version of scikit-bio somewhere (e.g., in a virtualenv) or point your ``PYTHONPATH`` environment variable to this code, *before* building the documentation. To build the documentation, assuming you are at the top-level scikit-bio directory:: make -C doc clean html The built HTML documentation will be at ``doc/build/html/index.html``. .. warning:: Before submitting your changes, ensure that the documentation builds without errors or warnings. Docstring style --------------- Most of scikit-bio's API documentation is automatically generated from `docstrings `_. The advantage to this approach is that users can access the documentation in an interactive Python session or from our website as HTML. Other output formats are also possible, such as PDF. scikit-bio docstrings follow the `numpydoc style guide `_. This ensures that the docstrings are easily readable both from the interpreter and HTML, PDF, etc. Please read the numpydoc guidelines before continuing. Documenting a module -------------------- In addition to following the numpydoc conventions for docstrings, we have a few more conventions that will ensure your documentation is correctly built and linked within our website, and that it maintains consistency with the rest of the scikit-bio docs. The easiest way to get started with documenting your code is to look at the docstrings in existing scikit-bio modules. A couple of modules to start with are ``skbio.sequence`` and ``skbio.stats.distance``. Go ahead and look through those now. We've structured our docs in a similar way to `SciPy's documentation `_, so that may be another good place to look for examples. We'll take a top-down approach by discussing how to document a new module that you'd like to add to scikit-bio (let's call it ``skbio/example.py``). Module docstring ^^^^^^^^^^^^^^^^ The first thing you'll need to add is a docstring for the module. The docstring must start at the first line of the file. It should start with a title for the module:: """ Documentation examples (:mod:`skbio.example`) ============================================= It is important to include the ``:mod:`` Sphinx directive in the title, as this title will be included in the table of contents. Also make sure that the title underline is the same length as the title. We also need to include another Sphinx directive below this:: .. currentmodule:: skbio.example This directive tells Sphinx that other classes, functions, etc. that we will reference are located in the ``skbio.example`` module. Next, include a more detailed description of the module. For example:: This module consists of several example classes and functions to illustrate the scikit-bio documentation system. Following that, list any classes, functions, and exceptions that you'd like documentation generated for. Note that you do *not* need to include every single class, function, or exception that is defined in the module. Also, you do not need to list class methods, as those will be automatically included in the generated class documentation. Only include objects that should be exposed as part of the public API. For example:: Classes ------- .. autosummary:: :toctree: generated/ ExampleClass1 ExampleClass2 Functions --------- .. autosummary:: :toctree: generated/ example_function1 example_function2 Exceptions ---------- .. autosummary:: :toctree: generated/ ExampleError The ``autosummary`` directives are important as they generate RST files in the ``generated/`` directory for each object. A single-line summary and link to each object is inserted into the page for you. After listing public module members, we encourage a usage example section showing how to use some of the module's functionality. Examples should be written in `doctest `_ format so that they can be automatically tested (e.g., using ``make test`` or ``python -m skbio.test``):: Examples -------- Run the ``example_function1`` function: >>> from skbio.example import example_function1 >>> example_function1("hello", "world") hello world! You can also embed the plots that an example generates into the built documentation with the ``.. plot::`` directive. For example:: .. plot:: >>> import pandas as pd >>> df = pd.DataFrame({'col1': [1, 2, 3, 4], 'col2': [10, 11, 12, 13]}) >>> fig = df.boxplot() This will include the plot, a link to the source code used to generate the plot, and links to different image formats (e.g., PNG and PDF) so that users can easily download the plot. You're now ready to document the members of your module. Documenting module members ^^^^^^^^^^^^^^^^^^^^^^^^^^ When documenting the members of a module (e.g., classes, methods, attributes, functions, and exceptions), follow the numpydoc conventions. In addition to these conventions, there are a few things to keep in mind: - When documenting a class, only public methods and attributes are included in the built documentation. If a method or attribute starts with an underscore, it is assumed to be private. - When documenting a class, include the ``Parameters`` section in the class docstring, instead of in the ``__init__`` docstring. While numpydoc technically supports either form, ``__init__`` is not included in the list of methods by default and thus should have its documentation included in the class docstring. Including the module in the docs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Until now, we've only been editing docstrings, which are attached to Python code. The final step is to hook up this new module's docstrings to the documentation build system: 1. Make sure you're within the ``scikit-bio/doc`` directory. 2. Create a new file with the same name as your module under the ``source`` directory. Do not include ``skbio`` as part of the name, and use ``.rst`` as the suffix. For example, ``source/example.rst``. 3. Add the following line to ``source/example.rst`` to have your module's docstring pulled into the document:: `` .. automodule:: skbio.example `` 4. Add the following line to ``source/index.rst`` to add the new page to the top-level table of contents:: `` example `` That's it! You can now try building the documentation, which should include the documentation for your new module! Documenting a subpackage ------------------------ The process of documenting a subpackage is very similar to documenting a module in scikit-bio. The only difference is that the module docstring goes in the subpackage's ``__init__.py``. Troubleshooting --------------- If things aren't working correctly, try running ``make clean`` and then rebuild the docs. If things still aren't working, try building the docs *without* your changes, and see if there are any Sphinx errors or warnings. Make note of these, and then see what new errors or warnings are generated when you add your changes again. scikit-bio-scikit-bio-a3beaa6/web/devdoc/new_module.rst000066400000000000000000000033701520735541300232670ustar00rootroot00000000000000Adding a new module =================== Each module needs an `__init__.py` file and a `tests` folder that also contains an `__init__.py` file. For a module, a simple one may look like this:: r""" A module (:mod:`skbio.module`) ============================== .. currentmodule:: skbio.module Documentation for this module. """ # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- from skbio.util import TestRunner test = TestRunner(__file__).test Usually, some functionality from the module will be made accessible by importing it in `__init__.py`. It's convenient to use explicit relative imports (`from .implementation import compute`), so that functionality can be neatly separated in different files but the user doesn't face a deeply nested package: `from skbio.module import compute` instead of `from skbio.module.implementation import compute`. Inside the tests folder, a simpler `__init__.py` works fine (it is necessary so that all tests can be run after installation):: # ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- Finally, remember to also follow the :doc:`doc_guide`. scikit-bio-scikit-bio-a3beaa6/web/devdoc/release.rst000066400000000000000000000174061520735541300225560ustar00rootroot00000000000000Releasing a new version ======================= Introduction ------------ This guide explains how to release a new version of scikit-bio. To illustrate examples of commands you might run, let's assume that the current version is **x.y.z-dev** and we want to release version **x.y.z**. .. note:: The following commands assume you are in the top-level directory of the scikit-bio repository unless otherwise noted. They also assume that you have [Conda](https://conda.io) installed. Large portions of the workflow are now automated through GitHub workflows. In order to check that things will work correctly before running the release workflow in ``release.yml``, please follow these steps. The general workflow is: 1. Update the version number in the repository from **x.y.z-dev** to **x.y.z**. 2. Ensure documentation, wheels, and source distribution build correctly before publishing release. 3. Publish release. 4. Update version number in the repository from **x.y.z** to **a.b.c-dev**. Prep the release ---------------- The purpose of these steps is to update the version within the package. At this point we are only updating the version number in the repository, and doing some basic checks. 1. Ensure the GitHub Actions CI build is passing against main. 2. Update the version strings (x.y.y-dev) to the new version (x.y.z). This will include ``__version__`` defined in ``skbio/__init__.py``. ``grep`` for the current version string to find all occurrences:: grep -r 'x\.y\.y-dev' . 3. Also make sure to update the current version displayed on website. This can be done by searching for the current version number in the code base. Affected files are typically `versions.json`, `index.rst`, and `README.rst`. 4. Remove any deprecated functionality that was scheduled for removal on or before this release. To find all deprecated functionality, search for `@deprecated` decorators: grep -r '@deprecated' . .. note:: Any deprecated functionality that was removed in the ``### Miscellaneous`` section of ``CHANGELOG.md``. 5. Update ``CHANGELOG.md`` to include descriptions of all **user-facing** changes that made it into this release. Be sure to update the heading to include the new version (x.y.z) and the date of the release. Use the existing structure in the file as a template/guide. 6. Submit a pull request and merge when CI tests are passing. Build documentation locally --------------------------- This is a **pre-release check** to be performed by the developer to ensure that things run smoothly once we get to the actual release publication steps. It is a **critical step** to avoid failures once the automated workflows run. In an environment with **the same version of Python** specified in the ``Publish documentation`` job within the ``release.yml`` workflow, build the documentation locally using ``make doc`` and ensure that it runs without error and that everything renders correctly. We now use Sphinx and automated workflows to handle the documentation building and publishing process. Check Sphinx's most recent Python version support, and pin to this version in ``release.yml`` if it isn't the latest. Test wheels and sdist fully --------------------------- This is a **pre-release check** to be performed by the developer to ensure that things run smoothly once we get to the actual release publication steps. It is a **critical step** to avoid failures once the automated workflows run. The ``wheels.yml`` file may be triggered manually through GitHub Actions ``workflow_dispatch`` (https://github.com/scikit-bio/scikit-bio/actions/workflows/wheels.yml). Click the ``Run workflow`` button and run it against the ``main`` branch. When this workflow is manually triggered, it will build wheels for all supported Python versions and all supported platforms, and run the full suite of unit tests on every wheel that it builds. This process typically takes some time, but it is well worth the time to ensure that the wheel building process will be successful when it's time to actually publish the release. Manually check that the correct wheels are built by downloading the artifacts from the workflow run or visually checking the output from ``cibuildwheel`` on the GitHub Actions workflow page. If downloading, inspect the zip file containing the wheels provided by workflow for each platform. The zip file should contain all the wheels you are trying to build. If you find that the desired wheels are not present in the zip files, or you are coming accross unexpected errors in the wheel building process, there are a few places to check: 1. Check that you have updated the ``cibuildwheel`` portion of the ``pyproject.toml`` configuration file to include all supported Python versions and any other information you want. 2. Ensure that the version of ``cibuildwheel`` used in ``wheels.yml`` is up to date. It may be the case that the latest version of Python is not supported by whichever version is currently in use in ``wheels.yml``. In this case, ``cibuildwheel`` will not throw an error or warning, it just won't build wheels for that version of Python. 3. Check that the version of ``manylinux`` in the ``cibuildwheel`` section of ``pyproject.toml`` is up to date. This is particularly relevant if any of the errors you encounter are related to specific versions of ``glibc``. This workflow also builds the source distribution for the package. It is **highly recommended** to download the built sdist from this workflow and test that you can build it against **every** Python version supported by scikit-bio. Again, this is tedious, but well worth the benefit of being certain things will work before publishing the release. Tag the release and publish --------------------------- Assuming that all of the above checks and tests have been performed and are passing, it is time to publish the release. **Once you hit the ``Publish`` button, all of the automated workflows will run, and they will actually upload the artifacts (documentation, sdist, wheels) to their respective locations (website, PyPI), so ensure that everything is in order before hitting ``Publish``!** From :repo:`scikit-bio GitHub repo`, click on the releases tab and draft a new release. Use the version number for the tag name (x.y.z) and create the tag against main. Fill in a release title that is consistent with previous release titles and add a summary of the release (linking to ``CHANGELOG.md`` is a good idea). This release summary will be the primary information that we point users to when we announce the release. Hit ``Publish`` when you are ready and keep an eye on the processes to see if any errors arise. Add wheels to GitHub release page --------------------------------- Once the automated workflows have run, and our wheels are successfully uploaded to PyPI, you can manually download the wheels from PyPI and add them to the GitHub release page for the release we just published. Click the ``edit release`` button, and then simply add the binaries to the release page. This isn't an elegant solution, and it may be automated in the future, but for now this is what we're doing. Post-release cleanup -------------------- 1. Submit and merge a pull request to update the version strings from x.y.z to a.b.c-dev (``skbio.__version__`` should be the only thing needing an update). Update ``CHANGELOG.md`` to include a new section for a.b.c-dev (there won't be any changes to note here yet). 2. Close the release milestone on the GitHub issue tracker if there was one. 3. Send an email to the skbio developers list and anyone else who might be interested (e.g., lab mailing lists). You might include links to the GitHub release page. 4. Tweet about the release from ``@scikit-bio``, including a link to the GitHub release page (for example, https://github.com/scikit-bio/scikit-bio/releases/tag/x.y.z). 5. Beers! :fa:`beer-mug-empty;fa-2x sd-text-success` scikit-bio-scikit-bio-a3beaa6/web/devdoc/review.rst000066400000000000000000000151741520735541300224370ustar00rootroot00000000000000Reviewing pull requests ======================= This document provides a high-level, general, and **incomplete** checklist of things that pull request reviewers should be aware of when performing code review. These are guidelines which generally make sense to follow, but they are not intended to be rigid. The checklist mainly consists of things that are specific to the scikit-bio project and that generally apply to incoming pull requests. The checklist is incomplete because it is not possible to describe all things to verify during code review (that depends on what is being reviewed). This document also doesn't attempt to describe *how* to perform code review (there are many online resources for that). Reviewers are encouraged to keep this document up-to-date as the project evolves and to add anything that's missing. The checklist is not in any particular order. Licensing and attribution ------------------------- Verify that code being included from external sources has a compatible license and is properly attributed: - Include the code's license in the top-level `licenses` directory. - Include a comment with the external code giving attribution and noting the license in the `licenses` directory. - Any other requirements set by the code's license and/or author. Changelog --------- This is one of the most important points to remember as users will review the changelog to identify changes relevant to them. This is one of the easiest parts to forget in a pull request. - Note all public (i.e. user-facing) changes in ``CHANGELOG.md`` under the latest development version section at the top of the file. This includes things like bug fixes, API additions/changes/removal, performance enhancements, etc. The changelog has several subsections for organizing these changes. - If a corresponding issue exists, it should be linked to from the changelog. - Use public imports (``skbio.sequence.Sequence`` instead of ``skbio.sequence._sequence.Sequence``) when documenting import paths in the changelog. - Internal changes not visible/applicable to users (e.g. refactoring, private methods, etc.) are better suited for commit messages than the changelog. Public vs. private API ---------------------- Be aware of what type of API changes are being made. scikit-bio uses the following conventions to distinguish public vs. private API: **Public API:** API with an import path that doesn't contain leading underscores in any submodule/subpackage/object names. Users and scikit-bio devs can use public API. Examples: ``skbio.sequence.Sequence``, ``skbio.stats.subsample``. **Package-private API:** API with an import path containing a leading underscore in at least one submodule/subpackage. Users should not import package-private API. Package-private API can be imported anywhere *within* the scikit-bio package. Examples: ``skbio.util._misc.chunk_str``, ``skbio.util._testing.ReallyEqualMixin``. **Private API:** API with object name starting with an underscore. Users should not import private API. Private API should only be imported and used in the module where it is defined. It should not be imported in other parts of the scikit-bio package. Examples: ``skbio.util._testing._normalize_signs``, ``skbio.stats.composition._gram_schmidt_basis``. - Prefer defining private APIs and only promote things to the public API that users need access to. - Within scikit-bio, prefer *using* public APIs defined in the package even if private APIs offer the same functionality. Integration/consistency with existing API ----------------------------------------- When reviewing API changes/additions, look at them in the context of the rest of the codebase and its existing APIs. For example, are there existing parameter names that could be reused for consistency/predictability? Does the new API (or changed API) compose with other relevant APIs? Example: ``skbio.stats.distance.anosim`` uses a ``permutations`` parameter, so a new nonparametric function would want to use this name over something like ``n`` or ``num_permutations``. Commit messages and merging pull requests ----------------------------------------- When merging pull requests, use GitHub's "Squash and merge" option to merge a single commit. See `this commit message `_ for an example. - Rewrite commit message to describe all changes being merged. This usually involves deleting individual commit messages that GitHub includes in the text box. - Include "fixes #n" text if there's an associated issue to be closed. - Use `NumPy-style commit tags `_ (ENH, BUG, PERF, etc.). - Include contributors' and reviewers' GitHub usernames in commit message (attribution will be lost on squash). Test changes locally -------------------- .. warning:: **This step is extremely important.** Pull down the PR changes locally and try out the API as a user would. Try to break it, make sure the docs are complete, etc. Build the docs locally and verify that they render correctly (this is a common pitfall). Documentation ------------- - Verify the docs follow the instructions in the scikit-bio :doc:`doc_guide`. - Verify the docs follow :doc:`new_module` when adding a new module or subpackage to scikit-bio. - Public API should have docstrings conforming to `numpydoc style guide `_. Manual and careful verification of the numpydoc docstrings is currently necessary; they are easy to get wrong and building the docs won't always flag issues. Building the docs and inspecting the rendered output can help with this process. - Package-private and private APIs do not need to be extensively documented; numpydoc docstrings are not required. Document these APIs as appropriate to help other devs understand the code (code comments are usually better for this anyways). Continuous integration (CI) --------------------------- - Make sure GitHub Actions CI is passing before merging a pull request. - Make sure coverage doesn't drop. Strive to have 100% coverage for new code being merged. - If changes involve Python Array API support, consider adding the `gpu-ci` label to the PR. See :doc:`array_api` for more details. Unit testing ------------ - Make sure the tests are as complete as possible. - Check that border cases are tested (e.g. zeros, '', [], None, etc.). - Check that the base case is tested (``n``), along with the inductive step (``n + 1``). - Verify that tests cover more than one input data set. - Make each test case simple, ideally only testing a single thing (follow `Arrange Act Assert `_). scikit-bio-scikit-bio-a3beaa6/web/index.rst000066400000000000000000000241601520735541300207740ustar00rootroot00000000000000.. remove right sidebar :html_theme.sidebar_secondary.remove: .. page style and classes .. raw:: html .. hidden page title .. title:: scikit-bio: Bioinformatics in Python .. light/dark logo image .. image:: _static/img/logo.svg :class: only-light :width: 600 px :align: center .. image:: _static/img/logo_inv.svg :class: only-dark :width: 600 px :align: center .. brief description of the project .. rst-class:: subtitle A community-driven Python library for bioinformatics, providing versatile data structures, algorithms and educational resources. .. toctree hidden from document but provides header links .. toctree:: :hidden: :maxdepth: 1 Install Learn Documentation Contribute Community Releases About Roadmap .. grid:: 1 1 1 3 .. grid-item-card:: :class-header: centered **For Researchers** :octicon:`beaker;1.2em;sd-text-danger` ^^^ Robust, performant and scalable algorithms tailored for the vast landscape of biological data analysis spanning genomics, microbiomics, ecology, evolutionary biology and more. Built to unveil the insights hidden in complex, multi-omic data. +++ .. dropdown example code, implemented using raw html details instead of sphinx-design's dropdown, because the latter has extra edges .. raw:: html

Example .. code-block:: python from skbio.tree import TreeNode from skbio.diversity import beta_diversity from skbio.stats.ordination import pcoa table = pd.read_table('data.tsv', index_col=0) metadata = pd.read_table('metadata.tsv', index_col=0) tree = TreeNode.read('tree.nwk') bdiv = beta_diversity('weighted_unifrac', table, tree=tree) ordi = pcoa(bdiv, dimensions=3) ordi.plot(metadata, column='bodysite') .. image:: _static/img/hmp1_pcoa.png :alt: PCoA plot .. raw:: html
.. grid-item-card:: :class-header: centered **For Educators** :octicon:`mortar-board;1.2em;sd-text-info` ^^^ Fundamental bioinformatics algorithms enriched by comprehensive documentation, examples and references, offering a rich resource for classroom and laboratory education (with proven `success `_). Designed to spark curiosity and foster innovation. +++ .. raw:: html
Example .. code-block:: python from skbio.alignment import pair_align_prot from skbio.alignment import TabularMSA from skbio.sequence.distance import hamming from skbio.stats.distance import DistanceMatrix from skbio.tree import nj def align_dist(seq1, seq2): score, (path,), _ = pair_align_prot(seq1, seq2) msa = TabularMSA.from_path_seqs(path, (seq1, seq2)) return hamming(*msa) dm = DistanceMatrix.from_iterable( seqs, align_dist, keys=ids, validate=False ) tree = nj(dm).root_at_midpoint() print(tree.ascii_art()) :: /-chicken | ---------| /-rat | /--------| | | \-mouse \--------| | /-pig | | \--------| /-chimp | /--------| \--------| \-human | \-monkey .. raw:: html
.. grid-item-card:: :class-header: centered **For Developers** :octicon:`git-merge;1.2em;sd-text-warning` ^^^ Industry-standard, production-ready Python codebase featuring a stable, unit-tested API that streamlines development and integration. Licensed under the :repo:`3-Clause BSD `, it provides an expansive platform for both academic research and commercial ventures. +++ .. raw:: html
Example .. code-block:: python def centralize(mat: "ArrayLike") -> "StdArray": r"""Center data around its geometric average. Parameters ---------- mat : array_like of shape (n_compositions, n_components) A matrix of proportions. Returns ------- ndarray of shape (n_compositions, n_components) Centered composition matrix. Examples -------- >>> import numpy as np >>> from skbio.stats.composition import centralize >>> X = np.array([[.1, .3, .4, .2], [.2, .2, .2, .4]]) >>> centralize(X) array([[ 0.17445763, 0.30216948, 0.34891526, 0.17445763], [ 0.32495488, 0.18761279, 0.16247744, 0.32495488]]) """ from scipy.stats import gmean mat = closure(mat) cen = gmean(mat, axis=0) return perturb_inv(mat, cen) .. raw:: html
---- .. grid:: 1 1 1 2 .. grid-item:: :columns: 12 12 5 5 :padding: 0 0 4 4 .. rst-class:: heading Install .. tab-set:: :class: no-top-pardding .. tab-item:: Conda .. code-block:: bash conda install -c conda-forge scikit-bio .. tab-item:: PyPI .. code-block:: bash pip install scikit-bio .. tab-item:: Dev .. code-block:: bash pip install git+https://github.com/scikit-bio/scikit-bio.git .. tab-item:: More See detailed :doc:`instructions ` on installing scikit-bio on various platforms. .. grid-item:: :columns: 12 12 7 7 :padding: 0 0 4 4 .. rst-class:: heading News .. card-carousel:: 3 .. card:: Latest release (2026-06-01): .. button-link:: https://github.com/scikit-bio/scikit-bio/releases/tag/0.7.3 :color: success :shadow: scikit-bio 0.7.3 .. card:: scikit-bio is participating in `Google Summer of Code 2026 `_. Contributors are welcome! .. card:: `scikit-bio paper `_ published in *Nature Methods*. Full text `available `_. .. card:: `scikit-bio workshop `_ at ISMB 2024. Materials are `publicly available `_. .. card:: `DOE grant `_ for scikit-bio development in multi-omics and complex modeling. .. card:: New website: `scikit.bio `_ and organization: https://github.com/scikit-bio are online. ---- .. rst-class:: heading Feature Highlights .. grid:: 1 2 3 3 :padding: 0 0 4 4 :gutter: 3 .. grid-item-card:: :fa:`dna;fa-2x sd-text-success` **Biological sequences**: Efficient data structure with a :docs:`flexible grammar ` for easy manipulation, :docs:`annotation `, :docs:`alignment `, and conversion into :docs:`motifs ` or :docs:`k-mers ` for in-depth analysis. .. grid-item-card:: :fa:`tree;fa-2x sd-text-success` **Phylogenetic trees**: Scalable :docs:`tree structure ` tailored for evolutionary biology, supporting diverse operations in :docs:`navigation `, :docs:`manipulation `, :docs:`comparison `, and :docs:`construction `. .. grid-item-card:: :fa:`chart-column;fa-2x sd-text-success` **Community diversity** analysis for ecological studies, with an extensive suite of metrics such as :docs:`UniFrac ` and :docs:`PD `, optimized to handle large-scale community datasets. .. grid-item-card:: :fa:`compass-drafting;fa-2x sd-text-success` **Ordination methods**, such as :docs:`PCoA `, :docs:`CA `, and :docs:`RDA `, to uncover patterns underlying high-dimensional data, facilitating insightful visualization. .. grid-item-card:: :fa:`arrow-up-right-dots;fa-2x sd-text-success` **Multivariate statistical tests**, such as :docs:`PERMANOVA `, :docs:`BIOENV `, and :docs:`Mantel `, to decode complex relationships across data matrices and sample properties. .. grid-item-card:: :fa:`chart-pie;fa-2x sd-text-success` **Compositional data** processing and analysis, such as :docs:`CLR ` transform and :docs:`ANCOM `, built for various omic data types from high-throughput experiments. scikit-bio-scikit-bio-a3beaa6/web/install.rst000066400000000000000000000131641520735541300213350ustar00rootroot00000000000000Installing scikit-bio ===================== Scikit-bio can be installed via `PyPI `_, `Conda `_, system package managers, from source, or from pre-compiled wheels. The PyPI and Conda methods are the most commonly used. System requirements ------------------- Platform ^^^^^^^^ Scikit-bio runs on Linux, macOS, and Windows. It is currently available for the x86_64 and ARM64 architectures. Python ^^^^^^ scikit-bio requires `Python `_ 3.10 or later installed in your system. See the `Python version support`_ section for more details. Environment based ----------------- Conda ^^^^^ The recommended way to install scikit-bio is via the Conda package manager. The latest release of scikit-bio is distributed via the `conda-forge `_ channel. You can install it via the following command:: conda install -c conda-forge scikit-bio Other channels such as anaconda and bioconda also host scikit-bio, which however may or may not be the up-to-date version. PyPI ^^^^ Alternatively, the latest release of scikit-bio can be installed from PyPI:: pip install scikit-bio System package managers ----------------------- Scikit-bio is available as third-party packages from software repositories for multiple Linux/BSD distributions. However, these packages may or may not be the latest version. **The scikit-bio development team is not involved in the maintenance of these packages**. For example, users of Debian-based Linux distributions (such as Ubuntu and Linux Mint) may install scikit-bio using:: sudo apt install python3-skbio python-skbio-doc Users of Arch Linux or variants (such as Manjaro) may install scikit-bio from AUR:: yay -S python-scikit-bio Pre-compiled wheels ------------------- Starting with version 0.7.0, scikit-bio now provides `pre-compiled wheels `_ for each release. To install from a wheel file, download the appropriate file for your platform and run:: pip install your_wheel_file.whl Development version ------------------- Scikit-bio is undergoing expansion, with many new features being introduced. You are welcome to try these features by installing the current development version from our `GitHub repo `_:: pip install git+https://github.com/scikit-bio/scikit-bio.git Alternatively, you may download the repository, extract, and execute:: pip install . However, be cautious that the new functionality may not be stable and could be changed in the next formal release. It is not recommended to deploy the development version in a production environment. Verifying the installation -------------------------- After installing scikit-bio, verify the installation by running the following in a Python shell or script:: import skbio print(skbio.__version__) This should print the installed version of scikit-bio without errors. For a more robust verification of the installation you may run the scikit-bio's unit tests in the environment where scikit-bio is installed. This will require the `pytest `_ package to be installed:: python -m skbio.test Parallelization --------------- Multiple compute-intensive algorithms in scikit-bio are implemented in Cython and use OpenMP for parallel execution. If your system does not support OpenMP, or if you prefer to disable it, you can build from the scikit-bio source code with OpenMP disabled:: DISABLE_OPENMP=1 pip install scikit-bio --no-binary scikit-bio Or, if you have downloaded the repository:: DISABLE_OPENMP=1 pip install . Many scikit-bio functions automatically take advantage of parallel processing to improve performance. By default, they utilize all available CPU cores when possible. There is currently no per-function parameter to control the number of threads used. You can set the environment variable ``OMP_NUM_THREADS`` to control the global parallelization behavior:: # Setting OMP_NUM_THREADS inside a script. # Note that the environmental variable must be set before the import statement of # whichever functionality you are using from scikit-bio. import os os.environ["OMP_NUM_THREADS"] = "4" from skbio import some_function # Alternatively, set it before launching your script. OMP_NUM_THREADS=4 python script.py If more granular control over thread use is desired, we recommend using `threadpoolctl `_:: from skbio import some_function from threadpoolctl import threadpool_limits with threadpool_limits(limits=4): some_function() Acceleration ------------ The new `scikit-bio-binaries `_ package is a separate package from scikit-bio, written in C++, which when installed in the same environment as scikit-bio will dramatically increase performance of select functions. Installation of scikit-bio-binaries is currently available with conda:: conda install -c conda-forge scikit-bio-binaries Python version support ---------------------- Scikit-bio's policy is to support Python versions until they reach official end-of-life, which typically provides 4-5 years of support per version. This approach accounts for the prevalence of legacy and under-maintained software packages in bioinformatics workflows, where users often cannot update their environments frequently. The goal is to strike an appropriate balance between encouraging modernization and maintaining compatibility for our user base, while still providing predictable deprecation timelines that researchers can plan around. scikit-bio-scikit-bio-a3beaa6/web/learn.rst000066400000000000000000000043221520735541300207640ustar00rootroot00000000000000Learn scikit-bio ================ Tutorials --------- :bdg-info:`New` `scikit-bio tutorials `_ given at ISMB 2024 are now publicly available. From basic sequence operations to protein language models. Code, instructions and test datasets included. .. button-link:: https://github.com/scikit-bio/scikit-bio-tutorials :color: primary :shadow: Tutorial repository Also check out the classical `scikit-bio-cookbook `_: A series of Jupyter Notebooks containing executable "recipes" for bioinformatics workflows using scikit-bio. .. button-link:: https://github.com/scikit-bio/scikit-bio-cookbook :color: primary :shadow: Cookbook repository Workshops --------- We are thrilled with the successful completion of our scikit-bio workshop at `ISMB 2024 `_! :fa:`beer-mug-empty` Huge thanks to everyone who attended and participated. It was great to connect with the bioinformatics community and explore the latest in the field. Stay tuned for more! - **When**: 9:00 - 18:00 EDT, July 12, 2024 | **Where**: Montreal, Canada .. button-link:: https://www.iscb.org/ismb2024/programme-schedule/tutorials#ip3 :color: primary :shadow: ISMB 2024 workshop Books ----- `An Introduction to Applied Bioinformatics `_, or **IAB**: An interactive bioinformatics textbook developed by By `Dr. Greg Caporaso `_ and colleagues at NAU. Available in Jupyter Book, Markdown, and PDF formats, IAB guides readers through the core concepts of bioinformatics with their practical application using Python libraries like scikit-learn and scikit-bio. This approach equips readers with the skills to develop their bioinformatics tools and pipelines, emphasizing rapid project initiation over theoretical depth. Focused on actionable knowledge, IAB prepares readers for effective roles in the bioinformatics field. .. button-link:: https://readiab.org/ :color: primary :shadow: IAB frontpage Videos ------ Check out our previous presentations at `SciPy conferences `_: .. youtube:: ZpgkRQooGqo .. youtube:: hgBx_DBiPxA scikit-bio-scikit-bio-a3beaa6/web/make.bat000066400000000000000000000014401520735541300205340ustar00rootroot00000000000000@ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. set BUILDDIR=_build %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.https://www.sphinx-doc.org/ exit /b 1 ) if "%1" == "" goto help %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd scikit-bio-scikit-bio-a3beaa6/web/roadmap.rst000066400000000000000000000064731520735541300213170ustar00rootroot00000000000000scikit-bio roadmap ================== This is a dynamic document tracking current development directions. It may be used for inspiration and encouragement and for coordination of efforts. Interoperability ---------------- We are enhancing scikit-bio's ability to work seamlessly with diverse data formats and computing frameworks. A new dispatch system handles multiple table formats including arrays, Pandas and Polars dataframes, BIOM tables, and AnnData objects, allowing functions to operate on any supported format while preserving input types or enabling user-specified output formats. This table dispatch system shipped in v0.7.0. Additionally, we are adopting the Python array API standard to enable compatibility with GPU-accelerated libraries. The integration of these complementary systems will significantly improve scikit-bio's interoperability across the scientific Python ecosystem and support its use across omics disciplines. GPU support ----------- Modern omics datasets often exceed memory limitations and benefit from hardware acceleration. To address this, we are adopting the Python array API standard, which enables seamless interoperability with GPU-accelerated libraries like CuPy and JAX, as well as distributed computing frameworks like Dask. Initial implementation has focused on compositional transformation algorithms, with successful testing on PyTorch GPU objects. This foundation will be extended to additional algorithms, enabling significant performance improvements for large-scale analyses. Support for free-threaded Python -------------------------------- CPython 3.13 introduces a free-threaded build that removes the Global Interpreter Lock, enabling true multi-threading for CPU-bound tasks. This presents significant opportunities for scikit-bio's computationally intensive operations. However, adoption depends on ecosystem readiness - key dependencies including statsmodels and h5py do not yet provide free-threaded builds. We will monitor dependency support and evaluate implementation once the required packages become available, with particular focus on algorithms that would benefit most from parallel execution. Type annotations ---------------- We are systematically adding type annotations to the scikit-bio codebase to improve code readability, IDE autocompletion, and bug detection in both development and downstream applications. Recent progress includes type annotations for distance statistics, alignment modules, and other core functionality shipped in v0.7.0. New code development incorporates type annotations by default, while existing modules are being updated incrementally. Benchmarking ------------ Performance monitoring is critical for preventing regression in computationally intensive bioinformatics workflows. While scikit-bio previously had lightweight benchmarks using asv, these were not maintained and became outdated. We have established a dedicated benchmarking repository (https://github.com/scikit-bio/scikit-bio-benchmarks) to systematically track performance across releases, starting with version 0.6.1 and continuing for all future releases. The current framework includes basic benchmarks with plans to expand coverage to key algorithms and data structures. This infrastructure will help ensure that performance improvements and potential regressions are identified early in the development process. scikit-bio-scikit-bio-a3beaa6/web/suburl.py000066400000000000000000000031351520735541300210200ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2013--, scikit-bio development team. # # Distributed under the terms of the Modified BSD License. # # The full license is in the file LICENSE.txt, distributed with this software. # ---------------------------------------------------------------------------- # Script to substitute domain names with relative paths in hyperlinks in the # built html files, such as to avoid unnecessary domain resolutions when the # visitor navigates the website. It may be executed only when "doc" and "web" # are hosted at the same web server. import os import re import glob from functools import partial # -- Configuration ----------------------------------------------------------- rootdir = "_build/html" source = "https://scikit.bio/docs/latest" target = "docs/latest" # -- Workflow ---------------------------------------------------------------- pattern = re.compile(f'href="{re.escape(source)}/([^"]+)"') def substitute(match, prefix): return f'href="{prefix}{target}/{match.group(1)}"' cwd = os.getcwd() os.chdir(os.path.join(os.path.dirname(__file__), rootdir)) for file in glob.glob("**/*.html", recursive=True): depth = len(os.path.normpath(file).split(os.sep)) prefix = "../" * (depth - 1) with open(file, "r") as fh: content = fh.read() content = content.replace( f'href="{source}"', f'href="{prefix}{target}/index.html"' ) repl = partial(substitute, prefix=prefix) content = pattern.sub(repl, content) with open(file, "w") as fh: fh.write(content) os.chdir(cwd) scikit-bio-scikit-bio-a3beaa6/web/versions.json000066400000000000000000000040561520735541300217000ustar00rootroot00000000000000[ { "name": "dev", "version": "dev", "url": "https://scikit.bio/docs/dev/" }, { "name": "latest", "version": "0.7.3", "url": "https://scikit.bio/docs/latest/", "preferred": true }, { "version": "0.7.3", "url": "https://scikit.bio/docs/0.7.3/" }, { "version": "0.7.2", "url": "https://scikit.bio/docs/0.7.2/" }, { "version": "0.7.1", "url": "https://scikit.bio/docs/0.7.1/" }, { "version": "0.7.0", "url": "https://scikit.bio/docs/0.7.0/" }, { "version": "0.6.3", "url": "https://scikit.bio/docs/0.6.3/" }, { "version": "0.6.2", "url": "https://scikit.bio/docs/0.6.2/" }, { "version": "0.6.1", "url": "https://scikit.bio/docs/0.6.1/" }, { "version": "0.6.0", "url": "https://scikit.bio/docs/0.6.0/" }, { "version": "0.5.9", "url": "https://scikit.bio/docs/0.5.9/" }, { "version": "0.5.8", "url": "https://scikit.bio/docs/0.5.8/" }, { "version": "0.5.7", "url": "https://scikit.bio/docs/0.5.7/" }, { "version": "0.5.6", "url": "https://scikit.bio/docs/0.5.6/" }, { "version": "0.5.5", "url": "https://scikit.bio/docs/0.5.5/" }, { "version": "0.5.4", "url": "https://scikit.bio/docs/0.5.4/" }, { "version": "0.5.3", "url": "https://scikit.bio/docs/0.5.3/" }, { "version": "0.5.2", "url": "https://scikit.bio/docs/0.5.2/" }, { "version": "0.5.1", "url": "https://scikit.bio/docs/0.5.1/" }, { "version": "0.5.0", "url": "https://scikit.bio/docs/0.5.0/" }, { "version": "0.4.2", "url": "https://scikit.bio/docs/0.4.2/" }, { "version": "0.4.1", "url": "https://scikit.bio/docs/0.4.1/" }, { "version": "0.4.0", "url": "https://scikit.bio/docs/0.4.0/" }, { "version": "0.2.3", "url": "https://scikit.bio/docs/0.2.3/" }, { "version": "0.2.2", "url": "https://scikit.bio/docs/0.2.2/" }, { "version": "0.2.1", "url": "https://scikit.bio/docs/0.2.1/" }, { "version": "0.2.0", "url": "https://scikit.bio/docs/0.2.0/" }, { "version": "0.1.4", "url": "https://scikit.bio/docs/0.1.4/" }, { "version": "0.1.3", "url": "https://scikit.bio/docs/0.1.3/" }, { "version": "0.1.1", "url": "https://scikit.bio/docs/0.1.1/" } ]